[Pkg-golang-commits] [golang] 01/01: Imported Upstream version 1.9~beta1

Michael Hudson-Doyle mwhudson-guest at moszumanska.debian.org
Thu Jun 15 02:44:40 UTC 2017


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

mwhudson-guest pushed a commit to branch upstream-1.9
in repository golang.

commit ca4e4600d74aa8ff29a3de1beaa75f6dc4b85b1e
Author: Michael Hudson-Doyle <michael.hudson at canonical.com>
Date:   Thu Jun 15 13:13:55 2017 +1200

    Imported Upstream version 1.9~beta1
---
 AUTHORS                                            |    90 +-
 CONTRIBUTING.md                                    |    18 +-
 CONTRIBUTORS                                       |   110 +-
 README.md                                          |     4 +
 VERSION                                            |     2 +-
 api/except.txt                                     |     1 +
 api/go1.9.txt                                      |   163 +
 doc/articles/wiki/test.bash                        |     2 +-
 doc/cmd.html                                       |     2 +
 doc/code.html                                      |     8 +-
 doc/contribute.html                                |    44 +-
 doc/devel/release.html                             |    19 +-
 doc/effective_go.html                              |     4 +-
 doc/go1.8.txt                                      |    55 -
 doc/go1.9.html                                     |   746 +
 doc/go_spec.html                                   |   278 +-
 doc/help.html                                      |     6 +
 doc/install-source.html                            |     2 +-
 doc/install.html                                   |     3 +-
 doc/security.html                                  |     8 +-
 lib/time/update.bash                               |     6 +-
 lib/time/zoneinfo.zip                              |   Bin 366113 -> 366776 bytes
 misc/android/go_android_exec.go                    |    11 +-
 misc/cgo/errors/issue18452.go                      |    18 +
 misc/cgo/errors/issue18889.go                      |     7 +
 misc/cgo/errors/test.bash                          |     4 +-
 misc/cgo/fortran/test.bash                         |     2 +-
 misc/cgo/test/cgo_test.go                          |     3 +
 misc/cgo/test/issue18720.go                        |    28 +
 misc/cgo/test/issue20266.go                        |    21 +
 misc/cgo/test/issue20266/issue20266.h              |     9 +
 misc/cgo/test/issue20369.go                        |    20 +
 misc/cgo/test/issue6612.go                         |    17 +-
 misc/cgo/testcarchive/carchive_test.go             |   164 +-
 misc/cgo/testcarchive/main2.c                      |    35 +-
 misc/cgo/testcarchive/main3.c                      |    34 +
 misc/cgo/testcarchive/main5.c                      |    18 +
 misc/cgo/testcarchive/main6.c                      |    34 +
 misc/cgo/testcarchive/src/libgo2/libgo2.go         |    30 +
 misc/cgo/testcarchive/src/libgo3/libgo3.go         |    12 +
 misc/cgo/testcarchive/src/libgo6/sigprof.go        |    25 +
 misc/cgo/testcshared/main0.c                       |     6 +
 misc/cgo/testcshared/src/p/p.go                    |     2 +
 misc/cgo/testcshared/test.bash                     |    20 +-
 misc/cgo/testplugin/src/issue19534/main.go         |    23 +
 misc/cgo/testplugin/src/issue19534/plugin.go       |     9 +
 misc/cgo/testplugin/test.bash                      |     8 +-
 misc/cgo/testplugin/unnamed1.go                    |    11 +
 misc/cgo/testplugin/unnamed2.go                    |     9 +
 misc/cgo/testsanitizers/test.bash                  |    33 +-
 misc/cgo/testsanitizers/tsan10.go                  |    31 +
 misc/cgo/testsanitizers/tsan11.go                  |    55 +
 misc/cgo/testsanitizers/tsan_shared.go             |    63 +
 misc/cgo/testshared/shared_test.go                 |    20 +-
 misc/cgo/testshared/src/division/division.go       |    17 +
 misc/ios/detect.go                                 |    61 +-
 misc/ios/go_darwin_arm_exec.go                     |    80 +-
 misc/nacl/testzip.proto                            |    22 +
 src/archive/tar/common.go                          |    20 +-
 src/archive/tar/tar_test.go                        |    80 +-
 src/archive/zip/register.go                        |    47 +-
 src/archive/zip/struct.go                          |     2 +-
 src/archive/zip/writer.go                          |    19 +
 src/archive/zip/writer_test.go                     |    90 +-
 src/archive/zip/zip_test.go                        |    14 +-
 src/bufio/bufio.go                                 |     5 +-
 src/bufio/scan_test.go                             |     1 -
 src/buildall.bash                                  |    74 +-
 src/builtin/builtin.go                             |     6 +-
 src/bytes/buffer.go                                |   137 +-
 src/bytes/buffer_test.go                           |    76 +-
 src/bytes/bytes.go                                 |    60 +-
 src/bytes/bytes_amd64.go                           |    17 +-
 src/bytes/bytes_generic.go                         |     6 +
 src/bytes/bytes_s390x.go                           |     6 +
 src/bytes/bytes_test.go                            |   146 +
 src/bytes/export_test.go                           |     1 +
 src/cmd/addr2line/addr2line_test.go                |    17 +-
 src/cmd/api/run.go                                 |     2 +-
 src/cmd/asm/internal/arch/arch.go                  |     8 +-
 src/cmd/asm/internal/arch/arm.go                   |     4 +-
 src/cmd/asm/internal/arch/arm64.go                 |     2 +
 src/cmd/asm/internal/arch/s390x.go                 |    50 -
 src/cmd/asm/internal/asm/asm.go                    |    91 +-
 src/cmd/asm/internal/asm/endtoend_test.go          |    48 +-
 src/cmd/asm/internal/asm/operand_test.go           |     5 +-
 src/cmd/asm/internal/asm/parse.go                  |    64 +-
 src/cmd/asm/internal/asm/pseudo_test.go            |     1 -
 src/cmd/asm/internal/asm/testdata/386.s            |     4 +-
 src/cmd/asm/internal/asm/testdata/amd64.s          |     4 +-
 src/cmd/asm/internal/asm/testdata/amd64enc.s       |   116 +-
 src/cmd/asm/internal/asm/testdata/arm.s            |   974 +-
 src/cmd/asm/internal/asm/testdata/arm64.s          |   100 +-
 src/cmd/asm/internal/asm/testdata/armerror.s       |    27 +
 src/cmd/asm/internal/asm/testdata/armv6.s          |    47 +
 src/cmd/asm/internal/asm/testdata/mips.s           |     4 +-
 src/cmd/asm/internal/asm/testdata/mips64.s         |    26 +-
 src/cmd/asm/internal/asm/testdata/ppc64.s          |    63 +-
 src/cmd/asm/internal/asm/testdata/s390x.s          |   154 +-
 src/cmd/asm/internal/lex/input.go                  |    11 +-
 src/cmd/asm/internal/lex/lex.go                    |    32 +-
 src/cmd/asm/internal/lex/slice.go                  |    43 +-
 src/cmd/asm/internal/lex/stack.go                  |    20 +-
 src/cmd/asm/internal/lex/tokenizer.go              |    46 +-
 src/cmd/asm/main.go                                |    19 +-
 src/cmd/cgo/ast.go                                 |    14 +-
 src/cmd/cgo/doc.go                                 |    80 +-
 src/cmd/cgo/gcc.go                                 |   462 +-
 src/cmd/cgo/main.go                                |    31 +-
 src/cmd/cgo/out.go                                 |    25 +-
 src/cmd/compile/doc.go                             |     4 +
 src/cmd/compile/fmt_test.go                        |    60 +-
 src/cmd/compile/internal/amd64/galign.go           |    26 +-
 src/cmd/compile/internal/amd64/ggen.go             |   128 +-
 src/cmd/compile/internal/amd64/prog.go             |   287 -
 src/cmd/compile/internal/amd64/ssa.go              |   372 +-
 src/cmd/compile/internal/arm/galign.go             |    20 +-
 src/cmd/compile/internal/arm/ggen.go               |    84 +-
 src/cmd/compile/internal/arm/prog.go               |   159 -
 src/cmd/compile/internal/arm/ssa.go                |   273 +-
 src/cmd/compile/internal/arm64/galign.go           |    21 +-
 src/cmd/compile/internal/arm64/ggen.go             |    94 +-
 src/cmd/compile/internal/arm64/prog.go             |   184 -
 src/cmd/compile/internal/arm64/ssa.go              |   225 +-
 src/cmd/compile/internal/gc/alg.go                 |   146 +-
 src/cmd/compile/internal/gc/align.go               |   165 +-
 src/cmd/compile/internal/gc/asm_test.go            |  1705 +-
 src/cmd/compile/internal/gc/bexport.go             |   479 +-
 src/cmd/compile/internal/gc/bimport.go             |   506 +-
 src/cmd/compile/internal/gc/bitset.go              |    49 +
 src/cmd/compile/internal/gc/bootstrap.go           |    13 +
 src/cmd/compile/internal/gc/builtin.go             |   443 +-
 src/cmd/compile/internal/gc/builtin/runtime.go     |    63 +-
 src/cmd/compile/internal/gc/bv.go                  |    18 +-
 src/cmd/compile/internal/gc/class_string.go        |    16 +
 src/cmd/compile/internal/gc/closure.go             |   203 +-
 src/cmd/compile/internal/gc/const.go               |   338 +-
 src/cmd/compile/internal/gc/constFold_test.go      |     3 +
 src/cmd/compile/internal/gc/dcl.go                 |   739 +-
 src/cmd/compile/internal/gc/esc.go                 |   479 +-
 src/cmd/compile/internal/gc/export.go              |   194 +-
 src/cmd/compile/internal/gc/float_test.go          |    21 +
 src/cmd/compile/internal/gc/fmt.go                 |   954 +-
 src/cmd/compile/internal/gc/gen.go                 |   231 +-
 src/cmd/compile/internal/gc/go.go                  |   240 +-
 src/cmd/compile/internal/gc/gsubr.go               |   385 +-
 src/cmd/compile/internal/gc/init.go                |   170 +-
 src/cmd/compile/internal/gc/inl.go                 |   516 +-
 src/cmd/compile/internal/gc/lex.go                 |    70 +-
 src/cmd/compile/internal/gc/lex_test.go            |     8 +-
 src/cmd/compile/internal/gc/magic.go               |   220 -
 src/cmd/compile/internal/gc/main.go                |   725 +-
 src/cmd/compile/internal/gc/mkbuiltin.go           |    43 +-
 src/cmd/compile/internal/gc/mpfloat.go             |    30 +-
 src/cmd/compile/internal/gc/mpint.go               |    38 +-
 src/cmd/compile/internal/gc/noder.go               |   607 +-
 src/cmd/compile/internal/gc/norace.go              |     9 +
 src/cmd/compile/internal/gc/obj.go                 |   165 +-
 src/cmd/compile/internal/gc/opnames.go             |    12 +-
 src/cmd/compile/internal/gc/order.go               |   283 +-
 src/cmd/compile/internal/gc/pgen.go                |   532 +-
 src/cmd/compile/internal/gc/pgen_test.go           |   165 +-
 src/cmd/compile/internal/gc/phi.go                 |    52 +-
 src/cmd/compile/internal/gc/plive.go               |  1996 +-
 src/cmd/compile/internal/gc/pprof.go               |    13 +
 src/cmd/compile/internal/gc/race.go                |     9 +
 src/cmd/compile/internal/gc/racewalk.go            |    43 +-
 src/cmd/compile/internal/gc/range.go               |   141 +-
 src/cmd/compile/internal/gc/reflect.go             |  1085 +-
 src/cmd/compile/internal/gc/reflect_test.go        |    24 +-
 .../compile/internal/gc/reproduciblebuilds_test.go |    48 +
 src/cmd/compile/internal/gc/scope.go               |   177 +
 src/cmd/compile/internal/gc/scope_test.go          |   413 +
 src/cmd/compile/internal/gc/select.go              |   156 +-
 src/cmd/compile/internal/gc/sinit.go               |   348 +-
 src/cmd/compile/internal/gc/sizeof_test.go         |    23 +-
 src/cmd/compile/internal/gc/ssa.go                 |  2869 +-
 src/cmd/compile/internal/gc/subr.go                |   905 +-
 src/cmd/compile/internal/gc/swt.go                 |   214 +-
 src/cmd/compile/internal/gc/swt_test.go            |    10 +-
 src/cmd/compile/internal/gc/syntax.go              |   401 +-
 src/cmd/compile/internal/gc/testdata/arith.go      |    11 -
 .../compile/internal/gc/testdata/arithBoundary.go  |     3 +
 src/cmd/compile/internal/gc/testdata/arithConst.go |     3 +
 src/cmd/compile/internal/gc/testdata/copy.go       |   111 +-
 src/cmd/compile/internal/gc/testdata/fp.go         |   137 +
 .../internal/gc/testdata/gen/arithBoundaryGen.go   |     3 +-
 .../internal/gc/testdata/gen/arithConstGen.go      |    40 +-
 .../internal/gc/testdata/gen/constFoldGen.go       |     4 +-
 .../compile/internal/gc/testdata/gen/copyGen.go    |    39 +-
 .../compile/internal/gc/testdata/gen/zeroGen.go    |     4 +-
 src/cmd/compile/internal/gc/testdata/loadstore.go  |   108 +
 .../gc/testdata/reproducible/issue20272.go         |    34 +
 src/cmd/compile/internal/gc/testdata/zero.go       |     3 +-
 src/cmd/compile/internal/gc/truncconst_test.go     |    63 +
 src/cmd/compile/internal/gc/type.go                |  1250 -
 src/cmd/compile/internal/gc/typecheck.go           |   876 +-
 src/cmd/compile/internal/gc/types.go               |    63 +
 src/cmd/compile/internal/gc/types_acc.go           |    16 +
 src/cmd/compile/internal/gc/universe.go            |   250 +-
 src/cmd/compile/internal/gc/util.go                |    31 +-
 src/cmd/compile/internal/gc/walk.go                |  1718 +-
 src/cmd/compile/internal/mips/galign.go            |    26 +-
 src/cmd/compile/internal/mips/ggen.go              |    74 +-
 src/cmd/compile/internal/mips/prog.go              |   157 -
 src/cmd/compile/internal/mips/ssa.go               |   269 +-
 src/cmd/compile/internal/mips64/galign.go          |    26 +-
 src/cmd/compile/internal/mips64/ggen.go            |    81 +-
 src/cmd/compile/internal/mips64/prog.go            |   154 -
 src/cmd/compile/internal/mips64/ssa.go             |   185 +-
 src/cmd/compile/internal/ppc64/galign.go           |    29 +-
 src/cmd/compile/internal/ppc64/ggen.go             |   111 +-
 src/cmd/compile/internal/ppc64/prog.go             |   304 -
 src/cmd/compile/internal/ppc64/ssa.go              |   989 +-
 src/cmd/compile/internal/s390x/galign.go           |    20 +-
 src/cmd/compile/internal/s390x/ggen.go             |   116 +-
 src/cmd/compile/internal/s390x/prog.go             |   196 -
 src/cmd/compile/internal/s390x/ssa.go              |   285 +-
 src/cmd/compile/internal/ssa/block.go              |    11 +-
 src/cmd/compile/internal/ssa/cache.go              |    41 +
 src/cmd/compile/internal/ssa/check.go              |   165 +-
 src/cmd/compile/internal/ssa/checkbce.go           |     2 +-
 src/cmd/compile/internal/ssa/compile.go            |    20 +-
 src/cmd/compile/internal/ssa/config.go             |   279 +-
 src/cmd/compile/internal/ssa/copyelim_test.go      |     8 +-
 src/cmd/compile/internal/ssa/critical.go           |     8 +-
 src/cmd/compile/internal/ssa/cse.go                |    49 +-
 src/cmd/compile/internal/ssa/cse_test.go           |    77 +-
 src/cmd/compile/internal/ssa/deadcode.go           |     8 +-
 src/cmd/compile/internal/ssa/deadcode_test.go      |    30 +-
 src/cmd/compile/internal/ssa/deadstore.go          |    23 +-
 src/cmd/compile/internal/ssa/deadstore_test.go     |    71 +-
 src/cmd/compile/internal/ssa/decompose.go          |   162 +-
 src/cmd/compile/internal/ssa/dom.go                |    59 +-
 src/cmd/compile/internal/ssa/dom_test.go           |   126 +-
 src/cmd/compile/internal/ssa/export_test.go        |   192 +-
 src/cmd/compile/internal/ssa/func.go               |   356 +-
 src/cmd/compile/internal/ssa/func_test.go          |   153 +-
 src/cmd/compile/internal/ssa/fuse.go               |    13 +-
 src/cmd/compile/internal/ssa/fuse_test.go          |    56 +-
 src/cmd/compile/internal/ssa/gen/386.rules         |   215 +-
 src/cmd/compile/internal/ssa/gen/386Ops.go         |   130 +-
 src/cmd/compile/internal/ssa/gen/AMD64.rules       |  1267 +-
 src/cmd/compile/internal/ssa/gen/AMD64Ops.go       |   277 +-
 src/cmd/compile/internal/ssa/gen/ARM.rules         |   253 +-
 src/cmd/compile/internal/ssa/gen/ARM64.rules       |   551 +-
 src/cmd/compile/internal/ssa/gen/ARM64Ops.go       |    50 +-
 src/cmd/compile/internal/ssa/gen/ARMOps.go         |    37 +-
 src/cmd/compile/internal/ssa/gen/MIPS.rules        |   205 +-
 src/cmd/compile/internal/ssa/gen/MIPS64.rules      |   240 +-
 src/cmd/compile/internal/ssa/gen/MIPS64Ops.go      |    50 +-
 src/cmd/compile/internal/ssa/gen/MIPSOps.go        |    46 +-
 src/cmd/compile/internal/ssa/gen/PPC64.rules       |   349 +-
 src/cmd/compile/internal/ssa/gen/PPC64Ops.go       |   238 +-
 src/cmd/compile/internal/ssa/gen/S390X.rules       |   996 +-
 src/cmd/compile/internal/ssa/gen/S390XOps.go       |   327 +-
 src/cmd/compile/internal/ssa/gen/dec.rules         |    76 +-
 src/cmd/compile/internal/ssa/gen/dec64.rules       |   344 +-
 src/cmd/compile/internal/ssa/gen/generic.rules     |   838 +-
 src/cmd/compile/internal/ssa/gen/genericOps.go     |   151 +-
 src/cmd/compile/internal/ssa/gen/main.go           |    39 +-
 src/cmd/compile/internal/ssa/gen/rulegen.go        |   335 +-
 src/cmd/compile/internal/ssa/html.go               |    37 +-
 src/cmd/compile/internal/ssa/layout.go             |    23 +-
 src/cmd/compile/internal/ssa/lca_test.go           |     4 +-
 src/cmd/compile/internal/ssa/likelyadjust.go       |    56 +-
 src/cmd/compile/internal/ssa/location.go           |    11 +-
 src/cmd/compile/internal/ssa/loop_test.go          |    36 +-
 src/cmd/compile/internal/ssa/loopbce.go            |    10 +-
 src/cmd/compile/internal/ssa/loopreschedchecks.go  |   154 +-
 src/cmd/compile/internal/ssa/looprotate.go         |   103 +
 src/cmd/compile/internal/ssa/magic.go              |   406 +-
 src/cmd/compile/internal/ssa/magic_test.go         |   205 +
 src/cmd/compile/internal/ssa/nilcheck.go           |    72 +-
 src/cmd/compile/internal/ssa/nilcheck_test.go      |   149 +-
 src/cmd/compile/internal/ssa/op.go                 |    97 +-
 src/cmd/compile/internal/ssa/opGen.go              |  2931 +-
 src/cmd/compile/internal/ssa/opt.go                |     2 +-
 src/cmd/compile/internal/ssa/passbm_test.go        |    29 +-
 src/cmd/compile/internal/ssa/phielim.go            |     2 +-
 src/cmd/compile/internal/ssa/phiopt.go             |    10 +-
 src/cmd/compile/internal/ssa/print.go              |     2 +-
 src/cmd/compile/internal/ssa/prove.go              |    89 +-
 src/cmd/compile/internal/ssa/regalloc.go           |   870 +-
 src/cmd/compile/internal/ssa/regalloc_test.go      |   133 +-
 src/cmd/compile/internal/ssa/rewrite.go            |   196 +-
 src/cmd/compile/internal/ssa/rewrite386.go         | 13455 ++++--
 src/cmd/compile/internal/ssa/rewriteAMD64.go       | 47798 ++++++++++++++-----
 src/cmd/compile/internal/ssa/rewriteARM.go         |  5882 ++-
 src/cmd/compile/internal/ssa/rewriteARM64.go       |  7492 +--
 src/cmd/compile/internal/ssa/rewriteMIPS.go        |  3955 +-
 src/cmd/compile/internal/ssa/rewriteMIPS64.go      |  4428 +-
 src/cmd/compile/internal/ssa/rewritePPC64.go       |  5141 +-
 src/cmd/compile/internal/ssa/rewriteS390X.go       | 32200 ++++++++++---
 src/cmd/compile/internal/ssa/rewrite_test.go       |     2 +-
 src/cmd/compile/internal/ssa/rewritedec.go         |   256 +-
 src/cmd/compile/internal/ssa/rewritedec64.go       |  1390 +-
 src/cmd/compile/internal/ssa/rewritegeneric.go     | 27621 ++++++++---
 src/cmd/compile/internal/ssa/schedule.go           |   196 +-
 src/cmd/compile/internal/ssa/schedule_test.go      |    66 +-
 src/cmd/compile/internal/ssa/shift_test.go         |    97 +-
 src/cmd/compile/internal/ssa/shortcircuit.go       |     9 +-
 src/cmd/compile/internal/ssa/shortcircuit_test.go  |    25 +-
 src/cmd/compile/internal/ssa/sizeof_test.go        |     3 +-
 src/cmd/compile/internal/ssa/sparsemap.go          |     8 +-
 src/cmd/compile/internal/ssa/stackalloc.go         |    22 +-
 src/cmd/compile/internal/ssa/stackframe.go         |     2 +-
 src/cmd/compile/internal/ssa/tighten.go            |     2 +-
 src/cmd/compile/internal/ssa/trim.go               |    20 +-
 src/cmd/compile/internal/ssa/type.go               |   192 -
 src/cmd/compile/internal/ssa/type_test.go          |   102 -
 src/cmd/compile/internal/ssa/value.go              |    63 +-
 src/cmd/compile/internal/ssa/writebarrier.go       |   471 +-
 src/cmd/compile/internal/ssa/writebarrier_test.go  |    43 +-
 src/cmd/compile/internal/ssa/zcse.go               |     4 +-
 src/cmd/compile/internal/syntax/branches.go        |   314 +
 src/cmd/compile/internal/syntax/dumper.go          |     2 +-
 src/cmd/compile/internal/syntax/dumper_test.go     |     2 +-
 src/cmd/compile/internal/syntax/nodes.go           |    88 +-
 src/cmd/compile/internal/syntax/nodes_test.go      |   329 +
 src/cmd/compile/internal/syntax/parser.go          |   795 +-
 src/cmd/compile/internal/syntax/parser_test.go     |    60 +-
 src/cmd/compile/internal/syntax/printer.go         |    44 +-
 src/cmd/compile/internal/syntax/printer_test.go    |    19 +-
 src/cmd/compile/internal/syntax/scanner.go         |   218 +-
 src/cmd/compile/internal/syntax/scanner_test.go    |   142 +-
 src/cmd/compile/internal/syntax/source.go          |    90 +-
 src/cmd/compile/internal/syntax/syntax.go          |    41 +-
 src/cmd/compile/internal/types/pkg.go              |   135 +
 src/cmd/compile/internal/types/scope.go            |    70 +
 src/cmd/compile/internal/types/sizeof_test.go      |    51 +
 src/cmd/compile/internal/types/sym.go              |    81 +
 src/cmd/compile/internal/types/type.go             |  1416 +
 src/cmd/compile/internal/types/utils.go            |   126 +
 src/cmd/compile/internal/x86/387.go                |   116 +-
 src/cmd/compile/internal/x86/galign.go             |    28 +-
 src/cmd/compile/internal/x86/ggen.go               |    78 +-
 src/cmd/compile/internal/x86/prog.go               |   270 -
 src/cmd/compile/internal/x86/ssa.go                |   329 +-
 src/cmd/compile/main.go                            |    41 +-
 src/cmd/cover/cover_test.go                        |    28 +-
 src/cmd/cover/func.go                              |    14 +-
 src/cmd/cover/testdata/p.go                        |    27 +
 src/cmd/cover/testdata/profile.cov                 |     5 +
 src/cmd/dist/build.go                              |    13 +-
 src/cmd/dist/buildgo.go                            |    28 +-
 src/cmd/dist/buildruntime.go                       |     6 +-
 src/cmd/dist/buildtool.go                          |    86 +-
 src/cmd/dist/deps.go                               |   108 +-
 src/cmd/dist/test.go                               |   106 +-
 src/cmd/doc/doc_test.go                            |    39 +
 src/cmd/doc/main.go                                |    15 +-
 src/cmd/doc/pkg.go                                 |    86 +-
 src/cmd/doc/testdata/pkg.go                        |    17 +
 src/cmd/fix/main.go                                |    39 +-
 src/cmd/go/alldocs.go                              |   137 +-
 src/cmd/go/bootstrap.go                            |    41 -
 src/cmd/go/bug.go                                  |   212 -
 src/cmd/go/build.go                                |  3832 --
 src/cmd/go/build_test.go                           |    44 -
 src/cmd/go/clean.go                                |   248 -
 src/cmd/go/context.go                              |    37 -
 src/cmd/go/discovery.go                            |    83 -
 src/cmd/go/doc.go                                  |   118 -
 src/cmd/go/env.go                                  |   138 -
 src/cmd/go/fix.go                                  |    30 -
 src/cmd/go/fmt.go                                  |    64 -
 src/cmd/go/generate.go                             |   401 -
 src/cmd/go/generate_test.go                        |    56 -
 src/cmd/go/get.go                                  |   588 -
 src/cmd/go/go_test.go                              |   559 +-
 src/cmd/go/help.go                                 |   607 -
 src/cmd/go/http.go                                 |   120 -
 src/cmd/go/internal/base/base.go                   |   173 +
 src/cmd/go/internal/base/env.go                    |    37 +
 src/cmd/go/internal/base/flag.go                   |    35 +
 src/cmd/go/internal/base/path.go                   |    74 +
 src/cmd/go/internal/base/signal.go                 |    31 +
 src/cmd/go/internal/base/signal_notunix.go         |    17 +
 src/cmd/go/internal/base/signal_unix.go            |    18 +
 src/cmd/go/internal/base/tool.go                   |    53 +
 src/cmd/go/internal/bug/bug.go                     |   218 +
 src/cmd/go/internal/buildid/buildid.go             |   201 +
 src/cmd/go/internal/buildid/note.go                |   187 +
 src/cmd/go/internal/cfg/cfg.go                     |   114 +
 src/cmd/go/internal/clean/clean.go                 |   254 +
 src/cmd/go/internal/cmdflag/flag.go                |   123 +
 src/cmd/go/internal/doc/doc.go                     |   123 +
 src/cmd/go/internal/envcmd/env.go                  |   178 +
 src/cmd/go/internal/fix/fix.go                     |    39 +
 src/cmd/go/internal/fmtcmd/fmt.go                  |    71 +
 src/cmd/go/internal/generate/generate.go           |   407 +
 src/cmd/go/internal/generate/generate_test.go      |    56 +
 src/cmd/go/internal/get/discovery.go               |    76 +
 src/cmd/go/internal/get/get.go                     |   528 +
 src/cmd/go/internal/get/pkg_test.go                |    83 +
 src/cmd/go/internal/get/tag_test.go                |   100 +
 src/cmd/go/internal/get/vcs.go                     |  1000 +
 src/cmd/go/internal/get/vcs_test.go                |   392 +
 src/cmd/go/internal/help/help.go                   |   178 +
 src/cmd/go/internal/help/helpdoc.go                |   620 +
 src/cmd/go/internal/list/context.go                |    37 +
 src/cmd/go/internal/list/list.go                   |   240 +
 src/cmd/go/internal/load/match_test.go             |   165 +
 src/cmd/go/internal/load/path.go                   |    80 +
 src/cmd/go/internal/load/pkg.go                    |  1924 +
 src/cmd/go/internal/load/search.go                 |   324 +
 src/cmd/go/internal/load/testgo.go                 |    21 +
 src/cmd/go/internal/run/run.go                     |   131 +
 src/cmd/go/internal/str/str.go                     |   141 +
 src/cmd/go/internal/test/test.go                   |  1604 +
 src/cmd/go/internal/test/testflag.go               |   211 +
 src/cmd/go/internal/tool/tool.go                   |   119 +
 src/cmd/go/internal/version/version.go             |    28 +
 src/cmd/go/internal/vet/vet.go                     |    56 +
 src/cmd/go/internal/vet/vetflag.go                 |    99 +
 src/cmd/go/internal/web/bootstrap.go               |    37 +
 src/cmd/go/internal/web/http.go                    |   122 +
 src/cmd/go/internal/web/security.go                |    16 +
 src/cmd/go/internal/work/build.go                  |  3865 ++
 src/cmd/go/internal/work/build_test.go             |   227 +
 src/cmd/go/internal/work/testgo.go                 |    17 +
 src/cmd/go/list.go                                 |   234 -
 src/cmd/go/main.go                                 |   779 +-
 src/cmd/go/match_test.go                           |    88 -
 src/cmd/go/note.go                                 |   187 -
 src/cmd/go/note_test.go                            |    13 +-
 src/cmd/go/pkg.go                                  |  2032 -
 src/cmd/go/pkg_test.go                             |   194 -
 src/cmd/go/run.go                                  |   156 -
 src/cmd/go/signal.go                               |    31 -
 src/cmd/go/signal_notunix.go                       |    17 -
 src/cmd/go/signal_unix.go                          |    18 -
 src/cmd/go/tag_test.go                             |   100 -
 src/cmd/go/test.go                                 |  1596 -
 src/cmd/go/testdata/inprogress_interrupt_test.go   |    40 +
 src/cmd/go/testdata/src/bench/x_test.go            |     6 +
 src/cmd/go/testflag.go                             |   294 -
 src/cmd/go/testgo.go                               |    21 -
 src/cmd/go/tool.go                                 |   152 -
 src/cmd/go/vcs.go                                  |  1006 -
 src/cmd/go/vcs_test.go                             |   382 -
 src/cmd/go/vendor_test.go                          |     6 +-
 src/cmd/go/version.go                              |    25 -
 src/cmd/go/vet.go                                  |    52 -
 src/cmd/gofmt/doc.go                               |     5 +-
 src/cmd/gofmt/gofmt.go                             |    70 +-
 src/cmd/gofmt/gofmt_test.go                        |    70 +-
 src/cmd/gofmt/rewrite.go                           |     2 +-
 src/cmd/gofmt/testdata/rewrite9.golden             |    11 +
 src/cmd/gofmt/testdata/rewrite9.input              |    11 +
 src/cmd/gofmt/testdata/typealias.golden            |    24 +
 src/cmd/gofmt/testdata/typealias.input             |    24 +
 src/cmd/internal/browser/browser.go                |    25 +-
 src/cmd/internal/dwarf/dwarf.go                    |   241 +-
 src/cmd/internal/dwarf/dwarf_defs.go               |     5 +
 src/cmd/internal/dwarf/dwarf_test.go               |    38 +
 src/cmd/internal/goobj/read.go                     |   191 +-
 src/cmd/internal/goobj/read_test.go                |    28 -
 src/cmd/internal/obj/arm/a.out.go                  |    20 +-
 src/cmd/internal/obj/arm/anames.go                 |    12 +
 src/cmd/internal/obj/arm/anames5.go                |     2 +
 src/cmd/internal/obj/arm/asm5.go                   |  1215 +-
 src/cmd/internal/obj/arm/list5.go                  |     4 +-
 src/cmd/internal/obj/arm/obj5.go                   |   517 +-
 src/cmd/internal/obj/arm64/a.out.go                |    44 +-
 src/cmd/internal/obj/arm64/anames7.go              |    21 +-
 src/cmd/internal/obj/arm64/asm7.go                 |  1159 +-
 src/cmd/internal/obj/arm64/list7.go                |     4 +-
 src/cmd/internal/obj/arm64/obj7.go                 |   454 +-
 src/cmd/internal/obj/bootstrap.go                  |    34 +
 src/cmd/internal/obj/data.go                       |    44 +-
 src/cmd/internal/obj/flag.go                       |   115 -
 src/cmd/internal/obj/funcdata.go                   |    48 -
 src/cmd/internal/obj/go.go                         |    72 -
 src/cmd/internal/obj/inl.go                        |    85 +
 src/cmd/internal/obj/ld.go                         |    15 +-
 src/cmd/internal/obj/line.go                       |   297 +-
 src/cmd/internal/obj/line_test.go                  |    51 +-
 src/cmd/internal/obj/link.go                       |   683 +-
 src/cmd/internal/obj/mips/a.out.go                 |    12 +-
 src/cmd/internal/obj/mips/anames.go                |     3 +
 src/cmd/internal/obj/mips/asm0.go                  |   759 +-
 src/cmd/internal/obj/mips/list0.go                 |     4 +-
 src/cmd/internal/obj/mips/obj0.go                  |   484 +-
 src/cmd/internal/obj/objfile.go                    |   329 +-
 src/cmd/internal/obj/pass.go                       |    95 +-
 src/cmd/internal/obj/pcln.go                       |   133 +-
 src/cmd/internal/obj/plist.go                      |   235 +-
 src/cmd/internal/obj/ppc64/a.out.go                |    19 +-
 src/cmd/internal/obj/ppc64/anames.go               |    19 +-
 src/cmd/internal/obj/ppc64/asm9.go                 |   921 +-
 src/cmd/internal/obj/ppc64/list9.go                |     4 +-
 src/cmd/internal/obj/ppc64/obj9.go                 |   474 +-
 src/cmd/internal/obj/reloctype_string.go           |    17 -
 src/cmd/internal/obj/s390x/a.out.go                |    21 +-
 src/cmd/internal/obj/s390x/anames.go               |     6 +-
 src/cmd/internal/obj/s390x/asmz.go                 |   750 +-
 src/cmd/internal/obj/s390x/listz.go                |     4 +-
 src/cmd/internal/obj/s390x/objz.go                 |   543 +-
 src/cmd/internal/obj/sizeof_test.go                |     6 +-
 src/cmd/internal/obj/sort.go                       |    13 +
 src/cmd/internal/obj/stack.go                      |    21 -
 src/cmd/internal/obj/sym.go                        |    99 +-
 src/cmd/internal/obj/symkind_string.go             |    16 -
 src/cmd/internal/obj/typekind.go                   |    41 -
 src/cmd/internal/obj/util.go                       |   142 +-
 src/cmd/internal/obj/x86/a.out.go                  |     1 -
 src/cmd/internal/obj/x86/anames.go                 |     1 -
 src/cmd/internal/obj/x86/asm6.go                   |  1135 +-
 src/cmd/internal/obj/x86/issue19518_test.go        |   110 +
 src/cmd/internal/obj/x86/list6.go                  |     4 +-
 src/cmd/internal/obj/x86/obj6.go                   |   594 +-
 src/cmd/internal/objabi/autotype.go                |    37 +
 src/cmd/internal/objabi/doc.go                     |   120 +
 src/cmd/internal/objabi/flag.go                    |   115 +
 src/cmd/internal/objabi/funcdata.go                |    25 +
 src/cmd/internal/objabi/head.go                    |   104 +
 src/cmd/internal/objabi/line.go                    |    82 +
 src/cmd/internal/objabi/path.go                    |    41 +
 src/cmd/internal/objabi/path_test.go               |    33 +
 src/cmd/internal/objabi/reloctype.go               |   200 +
 src/cmd/internal/objabi/reloctype_string.go        |    17 +
 src/cmd/internal/objabi/stack.go                   |    20 +
 src/cmd/internal/objabi/symkind.go                 |    60 +
 src/cmd/internal/objabi/symkind_string.go          |    16 +
 src/cmd/internal/objabi/typekind.go                |    41 +
 src/cmd/internal/objabi/util.go                    |   114 +
 src/cmd/internal/objfile/disasm.go                 |   108 +-
 src/cmd/internal/objfile/goobj.go                  |    11 +-
 src/cmd/internal/src/pos.go                        |   268 +
 src/cmd/internal/src/pos_test.go                   |   143 +
 src/cmd/internal/src/xpos.go                       |    75 +
 src/cmd/internal/src/xpos_test.go                  |    84 +
 src/cmd/internal/sys/arch.go                       |    20 +-
 src/cmd/link/dwarf_test.go                         |     4 -
 src/cmd/link/internal/amd64/asm.go                 |   204 +-
 src/cmd/link/internal/amd64/obj.go                 |    38 +-
 src/cmd/link/internal/arm/asm.go                   |   152 +-
 src/cmd/link/internal/arm/obj.go                   |    16 +-
 src/cmd/link/internal/arm64/asm.go                 |   104 +-
 src/cmd/link/internal/arm64/obj.go                 |    10 +-
 src/cmd/link/internal/ld/ar.go                     |     6 +-
 src/cmd/link/internal/ld/config.go                 |    32 +-
 src/cmd/link/internal/ld/data.go                   |   546 +-
 src/cmd/link/internal/ld/deadcode.go               |    43 +-
 src/cmd/link/internal/ld/decodesym.go              |    28 +-
 src/cmd/link/internal/ld/dwarf.go                  |   192 +-
 src/cmd/link/internal/ld/dwarf_test.go             |   194 +
 src/cmd/link/internal/ld/elf.go                    |   182 +-
 src/cmd/link/internal/ld/go.go                     |    23 +-
 src/cmd/link/internal/ld/ld.go                     |   103 +-
 src/cmd/link/internal/ld/ldelf.go                  |   121 +-
 src/cmd/link/internal/ld/ldmacho.go                |    20 +-
 src/cmd/link/internal/ld/ldpe.go                   |    50 +-
 src/cmd/link/internal/ld/lib.go                    |   339 +-
 src/cmd/link/internal/ld/link.go                   |    93 +-
 src/cmd/link/internal/ld/macho.go                  |    35 +-
 src/cmd/link/internal/ld/main.go                   |    46 +-
 src/cmd/link/internal/ld/nooptcgolink_test.go      |    32 +
 src/cmd/link/internal/ld/objfile.go                |   160 +-
 src/cmd/link/internal/ld/pcln.go                   |    97 +-
 src/cmd/link/internal/ld/pe.go                     |   296 +-
 src/cmd/link/internal/ld/sym.go                    |    29 +-
 src/cmd/link/internal/ld/symkind.go                |   152 +
 src/cmd/link/internal/ld/symkind_string.go         |    16 +
 src/cmd/link/internal/ld/symtab.go                 |   152 +-
 src/cmd/link/internal/ld/typelink.go               |     7 +-
 src/cmd/link/internal/ld/util.go                   |    10 +
 src/cmd/link/internal/mips/asm.go                  |    54 +-
 src/cmd/link/internal/mips/obj.go                  |     6 +-
 src/cmd/link/internal/mips64/asm.go                |    76 +-
 src/cmd/link/internal/mips64/obj.go                |    10 +-
 src/cmd/link/internal/ppc64/asm.go                 |   221 +-
 src/cmd/link/internal/ppc64/l.go                   |     2 +-
 src/cmd/link/internal/ppc64/obj.go                 |    10 +-
 src/cmd/link/internal/s390x/asm.go                 |    90 +-
 src/cmd/link/internal/s390x/obj.go                 |     4 +-
 src/cmd/link/internal/x86/asm.go                   |   163 +-
 src/cmd/link/internal/x86/obj.go                   |    32 +-
 src/cmd/link/linkbig_test.go                       |     8 +-
 src/cmd/link/main.go                               |     6 +-
 src/cmd/nm/nm.go                                   |    15 +-
 src/cmd/nm/nm_cgo_test.go                          |    36 +
 src/cmd/nm/nm_test.go                              |   171 +-
 src/cmd/objdump/main.go                            |    10 +-
 src/cmd/objdump/objdump_test.go                    |    96 +-
 src/cmd/objdump/testdata/fmthello.go               |     7 +-
 src/cmd/pprof/README                               |    20 +-
 src/cmd/pprof/internal/commands/commands.go        |   235 -
 src/cmd/pprof/internal/driver/driver.go            |  1042 -
 src/cmd/pprof/internal/driver/interactive.go       |   492 -
 src/cmd/pprof/internal/fetch/fetch.go              |    98 -
 src/cmd/pprof/internal/plugin/plugin.go            |   213 -
 src/cmd/pprof/internal/report/report.go            |  1726 -
 src/cmd/pprof/internal/report/source.go            |   454 -
 src/cmd/pprof/internal/report/source_html.go       |    77 -
 src/cmd/pprof/internal/svg/svg.go                  |    71 -
 src/cmd/pprof/internal/svg/svgpan.go               |   291 -
 src/cmd/pprof/internal/symbolizer/symbolizer.go    |   195 -
 src/cmd/pprof/internal/symbolz/symbolz.go          |   111 -
 src/cmd/pprof/internal/tempfile/tempfile.go        |    46 -
 src/cmd/pprof/pprof.go                             |   203 +-
 src/cmd/trace/doc.go                               |    35 +
 src/cmd/trace/main.go                              |    27 +-
 src/cmd/trace/pprof.go                             |     3 +-
 src/cmd/trace/trace.go                             |   101 +-
 src/cmd/trace/trace_test.go                        |    41 +
 src/cmd/vendor/github.com/google/pprof/AUTHORS     |     7 +
 .../vendor/github.com/google/pprof/CONTRIBUTING    |    27 +
 .../vendor/github.com/google/pprof/CONTRIBUTORS    |    14 +
 src/cmd/vendor/github.com/google/pprof/LICENSE     |   202 +
 src/cmd/vendor/github.com/google/pprof/README.md   |    86 +
 .../google/pprof/doc/developer/pprof.dev.md        |    14 +
 .../google/pprof/doc/developer/profile.proto.md    |   147 +
 .../vendor/github.com/google/pprof/doc/pprof.md    |   210 +
 .../github.com/google/pprof/driver/driver.go       |   281 +
 .../google/pprof/internal/binutils/addr2liner.go   |   222 +
 .../pprof/internal/binutils/addr2liner_llvm.go     |   170 +
 .../pprof/internal/binutils/addr2liner_nm.go       |   123 +
 .../google/pprof/internal/binutils/binutils.go     |   305 +
 .../pprof/internal/binutils/binutils_test.go       |   152 +
 .../google/pprof/internal/binutils/disasm.go       |   147 +
 .../google/pprof/internal/binutils/disasm_test.go  |   154 +
 .../github.com/google/pprof/internal/driver/cli.go |   272 +
 .../google/pprof/internal/driver/commands.go       |   561 +
 .../google/pprof/internal/driver/driver.go         |   287 +
 .../google/pprof/internal/driver/driver_focus.go   |   174 +
 .../google/pprof/internal/driver/driver_test.go    |  1095 +
 .../google/pprof/internal/driver/fetch.go          |   542 +
 .../google/pprof/internal/driver/fetch_test.go     |   229 +
 .../google/pprof/internal/driver/interactive.go    |   430 +
 .../pprof/internal/driver/interactive_test.go      |   325 +
 .../google/pprof/internal/driver/options.go        |   148 +
 .../google/pprof/internal/driver/tempfile.go       |    54 +
 .../pprof/internal/driver/testdata/cppbench.cpu    |   Bin 0 -> 24405 bytes
 .../pprof/internal/driver/testdata/file1000.src    |    17 +
 .../pprof/internal/driver/testdata/file2000.src    |    17 +
 .../pprof/internal/driver/testdata/file3000.src    |    17 +
 .../pprof/internal/driver/testdata/go.crc32.cpu    |   Bin 0 -> 5032 bytes
 .../internal/driver/testdata/go.nomappings.crash   |   Bin 0 -> 232 bytes
 .../driver/testdata/pprof.contention.cum.files.dot |    10 +
 ...prof.contention.flat.addresses.dot.focus.ignore |     9 +
 .../internal/driver/testdata/pprof.cpu.callgrind   |    88 +
 .../internal/driver/testdata/pprof.cpu.comments    |     0
 .../driver/testdata/pprof.cpu.cum.lines.text.hide  |     5 +
 .../driver/testdata/pprof.cpu.cum.lines.text.show  |     5 +
 .../testdata/pprof.cpu.cum.lines.topproto.hide     |     3 +
 .../testdata/pprof.cpu.flat.addresses.disasm       |    14 +
 .../testdata/pprof.cpu.flat.addresses.weblist      |   109 +
 .../driver/testdata/pprof.cpu.flat.functions.dot   |    20 +
 .../driver/testdata/pprof.cpu.flat.functions.text  |     8 +
 .../pprof/internal/driver/testdata/pprof.cpu.peek  |    13 +
 .../pprof/internal/driver/testdata/pprof.cpu.tags  |    13 +
 .../driver/testdata/pprof.cpu.tags.focus.ignore    |     6 +
 .../internal/driver/testdata/pprof.cpu.traces      |    32 +
 .../testdata/pprof.cpusmall.flat.addresses.tree    |    17 +
 .../internal/driver/testdata/pprof.heap.callgrind  |    88 +
 .../internal/driver/testdata/pprof.heap.comments   |     2 +
 .../testdata/pprof.heap.cum.lines.tree.focus       |    19 +
 .../pprof.heap.cum.relative_percentages.tree.focus |    19 +
 .../testdata/pprof.heap.flat.files.seconds.text    |     2 +
 .../driver/testdata/pprof.heap.flat.files.text     |     5 +
 .../testdata/pprof.heap.flat.inuse_objects.text    |     8 +
 .../testdata/pprof.heap.flat.inuse_space.dot.focus |    13 +
 .../pprof.heap.flat.inuse_space.dot.focus.ignore   |    16 +
 .../testdata/pprof.heap.flat.lines.dot.focus       |    21 +
 .../pprof/internal/driver/testdata/pprof.heap.tags |     6 +
 .../internal/driver/testdata/pprof.heap.tags.unit  |     6 +
 .../pprof.heap_alloc.flat.alloc_objects.text       |     8 +
 .../pprof.heap_alloc.flat.alloc_space.dot.focus    |    18 +
 .../pprof.heap_alloc.flat.alloc_space.dot.hide     |    11 +
 .../testdata/pprof.unknown.flat.functions.text     |     8 +
 .../google/pprof/internal/elfexec/elfexec.go       |   256 +
 .../google/pprof/internal/elfexec/elfexec_test.go  |    92 +
 .../google/pprof/internal/graph/dotgraph.go        |   483 +
 .../google/pprof/internal/graph/dotgraph_test.go   |   282 +
 .../google/pprof/internal/graph/graph.go           |  1134 +
 .../google/pprof/internal/graph/graph_test.go      |   314 +
 .../pprof/internal/graph/testdata/compose1.dot     |     7 +
 .../pprof/internal/graph/testdata/compose2.dot     |     7 +
 .../pprof/internal/graph/testdata/compose3.dot     |    11 +
 .../pprof/internal/graph/testdata/compose4.dot     |     4 +
 .../pprof/internal/graph/testdata/compose5.dot     |    11 +
 .../pprof/internal/measurement/measurement.go      |   299 +
 .../google/pprof/internal/plugin/plugin.go         |   187 +
 .../google/pprof/internal/proftest/proftest.go     |   106 +
 .../google/pprof/internal/report/report.go         |  1167 +
 .../google/pprof/internal/report/report_test.go    |   266 +
 .../google/pprof/internal/report/source.go         |   494 +
 .../google/pprof/internal/report/source_html.go    |    87 +
 .../pprof/internal/report/testdata/source.dot      |    17 +
 .../pprof/internal/report/testdata/source.rpt      |    49 +
 .../google/pprof/internal/report/testdata/source1  |    19 +
 .../google/pprof/internal/report/testdata/source2  |    19 +
 .../google/pprof/internal/symbolizer/symbolizer.go |   356 +
 .../pprof/internal/symbolizer/symbolizer_test.go   |   260 +
 .../google/pprof/internal/symbolz/symbolz.go       |   161 +
 .../google/pprof/internal/symbolz/symbolz_test.go  |   100 +
 src/cmd/vendor/github.com/google/pprof/pprof.go    |    31 +
 .../github.com/google/pprof/profile/encode.go      |   526 +
 .../github.com/google/pprof/profile/filter.go      |   201 +
 .../github.com/google/pprof/profile/index.go       |    64 +
 .../github.com/google/pprof/profile/index_test.go  |   114 +
 .../google/pprof/profile/legacy_java_profile.go    |   312 +
 .../google/pprof/profile/legacy_profile.go         |  1224 +
 .../google/pprof/profile/legacy_profile_test.go    |   319 +
 .../github.com/google/pprof/profile/merge.go       |   443 +
 .../github.com/google/pprof/profile/profile.go     |   619 +
 .../google/pprof/profile/profile_test.go           |   521 +
 .../github.com/google/pprof/profile/proto.go       |   375 +
 .../github.com/google/pprof/profile/proto_test.go  |   146 +
 .../github.com/google/pprof/profile/prune.go       |   155 +
 .../github.com/google/pprof/profile/prune_test.go  |   139 +
 .../pprof/profile/testdata/cppbench.contention     |    24 +
 .../profile/testdata/cppbench.contention.string    |    65 +
 .../google/pprof/profile/testdata/cppbench.cpu     |   Bin 0 -> 23631 bytes
 .../pprof/profile/testdata/cppbench.cpu.string     |   179 +
 .../google/pprof/profile/testdata/cppbench.growth  |    99 +
 .../pprof/profile/testdata/cppbench.growth.string  |   248 +
 .../google/pprof/profile/testdata/cppbench.heap    |    47 +
 .../pprof/profile/testdata/cppbench.heap.string    |   237 +
 .../google/pprof/profile/testdata/cppbench.thread  |    29 +
 .../pprof/profile/testdata/cppbench.thread.all     |    33 +
 .../profile/testdata/cppbench.thread.all.string    |    28 +
 .../pprof/profile/testdata/cppbench.thread.none    |    27 +
 .../profile/testdata/cppbench.thread.none.string   |    50 +
 .../pprof/profile/testdata/cppbench.thread.string  |    33 +
 .../google/pprof/profile/testdata/go.crc32.cpu     |   Bin 0 -> 5032 bytes
 .../pprof/profile/testdata/go.crc32.cpu.string     |    87 +
 .../google/pprof/profile/testdata/go.godoc.thread  |     8 +
 .../pprof/profile/testdata/go.godoc.thread.string  |    37 +
 .../google/pprof/profile/testdata/gobench.cpu      |   Bin 0 -> 8248 bytes
 .../pprof/profile/testdata/gobench.cpu.string      |   415 +
 .../google/pprof/profile/testdata/gobench.heap     |    16 +
 .../pprof/profile/testdata/gobench.heap.string     |   137 +
 .../google/pprof/profile/testdata/java.contention  |    43 +
 .../pprof/profile/testdata/java.contention.string  |    43 +
 .../google/pprof/profile/testdata/java.cpu         |   Bin 0 -> 3537 bytes
 .../google/pprof/profile/testdata/java.cpu.string  |    78 +
 .../google/pprof/profile/testdata/java.heap        |   133 +
 .../google/pprof/profile/testdata/java.heap.string |   139 +
 .../github.com/google/pprof/proto/profile.proto    |   183 +
 .../github.com/google/pprof/third_party/svg/svg.go |    79 +
 .../google/pprof/third_party/svg/svgpan.go         |   291 +
 .../github.com/ianlancetaylor/demangle/.gitignore  |    13 +
 .../github.com/ianlancetaylor/demangle/LICENSE     |    27 +
 .../github.com/ianlancetaylor/demangle/README.md   |     3 +
 .../github.com/ianlancetaylor/demangle/ast.go      |  2879 ++
 .../github.com/ianlancetaylor/demangle/ast_test.go |    42 +
 .../github.com/ianlancetaylor/demangle/c++filt.go  |   144 +
 .../github.com/ianlancetaylor/demangle/demangle.go |  2501 +
 .../ianlancetaylor/demangle/demangle_test.go       |   420 +
 .../ianlancetaylor/demangle/expected_test.go       |   183 +
 .../demangle/testdata/demangle-expected            |  4594 ++
 .../vendor/golang.org/x/arch/x86/x86asm/decode.go  |    90 +-
 src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go |     4 +-
 .../vendor/golang.org/x/arch/x86/x86asm/inst.go    |    16 +-
 .../vendor/golang.org/x/arch/x86/x86asm/intel.go   |    16 +-
 .../vendor/golang.org/x/arch/x86/x86asm/plan9x.go  |    22 +-
 .../vendor/golang.org/x/arch/x86/x86asm/tables.go  |  6408 +--
 .../x/arch/x86/x86asm/testdata/decode.txt          |   338 +-
 src/cmd/vendor/vendor.json                         |    16 +-
 src/cmd/vet/all/main.go                            |    86 +-
 src/cmd/vet/all/whitelist/64bit.txt                |    13 -
 src/cmd/vet/all/whitelist/all.txt                  |    42 +-
 src/cmd/vet/all/whitelist/amd64.txt                |     6 +-
 src/cmd/vet/all/whitelist/darwin_386.txt           |     1 +
 src/cmd/vet/all/whitelist/darwin_amd64.txt         |     1 +
 src/cmd/vet/all/whitelist/mips.txt                 |     7 +
 src/cmd/vet/all/whitelist/mipsle.txt               |     7 +
 src/cmd/vet/all/whitelist/mipsx.txt                |    11 +
 src/cmd/vet/all/whitelist/windows.txt              |     4 +
 src/cmd/vet/all/whitelist/windows_386.txt          |     1 +
 src/cmd/vet/all/whitelist/windows_amd64.txt        |     1 +
 src/cmd/vet/asmdecl.go                             |    77 +-
 src/cmd/vet/buildtag.go                            |     2 +
 src/cmd/vet/dead.go                                |   108 +
 src/cmd/vet/doc.go                                 |     3 +
 src/cmd/vet/httpresponse.go                        |    20 +-
 src/cmd/vet/lostcancel.go                          |     6 +-
 src/cmd/vet/main.go                                |    15 +-
 src/cmd/vet/method.go                              |     1 -
 src/cmd/vet/shift.go                               |    22 +-
 src/cmd/vet/testdata/copylock_func.go              |     6 +-
 src/cmd/vet/testdata/print.go                      |    13 +
 src/cmd/vet/testdata/shift.go                      |   169 +-
 src/cmd/vet/types.go                               |    35 +-
 src/compress/bzip2/bzip2_test.go                   |    24 +-
 src/compress/bzip2/huffman.go                      |     4 -
 src/compress/flate/huffman_code.go                 |     5 +
 src/compress/flate/inflate.go                      |     7 +-
 src/compress/flate/reverse_bits.go                 |    48 -
 src/compress/gzip/gzip.go                          |     5 +-
 src/compress/lzw/reader.go                         |    14 +-
 src/compress/lzw/reader_test.go                    |    97 +
 src/container/heap/heap.go                         |     7 +-
 src/context/context.go                             |    40 +-
 src/context/context_test.go                        |     2 +-
 src/crypto/aes/asm_ppc64le.s                       |   499 +
 src/crypto/aes/cipher_generic.go                   |     2 +-
 src/crypto/aes/cipher_ppc64le.go                   |    80 +
 src/crypto/crypto.go                               |    68 +-
 src/crypto/des/block.go                            |   114 +-
 src/crypto/des/cipher.go                           |    51 +-
 src/crypto/des/const.go                            |     3 +
 src/crypto/des/des_test.go                         |    39 +-
 src/crypto/dsa/dsa_test.go                         |    17 +-
 src/crypto/md5/md5.go                              |     3 +
 src/crypto/rand/rand_linux.go                      |    28 +-
 src/crypto/rand/util.go                            |    17 +-
 src/crypto/rand/util_test.go                       |    53 +
 src/crypto/rc4/rc4.go                              |     6 +-
 src/crypto/sha1/sha1.go                            |    11 +-
 src/crypto/sha1/sha1_test.go                       |     2 +-
 src/crypto/sha1/sha1block.go                       |     2 +-
 src/crypto/sha1/sha1block_386.s                    |     2 +-
 src/crypto/sha1/sha1block_amd64.go                 |     8 +-
 src/crypto/sha1/sha1block_amd64.s                  |    19 +-
 src/crypto/sha1/sha1block_amd64p32.s               |     2 +-
 src/crypto/sha1/sha1block_arm.s                    |    16 +-
 src/crypto/sha1/sha1block_s390x.go                 |     2 +-
 src/crypto/sha1/sha1block_s390x.s                  |     4 +-
 src/crypto/sha256/sha256block_amd64.go             |     9 +
 src/crypto/sha256/sha256block_amd64.s              |     5 +-
 src/crypto/sha256/sha256block_ppc64le.s            |   569 +-
 src/crypto/sha512/sha512block_amd64.go             |    25 +
 src/crypto/sha512/sha512block_amd64.s              |  1203 +-
 src/crypto/sha512/sha512block_decl.go              |     2 +-
 src/crypto/sha512/sha512block_ppc64le.s            |   609 +-
 src/crypto/tls/common.go                           |    36 +-
 src/crypto/tls/conn.go                             |     2 +-
 src/crypto/tls/conn_test.go                        |    41 +-
 src/crypto/tls/generate_cert.go                    |     2 +-
 src/crypto/tls/handshake_client.go                 |     2 +-
 src/crypto/tls/handshake_messages.go               |    11 +-
 src/crypto/tls/handshake_messages_test.go          |     4 +
 src/crypto/tls/handshake_server.go                 |     8 +-
 src/crypto/tls/handshake_server_test.go            |     4 +
 src/crypto/x509/pkcs1.go                           |    12 +-
 src/crypto/x509/root_bsd.go                        |     3 +-
 src/crypto/x509/root_unix.go                       |    34 +-
 src/crypto/x509/root_unix_test.go                  |   127 +
 src/crypto/x509/test-file.crt                      |    32 +
 src/crypto/x509/testdata/test-dir.crt              |    31 +
 src/crypto/x509/verify.go                          |    12 +-
 src/crypto/x509/verify_test.go                     |   219 +-
 src/crypto/x509/x509.go                            |   111 +-
 src/crypto/x509/x509_test.go                       |     5 +
 src/database/sql/convert.go                        |   215 +-
 src/database/sql/convert_test.go                   |    18 +-
 src/database/sql/driver/driver.go                  |    30 +
 src/database/sql/fakedb_test.go                    |    94 +-
 src/database/sql/sql.go                            |   682 +-
 src/database/sql/sql_test.go                       |   650 +-
 src/debug/dwarf/export_test.go                     |     7 +
 src/debug/dwarf/line.go                            |    74 +-
 src/debug/dwarf/line_test.go                       |    85 +
 src/debug/dwarf/testdata/line-gcc-win.bin          |   Bin 0 -> 133202 bytes
 src/debug/dwarf/type_test.go                       |    14 +
 src/debug/pe/file_cgo_test.go                      |    31 +
 src/debug/pe/file_test.go                          |   141 +-
 src/encoding/asn1/asn1.go                          |    35 +-
 src/encoding/asn1/asn1_test.go                     |    29 +
 src/encoding/asn1/common.go                        |     1 +
 src/encoding/asn1/marshal.go                       |    10 +-
 src/encoding/base32/base32.go                      |   133 +-
 src/encoding/base32/base32_test.go                 |   185 +
 src/encoding/base64/base64.go                      |    62 +-
 src/encoding/base64/base64_test.go                 |    29 +-
 src/encoding/binary/binary_test.go                 |    24 +
 src/encoding/csv/reader.go                         |    69 +-
 src/encoding/csv/reader_test.go                    |    31 +
 src/encoding/gob/codec_test.go                     |    74 +-
 src/encoding/gob/decode.go                         |    49 +-
 src/encoding/gob/doc.go                            |     6 +
 src/encoding/gob/encode.go                         |    30 +-
 src/encoding/gob/encoder_test.go                   |    65 +
 src/encoding/gob/error.go                          |     1 -
 src/encoding/gob/gobencdec_test.go                 |     2 +-
 src/encoding/gob/timing_test.go                    |   188 +-
 src/encoding/gob/type.go                           |    56 +-
 src/encoding/gob/type_test.go                      |     6 +-
 src/encoding/hex/hex.go                            |     5 +-
 src/encoding/json/bench_test.go                    |   137 +-
 src/encoding/json/decode.go                        |    69 +-
 src/encoding/json/encode.go                        |    36 +-
 src/encoding/json/encode_test.go                   |    53 +
 src/encoding/json/scanner.go                       |     5 +
 src/encoding/json/scanner_test.go                  |    20 +
 src/encoding/json/stream_test.go                   |    10 +-
 src/encoding/pem/pem.go                            |    10 +-
 src/encoding/pem/pem_test.go                       |    34 +-
 src/encoding/xml/marshal_test.go                   |   100 +-
 src/encoding/xml/read.go                           |    28 +-
 src/encoding/xml/read_test.go                      |   156 +
 src/encoding/xml/typeinfo.go                       |    20 +-
 src/encoding/xml/xml_test.go                       |    34 -
 src/expvar/expvar.go                               |   142 +-
 src/expvar/expvar_test.go                          |   168 +-
 src/flag/flag.go                                   |     4 +-
 src/flag/flag_test.go                              |    17 +
 src/fmt/doc.go                                     |    10 +-
 src/fmt/fmt_test.go                                |    42 +
 src/fmt/format.go                                  |    40 +
 src/fmt/print.go                                   |     2 -
 src/go/ast/ast.go                                  |     1 +
 src/go/build/build.go                              |    84 +-
 src/go/build/build_test.go                         |    38 +-
 src/go/build/deps_test.go                          |   134 +-
 src/go/build/doc.go                                |     1 +
 src/go/constant/value.go                           |    16 +-
 src/go/constant/value_test.go                      |     3 +-
 src/go/doc/comment.go                              |    19 +-
 src/go/doc/comment_test.go                         |     6 +
 src/go/doc/doc_test.go                             |     5 +-
 src/go/doc/exports.go                              |     4 +-
 src/go/format/internal.go                          |     8 +-
 src/go/importer/importer.go                        |    32 +-
 src/go/internal/gccgoimporter/importer_test.go     |     1 +
 src/go/internal/gccgoimporter/parser.go            |    50 +-
 src/go/internal/gccgoimporter/testdata/alias.gox   |     4 +
 src/go/internal/gcimporter/bimport.go              |   208 +-
 src/go/internal/gcimporter/gcimporter.go           |     3 +-
 src/go/internal/gcimporter/gcimporter_test.go      |    70 +-
 src/go/internal/gcimporter/testdata/issue20046.go  |     9 +
 .../gcimporter/testdata/versions/test_go1.8_4.a    |   Bin 0 -> 1658 bytes
 .../gcimporter/testdata/versions/test_go1.8_5.a    |   Bin 0 -> 1658 bytes
 src/go/internal/srcimporter/srcimporter.go         |   208 +
 src/go/internal/srcimporter/srcimporter_test.go    |   150 +
 src/go/parser/error_test.go                        |     4 +-
 src/go/parser/example_test.go                      |    19 +-
 src/go/parser/parser.go                            |     7 +-
 src/go/parser/parser_test.go                       |    15 +
 src/go/parser/performance_test.go                  |    13 +-
 src/go/parser/short_test.go                        |     2 +
 src/go/printer/nodes.go                            |     7 +-
 src/go/printer/printer.go                          |    59 +-
 src/go/printer/printer_test.go                     |   102 +-
 src/go/printer/testdata/declarations.golden        |    15 +
 src/go/printer/testdata/declarations.input         |    15 +
 src/go/token/position.go                           |    37 +-
 src/go/token/serialize.go                          |    19 +-
 src/go/types/api.go                                |    28 +-
 src/go/types/api_test.go                           |   185 +-
 src/go/types/assignments.go                        |     4 +-
 src/go/types/call.go                               |    14 +-
 src/go/types/check.go                              |    14 +-
 src/go/types/check_test.go                         |     2 +-
 src/go/types/decl.go                               |   194 +-
 src/go/types/example_test.go                       |     4 +-
 src/go/types/expr.go                               |    41 +-
 src/go/types/gotype.go                             |   190 +-
 src/go/types/hilbert_test.go                       |     3 +-
 src/go/types/lookup.go                             |    83 +-
 src/go/types/methodset.go                          |    52 +-
 src/go/types/object.go                             |   109 +-
 src/go/types/object_test.go                        |    44 +
 src/go/types/package.go                            |     8 +-
 src/go/types/predicates.go                         |     2 +-
 src/go/types/resolver.go                           |   133 +-
 src/go/types/sizes.go                              |    37 +-
 src/go/types/stdlib_test.go                        |    18 +-
 src/go/types/testdata/builtins.src                 |     1 +
 src/go/types/testdata/decls1.src                   |     2 +-
 src/go/types/testdata/decls4.src                   |   150 +
 src/go/types/testdata/expr3.src                    |     2 +-
 src/go/types/testdata/issues.src                   |    25 +-
 src/go/types/testdata/shifts.src                   |    18 +-
 src/go/types/testdata/stmt0.src                    |    20 +-
 src/go/types/testdata/vardecl.src                  |    18 +-
 src/go/types/type.go                               |     2 +-
 src/go/types/typestring.go                         |     1 +
 src/go/types/typestring_test.go                    |     4 +-
 src/go/types/typexpr.go                            |    66 +-
 src/hash/crc32/crc32_amd64.go                      |    30 +-
 src/hash/crc32/crc32_amd64.s                       |    30 -
 src/hash/crc32/crc32_amd64p32.go                   |    14 +-
 src/hash/crc32/crc32_amd64p32.s                    |    11 -
 src/hash/crc32/crc32_arm64.go                      |    51 +
 src/hash/crc32/crc32_arm64.s                       |    97 +
 src/hash/crc32/crc32_otherarch.go                  |     2 +-
 src/hash/crc32/crc32_ppc64le.go                    |    87 +
 src/hash/crc32/crc32_ppc64le.s                     |   707 +
 src/hash/crc32/crc32_s390x.s                       |     2 +-
 src/hash/crc32/crc32_table_ppc64le.s               |  3286 ++
 src/hash/crc32/crc32_test.go                       |    86 +-
 src/hash/crc32/gen_const_ppc64le.go                |   150 +
 src/hash/fnv/fnv.go                                |   122 +-
 src/hash/fnv/fnv_test.go                           |    39 +
 src/html/template/attr.go                          |     3 +-
 src/html/template/doc.go                           |     4 +-
 src/html/template/error.go                         |    28 +
 src/html/template/escape.go                        |   194 +-
 src/html/template/escape_test.go                   |   160 +-
 src/html/template/js.go                            |     2 +-
 src/html/template/template.go                      |     7 +-
 src/html/template/transition.go                    |     4 +-
 src/image/color/ycbcr.go                           |    58 +-
 src/image/geom.go                                  |     6 +-
 src/image/geom_test.go                             |     7 +-
 src/image/gif/reader.go                            |    45 +-
 src/image/gif/reader_test.go                       |    63 +-
 src/image/gif/writer.go                            |    37 +-
 src/image/gif/writer_test.go                       |    33 +
 src/image/image_test.go                            |    12 +-
 src/image/internal/imageutil/gen.go                |     2 +-
 src/image/internal/imageutil/impl.go               |     8 +-
 src/image/jpeg/huffman.go                          |     3 +-
 src/image/jpeg/reader.go                           |    17 +-
 src/image/jpeg/scan.go                             |    10 +-
 src/image/jpeg/writer.go                           |    29 +-
 src/image/jpeg/writer_test.go                      |    58 +-
 src/image/png/reader.go                            |    17 +-
 src/image/png/reader_test.go                       |    71 +-
 src/image/png/writer.go                            |   106 +-
 src/image/png/writer_test.go                       |    25 +
 src/internal/cpu/cpu.go                            |    32 +
 src/internal/cpu/cpu_arm.go                        |     7 +
 src/internal/cpu/cpu_arm64.go                      |     7 +
 src/internal/cpu/cpu_mips.go                       |     7 +
 src/internal/cpu/cpu_mips64.go                     |     7 +
 src/internal/cpu/cpu_mips64le.go                   |     7 +
 src/internal/cpu/cpu_mipsle.go                     |     7 +
 src/internal/cpu/cpu_ppc64.go                      |     7 +
 src/internal/cpu/cpu_ppc64le.go                    |     7 +
 src/internal/cpu/cpu_s390x.go                      |     7 +
 src/internal/cpu/cpu_test.go                       |    27 +
 src/internal/cpu/cpu_x86.go                        |    59 +
 src/internal/cpu/cpu_x86.s                         |    32 +
 src/internal/poll/export_posix_test.go             |    15 +
 src/internal/poll/export_test.go                   |    35 +
 src/internal/poll/fd.go                            |    57 +
 src/internal/poll/fd_io_plan9.go                   |    91 +
 src/internal/poll/fd_mutex.go                      |   250 +
 src/internal/poll/fd_mutex_test.go                 |   196 +
 src/internal/poll/fd_plan9.go                      |   216 +
 src/internal/poll/fd_poll_nacl.go                  |    92 +
 src/internal/poll/fd_poll_runtime.go               |   158 +
 src/internal/poll/fd_posix.go                      |    57 +
 src/internal/poll/fd_posix_test.go                 |    43 +
 src/internal/poll/fd_unix.go                       |   450 +
 src/internal/poll/fd_windows.go                    |   856 +
 src/internal/poll/hook_cloexec.go                  |    12 +
 src/internal/poll/hook_unix.go                     |    15 +
 src/internal/poll/hook_windows.go                  |    16 +
 src/internal/poll/sendfile_bsd.go                  |    53 +
 src/internal/poll/sendfile_linux.go                |    50 +
 src/internal/poll/sendfile_solaris.go              |    66 +
 src/internal/poll/sendfile_windows.go              |    23 +
 src/internal/poll/sock_cloexec.go                  |    50 +
 src/internal/poll/sockopt.go                       |    36 +
 src/internal/poll/sockopt_linux.go                 |    16 +
 src/internal/poll/sockopt_unix.go                  |    18 +
 src/internal/poll/sockopt_windows.go               |    25 +
 src/internal/poll/sockoptip.go                     |    27 +
 src/internal/poll/strconv.go                       |    41 +
 src/internal/poll/sys_cloexec.go                   |    36 +
 src/internal/poll/writev.go                        |    83 +
 src/internal/poll/writev_test.go                   |    62 +
 src/internal/pprof/profile/profile.go              |   572 -
 src/internal/testenv/testenv.go                    |    13 +
 src/internal/testenv/testenv_windows.go            |     1 -
 src/internal/trace/parser.go                       |   221 +-
 src/internal/trace/testdata/http_1_9_good          |   Bin 0 -> 2187 bytes
 src/internal/trace/testdata/stress_1_9_good        |   Bin 0 -> 365129 bytes
 .../trace/testdata/stress_start_stop_1_9_good      |   Bin 0 -> 6271 bytes
 src/internal/trace/writer.go                       |     2 +-
 src/io/ioutil/tempfile_test.go                     |    13 +-
 src/io/multi_test.go                               |    24 +-
 src/iostest.bash                                   |     6 +-
 src/log/log.go                                     |    18 +-
 src/log/log_test.go                                |    10 +
 src/log/syslog/syslog.go                           |    15 +-
 src/make.bash                                      |    19 +-
 src/math/acos_s390x.s                              |   144 +
 src/math/acosh.go                                  |     4 +-
 src/math/acosh_s390x.s                             |   172 +
 src/math/all_test.go                               |   347 +-
 src/math/arith_s390x.go                            |    48 +
 src/math/arith_s390x_test.go                       |   298 +
 src/math/asin_s390x.s                              |   162 +
 src/math/asinh.go                                  |     4 +-
 src/math/asinh_s390x.s                             |   223 +
 src/math/asinh_stub.s                              |    17 +
 src/math/atan2_s390x.s                             |   302 +
 src/math/atan_s390x.s                              |   132 +
 src/math/atanh.go                                  |     4 +-
 src/math/atanh_s390x.s                             |   178 +
 src/math/big/arith.go                              |    63 +-
 src/math/big/arith_386.s                           |    11 -
 src/math/big/arith_amd64.s                         |    11 -
 src/math/big/arith_amd64p32.s                      |     3 -
 src/math/big/arith_arm.s                           |     8 -
 src/math/big/arith_arm64.s                         |    10 -
 src/math/big/arith_decl.go                         |     1 -
 src/math/big/arith_decl_pure.go                    |     4 -
 src/math/big/arith_mips64x.s                       |     3 -
 src/math/big/arith_mipsx.s                         |     3 -
 src/math/big/arith_ppc64.s                         |    14 -
 src/math/big/arith_ppc64le.s                       |    50 -
 src/math/big/arith_ppc64x.s                        |    97 +-
 src/math/big/arith_s390x.s                         |    10 -
 src/math/big/arith_s390x_test.go                   |     2 +-
 src/math/big/arith_test.go                         |    29 -
 src/math/big/float.go                              |    20 +-
 src/math/big/float_test.go                         |    28 +
 src/math/big/floatconv_test.go                     |    29 +-
 src/math/big/int.go                                |    36 +-
 src/math/big/int_test.go                           |   125 +-
 src/math/big/nat.go                                |    63 +-
 src/math/big/nat_test.go                           |    30 -
 src/math/big/natconv.go                            |     3 +-
 src/math/big/natconv_test.go                       |     8 +
 src/math/big/prime_test.go                         |     2 +-
 src/math/bits/bits.go                              |   330 +
 src/math/bits/bits_tables.go                       |    83 +
 src/math/bits/bits_test.go                         |   747 +
 src/math/bits/make_tables.go                       |    92 +
 src/math/cbrt.go                                   |     4 +-
 src/math/cbrt_s390x.s                              |   162 +
 src/math/cbrt_stub.s                               |    11 +
 src/math/const.go                                  |     2 +
 src/math/cosh_s390x.s                              |    28 +-
 src/math/erf.go                                    |     8 +-
 src/math/erf_s390x.s                               |   299 +
 src/math/erf_stub.s                                |    14 +
 src/math/erfc_s390x.s                              |   530 +
 src/math/exp_amd64.s                               |     7 +-
 src/math/exp_s390x.s                               |   185 +
 src/math/expm1_s390x.s                             |   202 +
 src/math/export_s390x_test.go                      |    17 +
 src/math/floor_amd64.s                             |    15 +-
 src/math/floor_asm.go                              |     5 +-
 src/math/jn.go                                     |     6 +-
 src/math/log10_s390x.s                             |     4 +-
 src/math/log1p_s390x.s                             |   186 +
 src/math/log_amd64.s                               |     1 +
 src/math/log_s390x.s                               |   180 +
 src/math/pow.go                                    |     4 +-
 src/math/pow10.go                                  |    56 +-
 src/math/pow_s390x.s                               |   666 +
 src/math/pow_stub.s                                |    11 +
 src/math/sin_s390x.s                               |    20 +-
 src/math/sincos.go                                 |     6 +-
 src/math/sincos_386.go                             |    13 +
 src/math/sincos_amd64.s                            |   142 -
 src/math/sincos_amd64p32.s                         |     5 -
 src/math/sincos_arm.s                              |     8 -
 src/math/sinh_s390x.s                              |    18 +-
 src/math/stubs_arm64.s                             |    24 +-
 src/math/stubs_mips64x.s                           |    24 +-
 src/math/stubs_mipsx.s                             |    24 +-
 src/math/stubs_ppc64x.s                            |    25 +-
 src/math/stubs_s390x.s                             |   426 +-
 src/math/tan_s390x.s                               |   110 +
 src/math/tanh_s390x.s                              |    12 +-
 src/mime/encodedword.go                            |    20 +-
 src/mime/encodedword_test.go                       |     3 +
 src/mime/mediatype.go                              |    10 +-
 src/mime/mediatype_test.go                         |    18 +-
 src/mime/multipart/formdata.go                     |    26 +-
 src/mime/multipart/formdata_test.go                |    48 +-
 src/mime/multipart/writer.go                       |    11 +-
 src/mime/multipart/writer_test.go                  |    19 +-
 src/mime/type.go                                   |   108 +-
 src/mime/type_test.go                              |    40 +
 src/net/cgo_unix.go                                |     4 +-
 src/net/dial.go                                    |    48 +-
 src/net/dial_test.go                               |   118 +-
 src/net/dnsclient_unix.go                          |   118 +-
 src/net/dnsclient_unix_test.go                     |   620 +-
 src/net/error_posix.go                             |    21 +
 src/net/error_test.go                              |    42 +-
 src/net/example_test.go                            |    71 +
 src/net/external_test.go                           |     4 +-
 src/net/fd_io_plan9.go                             |    93 -
 src/net/fd_mutex.go                                |   249 -
 src/net/fd_mutex_test.go                           |   195 -
 src/net/fd_plan9.go                                |   152 +-
 src/net/fd_poll_nacl.go                            |    89 -
 src/net/fd_poll_runtime.go                         |   141 -
 src/net/fd_posix.go                                |    21 -
 src/net/fd_posix_test.go                           |    57 -
 src/net/fd_unix.go                                 |   313 +-
 src/net/fd_windows.go                              |   555 +-
 src/net/file_test.go                               |     4 +-
 src/net/file_unix.go                               |     9 +-
 src/net/hook_cloexec.go                            |    14 -
 src/net/hook_unix.go                               |    10 +-
 src/net/hook_windows.go                            |     9 +-
 src/net/http/cgi/host_test.go                      |     2 +-
 src/net/http/cgi/plan9_test.go                     |     3 +-
 src/net/http/cgi/posix_test.go                     |     3 +-
 src/net/http/client.go                             |    31 +-
 src/net/http/client_test.go                        |   185 +-
 src/net/http/cookie.go                             |     2 +-
 src/net/http/cookie_test.go                        |     9 +-
 src/net/http/cookiejar/jar.go                      |     5 +-
 src/net/http/cookiejar/jar_test.go                 |    57 +-
 src/net/http/export_test.go                        |    33 +-
 src/net/http/fcgi/child.go                         |    56 +
 src/net/http/fcgi/fcgi.go                          |     2 +-
 src/net/http/fcgi/fcgi_test.go                     |    66 +
 src/net/http/filetransport_test.go                 |     1 +
 src/net/http/fs.go                                 |    44 +-
 src/net/http/fs_test.go                            |    76 +-
 src/net/http/h2_bundle.go                          |  2302 +-
 src/net/http/httptest/example_test.go              |    22 +
 src/net/http/httptest/recorder.go                  |     3 +-
 src/net/http/httptest/recorder_test.go             |    13 +-
 src/net/http/httptest/server.go                    |    42 +
 src/net/http/httptest/server_test.go               |    64 +
 src/net/http/httputil/reverseproxy.go              |    22 +-
 src/net/http/httputil/reverseproxy_test.go         |   100 +-
 src/net/http/main_test.go                          |     4 -
 src/net/http/npn_test.go                           |    24 +-
 src/net/http/pprof/pprof.go                        |    24 +-
 src/net/http/proxy_test.go                         |     8 +-
 src/net/http/request.go                            |    59 +-
 src/net/http/request_test.go                       |    23 +
 src/net/http/response.go                           |    35 +-
 src/net/http/response_test.go                      |    51 +-
 src/net/http/serve_test.go                         |   483 +-
 src/net/http/server.go                             |   259 +-
 src/net/http/sniff.go                              |     4 +-
 src/net/http/sniff_test.go                         |     4 +
 src/net/http/transfer.go                           |    32 +-
 src/net/http/transport.go                          |   250 +-
 src/net/http/transport_internal_test.go            |    31 +-
 src/net/http/transport_test.go                     |   745 +-
 src/net/interface.go                               |    16 +-
 src/net/interface_linux.go                         |     4 +-
 src/net/interface_test.go                          |     6 +-
 src/net/interface_windows.go                       |     5 +-
 src/net/internal/socktest/sys_cloexec.go           |     4 +-
 src/net/internal/socktest/sys_unix.go              |    12 +-
 src/net/ip.go                                      |    21 +-
 src/net/ip_test.go                                 |   182 +-
 src/net/iprawsock.go                               |    11 +-
 src/net/iprawsock_posix.go                         |    10 +-
 src/net/iprawsock_test.go                          |    72 +
 src/net/ipsock.go                                  |    71 +-
 src/net/ipsock_plan9.go                            |    37 +-
 src/net/ipsock_posix.go                            |   129 +-
 src/net/ipsock_test.go                             |     2 +-
 src/net/listen_test.go                             |    16 +-
 src/net/lookup.go                                  |    21 +
 src/net/lookup_test.go                             |    22 +-
 src/net/lookup_unix.go                             |    86 +-
 src/net/lookup_windows.go                          |     2 +-
 src/net/mail/message.go                            |    26 +-
 src/net/mail/message_test.go                       |    11 +
 src/net/main_cloexec_test.go                       |    10 +-
 src/net/main_test.go                               |    10 +-
 src/net/main_unix_test.go                          |    16 +-
 src/net/main_windows_test.go                       |    22 +-
 src/net/mockserver_test.go                         |    16 +-
 src/net/net.go                                     |    29 +-
 src/net/net_test.go                                |    14 +-
 src/net/net_windows_test.go                        |    81 +-
 src/net/netgo_unix_test.go                         |     2 +-
 src/net/platform_test.go                           |    14 +-
 src/net/port_unix.go                               |     3 +-
 src/net/rawconn.go                                 |    62 +
 src/net/rawconn_unix_test.go                       |    94 +
 src/net/rawconn_windows_test.go                    |    36 +
 src/net/rpc/debug.go                               |    23 +-
 src/net/rpc/jsonrpc/all_test.go                    |    58 +
 src/net/rpc/jsonrpc/client.go                      |     3 +-
 src/net/rpc/server.go                              |    36 +-
 src/net/rpc/server_test.go                         |    67 +-
 src/net/sendfile_bsd.go                            |    67 +
 src/net/sendfile_dragonfly.go                      |   106 -
 src/net/sendfile_freebsd.go                        |   106 -
 src/net/sendfile_linux.go                          |    46 +-
 src/net/sendfile_solaris.go                        |    62 +-
 src/net/sendfile_windows.go                        |    14 +-
 src/net/smtp/smtp.go                               |     2 +-
 src/net/smtp/smtp_test.go                          |     5 +
 src/net/sock_cloexec.go                            |    43 +-
 src/net/sock_posix.go                              |    25 +-
 src/net/sockopt_bsd.go                             |     2 +-
 src/net/sockopt_posix.go                           |    34 +-
 src/net/sockoptip_bsd.go                           |    20 +-
 src/net/sockoptip_linux.go                         |    18 +-
 src/net/sockoptip_posix.go                         |    34 +-
 src/net/sockoptip_windows.go                       |    17 +-
 src/net/sys_cloexec.go                             |    27 +-
 src/net/tcpsock.go                                 |    11 +-
 src/net/tcpsock_plan9.go                           |     3 +
 src/net/tcpsock_posix.go                           |     2 +-
 src/net/tcpsock_test.go                            |    12 +-
 src/net/tcpsockopt_darwin.go                       |    14 +-
 src/net/tcpsockopt_dragonfly.go                    |    14 +-
 src/net/tcpsockopt_posix.go                        |    10 +-
 src/net/tcpsockopt_solaris.go                      |    10 +-
 src/net/tcpsockopt_unix.go                         |    14 +-
 src/net/tcpsockopt_windows.go                      |     8 +-
 src/net/timeout_test.go                            |    21 +-
 src/net/udpsock.go                                 |     9 +
 src/net/udpsock_posix.go                           |     6 +-
 src/net/udpsock_test.go                            |     4 +-
 src/net/unixsock.go                                |    11 +-
 src/net/url/example_test.go                        |    54 +-
 src/net/url/url.go                                 |    23 +-
 src/net/writev_test.go                             |     7 +-
 src/net/writev_unix.go                             |    74 +-
 src/os/dir_unix.go                                 |     6 +-
 src/os/dir_windows.go                              |    10 +-
 src/os/error_posix.go                              |    18 +
 src/os/example_test.go                             |    14 +
 src/os/exec/env_test.go                            |    39 +
 src/os/exec/example_test.go                        |    12 +
 src/os/exec/exec.go                                |    52 +-
 src/os/exec/exec_posix.go                          |    24 -
 src/os/exec/exec_posix_test.go                     |    83 +
 src/os/exec/exec_test.go                           |   156 +-
 src/os/exec/exec_unix.go                           |    24 +
 src/os/exec/exec_windows.go                        |    23 +
 src/os/exec_windows.go                             |    80 +-
 src/os/export_windows_test.go                      |     6 +-
 src/os/file.go                                     |    75 +-
 src/os/file_plan9.go                               |    44 +-
 src/os/file_posix.go                               |    38 +-
 src/os/file_unix.go                                |   154 +-
 src/os/file_windows.go                             |   267 +-
 src/os/os_test.go                                  |   375 +-
 src/os/os_windows_test.go                          |   186 +-
 src/os/pipe_bsd.go                                 |     4 +-
 src/os/pipe_freebsd.go                             |    34 +
 src/os/pipe_linux.go                               |     2 +-
 src/os/pipe_test.go                                |    77 +-
 src/os/signal/doc.go                               |     9 +-
 src/os/signal/signal_plan9_test.go                 |     3 +-
 src/os/signal/signal_test.go                       |     3 +-
 src/os/signal/signal_windows_test.go               |     2 +-
 src/os/stat_unix.go                                |     2 +-
 src/os/stat_windows.go                             |   136 +-
 src/os/sys_darwin.go                               |    26 +-
 src/os/types_unix.go                               |     2 -
 src/os/types_windows.go                            |    36 +-
 src/os/user/{lookup_unix.go => cgo_lookup_unix.go} |     0
 src/os/user/lookup.go                              |    22 +-
 src/os/user/lookup_android.go                      |    13 -
 src/os/user/lookup_stubs.go                        |    38 +-
 src/os/user/lookup_unix.go                         |   366 +-
 src/os/user/lookup_unix_test.go                    |   276 +
 src/os/user/user_test.go                           |    12 +-
 src/os/wait_unimp.go                               |     2 +-
 src/os/wait_waitid.go                              |     5 +-
 src/path/example_test.go                           |    40 +-
 src/path/filepath/path.go                          |     9 +
 src/path/filepath/path_test.go                     |    57 +-
 src/path/filepath/path_windows_test.go             |    30 +-
 src/path/path.go                                   |     5 +-
 src/plugin/plugin.go                               |     3 -
 src/plugin/plugin_dlopen.go                        |    52 +-
 src/reflect/all_test.go                            |   311 +-
 src/reflect/set_test.go                            |    18 +
 src/reflect/type.go                                |   489 +-
 src/reflect/value.go                               |    30 +-
 src/regexp/all_test.go                             |    10 +-
 src/regexp/exec.go                                 |     6 +-
 src/regexp/exec_test.go                            |    29 +
 src/regexp/onepass.go                              |    42 +-
 src/regexp/onepass_test.go                         |    22 +
 src/regexp/regexp.go                               |    49 +-
 src/regexp/syntax/parse.go                         |     4 +-
 src/run.bash                                       |    18 +-
 src/runtime/HACKING.md                             |    10 +-
 src/runtime/alg.go                                 |    38 +-
 src/runtime/asm.s                                  |    21 +
 src/runtime/asm_386.s                              |   134 +-
 src/runtime/asm_amd64.s                            |   362 +-
 src/runtime/asm_amd64p32.s                         |   140 +-
 src/runtime/asm_arm.s                              |    48 +-
 src/runtime/asm_arm64.s                            |    50 -
 src/runtime/asm_mips64x.s                          |    47 -
 src/runtime/asm_mipsx.s                            |    43 -
 src/runtime/asm_ppc64x.s                           |   254 +-
 src/runtime/asm_s390x.s                            |    47 -
 src/runtime/cgo.go                                 |     4 +
 src/runtime/cgo/asm_ppc64x.s                       |     4 +
 src/runtime/cgo/callbacks.go                       |    10 +
 src/runtime/cgo/gcc_android_arm.c                  |    13 +-
 src/runtime/cgo/gcc_android_arm64.c                |     6 +-
 src/runtime/cgo/gcc_darwin_arm.c                   |    32 +-
 src/runtime/cgo/gcc_darwin_arm64.c                 |    32 +-
 src/runtime/cgo/gcc_libinit.c                      |     2 +-
 src/runtime/cgo/gcc_libinit_openbsd.c              |    74 -
 src/runtime/cgo/gcc_mmap.c                         |    14 +
 src/runtime/cgo/gcc_openbsd_386.c                  |   133 +-
 src/runtime/cgo/gcc_openbsd_amd64.c                |   133 +-
 src/runtime/cgo/gcc_sigaction.c                    |    12 +-
 src/runtime/cgo/gcc_util.c                         |    36 +
 src/runtime/cgo/libcgo.h                           |     5 +
 src/runtime/cgo/mmap.go                            |     9 +
 src/runtime/cgo/openbsd.go                         |    15 +-
 src/runtime/cgo_mmap.go                            |    20 +
 src/runtime/cgocall.go                             |     6 +-
 src/runtime/cgocheck.go                            |     2 +-
 src/runtime/chan.go                                |    55 +-
 src/runtime/complex.go                             |   108 +-
 src/runtime/cpuflags_amd64.go                      |    71 +-
 src/runtime/cpuidlow_amd64.s                       |    22 -
 src/runtime/cpuprof.go                             |   496 +-
 src/runtime/crash_cgo_test.go                      |    61 +-
 src/runtime/crash_test.go                          |   129 +-
 src/runtime/crash_unix_test.go                     |    13 +
 src/runtime/debug/garbage.go                       |     4 +-
 src/runtime/debug/garbage_test.go                  |    68 +-
 src/runtime/defs_freebsd.go                        |    11 +
 src/runtime/defs_freebsd_386.go                    |     7 +
 src/runtime/defs_freebsd_amd64.go                  |     7 +
 src/runtime/defs_freebsd_arm.go                    |     7 +
 src/runtime/duff_386.s                             |     2 +-
 src/runtime/duff_amd64.s                           |     2 +-
 src/runtime/duff_arm.s                             |     2 +-
 src/runtime/duff_arm64.s                           |     2 +-
 src/runtime/duff_mips64x.s                         |     2 +-
 src/runtime/duff_ppc64x.s                          |     2 +-
 src/runtime/env_posix.go                           |     2 +-
 src/runtime/error.go                               |    70 +-
 src/runtime/example_test.go                        |    54 +
 src/runtime/export_test.go                         |    95 +-
 src/runtime/extern.go                              |    60 +-
 src/runtime/fastlog2.go                            |     6 -
 src/runtime/float.go                               |    53 +
 src/runtime/funcdata.h                             |     6 +-
 src/runtime/gc_test.go                             |    51 +
 src/runtime/hashmap.go                             |   160 +-
 src/runtime/hashmap_fast.go                        |   460 +-
 src/runtime/heapdump.go                            |     6 +-
 src/runtime/iface.go                               |   300 +-
 src/runtime/iface_test.go                          |   140 +
 src/runtime/internal/atomic/asm_mips64x.s          |    38 +-
 src/runtime/internal/atomic/asm_ppc64x.s           |    43 -
 src/runtime/internal/sys/intrinsics.go             |    16 +-
 src/runtime/internal/sys/intrinsics_386.s          |    10 +-
 src/runtime/internal/sys/intrinsics_stubs.go       |     4 +-
 src/runtime/internal/sys/intrinsics_test.go        |    12 +-
 src/runtime/lfstack.go                             |    35 +-
 src/runtime/lock_futex.go                          |    26 +-
 src/runtime/lock_sema.go                           |    27 +-
 src/runtime/malloc.go                              |   190 +-
 src/runtime/malloc_test.go                         |    72 +-
 src/runtime/map_test.go                            |    92 +
 src/runtime/mapspeed_test.go                       |    15 +
 src/runtime/mbarrier.go                            |     6 +
 src/runtime/mbitmap.go                             |   104 +-
 src/runtime/mcache.go                              |    15 +-
 src/runtime/mcentral.go                            |    40 +-
 src/runtime/mem_bsd.go                             |     5 +-
 src/runtime/memclr_386.s                           |     4 +-
 src/runtime/memmove_386.s                          |     8 +-
 src/runtime/memmove_amd64.s                        |    10 +-
 src/runtime/mfinal.go                              |    18 +-
 src/runtime/mfixalloc.go                           |    10 +-
 src/runtime/mgc.go                                 |   633 +-
 src/runtime/mgclarge.go                            |   326 +
 src/runtime/mgcmark.go                             |   203 +-
 src/runtime/mgcsweep.go                            |    98 +-
 src/runtime/mgcwork.go                             |   180 +-
 src/runtime/mheap.go                               |   585 +-
 src/runtime/mkduff.go                              |     2 +-
 src/runtime/mknacl.sh                              |     2 +-
 src/runtime/mksizeclasses.go                       |     2 +-
 src/runtime/mmap.go                                |     3 +
 src/runtime/mprof.go                               |   221 +-
 src/runtime/msize.go                               |    22 -
 src/runtime/mstats.go                              |   110 +-
 src/runtime/mstkbar.go                             |   393 -
 src/runtime/net_plan9.go                           |     4 +-
 src/runtime/netpoll.go                             |    91 +-
 src/runtime/netpoll_epoll.go                       |    12 +-
 src/runtime/netpoll_kqueue.go                      |    12 +-
 src/runtime/netpoll_nacl.go                        |     4 +
 src/runtime/netpoll_solaris.go                     |    18 +-
 src/runtime/netpoll_stub.go                        |     2 +
 src/runtime/netpoll_windows.go                     |    28 +-
 src/runtime/numcpu_freebsd_test.go                 |    15 +
 src/runtime/os3_plan9.go                           |     7 +-
 src/runtime/os_darwin_arm.go                       |     2 +
 src/runtime/os_darwin_arm64.go                     |     2 +
 src/runtime/os_freebsd.go                          |    96 +-
 src/runtime/os_freebsd_arm.go                      |     2 +
 src/runtime/os_linux_arm.go                        |     3 +
 src/runtime/os_linux_arm64.go                      |     7 +
 src/runtime/os_nacl.go                             |     8 +-
 src/runtime/os_nacl_arm.go                         |     2 +
 src/runtime/os_netbsd.go                           |    10 +
 src/runtime/os_netbsd_arm.go                       |     2 +
 src/runtime/os_openbsd_arm.go                      |     2 +
 src/runtime/os_plan9.go                            |     5 +
 src/runtime/os_plan9_arm.go                        |     2 +
 src/runtime/os_windows.go                          |   158 +-
 src/runtime/panic.go                               |    22 +-
 src/runtime/plugin.go                              |     6 +-
 src/runtime/pprof/elf.go                           |   109 +
 .../pprof/internal}/profile/encode.go              |     0
 .../pprof/internal}/profile/filter.go              |     0
 .../pprof/internal}/profile/legacy_profile.go      |     0
 src/runtime/pprof/internal/profile/profile.go      |   575 +
 .../pprof/internal}/profile/profile_test.go        |     0
 .../pprof/internal}/profile/proto.go               |     0
 .../pprof/internal}/profile/proto_test.go          |     0
 .../pprof/internal}/profile/prune.go               |     0
 .../pprof/internal/protopprof/protomemprofile.go   |    83 -
 .../internal/protopprof/protomemprofile_test.go    |   104 -
 .../pprof/internal/protopprof/protopprof.go        |   105 -
 .../pprof/internal/protopprof/protopprof_test.go   |   171 -
 src/runtime/pprof/label.go                         |    85 +
 src/runtime/pprof/label_test.go                    |    82 +
 src/runtime/pprof/map.go                           |    89 +
 src/runtime/pprof/mprof_test.go                    |    17 +-
 src/runtime/pprof/pprof.go                         |   101 +-
 src/runtime/pprof/pprof_test.go                    |   342 +-
 src/runtime/pprof/proto.go                         |   510 +
 src/runtime/pprof/proto_test.go                    |   222 +
 src/runtime/pprof/protobuf.go                      |   141 +
 src/runtime/pprof/protomem.go                      |    93 +
 src/runtime/pprof/protomem_test.go                 |    74 +
 src/runtime/pprof/runtime.go                       |    36 +
 src/runtime/pprof/runtime_test.go                  |    96 +
 src/runtime/pprof/testdata/README                  |     9 +
 src/runtime/pprof/testdata/test32                  |   Bin 0 -> 528 bytes
 src/runtime/pprof/testdata/test32be                |   Bin 0 -> 520 bytes
 src/runtime/pprof/testdata/test64                  |   Bin 0 -> 760 bytes
 src/runtime/pprof/testdata/test64be                |   Bin 0 -> 856 bytes
 src/runtime/proc.go                                |   283 +-
 src/runtime/proc_test.go                           |    17 +-
 src/runtime/profbuf.go                             |   561 +
 src/runtime/profbuf_test.go                        |   182 +
 src/runtime/proflabel.go                           |    25 +
 src/runtime/race.go                                |     5 +-
 src/runtime/race/output_test.go                    |     2 +
 src/runtime/race/race_test.go                      |     2 +-
 src/runtime/rand_test.go                           |    45 +
 src/runtime/relax_stub.go                          |    11 +
 src/runtime/rt0_linux_mips64x.s                    |     2 +-
 src/runtime/rt0_linux_ppc64le.s                    |     7 +
 src/runtime/runtime-gdb.py                         |    33 +-
 src/runtime/runtime-gdb_test.go                    |    19 +-
 src/runtime/runtime1.go                            |    56 +-
 src/runtime/runtime2.go                            |   100 +-
 src/runtime/runtime_test.go                        |    18 +-
 src/runtime/select.go                              |   152 +-
 src/runtime/sema.go                                |   328 +-
 src/runtime/signal_386.go                          |     2 +-
 src/runtime/signal_amd64x.go                       |     2 +-
 src/runtime/signal_arm.go                          |     2 +-
 src/runtime/signal_arm64.go                        |     2 +-
 src/runtime/signal_linux_s390x.go                  |     2 +-
 src/runtime/signal_mips64x.go                      |     2 +-
 src/runtime/signal_mipsx.go                        |     2 +-
 src/runtime/signal_ppc64x.go                       |     2 +-
 src/runtime/signal_sighandler.go                   |     2 +-
 src/runtime/signal_unix.go                         |   144 +-
 src/runtime/sizeclasses.go                         |     2 +-
 src/runtime/softfloat_arm.go                       |     5 +
 src/runtime/stack.go                               |   135 +-
 src/runtime/stack_test.go                          |   186 +-
 src/runtime/string.go                              |    20 +-
 src/runtime/string_test.go                         |    15 +
 src/runtime/stubs.go                               |    45 +-
 src/runtime/stubs2.go                              |     2 -
 src/runtime/stubs_linux.go                         |     9 +
 src/runtime/stubs_nonlinux.go                      |    12 +
 src/runtime/symtab.go                              |   434 +-
 src/runtime/symtab_test.go                         |     4 +
 src/runtime/sys_darwin_386.s                       |    22 +-
 src/runtime/sys_darwin_amd64.s                     |    98 +-
 src/runtime/sys_darwin_arm.s                       |     6 +-
 src/runtime/sys_darwin_arm64.s                     |     2 +-
 src/runtime/sys_dragonfly_amd64.s                  |     4 +-
 src/runtime/sys_freebsd_386.s                      |    17 +-
 src/runtime/sys_freebsd_amd64.s                    |    18 +-
 src/runtime/sys_freebsd_arm.s                      |    23 +-
 src/runtime/sys_linux_386.s                        |    17 +-
 src/runtime/sys_linux_amd64.s                      |    28 +-
 src/runtime/sys_linux_arm.s                        |    16 +-
 src/runtime/sys_linux_arm64.s                      |    14 +-
 src/runtime/sys_linux_mips64x.s                    |    14 +-
 src/runtime/sys_linux_mipsx.s                      |    22 +-
 src/runtime/sys_linux_ppc64x.s                     |    19 +-
 src/runtime/sys_linux_s390x.s                      |    14 +-
 src/runtime/sys_nacl_386.s                         |     8 +-
 src/runtime/sys_nacl_amd64p32.s                    |    76 +-
 src/runtime/sys_nacl_arm.s                         |    10 +-
 src/runtime/sys_netbsd_386.s                       |     8 +-
 src/runtime/sys_netbsd_amd64.s                     |     4 +-
 src/runtime/sys_netbsd_arm.s                       |     4 +-
 src/runtime/sys_openbsd_386.s                      |     8 +-
 src/runtime/sys_openbsd_amd64.s                    |     4 +-
 src/runtime/sys_openbsd_arm.s                      |     4 +-
 src/runtime/sys_plan9_386.s                        |     8 +-
 src/runtime/sys_plan9_amd64.s                      |     4 +-
 src/runtime/sys_plan9_arm.s                        |    36 +-
 src/runtime/sys_solaris_amd64.s                    |     4 +-
 src/runtime/sys_windows_386.s                      |   114 +-
 src/runtime/sys_windows_amd64.s                    |    64 +-
 src/runtime/syscall_nacl.h                         |     2 +-
 src/runtime/syscall_windows.go                     |     6 +
 src/runtime/syscall_windows_test.go                |     8 +-
 src/runtime/testdata/testprog/numcpu_freebsd.go    |   126 +
 src/runtime/testdata/testprog/panicrace.go         |    27 +
 src/runtime/testdata/testprogcgo/numgoroutine.go   |    99 +
 src/runtime/testdata/testprognet/signalexec.go     |    70 +
 src/runtime/time.go                                |    13 +-
 src/runtime/timeasm.go                             |    16 +
 src/runtime/timestub.go                            |    21 +
 src/runtime/tls_arm.s                              |     6 +-
 src/runtime/trace.go                               |   187 +-
 src/runtime/trace/trace_stack_test.go              |     7 +-
 src/runtime/traceback.go                           |   170 +-
 src/runtime/type.go                                |    52 +-
 src/runtime/vlop_arm.s                             |   146 +-
 src/runtime/write_err_android.go                   |     2 +-
 src/sort/example_test.go                           |    28 +
 src/sort/genzfunc.go                               |     4 +
 src/sort/search.go                                 |     4 +-
 src/sort/sort.go                                   |    19 +-
 src/sort/zfuncversion.go                           |    10 +-
 src/strconv/itoa.go                                |   111 +-
 src/strconv/itoa_test.go                           |    78 +-
 src/strconv/quote.go                               |     6 +-
 src/strings/replace_test.go                        |    41 +
 src/strings/strings.go                             |   274 +-
 src/strings/strings_amd64.go                       |    43 +-
 src/strings/strings_generic.go                     |    22 +-
 src/strings/strings_s390x.go                       |    32 +-
 src/strings/strings_test.go                        |   103 +-
 src/sync/atomic/asm_mips64x.s                      |    30 +-
 src/sync/atomic/asm_mipsx.s                        |     6 +-
 src/sync/atomic/atomic_test.go                     |    24 +-
 src/sync/atomic/value.go                           |     1 -
 src/sync/cond.go                                   |     1 -
 src/sync/map.go                                    |   367 +
 src/sync/map_bench_test.go                         |   217 +
 src/sync/map_reference_test.go                     |   142 +
 src/sync/map_test.go                               |   170 +
 src/sync/mutex.go                                  |   152 +-
 src/sync/mutex_test.go                             |    35 +-
 src/sync/pool.go                                   |    14 +-
 src/sync/runtime.go                                |     8 +-
 src/sync/runtime_sema_test.go                      |     6 +-
 src/sync/rwmutex.go                                |    22 +-
 src/sync/waitgroup.go                              |     2 +-
 src/sync/waitgroup_test.go                         |    26 +-
 src/syscall/asm.s                                  |     8 -
 src/syscall/asm_linux_amd64.s                      |    23 +
 src/syscall/asm_linux_mipsx.s                      |    12 +-
 src/syscall/asm_plan9_arm.s                        |    10 +-
 src/syscall/dll_windows.go                         |     1 -
 src/syscall/errors_plan9.go                        |     1 +
 src/syscall/exec_bsd.go                            |    25 +-
 src/syscall/exec_freebsd.go                        |    25 +
 src/syscall/exec_linux.go                          |    47 +-
 src/syscall/exec_linux_test.go                     |   131 +-
 src/syscall/exec_solaris.go                        |    11 +-
 src/syscall/exec_unix.go                           |     7 +-
 src/syscall/forkpipe_bsd.go                        |    20 +
 src/syscall/mkall.sh                               |     4 +-
 src/syscall/mksyscall.pl                           |    20 +-
 src/syscall/mksyscall_solaris.pl                   |    23 +-
 src/syscall/net.go                                 |    34 +
 src/syscall/net_nacl.go                            |    13 +
 src/syscall/syscall.go                             |    15 +-
 src/syscall/syscall_darwin.go                      |     2 -
 src/syscall/syscall_dragonfly.go                   |    26 +-
 src/syscall/syscall_freebsd.go                     |    19 +-
 src/syscall/syscall_linux.go                       |     2 -
 src/syscall/syscall_linux_386.go                   |     5 +-
 src/syscall/syscall_linux_amd64.go                 |     2 +
 src/syscall/syscall_linux_arm.go                   |     5 +-
 src/syscall/syscall_linux_arm64.go                 |     4 +
 src/syscall/syscall_linux_mips64x.go               |     4 +
 src/syscall/syscall_linux_mipsx.go                 |     6 +-
 src/syscall/syscall_linux_ppc64x.go                |     4 +
 src/syscall/syscall_linux_s390x.go                 |     5 +-
 src/syscall/syscall_plan9.go                       |     2 -
 src/syscall/syscall_unix_test.go                   |     8 +-
 src/syscall/syscall_windows.go                     |     9 +-
 src/syscall/zerrors_dragonfly_amd64.go             |     2 +
 src/syscall/zsyscall_darwin_386.go                 |    37 +-
 src/syscall/zsyscall_darwin_amd64.go               |    37 +-
 src/syscall/zsyscall_darwin_arm.go                 |    37 +-
 src/syscall/zsyscall_darwin_arm64.go               |   246 +-
 src/syscall/zsyscall_dragonfly_amd64.go            |    46 +-
 src/syscall/zsyscall_freebsd_386.go                |    45 +-
 src/syscall/zsyscall_freebsd_amd64.go              |    45 +-
 src/syscall/zsyscall_freebsd_arm.go                |    45 +-
 src/syscall/zsyscall_linux_386.go                  |    43 +-
 src/syscall/zsyscall_linux_amd64.go                |    44 +-
 src/syscall/zsyscall_linux_arm.go                  |    43 +-
 src/syscall/zsyscall_linux_arm64.go                |    42 +-
 src/syscall/zsyscall_linux_mips.go                 |    43 +-
 src/syscall/zsyscall_linux_mips64.go               |    56 +-
 src/syscall/zsyscall_linux_mips64le.go             |    56 +-
 src/syscall/zsyscall_linux_mipsle.go               |    43 +-
 src/syscall/zsyscall_linux_ppc64.go                |    44 +-
 src/syscall/zsyscall_linux_ppc64le.go              |    44 +-
 src/syscall/zsyscall_linux_s390x.go                |    44 +-
 src/syscall/zsyscall_nacl_386.go                   |     4 +-
 src/syscall/zsyscall_nacl_amd64p32.go              |     4 +-
 src/syscall/zsyscall_nacl_arm.go                   |     4 +-
 src/syscall/zsyscall_netbsd_386.go                 |    32 +-
 src/syscall/zsyscall_netbsd_amd64.go               |    32 +-
 src/syscall/zsyscall_netbsd_arm.go                 |    32 +-
 src/syscall/zsyscall_openbsd_386.go                |    34 +-
 src/syscall/zsyscall_openbsd_amd64.go              |    34 +-
 src/syscall/zsyscall_openbsd_arm.go                |    33 +-
 src/syscall/zsyscall_plan9_386.go                  |    14 +-
 src/syscall/zsyscall_plan9_amd64.go                |    14 +-
 src/syscall/zsyscall_plan9_arm.go                  |    14 +-
 src/syscall/zsyscall_solaris_amd64.go              |    35 +-
 src/syscall/zsysnum_dragonfly_amd64.go             |     1 +
 src/syscall/ztypes_windows.go                      |     1 +
 src/testing/benchmark.go                           |    57 +-
 src/testing/helper_test.go                         |    70 +
 src/testing/helperfuncs_test.go                    |    67 +
 src/testing/internal/testdeps/deps.go              |     7 +
 src/testing/quick/quick.go                         |     9 +-
 src/testing/quick/quick_test.go                    |    18 +
 src/testing/sub_test.go                            |    85 +-
 src/testing/testing.go                             |   247 +-
 src/text/scanner/example_test.go                   |    35 +-
 src/text/scanner/scanner.go                        |     5 +-
 src/text/template/doc.go                           |    18 +-
 src/text/template/exec.go                          |    10 +-
 src/text/template/exec_test.go                     |     3 +
 src/text/template/funcs.go                         |     5 +-
 src/text/template/parse/lex_test.go                |     4 +-
 src/text/template/parse/parse.go                   |     1 -
 src/text/template/template.go                      |     1 +
 src/time/export_test.go                            |    13 +
 src/time/format.go                                 |    44 +-
 src/time/format_test.go                            |     4 +-
 src/time/genzabbrs.go                              |     4 +-
 src/time/mono_test.go                              |   261 +
 src/time/sleep_test.go                             |     4 +-
 src/time/sys_plan9.go                              |     4 +
 src/time/sys_unix.go                               |     4 +
 src/time/sys_windows.go                            |     4 +
 src/time/time.go                                   |   402 +-
 src/time/time_test.go                              |    74 +
 src/time/zoneinfo.go                               |    32 +-
 src/time/zoneinfo_abbrs_windows.go                 |   176 +-
 src/time/zoneinfo_plan9.go                         |     2 +-
 src/time/zoneinfo_read.go                          |    13 +-
 src/time/zoneinfo_test.go                          |    50 +-
 src/time/zoneinfo_windows.go                       |     2 +-
 src/unicode/letter.go                              |     4 +-
 src/unicode/maketables.go                          |     4 +-
 src/unicode/tables.go                              |     4 +-
 .../x/crypto/chacha20poly1305/chacha20poly1305.go  |     2 +-
 .../chacha20poly1305/chacha20poly1305_amd64.go     |    59 +-
 .../chacha20poly1305/chacha20poly1305_amd64.s      |    45 +-
 ...vectors.go => chacha20poly1305_vectors_test.go} |     0
 .../internal/chacha20/chacha_test.go               |     4 +
 .../golang_org/x/crypto/curve25519/cswap_amd64.s   |   131 +-
 .../golang_org/x/crypto/curve25519/curve25519.go   |    23 +-
 .../x/crypto/curve25519/curve25519_test.go         |    10 +
 .../golang_org/x/crypto/poly1305/poly1305_test.go  |    67 +
 src/vendor/golang_org/x/crypto/poly1305/sum_ref.go |  1634 +-
 src/vendor/golang_org/x/net/http2/hpack/encode.go  |    29 +-
 .../golang_org/x/net/http2/hpack/encode_test.go    |    70 +-
 src/vendor/golang_org/x/net/http2/hpack/hpack.go   |   106 +-
 .../golang_org/x/net/http2/hpack/hpack_test.go     |   150 +-
 src/vendor/golang_org/x/net/http2/hpack/tables.go  |   255 +-
 .../golang_org/x/net/http2/hpack/tables_test.go    |   214 +
 src/vendor/golang_org/x/net/idna/idna.go           |   672 +-
 src/vendor/golang_org/x/net/idna/idna_test.go      |    43 -
 src/vendor/golang_org/x/net/idna/punycode.go       |    23 +-
 src/vendor/golang_org/x/net/idna/tables.go         |  4479 ++
 src/vendor/golang_org/x/net/idna/trie.go           |    72 +
 src/vendor/golang_org/x/net/idna/trieval.go        |   116 +
 src/vendor/golang_org/x/net/lif/address.go         |     4 +-
 src/vendor/golang_org/x/net/lif/address_test.go    |     6 +-
 src/vendor/golang_org/x/net/lif/binary.go          |    49 +-
 src/vendor/golang_org/x/net/lif/defs_solaris.go    |     2 +-
 src/vendor/golang_org/x/net/lif/link.go            |    14 +-
 src/vendor/golang_org/x/net/lif/link_test.go       |     6 +-
 src/vendor/golang_org/x/net/lif/sys.go             |    21 +
 .../golang_org/x/net/lif/sys_solaris_amd64.s       |     3 -
 src/vendor/golang_org/x/net/lif/syscall.go         |     5 -
 .../golang_org/x/net/lif/zsys_solaris_amd64.go     |     2 +-
 src/vendor/golang_org/x/net/nettest/conntest.go    |   456 +
 .../golang_org/x/net/nettest/conntest_go16.go      |    24 +
 .../golang_org/x/net/nettest/conntest_go17.go      |    24 +
 .../golang_org/x/net/nettest/conntest_test.go      |   126 +
 src/vendor/golang_org/x/net/proxy/direct.go        |    18 +
 src/vendor/golang_org/x/net/proxy/per_host.go      |   140 +
 src/vendor/golang_org/x/net/proxy/per_host_test.go |    55 +
 src/vendor/golang_org/x/net/proxy/proxy.go         |    94 +
 src/vendor/golang_org/x/net/proxy/proxy_test.go    |   142 +
 src/vendor/golang_org/x/net/proxy/socks5.go        |   213 +
 src/vendor/golang_org/x/net/route/address.go       |   152 +-
 src/vendor/golang_org/x/net/route/binary.go        |     2 +-
 src/vendor/golang_org/x/net/route/defs_darwin.go   |     8 +
 .../golang_org/x/net/route/defs_dragonfly.go       |     8 +
 src/vendor/golang_org/x/net/route/defs_freebsd.go  |     8 +
 src/vendor/golang_org/x/net/route/defs_netbsd.go   |     8 +
 src/vendor/golang_org/x/net/route/defs_openbsd.go  |    12 +
 src/vendor/golang_org/x/net/route/message.go       |     8 +-
 .../golang_org/x/net/route/message_darwin_test.go  |    31 +-
 .../golang_org/x/net/route/message_freebsd_test.go |    94 +-
 src/vendor/golang_org/x/net/route/message_test.go  |   159 +-
 src/vendor/golang_org/x/net/route/route.go         |    59 +-
 src/vendor/golang_org/x/net/route/route_classic.go |    36 +
 src/vendor/golang_org/x/net/route/route_openbsd.go |    35 +-
 src/vendor/golang_org/x/net/route/sys.go           |     7 +-
 src/vendor/golang_org/x/net/route/sys_darwin.go    |    45 +-
 src/vendor/golang_org/x/net/route/sys_dragonfly.go |    39 +-
 src/vendor/golang_org/x/net/route/sys_freebsd.go   |    39 +-
 src/vendor/golang_org/x/net/route/sys_netbsd.go    |    34 +-
 src/vendor/golang_org/x/net/route/sys_openbsd.go   |    39 +-
 src/vendor/golang_org/x/net/route/syscall.go       |     5 -
 src/vendor/golang_org/x/net/route/syscall.s        |     8 -
 src/vendor/golang_org/x/net/route/zsys_darwin.go   |     6 +
 .../golang_org/x/net/route/zsys_dragonfly.go       |     6 +
 .../golang_org/x/net/route/zsys_freebsd_386.go     |     6 +
 .../golang_org/x/net/route/zsys_freebsd_amd64.go   |     6 +
 .../golang_org/x/net/route/zsys_freebsd_arm.go     |     6 +
 src/vendor/golang_org/x/net/route/zsys_netbsd.go   |     6 +
 src/vendor/golang_org/x/net/route/zsys_openbsd.go  |    10 +
 .../golang_org/x/text/secure/bidirule/bidirule.go  |   344 +
 src/vendor/golang_org/x/text/secure/doc.go         |     8 +
 .../golang_org/x/text/transform/examples_test.go   |    39 +
 .../golang_org/x/text/transform/transform.go       |     4 +-
 src/vendor/golang_org/x/text/unicode/bidi/bidi.go  |   198 +
 .../golang_org/x/text/unicode/bidi/bracket.go      |   337 +
 src/vendor/golang_org/x/text/unicode/bidi/core.go  |  1060 +
 .../golang_org/x/text/unicode/bidi/example_test.go |   185 +
 src/vendor/golang_org/x/text/unicode/bidi/prop.go  |   208 +
 .../golang_org/x/text/unicode/bidi/tables.go       |  1781 +
 .../golang_org/x/text/unicode/bidi/trieval.go      |    62 +
 src/vendor/golang_org/x/text/unicode/doc.go        |    10 +
 .../golang_org/x/text/unicode/norm/composition.go  |     2 +
 .../x/text/unicode/norm/example_iter_test.go       |    84 +
 .../golang_org/x/text/unicode/norm/example_test.go |    29 +
 .../golang_org/x/text/unicode/norm/forminfo.go     |    51 +-
 src/vendor/golang_org/x/text/unicode/norm/input.go |     2 +
 src/vendor/golang_org/x/text/unicode/norm/iter.go  |     2 +
 .../golang_org/x/text/unicode/norm/normalize.go    |     7 +-
 .../golang_org/x/text/unicode/norm/readwriter.go   |     2 +
 .../golang_org/x/text/unicode/norm/tables.go       |  1022 +-
 .../golang_org/x/text/unicode/norm/transform.go    |     2 +
 src/vendor/golang_org/x/text/unicode/norm/trie.go  |     2 +
 src/vendor/golang_org/x/text/width/kind_string.go  |    16 -
 src/vendor/golang_org/x/text/width/tables.go       |  1284 -
 src/vendor/golang_org/x/text/width/transform.go    |   239 -
 src/vendor/golang_org/x/text/width/trieval.go      |    30 -
 src/vendor/golang_org/x/text/width/width.go        |   206 -
 test/alias2.go                                     |   104 +
 test/alias3.dir/a.go                               |    42 +
 test/alias3.dir/b.go                               |    26 +
 test/alias3.dir/c.go                               |    25 +
 test/alias3.go                                     |     7 +
 test/append1.go                                    |    20 +
 test/armimm.go                                     |   179 +
 test/bench/go1/parserdata_test.go                  |     2 +-
 test/chan/doubleselect.go                          |     1 +
 test/chan/fifo.go                                  |     1 -
 test/chan/perm.go                                  |    29 +-
 test/chan/powser1.go                               |   322 +-
 test/chan/powser2.go                               |   408 +-
 test/chan/select3.go                               |     7 +-
 test/chan/sendstmt.go                              |     2 +-
 test/checkbce.go                                   |    54 +-
 test/cmplx.go                                      |    14 +
 test/cmplxdivide.c                                 |    72 +-
 test/cmplxdivide.go                                |    26 +-
 test/cmplxdivide1.go                               |  6511 ++-
 test/complit1.go                                   |     9 +
 test/copy1.go                                      |    27 +
 test/ddd1.go                                       |     4 +
 test/devirt.go                                     |    39 +
 test/escape2.go                                    |    15 +
 test/escape5.go                                    |    14 +
 test/escape_closure.go                             |     8 +-
 test/fixedbugs/bug195.go                           |     8 +-
 test/fixedbugs/bug217.go                           |     2 +
 test/fixedbugs/bug251.go                           |    10 +-
 test/fixedbugs/bug255.go                           |     2 +-
 test/fixedbugs/bug273.go                           |    11 -
 test/fixedbugs/bug289.go                           |     4 +-
 test/fixedbugs/bug398.go                           |    25 +-
 test/fixedbugs/bug487.go                           |     4 +-
 test/fixedbugs/bug502.go                           |    28 +
 test/fixedbugs/gcc80226.go                         |    17 +
 test/fixedbugs/issue10607a.go                      |     2 +-
 test/fixedbugs/issue10958.go                       |     2 +-
 test/fixedbugs/issue11354.go                       |    15 +
 test/fixedbugs/issue11371.go                       |    17 +
 test/fixedbugs/issue11610.go                       |     2 +-
 test/fixedbugs/issue11614.go                       |     2 +-
 test/fixedbugs/issue11674.go                       |    40 +
 test/fixedbugs/issue11945.go                       |    71 +
 test/fixedbugs/issue12536.go                       |    22 +
 test/fixedbugs/issue13471.go                       |    22 +-
 test/fixedbugs/issue13559.go                       |    40 +-
 test/fixedbugs/issue14006.go                       |     4 +-
 test/fixedbugs/issue14010.go                       |     2 +-
 test/fixedbugs/issue14520.go                       |     2 +-
 test/fixedbugs/issue15055.go                       |    17 +
 test/fixedbugs/issue15550.go                       |    28 +
 test/fixedbugs/issue15611.go                       |    20 +
 test/fixedbugs/issue16369.go                       |     4 +-
 test/fixedbugs/issue16439.go                       |     2 +-
 test/fixedbugs/issue17328.go                       |    13 +
 test/fixedbugs/issue18089.go                       |    19 +
 test/fixedbugs/issue18231.go                       |    20 +
 test/fixedbugs/issue18331.go                       |    20 +
 test/fixedbugs/issue18392.go                       |     5 +-
 test/fixedbugs/issue18393.go                       |    24 +
 test/fixedbugs/issue18419.dir/other.go             |    11 +
 test/fixedbugs/issue18419.dir/test.go              |    15 +
 test/fixedbugs/issue18419.go                       |     7 +
 test/fixedbugs/issue18459.go                       |     2 +-
 test/fixedbugs/issue18595.go                       |    53 +
 test/fixedbugs/issue18636.go                       |    27 +
 test/fixedbugs/issue18640.go                       |    26 +
 test/fixedbugs/issue18655.go                       |    22 +
 test/fixedbugs/issue18661.go                       |    25 +-
 test/fixedbugs/issue18747.go                       |    28 +
 test/fixedbugs/issue18882.go                       |    13 +
 test/fixedbugs/issue18902.go                       |   137 +
 test/fixedbugs/issue18902b.go                      |   161 +
 test/fixedbugs/issue18994.go                       |    22 +
 test/fixedbugs/issue19012.go                       |    25 +
 test/fixedbugs/issue19040.go                       |    36 +
 test/fixedbugs/issue19056.go                       |     9 +
 test/fixedbugs/issue19078.go                       |    42 +
 test/fixedbugs/issue19084.go                       |    17 +
 test/fixedbugs/issue19246.go                       |    28 +
 test/fixedbugs/issue19275.go                       |    72 +
 test/fixedbugs/issue19359.go                       |    37 +
 test/fixedbugs/issue19467.dir/mysync.go            |    21 +
 test/fixedbugs/issue19467.dir/z.go                 |    34 +
 test/fixedbugs/issue19467.go                       |     7 +
 test/fixedbugs/issue19482.go                       |    34 +
 test/fixedbugs/issue19515.go                       |    51 +
 test/fixedbugs/issue19548.dir/a.go                 |    26 +
 test/fixedbugs/issue19548.dir/b.go                 |    24 +
 test/fixedbugs/issue19548.go                       |     9 +
 test/fixedbugs/issue19555.go                       |    36 +
 test/fixedbugs/issue19610.go                       |    14 +
 test/fixedbugs/issue19632.go                       |    21 +
 test/fixedbugs/issue19658.go                       |    99 +
 test/fixedbugs/issue19667.go                       |    13 +
 test/fixedbugs/issue19671.go                       |    16 +
 test/fixedbugs/issue19678.go                       |    21 +
 test/fixedbugs/issue19679.go                       |    38 +
 test/fixedbugs/issue19696.go                       |    20 +
 test/fixedbugs/issue19699.dir/a.go                 |    12 +
 test/fixedbugs/issue19699.dir/b.go                 |    11 +
 test/fixedbugs/issue19699.go                       |     7 +
 test/fixedbugs/issue19699b.go                      |    14 +
 test/fixedbugs/issue19705.go                       |    17 +
 test/fixedbugs/issue19710.go                       |    25 +
 test/fixedbugs/issue19764.dir/a.go                 |    15 +
 test/fixedbugs/issue19764.dir/b.go                 |    13 +
 test/fixedbugs/issue19764.go                       |    10 +
 test/fixedbugs/issue19783.go                       |    18 +
 test/fixedbugs/issue19799.go                       |    71 +
 test/fixedbugs/issue19880.go                       |    20 +
 test/fixedbugs/issue19911.go                       |    34 +
 test/fixedbugs/issue19947.go                       |    15 +
 test/fixedbugs/issue19977.go                       |    16 +
 test/fixedbugs/issue20145.go                       |    14 +
 test/fixedbugs/issue20162.go                       |    16 +
 test/fixedbugs/issue20174.go                       |    18 +
 test/fixedbugs/issue20185.go                       |    25 +
 test/fixedbugs/issue20227.go                       |    16 +
 test/fixedbugs/issue20232.go                       |    11 +
 test/fixedbugs/issue20233.go                       |    11 +
 test/fixedbugs/issue20245.go                       |    11 +
 test/fixedbugs/issue20250.go                       |    24 +
 test/fixedbugs/issue20298.go                       |    32 +
 test/fixedbugs/issue20333.go                       |    15 +
 test/fixedbugs/issue20415.go                       |    33 +
 test/fixedbugs/issue20529.go                       |    18 +
 test/fixedbugs/issue20530.go                       |    34 +
 test/fixedbugs/issue20602.go                       |    14 +
 test/fixedbugs/issue7525.go                        |     6 +-
 test/fixedbugs/issue7525b.go                       |    13 +
 test/fixedbugs/issue7525c.go                       |    13 +
 test/fixedbugs/issue8042.go                        |    66 +
 test/fixedbugs/issue8438.go                        |    17 +
 test/fixedbugs/issue8440.go                        |    11 +
 test/fixedbugs/issue9432.go                        |     4 +-
 test/goto.go                                       |    16 +-
 test/import5.go                                    |    36 +-
 test/import6.go                                    |    38 +
 test/initializerr.go                               |     1 +
 test/inline_caller.go                              |    77 +
 test/inline_callers.go                             |    95 +
 test/inline_literal.go                             |    50 +
 test/interface/explicit.go                         |     8 +-
 test/intrinsic.dir/main.go                         |    10 +-
 test/label1.go                                     |    28 +-
 test/linkname.dir/linkname1.go                     |    10 +
 test/linkname.dir/linkname2.go                     |    13 +
 test/linkname.dir/linkname3.go                     |    11 +
 test/linkname.go                                   |    15 +
 test/live.go                                       |    72 +-
 test/locklinear.go                                 |   165 +
 test/loopbce.go                                    |     4 +-
 test/makenew.go                                    |    19 +
 test/map1.go                                       |    10 +-
 test/nilptr3.go                                    |    41 +-
 test/nosplit.go                                    |     2 +-
 test/notinheap.go                                  |     8 +-
 test/prove.go                                      |    31 +-
 test/range.go                                      |    20 +
 test/recover5.go                                   |    16 +
 test/reorder.go                                    |    37 +
 test/run.go                                        |     9 +-
 test/runtime.go                                    |     2 +-
 test/shift1.go                                     |     6 +
 test/switch5.go                                    |    45 +-
 test/switch6.go                                    |    14 +
 test/switch7.go                                    |    35 +
 test/syntax/chan1.go                               |     4 +-
 test/syntax/forvar.go                              |    11 -
 test/syntax/initvar.go                             |    15 +
 test/syntax/semi1.go                               |     2 +-
 test/syntax/semi3.go                               |     2 +-
 test/syntax/semi4.go                               |     9 +-
 test/syntax/semi6.go                               |     6 +-
 test/typeswitch2.go                                |     4 +-
 test/typeswitch3.go                                |    29 +-
 test/writebarrier.go                               |    42 +-
 2035 files changed, 271978 insertions(+), 122680 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 555ce0a..2222572 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -24,6 +24,7 @@ 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>
+Aishraj Dahal <aishraj at users.noreply.github.com>
 Akihiro Suda <suda.kyoto at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Shreve <alan at inconshreveable.com>
@@ -60,6 +61,7 @@ Alexandre Fiori <fiorix at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
 Alexey Borzenkov <snaury at gmail.com>
+Alexey Neganov <neganovalexey at gmail.com>
 Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Aliaksandr Valialkin <valyala at gmail.com>
 Alif Rachmawadi <subosito at gmail.com>
@@ -75,6 +77,7 @@ Andrei Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andrew Austin <andrewaclt at gmail.com>
 Andrew Balholm <andybalholm at gmail.com>
+Andrew Benton <andrewmbenton at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
 Andrew Ekstedt <andrew.ekstedt at gmail.com>
@@ -126,9 +129,11 @@ awaw fumin <awawfumin at gmail.com>
 Ayanamist Yang <ayanamist at gmail.com>
 Aymerick Jéhanne <aymerick at jehanne.org>
 Baiju Muthukadan <baiju.m.mail at gmail.com>
+Bartosz Grzybowski <melkorm at gmail.com>
 Ben Burkert <ben at benburkert.com>
 Ben Lubar <ben.lubar at gmail.com>
 Ben Olive <sionide21 at gmail.com>
+Ben Shi <powerman1st at 163.com>
 Benjamin Black <b at b3k.us>
 Benny Siegert <bsiegert at gmail.com>
 Benoit Sigoure <tsunanet at gmail.com>
@@ -151,20 +156,28 @@ Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
 Brian Kennedy <btkennedy at gmail.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Brian Smith <ohohvi at gmail.com>
+Brian Starke <brian.starke at gmail.com>
 Bryan Alexander <Kozical at msn.com>
 Bryan Ford <brynosaurus at gmail.com>
+Bulat Gaifullin <gaifullinbf at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Caleb Spare <cespare at gmail.com>
 Carl Chatfield <carlchatfield at gmail.com>
+Carl Henrik Lunde <chlunde at ifi.uio.no>
 Carl Johnson <me at carlmjohnson.net>
+Carlisia Campos <carlisia at grokkingtech.io>
+Carlo Alberto Ferraris <cafxx at strayorange.com>
 Carlos Castillo <cookieo9 at gmail.com>
 Carlos Cirello <uldericofilho at gmail.com>
+Carolyn Van Slyck <me at carolynvanslyck.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
 Cezar Sá Espinola <cezarsa at gmail.com>
 ChaiShushan <chaishushan at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Charles Lee <zombie.fml at gmail.com>
+Chew Choon Keat <choonkeat at gmail.com>
+Chris Biscardi <chris at christopherbiscardi.com>
 Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
 Chris Hines <chris.cs.guy at gmail.com>
@@ -198,6 +211,7 @@ Cristian Staretu <unclejacksons at gmail.com>
 Currant
 Cyrill Schumacher <cyrill at schumacher.fm>
 Damian Gryski <dgryski at gmail.com>
+Damien Lespiau <damien.lespiau at gmail.com>
 Dan Caddigan <goldcaddy77 at gmail.com>
 Dan Callahan <dan.callahan at gmail.com>
 Dan Peterson <dpiddy at gmail.com>
@@ -225,6 +239,7 @@ David G. Andersen <dave.andersen at gmail.com>
 David Howden <dhowden at gmail.com>
 David Jakob Fritz <david.jakob.fritz at gmail.com>
 David Leon Gil <coruus at gmail.com>
+David NewHamlet <david at newhamlet.com>
 David R. Jenni <david.r.jenni at gmail.com>
 David Sansome <me at davidsansome.com>
 David Stainton <dstainton415 at gmail.com>
@@ -254,6 +269,7 @@ Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
 Dmitry Chestnykh <dchest at gmail.com>
 Dmitry Savintsev <dsavints at gmail.com>
 Dmitry Yakunin <nonamezeil at gmail.com>
+Dominic Green <dominicgreen1 at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
 Donald Huang <don.hcd at gmail.com>
 Donovan Hide <donovanhide at gmail.com>
@@ -267,6 +283,7 @@ Eden Li <eden.li at gmail.com>
 Edward Muller <edwardam at interlix.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
+Eitan Adler <lists at eitanadler.com>
 Eivind Uggedal <eivind at uggedal.com>
 Elias Naur <elias.naur at gmail.com>
 Elliot Morrison-Reed <elliotmr at gmail.com>
@@ -288,16 +305,21 @@ Esko Luontola <esko.luontola at gmail.com>
 Euan Kemp <euank at euank.com>
 Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
+Evgeniy Polyakov <zbr at ioremap.net>
 Ewan Chou <coocood at gmail.com>
+Ewan Valentine <ewan.valentine89 at gmail.com>
 Fabian Wickborn <fabian at wickborn.net>
 Fabrizio Milo <mistobaan at gmail.com>
+Facebook, Inc.
 Faiyaz Ahmed <ahmedf at vmware.com>
 Fan Hongjian <fan.howard at gmail.com>
 Fastly, Inc.
 Fatih Arslan <fatih at arslan.io>
 Fazlul Shahriar <fshahriar at gmail.com>
 Fedor Indutny <fedor at indutny.com>
+Felipe Oliveira <felipeweb.programador at gmail.com>
 Felix Geisendörfer <haimuiba at gmail.com>
+Filip Gruszczyński <gruszczy at gmail.com>
 Filippo Valsorda <hi at filippo.io>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de>
@@ -317,8 +339,10 @@ Gary Burd <gary at beagledreams.com>
 Gaurish Sharma <contact at gaurishsharma.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
 Geert-Johan Riemer <gjr19912 at gmail.com>
+Gengliang Wang <ltnwgl at gmail.com>
 Geoffroy Lorieux <lorieux.g at gmail.com>
 Georg Reinke <guelfey at gmail.com>
+George Gkirtsou <ggirtsou at gmail.com>
 George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
@@ -330,6 +354,7 @@ Gordon Klaus <gordon.klaus at gmail.com>
 Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
+Gregory Man <man.gregory at gmail.com>
 Guillaume J. Charmes <guillaume at charmes.net>
 Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
@@ -343,6 +368,7 @@ Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
 Harry Moreno <morenoh149 at gmail.com>
 Harshavardhana <hrshvardhana at gmail.com>
+Hauke Löffler <hloeffler at users.noreply.github.com>
 Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
@@ -355,10 +381,13 @@ 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>
+Hongfei Tan <feilengcui008 at gmail.com>
 Hsin-Ho Yeh <yhh92u at gmail.com>
 Hu Keping <hukeping at huawei.com>
+Hugues Bruant <hugues.bruant at gmail.com>
 Ian Gudger <ian at loosescre.ws>
 IBM
+Ibrahim AshShohail <ibra.sho at gmail.com>
 Icarus Sparry <golang at icarus.freeuk.com>
 Idora Shinatose <idora.shinatose at gmail.com>
 Igneous Systems, Inc.
@@ -381,16 +410,19 @@ James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
 James Gray <james at james4k.com>
 James Meneghello <rawrz0r at gmail.com>
+James Neve <jamesoneve at gmail.com>
 James P. Cooper <jamespcooper at gmail.com>
 James Schofield <james at shoeboxapp.com>
+James Smith <jrs1995 at icloud.com>
 James Sweet <james.sweet88 at googlemail.com>
 James Toy <nil at opensesame.st>
 James Whitehead <jnwhiteh at gmail.com>
 Jamie Beverly <jamie.r.beverly at gmail.com>
+Jamie Stackhouse <contin673 at gmail.com>
 Jamil Djadala <djadala at gmail.com>
+Jan Berktold <jan at berktold.co>
 Jan H. Hosang <jan.hosang at gmail.com>
-Jan Mercl <0xjnml at gmail.com>
-Jan Mercl <befelemepeseveze at gmail.com>
+Jan Mercl <0xjnml at gmail.com> <befelemepeseveze at gmail.com>
 Jan Newmarch <jan.newmarch at gmail.com>
 Jan Ziak <0xe2.0x9a.0x9b at gmail.com>
 Jani Monoses <jani.monoses at ubuntu.com>
@@ -426,6 +458,7 @@ 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 Brandhorst <johan.brandhorst at gmail.com>
 Johan Sageryd <j at 1616.se>
 John Asmuth <jasmuth at gmail.com>
 John C Barstow <jbowtie at amathaine.com>
@@ -441,10 +474,12 @@ Jonathan Boulle <jonathanboulle at gmail.com>
 Jonathan Gold <jgold.bg at gmail.com>
 Jonathan Mark <jhmark at xenops.com>
 Jonathan Rudenberg <jonathan at titanous.com>
+Jonathan Stacks <jonstacks13 at gmail.com>
 Jonathan Wills <runningwild at gmail.com>
 Jongmin Kim <atomaths at gmail.com>
 Joonas Kuorilehto <joneskoo at derbian.fi>
 Joop Kiefte <ikojba at gmail.com> <joop at kiefte.net>
+Jordan Krage <jmank88 at gmail.com>
 Jordan Lewis <jordanthelewis at gmail.com>
 Jose Luis Vázquez González <josvazg at gmail.com>
 Joseph Holsten <joseph at josephholsten.com>
@@ -453,7 +488,9 @@ Josh Chorlton <jchorlton at gmail.com>
 Josh Goebel <dreamer3 at gmail.com>
 Josh Holland <jrh at joshh.co.uk>
 Joshua Chase <jcjoshuachase at gmail.com>
+Josselin Costanzi <josselin at costanzi.fr>
 Jostein Stuhaug <js at solidsystem.no>
+Joyent, Inc.
 JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Kornberger <jk+github at digineo.de>
@@ -463,13 +500,16 @@ Justin Nuß <nuss.justin at gmail.com>
 Justyn Temme <justyntemme at gmail.com>
 Kai Backman <kaib at golang.org>
 Kale Blankenship <kale at lemnisys.com>
+Kamil Chmielewski <kamil.chm at gmail.com>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
 Kang Hu <hukangustc at gmail.com>
+Karoly Negyesi <chx1975 at gmail.com>
 Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kaviraj Kanagaraj <kavirajkanagaraj at gmail.com>
 Keegan Carruthers-Smith <keegan.csmith at gmail.com>
 Kei Son <hey.calmdown at gmail.com>
+Keiji Yoshida <keijiyoshida.mail at gmail.com>
 Keith Ball <inflatablewoman at gmail.com>
 Keith Rarick <kr at xph.us>
 Kelsey Hightower <kelsey.hightower at gmail.com>
@@ -485,23 +525,31 @@ 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>
+Koichi Shiraishi <zchee.io at gmail.com>
 Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
 KPCompass, Inc.
+Kris Nova <kris at nivenly.com>
 Kristopher Watts <traetox at gmail.com>
 Kun Li <likunarmstrong at gmail.com>
 Kyle Consalus <consalus at gmail.com>
 Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net>
+Kyrylo Silin <silin at kyrylo.org>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
+Lars Jeppesen <jeppesen.lars at gmail.com>
+Lars Wiegman <lars at namsral.com>
 Larz Conwell <larzconwell at gmail.com>
+Laurie Clark-Michalek <laurie at qubit.com>
 LE Manh Cuong <cuong.manhle.vn 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
+Lion Yang <lion at aosc.xyz>
 Lloyd Dewolf <foolswisdom at gmail.com>
+Lorenzo Masini <rugginoso at develer.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Luan Santos <cfcluan at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
@@ -518,8 +566,10 @@ Manu S Ajith <neo at codingarena.in>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
 Marcel Edmund Franke <marcel.edmund.franke at gmail.com>
+Marcelo E. Magallon <marcelo.magallon at gmail.com>
 Marco Hennings <marco.hennings at freiheit.com>
 Marin Bašić <marin.basic02 at gmail.com>
+Mark Adams <mark at markadams.me>
 Mark Bucciarelli <mkbucc at gmail.com>
 Mark Severson <miquella at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
@@ -532,23 +582,29 @@ Markus Zimmermann <zimmski at gmail.com>
 Martin Bertschler <mbertschler at gmail.com>
 Martin Garton <garton at gmail.com>
 Martin Hamrle <martin.hamrle at gmail.com>
+Martin Lindhe <martin.j.lindhe 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>
+Marwan Sulaiman <marwan.sulaiman at work.co>
+Máté Gulyás <mgulyas86 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>
+Matt Blair <me at matthewblair.net>
 Matt Bostock <matt at mattbostock.com>
 Matt Drollette <matt at drollette.com>
+Matt Harden <matt.harden at gmail.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
 Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
 Matt Robenolt <matt at ydekproductions.com>
+Matt Strong <mstrong1341 at gmail.com>
 Matt T. Proud <matt.proud at gmail.com>
 Matt Williams <gh at mattyw.net>
 Matthew Brennan <matty.brennan at gmail.com>
@@ -596,6 +652,7 @@ 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>
+Milutin Jovanović <jovanovic.milutin at gmail.com>
 Miquel Sabaté Solà <mikisabate at gmail.com>
 Miroslav Genov <mgenov at gmail.com>
 Mohit Agarwal <mohit at sdf.org>
@@ -605,8 +662,11 @@ Moov Corporation
 Moriyoshi Koizumi <mozo at mozo.jp>
 Morten Siebuhr <sbhr at sbhr.dk>
 Môshe van der Sterre <moshevds at gmail.com>
+Mostyn Bramley-Moore <mostyn at antipode.se>
 Muhammed Uluyol <uluyol0 at gmail.com>
+Mura Li <mura_li at castech.com.tw>
 Nan Deng <monnand at gmail.com>
+Nathan Caza <mastercactapus at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan Otterness <otternes at cs.unc.edu>
 Nathan P Finch <nate.finch at gmail.com>
@@ -615,15 +675,18 @@ Nathan Youngman <git at nathany.com>
 Neelesh Chandola <neelesh.c98 at gmail.com>
 Netflix, Inc.
 Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
+Nexedi
 ngmoco, LLC
 Niall Sheridan <nsheridan at gmail.com>
 Nic Day <nic.day at me.com>
 Nicholas Katsaros <nick at nickkatsaros.com>
+Nicholas Maniscalco <nicholas at maniscalco.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 Leli <nicholasleli at gmail.com>
+Nick Miyake <nmiyake at users.noreply.github.com>
 Nick Patavalis <nick.patavalis at gmail.com>
 Nick Petroni <npetroni at cs.umd.edu>
 Nicolas Kaiser <nikai at nikai.net>
@@ -632,6 +695,7 @@ Nicolas S. Dade <nic.dade at gmail.com>
 Niels Widger <niels.widger at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nik Nyby <nnyby at columbia.edu>
+Niklas Schnelle <niklas.schnelle at gmail.com>
 Niko Dziemba <niko at dziemba.com>
 Nikolay Turpitko <nikolay at turpitko.com>
 Noah Campbell <noahcampbell at gmail.com>
@@ -660,9 +724,11 @@ Patrick Higgins <patrick.allen.higgins at gmail.com>
 Patrick Lee <pattyshack101 at gmail.com>
 Patrick Mézard <patrick at mezard.eu>
 Patrick Mylund Nielsen <patrick at patrickmn.com>
+Patrick Pelletier <pp.pelletier at gmail.com>
 Patrick Smith <pat42smith at gmail.com>
 Paul A Querna <paul.querna at gmail.com>
 Paul Hammond <paul at paulhammond.org>
+Paul Jolly <paul at myitcv.org.uk>
 Paul Lalonde <paul.a.lalonde at gmail.com>
 Paul Meyer <paul.meyer at microsoft.com>
 Paul Rosania <paul.rosania at gmail.com>
@@ -681,6 +747,7 @@ Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter Moody <pmoody at uber.com>
 Peter Mundy <go.peter.90 at gmail.com>
+Peter Nguyen <peter at mictis.com>
 Péter Surányi <speter.go1 at gmail.com>
 Péter Szilágyi <peterke at gmail.com>
 Peter Waldschmidt <peter at waldschmidt.com>
@@ -694,6 +761,7 @@ 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>
+Pravendra Singh <hackpravj at gmail.com>
 Preetam Jinka <pj at preet.am>
 Quan Tran <qeed.quan at gmail.com>
 Quan Yong Zhai <qyzhai at gmail.com>
@@ -703,11 +771,14 @@ RackTop Systems Inc.
 Radu Berinde <radu at cockroachlabs.com>
 Rafal Jeczalik <rjeczalik at gmail.com>
 Raif S. Naffah <go at naffah-raif.name>
+RainTank
 Rajat Goel <rajat.goel2010 at gmail.com>
 Ralph Corderoy <ralph at inputplus.co.uk>
 Raphael Geronimi <raphael.geronimi at gmail.com>
+Raymond Kazlauskas <raima220 at gmail.com>
 Red Hat, Inc.
 Reinaldo de Souza Jr <juniorz at gmail.com>
+Remi Gillig <remigillig at gmail.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org>
 Ricardo Padilha <ricardospadilha at gmail.com>
 Richard Barnes <rlb at ipv.sx>
@@ -744,6 +815,7 @@ Ryan Slade <ryanslade at gmail.com>
 Ryuzo Yamamoto <ryuzo.yamamoto at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
 Salmān Aljammāz <s at 0x65.net>
+Sam Boyer <tech at samboyer.org>
 Sam Hug <samuel.b.hug at gmail.com>
 Sam Whited <sam at samwhited.com>
 Samuele Pedroni <pedronis at lucediurna.net>
@@ -767,6 +839,7 @@ 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>
+Shintaro Kaneko <kaneshin0120 at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Silvan Jegen <s.jegen at gmail.com>
 Simon Jefford <simon.jefford at gmail.com>
@@ -810,6 +883,7 @@ Terrel Shumway <gopher at shumway.us>
 Tetsuo Kiso <tetsuokiso9 at gmail.com>
 Thiago Fransosi Farina <thiago.farina at gmail.com>
 Thomas Alan Copeland <talan.copeland at gmail.com>
+Thomas Bonfort <thomas.bonfort at gmail.com>
 Thomas de Zeeuw <thomasdezeeuw at gmail.com>
 Thomas Desrosiers <thomasdesr at gmail.com>
 Thomas Kappler <tkappler at gmail.com>
@@ -829,9 +903,11 @@ Tom Linford <tomlinford at gmail.com>
 Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Tormod Erevik Lea <tormodlea at gmail.com>
+Toshiki Shima <hayabusa1419 at gmail.com>
 Totoro W <tw19881113 at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Trey Lawrence <lawrence.trey at gmail.com>
+Trey Roessig <trey.roessig at gmail.com>
 Trey Tacon <ttacon at gmail.com>
 Tristan Colgate <tcolgate at gmail.com>
 Tristan Ooohry <ooohry at gmail.com>
@@ -857,14 +933,19 @@ Vladimir Mihailenco <vladimir.webdev at gmail.com>
 Vladimir Nikishenko <vova616 at gmail.com>
 Vladimir Stefanovic <vladimir.stefanovic at imgtec.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
+Wade Simmons <wade at wades.im>
 Weaveworks
 Wei Guangjing <vcc.163 at gmail.com>
+Weichao Tang <tevic.tt at gmail.com>
+Will Storey <will at summercat.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>
+Wu Yunzhou <yunzhouwu at gmail.com>
 Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
+Xu Fei <badgangkiller at gmail.com>
 Xudong Zhang <felixmelon at gmail.com>
 Xuyang Kang <xuyangkang at gmail.com>
 Yahoo Inc.
@@ -882,9 +963,14 @@ Yusuke Kagiwada <block.rxckin.beats at gmail.com>
 Yuusei Kuwana <kuwana at kumama.org>
 Yuval Pavel Zholkover <paulzhol at gmail.com>
 Zac Bergquist <zbergquist99 at gmail.com>
+Zach Bintliff <zbintliff at gmail.com>
+Zak <zrjknill at gmail.com>
+Zellyn Hunter <zellyn at gmail.com>
 Zemanta d.o.o.
 Zev Goldstein <zev.goldstein at gmail.com>
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
+Максим Федосеев <max.faceless.frei at gmail.com>
 Фахриддин Балтаев <faxriddinjon at gmail.com>
+张嵩 <zs349596 at gmail.com>
 申习之 <bronze1man at gmail.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9620d81..274822b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,15 +4,18 @@ Go is an open source project.
 
 It is the work of hundreds of contributors. We appreciate your help!
 
+## Before filing an issue
+
+If you are unsure whether you have found a bug, please consider asking in the [golang-nuts mailing
+list](https://groups.google.com/forum/#!forum/golang-nuts) or [other forums](https://golang.org/help/) first. If
+the behavior you are seeing is confirmed as a bug or issue, it can easily be re-raised in the issue tracker.
 
 ## Filing issues
 
-General questions should go to the
-[golang-nuts mailing list](https://groups.google.com/group/golang-nuts) or
-[other forum](https://golang.org/wiki/Questions) instead of the issue tracker.
-The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+Sensitive security-related issues should be reported to [security at golang.org](mailto:security at golang.org).
+See the [security policy](https://golang.org/security) for details.
 
-When filing an issue, make sure to answer these five questions:
+Otherwise, when filing an issue, make sure to answer these five questions:
 
 1. What version of Go are you using (`go version`)?
 2. What operating system and processor architecture are you using?
@@ -22,12 +25,9 @@ When filing an issue, make sure to answer these five questions:
 
 For change proposals, see [Proposing Changes To Go](https://github.com/golang/proposal/).
 
-Sensitive security-related issues should be reported to [security at golang.org](mailto:security at golang.org).
-
 ## Contributing code
 
-Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
-before sending patches.
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches.
 
 **We do not accept GitHub pull requests**
 (we use [an instance](https://go-review.googlesource.com/) of the
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index d410b36..aa35e1b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -40,15 +40,18 @@ 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 Bender <abender at google.com>
 Adam Langley <agl at golang.org>
 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>
+Ahmet Alp Balkan <ahmetb at google.com>
 Ahmy Yulrizka <yulrizka at gmail.com>
 Aiden Scandella <ai at uber.com>
 Ainar Garipov <gugl.zadolbal at gmail.com>
+Aishraj Dahal <aishraj at users.noreply.github.com>
 Akihiro Suda <suda.kyoto at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Donovan <adonovan at google.com>
@@ -89,6 +92,7 @@ Alexandre Normand <alexandre.normand at gmail.com>
 Alexandru Moșoi <brtzsnr at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
 Alexey Borzenkov <snaury at gmail.com>
+Alexey Neganov <neganovalexey at gmail.com>
 Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Alexis Imperial-Legrand <ail at google.com>
 Aliaksandr Valialkin <valyala at gmail.com>
@@ -107,6 +111,7 @@ Andrei Vieru <euvieru at gmail.com>
 Andres Erbsen <andreser at google.com>
 Andrew Austin <andrewaclt at gmail.com>
 Andrew Balholm <andybalholm at gmail.com>
+Andrew Benton <andrewmbenton at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
 Andrew Ekstedt <andrew.ekstedt at gmail.com>
@@ -165,12 +170,14 @@ Ayanamist Yang <ayanamist at gmail.com>
 Aymerick Jéhanne <aymerick at jehanne.org>
 Baiju Muthukadan <baiju.m.mail at gmail.com>
 Balazs Lecz <leczb at google.com>
+Bartosz Grzybowski <melkorm at gmail.com>
 Ben Burkert <ben at benburkert.com>
 Ben Eitzen <eitzenb at golang.org>
 Ben Fried <ben.fried at gmail.com>
 Ben Lubar <ben.lubar at gmail.com>
 Ben Lynn <benlynn at gmail.com>
 Ben Olive <sionide21 at gmail.com>
+Ben Shi <powerman1st at 163.com>
 Benjamin Black <b at b3k.us>
 Benjamin Prosnitz <bprosnitz at google.com>
 Benjamin Wester <bwester at squareup.com>
@@ -194,6 +201,7 @@ Brad Garcia <bgarcia at golang.org>
 Braden Bassingthwaite <bbassingthwaite at vendasta.com>
 Brady Catherman <brady at gmail.com>
 Brady Sullivan <brady at bsull.com>
+Brandon Bennett <bbennett at fb.com>
 Brandon Gilmore <varz at google.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brendan O'Dea <bod at golang.org>
@@ -205,21 +213,27 @@ Brian Kennedy <btkennedy at gmail.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Brian Slesinsky <skybrian at google.com>
 Brian Smith <ohohvi at gmail.com>
+Brian Starke <brian.starke at gmail.com>
 Bryan Alexander <Kozical at msn.com>
 Bryan C. Mills <bcmills at google.com>
 Bryan Chan <bryan.chan at ca.ibm.com>
 Bryan Ford <brynosaurus at gmail.com>
+Bulat Gaifullin <gaifullinbf 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 Henrik Lunde <chlunde at ifi.uio.no>
 Carl Jackson <carl at stripe.com>
 Carl Johnson <me at carlmjohnson.net>
 Carl Mastrangelo <notcarl at google.com>
 Carl Shapiro <cshapiro at google.com> <cshapiro at golang.org>
+Carlisia Campos <carlisia at grokkingtech.io>
+Carlo Alberto Ferraris <cafxx at strayorange.com>
 Carlos Castillo <cookieo9 at gmail.com>
 Carlos Cirello <uldericofilho at gmail.com>
 Carlos Eduardo Seo <cseo at linux.vnet.ibm.com>
+Carolyn Van Slyck <me at carolynvanslyck.com>
 Cary Hull <chull at google.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
@@ -232,6 +246,8 @@ 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>
+Chew Choon Keat <choonkeat at gmail.com>
+Chris Biscardi <chris at christopherbiscardi.com>
 Chris Broadfoot <cbro at golang.org>
 Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
@@ -272,6 +288,7 @@ Cristian Staretu <unclejacksons at gmail.com>
 Cuihtlauac ALVARADO <cuihtlauac.alvarado at orange.com>
 Cyrill Schumacher <cyrill at schumacher.fm>
 Damian Gryski <dgryski at gmail.com>
+Damien Lespiau <damien.lespiau at gmail.com> <damien.lespiau at intel.com>
 Damien Neil <dneil at google.com>
 Dan Caddigan <goldcaddy77 at gmail.com>
 Dan Callahan <dan.callahan at gmail.com>
@@ -319,6 +336,7 @@ David Jakob Fritz <david.jakob.fritz at gmail.com>
 David Lazar <lazard at golang.org>
 David Leon Gil <coruus at gmail.com>
 David McLeish <davemc at google.com>
+David NewHamlet <david at newhamlet.com>
 David Presotto <presotto at gmail.com>
 David R. Jenni <david.r.jenni at gmail.com>
 David Sansome <me at davidsansome.com>
@@ -342,6 +360,7 @@ Dhaivat Pandit <dhaivatpandit at gmail.com>
 Dhananjay Nakrani <dhananjayn at google.com>
 Dhiru Kholia <dhiru.kholia at gmail.com>
 Didier Spezia <didier.06 at gmail.com>
+Dieter Plaetinck <dieter at raintank.io>
 Dimitri Tcaciuc <dtcaciuc at gmail.com>
 Dirk Gadsden <dirk at esherido.com>
 Diwaker Gupta <diwakergupta at gmail.com>
@@ -353,6 +372,7 @@ Dmitriy Vyukov <dvyukov at google.com>
 Dmitry Chestnykh <dchest at gmail.com>
 Dmitry Savintsev <dsavints at gmail.com>
 Dmitry Yakunin <nonamezeil at gmail.com>
+Dominic Green <dominicgreen1 at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
 Dominik Vogt <vogt at linux.vnet.ibm.com>
 Donald Huang <don.hcd at gmail.com>
@@ -370,6 +390,7 @@ Eden Li <eden.li at gmail.com>
 Edward Muller <edwardam at interlix.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
+Eitan Adler <lists at eitanadler.com>
 Eivind Uggedal <eivind at uggedal.com>
 Elias Naur <elias.naur at gmail.com>
 Elliot Morrison-Reed <elliotmr at gmail.com>
@@ -399,17 +420,22 @@ Evan Kroske <evankroske at google.com>
 Evan Martin <evan.martin at gmail.com>
 Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
+Evgeniy Polyakov <zbr at ioremap.net>
 Ewan Chou <coocood at gmail.com>
+Ewan Valentine <ewan.valentine89 at gmail.com>
 Fabian Wickborn <fabian at wickborn.net>
 Fabrizio Milo <mistobaan at gmail.com>
 Faiyaz Ahmed <ahmedf at vmware.com>
 Fan Hongjian <fan.howard at gmail.com>
+Fangming Fang <fangming.fang at arm.com>
 Fatih Arslan <fatih at arslan.io>
 Fazlul Shahriar <fshahriar at gmail.com>
 Federico Simoncelli <fsimonce at redhat.com>
 Fedor Indutny <fedor at indutny.com>
+Felipe Oliveira <felipeweb.programador at gmail.com>
 Felix Geisendörfer <haimuiba at gmail.com>
-Filippo Valsorda <hi at filippo.io>
+Filip Gruszczyński <gruszczy at gmail.com>
+Filippo Valsorda <filippo at cloudflare.com> <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>
@@ -434,8 +460,10 @@ 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>
+Gengliang Wang <ltnwgl at gmail.com>
 Geoffroy Lorieux <lorieux.g at gmail.com>
 Georg Reinke <guelfey at gmail.com>
+George Gkirtsou <ggirtsou at gmail.com>
 George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
@@ -449,6 +477,7 @@ Gordon Klaus <gordon.klaus at gmail.com>
 Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
+Gregory Man <man.gregory at gmail.com>
 Guillaume J. Charmes <guillaume at charmes.net>
 Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
@@ -465,6 +494,7 @@ Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
 Harry Moreno <morenoh149 at gmail.com>
 Harshavardhana <hrshvardhana at gmail.com>
+Hauke Löffler <hloeffler at users.noreply.github.com>
 Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
@@ -472,17 +502,21 @@ Henning Schmiedehausen <henning at schmiedehausen.org>
 Henrik Edwards <henrik.edwards at gmail.com>
 Henrik Hodne <henrik at hodne.io>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
+Heschi Kreinick <heschi at google.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>
+Hongfei Tan <feilengcui008 at gmail.com>
 Hossein Sheikh Attar <hattar at google.com>
 Hsin-Ho Yeh <yhh92u at gmail.com>
 Hu Keping <hukeping at huawei.com>
+Hugues Bruant <hugues.bruant at gmail.com>
 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>
+Ibrahim AshShohail <ibra.sho at gmail.com>
 Icarus Sparry <golang at icarus.freeuk.com>
 Idora Shinatose <idora.shinatose at gmail.com>
 Igor Bernstein <igorbernstein at google.com>
@@ -513,22 +547,25 @@ James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
 James Gray <james at james4k.com>
 James Meneghello <rawrz0r at gmail.com>
+James Neve <jamesoneve at gmail.com>
 James P. Cooper <jamespcooper at gmail.com>
 James Robinson <jamesr at google.com> <jamesr.gatech at gmail.com>
 James Schofield <james at shoeboxapp.com>
+James Smith <jrs1995 at icloud.com>
 James Sweet <james.sweet88 at googlemail.com>
 James Toy <nil at opensesame.st>
 James Tucker <raggi at google.com>
 James Whitehead <jnwhiteh at gmail.com>
 Jamie Beverly <jamie.r.beverly at gmail.com>
 Jamie Gennis <jgennis at google.com> <jgennis at gmail.com>
+Jamie Stackhouse <contin673 at gmail.com>
 Jamie Turner <jamwt at dropbox.com>
 Jamie Wilkinson <jaq at spacepants.org>
 Jamil Djadala <djadala at gmail.com>
+Jan Berktold <jan at berktold.co>
 Jan H. Hosang <jan.hosang at gmail.com>
 Jan Kratochvil <jan.kratochvil at redhat.com>
-Jan Mercl <0xjnml at gmail.com>
-Jan Mercl <befelemepeseveze at gmail.com>
+Jan Mercl <0xjnml at gmail.com> <befelemepeseveze at gmail.com>
 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>
@@ -545,6 +582,7 @@ Jean-Nicolas Moal <jn.moal at gmail.com>
 Jed Denlea <jed at fastly.com>
 Jeff Craig <jeffcraig at google.com>
 Jeff Hodges <jeff at somethingsimilar.com>
+Jeff Johnson <jrjohnson at google.com>
 Jeff R. Allen <jra at nella.org> <jeff.allen at gmail.com>
 Jeff Sickel <jas at corpus-callosum.com>
 Jeff Wendling <jeff at spacemonkey.com>
@@ -569,11 +607,14 @@ 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 Richey joerichey at google.com <joerichey at google.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>
+Joël Stemmer <jstemmer at google.com>
 Joel Stemmer <stemmertech at gmail.com>
+Johan Brandhorst <johan.brandhorst at gmail.com>
 Johan Euphrosine <proppy at google.com>
 Johan Sageryd <j at 1616.se>
 John Asmuth <jasmuth at gmail.com>
@@ -601,10 +642,12 @@ Jonathan Mark <jhmark at xenops.com> <jhmark000 at gmail.com>
 Jonathan Nieder <jrn at google.com>
 Jonathan Pittman <jmpittman at google.com> <jonathan.mark.pittman at gmail.com>
 Jonathan Rudenberg <jonathan at titanous.com>
+Jonathan Stacks <jonstacks13 at gmail.com>
 Jonathan Wills <runningwild at gmail.com>
 Jongmin Kim <atomaths at gmail.com>
 Joonas Kuorilehto <joneskoo at derbian.fi>
 Joop Kiefte <ikojba at gmail.com> <joop at kiefte.net>
+Jordan Krage <jmank88 at gmail.com>
 Jordan Lewis <jordanthelewis at gmail.com>
 Jos Visser <josv at google.com>
 Jose Luis Vázquez González <josvazg at gmail.com>
@@ -617,6 +660,7 @@ Josh Hoak <jhoak at google.com>
 Josh Holland <jrh at joshh.co.uk>
 Joshua Boelter <joshua.boelter at intel.com>
 Joshua Chase <jcjoshuachase at gmail.com>
+Josselin Costanzi <josselin at costanzi.fr>
 Jostein Stuhaug <js at solidsystem.no>
 JP Sugarbroad <jpsugar at google.com>
 JT Olds <jtolds at xnet5.com>
@@ -625,6 +669,7 @@ 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>
+Julio Montes <julio.montes at intel.com>
 Jungho Ahn <jhahn at google.com>
 Jure Ham <jure.ham at zemanta.com>
 Justin Nuß <nuss.justin at gmail.com>
@@ -632,9 +677,11 @@ Justyn Temme <justyntemme at gmail.com>
 Kai Backman <kaib at golang.org>
 Kale Blankenship <kale at lemnisys.com>
 Kamal Aboul-Hosn <aboulhosn at google.com>
+Kamil Chmielewski <kamil.chm at gmail.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>
+Karoly Negyesi <chx1975 at gmail.com>
 Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kaviraj Kanagaraj <kavirajkanagaraj at gmail.com>
@@ -642,6 +689,7 @@ Kay Zhu <kayzhu at google.com>
 KB Sriram <kbsriram at google.com>
 Keegan Carruthers-Smith <keegan.csmith at gmail.com>
 Kei Son <hey.calmdown at gmail.com>
+Keiji Yoshida <keijiyoshida.mail at gmail.com>
 Keith Ball <inflatablewoman at gmail.com>
 Keith Randall <khr at golang.org>
 Keith Rarick <kr at xph.us>
@@ -661,28 +709,38 @@ 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>
+Kirill Smelkov <kirr at nexedi.com>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
 Klaus Post <klauspost at gmail.com>
+Koichi Shiraishi <zchee.io at gmail.com>
 Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
+Kris Nova <kris at nivenly.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>
 Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net> <kevlar at google.com>
+Kyrylo Silin <silin at kyrylo.org>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
 Larry Hosken <lahosken at golang.org>
+Lars Jeppesen <jeppesen.lars at gmail.com>
+Lars Wiegman <lars at namsral.com>
 Larz Conwell <larzconwell at gmail.com>
+Laurie Clark-Michalek <laurie at qubit.com>
 LE Manh Cuong <cuong.manhle.vn at gmail.com>
 Lee Hinman <hinman at gmail.com>
 Lee Packham <lpackham at gmail.com>
 Lewin Bormann <lewin.bormann at gmail.com>
+Lion Yang <lion at aosc.xyz>
 Lloyd Dewolf <foolswisdom at gmail.com>
+Lorenzo Masini <rugginoso at develer.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>
+Lucas Clemente <lclemente at google.com>
 Lucien Stuker <lucien.stuker at gmail.com>
 Lucio De Re <lucio.dere at gmail.com>
 Luigi Riefolo <luigi.riefolo at gmail.com>
@@ -703,11 +761,15 @@ Marc Weistroff <marc at weistroff.net>
 Marc-Antoine Ruel <maruel at chromium.org>
 Marcel Edmund Franke <marcel.edmund.franke at gmail.com>
 Marcel van Lohuizen <mpvl at golang.org>
+Marcelo E. Magallon <marcelo.magallon at gmail.com>
 Marco Hennings <marco.hennings at freiheit.com>
 Marga Manterola <marga at google.com>
 Marin Bašić <marin.basic02 at gmail.com>
 Marius Nuennerich <mnu at google.com>
+Mark Adams <mark at markadams.me>
 Mark Bucciarelli <mkbucc at gmail.com>
+Mark Harrison <marhar at google.com>
+Mark Ryan <mark.d.ryan at intel.com>
 Mark Severson <miquella at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Mark Zavislak <zavislak at google.com>
@@ -721,25 +783,31 @@ Martin Bertschler <mbertschler at gmail.com>
 Martin Garton <garton at gmail.com>
 Martin Hamrle <martin.hamrle at gmail.com>
 Martin Kreichgauer <martinkr at google.com>
+Martin Lindhe <martin.j.lindhe at gmail.com>
 Martin Möhrmann <moehrmann at google.com> <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Marvin Stenger <marvin.stenger94 at gmail.com>
+Marwan Sulaiman <marwan.sulaiman at work.co>
+Máté Gulyás <mgulyas86 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>
+Matt Blair <me at matthewblair.net>
 Matt Bostock <matt at mattbostock.com>
 Matt Brown <mdbrown at google.com>
 Matt Drollette <matt at drollette.com>
+Matt Harden <matt.harden at gmail.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
 Matt Jones <mrjones at google.com>
 Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
 Matt Robenolt <matt at ydekproductions.com>
+Matt Strong <mstrong1341 at gmail.com>
 Matt T. Proud <matt.proud at gmail.com>
 Matt Williams <gh at mattyw.net> <mattyjwilliams at gmail.com>
 Matthew Brennan <matty.brennan at gmail.com>
@@ -801,22 +869,28 @@ Mike Rosset <mike.rosset at gmail.com>
 Mike Samuel <mikesamuel at gmail.com>
 Mike Solomon <msolo at gmail.com>
 Mike Strosaker <strosake at us.ibm.com>
+Mike Wiacek <mjwiacek at google.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>
+Milutin Jovanović <jovanovic.milutin at gmail.com>
 Miquel Sabaté Solà <mikisabate at gmail.com>
 Miroslav Genov <mgenov at gmail.com>
 Mohit Agarwal <mohit at sdf.org>
 Momchil Velikov <momchil.velikov at gmail.com>
+Monis Khan <mkhan at redhat.com>
 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>
+Mostyn Bramley-Moore <mostyn at antipode.se>
 Mrunal Patel <mrunalp at gmail.com>
 Muhammed Uluyol <uluyol0 at gmail.com>
+Mura Li <mura_li at castech.com.tw>
 Nan Deng <monnand at gmail.com>
+Nathan Caza <mastercactapus at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan Otterness <otternes at cs.unc.edu>
 Nathan P Finch <nate.finch at gmail.com>
@@ -828,13 +902,16 @@ 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 Maniscalco <nicholas at maniscalco.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 Harper <nharper at google.com>
+Nick Kubala <nkubala at google.com>
 Nick Leli <nicholasleli at gmail.com>
+Nick Miyake <nmiyake at users.noreply.github.com>
 Nick Patavalis <nick.patavalis at gmail.com>
 Nick Petroni <npetroni at cs.umd.edu>
 Nicolas Kaiser <nikai at nikai.net>
@@ -844,6 +921,7 @@ Niels Widger <niels.widger at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nigel Tao <nigeltao at golang.org>
 Nik Nyby <nnyby at columbia.edu>
+Niklas Schnelle <niklas.schnelle at gmail.com>
 Niko Dziemba <niko at dziemba.com>
 Nikolay Turpitko <nikolay at turpitko.com>
 Noah Campbell <noahcampbell at gmail.com>
@@ -871,6 +949,7 @@ Patrick Higgins <patrick.allen.higgins at gmail.com>
 Patrick Lee <pattyshack101 at gmail.com>
 Patrick Mézard <patrick at mezard.eu>
 Patrick Mylund Nielsen <patrick at patrickmn.com>
+Patrick Pelletier <pp.pelletier at gmail.com>
 Patrick Riley <pfr at google.com>
 Patrick Smith <pat42smith at gmail.com>
 Paul A Querna <paul.querna at gmail.com>
@@ -878,6 +957,7 @@ Paul Borman <borman at google.com>
 Paul Chang <paulchang at google.com>
 Paul Hammond <paul at paulhammond.org>
 Paul Hankin <paulhankin at google.com>
+Paul Jolly <paul at myitcv.org.uk>
 Paul Lalonde <paul.a.lalonde at gmail.com>
 Paul Marks <pmarks at google.com>
 Paul Meyer <paul.meyer at microsoft.com>
@@ -888,6 +968,7 @@ 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>
+Paulo Flabiano Smorigo <pfsmorigo at linux.vnet.ibm.com>
 Pavel Paulau <pavel.paulau at gmail.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Knap <pawelknap88 at gmail.com>
@@ -903,6 +984,7 @@ Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter McKenzie <petermck at google.com>
 Peter Moody <pmoody at uber.com>
 Peter Mundy <go.peter.90 at gmail.com>
+Peter Nguyen <peter at mictis.com>
 Péter Surányi <speter.go1 at gmail.com>
 Péter Szabó <pts at google.com>
 Péter Szilágyi <peterke at gmail.com>
@@ -921,6 +1003,7 @@ Pieter Droogendijk <pieter at binky.org.uk>
 Pietro Gagliardi <pietro10 at mac.com>
 Prasanna Swaminathan <prasanna at mediamath.com>
 Prashant Varanasi <prashant at prashantv.com>
+Pravendra Singh <hackpravj at gmail.com>
 Preetam Jinka <pj at preet.am>
 Quan Tran <qeed.quan at gmail.com>
 Quan Yong Zhai <qyzhai at gmail.com>
@@ -938,8 +1021,10 @@ Ramesh Dharan <dharan at google.com>
 Raph Levien <raph at google.com>
 Raphael Geronimi <raphael.geronimi at gmail.com>
 Raul Silvera <rsilvera at google.com>
+Raymond Kazlauskas <raima220 at gmail.com>
 Rebecca Stambler <rstambler at golang.org>
 Reinaldo de Souza Jr <juniorz at gmail.com>
+Remi Gillig <remigillig 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>
@@ -990,6 +1075,7 @@ Ryuzo Yamamoto <ryuzo.yamamoto 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 Boyer <tech at samboyer.org>
 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>
@@ -1010,6 +1096,8 @@ 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 Chittenden <seanc at joyent.com>
+Sean Christopherson <sean.j.christopherson at intel.com>
 Sean Dolphin <Sean.Dolphin at kpcompass.com>
 Sean Harger <sharger at google.com>
 Sean Rees <sean at erifax.org>
@@ -1029,6 +1117,7 @@ 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>
+Shintaro Kaneko <kaneshin0120 at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Shun Fan <sfan at google.com>
 Silvan Jegen <s.jegen at gmail.com>
@@ -1068,6 +1157,7 @@ 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>
+Takuto Ikuta <tikuta at google.com>
 Takuya Ueda <uedatakuya at gmail.com>
 Tal Shprecher <tshprecher at gmail.com>
 Tamir Duberstein <tamird at gmail.com>
@@ -1079,6 +1169,7 @@ Tetsuo Kiso <tetsuokiso9 at gmail.com>
 Than McIntosh <thanm at google.com>
 Thiago Fransosi Farina <thiago.farina at gmail.com> <tfarina at chromium.org>
 Thomas Alan Copeland <talan.copeland at gmail.com>
+Thomas Bonfort <thomas.bonfort at gmail.com>
 Thomas de Zeeuw <thomasdezeeuw at gmail.com>
 Thomas Desrosiers <thomasdesr at gmail.com>
 Thomas Habets <habets at google.com>
@@ -1107,10 +1198,12 @@ Tom Wilkie <tom at weave.works>
 Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Tormod Erevik Lea <tormodlea at gmail.com>
+Toshiki Shima <hayabusa1419 at gmail.com>
 Totoro W <tw19881113 at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Trevor Strohman <trevor.strohman at gmail.com>
 Trey Lawrence <lawrence.trey at gmail.com>
+Trey Roessig <trey.roessig at gmail.com>
 Trey Tacon <ttacon at gmail.com>
 Tristan Amini <tamini01 at ca.ibm.com>
 Tristan Colgate <tcolgate at gmail.com>
@@ -1142,18 +1235,24 @@ Vladimir Nikishenko <vova616 at gmail.com>
 Vladimir Stefanovic <vladimir.stefanovic at imgtec.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
 Volodymyr Paprotski <vpaprots at ca.ibm.com>
+Wade Simmons <wade at wades.im>
 Walter Poupore <wpoupore at google.com>
 Wedson Almeida Filho <wedsonaf at google.com>
 Wei Guangjing <vcc.163 at gmail.com>
+Wei Xiao <wei.xiao at arm.com>
+Weichao Tang <tevic.tt at gmail.com>
 Will Chan <willchan at google.com>
 Will Norris <willnorris at google.com>
+Will Storey <will at summercat.com>
 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>
+Wu Yunzhou <yunzhouwu at gmail.com>
 Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
+Xu Fei <badgangkiller at gmail.com>
 Xudong Zhang <felixmelon at gmail.com>
 Xuyang Kang <xuyangkang at gmail.com>
 Yan Zou <yzou at google.com>
@@ -1175,9 +1274,14 @@ Yuusei Kuwana <kuwana at kumama.org>
 Yuval Pavel Zholkover <paulzhol at gmail.com>
 Yves Junqueira <yvesj at google.com> <yves.junqueira at gmail.com>
 Zac Bergquist <zbergquist99 at gmail.com>
+Zach Bintliff <zbintliff at gmail.com>
+Zak <zrjknill at gmail.com>
+Zellyn Hunter <zellyn at squareup.com> <zellyn at gmail.com>
 Zev Goldstein <zev.goldstein at gmail.com>
 Zhongwei Yao <zhongwei.yao at arm.com>
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
+Максим Федосеев <max.faceless.frei at gmail.com>
 Фахриддин Балтаев <faxriddinjon at gmail.com>
+张嵩 <zs349596 at gmail.com>
 申习之 <bronze1man at gmail.com>
diff --git a/README.md b/README.md
index 672cdf5..57492b3 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@ Go is an open source programming language that makes it easy to build simple,
 reliable, and efficient software.
 
 ![Gopher image](doc/gopher/fiveyears.jpg)
+*Gopher image by [Renee French][rf], licensed under [Creative Commons 3.0 Attributions license][cc3-by].*
 
 Our canonical Git repository is located at https://go.googlesource.com/go.
 There is a mirror of the repository at https://github.com/golang/go.
@@ -39,3 +40,6 @@ Note that the Go project does not use GitHub pull requests, and that
 we use the issue tracker for bug reports and proposals only. See
 https://golang.org/wiki/Questions for a list of places to ask
 questions about the Go language.
+
+[rf]: https://reneefrench.blogspot.com/
+[cc3-by]: https://creativecommons.org/licenses/by/3.0/
diff --git a/VERSION b/VERSION
index 3e144cd..4775901 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.8.3
\ No newline at end of file
+go1.9beta1
\ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 857ebb5..fbabd18 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -1,4 +1,5 @@
 pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
+pkg math/big, type Word uintptr
 pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
 pkg os (linux-arm), const O_SYNC = 4096
 pkg os (linux-arm-cgo), const O_SYNC = 4096
diff --git a/api/go1.9.txt b/api/go1.9.txt
new file mode 100644
index 0000000..8fe861b
--- /dev/null
+++ b/api/go1.9.txt
@@ -0,0 +1,163 @@
+pkg crypto, const BLAKE2b_256 = 17
+pkg crypto, const BLAKE2b_256 Hash
+pkg crypto, const BLAKE2b_384 = 18
+pkg crypto, const BLAKE2b_384 Hash
+pkg crypto, const BLAKE2b_512 = 19
+pkg crypto, const BLAKE2b_512 Hash
+pkg crypto, const BLAKE2s_256 = 16
+pkg crypto, const BLAKE2s_256 Hash
+pkg crypto/x509, type Certificate struct, ExcludedDNSDomains []string
+pkg database/sql, method (*Conn) BeginTx(context.Context, *TxOptions) (*Tx, error)
+pkg database/sql, method (*Conn) Close() error
+pkg database/sql, method (*Conn) ExecContext(context.Context, string, ...interface{}) (Result, error)
+pkg database/sql, method (*Conn) PingContext(context.Context) error
+pkg database/sql, method (*Conn) PrepareContext(context.Context, string) (*Stmt, error)
+pkg database/sql, method (*Conn) QueryContext(context.Context, string, ...interface{}) (*Rows, error)
+pkg database/sql, method (*Conn) QueryRowContext(context.Context, string, ...interface{}) *Row
+pkg database/sql, method (*DB) Conn(context.Context) (*Conn, error)
+pkg database/sql, type Conn struct
+pkg database/sql, type Out struct
+pkg database/sql, type Out struct, Dest interface{}
+pkg database/sql, type Out struct, In bool
+pkg database/sql, var ErrConnDone error
+pkg database/sql/driver, type NamedValueChecker interface { CheckNamedValue }
+pkg database/sql/driver, type NamedValueChecker interface, CheckNamedValue(*NamedValue) error
+pkg database/sql/driver, var ErrRemoveArgument error
+pkg encoding/asn1, const TagNull = 5
+pkg encoding/asn1, const TagNull ideal-int
+pkg encoding/asn1, var NullBytes []uint8
+pkg encoding/asn1, var NullRawValue RawValue
+pkg encoding/base32, const NoPadding = -1
+pkg encoding/base32, const NoPadding int32
+pkg encoding/base32, const StdPadding = 61
+pkg encoding/base32, const StdPadding int32
+pkg encoding/base32, method (Encoding) WithPadding(int32) *Encoding
+pkg encoding/csv, type Reader struct, ReuseRecord bool
+pkg encoding/json, func Valid([]uint8) bool
+pkg go/ast, type TypeSpec struct, Assign token.Pos
+pkg go/types, func SizesFor(string, string) Sizes
+pkg go/types, method (*TypeName) IsAlias() bool
+pkg hash/fnv, func New128() hash.Hash
+pkg hash/fnv, func New128a() hash.Hash
+pkg html/template, const ErrPredefinedEscaper = 11
+pkg html/template, const ErrPredefinedEscaper ErrorCode
+pkg image/png, type Encoder struct, BufferPool EncoderBufferPool
+pkg image/png, type EncoderBuffer struct
+pkg image/png, type EncoderBufferPool interface { Get, Put }
+pkg image/png, type EncoderBufferPool interface, Get() *EncoderBuffer
+pkg image/png, type EncoderBufferPool interface, Put(*EncoderBuffer)
+pkg math/big, method (*Int) IsInt64() bool
+pkg math/big, method (*Int) IsUint64() bool
+pkg math/big, type Word uint
+pkg math/bits, const UintSize = 64
+pkg math/bits, const UintSize ideal-int
+pkg math/bits, func LeadingZeros(uint) int
+pkg math/bits, func LeadingZeros16(uint16) int
+pkg math/bits, func LeadingZeros32(uint32) int
+pkg math/bits, func LeadingZeros64(uint64) int
+pkg math/bits, func LeadingZeros8(uint8) int
+pkg math/bits, func Len(uint) int
+pkg math/bits, func Len16(uint16) int
+pkg math/bits, func Len32(uint32) int
+pkg math/bits, func Len64(uint64) int
+pkg math/bits, func Len8(uint8) int
+pkg math/bits, func OnesCount(uint) int
+pkg math/bits, func OnesCount16(uint16) int
+pkg math/bits, func OnesCount32(uint32) int
+pkg math/bits, func OnesCount64(uint64) int
+pkg math/bits, func OnesCount8(uint8) int
+pkg math/bits, func Reverse(uint) uint
+pkg math/bits, func Reverse16(uint16) uint16
+pkg math/bits, func Reverse32(uint32) uint32
+pkg math/bits, func Reverse64(uint64) uint64
+pkg math/bits, func Reverse8(uint8) uint8
+pkg math/bits, func ReverseBytes(uint) uint
+pkg math/bits, func ReverseBytes16(uint16) uint16
+pkg math/bits, func ReverseBytes32(uint32) uint32
+pkg math/bits, func ReverseBytes64(uint64) uint64
+pkg math/bits, func RotateLeft(uint, int) uint
+pkg math/bits, func RotateLeft16(uint16, int) uint16
+pkg math/bits, func RotateLeft32(uint32, int) uint32
+pkg math/bits, func RotateLeft64(uint64, int) uint64
+pkg math/bits, func RotateLeft8(uint8, int) uint8
+pkg math/bits, func TrailingZeros(uint) int
+pkg math/bits, func TrailingZeros16(uint16) int
+pkg math/bits, func TrailingZeros32(uint32) int
+pkg math/bits, func TrailingZeros64(uint64) int
+pkg math/bits, func TrailingZeros8(uint8) int
+pkg mime, var ErrInvalidMediaParameter error
+pkg mime/multipart, type FileHeader struct, Size int64
+pkg mime/multipart, var ErrMessageTooLarge error
+pkg net, method (*IPConn) SyscallConn() (syscall.RawConn, error)
+pkg net, method (*TCPConn) SyscallConn() (syscall.RawConn, error)
+pkg net, method (*UDPConn) SyscallConn() (syscall.RawConn, error)
+pkg net, method (*UnixConn) SyscallConn() (syscall.RawConn, error)
+pkg net, type Resolver struct, Dial func(context.Context, string, string) (Conn, error)
+pkg net, type Resolver struct, StrictErrors bool
+pkg net/http, func ServeTLS(net.Listener, Handler, string, string) error
+pkg net/http, method (*Server) RegisterOnShutdown(func())
+pkg net/http, method (*Server) ServeTLS(net.Listener, string, string) error
+pkg net/http/fcgi, func ProcessEnv(*http.Request) map[string]string
+pkg net/http/httptest, method (*Server) Certificate() *x509.Certificate
+pkg net/http/httptest, method (*Server) Client() *http.Client
+pkg reflect, func MakeMapWithSize(Type, int) Value
+pkg runtime/pprof, func Do(context.Context, LabelSet, func(context.Context))
+pkg runtime/pprof, func ForLabels(context.Context, func(string, string) bool)
+pkg runtime/pprof, func Label(context.Context, string) (string, bool)
+pkg runtime/pprof, func Labels(...string) LabelSet
+pkg runtime/pprof, func SetGoroutineLabels(context.Context)
+pkg runtime/pprof, func WithLabels(context.Context, LabelSet) context.Context
+pkg runtime/pprof, type LabelSet struct
+pkg sync, method (*Map) Delete(interface{})
+pkg sync, method (*Map) Load(interface{}) (interface{}, bool)
+pkg sync, method (*Map) LoadOrStore(interface{}, interface{}) (interface{}, bool)
+pkg sync, method (*Map) Range(func(interface{}, interface{}) bool)
+pkg sync, method (*Map) Store(interface{}, interface{})
+pkg sync, type Map struct
+pkg syscall (darwin-386-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (darwin-386), type Credential struct, NoSetGroups bool
+pkg syscall (darwin-amd64-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (darwin-amd64), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-386-cgo), func Pipe2([]int, int) error
+pkg syscall (freebsd-386-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-386), func Pipe2([]int, int) error
+pkg syscall (freebsd-386), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-amd64-cgo), func Pipe2([]int, int) error
+pkg syscall (freebsd-amd64-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-amd64), func Pipe2([]int, int) error
+pkg syscall (freebsd-amd64), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-arm-cgo), func Pipe2([]int, int) error
+pkg syscall (freebsd-arm-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (freebsd-arm), func Pipe2([]int, int) error
+pkg syscall (freebsd-arm), type Credential struct, NoSetGroups bool
+pkg syscall (linux-386-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (linux-386), type Credential struct, NoSetGroups bool
+pkg syscall (linux-amd64-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (linux-amd64), type Credential struct, NoSetGroups bool
+pkg syscall (linux-arm-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (linux-arm), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-386-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-386), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-amd64-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-amd64), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-arm-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (netbsd-arm), type Credential struct, NoSetGroups bool
+pkg syscall (openbsd-386-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (openbsd-386), type Credential struct, NoSetGroups bool
+pkg syscall (openbsd-amd64-cgo), type Credential struct, NoSetGroups bool
+pkg syscall (openbsd-amd64), type Credential struct, NoSetGroups bool
+pkg syscall (windows-386), const WSAECONNABORTED = 10053
+pkg syscall (windows-386), const WSAECONNABORTED Errno
+pkg syscall (windows-amd64), const WSAECONNABORTED = 10053
+pkg syscall (windows-amd64), const WSAECONNABORTED Errno
+pkg syscall, type Conn interface { SyscallConn }
+pkg syscall, type Conn interface, SyscallConn() (RawConn, error)
+pkg syscall, type RawConn interface { Control, Read, Write }
+pkg syscall, type RawConn interface, Control(func(uintptr)) error
+pkg syscall, type RawConn interface, Read(func(uintptr) bool) error
+pkg syscall, type RawConn interface, Write(func(uintptr) bool) error
+pkg testing, method (*B) Helper()
+pkg testing, method (*T) Helper()
+pkg testing, type TB interface, Helper()
+pkg time, method (Duration) Round(Duration) Duration
+pkg time, method (Duration) Truncate(Duration) Duration
diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash
index 8bbb734..cec51fd 100755
--- a/doc/articles/wiki/test.bash
+++ b/doc/articles/wiki/test.bash
@@ -20,7 +20,7 @@ trap cleanup 0 INT
 rm -f get.bin final-test.bin a.out
 
 # If called with -all, check that all code snippets compile.
-if [ "$1" == "-all" ]; then
+if [ "$1" = "-all" ]; then
 	for fn in *.go; do
 		go build -o a.out $fn
 	done
diff --git a/doc/cmd.html b/doc/cmd.html
index 4d6ac01..214b19e 100644
--- a/doc/cmd.html
+++ b/doc/cmd.html
@@ -22,6 +22,8 @@ using the go <code>tool</code> subcommand, such as <code>go tool vet</code>.
 This style of invocation allows, for instance, checking a single source file
 rather than an entire package: <code>go tool vet myprogram.go</code> as
 compared to <code>go vet mypackage</code>.
+Some of the commands, such as <code>pprof</code>, are accessible only through
+the go <code>tool</code> subcommand.
 </p>
 
 <p>
diff --git a/doc/code.html b/doc/code.html
index 796431a..ee9988b 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -124,8 +124,12 @@ workspace. It defaults to a directory named <code>go</code> inside your home dir
 so <code>$HOME/go</code> on Unix,
 <code>$home/go</code> on Plan 9,
 and <code>%USERPROFILE%\go</code> (usually <code>C:\Users\YourName\go</code>) on Windows.
-If you would like to work in a different location, you will need to set
-<code>GOPATH</code> to the path to that directory.
+</p>
+
+<p>
+If you would like to work in a different location, you will need to
+<a href="https://golang.org/wiki/SettingGOPATH">set <code>GOPATH</code></a>
+to the path to that directory.
 (Another common setup is to set <code>GOPATH=$HOME</code>.)
 Note that <code>GOPATH</code> must <b>not</b> be the
 same path as your Go installation.
diff --git a/doc/contribute.html b/doc/contribute.html
index 6977579..e3f6958 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -30,6 +30,25 @@ You must go through the following process <em>prior to contributing</em>.
 You only need to do this once per Google Account.
 </p>
 
+<h2 id="go-contrib-init">Automatically set up & diagnose your development environment</h3>
+<p>
+  The <code>go-contrib-init</code> tool configures and debugs your Go
+  development environment, automatically performing many of the steps
+  on this page, or telling you what you need to do next. If you wish
+  to use it, run:
+</p>
+
+<pre>
+$ go get -u golang.org/x/tools/cmd/go-contrib-init
+$ cd /code/to/edit
+$ go-contrib-init
+</pre>
+
+<p>
+  The tool will either set things up, tell you that everything is
+  configured, or tell you what steps you need to do manually.
+</p>
+
 <h2 id="auth">Configure Git to use Gerrit</h2>
 <p>
 You'll need a web browser and a command line terminal.
@@ -118,10 +137,10 @@ it does not need to be completed again.</i>
 You can see your currently signed agreements and sign new ones through the Gerrit
 interface.
 To do this, <a href="https://go-review.googlesource.com/login/">Log into Gerrit</a>,
-click your name in the upper-right, choose "Settings", then select "Agreements"
-from the topics on the left.
-If you do not have a signed agreement listed here,
-you can create one by clicking "New Contributor Agreement" and following the steps.
+then visit the <a href="https://go-review.googlesource.com/settings/agreements">Agreements</a>
+page.
+If you do not have a signed agreement listed there, you can create one
+by clicking "New Contributor Agreement" and following the steps.
 </p>
 
 <p>
@@ -305,10 +324,10 @@ Go to a directory where you want the source to appear and run the following
 command in a terminal.
 </p>
 
-<pre><code>
+<pre>
 $ git clone https://go.googlesource.com/go
 $ cd go
-</code></pre>
+</pre>
 
 <h3 id="master">Contributing to the main Go tree</h3>
 
@@ -396,8 +415,9 @@ and
 
 <p>
 Once you have the changes queued up, you will want to commit them.
-In the Go contribution workflow this is done with a `git change` command,
-which creates a local branch and commits the changes directly to that local branch.
+In the Go contribution workflow this is done with a <code>git</code>
+<code>change</code> command, which creates a local branch and commits the changes
+directly to that local branch.
 </p>
 
 <pre>
@@ -418,9 +438,9 @@ then <code>git</code> <code>commit</code>.)
 </p>
 
 <p>
-As the `git commit` is the final step, Git will open an editor to ask for a
-commit message.
-(It uses the editor named by the <code>$EDITOR</code> environment variable,
+As the <code>git</code> <code>commit</code> is the final step, Git will open an
+editor to ask for a commit message. (It uses the editor named by
+the <code>$EDITOR</code> environment variable,
 <code>vi</code> by default.)
 
 The file will look like:
@@ -571,7 +591,7 @@ changes to Gerrit using <code>git</code> <code>push</code> <code>origin</code>
 
 <p>
 If your change relates to an open issue, please add a comment to the issue
-announcing your proposed fix, including a link to your CL.
+announcing your proposed fix, including a link to your change.
 </p>
 
 <p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 8999a8f..e4821ff 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -15,19 +15,12 @@ git checkout <i>release-branch</i>
 <h2 id="policy">Release Policy</h2>
 
 <p>
-Each major Go release obsoletes and ends support for the previous one.
-For example, if Go 1.5 has been released, then it is the current release
-and Go 1.4 and earlier are no longer supported.
-We fix critical problems in the current release as needed by issuing minor revisions
-(for example, Go 1.5.1, Go 1.5.2, and so on).
-</p>
-
-<p>
-As a special case, we issue minor revisions for critical security problems
-in both the current release and the previous release.
-For example, if Go 1.5 is the current release then we will issue minor revisions
-to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
-See the <a href="/security">security policy</a> for more details.
+Each major Go release is supported until there are two newer major releases.
+For example, Go 1.8 is supported until Go 1.10 is released,
+and Go 1.9 is supported until Go 1.11 is released.
+We fix critical problems, including <a href="/security">critical security problems</a>,
+in supported releases as needed by issuing minor revisions
+(for example, Go 1.8.1, Go 1.8.2, and so on).
 </p>
 
 <h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index e3f3124..bc70b0c 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -1580,7 +1580,7 @@ if attended[person] { // will be false if person is not in the map
 <p>
 Sometimes you need to distinguish a missing entry from
 a zero value.  Is there an entry for <code>"UTC"</code>
-or is that the empty string because it's not in the map at all?
+or is that 0 because it's not in the map at all?
 You can discriminate with a form of multiple assignment.
 </p>
 <pre>
@@ -1833,7 +1833,7 @@ for a min function that chooses the least of a list of integers:
 </p>
 <pre>
 func Min(a ...int) int {
-    min := int(^uint(0) >> 1)  // largest int
+    min := int(^uint(0) >> 1)  // largest int
     for _, i := range a {
         if i < min {
             min = i
diff --git a/doc/go1.8.txt b/doc/go1.8.txt
deleted file mode 100644
index caa9a72..0000000
--- a/doc/go1.8.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-This file lists things yet to be moved into go1.8.html or deemed too
-minor to mention. Either way, delete from here when done.
-
-Tools:
-
-go: -buildmode=c-archive now builds PIC on ELF (CL 24180)
-go: mobile pkg dir change, recommend using go list in scripts (CL 24930, CL 27929)
-go, dist: can set default pkg-config tool using PKG_CONFIG env var (CL 29991)
-go: can set secure/insecure GIT schemes using GIT_ALLOW_PROTOCOL env var (CL 30135)
-
-API additions and behavior changes:
-
-cmd/compile, runtime, etc: get rid of constant FP registers (CL 28095)
-cmd/compile, runtime: add go:yeswritebarrierrec pragma (CL 30938)
-cmd/compile/internal/gc: enable new parser by default (CL 27203)
-cmd/compile/internal/syntax: fast Go syntax trees, initial commit (CL 27195)
-cmd/compile: add compiler phase timing (CL 24462)
-cmd/compile: add inline explainer (CL 22782)
-cmd/compile: enable flag-specified dump of specific phase+function (CL 23044)
-
-cmd/internal/obj, cmd/link: darwin dynlink support (CL 29393)
-cmd/internal/objfile: add ppc64/ppc64le disassembler support (CL 9682)
-cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end (CL 26670)
-cmd/link: R_ADDR dynamic relocs for internal PIE (CL 29118)
-cmd/link: add trampolines for too far calls in ppc64x (CL 30850)
-cmd/link: allow internal PIE linking (CL 28543)
-cmd/link: fix -X importpath.name=value when import path needs escaping (CL 31970)
-cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
-cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
-cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
-cmd/link: non-executable stack support for Solaris (CL 24142)
-cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
-cmd/link: remove the -shared flag (CL 28852)
-cmd/link: split large elf text sections on ppc64x (CL 27790)
-cmd/link: trampoline support for external linking on ARM (CL 31143)
-cmd/objdump: implement objdump of .o files (CL 24818)
-
-go/build: allow % in ${SRCDIR} expansion for Jenkins (CL 31611)
-go/build: do not record go:binary-only-package if build tags not satisfied (CL 31577)
-go/build: implement default GOPATH (CL 32019)
-
-runtime/race: update race runtime (CL 32160)
-runtime: assume 64kB physical pages on ARM (CL 25021)
-runtime: disable stack rescanning by default (CL 31766)
-runtime: don't call cgocallback from signal handler (CL 30218)
-runtime: fix check for vacuous page boundary rounding (CL 27230)
-runtime: fix map iterator concurrent map check (CL 24749)
-runtime: fix newextram PC passed to race detector (CL 29712)
-runtime: implement unconditional hybrid barrier (CL 31765)
-runtime: include pre-panic/throw logs in core dumps (CL 32013)
-runtime: limit the number of map overflow buckets (CL 25049)
-runtime: pass windows float syscall args via XMM (CL 32173)
-runtime: print sigcode on signal crash (CL 32183)
-runtime: record current PC for SIGPROF on non-Go thread (CL 30252)
-runtime: sleep on CLOCK_MONOTONIC in futexsleep1 on freebsd (CL 30154)
diff --git a/doc/go1.9.html b/doc/go1.9.html
new file mode 100644
index 0000000..63e8b7a
--- /dev/null
+++ b/doc/go1.9.html
@@ -0,0 +1,746 @@
+<!--{
+	"Title": "Go 1.9 Release Notes",
+	"Path":  "/doc/go1.9",
+	"Template": true
+}-->
+
+<!--
+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>
+
+<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.9</h2>
+
+<p><strong>
+    Go 1.9 is not yet released. These are work-in-progress
+    release notes. Go 1.9 is expected to be released in August 2017.
+</strong></p>
+
+<p>
+  The latest Go release, version 1.9, arrives six months
+  after <a href="go1.8">Go 1.8</a> and is the tenth release in
+  the <a href="https://golang.org/doc/devel/release.html">Go 1.x
+  series</a>.
+  There is one <a href="#language">change to the language</a>, adding
+  support for type aliases.
+  Most of the changes are in the implementation of the toolchain,
+  runtime, and libraries.
+  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
+  adds <a href="#monotonic-time">transparent monotonic time support</a>,
+  <a href="#parallel-compile">parallelizes compilation of functions</a> within a package,
+  better supports <a href="#test-helper">test helper functions</a>,
+  includes a new <a href="#math-bits">bit manipulation package</a>,
+  and has a new <a href="#sync-map">concurrent map type</a>.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+  There is one change to the language.
+  Go now supports type aliases to support gradual code repair while
+  moving a type between packages.
+  The <a href="https://golang.org/design/18130-type-alias">type alias
+  design document</a>
+  and <a href="https://talks.golang.org/2016/refactor.article">an
+  article on refactoring</a> cover the problem in detail.
+  In short, a type alias declaration has the form:
+</p>
+
+<pre>
+type T1 = T2
+</pre>
+
+<p>
+  This declaration introduces an alias name <code>T1</code>—an
+  alternate spelling—for the type denoted by <code>T2</code>; that is,
+  both <code>T1</code> and <code>T2</code> denote the same type.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+  There are no new supported operating systems or processor
+  architectures in this release.
+</p>
+
+<h3 id="power8">ppc64x requires Power8</h3>
+
+<p> <!-- CL 36725, CL 36832 -->
+  Both <code>GOARCH=ppc64</code> and <code>GOARCH=ppc64le</code> now
+  require at least Power8 support. In previous releases,
+  only <code>GOARCH=ppc64le</code> required Power8 and the big
+  endian <code>ppc64</code> architecture supported older
+  hardware.
+<p>
+
+<h3 id="known_issues">Known Issues</h3>
+
+<p>
+  There are some instabilities on FreeBSD that are known but not understood.
+  These can lead to program crashes in rare cases.
+  See <a href="https://golang.org/issue/15658">issue 15658</a>.
+  Any help in solving this FreeBSD-specific issue would be appreciated.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="parallel-compile">Parallel Compilation</h3>
+
+<p>
+  The Go compiler now supports compiling a package's functions in parallel, taking
+  advantage of multiple cores. This is in addition to the <code>go</code> command's
+  existing support for parallel compilation of separate packages.
+  Parallel compilation is on by default, but can be disabled by setting the
+  environment variable <code>GO19CONCURRENTCOMPILATION</code> to <code>0</code>.
+</p>
+
+<h3 id="compiler">Compiler Toolchain</h3>
+
+<p><!-- CL 37441 -->
+  Complex division is now C99-compatible. This has always been the
+  case in gccgo and is now fixed in the gc toolchain.
+</p>
+
+<p> <!-- CL 36983 -->
+  The linker will now generate DWARF information for cgo executables on Windows.
+</p>
+
+<p> <!-- CL 44210, CL 40095 -->
+  The compiler now includes lexical scopes in the generated DWARF, allowing
+  debuggers to hide variables that are not in scope. The <code>.debug_info</code>
+  section is now DWARF version 4.
+</p>
+
+<h3 id="go-test-list">Go test</h3>
+
+<p> <!-- CL 41195 -->
+  The <a href="/cmd/go/#hdr-Description_of_testing_flags"><code>go</code> <code>test</code></a>
+  command accepts a new <code>-list</code> flag, which takes a regular
+  expression as an argument and prints to stdout the name of any
+  tests, benchmarks, or examples that match it, without running them.
+</p>
+
+
+<!-- CL 42028: https://golang.org/cl/42028: cmd/asm: fix operand order of ARM's MULA instruction -->
+<!-- CL 36031: https://golang.org/cl/36031: cmd/doc: truncate long lists of arguments -->
+<!-- CL 38438: https://golang.org/cl/38438: cmd/doc: implement "go doc struct.field" -->
+<!-- CL 38745: https://golang.org/cl/38745: cmd/go: exclude vendored packages from ... matches -->
+<!-- CL 38757: https://golang.org/cl/38757: cmd/go: add -json flag to go env -->
+<!-- CL 40112: https://golang.org/cl/40112: cmd/go: allow full flag processing in go vet -->
+<!-- CL 43855: https://golang.org/cl/43855: cmd/go: include GOARM and GO386 in computed build ID -->
+<!-- CL 42990: https://golang.org/cl/42990: cmd/internal/obj/x86: add ADDSUBPS/PD -->
+<!-- CL 40331: https://golang.org/cl/40331: cmd/link,runtime/cgo: enable PT_TLS generation on OpenBSD -->
+<!-- CL 38343: https://golang.org/cl/38343: cmd/pprof: use proxy from environment -->
+
+
+<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,
+  better generated code, and optimizations in the core library.
+</p>
+
+<p> <!-- CL 39203 -->
+  TODO: There have been significant optimizations bringing more than 10% improvements
+  to implementations in the
+  <a href="/pkg/encoding/gob"><code>encoding/gob</code></a>, and ...
+  packages.
+</p>
+
+<h3 id="gc">Garbage Collector</h3>
+
+<p> <!-- CL 37520 -->
+  Library functions that used to trigger stop-the-world garbage
+  collection now trigger concurrent garbage collection.
+
+  Specifically, <a href="/pkg/runtime/#GC"><code>runtime.GC</code></a>,
+  <a href="/pkg/runtime/debug/#SetGCPercent"><code>debug.SetGCPercent</code></a>,
+  and
+  <a href="/pkg/runtime/debug/#FreeOSMemory"><code>debug.FreeOSMemory</code></a>,
+  now trigger concurrent garbage collection, blocking only the calling
+  goroutine until the garbage collection is done.
+</p>
+
+<p> <!-- CL 34103, CL 39835 -->
+  The
+  <a href="/pkg/runtime/debug/#SetGCPercent"><code>debug.SetGCPercent</code></a>
+  function only triggers a garbage collection if one is immediately
+  necessary because of the new GOGC value.
+  This makes it possible to adjust GOGC on-the-fly.
+</p>
+
+<p> <!-- CL 38732 -->
+  Large object allocation performance is significantly improved in
+  applications using large (>50GB) heaps containing many large
+  objects.
+</p>
+
+<p> <!-- CL 34937 -->
+  The <a href="/pkg/runtime/#ReadMemStats"><code>runtime.ReadMemStats</code></a>
+  function now takes less than 100µs even for very large heaps.
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3 id="monotonic-time">Transparent Monotonic Time support</h3>
+
+<p> <!-- CL 36255 -->
+  The <a href="/pkg/time/"><code>time</code></a> package now transparently
+  tracks monotonic time in each <a href="/pkg/time/#Time"><code>Time</code></a>
+  value, making computing durations between two <code>Time</code> values
+  a safe operation in the presence of wall clock adjustments.
+  See the <a href="/pkg/time/#hdr-Monotonic_Clocks">package docs</a> and
+  <a href="https://golang.org/design/12914-monotonic">design document</a>
+  for details.
+</p>
+
+<h3 id="math-bits">New bit manipulation package</h3>
+
+<p> <!-- CL 36315 -->
+  Go 1.9 includes a new package,
+  <a href="/pkg/math/bits/"><code>math/bits</code></a>, with optimized
+  implementations for manipulating bits. On most architectures
+  functions in this package are additionally recognized by the
+  compiler and treated as intrinsics for additional performance.
+</p>
+
+<h3 id="test-helper">Test Helper Functions</h3>
+
+<p> <!-- CL 38796 -->
+  The
+  new <a href="/pkg/testing/#T.Helper"><code>(*T).Helper</code></a>
+  an <a href="/pkg/testing/#B.Helper"><code>(*B).Helper</code></a>
+  methods mark the calling function as a test helper function.  When
+  printing file and line information, that function will be skipped.
+  This permits writing test helper functions while still having useful
+  line numbers for users.
+</p>
+
+<h3 id="sync-map">Concurrent Map</h3>
+
+<p> <!-- CL 36617 -->
+  The new <a href="/pkg/sync/#Map"><code>Map</code></a> type
+  in the <a href="/pkg/sync/"><code>sync</code></a> package
+  is a concurrent map with amortized-constant-time loads, stores, and
+  deletes. It is safe for multiple goroutines to call a Map's methods
+  concurrently.
+</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="archive/zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
+  <dd>
+    <p><!-- CL 39570 -->
+      The
+      ZIP <a href="/pkg/archive/zip/#Writer"><code>Writer</code></a>
+      now sets the UTF-8 bit in
+      the <a href="/pkg/archive/zip/#FileHeader.Flags"><code>FileHeader.Flags</code></a>
+      when appropriate.
+    </p>
+
+</dl><!-- archive/zip -->
+
+<dl id="crypto/rand"><dt><a href="/pkg/crypto/rand/">crypto/rand</a></dt>
+  <dd>
+    <p><!-- CL 43852 -->
+      On Linux, Go now calls the <code>getrandom</code> system call
+      without the <code>GRND_NONBLOCK</code> flag; it will now block
+      until the kernel has sufficient randomness. On kernels predating
+      the <code>getrandom</code> system call, Go continues to read
+      from <code>/dev/urandom</code>.
+    </p>
+
+</dl><!-- crypto/rand -->
+
+<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
+  <dd>
+    <p><!-- CL 36093 -->
+
+      On Unix systems the environment
+      variables <code>SSL_CERT_FILE</code>
+      and <code>SSL_CERT_DIR</code> can now be used to override the
+      system default locations for the SSL certificate file and SSL
+      certificate files directory, respectively.
+    </p>
+
+    <p>The FreeBSD path <code>/usr/local/etc/ssl/cert.pem</code> is
+      now included in the certificate search path.
+    </p>
+
+    <p><!-- CL 36900 -->
+
+      The package now supports excluded domains in name constraints.
+      In addition to enforcing such constraints,
+      <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+      will create certificates with excluded name constraints
+      if the provided template certificate has the new
+      field
+      <a href="/pkg/crypto/x509/#Certificate.ExcludedDNSDomains"><code>ExcludedDNSDomains</code></a>
+      populated.
+    </p>
+
+</dl><!-- crypto/x509 -->
+
+<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
+  <dd>
+    <p><!-- CL 35476 -->
+      The package will now use a cached <a href="/pkg/database/sql/#Stmt"><code>Stmt</code></a> if
+      available in <a href="/pkg/database/sql/#Tx.Stmt"><code>Tx.Stmt</code></a>.
+      This prevents statements from being re-prepared each time
+      <a href="/pkg/database/sql/#Tx.Stmt"><code>Tx.Stmt</code></a> is called.
+    </p>
+
+    <p><!-- CL 38533 -->
+      The package now allows drivers to implement their own argument checkers by implementing
+      <a href="/pkg/database/sql/driver/#NamedValueChecker"><code>driver.NamedValueChecker</code></a>.
+      This also allows drivers to support <code>OUTPUT</code> and <code>INOUT</code> parameter types.
+      <a href="/pkg/database/sql/#Out"><code>Out</code></a> should be used to return output parameters
+      when supported by the driver.
+    </p>
+
+    <p><!-- CL 39031 -->
+      <a href="/pkg/database/sql/#Rows.Scan"><code>Rows.Scan</code></a> can now scan user-defined string types.
+      Previously the package supported scanning into numeric types like <code>type Int int64</code>. It now also supports
+      scanning into string types like <code>type String string</code>.
+    </p>
+
+    <p><!-- CL 40694 -->
+      The new <a href="/pkg/database/sql/#DB.Conn"><code>DB.Conn</code></a> method returns the new
+      <a href="/pkg/database/sql/#Conn"><code>Conn</code></a> type representing an
+      exclusive connection to the database from the connection pool. All queries run on
+      a <a href="/pkg/database/sql/#Conn"><code>Conn</code></a> will use the same underlying
+      connection until <a href="/pkg/database/sql/#Conn.Close"><code>Conn.Close</code></a> is called
+      to return the connection to the connection pool.
+    </p>
+
+</dl><!-- database/sql -->
+
+<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
+  <dd>
+    <p><!-- CL 38660 -->
+	  The new
+	  <a href="/pkg/encoding/asn1/#NullBytes"><code>NullBytes</code></a>
+	  and
+	  <a href="/pkg/encoding/asn1/#NullRawValue"><code>NullRawValue</code></a>
+	  represent the <code>ASN.1 NULL</code> type.
+    </p>
+
+</dl><!-- encoding/asn1 -->
+
+<dl id="encoding/base32"><dt><a href="/pkg/encoding/base32/">encoding/base32</a></dt>
+  <dd>
+    <p><!-- CL 38634 --> 
+	  The new <a href="/pkg/encoding/base32/#Encoding.WithPadding">Encoding.WithPadding</a>
+	  method adds support for custom padding characters and disabling padding.
+    </p>
+
+</dl><!-- encoding/base32 -->
+
+<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
+  <dd>
+    <p><!-- CL 37051 -->
+      The sharp flag ('<code>#</code>') is now supported when printing
+      floating point and complex numbers. It will always print a
+      decimal point
+      for <code>%e</code>, <code>%E</code>, <code>%f</code>, <code>%F</code>, <code>%g</code>
+      and <code>%G</code>; it will not remove trailing zeros
+      for <code>%g</code> and <code>%G</code>.
+    </p>
+
+</dl><!-- fmt -->
+
+<dl id="hash/fnv"><dt><a href="/pkg/hash/fnv/">hash/fnv</a></dt>
+  <dd>
+    <p><!-- CL 38356 -->
+      The package now includes 128-bit FNV-1 and FNV-1a hash support with
+      <a href="/pkg/hash/fnv/#New128"><code>New128</code></a> and
+      <a href="/pkg/hash/fnv/#New128a"><code>New128a</code></a>, respectively.
+    </p>
+
+</dl><!-- hash/fnv -->
+
+<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
+  <dd>
+    <p><!-- CL 37880, CL 40936 -->
+	  The package now reports an error if a predefined escaper (one of
+	  "html", "urlquery" and "js") is found in a pipeline and its
+	  rewriting by the contextual auto-escaper could potentially lead
+	  to security or correctness issues.
+    </p>
+
+</dl><!-- html/template -->
+
+<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
+  <dd>
+    <p><!-- CL 36734 -->
+	  The <a href="/pkg/image/#Rectangle.Intersect"><code>Rectangle.Intersect</code></a>
+	  method now returns a zero <code>Rectangle</code> when called on
+	  adjacent but non-overlapping rectangles, as documented. In
+	  earlier releases it would incorrectly return an empty but
+	  non-zero <code>Rectangle</code>.
+    </p>
+
+</dl><!-- image -->
+
+<dl id="image/color"><dt><a href="/pkg/image/color/">image/color</a></dt>
+  <dd>
+    <p><!-- CL 36732 -->
+	  The YCbCr to RGBA conversion formula has been tweaked to ensure
+	  that rounding adjustments span the complete [0, 0xffff] RGBA
+	  range.
+    </p>
+
+</dl><!-- image/color -->
+
+<dl id="image/png"><dt><a href="/pkg/image/png/">image/png</a></dt>
+  <dd>
+    <p><!-- CL 34150 -->
+	  The new <a href="/pkg/image/png/#Encoder.BufferPool"><code>Encoder.BufferPool</code></a>
+	  field allows specifying an <a href="/pkg/image/png/#EncoderBufferPool"><code>EncoderBufferPool</code></a>,
+	  that will be used by the encoder to get temporary <code>EncoderBuffer</code>
+	  buffers when encoding a PNG image.
+
+	  The use of a <code>BufferPool</code> reduces the number of
+	  memory allocations performed while encoding multiple images.
+    </p>
+
+    <p><!-- CL 38271 -->
+	  The package now supports the decoding of transparent 8-bit
+	  grayscale ("Gray8") images.
+    </p>
+
+</dl><!-- image/png -->
+
+<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
+  <dd>
+    <p><!-- CL 36487 -->
+      The new
+      <a href="/pkg/math/big/#Int.IsInt64"><code>IsInt64</code></a>
+      and
+      <a href="/pkg/math/big/#Int.IsUint64"><code>IsUint64</code></a>
+      methods report whether an <code>Int</code>
+      may be represented as an <code>int64</code> or <code>uint64</code>
+      value.
+    </p>
+
+</dl><!-- math/big -->
+
+<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
+  <dd>
+    <p><!-- CL 39223 -->
+      The new
+      <a href="/pkg/mime/multipart/#FileHeader.Size"><code>FileHeader.Size</code></a>
+      field describes the size of a file in a multipart message.
+    </p>
+
+</dl><!-- mime/multipart -->
+
+<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
+  <dd>
+    <p><!-- CL 32572 -->
+      TODO: <a href="https://golang.org/cl/32572">https://golang.org/cl/32572</a>: add Resolver.StrictErrors
+    </p>
+
+    <p><!-- CL 37260 -->
+      TODO: <a href="https://golang.org/cl/37260">https://golang.org/cl/37260</a>: allow Resolver to use a custom dialer
+    </p>
+
+    <p><!-- CL 37402 -->
+      TODO: <a href="https://golang.org/cl/37402">https://golang.org/cl/37402</a>: implement deadline functionality on Pipe
+    </p>
+
+    <p><!-- CL 40510 -->
+      TODO: <a href="https://golang.org/cl/40510">https://golang.org/cl/40510</a>: don't enclose non-literal IPv6 addresses in square brackets
+    </p>
+
+    <p><!-- CL 40512 -->
+      TODO: <a href="https://golang.org/cl/40512">https://golang.org/cl/40512</a>: validate network in Dial{,IP} and Listen{Packet,IP} for IP networks
+    </p>
+
+    <p><!-- CL 37913 -->
+      The new methods
+      <a href="/pkg/net/#TCPConn.SyscallConn"><code>TCPConn.SyscallConn</code></a>,
+      <a href="/pkg/net/#IPConn.SyscallConn"><code>IPConn.SyscallConn</code></a>,
+      <a href="/pkg/net/#UDPConn.SyscallConn"><code>UDPConn.SyscallConn</code></a>,
+      and
+      <a href="/pkg/net/#UnixConn.SyscallConn"><code>UnixConn.SyscallConn</code></a>
+      provide access to the connections' underlying file descriptors.
+    </p>
+
+</dl><!-- net -->
+
+<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
+  <dd>
+
+    <p>Server changes:</p>
+    <ul>
+      <li><!-- CL 38194 -->
+        <a href="/pkg/net/http/#ServeMux"><code>ServeMux</code></a> now ignores ports in the host
+        header when matching handlers. The host is matched unmodified for <code>CONNECT</code> requests.
+      </li>
+
+      <li><!-- CL 34727 -->
+        <a href="/pkg/net/http/#Server.WriteTimeout"><code>Server.WriteTimeout</code></a>
+        now applies to HTTP/2 connections and is enforced per-stream.
+      </li>
+
+      <li><!-- CL 43231 -->
+        HTTP/2 now uses the priority write scheduler by default.
+        Frames are scheduled by following HTTP/2 priorities as described in
+        <a href="https://tools.ietf.org/html/rfc7540#section-5.3">RFC 7540 Section 5.3</a>.
+      </li>
+    </ul>
+
+    <p>Client & Transport changes:</p>
+    <ul>
+      <li><!-- CL 35488 -->
+        The <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+        now supports making requests via SOCKS5 proxy when the URL returned by
+        <a href="/net/http/#Transport.Proxy"><code>Transport.Proxy</code></a>
+        has the scheme <code>socks5</code>.
+      </li>
+    </ul>
+
+</dl><!-- net/http -->
+
+<dl id="net/http/fcgi"><dt><a href="/pkg/net/http/fcgi/">net/http/fcgi</a></dt>
+  <dd>
+    <p><!-- CL 40012 -->
+      The new
+      <a href="/pkg/net/http/fcgi/#ProcessEnv"><code>ProcessEnv</code></a>
+      function returns FastCGI environment variables associated with an HTTP request
+      for which there are no appropriate
+      <a href="/pkg/net/http/#Request"><code>http.Request</code></a>
+      fields, such as <code>REMOTE_USER</code>.
+    </p>
+
+</dl><!-- net/http/fcgi -->
+
+<dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
+  <dd>
+    <p><!-- CL 34639 -->
+      The new
+      <a href="/pkg/net/http/httptest/#Server.Client"><code>Server.Client</code></a>
+      method returns an HTTP client configured for making requests to the test server.
+    </p>
+
+    <p>
+      The new
+      <a href="/pkg/net/http/httptest/#Server.Certificate"><code>Server.Certificate</code></a>
+      method returns the test server's TLS certificate, if any.
+    </p>
+
+</dl><!-- net/http/httptest -->
+
+<dl id="net/rpc"><dt><a href="/pkg/net/rpc/">net/rpc</a></dt>
+  <dd>
+    <p><!-- CL 38474 -->
+      TODO: <a href="https://golang.org/cl/38474">https://golang.org/cl/38474</a>: Create empty maps and slices as return type
+    </p>
+
+</dl><!-- net/rpc -->
+
+<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
+  <dd>
+    <p><!-- CL 37915 -->
+      TODO: <a href="https://golang.org/cl/37915">https://golang.org/cl/37915</a>: parse command line without shell32.dll
+    </p>
+
+    <p><!-- CL 41830 -->
+      TODO: <a href="https://golang.org/cl/41830">https://golang.org/cl/41830</a>: do not report ModeDir for symlinks on windows
+    </p>
+
+</dl><!-- os -->
+
+<dl id="os/exec"><dt><a href="/pkg/os/exec/">os/exec</a></dt>
+  <dd>
+    <p><!-- CL 37586 -->
+      The <code>os/exec</code> package now prevents child processes from being created with
+      any duplicate environment variables.
+      If <a href="/pkg/os/exec/#Cmd.Env"><code>Cmd.Env</code></a>
+      contains duplicate environment keys, only the last
+      value in the slice for each duplicate key is used.
+    </p>
+
+</dl><!-- os/exec -->
+
+<dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt>
+  <dd>
+    <p><!-- CL 37664 -->
+      <a href="/pkg/os/user/#Lookup"><code>Lookup</code></a> and
+      <a href="/pkg/os/user/#LookupId"><code>LookupId</code></a> now
+      work on Unix systems when <code>CGO_ENABLED=0</code> by reading
+      the <code>/etc/passwd</code> file.
+    </p>
+
+    <p><!-- CL 33713 -->
+      <a href="/pkg/os/user/#LookupGroup"><code>LookupGroup</code></a> and
+      <a href="/pkg/os/user/#LookupGroupId"><code>LookupGroupId</code></a> now
+      work on Unix systems when <code>CGO_ENABLED=0</code> by reading
+      the <code>/etc/group</code> file.
+    </p>
+
+</dl><!-- os/user -->
+
+<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
+  <dd>
+    <p><!-- CL 38335 -->
+      The new
+      <a href="/pkg/reflect/#MakeMapWithSize"><code>MakeMapWithSize</code></a>
+      function creates a map with a capacity hint.
+    </p>
+
+</dl><!-- reflect -->
+
+<dl id="runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
+  <dd>
+    <p><!-- CL 37233, CL 37726 -->
+      Tracebacks generated by the runtime and recorded in profiles are
+      now accurate in the presence of inlining.
+      To retrieve tracebacks programmatically, applications should use
+      <a href="/pkg/runtime/#CallersFrames"><code>runtime.CallersFrames</code></a>
+      rather than directly iterating over the results of
+      <a href="/pkg/runtime/#Callers"><code>runtime.Callers</code></a>.
+    </p>
+
+    <p><!-- CL 38403 -->
+      On Windows, Go no longer forces the system timer to run at high
+      resolution when the program is idle.
+      This should reduce the impact of Go programs on battery life.
+    </p>
+
+    <p><!-- CL 29341 -->
+      On FreeBSD, <code>GOMAXPROCS</code> and
+      <a href="/pkg/runtime/#NumCPU"><code>runtime.NumCPU</code></a>
+      are now based on the process' CPU mask, rather than the total
+      number of CPUs.
+    </p>
+
+    <p><!-- CL 43641 -->
+      The runtime has preliminary support for Android O.
+    </p>
+
+</dl><!-- runtime -->
+
+<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
+  <dd>
+    <p><!-- CL 34198 -->
+      TODO: <a href="https://golang.org/cl/34198">https://golang.org/cl/34198</a>: add definitions of profile label types
+    </p>
+
+</dl><!-- runtime/pprof -->
+
+<dl id="runtime/trace"><dt><a href="/pkg/runtime/trace/">runtime/trace</a></dt>
+  <dd>
+    <p><!-- CL 36015 -->
+      The execution trace now displays mark assist events, which
+      indicate when an application goroutine is forced to assist
+      garbage collection because it is allocating too quickly.
+    </p>
+
+    <p><!-- CL 40810 -->
+      "Sweep" events now encompass the entire process of finding free
+      space for an allocation, rather than recording each individual
+      span that is swept.
+      This reduces allocation latency when tracing allocation-heavy
+      programs.
+      The sweep event shows how many bytes were swept and how many
+      were reclaimed.
+    </p>
+
+</dl><!-- runtime/trace -->
+
+<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
+  <dd>
+    <p><!-- CL 34310 -->
+      <a href="/pkg/sync/#Mutex"><code>Mutex</code></a> is now more fair.
+    </p>
+
+</dl><!-- sync -->
+
+<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
+  <dd>
+    <p><!-- CL 36697 -->
+      The new field
+      <a href="/pkg/syscall/#Credential.NoSetGroups"><code>Credential.NoSetGroups</code></a>
+      controls whether Unix systems make a <code>setgroups</code> system call
+      to set supplementary groups when starting a new process.
+    </p>
+
+    <p><!-- CL 37439 -->
+      On 64-bit x86 Linux, process creation latency has been optimized with
+      use of <code>CLONE_VFORK</code> and <code>CLONE_VM</code>.
+    </p>
+
+    <p><!-- CL 37913 -->
+      The new
+      <a href="/pkg/syscall/#Conn"><code>Conn</code></a>
+      interface describes some types in the
+      <a href="/pkg/net/"><code>net</code></a>
+      package that can provide access to their underlying file descriptor
+      using the new 
+      <a href="/pkg/syscall/#RawConn"><code>RawConn</code></a>
+      interface.
+    </p>
+
+</dl><!-- syscall -->
+
+
+<dl id="testing/quick"><dt><a href="/pkg/testing/quick/">testing/quick</a></dt>
+  <dd>
+    <p><!-- CL 39152 -->
+	  The package now chooses values in the full range when
+	  generating <code>int64</code> and <code>uint64</code> random
+	  numbers; in earlier releases generated values were always
+	  limited to the [-2<sup>62</sup>, 2<sup>62</sup>) range.
+    </p>
+
+</dl><!-- testing/quick -->
+
+<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
+  <dd>
+    <p><!-- CL 38420 -->
+	  The handling of empty blocks, which was broken by a Go 1.8
+	  change that made the result dependent on the order of templates,
+	  has been fixed, restoring the old Go 1.7 behavior.
+    </p>
+
+</dl><!-- text/template -->
+
+<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
+  <dd>
+    <p><!-- CL 36615 -->
+      The new methods
+      <a href="/pkg/time/#Duration.Round"><code>Duration.Round</code></a>
+      and 
+      <a href="/pkg/time/#Duration.Truncate"><code>Duration.Truncate</code></a>
+      handle rounding durations away from and towards zero, respectively.
+    </p>
+
+    <p><!-- CL 35710 -->
+      Retrieving the time and sleeping now work correctly under Wine.
+    </p>
+
+</dl><!-- time -->
+
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 5872eef..9ab0804 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of November 18, 2016",
+	"Subtitle": "Version of June 7, 2017",
 	"Path": "/ref/spec"
 }-->
 
@@ -154,7 +154,7 @@ Any other comment acts like a newline.
 <p>
 Tokens form the vocabulary of the Go language.
 There are four classes: <i>identifiers</i>, <i>keywords</i>, <i>operators
-and delimiters</i>, and <i>literals</i>.  <i>White space</i>, formed from
+and punctuation</i>, and <i>literals</i>.  <i>White space</i>, formed from
 spaces (U+0020), horizontal tabs (U+0009),
 carriage returns (U+000D), and newlines (U+000A),
 is ignored except as it separates tokens
@@ -197,7 +197,7 @@ into the token stream immediately after a line's final token if that token is
 	    <code>return</code>
 	</li>
 
-	<li>one of the <a href="#Operators_and_Delimiters">operators and delimiters</a>
+	<li>one of the <a href="#Operators_and_punctuation">operators and punctuation</a>
 	    <code>++</code>,
 	    <code>--</code>,
 	    <code>)</code>,
@@ -254,10 +254,11 @@ const        fallthrough  if           range        type
 continue     for          import       return       var
 </pre>
 
-<h3 id="Operators_and_Delimiters">Operators and Delimiters</h3>
+<h3 id="Operators_and_punctuation">Operators and punctuation</h3>
 
 <p>
-The following character sequences represent <a href="#Operators">operators</a>, delimiters, and other special tokens:
+The following character sequences represent <a href="#Operators">operators</a>
+(including <a href="#assign_op">assignment operators</a>) and punctuation:
 </p>
 <pre class="grammar">
 +    &     +=    &=     &&    ==    !=    (    )
@@ -685,11 +686,9 @@ If a variable has not yet been assigned a value, its value is the
 <h2 id="Types">Types</h2>
 
 <p>
-A type determines the set of values and operations specific to values of that
-type. Types may be <i>named</i> or <i>unnamed</i>. Named types are specified
-by a (possibly <a href="#Qualified_identifiers">qualified</a>)
-<a href="#Type_declarations"><i>type name</i></a>; unnamed types are specified
-using a <i>type literal</i>, which composes a new type from existing types.
+A type determines a set of values together with operations and methods specific
+to those values. A type may be denoted by a <i>type name</i>, if it has one,
+or specified using a <i>type literal</i>, which composes a type from existing types.
 </p>
 
 <pre class="ebnf">
@@ -702,6 +701,7 @@ TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType
 <p>
 Named instances of the boolean, numeric, and string types are
 <a href="#Predeclared_identifiers">predeclared</a>.
+Other named types are introduced with <a href="#Type_declarations">type declarations</a>.
 <i>Composite types</i>—array, struct, pointer, function,
 interface, slice, map, and channel types—may be constructed using
 type literals.
@@ -717,16 +717,23 @@ is the underlying type of the type to which <code>T</code> refers in its
 </p>
 
 <pre>
-   type T1 string
-   type T2 T1
-   type T3 []T1
-   type T4 T3
+type (
+	A1 = string
+	A2 = A1
+)
+
+type (
+	B1 string
+	B2 B1
+	B3 []B1
+	B4 B3
+)
 </pre>
 
 <p>
-The underlying type of <code>string</code>, <code>T1</code>, and <code>T2</code>
-is <code>string</code>. The underlying type of <code>[]T1</code>, <code>T3</code>,
-and <code>T4</code> is <code>[]T1</code>.
+The underlying type of <code>string</code>, <code>A1</code>, <code>A2</code>, <code>B1</code>,
+and <code>B2</code> is <code>string</code>.
+The underlying type of <code>[]B1</code>, <code>B3</code>, and <code>B4</code> is <code>[]B1</code>.
 </p>
 
 <h3 id="Method_sets">Method sets</h3>
@@ -738,7 +745,7 @@ The method set of any other type <code>T</code> consists of all
 The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
 is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
 (that is, it also contains the method set of <code>T</code>).
-Further rules apply to structs containing anonymous fields, as described
+Further rules apply to structs containing embedded fields, as described
 in the section on <a href="#Struct_types">struct types</a>.
 Any other type has an empty method set.
 In a method set, each method must have a
@@ -947,16 +954,16 @@ Moreover, the inner slices must be initialized individually.
 <p>
 A struct is a sequence of named elements, called fields, each of which has a
 name and a type. Field names may be specified explicitly (IdentifierList) or
-implicitly (AnonymousField).
+implicitly (EmbeddedField).
 Within a struct, non-<a href="#Blank_identifier">blank</a> field names must
 be <a href="#Uniqueness_of_identifiers">unique</a>.
 </p>
 
 <pre class="ebnf">
-StructType     = "struct" "{" { FieldDecl ";" } "}" .
-FieldDecl      = (IdentifierList Type | AnonymousField) [ Tag ] .
-AnonymousField = [ "*" ] TypeName .
-Tag            = string_lit .
+StructType    = "struct" "{" { FieldDecl ";" } "}" .
+FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
+EmbeddedField = [ "*" ] TypeName .
+Tag           = string_lit .
 </pre>
 
 <pre>
@@ -974,16 +981,15 @@ struct {
 </pre>
 
 <p>
-A field declared with a type but no explicit field name is an <i>anonymous field</i>,
-also called an <i>embedded</i> field or an embedding of the type in the struct.
-An embedded type must be specified as
+A field declared with a type but no explicit field name is called an <i>embedded field</i>.
+An embedded field must be specified as
 a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
 and <code>T</code> itself may not be
 a pointer type. The unqualified type name acts as the field name.
 </p>
 
 <pre>
-// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
+// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
 struct {
 	T1        // field name is T1
 	*T2       // field name is T2
@@ -1000,15 +1006,15 @@ in a struct type:
 
 <pre>
 struct {
-	T     // conflicts with anonymous field *T and *P.T
-	*T    // conflicts with anonymous field T and *P.T
-	*P.T  // conflicts with anonymous field T and *T
+	T     // conflicts with embedded field *T and *P.T
+	*T    // conflicts with embedded field T and *P.T
+	*P.T  // conflicts with embedded field T and *T
 }
 </pre>
 
 <p>
 A field or <a href="#Method_declarations">method</a> <code>f</code> of an
-anonymous field in a struct <code>x</code> is called <i>promoted</i> if
+embedded field in a struct <code>x</code> is called <i>promoted</i> if
 <code>x.f</code> is a legal <a href="#Selectors">selector</a> that denotes
 that field or method <code>f</code>.
 </p>
@@ -1025,7 +1031,7 @@ promoted methods are included in the method set of the struct as follows:
 </p>
 <ul>
 	<li>
-	If <code>S</code> contains an anonymous field <code>T</code>,
+	If <code>S</code> contains an embedded field <code>T</code>,
 	the <a href="#Method_sets">method sets</a> of <code>S</code>
 	and <code>*S</code> both include promoted methods with receiver
 	<code>T</code>. The method set of <code>*S</code> also
@@ -1033,7 +1039,7 @@ promoted methods are included in the method set of the struct as follows:
 	</li>
 
 	<li>
-	If <code>S</code> contains an anonymous field <code>*T</code>,
+	If <code>S</code> contains an embedded field <code>*T</code>,
 	the method sets of <code>S</code> and <code>*S</code> both
 	include promoted methods with receiver <code>T</code> or
 	<code>*T</code>.
@@ -1418,11 +1424,10 @@ Two types are either <i>identical</i> or <i>different</i>.
 </p>
 
 <p>
-Two <a href="#Types">named types</a> are identical if their type names originate in the same
-<a href="#Type_declarations">TypeSpec</a>.
-A named and an <a href="#Types">unnamed type</a> are always different. Two unnamed types are identical
-if the corresponding type literals are identical, that is, if they have the same
-literal structure and corresponding components have identical types. In detail:
+A <a href="#Type_definitions">defined type</a> is always different from any other type.
+Otherwise, two types are identical if their <a href="#Types">underlying</a> type literals are
+structurally equivalent; that is, they have the same literal structure and corresponding
+components have identical types. In detail:
 </p>
 
 <ul>
@@ -1434,8 +1439,8 @@ literal structure and corresponding components have identical types. In detail:
 	<li>Two struct types are identical if they have the same sequence of fields,
 	    and if corresponding fields have the same names, and identical types,
 	    and identical tags.
-	    Two anonymous fields are considered to have the same name. Lower-case field
-	    names from different packages are always different.</li>
+	    <a href="#Exported_identifiers">Non-exported</a> field names from different
+	    packages are always different.</li>
 
 	<li>Two pointer types are identical if they have identical base types.</li>
 
@@ -1445,8 +1450,9 @@ literal structure and corresponding components have identical types. In detail:
 	    Parameter and result names are not required to match.</li>
 
 	<li>Two interface types are identical if they have the same set of methods
-	    with the same names and identical function types. Lower-case method names from
-	    different packages are always different. The order of the methods is irrelevant.</li>
+	    with the same names and identical function types.
+	    <a href="#Exported_identifiers">Non-exported</a> method names from different
+	    packages are always different. The order of the methods is irrelevant.</li>
 
 	<li>Two map types are identical if they have identical key and value types.</li>
 
@@ -1460,13 +1466,24 @@ Given the declarations
 
 <pre>
 type (
-	T0 []string
-	T1 []string
-	T2 struct{ a, b int }
-	T3 struct{ a, c int }
-	T4 func(int, float64) *T0
-	T5 func(x int, y float64) *[]string
+	A0 = []string
+	A1 = A0
+	A2 = struct{ a, b int }
+	A3 = int
+	A4 = func(A3, float64) *A0
+	A5 = func(x int, _ float64) *[]string
 )
+
+type (
+	B0 A0
+	B1 []string
+	B2 struct{ a, b int }
+	B3 struct{ a, c int }
+	B4 func(int, float64) *B0
+	B5 func(x int, y float64) *A1
+)
+
+type	C0 = B0
 </pre>
 
 <p>
@@ -1474,17 +1491,22 @@ these types are identical:
 </p>
 
 <pre>
-T0 and T0
+A0, A1, and []string
+A2 and struct{ a, b int }
+A3 and int
+A4, func(int, float64) *[]string, and A5
+
+B0, B0, and C0
 []int and []int
 struct{ a, b *T5 } and struct{ a, b *T5 }
-func(x int, y float64) *[]string and func(int, float64) (result *[]string)
+func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5
 </pre>
 
 <p>
-<code>T0</code> and <code>T1</code> are different because they are named types
-with distinct declarations; <code>func(int, float64) *T0</code> and
-<code>func(x int, y float64) *[]string</code> are different because <code>T0</code>
-is different from <code>[]string</code>.
+<code>B0</code> and <code>B1</code> are different because they are new types
+created by distinct <a href="#Type_definitions">type definitions</a>;
+<code>func(int, float64) *B0</code> and <code>func(x int, y float64) *[]string</code>
+are different because <code>B0</code> is different from <code>[]string</code>.
 </p>
 
 
@@ -1502,7 +1524,7 @@ A value <code>x</code> is <i>assignable</i> to a <a href="#Variables">variable</
 <li>
 <code>x</code>'s type <code>V</code> and <code>T</code> have identical
 <a href="#Types">underlying types</a> and at least one of <code>V</code>
-or <code>T</code> is not a <a href="#Types">named type</a>.
+or <code>T</code> is not a <a href="#Type_definitions">defined</a> type.
 </li>
 <li>
 <code>T</code> is an interface type and
@@ -1511,7 +1533,7 @@ or <code>T</code> is not a <a href="#Types">named type</a>.
 <li>
 <code>x</code> is a bidirectional channel value, <code>T</code> is a channel type,
 <code>x</code>'s type <code>V</code> and <code>T</code> have identical element types,
-and at least one of <code>V</code> or <code>T</code> is not a named type.
+and at least one of <code>V</code> or <code>T</code> is not a defined type.
 </li>
 <li>
 <code>x</code> is the predeclared identifier <code>nil</code> and <code>T</code>
@@ -1840,23 +1862,60 @@ last non-empty expression list.
 <h3 id="Type_declarations">Type declarations</h3>
 
 <p>
-A type declaration binds an identifier, the <i>type name</i>, to a new type
-that has the same <a href="#Types">underlying type</a> as an existing type,
-and operations defined for the existing type are also defined for the new type.
-The new type is <a href="#Type_identity">different</a> from the existing type.
+A type declaration binds an identifier, the <i>type name</i>, to a <a href="#Types">type</a>.
+Type declarations come in two forms: alias declarations and type definitions.
+<p>
+
+<pre class="ebnf">
+TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
+TypeSpec = AliasDecl | TypeDef .
+</pre>
+
+<h4 id="Alias_declarations">Alias declarations</h4>
+
+<p>
+An alias declaration binds an identifier to the given type.
 </p>
 
 <pre class="ebnf">
-TypeDecl     = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
-TypeSpec     = identifier Type .
+AliasDecl = identifier "=" Type .
 </pre>
 
+<p>
+Within the <a href="#Declarations_and_scope">scope</a> of
+the identifier, it serves as an <i>alias</i> for the type.
+</p>
+
 <pre>
-type IntArray [16]int
+type (
+	nodeList = []*Node  // nodeList and []*Node are identical types
+	Polar    = polar    // Polar and polar denote identical types
+)
+</pre>
+
+
+<h4 id="Type_definitions">Type definitions</h4>
 
+<p>
+A type definition creates a new, distinct type with the same
+<a href="#Types">underlying type</a> and operations as the given type,
+and binds an identifier to it.
+</p>
+
+<pre class="ebnf">
+TypeDef = identifier Type .
+</pre>
+
+<p>
+The new type is called a <i>defined type</i>.
+It is <a href="#Type_identity">different</a> from any other type,
+including the type it is created from.
+</p>
+
+<pre>
 type (
-	Point struct{ x, y float64 }
-	Polar Point
+	Point struct{ x, y float64 }  // Point and struct{ x, y float64 } are different types
+	polar Point                   // polar and Point denote different types
 )
 
 type TreeNode struct {
@@ -1872,8 +1931,9 @@ type Block interface {
 </pre>
 
 <p>
-The declared type does not inherit any <a href="#Method_declarations">methods</a>
-bound to the existing type, but the <a href="#Method_sets">method set</a>
+A defined type may have <a href="#Method_declarations">methods</a> associated with it.
+It does not inherit any methods bound to the given type,
+but the <a href="#Method_sets">method set</a>
 of an interface type or of elements of a composite type remains unchanged:
 </p>
 
@@ -1891,7 +1951,7 @@ type NewMutex Mutex
 type PtrMutex *Mutex
 
 // The method set of *PrintableMutex contains the methods
-// Lock and Unlock bound to its anonymous field Mutex.
+// Lock and Unlock bound to its embedded field Mutex.
 type PrintableMutex struct {
 	Mutex
 }
@@ -1901,8 +1961,8 @@ type MyBlock Block
 </pre>
 
 <p>
-A type declaration may be used to define a different boolean, numeric, or string
-type and attach methods to it:
+Type definitions may be used to define different boolean, numeric,
+or string types and associate methods with them:
 </p>
 
 <pre>
@@ -1924,8 +1984,8 @@ func (tz TimeZone) String() string {
 <h3 id="Variable_declarations">Variable declarations</h3>
 
 <p>
-A variable declaration creates one or more variables, binds corresponding
-identifiers to them, and gives each a type and an initial value.
+A variable declaration creates one or more <a href="#Variables">variables</a>,
+binds corresponding identifiers to them, and gives each a type and an initial value.
 </p>
 
 <pre class="ebnf">
@@ -2083,8 +2143,8 @@ and associates the method with the receiver's <i>base type</i>.
 </p>
 
 <pre class="ebnf">
-MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
-Receiver     = Parameters .
+MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
+Receiver   = Parameters .
 </pre>
 
 <p>
@@ -2093,7 +2153,7 @@ name. That parameter section must declare a single non-variadic parameter, the r
 Its type must be of the form <code>T</code> or <code>*T</code> (possibly using
 parentheses) where <code>T</code> is a type name. The type denoted by <code>T</code> is called
 the receiver <i>base type</i>; it must not be a pointer or interface type and
-it must be declared in the same package as the method.
+it must be <a href="#Type_definitions">defined</a> in the same package as the method.
 The method is said to be <i>bound</i> to the base type and the method name
 is visible only within <a href="#Selectors">selectors</a> for type <code>T</code>
 or <code>*T</code>.
@@ -2235,7 +2295,8 @@ The key is interpreted as a field name for struct literals,
 an index for array and slice literals, and a key for map literals.
 For map literals, all elements must have a key. It is an error
 to specify multiple elements with the same field name or
-constant key value.
+constant key value. For non-constant map keys, see the section on
+<a href="#Order_of_evaluation">evaluation order</a>.
 </p>
 
 <p>
@@ -2492,13 +2553,13 @@ If <code>x</code> is a package name, see the section on
 A selector <code>f</code> may denote a field or method <code>f</code> of
 a type <code>T</code>, or it may refer
 to a field or method <code>f</code> of a nested
-<a href="#Struct_types">anonymous field</a> of <code>T</code>.
-The number of anonymous fields traversed
+<a href="#Struct_types">embedded field</a> of <code>T</code>.
+The number of embedded fields traversed
 to reach <code>f</code> is called its <i>depth</i> in <code>T</code>.
 The depth of a field or method <code>f</code>
 declared in <code>T</code> is zero.
 The depth of a field or method <code>f</code> declared in
-an anonymous field <code>A</code> in <code>T</code> is the
+an embedded field <code>A</code> in <code>T</code> is the
 depth of <code>f</code> in <code>A</code> plus one.
 </p>
 
@@ -3323,7 +3384,7 @@ to the type of the other operand.
 
 <p>
 The right operand in a shift expression must have unsigned integer type
-or be an untyped constant that can be converted to unsigned integer type.
+or be an untyped constant representable by a value of type <code>uint</code>.
 If the left operand of a non-constant shift expression is an untyped constant,
 it is first converted to the type it would assume if the shift expression were
 replaced by its left operand alone.
@@ -3521,6 +3582,33 @@ IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
 occurs is implementation-specific.
 </p>
 
+<p>
+An implementation may combine multiple floating-point operations into a single
+fused operation, possibly across statements, and produce a result that differs
+from the value obtained by executing and rounding the instructions individually.
+A floating-point type <a href="#Conversions">conversion</a> explicitly rounds to
+the precision of the target type, preventing fusion that would discard that rounding.
+</p>
+
+<p>
+For instance, some architectures provide a "fused multiply and add" (FMA) instruction
+that computes <code>x*y + z</code> without rounding the intermediate result <code>x*y</code>.
+These examples show when a Go implementation can use that instruction:
+</p>
+
+<pre>
+// FMA allowed for computing r, because x*y is not explicitly rounded:
+r  = x*y + z
+r  = z;   r += x*y
+t  = x*y; r = t + z
+*p = x*y; r = *p + z
+r  = x*y + float64(z)
+
+// FMA disallowed for computing r, because it would omit rounding of x*y:
+r  = float64(x*y) + z
+r  = z; r += float64(x*y)
+t  = float64(x*y); r = t + z
+</pre>
 
 <h4 id="String_concatenation">String concatenation</h4>
 
@@ -3579,7 +3667,7 @@ These terms and the result of the comparisons are defined as follows:
 	</li>
 
 	<li>
-	Floating point values are comparable and ordered,
+	Floating-point values are comparable and ordered,
 	as defined by the IEEE-754 standard.
 	</li>
 
@@ -3849,7 +3937,8 @@ in any of these cases:
 	</li>
 	<li>
 	ignoring struct tags (see below),
-	<code>x</code>'s type and <code>T</code> are unnamed pointer types
+	<code>x</code>'s type and <code>T</code> are pointer types
+	that are not <a href="#Type_definitions">defined types</a>,
 	and their pointer base types have identical underlying types.
 	</li>
 	<li>
@@ -4434,8 +4523,8 @@ a[i] = 23
 
 <p>
 An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
-<code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
-to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
+<code>y</code> where <i>op</i> is a binary <a href="#Arithmetic_operators">arithmetic operator</a>
+is equivalent to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
 <code>(y)</code> but evaluates <code>x</code>
 only once.  The <i>op</i><code>=</code> construct is a single token.
 In assignment operations, both the left- and right-hand expression lists
@@ -5037,7 +5126,7 @@ function completes.
 
 <pre>
 go Server()
-go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)
+go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
 </pre>
 
 
@@ -5583,7 +5672,7 @@ make(T, n)       slice      slice of type T with length n and capacity n
 make(T, n, m)    slice      slice of type T with length n and capacity m
 
 make(T)          map        map of type T
-make(T, n)       map        map of type T with initial space for n elements
+make(T, n)       map        map of type T with initial space for approximately n elements
 
 make(T)          channel    unbuffered channel of type T
 make(T, n)       channel    buffered channel of type T, buffer size n
@@ -5606,9 +5695,15 @@ s := make([]int, 1e3)           // slice with len(s) == cap(s) == 1000
 s := make([]int, 1<<63)         // illegal: len(s) is not representable by a value of type int
 s := make([]int, 10, 0)         // illegal: len(s) > cap(s)
 c := make(chan int, 10)         // channel with a buffer size of 10
-m := make(map[string]int, 100)  // map with initial space for 100 elements
+m := make(map[string]int, 100)  // map with initial space for approximately 100 elements
 </pre>
 
+<p>
+Calling <code>make</code> with a map type and size hint <code>n</code> will
+create a map with initial space to hold <code>n</code> map elements.
+The precise behavior is implementation-dependent.
+</p>
+
 
 <h3 id="Appending_and_copying_slices">Appending to and copying slices</h3>
 
@@ -5870,6 +5965,11 @@ print      prints all arguments; formatting of arguments is implementation-speci
 println    like print but prints spaces between arguments and a newline at the end
 </pre>
 
+<p>
+Implementation restriction: <code>print</code> and <code>println</code> need not
+accept arbitrary argument types, but printing of boolean, numeric, and string
+<a href="#Types">types</a> must be supported.
+</p>
 
 <h2 id="Packages">Packages</h2>
 
@@ -6331,7 +6431,7 @@ func Sizeof(variable ArbitraryType) uintptr
 A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
 value may not be <a href="#Address_operators">dereferenced</a>.
 Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
-a <code>Pointer</code> type and vice versa.
+a type of underlying type <code>Pointer</code> and vice versa.
 The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
 </p>
 
@@ -6409,7 +6509,7 @@ The following minimal alignment properties are guaranteed:
 </li>
 
 <li>For a variable <code>x</code> of array type: <code>unsafe.Alignof(x)</code> is the same as
-   <code>unsafe.Alignof(x[0])</code>, but at least 1.
+	the alignment of a variable of the array's element type.
 </li>
 </ol>
 
diff --git a/doc/help.html b/doc/help.html
index 62d9a4a..057d752 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -59,6 +59,12 @@ The <a href="https://reddit.com/r/golang">golang sub-Reddit</a> is a place
 for Go news and discussion.
 </p>
 
+<h3 id="gotime"><a href="https://changelog.com/gotime">Go Time Podcast</a></h3>
+<p>
+The <a href="https://changelog.com/gotime">Go Time podcast</a> is a panel of Go experts and special guests
+discussing the Go programming language, the community, and everything in between.
+</p>
+
 <h2 id="community">Community resources</h2>
 
 <h3 id="go_user_groups"><a href="/wiki/GoUserGroups">Go User Groups</a></h3>
diff --git a/doc/install-source.html b/doc/install-source.html
index 8fb26a9..5d732b0 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -143,7 +143,7 @@ packaged Go distribution.
 <p>
 To build a bootstrap tool chain from source, use
 either the git branch <code>release-branch.go1.4</code> or
-<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz">go1.4-bootstrap-20161024.tar.gz</a>,
+<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz">go1.4-bootstrap-20170531.tar.gz</a>,
 which contains the Go 1.4 source code plus accumulated fixes
 to keep the tools running on newer operating systems.
 (Go 1.4 was the last distribution in which the tool chain was written in C.)
diff --git a/doc/install.html b/doc/install.html
index 6bff75c..9de3aad 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -222,8 +222,7 @@ and building a simple program, as follows.
 Create your <a href="code.html#Workspaces">workspace</a> directory,
 <code class="testUnix">$HOME/go</code><code class="testWindows">%USERPROFILE%\go</code>.
 (If you'd like to use a different directory,
-you will need to set the <code>GOPATH</code> environment variable;
-see <a href="code.html#Workspaces">How to Write Go Code</a> for details.)
+you will need to <a href="https://golang.org/wiki/SettingGOPATH">set the <code>GOPATH</code> environment variable</a>.)
 </p>
 
 <p>
diff --git a/doc/security.html b/doc/security.html
index 5911586..0d8b5ee 100644
--- a/doc/security.html
+++ b/doc/security.html
@@ -20,7 +20,7 @@ This mail is delivered to a small security team.
 Your email will be acknowledged within 24 hours, and you'll receive a more
 detailed response to your email within 72 hours indicating the next steps in
 handling your report.
-If you would like, you can encrypt your report using our PGP key (listed below).
+For critical problems, you can encrypt your report using our PGP key (listed below).
 </p>
 
 <p>
@@ -118,6 +118,12 @@ If you have any suggestions to improve this policy, please send an email to
 
 <h3>PGP Key for <a href="mailto:security at golang.org">security at golang.org</a></h3>
 
+<p>
+We accept PGP-encrypted email, but the majority of the security team
+are not regular PGP users so it's somewhat inconvenient. Please only
+use PGP for critical security reports.
+</p>
+
 <pre>
 -----BEGIN PGP PUBLIC KEY BLOCK-----
 Comment: GPGTools - https://gpgtools.org
diff --git a/lib/time/update.bash b/lib/time/update.bash
index 4297c5f..6261f81 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -8,8 +8,8 @@
 # Consult http://www.iana.org/time-zones for the latest versions.
 
 # Versions to use.
-CODE=2016j
-DATA=2016j
+CODE=2017b
+DATA=2017b
 
 set -e
 rm -rf work
@@ -42,7 +42,7 @@ zip -0 -r ../../zoneinfo.zip *
 cd ../..
 
 echo
-if [ "$1" == "-work" ]; then 
+if [ "$1" = "-work" ]; then 
 	echo Left workspace behind in work/.
 else
 	rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index d33dc1d..b60ae7f 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 ebff845..49b7ae9 100644
--- a/misc/android/go_android_exec.go
+++ b/misc/android/go_android_exec.go
@@ -24,7 +24,16 @@ func run(args ...string) string {
 	buf := new(bytes.Buffer)
 	cmd := exec.Command("adb", args...)
 	cmd.Stdout = io.MultiWriter(os.Stdout, buf)
-	cmd.Stderr = os.Stderr
+	// If the adb subprocess somehow hangs, go test will kill this wrapper
+	// and wait for our os.Stderr (and os.Stdout) to close as a result.
+	// However, if the os.Stderr (or os.Stdout) file descriptors are
+	// passed on, the hanging adb subprocess will hold them open and
+	// go test will hang forever.
+	//
+	// Avoid that by wrapping stderr, breaking the short circuit and
+	// forcing cmd.Run to use another pipe and goroutine to pass
+	// along stderr from adb.
+	cmd.Stderr = struct{ io.Writer }{os.Stderr}
 	log.Printf("adb %s", strings.Join(args, " "))
 	err := cmd.Run()
 	if err != nil {
diff --git a/misc/cgo/errors/issue18452.go b/misc/cgo/errors/issue18452.go
new file mode 100644
index 0000000..36ef7f5
--- /dev/null
+++ b/misc/cgo/errors/issue18452.go
@@ -0,0 +1,18 @@
+// Copyright 2017 The Go 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 18452: show pos info in undefined name errors
+
+package p
+
+import (
+	"C"
+	"fmt"
+)
+
+func a() {
+	fmt.Println("Hello, world!")
+	C.function_that_does_not_exist() // line 16
+	C.pi                             // line 17
+}
diff --git a/misc/cgo/errors/issue18889.go b/misc/cgo/errors/issue18889.go
new file mode 100644
index 0000000..bba6b8f
--- /dev/null
+++ b/misc/cgo/errors/issue18889.go
@@ -0,0 +1,7 @@
+package main
+
+import "C"
+
+func main() {
+	_ = C.malloc // ERROR HERE
+}
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index 05261e9..ed0b094 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -17,7 +17,7 @@ check() {
 expect() {
 	file=$1
 	shift
-	if go build $file >errs 2>&1; then
+	if go build -gcflags=-C $file >errs 2>&1; then
 		echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded
 		exit 1
 	fi
@@ -47,6 +47,8 @@ expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulongl
 check issue13830.go
 check issue16116.go
 check issue16591.go
+check issue18889.go
+expect issue18452.go issue18452.go:16 issue18452.go:17
 
 if ! go build issue14669.go; then
 	exit 1
diff --git a/misc/cgo/fortran/test.bash b/misc/cgo/fortran/test.bash
index 3d1bc9d..1e0d59e 100755
--- a/misc/cgo/fortran/test.bash
+++ b/misc/cgo/fortran/test.bash
@@ -12,7 +12,7 @@ FC=$1
 goos=$(go env GOOS)
 
 libext="so"
-if [ "$goos" == "darwin" ]; then
+if [ "$goos" = "darwin" ]; then
 	libext="dylib"
 fi
 
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index a6de999..f248381 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -76,5 +76,8 @@ func TestThreadLock(t *testing.T)            { testThreadLockFunc(t) }
 func TestCheckConst(t *testing.T)            { testCheckConst(t) }
 func Test17537(t *testing.T)                 { test17537(t) }
 func Test18126(t *testing.T)                 { test18126(t) }
+func Test20369(t *testing.T)                 { test20369(t) }
+func Test18720(t *testing.T)                 { test18720(t) }
+func Test20266(t *testing.T)                 { test20266(t) }
 
 func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/issue18720.go b/misc/cgo/test/issue18720.go
new file mode 100644
index 0000000..a933044
--- /dev/null
+++ b/misc/cgo/test/issue18720.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go Authors. 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
+
+/*
+#define HELLO "hello"
+#define WORLD "world"
+#define HELLO_WORLD HELLO "\000" WORLD
+
+struct foo { char c; };
+#define SIZE_OF(x) sizeof(x)
+#define SIZE_OF_FOO SIZE_OF(struct foo)
+*/
+import "C"
+import "testing"
+
+func test18720(t *testing.T) {
+	if C.HELLO_WORLD != "hello\000world" {
+		t.Fatalf(`expected "hello\000world", but got %q`, C.HELLO_WORLD)
+	}
+
+	// Issue 20125.
+	if got, want := C.SIZE_OF_FOO, 1; got != want {
+		t.Errorf("C.SIZE_OF_FOO == %v, expected %v", got, want)
+	}
+}
diff --git a/misc/cgo/test/issue20266.go b/misc/cgo/test/issue20266.go
new file mode 100644
index 0000000..9f95086
--- /dev/null
+++ b/misc/cgo/test/issue20266.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go 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 20266: use -I with a relative path.
+
+package cgotest
+
+/*
+#cgo CFLAGS: -I issue20266 -Iissue20266 -Ddef20266
+#include "issue20266.h"
+*/
+import "C"
+
+import "testing"
+
+func test20266(t *testing.T) {
+	if got, want := C.issue20266, 20266; got != want {
+		t.Errorf("got %d, want %d", got, want)
+	}
+}
diff --git a/misc/cgo/test/issue20266/issue20266.h b/misc/cgo/test/issue20266/issue20266.h
new file mode 100644
index 0000000..8d3258e
--- /dev/null
+++ b/misc/cgo/test/issue20266/issue20266.h
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define issue20266 20266
+
+#ifndef def20266
+#error "expected def20266 to be defined"
+#endif
diff --git a/misc/cgo/test/issue20369.go b/misc/cgo/test/issue20369.go
new file mode 100644
index 0000000..37b4b78
--- /dev/null
+++ b/misc/cgo/test/issue20369.go
@@ -0,0 +1,20 @@
+// Copyright 2017 The Go Authors. 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
+
+/*
+#define UINT64_MAX        18446744073709551615ULL
+*/
+import "C"
+import (
+	"math"
+	"testing"
+)
+
+func test20369(t *testing.T) {
+	if C.UINT64_MAX != math.MaxUint64 {
+		t.Fatalf("got %v, want %v", uint64(C.UINT64_MAX), uint64(math.MaxUint64))
+	}
+}
diff --git a/misc/cgo/test/issue6612.go b/misc/cgo/test/issue6612.go
index c337f91..15a12fa 100644
--- a/misc/cgo/test/issue6612.go
+++ b/misc/cgo/test/issue6612.go
@@ -74,18 +74,15 @@ func testNaming(t *testing.T) {
 		}
 	}
 
-	// This would be nice, but it has never worked.
-	/*
-		if c := C.myfloat_def; c != 1.5 {
-			t.Errorf("C.myint_def = %v, want 1.5", c)
-		}
-		{
-			const c = C.myfloat_def
-			if c != 1.5 {
+	if c := C.myfloat_def; c != 1.5 {
+		t.Errorf("C.myint_def = %v, want 1.5", c)
+	}
+	{
+		const c = C.myfloat_def
+		if c != 1.5 {
 			t.Errorf("C.myint as const = %v, want 1.5", c)
-			}
 		}
-	*/
+	}
 
 	if s := C.mystring_def; s != "hello" {
 		t.Errorf("C.mystring_def = %q, want %q", s, "hello")
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index 4999929..74897c7 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -115,8 +115,10 @@ func init() {
 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)
+		fmt.Fprintf(os.Stderr, "go env %s failed:\n%s\n", key, err)
+		if ee, ok := err.(*exec.ExitError); ok {
+			fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
+		}
 		os.Exit(2)
 	}
 	return strings.TrimSpace(string(out))
@@ -218,15 +220,7 @@ func TestEarlySignalHandler(t *testing.T) {
 }
 
 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")
-	}
+	checkSignalForwardingTest(t)
 
 	defer func() {
 		os.Remove("libgo2.a")
@@ -251,32 +245,19 @@ func TestSignalForwarding(t *testing.T) {
 	cmd = exec.Command(bin[0], append(bin[1:], "1")...)
 
 	out, err := cmd.CombinedOutput()
+	t.Logf("%s", out)
+	expectSignal(t, err, syscall.SIGSEGV)
 
-	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)
-	}
+	// Test SIGPIPE forwarding
+	cmd = exec.Command(bin[0], append(bin[1:], "3")...)
+
+	out, err = cmd.CombinedOutput()
+	t.Logf("%s", out)
+	expectSignal(t, err, syscall.SIGPIPE)
 }
 
 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")
-	}
+	checkSignalForwardingTest(t)
 
 	defer func() {
 		os.Remove("libgo2.a")
@@ -344,14 +325,7 @@ func TestSignalForwardingExternal(t *testing.T) {
 			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.
+		if expectSignal(t, err, syscall.SIGSEGV) {
 			return
 		}
 	}
@@ -359,6 +333,38 @@ func TestSignalForwardingExternal(t *testing.T) {
 	t.Errorf("program succeeded unexpectedly %d times", tries)
 }
 
+// checkSignalForwardingTest calls t.Skip if the SignalForwarding test
+// doesn't work on this platform.
+func checkSignalForwardingTest(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")
+	}
+}
+
+// expectSignal checks that err, the exit status of a test program,
+// shows a failure due to a specific signal. Returns whether we found
+// the expected signal.
+func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
+	if err == nil {
+		t.Error("test program succeeded unexpectedly")
+	} else 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() != sig {
+		t.Errorf("got %v; expected signal %v", ee, sig)
+	} else {
+		return true
+	}
+	return false
+}
+
 func TestOsSignal(t *testing.T) {
 	switch GOOS {
 	case "windows":
@@ -538,3 +544,79 @@ func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
 	}
 	return false
 }
+
+func TestSIGPROF(t *testing.T) {
+	switch GOOS {
+	case "windows", "plan9":
+		t.Skipf("skipping SIGPROF test on %s", GOOS)
+	}
+
+	t.Parallel()
+
+	defer func() {
+		os.Remove("testp6" + exeSuffix)
+		os.Remove("libgo6.a")
+		os.Remove("libgo6.h")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	argv := cmdToRun("./testp6")
+	cmd = exec.Command(argv[0], argv[1:]...)
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+// TestCompileWithoutShared tests that if we compile code without the
+// -shared option, we can put it into an archive. When we use the go
+// tool with -buildmode=c-archive, it passes -shared to the compiler,
+// so we override that. The go tool doesn't work this way, but Bazel
+// will likely do it in the future. And it ought to work. This test
+// was added because at one time it did not work on PPC GNU/Linux.
+func TestCompileWithoutShared(t *testing.T) {
+	// For simplicity, reuse the signal forwarding test.
+	checkSignalForwardingTest(t)
+
+	defer func() {
+		os.Remove("libgo2.a")
+		os.Remove("libgo2.h")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2")
+	cmd.Env = gopathEnv
+	t.Log(cmd.Args)
+	out, err := cmd.CombinedOutput()
+	t.Logf("%s", out)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	exe := "./testnoshared" + exeSuffix
+	ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
+	t.Log(ccArgs)
+	out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+	t.Logf("%s", out)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(exe)
+
+	binArgs := append(cmdToRun(exe), "3")
+	t.Log(binArgs)
+	out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
+	t.Logf("%s", out)
+	expectSignal(t, err, syscall.SIGPIPE)
+}
diff --git a/misc/cgo/testcarchive/main2.c b/misc/cgo/testcarchive/main2.c
index 774e014..769cd49 100644
--- a/misc/cgo/testcarchive/main2.c
+++ b/misc/cgo/testcarchive/main2.c
@@ -17,6 +17,7 @@
 #include <unistd.h>
 #include <sched.h>
 #include <time.h>
+#include <errno.h>
 
 #include "libgo2.h"
 
@@ -26,6 +27,7 @@ static void die(const char* msg) {
 }
 
 static volatile sig_atomic_t sigioSeen;
+static volatile sig_atomic_t sigpipeSeen;
 
 // Use up some stack space.
 static void recur(int i, char *p) {
@@ -37,6 +39,10 @@ static void recur(int i, char *p) {
 	}
 }
 
+static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
+	sigpipeSeen = 1;
+}
+
 // Signal handler that uses up more stack space than a goroutine will have.
 static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
 	char a[1024];
@@ -106,6 +112,10 @@ static void init() {
 		die("sigaction");
 	}
 
+	sa.sa_sigaction = pipeHandler;
+	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+		die("sigaction");
+	}
 }
 
 int main(int argc, char** argv) {
@@ -167,7 +177,30 @@ int main(int argc, char** argv) {
 		nanosleep(&ts, NULL);
 		i++;
 		if (i > 5000) {
-			fprintf(stderr, "looping too long waiting for signal\n");
+			fprintf(stderr, "looping too long waiting for SIGIO\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (verbose) {
+		printf("provoking SIGPIPE\n");
+	}
+
+	GoRaiseSIGPIPE();
+
+	if (verbose) {
+		printf("waiting for sigpipeSeen\n");
+	}
+
+	// Wait until the signal has been delivered.
+	i = 0;
+	while (!sigpipeSeen) {
+		ts.tv_sec = 0;
+		ts.tv_nsec = 1000000;
+		nanosleep(&ts, NULL);
+		i++;
+		if (i > 5000) {
+			fprintf(stderr, "looping too long waiting for SIGPIPE\n");
 			exit(EXIT_FAILURE);
 		}
 	}
diff --git a/misc/cgo/testcarchive/main3.c b/misc/cgo/testcarchive/main3.c
index 0a6c0d3..60a16cf 100644
--- a/misc/cgo/testcarchive/main3.c
+++ b/misc/cgo/testcarchive/main3.c
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <time.h>
 #include <sched.h>
+#include <unistd.h>
 
 #include "libgo3.h"
 
@@ -25,6 +26,31 @@ static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
 	sigioSeen = 1;
 }
 
+// Set up the SIGPIPE signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
+	const char *s = "unexpected SIGPIPE\n";
+	write(2, s, strlen(s));
+	exit(EXIT_FAILURE);
+}
+
+static void init(void) __attribute__ ((constructor (200)));
+
+static void init() {
+    struct sigaction sa;
+
+	memset(&sa, 0, sizeof sa);
+	sa.sa_sigaction = pipeHandler;
+	if (sigemptyset(&sa.sa_mask) < 0) {
+		die("sigemptyset");
+	}
+	sa.sa_flags = SA_SIGINFO;
+	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+		die("sigaction");
+	}
+}
+
 int main(int argc, char** argv) {
 	int verbose;
 	struct sigaction sa;
@@ -35,6 +61,14 @@ int main(int argc, char** argv) {
 	setvbuf(stdout, NULL, _IONBF, 0);
 
 	if (verbose) {
+		printf("raising SIGPIPE\n");
+	}
+
+	// Test that the Go runtime handles SIGPIPE, even if we installed
+	// a non-default SIGPIPE handler before the runtime initializes.
+	ProvokeSIGPIPE();
+
+	if (verbose) {
 		printf("calling sigaction\n");
 	}
 
diff --git a/misc/cgo/testcarchive/main5.c b/misc/cgo/testcarchive/main5.c
index 9fadf08..2437bf0 100644
--- a/misc/cgo/testcarchive/main5.c
+++ b/misc/cgo/testcarchive/main5.c
@@ -68,6 +68,24 @@ int main(int argc, char** argv) {
 
 			break;
 		}
+		case 3: {
+			if (verbose) {
+				printf("attempting SIGPIPE\n");
+			}
+
+			int fd[2];
+			if (pipe(fd) != 0) {
+				printf("pipe(2) failed\n");
+				return 0;
+			}
+			// Close the reading end.
+			close(fd[0]);
+			// Expect that write(2) fails (EPIPE)
+			if (write(fd[1], "some data", 9) != -1) {
+				printf("write(2) unexpectedly succeeded\n");
+				return 0;
+			}
+		}
 		default:
 			printf("Unknown test: %d\n", test);
 			return 0;
diff --git a/misc/cgo/testcarchive/main6.c b/misc/cgo/testcarchive/main6.c
new file mode 100644
index 0000000..2745eb9
--- /dev/null
+++ b/misc/cgo/testcarchive/main6.c
@@ -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.
+
+// Test that using the Go profiler in a C program does not crash.
+
+#include <stddef.h>
+#include <sys/time.h>
+
+#include "libgo6.h"
+
+int main(int argc, char **argv) {
+	struct timeval tvstart, tvnow;
+	int diff;
+
+	gettimeofday(&tvstart, NULL);
+
+	go_start_profile();
+
+	// Busy wait so we have something to profile.
+	// If we just sleep the profiling signal will never fire.
+	while (1) {
+		gettimeofday(&tvnow, NULL);
+		diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
+
+		// Profile frequency is 100Hz so we should definitely
+		// get a signal in 50 milliseconds.
+		if (diff > 50 * 1000)
+			break;
+	}
+
+	go_stop_profile();
+	return 0;
+}
diff --git a/misc/cgo/testcarchive/src/libgo2/libgo2.go b/misc/cgo/testcarchive/src/libgo2/libgo2.go
index fbed493..19c8e1a 100644
--- a/misc/cgo/testcarchive/src/libgo2/libgo2.go
+++ b/misc/cgo/testcarchive/src/libgo2/libgo2.go
@@ -4,6 +4,30 @@
 
 package main
 
+/*
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+// Raise SIGPIPE.
+static void CRaiseSIGPIPE() {
+	int fds[2];
+
+	if (pipe(fds) == -1) {
+		perror("pipe");
+		exit(EXIT_FAILURE);
+	}
+	// Close the reader end
+	close(fds[0]);
+	// Write to the writer end to provoke a SIGPIPE
+	if (write(fds[1], "some data", 9) != -1) {
+		fprintf(stderr, "write to a closed pipe succeeded\n");
+		exit(EXIT_FAILURE);
+	}
+	close(fds[1]);
+}
+*/
 import "C"
 
 import (
@@ -46,5 +70,11 @@ func TestSEGV() {
 func Noop() {
 }
 
+// Raise SIGPIPE.
+//export GoRaiseSIGPIPE
+func GoRaiseSIGPIPE() {
+	C.CRaiseSIGPIPE()
+}
+
 func main() {
 }
diff --git a/misc/cgo/testcarchive/src/libgo3/libgo3.go b/misc/cgo/testcarchive/src/libgo3/libgo3.go
index 94e5d21..e276a3c 100644
--- a/misc/cgo/testcarchive/src/libgo3/libgo3.go
+++ b/misc/cgo/testcarchive/src/libgo3/libgo3.go
@@ -40,5 +40,17 @@ func SawSIGIO() C.int {
 	}
 }
 
+// ProvokeSIGPIPE provokes a kernel-initiated SIGPIPE.
+//export ProvokeSIGPIPE
+func ProvokeSIGPIPE() {
+	r, w, err := os.Pipe()
+	if err != nil {
+		panic(err)
+	}
+	r.Close()
+	defer w.Close()
+	w.Write([]byte("some data"))
+}
+
 func main() {
 }
diff --git a/misc/cgo/testcarchive/src/libgo6/sigprof.go b/misc/cgo/testcarchive/src/libgo6/sigprof.go
new file mode 100644
index 0000000..4cb05dc
--- /dev/null
+++ b/misc/cgo/testcarchive/src/libgo6/sigprof.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 main
+
+import (
+	"io/ioutil"
+	"runtime/pprof"
+)
+
+import "C"
+
+//export go_start_profile
+func go_start_profile() {
+	pprof.StartCPUProfile(ioutil.Discard)
+}
+
+//export go_stop_profile
+func go_stop_profile() {
+	pprof.StopCPUProfile()
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcshared/main0.c b/misc/cgo/testcshared/main0.c
index 1274b89..39ef7e3 100644
--- a/misc/cgo/testcshared/main0.c
+++ b/misc/cgo/testcshared/main0.c
@@ -12,6 +12,7 @@
 //   int8_t DidInitRun();
 //   int8_t DidMainRun();
 //   int32_t FromPkg();
+//   uint32_t Divu(uint32_t, uint32_t);
 int main(void) {
   int8_t ran_init = DidInitRun();
   if (!ran_init) {
@@ -30,6 +31,11 @@ int main(void) {
     fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024);
     return 1;
   }
+  uint32_t divu = Divu(2264, 31);
+  if (divu != 73) {
+    fprintf(stderr, "ERROR: Divu(2264, 31)=%d, want %d\n", divu, 73);
+    return 1;
+  }
   // test.bash looks for "PASS" to ensure this program has reached the end. 
   printf("PASS\n");
   return 0;
diff --git a/misc/cgo/testcshared/src/p/p.go b/misc/cgo/testcshared/src/p/p.go
index 82b445c..fb4b5ca 100644
--- a/misc/cgo/testcshared/src/p/p.go
+++ b/misc/cgo/testcshared/src/p/p.go
@@ -8,3 +8,5 @@ import "C"
 
 //export FromPkg
 func FromPkg() int32 { return 1024 }
+//export Divu
+func Divu(a, b uint32) uint32 { return a / b }
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
index 0315fb0..315a0d4 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -27,7 +27,7 @@ fi
 # Directory where cgo headers and outputs will be installed.
 # The installation directory format varies depending on the platform.
 installdir=pkg/${goos}_${goarch}_testcshared_shared
-if [ "${goos}" == "darwin" ]; then
+if [ "${goos}" = "darwin" ]; then
 	installdir=pkg/${goos}_${goarch}_testcshared
 fi
 
@@ -40,13 +40,13 @@ function cleanup() {
 	rm -f testp testp2 testp3 testp4 testp5
 	rm -rf pkg "${goroot}/${installdir}"
 
-	if [ "$goos" == "android" ]; then
+	if [ "$goos" = "android" ]; then
 		adb shell rm -rf "$androidpath"
 	fi
 }
 trap cleanup EXIT
 
-if [ "$goos" == "android" ]; then
+if [ "$goos" = "android" ]; then
 	adb shell mkdir -p "$androidpath"
 fi
 
@@ -69,7 +69,7 @@ function run() {
 
 function binpush() {
 	bin=${1}
-	if [ "$goos" == "android" ]; then
+	if [ "$goos" = "android" ]; then
 		adb push "$bin"  "${androidpath}/${bin}" 2>/dev/null
 	fi
 }
@@ -79,7 +79,7 @@ rm -rf pkg
 suffix="-installsuffix testcshared"
 
 libext="so"
-if [ "$goos" == "darwin" ]; then
+if [ "$goos" = "darwin" ]; then
 	libext="dylib"
 fi
 
@@ -89,7 +89,7 @@ GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
 GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go
 binpush libgo.$libext
 
-if [ "$goos" == "linux" ] || [ "$goos" == "android" ] ; then
+if [ "$goos" = "linux" ] || [ "$goos" = "android" ] ; then
     if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then
         echo "libgo.$libext has TEXTREL set"
         exit 1
@@ -97,8 +97,8 @@ if [ "$goos" == "linux" ] || [ "$goos" == "android" ] ; then
 fi
 
 GOGCCFLAGS=$(go env GOGCCFLAGS)
-if [ "$goos" == "android" ]; then
-	GOGCCFLAGS="${GOGCCFLAGS} -pie"
+if [ "$goos" = "android" ]; then
+	GOGCCFLAGS="${GOGCCFLAGS} -pie -fuse-ld=gold"
 fi
 
 status=0
@@ -127,7 +127,7 @@ fi
 GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2
 binpush libgo2.$libext
 linkflags="-Wl,--no-as-needed"
-if [ "$goos" == "darwin" ]; then
+if [ "$goos" = "darwin" ]; then
 	linkflags=""
 fi
 $(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext
@@ -139,7 +139,7 @@ if [ "$output" != "PASS" ]; then
 fi
 
 # test3: tests main.main is exported on android.
-if [ "$goos" == "android" ]; then
+if [ "$goos" = "android" ]; then
 	$(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl
 	binpush testp3
 	output=$(run ./testp ./libgo.so)
diff --git a/misc/cgo/testplugin/src/issue19534/main.go b/misc/cgo/testplugin/src/issue19534/main.go
new file mode 100644
index 0000000..de263b6
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue19534/main.go
@@ -0,0 +1,23 @@
+// Copyright 2017 The Go Authors. 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 "plugin"
+
+func main() {
+	p, err := plugin.Open("plugin.so")
+	if err != nil {
+		panic(err)
+	}
+
+	sym, err := p.Lookup("Foo")
+	if err != nil {
+		panic(err)
+	}
+	f := sym.(func() int)
+	if f() != 42 {
+		panic("expected f() == 42")
+	}
+}
diff --git a/misc/cgo/testplugin/src/issue19534/plugin.go b/misc/cgo/testplugin/src/issue19534/plugin.go
new file mode 100644
index 0000000..582d333
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue19534/plugin.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. 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 Foo() int {
+	return 42
+}
diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash
index ab7430a..69df5bd 100755
--- a/misc/cgo/testplugin/test.bash
+++ b/misc/cgo/testplugin/test.bash
@@ -16,7 +16,7 @@ goarch=$(go env GOARCH)
 
 function cleanup() {
 	rm -f plugin*.so unnamed*.so iface*.so
-	rm -rf host pkg sub iface issue18676
+	rm -rf host pkg sub iface issue18676 issue19534
 }
 trap cleanup EXIT
 
@@ -44,3 +44,9 @@ LD_LIBRARY_PATH=$(pwd) ./iface
 GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go
 GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go
 timeout 10s ./issue18676
+
+# Test for issue 19534 - that we can load a plugin built in a path with non-alpha
+# characters
+GOPATH=$(pwd) go build -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go
+GOPATH=$(pwd) go build -o issue19534 src/issue19534/main.go
+./issue19534
diff --git a/misc/cgo/testplugin/unnamed1.go b/misc/cgo/testplugin/unnamed1.go
index 102edaf..5c1df08 100644
--- a/misc/cgo/testplugin/unnamed1.go
+++ b/misc/cgo/testplugin/unnamed1.go
@@ -9,4 +9,15 @@ import "C"
 
 func FuncInt() int { return 1 }
 
+// Add a recursive type to to check that type equality across plugins doesn't
+// crash. See https://golang.org/issues/19258
+func FuncRecursive() X { return X{} }
+
+type Y struct {
+	X *X
+}
+type X struct {
+	Y Y
+}
+
 func main() {}
diff --git a/misc/cgo/testplugin/unnamed2.go b/misc/cgo/testplugin/unnamed2.go
index 55070d5..7ef6610 100644
--- a/misc/cgo/testplugin/unnamed2.go
+++ b/misc/cgo/testplugin/unnamed2.go
@@ -9,4 +9,13 @@ import "C"
 
 func FuncInt() int { return 2 }
 
+func FuncRecursive() X { return X{} }
+
+type Y struct {
+	X *X
+}
+type X struct {
+	Y Y
+}
+
 func main() {}
diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash
index 4da8502..3debb54 100755
--- a/misc/cgo/testsanitizers/test.bash
+++ b/misc/cgo/testsanitizers/test.bash
@@ -72,12 +72,12 @@ testmsanshared() {
   goos=$(go env GOOS)
   suffix="-installsuffix testsanitizers"
   libext="so"
-  if [ "$goos" == "darwin" ]; then
+  if [ "$goos" = "darwin" ]; then
 	  libext="dylib"
   fi
   go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
 
-	echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
+  echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
   $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
 
   if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
@@ -131,6 +131,25 @@ if test "$msan" = "yes"; then
     testmsanshared
 fi
 
+testtsanshared() {
+  goos=$(go env GOOS)
+  suffix="-installsuffix tsan"
+  libext="so"
+  if [ "$goos" = "darwin" ]; then
+	  libext="dylib"
+  fi
+  go build -buildmode=c-shared $suffix -o ${TMPDIR}/libtsanshared.$libext tsan_shared.go
+
+  echo 'int main() { return 0; }' > ${TMPDIR}/testtsanshared.c
+  $CC $(go env GOGCCFLAGS) -fsanitize=thread -o ${TMPDIR}/testtsanshared ${TMPDIR}/testtsanshared.c ${TMPDIR}/libtsanshared.$libext
+
+  if ! LD_LIBRARY_PATH=. ${TMPDIR}/testtsanshared; then
+    echo "FAIL: tsan_shared"
+    status=1
+  fi
+  rm -f ${TMPDIR}/{testtsanshared,testtsanshared.c,libtsanshared.$libext}
+}
+
 if test "$tsan" = "yes"; then
     echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
     ok=yes
@@ -190,14 +209,14 @@ if test "$tsan" = "yes"; then
     fi
 
     if test "$ok" = "true"; then
-	# This test requires rebuilding os/user with -fsanitize=thread.
+	# These tests require 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"
-
-	# This test requires rebuilding runtime/cgo with -fsanitize=thread.
 	testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+	testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+	testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+
+	testtsanshared
     fi
 fi
 
diff --git a/misc/cgo/testsanitizers/tsan10.go b/misc/cgo/testsanitizers/tsan10.go
new file mode 100644
index 0000000..a40f245
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan10.go
@@ -0,0 +1,31 @@
+// Copyright 2017 The Go Authors. 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 hung when run under the C/C++ ThreadSanitizer.
+// TSAN defers asynchronous signals until the signaled thread calls into libc.
+// Since the Go runtime makes direct futex syscalls, Go runtime threads could
+// run for an arbitrarily long time without triggering the libc interceptors.
+// See https://golang.org/issue/18717.
+
+import (
+	"os"
+	"os/signal"
+	"syscall"
+)
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+*/
+import "C"
+
+func main() {
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGUSR1)
+	defer signal.Stop(c)
+	syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+	<-c
+}
diff --git a/misc/cgo/testsanitizers/tsan11.go b/misc/cgo/testsanitizers/tsan11.go
new file mode 100644
index 0000000..70ac9c8
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan11.go
@@ -0,0 +1,55 @@
+// Copyright 2017 The Go Authors. 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 hung when run under the C/C++ ThreadSanitizer. TSAN defers
+// asynchronous signals until the signaled thread calls into libc. The runtime's
+// sysmon goroutine idles itself using direct usleep syscalls, so it could
+// run for an arbitrarily long time without triggering the libc interceptors.
+// See https://golang.org/issue/18717.
+
+import (
+	"os"
+	"os/signal"
+	"syscall"
+)
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void raise_usr2(int signo) {
+	raise(SIGUSR2);
+}
+
+static void register_handler(int signo) {
+	struct sigaction sa;
+	memset(&sa, 0, sizeof(sa));
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_ONSTACK;
+	sa.sa_handler = raise_usr2;
+
+	if (sigaction(SIGUSR1, &sa, NULL) != 0) {
+		perror("failed to register SIGUSR1 handler");
+		exit(EXIT_FAILURE);
+	}
+}
+*/
+import "C"
+
+func main() {
+	ch := make(chan os.Signal)
+	signal.Notify(ch, syscall.SIGUSR2)
+
+	C.register_handler(C.int(syscall.SIGUSR1))
+	syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+
+	<-ch
+}
diff --git a/misc/cgo/testsanitizers/tsan_shared.go b/misc/cgo/testsanitizers/tsan_shared.go
new file mode 100644
index 0000000..55ff67e
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan_shared.go
@@ -0,0 +1,63 @@
+// Copyright 2017 The Go Authors. 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 failed with SIGSEGV when run under the C/C++ ThreadSanitizer.
+// The Go runtime had re-registered the C handler with the wrong flags due to a
+// typo, resulting in null pointers being passed for the info and context
+// parameters to the handler.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+void check_params(int signo, siginfo_t *info, void *context) {
+	ucontext_t* uc = (ucontext_t*)(context);
+
+	if (info->si_signo != signo) {
+		fprintf(stderr, "info->si_signo does not match signo.\n");
+		abort();
+	}
+
+	if (uc->uc_stack.ss_size == 0) {
+		fprintf(stderr, "uc_stack has size 0.\n");
+		abort();
+	}
+}
+
+
+// Set up the signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void register_handler(void) __attribute__ ((constructor (200)));
+
+static void register_handler() {
+	struct sigaction sa;
+	memset(&sa, 0, sizeof(sa));
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_SIGINFO;
+	sa.sa_sigaction = check_params;
+
+	if (sigaction(SIGUSR1, &sa, NULL) != 0) {
+		perror("failed to register SIGUSR1 handler");
+		exit(EXIT_FAILURE);
+	}
+}
+*/
+import "C"
+
+import "syscall"
+
+func init() {
+	C.raise(C.int(syscall.SIGUSR1))
+}
+
+func main() {}
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index f0766e5..9e682a2 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -10,7 +10,6 @@ import (
 	"debug/elf"
 	"encoding/binary"
 	"errors"
-	"flag"
 	"fmt"
 	"go/build"
 	"io"
@@ -166,7 +165,6 @@ func TestMain(m *testing.M) {
 	// That won't work if GOBIN is set.
 	os.Unsetenv("GOBIN")
 
-	flag.Parse()
 	exitCode, err := testMain(m)
 	if err != nil {
 		log.Fatal(err)
@@ -402,6 +400,12 @@ func TestTrivialExecutablePIE(t *testing.T) {
 	AssertHasRPath(t, "./trivial.pie", gorootInstallDir)
 }
 
+// Build a division test program and check it runs.
+func TestDivisionExecutable(t *testing.T) {
+	goCmd(t, "install", "-linkshared", "division")
+	run(t, "division executable", "./bin/division")
+}
+
 // Build an executable that uses cgo linked against the shared runtime and check it
 // runs.
 func TestCgoExecutable(t *testing.T) {
@@ -759,6 +763,13 @@ func appendFile(path, content string) {
 	}
 }
 
+func writeFile(path, content string) {
+	err := ioutil.WriteFile(path, []byte(content), 0644)
+	if err != nil {
+		log.Fatalf("ioutil.WriteFile failed: %v", err)
+	}
+}
+
 func TestABIChecking(t *testing.T) {
 	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
 	goCmd(t, "install", "-linkshared", "exe")
@@ -797,9 +808,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 libdepBase.so, exe still works.
+	// function) and rebuild libdepBase.so, exe still works, even if new function
+	// is in a file by itself.
 	resetFileStamps()
-	appendFile("src/depBase/dep.go", "func noABIBreak() {}\n")
+	writeFile("src/depBase/dep2.go", "package depBase\nfunc 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/division/division.go b/misc/cgo/testshared/src/division/division.go
new file mode 100644
index 0000000..a0b11a5
--- /dev/null
+++ b/misc/cgo/testshared/src/division/division.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. 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 div(x, y uint32) uint32 {
+	return x / y
+}
+
+func main() {
+	a := div(97, 11)
+	if a != 8 {
+		panic("FAIL")
+	}
+}
\ No newline at end of file
diff --git a/misc/ios/detect.go b/misc/ios/detect.go
index 53749ad..7e4e6f6 100644
--- a/misc/ios/detect.go
+++ b/misc/ios/detect.go
@@ -23,28 +23,37 @@ import (
 
 func main() {
 	devID := detectDevID()
-	fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
 
 	udid := detectUDID()
-	mp := detectMobileProvisionFile(udid)
-
-	f, err := ioutil.TempFile("", "go_ios_detect_")
-	check(err)
-	fname := f.Name()
-	defer os.Remove(fname)
-
-	out := combinedOutput(parseMobileProvision(mp))
-	_, err = f.Write(out)
-	check(err)
-	check(f.Close())
-
-	appID, err := plistExtract(fname, "ApplicationIdentifierPrefix:0")
-	check(err)
-	fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
+	mps := detectMobileProvisionFiles(udid)
+	if len(mps) == 0 {
+		fail("did not find mobile provision matching device udid %s", udid)
+	}
 
-	teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
-	check(err)
-	fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
+	fmt.Println("Available provisioning profiles below.")
+	fmt.Println("NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
+	fmt.Println("will be overwritten when running Go programs.")
+	for _, mp := range mps {
+		fmt.Println()
+		fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
+		f, err := ioutil.TempFile("", "go_ios_detect_")
+		check(err)
+		fname := f.Name()
+		defer os.Remove(fname)
+
+		out := output(parseMobileProvision(mp))
+		_, err = f.Write(out)
+		check(err)
+		check(f.Close())
+
+		appID, err := plistExtract(fname, "Entitlements:application-identifier")
+		check(err)
+		fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
+
+		teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
+		check(err)
+		fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
+	}
 }
 
 func detectDevID() string {
@@ -79,10 +88,11 @@ func detectUDID() []byte {
 	panic("unreachable")
 }
 
-func detectMobileProvisionFile(udid []byte) string {
+func detectMobileProvisionFiles(udid []byte) []string {
 	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
 	lines := getLines(cmd)
 
+	var files []string
 	for _, line := range lines {
 		if len(line) == 0 {
 			continue
@@ -90,12 +100,11 @@ func detectMobileProvisionFile(udid []byte) string {
 		xmlLines := getLines(parseMobileProvision(string(line)))
 		for _, xmlLine := range xmlLines {
 			if bytes.Contains(xmlLine, udid) {
-				return string(line)
+				files = append(files, string(line))
 			}
 		}
 	}
-	fail("did not find mobile provision matching device udid %s", udid)
-	panic("ureachable")
+	return files
 }
 
 func parseMobileProvision(fname string) *exec.Cmd {
@@ -111,12 +120,12 @@ func plistExtract(fname string, path string) ([]byte, error) {
 }
 
 func getLines(cmd *exec.Cmd) [][]byte {
-	out := combinedOutput(cmd)
+	out := output(cmd)
 	return bytes.Split(out, []byte("\n"))
 }
 
-func combinedOutput(cmd *exec.Cmd) []byte {
-	out, err := cmd.CombinedOutput()
+func output(cmd *exec.Cmd) []byte {
+	out, err := cmd.Output()
 	if err != nil {
 		fmt.Println(strings.Join(cmd.Args, "\n"))
 		fmt.Fprintln(os.Stderr, err)
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
index 3de341b..e84e513 100644
--- a/misc/ios/go_darwin_arm_exec.go
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -45,9 +45,10 @@ var errRetry = errors.New("failed to start test harness (retry attempted)")
 var tmpdir string
 
 var (
-	devID  string
-	appID  string
-	teamID string
+	devID    string
+	appID    string
+	teamID   string
+	bundleID string
 )
 
 // lock is a file lock to serialize iOS runs. It is global to avoid the
@@ -76,6 +77,13 @@ func main() {
 	// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
 	teamID = getenv("GOIOS_TEAM_ID")
 
+	parts := strings.SplitN(appID, ".", 2)
+	// For compatibility with the old builders, use a fallback bundle ID
+	bundleID = "golang.gotest"
+	if len(parts) == 2 {
+		bundleID = parts[1]
+	}
+
 	var err error
 	tmpdir, err = ioutil.TempDir("", "go_darwin_arm_exec_")
 	if err != nil {
@@ -99,7 +107,7 @@ func main() {
 	// Approximately 1 in a 100 binaries fail to start. If it happens,
 	// try again. These failures happen for several reasons beyond
 	// our control, but all of them are safe to retry as they happen
-	// before lldb encounters the initial SIGUSR2 stop. As we
+	// before lldb encounters the initial getwd breakpoint. As we
 	// know the tests haven't started, we are not hiding flaky tests
 	// with this retry.
 	for i := 0; i < 5; i++ {
@@ -139,22 +147,22 @@ func run(bin string, args []string) (err error) {
 		return err
 	}
 
+	pkgpath, err := copyLocalData(appdir)
+	if err != nil {
+		return err
+	}
+
 	entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
 	if err := ioutil.WriteFile(entitlementsPath, []byte(entitlementsPlist()), 0744); err != nil {
 		return err
 	}
-	if err := ioutil.WriteFile(filepath.Join(appdir, "Info.plist"), []byte(infoPlist), 0744); err != nil {
+	if err := ioutil.WriteFile(filepath.Join(appdir, "Info.plist"), []byte(infoPlist(pkgpath)), 0744); err != nil {
 		return err
 	}
 	if err := ioutil.WriteFile(filepath.Join(appdir, "ResourceRules.plist"), []byte(resourceRules), 0744); err != nil {
 		return err
 	}
 
-	pkgpath, err := copyLocalData(appdir)
-	if err != nil {
-		return err
-	}
-
 	cmd := exec.Command(
 		"codesign",
 		"-f",
@@ -204,11 +212,6 @@ func run(bin string, args []string) (err error) {
 	var opts options
 	opts, args = parseArgs(args)
 
-	// Pass the suffix for the current working directory as the
-	// first argument to the test. For iOS, cmd/go generates
-	// special handling of this argument.
-	args = append([]string{"cwdSuffix=" + pkgpath}, args...)
-
 	// ios-deploy invokes lldb to give us a shell session with the app.
 	s, err := newSession(appdir, args, opts)
 	if err != nil {
@@ -229,7 +232,6 @@ 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 SIGUSR2 --stop true --pass false --notify true`) // sent by test harness
 	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
@@ -244,7 +246,7 @@ func run(bin string, args []string) (err error) {
 
 	started = true
 
-	s.doCmd("run", "stop reason = signal SIGUSR2", 20*time.Second)
+	s.doCmd("run", "stop reason = signal SIGINT", 20*time.Second)
 
 	startTestsLen := s.out.Len()
 	fmt.Fprintln(s.in, `process continue`)
@@ -254,7 +256,9 @@ func run(bin string, args []string) (err error) {
 		return s.out.LastIndex([]byte("\nPASS\n")) > startTestsLen ||
 			s.out.LastIndex([]byte("\nPASS\r")) > startTestsLen ||
 			s.out.LastIndex([]byte("\n(lldb) PASS\n")) > startTestsLen ||
-			s.out.LastIndex([]byte("\n(lldb) PASS\r")) > startTestsLen
+			s.out.LastIndex([]byte("\n(lldb) PASS\r")) > startTestsLen ||
+			s.out.LastIndex([]byte("exited with status = 0 (0x00000000) \n")) > startTestsLen ||
+			s.out.LastIndex([]byte("exited with status = 0 (0x00000000) \r")) > startTestsLen
 	}
 	err = s.wait("test completion", passed, opts.timeout)
 	if passed(s.out) {
@@ -342,7 +346,7 @@ 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, 10*time.Second); err != nil {
+	if err := s.wait("lldb start", cond, 15*time.Second); err != nil {
 		panic(waitPanic{err})
 	}
 	return s, nil
@@ -440,7 +444,7 @@ func parseArgs(binArgs []string) (opts options, remainingArgs []string) {
 		remainingArgs = append(remainingArgs, arg)
 	}
 	f := flag.NewFlagSet("", flag.ContinueOnError)
-	f.DurationVar(&opts.timeout, "test.timeout", 0, "")
+	f.DurationVar(&opts.timeout, "test.timeout", 10*time.Minute, "")
 	f.BoolVar(&opts.lldb, "lldb", false, "")
 	f.Parse(flagArgs)
 	return opts, remainingArgs
@@ -513,18 +517,33 @@ func copyLocalData(dstbase string) (pkgpath string, err error) {
 		}
 	}
 
-	// Copy timezone file.
-	//
-	// Apps have the zoneinfo.zip in the root of their app bundle,
-	// read by the time package as the working directory at initialization.
 	if underGoRoot {
+		// Copy timezone file.
+		//
+		// Typical apps have the zoneinfo.zip in the root of their app bundle,
+		// read by the time package as the working directory at initialization.
+		// As we move the working directory to the GOROOT pkg directory, we
+		// install the zoneinfo.zip file in the pkgpath.
 		err := cp(
-			dstbase,
+			filepath.Join(dstbase, pkgpath),
 			filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
 		)
 		if err != nil {
 			return "", err
 		}
+		// Copy src/runtime/textflag.h for (at least) Test386EndToEnd in
+		// cmd/asm/internal/asm.
+		runtimePath := filepath.Join(dstbase, "src", "runtime")
+		if err := os.MkdirAll(runtimePath, 0755); err != nil {
+			return "", err
+		}
+		err = cp(
+			filepath.Join(runtimePath, "textflag.h"),
+			filepath.Join(cwd, "src", "runtime", "textflag.h"),
+		)
+		if err != nil {
+			return "", err
+		}
 	}
 
 	return finalPkgpath, nil
@@ -562,7 +581,8 @@ func subdir() (pkgpath string, underGoRoot bool, err error) {
 	)
 }
 
-const infoPlist = `<?xml version="1.0" encoding="UTF-8"?>
+func infoPlist(pkgpath string) string {
+	return `<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
@@ -570,13 +590,15 @@ const infoPlist = `<?xml version="1.0" encoding="UTF-8"?>
 <key>CFBundleSupportedPlatforms</key><array><string>iPhoneOS</string></array>
 <key>CFBundleExecutable</key><string>gotest</string>
 <key>CFBundleVersion</key><string>1.0</string>
-<key>CFBundleIdentifier</key><string>golang.gotest</string>
+<key>CFBundleIdentifier</key><string>` + bundleID + `</string>
 <key>CFBundleResourceSpecification</key><string>ResourceRules.plist</string>
 <key>LSRequiresIPhoneOS</key><true/>
 <key>CFBundleDisplayName</key><string>gotest</string>
+<key>GoExecWrapperWorkingDirectory</key><string>` + pkgpath + `</string>
 </dict>
 </plist>
 `
+}
 
 func entitlementsPlist() string {
 	return `<?xml version="1.0" encoding="UTF-8"?>
@@ -584,11 +606,11 @@ func entitlementsPlist() string {
 <plist version="1.0">
 <dict>
 	<key>keychain-access-groups</key>
-	<array><string>` + appID + `.golang.gotest</string></array>
+	<array><string>` + appID + `</string></array>
 	<key>get-task-allow</key>
 	<true/>
 	<key>application-identifier</key>
-	<string>` + appID + `.golang.gotest</string>
+	<string>` + appID + `</string>
 	<key>com.apple.developer.team-identifier</key>
 	<string>` + teamID + `</string>
 </dict>
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index 561df80..8bf2540 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -37,6 +37,26 @@ go	src=..
 				testdata
 					+
 			vendor
+				github.com
+					google
+						pprof
+							internal
+								driver
+									testdata
+										+
+								graph
+									testdata
+										+
+								report
+									testdata
+										+
+							profile
+								testdata
+									+
+					ianlancetaylor
+						demangle
+							testdata
+								+
 				golang.org
 					x
 						arch
@@ -142,6 +162,8 @@ go	src=..
 		regexp
 			testdata
 				+
+		runtime
+			textflag.h
 		strconv
 			testdata
 				+
diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go
index d2ae66d..d49c5c3 100644
--- a/src/archive/tar/common.go
+++ b/src/archive/tar/common.go
@@ -158,11 +158,15 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) {
 // sysStat, if non-nil, populates h from system-dependent fields of fi.
 var sysStat func(fi os.FileInfo, h *Header) error
 
-// Mode constants from the tar spec.
 const (
-	c_ISUID  = 04000   // Set uid
-	c_ISGID  = 02000   // Set gid
-	c_ISVTX  = 01000   // Save text (sticky bit)
+	// Mode constants from the USTAR spec:
+	// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
+	c_ISUID = 04000 // Set uid
+	c_ISGID = 02000 // Set gid
+	c_ISVTX = 01000 // Save text (sticky bit)
+
+	// Common Unix mode constants; these are not defined in any common tar standard.
+	// Header.FileInfo understands these, but FileInfoHeader will never produce these.
 	c_ISDIR  = 040000  // Directory
 	c_ISFIFO = 010000  // FIFO
 	c_ISREG  = 0100000 // Regular file
@@ -208,30 +212,24 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
 	}
 	switch {
 	case fm.IsRegular():
-		h.Mode |= c_ISREG
 		h.Typeflag = TypeReg
 		h.Size = fi.Size()
 	case fi.IsDir():
 		h.Typeflag = TypeDir
-		h.Mode |= c_ISDIR
 		h.Name += "/"
 	case fm&os.ModeSymlink != 0:
 		h.Typeflag = TypeSymlink
-		h.Mode |= c_ISLNK
 		h.Linkname = link
 	case fm&os.ModeDevice != 0:
 		if fm&os.ModeCharDevice != 0 {
-			h.Mode |= c_ISCHR
 			h.Typeflag = TypeChar
 		} else {
-			h.Mode |= c_ISBLK
 			h.Typeflag = TypeBlock
 		}
 	case fm&os.ModeNamedPipe != 0:
 		h.Typeflag = TypeFifo
-		h.Mode |= c_ISFIFO
 	case fm&os.ModeSocket != 0:
-		h.Mode |= c_ISSOCK
+		return nil, fmt.Errorf("archive/tar: sockets not supported")
 	default:
 		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
 	}
diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go
index cf8337c..fb7a9dc 100644
--- a/src/archive/tar/tar_test.go
+++ b/src/archive/tar/tar_test.go
@@ -6,9 +6,11 @@ package tar
 
 import (
 	"bytes"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"path"
+	"path/filepath"
 	"reflect"
 	"strings"
 	"testing"
@@ -27,7 +29,7 @@ func TestFileInfoHeader(t *testing.T) {
 	if g, e := h.Name, "small.txt"; g != e {
 		t.Errorf("Name = %q; want %q", g, e)
 	}
-	if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e {
+	if g, e := h.Mode, int64(fi.Mode().Perm()); g != e {
 		t.Errorf("Mode = %#o; want %#o", g, e)
 	}
 	if g, e := h.Size, int64(5); g != e {
@@ -55,7 +57,7 @@ func TestFileInfoHeaderDir(t *testing.T) {
 		t.Errorf("Name = %q; want %q", g, e)
 	}
 	// Ignoring c_ISGID for golang.org/issue/4867
-	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
+	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm()); g != e {
 		t.Errorf("Mode = %#o; want %#o", g, e)
 	}
 	if g, e := h.Size, int64(0); g != e {
@@ -67,40 +69,56 @@ func TestFileInfoHeaderDir(t *testing.T) {
 }
 
 func TestFileInfoHeaderSymlink(t *testing.T) {
-	h, err := FileInfoHeader(symlink{}, "some-target")
+	testenv.MustHaveSymlink(t)
+
+	tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	link := filepath.Join(tmpdir, "link")
+	target := tmpdir
+	err = os.Symlink(target, link)
+	if err != nil {
+		t.Fatal(err)
+	}
+	fi, err := os.Lstat(link)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if g, e := h.Name, "some-symlink"; g != e {
+
+	h, err := FileInfoHeader(fi, target)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := h.Name, fi.Name(); g != e {
 		t.Errorf("Name = %q; want %q", g, e)
 	}
-	if g, e := h.Linkname, "some-target"; g != e {
+	if g, e := h.Linkname, target; g != e {
 		t.Errorf("Linkname = %q; want %q", g, e)
 	}
+	if g, e := h.Typeflag, byte(TypeSymlink); g != e {
+		t.Errorf("Typeflag = %v; want %v", g, e)
+	}
 }
 
-type symlink struct{}
-
-func (symlink) Name() string       { return "some-symlink" }
-func (symlink) Size() int64        { return 0 }
-func (symlink) Mode() os.FileMode  { return os.ModeSymlink }
-func (symlink) ModTime() time.Time { return time.Time{} }
-func (symlink) IsDir() bool        { return false }
-func (symlink) Sys() interface{}   { return nil }
-
 func TestRoundTrip(t *testing.T) {
 	data := []byte("some file contents")
 
 	var b bytes.Buffer
 	tw := NewWriter(&b)
 	hdr := &Header{
-		Name:    "file.txt",
-		Uid:     1 << 21, // too big for 8 octal digits
-		Size:    int64(len(data)),
-		ModTime: time.Now(),
+		Name: "file.txt",
+		Uid:  1 << 21, // too big for 8 octal digits
+		Size: int64(len(data)),
+		// AddDate to strip monotonic clock reading,
+		// and Round to discard sub-second precision,
+		// both of which are not included in the tar header
+		// and would otherwise break the round-trip check
+		// below.
+		ModTime: time.Now().AddDate(0, 0, 0).Round(1 * time.Second),
 	}
-	// tar only supports second precision.
-	hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond)
 	if err := tw.WriteHeader(hdr); err != nil {
 		t.Fatalf("tw.WriteHeader: %v", err)
 	}
@@ -139,7 +157,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// regular file.
 		h: &Header{
 			Name:     "test.txt",
-			Mode:     0644 | c_ISREG,
+			Mode:     0644,
 			Size:     12,
 			ModTime:  time.Unix(1360600916, 0),
 			Typeflag: TypeReg,
@@ -149,7 +167,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// symbolic link.
 		h: &Header{
 			Name:     "link.txt",
-			Mode:     0777 | c_ISLNK,
+			Mode:     0777,
 			Size:     0,
 			ModTime:  time.Unix(1360600852, 0),
 			Typeflag: TypeSymlink,
@@ -159,7 +177,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// character device node.
 		h: &Header{
 			Name:     "dev/null",
-			Mode:     0666 | c_ISCHR,
+			Mode:     0666,
 			Size:     0,
 			ModTime:  time.Unix(1360578951, 0),
 			Typeflag: TypeChar,
@@ -169,7 +187,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// block device node.
 		h: &Header{
 			Name:     "dev/sda",
-			Mode:     0660 | c_ISBLK,
+			Mode:     0660,
 			Size:     0,
 			ModTime:  time.Unix(1360578954, 0),
 			Typeflag: TypeBlock,
@@ -179,7 +197,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// directory.
 		h: &Header{
 			Name:     "dir/",
-			Mode:     0755 | c_ISDIR,
+			Mode:     0755,
 			Size:     0,
 			ModTime:  time.Unix(1360601116, 0),
 			Typeflag: TypeDir,
@@ -189,7 +207,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// fifo node.
 		h: &Header{
 			Name:     "dev/initctl",
-			Mode:     0600 | c_ISFIFO,
+			Mode:     0600,
 			Size:     0,
 			ModTime:  time.Unix(1360578949, 0),
 			Typeflag: TypeFifo,
@@ -199,7 +217,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// setuid.
 		h: &Header{
 			Name:     "bin/su",
-			Mode:     0755 | c_ISREG | c_ISUID,
+			Mode:     0755 | c_ISUID,
 			Size:     23232,
 			ModTime:  time.Unix(1355405093, 0),
 			Typeflag: TypeReg,
@@ -209,7 +227,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// setguid.
 		h: &Header{
 			Name:     "group.txt",
-			Mode:     0750 | c_ISREG | c_ISGID,
+			Mode:     0750 | c_ISGID,
 			Size:     0,
 			ModTime:  time.Unix(1360602346, 0),
 			Typeflag: TypeReg,
@@ -219,7 +237,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// sticky.
 		h: &Header{
 			Name:     "sticky.txt",
-			Mode:     0600 | c_ISREG | c_ISVTX,
+			Mode:     0600 | c_ISVTX,
 			Size:     7,
 			ModTime:  time.Unix(1360602540, 0),
 			Typeflag: TypeReg,
@@ -229,7 +247,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// hard link.
 		h: &Header{
 			Name:     "hard.txt",
-			Mode:     0644 | c_ISREG,
+			Mode:     0644,
 			Size:     0,
 			Linkname: "file.txt",
 			ModTime:  time.Unix(1360600916, 0),
@@ -240,7 +258,7 @@ func TestHeaderRoundTrip(t *testing.T) {
 		// More information.
 		h: &Header{
 			Name:     "info.txt",
-			Mode:     0600 | c_ISREG,
+			Mode:     0600,
 			Size:     0,
 			Uid:      1000,
 			Gid:      1000,
diff --git a/src/archive/zip/register.go b/src/archive/zip/register.go
index 2e76386..51e9c3e 100644
--- a/src/archive/zip/register.go
+++ b/src/archive/zip/register.go
@@ -103,51 +103,46 @@ func (r *pooledFlateReader) Close() error {
 }
 
 var (
-	mu sync.RWMutex // guards compressor and decompressor maps
+	compressors   sync.Map // map[uint16]Compressor
+	decompressors sync.Map // map[uint16]Decompressor
+)
 
-	compressors = map[uint16]Compressor{
-		Store:   func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
-		Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
-	}
+func init() {
+	compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
+	compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
 
-	decompressors = map[uint16]Decompressor{
-		Store:   ioutil.NopCloser,
-		Deflate: newFlateReader,
-	}
-)
+	decompressors.Store(Store, Decompressor(ioutil.NopCloser))
+	decompressors.Store(Deflate, Decompressor(newFlateReader))
+}
 
 // RegisterDecompressor allows custom decompressors for a specified method ID.
 // The common methods Store and Deflate are built in.
 func RegisterDecompressor(method uint16, dcomp Decompressor) {
-	mu.Lock()
-	defer mu.Unlock()
-
-	if _, ok := decompressors[method]; ok {
+	if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
 		panic("decompressor already registered")
 	}
-	decompressors[method] = dcomp
 }
 
 // RegisterCompressor registers custom compressors for a specified method ID.
 // The common methods Store and Deflate are built in.
 func RegisterCompressor(method uint16, comp Compressor) {
-	mu.Lock()
-	defer mu.Unlock()
-
-	if _, ok := compressors[method]; ok {
+	if _, dup := compressors.LoadOrStore(method, comp); dup {
 		panic("compressor already registered")
 	}
-	compressors[method] = comp
 }
 
 func compressor(method uint16) Compressor {
-	mu.RLock()
-	defer mu.RUnlock()
-	return compressors[method]
+	ci, ok := compressors.Load(method)
+	if !ok {
+		return nil
+	}
+	return ci.(Compressor)
 }
 
 func decompressor(method uint16) Decompressor {
-	mu.RLock()
-	defer mu.RUnlock()
-	return decompressors[method]
+	di, ok := decompressors.Load(method)
+	if !ok {
+		return nil
+	}
+	return di.(Decompressor)
 }
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index e92d02f..0be210e 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: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
+See: https://www.pkware.com/appnote
 
 This package does not support disk spanning.
 
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 8940e25..f46a03c 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -11,6 +11,7 @@ import (
 	"hash"
 	"hash/crc32"
 	"io"
+	"unicode/utf8"
 )
 
 // TODO(adg): support zip file comments
@@ -201,6 +202,20 @@ func (w *Writer) Create(name string) (io.Writer, error) {
 	return w.CreateHeader(header)
 }
 
+func hasValidUTF8(s string) bool {
+	n := 0
+	for _, r := range s {
+		// By default, ZIP uses CP437, which is only identical to ASCII for the printable characters.
+		if r < 0x20 || r >= 0x7f {
+			if !utf8.ValidRune(r) {
+				return false
+			}
+			n++
+		}
+	}
+	return n > 0
+}
+
 // CreateHeader adds a file to the zip file using the provided FileHeader
 // for the file metadata.
 // It returns a Writer to which the file contents should be written.
@@ -221,6 +236,10 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
 
 	fh.Flags |= 0x8 // we will write a data descriptor
 
+	if hasValidUTF8(fh.Name) || hasValidUTF8(fh.Comment) {
+		fh.Flags |= 0x800 // filename or comment have valid utf-8 string
+	}
+
 	fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
 	fh.ReaderVersion = zipVersion20
 
diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go
index 86841c7..92fb6ec 100644
--- a/src/archive/zip/writer_test.go
+++ b/src/archive/zip/writer_test.go
@@ -87,6 +87,69 @@ func TestWriter(t *testing.T) {
 	}
 }
 
+func TestWriterUTF8(t *testing.T) {
+	var utf8Tests = []struct {
+		name    string
+		comment string
+		expect  uint16
+	}{
+		{
+			name:    "hi, hello",
+			comment: "in the world",
+			expect:  0x8,
+		},
+		{
+			name:    "hi, こんにちわ",
+			comment: "in the world",
+			expect:  0x808,
+		},
+		{
+			name:    "hi, hello",
+			comment: "in the 世界",
+			expect:  0x808,
+		},
+		{
+			name:    "hi, こんにちわ",
+			comment: "in the 世界",
+			expect:  0x808,
+		},
+	}
+
+	// write a zip file
+	buf := new(bytes.Buffer)
+	w := NewWriter(buf)
+
+	for _, test := range utf8Tests {
+		h := &FileHeader{
+			Name:    test.name,
+			Comment: test.comment,
+			Method:  Deflate,
+		}
+		w, err := w.CreateHeader(h)
+		if err != nil {
+			t.Fatal(err)
+		}
+		w.Write([]byte{})
+	}
+
+	if err := w.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// read it back
+	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for i, test := range utf8Tests {
+		got := r.File[i].Flags
+		t.Logf("name %v, comment %v", test.name, test.comment)
+		if got != test.expect {
+			t.Fatalf("Flags: got %v, want %v", got, test.expect)
+		}
+	}
+}
+
 func TestWriterOffset(t *testing.T) {
 	largeData := make([]byte, 1<<17)
 	for i := range largeData {
@@ -181,12 +244,11 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
 }
 
 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++ {
+
+	runOnce := func(buf *bytes.Buffer) {
 		buf.Reset()
-		zw := NewWriter(&buf)
+		zw := NewWriter(buf)
 		for j := 0; j < 3; j++ {
 			w, _ := zw.CreateHeader(&FileHeader{
 				Name:   "foo",
@@ -195,11 +257,19 @@ 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()
-		}
 	}
+
+	b.ReportAllocs()
+	// Run once and then reset the timer.
+	// This effectively discards the very large initial flate setup cost,
+	// as well as the initialization of bigBuf.
+	runOnce(&bytes.Buffer{})
+	b.ResetTimer()
+
+	b.RunParallel(func(pb *testing.PB) {
+		var buf bytes.Buffer
+		for pb.Next() {
+			runOnce(&buf)
+		}
+	})
 }
diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go
index 57edb2c..18c2171 100644
--- a/src/archive/zip/zip_test.go
+++ b/src/archive/zip/zip_test.go
@@ -255,7 +255,7 @@ func TestZip64EdgeCase(t *testing.T) {
 	testZip64DirectoryRecordLength(buf, t)
 }
 
-// Tests that we generate a zip64 file if the the directory at offset
+// Tests that we generate a zip64 file if the directory at offset
 // 0xFFFFFFFF, but not before.
 func TestZip64DirectoryOffset(t *testing.T) {
 	if testing.Short() && race.Enabled {
@@ -681,6 +681,18 @@ func BenchmarkZip64Test(b *testing.B) {
 	}
 }
 
+func BenchmarkZip64TestSizes(b *testing.B) {
+	for _, size := range []int64{1 << 12, 1 << 20, 1 << 26} {
+		b.Run(fmt.Sprint(size), func(b *testing.B) {
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					testZip64(b, size)
+				}
+			})
+		})
+	}
+}
+
 func TestSuffixSaver(t *testing.T) {
 	const keep = 10
 	ss := &suffixSaver{keep: keep}
diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go
index e1e8fb2..da94a25 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package bufio implements buffered I/O.  It wraps an io.Reader or io.Writer
+// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
 // object, creating another object (Reader or Writer) that also implements
 // the interface but provides buffering and some help for textual I/O.
 package bufio
@@ -458,6 +458,7 @@ func (b *Reader) ReadString(delim byte) (string, error) {
 }
 
 // WriteTo implements io.WriterTo.
+// This may make multiple calls to the Read method of the underlying Reader.
 func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	n, err = b.writeBuf(w)
 	if err != nil {
@@ -513,7 +514,7 @@ func (b *Reader) writeBuf(w io.Writer) (int64, error) {
 
 // Writer implements buffering for an io.Writer object.
 // If an error occurs writing to a Writer, no more data will be
-// accepted and all subsequent writes will return the error.
+// accepted and all subsequent writes, and Flush, will return the error.
 // After all data has been written, the client should call the
 // Flush method to guarantee all data has been forwarded to
 // the underlying io.Writer.
diff --git a/src/bufio/scan_test.go b/src/bufio/scan_test.go
index 1bb1e88..2568225 100644
--- a/src/bufio/scan_test.go
+++ b/src/bufio/scan_test.go
@@ -169,7 +169,6 @@ func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
 		}
 		buf.WriteByte('\n')
 	}
-	return
 }
 
 // Test the line splitter, including some carriage returns but no long lines.
diff --git a/src/buildall.bash b/src/buildall.bash
index a322fe5..5820b4d 100755
--- a/src/buildall.bash
+++ b/src/buildall.bash
@@ -19,52 +19,70 @@ fi
 
 sete=false
 if [ "$1" = "-e" ]; then
-    sete=true
-    shift
+	sete=true
+	shift
 fi
 
 if [ "$sete" = true ]; then
-    set -e
+	set -e
 fi
 
 pattern="$1"
 if [ "$pattern" = "" ]; then
-    pattern=.
+	pattern=.
 fi
 
 ./make.bash || exit 1
 GOROOT="$(cd .. && pwd)"
 
+gettargets() {
+	../bin/go tool dist list | sed -e 's|/|-|'
+	echo linux-386-387
+	echo linux-arm-arm5
+}
+
+selectedtargets() {
+	gettargets | egrep -v 'android-arm|darwin-arm' | egrep "$pattern"
+}
+
 # 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')"
+linux_nacl_targets() {
+	selectedtargets | egrep 'linux|nacl' | sort
+}
+
+non_linux_nacl_targets() {
+	selectedtargets | egrep -v 'linux|nacl' | sort
+}
+
+# Note words in $targets are separated by both newlines and spaces.
+targets="$(linux_nacl_targets) $(non_linux_nacl_targets)"
 
 failed=false
 for target in $targets
 do
-    echo ""
-    echo "### Building $target"
-    export GOOS=$(echo $target | sed 's/-.*//')
-    export GOARCH=$(echo $target | sed 's/.*-//')
-    unset GO386 GOARM
-    if [ "$GOARCH" = "arm5" ]; then
-        export GOARCH=arm
-        export GOARM=5
-    fi
-    if [ "$GOARCH" = "387" ]; then
-        export GOARCH=386
-        export GO386=387
-    fi
-    if ! "$GOROOT/bin/go" build -a std cmd; then
-        failed=true
-        if $sete; then
-            exit 1
-        fi
-    fi
+	echo ""
+	echo "### Building $target"
+	export GOOS=$(echo $target | sed 's/-.*//')
+	export GOARCH=$(echo $target | sed 's/.*-//')
+	unset GO386 GOARM
+	if [ "$GOARCH" = "arm5" ]; then
+		export GOARCH=arm
+		export GOARM=5
+	fi
+	if [ "$GOARCH" = "387" ]; then
+		export GOARCH=386
+		export GO386=387
+	fi
+	if ! "$GOROOT/bin/go" build -a std cmd; then
+		failed=true
+		if $sete; then
+			exit 1
+		fi
+	fi
 done
 
 if [ "$failed" = "true" ]; then
-    echo "" 1>&2
-    echo "Build(s) failed." 1>&2
-    exit 1
+	echo "" 1>&2
+	echo "Build(s) failed." 1>&2
+	exit 1
 fi
diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go
index 281de0b..1c7c041 100644
--- a/src/builtin/builtin.go
+++ b/src/builtin/builtin.go
@@ -85,11 +85,11 @@ type uintptr uintptr
 // byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
 // used, by convention, to distinguish byte values from 8-bit unsigned
 // integer values.
-type byte byte
+type byte = uint8
 
 // rune is an alias for int32 and is equivalent to int32 in all ways. It is
 // used, by convention, to distinguish character values from integer values.
-type rune rune
+type rune = int32
 
 // iota is a predeclared identifier representing the untyped integer ordinal
 // number of the current const specification in a (usually parenthesized)
@@ -179,7 +179,7 @@ func cap(v Type) int
 //	Channel: The channel's buffer is initialized with the specified
 //	buffer capacity. If zero, or the size is omitted, the channel is
 //	unbuffered.
-func make(Type, size IntegerType) Type
+func make(t Type, size ...IntegerType) Type
 
 // The new built-in function allocates memory. The first argument is a type,
 // not a value, and the value returned is a pointer to a newly
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 196419d..20e42bb 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -15,10 +15,15 @@ import (
 // A Buffer is a variable-sized buffer of bytes with Read and Write methods.
 // The zero value for Buffer is an empty buffer ready to use.
 type Buffer struct {
-	buf       []byte   // contents are the bytes buf[off : len(buf)]
-	off       int      // read at &buf[off], write at &buf[len(buf)]
-	bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
-	lastRead  readOp   // last read operation, so that Unread* can work correctly.
+	buf      []byte // contents are the bytes buf[off : len(buf)]
+	off      int    // read at &buf[off], write at &buf[len(buf)]
+	lastRead readOp // last read operation, so that Unread* can work correctly.
+	// FIXME: lastRead can fit in a single byte
+
+	// memory to hold first slice; helps small buffers avoid allocation.
+	// FIXME: it would be advisable to align Buffer to cachelines to avoid false
+	// sharing.
+	bootstrap [64]byte
 }
 
 // The readOp constants describe the last action performed on
@@ -68,13 +73,13 @@ func (b *Buffer) Cap() int { return cap(b.buf) }
 // but continues to use the same allocated storage.
 // It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
+	if n == 0 {
+		b.Reset()
+		return
+	}
 	b.lastRead = opInvalid
-	switch {
-	case n < 0 || n > b.Len():
+	if n < 0 || n > b.Len() {
 		panic("bytes.Buffer: truncation out of range")
-	case n == 0:
-		// Reuse buffer space.
-		b.off = 0
 	}
 	b.buf = b.buf[0 : b.off+n]
 }
@@ -82,7 +87,22 @@ func (b *Buffer) Truncate(n int) {
 // Reset resets the buffer to be empty,
 // but it retains the underlying storage for use by future writes.
 // Reset is the same as Truncate(0).
-func (b *Buffer) Reset() { b.Truncate(0) }
+func (b *Buffer) Reset() {
+	b.buf = b.buf[:0]
+	b.off = 0
+	b.lastRead = opInvalid
+}
+
+// tryGrowByReslice is a inlineable version of grow for the fast-case where the
+// internal buffer only needs to be resliced.
+// It returns the index where bytes should be written and whether it succeeded.
+func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
+	if l := len(b.buf); l+n <= cap(b.buf) {
+		b.buf = b.buf[:l+n]
+		return l, true
+	}
+	return 0, false
+}
 
 // grow grows the buffer to guarantee space for n more bytes.
 // It returns the index where bytes should be written.
@@ -91,29 +111,33 @@ func (b *Buffer) grow(n int) int {
 	m := b.Len()
 	// If buffer is empty, reset to recover space.
 	if m == 0 && b.off != 0 {
-		b.Truncate(0)
+		b.Reset()
 	}
-	if len(b.buf)+n > cap(b.buf) {
-		var buf []byte
-		if b.buf == nil && n <= len(b.bootstrap) {
-			buf = b.bootstrap[0:]
-		} else if m+n <= cap(b.buf)/2 {
-			// We can slide things down instead of allocating a new
-			// slice. We only need m+n <= cap(b.buf) to slide, but
-			// we instead let capacity get twice as large so we
-			// don't spend all our time copying.
-			copy(b.buf[:], b.buf[b.off:])
-			buf = b.buf[:m]
-		} else {
-			// not enough space anywhere
-			buf = makeSlice(2*cap(b.buf) + n)
-			copy(buf, b.buf[b.off:])
-		}
+	// Try to grow by means of a reslice.
+	if i, ok := b.tryGrowByReslice(n); ok {
+		return i
+	}
+	// Check if we can make use of bootstrap array.
+	if b.buf == nil && n <= len(b.bootstrap) {
+		b.buf = b.bootstrap[:n]
+		return 0
+	}
+	if m+n <= cap(b.buf)/2 {
+		// We can slide things down instead of allocating a new
+		// slice. We only need m+n <= cap(b.buf) to slide, but
+		// we instead let capacity get twice as large so we
+		// don't spend all our time copying.
+		copy(b.buf[:], b.buf[b.off:])
+	} else {
+		// Not enough space anywhere, we need to allocate.
+		buf := makeSlice(2*cap(b.buf) + n)
+		copy(buf, b.buf[b.off:])
 		b.buf = buf
-		b.off = 0
 	}
-	b.buf = b.buf[0 : b.off+m+n]
-	return b.off + m
+	// Restore b.off and len(b.buf).
+	b.off = 0
+	b.buf = b.buf[:m+n]
+	return m
 }
 
 // Grow grows the buffer's capacity, if necessary, to guarantee space for
@@ -134,7 +158,10 @@ func (b *Buffer) Grow(n int) {
 // buffer becomes too large, Write will panic with ErrTooLarge.
 func (b *Buffer) Write(p []byte) (n int, err error) {
 	b.lastRead = opInvalid
-	m := b.grow(len(p))
+	m, ok := b.tryGrowByReslice(len(p))
+	if !ok {
+		m = b.grow(len(p))
+	}
 	return copy(b.buf[m:], p), nil
 }
 
@@ -143,7 +170,10 @@ func (b *Buffer) Write(p []byte) (n int, err error) {
 // buffer becomes too large, WriteString will panic with ErrTooLarge.
 func (b *Buffer) WriteString(s string) (n int, err error) {
 	b.lastRead = opInvalid
-	m := b.grow(len(s))
+	m, ok := b.tryGrowByReslice(len(s))
+	if !ok {
+		m = b.grow(len(s))
+	}
 	return copy(b.buf[m:], s), nil
 }
 
@@ -161,7 +191,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
 	b.lastRead = opInvalid
 	// If buffer is empty, reset to recover space.
 	if b.off >= len(b.buf) {
-		b.Truncate(0)
+		b.Reset()
 	}
 	for {
 		if free := cap(b.buf) - len(b.buf); free < MinRead {
@@ -225,7 +255,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
 		}
 	}
 	// Buffer is now empty; reset.
-	b.Truncate(0)
+	b.Reset()
 	return
 }
 
@@ -235,7 +265,10 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
 // ErrTooLarge.
 func (b *Buffer) WriteByte(c byte) error {
 	b.lastRead = opInvalid
-	m := b.grow(1)
+	m, ok := b.tryGrowByReslice(1)
+	if !ok {
+		m = b.grow(1)
+	}
 	b.buf[m] = c
 	return nil
 }
@@ -250,7 +283,10 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
 		return 1, nil
 	}
 	b.lastRead = opInvalid
-	m := b.grow(utf8.UTFMax)
+	m, ok := b.tryGrowByReslice(utf8.UTFMax)
+	if !ok {
+		m = b.grow(utf8.UTFMax)
+	}
 	n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
 	b.buf = b.buf[:m+n]
 	return n, nil
@@ -264,7 +300,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) {
 	b.lastRead = opInvalid
 	if b.off >= len(b.buf) {
 		// Buffer is empty, reset to recover space.
-		b.Truncate(0)
+		b.Reset()
 		if len(p) == 0 {
 			return
 		}
@@ -302,7 +338,7 @@ 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)
+		b.Reset()
 		return 0, io.EOF
 	}
 	c := b.buf[b.off]
@@ -320,7 +356,7 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
 	b.lastRead = opInvalid
 	if b.off >= len(b.buf) {
 		// Buffer is empty, reset to recover space.
-		b.Truncate(0)
+		b.Reset()
 		return 0, 0, io.EOF
 	}
 	c := b.buf[b.off]
@@ -337,12 +373,12 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
 
 // UnreadRune unreads the last rune returned by ReadRune.
 // If the most recent read or write operation on the buffer was
-// not a ReadRune, UnreadRune returns an error.  (In this regard
+// not a successful ReadRune, UnreadRune returns an error.  (In this regard
 // it is stricter than UnreadByte, which will unread the last byte
 // from any read operation.)
 func (b *Buffer) UnreadRune() error {
 	if b.lastRead <= opInvalid {
-		return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
+		return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
 	}
 	if b.off >= int(b.lastRead) {
 		b.off -= int(b.lastRead)
@@ -351,12 +387,13 @@ func (b *Buffer) UnreadRune() error {
 	return nil
 }
 
-// UnreadByte unreads the last byte returned by the most recent
-// read operation. If write has happened since the last read, UnreadByte
-// returns an error.
+// UnreadByte unreads the last byte returned by the most recent successful
+// read operation that read at least one byte. If a write has happened since
+// the last read, if the last read returned an error, or if the read read zero
+// bytes, UnreadByte returns an error.
 func (b *Buffer) UnreadByte() error {
 	if b.lastRead == opInvalid {
-		return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
+		return errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read")
 	}
 	b.lastRead = opInvalid
 	if b.off > 0 {
@@ -404,10 +441,12 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
 	return string(slice), err
 }
 
-// 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
-// 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.
+// NewBuffer creates and initializes a new Buffer using buf as its
+// initial contents. The new Buffer takes ownership of buf, and the
+// caller should not use buf after this call. NewBuffer 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.
 //
 // In most cases, new(Buffer) (or just declaring a Buffer variable) is
 // sufficient to initialize a Buffer.
diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go
index b1b85f9..ce2f01a 100644
--- a/src/bytes/buffer_test.go
+++ b/src/bytes/buffer_test.go
@@ -6,8 +6,10 @@ package bytes_test
 
 import (
 	. "bytes"
+	"internal/testenv"
 	"io"
 	"math/rand"
+	"os/exec"
 	"runtime"
 	"testing"
 	"unicode/utf8"
@@ -311,6 +313,19 @@ func TestRuneIO(t *testing.T) {
 
 	// Check that UnreadRune works
 	buf.Reset()
+
+	// check at EOF
+	if err := buf.UnreadRune(); err == nil {
+		t.Fatal("UnreadRune at EOF: got no error")
+	}
+	if _, _, err := buf.ReadRune(); err == nil {
+		t.Fatal("ReadRune at EOF: got no error")
+	}
+	if err := buf.UnreadRune(); err == nil {
+		t.Fatal("UnreadRune after ReadRune at EOF: got no error")
+	}
+
+	// check not at EOF
 	buf.Write(b)
 	for r := rune(0); r < NRune; r++ {
 		r1, size, _ := buf.ReadRune()
@@ -473,15 +488,34 @@ func TestReadEmptyAtEOF(t *testing.T) {
 
 func TestUnreadByte(t *testing.T) {
 	b := new(Buffer)
+
+	// check at EOF
+	if err := b.UnreadByte(); err == nil {
+		t.Fatal("UnreadByte at EOF: got no error")
+	}
+	if _, err := b.ReadByte(); err == nil {
+		t.Fatal("ReadByte at EOF: got no error")
+	}
+	if err := b.UnreadByte(); err == nil {
+		t.Fatal("UnreadByte after ReadByte at EOF: got no error")
+	}
+
+	// check not at EOF
 	b.WriteString("abcdefghijklmnopqrstuvwxyz")
 
-	_, err := b.ReadBytes('m')
-	if err != nil {
-		t.Fatalf("ReadBytes: %v", err)
+	// after unsuccessful read
+	if n, err := b.Read(nil); n != 0 || err != nil {
+		t.Fatalf("Read(nil) = %d,%v; want 0,nil", n, err)
+	}
+	if err := b.UnreadByte(); err == nil {
+		t.Fatal("UnreadByte after Read(nil): got no error")
 	}
 
-	err = b.UnreadByte()
-	if err != nil {
+	// after successful read
+	if _, err := b.ReadBytes('m'); err != nil {
+		t.Fatalf("ReadBytes: %v", err)
+	}
+	if err := b.UnreadByte(); err != nil {
 		t.Fatalf("UnreadByte: %v", err)
 	}
 	c, err := b.ReadByte()
@@ -514,6 +548,38 @@ func TestBufferGrowth(t *testing.T) {
 	}
 }
 
+// Test that tryGrowByReslice is inlined.
+// Only execute on "linux-amd64" builder in order to avoid breakage.
+func TestTryGrowByResliceInlined(t *testing.T) {
+	targetBuilder := "linux-amd64"
+	if testenv.Builder() != targetBuilder {
+		t.Skipf("%q gets executed on %q builder only", t.Name(), targetBuilder)
+	}
+	t.Parallel()
+	goBin := testenv.GoToolPath(t)
+	out, err := exec.Command(goBin, "tool", "nm", goBin).CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool nm: %v: %s", err, out)
+	}
+	// Verify this doesn't exist:
+	sym := "bytes.(*Buffer).tryGrowByReslice"
+	if Contains(out, []byte(sym)) {
+		t.Errorf("found symbol %q in cmd/go, but should be inlined", sym)
+	}
+}
+
+func BenchmarkWriteByte(b *testing.B) {
+	const n = 4 << 10
+	b.SetBytes(n)
+	buf := NewBuffer(make([]byte, n))
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		for i := 0; i < n; i++ {
+			buf.WriteByte('x')
+		}
+	}
+}
+
 func BenchmarkWriteRune(b *testing.B) {
 	const n = 4 << 10
 	const r = '☺'
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 406a382..7c878af 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -46,36 +46,21 @@ func explode(s []byte, n int) [][]byte {
 	return a[0:na]
 }
 
-// Count counts the number of non-overlapping instances of sep in s.
-// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
-func Count(s, sep []byte) int {
-	n := len(sep)
-	if n == 0 {
+// countGeneric actually implements Count
+func countGeneric(s, sep []byte) int {
+	// special case
+	if len(sep) == 0 {
 		return utf8.RuneCount(s) + 1
 	}
-	if n > len(s) {
-		return 0
-	}
-	count := 0
-	c := sep[0]
-	i := 0
-	t := s[:len(s)-n+1]
-	for i < len(t) {
-		if t[i] != c {
-			o := IndexByte(t[i:], c)
-			if o < 0 {
-				break
-			}
-			i += o
-		}
-		if n == 1 || Equal(s[i:i+n], sep) {
-			count++
-			i += n
-			continue
+	n := 0
+	for {
+		i := Index(s, sep)
+		if i == -1 {
+			return n
 		}
-		i++
+		n++
+		s = s[i+len(sep):]
 	}
-	return count
 }
 
 // Contains reports whether subslice is within b.
@@ -229,20 +214,21 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
 	if n < 0 {
 		n = Count(s, sep) + 1
 	}
-	c := sep[0]
-	start := 0
+
 	a := make([][]byte, n)
-	na := 0
-	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
-		if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
-			a[na] = s[start : i+sepSave]
-			na++
-			start = i + len(sep)
-			i += len(sep) - 1
+	n--
+	i := 0
+	for i < n {
+		m := Index(s, sep)
+		if m < 0 {
+			break
 		}
+		a[i] = s[:m+sepSave]
+		s = s[m+len(sep):]
+		i++
 	}
-	a[na] = s[start:]
-	return a[0 : na+1]
+	a[i] = s
+	return a[:i+1]
 }
 
 // SplitN slices s into subslices separated by sep and returns a slice of
diff --git a/src/bytes/bytes_amd64.go b/src/bytes/bytes_amd64.go
index 6affff6..77d5970 100644
--- a/src/bytes/bytes_amd64.go
+++ b/src/bytes/bytes_amd64.go
@@ -4,17 +4,19 @@
 
 package bytes
 
+import "internal/cpu"
+
 //go:noescape
 
 // indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s.
 // indexShortStr requires 2 <= len(c) <= shortStringLen
-func indexShortStr(s, c []byte) int // ../runtime/asm_$GOARCH.s
-func supportAVX2() bool             // ../runtime/asm_$GOARCH.s
+func indexShortStr(s, c []byte) int  // ../runtime/asm_amd64.s
+func countByte(s []byte, c byte) int // ../runtime/asm_amd64.s
 
 var shortStringLen int
 
 func init() {
-	if supportAVX2() {
+	if cpu.X86.HasAVX2 {
 		shortStringLen = 63
 	} else {
 		shortStringLen = 31
@@ -94,6 +96,15 @@ func Index(s, sep []byte) int {
 	return -1
 }
 
+// Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
+func Count(s, sep []byte) int {
+	if len(sep) == 1 && cpu.X86.HasPOPCNT {
+		return countByte(s, sep[0])
+	}
+	return countGeneric(s, sep)
+}
+
 // primeRK is the prime base used in Rabin-Karp algorithm.
 const primeRK = 16777619
 
diff --git a/src/bytes/bytes_generic.go b/src/bytes/bytes_generic.go
index 06c9e1f..98454bc 100644
--- a/src/bytes/bytes_generic.go
+++ b/src/bytes/bytes_generic.go
@@ -39,3 +39,9 @@ func Index(s, sep []byte) int {
 	}
 	return -1
 }
+
+// Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
+func Count(s, sep []byte) int {
+	return countGeneric(s, sep)
+}
diff --git a/src/bytes/bytes_s390x.go b/src/bytes/bytes_s390x.go
index 988c603..68b5730 100644
--- a/src/bytes/bytes_s390x.go
+++ b/src/bytes/bytes_s390x.go
@@ -97,6 +97,12 @@ func Index(s, sep []byte) int {
 	return -1
 }
 
+// Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
+func Count(s, sep []byte) int {
+	return countGeneric(s, sep)
+}
+
 // primeRK is the prime base used in Rabin-Karp algorithm.
 const primeRK = 16777619
 
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index 26eac5e..ca0cdbb 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -396,6 +396,79 @@ func TestIndexRune(t *testing.T) {
 	}
 }
 
+// test count of a single byte across page offsets
+func TestCountByte(t *testing.T) {
+	b := make([]byte, 5015) // bigger than a page
+	windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
+	testCountWindow := func(i, window int) {
+		for j := 0; j < window; j++ {
+			b[i+j] = byte(100)
+			p := Count(b[i:i+window], []byte{100})
+			if p != j+1 {
+				t.Errorf("TestCountByte.Count(%q, 100) = %d", b[i:i+window], p)
+			}
+			pGeneric := CountGeneric(b[i:i+window], []byte{100})
+			if pGeneric != j+1 {
+				t.Errorf("TestCountByte.CountGeneric(%q, 100) = %d", b[i:i+window], p)
+			}
+		}
+	}
+
+	maxWnd := windows[len(windows)-1]
+
+	for i := 0; i <= 2*maxWnd; i++ {
+		for _, window := range windows {
+			if window > len(b[i:]) {
+				window = len(b[i:])
+			}
+			testCountWindow(i, window)
+			for j := 0; j < window; j++ {
+				b[i+j] = byte(0)
+			}
+		}
+	}
+	for i := 4096 - (maxWnd + 1); i < len(b); i++ {
+		for _, window := range windows {
+			if window > len(b[i:]) {
+				window = len(b[i:])
+			}
+			testCountWindow(i, window)
+			for j := 0; j < window; j++ {
+				b[i+j] = byte(0)
+			}
+		}
+	}
+}
+
+// Make sure we don't count bytes outside our window
+func TestCountByteNoMatch(t *testing.T) {
+	b := make([]byte, 5015)
+	windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
+	for i := 0; i <= len(b); i++ {
+		for _, window := range windows {
+			if window > len(b[i:]) {
+				window = len(b[i:])
+			}
+			// Fill the window with non-match
+			for j := 0; j < window; j++ {
+				b[i+j] = byte(100)
+			}
+			// Try to find something that doesn't exist
+			p := Count(b[i:i+window], []byte{0})
+			if p != 0 {
+				t.Errorf("TestCountByteNoMatch(%q, 0) = %d", b[i:i+window], p)
+			}
+			pGeneric := CountGeneric(b[i:i+window], []byte{0})
+			if pGeneric != 0 {
+				t.Errorf("TestCountByteNoMatch.CountGeneric(%q, 100) = %d", b[i:i+window], p)
+			}
+			for j := 0; j < window; j++ {
+				b[i+j] = byte(0)
+			}
+		}
+	}
+}
+
 var bmbuf []byte
 
 func valName(x int) string {
@@ -589,6 +662,26 @@ func BenchmarkCountEasy(b *testing.B) {
 	})
 }
 
+func BenchmarkCountSingle(b *testing.B) {
+	benchBytes(b, indexSizes, func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		step := 8
+		for i := 0; i < len(buf); i += step {
+			buf[i] = 1
+		}
+		expect := (len(buf) + (step - 1)) / step
+		for i := 0; i < b.N; i++ {
+			j := Count(buf, []byte{1})
+			if j != expect {
+				b.Fatal("bad count", j, expect)
+			}
+		}
+		for i := 0; i < len(buf); i++ {
+			buf[i] = 0
+		}
+	})
+}
+
 type ExplodeTest struct {
 	s string
 	n int
@@ -1432,6 +1525,59 @@ func BenchmarkTrimSpace(b *testing.B) {
 	}
 }
 
+func makeBenchInputHard() []byte {
+	tokens := [...]string{
+		"<a>", "<p>", "<b>", "<strong>",
+		"</a>", "</p>", "</b>", "</strong>",
+		"hello", "world",
+	}
+	x := make([]byte, 0, 1<<20)
+	for {
+		i := rand.Intn(len(tokens))
+		if len(x)+len(tokens[i]) >= 1<<20 {
+			break
+		}
+		x = append(x, tokens[i]...)
+	}
+	return x
+}
+
+var benchInputHard = makeBenchInputHard()
+
+func BenchmarkSplitEmptySeparator(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		Split(benchInputHard, nil)
+	}
+}
+
+func BenchmarkSplitSingleByteSeparator(b *testing.B) {
+	sep := []byte("/")
+	for i := 0; i < b.N; i++ {
+		Split(benchInputHard, sep)
+	}
+}
+
+func BenchmarkSplitMultiByteSeparator(b *testing.B) {
+	sep := []byte("hello")
+	for i := 0; i < b.N; i++ {
+		Split(benchInputHard, sep)
+	}
+}
+
+func BenchmarkSplitNSingleByteSeparator(b *testing.B) {
+	sep := []byte("/")
+	for i := 0; i < b.N; i++ {
+		SplitN(benchInputHard, sep, 10)
+	}
+}
+
+func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
+	sep := []byte("hello")
+	for i := 0; i < b.N; i++ {
+		SplitN(benchInputHard, sep, 10)
+	}
+}
+
 func BenchmarkRepeat(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Repeat([]byte("-"), 80)
diff --git a/src/bytes/export_test.go b/src/bytes/export_test.go
index f61523e..823c8b0 100644
--- a/src/bytes/export_test.go
+++ b/src/bytes/export_test.go
@@ -7,3 +7,4 @@ package bytes
 // Export func for testing
 var IndexBytePortable = indexBytePortable
 var EqualPortable = equalPortable
+var CountGeneric = countGeneric
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 2bd2e35..22bf137 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -89,16 +89,25 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
 func TestAddr2Line(t *testing.T) {
 	testenv.MustHaveGoBuild(t)
 
-	syms := loadSyms(t)
-
 	tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
 	if err != nil {
 		t.Fatal("TempDir failed: ", err)
 	}
 	defer os.RemoveAll(tmpDir)
 
-	exepath := filepath.Join(tmpDir, "testaddr2line.exe")
-	out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
+	// Build copy of test binary with debug symbols,
+	// since the one running now may not have them.
+	exepath := filepath.Join(tmpDir, "testaddr2line_test.exe")
+	out, err := exec.Command(testenv.GoToolPath(t), "test", "-c", "-o", exepath, "cmd/addr2line").CombinedOutput()
+	if err != nil {
+		t.Fatalf("go test -c -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
+	}
+	os.Args[0] = exepath
+
+	syms := loadSyms(t)
+
+	exepath = filepath.Join(tmpDir, "testaddr2line.exe")
+	out, err = exec.Command(testenv.GoToolPath(t), "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
 	if err != nil {
 		t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
 	}
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index 1753644..20cddb7 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -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", "go1.7", "go1.8"),
+		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.9"),
 		"-next", file("next"),
 		"-except", file("except")).CombinedOutput()
 	if err != nil {
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 9110ca7..b4ce2fd 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -236,15 +236,15 @@ func archArm64() *Arch {
 	register := make(map[string]int16)
 	// Create maps for easy lookup of instruction names etc.
 	// Note that there is no list of names as there is for 386 and amd64.
-	register[arm64.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
+	register[obj.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
 	for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
-		register[arm64.Rconv(i)] = int16(i)
+		register[obj.Rconv(i)] = int16(i)
 	}
 	for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
-		register[arm64.Rconv(i)] = int16(i)
+		register[obj.Rconv(i)] = int16(i)
 	}
 	for i := arm64.REG_V0; i <= arm64.REG_V31; i++ {
-		register[arm64.Rconv(i)] = int16(i)
+		register[obj.Rconv(i)] = int16(i)
 	}
 	register["LR"] = arm64.REGLINK
 	register["DAIF"] = arm64.REG_DAIF
diff --git a/src/cmd/asm/internal/arch/arm.go b/src/cmd/asm/internal/arch/arm.go
index 967dedc..40443d5 100644
--- a/src/cmd/asm/internal/arch/arm.go
+++ b/src/cmd/asm/internal/arch/arm.go
@@ -158,10 +158,10 @@ func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset
 }
 
 // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
-// MULA, MULAWT or MULAWB, the 4-operand instructions.
+// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
 func IsARMMULA(op obj.As) bool {
 	switch op {
-	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
+	case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
 		return true
 	}
 	return false
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
index ab64a05..dd04719 100644
--- a/src/cmd/asm/internal/arch/arm64.go
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -43,6 +43,8 @@ var arm64Jump = map[string]bool{
 	"CBNZ":  true,
 	"CBNZW": true,
 	"JMP":   true,
+	"TBNZ":  true,
+	"TBZ":   true,
 }
 
 func jumpArm64(word string) bool {
diff --git a/src/cmd/asm/internal/arch/s390x.go b/src/cmd/asm/internal/arch/s390x.go
index 1836f87..d6d46f8 100644
--- a/src/cmd/asm/internal/arch/s390x.go
+++ b/src/cmd/asm/internal/arch/s390x.go
@@ -48,24 +48,6 @@ func jumpS390x(word string) bool {
 	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 {
@@ -86,38 +68,6 @@ func IsS390xNEG(op obj.As) bool {
 	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.AVLEG, s390x.AVLEF, s390x.AVLEH, s390x.AVLEB:
-		return true
-	case s390x.AVSTEG, s390x.AVSTEF, s390x.AVSTEH, s390x.AVSTEB:
-		return true
-	case s390x.AVPDI:
-		return true
-	}
-	return false
-}
-
 func s390xRegisterNumber(name string, n int16) (int16, bool) {
 	switch name {
 	case "AR":
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index d7c5687..df23856 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/objabi"
 	"cmd/internal/sys"
 )
 
@@ -61,7 +62,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
 	}
 	prog.Pc = p.pc
 	if *flags.Debug {
-		fmt.Println(p.histLineNum, prog)
+		fmt.Println(p.lineNum, prog)
 	}
 	if testOut != nil {
 		fmt.Fprintln(testOut, prog)
@@ -151,7 +152,7 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
 		frameSize = -frameSize
 	}
 	op = op[1:]
-	argSize := int64(obj.ArgsSizeUnknown)
+	argSize := int64(objabi.ArgsSizeUnknown)
 	if len(op) > 0 {
 		// There is an argument size. It must be a minus sign followed by a non-negative integer literal.
 		if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
@@ -160,23 +161,20 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
 		}
 		argSize = p.positiveAtoi(op[1].String())
 	}
+	p.ctxt.InitTextSym(nameAddr.Sym, int(flag))
 	prog := &obj.Prog{
-		Ctxt:   p.ctxt,
-		As:     obj.ATEXT,
-		Lineno: p.histLineNum,
-		From:   nameAddr,
-		From3: &obj.Addr{
-			Type:   obj.TYPE_CONST,
-			Offset: flag,
-		},
+		Ctxt: p.ctxt,
+		As:   obj.ATEXT,
+		Pos:  p.pos(),
+		From: nameAddr,
 		To: obj.Addr{
 			Type:   obj.TYPE_TEXTSIZE,
 			Offset: frameSize,
 			// Argsize set below.
 		},
 	}
+	nameAddr.Sym.Func.Text = prog
 	prog.To.Val = int32(argSize)
-
 	p.append(prog, "", true)
 }
 
@@ -294,11 +292,11 @@ func (p *Parser) asmPCData(word string, operands [][]lex.Token) {
 
 	// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
 	prog := &obj.Prog{
-		Ctxt:   p.ctxt,
-		As:     obj.APCDATA,
-		Lineno: p.histLineNum,
-		From:   key,
-		To:     value,
+		Ctxt: p.ctxt,
+		As:   obj.APCDATA,
+		Pos:  p.pos(),
+		From: key,
+		To:   value,
 	}
 	p.append(prog, "", true)
 }
@@ -324,11 +322,11 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
 	}
 
 	prog := &obj.Prog{
-		Ctxt:   p.ctxt,
-		As:     obj.AFUNCDATA,
-		Lineno: p.histLineNum,
-		From:   valueAddr,
-		To:     nameAddr,
+		Ctxt: p.ctxt,
+		As:   obj.AFUNCDATA,
+		Pos:  p.pos(),
+		From: valueAddr,
+		To:   nameAddr,
 	}
 	p.append(prog, "", true)
 }
@@ -340,9 +338,9 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
 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:     op,
+		Ctxt: p.ctxt,
+		Pos:  p.pos(),
+		As:   op,
 	}
 	switch len(a) {
 	case 1:
@@ -390,6 +388,18 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
 			}
 			break
 		}
+		if p.arch.Family == sys.ARM64 {
+			// Special 3-operand jumps.
+			// a[0] must be immediate constant; a[1] is a register.
+			if a[0].Type != obj.TYPE_CONST {
+				p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
+				return
+			}
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			target = &a[2]
+			break
+		}
 
 		fallthrough
 	default:
@@ -468,9 +478,9 @@ func (p *Parser) branch(jmp, target *obj.Prog) {
 func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
 	// fmt.Printf("%s %+v\n", op, a)
 	prog := &obj.Prog{
-		Ctxt:   p.ctxt,
-		Lineno: p.histLineNum,
-		As:     op,
+		Ctxt: p.ctxt,
+		Pos:  p.pos(),
+		As:   op,
 	}
 	switch len(a) {
 	case 0:
@@ -613,12 +623,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
 				return
 			}
 		case sys.S390X:
-			if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) {
-				prog.From = a[1]
-				prog.From3 = newAddr(a[0])
-			} else {
+			prog.From = a[0]
+			if a[1].Type == obj.TYPE_REG {
 				prog.Reg = p.getRegister(prog, op, &a[1])
-				prog.From = a[0]
+			} else {
+				prog.From3 = newAddr(a[1])
 			}
 			prog.To = a[2]
 		default:
@@ -630,12 +639,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
 			// All must be registers.
 			p.getRegister(prog, op, &a[0])
 			r1 := p.getRegister(prog, op, &a[1])
-			p.getRegister(prog, op, &a[2])
-			r3 := p.getRegister(prog, op, &a[3])
+			r2 := p.getRegister(prog, op, &a[2])
+			p.getRegister(prog, op, &a[3])
 			prog.From = a[0]
-			prog.To = a[2]
+			prog.To = a[3]
 			prog.To.Type = obj.TYPE_REGREG2
-			prog.To.Offset = int64(r3)
+			prog.To.Offset = int64(r2)
 			prog.Reg = r1
 			break
 		}
@@ -701,9 +710,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
 			}
 		}
 		if p.arch.Family == sys.S390X {
-			prog.From = a[1]
-			prog.Reg = p.getRegister(prog, op, &a[2])
-			prog.From3 = newAddr(a[0])
+			if a[1].Type != obj.TYPE_REG {
+				p.errorf("second operand must be a register in %s instruction", op)
+				return
+			}
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.From3 = newAddr(a[2])
 			prog.To = a[3]
 			break
 		}
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index a2f31f8..239c211 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -19,6 +19,7 @@ import (
 
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 )
 
 // An end-to-end test for the assembler: Do we print what we parse?
@@ -26,12 +27,12 @@ import (
 // result against a golden file.
 
 func testEndToEnd(t *testing.T, goarch, file string) {
-	lex.InitHist()
 	input := filepath.Join("testdata", file+".s")
 	architecture, ctxt := setArch(goarch)
-	lexer := lex.NewLexer(input, ctxt)
+	architecture.Init(ctxt)
+	lexer := lex.NewLexer(input)
 	parser := NewParser(ctxt, architecture, lexer)
-	pList := obj.Linknewplist(ctxt)
+	pList := new(obj.Plist)
 	var ok bool
 	testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
 	ctxt.Bso = bufio.NewWriter(os.Stdout)
@@ -62,6 +63,11 @@ Diff:
 	for _, line := range lines {
 		lineno++
 
+		// Ignore include of textflag.h.
+		if strings.HasPrefix(line, "#include ") {
+			continue
+		}
+
 		// The general form of a test input line is:
 		//	// comment
 		//	INST args [// printed form] [// hex encoding]
@@ -180,7 +186,7 @@ Diff:
 		t.Errorf(format, args...)
 		ok = false
 	}
-	obj.FlushplistNoFree(ctxt)
+	obj.Flushplist(ctxt, pList, nil)
 
 	for p := top; p != nil; p = p.Link {
 		if p.As == obj.ATEXT {
@@ -264,12 +270,11 @@ var (
 )
 
 func testErrors(t *testing.T, goarch, file string) {
-	lex.InitHist()
 	input := filepath.Join("testdata", file+".s")
 	architecture, ctxt := setArch(goarch)
-	lexer := lex.NewLexer(input, ctxt)
+	lexer := lex.NewLexer(input)
 	parser := NewParser(ctxt, architecture, lexer)
-	pList := obj.Linknewplist(ctxt)
+	pList := new(obj.Plist)
 	var ok bool
 	testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
 	ctxt.Bso = bufio.NewWriter(os.Stdout)
@@ -285,7 +290,7 @@ func testErrors(t *testing.T, goarch, file string) {
 		errBuf.WriteString(s)
 	}
 	pList.Firstpc, ok = parser.Parse()
-	obj.Flushplist(ctxt)
+	obj.Flushplist(ctxt, pList, nil)
 	if ok && !failed {
 		t.Errorf("asm: %s had no errors", goarch)
 	}
@@ -301,7 +306,7 @@ func testErrors(t *testing.T, goarch, file string) {
 			continue
 		}
 		fileline := m[1]
-		if errors[fileline] != "" {
+		if errors[fileline] != "" && errors[fileline] != line {
 			t.Errorf("multiple errors on %s:\n\t%s\n\t%s", fileline, errors[fileline], line)
 			continue
 		}
@@ -348,25 +353,30 @@ func testErrors(t *testing.T, goarch, file string) {
 }
 
 func Test386EndToEnd(t *testing.T) {
-	defer os.Setenv("GO386", os.Getenv("GO386"))
-
-	for _, go386 := range []string{"387", "sse"} {
-		os.Setenv("GO386", go386)
-		t.Logf("GO386=%v", os.Getenv("GO386"))
+	defer func(old string) { objabi.GO386 = old }(objabi.GO386)
+	for _, go386 := range []string{"387", "sse2"} {
+		t.Logf("GO386=%v", go386)
+		objabi.GO386 = go386
 		testEndToEnd(t, "386", "386")
 	}
 }
 
 func TestARMEndToEnd(t *testing.T) {
-	defer os.Setenv("GOARM", os.Getenv("GOARM"))
-
-	for _, goarm := range []string{"5", "6", "7"} {
-		os.Setenv("GOARM", goarm)
-		t.Logf("GOARM=%v", os.Getenv("GOARM"))
+	defer func(old int) { objabi.GOARM = old }(objabi.GOARM)
+	for _, goarm := range []int{5, 6, 7} {
+		t.Logf("GOARM=%d", goarm)
+		objabi.GOARM = goarm
 		testEndToEnd(t, "arm", "arm")
+		if goarm == 6 {
+			testEndToEnd(t, "arm", "armv6")
+		}
 	}
 }
 
+func TestARMErrors(t *testing.T) {
+	testErrors(t, "arm", "armerror")
+}
+
 func TestARM64EndToEnd(t *testing.T) {
 	testEndToEnd(t, "arm64", "arm64")
 }
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index f1531a8..ca692bf 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -10,13 +10,14 @@ import (
 	"cmd/asm/internal/arch"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 )
 
 // A simple in-out test: Do we print what we parse?
 
 func setArch(goarch string) (*arch.Arch, *obj.Link) {
-	obj.GOOS = "linux" // obj can handle this OS for all architectures.
-	obj.GOARCH = goarch
+	objabi.GOOS = "linux" // obj can handle this OS for all architectures.
+	objabi.GOARCH = goarch
 	architecture := arch.Set(goarch)
 	if architecture == nil {
 		panic("asm: unrecognized architecture " + goarch)
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 406c65e..a6e13db 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -19,14 +19,14 @@ import (
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/src"
 	"cmd/internal/sys"
 )
 
 type Parser struct {
 	lex           lex.TokenReader
 	lineNum       int   // Line number in source file.
-	histLineNum   int32 // Cumulative line number across source files.
-	errorLine     int32 // (Cumulative) line number of last error.
+	errorLine     int   // Line number of last error.
 	errorCount    int   // Number of errors.
 	pc            int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
 	input         []lex.Token
@@ -60,7 +60,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
 	}
 }
 
-// panicOnError is enable when testing to abort execution on the first error
+// panicOnError is enabled when testing to abort execution on the first error
 // and turn it into a recoverable panic.
 var panicOnError bool
 
@@ -68,11 +68,11 @@ func (p *Parser) errorf(format string, args ...interface{}) {
 	if panicOnError {
 		panic(fmt.Errorf(format, args...))
 	}
-	if p.histLineNum == p.errorLine {
+	if p.lineNum == p.errorLine {
 		// Only one error per line.
 		return
 	}
-	p.errorLine = p.histLineNum
+	p.errorLine = p.lineNum
 	if p.lex != nil {
 		// Put file and line information on head of message.
 		format = "%s:%d: " + format + "\n"
@@ -85,6 +85,10 @@ func (p *Parser) errorf(format string, args ...interface{}) {
 	}
 }
 
+func (p *Parser) pos() src.XPos {
+	return p.ctxt.PosTable.XPos(src.MakePos(p.lex.Base(), uint(p.lineNum), 0))
+}
+
 func (p *Parser) Parse() (*obj.Prog, bool) {
 	for p.line() {
 	}
@@ -105,7 +109,6 @@ func (p *Parser) line() bool {
 		// are labeled with this line. Otherwise we complain after we've absorbed
 		// the terminating newline and the line numbers are off by one in errors.
 		p.lineNum = p.lex.Line()
-		p.histLineNum = lex.HistLine()
 		switch tok {
 		case '\n', ';':
 			continue
@@ -421,7 +424,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.Family != sys.ARM {
+	if !p.arch.InFamily(sys.ARM, sys.ARM64) {
 		return false
 	}
 	// R1<<...
@@ -503,7 +506,7 @@ func (p *Parser) register(name string, prefix rune) (r1, r2 int16, scale int8, o
 	return r1, r2, scale, true
 }
 
-// registerShift parses an ARM shifted register reference and returns the encoded representation.
+// registerShift parses an ARM/ARM64 shifted register reference and returns the encoded representation.
 // There is known to be a register (current token) and a shift operator (peeked token).
 func (p *Parser) registerShift(name string, prefix rune) int64 {
 	if prefix != 0 {
@@ -528,6 +531,8 @@ func (p *Parser) registerShift(name string, prefix rune) int64 {
 	case lex.ARR:
 		op = 2
 	case lex.ROT:
+		// following instructions on ARM64 support rotate right
+		// AND, ANDS, TST, BIC, BICS, EON, EOR, ORR, MVN, ORN
 		op = 3
 	}
 	tok := p.next()
@@ -535,22 +540,37 @@ func (p *Parser) registerShift(name string, prefix rune) int64 {
 	var count int16
 	switch tok.ScanToken {
 	case scanner.Ident:
-		r2, ok := p.registerReference(str)
-		if !ok {
-			p.errorf("rhs of shift must be register or integer: %s", str)
+		if p.arch.Family == sys.ARM64 {
+			p.errorf("rhs of shift must be integer: %s", str)
+		} else {
+			r2, ok := p.registerReference(str)
+			if !ok {
+				p.errorf("rhs of shift must be register or integer: %s", str)
+			}
+			count = (r2&15)<<8 | 1<<4
 		}
-		count = (r2&15)<<8 | 1<<4
 	case scanner.Int, '(':
 		p.back()
 		x := int64(p.expr())
-		if x >= 32 {
-			p.errorf("register shift count too large: %s", str)
+		if p.arch.Family == sys.ARM64 {
+			if x >= 64 {
+				p.errorf("register shift count too large: %s", str)
+			}
+			count = int16((x & 63) << 10)
+		} else {
+			if x >= 32 {
+				p.errorf("register shift count too large: %s", str)
+			}
+			count = int16((x & 31) << 7)
 		}
-		count = int16((x & 31) << 7)
 	default:
 		p.errorf("unexpected %s in register shift", tok.String())
 	}
-	return int64((r1 & 15) | op<<5 | count)
+	if p.arch.Family == sys.ARM64 {
+		return int64(int64(r1&31)<<16 | int64(op)<<22 | int64(uint16(count)))
+	} else {
+		return int64((r1 & 15) | op<<5 | count)
+	}
 }
 
 // symbolReference parses a symbol that is known not to be a register.
@@ -565,16 +585,20 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
 		a.Type = obj.TYPE_INDIR
 	}
 	// Weirdness with statics: Might now have "<>".
-	isStatic := 0 // TODO: Really a boolean, but Linklookup wants a "version" integer.
+	isStatic := false
 	if p.peek() == '<' {
-		isStatic = 1
+		isStatic = true
 		p.next()
 		p.get('>')
 	}
 	if p.peek() == '+' || p.peek() == '-' {
 		a.Offset = int64(p.expr())
 	}
-	a.Sym = obj.Linklookup(p.ctxt, name, isStatic)
+	if isStatic {
+		a.Sym = p.ctxt.LookupStatic(name)
+	} else {
+		a.Sym = p.ctxt.Lookup(name)
+	}
 	if p.peek() == scanner.EOF {
 		if prefix == 0 && p.isJump {
 			// Symbols without prefix or suffix are jump labels.
@@ -587,7 +611,7 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
 	p.get('(')
 	reg := p.get(scanner.Ident).String()
 	p.get(')')
-	p.setPseudoRegister(a, reg, isStatic != 0, prefix)
+	p.setPseudoRegister(a, reg, isStatic, prefix)
 }
 
 // setPseudoRegister sets the NAME field of addr for a pseudo-register reference such as (SB).
diff --git a/src/cmd/asm/internal/asm/pseudo_test.go b/src/cmd/asm/internal/asm/pseudo_test.go
index 1697973..9ba9adf 100644
--- a/src/cmd/asm/internal/asm/pseudo_test.go
+++ b/src/cmd/asm/internal/asm/pseudo_test.go
@@ -56,7 +56,6 @@ func TestErroneous(t *testing.T) {
 	for _, test := range tests {
 		parser.errorCount = 0
 		parser.lineNum++
-		parser.histLineNum++
 		if !parser.pseudo(test.pseudo, tokenize(test.operands)) {
 			t.Fatalf("Wrong pseudo-instruction: %s", test.pseudo)
 		}
diff --git a/src/cmd/asm/internal/asm/testdata/386.s b/src/cmd/asm/internal/asm/testdata/386.s
index 4d969d1..ad8affd 100644
--- a/src/cmd/asm/internal/asm/testdata/386.s
+++ b/src/cmd/asm/internal/asm/testdata/386.s
@@ -2,7 +2,9 @@
 // the old assembler's (8a's) grammar and hand-writing complete
 // instructions for each rule, to guarantee we cover the same space.
 
-TEXT foo(SB), 7, $0
+#include "../../../../../runtime/textflag.h"
+
+TEXT foo(SB), DUPOK|NOSPLIT, $0
 
 // LTYPE1 nonrem	{ outcode(int($1), &$2); }
 	SETCC	AX
diff --git a/src/cmd/asm/internal/asm/testdata/amd64.s b/src/cmd/asm/internal/asm/testdata/amd64.s
index da01442..d07cf0d 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64.s
@@ -6,7 +6,9 @@
 // the old assembler's (6a's) grammar and hand-writing complete
 // instructions for each rule, to guarantee we cover the same space.
 
-TEXT	foo(SB), 7, $0
+#include "../../../../../runtime/textflag.h"
+
+TEXT	foo(SB), DUPOK|NOSPLIT, $0
 
 // LTYPE1 nonrem	{ outcode($1, &$2); }
 	NEGQ	R11
diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc.s b/src/cmd/asm/internal/asm/testdata/amd64enc.s
index b27faa5..ec888bc 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64enc.s
@@ -1,7 +1,9 @@
 // generated by x86test -amd64
 // DO NOT EDIT
 
-TEXT asmtest(SB),7,$0
+#include "../../../../../runtime/textflag.h"
+
+TEXT asmtest(SB),DUPOK|NOSPLIT,$0
 	ADCB $7, AL                             // 1407
 	ADCW $61731, AX                         // 661523f1
 	ADCL $4045620583, AX                    // 15674523f1
@@ -78,10 +80,10 @@ TEXT asmtest(SB),7,$0
 	ADCQ (R11), DX                          // 491313
 	ADCQ (BX), R11                          // 4c131b
 	ADCQ (R11), R11                         // 4d131b
-	//TODO: ADCB (BX), DL                   // 1213
-	//TODO: ADCB (R11), DL                  // 411213
-	//TODO: ADCB (BX), R11                  // 44121b
-	//TODO: ADCB (R11), R11                 // 45121b
+	ADCB (BX), DL                           // 1213
+	ADCB (R11), DL                          // 411213
+	ADCB (BX), R11                          // 44121b
+	ADCB (R11), R11                         // 45121b
 	//TODO: ADCXL (BX), DX                  // 660f38f613
 	//TODO: ADCXL (R11), DX                 // 66410f38f613
 	//TODO: ADCXL DX, DX                    // 660f38f6d2
@@ -410,14 +412,14 @@ TEXT asmtest(SB),7,$0
 	ANDPD (R11), X11                        // 66450f541b
 	ANDPD X2, X11                           // 66440f54da
 	ANDPD X11, X11                          // 66450f54db
-	//TODO: ANDPS (BX), X2                  // 0f5413
-	//TODO: ANDPS (R11), X2                 // 410f5413
-	//TODO: ANDPS X2, X2                    // 0f54d2
-	//TODO: ANDPS X11, X2                   // 410f54d3
-	//TODO: ANDPS (BX), X11                 // 440f541b
-	//TODO: ANDPS (R11), X11                // 450f541b
-	//TODO: ANDPS X2, X11                   // 440f54da
-	//TODO: ANDPS X11, X11                  // 450f54db
+	ANDPS (BX), X2                          // 0f5413
+	ANDPS (R11), X2                         // 410f5413
+	ANDPS X2, X2                            // 0f54d2
+	ANDPS X11, X2                           // 410f54d3
+	ANDPS (BX), X11                         // 440f541b
+	ANDPS (R11), X11                        // 450f541b
+	ANDPS X2, X11                           // 440f54da
+	ANDPS X11, X11                          // 450f54db
 	BEXTRL R9, (BX), DX                     // c4e230f713
 	BEXTRL R9, (R11), DX                    // c4c230f713
 	BEXTRL R9, DX, DX                       // c4e230f7d2
@@ -1240,41 +1242,41 @@ TEXT asmtest(SB),7,$0
 	CMPB DL, (R11)                          // 413a13
 	CMPB R11, (BX)                          // 443a1b
 	CMPB R11, (R11)                         // 453a1b
-	//TODO: CMPPD $7, X2, (BX)              // 660fc21307
-	//TODO: CMPPD $7, X2, (R11)             // 66410fc21307
-	//TODO: CMPPD $7, X2, X2                // 660fc2d207
-	//TODO: CMPPD $7, X2, X11               // 66410fc2d307
-	//TODO: CMPPD $7, X11, (BX)             // 66440fc21b07
-	//TODO: CMPPD $7, X11, (R11)            // 66450fc21b07
-	//TODO: CMPPD $7, X11, X2               // 66440fc2da07
-	//TODO: CMPPD $7, X11, X11              // 66450fc2db07
-	//TODO: CMPPS $7, X2, (BX)              // 0fc21307
-	//TODO: CMPPS $7, X2, (R11)             // 410fc21307
-	//TODO: CMPPS $7, X2, X2                // 0fc2d207
-	//TODO: CMPPS $7, X2, X11               // 410fc2d307
-	//TODO: CMPPS $7, X11, (BX)             // 440fc21b07
-	//TODO: CMPPS $7, X11, (R11)            // 450fc21b07
-	//TODO: CMPPS $7, X11, X2               // 440fc2da07
-	//TODO: CMPPS $7, X11, X11              // 450fc2db07
+	CMPPD (BX), X2, $7                      // 660fc21307
+	CMPPD (R11), X2, $7                     // 66410fc21307
+	CMPPD X2, X2, $7                        // 660fc2d207
+	CMPPD X11, X2, $7                       // 66410fc2d307
+	CMPPD (BX), X11, $7                     // 66440fc21b07
+	CMPPD (R11), X11, $7                    // 66450fc21b07
+	CMPPD X2, X11, $7                       // 66440fc2da07
+	CMPPD X11, X11, $7                      // 66450fc2db07
+	CMPPS (BX), X2, $7                      // 0fc21307
+	CMPPS (R11), X2, $7                     // 410fc21307
+	CMPPS X2, X2, $7                        // 0fc2d207
+	CMPPS X11, X2, $7                       // 410fc2d307
+	CMPPS (BX), X11, $7                     // 440fc21b07
+	CMPPS (R11), X11, $7                    // 450fc21b07
+	CMPPS X2, X11, $7                       // 440fc2da07
+	CMPPS X11, X11, $7                      // 450fc2db07
 	CMPSB                                   // a6
 	CMPSL                                   // a7
-	//TODO: CMPSD $7, X2, (BX)              // f20fc21307
-	//TODO: CMPSD $7, X2, (R11)             // f2410fc21307
-	//TODO: CMPSD $7, X2, X2                // f20fc2d207
-	//TODO: CMPSD $7, X2, X11               // f2410fc2d307
-	//TODO: CMPSD $7, X11, (BX)             // f2440fc21b07
-	//TODO: CMPSD $7, X11, (R11)            // f2450fc21b07
-	//TODO: CMPSD $7, X11, X2               // f2440fc2da07
-	//TODO: CMPSD $7, X11, X11              // f2450fc2db07
+	CMPSD (BX), X2, $7                      // f20fc21307
+	CMPSD (R11), X2, $7                     // f2410fc21307
+	CMPSD X2, X2, $7                        // f20fc2d207
+	CMPSD X11, X2, $7                       // f2410fc2d307
+	CMPSD (BX), X11, $7                     // f2440fc21b07
+	CMPSD (R11), X11, $7                    // f2450fc21b07
+	CMPSD X2, X11, $7                       // f2440fc2da07
+	CMPSD X11, X11, $7                      // f2450fc2db07
 	CMPSQ                                   // 48a7
-	//TODO: CMPSS $7, X2, (BX)              // f30fc21307
-	//TODO: CMPSS $7, X2, (R11)             // f3410fc21307
-	//TODO: CMPSS $7, X2, X2                // f30fc2d207
-	//TODO: CMPSS $7, X2, X11               // f3410fc2d307
-	//TODO: CMPSS $7, X11, (BX)             // f3440fc21b07
-	//TODO: CMPSS $7, X11, (R11)            // f3450fc21b07
-	//TODO: CMPSS $7, X11, X2               // f3440fc2da07
-	//TODO: CMPSS $7, X11, X11              // f3450fc2db07
+	CMPSS (BX), X2, $7                      // f30fc21307
+	CMPSS (R11), X2, $7                     // f3410fc21307
+	CMPSS X2, X2, $7                        // f30fc2d207
+	CMPSS X11, X2, $7                       // f3410fc2d307
+	CMPSS (BX), X11, $7                     // f3440fc21b07
+	CMPSS (R11), X11, $7                    // f3450fc21b07
+	CMPSS X2, X11, $7                       // f3440fc2da07
+	CMPSS X11, X11, $7                      // f3450fc2db07
 	CMPSW                                   // 66a7
 	CMPXCHGW DX, (BX)                       // 660fb113
 	CMPXCHGW R11, (BX)                      // 66440fb11b
@@ -2685,18 +2687,18 @@ TEXT asmtest(SB),7,$0
 	MOVQOZX M3, X11                         // f3440fd6db
 	MOVSB                                   // a4
 	MOVSL                                   // a5
-	//TODO: MOVSD (BX), X2                  // f20f1013
-	//TODO: MOVSD (R11), X2                 // f2410f1013
-	//TODO: MOVSD X2, X2                    // f20f10d2 or f20f11d2
-	//TODO: MOVSD X11, X2                   // f2410f10d3 or f2440f11da
-	//TODO: MOVSD (BX), X11                 // f2440f101b
-	//TODO: MOVSD (R11), X11                // f2450f101b
-	//TODO: MOVSD X2, X11                   // f2440f10da or f2410f11d3
-	//TODO: MOVSD X11, X11                  // f2450f10db or f2450f11db
-	//TODO: MOVSD X2, (BX)                  // f20f1113
-	//TODO: MOVSD X11, (BX)                 // f2440f111b
-	//TODO: MOVSD X2, (R11)                 // f2410f1113
-	//TODO: MOVSD X11, (R11)                // f2450f111b
+	MOVSD (BX), X2                          // f20f1013
+	MOVSD (R11), X2                         // f2410f1013
+	MOVSD X2, X2                            // f20f10d2 or f20f11d2
+	MOVSD X11, X2                           // f2410f10d3 or f2440f11da
+	MOVSD (BX), X11                         // f2440f101b
+	MOVSD (R11), X11                        // f2450f101b
+	MOVSD X2, X11                           // f2440f10da or f2410f11d3
+	MOVSD X11, X11                          // f2450f10db or f2450f11db
+	MOVSD X2, (BX)                          // f20f1113
+	MOVSD X11, (BX)                         // f2440f111b
+	MOVSD X2, (R11)                         // f2410f1113
+	MOVSD X11, (R11)                        // f2450f111b
 	MOVSHDUP (BX), X2                       // f30f1613
 	MOVSHDUP (R11), X2                      // f3410f1613
 	MOVSHDUP X2, X2                         // f30f16d2
diff --git a/src/cmd/asm/internal/asm/testdata/arm.s b/src/cmd/asm/internal/asm/testdata/arm.s
index 06fc44c..e1a7548 100644
--- a/src/cmd/asm/internal/asm/testdata/arm.s
+++ b/src/cmd/asm/internal/asm/testdata/arm.s
@@ -6,7 +6,9 @@
 // the old assembler's (5a's) grammar and hand-writing complete
 // instructions for each rule, to guarantee we cover the same space.
 
-TEXT	foo(SB), 7, $0
+#include "../../../../../runtime/textflag.h"
+
+TEXT	foo(SB), DUPOK|NOSPLIT, $0
 
 // ADD
 //
@@ -45,7 +47,7 @@ TEXT	foo(SB), 7, $0
 //	{
 //		outcode($1, $2, &$3, 0, &$5);
 //	}
-	CLZ.S	R1, R2
+	CLZ	R1, R2
 
 //
 // MOVW
@@ -101,9 +103,9 @@ TEXT	foo(SB), 7, $0
 //	{
 //		outcode($1, $2, &nullgen, 0, &$4);
 //	}
-	SWI.S	$2
-	SWI.S	(R1)
-//	SWI.S	foo(SB) - TODO: classifying foo(SB) as C_TLS_LE
+	SWI	$2
+	SWI	$3
+//	SWI	foo(SB) - TODO: classifying foo(SB) as C_TLS_LE
 
 //
 // CMP
@@ -112,9 +114,9 @@ TEXT	foo(SB), 7, $0
 //	{
 //		outcode($1, $2, &$3, $5, &nullgen);
 //	}
-	CMP.S	$1, R2
-	CMP.S	R1<<R2, R3
-	CMP.S	R1, R2
+	CMP	$1, R2
+	CMP	R1<<R2, R3
+	CMP	R1, R2
 
 //
 // MOVM
@@ -130,7 +132,7 @@ TEXT	foo(SB), 7, $0
 //	}
 	MOVM	0(R1), [R2,R5,R8,g] // MOVM	(R1), [R2,R5,R8,g]
 	MOVM	(R1), [R2-R5] // MOVM (R1), [R2,R3,R4,R5]
-	MOVM.S	(R1), [R2]
+	MOVM	(R1), [R2]
 
 //	LTYPE8 cond '[' reglist ']' ',' ioreg
 //	{
@@ -143,7 +145,7 @@ TEXT	foo(SB), 7, $0
 //	}
 	MOVM	[R2,R5,R8,g], 0(R1) // MOVM	[R2,R5,R8,g], (R1)
 	MOVM	[R2-R5], (R1) // MOVM [R2,R3,R4,R5], (R1)
-	MOVM.S	[R2], (R1)
+	MOVM	[R2], (R1)
 
 //
 // SWAP
@@ -152,19 +154,19 @@ TEXT	foo(SB), 7, $0
 //	{
 //		outcode($1, $2, &$5, int32($3.Reg), &$7);
 //	}
-	STREX.S	R1, (R2), R3 // STREX.S (R2), R1, R3
+	STREX	R1, (R2), R3 // STREX (R2), R1, R3
 
 //	LTYPE9 cond reg ',' ireg
 //	{
 //		outcode($1, $2, &$5, int32($3.Reg), &$3);
 //	}
-	STREX.S	R1, (R2) // STREX.S (R2), R1, R1
+	STREX	R1, (R2) // STREX (R2), R1, R1
 
 //	LTYPE9 cond comma ireg ',' reg
 //	{
 //		outcode($1, $2, &$4, int32($6.Reg), &$6);
 //	}
-	STREX.S	(R2), R3 // STREX.S (R2), R3, R3
+	STREX	(R2), R3 // STREX (R2), R3, R3
 
 //
 // word
@@ -182,26 +184,26 @@ TEXT	foo(SB), 7, $0
 //	{
 //		outcode($1, $2, &$3, 0, &$5);
 //	}
-	ABSF.S	F1, F2
+	ABSF	F1, F2
 
 //	LTYPEK cond frcon ',' freg
 //	{
 //		outcode($1, $2, &$3, 0, &$5);
 //	}
-	ADDD.S	F1, F2
+	ADDD	F1, F2
 	MOVF	$0.5, F2 // MOVF $(0.5), F2
 
 //	LTYPEK cond frcon ',' LFREG ',' freg
 //	{
 //		outcode($1, $2, &$3, $5, &$7);
 //	}
-	ADDD.S	F1, F2, F3
+	ADDD	F1, F2, F3
 
 //	LTYPEL cond freg ',' freg
 //	{
 //		outcode($1, $2, &$3, int32($5.Reg), &nullgen);
 //	}
-	CMPD.S	F1, F2
+	CMPD	F1, F2
 
 //
 // MCR MRC
@@ -281,6 +283,944 @@ TEXT	foo(SB), 7, $0
 	CMPF F1, F2
 	CMPD F1, F2
 
+// AND
+	AND	$255, R0, R1         // ff1000e2
+	AND	$4278190080, R0, R1  // ff1400e2
+	AND.S	$255, R0, R1         // ff1010e2
+	AND.S	$4278190080, R0, R1  // ff1410e2
+	AND	$255, R0             // ff0000e2
+	AND	$4278190080, R0      // ff0400e2
+	AND.S	$255, R0             // ff0010e2
+	AND.S	$4278190080, R0      // ff0410e2
+	AND	R0, R1, R2           // 002001e0
+	AND.S	R0, R1, R2           // 002011e0
+	AND	R0, R1               // 001001e0
+	AND.S	R0, R1               // 001011e0
+	AND	R0>>28, R1, R2       // 202e01e0
+	AND	R0<<28, R1, R2       // 002e01e0
+	AND	R0->28, R1, R2       // 402e01e0
+	AND	R0@>28, R1, R2       // 602e01e0
+	AND.S	R0>>28, R1, R2       // 202e11e0
+	AND.S	R0<<28, R1, R2       // 002e11e0
+	AND.S	R0->28, R1, R2       // 402e11e0
+	AND.S	R0@>28, R1, R2       // 602e11e0
+	AND	R0<<28, R1           // 001e01e0
+	AND	R0>>28, R1           // 201e01e0
+	AND	R0->28, R1           // 401e01e0
+	AND	R0@>28, R1           // 601e01e0
+	AND.S	R0<<28, R1           // 001e11e0
+	AND.S	R0>>28, R1           // 201e11e0
+	AND.S	R0->28, R1           // 401e11e0
+	AND.S	R0@>28, R1           // 601e11e0
+	AND	R0<<R1, R2, R3       // 103102e0
+	AND	R0>>R1, R2, R3       // 303102e0
+	AND	R0->R1, R2, R3       // 503102e0
+	AND	R0@>R1, R2, R3       // 703102e0
+	AND.S	R0<<R1, R2, R3       // 103112e0
+	AND.S	R0>>R1, R2, R3       // 303112e0
+	AND.S	R0->R1, R2, R3       // 503112e0
+	AND.S	R0@>R1, R2, R3       // 703112e0
+	AND	R0<<R1, R2           // 102102e0
+	AND	R0>>R1, R2           // 302102e0
+	AND	R0->R1, R2           // 502102e0
+	AND	R0@>R1, R2           // 702102e0
+	AND.S	R0<<R1, R2           // 102112e0
+	AND.S	R0>>R1, R2           // 302112e0
+	AND.S	R0->R1, R2           // 502112e0
+	AND.S	R0@>R1, R2           // 702112e0
+
+// EOR
+	EOR	$255, R0, R1         // ff1020e2
+	EOR	$4278190080, R0, R1  // ff1420e2
+	EOR.S	$255, R0, R1         // ff1030e2
+	EOR.S	$4278190080, R0, R1  // ff1430e2
+	EOR	$255, R0             // ff0020e2
+	EOR	$4278190080, R0      // ff0420e2
+	EOR.S	$255, R0             // ff0030e2
+	EOR.S	$4278190080, R0      // ff0430e2
+	EOR	R0, R1, R2           // 002021e0
+	EOR.S	R0, R1, R2           // 002031e0
+	EOR	R0, R1               // 001021e0
+	EOR.S	R0, R1               // 001031e0
+	EOR	R0>>28, R1, R2       // 202e21e0
+	EOR	R0<<28, R1, R2       // 002e21e0
+	EOR	R0->28, R1, R2       // 402e21e0
+	EOR	R0@>28, R1, R2       // 602e21e0
+	EOR.S	R0>>28, R1, R2       // 202e31e0
+	EOR.S	R0<<28, R1, R2       // 002e31e0
+	EOR.S	R0->28, R1, R2       // 402e31e0
+	EOR.S	R0@>28, R1, R2       // 602e31e0
+	EOR	R0<<28, R1           // 001e21e0
+	EOR	R0>>28, R1           // 201e21e0
+	EOR	R0->28, R1           // 401e21e0
+	EOR	R0@>28, R1           // 601e21e0
+	EOR.S	R0<<28, R1           // 001e31e0
+	EOR.S	R0>>28, R1           // 201e31e0
+	EOR.S	R0->28, R1           // 401e31e0
+	EOR.S	R0@>28, R1           // 601e31e0
+	EOR	R0<<R1, R2, R3       // 103122e0
+	EOR	R0>>R1, R2, R3       // 303122e0
+	EOR	R0->R1, R2, R3       // 503122e0
+	EOR	R0@>R1, R2, R3       // 703122e0
+	EOR.S	R0<<R1, R2, R3       // 103132e0
+	EOR.S	R0>>R1, R2, R3       // 303132e0
+	EOR.S	R0->R1, R2, R3       // 503132e0
+	EOR.S	R0@>R1, R2, R3       // 703132e0
+	EOR	R0<<R1, R2           // 102122e0
+	EOR	R0>>R1, R2           // 302122e0
+	EOR	R0->R1, R2           // 502122e0
+	EOR	R0@>R1, R2           // 702122e0
+	EOR.S	R0<<R1, R2           // 102132e0
+	EOR.S	R0>>R1, R2           // 302132e0
+	EOR.S	R0->R1, R2           // 502132e0
+	EOR.S	R0@>R1, R2           // 702132e0
+
+// ORR
+	ORR	$255, R0, R1         // ff1080e3
+	ORR	$4278190080, R0, R1  // ff1480e3
+	ORR.S	$255, R0, R1         // ff1090e3
+	ORR.S	$4278190080, R0, R1  // ff1490e3
+	ORR	$255, R0             // ff0080e3
+	ORR	$4278190080, R0      // ff0480e3
+	ORR.S	$255, R0             // ff0090e3
+	ORR.S	$4278190080, R0      // ff0490e3
+	ORR	R0, R1, R2           // 002081e1
+	ORR.S	R0, R1, R2           // 002091e1
+	ORR	R0, R1               // 001081e1
+	ORR.S	R0, R1               // 001091e1
+	ORR	R0>>28, R1, R2       // 202e81e1
+	ORR	R0<<28, R1, R2       // 002e81e1
+	ORR	R0->28, R1, R2       // 402e81e1
+	ORR	R0@>28, R1, R2       // 602e81e1
+	ORR.S	R0>>28, R1, R2       // 202e91e1
+	ORR.S	R0<<28, R1, R2       // 002e91e1
+	ORR.S	R0->28, R1, R2       // 402e91e1
+	ORR.S	R0@>28, R1, R2       // 602e91e1
+	ORR	R0<<28, R1           // 001e81e1
+	ORR	R0>>28, R1           // 201e81e1
+	ORR	R0->28, R1           // 401e81e1
+	ORR	R0@>28, R1           // 601e81e1
+	ORR.S	R0<<28, R1           // 001e91e1
+	ORR.S	R0>>28, R1           // 201e91e1
+	ORR.S	R0->28, R1           // 401e91e1
+	ORR.S	R0@>28, R1           // 601e91e1
+	ORR	R0<<R1, R2, R3       // 103182e1
+	ORR	R0>>R1, R2, R3       // 303182e1
+	ORR	R0->R1, R2, R3       // 503182e1
+	ORR	R0@>R1, R2, R3       // 703182e1
+	ORR.S	R0<<R1, R2, R3       // 103192e1
+	ORR.S	R0>>R1, R2, R3       // 303192e1
+	ORR.S	R0->R1, R2, R3       // 503192e1
+	ORR.S	R0@>R1, R2, R3       // 703192e1
+	ORR	R0<<R1, R2           // 102182e1
+	ORR	R0>>R1, R2           // 302182e1
+	ORR	R0->R1, R2           // 502182e1
+	ORR	R0@>R1, R2           // 702182e1
+	ORR.S	R0<<R1, R2           // 102192e1
+	ORR.S	R0>>R1, R2           // 302192e1
+	ORR.S	R0->R1, R2           // 502192e1
+	ORR.S	R0@>R1, R2           // 702192e1
+
+// SUB
+	SUB	$255, R0, R1         // ff1040e2
+	SUB	$4278190080, R0, R1  // ff1440e2
+	SUB.S	$255, R0, R1         // ff1050e2
+	SUB.S	$4278190080, R0, R1  // ff1450e2
+	SUB	$255, R0             // ff0040e2
+	SUB	$4278190080, R0      // ff0440e2
+	SUB.S	$255, R0             // ff0050e2
+	SUB.S	$4278190080, R0      // ff0450e2
+	SUB	R0, R1, R2           // 002041e0
+	SUB.S	R0, R1, R2           // 002051e0
+	SUB	R0, R1               // 001041e0
+	SUB.S	R0, R1               // 001051e0
+	SUB	R0>>28, R1, R2       // 202e41e0
+	SUB	R0<<28, R1, R2       // 002e41e0
+	SUB	R0->28, R1, R2       // 402e41e0
+	SUB	R0@>28, R1, R2       // 602e41e0
+	SUB.S	R0>>28, R1, R2       // 202e51e0
+	SUB.S	R0<<28, R1, R2       // 002e51e0
+	SUB.S	R0->28, R1, R2       // 402e51e0
+	SUB.S	R0@>28, R1, R2       // 602e51e0
+	SUB	R0<<28, R1           // 001e41e0
+	SUB	R0>>28, R1           // 201e41e0
+	SUB	R0->28, R1           // 401e41e0
+	SUB	R0@>28, R1           // 601e41e0
+	SUB.S	R0<<28, R1           // 001e51e0
+	SUB.S	R0>>28, R1           // 201e51e0
+	SUB.S	R0->28, R1           // 401e51e0
+	SUB.S	R0@>28, R1           // 601e51e0
+	SUB	R0<<R1, R2, R3       // 103142e0
+	SUB	R0>>R1, R2, R3       // 303142e0
+	SUB	R0->R1, R2, R3       // 503142e0
+	SUB	R0@>R1, R2, R3       // 703142e0
+	SUB.S	R0<<R1, R2, R3       // 103152e0
+	SUB.S	R0>>R1, R2, R3       // 303152e0
+	SUB.S	R0->R1, R2, R3       // 503152e0
+	SUB.S	R0@>R1, R2, R3       // 703152e0
+	SUB	R0<<R1, R2           // 102142e0
+	SUB	R0>>R1, R2           // 302142e0
+	SUB	R0->R1, R2           // 502142e0
+	SUB	R0@>R1, R2           // 702142e0
+	SUB.S	R0<<R1, R2           // 102152e0
+	SUB.S	R0>>R1, R2           // 302152e0
+	SUB.S	R0->R1, R2           // 502152e0
+	SUB.S	R0@>R1, R2           // 702152e0
+
+// SBC
+	SBC	$255, R0, R1         // ff10c0e2
+	SBC	$4278190080, R0, R1  // ff14c0e2
+	SBC.S	$255, R0, R1         // ff10d0e2
+	SBC.S	$4278190080, R0, R1  // ff14d0e2
+	SBC	$255, R0             // ff00c0e2
+	SBC	$4278190080, R0      // ff04c0e2
+	SBC.S	$255, R0             // ff00d0e2
+	SBC.S	$4278190080, R0      // ff04d0e2
+	SBC	R0, R1, R2           // 0020c1e0
+	SBC.S	R0, R1, R2           // 0020d1e0
+	SBC	R0, R1               // 0010c1e0
+	SBC.S	R0, R1               // 0010d1e0
+	SBC	R0>>28, R1, R2       // 202ec1e0
+	SBC	R0<<28, R1, R2       // 002ec1e0
+	SBC	R0->28, R1, R2       // 402ec1e0
+	SBC	R0@>28, R1, R2       // 602ec1e0
+	SBC.S	R0>>28, R1, R2       // 202ed1e0
+	SBC.S	R0<<28, R1, R2       // 002ed1e0
+	SBC.S	R0->28, R1, R2       // 402ed1e0
+	SBC.S	R0@>28, R1, R2       // 602ed1e0
+	SBC	R0<<28, R1           // 001ec1e0
+	SBC	R0>>28, R1           // 201ec1e0
+	SBC	R0->28, R1           // 401ec1e0
+	SBC	R0@>28, R1           // 601ec1e0
+	SBC.S	R0<<28, R1           // 001ed1e0
+	SBC.S	R0>>28, R1           // 201ed1e0
+	SBC.S	R0->28, R1           // 401ed1e0
+	SBC.S	R0@>28, R1           // 601ed1e0
+	SBC	R0<<R1, R2, R3       // 1031c2e0
+	SBC	R0>>R1, R2, R3       // 3031c2e0
+	SBC	R0->R1, R2, R3       // 5031c2e0
+	SBC	R0@>R1, R2, R3       // 7031c2e0
+	SBC.S	R0<<R1, R2, R3       // 1031d2e0
+	SBC.S	R0>>R1, R2, R3       // 3031d2e0
+	SBC.S	R0->R1, R2, R3       // 5031d2e0
+	SBC.S	R0@>R1, R2, R3       // 7031d2e0
+	SBC	R0<<R1, R2           // 1021c2e0
+	SBC	R0>>R1, R2           // 3021c2e0
+	SBC	R0->R1, R2           // 5021c2e0
+	SBC	R0@>R1, R2           // 7021c2e0
+	SBC.S	R0<<R1, R2           // 1021d2e0
+	SBC.S	R0>>R1, R2           // 3021d2e0
+	SBC.S	R0->R1, R2           // 5021d2e0
+	SBC.S	R0@>R1, R2           // 7021d2e0
+
+// RSB
+	RSB	$255, R0, R1         // ff1060e2
+	RSB	$4278190080, R0, R1  // ff1460e2
+	RSB.S	$255, R0, R1         // ff1070e2
+	RSB.S	$4278190080, R0, R1  // ff1470e2
+	RSB	$255, R0             // ff0060e2
+	RSB	$4278190080, R0      // ff0460e2
+	RSB.S	$255, R0             // ff0070e2
+	RSB.S	$4278190080, R0      // ff0470e2
+	RSB	R0, R1, R2           // 002061e0
+	RSB.S	R0, R1, R2           // 002071e0
+	RSB	R0, R1               // 001061e0
+	RSB.S	R0, R1               // 001071e0
+	RSB	R0>>28, R1, R2       // 202e61e0
+	RSB	R0<<28, R1, R2       // 002e61e0
+	RSB	R0->28, R1, R2       // 402e61e0
+	RSB	R0@>28, R1, R2       // 602e61e0
+	RSB.S	R0>>28, R1, R2       // 202e71e0
+	RSB.S	R0<<28, R1, R2       // 002e71e0
+	RSB.S	R0->28, R1, R2       // 402e71e0
+	RSB.S	R0@>28, R1, R2       // 602e71e0
+	RSB	R0<<28, R1           // 001e61e0
+	RSB	R0>>28, R1           // 201e61e0
+	RSB	R0->28, R1           // 401e61e0
+	RSB	R0@>28, R1           // 601e61e0
+	RSB.S	R0<<28, R1           // 001e71e0
+	RSB.S	R0>>28, R1           // 201e71e0
+	RSB.S	R0->28, R1           // 401e71e0
+	RSB.S	R0@>28, R1           // 601e71e0
+	RSB	R0<<R1, R2, R3       // 103162e0
+	RSB	R0>>R1, R2, R3       // 303162e0
+	RSB	R0->R1, R2, R3       // 503162e0
+	RSB	R0@>R1, R2, R3       // 703162e0
+	RSB.S	R0<<R1, R2, R3       // 103172e0
+	RSB.S	R0>>R1, R2, R3       // 303172e0
+	RSB.S	R0->R1, R2, R3       // 503172e0
+	RSB.S	R0@>R1, R2, R3       // 703172e0
+	RSB	R0<<R1, R2           // 102162e0
+	RSB	R0>>R1, R2           // 302162e0
+	RSB	R0->R1, R2           // 502162e0
+	RSB	R0@>R1, R2           // 702162e0
+	RSB.S	R0<<R1, R2           // 102172e0
+	RSB.S	R0>>R1, R2           // 302172e0
+	RSB.S	R0->R1, R2           // 502172e0
+	RSB.S	R0@>R1, R2           // 702172e0
+
+// RSC
+	RSC	$255, R0, R1         // ff10e0e2
+	RSC	$4278190080, R0, R1  // ff14e0e2
+	RSC.S	$255, R0, R1         // ff10f0e2
+	RSC.S	$4278190080, R0, R1  // ff14f0e2
+	RSC	$255, R0             // ff00e0e2
+	RSC	$4278190080, R0      // ff04e0e2
+	RSC.S	$255, R0             // ff00f0e2
+	RSC.S	$4278190080, R0      // ff04f0e2
+	RSC	R0, R1, R2           // 0020e1e0
+	RSC.S	R0, R1, R2           // 0020f1e0
+	RSC	R0, R1               // 0010e1e0
+	RSC.S	R0, R1               // 0010f1e0
+	RSC	R0>>28, R1, R2       // 202ee1e0
+	RSC	R0<<28, R1, R2       // 002ee1e0
+	RSC	R0->28, R1, R2       // 402ee1e0
+	RSC	R0@>28, R1, R2       // 602ee1e0
+	RSC.S	R0>>28, R1, R2       // 202ef1e0
+	RSC.S	R0<<28, R1, R2       // 002ef1e0
+	RSC.S	R0->28, R1, R2       // 402ef1e0
+	RSC.S	R0@>28, R1, R2       // 602ef1e0
+	RSC	R0<<28, R1           // 001ee1e0
+	RSC	R0>>28, R1           // 201ee1e0
+	RSC	R0->28, R1           // 401ee1e0
+	RSC	R0@>28, R1           // 601ee1e0
+	RSC.S	R0<<28, R1           // 001ef1e0
+	RSC.S	R0>>28, R1           // 201ef1e0
+	RSC.S	R0->28, R1           // 401ef1e0
+	RSC.S	R0@>28, R1           // 601ef1e0
+	RSC	R0<<R1, R2, R3       // 1031e2e0
+	RSC	R0>>R1, R2, R3       // 3031e2e0
+	RSC	R0->R1, R2, R3       // 5031e2e0
+	RSC	R0@>R1, R2, R3       // 7031e2e0
+	RSC.S	R0<<R1, R2, R3       // 1031f2e0
+	RSC.S	R0>>R1, R2, R3       // 3031f2e0
+	RSC.S	R0->R1, R2, R3       // 5031f2e0
+	RSC.S	R0@>R1, R2, R3       // 7031f2e0
+	RSC	R0<<R1, R2           // 1021e2e0
+	RSC	R0>>R1, R2           // 3021e2e0
+	RSC	R0->R1, R2           // 5021e2e0
+	RSC	R0@>R1, R2           // 7021e2e0
+	RSC.S	R0<<R1, R2           // 1021f2e0
+	RSC.S	R0>>R1, R2           // 3021f2e0
+	RSC.S	R0->R1, R2           // 5021f2e0
+	RSC.S	R0@>R1, R2           // 7021f2e0
+
+// ADD
+	ADD	$255, R0, R1         // ff1080e2
+	ADD	$4278190080, R0, R1  // ff1480e2
+	ADD.S	$255, R0, R1         // ff1090e2
+	ADD.S	$4278190080, R0, R1  // ff1490e2
+	ADD	$255, R0             // ff0080e2
+	ADD	$4278190080, R0      // ff0480e2
+	ADD.S	$255, R0             // ff0090e2
+	ADD.S	$4278190080, R0      // ff0490e2
+	ADD	R0, R1, R2           // 002081e0
+	ADD.S	R0, R1, R2           // 002091e0
+	ADD	R0, R1               // 001081e0
+	ADD.S	R0, R1               // 001091e0
+	ADD	R0>>28, R1, R2       // 202e81e0
+	ADD	R0<<28, R1, R2       // 002e81e0
+	ADD	R0->28, R1, R2       // 402e81e0
+	ADD	R0@>28, R1, R2       // 602e81e0
+	ADD.S	R0>>28, R1, R2       // 202e91e0
+	ADD.S	R0<<28, R1, R2       // 002e91e0
+	ADD.S	R0->28, R1, R2       // 402e91e0
+	ADD.S	R0@>28, R1, R2       // 602e91e0
+	ADD	R0<<28, R1           // 001e81e0
+	ADD	R0>>28, R1           // 201e81e0
+	ADD	R0->28, R1           // 401e81e0
+	ADD	R0@>28, R1           // 601e81e0
+	ADD.S	R0<<28, R1           // 001e91e0
+	ADD.S	R0>>28, R1           // 201e91e0
+	ADD.S	R0->28, R1           // 401e91e0
+	ADD.S	R0@>28, R1           // 601e91e0
+	ADD	R0<<R1, R2, R3       // 103182e0
+	ADD	R0>>R1, R2, R3       // 303182e0
+	ADD	R0->R1, R2, R3       // 503182e0
+	ADD	R0@>R1, R2, R3       // 703182e0
+	ADD.S	R0<<R1, R2, R3       // 103192e0
+	ADD.S	R0>>R1, R2, R3       // 303192e0
+	ADD.S	R0->R1, R2, R3       // 503192e0
+	ADD.S	R0@>R1, R2, R3       // 703192e0
+	ADD	R0<<R1, R2           // 102182e0
+	ADD	R0>>R1, R2           // 302182e0
+	ADD	R0->R1, R2           // 502182e0
+	ADD	R0@>R1, R2           // 702182e0
+	ADD.S	R0<<R1, R2           // 102192e0
+	ADD.S	R0>>R1, R2           // 302192e0
+	ADD.S	R0->R1, R2           // 502192e0
+	ADD.S	R0@>R1, R2           // 702192e0
+
+// ADC
+	ADC	$255, R0, R1         // ff10a0e2
+	ADC	$4278190080, R0, R1  // ff14a0e2
+	ADC.S	$255, R0, R1         // ff10b0e2
+	ADC.S	$4278190080, R0, R1  // ff14b0e2
+	ADC	$255, R0             // ff00a0e2
+	ADC	$4278190080, R0      // ff04a0e2
+	ADC.S	$255, R0             // ff00b0e2
+	ADC.S	$4278190080, R0      // ff04b0e2
+	ADC	R0, R1, R2           // 0020a1e0
+	ADC.S	R0, R1, R2           // 0020b1e0
+	ADC	R0, R1               // 0010a1e0
+	ADC.S	R0, R1               // 0010b1e0
+	ADC	R0>>28, R1, R2       // 202ea1e0
+	ADC	R0<<28, R1, R2       // 002ea1e0
+	ADC	R0->28, R1, R2       // 402ea1e0
+	ADC	R0@>28, R1, R2       // 602ea1e0
+	ADC.S	R0>>28, R1, R2       // 202eb1e0
+	ADC.S	R0<<28, R1, R2       // 002eb1e0
+	ADC.S	R0->28, R1, R2       // 402eb1e0
+	ADC.S	R0@>28, R1, R2       // 602eb1e0
+	ADC	R0<<28, R1           // 001ea1e0
+	ADC	R0>>28, R1           // 201ea1e0
+	ADC	R0->28, R1           // 401ea1e0
+	ADC	R0@>28, R1           // 601ea1e0
+	ADC.S	R0<<28, R1           // 001eb1e0
+	ADC.S	R0>>28, R1           // 201eb1e0
+	ADC.S	R0->28, R1           // 401eb1e0
+	ADC.S	R0@>28, R1           // 601eb1e0
+	ADC	R0<<R1, R2, R3       // 1031a2e0
+	ADC	R0>>R1, R2, R3       // 3031a2e0
+	ADC	R0->R1, R2, R3       // 5031a2e0
+	ADC	R0@>R1, R2, R3       // 7031a2e0
+	ADC.S	R0<<R1, R2, R3       // 1031b2e0
+	ADC.S	R0>>R1, R2, R3       // 3031b2e0
+	ADC.S	R0->R1, R2, R3       // 5031b2e0
+	ADC.S	R0@>R1, R2, R3       // 7031b2e0
+	ADC	R0<<R1, R2           // 1021a2e0
+	ADC	R0>>R1, R2           // 3021a2e0
+	ADC	R0->R1, R2           // 5021a2e0
+	ADC	R0@>R1, R2           // 7021a2e0
+	ADC.S	R0<<R1, R2           // 1021b2e0
+	ADC.S	R0>>R1, R2           // 3021b2e0
+	ADC.S	R0->R1, R2           // 5021b2e0
+	ADC.S	R0@>R1, R2           // 7021b2e0
+
+// TEQ
+	TEQ	$255, R7             // ff0037e3
+	TEQ	$4278190080, R9      // ff0439e3
+	TEQ	R9<<30, R7           // 090f37e1
+	TEQ	R9>>30, R7           // 290f37e1
+	TEQ	R9->30, R7           // 490f37e1
+	TEQ	R9@>30, R7           // 690f37e1
+	TEQ	R9<<R8, R7           // 190837e1
+	TEQ	R9>>R8, R7           // 390837e1
+	TEQ	R9->R8, R7           // 590837e1
+	TEQ	R9@>R8, R7           // 790837e1
+
+// TST
+	TST	$255, R7             // ff0017e3
+	TST	$4278190080, R9      // ff0419e3
+	TST	R9<<30, R7           // 090f17e1
+	TST	R9>>30, R7           // 290f17e1
+	TST	R9->30, R7           // 490f17e1
+	TST	R9@>30, R7           // 690f17e1
+	TST	R9<<R8, R7           // 190817e1
+	TST	R9>>R8, R7           // 390817e1
+	TST	R9->R8, R7           // 590817e1
+	TST	R9@>R8, R7           // 790817e1
+
+// CMP
+	CMP	$255, R7             // ff0057e3
+	CMP	$4278190080, R9      // ff0459e3
+	CMP	R9<<30, R7           // 090f57e1
+	CMP	R9>>30, R7           // 290f57e1
+	CMP	R9->30, R7           // 490f57e1
+	CMP	R9@>30, R7           // 690f57e1
+	CMP	R9<<R8, R7           // 190857e1
+	CMP	R9>>R8, R7           // 390857e1
+	CMP	R9->R8, R7           // 590857e1
+	CMP	R9@>R8, R7           // 790857e1
+
+// CMN
+	CMN	$255, R7             // ff0077e3
+	CMN	$4278190080, R9      // ff0479e3
+	CMN	R9<<30, R7           // 090f77e1
+	CMN	R9>>30, R7           // 290f77e1
+	CMN	R9->30, R7           // 490f77e1
+	CMN	R9@>30, R7           // 690f77e1
+	CMN	R9<<R8, R7           // 190877e1
+	CMN	R9>>R8, R7           // 390877e1
+	CMN	R9->R8, R7           // 590877e1
+	CMN	R9@>R8, R7           // 790877e1
+
+// B*
+	BEQ	14(PC) // BEQ 14(PC)   // 0c00000a
+	BNE	13(PC) // BNE 13(PC)   // 0b00001a
+	BCS	12(PC) // BCS 12(PC)   // 0a00002a
+	BCC	11(PC) // BCC 11(PC)   // 0900003a
+	BMI	10(PC) // BMI 10(PC)   // 0800004a
+	BPL	9(PC)  // BPL 9(PC)    // 0700005a
+	BVS	8(PC)  // BVS 8(PC)    // 0600006a
+	BVC	7(PC)  // BVC 7(PC)    // 0500007a
+	BHI	6(PC)  // BHI 6(PC)    // 0400008a
+	BLS	5(PC)  // BLS 5(PC)    // 0300009a
+	BGE	4(PC)  // BGE 4(PC)    // 020000aa
+	BLT	3(PC)  // BLT 3(PC)    // 010000ba
+	BGT	2(PC)  // BGT 2(PC)    // 000000ca
+	BLE	1(PC)  // BLE 1(PC)    // ffffffda
+	ADD	$0, R0, R0
+	B	-1(PC) // JMP -1(PC)   // fdffffea
+	B	-2(PC) // JMP -2(PC)   // fcffffea
+	B	-3(PC) // JMP -3(PC)   // fbffffea
+	B	-4(PC) // JMP -4(PC)   // faffffea
+	B	-5(PC) // JMP -5(PC)   // f9ffffea
+	B	jmp_label_0 // JMP     // 010000ea
+	B	jmp_label_0 // JMP     // 000000ea
+	B	jmp_label_0 // JMP     // ffffffea
+jmp_label_0:
+	ADD	$0, R0, R0
+	BEQ	jmp_label_0 // BEQ 521 // fdffff0a
+	BNE	jmp_label_0 // BNE 521 // fcffff1a
+	BCS	jmp_label_0 // BCS 521 // fbffff2a
+	BCC	jmp_label_0 // BCC 521 // faffff3a
+	BMI	jmp_label_0 // BMI 521 // f9ffff4a
+	BPL	jmp_label_0 // BPL 521 // f8ffff5a
+	BVS	jmp_label_0 // BVS 521 // f7ffff6a
+	BVC	jmp_label_0 // BVC 521 // f6ffff7a
+	BHI	jmp_label_0 // BHI 521 // f5ffff8a
+	BLS	jmp_label_0 // BLS 521 // f4ffff9a
+	BGE	jmp_label_0 // BGE 521 // f3ffffaa
+	BLT	jmp_label_0 // BLT 521 // f2ffffba
+	BGT	jmp_label_0 // BGT 521 // f1ffffca
+	BLE	jmp_label_0 // BLE 521 // f0ffffda
+	B	jmp_label_0 // JMP 521 // efffffea
+	B	0(PC)    // JMP 0(PC)  // feffffea
+jmp_label_1:
+	B	jmp_label_1 // JMP     // feffffea
+
+// BL
+	BL.EQ	14(PC) // CALL.EQ 14(PC)   // 0c00000b
+	BL.NE	13(PC) // CALL.NE 13(PC)   // 0b00001b
+	BL.CS	12(PC) // CALL.CS 12(PC)   // 0a00002b
+	BL.CC	11(PC) // CALL.CC 11(PC)   // 0900003b
+	BL.MI	10(PC) // CALL.MI 10(PC)   // 0800004b
+	BL.PL	9(PC)  // CALL.PL 9(PC)    // 0700005b
+	BL.VS	8(PC)  // CALL.VS 8(PC)    // 0600006b
+	BL.VC	7(PC)  // CALL.VC 7(PC)    // 0500007b
+	BL.HI	6(PC)  // CALL.HI 6(PC)    // 0400008b
+	BL.LS	5(PC)  // CALL.LS 5(PC)    // 0300009b
+	BL.GE	4(PC)  // CALL.GE 4(PC)    // 020000ab
+	BL.LT	3(PC)  // CALL.LT 3(PC)    // 010000bb
+	BL.GT	2(PC)  // CALL.GT 2(PC)    // 000000cb
+	BL.LE	1(PC)  // CALL.LE 1(PC)    // ffffffdb
+	ADD	$0, R0, R0
+	BL	-1(PC) // CALL -1(PC)      // fdffffeb
+	BL	-2(PC) // CALL -2(PC)      // fcffffeb
+	BL	-3(PC) // CALL -3(PC)      // fbffffeb
+	BL	-4(PC) // CALL -4(PC)      // faffffeb
+	BL	-5(PC) // CALL -5(PC)      // f9ffffeb
+	BL	jmp_label_2 // CALL        // 010000eb
+	BL	jmp_label_2 // CALL        // 000000eb
+	BL	jmp_label_2 // CALL        // ffffffeb
+jmp_label_2:
+	ADD	$0, R0, R0
+	BL.EQ	jmp_label_2 // CALL.EQ 562 // fdffff0b
+	BL.NE	jmp_label_2 // CALL.NE 562 // fcffff1b
+	BL.CS	jmp_label_2 // CALL.CS 562 // fbffff2b
+	BL.CC	jmp_label_2 // CALL.CC 562 // faffff3b
+	BL.MI	jmp_label_2 // CALL.MI 562 // f9ffff4b
+	BL.PL	jmp_label_2 // CALL.PL 562 // f8ffff5b
+	BL.VS	jmp_label_2 // CALL.VS 562 // f7ffff6b
+	BL.VC	jmp_label_2 // CALL.VC 562 // f6ffff7b
+	BL.HI	jmp_label_2 // CALL.HI 562 // f5ffff8b
+	BL.LS	jmp_label_2 // CALL.LS 562 // f4ffff9b
+	BL.GE	jmp_label_2 // CALL.GE 562 // f3ffffab
+	BL.LT	jmp_label_2 // CALL.LT 562 // f2ffffbb
+	BL.GT	jmp_label_2 // CALL.GT 562 // f1ffffcb
+	BL.LE	jmp_label_2 // CALL.LE 562 // f0ffffdb
+	BL	jmp_label_2 // CALL 562    // efffffeb
+	BL	0(PC)    // CALL 0(PC)     // feffffeb
+jmp_label_3:
+	BL	jmp_label_3 // CALL        // feffffeb
+
+// BIC
+	BIC	$255, R0, R1         // ff10c0e3
+	BIC	$4278190080, R0, R1  // ff14c0e3
+	BIC.S	$255, R0, R1         // ff10d0e3
+	BIC.S	$4278190080, R0, R1  // ff14d0e3
+	BIC	$255, R0             // ff00c0e3
+	BIC	$4278190080, R0      // ff04c0e3
+	BIC.S	$255, R0             // ff00d0e3
+	BIC.S	$4278190080, R0      // ff04d0e3
+	BIC	R0, R1, R2           // 0020c1e1
+	BIC.S	R0, R1, R2           // 0020d1e1
+	BIC	R0, R1               // 0010c1e1
+	BIC.S	R0, R1               // 0010d1e1
+	BIC	R0>>28, R1, R2       // 202ec1e1
+	BIC	R0<<28, R1, R2       // 002ec1e1
+	BIC	R0->28, R1, R2       // 402ec1e1
+	BIC	R0@>28, R1, R2       // 602ec1e1
+	BIC.S	R0>>28, R1, R2       // 202ed1e1
+	BIC.S	R0<<28, R1, R2       // 002ed1e1
+	BIC.S	R0->28, R1, R2       // 402ed1e1
+	BIC.S	R0@>28, R1, R2       // 602ed1e1
+	BIC	R0<<28, R1           // 001ec1e1
+	BIC	R0>>28, R1           // 201ec1e1
+	BIC	R0->28, R1           // 401ec1e1
+	BIC	R0@>28, R1           // 601ec1e1
+	BIC.S	R0<<28, R1           // 001ed1e1
+	BIC.S	R0>>28, R1           // 201ed1e1
+	BIC.S	R0->28, R1           // 401ed1e1
+	BIC.S	R0@>28, R1           // 601ed1e1
+	BIC	R0<<R1, R2, R3       // 1031c2e1
+	BIC	R0>>R1, R2, R3       // 3031c2e1
+	BIC	R0->R1, R2, R3       // 5031c2e1
+	BIC	R0@>R1, R2, R3       // 7031c2e1
+	BIC.S	R0<<R1, R2, R3       // 1031d2e1
+	BIC.S	R0>>R1, R2, R3       // 3031d2e1
+	BIC.S	R0->R1, R2, R3       // 5031d2e1
+	BIC.S	R0@>R1, R2, R3       // 7031d2e1
+	BIC	R0<<R1, R2           // 1021c2e1
+	BIC	R0>>R1, R2           // 3021c2e1
+	BIC	R0->R1, R2           // 5021c2e1
+	BIC	R0@>R1, R2           // 7021c2e1
+	BIC.S	R0<<R1, R2           // 1021d2e1
+	BIC.S	R0>>R1, R2           // 3021d2e1
+	BIC.S	R0->R1, R2           // 5021d2e1
+	BIC.S	R0@>R1, R2           // 7021d2e1
+
+// SRL
+	SRL	$14, R5, R6          // 2567a0e1
+	SRL	$15, R5, R6          // a567a0e1
+	SRL	$30, R5, R6          // 256fa0e1
+	SRL	$31, R5, R6          // a56fa0e1
+	SRL.S	$14, R5, R6          // 2567b0e1
+	SRL.S	$15, R5, R6          // a567b0e1
+	SRL.S	$30, R5, R6          // 256fb0e1
+	SRL.S	$31, R5, R6          // a56fb0e1
+	SRL	$14, R5              // 2557a0e1
+	SRL	$15, R5              // a557a0e1
+	SRL	$30, R5              // 255fa0e1
+	SRL	$31, R5              // a55fa0e1
+	SRL.S	$14, R5              // 2557b0e1
+	SRL.S	$15, R5              // a557b0e1
+	SRL.S	$30, R5              // 255fb0e1
+	SRL.S	$31, R5              // a55fb0e1
+	SRL	R5, R6, R7           // 3675a0e1
+	SRL.S	R5, R6, R7           // 3675b0e1
+	SRL	R5, R7               // 3775a0e1
+	SRL.S	R5, R7               // 3775b0e1
+
+// SRA
+	SRA	$14, R5, R6          // 4567a0e1
+	SRA	$15, R5, R6          // c567a0e1
+	SRA	$30, R5, R6          // 456fa0e1
+	SRA	$31, R5, R6          // c56fa0e1
+	SRA.S	$14, R5, R6          // 4567b0e1
+	SRA.S	$15, R5, R6          // c567b0e1
+	SRA.S	$30, R5, R6          // 456fb0e1
+	SRA.S	$31, R5, R6          // c56fb0e1
+	SRA	$14, R5              // 4557a0e1
+	SRA	$15, R5              // c557a0e1
+	SRA	$30, R5              // 455fa0e1
+	SRA	$31, R5              // c55fa0e1
+	SRA.S	$14, R5              // 4557b0e1
+	SRA.S	$15, R5              // c557b0e1
+	SRA.S	$30, R5              // 455fb0e1
+	SRA.S	$31, R5              // c55fb0e1
+	SRA	R5, R6, R7           // 5675a0e1
+	SRA.S	R5, R6, R7           // 5675b0e1
+	SRA	R5, R7               // 5775a0e1
+	SRA.S	R5, R7               // 5775b0e1
+
+// SLL
+	SLL	$14, R5, R6          // 0567a0e1
+	SLL	$15, R5, R6          // 8567a0e1
+	SLL	$30, R5, R6          // 056fa0e1
+	SLL	$31, R5, R6          // 856fa0e1
+	SLL.S	$14, R5, R6          // 0567b0e1
+	SLL.S	$15, R5, R6          // 8567b0e1
+	SLL.S	$30, R5, R6          // 056fb0e1
+	SLL.S	$31, R5, R6          // 856fb0e1
+	SLL	$14, R5              // 0557a0e1
+	SLL	$15, R5              // 8557a0e1
+	SLL	$30, R5              // 055fa0e1
+	SLL	$31, R5              // 855fa0e1
+	SLL.S	$14, R5              // 0557b0e1
+	SLL.S	$15, R5              // 8557b0e1
+	SLL.S	$30, R5              // 055fb0e1
+	SLL.S	$31, R5              // 855fb0e1
+	SLL	R5, R6, R7           // 1675a0e1
+	SLL.S	R5, R6, R7           // 1675b0e1
+	SLL	R5, R7               // 1775a0e1
+	SLL.S	R5, R7               // 1775b0e1
+
+// MULA / MULS
+	MULAWT		R1, R2, R3, R4       // c23124e1
+	MULAWB		R1, R2, R3, R4       // 823124e1
+	MULS		R1, R2, R3, R4       // 923164e0
+	MULA		R1, R2, R3, R4       // 923124e0
+	MULA.S		R1, R2, R3, R4       // 923134e0
+	MMULA		R1, R2, R3, R4       // 123154e7
+	MMULS		R1, R2, R3, R4       // d23154e7
+	MULABB		R1, R2, R3, R4       // 823104e1
+	MULAL		R1, R2, (R4, R3)     // 9231e4e0
+	MULAL.S		R1, R2, (R4, R3)     // 9231f4e0
+	MULALU		R1, R2, (R4, R3)     // 9231a4e0
+	MULALU.S	R1, R2, (R4, R3)     // 9231b4e0
+
+// MUL
+	MUL	R2, R3, R4           // 930204e0
+	MUL	R2, R4               // 920404e0
+	MUL.S	R2, R3, R4           // 930214e0
+	MUL.S	R2, R4               // 920414e0
+	MULU	R5, R6, R7           // 960507e0
+	MULU	R5, R7               // 950707e0
+	MULU.S	R5, R6, R7           // 960517e0
+	MULU.S	R5, R7               // 950717e0
+	MULLU	R1, R2, (R4, R3)     // 923184e0
+	MULLU.S	R1, R2, (R4, R3)     // 923194e0
+	MULL	R1, R2, (R4, R3)     // 9231c4e0
+	MULL.S	R1, R2, (R4, R3)     // 9231d4e0
+	MMUL	R1, R2, R3           // 12f153e7
+	MULBB	R1, R2, R3           // 82f163e1
+	MULWB	R1, R2, R3           // a20123e1
+	MULWT	R1, R2, R3           // e20123e1
+
+// REV
+	REV	R1, R2               // 312fbfe6
+	REV16	R1, R2               // b12fbfe6
+	REVSH	R1, R2               // b12fffe6
+	RBIT	R1, R2               // 312fffe6
+
+// DIVHW R0, R1, R2: R1 / R0 -> R2
+	DIVHW	R0, R1, R2           // 11f012e7
+	DIVUHW	R0, R1, R2           // 11f032e7
+// DIVHW R0, R1: R1 / R0 -> R1
+	DIVHW	R0, R1               // 11f011e7
+	DIVUHW	R0, R1               // 11f031e7
+
+// misc
+	CLZ	R1, R2         // 112f6fe1
+	WORD	$0             // 00000000
+	WORD	$4294967295    // ffffffff
+	WORD	$2863311530    // aaaaaaaa
+	WORD	$1431655765    // 55555555
+	PLD	4080(R6)       // f0ffd6f5
+	PLD	-4080(R9)      // f0ff59f5
+	RFE	               // 0080fde8
+	SWPW	R3, (R7), R9   // SWPW  (R7), R3, R9 // 939007e1
+	SWPBU	R4, (R2), R8   // SWPBU (R2), R4, R8 // 948042e1
+	SWI	$0             // 000000ef
+	SWI	$65535         // ffff00ef
+	SWI	               // 000000ef
+
+// synthetic arithmatic
+	ADD	$0xffffffaa, R2, R3 // ADD $4294967210, R2, R3   // 55b0e0e30b3082e0
+	ADD	$0xffffff55, R5     // ADD $4294967125, R5       // aab0e0e30b5085e0
+	ADD.S	$0xffffffab, R2, R3 // ADD.S $4294967211, R2, R3 // 54b0e0e30b3092e0
+	ADD.S	$0xffffff54, R5     // ADD.S $4294967124, R5     // abb0e0e30b5095e0
+	ADC	$0xffffffac, R2, R3 // ADC $4294967212, R2, R3   // 53b0e0e30b30a2e0
+	ADC	$0xffffff53, R5     // ADC $4294967123, R5       // acb0e0e30b50a5e0
+	ADC.S	$0xffffffad, R2, R3 // ADC.S $4294967213, R2, R3 // 52b0e0e30b30b2e0
+	ADC.S	$0xffffff52, R5     // ADC.S $4294967122, R5     // adb0e0e30b50b5e0
+	SUB	$0xffffffae, R2, R3 // SUB $4294967214, R2, R3   // 51b0e0e30b3042e0
+	SUB	$0xffffff51, R5     // SUB $4294967121, R5       // aeb0e0e30b5045e0
+	SUB.S	$0xffffffaf, R2, R3 // SUB.S $4294967215, R2, R3 // 50b0e0e30b3052e0
+	SUB.S	$0xffffff50, R5     // SUB.S $4294967120, R5     // afb0e0e30b5055e0
+	SBC	$0xffffffb0, R2, R3 // SBC $4294967216, R2, R3   // 4fb0e0e30b30c2e0
+	SBC	$0xffffff4f, R5     // SBC $4294967119, R5       // b0b0e0e30b50c5e0
+	SBC.S	$0xffffffb1, R2, R3 // SBC.S $4294967217, R2, R3 // 4eb0e0e30b30d2e0
+	SBC.S	$0xffffff4e, R5     // SBC.S $4294967118, R5     // b1b0e0e30b50d5e0
+	RSB	$0xffffffb2, R2, R3 // RSB $4294967218, R2, R3   // 4db0e0e30b3062e0
+	RSB	$0xffffff4d, R5     // RSB $4294967117, R5       // b2b0e0e30b5065e0
+	RSB.S	$0xffffffb3, R2, R3 // RSB.S $4294967219, R2, R3 // 4cb0e0e30b3072e0
+	RSB.S	$0xffffff4c, R5     // RSB.S $4294967116, R5     // b3b0e0e30b5075e0
+	RSC	$0xffffffb4, R2, R3 // RSC $4294967220, R2, R3   // 4bb0e0e30b30e2e0
+	RSC	$0xffffff4b, R5     // RSC $4294967115, R5       // b4b0e0e30b50e5e0
+	RSC.S	$0xffffffb5, R2, R3 // RSC.S $4294967221, R2, R3 // 4ab0e0e30b30f2e0
+	RSC.S	$0xffffff4a, R5     // RSC.S $4294967114, R5     // b5b0e0e30b50f5e0
+	AND	$0xffffffaa, R2, R3 // AND $4294967210, R2, R3   // 55b0e0e30b3002e0
+	AND	$0xffffff55, R5     // AND $4294967125, R5       // aab0e0e30b5005e0
+	AND.S	$0xffffffab, R2, R3 // AND.S $4294967211, R2, R3 // 54b0e0e30b3012e0
+	AND.S	$0xffffff54, R5     // AND.S $4294967124, R5     // abb0e0e30b5015e0
+	ORR	$0xffffffaa, R2, R3 // ORR $4294967210, R2, R3   // 55b0e0e30b3082e1
+	ORR	$0xffffff55, R5     // ORR $4294967125, R5       // aab0e0e30b5085e1
+	ORR.S	$0xffffffab, R2, R3 // ORR.S $4294967211, R2, R3 // 54b0e0e30b3092e1
+	ORR.S	$0xffffff54, R5     // ORR.S $4294967124, R5     // abb0e0e30b5095e1
+	EOR	$0xffffffaa, R2, R3 // EOR $4294967210, R2, R3   // 55b0e0e30b3022e0
+	EOR	$0xffffff55, R5     // EOR $4294967125, R5       // aab0e0e30b5025e0
+	EOR.S	$0xffffffab, R2, R3 // EOR.S $4294967211, R2, R3 // 54b0e0e30b3032e0
+	EOR.S	$0xffffff54, R5     // EOR.S $4294967124, R5     // abb0e0e30b5035e0
+	BIC	$0xffffffaa, R2, R3 // BIC $4294967210, R2, R3   // 55b0e0e30b30c2e1
+	BIC	$0xffffff55, R5     // BIC $4294967125, R5       // aab0e0e30b50c5e1
+	BIC.S	$0xffffffab, R2, R3 // BIC.S $4294967211, R2, R3 // 54b0e0e30b30d2e1
+	BIC.S	$0xffffff54, R5     // BIC.S $4294967124, R5     // abb0e0e30b50d5e1
+	CMP	$0xffffffab, R2     // CMP $4294967211, R2       // 54b0e0e30b0052e1
+	CMN	$0xffffffac, R3     // CMN $4294967212, R3       // 53b0e0e30b0073e1
+	TST	$0xffffffad, R4     // TST $4294967213, R4       // 52b0e0e30b0014e1
+	TEQ	$0xffffffae, R5     // TEQ $4294967214, R5       // 51b0e0e30b0035e1
+
+// immediate decomposition
+	ADD	$0xff0000ff, R0, R1 // ADD $4278190335, R0, R1 // ff1080e2ff1481e2
+	EOR	$0xff0000ff, R0, R1 // EOR $4278190335, R0, R1 // ff1020e2ff1421e2
+	ORR	$0xff0000ff, R0, R1 // ORR $4278190335, R0, R1 // ff1080e3ff1481e3
+	SUB	$0xff0000ff, R0, R1 // SUB $4278190335, R0, R1 // ff1040e2ff1441e2
+	BIC	$0xff0000ff, R0, R1 // BIC $4278190335, R0, R1 // ff10c0e3ff14c1e3
+	RSB	$0xff0000ff, R0, R1 // RSB $4278190335, R0, R1 // ff1060e2ff1481e2
+	ADC	$0xff0000ff, R0, R1 // ADC $4278190335, R0, R1 // ff10a0e2ff1481e2
+	SBC	$0xff0000ff, R0, R1 // SBC $4278190335, R0, R1 // ff10c0e2ff1441e2
+	RSC	$0xff0000ff, R0, R1 // RSC $4278190335, R0, R1 // ff10e0e2ff1481e2
+	ADD	$0x000fffff, R0, R1 // ADD $1048575, R0, R1    // 011680e2011041e2
+	ADC	$0x000fffff, R0, R1 // ADC $1048575, R0, R1    // 0116a0e2011041e2
+	SUB	$0x000fffff, R0, R1 // SUB $1048575, R0, R1    // 011640e2011081e2
+	SBC	$0x000fffff, R0, R1 // SBC $1048575, R0, R1    // 0116c0e2011081e2
+	RSB	$0x000fffff, R0, R1 // RSB $1048575, R0, R1    // 011660e2011041e2
+	RSC	$0x000fffff, R0, R1 // RSC $1048575, R0, R1    // 0116e0e2011041e2
+	ADD	$0xff0000ff, R1     // ADD $4278190335, R1     // ff1081e2ff1481e2
+	EOR	$0xff0000ff, R1     // EOR $4278190335, R1     // ff1021e2ff1421e2
+	ORR	$0xff0000ff, R1     // ORR $4278190335, R1     // ff1081e3ff1481e3
+	SUB	$0xff0000ff, R1     // SUB $4278190335, R1     // ff1041e2ff1441e2
+	BIC	$0xff0000ff, R1     // BIC $4278190335, R1     // ff10c1e3ff14c1e3
+	RSB	$0xff0000ff, R1     // RSB $4278190335, R1     // ff1061e2ff1481e2
+	ADC	$0xff0000ff, R1     // ADC $4278190335, R1     // ff10a1e2ff1481e2
+	SBC	$0xff0000ff, R1     // SBC $4278190335, R1     // ff10c1e2ff1441e2
+	RSC	$0xff0000ff, R1     // RSC $4278190335, R1     // ff10e1e2ff1481e2
+	ADD	$0x000fffff, R1     // ADD $1048575, R1        // 011681e2011041e2
+	ADC	$0x000fffff, R1     // ADC $1048575, R1        // 0116a1e2011041e2
+	SUB	$0x000fffff, R1     // SUB $1048575, R1        // 011641e2011081e2
+	SBC	$0x000fffff, R1     // SBC $1048575, R1        // 0116c1e2011081e2
+	RSB	$0x000fffff, R1     // RSB $1048575, R1        // 011661e2011041e2
+	RSC	$0x000fffff, R1     // RSC $1048575, R1        // 0116e1e2011041e2
+
+// MVN
+	MVN	$0xff, R1        // MVN $255, R1          // ff10e0e3
+	MVN	$0xff000000, R1  // MVN $4278190080, R1   // ff14e0e3
+	MVN.S	$0xff, R1        // MVN.S $255, R1        // ff10f0e3
+	MVN.S	$0xff000000, R1  // MVN.S $4278190080, R1 // ff14f0e3
+	MVN	R9<<30, R7       // 097fe0e1
+	MVN	R9>>30, R7       // 297fe0e1
+	MVN	R9->30, R7       // 497fe0e1
+	MVN	R9@>30, R7       // 697fe0e1
+	MVN.S	R9<<30, R7       // 097ff0e1
+	MVN.S	R9>>30, R7       // 297ff0e1
+	MVN.S	R9->30, R7       // 497ff0e1
+	MVN.S	R9@>30, R7       // 697ff0e1
+	MVN	R9<<R8, R7       // 1978e0e1
+	MVN	R9>>R8, R7       // 3978e0e1
+	MVN	R9->R8, R7       // 5978e0e1
+	MVN	R9@>R8, R7       // 7978e0e1
+	MVN.S	R9<<R8, R7       // 1978f0e1
+	MVN.S	R9>>R8, R7       // 3978f0e1
+	MVN.S	R9->R8, R7       // 5978f0e1
+	MVN.S	R9@>R8, R7       // 7978f0e1
+	MVN	$0xffffffae, R5  // MVN $4294967214, R5   // 51b0e0e30b50e0e1
+	MVN.S	$0xffffffae, R5  // MVN.S $4294967214, R5 // 51b0e0e30b50f0e1
+
+// MOVM
+	MOVM.IA   [R0,R2,R4,R6], (R1)        // MOVM.U [R0,R2,R4,R6], (R1)                      // 550081e8
+	MOVM.IA   [R0-R4,R6,R8,R9-R11], (R1) // MOVM.U [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)    // 5f0f81e8
+	MOVM.IA.W [R0,R2,R4,R6], (R1)        // MOVM.W.U [R0,R2,R4,R6], (R1)                    // 5500a1e8
+	MOVM.IA.W [R0-R4,R6,R8,R9-R11], (R1) // MOVM.W.U [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)  // 5f0fa1e8
+	MOVM.IA   (R1), [R0,R2,R4,R6]        // MOVM.U (R1), [R0,R2,R4,R6]                      // 550091e8
+	MOVM.IA   (R1), [R0-R4,R6,R8,R9-R11] // MOVM.U (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]    // 5f0f91e8
+	MOVM.IA.W (R1), [R0,R2,R4,R6]        // MOVM.W.U (R1), [R0,R2,R4,R6]                    // 5500b1e8
+	MOVM.IA.W (R1), [R0-R4,R6,R8,R9-R11] // MOVM.W.U (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]  // 5f0fb1e8
+	MOVM.DA   [R0,R2,R4,R6], (R1)        // MOVM [R0,R2,R4,R6], (R1)                        // 550001e8
+	MOVM.DA   [R0-R4,R6,R8,R9-R11], (R1) // MOVM [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)      // 5f0f01e8
+	MOVM.DA.W [R0,R2,R4,R6], (R1)        // MOVM.W [R0,R2,R4,R6], (R1)                      // 550021e8
+	MOVM.DA.W [R0-R4,R6,R8,R9-R11], (R1) // MOVM.W [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)    // 5f0f21e8
+	MOVM.DA   (R1), [R0,R2,R4,R6]        // MOVM (R1), [R0,R2,R4,R6]                        // 550011e8
+	MOVM.DA   (R1), [R0-R4,R6,R8,R9-R11] // MOVM (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]      // 5f0f11e8
+	MOVM.DA.W (R1), [R0,R2,R4,R6]        // MOVM.W (R1), [R0,R2,R4,R6]                      // 550031e8
+	MOVM.DA.W (R1), [R0-R4,R6,R8,R9-R11] // MOVM.W (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]    // 5f0f31e8
+	MOVM.DB   [R0,R2,R4,R6], (R1)        // MOVM.P [R0,R2,R4,R6], (R1)                      // 550001e9
+	MOVM.DB   [R0-R4,R6,R8,R9-R11], (R1) // MOVM.P [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)    // 5f0f01e9
+	MOVM.DB.W [R0,R2,R4,R6], (R1)        // MOVM.P.W [R0,R2,R4,R6], (R1)                    // 550021e9
+	MOVM.DB.W [R0-R4,R6,R8,R9-R11], (R1) // MOVM.P.W [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (R1)  // 5f0f21e9
+	MOVM.DB   (R1), [R0,R2,R4,R6]        // MOVM.P (R1), [R0,R2,R4,R6]                      // 550011e9
+	MOVM.DB   (R1), [R0-R4,R6,R8,R9-R11] // MOVM.P (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]    // 5f0f11e9
+	MOVM.DB.W (R1), [R0,R2,R4,R6]        // MOVM.P.W (R1), [R0,R2,R4,R6]                    // 550031e9
+	MOVM.DB.W (R1), [R0-R4,R6,R8,R9-R11] // MOVM.P.W (R1), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]  // 5f0f31e9
+	MOVM.IB   [R0,R2,R4,R6], (g)         // MOVM.P.U [R0,R2,R4,R6], (g)                     // 55008ae9
+	MOVM.IB   [R0-R4,R6,R8,R9-R11], (g)  // MOVM.P.U [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (g)   // 5f0f8ae9
+	MOVM.IB.W [R0,R2,R4,R6], (g)         // MOVM.P.W.U [R0,R2,R4,R6], (g)                   // 5500aae9
+	MOVM.IB.W [R0-R4,R6,R8,R9-R11], (g)  // MOVM.P.W.U [R0,R1,R2,R3,R4,R6,R8,R9,g,R11], (g) // 5f0faae9
+	MOVM.IB   (g), [R0,R2,R4,R6]         // MOVM.P.U (g), [R0,R2,R4,R6]                     // 55009ae9
+	MOVM.IB   (g), [R0-R4,R6,R8,R9-R11]  // MOVM.P.U (g), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11]   // 5f0f9ae9
+	MOVM.IB.W (g), [R0,R2,R4,R6]         // MOVM.P.W.U (g), [R0,R2,R4,R6]                   // 5500bae9
+	MOVM.IB.W (g), [R0-R4,R6,R8,R9-R11]  // MOVM.P.W.U (g), [R0,R1,R2,R3,R4,R6,R8,R9,g,R11] // 5f0fbae9
+
+// MOVW
+mov_label_0:
+	MOVW	R3, R4                                            // 0340a0e1
+	MOVW	R9, R2                                            // 0920a0e1
+	MOVW	$0xff, R9            // MOVW $255, R9             // ff90a0e3
+	MOVW	$0xff000000, R9      // MOVW $4278190080, R9      // ff94a0e3
+	MOVW	$0xff(R0), R1        // MOVW $255(R0), R1         // ff1080e2
+	MOVW	$-0xff(R0), R1       // MOVW $-255(R0), R1        // ff1040e2
+	MOVW	$0xffffffae, R1      // MOVW $4294967214, R1      // 5110e0e3
+	MOVW	$0xaaaaaaaa, R1      // MOVW $2863311530, R1
+	MOVW	$mov_label_0(SB), R2
+	MOVW	R1, (R2)                                          // 001082e5
+	MOVW.P	R1, (R2)                                          // 001082e4
+	MOVW.W	R1, (R2)                                          // 0010a2e5
+	MOVW	R1, 0x20(R2)         // MOVW R1, 32(R2)           // 201082e5
+	MOVW.P	R1, 0x20(R2)         // MOVW.P R1, 32(R2)         // 201082e4
+	MOVW.W	R1, 0x20(R2)         // MOVW.W R1, 32(R2)         // 2010a2e5
+	MOVW	R1, -0x20(R2)        // MOVW R1, -32(R2)          // 201002e5
+	MOVW.P	R1, -0x20(R2)        // MOVW.P R1, -32(R2)        // 201002e4
+	MOVW.W	R1, -0x20(R2)        // MOVW.W R1, -32(R2)        // 201022e5
+	MOVW	R1, mov_label_0(SB)
+	MOVW	(R2), R1                                          // 001092e5
+	MOVW.P	(R2), R1                                          // 001092e4
+	MOVW.W	(R2), R1                                          // 0010b2e5
+	MOVW	0x20(R2), R1         // MOVW 32(R2), R1           // 201092e5
+	MOVW.P	0x20(R2), R1         // MOVW.P 32(R2), R1         // 201092e4
+	MOVW.W	0x20(R2), R1         // MOVW.W 32(R2), R1         // 2010b2e5
+	MOVW	-0x20(R2), R1        // MOVW -32(R2), R1          // 201012e5
+	MOVW.P	-0x20(R2), R1        // MOVW.P -32(R2), R1        // 201012e4
+	MOVW.W	-0x20(R2), R1        // MOVW.W -32(R2), R1        // 201032e5
+	MOVW	mov_label_0(SB), R1
+	MOVW	R1, 0x00ffffff(R2)   // MOVW R1, 16777215(R2)
+	MOVW	R1, foo(SB)
+	MOVW	0x00ffffff(R2), R1   // MOVW 16777215(R2), R1
+	MOVW	foo(SB), R1
+	MOVW	CPSR, R1                                          // 00100fe1
+	MOVW	R1, CPSR                                          // 01f02ce1
+	MOVW	$0xff, CPSR          // MOVW $255, CPSR           // fff02ce3
+	MOVW	$0xff000000, CPSR    // MOVW $4278190080, CPSR    // fff42ce3
+	MOVW	FPSR, R9                                          // 109af1ee
+	MOVW	FPSR, g                                           // 10aaf1ee
+	MOVW	R9, FPSR                                          // 109ae1ee
+	MOVW	g, FPSR                                           // 10aae1ee
+	MOVW	R0>>28(R1), R2                                    // 202e91e7
+	MOVW	R0<<28(R1), R2                                    // 002e91e7
+	MOVW	R0->28(R1), R2                                    // 402e91e7
+	MOVW	R0@>28(R1), R2                                    // 602e91e7
+	MOVW.U	R0>>28(R1), R2                                    // 202e11e7
+	MOVW.U	R0<<28(R1), R2                                    // 002e11e7
+	MOVW.U	R0->28(R1), R2                                    // 402e11e7
+	MOVW.U	R0@>28(R1), R2                                    // 602e11e7
+	MOVW.W	R0>>28(R1), R2                                    // 202eb1e7
+	MOVW.W	R0<<28(R1), R2                                    // 002eb1e7
+	MOVW.W	R0->28(R1), R2                                    // 402eb1e7
+	MOVW.W	R0@>28(R1), R2                                    // 602eb1e7
+	MOVW.P	R0>>28(g), R2                                     // 202e9ae6
+	MOVW.P	R0<<28(g), R2                                     // 002e9ae6
+	MOVW.P	R0->28(g), R2                                     // 402e9ae6
+	MOVW.P	R0@>28(g), R2                                     // 602e9ae6
+	MOVW	R2, R0>>28(R1)                                    // 202e81e7
+	MOVW	R2, R0<<28(R1)                                    // 002e81e7
+	MOVW	R2, R0->28(R1)                                    // 402e81e7
+	MOVW	R2, R0@>28(R1)                                    // 602e81e7
+	MOVW.U	R2, R0>>28(R1)                                    // 202e01e7
+	MOVW.U	R2, R0<<28(R1)                                    // 002e01e7
+	MOVW.U	R2, R0->28(R1)                                    // 402e01e7
+	MOVW.U	R2, R0@>28(R1)                                    // 602e01e7
+	MOVW.W	R2, R0>>28(R1)                                    // 202ea1e7
+	MOVW.W	R2, R0<<28(R1)                                    // 002ea1e7
+	MOVW.W	R2, R0->28(R1)                                    // 402ea1e7
+	MOVW.W	R2, R0@>28(R1)                                    // 602ea1e7
+	MOVW.P	R2, R0>>28(R5)                                    // 202e85e6
+	MOVW.P	R2, R0<<28(R5)                                    // 002e85e6
+	MOVW.P	R2, R0->28(R5)                                    // 402e85e6
+	MOVW.P	R2, R0@>28(R5)                                    // 602e85e6
+	MOVW	R0, math·Exp(SB)     // MOVW R0, math.Exp(SB)
+	MOVW	math·Exp(SB), R0     // MOVW math.Exp(SB), R0
+
 //
 // END
 //
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 8d50196..1b6dc18 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -6,7 +6,9 @@
 // the old assembler's (7a's) grammar and hand-writing complete
 // instructions for each rule, to guarantee we cover the same space.
 
-TEXT	foo(SB), 7, $-8
+#include "../../../../../runtime/textflag.h"
+
+TEXT	foo(SB), DUPOK|NOSPLIT, $-8
 
 //
 // ADD
@@ -16,7 +18,6 @@ TEXT	foo(SB), 7, $-8
 //		outcode($1, &$2, $4, &$6);
 //	}
 // imsr comes from the old 7a, we only support immediates and registers
-// at the moment, no shifted registers.
 	ADDW	$1, R2, R3
 	ADDW	R1, R2, R3
 	ADDW	R1, ZR, R3
@@ -24,6 +25,10 @@ TEXT	foo(SB), 7, $-8
 	ADD	R1, R2, R3
 	ADD	R1, ZR, R3
 	ADD	$1, R2, R3
+	ADD	R1>>11, R2, R3
+	ADD	R1<<22, R2, R3
+	ADD	R1->33, R2, R3
+	AND	R1@>33, R2, R3
 
 //	LTYPE1 imsr ',' spreg ','
 //	{
@@ -37,6 +42,19 @@ TEXT	foo(SB), 7, $-8
 	ADDW	R1, R2
 	ADD	$1, R2
 	ADD	R1, R2
+	ADD	R1>>11, R2
+	ADD	R1<<22, R2
+	ADD	R1->33, R2
+	AND	R1@>33, R2
+
+// logical ops
+// make sure constants get encoded into an instruction when it could
+	AND	$(1<<63), R1   // AND	$-9223372036854775808, R1 // 21004192
+	AND	$(1<<63-1), R1 // AND	$9223372036854775807, R1  // 21f84092
+	ORR	$(1<<63), R1   // ORR	$-9223372036854775808, R1 // 210041b2
+	ORR	$(1<<63-1), R1 // ORR	$9223372036854775807, R1  // 21f840b2
+	EOR	$(1<<63), R1   // EOR	$-9223372036854775808, R1 // 210041d2
+	EOR	$(1<<63-1), R1 // EOR	$9223372036854775807, R1  // 21f840d2
 
 //
 // CLS
@@ -67,6 +85,60 @@ TEXT	foo(SB), 7, $-8
 	MOVD	$1, R1
 	MOVD	ZR, (R1)
 
+	// small offset fits into instructions
+	MOVB	1(R1), R2 // 22048039
+	MOVH	1(R1), R2 // 22108078
+	MOVH	2(R1), R2 // 22048079
+	MOVW	1(R1), R2 // 221080b8
+	MOVW	4(R1), R2 // 220480b9
+	MOVD	1(R1), R2 // 221040f8
+	MOVD	8(R1), R2 // 220440f9
+	FMOVS	1(R1), F2 // 221040bc
+	FMOVS	4(R1), F2 // 220440bd
+	FMOVD	1(R1), F2 // 221040fc
+	FMOVD	8(R1), F2 // 220440fd
+	MOVB	R1, 1(R2) // 41040039
+	MOVH	R1, 1(R2) // 41100078
+	MOVH	R1, 2(R2) // 41040079
+	MOVW	R1, 1(R2) // 411000b8
+	MOVW	R1, 4(R2) // 410400b9
+	MOVD	R1, 1(R2) // 411000f8
+	MOVD	R1, 8(R2) // 410400f9
+	FMOVS	F1, 1(R2) // 411000bc
+	FMOVS	F1, 4(R2) // 410400bd
+	FMOVD	F1, 1(R2) // 411000fc
+	FMOVD	F1, 8(R2) // 410400fd
+
+	// large aligned offset, use two instructions
+	MOVB	0x1001(R1), R2 // MOVB	4097(R1), R2  // 3b04409162078039
+	MOVH	0x2002(R1), R2 // MOVH	8194(R1), R2  // 3b08409162078079
+	MOVW	0x4004(R1), R2 // MOVW	16388(R1), R2 // 3b104091620780b9
+	MOVD	0x8008(R1), R2 // MOVD	32776(R1), R2 // 3b204091620740f9
+	FMOVS	0x4004(R1), F2 // FMOVS	16388(R1), F2 // 3b104091620740bd
+	FMOVD	0x8008(R1), F2 // FMOVD	32776(R1), F2 // 3b204091620740fd
+	MOVB	R1, 0x1001(R2) // MOVB	R1, 4097(R2)  // 5b04409161070039
+	MOVH	R1, 0x2002(R2) // MOVH	R1, 8194(R2)  // 5b08409161070079
+	MOVW	R1, 0x4004(R2) // MOVW	R1, 16388(R2) // 5b104091610700b9
+	MOVD	R1, 0x8008(R2) // MOVD	R1, 32776(R2) // 5b204091610700f9
+	FMOVS	F1, 0x4004(R2) // FMOVS	F1, 16388(R2) // 5b104091610700bd
+	FMOVD	F1, 0x8008(R2) // FMOVD	F1, 32776(R2) // 5b204091610700fd
+
+	// very large or unaligned offset uses constant pool
+	// the encoding cannot be checked as the address of the constant pool is unknown.
+	// here we only test that they can be assembled.
+	MOVB	0x44332211(R1), R2 // MOVB	1144201745(R1), R2
+	MOVH	0x44332211(R1), R2 // MOVH	1144201745(R1), R2
+	MOVW	0x44332211(R1), R2 // MOVW	1144201745(R1), R2
+	MOVD	0x44332211(R1), R2 // MOVD	1144201745(R1), R2
+	FMOVS	0x44332211(R1), F2 // FMOVS	1144201745(R1), F2
+	FMOVD	0x44332211(R1), F2 // FMOVD	1144201745(R1), F2
+	MOVB	R1, 0x44332211(R2) // MOVB	R1, 1144201745(R2)
+	MOVH	R1, 0x44332211(R2) // MOVH	R1, 1144201745(R2)
+	MOVW	R1, 0x44332211(R2) // MOVW	R1, 1144201745(R2)
+	MOVD	R1, 0x44332211(R2) // MOVD	R1, 1144201745(R2)
+	FMOVS	F1, 0x44332211(R2) // FMOVS	F1, 1144201745(R2)
+	FMOVD	F1, 0x44332211(R2) // FMOVD	F1, 1144201745(R2)
+
 //
 // MOVK
 //
@@ -118,7 +190,9 @@ TEXT	foo(SB), 7, $-8
 //	}
 	CMP	$3, R2
 	CMP	R1, R2
-
+	CMP	R1->11, R2
+	CMP	R1>>22, R2
+	CMP	R1<<33, R2
 //
 // CBZ
 //
@@ -136,7 +210,7 @@ again:
 //	{
 //		outcode($1, &$2, NREG, &$4);
 //	}
-	CSET	GT, R1
+	CSET	GT, R1	// e1d79f9a
 //
 // CSEL/CSINC/CSNEG/CSINV
 //
@@ -144,16 +218,18 @@ again:
 //	{
 //		outgcode($1, &$2, $6.reg, &$4, &$8);
 //	}
-	CSEL	LT, R1, R2, ZR
-	CSINC	GT, R1, ZR, R3
-	CSNEG	MI, R1, R2, R3
-	CSINV	CS, R1, R2, R3 // CSINV HS, R1, R2, R3
+	CSEL	LT, R1, R2, ZR	// 3fb0829a
+	CSINC	GT, R1, ZR, R3	// 23c49f9a
+	CSNEG	MI, R1, R2, R3	// 234482da
+	CSINV	CS, R1, R2, R3	// CSINV HS, R1, R2, R3 // 232082da
 
 //		LTYPES cond ',' reg ',' reg
 //	{
 //		outcode($1, &$2, $4.reg, &$6);
 //	}
-	CSEL	LT, R1, R2
+	CINC	EQ, R4, R9	// 8914849a
+	CINV	PL, R11, R22	// 76418bda
+	CNEG	LS, R13, R7	// a7858dda
 //
 // CCMN
 //
@@ -161,7 +237,7 @@ again:
 //	{
 //		outgcode($1, &$2, $6.reg, &$4, &$8);
 //	}
-	CCMN	MI, ZR, R1, $4
+	CCMN	MI, ZR, R1, $4	// e44341ba
 
 //
 // FADDD
@@ -197,7 +273,7 @@ again:
 //	{
 //		outgcode($1, &$2, $6.reg, &$4, &$8);
 //	}
-//	FCCMP	LT, F1, F2, $1
+	FCCMPS	LT, F1, F2, $1	// 41b4211e
 
 //
 // FMULA
@@ -257,6 +333,8 @@ again:
 	B	foo(SB) // JMP foo(SB)
 	BL	foo(SB) // CALL foo(SB)
 	BEQ	2(PC)
+	TBZ	$1, R1, 2(PC)
+	TBNZ	$2, R2, 2(PC)
 	JMP	foo(SB)
 	CALL	foo(SB)
 
diff --git a/src/cmd/asm/internal/asm/testdata/armerror.s b/src/cmd/asm/internal/asm/testdata/armerror.s
new file mode 100644
index 0000000..b3a8da7
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/armerror.s
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go 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
+	MULS.S	R1, R2, R3, R4     // ERROR "invalid .S suffix"
+	ADD.P	R1, R2, R3         // ERROR "invalid .P suffix"
+	SUB.W	R2, R3             // ERROR "invalid .W suffix"
+	BL	4(R4)              // ERROR "non-zero offset"
+	ADDF	F0, R1, F2         // ERROR "illegal combination"
+	SWI	(R0)               // ERROR "illegal combination"
+	NEGF	F0, F1, F2         // ERROR "illegal combination"
+	NEGD	F0, F1, F2         // ERROR "illegal combination"
+	ABSF	F0, F1, F2         // ERROR "illegal combination"
+	ABSD	F0, F1, F2         // ERROR "illegal combination"
+	SQRTF	F0, F1, F2         // ERROR "illegal combination"
+	SQRTD	F0, F1, F2         // ERROR "illegal combination"
+	MOVF	F0, F1, F2         // ERROR "illegal combination"
+	MOVD	F0, F1, F2         // ERROR "illegal combination"
+	MOVDF	F0, F1, F2         // ERROR "illegal combination"
+	MOVFD	F0, F1, F2         // ERROR "illegal combination"
+	MOVM.IA	4(R1), [R0-R4]     // ERROR "offset must be zero"
+	MOVM.DA	4(R1), [R0-R4]     // ERROR "offset must be zero"
+	MOVM.IB	4(R1), [R0-R4]     // ERROR "offset must be zero"
+	MOVM.DB	4(R1), [R0-R4]     // ERROR "offset must be zero"
+
+	END
diff --git a/src/cmd/asm/internal/asm/testdata/armv6.s b/src/cmd/asm/internal/asm/testdata/armv6.s
new file mode 100644
index 0000000..7e38ca0
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/armv6.s
@@ -0,0 +1,47 @@
+// Copyright 2017 The Go 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	foo(SB), DUPOK|NOSPLIT, $0
+
+	ADDF	F0, F1, F2    // 002a31ee
+	ADDD.EQ	F3, F4, F5    // 035b340e
+	ADDF.NE	F0, F2        // 002a321e
+	ADDD	F3, F5        // 035b35ee
+	SUBF	F0, F1, F2    // 402a31ee
+	SUBD.EQ	F3, F4, F5    // 435b340e
+	SUBF.NE	F0, F2        // 402a321e
+	SUBD	F3, F5        // 435b35ee
+	MULF	F0, F1, F2    // 002a21ee
+	MULD.EQ	F3, F4, F5    // 035b240e
+	MULF.NE	F0, F2        // 002a221e
+	MULD	F3, F5        // 035b25ee
+	DIVF	F0, F1, F2    // 002a81ee
+	DIVD.EQ	F3, F4, F5    // 035b840e
+	DIVF.NE	F0, F2        // 002a821e
+	DIVD	F3, F5        // 035b85ee
+	NEGF	F0, F1        // 401ab1ee
+	NEGD	F4, F5        // 445bb1ee
+	ABSF	F0, F1        // c01ab0ee
+	ABSD	F4, F5        // c45bb0ee
+	SQRTF	F0, F1        // c01ab1ee
+	SQRTD	F4, F5        // c45bb1ee
+	MOVFD	F0, F1        // c01ab7ee
+	MOVDF	F4, F5        // c45bb7ee
+
+	LDREX	(R8), R9      // 9f9f98e1
+	LDREXD	(R11), R12    // 9fcfbbe1
+	STREX	R3, (R4), R5  // STREX  (R4), R3, R5 // 935f84e1
+	STREXD	R8, (R9), g   // STREXD (R9), R8, g  // 98afa9e1
+
+	CMPF    F8, F9        // c89ab4ee10faf1ee
+	CMPD.CS F4, F5        // c45bb42e10faf12e
+	CMPF.VS F7            // c07ab56e10faf16e
+	CMPD    F6            // c06bb5ee10faf1ee
+
+	MOVW	R4, F8        // 104b08ee
+	MOVW	F4, R8        // 108b14ee
+
+	END
diff --git a/src/cmd/asm/internal/asm/testdata/mips.s b/src/cmd/asm/internal/asm/testdata/mips.s
index f48d918..0f0226d 100644
--- a/src/cmd/asm/internal/asm/testdata/mips.s
+++ b/src/cmd/asm/internal/asm/testdata/mips.s
@@ -5,7 +5,9 @@
 // This input was created by taking the mips64 testcase and modified
 // by hand.
 
-TEXT foo(SB),7,$0
+#include "../../../../../runtime/textflag.h"
+
+TEXT foo(SB),DUPOK|NOSPLIT,$0
 
 	//inst:
 	//
diff --git a/src/cmd/asm/internal/asm/testdata/mips64.s b/src/cmd/asm/internal/asm/testdata/mips64.s
index e217d35..50a2694 100644
--- a/src/cmd/asm/internal/asm/testdata/mips64.s
+++ b/src/cmd/asm/internal/asm/testdata/mips64.s
@@ -5,7 +5,9 @@
 // This input was created by taking the ppc64 testcase and modified
 // by hand.
 
-TEXT foo(SB),7,$0
+#include "../../../../../runtime/textflag.h"
+
+TEXT foo(SB),DUPOK|NOSPLIT,$0
 
 //inst:
 //
@@ -37,6 +39,9 @@ TEXT foo(SB),7,$0
 	MOVV	16(R1), R2
 	MOVV	(R1), R2
 
+	LL	(R1), R2 // c0220000
+	LLV	(R1), R2 // d0220000
+
 //	LMOVB rreg ',' rreg
 //	{
 //		outcode(int($1), &$2, 0, &$4);
@@ -96,6 +101,9 @@ TEXT foo(SB),7,$0
 	MOVV	R1, 16(R2)
 	MOVV	R1, (R2)
 
+	SC	R1, (R2) // e0410000
+	SCV	R1, (R2) // f0410000
+
 //	LMOVB rreg ',' addr
 //	{
 //		outcode(int($1), &$2, 0, &$4);
@@ -236,11 +244,11 @@ TEXT foo(SB),7,$0
 label0:
 	JMP	1(PC)
 	BEQ	R1, 2(PC)
-	JMP	label0+0 // JMP 64
+	JMP	label0+0 // JMP 68
 	BEQ	R1, 2(PC)
 	JAL	1(PC) // CALL 1(PC)
 	BEQ	R1, 2(PC)
-	JAL	label0+0 // CALL 64
+	JAL	label0+0 // CALL 68
 
 //	LBRA addr
 //	{
@@ -264,7 +272,7 @@ label0:
 //	}
 label1:
 	BEQ	R1, 1(PC)
-	BEQ	R1, label1 // BEQ R1, 79
+	BEQ	R1, label1 // BEQ R1, 83
 
 //	LBRA rreg ',' sreg ',' rel
 //	{
@@ -272,7 +280,7 @@ label1:
 //	}
 label2:
 	BEQ	R1, R2, 1(PC)
-	BEQ	R1, R2, label2 // BEQ R1, R2, 81
+	BEQ	R1, R2, label2 // BEQ R1, R2, 85
 
 //
 // other integer conditional branch
@@ -283,7 +291,7 @@ label2:
 //	}
 label3:
 	BLTZ	R1, 1(PC)
-	BLTZ	R1, label3 // BLTZ R1, 83
+	BLTZ	R1, label3 // BLTZ R1, 87
 
 //
 // floating point conditional branch
@@ -291,7 +299,7 @@ label3:
 //	LBRA rel
 label4:
 	BFPT	1(PC)
-	BFPT	label4 // BFPT 85
+	BFPT	label4 // BFPT 89
 
 
 //
@@ -325,7 +333,9 @@ label4:
 //
 // WORD
 //
-	WORD	$1
+	WORD	$1	// 00000001
+	NOOP		// 00000000
+	SYNC		// 0000000f
 
 //
 // NOP
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index d1ebaa2..30fb0f2 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -6,7 +6,9 @@
 // the old assembler's (9a's) grammar and hand-writing complete
 // instructions for each rule, to guarantee we cover the same space.
 
-TEXT foo(SB),7,$0
+#include "../../../../../runtime/textflag.h"
+
+TEXT foo(SB),DUPOK|NOSPLIT,$0
 
 //inst:
 //
@@ -22,7 +24,7 @@ TEXT foo(SB),7,$0
 //	{
 //		outcode(int($1), &$2, 0, &$4);
 //	}
-	MOVW	foo<>+3(SB), R2
+	MOVW	foo<>+4(SB), R2
 	MOVW	16(R1), R2
 
 //	LMOVW regaddr ',' rreg
@@ -59,7 +61,7 @@ TEXT foo(SB),7,$0
 //	{
 //		outcode(int($1), &$2, 0, &$4);
 //	}
-	FMOVD	foo<>+3(SB), F2
+	FMOVD	foo<>+4(SB), F2
 	FMOVD	16(R1), F2
 
 //	LFMOV regaddr ',' freg
@@ -84,7 +86,7 @@ TEXT foo(SB),7,$0
 //	{
 //		outcode(int($1), &$2, 0, &$4);
 //	}
-	FMOVD	F2, foo<>+3(SB)
+	FMOVD	F2, foo<>+4(SB)
 	FMOVD	F2, 16(R1)
 
 //	LFMOV freg ',' regaddr
@@ -130,7 +132,7 @@ TEXT foo(SB),7,$0
 //	{
 //		outcode(int($1), &$2, 0, &$4);
 //	}
-	FMOVD	F1, foo<>+3(SB)
+	FMOVD	F1, foo<>+4(SB)
 	FMOVD	F1, 16(R2)
 
 //	LMOVW freg ',' regaddr
@@ -540,6 +542,14 @@ label1:
 //	}
 //	FCMPU	F1, F2, CR0
 
+//	FTDIV FRA, FRB, BF produces
+//	ftdiv BF, FRA, FRB
+	FTDIV F1,F2,$7
+
+//	FTSQRT	FRB, BF produces
+//	ftsqrt	BF, FRB
+	FTSQRT	F2,$7
+
 //
 // CMP
 //
@@ -567,6 +577,19 @@ label1:
 //	}
 	CMP	R1, $4, CR0 // CMP R1, CR0, $4
 
+//	CMPB  RS,RB,RA produces
+//	cmpb  RA,RS,RB
+	CMPB  R2,R2,R1
+
+//
+// rotate extended mnemonics map onto other shift instructions
+//
+
+	ROTL	$12,R2,R3
+	ROTL	R2,R3,R4
+	ROTLW	$9,R2,R3
+	ROTLW	R2,R3,R4
+
 //
 // rotate and mask
 //
@@ -603,6 +626,17 @@ label1:
 
 	RLDIMI  $7, R2, $52, R7
 
+// opcodes for right and left shifts, const and reg shift counts
+
+	SLD	$4, R3, R4
+	SLD	R2, R3, R4
+	SLW	$4, R3, R4
+	SLW	R2, R3, R4
+	SRD	$8, R3, R4
+	SRD	R2, R3, R4
+	SRW	$8, R3, R4
+	SRW	R2, R3, R4
+
 //
 // load/store multiple
 //
@@ -673,6 +707,13 @@ label1:
 	DCBF	(R1)
 	DCBF	(R1+R2) // DCBF	(R1)(R2*1)
 
+//	Population count, X-form
+//	<MNEMONIC> RS,RA produces
+//	<mnemonic> RA,RS
+	POPCNTD	R1,R2
+	POPCNTW	R1,R2
+	POPCNTB R1,R2
+
 //	VMX instructions
 
 //	Described as:
@@ -703,14 +744,14 @@ label1:
 //	Vector AND, VX-form
 //	<MNEMONIC> VRA,VRB,VRT produces
 //	<mnemonic> VRT,VRA,VRB
-	VANDL	V10, V9, V8
+	VAND	V10, V9, V8
 	VANDC	V15, V14, V13
 	VNAND	V19, V18, V17
 
 //	Vector OR, VX-form
 //	<MNEMONIC> VRA,VRB,VRT produces
 //	<mnemonic> VRT,VRA,VRB
-	VORL	V26, V25, V24
+	VOR	V26, V25, V24
 	VORC	V23, V22, V21
 	VNOR	V20, V19, V18
 	VXOR	V17, V16, V15
@@ -739,6 +780,14 @@ label1:
 	VADDEUQM V4, V3, V2, V1
 	VADDECUQ V4, V3, V2, V1
 
+//	Vector polynomial multiply-sum, VX-form
+//	<MNEMONIC>  VRA,VRB,VRT produces
+//	<mnemonic>  VRT,VRA,VRB
+	VPMSUMB	V2, V3, V1
+	VPMSUMH	V2, V3, V1
+	VPMSUMW	V2, V3, V1
+	VPMSUMD	V2, V3, V1
+
 //	Vector SUB, VX-form
 //	<MNEMONIC> VRA,VRB,VRT produces
 //	<mnemonic> VRT,VRA,VRB
diff --git a/src/cmd/asm/internal/asm/testdata/s390x.s b/src/cmd/asm/internal/asm/testdata/s390x.s
index badedc1..6cc129c 100644
--- a/src/cmd/asm/internal/asm/testdata/s390x.s
+++ b/src/cmd/asm/internal/asm/testdata/s390x.s
@@ -2,7 +2,9 @@
 // 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
+#include "../../../../../runtime/textflag.h"
+
+TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-0
 	MOVD	R1, R2                // b9040021
 	MOVW	R3, R4                // b9140043
 	MOVH	R5, R6                // b9070065
@@ -45,10 +47,16 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
 	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
+	MOVD	$32767, n-8(SP)       // e548f0107fff
+	MOVD	$-1, -524288(R1)      // e3a010008071e548a000ffff
+	MOVW	$32767, n-8(SP)       // e54cf0107fff
+	MOVW	$-32768, 4096(R2)     // e3a020000171e54ca0008000
+	MOVH	$512, n-8(SP)         // e544f0100200
+	MOVH	$-512, 524288(R3)     // c0a10008000041aa3000e544a000fe00
 	MOVB	$-1, n-8(SP)          // 92fff010
+	MOVB	$255, 4096(R4)        // ebff40000152
+	MOVB	$-128, -524288(R5)    // eb8050008052
+	MOVB	$1, -524289(R6)       // c0a1fff7ffff41aa60009201a000
 
 	ADD	R1, R2                // b9e81022
 	ADD	R1, R2, R3            // b9e81032
@@ -184,13 +192,13 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
 	LAO	R1, R2, (R3)          // eb21300000f6
 	LAOG	R4, R5, (R6)          // eb54600000e6
 
-	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
+	XC	$8, (R15), n-8(SP)       // d707f010f000
+	NC	$8, (R15), n-8(SP)       // d407f010f000
+	OC	$8, (R15), n-8(SP)       // d607f010f000
+	MVC	$8, (R15), n-8(SP)       // d207f010f000
+	CLC	$8, (R15), n-8(SP)       // d507f000f010
+	XC	$256, -8(R15), -8(R15)   // b90400afc2a8fffffff8d7ffa000a000
+	MVC	$256, 8192(R1), 8192(R2) // b90400a2c2a800002000b90400b1c2b800002000d2ffa000b000
 
 	CMP	R1, R2                 // b9200012
 	CMP	R3, $32767             // a73f7fff
@@ -242,6 +250,9 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
 	CMPUBGT	R9, $256, 0(PC)        // ec920000007d
 	CMPUBGE	R2, $0, 0(PC)          // ec2a0000007d
 
+	LGDR	F1, R12                // b3cd00c1
+	LDGR	R2, F15                // b3c100f2
+
 	CEFBRA	R0, F15                // b39400f0
 	CDFBRA	R1, F14                // b39500e1
 	CEGBRA	R2, F13                // b3a400d2
@@ -281,68 +292,75 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
 	FSQRT	F5, F15                // b31500f5
 	FIEBR	$0, F0, F1             // b3570010
 	FIDBR	$7, F2, F3             // b35f7032
+	FMADD	F1, F1, F1             // b31e1011
+	FMADDS	F1, F2, F3             // b30e3012
+	FMSUB	F4, F5, F5             // b31f5045
+	FMSUBS	F6, F6, F7             // b30f7066
 
-	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
-	VFMADB	V16, V8, V9, V10        // VFMADB  V8, V9, V16, V10        // e7a08300948f
-	WFMADB	V17, V18, V19, V20      // WFMADB  V18, V19, V17, V20      // e74123083f8f
-	VFMSDB	V2, V25, V24, V31       // VFMSDB  V25, V24, V2, V31       // e7f293008b8e
-	WFMSDB	V31, V2, V3, V4         // WFMSDB  V2, V3, V31, V4         // e74f2308348e
-	VPERM	V31, V0, V2, V3         // VPERM   V0, V2, V31, V3         // e73f0000248c
-	VPDI	$1, V2, V31, V1         // VPDI    V2, V31, $1, V1         // e712f0001284
-	VLEG	$1, (R3), V1            // VLEG    (R3), $1, V1            // e71030001002
-	VLEF	$2, (R0), V31           // VLEF    (R0), $2, V31           // e7f000002803
-	VLEH	$3, (R12), V16          // VLEH    (R12), $3, V16          // e700c0003801
-	VLEB	$15, 4095(R9), V15      // VLEB    4095(R9), $15, V15      // e7f09ffff000
-	VSTEG	$1, V30, (R1)(R2*1)     // VSTEG   V30, $1, (R1)(R2*1)     // e7e21000180a
-	VSTEF	$3, V2, (R9)            // VSTEF   V2, $3, (R9)            // e7209000300b
-	VSTEH	$7, V31, (R2)           // VSTEH   V31, $7, (R2)           // e7f020007809
-	VSTEB	$15, V29, 4094(R12)     // VSTEB   V29, $15, 4094(R12)     // e7d0cffef808
+	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
+	VREPIH	$-1, V16                // e700ffff1845
+	VREPIF	$-32768, V0             // e70080002045
+	VREPIG	$32767, V31             // e7f07fff3845
+	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
+	VGEG	$1, 8(R15)(V30*1), V31  // e7fef0081c12
+	VSCEG	$1, V31, 16(R15)(V30*1) // e7fef0101c1a
+	VGEF	$0, 2048(R15)(V1*1), V2 // e721f8000013
+	VSCEF	$0, V2, 4095(R15)(V1*1) // e721ffff001b
+	VLL	R0, (R15), V1           // e710f0000037
+	VSTL	R0, V16, (R15)          // e700f000083f
+	VGMH	$8, $16, V12            // e7c008101046
+	VLEIB	$15, $255, V0           // e70000fff040
+	VLEIH	$7, $-32768, V15        // e7f080007041
+	VLEIF	$2, $-43, V16           // e700ffd52843
+	VLEIG	$1, $32767, V31         // e7f07fff1842
+	VSLDB	$3, V1, V16, V18        // e72100030a77
+	VERIMB	$2, V31, V1, V2         // e72f10020472
+	VSEL	V1, V2, V3, V4          // e7412000308d
+	VGFMAH	V21, V31, V24, V0       // e705f10087bc
+	VFMADB	V16, V8, V9, V10        // e7a08300948f
+	WFMADB	V17, V18, V19, V20      // e74123083f8f
+	VFMSDB	V2, V25, V24, V31       // e7f293008b8e
+	WFMSDB	V31, V2, V3, V4         // e74f2308348e
+	VPERM	V31, V0, V2, V3         // e73f0000248c
+	VPDI	$1, V2, V31, V1         // e712f0001284
+	VLEG	$1, (R3), V1            // e71030001002
+	VLEF	$2, (R0), V31           // e7f000002803
+	VLEH	$3, (R12), V16          // e700c0003801
+	VLEB	$15, 4095(R9), V15      // e7f09ffff000
+	VSTEG	$1, V30, (R1)(R2*1)     // e7e21000180a
+	VSTEF	$3, V2, (R9)            // e7209000300b
+	VSTEH	$7, V31, (R2)           // e7f020007809
+	VSTEB	$15, V29, 4094(R12)     // e7d0cffef808
 
 	RET
 
-TEXT main·init(SB),7,$0 // TEXT main.init(SB), 7, $0
+TEXT main·init(SB),DUPOK|NOSPLIT,$0 // TEXT main.init(SB), DUPOK|NOSPLIT, $0
 	RET
 
-TEXT main·main(SB),7,$0 // TEXT main.main(SB), 7, $0
+TEXT main·main(SB),DUPOK|NOSPLIT,$0 // TEXT main.main(SB), DUPOK|NOSPLIT, $0
 	BL      main·foo(SB)    // CALL main.foo(SB)
 	RET
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index 4855daa..ddfcddf 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -13,6 +13,7 @@ import (
 	"text/scanner"
 
 	"cmd/asm/internal/flags"
+	"cmd/internal/src"
 )
 
 // Input is the main input: a stack of readers and some macro definitions.
@@ -290,7 +291,7 @@ func lookup(args []string, arg string) int {
 func (in *Input) invokeMacro(macro *Macro) {
 	// If the macro has no arguments, just substitute the text.
 	if macro.args == nil {
-		in.Push(NewSlice(in.File(), in.Line(), macro.tokens))
+		in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
 		return
 	}
 	tok := in.Stack.Next()
@@ -300,7 +301,7 @@ func (in *Input) invokeMacro(macro *Macro) {
 		in.peekToken = tok
 		in.peekText = in.text
 		in.peek = true
-		in.Push(NewSlice(in.File(), in.Line(), []Token{Make(macroName, macro.name)}))
+		in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
 		return
 	}
 	actuals := in.argsFor(macro)
@@ -317,7 +318,7 @@ func (in *Input) invokeMacro(macro *Macro) {
 		}
 		tokens = append(tokens, substitution...)
 	}
-	in.Push(NewSlice(in.File(), in.Line(), tokens))
+	in.Push(NewSlice(in.Base(), in.Line(), tokens))
 }
 
 // argsFor returns a map from formal name to actual value for this argumented macro invocation.
@@ -452,8 +453,8 @@ func (in *Input) line() {
 	if tok != '\n' {
 		in.Error("unexpected token at end of #line: ", tok)
 	}
-	linkCtxt.LineHist.Update(histLine, file, line)
-	in.Stack.SetPos(line, file)
+	pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
+	in.Stack.SetBase(src.NewLinePragmaBase(pos, file, uint(line)))
 }
 
 // #undef processing
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
index 8133905..f1f7da7 100644
--- a/src/cmd/asm/internal/lex/lex.go
+++ b/src/cmd/asm/internal/lex/lex.go
@@ -12,7 +12,7 @@ import (
 	"strings"
 	"text/scanner"
 
-	"cmd/internal/obj"
+	"cmd/internal/src"
 )
 
 // A ScanToken represents an input item. It is a simple wrapping of rune, as
@@ -57,23 +57,8 @@ func (t ScanToken) String() string {
 	}
 }
 
-var (
-	// It might be nice if these weren't global.
-	linkCtxt *obj.Link     // The link context for all instructions.
-	histLine int       = 1 // The cumulative count of lines processed.
-)
-
-// HistLine reports the cumulative source line number of the token,
-// for use in the Prog structure for the linker. (It's always handling the
-// instruction from the current lex line.)
-// It returns int32 because that's what type ../asm prefers.
-func HistLine() int32 {
-	return int32(histLine)
-}
-
 // NewLexer returns a lexer for the named file and the given link context.
-func NewLexer(name string, ctxt *obj.Link) TokenReader {
-	linkCtxt = ctxt
+func NewLexer(name string) TokenReader {
 	input := NewInput(name)
 	fd, err := os.Open(name)
 	if err != nil {
@@ -83,16 +68,11 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
 	return input
 }
 
-// InitHist sets the line count to 1, for reproducible testing.
-func InitHist() {
-	histLine = 1
-}
-
 // The other files in this directory each contain an implementation of TokenReader.
 
 // A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what
 // the text of the most recently returned token is, and where it was found.
-// The underlying scanner elides all spaces except newline, so the input looks like a  stream of
+// The underlying scanner elides all spaces except newline, so the input looks like a stream of
 // Tokens; original spacing is lost but we don't need it.
 type TokenReader interface {
 	// Next returns the next token.
@@ -102,12 +82,14 @@ type TokenReader interface {
 	Text() string
 	// File reports the source file name of the token.
 	File() string
+	// Base reports the position base of the token.
+	Base() *src.PosBase
+	// SetBase sets the position base.
+	SetBase(*src.PosBase)
 	// Line reports the source line number of the token.
 	Line() int
 	// Col reports the source column number of the token.
 	Col() int
-	// SetPos sets the file and line number.
-	SetPos(line int, file string)
 	// Close does any teardown required.
 	Close()
 }
diff --git a/src/cmd/asm/internal/lex/slice.go b/src/cmd/asm/internal/lex/slice.go
index b0d5429..8ee0c70 100644
--- a/src/cmd/asm/internal/lex/slice.go
+++ b/src/cmd/asm/internal/lex/slice.go
@@ -4,22 +4,26 @@
 
 package lex
 
-import "text/scanner"
+import (
+	"text/scanner"
+
+	"cmd/internal/src"
+)
 
 // A Slice reads from a slice of Tokens.
 type Slice struct {
-	tokens   []Token
-	fileName string
-	line     int
-	pos      int
+	tokens []Token
+	base   *src.PosBase
+	line   int
+	pos    int
 }
 
-func NewSlice(fileName string, line int, tokens []Token) *Slice {
+func NewSlice(base *src.PosBase, line int, tokens []Token) *Slice {
 	return &Slice{
-		tokens:   tokens,
-		fileName: fileName,
-		line:     line,
-		pos:      -1, // Next will advance to zero.
+		tokens: tokens,
+		base:   base,
+		line:   line,
+		pos:    -1, // Next will advance to zero.
 	}
 }
 
@@ -36,7 +40,17 @@ func (s *Slice) Text() string {
 }
 
 func (s *Slice) File() string {
-	return s.fileName
+	return s.base.Filename()
+}
+
+func (s *Slice) Base() *src.PosBase {
+	return s.base
+}
+
+func (s *Slice) SetBase(base *src.PosBase) {
+	// Cannot happen because we only have slices of already-scanned text,
+	// but be prepared.
+	s.base = base
 }
 
 func (s *Slice) Line() int {
@@ -56,12 +70,5 @@ func (s *Slice) Col() int {
 	return s.pos
 }
 
-func (s *Slice) SetPos(line int, file string) {
-	// Cannot happen because we only have slices of already-scanned
-	// text, but be prepared.
-	s.line = line
-	s.fileName = file
-}
-
 func (s *Slice) Close() {
 }
diff --git a/src/cmd/asm/internal/lex/stack.go b/src/cmd/asm/internal/lex/stack.go
index 72d7f8a..929e528 100644
--- a/src/cmd/asm/internal/lex/stack.go
+++ b/src/cmd/asm/internal/lex/stack.go
@@ -4,7 +4,11 @@
 
 package lex
 
-import "text/scanner"
+import (
+	"text/scanner"
+
+	"cmd/internal/src"
+)
 
 // A Stack is a stack of TokenReaders. As the top TokenReader hits EOF,
 // it resumes reading the next one down.
@@ -34,7 +38,15 @@ func (s *Stack) Text() string {
 }
 
 func (s *Stack) File() string {
-	return s.tr[len(s.tr)-1].File()
+	return s.Base().Filename()
+}
+
+func (s *Stack) Base() *src.PosBase {
+	return s.tr[len(s.tr)-1].Base()
+}
+
+func (s *Stack) SetBase(base *src.PosBase) {
+	s.tr[len(s.tr)-1].SetBase(base)
 }
 
 func (s *Stack) Line() int {
@@ -45,9 +57,5 @@ func (s *Stack) Col() int {
 	return s.tr[len(s.tr)-1].Col()
 }
 
-func (s *Stack) SetPos(line int, file string) {
-	s.tr[len(s.tr)-1].SetPos(line, file)
-}
-
 func (s *Stack) Close() { // Unused.
 }
diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go
index 6a4d954..aef9ea8 100644
--- a/src/cmd/asm/internal/lex/tokenizer.go
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -10,17 +10,21 @@ import (
 	"strings"
 	"text/scanner"
 	"unicode"
+
+	"cmd/asm/internal/flags"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 )
 
 // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
 // for our purposes and made a TokenReader. It forms the lowest level,
 // turning text from readers into tokens.
 type Tokenizer struct {
-	tok      ScanToken
-	s        *scanner.Scanner
-	line     int
-	fileName string
-	file     *os.File // If non-nil, file descriptor to close.
+	tok  ScanToken
+	s    *scanner.Scanner
+	base *src.PosBase
+	line int
+	file *os.File // If non-nil, file descriptor to close.
 }
 
 func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
@@ -37,14 +41,11 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
 		scanner.ScanComments
 	s.Position.Filename = name
 	s.IsIdentRune = isIdentRune
-	if file != nil {
-		linkCtxt.LineHist.Push(histLine, name)
-	}
 	return &Tokenizer{
-		s:        &s,
-		line:     1,
-		fileName: name,
-		file:     file,
+		s:    &s,
+		base: src.NewFileBase(name, objabi.AbsFile(objabi.WorkingDir(), name, *flags.TrimPath)),
+		line: 1,
+		file: file,
 	}
 }
 
@@ -80,7 +81,15 @@ func (t *Tokenizer) Text() string {
 }
 
 func (t *Tokenizer) File() string {
-	return t.fileName
+	return t.base.Filename()
+}
+
+func (t *Tokenizer) Base() *src.PosBase {
+	return t.base
+}
+
+func (t *Tokenizer) SetBase(base *src.PosBase) {
+	t.base = base
 }
 
 func (t *Tokenizer) Line() int {
@@ -91,11 +100,6 @@ func (t *Tokenizer) Col() int {
 	return t.s.Pos().Column
 }
 
-func (t *Tokenizer) SetPos(line int, file string) {
-	t.line = line
-	t.fileName = file
-}
-
 func (t *Tokenizer) Next() ScanToken {
 	s := t.s
 	for {
@@ -105,15 +109,11 @@ func (t *Tokenizer) Next() ScanToken {
 		}
 		length := strings.Count(s.TokenText(), "\n")
 		t.line += length
-		histLine += length
 		// TODO: If we ever have //go: comments in assembly, will need to keep them here.
 		// For now, just discard all comments.
 	}
 	switch t.tok {
 	case '\n':
-		if t.file != nil {
-			histLine++
-		}
 		t.line++
 	case '-':
 		if s.Peek() == '>' {
@@ -146,7 +146,5 @@ func (t *Tokenizer) Next() ScanToken {
 func (t *Tokenizer) Close() {
 	if t.file != nil {
 		t.file.Close()
-		// It's an open file, so pop the line history.
-		linkCtxt.LineHist.Pop(histLine)
 	}
 }
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 13e5302..2e79916 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -18,13 +18,14 @@ import (
 
 	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 )
 
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("asm: ")
 
-	GOARCH := obj.GOARCH
+	GOARCH := objabi.GOARCH
 
 	architecture := arch.Set(GOARCH)
 	if architecture == nil {
@@ -35,14 +36,15 @@ func main() {
 
 	ctxt := obj.Linknew(architecture.LinkArch)
 	if *flags.PrintOut {
-		ctxt.Debugasm = 1
+		ctxt.Debugasm = true
 	}
-	ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
 	ctxt.Flag_dynlink = *flags.Dynlink
 	ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
 	ctxt.Bso = bufio.NewWriter(os.Stdout)
 	defer ctxt.Bso.Flush()
 
+	architecture.Init(ctxt)
+
 	// Create object file, write header.
 	out, err := os.Create(*flags.OutputFile)
 	if err != nil {
@@ -51,28 +53,29 @@ func main() {
 	defer bio.MustClose(out)
 	buf := bufio.NewWriter(bio.MustWriter(out))
 
-	fmt.Fprintf(buf, "go object %s %s %s\n", obj.GOOS, obj.GOARCH, obj.Version)
+	fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
 	fmt.Fprintf(buf, "!\n")
 
 	var ok, diag bool
 	var failedFile string
 	for _, f := range flag.Args() {
-		lexer := lex.NewLexer(f, ctxt)
+		lexer := lex.NewLexer(f)
 		parser := asm.NewParser(ctxt, architecture, lexer)
 		ctxt.DiagFunc = func(format string, args ...interface{}) {
 			diag = true
 			log.Printf(format, args...)
 		}
-		pList := obj.Linknewplist(ctxt)
+		pList := new(obj.Plist)
 		pList.Firstpc, ok = parser.Parse()
 		if !ok {
 			failedFile = f
 			break
 		}
+		// reports errors to parser.Errorf
+		obj.Flushplist(ctxt, pList, nil)
 	}
 	if ok {
-		// reports errors to parser.Errorf
-		obj.Writeobjdirect(ctxt, buf)
+		obj.WriteObjFile(ctxt, buf)
 	}
 	if !ok || diag {
 		if failedFile != "" {
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 8ce8241..7122a9d 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -17,8 +17,8 @@ import (
 	"strings"
 )
 
-func parse(name string, flags parser.Mode) *ast.File {
-	ast1, err := parser.ParseFile(fset, name, nil, flags)
+func parse(name string, src []byte, flags parser.Mode) *ast.File {
+	ast1, err := parser.ParseFile(fset, name, src, flags)
 	if err != nil {
 		if list, ok := err.(scanner.ErrorList); ok {
 			// If err is a scanner.ErrorList, its String will print just
@@ -39,12 +39,12 @@ func sourceLine(n ast.Node) int {
 	return fset.Position(n.Pos()).Line
 }
 
-// ReadGo populates f with information learned from reading the
-// Go source file with the given file name. It gathers the C preamble
+// ParseGo populates f with information learned from the Go source code
+// which was read from the named file. 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.
-func (f *File) ReadGo(name string) {
+func (f *File) ParseGo(name string, src []byte) {
 	// Create absolute path for file, so that it will be used in error
 	// messages and recorded in debug line number information.
 	// This matches the rest of the toolchain. See golang.org/issue/5122.
@@ -58,8 +58,8 @@ func (f *File) ReadGo(name string) {
 	// so we use ast1 to look for the doc comments on import "C"
 	// and on exported functions, and we use ast2 for translating
 	// and reprinting.
-	ast1 := parse(name, parser.ParseComments)
-	ast2 := parse(name, 0)
+	ast1 := parse(name, src, parser.ParseComments)
+	ast2 := parse(name, src, 0)
 
 	f.Package = ast1.Name.Name
 	f.Name = make(map[string]*Name)
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 85441e6..b238882 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -14,27 +14,27 @@ as C.stdout, or functions such as C.putchar.
 
 If the import of "C" is immediately preceded by a comment, that
 comment, called the preamble, is used as a header when compiling
-the C parts of the package.  For example:
+the C parts of the package. For example:
 
 	// #include <stdio.h>
 	// #include <errno.h>
 	import "C"
 
 The preamble may contain any C code, including function and variable
-declarations and definitions.  These may then be referred to from Go
-code as though they were defined in the package "C".  All names
+declarations and definitions. These may then be referred to from Go
+code as though they were defined in the package "C". All names
 declared in the preamble may be used, even if they start with a
-lower-case letter.  Exception: static variables in the preamble may
+lower-case letter. Exception: static variables in the preamble may
 not be referenced from Go code; static functions are permitted.
 
-See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples.  See
+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, 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
+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).
 For example:
@@ -57,16 +57,16 @@ The default pkg-config tool may be changed by setting the PKG_CONFIG environment
 
 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
+these directives. Package-specific flags should be set using the
 directives, not the environment variables, so that builds work in
 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
+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 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
+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.
 
@@ -84,27 +84,27 @@ Will be expanded to:
 
 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 .f, .F, .for or .f90 files will be
+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 .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++
+the C and C++ files will be recompiled. The default C and C++
 compilers may be changed by the CC and CXX environment variables,
 respectively; those environment variables may include command line
 options.
 
 The cgo tool is enabled by default for native builds on systems where
-it is expected to work.  It is disabled by default when
-cross-compiling.  You can control this by setting the CGO_ENABLED
+it is expected to work. It is disabled by default when
+cross-compiling. You can control this by setting the CGO_ENABLED
 environment variable when running the go tool: set it to 1 to enable
-the use of cgo, and to 0 to disable it.  The go tool will set the
+the use of cgo, and to 0 to disable it. The go tool will set the
 build constraint "cgo" if cgo is enabled.
 
 When cross-compiling, you must specify a C cross-compiler for cgo to
-use.  You can do this by setting the CC_FOR_TARGET environment
+use. You can do this by setting the CC_FOR_TARGET environment
 variable when building the toolchain using make.bash, or by setting
-the CC environment variable any time you run the go tool.  The
+the CC environment variable any time you run the go tool. The
 CXX_FOR_TARGET and CXX environment variables work in a similar way for
 C++ code.
 
@@ -138,7 +138,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 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
+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.
 
@@ -150,7 +150,7 @@ is different from the same C type used in another.
 Any C function (even void functions) may be called in a multiple
 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:
+function returns void). For example:
 
 	n, err = C.sqrt(-1)
 	_, err := C.voidFunc()
@@ -187,11 +187,11 @@ received from Go. For example:
 In C, a function argument written as a fixed size array
 actually requires a pointer to the first element of the array.
 C compilers are aware of this calling convention and adjust
-the call accordingly, but Go cannot.  In Go, you must pass
+the call accordingly, but Go cannot. In Go, you must pass
 the pointer to the first element explicitly: C.f(&C.x[0]).
 
 A few special functions convert between Go and C types
-by making copies of the data.  In pseudo-Go definitions:
+by making copies of the data. In pseudo-Go definitions:
 
 	// Go string to C string
 	// The C string is allocated in the C heap using malloc.
@@ -253,50 +253,50 @@ must be placed in preambles in other files, or in C source files.
 Passing pointers
 
 Go is a garbage collected language, and the garbage collector needs to
-know the location of every pointer to Go memory.  Because of this,
+know the location of every pointer to Go memory. Because of this,
 there are restrictions on passing pointers between Go and C.
 
 In this section the term Go pointer means a pointer to memory
 allocated by Go (such as by using the & operator or calling the
 predefined new function) and the term C pointer means a pointer to
-memory allocated by C (such as by a call to C.malloc).  Whether a
+memory allocated by C (such as by a call to C.malloc). Whether a
 pointer is a Go pointer or a C pointer is a dynamic property
 determined by how the memory was allocated; it has nothing to do with
 the type of the pointer.
 
 Go code may pass a Go pointer to C provided the Go memory to which it
-points does not contain any Go pointers.  The C code must preserve
+points does not contain any Go pointers. The C code must preserve
 this property: it must not store any Go pointers in Go memory, even
-temporarily.  When passing a pointer to a field in a struct, the Go
+temporarily. When passing a pointer to a field in a struct, the Go
 memory in question is the memory occupied by the field, not the entire
-struct.  When passing a pointer to an element in an array or slice,
+struct. When passing a pointer to an element in an array or slice,
 the Go memory in question is the entire array or the entire backing
 array of the slice.
 
 C code may not keep a copy of a Go pointer after the call returns.
 
-A Go function called by C code may not return a Go pointer.  A Go
+A Go function called by C code may not return a Go pointer. A Go
 function called by C code may take C pointers as arguments, and it may
 store non-pointer or C pointer data through those pointers, but it may
-not store a Go pointer in memory pointed to by a C pointer.  A Go
+not store a Go pointer in memory pointed to by a C pointer. A Go
 function called by C code may take a Go pointer as an argument, but it
 must preserve the property that the Go memory to which it points does
 not contain any Go pointers.
 
-Go code may not store a Go pointer in C memory.  C code may store Go
+Go code may not store a Go pointer in C memory. C code may store Go
 pointers in C memory, subject to the rule above: it must stop storing
 the Go pointer when the C function returns.
 
-These rules are checked dynamically at runtime.  The checking is
+These rules are checked dynamically at runtime. The checking is
 controlled by the cgocheck setting of the GODEBUG environment
-variable.  The default setting is GODEBUG=cgocheck=1, which implements
-reasonably cheap dynamic checks.  These checks may be disabled
-entirely using GODEBUG=cgocheck=0.  Complete checking of pointer
+variable. The default setting is GODEBUG=cgocheck=1, which implements
+reasonably cheap dynamic checks. These checks may be disabled
+entirely using GODEBUG=cgocheck=0. Complete checking of pointer
 handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
 
 It is possible to defeat this enforcement by using the unsafe package,
 and of course there is nothing stopping the C code from doing anything
-it likes.  However, programs that break these rules are likely to fail
+it likes. However, programs that break these rules are likely to fail
 in unexpected and unpredictable ways.
 
 Using cgo directly
@@ -499,7 +499,7 @@ Here is a _cgo_gotypes.go containing definitions for needed C types:
 	type _Ctype_void [0]byte
 
 The _cgo_gotypes.go file also contains the definitions of the
-functions.  They all have similar bodies that invoke runtime·cgocall
+functions. They all have similar bodies that invoke runtime·cgocall
 to make a switch from the Go runtime world to the system C (GCC-based)
 world.
 
@@ -835,7 +835,7 @@ to avoid conflicts), write the go.o file to that directory, and invoke
 the host linker. The default value for the host linker is $CC, split
 into fields, or else "gcc". The specific host linker command line can
 be overridden using command line flags: cmd/link -extld=clang
--extldflags='-ggdb -O3'.  If any package in a build includes a .cc or
+-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
 other file compiled by the C++ compiler, the go tool will use the
 -extld option to set the host linker to the C++ compiler.
 
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 5ea2d94..766d87d 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -20,6 +20,7 @@ import (
 	"go/ast"
 	"go/parser"
 	"go/token"
+	"math"
 	"os"
 	"strconv"
 	"strings"
@@ -241,26 +242,26 @@ func (p *Package) guessKinds(f *File) []*Name {
 		// If we've already found this name as a #define
 		// and we can translate it as a constant value, do so.
 		if n.Define != "" {
-			isConst := false
-			if _, err := strconv.Atoi(n.Define); err == nil {
-				isConst = true
-			} else if n.Define[0] == '"' || n.Define[0] == '\'' {
-				if _, err := parser.ParseExpr(n.Define); err == nil {
-					isConst = true
-				}
-			}
-			if isConst {
-				n.Kind = "const"
+			if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
+				n.Kind = "iconst"
 				// Turn decimal into hex, just for consistency
 				// 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)
-				if err == nil {
-					n.Const = fmt.Sprintf("%#x", i)
-				} else {
+				n.Const = fmt.Sprintf("%#x", i)
+			} else if n.Define[0] == '\'' {
+				if _, err := parser.ParseExpr(n.Define); err == nil {
+					n.Kind = "iconst"
 					n.Const = n.Define
 				}
+			} else if n.Define[0] == '"' {
+				if _, err := parser.ParseExpr(n.Define); err == nil {
+					n.Kind = "sconst"
+					n.Const = n.Define
+				}
+			}
+
+			if n.IsConst() {
 				continue
 			}
 
@@ -269,11 +270,10 @@ func (p *Package) guessKinds(f *File) []*Name {
 			}
 		}
 
-		needType = append(needType, n)
-
 		// If this is a struct, union, or enum type name, no need to guess the kind.
 		if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
 			n.Kind = "type"
+			needType = append(needType, n)
 			continue
 		}
 
@@ -299,14 +299,24 @@ func (p *Package) guessKinds(f *File) []*Name {
 	//	void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
 	//	#line xxx "not-type"
 	//	void __cgo_f_xxx_2(void) { name *__cgo_undefined__; }
-	//	#line xxx "not-const"
+	//	#line xxx "not-int-const"
 	//	void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; }
+	//	#line xxx "not-num-const"
+	//	void __cgo_f_xxx_4(void) { static const double x = (name); }
+	//	#line xxx "not-str-lit"
+	//	void __cgo_f_xxx_5(void) { static const char x[] = (name); }
+	//	#line xxx "not-signed-int-const"
+	//	#if 0 < -(name)
+	//	#line xxx "not-signed-int-const"
+	//	#error found unsigned int
+	//	#endif
 	//
 	// If we see an error at not-declared:xxx, the corresponding name is not declared.
 	// If we see an error at not-type:xxx, the corresponding name is a type.
-	// If we see an error at not-const:xxx, the corresponding name is not an integer constant.
-	// If we see no errors, we assume the name is an expression but not a constant
-	// (so a variable or a function).
+	// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
+	// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
+	// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
+	// If we see an error at not-signed-int-const:xxx, the corresponding name is not a signed integer literal.
 	//
 	// The specific input forms are chosen so that they are valid C syntax regardless of
 	// whether name denotes a type or an expression.
@@ -320,11 +330,24 @@ func (p *Package) guessKinds(f *File) []*Name {
 			"void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+
 			"#line %d \"not-type\"\n"+
 			"void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+
-			"#line %d \"not-const\"\n"+
-			"void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n",
+			"#line %d \"not-int-const\"\n"+
+			"void __cgo_f_%d_3(void) { enum { __cgo_undefined__ = (%s)*1 }; }\n"+
+			"#line %d \"not-num-const\"\n"+
+			"void __cgo_f_%d_4(void) { static const double x = (%s); }\n"+
+			"#line %d \"not-str-lit\"\n"+
+			"void __cgo_f_%d_5(void) { static const char s[] = (%s); }\n"+
+			"#line %d \"not-signed-int-const\"\n"+
+			"#if 0 < (%s)\n"+
+			"#line %d \"not-signed-int-const\"\n"+
+			"#error found unsigned int\n"+
+			"#endif\n",
+			i+1, i+1, n.C,
+			i+1, i+1, n.C,
 			i+1, i+1, n.C,
 			i+1, i+1, n.C,
-			i+1, i+1, n.C)
+			i+1, i+1, n.C,
+			i+1, n.C, i+1,
+		)
 	}
 	fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
 		"int __cgo__1 = __cgo__2;\n")
@@ -338,13 +361,23 @@ func (p *Package) guessKinds(f *File) []*Name {
 	sniff := make([]int, len(names))
 	const (
 		notType = 1 << iota
-		notConst
+		notIntConst
+		notNumConst
+		notStrLiteral
 		notDeclared
+		notSignedIntConst
 	)
+	sawUnmatchedErrors := false
 	for _, line := range strings.Split(stderr, "\n") {
-		if !strings.Contains(line, ": error:") {
-			// we only care about errors.
-			// we tried to turn off warnings on the command line, but one never knows.
+		// Ignore warnings and random comments, with one
+		// exception: newer GCC versions will sometimes emit
+		// an error on a macro #define with a note referring
+		// to where the expansion occurs. We care about where
+		// the expansion occurs, so in that case treat the note
+		// as an error.
+		isError := strings.Contains(line, ": error:")
+		isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors
+		if !isError && !isErrorNote {
 			continue
 		}
 
@@ -362,6 +395,9 @@ func (p *Package) guessKinds(f *File) []*Name {
 		i, _ := strconv.Atoi(line[c1+1 : c2])
 		i--
 		if i < 0 || i >= len(names) {
+			if isError {
+				sawUnmatchedErrors = true
+			}
 			continue
 		}
 
@@ -377,9 +413,22 @@ func (p *Package) guessKinds(f *File) []*Name {
 			sniff[i] |= notDeclared
 		case "not-type":
 			sniff[i] |= notType
-		case "not-const":
-			sniff[i] |= notConst
+		case "not-int-const":
+			sniff[i] |= notIntConst
+		case "not-num-const":
+			sniff[i] |= notNumConst
+		case "not-str-lit":
+			sniff[i] |= notStrLiteral
+		case "not-signed-int-const":
+			sniff[i] |= notSignedIntConst
+		default:
+			if isError {
+				sawUnmatchedErrors = true
+			}
+			continue
 		}
+
+		sawUnmatchedErrors = false
 	}
 
 	if !completed {
@@ -387,14 +436,29 @@ func (p *Package) guessKinds(f *File) []*Name {
 	}
 
 	for i, n := range names {
-		switch sniff[i] {
+		switch sniff[i] &^ notSignedIntConst {
 		default:
-			error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
-		case notType:
-			n.Kind = "const"
-		case notConst:
+			var tpos token.Pos
+			for _, ref := range f.Ref {
+				if ref.Name == n {
+					tpos = ref.Pos()
+					break
+				}
+			}
+			error_(tpos, "could not determine kind of name for C.%s", fixGo(n.Go))
+		case notStrLiteral | notType:
+			if sniff[i]&notSignedIntConst != 0 {
+				n.Kind = "uconst"
+			} else {
+				n.Kind = "iconst"
+			}
+		case notIntConst | notStrLiteral | notType:
+			n.Kind = "fconst"
+		case notIntConst | notNumConst | notType:
+			n.Kind = "sconst"
+		case notIntConst | notNumConst | notStrLiteral:
 			n.Kind = "type"
-		case notConst | notType:
+		case notIntConst | notNumConst | notStrLiteral | notType:
 			n.Kind = "not-type"
 		}
 	}
@@ -432,18 +496,16 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 	b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
 	for i, n := range names {
 		fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
-		if n.Kind == "const" {
+		if n.Kind == "iconst" || n.Kind == "uconst" {
 			fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
 		}
 	}
 
-	// Apple's LLVM-based gcc does not include the enumeration
-	// 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")
+	// We create a data block initialized with the values,
+	// so we can read them out of the object file.
+	fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
 	for _, n := range names {
-		if n.Kind == "const" {
+		if n.Kind == "iconst" || n.Kind == "uconst" {
 			fmt.Fprintf(&b, "\t%s,\n", n.C)
 		} else {
 			fmt.Fprintf(&b, "\t0,\n")
@@ -457,15 +519,30 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 	fmt.Fprintf(&b, "\t1\n")
 	fmt.Fprintf(&b, "};\n")
 
-	d, bo, debugData := p.gccDebug(b.Bytes())
-	enumVal := make([]int64, len(debugData)/8)
-	for i := range enumVal {
-		enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
+	// do the same work for floats.
+	fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n")
+	for _, n := range names {
+		if n.Kind == "fconst" {
+			fmt.Fprintf(&b, "\t%s,\n", n.C)
+		} else {
+			fmt.Fprintf(&b, "\t0,\n")
+		}
+	}
+	fmt.Fprintf(&b, "\t1\n")
+	fmt.Fprintf(&b, "};\n")
+
+	// do the same work for strings.
+	for i, n := range names {
+		if n.Kind == "sconst" {
+			fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C)
+			fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C)
+		}
 	}
 
+	d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names))
+
 	// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
 	types := make([]dwarf.Type, len(names))
-	enums := make([]dwarf.Offset, len(names))
 	nameToIndex := make(map[*Name]int)
 	for i, n := range names {
 		nameToIndex[n] = i
@@ -484,26 +561,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 			break
 		}
 		switch e.Tag {
-		case dwarf.TagEnumerationType:
-			offset := e.Offset
-			for {
-				e, err := r.Next()
-				if err != nil {
-					fatalf("reading DWARF entry: %s", err)
-				}
-				if e.Tag == 0 {
-					break
-				}
-				if e.Tag == dwarf.TagEnumerator {
-					entryName := e.Val(dwarf.AttrName).(string)
-					if strings.HasPrefix(entryName, "__cgo_enum__") {
-						n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
-						if 0 <= n && n < len(names) {
-							enums[n] = offset
-						}
-					}
-				}
-			}
 		case dwarf.TagVariable:
 			name, _ := e.Val(dwarf.AttrName).(string)
 			typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
@@ -530,15 +587,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 			if err != nil {
 				fatalf("malformed __cgo__ name: %s", name)
 			}
-			if enums[i] != 0 {
-				t, err := d.Type(enums[i])
-				if err != nil {
-					fatalf("loading DWARF type: %s", err)
-				}
-				types[i] = t
-			} else {
-				types[i] = t.Type
-			}
+			types[i] = t.Type
 		}
 		if e.Tag != dwarf.TagCompileUnit {
 			r.SkipChildren()
@@ -562,17 +611,23 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 			n.FuncType = conv.FuncType(f, pos)
 		} else {
 			n.Type = conv.Type(types[i], pos)
-			if enums[i] != 0 && n.Type.EnumValues != nil {
-				k := fmt.Sprintf("__cgo_enum__%d", i)
-				n.Kind = "const"
-				n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k])
-				// Remove injected enum to ensure the value will deep-compare
-				// equally in future loads of the same constant.
-				delete(n.Type.EnumValues, k)
-			}
-			// Prefer debug data over DWARF debug output, if we have it.
-			if n.Kind == "const" && i < len(enumVal) {
-				n.Const = fmt.Sprintf("%#x", enumVal[i])
+			switch n.Kind {
+			case "iconst":
+				if i < len(ints) {
+					n.Const = fmt.Sprintf("%#x", ints[i])
+				}
+			case "uconst":
+				if i < len(ints) {
+					n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
+				}
+			case "fconst":
+				if i < len(floats) {
+					n.Const = fmt.Sprintf("%f", floats[i])
+				}
+			case "sconst":
+				if i < len(strs) {
+					n.Const = fmt.Sprintf("%q", strs[i])
+				}
 			}
 		}
 		conv.FinishType(pos)
@@ -1051,7 +1106,7 @@ func (p *Package) rewriteRef(f *File) {
 	// 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 == "" {
+		if r.Name.IsConst() && r.Name.Const == "" {
 			error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
 		}
 		var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
@@ -1091,6 +1146,10 @@ func (p *Package) rewriteRef(f *File) {
 			}
 		case "expr":
 			if r.Name.Kind == "func" {
+				if builtinDefs[r.Name.C] != "" {
+					error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
+				}
+
 				// Function is being used in an expression, to e.g. pass around a C function pointer.
 				// Create a new Name for this Ref which causes the variable to be declared in Go land.
 				fpName := "fp_" + r.Name.Go
@@ -1259,12 +1318,55 @@ func (p *Package) gccCmd() []string {
 
 // gccDebug runs gcc -gdwarf-2 over the C program stdin and
 // returns the corresponding DWARF data and, if present, debug data block.
-func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
+func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
 	runGcc(stdin, p.gccCmd())
 
-	isDebugData := func(s string) bool {
+	isDebugInts := func(s string) bool {
+		// Some systems use leading _ to denote non-assembly symbols.
+		return s == "__cgodebug_ints" || s == "___cgodebug_ints"
+	}
+	isDebugFloats := func(s string) bool {
+		// Some systems use leading _ to denote non-assembly symbols.
+		return s == "__cgodebug_floats" || s == "___cgodebug_floats"
+	}
+	indexOfDebugStr := func(s string) int {
+		// Some systems use leading _ to denote non-assembly symbols.
+		if strings.HasPrefix(s, "___") {
+			s = s[1:]
+		}
+		if strings.HasPrefix(s, "__cgodebug_str__") {
+			if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
+				return n
+			}
+		}
+		return -1
+	}
+	indexOfDebugStrlen := func(s string) int {
 		// Some systems use leading _ to denote non-assembly symbols.
-		return s == "__cgodebug_data" || s == "___cgodebug_data"
+		if strings.HasPrefix(s, "___") {
+			s = s[1:]
+		}
+		if strings.HasPrefix(s, "__cgodebug_strlen__") {
+			if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
+				return n
+			}
+		}
+		return -1
+	}
+
+	strs = make([]string, nnames)
+
+	strdata := make(map[int]string, nnames)
+	strlens := make(map[int]int, nnames)
+
+	buildStrings := func() {
+		for n, strlen := range strlens {
+			data := strdata[n]
+			if len(data) <= strlen {
+				fatalf("invalid string literal")
+			}
+			strs[n] = string(data[:strlen])
+		}
 	}
 
 	if f, err := macho.Open(gccTmp()); err == nil {
@@ -1273,24 +1375,76 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
 		if err != nil {
 			fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
 		}
-		var data []byte
+		bo := f.ByteOrder
 		if f.Symtab != nil {
 			for i := range f.Symtab.Syms {
 				s := &f.Symtab.Syms[i]
-				if isDebugData(s.Name) {
+				switch {
+				case isDebugInts(s.Name):
 					// 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 {
 							if sdat, err := sect.Data(); err == nil {
-								data = sdat[s.Value-sect.Addr:]
+								data := sdat[s.Value-sect.Addr:]
+								ints = make([]int64, len(data)/8)
+								for i := range ints {
+									ints[i] = int64(bo.Uint64(data[i*8:]))
+								}
 							}
 						}
 					}
+				case isDebugFloats(s.Name):
+					// 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 {
+							if sdat, err := sect.Data(); err == nil {
+								data := sdat[s.Value-sect.Addr:]
+								floats = make([]float64, len(data)/8)
+								for i := range floats {
+									floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+								}
+							}
+						}
+					}
+				default:
+					if n := indexOfDebugStr(s.Name); n != -1 {
+						// 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 {
+								if sdat, err := sect.Data(); err == nil {
+									data := sdat[s.Value-sect.Addr:]
+									strdata[n] = string(data)
+								}
+							}
+						}
+						break
+					}
+					if n := indexOfDebugStrlen(s.Name); n != -1 {
+						// 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 {
+								if sdat, err := sect.Data(); err == nil {
+									data := sdat[s.Value-sect.Addr:]
+									strlen := bo.Uint64(data[:8])
+									if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+										fatalf("string literal too big")
+									}
+									strlens[n] = int(strlen)
+								}
+							}
+						}
+						break
+					}
 				}
 			}
+
+			buildStrings()
 		}
-		return d, f.ByteOrder, data
+		return d, ints, floats, strs
 	}
 
 	if f, err := elf.Open(gccTmp()); err == nil {
@@ -1299,25 +1453,77 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
 		if err != nil {
 			fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
 		}
-		var data []byte
+		bo := f.ByteOrder
 		symtab, err := f.Symbols()
 		if err == nil {
 			for i := range symtab {
 				s := &symtab[i]
-				if isDebugData(s.Name) {
+				switch {
+				case isDebugInts(s.Name):
+					// 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 {
+							if sdat, err := sect.Data(); err == nil {
+								data := sdat[s.Value-sect.Addr:]
+								ints = make([]int64, len(data)/8)
+								for i := range ints {
+									ints[i] = int64(bo.Uint64(data[i*8:]))
+								}
+							}
+						}
+					}
+				case isDebugFloats(s.Name):
 					// 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 {
 							if sdat, err := sect.Data(); err == nil {
-								data = sdat[s.Value-sect.Addr:]
+								data := sdat[s.Value-sect.Addr:]
+								floats = make([]float64, len(data)/8)
+								for i := range floats {
+									floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+								}
+							}
+						}
+					}
+				default:
+					if n := indexOfDebugStr(s.Name); n != -1 {
+						// 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 {
+								if sdat, err := sect.Data(); err == nil {
+									data := sdat[s.Value-sect.Addr:]
+									strdata[n] = string(data)
+								}
 							}
 						}
+						break
+					}
+					if n := indexOfDebugStrlen(s.Name); n != -1 {
+						// 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 {
+								if sdat, err := sect.Data(); err == nil {
+									data := sdat[s.Value-sect.Addr:]
+									strlen := bo.Uint64(data[:8])
+									if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+										fatalf("string literal too big")
+									}
+									strlens[n] = int(strlen)
+								}
+							}
+						}
+						break
 					}
 				}
 			}
+
+			buildStrings()
 		}
-		return d, f.ByteOrder, data
+		return d, ints, floats, strs
 	}
 
 	if f, err := pe.Open(gccTmp()); err == nil {
@@ -1326,20 +1532,70 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
 		if err != nil {
 			fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
 		}
-		var data []byte
+		bo := binary.LittleEndian
 		for _, s := range f.Symbols {
-			if isDebugData(s.Name) {
+			switch {
+			case isDebugInts(s.Name):
 				if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
 					sect := f.Sections[i]
 					if s.Value < sect.Size {
 						if sdat, err := sect.Data(); err == nil {
-							data = sdat[s.Value:]
+							data := sdat[s.Value:]
+							ints = make([]int64, len(data)/8)
+							for i := range ints {
+								ints[i] = int64(bo.Uint64(data[i*8:]))
+							}
+						}
+					}
+				}
+			case isDebugFloats(s.Name):
+				if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+					sect := f.Sections[i]
+					if s.Value < sect.Size {
+						if sdat, err := sect.Data(); err == nil {
+							data := sdat[s.Value:]
+							floats = make([]float64, len(data)/8)
+							for i := range floats {
+								floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+							}
 						}
 					}
 				}
+			default:
+				if n := indexOfDebugStr(s.Name); n != -1 {
+					if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+						sect := f.Sections[i]
+						if s.Value < sect.Size {
+							if sdat, err := sect.Data(); err == nil {
+								data := sdat[s.Value:]
+								strdata[n] = string(data)
+							}
+						}
+					}
+					break
+				}
+				if n := indexOfDebugStrlen(s.Name); n != -1 {
+					if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+						sect := f.Sections[i]
+						if s.Value < sect.Size {
+							if sdat, err := sect.Data(); err == nil {
+								data := sdat[s.Value:]
+								strlen := bo.Uint64(data[:8])
+								if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+									fatalf("string literal too big")
+								}
+								strlens[n] = int(strlen)
+							}
+						}
+					}
+					break
+				}
 			}
 		}
-		return d, binary.LittleEndian, data
+
+		buildStrings()
+
+		return d, ints, floats, strs
 	}
 
 	fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index df27983..3dc3d14 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -17,7 +17,7 @@ import (
 	"go/ast"
 	"go/printer"
 	"go/token"
-	"io"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -88,7 +88,7 @@ type Name struct {
 	Mangle   string // name used in generated Go
 	C        string // name used in C
 	Define   string // #define expansion
-	Kind     string // "const", "type", "var", "fpvar", "func", "not-type"
+	Kind     string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type"
 	Type     *Type  // the type of xxx
 	FuncType *FuncType
 	AddError bool
@@ -100,6 +100,11 @@ func (n *Name) IsVar() bool {
 	return n.Kind == "var" || n.Kind == "fpvar"
 }
 
+// IsConst reports whether Kind is either "iconst", "uconst", "fconst" or "sconst"
+func (n *Name) IsConst() bool {
+	return strings.HasSuffix(n.Kind, "const")
+}
+
 // A ExpFunc is an exported function, callable from C.
 // Such functions are identified in the Go input file
 // by doc comments containing the line //export ExpName
@@ -260,30 +265,28 @@ func main() {
 	// concern is other cgo wrappers for the same functions.
 	// Use the beginning of the md5 of the input to disambiguate.
 	h := md5.New()
-	for _, input := range goFiles {
+	fs := make([]*File, len(goFiles))
+	for i, input := range goFiles {
 		if *srcDir != "" {
 			input = filepath.Join(*srcDir, input)
 		}
-		f, err := os.Open(input)
+
+		b, err := ioutil.ReadFile(input)
 		if err != nil {
 			fatalf("%s", err)
 		}
-		io.Copy(h, f)
-		f.Close()
-	}
-	cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
-
-	fs := make([]*File, len(goFiles))
-	for i, input := range goFiles {
-		if *srcDir != "" {
-			input = filepath.Join(*srcDir, input)
+		if _, err = h.Write(b); err != nil {
+			fatalf("%s", err)
 		}
+
 		f := new(File)
-		f.ReadGo(input)
+		f.ParseGo(input, b)
 		f.DiscardCgoDirectives()
 		fs[i] = f
 	}
 
+	cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
+
 	if *objDir == "" {
 		// make sure that _obj directory exists, so that we can write
 		// all the output files there.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index e82ec37..9ab6bd8 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -185,7 +185,7 @@ func (p *Package) writeDefs() {
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
 		if n.Const != "" {
-			fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
+			fmt.Fprintf(fgo2, "const %s = %s\n", n.Mangle, n.Const)
 		}
 	}
 	fmt.Fprintf(fgo2, "\n")
@@ -1298,7 +1298,7 @@ const gccProlog = `
 */
 #define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
 
-// Check at compile time that the sizes we use match our expectations.
+/* Check at compile time that the sizes we use match our expectations. */
 #define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
 
 __cgo_size_assert(char, 1)
@@ -1323,6 +1323,27 @@ const noTsanProlog = `
 `
 
 // This must match the TSAN code in runtime/cgo/libcgo.h.
+// This is used when the code is built with the C/C++ Thread SANitizer,
+// which is not the same as the Go race detector.
+// __tsan_acquire tells TSAN that we are acquiring a lock on a variable,
+// in this case _cgo_sync. __tsan_release releases the lock.
+// (There is no actual lock, we are just telling TSAN that there is.)
+//
+// When we call from Go to C we call _cgo_tsan_acquire.
+// When the C function returns we call _cgo_tsan_release.
+// Similarly, when C calls back into Go we call _cgo_tsan_release
+// and then call _cgo_tsan_acquire when we return to C.
+// These calls tell TSAN that there is a serialization point at the C call.
+//
+// This is necessary because TSAN, which is a C/C++ tool, can not see
+// the synchronization in the Go code. Without these calls, when
+// multiple goroutines call into C code, TSAN does not understand
+// that the calls are properly synchronized on the Go side.
+//
+// To be clear, if the calls are not properly synchronized on the Go side,
+// we will be hiding races. But when using TSAN on mixed Go C/C++ code
+// it is more important to avoid false positives, which reduce confidence
+// in the tool, than to avoid false negatives.
 const yesTsanProlog = `
 #line 1 "cgo-tsan-prolog"
 #define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go
index 2e77f70..83bd36c 100644
--- a/src/cmd/compile/doc.go
+++ b/src/cmd/compile/doc.go
@@ -44,6 +44,8 @@ Flags:
 		Print compiler version and exit.
 	-asmhdr file
 		Write assembly header to file.
+	-blockprofile file
+		Write block profile for the compilation to file.
 	-complete
 		Assume package has no non-Go components.
 	-cpuprofile file
@@ -75,6 +77,8 @@ Flags:
 		Set runtime.MemProfileRate for the compilation to rate.
 	-msan
 		Insert calls to C/C++ memory sanitizer.
+	-mutexprofile file
+		Write mutex profile for the compilation to file.
 	-nolocalimports
 		Disallow local (relative) imports.
 	-o file
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index 1a64808..59de326 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -557,8 +557,6 @@ func init() {
 // To print out a new table, run: go test -run Formats -v.
 var knownFormats = map[string]string{
 	"*bytes.Buffer %s":                                "",
-	"*cmd/compile/internal/gc.Field %p":               "",
-	"*cmd/compile/internal/gc.Field %v":               "",
 	"*cmd/compile/internal/gc.Mpflt %v":               "",
 	"*cmd/compile/internal/gc.Mpint %v":               "",
 	"*cmd/compile/internal/gc.Node %#v":               "",
@@ -570,20 +568,6 @@ var knownFormats = map[string]string{
 	"*cmd/compile/internal/gc.Node %j":                "",
 	"*cmd/compile/internal/gc.Node %p":                "",
 	"*cmd/compile/internal/gc.Node %v":                "",
-	"*cmd/compile/internal/gc.Sym %+v":                "",
-	"*cmd/compile/internal/gc.Sym %-v":                "",
-	"*cmd/compile/internal/gc.Sym %0S":                "",
-	"*cmd/compile/internal/gc.Sym %S":                 "",
-	"*cmd/compile/internal/gc.Sym %p":                 "",
-	"*cmd/compile/internal/gc.Sym %v":                 "",
-	"*cmd/compile/internal/gc.Type %#v":               "",
-	"*cmd/compile/internal/gc.Type %+v":               "",
-	"*cmd/compile/internal/gc.Type %-S":               "",
-	"*cmd/compile/internal/gc.Type %0S":               "",
-	"*cmd/compile/internal/gc.Type %L":                "",
-	"*cmd/compile/internal/gc.Type %S":                "",
-	"*cmd/compile/internal/gc.Type %p":                "",
-	"*cmd/compile/internal/gc.Type %v":                "",
 	"*cmd/compile/internal/ssa.Block %s":              "",
 	"*cmd/compile/internal/ssa.Block %v":              "",
 	"*cmd/compile/internal/ssa.Func %s":               "",
@@ -591,11 +575,28 @@ var knownFormats = map[string]string{
 	"*cmd/compile/internal/ssa.Value %s":              "",
 	"*cmd/compile/internal/ssa.Value %v":              "",
 	"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
+	"*cmd/compile/internal/types.Field %p":            "",
+	"*cmd/compile/internal/types.Field %v":            "",
+	"*cmd/compile/internal/types.Sym %+v":             "",
+	"*cmd/compile/internal/types.Sym %-v":             "",
+	"*cmd/compile/internal/types.Sym %0S":             "",
+	"*cmd/compile/internal/types.Sym %S":              "",
+	"*cmd/compile/internal/types.Sym %p":              "",
+	"*cmd/compile/internal/types.Sym %v":              "",
+	"*cmd/compile/internal/types.Type %#v":            "",
+	"*cmd/compile/internal/types.Type %+v":            "",
+	"*cmd/compile/internal/types.Type %-S":            "",
+	"*cmd/compile/internal/types.Type %0S":            "",
+	"*cmd/compile/internal/types.Type %L":             "",
+	"*cmd/compile/internal/types.Type %S":             "",
+	"*cmd/compile/internal/types.Type %p":             "",
+	"*cmd/compile/internal/types.Type %s":             "",
+	"*cmd/compile/internal/types.Type %v":             "",
 	"*cmd/internal/obj.Addr %v":                       "",
-	"*cmd/internal/obj.Prog %p":                       "",
+	"*cmd/internal/obj.LSym %v":                       "",
 	"*cmd/internal/obj.Prog %s":                       "",
-	"*cmd/internal/obj.Prog %v":                       "",
 	"*math/big.Int %#x":                               "",
+	"*math/big.Int %s":                                "",
 	"[16]byte %x":                                     "",
 	"[]*cmd/compile/internal/gc.Node %v":              "",
 	"[]*cmd/compile/internal/gc.Sig %#v":              "",
@@ -606,19 +607,14 @@ var knownFormats = map[string]string{
 	"[]cmd/compile/internal/ssa.ID %v":                "",
 	"[]string %v":                                     "",
 	"bool %v":                                         "",
-	"byte %02x":                                       "",
 	"byte %08b":                                       "",
 	"byte %c":                                         "",
 	"cmd/compile/internal/arm.shift %d":               "",
 	"cmd/compile/internal/gc.Class %d":                "",
 	"cmd/compile/internal/gc.Ctype %d":                "",
 	"cmd/compile/internal/gc.Ctype %v":                "",
-	"cmd/compile/internal/gc.EType %d":                "",
-	"cmd/compile/internal/gc.EType %s":                "",
-	"cmd/compile/internal/gc.EType %v":                "",
 	"cmd/compile/internal/gc.Level %d":                "",
 	"cmd/compile/internal/gc.Level %v":                "",
-	"cmd/compile/internal/gc.Node %#v":                "",
 	"cmd/compile/internal/gc.Nodes %#v":               "",
 	"cmd/compile/internal/gc.Nodes %+v":               "",
 	"cmd/compile/internal/gc.Nodes %.v":               "",
@@ -628,6 +624,7 @@ var knownFormats = map[string]string{
 	"cmd/compile/internal/gc.Val %#v":                 "",
 	"cmd/compile/internal/gc.Val %T":                  "",
 	"cmd/compile/internal/gc.Val %v":                  "",
+	"cmd/compile/internal/gc.fmtMode %d":              "",
 	"cmd/compile/internal/gc.initKind %d":             "",
 	"cmd/compile/internal/ssa.BranchPrediction %d":    "",
 	"cmd/compile/internal/ssa.Edge %v":                "",
@@ -637,33 +634,30 @@ var knownFormats = map[string]string{
 	"cmd/compile/internal/ssa.Location %v":            "",
 	"cmd/compile/internal/ssa.Op %s":                  "",
 	"cmd/compile/internal/ssa.Op %v":                  "",
-	"cmd/compile/internal/ssa.SizeAndAlign %s":        "",
-	"cmd/compile/internal/ssa.Type %s":                "",
-	"cmd/compile/internal/ssa.Type %v":                "",
 	"cmd/compile/internal/ssa.ValAndOff %s":           "",
-	"cmd/compile/internal/ssa.markKind %d":            "",
 	"cmd/compile/internal/ssa.rbrank %d":              "",
 	"cmd/compile/internal/ssa.regMask %d":             "",
 	"cmd/compile/internal/ssa.register %d":            "",
 	"cmd/compile/internal/syntax.Expr %#v":            "",
-	"cmd/compile/internal/syntax.Expr %s":             "",
 	"cmd/compile/internal/syntax.Node %T":             "",
 	"cmd/compile/internal/syntax.Operator %d":         "",
 	"cmd/compile/internal/syntax.Operator %s":         "",
 	"cmd/compile/internal/syntax.token %d":            "",
 	"cmd/compile/internal/syntax.token %q":            "",
 	"cmd/compile/internal/syntax.token %s":            "",
-	"cmd/internal/obj.As %v":                          "",
+	"cmd/compile/internal/types.EType %d":             "",
+	"cmd/compile/internal/types.EType %s":             "",
+	"cmd/compile/internal/types.EType %v":             "",
+	"cmd/internal/src.Pos %s":                         "",
+	"cmd/internal/src.Pos %v":                         "",
 	"error %v":                                        "",
 	"float64 %.2f":                                    "",
 	"float64 %.3f":                                    "",
 	"float64 %.6g":                                    "",
 	"float64 %g":                                      "",
-	"fmt.Stringer %T":                                 "",
 	"int %-12d":                                       "",
 	"int %-6d":                                        "",
 	"int %-8o":                                        "",
-	"int %5d":                                         "",
 	"int %6d":                                         "",
 	"int %c":                                          "",
 	"int %d":                                          "",
@@ -691,6 +685,7 @@ var knownFormats = map[string]string{
 	"reflect.Type %s":  "",
 	"rune %#U":         "",
 	"rune %c":          "",
+	"string %-*s":      "",
 	"string %-16s":     "",
 	"string %.*s":      "",
 	"string %q":        "",
@@ -699,14 +694,13 @@ var knownFormats = map[string]string{
 	"time.Duration %d": "",
 	"time.Duration %v": "",
 	"uint %04x":        "",
+	"uint %5d":         "",
 	"uint %d":          "",
 	"uint16 %d":        "",
 	"uint16 %v":        "",
 	"uint16 %x":        "",
-	"uint32 %08x":      "",
 	"uint32 %d":        "",
 	"uint32 %x":        "",
-	"uint64 %016x":     "",
 	"uint64 %08x":      "",
 	"uint64 %d":        "",
 	"uint64 %x":        "",
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 6fd7f31..58c4699 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -6,26 +6,26 @@ package amd64
 
 import (
 	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
+	"cmd/internal/objabi"
 )
 
 var leaptr = x86.ALEAQ
 
-func Init() {
-	gc.Thearch.LinkArch = &x86.Linkamd64
-	if obj.GOARCH == "amd64p32" {
-		gc.Thearch.LinkArch = &x86.Linkamd64p32
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &x86.Linkamd64
+	if objabi.GOARCH == "amd64p32" {
+		arch.LinkArch = &x86.Linkamd64p32
 		leaptr = x86.ALEAL
 	}
-	gc.Thearch.REGSP = x86.REGSP
-	gc.Thearch.MAXWIDTH = 1 << 50
+	arch.REGSP = x86.REGSP
+	arch.MAXWIDTH = 1 << 50
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = ssaMarkMoves
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = ssaMarkMoves
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
index d121533..e294bce 100644
--- a/src/cmd/compile/internal/amd64/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -8,60 +8,11 @@ import (
 	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
+	"cmd/internal/objabi"
 )
 
 // no floating point in note handlers on Plan 9
-var isPlan9 = obj.GOOS == "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.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
-	ax := uint32(0)
-	x0 := uint32(0)
-
-	// 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 %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
-		}
-
-		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
-			// merge with range we already have
-			lo = n.Xoffset
-
-			continue
-		}
-
-		// zero old range
-		p = zerorange(p, int64(frame), lo, hi, &ax, &x0)
-
-		// set new range
-		hi = n.Xoffset + n.Type.Width
-
-		lo = n.Xoffset
-	}
-
-	// zero final range
-	zerorange(p, int64(frame), lo, hi, &ax, &x0)
-}
+var isPlan9 = objabi.GOOS == "plan9"
 
 // DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
 // See runtime/mkduff.go.
@@ -100,8 +51,12 @@ func dzDI(b int64) int64 {
 	return -dzClearStep * (dzBlockLen - tailSteps)
 }
 
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uint32) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.Prog {
+	const (
+		ax = 1 << iota
+		x0
+	)
+
 	if cnt == 0 {
 		return p
 	}
@@ -111,72 +66,71 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
 		if cnt%int64(gc.Widthptr) != 0 {
 			gc.Fatalf("zerorange count not a multiple of widthptr %d", cnt)
 		}
-		if *ax == 0 {
-			p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
-			*ax = 1
+		if *state&ax == 0 {
+			p = pp.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+			*state |= ax
 		}
-		p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
-		lo += int64(gc.Widthptr)
+		p = pp.Appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, off)
+		off += int64(gc.Widthptr)
 		cnt -= int64(gc.Widthptr)
 	}
 
 	if cnt == 8 {
-		if *ax == 0 {
-			p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
-			*ax = 1
+		if *state&ax == 0 {
+			p = pp.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+			*state |= ax
 		}
-		p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
+		p = pp.Appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, off)
 	} else if !isPlan9 && cnt <= int64(8*gc.Widthreg) {
-		if *x0 == 0 {
-			p = gc.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
-			*x0 = 1
+		if *state&x0 == 0 {
+			p = pp.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
+			*state |= x0
 		}
 
 		for i := int64(0); i < cnt/16; i++ {
-			p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i*16)
+			p = pp.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, off+i*16)
 		}
 
 		if cnt%16 != 0 {
-			p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+cnt-int64(16))
+			p = pp.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, off+cnt-int64(16))
 		}
 	} else if !gc.Nacl && !isPlan9 && (cnt <= int64(128*gc.Widthreg)) {
-		if *x0 == 0 {
-			p = gc.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
-			*x0 = 1
+		if *state&x0 == 0 {
+			p = pp.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
+			*state |= x0
 		}
-		p = gc.Appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0)
-		p = gc.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))
+		p = pp.Appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, off+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0)
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(cnt))
+		p.To.Sym = gc.Duffzero
 
 		if cnt%16 != 0 {
-			p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8))
+			p = pp.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8))
 		}
 	} else {
-		if *ax == 0 {
-			p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
-			*ax = 1
+		if *state&ax == 0 {
+			p = pp.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+			*state |= ax
 		}
 
-		p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
-		p = gc.Appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
-		p = gc.Appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
-		p = gc.Appendpp(p, x86.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
+		p = pp.Appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, off, obj.TYPE_REG, x86.REG_DI, 0)
+		p = pp.Appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, x86.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
 	}
 
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
 	op := x86.AMOVQ
 	if gc.Widthptr == 4 {
 		op = x86.AMOVL
 	}
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += int64(gc.Widthptr) {
-		p := gc.AddAsmAfter(op, pp)
-		pp = p
+		p := pp.Prog(op)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 0
 		p.To.Type = obj.TYPE_MEM
@@ -187,11 +141,11 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
+func ginsnop(pp *gc.Progs) {
 	// This is actually not the x86 NOP anymore,
 	// but at the point where it gets used, AX is dead
 	// so it's okay if we lose the high bits.
-	p := gc.Prog(x86.AXCHGL)
+	p := pp.Prog(x86.AXCHGL)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = x86.REG_AX
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/amd64/prog.go b/src/cmd/compile/internal/amd64/prog.go
deleted file mode 100644
index bd95f46..0000000
--- a/src/cmd/compile/internal/amd64/prog.go
+++ /dev/null
@@ -1,287 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package amd64
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/x86"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-var progtable = [x86.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// 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 & 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},
-	x86.ACQO & obj.AMask:  {Flags: gc.OK},
-	x86.ACWD & obj.AMask:  {Flags: gc.OK},
-	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.ACMPXCHGL & obj.AMask:  {Flags: gc.SizeL | LeftRdwr | RightRdwr | gc.SetCarry},
-	x86.ACMPXCHGQ & obj.AMask:  {Flags: gc.SizeQ | LeftRdwr | RightRdwr | 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},
-	x86.ADIVL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.ADIVQ & obj.AMask:      {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry},
-	x86.ADIVW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	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},
-	x86.AIDIVL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.AIDIVQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry},
-	x86.AIDIVW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	x86.AIMULB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry},
-	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.ALOCK & obj.AMask:      {Flags: gc.OK},
-	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},
-	x86.AMOVSL & obj.AMask:     {Flags: gc.OK},
-	x86.AMOVSQ & obj.AMask:     {Flags: gc.OK},
-	x86.AMOVSW & obj.AMask:     {Flags: gc.OK},
-	obj.ADUFFCOPY & obj.AMask:  {Flags: gc.OK},
-	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&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},
-	x86.AMULL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.AMULQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry},
-	x86.AMULW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	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},
-	x86.AREPN & obj.AMask:     {Flags: gc.OK},
-	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},
-	x86.ASTOSL & obj.AMask:    {Flags: gc.OK},
-	x86.ASTOSQ & obj.AMask:    {Flags: gc.OK},
-	x86.ASTOSW & obj.AMask:    {Flags: gc.OK},
-	obj.ADUFFZERO & obj.AMask: {Flags: gc.OK},
-	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.AXADDL & obj.AMask:    {Flags: gc.SizeL | LeftRdwr | RightRdwr | gc.KillCarry},
-	x86.AXADDQ & obj.AMask:    {Flags: gc.SizeQ | LeftRdwr | RightRdwr | gc.KillCarry},
-	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 proginfo(p *obj.Prog) gc.ProgInfo {
-	info := progtable[p.As&obj.AMask]
-	if info.Flags == 0 {
-		gc.Fatalf("unknown instruction %v", p)
-	}
-
-	if info.Flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
-		info.Flags |= RightRdwr
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 3c997f2..2d7727b 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -10,6 +10,7 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -38,7 +39,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	// Avoid partial register write
 	if !t.IsFloat() && t.Size() <= 2 {
 		if t.Size() == 1 {
@@ -52,7 +53,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	width := t.Size()
 	if t.IsFloat() {
 		switch width {
@@ -77,7 +78,7 @@ func storeByType(t ssa.Type) obj.As {
 }
 
 // moveByType returns the reg->reg move instruction of the given type.
-func moveByType(t ssa.Type) obj.As {
+func moveByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		// Moving the whole sse2 register is faster
 		// than moving just the correct low portion of it.
@@ -107,8 +108,8 @@ func moveByType(t ssa.Type) obj.As {
 //     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)
+func opregreg(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog {
+	p := s.Prog(op)
 	p.From.Type = obj.TYPE_REG
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = dest
@@ -147,7 +148,6 @@ func duff(size int64) (int64, int64) {
 }
 
 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
-	s.SetLineno(v.Line)
 	switch v.Op {
 	case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
 		r := v.Reg()
@@ -155,13 +155,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r2 := v.Args[1].Reg()
 		switch {
 		case r == r1:
-			p := gc.Prog(v.Op.Asm())
+			p := s.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 := s.Prog(v.Op.Asm())
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = r1
 			p.To.Type = obj.TYPE_REG
@@ -173,7 +173,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			} else {
 				asm = x86.ALEAL
 			}
-			p := gc.Prog(asm)
+			p := s.Prog(asm)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = r1
 			p.From.Scale = 1
@@ -190,6 +190,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL,
 		ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
 		ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB,
+		ssa.OpAMD64ROLQ, ssa.OpAMD64ROLL, ssa.OpAMD64ROLW, ssa.OpAMD64ROLB,
+		ssa.OpAMD64RORQ, ssa.OpAMD64RORL, ssa.OpAMD64RORW, ssa.OpAMD64RORB,
 		ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD, ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD,
 		ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD,
 		ssa.OpAMD64PXOR:
@@ -197,7 +199,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		opregreg(v.Op.Asm(), r, v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
 
 	case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU:
 		// Arg[0] (the dividend) is in AX.
@@ -207,14 +209,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Args[1].Reg()
 
 		// Zero extend dividend.
-		c := gc.Prog(x86.AXORL)
+		c := s.Prog(x86.AXORL)
 		c.From.Type = obj.TYPE_REG
 		c.From.Reg = x86.REG_DX
 		c.To.Type = obj.TYPE_REG
 		c.To.Reg = x86.REG_DX
 
 		// Issue divide.
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 
@@ -230,46 +232,46 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		var c *obj.Prog
 		switch v.Op {
 		case ssa.OpAMD64DIVQ:
-			c = gc.Prog(x86.ACMPQ)
+			c = s.Prog(x86.ACMPQ)
 		case ssa.OpAMD64DIVL:
-			c = gc.Prog(x86.ACMPL)
+			c = s.Prog(x86.ACMPL)
 		case ssa.OpAMD64DIVW:
-			c = gc.Prog(x86.ACMPW)
+			c = s.Prog(x86.ACMPW)
 		}
 		c.From.Type = obj.TYPE_REG
 		c.From.Reg = r
 		c.To.Type = obj.TYPE_CONST
 		c.To.Offset = -1
-		j1 := gc.Prog(x86.AJEQ)
+		j1 := s.Prog(x86.AJEQ)
 		j1.To.Type = obj.TYPE_BRANCH
 
 		// Sign extend dividend.
 		switch v.Op {
 		case ssa.OpAMD64DIVQ:
-			gc.Prog(x86.ACQO)
+			s.Prog(x86.ACQO)
 		case ssa.OpAMD64DIVL:
-			gc.Prog(x86.ACDQ)
+			s.Prog(x86.ACDQ)
 		case ssa.OpAMD64DIVW:
-			gc.Prog(x86.ACWD)
+			s.Prog(x86.ACWD)
 		}
 
 		// Issue divide.
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 
 		// Skip over -1 fixup code.
-		j2 := gc.Prog(obj.AJMP)
+		j2 := s.Prog(obj.AJMP)
 		j2.To.Type = obj.TYPE_BRANCH
 
 		// Issue -1 fixup code.
 		// n / -1 = -n
-		n1 := gc.Prog(x86.ANEGQ)
+		n1 := s.Prog(x86.ANEGQ)
 		n1.To.Type = obj.TYPE_REG
 		n1.To.Reg = x86.REG_AX
 
 		// n % -1 == 0
-		n2 := gc.Prog(x86.AXORL)
+		n2 := s.Prog(x86.AXORL)
 		n2.From.Type = obj.TYPE_REG
 		n2.From.Reg = x86.REG_DX
 		n2.To.Type = obj.TYPE_REG
@@ -281,22 +283,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		j1.To.Val = n1
 		j2.To.Val = s.Pc()
 
-	case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
-		ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
+	case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU:
 		// 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 := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 
 		// 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 := s.Prog(x86.AMOVB)
 			m.From.Type = obj.TYPE_REG
 			m.From.Reg = x86.REG_AH
 			m.To.Type = obj.TYPE_REG
@@ -306,14 +307,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpAMD64MULQU2:
 		// Arg[0] is already in AX as it's the only register we allow
 		// results hi in DX, lo in AX
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 
 	case ssa.OpAMD64DIVQU2:
 		// Arg[0], Arg[1] are already in Dx, AX, as they're the only registers we allow
 		// results q in AX, r in DX
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 
@@ -325,12 +326,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(x86.AADDQ)
+		p := s.Prog(x86.AADDQ)
 		p.From.Type = obj.TYPE_REG
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		p.From.Reg = v.Args[1].Reg()
-		p = gc.Prog(x86.ARCRQ)
+		p = s.Prog(x86.ARCRQ)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 1
 		p.To.Type = obj.TYPE_REG
@@ -352,7 +353,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				} else {
 					asm = x86.AINCL
 				}
-				p := gc.Prog(asm)
+				p := s.Prog(asm)
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = r
 				return
@@ -364,12 +365,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				} else {
 					asm = x86.ADECL
 				}
-				p := gc.Prog(asm)
+				p := s.Prog(asm)
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = r
 				return
 			}
-			p := gc.Prog(v.Op.Asm())
+			p := s.Prog(v.Op.Asm())
 			p.From.Type = obj.TYPE_CONST
 			p.From.Offset = v.AuxInt
 			p.To.Type = obj.TYPE_REG
@@ -382,7 +383,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		} else {
 			asm = x86.ALEAL
 		}
-		p := gc.Prog(asm)
+		p := s.Prog(asm)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = a
 		p.From.Offset = v.AuxInt
@@ -394,7 +395,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_REG
@@ -405,7 +406,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -428,14 +429,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.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 := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		p.To.Type = obj.TYPE_REG
@@ -443,7 +444,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
 		r := v.Args[0].Reg()
 		i := v.Args[1].Reg()
-		p := gc.Prog(x86.ALEAQ)
+		p := s.Prog(x86.ALEAQ)
 		switch v.Op {
 		case ssa.OpAMD64LEAQ1:
 			p.From.Scale = 1
@@ -464,34 +465,43 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64LEAQ, ssa.OpAMD64LEAL:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
-		ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
-		opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
+		ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB,
+		ssa.OpAMD64BTL, ssa.OpAMD64BTQ:
+		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
 	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(), v.Args[0].Reg(), v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg())
 	case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		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())
+	case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst,
+		ssa.OpAMD64BTLconst, ssa.OpAMD64BTQconst:
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Args[0].Reg()
 	case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		asm := v.Op.Asm()
+		// Use MOVL to move a small constant into a register
+		// when the constant is positive and fits into 32 bits.
+		if 0 <= v.AuxInt && v.AuxInt <= (1<<32-1) {
+			// The upper 32bit are zeroed automatically when using MOVL.
+			asm = x86.AMOVL
+		}
+		p := s.Prog(asm)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -503,20 +513,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		}
 	case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.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 := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -525,7 +535,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -534,7 +544,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64MOVWloadidx2:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -548,7 +558,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == x86.REG_SP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r
 		p.From.Scale = 1
@@ -557,14 +567,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -573,7 +583,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = v.Args[1].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -582,7 +592,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = v.Args[1].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.OpAMD64MOVWstoreidx2:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -596,7 +606,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == x86.REG_SP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -605,7 +615,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		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 := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -613,7 +623,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Args[0].Reg()
 		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 := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -639,37 +649,50 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
 		ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
 		ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
-		opregreg(v.Op.Asm(), v.Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
 	case ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSL2SS:
 		r := v.Reg()
 		// Break false dependency on destination register.
-		opregreg(x86.AXORPS, r, r)
-		opregreg(v.Op.Asm(), r, v.Args[0].Reg())
+		opregreg(s, x86.AXORPS, r, r)
+		opregreg(s, v.Op.Asm(), r, v.Args[0].Reg())
+	case ssa.OpAMD64ADDQmem, ssa.OpAMD64ADDLmem, ssa.OpAMD64SUBQmem, ssa.OpAMD64SUBLmem,
+		ssa.OpAMD64ANDQmem, ssa.OpAMD64ANDLmem, ssa.OpAMD64ORQmem, ssa.OpAMD64ORLmem,
+		ssa.OpAMD64XORQmem, ssa.OpAMD64XORLmem, ssa.OpAMD64ADDSDmem, ssa.OpAMD64ADDSSmem,
+		ssa.OpAMD64SUBSDmem, ssa.OpAMD64SUBSSmem, ssa.OpAMD64MULSDmem, ssa.OpAMD64MULSSmem:
+		p := s.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = v.Args[1].Reg()
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = v.Reg()
+		if v.Reg() != v.Args[0].Reg() {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
 	case ssa.OpAMD64DUFFZERO:
 		off := duffStart(v.AuxInt)
 		adj := duffAdj(v.AuxInt)
 		var p *obj.Prog
 		if adj != 0 {
-			p = gc.Prog(x86.AADDQ)
+			p = s.Prog(x86.AADDQ)
 			p.From.Type = obj.TYPE_CONST
 			p.From.Offset = adj
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = x86.REG_DI
 		}
-		p = gc.Prog(obj.ADUFFZERO)
+		p = s.Prog(obj.ADUFFZERO)
 		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = off
 	case ssa.OpAMD64MOVOconst:
 		if v.AuxInt != 0 {
 			v.Fatalf("MOVOconst can only do constant=0")
 		}
 		r := v.Reg()
-		opregreg(x86.AXORPS, r, r)
+		opregreg(s, x86.AXORPS, r, r)
 	case ssa.OpAMD64DUFFCOPY:
-		p := gc.Prog(obj.ADUFFCOPY)
+		p := s.Prog(obj.ADUFFCOPY)
 		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+		p.To.Sym = gc.Duffcopy
 		p.To.Offset = v.AuxInt
 
 	case ssa.OpCopy, ssa.OpAMD64MOVQconvert, ssa.OpAMD64MOVLconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
@@ -679,14 +702,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		x := v.Args[0].Reg()
 		y := v.Reg()
 		if x != y {
-			opregreg(moveByType(v.Type), y, x)
+			opregreg(s, moveByType(v.Type), y, x)
 		}
 	case ssa.OpLoadReg:
 		if v.Type.IsFlags() {
 			v.Fatalf("load flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(loadByType(v.Type))
+		p := s.Prog(loadByType(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -696,16 +719,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(storeByType(v.Type))
+		p := s.Prog(storeByType(v.Type))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
-	case ssa.OpInitMem:
-		// memory arg needs no code
-	case ssa.OpArg:
-		// input args need no code
 	case ssa.OpAMD64LoweredGetClosurePtr:
 		// Closure pointer is DX.
 		gc.CheckLoweredGetClosurePtr(v)
@@ -715,7 +732,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// near CanUse1InsnTLS for a detailed explanation of these instructions.
 		if x86.CanUse1InsnTLS(gc.Ctxt) {
 			// MOVQ (TLS), r
-			p := gc.Prog(x86.AMOVQ)
+			p := s.Prog(x86.AMOVQ)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = x86.REG_TLS
 			p.To.Type = obj.TYPE_REG
@@ -723,12 +740,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		} else {
 			// MOVQ TLS, r
 			// MOVQ (r)(TLS*1), r
-			p := gc.Prog(x86.AMOVQ)
+			p := s.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 := s.Prog(x86.AMOVQ)
 			q.From.Type = obj.TYPE_MEM
 			q.From.Reg = r
 			q.From.Index = x86.REG_TLS
@@ -736,55 +753,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			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 = v.Args[0].Reg()
-		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 = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.OpAMD64CALLstatic, ssa.OpAMD64CALLclosure, ssa.OpAMD64CALLinter:
+		s.Call(v)
 	case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
 		ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,
 		ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL:
@@ -792,25 +762,36 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
-	case ssa.OpAMD64BSFQ, ssa.OpAMD64BSFL:
-		p := gc.Prog(v.Op.Asm())
+	case ssa.OpAMD64BSFQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRQ, ssa.OpAMD64BSRL:
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 	case ssa.OpAMD64SQRTSD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = v.Args[0].Reg()
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = v.Reg()
+	case ssa.OpAMD64POPCNTQ, ssa.OpAMD64POPCNTL:
+		if v.Args[0].Reg() != v.Reg() {
+			// POPCNT on Intel has a false dependency on the destination register.
+			// Zero the destination to break the dependency.
+			p := s.Prog(x86.AMOVQ)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 0
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = v.Reg()
+		}
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpSP, ssa.OpSB:
-		// nothing to do
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
 		ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
 		ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
@@ -818,29 +799,29 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
 		ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
 		ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 	case ssa.OpAMD64SETNEF:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		q := gc.Prog(x86.ASETPS)
+		q := s.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, v.Reg(), x86.REG_AX)
+		opregreg(s, x86.AORL, v.Reg(), x86.REG_AX)
 
 	case ssa.OpAMD64SETEQF:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		q := gc.Prog(x86.ASETPC)
+		q := s.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, v.Reg(), x86.REG_AX)
+		opregreg(s, x86.AANDL, v.Reg(), x86.REG_AX)
 
 	case ssa.OpAMD64InvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
@@ -849,19 +830,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpAMD64AddTupleFirst32, ssa.OpAMD64AddTupleFirst64:
 		v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString())
 	case ssa.OpAMD64REPSTOSQ:
-		gc.Prog(x86.AREP)
-		gc.Prog(x86.ASTOSQ)
+		s.Prog(x86.AREP)
+		s.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:
-		gc.KeepAlive(v)
+		s.Prog(x86.AREP)
+		s.Prog(x86.AMOVSQ)
 	case ssa.OpAMD64LoweredNilCheck:
 		// Issue a load which will fault if the input is nil.
 		// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
@@ -869,17 +842,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// 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 := s.Prog(x86.ATESTB)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_AX
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		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")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 	case ssa.OpAMD64MOVLatomicload, ssa.OpAMD64MOVQatomicload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -890,7 +863,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		p.To.Type = obj.TYPE_MEM
@@ -901,8 +874,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
 		}
-		gc.Prog(x86.ALOCK)
-		p := gc.Prog(v.Op.Asm())
+		s.Prog(x86.ALOCK)
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		p.To.Type = obj.TYPE_MEM
@@ -912,24 +885,38 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Args[1].Reg() != x86.REG_AX {
 			v.Fatalf("input[1] not in AX %s", v.LongString())
 		}
-		gc.Prog(x86.ALOCK)
-		p := gc.Prog(v.Op.Asm())
+		s.Prog(x86.ALOCK)
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
-		p = gc.Prog(x86.ASETEQ)
+		p = s.Prog(x86.ASETEQ)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 	case ssa.OpAMD64ANDBlock, ssa.OpAMD64ORBlock:
-		gc.Prog(x86.ALOCK)
-		p := gc.Prog(v.Op.Asm())
+		s.Prog(x86.ALOCK)
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
+	case ssa.OpClobber:
+		p := s.Prog(x86.AMOVL)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 0xdeaddead
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = x86.REG_SP
+		gc.AddAux(&p.To, v)
+		p = s.Prog(x86.AMOVL)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 0xdeaddead
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = x86.REG_SP
+		gc.AddAux(&p.To, v)
+		p.To.Offset += 4
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -962,12 +949,10 @@ var nefJumps = [2][2]gc.FloatingEQNEJump{
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -975,34 +960,34 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in rax:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(x86.ATESTL)
+		p := s.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 = s.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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.AJMP)
+		p := s.Prog(obj.AJMP)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 
 	case ssa.BlockAMD64EQF:
-		gc.SSAGenFPJump(s, b, next, &eqfJumps)
+		s.FPJump(b, next, &eqfJumps)
 
 	case ssa.BlockAMD64NEF:
-		gc.SSAGenFPJump(s, b, next, &nefJumps)
+		s.FPJump(b, next, &nefJumps)
 
 	case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
 		ssa.BlockAMD64LT, ssa.BlockAMD64GE,
@@ -1010,40 +995,25 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		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 = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.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.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
 	}
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index 53f57cd..6df6208 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -10,16 +10,16 @@ import (
 	"cmd/internal/obj/arm"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &arm.Linkarm
-	gc.Thearch.REGSP = arm.REGSP
-	gc.Thearch.MAXWIDTH = (1 << 32) - 1
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &arm.Linkarm
+	arch.REGSP = arm.REGSP
+	arch.MAXWIDTH = (1 << 32) - 1
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go
index 1b97a4d..b2fc272 100644
--- a/src/cmd/compile/internal/arm/ggen.go
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -10,100 +10,54 @@ import (
 	"cmd/internal/obj/arm"
 )
 
-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 contain ambiguously live variables
-	// so that garbage collector only sees initialized values
-	// when it looks for pointers.
-	p := ptxt
-
-	hi := int64(0)
-	lo := hi
-	r0 := uint32(0)
-	for _, 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 %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
-		}
-		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) {
-			// merge with range we already have
-			lo = gc.Rnd(n.Xoffset, int64(gc.Widthptr))
-
-			continue
-		}
-
-		// zero old range
-		p = zerorange(p, int64(frame), lo, hi, &r0)
-
-		// set new range
-		hi = n.Xoffset + n.Type.Width
-
-		lo = n.Xoffset
-	}
-
-	// zero final range
-	zerorange(p, int64(frame), lo, hi, &r0)
-}
-
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, r0 *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 	if *r0 == 0 {
-		p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
+		p = pp.Appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
 		*r0 = 1
 	}
 
 	if cnt < int64(4*gc.Widthptr) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
-			p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, 4+frame+lo+i)
+			p = pp.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, 4+off+i)
 		}
 	} else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) {
-		p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+frame+lo, obj.TYPE_REG, arm.REG_R1, 0)
+		p = pp.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+off, obj.TYPE_REG, arm.REG_R1, 0)
 		p.Reg = arm.REGSP
-		p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
-		gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
 	} else {
-		p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+frame+lo, obj.TYPE_REG, arm.REG_R1, 0)
+		p = pp.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+off, obj.TYPE_REG, arm.REG_R1, 0)
 		p.Reg = arm.REGSP
-		p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm.REG_R2, 0)
+		p = pp.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm.REG_R2, 0)
 		p.Reg = arm.REG_R1
-		p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
+		p = pp.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
 		p1 := p
 		p.Scond |= arm.C_PBIT
-		p = gc.Appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
 		p.Reg = arm.REG_R2
-		p = gc.Appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
 		gc.Patch(p, p1)
 	}
 
 	return p
 }
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
-	p := gc.Prog(arm.AMOVW)
+	p := pp.Prog(arm.AMOVW)
 	p.From.Type = obj.TYPE_CONST
 	p.From.Offset = 0
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = arm.REGTMP
 	for i := int64(0); i < size; i += 4 {
-		p := gc.AddAsmAfter(arm.AMOVW, pp)
-		pp = p
+		p := pp.Prog(arm.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = arm.REGTMP
 		p.To.Type = obj.TYPE_MEM
@@ -114,8 +68,8 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(arm.AAND)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(arm.AAND)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = arm.REG_R0
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go
deleted file mode 100644
index 1dd7c98..0000000
--- a/src/cmd/compile/internal/arm/prog.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package arm
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/arm"
-)
-
-const (
-	RightRdwr = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-var progtable = [arm.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// 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},
-
-	// Integer.
-	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.ACLZ & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | 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 & 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.ANEGD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	arm.ANEGF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	arm.ASQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-
-	// Conversions.
-	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 & 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 addition, duffzero reads R0,R1 and writes R1.  This fact is
-	// encoded in peep.c
-	obj.ADUFFZERO: {Flags: gc.Call},
-
-	// 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 & 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 & 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) gc.ProgInfo {
-	info := progtable[p.As&obj.AMask]
-	if info.Flags == 0 {
-		gc.Fatalf("unknown instruction %v", p)
-	}
-
-	if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	if (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
-		info.Flags &^= gc.RegRead
-		info.Flags |= gc.CanRegRead | gc.RightRead
-	}
-
-	if (p.Scond&arm.C_SCOND != arm.C_SCOND_NONE) && (info.Flags&gc.RightWrite != 0) {
-		info.Flags |= gc.RightRead
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go
index 5a69ed3..343f2d3 100644
--- a/src/cmd/compile/internal/arm/ssa.go
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -10,12 +10,13 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -45,7 +46,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -86,11 +87,11 @@ func makeshift(reg int16, typ int64, s int64) shift {
 	return shift(int64(reg&0xf) | typ | (s&31)<<7)
 }
 
-// genshift generates a Prog for r = r0 op (r1 shifted by s)
-func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
-	p := gc.Prog(as)
+// genshift generates a Prog for r = r0 op (r1 shifted by n)
+func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
+	p := s.Prog(as)
 	p.From.Type = obj.TYPE_SHIFT
-	p.From.Offset = int64(makeshift(r1, typ, s))
+	p.From.Offset = int64(makeshift(r1, typ, n))
 	p.Reg = r0
 	if r != 0 {
 		p.To.Type = obj.TYPE_REG
@@ -105,8 +106,8 @@ func makeregshift(r1 int16, typ int64, r2 int16) shift {
 }
 
 // genregshift generates a Prog for r = r0 op (r1 shifted by r2)
-func genregshift(as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
-	p := gc.Prog(as)
+func genregshift(s *gc.SSAGenState, as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
+	p := s.Prog(as)
 	p.From.Type = obj.TYPE_SHIFT
 	p.From.Offset = int64(makeregshift(r1, typ, r2))
 	p.Reg = r0
@@ -118,14 +119,7 @@ func genregshift(as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
 }
 
 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, ssa.OpGetG:
-		// nothing to do
 	case ssa.OpCopy, ssa.OpARMMOVWconvert, ssa.OpARMMOVWreg:
 		if v.Type.IsMemory() {
 			return
@@ -146,7 +140,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				panic("bad float size")
 			}
 		}
-		p := gc.Prog(as)
+		p := s.Prog(as)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x
 		p.To.Type = obj.TYPE_REG
@@ -161,26 +155,19 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("load flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(loadByType(v.Type))
+		p := s.Prog(loadByType(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
 	case ssa.OpStoreReg:
 		if v.Type.IsFlags() {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(storeByType(v.Type))
+		p := s.Prog(storeByType(v.Type))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
-	case ssa.OpARMUDIVrtcall:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = obj.Linklookup(gc.Ctxt, "udiv", 0)
 	case ssa.OpARMADD,
 		ssa.OpARMADC,
 		ssa.OpARMSUB,
@@ -202,7 +189,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
 		p.Reg = r1
@@ -213,7 +200,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg0()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Scond = arm.C_SBIT
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
@@ -226,7 +213,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
 		p.Reg = r1
@@ -241,14 +228,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(arm.ASRA)
+		p := s.Prog(arm.ASRA)
 		p.Scond = arm.C_SCOND_HS
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 31
 		p.Reg = r1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
-		p = gc.Prog(arm.ASRA)
+		p = s.Prog(arm.ASRA)
 		p.Scond = arm.C_SCOND_LO
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
@@ -268,7 +255,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMSLLconst,
 		ssa.OpARMSRLconst,
 		ssa.OpARMSRAconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
@@ -277,7 +264,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpARMADDSconst,
 		ssa.OpARMSUBSconst,
 		ssa.OpARMRSBSconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Scond = arm.C_SBIT
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
@@ -285,7 +272,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 	case ssa.OpARMSRRconst:
-		genshift(arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
+		genshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
 	case ssa.OpARMADDshiftLL,
 		ssa.OpARMADCshiftLL,
 		ssa.OpARMSUBshiftLL,
@@ -296,11 +283,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftLL,
 		ssa.OpARMXORshiftLL,
 		ssa.OpARMBICshiftLL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
 	case ssa.OpARMADDSshiftLL,
 		ssa.OpARMSUBSshiftLL,
 		ssa.OpARMRSBSshiftLL:
-		p := genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMADDshiftRL,
 		ssa.OpARMADCshiftRL,
@@ -312,11 +299,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftRL,
 		ssa.OpARMXORshiftRL,
 		ssa.OpARMBICshiftRL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
 	case ssa.OpARMADDSshiftRL,
 		ssa.OpARMSUBSshiftRL,
 		ssa.OpARMRSBSshiftRL:
-		p := genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMADDshiftRA,
 		ssa.OpARMADCshiftRA,
@@ -328,26 +315,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftRA,
 		ssa.OpARMXORshiftRA,
 		ssa.OpARMBICshiftRA:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
 	case ssa.OpARMADDSshiftRA,
 		ssa.OpARMSUBSshiftRA,
 		ssa.OpARMRSBSshiftRA:
-		p := genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMXORshiftRR:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
 	case ssa.OpARMMVNshiftLL:
-		genshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+		genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
 	case ssa.OpARMMVNshiftRL:
-		genshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+		genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
 	case ssa.OpARMMVNshiftRA:
-		genshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+		genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
 	case ssa.OpARMMVNshiftLLreg:
-		genregshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL)
+		genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL)
 	case ssa.OpARMMVNshiftRLreg:
-		genregshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR)
+		genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR)
 	case ssa.OpARMMVNshiftRAreg:
-		genregshift(v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR)
+		genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR)
 	case ssa.OpARMADDshiftLLreg,
 		ssa.OpARMADCshiftLLreg,
 		ssa.OpARMSUBshiftLLreg,
@@ -358,11 +345,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftLLreg,
 		ssa.OpARMXORshiftLLreg,
 		ssa.OpARMBICshiftLLreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LL)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LL)
 	case ssa.OpARMADDSshiftLLreg,
 		ssa.OpARMSUBSshiftLLreg,
 		ssa.OpARMRSBSshiftLLreg:
-		p := genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LL)
+		p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LL)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMADDshiftRLreg,
 		ssa.OpARMADCshiftRLreg,
@@ -374,11 +361,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftRLreg,
 		ssa.OpARMXORshiftRLreg,
 		ssa.OpARMBICshiftRLreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LR)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LR)
 	case ssa.OpARMADDSshiftRLreg,
 		ssa.OpARMSUBSshiftRLreg,
 		ssa.OpARMRSBSshiftRLreg:
-		p := genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LR)
+		p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LR)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMADDshiftRAreg,
 		ssa.OpARMADCshiftRAreg,
@@ -390,16 +377,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMORshiftRAreg,
 		ssa.OpARMXORshiftRAreg,
 		ssa.OpARMBICshiftRAreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_AR)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_AR)
 	case ssa.OpARMADDSshiftRAreg,
 		ssa.OpARMSUBSshiftRAreg,
 		ssa.OpARMRSBSshiftRAreg:
-		p := genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_AR)
+		p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_AR)
 		p.Scond = arm.C_SBIT
 	case ssa.OpARMHMUL,
 		ssa.OpARMHMULU:
 		// 32-bit high multiplication
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -408,7 +395,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Offset = arm.REGTMP // throw away low 32-bit into tmp register
 	case ssa.OpARMMULLU:
 		// 32-bit multiplication, results 64-bit, high 32-bit in out0, low 32-bit in out1
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -416,7 +403,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg0()           // high 32-bit
 		p.To.Offset = int64(v.Reg1()) // low 32-bit
 	case ssa.OpARMMULA:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -424,14 +411,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()                   // result
 		p.To.Offset = int64(v.Args[2].Reg()) // addend
 	case ssa.OpARMMOVWconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpARMMOVFconst,
 		ssa.OpARMMOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
@@ -442,7 +429,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMTEQ,
 		ssa.OpARMCMPF,
 		ssa.OpARMCMPD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.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.
@@ -453,29 +440,29 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMTSTconst,
 		ssa.OpARMTEQconst:
 		// Special layout in ARM assembly
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
 	case ssa.OpARMCMPF0,
 		ssa.OpARMCMPD0:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 	case ssa.OpARMCMPshiftLL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
 	case ssa.OpARMCMPshiftRL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
 	case ssa.OpARMCMPshiftRA:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
 	case ssa.OpARMCMPshiftLLreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL)
 	case ssa.OpARMCMPshiftRLreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LR)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LR)
 	case ssa.OpARMCMPshiftRAreg:
-		genregshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_AR)
+		genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_AR)
 	case ssa.OpARMMOVWaddr:
-		p := gc.Prog(arm.AMOVW)
+		p := s.Prog(arm.AMOVW)
 		p.From.Type = obj.TYPE_ADDR
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -512,7 +499,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMMOVWload,
 		ssa.OpARMMOVFload,
 		ssa.OpARMMOVDload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -523,7 +510,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMMOVWstore,
 		ssa.OpARMMOVFstore,
 		ssa.OpARMMOVDstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -533,33 +520,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// this is just shift 0 bits
 		fallthrough
 	case ssa.OpARMMOVWloadshiftLL:
-		p := genshift(v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
 		p.From.Reg = v.Args[0].Reg()
 	case ssa.OpARMMOVWloadshiftRL:
-		p := genshift(v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
 		p.From.Reg = v.Args[0].Reg()
 	case ssa.OpARMMOVWloadshiftRA:
-		p := genshift(v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+		p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
 		p.From.Reg = v.Args[0].Reg()
 	case ssa.OpARMMOVWstoreidx:
 		// this is just shift 0 bits
 		fallthrough
 	case ssa.OpARMMOVWstoreshiftLL:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_SHIFT
 		p.To.Reg = v.Args[0].Reg()
 		p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt))
 	case ssa.OpARMMOVWstoreshiftRL:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_SHIFT
 		p.To.Reg = v.Args[0].Reg()
 		p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt))
 	case ssa.OpARMMOVWstoreshiftRA:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_SHIFT
@@ -584,7 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				if v.Reg() == v.Args[0].Reg() {
 					return
 				}
-				p := gc.Prog(arm.AMOVW)
+				p := s.Prog(arm.AMOVW)
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = v.Args[0].Reg()
 				p.To.Type = obj.TYPE_REG
@@ -596,6 +583,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		fallthrough
 	case ssa.OpARMMVN,
 		ssa.OpARMCLZ,
+		ssa.OpARMREV,
+		ssa.OpARMRBIT,
 		ssa.OpARMSQRTD,
 		ssa.OpARMNEGF,
 		ssa.OpARMNEGD,
@@ -605,7 +594,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMMOVDW,
 		ssa.OpARMMOVFD,
 		ssa.OpARMMOVDF:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
@@ -614,99 +603,55 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMMOVWUD,
 		ssa.OpARMMOVFWU,
 		ssa.OpARMMOVDWU:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Scond = arm.C_UBIT
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpARMCMOVWHSconst:
-		p := gc.Prog(arm.AMOVW)
+		p := s.Prog(arm.AMOVW)
 		p.Scond = arm.C_SCOND_HS
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpARMCMOVWLSconst:
-		p := gc.Prog(arm.AMOVW)
+		p := s.Prog(arm.AMOVW)
 		p.Scond = arm.C_SCOND_LS
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpARMCALLstatic:
-		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.OpARMCALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.OpARMCALLdefer:
-		p := gc.Prog(obj.ACALL)
+	case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter:
+		s.Call(v)
+	case ssa.OpARMCALLudiv:
+		p := s.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.OpARMCALLgo:
-		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.OpARMCALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+		p.To.Sym = gc.Udiv
 	case ssa.OpARMDUFFZERO:
-		p := gc.Prog(obj.ADUFFZERO)
+		p := s.Prog(obj.ADUFFZERO)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = v.AuxInt
 	case ssa.OpARMDUFFCOPY:
-		p := gc.Prog(obj.ADUFFCOPY)
+		p := s.Prog(obj.ADUFFCOPY)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+		p.To.Sym = gc.Duffcopy
 		p.To.Offset = v.AuxInt
 	case ssa.OpARMLoweredNilCheck:
 		// Issue a load which will fault if arg is nil.
-		p := gc.Prog(arm.AMOVB)
+		p := s.Prog(arm.AMOVB)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 	case ssa.OpARMLoweredZero:
 		// MOVW.P	Rarg2, 4(R1)
@@ -728,18 +673,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = arm.AMOVB
 		}
-		p := gc.Prog(mov)
+		p := s.Prog(mov)
 		p.Scond = arm.C_PBIT
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = arm.REG_R1
 		p.To.Offset = sz
-		p2 := gc.Prog(arm.ACMP)
+		p2 := s.Prog(arm.ACMP)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = v.Args[1].Reg()
 		p2.Reg = arm.REG_R1
-		p3 := gc.Prog(arm.ABLE)
+		p3 := s.Prog(arm.ABLE)
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 	case ssa.OpARMLoweredMove:
@@ -762,35 +707,27 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = arm.AMOVB
 		}
-		p := gc.Prog(mov)
+		p := s.Prog(mov)
 		p.Scond = arm.C_PBIT
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = arm.REG_R1
 		p.From.Offset = sz
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm.REGTMP
-		p2 := gc.Prog(mov)
+		p2 := s.Prog(mov)
 		p2.Scond = arm.C_PBIT
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = arm.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = arm.REG_R2
 		p2.To.Offset = sz
-		p3 := gc.Prog(arm.ACMP)
+		p3 := s.Prog(arm.ACMP)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = v.Args[2].Reg()
 		p3.Reg = arm.REG_R1
-		p4 := gc.Prog(arm.ABLE)
+		p4 := s.Prog(arm.ABLE)
 		p4.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p4, p)
-	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:
-		gc.KeepAlive(v)
 	case ssa.OpARMEqual,
 		ssa.OpARMNotEqual,
 		ssa.OpARMLessThan,
@@ -803,19 +740,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARMGreaterEqualU:
 		// generate boolean values
 		// use conditional move
-		p := gc.Prog(arm.AMOVW)
+		p := s.Prog(arm.AMOVW)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		p = gc.Prog(arm.AMOVW)
+		p = s.Prog(arm.AMOVW)
 		p.Scond = condBits[v.Op]
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.OpARMLoweredGetClosurePtr:
 		// Closure pointer is R7 (arm.REGCTXT).
 		gc.CheckLoweredGetClosurePtr(v)
@@ -827,6 +762,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
 	case ssa.OpARMInvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -861,12 +798,10 @@ var blockJump = map[ssa.BlockKind]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -875,30 +810,30 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in R0:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(arm.ACMP)
+		p := s.Prog(arm.ACMP)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 0
 		p.Reg = arm.REG_R0
-		p = gc.Prog(arm.ABNE)
+		p = s.Prog(arm.ABNE)
 		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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.ARET)
+		p := s.Prog(obj.ARET)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 
 	case ssa.BlockARMEQ, ssa.BlockARMNE,
 		ssa.BlockARMLT, ssa.BlockARMGE,
@@ -909,18 +844,18 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		var p *obj.Prog
 		switch next {
 		case b.Succs[0].Block():
-			p = gc.Prog(jmp.invasm)
+			p = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.Prog(obj.AJMP)
 			q.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 		}
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index 15680dd..a64be8e 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -10,16 +10,17 @@ import (
 	"cmd/internal/obj/arm64"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &arm64.Linkarm64
-	gc.Thearch.REGSP = arm64.REGSP
-	gc.Thearch.MAXWIDTH = 1 << 50
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &arm64.Linkarm64
+	arch.REGSP = arm64.REGSP
+	arch.MAXWIDTH = 1 << 50
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.PadFrame = padframe
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
index 83966a4..52a8e3f 100644
--- a/src/cmd/compile/internal/arm64/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -8,108 +8,62 @@ import (
 	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
+	"cmd/internal/objabi"
 )
 
-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)))
+var darwin = objabi.GOOS == "darwin"
 
+func padframe(frame int64) int64 {
 	// arm64 requires that the frame size (not counting saved LR)
 	// be empty or be 8 mod 16. If not, pad it.
 	if frame != 0 && frame%16 != 8 {
 		frame += 8
 	}
-
-	ptxt.To.Offset = int64(frame)
-
-	// insert code to zero ambiguously live variables
-	// so that the garbage collector only sees initialized values
-	// when it looks for pointers.
-	p := ptxt
-
-	hi := int64(0)
-	lo := hi
-
-	// iterate through declarations - they are sorted in decreasing xoffset order.
-	for _, 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 %L has size %d offset %d", n, 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)
+	return frame
 }
 
-var darwin = obj.GOOS == "darwin"
-
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 	if cnt < int64(4*gc.Widthptr) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
-			p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
+			p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+off+i)
 		}
 	} else if cnt <= int64(128*gc.Widthptr) && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
-		p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
-		p = gc.Appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = pp.Appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+off-8, obj.TYPE_REG, arm64.REGRT1, 0)
 		p.Reg = arm64.REGRT1
-		p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
-		gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
 	} else {
-		p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGTMP, 0)
-		p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
-		p = gc.Appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, 8+off-8, obj.TYPE_REG, arm64.REGTMP, 0)
+		p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = pp.Appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
 		p.Reg = arm64.REGRT1
-		p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm64.REGTMP, 0)
-		p = gc.Appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT2, 0)
+		p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm64.REGTMP, 0)
+		p = pp.Appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT2, 0)
 		p.Reg = arm64.REGRT1
-		p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
+		p = pp.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
 		p.Scond = arm64.C_XPRE
 		p1 := p
-		p = gc.Appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
 		p.Reg = arm64.REGRT2
-		p = gc.Appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
 		gc.Patch(p, p1)
 	}
 
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += 8 {
-		p := gc.AddAsmAfter(arm64.AMOVD, pp)
-		pp = p
+		p := pp.Prog(arm64.AMOVD)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = arm64.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -120,7 +74,7 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(arm64.AHINT)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(arm64.AHINT)
 	p.From.Type = obj.TYPE_CONST
 }
diff --git a/src/cmd/compile/internal/arm64/prog.go b/src/cmd/compile/internal/arm64/prog.go
deleted file mode 100644
index 5d3ec67..0000000
--- a/src/cmd/compile/internal/arm64/prog.go
+++ /dev/null
@@ -1,184 +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 arm64
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/arm64"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-var progtable = [arm64.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// 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 & obj.AMask: {Flags: gc.OK},
-
-	// Integer
-	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}, // why RegRead? revisit once the old backend gone
-	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.ABIC & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AMVN & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
-	arm64.AMUL & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AMULW & obj.AMask:   {Flags: gc.SizeL | 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.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUMULH & obj.AMask:  {Flags: gc.SizeQ | 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.ASDIVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUDIVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AREM & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUREM & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AREMW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUREMW & obj.AMask:  {Flags: gc.SizeL | 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.ACMPW & obj.AMask:   {Flags: gc.SizeL | 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.ARORW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AADDS & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry},
-	arm64.ACSET & obj.AMask:   {Flags: gc.SizeQ | gc.RightWrite},
-	arm64.ACSEL & obj.AMask:   {Flags: gc.SizeQ | gc.RegRead | gc.RightWrite},
-	arm64.AREV & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
-	arm64.AREVW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-	arm64.AREV16W & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-	arm64.ARBIT & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
-	arm64.ARBITW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-	arm64.ACLZ & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
-	arm64.ACLZW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-
-	// Floating point.
-	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 & 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 & 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 & 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 & 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},
-	arm64.ALDARW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ALDAR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ALDAXRB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ALDAXRW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ALDAXR & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ASTLRW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ASTLR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ASTLXRB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ASTLXRW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.ASTLXR & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-
-	// Jumps
-	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},
-	arm64.ACBZW & obj.AMask:  {Flags: gc.Cjmp},
-	arm64.ACBNZW & 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) gc.ProgInfo {
-	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_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
index 5670ef8..dec6a4e 100644
--- a/src/cmd/compile/internal/arm64/ssa.go
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -9,12 +9,13 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 )
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -50,7 +51,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -78,11 +79,11 @@ func makeshift(reg int16, typ int64, s int64) int64 {
 	return int64(reg&31)<<16 | typ | (s&63)<<10
 }
 
-// genshift generates a Prog for r = r0 op (r1 shifted by s)
-func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
-	p := gc.Prog(as)
+// genshift generates a Prog for r = r0 op (r1 shifted by n)
+func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
+	p := s.Prog(as)
 	p.From.Type = obj.TYPE_SHIFT
-	p.From.Offset = makeshift(r1, typ, s)
+	p.From.Offset = makeshift(r1, typ, n)
 	p.Reg = r0
 	if r != 0 {
 		p.To.Type = obj.TYPE_REG
@@ -92,14 +93,7 @@ func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
 }
 
 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, ssa.OpGetG:
-		// nothing to do
 	case ssa.OpCopy, ssa.OpARM64MOVDconvert, ssa.OpARM64MOVDreg:
 		if v.Type.IsMemory() {
 			return
@@ -120,7 +114,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				panic("bad float size")
 			}
 		}
-		p := gc.Prog(as)
+		p := s.Prog(as)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x
 		p.To.Type = obj.TYPE_REG
@@ -135,18 +129,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("load flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(loadByType(v.Type))
+		p := s.Prog(loadByType(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
 	case ssa.OpStoreReg:
 		if v.Type.IsFlags() {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(storeByType(v.Type))
+		p := s.Prog(storeByType(v.Type))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
@@ -184,7 +176,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
 		p.Reg = r1
@@ -201,7 +193,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64SRAconst,
 		ssa.OpARM64RORconst,
 		ssa.OpARM64RORWconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
@@ -213,30 +205,30 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64ORshiftLL,
 		ssa.OpARM64XORshiftLL,
 		ssa.OpARM64BICshiftLL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
 	case ssa.OpARM64ADDshiftRL,
 		ssa.OpARM64SUBshiftRL,
 		ssa.OpARM64ANDshiftRL,
 		ssa.OpARM64ORshiftRL,
 		ssa.OpARM64XORshiftRL,
 		ssa.OpARM64BICshiftRL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
 	case ssa.OpARM64ADDshiftRA,
 		ssa.OpARM64SUBshiftRA,
 		ssa.OpARM64ANDshiftRA,
 		ssa.OpARM64ORshiftRA,
 		ssa.OpARM64XORshiftRA,
 		ssa.OpARM64BICshiftRA:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
 	case ssa.OpARM64MOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpARM64FMOVSconst,
 		ssa.OpARM64FMOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
@@ -247,7 +239,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64CMNW,
 		ssa.OpARM64FCMPS,
 		ssa.OpARM64FCMPD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[0].Reg()
@@ -255,18 +247,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64CMPWconst,
 		ssa.OpARM64CMNconst,
 		ssa.OpARM64CMNWconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
 	case ssa.OpARM64CMPshiftLL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
 	case ssa.OpARM64CMPshiftRL:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
 	case ssa.OpARM64CMPshiftRA:
-		genshift(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
+		genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
 	case ssa.OpARM64MOVDaddr:
-		p := gc.Prog(arm64.AMOVD)
+		p := s.Prog(arm64.AMOVD)
 		p.From.Type = obj.TYPE_ADDR
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -304,7 +296,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64MOVDload,
 		ssa.OpARM64FMOVSload,
 		ssa.OpARM64FMOVDload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -312,7 +304,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpARM64LDAR,
 		ssa.OpARM64LDARW:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -326,7 +318,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64FMOVDstore,
 		ssa.OpARM64STLR,
 		ssa.OpARM64STLRW:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -336,7 +328,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64MOVHstorezero,
 		ssa.OpARM64MOVWstorezero,
 		ssa.OpARM64MOVDstorezero:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = arm64.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -356,18 +348,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r0 := v.Args[0].Reg()
 		r1 := v.Args[1].Reg()
 		out := v.Reg0()
-		p := gc.Prog(ld)
+		p := s.Prog(ld)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = out
-		p1 := gc.Prog(st)
+		p1 := s.Prog(st)
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = r1
 		p1.To.Type = obj.TYPE_MEM
 		p1.To.Reg = r0
 		p1.RegTo2 = arm64.REGTMP
-		p2 := gc.Prog(arm64.ACBNZ)
+		p2 := s.Prog(arm64.ACBNZ)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = arm64.REGTMP
 		p2.To.Type = obj.TYPE_BRANCH
@@ -387,23 +379,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r0 := v.Args[0].Reg()
 		r1 := v.Args[1].Reg()
 		out := v.Reg0()
-		p := gc.Prog(ld)
+		p := s.Prog(ld)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = out
-		p1 := gc.Prog(arm64.AADD)
+		p1 := s.Prog(arm64.AADD)
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = r1
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = out
-		p2 := gc.Prog(st)
+		p2 := s.Prog(st)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = out
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = r0
 		p2.RegTo2 = arm64.REGTMP
-		p3 := gc.Prog(arm64.ACBNZ)
+		p3 := s.Prog(arm64.ACBNZ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = arm64.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
@@ -428,29 +420,29 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r1 := v.Args[1].Reg()
 		r2 := v.Args[2].Reg()
 		out := v.Reg0()
-		p := gc.Prog(ld)
+		p := s.Prog(ld)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm64.REGTMP
-		p1 := gc.Prog(cmp)
+		p1 := s.Prog(cmp)
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = r1
 		p1.Reg = arm64.REGTMP
-		p2 := gc.Prog(arm64.ABNE)
+		p2 := s.Prog(arm64.ABNE)
 		p2.To.Type = obj.TYPE_BRANCH
-		p3 := gc.Prog(st)
+		p3 := s.Prog(st)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = r2
 		p3.To.Type = obj.TYPE_MEM
 		p3.To.Reg = r0
 		p3.RegTo2 = arm64.REGTMP
-		p4 := gc.Prog(arm64.ACBNZ)
+		p4 := s.Prog(arm64.ACBNZ)
 		p4.From.Type = obj.TYPE_REG
 		p4.From.Reg = arm64.REGTMP
 		p4.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p4, p)
-		p5 := gc.Prog(arm64.ACSET)
+		p5 := s.Prog(arm64.ACSET)
 		p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
 		p5.From.Reg = arm64.COND_EQ
 		p5.To.Type = obj.TYPE_REG
@@ -464,23 +456,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// CBNZ		Rtmp, -3(PC)
 		r0 := v.Args[0].Reg()
 		r1 := v.Args[1].Reg()
-		p := gc.Prog(arm64.ALDAXRB)
+		p := s.Prog(arm64.ALDAXRB)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm64.REGTMP
-		p1 := gc.Prog(v.Op.Asm())
+		p1 := s.Prog(v.Op.Asm())
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = r1
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = arm64.REGTMP
-		p2 := gc.Prog(arm64.ASTLXRB)
+		p2 := s.Prog(arm64.ASTLXRB)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = arm64.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = r0
 		p2.RegTo2 = arm64.REGTMP
-		p3 := gc.Prog(arm64.ACBNZ)
+		p3 := s.Prog(arm64.ACBNZ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = arm64.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
@@ -508,7 +500,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				if v.Reg() == v.Args[0].Reg() {
 					return
 				}
-				p := gc.Prog(arm64.AMOVD)
+				p := s.Prog(arm64.AMOVD)
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = v.Args[0].Reg()
 				p.To.Type = obj.TYPE_REG
@@ -548,7 +540,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64RBITW,
 		ssa.OpARM64CLZ,
 		ssa.OpARM64CLZW:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
@@ -559,7 +551,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Op == ssa.OpARM64CSELULT {
 			r1 = v.Args[1].Reg()
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
 		p.From.Reg = arm64.COND_LO
 		p.Reg = v.Args[0].Reg()
@@ -568,41 +560,41 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpARM64DUFFZERO:
 		// runtime.duffzero expects start address - 8 in R16
-		p := gc.Prog(arm64.ASUB)
+		p := s.Prog(arm64.ASUB)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
 		p.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm64.REG_R16
-		p = gc.Prog(obj.ADUFFZERO)
+		p = s.Prog(obj.ADUFFZERO)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = v.AuxInt
 	case ssa.OpARM64LoweredZero:
 		// MOVD.P	ZR, 8(R16)
 		// CMP	Rarg1, R16
 		// BLE	-2(PC)
 		// arg1 is the address of the last element to zero
-		p := gc.Prog(arm64.AMOVD)
+		p := s.Prog(arm64.AMOVD)
 		p.Scond = arm64.C_XPOST
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = arm64.REGZERO
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = arm64.REG_R16
 		p.To.Offset = 8
-		p2 := gc.Prog(arm64.ACMP)
+		p2 := s.Prog(arm64.ACMP)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = v.Args[1].Reg()
 		p2.Reg = arm64.REG_R16
-		p3 := gc.Prog(arm64.ABLE)
+		p3 := s.Prog(arm64.ABLE)
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 	case ssa.OpARM64DUFFCOPY:
-		p := gc.Prog(obj.ADUFFCOPY)
+		p := s.Prog(obj.ADUFFCOPY)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+		p.To.Sym = gc.Duffcopy
 		p.To.Offset = v.AuxInt
 	case ssa.OpARM64LoweredMove:
 		// MOVD.P	8(R16), Rtmp
@@ -610,97 +602,40 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// CMP	Rarg2, R16
 		// BLE	-3(PC)
 		// arg2 is the address of the last element of src
-		p := gc.Prog(arm64.AMOVD)
+		p := s.Prog(arm64.AMOVD)
 		p.Scond = arm64.C_XPOST
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = arm64.REG_R16
 		p.From.Offset = 8
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm64.REGTMP
-		p2 := gc.Prog(arm64.AMOVD)
+		p2 := s.Prog(arm64.AMOVD)
 		p2.Scond = arm64.C_XPOST
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = arm64.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = arm64.REG_R17
 		p2.To.Offset = 8
-		p3 := gc.Prog(arm64.ACMP)
+		p3 := s.Prog(arm64.ACMP)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = v.Args[2].Reg()
 		p3.Reg = arm64.REG_R16
-		p4 := gc.Prog(arm64.ABLE)
+		p4 := s.Prog(arm64.ABLE)
 		p4.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p4, p)
-	case ssa.OpARM64CALLstatic:
-		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.OpARM64CALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.OpARM64CALLdefer:
-		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.OpARM64CALLgo:
-		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.OpARM64CALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
+		s.Call(v)
 	case ssa.OpARM64LoweredNilCheck:
 		// Issue a load which will fault if arg is nil.
-		p := gc.Prog(arm64.AMOVB)
+		p := s.Prog(arm64.AMOVB)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = arm64.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
-	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:
-		gc.KeepAlive(v)
 	case ssa.OpARM64Equal,
 		ssa.OpARM64NotEqual,
 		ssa.OpARM64LessThan,
@@ -712,13 +647,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpARM64GreaterThanU,
 		ssa.OpARM64GreaterEqualU:
 		// generate boolean values using CSET
-		p := gc.Prog(arm64.ACSET)
+		p := s.Prog(arm64.ACSET)
 		p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
 		p.From.Reg = condBits[v.Op]
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.OpARM64LoweredGetClosurePtr:
 		// Closure pointer is R26 (arm64.REGCTXT).
 		gc.CheckLoweredGetClosurePtr(v)
@@ -730,6 +663,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
 	case ssa.OpARM64InvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -768,12 +703,10 @@ var blockJump = map[ssa.BlockKind]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -782,30 +715,30 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in R0:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(arm64.ACMP)
+		p := s.Prog(arm64.ACMP)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 0
 		p.Reg = arm64.REG_R0
-		p = gc.Prog(arm64.ABNE)
+		p = s.Prog(arm64.ABNE)
 		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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.ARET)
+		p := s.Prog(obj.ARET)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 
 	case ssa.BlockARM64EQ, ssa.BlockARM64NE,
 		ssa.BlockARM64LT, ssa.BlockARM64GE,
@@ -818,18 +751,18 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		var p *obj.Prog
 		switch next {
 		case b.Succs[0].Block():
-			p = gc.Prog(jmp.invasm)
+			p = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.Prog(obj.AJMP)
 			q.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 		}
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index d4f3d98..0b4c9c7 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -4,7 +4,10 @@
 
 package gc
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"fmt"
+)
 
 // AlgKind describes the kind of algorithms used for comparing and
 // hashing a Type.
@@ -35,21 +38,21 @@ const (
 )
 
 // IsComparable reports whether t is a comparable type.
-func (t *Type) IsComparable() bool {
+func IsComparable(t *types.Type) bool {
 	a, _ := algtype1(t)
 	return a != ANOEQ
 }
 
 // IsRegularMemory reports whether t can be compared/hashed as regular memory.
-func (t *Type) IsRegularMemory() bool {
+func IsRegularMemory(t *types.Type) bool {
 	a, _ := algtype1(t)
 	return a == AMEM
 }
 
 // IncomparableField returns an incomparable Field of struct Type t, if any.
-func (t *Type) IncomparableField() *Field {
+func IncomparableField(t *types.Type) *types.Field {
 	for _, f := range t.FieldSlice() {
-		if !f.Type.IsComparable() {
+		if !IsComparable(f.Type) {
 			return f
 		}
 	}
@@ -58,7 +61,7 @@ func (t *Type) IncomparableField() *Field {
 
 // 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 {
+func algtype(t *types.Type) AlgKind {
 	a, _ := algtype1(t)
 	if a == AMEM {
 		switch t.Width {
@@ -83,11 +86,11 @@ func algtype(t *Type) AlgKind {
 // 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 {
+func algtype1(t *types.Type) (AlgKind, *types.Type) {
+	if t.Broke() {
 		return AMEM, nil
 	}
-	if t.Noalg {
+	if t.Noalg() {
 		return ANOEQ, t
 	}
 
@@ -154,7 +157,7 @@ func algtype1(t *Type) (AlgKind, *Type) {
 		fields := t.FieldSlice()
 
 		// One-field struct is same as that one field alone.
-		if len(fields) == 1 && !isblanksym(fields[0].Sym) {
+		if len(fields) == 1 && !fields[0].Sym.IsBlank() {
 			return algtype1(fields[0].Type)
 		}
 
@@ -168,7 +171,7 @@ func algtype1(t *Type) (AlgKind, *Type) {
 
 			// Blank fields, padded fields, fields with non-memory
 			// equality need special compare.
-			if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, i) {
+			if a != AMEM || f.Sym.IsBlank() || ispaddedfield(t, i) {
 				ret = ASPECIAL
 			}
 		}
@@ -181,34 +184,27 @@ func algtype1(t *Type) (AlgKind, *Type) {
 }
 
 // Generate a helper function to compute the hash of a value of type t.
-func genhash(sym *Sym, t *Type) {
+func genhash(sym *types.Sym, t *types.Type) {
 	if Debug['r'] != 0 {
 		fmt.Printf("genhash %v %v\n", sym, t)
 	}
 
-	lineno = 1 // less confusing than end of input
+	lineno = autogeneratedPos // less confusing than end of input
 	dclcontext = PEXTERN
-	markdcl()
+	types.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)))
+	n := namedfield("p", types.NewPtr(t))
 	tfn.List.Append(n)
 	np := n.Left
-	n = nod(ODCLFIELD, newname(lookup("h")), typenod(Types[TUINTPTR]))
+	n = namedfield("h", types.Types[TUINTPTR])
 	tfn.List.Append(n)
 	nh := n.Left
-	n = nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
+	n = anonfield(types.Types[TUINTPTR]) // return value
 	tfn.Rlist.Append(n)
 
-	funchdr(fn)
-	fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
+	fn := dclfunc(sym, tfn)
 
 	// genhash is only called for types that have equality but
 	// cannot be handled by the standard algorithms,
@@ -217,7 +213,7 @@ func genhash(sym *Sym, t *Type) {
 	default:
 		Fatalf("genhash %v", t)
 
-	case TARRAY:
+	case types.TARRAY:
 		// An array of pure memory would be handled by the
 		// standard algorithm, so the element type must not be
 		// pure memory.
@@ -225,9 +221,9 @@ func genhash(sym *Sym, t *Type) {
 
 		n := nod(ORANGE, nil, nod(OIND, np, nil))
 		ni := newname(lookup("i"))
-		ni.Type = Types[TINT]
+		ni.Type = types.Types[TINT]
 		n.List.Set1(ni)
-		n.Colas = true
+		n.SetColas(true)
 		colasdefn(n.List.Slice(), n)
 		ni = n.List.First()
 
@@ -235,7 +231,7 @@ func genhash(sym *Sym, t *Type) {
 		call := nod(OCALL, hashel, nil)
 
 		nx := nod(OINDEX, np, ni)
-		nx.Bounded = true
+		nx.SetBounded(true)
 		na := nod(OADDR, nx, nil)
 		na.Etype = 1 // no escape to heap
 		call.List.Append(na)
@@ -244,20 +240,20 @@ func genhash(sym *Sym, t *Type) {
 
 		fn.Nbody.Append(n)
 
-	case TSTRUCT:
+	case types.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) {
+			if f.Sym.IsBlank() {
 				i++
 				continue
 			}
 
 			// Hash non-memory fields with appropriate hash function.
-			if !f.Type.IsRegularMemory() {
+			if !IsRegularMemory(f.Type) {
 				hashel := hashfor(f.Type)
 				call := nod(OCALL, hashel, nil)
 				nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
@@ -298,11 +294,11 @@ func genhash(sym *Sym, t *Type) {
 
 	funcbody(fn)
 	Curfn = fn
-	fn.Func.Dupok = true
+	fn.Func.SetDupok(true)
 	fn = typecheck(fn, Etop)
 	typecheckslice(fn.Nbody.Slice(), Etop)
 	Curfn = nil
-	popdcl()
+	types.Popdcl()
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
@@ -315,43 +311,42 @@ func genhash(sym *Sym, t *Type) {
 	old_safemode := safemode
 	safemode = false
 
-	disable_checknil++
+	fn.Func.SetNilCheckDisabled(true)
 	funccompile(fn)
-	disable_checknil--
 
 	safemode = old_safemode
 }
 
-func hashfor(t *Type) *Node {
-	var sym *Sym
+func hashfor(t *types.Type) *Node {
+	var sym *types.Sym
 
 	switch a, _ := algtype1(t); a {
 	case AMEM:
 		Fatalf("hashfor with AMEM type")
 	case AINTER:
-		sym = Pkglookup("interhash", Runtimepkg)
+		sym = Runtimepkg.Lookup("interhash")
 	case ANILINTER:
-		sym = Pkglookup("nilinterhash", Runtimepkg)
+		sym = Runtimepkg.Lookup("nilinterhash")
 	case ASTRING:
-		sym = Pkglookup("strhash", Runtimepkg)
+		sym = Runtimepkg.Lookup("strhash")
 	case AFLOAT32:
-		sym = Pkglookup("f32hash", Runtimepkg)
+		sym = Runtimepkg.Lookup("f32hash")
 	case AFLOAT64:
-		sym = Pkglookup("f64hash", Runtimepkg)
+		sym = Runtimepkg.Lookup("f64hash")
 	case ACPLX64:
-		sym = Pkglookup("c64hash", Runtimepkg)
+		sym = Runtimepkg.Lookup("c64hash")
 	case ACPLX128:
-		sym = Pkglookup("c128hash", Runtimepkg)
+		sym = Runtimepkg.Lookup("c128hash")
 	default:
 		sym = typesymprefix(".hash", t)
 	}
 
 	n := newname(sym)
-	n.Class = PFUNC
+	n.SetClass(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.List.Append(anonfield(types.NewPtr(t)))
+	tfn.List.Append(anonfield(types.Types[TUINTPTR]))
+	tfn.Rlist.Append(anonfield(types.Types[TUINTPTR]))
 	tfn = typecheck(tfn, Etype)
 	n.Type = tfn.Type
 	return n
@@ -359,34 +354,27 @@ func hashfor(t *Type) *Node {
 
 // geneq generates a helper function to
 // check equality of two values of type t.
-func geneq(sym *Sym, t *Type) {
+func geneq(sym *types.Sym, t *types.Type) {
 	if Debug['r'] != 0 {
 		fmt.Printf("geneq %v %v\n", sym, t)
 	}
 
-	lineno = 1 // less confusing than end of input
+	lineno = autogeneratedPos // less confusing than end of input
 	dclcontext = PEXTERN
-	markdcl()
+	types.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)))
+	n := namedfield("p", types.NewPtr(t))
 	tfn.List.Append(n)
 	np := n.Left
-	n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)))
+	n = namedfield("q", types.NewPtr(t))
 	tfn.List.Append(n)
 	nq := n.Left
-	n = nod(ODCLFIELD, nil, typenod(Types[TBOOL]))
+	n = anonfield(types.Types[TBOOL])
 	tfn.Rlist.Append(n)
 
-	funchdr(fn)
-	fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
+	fn := dclfunc(sym, tfn)
 
 	// geneq is only called for types that have equality but
 	// cannot be handled by the standard algorithms,
@@ -404,18 +392,18 @@ func geneq(sym *Sym, t *Type) {
 		nrange := nod(ORANGE, nil, nod(OIND, np, nil))
 
 		ni := newname(lookup("i"))
-		ni.Type = Types[TINT]
+		ni.Type = types.Types[TINT]
 		nrange.List.Set1(ni)
-		nrange.Colas = true
+		nrange.SetColas(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
+		nx.SetBounded(true)
 		ny := nod(OINDEX, nq, ni)
-		ny.Bounded = true
+		ny.SetBounded(true)
 
 		nif := nod(OIF, nil, nil)
 		nif.Left = nod(ONE, nx, ny)
@@ -446,13 +434,13 @@ func geneq(sym *Sym, t *Type) {
 			f := fields[i]
 
 			// Skip blank-named fields.
-			if isblanksym(f.Sym) {
+			if f.Sym.IsBlank() {
 				i++
 				continue
 			}
 
 			// Compare non-memory fields with field equality.
-			if !f.Type.IsRegularMemory() {
+			if !IsRegularMemory(f.Type) {
 				and(eqfield(np, nq, f.Sym))
 				i++
 				continue
@@ -490,11 +478,11 @@ func geneq(sym *Sym, t *Type) {
 
 	funcbody(fn)
 	Curfn = fn
-	fn.Func.Dupok = true
+	fn.Func.SetDupok(true)
 	fn = typecheck(fn, Etop)
 	typecheckslice(fn.Nbody.Slice(), Etop)
 	Curfn = nil
-	popdcl()
+	types.Popdcl()
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
@@ -511,17 +499,15 @@ func geneq(sym *Sym, t *Type) {
 	// We are comparing a struct or an array,
 	// neither of which can be nil, and our comparisons
 	// are shallow.
-	disable_checknil++
-
+	fn.Func.SetNilCheckDisabled(true)
 	funccompile(fn)
 
 	safemode = old_safemode
-	disable_checknil--
 }
 
 // eqfield returns the node
 // 	p.field == q.field
-func eqfield(p *Node, q *Node, field *Sym) *Node {
+func eqfield(p *Node, q *Node, field *types.Sym) *Node {
 	nx := nodSym(OXDOT, p, field)
 	ny := nodSym(OXDOT, q, field)
 	ne := nod(OEQ, nx, ny)
@@ -530,7 +516,7 @@ func eqfield(p *Node, q *Node, field *Sym) *Node {
 
 // eqmem returns the node
 // 	memequal(&p.field, &q.field [, size])
-func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
+func eqmem(p *Node, q *Node, field *types.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)
@@ -549,7 +535,7 @@ func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
 	return call
 }
 
-func eqmemfunc(size int64, t *Type) (fn *Node, needsize bool) {
+func eqmemfunc(size int64, t *types.Type) (fn *Node, needsize bool) {
 	switch size {
 	default:
 		fn = syslook("memequal")
@@ -567,7 +553,7 @@ func eqmemfunc(size int64, t *Type) (fn *Node, needsize bool) {
 // 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) {
+func memrun(t *types.Type, start int) (size int64, next int) {
 	next = start
 	for {
 		next++
@@ -579,7 +565,7 @@ func memrun(t *Type, start int) (size int64, next int) {
 			break
 		}
 		// Also, stop before a blank or non-memory field.
-		if f := t.Field(next); isblanksym(f.Sym) || !f.Type.IsRegularMemory() {
+		if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
 			break
 		}
 	}
@@ -588,7 +574,7 @@ func memrun(t *Type, start int) (size int64, next int) {
 
 // ispaddedfield reports whether the i'th field of struct type t is followed
 // by padding.
-func ispaddedfield(t *Type, i int) bool {
+func ispaddedfield(t *types.Type, i int) bool {
 	if !t.IsStruct() {
 		Fatalf("ispaddedfield called non-struct %v", t)
 	}
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index eee801f..f29c587 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -4,6 +4,15 @@
 
 package gc
 
+import (
+	"cmd/compile/internal/types"
+	"sort"
+)
+
+// sizeCalculationDisabled indicates whether it is safe
+// to calculate Types' widths and alignments. See dowidth.
+var sizeCalculationDisabled bool
+
 // machine size and rounding alignment is dictated around
 // the size of a pointer, set in betypeinit (see ../amd64/galign.go).
 var defercalc int
@@ -15,26 +24,67 @@ func Rnd(o int64, r int64) int64 {
 	return (o + r - 1) &^ (r - 1)
 }
 
-func offmod(t *Type) {
+// expandiface computes the method set for interface type t by
+// expanding embedded interfaces.
+func expandiface(t *types.Type) {
+	var fields []*types.Field
+	for _, m := range t.Methods().Slice() {
+		if m.Sym != nil {
+			fields = append(fields, m)
+			checkwidth(m.Type)
+			continue
+		}
+
+		if !m.Type.IsInterface() {
+			yyerrorl(asNode(m.Nname).Pos, "interface contains embedded non-interface %v", m.Type)
+			m.SetBroke(true)
+			t.SetBroke(true)
+			// Add to fields so that error messages
+			// include the broken embedded type when
+			// printing t.
+			// TODO(mdempsky): Revisit this.
+			fields = append(fields, m)
+			continue
+		}
+
+		// Embedded interface: duplicate all methods
+		// (including broken ones, if any) and add to t's
+		// method set.
+		for _, t1 := range m.Type.Fields().Slice() {
+			f := types.NewField()
+			f.Type = t1.Type
+			f.SetBroke(t1.Broke())
+			f.Sym = t1.Sym
+			f.Nname = m.Nname // preserve embedding position
+			fields = append(fields, f)
+		}
+	}
+	sort.Sort(methcmp(fields))
+
+	// Access fields directly to avoid recursively calling dowidth
+	// within Type.Fields().
+	t.Extra.(*types.Interface).Fields.Set(fields)
+}
+
+func offmod(t *types.Type) {
 	o := int32(0)
 	for _, f := range t.Fields().Slice() {
 		f.Offset = int64(o)
 		o += int32(Widthptr)
-		if int64(o) >= Thearch.MAXWIDTH {
+		if int64(o) >= thearch.MAXWIDTH {
 			yyerror("interface too large")
 			o = int32(Widthptr)
 		}
 	}
 }
 
-func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
+func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
 	starto := o
 	maxalign := int32(flag)
 	if maxalign < 1 {
 		maxalign = 1
 	}
 	lastzero := int64(0)
-	var w int64
 	for _, f := range t.Fields().Slice() {
 		if f.Type == nil {
 			// broken field, just skip it so that other valid fields
@@ -46,15 +96,11 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 		if int32(f.Type.Align) > maxalign {
 			maxalign = int32(f.Type.Align)
 		}
-		if f.Type.Width < 0 {
-			Fatalf("invalid width %d", f.Type.Width)
-		}
-		w = f.Type.Width
 		if f.Type.Align > 0 {
 			o = Rnd(o, int64(f.Type.Align))
 		}
 		f.Offset = o
-		if f.Nname != nil {
+		if asNode(f.Nname) != nil {
 			// addrescapes has similar code to update these offsets.
 			// Usually addrescapes runs after widstruct,
 			// in which case we could drop this,
@@ -62,19 +108,29 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 			// 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
+			if asNode(f.Nname).Name.Param.Stackcopy != nil {
+				asNode(f.Nname).Name.Param.Stackcopy.Xoffset = o
+				asNode(f.Nname).Xoffset = 0
 			} else {
-				f.Nname.Xoffset = o
+				asNode(f.Nname).Xoffset = o
 			}
 		}
 
+		w := f.Type.Width
+		if w < 0 {
+			Fatalf("invalid width %d", f.Type.Width)
+		}
 		if w == 0 {
 			lastzero = o
 		}
 		o += w
-		if o >= Thearch.MAXWIDTH {
+		maxwidth := thearch.MAXWIDTH
+		// On 32-bit systems, reflect tables impose an additional constraint
+		// that each field start offset must fit in 31 bits.
+		if maxwidth < 1<<32 {
+			maxwidth = 1<<31 - 1
+		}
+		if o >= maxwidth {
 			yyerror("type %L too large", errtype)
 			o = 8 // small but nonzero
 		}
@@ -100,7 +156,11 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 	return o
 }
 
-func dowidth(t *Type) {
+// dowidth calculates and stores the size and alignment for t.
+// If sizeCalculationDisabled is set, and the size/alignment
+// have not already been calculated, it calls Fatal.
+// This is used to prevent data races in the back end.
+func dowidth(t *types.Type) {
 	if Widthptr == 0 {
 		Fatalf("dowidth without betypeinit")
 	}
@@ -109,27 +169,32 @@ func dowidth(t *Type) {
 		return
 	}
 
-	if t.Width > 0 {
-		if t.Align == 0 {
-			// See issue 11354
-			Fatalf("zero alignment with nonzero size %v", t)
-		}
-		return
-	}
-
 	if t.Width == -2 {
-		if !t.Broke {
-			t.Broke = true
-			yyerrorl(t.Lineno, "invalid recursive type %v", t)
+		if !t.Broke() {
+			t.SetBroke(true)
+			yyerrorl(asNode(t.Nod).Pos, "invalid recursive type %v", t)
 		}
 
 		t.Width = 0
 		return
 	}
 
+	if t.WidthCalculated() {
+		return
+	}
+
+	if sizeCalculationDisabled {
+		if t.Broke() {
+			// break infinite recursion from Fatal call below
+			return
+		}
+		t.SetBroke(true)
+		Fatalf("width not calculated: %v", t)
+	}
+
 	// break infinite recursion if the broken recursive type
 	// is referenced again
-	if t.Broke && t.Width == 0 {
+	if t.Broke() && t.Width == 0 {
 		return
 	}
 
@@ -137,7 +202,10 @@ func dowidth(t *Type) {
 	defercalc++
 
 	lno := lineno
-	lineno = t.Lineno
+	if asNode(t.Nod) != nil {
+		lineno = asNode(t.Nod).Pos
+	}
+
 	t.Width = -2
 	t.Align = 0
 
@@ -194,9 +262,8 @@ func dowidth(t *Type) {
 
 	case TINTER: // implemented as 2 pointers
 		w = 2 * int64(Widthptr)
-
 		t.Align = uint8(Widthptr)
-		offmod(t)
+		expandiface(t)
 
 	case TCHAN: // implemented as pointer
 		w = int64(Widthptr)
@@ -205,7 +272,7 @@ func dowidth(t *Type) {
 
 		// make fake type to check later to
 		// trigger channel argument check.
-		t1 := typChanArgs(t)
+		t1 := types.NewChanArgs(t)
 		checkwidth(t1)
 
 	case TCHANARGS:
@@ -214,7 +281,7 @@ func dowidth(t *Type) {
 		if t1.Elem().Width >= 1<<16 {
 			yyerror("channel element type too large (>64kB)")
 		}
-		t.Width = 1
+		w = 1 // anything will do
 
 	case TMAP: // implemented as pointer
 		w = int64(Widthptr)
@@ -222,7 +289,7 @@ func dowidth(t *Type) {
 		checkwidth(t.Key())
 
 	case TFORW: // should have been filled in
-		if !t.Broke {
+		if !t.Broke() {
 			yyerror("invalid recursive type %v", t)
 		}
 		w = 1 // anything will do
@@ -242,17 +309,17 @@ func dowidth(t *Type) {
 		if t.Elem() == nil {
 			break
 		}
-		if t.isDDDArray() {
-			if !t.Broke {
+		if t.IsDDDArray() {
+			if !t.Broke() {
 				yyerror("use of [...] array outside of array literal")
-				t.Broke = true
+				t.SetBroke(true)
 			}
 			break
 		}
 
 		dowidth(t.Elem())
 		if t.Elem().Width != 0 {
-			cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
+			cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
 			if uint64(t.NumElem()) > cap {
 				yyerror("type %L larger than address space", t)
 			}
@@ -277,7 +344,7 @@ func dowidth(t *Type) {
 	// make fake type to check later to
 	// trigger function argument computation.
 	case TFUNC:
-		t1 := typFuncArgs(t)
+		t1 := types.NewFuncArgs(t)
 		checkwidth(t1)
 		w = int64(Widthptr) // width of func type is pointer
 
@@ -288,7 +355,7 @@ func dowidth(t *Type) {
 		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
+		t1.Extra.(*types.Func).Argwid = w
 		if w%int64(Widthreg) != 0 {
 			Warn("bad type %v %d\n", t1, w)
 		}
@@ -301,12 +368,20 @@ func dowidth(t *Type) {
 
 	t.Width = w
 	if t.Align == 0 {
-		if w > 8 || w&(w-1) != 0 {
+		if w > 8 || w&(w-1) != 0 || w == 0 {
 			Fatalf("invalid alignment for %v", t)
 		}
 		t.Align = uint8(w)
 	}
 
+	if t.Etype == TINTER {
+		// We defer calling these functions until after
+		// setting t.Width and t.Align so the recursive calls
+		// to dowidth within t.Fields() will succeed.
+		checkdupfields("method", t)
+		offmod(t)
+	}
+
 	lineno = lno
 
 	if defercalc == 1 {
@@ -332,9 +407,9 @@ func dowidth(t *Type) {
 // is needed immediately.  checkwidth makes sure the
 // size is evaluated eventually.
 
-var deferredTypeStack []*Type
+var deferredTypeStack []*types.Type
 
-func checkwidth(t *Type) {
+func checkwidth(t *types.Type) {
 	if t == nil {
 		return
 	}
@@ -350,10 +425,10 @@ func checkwidth(t *Type) {
 		return
 	}
 
-	if t.Deferwidth {
+	if t.Deferwidth() {
 		return
 	}
-	t.Deferwidth = true
+	t.SetDeferwidth(true)
 
 	deferredTypeStack = append(deferredTypeStack, t)
 }
@@ -373,7 +448,7 @@ func resumecheckwidth() {
 	for len(deferredTypeStack) > 0 {
 		t := deferredTypeStack[len(deferredTypeStack)-1]
 		deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
-		t.Deferwidth = false
+		t.SetDeferwidth(false)
 		dowidth(t)
 	}
 
diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go
index db800ab..221b849 100644
--- a/src/cmd/compile/internal/gc/asm_test.go
+++ b/src/cmd/compile/internal/gc/asm_test.go
@@ -21,9 +21,6 @@ import (
 // TestAssembly checks to make sure the assembly generated for
 // functions contains certain expected instructions.
 func TestAssembly(t *testing.T) {
-	if testing.Short() {
-		t.Skip("slow test; skipping")
-	}
 	testenv.MustHaveGoBuild(t)
 	if runtime.GOOS == "windows" {
 		// TODO: remove if we can get "go tool compile -S" to work on windows.
@@ -35,224 +32,1616 @@ func TestAssembly(t *testing.T) {
 	}
 	defer os.RemoveAll(dir)
 
-	for _, test := range asmTests {
-		asm := compileToAsm(t, dir, test.arch, test.os, 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]
+	nameRegexp := regexp.MustCompile("func \\w+")
+	t.Run("platform", func(t *testing.T) {
+		for _, ats := range allAsmTests {
+			ats := ats
+			t.Run(ats.os+"/"+ats.arch, func(tt *testing.T) {
+				tt.Parallel()
+
+				asm := ats.compileToAsm(tt, dir)
+
+				for _, at := range ats.tests {
+					funcName := nameRegexp.FindString(at.function)[len("func "):]
+					fa := funcAsm(tt, asm, funcName)
+					if fa != "" {
+						at.verifyAsm(tt, fa)
+					}
+				}
+			})
 		}
-		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)
-			}
+	})
+}
+
+var nextTextRegexp = regexp.MustCompile(`\n\S`)
+
+// funcAsm returns the assembly listing for the given function name.
+func funcAsm(t *testing.T, asm string, funcName string) string {
+	if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".%s(SB)", funcName)); i >= 0 {
+		asm = asm[i:]
+	} else {
+		t.Errorf("could not find assembly for function %v", funcName)
+		return ""
+	}
+
+	// Find the next line that doesn't begin with whitespace.
+	loc := nextTextRegexp.FindStringIndex(asm)
+	if loc != nil {
+		asm = asm[:loc[0]]
+	}
+
+	return asm
+}
+
+type asmTest struct {
+	// function to compile, must be named fX,
+	// where X is this test's index in asmTests.tests.
+	function string
+	// regexps that must match the generated assembly
+	regexps []string
+}
+
+func (at asmTest) verifyAsm(t *testing.T, fa string) {
+	for _, r := range at.regexps {
+		if b, err := regexp.MatchString(r, fa); !b || err != nil {
+			t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.function, fa)
 		}
 	}
 }
 
+type asmTests struct {
+	arch    string
+	os      string
+	imports []string
+	tests   []*asmTest
+}
+
+func (ats *asmTests) generateCode() []byte {
+	var buf bytes.Buffer
+	fmt.Fprintln(&buf, "package main")
+	for _, s := range ats.imports {
+		fmt.Fprintf(&buf, "import %q\n", s)
+	}
+
+	for _, t := range ats.tests {
+		fmt.Fprintln(&buf, t.function)
+	}
+
+	return buf.Bytes()
+}
+
 // compile compiles the package pkg for architecture arch and
 // returns the generated assembly.  dir is a scratch directory.
-func compileToAsm(t *testing.T, dir, goarch, goos, pkg string) string {
+func (ats *asmTests) compileToAsm(t *testing.T, dir string) string {
+	// create test directory
+	testDir := filepath.Join(dir, fmt.Sprintf("%s_%s", ats.arch, ats.os))
+	err := os.Mkdir(testDir, 0700)
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+
 	// Create source.
-	src := filepath.Join(dir, "test.go")
-	f, err := os.Create(src)
+	src := filepath.Join(testDir, "test.go")
+	err = ioutil.WriteFile(src, ats.generateCode(), 0600)
 	if err != nil {
-		panic(err)
+		t.Fatalf("error writing code: %v", err)
 	}
-	f.Write([]byte(pkg))
-	f.Close()
 
 	// First, install any dependencies we need.  This builds the required export data
 	// for any packages that are imported.
-	// TODO: extract dependencies automatically?
-	var stdout, stderr bytes.Buffer
-	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", filepath.Join(dir, "encoding/binary.a"), "encoding/binary")
-	cmd.Env = mergeEnvLists([]string{"GOARCH=" + goarch, "GOOS=" + goos}, os.Environ())
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-	if err := cmd.Run(); err != nil {
-		panic(err)
-	}
-	if s := stdout.String(); s != "" {
-		panic(fmt.Errorf("Stdout = %s\nWant empty", s))
-	}
-	if s := stderr.String(); s != "" {
-		panic(fmt.Errorf("Stderr = %s\nWant empty", s))
+	for _, i := range ats.imports {
+		out := filepath.Join(testDir, i+".a")
+
+		if s := ats.runGo(t, "build", "-o", out, "-gcflags=-dolinkobj=false", i); s != "" {
+			t.Fatalf("Stdout = %s\nWant empty", s)
+		}
 	}
 
 	// Now, compile the individual file for which we want to see the generated assembly.
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", dir, "-S", "-o", filepath.Join(dir, "out.o"), src)
-	cmd.Env = mergeEnvLists([]string{"GOARCH=" + goarch, "GOOS=" + goos}, os.Environ())
+	asm := ats.runGo(t, "tool", "compile", "-I", testDir, "-S", "-o", filepath.Join(testDir, "out.o"), src)
+	return asm
+}
+
+// runGo runs go command with the given args and returns stdout string.
+// go is run with GOARCH and GOOS set as ats.arch and ats.os respectively
+func (ats *asmTests) runGo(t *testing.T, args ...string) string {
+	var stdout, stderr bytes.Buffer
+	cmd := exec.Command(testenv.GoToolPath(t), args...)
+	cmd.Env = append(os.Environ(), "GOARCH="+ats.arch, "GOOS="+ats.os)
 	cmd.Stdout = &stdout
 	cmd.Stderr = &stderr
+
 	if err := cmd.Run(); err != nil {
-		panic(err)
+		t.Fatalf("error running cmd: %v\nstdout:\n%sstderr:\n%s\n", err, stdout.String(), stderr.String())
 	}
+
 	if s := stderr.String(); s != "" {
-		panic(fmt.Errorf("Stderr = %s\nWant empty", s))
+		t.Fatalf("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
-	// os to compile to
-	os string
-	// function to compile
-	function string
-	// regexps that must match the generated assembly
-	regexps []string
+var allAsmTests = []*asmTests{
+	{
+		arch:    "amd64",
+		os:      "linux",
+		imports: []string{"encoding/binary", "math/bits", "unsafe"},
+		tests:   linuxAMD64Tests,
+	},
+	{
+		arch:    "386",
+		os:      "linux",
+		imports: []string{"encoding/binary"},
+		tests:   linux386Tests,
+	},
+	{
+		arch:    "s390x",
+		os:      "linux",
+		imports: []string{"encoding/binary", "math/bits"},
+		tests:   linuxS390XTests,
+	},
+	{
+		arch:    "arm",
+		os:      "linux",
+		imports: []string{"math/bits"},
+		tests:   linuxARMTests,
+	},
+	{
+		arch:    "arm64",
+		os:      "linux",
+		imports: []string{"math/bits"},
+		tests:   linuxARM64Tests,
+	},
+	{
+		arch:    "mips",
+		os:      "linux",
+		imports: []string{"math/bits"},
+		tests:   linuxMIPSTests,
+	},
+	{
+		arch:  "ppc64le",
+		os:    "linux",
+		tests: linuxPPC64LETests,
+	},
 }
 
-var asmTests = [...]asmTest{
-	{"amd64", "linux", `
-func f(x int) int {
-	return x * 64
-}
-`,
+var linuxAMD64Tests = []*asmTest{
+	{
+		`
+		func f0(x int) int {
+			return x * 64
+		}
+		`,
 		[]string{"\tSHLQ\t\\$6,"},
 	},
-	{"amd64", "linux", `
-func f(x int) int {
-	return x * 96
-}`,
+	{
+		`
+		func f1(x int) int {
+			return x * 96
+		}
+		`,
 		[]string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
 	},
 	// Load-combining tests.
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte) uint64 {
-	return binary.LittleEndian.Uint64(b)
-}
-`,
+	{
+		`
+		func f2(b []byte) uint64 {
+			return binary.LittleEndian.Uint64(b)
+		}
+		`,
 		[]string{"\tMOVQ\t\\(.*\\),"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, i int) uint64 {
-	return binary.LittleEndian.Uint64(b[i:])
-}
-`,
+	{
+		`
+		func f3(b []byte, i int) uint64 {
+			return binary.LittleEndian.Uint64(b[i:])
+		}
+		`,
 		[]string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte) uint32 {
-	return binary.LittleEndian.Uint32(b)
-}
-`,
+	{
+		`
+		func f4(b []byte) uint32 {
+			return binary.LittleEndian.Uint32(b)
+		}
+		`,
 		[]string{"\tMOVL\t\\(.*\\),"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, i int) uint32 {
-	return binary.LittleEndian.Uint32(b[i:])
-}
-`,
+	{
+		`
+		func f5(b []byte, i int) uint32 {
+			return binary.LittleEndian.Uint32(b[i:])
+		}
+		`,
 		[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte) uint64 {
-	return binary.BigEndian.Uint64(b)
-}
-`,
+	{
+		`
+		func f6(b []byte) uint64 {
+			return binary.BigEndian.Uint64(b)
+		}
+		`,
 		[]string{"\tBSWAPQ\t"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, i int) uint64 {
-	return binary.BigEndian.Uint64(b[i:])
-}
-`,
+	{
+		`
+		func f7(b []byte, i int) uint64 {
+			return binary.BigEndian.Uint64(b[i:])
+		}
+		`,
 		[]string{"\tBSWAPQ\t"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, v uint64) {
-	binary.BigEndian.PutUint64(b, v)
-}
-`,
+	{
+		`
+		func f8(b []byte, v uint64) {
+			binary.BigEndian.PutUint64(b, v)
+		}
+		`,
 		[]string{"\tBSWAPQ\t"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte) uint32 {
-	return binary.BigEndian.Uint32(b)
-}
-`,
+	{
+		`
+		func f9(b []byte, i int, v uint64) {
+			binary.BigEndian.PutUint64(b[i:], v)
+		}
+		`,
+		[]string{"\tBSWAPQ\t"},
+	},
+	{
+		`
+		func f10(b []byte) uint32 {
+			return binary.BigEndian.Uint32(b)
+		}
+		`,
 		[]string{"\tBSWAPL\t"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, i int) uint32 {
-	return binary.BigEndian.Uint32(b[i:])
-}
-`,
+	{
+		`
+		func f11(b []byte, i int) uint32 {
+			return binary.BigEndian.Uint32(b[i:])
+		}
+		`,
 		[]string{"\tBSWAPL\t"},
 	},
-	{"amd64", "linux", `
-import "encoding/binary"
-func f(b []byte, v uint32) {
-	binary.BigEndian.PutUint32(b, v)
-}
-`,
+	{
+		`
+		func f12(b []byte, v uint32) {
+			binary.BigEndian.PutUint32(b, v)
+		}
+		`,
+		[]string{"\tBSWAPL\t"},
+	},
+	{
+		`
+		func f13(b []byte, i int, v uint32) {
+			binary.BigEndian.PutUint32(b[i:], v)
+		}
+		`,
+		[]string{"\tBSWAPL\t"},
+	},
+	{
+		`
+		func f14(b []byte) uint16 {
+			return binary.BigEndian.Uint16(b)
+		}
+		`,
+		[]string{"\tROLW\t\\$8,"},
+	},
+	{
+		`
+		func f15(b []byte, i int) uint16 {
+			return binary.BigEndian.Uint16(b[i:])
+		}
+		`,
+		[]string{"\tROLW\t\\$8,"},
+	},
+	{
+		`
+		func f16(b []byte, v uint16) {
+			binary.BigEndian.PutUint16(b, v)
+		}
+		`,
+		[]string{"\tROLW\t\\$8,"},
+	},
+	{
+		`
+		func f17(b []byte, i int, v uint16) {
+			binary.BigEndian.PutUint16(b[i:], v)
+		}
+		`,
+		[]string{"\tROLW\t\\$8,"},
+	},
+	// Structure zeroing.  See issue #18370.
+	{
+		`
+		type T1 struct {
+			a, b, c int
+		}
+		func f18(t *T1) {
+			*t = T1{}
+		}
+		`,
+		[]string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
+	},
+	// SSA-able composite literal initialization. Issue 18872.
+	{
+		`
+		type T18872 struct {
+			a, b, c, d int
+		}
+
+		func f18872(p *T18872) {
+			*p = T18872{1, 2, 3, 4}
+		}
+		`,
+		[]string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"},
+	},
+	// Also test struct containing pointers (this was special because of write barriers).
+	{
+		`
+		type T2 struct {
+			a, b, c *int
+		}
+		func f19(t *T2) {
+			*t = T2{}
+		}
+		`,
+		[]string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"},
+	},
+	// Rotate tests
+	{
+		`
+		func f20(x uint64) uint64 {
+			return x<<7 | x>>57
+		}
+		`,
+		[]string{"\tROLQ\t[$]7,"},
+	},
+	{
+		`
+		func f21(x uint64) uint64 {
+			return x<<7 + x>>57
+		}
+		`,
+		[]string{"\tROLQ\t[$]7,"},
+	},
+	{
+		`
+		func f22(x uint64) uint64 {
+			return x<<7 ^ x>>57
+		}
+		`,
+		[]string{"\tROLQ\t[$]7,"},
+	},
+	{
+		`
+		func f23(x uint32) uint32 {
+			return x<<7 + x>>25
+		}
+		`,
+		[]string{"\tROLL\t[$]7,"},
+	},
+	{
+		`
+		func f24(x uint32) uint32 {
+			return x<<7 | x>>25
+		}
+		`,
+		[]string{"\tROLL\t[$]7,"},
+	},
+	{
+		`
+		func f25(x uint32) uint32 {
+			return x<<7 ^ x>>25
+		}
+		`,
+		[]string{"\tROLL\t[$]7,"},
+	},
+	{
+		`
+		func f26(x uint16) uint16 {
+			return x<<7 + x>>9
+		}
+		`,
+		[]string{"\tROLW\t[$]7,"},
+	},
+	{
+		`
+		func f27(x uint16) uint16 {
+			return x<<7 | x>>9
+		}
+		`,
+		[]string{"\tROLW\t[$]7,"},
+	},
+	{
+		`
+		func f28(x uint16) uint16 {
+			return x<<7 ^ x>>9
+		}
+		`,
+		[]string{"\tROLW\t[$]7,"},
+	},
+	{
+		`
+		func f29(x uint8) uint8 {
+			return x<<7 + x>>1
+		}
+		`,
+		[]string{"\tROLB\t[$]7,"},
+	},
+	{
+		`
+		func f30(x uint8) uint8 {
+			return x<<7 | x>>1
+		}
+		`,
+		[]string{"\tROLB\t[$]7,"},
+	},
+	{
+		`
+		func f31(x uint8) uint8 {
+			return x<<7 ^ x>>1
+		}
+		`,
+		[]string{"\tROLB\t[$]7,"},
+	},
+	// Rotate after inlining (see issue 18254).
+	{
+		`
+		func f32(x uint32) uint32 {
+			return g(x, 7)
+		}
+		func g(x uint32, k uint) uint32 {
+			return x<<k | x>>(32-k)
+		}
+		`,
+		[]string{"\tROLL\t[$]7,"},
+	},
+	{
+		`
+		func f33(m map[int]int) int {
+			return m[5]
+		}
+		`,
+		[]string{"\tMOVQ\t[$]5,"},
+	},
+	// Direct use of constants in fast map access calls. Issue 19015.
+	{
+		`
+		func f34(m map[int]int) bool {
+			_, ok := m[5]
+			return ok
+		}
+		`,
+		[]string{"\tMOVQ\t[$]5,"},
+	},
+	{
+		`
+		func f35(m map[string]int) int {
+			return m["abc"]
+		}
+		`,
+		[]string{"\"abc\""},
+	},
+	{
+		`
+		func f36(m map[string]int) bool {
+			_, ok := m["abc"]
+			return ok
+		}
+		`,
+		[]string{"\"abc\""},
+	},
+	// Bit test ops on amd64, issue 18943.
+	{
+		`
+		func f37(a, b uint64) int {
+			if a&(1<<(b&63)) != 0 {
+				return 1
+			}
+			return -1
+		}
+		`,
+		[]string{"\tBTQ\t"},
+	},
+	{
+		`
+		func f38(a, b uint64) bool {
+			return a&(1<<(b&63)) != 0
+		}
+		`,
+		[]string{"\tBTQ\t"},
+	},
+	{
+		`
+		func f39(a uint64) int {
+			if a&(1<<60) != 0 {
+				return 1
+			}
+			return -1
+		}
+		`,
+		[]string{"\tBTQ\t\\$60"},
+	},
+	{
+		`
+		func f40(a uint64) bool {
+			return a&(1<<60) != 0
+		}
+		`,
+		[]string{"\tBTQ\t\\$60"},
+	},
+	// Intrinsic tests for math/bits
+	{
+		`
+		func f41(a uint64) int {
+			return bits.TrailingZeros64(a)
+		}
+		`,
+		[]string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"},
+	},
+	{
+		`
+		func f42(a uint32) int {
+			return bits.TrailingZeros32(a)
+		}
+		`,
+		[]string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"},
+	},
+	{
+		`
+		func f43(a uint16) int {
+			return bits.TrailingZeros16(a)
+		}
+		`,
+		[]string{"\tBSFQ\t", "\tORQ\t\\$65536,"},
+	},
+	{
+		`
+		func f44(a uint8) int {
+			return bits.TrailingZeros8(a)
+		}
+		`,
+		[]string{"\tBSFQ\t", "\tORQ\t\\$256,"},
+	},
+	{
+		`
+		func f45(a uint64) uint64 {
+			return bits.ReverseBytes64(a)
+		}
+		`,
+		[]string{"\tBSWAPQ\t"},
+	},
+	{
+		`
+		func f46(a uint32) uint32 {
+			return bits.ReverseBytes32(a)
+		}
+		`,
 		[]string{"\tBSWAPL\t"},
 	},
-	{"386", "linux", `
-import "encoding/binary"
-func f(b []byte) uint32 {
-	return binary.LittleEndian.Uint32(b)
+	{
+		`
+		func f47(a uint16) uint16 {
+			return bits.ReverseBytes16(a)
+		}
+		`,
+		[]string{"\tROLW\t\\$8,"},
+	},
+	{
+		`
+		func f48(a uint64) int {
+			return bits.Len64(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func f49(a uint32) int {
+			return bits.Len32(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func f50(a uint16) int {
+			return bits.Len16(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	/* see ssa.go
+	{
+		`
+		func f51(a uint8) int {
+			return bits.Len8(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	*/
+	{
+		`
+		func f52(a uint) int {
+			return bits.Len(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func f53(a uint64) int {
+			return bits.LeadingZeros64(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func f54(a uint32) int {
+			return bits.LeadingZeros32(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func f55(a uint16) int {
+			return bits.LeadingZeros16(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	/* see ssa.go
+	{
+		`
+		func f56(a uint8) int {
+			return bits.LeadingZeros8(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	*/
+	{
+		`
+		func f57(a uint) int {
+			return bits.LeadingZeros(a)
+		}
+		`,
+		[]string{"\tBSRQ\t"},
+	},
+	{
+		`
+		func pop1(x uint64) int {
+			return bits.OnesCount64(x)
+		}`,
+		[]string{"\tPOPCNTQ\t", "support_popcnt"},
+	},
+	{
+		`
+		func pop2(x uint32) int {
+			return bits.OnesCount32(x)
+		}`,
+		[]string{"\tPOPCNTL\t", "support_popcnt"},
+	},
+	{
+		`
+		func pop3(x uint16) int {
+			return bits.OnesCount16(x)
+		}`,
+		[]string{"\tPOPCNTL\t", "support_popcnt"},
+	},
+	{
+		`
+		func pop4(x uint) int {
+			return bits.OnesCount(x)
+		}`,
+		[]string{"\tPOPCNTQ\t", "support_popcnt"},
+	},
+	// see issue 19595.
+	// We want to merge load+op in f58, but not in f59.
+	{
+		`
+		func f58(p, q *int) {
+			x := *p
+			*q += x
+		}`,
+		[]string{"\tADDQ\t\\("},
+	},
+	{
+		`
+		func f59(p, q *int) {
+			x := *p
+			for i := 0; i < 10; i++ {
+				*q += x
+			}
+		}`,
+		[]string{"\tADDQ\t[A-Z]"},
+	},
+	// Floating-point strength reduction
+	{
+		`
+		func f60(f float64) float64 {
+			return f * 2.0
+		}`,
+		[]string{"\tADDSD\t"},
+	},
+	{
+		`
+		func f62(f float64) float64 {
+			return f / 16.0
+		}`,
+		[]string{"\tMULSD\t"},
+	},
+	{
+		`
+		func f63(f float64) float64 {
+			return f / 0.125
+		}`,
+		[]string{"\tMULSD\t"},
+	},
+	{
+		`
+		func f64(f float64) float64 {
+			return f / 0.5
+		}`,
+		[]string{"\tADDSD\t"},
+	},
+	// Check that compare to constant string uses 2/4/8 byte compares
+	{
+		`
+		func f65(a string) bool {
+		    return a == "xx"
+		}`,
+		[]string{"\tCMPW\t[A-Z]"},
+	},
+	{
+		`
+		func f66(a string) bool {
+		    return a == "xxxx"
+		}`,
+		[]string{"\tCMPL\t[A-Z]"},
+	},
+	{
+		`
+		func f67(a string) bool {
+		    return a == "xxxxxxxx"
+		}`,
+		[]string{"\tCMPQ\t[A-Z]"},
+	},
+	// Non-constant rotate
+	{
+		`func rot64l(x uint64, y int) uint64 {
+			z := uint(y & 63)
+			return x << z | x >> (64-z)
+		}`,
+		[]string{"\tROLQ\t"},
+	},
+	{
+		`func rot64r(x uint64, y int) uint64 {
+			z := uint(y & 63)
+			return x >> z | x << (64-z)
+		}`,
+		[]string{"\tRORQ\t"},
+	},
+	{
+		`func rot32l(x uint32, y int) uint32 {
+			z := uint(y & 31)
+			return x << z | x >> (32-z)
+		}`,
+		[]string{"\tROLL\t"},
+	},
+	{
+		`func rot32r(x uint32, y int) uint32 {
+			z := uint(y & 31)
+			return x >> z | x << (32-z)
+		}`,
+		[]string{"\tRORL\t"},
+	},
+	{
+		`func rot16l(x uint16, y int) uint16 {
+			z := uint(y & 15)
+			return x << z | x >> (16-z)
+		}`,
+		[]string{"\tROLW\t"},
+	},
+	{
+		`func rot16r(x uint16, y int) uint16 {
+			z := uint(y & 15)
+			return x >> z | x << (16-z)
+		}`,
+		[]string{"\tRORW\t"},
+	},
+	{
+		`func rot8l(x uint8, y int) uint8 {
+			z := uint(y & 7)
+			return x << z | x >> (8-z)
+		}`,
+		[]string{"\tROLB\t"},
+	},
+	{
+		`func rot8r(x uint8, y int) uint8 {
+			z := uint(y & 7)
+			return x >> z | x << (8-z)
+		}`,
+		[]string{"\tRORB\t"},
+	},
+	// Check that array compare uses 2/4/8 byte compares
+	{
+		`
+		func f68(a,b [2]byte) bool {
+		    return a == b
+		}`,
+		[]string{"\tCMPW\t[A-Z]"},
+	},
+	{
+		`
+		func f69(a,b [3]uint16) bool {
+		    return a == b
+		}`,
+		[]string{"\tCMPL\t[A-Z]"},
+	},
+	{
+		`
+		func f70(a,b [15]byte) bool {
+		    return a == b
+		}`,
+		[]string{"\tCMPQ\t[A-Z]"},
+	},
+	{
+		`
+		func f71(a,b unsafe.Pointer) bool { // This was a TODO in mapaccess1_faststr
+		    return *((*[4]byte)(a)) != *((*[4]byte)(b))
+		}`,
+		[]string{"\tCMPL\t[A-Z]"},
+	},
 }
-`,
+
+var linux386Tests = []*asmTest{
+	{
+		`
+		func f0(b []byte) uint32 {
+			return binary.LittleEndian.Uint32(b)
+		}
+		`,
 		[]string{"\tMOVL\t\\(.*\\),"},
 	},
-	{"386", "linux", `
-import "encoding/binary"
-func f(b []byte, i int) uint32 {
-	return binary.LittleEndian.Uint32(b[i:])
-}
-`,
+	{
+		`
+		func f1(b []byte, i int) uint32 {
+			return binary.LittleEndian.Uint32(b[i:])
+		}
+		`,
 		[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
 	},
+}
 
-	// Structure zeroing.  See issue #18370.
-	{"amd64", "linux", `
-type T struct {
-	a, b, c int
+var linuxS390XTests = []*asmTest{
+	{
+		`
+		func f0(b []byte) uint32 {
+			return binary.LittleEndian.Uint32(b)
+		}
+		`,
+		[]string{"\tMOVWBR\t\\(.*\\),"},
+	},
+	{
+		`
+		func f1(b []byte, i int) uint32 {
+			return binary.LittleEndian.Uint32(b[i:])
+		}
+		`,
+		[]string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
+	},
+	{
+		`
+		func f2(b []byte) uint64 {
+			return binary.LittleEndian.Uint64(b)
+		}
+		`,
+		[]string{"\tMOVDBR\t\\(.*\\),"},
+	},
+	{
+		`
+		func f3(b []byte, i int) uint64 {
+			return binary.LittleEndian.Uint64(b[i:])
+		}
+		`,
+		[]string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
+	},
+	{
+		`
+		func f4(b []byte) uint32 {
+			return binary.BigEndian.Uint32(b)
+		}
+		`,
+		[]string{"\tMOVWZ\t\\(.*\\),"},
+	},
+	{
+		`
+		func f5(b []byte, i int) uint32 {
+			return binary.BigEndian.Uint32(b[i:])
+		}
+		`,
+		[]string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"},
+	},
+	{
+		`
+		func f6(b []byte) uint64 {
+			return binary.BigEndian.Uint64(b)
+		}
+		`,
+		[]string{"\tMOVD\t\\(.*\\),"},
+	},
+	{
+		`
+		func f7(b []byte, i int) uint64 {
+			return binary.BigEndian.Uint64(b[i:])
+		}
+		`,
+		[]string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"},
+	},
+	{
+		`
+		func f8(x uint64) uint64 {
+			return x<<7 + x>>57
+		}
+		`,
+		[]string{"\tRLLG\t[$]7,"},
+	},
+	{
+		`
+		func f9(x uint64) uint64 {
+			return x<<7 | x>>57
+		}
+		`,
+		[]string{"\tRLLG\t[$]7,"},
+	},
+	{
+		`
+		func f10(x uint64) uint64 {
+			return x<<7 ^ x>>57
+		}
+		`,
+		[]string{"\tRLLG\t[$]7,"},
+	},
+	{
+		`
+		func f11(x uint32) uint32 {
+			return x<<7 + x>>25
+		}
+		`,
+		[]string{"\tRLL\t[$]7,"},
+	},
+	{
+		`
+		func f12(x uint32) uint32 {
+			return x<<7 | x>>25
+		}
+		`,
+		[]string{"\tRLL\t[$]7,"},
+	},
+	{
+		`
+		func f13(x uint32) uint32 {
+			return x<<7 ^ x>>25
+		}
+		`,
+		[]string{"\tRLL\t[$]7,"},
+	},
+	// Fused multiply-add/sub instructions.
+	{
+		`
+		func f14(x, y, z float64) float64 {
+			return x * y + z
+		}
+		`,
+		[]string{"\tFMADD\t"},
+	},
+	{
+		`
+		func f15(x, y, z float64) float64 {
+			return x * y - z
+		}
+		`,
+		[]string{"\tFMSUB\t"},
+	},
+	{
+		`
+		func f16(x, y, z float32) float32 {
+			return x * y + z
+		}
+		`,
+		[]string{"\tFMADDS\t"},
+	},
+	{
+		`
+		func f17(x, y, z float32) float32 {
+			return x * y - z
+		}
+		`,
+		[]string{"\tFMSUBS\t"},
+	},
+	// Intrinsic tests for math/bits
+	{
+		`
+		func f18(a uint64) int {
+			return bits.TrailingZeros64(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f19(a uint32) int {
+			return bits.TrailingZeros32(a)
+		}
+		`,
+		[]string{"\tFLOGR\t", "\tMOVWZ\t"},
+	},
+	{
+		`
+		func f20(a uint16) int {
+			return bits.TrailingZeros16(a)
+		}
+		`,
+		[]string{"\tFLOGR\t", "\tOR\t\\$65536,"},
+	},
+	{
+		`
+		func f21(a uint8) int {
+			return bits.TrailingZeros8(a)
+		}
+		`,
+		[]string{"\tFLOGR\t", "\tOR\t\\$256,"},
+	},
+	// Intrinsic tests for math/bits
+	{
+		`
+		func f22(a uint64) uint64 {
+			return bits.ReverseBytes64(a)
+		}
+		`,
+		[]string{"\tMOVDBR\t"},
+	},
+	{
+		`
+		func f23(a uint32) uint32 {
+			return bits.ReverseBytes32(a)
+		}
+		`,
+		[]string{"\tMOVWBR\t"},
+	},
+	{
+		`
+		func f24(a uint64) int {
+			return bits.Len64(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f25(a uint32) int {
+			return bits.Len32(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f26(a uint16) int {
+			return bits.Len16(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f27(a uint8) int {
+			return bits.Len8(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f28(a uint) int {
+			return bits.Len(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f29(a uint64) int {
+			return bits.LeadingZeros64(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f30(a uint32) int {
+			return bits.LeadingZeros32(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f31(a uint16) int {
+			return bits.LeadingZeros16(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f32(a uint8) int {
+			return bits.LeadingZeros8(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
+	{
+		`
+		func f33(a uint) int {
+			return bits.LeadingZeros(a)
+		}
+		`,
+		[]string{"\tFLOGR\t"},
+	},
 }
-func f(t *T) {
-	*t = T{}
+
+var linuxARMTests = []*asmTest{
+	{
+		`
+		func f0(x uint32) uint32 {
+			return x<<7 + x>>25
+		}
+		`,
+		[]string{"\tMOVW\tR[0-9]+@>25,"},
+	},
+	{
+		`
+		func f1(x uint32) uint32 {
+			return x<<7 | x>>25
+		}
+		`,
+		[]string{"\tMOVW\tR[0-9]+@>25,"},
+	},
+	{
+		`
+		func f2(x uint32) uint32 {
+			return x<<7 ^ x>>25
+		}
+		`,
+		[]string{"\tMOVW\tR[0-9]+@>25,"},
+	},
+	{
+		`
+		func f3(a uint64) int {
+			return bits.Len64(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f4(a uint32) int {
+			return bits.Len32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f5(a uint16) int {
+			return bits.Len16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f6(a uint8) int {
+			return bits.Len8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f7(a uint) int {
+			return bits.Len(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f8(a uint64) int {
+			return bits.LeadingZeros64(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f9(a uint32) int {
+			return bits.LeadingZeros32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f10(a uint16) int {
+			return bits.LeadingZeros16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f11(a uint8) int {
+			return bits.LeadingZeros8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f12(a uint) int {
+			return bits.LeadingZeros(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
 }
-`,
-		[]string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
+
+var linuxARM64Tests = []*asmTest{
+	{
+		`
+		func f0(x uint64) uint64 {
+			return x<<7 + x>>57
+		}
+		`,
+		[]string{"\tROR\t[$]57,"},
+	},
+	{
+		`
+		func f1(x uint64) uint64 {
+			return x<<7 | x>>57
+		}
+		`,
+		[]string{"\tROR\t[$]57,"},
+	},
+	{
+		`
+		func f2(x uint64) uint64 {
+			return x<<7 ^ x>>57
+		}
+		`,
+		[]string{"\tROR\t[$]57,"},
+	},
+	{
+		`
+		func f3(x uint32) uint32 {
+			return x<<7 + x>>25
+		}
+		`,
+		[]string{"\tRORW\t[$]25,"},
+	},
+	{
+		`
+		func f4(x uint32) uint32 {
+			return x<<7 | x>>25
+		}
+		`,
+		[]string{"\tRORW\t[$]25,"},
+	},
+	{
+		`
+		func f5(x uint32) uint32 {
+			return x<<7 ^ x>>25
+		}
+		`,
+		[]string{"\tRORW\t[$]25,"},
+	},
+	{
+		`
+		func f22(a uint64) uint64 {
+			return bits.ReverseBytes64(a)
+		}
+		`,
+		[]string{"\tREV\t"},
+	},
+	{
+		`
+		func f23(a uint32) uint32 {
+			return bits.ReverseBytes32(a)
+		}
+		`,
+		[]string{"\tREVW\t"},
+	},
+	{
+		`
+		func f24(a uint64) int {
+			return bits.Len64(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f25(a uint32) int {
+			return bits.Len32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f26(a uint16) int {
+			return bits.Len16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f27(a uint8) int {
+			return bits.Len8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f28(a uint) int {
+			return bits.Len(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f29(a uint64) int {
+			return bits.LeadingZeros64(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f30(a uint32) int {
+			return bits.LeadingZeros32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f31(a uint16) int {
+			return bits.LeadingZeros16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f32(a uint8) int {
+			return bits.LeadingZeros8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f33(a uint) int {
+			return bits.LeadingZeros(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f34(a uint64) uint64 {
+			return a & ((1<<63)-1)
+		}
+		`,
+		[]string{"\tAND\t"},
+	},
+	{
+		`
+		func f35(a uint64) uint64 {
+			return a & (1<<63)
+		}
+		`,
+		[]string{"\tAND\t"},
+	},
+	{
+		// make sure offsets are folded into load and store.
+		`
+		func f36(_, a [20]byte) (b [20]byte) {
+			b = a
+			return
+		}
+		`,
+		[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(RSP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(RSP\\)"},
 	},
-	// TODO: add a test for *t = T{3,4,5} when we fix that.
 }
 
-// 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
-			}
+var linuxMIPSTests = []*asmTest{
+	{
+		`
+		func f0(a uint64) int {
+			return bits.Len64(a)
 		}
-		out = append(out, inkv)
-	}
-	return out
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f1(a uint32) int {
+			return bits.Len32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f2(a uint16) int {
+			return bits.Len16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f3(a uint8) int {
+			return bits.Len8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f4(a uint) int {
+			return bits.Len(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f5(a uint64) int {
+			return bits.LeadingZeros64(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f6(a uint32) int {
+			return bits.LeadingZeros32(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f7(a uint16) int {
+			return bits.LeadingZeros16(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f8(a uint8) int {
+			return bits.LeadingZeros8(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+	{
+		`
+		func f9(a uint) int {
+			return bits.LeadingZeros(a)
+		}
+		`,
+		[]string{"\tCLZ\t"},
+	},
+}
+
+var linuxPPC64LETests = []*asmTest{
+	// Fused multiply-add/sub instructions.
+	{
+		`
+		func f0(x, y, z float64) float64 {
+			return x * y + z
+		}
+		`,
+		[]string{"\tFMADD\t"},
+	},
+	{
+		`
+		func f1(x, y, z float64) float64 {
+			return x * y - z
+		}
+		`,
+		[]string{"\tFMSUB\t"},
+	},
+	{
+		`
+		func f2(x, y, z float32) float32 {
+			return x * y + z
+		}
+		`,
+		[]string{"\tFMADDS\t"},
+	},
+	{
+		`
+		func f3(x, y, z float32) float32 {
+			return x * y - z
+		}
+		`,
+		[]string{"\tFMSUBS\t"},
+	},
+	{
+		`
+		func f4(x uint32) uint32 {
+			return x<<7 | x>>25
+		}
+		`,
+		[]string{"\tROTLW\t"},
+	},
+	{
+		`
+		func f5(x uint32) uint32 {
+			return x<<7 + x>>25
+		}
+		`,
+		[]string{"\tROTLW\t"},
+	},
+	{
+		`
+		func f6(x uint32) uint32 {
+			return x<<7 ^ x>>25
+		}
+		`,
+		[]string{"\tROTLW\t"},
+	},
+	{
+		`
+		func f7(x uint64) uint64 {
+			return x<<7 | x>>57
+		}
+		`,
+		[]string{"\tROTL\t"},
+	},
+	{
+		`
+		func f8(x uint64) uint64 {
+			return x<<7 + x>>57
+		}
+		`,
+		[]string{"\tROTL\t"},
+	},
+	{
+		`
+		func f9(x uint64) uint64 {
+			return x<<7 ^ x>>57
+		}
+		`,
+		[]string{"\tROTL\t"},
+	},
 }
 
 // TestLineNumber checks to make sure the generated assembly has line numbers
@@ -286,6 +1675,6 @@ 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
+	return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
 }
 `
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index ffc5419..0c19ad9 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -114,6 +114,7 @@ package gc
 import (
 	"bufio"
 	"bytes"
+	"cmd/compile/internal/types"
 	"encoding/binary"
 	"fmt"
 	"math/big"
@@ -133,18 +134,14 @@ import (
 // (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
-
 // Current export format version. Increase with each format change.
-// 3: added aliasTag and export of aliases
-// 2: removed unused bool in ODCL export
+// 5: improved position encoding efficiency (issue 20080, CL 41619)
+// 4: type name objects support type aliases, uses aliasTag
+// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
+// 2: removed unused bool in ODCL export (compiler only)
 // 1: header format change (more regular), export package for _ struct fields
 // 0: Go1.7 encoding
-const exportVersion = 3
+const exportVersion = 5
 
 // exportInlined enables the export of inlined function bodies and related
 // dependencies. The compiler should work w/o any loss of functionality with
@@ -161,17 +158,21 @@ const exportInlined = true // default: true
 // less efficient encoding in rare cases. It also prevents the export of
 // some corner-case type declarations (but those were not handled correctly
 // with the former textual export format either).
-// TODO(gri) enable and remove once issues caused by it are fixed
+// Note that when a type is only seen once, as many unnamed types are,
+// it is less efficient to track it, since we then also record an index for it.
+// See CLs 41622 and 41623 for some data and discussion.
+// TODO(gri) enable selectively 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
+	strIndex  map[string]int
+	pathIndex map[string]int
+	pkgIndex  map[*types.Pkg]int
+	typIndex  map[*types.Type]int
+	funcList  []*Func
 
 	// position encoding
 	posInfoFormat bool
@@ -182,9 +183,6 @@ type exporter struct {
 	written int // bytes written
 	indent  int // for p.trace
 	trace   bool
-
-	// work-around for issue #16369 only
-	nesting int // amount of "nesting" of interface types
 }
 
 // export writes the exportlist for localpkg to out and returns the number of bytes written.
@@ -192,8 +190,9 @@ 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),
+		pathIndex:     map[string]int{"": 0}, // empty path is mapped to 0
+		pkgIndex:      make(map[*types.Pkg]int),
+		typIndex:      make(map[*types.Type]int),
 		posInfoFormat: true,
 		trace:         trace,
 	}
@@ -256,10 +255,10 @@ func export(out *bufio.Writer, trace bool) int {
 	for _, n := range exportlist {
 		sym := n.Sym
 
-		if sym.Flags&SymExported != 0 {
+		if sym.Exported() {
 			continue
 		}
-		sym.Flags |= SymExported
+		sym.SetExported(true)
 
 		// TODO(gri) Closures have dots in their names;
 		// e.g., TestFloatZeroValue.func1 in math/big tests.
@@ -267,11 +266,6 @@ func export(out *bufio.Writer, trace bool) int {
 			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)
 		}
@@ -323,10 +317,10 @@ func export(out *bufio.Writer, trace bool) int {
 		// are different optimization opportunities, but factor
 		// eventually.
 
-		if sym.Flags&SymExported != 0 {
+		if sym.Exported() {
 			continue
 		}
-		sym.Flags |= SymExported
+		sym.SetExported(true)
 
 		// TODO(gri) Closures have dots in their names;
 		// e.g., TestFloatZeroValue.func1 in math/big tests.
@@ -334,11 +328,6 @@ func export(out *bufio.Writer, trace bool) int {
 			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)
 		}
@@ -351,8 +340,8 @@ func export(out *bufio.Writer, trace bool) int {
 			p.tracef("\n")
 		}
 
-		if sym.Flags&SymAlias != 0 {
-			Fatalf("exporter: unexpected alias %v in inlined function body", sym)
+		if IsAlias(sym) {
+			Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
 		}
 
 		p.obj(sym)
@@ -413,7 +402,7 @@ func export(out *bufio.Writer, trace bool) int {
 	return p.written
 }
 
-func (p *exporter) pkg(pkg *Pkg) {
+func (p *exporter) pkg(pkg *types.Pkg) {
 	if pkg == nil {
 		Fatalf("exporter: unexpected nil pkg")
 	}
@@ -433,10 +422,10 @@ func (p *exporter) pkg(pkg *Pkg) {
 
 	p.tag(packageTag)
 	p.string(pkg.Name)
-	p.string(pkg.Path)
+	p.path(pkg.Path)
 }
 
-func unidealType(typ *Type, val Val) *Type {
+func unidealType(typ *types.Type, val Val) *types.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() {
@@ -445,31 +434,7 @@ func unidealType(typ *Type, val Val) *Type {
 	return typ
 }
 
-func (p *exporter) obj(sym *Sym) {
-	if sym.Flags&SymAlias != 0 {
-		p.tag(aliasTag)
-		p.pos(nil) // TODO(gri) fix position information
-		// Aliases can only be exported from the package that
-		// declares them (aliases to aliases are resolved to the
-		// original object, and so are uses of aliases in inlined
-		// exported function bodies). Thus, we only need the alias
-		// name without package qualification.
-		if sym.Pkg != localpkg {
-			Fatalf("exporter: export of non-local alias: %v", sym)
-		}
-		p.string(sym.Name)
-		orig := sym.Def.Sym
-		if orig.Flags&SymAlias != 0 {
-			Fatalf("exporter: original object %v marked as alias", sym)
-		}
-		p.qualifiedName(orig)
-		return
-	}
-
-	if sym != sym.Def.Sym {
-		Fatalf("exporter: exported object %v is not original %v", sym, sym.Def.Sym)
-	}
-
+func (p *exporter) obj(sym *types.Sym) {
 	// Exported objects may be from different packages because they
 	// may be re-exported via an exported alias or as dependencies in
 	// exported inlined function bodies. Thus, exported object names
@@ -482,7 +447,7 @@ func (p *exporter) obj(sym *Sym) {
 	// pulled in via inlined function bodies. In that case the package
 	// qualifier is not needed. Possible space optimization.)
 
-	n := sym.Def
+	n := asNode(sym.Def)
 	switch n.Op {
 	case OLITERAL:
 		// constant
@@ -509,7 +474,13 @@ func (p *exporter) obj(sym *Sym) {
 			Fatalf("exporter: export of incomplete type %v", sym)
 		}
 
-		p.tag(typeTag)
+		if IsAlias(sym) {
+			p.tag(aliasTag)
+			p.pos(n)
+			p.qualifiedName(sym)
+		} else {
+			p.tag(typeTag)
+		}
 		p.typ(t)
 
 	case ONAME:
@@ -519,28 +490,21 @@ func (p *exporter) obj(sym *Sym) {
 			Fatalf("exporter: variable/function exported but not defined: %v", sym)
 		}
 
-		if n.Type.Etype == TFUNC && n.Class == PFUNC {
+		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)
+			sig := asNode(sym.Def).Type
+			inlineable := isInlineable(asNode(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.
+				f = asNode(sym.Def).Func
 				reexportdeplist(f.Inl)
 			}
 			p.funcList = append(p.funcList, f)
@@ -549,7 +513,7 @@ func (p *exporter) obj(sym *Sym) {
 			p.tag(varTag)
 			p.pos(n)
 			p.qualifiedName(sym)
-			p.typ(sym.Def.Type)
+			p.typ(asNode(sym.Def).Type)
 		}
 
 	default:
@@ -557,6 +521,11 @@ func (p *exporter) obj(sym *Sym) {
 	}
 }
 
+// deltaNewFile is a magic line delta offset indicating a new file.
+// We use -64 because it is rare; see issue 20080 and CL 41619.
+// -64 is the smallest int that fits in a single byte as a varint.
+const deltaNewFile = -64
+
 func (p *exporter) pos(n *Node) {
 	if !p.posInfoFormat {
 		return
@@ -565,47 +534,46 @@ func (p *exporter) pos(n *Node) {
 	file, line := fileLine(n)
 	if file == p.prevFile {
 		// common case: write line delta
-		// delta == 0 means different file or no line change
+		// delta == deltaNewFile means different file
+		// if the actual line delta is deltaNewFile,
+		// follow up with a negative int to indicate that.
+		// only non-negative ints can follow deltaNewFile
+		// when writing a new file.
 		delta := line - p.prevLine
 		p.int(delta)
-		if delta == 0 {
+		if delta == deltaNewFile {
 			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.int(deltaNewFile)
+		p.int(line) // line >= 0
+		p.path(file)
 		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))
+func (p *exporter) path(s string) {
+	if i, ok := p.pathIndex[s]; ok {
+		p.index('p', i) // i >= 0
+		return
+	}
+	p.pathIndex[s] = len(p.pathIndex)
+	c := strings.Split(s, "/")
+	p.int(-len(c)) // -len(c) < 0
+	for _, x := range c {
+		p.string(x)
 	}
-	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++
+func fileLine(n *Node) (file string, line int) {
+	if n != nil {
+		pos := Ctxt.PosTable.Pos(n.Pos)
+		file = pos.Base().AbsFilename()
+		line = int(pos.RelLine())
 	}
-	return i
+	return
 }
 
 func isInlineable(n *Node) bool {
@@ -620,9 +588,9 @@ func isInlineable(n *Node) bool {
 	return false
 }
 
-var errorInterface *Type // lazily initialized
+var errorInterface *types.Type // lazily initialized
 
-func (p *exporter) typ(t *Type) {
+func (p *exporter) typ(t *types.Type) {
 	if t == nil {
 		Fatalf("exporter: nil type")
 	}
@@ -674,7 +642,7 @@ func (p *exporter) typ(t *Type) {
 
 		// write underlying type
 		orig := t.Orig
-		if orig == errortype {
+		if orig == types.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
@@ -695,7 +663,7 @@ func (p *exporter) typ(t *Type) {
 		// sort methods for reproducible export format
 		// TODO(gri) Determine if they are already sorted
 		// in which case we can drop this step.
-		var methods []*Field
+		var methods []*types.Field
 		for _, m := range t.Methods().Slice() {
 			methods = append(methods, m)
 		}
@@ -714,22 +682,22 @@ func (p *exporter) typ(t *Type) {
 				Fatalf("invalid symbol name: %s (%v)", m.Sym.Name, m.Sym)
 			}
 
-			p.pos(m.Nname)
+			p.pos(asNode(m.Nname))
 			p.fieldSym(m.Sym, false)
 
 			sig := m.Type
-			mfn := sig.Nname()
+			mfn := asNode(sig.FuncType().Nname)
 			inlineable := isInlineable(mfn)
 
 			p.paramList(sig.Recvs(), inlineable)
 			p.paramList(sig.Params(), inlineable)
 			p.paramList(sig.Results(), inlineable)
-			p.bool(m.Nointerface) // record go:nointerface pragma value (see also #16243)
+			p.bool(m.Nointerface()) // record go:nointerface pragma value (see also #16243)
 
 			var f *Func
 			if inlineable {
 				f = mfn.Func
-				reexportdeplist(mfn.Func.Inl)
+				reexportdeplist(f.Inl)
 			}
 			p.funcList = append(p.funcList, f)
 		}
@@ -744,7 +712,7 @@ func (p *exporter) typ(t *Type) {
 	// otherwise we have a type literal
 	switch t.Etype {
 	case TARRAY:
-		if t.isDDDArray() {
+		if t.IsDDDArray() {
 			Fatalf("array bounds should be known at export time: %v", t)
 		}
 		p.tag(arrayTag)
@@ -775,39 +743,7 @@ func (p *exporter) typ(t *Type) {
 
 	case TINTER:
 		p.tag(interfaceTag)
-		// gc doesn't separate between embedded interfaces
-		// and methods declared explicitly with an interface
-		p.int(0) // no embedded interfaces
-
-		// Because the compiler flattens interfaces containing
-		// embedded interfaces, it is possible to create interface
-		// types that recur through an unnamed type.
-		// If trackAllTypes is disabled, such recursion is not
-		// detected, leading to a stack overflow during export
-		// (issue #16369).
-		// As a crude work-around we terminate deep recursion
-		// through interface types with an empty interface and
-		// report an error.
-		// This will catch endless recursion, but is unlikely
-		// to trigger for valid, deeply nested types given the
-		// high threshold.
-		// It would be ok to continue without reporting an error
-		// since the export format is valid. But a subsequent
-		// import would import an incorrect type. The textual
-		// exporter does not report an error but importing the
-		// resulting package will lead to a syntax error during
-		// import.
-		// TODO(gri) remove this once we have a permanent fix
-		// for the issue.
-		if p.nesting > 100 {
-			p.int(0) // 0 methods to indicate empty interface
-			yyerrorl(t.Lineno, "cannot export unnamed recursive interface")
-			break
-		}
-
-		p.nesting++
 		p.methodList(t)
-		p.nesting--
 
 	case TMAP:
 		p.tag(mapTag)
@@ -824,12 +760,12 @@ func (p *exporter) typ(t *Type) {
 	}
 }
 
-func (p *exporter) qualifiedName(sym *Sym) {
+func (p *exporter) qualifiedName(sym *types.Sym) {
 	p.string(sym.Name)
 	p.pkg(sym.Pkg)
 }
 
-func (p *exporter) fieldList(t *Type) {
+func (p *exporter) fieldList(t *types.Type) {
 	if p.trace && t.NumFields() > 0 {
 		p.tracef("fields {>")
 		defer p.tracef("<\n} ")
@@ -844,43 +780,79 @@ func (p *exporter) fieldList(t *Type) {
 	}
 }
 
-func (p *exporter) field(f *Field) {
-	p.pos(f.Nname)
+func (p *exporter) field(f *types.Field) {
+	p.pos(asNode(f.Nname))
 	p.fieldName(f)
 	p.typ(f.Type)
 	p.string(f.Note)
 }
 
-func (p *exporter) methodList(t *Type) {
-	if p.trace && t.NumFields() > 0 {
-		p.tracef("methods {>")
-		defer p.tracef("<\n} ")
+func (p *exporter) methodList(t *types.Type) {
+	var embeddeds, methods []*types.Field
+
+	for _, m := range t.Methods().Slice() {
+		if m.Sym != nil {
+			methods = append(methods, m)
+		} else {
+			embeddeds = append(embeddeds, m)
+		}
 	}
 
-	p.int(t.NumFields())
-	for _, m := range t.Fields().Slice() {
+	if p.trace && len(embeddeds) > 0 {
+		p.tracef("embeddeds {>")
+	}
+	p.int(len(embeddeds))
+	for _, m := range embeddeds {
+		if p.trace {
+			p.tracef("\n")
+		}
+		p.pos(asNode(m.Nname))
+		p.typ(m.Type)
+	}
+	if p.trace && len(embeddeds) > 0 {
+		p.tracef("<\n} ")
+	}
+
+	if p.trace && len(methods) > 0 {
+		p.tracef("methods {>")
+	}
+	p.int(len(methods))
+	for _, m := range methods {
 		if p.trace {
 			p.tracef("\n")
 		}
 		p.method(m)
 	}
+	if p.trace && len(methods) > 0 {
+		p.tracef("<\n} ")
+	}
 }
 
-func (p *exporter) method(m *Field) {
-	p.pos(m.Nname)
-	p.fieldName(m)
+func (p *exporter) method(m *types.Field) {
+	p.pos(asNode(m.Nname))
+	p.methodName(m.Sym)
 	p.paramList(m.Type.Params(), false)
 	p.paramList(m.Type.Results(), false)
 }
 
-// fieldName is like qualifiedName but it doesn't record the package for exported names.
-func (p *exporter) fieldName(t *Field) {
+func (p *exporter) fieldName(t *types.Field) {
 	name := t.Sym.Name
 	if t.Embedded != 0 {
-		name = "" // anonymous field
-		if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
-			// anonymous field with unexported base type name
-			name = "?" // unexported name to force export of package
+		// anonymous field - we distinguish between 3 cases:
+		// 1) field name matches base type name and is exported
+		// 2) field name matches base type name and is not exported
+		// 3) field name doesn't match base type name (alias name)
+		bname := basetypeName(t.Type)
+		if name == bname {
+			if exportname(name) {
+				name = "" // 1) we don't need to know the field name or package
+			} else {
+				name = "?" // 2) use unexported name "?" to force package export
+			}
+		} else {
+			// 3) indicate alias and export name as is
+			// (this requires an extra "@" but this is a rare case)
+			p.string("@")
 		}
 	}
 	p.string(name)
@@ -889,19 +861,26 @@ func (p *exporter) fieldName(t *Field) {
 	}
 }
 
-func basetypeName(t *Type) string {
+// methodName is like qualifiedName but it doesn't record the package for exported names.
+func (p *exporter) methodName(sym *types.Sym) {
+	p.string(sym.Name)
+	if !exportname(sym.Name) {
+		p.pkg(sym.Pkg)
+	}
+}
+
+func basetypeName(t *types.Type) string {
 	s := t.Sym
 	if s == nil && t.IsPtr() {
 		s = t.Elem().Sym // deref
 	}
-	// s should exist, but be conservative
 	if s != nil {
 		return s.Name
 	}
-	return ""
+	return "" // unnamed type
 }
 
-func (p *exporter) paramList(params *Type, numbered bool) {
+func (p *exporter) paramList(params *types.Type, numbered bool) {
 	if !params.IsFuncArgStruct() {
 		Fatalf("exporter: parameter list expected")
 	}
@@ -924,11 +903,11 @@ func (p *exporter) paramList(params *Type, numbered bool) {
 	}
 }
 
-func (p *exporter) param(q *Field, n int, numbered bool) {
+func (p *exporter) param(q *types.Field, n int, numbered bool) {
 	t := q.Type
-	if q.Isddd {
+	if q.Isddd() {
 		// create a fake type to encode ... just for the p.typ call
-		t = typDDDField(t.Elem())
+		t = types.NewDDDField(t.Elem())
 	}
 	p.typ(t)
 	if n > 0 {
@@ -967,7 +946,7 @@ func (p *exporter) param(q *Field, n int, numbered bool) {
 	p.string(q.Note)
 }
 
-func parName(f *Field, numbered bool) string {
+func parName(f *types.Field, numbered bool) string {
 	s := f.Sym
 	if s == nil {
 		return ""
@@ -975,9 +954,9 @@ func parName(f *Field, numbered bool) string {
 
 	// 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 asNode(f.Nname) != nil {
+		if asNode(f.Nname).Orig != nil {
+			s = asNode(f.Nname).Orig.Sym
 			if s != nil && s.Name[0] == '~' {
 				if s.Name[1] == 'r' { // originally an unnamed result
 					return "" // s = nil
@@ -1003,9 +982,9 @@ func parName(f *Field, numbered bool) string {
 	// Functions that can be inlined use numbered parameters so we can distinguish 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
+	if numbered {
+		if !strings.Contains(name, "·") && asNode(f.Nname) != nil && asNode(f.Nname).Name != nil && asNode(f.Nname).Name.Vargen > 0 {
+			name = fmt.Sprintf("%s·%d", name, asNode(f.Nname).Name.Vargen) // append Vargen
 		}
 	} else {
 		if i := strings.Index(name, "·"); i > 0 {
@@ -1188,7 +1167,7 @@ func (p *exporter) expr(n *Node) {
 	// }
 
 	// from exprfmt (fmt.go)
-	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
+	for n != nil && n.Implicit() && (n.Op == OIND || n.Op == OADDR) {
 		n = n.Left
 	}
 
@@ -1207,6 +1186,7 @@ func (p *exporter) expr(n *Node) {
 			break
 		}
 		p.op(OLITERAL)
+		p.pos(n)
 		p.typ(unidealType(n.Type, n.Val()))
 		p.value(n.Val())
 
@@ -1215,12 +1195,14 @@ func (p *exporter) expr(n *Node) {
 		// _ 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.pos(n)
 			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.pos(n)
 			p.sym(n)
 			break
 		}
@@ -1230,12 +1212,14 @@ func (p *exporter) expr(n *Node) {
 		// 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.pos(n)
 			p.expr(n.Left) // n.Left.Op == OTYPE
 			p.fieldSym(n.Right.Sym, true)
 			break
 		}
 
 		p.op(ONAME)
+		p.pos(n)
 		p.sym(n)
 
 	// case OPACK, ONONAME:
@@ -1243,6 +1227,7 @@ func (p *exporter) expr(n *Node) {
 
 	case OTYPE:
 		p.op(OTYPE)
+		p.pos(n)
 		if p.bool(n.Type == nil) {
 			p.sym(n)
 		} else {
@@ -1260,21 +1245,25 @@ func (p *exporter) expr(n *Node) {
 
 	case OPTRLIT:
 		p.op(OPTRLIT)
+		p.pos(n)
 		p.expr(n.Left)
-		p.bool(n.Implicit)
+		p.bool(n.Implicit())
 
 	case OSTRUCTLIT:
 		p.op(OSTRUCTLIT)
+		p.pos(n)
 		p.typ(n.Type)
 		p.elemList(n.List) // special handling of field names
 
 	case OARRAYLIT, OSLICELIT, OMAPLIT:
 		p.op(OCOMPLIT)
+		p.pos(n)
 		p.typ(n.Type)
 		p.exprList(n.List)
 
 	case OKEY:
 		p.op(OKEY)
+		p.pos(n)
 		p.exprsOrNil(n.Left, n.Right)
 
 	// case OSTRUCTKEY:
@@ -1285,31 +1274,32 @@ func (p *exporter) expr(n *Node) {
 
 	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
 		p.op(OXDOT)
+		p.pos(n)
 		p.expr(n.Left)
 		p.fieldSym(n.Sym, true)
 
 	case ODOTTYPE, ODOTTYPE2:
 		p.op(ODOTTYPE)
+		p.pos(n)
 		p.expr(n.Left)
-		if p.bool(n.Right != nil) {
-			p.expr(n.Right)
-		} else {
-			p.typ(n.Type)
-		}
+		p.typ(n.Type)
 
 	case OINDEX, OINDEXMAP:
 		p.op(OINDEX)
+		p.pos(n)
 		p.expr(n.Left)
 		p.expr(n.Right)
 
 	case OSLICE, OSLICESTR, OSLICEARR:
 		p.op(OSLICE)
+		p.pos(n)
 		p.expr(n.Left)
 		low, high, _ := n.SliceBounds()
 		p.exprsOrNil(low, high)
 
 	case OSLICE3, OSLICE3ARR:
 		p.op(OSLICE3)
+		p.pos(n)
 		p.expr(n.Left)
 		low, high, max := n.SliceBounds()
 		p.exprsOrNil(low, high)
@@ -1318,22 +1308,20 @@ func (p *exporter) expr(n *Node) {
 	case OCOPY, OCOMPLEX:
 		// treated like other builtin calls (see e.g., OREAL)
 		p.op(op)
+		p.pos(n)
 		p.expr(n.Left)
 		p.expr(n.Right)
 		p.op(OEND)
 
 	case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
 		p.op(OCONV)
+		p.pos(n)
+		p.expr(n.Left)
 		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)
+		p.pos(n)
 		if n.Left != nil {
 			p.expr(n.Left)
 			p.op(OEND)
@@ -1342,19 +1330,21 @@ func (p *exporter) expr(n *Node) {
 		}
 		// only append() calls may contain '...' arguments
 		if op == OAPPEND {
-			p.bool(n.Isddd)
-		} else if n.Isddd {
+			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.pos(n)
 		p.expr(n.Left)
 		p.exprList(n.List)
-		p.bool(n.Isddd)
+		p.bool(n.Isddd())
 
 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
 		p.op(op) // must keep separate from OMAKE for importer
+		p.pos(n)
 		p.typ(n.Type)
 		switch {
 		default:
@@ -1374,21 +1364,25 @@ func (p *exporter) expr(n *Node) {
 	// unary expressions
 	case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
 		p.op(op)
+		p.pos(n)
 		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.pos(n)
 		p.expr(n.Left)
 		p.expr(n.Right)
 
 	case OADDSTR:
 		p.op(OADDSTR)
+		p.pos(n)
 		p.exprList(n.List)
 
 	case OCMPSTR, OCMPIFACE:
 		p.op(Op(n.Etype))
+		p.pos(n)
 		p.expr(n.Left)
 		p.expr(n.Right)
 
@@ -1398,6 +1392,7 @@ func (p *exporter) expr(n *Node) {
 		// 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)
+		p.pos(n)
 
 	default:
 		Fatalf("cannot export %v (%d) node\n"+
@@ -1431,37 +1426,42 @@ func (p *exporter) stmt(n *Node) {
 	switch op := n.Op; op {
 	case ODCL:
 		p.op(ODCL)
+		p.pos(n)
 		p.sym(n.Left)
 		p.typ(n.Left.Type)
 
 	// case ODCLFIELD:
 	//	unimplemented - handled by default case
 
-	case OAS, OASWB:
+	case OAS:
 		// Don't export "v = <N>" initializing statements, hope they're always
 		// preceded by the DCL which will be re-parsed and typecheck to reproduce
 		// the "v = <N>" again.
 		if n.Right != nil {
 			p.op(OAS)
+			p.pos(n)
 			p.expr(n.Left)
 			p.expr(n.Right)
 		}
 
 	case OASOP:
 		p.op(OASOP)
+		p.pos(n)
 		p.int(int(n.Etype))
 		p.expr(n.Left)
-		if p.bool(!n.Implicit) {
+		if p.bool(!n.Implicit()) {
 			p.expr(n.Right)
 		}
 
 	case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
 		p.op(OAS2)
+		p.pos(n)
 		p.exprList(n.List)
 		p.exprList(n.Rlist)
 
 	case ORETURN:
 		p.op(ORETURN)
+		p.pos(n)
 		p.exprList(n.List)
 
 	// case ORETJMP:
@@ -1469,10 +1469,12 @@ func (p *exporter) stmt(n *Node) {
 
 	case OPROC, ODEFER:
 		p.op(op)
+		p.pos(n)
 		p.expr(n.Left)
 
 	case OIF:
 		p.op(OIF)
+		p.pos(n)
 		p.stmtList(n.Ninit)
 		p.expr(n.Left)
 		p.stmtList(n.Nbody)
@@ -1480,32 +1482,38 @@ func (p *exporter) stmt(n *Node) {
 
 	case OFOR:
 		p.op(OFOR)
+		p.pos(n)
 		p.stmtList(n.Ninit)
 		p.exprsOrNil(n.Left, n.Right)
 		p.stmtList(n.Nbody)
 
 	case ORANGE:
 		p.op(ORANGE)
+		p.pos(n)
 		p.stmtList(n.List)
 		p.expr(n.Right)
 		p.stmtList(n.Nbody)
 
 	case OSELECT, OSWITCH:
 		p.op(op)
+		p.pos(n)
 		p.stmtList(n.Ninit)
 		p.exprsOrNil(n.Left, nil)
 		p.stmtList(n.List)
 
 	case OCASE, OXCASE:
 		p.op(OXCASE)
+		p.pos(n)
 		p.stmtList(n.List)
 		p.stmtList(n.Nbody)
 
 	case OFALL, OXFALL:
 		p.op(OXFALL)
+		p.pos(n)
 
 	case OBREAK, OCONTINUE:
 		p.op(op)
+		p.pos(n)
 		p.exprsOrNil(n.Left, nil)
 
 	case OEMPTY:
@@ -1513,6 +1521,7 @@ func (p *exporter) stmt(n *Node) {
 
 	case OGOTO, OLABEL:
 		p.op(op)
+		p.pos(n)
 		p.expr(n.Left)
 
 	default:
@@ -1537,7 +1546,7 @@ func (p *exporter) exprsOrNil(a, b *Node) {
 	}
 }
 
-func (p *exporter) fieldSym(s *Sym, short bool) {
+func (p *exporter) fieldSym(s *types.Sym, short bool) {
 	name := s.Name
 
 	// remove leading "type." in method names ("(T).m" -> "m")
@@ -1589,6 +1598,8 @@ func (p *exporter) sym(n *Node) {
 	if name != "_" {
 		p.pkg(s.Pkg)
 	}
+	// Fixes issue #18167.
+	p.string(s.Linkname)
 }
 
 func (p *exporter) bool(b bool) bool {
@@ -1797,7 +1808,7 @@ const (
 	nilTag
 	unknownTag // not used by gc (only appears in packages with errors)
 
-	// Aliases
+	// Type aliases
 	aliasTag
 )
 
@@ -1835,66 +1846,66 @@ var tagString = [...]string{
 	-nilTag:      "nil",
 	-unknownTag:  "unknown",
 
-	// Aliases
+	// Type aliases
 	-aliasTag: "alias",
 }
 
 // untype returns the "pseudo" untyped type for a Ctype (import/export use only).
 // (we can't use an pre-initialized array because we must be sure all types are
 // set up)
-func untype(ctype Ctype) *Type {
+func untype(ctype Ctype) *types.Type {
 	switch ctype {
 	case CTINT:
-		return idealint
+		return types.Idealint
 	case CTRUNE:
-		return idealrune
+		return types.Idealrune
 	case CTFLT:
-		return idealfloat
+		return types.Idealfloat
 	case CTCPLX:
-		return idealcomplex
+		return types.Idealcomplex
 	case CTSTR:
-		return idealstring
+		return types.Idealstring
 	case CTBOOL:
-		return idealbool
+		return types.Idealbool
 	case CTNIL:
-		return Types[TNIL]
+		return types.Types[TNIL]
 	}
 	Fatalf("exporter: unknown Ctype")
 	return nil
 }
 
-var predecl []*Type // initialized lazily
+var predecl []*types.Type // initialized lazily
 
-func predeclared() []*Type {
+func predeclared() []*types.Type {
 	if predecl == nil {
 		// initialize lazily to be sure that all
 		// elements have been initialized before
-		predecl = []*Type{
+		predecl = []*types.Type{
 			// basic types
-			Types[TBOOL],
-			Types[TINT],
-			Types[TINT8],
-			Types[TINT16],
-			Types[TINT32],
-			Types[TINT64],
-			Types[TUINT],
-			Types[TUINT8],
-			Types[TUINT16],
-			Types[TUINT32],
-			Types[TUINT64],
-			Types[TUINTPTR],
-			Types[TFLOAT32],
-			Types[TFLOAT64],
-			Types[TCOMPLEX64],
-			Types[TCOMPLEX128],
-			Types[TSTRING],
-
-			// aliases
-			bytetype,
-			runetype,
+			types.Types[TBOOL],
+			types.Types[TINT],
+			types.Types[TINT8],
+			types.Types[TINT16],
+			types.Types[TINT32],
+			types.Types[TINT64],
+			types.Types[TUINT],
+			types.Types[TUINT8],
+			types.Types[TUINT16],
+			types.Types[TUINT32],
+			types.Types[TUINT64],
+			types.Types[TUINTPTR],
+			types.Types[TFLOAT32],
+			types.Types[TFLOAT64],
+			types.Types[TCOMPLEX64],
+			types.Types[TCOMPLEX128],
+			types.Types[TSTRING],
+
+			// basic type aliases
+			types.Bytetype,
+			types.Runetype,
 
 			// error
-			errortype,
+			types.Errortype,
 
 			// untyped types
 			untype(CTBOOL),
@@ -1906,13 +1917,13 @@ func predeclared() []*Type {
 			untype(CTNIL),
 
 			// package unsafe
-			Types[TUNSAFEPTR],
+			types.Types[TUNSAFEPTR],
 
 			// invalid type (package contains errors)
-			Types[Txxx],
+			types.Types[Txxx],
 
 			// any type, for builtin export data
-			Types[TANY],
+			types.Types[TANY],
 		}
 	}
 	return predecl
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 94c1184..30ee31a 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -10,6 +10,8 @@ package gc
 
 import (
 	"bufio"
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"encoding/binary"
 	"fmt"
 	"math/big"
@@ -24,35 +26,43 @@ import (
 
 type importer struct {
 	in      *bufio.Reader
-	buf     []byte // reused for reading strings
-	version int    // export format version
+	imp     *types.Pkg // imported package
+	buf     []byte     // reused for reading strings
+	version int        // export format version
 
 	// object lists, in order of deserialization
 	strList       []string
-	pkgList       []*Pkg
-	typList       []*Type
+	pathList      []string
+	pkgList       []*types.Pkg
+	typList       []*types.Type
 	funcList      []*Node // nil entry means already declared
 	trackAllTypes bool
 
 	// for delayed type verification
-	cmpList []struct{ pt, t *Type }
+	cmpList []struct{ pt, t *types.Type }
 
 	// position encoding
 	posInfoFormat bool
 	prevFile      string
 	prevLine      int
+	posBase       *src.PosBase
 
 	// debugging support
 	debugFormat bool
 	read        int // bytes read
 }
 
-// Import populates importpkg from the serialized package data.
-func Import(in *bufio.Reader) {
+// Import populates imp from the serialized package data read from in.
+func Import(imp *types.Pkg, in *bufio.Reader) {
+	inimport = true
+	defer func() { inimport = false }()
+
 	p := importer{
-		in:      in,
-		version: -1,           // unknown version
-		strList: []string{""}, // empty string is mapped to 0
+		in:       in,
+		imp:      imp,
+		version:  -1,           // unknown version
+		strList:  []string{""}, // empty string is mapped to 0
+		pathList: []string{""}, // empty path is mapped to 0
 	}
 
 	// read version info
@@ -86,17 +96,17 @@ func Import(in *bufio.Reader) {
 
 	// read version specific flags - extend as necessary
 	switch p.version {
-	// case 4:
+	// case 6:
 	// 	...
 	//	fallthrough
-	case 3, 2, 1:
+	case 5, 4, 3, 2, 1:
 		p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
 		p.trackAllTypes = p.bool()
 		p.posInfoFormat = p.bool()
 	case 0:
 		// Go1.7 encoding format - nothing to do here
 	default:
-		formatErrorf("unknown export format version %d (%q)", p.version, versionstr)
+		p.formatErrorf("unknown export format version %d (%q)", p.version, versionstr)
 	}
 
 	// --- generic export data ---
@@ -127,7 +137,7 @@ func Import(in *bufio.Reader) {
 
 	// self-verification
 	if count := p.int(); count != objcount {
-		formatErrorf("got %d objects; want %d", objcount, count)
+		p.formatErrorf("got %d objects; want %d", objcount, count)
 	}
 
 	// --- compiler-specific export data ---
@@ -147,12 +157,12 @@ func Import(in *bufio.Reader) {
 
 	// self-verification
 	if count := p.int(); count != objcount {
-		formatErrorf("got %d objects; want %d", objcount, count)
+		p.formatErrorf("got %d objects; want %d", objcount, count)
 	}
 
 	// read inlineable functions bodies
 	if dclcontext != PEXTERN {
-		formatErrorf("unexpected context %d", dclcontext)
+		p.formatErrorf("unexpected context %d", dclcontext)
 	}
 
 	objcount = 0
@@ -164,12 +174,12 @@ func Import(in *bufio.Reader) {
 
 		// don't process the same function twice
 		if i <= i0 {
-			formatErrorf("index not increasing: %d <= %d", i, i0)
+			p.formatErrorf("index not increasing: %d <= %d", i, i0)
 		}
 		i0 = i
 
 		if funcdepth != 0 {
-			formatErrorf("unexpected Funcdepth %d", funcdepth)
+			p.formatErrorf("unexpected Funcdepth %d", funcdepth)
 		}
 
 		// Note: In the original code, funchdr and funcbody are called for
@@ -203,11 +213,11 @@ func Import(in *bufio.Reader) {
 
 	// self-verification
 	if count := p.int(); count != objcount {
-		formatErrorf("got %d functions; want %d", objcount, count)
+		p.formatErrorf("got %d functions; want %d", objcount, count)
 	}
 
 	if dclcontext != PEXTERN {
-		formatErrorf("unexpected context %d", dclcontext)
+		p.formatErrorf("unexpected context %d", dclcontext)
 	}
 
 	p.verifyTypes()
@@ -222,13 +232,13 @@ func Import(in *bufio.Reader) {
 	}
 }
 
-func formatErrorf(format string, args ...interface{}) {
+func (p *importer) formatErrorf(format string, args ...interface{}) {
 	if debugFormat {
 		Fatalf(format, args...)
 	}
 
 	yyerror("cannot import %q due to version skew - reinstall package (%s)",
-		importpkg.Path, fmt.Sprintf(format, args...))
+		p.imp.Path, fmt.Sprintf(format, args...))
 	errorexit()
 }
 
@@ -237,7 +247,7 @@ func (p *importer) verifyTypes() {
 		pt := pair.pt
 		t := pair.t
 		if !eqtype(pt.Orig, t) {
-			formatErrorf("inconsistent definition for type %v during import\n\t%L (in %q)\n\t%L (in %q)", pt.Sym, pt, pt.Sym.Importdef.Path, t, importpkg.Path)
+			p.formatErrorf("inconsistent definition for type %v during import\n\t%L (in %q)\n\t%L (in %q)", pt.Sym, pt, pt.Sym.Importdef.Path, t, p.imp.Path)
 		}
 	}
 }
@@ -248,7 +258,7 @@ func (p *importer) verifyTypes() {
 // the same name appears in an error message.
 var numImport = make(map[string]int)
 
-func (p *importer) pkg() *Pkg {
+func (p *importer) pkg() *types.Pkg {
 	// if the package was seen before, i is its index (>= 0)
 	i := p.tagOrIndex()
 	if i >= 0 {
@@ -257,33 +267,38 @@ func (p *importer) pkg() *Pkg {
 
 	// otherwise, i is the package tag (< 0)
 	if i != packageTag {
-		formatErrorf("expected package tag, found tag = %d", i)
+		p.formatErrorf("expected package tag, found tag = %d", i)
 	}
 
 	// read package data
 	name := p.string()
-	path := p.string()
+	var path string
+	if p.version >= 5 {
+		path = p.path()
+	} else {
+		path = p.string()
+	}
 
 	// we should never see an empty package name
 	if name == "" {
-		formatErrorf("empty package name for path %q", path)
+		p.formatErrorf("empty package name for path %q", path)
 	}
 
 	// we should never see a bad import path
 	if isbadimport(path) {
-		formatErrorf("bad package path %q for package %s", path, name)
+		p.formatErrorf("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) {
-		formatErrorf("package path %q for pkg index %d", path, len(p.pkgList))
+		p.formatErrorf("package path %q for pkg index %d", path, len(p.pkgList))
 	}
 
 	// add package to pkgList
-	pkg := importpkg
+	pkg := p.imp
 	if path != "" {
-		pkg = mkpkg(path)
+		pkg = types.NewPkg(path, "")
 	}
 	if pkg.Name == "" {
 		pkg.Name = name
@@ -292,7 +307,7 @@ func (p *importer) pkg() *Pkg {
 		yyerror("conflicting package names %s and %s for path %q", pkg.Name, name, path)
 	}
 	if myimportpath != "" && path == myimportpath {
-		yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
+		yyerror("import %q: package depends on %q (import cycle)", p.imp.Path, path)
 		errorexit()
 	}
 	p.pkgList = append(p.pkgList, pkg)
@@ -300,10 +315,10 @@ func (p *importer) pkg() *Pkg {
 	return pkg
 }
 
-func idealType(typ *Type) *Type {
+func idealType(typ *types.Type) *types.Type {
 	if typ.IsUntyped() {
 		// canonicalize ideal types
-		typ = Types[TIDEAL]
+		typ = types.Types[TIDEAL]
 	}
 	return typ
 }
@@ -315,7 +330,13 @@ func (p *importer) obj(tag int) {
 		sym := p.qualifiedName()
 		typ := p.typ()
 		val := p.value(typ)
-		importconst(sym, idealType(typ), nodlit(val))
+		importconst(p.imp, sym, idealType(typ), nodlit(val))
+
+	case aliasTag:
+		p.pos()
+		sym := p.qualifiedName()
+		typ := p.typ()
+		importalias(p.imp, sym, typ)
 
 	case typeTag:
 		p.typ()
@@ -324,7 +345,7 @@ func (p *importer) obj(tag int) {
 		p.pos()
 		sym := p.qualifiedName()
 		typ := p.typ()
-		importvar(sym, typ)
+		importvar(p.imp, sym, typ)
 
 	case funcTag:
 		p.pos()
@@ -333,11 +354,11 @@ func (p *importer) obj(tag int) {
 		result := p.paramList()
 
 		sig := functypefield(nil, params, result)
-		importsym(sym, ONAME)
-		if sym.Def != nil && sym.Def.Op == ONAME {
+		importsym(p.imp, sym, ONAME)
+		if asNode(sym.Def) != nil && asNode(sym.Def).Op == ONAME {
 			// function was imported before (via another import)
-			if !eqtype(sig, sym.Def.Type) {
-				formatErrorf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
+			if !eqtype(sig, asNode(sym.Def).Type) {
+				p.formatErrorf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, asNode(sym.Def).Type, sig)
 			}
 			p.funcList = append(p.funcList, nil)
 			break
@@ -350,51 +371,76 @@ func (p *importer) obj(tag int) {
 		importlist = append(importlist, n)
 
 		if Debug['E'] > 0 {
-			fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
+			fmt.Printf("import [%q] func %v \n", p.imp.Path, n)
 			if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
 				fmt.Printf("inl body: %v\n", n.Func.Inl)
 			}
 		}
 
-	case aliasTag:
-		p.pos()
-		alias := importpkg.Lookup(p.string())
-		orig := p.qualifiedName()
-
-		// Although the protocol allows the alias to precede the original,
-		// this never happens in files produced by gc.
-		alias.Flags |= SymAlias
-		alias.Def = orig.Def
-		importsym(alias, orig.Def.Op)
-
 	default:
-		formatErrorf("unexpected object (tag = %d)", tag)
+		p.formatErrorf("unexpected object (tag = %d)", tag)
 	}
 }
 
-func (p *importer) pos() {
+func (p *importer) pos() src.XPos {
 	if !p.posInfoFormat {
-		return
+		return src.NoXPos
 	}
 
 	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()
+	delta := p.int()
+	line += delta
+	if p.version >= 5 {
+		if delta == deltaNewFile {
+			if n := p.int(); n >= 0 {
+				// file changed
+				file = p.path()
+				line = n
+			}
+		}
+	} else {
+		if delta == 0 {
+			if n := p.int(); n >= 0 {
+				// file changed
+				file = p.prevFile[:n] + p.string()
+				line = p.int()
+			}
+		}
+	}
+	if file != p.prevFile {
 		p.prevFile = file
-		line = p.int()
+		p.posBase = src.NewFileBase(file, file)
 	}
 	p.prevLine = line
 
-	// TODO(gri) register new position
+	pos := src.MakePos(p.posBase, uint(line), 0)
+	xpos := Ctxt.PosTable.XPos(pos)
+	return xpos
+}
+
+func (p *importer) path() string {
+	if p.debugFormat {
+		p.marker('p')
+	}
+	// if the path was seen before, i is its index (>= 0)
+	// (the empty string is at index 0)
+	i := p.rawInt64()
+	if i >= 0 {
+		return p.pathList[i]
+	}
+	// otherwise, i is the negative path length (< 0)
+	a := make([]string, -i)
+	for n := range a {
+		a[n] = p.string()
+	}
+	s := strings.Join(a, "/")
+	p.pathList = append(p.pathList, s)
+	return s
 }
 
-func (p *importer) newtyp(etype EType) *Type {
-	t := typ(etype)
+func (p *importer) newtyp(etype types.EType) *types.Type {
+	t := types.New(etype)
 	if p.trackAllTypes {
 		p.typList = append(p.typList, t)
 	}
@@ -402,23 +448,21 @@ func (p *importer) newtyp(etype EType) *Type {
 }
 
 // importtype declares that pt, an imported named type, has underlying type t.
-func (p *importer) importtype(pt, t *Type) {
+func (p *importer) importtype(pt, t *types.Type) {
 	if pt.Etype == TFORW {
-		n := pt.nod
-		copytype(pt.nod, t)
-		pt.nod = n // unzero nod
-		pt.Sym.Importdef = importpkg
+		copytype(asNode(pt.Nod), t)
+		pt.Sym.Importdef = p.imp
 		pt.Sym.Lastlineno = lineno
-		declare(n, PEXTERN)
+		declare(asNode(pt.Nod), PEXTERN)
 		checkwidth(pt)
 	} else {
 		// pt.Orig and t must be identical.
 		if p.trackAllTypes {
 			// If we track all types, 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})
+			p.cmpList = append(p.cmpList, struct{ pt, t *types.Type }{pt, t})
 		} else if !eqtype(pt.Orig, t) {
-			yyerror("inconsistent definition for type %v during import\n\t%L (in %q)\n\t%L (in %q)", pt.Sym, pt, pt.Sym.Importdef.Path, t, importpkg.Path)
+			yyerror("inconsistent definition for type %v during import\n\t%L (in %q)\n\t%L (in %q)", pt.Sym, pt, pt.Sym.Importdef.Path, t, p.imp.Path)
 		}
 	}
 
@@ -427,7 +471,7 @@ func (p *importer) importtype(pt, t *Type) {
 	}
 }
 
-func (p *importer) typ() *Type {
+func (p *importer) typ() *types.Type {
 	// if the type was seen before, i is its index (>= 0)
 	i := p.tagOrIndex()
 	if i >= 0 {
@@ -435,13 +479,13 @@ func (p *importer) typ() *Type {
 	}
 
 	// otherwise, i is the type tag (< 0)
-	var t *Type
+	var t *types.Type
 	switch i {
 	case namedTag:
 		p.pos()
 		tsym := p.qualifiedName()
 
-		t = pkgtype(tsym)
+		t = pkgtype(p.imp, tsym)
 		p.typList = append(p.typList, t)
 
 		// read underlying type
@@ -473,14 +517,7 @@ func (p *importer) typ() *Type {
 			result := p.paramList()
 			nointerface := p.bool()
 
-			base := recv[0].Type
-			star := false
-			if base.IsPtr() {
-				base = base.Elem()
-				star = true
-			}
-
-			n := methodname0(sym, star, base.Sym)
+			n := newfuncname(methodname(sym, recv[0].Type))
 			n.Type = functypefield(recv[0], params, result)
 			checkwidth(n.Type)
 			addmethod(sym, n.Type, false, nointerface)
@@ -492,10 +529,10 @@ func (p *importer) typ() *Type {
 			// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
 			// out by typecheck's lookdot as this $$.ttype. So by providing
 			// this back link here we avoid special casing there.
-			n.Type.SetNname(n)
+			n.Type.FuncType().Nname = asTypesNode(n)
 
 			if Debug['E'] > 0 {
-				fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
+				fmt.Printf("import [%q] meth %v \n", p.imp.Path, n)
 				if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
 					fmt.Printf("inl body: %v\n", n.Func.Inl)
 				}
@@ -508,16 +545,16 @@ func (p *importer) typ() *Type {
 		t = p.newtyp(TARRAY)
 		bound := p.int64()
 		elem := p.typ()
-		t.Extra = &ArrayType{Elem: elem, Bound: bound}
+		t.Extra = &types.Array{Elem: elem, Bound: bound}
 
 	case sliceTag:
 		t = p.newtyp(TSLICE)
 		elem := p.typ()
-		t.Extra = SliceType{Elem: elem}
+		t.Extra = types.Slice{Elem: elem}
 
 	case dddTag:
 		t = p.newtyp(TDDDFIELD)
-		t.Extra = DDDFieldType{T: p.typ()}
+		t.Extra = types.DDDField{T: p.typ()}
 
 	case structTag:
 		t = p.newtyp(TSTRUCT)
@@ -525,8 +562,8 @@ func (p *importer) typ() *Type {
 		checkwidth(t)
 
 	case pointerTag:
-		t = p.newtyp(Tptr)
-		t.Extra = PtrType{Elem: p.typ()}
+		t = p.newtyp(types.Tptr)
+		t.Extra = types.Ptr{Elem: p.typ()}
 
 	case signatureTag:
 		t = p.newtyp(TFUNC)
@@ -535,12 +572,12 @@ func (p *importer) typ() *Type {
 		functypefield0(t, nil, params, result)
 
 	case interfaceTag:
-		t = p.newtyp(TINTER)
-		if p.int() != 0 {
-			formatErrorf("unexpected embedded interface")
+		if ml := p.methodList(); len(ml) == 0 {
+			t = types.Types[TINTER]
+		} else {
+			t = p.newtyp(TINTER)
+			t.SetInterface(ml)
 		}
-		t.SetFields(p.methodList())
-		checkwidth(t)
 
 	case mapTag:
 		t = p.newtyp(TMAP)
@@ -551,29 +588,29 @@ func (p *importer) typ() *Type {
 	case chanTag:
 		t = p.newtyp(TCHAN)
 		ct := t.ChanType()
-		ct.Dir = ChanDir(p.int())
+		ct.Dir = types.ChanDir(p.int())
 		ct.Elem = p.typ()
 
 	default:
-		formatErrorf("unexpected type (tag = %d)", i)
+		p.formatErrorf("unexpected type (tag = %d)", i)
 	}
 
 	if t == nil {
-		formatErrorf("nil type (type tag = %d)", i)
+		p.formatErrorf("nil type (type tag = %d)", i)
 	}
 
 	return t
 }
 
-func (p *importer) qualifiedName() *Sym {
+func (p *importer) qualifiedName() *types.Sym {
 	name := p.string()
 	pkg := p.pkg()
 	return pkg.Lookup(name)
 }
 
-func (p *importer) fieldList() (fields []*Field) {
+func (p *importer) fieldList() (fields []*types.Field) {
 	if n := p.int(); n > 0 {
-		fields = make([]*Field, n)
+		fields = make([]*types.Field, n)
 		for i := range fields {
 			fields[i] = p.field()
 		}
@@ -581,72 +618,107 @@ func (p *importer) fieldList() (fields []*Field) {
 	return
 }
 
-func (p *importer) field() *Field {
+func (p *importer) field() *types.Field {
 	p.pos()
-	sym := p.fieldName()
+	sym, alias := p.fieldName()
 	typ := p.typ()
 	note := p.string()
 
-	f := newField()
+	f := types.NewField()
 	if sym.Name == "" {
-		// anonymous field - typ must be T or *T and T must be a type name
+		// anonymous field: typ must be T or *T and T must be a type name
 		s := typ.Sym
 		if s == nil && typ.IsPtr() {
 			s = typ.Elem().Sym // deref
 		}
 		sym = sym.Pkg.Lookup(s.Name)
 		f.Embedded = 1
+	} else if alias {
+		// anonymous field: we have an explicit name because it's a type alias
+		f.Embedded = 1
 	}
 
 	f.Sym = sym
-	f.Nname = newname(sym)
+	f.Nname = asTypesNode(newname(sym))
 	f.Type = typ
 	f.Note = note
 
 	return f
 }
 
-func (p *importer) methodList() (methods []*Field) {
-	if n := p.int(); n > 0 {
-		methods = make([]*Field, n)
-		for i := range methods {
-			methods[i] = p.method()
-		}
+func (p *importer) methodList() (methods []*types.Field) {
+	for n := p.int(); n > 0; n-- {
+		f := types.NewField()
+		f.Nname = asTypesNode(newname(nblank.Sym))
+		asNode(f.Nname).Pos = p.pos()
+		f.Type = p.typ()
+		methods = append(methods, f)
 	}
+
+	for n := p.int(); n > 0; n-- {
+		methods = append(methods, p.method())
+	}
+
 	return
 }
 
-func (p *importer) method() *Field {
+func (p *importer) method() *types.Field {
 	p.pos()
-	sym := p.fieldName()
+	sym := p.methodName()
 	params := p.paramList()
 	result := p.paramList()
 
-	f := newField()
+	f := types.NewField()
 	f.Sym = sym
-	f.Nname = newname(sym)
-	f.Type = functypefield(fakethisfield(), params, result)
+	f.Nname = asTypesNode(newname(sym))
+	f.Type = functypefield(fakeRecvField(), params, result)
 	return f
 }
 
-func (p *importer) fieldName() *Sym {
+func (p *importer) fieldName() (*types.Sym, bool) {
 	name := p.string()
 	if p.version == 0 && name == "_" {
-		// version 0 didn't export a package for _ fields
+		// version 0 didn't export a package for _ field names
 		// but used the builtin package instead
-		return builtinpkg.Lookup(name)
+		return builtinpkg.Lookup(name), false
 	}
 	pkg := localpkg
-	if name != "" && !exportname(name) {
-		if name == "?" {
-			name = ""
+	alias := false
+	switch name {
+	case "":
+		// 1) field name matches base type name and is exported: nothing to do
+	case "?":
+		// 2) field name matches base type name and is not exported: need package
+		name = ""
+		pkg = p.pkg()
+	case "@":
+		// 3) field name doesn't match base type name (alias name): need name and possibly package
+		name = p.string()
+		alias = true
+		fallthrough
+	default:
+		if !exportname(name) {
+			pkg = p.pkg()
 		}
+	}
+	return pkg.Lookup(name), alias
+}
+
+func (p *importer) methodName() *types.Sym {
+	name := p.string()
+	if p.version == 0 && name == "_" {
+		// version 0 didn't export a package for _ method names
+		// but used the builtin package instead
+		return builtinpkg.Lookup(name)
+	}
+	pkg := localpkg
+	if !exportname(name) {
 		pkg = p.pkg()
 	}
 	return pkg.Lookup(name)
 }
 
-func (p *importer) paramList() []*Field {
+func (p *importer) paramList() []*types.Field {
 	i := p.int()
 	if i == 0 {
 		return nil
@@ -658,26 +730,26 @@ func (p *importer) paramList() []*Field {
 		named = false
 	}
 	// i > 0
-	fs := make([]*Field, i)
+	fs := make([]*types.Field, i)
 	for i := range fs {
 		fs[i] = p.param(named)
 	}
 	return fs
 }
 
-func (p *importer) param(named bool) *Field {
-	f := newField()
+func (p *importer) param(named bool) *types.Field {
+	f := types.NewField()
 	f.Type = p.typ()
 	if f.Type.Etype == TDDDFIELD {
 		// TDDDFIELD indicates wrapped ... slice type
-		f.Type = typSlice(f.Type.DDDField())
-		f.Isddd = true
+		f.Type = types.NewSlice(f.Type.DDDField())
+		f.SetIsddd(true)
 	}
 
 	if named {
 		name := p.string()
 		if name == "" {
-			formatErrorf("expected named parameter")
+			p.formatErrorf("expected named parameter")
 		}
 		// TODO(gri) Supply function/method package rather than
 		// encoding the package for each parameter repeatedly.
@@ -686,7 +758,7 @@ func (p *importer) param(named bool) *Field {
 			pkg = p.pkg()
 		}
 		f.Sym = pkg.Lookup(name)
-		f.Nname = newname(f.Sym)
+		f.Nname = asTypesNode(newname(f.Sym))
 	}
 
 	// TODO(gri) This is compiler-specific (escape info).
@@ -696,7 +768,7 @@ func (p *importer) param(named bool) *Field {
 	return f
 }
 
-func (p *importer) value(typ *Type) (x Val) {
+func (p *importer) value(typ *types.Type) (x Val) {
 	switch tag := p.tagOrIndex(); tag {
 	case falseTag:
 		x.U = false
@@ -707,13 +779,13 @@ func (p *importer) value(typ *Type) (x Val) {
 	case int64Tag:
 		u := new(Mpint)
 		u.SetInt64(p.int64())
-		u.Rune = typ == idealrune
+		u.Rune = typ == types.Idealrune
 		x.U = u
 
 	case floatTag:
 		f := newMpflt()
 		p.float(f)
-		if typ == idealint || typ.IsInteger() {
+		if typ == types.Idealint || typ.IsInteger() {
 			// uncommon case: large int encoded as float
 			u := new(Mpint)
 			u.SetFloat(f)
@@ -732,18 +804,18 @@ func (p *importer) value(typ *Type) (x Val) {
 		x.U = p.string()
 
 	case unknownTag:
-		formatErrorf("unknown constant (importing package with errors)")
+		p.formatErrorf("unknown constant (importing package with errors)")
 
 	case nilTag:
 		x.U = new(NilVal)
 
 	default:
-		formatErrorf("unexpected value tag %d", tag)
+		p.formatErrorf("unexpected value tag %d", tag)
 	}
 
 	// verify ideal type
 	if typ.IsUntyped() && untype(x.Ctype()) != typ {
-		formatErrorf("value %v and type %v don't match", x, typ)
+		p.formatErrorf("value %v and type %v don't match", x, typ)
 	}
 
 	return
@@ -828,6 +900,11 @@ func (p *importer) expr() *Node {
 	return n
 }
 
+func npos(pos src.XPos, n *Node) *Node {
+	n.Pos = pos
+	return n
+}
+
 // TODO(gri) split into expr and stmt
 func (p *importer) node() *Node {
 	switch op := p.op(); op {
@@ -839,35 +916,35 @@ func (p *importer) node() *Node {
 	//	unimplemented
 
 	case OLITERAL:
+		pos := p.pos()
 		typ := p.typ()
-		n := nodlit(p.value(typ))
+		n := npos(pos, nodlit(p.value(typ)))
 		if !typ.IsUntyped() {
 			// Type-checking simplifies unsafe.Pointer(uintptr(c))
 			// to unsafe.Pointer(c) which then cannot type-checked
 			// again. Re-introduce explicit uintptr(c) conversion.
 			// (issue 16317).
 			if typ.IsUnsafePtr() {
-				conv := nod(OCALL, typenod(Types[TUINTPTR]), nil)
-				conv.List.Set1(n)
-				n = conv
+				n = nod(OCONV, n, nil)
+				n.Type = types.Types[TUINTPTR]
 			}
-			conv := nod(OCALL, typenod(typ), nil)
-			conv.List.Set1(n)
-			n = conv
+			n = nod(OCONV, n, nil)
+			n.Type = typ
 		}
 		return n
 
 	case ONAME:
-		return mkname(p.sym())
+		return npos(p.pos(), mkname(p.sym()))
 
 	// case OPACK, ONONAME:
 	// 	unreachable - should have been resolved by typechecking
 
 	case OTYPE:
+		pos := p.pos()
 		if p.bool() {
-			return mkname(p.sym())
+			return npos(pos, mkname(p.sym()))
 		}
-		return typenod(p.typ())
+		return npos(pos, typenod(p.typ()))
 
 	// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
 	//      unreachable - should have been resolved by typechecking
@@ -876,12 +953,12 @@ func (p *importer) node() *Node {
 	//	unimplemented
 
 	case OPTRLIT:
-		n := p.expr()
+		n := npos(p.pos(), 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
+				n.Right.SetImplicit(true)
 			} else {
 				n = nod(OADDR, n, nil)
 			}
@@ -889,7 +966,7 @@ func (p *importer) node() *Node {
 		return n
 
 	case OSTRUCTLIT:
-		n := nod(OCOMPLIT, nil, typenod(p.typ()))
+		n := nodl(p.pos(), OCOMPLIT, nil, typenod(p.typ()))
 		n.List.Set(p.elemList()) // special handling of field names
 		return n
 
@@ -897,13 +974,14 @@ func (p *importer) node() *Node {
 	// 	unreachable - mapped to case OCOMPLIT below by exporter
 
 	case OCOMPLIT:
-		n := nod(OCOMPLIT, nil, typenod(p.typ()))
+		n := nodl(p.pos(), OCOMPLIT, nil, typenod(p.typ()))
 		n.List.Set(p.exprList())
 		return n
 
 	case OKEY:
+		pos := p.pos()
 		left, right := p.exprsOrNil()
-		return nod(OKEY, left, right)
+		return nodl(pos, OKEY, left, right)
 
 	// case OSTRUCTKEY:
 	//	unreachable - handled in case OSTRUCTLIT by elemList
@@ -916,28 +994,24 @@ func (p *importer) node() *Node {
 
 	case OXDOT:
 		// see parser.new_dotname
-		return nodSym(OXDOT, p.expr(), p.fieldSym())
+		return npos(p.pos(), 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())
-		}
+		n := nodl(p.pos(), ODOTTYPE, p.expr(), nil)
+		n.Type = 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())
+		return nodl(p.pos(), op, p.expr(), p.expr())
 
 	case OSLICE, OSLICE3:
-		n := nod(op, p.expr(), nil)
+		n := nodl(p.pos(), op, p.expr(), nil)
 		low, high := p.exprsOrNil()
 		var max *Node
 		if n.Op.IsSlice3() {
@@ -950,15 +1024,15 @@ func (p *importer) node() *Node {
 	// 	unreachable - mapped to OCONV case below by exporter
 
 	case OCONV:
-		n := nod(OCALL, typenod(p.typ()), nil)
-		n.List.Set(p.exprList())
+		n := nodl(p.pos(), OCONV, p.expr(), nil)
+		n.Type = p.typ()
 		return n
 
 	case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
-		n := builtinCall(op)
+		n := npos(p.pos(), builtinCall(op))
 		n.List.Set(p.exprList())
 		if op == OAPPEND {
-			n.Isddd = p.bool()
+			n.SetIsddd(p.bool())
 		}
 		return n
 
@@ -966,31 +1040,32 @@ func (p *importer) node() *Node {
 	// 	unreachable - mapped to OCALL case below by exporter
 
 	case OCALL:
-		n := nod(OCALL, p.expr(), nil)
+		n := nodl(p.pos(), OCALL, p.expr(), nil)
 		n.List.Set(p.exprList())
-		n.Isddd = p.bool()
+		n.SetIsddd(p.bool())
 		return n
 
 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
-		n := builtinCall(OMAKE)
+		n := npos(p.pos(), 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)
+		return nodl(p.pos(), 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())
+		return nodl(p.pos(), op, p.expr(), p.expr())
 
 	case OADDSTR:
+		pos := p.pos()
 		list := p.exprList()
-		x := list[0]
+		x := npos(pos, list[0])
 		for _, y := range list[1:] {
-			x = nod(OADD, x, y)
+			x = nodl(pos, OADD, x, y)
 		}
 		return x
 
@@ -999,7 +1074,7 @@ func (p *importer) node() *Node {
 
 	case ODCLCONST:
 		// TODO(gri) these should not be exported in the first place
-		return nod(OEMPTY, nil, nil)
+		return nodl(p.pos(), OEMPTY, nil, nil)
 
 	// --------------------------------------------------------------------
 	// statements
@@ -1009,9 +1084,10 @@ func (p *importer) node() *Node {
 			// was always false - simply ignore in this case
 			p.bool()
 		}
+		pos := p.pos()
 		lhs := dclname(p.sym())
 		typ := typenod(p.typ())
-		return liststmt(variter([]*Node{lhs}, typ, nil)) // TODO(gri) avoid list creation
+		return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
 
 	// case ODCLFIELD:
 	//	unimplemented
@@ -1020,15 +1096,15 @@ func (p *importer) node() *Node {
 	// 	unreachable - mapped to OAS case below by exporter
 
 	case OAS:
-		return nod(OAS, p.expr(), p.expr())
+		return nodl(p.pos(), OAS, p.expr(), p.expr())
 
 	case OASOP:
-		n := nod(OASOP, nil, nil)
-		n.Etype = EType(p.int())
+		n := nodl(p.pos(), OASOP, nil, nil)
+		n.Etype = types.EType(p.int())
 		n.Left = p.expr()
 		if !p.bool() {
 			n.Right = nodintconst(1)
-			n.Implicit = true
+			n.SetImplicit(true)
 		} else {
 			n.Right = p.expr()
 		}
@@ -1038,13 +1114,13 @@ func (p *importer) node() *Node {
 	// 	unreachable - mapped to OAS2 case below by exporter
 
 	case OAS2:
-		n := nod(OAS2, nil, nil)
+		n := nodl(p.pos(), OAS2, nil, nil)
 		n.List.Set(p.exprList())
 		n.Rlist.Set(p.exprList())
 		return n
 
 	case ORETURN:
-		n := nod(ORETURN, nil, nil)
+		n := nodl(p.pos(), ORETURN, nil, nil)
 		n.List.Set(p.exprList())
 		return n
 
@@ -1052,81 +1128,80 @@ func (p *importer) node() *Node {
 	// 	unreachable - generated by compiler for trampolin routines (not exported)
 
 	case OPROC, ODEFER:
-		return nod(op, p.expr(), nil)
+		return nodl(p.pos(), op, p.expr(), nil)
 
 	case OIF:
-		markdcl()
-		n := nod(OIF, nil, nil)
+		types.Markdcl()
+		n := nodl(p.pos(), OIF, nil, nil)
 		n.Ninit.Set(p.stmtList())
 		n.Left = p.expr()
 		n.Nbody.Set(p.stmtList())
 		n.Rlist.Set(p.stmtList())
-		popdcl()
+		types.Popdcl()
 		return n
 
 	case OFOR:
-		markdcl()
-		n := nod(OFOR, nil, nil)
+		types.Markdcl()
+		n := nodl(p.pos(), OFOR, nil, nil)
 		n.Ninit.Set(p.stmtList())
 		n.Left, n.Right = p.exprsOrNil()
 		n.Nbody.Set(p.stmtList())
-		popdcl()
+		types.Popdcl()
 		return n
 
 	case ORANGE:
-		markdcl()
-		n := nod(ORANGE, nil, nil)
+		types.Markdcl()
+		n := nodl(p.pos(), ORANGE, nil, nil)
 		n.List.Set(p.stmtList())
 		n.Right = p.expr()
 		n.Nbody.Set(p.stmtList())
-		popdcl()
+		types.Popdcl()
 		return n
 
 	case OSELECT, OSWITCH:
-		markdcl()
-		n := nod(op, nil, nil)
+		types.Markdcl()
+		n := nodl(p.pos(), op, nil, nil)
 		n.Ninit.Set(p.stmtList())
 		n.Left, _ = p.exprsOrNil()
 		n.List.Set(p.stmtList())
-		popdcl()
+		types.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)
+		types.Markdcl()
+		n := nodl(p.pos(), OXCASE, nil, nil)
+		n.Xoffset = int64(types.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()
+		types.Popdcl()
 		return n
 
 	// case OFALL:
 	// 	unreachable - mapped to OXFALL case below by exporter
 
 	case OXFALL:
-		n := nod(OXFALL, nil, nil)
-		n.Xoffset = int64(block)
+		n := nodl(p.pos(), OXFALL, nil, nil)
+		n.Xoffset = int64(types.Block)
 		return n
 
 	case OBREAK, OCONTINUE:
+		pos := p.pos()
 		left, _ := p.exprsOrNil()
 		if left != nil {
 			left = newname(left.Sym)
 		}
-		return nod(op, left, nil)
+		return nodl(pos, 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
+		return nodl(p.pos(), op, newname(p.expr().Sym), nil)
 
 	case OEND:
 		return nil
@@ -1153,7 +1228,7 @@ func (p *importer) exprsOrNil() (a, b *Node) {
 	return
 }
 
-func (p *importer) fieldSym() *Sym {
+func (p *importer) fieldSym() *types.Sym {
 	name := p.string()
 	pkg := localpkg
 	if !exportname(name) {
@@ -1162,13 +1237,16 @@ func (p *importer) fieldSym() *Sym {
 	return pkg.Lookup(name)
 }
 
-func (p *importer) sym() *Sym {
+func (p *importer) sym() *types.Sym {
 	name := p.string()
 	pkg := localpkg
 	if name != "_" {
 		pkg = p.pkg()
 	}
-	return pkg.Lookup(name)
+	linkname := p.string()
+	sym := pkg.Lookup(name)
+	sym.Linkname = linkname
+	return sym
 }
 
 func (p *importer) bool() bool {
@@ -1193,7 +1271,7 @@ func (p *importer) tagOrIndex() int {
 func (p *importer) int() int {
 	x := p.int64()
 	if int64(int(x)) != x {
-		formatErrorf("exported integer too large")
+		p.formatErrorf("exported integer too large")
 	}
 	return int(x)
 }
@@ -1232,12 +1310,12 @@ func (p *importer) string() string {
 
 func (p *importer) marker(want byte) {
 	if got := p.rawByte(); got != want {
-		formatErrorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
+		p.formatErrorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
 	}
 
 	pos := p.read
 	if n := int(p.rawInt64()); n != pos {
-		formatErrorf("incorrect position: got %d; want %d", n, pos)
+		p.formatErrorf("incorrect position: got %d; want %d", n, pos)
 	}
 }
 
@@ -1245,7 +1323,7 @@ func (p *importer) marker(want byte) {
 func (p *importer) rawInt64() int64 {
 	i, err := binary.ReadVarint(p)
 	if err != nil {
-		formatErrorf("read error: %v", err)
+		p.formatErrorf("read error: %v", err)
 	}
 	return i
 }
@@ -1272,13 +1350,13 @@ func (p *importer) rawByte() byte {
 	c, err := p.in.ReadByte()
 	p.read++
 	if err != nil {
-		formatErrorf("read error: %v", err)
+		p.formatErrorf("read error: %v", err)
 	}
 	if c == '|' {
 		c, err = p.in.ReadByte()
 		p.read++
 		if err != nil {
-			formatErrorf("read error: %v", err)
+			p.formatErrorf("read error: %v", err)
 		}
 		switch c {
 		case 'S':
@@ -1286,7 +1364,7 @@ func (p *importer) rawByte() byte {
 		case '|':
 			// nothing to do
 		default:
-			formatErrorf("unexpected escape sequence in export data")
+			p.formatErrorf("unexpected escape sequence in export data")
 		}
 	}
 	return c
diff --git a/src/cmd/compile/internal/gc/bitset.go b/src/cmd/compile/internal/gc/bitset.go
new file mode 100644
index 0000000..90babd5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bitset.go
@@ -0,0 +1,49 @@
+// Copyright 2017 The Go Authors. 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
+
+type bitset8 uint8
+
+func (f *bitset8) set(mask uint8, b bool) {
+	if b {
+		*(*uint8)(f) |= mask
+	} else {
+		*(*uint8)(f) &^= mask
+	}
+}
+
+type bitset32 uint32
+
+func (f *bitset32) set(mask uint32, b bool) {
+	if b {
+		*(*uint32)(f) |= mask
+	} else {
+		*(*uint32)(f) &^= mask
+	}
+}
+
+func (f bitset32) get2(shift uint8) uint8 {
+	return uint8(f>>shift) & 3
+}
+
+// set2 sets two bits in f using the bottom two bits of b.
+func (f *bitset32) set2(shift uint8, b uint8) {
+	// Clear old bits.
+	*(*uint32)(f) &^= 3 << shift
+	// Set new bits.
+	*(*uint32)(f) |= uint32(b&3) << shift
+}
+
+func (f bitset32) get3(shift uint8) uint8 {
+	return uint8(f>>shift) & 7
+}
+
+// set3 sets three bits in f using the bottom three bits of b.
+func (f *bitset32) set3(shift uint8, b uint8) {
+	// Clear old bits.
+	*(*uint32)(f) &^= 7 << shift
+	// Set new bits.
+	*(*uint32)(f) |= uint32(b&7) << shift
+}
diff --git a/src/cmd/compile/internal/gc/bootstrap.go b/src/cmd/compile/internal/gc/bootstrap.go
new file mode 100644
index 0000000..967f75a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bootstrap.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.8
+
+package gc
+
+import "runtime"
+
+func startMutexProfiling() {
+	Fatalf("mutex profiling unavailable in version %v", runtime.Version())
+}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 71b323f..f21a4da 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -1,7 +1,9 @@
-// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT
+// Code generated by mkbuiltin.go. DO NOT EDIT.
 
 package gc
 
+import "cmd/compile/internal/types"
+
 var runtimeDecls = [...]struct {
 	name string
 	tag  int
@@ -12,229 +14,252 @@ var runtimeDecls = [...]struct {
 	{"panicslice", funcTag, 5},
 	{"panicdivide", funcTag, 5},
 	{"throwinit", funcTag, 5},
-	{"panicwrap", funcTag, 7},
-	{"gopanic", funcTag, 9},
-	{"gorecover", funcTag, 12},
+	{"panicwrap", funcTag, 5},
+	{"gopanic", funcTag, 7},
+	{"gorecover", funcTag, 10},
 	{"goschedguarded", funcTag, 5},
-	{"printbool", funcTag, 14},
-	{"printfloat", funcTag, 16},
-	{"printint", funcTag, 18},
-	{"printhex", funcTag, 20},
-	{"printuint", funcTag, 20},
-	{"printcomplex", funcTag, 22},
-	{"printstring", funcTag, 23},
-	{"printpointer", funcTag, 24},
-	{"printiface", funcTag, 24},
-	{"printeface", funcTag, 24},
-	{"printslice", funcTag, 24},
+	{"printbool", funcTag, 12},
+	{"printfloat", funcTag, 14},
+	{"printint", funcTag, 16},
+	{"printhex", funcTag, 18},
+	{"printuint", funcTag, 18},
+	{"printcomplex", funcTag, 20},
+	{"printstring", funcTag, 22},
+	{"printpointer", funcTag, 23},
+	{"printiface", funcTag, 23},
+	{"printeface", funcTag, 23},
+	{"printslice", funcTag, 23},
 	{"printnl", funcTag, 5},
 	{"printsp", funcTag, 5},
 	{"printlock", funcTag, 5},
 	{"printunlock", funcTag, 5},
-	{"concatstring2", funcTag, 27},
-	{"concatstring3", funcTag, 28},
-	{"concatstring4", funcTag, 29},
-	{"concatstring5", funcTag, 30},
-	{"concatstrings", funcTag, 32},
-	{"cmpstring", funcTag, 34},
-	{"eqstring", funcTag, 35},
-	{"intstring", funcTag, 38},
-	{"slicebytetostring", funcTag, 40},
-	{"slicebytetostringtmp", funcTag, 41},
-	{"slicerunetostring", funcTag, 44},
-	{"stringtoslicebyte", funcTag, 45},
-	{"stringtoslicerune", funcTag, 48},
-	{"decoderune", funcTag, 49},
-	{"slicecopy", funcTag, 51},
-	{"slicestringcopy", funcTag, 52},
-	{"convI2I", funcTag, 53},
-	{"convT2E", funcTag, 54},
-	{"convT2I", funcTag, 54},
-	{"assertE2I", funcTag, 53},
-	{"assertE2I2", funcTag, 55},
-	{"assertI2I", funcTag, 53},
-	{"assertI2I2", funcTag, 55},
-	{"panicdottype", funcTag, 56},
-	{"panicnildottype", funcTag, 57},
-	{"ifaceeq", funcTag, 58},
-	{"efaceeq", funcTag, 58},
-	{"makemap", funcTag, 60},
-	{"mapaccess1", funcTag, 61},
-	{"mapaccess1_fast32", funcTag, 62},
-	{"mapaccess1_fast64", funcTag, 62},
-	{"mapaccess1_faststr", funcTag, 62},
-	{"mapaccess1_fat", funcTag, 63},
-	{"mapaccess2", funcTag, 64},
-	{"mapaccess2_fast32", funcTag, 65},
-	{"mapaccess2_fast64", funcTag, 65},
-	{"mapaccess2_faststr", funcTag, 65},
-	{"mapaccess2_fat", funcTag, 66},
-	{"mapassign", funcTag, 61},
-	{"mapiterinit", funcTag, 67},
-	{"mapdelete", funcTag, 67},
-	{"mapiternext", funcTag, 68},
-	{"makechan", funcTag, 70},
-	{"chanrecv1", funcTag, 72},
-	{"chanrecv2", funcTag, 73},
-	{"chansend1", funcTag, 75},
-	{"closechan", funcTag, 24},
-	{"writeBarrier", varTag, 76},
-	{"writebarrierptr", funcTag, 77},
-	{"typedmemmove", funcTag, 78},
-	{"typedmemclr", funcTag, 79},
-	{"typedslicecopy", funcTag, 80},
-	{"selectnbsend", funcTag, 81},
-	{"selectnbrecv", funcTag, 82},
-	{"selectnbrecv2", funcTag, 84},
-	{"newselect", funcTag, 85},
-	{"selectsend", funcTag, 81},
-	{"selectrecv", funcTag, 73},
-	{"selectrecv2", funcTag, 86},
-	{"selectdefault", funcTag, 87},
-	{"selectgo", funcTag, 57},
+	{"concatstring2", funcTag, 26},
+	{"concatstring3", funcTag, 27},
+	{"concatstring4", funcTag, 28},
+	{"concatstring5", funcTag, 29},
+	{"concatstrings", funcTag, 31},
+	{"cmpstring", funcTag, 33},
+	{"eqstring", funcTag, 34},
+	{"intstring", funcTag, 37},
+	{"slicebytetostring", funcTag, 39},
+	{"slicebytetostringtmp", funcTag, 40},
+	{"slicerunetostring", funcTag, 43},
+	{"stringtoslicebyte", funcTag, 44},
+	{"stringtoslicerune", funcTag, 47},
+	{"decoderune", funcTag, 48},
+	{"slicecopy", funcTag, 50},
+	{"slicestringcopy", funcTag, 51},
+	{"convI2I", funcTag, 52},
+	{"convT2E", funcTag, 53},
+	{"convT2E16", funcTag, 53},
+	{"convT2E32", funcTag, 53},
+	{"convT2E64", funcTag, 53},
+	{"convT2Estring", funcTag, 53},
+	{"convT2Eslice", funcTag, 53},
+	{"convT2Enoptr", funcTag, 53},
+	{"convT2I", funcTag, 53},
+	{"convT2I16", funcTag, 53},
+	{"convT2I32", funcTag, 53},
+	{"convT2I64", funcTag, 53},
+	{"convT2Istring", funcTag, 53},
+	{"convT2Islice", funcTag, 53},
+	{"convT2Inoptr", funcTag, 53},
+	{"assertE2I", funcTag, 52},
+	{"assertE2I2", funcTag, 54},
+	{"assertI2I", funcTag, 52},
+	{"assertI2I2", funcTag, 54},
+	{"panicdottypeE", funcTag, 55},
+	{"panicdottypeI", funcTag, 55},
+	{"panicnildottype", funcTag, 56},
+	{"ifaceeq", funcTag, 59},
+	{"efaceeq", funcTag, 59},
+	{"makemap", funcTag, 61},
+	{"mapaccess1", funcTag, 62},
+	{"mapaccess1_fast32", funcTag, 63},
+	{"mapaccess1_fast64", funcTag, 63},
+	{"mapaccess1_faststr", funcTag, 63},
+	{"mapaccess1_fat", funcTag, 64},
+	{"mapaccess2", funcTag, 65},
+	{"mapaccess2_fast32", funcTag, 66},
+	{"mapaccess2_fast64", funcTag, 66},
+	{"mapaccess2_faststr", funcTag, 66},
+	{"mapaccess2_fat", funcTag, 67},
+	{"mapassign", funcTag, 62},
+	{"mapassign_fast32", funcTag, 63},
+	{"mapassign_fast64", funcTag, 63},
+	{"mapassign_faststr", funcTag, 63},
+	{"mapiterinit", funcTag, 68},
+	{"mapdelete", funcTag, 68},
+	{"mapdelete_fast32", funcTag, 69},
+	{"mapdelete_fast64", funcTag, 69},
+	{"mapdelete_faststr", funcTag, 69},
+	{"mapiternext", funcTag, 70},
+	{"makechan", funcTag, 72},
+	{"chanrecv1", funcTag, 74},
+	{"chanrecv2", funcTag, 75},
+	{"chansend1", funcTag, 77},
+	{"closechan", funcTag, 23},
+	{"writeBarrier", varTag, 79},
+	{"writebarrierptr", funcTag, 80},
+	{"typedmemmove", funcTag, 81},
+	{"typedmemclr", funcTag, 82},
+	{"typedslicecopy", funcTag, 83},
+	{"selectnbsend", funcTag, 84},
+	{"selectnbrecv", funcTag, 85},
+	{"selectnbrecv2", funcTag, 87},
+	{"newselect", funcTag, 88},
+	{"selectsend", funcTag, 89},
+	{"selectrecv", funcTag, 90},
+	{"selectdefault", funcTag, 56},
+	{"selectgo", funcTag, 91},
 	{"block", funcTag, 5},
-	{"makeslice", funcTag, 89},
-	{"makeslice64", funcTag, 90},
-	{"growslice", funcTag, 91},
-	{"memmove", funcTag, 92},
-	{"memclrNoHeapPointers", funcTag, 93},
-	{"memclrHasPointers", funcTag, 93},
-	{"memequal", funcTag, 94},
-	{"memequal8", funcTag, 95},
-	{"memequal16", funcTag, 95},
-	{"memequal32", funcTag, 95},
-	{"memequal64", funcTag, 95},
-	{"memequal128", funcTag, 95},
-	{"int64div", funcTag, 96},
-	{"uint64div", funcTag, 97},
-	{"int64mod", funcTag, 96},
-	{"uint64mod", funcTag, 97},
-	{"float64toint64", funcTag, 98},
-	{"float64touint64", funcTag, 99},
-	{"float64touint32", funcTag, 101},
-	{"int64tofloat64", funcTag, 102},
-	{"uint64tofloat64", funcTag, 103},
-	{"uint32tofloat64", funcTag, 104},
-	{"complex128div", funcTag, 105},
-	{"racefuncenter", funcTag, 106},
+	{"makeslice", funcTag, 93},
+	{"makeslice64", funcTag, 94},
+	{"growslice", funcTag, 95},
+	{"memmove", funcTag, 96},
+	{"memclrNoHeapPointers", funcTag, 97},
+	{"memclrHasPointers", funcTag, 97},
+	{"memequal", funcTag, 98},
+	{"memequal8", funcTag, 99},
+	{"memequal16", funcTag, 99},
+	{"memequal32", funcTag, 99},
+	{"memequal64", funcTag, 99},
+	{"memequal128", funcTag, 99},
+	{"int64div", funcTag, 100},
+	{"uint64div", funcTag, 101},
+	{"int64mod", funcTag, 100},
+	{"uint64mod", funcTag, 101},
+	{"float64toint64", funcTag, 102},
+	{"float64touint64", funcTag, 103},
+	{"float64touint32", funcTag, 105},
+	{"int64tofloat64", funcTag, 106},
+	{"uint64tofloat64", funcTag, 107},
+	{"uint32tofloat64", funcTag, 108},
+	{"complex128div", funcTag, 109},
+	{"racefuncenter", funcTag, 110},
 	{"racefuncexit", funcTag, 5},
-	{"raceread", funcTag, 106},
-	{"racewrite", funcTag, 106},
-	{"racereadrange", funcTag, 107},
-	{"racewriterange", funcTag, 107},
-	{"msanread", funcTag, 107},
-	{"msanwrite", funcTag, 107},
+	{"raceread", funcTag, 110},
+	{"racewrite", funcTag, 110},
+	{"racereadrange", funcTag, 111},
+	{"racewriterange", funcTag, 111},
+	{"msanread", funcTag, 111},
+	{"msanwrite", funcTag, 111},
+	{"support_popcnt", varTag, 11},
 }
 
-func runtimeTypes() []*Type {
-	var typs [108]*Type
-	typs[0] = bytetype
-	typs[1] = typPtr(typs[0])
-	typs[2] = Types[TANY]
-	typs[3] = typPtr(typs[2])
+func runtimeTypes() []*types.Type {
+	var typs [112]*types.Type
+	typs[0] = types.Bytetype
+	typs[1] = types.NewPtr(typs[0])
+	typs[2] = types.Types[TANY]
+	typs[3] = types.NewPtr(typs[2])
 	typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
 	typs[5] = functype(nil, nil, nil)
-	typs[6] = Types[TSTRING]
-	typs[7] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6])}, nil)
-	typs[8] = Types[TINTER]
-	typs[9] = functype(nil, []*Node{anonfield(typs[8])}, nil)
-	typs[10] = Types[TINT32]
-	typs[11] = typPtr(typs[10])
-	typs[12] = functype(nil, []*Node{anonfield(typs[11])}, []*Node{anonfield(typs[8])})
-	typs[13] = Types[TBOOL]
+	typs[6] = types.Types[TINTER]
+	typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil)
+	typs[8] = types.Types[TINT32]
+	typs[9] = types.NewPtr(typs[8])
+	typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])})
+	typs[11] = types.Types[TBOOL]
+	typs[12] = functype(nil, []*Node{anonfield(typs[11])}, nil)
+	typs[13] = types.Types[TFLOAT64]
 	typs[14] = functype(nil, []*Node{anonfield(typs[13])}, nil)
-	typs[15] = Types[TFLOAT64]
+	typs[15] = types.Types[TINT64]
 	typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
-	typs[17] = Types[TINT64]
+	typs[17] = types.Types[TUINT64]
 	typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
-	typs[19] = Types[TUINT64]
+	typs[19] = types.Types[TCOMPLEX128]
 	typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
-	typs[21] = Types[TCOMPLEX128]
+	typs[21] = types.Types[TSTRING]
 	typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil)
-	typs[23] = functype(nil, []*Node{anonfield(typs[6])}, nil)
-	typs[24] = functype(nil, []*Node{anonfield(typs[2])}, nil)
-	typs[25] = typArray(typs[0], 32)
-	typs[26] = typPtr(typs[25])
-	typs[27] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[6])})
-	typs[28] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[6])})
-	typs[29] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[6])})
-	typs[30] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[6])})
-	typs[31] = typSlice(typs[6])
-	typs[32] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[31])}, []*Node{anonfield(typs[6])})
-	typs[33] = Types[TINT]
-	typs[34] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[33])})
-	typs[35] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[6])}, []*Node{anonfield(typs[13])})
-	typs[36] = typArray(typs[0], 4)
-	typs[37] = typPtr(typs[36])
-	typs[38] = functype(nil, []*Node{anonfield(typs[37]), anonfield(typs[17])}, []*Node{anonfield(typs[6])})
-	typs[39] = typSlice(typs[0])
-	typs[40] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[39])}, []*Node{anonfield(typs[6])})
-	typs[41] = functype(nil, []*Node{anonfield(typs[39])}, []*Node{anonfield(typs[6])})
-	typs[42] = runetype
-	typs[43] = typSlice(typs[42])
-	typs[44] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[43])}, []*Node{anonfield(typs[6])})
-	typs[45] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[6])}, []*Node{anonfield(typs[39])})
-	typs[46] = typArray(typs[42], 32)
-	typs[47] = typPtr(typs[46])
-	typs[48] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[6])}, []*Node{anonfield(typs[43])})
-	typs[49] = functype(nil, []*Node{anonfield(typs[6]), anonfield(typs[33])}, []*Node{anonfield(typs[42]), anonfield(typs[33])})
-	typs[50] = Types[TUINTPTR]
-	typs[51] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[50])}, []*Node{anonfield(typs[33])})
-	typs[52] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])})
-	typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
-	typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
-	typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[13])})
-	typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
-	typs[57] = functype(nil, []*Node{anonfield(typs[1])}, nil)
-	typs[58] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[13])})
-	typs[59] = typMap(typs[2], typs[2])
-	typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[59])})
-	typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
-	typs[62] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
-	typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
-	typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[13])})
-	typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[13])})
-	typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[13])})
-	typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[59]), anonfield(typs[3])}, nil)
-	typs[68] = functype(nil, []*Node{anonfield(typs[3])}, nil)
-	typs[69] = typChan(typs[2], Cboth)
-	typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17])}, []*Node{anonfield(typs[69])})
-	typs[71] = typChan(typs[2], Crecv)
-	typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3])}, nil)
-	typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3])}, []*Node{anonfield(typs[13])})
-	typs[74] = typChan(typs[2], Csend)
-	typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[74]), anonfield(typs[3])}, nil)
-	typs[76] = tostruct([]*Node{namedfield("enabled", typs[13]), namedfield("needed", typs[13]), namedfield("cgo", typs[13])})
-	typs[77] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil)
-	typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
-	typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
-	typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[33])})
-	typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[74]), anonfield(typs[3])}, []*Node{anonfield(typs[13])})
-	typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[71])}, []*Node{anonfield(typs[13])})
-	typs[83] = typPtr(typs[13])
-	typs[84] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[83]), anonfield(typs[71])}, []*Node{anonfield(typs[13])})
-	typs[85] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[10])}, nil)
-	typs[86] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[71]), anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[13])})
-	typs[87] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[13])})
-	typs[88] = typSlice(typs[2])
-	typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[33]), anonfield(typs[33])}, []*Node{anonfield(typs[88])})
-	typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[88])})
-	typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[88]), anonfield(typs[33])}, []*Node{anonfield(typs[88])})
-	typs[92] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil)
-	typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[50])}, nil)
-	typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[13])})
-	typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[13])})
-	typs[96] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
-	typs[97] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
-	typs[98] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[17])})
-	typs[99] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[19])})
-	typs[100] = Types[TUINT32]
-	typs[101] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[100])})
-	typs[102] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[15])})
-	typs[103] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[15])})
-	typs[104] = functype(nil, []*Node{anonfield(typs[100])}, []*Node{anonfield(typs[15])})
-	typs[105] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
-	typs[106] = functype(nil, []*Node{anonfield(typs[50])}, nil)
-	typs[107] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil)
+	typs[23] = functype(nil, []*Node{anonfield(typs[2])}, nil)
+	typs[24] = types.NewArray(typs[0], 32)
+	typs[25] = types.NewPtr(typs[24])
+	typs[26] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
+	typs[27] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
+	typs[28] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
+	typs[29] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
+	typs[30] = types.NewSlice(typs[21])
+	typs[31] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[30])}, []*Node{anonfield(typs[21])})
+	typs[32] = types.Types[TINT]
+	typs[33] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[32])})
+	typs[34] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[11])})
+	typs[35] = types.NewArray(typs[0], 4)
+	typs[36] = types.NewPtr(typs[35])
+	typs[37] = functype(nil, []*Node{anonfield(typs[36]), anonfield(typs[15])}, []*Node{anonfield(typs[21])})
+	typs[38] = types.NewSlice(typs[0])
+	typs[39] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[38])}, []*Node{anonfield(typs[21])})
+	typs[40] = functype(nil, []*Node{anonfield(typs[38])}, []*Node{anonfield(typs[21])})
+	typs[41] = types.Runetype
+	typs[42] = types.NewSlice(typs[41])
+	typs[43] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[42])}, []*Node{anonfield(typs[21])})
+	typs[44] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[21])}, []*Node{anonfield(typs[38])})
+	typs[45] = types.NewArray(typs[41], 32)
+	typs[46] = types.NewPtr(typs[45])
+	typs[47] = functype(nil, []*Node{anonfield(typs[46]), anonfield(typs[21])}, []*Node{anonfield(typs[42])})
+	typs[48] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[32])}, []*Node{anonfield(typs[41]), anonfield(typs[32])})
+	typs[49] = types.Types[TUINTPTR]
+	typs[50] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[49])}, []*Node{anonfield(typs[32])})
+	typs[51] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])})
+	typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
+	typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
+	typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])})
+	typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+	typs[56] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+	typs[57] = types.NewPtr(typs[49])
+	typs[58] = types.Types[TUNSAFEPTR]
+	typs[59] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[58]), anonfield(typs[58])}, []*Node{anonfield(typs[11])})
+	typs[60] = types.NewMap(typs[2], typs[2])
+	typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[60])})
+	typs[62] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
+	typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
+	typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+	typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+	typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+	typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+	typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[3])}, nil)
+	typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[60]), anonfield(typs[2])}, nil)
+	typs[70] = functype(nil, []*Node{anonfield(typs[3])}, nil)
+	typs[71] = types.NewChan(typs[2], types.Cboth)
+	typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[71])})
+	typs[73] = types.NewChan(typs[2], types.Crecv)
+	typs[74] = functype(nil, []*Node{anonfield(typs[73]), anonfield(typs[3])}, nil)
+	typs[75] = functype(nil, []*Node{anonfield(typs[73]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+	typs[76] = types.NewChan(typs[2], types.Csend)
+	typs[77] = functype(nil, []*Node{anonfield(typs[76]), anonfield(typs[3])}, nil)
+	typs[78] = types.NewArray(typs[0], 3)
+	typs[79] = tostruct([]*Node{namedfield("enabled", typs[11]), namedfield("pad", typs[78]), namedfield("needed", typs[11]), namedfield("cgo", typs[11]), namedfield("alignme", typs[17])})
+	typs[80] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[2])}, nil)
+	typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+	typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+	typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])})
+	typs[84] = functype(nil, []*Node{anonfield(typs[76]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+	typs[85] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[73])}, []*Node{anonfield(typs[11])})
+	typs[86] = types.NewPtr(typs[11])
+	typs[87] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[86]), anonfield(typs[73])}, []*Node{anonfield(typs[11])})
+	typs[88] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[8])}, nil)
+	typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[76]), anonfield(typs[3])}, nil)
+	typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[73]), anonfield(typs[3]), anonfield(typs[86])}, nil)
+	typs[91] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[32])})
+	typs[92] = types.NewSlice(typs[2])
+	typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[92])})
+	typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[92])})
+	typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[92]), anonfield(typs[32])}, []*Node{anonfield(typs[92])})
+	typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[49])}, nil)
+	typs[97] = functype(nil, []*Node{anonfield(typs[58]), anonfield(typs[49])}, nil)
+	typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[49])}, []*Node{anonfield(typs[11])})
+	typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+	typs[100] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+	typs[101] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
+	typs[102] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
+	typs[103] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
+	typs[104] = types.Types[TUINT32]
+	typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[104])})
+	typs[106] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
+	typs[107] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
+	typs[108] = functype(nil, []*Node{anonfield(typs[104])}, []*Node{anonfield(typs[13])})
+	typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
+	typs[110] = functype(nil, []*Node{anonfield(typs[49])}, nil)
+	typs[111] = functype(nil, []*Node{anonfield(typs[49]), anonfield(typs[49])}, nil)
 	return typs[:]
 }
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 6951115..7f4846d 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -12,12 +12,14 @@ package runtime
 
 // emitted by compiler, not referred to by go programs
 
+import "unsafe"
+
 func newobject(typ *byte) *any
 func panicindex()
 func panicslice()
 func panicdivide()
 func throwinit()
-func panicwrap(string, string, string)
+func panicwrap()
 
 func gopanic(interface{})
 func gorecover(*int32) interface{}
@@ -59,19 +61,36 @@ func slicestringcopy(to any, fr any) int
 
 // interface conversions
 func convI2I(typ *byte, elem any) (ret any)
+
 func convT2E(typ *byte, elem *any) (ret any)
+func convT2E16(typ *byte, elem *any) (ret any)
+func convT2E32(typ *byte, elem *any) (ret any)
+func convT2E64(typ *byte, elem *any) (ret any)
+func convT2Estring(typ *byte, elem *any) (ret any)
+func convT2Eslice(typ *byte, elem *any) (ret any)
+func convT2Enoptr(typ *byte, elem *any) (ret any)
+
 func convT2I(tab *byte, elem *any) (ret any)
+func convT2I16(tab *byte, elem *any) (ret any)
+func convT2I32(tab *byte, elem *any) (ret any)
+func convT2I64(tab *byte, elem *any) (ret any)
+func convT2Istring(tab *byte, elem *any) (ret any)
+func convT2Islice(tab *byte, elem *any) (ret any)
+func convT2Inoptr(tab *byte, elem *any) (ret any)
 
 // interface type assertions  x.(T)
 func assertE2I(typ *byte, iface any) (ret any)
 func assertE2I2(typ *byte, iface any) (ret any, b bool)
 func assertI2I(typ *byte, iface any) (ret any)
 func assertI2I2(typ *byte, iface any) (ret any, b bool)
-func panicdottype(have, want, iface *byte)
+func panicdottypeE(have, want, iface *byte)
+func panicdottypeI(have, want, iface *byte)
 func panicnildottype(want *byte)
 
-func ifaceeq(i1 any, i2 any) (ret bool)
-func efaceeq(i1 any, i2 any) (ret bool)
+// interface equality. Type/itab pointers are already known to be equal, so
+// we only need to pass one.
+func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
+func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
 
 // *byte is really *runtime.Type
 func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
@@ -86,21 +105,29 @@ func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres
 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 mapassign(mapType *byte, hmap map[any]any, key *any) (val *any)
+func mapassign_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
 func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
 func mapdelete(mapType *byte, hmap map[any]any, key *any)
+func mapdelete_fast32(mapType *byte, hmap map[any]any, key any)
+func mapdelete_fast64(mapType *byte, hmap map[any]any, key any)
+func mapdelete_faststr(mapType *byte, hmap map[any]any, key any)
 func mapiternext(hiter *any)
 
 // *byte is really *runtime.Type
 func makechan(chanType *byte, hint int64) (hchan chan any)
-func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
-func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
-func chansend1(chanType *byte, hchan chan<- any, elem *any)
+func chanrecv1(hchan <-chan any, elem *any)
+func chanrecv2(hchan <-chan any, elem *any) bool
+func chansend1(hchan chan<- any, elem *any)
 func closechan(hchan any)
 
 var writeBarrier struct {
 	enabled bool
+	pad     [3]byte
 	needed  bool
 	cgo     bool
+	alignme uint64
 }
 
 func writebarrierptr(dst *any, src any)
@@ -110,24 +137,23 @@ func typedmemmove(typ *byte, dst *any, src *any)
 func typedmemclr(typ *byte, dst *any)
 func typedslicecopy(typ *byte, dst any, src any) int
 
-func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
-func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
-func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
+func selectnbsend(hchan chan<- any, elem *any) bool
+func selectnbrecv(elem *any, hchan <-chan any) bool
+func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
 
 func newselect(sel *byte, selsize int64, size int32)
-func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
-func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
-func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
-func selectdefault(sel *byte) (selected bool)
-func selectgo(sel *byte)
+func selectsend(sel *byte, hchan chan<- any, elem *any)
+func selectrecv(sel *byte, hchan <-chan any, elem *any, received *bool)
+func selectdefault(sel *byte)
+func selectgo(sel *byte) int
 func block()
 
 func makeslice(typ *byte, len int, cap int) (ary []any)
 func makeslice64(typ *byte, len int64, cap int64) (ary []any)
 func growslice(typ *byte, old []any, cap int) (ary []any)
 func memmove(to *any, frm *any, length uintptr)
-func memclrNoHeapPointers(ptr *byte, length uintptr)
-func memclrHasPointers(ptr *byte, length uintptr)
+func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
+func memclrHasPointers(ptr unsafe.Pointer, n uintptr)
 
 func memequal(x, y *any, size uintptr) bool
 func memequal8(x, y *any) bool
@@ -161,3 +187,6 @@ func racewriterange(addr, size uintptr)
 // memory sanitizer
 func msanread(addr, size uintptr)
 func msanwrite(addr, size uintptr)
+
+// architecture variants
+var support_popcnt bool
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
index 183105f..72f29e8 100644
--- a/src/cmd/compile/internal/gc/bv.go
+++ b/src/cmd/compile/internal/gc/bv.go
@@ -29,8 +29,12 @@ type bulkBvec struct {
 
 func bvbulkalloc(nbit int32, count int32) bulkBvec {
 	nword := (nbit + WORDBITS - 1) / WORDBITS
+	size := int64(nword) * int64(count)
+	if int64(int32(size*4)) != size*4 {
+		Fatalf("bvbulkalloc too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size)
+	}
 	return bulkBvec{
-		words: make([]uint32, nword*count),
+		words: make([]uint32, size),
 		nbit:  nbit,
 		nword: nword,
 	}
@@ -55,9 +59,7 @@ func (bv1 bvec) Eq(bv2 bvec) bool {
 }
 
 func (dst bvec) Copy(src bvec) {
-	for i, x := range src.b {
-		dst.b[i] = x
-	}
+	copy(dst.b, src.b)
 }
 
 func (bv bvec) Get(i int32) bool {
@@ -76,6 +78,14 @@ func (bv bvec) Set(i int32) {
 	bv.b[i/WORDBITS] |= mask
 }
 
+func (bv bvec) Unset(i int32) {
+	if i < 0 || i >= bv.n {
+		Fatalf("bvunset: index %d is out of bounds with length %d\n", i, bv.n)
+	}
+	mask := uint32(1 << uint(i%WORDBITS))
+	bv.b[i/WORDBITS] &^= mask
+}
+
 // bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
 // If there is no such index, bvnext returns -1.
 func (bv bvec) Next(i int32) int32 {
diff --git a/src/cmd/compile/internal/gc/class_string.go b/src/cmd/compile/internal/gc/class_string.go
new file mode 100644
index 0000000..2722f43
--- /dev/null
+++ b/src/cmd/compile/internal/gc/class_string.go
@@ -0,0 +1,16 @@
+// Code generated by "stringer -type=Class"; DO NOT EDIT.
+
+package gc
+
+import "fmt"
+
+const _Class_name = "PxxxPEXTERNPAUTOPAUTOHEAPPPARAMPPARAMOUTPFUNCPDISCARD"
+
+var _Class_index = [...]uint8{0, 4, 11, 16, 25, 31, 40, 45, 53}
+
+func (i Class) String() string {
+	if i >= Class(len(_Class_index)-1) {
+		return fmt.Sprintf("Class(%d)", i)
+	}
+	return _Class_name[_Class_index[i]:_Class_index[i+1]]
+}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 5183510..143e196 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -5,17 +5,21 @@
 package gc
 
 import (
+	"cmd/compile/internal/syntax"
+	"cmd/compile/internal/types"
 	"fmt"
 )
 
-// function literals aka closures
-func closurehdr(ntype *Node) {
-	n := nod(OCLOSURE, nil, nil)
+func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
+	ntype := p.typeExpr(expr.Type)
+
+	n := p.nod(expr, OCLOSURE, nil, nil)
+	n.Func.SetIsHiddenClosure(Curfn != nil)
 	n.Func.Ntype = ntype
 	n.Func.Depth = funcdepth
 	n.Func.Outerfunc = Curfn
 
-	funchdr(n)
+	old := p.funchdr(n, expr.Pos())
 
 	// steal ntype's argument names and
 	// leave a fresh copy in their place.
@@ -23,8 +27,8 @@ func closurehdr(ntype *Node) {
 	// refer to the variables in the external
 	// function declared below; see walkclosure.
 	n.List.Set(ntype.List.Slice())
-
 	n.Rlist.Set(ntype.Rlist.Slice())
+
 	ntype.List.Set(nil)
 	ntype.Rlist.Set(nil)
 	for _, n1 := range n.List.Slice() {
@@ -33,9 +37,9 @@ func closurehdr(ntype *Node) {
 			name = newname(name.Sym)
 		}
 		a := nod(ODCLFIELD, name, n1.Right)
-		a.Isddd = n1.Isddd
+		a.SetIsddd(n1.Isddd())
 		if name != nil {
-			name.Isddd = a.Isddd
+			name.SetIsddd(a.Isddd())
 		}
 		ntype.List.Append(a)
 	}
@@ -46,23 +50,23 @@ func closurehdr(ntype *Node) {
 		}
 		ntype.Rlist.Append(nod(ODCLFIELD, name, n2.Right))
 	}
-}
 
-func closurebody(body []*Node) *Node {
+	body := p.stmts(expr.Body.List)
+
+	lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
 	if len(body) == 0 {
 		body = []*Node{nod(OEMPTY, nil, nil)}
 	}
 
-	func_ := Curfn
-	func_.Nbody.Set(body)
-	func_.Func.Endlineno = lineno
-	funcbody(func_)
+	n.Nbody.Set(body)
+	n.Func.Endlineno = lineno
+	p.funcbody(n, expr.Body.Rbrace, old)
 
 	// closure-specific variables are hanging off the
 	// ordinary ones in the symbol table; see oldname.
 	// unhook them.
 	// make the list of pointers for the closure call.
-	for _, v := range func_.Func.Cvars.Slice() {
+	for _, v := range n.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
@@ -98,14 +102,14 @@ func closurebody(body []*Node) *Node {
 		v.Name.Param.Outer = oldname(v.Sym)
 	}
 
-	return func_
+	return n
 }
 
 func typecheckclosure(func_ *Node, top int) {
 	for _, ln := range func_.Func.Cvars.Slice() {
 		n := ln.Name.Defn
-		if !n.Name.Captured {
-			n.Name.Captured = true
+		if !n.Name.Captured() {
+			n.Name.SetCaptured(true)
 			if n.Name.Decldepth == 0 {
 				Fatalf("typecheckclosure: var %S does not have decldepth assigned", n)
 			}
@@ -113,13 +117,13 @@ func typecheckclosure(func_ *Node, top int) {
 			// Ignore assignments to the variable in straightline code
 			// preceding the first capturing by a closure.
 			if n.Name.Decldepth == decldepth {
-				n.Assigned = false
+				n.SetAssigned(false)
 			}
 		}
 	}
 
 	for _, ln := range func_.Func.Dcl {
-		if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+		if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
 			ln.Name.Decldepth = 1
 		}
 	}
@@ -154,7 +158,7 @@ func typecheckclosure(func_ *Node, top int) {
 
 var closurename_closgen int
 
-func closurename(n *Node) *Sym {
+func closurename(n *Node) *types.Sym {
 	if n.Sym != nil {
 		return n.Sym
 	}
@@ -171,7 +175,7 @@ func closurename(n *Node) *Sym {
 		gen = closurename_closgen
 	case n.Func.Outerfunc.Op == ODCLFUNC:
 		// The outermost closure inside of a named function.
-		outer = n.Func.Outerfunc.Func.Nname.Sym.Name
+		outer = n.Func.Outerfunc.funcname()
 
 		prefix = "func"
 
@@ -195,7 +199,7 @@ func closurename(n *Node) *Sym {
 	default:
 		Fatalf("closurename called for %S", n)
 	}
-	n.Sym = lookupf("%s.%s%d", outer, prefix, gen)
+	n.Sym = lookup(fmt.Sprintf("%s.%s%d", outer, prefix, gen))
 	return n.Sym
 }
 
@@ -209,9 +213,10 @@ func makeclosure(func_ *Node) *Node {
 
 	// create the function
 	xfunc := nod(ODCLFUNC, nil, nil)
+	xfunc.Func.SetIsHiddenClosure(Curfn != nil)
 
 	xfunc.Func.Nname = newfuncname(closurename(func_))
-	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
+	xfunc.Func.Nname.Sym.SetExported(true) // disable export
 	xfunc.Func.Nname.Name.Param.Ntype = xtype
 	xfunc.Func.Nname.Name.Defn = xfunc
 	declare(xfunc.Func.Nname, PFUNC)
@@ -224,7 +229,11 @@ func makeclosure(func_ *Node) *Node {
 
 	xfunc.Nbody.Set(func_.Nbody.Slice())
 	xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
+	xfunc.Func.Parents = func_.Func.Parents
+	xfunc.Func.Marks = func_.Func.Marks
 	func_.Func.Dcl = nil
+	func_.Func.Parents = nil
+	func_.Func.Marks = nil
 	if xfunc.Nbody.Len() == 0 {
 		Fatalf("empty body - won't generate any code")
 	}
@@ -240,6 +249,9 @@ func makeclosure(func_ *Node) *Node {
 	return xfunc
 }
 
+// capturevarscomplete is set to true when the capturevars phase is done.
+var capturevarscomplete bool
+
 // capturevars is called in a separate phase after all typechecking is done.
 // It decides whether each variable captured by a closure should be captured
 // by value or by reference.
@@ -247,7 +259,7 @@ func makeclosure(func_ *Node) *Node {
 // after capturing (effectively constant).
 func capturevars(xfunc *Node) {
 	lno := lineno
-	lineno = xfunc.Lineno
+	lineno = xfunc.Pos
 
 	func_ := xfunc.Func.Closure
 	func_.Func.Enter.Set(nil)
@@ -272,23 +284,23 @@ func capturevars(xfunc *Node) {
 		outermost := v.Name.Defn
 
 		// out parameters will be assigned to implicitly upon return.
-		if outer.Class != PPARAMOUT && !outermost.Addrtaken && !outermost.Assigned && v.Type.Width <= 128 {
-			v.Name.Byval = true
+		if outer.Class() != PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && v.Type.Width <= 128 {
+			v.Name.SetByval(true)
 		} else {
-			outermost.Addrtaken = true
+			outermost.SetAddrtaken(true)
 			outer = nod(OADDR, outer, nil)
 		}
 
 		if Debug['m'] > 1 {
-			var name *Sym
+			var name *types.Sym
 			if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
 				name = v.Name.Curfn.Func.Nname.Sym
 			}
 			how := "ref"
-			if v.Name.Byval {
+			if v.Name.Byval() {
 				how = "value"
 			}
-			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))
+			Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken(), outermost.Assigned(), int32(v.Type.Width))
 		}
 
 		outer = typecheck(outer, Erv)
@@ -302,7 +314,7 @@ func capturevars(xfunc *Node) {
 // It transform closure bodies to properly reference captured variables.
 func transformclosure(xfunc *Node) {
 	lno := lineno
-	lineno = xfunc.Lineno
+	lineno = xfunc.Pos
 	func_ := xfunc.Func.Closure
 
 	if func_.Func.Top&Ecall != 0 {
@@ -316,7 +328,7 @@ func transformclosure(xfunc *Node) {
 		//		byref++
 		//	}(42)
 		// becomes:
-		//	func(a int, byval int, &byref *int) {
+		//	func(byval int, &byref *int, a int) {
 		//		println(byval)
 		//		(*&byref)++
 		//	}(byval, &byref, 42)
@@ -325,37 +337,35 @@ func transformclosure(xfunc *Node) {
 		f := xfunc.Func.Nname
 
 		// We are going to insert captured variables before input args.
-		var params []*Field
+		var params []*types.Field
 		var decls []*Node
 		for _, v := range func_.Func.Cvars.Slice() {
 			if v.Op == OXXX {
 				continue
 			}
-			fld := newField()
-			fld.Funarg = FunargParams
-			if v.Name.Byval {
+			fld := types.NewField()
+			fld.Funarg = types.FunargParams
+			if v.Name.Byval() {
 				// If v is captured by value, we merely downgrade it to PPARAM.
-				v.Class = PPARAM
-
-				v.Ullman = 1
-				fld.Nname = v
+				v.SetClass(PPARAM)
+				fld.Nname = asTypesNode(v)
 			} else {
 				// If v of type T is captured by reference,
 				// we introduce function param &v *T
 				// and v remains PAUTOHEAP with &v heapaddr
 				// (accesses will implicitly deref &v).
-				addr := newname(lookupf("&%s", v.Sym.Name))
-				addr.Type = ptrto(v.Type)
-				addr.Class = PPARAM
-				v.Name.Heapaddr = addr
-				fld.Nname = addr
+				addr := newname(lookup("&" + v.Sym.Name))
+				addr.Type = types.NewPtr(v.Type)
+				addr.SetClass(PPARAM)
+				v.Name.Param.Heapaddr = addr
+				fld.Nname = asTypesNode(addr)
 			}
 
-			fld.Type = fld.Nname.Type
-			fld.Sym = fld.Nname.Sym
+			fld.Type = asNode(fld.Nname).Type
+			fld.Sym = asNode(fld.Nname).Sym
 
 			params = append(params, fld)
-			decls = append(decls, fld.Nname)
+			decls = append(decls, asNode(fld.Nname))
 		}
 
 		if len(params) > 0 {
@@ -364,10 +374,6 @@ func transformclosure(xfunc *Node) {
 			xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...)
 		}
 
-		// Recalculate param offsets.
-		if f.Type.Width > 0 {
-			Fatalf("transformclosure: width is already calculated")
-		}
 		dowidth(f.Type)
 		xfunc.Type = f.Type // update type of ODCLFUNC
 	} else {
@@ -383,30 +389,29 @@ func transformclosure(xfunc *Node) {
 			cv := nod(OCLOSUREVAR, nil, nil)
 
 			cv.Type = v.Type
-			if !v.Name.Byval {
-				cv.Type = ptrto(v.Type)
+			if !v.Name.Byval() {
+				cv.Type = types.NewPtr(v.Type)
 			}
 			offset = Rnd(offset, int64(cv.Type.Align))
 			cv.Xoffset = offset
 			offset += cv.Type.Width
 
-			if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) {
+			if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
 				// If it is a small variable captured by value, downgrade it to PAUTO.
-				v.Class = PAUTO
-				v.Ullman = 1
+				v.SetClass(PAUTO)
 				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.
-				addr := newname(lookupf("&%s", v.Sym.Name))
-				addr.Name.Param.Ntype = nod(OIND, typenod(v.Type), nil)
-				addr.Class = PAUTO
-				addr.Used = true
+				addr := newname(lookup("&" + v.Sym.Name))
+				addr.Type = types.NewPtr(v.Type)
+				addr.SetClass(PAUTO)
+				addr.Name.SetUsed(true)
 				addr.Name.Curfn = xfunc
 				xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
-				v.Name.Heapaddr = addr
-				if v.Name.Byval {
+				v.Name.Param.Heapaddr = addr
+				if v.Name.Byval() {
 					cv = nod(OADDR, cv, nil)
 				}
 				body = append(body, nod(OAS, addr, cv))
@@ -417,7 +422,7 @@ func transformclosure(xfunc *Node) {
 			typecheckslice(body, Etop)
 			walkstmtlist(body)
 			xfunc.Func.Enter.Set(body)
-			xfunc.Func.Needctxt = true
+			xfunc.Func.SetNeedctxt(true)
 		}
 	}
 
@@ -441,13 +446,13 @@ func hasemptycvars(func_ *Node) bool {
 func closuredebugruntimecheck(r *Node) {
 	if Debug_closure > 0 {
 		if r.Esc == EscHeap {
-			Warnl(r.Lineno, "heap closure, captured vars = %v", r.Func.Cvars)
+			Warnl(r.Pos, "heap closure, captured vars = %v", r.Func.Cvars)
 		} else {
-			Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars)
+			Warnl(r.Pos, "stack closure, captured vars = %v", r.Func.Cvars)
 		}
 	}
 	if compiling_runtime && r.Esc == EscHeap {
-		yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.")
+		yyerrorl(r.Pos, "heap-allocated closure, not allowed in runtime.")
 	}
 }
 
@@ -455,7 +460,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
 	// If no closure vars, don't bother wrapping.
 	if hasemptycvars(func_) {
 		if Debug_closure > 0 {
-			Warnl(func_.Lineno, "closure converted to global")
+			Warnl(func_.Pos, "closure converted to global")
 		}
 		return func_.Func.Closure.Func.Nname
 	} else {
@@ -478,13 +483,13 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
 
 	typ := nod(OTSTRUCT, nil, nil)
 
-	typ.List.Set1(nod(ODCLFIELD, newname(lookup(".F")), typenod(Types[TUINTPTR])))
+	typ.List.Set1(namedfield(".F", types.Types[TUINTPTR]))
 	for _, v := range func_.Func.Cvars.Slice() {
 		if v.Op == OXXX {
 			continue
 		}
 		typ1 := typenod(v.Type)
-		if !v.Name.Byval {
+		if !v.Name.Byval() {
 			typ1 = nod(OIND, typ1, nil)
 		}
 		typ.List.Append(nod(ODCLFIELD, newname(v.Sym), typ1))
@@ -492,7 +497,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
 
 	clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil))
 	clos.Esc = func_.Esc
-	clos.Right.Implicit = true
+	clos.Right.SetImplicit(true)
 	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.
@@ -518,7 +523,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
 	return walkexpr(clos, init)
 }
 
-func typecheckpartialcall(fn *Node, sym *Sym) {
+func typecheckpartialcall(fn *Node, sym *types.Sym) {
 	switch fn.Op {
 	case ODOTINTER, ODOTMETH:
 		break
@@ -535,9 +540,9 @@ func typecheckpartialcall(fn *Node, sym *Sym) {
 	fn.Type = xfunc.Type
 }
 
-var makepartialcall_gopkg *Pkg
+var makepartialcall_gopkg *types.Pkg
 
-func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
+func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
 	var p string
 
 	rcvrtype := fn.Left.Type
@@ -554,23 +559,23 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
 		Fatalf("missing base type for %v", rcvrtype)
 	}
 
-	var spkg *Pkg
+	var spkg *types.Pkg
 	if basetype.Sym != nil {
 		spkg = basetype.Sym.Pkg
 	}
 	if spkg == nil {
 		if makepartialcall_gopkg == nil {
-			makepartialcall_gopkg = mkpkg("go")
+			makepartialcall_gopkg = types.NewPkg("go", "")
 		}
 		spkg = makepartialcall_gopkg
 	}
 
-	sym := Pkglookup(p, spkg)
+	sym := spkg.Lookup(p)
 
-	if sym.Flags&SymUniq != 0 {
-		return sym.Def
+	if sym.Uniq() {
+		return asNode(sym.Def)
 	}
-	sym.Flags |= SymUniq
+	sym.SetUniq(true)
 
 	savecurfn := Curfn
 	Curfn = nil
@@ -583,12 +588,12 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
 	Curfn = xfunc
 	for i, t := range t0.Params().Fields().Slice() {
 		n := newname(lookupN("a", i))
-		n.Class = PPARAM
+		n.SetClass(PPARAM)
 		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
+		if t.Isddd() {
+			fld.SetIsddd(true)
 			ddd = true
 		}
 
@@ -600,7 +605,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
 	var retargs []*Node
 	for i, t := range t0.Results().Fields().Slice() {
 		n := newname(lookupN("r", i))
-		n.Class = PPARAMOUT
+		n.SetClass(PPARAMOUT)
 		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
 		retargs = append(retargs, n)
 		l = append(l, nod(ODCLFIELD, n, typenod(t.Type)))
@@ -608,43 +613,39 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
 
 	xtype.Rlist.Set(l)
 
-	xfunc.Func.Dupok = true
+	xfunc.Func.SetDupok(true)
 	xfunc.Func.Nname = newfuncname(sym)
-	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
+	xfunc.Func.Nname.Sym.SetExported(true) // disable export
 	xfunc.Func.Nname.Name.Param.Ntype = xtype
 	xfunc.Func.Nname.Name.Defn = xfunc
 	declare(xfunc.Func.Nname, PFUNC)
 
 	// Declare and initialize variable holding receiver.
 
-	xfunc.Func.Needctxt = true
+	xfunc.Func.SetNeedctxt(true)
 	cv := nod(OCLOSUREVAR, nil, nil)
 	cv.Xoffset = int64(Widthptr)
 	cv.Type = rcvrtype
 	if int(cv.Type.Align) > Widthptr {
 		cv.Xoffset = int64(cv.Type.Align)
 	}
-	ptr := nod(ONAME, nil, nil)
-	ptr.Sym = lookup("rcvr")
-	ptr.Class = PAUTO
-	ptr.Addable = true
-	ptr.Ullman = 1
-	ptr.Used = true
+	ptr := newname(lookup("rcvr"))
+	ptr.SetClass(PAUTO)
+	ptr.Name.SetUsed(true)
 	ptr.Name.Curfn = xfunc
-	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)
+		ptr.Type = rcvrtype
 		body = append(body, nod(OAS, ptr, cv))
 	} else {
-		ptr.Name.Param.Ntype = typenod(ptrto(rcvrtype))
+		ptr.Type = types.NewPtr(rcvrtype)
 		body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil)))
 	}
 
 	call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
 	call.List.Set(callargs)
-	call.Isddd = ddd
+	call.SetIsddd(ddd)
 	if t0.Results().NumFields() == 0 {
 		body = append(body, call)
 	} else {
@@ -659,7 +660,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
 	xfunc.Nbody.Set(body)
 
 	xfunc = typecheck(xfunc, Etop)
-	sym.Def = xfunc
+	sym.Def = asTypesNode(xfunc)
 	xtop = append(xtop, xfunc)
 	Curfn = savecurfn
 
@@ -683,12 +684,12 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
 	}
 
 	typ := nod(OTSTRUCT, nil, nil)
-	typ.List.Set1(nod(ODCLFIELD, newname(lookup("F")), typenod(Types[TUINTPTR])))
-	typ.List.Append(nod(ODCLFIELD, newname(lookup("R")), typenod(n.Left.Type)))
+	typ.List.Set1(namedfield("F", types.Types[TUINTPTR]))
+	typ.List.Append(namedfield("R", n.Left.Type))
 
 	clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil))
 	clos.Esc = n.Esc
-	clos.Right.Implicit = true
+	clos.Right.SetImplicit(true)
 	clos.List.Set1(nod(OCFUNC, n.Func.Nname, nil))
 	clos.List.Append(n.Left)
 
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 2b25558..a465d4a 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -4,7 +4,12 @@
 
 package gc
 
-import "strings"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+	"math/big"
+	"strings"
+)
 
 // Ctype describes the constant kind of an "ideal" (untyped) constant.
 type Ctype int8
@@ -112,40 +117,81 @@ type NilVal struct{}
 // n must be an integer or rune constant.
 func (n *Node) Int64() int64 {
 	if !Isconst(n, CTINT) {
-		Fatalf("Int(%v)", n)
+		Fatalf("Int64(%v)", n)
 	}
 	return n.Val().U.(*Mpint).Int64()
 }
 
+// Bool returns n as a bool.
+// n must be a boolean constant.
+func (n *Node) Bool() bool {
+	if !Isconst(n, CTBOOL) {
+		Fatalf("Bool(%v)", n)
+	}
+	return n.Val().U.(bool)
+}
+
 // truncate float literal fv to 32-bit or 64-bit precision
 // according to type; return truncated value.
-func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
+func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
 	if t == nil {
 		return oldv
 	}
 
-	var v Val
-	v.U = oldv
-	overflow(v, t)
+	if overflow(Val{oldv}, t) {
+		// If there was overflow, simply continuing would set the
+		// value to Inf which in turn would lead to spurious follow-on
+		// errors. Avoid this by returning the existing value.
+		return oldv
+	}
 
 	fv := newMpflt()
-	fv.Set(oldv)
 
 	// convert large precision literal floating
 	// into limited precision (float64 or float32)
 	switch t.Etype {
-	case TFLOAT64:
-		d := fv.Float64()
-		fv.SetFloat64(d)
-
-	case TFLOAT32:
-		d := fv.Float32()
-		fv.SetFloat64(d)
+	case types.TFLOAT32:
+		fv.SetFloat64(oldv.Float32())
+	case types.TFLOAT64:
+		fv.SetFloat64(oldv.Float64())
+	default:
+		Fatalf("truncfltlit: unexpected Etype %v", t.Etype)
 	}
 
 	return fv
 }
 
+// truncate Real and Imag parts of Mpcplx to 32-bit or 64-bit
+// precision, according to type; return truncated value. In case of
+// overflow, calls yyerror but does not truncate the input value.
+func trunccmplxlit(oldv *Mpcplx, t *types.Type) *Mpcplx {
+	if t == nil {
+		return oldv
+	}
+
+	if overflow(Val{oldv}, t) {
+		// If there was overflow, simply continuing would set the
+		// value to Inf which in turn would lead to spurious follow-on
+		// errors. Avoid this by returning the existing value.
+		return oldv
+	}
+
+	cv := newMpcmplx()
+
+	switch t.Etype {
+	case types.TCOMPLEX64:
+		cv.Real.SetFloat64(oldv.Real.Float32())
+		cv.Imag.SetFloat64(oldv.Imag.Float32())
+	case types.TCOMPLEX128:
+		cv.Real.SetFloat64(oldv.Real.Float64())
+		cv.Imag.SetFloat64(oldv.Imag.Float64())
+	default:
+		Fatalf("trunccplxlit: unexpected Etype %v", t.Etype)
+	}
+
+	return cv
+}
+
 // canReuseNode indicates whether it is known to be safe
 // to reuse a Node.
 type canReuseNode bool
@@ -159,7 +205,7 @@ const (
 // implicit conversion.
 // 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 {
+func convlit(n *Node, t *types.Type) *Node {
 	return convlit1(n, t, false, noReuse)
 }
 
@@ -167,7 +213,7 @@ func convlit(n *Node, t *Type) *Node {
 // 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 {
+func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
 	if n == nil || t == nil || n.Type == nil || t.IsUntyped() || n.Type == t {
 		return n
 	}
@@ -185,11 +231,11 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 
 	switch n.Op {
 	default:
-		if n.Type == idealbool {
+		if n.Type == types.Idealbool {
 			if t.IsBoolean() {
 				n.Type = t
 			} else {
-				n.Type = Types[TBOOL]
+				n.Type = types.Types[TBOOL]
 			}
 		}
 
@@ -227,17 +273,17 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 			default:
 				// If trying to convert to non-complex type,
 				// leave as complex128 and let typechecker complain.
-				t = Types[TCOMPLEX128]
+				t = types.Types[TCOMPLEX128]
 				fallthrough
-			case TCOMPLEX128:
+			case types.TCOMPLEX128:
 				n.Type = t
-				n.Left = convlit(n.Left, Types[TFLOAT64])
-				n.Right = convlit(n.Right, Types[TFLOAT64])
+				n.Left = convlit(n.Left, types.Types[TFLOAT64])
+				n.Right = convlit(n.Right, types.Types[TFLOAT64])
 
 			case TCOMPLEX64:
 				n.Type = t
-				n.Left = convlit(n.Left, Types[TFLOAT32])
-				n.Right = convlit(n.Right, Types[TFLOAT32])
+				n.Left = convlit(n.Left, types.Types[TFLOAT32])
+				n.Right = convlit(n.Right, types.Types[TFLOAT32])
 			}
 		}
 
@@ -250,14 +296,14 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 	}
 
 	ct := consttype(n)
-	var et EType
+	var et types.EType
 	if ct < 0 {
 		goto bad
 	}
 
 	et = t.Etype
 	if et == TINTER {
-		if ct == CTNIL && n.Type == Types[TNIL] {
+		if ct == CTNIL && n.Type == types.Types[TNIL] {
 			n.Type = t
 			return n
 		}
@@ -295,8 +341,9 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 		// if it is an unsafe.Pointer
 		case TUINTPTR:
 			if n.Type.Etype == TUNSAFEPTR {
-				n.SetVal(Val{new(Mpint)})
-				n.Val().U.(*Mpint).SetInt64(0)
+				i := new(Mpint)
+				i.SetInt64(0)
+				n.SetVal(Val{i})
 			} else {
 				goto bad
 			}
@@ -346,9 +393,9 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 				fallthrough
 
 			case CTCPLX:
-				overflow(n.Val(), t)
+				n.SetVal(Val{trunccmplxlit(n.Val().U.(*Mpcplx), t)})
 			}
-		} else if et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
+		} else if et == types.TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
 			n.SetVal(tostr(n.Val()))
 		} else {
 			goto bad
@@ -359,11 +406,11 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
 	return n
 
 bad:
-	if !n.Diag {
-		if !t.Broke {
+	if !n.Diag() {
+		if !t.Broke() {
 			yyerror("cannot convert %v to type %v", n, t)
 		}
-		n.Diag = true
+		n.SetDiag(true)
 	}
 
 	if n.Type.IsUntyped() {
@@ -443,31 +490,43 @@ func toint(v Val) Val {
 
 	case *Mpflt:
 		i := new(Mpint)
-		if i.SetFloat(u) < 0 {
-			msg := "constant %v truncated to integer"
-			// provide better error message if SetFloat failed because f was too large
-			if u.Val.IsInt() {
-				msg = "constant %v overflows integer"
+		if !i.SetFloat(u) {
+			if i.checkOverflow(0) {
+				yyerror("integer too large")
+			} else {
+				// The value of u cannot be represented as an integer;
+				// so we need to print an error message.
+				// Unfortunately some float values cannot be
+				// reasonably formatted for inclusion in an error
+				// message (example: 1 + 1e-100), so first we try to
+				// format the float; if the truncation resulted in
+				// something that looks like an integer we omit the
+				// value from the error message.
+				// (See issue #11371).
+				var t big.Float
+				t.Parse(fconv(u, FmtSharp), 10)
+				if t.IsInt() {
+					yyerror("constant truncated to integer")
+				} else {
+					yyerror("constant %v truncated to integer", fconv(u, FmtSharp))
+				}
 			}
-			yyerror(msg, fconv(u, FmtSharp))
 		}
 		v.U = i
 
 	case *Mpcplx:
 		i := new(Mpint)
-		if i.SetFloat(&u.Real) < 0 {
+		if !i.SetFloat(&u.Real) || u.Imag.CmpFloat64(0) != 0 {
 			yyerror("constant %v%vi truncated to integer", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|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
 	}
 
 	return v
 }
 
-func doesoverflow(v Val, t *Type) bool {
+func doesoverflow(v Val, t *types.Type) bool {
 	switch u := v.U.(type) {
 	case *Mpint:
 		if !t.IsInteger() {
@@ -492,21 +551,25 @@ func doesoverflow(v Val, t *Type) bool {
 	return false
 }
 
-func overflow(v Val, t *Type) {
+func overflow(v Val, t *types.Type) bool {
 	// v has already been converted
 	// to appropriate form for t.
 	if t == nil || t.Etype == TIDEAL {
-		return
+		return false
 	}
 
 	// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
 	if t.Etype == TUNSAFEPTR {
-		return
+		return false
 	}
 
 	if doesoverflow(v, t) {
 		yyerror("constant %v overflows %v", v, t)
+		return true
 	}
+
+	return false
+
 }
 
 func tostr(v Val) Val {
@@ -676,8 +739,9 @@ func evconst(n *Node) {
 
 	nr := n.Right
 	var rv Val
-	var lno int32
-	var wr EType
+	var lno src.XPos
+	var wr types.EType
+	var ctype uint32
 	var v Val
 	var norig *Node
 	var nn *Node
@@ -690,11 +754,17 @@ func evconst(n *Node) {
 			v = copyval(v)
 		}
 
-		switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
+		// rune values are int values for the purpose of constant folding.
+		ctype = uint32(v.Ctype())
+		if ctype == CTRUNE_ {
+			ctype = CTINT_
+		}
+
+		switch uint32(n.Op)<<16 | ctype {
 		default:
-			if !n.Diag {
+			if !n.Diag() {
 				yyerror("illegal constant expression %v %v", n.Op, nl.Type)
-				n.Diag = true
+				n.SetDiag(true)
 			}
 			return
 
@@ -707,24 +777,21 @@ func evconst(n *Node) {
 			}
 			fallthrough
 		case OCONV_ | CTINT_,
-			OCONV_ | CTRUNE_,
 			OCONV_ | CTFLT_,
+			OCONV_ | CTCPLX_,
 			OCONV_ | CTSTR_,
 			OCONV_ | CTBOOL_:
 			nl = convlit1(nl, n.Type, true, false)
 			v = nl.Val()
 
-		case OPLUS_ | CTINT_,
-			OPLUS_ | CTRUNE_:
+		case OPLUS_ | CTINT_:
 			break
 
-		case OMINUS_ | CTINT_,
-			OMINUS_ | CTRUNE_:
+		case OMINUS_ | CTINT_:
 			v.U.(*Mpint).Neg()
 
-		case OCOM_ | CTINT_,
-			OCOM_ | CTRUNE_:
-			var et EType = Txxx
+		case OCOM_ | CTINT_:
+			var et types.EType = Txxx
 			if nl.Type != nil {
 				et = nl.Type.Etype
 			}
@@ -784,6 +851,9 @@ func evconst(n *Node) {
 	// check for compatible general types (numeric, string, etc)
 	if wl != wr {
 		if wl == TINTER || wr == TINTER {
+			if n.Op == ONE {
+				goto settrue
+			}
 			goto setfalse
 		}
 		goto illegal
@@ -810,7 +880,7 @@ func evconst(n *Node) {
 	// right must be unsigned.
 	// left can be ideal.
 	case OLSH, ORSH:
-		nr = defaultlit(nr, Types[TUINT])
+		nr = defaultlit(nr, types.Types[TUINT])
 
 		n.Right = nr
 		if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) {
@@ -871,25 +941,27 @@ func evconst(n *Node) {
 		Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
 	}
 
+	// rune values are int values for the purpose of constant folding.
+	ctype = uint32(v.Ctype())
+	if ctype == CTRUNE_ {
+		ctype = CTINT_
+	}
+
 	// run op
-	switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
+	switch uint32(n.Op)<<16 | ctype {
 	default:
 		goto illegal
 
-	case OADD_ | CTINT_,
-		OADD_ | CTRUNE_:
+	case OADD_ | CTINT_:
 		v.U.(*Mpint).Add(rv.U.(*Mpint))
 
-	case OSUB_ | CTINT_,
-		OSUB_ | CTRUNE_:
+	case OSUB_ | CTINT_:
 		v.U.(*Mpint).Sub(rv.U.(*Mpint))
 
-	case OMUL_ | CTINT_,
-		OMUL_ | CTRUNE_:
+	case OMUL_ | CTINT_:
 		v.U.(*Mpint).Mul(rv.U.(*Mpint))
 
-	case ODIV_ | CTINT_,
-		ODIV_ | CTRUNE_:
+	case ODIV_ | CTINT_:
 		if rv.U.(*Mpint).CmpInt64(0) == 0 {
 			yyerror("division by zero")
 			v.U.(*Mpint).SetOverflow()
@@ -898,8 +970,7 @@ func evconst(n *Node) {
 
 		v.U.(*Mpint).Quo(rv.U.(*Mpint))
 
-	case OMOD_ | CTINT_,
-		OMOD_ | CTRUNE_:
+	case OMOD_ | CTINT_:
 		if rv.U.(*Mpint).CmpInt64(0) == 0 {
 			yyerror("division by zero")
 			v.U.(*Mpint).SetOverflow()
@@ -908,28 +979,22 @@ func evconst(n *Node) {
 
 		v.U.(*Mpint).Rem(rv.U.(*Mpint))
 
-	case OLSH_ | CTINT_,
-		OLSH_ | CTRUNE_:
+	case OLSH_ | CTINT_:
 		v.U.(*Mpint).Lsh(rv.U.(*Mpint))
 
-	case ORSH_ | CTINT_,
-		ORSH_ | CTRUNE_:
+	case ORSH_ | CTINT_:
 		v.U.(*Mpint).Rsh(rv.U.(*Mpint))
 
-	case OOR_ | CTINT_,
-		OOR_ | CTRUNE_:
+	case OOR_ | CTINT_:
 		v.U.(*Mpint).Or(rv.U.(*Mpint))
 
-	case OAND_ | CTINT_,
-		OAND_ | CTRUNE_:
+	case OAND_ | CTINT_:
 		v.U.(*Mpint).And(rv.U.(*Mpint))
 
-	case OANDNOT_ | CTINT_,
-		OANDNOT_ | CTRUNE_:
+	case OANDNOT_ | CTINT_:
 		v.U.(*Mpint).AndNot(rv.U.(*Mpint))
 
-	case OXOR_ | CTINT_,
-		OXOR_ | CTRUNE_:
+	case OXOR_ | CTINT_:
 		v.U.(*Mpint).Xor(rv.U.(*Mpint))
 
 	case OADD_ | CTFLT_:
@@ -953,9 +1018,9 @@ func evconst(n *Node) {
 	// The default case above would print 'ideal % ideal',
 	// which is not quite an ideal error.
 	case OMOD_ | CTFLT_:
-		if !n.Diag {
+		if !n.Diag() {
 			yyerror("illegal constant expression: floating-point %% operation")
-			n.Diag = true
+			n.SetDiag(true)
 		}
 
 		return
@@ -972,58 +1037,50 @@ func evconst(n *Node) {
 		cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
 
 	case ODIV_ | CTCPLX_:
-		if rv.U.(*Mpcplx).Real.CmpFloat64(0) == 0 && rv.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
+		if !cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx)) {
 			yyerror("complex division by zero")
 			rv.U.(*Mpcplx).Real.SetFloat64(1.0)
 			rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
 			break
 		}
 
-		cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
-
 	case OEQ_ | CTNIL_:
 		goto settrue
 
 	case ONE_ | CTNIL_:
 		goto setfalse
 
-	case OEQ_ | CTINT_,
-		OEQ_ | CTRUNE_:
+	case OEQ_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
-	case ONE_ | CTINT_,
-		ONE_ | CTRUNE_:
+	case ONE_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
 			goto settrue
 		}
 		goto setfalse
 
-	case OLT_ | CTINT_,
-		OLT_ | CTRUNE_:
+	case OLT_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
 			goto settrue
 		}
 		goto setfalse
 
-	case OLE_ | CTINT_,
-		OLE_ | CTRUNE_:
+	case OLE_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
 			goto settrue
 		}
 		goto setfalse
 
-	case OGE_ | CTINT_,
-		OGE_ | CTRUNE_:
+	case OGE_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
 			goto settrue
 		}
 		goto setfalse
 
-	case OGT_ | CTINT_,
-		OGT_ | CTRUNE_:
+	case OGT_ | CTINT_:
 		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) > 0 {
 			goto settrue
 		}
@@ -1179,9 +1236,9 @@ setfalse:
 	return
 
 illegal:
-	if !n.Diag {
+	if !n.Diag() {
 		yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
-		n.Diag = true
+		n.SetDiag(true)
 	}
 }
 
@@ -1193,16 +1250,16 @@ func nodlit(v Val) *Node {
 		Fatalf("nodlit ctype %d", v.Ctype())
 
 	case CTSTR:
-		n.Type = idealstring
+		n.Type = types.Idealstring
 
 	case CTBOOL:
-		n.Type = idealbool
+		n.Type = types.Idealbool
 
 	case CTINT, CTRUNE, CTFLT, CTCPLX:
-		n.Type = Types[TIDEAL]
+		n.Type = types.Types[TIDEAL]
 
 	case CTNIL:
-		n.Type = Types[TNIL]
+		n.Type = types.Types[TNIL]
 	}
 
 	return n
@@ -1214,7 +1271,7 @@ func nodcplxlit(r Val, i Val) *Node {
 
 	c := new(Mpcplx)
 	n := nod(OLITERAL, nil, nil)
-	n.Type = Types[TIDEAL]
+	n.Type = types.Types[TIDEAL]
 	n.SetVal(Val{c})
 
 	if r.Ctype() != CTFLT || i.Ctype() != CTFLT {
@@ -1292,13 +1349,13 @@ func idealkind(n *Node) Ctype {
 
 // 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 {
+func defaultlit(n *Node, t *types.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 {
+func defaultlitreuse(n *Node, t *types.Type, reuse canReuseNode) *Node {
 	if n == nil || !n.Type.IsUntyped() {
 		return n
 	}
@@ -1311,7 +1368,7 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
 
 	lno := setlineno(n)
 	ctype := idealkind(n)
-	var t1 *Type
+	var t1 *types.Type
 	switch ctype {
 	default:
 		if t != nil {
@@ -1320,9 +1377,9 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
 
 		if n.Val().Ctype() == CTNIL {
 			lineno = lno
-			if !n.Diag {
+			if !n.Diag() {
 				yyerror("use of untyped nil")
-				n.Diag = true
+				n.SetDiag(true)
 			}
 
 			n.Type = nil
@@ -1330,7 +1387,7 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
 		}
 
 		if n.Val().Ctype() == CTSTR {
-			t1 := Types[TSTRING]
+			t1 := types.Types[TSTRING]
 			n = convlit1(n, t1, false, reuse)
 			break
 		}
@@ -1341,26 +1398,26 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
 		Fatalf("defaultlit: idealkind is CTxxx: %+v", n)
 
 	case CTBOOL:
-		t1 := Types[TBOOL]
+		t1 := types.Types[TBOOL]
 		if t != nil && t.IsBoolean() {
 			t1 = t
 		}
 		n = convlit1(n, t1, false, reuse)
 
 	case CTINT:
-		t1 = Types[TINT]
+		t1 = types.Types[TINT]
 		goto num
 
 	case CTRUNE:
-		t1 = runetype
+		t1 = types.Runetype
 		goto num
 
 	case CTFLT:
-		t1 = Types[TFLOAT64]
+		t1 = types.Types[TFLOAT64]
 		goto num
 
 	case CTCPLX:
-		t1 = Types[TCOMPLEX128]
+		t1 = types.Types[TCOMPLEX128]
 		goto num
 	}
 
@@ -1420,32 +1477,32 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
 	}
 
 	if l.Type.IsBoolean() {
-		l = convlit(l, Types[TBOOL])
-		r = convlit(r, Types[TBOOL])
+		l = convlit(l, types.Types[TBOOL])
+		r = convlit(r, types.Types[TBOOL])
 	}
 
 	lkind := idealkind(l)
 	rkind := idealkind(r)
 	if lkind == CTCPLX || rkind == CTCPLX {
-		l = convlit(l, Types[TCOMPLEX128])
-		r = convlit(r, Types[TCOMPLEX128])
+		l = convlit(l, types.Types[TCOMPLEX128])
+		r = convlit(r, types.Types[TCOMPLEX128])
 		return l, r
 	}
 
 	if lkind == CTFLT || rkind == CTFLT {
-		l = convlit(l, Types[TFLOAT64])
-		r = convlit(r, Types[TFLOAT64])
+		l = convlit(l, types.Types[TFLOAT64])
+		r = convlit(r, types.Types[TFLOAT64])
 		return l, r
 	}
 
 	if lkind == CTRUNE || rkind == CTRUNE {
-		l = convlit(l, runetype)
-		r = convlit(r, runetype)
+		l = convlit(l, types.Runetype)
+		r = convlit(r, types.Runetype)
 		return l, r
 	}
 
-	l = convlit(l, Types[TINT])
-	r = convlit(r, Types[TINT])
+	l = convlit(l, types.Types[TINT])
+	r = convlit(r, types.Types[TINT])
 
 	return l, r
 }
@@ -1491,7 +1548,7 @@ func nonnegintconst(n *Node) int64 {
 	// Mpint, so we still have to guard the conversion.
 	v := toint(n.Val())
 	vi, ok := v.U.(*Mpint)
-	if !ok || vi.Val.Sign() < 0 || vi.Cmp(maxintval[TINT32]) > 0 {
+	if !ok || vi.CmpInt64(0) < 0 || vi.Cmp(maxintval[TINT32]) > 0 {
 		return -1
 	}
 
@@ -1532,7 +1589,11 @@ func cmplxmpy(v *Mpcplx, rv *Mpcplx) {
 
 // complex divide v /= rv
 //	(a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
+func cmplxdiv(v *Mpcplx, rv *Mpcplx) bool {
+	if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
+		return false
+	}
+
 	var ac Mpflt
 	var bd Mpflt
 	var bc Mpflt
@@ -1540,6 +1601,7 @@ func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
 	var cc_plus_dd Mpflt
 
 	cc_plus_dd.Set(&rv.Real)
+
 	cc_plus_dd.Mul(&rv.Real) // cc
 
 	ac.Set(&rv.Imag)
@@ -1548,6 +1610,14 @@ func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
 
 	cc_plus_dd.Add(&ac) // cc+dd
 
+	// We already checked that c and d are not both zero, but we can't
+	// assume that c²+d² != 0 follows, because for tiny values of c
+	// and/or d c²+d² can underflow to zero.  Check that c²+d² is
+	// nonzero,return if it's not.
+	if cc_plus_dd.CmpFloat64(0) == 0 {
+		return false
+	}
+
 	ac.Set(&v.Real)
 
 	ac.Mul(&rv.Real) // ac
@@ -1573,6 +1643,8 @@ func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
 
 	v.Imag.Sub(&ad)         // bc-ad
 	v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
+
+	return true
 }
 
 // Is n a Go language constant (as opposed to a compile-time constant)?
@@ -1647,13 +1719,13 @@ func isgoconst(n *Node) bool {
 		}
 
 	case ONAME:
-		l := n.Sym.Def
+		l := asNode(n.Sym.Def)
 		if l != nil && l.Op == OLITERAL && n.Val().Ctype() != CTNIL {
 			return true
 		}
 
 	case ONONAME:
-		if n.Sym.Def != nil && n.Sym.Def.Op == OIOTA {
+		if asNode(n.Sym.Def) != nil && asNode(n.Sym.Def).Op == OIOTA {
 			return true
 		}
 
diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go
index fe57717..59f905d 100644
--- a/src/cmd/compile/internal/gc/constFold_test.go
+++ b/src/cmd/compile/internal/gc/constFold_test.go
@@ -1,3 +1,6 @@
+// run
+// Code generated by gen/constFoldGen.go. DO NOT EDIT.
+
 package gc
 
 import "testing"
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 3cdd71d..b8a5a90 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -5,9 +5,9 @@
 package gc
 
 import (
-	"cmd/internal/obj"
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"fmt"
-	"sort"
 	"strings"
 )
 
@@ -15,105 +15,18 @@ import (
 
 var externdcl []*Node
 
-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
-	a.Block = b.Block
-	a.Lastlineno = b.Lastlineno
-}
-
-func push() *Sym {
-	d := new(Sym)
-	d.Lastlineno = lineno
-	d.Link = dclstack
-	dclstack = d
-	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)
-	return d
-}
-
-// popdcl pops the innermost block scope and restores all symbol declarations
-// to their previous state.
-func popdcl() {
-	d := dclstack
-	for ; d != nil && d.Name != ""; d = d.Link {
-		s := Pkglookup(d.Name, d.Pkg)
-		lno := s.Lastlineno
-		dcopy(s, d)
-		d.Lastlineno = lno
-	}
-
-	if d == nil {
-		Fatalf("popdcl: no mark")
-	}
-
-	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
-	d.Block = block
-
-	blockgen++
-	block = blockgen
-}
-
-// keep around for debugging
-func dumpdclstack() {
-	i := 0
-	for d := dclstack; d != nil; d = d.Link {
-		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")
-		}
-		i++
-	}
-}
-
 func testdclstack() {
-	for d := dclstack; d != nil; d = d.Link {
-		if d.Name == "" {
-			if nerrors != 0 {
-				errorexit()
-			}
-			yyerror("mark left on the stack")
+	if !types.IsDclstackValid() {
+		if nerrors != 0 {
+			errorexit()
 		}
+		Fatalf("mark left on the dclstack")
 	}
 }
 
 // redeclare emits a diagnostic about symbol s being redeclared somewhere.
-func redeclare(s *Sym, where string) {
-	if s.Lastlineno == 0 {
+func redeclare(s *types.Sym, where string) {
+	if !s.Lastlineno.IsKnown() {
 		var tmp string
 		if s.Origpkg != nil {
 			tmp = s.Origpkg.Path
@@ -162,11 +75,11 @@ func declare(n *Node, ctxt Class) {
 		// named OLITERAL needs Name; most OLITERALs don't.
 		n.Name = new(Name)
 	}
-	n.Lineno = lineno
+	n.Pos = lineno
 	s := n.Sym
 
 	// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
-	if importpkg == nil && !typecheckok && s.Pkg != localpkg {
+	if !inimport && !typecheckok && s.Pkg != localpkg {
 		yyerror("cannot declare name %v", s)
 	}
 
@@ -191,7 +104,7 @@ func declare(n *Node, ctxt Class) {
 			vargen++
 			gen = vargen
 		}
-		pushdcl(s)
+		types.Pushdcl(s)
 		n.Name.Curfn = Curfn
 	}
 
@@ -199,7 +112,7 @@ func declare(n *Node, ctxt Class) {
 		n.Xoffset = 0
 	}
 
-	if s.Block == block {
+	if s.Block == types.Block {
 		// functype will print errors about duplicate function arguments.
 		// Don't repeat the error here.
 		if ctxt != PPARAM && ctxt != PPARAMOUT {
@@ -207,17 +120,17 @@ func declare(n *Node, ctxt Class) {
 		}
 	}
 
-	s.Block = block
+	s.Block = types.Block
 	s.Lastlineno = lineno
-	s.Def = n
+	s.Def = asTypesNode(n)
 	n.Name.Vargen = int32(gen)
 	n.Name.Funcdepth = funcdepth
-	n.Class = ctxt
+	n.SetClass(ctxt)
 
 	autoexport(n, ctxt)
 }
 
-func addvar(n *Node, t *Type, ctxt Class) {
+func addvar(n *Node, t *types.Type, ctxt Class) {
 	if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
 		Fatalf("addvar: n=%v t=%v nil", n, t)
 	}
@@ -284,124 +197,65 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
 	return init
 }
 
-// declare constants from grammar
-// new_name_list [[type] = expr_list]
-func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
-	lno := int32(0) // default is to leave line number alone in listtreecopy
-	if len(cl) == 0 {
-		if t != nil {
-			yyerror("const declaration cannot have type without expression")
-		}
-		cl = lastconst
-		t = lasttype
-		lno = vl[0].Lineno
-	} else {
-		lastconst = cl
-		lasttype = t
-	}
-	clcopy := listtreecopy(cl, lno)
-
-	var vv []*Node
-	for _, v := range vl {
-		if len(clcopy) == 0 {
-			yyerror("missing value in const declaration")
-			break
-		}
-
-		c := clcopy[0]
-		clcopy = clcopy[1:]
-
-		v.Op = OLITERAL
-		declare(v, dclcontext)
-
-		v.Name.Param.Ntype = t
-		v.Name.Defn = c
-
-		vv = append(vv, nod(ODCLCONST, v, nil))
-	}
-
-	if len(clcopy) != 0 {
-		yyerror("extra expression in const declaration")
-	}
-	iota_ += 1
-	return vv
-}
-
-// newname returns a new ONAME Node associated with symbol s.
-func newname(s *Sym) *Node {
-	if s == nil {
-		Fatalf("newname nil")
-	}
-	n := nod(ONAME, nil, nil)
-	n.Sym = s
-	n.Addable = true
-	n.Ullman = 1
-	n.Xoffset = 0
-	return n
-}
-
 // newnoname returns a new ONONAME Node associated with symbol s.
-func newnoname(s *Sym) *Node {
+func newnoname(s *types.Sym) *Node {
 	if s == nil {
 		Fatalf("newnoname nil")
 	}
 	n := nod(ONONAME, nil, nil)
 	n.Sym = s
-	n.Addable = true
-	n.Ullman = 1
+	n.SetAddable(true)
 	n.Xoffset = 0
 	return n
 }
 
 // newfuncname generates a new name node for a function or method.
 // TODO(rsc): Use an ODCLFUNC node instead. See comment in CL 7360.
-func newfuncname(s *Sym) *Node {
+func newfuncname(s *types.Sym) *Node {
 	n := newname(s)
 	n.Func = new(Func)
-	n.Func.IsHiddenClosure = Curfn != nil
+	n.Func.SetIsHiddenClosure(Curfn != nil)
 	return n
 }
 
 // this generates a new name node for a name
 // being declared.
-func dclname(s *Sym) *Node {
+func dclname(s *types.Sym) *Node {
 	n := newname(s)
 	n.Op = ONONAME // caller will correct it
 	return n
 }
 
-func typenod(t *Type) *Node {
+func typenod(t *types.Type) *Node {
 	// if we copied another type with *t = *u
 	// then t->nod might be out of date, so
 	// check t->nod->type too
-	if t.nod == nil || t.nod.Type != t {
-		t.nod = nod(OTYPE, nil, nil)
-		t.nod.Type = t
-		t.nod.Sym = t.Sym
+	if asNode(t.Nod) == nil || asNode(t.Nod).Type != t {
+		t.Nod = asTypesNode(nod(OTYPE, nil, nil))
+		asNode(t.Nod).Type = t
+		asNode(t.Nod).Sym = t.Sym
 	}
 
-	return t.nod
+	return asNode(t.Nod)
 }
 
-func anonfield(typ *Type) *Node {
+func anonfield(typ *types.Type) *Node {
 	return nod(ODCLFIELD, nil, typenod(typ))
 }
 
-func namedfield(s string, typ *Type) *Node {
+func namedfield(s string, typ *types.Type) *Node {
 	return nod(ODCLFIELD, newname(lookup(s)), typenod(typ))
 }
 
 // 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
+func oldname(s *types.Sym) *Node {
+	n := asNode(s.Def)
 	if n == nil {
 		// 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 = newnoname(s)
-		n.SetIota(iota_) // save current iota value in const declarations
-		return n
+		return newnoname(s)
 	}
 
 	if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != funcdepth {
@@ -414,14 +268,12 @@ func oldname(s *Sym) *Node {
 		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 = PAUTOHEAP
-			c.setIsClosureVar(true)
-			c.Isddd = n.Isddd
+			c = newname(s)
+			c.SetClass(PAUTOHEAP)
+			c.SetIsClosureVar(true)
+			c.SetIsddd(n.Isddd())
 			c.Name.Defn = n
-			c.Addable = false
-			c.Ullman = 2
+			c.SetAddable(false)
 			c.Name.Funcdepth = funcdepth
 
 			// Link into list of active closure variables.
@@ -429,7 +281,6 @@ func oldname(s *Sym) *Node {
 			c.Name.Param.Outer = n.Name.Param.Innermost
 			n.Name.Param.Innermost = c
 
-			c.Xoffset = 0
 			Curfn.Func.Cvars.Append(c)
 		}
 
@@ -457,7 +308,7 @@ func colasname(n *Node) bool {
 func colasdefn(left []*Node, defn *Node) {
 	for _, n := range left {
 		if n.Sym != nil {
-			n.Sym.Flags |= SymUniq
+			n.Sym.SetUniq(true)
 		}
 	}
 
@@ -467,20 +318,20 @@ func colasdefn(left []*Node, defn *Node) {
 			continue
 		}
 		if !colasname(n) {
-			yyerrorl(defn.Lineno, "non-name %v on left side of :=", n)
+			yyerrorl(defn.Pos, "non-name %v on left side of :=", n)
 			nerr++
 			continue
 		}
 
-		if n.Sym.Flags&SymUniq == 0 {
-			yyerrorl(defn.Lineno, "%v repeated on left side of :=", n.Sym)
-			n.Diag = true
+		if !n.Sym.Uniq() {
+			yyerrorl(defn.Pos, "%v repeated on left side of :=", n.Sym)
+			n.SetDiag(true)
 			nerr++
 			continue
 		}
 
-		n.Sym.Flags &^= SymUniq
-		if n.Sym.Block == block {
+		n.Sym.SetUniq(false)
+		if n.Sym.Block == types.Block {
 			continue
 		}
 
@@ -493,7 +344,7 @@ func colasdefn(left []*Node, defn *Node) {
 	}
 
 	if nnew == 0 && nerr == 0 {
-		yyerrorl(defn.Lineno, "no new variables on left side of :=")
+		yyerrorl(defn.Pos, "no new variables on left side of :=")
 	}
 }
 
@@ -519,10 +370,6 @@ func funchdr(n *Node) {
 		Fatalf("funchdr: dclcontext = %d", dclcontext)
 	}
 
-	if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
-		makefuncsym(n.Func.Nname.Sym)
-	}
-
 	dclcontext = PAUTO
 	funcstart(n)
 
@@ -624,34 +471,34 @@ func funcargs(nt *Node) {
 // Same as funcargs, except run over an already constructed TFUNC.
 // This happens during import, where the hidden_fndcl rule has
 // used functype directly to parse the function's type.
-func funcargs2(t *Type) {
+func funcargs2(t *types.Type) {
 	if t.Etype != TFUNC {
 		Fatalf("funcargs2 %v", t)
 	}
 
 	for _, ft := range t.Recvs().Fields().Slice() {
-		if ft.Nname == nil || ft.Nname.Sym == nil {
+		if asNode(ft.Nname) == nil || asNode(ft.Nname).Sym == nil {
 			continue
 		}
-		n := ft.Nname // no need for newname(ft->nname->sym)
+		n := asNode(ft.Nname) // no need for newname(ft->nname->sym)
 		n.Type = ft.Type
 		declare(n, PPARAM)
 	}
 
 	for _, ft := range t.Params().Fields().Slice() {
-		if ft.Nname == nil || ft.Nname.Sym == nil {
+		if asNode(ft.Nname) == nil || asNode(ft.Nname).Sym == nil {
 			continue
 		}
-		n := ft.Nname
+		n := asNode(ft.Nname)
 		n.Type = ft.Type
 		declare(n, PPARAM)
 	}
 
 	for _, ft := range t.Results().Fields().Slice() {
-		if ft.Nname == nil || ft.Nname.Sym == nil {
+		if asNode(ft.Nname) == nil || asNode(ft.Nname).Sym == nil {
 			continue
 		}
-		n := ft.Nname
+		n := asNode(ft.Nname)
 		n.Type = ft.Type
 		declare(n, PPARAMOUT)
 	}
@@ -663,7 +510,7 @@ var funcdepth int32   // len(funcstack) during parsing, but then forced to be th
 // start the function.
 // called before funcargs; undone at end of funcbody.
 func funcstart(n *Node) {
-	markdcl()
+	types.Markdcl()
 	funcstack = append(funcstack, Curfn)
 	funcdepth++
 	Curfn = n
@@ -677,7 +524,7 @@ func funcbody(n *Node) {
 	if dclcontext != PAUTO {
 		Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
 	}
-	popdcl()
+	types.Popdcl()
 	funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
 	funcdepth--
 	if funcdepth == 0 {
@@ -685,26 +532,9 @@ func funcbody(n *Node) {
 	}
 }
 
-// new type being defined with name s.
-func typedcl0(s *Sym) *Node {
-	n := newname(s)
-	n.Op = OTYPE
-	declare(n, dclcontext)
-	return n
-}
-
-// node n, which was returned by typedcl0
-// is being declared to have uncompiled type t.
-// return the ODCLTYPE node to use.
-func typedcl1(n *Node, t *Node, local bool) *Node {
-	n.Name.Param.Ntype = t
-	n.Local = local
-	return nod(ODCLTYPE, n, nil)
-}
-
 // structs, functions, and methods.
 // they don't belong here, but where do they belong?
-func checkembeddedtype(t *Type) {
+func checkembeddedtype(t *types.Type) {
 	if t == nil {
 		return
 	}
@@ -718,21 +548,21 @@ func checkembeddedtype(t *Type) {
 
 	if t.IsPtr() || t.IsUnsafePtr() {
 		yyerror("embedded type cannot be a pointer")
-	} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
+	} else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
 		t.ForwardType().Embedlineno = lineno
 	}
 }
 
-func structfield(n *Node) *Field {
+func structfield(n *Node) *types.Field {
 	lno := lineno
-	lineno = n.Lineno
+	lineno = n.Pos
 
 	if n.Op != ODCLFIELD {
 		Fatalf("structfield: oops %v\n", n)
 	}
 
-	f := newField()
-	f.Isddd = n.Isddd
+	f := types.NewField()
+	f.SetIsddd(n.Isddd())
 
 	if n.Right != nil {
 		n.Right = typecheck(n.Right, Etype)
@@ -740,7 +570,7 @@ func structfield(n *Node) *Field {
 		if n.Left != nil {
 			n.Left.Type = n.Type
 		}
-		if n.Embedded != 0 {
+		if n.Embedded() {
 			checkembeddedtype(n.Type)
 		}
 	}
@@ -749,22 +579,26 @@ func structfield(n *Node) *Field {
 
 	f.Type = n.Type
 	if f.Type == nil {
-		f.Broke = true
+		f.SetBroke(true)
 	}
 
 	switch u := n.Val().U.(type) {
 	case string:
 		f.Note = u
 	default:
-		yyerror("field annotation must be string")
+		yyerror("field tag must be a string")
 	case nil:
-		// noop
+		// no-op
 	}
 
 	if n.Left != nil && n.Left.Op == ONAME {
-		f.Nname = n.Left
-		f.Embedded = n.Embedded
-		f.Sym = f.Nname.Sym
+		f.Nname = asTypesNode(n.Left)
+		if n.Embedded() {
+			f.Embedded = 1
+		} else {
+			f.Embedded = 0
+		}
+		f.Sym = asNode(f.Nname).Sym
 	}
 
 	lineno = lno
@@ -773,45 +607,40 @@ func structfield(n *Node) *Field {
 
 // 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
-
-	seen := make(map[*Sym]bool)
+func checkdupfields(what string, ts ...*types.Type) {
+	seen := make(map[*types.Sym]bool)
 	for _, t := range ts {
 		for _, f := range t.Fields().Slice() {
-			if f.Sym == nil || f.Nname == nil || isblank(f.Nname) {
+			if f.Sym == nil || f.Sym.IsBlank() || asNode(f.Nname) == nil {
 				continue
 			}
 			if seen[f.Sym] {
-				lineno = f.Nname.Lineno
-				yyerror("duplicate %s %s", what, f.Sym.Name)
+				yyerrorl(asNode(f.Nname).Pos, "duplicate %s %s", what, f.Sym.Name)
 				continue
 			}
 			seen[f.Sym] = true
 		}
 	}
-
-	lineno = lno
 }
 
 // convert a parsed id/type list into
 // a type for struct/interface/arglist
-func tostruct(l []*Node) *Type {
-	t := typ(TSTRUCT)
+func tostruct(l []*Node) *types.Type {
+	t := types.New(TSTRUCT)
 	tostruct0(t, l)
 	return t
 }
 
-func tostruct0(t *Type, l []*Node) {
+func tostruct0(t *types.Type, l []*Node) {
 	if t == nil || !t.IsStruct() {
 		Fatalf("struct expected")
 	}
 
-	fields := make([]*Field, len(l))
+	fields := make([]*types.Field, len(l))
 	for i, n := range l {
 		f := structfield(n)
-		if f.Broke {
-			t.Broke = true
+		if f.Broke() {
+			t.SetBroke(true)
 		}
 		fields[i] = f
 	}
@@ -819,26 +648,26 @@ func tostruct0(t *Type, l []*Node) {
 
 	checkdupfields("field", t)
 
-	if !t.Broke {
+	if !t.Broke() {
 		checkwidth(t)
 	}
 }
 
-func tofunargs(l []*Node, funarg Funarg) *Type {
-	t := typ(TSTRUCT)
+func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
+	t := types.New(TSTRUCT)
 	t.StructType().Funarg = funarg
 
-	fields := make([]*Field, len(l))
+	fields := make([]*types.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 n.Left != nil && n.Left.Class == PPARAM {
+		if n.Left != nil && n.Left.Class() == PPARAM {
 			n.Left.Name.Param.Field = f
 		}
-		if f.Broke {
-			t.Broke = true
+		if f.Broke() {
+			t.SetBroke(true)
 		}
 		fields[i] = f
 	}
@@ -846,25 +675,25 @@ func tofunargs(l []*Node, funarg Funarg) *Type {
 	return t
 }
 
-func tofunargsfield(fields []*Field, funarg Funarg) *Type {
-	t := typ(TSTRUCT)
+func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
+	t := types.New(TSTRUCT)
 	t.StructType().Funarg = funarg
 
 	for _, f := range fields {
 		f.Funarg = funarg
 
 		// esc.go needs to find f given a PPARAM to add the tag.
-		if f.Nname != nil && f.Nname.Class == PPARAM {
-			f.Nname.Name.Param.Field = f
+		if asNode(f.Nname) != nil && asNode(f.Nname).Class() == PPARAM {
+			asNode(f.Nname).Name.Param.Field = f
 		}
 	}
 	t.SetFields(fields)
 	return t
 }
 
-func interfacefield(n *Node) *Field {
+func interfacefield(n *Node) *types.Field {
 	lno := lineno
-	lineno = n.Lineno
+	lineno = n.Pos
 
 	if n.Op != ODCLFIELD {
 		Fatalf("interfacefield: oops %v\n", n)
@@ -874,104 +703,64 @@ func interfacefield(n *Node) *Field {
 		yyerror("interface method cannot have annotation")
 	}
 
-	f := newField()
-	f.Isddd = n.Isddd
+	// MethodSpec = MethodName Signature | InterfaceTypeName .
+	//
+	// If Left != nil, then Left is MethodName and Right is Signature.
+	// Otherwise, Right is InterfaceTypeName.
 
 	if n.Right != nil {
-		if n.Left != nil {
-			// queue resolution of method type for later.
-			// right now all we need is the name list.
-			// avoids cycles for recursive interface types.
-			n.Type = typ(TINTERMETH)
-			n.Type.SetNname(n.Right)
-			n.Left.Type = n.Type
-			queuemethod(n)
-
-			if n.Left.Op == ONAME {
-				f.Nname = n.Left
-				f.Embedded = n.Embedded
-				f.Sym = f.Nname.Sym
-			}
-		} else {
-			n.Right = typecheck(n.Right, Etype)
-			n.Type = n.Right.Type
-
-			if n.Embedded != 0 {
-				checkembeddedtype(n.Type)
-			}
-
-			if n.Type != nil {
-				switch n.Type.Etype {
-				case TINTER:
-					break
-
-				case TFORW:
-					yyerror("interface type loop involving %v", n.Type)
-					f.Broke = true
-
-				default:
-					yyerror("interface contains embedded non-interface %v", n.Type)
-					f.Broke = true
-				}
-			}
-		}
+		n.Right = typecheck(n.Right, Etype)
+		n.Type = n.Right.Type
+		n.Right = nil
 	}
 
-	n.Right = nil
+	f := types.NewField()
+	if n.Left != nil {
+		f.Nname = asTypesNode(n.Left)
+		f.Sym = asNode(f.Nname).Sym
+	} else {
+		// Placeholder ONAME just to hold Pos.
+		// TODO(mdempsky): Add Pos directly to Field instead.
+		f.Nname = asTypesNode(newname(nblank.Sym))
+	}
 
 	f.Type = n.Type
 	if f.Type == nil {
-		f.Broke = true
+		f.SetBroke(true)
 	}
 
 	lineno = lno
 	return f
 }
 
-func tointerface(l []*Node) *Type {
-	t := typ(TINTER)
+func tointerface(l []*Node) *types.Type {
+	if len(l) == 0 {
+		return types.Types[TINTER]
+	}
+	t := types.New(TINTER)
 	tointerface0(t, l)
 	return t
 }
 
-func tointerface0(t *Type, l []*Node) *Type {
+func tointerface0(t *types.Type, l []*Node) *types.Type {
 	if t == nil || !t.IsInterface() {
 		Fatalf("interface expected")
 	}
 
-	var fields []*Field
+	var fields []*types.Field
 	for _, n := range l {
 		f := interfacefield(n)
-
-		if n.Left == nil && f.Type.IsInterface() {
-			// embedded interface, inline methods
-			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)
-				}
-				fields = append(fields, f)
-			}
-		} else {
-			fields = append(fields, f)
-		}
-		if f.Broke {
-			t.Broke = true
+		if f.Broke() {
+			t.SetBroke(true)
 		}
+		fields = append(fields, f)
 	}
-	sort.Sort(methcmp(fields))
-	t.SetFields(fields)
-
-	checkdupfields("method", t)
-	checkwidth(t)
+	t.SetInterface(fields)
 
 	return t
 }
 
-func embedded(s *Sym, pkg *Pkg) *Node {
+func embedded(s *types.Sym, pkg *types.Pkg) *Node {
 	const (
 		CenterDot = 0xB7
 	)
@@ -989,49 +778,40 @@ func embedded(s *Sym, pkg *Pkg) *Node {
 		n = newname(lookup(name))
 	} else if s.Pkg == builtinpkg {
 		// The name of embedded builtins belongs to pkg.
-		n = newname(Pkglookup(name, pkg))
+		n = newname(pkg.Lookup(name))
 	} else {
-		n = newname(Pkglookup(name, s.Pkg))
+		n = newname(s.Pkg.Lookup(name))
 	}
 	n = nod(ODCLFIELD, n, oldname(s))
-	n.Embedded = 1
+	n.SetEmbedded(true)
 	return n
 }
 
-// thisT is the singleton type used for interface method receivers.
-var thisT *Type
-
-func fakethis() *Node {
-	if thisT == nil {
-		thisT = ptrto(typ(TSTRUCT))
-	}
-	return nod(ODCLFIELD, nil, typenod(thisT))
+func fakeRecv() *Node {
+	return anonfield(types.FakeRecvType())
 }
 
-func fakethisfield() *Field {
-	if thisT == nil {
-		thisT = ptrto(typ(TSTRUCT))
-	}
-	f := newField()
-	f.Type = thisT
+func fakeRecvField() *types.Field {
+	f := types.NewField()
+	f.Type = types.FakeRecvType()
 	return f
 }
 
-// Is this field a method on an interface?
-// Those methods have thisT as the receiver.
-// (See fakethis above.)
-func isifacemethod(f *Type) bool {
-	return f.Recv().Type == thisT
+// isifacemethod reports whether (field) m is
+// an interface method. Such methods have the
+// special receiver type types.FakeRecvType().
+func isifacemethod(f *types.Type) bool {
+	return f.Recv().Type == types.FakeRecvType()
 }
 
 // turn a parsed function declaration into a type
-func functype(this *Node, in, out []*Node) *Type {
-	t := typ(TFUNC)
+func functype(this *Node, in, out []*Node) *types.Type {
+	t := types.New(TFUNC)
 	functype0(t, this, in, out)
 	return t
 }
 
-func functype0(t *Type, this *Node, in, out []*Node) {
+func functype0(t *types.Type, this *Node, in, out []*Node) {
 	if t == nil || t.Etype != TFUNC {
 		Fatalf("function type expected")
 	}
@@ -1040,14 +820,14 @@ func functype0(t *Type, this *Node, in, out []*Node) {
 	if this != nil {
 		rcvr = []*Node{this}
 	}
-	t.FuncType().Receiver = tofunargs(rcvr, FunargRcvr)
-	t.FuncType().Results = tofunargs(out, FunargResults)
-	t.FuncType().Params = tofunargs(in, FunargParams)
+	t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
+	t.FuncType().Results = tofunargs(out, types.FunargResults)
+	t.FuncType().Params = tofunargs(in, types.FunargParams)
 
 	checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
 
-	if t.Recvs().Broke || t.Results().Broke || t.Params().Broke {
-		t.Broke = true
+	if t.Recvs().Broke() || t.Results().Broke() || t.Params().Broke() {
+		t.SetBroke(true)
 	}
 
 	t.FuncType().Outnamed = false
@@ -1059,136 +839,117 @@ func functype0(t *Type, this *Node, in, out []*Node) {
 	}
 }
 
-func functypefield(this *Field, in, out []*Field) *Type {
-	t := typ(TFUNC)
+func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
+	t := types.New(TFUNC)
 	functypefield0(t, this, in, out)
 	return t
 }
 
-func functypefield0(t *Type, this *Field, in, out []*Field) {
-	var rcvr []*Field
+func functypefield0(t *types.Type, this *types.Field, in, out []*types.Field) {
+	var rcvr []*types.Field
 	if this != nil {
-		rcvr = []*Field{this}
+		rcvr = []*types.Field{this}
 	}
-	t.FuncType().Receiver = tofunargsfield(rcvr, FunargRcvr)
-	t.FuncType().Results = tofunargsfield(out, FunargRcvr)
-	t.FuncType().Params = tofunargsfield(in, FunargRcvr)
+	t.FuncType().Receiver = tofunargsfield(rcvr, types.FunargRcvr)
+	t.FuncType().Results = tofunargsfield(out, types.FunargRcvr)
+	t.FuncType().Params = tofunargsfield(in, types.FunargRcvr)
 
 	t.FuncType().Outnamed = false
-	if len(out) > 0 && out[0].Nname != nil && out[0].Nname.Orig != nil {
-		s := out[0].Nname.Orig.Sym
+	if len(out) > 0 && asNode(out[0].Nname) != nil && asNode(out[0].Nname).Orig != nil {
+		s := asNode(out[0].Nname).Orig.Sym
 		if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
 			t.FuncType().Outnamed = true
 		}
 	}
 }
 
-var methodsym_toppkg *Pkg
+var methodsym_toppkg *types.Pkg
 
-func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
-	var s *Sym
-	var p string
-	var suffix string
-	var spkg *Pkg
+func methodsym(nsym *types.Sym, t0 *types.Type, iface bool) *types.Sym {
+	if t0 == nil {
+		Fatalf("methodsym: nil receiver type")
+	}
 
 	t := t0
-	if t == nil {
-		goto bad
-	}
-	s = t.Sym
+	s := t.Sym
 	if s == nil && t.IsPtr() {
 		t = t.Elem()
 		if t == nil {
-			goto bad
+			Fatalf("methodsym: ptrto nil")
 		}
 		s = t.Sym
 	}
 
-	spkg = nil
-	if s != nil {
-		spkg = s.Pkg
-	}
-
 	// if t0 == *t and t0 has a sym,
 	// we want to see *t, not t0, in the method name.
 	if t != t0 && t0.Sym != nil {
-		t0 = ptrto(t)
+		t0 = types.NewPtr(t)
 	}
 
-	suffix = ""
-	if iface != 0 {
+	suffix := ""
+	if iface {
 		dowidth(t0)
-		if t0.Width < Types[Tptr].Width {
+		if t0.Width < int64(Widthptr) {
 			suffix = "·i"
 		}
 	}
 
-	if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) {
-		if t0.Sym == nil && t0.IsPtr() {
-			p = fmt.Sprintf("(%-S).%s.%s%s", t0, nsym.Pkg.Prefix, nsym.Name, suffix)
-		} else {
-			p = fmt.Sprintf("%-S.%s.%s%s", t0, nsym.Pkg.Prefix, nsym.Name, suffix)
-		}
+	var spkg *types.Pkg
+	if s != nil {
+		spkg = s.Pkg
+	}
+	pkgprefix := ""
+	if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) && nsym.Pkg.Prefix != `""` {
+		pkgprefix = "." + nsym.Pkg.Prefix
+	}
+	var p string
+	if t0.Sym == nil && t0.IsPtr() {
+		p = fmt.Sprintf("(%-S)%s.%s%s", t0, pkgprefix, nsym.Name, suffix)
 	} else {
-		if t0.Sym == nil && t0.IsPtr() {
-			p = fmt.Sprintf("(%-S).%s%s", t0, nsym.Name, suffix)
-		} else {
-			p = fmt.Sprintf("%-S.%s%s", t0, nsym.Name, suffix)
-		}
+		p = fmt.Sprintf("%-S%s.%s%s", t0, pkgprefix, nsym.Name, suffix)
 	}
 
 	if spkg == nil {
 		if methodsym_toppkg == nil {
-			methodsym_toppkg = mkpkg("go")
+			methodsym_toppkg = types.NewPkg("go", "")
 		}
 		spkg = methodsym_toppkg
 	}
 
-	s = Pkglookup(p, spkg)
-
-	return s
-
-bad:
-	yyerror("illegal receiver type: %v", t0)
-	return nil
+	return spkg.Lookup(p)
 }
 
-func methodname(n *Node, t *Node) *Node {
+// methodname is a misnomer because this now returns a Sym, rather
+// than an ONAME.
+// TODO(mdempsky): Reconcile with methodsym.
+func methodname(s *types.Sym, recv *types.Type) *types.Sym {
 	star := false
-	if t.Op == OIND {
+	if recv.IsPtr() {
 		star = true
-		t = t.Left
+		recv = recv.Elem()
 	}
 
-	return methodname0(n.Sym, star, t.Sym)
-}
-
-func methodname0(s *Sym, star bool, tsym *Sym) *Node {
-	if tsym == nil || isblanksym(s) {
-		return newfuncname(s)
+	tsym := recv.Sym
+	if tsym == nil || s.IsBlank() {
+		return s
 	}
 
 	var p string
 	if star {
-		p = fmt.Sprintf("(*%v).%v", tsym, s)
+		p = fmt.Sprintf("(*%v).%v", tsym.Name, s)
 	} else {
 		p = fmt.Sprintf("%v.%v", tsym, s)
 	}
 
-	if exportname(tsym.Name) {
-		s = lookup(p)
-	} else {
-		s = Pkglookup(p, tsym.Pkg)
-	}
+	s = tsym.Pkg.Lookup(p)
 
-	return newfuncname(s)
+	return s
 }
 
 // Add a method, declared as a function.
 // - msym is the method symbol
 // - t is function type (with receiver)
-func addmethod(msym *Sym, t *Type, local, nointerface bool) {
-	// get field sym
+func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) {
 	if msym == nil {
 		Fatalf("no method symbol")
 	}
@@ -1213,7 +974,7 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) {
 		}
 
 		switch {
-		case t == nil || t.Broke:
+		case t == nil || t.Broke():
 			// rely on typecheck having complained before
 		case t.Sym == nil:
 			yyerror("invalid receiver type %v (%v is an unnamed type)", pa, t)
@@ -1229,12 +990,12 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) {
 		return
 	}
 
-	if local && !mt.Local {
+	if local && !mt.Local() {
 		yyerror("cannot define new methods on non-local type %v", mt)
 		return
 	}
 
-	if isblanksym(msym) {
+	if msym.IsBlank() {
 		return
 	}
 
@@ -1259,19 +1020,16 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) {
 		return
 	}
 
-	f := newField()
+	f := types.NewField()
 	f.Sym = msym
-	f.Nname = newname(msym)
+	f.Nname = asTypesNode(newname(msym))
 	f.Type = t
-	f.Nointerface = nointerface
+	f.SetNointerface(nointerface)
 
 	mt.Methods().Append(f)
 }
 
 func funccompile(n *Node) {
-	Stksize = BADWIDTH
-	Maxarg = 0
-
 	if n.Type == nil {
 		if nerrors == 0 {
 			Fatalf("funccompile missing type")
@@ -1286,38 +1044,56 @@ func funccompile(n *Node) {
 		Fatalf("funccompile %v inside %v", n.Func.Nname.Sym, Curfn.Func.Nname.Sym)
 	}
 
-	Stksize = 0
 	dclcontext = PAUTO
 	funcdepth = n.Func.Depth + 1
 	compile(n)
 	Curfn = nil
-	pc = nil
 	funcdepth = 0
 	dclcontext = PEXTERN
-	if nerrors != 0 {
-		// If we have compile errors, ignore any assembler/linker errors.
-		Ctxt.DiagFunc = func(string, ...interface{}) {}
-	}
-	obj.Flushplist(Ctxt) // convert from Prog list to machine code
 }
 
-func funcsym(s *Sym) *Sym {
-	if s.Fsym != nil {
-		return s.Fsym
-	}
+func funcsymname(s *types.Sym) string {
+	return s.Name + "·f"
+}
 
-	s1 := Pkglookup(s.Name+"·f", s.Pkg)
-	if !Ctxt.Flag_dynlink && s1.Def == nil {
-		s1.Def = newfuncname(s1)
-		s1.Def.Func.Shortname = newname(s)
-		funcsyms = append(funcsyms, s1.Def)
-	}
-	s.Fsym = s1
-	return s1
+// funcsym returns s·f.
+func funcsym(s *types.Sym) *types.Sym {
+	// funcsymsmu here serves to protect not just mutations of funcsyms (below),
+	// but also the package lookup of the func sym name,
+	// since this function gets called concurrently from the backend.
+	// There are no other concurrent package lookups in the backend,
+	// except for the types package, which is protected separately.
+	// Reusing funcsymsmu to also cover this package lookup
+	// avoids a general, broader, expensive package lookup mutex.
+	// Note makefuncsym also does package look-up of func sym names,
+	// but that it is only called serially, from the front end.
+	funcsymsmu.Lock()
+	sf, existed := s.Pkg.LookupOK(funcsymname(s))
+	// Don't export s·f when compiling for dynamic linking.
+	// When dynamically linking, the necessary function
+	// symbols will be created explicitly with makefuncsym.
+	// See the makefuncsym comment for details.
+	if !Ctxt.Flag_dynlink && !existed {
+		funcsyms = append(funcsyms, s)
+	}
+	funcsymsmu.Unlock()
+	return sf
 }
 
-func makefuncsym(s *Sym) {
-	if isblanksym(s) {
+// makefuncsym ensures that s·f is exported.
+// It is only used with -dynlink.
+// When not compiling for dynamic linking,
+// the funcsyms are created as needed by
+// the packages that use them.
+// Normally we emit the s·f stubs as DUPOK syms,
+// but DUPOK doesn't work across shared library boundaries.
+// So instead, when dynamic linking, we only create
+// the s·f stubs in s's package.
+func makefuncsym(s *types.Sym) {
+	if !Ctxt.Flag_dynlink {
+		Fatalf("makefuncsym dynlink")
+	}
+	if s.IsBlank() {
 		return
 	}
 	if compiling_runtime && s.Name == "getg" {
@@ -1325,10 +1101,24 @@ func makefuncsym(s *Sym) {
 		// not get a funcsym.
 		return
 	}
-	s1 := funcsym(s)
-	s1.Def = newfuncname(s1)
-	s1.Def.Func.Shortname = newname(s)
-	funcsyms = append(funcsyms, s1.Def)
+	if _, existed := s.Pkg.LookupOK(funcsymname(s)); !existed {
+		funcsyms = append(funcsyms, s)
+	}
+}
+
+func dclfunc(sym *types.Sym, tfn *Node) *Node {
+	if tfn.Op != OTFUNC {
+		Fatalf("expected OTFUNC node, got %v", tfn)
+	}
+
+	fn := nod(ODCLFUNC, nil, nil)
+	fn.Func.Nname = newname(sym)
+	fn.Func.Nname.Name.Defn = fn
+	fn.Func.Nname.Name.Param.Ntype = tfn
+	declare(fn.Func.Nname, PFUNC)
+	funchdr(fn)
+	fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
+	return fn
 }
 
 type nowritebarrierrecChecker struct {
@@ -1344,7 +1134,7 @@ type nowritebarrierrecChecker struct {
 type nowritebarrierrecCall struct {
 	target *Node
 	depth  int
-	lineno int32
+	lineno src.XPos
 }
 
 func checknowritebarrierrec() {
@@ -1354,8 +1144,11 @@ func checknowritebarrierrec() {
 	visitBottomUp(xtop, func(list []*Node, recursive bool) {
 		// Functions with write barriers have depth 0.
 		for _, n := range list {
-			if n.Func.WBLineno != 0 && n.Func.Pragma&Yeswritebarrierrec == 0 {
-				c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBLineno}
+			if n.Func.WBPos.IsKnown() && n.Func.Pragma&Nowritebarrier != 0 {
+				yyerrorl(n.Func.WBPos, "write barrier prohibited")
+			}
+			if n.Func.WBPos.IsKnown() && n.Func.Pragma&Yeswritebarrierrec == 0 {
+				c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBPos}
 			}
 		}
 
@@ -1372,7 +1165,7 @@ func checknowritebarrierrec() {
 					// yeswritebarrierrec function.
 					continue
 				}
-				if n.Func.WBLineno == 0 {
+				if !n.Func.WBPos.IsKnown() {
 					c.curfn = n
 					c.visitcodelist(n.Nbody)
 				}
@@ -1400,7 +1193,7 @@ func checknowritebarrierrec() {
 				call = c.best[n]
 			}
 			err = fmt.Sprintf("write barrier prohibited by caller; %v%s", n.Func.Nname, err)
-			yyerrorl(n.Func.WBLineno, err)
+			yyerrorl(n.Func.WBPos, err)
 		}
 	})
 }
@@ -1431,9 +1224,9 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) {
 func (c *nowritebarrierrecChecker) visitcall(n *Node) {
 	fn := n.Left
 	if n.Op == OCALLMETH {
-		fn = n.Left.Sym.Def
+		fn = asNode(n.Left.Sym.Def)
 	}
-	if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
+	if fn == nil || fn.Op != ONAME || fn.Class() != PFUNC || fn.Name.Defn == nil {
 		return
 	}
 	defn := fn.Name.Defn
@@ -1446,6 +1239,6 @@ func (c *nowritebarrierrecChecker) visitcall(n *Node) {
 	if ok && fnbest.depth+1 >= best.depth {
 		return
 	}
-	c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Lineno}
+	c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Pos}
 	c.stable = false
 }
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index f4a70c4..c25eb54 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -5,6 +5,7 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"strconv"
 	"strings"
@@ -18,7 +19,7 @@ import (
 // The algorithm (known as Tarjan's algorithm) for doing that is taken from
 // Sedgewick, Algorithms, Second Edition, p. 482, with two adaptations.
 //
-// First, a hidden closure function (n.Func.IsHiddenClosure) cannot be the
+// First, a hidden closure function (n.Func.IsHiddenClosure()) cannot be the
 // root of a connected component. Refusing to use it as a root
 // forces it into the component of the function in which it appears.
 // This is more convenient for escape analysis.
@@ -58,7 +59,7 @@ func visitBottomUp(list []*Node, analyze func(list []*Node, recursive bool)) {
 	v.analyze = analyze
 	v.nodeID = make(map[*Node]uint32)
 	for _, n := range list {
-		if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure {
+		if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure() {
 			v.visit(n)
 		}
 	}
@@ -78,7 +79,7 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
 
 	v.stack = append(v.stack, n)
 	min = v.visitcodelist(n.Nbody, min)
-	if (min == id || min == id+1) && !n.Func.IsHiddenClosure {
+	if (min == id || min == id+1) && !n.Func.IsHiddenClosure() {
 		// This node is the root of a strongly connected component.
 
 		// The original min passed to visitcodelist was v.nodeID[n]+1.
@@ -131,9 +132,9 @@ 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.Sym.Def
+			fn = asNode(n.Left.Sym.Def)
 		}
-		if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
+		if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
 			m := v.visit(fn.Name.Defn)
 			if m < min {
 				min = m
@@ -412,7 +413,7 @@ func newEscState(recursive bool) *EscState {
 	e := new(EscState)
 	e.theSink.Op = ONAME
 	e.theSink.Orig = &e.theSink
-	e.theSink.Class = PEXTERN
+	e.theSink.SetClass(PEXTERN)
 	e.theSink.Sym = lookup(".sink")
 	e.nodeEscState(&e.theSink).Loopdepth = -1
 	e.recursive = recursive
@@ -458,7 +459,7 @@ func (e *EscState) stepAssignWhere(dst, src *Node, why string, where *Node) *Esc
 }
 
 // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
-func funcSym(fn *Node) *Sym {
+func funcSym(fn *Node) *types.Sym {
 	if fn == nil || fn.Func.Nname == nil {
 		return nil
 	}
@@ -466,7 +467,7 @@ func funcSym(fn *Node) *Sym {
 }
 
 // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
-func (e *EscState) curfnSym(n *Node) *Sym {
+func (e *EscState) curfnSym(n *Node) *types.Sym {
 	nE := e.nodeEscState(n)
 	return funcSym(nE.Curfn)
 }
@@ -508,7 +509,7 @@ func escAnalyze(all []*Node, recursive bool) {
 			if n.Esc != escapes[i] {
 				done = false
 				if Debug['m'] > 2 {
-					Warnl(n.Lineno, "Reflooding %v %S", e.curfnSym(n), n)
+					Warnl(n.Pos, "Reflooding %v %S", e.curfnSym(n), n)
 				}
 				escapes[i] = n.Esc
 				e.escflood(n)
@@ -529,7 +530,7 @@ func escAnalyze(all []*Node, recursive bool) {
 	if Debug['m'] != 0 {
 		for _, n := range e.noesc {
 			if n.Esc == EscNone {
-				Warnl(n.Lineno, "%v %S does not escape", e.curfnSym(n), n)
+				Warnl(n.Pos, "%v %S does not escape", e.curfnSym(n), n)
 			}
 		}
 	}
@@ -556,17 +557,17 @@ func (e *EscState) escfunc(fn *Node) {
 			continue
 		}
 		lnE := e.nodeEscState(ln)
-		switch ln.Class {
+		switch ln.Class() {
 		// out params are in a loopdepth between the sink and all local variables
 		case PPARAMOUT:
 			lnE.Loopdepth = 0
 
 		case PPARAM:
 			lnE.Loopdepth = 1
-			if ln.Type != nil && !haspointers(ln.Type) {
+			if ln.Type != nil && !types.Haspointers(ln.Type) {
 				break
 			}
-			if Curfn.Nbody.Len() == 0 && !Curfn.Noescape {
+			if Curfn.Nbody.Len() == 0 && !Curfn.Noescape() {
 				ln.Esc = EscHeap
 			} else {
 				ln.Esc = EscNone // prime for escflood later
@@ -578,7 +579,7 @@ func (e *EscState) escfunc(fn *Node) {
 	// in a mutually recursive group we lose track of the return values
 	if e.recursive {
 		for _, ln := range Curfn.Func.Dcl {
-			if ln.Op == ONAME && ln.Class == PPARAMOUT {
+			if ln.Op == ONAME && ln.Class() == PPARAMOUT {
 				e.escflows(&e.theSink, ln, e.stepAssign(nil, ln, ln, "returned from recursive function"))
 			}
 		}
@@ -621,7 +622,7 @@ func (e *EscState) escloopdepth(n *Node) {
 		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
 		// if(n.Left.Sym.Label != nil)
 		//	fatal("escape analysis messed up analyzing label: %+N", n);
-		n.Left.Sym.Label = &nonlooping
+		n.Left.Sym.Label = asTypesNode(&nonlooping)
 
 	case OGOTO:
 		if n.Left == nil || n.Left.Sym == nil {
@@ -630,8 +631,8 @@ func (e *EscState) escloopdepth(n *Node) {
 
 		// If we come past one that's uninitialized, this must be a (harmless) forward jump
 		// but if it's set to nonlooping the label must have preceded this goto.
-		if n.Left.Sym.Label == &nonlooping {
-			n.Left.Sym.Label = &looping
+		if asNode(n.Left.Sym.Label) == &nonlooping {
+			n.Left.Sym.Label = asTypesNode(&looping)
 		}
 	}
 
@@ -658,7 +659,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 	// ninit logically runs at a different loopdepth than the rest of the for loop.
 	e.esclist(n.Ninit, n)
 
-	if n.Op == OFOR || n.Op == ORANGE {
+	if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE {
 		e.loopdepth++
 	}
 
@@ -667,10 +668,10 @@ func (e *EscState) esc(n *Node, parent *Node) {
 	// must happen before processing of switch body,
 	// so before recursion.
 	if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW {
-		for _, n1 := range n.List.Slice() { // cases
+		for _, cas := range n.List.Slice() { // cases
 			// it.N().Rlist is the variable per case
-			if n1.Rlist.Len() != 0 {
-				e.nodeEscState(n1.Rlist.First()).Loopdepth = e.loopdepth
+			if cas.Rlist.Len() != 0 {
+				e.nodeEscState(cas.Rlist.First()).Loopdepth = e.loopdepth
 			}
 		}
 	}
@@ -682,7 +683,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 			(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)
+			Warnl(n.Pos, "%v is too large for stack", n)
 		}
 		n.Esc = EscHeap
 		addrescapes(n)
@@ -695,7 +696,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 	e.esclist(n.List, n)
 	e.esclist(n.Rlist, n)
 
-	if n.Op == OFOR || n.Op == ORANGE {
+	if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE {
 		e.loopdepth--
 	}
 
@@ -711,11 +712,11 @@ func (e *EscState) esc(n *Node, parent *Node) {
 		}
 
 	case OLABEL:
-		if n.Left.Sym.Label == &nonlooping {
+		if asNode(n.Left.Sym.Label) == &nonlooping {
 			if Debug['m'] > 2 {
 				fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
 			}
-		} else if n.Left.Sym.Label == &looping {
+		} else if asNode(n.Left.Sym.Label) == &looping {
 			if Debug['m'] > 2 {
 				fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
 			}
@@ -745,12 +746,12 @@ func (e *EscState) esc(n *Node, parent *Node) {
 
 	case OSWITCH:
 		if n.Left != nil && n.Left.Op == OTYPESW {
-			for _, n2 := range n.List.Slice() {
+			for _, cas := range n.List.Slice() {
 				// cases
 				// n.Left.Right is the argument of the .(type),
 				// it.N().Rlist is the variable per case
-				if n2.Rlist.Len() != 0 {
-					e.escassignWhyWhere(n2.Rlist.First(), n.Left.Right, "switch case", n)
+				if cas.Rlist.Len() != 0 {
+					e.escassignWhyWhere(cas.Rlist.First(), n.Left.Right, "switch case", n)
 				}
 			}
 		}
@@ -765,7 +766,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 	// This assignment is a no-op for escape analysis,
 	// it does not store any new pointers into b that were not already there.
 	// However, without this special case b will escape, because we assign to OIND/ODOTPTR.
-	case OAS, OASOP, OASWB:
+	case OAS, OASOP:
 		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference
 			(n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation
 			(n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference
@@ -782,7 +783,7 @@ func (e *EscState) esc(n *Node, parent *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(n.Lineno, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
+				Warnl(n.Pos, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
 			}
 
 			break
@@ -816,19 +817,17 @@ func (e *EscState) esc(n *Node, parent *Node) {
 		// TODO: leak to a dummy node instead
 		// defer f(x) - f and x escape
 		e.escassignSinkWhy(n, n.Left.Left, "defer func")
-
 		e.escassignSinkWhy(n, n.Left.Right, "defer func ...") // ODDDARG for call
-		for _, n4 := range n.Left.List.Slice() {
-			e.escassignSinkWhy(n, n4, "defer func arg")
+		for _, arg := range n.Left.List.Slice() {
+			e.escassignSinkWhy(n, arg, "defer func arg")
 		}
 
 	case OPROC:
 		// go f(x) - f and x escape
 		e.escassignSinkWhy(n, n.Left.Left, "go func")
-
 		e.escassignSinkWhy(n, n.Left.Right, "go func ...") // ODDDARG for call
-		for _, n4 := range n.Left.List.Slice() {
-			e.escassignSinkWhy(n, n4, "go func arg")
+		for _, arg := range n.Left.List.Slice() {
+			e.escassignSinkWhy(n, arg, "go func arg")
 		}
 
 	case OCALLMETH, OCALLFUNC, OCALLINTER:
@@ -861,7 +860,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 			if i >= retList.Len() {
 				break
 			}
-			if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
+			if lrn.Op != ONAME || lrn.Class() != PPARAMOUT {
 				continue
 			}
 			e.escassignWhyWhere(lrn, retList.Index(i), "return", n)
@@ -877,7 +876,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 		e.escassignSinkWhy(n, n.Left, "panic")
 
 	case OAPPEND:
-		if !n.Isddd {
+		if !n.Isddd() {
 			for _, nn := range n.List.Slice()[1:] {
 				e.escassignSinkWhy(n, nn, "appended to slice") // lose track of assign to dereference
 			}
@@ -886,7 +885,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 			slice2 := n.List.Second()
 			e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference
 			if Debug['m'] > 3 {
-				Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
+				Warnl(n.Pos, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
 			}
 		}
 		e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too
@@ -903,28 +902,28 @@ func (e *EscState) esc(n *Node, parent *Node) {
 
 	case OARRAYLIT:
 		// Link values to array
-		for _, n2 := range n.List.Slice() {
-			if n2.Op == OKEY {
-				n2 = n2.Right
+		for _, elt := range n.List.Slice() {
+			if elt.Op == OKEY {
+				elt = elt.Right
 			}
-			e.escassign(n, n2, e.stepAssignWhere(n, n2, "array literal element", n))
+			e.escassign(n, elt, e.stepAssignWhere(n, elt, "array literal element", n))
 		}
 
 	case OSLICELIT:
 		// Slice is not leaked until proven otherwise
 		e.track(n)
 		// Link values to slice
-		for _, n2 := range n.List.Slice() {
-			if n2.Op == OKEY {
-				n2 = n2.Right
+		for _, elt := range n.List.Slice() {
+			if elt.Op == OKEY {
+				elt = elt.Right
 			}
-			e.escassign(n, n2, e.stepAssignWhere(n, n2, "slice literal element", n))
+			e.escassign(n, elt, e.stepAssignWhere(n, elt, "slice literal element", n))
 		}
 
 		// Link values to struct.
 	case OSTRUCTLIT:
-		for _, n6 := range n.List.Slice() {
-			e.escassignWhyWhere(n, n6.Left, "struct literal element", n)
+		for _, elt := range n.List.Slice() {
+			e.escassignWhyWhere(n, elt.Left, "struct literal element", n)
 		}
 
 	case OPTRLIT:
@@ -942,9 +941,9 @@ func (e *EscState) esc(n *Node, parent *Node) {
 	case OMAPLIT:
 		e.track(n)
 		// Keys and values make it to memory, lose track.
-		for _, n7 := range n.List.Slice() {
-			e.escassignSinkWhy(n, n7.Left, "map literal key")
-			e.escassignSinkWhy(n, n7.Right, "map literal value")
+		for _, elt := range n.List.Slice() {
+			e.escassignSinkWhy(n, elt.Left, "map literal key")
+			e.escassignSinkWhy(n, elt.Right, "map literal value")
 		}
 
 	case OCLOSURE:
@@ -954,9 +953,9 @@ func (e *EscState) esc(n *Node, parent *Node) {
 				continue
 			}
 			a := v.Name.Defn
-			if !v.Name.Byval {
+			if !v.Name.Byval() {
 				a = nod(OADDR, a, nil)
-				a.Lineno = v.Lineno
+				a.Pos = v.Pos
 				e.nodeEscState(a).Loopdepth = e.loopdepth
 				a = typecheck(a, Erv)
 			}
@@ -989,7 +988,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
 		// it should always be known, but if not, be conservative
 		// and keep the current loop depth.
 		if n.Left.Op == ONAME {
-			switch n.Left.Class {
+			switch n.Left.Class() {
 			case PAUTO:
 				nE := e.nodeEscState(n)
 				leftE := e.nodeEscState(n.Left)
@@ -1084,7 +1083,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
 		OCALLPART:
 
 	case ONAME:
-		if dst.Class == PEXTERN {
+		if dst.Class() == PEXTERN {
 			dstwhy = "assigned to top level variable"
 			dst = &e.theSink
 		}
@@ -1149,9 +1148,9 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
 		// OCLOSURE is lowered to OPTRLIT,
 		// insert OADDR to account for the additional indirection.
 		a := nod(OADDR, src, nil)
-		a.Lineno = src.Lineno
+		a.Pos = src.Pos
 		e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth
-		a.Type = ptrto(src.Type)
+		a.Type = types.NewPtr(src.Type)
 		e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
 
 	// Flowing multiple returns to a single dst happens when
@@ -1163,7 +1162,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
 
 		// A non-pointer escaping from a struct does not concern us.
 	case ODOT:
-		if src.Type != nil && !haspointers(src.Type) {
+		if src.Type != nil && !types.Haspointers(src.Type) {
 			break
 		}
 		fallthrough
@@ -1184,7 +1183,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
 
 	case ODOTTYPE,
 		ODOTTYPE2:
-		if src.Type != nil && !haspointers(src.Type) {
+		if src.Type != nil && !types.Haspointers(src.Type) {
 			break
 		}
 		e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
@@ -1387,9 +1386,9 @@ func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) {
 func (e *EscState) addDereference(n *Node) *Node {
 	ind := nod(OIND, n, nil)
 	e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth
-	ind.Lineno = n.Lineno
+	ind.Pos = n.Pos
 	t := n.Type
-	if t.IsKind(Tptr) {
+	if t.IsKind(types.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...
@@ -1433,19 +1432,19 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
 	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
 }
 
-func (e *EscState) initEscRetval(call *Node, fntype *Type) {
+func (e *EscState) initEscRetval(call *Node, fntype *types.Type) {
 	cE := e.nodeEscState(call)
 	cE.Retval.Set(nil) // Suspect this is not nil for indirect calls.
 	for i, f := range fntype.Results().Fields().Slice() {
-		ret := nod(ONAME, nil, nil)
 		buf := fmt.Sprintf(".out%d", i)
-		ret.Sym = lookup(buf)
+		ret := newname(lookup(buf))
+		ret.SetAddable(false) // TODO(mdempsky): Seems suspicious.
 		ret.Type = f.Type
-		ret.Class = PAUTO
+		ret.SetClass(PAUTO)
 		ret.Name.Curfn = Curfn
 		e.nodeEscState(ret).Loopdepth = e.loopdepth
-		ret.Used = true
-		ret.Lineno = call.Lineno
+		ret.Name.SetUsed(true)
+		ret.Pos = call.Pos
 		cE.Retval.Append(ret)
 	}
 }
@@ -1457,7 +1456,7 @@ func (e *EscState) initEscRetval(call *Node, fntype *Type) {
 // different for methods vs plain functions and for imported vs
 // this-package
 func (e *EscState) esccall(call *Node, parent *Node) {
-	var fntype *Type
+	var fntype *types.Type
 	var indirect bool
 	var fn *Node
 	switch call.Op {
@@ -1467,10 +1466,10 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 	case OCALLFUNC:
 		fn = call.Left
 		fntype = fn.Type
-		indirect = fn.Op != ONAME || fn.Class != PFUNC
+		indirect = fn.Op != ONAME || fn.Class() != PFUNC
 
 	case OCALLMETH:
-		fn = call.Left.Sym.Def
+		fn = asNode(call.Left.Sym.Def)
 		if fn != nil {
 			fntype = fn.Type
 		} else {
@@ -1507,7 +1506,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 		if call.Op != OCALLFUNC {
 			rf := fntype.Recv()
 			r := call.Left.Left
-			if haspointers(rf.Type) {
+			if types.Haspointers(rf.Type) {
 				e.escassignSinkWhy(call, r, "receiver in indirect call")
 			}
 		} else { // indirect and OCALLFUNC = could be captured variables, too. (#14409)
@@ -1520,7 +1519,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 	}
 
 	cE := e.nodeEscState(call)
-	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
+	if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC &&
 		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:: %S in recursive group\n", linestr(lineno), call)
@@ -1534,7 +1533,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 
 		sawRcvr := false
 		for _, n := range fn.Name.Defn.Func.Dcl {
-			switch n.Class {
+			switch n.Class() {
 			case PPARAM:
 				if call.Op != OCALLFUNC && !sawRcvr {
 					e.escassignWhyWhere(n, call.Left.Left, "call receiver", call)
@@ -1545,12 +1544,12 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 					continue
 				}
 				arg := args[0]
-				if n.Isddd && !call.Isddd {
+				if n.Isddd() && !call.Isddd() {
 					// Introduce ODDDARG node to represent ... allocation.
 					arg = nod(ODDDARG, nil, nil)
-					arr := typArray(n.Type.Elem(), int64(len(args)))
-					arg.Type = ptrto(arr) // make pointer so it will be tracked
-					arg.Lineno = call.Lineno
+					arr := types.NewArray(n.Type.Elem(), int64(len(args)))
+					arg.Type = types.NewPtr(arr) // make pointer so it will be tracked
+					arg.Pos = call.Pos
 					e.track(arg)
 					call.Right = arg
 				}
@@ -1596,77 +1595,64 @@ func (e *EscState) esccall(call *Node, parent *Node) {
 	if call.Op != OCALLFUNC {
 		rf := fntype.Recv()
 		r := call.Left.Left
-		if haspointers(rf.Type) {
+		if types.Haspointers(rf.Type) {
 			e.escassignfromtag(rf.Note, cE.Retval, r, call)
 		}
 	}
 
-	var arg *Node
-	var note string
-	param, it := iterFields(fntype.Params())
-	i := 0
-	for ; i < len(args); i++ {
-		arg = args[i]
-		note = param.Note
-		if param.Isddd && !call.Isddd {
+	for i, param := range fntype.Params().FieldSlice() {
+		note := param.Note
+		var arg *Node
+		if param.Isddd() && !call.Isddd() {
+			rest := args[i:]
+			if len(rest) == 0 {
+				break
+			}
+
 			// Introduce ODDDARG node to represent ... allocation.
 			arg = nod(ODDDARG, nil, nil)
-			arg.Lineno = call.Lineno
-			arr := typArray(param.Type.Elem(), int64(len(args)-i))
-			arg.Type = ptrto(arr) // make pointer so it will be tracked
+			arg.Pos = call.Pos
+			arr := types.NewArray(param.Type.Elem(), int64(len(rest)))
+			arg.Type = types.NewPtr(arr) // make pointer so it will be tracked
 			e.track(arg)
 			call.Right = arg
-		}
 
-		if haspointers(param.Type) {
-			if e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC {
-				a := arg
-				for a.Op == OCONVNOP {
-					a = a.Left
+			// Store arguments into slice for ... arg.
+			for _, a := range rest {
+				if Debug['m'] > 3 {
+					fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), a)
 				}
-				switch a.Op {
-				// The callee has already been analyzed, so its arguments have esc tags.
-				// The argument is marked as not escaping at all.
-				// Record that fact so that any temporary used for
-				// synthesizing this expression can be reclaimed when
-				// the function returns.
-				// This 'noescape' is even stronger than the usual esc == EscNone.
-				// arg.Esc == EscNone means that arg does not escape the current function.
-				// arg.Noescape = true here means that arg does not escape this statement
-				// in the current function.
-				case OCALLPART,
-					OCLOSURE,
-					ODDDARG,
-					OARRAYLIT,
-					OSLICELIT,
-					OPTRLIT,
-					OSTRUCTLIT:
-					a.Noescape = true
+				if note == uintptrEscapesTag {
+					e.escassignSinkWhyWhere(arg, a, "arg to uintptrescapes ...", call)
+				} else {
+					e.escassignWhyWhere(arg, a, "arg to ...", call)
 				}
 			}
+		} else {
+			arg = args[i]
+			if note == uintptrEscapesTag {
+				e.escassignSinkWhy(arg, arg, "escaping uintptr")
+			}
 		}
 
-		if arg != args[i] {
-			// This occurs when function parameter field Isddd and call not Isddd
-			break
-		}
-
-		if note == uintptrEscapesTag {
-			e.escassignSinkWhy(arg, arg, "escaping uintptr")
-		}
-
-		param = it.Next()
-	}
-
-	// Store arguments into slice for ... arg.
-	for ; i < len(args); i++ {
-		if Debug['m'] > 3 {
-			fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), args[i])
-		}
-		if note == uintptrEscapesTag {
-			e.escassignSinkWhyWhere(arg, args[i], "arg to uintptrescapes ...", call)
-		} else {
-			e.escassignWhyWhere(arg, args[i], "arg to ...", call)
+		if types.Haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC {
+			a := arg
+			for a.Op == OCONVNOP {
+				a = a.Left
+			}
+			switch a.Op {
+			// The callee has already been analyzed, so its arguments have esc tags.
+			// The argument is marked as not escaping at all.
+			// Record that fact so that any temporary used for
+			// synthesizing this expression can be reclaimed when
+			// the function returns.
+			// This 'noescape' is even stronger than the usual esc == EscNone.
+			// arg.Esc == EscNone means that arg does not escape the current function.
+			// arg.SetNoescape(true) here means that arg does not escape this statement
+			// in the current function.
+			case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
+				a.SetNoescape(true)
+			}
 		}
 	}
 }
@@ -1679,7 +1665,7 @@ func (e *EscState) escflows(dst, src *Node, why *EscStep) {
 	}
 
 	// Don't bother building a graph for scalars.
-	if src.Type != nil && !haspointers(src.Type) && !isReflectHeaderDataField(src) {
+	if src.Type != nil && !types.Haspointers(src.Type) && !isReflectHeaderDataField(src) {
 		if Debug['m'] > 3 {
 			fmt.Printf("%v::NOT flows:: %S <- %S\n", linestr(lineno), dst, src)
 		}
@@ -1739,8 +1725,8 @@ func (e *EscState) escflood(dst *Node) {
 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function.
 func funcOutputAndInput(dst, src *Node) bool {
 	// Note if dst is marked as escaping, then "returned" is too weak.
-	return dst.Op == ONAME && dst.Class == PPARAMOUT &&
-		src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn
+	return dst.Op == ONAME && dst.Class() == PPARAMOUT &&
+		src.Op == ONAME && src.Class() == PPARAM && src.Name.Curfn == dst.Name.Curfn
 }
 
 func (es *EscStep) describe(src *Node) {
@@ -1764,7 +1750,7 @@ func (es *EscStep) describe(src *Node) {
 		if where == nil {
 			where = dst
 		}
-		Warnl(src.Lineno, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
+		Warnl(src.Pos, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
 	}
 	for step := step0; step != nil && step.busy; step = step.parent {
 		step.busy = false
@@ -1828,10 +1814,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 		// 4. return *in
 		if Debug['m'] != 0 {
 			if Debug['m'] <= 2 {
-				Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
+				Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
 				step.describe(src)
 			} else {
-				Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
+				Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
 			}
 		}
 		if src.Esc&EscMask != EscReturn {
@@ -1844,11 +1830,11 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 	// If parameter content escapes to heap, set EscContentEscapes
 	// Note minor confusion around escape from pointer-to-struct vs escape from struct
 	if dst.Esc == EscHeap &&
-		src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscHeap &&
+		src.Op == ONAME && src.Class() == PPARAM && src.Esc&EscMask < EscHeap &&
 		level.int() > 0 {
 		src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
 		if Debug['m'] != 0 {
-			Warnl(src.Lineno, "mark escaped content: %S", src)
+			Warnl(src.Pos, "mark escaped content: %S", src)
 			step.describe(src)
 		}
 	}
@@ -1859,17 +1845,17 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 	osrcesc = src.Esc
 	switch src.Op {
 	case ONAME:
-		if src.Class == PPARAM && (leaks || dstE.Loopdepth < 0) && src.Esc&EscMask < EscHeap {
+		if src.Class() == PPARAM && (leaks || dstE.Loopdepth < 0) && src.Esc&EscMask < EscHeap {
 			if level.guaranteedDereference() > 0 {
 				src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
 				if Debug['m'] != 0 {
 					if Debug['m'] <= 2 {
 						if osrcesc != src.Esc {
-							Warnl(src.Lineno, "leaking param content: %S", src)
+							Warnl(src.Pos, "leaking param content: %S", src)
 							step.describe(src)
 						}
 					} else {
-						Warnl(src.Lineno, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
+						Warnl(src.Pos, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
 							src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
 					}
 				}
@@ -1877,10 +1863,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 				src.Esc = EscHeap
 				if Debug['m'] != 0 {
 					if Debug['m'] <= 2 {
-						Warnl(src.Lineno, "leaking param: %S", src)
+						Warnl(src.Pos, "leaking param: %S", src)
 						step.describe(src)
 					} else {
-						Warnl(src.Lineno, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
+						Warnl(src.Pos, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
 							src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
 					}
 				}
@@ -1889,9 +1875,9 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 
 		// Treat a captured closure variable as equivalent to the
 		// original variable.
-		if src.isClosureVar() {
+		if src.IsClosureVar() {
 			if leaks && Debug['m'] != 0 {
-				Warnl(src.Lineno, "leaking closure reference %S", src)
+				Warnl(src.Pos, "leaking closure reference %S", src)
 				step.describe(src)
 			}
 			e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
@@ -1910,10 +1896,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 					p = p.Left // merely to satisfy error messages in tests
 				}
 				if Debug['m'] > 2 {
-					Warnl(src.Lineno, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
+					Warnl(src.Pos, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
 						p, level, dst, dstE.Loopdepth, modSrcLoopdepth)
 				} else {
-					Warnl(src.Lineno, "%S escapes to heap", p)
+					Warnl(src.Pos, "%S escapes to heap", p)
 					step.describe(src)
 				}
 			}
@@ -1931,7 +1917,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 		if leaks {
 			src.Esc = EscHeap
 			if Debug['m'] != 0 && osrcesc != src.Esc {
-				Warnl(src.Lineno, "%S escapes to heap", src)
+				Warnl(src.Pos, "%S escapes to heap", src)
 				step.describe(src)
 			}
 			extraloopdepth = modSrcLoopdepth
@@ -1940,11 +1926,11 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 		level = level.dec()
 
 	case OSLICELIT:
-		for _, n1 := range src.List.Slice() {
-			if n1.Op == OKEY {
-				n1 = n1.Right
+		for _, elt := range src.List.Slice() {
+			if elt.Op == OKEY {
+				elt = elt.Right
 			}
-			e.escwalk(level.dec(), dst, n1, e.stepWalk(dst, n1, "slice-literal-element", step))
+			e.escwalk(level.dec(), dst, elt, e.stepWalk(dst, elt, "slice-literal-element", step))
 		}
 
 		fallthrough
@@ -1966,7 +1952,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 		if leaks {
 			src.Esc = EscHeap
 			if Debug['m'] != 0 && osrcesc != src.Esc {
-				Warnl(src.Lineno, "%S escapes to heap", src)
+				Warnl(src.Pos, "%S escapes to heap", src)
 				step.describe(src)
 			}
 			extraloopdepth = modSrcLoopdepth
@@ -2028,6 +2014,158 @@ recurse:
 	e.pdepth--
 }
 
+// addrescapes tags node n as having had its address taken
+// by "increasing" the "value" of n.Esc to EscHeap.
+// Storage is allocated as necessary to allow the address
+// to be taken.
+func addrescapes(n *Node) {
+	switch n.Op {
+	default:
+		// Unexpected Op, probably due to a previous type error. Ignore.
+
+	case OIND, ODOTPTR:
+		// Nothing to do.
+
+	case ONAME:
+		if n == nodfp {
+			break
+		}
+
+		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+		// on PPARAM it means something different.
+		if n.Class() == PAUTO && n.Esc == EscNever {
+			break
+		}
+
+		// If a closure reference escapes, mark the outer variable as escaping.
+		if n.IsClosureVar() {
+			addrescapes(n.Name.Defn)
+			break
+		}
+
+		if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO {
+			break
+		}
+
+		// 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.Pos
+		moveToHeap(n)
+		Curfn = oldfn
+		lineno = ln
+
+	// ODOTPTR has already been introduced,
+	// so these are the non-pointer ODOT and OINDEX.
+	// In &x[0], if x is a slice, then x does not
+	// escape--the pointer inside x does, but that
+	// is always a heap pointer anyway.
+	case ODOT, OINDEX, OPAREN, OCONVNOP:
+		if !n.Left.Type.IsSlice() {
+			addrescapes(n.Left)
+		}
+	}
+}
+
+// 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(types.NewPtr(n.Type))
+	heapaddr.Sym = lookup("&" + n.Sym.Name)
+	heapaddr.Orig.Sym = heapaddr.Sym
+
+	// Unset AutoTemp to persist the &foo variable name through SSA to
+	// liveness analysis.
+	// TODO(mdempsky/drchase): Cleaner solution?
+	heapaddr.Name.SetAutoTemp(false)
+
+	// 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 := newname(n.Sym)
+		stackcopy.SetAddable(false)
+		stackcopy.Type = n.Type
+		stackcopy.Xoffset = n.Xoffset
+		stackcopy.SetClass(n.Class())
+		stackcopy.Name.Param.Heapaddr = heapaddr
+		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.SetClass(PAUTOHEAP)
+	n.Xoffset = 0
+	n.Name.Param.Heapaddr = heapaddr
+	n.Esc = EscHeap
+	if Debug['m'] != 0 {
+		fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
+	}
+}
+
 // This special tag is applied to uintptr variables
 // that we believe may hold unsafe.Pointers for
 // calls into assembly functions.
@@ -2042,7 +2180,7 @@ const uintptrEscapesTag = "uintptr-escapes"
 func (e *EscState) esctag(fn *Node) {
 	fn.Esc = EscFuncTagged
 
-	name := func(s *Sym, narg int) string {
+	name := func(s *types.Sym, narg int) string {
 		if s != nil {
 			return s.Name
 		}
@@ -2052,9 +2190,9 @@ func (e *EscState) esctag(fn *Node) {
 	// External functions are assumed unsafe,
 	// unless //go:noescape is given before the declaration.
 	if fn.Nbody.Len() == 0 {
-		if fn.Noescape {
+		if fn.Noescape() {
 			for _, f := range fn.Type.Params().Fields().Slice() {
-				if haspointers(f.Type) {
+				if types.Haspointers(f.Type) {
 					f.Note = mktag(EscNone)
 				}
 			}
@@ -2071,7 +2209,7 @@ func (e *EscState) esctag(fn *Node) {
 			narg++
 			if f.Type.Etype == TUINTPTR {
 				if Debug['m'] != 0 {
-					Warnl(fn.Lineno, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
+					Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
 				}
 				f.Note = unsafeUintptrTag
 			}
@@ -2086,15 +2224,15 @@ func (e *EscState) esctag(fn *Node) {
 			narg++
 			if f.Type.Etype == TUINTPTR {
 				if Debug['m'] != 0 {
-					Warnl(fn.Lineno, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
+					Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
 				}
 				f.Note = uintptrEscapesTag
 			}
 
-			if f.Isddd && f.Type.Elem().Etype == TUINTPTR {
+			if f.Isddd() && f.Type.Elem().Etype == TUINTPTR {
 				// final argument is ...uintptr.
 				if Debug['m'] != 0 {
-					Warnl(fn.Lineno, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
+					Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
 				}
 				f.Note = uintptrEscapesTag
 			}
@@ -2109,7 +2247,7 @@ func (e *EscState) esctag(fn *Node) {
 		switch ln.Esc & EscMask {
 		case EscNone, // not touched by escflood
 			EscReturn:
-			if haspointers(ln.Type) { // don't bother tagging for scalars
+			if types.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))
 				}
@@ -2118,4 +2256,13 @@ func (e *EscState) esctag(fn *Node) {
 		case EscHeap: // touched by escflood, moved to heap
 		}
 	}
+
+	// Unnamed parameters are unused and therefore do not escape.
+	// (Unnamed parameters are not in the Dcl list in the loop above
+	// so we need to mark them separately.)
+	for _, f := range fn.Type.Params().Fields().Slice() {
+		if f.Sym == nil || f.Sym.IsBlank() {
+			f.Note = mktag(EscNone)
+		}
+	}
 }
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index b4c15e4..75be4ec 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -7,6 +7,7 @@ package gc
 import (
 	"bufio"
 	"bytes"
+	"cmd/compile/internal/types"
 	"cmd/internal/bio"
 	"fmt"
 	"unicode"
@@ -15,12 +16,10 @@ import (
 
 var (
 	Debug_export int // if set, print debugging information about export data
-	exportsize   int
 )
 
 func exportf(format string, args ...interface{}) {
-	n, _ := fmt.Fprintf(bout, format, args...)
-	exportsize += n
+	fmt.Fprintf(bout, format, args...)
 	if Debug_export != 0 {
 		fmt.Printf(format, args...)
 	}
@@ -33,21 +32,21 @@ func exportsym(n *Node) {
 	if n == nil || n.Sym == nil {
 		return
 	}
-	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
-		if n.Sym.Flags&SymPackage != 0 {
-			yyerror("export/package mismatch: %v", n.Sym)
+	if n.Sym.Export() || n.Sym.Package() {
+		if n.Sym.Package() {
+			Fatalf("export/package mismatch: %v", n.Sym)
 		}
 		return
 	}
 
-	n.Sym.Flags |= SymExport
+	n.Sym.SetExport(true)
 	if Debug['E'] != 0 {
 		fmt.Printf("export symbol %v\n", n.Sym)
 	}
 
-	// Ensure original object is on exportlist before aliases.
-	if n.Sym.Flags&SymAlias != 0 {
-		exportlist = append(exportlist, n.Sym.Def)
+	// Ensure original types are on exportlist before type aliases.
+	if IsAlias(n.Sym) {
+		exportlist = append(exportlist, asNode(n.Sym.Def))
 	}
 
 	exportlist = append(exportlist, n)
@@ -67,7 +66,7 @@ func initname(s string) bool {
 
 // exportedsym reports whether a symbol will be visible
 // to files that import our package.
-func exportedsym(sym *Sym) bool {
+func exportedsym(sym *types.Sym) bool {
 	// Builtins are visible everywhere.
 	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
 		return true
@@ -83,15 +82,15 @@ func autoexport(n *Node, ctxt Class) {
 	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
 		return
 	}
-	if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
+	if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
 		return
 	}
 
 	if exportname(n.Sym.Name) || initname(n.Sym.Name) {
 		exportsym(n)
 	}
-	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
-		n.Sym.Flags |= SymAsm
+	if asmhdr != "" && n.Sym.Pkg == localpkg && !n.Sym.Asm() {
+		n.Sym.SetAsm(true)
 		asmlist = append(asmlist, n)
 	}
 }
@@ -108,10 +107,9 @@ func reexportdep(n *Node) {
 		return
 	}
 
-	//print("reexportdep %+hN\n", n);
 	switch n.Op {
 	case ONAME:
-		switch n.Class {
+		switch n.Class() {
 		// methods will be printed along with their type
 		// nodes for T.Method expressions
 		case PFUNC:
@@ -133,78 +131,6 @@ func reexportdep(n *Node) {
 				exportlist = append(exportlist, n)
 			}
 		}
-
-	// Local variables in the bodies need their type.
-	case ODCL:
-		t := n.Left.Type
-
-		if t != Types[t.Etype] && t != idealbool && t != idealstring {
-			if t.IsPtr() {
-				t = t.Elem()
-			}
-			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
-				if Debug['E'] != 0 {
-					fmt.Printf("reexport type %v from declaration\n", t.Sym)
-				}
-				exportlist = append(exportlist, t.Sym.Def)
-			}
-		}
-
-	case OLITERAL:
-		t := n.Type
-		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
-			if t.IsPtr() {
-				t = t.Elem()
-			}
-			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
-				if Debug['E'] != 0 {
-					fmt.Printf("reexport literal type %v\n", t.Sym)
-				}
-				exportlist = append(exportlist, t.Sym.Def)
-			}
-		}
-		fallthrough
-
-	case OTYPE:
-		if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) {
-			if Debug['E'] != 0 {
-				fmt.Printf("reexport literal/type %v\n", n.Sym)
-			}
-			exportlist = append(exportlist, n)
-		}
-
-	// for operations that need a type when rendered, put the type on the export list.
-	case OCONV,
-		OCONVIFACE,
-		OCONVNOP,
-		ORUNESTR,
-		OARRAYBYTESTR,
-		OARRAYRUNESTR,
-		OSTRARRAYBYTE,
-		OSTRARRAYRUNE,
-		ODOTTYPE,
-		ODOTTYPE2,
-		OSTRUCTLIT,
-		OARRAYLIT,
-		OSLICELIT,
-		OPTRLIT,
-		OMAKEMAP,
-		OMAKESLICE,
-		OMAKECHAN:
-		t := n.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 {
-				fmt.Printf("reexport type for expression %v\n", t.Sym)
-			}
-			exportlist = append(exportlist, t.Sym.Def)
-		}
 	}
 
 	reexportdep(n.Left)
@@ -216,7 +142,7 @@ func reexportdep(n *Node) {
 }
 
 // methodbyname sorts types by symbol name.
-type methodbyname []*Field
+type methodbyname []*types.Field
 
 func (x methodbyname) Len() int           { return len(x) }
 func (x methodbyname) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
@@ -247,15 +173,9 @@ func dumpexport() {
 
 		// verify that we can read the copied export data back in
 		// (use empty package map to avoid collisions)
-		savedPkgMap := pkgMap
-		savedPkgs := pkgs
-		pkgMap = make(map[string]*Pkg)
-		pkgs = nil
-		importpkg = mkpkg("")
-		Import(bufio.NewReader(&copy)) // must not die
-		importpkg = nil
-		pkgs = savedPkgs
-		pkgMap = savedPkgMap
+		types.CleanroomDo(func() {
+			Import(types.NewPkg("", ""), bufio.NewReader(&copy)) // must not die
+		})
 	} else {
 		size = export(bout.Writer, Debug_export != 0)
 	}
@@ -267,45 +187,48 @@ func dumpexport() {
 }
 
 // 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)
+// pkg is the package being imported
+func importsym(pkg *types.Pkg, s *types.Sym, op Op) {
+	if asNode(s.Def) != nil && asNode(s.Def).Op != op {
+		pkgstr := fmt.Sprintf("during import %q", pkg.Path)
 		redeclare(s, pkgstr)
 	}
 
 	// mark the symbol so it is not reexported
-	if s.Def == nil {
+	if asNode(s.Def) == nil {
 		if exportname(s.Name) || initname(s.Name) {
-			s.Flags |= SymExport
+			s.SetExport(true)
 		} else {
-			s.Flags |= SymPackage // package scope
+			s.SetPackage(true) // package scope
 		}
 	}
 }
 
 // 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 {
-		t := typ(TFORW)
+// pkg is the package being imported
+func pkgtype(pkg *types.Pkg, s *types.Sym) *types.Type {
+	importsym(pkg, s, OTYPE)
+	if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE {
+		t := types.New(TFORW)
 		t.Sym = s
-		s.Def = typenod(t)
-		s.Def.Name = new(Name)
+		s.Def = asTypesNode(typenod(t))
+		asNode(s.Def).Name = new(Name)
 	}
 
-	if s.Def.Type == nil {
-		yyerror("pkgtype %v", s)
+	if asNode(s.Def).Type == nil {
+		Fatalf("pkgtype %v", s)
 	}
-	return s.Def.Type
+	return asNode(s.Def).Type
 }
 
 // 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)
+// pkg is the package being imported
+func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) {
+	importsym(pkg, s, OLITERAL)
 	n = convlit(n, t)
 
-	if s.Def != nil { // TODO: check if already the same.
+	if asNode(s.Def) != nil { // TODO: check if already the same.
 		return
 	}
 
@@ -329,17 +252,18 @@ 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 {
-		if eqtype(t, s.Def.Type) {
+// pkg is the package being imported
+func importvar(pkg *types.Pkg, s *types.Sym, t *types.Type) {
+	importsym(pkg, s, ONAME)
+	if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME {
+		if eqtype(t, asNode(s.Def).Type) {
 			return
 		}
-		yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
+		yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path)
 	}
 
 	n := newname(s)
-	s.Importdef = importpkg
+	s.Importdef = pkg
 	n.Type = t
 	declare(n, PEXTERN)
 
@@ -348,6 +272,28 @@ func importvar(s *Sym, t *Type) {
 	}
 }
 
+// importalias declares symbol s as an imported type alias with type t.
+// pkg is the package being imported
+func importalias(pkg *types.Pkg, s *types.Sym, t *types.Type) {
+	importsym(pkg, s, OTYPE)
+	if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE {
+		if eqtype(t, asNode(s.Def).Type) {
+			return
+		}
+		yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path)
+	}
+
+	n := newname(s)
+	n.Op = OTYPE
+	s.Importdef = pkg
+	n.Type = t
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import type %v = %L\n", s, t)
+	}
+}
+
 func dumpasmhdr() {
 	b, err := bio.Create(asmhdr)
 	if err != nil {
@@ -355,7 +301,7 @@ func dumpasmhdr() {
 	}
 	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
 	for _, n := range asmlist {
-		if isblanksym(n.Sym) {
+		if n.Sym.IsBlank() {
 			continue
 		}
 		switch n.Op {
@@ -369,7 +315,7 @@ func dumpasmhdr() {
 			}
 			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
 			for _, t := range t.Fields().Slice() {
-				if !isblanksym(t.Sym) {
+				if !t.Sym.IsBlank() {
 					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
 				}
 			}
diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go
index 4fdcc7e..f906f3a 100644
--- a/src/cmd/compile/internal/gc/float_test.go
+++ b/src/cmd/compile/internal/gc/float_test.go
@@ -133,3 +133,24 @@ func TestFloatConvert(t *testing.T) {
 		t.Errorf("cvt12 got %d, wanted 3", got)
 	}
 }
+
+var sinkFloat float64
+
+func BenchmarkMul2(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var m float64 = 1
+		for j := 0; j < 500; j++ {
+			m *= 2
+		}
+		sinkFloat = m
+	}
+}
+func BenchmarkMulNeg2(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var m float64 = 1
+		for j := 0; j < 500; j++ {
+			m *= -2
+		}
+		sinkFloat = m
+	}
+}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index fffce44..2f56d8a 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -5,6 +5,7 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"strconv"
 	"strings"
@@ -16,14 +17,11 @@ import (
 // See the respective function's documentation for details.
 type FmtFlag int
 
-// TODO(gri) The ' ' flag is not used anymore in %-formats.
-//           Eliminate eventually.
-
 const ( //                                 fmt.Format flag/prec or verb
 	FmtLeft     FmtFlag = 1 << iota // '-'
 	FmtSharp                        // '#'
 	FmtSign                         // '+'
-	FmtUnsigned                     // ' '               (historic: u flag)
+	FmtUnsigned                     // internal use only (historic: u flag)
 	FmtShort                        // verb == 'S'       (historic: h flag)
 	FmtLong                         // verb == 'L'       (historic: l flag)
 	FmtComma                        // '.' (== hasPrec)  (historic: , flag)
@@ -44,7 +42,7 @@ func fmtFlag(s fmt.State, verb rune) FmtFlag {
 		flag |= FmtSign
 	}
 	if s.Flag(' ') {
-		flag |= FmtUnsigned
+		Fatalf("FmtUnsigned in format string")
 	}
 	if _, ok := s.Precision(); ok {
 		flag |= FmtComma
@@ -65,19 +63,19 @@ func fmtFlag(s fmt.State, verb rune) FmtFlag {
 // TODO(gri) verify these; eliminate those not used anymore
 //
 //	%v Op		Node opcodes
-//		Flags:  #: print Go syntax (automatic unless fmtmode == FDbg)
+//		Flags:  #: print Go syntax (automatic unless mode == FDbg)
 //
 //	%j *Node	Node details
 //		Flags:  0: suppresses things not relevant until walk
 //
 //	%v *Val		Constant values
 //
-//	%v *Sym		Symbols
+//	%v *types.Sym		Symbols
 //	%S              unqualified identifier in any mode
 //		Flags:  +,- #: mode (see below)
 //			0: in export mode: unqualified identifier if exported, qualified if not
 //
-//	%v *Type	Types
+//	%v *types.Type	Types
 //	%S              omit "func" and receiver in function types
 //	%L              definition instead of name.
 //		Flags:  +,- #: mode (see below)
@@ -92,22 +90,19 @@ func fmtFlag(s fmt.State, verb rune) FmtFlag {
 //		Flags:  those of *Node
 //			.: separate items with ',' instead of ';'
 
-// *Sym, *Type, and *Node types use the flags below to set the format mode
+// *types.Sym, *types.Type, and *Node types use the flags below to set the format mode
 const (
 	FErr = iota
 	FDbg
 	FTypeId
+	FTypeIdName // same as FTypeId, but use package name instead of prefix
 )
 
-var fmtmode int = FErr
-
-var fmtpkgpfx int // "% v" stickyness for *Type objects
-
 // The mode flags '+', '-', and '#' are sticky; they persist through
-// recursions of *Node, *Type, and *Sym values. The ' ' flag is
-// sticky only on *Type recursions and only used in %-/*Sym mode.
+// recursions of *Node, *types.Type, and *types.Sym values. The ' ' flag is
+// sticky only on *types.Type recursions and only used in %-/*types.Sym mode.
 //
-// Example: given a *Sym: %+v %#v %-v print an identifier properly qualified for debug/export/internal mode
+// Example: given a *types.Sym: %+v %#v %-v print an identifier properly qualified for debug/export/internal mode
 
 // Useful format combinations:
 // TODO(gri): verify these
@@ -120,7 +115,7 @@ var fmtpkgpfx int // "% v" stickyness for *Type objects
 //   %#v    Go format
 //   %L     "foo (type Bar)" for error messages
 //
-// *Type:
+// *types.Type:
 //   %#v    Go format
 //   %#L    type definition instead of name
 //   %#S    omit"func" and receiver in function signature
@@ -129,18 +124,21 @@ var fmtpkgpfx int // "% v" stickyness for *Type objects
 //   %-S    type identifiers without "func" and arg names in type signatures (methodsym)
 //   %- v   type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
 
-func setfmode(flags *FmtFlag) (fm int) {
-	fm = fmtmode
-	if *flags&FmtSign != 0 {
-		fmtmode = FDbg
-	} else if *flags&FmtSharp != 0 {
+// update returns the results of applying f to mode.
+func (f FmtFlag) update(mode fmtMode) (FmtFlag, fmtMode) {
+	switch {
+	case f&FmtSign != 0:
+		mode = FDbg
+	case f&FmtSharp != 0:
 		// ignore (textual export format no longer supported)
-	} else if *flags&FmtLeft != 0 {
-		fmtmode = FTypeId
+	case f&FmtUnsigned != 0:
+		mode = FTypeIdName
+	case f&FmtLeft != 0:
+		mode = FTypeId
 	}
 
-	*flags &^= (FmtSharp | FmtLeft | FmtSign)
-	return
+	f &^= FmtSharp | FmtLeft | FmtSign
+	return f, mode
 }
 
 var goopnames = []string{
@@ -163,19 +161,18 @@ var goopnames = []string{
 	OCOM:      "^",
 	OCONTINUE: "continue",
 	OCOPY:     "copy",
-	ODEC:      "--",
 	ODELETE:   "delete",
 	ODEFER:    "defer",
 	ODIV:      "/",
 	OEQ:       "==",
 	OFALL:     "fallthrough",
 	OFOR:      "for",
+	OFORUNTIL: "foruntil", // not actual syntax; used to avoid off-end pointer live on backedge.892
 	OGE:       ">=",
 	OGOTO:     "goto",
 	OGT:       ">",
 	OIF:       "if",
 	OIMAG:     "imag",
-	OINC:      "++",
 	OIND:      "*",
 	OLEN:      "len",
 	OLE:       "<=",
@@ -218,18 +215,18 @@ func (o Op) GoString() string {
 	return fmt.Sprintf("%#v", o)
 }
 
-func (o Op) Format(s fmt.State, verb rune) {
+func (o Op) format(s fmt.State, verb rune, mode fmtMode) {
 	switch verb {
 	case 'v':
-		o.oconv(s, fmtFlag(s, verb))
+		o.oconv(s, fmtFlag(s, verb), mode)
 
 	default:
 		fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
 	}
 }
 
-func (o Op) oconv(s fmt.State, flag FmtFlag) {
-	if (flag&FmtSharp != 0) || fmtmode != FDbg {
+func (o Op) oconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+	if flag&FmtSharp != 0 || mode != FDbg {
 		if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
 			fmt.Fprint(s, goopnames[o])
 			return
@@ -254,10 +251,173 @@ var classnames = []string{
 	"PFUNC",
 }
 
-func (n *Node) Format(s fmt.State, verb rune) {
+type (
+	fmtMode int
+
+	fmtNodeErr        Node
+	fmtNodeDbg        Node
+	fmtNodeTypeId     Node
+	fmtNodeTypeIdName Node
+
+	fmtOpErr        Op
+	fmtOpDbg        Op
+	fmtOpTypeId     Op
+	fmtOpTypeIdName Op
+
+	fmtTypeErr        types.Type
+	fmtTypeDbg        types.Type
+	fmtTypeTypeId     types.Type
+	fmtTypeTypeIdName types.Type
+
+	fmtSymErr        types.Sym
+	fmtSymDbg        types.Sym
+	fmtSymTypeId     types.Sym
+	fmtSymTypeIdName types.Sym
+
+	fmtNodesErr        Nodes
+	fmtNodesDbg        Nodes
+	fmtNodesTypeId     Nodes
+	fmtNodesTypeIdName Nodes
+)
+
+func (n *fmtNodeErr) Format(s fmt.State, verb rune)        { (*Node)(n).format(s, verb, FErr) }
+func (n *fmtNodeDbg) Format(s fmt.State, verb rune)        { (*Node)(n).format(s, verb, FDbg) }
+func (n *fmtNodeTypeId) Format(s fmt.State, verb rune)     { (*Node)(n).format(s, verb, FTypeId) }
+func (n *fmtNodeTypeIdName) Format(s fmt.State, verb rune) { (*Node)(n).format(s, verb, FTypeIdName) }
+func (n *Node) Format(s fmt.State, verb rune)              { n.format(s, verb, FErr) }
+
+func (o fmtOpErr) Format(s fmt.State, verb rune)        { Op(o).format(s, verb, FErr) }
+func (o fmtOpDbg) Format(s fmt.State, verb rune)        { Op(o).format(s, verb, FDbg) }
+func (o fmtOpTypeId) Format(s fmt.State, verb rune)     { Op(o).format(s, verb, FTypeId) }
+func (o fmtOpTypeIdName) Format(s fmt.State, verb rune) { Op(o).format(s, verb, FTypeIdName) }
+func (o Op) Format(s fmt.State, verb rune)              { o.format(s, verb, FErr) }
+
+func (t *fmtTypeErr) Format(s fmt.State, verb rune)    { typeFormat((*types.Type)(t), s, verb, FErr) }
+func (t *fmtTypeDbg) Format(s fmt.State, verb rune)    { typeFormat((*types.Type)(t), s, verb, FDbg) }
+func (t *fmtTypeTypeId) Format(s fmt.State, verb rune) { typeFormat((*types.Type)(t), s, verb, FTypeId) }
+func (t *fmtTypeTypeIdName) Format(s fmt.State, verb rune) {
+	typeFormat((*types.Type)(t), s, verb, FTypeIdName)
+}
+
+// func (t *types.Type) Format(s fmt.State, verb rune)     // in package types
+
+func (y *fmtSymErr) Format(s fmt.State, verb rune)    { symFormat((*types.Sym)(y), s, verb, FErr) }
+func (y *fmtSymDbg) Format(s fmt.State, verb rune)    { symFormat((*types.Sym)(y), s, verb, FDbg) }
+func (y *fmtSymTypeId) Format(s fmt.State, verb rune) { symFormat((*types.Sym)(y), s, verb, FTypeId) }
+func (y *fmtSymTypeIdName) Format(s fmt.State, verb rune) {
+	symFormat((*types.Sym)(y), s, verb, FTypeIdName)
+}
+
+// func (y *types.Sym) Format(s fmt.State, verb rune)            // in package types  { y.format(s, verb, FErr) }
+
+func (n fmtNodesErr) Format(s fmt.State, verb rune)        { (Nodes)(n).format(s, verb, FErr) }
+func (n fmtNodesDbg) Format(s fmt.State, verb rune)        { (Nodes)(n).format(s, verb, FDbg) }
+func (n fmtNodesTypeId) Format(s fmt.State, verb rune)     { (Nodes)(n).format(s, verb, FTypeId) }
+func (n fmtNodesTypeIdName) Format(s fmt.State, verb rune) { (Nodes)(n).format(s, verb, FTypeIdName) }
+func (n Nodes) Format(s fmt.State, verb rune)              { n.format(s, verb, FErr) }
+
+func (m fmtMode) Fprintf(s fmt.State, format string, args ...interface{}) {
+	m.prepareArgs(args)
+	fmt.Fprintf(s, format, args...)
+}
+
+func (m fmtMode) Sprintf(format string, args ...interface{}) string {
+	m.prepareArgs(args)
+	return fmt.Sprintf(format, args...)
+}
+
+func (m fmtMode) Sprint(args ...interface{}) string {
+	m.prepareArgs(args)
+	return fmt.Sprint(args...)
+}
+
+func (m fmtMode) prepareArgs(args []interface{}) {
+	switch m {
+	case FErr:
+		for i, arg := range args {
+			switch arg := arg.(type) {
+			case Op:
+				args[i] = fmtOpErr(arg)
+			case *Node:
+				args[i] = (*fmtNodeErr)(arg)
+			case *types.Type:
+				args[i] = (*fmtTypeErr)(arg)
+			case *types.Sym:
+				args[i] = (*fmtSymErr)(arg)
+			case Nodes:
+				args[i] = fmtNodesErr(arg)
+			case Val, int32, int64, string, types.EType:
+				// OK: printing these types doesn't depend on mode
+			default:
+				Fatalf("mode.prepareArgs type %T", arg)
+			}
+		}
+	case FDbg:
+		for i, arg := range args {
+			switch arg := arg.(type) {
+			case Op:
+				args[i] = fmtOpDbg(arg)
+			case *Node:
+				args[i] = (*fmtNodeDbg)(arg)
+			case *types.Type:
+				args[i] = (*fmtTypeDbg)(arg)
+			case *types.Sym:
+				args[i] = (*fmtSymDbg)(arg)
+			case Nodes:
+				args[i] = fmtNodesDbg(arg)
+			case Val, int32, int64, string, types.EType:
+				// OK: printing these types doesn't depend on mode
+			default:
+				Fatalf("mode.prepareArgs type %T", arg)
+			}
+		}
+	case FTypeId:
+		for i, arg := range args {
+			switch arg := arg.(type) {
+			case Op:
+				args[i] = fmtOpTypeId(arg)
+			case *Node:
+				args[i] = (*fmtNodeTypeId)(arg)
+			case *types.Type:
+				args[i] = (*fmtTypeTypeId)(arg)
+			case *types.Sym:
+				args[i] = (*fmtSymTypeId)(arg)
+			case Nodes:
+				args[i] = fmtNodesTypeId(arg)
+			case Val, int32, int64, string, types.EType:
+				// OK: printing these types doesn't depend on mode
+			default:
+				Fatalf("mode.prepareArgs type %T", arg)
+			}
+		}
+	case FTypeIdName:
+		for i, arg := range args {
+			switch arg := arg.(type) {
+			case Op:
+				args[i] = fmtOpTypeIdName(arg)
+			case *Node:
+				args[i] = (*fmtNodeTypeIdName)(arg)
+			case *types.Type:
+				args[i] = (*fmtTypeTypeIdName)(arg)
+			case *types.Sym:
+				args[i] = (*fmtSymTypeIdName)(arg)
+			case Nodes:
+				args[i] = fmtNodesTypeIdName(arg)
+			case Val, int32, int64, string, types.EType:
+				// OK: printing these types doesn't depend on mode
+			default:
+				Fatalf("mode.prepareArgs type %T", arg)
+			}
+		}
+	default:
+		Fatalf("mode.prepareArgs mode %d", m)
+	}
+}
+
+func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
 	switch verb {
 	case 'v', 'S', 'L':
-		n.Nconv(s, fmtFlag(s, verb))
+		n.nconv(s, fmtFlag(s, verb), mode)
 
 	case 'j':
 		n.jconv(s, fmtFlag(s, verb))
@@ -271,36 +431,32 @@ func (n *Node) Format(s fmt.State, verb rune) {
 func (n *Node) jconv(s fmt.State, flag FmtFlag) {
 	c := flag & FmtShort
 
-	if c == 0 && n.Ullman != 0 {
-		fmt.Fprintf(s, " u(%d)", n.Ullman)
-	}
-
-	if c == 0 && n.Addable {
-		fmt.Fprintf(s, " a(%v)", n.Addable)
+	if c == 0 && n.Addable() {
+		fmt.Fprintf(s, " a(%v)", n.Addable())
 	}
 
 	if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
 		fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
 	}
 
-	if n.Lineno != 0 {
-		fmt.Fprintf(s, " l(%d)", n.Lineno)
+	if n.Pos.IsKnown() {
+		fmt.Fprintf(s, " l(%d)", n.Pos.Line())
 	}
 
 	if c == 0 && n.Xoffset != BADWIDTH {
 		fmt.Fprintf(s, " x(%d)", n.Xoffset)
 	}
 
-	if n.Class != 0 {
-		if int(n.Class) < len(classnames) {
-			fmt.Fprintf(s, " class(%s)", classnames[n.Class])
+	if n.Class() != 0 {
+		if int(n.Class()) < len(classnames) {
+			fmt.Fprintf(s, " class(%s)", classnames[n.Class()])
 		} else {
-			fmt.Fprintf(s, " class(%d?)", n.Class)
+			fmt.Fprintf(s, " class(%d?)", n.Class())
 		}
 	}
 
-	if n.Colas {
-		fmt.Fprintf(s, " colas(%v)", n.Colas)
+	if n.Colas() {
+		fmt.Fprintf(s, " colas(%v)", n.Colas())
 	}
 
 	if n.Name != nil && n.Name.Funcdepth != 0 {
@@ -333,42 +489,42 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
 		fmt.Fprintf(s, " ld(%d)", e.Loopdepth)
 	}
 
-	if c == 0 && n.Typecheck != 0 {
-		fmt.Fprintf(s, " tc(%d)", n.Typecheck)
+	if c == 0 && n.Typecheck() != 0 {
+		fmt.Fprintf(s, " tc(%d)", n.Typecheck())
 	}
 
-	if c == 0 && n.IsStatic {
-		fmt.Fprint(s, " static")
+	if n.Isddd() {
+		fmt.Fprintf(s, " isddd(%v)", n.Isddd())
 	}
 
-	if n.Isddd {
-		fmt.Fprintf(s, " isddd(%v)", n.Isddd)
+	if n.Implicit() {
+		fmt.Fprintf(s, " implicit(%v)", n.Implicit())
 	}
 
-	if n.Implicit {
-		fmt.Fprintf(s, " implicit(%v)", n.Implicit)
+	if n.Embedded() {
+		fmt.Fprintf(s, " embedded")
 	}
 
-	if n.Embedded != 0 {
-		fmt.Fprintf(s, " embedded(%d)", n.Embedded)
-	}
-
-	if n.Addrtaken {
+	if n.Addrtaken() {
 		fmt.Fprint(s, " addrtaken")
 	}
 
-	if n.Assigned {
+	if n.Assigned() {
 		fmt.Fprint(s, " assigned")
 	}
-	if n.Bounded {
+	if n.Bounded() {
 		fmt.Fprint(s, " bounded")
 	}
-	if n.NonNil {
+	if n.NonNil() {
 		fmt.Fprint(s, " nonnil")
 	}
 
-	if c == 0 && n.Used {
-		fmt.Fprintf(s, " used(%v)", n.Used)
+	if c == 0 && n.HasCall() {
+		fmt.Fprint(s, " hascall")
+	}
+
+	if c == 0 && n.Name != nil && n.Name.Used() {
+		fmt.Fprint(s, " used")
 	}
 }
 
@@ -438,11 +594,7 @@ func (v Val) vconv(s fmt.State, flag FmtFlag) {
 		fmt.Fprint(s, strconv.Quote(u))
 
 	case bool:
-		t := "false"
-		if u {
-			t = "true"
-		}
-		fmt.Fprint(s, t)
+		fmt.Fprint(s, u)
 
 	case *NilVal:
 		fmt.Fprint(s, "nil")
@@ -461,56 +613,10 @@ s%.+%	[T&]		= "&",%g
 s%^	........*\]%&~%g
 s%~	%%g
 */
-var etnames = []string{
-	Txxx:        "Txxx",
-	TINT:        "INT",
-	TUINT:       "UINT",
-	TINT8:       "INT8",
-	TUINT8:      "UINT8",
-	TINT16:      "INT16",
-	TUINT16:     "UINT16",
-	TINT32:      "INT32",
-	TUINT32:     "UINT32",
-	TINT64:      "INT64",
-	TUINT64:     "UINT64",
-	TUINTPTR:    "UINTPTR",
-	TFLOAT32:    "FLOAT32",
-	TFLOAT64:    "FLOAT64",
-	TCOMPLEX64:  "COMPLEX64",
-	TCOMPLEX128: "COMPLEX128",
-	TBOOL:       "BOOL",
-	TPTR32:      "PTR32",
-	TPTR64:      "PTR64",
-	TFUNC:       "FUNC",
-	TARRAY:      "ARRAY",
-	TSLICE:      "SLICE",
-	TSTRUCT:     "STRUCT",
-	TCHAN:       "CHAN",
-	TMAP:        "MAP",
-	TINTER:      "INTER",
-	TFORW:       "FORW",
-	TSTRING:     "STRING",
-	TUNSAFEPTR:  "TUNSAFEPTR",
-	TANY:        "ANY",
-	TIDEAL:      "TIDEAL",
-	TNIL:        "TNIL",
-	TBLANK:      "TBLANK",
-	TFUNCARGS:   "TFUNCARGS",
-	TCHANARGS:   "TCHANARGS",
-	TINTERMETH:  "TINTERMETH",
-	TDDDFIELD:   "TDDDFIELD",
-}
-
-func (et EType) String() string {
-	if int(et) < len(etnames) && etnames[et] != "" {
-		return etnames[et]
-	}
-	return fmt.Sprintf("E-%d", et)
-}
 
-func (s *Sym) symfmt(flag FmtFlag) string {
+func symfmt(s *types.Sym, flag FmtFlag, mode fmtMode) string {
 	if s.Pkg != nil && flag&FmtShort == 0 {
-		switch fmtmode {
+		switch mode {
 		case FErr: // This is for the user
 			if s.Pkg == builtinpkg || s.Pkg == localpkg {
 				return s.Name
@@ -525,10 +631,10 @@ func (s *Sym) symfmt(flag FmtFlag) string {
 		case FDbg:
 			return s.Pkg.Name + "." + s.Name
 
+		case FTypeIdName:
+			return s.Pkg.Name + "." + s.Name // dcommontype, typehash
+
 		case FTypeId:
-			if flag&FmtUnsigned != 0 {
-				return s.Pkg.Name + "." + s.Name // dcommontype, typehash
-			}
 			return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
 		}
 	}
@@ -541,7 +647,7 @@ func (s *Sym) symfmt(flag FmtFlag) string {
 			name = name[i+1:]
 		}
 
-		if fmtmode == FDbg {
+		if mode == FDbg {
 			return fmt.Sprintf("@%q.%s", s.Pkg.Path, name)
 		}
 
@@ -575,93 +681,95 @@ var basicnames = []string{
 	TBLANK:      "blank",
 }
 
-func (t *Type) typefmt(flag FmtFlag) string {
+func typefmt(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
 	if t == nil {
 		return "<T>"
 	}
 
-	if t == bytetype || t == runetype {
+	if t == types.Bytetype || t == types.Runetype {
 		// in %-T mode collapse rune and byte with their originals.
-		if fmtmode != FTypeId {
-			return t.Sym.sconv(FmtShort)
+		switch mode {
+		case FTypeIdName, FTypeId:
+			t = types.Types[t.Etype]
+		default:
+			return sconv(t.Sym, FmtShort, mode)
 		}
-		t = Types[t.Etype]
 	}
 
-	if t == errortype {
+	if t == types.Errortype {
 		return "error"
 	}
 
 	// Unless the 'l' flag was specified, if the type has a name, just print that name.
-	if flag&FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] {
-		switch fmtmode {
-		case FTypeId:
+	if flag&FmtLong == 0 && t.Sym != nil && t != types.Types[t.Etype] {
+		switch mode {
+		case FTypeId, FTypeIdName:
 			if flag&FmtShort != 0 {
 				if t.Vargen != 0 {
-					return fmt.Sprintf("%v·%d", t.Sym.sconv(FmtShort), t.Vargen)
+					return mode.Sprintf("%v·%d", sconv(t.Sym, FmtShort, mode), t.Vargen)
 				}
-				return t.Sym.sconv(FmtShort)
+				return sconv(t.Sym, FmtShort, mode)
 			}
 
-			if flag&FmtUnsigned != 0 {
-				return t.Sym.sconv(FmtUnsigned)
+			if mode == FTypeIdName {
+				return sconv(t.Sym, FmtUnsigned, mode)
 			}
 
 			if t.Sym.Pkg == localpkg && t.Vargen != 0 {
-				return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
+				return mode.Sprintf("%v·%d", t.Sym, t.Vargen)
 			}
 		}
 
-		return t.Sym.String()
+		return smodeString(t.Sym, mode)
 	}
 
 	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
 		prefix := ""
-		if fmtmode == FErr && (t == idealbool || t == idealstring) {
+		if mode == FErr && (t == types.Idealbool || t == types.Idealstring) {
 			prefix = "untyped "
 		}
 		return prefix + basicnames[t.Etype]
 	}
 
-	if fmtmode == FDbg {
-		fmtmode = 0
-		str := t.Etype.String() + "-" + t.typefmt(flag)
-		fmtmode = FDbg
-		return str
+	if mode == FDbg {
+		return t.Etype.String() + "-" + typefmt(t, flag, 0, depth)
 	}
 
 	switch t.Etype {
 	case TPTR32, TPTR64:
-		if fmtmode == FTypeId && (flag&FmtShort != 0) {
-			return "*" + t.Elem().tconv(FmtShort)
+		switch mode {
+		case FTypeId, FTypeIdName:
+			if flag&FmtShort != 0 {
+				return "*" + tconv(t.Elem(), FmtShort, mode, depth)
+			}
 		}
-		return "*" + t.Elem().String()
+		return "*" + tmodeString(t.Elem(), mode, depth)
 
 	case TARRAY:
-		if t.isDDDArray() {
-			return "[...]" + t.Elem().String()
+		if t.IsDDDArray() {
+			return "[...]" + tmodeString(t.Elem(), mode, depth)
 		}
-		return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
+		return "[" + strconv.FormatInt(t.NumElem(), 10) + "]" + tmodeString(t.Elem(), mode, depth)
 
 	case TSLICE:
-		return "[]" + t.Elem().String()
+		return "[]" + tmodeString(t.Elem(), mode, depth)
 
 	case TCHAN:
 		switch t.ChanDir() {
-		case Crecv:
-			return "<-chan " + t.Elem().String()
+		case types.Crecv:
+			return "<-chan " + tmodeString(t.Elem(), mode, depth)
 
-		case Csend:
-			return "chan<- " + t.Elem().String()
+		case types.Csend:
+			return "chan<- " + tmodeString(t.Elem(), mode, depth)
 		}
 
-		if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv {
-			return "chan (" + t.Elem().String() + ")"
+		if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == types.Crecv {
+			return "chan (" + tmodeString(t.Elem(), mode, depth) + ")"
 		}
-		return "chan " + t.Elem().String()
+		return "chan " + tmodeString(t.Elem(), mode, depth)
 
 	case TMAP:
-		return "map[" + t.Key().String() + "]" + t.Val().String()
+		return "map[" + tmodeString(t.Key(), mode, depth) + "]" + tmodeString(t.Val(), mode, depth)
 
 	case TINTER:
 		if t.IsEmptyInterface() {
@@ -680,11 +788,11 @@ func (t *Type) typefmt(flag FmtFlag) string {
 				// Wrong interface definitions may have types lacking a symbol.
 				break
 			case exportname(f.Sym.Name):
-				buf = append(buf, f.Sym.sconv(FmtShort)...)
+				buf = append(buf, sconv(f.Sym, FmtShort, mode)...)
 			default:
-				buf = append(buf, f.Sym.sconv(FmtUnsigned)...)
+				buf = append(buf, sconv(f.Sym, FmtUnsigned, mode)...)
 			}
-			buf = append(buf, f.Type.tconv(FmtShort)...)
+			buf = append(buf, tconv(f.Type, FmtShort, mode, depth)...)
 		}
 		if t.NumFields() != 0 {
 			buf = append(buf, ' ')
@@ -699,12 +807,12 @@ func (t *Type) typefmt(flag FmtFlag) string {
 		} else {
 			if t.Recv() != nil {
 				buf = append(buf, "method"...)
-				buf = append(buf, t.Recvs().String()...)
+				buf = append(buf, tmodeString(t.Recvs(), mode, depth)...)
 				buf = append(buf, ' ')
 			}
 			buf = append(buf, "func"...)
 		}
-		buf = append(buf, t.Params().String()...)
+		buf = append(buf, tmodeString(t.Params(), mode, depth)...)
 
 		switch t.Results().NumFields() {
 		case 0:
@@ -712,11 +820,11 @@ func (t *Type) typefmt(flag FmtFlag) string {
 
 		case 1:
 			buf = append(buf, ' ')
-			buf = append(buf, t.Results().Field(0).Type.String()...) // struct->field->field's type
+			buf = append(buf, tmodeString(t.Results().Field(0).Type, mode, depth)...) // struct->field->field's type
 
 		default:
 			buf = append(buf, ' ')
-			buf = append(buf, t.Results().String()...)
+			buf = append(buf, tmodeString(t.Results(), mode, depth)...)
 		}
 		return string(buf)
 
@@ -726,32 +834,34 @@ func (t *Type) typefmt(flag FmtFlag) string {
 			// Format the bucket struct for map[x]y as map.bucket[x]y.
 			// This avoids a recursive print that generates very long names.
 			if mt.Bucket == t {
-				return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
+				return "map.bucket[" + tmodeString(m.Key(), mode, depth) + "]" + tmodeString(m.Val(), mode, depth)
 			}
 
 			if mt.Hmap == t {
-				return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
+				return "map.hdr[" + tmodeString(m.Key(), mode, depth) + "]" + tmodeString(m.Val(), mode, depth)
 			}
 
 			if mt.Hiter == t {
-				return "map.iter[" + m.Key().String() + "]" + m.Val().String()
+				return "map.iter[" + tmodeString(m.Key(), mode, depth) + "]" + tmodeString(m.Val(), mode, depth)
 			}
 
-			yyerror("unknown internal map type")
+			Fatalf("unknown internal map type")
 		}
 
 		buf := make([]byte, 0, 64)
 		if t.IsFuncArgStruct() {
 			buf = append(buf, '(')
 			var flag1 FmtFlag
-			if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
+			switch mode {
+			case FTypeId, FTypeIdName, FErr:
+				// no argument names on function signature, and no "noescape"/"nosplit" tags
 				flag1 = FmtShort
 			}
 			for i, f := range t.Fields().Slice() {
 				if i != 0 {
 					buf = append(buf, ", "...)
 				}
-				buf = append(buf, fldconv(f, flag1)...)
+				buf = append(buf, fldconv(f, flag1, mode, depth)...)
 			}
 			buf = append(buf, ')')
 		} else {
@@ -761,7 +871,7 @@ func (t *Type) typefmt(flag FmtFlag) string {
 					buf = append(buf, ';')
 				}
 				buf = append(buf, ' ')
-				buf = append(buf, fldconv(f, FmtLong)...)
+				buf = append(buf, fldconv(f, FmtLong, mode, depth)...)
 			}
 			if t.NumFields() != 0 {
 				buf = append(buf, ' ')
@@ -772,7 +882,7 @@ func (t *Type) typefmt(flag FmtFlag) string {
 
 	case TFORW:
 		if t.Sym != nil {
-			return "undefined " + t.Sym.String()
+			return "undefined " + smodeString(t.Sym, mode)
 		}
 		return "undefined"
 
@@ -780,27 +890,27 @@ func (t *Type) typefmt(flag FmtFlag) string {
 		return "unsafe.Pointer"
 
 	case TDDDFIELD:
-		return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
+		return mode.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
 
 	case Txxx:
 		return "Txxx"
 	}
 
 	// Don't know how to handle - fall back to detailed prints.
-	return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
+	return mode.Sprintf("%v <%v>", t.Etype, t.Sym)
 }
 
 // Statements which may be rendered with a simplestmt as init.
 func stmtwithinit(op Op) bool {
 	switch op {
-	case OIF, OFOR, OSWITCH:
+	case OIF, OFOR, OFORUNTIL, OSWITCH:
 		return true
 	}
 
 	return false
 }
 
-func (n *Node) stmtfmt(s fmt.State) {
+func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
 	// 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
@@ -810,7 +920,7 @@ func (n *Node) stmtfmt(s fmt.State) {
 	simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
 
 	// otherwise, print the inits as separate statements
-	complexinit := n.Ninit.Len() != 0 && !simpleinit && (fmtmode != FErr)
+	complexinit := n.Ninit.Len() != 0 && !simpleinit && (mode != FErr)
 
 	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
 	extrablock := complexinit && stmtwithinit(n.Op)
@@ -820,151 +930,155 @@ func (n *Node) stmtfmt(s fmt.State) {
 	}
 
 	if complexinit {
-		fmt.Fprintf(s, " %v; ", n.Ninit)
+		mode.Fprintf(s, " %v; ", n.Ninit)
 	}
 
 	switch n.Op {
 	case ODCL:
-		fmt.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
+		mode.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
 
 	case ODCLFIELD:
 		if n.Left != nil {
-			fmt.Fprintf(s, "%v %v", n.Left, n.Right)
+			mode.Fprintf(s, "%v %v", n.Left, n.Right)
 		} else {
-			fmt.Fprintf(s, "%v", n.Right)
+			mode.Fprintf(s, "%v", n.Right)
 		}
 
 	// Don't export "v = <N>" initializing statements, hope they're always
 	// preceded by the DCL which will be re-parsed and typechecked to reproduce
 	// the "v = <N>" again.
-	case OAS, OASWB:
-		if n.Colas && !complexinit {
-			fmt.Fprintf(s, "%v := %v", n.Left, n.Right)
+	case OAS:
+		if n.Colas() && !complexinit {
+			mode.Fprintf(s, "%v := %v", n.Left, n.Right)
 		} else {
-			fmt.Fprintf(s, "%v = %v", n.Left, n.Right)
+			mode.Fprintf(s, "%v = %v", n.Left, n.Right)
 		}
 
 	case OASOP:
-		if n.Implicit {
+		if n.Implicit() {
 			if Op(n.Etype) == OADD {
-				fmt.Fprintf(s, "%v++", n.Left)
+				mode.Fprintf(s, "%v++", n.Left)
 			} else {
-				fmt.Fprintf(s, "%v--", n.Left)
+				mode.Fprintf(s, "%v--", n.Left)
 			}
 			break
 		}
 
-		fmt.Fprintf(s, "%v %#v= %v", n.Left, Op(n.Etype), n.Right)
+		mode.Fprintf(s, "%v %#v= %v", n.Left, Op(n.Etype), n.Right)
 
 	case OAS2:
-		if n.Colas && !complexinit {
-			fmt.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
+		if n.Colas() && !complexinit {
+			mode.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
 			break
 		}
 		fallthrough
 
 	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
-		fmt.Fprintf(s, "%.v = %.v", n.List, n.Rlist)
+		mode.Fprintf(s, "%.v = %.v", n.List, n.Rlist)
 
 	case ORETURN:
-		fmt.Fprintf(s, "return %.v", n.List)
+		mode.Fprintf(s, "return %.v", n.List)
 
 	case ORETJMP:
-		fmt.Fprintf(s, "retjmp %v", n.Sym)
+		mode.Fprintf(s, "retjmp %v", n.Sym)
 
 	case OPROC:
-		fmt.Fprintf(s, "go %v", n.Left)
+		mode.Fprintf(s, "go %v", n.Left)
 
 	case ODEFER:
-		fmt.Fprintf(s, "defer %v", n.Left)
+		mode.Fprintf(s, "defer %v", n.Left)
 
 	case OIF:
 		if simpleinit {
-			fmt.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
+			mode.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
 		} else {
-			fmt.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
+			mode.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
 		}
 		if n.Rlist.Len() != 0 {
-			fmt.Fprintf(s, " else { %v }", n.Rlist)
+			mode.Fprintf(s, " else { %v }", n.Rlist)
 		}
 
-	case OFOR:
-		if fmtmode == FErr { // TODO maybe only if FmtShort, same below
-			fmt.Fprint(s, "for loop")
+	case OFOR, OFORUNTIL:
+		opname := "for"
+		if n.Op == OFORUNTIL {
+			opname = "foruntil"
+		}
+		if mode == FErr { // TODO maybe only if FmtShort, same below
+			fmt.Fprintf(s, "%s loop", opname)
 			break
 		}
 
-		fmt.Fprint(s, "for")
+		fmt.Fprint(s, opname)
 		if simpleinit {
-			fmt.Fprintf(s, " %v;", n.Ninit.First())
+			mode.Fprintf(s, " %v;", n.Ninit.First())
 		} else if n.Right != nil {
 			fmt.Fprint(s, " ;")
 		}
 
 		if n.Left != nil {
-			fmt.Fprintf(s, " %v", n.Left)
+			mode.Fprintf(s, " %v", n.Left)
 		}
 
 		if n.Right != nil {
-			fmt.Fprintf(s, "; %v", n.Right)
+			mode.Fprintf(s, "; %v", n.Right)
 		} else if simpleinit {
 			fmt.Fprint(s, ";")
 		}
 
-		fmt.Fprintf(s, " { %v }", n.Nbody)
+		mode.Fprintf(s, " { %v }", n.Nbody)
 
 	case ORANGE:
-		if fmtmode == FErr {
+		if mode == FErr {
 			fmt.Fprint(s, "for loop")
 			break
 		}
 
 		if n.List.Len() == 0 {
-			fmt.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
+			mode.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
 			break
 		}
 
-		fmt.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
+		mode.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
 
 	case OSELECT, OSWITCH:
-		if fmtmode == FErr {
-			fmt.Fprintf(s, "%v statement", n.Op)
+		if mode == FErr {
+			mode.Fprintf(s, "%v statement", n.Op)
 			break
 		}
 
-		fmt.Fprint(s, n.Op.GoString()) // %#v
+		mode.Fprintf(s, "%#v", n.Op)
 		if simpleinit {
-			fmt.Fprintf(s, " %v;", n.Ninit.First())
+			mode.Fprintf(s, " %v;", n.Ninit.First())
 		}
 		if n.Left != nil {
-			fmt.Fprintf(s, " %v ", n.Left)
+			mode.Fprintf(s, " %v ", n.Left)
 		}
 
-		fmt.Fprintf(s, " { %v }", n.List)
+		mode.Fprintf(s, " { %v }", n.List)
 
 	case OXCASE:
 		if n.List.Len() != 0 {
-			fmt.Fprintf(s, "case %.v", n.List)
+			mode.Fprintf(s, "case %.v", n.List)
 		} else {
 			fmt.Fprint(s, "default")
 		}
-		fmt.Fprintf(s, ": %v", n.Nbody)
+		mode.Fprintf(s, ": %v", n.Nbody)
 
 	case OCASE:
 		switch {
 		case n.Left != nil:
 			// single element
-			fmt.Fprintf(s, "case %v", n.Left)
+			mode.Fprintf(s, "case %v", n.Left)
 		case n.List.Len() > 0:
 			// range
 			if n.List.Len() != 2 {
 				Fatalf("bad OCASE list length %d", n.List.Len())
 			}
-			fmt.Fprintf(s, "case %v..%v", n.List.First(), n.List.Second())
+			mode.Fprintf(s, "case %v..%v", n.List.First(), n.List.Second())
 		default:
 			fmt.Fprint(s, "default")
 		}
-		fmt.Fprintf(s, ": %v", n.Nbody)
+		mode.Fprintf(s, ": %v", n.Nbody)
 
 	case OBREAK,
 		OCONTINUE,
@@ -972,16 +1086,16 @@ func (n *Node) stmtfmt(s fmt.State) {
 		OFALL,
 		OXFALL:
 		if n.Left != nil {
-			fmt.Fprintf(s, "%#v %v", n.Op, n.Left)
+			mode.Fprintf(s, "%#v %v", n.Op, n.Left)
 		} else {
-			fmt.Fprint(s, n.Op.GoString()) // %#v
+			mode.Fprintf(s, "%#v", n.Op)
 		}
 
 	case OEMPTY:
 		break
 
 	case OLABEL:
-		fmt.Fprintf(s, "%v: ", n.Left)
+		mode.Fprintf(s, "%v: ", n.Left)
 	}
 
 	if extrablock {
@@ -1077,6 +1191,7 @@ var opprec = []int{
 	OSEND:         3,
 	OANDAND:       2,
 	OOROR:         1,
+
 	// Statements handled by stmtfmt
 	OAS:         -1,
 	OAS2:        -1,
@@ -1094,6 +1209,7 @@ var opprec = []int{
 	OEMPTY:      -1,
 	OFALL:       -1,
 	OFOR:        -1,
+	OFORUNTIL:   -1,
 	OGOTO:       -1,
 	OIF:         -1,
 	OLABEL:      -1,
@@ -1104,11 +1220,12 @@ var opprec = []int{
 	OSWITCH:     -1,
 	OXCASE:      -1,
 	OXFALL:      -1,
-	OEND:        0,
+
+	OEND: 0,
 }
 
-func (n *Node) exprfmt(s fmt.State, prec int) {
-	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
+func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
+	for n != nil && n.Implicit() && (n.Op == OIND || n.Op == OADDR) {
 		n = n.Left
 	}
 
@@ -1123,87 +1240,87 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 	}
 
 	if prec > nprec {
-		fmt.Fprintf(s, "(%v)", n)
+		mode.Fprintf(s, "(%v)", n)
 		return
 	}
 
 	switch n.Op {
 	case OPAREN:
-		fmt.Fprintf(s, "(%v)", n.Left)
+		mode.Fprintf(s, "(%v)", n.Left)
 
 	case ODDDARG:
 		fmt.Fprint(s, "... argument")
 
 	case OLITERAL: // this is a bit of a mess
-		if fmtmode == FErr {
+		if mode == FErr {
 			if n.Orig != nil && n.Orig != n {
-				n.Orig.exprfmt(s, prec)
+				n.Orig.exprfmt(s, prec, mode)
 				return
 			}
 			if n.Sym != nil {
-				fmt.Fprint(s, n.Sym.String())
+				fmt.Fprint(s, smodeString(n.Sym, mode))
 				return
 			}
 		}
 		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
-			n.Orig.exprfmt(s, prec)
+			n.Orig.exprfmt(s, prec, mode)
 			return
 		}
-		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
+		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != types.Idealbool && n.Type != types.Idealstring {
 			// Need parens when type begins with what might
 			// be misinterpreted as a unary operator: * or <-.
-			if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) {
-				fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
+			if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) {
+				mode.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
 				return
 			} else {
-				fmt.Fprintf(s, "%v(%v)", n.Type, n.Val())
+				mode.Fprintf(s, "%v(%v)", n.Type, n.Val())
 				return
 			}
 		}
 
-		fmt.Fprintf(s, "%v", n.Val())
+		mode.Fprintf(s, "%v", n.Val())
 
 	// Special case: name used as local variable in export.
 	// _ becomes ~b%d internally; print as _ for export
 	case ONAME:
-		if fmtmode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+		if mode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
 			fmt.Fprint(s, "_")
 			return
 		}
 		fallthrough
 	case OPACK, ONONAME:
-		fmt.Fprint(s, n.Sym.String())
+		fmt.Fprint(s, smodeString(n.Sym, mode))
 
 	case OTYPE:
 		if n.Type == nil && n.Sym != nil {
-			fmt.Fprint(s, n.Sym.String())
+			fmt.Fprint(s, smodeString(n.Sym, mode))
 			return
 		}
-		fmt.Fprintf(s, "%v", n.Type)
+		mode.Fprintf(s, "%v", n.Type)
 
 	case OTARRAY:
 		if n.Left != nil {
-			fmt.Fprintf(s, "[]%v", n.Left)
+			mode.Fprintf(s, "[]%v", n.Left)
 			return
 		}
-		fmt.Fprintf(s, "[]%v", n.Right) // happens before typecheck
+		mode.Fprintf(s, "[]%v", n.Right) // happens before typecheck
 
 	case OTMAP:
-		fmt.Fprintf(s, "map[%v]%v", n.Left, n.Right)
+		mode.Fprintf(s, "map[%v]%v", n.Left, n.Right)
 
 	case OTCHAN:
-		switch ChanDir(n.Etype) {
-		case Crecv:
-			fmt.Fprintf(s, "<-chan %v", n.Left)
+		switch types.ChanDir(n.Etype) {
+		case types.Crecv:
+			mode.Fprintf(s, "<-chan %v", n.Left)
 
-		case Csend:
-			fmt.Fprintf(s, "chan<- %v", n.Left)
+		case types.Csend:
+			mode.Fprintf(s, "chan<- %v", n.Left)
 
 		default:
-			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
-				fmt.Fprintf(s, "chan (%v)", n.Left)
+			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && types.ChanDir(n.Left.Etype) == types.Crecv {
+				mode.Fprintf(s, "chan (%v)", n.Left)
 			} else {
-				fmt.Fprintf(s, "chan %v", n.Left)
+				mode.Fprintf(s, "chan %v", n.Left)
 			}
 		}
 
@@ -1217,25 +1334,25 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 		fmt.Fprint(s, "<func>")
 
 	case OCLOSURE:
-		if fmtmode == FErr {
+		if mode == FErr {
 			fmt.Fprint(s, "func literal")
 			return
 		}
 		if n.Nbody.Len() != 0 {
-			fmt.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
+			mode.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
 			return
 		}
-		fmt.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
+		mode.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
 
 	case OCOMPLIT:
-		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 {
+		ptrlit := n.Right != nil && n.Right.Implicit() && n.Right.Type != nil && n.Right.Type.IsPtr()
+		if mode == FErr {
+			if n.Right != nil && n.Right.Type != nil && !n.Implicit() {
 				if ptrlit {
-					fmt.Fprintf(s, "&%v literal", n.Right.Type.Elem())
+					mode.Fprintf(s, "&%v literal", n.Right.Type.Elem())
 					return
 				} else {
-					fmt.Fprintf(s, "%v literal", n.Right.Type)
+					mode.Fprintf(s, "%v literal", n.Right.Type)
 					return
 				}
 			}
@@ -1243,86 +1360,86 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 			fmt.Fprint(s, "composite literal")
 			return
 		}
-		fmt.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
+		mode.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
 
 	case OPTRLIT:
-		fmt.Fprintf(s, "&%v", n.Left)
+		mode.Fprintf(s, "&%v", n.Left)
 
 	case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
-		if fmtmode == FErr {
-			fmt.Fprintf(s, "%v literal", n.Type)
+		if mode == FErr {
+			mode.Fprintf(s, "%v literal", n.Type)
 			return
 		}
-		fmt.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
+		mode.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
 
 	case OKEY:
 		if n.Left != nil && n.Right != nil {
-			fmt.Fprintf(s, "%v:%v", n.Left, n.Right)
+			mode.Fprintf(s, "%v:%v", n.Left, n.Right)
 			return
 		}
 
 		if n.Left == nil && n.Right != nil {
-			fmt.Fprintf(s, ":%v", n.Right)
+			mode.Fprintf(s, ":%v", n.Right)
 			return
 		}
 		if n.Left != nil && n.Right == nil {
-			fmt.Fprintf(s, "%v:", n.Left)
+			mode.Fprintf(s, "%v:", n.Left)
 			return
 		}
 		fmt.Fprint(s, ":")
 
 	case OSTRUCTKEY:
-		fmt.Fprintf(s, "%v:%v", n.Sym, n.Left)
+		mode.Fprintf(s, "%v:%v", n.Sym, n.Left)
 
 	case OCALLPART:
-		n.Left.exprfmt(s, nprec)
+		n.Left.exprfmt(s, nprec, mode)
 		if n.Right == nil || n.Right.Sym == nil {
 			fmt.Fprint(s, ".<nil>")
 			return
 		}
-		fmt.Fprintf(s, ".%0S", n.Right.Sym)
+		mode.Fprintf(s, ".%0S", n.Right.Sym)
 
 	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
-		n.Left.exprfmt(s, nprec)
+		n.Left.exprfmt(s, nprec, mode)
 		if n.Sym == nil {
 			fmt.Fprint(s, ".<nil>")
 			return
 		}
-		fmt.Fprintf(s, ".%0S", n.Sym)
+		mode.Fprintf(s, ".%0S", n.Sym)
 
 	case ODOTTYPE, ODOTTYPE2:
-		n.Left.exprfmt(s, nprec)
+		n.Left.exprfmt(s, nprec, mode)
 		if n.Right != nil {
-			fmt.Fprintf(s, ".(%v)", n.Right)
+			mode.Fprintf(s, ".(%v)", n.Right)
 			return
 		}
-		fmt.Fprintf(s, ".(%v)", n.Type)
+		mode.Fprintf(s, ".(%v)", n.Type)
 
 	case OINDEX, OINDEXMAP:
-		n.Left.exprfmt(s, nprec)
-		fmt.Fprintf(s, "[%v]", n.Right)
+		n.Left.exprfmt(s, nprec, mode)
+		mode.Fprintf(s, "[%v]", n.Right)
 
 	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
-		n.Left.exprfmt(s, nprec)
+		n.Left.exprfmt(s, nprec, mode)
 		fmt.Fprint(s, "[")
 		low, high, max := n.SliceBounds()
 		if low != nil {
-			fmt.Fprint(s, low.String())
+			fmt.Fprint(s, low.modeString(mode))
 		}
 		fmt.Fprint(s, ":")
 		if high != nil {
-			fmt.Fprint(s, high.String())
+			fmt.Fprint(s, high.modeString(mode))
 		}
 		if n.Op.IsSlice3() {
 			fmt.Fprint(s, ":")
 			if max != nil {
-				fmt.Fprint(s, max.String())
+				fmt.Fprint(s, max.modeString(mode))
 			}
 		}
 		fmt.Fprint(s, "]")
 
 	case OCOPY, OCOMPLEX:
-		fmt.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
+		mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
 
 	case OCONV,
 		OCONVIFACE,
@@ -1333,14 +1450,15 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 		OSTRARRAYRUNE,
 		ORUNESTR:
 		if n.Type == nil || n.Type.Sym == nil {
-			fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Left)
-			return
+			mode.Fprintf(s, "(%v)", n.Type)
+		} else {
+			mode.Fprintf(s, "%v", n.Type)
 		}
 		if n.Left != nil {
-			fmt.Fprintf(s, "%v(%v)", n.Type, n.Left)
-			return
+			mode.Fprintf(s, "(%v)", n.Left)
+		} else {
+			mode.Fprintf(s, "(%.v)", n.List)
 		}
-		fmt.Fprintf(s, "%v(%.v)", n.Type, n.List)
 
 	case OREAL,
 		OIMAG,
@@ -1359,51 +1477,45 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 		OPRINT,
 		OPRINTN:
 		if n.Left != nil {
-			fmt.Fprintf(s, "%#v(%v)", n.Op, n.Left)
+			mode.Fprintf(s, "%#v(%v)", n.Op, n.Left)
 			return
 		}
-		if n.Isddd {
-			fmt.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
+		if n.Isddd() {
+			mode.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
 			return
 		}
-		fmt.Fprintf(s, "%#v(%.v)", n.Op, n.List)
+		mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
 
 	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
-		n.Left.exprfmt(s, nprec)
-		if n.Isddd {
-			fmt.Fprintf(s, "(%.v...)", n.List)
+		n.Left.exprfmt(s, nprec, mode)
+		if n.Isddd() {
+			mode.Fprintf(s, "(%.v...)", n.List)
 			return
 		}
-		fmt.Fprintf(s, "(%.v)", n.List)
+		mode.Fprintf(s, "(%.v)", n.List)
 
 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
 		if n.List.Len() != 0 { // pre-typecheck
-			fmt.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
+			mode.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
 			return
 		}
 		if n.Right != nil {
-			fmt.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
+			mode.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
 			return
 		}
 		if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
-			fmt.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
+			mode.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
 			return
 		}
-		fmt.Fprintf(s, "make(%v)", n.Type)
+		mode.Fprintf(s, "make(%v)", n.Type)
 
+	case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
 		// Unary
-	case OPLUS,
-		OMINUS,
-		OADDR,
-		OCOM,
-		OIND,
-		ONOT,
-		ORECV:
-		fmt.Fprint(s, n.Op.GoString()) // %#v
-		if n.Left.Op == n.Op {
+		mode.Fprintf(s, "%#v", n.Op)
+		if n.Left != nil && n.Left.Op == n.Op {
 			fmt.Fprint(s, " ")
 		}
-		n.Left.exprfmt(s, nprec+1)
+		n.Left.exprfmt(s, nprec+1, mode)
 
 		// Binary
 	case OADD,
@@ -1426,9 +1538,9 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 		OSEND,
 		OSUB,
 		OXOR:
-		n.Left.exprfmt(s, nprec)
-		fmt.Fprintf(s, " %#v ", n.Op)
-		n.Right.exprfmt(s, nprec+1)
+		n.Left.exprfmt(s, nprec, mode)
+		mode.Fprintf(s, " %#v ", n.Op)
+		n.Right.exprfmt(s, nprec+1, mode)
 
 	case OADDSTR:
 		i := 0
@@ -1436,27 +1548,27 @@ func (n *Node) exprfmt(s fmt.State, prec int) {
 			if i != 0 {
 				fmt.Fprint(s, " + ")
 			}
-			n1.exprfmt(s, nprec)
+			n1.exprfmt(s, nprec, mode)
 			i++
 		}
 
 	case OCMPSTR, OCMPIFACE:
-		n.Left.exprfmt(s, nprec)
+		n.Left.exprfmt(s, nprec, mode)
 		// TODO(marvin): Fix Node.EType type union.
-		fmt.Fprintf(s, " %#v ", Op(n.Etype))
-		n.Right.exprfmt(s, nprec+1)
+		mode.Fprintf(s, " %#v ", Op(n.Etype))
+		n.Right.exprfmt(s, nprec+1, mode)
 
 	default:
-		fmt.Fprintf(s, "<node %v>", n.Op)
+		mode.Fprintf(s, "<node %v>", n.Op)
 	}
 }
 
-func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
+func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
 	t := n.Type
 
-	// we almost always want the original, except in export mode for literals
-	// this saves the importer some work, and avoids us having to redo some
-	// special casing for package unsafe
+	// We almost always want the original, except in export mode for literals.
+	// This saves the importer some work, and avoids us having to redo some
+	// special casing for package unsafe.
 	if n.Op != OLITERAL && n.Orig != nil {
 		n = n.Orig
 	}
@@ -1465,7 +1577,7 @@ func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
 		if t.Etype == TNIL {
 			fmt.Fprint(s, "nil")
 		} else {
-			fmt.Fprintf(s, "%v (type %v)", n, t)
+			mode.Fprintf(s, "%v (type %v)", n, t)
 		}
 		return
 	}
@@ -1473,114 +1585,108 @@ func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
 	// TODO inlining produces expressions with ninits. we can't print these yet.
 
 	if opprec[n.Op] < 0 {
-		n.stmtfmt(s)
+		n.stmtfmt(s, mode)
 		return
 	}
 
-	n.exprfmt(s, 0)
+	n.exprfmt(s, 0, mode)
 }
 
-func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
-	if n == nil {
-		return
-	}
-
+func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
 	recur := flag&FmtShort == 0
 
 	if recur {
 		indent(s)
-		if dumpdepth > 10 {
+		if dumpdepth > 40 {
 			fmt.Fprint(s, "...")
 			return
 		}
 
 		if n.Ninit.Len() != 0 {
-			fmt.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
+			mode.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
 			indent(s)
 		}
 	}
 
 	switch n.Op {
 	default:
-		fmt.Fprintf(s, "%v%j", n.Op, n)
+		mode.Fprintf(s, "%v%j", n.Op, n)
 
 	case OINDREGSP:
-		fmt.Fprintf(s, "%v-SP%j", n.Op, n)
+		mode.Fprintf(s, "%v-SP%j", n.Op, n)
 
 	case OLITERAL:
-		fmt.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
+		mode.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
 
 	case ONAME, ONONAME:
 		if n.Sym != nil {
-			fmt.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
+			mode.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
 		} else {
-			fmt.Fprintf(s, "%v%j", n.Op, n)
+			mode.Fprintf(s, "%v%j", n.Op, n)
 		}
 		if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
 			indent(s)
-			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+			mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
 		}
 
 	case OASOP:
-		fmt.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
+		mode.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
 
 	case OTYPE:
-		fmt.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
+		mode.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
 		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
 			indent(s)
-			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+			mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
 		}
 	}
 
 	if n.Sym != nil && n.Op != ONAME {
-		fmt.Fprintf(s, " %v", n.Sym)
+		mode.Fprintf(s, " %v", n.Sym)
 	}
 
 	if n.Type != nil {
-		fmt.Fprintf(s, " %v", n.Type)
+		mode.Fprintf(s, " %v", n.Type)
 	}
 
 	if recur {
 		if n.Left != nil {
-			fmt.Fprintf(s, "%v", n.Left)
+			mode.Fprintf(s, "%v", n.Left)
 		}
 		if n.Right != nil {
-			fmt.Fprintf(s, "%v", n.Right)
+			mode.Fprintf(s, "%v", n.Right)
 		}
 		if n.List.Len() != 0 {
 			indent(s)
-			fmt.Fprintf(s, "%v-list%v", n.Op, n.List)
+			mode.Fprintf(s, "%v-list%v", n.Op, n.List)
 		}
 
 		if n.Rlist.Len() != 0 {
 			indent(s)
-			fmt.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
+			mode.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
 		}
 
 		if n.Nbody.Len() != 0 {
 			indent(s)
-			fmt.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
+			mode.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
 		}
 	}
 }
 
 // "%S" suppresses qualifying with package
-func (s *Sym) Format(f fmt.State, verb rune) {
+func symFormat(s *types.Sym, f fmt.State, verb rune, mode fmtMode) {
 	switch verb {
 	case 'v', 'S':
-		fmt.Fprint(f, s.sconv(fmtFlag(f, verb)))
+		fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode))
 
 	default:
-		fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
+		fmt.Fprintf(f, "%%!%c(*types.Sym=%p)", verb, s)
 	}
 }
 
-func (s *Sym) String() string {
-	return s.sconv(0)
-}
+func smodeString(s *types.Sym, mode fmtMode) string { return sconv(s, 0, mode) }
 
 // See #16897 before changing the implementation of sconv.
-func (s *Sym) sconv(flag FmtFlag) string {
+func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
 	if flag&FmtLong != 0 {
 		panic("linksymfmt")
 	}
@@ -1593,30 +1699,21 @@ func (s *Sym) sconv(flag FmtFlag) string {
 		return "_"
 	}
 
-	sf := flag
-	sm := setfmode(&flag)
-	str := s.symfmt(flag)
-	flag = sf
-	fmtmode = sm
-	return str
+	flag, mode = flag.update(mode)
+	return symfmt(s, flag, mode)
 }
 
-func (t *Type) String() string {
-	return t.tconv(0)
+func tmodeString(t *types.Type, mode fmtMode, depth int) string {
+	return tconv(t, 0, mode, depth)
 }
 
-func fldconv(f *Field, flag FmtFlag) string {
+func fldconv(f *types.Field, flag FmtFlag, mode fmtMode, depth int) string {
 	if f == nil {
 		return "<T>"
 	}
 
-	sf := flag
-	sm := setfmode(&flag)
-
-	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
-		fmtpkgpfx++
-	}
-	if fmtpkgpfx != 0 {
+	flag, mode = flag.update(mode)
+	if mode == FTypeIdName {
 		flag |= FmtUnsigned
 	}
 
@@ -1626,9 +1723,9 @@ func fldconv(f *Field, flag FmtFlag) string {
 
 		// 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 && f.Nname != nil {
-			if f.Nname.Orig != nil {
-				s = f.Nname.Orig.Sym
+		if mode == FErr && asNode(f.Nname) != nil {
+			if asNode(f.Nname).Orig != nil {
+				s = asNode(f.Nname).Orig.Sym
 				if s != nil && s.Name[0] == '~' {
 					if s.Name[1] == 'r' { // originally an unnamed result
 						s = nil
@@ -1642,24 +1739,28 @@ func fldconv(f *Field, flag FmtFlag) string {
 		}
 
 		if s != nil && f.Embedded == 0 {
-			if f.Funarg != FunargNone {
-				name = f.Nname.String()
+			if f.Funarg != types.FunargNone {
+				name = asNode(f.Nname).modeString(mode)
 			} else if flag&FmtLong != 0 {
-				name = fmt.Sprintf("%0S", s)
+				name = mode.Sprintf("%0S", s)
 				if !exportname(name) && flag&FmtUnsigned == 0 {
-					name = s.String() // qualify non-exported names (used on structs, not on funarg)
+					name = smodeString(s, mode) // qualify non-exported names (used on structs, not on funarg)
 				}
 			} else {
-				name = s.String()
+				name = smodeString(s, mode)
 			}
 		}
 	}
 
 	var typ string
-	if f.Isddd {
-		typ = fmt.Sprintf("...%v", f.Type.Elem())
+	if f.Isddd() {
+		var et *types.Type
+		if f.Type != nil {
+			et = f.Type.Elem()
+		}
+		typ = "..." + tmodeString(et, mode, depth)
 	} else {
-		typ = fmt.Sprintf("%v", f.Type)
+		typ = tmodeString(f.Type, mode, depth)
 	}
 
 	str := typ
@@ -1667,26 +1768,21 @@ func fldconv(f *Field, flag FmtFlag) string {
 		str = name + " " + typ
 	}
 
-	if flag&FmtShort == 0 && f.Funarg == FunargNone && f.Note != "" {
+	if flag&FmtShort == 0 && f.Funarg == types.FunargNone && f.Note != "" {
 		str += " " + strconv.Quote(f.Note)
 	}
 
-	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
-		fmtpkgpfx--
-	}
-
-	flag = sf
-	fmtmode = sm
 	return str
 }
 
 // "%L"  print definition, not name
 // "%S"  omit 'func' and receiver from function types, short type names
-// "% v" package name, not prefix (FTypeId mode, sticky)
-func (t *Type) Format(s fmt.State, verb rune) {
+func typeFormat(t *types.Type, s fmt.State, verb rune, mode fmtMode) {
 	switch verb {
 	case 'v', 'S', 'L':
-		fmt.Fprint(s, t.tconv(fmtFlag(s, verb)))
+		// This is an external entry point, so we pass depth 0 to tconv.
+		// See comments in Type.String.
+		fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode, 0))
 
 	default:
 		fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
@@ -1694,74 +1790,62 @@ func (t *Type) Format(s fmt.State, verb rune) {
 }
 
 // See #16897 before changing the implementation of tconv.
-func (t *Type) tconv(flag FmtFlag) string {
+func tconv(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
 	if t == nil {
 		return "<T>"
 	}
+	if t.Etype == types.TSSA {
+		return t.Extra.(string)
+	}
+	if t.Etype == types.TTUPLE {
+		return t.FieldType(0).String() + "," + t.FieldType(1).String()
+	}
 
-	if t.Trecur > 4 {
+	if depth > 100 {
 		return "<...>"
 	}
 
-	t.Trecur++
-	sf := flag
-	sm := setfmode(&flag)
-
-	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
-		fmtpkgpfx++
-	}
-	if fmtpkgpfx != 0 {
+	flag, mode = flag.update(mode)
+	if mode == FTypeIdName {
 		flag |= FmtUnsigned
 	}
 
-	str := t.typefmt(flag)
-
-	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
-		fmtpkgpfx--
-	}
+	str := typefmt(t, flag, mode, depth+1)
 
-	flag = sf
-	fmtmode = sm
-	t.Trecur--
 	return str
 }
 
-func (n *Node) String() string {
-	return fmt.Sprint(n)
-}
+func (n *Node) String() string                 { return fmt.Sprint(n) }
+func (n *Node) modeString(mode fmtMode) string { return mode.Sprint(n) }
 
 // "%L"  suffix with "(type %T)" where possible
 // "%+S" in debug mode, don't recurse, no multiline output
-func (n *Node) Nconv(s fmt.State, flag FmtFlag) {
+func (n *Node) nconv(s fmt.State, flag FmtFlag, mode fmtMode) {
 	if n == nil {
 		fmt.Fprint(s, "<N>")
 		return
 	}
 
-	sf := flag
-	sm := setfmode(&flag)
+	flag, mode = flag.update(mode)
 
-	switch fmtmode {
+	switch mode {
 	case FErr:
-		n.nodefmt(s, flag)
+		n.nodefmt(s, flag, mode)
 
 	case FDbg:
 		dumpdepth++
-		n.nodedump(s, flag)
+		n.nodedump(s, flag, mode)
 		dumpdepth--
 
 	default:
-		Fatalf("unhandled %%N mode: %d", fmtmode)
+		Fatalf("unhandled %%N mode: %d", mode)
 	}
-
-	flag = sf
-	fmtmode = sm
 }
 
-func (l Nodes) Format(s fmt.State, verb rune) {
+func (l Nodes) format(s fmt.State, verb rune, mode fmtMode) {
 	switch verb {
 	case 'v':
-		l.hconv(s, fmtFlag(s, verb))
+		l.hconv(s, fmtFlag(s, verb), mode)
 
 	default:
 		fmt.Fprintf(s, "%%!%c(Nodes)", verb)
@@ -1773,30 +1857,26 @@ func (n Nodes) String() string {
 }
 
 // Flags: all those of %N plus '.': separate with comma's instead of semicolons.
-func (l Nodes) hconv(s fmt.State, flag FmtFlag) {
-	if l.Len() == 0 && fmtmode == FDbg {
+func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+	if l.Len() == 0 && mode == FDbg {
 		fmt.Fprint(s, "<nil>")
 		return
 	}
 
-	sf := flag
-	sm := setfmode(&flag)
+	flag, mode = flag.update(mode)
 	sep := "; "
-	if fmtmode == FDbg {
+	if mode == FDbg {
 		sep = "\n"
 	} else if flag&FmtComma != 0 {
 		sep = ", "
 	}
 
 	for i, n := range l.Slice() {
-		fmt.Fprint(s, n)
+		fmt.Fprint(s, n.modeString(mode))
 		if i+1 < l.Len() {
 			fmt.Fprint(s, sep)
 		}
 	}
-
-	flag = sf
-	fmtmode = sm
 }
 
 func dumplist(s string, l Nodes) {
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index c3d2c44..626d282 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -2,225 +2,82 @@
 // 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 "fmt"
-
-func Sysfunc(name string) *Node {
-	n := newname(Pkglookup(name, Runtimepkg))
-	n.Class = PFUNC
-	return n
-}
-
-// addrescapes tags node n as having had its address taken
-// by "increasing" the "value" of n.Esc to EscHeap.
-// Storage is allocated as necessary to allow the address
-// to be taken.
-func addrescapes(n *Node) {
-	switch n.Op {
-	// probably a type error already.
-	// dump("addrescapes", n);
-	default:
-		break
-
-	case ONAME:
-		if n == nodfp {
-			break
-		}
-
-		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
-		// on PPARAM it means something different.
-		if n.Class == PAUTO && n.Esc == EscNever {
-			break
-		}
-
-		// If a closure reference escapes, mark the outer variable as escaping.
-		if n.isClosureVar() {
-			addrescapes(n.Name.Defn)
-			break
-		}
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
+	"cmd/internal/src"
+	"strconv"
+)
 
-		if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
-			break
-		}
-
-		// 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
-
-	// ODOTPTR has already been introduced,
-	// so these are the non-pointer ODOT and OINDEX.
-	// In &x[0], if x is a slice, then x does not
-	// escape--the pointer inside x does, but that
-	// is always a heap pointer anyway.
-	case ODOT, OINDEX, OPAREN, OCONVNOP:
-		if !n.Left.Type.IsSlice() {
-			addrescapes(n.Left)
-		}
-	}
+func Sysfunc(name string) *obj.LSym {
+	return Runtimepkg.Lookup(name).Linksym()
 }
 
 // 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
+	return n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Name.Param.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
+	return n.Op == ONAME && n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy != nil
 }
 
-// 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
-
-	// Unset AutoTemp to persist the &foo variable name through SSA to
-	// liveness analysis.
-	// TODO(mdempsky/drchase): Cleaner solution?
-	heapaddr.Name.AutoTemp = false
-
-	// 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 == 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)
-	}
+// autotmpname returns the name for an autotmp variable numbered n.
+func autotmpname(n int) string {
+	// Give each tmp a different name so that they can be registerized.
+	// Add a preceding . to avoid clashing with legal names.
+	const prefix = ".autotmp_"
+	// Start with a buffer big enough to hold a large n.
+	b := []byte(prefix + "      ")[:len(prefix)]
+	b = strconv.AppendInt(b, int64(n), 10)
+	return types.InternString(b)
 }
 
 // make a new Node off the books
-func tempname(nn *Node, t *Type) {
-	if Curfn == nil {
+func tempnamel(pos src.XPos, curfn *Node, nn *Node, t *types.Type) {
+	if curfn == nil {
 		Fatalf("no curfn for tempname")
 	}
-	if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
-		Dump("tempname", Curfn)
+	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")
-		t = Types[TINT32]
+		Fatalf("tempname called with nil type")
 	}
 
-	// give each tmp a different name so that there
-	// a chance to registerizer them.
-	// Add a preceding . to avoid clash with legal names.
-	s := lookupN(".autotmp_", statuniqgen)
-	statuniqgen++
-	n := nod(ONAME, nil, nil)
-	n.Sym = s
-	s.Def = n
+	s := &types.Sym{
+		Name: autotmpname(len(curfn.Func.Dcl)),
+		Pkg:  localpkg,
+	}
+	n := newnamel(pos, s)
+	s.Def = asTypesNode(n)
 	n.Type = t
-	n.Class = PAUTO
-	n.Addable = true
-	n.Ullman = 1
+	n.SetClass(PAUTO)
 	n.Esc = EscNever
-	n.Name.Curfn = Curfn
-	n.Name.AutoTemp = true
-	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+	n.Name.Curfn = curfn
+	n.Name.SetAutoTemp(true)
+	curfn.Func.Dcl = append(curfn.Func.Dcl, n)
 
 	dowidth(t)
-	n.Xoffset = 0
 	*nn = *n
 }
 
-func temp(t *Type) *Node {
+func temp(t *types.Type) *Node {
+	var n Node
+	tempnamel(lineno, Curfn, &n, t)
+	asNode(n.Sym.Def).Name.SetUsed(true)
+	return n.Orig
+}
+
+func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
 	var n Node
-	tempname(&n, t)
-	n.Sym.Def.Used = true
+	tempnamel(pos, curfn, &n, t)
+	asNode(n.Sym.Def).Name.SetUsed(true)
 	return n.Orig
 }
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index a529ca4..65d8946 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -6,88 +6,57 @@ package gc
 
 import (
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/src"
+	"sync"
 )
 
 const (
-	UINF            = 100
-	BADWIDTH        = -1000000000
+	BADWIDTH        = types.BADWIDTH
 	MaxStackVarSize = 10 * 1024 * 1024
 )
 
-type Pkg struct {
-	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
-	Direct   bool   // imported directly
-	Syms     map[string]*Sym
+// isRuntimePkg reports whether p is package runtime.
+func isRuntimePkg(p *types.Pkg) bool {
+	if compiling_runtime && p == localpkg {
+		return true
+	}
+	return p.Path == "runtime"
 }
 
-// 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 an 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 {
-	Flags     SymFlags
-	Link      *Sym
-	Importdef *Pkg   // where imported definition was found
-	Linkname  string // link name
-
-	// saved and restored by dcopy
-	Pkg        *Pkg
-	Name       string // object name
-	Def        *Node  // definition: ONAME OTYPE OPACK or OLITERAL
-	Block      int32  // blocknumber to catch redeclaration
-	Lastlineno int32  // last declaration for diagnostic
-
-	Label   *Node // corresponding label (ephemeral)
-	Origpkg *Pkg  // original package for . import
-	Lsym    *obj.LSym
-	Fsym    *Sym // funcsym
-}
-
-type SymFlags uint8
-
-const (
-	SymExport SymFlags = 1 << iota // to be exported
-	SymPackage
-	SymExported // already written out by export
-	SymUniq
-	SymSiggen
-	SymAsm
-	SymAlgGen
-	SymAlias // alias, original is Sym.Def.Sym
-)
-
 // The Class of a variable/function describes the "storage class"
 // of a variable or function. During parsing, storage classes are
 // called declaration contexts.
 type Class uint8
 
+//go:generate stringer -type=Class
 const (
-	Pxxx      Class = iota
-	PEXTERN         // global variable
-	PAUTO           // local variables
-	PAUTOHEAP       // local variable or parameter moved to heap
-	PPARAM          // input arguments
-	PPARAMOUT       // output results
-	PFUNC           // global function
+	Pxxx      Class = iota // no class; used during ssa conversion to indicate pseudo-variables
+	PEXTERN                // global variable
+	PAUTO                  // local variables
+	PAUTOHEAP              // local variable or parameter moved to heap
+	PPARAM                 // input arguments
+	PPARAMOUT              // output results
+	PFUNC                  // global function
 
 	PDISCARD // discard during parse of duplicate import
+	// Careful: Class is stored in three bits in Node.flags.
+	// Adding a new Class will overflow that.
 )
 
+func init() {
+	if PDISCARD != 7 {
+		panic("PDISCARD changed; does all Class values still fit in three bits?")
+	}
+}
+
 // note this is the runtime representation
 // of the compilers arrays.
 //
 // typedef	struct
-// {					// must not move anything
+// {				// must not move anything
 // 	uchar	array[8];	// pointer to data
 // 	uchar	nel[4];		// number of elements
 // 	uchar	cap[4];		// allocated number of elements
@@ -104,7 +73,7 @@ var sizeof_Array int // runtime sizeof(Array)
 // of the compilers strings.
 //
 // typedef	struct
-// {					// must not move anything
+// {				// must not move anything
 // 	uchar	array[8];	// pointer to data
 // 	uchar	nel[4];		// number of elements
 // } String;
@@ -112,10 +81,9 @@ var sizeof_String int // runtime sizeof(String)
 
 var pragcgobuf string
 
-var infile string
-
 var outfile string
 var linkobj string
+var dolinkobj bool
 
 var bout *bio.Writer
 
@@ -142,38 +110,34 @@ var debugstr string
 var Debug_checknil int
 var Debug_typeassert int
 
-var localpkg *Pkg // package being compiled
+var localpkg *types.Pkg // package being compiled
 
-var importpkg *Pkg // package being imported
+var inimport bool // set during import
 
-var itabpkg *Pkg // fake pkg for itab entries
+var itabpkg *types.Pkg // fake pkg for itab entries
 
-var itablinkpkg *Pkg // fake package for runtime itab entries
+var itablinkpkg *types.Pkg // fake package for runtime itab entries
 
-var Runtimepkg *Pkg // package runtime
+var Runtimepkg *types.Pkg // fake package runtime
 
-var racepkg *Pkg // package runtime/race
+var racepkg *types.Pkg // package runtime/race
 
-var msanpkg *Pkg // package runtime/msan
+var msanpkg *types.Pkg // package runtime/msan
 
-var typepkg *Pkg // fake package for runtime type info (headers)
+var unsafepkg *types.Pkg // package unsafe
 
-var unsafepkg *Pkg // package unsafe
+var trackpkg *types.Pkg // fake package for field tracking
 
-var trackpkg *Pkg // fake package for field tracking
-
-var mappkg *Pkg // fake package for map zero value
+var mappkg *types.Pkg // fake package for map zero value
 var zerosize int64
 
-var Tptr EType // either TPTR32 or TPTR64
-
 var myimportpath string
 
 var localimport string
 
 var asmhdr string
 
-var simtype [NTYPE]EType
+var simtype [NTYPE]types.EType
 
 var (
 	isforw    [NTYPE]bool
@@ -215,32 +179,17 @@ var exportlist []*Node
 
 var importlist []*Node // imported functions and methods with inlinable bodies
 
-var funcsyms []*Node
+var (
+	funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
+	funcsyms   []*types.Sym
+)
 
 var dclcontext Class // PEXTERN/PAUTO
 
-var statuniqgen int // name generator for static temps
-
-var iota_ int64
-
-var lastconst []*Node
-
-var lasttype *Node
-
-var Maxarg int64
-
-var Stksize int64 // stack size for current frame
-
-var stkptrsize int64 // prefix of stack containing pointers
-
-var hasdefer bool // flag that curfn has defer statement
-
 var Curfn *Node
 
 var Widthptr int
 
-var Widthint int
-
 var Widthreg int
 
 var nblank *Node
@@ -249,6 +198,9 @@ var typecheckok bool
 
 var compiling_runtime bool
 
+// Compiling the standard library
+var compiling_std bool
+
 var compiling_wrappers int
 
 var use_writebarrier bool
@@ -261,12 +213,15 @@ var flag_race bool
 
 var flag_msan bool
 
-var flag_largemodel bool
+var flagDWARF bool
 
 // Whether we are adding any sort of code instrumentation, such as
 // when the race detector is enabled.
 var instrumenting bool
 
+// Whether we are tracking lexical scopes for DWARF.
+var trackScopes bool
+
 var debuglive int
 
 var Ctxt *obj.Link
@@ -275,82 +230,24 @@ var writearchive bool
 
 var Nacl bool
 
-var pc *obj.Prog
-
 var nodfp *Node
 
 var disable_checknil int
 
-// interface to back end
+var autogeneratedPos src.XPos
 
-const (
-	// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
-	Pseudo = 1 << 1
-
-	// There's nothing to say about the instruction,
-	// but it's still okay to see.
-	OK = 1 << 2
-
-	// Size of right-side write, or right-side read if no write.
-	SizeB = 1 << 3
-	SizeW = 1 << 4
-	SizeL = 1 << 5
-	SizeQ = 1 << 6
-	SizeF = 1 << 7
-	SizeD = 1 << 8
-
-	// Left side (Prog.from): address taken, read, write.
-	LeftAddr  = 1 << 9
-	LeftRead  = 1 << 10
-	LeftWrite = 1 << 11
-
-	// Register in middle (Prog.reg); only ever read. (arm, ppc64)
-	RegRead    = 1 << 12
-	CanRegRead = 1 << 13
-
-	// Right side (Prog.to): address taken, read, write.
-	RightAddr  = 1 << 14
-	RightRead  = 1 << 15
-	RightWrite = 1 << 16
-
-	// Instruction kinds
-	Move  = 1 << 17 // straight move
-	Conv  = 1 << 18 // size conversion
-	Cjmp  = 1 << 19 // conditional jump
-	Break = 1 << 20 // breaks control flow (no fallthrough)
-	Call  = 1 << 21 // function call
-	Jump  = 1 << 22 // jump
-	Skip  = 1 << 23 // data instruction
-
-	// Set, use, or kill of carry bit.
-	// Kill means we never look at the carry bit after this kind of instruction.
-	// 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
-
-	// Special cases for register use. (amd64, 386)
-	ShiftCX  = 1 << 27 // possible shift by CX
-	ImulAXDX = 1 << 28 // possible multiply into DX:AX
-
-	// Instruction updates whichever of from/to is type D_OREG. (ppc64)
-	PostInc = 1 << 29
-
-	// Optional 3rd input operand, only ever read.
-	From3Read = 1 << 30
-)
+// interface to back end
 
 type Arch struct {
 	LinkArch *obj.LinkArch
 
 	REGSP    int
 	MAXWIDTH int64
+	Use387   bool // should 386 backend use 387 FP instructions instead of sse2.
 
-	Defframe func(*obj.Prog)
-	Proginfo func(*obj.Prog) ProgInfo
-	Use387   bool // should 8g use 387 FP instructions instead of sse2.
+	PadFrame  func(int64) int64
+	ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
+	Ginsnop   func(*Progs)
 
 	// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
 	SSAMarkMoves func(*SSAGenState, *ssa.Block)
@@ -363,28 +260,37 @@ type Arch struct {
 	SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
 
 	// ZeroAuto emits code to zero the given auto stack variable.
-	// Code is added immediately after pp.
 	// ZeroAuto must not use any non-temporary registers.
 	// ZeroAuto will only be called for variables which contain a pointer.
-	ZeroAuto func(n *Node, pp *obj.Prog)
+	ZeroAuto func(*Progs, *Node)
 }
 
-var pcloc int32
-
-var Thearch Arch
+var thearch Arch
 
 var (
+	staticbytes,
+	zerobase *Node
+
 	Newproc,
 	Deferproc,
 	Deferreturn,
+	Duffcopy,
+	Duffzero,
 	panicindex,
 	panicslice,
 	panicdivide,
 	growslice,
-	panicdottype,
+	panicdottypeE,
+	panicdottypeI,
 	panicnildottype,
 	assertE2I,
 	assertE2I2,
 	assertI2I,
-	assertI2I2 *Node
+	assertI2I2,
+	goschedguarded,
+	writeBarrier,
+	writebarrierptr,
+	typedmemmove,
+	typedmemclr,
+	Udiv *obj.LSym
 )
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 2a8bedf..b25709b 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -30,37 +30,104 @@
 
 package gc
 
-import "cmd/internal/obj"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
+)
+
+var sharedProgArray *[10000]obj.Prog = new([10000]obj.Prog) // *T instead of T to work around issue 19839
+
+// Progs accumulates Progs for a function and converts them into machine code.
+type Progs struct {
+	Text      *obj.Prog  // ATEXT Prog for this function
+	next      *obj.Prog  // next Prog
+	pc        int64      // virtual PC; count of Progs
+	pos       src.XPos   // position to use for new Progs
+	curfn     *Node      // fn these Progs are for
+	progcache []obj.Prog // local progcache
+	cacheidx  int        // first free element of progcache
+}
+
+// newProgs returns a new Progs for fn.
+// worker indicates which of the backend workers will use the Progs.
+func newProgs(fn *Node, worker int) *Progs {
+	pp := new(Progs)
+	if Ctxt.CanReuseProgs() {
+		sz := len(sharedProgArray) / nBackendWorkers
+		pp.progcache = sharedProgArray[sz*worker : sz*(worker+1)]
+	}
+	pp.curfn = fn
+
+	// prime the pump
+	pp.next = pp.NewProg()
+	pp.clearp(pp.next)
+
+	pp.pos = fn.Pos
+	pp.settext(fn)
+	return pp
+}
+
+func (pp *Progs) NewProg() *obj.Prog {
+	if pp.cacheidx < len(pp.progcache) {
+		p := &pp.progcache[pp.cacheidx]
+		p.Ctxt = Ctxt
+		pp.cacheidx++
+		return p
+	}
+	p := new(obj.Prog)
+	p.Ctxt = Ctxt
+	return p
+}
+
+// Flush converts from pp to machine code.
+func (pp *Progs) Flush() {
+	plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.curfn}
+	obj.Flushplist(Ctxt, plist, pp.NewProg)
+}
 
-func Prog(as obj.As) *obj.Prog {
-	var p *obj.Prog
+// Free clears pp and any associated resources.
+func (pp *Progs) Free() {
+	if Ctxt.CanReuseProgs() {
+		// Clear progs to enable GC and avoid abuse.
+		s := pp.progcache[:pp.cacheidx]
+		for i := range s {
+			s[i] = obj.Prog{}
+		}
+	}
+	// Clear pp to avoid abuse.
+	*pp = Progs{}
+}
 
-	p = pc
-	pc = Ctxt.NewProg()
-	Clearp(pc)
-	p.Link = pc
+// Prog adds a Prog with instruction As to pp.
+func (pp *Progs) Prog(as obj.As) *obj.Prog {
+	p := pp.next
+	pp.next = pp.NewProg()
+	pp.clearp(pp.next)
+	p.Link = pp.next
 
-	if lineno == 0 && Debug['K'] != 0 {
-		Warn("prog: line 0")
+	if !pp.pos.IsKnown() && Debug['K'] != 0 {
+		Warn("prog: unknown position (line 0)")
 	}
 
 	p.As = as
-	p.Lineno = lineno
+	p.Pos = pp.pos
 	return p
 }
 
-func Clearp(p *obj.Prog) {
+func (pp *Progs) clearp(p *obj.Prog) {
 	obj.Nopout(p)
 	p.As = obj.AEND
-	p.Pc = int64(pcloc)
-	pcloc++
+	p.Pc = pp.pc
+	pp.pc++
 }
 
-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 := Ctxt.NewProg()
-	Clearp(q)
+func (pp *Progs) Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
+	q := pp.NewProg()
+	pp.clearp(q)
 	q.As = as
-	q.Lineno = p.Lineno
+	q.Pos = p.Pos
 	q.From.Type = ftype
 	q.From.Reg = freg
 	q.From.Offset = foffset
@@ -72,33 +139,95 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
 	return q
 }
 
-func AddAsmAfter(as obj.As, p *obj.Prog) *obj.Prog {
-	q := Ctxt.NewProg()
-	Clearp(q)
-	q.As = as
-	q.Link = p.Link
-	p.Link = q
-	return q
+func (pp *Progs) settext(fn *Node) {
+	if pp.Text != nil {
+		Fatalf("Progs.settext called twice")
+	}
+	ptxt := pp.Prog(obj.ATEXT)
+	pp.Text = ptxt
+
+	if fn.Func.lsym == nil {
+		// func _() { }
+		return
+	}
+
+	fn.Func.lsym.Func.Text = ptxt
+	ptxt.From.Type = obj.TYPE_MEM
+	ptxt.From.Name = obj.NAME_EXTERN
+	ptxt.From.Sym = fn.Func.lsym
+
+	p := pp.Prog(obj.AFUNCDATA)
+	Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
+	p.To.Type = obj.TYPE_MEM
+	p.To.Name = obj.NAME_EXTERN
+	p.To.Sym = &fn.Func.lsym.Func.GCArgs
+
+	p = pp.Prog(obj.AFUNCDATA)
+	Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
+	p.To.Type = obj.TYPE_MEM
+	p.To.Name = obj.NAME_EXTERN
+	p.To.Sym = &fn.Func.lsym.Func.GCLocals
+}
+
+func (f *Func) initLSym() {
+	if f.lsym != nil {
+		Fatalf("Func.initLSym called twice")
+	}
+
+	if nam := f.Nname; !isblank(nam) {
+		f.lsym = nam.Sym.Linksym()
+		if f.Pragma&Systemstack != 0 {
+			f.lsym.Set(obj.AttrCFunc, true)
+		}
+	}
+
+	var flag int
+	if f.Dupok() {
+		flag |= obj.DUPOK
+	}
+	if f.Wrapper() {
+		flag |= obj.WRAPPER
+	}
+	if f.NoFramePointer() {
+		flag |= obj.NOFRAME
+	}
+	if f.Needctxt() {
+		flag |= obj.NEEDCTXT
+	}
+	if f.Pragma&Nosplit != 0 {
+		flag |= obj.NOSPLIT
+	}
+	if f.ReflectMethod() {
+		flag |= obj.REFLECTMETHOD
+	}
+
+	// Clumsy but important.
+	// See test/recover.go for test cases and src/reflect/value.go
+	// for the actual functions being considered.
+	if myimportpath == "reflect" {
+		switch f.Nname.Sym.Name {
+		case "callReflect", "callMethod":
+			flag |= obj.WRAPPER
+		}
+	}
+
+	Ctxt.InitTextSym(f.lsym, flag)
 }
 
 func ggloblnod(nam *Node) {
-	s := Linksym(nam.Sym)
-	s.Gotype = Linksym(ngotype(nam))
+	s := nam.Sym.Linksym()
+	s.Gotype = ngotype(nam).Linksym()
 	flags := 0
-	if nam.Name.Readonly {
+	if nam.Name.Readonly() {
 		flags = obj.RODATA
 	}
-	if nam.Type != nil && !haspointers(nam.Type) {
+	if nam.Type != nil && !types.Haspointers(nam.Type) {
 		flags |= obj.NOPTR
 	}
 	Ctxt.Globl(s, nam.Type.Width, flags)
 }
 
-func ggloblsym(s *Sym, width int32, flags int16) {
-	ggloblLSym(Linksym(s), width, flags)
-}
-
-func ggloblLSym(s *obj.LSym, width int32, flags int16) {
+func ggloblsym(s *obj.LSym, width int32, flags int16) {
 	if flags&obj.LOCAL != 0 {
 		s.Set(obj.AttrLocal, true)
 		flags &^= obj.LOCAL
@@ -106,14 +235,7 @@ func ggloblLSym(s *obj.LSym, width int32, flags int16) {
 	Ctxt.Globl(s, int64(width), int(flags))
 }
 
-func gtrack(s *Sym) {
-	p := Gins(obj.AUSEFIELD, nil, nil)
-	p.From.Type = obj.TYPE_MEM
-	p.From.Name = obj.NAME_EXTERN
-	p.From.Sym = Linksym(s)
-}
-
-func isfat(t *Type) bool {
+func isfat(t *types.Type) bool {
 	if t != nil {
 		switch t.Etype {
 		case TSTRUCT, TARRAY, TSLICE, TSTRING,
@@ -125,178 +247,12 @@ func isfat(t *Type) bool {
 	return false
 }
 
-// Naddr rewrites a to refer to n.
-// It assumes that a is zeroed on entry.
-func Naddr(a *obj.Addr, n *Node) {
-	if n == nil {
-		return
-	}
-
-	if n.Op != ONAME {
-		Debug['h'] = 1
-		Dump("naddr", n)
-		Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
-	}
-
-	a.Offset = n.Xoffset
-	s := n.Sym
-	a.Node = n.Orig
-
-	if s == nil {
-		Fatalf("naddr: nil sym %v", n)
-	}
-
-	a.Type = obj.TYPE_MEM
-	switch n.Class {
-	default:
-		Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class)
-
-	case PEXTERN, PFUNC:
-		a.Name = obj.NAME_EXTERN
-
-	case PAUTO:
-		a.Name = obj.NAME_AUTO
-
-	case PPARAM, PPARAMOUT:
-		a.Name = obj.NAME_PARAM
-	}
-
-	a.Sym = Linksym(s)
-}
-
 func Addrconst(a *obj.Addr, v int64) {
 	a.Sym = nil
 	a.Type = obj.TYPE_CONST
 	a.Offset = v
 }
 
-func newplist() *obj.Plist {
-	pl := obj.Linknewplist(Ctxt)
-
-	pc = Ctxt.NewProg()
-	Clearp(pc)
-	pl.Firstpc = pc
-
-	return pl
-}
-
-// 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
-
-	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
-		first := t.Field(0)
-		if first == nil {
-			Fatalf("nodarg: bad struct")
-		}
-		if first.Offset == BADWIDTH {
-			Fatalf("nodarg: offset not computed for %v", t)
-		}
-		n.Xoffset = first.Offset
-		n.Addable = true
-
-	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
-			}
-
-			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
-				}
-			}
-
-			if !isblanksym(expect.Sym) {
-				Fatalf("nodarg: did not find node in dcl list: %v", expect)
-			}
-		}
-
-		// 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
-	}
-
-	// Rewrite argument named _ to __,
-	// or else the assignment to _ will be
-	// discarded during code generation.
-	if isblank(n) {
-		n.Sym = lookup("__")
-	}
-
-	switch fp {
-	default:
-		Fatalf("bad fp")
-
-	case 0: // preparing arguments for call
-		n.Op = OINDREGSP
-		n.Xoffset += Ctxt.FixedFrameSize()
-
-	case 1: // reading arguments inside call
-		n.Class = PPARAM
-		if funarg == FunargResults {
-			n.Class = PPARAMOUT
-		}
-	}
-
-	n.Typecheck = 1
-	n.Addrtaken = true // keep optimizers at bay
-	return n
-}
-
 func Patch(p *obj.Prog, to *obj.Prog) {
 	if p.To.Type != obj.TYPE_BRANCH {
 		Fatalf("patch: not a branch")
@@ -304,18 +260,3 @@ func Patch(p *obj.Prog, to *obj.Prog) {
 	p.To.Val = to
 	p.To.Offset = to.Pc
 }
-
-// Gins inserts instruction as. f is from, t is to.
-func Gins(as obj.As, f, t *Node) *obj.Prog {
-	switch as {
-	case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF, obj.ATYPE,
-		obj.ATEXT, obj.AFUNCDATA, obj.AUSEFIELD:
-	default:
-		Fatalf("unhandled gins op %v", as)
-	}
-
-	p := Prog(as)
-	Naddr(&p.From, f)
-	Naddr(&p.To, t)
-	return p
-}
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index 5693052..93ae241 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -4,48 +4,31 @@
 
 package gc
 
-// a function named init is a special case.
-// it is called by the initialization before
-// main is run. to make it unique within a
-// package and also uncallable, the name,
-// normally "pkg.init", is altered to "pkg.init.1".
-
-var renameinit_initgen int
-
-func renameinit() *Sym {
-	renameinit_initgen++
-	return lookupN("init.", renameinit_initgen)
+import (
+	"cmd/compile/internal/types"
+)
+
+// A function named init is a special case.
+// It is called by the initialization before main is run.
+// To make it unique within a package and also uncallable,
+// the name, normally "pkg.init", is altered to "pkg.init.0".
+var renameinitgen int
+
+func renameinit() *types.Sym {
+	s := lookupN("init.", renameinitgen)
+	renameinitgen++
+	return s
 }
 
-// hand-craft the following initialization code
-//      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)
-//      }
+// anyinit reports whether there any interesting init statements.
 func anyinit(n []*Node) bool {
-	// are there any interesting init statements
 	for _, ln := range n {
 		switch ln.Op {
 		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
-			break
-
-		case OAS, OASWB:
-			if isblank(ln.Left) && candiscard(ln.Right) {
-				break
+		case OAS:
+			if !isblank(ln.Left) || !candiscard(ln.Right) {
+				return true
 			}
-			fallthrough
 		default:
 			return true
 		}
@@ -57,14 +40,12 @@ func anyinit(n []*Node) bool {
 	}
 
 	// is there an explicit init function
-	s := lookup("init.1")
-
-	if s.Def != nil {
+	if renameinitgen > 0 {
 		return true
 	}
 
 	// are there any imported init functions
-	for _, s := range initSyms {
+	for _, s := range types.InitSyms {
 		if s.Def != nil {
 			return true
 		}
@@ -74,7 +55,26 @@ func anyinit(n []*Node) bool {
 	return false
 }
 
+// fninit hand-crafts package initialization code.
+//
+//      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 fninit(n []*Node) {
+	lineno = autogeneratedPos
 	nf := initfix(n)
 	if !anyinit(nf) {
 		return
@@ -84,23 +84,16 @@ func fninit(n []*Node) {
 
 	// (1)
 	gatevar := newname(lookup("initdone·"))
-	addvar(gatevar, Types[TUINT8], PEXTERN)
+	addvar(gatevar, types.Types[TUINT8], PEXTERN)
 
 	// (2)
-	Maxarg = 0
-
-	fn := nod(ODCLFUNC, nil, nil)
 	initsym := lookup("init")
-	fn.Func.Nname = newname(initsym)
-	fn.Func.Nname.Name.Defn = fn
-	fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil)
-	declare(fn.Func.Nname, PFUNC)
-	funchdr(fn)
+	fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
 
 	// (3)
 	a := nod(OIF, nil, nil)
 	a.Left = nod(OGT, gatevar, nodintconst(1))
-	a.Likely = 1
+	a.SetLikely(true)
 	r = append(r, a)
 	// (3a)
 	a.Nbody.Set1(nod(ORETURN, nil, nil))
@@ -110,7 +103,7 @@ func fninit(n []*Node) {
 	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
+	b.SetLikely(true)
 	r = append(r, b)
 	// (4a)
 	b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
@@ -121,10 +114,11 @@ func fninit(n []*Node) {
 	r = append(r, a)
 
 	// (6)
-	for _, s := range initSyms {
+	for _, s := range types.InitSyms {
 		if s.Def != nil && s != initsym {
-			// could check that it is fn of no args/returns
-			a = nod(OCALL, s.Def, nil)
+			n := asNode(s.Def)
+			n.checkInitFuncSignature()
+			a = nod(OCALL, n, nil)
 			r = append(r, a)
 		}
 	}
@@ -133,14 +127,63 @@ func fninit(n []*Node) {
 	r = append(r, nf...)
 
 	// (8)
-	// could check that it is fn of no args/returns
-	for i := 1; ; i++ {
-		s := lookupN("init.", i)
-		if s.Def == nil {
-			break
+
+	// maxInlineInitCalls is the threshold at which we switch
+	// from generating calls inline to generating a static array
+	// of functions and calling them in a loop.
+	// See CL 41500 for more discussion.
+	const maxInlineInitCalls = 500
+
+	if renameinitgen < maxInlineInitCalls {
+		// Not many init functions. Just call them all directly.
+		for i := 0; i < renameinitgen; i++ {
+			s := lookupN("init.", i)
+			n := asNode(s.Def)
+			n.checkInitFuncSignature()
+			a = nod(OCALL, n, nil)
+			r = append(r, a)
 		}
-		a = nod(OCALL, s.Def, nil)
-		r = append(r, a)
+	} else {
+		// Lots of init functions.
+		// Set up an array of functions and loop to call them.
+		// This is faster to compile and similar at runtime.
+
+		// Build type [renameinitgen]func().
+		typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen))
+
+		// Make and fill array.
+		fnarr := staticname(typ)
+		fnarr.Name.SetReadonly(true)
+		for i := 0; i < renameinitgen; i++ {
+			s := lookupN("init.", i)
+			lhs := nod(OINDEX, fnarr, nodintconst(int64(i)))
+			rhs := asNode(s.Def)
+			rhs.checkInitFuncSignature()
+			as := nod(OAS, lhs, rhs)
+			as = typecheck(as, Etop)
+			genAsStatic(as)
+		}
+
+		// Generate a loop that calls each function in turn.
+		// for i := 0; i < renameinitgen; i++ {
+		//   fnarr[i]()
+		// }
+		i := temp(types.Types[TINT])
+		fnidx := nod(OINDEX, fnarr, i)
+		fnidx.SetBounded(true)
+
+		zero := nod(OAS, i, nodintconst(0))
+		cond := nod(OLT, i, nodintconst(int64(renameinitgen)))
+		incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
+		body := nod(OCALL, fnidx, nil)
+
+		loop := nod(OFOR, cond, incr)
+		loop.Nbody.Set1(body)
+		loop.Ninit.Set1(zero)
+
+		loop = typecheck(loop, Etop)
+		loop = walkstmt(loop)
+		r = append(r, loop)
 	}
 
 	// (9)
@@ -163,3 +206,10 @@ func fninit(n []*Node) {
 	Curfn = nil
 	funccompile(fn)
 }
+
+func (n *Node) checkInitFuncSignature() {
+	ft := n.Type.FuncType()
+	if ft.Receiver.Fields().Len()+ft.Params.Fields().Len()+ft.Results.Fields().Len() > 0 {
+		Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 7b2fcf8..dfa13e3 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -11,7 +11,7 @@
 // making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
 // These additional levels (beyond -l) may be buggy and are not supported.
 //      0: disabled
-//      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
+//      1: 80-nodes leaf functions, oneliners, lazy typechecking (default)
 //      2: early typechecking of all imported bodies
 //      3: allow variadic functions
 //      4: allow non-leaf functions , (breaks runtime.Caller)
@@ -27,11 +27,15 @@
 
 package gc
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+	"fmt"
+)
 
 // 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 {
+func fnpkg(fn *Node) *types.Pkg {
 	if fn.IsMethod() {
 		// method
 		rcvr := fn.Type.Recv().Type
@@ -107,7 +111,8 @@ func caninl(fn *Node) {
 		return
 	}
 
-	// If marked "go:cgo_unsafe_args", don't inline
+	// If marked "go:cgo_unsafe_args", don't inline, since the
+	// function makes assumptions about its argument frame layout.
 	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
 		reason = "marked go:cgo_unsafe_args"
 		return
@@ -119,7 +124,7 @@ func caninl(fn *Node) {
 		return
 	}
 
-	if fn.Typecheck == 0 {
+	if fn.Typecheck() == 0 {
 		Fatalf("caninl on non-typechecked function %v", fn)
 	}
 
@@ -127,7 +132,7 @@ func caninl(fn *Node) {
 	if Debug['l'] < 3 {
 		f := fn.Type.Params().Fields()
 		if len := f.Len(); len > 0 {
-			if t := f.Index(len - 1); t.Isddd {
+			if t := f.Index(len - 1); t.Isddd() {
 				reason = "has ... args"
 				return
 			}
@@ -146,11 +151,12 @@ func caninl(fn *Node) {
 	}
 
 	const maxBudget = 80
-	budget := int32(maxBudget) // allowed hairyness
-	if ishairylist(fn.Nbody, &budget, &reason) {
+	visitor := hairyVisitor{budget: maxBudget}
+	if visitor.visitList(fn.Nbody) {
+		reason = visitor.reason
 		return
 	}
-	if budget < 0 {
+	if visitor.budget < 0 {
 		reason = "function too complex"
 		return
 	}
@@ -164,11 +170,11 @@ func caninl(fn *Node) {
 	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
+	n.Func.InlCost = maxBudget - visitor.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.SetNname(n)
+	fn.Type.FuncType().Nname = asTypesNode(n)
 
 	if Debug['m'] > 1 {
 		fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
@@ -179,17 +185,24 @@ func caninl(fn *Node) {
 	Curfn = savefn
 }
 
+// hairyVisitor visits a function body to determine its inlining
+// hairiness and whether or not it can be inlined.
+type hairyVisitor struct {
+	budget int32
+	reason string
+}
+
 // Look for anything we want to punt on.
-func ishairylist(ll Nodes, budget *int32, reason *string) bool {
+func (v *hairyVisitor) visitList(ll Nodes) bool {
 	for _, n := range ll.Slice() {
-		if ishairy(n, budget, reason) {
+		if v.visit(n) {
 			return true
 		}
 	}
 	return false
 }
 
-func ishairy(n *Node, budget *int32, reason *string) bool {
+func (v *hairyVisitor) visit(n *Node) bool {
 	if n == nil {
 		return false
 	}
@@ -197,19 +210,33 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
 	switch n.Op {
 	// Call is okay if inlinable and we have the budget for the body.
 	case OCALLFUNC:
+		if isIntrinsicCall(n) {
+			v.budget--
+			break
+		}
+		// Functions that call runtime.getcaller{pc,sp} can not be inlined
+		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
+		if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
+			fn := n.Left.Sym.Name
+			if fn == "getcallerpc" || fn == "getcallersp" {
+				v.reason = "call to " + fn
+				return true
+			}
+		}
+
 		if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
-			*budget -= fn.InlCost
+			v.budget -= fn.InlCost
 			break
 		}
 
 		if n.isMethodCalledAsFunction() {
-			if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
-				*budget -= d.Func.InlCost
+			if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
+				v.budget -= d.Func.InlCost
 				break
 			}
 		}
 		if Debug['l'] < 4 {
-			*reason = "non-leaf function"
+			v.reason = "non-leaf function"
 			return true
 		}
 
@@ -222,19 +249,19 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
 		if t.Nname() == nil {
 			Fatalf("no function definition for [%p] %+v\n", t, t)
 		}
-		if inlfn := t.Nname().Func; inlfn.Inl.Len() != 0 {
-			*budget -= inlfn.InlCost
+		if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
+			v.budget -= inlfn.InlCost
 			break
 		}
 		if Debug['l'] < 4 {
-			*reason = "non-leaf method"
+			v.reason = "non-leaf method"
 			return true
 		}
 
 	// Things that are too hairy, irrespective of the budget
 	case OCALL, OCALLINTER, OPANIC, ORECOVER:
 		if Debug['l'] < 4 {
-			*reason = "non-leaf op " + n.Op.String()
+			v.reason = "non-leaf op " + n.Op.String()
 			return true
 		}
 
@@ -242,6 +269,7 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
 		OCALLPART,
 		ORANGE,
 		OFOR,
+		OFORUNTIL,
 		OSELECT,
 		OTYPESW,
 		OPROC,
@@ -249,25 +277,30 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
 		ODCLTYPE, // can't print yet
 		OBREAK,
 		ORETJMP:
-		*reason = "unhandled op " + n.Op.String()
+		v.reason = "unhandled op " + n.Op.String()
 		return true
 	}
 
-	(*budget)--
+	v.budget--
 	// TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
 	// See issue 17566 and CL 31674 for discussion.
 	switch n.Op {
 	case OSTRUCTKEY:
-		(*budget)--
+		v.budget--
 	case OSLICE, OSLICEARR, OSLICESTR:
-		(*budget)--
+		v.budget--
 	case OSLICE3, OSLICE3ARR:
-		*budget -= 2
+		v.budget -= 2
 	}
 
-	return *budget < 0 || ishairy(n.Left, budget, reason) || ishairy(n.Right, budget, reason) ||
-		ishairylist(n.List, budget, reason) || ishairylist(n.Rlist, budget, reason) ||
-		ishairylist(n.Ninit, budget, reason) || ishairylist(n.Nbody, budget, reason)
+	if v.budget < 0 {
+		v.reason = "function too complex"
+		return true
+	}
+
+	return v.visit(n.Left) || v.visit(n.Right) ||
+		v.visitList(n.List) || v.visitList(n.Rlist) ||
+		v.visitList(n.Ninit) || v.visitList(n.Nbody)
 }
 
 // Inlcopy and inlcopylist recursively copy the body of a function.
@@ -381,9 +414,9 @@ func inlnode(n *Node) *Node {
 	case ODEFER, OPROC:
 		switch n.Left.Op {
 		case OCALLFUNC, OCALLMETH:
-			n.Left.setNoInline(true)
+			n.Left.SetNoInline(true)
 		}
-		fallthrough
+		return n
 
 	// TODO do them here (or earlier),
 	// so escape analysis can avoid more heapmoves.
@@ -407,7 +440,7 @@ func inlnode(n *Node) *Node {
 
 	n.Right = inlnode(n.Right)
 	if n.Right != nil && n.Right.Op == OINLCALL {
-		if n.Op == OFOR {
+		if n.Op == OFOR || n.Op == OFORUNTIL {
 			inlconv2stmt(n.Right)
 		} else {
 			n.Right = inlconv2expr(n.Right)
@@ -423,14 +456,9 @@ func inlnode(n *Node) *Node {
 			}
 		}
 
-	// if we just replaced arg in f(arg()) or return arg with an inlined call
-	// and arg returns multiple values, glue as list
-	case ORETURN,
-		OCALLFUNC,
-		OCALLMETH,
-		OCALLINTER,
-		OAPPEND,
-		OCOMPLEX:
+	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
+		// if we just replaced arg in f(arg()) or return arg with an inlined call
+		// and arg returns multiple values, glue as list
 		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
 			n.List.Set(inlconv2list(n.List.First()))
 			break
@@ -447,18 +475,12 @@ func inlnode(n *Node) *Node {
 	}
 
 	inlnodelist(n.Rlist)
-	switch n.Op {
-	case OAS2FUNC:
-		if n.Rlist.First().Op == OINLCALL {
-			n.Rlist.Set(inlconv2list(n.Rlist.First()))
-			n.Op = OAS2
-			n.Typecheck = 0
-			n = typecheck(n, Etop)
-			break
-		}
-		fallthrough
-
-	default:
+	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
+		n.Rlist.Set(inlconv2list(n.Rlist.First()))
+		n.Op = OAS2
+		n.SetTypecheck(0)
+		n = typecheck(n, Etop)
+	} else {
 		s := n.Rlist.Slice()
 		for i1, n1 := range s {
 			if n1.Op == OINLCALL {
@@ -483,7 +505,7 @@ func inlnode(n *Node) *Node {
 	// switch at the top of this function.
 	switch n.Op {
 	case OCALLFUNC, OCALLMETH:
-		if n.noInline() {
+		if n.NoInline() {
 			return n
 		}
 	}
@@ -494,9 +516,9 @@ func inlnode(n *Node) *Node {
 			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
 		}
 		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
-			n = mkinlcall(n, n.Left, n.Isddd)
-		} else if n.isMethodCalledAsFunction() && n.Left.Sym.Def != nil {
-			n = mkinlcall(n, n.Left.Sym.Def, n.Isddd)
+			n = mkinlcall(n, n.Left, n.Isddd())
+		} else if n.isMethodCalledAsFunction() && asNode(n.Left.Sym.Def) != nil {
+			n = mkinlcall(n, asNode(n.Left.Sym.Def), n.Isddd())
 		}
 
 	case OCALLMETH:
@@ -513,7 +535,7 @@ func inlnode(n *Node) *Node {
 			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
 		}
 
-		n = mkinlcall(n, n.Left.Type.Nname(), n.Isddd)
+		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), n.Isddd())
 	}
 
 	lineno = lno
@@ -537,11 +559,11 @@ func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
 	return n
 }
 
-func tinlvar(t *Field, inlvars map[*Node]*Node) *Node {
-	if t.Nname != nil && !isblank(t.Nname) {
-		inlvar := inlvars[t.Nname]
+func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
+	if asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
+		inlvar := inlvars[asNode(t.Nname)]
 		if inlvar == nil {
-			Fatalf("missing inlvar for %v\n", t.Nname)
+			Fatalf("missing inlvar for %v\n", asNode(t.Nname))
 		}
 		return inlvar
 	}
@@ -551,227 +573,144 @@ func tinlvar(t *Field, inlvars map[*Node]*Node) *Node {
 
 var inlgen int
 
-// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
+// If n is a call, and fn is a function with an inlinable body,
+// return an OINLCALL.
 // On return ninit has the parameter assignments, the nbody is the
 // inlined function body and list, rlist contain the input, output
 // parameters.
 // 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.Len() == 0 {
+		// No inlinable body.
 		return n
 	}
 
 	if fn == Curfn || fn.Name.Defn == Curfn {
+		// Can't recursively inline a function into itself.
 		return n
 	}
 
-	inlvars := make(map[*Node]*Node)
-
 	if Debug['l'] < 2 {
 		typecheckinl(fn)
 	}
 
-	// Bingo, we have a function node, and it has an inlineable body
+	// 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, fn.Type, fn.Func.Inl)
 	} 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(), n)
 	}
 
 	ninit := n.Ninit
 
-	//dumplist("ninit pre", ninit);
-
+	// Find declarations corresponding to inlineable body.
 	var dcl []*Node
 	if fn.Name.Defn != nil {
-		// local function
-		dcl = fn.Func.Inldcl.Slice()
+		dcl = fn.Func.Inldcl.Slice() // local function
 	} else {
-		// imported function
-		dcl = fn.Func.Dcl
+		dcl = fn.Func.Dcl // imported function
 	}
 
-	var retvars []*Node
-	i := 0
-
-	// Make temp names to use instead of the originals
+	// Make temp names to use instead of the originals.
+	inlvars := make(map[*Node]*Node)
 	for _, ln := range dcl {
-		if ln.Class == PPARAMOUT { // return values handled below.
+		if ln.Op != ONAME {
+			continue
+		}
+		if ln.Class() == PPARAMOUT { // return values handled below.
 			continue
 		}
 		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
 			continue
 		}
-		if ln.Op == ONAME {
-			inlvars[ln] = typecheck(inlvar(ln), Erv)
-			if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM {
-				ninit.Append(nod(ODCL, inlvars[ln], nil))
-			}
+		inlvars[ln] = typecheck(inlvar(ln), Erv)
+		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
+			ninit.Append(nod(ODCL, inlvars[ln], nil))
 		}
 	}
 
 	// temporaries for return values.
-	var m *Node
-	for _, t := range fn.Type.Results().Fields().Slice() {
-		if t != nil && t.Nname != nil && !isblank(t.Nname) {
-			m = inlvar(t.Nname)
+	var retvars []*Node
+	for i, t := range fn.Type.Results().Fields().Slice() {
+		var m *Node
+		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
+			m = inlvar(asNode(t.Nname))
 			m = typecheck(m, Erv)
-			inlvars[t.Nname] = m
+			inlvars[asNode(t.Nname)] = m
 		} else {
 			// anonymous return values, synthesize names for use in assignment that replaces return
 			m = retvar(t, i)
-			i++
 		}
 
 		ninit.Append(nod(ODCL, m, nil))
 		retvars = append(retvars, m)
 	}
 
-	// assign receiver.
-	if fn.IsMethod() && n.Left.Op == ODOTMETH {
-		// method call with a receiver.
-		t := fn.Type.Recv()
-
-		if t != nil && t.Nname != nil && !isblank(t.Nname) && inlvars[t.Nname] == nil {
-			Fatalf("missing inlvar for %v\n", t.Nname)
-		}
-		if n.Left.Left == nil {
-			Fatalf("method call without receiver: %+v", n)
-		}
-		if t == nil {
-			Fatalf("method call unknown receiver type: %+v", n)
-		}
-		as := nod(OAS, tinlvar(t, inlvars), n.Left.Left)
-		if as != nil {
-			as = typecheck(as, Etop)
-			ninit.Append(as)
-		}
-	}
-
-	// check if inlined function is variadic.
-	variadic := false
-
-	var varargtype *Type
-	varargcount := 0
-	for _, t := range fn.Type.Params().Fields().Slice() {
-		if t.Isddd {
-			variadic = true
-			varargtype = t.Type
-		}
-	}
+	// Assign arguments to the parameters' temp names.
+	as := nod(OAS2, nil, nil)
+	as.Rlist.Set(n.List.Slice())
 
-	// but if argument is dotted too forget about variadicity.
-	if variadic && isddd {
-		variadic = false
-	}
+	// For non-dotted calls to variadic functions, we assign the
+	// variadic parameter's temp name separately.
+	var vas *Node
 
-	// check if argument is actually a returned tuple from call.
-	multiret := 0
+	if fn.IsMethod() {
+		rcv := fn.Type.Recv()
 
-	if n.List.Len() == 1 {
-		switch n.List.First().Op {
-		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
-			if n.List.First().Left.Type.Results().NumFields() > 1 {
-				multiret = n.List.First().Left.Type.Results().NumFields() - 1
+		if n.Left.Op == ODOTMETH {
+			// For x.M(...), assign x directly to the
+			// receiver parameter.
+			if n.Left.Left == nil {
+				Fatalf("method call without receiver: %+v", n)
 			}
+			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
+			ras = typecheck(ras, Etop)
+			ninit.Append(ras)
+		} else {
+			// For T.M(...), add the receiver parameter to
+			// as.List, so it's assigned by the normal
+			// arguments.
+			if as.Rlist.Len() == 0 {
+				Fatalf("non-method call to method without first arg: %+v", n)
+			}
+			as.List.Append(tinlvar(rcv, inlvars))
 		}
 	}
 
-	if variadic {
-		varargcount = n.List.Len() + multiret
-		if n.Left.Op != ODOTMETH {
-			varargcount -= fn.Type.Recvs().NumFields()
-		}
-		varargcount -= fn.Type.Params().NumFields() - 1
-	}
-
-	// assign arguments to the parameters' temp names
-	as := nod(OAS2, nil, nil)
-
-	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.IsMethod() && n.Left.Op != ODOTMETH {
-		// non-method call to method
-		if n.List.Len() == 0 {
-			Fatalf("non-method call to method without first arg: %+v", n)
-		}
-
-		// append receiver inlvar to LHS.
-		t := fn.Type.Recv()
-
-		if t != nil && t.Nname != nil && !isblank(t.Nname) && inlvars[t.Nname] == nil {
-			Fatalf("missing inlvar for %v\n", t.Nname)
-		}
-		if t == nil {
-			Fatalf("method call unknown receiver type: %+v", n)
+	for _, param := range fn.Type.Params().Fields().Slice() {
+		// For ordinary parameters or variadic parameters in
+		// dotted calls, just add the variable to the
+		// assignment list, and we're done.
+		if !param.Isddd() || isddd {
+			as.List.Append(tinlvar(param, inlvars))
+			continue
 		}
-		as.List.Append(tinlvar(t, inlvars))
-		li++
-	}
-
-	// append ordinary arguments to LHS.
-	chkargcount := n.List.Len() > 1
-
-	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 := range fn.Type.Params().Fields().Slice() {
-			if variadic && t.Isddd {
-				vararg = tinlvar(t, inlvars)
-				for i = 0; i < varargcount && li < n.List.Len(); i++ {
-					m = argvar(varargtype, i)
-					varargs = append(varargs, m)
-					as.List.Append(m)
-				}
 
-				break
-			}
+		// Otherwise, we need to collect the remaining values
+		// to pass as a slice.
 
-			as.List.Append(tinlvar(t, inlvars))
-		}
-	} else {
-		// match arguments except final variadic (unless the call is dotted itself)
-		t, it := iterFields(fn.Type.Params())
-		for t != nil {
-			if li >= n.List.Len() {
-				break
-			}
-			if variadic && t.Isddd {
-				break
-			}
-			as.List.Append(tinlvar(t, inlvars))
-			t = it.Next()
-			li++
+		numvals := n.List.Len()
+		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
+			numvals = n.List.First().Type.NumFields()
 		}
 
-		// match varargcount arguments with variadic parameters.
-		if variadic && t != nil && t.Isddd {
-			vararg = tinlvar(t, inlvars)
-			var i int
-			for i = 0; i < varargcount && li < n.List.Len(); i++ {
-				m = argvar(varargtype, i)
-				varargs = append(varargs, m)
-				as.List.Append(m)
-				li++
-			}
-
-			if i == varargcount {
-				t = it.Next()
-			}
+		x := as.List.Len()
+		for as.List.Len() < numvals {
+			as.List.Append(argvar(param.Type, as.List.Len()))
 		}
+		varargs := as.List.Slice()[x:]
 
-		if li < n.List.Len() || t != nil {
-			Fatalf("arg count mismatch: %#v vs %.v\n", fn.Type.Params(), n.List)
+		vas = nod(OAS, tinlvar(param, inlvars), nil)
+		if len(varargs) == 0 {
+			vas.Right = nodnil()
+			vas.Right.Type = param.Type
+		} else {
+			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
+			vas.Right.List.Set(varargs)
 		}
 	}
 
@@ -780,27 +719,16 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
 		ninit.Append(as)
 	}
 
-	// turn the variadic args into a slice.
-	if variadic {
-		as = nod(OAS, vararg, nil)
-		if varargcount == 0 {
-			as.Right = nodnil()
-			as.Right.Type = varargtype
-		} else {
-			varslicetype := typSlice(varargtype.Elem())
-			as.Right = nod(OCOMPLIT, nil, typenod(varslicetype))
-			as.Right.List.Set(varargs)
-		}
-
-		as = typecheck(as, Etop)
-		ninit.Append(as)
+	if vas != nil {
+		vas = typecheck(vas, Etop)
+		ninit.Append(vas)
 	}
 
-	// zero the outparams
+	// Zero the return parameters.
 	for _, n := range retvars {
-		as = nod(OAS, n, nil)
-		as = typecheck(as, Etop)
-		ninit.Append(as)
+		ras := nod(OAS, n, nil)
+		ras = typecheck(ras, Etop)
+		ninit.Append(ras)
 	}
 
 	retlabel := autolabel(".i")
@@ -817,7 +745,6 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
 	body := subst.list(fn.Func.Inl)
 
 	lab := nod(OLABEL, retlabel, nil)
-	lab.Used = true // avoid 'not used' when function doesn't have return
 	body = append(body, lab)
 
 	typecheckslice(body, Etop)
@@ -825,19 +752,29 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
 	//dumplist("ninit post", ninit);
 
 	call := nod(OINLCALL, nil, nil)
-
 	call.Ninit.Set(ninit.Slice())
 	call.Nbody.Set(body)
 	call.Rlist.Set(retvars)
 	call.Type = n.Type
-	call.Typecheck = 1
+	call.SetTypecheck(1)
 
-	// Hide the args from setlno -- the parameters to the inlined
+	// Hide the args from setPos -- the parameters to the inlined
 	// call already have good line numbers that should be preserved.
 	args := as.Rlist
 	as.Rlist.Set(nil)
 
-	setlno(call, n.Lineno)
+	// Rewrite the line information for the inlined AST.
+	parent := -1
+	callBase := Ctxt.PosTable.Pos(n.Pos).Base()
+	if callBase != nil {
+		parent = callBase.InliningIndex()
+	}
+	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
+	setpos := &setPos{
+		bases:       make(map[*src.PosBase]*src.PosBase),
+		newInlIndex: newIndex,
+	}
+	setpos.node(call)
 
 	as.Rlist.Set(args.Slice())
 
@@ -878,21 +815,21 @@ func inlvar(var_ *Node) *Node {
 
 	n := newname(var_.Sym)
 	n.Type = var_.Type
-	n.Class = PAUTO
-	n.Used = true
+	n.SetClass(PAUTO)
+	n.Name.SetUsed(true)
 	n.Name.Curfn = Curfn // the calling function, not the called one
-	n.Addrtaken = var_.Addrtaken
+	n.SetAddrtaken(var_.Addrtaken())
 
 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 	return n
 }
 
 // Synthesize a variable to store the inlined function's results in.
-func retvar(t *Field, i int) *Node {
+func retvar(t *types.Field, i int) *Node {
 	n := newname(lookupN("~r", i))
 	n.Type = t.Type
-	n.Class = PAUTO
-	n.Used = true
+	n.SetClass(PAUTO)
+	n.Name.SetUsed(true)
 	n.Name.Curfn = Curfn // the calling function, not the called one
 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 	return n
@@ -900,11 +837,11 @@ func retvar(t *Field, i int) *Node {
 
 // 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 {
+func argvar(t *types.Type, i int) *Node {
 	n := newname(lookupN("~arg", i))
 	n.Type = t.Elem()
-	n.Class = PAUTO
-	n.Used = true
+	n.SetClass(PAUTO)
+	n.Name.SetUsed(true)
 	n.Name.Curfn = Curfn // the calling function, not the called one
 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 	return n
@@ -955,7 +892,12 @@ func (subst *inlsubst) node(n *Node) *Node {
 		return n
 
 	case OLITERAL, OTYPE:
-		return n
+		// If n is a named constant or type, we can continue
+		// using it in the inline copy. Otherwise, make a copy
+		// so we can update the line number.
+		if n.Sym != nil {
+			return n
+		}
 
 		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
 
@@ -993,49 +935,73 @@ func (subst *inlsubst) node(n *Node) *Node {
 		m.Left = newname(lookup(p))
 
 		return m
-	default:
-		m := nod(OXXX, nil, nil)
-		*m = *n
-		m.Ninit.Set(nil)
-
-		if n.Op == OCLOSURE {
-			Fatalf("cannot inline function containing closure: %+v", n)
-		}
+	}
 
-		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))
+	m := nod(OXXX, nil, nil)
+	*m = *n
+	m.Ninit.Set(nil)
 
-		return m
+	if n.Op == OCLOSURE {
+		Fatalf("cannot inline function containing closure: %+v", n)
 	}
+
+	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
 }
 
-// Plaster over linenumbers
-func setlnolist(ll Nodes, lno int32) {
+// setPos is a visitor to update position info with a new inlining index.
+type setPos struct {
+	bases       map[*src.PosBase]*src.PosBase
+	newInlIndex int
+}
+
+func (s *setPos) nodelist(ll Nodes) {
 	for _, n := range ll.Slice() {
-		setlno(n, lno)
+		s.node(n)
 	}
 }
 
-func setlno(n *Node, lno int32) {
+func (s *setPos) node(n *Node) {
 	if n == nil {
 		return
 	}
+	if n.Op == OLITERAL || n.Op == OTYPE {
+		if n.Sym != nil {
+			// This node is not a copy, so don't clobber position.
+			return
+		}
+	}
 
 	// don't clobber names, unless they're freshly synthesized
-	if n.Op != ONAME || n.Lineno == 0 {
-		n.Lineno = lno
+	if n.Op != ONAME || !n.Pos.IsKnown() {
+		n.Pos = s.updatedPos(n)
 	}
 
-	setlno(n.Left, lno)
-	setlno(n.Right, lno)
-	setlnolist(n.List, lno)
-	setlnolist(n.Rlist, lno)
-	setlnolist(n.Ninit, lno)
-	setlnolist(n.Nbody, lno)
+	s.node(n.Left)
+	s.node(n.Right)
+	s.nodelist(n.List)
+	s.nodelist(n.Rlist)
+	s.nodelist(n.Ninit)
+	s.nodelist(n.Nbody)
+}
+
+func (s *setPos) updatedPos(n *Node) src.XPos {
+	pos := Ctxt.PosTable.Pos(n.Pos)
+	oldbase := pos.Base() // can be nil
+	newbase := s.bases[oldbase]
+	if newbase == nil {
+		newbase = src.NewInliningBase(oldbase, s.newInlIndex)
+		pos.SetBase(newbase)
+		s.bases[oldbase] = newbase
+	}
+	pos.SetBase(newbase)
+	return Ctxt.PosTable.XPos(pos)
 }
 
 func (n *Node) isMethodCalledAsFunction() bool {
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 87f9bf2..9d14f53 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -6,17 +6,19 @@ package gc
 
 import (
 	"cmd/compile/internal/syntax"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"fmt"
 	"strings"
 )
 
-// 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
+// lineno is the source position at the start of the most recently lexed token.
+// TODO(gri) rename and eventually remove
+var lineno src.XPos
 
-// lineno is the line number at the start of the most recently lexed token.
-var lineno int32
+func makePos(base *src.PosBase, line, col uint) src.XPos {
+	return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
+}
 
 func isSpace(c rune) bool {
 	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
@@ -38,17 +40,15 @@ func plan9quote(s string) string {
 	return s
 }
 
-type Pragma syntax.Pragma
-
 const (
 	// Func pragmas.
-	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
-	CgoUnsafeArgs         // treat a pointer to one arg as a pointer to them all
-	UintptrEscapes        // pointers converted to uintptr escape
+	Nointerface    syntax.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
+	CgoUnsafeArgs                // treat a pointer to one arg as a pointer to them all
+	UintptrEscapes               // pointers converted to uintptr escape
 
 	// Runtime-only func pragmas.
 	// See ../../../../runtime/README.md for detailed descriptions.
@@ -61,10 +61,10 @@ const (
 	NotInHeap // values of this type must not be heap allocated
 )
 
-func pragmaValue(verb string) Pragma {
+func pragmaValue(verb string) syntax.Pragma {
 	switch verb {
 	case "go:nointerface":
-		if obj.Fieldtrack_enabled != 0 {
+		if objabi.Fieldtrack_enabled != 0 {
 			return Nointerface
 		}
 	case "go:noescape":
@@ -76,24 +76,12 @@ func pragmaValue(verb string) Pragma {
 	case "go:noinline":
 		return Noinline
 	case "go:systemstack":
-		if !compiling_runtime {
-			yyerror("//go:systemstack only allowed in runtime")
-		}
 		return Systemstack
 	case "go:nowritebarrier":
-		if !compiling_runtime {
-			yyerror("//go:nowritebarrier only allowed in runtime")
-		}
 		return Nowritebarrier
 	case "go:nowritebarrierrec":
-		if !compiling_runtime {
-			yyerror("//go:nowritebarrierrec only allowed in runtime")
-		}
 		return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
 	case "go:yeswritebarrierrec":
-		if !compiling_runtime {
-			yyerror("//go:yeswritebarrierrec only allowed in runtime")
-		}
 		return Yeswritebarrierrec
 	case "go:cgo_unsafe_args":
 		return CgoUnsafeArgs
@@ -116,18 +104,8 @@ func pragmaValue(verb string) Pragma {
 	return 0
 }
 
-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
-	}
-	return s
-}
-
-func pragcgo(text string) string {
+// pragcgo is called concurrently if files are parsed concurrently.
+func (p *noder) pragcgo(pos src.Pos, text string) string {
 	f := pragmaFields(text)
 
 	verb := f[0][3:] // skip "go:"
@@ -144,7 +122,7 @@ func pragcgo(text string) string {
 			return fmt.Sprintln(verb, local, remote)
 
 		default:
-			yyerror(`usage: //go:%s local [remote]`, verb)
+			p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)})
 		}
 	case "cgo_import_dynamic":
 		switch {
@@ -164,7 +142,7 @@ func pragcgo(text string) string {
 			return fmt.Sprintln(verb, local, remote, library)
 
 		default:
-			yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
+			p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
 		}
 	case "cgo_import_static":
 		switch {
@@ -173,7 +151,7 @@ func pragcgo(text string) string {
 			return fmt.Sprintln(verb, local)
 
 		default:
-			yyerror(`usage: //go:cgo_import_static local`)
+			p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`})
 		}
 	case "cgo_dynamic_linker":
 		switch {
@@ -182,7 +160,7 @@ func pragcgo(text string) string {
 			return fmt.Sprintln(verb, path)
 
 		default:
-			yyerror(`usage: //go:cgo_dynamic_linker "path"`)
+			p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`})
 		}
 	case "cgo_ldflag":
 		switch {
@@ -191,7 +169,7 @@ func pragcgo(text string) string {
 			return fmt.Sprintln(verb, arg)
 
 		default:
-			yyerror(`usage: //go:cgo_ldflag "arg"`)
+			p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`})
 		}
 	}
 	return ""
diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go
index 9230b30..a56f396 100644
--- a/src/cmd/compile/internal/gc/lex_test.go
+++ b/src/cmd/compile/internal/gc/lex_test.go
@@ -4,7 +4,10 @@
 
 package gc
 
-import "testing"
+import (
+	"cmd/internal/src"
+	"testing"
+)
 
 func eq(a, b []string) bool {
 	if len(a) != len(b) {
@@ -69,8 +72,9 @@ func TestPragcgo(t *testing.T) {
 		{`go:cgo_ldflag "a rg"`, "cgo_ldflag 'a rg'\n"},
 	}
 
+	var p noder
 	for _, tt := range tests {
-		got := pragcgo(tt.in)
+		got := p.pragcgo(src.NoPos, 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/magic.go b/src/cmd/compile/internal/gc/magic.go
deleted file mode 100644
index 4da30c4..0000000
--- a/src/cmd/compile/internal/gc/magic.go
+++ /dev/null
@@ -1,220 +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
-
-// 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
index 1690944..87d8440 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -10,11 +10,15 @@ import (
 	"bufio"
 	"bytes"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"cmd/internal/sys"
 	"flag"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
 	"os"
 	"path"
@@ -30,38 +34,59 @@ var (
 )
 
 var (
-	Debug_append   int
-	Debug_closure  int
-	debug_dclstack int
-	Debug_panic    int
-	Debug_slice    int
-	Debug_wb       int
+	Debug_append       int
+	Debug_asm          bool
+	Debug_closure      int
+	Debug_compilelater int
+	debug_dclstack     int
+	Debug_panic        int
+	Debug_slice        int
+	Debug_vlog         bool
+	Debug_wb           int
+	Debug_pctab        string
 )
 
 // 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.
+// to set the debug_checknil variable.
+// Multiple options can be comma-separated.
+// Each option accepts an optional argument, as in "gcprog=2"
 var debugtab = []struct {
 	name string
-	val  *int
+	help string
+	val  interface{} // must be *int or *string
 }{
-	{"append", &Debug_append},         // print information about append compilation
-	{"closure", &Debug_closure},       // print information about closure compilation
-	{"disablenil", &disable_checknil}, // disable nil checks
-	{"dclstack", &debug_dclstack},     // run internal dclstack 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
+	{"append", "print information about append compilation", &Debug_append},
+	{"closure", "print information about closure compilation", &Debug_closure},
+	{"compilelater", "compile functions as late as possible", &Debug_compilelater},
+	{"disablenil", "disable nil checks", &disable_checknil},
+	{"dclstack", "run internal dclstack check", &debug_dclstack},
+	{"gcprog", "print dump of GC programs", &Debug_gcprog},
+	{"nil", "print information about nil checks", &Debug_checknil},
+	{"panic", "do not hide any compiler panic", &Debug_panic},
+	{"slice", "print information about slice compilation", &Debug_slice},
+	{"typeassert", "print information about type assertion inlining", &Debug_typeassert},
+	{"wb", "print information about write barriers", &Debug_wb},
+	{"export", "print export data", &Debug_export},
+	{"pctab", "print named pc-value table", &Debug_pctab},
 }
 
+const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
+
+<key> is one of:
+
+`
+
+const debugHelpFooter = `
+<value> is key-specific.
+
+Key "pctab" supports values:
+	"pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
+`
+
 func usage() {
 	fmt.Printf("usage: compile [options] file.go...\n")
-	obj.Flagprint(1)
+	objabi.Flagprint(1)
 	Exit(2)
 }
 
@@ -78,7 +103,7 @@ func hidePanic() {
 }
 
 func doversion() {
-	p := obj.Expstring()
+	p := objabi.Expstring()
 	if p == "X:none" {
 		p = ""
 	}
@@ -86,7 +111,7 @@ func doversion() {
 	if p != "" {
 		sep = " "
 	}
-	fmt.Printf("compile version %s%s%s\n", obj.Version, sep, p)
+	fmt.Printf("compile version %s%s%s\n", objabi.Version, sep, p)
 	os.Exit(0)
 }
 
@@ -103,137 +128,176 @@ var benchfile string
 // Main parses flags and Go source files specified in the command-line
 // arguments, type-checks the parsed Go package, compiles functions to machine
 // code, and finally writes the compiled package definition to disk.
-func Main() {
+func Main(archInit func(*Arch)) {
 	timings.Start("fe", "init")
 
 	defer hidePanic()
 
-	Ctxt = obj.Linknew(Thearch.LinkArch)
+	archInit(&thearch)
+
+	Ctxt = obj.Linknew(thearch.LinkArch)
 	Ctxt.DiagFunc = yyerror
 	Ctxt.Bso = bufio.NewWriter(os.Stdout)
 
-	localpkg = mkpkg("")
+	localpkg = types.NewPkg("", "")
 	localpkg.Prefix = "\"\""
 
 	// pseudo-package, for scoping
-	builtinpkg = mkpkg("go.builtin")
-	builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
+	builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
+	builtinpkg.Prefix = "go.builtin"            // not go%2ebuiltin
 
 	// pseudo-package, accessed by import "unsafe"
-	unsafepkg = mkpkg("unsafe")
-	unsafepkg.Name = "unsafe"
+	unsafepkg = types.NewPkg("unsafe", "unsafe")
 
-	// real package, referred to by generated runtime calls
-	Runtimepkg = mkpkg("runtime")
-	Runtimepkg.Name = "runtime"
+	// Pseudo-package that contains the compiler's builtin
+	// declarations for package runtime. These are declared in a
+	// separate package to avoid conflicts with package runtime's
+	// actual declarations, which may differ intentionally but
+	// insignificantly.
+	Runtimepkg = types.NewPkg("go.runtime", "runtime")
+	Runtimepkg.Prefix = "runtime"
 
 	// pseudo-packages used in symbol tables
-	itabpkg = mkpkg("go.itab")
-	itabpkg.Name = "go.itab"
+	itabpkg = types.NewPkg("go.itab", "go.itab")
 	itabpkg.Prefix = "go.itab" // not go%2eitab
 
-	itablinkpkg = mkpkg("go.itablink")
-	itablinkpkg.Name = "go.itablink"
+	itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
 	itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
 
-	trackpkg = mkpkg("go.track")
-	trackpkg.Name = "go.track"
+	trackpkg = types.NewPkg("go.track", "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 = types.NewPkg("go.map", "go.map")
 	mappkg.Prefix = "go.map"
 
-	Nacl = obj.GOOS == "nacl"
-	if Nacl {
-		flag_largemodel = true
-	}
+	Nacl = objabi.GOOS == "nacl"
 
 	flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
-	obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
-	obj.Flagcount("B", "disable bounds checking", &Debug['B'])
+	flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
+	objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
+	objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
+	objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
 	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("N", "disable optimizations", &Debug['N'])
-	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'])
+	objabi.Flagcount("E", "debug symbol export", &Debug['E'])
+	objabi.Flagfn1("I", "add `directory` to import search path", addidir)
+	objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
+	objabi.Flagcount("N", "disable optimizations", &Debug['N'])
+	flag.BoolVar(&Debug_asm, "S", false, "print assembly listing")
+	objabi.Flagfn0("V", "print compiler version", doversion)
+	objabi.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.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
 	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("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(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
+	flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols")
+	objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
+	objabi.Flagcount("f", "debug stack frames", &Debug['f'])
+	objabi.Flagcount("h", "halt on error", &Debug['h'])
+	objabi.Flagcount("i", "debug line number stack", &Debug['i'])
+	objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
+	objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
 	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'])
+	objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
+	objabi.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'])
+	objabi.Flagcount("live", "debug liveness analysis", &debuglive)
+	objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
 	flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
+	flag.BoolVar(&dolinkobj, "dolinkobj", true, "generate linker-specific objects; if false, some invalid code may compile")
 	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'])
+	objabi.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")
+	objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
+	flag.StringVar(&pathPrefix, "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(&Debug_vlog, "v", false, "increase debug verbosity")
+	objabi.Flagcount("w", "debug type checking", &Debug['w'])
 	flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
 	var flag_shared bool
 	var flag_dynlink bool
-	if supportsDynlink(Thearch.LinkArch.Arch) {
+	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`")
+	var goversion string
+	flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
 	flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
+	flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
+	flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
 	flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
-	obj.Flagparse(usage)
+	objabi.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'])
+	Ctxt.Debugasm = Debug_asm
+	Ctxt.Debugvlog = Debug_vlog
+	if flagDWARF {
+		Ctxt.DebugInfo = debuginfo
+	}
 
-	if flag.NArg() < 1 {
+	if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
 		usage()
 	}
 
+	if goversion != "" && goversion != runtime.Version() {
+		fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
+		Exit(2)
+	}
+
+	thearch.LinkArch.Init(Ctxt)
+
+	if outfile == "" {
+		p := flag.Arg(0)
+		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
+	}
+
 	startProfile()
 
 	if flag_race {
-		racepkg = mkpkg("runtime/race")
-		racepkg.Name = "race"
+		racepkg = types.NewPkg("runtime/race", "race")
 	}
 	if flag_msan {
-		msanpkg = mkpkg("runtime/msan")
-		msanpkg.Name = "msan"
+		msanpkg = types.NewPkg("runtime/msan", "msan")
 	}
 	if flag_race && flag_msan {
 		log.Fatal("cannot use both -race and -msan")
 	} else if flag_race || flag_msan {
 		instrumenting = true
 	}
+	if compiling_runtime && Debug['N'] != 0 {
+		log.Fatal("cannot disable optimizations while compiling runtime")
+	}
+	if nBackendWorkers < 1 {
+		log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
+	}
+	if nBackendWorkers > 1 && !concurrentBackendAllowed() {
+		log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
+	}
 
 	// parse -d argument
 	if debugstr != "" {
@@ -242,26 +306,50 @@ func Main() {
 			if name == "" {
 				continue
 			}
-			val := 1
-			valstring := ""
-			if i := strings.Index(name, "="); i >= 0 {
+			// display help about the -d option itself and quit
+			if name == "help" {
+				fmt.Printf(debugHelpHeader)
+				maxLen := len("ssa/help")
+				for _, t := range debugtab {
+					if len(t.name) > maxLen {
+						maxLen = len(t.name)
+					}
+				}
+				for _, t := range debugtab {
+					fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
+				}
+				// ssa options have their own help
+				fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
+				fmt.Printf(debugHelpFooter)
+				os.Exit(0)
+			}
+			val, valstring, haveInt := 1, "", true
+			if i := strings.IndexAny(name, "=:"); i >= 0 {
 				var err error
-				val, err = strconv.Atoi(name[i+1:])
+				name, valstring = name[:i], name[i+1:]
+				val, err = strconv.Atoi(valstring)
 				if err != nil {
-					log.Fatalf("invalid debug value %v", name)
+					val, haveInt = 1, false
 				}
-				name = name[:i]
-			} else if i := strings.Index(name, ":"); i >= 0 {
-				valstring = name[i+1:]
-				name = name[:i]
 			}
 			for _, t := range debugtab {
-				if t.name == name {
-					if t.val != nil {
-						*t.val = val
-						continue Split
+				if t.name != name {
+					continue
+				}
+				switch vp := t.val.(type) {
+				case nil:
+					// Ignore
+				case *string:
+					*vp = valstring
+				case *int:
+					if !haveInt {
+						log.Fatalf("invalid debug value %v", name)
 					}
+					*vp = val
+				default:
+					panic("bad debugtab type")
 				}
+				continue Split
 			}
 			// special case for ssa for now
 			if strings.HasPrefix(name, "ssa/") {
@@ -284,6 +372,9 @@ func Main() {
 		}
 	}
 
+	// set via a -d flag
+	Ctxt.Debugpcln = Debug_pctab
+
 	// enable inlining.  for now:
 	//	default: inlining on.  (debug['l'] == 1)
 	//	-l: inlining off  (debug['l'] == 0)
@@ -292,42 +383,52 @@ func Main() {
 		Debug['l'] = 1 - Debug['l']
 	}
 
-	Widthint = Thearch.LinkArch.IntSize
-	Widthptr = Thearch.LinkArch.PtrSize
-	Widthreg = Thearch.LinkArch.RegSize
+	trackScopes = flagDWARF && Debug['l'] == 0 && Debug['N'] != 0
+
+	Widthptr = thearch.LinkArch.PtrSize
+	Widthreg = thearch.LinkArch.RegSize
+
+	// initialize types package
+	// (we need to do this to break dependencies that otherwise
+	// would lead to import cycles)
+	types.Widthptr = Widthptr
+	types.Dowidth = dowidth
+	types.Fatalf = Fatalf
+	types.Sconv = func(s *types.Sym, flag, mode int) string {
+		return sconv(s, FmtFlag(flag), fmtMode(mode))
+	}
+	types.Tconv = func(t *types.Type, flag, mode, depth int) string {
+		return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
+	}
+	types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
+		symFormat(sym, s, verb, fmtMode(mode))
+	}
+	types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
+		typeFormat(t, s, verb, fmtMode(mode))
+	}
+	types.TypeLinkSym = func(t *types.Type) *obj.LSym {
+		return typenamesym(t).Linksym()
+	}
+	types.FmtLeft = int(FmtLeft)
+	types.FmtUnsigned = int(FmtUnsigned)
+	types.FErr = FErr
+	types.Ctxt = Ctxt
 
 	initUniverse()
 
-	blockgen = 1
 	dclcontext = PEXTERN
 	nerrors = 0
-	lexlineno = 1
+
+	autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
 
 	timings.Start("fe", "loadsys")
 	loadsys()
 
 	timings.Start("fe", "parse")
-	lexlineno0 := lexlineno
-	for _, infile = range flag.Args() {
-		linehistpush(infile)
-		block = 1
-		iota_ = -1000000
-		imported_unsafe = false
-		parseFile(infile)
-		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()
-	}
+	lines := parseFiles(flag.Args())
 	timings.Stop()
-	timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
+	timings.AddEvent(int64(lines), "lines")
 
-	mkpackage(localpkg.Name) // final import not used checks
 	finishUniverse()
 
 	typecheckok = true
@@ -340,13 +441,16 @@ func Main() {
 	// 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.
+	//   We also defer type alias declarations until phase 2
+	//   to avoid cycles like #18640.
 	defercheckwidth()
 
 	// Don't use range--typecheck can add closures to xtop.
 	timings.Start("fe", "typecheck", "top1")
 	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)
+		n := xtop[i]
+		if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+			xtop[i] = typecheck(n, Etop)
 		}
 	}
 
@@ -356,8 +460,9 @@ func Main() {
 	// Don't use range--typecheck can add closures to xtop.
 	timings.Start("fe", "typecheck", "top2")
 	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)
+		n := xtop[i]
+		if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+			xtop[i] = typecheck(n, Etop)
 		}
 	}
 	resumecheckwidth()
@@ -367,8 +472,9 @@ func Main() {
 	timings.Start("fe", "typecheck", "func")
 	var fcount int64
 	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
-			Curfn = xtop[i]
+		n := xtop[i]
+		if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
+			Curfn = n
 			decldepth = 1
 			saveerrors()
 			typecheckslice(Curfn.Nbody.Slice(), Etop)
@@ -376,6 +482,9 @@ func Main() {
 			if nerrors != 0 {
 				Curfn.Nbody.Set(nil) // type errors; do not compile
 			}
+			// Now that we've checked whether n terminates,
+			// we can eliminate some obviously dead code.
+			deadcode(Curfn)
 			fcount++
 		}
 	}
@@ -391,6 +500,7 @@ func Main() {
 			capturevars(n)
 		}
 	}
+	capturevarscomplete = true
 
 	Curfn = nil
 
@@ -442,37 +552,66 @@ func Main() {
 	timings.Start("fe", "escapes")
 	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.
-	timings.Start("fe", "xclosures")
-	for _, n := range xtop {
-		if n.Op == ODCLFUNC && n.Func.Closure != nil {
-			Curfn = n
-			transformclosure(n)
+	if dolinkobj {
+		// 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.
+		timings.Start("fe", "xclosures")
+		for _, n := range xtop {
+			if n.Op == ODCLFUNC && n.Func.Closure != nil {
+				Curfn = n
+				transformclosure(n)
+			}
 		}
-	}
 
-	Curfn = nil
+		// Prepare for SSA compilation.
+		// This must be before peekitabs, because peekitabs
+		// can trigger function compilation.
+		initssaconfig()
+
+		// Just before compilation, compile itabs found on
+		// the right side of OCONVIFACE so that methods
+		// can be de-virtualized during compilation.
+		Curfn = nil
+		peekitabs()
+
+		// Phase 8: Compile top level functions.
+		// Don't use range--walk can add functions to xtop.
+		timings.Start("be", "compilefuncs")
+		fcount = 0
+		for i := 0; i < len(xtop); i++ {
+			n := xtop[i]
+			if n.Op == ODCLFUNC {
+				funccompile(n)
+				fcount++
+			}
+		}
+		timings.AddEvent(fcount, "funcs")
 
-	// Phase 8: Compile top level functions.
-	// Don't use range--walk can add functions to xtop.
-	timings.Start("be", "compilefuncs")
-	fcount = 0
-	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op == ODCLFUNC {
-			funccompile(xtop[i])
-			fcount++
+		if nsavederrors+nerrors == 0 {
+			fninit(xtop)
 		}
-	}
-	timings.AddEvent(fcount, "funcs")
 
-	if nsavederrors+nerrors == 0 {
-		fninit(xtop)
-	}
+		compileFunctions()
+
+		// We autogenerate and compile some small functions
+		// such as method wrappers and equality/hash routines
+		// while exporting code.
+		// Disable concurrent compilation from here on,
+		// at least until this convoluted structure has been unwound.
+		nBackendWorkers = 1
 
-	if compiling_runtime {
-		checknowritebarrierrec()
+		if compiling_runtime {
+			checknowritebarrierrec()
+		}
+
+		// Check whether any of the functions we have compiled have gigantic stack frames.
+		obj.SortSlice(largeStackFrames, func(i, j int) bool {
+			return largeStackFrames[i].Before(largeStackFrames[j])
+		})
+		for _, largePos := range largeStackFrames {
+			yyerrorl(largePos, "stack frame too large (>2GB)")
+		}
 	}
 
 	// Phase 9: Check external declarations.
@@ -494,6 +633,10 @@ func Main() {
 		dumpasmhdr()
 	}
 
+	if len(compilequeue) != 0 {
+		Fatalf("%d uncompiled functions", len(compilequeue))
+	}
+
 	if nerrors+nsavederrors != 0 {
 		errorexit()
 	}
@@ -515,7 +658,7 @@ func writebench(filename string) error {
 	}
 
 	var buf bytes.Buffer
-	fmt.Fprintln(&buf, "commit:", obj.Version)
+	fmt.Fprintln(&buf, "commit:", objabi.Version)
 	fmt.Fprintln(&buf, "goos:", runtime.GOOS)
 	fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
 	timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
@@ -531,7 +674,10 @@ func writebench(filename string) error {
 	return f.Close()
 }
 
-var importMap = map[string]string{}
+var (
+	importMap   = map[string]string{}
+	packageFile map[string]string // nil means not in use
+)
 
 func addImportMap(s string) {
 	if strings.Count(s, "=") != 1 {
@@ -545,6 +691,47 @@ func addImportMap(s string) {
 	importMap[source] = actual
 }
 
+func readImportCfg(file string) {
+	packageFile = map[string]string{}
+	data, err := ioutil.ReadFile(file)
+	if err != nil {
+		log.Fatalf("-importcfg: %v", err)
+	}
+
+	for lineNum, line := range strings.Split(string(data), "\n") {
+		lineNum++ // 1-based
+		line = strings.TrimSpace(line)
+		if line == "" || strings.HasPrefix(line, "#") {
+			continue
+		}
+
+		var verb, args string
+		if i := strings.Index(line, " "); i < 0 {
+			verb = line
+		} else {
+			verb, args = line[:i], strings.TrimSpace(line[i+1:])
+		}
+		var before, after string
+		if i := strings.Index(args, "="); i >= 0 {
+			before, after = args[:i], args[i+1:]
+		}
+		switch verb {
+		default:
+			log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
+		case "importmap":
+			if before == "" || after == "" {
+				log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
+			}
+			importMap[before] = after
+		case "packagefile":
+			if before == "" || after == "" {
+				log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
+			}
+			packageFile[before] = after
+		}
+	}
+}
+
 func saveerrors() {
 	nsavederrors += nerrors
 	nerrors = 0
@@ -564,21 +751,6 @@ func arsize(b *bufio.Reader, name string) int {
 	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) {
@@ -605,6 +777,11 @@ func findpkg(name string) (file string, ok bool) {
 			return "", false
 		}
 
+		if packageFile != nil {
+			file, ok = packageFile[name]
+			return file, ok
+		}
+
 		// 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.
@@ -627,6 +804,11 @@ func findpkg(name string) (file string, ok bool) {
 		return "", false
 	}
 
+	if packageFile != nil {
+		file, ok = packageFile[name]
+		return file, ok
+	}
+
 	for _, dir := range idirs {
 		file = fmt.Sprintf("%s/%s.a", dir, name)
 		if _, err := os.Stat(file); err == nil {
@@ -638,7 +820,7 @@ func findpkg(name string) (file string, ok bool) {
 		}
 	}
 
-	if obj.GOROOT != "" {
+	if objabi.GOROOT != "" {
 		suffix := ""
 		suffixsep := ""
 		if flag_installsuffix != "" {
@@ -652,11 +834,11 @@ func findpkg(name string) (file string, ok bool) {
 			suffix = "msan"
 		}
 
-		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.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", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
 		if _, err := os.Stat(file); err == nil {
 			return file, true
 		}
@@ -669,25 +851,24 @@ func findpkg(name string) (file string, ok bool) {
 // so that the compiler can generate calls to them,
 // but does not make them visible to user code.
 func loadsys() {
-	block = 1
-	iota_ = -1000000
+	types.Block = 1
 
-	importpkg = Runtimepkg
+	inimport = true
 	typecheckok = true
 	defercheckwidth()
 
 	typs := runtimeTypes()
 	for _, d := range runtimeDecls {
-		sym := Pkglookup(d.name, importpkg)
+		sym := Runtimepkg.Lookup(d.name)
 		typ := typs[d.typ]
 		switch d.tag {
 		case funcTag:
-			importsym(sym, ONAME)
+			importsym(Runtimepkg, sym, ONAME)
 			n := newfuncname(sym)
 			n.Type = typ
 			declare(n, PFUNC)
 		case varTag:
-			importvar(sym, typ)
+			importvar(Runtimepkg, sym, typ)
 		default:
 			Fatalf("unhandled declaration tag %v", d.tag)
 		}
@@ -695,27 +876,23 @@ func loadsys() {
 
 	typecheckok = false
 	resumecheckwidth()
-	importpkg = nil
+	inimport = false
 }
 
-func importfile(f *Val, indent []byte) {
-	if importpkg != nil {
-		Fatalf("importpkg not nil")
-	}
-
+func importfile(f *Val) *types.Pkg {
 	path_, ok := f.U.(string)
 	if !ok {
-		yyerror("import statement not a string")
-		return
+		yyerror("import path must be a string")
+		return nil
 	}
 
 	if len(path_) == 0 {
 		yyerror("import path is empty")
-		return
+		return nil
 	}
 
 	if isbadimport(path_) {
-		return
+		return nil
 	}
 
 	// The package name main is no longer reserved,
@@ -742,15 +919,14 @@ func importfile(f *Val, indent []byte) {
 			errorexit()
 		}
 
-		importpkg = unsafepkg
 		imported_unsafe = true
-		return
+		return unsafepkg
 	}
 
 	if islocalname(path_) {
 		if path_[0] == '/' {
 			yyerror("import path cannot be absolute path")
-			return
+			return nil
 		}
 
 		prefix := Ctxt.Pathname
@@ -760,7 +936,7 @@ func importfile(f *Val, indent []byte) {
 		path_ = path.Join(prefix, path_)
 
 		if isbadimport(path_) {
-			return
+			return nil
 		}
 	}
 
@@ -770,10 +946,9 @@ func importfile(f *Val, indent []byte) {
 		errorexit()
 	}
 
-	importpkg = mkpkg(path_)
-
+	importpkg := types.NewPkg(path_, "")
 	if importpkg.Imported {
-		return
+		return importpkg
 	}
 
 	importpkg.Imported = true
@@ -786,13 +961,6 @@ func importfile(f *Val, indent []byte) {
 	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 {
@@ -802,13 +970,29 @@ func importfile(f *Val, indent []byte) {
 		p = p[:len(p)-1]
 	}
 
+	if p == "!<arch>" { // package archive
+		// package export block should be first
+		sz := arsize(imp, "__.PKGDEF")
+		if sz <= 0 {
+			yyerror("import %s: not a package file", file)
+			errorexit()
+		}
+		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.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
+		q := fmt.Sprintf("%s %s %s %s", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
 		if p[10:] != q {
 			yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
 			errorexit()
@@ -834,9 +1018,14 @@ func importfile(f *Val, indent []byte) {
 		yyerror("cannot import unsafe package %q", importpkg.Path)
 	}
 
-	// assume files move (get installed)
-	// so don't record the full path.
-	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
+	// assume files move (get installed) so don't record the full path
+	if packageFile != nil {
+		// If using a packageFile map, assume path_ can be recorded directly.
+		Ctxt.AddImport(path_)
+	} else {
+		// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
+		Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
+	}
 
 	// In the importfile, if we find:
 	// $$\n  (textual format): not supported anymore
@@ -865,21 +1054,24 @@ func importfile(f *Val, indent []byte) {
 	switch c {
 	case '\n':
 		yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
+		return nil
 
 	case 'B':
 		if Debug_export != 0 {
 			fmt.Printf("importing %s (%s)\n", path_, file)
 		}
 		imp.ReadByte() // skip \n after $$B
-		Import(imp)
+		Import(importpkg, imp)
 
 	default:
 		yyerror("no import in %q", path_)
 		errorexit()
 	}
+
+	return importpkg
 }
 
-func pkgnotused(lineno int32, path string, name string) {
+func pkgnotused(lineno src.XPos, 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
@@ -907,54 +1099,89 @@ func mkpackage(pkgname string) {
 		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 && s.Flags&SymAlias == 0 {
-				// 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
-			}
-		}
+func clearImports() {
+	type importedPkg struct {
+		pos  src.XPos
+		path string
+		name string
 	}
+	var unused []importedPkg
 
-	if outfile == "" {
-		p := infile
-		if i := strings.LastIndex(p, "/"); i >= 0 {
-			p = p[i+1:]
+	for _, s := range localpkg.Syms {
+		n := asNode(s.Def)
+		if n == nil {
+			continue
 		}
-		if runtime.GOOS == "windows" {
-			if i := strings.LastIndex(p, `\`); i >= 0 {
-				p = p[i+1:]
+		if n.Op == OPACK {
+			// throw away top-level package name left over
+			// from previous file.
+			// leave s->block set to cause redeclaration
+			// errors if a conflicting top-level name is
+			// introduced by a different file.
+			if !n.Name.Used() && nsyntaxerrors == 0 {
+				unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
 			}
+			s.Def = nil
+			continue
 		}
-		if i := strings.LastIndex(p, "."); i >= 0 {
-			p = p[:i]
+		if IsAlias(s) {
+			// throw away top-level name left over
+			// from previous import . "x"
+			if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
+				unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
+				n.Name.Pack.Name.SetUsed(true)
+			}
+			s.Def = nil
+			continue
 		}
-		suffix := ".o"
-		if writearchive {
-			suffix = ".a"
+	}
+
+	obj.SortSlice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
+	for _, pkg := range unused {
+		pkgnotused(pkg.pos, pkg.path, pkg.name)
+	}
+}
+
+func IsAlias(sym *types.Sym) bool {
+	return sym.Def != nil && asNode(sym.Def).Sym != sym
+}
+
+// By default, assume any debug flags are incompatible with concurrent compilation.
+// A few are safe and potentially in common use for normal compiles, though; mark them as such here.
+var concurrentFlagOK = [256]bool{
+	'B': true, // disabled bounds checking
+	'C': true, // disable printing of columns in error messages
+	'e': true, // no limit on errors; errors all come from non-concurrent code
+	'I': true, // add `directory` to import search path
+	'N': true, // disable optimizations
+	'l': true, // disable inlining
+	'w': true, // all printing happens before compilation
+	'W': true, // all printing happens before compilation
+}
+
+func concurrentBackendAllowed() bool {
+	for i, x := range Debug {
+		if x != 0 && !concurrentFlagOK[i] {
+			return false
 		}
-		outfile = p + suffix
 	}
+	// Debug_asm by itself is ok, because all printing occurs
+	// while writing the object file, and that is non-concurrent.
+	// Adding Debug_vlog, however, causes Debug_asm to also print
+	// while flushing the plist, which happens concurrently.
+	if Debug_vlog || debugstr != "" || debuglive > 0 {
+		return false
+	}
+	// TODO: test and add builders for GOEXPERIMENT values, and enable
+	if os.Getenv("GOEXPERIMENT") != "" {
+		return false
+	}
+	// TODO: fix races and enable the following flags
+	if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
+		return false
+	}
+	return true
 }
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
index 995f5be..63d2a12 100644
--- a/src/cmd/compile/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -31,9 +31,11 @@ func main() {
 	flag.Parse()
 
 	var b bytes.Buffer
-	fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
+	fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
 	fmt.Fprintln(&b)
 	fmt.Fprintln(&b, "package gc")
+	fmt.Fprintln(&b)
+	fmt.Fprintln(&b, `import "cmd/compile/internal/types"`)
 
 	mkbuiltin(&b, "runtime")
 
@@ -72,6 +74,12 @@ func mkbuiltin(w io.Writer, name string) {
 			}
 			fmt.Fprintf(w, "{%q, funcTag, %d},\n", decl.Name.Name, interner.intern(decl.Type))
 		case *ast.GenDecl:
+			if decl.Tok == token.IMPORT {
+				if len(decl.Specs) != 1 || decl.Specs[0].(*ast.ImportSpec).Path.Value != "\"unsafe\"" {
+					log.Fatal("runtime cannot import other package")
+				}
+				continue
+			}
 			if decl.Tok != token.VAR {
 				log.Fatal("unhandled declaration kind", decl.Tok)
 			}
@@ -92,8 +100,8 @@ func mkbuiltin(w io.Writer, name string) {
 	fmt.Fprintln(w, "}")
 
 	fmt.Fprintln(w)
-	fmt.Fprintf(w, "func %sTypes() []*Type {\n", name)
-	fmt.Fprintf(w, "var typs [%d]*Type\n", len(interner.typs))
+	fmt.Fprintf(w, "func %sTypes() []*types.Type {\n", name)
+	fmt.Fprintf(w, "var typs [%d]*types.Type\n", len(interner.typs))
 	for i, typ := range interner.typs {
 		fmt.Fprintf(w, "typs[%d] = %s\n", i, typ)
 	}
@@ -132,37 +140,42 @@ func (i *typeInterner) mktype(t ast.Expr) string {
 	case *ast.Ident:
 		switch t.Name {
 		case "byte":
-			return "bytetype"
+			return "types.Bytetype"
 		case "rune":
-			return "runetype"
+			return "types.Runetype"
+		}
+		return fmt.Sprintf("types.Types[T%s]", strings.ToUpper(t.Name))
+	case *ast.SelectorExpr:
+		if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
+			log.Fatalf("unhandled type: %#v", t)
 		}
-		return fmt.Sprintf("Types[T%s]", strings.ToUpper(t.Name))
+		return "types.Types[TUNSAFEPTR]"
 
 	case *ast.ArrayType:
 		if t.Len == nil {
-			return fmt.Sprintf("typSlice(%s)", i.subtype(t.Elt))
+			return fmt.Sprintf("types.NewSlice(%s)", i.subtype(t.Elt))
 		}
-		return fmt.Sprintf("typArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
+		return fmt.Sprintf("types.NewArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
 	case *ast.ChanType:
-		dir := "Cboth"
+		dir := "types.Cboth"
 		switch t.Dir {
 		case ast.SEND:
-			dir = "Csend"
+			dir = "types.Csend"
 		case ast.RECV:
-			dir = "Crecv"
+			dir = "types.Crecv"
 		}
-		return fmt.Sprintf("typChan(%s, %s)", i.subtype(t.Value), dir)
+		return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir)
 	case *ast.FuncType:
 		return fmt.Sprintf("functype(nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false))
 	case *ast.InterfaceType:
 		if len(t.Methods.List) != 0 {
 			log.Fatal("non-empty interfaces unsupported")
 		}
-		return "Types[TINTER]"
+		return "types.Types[TINTER]"
 	case *ast.MapType:
-		return fmt.Sprintf("typMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
+		return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
 	case *ast.StarExpr:
-		return fmt.Sprintf("typPtr(%s)", i.subtype(t.X))
+		return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
 	case *ast.StructType:
 		return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true))
 
diff --git a/src/cmd/compile/internal/gc/mpfloat.go b/src/cmd/compile/internal/gc/mpfloat.go
index c851022..8d7036b 100644
--- a/src/cmd/compile/internal/gc/mpfloat.go
+++ b/src/cmd/compile/internal/gc/mpfloat.go
@@ -37,8 +37,15 @@ func newMpflt() *Mpflt {
 	return &a
 }
 
+func newMpcmplx() *Mpcplx {
+	var a Mpcplx
+	a.Real = *newMpflt()
+	a.Imag = *newMpflt()
+	return &a
+}
+
 func (a *Mpflt) SetInt(b *Mpint) {
-	if b.Ovf {
+	if b.checkOverflow(0) {
 		// sign doesn't really matter but copy anyway
 		a.Val.SetInf(b.Val.Sign() < 0)
 		return
@@ -128,7 +135,7 @@ func (a *Mpflt) Float64() float64 {
 
 	// check for overflow
 	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
-		yyerror("ovf in Mpflt Float64")
+		Fatalf("ovf in Mpflt Float64")
 	}
 
 	return x + 0 // avoid -0 (should not be needed, but be conservative)
@@ -140,7 +147,7 @@ func (a *Mpflt) Float32() float64 {
 
 	// check for overflow
 	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
-		yyerror("ovf in Mpflt Float32")
+		Fatalf("ovf in Mpflt Float32")
 	}
 
 	return x + 0 // avoid -0 (should not be needed, but be conservative)
@@ -169,25 +176,14 @@ func (a *Mpflt) Neg() {
 	}
 }
 
-//
-// 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)
+	f, _, err := a.Val.Parse(as, 10)
+	if err != nil {
+		yyerror("malformed constant: %s (%v)", as, err)
 		a.Val.SetFloat64(0)
 		return
 	}
diff --git a/src/cmd/compile/internal/gc/mpint.go b/src/cmd/compile/internal/gc/mpint.go
index fba8260..e9471b2 100644
--- a/src/cmd/compile/internal/gc/mpint.go
+++ b/src/cmd/compile/internal/gc/mpint.go
@@ -36,15 +36,16 @@ func (a *Mpint) Set(b *Mpint) {
 	a.Val.Set(&b.Val)
 }
 
-func (a *Mpint) SetFloat(b *Mpflt) int {
+func (a *Mpint) SetFloat(b *Mpflt) bool {
 	// 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
+		a.SetOverflow()
+		return false
 	}
 
 	if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
-		return 0
+		return true
 	}
 
 	const delta = 16 // a reasonably small number of bits > 0
@@ -55,23 +56,24 @@ func (a *Mpint) SetFloat(b *Mpflt) int {
 	t.SetMode(big.ToZero)
 	t.Set(&b.Val)
 	if _, acc := t.Int(&a.Val); acc == big.Exact {
-		return 0
+		return true
 	}
 
 	// 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 true
 	}
 
-	return -1
+	a.Ovf = false
+	return false
 }
 
 func (a *Mpint) Add(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Add")
+			Fatalf("ovf in Mpint Add")
 		}
 		a.SetOverflow()
 		return
@@ -87,7 +89,7 @@ func (a *Mpint) Add(b *Mpint) {
 func (a *Mpint) Sub(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Sub")
+			Fatalf("ovf in Mpint Sub")
 		}
 		a.SetOverflow()
 		return
@@ -103,7 +105,7 @@ func (a *Mpint) Sub(b *Mpint) {
 func (a *Mpint) Mul(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Mul")
+			Fatalf("ovf in Mpint Mul")
 		}
 		a.SetOverflow()
 		return
@@ -119,7 +121,7 @@ func (a *Mpint) Mul(b *Mpint) {
 func (a *Mpint) Quo(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Quo")
+			Fatalf("ovf in Mpint Quo")
 		}
 		a.SetOverflow()
 		return
@@ -136,7 +138,7 @@ func (a *Mpint) Quo(b *Mpint) {
 func (a *Mpint) Rem(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Rem")
+			Fatalf("ovf in Mpint Rem")
 		}
 		a.SetOverflow()
 		return
@@ -153,7 +155,7 @@ func (a *Mpint) Rem(b *Mpint) {
 func (a *Mpint) Or(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Or")
+			Fatalf("ovf in Mpint Or")
 		}
 		a.SetOverflow()
 		return
@@ -165,7 +167,7 @@ func (a *Mpint) Or(b *Mpint) {
 func (a *Mpint) And(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint And")
+			Fatalf("ovf in Mpint And")
 		}
 		a.SetOverflow()
 		return
@@ -177,7 +179,7 @@ func (a *Mpint) And(b *Mpint) {
 func (a *Mpint) AndNot(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint AndNot")
+			Fatalf("ovf in Mpint AndNot")
 		}
 		a.SetOverflow()
 		return
@@ -189,7 +191,7 @@ func (a *Mpint) AndNot(b *Mpint) {
 func (a *Mpint) Xor(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Xor")
+			Fatalf("ovf in Mpint Xor")
 		}
 		a.SetOverflow()
 		return
@@ -201,7 +203,7 @@ func (a *Mpint) Xor(b *Mpint) {
 func (a *Mpint) Lsh(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Lsh")
+			Fatalf("ovf in Mpint Lsh")
 		}
 		a.SetOverflow()
 		return
@@ -228,7 +230,7 @@ func (a *Mpint) Lsh(b *Mpint) {
 func (a *Mpint) Rsh(b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("ovf in Mpint Rsh")
+			Fatalf("ovf in Mpint Rsh")
 		}
 		a.SetOverflow()
 		return
@@ -266,7 +268,7 @@ func (a *Mpint) Neg() {
 func (a *Mpint) Int64() int64 {
 	if a.Ovf {
 		if nsavederrors+nerrors == 0 {
-			yyerror("constant overflow")
+			Fatalf("constant overflow")
 		}
 		return 0
 	}
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index ce18297..3977be1 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -12,53 +12,158 @@ import (
 	"unicode/utf8"
 
 	"cmd/compile/internal/syntax"
+	"cmd/compile/internal/types"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 )
 
-func parseFile(filename string) {
-	src, err := os.Open(filename)
-	if err != nil {
-		fmt.Println(err)
-		errorexit()
-	}
-	defer src.Close()
+func parseFiles(filenames []string) uint {
+	var lines uint
+	var noders []*noder
 
-	p := noder{baseline: lexlineno}
-	file, _ := syntax.Parse(src, p.error, p.pragma, 0) // errors are tracked via p.error
+	for _, filename := range filenames {
+		p := &noder{err: make(chan syntax.Error)}
+		noders = append(noders, p)
 
-	p.file(file)
+		go func(filename string) {
+			defer close(p.err)
+			base := src.NewFileBase(filename, absFilename(filename))
 
-	if !imported_unsafe {
-		for _, x := range p.linknames {
-			p.error(syntax.Error{Line: x, Msg: "//go:linkname only allowed in Go files that import \"unsafe\""})
-		}
+			f, err := os.Open(filename)
+			if err != nil {
+				p.error(syntax.Error{Pos: src.MakePos(base, 0, 0), Msg: err.Error()})
+				return
+			}
+			defer f.Close()
+
+			p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
+		}(filename)
 	}
 
-	if nsyntaxerrors == 0 {
+	for _, p := range noders {
+		for e := range p.err {
+			yyerrorpos(e.Pos, "%s", e.Msg)
+		}
+
+		p.node()
+		lines += p.file.Lines
+		p.file = nil // release memory
+
+		if nsyntaxerrors != 0 {
+			errorexit()
+		}
 		// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
 		testdclstack()
 	}
+
+	return lines
+}
+
+func yyerrorpos(pos src.Pos, format string, args ...interface{}) {
+	yyerrorl(Ctxt.PosTable.XPos(pos), format, args...)
 }
 
-// noder transforms package syntax's AST into a Nod tree.
+var pathPrefix string
+
+func absFilename(name string) string {
+	return objabi.AbsFile(Ctxt.Pathname, name, pathPrefix)
+}
+
+// noder transforms package syntax's AST into a Node tree.
 type noder struct {
-	baseline  int32
-	linknames []int // tracks //go:linkname lines
+	file       *syntax.File
+	linknames  []linkname
+	pragcgobuf string
+	err        chan syntax.Error
+	scope      ScopeID
+}
+
+func (p *noder) funchdr(n *Node, pos src.Pos) ScopeID {
+	old := p.scope
+	p.scope = 0
+	funchdr(n)
+	return old
+}
+
+func (p *noder) funcbody(n *Node, pos src.Pos, old ScopeID) {
+	funcbody(n)
+	p.scope = old
+}
+
+func (p *noder) openScope(pos src.Pos) {
+	types.Markdcl()
+
+	if trackScopes {
+		Curfn.Func.Parents = append(Curfn.Func.Parents, p.scope)
+		p.scope = ScopeID(len(Curfn.Func.Parents))
+
+		p.markScope(pos)
+	}
+}
+
+func (p *noder) closeScope(pos src.Pos) {
+	types.Popdcl()
+
+	if trackScopes {
+		p.scope = Curfn.Func.Parents[p.scope-1]
+
+		p.markScope(pos)
+	}
 }
 
-func (p *noder) file(file *syntax.File) {
-	p.lineno(file.PkgName)
-	mkpackage(file.PkgName.Value)
+func (p *noder) markScope(pos src.Pos) {
+	xpos := Ctxt.PosTable.XPos(pos)
+	if i := len(Curfn.Func.Marks); i > 0 && Curfn.Func.Marks[i-1].Pos == xpos {
+		Curfn.Func.Marks[i-1].Scope = p.scope
+	} else {
+		Curfn.Func.Marks = append(Curfn.Func.Marks, Mark{xpos, p.scope})
+	}
+}
 
-	xtop = append(xtop, p.decls(file.DeclList)...)
+// closeAnotherScope is like closeScope, but it reuses the same mark
+// position as the last closeScope call. This is useful for "for" and
+// "if" statements, as their implicit blocks always end at the same
+// position as an explicit block.
+func (p *noder) closeAnotherScope() {
+	types.Popdcl()
 
-	lexlineno = p.baseline + int32(file.Lines) - 1
-	lineno = lexlineno
+	if trackScopes {
+		p.scope = Curfn.Func.Parents[p.scope-1]
+		Curfn.Func.Marks[len(Curfn.Func.Marks)-1].Scope = p.scope
+	}
+}
+
+// linkname records a //go:linkname directive.
+type linkname struct {
+	pos    src.Pos
+	local  string
+	remote string
+}
+
+func (p *noder) node() {
+	types.Block = 1
+	imported_unsafe = false
+
+	p.lineno(p.file.PkgName)
+	mkpackage(p.file.PkgName.Value)
+
+	xtop = append(xtop, p.decls(p.file.DeclList)...)
+
+	for _, n := range p.linknames {
+		if imported_unsafe {
+			lookup(n.local).Linkname = n.remote
+		} else {
+			yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
+		}
+	}
+
+	pragcgobuf += p.pragcgobuf
+	lineno = src.NoXPos
+	clearImports()
 }
 
 func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
-	var lastConstGroup *syntax.Group
-	var lastConstRHS []*Node
-	var iotaVal int64
+	var cs constState
 
 	for _, decl := range decls {
 		p.lineno(decl)
@@ -70,27 +175,7 @@ func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
 			l = append(l, p.varDecl(decl)...)
 
 		case *syntax.ConstDecl:
-			// Tricky to handle golang.org/issue/15550 correctly.
-
-			prevIota := iota_
-
-			if decl.Group == nil || decl.Group != lastConstGroup {
-				iotaVal = 0
-				lastConstRHS = nil
-			}
-
-			iota_ = iotaVal
-			lastconst = lastConstRHS
-
-			l = append(l, p.constDecl(decl)...)
-
-			lastConstRHS = lastconst
-			lastconst = nil
-
-			iota_ = prevIota
-			iotaVal++
-
-			lastConstGroup = decl.Group
+			l = append(l, p.constDecl(decl, &cs)...)
 
 		case *syntax.TypeDecl:
 			l = append(l, p.typeDecl(decl))
@@ -108,9 +193,7 @@ func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
 
 func (p *noder) importDecl(imp *syntax.ImportDecl) {
 	val := p.basicLit(imp.Path)
-	importfile(&val, nil)
-	ipkg := importpkg
-	importpkg = nil
+	ipkg := importfile(&val)
 
 	if ipkg == nil {
 		if nerrors == 0 {
@@ -121,7 +204,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
 
 	ipkg.Direct = true
 
-	var my *Sym
+	var my *types.Sym
 	if imp.LocalPkgName != nil {
 		my = p.name(imp.LocalPkgName)
 	} else {
@@ -137,28 +220,24 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
 		return
 	}
 	if my.Name == "init" {
-		yyerrorl(pack.Lineno, "cannot import package as init - init must be a func")
+		yyerrorl(pack.Pos, "cannot import package as init - init must be a func")
 		return
 	}
 	if my.Name == "_" {
 		return
 	}
 	if my.Def != nil {
-		lineno = pack.Lineno
+		lineno = pack.Pos
 		redeclare(my, "as imported package name")
 	}
-	my.Def = pack
-	my.Lastlineno = pack.Lineno
+	my.Def = asTypesNode(pack)
+	my.Lastlineno = pack.Pos
 	my.Block = 1 // at top level
 }
 
 func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
 	names := p.declNames(decl.NameList)
-
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
-	}
+	typ := p.typeExprOrNil(decl.Type)
 
 	var exprs []*Node
 	if decl.Values != nil {
@@ -169,32 +248,87 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
 	return variter(names, typ, exprs)
 }
 
-func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
-	names := p.declNames(decl.NameList)
+// constState tracks state between constant specifiers within a
+// declaration group. This state is kept separate from noder so nested
+// constant declarations are handled correctly (e.g., issue 15550).
+type constState struct {
+	group  *syntax.Group
+	typ    *Node
+	values []*Node
+	iota   int64
+}
 
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
+func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []*Node {
+	if decl.Group == nil || decl.Group != cs.group {
+		*cs = constState{
+			group: decl.Group,
+		}
 	}
 
-	var exprs []*Node
+	names := p.declNames(decl.NameList)
+	typ := p.typeExprOrNil(decl.Type)
+
+	var values []*Node
 	if decl.Values != nil {
-		exprs = p.exprList(decl.Values)
+		values = p.exprList(decl.Values)
+		cs.typ, cs.values = typ, values
+	} else {
+		if typ != nil {
+			yyerror("const declaration cannot have type without expression")
+		}
+		typ, values = cs.typ, cs.values
+	}
+
+	var nn []*Node
+	for i, n := range names {
+		if i >= len(values) {
+			yyerror("missing value in const declaration")
+			break
+		}
+		v := values[i]
+		if decl.Values == nil {
+			v = treecopy(v, n.Pos)
+		}
+
+		n.Op = OLITERAL
+		declare(n, dclcontext)
+
+		n.Name.Param.Ntype = typ
+		n.Name.Defn = v
+		n.SetIota(cs.iota)
+
+		nn = append(nn, p.nod(decl, ODCLCONST, n, nil))
 	}
 
-	return constiter(names, typ, exprs)
+	if len(values) > len(names) {
+		yyerror("extra expression in const declaration")
+	}
+
+	cs.iota++
+
+	return nn
 }
 
 func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
-	name := typedcl0(p.name(decl.Name))
-	name.Name.Param.Pragma = Pragma(decl.Pragma)
-
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
+	n := p.declName(decl.Name)
+	n.Op = OTYPE
+	declare(n, dclcontext)
+	n.SetLocal(true)
+
+	// decl.Type may be nil but in that case we got a syntax error during parsing
+	typ := p.typeExprOrNil(decl.Type)
+
+	param := n.Name.Param
+	param.Ntype = typ
+	param.Pragma = decl.Pragma
+	param.Alias = decl.Alias
+	if param.Alias && param.Pragma != 0 {
+		yyerror("cannot specify directive with type alias")
+		param.Pragma = 0
 	}
 
-	return typedcl1(name, typ, true)
+	return p.nod(decl, ODCLTYPE, n, nil)
+
 }
 
 func (p *noder) declNames(names []*syntax.Name) []*Node {
@@ -211,68 +345,67 @@ func (p *noder) declName(name *syntax.Name) *Node {
 }
 
 func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
-	f := p.funcHeader(fun)
-	if f == nil {
-		return nil
-	}
-
-	var body []*Node
-	if fun.Body != nil {
-		body = p.stmts(fun.Body)
-		if body == nil {
-			body = []*Node{p.nod(fun, OEMPTY, nil, nil)}
-		}
-	}
-
-	pragma := Pragma(fun.Pragma)
-
-	f.Nbody.Set(body)
-	f.Noescape = pragma&Noescape != 0
-	if f.Noescape && len(body) != 0 {
-		yyerror("can only use //go:noescape with external func implementations")
-	}
-	f.Func.Pragma = pragma
-	lineno = p.baseline + int32(fun.EndLine) - 1
-	f.Func.Endlineno = lineno
-
-	funcbody(f)
-
-	return f
-}
-
-func (p *noder) funcHeader(fun *syntax.FuncDecl) *Node {
 	name := p.name(fun.Name)
 	t := p.signature(fun.Recv, fun.Type)
 	f := p.nod(fun, ODCLFUNC, nil, nil)
 
 	if fun.Recv == nil {
-		// FunctionName Signature
 		if name.Name == "init" {
 			name = renameinit()
 			if t.List.Len() > 0 || t.Rlist.Len() > 0 {
-				yyerror("func init must have no arguments and no return values")
+				yyerrorl(f.Pos, "func init must have no arguments and no return values")
 			}
 		}
 
 		if localpkg.Name == "main" && name.Name == "main" {
 			if t.List.Len() > 0 || t.Rlist.Len() > 0 {
-				yyerror("func main must have no arguments and no return values")
+				yyerrorl(f.Pos, "func main must have no arguments and no return values")
 			}
 		}
-
-		f.Func.Nname = newfuncname(name)
 	} else {
-		// Receiver MethodName Signature
-
-		f.Func.Shortname = newfuncname(name)
-		f.Func.Nname = methodname(f.Func.Shortname, t.Left.Right)
+		f.Func.Shortname = name
+		name = nblank.Sym // filled in by typecheckfunc
 	}
 
+	f.Func.Nname = newfuncname(name)
 	f.Func.Nname.Name.Defn = f
-	f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
+	f.Func.Nname.Name.Param.Ntype = t
+
+	pragma := fun.Pragma
+	f.Func.Pragma = fun.Pragma
+	f.SetNoescape(pragma&Noescape != 0)
+	if pragma&Systemstack != 0 && pragma&Nosplit != 0 {
+		yyerrorl(f.Pos, "go:nosplit and go:systemstack cannot be combined")
+	}
+
+	if fun.Recv == nil {
+		declare(f.Func.Nname, PFUNC)
+	}
+
+	oldScope := p.funchdr(f, fun.Pos())
+
+	endPos := fun.Pos()
+	if fun.Body != nil {
+		if f.Noescape() {
+			yyerrorl(f.Pos, "can only use //go:noescape with external func implementations")
+		}
+
+		body := p.stmts(fun.Body.List)
+		if body == nil {
+			body = []*Node{p.nod(fun, OEMPTY, nil, nil)}
+		}
+		f.Nbody.Set(body)
 
-	declare(f.Func.Nname, PFUNC)
-	funchdr(f)
+		endPos = fun.Body.Rbrace
+		lineno = Ctxt.PosTable.XPos(fun.Body.Rbrace)
+		f.Func.Endlineno = lineno
+	} else {
+		if pure_go || strings.HasPrefix(f.funcname(), "init.") {
+			yyerrorl(f.Pos, "missing function body for %q", f.funcname())
+		}
+	}
+
+	p.funcbody(f, endPos, oldScope)
 	return f
 }
 
@@ -314,9 +447,9 @@ func (p *noder) param(param *syntax.Field, dddOk, final bool) *Node {
 		typ.Op = OTARRAY
 		typ.Right = typ.Left
 		typ.Left = nil
-		n.Isddd = true
+		n.SetIsddd(true)
 		if n.Left != nil {
-			n.Left.Isddd = true
+			n.Left.SetIsddd(true)
 		}
 	}
 
@@ -341,7 +474,7 @@ func (p *noder) exprs(exprs []syntax.Expr) []*Node {
 func (p *noder) expr(expr syntax.Expr) *Node {
 	p.lineno(expr)
 	switch expr := expr.(type) {
-	case nil:
+	case nil, *syntax.BadExpr:
 		return nil
 	case *syntax.Name:
 		return p.mkname(expr)
@@ -358,22 +491,19 @@ func (p *noder) expr(expr syntax.Expr) *Node {
 			l[i] = p.wrapname(expr.ElemList[i], e)
 		}
 		n.List.Set(l)
-		lineno = p.baseline + int32(expr.EndLine) - 1
+		lineno = Ctxt.PosTable.XPos(expr.Rbrace)
 		return n
 	case *syntax.KeyValueExpr:
 		return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
 	case *syntax.FuncLit:
-		closurehdr(p.typeExpr(expr.Type))
-		body := p.stmts(expr.Body)
-		lineno = p.baseline + int32(expr.EndLine) - 1
-		return p.setlineno(expr, closurebody(body))
+		return p.funcLit(expr)
 	case *syntax.ParenExpr:
 		return p.nod(expr, OPAREN, p.expr(expr.X), nil)
 	case *syntax.SelectorExpr:
 		// parser.new_dotname
 		obj := p.expr(expr.X)
 		if obj.Op == OPACK {
-			obj.Used = true
+			obj.Name.SetUsed(true)
 			return oldname(restrictlookup(expr.Sel.Value, obj.Name.Pkg))
 		}
 		return p.setlineno(expr, nodSym(OXDOT, obj, p.name(expr.Sel)))
@@ -411,7 +541,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
 					// TODO(mdempsky): Switch back to p.nod after we
 					// get rid of gcCompat.
 					x.Right = nod(OIND, x.Right, nil)
-					x.Right.Implicit = true
+					x.Right.SetImplicit(true)
 					return x
 				}
 			}
@@ -421,7 +551,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
 	case *syntax.CallExpr:
 		n := p.nod(expr, OCALL, p.expr(expr.Fun), nil)
 		n.List.Set(p.exprs(expr.ArgList))
-		n.Isddd = expr.HasDots
+		n.SetIsddd(expr.HasDots)
 		return n
 
 	case *syntax.ArrayType:
@@ -446,7 +576,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
 		return p.nod(expr, OTMAP, p.typeExpr(expr.Key), p.typeExpr(expr.Value))
 	case *syntax.ChanType:
 		n := p.nod(expr, OTCHAN, p.typeExpr(expr.Elem), nil)
-		n.Etype = EType(p.chanDir(expr.Dir))
+		n.Etype = types.EType(p.chanDir(expr.Dir))
 		return n
 
 	case *syntax.TypeSwitchGuard:
@@ -467,14 +597,21 @@ func (p *noder) typeExpr(typ syntax.Expr) *Node {
 	return p.expr(typ)
 }
 
-func (p *noder) chanDir(dir syntax.ChanDir) ChanDir {
+func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
+	if typ != nil {
+		return p.expr(typ)
+	}
+	return nil
+}
+
+func (p *noder) chanDir(dir syntax.ChanDir) types.ChanDir {
 	switch dir {
 	case 0:
-		return Cboth
+		return types.Cboth
 	case syntax.SendOnly:
-		return Csend
+		return types.Csend
 	case syntax.RecvOnly:
-		return Crecv
+		return types.Crecv
 	}
 	panic("unhandled ChanDir")
 }
@@ -511,7 +648,7 @@ func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
 		} else {
 			mname := p.newname(method.Name)
 			sig := p.typeExpr(method.Type)
-			sig.Left = fakethis()
+			sig.Left = fakeRecv()
 			n = p.nod(method, ODCLFIELD, mname, sig)
 			ifacedcl(n)
 		}
@@ -523,23 +660,23 @@ func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
 	return n
 }
 
-func (p *noder) packname(expr syntax.Expr) *Sym {
+func (p *noder) packname(expr syntax.Expr) *types.Sym {
 	switch expr := expr.(type) {
 	case *syntax.Name:
 		name := p.name(expr)
 		if n := oldname(name); n.Name != nil && n.Name.Pack != nil {
-			n.Name.Pack.Used = true
+			n.Name.Pack.Name.SetUsed(true)
 		}
 		return name
 	case *syntax.SelectorExpr:
 		name := p.name(expr.X.(*syntax.Name))
-		var pkg *Pkg
-		if name.Def == nil || name.Def.Op != OPACK {
+		var pkg *types.Pkg
+		if asNode(name.Def) == nil || asNode(name.Def).Op != OPACK {
 			yyerror("%v is not a package", name)
 			pkg = localpkg
 		} else {
-			name.Def.Used = true
-			pkg = name.Def.Name.Pkg
+			asNode(name.Def).Name.SetUsed(true)
+			pkg = asNode(name.Def).Name.Pkg
 		}
 		return restrictlookup(expr.Sel.Value, pkg)
 	}
@@ -583,7 +720,12 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 	case *syntax.LabeledStmt:
 		return p.labeledStmt(stmt)
 	case *syntax.BlockStmt:
-		return p.body(stmt.Body)
+		l := p.blockStmt(stmt)
+		if len(l) == 0 {
+			// TODO(mdempsky): Line number?
+			return nod(OEMPTY, nil, nil)
+		}
+		return liststmt(l)
 	case *syntax.ExprStmt:
 		return p.wrapname(stmt, p.expr(stmt.X))
 	case *syntax.SendStmt:
@@ -593,8 +735,8 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 	case *syntax.AssignStmt:
 		if stmt.Op != 0 && stmt.Op != syntax.Def {
 			n := p.nod(stmt, OASOP, p.expr(stmt.Lhs), p.expr(stmt.Rhs))
-			n.Implicit = stmt.Rhs == syntax.ImplicitOne
-			n.Etype = EType(p.binOp(stmt.Op))
+			n.SetImplicit(stmt.Rhs == syntax.ImplicitOne)
+			n.Etype = types.EType(p.binOp(stmt.Op))
 			return n
 		}
 
@@ -604,7 +746,7 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 		n := p.nod(stmt, OAS, nil, nil) // assume common case
 
 		if stmt.Op == syntax.Def {
-			n.Colas = true
+			n.SetColas(true)
 			colasdefn(lhs, n) // modifies lhs, call before using lhs[0] in common case
 		}
 
@@ -637,11 +779,8 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 		if stmt.Label != nil {
 			n.Left = p.newname(stmt.Label)
 		}
-		if op == OGOTO {
-			n.Sym = dclstack // context, for goto restriction
-		}
 		if op == OXFALL {
-			n.Xoffset = int64(block)
+			n.Xoffset = int64(types.Block)
 		}
 		return n
 	case *syntax.CallStmt:
@@ -664,13 +803,13 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 		n.List.Set(results)
 		if n.List.Len() == 0 && Curfn != nil {
 			for _, ln := range Curfn.Func.Dcl {
-				if ln.Class == PPARAM {
+				if ln.Class() == PPARAM {
 					continue
 				}
-				if ln.Class != PPARAMOUT {
+				if ln.Class() != PPARAMOUT {
 					break
 				}
-				if ln.Sym.Def != ln {
+				if asNode(ln.Sym.Def) != ln {
 					yyerror("%s is shadowed during return", ln.Sym.Name)
 				}
 			}
@@ -688,24 +827,15 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
 	panic("unhandled Stmt")
 }
 
-func (p *noder) body(body []syntax.Stmt) *Node {
-	l := p.bodyList(body)
-	if len(l) == 0 {
-		// TODO(mdempsky): Line number?
-		return nod(OEMPTY, nil, nil)
-	}
-	return liststmt(l)
-}
-
-func (p *noder) bodyList(body []syntax.Stmt) []*Node {
-	markdcl()
-	nodes := p.stmts(body)
-	popdcl()
+func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
+	p.openScope(stmt.Pos())
+	nodes := p.stmts(stmt.List)
+	p.closeScope(stmt.Rbrace)
 	return nodes
 }
 
 func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
-	markdcl()
+	p.openScope(stmt.Pos())
 	n := p.nod(stmt, OIF, nil, nil)
 	if stmt.Init != nil {
 		n.Ninit.Set1(p.stmt(stmt.Init))
@@ -713,7 +843,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
 	if stmt.Cond != nil {
 		n.Left = p.expr(stmt.Cond)
 	}
-	n.Nbody.Set(p.bodyList(stmt.Then))
+	n.Nbody.Set(p.blockStmt(stmt.Then))
 	if stmt.Else != nil {
 		e := p.stmt(stmt.Else)
 		if e.Op == OBLOCK && e.Ninit.Len() == 0 {
@@ -722,12 +852,12 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
 			n.Rlist.Set1(e)
 		}
 	}
-	popdcl()
+	p.closeAnotherScope()
 	return n
 }
 
 func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
-	markdcl()
+	p.openScope(stmt.Pos())
 	var n *Node
 	if r, ok := stmt.Init.(*syntax.RangeClause); ok {
 		if stmt.Cond != nil || stmt.Post != nil {
@@ -739,7 +869,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
 			lhs := p.exprList(r.Lhs)
 			n.List.Set(lhs)
 			if r.Def {
-				n.Colas = true
+				n.SetColas(true)
 				colasdefn(lhs, n)
 			}
 		}
@@ -755,13 +885,13 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
 			n.Right = p.stmt(stmt.Post)
 		}
 	}
-	n.Nbody.Set(p.bodyList(stmt.Body))
-	popdcl()
+	n.Nbody.Set(p.blockStmt(stmt.Body))
+	p.closeAnotherScope()
 	return n
 }
 
 func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
-	markdcl()
+	p.openScope(stmt.Pos())
 	n := p.nod(stmt, OSWITCH, nil, nil)
 	if stmt.Init != nil {
 		n.Ninit.Set1(p.stmt(stmt.Init))
@@ -774,18 +904,21 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
 	if tswitch != nil && (tswitch.Op != OTYPESW || tswitch.Left == nil) {
 		tswitch = nil
 	}
+	n.List.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace))
 
-	n.List.Set(p.caseClauses(stmt.Body, tswitch))
-
-	popdcl()
+	p.closeScope(stmt.Rbrace)
 	return n
 }
 
-func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node {
+func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace src.Pos) []*Node {
 	var nodes []*Node
-	for _, clause := range clauses {
+	for i, clause := range clauses {
 		p.lineno(clause)
-		markdcl()
+		if i > 0 {
+			p.closeScope(clause.Pos())
+		}
+		p.openScope(clause.Pos())
+
 		n := p.nod(clause, OXCASE, nil, nil)
 		if clause.Cases != nil {
 			n.List.Set(p.exprList(clause.Cases))
@@ -797,40 +930,47 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
 			// keep track of the instances for reporting unused
 			nn.Name.Defn = tswitch
 		}
-		n.Xoffset = int64(block)
+		n.Xoffset = int64(types.Block)
 		n.Nbody.Set(p.stmts(clause.Body))
-		popdcl()
 		nodes = append(nodes, n)
 	}
+	if len(clauses) > 0 {
+		p.closeScope(rbrace)
+	}
 	return nodes
 }
 
 func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
 	n := p.nod(stmt, OSELECT, nil, nil)
-	n.List.Set(p.commClauses(stmt.Body))
+	n.List.Set(p.commClauses(stmt.Body, stmt.Rbrace))
 	return n
 }
 
-func (p *noder) commClauses(clauses []*syntax.CommClause) []*Node {
+func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace src.Pos) []*Node {
 	var nodes []*Node
-	for _, clause := range clauses {
+	for i, clause := range clauses {
 		p.lineno(clause)
-		markdcl()
+		if i > 0 {
+			p.closeScope(clause.Pos())
+		}
+		p.openScope(clause.Pos())
+
 		n := p.nod(clause, OXCASE, nil, nil)
 		if clause.Comm != nil {
 			n.List.Set1(p.stmt(clause.Comm))
 		}
-		n.Xoffset = int64(block)
+		n.Xoffset = int64(types.Block)
 		n.Nbody.Set(p.stmts(clause.Body))
-		popdcl()
 		nodes = append(nodes, n)
 	}
+	if len(clauses) > 0 {
+		p.closeScope(rbrace)
+	}
 	return nodes
 }
 
 func (p *noder) labeledStmt(label *syntax.LabeledStmt) *Node {
 	lhs := p.nod(label, OLABEL, p.newname(label.Label), nil)
-	lhs.Sym = dclstack
 
 	var ls *Node
 	if label.Stmt != nil { // TODO(mdempsky): Should always be present.
@@ -952,7 +1092,7 @@ func (p *noder) basicLit(lit *syntax.BasicLit) Val {
 	}
 }
 
-func (p *noder) name(name *syntax.Name) *Sym {
+func (p *noder) name(name *syntax.Name) *types.Sym {
 	return lookup(name.Value)
 }
 
@@ -977,7 +1117,7 @@ func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
 		fallthrough
 	case ONAME, ONONAME, OPACK:
 		x = p.nod(n, OPAREN, x, nil)
-		x.Implicit = true
+		x.SetImplicit(true)
 	}
 	return x
 }
@@ -986,13 +1126,13 @@ func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
 	return p.setlineno(orig, nod(op, left, right))
 }
 
-func (p *noder) setlineno(src syntax.Node, dst *Node) *Node {
-	l := int32(src.Line())
-	if l == 0 {
+func (p *noder) setlineno(src_ syntax.Node, dst *Node) *Node {
+	pos := src_.Pos()
+	if !pos.IsKnown() {
 		// TODO(mdempsky): Shouldn't happen. Fix package syntax.
 		return dst
 	}
-	dst.Lineno = p.baseline + l - 1
+	dst.Pos = Ctxt.PosTable.XPos(pos)
 	return dst
 }
 
@@ -1000,81 +1140,72 @@ func (p *noder) lineno(n syntax.Node) {
 	if n == nil {
 		return
 	}
-	l := int32(n.Line())
-	if l == 0 {
+	pos := n.Pos()
+	if !pos.IsKnown() {
 		// TODO(mdempsky): Shouldn't happen. Fix package syntax.
 		return
 	}
-	lineno = p.baseline + l - 1
+	lineno = Ctxt.PosTable.XPos(pos)
 }
 
+// error is called concurrently if files are parsed concurrently.
 func (p *noder) error(err error) {
-	line := p.baseline
-	var msg string
-	if err, ok := err.(syntax.Error); ok {
-		line += int32(err.Line) - 1
-		msg = err.Msg
-	} else {
-		msg = err.Error()
-	}
-	yyerrorl(line, "%s", msg)
+	p.err <- err.(syntax.Error)
 }
 
-func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
+// pragmas that are allowed in the std lib, but don't have
+// a syntax.Pragma value (see lex.go) associated with them.
+var allowedStdPragmas = map[string]bool{
+	"go:cgo_export_static":  true,
+	"go:cgo_export_dynamic": true,
+	"go:cgo_import_static":  true,
+	"go:cgo_import_dynamic": true,
+	"go:cgo_ldflag":         true,
+	"go:cgo_dynamic_linker": true,
+	"go:generate":           true,
+}
+
+// pragma is called concurrently if files are parsed concurrently.
+func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
 	switch {
 	case strings.HasPrefix(text, "line "):
-		// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
-		i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
-		if i < 0 {
-			break
-		}
-		n, err := strconv.Atoi(text[i+1:])
-		if err != nil {
-			// TODO: make this an error instead? it is almost certainly a bug.
-			break
-		}
-		if n > 1e8 {
-			p.error(syntax.Error{Pos: pos, Line: line, Msg: "line number out of range"})
-			errorexit()
-		}
-		if n <= 0 {
-			break
-		}
-		lexlineno = p.baseline + int32(line)
-		linehistupdate(text[5:i], n)
+		// line directives are handled by syntax package
+		panic("unreachable")
 
 	case strings.HasPrefix(text, "go:linkname "):
-		// Record line number so we can emit an error later if
-		// the file doesn't import package unsafe.
-		p.linknames = append(p.linknames, line)
-
 		f := strings.Fields(text)
 		if len(f) != 3 {
-			p.error(syntax.Error{Pos: pos, Line: line, Msg: "usage: //go:linkname localname linkname"})
+			p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname linkname"})
 			break
 		}
-		lookup(f[1]).Linkname = f[2]
+		p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
 
 	case strings.HasPrefix(text, "go:cgo_"):
-		lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
-		pragcgobuf += pragcgo(text)
+		p.pragcgobuf += p.pragcgo(pos, text)
 		fallthrough // because of //go:cgo_unsafe_args
 	default:
 		verb := text
 		if i := strings.Index(text, " "); i >= 0 {
 			verb = verb[:i]
 		}
-		lineno = p.baseline + int32(line) - 1 // pragmaValue may call yyerror
-		return syntax.Pragma(pragmaValue(verb))
+		prag := pragmaValue(verb)
+		const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
+		if !compiling_runtime && prag&runtimePragmas != 0 {
+			p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)})
+		}
+		if prag == 0 && !allowedStdPragmas[verb] && compiling_std {
+			p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is not allowed in the standard library", verb)})
+		}
+		return prag
 	}
 
 	return 0
 }
 
-func mkname(sym *Sym) *Node {
+func mkname(sym *types.Sym) *Node {
 	n := oldname(sym)
 	if n.Name != nil && n.Name.Pack != nil {
-		n.Name.Pack.Used = true
+		n.Name.Pack.Name.SetUsed(true)
 	}
 	return n
 }
diff --git a/src/cmd/compile/internal/gc/norace.go b/src/cmd/compile/internal/gc/norace.go
new file mode 100644
index 0000000..e00f0c4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/norace.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !race
+
+package gc
+
+const raceEnabled = false
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 08ed560..83e64e7 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -5,8 +5,10 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
 	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"crypto/sha256"
 	"fmt"
 	"io"
@@ -41,12 +43,16 @@ const (
 )
 
 func dumpobj() {
+	if !dolinkobj {
+		dumpobj1(outfile, modeCompilerObj)
+		return
+	}
 	if linkobj == "" {
 		dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
-	} else {
-		dumpobj1(outfile, modeCompilerObj)
-		dumpobj1(linkobj, modeLinkerObj)
+		return
 	}
+	dumpobj1(outfile, modeCompilerObj)
+	dumpobj1(linkobj, modeLinkerObj)
 }
 
 func dumpobj1(outfile string, mode int) {
@@ -68,7 +74,7 @@ func dumpobj1(outfile string, mode int) {
 	}
 
 	printheader := func() {
-		fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
+		fmt.Fprintf(bout, "go object %s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
 		if buildid != "" {
 			fmt.Fprintf(bout, "build id %q\n", buildid)
 		}
@@ -130,8 +136,12 @@ func dumpobj1(outfile string, mode int) {
 	externs := len(externdcl)
 
 	dumpglobls()
-	dumpptabs()
-	dumptypestructs()
+	addptabs()
+	addsignats(externdcl)
+	dumpsignats()
+	dumptabs()
+	dumpimportstrings()
+	dumpbasictypes()
 
 	// Dump extra globals.
 	tmp := externdcl
@@ -143,11 +153,13 @@ func dumpobj1(outfile string, mode int) {
 	externdcl = tmp
 
 	if zerosize > 0 {
-		zero := Pkglookup("zero", mappkg)
-		ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
+		zero := mappkg.Lookup("zero")
+		ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
 	}
 
-	obj.Writeobjdirect(Ctxt, bout.Writer)
+	addGCLocals()
+
+	obj.WriteObjFile(Ctxt, bout.Writer)
 
 	if writearchive {
 		bout.Flush()
@@ -163,13 +175,13 @@ func dumpobj1(outfile string, mode int) {
 	bout.Close()
 }
 
-func dumpptabs() {
+func addptabs() {
 	if !Ctxt.Flag_dynlink || localpkg.Name != "main" {
 		return
 	}
 	for _, exportn := range exportlist {
 		s := exportn.Sym
-		n := s.Def
+		n := asNode(s.Def)
 		if n == nil {
 			continue
 		}
@@ -182,12 +194,12 @@ func dumpptabs() {
 		if s.Pkg.Name != "main" {
 			continue
 		}
-		if n.Type.Etype == TFUNC && n.Class == PFUNC {
+		if n.Type.Etype == TFUNC && n.Class() == PFUNC {
 			// function
-			ptabs = append(ptabs, ptabEntry{s: s, t: s.Def.Type})
+			ptabs = append(ptabs, ptabEntry{s: s, t: asNode(s.Def).Type})
 		} else {
 			// variable
-			ptabs = append(ptabs, ptabEntry{s: s, t: typPtr(s.Def.Type)})
+			ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)})
 		}
 	}
 }
@@ -202,7 +214,7 @@ func dumpglobls() {
 		if n.Type == nil {
 			Fatalf("external %v nil type\n", n)
 		}
-		if n.Class == PFUNC {
+		if n.Class() == PFUNC {
 			continue
 		}
 		if n.Sym.Pkg != localpkg {
@@ -212,66 +224,65 @@ func dumpglobls() {
 		ggloblnod(n)
 	}
 
-	for _, n := range funcsyms {
-		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
-		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
+	obj.SortSlice(funcsyms, func(i, j int) bool {
+		return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
+	})
+	for _, s := range funcsyms {
+		sf := s.Pkg.Lookup(funcsymname(s)).Linksym()
+		dsymptr(sf, 0, s.Linksym(), 0)
+		ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA)
 	}
 
 	// Do not reprocess funcsyms on next dumpglobls call.
 	funcsyms = nil
 }
 
-func Linksym(s *Sym) *obj.LSym {
-	if s == nil {
-		return nil
-	}
-	if s.Lsym != nil {
-		return s.Lsym
-	}
-	var name string
-	if isblanksym(s) {
-		name = "_"
-	} else if s.Linkname != "" {
-		name = s.Linkname
-	} else {
-		name = s.Pkg.Prefix + "." + s.Name
+// addGCLocals adds gcargs and gclocals symbols to Ctxt.Data.
+// It takes care not to add any duplicates.
+// Though the object file format handles duplicates efficiently,
+// storing only a single copy of the data,
+// failure to remove these duplicates adds a few percent to object file size.
+func addGCLocals() {
+	seen := make(map[string]bool)
+	for _, s := range Ctxt.Text {
+		if s.Func == nil {
+			continue
+		}
+		for _, gcsym := range []*obj.LSym{&s.Func.GCArgs, &s.Func.GCLocals} {
+			if seen[gcsym.Name] {
+				continue
+			}
+			Ctxt.Data = append(Ctxt.Data, gcsym)
+			seen[gcsym.Name] = true
+		}
 	}
-
-	ls := obj.Linklookup(Ctxt, name, 0)
-	s.Lsym = ls
-	return ls
 }
 
-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, s, int64(off), v, int64(wid)))
+func duintxx(s *obj.LSym, off int, v uint64, wid int) int {
+	if off&(wid-1) != 0 {
+		Fatalf("duintxxLSym: misaligned: v=%d wid=%d off=%d", v, wid, off)
+	}
+	s.WriteInt(Ctxt, int64(off), wid, int64(v))
+	return off + wid
 }
 
-func duint8(s *Sym, off int, v uint8) int {
+func duint8(s *obj.LSym, off int, v uint8) int {
 	return duintxx(s, off, uint64(v), 1)
 }
 
-func duint16(s *Sym, off int, v uint16) int {
+func duint16(s *obj.LSym, off int, v uint16) int {
 	return duintxx(s, off, uint64(v), 2)
 }
 
-func duint32(s *Sym, off int, v uint32) int {
+func duint32(s *obj.LSym, off int, v uint32) int {
 	return duintxx(s, off, uint64(v), 4)
 }
 
-func duintptr(s *Sym, off int, v uint64) int {
+func duintptr(s *obj.LSym, off int, v uint64) int {
 	return duintxx(s, off, v, Widthptr)
 }
 
-func dbvec(s *Sym, off int, bv bvec) int {
+func dbvec(s *obj.LSym, off int, bv bvec) int {
 	// Runtime reads the bitmaps as byte arrays. Oblige.
 	for j := 0; int32(j) < bv.n; j += 8 {
 		word := bv.b[j/32]
@@ -297,12 +308,12 @@ func stringsym(s string) (data *obj.LSym) {
 	const prefix = "go.string."
 	symdataname := prefix + symname
 
-	symdata := obj.Linklookup(Ctxt, symdataname, 0)
+	symdata := Ctxt.Lookup(symdataname)
 
 	if !symdata.SeenGlobl() {
 		// string data
-		off := dsnameLSym(symdata, 0, s)
-		ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+		off := dsname(symdata, 0, s)
+		ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
 	}
 
 	return symdata
@@ -313,48 +324,42 @@ var slicebytes_gen int
 func slicebytes(nam *Node, s string, len int) {
 	slicebytes_gen++
 	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
-	sym := Pkglookup(symname, localpkg)
-	sym.Def = newname(sym)
+	sym := localpkg.Lookup(symname)
+	sym.Def = asTypesNode(newname(sym))
 
-	off := dsname(sym, 0, s)
-	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
+	lsym := sym.Linksym()
+	off := dsname(lsym, 0, s)
+	ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
 
 	if nam.Op != ONAME {
 		Fatalf("slicebytes %v", nam)
 	}
+	nsym := nam.Sym.Linksym()
 	off = int(nam.Xoffset)
-	off = dsymptr(nam.Sym, off, sym, 0)
-	off = duintxx(nam.Sym, off, uint64(len), Widthint)
-	duintxx(nam.Sym, off, uint64(len), Widthint)
-}
-
-func dsname(s *Sym, off int, t string) int {
-	return dsnameLSym(Linksym(s), off, t)
+	off = dsymptr(nsym, off, lsym, 0)
+	off = duintptr(nsym, off, uint64(len))
+	duintptr(nsym, off, uint64(len))
 }
 
-func dsnameLSym(s *obj.LSym, off int, t string) int {
+func dsname(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 {
-	return dsymptrLSym(Linksym(s), off, Linksym(x), xoff)
-}
-
-func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+func dsymptr(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 {
+func dsymptrOff(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
 	s.WriteOff(Ctxt, int64(off), x, int64(xoff))
 	off += 4
 	return off
 }
 
-func dsymptrWeakOffLSym(s *obj.LSym, off int, x *obj.LSym) int {
+func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int {
 	s.WriteWeakOff(Ctxt, int64(off), x, 0)
 	off += 4
 	return off
@@ -367,7 +372,7 @@ func gdata(nam *Node, nr *Node, wid int) {
 	if nam.Sym == nil {
 		Fatalf("gdata nil nam sym")
 	}
-	s := Linksym(nam.Sym)
+	s := nam.Sym.Linksym()
 
 	switch nr.Op {
 	case OLITERAL:
@@ -403,7 +408,7 @@ func gdata(nam *Node, nr *Node, wid int) {
 		case string:
 			symdata := stringsym(u)
 			s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
-			s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(u)))
+			s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthptr, int64(len(u)))
 
 		default:
 			Fatalf("gdata unhandled OLITERAL %v", nr)
@@ -414,13 +419,13 @@ func gdata(nam *Node, nr *Node, wid int) {
 			Fatalf("gdata ADDR left op %v", nr.Left.Op)
 		}
 		to := nr.Left
-		s.WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
+		s.WriteAddr(Ctxt, nam.Xoffset, wid, to.Sym.Linksym(), to.Xoffset)
 
 	case ONAME:
-		if nr.Class != PFUNC {
-			Fatalf("gdata NAME not PFUNC %d", nr.Class)
+		if nr.Class() != PFUNC {
+			Fatalf("gdata NAME not PFUNC %d", nr.Class())
 		}
-		s.WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
+		s.WriteAddr(Ctxt, nam.Xoffset, wid, funcsym(nr.Sym).Linksym(), nr.Xoffset)
 
 	default:
 		Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
index bd56506..09442b5 100644
--- a/src/cmd/compile/internal/gc/opnames.go
+++ b/src/cmd/compile/internal/gc/opnames.go
@@ -33,7 +33,6 @@ var opnames = []string{
 	OAS2MAPR:         "AS2MAPR",
 	OAS2DOTTYPE:      "AS2DOTTYPE",
 	OASOP:            "ASOP",
-	OASWB:            "ASWB",
 	OCALL:            "CALL",
 	OCALLFUNC:        "CALLFUNC",
 	OCALLMETH:        "CALLMETH",
@@ -125,6 +124,7 @@ var opnames = []string{
 	OFALL:            "FALL",
 	OXFALL:           "XFALL",
 	OFOR:             "FOR",
+	OFORUNTIL:        "FORUNTIL",
 	OGOTO:            "GOTO",
 	OIF:              "IF",
 	OLABEL:           "LABEL",
@@ -153,17 +153,7 @@ var opnames = []string{
 	OVARKILL:         "VARKILL",
 	OVARLIVE:         "VARLIVE",
 	OINDREGSP:        "INDREGSP",
-	OCMP:             "CMP",
-	ODEC:             "DEC",
-	OINC:             "INC",
-	OEXTEND:          "EXTEND",
-	OHMUL:            "HMUL",
-	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 e3d65e5..cdda2f3 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -5,6 +5,8 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"fmt"
 )
 
@@ -58,7 +60,7 @@ func order(fn *Node) {
 // Ordertemp allocates a new temporary with the given type,
 // pushes it onto the temp stack, and returns it.
 // If clear is true, ordertemp emits code to zero the temporary.
-func ordertemp(t *Type, order *Order, clear bool) *Node {
+func ordertemp(t *types.Type, order *Order, clear bool) *Node {
 	var_ := temp(t)
 	if clear {
 		a := nod(OAS, var_, nil)
@@ -82,7 +84,7 @@ func ordertemp(t *Type, order *Order, clear bool) *Node {
 // (The other candidate would be map access, but map access
 // returns a pointer to the result data instead of taking a pointer
 // to be filled in.)
-func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node {
+func ordercopyexpr(n *Node, t *types.Type, order *Order, clear int) *Node {
 	var_ := ordertemp(t, order, clear != 0)
 	a := nod(OAS, var_, n)
 	a = typecheck(a, Etop)
@@ -176,19 +178,46 @@ func ordersafeexpr(n *Node, order *Order) *Node {
 // because we emit explicit VARKILL instructions marking the end of those
 // temporaries' lifetimes.
 func isaddrokay(n *Node) bool {
-	return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || n.IsAutoTmp())
+	return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp())
 }
 
 // Orderaddrtemp ensures that n is okay to pass by address to runtime routines.
 // If the original argument n is not okay, orderaddrtemp creates a tmp, emits
 // tmp = n, and then returns tmp.
+// The result of orderaddrtemp MUST be assigned back to n, e.g.
+// 	n.Left = orderaddrtemp(n.Left, order)
 func orderaddrtemp(n *Node, order *Order) *Node {
+	if consttype(n) >= 0 {
+		// TODO: expand this to all static composite literal nodes?
+		n = defaultlit(n, nil)
+		dowidth(n.Type)
+		vstat := staticname(n.Type)
+		vstat.Name.SetReadonly(true)
+		var out []*Node
+		staticassign(vstat, n, &out)
+		if out != nil {
+			Fatalf("staticassign of const generated code: %+v", n)
+		}
+		vstat = typecheck(vstat, Erv)
+		return vstat
+	}
 	if isaddrokay(n) {
 		return n
 	}
 	return ordercopyexpr(n, n.Type, order, 0)
 }
 
+// ordermapkeytemp prepares n to be a key in a map runtime call and returns n.
+// It should only be used for map runtime calls which have *_fast* versions.
+func ordermapkeytemp(t *types.Type, n *Node, order *Order) *Node {
+	// Most map calls need to take the address of the key.
+	// Exception: map*_fast* calls. See golang.org/issue/19015.
+	if mapfast(t) == mapslow {
+		return orderaddrtemp(n, order)
+	}
+	return n
+}
+
 type ordermarker int
 
 // Marktemp returns the top of the temporary variable stack.
@@ -210,9 +239,9 @@ func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
 
 	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
+		if n.Name.Keepalive() {
+			n.Name.SetKeepalive(false)
+			n.SetAddrtaken(true) // ensure SSA keeps the n variable
 			kill = nod(OVARLIVE, n, nil)
 			kill = typecheck(kill, Etop)
 			*out = append(*out, kill)
@@ -286,6 +315,14 @@ func orderstmtinplace(n *Node) *Node {
 
 // Orderinit moves n's init list to order->out.
 func orderinit(n *Node, order *Order) {
+	if n.mayBeShared() {
+		// For concurrency safety, don't mutate potentially shared nodes.
+		// First, ensure that no work is required here.
+		if n.Ninit.Len() > 0 {
+			Fatalf("orderinit shared node with ninit")
+		}
+		return
+	}
 	orderstmtlist(n.Ninit, order)
 	n.Ninit.Set(nil)
 }
@@ -354,33 +391,36 @@ func ordercall(n *Node, order *Order) {
 	ordercallargs(&n.List, order)
 
 	if n.Op == OCALLFUNC {
-		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
+		keepAlive := func(i int) {
+			// If 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 == nil {
-				break
+			xp := n.List.Addr(i)
+			for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
+				xp = &(*xp).Left
 			}
-			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 x.Type.IsPtr() {
+				x = ordercopyexpr(x, x.Type, order, 0)
+				x.Name.SetKeepalive(true)
+				*xp = x
+			}
+		}
+
+		for i, t := range n.Left.Type.Params().FieldSlice() {
+			// Check for "unsafe-uintptr" tag provided by escape analysis.
+			if t.Isddd() && !n.Isddd() {
+				if t.Note == uintptrEscapesTag {
+					for ; i < n.List.Len(); i++ {
+						keepAlive(i)
+					}
 				}
-				x := *xp
-				if x.Type.IsPtr() {
-					x = ordercopyexpr(x, x.Type, order, 0)
-					x.Name.Keepalive = true
-					*xp = x
+			} else {
+				if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
+					keepAlive(i)
 				}
 			}
-			next := it.Next()
-			if next == nil && t.Isddd && t.Note == uintptrEscapesTag {
-				next = t
-			}
-			t = next
 		}
 	}
 }
@@ -400,9 +440,6 @@ func ordercall(n *Node, order *Order) {
 // cases they are also typically registerizable, so not much harm done.
 // And this only applies to the multiple-assignment form.
 // We could do a more precise analysis if needed, like in walk.go.
-//
-// Ordermapassign also inserts these temporaries if needed for
-// calling writebarrierfat with a pointer to n->right.
 func ordermapassign(n *Node, order *Order) {
 	switch n.Op {
 	default:
@@ -411,17 +448,6 @@ func ordermapassign(n *Node, order *Order) {
 	case OAS:
 		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 needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr) && n.Right != nil && !isaddrokay(n.Right) {
-			m := n.Left
-			n.Left = ordertemp(m.Type, order, false)
-			a := nod(OAS, m, n.Left)
-			a = typecheck(a, Etop)
-			order.out = append(order.out, a)
-		}
-
 	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
 		var post []*Node
 		var m *Node
@@ -493,7 +519,7 @@ func orderstmt(n *Node, order *Order) {
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 		switch n.Op {
-		case OAS2, OAS2DOTTYPE:
+		case OAS2:
 			ordermapassign(n, order)
 		default:
 			order.out = append(order.out, n)
@@ -510,7 +536,7 @@ func orderstmt(n *Node, order *Order) {
 
 		n.Left = orderexpr(n.Left, order, nil)
 		n.Left = ordersafeexpr(n.Left, order)
-		tmp1 := treecopy(n.Left, 0)
+		tmp1 := treecopy(n.Left, src.NoXPos)
 		if tmp1.Op == OINDEXMAP {
 			tmp1.Etype = 0 // now an rvalue not an lvalue
 		}
@@ -524,7 +550,7 @@ func orderstmt(n *Node, order *Order) {
 		ordermapassign(n, order)
 		cleantemp(t, order)
 
-	// Special: make sure key is addressable,
+	// Special: make sure key is addressable if needed,
 	// and make sure OINDEXMAP is not copied out.
 	case OAS2MAPR:
 		t := marktemp(order)
@@ -538,8 +564,8 @@ func orderstmt(n *Node, order *Order) {
 		if r.Right.Op == OARRAYBYTESTR {
 			r.Right.Op = OARRAYBYTESTRTMP
 		}
-		r.Right = orderaddrtemp(r.Right, order)
-		ordermapassign(n, order)
+		r.Right = ordermapkeytemp(r.Left.Type, r.Right, order)
+		orderokas2(n, order)
 		cleantemp(t, order)
 
 	// Special: avoid copy of func call n->rlist->n.
@@ -548,7 +574,7 @@ func orderstmt(n *Node, order *Order) {
 
 		orderexprlist(n.List, order)
 		ordercall(n.Rlist.First(), order)
-		ordermapassign(n, order)
+		orderas2(n, order)
 		cleantemp(t, order)
 
 	// Special: use temporary variables to hold result,
@@ -559,31 +585,7 @@ func orderstmt(n *Node, order *Order) {
 
 		orderexprlist(n.List, order)
 		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
-
-		var tmp1, tmp2 *Node
-		if !isblank(n.List.First()) {
-			typ := n.Rlist.First().Type
-			tmp1 = ordertemp(typ, order, haspointers(typ))
-		}
-		if !isblank(n.List.Second()) && !n.List.Second().Type.IsBoolean() {
-			tmp2 = ordertemp(Types[TBOOL], order, false)
-		}
-
-		order.out = append(order.out, n)
-
-		if tmp1 != nil {
-			r := nod(OAS, n.List.First(), tmp1)
-			r = typecheck(r, Etop)
-			ordermapassign(r, order)
-			n.List.SetIndex(0, tmp1)
-		}
-		if tmp2 != nil {
-			r := okas(n.List.Second(), tmp2)
-			r = typecheck(r, Etop)
-			ordermapassign(r, order)
-			n.List.SetIndex(1, tmp2)
-		}
-
+		orderokas2(n, order)
 		cleantemp(t, order)
 
 	// Special: use temporary variables to hold result,
@@ -594,8 +596,8 @@ func orderstmt(n *Node, order *Order) {
 		orderexprlist(n.List, order)
 		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()))
-		tmp2 := ordertemp(Types[TBOOL], order, false)
+		tmp1 := ordertemp(ch.Elem(), order, types.Haspointers(ch.Elem()))
+		tmp2 := ordertemp(types.Types[TBOOL], order, false)
 		order.out = append(order.out, n)
 		r := nod(OAS, n.List.First(), tmp1)
 		r = typecheck(r, Etop)
@@ -603,7 +605,7 @@ func orderstmt(n *Node, order *Order) {
 		r = okas(n.List.Second(), tmp2)
 		r = typecheck(r, Etop)
 		ordermapassign(r, order)
-		n.List.Set([]*Node{tmp1, tmp2})
+		n.List.Set2(tmp1, tmp2)
 		cleantemp(t, order)
 
 	// Special: does not save n onto out.
@@ -642,10 +644,12 @@ func orderstmt(n *Node, order *Order) {
 		case ODELETE:
 			orderexprlist(n.Left.List, order)
 
-			t1 := marktemp(order)
-			np := n.Left.List.Addr(1) // map key
-			*np = ordercopyexpr(*np, (*np).Type, order, 0)
-			poptemp(t1, order)
+			if mapfast(n.Left.List.First().Type) == mapslow {
+				t1 := marktemp(order)
+				np := n.Left.List.Addr(1) // map key
+				*np = ordercopyexpr(*np, (*np).Type, order, 0)
+				poptemp(t1, order)
+			}
 
 		default:
 			ordercall(n.Left, order)
@@ -656,9 +660,9 @@ func orderstmt(n *Node, order *Order) {
 
 	case ODELETE:
 		t := marktemp(order)
-		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
+		n.List.SetFirst(orderexpr(n.List.First(), order, nil))
+		n.List.SetSecond(orderexpr(n.List.Second(), order, nil))
+		n.List.SetSecond(ordermapkeytemp(n.List.First().Type, n.List.Second(), order))
 		order.out = append(order.out, n)
 		cleantemp(t, order)
 
@@ -742,9 +746,9 @@ func orderstmt(n *Node, order *Order) {
 			// make copy.
 			r := n.Right
 
-			if r.Type.IsString() && r.Type != Types[TSTRING] {
+			if r.Type.IsString() && r.Type != types.Types[TSTRING] {
 				r = nod(OCONV, r, nil)
-				r.Type = Types[TSTRING]
+				r.Type = types.Types[TSTRING]
 				r = typecheck(r, Erv)
 			}
 
@@ -758,7 +762,7 @@ func orderstmt(n *Node, order *Order) {
 			n.Right = ordercopyexpr(r, r.Type, order, 0)
 
 			// n->alloc is the temp for the iterator.
-			prealloc[n] = ordertemp(Types[TUINT8], order, true)
+			prealloc[n] = ordertemp(types.Types[TUINT8], order, true)
 		}
 		for i := range n.List.Slice() {
 			n.List.SetIndex(i, orderexprinplace(n.List.Index(i), order))
@@ -801,15 +805,15 @@ func orderstmt(n *Node, order *Order) {
 			if r != nil {
 				switch r.Op {
 				default:
-					yyerror("unknown op in select %v", r.Op)
 					Dump("select case", r)
+					Fatalf("unknown op in select %v", r.Op)
 
 				// 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 {
+					if r.Colas() {
 						i := 0
 						if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
 							i++
@@ -823,8 +827,8 @@ func orderstmt(n *Node, order *Order) {
 					}
 
 					if r.Ninit.Len() != 0 {
-						yyerror("ninit on select recv")
 						dumplist("ninit", r.Ninit)
+						Fatalf("ninit on select recv")
 					}
 
 					// case x = <-c
@@ -853,13 +857,13 @@ func orderstmt(n *Node, order *Order) {
 						// the conversion happens in the OAS instead.
 						tmp1 = r.Left
 
-						if r.Colas {
+						if r.Colas() {
 							tmp2 = nod(ODCL, tmp1, nil)
 							tmp2 = typecheck(tmp2, Etop)
 							n2.Ninit.Append(tmp2)
 						}
 
-						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, haspointers(r.Right.Left.Type.Elem()))
+						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, types.Haspointers(r.Right.Left.Type.Elem()))
 						tmp2 = nod(OAS, tmp1, r.Left)
 						tmp2 = typecheck(tmp2, Etop)
 						n2.Ninit.Append(tmp2)
@@ -870,13 +874,13 @@ func orderstmt(n *Node, order *Order) {
 					}
 					if r.List.Len() != 0 {
 						tmp1 = r.List.First()
-						if r.Colas {
+						if r.Colas() {
 							tmp2 = nod(ODCL, tmp1, nil)
 							tmp2 = typecheck(tmp2, Etop)
 							n2.Ninit.Append(tmp2)
 						}
 
-						r.List.Set1(ordertemp(Types[TBOOL], order, false))
+						r.List.Set1(ordertemp(types.Types[TBOOL], order, false))
 						tmp2 = okas(tmp1, r.List.First())
 						tmp2 = typecheck(tmp2, Etop)
 						n2.Ninit.Append(tmp2)
@@ -885,8 +889,8 @@ func orderstmt(n *Node, order *Order) {
 
 				case OSEND:
 					if r.Ninit.Len() != 0 {
-						yyerror("ninit on select send")
 						dumplist("ninit", r.Ninit)
+						Fatalf("ninit on select send")
 					}
 
 					// case c <- x
@@ -924,7 +928,13 @@ func orderstmt(n *Node, order *Order) {
 
 		n.Left = orderexpr(n.Left, order, nil)
 		n.Right = orderexpr(n.Right, order, nil)
-		n.Right = orderaddrtemp(n.Right, order)
+		if instrumenting {
+			// Force copying to the stack so that (chan T)(nil) <- x
+			// is still instrumented as a read of x.
+			n.Right = ordercopyexpr(n.Right, n.Right.Type, order, 0)
+		} else {
+			n.Right = orderaddrtemp(n.Right, order)
+		}
 		order.out = append(order.out, n)
 		cleantemp(t, order)
 
@@ -1003,7 +1013,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 		orderexprlist(n.List, order)
 
 		if n.List.Len() > 5 {
-			t := typArray(Types[TSTRING], int64(n.List.Len()))
+			t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
 			prealloc[n] = ordertemp(t, order, false)
 		}
 
@@ -1071,9 +1081,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 			needCopy = true
 		}
 
-		// Map calls need to take the address of the key.
-		n.Right = orderaddrtemp(n.Right, order)
-
+		n.Right = ordermapkeytemp(n.Left.Type, n.Right, order)
 		if needCopy {
 			n = ordercopyexpr(n, n.Type, order, 0)
 		}
@@ -1111,7 +1119,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 		var s []*Node
 
 		cleantempnopop(mark, order, &s)
-		n.Right.Ninit.Prepend(s...)
+		n.Right = addinit(n.Right, s)
 		n.Right = orderexprinplace(n.Right, order)
 
 	case OCALLFUNC,
@@ -1157,8 +1165,8 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 		}
 
 	case OCLOSURE:
-		if n.Noescape && n.Func.Cvars.Len() > 0 {
-			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
+		if n.Noescape() && n.Func.Cvars.Len() > 0 {
+			prealloc[n] = ordertemp(types.Types[TUINT8], order, false) // walk will fill in correct type
 		}
 
 	case OARRAYLIT, OSLICELIT, OCALLPART:
@@ -1166,12 +1174,12 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 		n.Right = orderexpr(n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
-		if n.Noescape {
-			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
+		if n.Noescape() {
+			prealloc[n] = ordertemp(types.Types[TUINT8], order, false) // walk will fill in correct type
 		}
 
 	case ODDDARG:
-		if n.Noescape {
+		if n.Noescape() {
 			// The ddd argument does not live beyond the call it is created for.
 			// Allocate a temporary that will be cleaned up when this statement
 			// completes. We could be more aggressive and try to arrange for it
@@ -1216,3 +1224,68 @@ func okas(ok, val *Node) *Node {
 	}
 	return nod(OAS, ok, val)
 }
+
+// orderas2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
+// The caller should order the right-hand side of the assignment before calling orderas2.
+// It rewrites,
+// 	a, b, a = ...
+// as
+//	tmp1, tmp2, tmp3 = ...
+// 	a, b, a = tmp1, tmp2, tmp3
+// This is necessary to ensure left to right assignment order.
+func orderas2(n *Node, order *Order) {
+	tmplist := []*Node{}
+	left := []*Node{}
+	for _, l := range n.List.Slice() {
+		if !isblank(l) {
+			tmp := ordertemp(l.Type, order, types.Haspointers(l.Type))
+			tmplist = append(tmplist, tmp)
+			left = append(left, l)
+		}
+	}
+
+	order.out = append(order.out, n)
+
+	as := nod(OAS2, nil, nil)
+	as.List.Set(left)
+	as.Rlist.Set(tmplist)
+	as = typecheck(as, Etop)
+	orderstmt(as, order)
+
+	ti := 0
+	for ni, l := range n.List.Slice() {
+		if !isblank(l) {
+			n.List.SetIndex(ni, tmplist[ti])
+			ti++
+		}
+	}
+}
+
+// orderokas2 orders OAS2 with ok.
+// Just like orderas2(), this also adds temporaries to ensure left-to-right assignment.
+func orderokas2(n *Node, order *Order) {
+	var tmp1, tmp2 *Node
+	if !isblank(n.List.First()) {
+		typ := n.Rlist.First().Type
+		tmp1 = ordertemp(typ, order, types.Haspointers(typ))
+	}
+
+	if !isblank(n.List.Second()) {
+		tmp2 = ordertemp(types.Types[TBOOL], order, false)
+	}
+
+	order.out = append(order.out, n)
+
+	if tmp1 != nil {
+		r := nod(OAS, n.List.First(), tmp1)
+		r = typecheck(r, Etop)
+		ordermapassign(r, order)
+		n.List.SetFirst(tmp1)
+	}
+	if tmp2 != nil {
+		r := okas(n.List.Second(), tmp2)
+		r = typecheck(r, Etop)
+		ordermapassign(r, order)
+		n.List.SetSecond(tmp2)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index dde28f6..66e4a10 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -6,160 +6,32 @@ package gc
 
 import (
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
+	"cmd/internal/dwarf"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"cmd/internal/sys"
 	"fmt"
+	"math/rand"
 	"sort"
-	"strings"
+	"sync"
+	"time"
 )
 
 // "Portable" code generation.
 
-var makefuncdatasym_nsym int
-
-func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
-	sym := lookupN(nameprefix, makefuncdatasym_nsym)
-	makefuncdatasym_nsym++
-	pnod := newname(sym)
-	pnod.Class = PEXTERN
-	p := Gins(obj.AFUNCDATA, nil, pnod)
-	Addrconst(&p.From, funcdatakind)
-	return sym
-}
-
-// gvardef inserts a VARDEF for n into the instruction stream.
-// VARDEF is an annotation for the liveness analysis, marking a place
-// where a complete initialization (definition) of a variable begins.
-// Since the liveness analysis can see initialization of single-word
-// variables quite easy, gvardef is usually only called for multi-word
-// or 'fat' variables, those satisfying isfat(n->type).
-// However, gvardef is also called when a non-fat variable is initialized
-// via a block move; the only time this happens is when you have
-//	return f()
-// for a function with multiple return values exactly matching the return
-// types of the current function.
-//
-// A 'VARDEF x' annotation in the instruction stream tells the liveness
-// analysis to behave as though the variable x is being initialized at that
-// point in the instruction stream. The VARDEF must appear before the
-// actual (multi-instruction) initialization, and it must also appear after
-// any uses of the previous value, if any. For example, if compiling:
-//
-//	x = x[1:]
-//
-// it is important to generate code like:
-//
-//	base, len, cap = pieces of x[1:]
-//	VARDEF x
-//	x = {base, len, cap}
-//
-// If instead the generated code looked like:
-//
-//	VARDEF x
-//	base, len, cap = pieces of x[1:]
-//	x = {base, len, cap}
-//
-// then the liveness analysis would decide the previous value of x was
-// unnecessary even though it is about to be used by the x[1:] computation.
-// Similarly, if the generated code looked like:
-//
-//	base, len, cap = pieces of x[1:]
-//	x = {base, len, cap}
-//	VARDEF x
-//
-// then the liveness analysis will not preserve the new value of x, because
-// the VARDEF appears to have "overwritten" it.
-//
-// VARDEF is a bit of a kludge to work around the fact that the instruction
-// stream is working on single-word values but the liveness analysis
-// wants to work on individual variables, which might be multi-word
-// aggregates. It might make sense at some point to look into letting
-// the liveness analysis work on single-word values as well, although
-// there are complications around interface values, slices, and strings,
-// all of which cannot be treated as individual words.
-//
-// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
-// even if its address has been taken. That is, a VARKILL annotation asserts
-// that its argument is certainly dead, for use when the liveness analysis
-// would not otherwise be able to deduce that fact.
-
-func gvardefx(n *Node, as obj.As) {
-	if n == nil {
-		Fatalf("gvardef nil")
-	}
-	if n.Op != ONAME {
-		yyerror("gvardef %#v; %v", n.Op, n)
-		return
-	}
-
-	switch n.Class {
-	case PAUTO, PPARAM, PPARAMOUT:
-		if !n.Used {
-			Prog(obj.ANOP)
-			return
-		}
-
-		if as == obj.AVARLIVE {
-			Gins(as, n, nil)
-		} else {
-			Gins(as, nil, n)
-		}
-	}
-}
-
-func Gvardef(n *Node) {
-	gvardefx(n, obj.AVARDEF)
-}
-
-func Gvarkill(n *Node) {
-	gvardefx(n, obj.AVARKILL)
-}
-
-func Gvarlive(n *Node) {
-	gvardefx(n, obj.AVARLIVE)
-}
-
-func removevardef(firstp *obj.Prog) {
-	// At VARKILLs, zero variable if it is ambiguously live.
-	// After the VARKILL anything this variable references
-	// might be collected. If it were to become live again later,
-	// the GC will see references to already-collected objects.
-	// See issue 20029.
-	for p := firstp; p != nil; p = p.Link {
-		if p.As != obj.AVARKILL {
-			continue
-		}
-		n := p.To.Node.(*Node)
-		if !n.Name.Needzero {
-			continue
-		}
-		if n.Class != PAUTO {
-			Fatalf("zero of variable which isn't PAUTO %v", n)
-		}
-		if n.Type.Size()%int64(Widthptr) != 0 {
-			Fatalf("zero of variable not a multiple of ptr size %v", n)
-		}
-		Thearch.ZeroAuto(n, p)
-	}
-
-	for p := firstp; p != nil; p = p.Link {
-
-		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
-			p.Link = p.Link.Link
-		}
-		if p.To.Type == obj.TYPE_BRANCH {
-			for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL || p.To.Val.(*obj.Prog).As == obj.AVARLIVE) {
-				p.To.Val = p.To.Val.(*obj.Prog).Link
-			}
-		}
-	}
-}
+var (
+	nBackendWorkers int     // number of concurrent backend workers, set by a compiler flag
+	compilequeue    []*Node // functions waiting to be compiled
+)
 
 func emitptrargsmap() {
-	if Curfn.Func.Nname.Sym.Name == "_" {
+	if Curfn.funcname() == "_" {
 		return
 	}
-	sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
+	sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.funcname()))
+	lsym := sym.Linksym()
 
 	nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
 	bv := bvalloc(int32(nptr) * 2)
@@ -167,8 +39,8 @@ func emitptrargsmap() {
 	if Curfn.Type.Results().NumFields() > 0 {
 		nbitmap = 2
 	}
-	off := duint32(sym, 0, uint32(nbitmap))
-	off = duint32(sym, off, uint32(bv.n))
+	off := duint32(lsym, 0, uint32(nbitmap))
+	off = duint32(lsym, off, uint32(bv.n))
 	var xoffset int64
 	if Curfn.IsMethod() {
 		xoffset = 0
@@ -180,14 +52,14 @@ func emitptrargsmap() {
 		onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
 	}
 
-	off = dbvec(sym, off, bv)
+	off = dbvec(lsym, off, bv)
 	if Curfn.Type.Results().NumFields() > 0 {
 		xoffset = 0
 		onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
-		off = dbvec(sym, off, bv)
+		off = dbvec(lsym, off, bv)
 	}
 
-	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
+	ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL)
 }
 
 // cmpstackvarlt reports whether the stack variable a sorts before b.
@@ -201,26 +73,26 @@ 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 == PAUTO) != (b.Class == PAUTO) {
-		return b.Class == PAUTO
+	if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
+		return b.Class() == PAUTO
 	}
 
-	if a.Class != PAUTO {
+	if a.Class() != PAUTO {
 		return a.Xoffset < b.Xoffset
 	}
 
-	if a.Used != b.Used {
-		return a.Used
+	if a.Name.Used() != b.Name.Used() {
+		return a.Name.Used()
 	}
 
-	ap := haspointers(a.Type)
-	bp := haspointers(b.Type)
+	ap := types.Haspointers(a.Type)
+	bp := types.Haspointers(b.Type)
 	if ap != bp {
 		return ap
 	}
 
-	ap = a.Name.Needzero
-	bp = b.Name.Needzero
+	ap = a.Name.Needzero()
+	bp = b.Name.Needzero()
 	if ap != bp {
 		return ap
 	}
@@ -239,24 +111,22 @@ 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] }
 
-var scratchFpMem *Node
-
-func (s *ssaExport) AllocFrame(f *ssa.Func) {
-	Stksize = 0
-	stkptrsize = 0
+func (s *ssafn) AllocFrame(f *ssa.Func) {
+	s.stksize = 0
+	s.stkptrsize = 0
+	fn := s.curfn.Func
 
 	// Mark the PAUTO's unused.
-	for _, ln := range Curfn.Func.Dcl {
-		if ln.Class == PAUTO {
-			ln.Used = false
+	for _, ln := range fn.Dcl {
+		if ln.Class() == PAUTO {
+			ln.Name.SetUsed(false)
 		}
 	}
 
 	for _, l := range f.RegAlloc {
 		if ls, ok := l.(ssa.LocalSlot); ok {
-			ls.N.(*Node).Used = true
+			ls.N.(*Node).Name.SetUsed(true)
 		}
-
 	}
 
 	scratchUsed := false
@@ -264,9 +134,13 @@ func (s *ssaExport) AllocFrame(f *ssa.Func) {
 		for _, v := range b.Values {
 			switch a := v.Aux.(type) {
 			case *ssa.ArgSymbol:
-				a.Node.(*Node).Used = true
+				n := a.Node.(*Node)
+				// Don't modify nodfp; it is a global.
+				if n != nodfp {
+					n.Name.SetUsed(true)
+				}
 			case *ssa.AutoSymbol:
-				a.Node.(*Node).Used = true
+				a.Node.(*Node).Name.SetUsed(true)
 			}
 
 			if !scratchUsed {
@@ -275,199 +149,259 @@ func (s *ssaExport) AllocFrame(f *ssa.Func) {
 		}
 	}
 
-	if f.Config.NeedsFpScratch {
-		scratchFpMem = temp(Types[TUINT64])
-		scratchFpMem.Used = scratchUsed
+	if f.Config.NeedsFpScratch && scratchUsed {
+		s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
 	}
 
-	sort.Sort(byStackVar(Curfn.Func.Dcl))
+	sort.Sort(byStackVar(fn.Dcl))
 
 	// Reassign stack offsets of the locals that are used.
-	for i, n := range Curfn.Func.Dcl {
-		if n.Op != ONAME || n.Class != PAUTO {
+	for i, n := range fn.Dcl {
+		if n.Op != ONAME || n.Class() != PAUTO {
 			continue
 		}
-		if !n.Used {
-			Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
+		if !n.Name.Used() {
+			fn.Dcl = fn.Dcl[:i]
 			break
 		}
 
 		dowidth(n.Type)
 		w := n.Type.Width
-		if w >= Thearch.MAXWIDTH || w < 0 {
+		if w >= thearch.MAXWIDTH || w < 0 {
 			Fatalf("bad width")
 		}
-		Stksize += w
-		Stksize = Rnd(Stksize, int64(n.Type.Align))
-		if haspointers(n.Type) {
-			stkptrsize = Stksize
-		}
-		if Thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
-			Stksize = Rnd(Stksize, int64(Widthptr))
+		s.stksize += w
+		s.stksize = Rnd(s.stksize, int64(n.Type.Align))
+		if types.Haspointers(n.Type) {
+			s.stkptrsize = s.stksize
 		}
-		if Stksize >= 1<<31 {
-			setlineno(Curfn)
-			yyerror("stack frame too large (>2GB)")
+		if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
+			s.stksize = Rnd(s.stksize, int64(Widthptr))
 		}
-
-		n.Xoffset = -Stksize
+		n.Xoffset = -s.stksize
 	}
 
-	Stksize = Rnd(Stksize, int64(Widthreg))
-	stkptrsize = Rnd(stkptrsize, int64(Widthreg))
+	s.stksize = Rnd(s.stksize, int64(Widthreg))
+	s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
 }
 
 func compile(fn *Node) {
-	if Newproc == nil {
-		Newproc = Sysfunc("newproc")
-		Deferproc = Sysfunc("deferproc")
-		Deferreturn = Sysfunc("deferreturn")
-		panicindex = Sysfunc("panicindex")
-		panicslice = Sysfunc("panicslice")
-		panicdivide = Sysfunc("panicdivide")
-		growslice = Sysfunc("growslice")
-		panicdottype = Sysfunc("panicdottype")
-		panicnildottype = Sysfunc("panicnildottype")
-		assertE2I = Sysfunc("assertE2I")
-		assertE2I2 = Sysfunc("assertE2I2")
-		assertI2I = Sysfunc("assertI2I")
-		assertI2I2 = Sysfunc("assertI2I2")
-	}
-
-	defer func(lno int32) {
-		lineno = lno
-	}(setlineno(fn))
-
 	Curfn = fn
-	dowidth(Curfn.Type)
+	dowidth(fn.Type)
 
 	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)
-			return
-		}
-
 		emitptrargsmap()
 		return
 	}
 
 	saveerrors()
 
-	if Curfn.Type.FuncType().Outnamed {
-		// add clearing of the output parameters
-		for _, t := range Curfn.Type.Results().Fields().Slice() {
-			if t.Nname != nil {
-				n := nod(OAS, t.Nname, nil)
-				n = typecheck(n, Etop)
-				Curfn.Nbody.Prepend(n)
-			}
-		}
-	}
-
-	order(Curfn)
+	order(fn)
 	if nerrors != 0 {
 		return
 	}
 
-	hasdefer = false
-	walk(Curfn)
+	walk(fn)
 	if nerrors != 0 {
 		return
 	}
 	if instrumenting {
-		instrument(Curfn)
-	}
-	if nerrors != 0 {
-		return
+		instrument(fn)
 	}
 
-	// Build an SSA backend function.
-	ssafn := buildssa(Curfn)
-	if nerrors != 0 {
-		return
+	// From this point, there should be no uses of Curfn. Enforce that.
+	Curfn = nil
+
+	// Set up the function's LSym early to avoid data races with the assemblers.
+	fn.Func.initLSym()
+
+	if compilenow() {
+		compileSSA(fn, 0)
+	} else {
+		compilequeue = append(compilequeue, fn)
 	}
+}
 
-	newplist()
+// compilenow reports whether to compile immediately.
+// If functions are not compiled immediately,
+// they are enqueued in compilequeue,
+// which is drained by compileFunctions.
+func compilenow() bool {
+	return nBackendWorkers == 1 && Debug_compilelater == 0
+}
 
-	setlineno(Curfn)
+const maxStackSize = 1 << 31
+
+// compileSSA builds an SSA backend function,
+// uses it to generate a plist,
+// and flushes that plist to machine code.
+// worker indicates which of the backend workers is doing the processing.
+func compileSSA(fn *Node, worker int) {
+	ssafn := buildssa(fn, worker)
+	pp := newProgs(fn, worker)
+	genssa(ssafn, pp)
+	if pp.Text.To.Offset < maxStackSize {
+		pp.Flush()
+	} else {
+		largeStackFramesMu.Lock()
+		largeStackFrames = append(largeStackFrames, fn.Pos)
+		largeStackFramesMu.Unlock()
+	}
+	// fieldtrack must be called after pp.Flush. See issue 20014.
+	fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
+	pp.Free()
+}
 
-	nam := Curfn.Func.Nname
-	if isblank(nam) {
-		nam = nil
-	}
-	ptxt := Gins(obj.ATEXT, nam, nil)
-	ptxt.From3 = new(obj.Addr)
-	if fn.Func.Dupok {
-		ptxt.From3.Offset |= obj.DUPOK
-	}
-	if fn.Func.Wrapper {
-		ptxt.From3.Offset |= obj.WRAPPER
-	}
-	if fn.Func.NoFramePointer {
-		ptxt.From3.Offset |= obj.NOFRAME
-	}
-	if fn.Func.Needctxt {
-		ptxt.From3.Offset |= obj.NEEDCTXT
-	}
-	if fn.Func.Pragma&Nosplit != 0 {
-		ptxt.From3.Offset |= obj.NOSPLIT
-	}
-	if fn.Func.ReflectMethod {
-		ptxt.From3.Offset |= obj.REFLECTMETHOD
-	}
-	if fn.Func.Pragma&Systemstack != 0 {
-		ptxt.From.Sym.Set(obj.AttrCFunc, true)
+func init() {
+	if raceEnabled {
+		rand.Seed(time.Now().UnixNano())
 	}
+}
 
-	// Clumsy but important.
-	// See test/recover.go for test cases and src/reflect/value.go
-	// for the actual functions being considered.
-	if myimportpath == "reflect" {
-		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
-			ptxt.From3.Offset |= obj.WRAPPER
+// compileFunctions compiles all functions in compilequeue.
+// It fans out nBackendWorkers to do the work
+// and waits for them to complete.
+func compileFunctions() {
+	if len(compilequeue) != 0 {
+		sizeCalculationDisabled = true // not safe to calculate sizes concurrently
+		if raceEnabled {
+			// Randomize compilation order to try to shake out races.
+			tmp := make([]*Node, len(compilequeue))
+			perm := rand.Perm(len(compilequeue))
+			for i, v := range perm {
+				tmp[v] = compilequeue[i]
+			}
+			copy(compilequeue, tmp)
+		} else {
+			// Compile the longest functions first,
+			// since they're most likely to be the slowest.
+			// This helps avoid stragglers.
+			obj.SortSlice(compilequeue, func(i, j int) bool {
+				return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
+			})
 		}
-	}
-
-	gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
-	gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
-
-	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)
+		var wg sync.WaitGroup
+		c := make(chan *Node, nBackendWorkers)
+		for i := 0; i < nBackendWorkers; i++ {
+			wg.Add(1)
+			go func(worker int) {
+				for fn := range c {
+					compileSSA(fn, worker)
+				}
+				wg.Done()
+			}(i)
 		}
-		sort.Sort(symByName(trackSyms))
-		for _, sym := range trackSyms {
-			gtrack(sym)
+		for _, fn := range compilequeue {
+			c <- fn
 		}
+		close(c)
+		compilequeue = nil
+		wg.Wait()
+		sizeCalculationDisabled = false
 	}
+}
+
+func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope {
+	fn := curfn.(*Node)
+	if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
+		Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
+	}
+
+	var dwarfVars []*dwarf.Var
+	var varScopes []ScopeID
 
 	for _, n := range fn.Func.Dcl {
 		if n.Op != ONAME { // might be OTYPE or OLITERAL
 			continue
 		}
-		switch n.Class {
+
+		var name obj.AddrName
+		var abbrev int
+		offs := n.Xoffset
+
+		switch n.Class() {
 		case PAUTO:
-			if !n.Used {
-				continue
+			if !n.Name.Used() {
+				Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
+			}
+			name = obj.NAME_AUTO
+
+			abbrev = dwarf.DW_ABRV_AUTO
+			if Ctxt.FixedFrameSize() == 0 {
+				offs -= int64(Widthptr)
+			}
+			if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
+				offs -= int64(Widthptr)
 			}
-			fallthrough
+
 		case PPARAM, PPARAMOUT:
-			// The symbol is excluded later from debugging info if its name begins ".autotmp_", but the type is still necessary.
-			// See bugs #17644 and #17830 and cmd/internal/dwarf/dwarf.go
-			p := Gins(obj.ATYPE, n, nil)
-			p.From.Sym = obj.Linklookup(Ctxt, n.Sym.Name, 0)
-			p.To.Type = obj.TYPE_MEM
-			p.To.Name = obj.NAME_EXTERN
-			p.To.Sym = Linksym(ngotype(n))
+			name = obj.NAME_PARAM
+
+			abbrev = dwarf.DW_ABRV_PARAM
+			offs += Ctxt.FixedFrameSize()
+
+		default:
+			continue
 		}
+
+		gotype := ngotype(n).Linksym()
+		fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
+			Asym:    Ctxt.Lookup(n.Sym.Name),
+			Aoffset: int32(n.Xoffset),
+			Name:    name,
+			Gotype:  gotype,
+		})
+
+		if n.IsAutoTmp() {
+			continue
+		}
+
+		typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
+		dwarfVars = append(dwarfVars, &dwarf.Var{
+			Name:   n.Sym.Name,
+			Abbrev: abbrev,
+			Offset: int32(offs),
+			Type:   Ctxt.Lookup(typename),
+		})
+
+		var scope ScopeID
+		if !n.Name.Captured() && !n.Name.Byval() {
+			// n.Pos of captured variables is their first
+			// use in the closure but they should always
+			// be assigned to scope 0 instead.
+			// TODO(mdempsky): Verify this.
+			scope = findScope(fn.Func.Marks, n.Pos)
+		}
+
+		varScopes = append(varScopes, scope)
 	}
 
-	genssa(ssafn, ptxt, gcargs, gclocals)
-	ssafn.Free()
+	return assembleScopes(fnsym, fn, dwarfVars, varScopes)
+}
+
+// fieldtrack adds R_USEFIELD relocations to fnsym to record any
+// struct fields that it used.
+func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
+	if fnsym == nil {
+		return
+	}
+	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
+		return
+	}
+
+	trackSyms := make([]*types.Sym, 0, len(tracked))
+	for sym := range tracked {
+		trackSyms = append(trackSyms, sym)
+	}
+	sort.Sort(symByName(trackSyms))
+	for _, sym := range trackSyms {
+		r := obj.Addrel(fnsym)
+		r.Sym = sym.Linksym()
+		r.Type = objabi.R_USEFIELD
+	}
 }
 
-type symByName []*Sym
+type symByName []*types.Sym
 
 func (a symByName) Len() int           { return len(a) }
 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
index 44dc1db..d75c5b8 100644
--- a/src/cmd/compile/internal/gc/pgen_test.go
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -5,123 +5,146 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
 	"reflect"
 	"sort"
 	"testing"
 )
 
-func typeWithoutPointers() *Type {
-	return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 1}} // haspointers -> false
+func typeWithoutPointers() *types.Type {
+	t := types.New(TSTRUCT)
+	f := &types.Field{Type: types.New(TINT)}
+	t.SetFields([]*types.Field{f})
+	return t
 }
 
-func typeWithPointers() *Type {
-	return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 2}} // haspointers -> true
+func typeWithPointers() *types.Type {
+	t := types.New(TSTRUCT)
+	f := &types.Field{Type: types.New(TPTR64)}
+	t.SetFields([]*types.Field{f})
+	return t
+}
+
+func markUsed(n *Node) *Node {
+	n.Name.SetUsed(true)
+	return n
+}
+
+func markNeedZero(n *Node) *Node {
+	n.Name.SetNeedzero(true)
+	return n
+}
+
+func nodeWithClass(n Node, c Class) *Node {
+	n.SetClass(c)
+	n.Name = new(Name)
+	return &n
 }
 
 // Test all code paths for cmpstackvarlt.
 func TestCmpstackvar(t *testing.T) {
 	testdata := []struct {
-		a, b Node
+		a, b *Node
 		lt   bool
 	}{
 		{
-			Node{Class: PAUTO},
-			Node{Class: PFUNC},
+			nodeWithClass(Node{}, PAUTO),
+			nodeWithClass(Node{}, PFUNC),
 			false,
 		},
 		{
-			Node{Class: PFUNC},
-			Node{Class: PAUTO},
+			nodeWithClass(Node{}, PFUNC),
+			nodeWithClass(Node{}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PFUNC, Xoffset: 0},
-			Node{Class: PFUNC, Xoffset: 10},
+			nodeWithClass(Node{Xoffset: 0}, PFUNC),
+			nodeWithClass(Node{Xoffset: 10}, PFUNC),
 			true,
 		},
 		{
-			Node{Class: PFUNC, Xoffset: 20},
-			Node{Class: PFUNC, Xoffset: 10},
+			nodeWithClass(Node{Xoffset: 20}, PFUNC),
+			nodeWithClass(Node{Xoffset: 10}, PFUNC),
 			false,
 		},
 		{
-			Node{Class: PFUNC, Xoffset: 10},
-			Node{Class: PFUNC, Xoffset: 10},
+			nodeWithClass(Node{Xoffset: 10}, PFUNC),
+			nodeWithClass(Node{Xoffset: 10}, PFUNC),
 			false,
 		},
 		{
-			Node{Class: PPARAM, Xoffset: 10},
-			Node{Class: PPARAMOUT, Xoffset: 20},
+			nodeWithClass(Node{Xoffset: 10}, PPARAM),
+			nodeWithClass(Node{Xoffset: 20}, PPARAMOUT),
 			true,
 		},
 		{
-			Node{Class: PPARAMOUT, Xoffset: 10},
-			Node{Class: PPARAM, Xoffset: 20},
+			nodeWithClass(Node{Xoffset: 10}, PPARAMOUT),
+			nodeWithClass(Node{Xoffset: 20}, PPARAM),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Used: true},
-			Node{Class: PAUTO, Used: false},
+			markUsed(nodeWithClass(Node{}, PAUTO)),
+			nodeWithClass(Node{}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Used: false},
-			Node{Class: PAUTO, Used: true},
+			nodeWithClass(Node{}, PAUTO),
+			markUsed(nodeWithClass(Node{}, PAUTO)),
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: typeWithoutPointers()},
-			Node{Class: PAUTO, Type: typeWithPointers()},
+			nodeWithClass(Node{Type: typeWithoutPointers()}, PAUTO),
+			nodeWithClass(Node{Type: typeWithPointers()}, PAUTO),
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: typeWithPointers()},
-			Node{Class: PAUTO, Type: typeWithoutPointers()},
+			nodeWithClass(Node{Type: typeWithPointers()}, PAUTO),
+			nodeWithClass(Node{Type: typeWithoutPointers()}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}},
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: false}},
+			markNeedZero(nodeWithClass(Node{Type: &types.Type{}}, PAUTO)),
+			nodeWithClass(Node{Type: &types.Type{}, Name: &Name{}}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: false}},
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}},
+			nodeWithClass(Node{Type: &types.Type{}, Name: &Name{}}, PAUTO),
+			markNeedZero(nodeWithClass(Node{Type: &types.Type{}}, PAUTO)),
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}},
-			Node{Class: PAUTO, Type: &Type{Width: 2}, Name: &Name{}},
+			nodeWithClass(Node{Type: &types.Type{Width: 1}, Name: &Name{}}, PAUTO),
+			nodeWithClass(Node{Type: &types.Type{Width: 2}, Name: &Name{}}, PAUTO),
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{Width: 2}, Name: &Name{}},
-			Node{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}},
+			nodeWithClass(Node{Type: &types.Type{Width: 2}, Name: &Name{}}, PAUTO),
+			nodeWithClass(Node{Type: &types.Type{Width: 1}, Name: &Name{}}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
 			true,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
-			Node{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+			nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
 			false,
 		},
 	}
 	for _, d := range testdata {
-		got := cmpstackvarlt(&d.a, &d.b)
+		got := cmpstackvarlt(d.a, d.b)
 		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) {
+		if d.lt && cmpstackvarlt(d.b, d.a) {
 			t.Errorf("unexpected %#v < %#v", d.b, d.a)
 		}
 	}
@@ -129,41 +152,41 @@ func TestCmpstackvar(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{}},
-		{Class: PFUNC, Xoffset: 0, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
-		{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: 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{}},
-		{Class: PAUTO, Type: &Type{Width: 2}, Name: &Name{}, Sym: &Sym{}},
-		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
-		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Xoffset: 0, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Xoffset: 10, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Xoffset: 20, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		markUsed(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+		nodeWithClass(Node{Type: typeWithoutPointers(), Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+		markNeedZero(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+		nodeWithClass(Node{Type: &types.Type{Width: 1}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{Width: 2}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
 	}
 	want := []*Node{
-		{Class: PFUNC, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
-		{Class: PFUNC, Xoffset: 0, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
-		{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{}, Name: &Name{Needzero: true}, Sym: &Sym{}},
-		{Class: PAUTO, Type: &Type{Width: 2}, Name: &Name{}, Sym: &Sym{}},
-		{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}},
-		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
-		{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: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Xoffset: 0, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Xoffset: 10, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		nodeWithClass(Node{Xoffset: 20, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+		markUsed(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+		markNeedZero(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+		nodeWithClass(Node{Type: &types.Type{Width: 2}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{Width: 1}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+		nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+		nodeWithClass(Node{Type: typeWithoutPointers(), Sym: &types.Sym{}}, PAUTO),
 	}
 	// haspointers updates Type.Haspointers as a side effect, so
 	// exercise this function on all inputs so that reflect.DeepEqual
 	// doesn't produce false positives.
 	for i := range want {
-		haspointers(want[i].Type)
-		haspointers(inp[i].Type)
+		types.Haspointers(want[i].Type)
+		types.Haspointers(inp[i].Type)
 	}
 
 	sort.Sort(byStackVar(inp))
diff --git a/src/cmd/compile/internal/gc/phi.go b/src/cmd/compile/internal/gc/phi.go
index 0d4dbb5..0ce7a4b 100644
--- a/src/cmd/compile/internal/gc/phi.go
+++ b/src/cmd/compile/internal/gc/phi.go
@@ -6,6 +6,8 @@ package gc
 
 import (
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"container/heap"
 	"fmt"
 )
@@ -70,7 +72,7 @@ func (s *phiState) insertPhis() {
 	// Generate a numbering for these variables.
 	s.varnum = map[*Node]int32{}
 	var vars []*Node
-	var vartypes []ssa.Type
+	var vartypes []*types.Type
 	for _, b := range s.f.Blocks {
 		for _, v := range b.Values {
 			if v.Op != ssa.OpFwdRef {
@@ -161,7 +163,7 @@ levels:
 	s.queued = newSparseSet(s.f.NumBlocks())
 	s.hasPhi = newSparseSet(s.f.NumBlocks())
 	s.hasDef = newSparseSet(s.f.NumBlocks())
-	s.placeholder = s.s.entryNewValue0(ssa.OpUnknown, ssa.TypeInvalid)
+	s.placeholder = s.s.entryNewValue0(ssa.OpUnknown, types.TypeInvalid)
 
 	// Generate phi ops for each variable.
 	for n := range vartypes {
@@ -181,7 +183,7 @@ levels:
 	}
 }
 
-func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ ssa.Type) {
+func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ *types.Type) {
 	priq := &s.priq
 	q := s.q
 	queued := s.queued
@@ -223,17 +225,18 @@ func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ ssa.T
 				fmt.Printf("  processing %s\n", b)
 			}
 
+			currentRootLevel := s.level[currentRoot.ID]
 			for _, e := range b.Succs {
 				c := e.Block()
 				// TODO: if the variable is dead at c, skip it.
-				if s.level[c.ID] > s.level[currentRoot.ID] {
+				if s.level[c.ID] > currentRootLevel {
 					// a D-edge, or an edge whose target is in currentRoot's subtree.
 					continue
 				}
 				if !hasPhi.contains(c.ID) {
 					// Add a phi to block c for variable n.
 					hasPhi.add(c.ID)
-					v := c.NewValue0I(currentRoot.Line, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
+					v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
 					// Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
 					s.s.addNamedValue(var_, v)
 					for i := 0; i < len(c.Preds); i++ {
@@ -341,7 +344,12 @@ func (s *phiState) resolveFwdRefs() {
 				if v.Op != ssa.OpPhi {
 					break // All phis will be at the end of the block during phi building.
 				}
-				v.SetArg(i, values[v.AuxInt])
+				// Only set arguments that have been resolved.
+				// For very wide CFGs, this significantly speeds up phi resolution.
+				// See golang.org/issue/8225.
+				if w := values[v.AuxInt]; w.Op != ssa.OpUnknown {
+					v.SetArg(i, w)
+				}
 			}
 		}
 
@@ -423,13 +431,16 @@ func (s *sparseSet) clear() {
 
 // Variant to use for small functions.
 type simplePhiState struct {
-	s       *state                 // SSA state
-	f       *ssa.Func              // function to work on
-	fwdrefs []*ssa.Value           // list of FwdRefs to be processed
-	defvars []map[*Node]*ssa.Value // defined variables at end of each block
+	s         *state                 // SSA state
+	f         *ssa.Func              // function to work on
+	fwdrefs   []*ssa.Value           // list of FwdRefs to be processed
+	defvars   []map[*Node]*ssa.Value // defined variables at end of each block
+	reachable []bool                 // which blocks are reachable
 }
 
 func (s *simplePhiState) insertPhis() {
+	s.reachable = ssa.ReachableBlocks(s.f)
+
 	// Find FwdRef ops.
 	for _, b := range s.f.Blocks {
 		for _, v := range b.Values {
@@ -452,12 +463,12 @@ loop:
 		s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
 		b := v.Block
 		var_ := v.Aux.(*Node)
-		if len(b.Preds) == 0 {
-			if b == s.f.Entry {
-				// No variable should be live at entry.
-				s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
-			}
-			// This block is dead; it has no predecessors and it is not the entry block.
+		if b == s.f.Entry {
+			// No variable should be live at entry.
+			s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
+		}
+		if !s.reachable[b.ID] {
+			// This block is dead.
 			// It doesn't matter what we use here as long as it is well-formed.
 			v.Op = ssa.OpUnknown
 			v.Aux = nil
@@ -466,7 +477,7 @@ loop:
 		// Find variable value on each predecessor.
 		args = args[:0]
 		for _, e := range b.Preds {
-			args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Line))
+			args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos))
 		}
 
 		// Decide if we need a phi or not. We need a phi if there
@@ -499,7 +510,7 @@ loop:
 }
 
 // lookupVarOutgoing finds the variable's value at the end of block b.
-func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line int32) *ssa.Value {
+func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *Node, line src.XPos) *ssa.Value {
 	for {
 		if v := s.defvars[b.ID][var_]; v != nil {
 			return v
@@ -511,6 +522,11 @@ func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node,
 			break
 		}
 		b = b.Preds[0].Block()
+		if !s.reachable[b.ID] {
+			// This is rare; it happens with oddly interleaved infinite loops in dead code.
+			// See issue 19783.
+			break
+		}
 	}
 	// Generate a FwdRef for the variable and return that.
 	v := b.NewValue0A(line, ssa.OpFwdRef, t, var_)
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 5fa8645..ca449b7 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -9,55 +9,84 @@
 //
 //	-live (aka -live=1): print liveness lists as code warnings at safe points
 //	-live=2: print an assembly listing with liveness annotations
-//	-live=3: print information during each computation phase (much chattier)
 //
 // Each level includes the earlier output as well.
 
 package gc
 
 import (
+	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
-	"cmd/internal/sys"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"crypto/md5"
+	"crypto/sha1"
 	"fmt"
-	"sort"
+	"os"
 	"strings"
 )
 
-const (
-	UNVISITED = 0
-	VISITED   = 1
-)
-
-// An ordinary basic block.
+// TODO(mdempsky): Update to reference OpVar{Def,Kill,Live} instead.
+
+// VARDEF is an annotation for the liveness analysis, marking a place
+// where a complete initialization (definition) of a variable begins.
+// Since the liveness analysis can see initialization of single-word
+// variables quite easy, gvardef is usually only called for multi-word
+// or 'fat' variables, those satisfying isfat(n->type).
+// However, gvardef is also called when a non-fat variable is initialized
+// via a block move; the only time this happens is when you have
+//	return f()
+// for a function with multiple return values exactly matching the return
+// types of the current function.
+//
+// A 'VARDEF x' annotation in the instruction stream tells the liveness
+// analysis to behave as though the variable x is being initialized at that
+// point in the instruction stream. The VARDEF must appear before the
+// actual (multi-instruction) initialization, and it must also appear after
+// any uses of the previous value, if any. For example, if compiling:
+//
+//	x = x[1:]
+//
+// it is important to generate code like:
+//
+//	base, len, cap = pieces of x[1:]
+//	VARDEF x
+//	x = {base, len, cap}
+//
+// If instead the generated code looked like:
 //
-// 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
+//	VARDEF x
+//	base, len, cap = pieces of x[1:]
+//	x = {base, len, cap}
 //
-//   for p = bb.first; ; p = p.link {
-//     ...
-//     if p == bb.last {
-//       break
-//     }
-//   }
+// then the liveness analysis would decide the previous value of x was
+// unnecessary even though it is about to be used by the x[1:] computation.
+// Similarly, if the generated code looked like:
 //
-// To iterate in reverse program order by following the opt pointer from the
-// last node
+//	base, len, cap = pieces of x[1:]
+//	x = {base, len, cap}
+//	VARDEF x
 //
-//   for p = bb.last; p != nil; p = p.opt {
-//     ...
-//   }
-type BasicBlock struct {
-	pred            []*BasicBlock // predecessors; if none, probably start of CFG
-	succ            []*BasicBlock // successors; if none, probably ends in return statement
-	first           *obj.Prog     // first instruction in block
-	last            *obj.Prog     // last instruction in block
-	rpo             int           // reverse post-order number (also index in cfg)
-	mark            int           // mark bit for traversals
-	lastbitmapindex int           // for livenessepilogue
-
-	// Summary sets of block effects.
+// then the liveness analysis will not preserve the new value of x, because
+// the VARDEF appears to have "overwritten" it.
+//
+// VARDEF is a bit of a kludge to work around the fact that the instruction
+// stream is working on single-word values but the liveness analysis
+// wants to work on individual variables, which might be multi-word
+// aggregates. It might make sense at some point to look into letting
+// the liveness analysis work on single-word values as well, although
+// there are complications around interface values, slices, and strings,
+// all of which cannot be treated as individual words.
+//
+// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
+// even if its address has been taken. That is, a VARKILL annotation asserts
+// that its argument is certainly dead, for use when the liveness analysis
+// would not otherwise be able to deduce that fact.
+
+// BlockEffects summarizes the liveness effects on an SSA block.
+type BlockEffects struct {
+	lastbitmapindex int // for livenessepilogue
 
 	// Computed during livenessprologue using only the content of
 	// individual blocks:
@@ -85,133 +114,29 @@ type BasicBlock struct {
 
 // A collection of global state used by liveness analysis.
 type Liveness struct {
-	fn   *Node
-	ptxt *obj.Prog
-	vars []*Node
-	cfg  []*BasicBlock
-
-	// An array with a bit vector for each safe point tracking live pointers
-	// in the arguments and locals area, indexed by bb.rpo.
-	argslivepointers []bvec
-	livepointers     []bvec
-}
+	fn         *Node
+	f          *ssa.Func
+	vars       []*Node
+	idx        map[*Node]int32
+	stkptrsize int64
 
-// ProgInfo holds information about the instruction for use
-// by clients such as the compiler. The exact meaning of this
-// data is up to the client and is not interpreted by the cmd/internal/obj/... packages.
-type ProgInfo struct {
-	_     struct{} // to prevent unkeyed literals. Trailing zero-sized field will take space.
-	Flags uint32   // flag bits
-}
+	be []BlockEffects
 
-// Constructs a new basic block containing a single instruction.
-func newblock(prog *obj.Prog) *BasicBlock {
-	if prog == nil {
-		Fatalf("newblock: prog cannot be nil")
-	}
-	// type block allows us to allocate a BasicBlock
-	// and its pred/succ slice together.
-	type block struct {
-		result BasicBlock
-		pred   [2]*BasicBlock
-		succ   [2]*BasicBlock
-	}
-	b := new(block)
-
-	result := &b.result
-	result.rpo = -1
-	result.mark = UNVISITED
-	result.first = prog
-	result.last = prog
-	result.pred = b.pred[:0]
-	result.succ = b.succ[:0]
-	return result
-}
-
-// Adds an edge between two basic blocks by making from a predecessor of to and
-// to a successor of from.
-func addedge(from *BasicBlock, to *BasicBlock) {
-	if from == nil {
-		Fatalf("addedge: from is nil")
-	}
-	if to == nil {
-		Fatalf("addedge: to is nil")
-	}
-	from.succ = append(from.succ, to)
-	to.pred = append(to.pred, from)
-}
-
-// Inserts prev before curr in the instruction
-// stream. Any control flow, such as branches or fall-throughs, that target the
-// existing instruction are adjusted to target the new instruction.
-func splicebefore(lv *Liveness, bb *BasicBlock, prev *obj.Prog, curr *obj.Prog) {
-	// There may be other instructions pointing at curr,
-	// and we want them to now point at prev. Instead of
-	// trying to find all such instructions, swap the contents
-	// so that the problem becomes inserting next after curr.
-	// The "opt" field is the backward link in the linked list.
-
-	// Overwrite curr's data with prev, but keep the list links.
-	tmp := *curr
-
-	*curr = *prev
-	curr.Opt = tmp.Opt
-	curr.Link = tmp.Link
-
-	// Overwrite prev (now next) with curr's old data.
-	next := prev
-
-	*next = tmp
-	next.Opt = nil
-	next.Link = nil
-
-	// Now insert next after curr.
-	next.Link = curr.Link
-
-	next.Opt = curr
-	curr.Link = next
-	if next.Link != nil && next.Link.Opt == curr {
-		next.Link.Opt = next
-	}
+	// stackMapIndex maps from safe points (i.e., CALLs) to their
+	// index within the stack maps.
+	stackMapIndex map[*ssa.Value]int
 
-	if bb.last == curr {
-		bb.last = next
-	}
-}
+	// An array with a bit vector for each safe point tracking live variables.
+	livevars []bvec
 
-// A pretty printer for basic blocks.
-func printblock(bb *BasicBlock) {
-	fmt.Printf("basic block %d\n", bb.rpo)
-	fmt.Printf("\tpred:")
-	for _, pred := range bb.pred {
-		fmt.Printf(" %d", pred.rpo)
-	}
-	fmt.Printf("\n")
-	fmt.Printf("\tsucc:")
-	for _, succ := range bb.succ {
-		fmt.Printf(" %d", succ.rpo)
-	}
-	fmt.Printf("\n")
-	fmt.Printf("\tprog:\n")
-	for prog := bb.first; ; prog = prog.Link {
-		fmt.Printf("\t\t%v\n", prog)
-		if prog == bb.last {
-			break
-		}
-	}
+	cache progeffectscache
 }
 
-// Iterates over a basic block applying a callback to each instruction. There
-// are two criteria for termination. If the end of basic block is reached a
-// value of zero is returned. If the callback returns a non-zero value, the
-// iteration is stopped and the value of the callback is returned.
-func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
-	for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) {
-		if f(p) {
-			return true
-		}
-	}
-	return false
+type progeffectscache struct {
+	textavarinit []int32
+	retuevar     []int32
+	tailuevar    []int32
+	initialized  bool
 }
 
 // livenessShouldTrack reports whether the liveness analysis
@@ -221,670 +146,218 @@ func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
 // 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)
+	return n.Op == ONAME && (n.Class() == PAUTO || n.Class() == PPARAM || n.Class() == PPARAMOUT) && types.Haspointers(n.Type)
 }
 
-// getvariables returns the list of on-stack variables that we need to track.
-func getvariables(fn *Node) []*Node {
+// getvariables returns the list of on-stack variables that we need to track
+// and a map for looking up indices by *Node.
+func getvariables(fn *Node) ([]*Node, map[*Node]int32) {
 	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
-			// (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() != nil. Then n.Opt().(int32)
-			// is the index in the variables list.
-			n.SetOpt(nil)
-			n.Name.Curfn = Curfn
-		}
-
 		if livenessShouldTrack(n) {
-			n.SetOpt(int32(len(vars)))
 			vars = append(vars, n)
 		}
 	}
-
-	return vars
-}
-
-// A pretty printer for control flow graphs. Takes a slice of *BasicBlocks.
-func printcfg(cfg []*BasicBlock) {
-	for _, bb := range cfg {
-		printblock(bb)
-	}
-}
-
-// Assigns a reverse post order number to each connected basic block using the
-// standard algorithm. Unconnected blocks will not be affected.
-func reversepostorder(root *BasicBlock, rpo *int32) {
-	root.mark = VISITED
-	for _, bb := range root.succ {
-		if bb.mark == UNVISITED {
-			reversepostorder(bb, rpo)
-		}
-	}
-	*rpo -= 1
-	root.rpo = int(*rpo)
-}
-
-// Comparison predicate used for sorting basic blocks by their rpo in ascending
-// order.
-type blockrpocmp []*BasicBlock
-
-func (x blockrpocmp) Len() int           { return len(x) }
-func (x blockrpocmp) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
-func (x blockrpocmp) Less(i, j int) bool { return x[i].rpo < x[j].rpo }
-
-// A pattern matcher for call instructions. Returns true when the instruction
-// is a call to a specific package qualified function name.
-func iscall(prog *obj.Prog, name *obj.LSym) bool {
-	if prog == nil {
-		Fatalf("iscall: prog is nil")
-	}
-	if name == nil {
-		Fatalf("iscall: function name is nil")
-	}
-	if prog.As != obj.ACALL {
-		return false
-	}
-	return name == prog.To.Sym
-}
-
-// Returns true for instructions that call a runtime function implementing a
-// select communication clause.
-
-var selectNames [4]*obj.LSym
-
-func isselectcommcasecall(prog *obj.Prog) bool {
-	if selectNames[0] == nil {
-		selectNames[0] = Linksym(Pkglookup("selectsend", Runtimepkg))
-		selectNames[1] = Linksym(Pkglookup("selectrecv", Runtimepkg))
-		selectNames[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg))
-		selectNames[3] = Linksym(Pkglookup("selectdefault", Runtimepkg))
-	}
-
-	for _, name := range selectNames {
-		if iscall(prog, name) {
-			return true
-		}
-	}
-	return false
-}
-
-// Returns true for call instructions that target runtime·newselect.
-
-var isnewselect_sym *obj.LSym
-
-func isnewselect(prog *obj.Prog) bool {
-	if isnewselect_sym == nil {
-		isnewselect_sym = Linksym(Pkglookup("newselect", Runtimepkg))
-	}
-	return iscall(prog, isnewselect_sym)
-}
-
-// Returns true for call instructions that target runtime·selectgo.
-
-var isselectgocall_sym *obj.LSym
-
-func isselectgocall(prog *obj.Prog) bool {
-	if isselectgocall_sym == nil {
-		isselectgocall_sym = Linksym(Pkglookup("selectgo", Runtimepkg))
-	}
-	return iscall(prog, isselectgocall_sym)
-}
-
-var isdeferreturn_sym *obj.LSym
-
-func isdeferreturn(prog *obj.Prog) bool {
-	if isdeferreturn_sym == nil {
-		isdeferreturn_sym = Linksym(Pkglookup("deferreturn", Runtimepkg))
-	}
-	return iscall(prog, isdeferreturn_sym)
-}
-
-// Walk backwards from a runtime·selectgo call up to its immediately dominating
-// runtime·newselect call. Any successor nodes of communication clause nodes
-// are implicit successors of the runtime·selectgo call node. The goal of this
-// analysis is to add these missing edges to complete the control flow graph.
-func addselectgosucc(selectgo *BasicBlock) {
-	pred := selectgo
-	for {
-		if len(pred.pred) == 0 {
-			Fatalf("selectgo does not have a newselect")
-		}
-		pred = pred.pred[0]
-		if blockany(pred, isselectcommcasecall) {
-			// A select comm case block should have exactly one
-			// successor.
-			if len(pred.succ) != 1 {
-				Fatalf("select comm case has too many successors")
-			}
-			succ := pred.succ[0]
-
-			// Its successor should have exactly two successors.
-			// The drop through should flow to the selectgo block
-			// and the branch should lead to the select case
-			// statements block.
-			if len(succ.succ) != 2 {
-				Fatalf("select comm case successor has too many successors")
-			}
-
-			// Add the block as a successor of the selectgo block.
-			addedge(selectgo, succ)
-		}
-
-		if blockany(pred, isnewselect) {
-			// Reached the matching newselect.
-			break
-		}
-	}
-}
-
-// The entry point for the missing selectgo control flow algorithm. Takes a
-// slice of *BasicBlocks containing selectgo calls.
-func fixselectgo(selectgo []*BasicBlock) {
-	for _, bb := range selectgo {
-		addselectgosucc(bb)
+	idx := make(map[*Node]int32, len(vars))
+	for i, n := range vars {
+		idx[n] = int32(i)
 	}
+	return vars, idx
 }
 
-// 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 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
-	// passes, instructions that are labels temporarily use the opt field to
-	// point to their basic block. In the third pass, the opt field reset
-	// to point to the predecessor of an instruction in its basic block.
-	for p := firstp; p != nil; p = p.Link {
-		p.Opt = nil
-	}
-
-	// Allocate a slice to remember where we have seen selectgo calls.
-	// These blocks will be revisited to add successor control flow edges.
-	var selectgo []*BasicBlock
-
-	// Loop through all instructions identifying branch targets
-	// and fall-throughs and allocate basic blocks.
-	var cfg []*BasicBlock
-
-	bb := newblock(firstp)
-	cfg = append(cfg, bb)
-	for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
-		if p.To.Type == obj.TYPE_BRANCH {
-			if p.To.Val == nil {
-				Fatalf("prog branch to nil")
-			}
-			if p.To.Val.(*obj.Prog).Opt == nil {
-				p.To.Val.(*obj.Prog).Opt = newblock(p.To.Val.(*obj.Prog))
-				cfg = append(cfg, p.To.Val.(*obj.Prog).Opt.(*BasicBlock))
-			}
-
-			if p.As != obj.AJMP && p.Link != nil && p.Link.Opt == nil {
-				p.Link.Opt = newblock(p.Link)
-				cfg = append(cfg, p.Link.Opt.(*BasicBlock))
-			}
-		} else if isselectcommcasecall(p) || isselectgocall(p) {
-			// Accommodate implicit selectgo control flow.
-			if p.Link.Opt == nil {
-				p.Link.Opt = newblock(p.Link)
-				cfg = append(cfg, p.Link.Opt.(*BasicBlock))
-			}
-		}
+func (lv *Liveness) initcache() {
+	if lv.cache.initialized {
+		Fatalf("liveness cache initialized twice")
+		return
 	}
+	lv.cache.initialized = true
 
-	// Loop through all basic blocks maximally growing the list of
-	// contained instructions until a label is reached. Add edges
-	// for branches and fall-through instructions.
-	for _, bb := range cfg {
-		for p := bb.last; p != nil && p.As != obj.AEND; p = p.Link {
-			if p.Opt != nil && p != bb.last {
-				break
-			}
-			bb.last = p
-
-			// Stop before an unreachable RET, to avoid creating
-			// unreachable control flow nodes.
-			if p.Link != nil && p.Link.As == obj.ARET && p.Link.Mode == 1 {
-				// TODO: remove after SSA is done. SSA does not
-				// generate any unreachable RET instructions.
-				break
-			}
+	for i, node := range lv.vars {
+		switch node.Class() {
+		case PPARAM:
+			// 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.
 
-			// Collect basic blocks with selectgo calls.
-			if isselectgocall(p) {
-				selectgo = append(selectgo, bb)
-			}
-		}
+			lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i))
 
-		if bb.last.To.Type == obj.TYPE_BRANCH {
-			addedge(bb, bb.last.To.Val.(*obj.Prog).Opt.(*BasicBlock))
-		}
-		if bb.last.Link != nil {
-			// Add a fall-through when the instruction is
-			// not an unconditional control transfer.
-			if bb.last.As != obj.AJMP && bb.last.As != obj.ARET && bb.last.As != obj.AUNDEF {
-				addedge(bb, bb.last.Link.Opt.(*BasicBlock))
+			if node.Addrtaken() {
+				lv.cache.textavarinit = append(lv.cache.textavarinit, int32(i))
 			}
-		}
-	}
 
-	// Add back links so the instructions in a basic block can be traversed
-	// backward. This is the final state of the instruction opt field.
-	for _, bb := range cfg {
-		p := bb.first
-		var prev *obj.Prog
-		for {
-			p.Opt = prev
-			if p == bb.last {
-				break
+		case PPARAMOUT:
+			// If the result had its address taken, it is being tracked
+			// by the avarinit code, which does not use uevar.
+			// If we added it to uevar too, we'd not see any kill
+			// and decide that the variable was live entry, which it is not.
+			// So only use uevar in the non-addrtaken case.
+			// The p.to.type == obj.TYPE_NONE limits the bvset to
+			// non-tail-call return instructions; see note below for details.
+			if !node.Addrtaken() {
+				lv.cache.retuevar = append(lv.cache.retuevar, int32(i))
 			}
-			prev = p
-			p = p.Link
 		}
 	}
-
-	// Add missing successor edges to the selectgo blocks.
-	if len(selectgo) != 0 {
-		fixselectgo(selectgo)
-	}
-
-	// Find a depth-first order and assign a depth-first number to
-	// all basic blocks.
-	for _, bb := range cfg {
-		bb.mark = UNVISITED
-	}
-	bb = cfg[0]
-	rpo := int32(len(cfg))
-	reversepostorder(bb, &rpo)
-
-	// Sort the basic blocks by their depth first number. The
-	// 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
-	// upstream compilation phase.
-	bb = cfg[0]
-	if bb.rpo == -1 {
-		fmt.Printf("newcfg: unreachable basic block for %v\n", bb.last)
-		printcfg(cfg)
-		Fatalf("newcfg: invalid control flow graph")
-	}
-
-	return cfg
 }
 
-// Frees a control flow graph (a slice of *BasicBlocks) and all of its leaf
-// data structures.
-func freecfg(cfg []*BasicBlock) {
-	if len(cfg) > 0 {
-		bb0 := cfg[0]
-		for p := bb0.first; p != nil; p = p.Link {
-			p.Opt = nil
-		}
-	}
-}
-
-// Returns true if the node names a variable that is otherwise uninteresting to
-// the liveness computation.
-func isfunny(n *Node) bool {
-	return n.Sym != nil && (n.Sym.Name == ".fp" || n.Sym.Name == ".args")
-}
-
-// Computes the effects of an instruction on a set of
-// variables. The vars argument is a slice of *Nodes.
+// A liveEffect is a set of flags that describe an instruction's
+// liveness effects on a variable.
 //
-// The output vectors give bits for variables:
-//	uevar - used by this instruction
-//	varkill - killed by this instruction
+// The possible flags are:
+//	uevar - used by the instruction
+//	varkill - killed by the instruction
 //		for variables without address taken, means variable was set
 //		for variables with address taken, means variable was marked dead
-//	avarinit - initialized or referred to by this instruction,
+//	avarinit - initialized or referred to by the instruction,
 //		only for variables with address taken but not escaping to heap
 //
 // The avarinit output serves as a signal that the data has been
 // initialized, because any use of a variable must come after its
 // initialization.
-func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarinit bvec) {
-	uevar.Clear()
-	varkill.Clear()
-	avarinit.Clear()
-
-	// 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.
-	if (prog.As == obj.AJMP || prog.As == obj.ARET) && 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 {
-				uevar.Set(int32(i))
-			}
-		}
-	}
-
-	if prog.As == obj.ARET {
-		// Return instructions read all of the out arguments.
-		for i, node := range vars {
-			switch node.Class {
-			// 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 == obj.TYPE_NONE limits the bvset to
-			// non-tail-call return instructions; see note below for details.
-			case PPARAMOUT:
-				if !node.Addrtaken && prog.To.Type == obj.TYPE_NONE {
-					uevar.Set(int32(i))
-				}
-			}
-		}
+type liveEffect int
 
-		return
-	}
+const (
+	uevar liveEffect = 1 << iota
+	varkill
+	avarinit
+)
 
-	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 {
-			case PPARAM:
-				if node.Addrtaken {
-					avarinit.Set(int32(i))
-				}
-				varkill.Set(int32(i))
-			}
+// valueEffects returns the index of a variable in lv.vars and the
+// liveness effects v has on that variable.
+// If v does not affect any tracked variables, it returns -1, 0.
+func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
+	n, e := affectedNode(v)
+	if e == 0 || n == nil || n.Op != ONAME { // cheapest checks first
+		return -1, 0
+	}
+
+	// AllocFrame has dropped unused variables from
+	// lv.fn.Func.Dcl, but they might still be referenced by
+	// OpVarFoo pseudo-ops. Ignore them to prevent "lost track of
+	// variable" ICEs (issue 19632).
+	switch v.Op {
+	case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
+		if !n.Name.Used() {
+			return -1, 0
 		}
-
-		return
 	}
 
-	info := Thearch.Proginfo(prog)
-
-	if info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
-		from := &prog.From
-		if from.Node != nil && from.Sym != nil {
-			n := from.Node.(*Node)
-			if pos := liveIndex(n, vars); pos >= 0 {
-				if n.Addrtaken {
-					avarinit.Set(pos)
-				} else {
-					if info.Flags&(LeftRead|LeftAddr) != 0 {
-						uevar.Set(pos)
-					}
-					if info.Flags&LeftWrite != 0 {
-						if !isfat(n.Type) {
-							varkill.Set(pos)
-						}
-					}
-				}
-			}
+	var effect liveEffect
+	if n.Addrtaken() {
+		if v.Op != ssa.OpVarKill {
+			effect |= avarinit
+		}
+		if v.Op == ssa.OpVarDef || v.Op == ssa.OpVarKill {
+			effect |= varkill
+		}
+	} else {
+		// Read is a read, obviously.
+		// Addr by itself is also implicitly a read.
+		//
+		// Addr|Write means that the address is being taken
+		// but only so that the instruction can write to the value.
+		// It is not a read.
+
+		if e&ssa.SymRead != 0 || e&(ssa.SymAddr|ssa.SymWrite) == ssa.SymAddr {
+			effect |= uevar
+		}
+		if e&ssa.SymWrite != 0 && (!isfat(n.Type) || v.Op == ssa.OpVarDef) {
+			effect |= varkill
 		}
 	}
 
-	if info.Flags&From3Read != 0 {
-		from := prog.From3
-		if from.Node != nil && from.Sym != nil {
-			n := from.Node.(*Node)
-			if pos := liveIndex(n, vars); pos >= 0 {
-				if n.Addrtaken {
-					avarinit.Set(pos)
-				} else {
-					uevar.Set(pos)
-				}
-			}
-		}
+	if effect == 0 {
+		return -1, 0
 	}
 
-	if info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
-		to := &prog.To
-		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 {
-						avarinit.Set(pos)
-					}
-					if prog.As == obj.AVARDEF || prog.As == obj.AVARKILL {
-						varkill.Set(pos)
-					}
-				} else {
-					// RightRead is a read, obviously.
-					// RightAddr by itself is also implicitly a read.
-					//
-					// RightAddr|RightWrite means that the address is being taken
-					// but only so that the instruction can write to the value.
-					// It is not a read. It is equivalent to RightWrite except that
-					// having the RightAddr bit set keeps the registerizer from
-					// trying to substitute a register for the memory location.
-					if (info.Flags&RightRead != 0) || info.Flags&(RightAddr|RightWrite) == RightAddr {
-						uevar.Set(pos)
-					}
-					if info.Flags&RightWrite != 0 {
-						if !isfat(n.Type) || prog.As == obj.AVARDEF {
-							varkill.Set(pos)
-						}
-					}
-				}
-			}
-		}
+	if pos, ok := lv.idx[n]; ok {
+		return pos, effect
 	}
+	return -1, 0
 }
 
-// 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
+// affectedNode returns the *Node affected by v
+func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
+	// Special cases.
+	switch v.Op {
+	case ssa.OpLoadReg:
+		n, _ := AutoVar(v.Args[0])
+		return n, ssa.SymRead
+	case ssa.OpStoreReg:
+		n, _ := AutoVar(v)
+		return n, ssa.SymWrite
+
+	case ssa.OpVarLive:
+		return v.Aux.(*Node), ssa.SymRead
+	case ssa.OpVarDef, ssa.OpVarKill:
+		return v.Aux.(*Node), ssa.SymWrite
+	case ssa.OpKeepAlive:
+		n, _ := AutoVar(v.Args[0])
+		return n, ssa.SymRead
+	}
+
+	e := v.Op.SymEffect()
+	if e == 0 {
+		return nil, 0
+	}
+
+	var n *Node
+	switch a := v.Aux.(type) {
+	case nil, *ssa.ExternSymbol:
+		// ok, but no node
+	case *ssa.ArgSymbol:
+		n = a.Node.(*Node)
+	case *ssa.AutoSymbol:
+		n = a.Node.(*Node)
+	default:
+		Fatalf("weird aux: %s", v.LongString())
 	}
 
-	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
+	return n, e
 }
 
 // Constructs a new liveness structure used to hold the global state of the
 // 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 := Liveness{
-		fn:   fn,
-		ptxt: ptxt,
-		cfg:  cfg,
-		vars: vars,
+func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkptrsize int64) *Liveness {
+	lv := &Liveness{
+		fn:         fn,
+		f:          f,
+		vars:       vars,
+		idx:        idx,
+		stkptrsize: stkptrsize,
+		be:         make([]BlockEffects, f.NumBlocks()),
 	}
 
-	nblocks := int32(len(cfg))
+	nblocks := int32(len(f.Blocks))
 	nvars := int32(len(vars))
 	bulk := bvbulkalloc(nvars, nblocks*7)
-	for _, bb := range cfg {
-		bb.uevar = bulk.next()
-		bb.varkill = bulk.next()
-		bb.livein = bulk.next()
-		bb.liveout = bulk.next()
-		bb.avarinit = bulk.next()
-		bb.avarinitany = bulk.next()
-		bb.avarinitall = bulk.next()
-	}
-	return &result
-}
-
-func printeffects(p *obj.Prog, uevar bvec, varkill bvec, avarinit bvec) {
-	fmt.Printf("effects of %v\n", p)
-	fmt.Println("uevar:", uevar)
-	fmt.Println("varkill:", varkill)
-	fmt.Println("avarinit:", avarinit)
-}
-
-// Pretty print a variable node. Uses Pascal like conventions for pointers and
-// addresses to avoid confusing the C like conventions used in the node variable
-// names.
-func printnode(node *Node) {
-	p := ""
-	if haspointers(node.Type) {
-		p = "^"
-	}
-	a := ""
-	if node.Addrtaken {
-		a = "@"
-	}
-	fmt.Printf(" %v%s%s", node, p, a)
+	for _, b := range f.Blocks {
+		be := lv.blockEffects(b)
+
+		be.uevar = bulk.next()
+		be.varkill = bulk.next()
+		be.livein = bulk.next()
+		be.liveout = bulk.next()
+		be.avarinit = bulk.next()
+		be.avarinitany = bulk.next()
+		be.avarinitall = bulk.next()
+	}
+	return lv
 }
 
-// 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 bv.Get(int32(i)) {
-			printnode(node)
-		}
-	}
-	fmt.Printf("\n")
-}
-
-// Prints a basic block annotated with the information computed by liveness
-// analysis.
-func livenessprintblock(lv *Liveness, bb *BasicBlock) {
-	fmt.Printf("basic block %d\n", bb.rpo)
-
-	fmt.Printf("\tpred:")
-	for _, pred := range bb.pred {
-		fmt.Printf(" %d", pred.rpo)
-	}
-	fmt.Printf("\n")
-
-	fmt.Printf("\tsucc:")
-	for _, succ := range bb.succ {
-		fmt.Printf(" %d", succ.rpo)
-	}
-	fmt.Printf("\n")
-
-	printvars("\tuevar", bb.uevar, 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 {
-		fmt.Printf("\t\t%v", prog)
-		if prog.As == obj.APCDATA && prog.From.Offset == obj.PCDATA_StackMapIndex {
-			pos := int32(prog.To.Offset)
-			live := lv.livepointers[pos]
-			fmt.Printf(" %s", live.String())
-		}
-
-		fmt.Printf("\n")
-		if prog == bb.last {
-			break
-		}
-	}
-}
-
-// Prints a control flow graph annotated with any information computed by
-// liveness analysis.
-func livenessprintcfg(lv *Liveness) {
-	for _, bb := range lv.cfg {
-		livenessprintblock(lv, bb)
-	}
-}
-
-func checkauto(fn *Node, p *obj.Prog, n *Node) {
-	for _, ln := range fn.Func.Dcl {
-		if ln.Op == ONAME && ln.Class == PAUTO && ln == n {
-			return
-		}
-	}
-
-	if n == nil {
-		fmt.Printf("%v: checkauto %v: nil node in %v\n", p.Line(), Curfn, p)
-		return
-	}
-
-	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %p %v\n", funcSym(Curfn), n, n, n.Class, p, p)
-	for _, ln := range fn.Func.Dcl {
-		fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
-	}
-	yyerror("checkauto: invariant lost")
-}
-
-func checkparam(fn *Node, p *obj.Prog, n *Node) {
-	if isfunny(n) {
-		return
-	}
-	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 _, ln := range fn.Func.Dcl {
-		fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
-	}
-	yyerror("checkparam: invariant lost")
-}
-
-func checkprog(fn *Node, p *obj.Prog) {
-	if p.From.Name == obj.NAME_AUTO {
-		checkauto(fn, p, p.From.Node.(*Node))
-	}
-	if p.From.Name == obj.NAME_PARAM {
-		checkparam(fn, p, p.From.Node.(*Node))
-	}
-	if p.To.Name == obj.NAME_AUTO {
-		checkauto(fn, p, p.To.Node.(*Node))
-	}
-	if p.To.Name == obj.NAME_PARAM {
-		checkparam(fn, p, p.To.Node.(*Node))
-	}
-}
-
-// Check instruction invariants. We assume that the nodes corresponding to the
-// sources and destinations of memory operations will be declared in the
-// function. This is not strictly true, as is the case for the so-called funny
-// nodes and there are special cases to skip over that stuff. The analysis will
-// fail if this invariant blindly changes.
-func checkptxt(fn *Node, firstp *obj.Prog) {
-	if debuglive == 0 {
-		return
-	}
-
-	for p := firstp; p != nil; p = p.Link {
-		if false {
-			fmt.Printf("analyzing '%v'\n", p)
-		}
-		if p.As != obj.ATYPE {
-			checkprog(fn, p)
-		}
-	}
+func (lv *Liveness) blockEffects(b *ssa.Block) *BlockEffects {
+	return &lv.be[b.ID]
 }
 
 // NOTE: The bitmap for a specific type t should be cached in t after the first run
 // and then simply copied into bv at the correct offset on future calls with
 // the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, onebitwalktype1
 // accounts for 40% of the 6g execution time.
-func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
+func onebitwalktype1(t *types.Type, xoffset *int64, bv bvec) {
 	if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
 		Fatalf("onebitwalktype1: invalid initial alignment, %v", t)
 	}
@@ -969,13 +442,13 @@ func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
 }
 
 // Returns the number of words of local variables.
-func localswords() int32 {
-	return int32(stkptrsize / int64(Widthptr))
+func localswords(lv *Liveness) int32 {
+	return int32(lv.stkptrsize / int64(Widthptr))
 }
 
 // Returns the number of words of in and out arguments.
-func argswords() int32 {
-	return int32(Curfn.Type.ArgWidth() / int64(Widthptr))
+func argswords(lv *Liveness) int32 {
+	return int32(lv.fn.Type.ArgWidth() / int64(Widthptr))
 }
 
 // Generates live pointer value maps for arguments and local variables. The
@@ -990,9 +463,9 @@ func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, l
 			break
 		}
 		node := vars[i]
-		switch node.Class {
+		switch node.Class() {
 		case PAUTO:
-			xoffset = node.Xoffset + stkptrsize
+			xoffset = node.Xoffset + lv.stkptrsize
 			onebitwalktype1(node.Type, &xoffset, locals)
 
 		case PPARAM, PPARAMOUT:
@@ -1002,66 +475,43 @@ func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, l
 	}
 }
 
-// Construct a disembodied instruction.
-func unlinkedprog(as obj.As) *obj.Prog {
-	p := Ctxt.NewProg()
-	Clearp(p)
-	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 {
-	pcdata := unlinkedprog(obj.APCDATA)
-	pcdata.Lineno = prog.Lineno
-	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
-}
-
 // Returns true for instructions that are safe points that must be annotated
 // with liveness information.
-func issafepoint(prog *obj.Prog) bool {
-	return prog.As == obj.ATEXT || prog.As == obj.ACALL
+func issafepoint(v *ssa.Value) bool {
+	return v.Op.IsCall()
 }
 
 // Initializes the sets for solving the live variables. Visits all the
 // instructions in each basic block to summarizes the information at each basic
 // block
 func livenessprologue(lv *Liveness) {
-	nvars := int32(len(lv.vars))
-	uevar := bvalloc(nvars)
-	varkill := bvalloc(nvars)
-	avarinit := bvalloc(nvars)
-	for _, bb := range lv.cfg {
+	lv.initcache()
+
+	for _, b := range lv.f.Blocks {
+		be := lv.blockEffects(b)
+
 		// 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, lv.vars, uevar, varkill, avarinit)
-			if debuglive >= 3 {
-				printeffects(p, uevar, varkill, avarinit)
+		for j := len(b.Values) - 1; j >= 0; j-- {
+			pos, e := lv.valueEffects(b.Values[j])
+			if e&varkill != 0 {
+				be.varkill.Set(pos)
+				be.uevar.Unset(pos)
+			}
+			if e&uevar != 0 {
+				be.uevar.Set(pos)
 			}
-			bb.varkill.Or(bb.varkill, varkill)
-			bb.uevar.AndNot(bb.uevar, varkill)
-			bb.uevar.Or(bb.uevar, uevar)
 		}
 
 		// Walk the block instructions forward to update avarinit bits.
 		// avarinit describes the effect at the end of the block, not the beginning.
-		varkill.Clear()
-
-		for p := bb.first; ; p = p.Link {
-			progeffects(p, lv.vars, uevar, varkill, avarinit)
-			if debuglive >= 3 {
-				printeffects(p, uevar, varkill, avarinit)
+		for j := 0; j < len(b.Values); j++ {
+			pos, e := lv.valueEffects(b.Values[j])
+			if e&varkill != 0 {
+				be.avarinit.Unset(pos)
 			}
-			bb.avarinit.AndNot(bb.avarinit, varkill)
-			bb.avarinit.Or(bb.avarinit, avarinit)
-			if p == bb.last {
-				break
+			if e&avarinit != 0 {
+				be.avarinit.Set(pos)
 			}
 		}
 	}
@@ -1072,7 +522,6 @@ func livenesssolve(lv *Liveness) {
 	// These temporary bitvectors exist to avoid successive allocations and
 	// frees within the loop.
 	newlivein := bvalloc(int32(len(lv.vars)))
-
 	newliveout := bvalloc(int32(len(lv.vars)))
 	any := bvalloc(int32(len(lv.vars)))
 	all := bvalloc(int32(len(lv.vars)))
@@ -1080,43 +529,41 @@ func livenesssolve(lv *Liveness) {
 	// Push avarinitall, avarinitany forward.
 	// avarinitall says the addressed var is initialized along all paths reaching the block exit.
 	// avarinitany says the addressed var is initialized along some path reaching the block exit.
-	for i, bb := range lv.cfg {
-		if i == 0 {
-			bb.avarinitall.Copy(bb.avarinit)
+	for _, b := range lv.f.Blocks {
+		be := lv.blockEffects(b)
+		if b == lv.f.Entry {
+			be.avarinitall.Copy(be.avarinit)
 		} else {
-			bb.avarinitall.Clear()
-			bb.avarinitall.Not()
+			be.avarinitall.Clear()
+			be.avarinitall.Not()
 		}
-		bb.avarinitany.Copy(bb.avarinit)
+		be.avarinitany.Copy(be.avarinit)
 	}
 
+	// Walk blocks in the general direction of propagation (RPO
+	// for avarinit{any,all}, and PO for live{in,out}). This
+	// improves convergence.
+	po := lv.f.Postorder()
+
 	for change := true; change; {
 		change = false
-		for _, bb := range lv.cfg {
-			any.Clear()
-			all.Clear()
-			for j, pred := range bb.pred {
-				if j == 0 {
-					any.Copy(pred.avarinitany)
-					all.Copy(pred.avarinitall)
-				} else {
-					any.Or(any, pred.avarinitany)
-					all.And(all, pred.avarinitall)
-				}
-			}
-
-			any.AndNot(any, bb.varkill)
-			all.AndNot(all, bb.varkill)
-			any.Or(any, bb.avarinit)
-			all.Or(all, bb.avarinit)
-			if !any.Eq(bb.avarinitany) {
+		for i := len(po) - 1; i >= 0; i-- {
+			b := po[i]
+			be := lv.blockEffects(b)
+			lv.avarinitanyall(b, any, all)
+
+			any.AndNot(any, be.varkill)
+			all.AndNot(all, be.varkill)
+			any.Or(any, be.avarinit)
+			all.Or(all, be.avarinit)
+			if !any.Eq(be.avarinitany) {
 				change = true
-				bb.avarinitany.Copy(any)
+				be.avarinitany.Copy(any)
 			}
 
-			if !all.Eq(bb.avarinitall) {
+			if !all.Eq(be.avarinitall) {
 				change = true
-				bb.avarinitall.Copy(all)
+				be.avarinitall.Copy(all)
 			}
 		}
 	}
@@ -1127,24 +574,35 @@ func livenesssolve(lv *Liveness) {
 
 	for change := true; change; {
 		change = false
+		for _, b := range po {
+			be := lv.blockEffects(b)
 
-		// Walk blocks in the general direction of propagation. This
-		// improves convergence.
-		for i := len(lv.cfg) - 1; i >= 0; i-- {
-			bb := lv.cfg[i]
-
-			// A variable is live on output from this block
-			// if it is live on input to some successor.
-			//
-			// out[b] = \bigcup_{s \in succ[b]} in[s]
 			newliveout.Clear()
-			for _, succ := range bb.succ {
-				newliveout.Or(newliveout, succ.livein)
+			switch b.Kind {
+			case ssa.BlockRet:
+				for _, pos := range lv.cache.retuevar {
+					newliveout.Set(pos)
+				}
+			case ssa.BlockRetJmp:
+				for _, pos := range lv.cache.tailuevar {
+					newliveout.Set(pos)
+				}
+			case ssa.BlockExit:
+				// nothing to do
+			default:
+				// A variable is live on output from this block
+				// if it is live on input to some successor.
+				//
+				// out[b] = \bigcup_{s \in succ[b]} in[s]
+				newliveout.Copy(lv.blockEffects(b.Succs[0].Block()).livein)
+				for _, succ := range b.Succs[1:] {
+					newliveout.Or(newliveout, lv.blockEffects(succ.Block()).livein)
+				}
 			}
 
-			if !bb.liveout.Eq(newliveout) {
+			if !be.liveout.Eq(newliveout) {
 				change = true
-				bb.liveout.Copy(newliveout)
+				be.liveout.Copy(newliveout)
 			}
 
 			// A variable is live on input to this block
@@ -1152,291 +610,349 @@ func livenesssolve(lv *Liveness) {
 			// not set by the code in this block.
 			//
 			// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
-			newlivein.AndNot(bb.liveout, bb.varkill)
-
-			bb.livein.Or(newlivein, bb.uevar)
-		}
-	}
-}
-
-// This function is slow but it is only used for generating debug prints.
-// Check whether n is marked live in args/locals.
-func islive(n *Node, args bvec, locals bvec) bool {
-	switch n.Class {
-	case PPARAM, PPARAMOUT:
-		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
-			if args.Get(int32(n.Xoffset/int64(Widthptr) + int64(i))) {
-				return true
-			}
-		}
-
-	case PAUTO:
-		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
-			if locals.Get(int32((n.Xoffset+stkptrsize)/int64(Widthptr) + int64(i))) {
-				return true
-			}
+			newlivein.AndNot(be.liveout, be.varkill)
+			be.livein.Or(newlivein, be.uevar)
 		}
 	}
-
-	return false
 }
 
 // Visits all instructions in a basic block and computes a bit vector of live
 // variables at each safe point locations.
 func livenessepilogue(lv *Liveness) {
 	nvars := int32(len(lv.vars))
-	livein := bvalloc(nvars)
 	liveout := bvalloc(nvars)
-	uevar := bvalloc(nvars)
-	varkill := bvalloc(nvars)
-	avarinit := bvalloc(nvars)
 	any := bvalloc(nvars)
 	all := bvalloc(nvars)
-	pparamout := bvalloc(localswords())
-
-	// Record 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 {
+	livedefer := bvalloc(nvars) // always-live variables
+
+	// If there is a defer (that could recover), then all output
+	// parameters are live all the time.  In addition, any locals
+	// that are pointers to heap-allocated output parameters are
+	// also always live (post-deferreturn code needs these
+	// pointers to copy values back to the stack).
+	// TODO: if the output parameter is heap-allocated, then we
+	// don't need to keep the stack copy live?
+	if lv.fn.Func.HasDefer() {
+		for i, n := range lv.vars {
+			if n.Class() == PPARAMOUT {
+				if n.IsOutputParamHeapAddr() {
+					// Just to be paranoid.  Heap addresses are PAUTOs.
+					Fatalf("variable %v both output param and heap output param", n)
+				}
+				if n.Name.Param.Heapaddr != nil {
+					// If this variable moved to the heap, then
+					// its stack copy is not live.
+					continue
+				}
+				// Note: zeroing is handled by zeroResults in walk.go.
+				livedefer.Set(int32(i))
+			}
 			if n.IsOutputParamHeapAddr() {
-				n.Name.Needzero = true
-				xoffset := n.Xoffset + stkptrsize
-				onebitwalktype1(n.Type, &xoffset, pparamout)
+				n.Name.SetNeedzero(true)
+				livedefer.Set(int32(i))
 			}
 		}
 	}
 
-	for _, bb := range lv.cfg {
+	{
+		// Reserve an entry for function entry.
+		live := bvalloc(nvars)
+		for _, pos := range lv.cache.textavarinit {
+			live.Set(pos)
+		}
+		lv.livevars = append(lv.livevars, live)
+	}
+
+	for _, b := range lv.f.Blocks {
+		be := lv.blockEffects(b)
+
 		// Compute avarinitany and avarinitall for entry to block.
 		// This duplicates information known during livenesssolve
 		// but avoids storing two more vectors for each block.
-		any.Clear()
-
-		all.Clear()
-		for j := 0; j < len(bb.pred); j++ {
-			pred := bb.pred[j]
-			if j == 0 {
-				any.Copy(pred.avarinitany)
-				all.Copy(pred.avarinitall)
-			} else {
-				any.Or(any, pred.avarinitany)
-				all.And(all, pred.avarinitall)
-			}
-		}
+		lv.avarinitanyall(b, any, all)
 
 		// Walk forward through the basic block instructions and
 		// allocate liveness maps for those instructions that need them.
 		// Seed the maps with information about the addrtaken variables.
-		for p := bb.first; ; p = p.Link {
-			progeffects(p, lv.vars, uevar, varkill, avarinit)
-			any.AndNot(any, varkill)
-			all.AndNot(all, varkill)
-			any.Or(any, avarinit)
-			all.Or(all, avarinit)
-
-			if issafepoint(p) {
-				// Annotate ambiguously live variables so that they can
-				// be zeroed at function entry.
-				// livein and liveout are dead here and used as temporaries.
-				livein.Clear()
-
-				liveout.AndNot(any, all)
-				if !liveout.IsEmpty() {
-					for pos := int32(0); pos < liveout.n; pos++ {
-						if !liveout.Get(pos) {
-							continue
-						}
-						all.Set(pos) // silence future warnings in this block
-						n := lv.vars[pos]
-						if !n.Name.Needzero {
-							n.Name.Needzero = true
-							if debuglive >= 1 {
-								Warnl(p.Lineno, "%v: %L is ambiguously live", Curfn.Func.Nname, n)
-							}
+		for _, v := range b.Values {
+			pos, e := lv.valueEffects(v)
+			if e&varkill != 0 {
+				any.Unset(pos)
+				all.Unset(pos)
+			}
+			if e&avarinit != 0 {
+				any.Set(pos)
+				all.Set(pos)
+			}
+
+			if !issafepoint(v) {
+				continue
+			}
+
+			// Annotate ambiguously live variables so that they can
+			// be zeroed at function entry and at VARKILL points.
+			// liveout is dead here and used as a temporary.
+			liveout.AndNot(any, all)
+			if !liveout.IsEmpty() {
+				for pos := int32(0); pos < liveout.n; pos++ {
+					if !liveout.Get(pos) {
+						continue
+					}
+					all.Set(pos) // silence future warnings in this block
+					n := lv.vars[pos]
+					if !n.Name.Needzero() {
+						n.Name.SetNeedzero(true)
+						if debuglive >= 1 {
+							Warnl(v.Pos, "%v: %L is ambiguously live", lv.fn.Func.Nname, n)
 						}
 					}
 				}
+			}
 
-				// Allocate a bit vector for each class and facet of
-				// value we are tracking.
+			// Live stuff first.
+			live := bvalloc(nvars)
+			live.Copy(any)
+			lv.livevars = append(lv.livevars, live)
+		}
 
-				// Live stuff first.
-				args := bvalloc(argswords())
+		be.lastbitmapindex = len(lv.livevars) - 1
+	}
 
-				lv.argslivepointers = append(lv.argslivepointers, args)
-				locals := bvalloc(localswords())
-				lv.livepointers = append(lv.livepointers, locals)
+	for _, b := range lv.f.Blocks {
+		be := lv.blockEffects(b)
 
-				if debuglive >= 3 {
-					fmt.Printf("%v\n", p)
-					printvars("avarinitany", any, lv.vars)
-				}
+		// walk backward, emit pcdata and populate the maps
+		index := int32(be.lastbitmapindex)
+		if index < 0 {
+			// the first block we encounter should have the ATEXT so
+			// at no point should pos ever be less than zero.
+			Fatalf("livenessepilogue")
+		}
 
-				// Record any values with an "address taken" reaching
-				// this code position as live. Must do now instead of below
-				// because the any/all calculation requires walking forward
-				// over the block (as this loop does), while the liveout
-				// requires walking backward (as the next loop does).
-				onebitlivepointermap(lv, any, lv.vars, args, locals)
+		liveout.Copy(be.liveout)
+		for i := len(b.Values) - 1; i >= 0; i-- {
+			v := b.Values[i]
+
+			if issafepoint(v) {
+				// Found an interesting instruction, record the
+				// corresponding liveness information.
+
+				live := lv.livevars[index]
+				live.Or(live, liveout)
+				live.Or(live, livedefer) // only for non-entry safe points
+				index--
 			}
 
-			if p == bb.last {
-				break
+			// Update liveness information.
+			pos, e := lv.valueEffects(v)
+			if e&varkill != 0 {
+				liveout.Unset(pos)
+			}
+			if e&uevar != 0 {
+				liveout.Set(pos)
 			}
 		}
 
-		bb.lastbitmapindex = len(lv.livepointers) - 1
-	}
-
-	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 = len(lv.livepointers)
-			startmsg = nmsg
-			msg = make([]string, nmsg)
-			for j := 0; j < nmsg; j++ {
-				msg[j] = ""
+		if b == lv.f.Entry {
+			if index != 0 {
+				Fatalf("bad index for entry point: %v", index)
 			}
+
+			// Record live variables.
+			live := lv.livevars[index]
+			live.Or(live, liveout)
 		}
+	}
 
-		// walk backward, emit pcdata and populate the maps
-		pos := int32(bb.lastbitmapindex)
+	// Useful sanity check: on entry to the function,
+	// the only things that can possibly be live are the
+	// input parameters.
+	for j, n := range lv.vars {
+		if n.Class() != PPARAM && lv.livevars[0].Get(int32(j)) {
+			Fatalf("internal error: %v %L recorded as live on entry", lv.fn.Func.Nname, n)
+		}
+	}
+}
 
-		if pos < 0 {
-			// the first block we encounter should have the ATEXT so
-			// at no point should pos ever be less than zero.
-			Fatalf("livenessepilogue")
+func (lv *Liveness) clobber() {
+	// The clobberdead experiment inserts code to clobber all the dead variables (locals and args)
+	// before and after every safepoint. This experiment is useful for debugging the generation
+	// of live pointer bitmaps.
+	if objabi.Clobberdead_enabled == 0 {
+		return
+	}
+	var varSize int64
+	for _, n := range lv.vars {
+		varSize += n.Type.Size()
+	}
+	if len(lv.livevars) > 1000 || varSize > 10000 {
+		// Be careful to avoid doing too much work.
+		// Bail if >1000 safepoints or >10000 bytes of variables.
+		// Otherwise, giant functions make this experiment generate too much code.
+		return
+	}
+	if h := os.Getenv("GOCLOBBERDEADHASH"); h != "" {
+		// Clobber only functions where the hash of the function name matches a pattern.
+		// Useful for binary searching for a miscompiled function.
+		hstr := ""
+		for _, b := range sha1.Sum([]byte(lv.fn.funcname())) {
+			hstr += fmt.Sprintf("%08b", b)
 		}
+		if !strings.HasSuffix(hstr, h) {
+			return
+		}
+		fmt.Printf("\t\t\tCLOBBERDEAD %s\n", lv.fn.funcname())
+	}
+	if lv.f.Name == "forkAndExecInChild" {
+		// forkAndExecInChild calls vfork (on linux/amd64, anyway).
+		// The code we add here clobbers parts of the stack in the child.
+		// When the parent resumes, it is using the same stack frame. But the
+		// child has clobbered stack variables that the parent needs. Boom!
+		// In particular, the sys argument gets clobbered.
+		// Note to self: GOCLOBBERDEADHASH=011100101110
+		return
+	}
 
-		livein.Copy(bb.liveout)
-		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)
-
-			liveout.Copy(livein)
-			livein.AndNot(liveout, varkill)
-			livein.Or(livein, uevar)
-			if debuglive >= 3 && issafepoint(p) {
-				fmt.Printf("%v\n", p)
-				printvars("uevar", uevar, lv.vars)
-				printvars("varkill", varkill, lv.vars)
-				printvars("livein", livein, lv.vars)
-				printvars("liveout", liveout, lv.vars)
+	var oldSched []*ssa.Value
+	for _, b := range lv.f.Blocks {
+		// Copy block's values to a temporary.
+		oldSched = append(oldSched[:0], b.Values...)
+		b.Values = b.Values[:0]
+
+		// Clobber all dead variables at entry.
+		if b == lv.f.Entry {
+			for len(oldSched) > 0 && len(oldSched[0].Args) == 0 {
+				// Skip argless ops. We need to skip at least
+				// the lowered ClosurePtr op, because it
+				// really wants to be first. This will also
+				// skip ops like InitMem and SP, which are ok.
+				b.Values = append(b.Values, oldSched[0])
+				oldSched = oldSched[1:]
 			}
+			clobber(lv, b, lv.livevars[0])
+		}
 
-			if issafepoint(p) {
-				// Found an interesting instruction, record the
-				// corresponding liveness information.
-
-				// Useful sanity check: on entry to the function,
-				// the only things that can possibly be live are the
-				// input parameters.
-				if p.As == obj.ATEXT {
-					for j := int32(0); j < liveout.n; j++ {
-						if !liveout.Get(j) {
-							continue
-						}
-						n := lv.vars[j]
-						if n.Class != PPARAM {
-							yyerrorl(p.Lineno, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
-						}
-					}
-				}
+		// Copy values into schedule, adding clobbering around safepoints.
+		for _, v := range oldSched {
+			if !issafepoint(v) {
+				b.Values = append(b.Values, v)
+				continue
+			}
+			before := true
+			if v.Op.IsCall() && v.Aux != nil && v.Aux.(*obj.LSym) == typedmemmove {
+				// Can't put clobber code before the call to typedmemmove.
+				// The variable to-be-copied is marked as dead
+				// at the callsite. That is ok, though, as typedmemmove
+				// is marked as nosplit, and the first thing it does
+				// is to call memmove (also nosplit), after which
+				// the source value is dead.
+				// See issue 16026.
+				before = false
+			}
+			if before {
+				clobber(lv, b, lv.livevars[lv.stackMapIndex[v]])
+			}
+			b.Values = append(b.Values, v)
+			clobber(lv, b, lv.livevars[lv.stackMapIndex[v]])
+		}
+	}
+}
 
-				// Record live pointers.
-				args := lv.argslivepointers[pos]
+// clobber generates code to clobber all dead variables (those not marked in live).
+// Clobbering instructions are added to the end of b.Values.
+func clobber(lv *Liveness, b *ssa.Block, live bvec) {
+	for i, n := range lv.vars {
+		if !live.Get(int32(i)) {
+			clobberVar(b, n)
+		}
+	}
+}
 
-				locals := lv.livepointers[pos]
-				onebitlivepointermap(lv, liveout, lv.vars, args, locals)
+// clobberVar generates code to trash the pointers in v.
+// Clobbering instructions are added to the end of b.Values.
+func clobberVar(b *ssa.Block, v *Node) {
+	clobberWalk(b, v, 0, v.Type)
+}
 
-				// Mark pparamout variables (as described above)
-				if p.As == obj.ACALL {
-					locals.Or(locals, pparamout)
-				}
+// b = block to which we append instructions
+// v = variable
+// offset = offset of (sub-portion of) variable to clobber (in bytes)
+// t = type of sub-portion of v.
+func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) {
+	if !types.Haspointers(t) {
+		return
+	}
+	switch t.Etype {
+	case TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TFUNC,
+		TCHAN,
+		TMAP:
+		clobberPtr(b, v, offset)
 
-				// Show live pointer bitmaps.
-				// We're interpreting the args and locals bitmap instead of liveout so that we
-				// include the bits added by the avarinit logic in the
-				// previous loop.
-				if msg != nil {
-					fmt_ := fmt.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 < len(lv.vars); j++ {
-						n := lv.vars[j]
-						if islive(n, args, locals) {
-							fmt_ += fmt.Sprintf(" %v", n)
-							numlive++
-						}
-					}
+	case TSTRING:
+		// struct { byte *str; int len; }
+		clobberPtr(b, v, offset)
 
-					fmt_ += "\n"
-					if numlive == 0 { // squelch message
+	case TINTER:
+		// struct { Itab *tab; void *data; }
+		// or, when isnilinter(t)==true:
+		// struct { Type *type; void *data; }
+		clobberPtr(b, v, offset)
+		clobberPtr(b, v, offset+int64(Widthptr))
 
-					} else {
-						startmsg--
-						msg[startmsg] = fmt_
-					}
-				}
+	case TSLICE:
+		// struct { byte *array; int len; int cap; }
+		clobberPtr(b, v, offset)
 
-				// Only CALL instructions need a PCDATA annotation.
-				// The TEXT instruction annotation is implicit.
-				if p.As == obj.ACALL {
-					if isdeferreturn(p) {
-						// runtime.deferreturn modifies its return address to return
-						// back to the CALL, not to the subsequent instruction.
-						// Because the return comes back one instruction early,
-						// the PCDATA must begin one instruction early too.
-						// The instruction before a call to deferreturn is always a
-						// no-op, to keep PC-specific data unambiguous.
-						prev := p.Opt.(*obj.Prog)
-						if Ctxt.Arch.Family == sys.PPC64 {
-							// On ppc64 there is an additional instruction
-							// (another no-op or reload of toc pointer) before
-							// the call.
-							prev = prev.Opt.(*obj.Prog)
-						}
-						splicebefore(lv, bb, newpcdataprog(prev, pos), prev)
-					} else {
-						splicebefore(lv, bb, newpcdataprog(p, pos), p)
-					}
-				}
+	case TARRAY:
+		for i := int64(0); i < t.NumElem(); i++ {
+			clobberWalk(b, v, offset+i*t.Elem().Size(), t.Elem())
+		}
 
-				pos--
-			}
+	case TSTRUCT:
+		for _, t1 := range t.Fields().Slice() {
+			clobberWalk(b, v, offset+t1.Offset, t1.Type)
 		}
 
-		if msg != nil {
-			for j := startmsg; j < nmsg; j++ {
-				if msg[j] != "" {
-					fmt.Printf("%s", msg[j])
-				}
-			}
+	default:
+		Fatalf("clobberWalk: unexpected type, %v", t)
+	}
+}
 
-			msg = nil
-			nmsg = 0
-			startmsg = 0
+// clobberPtr generates a clobber of the pointer at offset offset in v.
+// The clobber instruction is added at the end of b.
+func clobberPtr(b *ssa.Block, v *Node, offset int64) {
+	var aux interface{}
+	if v.Class() == PAUTO {
+		aux = &ssa.AutoSymbol{Node: v}
+	} else {
+		aux = &ssa.ArgSymbol{Node: v}
+	}
+	b.NewValue0IA(src.NoXPos, ssa.OpClobber, types.TypeVoid, offset, aux)
+}
+
+func (lv *Liveness) avarinitanyall(b *ssa.Block, any, all bvec) {
+	if len(b.Preds) == 0 {
+		any.Clear()
+		all.Clear()
+		for _, pos := range lv.cache.textavarinit {
+			any.Set(pos)
+			all.Set(pos)
 		}
+		return
 	}
 
-	flusherrors()
+	be := lv.blockEffects(b.Preds[0].Block())
+	any.Copy(be.avarinitany)
+	all.Copy(be.avarinitall)
+
+	for _, pred := range b.Preds[1:] {
+		be := lv.blockEffects(pred.Block())
+		any.Or(any, be.avarinitany)
+		all.And(all, be.avarinitall)
+	}
 }
 
 // FNV-1 hash function constants.
@@ -1476,7 +992,7 @@ func livenesscompact(lv *Liveness) {
 	// Linear probing hash table of bitmaps seen so far.
 	// The hash table has 4n entries to keep the linear
 	// scan short. An entry of -1 indicates an empty slot.
-	n := len(lv.livepointers)
+	n := len(lv.livevars)
 
 	tablesize := 4 * n
 	table := make([]int, tablesize)
@@ -1486,7 +1002,6 @@ func livenesscompact(lv *Liveness) {
 
 	// remap[i] = the new index of the old bit vector #i.
 	remap := make([]int, n)
-
 	for i := range remap {
 		remap[i] = -1
 	}
@@ -1494,24 +1009,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.livevars
 	// under the new index, and add entry to hash table.
-	// If already seen, record earlier index in remap and free bitmaps.
-	for i := 0; i < n; i++ {
-		local := lv.livepointers[i]
-		arg := lv.argslivepointers[i]
-		h := hashbitmap(hashbitmap(H0, local), arg) % uint32(tablesize)
+	// If already seen, record earlier index in remap.
+Outer:
+	for i, live := range lv.livevars {
+		h := hashbitmap(H0, live) % uint32(tablesize)
 
 		for {
 			j := table[h]
 			if j < 0 {
 				break
 			}
-			jlocal := lv.livepointers[j]
-			jarg := lv.argslivepointers[j]
-			if local.Eq(jlocal) && arg.Eq(jarg) {
+			jlive := lv.livevars[j]
+			if live.Eq(jlive) {
 				remap[i] = j
-				goto Next
+				continue Outer
 			}
 
 			h++
@@ -1522,37 +1035,72 @@ func livenesscompact(lv *Liveness) {
 
 		table[h] = uniq
 		remap[i] = uniq
-		lv.livepointers[uniq] = local
-		lv.argslivepointers[uniq] = arg
+		lv.livevars[uniq] = live
 		uniq++
-	Next:
 	}
 
-	// We've already reordered lv.livepointers[0:uniq]
-	// and lv.argslivepointers[0:uniq] and freed the bitmaps
-	// we don't need anymore. Clear the pointers later in the
-	// array so that we can tell where the coalesced bitmaps stop
-	// and so that we don't double-free when cleaning up.
-	for j := uniq; j < n; j++ {
-		lv.livepointers[j] = bvec{}
-		lv.argslivepointers[j] = bvec{}
+	// We've already reordered lv.livevars[0:uniq]. Clear the
+	// pointers later in the array so they can be GC'd.
+	tail := lv.livevars[uniq:]
+	for i := range tail { // memclr loop pattern
+		tail[i] = bvec{}
 	}
+	lv.livevars = lv.livevars[:uniq]
 
 	// Rewrite PCDATA instructions to use new numbering.
-	for p := lv.ptxt; p != nil; p = p.Link {
-		if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
-			i := p.To.Offset
-			if i >= 0 {
-				p.To.Offset = int64(remap[i])
+	lv.showlive(nil, lv.livevars[0])
+	pos := 1
+	lv.stackMapIndex = make(map[*ssa.Value]int)
+	for _, b := range lv.f.Blocks {
+		for _, v := range b.Values {
+			if issafepoint(v) {
+				lv.showlive(v, lv.livevars[remap[pos]])
+				lv.stackMapIndex[v] = int(remap[pos])
+				pos++
 			}
 		}
 	}
 }
 
-func printbitset(printed bool, name string, vars []*Node, bits bvec) bool {
+func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
+	if debuglive == 0 || lv.fn.funcname() == "init" || strings.HasPrefix(lv.fn.funcname(), ".") {
+		return
+	}
+	if live.IsEmpty() {
+		return
+	}
+
+	pos := lv.fn.Func.Nname.Pos
+	if v != nil {
+		pos = v.Pos
+	}
+
+	s := "live at "
+	if v == nil {
+		s += fmt.Sprintf("entry to %s:", lv.fn.funcname())
+	} else if sym, ok := v.Aux.(*obj.LSym); ok {
+		fn := sym.Name
+		if pos := strings.Index(fn, "."); pos >= 0 {
+			fn = fn[pos+1:]
+		}
+		s += fmt.Sprintf("call to %s:", fn)
+	} else {
+		s += "indirect call:"
+	}
+
+	for j, n := range lv.vars {
+		if live.Get(int32(j)) {
+			s += fmt.Sprintf(" %v", n)
+		}
+	}
+
+	Warnl(pos, s)
+}
+
+func (lv *Liveness) printbvec(printed bool, name string, live bvec) bool {
 	started := false
-	for i, n := range vars {
-		if !bits.Get(int32(i)) {
+	for i, n := range lv.vars {
+		if !live.Get(int32(i)) {
 			continue
 		}
 		if !started {
@@ -1570,100 +1118,126 @@ func printbitset(printed bool, name string, vars []*Node, bits bvec) bool {
 
 		fmt.Printf("%s", n.Sym.Name)
 	}
-
 	return printed
 }
 
+// printeffect is like printbvec, but for a single variable.
+func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bool {
+	if !x {
+		return printed
+	}
+	if !printed {
+		fmt.Printf("\t")
+	} else {
+		fmt.Printf(" ")
+	}
+	fmt.Printf("%s=%s", name, lv.vars[pos].Sym.Name)
+	return true
+}
+
 // Prints the computed liveness information and inputs, for debugging.
 // This format synthesizes the information used during the multiple passes
 // into a single presentation.
 func livenessprintdebug(lv *Liveness) {
-	fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
-
-	uevar := bvalloc(int32(len(lv.vars)))
-	varkill := bvalloc(int32(len(lv.vars)))
-	avarinit := bvalloc(int32(len(lv.vars)))
+	fmt.Printf("liveness: %s\n", lv.fn.funcname())
 
 	pcdata := 0
-	for i, bb := range lv.cfg {
+	for i, b := range lv.f.Blocks {
 		if i > 0 {
 			fmt.Printf("\n")
 		}
 
 		// bb#0 pred=1,2 succ=3,4
-		fmt.Printf("bb#%d pred=", i)
-
-		for j := 0; j < len(bb.pred); j++ {
+		fmt.Printf("bb#%d pred=", b.ID)
+		for j, pred := range b.Preds {
 			if j > 0 {
 				fmt.Printf(",")
 			}
-			fmt.Printf("%d", (bb.pred[j]).rpo)
+			fmt.Printf("%d", pred.Block().ID)
 		}
-
 		fmt.Printf(" succ=")
-		for j := 0; j < len(bb.succ); j++ {
+		for j, succ := range b.Succs {
 			if j > 0 {
 				fmt.Printf(",")
 			}
-			fmt.Printf("%d", (bb.succ[j]).rpo)
+			fmt.Printf("%d", succ.Block().ID)
 		}
-
 		fmt.Printf("\n")
 
-		// initial settings
-		var printed bool
+		be := lv.blockEffects(b)
 
-		printed = printbitset(printed, "uevar", lv.vars, bb.uevar)
-		printed = printbitset(printed, "livein", lv.vars, bb.livein)
+		// initial settings
+		printed := false
+		printed = lv.printbvec(printed, "uevar", be.uevar)
+		printed = lv.printbvec(printed, "livein", be.livein)
 		if printed {
 			fmt.Printf("\n")
 		}
 
 		// program listing, with individual effects listed
-		for p := bb.first; ; p = p.Link {
-			fmt.Printf("%v\n", p)
-			if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
-				pcdata = int(p.To.Offset)
+
+		if b == lv.f.Entry {
+			live := lv.livevars[pcdata]
+			fmt.Printf("(%s) function entry\n", linestr(lv.fn.Func.Nname.Pos))
+			fmt.Printf("\tlive=")
+			printed = false
+			for j, n := range lv.vars {
+				if !live.Get(int32(j)) {
+					continue
+				}
+				if printed {
+					fmt.Printf(",")
+				}
+				fmt.Printf("%v", n)
+				printed = true
 			}
-			progeffects(p, lv.vars, uevar, varkill, avarinit)
+			fmt.Printf("\n")
+		}
+
+		for _, v := range b.Values {
+			fmt.Printf("(%s) %v\n", linestr(v.Pos), v.LongString())
+
+			if pos, ok := lv.stackMapIndex[v]; ok {
+				pcdata = pos
+			}
+
+			pos, effect := lv.valueEffects(v)
 			printed = false
-			printed = printbitset(printed, "uevar", lv.vars, uevar)
-			printed = printbitset(printed, "varkill", lv.vars, varkill)
-			printed = printbitset(printed, "avarinit", lv.vars, avarinit)
+			printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0)
+			printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0)
+			printed = lv.printeffect(printed, "avarinit", pos, effect&avarinit != 0)
 			if printed {
 				fmt.Printf("\n")
 			}
-			if issafepoint(p) {
-				args := lv.argslivepointers[pcdata]
-				locals := lv.livepointers[pcdata]
-				fmt.Printf("\tlive=")
-				printed = false
-				for j := 0; j < len(lv.vars); j++ {
-					n := lv.vars[j]
-					if islive(n, args, locals) {
-						if printed {
-							fmt.Printf(",")
-						}
-						fmt.Printf("%v", n)
-						printed = true
-					}
-				}
-				fmt.Printf("\n")
+
+			if !issafepoint(v) {
+				continue
 			}
 
-			if p == bb.last {
-				break
+			live := lv.livevars[pcdata]
+			fmt.Printf("\tlive=")
+			printed = false
+			for j, n := range lv.vars {
+				if !live.Get(int32(j)) {
+					continue
+				}
+				if printed {
+					fmt.Printf(",")
+				}
+				fmt.Printf("%v", n)
+				printed = true
 			}
+			fmt.Printf("\n")
 		}
 
 		// bb bitsets
 		fmt.Printf("end\n")
-
-		printed = printbitset(printed, "varkill", lv.vars, bb.varkill)
-		printed = printbitset(printed, "liveout", lv.vars, bb.liveout)
-		printed = printbitset(printed, "avarinit", lv.vars, bb.avarinit)
-		printed = printbitset(printed, "avarinitany", lv.vars, bb.avarinitany)
-		printed = printbitset(printed, "avarinitall", lv.vars, bb.avarinitall)
+		printed = false
+		printed = lv.printbvec(printed, "varkill", be.varkill)
+		printed = lv.printbvec(printed, "liveout", be.liveout)
+		printed = lv.printbvec(printed, "avarinit", be.avarinit)
+		printed = lv.printbvec(printed, "avarinitany", be.avarinitany)
+		printed = lv.printbvec(printed, "avarinitall", be.avarinitall)
 		if printed {
 			fmt.Printf("\n")
 		}
@@ -1676,102 +1250,56 @@ func livenessprintdebug(lv *Liveness) {
 // 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
 // remaining bytes are the raw bitmaps.
-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
-	for i = 0; i < len(arr); i++ {
-		// bitmap words
-		bv := arr[i]
-
-		if bv.b == nil {
-			break
-		}
-		off = dbvec(sym, off, bv)
-	}
-
-	duint32(sym, 0, uint32(i)) // number of bitmaps
-	ls := Linksym(sym)
-	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
-	ls.Set(obj.AttrDuplicateOK, 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 livenessemit(lv *Liveness, argssym, livesym *obj.LSym) {
+	args := bvalloc(argswords(lv))
+	aoff := duint32(argssym, 0, uint32(len(lv.livevars))) // number of bitmaps
+	aoff = duint32(argssym, aoff, uint32(args.n))         // number of bits in each bitmap
 
-func printprog(p *obj.Prog) {
-	for p != nil {
-		fmt.Printf("%v\n", p)
-		p = p.Link
-	}
-}
+	locals := bvalloc(localswords(lv))
+	loff := duint32(livesym, 0, uint32(len(lv.livevars))) // number of bitmaps
+	loff = duint32(livesym, loff, uint32(locals.n))       // number of bits in each bitmap
 
-// Entry pointer for liveness analysis. Constructs a complete CFG, solves for
-// the liveness of pointer variables in the function, and emits a runtime data
-// structure read by the garbage collector.
-func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
-	// Change name to dump debugging information only for a specific function.
-	debugdelta := 0
+	for _, live := range lv.livevars {
+		args.Clear()
+		locals.Clear()
 
-	if Curfn.Func.Nname.Sym.Name == "!" {
-		debugdelta = 2
-	}
+		onebitlivepointermap(lv, live, lv.vars, args, locals)
 
-	debuglive += debugdelta
-	if debuglive >= 3 {
-		fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
-		printprog(firstp)
+		aoff = dbvec(argssym, aoff, args)
+		loff = dbvec(livesym, loff, locals)
 	}
 
-	checkptxt(fn, firstp)
+	// Give these LSyms content-addressable names,
+	// so that they can be de-duplicated.
+	// This provides significant binary size savings.
+	// It is safe to rename these LSyms because
+	// they are tracked separately from ctxt.hash.
+	argssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(argssym.P))
+	livesym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(livesym.P))
+}
 
+// Entry pointer for liveness analysis. Solves for the liveness of
+// pointer variables in the function and emits a runtime data
+// structure read by the garbage collector.
+// Returns a map from GC safe points to their corresponding stack map index.
+func liveness(e *ssafn, f *ssa.Func) map[*ssa.Value]int {
 	// Construct the global liveness state.
-	cfg := newcfg(firstp)
-
-	if debuglive >= 3 {
-		printcfg(cfg)
-	}
-	vars := getvariables(fn)
-	lv := newliveness(fn, firstp, cfg, vars)
+	vars, idx := getvariables(e.curfn)
+	lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize)
 
 	// Run the dataflow framework.
 	livenessprologue(lv)
-
-	if debuglive >= 3 {
-		livenessprintcfg(lv)
-	}
 	livenesssolve(lv)
-	if debuglive >= 3 {
-		livenessprintcfg(lv)
-	}
 	livenessepilogue(lv)
-	if debuglive >= 3 {
-		livenessprintcfg(lv)
-	}
 	livenesscompact(lv)
-
+	lv.clobber()
 	if debuglive >= 2 {
 		livenessprintdebug(lv)
 	}
 
 	// Emit the live pointer map data structures
-	onebitwritesymbol(lv.livepointers, livesym)
-
-	onebitwritesymbol(lv.argslivepointers, argssym)
-
-	// Free everything.
-	for _, ln := range fn.Func.Dcl {
-		if ln != nil {
-			ln.SetOpt(nil)
-		}
+	if ls := e.curfn.Func.lsym; ls != nil {
+		livenessemit(lv, &ls.Func.GCArgs, &ls.Func.GCLocals)
 	}
-
-	freecfg(cfg)
-
-	debuglive -= debugdelta
+	return lv.stackMapIndex
 }
diff --git a/src/cmd/compile/internal/gc/pprof.go b/src/cmd/compile/internal/gc/pprof.go
new file mode 100644
index 0000000..256c659
--- /dev/null
+++ b/src/cmd/compile/internal/gc/pprof.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package gc
+
+import "runtime"
+
+func startMutexProfiling() {
+	runtime.SetMutexProfileFraction(1)
+}
diff --git a/src/cmd/compile/internal/gc/race.go b/src/cmd/compile/internal/gc/race.go
new file mode 100644
index 0000000..78e1997
--- /dev/null
+++ b/src/cmd/compile/internal/gc/race.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build race
+
+package gc
+
+const raceEnabled = true
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index bfb82b9..cfb8031 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -5,6 +5,8 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"fmt"
 	"strings"
 )
@@ -66,7 +68,7 @@ func instrument(fn *Node) {
 		// getcallerpc. We use -widthptr(FP) for x86.
 		// BUG: this will not work on arm.
 		nodpc := *nodfp
-		nodpc.Type = Types[TUINTPTR]
+		nodpc.Type = types.Types[TUINTPTR]
 		nodpc.Xoffset = int64(-Widthptr)
 		nd := mkcall("racefuncenter", nil, nil, &nodpc)
 		fn.Func.Enter.Prepend(nd)
@@ -135,7 +137,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 	default:
 		Fatalf("instrument: unknown node type %v", n.Op)
 
-	case OAS, OASWB, OAS2FUNC:
+	case OAS, OAS2FUNC:
 		instrumentnode(&n.Left, init, 1, 0)
 		instrumentnode(&n.Right, init, 0, 0)
 		goto ret
@@ -186,8 +188,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 		OPLUS,
 		OREAL,
 		OIMAG,
-		OCOM,
-		OSQRT:
+		OCOM:
 		instrumentnode(&n.Left, init, wr, 0)
 		goto ret
 
@@ -216,7 +217,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 		instrumentnode(&n.Left, init, 0, 0)
 		if n.Left.Type.IsMap() {
 			n1 := nod(OCONVNOP, n.Left, nil)
-			n1.Type = ptrto(Types[TUINT8])
+			n1.Type = types.NewPtr(types.Types[TUINT8])
 			n1 = nod(OIND, n1, nil)
 			n1 = typecheck(n1, Erv)
 			callinstr(&n1, init, 0, skip)
@@ -226,14 +227,12 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 
 	case OLSH,
 		ORSH,
-		OLROT,
 		OAND,
 		OANDNOT,
 		OOR,
 		OXOR,
 		OSUB,
 		OMUL,
-		OHMUL,
 		OEQ,
 		ONE,
 		OLT,
@@ -366,20 +365,12 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 		OAS2RECV,
 		OAS2MAPR,
 		OASOP:
-		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", n.Op)
-		goto ret
+		Fatalf("instrument: %v must be lowered by now", n.Op)
 
 	case OGETG:
-		yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
-		goto ret
+		Fatalf("instrument: OGETG can happen only in runtime which we don't instrument")
 
-	case OFOR:
+	case OFOR, OFORUNTIL:
 		if n.Left != nil {
 			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
 		}
@@ -481,7 +472,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
 	if isartificial(b) {
 		return false
 	}
-	class := b.Class
+	class := b.Class()
 
 	// BUG: we _may_ want to instrument PAUTO sometimes
 	// e.g. if we've got a local variable/method receiver
@@ -495,7 +486,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
 			*np = n
 		}
 
-		n = treecopy(n, 0)
+		n = treecopy(n, src.NoXPos)
 		makeaddable(n)
 		var f *Node
 		if flag_msan {
@@ -570,15 +561,15 @@ func makeaddable(n *Node) {
 
 func uintptraddr(n *Node) *Node {
 	r := nod(OADDR, n, nil)
-	r.Bounded = true
-	r = conv(r, Types[TUNSAFEPTR])
-	r = conv(r, Types[TUINTPTR])
+	r.SetBounded(true)
+	r = conv(r, types.Types[TUNSAFEPTR])
+	r = conv(r, types.Types[TUINTPTR])
 	return r
 }
 
 func detachexpr(n *Node, init *Nodes) *Node {
 	addr := nod(OADDR, n, nil)
-	l := temp(ptrto(n.Type))
+	l := temp(types.NewPtr(n.Type))
 	as := nod(OAS, l, addr)
 	as = typecheck(as, Etop)
 	as = walkexpr(as, init)
@@ -632,10 +623,10 @@ func appendinit(np **Node, init Nodes) {
 		n = nod(OCONVNOP, n, nil)
 
 		n.Type = n.Left.Type
-		n.Typecheck = 1
+		n.SetTypecheck(1)
 		*np = n
 	}
 
 	n.Ninit.AppendNodes(&init)
-	n.Ullman = UINF
+	n.SetHasCall(true)
 }
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index b590474..963c268 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -4,14 +4,17 @@
 
 package gc
 
-import "unicode/utf8"
+import (
+	"cmd/compile/internal/types"
+	"unicode/utf8"
+)
 
 // range
 func typecheckrange(n *Node) {
 	var toomany int
 	var why string
-	var t1 *Type
-	var t2 *Type
+	var t1 *types.Type
+	var t2 *types.Type
 	var v1 *Node
 	var v2 *Node
 	var ls []*Node
@@ -52,7 +55,7 @@ func typecheckrange(n *Node) {
 		goto out
 
 	case TARRAY, TSLICE:
-		t1 = Types[TINT]
+		t1 = types.Types[TINT]
 		t2 = t.Elem()
 
 	case TMAP:
@@ -72,8 +75,8 @@ func typecheckrange(n *Node) {
 		}
 
 	case TSTRING:
-		t1 = Types[TINT]
-		t2 = runetype
+		t1 = types.Types[TINT]
+		t2 = types.Runetype
 	}
 
 	if n.List.Len() > 2 || toomany != 0 {
@@ -120,10 +123,10 @@ func typecheckrange(n *Node) {
 
 	// second half of dance
 out:
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 	ls = n.List.Slice()
 	for i1, n1 := range ls {
-		if n1.Typecheck == 0 {
+		if n1.Typecheck() == 0 {
 			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
@@ -133,7 +136,11 @@ out:
 	decldepth--
 }
 
-func walkrange(n *Node) {
+// walkrange transforms various forms of ORANGE into
+// simpler forms.  The result must be assigned back to n.
+// Node n may also be modified in place, and may also be
+// the returned node.
+func walkrange(n *Node) *Node {
 	// variable name conventions:
 	//	ohv1, hv1, hv2: hidden (old) val 1, 2
 	//	ha, hit: hidden aggregate, iterator
@@ -156,6 +163,14 @@ func walkrange(n *Node) {
 		v2 = n.List.Second()
 	}
 
+	if v1 == nil && v2 != nil {
+		Fatalf("walkrange: v2 != nil while v1 == nil")
+	}
+
+	var ifGuard *Node
+
+	translatedLoopOp := OFOR
+
 	// n.List has no meaning anymore, clear it
 	// to avoid erroneous processing by racewalk.
 	n.List.Set(nil)
@@ -169,22 +184,23 @@ func walkrange(n *Node) {
 	case TARRAY, TSLICE:
 		if memclrrange(n, v1, v2, a) {
 			lineno = lno
-			return
+			return n
 		}
 
 		// orderstmt arranged for a copy of the array/slice variable if needed.
 		ha := a
 
-		hv1 := temp(Types[TINT])
-		hn := temp(Types[TINT])
+		hv1 := temp(types.Types[TINT])
+		hn := temp(types.Types[TINT])
 		var hp *Node
 
 		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.Elem()))
+			hp = temp(types.NewPtr(n.Type.Elem()))
 			tmp := nod(OINDEX, ha, nodintconst(0))
-			tmp.Bounded = true
+			tmp.SetBounded(true)
 			init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
 		}
 
@@ -194,10 +210,14 @@ func walkrange(n *Node) {
 			body = nil
 		} else if v2 == nil {
 			body = []*Node{nod(OAS, v1, hv1)}
-		} else {
+		} else { // for i,a := range thing { body }
+			ifGuard = nod(OIF, nil, nil)
+			ifGuard.Left = nod(OLT, hv1, hn)
+			translatedLoopOp = OFORUNTIL
+
 			a := nod(OAS2, nil, nil)
-			a.List.Set([]*Node{v1, v2})
-			a.Rlist.Set([]*Node{hv1, nod(OIND, hp, nil)})
+			a.List.Set2(v1, v2)
+			a.Rlist.Set2(hv1, nod(OIND, hp, nil))
 			body = []*Node{a}
 
 			// Advance pointer as part of increment.
@@ -211,9 +231,9 @@ func walkrange(n *Node) {
 			tmp := nod(OADD, hp, nodintconst(t.Elem().Width))
 
 			tmp.Type = hp.Type
-			tmp.Typecheck = 1
-			tmp.Right.Type = Types[Tptr]
-			tmp.Right.Typecheck = 1
+			tmp.SetTypecheck(1)
+			tmp.Right.Type = types.Types[types.Tptr]
+			tmp.Right.SetTypecheck(1)
 			a = nod(OAS, hp, tmp)
 			a = typecheck(a, Etop)
 			n.Right.Ninit.Set1(a)
@@ -251,8 +271,8 @@ func walkrange(n *Node) {
 			val := nodSym(ODOT, hit, valsym)
 			val = nod(OIND, val, nil)
 			a := nod(OAS2, nil, nil)
-			a.List.Set([]*Node{v1, v2})
-			a.Rlist.Set([]*Node{key, val})
+			a.List.Set2(v1, v2)
+			a.Rlist.Set2(key, val)
 			body = []*Node{a}
 		}
 
@@ -263,16 +283,16 @@ func walkrange(n *Node) {
 		n.Left = nil
 
 		hv1 := temp(t.Elem())
-		hv1.Typecheck = 1
-		if haspointers(t.Elem()) {
+		hv1.SetTypecheck(1)
+		if types.Haspointers(t.Elem()) {
 			init = append(init, nod(OAS, hv1, nil))
 		}
-		hb := temp(Types[TBOOL])
+		hb := temp(types.Types[TBOOL])
 
 		n.Left = nod(ONE, hb, nodbool(false))
 		a := nod(OAS2RECV, nil, nil)
-		a.Typecheck = 1
-		a.List.Set([]*Node{hv1, hb})
+		a.SetTypecheck(1)
+		a.List.Set2(hv1, hb)
 		a.Rlist.Set1(nod(ORECV, ha, nil))
 		n.Left.Ninit.Set1(a)
 		if v1 == nil {
@@ -290,22 +310,23 @@ func walkrange(n *Node) {
 		//
 		// ha := a
 		// for hv1 := 0; hv1 < len(ha); {
-		//   v1 = hv1
+		//   hv1t := hv1
 		//   hv2 := rune(ha[hv1])
 		//   if hv2 < utf8.RuneSelf {
 		//      hv1++
 		//   } else {
 		//      hv2, hv1 = decoderune(ha, hv1)
 		//   }
-		//   v2 = hv2
+		//   v1, v2 = hv1t, hv2
 		//   // original body
 		// }
 
 		// orderstmt arranged for a copy of the string variable.
 		ha := a
 
-		hv1 := temp(Types[TINT])
-		hv2 := temp(runetype)
+		hv1 := temp(types.Types[TINT])
+		hv1t := temp(types.Types[TINT])
+		hv2 := temp(types.Runetype)
 
 		// hv1 := 0
 		init = append(init, nod(OAS, hv1, nil))
@@ -314,18 +335,18 @@ func walkrange(n *Node) {
 		n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
 
 		if v1 != nil {
-			// v1 = hv1
-			body = append(body, nod(OAS, v1, hv1))
+			// hv1t = hv1
+			body = append(body, nod(OAS, hv1t, hv1))
 		}
 
-		// hv2 := ha[hv1]
+		// hv2 := rune(ha[hv1])
 		nind := nod(OINDEX, ha, hv1)
-		nind.Bounded = true
-		body = append(body, nod(OAS, hv2, conv(nind, runetype)))
+		nind.SetBounded(true)
+		body = append(body, nod(OAS, hv2, conv(nind, types.Runetype)))
 
 		// if hv2 < utf8.RuneSelf
 		nif := nod(OIF, nil, nil)
-		nif.Left = nod(OLT, nind, nodintconst(utf8.RuneSelf))
+		nif.Left = nod(OLT, hv2, nodintconst(utf8.RuneSelf))
 
 		// hv1++
 		nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
@@ -341,23 +362,47 @@ func walkrange(n *Node) {
 
 		body = append(body, nif)
 
-		if v2 != nil {
-			// v2 = hv2
-			body = append(body, nod(OAS, v2, hv2))
+		if v1 != nil {
+			if v2 != nil {
+				// v1, v2 = hv1t, hv2
+				a := nod(OAS2, nil, nil)
+				a.List.Set2(v1, v2)
+				a.Rlist.Set2(hv1t, hv2)
+				body = append(body, a)
+			} else {
+				// v1 = hv1t
+				body = append(body, nod(OAS, v1, hv1t))
+			}
 		}
 	}
 
-	n.Op = OFOR
+	n.Op = translatedLoopOp
 	typecheckslice(init, Etop)
-	n.Ninit.Append(init...)
+
+	if ifGuard != nil {
+		ifGuard.Ninit.Append(init...)
+		typecheckslice(ifGuard.Left.Ninit.Slice(), Etop)
+		ifGuard.Left = typecheck(ifGuard.Left, Erv)
+	} else {
+		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.Prepend(body...)
+
+	if ifGuard != nil {
+		ifGuard.Nbody.Set1(n)
+		n = ifGuard
+	}
+
 	n = walkstmt(n)
 
 	lineno = lno
+	return n
 }
 
 // Lower n into runtime·memclr if possible, for
@@ -406,25 +451,25 @@ func memclrrange(n, v1, v2, a *Node) bool {
 	n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
 
 	// hp = &a[0]
-	hp := temp(ptrto(Types[TUINT8]))
+	hp := temp(types.Types[TUNSAFEPTR])
 
 	tmp := nod(OINDEX, a, nodintconst(0))
-	tmp.Bounded = true
+	tmp.SetBounded(true)
 	tmp = nod(OADDR, tmp, nil)
 	tmp = nod(OCONVNOP, tmp, nil)
-	tmp.Type = ptrto(Types[TUINT8])
+	tmp.Type = types.Types[TUNSAFEPTR]
 	n.Nbody.Append(nod(OAS, hp, tmp))
 
 	// hn = len(a) * sizeof(elem(a))
-	hn := temp(Types[TUINTPTR])
+	hn := temp(types.Types[TUINTPTR])
 
 	tmp = nod(OLEN, a, nil)
 	tmp = nod(OMUL, tmp, nodintconst(elemsize))
-	tmp = conv(tmp, Types[TUINTPTR])
+	tmp = conv(tmp, types.Types[TUINTPTR])
 	n.Nbody.Append(nod(OAS, hn, tmp))
 
 	var fn *Node
-	if haspointers(a.Type.Elem()) {
+	if types.Haspointers(a.Type.Elem()) {
 		// memclrHasPointers(hp, hn)
 		fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
 	} else {
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 61ac67c..8827d6c 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -5,49 +5,53 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
 	"cmd/internal/gcprog"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"fmt"
 	"os"
 	"sort"
 	"strings"
+	"sync"
 )
 
 type itabEntry struct {
-	t, itype *Type
-	sym      *Sym
+	t, itype *types.Type
+	lsym     *obj.LSym // symbol of the itab itself
+
+	// symbols of each method in
+	// the itab, sorted by byte offset;
+	// filled in by peekitabs
+	entries []*obj.LSym
 }
 
 type ptabEntry struct {
-	s *Sym
-	t *Type
+	s *types.Sym
+	t *types.Type
 }
 
 // runtime interface and reflection data structures
-var signatlist []*Node
-var itabs []itabEntry
-var ptabs []ptabEntry
+var (
+	signatsetmu sync.Mutex // protects signatset
+	signatset   = make(map[*types.Type]struct{})
+
+	itabs []itabEntry
+	ptabs []ptabEntry
+)
 
 type Sig struct {
 	name   string
-	pkg    *Pkg
-	isym   *Sym
-	tsym   *Sym
-	type_  *Type
-	mtype  *Type
+	pkg    *types.Pkg
+	isym   *types.Sym
+	tsym   *types.Sym
+	type_  *types.Type
+	mtype  *types.Type
 	offset int32
 }
 
-// byMethodNameAndPackagePath sorts method signatures by name, then package path.
-type byMethodNameAndPackagePath []*Sig
-
-func (x byMethodNameAndPackagePath) Len() int      { return len(x) }
-func (x byMethodNameAndPackagePath) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byMethodNameAndPackagePath) Less(i, j int) bool {
-	return siglt(x[i], x[j])
-}
-
-// siglt reports whether a < b
+// siglt sorts method signatures by name, then package path.
 func siglt(a, b *Sig) bool {
 	if a.name != b.name {
 		return a.name < b.name
@@ -75,51 +79,51 @@ const (
 	MAXVALSIZE = 128
 )
 
-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{})
+func structfieldSize() int             { return 3 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int                 { return 4 + 4 }        // Sizeof(runtime.imethod{})
+func uncommonSize(t *types.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()
+func makefield(name string, t *types.Type) *types.Field {
+	f := types.NewField()
 	f.Type = t
-	f.Sym = nopkg.Lookup(name)
+	f.Sym = (*types.Pkg)(nil).Lookup(name)
 	return f
 }
 
-func mapbucket(t *Type) *Type {
+func mapbucket(t *types.Type) *types.Type {
 	if t.MapType().Bucket != nil {
 		return t.MapType().Bucket
 	}
 
-	bucket := typ(TSTRUCT)
+	bucket := types.New(TSTRUCT)
 	keytype := t.Key()
 	valtype := t.Val()
 	dowidth(keytype)
 	dowidth(valtype)
 	if keytype.Width > MAXKEYSIZE {
-		keytype = ptrto(keytype)
+		keytype = types.NewPtr(keytype)
 	}
 	if valtype.Width > MAXVALSIZE {
-		valtype = ptrto(valtype)
+		valtype = types.NewPtr(valtype)
 	}
 
-	field := make([]*Field, 0, 5)
+	field := make([]*types.Field, 0, 5)
 
 	// The first field is: uint8 topbits[BUCKETSIZE].
-	arr := typArray(Types[TUINT8], BUCKETSIZE)
+	arr := types.NewArray(types.Types[TUINT8], BUCKETSIZE)
 	field = append(field, makefield("topbits", arr))
 
-	arr = typArray(keytype, BUCKETSIZE)
-	arr.Noalg = true
+	arr = types.NewArray(keytype, BUCKETSIZE)
+	arr.SetNoalg(true)
 	field = append(field, makefield("keys", arr))
 
-	arr = typArray(valtype, BUCKETSIZE)
-	arr.Noalg = true
+	arr = types.NewArray(valtype, BUCKETSIZE)
+	arr.SetNoalg(true)
 	field = append(field, makefield("values", arr))
 
 	// Make sure the overflow pointer is the last memory in the struct,
@@ -140,7 +144,7 @@ func mapbucket(t *Type) *Type {
 	// then it would end with an extra 32-bit padding field.
 	// Preempt that by emitting the padding here.
 	if int(t.Val().Align) > Widthptr || int(t.Key().Align) > Widthptr {
-		field = append(field, makefield("pad", Types[TUINTPTR]))
+		field = append(field, makefield("pad", types.Types[TUINTPTR]))
 	}
 
 	// If keys and values have no pointers, the map implementation
@@ -149,23 +153,23 @@ func mapbucket(t *Type) *Type {
 	// Arrange for the bucket to have no pointers by changing
 	// the type of the overflow field to uintptr in this case.
 	// See comment on hmap.overflow in ../../../../runtime/hashmap.go.
-	otyp := ptrto(bucket)
-	if !haspointers(t.Val()) && !haspointers(t.Key()) && t.Val().Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE {
-		otyp = Types[TUINTPTR]
+	otyp := types.NewPtr(bucket)
+	if !types.Haspointers(t.Val()) && !types.Haspointers(t.Key()) && t.Val().Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE {
+		otyp = types.Types[TUINTPTR]
 	}
 	ovf := makefield("overflow", otyp)
 	field = append(field, ovf)
 
 	// link up fields
-	bucket.Noalg = true
-	bucket.Local = t.Local
+	bucket.SetNoalg(true)
+	bucket.SetLocal(t.Local())
 	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.Offset != bucket.Width-int64(Widthptr) {
-		yyerror("bad math in mapbucket for %v", t)
+		Fatalf("bad math in mapbucket for %v", t)
 	}
 
 	t.MapType().Bucket = bucket
@@ -176,27 +180,27 @@ func mapbucket(t *Type) *Type {
 
 // Builds a type representing a Hmap structure for the given map type.
 // Make sure this stays in sync with ../../../../runtime/hashmap.go!
-func hmap(t *Type) *Type {
+func hmap(t *types.Type) *types.Type {
 	if t.MapType().Hmap != nil {
 		return t.MapType().Hmap
 	}
 
 	bucket := mapbucket(t)
-	fields := []*Field{
-		makefield("count", Types[TINT]),
-		makefield("flags", Types[TUINT8]),
-		makefield("B", Types[TUINT8]),
-		makefield("noverflow", Types[TUINT16]),
-		makefield("hash0", Types[TUINT32]),
-		makefield("buckets", ptrto(bucket)),
-		makefield("oldbuckets", ptrto(bucket)),
-		makefield("nevacuate", Types[TUINTPTR]),
-		makefield("overflow", Types[TUNSAFEPTR]),
-	}
-
-	h := typ(TSTRUCT)
-	h.Noalg = true
-	h.Local = t.Local
+	fields := []*types.Field{
+		makefield("count", types.Types[TINT]),
+		makefield("flags", types.Types[TUINT8]),
+		makefield("B", types.Types[TUINT8]),
+		makefield("noverflow", types.Types[TUINT16]),
+		makefield("hash0", types.Types[TUINT32]),
+		makefield("buckets", types.NewPtr(bucket)),
+		makefield("oldbuckets", types.NewPtr(bucket)),
+		makefield("nevacuate", types.Types[TUINTPTR]),
+		makefield("overflow", types.Types[TUNSAFEPTR]),
+	}
+
+	h := types.New(TSTRUCT)
+	h.SetNoalg(true)
+	h.SetLocal(t.Local())
 	h.SetFields(fields)
 	dowidth(h)
 	t.MapType().Hmap = h
@@ -204,7 +208,7 @@ func hmap(t *Type) *Type {
 	return h
 }
 
-func hiter(t *Type) *Type {
+func hiter(t *types.Type) *types.Type {
 	if t.MapType().Hiter != nil {
 		return t.MapType().Hiter
 	}
@@ -225,27 +229,27 @@ func hiter(t *Type) *Type {
 	//    checkBucket uintptr
 	// }
 	// 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)))
-	field[5] = makefield("bptr", ptrto(mapbucket(t)))
-	field[6] = makefield("overflow0", Types[TUNSAFEPTR])
-	field[7] = makefield("overflow1", Types[TUNSAFEPTR])
-	field[8] = makefield("startBucket", Types[TUINTPTR])
-	field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I
-	field[10] = makefield("bucket", Types[TUINTPTR])
-	field[11] = makefield("checkBucket", Types[TUINTPTR])
+	var field [12]*types.Field
+	field[0] = makefield("key", types.NewPtr(t.Key()))
+	field[1] = makefield("val", types.NewPtr(t.Val()))
+	field[2] = makefield("t", types.NewPtr(types.Types[TUINT8]))
+	field[3] = makefield("h", types.NewPtr(hmap(t)))
+	field[4] = makefield("buckets", types.NewPtr(mapbucket(t)))
+	field[5] = makefield("bptr", types.NewPtr(mapbucket(t)))
+	field[6] = makefield("overflow0", types.Types[TUNSAFEPTR])
+	field[7] = makefield("overflow1", types.Types[TUNSAFEPTR])
+	field[8] = makefield("startBucket", types.Types[TUINTPTR])
+	field[9] = makefield("stuff", types.Types[TUINTPTR]) // offset+wrapped+B+I
+	field[10] = makefield("bucket", types.Types[TUINTPTR])
+	field[11] = makefield("checkBucket", types.Types[TUINTPTR])
 
 	// build iterator struct holding the above fields
-	i := typ(TSTRUCT)
-	i.Noalg = true
+	i := types.New(TSTRUCT)
+	i.SetNoalg(true)
 	i.SetFields(field[:])
 	dowidth(i)
 	if i.Width != int64(12*Widthptr) {
-		yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
+		Fatalf("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
 	}
 	t.MapType().Hiter = i
 	i.StructType().Map = t
@@ -254,7 +258,7 @@ func hiter(t *Type) *Type {
 
 // f is method type, with receiver.
 // return function type, receiver as first argument (or not).
-func methodfunc(f *Type, receiver *Type) *Type {
+func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
 	var in []*Node
 	if receiver != nil {
 		d := nod(ODCLFIELD, nil, nil)
@@ -266,7 +270,7 @@ func methodfunc(f *Type, receiver *Type) *Type {
 	for _, t := range f.Params().Fields().Slice() {
 		d = nod(ODCLFIELD, nil, nil)
 		d.Type = t.Type
-		d.Isddd = t.Isddd
+		d.SetIsddd(t.Isddd())
 		in = append(in, d)
 	}
 
@@ -288,7 +292,7 @@ func methodfunc(f *Type, receiver *Type) *Type {
 
 // methods returns the methods of the non-interface type t, sorted by name.
 // Generates stub functions as needed.
-func methods(t *Type) []*Sig {
+func methods(t *types.Type) []*Sig {
 	// method type
 	mt := methtype(t)
 
@@ -301,7 +305,7 @@ func methods(t *Type) []*Sig {
 	it := t
 
 	if !isdirectiface(it) {
-		it = ptrto(t)
+		it = types.NewPtr(t)
 	}
 
 	// make list of methods for t,
@@ -314,7 +318,7 @@ func methods(t *Type) []*Sig {
 		if f.Type.Recv() == nil {
 			Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
 		}
-		if f.Nointerface {
+		if f.Nointerface() {
 			continue
 		}
 
@@ -347,22 +351,22 @@ func methods(t *Type) []*Sig {
 			sig.pkg = method.Pkg
 		}
 
-		sig.isym = methodsym(method, it, 1)
-		sig.tsym = methodsym(method, t, 0)
+		sig.isym = methodsym(method, it, true)
+		sig.tsym = methodsym(method, t, false)
 		sig.type_ = methodfunc(f.Type, t)
 		sig.mtype = methodfunc(f.Type, nil)
 
-		if sig.isym.Flags&SymSiggen == 0 {
-			sig.isym.Flags |= SymSiggen
-			if !eqtype(this, it) || this.Width < Types[Tptr].Width {
+		if !sig.isym.Siggen() {
+			sig.isym.SetSiggen(true)
+			if !eqtype(this, it) || this.Width < int64(Widthptr) {
 				compiling_wrappers = 1
 				genwrapper(it, f, sig.isym, 1)
 				compiling_wrappers = 0
 			}
 		}
 
-		if sig.tsym.Flags&SymSiggen == 0 {
-			sig.tsym.Flags |= SymSiggen
+		if !sig.tsym.Siggen() {
+			sig.tsym.SetSiggen(true)
 			if !eqtype(this, t) {
 				compiling_wrappers = 1
 				genwrapper(t, f, sig.tsym, 0)
@@ -371,12 +375,12 @@ func methods(t *Type) []*Sig {
 		}
 	}
 
-	sort.Sort(byMethodNameAndPackagePath(ms))
+	obj.SortSlice(ms, func(i, j int) bool { return siglt(ms[i], ms[j]) })
 	return ms
 }
 
 // imethods returns the methods of the interface type t, sorted by name.
-func imethods(t *Type) []*Sig {
+func imethods(t *types.Type) []*Sig {
 	var methods []*Sig
 	for _, f := range t.Fields().Slice() {
 		if f.Type.Etype != TFUNC || f.Sym == nil {
@@ -406,7 +410,7 @@ func imethods(t *Type) []*Sig {
 		methods = append(methods, &sig)
 
 		// Compiler can only refer to wrappers for non-blank methods.
-		if isblanksym(method) {
+		if method.IsBlank() {
 			continue
 		}
 
@@ -414,10 +418,9 @@ func imethods(t *Type) []*Sig {
 		// IfaceType.Method is not in the reflect data.
 		// Generate the method body, so that compiled
 		// code can refer to it.
-		isym := methodsym(method, t, 0)
-
-		if isym.Flags&SymSiggen == 0 {
-			isym.Flags |= SymSiggen
+		isym := methodsym(method, t, false)
+		if !isym.Siggen() {
+			isym.SetSiggen(true)
 			genwrapper(t, f, isym, 0)
 		}
 	}
@@ -425,7 +428,7 @@ func imethods(t *Type) []*Sig {
 	return methods
 }
 
-func dimportpath(p *Pkg) {
+func dimportpath(p *types.Pkg) {
 	if p.Pathsym != nil {
 		return
 	}
@@ -445,19 +448,15 @@ func dimportpath(p *Pkg) {
 		str = p.Path
 	}
 
-	s := obj.Linklookup(Ctxt, "type..importpath."+p.Prefix+".", 0)
+	s := Ctxt.Lookup("type..importpath." + p.Prefix + ".")
 	ot := dnameData(s, 0, str, "", nil, false)
-	ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+	ggloblsym(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 {
+func dgopkgpath(s *obj.LSym, ot int, pkg *types.Pkg) int {
 	if pkg == nil {
-		return duintxxLSym(s, ot, 0, Widthptr)
+		return duintptr(s, ot, 0)
 	}
 
 	if pkg == localpkg && myimportpath == "" {
@@ -466,18 +465,18 @@ func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int {
 		// 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 dsymptrLSym(s, ot, ns, 0)
+		ns := Ctxt.Lookup(`type..importpath."".`)
+		return dsymptr(s, ot, ns, 0)
 	}
 
 	dimportpath(pkg)
-	return dsymptrLSym(s, ot, pkg.Pathsym, 0)
+	return dsymptr(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 {
+// dgopkgpathOff writes an offset relocation in s at offset ot to the pkg path symbol.
+func dgopkgpathOff(s *obj.LSym, ot int, pkg *types.Pkg) int {
 	if pkg == nil {
-		return duintxxLSym(s, ot, 0, 4)
+		return duint32(s, ot, 0)
 	}
 	if pkg == localpkg && myimportpath == "" {
 		// If we don't know the full import path of the package being compiled
@@ -485,17 +484,17 @@ func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int {
 		// 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)
+		ns := Ctxt.Lookup(`type..importpath."".`)
+		return dsymptrOff(s, ot, ns, 0)
 	}
 
 	dimportpath(pkg)
-	return dsymptrOffLSym(s, ot, pkg.Pathsym, 0)
+	return dsymptrOff(s, ot, pkg.Pathsym, 0)
 }
 
 // isExportedField reports whether a struct field is exported.
 // It also returns the package to use for PkgPath for an unexported field.
-func isExportedField(ft *Field) (bool, *Pkg) {
+func isExportedField(ft *types.Field) (bool, *types.Pkg) {
 	if ft.Sym != nil && ft.Embedded == 0 {
 		return exportname(ft.Sym.Name), ft.Sym.Pkg
 	} else {
@@ -509,9 +508,9 @@ func isExportedField(ft *Field) (bool, *Pkg) {
 }
 
 // dnameField dumps a reflect.name for a struct field.
-func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
+func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int {
 	var name string
-	if ft.Sym != nil && ft.Embedded == 0 {
+	if ft.Sym != nil {
 		name = ft.Sym.Name
 	}
 	isExported, fpkg := isExportedField(ft)
@@ -519,11 +518,11 @@ func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
 		fpkg = nil
 	}
 	nsym := dname(name, ft.Note, fpkg, isExported)
-	return dsymptrLSym(Linksym(s), ot, nsym, 0)
+	return dsymptr(lsym, ot, nsym, 0)
 }
 
 // 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 {
+func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported bool) int {
 	if len(name) > 1<<16-1 {
 		Fatalf("name too long: %s", name)
 	}
@@ -559,7 +558,7 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) i
 	ot = int(s.WriteBytes(Ctxt, int64(ot), b))
 
 	if pkg != nil {
-		ot = dgopkgpathOffLSym(s, ot, pkg)
+		ot = dgopkgpathOff(s, ot, pkg)
 	}
 
 	return ot
@@ -568,7 +567,7 @@ func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) i
 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 {
+func dname(name, tag string, pkg *types.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
@@ -589,19 +588,19 @@ func dname(name, tag string, pkg *Pkg, exported bool) *obj.LSym {
 		sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
 		dnameCount++
 	}
-	s := obj.Linklookup(Ctxt, sname, 0)
+	s := Ctxt.Lookup(sname)
 	if len(s.P) > 0 {
 		return s
 	}
 	ot := dnameData(s, 0, name, tag, pkg, exported)
-	ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+	ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
 	return s
 }
 
 // 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 {
+func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
 	m := methods(t)
 	if t.Sym == nil && len(m) == 0 {
 		return ot
@@ -615,7 +614,7 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
 		dtypesym(a.type_)
 	}
 
-	ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
+	ot = dgopkgpathOff(lsym, ot, typePkg(t))
 
 	dataAdd += uncommonSize(t)
 	mcount := len(m)
@@ -626,14 +625,14 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
 		Fatalf("methods are too far away on %v: %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)
+	ot = duint16(lsym, ot, uint16(mcount))
+	ot = duint16(lsym, ot, 0)
+	ot = duint32(lsym, ot, uint32(dataAdd))
+	ot = duint32(lsym, ot, 0)
 	return ot
 }
 
-func typePkg(t *Type) *Pkg {
+func typePkg(t *types.Type) *types.Pkg {
 	tsym := t.Sym
 	if tsym == nil {
 		switch t.Etype {
@@ -643,7 +642,7 @@ func typePkg(t *Type) *Pkg {
 			}
 		}
 	}
-	if tsym != nil && t != Types[t.Etype] && t != errortype {
+	if tsym != nil && t != types.Types[t.Etype] && t != types.Errortype {
 		return tsym.Pkg
 	}
 	return nil
@@ -651,112 +650,68 @@ func typePkg(t *Type) *Pkg {
 
 // dextratypeData dumps the backing array for the []method field of
 // runtime.uncommontype.
-func dextratypeData(s *Sym, ot int, t *Type) int {
-	lsym := Linksym(s)
+func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
 	for _, a := range methods(t) {
 		// ../../../../runtime/type.go:/method
 		exported := exportname(a.name)
-		var pkg *Pkg
+		var pkg *types.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))
+		ot = dsymptrOff(lsym, ot, nsym, 0)
+		ot = dmethodptrOff(lsym, ot, dtypesym(a.mtype).Linksym())
+		ot = dmethodptrOff(lsym, ot, a.isym.Linksym())
+		ot = dmethodptrOff(lsym, ot, a.tsym.Linksym())
 	}
 	return ot
 }
 
-func dmethodptrOffLSym(s *obj.LSym, ot int, x *obj.LSym) int {
-	duintxxLSym(s, ot, 0, 4)
+func dmethodptrOff(s *obj.LSym, ot int, x *obj.LSym) int {
+	duint32(s, ot, 0)
 	r := obj.Addrel(s)
 	r.Off = int32(ot)
 	r.Siz = 4
 	r.Sym = x
-	r.Type = obj.R_METHODOFF
+	r.Type = objabi.R_METHODOFF
 	return ot + 4
 }
 
 var kinds = []int{
-	TINT:        obj.KindInt,
-	TUINT:       obj.KindUint,
-	TINT8:       obj.KindInt8,
-	TUINT8:      obj.KindUint8,
-	TINT16:      obj.KindInt16,
-	TUINT16:     obj.KindUint16,
-	TINT32:      obj.KindInt32,
-	TUINT32:     obj.KindUint32,
-	TINT64:      obj.KindInt64,
-	TUINT64:     obj.KindUint64,
-	TUINTPTR:    obj.KindUintptr,
-	TFLOAT32:    obj.KindFloat32,
-	TFLOAT64:    obj.KindFloat64,
-	TBOOL:       obj.KindBool,
-	TSTRING:     obj.KindString,
-	TPTR32:      obj.KindPtr,
-	TPTR64:      obj.KindPtr,
-	TSTRUCT:     obj.KindStruct,
-	TINTER:      obj.KindInterface,
-	TCHAN:       obj.KindChan,
-	TMAP:        obj.KindMap,
-	TARRAY:      obj.KindArray,
-	TSLICE:      obj.KindSlice,
-	TFUNC:       obj.KindFunc,
-	TCOMPLEX64:  obj.KindComplex64,
-	TCOMPLEX128: obj.KindComplex128,
-	TUNSAFEPTR:  obj.KindUnsafePointer,
-}
-
-func haspointers(t *Type) bool {
-	switch t.Etype {
-	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:
-		at := t.Extra.(*ArrayType)
-		if at.Haspointers != 0 {
-			return at.Haspointers-1 != 0
-		}
-
-		ret := false
-		if t.NumElem() != 0 { // non-empty array
-			ret = haspointers(t.Elem())
-		}
-
-		at.Haspointers = 1 + uint8(obj.Bool2int(ret))
-		return ret
-
-	case TSTRUCT:
-		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
-			}
-		}
-		st.Haspointers = 1 + uint8(obj.Bool2int(ret))
-		return ret
-	}
-
-	return true
+	TINT:        objabi.KindInt,
+	TUINT:       objabi.KindUint,
+	TINT8:       objabi.KindInt8,
+	TUINT8:      objabi.KindUint8,
+	TINT16:      objabi.KindInt16,
+	TUINT16:     objabi.KindUint16,
+	TINT32:      objabi.KindInt32,
+	TUINT32:     objabi.KindUint32,
+	TINT64:      objabi.KindInt64,
+	TUINT64:     objabi.KindUint64,
+	TUINTPTR:    objabi.KindUintptr,
+	TFLOAT32:    objabi.KindFloat32,
+	TFLOAT64:    objabi.KindFloat64,
+	TBOOL:       objabi.KindBool,
+	TSTRING:     objabi.KindString,
+	TPTR32:      objabi.KindPtr,
+	TPTR64:      objabi.KindPtr,
+	TSTRUCT:     objabi.KindStruct,
+	TINTER:      objabi.KindInterface,
+	TCHAN:       objabi.KindChan,
+	TMAP:        objabi.KindMap,
+	TARRAY:      objabi.KindArray,
+	TSLICE:      objabi.KindSlice,
+	TFUNC:       objabi.KindFunc,
+	TCOMPLEX64:  objabi.KindComplex64,
+	TCOMPLEX128: objabi.KindComplex128,
+	TUNSAFEPTR:  objabi.KindUnsafePointer,
 }
 
 // typeptrdata returns the length in bytes of the prefix of t
 // containing pointer data. Anything after this offset is scalar data.
-func typeptrdata(t *Type) int64 {
-	if !haspointers(t) {
+func typeptrdata(t *types.Type) int64 {
+	if !types.Haspointers(t) {
 		return 0
 	}
 
@@ -788,9 +743,9 @@ func typeptrdata(t *Type) int64 {
 
 	case TSTRUCT:
 		// Find the last field that has pointers.
-		var lastPtrField *Field
+		var lastPtrField *types.Field
 		for _, t1 := range t.Fields().Slice() {
-			if haspointers(t1.Type) {
+			if types.Haspointers(t1.Type) {
 				lastPtrField = t1
 			}
 		}
@@ -815,33 +770,37 @@ const (
 	tflagNamed     = 1 << 2
 )
 
-var dcommontype_algarray *Sym
+var (
+	algarray       *obj.LSym
+	memhashvarlen  *obj.LSym
+	memequalvarlen *obj.LSym
+)
 
 // dcommontype dumps the contents of a reflect.rtype (runtime._type).
-func dcommontype(s *Sym, ot int, t *Type) int {
+func dcommontype(lsym *obj.LSym, ot int, t *types.Type) int {
 	if ot != 0 {
 		Fatalf("dcommontype %d", ot)
 	}
 
 	sizeofAlg := 2 * Widthptr
-	if dcommontype_algarray == nil {
-		dcommontype_algarray = Pkglookup("algarray", Runtimepkg)
+	if algarray == nil {
+		algarray = Sysfunc("algarray")
 	}
 	dowidth(t)
 	alg := algtype(t)
-	var algsym *Sym
+	var algsym *obj.LSym
 	if alg == ASPECIAL || alg == AMEM {
 		algsym = dalgsym(t)
 	}
 
 	sptrWeak := true
-	var sptr *Sym
-	if !t.IsPtr() || t.ptrTo != nil {
-		tptr := ptrto(t)
+	var sptr *obj.LSym
+	if !t.IsPtr() || t.PtrBase != nil {
+		tptr := types.NewPtr(t)
 		if t.Sym != nil || methods(tptr) != nil {
 			sptrWeak = false
 		}
-		sptr = dtypesym(tptr)
+		sptr = dtypesym(tptr).Linksym()
 	}
 
 	gcsym, useGCProg, ptrdata := dgcsym(t)
@@ -861,10 +820,9 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	//		str           nameOff
 	//		ptrToThis     typeOff
 	//	}
-	ot = duintptr(s, ot, uint64(t.Width))
-	ot = duintptr(s, ot, uint64(ptrdata))
-
-	ot = duint32(s, ot, typehash(t))
+	ot = duintptr(lsym, ot, uint64(t.Width))
+	ot = duintptr(lsym, ot, uint64(ptrdata))
+	ot = duint32(lsym, ot, typehash(t))
 
 	var tflag uint8
 	if uncommonSize(t) != 0 {
@@ -875,7 +833,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	}
 
 	exported := false
-	p := t.tconv(FmtLeft | FmtUnsigned)
+	p := t.LongString()
 	// 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
@@ -893,7 +851,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 		}
 	}
 
-	ot = duint8(s, ot, tflag)
+	ot = duint8(lsym, ot, tflag)
 
 	// runtime (and common sense) expects alignment to be a power of two.
 	i := int(t.Align)
@@ -904,121 +862,135 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	if i&(i-1) != 0 {
 		Fatalf("invalid alignment %d for %v", t.Align, t)
 	}
-	ot = duint8(s, ot, t.Align) // align
-	ot = duint8(s, ot, t.Align) // fieldAlign
+	ot = duint8(lsym, ot, t.Align) // align
+	ot = duint8(lsym, ot, t.Align) // fieldAlign
 
 	i = kinds[t.Etype]
-	if !haspointers(t) {
-		i |= obj.KindNoPointers
+	if !types.Haspointers(t) {
+		i |= objabi.KindNoPointers
 	}
 	if isdirectiface(t) {
-		i |= obj.KindDirectIface
+		i |= objabi.KindDirectIface
 	}
 	if useGCProg {
-		i |= obj.KindGCProg
+		i |= objabi.KindGCProg
 	}
-	ot = duint8(s, ot, uint8(i)) // kind
+	ot = duint8(lsym, ot, uint8(i)) // kind
 	if algsym == nil {
-		ot = dsymptr(s, ot, dcommontype_algarray, int(alg)*sizeofAlg)
+		ot = dsymptr(lsym, ot, algarray, int(alg)*sizeofAlg)
 	} else {
-		ot = dsymptr(s, ot, algsym, 0)
+		ot = dsymptr(lsym, ot, algsym, 0)
 	}
-	ot = dsymptr(s, ot, gcsym, 0) // gcdata
+	ot = dsymptr(lsym, ot, gcsym, 0) // gcdata
 
 	nsym := dname(p, "", nil, exported)
-	ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) // str
+	ot = dsymptrOff(lsym, ot, nsym, 0) // str
 	// ptrToThis
 	if sptr == nil {
-		ot = duint32(s, ot, 0)
+		ot = duint32(lsym, ot, 0)
 	} else if sptrWeak {
-		ot = dsymptrWeakOffLSym(Linksym(s), ot, Linksym(sptr))
+		ot = dsymptrWeakOff(lsym, ot, sptr)
 	} else {
-		ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0)
+		ot = dsymptrOff(lsym, ot, sptr, 0)
 	}
 
 	return ot
 }
 
-func typesym(t *Type) *Sym {
-	name := t.tconv(FmtLeft)
-
+func typesymname(t *types.Type) string {
+	name := t.ShortString()
 	// Use a separate symbol name for Noalg types for #17752.
-	if a, bad := algtype1(t); a == ANOEQ && bad.Noalg {
+	if a, bad := algtype1(t); a == ANOEQ && bad.Noalg() {
 		name = "noalg." + name
 	}
+	return name
+}
 
-	return Pkglookup(name, typepkg)
+// Fake package for runtime type info (headers)
+// Don't access directly, use typeLookup below.
+var (
+	typepkgmu sync.Mutex // protects typepkg lookups
+	typepkg   = types.NewPkg("type", "type")
+)
+
+func typeLookup(name string) *types.Sym {
+	typepkgmu.Lock()
+	s := typepkg.Lookup(name)
+	typepkgmu.Unlock()
+	return s
+}
+
+func typesym(t *types.Type) *types.Sym {
+	return typeLookup(typesymname(t))
 }
 
 // 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(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg)
+func tracksym(t *types.Type, f *types.Field) *types.Sym {
+	return trackpkg.Lookup(t.ShortString() + "." + f.Sym.Name)
 }
 
-func typesymprefix(prefix string, t *Type) *Sym {
-	p := prefix + "." + t.tconv(FmtLeft)
-	s := Pkglookup(p, typepkg)
+func typesymprefix(prefix string, t *types.Type) *types.Sym {
+	p := prefix + "." + t.ShortString()
+	s := typeLookup(p)
 
 	//print("algsym: %s -> %+S\n", p, s);
 
 	return s
 }
 
-func typenamesym(t *Type) *Sym {
+func typenamesym(t *types.Type) *types.Sym {
 	if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
-		Fatalf("typename %v", t)
+		Fatalf("typenamesym %v", t)
 	}
 	s := typesym(t)
-	if s.Def == nil {
-		n := newname(s)
-		n.Type = Types[TUINT8]
-		n.Class = PEXTERN
-		n.Typecheck = 1
-		s.Def = n
-
-		signatlist = append(signatlist, typenod(t))
-	}
-
-	return s.Def.Sym
+	signatsetmu.Lock()
+	addsignat(t)
+	signatsetmu.Unlock()
+	return s
 }
 
-func typename(t *Type) *Node {
+func typename(t *types.Type) *Node {
 	s := typenamesym(t)
-	n := nod(OADDR, s.Def, nil)
-	n.Type = ptrto(s.Def.Type)
-	n.Addable = true
-	n.Ullman = 2
-	n.Typecheck = 1
+	if s.Def == nil {
+		n := newnamel(src.NoXPos, s)
+		n.Type = types.Types[TUINT8]
+		n.SetClass(PEXTERN)
+		n.SetTypecheck(1)
+		s.Def = asTypesNode(n)
+	}
+
+	n := nod(OADDR, asNode(s.Def), nil)
+	n.Type = types.NewPtr(asNode(s.Def).Type)
+	n.SetAddable(true)
+	n.SetTypecheck(1)
 	return n
 }
 
-func itabname(t, itype *Type) *Node {
+func itabname(t, itype *types.Type) *Node {
 	if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
 		Fatalf("itabname(%v, %v)", t, itype)
 	}
-	s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg)
+	s := itabpkg.Lookup(t.ShortString() + "," + itype.ShortString())
 	if s.Def == nil {
 		n := newname(s)
-		n.Type = Types[TUINT8]
-		n.Class = PEXTERN
-		n.Typecheck = 1
-		s.Def = n
-
-		itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s})
+		n.Type = types.Types[TUINT8]
+		n.SetClass(PEXTERN)
+		n.SetTypecheck(1)
+		s.Def = asTypesNode(n)
+		itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
 	}
 
-	n := nod(OADDR, s.Def, nil)
-	n.Type = ptrto(s.Def.Type)
-	n.Addable = true
-	n.Ullman = 2
-	n.Typecheck = 1
+	n := nod(OADDR, asNode(s.Def), nil)
+	n.Type = types.NewPtr(asNode(s.Def).Type)
+	n.SetAddable(true)
+	n.SetTypecheck(1)
 	return n
 }
 
 // isreflexive reports whether t has a reflexive equality operator.
 // That is, if x==x for all x of type t.
-func isreflexive(t *Type) bool {
+func isreflexive(t *types.Type) bool {
 	switch t.Etype {
 	case TBOOL,
 		TINT,
@@ -1065,30 +1037,13 @@ func isreflexive(t *Type) bool {
 
 // needkeyupdate reports whether map updates with t as a key
 // need the key to be updated.
-func needkeyupdate(t *Type) bool {
+func needkeyupdate(t *types.Type) bool {
 	switch t.Etype {
-	case TBOOL,
-		TINT,
-		TUINT,
-		TINT8,
-		TUINT8,
-		TINT16,
-		TUINT16,
-		TINT32,
-		TUINT32,
-		TINT64,
-		TUINT64,
-		TUINTPTR,
-		TPTR32,
-		TPTR64,
-		TUNSAFEPTR,
-		TCHAN:
+	case TBOOL, TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32,
+		TINT64, TUINT64, TUINTPTR, TPTR32, TPTR64, TUNSAFEPTR, TCHAN:
 		return false
 
-	case TFLOAT32, // floats can be +0/-0
-		TFLOAT64,
-		TCOMPLEX64,
-		TCOMPLEX128,
+	case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, // floats and complex can be +0/-0
 		TINTER,
 		TSTRING: // strings might have smaller backing stores
 		return true
@@ -1110,23 +1065,27 @@ func needkeyupdate(t *Type) bool {
 	}
 }
 
-func dtypesym(t *Type) *Sym {
-	// Replace byte, rune aliases with real type.
-	// They've been separate internally to make error messages
-	// better, but we have to merge them in the reflect tables.
-	if t == bytetype || t == runetype {
-		t = Types[t.Etype]
+// formalType replaces byte and rune aliases with real types.
+// They've been separate internally to make error messages
+// better, but we have to merge them in the reflect tables.
+func formalType(t *types.Type) *types.Type {
+	if t == types.Bytetype || t == types.Runetype {
+		return types.Types[t.Etype]
 	}
+	return t
+}
 
+func dtypesym(t *types.Type) *types.Sym {
+	t = formalType(t)
 	if t.IsUntyped() {
 		Fatalf("dtypesym %v", t)
 	}
 
 	s := typesym(t)
-	if s.Flags&SymSiggen != 0 {
+	if s.Siggen() {
 		return s
 	}
-	s.Flags |= SymSiggen
+	s.SetSiggen(true)
 
 	// special case (look for runtime below):
 	// when compiling package runtime,
@@ -1141,12 +1100,12 @@ func dtypesym(t *Type) *Sym {
 		dupok = obj.DUPOK
 	}
 
-	if myimportpath == "runtime" && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc
+	if myimportpath == "runtime" && (tbase == types.Types[tbase.Etype] || tbase == types.Bytetype || tbase == types.Runetype || tbase == types.Errortype) { // int, float, etc
 		goto ok
 	}
 
 	// named types from other files are defined only by those files
-	if tbase.Sym != nil && !tbase.Local {
+	if tbase.Sym != nil && !tbase.Local() {
 		return s
 	}
 	if isforw[tbase.Etype] {
@@ -1155,36 +1114,37 @@ func dtypesym(t *Type) *Sym {
 
 ok:
 	ot := 0
+	lsym := s.Linksym()
 	switch t.Etype {
 	default:
-		ot = dcommontype(s, ot, t)
-		ot = dextratype(s, ot, t, 0)
+		ot = dcommontype(lsym, ot, t)
+		ot = dextratype(lsym, ot, t, 0)
 
 	case TARRAY:
 		// ../../../../runtime/type.go:/arrayType
 		s1 := dtypesym(t.Elem())
-		t2 := typSlice(t.Elem())
+		t2 := types.NewSlice(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(lsym, ot, t)
+		ot = dsymptr(lsym, ot, s1.Linksym(), 0)
+		ot = dsymptr(lsym, ot, s2.Linksym(), 0)
+		ot = duintptr(lsym, ot, uint64(t.NumElem()))
+		ot = dextratype(lsym, ot, t, 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)
+		ot = dcommontype(lsym, ot, t)
+		ot = dsymptr(lsym, ot, s1.Linksym(), 0)
+		ot = dextratype(lsym, ot, t, 0)
 
 	case TCHAN:
 		// ../../../../runtime/type.go:/chanType
 		s1 := dtypesym(t.Elem())
-		ot = dcommontype(s, ot, t)
-		ot = dsymptr(s, ot, s1, 0)
-		ot = duintptr(s, ot, uint64(t.ChanDir()))
-		ot = dextratype(s, ot, t, 0)
+		ot = dcommontype(lsym, ot, t)
+		ot = dsymptr(lsym, ot, s1.Linksym(), 0)
+		ot = duintptr(lsym, ot, uint64(t.ChanDir()))
+		ot = dextratype(lsym, ot, t, 0)
 
 	case TFUNC:
 		for _, t1 := range t.Recvs().Fields().Slice() {
@@ -1192,37 +1152,37 @@ ok:
 		}
 		isddd := false
 		for _, t1 := range t.Params().Fields().Slice() {
-			isddd = t1.Isddd
+			isddd = t1.Isddd()
 			dtypesym(t1.Type)
 		}
 		for _, t1 := range t.Results().Fields().Slice() {
 			dtypesym(t1.Type)
 		}
 
-		ot = dcommontype(s, ot, t)
+		ot = dcommontype(lsym, ot, t)
 		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))
+		ot = duint16(lsym, ot, uint16(inCount))
+		ot = duint16(lsym, ot, uint16(outCount))
 		if Widthptr == 8 {
 			ot += 4 // align for *rtype
 		}
 
 		dataAdd := (inCount + t.Results().NumFields()) * Widthptr
-		ot = dextratype(s, ot, t, dataAdd)
+		ot = dextratype(lsym, ot, t, dataAdd)
 
 		// Array of rtype pointers follows funcType.
 		for _, t1 := range t.Recvs().Fields().Slice() {
-			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			ot = dsymptr(lsym, ot, dtypesym(t1.Type).Linksym(), 0)
 		}
 		for _, t1 := range t.Params().Fields().Slice() {
-			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			ot = dsymptr(lsym, ot, dtypesym(t1.Type).Linksym(), 0)
 		}
 		for _, t1 := range t.Results().Fields().Slice() {
-			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			ot = dsymptr(lsym, ot, dtypesym(t1.Type).Linksym(), 0)
 		}
 
 	case TINTER:
@@ -1233,32 +1193,31 @@ ok:
 		}
 
 		// ../../../../runtime/type.go:/interfaceType
-		ot = dcommontype(s, ot, t)
+		ot = dcommontype(lsym, ot, t)
 
-		var tpkg *Pkg
-		if t.Sym != nil && t != Types[t.Etype] && t != errortype {
+		var tpkg *types.Pkg
+		if t.Sym != nil && t != types.Types[t.Etype] && t != types.Errortype {
 			tpkg = t.Sym.Pkg
 		}
-		ot = dgopkgpath(s, ot, tpkg)
+		ot = dgopkgpath(lsym, 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)
+		ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
+		ot = duintptr(lsym, ot, uint64(n))
+		ot = duintptr(lsym, ot, uint64(n))
 		dataAdd := imethodSize() * n
-		ot = dextratype(s, ot, t, dataAdd)
+		ot = dextratype(lsym, ot, t, dataAdd)
 
-		lsym := Linksym(s)
 		for _, a := range m {
 			// ../../../../runtime/type.go:/imethod
 			exported := exportname(a.name)
-			var pkg *Pkg
+			var pkg *types.Pkg
 			if !exported && a.pkg != tpkg {
 				pkg = a.pkg
 			}
 			nsym := dname(a.name, "", pkg, exported)
 
-			ot = dsymptrOffLSym(lsym, ot, nsym, 0)
-			ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0)
+			ot = dsymptrOff(lsym, ot, nsym, 0)
+			ot = dsymptrOff(lsym, ot, dtypesym(a.type_).Linksym(), 0)
 		}
 
 	// ../../../../runtime/type.go:/mapType
@@ -1267,37 +1226,37 @@ ok:
 		s2 := dtypesym(t.Val())
 		s3 := dtypesym(mapbucket(t))
 		s4 := dtypesym(hmap(t))
-		ot = dcommontype(s, ot, t)
-		ot = dsymptr(s, ot, s1, 0)
-		ot = dsymptr(s, ot, s2, 0)
-		ot = dsymptr(s, ot, s3, 0)
-		ot = dsymptr(s, ot, s4, 0)
+		ot = dcommontype(lsym, ot, t)
+		ot = dsymptr(lsym, ot, s1.Linksym(), 0)
+		ot = dsymptr(lsym, ot, s2.Linksym(), 0)
+		ot = dsymptr(lsym, ot, s3.Linksym(), 0)
+		ot = dsymptr(lsym, ot, s4.Linksym(), 0)
 		if t.Key().Width > MAXKEYSIZE {
-			ot = duint8(s, ot, uint8(Widthptr))
-			ot = duint8(s, ot, 1) // indirect
+			ot = duint8(lsym, ot, uint8(Widthptr))
+			ot = duint8(lsym, ot, 1) // indirect
 		} else {
-			ot = duint8(s, ot, uint8(t.Key().Width))
-			ot = duint8(s, ot, 0) // not indirect
+			ot = duint8(lsym, ot, uint8(t.Key().Width))
+			ot = duint8(lsym, ot, 0) // not indirect
 		}
 
 		if t.Val().Width > MAXVALSIZE {
-			ot = duint8(s, ot, uint8(Widthptr))
-			ot = duint8(s, ot, 1) // indirect
+			ot = duint8(lsym, ot, uint8(Widthptr))
+			ot = duint8(lsym, ot, 1) // indirect
 		} else {
-			ot = duint8(s, ot, uint8(t.Val().Width))
-			ot = duint8(s, ot, 0) // not indirect
+			ot = duint8(lsym, ot, uint8(t.Val().Width))
+			ot = duint8(lsym, ot, 0) // not indirect
 		}
 
-		ot = duint16(s, ot, uint16(mapbucket(t).Width))
-		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)
+		ot = duint16(lsym, ot, uint16(mapbucket(t).Width))
+		ot = duint8(lsym, ot, uint8(obj.Bool2int(isreflexive(t.Key()))))
+		ot = duint8(lsym, ot, uint8(obj.Bool2int(needkeyupdate(t.Key()))))
+		ot = dextratype(lsym, ot, t, 0)
 
 	case TPTR32, TPTR64:
 		if t.Elem().Etype == TANY {
 			// ../../../../runtime/type.go:/UnsafePointerType
-			ot = dcommontype(s, ot, t)
-			ot = dextratype(s, ot, t, 0)
+			ot = dcommontype(lsym, ot, t)
+			ot = dextratype(lsym, ot, t, 0)
 
 			break
 		}
@@ -1305,9 +1264,9 @@ ok:
 		// ../../../../runtime/type.go:/ptrType
 		s1 := dtypesym(t.Elem())
 
-		ot = dcommontype(s, ot, t)
-		ot = dsymptr(s, ot, s1, 0)
-		ot = dextratype(s, ot, t, 0)
+		ot = dcommontype(lsym, ot, t)
+		ot = dsymptr(lsym, ot, s1.Linksym(), 0)
+		ot = dextratype(lsym, ot, t, 0)
 
 	// ../../../../runtime/type.go:/structType
 	// for security, only the exported fields.
@@ -1319,7 +1278,7 @@ ok:
 			n++
 		}
 
-		ot = dcommontype(s, ot, t)
+		ot = dcommontype(lsym, ot, t)
 		pkg := localpkg
 		if t.Sym != nil {
 			pkg = t.Sym.Pkg
@@ -1333,24 +1292,31 @@ ok:
 				break
 			}
 		}
-		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)
+		ot = dgopkgpath(lsym, ot, pkg)
+		ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
+		ot = duintptr(lsym, ot, uint64(n))
+		ot = duintptr(lsym, ot, uint64(n))
 
 		dataAdd := n * structfieldSize()
-		ot = dextratype(s, ot, t, dataAdd)
+		ot = dextratype(lsym, ot, t, dataAdd)
 
 		for _, f := range t.Fields().Slice() {
 			// ../../../../runtime/type.go:/structField
-			ot = dnameField(s, ot, pkg, f)
-			ot = dsymptr(s, ot, dtypesym(f.Type), 0)
-			ot = duintptr(s, ot, uint64(f.Offset))
+			ot = dnameField(lsym, ot, pkg, f)
+			ot = dsymptr(lsym, ot, dtypesym(f.Type).Linksym(), 0)
+			offsetAnon := uint64(f.Offset) << 1
+			if offsetAnon>>1 != uint64(f.Offset) {
+				Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
+			}
+			if f.Embedded != 0 {
+				offsetAnon |= 1
+			}
+			ot = duintptr(lsym, ot, offsetAnon)
 		}
 	}
 
-	ot = dextratypeData(s, ot, t)
-	ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
+	ot = dextratypeData(lsym, ot, t)
+	ggloblsym(lsym, int32(ot), int16(dupok|obj.RODATA))
 
 	// The linker will leave a table of all the typelinks for
 	// types in the binary, so the runtime can find them.
@@ -1369,34 +1335,118 @@ ok:
 			keep = true
 		}
 	}
-	s.Lsym.Set(obj.AttrMakeTypelink, keep)
+	lsym.Set(obj.AttrMakeTypelink, keep)
 
 	return s
 }
 
-func dumptypestructs() {
-	// copy types from externdcl list to signatlist
-	for _, n := range externdcl {
-		if n.Op != OTYPE {
+// for each itabEntry, gather the methods on
+// the concrete type that implement the interface
+func peekitabs() {
+	for i := range itabs {
+		tab := &itabs[i]
+		methods := genfun(tab.t, tab.itype)
+		if len(methods) == 0 {
 			continue
 		}
-		signatlist = append(signatlist, n)
+		tab.entries = methods
 	}
+}
 
-	// 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
+// for the given concrete type and interface
+// type, return the (sorted) set of methods
+// on the concrete type that implement the interface
+func genfun(t, it *types.Type) []*obj.LSym {
+	if t == nil || it == nil {
+		return nil
+	}
+	sigs := imethods(it)
+	methods := methods(t)
+	out := make([]*obj.LSym, 0, len(sigs))
+	if len(sigs) == 0 {
+		return nil
+	}
+
+	// both sigs and methods are sorted by name,
+	// so we can find the intersect in a single pass
+	for _, m := range methods {
+		if m.name == sigs[0].name {
+			out = append(out, m.isym.Linksym())
+			sigs = sigs[1:]
+			if len(sigs) == 0 {
+				break
+			}
 		}
-		t := n.Type
-		dtypesym(t)
-		if t.Sym != nil {
-			dtypesym(ptrto(t))
+	}
+
+	return out
+}
+
+// itabsym uses the information gathered in
+// peekitabs to de-virtualize interface methods.
+// Since this is called by the SSA backend, it shouldn't
+// generate additional Nodes, Syms, etc.
+func itabsym(it *obj.LSym, offset int64) *obj.LSym {
+	var syms []*obj.LSym
+	if it == nil {
+		return nil
+	}
+
+	for i := range itabs {
+		e := &itabs[i]
+		if e.lsym == it {
+			syms = e.entries
+			break
+		}
+	}
+	if syms == nil {
+		return nil
+	}
+
+	// keep this arithmetic in sync with *itab layout
+	methodnum := int((offset - 3*int64(Widthptr) - 8) / int64(Widthptr))
+	if methodnum >= len(syms) {
+		return nil
+	}
+	return syms[methodnum]
+}
+
+func addsignat(t *types.Type) {
+	signatset[t] = struct{}{}
+}
+
+func addsignats(dcls []*Node) {
+	// copy types from dcl list to signatset
+	for _, n := range dcls {
+		if n.Op == OTYPE {
+			addsignat(n.Type)
 		}
 	}
+}
 
+func dumpsignats() {
+	// Process signatset. Use a loop, as dtypesym adds
+	// entries to signatset while it is being processed.
+	signats := make([]typeAndStr, len(signatset))
+	for len(signatset) > 0 {
+		signats = signats[:0]
+		// Transfer entries to a slice and sort, for reproducible builds.
+		for t := range signatset {
+			signats = append(signats, typeAndStr{t: t, short: typesymname(t), regular: t.String()})
+			delete(signatset, t)
+		}
+		sort.Sort(typesByString(signats))
+		for _, ts := range signats {
+			t := ts.t
+			dtypesym(t)
+			if t.Sym != nil {
+				dtypesym(types.NewPtr(t))
+			}
+		}
+	}
+}
+
+func dumptabs() {
 	// process itabs
 	for _, i := range itabs {
 		// dump empty itab symbol into i.sym
@@ -1404,27 +1454,31 @@ func dumptypestructs() {
 		//   inter  *interfacetype
 		//   _type  *_type
 		//   link   *itab
-		//   bad    int32
-		//   unused int32
+		//   hash   uint32
+		//   bad    bool
+		//   inhash bool
+		//   unused [2]byte
 		//   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/inhash fields
+		o := dsymptr(i.lsym, 0, dtypesym(i.itype).Linksym(), 0)
+		o = dsymptr(i.lsym, o, dtypesym(i.t).Linksym(), 0)
+		o += Widthptr                          // skip link field
+		o = duint32(i.lsym, o, typehash(i.t))  // copy of type hash
+		o += 4                                 // skip bad/inhash/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))
+		ggloblsym(i.lsym, int32(o), int16(obj.DUPOK|obj.NOPTR))
 
-		ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg)
-		dsymptr(ilink, 0, i.sym, 0)
+		ilink := itablinkpkg.Lookup(i.t.ShortString() + "," + i.itype.ShortString()).Linksym()
+		dsymptr(ilink, 0, i.lsym, 0)
 		ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
 	}
 
 	// process ptabs
 	if localpkg.Name == "main" && len(ptabs) > 0 {
 		ot := 0
-		s := obj.Linklookup(Ctxt, "go.plugin.tabs", 0)
+		s := Ctxt.Lookup("go.plugin.tabs")
 		for _, p := range ptabs {
 			// Dump ptab symbol into go.pluginsym package.
 			//
@@ -1433,49 +1487,46 @@ func dumptypestructs() {
 			//	typ  typeOff // pointer to symbol
 			// }
 			nsym := dname(p.s.Name, "", nil, true)
-			ot = dsymptrOffLSym(s, ot, nsym, 0)
-			ot = dsymptrOffLSym(s, ot, Linksym(dtypesym(p.t)), 0)
+			ot = dsymptrOff(s, ot, nsym, 0)
+			ot = dsymptrOff(s, ot, dtypesym(p.t).Linksym(), 0)
 		}
-		ggloblLSym(s, int32(ot), int16(obj.RODATA))
+		ggloblsym(s, int32(ot), int16(obj.RODATA))
 
 		ot = 0
-		s = obj.Linklookup(Ctxt, "go.plugin.exports", 0)
+		s = Ctxt.Lookup("go.plugin.exports")
 		for _, p := range ptabs {
-			ot = dsymptrLSym(s, ot, Linksym(p.s), 0)
+			ot = dsymptr(s, ot, p.s.Linksym(), 0)
 		}
-		ggloblLSym(s, int32(ot), int16(obj.RODATA))
+		ggloblsym(s, int32(ot), int16(obj.RODATA))
 	}
+}
 
+func dumpimportstrings() {
 	// 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)
-		}
+	for _, p := range types.ImportedPkgList() {
+		dimportpath(p)
 	}
+}
 
+func dumpbasictypes() {
 	// do basic types if compiling package runtime.
 	// they have to be in at least one package,
 	// and runtime is always loaded implicitly,
 	// so this is as good as any.
 	// another possible choice would be package main,
-	// but using runtime means fewer copies in .6 files.
+	// but using runtime means fewer copies in object files.
 	if myimportpath == "runtime" {
-		for i := EType(1); i <= TBOOL; i++ {
-			dtypesym(ptrto(Types[i]))
+		for i := types.EType(1); i <= TBOOL; i++ {
+			dtypesym(types.NewPtr(types.Types[i]))
 		}
-		dtypesym(ptrto(Types[TSTRING]))
-		dtypesym(ptrto(Types[TUNSAFEPTR]))
+		dtypesym(types.NewPtr(types.Types[TSTRING]))
+		dtypesym(types.NewPtr(types.Types[TUNSAFEPTR]))
 
 		// emit type structs for error and func(error) string.
 		// The latter is the type of an auto-generated wrapper.
-		dtypesym(ptrto(errortype))
+		dtypesym(types.NewPtr(types.Errortype))
 
-		dtypesym(functype(nil, []*Node{nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{nod(ODCLFIELD, nil, typenod(Types[TSTRING]))}))
+		dtypesym(functype(nil, []*Node{anonfield(types.Errortype)}, []*Node{anonfield(types.Types[TSTRING])}))
 
 		// add paths for runtime and main, which 6l imports implicitly.
 		dimportpath(Runtimepkg)
@@ -1486,20 +1537,35 @@ func dumptypestructs() {
 		if flag_msan {
 			dimportpath(msanpkg)
 		}
-		dimportpath(mkpkg("main"))
+		dimportpath(types.NewPkg("main", ""))
 	}
 }
 
-type pkgByPath []*Pkg
+type typeAndStr struct {
+	t       *types.Type
+	short   string
+	regular string
+}
 
-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] }
+type typesByString []typeAndStr
 
-func dalgsym(t *Type) *Sym {
-	var s *Sym
-	var hashfunc *Sym
-	var eqfunc *Sym
+func (a typesByString) Len() int { return len(a) }
+func (a typesByString) Less(i, j int) bool {
+	if a[i].short != a[j].short {
+		return a[i].short < a[j].short
+	}
+	// When the only difference between the types is whether
+	// they refer to byte or uint8, such as **byte vs **uint8,
+	// the types' ShortStrings can be identical.
+	// To preserve deterministic sort ordering, sort these by String().
+	return a[i].regular < a[j].regular
+}
+func (a typesByString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+func dalgsym(t *types.Type) *obj.LSym {
+	var lsym *obj.LSym
+	var hashfunc *obj.LSym
+	var eqfunc *obj.LSym
 
 	// dalgsym is only called for a type that needs an algorithm table,
 	// which implies that the type is comparable (or else it would use ANOEQ).
@@ -1508,71 +1574,75 @@ func dalgsym(t *Type) *Sym {
 		// we use one algorithm table for all AMEM types of a given size
 		p := fmt.Sprintf(".alg%d", t.Width)
 
-		s = Pkglookup(p, typepkg)
+		s := typeLookup(p)
+		lsym = s.Linksym()
+		if s.AlgGen() {
+			return lsym
+		}
+		s.SetAlgGen(true)
 
-		if s.Flags&SymAlgGen != 0 {
-			return s
+		if memhashvarlen == nil {
+			memhashvarlen = Sysfunc("memhash_varlen")
+			memequalvarlen = Sysfunc("memequal_varlen")
 		}
-		s.Flags |= SymAlgGen
 
 		// make hash closure
 		p = fmt.Sprintf(".hashfunc%d", t.Width)
 
-		hashfunc = Pkglookup(p, typepkg)
+		hashfunc = typeLookup(p).Linksym()
 
 		ot := 0
-		ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0)
-		ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure
+		ot = dsymptr(hashfunc, ot, memhashvarlen, 0)
+		ot = duintptr(hashfunc, ot, uint64(t.Width)) // size encoded in closure
 		ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA)
 
 		// make equality closure
 		p = fmt.Sprintf(".eqfunc%d", t.Width)
 
-		eqfunc = Pkglookup(p, typepkg)
+		eqfunc = typeLookup(p).Linksym()
 
 		ot = 0
-		ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0)
-		ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr)
+		ot = dsymptr(eqfunc, ot, memequalvarlen, 0)
+		ot = duintptr(eqfunc, ot, uint64(t.Width))
 		ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA)
 	} else {
 		// generate an alg table specific to this type
-		s = typesymprefix(".alg", t)
+		s := typesymprefix(".alg", t)
+		lsym = s.Linksym()
 
 		hash := typesymprefix(".hash", t)
 		eq := typesymprefix(".eq", t)
-		hashfunc = typesymprefix(".hashfunc", t)
-		eqfunc = typesymprefix(".eqfunc", t)
+		hashfunc = typesymprefix(".hashfunc", t).Linksym()
+		eqfunc = typesymprefix(".eqfunc", t).Linksym()
 
 		genhash(hash, t)
 		geneq(eq, t)
 
 		// make Go funcs (closures) for calling hash and equal from Go
-		dsymptr(hashfunc, 0, hash, 0)
-
+		dsymptr(hashfunc, 0, hash.Linksym(), 0)
 		ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
-		dsymptr(eqfunc, 0, eq, 0)
+		dsymptr(eqfunc, 0, eq.Linksym(), 0)
 		ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
 	}
 
 	// ../../../../runtime/alg.go:/typeAlg
 	ot := 0
 
-	ot = dsymptr(s, ot, hashfunc, 0)
-	ot = dsymptr(s, ot, eqfunc, 0)
-	ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
-	return s
+	ot = dsymptr(lsym, ot, hashfunc, 0)
+	ot = dsymptr(lsym, ot, eqfunc, 0)
+	ggloblsym(lsym, int32(ot), obj.DUPOK|obj.RODATA)
+	return lsym
 }
 
 // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
 // which holds 1-bit entries describing where pointers are in a given type.
-// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes
-// depending on the system. Above this length, the GC information is
-// recorded as a GC program, which can express repetition compactly.
-// In either form, the information is used by the runtime to initialize the
-// heap bitmap, and for large types (like 128 or more words), they are
-// roughly the same speed. GC programs are never much larger and often
-// more compact. (If large arrays are involved, they can be arbitrarily more
-// compact.)
+// Above this length, the GC information is recorded as a GC program,
+// which can express repetition compactly. In either form, the
+// information is used by the runtime to initialize the heap bitmap,
+// and for large types (like 128 or more words), they are roughly the
+// same speed. GC programs are never much larger and often more
+// compact. (If large arrays are involved, they can be arbitrarily
+// more compact.)
 //
 // The cutoff must be large enough that any allocation large enough to
 // use a GC program is large enough that it does not share heap bitmap
@@ -1601,43 +1671,44 @@ const maxPtrmaskBytes = 2048
 // dgcsym emits and returns a data symbol containing GC information for type t,
 // along with a boolean reporting whether the UseGCProg bit should be set in
 // the type kind, and the ptrdata field to record in the reflect type information.
-func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) {
+func dgcsym(t *types.Type) (lsym *obj.LSym, useGCProg bool, ptrdata int64) {
 	ptrdata = typeptrdata(t)
 	if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
-		sym = dgcptrmask(t)
+		lsym = dgcptrmask(t)
 		return
 	}
 
 	useGCProg = true
-	sym, ptrdata = dgcprog(t)
+	lsym, ptrdata = dgcprog(t)
 	return
 }
 
 // dgcptrmask emits and returns the symbol containing a pointer mask for type t.
-func dgcptrmask(t *Type) *Sym {
+func dgcptrmask(t *types.Type) *obj.LSym {
 	ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
 	fillptrmask(t, ptrmask)
 	p := fmt.Sprintf("gcbits.%x", ptrmask)
 
-	sym := Pkglookup(p, Runtimepkg)
-	if sym.Flags&SymUniq == 0 {
-		sym.Flags |= SymUniq
+	sym := Runtimepkg.Lookup(p)
+	lsym := sym.Linksym()
+	if !sym.Uniq() {
+		sym.SetUniq(true)
 		for i, x := range ptrmask {
-			duint8(sym, i, x)
+			duint8(lsym, i, x)
 		}
-		ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
+		ggloblsym(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
 	}
-	return sym
+	return lsym
 }
 
 // fillptrmask fills in ptrmask with 1s corresponding to the
 // word offsets in t that hold pointers.
 // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
-func fillptrmask(t *Type, ptrmask []byte) {
+func fillptrmask(t *types.Type, ptrmask []byte) {
 	for i := range ptrmask {
 		ptrmask[i] = 0
 	}
-	if !haspointers(t) {
+	if !types.Haspointers(t) {
 		return
 	}
 
@@ -1657,57 +1728,57 @@ func fillptrmask(t *Type, ptrmask []byte) {
 // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
 // In practice, the size is typeptrdata(t) except for non-trivial arrays.
 // For non-trivial arrays, the program describes the full t.Width size.
-func dgcprog(t *Type) (*Sym, int64) {
+func dgcprog(t *types.Type) (*obj.LSym, int64) {
 	dowidth(t)
 	if t.Width == BADWIDTH {
 		Fatalf("dgcprog: %v badwidth", t)
 	}
-	sym := typesymprefix(".gcprog", t)
+	lsym := typesymprefix(".gcprog", t).Linksym()
 	var p GCProg
-	p.init(sym)
+	p.init(lsym)
 	p.emit(t, 0)
 	offset := p.w.BitIndex() * int64(Widthptr)
 	p.end()
 	if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
 		Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
 	}
-	return sym, offset
+	return lsym, offset
 }
 
 type GCProg struct {
-	sym    *Sym
+	lsym   *obj.LSym
 	symoff int
 	w      gcprog.Writer
 }
 
 var Debug_gcprog int // set by -d gcprog
 
-func (p *GCProg) init(sym *Sym) {
-	p.sym = sym
+func (p *GCProg) init(lsym *obj.LSym) {
+	p.lsym = lsym
 	p.symoff = 4 // first 4 bytes hold program length
 	p.w.Init(p.writeByte)
 	if Debug_gcprog > 0 {
-		fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym)
+		fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", lsym)
 		p.w.Debug(os.Stderr)
 	}
 }
 
 func (p *GCProg) writeByte(x byte) {
-	p.symoff = duint8(p.sym, p.symoff, x)
+	p.symoff = duint8(p.lsym, p.symoff, x)
 }
 
 func (p *GCProg) end() {
 	p.w.End()
-	duint32(p.sym, 0, uint32(p.symoff-4))
-	ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
+	duint32(p.lsym, 0, uint32(p.symoff-4))
+	ggloblsym(p.lsym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
 	if Debug_gcprog > 0 {
-		fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym)
+		fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.lsym)
 	}
 }
 
-func (p *GCProg) emit(t *Type, offset int64) {
+func (p *GCProg) emit(t *types.Type, offset int64) {
 	dowidth(t)
-	if !haspointers(t) {
+	if !types.Haspointers(t) {
 		return
 	}
 	if t.Width == int64(Widthptr) {
@@ -1769,17 +1840,17 @@ func zeroaddr(size int64) *Node {
 	if zerosize < size {
 		zerosize = size
 	}
-	s := Pkglookup("zero", mappkg)
+	s := mappkg.Lookup("zero")
 	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
+		x.Type = types.Types[TUINT8]
+		x.SetClass(PEXTERN)
+		x.SetTypecheck(1)
+		s.Def = asTypesNode(x)
+	}
+	z := nod(OADDR, asNode(s.Def), nil)
+	z.Type = types.NewPtr(types.Types[TUINT8])
+	z.SetAddable(true)
+	z.SetTypecheck(1)
 	return z
 }
diff --git a/src/cmd/compile/internal/gc/reflect_test.go b/src/cmd/compile/internal/gc/reflect_test.go
index 9e39933..fe6dcf0 100644
--- a/src/cmd/compile/internal/gc/reflect_test.go
+++ b/src/cmd/compile/internal/gc/reflect_test.go
@@ -5,31 +5,32 @@
 package gc
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
 	"reflect"
-	"sort"
 	"testing"
 )
 
-func TestSortingByMethodNameAndPackagePath(t *testing.T) {
+func TestSortingBySigLT(t *testing.T) {
 	data := []*Sig{
-		&Sig{name: "b", pkg: &Pkg{Path: "abc"}},
+		&Sig{name: "b", pkg: &types.Pkg{Path: "abc"}},
 		&Sig{name: "b", pkg: nil},
 		&Sig{name: "c", pkg: nil},
-		&Sig{name: "c", pkg: &Pkg{Path: "uvw"}},
+		&Sig{name: "c", pkg: &types.Pkg{Path: "uvw"}},
 		&Sig{name: "c", pkg: nil},
-		&Sig{name: "b", pkg: &Pkg{Path: "xyz"}},
-		&Sig{name: "a", pkg: &Pkg{Path: "abc"}},
+		&Sig{name: "b", pkg: &types.Pkg{Path: "xyz"}},
+		&Sig{name: "a", pkg: &types.Pkg{Path: "abc"}},
 		&Sig{name: "b", pkg: nil},
 	}
 	want := []*Sig{
-		&Sig{name: "a", pkg: &Pkg{Path: "abc"}},
+		&Sig{name: "a", pkg: &types.Pkg{Path: "abc"}},
 		&Sig{name: "b", pkg: nil},
 		&Sig{name: "b", pkg: nil},
-		&Sig{name: "b", pkg: &Pkg{Path: "abc"}},
-		&Sig{name: "b", pkg: &Pkg{Path: "xyz"}},
+		&Sig{name: "b", pkg: &types.Pkg{Path: "abc"}},
+		&Sig{name: "b", pkg: &types.Pkg{Path: "xyz"}},
 		&Sig{name: "c", pkg: nil},
 		&Sig{name: "c", pkg: nil},
-		&Sig{name: "c", pkg: &Pkg{Path: "uvw"}},
+		&Sig{name: "c", pkg: &types.Pkg{Path: "uvw"}},
 	}
 	if len(data) != len(want) {
 		t.Fatal("want and data must match")
@@ -37,11 +38,10 @@ func TestSortingByMethodNameAndPackagePath(t *testing.T) {
 	if reflect.DeepEqual(data, want) {
 		t.Fatal("data must be shuffled")
 	}
-	sort.Sort(byMethodNameAndPackagePath(data))
+	obj.SortSlice(data, func(i, j int) bool { return siglt(data[i], data[j]) })
 	if !reflect.DeepEqual(data, want) {
 		t.Logf("want: %#v", want)
 		t.Logf("data: %#v", data)
 		t.Errorf("sorting failed")
 	}
-
 }
diff --git a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
new file mode 100644
index 0000000..b5f318e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
@@ -0,0 +1,48 @@
+// Copyright 2017 The Go Authors. 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"
+	"os/exec"
+	"path/filepath"
+	"testing"
+)
+
+func TestReproducibleBuilds(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	iters := 10
+	if testing.Short() {
+		iters = 4
+	}
+	t.Parallel()
+	var want []byte
+	tmp, err := ioutil.TempFile("", "")
+	if err != nil {
+		t.Fatalf("temp file creation failed: %v", err)
+	}
+	defer os.Remove(tmp.Name())
+	defer tmp.Close()
+	for i := 0; i < iters; i++ {
+		out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", "issue20272.go")).CombinedOutput()
+		if err != nil {
+			t.Fatalf("failed to compile: %v\n%s", err, out)
+		}
+		obj, err := ioutil.ReadFile(tmp.Name())
+		if err != nil {
+			t.Fatalf("failed to read object file: %v", err)
+		}
+		if i == 0 {
+			want = obj
+		} else {
+			if !bytes.Equal(want, obj) {
+				t.Fatalf("builds produced different output after %d iters (%d bytes vs %d bytes)", i, len(want), len(obj))
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/scope.go b/src/cmd/compile/internal/gc/scope.go
new file mode 100644
index 0000000..b0bc7f6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/scope.go
@@ -0,0 +1,177 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+	"cmd/internal/dwarf"
+	"cmd/internal/obj"
+	"cmd/internal/src"
+	"sort"
+)
+
+// See golang.org/issue/20390.
+func xposBefore(p, q src.XPos) bool {
+	return Ctxt.PosTable.Pos(p).Before(Ctxt.PosTable.Pos(q))
+}
+
+func findScope(marks []Mark, pos src.XPos) ScopeID {
+	i := sort.Search(len(marks), func(i int) bool {
+		return xposBefore(pos, marks[i].Pos)
+	})
+	if i == 0 {
+		return 0
+	}
+	return marks[i-1].Scope
+}
+
+func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes []ScopeID) []dwarf.Scope {
+	// Initialize the DWARF scope tree based on lexical scopes.
+	dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents))
+	for i, parent := range fn.Func.Parents {
+		dwarfScopes[i+1].Parent = int32(parent)
+	}
+
+	scopeVariables(dwarfVars, varScopes, dwarfScopes)
+	scopePCs(fnsym, fn.Func.Marks, dwarfScopes)
+	return compactScopes(dwarfScopes)
+}
+
+// scopeVariables assigns DWARF variable records to their scopes.
+func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []dwarf.Scope) {
+	sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes})
+
+	i0 := 0
+	for i := range dwarfVars {
+		if varScopes[i] == varScopes[i0] {
+			continue
+		}
+		dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:i]
+		i0 = i
+	}
+	if i0 < len(dwarfVars) {
+		dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:]
+	}
+}
+
+// A scopedPCs represents a non-empty half-open interval of PCs that
+// share a common source position.
+type scopedPCs struct {
+	start, end int64
+	pos        src.XPos
+	scope      ScopeID
+}
+
+// scopePCs assigns PC ranges to their scopes.
+func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
+	// If there aren't any child scopes (in particular, when scope
+	// tracking is disabled), we can skip a whole lot of work.
+	if len(marks) == 0 {
+		return
+	}
+
+	// Break function text into scopedPCs.
+	var pcs []scopedPCs
+	p0 := fnsym.Func.Text
+	for p := fnsym.Func.Text; p != nil; p = p.Link {
+		if p.Pos == p0.Pos {
+			continue
+		}
+		if p0.Pc < p.Pc {
+			pcs = append(pcs, scopedPCs{start: p0.Pc, end: p.Pc, pos: p0.Pos})
+		}
+		p0 = p
+	}
+	if p0.Pc < fnsym.Size {
+		pcs = append(pcs, scopedPCs{start: p0.Pc, end: fnsym.Size, pos: p0.Pos})
+	}
+
+	// Sort PCs by source position, and walk in parallel with
+	// scope marks to assign a lexical scope to each PC interval.
+	sort.Sort(pcsByPos(pcs))
+	var marki int
+	var scope ScopeID
+	for i := range pcs {
+		for marki < len(marks) && !xposBefore(pcs[i].pos, marks[marki].Pos) {
+			scope = marks[marki].Scope
+			marki++
+		}
+		pcs[i].scope = scope
+	}
+
+	// Re-sort to create sorted PC ranges for each DWARF scope.
+	sort.Sort(pcsByPC(pcs))
+	for _, pc := range pcs {
+		r := &dwarfScopes[pc.scope].Ranges
+		if i := len(*r); i > 0 && (*r)[i-1].End == pc.start {
+			(*r)[i-1].End = pc.end
+		} else {
+			*r = append(*r, dwarf.Range{Start: pc.start, End: pc.end})
+		}
+	}
+}
+
+func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope {
+	// Forward pass to collapse empty scopes into parents.
+	remap := make([]int32, len(dwarfScopes))
+	j := int32(1)
+	for i := 1; i < len(dwarfScopes); i++ {
+		s := &dwarfScopes[i]
+		s.Parent = remap[s.Parent]
+		if len(s.Vars) == 0 {
+			dwarfScopes[s.Parent].UnifyRanges(s)
+			remap[i] = s.Parent
+			continue
+		}
+		remap[i] = j
+		dwarfScopes[j] = *s
+		j++
+	}
+	dwarfScopes = dwarfScopes[:j]
+
+	// Reverse pass to propagate PC ranges to parent scopes.
+	for i := len(dwarfScopes) - 1; i > 0; i-- {
+		s := &dwarfScopes[i]
+		dwarfScopes[s.Parent].UnifyRanges(s)
+	}
+
+	return dwarfScopes
+}
+
+type pcsByPC []scopedPCs
+
+func (s pcsByPC) Len() int      { return len(s) }
+func (s pcsByPC) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s pcsByPC) Less(i, j int) bool {
+	return s[i].start < s[j].start
+}
+
+type pcsByPos []scopedPCs
+
+func (s pcsByPos) Len() int      { return len(s) }
+func (s pcsByPos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s pcsByPos) Less(i, j int) bool {
+	return xposBefore(s[i].pos, s[j].pos)
+}
+
+type varsByScopeAndOffset struct {
+	vars   []*dwarf.Var
+	scopes []ScopeID
+}
+
+func (v varsByScopeAndOffset) Len() int {
+	return len(v.vars)
+}
+
+func (v varsByScopeAndOffset) Less(i, j int) bool {
+	if v.scopes[i] != v.scopes[j] {
+		return v.scopes[i] < v.scopes[j]
+	}
+	return v.vars[i].Offset < v.vars[j].Offset
+}
+
+func (v varsByScopeAndOffset) Swap(i, j int) {
+	v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
+	v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i]
+}
diff --git a/src/cmd/compile/internal/gc/scope_test.go b/src/cmd/compile/internal/gc/scope_test.go
new file mode 100644
index 0000000..f08e900
--- /dev/null
+++ b/src/cmd/compile/internal/gc/scope_test.go
@@ -0,0 +1,413 @@
+// Copyright 2016 The Go Authors. 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 (
+	"cmd/internal/objfile"
+	"debug/dwarf"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type testline struct {
+	// line is one line of go source
+	line string
+
+	// scopes is a list of scope IDs of all the lexical scopes that this line
+	// of code belongs to.
+	// Scope IDs are assigned by traversing the tree of lexical blocks of a
+	// function in pre-order
+	// Scope IDs are function specific, i.e. scope 0 is always the root scope
+	// of the function that this line belongs to. Empty scopes are not assigned
+	// an ID (because they are not saved in debug_info).
+	// Scope 0 is always omitted from this list since all lines always belong
+	// to it.
+	scopes []int
+
+	// vars is the list of variables that belong in scopes[len(scopes)-1].
+	// Local variables are prefixed with "var ", formal parameters with "arg ".
+	// Must be ordered alphabetically.
+	// Set to nil to skip the check.
+	vars []string
+}
+
+var testfile = []testline{
+	{line: "package main"},
+	{line: "func f1(x int) { }"},
+	{line: "func f2(x int) { }"},
+	{line: "func f3(x int) { }"},
+	{line: "func f4(x int) { }"},
+	{line: "func f5(x int) { }"},
+	{line: "func f6(x int) { }"},
+	{line: "func gret1() int { return 2 }"},
+	{line: "func gretbool() bool { return true }"},
+	{line: "func gret3() (int, int, int) { return 0, 1, 2 }"},
+	{line: "var v = []int{ 0, 1, 2 }"},
+	{line: "var ch = make(chan int)"},
+	{line: "var floatch = make(chan float64)"},
+	{line: "var iface interface{}"},
+	{line: "func TestNestedFor() {", vars: []string{"var a int"}},
+	{line: "	a := 0"},
+	{line: "	f1(a)"},
+	{line: "	for i := 0; i < 5; i++ {", scopes: []int{1}, vars: []string{"var i int"}},
+	{line: "		f2(i)", scopes: []int{1}},
+	{line: "		for i := 0; i < 5; i++ {", scopes: []int{1, 2}, vars: []string{"var i int"}},
+	{line: "			f3(i)", scopes: []int{1, 2}},
+	{line: "		}"},
+	{line: "		f4(i)", scopes: []int{1}},
+	{line: "	}"},
+	{line: "	f5(a)"},
+	{line: "}"},
+	{line: "func TestOas2() {", vars: []string{}},
+	{line: "	if a, b, c := gret3(); a != 1 {", scopes: []int{1}, vars: []string{"var a int", "var b int", "var c int"}},
+	{line: "		f1(a)", scopes: []int{1}},
+	{line: "		f1(b)", scopes: []int{1}},
+	{line: "		f1(c)", scopes: []int{1}},
+	{line: "	}"},
+	{line: "	for i, x := range v {", scopes: []int{2}, vars: []string{"var i int", "var x int"}},
+	{line: "		f1(i)", scopes: []int{2}},
+	{line: "		f1(x)", scopes: []int{2}},
+	{line: "	}"},
+	{line: "	if a, ok := <- ch; ok {", scopes: []int{3}, vars: []string{"var a int", "var ok bool"}},
+	{line: "		f1(a)", scopes: []int{3}},
+	{line: "	}"},
+	{line: "	if a, ok := iface.(int); ok {", scopes: []int{4}, vars: []string{"var a int", "var ok bool"}},
+	{line: "		f1(a)", scopes: []int{4}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestIfElse() {"},
+	{line: "	if x := gret1(); x != 0 {", scopes: []int{1}, vars: []string{"var x int"}},
+	{line: "		a := 0", scopes: []int{1, 2}, vars: []string{"var a int"}},
+	{line: "		f1(a); f1(x)", scopes: []int{1, 2}},
+	{line: "	} else {"},
+	{line: "		b := 1", scopes: []int{1, 3}, vars: []string{"var b int"}},
+	{line: "		f1(b); f1(x+1)", scopes: []int{1, 3}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestSwitch() {", vars: []string{}},
+	{line: "	switch x := gret1(); x {", scopes: []int{1}, vars: []string{"var x int"}},
+	{line: "	case 0:", scopes: []int{1, 2}},
+	{line: "		i := x + 5", scopes: []int{1, 2}, vars: []string{"var i int"}},
+	{line: "		f1(x); f1(i)", scopes: []int{1, 2}},
+	{line: "	case 1:", scopes: []int{1, 3}},
+	{line: "		j := x + 10", scopes: []int{1, 3}, vars: []string{"var j int"}},
+	{line: "		f1(x); f1(j)", scopes: []int{1, 3}},
+	{line: "	case 2:", scopes: []int{1, 4}},
+	{line: "		k := x + 2", scopes: []int{1, 4}, vars: []string{"var k int"}},
+	{line: "		f1(x); f1(k)", scopes: []int{1, 4}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestTypeSwitch() {", vars: []string{}},
+	{line: "	switch x := iface.(type) {"},
+	{line: "	case int:", scopes: []int{1}},
+	{line: "		f1(x)", scopes: []int{1}, vars: []string{"var x int"}},
+	{line: "	case uint8:", scopes: []int{2}},
+	{line: "		f1(int(x))", scopes: []int{2}, vars: []string{"var x uint8"}},
+	{line: "	case float64:", scopes: []int{3}},
+	{line: "		f1(int(x)+1)", scopes: []int{3}, vars: []string{"var x float64"}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestSelectScope() {"},
+	{line: "	select {"},
+	{line: "	case i := <- ch:", scopes: []int{1}},
+	{line: "		f1(i)", scopes: []int{1}, vars: []string{"var i int"}},
+	{line: "	case f := <- floatch:", scopes: []int{2}},
+	{line: "		f1(int(f))", scopes: []int{2}, vars: []string{"var f float64"}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestBlock() {", vars: []string{"var a int"}},
+	{line: "	a := 1"},
+	{line: "	{"},
+	{line: "		b := 2", scopes: []int{1}, vars: []string{"var b int"}},
+	{line: "		f1(b)", scopes: []int{1}},
+	{line: "		f1(a)", scopes: []int{1}},
+	{line: "	}"},
+	{line: "}"},
+	{line: "func TestDiscontiguousRanges() {", vars: []string{"var a int"}},
+	{line: "	a := 0"},
+	{line: "	f1(a)"},
+	{line: "	{"},
+	{line: "		b := 0", scopes: []int{1}, vars: []string{"var b int"}},
+	{line: "		f2(b)", scopes: []int{1}},
+	{line: "		if gretbool() {", scopes: []int{1}},
+	{line: "			c := 0", scopes: []int{1, 2}, vars: []string{"var c int"}},
+	{line: "			f3(c)", scopes: []int{1, 2}},
+	{line: "		} else {"},
+	{line: "			c := 1.1", scopes: []int{1, 3}, vars: []string{"var c float64"}},
+	{line: "			f4(int(c))", scopes: []int{1, 3}},
+	{line: "		}"},
+	{line: "		f5(b)", scopes: []int{1}},
+	{line: "	}"},
+	{line: "	f6(a)"},
+	{line: "}"},
+	{line: "func TestClosureScope() {", vars: []string{"var a int", "var b int", "var f func(int)"}},
+	{line: "	a := 1; b := 1"},
+	{line: "	f := func(c int) {", scopes: []int{0}, vars: []string{"arg c int", "var &b *int", "var a int", "var d int"}},
+	{line: "		d := 3"},
+	{line: "		f1(c); f1(d)"},
+	{line: "		if e := 3; e != 0 {", scopes: []int{1}, vars: []string{"var e int"}},
+	{line: "			f1(e)", scopes: []int{1}},
+	{line: "			f1(a)", scopes: []int{1}},
+	{line: "			b = 2", scopes: []int{1}},
+	{line: "		}"},
+	{line: "	}"},
+	{line: "	f(3); f1(b)"},
+	{line: "}"},
+	{line: "func main() {"},
+	{line: "	TestNestedFor()"},
+	{line: "	TestOas2()"},
+	{line: "	TestIfElse()"},
+	{line: "	TestSwitch()"},
+	{line: "	TestTypeSwitch()"},
+	{line: "	TestSelectScope()"},
+	{line: "	TestBlock()"},
+	{line: "	TestDiscontiguousRanges()"},
+	{line: "	TestClosureScope()"},
+	{line: "}"},
+}
+
+const detailOutput = false
+
+// Compiles testfile checks that the description of lexical blocks emitted
+// by the linker in debug_info, for each function in the main package,
+// corresponds to what we expect it to be.
+func TestScopeRanges(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9; no DWARF symbol table in executables")
+	}
+
+	dir, err := ioutil.TempDir("", "TestScopeRanges")
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	src, f := gobuild(t, dir, testfile)
+	defer f.Close()
+
+	// the compiler uses forward slashes for paths even on windows
+	src = strings.Replace(src, "\\", "/", -1)
+
+	pcln, err := f.PCLineTable()
+	if err != nil {
+		t.Fatal(err)
+	}
+	dwarfData, err := f.DWARF()
+	if err != nil {
+		t.Fatal(err)
+	}
+	dwarfReader := dwarfData.Reader()
+
+	lines := make(map[line][]*lexblock)
+
+	for {
+		entry, err := dwarfReader.Next()
+		if err != nil {
+			t.Fatal(err)
+		}
+		if entry == nil {
+			break
+		}
+
+		if entry.Tag != dwarf.TagSubprogram {
+			continue
+		}
+
+		name, ok := entry.Val(dwarf.AttrName).(string)
+		if !ok || !strings.HasPrefix(name, "main.Test") {
+			continue
+		}
+
+		var scope lexblock
+		ctxt := scopexplainContext{
+			dwarfData:   dwarfData,
+			dwarfReader: dwarfReader,
+			scopegen:    1,
+		}
+
+		readScope(&ctxt, &scope, entry)
+
+		scope.markLines(pcln, lines)
+	}
+
+	anyerror := false
+	for i := range testfile {
+		tgt := testfile[i].scopes
+		out := lines[line{src, i + 1}]
+
+		if detailOutput {
+			t.Logf("%s // %v", testfile[i].line, out)
+		}
+
+		scopesok := checkScopes(tgt, out)
+		if !scopesok {
+			t.Logf("mismatch at line %d %q: expected: %v got: %v\n", i, testfile[i].line, tgt, scopesToString(out))
+		}
+
+		varsok := true
+		if testfile[i].vars != nil {
+			if len(out) > 0 {
+				varsok = checkVars(testfile[i].vars, out[len(out)-1].vars)
+				if !varsok {
+					t.Logf("variable mismatch at line %d %q for scope %d: expected: %v got: %v\n", i, testfile[i].line, out[len(out)-1].id, testfile[i].vars, out[len(out)-1].vars)
+				}
+			}
+		}
+
+		anyerror = anyerror || !scopesok || !varsok
+	}
+
+	if anyerror {
+		t.Fatalf("mismatched output")
+	}
+}
+
+func scopesToString(v []*lexblock) string {
+	r := make([]string, len(v))
+	for i, s := range v {
+		r[i] = strconv.Itoa(s.id)
+	}
+	return "[ " + strings.Join(r, ", ") + " ]"
+}
+
+func checkScopes(tgt []int, out []*lexblock) bool {
+	if len(out) > 0 {
+		// omit scope 0
+		out = out[1:]
+	}
+	if len(tgt) != len(out) {
+		return false
+	}
+	for i := range tgt {
+		if tgt[i] != out[i].id {
+			return false
+		}
+	}
+	return true
+}
+
+func checkVars(tgt, out []string) bool {
+	if len(tgt) != len(out) {
+		return false
+	}
+	for i := range tgt {
+		if tgt[i] != out[i] {
+			return false
+		}
+	}
+	return true
+}
+
+type lexblock struct {
+	id     int
+	ranges [][2]uint64
+	vars   []string
+	scopes []lexblock
+}
+
+type line struct {
+	file   string
+	lineno int
+}
+
+type scopexplainContext struct {
+	dwarfData   *dwarf.Data
+	dwarfReader *dwarf.Reader
+	scopegen    int
+	lines       map[line][]int
+}
+
+// readScope reads the DW_TAG_lexical_block or the DW_TAG_subprogram in
+// entry and writes a description in scope.
+// Nested DW_TAG_lexical_block entries are read recursively.
+func readScope(ctxt *scopexplainContext, scope *lexblock, entry *dwarf.Entry) {
+	var err error
+	scope.ranges, err = ctxt.dwarfData.Ranges(entry)
+	if err != nil {
+		panic(err)
+	}
+	for {
+		e, err := ctxt.dwarfReader.Next()
+		if err != nil {
+			panic(err)
+		}
+		switch e.Tag {
+		case 0:
+			sort.Strings(scope.vars)
+			return
+		case dwarf.TagFormalParameter:
+			typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
+			if err != nil {
+				panic(err)
+			}
+			scope.vars = append(scope.vars, "arg "+e.Val(dwarf.AttrName).(string)+" "+typ.String())
+		case dwarf.TagVariable:
+			typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
+			if err != nil {
+				panic(err)
+			}
+			scope.vars = append(scope.vars, "var "+e.Val(dwarf.AttrName).(string)+" "+typ.String())
+		case dwarf.TagLexDwarfBlock:
+			scope.scopes = append(scope.scopes, lexblock{id: ctxt.scopegen})
+			ctxt.scopegen++
+			readScope(ctxt, &scope.scopes[len(scope.scopes)-1], e)
+		}
+	}
+}
+
+// markLines marks all lines that belong to this scope with this scope
+// Recursively calls markLines for all children scopes.
+func (scope *lexblock) markLines(pcln objfile.Liner, lines map[line][]*lexblock) {
+	for _, r := range scope.ranges {
+		for pc := r[0]; pc < r[1]; pc++ {
+			file, lineno, _ := pcln.PCToLine(pc)
+			l := line{file, lineno}
+			if len(lines[l]) == 0 || lines[l][len(lines[l])-1] != scope {
+				lines[l] = append(lines[l], scope)
+			}
+		}
+	}
+
+	for i := range scope.scopes {
+		scope.scopes[i].markLines(pcln, lines)
+	}
+}
+
+func gobuild(t *testing.T, dir string, testfile []testline) (string, *objfile.File) {
+	src := filepath.Join(dir, "test.go")
+	dst := filepath.Join(dir, "out.o")
+
+	f, err := os.Create(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for i := range testfile {
+		f.Write([]byte(testfile[i].line))
+		f.Write([]byte{'\n'})
+	}
+	f.Close()
+
+	cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", dst, src)
+	if b, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("build: %s\n", string(b))
+		t.Fatal(err)
+	}
+
+	pkg, err := objfile.Open(dst)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return src, pkg
+}
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index d999190..320cd9a 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -4,6 +4,8 @@
 
 package gc
 
+import "cmd/compile/internal/types"
+
 // select
 func typecheckselect(sel *Node) {
 	var ncase *Node
@@ -31,8 +33,8 @@ func typecheckselect(sel *Node) {
 		} else if ncase.List.Len() > 1 {
 			yyerror("select cases cannot be lists")
 		} else {
-			ncase.List.SetIndex(0, typecheck(ncase.List.Index(0), Etop))
-			n = ncase.List.Index(0)
+			ncase.List.SetFirst(typecheck(ncase.List.First(), Etop))
+			n = ncase.List.First()
 			ncase.Left = n
 			ncase.List.Set(nil)
 			setlineno(n)
@@ -44,7 +46,7 @@ func typecheckselect(sel *Node) {
 			// remove implicit conversions; the eventual assignment
 			// will reintroduce them.
 			case OAS:
-				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit {
+				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit() {
 					n.Right = n.Right.Left
 				}
 
@@ -72,7 +74,7 @@ func typecheckselect(sel *Node) {
 			case ORECV:
 				n = nod(OSELRECV, nil, n)
 
-				n.Typecheck = 1
+				n.SetTypecheck(1)
 				ncase.Left = n
 
 			case OSEND:
@@ -101,6 +103,7 @@ func walkselect(sel *Node) {
 	var n *Node
 	var var_ *Node
 	var selv *Node
+	var chosen *Node
 	if i == 0 {
 		sel.Nbody.Set1(mkcall("block", nil, nil))
 		goto out
@@ -147,7 +150,7 @@ func walkselect(sel *Node) {
 				n.Rlist.Set1(n.Right)
 				n.Right = nil
 				n.Left = nil
-				n.Typecheck = 0
+				n.SetTypecheck(0)
 				n = typecheck(n, Etop)
 			}
 
@@ -165,6 +168,7 @@ func walkselect(sel *Node) {
 		}
 
 		l = append(l, cas.Nbody.Slice()...)
+		l = append(l, nod(OBREAK, nil, nil))
 		sel.Nbody.Set(l)
 		goto out
 	}
@@ -187,8 +191,8 @@ func walkselect(sel *Node) {
 				n.Op = OSELRECV
 			}
 			if n.Op == OSELRECV2 {
-				n.List.SetIndex(0, nod(OADDR, n.List.First(), nil))
-				n.List.SetIndex(0, typecheck(n.List.Index(0), Erv))
+				n.List.SetFirst(nod(OADDR, n.List.First(), nil))
+				n.List.SetFirst(typecheck(n.List.First(), Erv))
 			}
 
 			if n.Left == nil {
@@ -220,33 +224,30 @@ func walkselect(sel *Node) {
 		default:
 			Fatalf("select %v", n.Op)
 
-			// if selectnbsend(c, v) { body } else { default body }
 		case OSEND:
+			// if selectnbsend(c, v) { body } else { default body }
 			ch := n.Left
+			r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), types.Types[TBOOL], &r.Ninit, ch, n.Right)
 
-			r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), ch, n.Right)
-
-			// if c != nil && selectnbrecv(&v, c) { body } else { default body }
 		case OSELRECV:
+			// if c != nil && selectnbrecv(&v, c) { body } else { default body }
 			r = nod(OIF, nil, nil)
-
 			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)
+			r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, n.Left, ch)
 
-			// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
 		case OSELRECV2:
+			// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
 			r = nod(OIF, nil, nil)
-
 			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.First(), ch)
+			r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, n.Left, n.List.First(), ch)
 		}
 
 		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)
+		sel.Nbody.Set2(r, nod(OBREAK, nil, nil))
 		goto out
 	}
 
@@ -255,61 +256,70 @@ func walkselect(sel *Node) {
 
 	// generate sel-struct
 	setlineno(sel)
-
-	selv = temp(selecttype(int32(sel.Xoffset)))
+	selv = temp(selecttype(sel.Xoffset))
 	r = nod(OAS, selv, nil)
 	r = typecheck(r, Etop)
 	init = append(init, r)
-	var_ = conv(conv(nod(OADDR, selv, nil), Types[TUNSAFEPTR]), ptrto(Types[TUINT8]))
+	var_ = conv(conv(nod(OADDR, selv, nil), types.Types[TUNSAFEPTR]), types.NewPtr(types.Types[TUINT8]))
 	r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(sel.Xoffset))
 	r = typecheck(r, Etop)
 	init = append(init, r)
+
 	// register cases
 	for _, cas := range sel.List.Slice() {
 		setlineno(cas)
-		n = cas.Left
-		r = nod(OIF, nil, nil)
-		r.Ninit.Set(cas.Ninit.Slice())
+
+		init = append(init, cas.Ninit.Slice()...)
 		cas.Ninit.Set(nil)
-		if n != nil {
-			r.Ninit.AppendNodes(&n.Ninit)
-			n.Ninit.Set(nil)
-		}
 
-		if n == nil {
-			// selectdefault(sel *byte);
-			r.Left = mkcall("selectdefault", Types[TBOOL], &r.Ninit, var_)
-		} else {
+		var x *Node
+		if n := cas.Left; n != nil {
+			init = append(init, n.Ninit.Slice()...)
+
 			switch n.Op {
 			default:
 				Fatalf("select %v", n.Op)
-
-				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
 			case OSEND:
-				r.Left = mkcall1(chanfn("selectsend", 2, n.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Left, n.Right)
-
-				// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+				// selectsend(sel *byte, hchan *chan any, elem *any)
+				x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, var_, n.Left, n.Right)
 			case OSELRECV:
-				r.Left = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left)
-
-				// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
+				// selectrecv(sel *byte, hchan *chan any, elem *any, received *bool)
+				x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, nodnil())
 			case OSELRECV2:
-				r.Left = mkcall1(chanfn("selectrecv2", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left, n.List.First())
+				// selectrecv(sel *byte, hchan *chan any, elem *any, received *bool)
+				x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, n.List.First())
 			}
+		} else {
+			// selectdefault(sel *byte)
+			x = mkcall("selectdefault", nil, nil, var_)
 		}
 
-		// selv is no longer alive after use.
-		r.Nbody.Append(nod(OVARKILL, selv, nil))
+		init = append(init, x)
+	}
+
+	// run the select
+	setlineno(sel)
+	chosen = temp(types.Types[TINT])
+	r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, var_))
+	r = typecheck(r, Etop)
+	init = append(init, r)
+
+	// selv is no longer alive after selectgo.
+	init = append(init, nod(OVARKILL, selv, nil))
+
+	// dispatch cases
+	for i, cas := range sel.List.Slice() {
+		setlineno(cas)
 
+		cond := nod(OEQ, chosen, nodintconst(int64(i)))
+		cond = typecheck(cond, Erv)
+
+		r = nod(OIF, cond, nil)
 		r.Nbody.AppendNodes(&cas.Nbody)
 		r.Nbody.Append(nod(OBREAK, nil, nil))
 		init = append(init, r)
 	}
 
-	// run the select
-	setlineno(sel)
-
-	init = append(init, mkcall("selectgo", nil, nil, var_))
 	sel.Nbody.Set(init)
 
 out:
@@ -319,36 +329,32 @@ out:
 }
 
 // Keep in sync with src/runtime/select.go.
-func selecttype(size int32) *Type {
+func selecttype(size int64) *types.Type {
 	// TODO(dvyukov): it's possible to generate Scase only once
 	// and then cache; and also cache Select per size.
 
-	scase := nod(OTSTRUCT, nil, nil)
-	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.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.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.Append(nod(ODCLFIELD, newname(lookup("pollorderarr")), arr))
-	sel = typecheck(sel, Etype)
-	sel.Type.Noalg = true
-	sel.Type.Local = true
-
-	return sel.Type
+	scase := tostruct([]*Node{
+		namedfield("elem", types.NewPtr(types.Types[TUINT8])),
+		namedfield("chan", types.NewPtr(types.Types[TUINT8])),
+		namedfield("pc", types.Types[TUINTPTR]),
+		namedfield("kind", types.Types[TUINT16]),
+		namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
+		namedfield("releasetime", types.Types[TUINT64]),
+	})
+	scase.SetNoalg(true)
+	scase.SetLocal(true)
+
+	sel := tostruct([]*Node{
+		namedfield("tcase", types.Types[TUINT16]),
+		namedfield("ncase", types.Types[TUINT16]),
+		namedfield("pollorder", types.NewPtr(types.Types[TUINT8])),
+		namedfield("lockorder", types.NewPtr(types.Types[TUINT8])),
+		namedfield("scase", types.NewArray(scase, size)),
+		namedfield("lockorderarr", types.NewArray(types.Types[TUINT16], size)),
+		namedfield("pollorderarr", types.NewArray(types.Types[TUINT16], size)),
+	})
+	sel.SetNoalg(true)
+	sel.SetLocal(true)
+
+	return sel
 }
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 416e2b2..613cdf6 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -4,13 +4,17 @@
 
 package gc
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"fmt"
+)
 
-// static initialization
+// Static initialization ordering state.
+// These values are stored in two bits in Node.flags.
 const (
-	InitNotStarted = 0
-	InitDone       = 1
-	InitPending    = 2
+	InitNotStarted = iota
+	InitDone
+	InitPending
 )
 
 type InitEntry struct {
@@ -40,19 +44,19 @@ func init1(n *Node, out *[]*Node) {
 		init1(n1, out)
 	}
 
-	if n.Left != nil && n.Type != nil && n.Left.Op == OTYPE && n.Class == PFUNC {
+	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(asNode(n.Type.FuncType().Nname), out)
 	}
 
 	if n.Op != ONAME {
 		return
 	}
-	switch n.Class {
+	switch n.Class() {
 	case PEXTERN, PFUNC:
 	default:
-		if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
+		if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder() == InitNotStarted {
 			// blank names initialization is part of init() but not
 			// when they are inside a function.
 			break
@@ -60,10 +64,10 @@ func init1(n *Node, out *[]*Node) {
 		return
 	}
 
-	if n.Initorder == InitDone {
+	if n.Initorder() == InitDone {
 		return
 	}
-	if n.Initorder == InitPending {
+	if n.Initorder() == InitPending {
 		// Since mutually recursive sets of functions are allowed,
 		// we don't necessarily raise an error if n depends on a node
 		// which is already waiting for its dependencies to be visited.
@@ -73,7 +77,7 @@ func init1(n *Node, out *[]*Node) {
 		// Conversely, if there exists an initialization cycle involving
 		// a variable in the program, the tree walk will reach a cycle
 		// involving that variable.
-		if n.Class != PFUNC {
+		if n.Class() != PFUNC {
 			foundinitloop(n, n)
 		}
 
@@ -82,7 +86,7 @@ func init1(n *Node, out *[]*Node) {
 			if x == n {
 				break
 			}
-			if x.Class != PFUNC {
+			if x.Class() != PFUNC {
 				foundinitloop(n, x)
 			}
 		}
@@ -92,7 +96,7 @@ func init1(n *Node, out *[]*Node) {
 	}
 
 	// reached a new unvisited node.
-	n.Initorder = InitPending
+	n.SetInitorder(InitPending)
 	initlist = append(initlist, n)
 
 	// make sure that everything n depends on is initialized.
@@ -130,10 +134,10 @@ func init1(n *Node, out *[]*Node) {
 			}
 
 		case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
-			if defn.Initorder == InitDone {
+			if defn.Initorder() == InitDone {
 				break
 			}
-			defn.Initorder = InitPending
+			defn.SetInitorder(InitPending)
 			for _, n2 := range defn.Rlist.Slice() {
 				init1(n2, out)
 			}
@@ -141,7 +145,7 @@ func init1(n *Node, out *[]*Node) {
 				Dump("nonstatic", defn)
 			}
 			*out = append(*out, defn)
-			defn.Initorder = InitDone
+			defn.SetInitorder(InitDone)
 		}
 	}
 
@@ -152,7 +156,7 @@ func init1(n *Node, out *[]*Node) {
 	initlist[last] = nil // allow GC
 	initlist = initlist[:last]
 
-	n.Initorder = InitDone
+	n.SetInitorder(InitDone)
 	return
 }
 
@@ -194,7 +198,7 @@ func foundinitloop(node, visited *Node) {
 
 // recurse over n, doing init1 everywhere.
 func init2(n *Node, out *[]*Node) {
-	if n == nil || n.Initorder == InitDone {
+	if n == nil || n.Initorder() == InitDone {
 		return
 	}
 
@@ -214,7 +218,7 @@ func init2(n *Node, out *[]*Node) {
 		init2list(n.Func.Closure.Nbody, out)
 	}
 	if n.Op == ODOTMETH || n.Op == OCALLPART {
-		init2(n.Type.Nname(), out)
+		init2(asNode(n.Type.FuncType().Nname), out)
 	}
 }
 
@@ -254,11 +258,11 @@ func initfix(l []*Node) []*Node {
 // compilation of top-level (static) assignments
 // into DATA statements if at all possible.
 func staticinit(n *Node, out *[]*Node) bool {
-	if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
+	if n.Op != ONAME || n.Class() != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
 		Fatalf("staticinit")
 	}
 
-	lineno = n.Lineno
+	lineno = n.Pos
 	l := n.Name.Defn.Left
 	r := n.Name.Defn.Right
 	return staticassign(l, r, out)
@@ -270,11 +274,11 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
 	if r.Op != ONAME {
 		return false
 	}
-	if r.Class == PFUNC {
+	if r.Class() == PFUNC {
 		gdata(l, r, Widthptr)
 		return true
 	}
-	if r.Class != PEXTERN || r.Sym.Pkg != localpkg {
+	if r.Class() != PEXTERN || r.Sym.Pkg != localpkg {
 		return false
 	}
 	if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
@@ -330,9 +334,9 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
 		n.Xoffset = l.Xoffset + int64(array_array)
 		gdata(&n, nod(OADDR, a, nil), Widthptr)
 		n.Xoffset = l.Xoffset + int64(array_nel)
-		gdata(&n, r.Right, Widthint)
+		gdata(&n, r.Right, Widthptr)
 		n.Xoffset = l.Xoffset + int64(array_cap)
-		gdata(&n, r.Right, Widthint)
+		gdata(&n, r.Right, Widthptr)
 		return true
 
 	case OARRAYLIT, OSTRUCTLIT:
@@ -414,7 +418,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
 		//dump("not static ptrlit", r);
 
 	case OSTRARRAYBYTE:
-		if l.Class == PEXTERN && r.Left.Op == OLITERAL {
+		if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
 			sval := r.Left.Val().U.(string)
 			slicebytes(l, sval, len(sval))
 			return true
@@ -424,16 +428,16 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
 		initplan(r)
 		// Init slice.
 		bound := r.Right.Int64()
-		ta := typArray(r.Type.Elem(), bound)
+		ta := types.NewArray(r.Type.Elem(), bound)
 		a := staticname(ta)
 		inittemps[r] = a
 		n := *l
 		n.Xoffset = l.Xoffset + int64(array_array)
 		gdata(&n, nod(OADDR, a, nil), Widthptr)
 		n.Xoffset = l.Xoffset + int64(array_nel)
-		gdata(&n, r.Right, Widthint)
+		gdata(&n, r.Right, Widthptr)
 		n.Xoffset = l.Xoffset + int64(array_cap)
-		gdata(&n, r.Right, Widthint)
+		gdata(&n, r.Right, Widthptr)
 
 		// Fall through to init underlying array.
 		l = a
@@ -469,7 +473,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
 	case OCLOSURE:
 		if hasemptycvars(r) {
 			if Debug_closure > 0 {
-				Warnl(r.Lineno, "closure converted to global")
+				Warnl(r.Pos, "closure converted to global")
 			}
 			// Closures with no captured variables are globals,
 			// so the assignment can be done at link time.
@@ -535,7 +539,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
 				*out = append(*out, nod(OAS, a, val))
 			}
 			ptr := nod(OADDR, a, nil)
-			n.Type = ptrto(val.Type)
+			n.Type = types.NewPtr(val.Type)
 			gdata(&n, ptr, Widthptr)
 		}
 
@@ -569,11 +573,14 @@ const (
 // data statements for the constant
 // part of the composite literal.
 
+var statuniqgen int // name generator for static temps
+
 // staticname returns a name backed by a static data symbol.
-// Callers should set n.Name.Readonly = true on the
+// Callers should call n.Name.SetReadonly(true) on the
 // returned node for readonly nodes.
-func staticname(t *Type) *Node {
-	n := newname(lookupN("statictmp_", statuniqgen))
+func staticname(t *types.Type) *Node {
+	// Don't use lookupN; it interns the resulting string, but these are all unique.
+	n := newname(lookup(fmt.Sprintf("statictmp_%d", statuniqgen)))
 	statuniqgen++
 	addvar(n, t, PEXTERN)
 	return n
@@ -585,7 +592,7 @@ func isliteral(n *Node) bool {
 }
 
 func (n *Node) isSimpleName() bool {
-	return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP && n.Class != PEXTERN
+	return n.Op == ONAME && n.Addable() && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
 }
 
 func litas(l *Node, r *Node, init *Nodes) {
@@ -719,6 +726,9 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
 			if r.Op != OSTRUCTKEY {
 				Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
 			}
+			if r.Sym.IsBlank() {
+				return nblank, r.Left
+			}
 			return nodSym(ODOT, var_, r.Sym), r.Left
 		}
 	default:
@@ -751,30 +761,21 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
 		a = typecheck(a, Etop)
 		switch kind {
 		case initKindStatic:
-			a = walkexpr(a, init) // add any assignments in r to top
-			if a.Op == OASWB {
-				// Static initialization never needs
-				// write barriers.
-				a.Op = OAS
-			}
-			if a.Op != OAS {
-				Fatalf("fixedlit: not as, is %v", a)
-			}
-			a.IsStatic = true
+			genAsStatic(a)
 		case initKindDynamic, initKindLocalCode:
 			a = orderstmtinplace(a)
 			a = walkstmt(a)
+			init.Append(a)
 		default:
 			Fatalf("fixedlit: bad kind %d", kind)
 		}
 
-		init.Append(a)
 	}
 }
 
 func slicelit(ctxt initContext, 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())
+	t := types.NewArray(n.Type.Elem(), n.Right.Int64())
 	dowidth(t)
 
 	if ctxt == inNonInitFunction {
@@ -785,12 +786,22 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
 		fixedlit(ctxt, initKindDynamic, n, vstat, init)
 
 		// copy static to slice
-		a := nod(OSLICE, vstat, nil)
+		var_ = typecheck(var_, Erv|Easgn)
+		var nam Node
+		if !stataddr(&nam, var_) || nam.Class() != PEXTERN {
+			Fatalf("slicelit: %v", var_)
+		}
+
+		var v Node
+		nodconst(&v, types.Types[TINT], t.NumElem())
+
+		nam.Xoffset += int64(array_array)
+		gdata(&nam, nod(OADDR, vstat, nil), Widthptr)
+		nam.Xoffset += int64(array_nel) - int64(array_array)
+		gdata(&nam, &v, Widthptr)
+		nam.Xoffset += int64(array_cap) - int64(array_nel)
+		gdata(&nam, &v, Widthptr)
 
-		a = nod(OAS, var_, a)
-		a = typecheck(a, Etop)
-		a.IsStatic = true
-		init.Append(a)
 		return
 	}
 
@@ -821,13 +832,13 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
 	if mode&initConst != 0 {
 		vstat = staticname(t)
 		if ctxt == inInitFunction {
-			vstat.Name.Readonly = true
+			vstat.Name.SetReadonly(true)
 		}
 		fixedlit(ctxt, initKindStatic, n, vstat, init)
 	}
 
 	// make new auto *array (3 declare)
-	vauto := temp(ptrto(t))
+	vauto := temp(types.NewPtr(t))
 
 	// set auto to point at new temp or heap (3 assign)
 	var a *Node
@@ -881,7 +892,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
 			value = r.Right
 		}
 		a := nod(OINDEX, vauto, nodintconst(index))
-		a.Bounded = true
+		a.SetBounded(true)
 		index++
 
 		// TODO need to check bounds?
@@ -920,30 +931,30 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
 
 func maplit(n *Node, m *Node, init *Nodes) {
 	// make the map var
-	nerr := nerrors
-
 	a := nod(OMAKE, nil, nil)
-	a.List.Set2(typenod(n.Type), nodintconst(int64(len(n.List.Slice()))))
+	a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len())))
 	litas(m, a, init)
 
-	// count the initializers
-	b := 0
+	// Split the initializers into static and dynamic.
+	var stat, dyn []*Node
 	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
 			Fatalf("maplit: rhs not OKEY: %v", r)
 		}
-		index := r.Left
-		value := r.Right
-
-		if isliteral(index) && isliteral(value) {
-			b++
+		if isliteral(r.Left) && isliteral(r.Right) {
+			stat = append(stat, r)
+		} else {
+			dyn = append(dyn, r)
 		}
 	}
 
-	if b != 0 {
+	// Add static entries.
+	if len(stat) > 25 {
+		// For a large number of static entries, put them in an array and loop.
+
 		// build types [count]Tindex and [count]Tvalue
-		tk := typArray(n.Type.Key(), int64(b))
-		tv := typArray(n.Type.Val(), int64(b))
+		tk := types.NewArray(n.Type.Key(), int64(len(stat)))
+		tv := types.NewArray(n.Type.Val(), int64(len(stat)))
 
 		// TODO(josharian): suppress alg generation for these types?
 		dowidth(tk)
@@ -951,51 +962,39 @@ func maplit(n *Node, m *Node, init *Nodes) {
 
 		// make and initialize static arrays
 		vstatk := staticname(tk)
-		vstatk.Name.Readonly = true
+		vstatk.Name.SetReadonly(true)
 		vstatv := staticname(tv)
-		vstatv.Name.Readonly = true
+		vstatv.Name.SetReadonly(true)
 
-		b := int64(0)
-		for _, r := range n.List.Slice() {
-			if r.Op != OKEY {
-				Fatalf("maplit: rhs not OKEY: %v", r)
-			}
+		for i, r := range stat {
 			index := r.Left
 			value := r.Right
 
-			if isliteral(index) && isliteral(value) {
-				// build vstatk[b] = index
-				setlineno(index)
-				lhs := nod(OINDEX, vstatk, nodintconst(b))
-				as := nod(OAS, lhs, index)
-				as = typecheck(as, Etop)
-				as = walkexpr(as, init)
-				as.IsStatic = true
-				init.Append(as)
-
-				// build vstatv[b] = value
-				setlineno(value)
-				lhs = nod(OINDEX, vstatv, nodintconst(b))
-				as = nod(OAS, lhs, value)
-				as = typecheck(as, Etop)
-				as = walkexpr(as, init)
-				as.IsStatic = true
-				init.Append(as)
-
-				b++
-			}
+			// build vstatk[b] = index
+			setlineno(index)
+			lhs := nod(OINDEX, vstatk, nodintconst(int64(i)))
+			as := nod(OAS, lhs, index)
+			as = typecheck(as, Etop)
+			genAsStatic(as)
+
+			// build vstatv[b] = value
+			setlineno(value)
+			lhs = nod(OINDEX, vstatv, nodintconst(int64(i)))
+			as = nod(OAS, lhs, value)
+			as = typecheck(as, Etop)
+			genAsStatic(as)
 		}
 
 		// loop adding structure elements to map
 		// for i = 0; i < len(vstatk); i++ {
 		//	map[vstatk[i]] = vstatv[i]
 		// }
-		i := temp(Types[TINT])
+		i := temp(types.Types[TINT])
 		rhs := nod(OINDEX, vstatv, i)
-		rhs.Bounded = true
+		rhs.SetBounded(true)
 
 		kidx := nod(OINDEX, vstatk, i)
-		kidx.Bounded = true
+		kidx.SetBounded(true)
 		lhs := nod(OINDEX, m, kidx)
 
 		zero := nod(OAS, i, nodintconst(0))
@@ -1010,30 +1009,33 @@ func maplit(n *Node, m *Node, init *Nodes) {
 		loop = typecheck(loop, Etop)
 		loop = walkstmt(loop)
 		init.Append(loop)
+	} else {
+		// For a small number of static entries, just add them directly.
+		addMapEntries(m, stat, init)
 	}
 
-	// put in dynamic entries one-at-a-time
-	var key, val *Node
-	for _, r := range n.List.Slice() {
-		if r.Op != OKEY {
-			Fatalf("maplit: rhs not OKEY: %v", r)
-		}
-		index := r.Left
-		value := r.Right
+	// Add dynamic entries.
+	addMapEntries(m, dyn, init)
+}
 
-		if isliteral(index) && isliteral(value) {
-			continue
-		}
+func addMapEntries(m *Node, dyn []*Node, init *Nodes) {
+	if len(dyn) == 0 {
+		return
+	}
 
-		// build list of var[c] = expr.
-		// use temporary so that mapassign1 can have addressable key, val.
-		if key == nil {
-			key = temp(m.Type.Key())
-			val = temp(m.Type.Val())
-		}
+	nerr := nerrors
+
+	// Build list of var[c] = expr.
+	// Use temporaries so that mapassign1 can have addressable key, val.
+	// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
+	key := temp(m.Type.Key())
+	val := temp(m.Type.Val())
+
+	for _, r := range dyn {
+		index, value := r.Left, r.Right
 
 		setlineno(index)
-		a = nod(OAS, key, index)
+		a := nod(OAS, key, index)
 		a = typecheck(a, Etop)
 		a = walkstmt(a)
 		init.Append(a)
@@ -1055,14 +1057,12 @@ func maplit(n *Node, m *Node, init *Nodes) {
 		}
 	}
 
-	if key != nil {
-		a = nod(OVARKILL, key, nil)
-		a = typecheck(a, Etop)
-		init.Append(a)
-		a = nod(OVARKILL, val, nil)
-		a = typecheck(a, Etop)
-		init.Append(a)
-	}
+	a := nod(OVARKILL, key, nil)
+	a = typecheck(a, Etop)
+	init.Append(a)
+	a = nod(OVARKILL, val, nil)
+	a = typecheck(a, Etop)
+	init.Append(a)
 }
 
 func anylit(n *Node, var_ *Node, init *Nodes) {
@@ -1084,7 +1084,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) {
 			r = typecheck(r, Erv)
 		} else {
 			r = nod(ONEW, nil, nil)
-			r.Typecheck = 1
+			r.SetTypecheck(1)
 			r.Type = t
 			r.Esc = n.Esc
 		}
@@ -1107,7 +1107,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) {
 		if var_.isSimpleName() && n.List.Len() > 4 {
 			// lay out static data
 			vstat := staticname(t)
-			vstat.Name.Readonly = true
+			vstat.Name.SetReadonly(true)
 
 			ctxt := inInitFunction
 			if n.Op == OARRAYLIT {
@@ -1206,7 +1206,7 @@ func stataddr(nam *Node, n *Node) bool {
 	switch n.Op {
 	case ONAME:
 		*nam = *n
-		return n.Addable
+		return n.Addable()
 
 	case ODOT:
 		if !stataddr(nam, n.Left) {
@@ -1229,7 +1229,7 @@ func stataddr(nam *Node, n *Node) bool {
 		}
 
 		// Check for overflow.
-		if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
+		if n.Type.Width != 0 && thearch.MAXWIDTH/n.Type.Width <= int64(l) {
 			break
 		}
 		nam.Xoffset += int64(l) * n.Type.Width
@@ -1349,88 +1349,22 @@ func isvaluelit(n *Node) bool {
 	return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
 }
 
-// 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.IsStatic {
-		Dump("\ngen_as_init", n)
-		Fatalf("gen_as_init couldn't generate static data")
-	}
-	return success
-}
-
-func genAsInitNoCheck(n *Node, reportOnly bool) bool {
-	if !n.IsStatic {
-		return false
-	}
-
-	nr := n.Right
-	nl := n.Left
-	if nr == nil {
-		var nam Node
-		return stataddr(&nam, nl) && nam.Class == PEXTERN
-	}
-
-	if nr.Type == nil || !eqtype(nl.Type, nr.Type) {
-		return false
+func genAsStatic(as *Node) {
+	if as.Left.Type == nil {
+		Fatalf("genAsStatic as.Left not typechecked")
 	}
 
 	var nam Node
-	if !stataddr(&nam, nl) || nam.Class != PEXTERN {
-		return false
+	if !stataddr(&nam, as.Left) || (nam.Class() != PEXTERN && as.Left != nblank) {
+		Fatalf("genAsStatic: lhs %v", as.Left)
 	}
 
-	switch nr.Op {
+	switch {
+	case as.Right.Op == OLITERAL:
+	case as.Right.Op == ONAME && as.Right.Class() == PFUNC:
 	default:
-		return false
-
-	case OCONVNOP:
-		nr = nr.Left
-		if nr == nil || nr.Op != OSLICEARR {
-			return false
-		}
-		fallthrough
-
-	case OSLICEARR:
-		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.IsArray() {
-			return false
-		}
-
-		if !reportOnly {
-			nam.Xoffset += int64(array_array)
-			gdata(&nam, ptr, Widthptr)
-
-			nam.Xoffset += int64(array_nel) - int64(array_array)
-			var nod1 Node
-			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
-
-	case OLITERAL:
-		if !reportOnly {
-			gdata(&nam, nr, int(nr.Type.Width))
-		}
-		return true
+		Fatalf("genAsStatic: rhs %v", as.Right)
 	}
+
+	gdata(&nam, as.Right, int(as.Right.Type.Width))
 }
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
index b86188c..1ca0a61 100644
--- a/src/cmd/compile/internal/gc/sizeof_test.go
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -22,25 +22,10 @@ func TestSizeof(t *testing.T) {
 		_32bit uintptr     // size on 32bit platforms
 		_64bit uintptr     // size on 64bit platforms
 	}{
-		{Func{}, 92, 160},
-		{Name{}, 44, 72},
-		{Param{}, 24, 48},
-		{Node{}, 92, 144},
-		{Sym{}, 60, 112},
-		{Type{}, 60, 96},
-		{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},
+		{Func{}, 124, 216},
+		{Name{}, 36, 56},
+		{Param{}, 28, 56},
+		{Node{}, 76, 128},
 	}
 
 	for _, tt := range tests {
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index a0c1cf1..1497c5c 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -13,27 +13,91 @@ import (
 	"sort"
 
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"cmd/internal/sys"
 )
 
 var ssaConfig *ssa.Config
-var ssaExp ssaExport
-
-func initssa() *ssa.Config {
-	if ssaConfig == nil {
-		ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
-		if Thearch.LinkArch.Name == "386" {
-			ssaConfig.Set387(Thearch.Use387)
-		}
-	}
-	ssaConfig.HTML = nil
-	return ssaConfig
-}
-
-// buildssa builds an SSA function.
-func buildssa(fn *Node) *ssa.Func {
-	name := fn.Func.Nname.Sym.Name
+var ssaCaches []ssa.Cache
+
+func initssaconfig() {
+	types_ := ssa.Types{
+		Bool:       types.Types[TBOOL],
+		Int8:       types.Types[TINT8],
+		Int16:      types.Types[TINT16],
+		Int32:      types.Types[TINT32],
+		Int64:      types.Types[TINT64],
+		UInt8:      types.Types[TUINT8],
+		UInt16:     types.Types[TUINT16],
+		UInt32:     types.Types[TUINT32],
+		UInt64:     types.Types[TUINT64],
+		Float32:    types.Types[TFLOAT32],
+		Float64:    types.Types[TFLOAT64],
+		Int:        types.Types[TINT],
+		Uintptr:    types.Types[TUINTPTR],
+		String:     types.Types[TSTRING],
+		BytePtr:    types.NewPtr(types.Types[TUINT8]),
+		Int32Ptr:   types.NewPtr(types.Types[TINT32]),
+		UInt32Ptr:  types.NewPtr(types.Types[TUINT32]),
+		IntPtr:     types.NewPtr(types.Types[TINT]),
+		UintptrPtr: types.NewPtr(types.Types[TUINTPTR]),
+		Float32Ptr: types.NewPtr(types.Types[TFLOAT32]),
+		Float64Ptr: types.NewPtr(types.Types[TFLOAT64]),
+		BytePtrPtr: types.NewPtr(types.NewPtr(types.Types[TUINT8])),
+	}
+	// Generate a few pointer types that are uncommon in the frontend but common in the backend.
+	// Caching is disabled in the backend, so generating these here avoids allocations.
+	_ = types.NewPtr(types.Types[TINTER])                             // *interface{}
+	_ = types.NewPtr(types.NewPtr(types.Types[TSTRING]))              // **string
+	_ = types.NewPtr(types.NewPtr(types.Idealstring))                 // **string
+	_ = types.NewPtr(types.NewSlice(types.Types[TINTER]))             // *[]interface{}
+	_ = types.NewPtr(types.NewPtr(types.Bytetype))                    // **byte
+	_ = types.NewPtr(types.NewSlice(types.Bytetype))                  // *[]byte
+	_ = types.NewPtr(types.NewSlice(types.Types[TSTRING]))            // *[]string
+	_ = types.NewPtr(types.NewSlice(types.Idealstring))               // *[]string
+	_ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
+	_ = types.NewPtr(types.Types[TINT16])                             // *int16
+	_ = types.NewPtr(types.Types[TINT64])                             // *int64
+	_ = types.NewPtr(types.Errortype)                                 // *error
+	types.NewPtrCacheEnabled = false
+	ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, types_, Ctxt, Debug['N'] == 0)
+	if thearch.LinkArch.Name == "386" {
+		ssaConfig.Set387(thearch.Use387)
+	}
+	ssaCaches = make([]ssa.Cache, nBackendWorkers)
+
+	// Set up some runtime functions we'll need to call.
+	Newproc = Sysfunc("newproc")
+	Deferproc = Sysfunc("deferproc")
+	Deferreturn = Sysfunc("deferreturn")
+	Duffcopy = Sysfunc("duffcopy")
+	Duffzero = Sysfunc("duffzero")
+	panicindex = Sysfunc("panicindex")
+	panicslice = Sysfunc("panicslice")
+	panicdivide = Sysfunc("panicdivide")
+	growslice = Sysfunc("growslice")
+	panicdottypeE = Sysfunc("panicdottypeE")
+	panicdottypeI = Sysfunc("panicdottypeI")
+	panicnildottype = Sysfunc("panicnildottype")
+	assertE2I = Sysfunc("assertE2I")
+	assertE2I2 = Sysfunc("assertE2I2")
+	assertI2I = Sysfunc("assertI2I")
+	assertI2I2 = Sysfunc("assertI2I2")
+	goschedguarded = Sysfunc("goschedguarded")
+	writeBarrier = Sysfunc("writeBarrier")
+	writebarrierptr = Sysfunc("writebarrierptr")
+	typedmemmove = Sysfunc("typedmemmove")
+	typedmemclr = Sysfunc("typedmemclr")
+	Udiv = Sysfunc("udiv")
+}
+
+// buildssa builds an SSA function for fn.
+// worker indicates which of the backend workers is doing the processing.
+func buildssa(fn *Node, worker int) *ssa.Func {
+	name := fn.funcname()
 	printssa := name == os.Getenv("GOSSAFUNC")
 	if printssa {
 		fmt.Println("generating SSA for", name)
@@ -43,38 +107,40 @@ func buildssa(fn *Node) *ssa.Func {
 	}
 
 	var s state
-	s.pushLine(fn.Lineno)
+	s.pushLine(fn.Pos)
 	defer s.popLine()
 
+	s.hasdefer = fn.Func.HasDefer()
 	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
+	fe := ssafn{
+		curfn: fn,
+		log:   printssa,
+	}
+	s.curfn = fn
 
-	s.config = initssa()
-	s.f = s.config.NewFunc()
+	s.f = ssa.NewFunc(&fe)
+	s.config = ssaConfig
+	s.f.Config = ssaConfig
+	s.f.Cache = &ssaCaches[worker]
+	s.f.Cache.Reset()
+	s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH", name)
 	s.f.Name = name
 	if fn.Func.Pragma&Nosplit != 0 {
 		s.f.NoSplit = true
 	}
+	defer func() {
+		if s.f.WBPos.IsKnown() {
+			fn.Func.WBPos = s.f.WBPos
+		}
+	}()
 	s.exitCode = fn.Func.Exit
 	s.panics = map[funcLine]*ssa.Block{}
-	s.config.DebugTest = s.config.DebugHashMatch("GOSSAHASH", name)
 
 	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)
+		s.f.HTMLWriter = ssa.NewHTMLWriter("ssa.html", s.f.Frontend(), name)
 		// TODO: generate and print a mapping from nodes to values and blocks
 	}
 
@@ -85,9 +151,9 @@ func buildssa(fn *Node) *ssa.Func {
 	s.labels = map[string]*ssaLabel{}
 	s.labeledNodes = map[*Node]*ssaLabel{}
 	s.fwdVars = map[*Node]*ssa.Value{}
-	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.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
+	s.sp = s.entryNewValue0(ssa.OpSP, types.Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
+	s.sb = s.entryNewValue0(ssa.OpSB, types.Types[TUINTPTR])
 
 	s.startBlock(s.f.Entry)
 	s.vars[&memVar] = s.startmem
@@ -97,11 +163,11 @@ func buildssa(fn *Node) *ssa.Func {
 	// Generate addresses of local declarations
 	s.decladdrs = map[*Node]*ssa.Value{}
 	for _, n := range fn.Func.Dcl {
-		switch n.Class {
+		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) {
+			aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n})
+			s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(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.
@@ -115,23 +181,15 @@ func buildssa(fn *Node) *ssa.Func {
 		case PFUNC:
 			// local function - already handled by frontend
 		default:
-			s.Fatalf("local variable with class %s unimplemented", classnames[n.Class])
+			s.Fatalf("local variable with class %s unimplemented", classnames[n.Class()])
 		}
 	}
 
-	// Populate arguments.
+	// Populate SSAable arguments.
 	for _, n := range fn.Func.Dcl {
-		if n.Class != PPARAM {
-			continue
-		}
-		var v *ssa.Value
-		if s.canSSA(n) {
-			v = s.newValue0A(ssa.OpArg, n.Type, n)
-		} else {
-			// Not SSAable. Load it.
-			v = s.newValue2(ssa.OpLoad, n.Type, s.decladdrs[n], s.startmem)
+		if n.Class() == PPARAM && s.canSSA(n) {
+			s.vars[n] = s.newValue0A(ssa.OpArg, n.Type, n)
 		}
-		s.vars[n] = v
 	}
 
 	// Convert the AST-based IR to the SSA-based IR
@@ -145,32 +203,6 @@ func buildssa(fn *Node) *ssa.Func {
 		s.popLine()
 	}
 
-	// Check that we used all labels
-	for name, lab := range s.labels {
-		if !lab.used() && !lab.reported && !lab.defNode.Used {
-			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
-	}
-
 	s.insertPhis()
 
 	// Don't carry reference this around longer than necessary
@@ -178,7 +210,6 @@ func buildssa(fn *Node) *ssa.Func {
 
 	// Main call to ssa package to compile function
 	ssa.Compile(s.f)
-
 	return s.f
 }
 
@@ -189,12 +220,13 @@ type state struct {
 	// function we're building
 	f *ssa.Func
 
-	// labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
+	// Node for function
+	curfn *Node
+
+	// labels and labeled control flow nodes (OFOR, OFORUNTIL, 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
@@ -231,7 +263,7 @@ type state struct {
 	sb       *ssa.Value
 
 	// line number stack. The current line number is top of stack
-	line []int32
+	line []src.XPos
 
 	// list of panic calls by function name and line number.
 	// Used to deduplicate panic calls.
@@ -240,39 +272,24 @@ type state struct {
 	// list of PPARAMOUT (return) variables.
 	returns []*Node
 
-	// A dummy value used during phi construction.
-	placeholder *ssa.Value
-
 	cgoUnsafeArgs bool
-	noWB          bool
-	WBLineno      int32 // line number of first write barrier. 0=no write barriers
+	hasdefer      bool // whether the function contains a defer statement
 }
 
 type funcLine struct {
-	f    *Node
-	line int32
+	f    *obj.LSym
+	file string
+	line uint
 }
 
 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 {
+func (s *state) label(sym *types.Sym) *ssaLabel {
 	lab := s.labels[sym.Name]
 	if lab == nil {
 		lab = new(ssaLabel)
@@ -281,23 +298,25 @@ func (s *state) label(sym *Sym) *ssaLabel {
 	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) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
-func (s *state) Debug_checknil() bool                              { return s.config.Debug_checknil() }
+func (s *state) Logf(msg string, args ...interface{}) { s.f.Logf(msg, args...) }
+func (s *state) Log() bool                            { return s.f.Log() }
+func (s *state) Fatalf(msg string, args ...interface{}) {
+	s.f.Frontend().Fatalf(s.peekPos(), msg, args...)
+}
+func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) { s.f.Warnl(pos, msg, args...) }
+func (s *state) Debug_checknil() bool                                { return s.f.Frontend().Debug_checknil() }
 
 var (
 	// dummy node for the memory variable
-	memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
+	memVar = Node{Op: ONAME, Sym: &types.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"}}
-	okVar     = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
+	ptrVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "ptr"}}
+	lenVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "len"}}
+	newlenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "newlen"}}
+	capVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "cap"}}
+	typVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "typ"}}
+	okVar     = Node{Op: ONAME, Sym: &types.Sym{Name: "ok"}}
 )
 
 // startBlock sets the current block we're generating code in to b.
@@ -326,18 +345,18 @@ func (s *state) endBlock() *ssa.Block {
 	s.defvars[b.ID] = s.vars
 	s.curBlock = nil
 	s.vars = nil
-	b.Line = s.peekLine()
+	b.Pos = s.peekPos()
 	return b
 }
 
 // pushLine pushes a line number on the line number stack.
-func (s *state) pushLine(line int32) {
-	if line == 0 {
+func (s *state) pushLine(line src.XPos) {
+	if !line.IsKnown() {
 		// the frontend may emit node with line number missing,
 		// use the parent line number in this case.
-		line = s.peekLine()
+		line = s.peekPos()
 		if Debug['K'] != 0 {
-			Warn("buildssa: line 0")
+			Warn("buildssa: unknown position (line 0)")
 		}
 	}
 	s.line = append(s.line, line)
@@ -348,133 +367,135 @@ 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 {
+// peekPos peeks the top of the line number stack.
+func (s *state) peekPos() src.XPos {
 	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)
+func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value {
+	return s.curBlock.NewValue0(s.peekPos(), 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)
+func (s *state) newValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value {
+	return s.curBlock.NewValue0A(s.peekPos(), 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)
+func (s *state) newValue0I(op ssa.Op, t *types.Type, auxint int64) *ssa.Value {
+	return s.curBlock.NewValue0I(s.peekPos(), 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)
+func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1(s.peekPos(), 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)
+func (s *state) newValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1A(s.peekPos(), 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)
+func (s *state) newValue1I(op ssa.Op, t *types.Type, aux int64, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1I(s.peekPos(), 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)
+func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue2(s.peekPos(), 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)
+func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue2I(s.peekPos(), 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)
+func (s *state) newValue3(op ssa.Op, t *types.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue3(s.peekPos(), 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)
+func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2)
+}
+
+// newValue3A adds a new value with three arguments and an aux value to the current block.
+func (s *state) newValue3A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2)
 }
 
 // newValue4 adds a new value with four arguments to the current block.
-func (s *state) newValue4(op ssa.Op, t ssa.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
-	return s.curBlock.NewValue4(s.peekLine(), op, t, arg0, arg1, arg2, arg3)
+func (s *state) newValue4(op ssa.Op, t *types.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3)
 }
 
 // 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)
+func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value {
+	return s.f.Entry.NewValue0(src.NoXPos, 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)
+func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value {
+	return s.f.Entry.NewValue0A(s.peekPos(), op, t, aux)
 }
 
 // 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)
+func (s *state) entryNewValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1(s.peekPos(), 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)
+func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1I(s.peekPos(), 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)
+func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1A(s.peekPos(), 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)
+func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue2(s.peekPos(), 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) constSlice(t *types.Type) *ssa.Value {
+	return s.f.ConstSlice(s.peekPos(), t)
+}
+func (s *state) constInterface(t *types.Type) *ssa.Value {
+	return s.f.ConstInterface(s.peekPos(), t)
+}
+func (s *state) constNil(t *types.Type) *ssa.Value { return s.f.ConstNil(s.peekPos(), t) }
+func (s *state) constEmptyString(t *types.Type) *ssa.Value {
+	return s.f.ConstEmptyString(s.peekPos(), t)
+}
 func (s *state) constBool(c bool) *ssa.Value {
-	return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
+	return s.f.ConstBool(s.peekPos(), types.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) constInt8(t *types.Type, c int8) *ssa.Value {
+	return s.f.ConstInt8(s.peekPos(), t, c)
 }
-func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
-	return s.f.ConstInt16(s.peekLine(), t, c)
+func (s *state) constInt16(t *types.Type, c int16) *ssa.Value {
+	return s.f.ConstInt16(s.peekPos(), t, c)
 }
-func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
-	return s.f.ConstInt32(s.peekLine(), t, c)
+func (s *state) constInt32(t *types.Type, c int32) *ssa.Value {
+	return s.f.ConstInt32(s.peekPos(), t, c)
 }
-func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
-	return s.f.ConstInt64(s.peekLine(), t, c)
+func (s *state) constInt64(t *types.Type, c int64) *ssa.Value {
+	return s.f.ConstInt64(s.peekPos(), t, c)
 }
-func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
-	return s.f.ConstFloat32(s.peekLine(), t, c)
+func (s *state) constFloat32(t *types.Type, c float64) *ssa.Value {
+	return s.f.ConstFloat32(s.peekPos(), t, c)
 }
-func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
-	return s.f.ConstFloat64(s.peekLine(), t, c)
+func (s *state) constFloat64(t *types.Type, c float64) *ssa.Value {
+	return s.f.ConstFloat64(s.peekPos(), t, c)
 }
-func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
-	if s.config.IntSize == 8 {
+func (s *state) constInt(t *types.Type, c int64) *ssa.Value {
+	if s.config.PtrSize == 8 {
 		return s.constInt64(t, c)
 	}
 	if int64(int32(c)) != c {
@@ -482,6 +503,9 @@ func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
 	}
 	return s.constInt32(t, int32(c))
 }
+func (s *state) constOffPtrSP(t *types.Type, c int64) *ssa.Value {
+	return s.f.ConstOffPtrSP(s.peekPos(), t, c, s.sp)
+}
 
 // stmtList converts the statement list n to SSA and adds it to s.
 func (s *state) stmtList(l Nodes) {
@@ -492,17 +516,13 @@ func (s *state) stmtList(l Nodes) {
 
 // stmt converts the statement n to SSA and adds it to s.
 func (s *state) stmt(n *Node) {
-	s.pushLine(n.Lineno)
+	s.pushLine(n.Pos)
 	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)
+	// If s.curBlock is nil, and n isn't a label (which might have an associated goto somewhere),
+	// then this code is dead. Stop here.
+	if s.curBlock == nil && n.Op != OLABEL {
+		return
 	}
 
 	s.stmtList(n.Ninit)
@@ -524,9 +544,9 @@ func (s *state) stmt(n *Node) {
 
 	case OCALLMETH, OCALLINTER:
 		s.call(n, callNormal)
-		if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC {
+		if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class() == PFUNC {
 			if fn := n.Left.Sym.Name; compiling_runtime && fn == "throw" ||
-				n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "selectgo" || fn == "block") {
+				n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block") {
 				m := s.mem()
 				b := s.endBlock()
 				b.Kind = ssa.BlockExit
@@ -558,8 +578,8 @@ func (s *state) stmt(n *Node) {
 			deref = true
 			res = res.Args[0]
 		}
-		s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), deref, n.Lineno, 0, false)
-		s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false)
+		s.assign(n.List.First(), res, deref, 0)
+		s.assign(n.List.Second(), resok, false, 0)
 		return
 
 	case OAS2FUNC:
@@ -570,52 +590,35 @@ func (s *state) stmt(n *Node) {
 		v := s.intrinsicCall(n.Rlist.First())
 		v1 := s.newValue1(ssa.OpSelect0, n.List.First().Type, v)
 		v2 := s.newValue1(ssa.OpSelect1, n.List.Second().Type, v)
-		// Make a fake node to mimic loading return value, ONLY for write barrier test.
-		// This is future-proofing against non-scalar 2-result intrinsics.
-		// Currently we only have scalar ones, which result in no write barrier.
-		fakeret := &Node{Op: OINDREGSP}
-		s.assign(n.List.First(), v1, needwritebarrier(n.List.First(), fakeret), false, n.Lineno, 0, false)
-		s.assign(n.List.Second(), v2, needwritebarrier(n.List.Second(), fakeret), false, n.Lineno, 0, false)
+		s.assign(n.List.First(), v1, false, 0)
+		s.assign(n.List.Second(), v2, false, 0)
 		return
 
 	case ODCL:
-		if n.Left.Class == PAUTOHEAP {
+		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 ctl := n.labeledControl(); ctl != nil {
+			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)
+		// Go to that label.
+		// (We pretend "label:" is preceded by "goto label", unless the predecessor is unreachable.)
+		if s.curBlock != nil {
+			b := s.endBlock()
+			b.AddEdgeTo(lab.target)
+		}
 		s.startBlock(lab.target)
 
 	case OGOTO:
@@ -625,32 +628,11 @@ func (s *state) stmt(n *Node) {
 		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
-		}
-
+	case OAS:
 		if n.Left == n.Right && n.Left.Op == ONAME {
 			// An x=x assignment. No point in doing anything
 			// here. In addition, skipping this assignment
@@ -662,13 +644,6 @@ func (s *state) stmt(n *Node) {
 			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 {
@@ -690,27 +665,42 @@ func (s *state) stmt(n *Node) {
 				if samesafeexpr(n.Left, rhs.List.First()) {
 					if !s.canSSA(n.Left) {
 						if Debug_append > 0 {
-							Warnl(n.Lineno, "append: len-only update")
+							Warnl(n.Pos, "append: len-only update")
 						}
 						s.append(rhs, true)
 						return
 					} else {
 						if Debug_append > 0 { // replicating old diagnostic message
-							Warnl(n.Lineno, "append: len-only update (in local slice)")
+							Warnl(n.Pos, "append: len-only update (in local slice)")
 						}
 					}
 				}
 			}
 		}
+
+		if isblank(n.Left) {
+			// _ = rhs
+			// Just evaluate rhs for side-effects.
+			if rhs != nil {
+				s.expr(rhs)
+			}
+			return
+		}
+
+		var t *types.Type
+		if n.Right != nil {
+			t = n.Right.Type
+		} else {
+			t = n.Left.Type
+		}
+
 		var r *ssa.Value
-		var isVolatile bool
-		needwb := n.Op == OASWB
 		deref := !canSSAType(t)
 		if deref {
 			if rhs == nil {
 				r = nil // Signal assign to use OpZero.
 			} else {
-				r, isVolatile = s.addr(rhs, false)
+				r = s.addr(rhs, false)
 			}
 		} else {
 			if rhs == nil {
@@ -719,15 +709,6 @@ func (s *state) stmt(n *Node) {
 				r = s.expr(rhs)
 			}
 		}
-		if rhs != nil && rhs.Op == OAPPEND && needwritebarrier(n.Left, rhs) {
-			// 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) {
@@ -759,17 +740,21 @@ func (s *state) stmt(n *Node) {
 			}
 		}
 
-		s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile)
+		s.assign(n.Left, r, deref, skip)
 
 	case OIF:
 		bThen := s.f.NewBlock(ssa.BlockPlain)
 		bEnd := s.f.NewBlock(ssa.BlockPlain)
 		var bElse *ssa.Block
+		var likely int8
+		if n.Likely() {
+			likely = 1
+		}
 		if n.Rlist.Len() != 0 {
 			bElse = s.f.NewBlock(ssa.BlockPlain)
-			s.condBranch(n.Left, bThen, bElse, n.Likely)
+			s.condBranch(n.Left, bThen, bElse, likely)
 		} else {
-			s.condBranch(n.Left, bThen, bEnd, n.Likely)
+			s.condBranch(n.Left, bThen, bEnd, likely)
 		}
 
 		s.startBlock(bThen)
@@ -794,78 +779,57 @@ func (s *state) stmt(n *Node) {
 		s.stmtList(n.List)
 		b := s.exit()
 		b.Kind = ssa.BlockRetJmp // override BlockRet
-		b.Aux = n.Left.Sym
+		b.Aux = n.Left.Sym.Linksym()
 
 	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
+			switch n.Op {
+			case OCONTINUE:
+				to = s.continueTo
+			case OBREAK:
+				to = s.breakTo
 			}
-			// 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:
+	case OFOR, OFORUNTIL:
 		// OFOR: for Ninit; Left; Right { Nbody }
+		// For      = cond; body; incr
+		// Foruntil = body; incr; cond
 		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
+		// first, jump to condition test (OFOR) or body (OFORUNTIL)
 		b := s.endBlock()
-		b.AddEdgeTo(bCond)
+		if n.Op == OFOR {
+			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)
+			}
 
-		// 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)
 		}
 
@@ -906,6 +870,19 @@ func (s *state) stmt(n *Node) {
 		if b := s.endBlock(); b != nil {
 			b.AddEdgeTo(bCond)
 		}
+
+		if n.Op == OFORUNTIL {
+			// 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)
+			}
+		}
+
 		s.startBlock(bEnd)
 
 	case OSWITCH, OSELECT:
@@ -929,12 +906,13 @@ func (s *state) stmt(n *Node) {
 			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)
+		// walk adds explicit OBREAK nodes to the end of all reachable code paths.
+		// If we still have a current block here, then mark it unreachable.
+		if s.curBlock != nil {
+			m := s.mem()
+			b := s.endBlock()
+			b.Kind = ssa.BlockExit
+			b.SetControl(m)
 		}
 		s.startBlock(bEnd)
 
@@ -944,23 +922,20 @@ func (s *state) stmt(n *Node) {
 		// 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())
+			s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, n.Left, s.mem())
 		}
 
 	case OVARLIVE:
 		// Insert a varlive op to record that a variable is still live.
-		if !n.Left.Addrtaken {
+		if !n.Left.Addrtaken() {
 			s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
 		}
-		s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
 
 	case OCHECKNIL:
 		p := s.expr(n.Left)
 		s.nilCheck(p)
 
-	case OSQRT:
-		s.expr(n.Left)
-
 	default:
 		s.Fatalf("unhandled stmt %v", n.Op)
 	}
@@ -970,7 +945,7 @@ func (s *state) stmt(n *Node) {
 // 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 {
+	if s.hasdefer {
 		s.rtcall(Deferreturn, true, nil)
 	}
 
@@ -982,8 +957,8 @@ func (s *state) exit() *ssa.Block {
 	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())
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem())
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, n.Type, 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.
@@ -999,7 +974,7 @@ func (s *state) exit() *ssa.Block {
 
 type opAndType struct {
 	op    Op
-	etype EType
+	etype types.EType
 }
 
 var opToSSA = map[opAndType]ssa.Op{
@@ -1068,13 +1043,6 @@ var opToSSA = map[opAndType]ssa.Op{
 	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,
@@ -1205,27 +1173,20 @@ var opToSSA = map[opAndType]ssa.Op{
 	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 {
+func (s *state) concreteEtype(t *types.Type) types.EType {
 	e := t.Etype
 	switch e {
 	default:
 		return e
 	case TINT:
-		if s.config.IntSize == 8 {
+		if s.config.PtrSize == 8 {
 			return TINT64
 		}
 		return TINT32
 	case TUINT:
-		if s.config.IntSize == 8 {
+		if s.config.PtrSize == 8 {
 			return TUINT64
 		}
 		return TUINT32
@@ -1237,7 +1198,7 @@ func (s *state) concreteEtype(t *Type) EType {
 	}
 }
 
-func (s *state) ssaOp(op Op, t *Type) ssa.Op {
+func (s *state) ssaOp(op Op, t *types.Type) ssa.Op {
 	etype := s.concreteEtype(t)
 	x, ok := opToSSA[opAndType{op, etype}]
 	if !ok {
@@ -1246,29 +1207,29 @@ func (s *state) ssaOp(op Op, t *Type) ssa.Op {
 	return x
 }
 
-func floatForComplex(t *Type) *Type {
+func floatForComplex(t *types.Type) *types.Type {
 	if t.Size() == 8 {
-		return Types[TFLOAT32]
+		return types.Types[TFLOAT32]
 	} else {
-		return Types[TFLOAT64]
+		return types.Types[TFLOAT64]
 	}
 }
 
 type opAndTwoTypes struct {
 	op     Op
-	etype1 EType
-	etype2 EType
+	etype1 types.EType
+	etype2 types.EType
 }
 
 type twoTypes struct {
-	etype1 EType
-	etype2 EType
+	etype1 types.EType
+	etype2 types.EType
 }
 
 type twoOpsAndType struct {
 	op1              ssa.Op
 	op2              ssa.Op
-	intermediateType EType
+	intermediateType types.EType
 }
 
 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
@@ -1315,8 +1276,8 @@ var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
 
 	// 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{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpRound64F, ssa.OpCopy, TFLOAT64},
+	twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpRound32F, ssa.OpCopy, TFLOAT32},
 	twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
 }
 
@@ -1411,7 +1372,7 @@ var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
 	opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
 }
 
-func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
+func (s *state) ssaShiftOp(op Op, t *types.Type, u *types.Type) ssa.Op {
 	etype1 := s.concreteEtype(t)
 	etype2 := s.concreteEtype(u)
 	x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
@@ -1421,21 +1382,12 @@ func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
 	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.Fatalf("unhandled rotate op %v 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)
+		s.pushLine(n.Pos)
 		defer s.popLine()
 	}
 
@@ -1443,31 +1395,31 @@ func (s *state) expr(n *Node) *ssa.Value {
 	switch n.Op {
 	case OARRAYBYTESTRTMP:
 		slice := s.expr(n.Left)
-		ptr := s.newValue1(ssa.OpSlicePtr, ptrto(Types[TUINT8]), slice)
-		len := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
+		ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
+		len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
 		return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
 	case OSTRARRAYBYTETMP:
 		str := s.expr(n.Left)
-		ptr := s.newValue1(ssa.OpStringPtr, ptrto(Types[TUINT8]), str)
-		len := s.newValue1(ssa.OpStringLen, Types[TINT], str)
+		ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str)
+		len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str)
 		return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len)
 	case OCFUNC:
-		aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
+		aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: n.Left.Sym.Linksym()})
 		return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
 	case ONAME:
-		if n.Class == PFUNC {
+		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)
+			sym := funcsym(n.Sym).Linksym()
+			aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: sym})
+			return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), aux, s.sb)
 		}
 		if s.canSSA(n) {
 			return s.variable(n, n.Type)
 		}
-		addr, _ := s.addr(n, false)
+		addr := s.addr(n, false)
 		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
 	case OCLOSUREVAR:
-		addr, _ := s.addr(n, false)
+		addr := s.addr(n, false)
 		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
 	case OLITERAL:
 		switch u := n.Val().U.(type) {
@@ -1518,12 +1470,12 @@ func (s *state) expr(n *Node) *ssa.Value {
 			i := &u.Imag
 			switch n.Type.Size() {
 			case 8:
-				pt := Types[TFLOAT32]
+				pt := types.Types[TFLOAT32]
 				return s.newValue2(ssa.OpComplexMake, n.Type,
 					s.constFloat32(pt, r.Float32()),
 					s.constFloat32(pt, i.Float32()))
 			case 16:
-				pt := Types[TFLOAT64]
+				pt := types.Types[TFLOAT64]
 				return s.newValue2(ssa.OpComplexMake, n.Type,
 					s.constFloat64(pt, r.Float64()),
 					s.constFloat64(pt, i.Float64()))
@@ -1599,6 +1551,10 @@ func (s *state) expr(n *Node) *ssa.Value {
 		x := s.expr(n.Left)
 		ft := n.Left.Type // from type
 		tt := n.Type      // to type
+		if ft.IsBoolean() && tt.IsKind(TUINT8) {
+			// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
+			return s.newValue1(ssa.OpCopy, n.Type, x)
+		}
 		if ft.IsInteger() && tt.IsInteger() {
 			var op ssa.Op
 			if tt.Size() == ft.Size() {
@@ -1663,18 +1619,18 @@ func (s *state) expr(n *Node) *ssa.Value {
 
 		if ft.IsFloat() || tt.IsFloat() {
 			conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
-			if s.config.IntSize == 4 && Thearch.LinkArch.Name != "amd64p32" && Thearch.LinkArch.Family != sys.MIPS {
+			if s.config.RegSize == 4 && thearch.LinkArch.Family != sys.MIPS {
 				if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
 					conv = conv1
 				}
 			}
-			if Thearch.LinkArch.Name == "arm64" {
+			if thearch.LinkArch.Family == sys.ARM64 {
 				if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
 					conv = conv1
 				}
 			}
 
-			if Thearch.LinkArch.Family == sys.MIPS {
+			if thearch.LinkArch.Family == sys.MIPS {
 				if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
 					// tt is float32 or float64, and ft is also unsigned
 					if tt.Size() == 4 {
@@ -1710,7 +1666,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 				if op2 == ssa.OpCopy {
 					return s.newValue1(op1, n.Type, x)
 				}
-				return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
+				return s.newValue1(op2, n.Type, s.newValue1(op1, types.Types[it], x))
 			}
 			// Tricky 64-bit unsigned cases.
 			if ft.IsInteger() {
@@ -1737,7 +1693,14 @@ func (s *state) expr(n *Node) *ssa.Value {
 		if ft.IsComplex() && tt.IsComplex() {
 			var op ssa.Op
 			if ft.Size() == tt.Size() {
-				op = ssa.OpCopy
+				switch ft.Size() {
+				case 8:
+					op = ssa.OpRound32F
+				case 16:
+					op = ssa.OpRound64F
+				default:
+					s.Fatalf("weird complex conversion %v -> %v", ft, tt)
+				}
 			} else if ft.Size() == 8 && tt.Size() == 16 {
 				op = ssa.OpCvt32Fto64F
 			} else if ft.Size() == 16 && tt.Size() == 8 {
@@ -1766,19 +1729,19 @@ func (s *state) expr(n *Node) *ssa.Value {
 		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.OpAndB, Types[TBOOL], r, i)
+			r := s.newValue2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
+			i := s.newValue2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
+			c := s.newValue2(ssa.OpAndB, types.Types[TBOOL], r, i)
 			switch n.Op {
 			case OEQ:
 				return c
 			case ONE:
-				return s.newValue1(ssa.OpNot, Types[TBOOL], c)
+				return s.newValue1(ssa.OpNot, types.Types[TBOOL], c)
 			default:
 				s.Fatalf("ordered complex compare %v", n.Op)
 			}
 		}
-		return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
+		return s.newValue2(s.ssaOp(n.Op, n.Left.Type), types.Types[TBOOL], a, b)
 	case OMUL:
 		a := s.expr(n.Left)
 		b := s.expr(n.Right)
@@ -1787,7 +1750,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 			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
+			wt := types.Types[TFLOAT64]   // Compute in Float64 to minimize cancelation error
 
 			areal := s.newValue1(ssa.OpComplexReal, pt, a)
 			breal := s.newValue1(ssa.OpComplexReal, pt, b)
@@ -1825,7 +1788,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 			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
+			wt := types.Types[TFLOAT64]   // Compute in Float64 to minimize cancelation error
 
 			areal := s.newValue1(ssa.OpComplexReal, pt, a)
 			breal := s.newValue1(ssa.OpComplexReal, pt, b)
@@ -1875,7 +1838,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 				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:
+	case OAND, OOR, OXOR:
 		a := s.expr(n.Left)
 		b := s.expr(n.Right)
 		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
@@ -1883,13 +1846,6 @@ func (s *state) expr(n *Node) *ssa.Value {
 		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
@@ -1933,7 +1889,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 		b.AddEdgeTo(bResult)
 
 		s.startBlock(bResult)
-		return s.variable(n, Types[TBOOL])
+		return s.variable(n, types.Types[TBOOL])
 	case OCOMPLEX:
 		r := s.expr(n.Left)
 		i := s.expr(n.Right)
@@ -1950,7 +1906,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 				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:
+	case ONOT, OCOM:
 		a := s.expr(n.Left)
 		return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
 	case OIMAG, OREAL:
@@ -1960,16 +1916,14 @@ func (s *state) expr(n *Node) *ssa.Value {
 		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
+		return s.addr(n.Left, n.Bounded())
 
 	case OINDREGSP:
-		addr := s.entryNewValue1I(ssa.OpOffPtr, ptrto(n.Type), n.Xoffset, s.sp)
+		addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
 		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
 
 	case OIND:
-		p := s.exprPtr(n.Left, false, n.Lineno)
+		p := s.exprPtr(n.Left, false, n.Pos)
 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
 
 	case ODOT:
@@ -1978,40 +1932,49 @@ func (s *state) expr(n *Node) *ssa.Value {
 			v := s.expr(n.Left)
 			return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
 		}
-		p, _ := s.addr(n, false)
+		if n.Left.Op == OSTRUCTLIT {
+			// 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(n.Left) {
+				Fatalf("literal with nonzero value in SSA: %v", n.Left)
+			}
+			return s.zeroVal(n.Type)
+		}
+		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)
+		p := s.exprPtr(n.Left, false, n.Pos)
+		p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type), n.Xoffset, p)
 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
 
 	case OINDEX:
 		switch {
 		case n.Left.Type.IsString():
-			if n.Bounded && Isconst(n.Left, CTSTR) && Isconst(n.Right, CTINT) {
+			if n.Bounded() && Isconst(n.Left, CTSTR) && Isconst(n.Right, CTINT) {
 				// Replace "abc"[1] with 'b'.
 				// Delayed until now because "abc"[1] is not an ideal constant.
 				// See test/fixedbugs/issue11370.go.
-				return s.newValue0I(ssa.OpConst8, Types[TUINT8], int64(int8(n.Left.Val().U.(string)[n.Right.Int64()])))
+				return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.Val().U.(string)[n.Right.Int64()])))
 			}
 			a := s.expr(n.Left)
 			i := s.expr(n.Right)
 			i = s.extendIndex(i, panicindex)
-			if !n.Bounded {
-				len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
+			if !n.Bounded() {
+				len := s.newValue1(ssa.OpStringLen, types.Types[TINT], a)
 				s.boundsCheck(i, len)
 			}
-			ptrtyp := ptrto(Types[TUINT8])
+			ptrtyp := s.f.Config.Types.BytePtr
 			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())
+			return s.newValue2(ssa.OpLoad, types.Types[TUINT8], ptr, s.mem())
 		case n.Left.Type.IsSlice():
-			p, _ := s.addr(n, false)
+			p := s.addr(n, false)
 			return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
 		case n.Left.Type.IsArray():
 			if bound := n.Left.Type.NumElem(); bound <= 1 {
@@ -2021,16 +1984,18 @@ func (s *state) expr(n *Node) *ssa.Value {
 				if bound == 0 {
 					// Bounds check will never succeed.  Might as well
 					// use constants for the bounds check.
-					z := s.constInt(Types[TINT], 0)
+					z := s.constInt(types.Types[TINT], 0)
 					s.boundsCheck(z, z)
 					// The return value won't be live, return junk.
 					return s.newValue0(ssa.OpUnknown, n.Type)
 				}
 				i = s.extendIndex(i, panicindex)
-				s.boundsCheck(i, s.constInt(Types[TINT], bound))
+				if !n.Bounded() {
+					s.boundsCheck(i, s.constInt(types.Types[TINT], bound))
+				}
 				return s.newValue1I(ssa.OpArraySelect, n.Type, 0, a)
 			}
-			p, _ := s.addr(n, false)
+			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)
@@ -2044,13 +2009,13 @@ func (s *state) expr(n *Node) *ssa.Value {
 			if n.Op == OCAP {
 				op = ssa.OpSliceCap
 			}
-			return s.newValue1(op, Types[TINT], s.expr(n.Left))
+			return s.newValue1(op, types.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))
+			return s.newValue1(ssa.OpStringLen, types.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())
+			return s.constInt(types.Types[TINT], n.Left.Type.NumElem())
 		}
 
 	case OSPTR:
@@ -2119,6 +2084,15 @@ func (s *state) expr(n *Node) *ssa.Value {
 	case OAPPEND:
 		return s.append(n, false)
 
+	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(n) {
+			Fatalf("literal with nonzero value in SSA: %v", n)
+		}
+		return s.zeroVal(n.Type)
+
 	default:
 		s.Fatalf("unhandled expr %v", n.Op)
 		return nil
@@ -2166,14 +2140,14 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
 	// *(ptr+len+2) = e3
 
 	et := n.Type.Elem()
-	pt := ptrto(et)
+	pt := types.NewPtr(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)
+		addr = s.addr(sn, false)
 		slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
 	} else {
 		slice = s.expr(sn)
@@ -2186,11 +2160,11 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
 	// 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))
+	l := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
+	c := s.newValue1(ssa.OpSliceCap, types.Types[TINT], slice)
+	nl := s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
 
-	cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
+	cmp := s.newValue2(s.ssaOp(OGT, types.Types[TINT]), types.Types[TBOOL], nl, c)
 	s.vars[&ptrVar] = p
 
 	if !inplace {
@@ -2209,28 +2183,23 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
 
 	// 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)
+	taddr := s.expr(n.Left)
+	r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.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())
-		if ssa.IsStackAddr(addr) {
-			s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, pt.Size(), addr, r[0], s.mem())
-		} else {
-			s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
+			s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
 		}
+		capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, int64(array_cap), addr)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], capaddr, r[2], s.mem())
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, pt, addr, r[0], s.mem())
 		// 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[&newlenVar] = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], r[1], s.constInt(types.Types[TINT], nargs))
 		s.vars[&capVar] = r[2]
 	}
 
@@ -2241,53 +2210,43 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
 	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())
+		l = s.variable(&lenVar, types.Types[TINT]) // generates phi for len
+		nl = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
+		lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, int64(array_nel), addr)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], 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
+		// value at *v.
+		v     *ssa.Value
+		store 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})
+			v := s.addr(n, false)
+			args = append(args, argRec{v: v})
 		}
 	}
 
 	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
+		nl = s.variable(&newlenVar, types.Types[TINT]) // generates phi for nl
+		c = s.variable(&capVar, types.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)))
+		addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.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())
-			}
+			s.storeType(et, addr, arg.v, 0)
 		} else {
-			if haspointers(et) {
-				s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile)
-			} else {
-				s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(et), addr, arg.v, s.mem())
-			}
+			store := s.newValue3I(ssa.OpMove, types.TypeMem, et.Size(), addr, arg.v, s.mem())
+			store.Aux = et
+			s.vars[&memVar] = store
 		}
 	}
 
@@ -2358,10 +2317,8 @@ const (
 // 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) {
+func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) {
 	if left.Op == ONAME && isblank(left) {
 		return
 	}
@@ -2402,7 +2359,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
 			}
 
 			// 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)
+			s.assign(left.Left, new, false, 0)
 			// TODO: do we need to update named values here?
 			return
 		}
@@ -2416,7 +2373,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
 			if n == 0 {
 				// The bounds check must fail.  Might as well
 				// ignore the actual index and just use zeros.
-				z := s.constInt(Types[TINT], 0)
+				z := s.constInt(types.Types[TINT], 0)
 				s.boundsCheck(z, z)
 				return
 			}
@@ -2425,9 +2382,9 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
 			}
 			// Rewrite to a = [1]{v}
 			i = s.extendIndex(i, panicindex)
-			s.boundsCheck(i, s.constInt(Types[TINT], 1))
+			s.boundsCheck(i, s.constInt(types.Types[TINT], 1))
 			v := s.newValue1(ssa.OpArrayMake1, t, right)
-			s.assign(left.Left, v, false, false, line, 0, rightIsVolatile)
+			s.assign(left.Left, v, false, 0)
 			return
 		}
 		// Update variable assignment.
@@ -2436,46 +2393,36 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
 		return
 	}
 	// Left is not ssa-able. Compute its address.
-	addr, _ := s.addr(left, false)
+	addr := s.addr(left, false)
 	if left.Op == ONAME && skip == 0 {
-		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, left, s.mem())
+	}
+	if isReflectHeaderDataField(left) {
+		// Package unsafe's documentation says storing pointers into
+		// reflect.SliceHeader and reflect.StringHeader's Data fields
+		// is valid, even though they have type uintptr (#19168).
+		// Mark it pointer type to signal the writebarrier pass to
+		// insert a write barrier.
+		t = types.Types[TUNSAFEPTR]
 	}
 	if deref {
 		// Treat as a mem->mem move.
-		if wb && !ssa.IsStackAddr(addr) {
-			s.insertWBmove(t, addr, right, line, rightIsVolatile)
-			return
-		}
+		var store *ssa.Value
 		if right == nil {
-			s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, sizeAlignAuxInt(t), addr, s.mem())
-			return
+			store = s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), addr, s.mem())
+		} else {
+			store = s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), addr, right, s.mem())
 		}
-		s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(t), addr, right, s.mem())
+		store.Aux = t
+		s.vars[&memVar] = store
 		return
 	}
 	// Treat as a store.
-	if wb && !ssa.IsStackAddr(addr) {
-		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())
+	s.storeType(t, addr, right, skip)
 }
 
 // zeroVal returns the zero value for type t.
-func (s *state) zeroVal(t *Type) *ssa.Value {
+func (s *state) zeroVal(t *types.Type) *ssa.Value {
 	switch {
 	case t.IsInteger():
 		switch t.Size() {
@@ -2502,10 +2449,10 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
 	case t.IsComplex():
 		switch t.Size() {
 		case 8:
-			z := s.constFloat32(Types[TFLOAT32], 0)
+			z := s.constFloat32(types.Types[TFLOAT32], 0)
 			return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
 		case 16:
-			z := s.constFloat64(Types[TFLOAT64], 0)
+			z := s.constFloat64(types.Types[TFLOAT64], 0)
 			return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
 		default:
 			s.Fatalf("bad sized complex type %v", t)
@@ -2525,7 +2472,7 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
 		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)))
+			v.AddArg(s.zeroVal(t.FieldType(i)))
 		}
 		return v
 	case t.IsArray():
@@ -2548,293 +2495,484 @@ const (
 	callGo
 )
 
-// TODO: make this a field of a configuration object instead of a global.
-var intrinsics *intrinsicInfo
-
-type intrinsicInfo struct {
-	std      map[intrinsicKey]intrinsicBuilder
-	intSized map[sizedIntrinsicKey]intrinsicBuilder
-	ptrSized map[sizedIntrinsicKey]intrinsicBuilder
-}
+var intrinsics map[intrinsicKey]intrinsicBuilder
 
 // An intrinsicBuilder converts a call node n into an ssa value that
 // implements that call as an intrinsic. args is a list of arguments to the func.
 type intrinsicBuilder func(s *state, n *Node, args []*ssa.Value) *ssa.Value
 
 type intrinsicKey struct {
-	pkg string
-	fn  string
-}
-
-type sizedIntrinsicKey struct {
+	arch *sys.Arch
 	pkg  string
 	fn   string
-	size int
 }
 
-// disableForInstrumenting returns nil when instrumenting, fn otherwise
-func disableForInstrumenting(fn intrinsicBuilder) intrinsicBuilder {
-	if instrumenting {
-		return nil
+func init() {
+	intrinsics = map[intrinsicKey]intrinsicBuilder{}
+
+	var all []*sys.Arch
+	var p4 []*sys.Arch
+	var p8 []*sys.Arch
+	for _, a := range sys.Archs {
+		all = append(all, a)
+		if a.PtrSize == 4 {
+			p4 = append(p4, a)
+		} else {
+			p8 = append(p8, a)
+		}
 	}
-	return fn
-}
 
-// enableOnArch returns fn on given archs, nil otherwise
-func enableOnArch(fn intrinsicBuilder, archs ...sys.ArchFamily) intrinsicBuilder {
-	if Thearch.LinkArch.InFamily(archs...) {
-		return fn
+	// add adds the intrinsic b for pkg.fn for the given list of architectures.
+	add := func(pkg, fn string, b intrinsicBuilder, archs ...*sys.Arch) {
+		for _, a := range archs {
+			intrinsics[intrinsicKey{a, pkg, fn}] = b
+		}
+	}
+	// addF does the same as add but operates on architecture families.
+	addF := func(pkg, fn string, b intrinsicBuilder, archFamilies ...sys.ArchFamily) {
+		m := 0
+		for _, f := range archFamilies {
+			if f >= 32 {
+				panic("too many architecture families")
+			}
+			m |= 1 << uint(f)
+		}
+		for _, a := range all {
+			if m>>uint(a.Family)&1 != 0 {
+				intrinsics[intrinsicKey{a, pkg, fn}] = b
+			}
+		}
+	}
+	// alias defines pkg.fn = pkg2.fn2 for all architectures in archs for which pkg2.fn2 exists.
+	alias := func(pkg, fn, pkg2, fn2 string, archs ...*sys.Arch) {
+		for _, a := range archs {
+			if b, ok := intrinsics[intrinsicKey{a, pkg2, fn2}]; ok {
+				intrinsics[intrinsicKey{a, pkg, fn}] = b
+			}
+		}
 	}
-	return nil
-}
 
-func intrinsicInit() {
-	i := &intrinsicInfo{}
-	intrinsics = i
-
-	// initial set of intrinsics.
-	i.std = map[intrinsicKey]intrinsicBuilder{
-		/******** runtime ********/
-		intrinsicKey{"runtime", "slicebytetostringtmp"}: disableForInstrumenting(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			// Compiler frontend optimizations emit OARRAYBYTESTRTMP nodes
-			// for the backend instead of slicebytetostringtmp calls
-			// when not instrumenting.
-			slice := args[0]
-			ptr := s.newValue1(ssa.OpSlicePtr, ptrto(Types[TUINT8]), slice)
-			len := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
-			return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
-		}),
-		intrinsicKey{"runtime", "KeepAlive"}: func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			data := s.newValue1(ssa.OpIData, ptrto(Types[TUINT8]), args[0])
-			s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, data, s.mem())
+	/******** runtime ********/
+	if !instrumenting {
+		add("runtime", "slicebytetostringtmp",
+			func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+				// Compiler frontend optimizations emit OARRAYBYTESTRTMP nodes
+				// for the backend instead of slicebytetostringtmp calls
+				// when not instrumenting.
+				slice := args[0]
+				ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
+				len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
+				return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
+			},
+			all...)
+	}
+	add("runtime", "KeepAlive",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
+			s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, types.TypeMem, data, s.mem())
 			return nil
 		},
+		all...)
 
-		/******** runtime/internal/sys ********/
-		intrinsicKey{"runtime/internal/sys", "Ctz32"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue1(ssa.OpCtz32, Types[TUINT32], args[0])
-		}, sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/sys", "Ctz64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue1(ssa.OpCtz64, Types[TUINT64], args[0])
-		}, sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/sys", "Bswap32"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue1(ssa.OpBswap32, Types[TUINT32], args[0])
-		}, sys.AMD64, sys.ARM64, sys.ARM, sys.S390X),
-		intrinsicKey{"runtime/internal/sys", "Bswap64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue1(ssa.OpBswap64, Types[TUINT64], args[0])
-		}, sys.AMD64, sys.ARM64, sys.ARM, sys.S390X),
-
-		/******** runtime/internal/atomic ********/
-		intrinsicKey{"runtime/internal/atomic", "Load"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue2(ssa.OpAtomicLoad32, ssa.MakeTuple(Types[TUINT32], ssa.TypeMem), args[0], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT32], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Load64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue2(ssa.OpAtomicLoad64, ssa.MakeTuple(Types[TUINT64], ssa.TypeMem), args[0], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT64], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X),
-		intrinsicKey{"runtime/internal/atomic", "Loadp"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue2(ssa.OpAtomicLoadPtr, ssa.MakeTuple(ptrto(Types[TUINT8]), ssa.TypeMem), args[0], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, ptrto(Types[TUINT8]), v)
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-
-		intrinsicKey{"runtime/internal/atomic", "Store"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore32, ssa.TypeMem, args[0], args[1], s.mem())
+	/******** runtime/internal/sys ********/
+	addF("runtime/internal/sys", "Ctz32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS)
+	addF("runtime/internal/sys", "Ctz64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS)
+	addF("runtime/internal/sys", "Bswap32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBswap32, types.Types[TUINT32], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
+	addF("runtime/internal/sys", "Bswap64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBswap64, types.Types[TUINT64], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
+
+	/******** runtime/internal/atomic ********/
+	addF("runtime/internal/atomic", "Load",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+
+	addF("runtime/internal/atomic", "Load64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64)
+	addF("runtime/internal/atomic", "Loadp",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, s.f.Config.Types.BytePtr, v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+
+	addF("runtime/internal/atomic", "Store",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore32, types.TypeMem, args[0], args[1], s.mem())
 			return nil
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Store64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore64, ssa.TypeMem, args[0], args[1], s.mem())
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("runtime/internal/atomic", "Store64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem())
 			return nil
-		}, sys.AMD64, sys.ARM64, sys.S390X),
-		intrinsicKey{"runtime/internal/atomic", "StorepNoWB"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, ssa.TypeMem, args[0], args[1], s.mem())
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64)
+	addF("runtime/internal/atomic", "StorepNoWB",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			s.vars[&memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, types.TypeMem, args[0], args[1], s.mem())
 			return nil
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-
-		intrinsicKey{"runtime/internal/atomic", "Xchg"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue3(ssa.OpAtomicExchange32, ssa.MakeTuple(Types[TUINT32], ssa.TypeMem), args[0], args[1], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT32], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Xchg64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue3(ssa.OpAtomicExchange64, ssa.MakeTuple(Types[TUINT64], ssa.TypeMem), args[0], args[1], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT64], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X),
-
-		intrinsicKey{"runtime/internal/atomic", "Xadd"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue3(ssa.OpAtomicAdd32, ssa.MakeTuple(Types[TUINT32], ssa.TypeMem), args[0], args[1], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT32], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Xadd64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue3(ssa.OpAtomicAdd64, ssa.MakeTuple(Types[TUINT64], ssa.TypeMem), args[0], args[1], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TUINT64], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X),
-
-		intrinsicKey{"runtime/internal/atomic", "Cas"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue4(ssa.OpAtomicCompareAndSwap32, ssa.MakeTuple(Types[TBOOL], ssa.TypeMem), args[0], args[1], args[2], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TBOOL], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Cas64"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			v := s.newValue4(ssa.OpAtomicCompareAndSwap64, ssa.MakeTuple(Types[TBOOL], ssa.TypeMem), args[0], args[1], args[2], s.mem())
-			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, ssa.TypeMem, v)
-			return s.newValue1(ssa.OpSelect0, Types[TBOOL], v)
-		}, sys.AMD64, sys.ARM64, sys.S390X),
-
-		intrinsicKey{"runtime/internal/atomic", "And8"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, ssa.TypeMem, args[0], args[1], s.mem())
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS)
+
+	addF("runtime/internal/atomic", "Xchg",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("runtime/internal/atomic", "Xchg64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64)
+
+	addF("runtime/internal/atomic", "Xadd",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("runtime/internal/atomic", "Xadd64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64)
+
+	addF("runtime/internal/atomic", "Cas",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("runtime/internal/atomic", "Cas64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+			s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+			return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64)
+
+	addF("runtime/internal/atomic", "And8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
 			return nil
-		}, sys.AMD64, sys.ARM64, sys.MIPS),
-		intrinsicKey{"runtime/internal/atomic", "Or8"}: enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, ssa.TypeMem, args[0], args[1], s.mem())
+		},
+		sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64)
+	addF("runtime/internal/atomic", "Or8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
 			return nil
-		}, sys.AMD64, sys.ARM64, sys.MIPS),
-	}
-
-	// aliases internal to runtime/internal/atomic
-	i.std[intrinsicKey{"runtime/internal/atomic", "Loadint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}]
-	i.std[intrinsicKey{"runtime/internal/atomic", "Xaddint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd64"}]
-
-	// intrinsics which vary depending on the size of int/ptr.
-	i.intSized = map[sizedIntrinsicKey]intrinsicBuilder{
-		sizedIntrinsicKey{"runtime/internal/atomic", "Loaduint", 4}: i.std[intrinsicKey{"runtime/internal/atomic", "Load"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Loaduint", 8}: i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}],
-	}
-	i.ptrSized = map[sizedIntrinsicKey]intrinsicBuilder{
-		sizedIntrinsicKey{"runtime/internal/atomic", "Loaduintptr", 4}:  i.std[intrinsicKey{"runtime/internal/atomic", "Load"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Loaduintptr", 8}:  i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Storeuintptr", 4}: i.std[intrinsicKey{"runtime/internal/atomic", "Store"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Storeuintptr", 8}: i.std[intrinsicKey{"runtime/internal/atomic", "Store64"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Xchguintptr", 4}:  i.std[intrinsicKey{"runtime/internal/atomic", "Xchg"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Xchguintptr", 8}:  i.std[intrinsicKey{"runtime/internal/atomic", "Xchg64"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Xadduintptr", 4}:  i.std[intrinsicKey{"runtime/internal/atomic", "Xadd"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Xadduintptr", 8}:  i.std[intrinsicKey{"runtime/internal/atomic", "Xadd64"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Casuintptr", 4}:   i.std[intrinsicKey{"runtime/internal/atomic", "Cas"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Casuintptr", 8}:   i.std[intrinsicKey{"runtime/internal/atomic", "Cas64"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Casp1", 4}:        i.std[intrinsicKey{"runtime/internal/atomic", "Cas"}],
-		sizedIntrinsicKey{"runtime/internal/atomic", "Casp1", 8}:        i.std[intrinsicKey{"runtime/internal/atomic", "Cas64"}],
+		},
+		sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64)
+
+	alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
+	alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
+	alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load", p4...)
+	alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load64", p8...)
+	alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
+	alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
+	alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
+	alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
+	alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
+	alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
+	alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
+	alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd64", p8...)
+	alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas", p4...)
+	alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas64", p8...)
+	alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas", p4...)
+	alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas64", p8...)
+
+	/******** math ********/
+	addF("math", "Sqrt",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpSqrt, types.Types[TFLOAT64], args[0])
+		},
+		sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
+
+	/******** math/bits ********/
+	addF("math/bits", "TrailingZeros64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("math/bits", "TrailingZeros32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("math/bits", "TrailingZeros16",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
+			c := s.constInt32(types.Types[TUINT32], 1<<16)
+			y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
+			return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+		},
+		sys.ARM, sys.MIPS)
+	addF("math/bits", "TrailingZeros16",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
+			c := s.constInt64(types.Types[TUINT64], 1<<16)
+			y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
+			return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X)
+	addF("math/bits", "TrailingZeros8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
+			c := s.constInt32(types.Types[TUINT32], 1<<8)
+			y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
+			return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+		},
+		sys.ARM, sys.MIPS)
+	addF("math/bits", "TrailingZeros8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
+			c := s.constInt64(types.Types[TUINT64], 1<<8)
+			y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
+			return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+		},
+		sys.AMD64, sys.ARM64, sys.S390X)
+	alias("math/bits", "ReverseBytes64", "runtime/internal/sys", "Bswap64", all...)
+	alias("math/bits", "ReverseBytes32", "runtime/internal/sys", "Bswap32", all...)
+	// ReverseBytes inlines correctly, no need to intrinsify it.
+	// ReverseBytes16 lowers to a rotate, no need for anything special here.
+	addF("math/bits", "Len64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("math/bits", "Len32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			if s.config.PtrSize == 4 {
+				return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+			}
+			x := s.newValue1(ssa.OpZeroExt32to64, types.Types[TUINT64], args[0])
+			return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	addF("math/bits", "Len16",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			if s.config.PtrSize == 4 {
+				x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
+				return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+			}
+			x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
+			return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	// Note: disabled on AMD64 because the Go code is faster!
+	addF("math/bits", "Len8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			if s.config.PtrSize == 4 {
+				x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
+				return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+			}
+			x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
+			return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+		},
+		sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+
+	addF("math/bits", "Len",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			if s.config.PtrSize == 4 {
+				return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+			}
+			return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+		},
+		sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+	// LeadingZeros is handled because it trivially calls Len.
+	addF("math/bits", "Reverse64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+		},
+		sys.ARM64)
+	addF("math/bits", "Reverse32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+		},
+		sys.ARM64)
+	addF("math/bits", "Reverse16",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBitRev16, types.Types[TINT], args[0])
+		},
+		sys.ARM64)
+	addF("math/bits", "Reverse8",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpBitRev8, types.Types[TINT], args[0])
+		},
+		sys.ARM64)
+	addF("math/bits", "Reverse",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			if s.config.PtrSize == 4 {
+				return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+			}
+			return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+		},
+		sys.ARM64)
+	makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+		return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: syslook("support_popcnt").Sym.Linksym()})
+			addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), aux, s.sb)
+			v := s.newValue2(ssa.OpLoad, types.Types[TBOOL], addr, s.mem())
+			b := s.endBlock()
+			b.Kind = ssa.BlockIf
+			b.SetControl(v)
+			bTrue := s.f.NewBlock(ssa.BlockPlain)
+			bFalse := s.f.NewBlock(ssa.BlockPlain)
+			bEnd := s.f.NewBlock(ssa.BlockPlain)
+			b.AddEdgeTo(bTrue)
+			b.AddEdgeTo(bFalse)
+			b.Likely = ssa.BranchLikely // most machines have popcnt nowadays
+
+			// We have the intrinsic - use it directly.
+			s.startBlock(bTrue)
+			op := op64
+			if s.config.PtrSize == 4 {
+				op = op32
+			}
+			s.vars[n] = s.newValue1(op, types.Types[TINT], args[0])
+			s.endBlock().AddEdgeTo(bEnd)
+
+			// Call the pure Go version.
+			s.startBlock(bFalse)
+			a := s.call(n, callNormal)
+			s.vars[n] = s.newValue2(ssa.OpLoad, types.Types[TINT], a, s.mem())
+			s.endBlock().AddEdgeTo(bEnd)
+
+			// Merge results.
+			s.startBlock(bEnd)
+			return s.variable(n, types.Types[TINT])
+		}
 	}
+	addF("math/bits", "OnesCount64",
+		makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64),
+		sys.AMD64)
+	addF("math/bits", "OnesCount64",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpPopCount64, types.Types[TINT], args[0])
+		},
+		sys.PPC64)
+	addF("math/bits", "OnesCount32",
+		makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32),
+		sys.AMD64)
+	addF("math/bits", "OnesCount32",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue1(ssa.OpPopCount32, types.Types[TINT], args[0])
+		},
+		sys.PPC64)
+	addF("math/bits", "OnesCount16",
+		makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16),
+		sys.AMD64)
+	// Note: no OnesCount8, the Go implementation is faster - just a table load.
+	addF("math/bits", "OnesCount",
+		makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
+		sys.AMD64)
 
 	/******** sync/atomic ********/
-	if flag_race {
-		// The race detector needs to be able to intercept these calls.
-		// We can't intrinsify them.
-		return
-	}
-	// these are all aliases to runtime/internal/atomic implementations.
-	i.std[intrinsicKey{"sync/atomic", "LoadInt32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load"}]
-	i.std[intrinsicKey{"sync/atomic", "LoadInt64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}]
-	i.std[intrinsicKey{"sync/atomic", "LoadPointer"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Loadp"}]
-	i.std[intrinsicKey{"sync/atomic", "LoadUint32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load"}]
-	i.std[intrinsicKey{"sync/atomic", "LoadUint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "LoadUintptr", 4}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "LoadUintptr", 8}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Load64"}]
-
-	i.std[intrinsicKey{"sync/atomic", "StoreInt32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store"}]
-	i.std[intrinsicKey{"sync/atomic", "StoreInt64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store64"}]
+
+	// Note: these are disabled by flag_race in findIntrinsic below.
+	alias("sync/atomic", "LoadInt32", "runtime/internal/atomic", "Load", all...)
+	alias("sync/atomic", "LoadInt64", "runtime/internal/atomic", "Load64", all...)
+	alias("sync/atomic", "LoadPointer", "runtime/internal/atomic", "Loadp", all...)
+	alias("sync/atomic", "LoadUint32", "runtime/internal/atomic", "Load", all...)
+	alias("sync/atomic", "LoadUint64", "runtime/internal/atomic", "Load64", all...)
+	alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load", p4...)
+	alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load64", p8...)
+
+	alias("sync/atomic", "StoreInt32", "runtime/internal/atomic", "Store", all...)
+	alias("sync/atomic", "StoreInt64", "runtime/internal/atomic", "Store64", all...)
 	// Note: not StorePointer, that needs a write barrier.  Same below for {CompareAnd}Swap.
-	i.std[intrinsicKey{"sync/atomic", "StoreUint32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store"}]
-	i.std[intrinsicKey{"sync/atomic", "StoreUint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store64"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "StoreUintptr", 4}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "StoreUintptr", 8}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Store64"}]
-
-	i.std[intrinsicKey{"sync/atomic", "SwapInt32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg"}]
-	i.std[intrinsicKey{"sync/atomic", "SwapInt64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg64"}]
-	i.std[intrinsicKey{"sync/atomic", "SwapUint32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg"}]
-	i.std[intrinsicKey{"sync/atomic", "SwapUint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg64"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "SwapUintptr", 4}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "SwapUintptr", 8}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xchg64"}]
-
-	i.std[intrinsicKey{"sync/atomic", "CompareAndSwapInt32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas"}]
-	i.std[intrinsicKey{"sync/atomic", "CompareAndSwapInt64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas64"}]
-	i.std[intrinsicKey{"sync/atomic", "CompareAndSwapUint32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas"}]
-	i.std[intrinsicKey{"sync/atomic", "CompareAndSwapUint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas64"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "CompareAndSwapUintptr", 4}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "CompareAndSwapUintptr", 8}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Cas64"}]
-
-	i.std[intrinsicKey{"sync/atomic", "AddInt32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd"}]
-	i.std[intrinsicKey{"sync/atomic", "AddInt64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd64"}]
-	i.std[intrinsicKey{"sync/atomic", "AddUint32"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd"}]
-	i.std[intrinsicKey{"sync/atomic", "AddUint64"}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd64"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "AddUintptr", 4}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd"}]
-	i.ptrSized[sizedIntrinsicKey{"sync/atomic", "AddUintptr", 8}] =
-		i.std[intrinsicKey{"runtime/internal/atomic", "Xadd64"}]
+	alias("sync/atomic", "StoreUint32", "runtime/internal/atomic", "Store", all...)
+	alias("sync/atomic", "StoreUint64", "runtime/internal/atomic", "Store64", all...)
+	alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store", p4...)
+	alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store64", p8...)
+
+	alias("sync/atomic", "SwapInt32", "runtime/internal/atomic", "Xchg", all...)
+	alias("sync/atomic", "SwapInt64", "runtime/internal/atomic", "Xchg64", all...)
+	alias("sync/atomic", "SwapUint32", "runtime/internal/atomic", "Xchg", all...)
+	alias("sync/atomic", "SwapUint64", "runtime/internal/atomic", "Xchg64", all...)
+	alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg", p4...)
+	alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg64", p8...)
+
+	alias("sync/atomic", "CompareAndSwapInt32", "runtime/internal/atomic", "Cas", all...)
+	alias("sync/atomic", "CompareAndSwapInt64", "runtime/internal/atomic", "Cas64", all...)
+	alias("sync/atomic", "CompareAndSwapUint32", "runtime/internal/atomic", "Cas", all...)
+	alias("sync/atomic", "CompareAndSwapUint64", "runtime/internal/atomic", "Cas64", all...)
+	alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas", p4...)
+	alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas64", p8...)
+
+	alias("sync/atomic", "AddInt32", "runtime/internal/atomic", "Xadd", all...)
+	alias("sync/atomic", "AddInt64", "runtime/internal/atomic", "Xadd64", all...)
+	alias("sync/atomic", "AddUint32", "runtime/internal/atomic", "Xadd", all...)
+	alias("sync/atomic", "AddUint64", "runtime/internal/atomic", "Xadd64", all...)
+	alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd", p4...)
+	alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd64", p8...)
 
 	/******** math/big ********/
-	i.intSized[sizedIntrinsicKey{"math/big", "mulWW", 8}] =
-		enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue2(ssa.OpMul64uhilo, ssa.MakeTuple(Types[TUINT64], Types[TUINT64]), args[0], args[1])
-		}, sys.AMD64)
-	i.intSized[sizedIntrinsicKey{"math/big", "divWW", 8}] =
-		enableOnArch(func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
-			return s.newValue3(ssa.OpDiv128u, ssa.MakeTuple(Types[TUINT64], Types[TUINT64]), args[0], args[1], args[2])
-		}, sys.AMD64)
+	add("math/big", "mulWW",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
+		},
+		sys.ArchAMD64)
+	add("math/big", "divWW",
+		func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+			return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+		},
+		sys.ArchAMD64)
 }
 
 // findIntrinsic returns a function which builds the SSA equivalent of the
 // function identified by the symbol sym.  If sym is not an intrinsic call, returns nil.
-func findIntrinsic(sym *Sym) intrinsicBuilder {
+func findIntrinsic(sym *types.Sym) intrinsicBuilder {
 	if ssa.IntrinsicsDisable {
 		return nil
 	}
 	if sym == nil || sym.Pkg == nil {
 		return nil
 	}
-	if intrinsics == nil {
-		intrinsicInit()
-	}
 	pkg := sym.Pkg.Path
 	if sym.Pkg == localpkg {
 		pkg = myimportpath
 	}
-	fn := sym.Name
-	f := intrinsics.std[intrinsicKey{pkg, fn}]
-	if f != nil {
-		return f
-	}
-	f = intrinsics.intSized[sizedIntrinsicKey{pkg, fn, Widthint}]
-	if f != nil {
-		return f
+	if flag_race && pkg == "sync/atomic" {
+		// The race detector needs to be able to intercept these calls.
+		// We can't intrinsify them.
+		return nil
 	}
-	return intrinsics.ptrSized[sizedIntrinsicKey{pkg, fn, Widthptr}]
+	fn := sym.Name
+	return intrinsics[intrinsicKey{thearch.LinkArch.Arch, pkg, fn}]
 }
 
 func isIntrinsicCall(n *Node) bool {
@@ -2855,7 +2993,7 @@ func (s *state) intrinsicCall(n *Node) *ssa.Value {
 		if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 {
 			x = x.Args[0]
 		}
-		Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
+		Warnl(n.Pos, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
 	}
 	return v
 }
@@ -2918,14 +3056,14 @@ func (s *state) intrinsicArgs(n *Node) []*ssa.Value {
 // 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 sym *types.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 {
+		if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
 			sym = fn.Sym
 			break
 		}
@@ -2943,10 +3081,11 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
 		// Make a PFUNC node out of that, then evaluate it.
 		// We get back an SSA value representing &sync.(*Mutex).Unlock·f.
 		// We can then pass that to defer or go.
-		n2 := newname(fn.Sym)
-		n2.Class = PFUNC
-		n2.Lineno = fn.Lineno
-		n2.Type = Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
+		n2 := newnamel(fn.Pos, fn.Sym)
+		n2.Name.Curfn = s.curfn
+		n2.SetClass(PFUNC)
+		n2.Pos = fn.Pos
+		n2.Type = types.Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
 		closure = s.expr(n2)
 		// Note: receiver is already assigned in n.List, so we don't
 		// want to set it here.
@@ -2955,18 +3094,18 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
 			Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
 		}
 		i := s.expr(fn.Left)
-		itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
+		itab := s.newValue1(ssa.OpITab, types.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, ptrto(Types[TUINTPTR]), itabidx, itab)
+		itab = s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
 		if k == callNormal {
-			codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
+			codeptr = s.newValue2(ssa.OpLoad, types.Types[TUINTPTR], itab, s.mem())
 		} else {
 			closure = itab
 		}
-		rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
+		rcvr = s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
 	}
 	dowidth(fn.Type)
 	stksize := fn.Type.ArgWidth() // includes receiver
@@ -2983,19 +3122,19 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
 		if k != callNormal {
 			argStart += int64(2 * Widthptr)
 		}
-		addr := s.entryNewValue1I(ssa.OpOffPtr, ptrto(Types[TUINTPTR]), argStart, s.sp)
-		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
+		addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], addr, rcvr, s.mem())
 	}
 
 	// Defer/go args
 	if k != callNormal {
 		// Write argsize and closure (args to Newproc/Deferproc).
 		argStart := Ctxt.FixedFrameSize()
-		argsize := s.constInt32(Types[TUINT32], int32(stksize))
-		addr := s.entryNewValue1I(ssa.OpOffPtr, ptrto(Types[TUINT32]), argStart, s.sp)
-		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, addr, argsize, s.mem())
-		addr = s.entryNewValue1I(ssa.OpOffPtr, ptrto(Types[TUINTPTR]), argStart+int64(Widthptr), s.sp)
-		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
+		argsize := s.constInt32(types.Types[TUINT32], int32(stksize))
+		addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINT32], addr, argsize, s.mem())
+		addr = s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart+int64(Widthptr))
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], addr, closure, s.mem())
 		stksize += 2 * int64(Widthptr)
 	}
 
@@ -3003,16 +3142,16 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
 	var call *ssa.Value
 	switch {
 	case k == callDefer:
-		call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
+		call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Deferproc, s.mem())
 	case k == callGo:
-		call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
+		call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Newproc, 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())
+		codeptr = s.newValue2(ssa.OpLoad, types.Types[TUINTPTR], closure, s.mem())
+		call = s.newValue3(ssa.OpClosureCall, types.TypeMem, codeptr, closure, s.mem())
 	case codeptr != nil:
-		call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
+		call = s.newValue2(ssa.OpInterCall, types.TypeMem, codeptr, s.mem())
 	case sym != nil:
-		call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
+		call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, sym.Linksym(), s.mem())
 	default:
 		Fatalf("bad call type %v %v", n.Op, n)
 	}
@@ -3041,12 +3180,12 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
 		return nil
 	}
 	fp := res.Field(0)
-	return s.entryNewValue1I(ssa.OpOffPtr, ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
+	return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
 }
 
 // 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 {
+func etypesign(e types.EType) int8 {
 	switch e {
 	case TINT8, TINT16, TINT32, TINT64, TINT:
 		return -1
@@ -3062,105 +3201,102 @@ func etypesign(e EType) int8 {
 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
 	switch sym.(type) {
 	default:
-		s.Fatalf("sym %v is of uknown type %T", sym, sym)
+		s.Fatalf("sym %v is of unknown 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
 	}
+	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)
+func (s *state) addr(n *Node, bounded bool) *ssa.Value {
+	t := types.NewPtr(n.Type)
 	switch n.Op {
 	case ONAME:
-		switch n.Class {
+		switch n.Class() {
 		case PEXTERN:
 			// global variable
-			aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Sym})
+			aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: n.Sym.Linksym()})
 			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
+			return v
 		case PPARAM:
 			// parameter slot
 			v := s.decladdrs[n]
 			if v != nil {
-				return v, false
+				return v
 			}
 			if n == nodfp {
 				// Special arg that points to the frame pointer (Used by ORECOVER).
-				aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
-				return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp), false
+				aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n})
+				return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
 			}
 			s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
-			return nil, false
+			return nil
 		case PAUTO:
-			aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
-			return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
+			aux := s.lookupSymbol(n, &ssa.AutoSymbol{Node: n})
+			return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
 		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
+			aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n})
+			return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
 		default:
-			s.Fatalf("variable address class %v not implemented", classnames[n.Class])
-			return nil, false
+			s.Fatalf("variable address class %v not implemented", classnames[n.Class()])
+			return nil
 		}
 	case OINDREGSP:
 		// indirect off REGSP
 		// used for storing/loading arguments/returns to/from callees
-		return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp), true
+		return s.constOffPtrSP(t, n.Xoffset)
 	case OINDEX:
 		if n.Left.Type.IsSlice() {
 			a := s.expr(n.Left)
 			i := s.expr(n.Right)
 			i = s.extendIndex(i, panicindex)
-			len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
-			if !n.Bounded {
+			len := s.newValue1(ssa.OpSliceLen, types.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
+			return s.newValue2(ssa.OpPtrIndex, t, p, i)
 		} else { // array
-			a, isVolatile := s.addr(n.Left, bounded)
+			a := s.addr(n.Left, bounded)
 			i := s.expr(n.Right)
 			i = s.extendIndex(i, panicindex)
-			len := s.constInt(Types[TINT], n.Left.Type.NumElem())
-			if !n.Bounded {
+			len := s.constInt(types.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
+			return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left.Type.Elem()), a, i)
 		}
 	case OIND:
-		return s.exprPtr(n.Left, bounded, n.Lineno), false
+		return s.exprPtr(n.Left, bounded, n.Pos)
 	case ODOT:
-		p, isVolatile := s.addr(n.Left, bounded)
-		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile
+		p := s.addr(n.Left, bounded)
+		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
 	case ODOTPTR:
-		p := s.exprPtr(n.Left, bounded, n.Lineno)
-		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
+		p := s.exprPtr(n.Left, bounded, n.Pos)
+		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
 	case OCLOSUREVAR:
 		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
-			s.entryNewValue0(ssa.OpGetClosurePtr, ptrto(Types[TUINT8]))), false
+			s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr))
 	case OCONVNOP:
-		addr, isVolatile := s.addr(n.Left, bounded)
-		return s.newValue1(ssa.OpCopy, t, addr), isVolatile // ensure that addr has the right type
+		addr := s.addr(n.Left, bounded)
+		return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
 	case OCALLFUNC, OCALLINTER, OCALLMETH:
-		return s.call(n, callNormal), true
+		return s.call(n, callNormal)
 	case ODOTTYPE:
 		v, _ := s.dottype(n, false)
 		if v.Op != ssa.OpLoad {
@@ -3169,10 +3305,10 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
 		if v.Args[1] != s.mem() {
 			s.Fatalf("memory no longer live from dottype load")
 		}
-		return v.Args[0], false
+		return v.Args[0]
 	default:
 		s.Fatalf("unhandled addr %v", n.Op)
-		return nil, false
+		return nil
 	}
 }
 
@@ -3188,23 +3324,25 @@ func (s *state) canSSA(n *Node) bool {
 	if n.Op != ONAME {
 		return false
 	}
-	if n.Addrtaken {
+	if n.Addrtaken() {
 		return false
 	}
 	if n.isParamHeapCopy() {
 		return false
 	}
-	if n.Class == PAUTOHEAP {
+	if n.Class() == PAUTOHEAP {
 		Fatalf("canSSA of PAUTOHEAP %v", n)
 	}
-	switch n.Class {
+	switch n.Class() {
 	case PEXTERN:
 		return false
 	case PPARAMOUT:
-		if hasdefer {
+		if s.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 }
+			// Or maybe not, see issue 18860.  Even unnamed return values
+			// must be written back so if a defer recovers, the caller can see them.
 			return false
 		}
 		if s.cgoUnsafeArgs {
@@ -3213,7 +3351,7 @@ func (s *state) canSSA(n *Node) bool {
 			return false
 		}
 	}
-	if n.Class == PPARAM && n.String() == ".this" {
+	if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
 		// wrappers generated by genwrapper need to update
 		// the .this pointer in place.
 		// TODO: treat as a PPARMOUT?
@@ -3224,7 +3362,7 @@ func (s *state) canSSA(n *Node) bool {
 }
 
 // canSSA reports whether variables of type t are SSA-able.
-func canSSAType(t *Type) bool {
+func canSSAType(t *types.Type) bool {
 	dowidth(t)
 	if t.Width > int64(4*Widthptr) {
 		// 4*Widthptr is an arbitrary constant. We want it
@@ -3237,10 +3375,7 @@ func canSSAType(t *Type) bool {
 		// We can't do larger arrays because dynamic indexing is
 		// not supported on SSA variables.
 		// TODO: allow if all indexes are constant.
-		if t.NumElem() == 0 {
-			return true
-		}
-		if t.NumElem() == 1 {
+		if t.NumElem() <= 1 {
 			return canSSAType(t.Elem())
 		}
 		return false
@@ -3260,11 +3395,11 @@ func canSSAType(t *Type) bool {
 }
 
 // exprPtr evaluates n to a pointer and nil-checks it.
-func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
+func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *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")
+	if bounded || n.NonNil() {
+		if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
+			s.f.Warnl(lineno, "removed nil check")
 		}
 		return p
 	}
@@ -3276,10 +3411,10 @@ func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
 // 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 {
+	if disable_checknil != 0 || s.curfn.Func.NilCheckDisabled() {
 		return
 	}
-	s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
+	s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem())
 }
 
 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
@@ -3291,7 +3426,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) {
 	}
 
 	// bounds check
-	cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
+	cmp := s.newValue2(ssa.OpIsInBounds, types.Types[TBOOL], idx, len)
 	s.check(cmp, panicindex)
 }
 
@@ -3304,22 +3439,24 @@ func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
 	}
 
 	// bounds check
-	cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
+	cmp := s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len)
 	s.check(cmp, panicslice)
 }
 
 // If cmp (a bool) is false, panic using the given function.
-func (s *state) check(cmp *ssa.Value, fn *Node) {
+func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
 	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}]
+	line := s.peekPos()
+	pos := Ctxt.PosTable.Pos(line)
+	fl := funcLine{f: fn, file: pos.Filename(), line: pos.Line()}
+	bPanic := s.panics[fl]
 	if bPanic == nil {
 		bPanic = s.f.NewBlock(ssa.BlockPlain)
-		s.panics[funcLine{fn, line}] = bPanic
+		s.panics[fl] = bPanic
 		s.startBlock(bPanic)
 		// The panic call takes/returns memory to ensure that the right
 		// memory state is observed if the panic happens.
@@ -3340,7 +3477,7 @@ func (s *state) intDivide(n *Node, a, b *ssa.Value) *ssa.Value {
 	}
 	if needcheck {
 		// do a size-appropriate check for zero
-		cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
+		cmp := s.newValue2(s.ssaOp(ONE, n.Type), types.Types[TBOOL], b, s.zeroVal(n.Type))
 		s.check(cmp, panicdivide)
 	}
 	return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
@@ -3350,28 +3487,21 @@ func (s *state) intDivide(n *Node, a, b *ssa.Value) *ssa.Value {
 // 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.
-func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
+func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
 	// Write args to the stack
 	off := Ctxt.FixedFrameSize()
 	for _, arg := range args {
 		t := arg.Type
 		off = Rnd(off, t.Alignment())
-		ptr := s.sp
-		if off != 0 {
-			ptr = s.newValue1I(ssa.OpOffPtr, t.PtrTo(), off, s.sp)
-		}
+		ptr := s.constOffPtrSP(t.PtrTo(), off)
 		size := t.Size()
-		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, ptr, arg, s.mem())
 		off += size
 	}
-	off = Rnd(off, int64(Widthptr))
-	if Thearch.LinkArch.Name == "amd64p32" {
-		// amd64p32 wants 8-byte alignment of the start of the return values.
-		off = Rnd(off, 8)
-	}
+	off = Rnd(off, int64(Widthreg))
 
 	// Issue call
-	call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
+	call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, fn, s.mem())
 	s.vars[&memVar] = call
 
 	if !returns {
@@ -3390,10 +3520,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
 	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, ptrto(t), off, s.sp)
-		}
+		ptr := s.constOffPtrSP(types.NewPtr(t), off)
 		res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
 		off += t.Size()
 	}
@@ -3405,124 +3532,61 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
 	return res
 }
 
-// insertWBmove inserts the assignment *left = *right including a write barrier.
-// t is the type being assigned.
-// If right == nil, then we're zeroing *left.
-func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) {
-	// if writeBarrier.enabled {
-	//   typedmemmove(&t, left, right)
-	// } else {
-	//   *left = *right
-	// }
-	//
-	// or
-	//
-	// if writeBarrier.enabled {
-	//   typedmemclr(&t, left)
-	// } else {
-	//   *left = zeroValue
-	// }
-
-	if s.noWB {
-		s.Error("write barrier prohibited")
-	}
-	if s.WBLineno == 0 {
-		s.WBLineno = left.Line
-	}
-
-	var val *ssa.Value
-	if right == nil {
-		val = s.newValue2I(ssa.OpZeroWB, ssa.TypeMem, sizeAlignAuxInt(t), left, s.mem())
-	} else {
-		var op ssa.Op
-		if rightIsVolatile {
-			op = ssa.OpMoveWBVolatile
-		} else {
-			op = ssa.OpMoveWB
-		}
-		val = s.newValue3I(op, ssa.TypeMem, sizeAlignAuxInt(t), left, right, s.mem())
+// do *left = right for type t.
+func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask) {
+	if skip == 0 && (!types.Haspointers(t) || ssa.IsStackAddr(left)) {
+		// Known to not have write barrier. Store the whole type.
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, left, right, s.mem())
+		return
 	}
-	val.Aux = &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}
-	s.vars[&memVar] = val
 
-	// WB ops will be expanded to branches at writebarrier phase.
-	// To make it easy, we put WB ops at the end of a block, so
-	// that it does not need to split a block into two parts when
-	// expanding WB ops.
-	b := s.f.NewBlock(ssa.BlockPlain)
-	s.endBlock().AddEdgeTo(b)
-	s.startBlock(b)
-}
-
-// 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.Error("write barrier prohibited")
-	}
-	if s.WBLineno == 0 {
-		s.WBLineno = left.Line
-	}
-	if t == Types[TUINTPTR] {
-		// Stores to reflect.{Slice,String}Header.Data.
-		s.vars[&memVar] = s.newValue3I(ssa.OpStoreWB, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
-	} else {
-		s.storeTypeScalars(t, left, right, skip)
-		s.storeTypePtrsWB(t, left, right)
+	// store scalar fields first, so write barrier stores for
+	// pointer fields can be grouped together, and scalar values
+	// don't need to be live across the write barrier call.
+	// TODO: if the writebarrier pass knows how to reorder stores,
+	// we can do a single store here as long as skip==0.
+	s.storeTypeScalars(t, left, right, skip)
+	if skip&skipPtr == 0 && types.Haspointers(t) {
+		s.storeTypePtrs(t, left, right)
 	}
-
-	// WB ops will be expanded to branches at writebarrier phase.
-	// To make it easy, we put WB ops at the end of a block, so
-	// that it does not need to split a block into two parts when
-	// expanding WB ops.
-	b := s.f.NewBlock(ssa.BlockPlain)
-	s.endBlock().AddEdgeTo(b)
-	s.startBlock(b)
 }
 
 // do *left = right for all scalar (non-pointer) parts of t.
-func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask) {
+func (s *state) storeTypeScalars(t *types.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())
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, 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())
+		len := s.newValue1(ssa.OpStringLen, types.Types[TINT], right)
+		lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], 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())
+			len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], right)
+			lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
+			s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], 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())
+			cap := s.newValue1(ssa.OpSliceCap, types.Types[TINT], right)
+			capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
+			s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], 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())
+		itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], 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)
+			s.storeTypeScalars(ft, addr, val, 0)
 		}
 	case t.IsArray() && t.NumElem() == 0:
 		// nothing
@@ -3534,31 +3598,31 @@ func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask)
 }
 
 // do *left = right for all pointer parts of t.
-func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
+func (s *state) storeTypePtrs(t *types.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())
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, 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())
+		ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, 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())
+		ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, right)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, 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())
+		idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right)
+		idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
+		s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, idataAddr, idata, s.mem())
 	case t.IsStruct():
 		n := t.NumFields()
 		for i := 0; i < n; i++ {
 			ft := t.FieldType(i)
-			if !haspointers(ft.(*Type)) {
+			if !types.Haspointers(ft) {
 				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)
+			s.storeTypePtrs(ft, addr, val)
 		}
 	case t.IsArray() && t.NumElem() == 0:
 		// nothing
@@ -3569,74 +3633,38 @@ func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
 	}
 }
 
-// do *left = right for all pointer parts of t, with write barriers if necessary.
-func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
-	switch {
-	case t.IsPtrShaped():
-		s.vars[&memVar] = s.newValue3I(ssa.OpStoreWB, 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.OpStoreWB, 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.OpStoreWB, 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.OpStoreWB, 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.storeTypePtrsWB(ft.(*Type), addr, val)
-		}
-	case t.IsArray() && t.NumElem() == 0:
-		// nothing
-	case t.IsArray() && t.NumElem() == 1:
-		s.storeTypePtrsWB(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right))
-	default:
-		s.Fatalf("bad write barrier type %v", 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
+func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
+	var elemtype *types.Type
+	var ptrtype *types.Type
 	var ptr *ssa.Value
 	var len *ssa.Value
 	var cap *ssa.Value
-	zero := s.constInt(Types[TINT], 0)
+	zero := s.constInt(types.Types[TINT], 0)
 	switch {
 	case t.IsSlice():
 		elemtype = t.Elem()
-		ptrtype = ptrto(elemtype)
+		ptrtype = types.NewPtr(elemtype)
 		ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
-		len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
-		cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
+		len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v)
+		cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v)
 	case t.IsString():
-		elemtype = Types[TUINT8]
-		ptrtype = ptrto(elemtype)
+		elemtype = types.Types[TUINT8]
+		ptrtype = types.NewPtr(elemtype)
 		ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
-		len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
+		len = s.newValue1(ssa.OpStringLen, types.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)
+		ptrtype = types.NewPtr(elemtype)
 		s.nilCheck(v)
 		ptr = v
-		len = s.constInt(Types[TINT], t.Elem().NumElem())
+		len = s.constInt(types.Types[TINT], t.Elem().NumElem())
 		cap = len
 	default:
 		s.Fatalf("bad type in slice %v\n", t)
@@ -3671,10 +3699,10 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
 	// rptr = p + delta&mask(rcap)
 	// result = (SliceMake rptr rlen rcap)
 	// where mask(x) is 0 if x==0 and -1 if x>0.
-	subOp := s.ssaOp(OSUB, Types[TINT])
-	mulOp := s.ssaOp(OMUL, Types[TINT])
-	andOp := s.ssaOp(OAND, Types[TINT])
-	rlen := s.newValue2(subOp, Types[TINT], j, i)
+	subOp := s.ssaOp(OSUB, types.Types[TINT])
+	mulOp := s.ssaOp(OMUL, types.Types[TINT])
+	andOp := s.ssaOp(OAND, types.Types[TINT])
+	rlen := s.newValue2(subOp, types.Types[TINT], j, i)
 	var rcap *ssa.Value
 	switch {
 	case t.IsString():
@@ -3685,7 +3713,7 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
 	case j == k:
 		rcap = rlen
 	default:
-		rcap = s.newValue2(subOp, Types[TINT], k, i)
+		rcap = s.newValue2(subOp, types.Types[TINT], k, i)
 	}
 
 	var rptr *ssa.Value
@@ -3694,11 +3722,11 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
 		rptr = ptr
 	} else {
 		// delta = # of bytes to offset pointer by.
-		delta := s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
+		delta := s.newValue2(mulOp, types.Types[TINT], i, s.constInt(types.Types[TINT], elemtype.Width))
 		// If we're slicing to the point where the capacity is zero,
 		// zero out the delta.
-		mask := s.newValue1(ssa.OpSlicemask, Types[TINT], rcap)
-		delta = s.newValue2(andOp, Types[TINT], delta, mask)
+		mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap)
+		delta = s.newValue2(andOp, types.Types[TINT], delta, mask)
 		// Compute rptr = ptr + delta
 		rptr = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, delta)
 	}
@@ -3708,7 +3736,7 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
 
 type u642fcvtTab struct {
 	geq, cvt2F, and, rsh, or, add ssa.Op
-	one                           func(*state, ssa.Type, int64) *ssa.Value
+	one                           func(*state, *types.Type, int64) *ssa.Value
 }
 
 var u64_f64 u642fcvtTab = u642fcvtTab{
@@ -3731,15 +3759,15 @@ var u64_f32 u642fcvtTab = u642fcvtTab{
 	one:   (*state).constInt64,
 }
 
-func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
 }
 
-func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
 }
 
-func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	// if x >= 0 {
 	//    result = (floatY) x
 	// } else {
@@ -3765,7 +3793,7 @@ func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt
 	// 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))
+	cmp := s.newValue2(cvttab.geq, types.Types[TBOOL], x, s.zeroVal(ft))
 	b := s.endBlock()
 	b.Kind = ssa.BlockIf
 	b.SetControl(cmp)
@@ -3812,21 +3840,21 @@ var u32_f32 u322fcvtTab = u322fcvtTab{
 	cvtF2F: ssa.OpCvt64Fto32F,
 }
 
-func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
 }
 
-func (s *state) uint32Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint32Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
 }
 
-func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	// if x >= 0 {
 	// 	result = floatY(x)
 	// } else {
 	// 	result = floatY(float64(x) + (1<<32))
 	// }
-	cmp := s.newValue2(ssa.OpGeq32, Types[TBOOL], x, s.zeroVal(ft))
+	cmp := s.newValue2(ssa.OpGeq32, types.Types[TBOOL], x, s.zeroVal(ft))
 	b := s.endBlock()
 	b.Kind = ssa.BlockIf
 	b.SetControl(cmp)
@@ -3845,9 +3873,9 @@ func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt
 
 	b.AddEdgeTo(bElse)
 	s.startBlock(bElse)
-	a1 := s.newValue1(ssa.OpCvt32to64F, Types[TFLOAT64], x)
-	twoToThe32 := s.constFloat64(Types[TFLOAT64], float64(1<<32))
-	a2 := s.newValue2(ssa.OpAdd64F, Types[TFLOAT64], a1, twoToThe32)
+	a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[TFLOAT64], x)
+	twoToThe32 := s.constFloat64(types.Types[TFLOAT64], float64(1<<32))
+	a2 := s.newValue2(ssa.OpAdd64F, types.Types[TFLOAT64], a1, twoToThe32)
 	a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
 
 	s.vars[n] = a3
@@ -3872,8 +3900,8 @@ func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
 	//   return *(((*int)n)+1)
 	// }
 	lenType := n.Type
-	nilValue := s.constNil(Types[TUINTPTR])
-	cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
+	nilValue := s.constNil(types.Types[TUINTPTR])
+	cmp := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], x, nilValue)
 	b := s.endBlock()
 	b.Kind = ssa.BlockIf
 	b.SetControl(cmp)
@@ -3911,8 +3939,8 @@ func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
 
 type f2uCvtTab struct {
 	ltf, cvt2U, subf, or ssa.Op
-	floatValue           func(*state, ssa.Type, float64) *ssa.Value
-	intValue             func(*state, ssa.Type, int64) *ssa.Value
+	floatValue           func(*state, *types.Type, float64) *ssa.Value
+	intValue             func(*state, *types.Type, int64) *ssa.Value
 	cutoff               uint64
 }
 
@@ -3942,7 +3970,7 @@ var f32_u32 f2uCvtTab = f2uCvtTab{
 	subf:       ssa.OpSub32F,
 	or:         ssa.OpOr32,
 	floatValue: (*state).constFloat32,
-	intValue:   func(s *state, t ssa.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
+	intValue:   func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
 	cutoff:     2147483648,
 }
 
@@ -3952,26 +3980,26 @@ var f64_u32 f2uCvtTab = f2uCvtTab{
 	subf:       ssa.OpSub64F,
 	or:         ssa.OpOr32,
 	floatValue: (*state).constFloat64,
-	intValue:   func(s *state, t ssa.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
+	intValue:   func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
 	cutoff:     2147483648,
 }
 
-func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *types.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 {
+func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.floatToUint(&f64_u64, n, x, ft, tt)
 }
 
-func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.floatToUint(&f32_u32, n, x, ft, tt)
 }
 
-func (s *state) float64ToUint32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) float64ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	return s.floatToUint(&f64_u32, n, x, ft, tt)
 }
 
-func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
 	// cutoff:=1<<(intY_Size-1)
 	// if x < floatX(cutoff) {
 	// 	result = uintY(x)
@@ -3981,7 +4009,7 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Ty
 	// 	result = z | -(cutoff)
 	// }
 	cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
-	cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, cutoff)
+	cmp := s.newValue2(cvttab.ltf, types.Types[TBOOL], x, cutoff)
 	b := s.endBlock()
 	b.Kind = ssa.BlockIf
 	b.SetControl(cmp)
@@ -4012,68 +4040,26 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Ty
 	return s.variable(n, n.Type)
 }
 
-// ifaceType returns the value for the word containing the type.
-// t is the type of the interface expression.
-// v is the corresponding value.
-func (s *state) ifaceType(t *Type, v *ssa.Value) *ssa.Value {
-	byteptr := ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
-
-	if t.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)            // input interface
-	target := s.expr(typename(n.Type)) // target type
-	byteptr := ptrto(Types[TUINT8])
+	iface := s.expr(n.Left)   // input interface
+	target := s.expr(n.Right) // target type
+	byteptr := s.f.Config.Types.BytePtr
 
 	if n.Type.IsInterface() {
 		if n.Type.IsEmptyInterface() {
 			// Converting to an empty interface.
 			// Input could be an empty or nonempty interface.
 			if Debug_typeassert > 0 {
-				Warnl(n.Lineno, "type assertion inlined")
+				Warnl(n.Pos, "type assertion inlined")
 			}
 
 			// Get itab/type field from input.
 			itab := s.newValue1(ssa.OpITab, byteptr, iface)
 			// Conversion succeeds iff that field is not nil.
-			cond := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], itab, s.constNil(byteptr))
+			cond := s.newValue2(ssa.OpNeqPtr, types.Types[TBOOL], itab, s.constNil(byteptr))
 
 			if n.Left.Type.IsEmptyInterface() && commaok {
 				// Converting empty interface to empty interface with ,ok is just a nil check.
@@ -4134,32 +4120,39 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 		}
 		// converting to a nonempty interface needs a runtime call.
 		if Debug_typeassert > 0 {
-			Warnl(n.Lineno, "type assertion not inlined")
+			Warnl(n.Pos, "type assertion not inlined")
 		}
 		if n.Left.Type.IsEmptyInterface() {
 			if commaok {
-				call := s.rtcall(assertE2I2, true, []*Type{n.Type, Types[TBOOL]}, target, iface)
+				call := s.rtcall(assertE2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
 				return call[0], call[1]
 			}
-			return s.rtcall(assertE2I, true, []*Type{n.Type}, target, iface)[0], nil
+			return s.rtcall(assertE2I, true, []*types.Type{n.Type}, target, iface)[0], nil
 		}
 		if commaok {
-			call := s.rtcall(assertI2I2, true, []*Type{n.Type, Types[TBOOL]}, target, iface)
+			call := s.rtcall(assertI2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
 			return call[0], call[1]
 		}
-		return s.rtcall(assertI2I, true, []*Type{n.Type}, target, iface)[0], nil
+		return s.rtcall(assertI2I, true, []*types.Type{n.Type}, target, iface)[0], nil
 	}
 
 	if Debug_typeassert > 0 {
-		Warnl(n.Lineno, "type assertion inlined")
+		Warnl(n.Pos, "type assertion inlined")
 	}
 
 	// Converting to a concrete type.
 	direct := isdirectiface(n.Type)
-	typ := s.ifaceType(n.Left.Type, iface) // actual concrete type of input interface
-
+	itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface
 	if Debug_typeassert > 0 {
-		Warnl(n.Lineno, "type assertion inlined")
+		Warnl(n.Pos, "type assertion inlined")
+	}
+	var targetITab *ssa.Value
+	if n.Left.Type.IsEmptyInterface() {
+		// Looking for pointer to target type.
+		targetITab = target
+	} else {
+		// Looking for pointer to itab for target type and source interface.
+		targetITab = s.expr(n.List.First())
 	}
 
 	var tmp *Node       // temporary for use with large types
@@ -4167,14 +4160,12 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 	if commaok && !canSSAType(n.Type) {
 		// unSSAable type, use temporary.
 		// TODO: get rid of some of these temporaries.
-		tmp = temp(n.Type)
-		addr, _ = s.addr(tmp, false)
-		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, tmp, s.mem())
+		tmp = tempAt(n.Pos, s.curfn, n.Type)
+		addr = s.addr(tmp, false)
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
 	}
 
-	// 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)
+	cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab)
 	b := s.endBlock()
 	b.Kind = ssa.BlockIf
 	b.SetControl(cond)
@@ -4188,15 +4179,19 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 	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)
+		taddr := s.expr(n.Right.Right)
+		if n.Left.Type.IsEmptyInterface() {
+			s.rtcall(panicdottypeE, false, nil, itab, target, taddr)
+		} else {
+			s.rtcall(panicdottypeI, false, nil, itab, target, taddr)
+		}
 
 		// on success, return data from interface
 		s.startBlock(bOk)
 		if direct {
 			return s.newValue1(ssa.OpIData, n.Type, iface), nil
 		}
-		p := s.newValue1(ssa.OpIData, ptrto(n.Type), iface)
+		p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()), nil
 	}
 
@@ -4205,7 +4200,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 	bEnd := s.f.NewBlock(ssa.BlockPlain)
 	// Note that we need a new valVar each time (unlike okVar where we can
 	// reuse the variable) because it might have a different type every time.
-	valVar := &Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "val"}}
+	valVar := &Node{Op: ONAME, Sym: &types.Sym{Name: "val"}}
 
 	// type assertion succeeded
 	s.startBlock(bOk)
@@ -4213,12 +4208,14 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 		if direct {
 			s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type, iface)
 		} else {
-			p := s.newValue1(ssa.OpIData, ptrto(n.Type), iface)
+			p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
 			s.vars[valVar] = s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
 		}
 	} else {
-		p := s.newValue1(ssa.OpIData, ptrto(n.Type), iface)
-		s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(n.Type), addr, p, s.mem())
+		p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
+		store := s.newValue3I(ssa.OpMove, types.TypeMem, n.Type.Size(), addr, p, s.mem())
+		store.Aux = n.Type
+		s.vars[&memVar] = store
 	}
 	s.vars[&okVar] = s.constBool(true)
 	s.endBlock()
@@ -4229,7 +4226,9 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 	if tmp == nil {
 		s.vars[valVar] = s.zeroVal(n.Type)
 	} else {
-		s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, sizeAlignAuxInt(n.Type), addr, s.mem())
+		store := s.newValue2I(ssa.OpZero, types.TypeMem, n.Type.Size(), addr, s.mem())
+		store.Aux = n.Type
+		s.vars[&memVar] = store
 	}
 	s.vars[&okVar] = s.constBool(false)
 	s.endBlock()
@@ -4242,73 +4241,15 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
 		delete(s.vars, valVar)
 	} else {
 		res = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
-		s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, tmp, s.mem())
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, tmp, s.mem())
 	}
-	resok = s.variable(&okVar, Types[TBOOL])
+	resok = s.variable(&okVar, types.Types[TBOOL])
 	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 {
+func (s *state) variable(name *Node, t *types.Type) *ssa.Value {
 	v := s.vars[name]
 	if v != nil {
 		return v
@@ -4331,11 +4272,11 @@ func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
 }
 
 func (s *state) mem() *ssa.Value {
-	return s.variable(&memVar, ssa.TypeMem)
+	return s.variable(&memVar, types.TypeMem)
 }
 
 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
-	if n.Class == Pxxx {
+	if n.Class() == Pxxx {
 		// Don't track our dummy nodes (&memVar etc.).
 		return
 	}
@@ -4343,12 +4284,12 @@ func (s *state) addNamedValue(n *Node, v *ssa.Value) {
 		// Don't track temporary variables.
 		return
 	}
-	if n.Class == PPARAMOUT {
+	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 {
+	if n.Class() == PAUTO && n.Xoffset != 0 {
 		s.Fatalf("AUTO var with offset %v %d", n, n.Xoffset)
 	}
 	loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
@@ -4367,6 +4308,8 @@ type Branch struct {
 
 // SSAGenState contains state needed during Prog generation.
 type SSAGenState struct {
+	pp *Progs
+
 	// Branches remembers all the branch instructions we've seen
 	// and where they would like to go.
 	Branches []Branch
@@ -4378,28 +4321,67 @@ type SSAGenState struct {
 	SSEto387 map[int16]int16
 	// Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include x86-387, PPC, and Sparc V8.
 	ScratchFpMem *Node
+
+	maxarg int64 // largest frame size for arguments to calls made by the function
+
+	// Map from GC safe points to stack map index, generated by
+	// liveness analysis.
+	stackMapIndex map[*ssa.Value]int
 }
 
-// Pc returns the current Prog.
-func (s *SSAGenState) Pc() *obj.Prog {
-	return pc
+// Prog appends a new Prog.
+func (s *SSAGenState) Prog(as obj.As) *obj.Prog {
+	return s.pp.Prog(as)
 }
 
-// SetLineno sets the current source line number.
-func (s *SSAGenState) SetLineno(l int32) {
-	lineno = l
+// Pc returns the current Prog.
+func (s *SSAGenState) Pc() *obj.Prog {
+	return s.pp.next
+}
+
+// SetPos sets the current source position.
+func (s *SSAGenState) SetPos(pos src.XPos) {
+	s.pp.pos = pos
+}
+
+// DebugFriendlySetPos sets the position subject to heuristics
+// that reduce "jumpy" line number churn when debugging.
+// Spill/fill/copy instructions from the register allocator,
+// phi functions, and instructions with a no-pos position
+// are examples of instructions that can cause churn.
+func (s *SSAGenState) DebugFriendlySetPosFrom(v *ssa.Value) {
+	// The two choices here are either to leave lineno unchanged,
+	// or to explicitly set it to src.NoXPos.  Leaving it unchanged
+	// (reusing the preceding line number) produces slightly better-
+	// looking assembly language output from the compiler, and is
+	// expected by some already-existing tests.
+	// The debug information appears to be the same in either case
+	switch v.Op {
+	case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg:
+		// leave the position unchanged from beginning of block
+		// or previous line number.
+	default:
+		if v.Pos != src.NoXPos {
+			s.SetPos(v.Pos)
+		}
+	}
 }
 
-// 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) {
+// genssa appends entries to pp for each instruction in f.
+func genssa(f *ssa.Func, pp *Progs) {
 	var s SSAGenState
 
-	e := f.Config.Frontend().(*ssaExport)
+	e := f.Frontend().(*ssafn)
+
+	// Generate GC bitmaps, except if the stack is too large,
+	// in which compilation will fail later anyway (issue 20529).
+	if e.stksize < maxStackSize {
+		s.stackMapIndex = liveness(e, f)
+	}
 
 	// Remember where each block starts.
 	s.bstart = make([]*obj.Prog, f.NumBlocks())
-
+	s.pp = pp
 	var valueProgs map[*obj.Prog]*ssa.Value
 	var blockProgs map[*obj.Prog]*ssa.Block
 	var logProgs = e.log
@@ -4407,26 +4389,63 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 		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]
+		blockProgs[s.pp.next] = f.Blocks[0]
 	}
 
-	if Thearch.Use387 {
+	if thearch.Use387 {
 		s.SSEto387 = map[int16]int16{}
 	}
 
-	s.ScratchFpMem = scratchFpMem
-	scratchFpMem = nil
+	s.ScratchFpMem = e.scratchFpMem
 
 	// Emit basic blocks
 	for i, b := range f.Blocks {
-		s.bstart[b.ID] = pc
+		s.bstart[b.ID] = s.pp.next
 		// Emit values in block
-		Thearch.SSAMarkMoves(&s, b)
+		thearch.SSAMarkMoves(&s, b)
 		for _, v := range b.Values {
-			x := pc
-			Thearch.SSAGenValue(&s, v)
+			x := s.pp.next
+			s.DebugFriendlySetPosFrom(v)
+			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.OpSelect0, ssa.OpSelect1:
+				// nothing to do
+			case ssa.OpGetG:
+				// nothing to do when there's a g register,
+				// and checkLower complains if there's not
+			case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive:
+				// nothing to do; already used by liveness
+			case ssa.OpVarKill:
+				// Zero variable if it is ambiguously live.
+				// After the VARKILL anything this variable references
+				// might be collected. If it were to become live again later,
+				// the GC will see references to already-collected objects.
+				// See issue 20029.
+				n := v.Aux.(*Node)
+				if n.Name.Needzero() {
+					if n.Class() != PAUTO {
+						v.Fatalf("zero of variable which isn't PAUTO %v", n)
+					}
+					if n.Type.Size()%int64(Widthptr) != 0 {
+						v.Fatalf("zero of variable not a multiple of ptr size %v", n)
+					}
+					thearch.ZeroAuto(s.pp, n)
+				}
+			case ssa.OpPhi:
+				CheckLoweredPhi(v)
+
+			default:
+				// let the backend handle it
+				thearch.SSAGenValue(&s, v)
+			}
+
 			if logProgs {
-				for ; x != pc; x = x.Link {
+				for ; x != s.pp.next; x = x.Link {
 					valueProgs[x] = v
 				}
 			}
@@ -4440,10 +4459,11 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 			// line numbers for otherwise empty blocks.
 			next = f.Blocks[i+1]
 		}
-		x := pc
-		Thearch.SSAGenBlock(&s, b, next)
+		x := s.pp.next
+		s.SetPos(b.Pos)
+		thearch.SSAGenBlock(&s, b, next)
 		if logProgs {
-			for ; x != pc; x = x.Link {
+			for ; x != s.pp.next; x = x.Link {
 				blockProgs[x] = b
 			}
 		}
@@ -4455,7 +4475,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 	}
 
 	if logProgs {
-		for p := ptxt; p != nil; p = p.Link {
+		for p := pp.Text; p != nil; p = p.Link {
 			var s string
 			if v, ok := valueProgs[p]; ok {
 				s = v.String()
@@ -4466,13 +4486,16 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 			}
 			f.Logf("%s\t%s\n", s, p)
 		}
-		if f.Config.HTML != nil {
-			saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
-			ptxt.Ctxt.LineHist.PrintFilenameOnly = true
+		if f.HTMLWriter != nil {
+			// LineHist is defunct now - this code won't do
+			// anything.
+			// TODO: fix this (ideally without a global variable)
+			// saved := pp.Text.Ctxt.LineHist.PrintFilenameOnly
+			// pp.Text.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 {
+			for p := pp.Text; p != nil; p = p.Link {
 				buf.WriteString("<dt class=\"ssa-prog-src\">")
 				if v, ok := valueProgs[p]; ok {
 					buf.WriteString(v.HTML())
@@ -4487,34 +4510,71 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 			}
 			buf.WriteString("</dl>")
 			buf.WriteString("</code>")
-			f.Config.HTML.WriteColumn("genssa", buf.String())
-			ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
+			f.HTMLWriter.WriteColumn("genssa", buf.String())
+			// pp.Text.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)
-			}
-		}
+	defframe(&s, e)
+	if Debug['f'] != 0 {
+		frame(0)
 	}
 
-	// Generate gc bitmaps.
-	liveness(Curfn, ptxt, gcargs, gclocals)
+	f.HTMLWriter.Close()
+	f.HTMLWriter = nil
+}
 
-	// Add frame prologue. Zero ambiguously live variables.
-	Thearch.Defframe(ptxt)
-	if Debug['f'] != 0 {
-		frame(0)
+func defframe(s *SSAGenState, e *ssafn) {
+	pp := s.pp
+
+	frame := Rnd(s.maxarg+e.stksize, int64(Widthreg))
+	if thearch.PadFrame != nil {
+		frame = thearch.PadFrame(frame)
 	}
 
-	// Remove leftover instrumentation from the instruction stream.
-	removevardef(ptxt)
+	// Fill in argument and frame size.
+	pp.Text.To.Type = obj.TYPE_TEXTSIZE
+	pp.Text.To.Val = int32(Rnd(e.curfn.Type.ArgWidth(), int64(Widthreg)))
+	pp.Text.To.Offset = frame
+
+	// Insert code to zero ambiguously live variables so that the
+	// garbage collector only sees initialized values when it
+	// looks for pointers.
+	p := pp.Text
+	var lo, hi int64
+
+	// Opaque state for backend to use. Current backends use it to
+	// keep track of which helper registers have been zeroed.
+	var state uint32
+
+	// Iterate through declarations. They are sorted in decreasing Xoffset order.
+	for _, n := range e.curfn.Func.Dcl {
+		if !n.Name.Needzero() {
+			continue
+		}
+		if n.Class() != PAUTO {
+			Fatalf("needzero class %d", n.Class())
+		}
+		if n.Type.Size()%int64(Widthptr) != 0 || n.Xoffset%int64(Widthptr) != 0 || n.Type.Size() == 0 {
+			Fatalf("var %L has size %d offset %d", n, n.Type.Size(), n.Xoffset)
+		}
+
+		if lo != hi && n.Xoffset+n.Type.Size() >= lo-int64(2*Widthreg) {
+			// Merge with range we already have.
+			lo = n.Xoffset
+			continue
+		}
+
+		// Zero old range
+		p = thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
 
-	f.Config.HTML.Close()
-	f.Config.HTML = nil
+		// Set new range.
+		lo = n.Xoffset
+		hi = lo + n.Type.Size()
+	}
+
+	// Zero final range.
+	thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
 }
 
 type FloatingEQNEJump struct {
@@ -4522,42 +4582,25 @@ type FloatingEQNEJump struct {
 	Index int
 }
 
-func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
-	p := Prog(jumps.Jump)
+func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) {
+	p := s.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
+	s.Branches = append(s.Branches, Branch{p, b.Succs[to].Block()})
+}
+
+func (s *SSAGenState) FPJump(b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
 	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)
+		s.oneFPJump(b, &jumps[0][0])
+		s.oneFPJump(b, &jumps[0][1])
 	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)
+		s.oneFPJump(b, &jumps[1][0])
+		s.oneFPJump(b, &jumps[1][1])
 	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)
+		s.oneFPJump(b, &jumps[1][0])
+		s.oneFPJump(b, &jumps[1][1])
+		q := s.Prog(obj.AJMP)
 		q.To.Type = obj.TYPE_BRANCH
 		s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()})
 	}
@@ -4595,58 +4638,44 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
 	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)
-		}
+		a.Sym = sym.Sym
 	case *ssa.ArgSymbol:
 		n := sym.Node.(*Node)
 		a.Name = obj.NAME_PARAM
-		a.Node = n
-		a.Sym = Linksym(n.Orig.Sym)
+		a.Sym = n.Orig.Sym.Linksym()
 		a.Offset += n.Xoffset
 	case *ssa.AutoSymbol:
 		n := sym.Node.(*Node)
 		a.Name = obj.NAME_AUTO
-		a.Node = n
-		a.Sym = Linksym(n.Sym)
+		a.Sym = n.Sym.Linksym()
 		a.Offset += n.Xoffset
 	default:
 		v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
 	}
 }
 
-// sizeAlignAuxInt returns an AuxInt encoding the size and alignment of type t.
-func sizeAlignAuxInt(t *Type) int64 {
-	return ssa.MakeSizeAndAlign(t.Size(), t.Alignment()).Int64()
-}
-
 // extendIndex extends v to a full int width.
 // panic using the given function if v does not fit in an int (only on 32-bit archs).
-func (s *state) extendIndex(v *ssa.Value, panicfn *Node) *ssa.Value {
+func (s *state) extendIndex(v *ssa.Value, panicfn *obj.LSym) *ssa.Value {
 	size := v.Type.Size()
-	if size == s.config.IntSize {
+	if size == s.config.PtrSize {
 		return v
 	}
-	if size > s.config.IntSize {
+	if size > s.config.PtrSize {
 		// truncate 64-bit indexes on 32-bit pointer archs. Test the
 		// high word and branch to out-of-bounds failure if it is not 0.
 		if Debug['B'] == 0 {
-			hi := s.newValue1(ssa.OpInt64Hi, Types[TUINT32], v)
-			cmp := s.newValue2(ssa.OpEq32, Types[TBOOL], hi, s.constInt32(Types[TUINT32], 0))
+			hi := s.newValue1(ssa.OpInt64Hi, types.Types[TUINT32], v)
+			cmp := s.newValue2(ssa.OpEq32, types.Types[TBOOL], hi, s.constInt32(types.Types[TUINT32], 0))
 			s.check(cmp, panicfn)
 		}
-		return s.newValue1(ssa.OpTrunc64to32, Types[TINT], v)
+		return s.newValue1(ssa.OpTrunc64to32, types.Types[TINT], v)
 	}
 
 	// Extend value to the required size
 	var op ssa.Op
 	if v.Type.IsSigned() {
-		switch 10*size + s.config.IntSize {
+		switch 10*size + s.config.PtrSize {
 		case 14:
 			op = ssa.OpSignExt8to32
 		case 18:
@@ -4661,7 +4690,7 @@ func (s *state) extendIndex(v *ssa.Value, panicfn *Node) *ssa.Value {
 			s.Fatalf("bad signed index extension %s", v.Type)
 		}
 	} else {
-		switch 10*size + s.config.IntSize {
+		switch 10*size + s.config.PtrSize {
 		case 14:
 			op = ssa.OpZeroExt8to32
 		case 18:
@@ -4676,7 +4705,7 @@ func (s *state) extendIndex(v *ssa.Value, panicfn *Node) *ssa.Value {
 			s.Fatalf("bad unsigned index extension %s", v.Type)
 		}
 	}
-	return s.newValue1(op, Types[TINT], v)
+	return s.newValue1(op, types.Types[TINT], v)
 }
 
 // CheckLoweredPhi checks that regalloc and stackalloc correctly handled phi values.
@@ -4707,26 +4736,6 @@ func CheckLoweredGetClosurePtr(v *ssa.Value) {
 	}
 }
 
-// KeepAlive marks the variable referenced by OpKeepAlive as live.
-// Called during ssaGenValue.
-func KeepAlive(v *ssa.Value) {
-	if v.Op != ssa.OpKeepAlive {
-		v.Fatalf("KeepAlive called with non-KeepAlive value: %v", v.LongString())
-	}
-	if !v.Args[0].Type.IsPtrShaped() {
-		v.Fatalf("keeping non-pointer alive %v", v.Args[0])
-	}
-	n, _ := AutoVar(v.Args[0])
-	if n == nil {
-		v.Fatalf("KeepAlive with non-spilled value %s %s", v, v.Args[0])
-	}
-	// Note: KeepAlive arg may be a small part of a larger variable n.  We keep the
-	// whole variable n alive at this point. (Typically, this happens when
-	// we are requested to keep the idata portion of an interface{} alive, and
-	// we end up keeping the whole interface{} alive.  That's ok.)
-	Gvarlive(n)
-}
-
 // 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) {
@@ -4740,10 +4749,10 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
 func AddrAuto(a *obj.Addr, v *ssa.Value) {
 	n, off := AutoVar(v)
 	a.Type = obj.TYPE_MEM
-	a.Node = n
-	a.Sym = Linksym(n.Sym)
+	a.Sym = n.Sym.Linksym()
+	a.Reg = int16(thearch.REGSP)
 	a.Offset = n.Xoffset + off
-	if n.Class == PPARAM || n.Class == PPARAMOUT {
+	if n.Class() == PPARAM || n.Class() == PPARAMOUT {
 		a.Name = obj.NAME_PARAM
 	} else {
 		a.Name = obj.NAME_AUTO
@@ -4756,12 +4765,55 @@ func (s *SSAGenState) AddrScratch(a *obj.Addr) {
 	}
 	a.Type = obj.TYPE_MEM
 	a.Name = obj.NAME_AUTO
-	a.Node = s.ScratchFpMem
-	a.Sym = Linksym(s.ScratchFpMem.Sym)
-	a.Reg = int16(Thearch.REGSP)
+	a.Sym = s.ScratchFpMem.Sym.Linksym()
+	a.Reg = int16(thearch.REGSP)
 	a.Offset = s.ScratchFpMem.Xoffset
 }
 
+func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
+	idx, ok := s.stackMapIndex[v]
+	if !ok {
+		Fatalf("missing stack map index for %v", v.LongString())
+	}
+	p := s.Prog(obj.APCDATA)
+	Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
+	Addrconst(&p.To, int64(idx))
+
+	if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn {
+		// Deferred calls will appear to be returning to
+		// the CALL deferreturn(SB) that we are about to emit.
+		// However, the stack trace code will show the line
+		// of the instruction byte before the return PC.
+		// To avoid that being an unrelated instruction,
+		// insert an actual hardware NOP that will have the right line number.
+		// This is different from obj.ANOP, which is a virtual no-op
+		// that doesn't make it into the instruction stream.
+		thearch.Ginsnop(s.pp)
+	}
+
+	p = s.Prog(obj.ACALL)
+	if sym, ok := v.Aux.(*obj.LSym); ok {
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = sym
+	} else {
+		// TODO(mdempsky): Can these differences be eliminated?
+		switch thearch.LinkArch.Family {
+		case sys.AMD64, sys.I386, sys.PPC64, sys.S390X:
+			p.To.Type = obj.TYPE_REG
+		case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
+			p.To.Type = obj.TYPE_MEM
+		default:
+			Fatalf("unknown indirect call family")
+		}
+		p.To.Reg = v.Args[0].Reg()
+	}
+	if s.maxarg < v.AuxInt {
+		s.maxarg = v.AuxInt
+	}
+	return p
+}
+
 // fieldIdx finds the index of the field referred to by the ODOT node n.
 func fieldIdx(n *Node) int {
 	t := n.Left.Type
@@ -4787,80 +4839,77 @@ func fieldIdx(n *Node) int {
 	// 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
-}
-
-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
+// ssafn holds frontend information about a function that the backend is processing.
+// It also exports a bunch of compiler services for the ssa backend.
+type ssafn struct {
+	curfn        *Node
+	strings      map[string]interface{} // map from constant string to data symbols
+	scratchFpMem *Node                  // temp for floating point register / memory moves on some architectures
+	stksize      int64                  // stack size for current frame
+	stkptrsize   int64                  // prefix of stack containing pointers
+	log          bool
+}
+
+// StringData returns a symbol (a *types.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...
+func (e *ssafn) StringData(s string) interface{} {
+	if aux, ok := e.strings[s]; ok {
+		return aux
+	}
+	if e.strings == nil {
+		e.strings = make(map[string]interface{})
+	}
 	data := stringsym(s)
-	return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
+	aux := &ssa.ExternSymbol{Sym: data}
+	e.strings[s] = aux
+	return aux
 }
 
-func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
-	n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
+func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
+	n := tempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
 	return n
 }
 
-func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+func (e *ssafn) 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 {
+	ptrType := types.NewPtr(types.Types[TUINT8])
+	lenType := types.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)
+		p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
+		l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
 		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) {
+func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
 	n := name.N.(*Node)
-	t := ptrto(Types[TUINT8])
-	if n.Class == PAUTO && !n.Addrtaken {
+	t := types.NewPtr(types.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)
+		c := e.namedAuto(n.Sym.Name+f, t, n.Pos)
+		d := e.namedAuto(n.Sym.Name+".data", t, n.Pos)
 		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) {
+func (e *ssafn) 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 {
+	ptrType := types.NewPtr(name.Type.ElemType())
+	lenType := types.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)
+		p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
+		l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
+		c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos)
 		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.
@@ -4869,139 +4918,163 @@ func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
 		ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
 }
 
-func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
 	n := name.N.(*Node)
 	s := name.Type.Size() / 2
-	var t *Type
+	var t *types.Type
 	if s == 8 {
-		t = Types[TFLOAT64]
+		t = types.Types[TFLOAT64]
 	} else {
-		t = Types[TFLOAT32]
+		t = types.Types[TFLOAT32]
 	}
-	if n.Class == PAUTO && !n.Addrtaken {
+	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)
+		c := e.namedAuto(n.Sym.Name+".real", t, n.Pos)
+		d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos)
 		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) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
 	n := name.N.(*Node)
-	var t *Type
+	var t *types.Type
 	if name.Type.IsSigned() {
-		t = Types[TINT32]
+		t = types.Types[TINT32]
 	} else {
-		t = Types[TUINT32]
+		t = types.Types[TUINT32]
 	}
-	if n.Class == PAUTO && !n.Addrtaken {
+	if n.Class() == PAUTO && !n.Addrtaken() {
 		// Split this int64 up into two separate variables.
-		h := e.namedAuto(n.Sym.Name+".hi", t)
-		l := e.namedAuto(n.Sym.Name+".lo", Types[TUINT32])
-		return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: Types[TUINT32], Off: 0}
+		h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos)
+		l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos)
+		return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0}
 	}
 	// Return the two parts of the larger variable.
-	if Thearch.LinkArch.ByteOrder == binary.BigEndian {
-		return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: Types[TUINT32], Off: name.Off + 4}
+	if thearch.LinkArch.ByteOrder == binary.BigEndian {
+		return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off + 4}
 	}
-	return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: Types[TUINT32], Off: name.Off}
+	return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off}
 }
 
-func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
+func (e *ssafn) 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 {
+	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)
+		x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos)
 		return ssa.LocalSlot{N: x, Type: ft, Off: 0}
 	}
 	return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
 }
 
-func (e *ssaExport) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
+func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
 	n := name.N.(*Node)
 	at := name.Type
 	if at.NumElem() != 1 {
 		Fatalf("bad array size")
 	}
 	et := at.ElemType()
-	if n.Class == PAUTO && !n.Addrtaken {
-		x := e.namedAuto(n.Sym.Name+"[0]", et)
+	if n.Class() == PAUTO && !n.Addrtaken() {
+		x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos)
 		return ssa.LocalSlot{N: x, Type: et, Off: 0}
 	}
 	return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
 }
 
+func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
+	return itabsym(it, offset)
+}
+
 // namedAuto returns a new AUTO variable with the given name and type.
 // These are exposed to the debugger.
-func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
-	t := typ.(*Type)
-	s := &Sym{Name: name, Pkg: localpkg}
-	n := nod(ONAME, nil, nil)
-	s.Def = n
-	s.Def.Used = true
+func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode {
+	t := typ
+	s := &types.Sym{Name: name, Pkg: localpkg}
+
+	n := new(Node)
+	n.Name = new(Name)
+	n.Op = ONAME
+	n.Pos = pos
+	n.Orig = n
+
+	s.Def = asTypesNode(n)
+	asNode(s.Def).Name.SetUsed(true)
 	n.Sym = s
 	n.Type = t
-	n.Class = PAUTO
-	n.Addable = true
-	n.Ullman = 1
+	n.SetClass(PAUTO)
+	n.SetAddable(true)
 	n.Esc = EscNever
-	n.Xoffset = 0
-	n.Name.Curfn = Curfn
-	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
-
+	n.Name.Curfn = e.curfn
+	e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
 	dowidth(t)
 	return n
 }
 
-func (e *ssaExport) CanSSA(t ssa.Type) bool {
-	return canSSAType(t.(*Type))
+func (e *ssafn) CanSSA(t *types.Type) bool {
+	return canSSAType(t)
 }
 
-func (e *ssaExport) Line(line int32) string {
-	return linestr(line)
+func (e *ssafn) Line(pos src.XPos) string {
+	return linestr(pos)
 }
 
 // Log logs a message from the compiler.
-func (e *ssaExport) Logf(msg string, args ...interface{}) {
+func (e *ssafn) Logf(msg string, args ...interface{}) {
 	if e.log {
 		fmt.Printf(msg, args...)
 	}
 }
 
-func (e *ssaExport) Log() bool {
+func (e *ssafn) Log() bool {
 	return e.log
 }
 
 // Fatal reports a compiler error and exits.
-func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
-	lineno = line
+func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) {
+	lineno = pos
 	Fatalf(msg, args...)
 }
 
 // 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 *ssafn) Warnl(pos src.XPos, fmt_ string, args ...interface{}) {
+	Warnl(pos, fmt_, args...)
 }
 
-func (e *ssaExport) Debug_checknil() bool {
+func (e *ssafn) Debug_checknil() bool {
 	return Debug_checknil != 0
 }
 
-func (e *ssaExport) Debug_wb() bool {
+func (e *ssafn) Debug_wb() bool {
 	return Debug_wb != 0
 }
 
-func (e *ssaExport) Syslook(name string) interface{} {
-	return syslook(name).Sym
+func (e *ssafn) UseWriteBarrier() bool {
+	return use_writebarrier
+}
+
+func (e *ssafn) Syslook(name string) *obj.LSym {
+	switch name {
+	case "goschedguarded":
+		return goschedguarded
+	case "writeBarrier":
+		return writeBarrier
+	case "writebarrierptr":
+		return writebarrierptr
+	case "typedmemmove":
+		return typedmemmove
+	case "typedmemclr":
+		return typedmemclr
+	}
+	Fatalf("unknown Syslook func %v", name)
+	return nil
 }
 
-func (n *Node) Typ() ssa.Type {
+func (n *Node) Typ() *types.Type {
 	return n.Type
 }
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 7d008df..566403b 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -5,8 +5,9 @@
 package gc
 
 import (
-	"bytes"
-	"cmd/internal/obj"
+	"cmd/compile/internal/types"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"crypto/md5"
 	"encoding/binary"
 	"fmt"
@@ -15,17 +16,23 @@ import (
 	"sort"
 	"strconv"
 	"strings"
+	"sync"
 	"unicode"
 	"unicode/utf8"
 )
 
 type Error struct {
-	lineno int32
-	msg    string
+	pos src.XPos
+	msg string
 }
 
 var errors []Error
 
+var (
+	largeStackFramesMu sync.Mutex // protects largeStackFrames
+	largeStackFrames   []src.XPos // positions of functions whose stack frames are too large (rare)
+)
+
 func errorexit() {
 	flusherrors()
 	if outfile != "" {
@@ -39,24 +46,24 @@ func adderrorname(n *Node) {
 		return
 	}
 	old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
-	if len(errors) > 0 && errors[len(errors)-1].lineno == n.Lineno && errors[len(errors)-1].msg == old {
+	if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && 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 int32, format string, args ...interface{}) {
+func adderr(pos src.XPos, format string, args ...interface{}) {
 	errors = append(errors, Error{
-		lineno: line,
-		msg:    fmt.Sprintf("%v: %s\n", linestr(line), fmt.Sprintf(format, args...)),
+		pos: pos,
+		msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
 	})
 }
 
-// byLineno sorts errors by lineno.
-type byLineno []Error
+// byPos sorts errors by source position.
+type byPos []Error
 
-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 (x byPos) Len() int           { return len(x) }
+func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
+func (x byPos) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
 
 // flusherrors sorts errors seen so far by line number, prints them to stdout,
 // and empties the errors array.
@@ -65,7 +72,7 @@ func flusherrors() {
 	if len(errors) == 0 {
 		return
 	}
-	sort.Stable(byLineno(errors))
+	sort.Stable(byPos(errors))
 	for i := 0; i < len(errors); i++ {
 		if i == 0 || errors[i].msg != errors[i-1].msg {
 			fmt.Printf("%s", errors[i].msg)
@@ -85,49 +92,56 @@ func hcrash() {
 	}
 }
 
-func linestr(line int32) string {
-	return Ctxt.Line(int(line))
+func linestr(pos src.XPos) string {
+	return Ctxt.OutermostPos(pos).Format(Debug['C'] == 0)
 }
 
 // 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
+	syntax src.XPos // source position of last syntax error
+	other  src.XPos // source position of last non-syntax error
+	msg    string   // error message of last non-syntax error
+}
+
+// sameline reports whether two positions a, b are on the same line.
+func sameline(a, b src.XPos) bool {
+	p := Ctxt.PosTable.Pos(a)
+	q := Ctxt.PosTable.Pos(b)
+	return p.Base() == q.Base() && p.Line() == q.Line()
 }
 
-func yyerrorl(line int32, format string, args ...interface{}) {
+func yyerrorl(pos src.XPos, format string, args ...interface{}) {
 	msg := fmt.Sprintf(format, args...)
 
 	if strings.HasPrefix(msg, "syntax error") {
 		nsyntaxerrors++
 		// only one syntax error per line, no matter what error
-		if lasterror.syntax == line {
+		if sameline(lasterror.syntax, pos) {
 			return
 		}
-		lasterror.syntax = line
+		lasterror.syntax = pos
 	} 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 {
+		if sameline(lasterror.other, pos) && lasterror.msg == msg {
 			return
 		}
-		lasterror.other = line
+		lasterror.other = pos
 		lasterror.msg = msg
 	}
 
-	adderr(line, "%s", msg)
+	adderr(pos, "%s", msg)
 
 	hcrash()
 	nerrors++
 	if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
 		flusherrors()
-		fmt.Printf("%v: too many errors\n", linestr(line))
+		fmt.Printf("%v: too many errors\n", linestr(pos))
 		errorexit()
 	}
 }
@@ -142,7 +156,7 @@ func Warn(fmt_ string, args ...interface{}) {
 	hcrash()
 }
 
-func Warnl(line int32, fmt_ string, args ...interface{}) {
+func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
 	adderr(line, fmt_, args...)
 	if Debug['m'] != 0 {
 		flusherrors()
@@ -157,7 +171,7 @@ func Fatalf(fmt_ string, args ...interface{}) {
 	fmt.Printf("\n")
 
 	// If this is a released compiler version, ask for a bug report.
-	if strings.HasPrefix(obj.Version, "release") {
+	if strings.HasPrefix(objabi.Version, "release") {
 		fmt.Printf("\n")
 		fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
 		fmt.Printf("https://golang.org/issue/new\n")
@@ -172,35 +186,7 @@ func Fatalf(fmt_ string, args ...interface{}) {
 	errorexit()
 }
 
-func linehistpragma(file string) {
-	if Debug['i'] != 0 {
-		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, linestr(lexlineno))
-	}
-	Ctxt.LineHist.Push(int(lexlineno), file)
-}
-
-func linehistpop() {
-	if Debug['i'] != 0 {
-		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, linestr(lexlineno))
-	}
-	Ctxt.LineHist.Update(int(lexlineno), file, off)
-}
-
-func setlineno(n *Node) int32 {
+func setlineno(n *Node) src.XPos {
 	lno := lineno
 	if n != nil {
 		switch n.Op {
@@ -214,10 +200,10 @@ func setlineno(n *Node) int32 {
 			fallthrough
 
 		default:
-			lineno = n.Lineno
-			if lineno == 0 {
+			lineno = n.Pos
+			if !lineno.IsKnown() {
 				if Debug['K'] != 0 {
-					Warn("setlineno: line 0")
+					Warn("setlineno: unknown position (line 0)")
 				}
 				lineno = lno
 			}
@@ -227,25 +213,17 @@ func setlineno(n *Node) int32 {
 	return lno
 }
 
-func lookup(name string) *Sym {
+func lookup(name string) *types.Sym {
 	return localpkg.Lookup(name)
 }
 
-func lookupf(format string, a ...interface{}) *Sym {
-	return lookup(fmt.Sprintf(format, a...))
-}
-
-func lookupBytes(name []byte) *Sym {
-	return localpkg.LookupBytes(name)
-}
-
 // 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 {
+func lookupN(prefix string, n int) *types.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)
+	return localpkg.LookupBytes(b)
 }
 
 // autolabel generates a new Name node for use with
@@ -267,57 +245,17 @@ func autolabel(prefix string) *Node {
 	return newname(lookupN(prefix, int(n)))
 }
 
-var initSyms []*Sym
-
-var nopkg = &Pkg{
-	Syms: make(map[string]*Sym),
-}
-
-func (pkg *Pkg) Lookup(name string) *Sym {
-	if pkg == nil {
-		pkg = nopkg
-	}
-	if s := pkg.Syms[name]; s != nil {
-		return s
-	}
-
-	s := &Sym{
-		Name: name,
-		Pkg:  pkg,
-	}
-	if name == "init" {
-		initSyms = append(initSyms, s)
-	}
-	pkg.Syms[name] = s
-	return s
-}
-
-func (pkg *Pkg) LookupBytes(name []byte) *Sym {
-	if pkg == nil {
-		pkg = nopkg
-	}
-	if s := pkg.Syms[string(name)]; s != nil {
-		return s
-	}
-	str := internString(name)
-	return pkg.Lookup(str)
-}
-
-func Pkglookup(name string, pkg *Pkg) *Sym {
-	return pkg.Lookup(name)
-}
-
-func restrictlookup(name string, pkg *Pkg) *Sym {
+func restrictlookup(name string, pkg *types.Pkg) *types.Sym {
 	if !exportname(name) && pkg != localpkg {
 		yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
 	}
-	return Pkglookup(name, pkg)
+	return pkg.Lookup(name)
 }
 
 // find all the exported symbols in package opkg
 // and make them available in the current package
-func importdot(opkg *Pkg, pack *Node) {
-	var s1 *Sym
+func importdot(opkg *types.Pkg, pack *Node) {
+	var s1 *types.Sym
 	var pkgerror string
 
 	n := 0
@@ -337,48 +275,91 @@ func importdot(opkg *Pkg, pack *Node) {
 
 		s1.Def = s.Def
 		s1.Block = s.Block
-		if s1.Def.Name == nil {
-			Dump("s1def", s1.Def)
+		if asNode(s1.Def).Name == nil {
+			Dump("s1def", asNode(s1.Def))
 			Fatalf("missing Name")
 		}
-		s1.Def.Name.Pack = pack
+		asNode(s1.Def).Name.Pack = pack
 		s1.Origpkg = opkg
 		n++
 	}
 
 	if n == 0 {
 		// can't possibly be used - there were no symbols
-		yyerrorl(pack.Lineno, "imported and not used: %q", opkg.Path)
+		yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
 	}
 }
 
-func nod(op Op, nleft *Node, nright *Node) *Node {
-	n := new(Node)
+func nod(op Op, nleft, nright *Node) *Node {
+	return nodl(lineno, op, nleft, nright)
+}
+
+func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
+	var n *Node
+	switch op {
+	case OCLOSURE, ODCLFUNC:
+		var x struct {
+			Node
+			Func
+		}
+		n = &x.Node
+		n.Func = &x.Func
+	case ONAME:
+		Fatalf("use newname instead")
+	case OLABEL, OPACK:
+		var x struct {
+			Node
+			Name
+		}
+		n = &x.Node
+		n.Name = &x.Name
+	default:
+		n = new(Node)
+	}
 	n.Op = op
 	n.Left = nleft
 	n.Right = nright
-	n.Lineno = lineno
+	n.Pos = pos
 	n.Xoffset = BADWIDTH
 	n.Orig = n
-	switch op {
-	case OCLOSURE, ODCLFUNC:
-		n.Func = new(Func)
-		n.Func.IsHiddenClosure = Curfn != nil
-	case ONAME:
-		n.Name = new(Name)
-		n.Name.Param = new(Param)
-	case OLABEL, OPACK:
-		n.Name = new(Name)
+	return n
+}
+
+// newname returns a new ONAME Node associated with symbol s.
+func newname(s *types.Sym) *Node {
+	n := newnamel(lineno, s)
+	n.Name.Curfn = Curfn
+	return n
+}
+
+// newname returns a new ONAME Node associated with symbol s at position pos.
+// The caller is responsible for setting n.Name.Curfn.
+func newnamel(pos src.XPos, s *types.Sym) *Node {
+	if s == nil {
+		Fatalf("newnamel nil")
 	}
-	if n.Name != nil {
-		n.Name.Curfn = Curfn
+
+	var x struct {
+		Node
+		Name
+		Param
 	}
+	n := &x.Node
+	n.Name = &x.Name
+	n.Name.Param = &x.Param
+
+	n.Op = ONAME
+	n.Pos = pos
+	n.Orig = n
+
+	n.Sym = s
+	n.SetAddable(true)
 	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 {
+func nodSym(op Op, left *Node, sym *types.Sym) *Node {
 	n := nod(op, left, nil)
 	n.Sym = sym
 	return n
@@ -394,7 +375,7 @@ func saveorignode(n *Node) {
 }
 
 // methcmp sorts by symbol, then by package path for unexported symbols.
-type methcmp []*Field
+type methcmp []*types.Field
 
 func (x methcmp) Len() int      { return len(x) }
 func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
@@ -424,29 +405,26 @@ func (x methcmp) Less(i, j int) bool {
 
 func nodintconst(v int64) *Node {
 	c := nod(OLITERAL, nil, nil)
-	c.Addable = true
+	c.SetAddable(true)
 	c.SetVal(Val{new(Mpint)})
 	c.Val().U.(*Mpint).SetInt64(v)
-	c.Type = Types[TIDEAL]
-	ullmancalc(c)
+	c.Type = types.Types[TIDEAL]
 	return c
 }
 
 func nodfltconst(v *Mpflt) *Node {
 	c := nod(OLITERAL, nil, nil)
-	c.Addable = true
+	c.SetAddable(true)
 	c.SetVal(Val{newMpflt()})
 	c.Val().U.(*Mpflt).Set(v)
-	c.Type = Types[TIDEAL]
-	ullmancalc(c)
+	c.Type = types.Types[TIDEAL]
 	return c
 }
 
-func Nodconst(n *Node, t *Type, v int64) {
+func nodconst(n *Node, t *types.Type, v int64) {
 	*n = Node{}
 	n.Op = OLITERAL
-	n.Addable = true
-	ullmancalc(n)
+	n.SetAddable(true)
 	n.SetVal(Val{new(Mpint)})
 	n.Val().U.(*Mpint).SetInt64(v)
 	n.Type = t
@@ -459,23 +437,23 @@ func Nodconst(n *Node, t *Type, v int64) {
 func nodnil() *Node {
 	c := nodintconst(0)
 	c.SetVal(Val{new(NilVal)})
-	c.Type = Types[TNIL]
+	c.Type = types.Types[TNIL]
 	return c
 }
 
 func nodbool(b bool) *Node {
 	c := nodintconst(0)
 	c.SetVal(Val{b})
-	c.Type = idealbool
+	c.Type = types.Idealbool
 	return c
 }
 
 // treecopy recursively copies n, with the exception of
 // ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
 // Copies of iota ONONAME nodes are assigned the current
-// value of iota_. If lineno != 0, it sets the line number
-// of newly allocated nodes to lineno.
-func treecopy(n *Node, lineno int32) *Node {
+// value of iota_. If pos.IsKnown(), it sets the source
+// position of newly allocated nodes to pos.
+func treecopy(n *Node, pos src.XPos) *Node {
 	if n == nil {
 		return nil
 	}
@@ -484,11 +462,11 @@ func treecopy(n *Node, lineno int32) *Node {
 	default:
 		m := *n
 		m.Orig = &m
-		m.Left = treecopy(n.Left, lineno)
-		m.Right = treecopy(n.Right, lineno)
-		m.List.Set(listtreecopy(n.List.Slice(), lineno))
-		if lineno != 0 {
-			m.Lineno = lineno
+		m.Left = treecopy(n.Left, pos)
+		m.Right = treecopy(n.Right, pos)
+		m.List.Set(listtreecopy(n.List.Slice(), pos))
+		if pos.IsKnown() {
+			m.Pos = pos
 		}
 		if m.Name != nil && n.Op != ODCLFIELD {
 			Dump("treecopy", n)
@@ -496,28 +474,13 @@ func treecopy(n *Node, lineno int32) *Node {
 		}
 		return &m
 
-	case ONONAME:
-		if n.Sym == lookup("iota") {
-			// Not sure yet whether this is the real iota,
-			// but make a copy of the Node* just in case,
-			// so that all the copies of this const definition
-			// don't have the same iota value.
-			m := *n
-			if lineno != 0 {
-				m.Lineno = lineno
-			}
-			m.SetIota(iota_)
-			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:
+	case ONAME, ONONAME, OLITERAL, OTYPE:
 		return n
 
 	}
@@ -530,7 +493,7 @@ func isnil(n *Node) bool {
 	return Isconst(n.Orig, CTNIL)
 }
 
-func isptrto(t *Type, et EType) bool {
+func isptrto(t *types.Type, et types.EType) bool {
 	if t == nil {
 		return false
 	}
@@ -551,17 +514,13 @@ func isblank(n *Node) bool {
 	if n == nil {
 		return false
 	}
-	return isblanksym(n.Sym)
-}
-
-func isblanksym(s *Sym) bool {
-	return s != nil && s.Name == "_"
+	return n.Sym.IsBlank()
 }
 
 // methtype returns the underlying type, if any,
 // that owns methods with receiver parameter t.
 // The result is either a named type or an anonymous struct.
-func methtype(t *Type) *Type {
+func methtype(t *types.Type) *types.Type {
 	if t == nil {
 		return nil
 	}
@@ -593,44 +552,31 @@ func methtype(t *Type) *Type {
 	return nil
 }
 
-func cplxsubtype(et EType) EType {
-	switch et {
-	case TCOMPLEX64:
-		return TFLOAT32
-
-	case TCOMPLEX128:
-		return TFLOAT64
-	}
-
-	Fatalf("cplxsubtype: %v\n", et)
-	return 0
-}
-
 // 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, t2 *Type) bool {
+func eqtype(t1, t2 *types.Type) bool {
 	return eqtype1(t1, t2, true, nil)
 }
 
 // eqtypeIgnoreTags is like eqtype but it ignores struct tags for struct identity.
-func eqtypeIgnoreTags(t1, t2 *Type) bool {
+func eqtypeIgnoreTags(t1, t2 *types.Type) bool {
 	return eqtype1(t1, t2, false, nil)
 }
 
 type typePair struct {
-	t1 *Type
-	t2 *Type
+	t1 *types.Type
+	t2 *types.Type
 }
 
-func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) bool {
+func eqtype1(t1, t2 *types.Type, cmpTags bool, assumedEqual map[typePair]struct{}) bool {
 	if t1 == t2 {
 		return true
 	}
-	if t1 == nil || t2 == nil || t1.Etype != t2.Etype || t1.Broke || t2.Broke {
+	if t1 == nil || t2 == nil || t1.Etype != t2.Etype || t1.Broke() || t2.Broke() {
 		return false
 	}
 	if t1.Sym != nil || t2.Sym != nil {
@@ -638,9 +584,9 @@ func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) boo
 		// separate for error messages. Treat them as equal.
 		switch t1.Etype {
 		case TUINT8:
-			return (t1 == Types[TUINT8] || t1 == bytetype) && (t2 == Types[TUINT8] || t2 == bytetype)
+			return (t1 == types.Types[TUINT8] || t1 == types.Bytetype) && (t2 == types.Types[TUINT8] || t2 == types.Bytetype)
 		case TINT32:
-			return (t1 == Types[TINT32] || t1 == runetype) && (t2 == Types[TINT32] || t2 == runetype)
+			return (t1 == types.Types[TINT32] || t1 == types.Runetype) && (t2 == types.Types[TINT32] || t2 == types.Runetype)
 		default:
 			return false
 		}
@@ -654,36 +600,49 @@ func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) boo
 	assumedEqual[typePair{t1, t2}] = struct{}{}
 
 	switch t1.Etype {
-	case TINTER, TSTRUCT:
-		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, cmpTags, assumedEqual) || cmpTags && t1.Note != t2.Note {
+	case TINTER:
+		if t1.NumFields() != t2.NumFields() {
+			return false
+		}
+		for i, f1 := range t1.FieldSlice() {
+			f2 := t2.Field(i)
+			if f1.Sym != f2.Sym || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
 				return false
 			}
 		}
+		return true
 
-		if t1 == nil && t2 == nil {
-			return true
+	case TSTRUCT:
+		if t1.NumFields() != t2.NumFields() {
+			return false
 		}
-		return false
+		for i, f1 := range t1.FieldSlice() {
+			f2 := t2.Field(i)
+			if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
+				return false
+			}
+			if cmpTags && f1.Note != f2.Note {
+				return false
+			}
+		}
+		return true
 
 	case TFUNC:
 		// 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 {
+		for _, f := range types.ParamsResults {
 			// Loop over fields in structs, ignoring argument names.
-			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, cmpTags, assumedEqual) {
+			fs1, fs2 := f(t1).FieldSlice(), f(t2).FieldSlice()
+			if len(fs1) != len(fs2) {
+				return false
+			}
+			for i, f1 := range fs1 {
+				f2 := fs2[i]
+				if f1.Isddd() != f2.Isddd() || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
 					return false
 				}
 			}
-			if ta != nil || tb != nil {
-				return false
-			}
 		}
 		return true
 
@@ -710,36 +669,34 @@ func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) boo
 // 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 {
+func eqtypenoname(t1 *types.Type, t2 *types.Type) bool {
 	if t1 == nil || t2 == nil || !t1.IsStruct() || !t2.IsStruct() {
 		return false
 	}
 
-	f1, i1 := iterFields(t1)
-	f2, i2 := iterFields(t2)
-	for {
+	if t1.NumFields() != t2.NumFields() {
+		return false
+	}
+	for i, f1 := range t1.FieldSlice() {
+		f2 := t2.Field(i)
 		if !eqtype(f1.Type, f2.Type) {
 			return false
 		}
-		if f1 == nil {
-			return true
-		}
-		f1 = i1.Next()
-		f2 = i2.Next()
 	}
+	return true
 }
 
 // Is type src assignment compatible to type dst?
 // If so, return op code to use in conversion.
 // If not, return 0.
-func assignop(src *Type, dst *Type, why *string) Op {
+func assignop(src *types.Type, dst *types.Type, why *string) Op {
 	if why != nil {
 		*why = ""
 	}
 
 	// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
 	// https://golang.org/issue/2795
-	if safemode && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
+	if safemode && !inimport && src != nil && src.Etype == TUNSAFEPTR {
 		yyerror("cannot use unsafe.Pointer")
 		errorexit()
 	}
@@ -760,28 +717,40 @@ func assignop(src *Type, dst *Type, why *string) Op {
 	// and either src or dst is not a named type or
 	// both are empty interface types.
 	// For assignable but different non-empty interface types,
-	// we want to recompute the itab.
-	if eqtype(src.Orig, dst.Orig) && (src.Sym == nil || dst.Sym == nil || src.IsEmptyInterface()) {
-		return OCONVNOP
+	// we want to recompute the itab. Recomputing the itab ensures
+	// that itabs are unique (thus an interface with a compile-time
+	// type I has an itab with interface type I).
+	if eqtype(src.Orig, dst.Orig) {
+		if src.IsEmptyInterface() {
+			// Conversion between two empty interfaces
+			// requires no code.
+			return OCONVNOP
+		}
+		if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
+			// Conversion between two types, at least one unnamed,
+			// needs no conversion. The exception is nonempty interfaces
+			// which need to have their itab updated.
+			return OCONVNOP
+		}
 	}
 
 	// 3. dst is an interface type and src implements dst.
 	if dst.IsInterface() && src.Etype != TNIL {
-		var missing, have *Field
+		var missing, have *types.Field
 		var ptr int
 		if implements(src, dst, &missing, &have, &ptr) {
 			return OCONVIFACE
 		}
 
 		// we'll have complained about this method anyway, suppress spurious messages.
-		if have != nil && have.Sym == missing.Sym && (have.Type.Broke || missing.Type.Broke) {
+		if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
 			return OCONVIFACE
 		}
 
 		if why != nil {
 			if isptrto(src, TINTER) {
 				*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
-			} else if have != nil && have.Sym == missing.Sym && have.Nointerface {
+			} 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"+
@@ -807,7 +776,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
 	}
 
 	if src.IsInterface() && dst.Etype != TBLANK {
-		var missing, have *Field
+		var missing, have *types.Field
 		var ptr int
 		if why != nil && implements(dst, src, &missing, &have, &ptr) {
 			*why = ": need type assertion"
@@ -818,7 +787,7 @@ 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.IsChan() && src.ChanDir() == Cboth && dst.IsChan() {
+	if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
 		if eqtype(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
 			return OCONVNOP
 		}
@@ -851,7 +820,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
 // Can we convert a value of type src to a value of type dst?
 // If so, return op code to use in conversion (maybe OCONVNOP).
 // If not, return 0.
-func convertop(src *Type, dst *Type, why *string) Op {
+func convertop(src *types.Type, dst *types.Type, why *string) Op {
 	if why != nil {
 		*why = ""
 	}
@@ -866,7 +835,7 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	// Conversions from regular to go:notinheap are not allowed
 	// (unless it's unsafe.Pointer). This is a runtime-specific
 	// rule.
-	if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap && !src.Elem().NotInHeap {
+	if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
 		if why != nil {
 			*why = fmt.Sprintf(":\n\t%v is go:notinheap, but %v is not", dst.Elem(), src.Elem())
 		}
@@ -926,10 +895,10 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	}
 
 	if src.IsSlice() && dst.IsString() {
-		if src.Elem().Etype == bytetype.Etype {
+		if src.Elem().Etype == types.Bytetype.Etype {
 			return OARRAYBYTESTR
 		}
-		if src.Elem().Etype == runetype.Etype {
+		if src.Elem().Etype == types.Runetype.Etype {
 			return OARRAYRUNESTR
 		}
 	}
@@ -937,10 +906,10 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	// 7. src is a string and dst is []byte or []rune.
 	// String to slice.
 	if src.IsString() && dst.IsSlice() {
-		if dst.Elem().Etype == bytetype.Etype {
+		if dst.Elem().Etype == types.Bytetype.Etype {
 			return OSTRARRAYBYTE
 		}
-		if dst.Elem().Etype == runetype.Etype {
+		if dst.Elem().Etype == types.Runetype.Etype {
 			return OSTRARRAYRUNE
 		}
 	}
@@ -958,13 +927,13 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	return 0
 }
 
-func assignconv(n *Node, t *Type, context string) *Node {
+func assignconv(n *Node, t *types.Type, context string) *Node {
 	return assignconvfn(n, t, func() string { return context })
 }
 
 // Convert node n for assignment to type t.
-func assignconvfn(n *Node, t *Type, context func() string) *Node {
-	if n == nil || n.Type == nil || n.Type.Broke {
+func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
+	if n == nil || n.Type == nil || n.Type.Broke() {
 		return n
 	}
 
@@ -973,22 +942,22 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
 	}
 
 	old := n
-	od := old.Diag
-	old.Diag = true // silence errors about n; we'll issue one below
+	od := old.Diag()
+	old.SetDiag(true) // silence errors about n; we'll issue one below
 	n = defaultlit(n, t)
-	old.Diag = od
+	old.SetDiag(od)
 	if t.Etype == TBLANK {
 		return n
 	}
 
 	// Convert ideal bool from comparison to plain bool
 	// if the next step is non-bool (like interface{}).
-	if n.Type == idealbool && !t.IsBoolean() {
+	if n.Type == types.Idealbool && !t.IsBoolean() {
 		if n.Op == ONAME || n.Op == OLITERAL {
 			r := nod(OCONVNOP, n, nil)
-			r.Type = Types[TBOOL]
-			r.Typecheck = 1
-			r.Implicit = true
+			r.Type = types.Types[TBOOL]
+			r.SetTypecheck(1)
+			r.SetImplicit(true)
 			n = r
 		}
 	}
@@ -1000,14 +969,16 @@ 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 %L as type %v in %s%s", n, t, context(), why)
+		if !old.Diag() {
+			yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
+		}
 		op = OCONV
 	}
 
 	r := nod(op, n, nil)
 	r.Type = t
-	r.Typecheck = 1
-	r.Implicit = true
+	r.SetTypecheck(1)
+	r.SetImplicit(true)
 	r.Orig = n.Orig
 	return r
 }
@@ -1050,7 +1021,7 @@ func (n *Node) SetSliceBounds(low, high, max *Node) {
 			if low == nil && high == nil {
 				return
 			}
-			n.List.Set([]*Node{low, high})
+			n.List.Set2(low, high)
 			return
 		}
 		s[0] = low
@@ -1062,7 +1033,7 @@ func (n *Node) SetSliceBounds(low, high, max *Node) {
 			if low == nil && high == nil && max == nil {
 				return
 			}
-			n.List.Set([]*Node{low, high, max})
+			n.List.Set3(low, high, max)
 			return
 		}
 		s[0] = low
@@ -1086,40 +1057,40 @@ func (o Op) IsSlice3() bool {
 	return false
 }
 
+// labeledControl returns the control flow Node (for, switch, select)
+// associated with the label n, if any.
+func (n *Node) labeledControl() *Node {
+	if n.Op != OLABEL {
+		Fatalf("labeledControl %v", n.Op)
+	}
+	ctl := n.Name.Defn
+	if ctl == nil {
+		return nil
+	}
+	switch ctl.Op {
+	case OFOR, OFORUNTIL, OSWITCH, OSELECT:
+		return ctl
+	}
+	return nil
+}
+
 func syslook(name string) *Node {
-	s := Pkglookup(name, Runtimepkg)
+	s := Runtimepkg.Lookup(name)
 	if s == nil || s.Def == nil {
 		Fatalf("syslook: can't find runtime.%s", name)
 	}
-	return s.Def
+	return asNode(s.Def)
 }
 
-// typehash computes a hash value for type t to use in type switch
-// statements.
-func typehash(t *Type) uint32 {
-	// t.tconv(FmtLeft | FmtUnsigned) already contains all the necessary logic
-	// to generate a representation that completely describes the type, so using
-	// it here avoids duplicating that code.
-	// See the comments in exprSwitch.checkDupCases.
-	p := t.tconv(FmtLeft | FmtUnsigned)
+// typehash computes a hash value for type t to use in type switch statements.
+func typehash(t *types.Type) uint32 {
+	p := t.LongString()
 
 	// Using MD5 is overkill, but reduces accidental collisions.
 	h := md5.Sum([]byte(p))
 	return binary.LittleEndian.Uint32(h[:4])
 }
 
-// ptrto returns the Type *t.
-// The returned struct must not be modified.
-func ptrto(t *Type) *Type {
-	if Tptr == 0 {
-		Fatalf("ptrto: no tptr")
-	}
-	if t == nil {
-		Fatalf("ptrto: nil ptr")
-	}
-	return typPtr(t)
-}
-
 func frame(context int) {
 	if context != 0 {
 		fmt.Printf("--- external frame ---\n")
@@ -1150,71 +1121,62 @@ func printframenode(n *Node) {
 	}
 }
 
-// calculate sethi/ullman number
-// roughly how many registers needed to
-// compile a node. used to compile the
-// hardest side first to minimize registers.
-func ullmancalc(n *Node) {
+// updateHasCall checks whether expression n contains any function
+// calls and sets the n.HasCall flag if so.
+func updateHasCall(n *Node) {
 	if n == nil {
 		return
 	}
 
-	var ul int
-	var ur int
+	b := false
 	if n.Ninit.Len() != 0 {
-		ul = UINF
+		// TODO(mdempsky): This seems overly conservative.
+		b = true
 		goto out
 	}
 
 	switch n.Op {
-	case OLITERAL, ONAME:
-		ul = 1
-		if n.Class == PAUTOHEAP {
-			ul++
+	case OLITERAL, ONAME, OTYPE:
+		if b || n.HasCall() {
+			Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
 		}
+		return
+	case OAS:
+		if needwritebarrier(n.Left) {
+			b = true
+			goto out
+		}
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
+		b = true
 		goto out
-
-	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OASWB:
-		ul = UINF
-		goto out
-
-		// hard with instrumented code
 	case OANDAND, OOROR:
+		// hard with instrumented code
 		if instrumenting {
-			ul = UINF
+			b = true
 			goto out
 		}
 	case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR,
 		OIND, ODOTPTR, ODOTTYPE, ODIV, OMOD:
 		// These ops might panic, make sure they are done
 		// before we start marshaling args for a call. See issue 16760.
-		ul = UINF
+		b = true
 		goto out
 	}
 
-	ul = 1
-	if n.Left != nil {
-		ul = int(n.Left.Ullman)
-	}
-	ur = 1
-	if n.Right != nil {
-		ur = int(n.Right.Ullman)
-	}
-	if ul == ur {
-		ul += 1
+	if n.Left != nil && n.Left.HasCall() {
+		b = true
+		goto out
 	}
-	if ur > ul {
-		ul = ur
+	if n.Right != nil && n.Right.HasCall() {
+		b = true
+		goto out
 	}
 
 out:
-	if ul > 200 {
-		ul = 200 // clamp to uchar with room to grow
-	}
-	n.Ullman = uint8(ul)
+	n.SetHasCall(b)
 }
 
-func badtype(op Op, tl *Type, tr *Type) {
+func badtype(op Op, tl *types.Type, tr *types.Type) {
 	fmt_ := ""
 	if tl != nil {
 		fmt_ += fmt.Sprintf("\n\t%v", tl)
@@ -1343,7 +1305,7 @@ func safeexpr(n *Node, init *Nodes) *Node {
 	return cheapexpr(n, init)
 }
 
-func copyexpr(n *Node, t *Type, init *Nodes) *Node {
+func copyexpr(n *Node, t *types.Type, init *Nodes) *Node {
 	l := temp(t)
 	a := nod(OAS, l, n)
 	a = typecheck(a, Etop)
@@ -1368,7 +1330,7 @@ func cheapexpr(n *Node, init *Nodes) *Node {
 // A Dlist stores a pointer to a TFIELD Type embedded within
 // a TSTRUCT or TINTER Type.
 type Dlist struct {
-	field *Field
+	field *types.Field
 }
 
 // dotlist is used by adddot1 to record the path of embedded fields
@@ -1379,7 +1341,7 @@ var dotlist = make([]Dlist, 10)
 // 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 {
+func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
 	u := t
 	if u.IsPtr() {
 		u = u.Elem()
@@ -1418,13 +1380,13 @@ func lookdot0(s *Sym, t *Type, save **Field, ignorecase bool) int {
 // 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 {
+func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
+	if t.Recur() {
 		return
 	}
-	t.Trecur = 1
+	t.SetRecur(true)
 
-	var u *Type
+	var u *types.Type
 	d--
 	if d < 0 {
 		// We've reached our target depth. If t has any fields/methods
@@ -1464,7 +1426,7 @@ func adddot1(s *Sym, t *Type, d int, save **Field, ignorecase bool) (c int, more
 	}
 
 out:
-	t.Trecur = 0
+	t.SetRecur(false)
 	return c, more
 }
 
@@ -1472,7 +1434,7 @@ out:
 // 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) {
+func dotpath(s *types.Sym, t *types.Type, save **types.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
@@ -1499,8 +1461,8 @@ func dotpath(s *Sym, t *Type, save **Field, ignorecase bool) (path []Dlist, ambi
 // modify the tree with missing type names.
 func adddot(n *Node) *Node {
 	n.Left = typecheck(n.Left, Etype|Erv)
-	if n.Left.Diag {
-		n.Diag = true
+	if n.Left.Diag() {
+		n.SetDiag(true)
 	}
 	t := n.Left.Type
 	if t == nil {
@@ -1521,7 +1483,7 @@ func adddot(n *Node) *Node {
 		// 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
+			n.Left.SetImplicit(true)
 		}
 	case ambig:
 		yyerror("ambiguous selector %v", n)
@@ -1540,13 +1502,13 @@ func adddot(n *Node) *Node {
 // with unique tasks and they return
 // the actual methods.
 type Symlink struct {
-	field     *Field
+	field     *types.Field
 	followptr bool
 }
 
 var slist []Symlink
 
-func expand0(t *Type, followptr bool) {
+func expand0(t *types.Type, followptr bool) {
 	u := t
 	if u.IsPtr() {
 		followptr = true
@@ -1555,10 +1517,10 @@ func expand0(t *Type, followptr bool) {
 
 	if u.IsInterface() {
 		for _, f := range u.Fields().Slice() {
-			if f.Sym.Flags&SymUniq != 0 {
+			if f.Sym.Uniq() {
 				continue
 			}
-			f.Sym.Flags |= SymUniq
+			f.Sym.SetUniq(true)
 			slist = append(slist, Symlink{field: f, followptr: followptr})
 		}
 
@@ -1568,20 +1530,20 @@ func expand0(t *Type, followptr bool) {
 	u = methtype(t)
 	if u != nil {
 		for _, f := range u.Methods().Slice() {
-			if f.Sym.Flags&SymUniq != 0 {
+			if f.Sym.Uniq() {
 				continue
 			}
-			f.Sym.Flags |= SymUniq
+			f.Sym.SetUniq(true)
 			slist = append(slist, Symlink{field: f, followptr: followptr})
 		}
 	}
 }
 
-func expand1(t *Type, top, followptr bool) {
-	if t.Trecur != 0 {
+func expand1(t *types.Type, top, followptr bool) {
+	if t.Recur() {
 		return
 	}
-	t.Trecur = 1
+	t.SetRecur(true)
 
 	if !top {
 		expand0(t, followptr)
@@ -1608,10 +1570,10 @@ func expand1(t *Type, top, followptr bool) {
 	}
 
 out:
-	t.Trecur = 0
+	t.SetRecur(false)
 }
 
-func expandmeth(t *Type) {
+func expandmeth(t *types.Type) {
 	if t == nil || t.AllMethods().Len() != 0 {
 		return
 	}
@@ -1619,7 +1581,7 @@ func expandmeth(t *Type) {
 	// mark top-level method symbols
 	// so that expand1 doesn't consider them.
 	for _, f := range t.Methods().Slice() {
-		f.Sym.Flags |= SymUniq
+		f.Sym.SetUniq(true)
 	}
 
 	// generate all reachable methods
@@ -1627,12 +1589,12 @@ func expandmeth(t *Type) {
 	expand1(t, true, false)
 
 	// check each method to be uniquely reachable
-	var ms []*Field
+	var ms []*types.Field
 	for i, sl := range slist {
 		slist[i].field = nil
-		sl.field.Sym.Flags &^= SymUniq
+		sl.field.Sym.SetUniq(false)
 
-		var f *Field
+		var f *types.Field
 		if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
 			continue
 		}
@@ -1652,7 +1614,7 @@ func expandmeth(t *Type) {
 	}
 
 	for _, f := range t.Methods().Slice() {
-		f.Sym.Flags &^= SymUniq
+		f.Sym.SetUniq(false)
 	}
 
 	ms = append(ms, t.Methods().Slice()...)
@@ -1660,7 +1622,7 @@ func expandmeth(t *Type) {
 }
 
 // Given funarg struct list, return list of ODCLFIELD Node fn args.
-func structargs(tl *Type, mustname bool) []*Node {
+func structargs(tl *types.Type, mustname bool) []*Node {
 	var args []*Node
 	gen := 0
 	for _, t := range tl.Fields().Slice() {
@@ -1674,9 +1636,9 @@ func structargs(tl *Type, mustname bool) []*Node {
 			n = newname(t.Sym)
 		}
 		a := nod(ODCLFIELD, n, typenod(t.Type))
-		a.Isddd = t.Isddd
+		a.SetIsddd(t.Isddd())
 		if n != nil {
-			n.Isddd = t.Isddd
+			n.SetIsddd(t.Isddd())
 		}
 		args = append(args, a)
 	}
@@ -1705,53 +1667,40 @@ func structargs(tl *Type, mustname bool) []*Node {
 //	rcvr - U
 //	method - M func (t T)(), a TFIELD type struct
 //	newnam - the eventual mangled name of this function
-
-var genwrapper_linehistdone int = 0
-
-func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
+func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface int) {
 	if false && Debug['r'] != 0 {
 		fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
 	}
 
-	lexlineno++
-	lineno = lexlineno
-	if genwrapper_linehistdone == 0 {
-		// All the wrappers can share the same linehist entry.
-		linehistpush("<autogenerated>")
-
-		genwrapper_linehistdone = 1
-	}
+	lineno = autogeneratedPos
 
 	dclcontext = PEXTERN
-	markdcl()
+	types.Markdcl()
 
-	this := nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr))
+	this := namedfield(".this", rcvr)
 	this.Left.Name.Param.Ntype = this.Right
 	in := structargs(method.Type.Params(), true)
 	out := structargs(method.Type.Results(), false)
 
 	t := nod(OTFUNC, nil, nil)
 	l := []*Node{this}
-	if iface != 0 && rcvr.Width < Types[Tptr].Width {
+	if iface != 0 && rcvr.Width < int64(Widthptr) {
 		// 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 := typArray(Types[TUINT8], Types[Tptr].Width-rcvr.Width)
-		pad := nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad))
+		tpad := types.NewArray(types.Types[TUINT8], int64(Widthptr)-rcvr.Width)
+		pad := namedfield(".pad", tpad)
 		l = append(l, pad)
 	}
 
 	t.List.Set(append(l, in...))
 	t.Rlist.Set(out)
 
-	fn := nod(ODCLFUNC, nil, nil)
-	fn.Func.Nname = newname(newnam)
-	fn.Func.Nname.Name.Defn = fn
-	fn.Func.Nname.Name.Param.Ntype = t
-	declare(fn.Func.Nname, PFUNC)
-	funchdr(fn)
+	fn := dclfunc(newnam, t)
+	fn.Func.SetDupok(true)
+	fn.Func.Nname.Sym.SetExported(true) // prevent export; see closure.go
 
 	// arg list
 	var args []*Node
@@ -1759,7 +1708,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 	isddd := false
 	for _, n := range in {
 		args = append(args, n.Left)
-		isddd = n.Left.Isddd
+		isddd = n.Left.Isddd()
 	}
 
 	methodrcvr := method.Type.Recv().Type
@@ -1768,22 +1717,8 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 	if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
 		// generating wrapper from *T to T.
 		n := nod(OIF, nil, nil)
-
 		n.Left = nod(OEQ, this.Left, nodnil())
-
-		// these strings are already in the reflect tables,
-		// so no space cost to use them here.
-		var l []*Node
-
-		var v Val
-		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 = append(l, nodlit(v)) // method name
 		call := nod(OCALL, syslook("panicwrap"), nil)
-		call.List.Set(l)
 		n.Nbody.Set1(call)
 		fn.Nbody.Append(n)
 	}
@@ -1797,7 +1732,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 	// 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) {
+	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
 		// TODO(mdempsky): Remove dependency on dotlist.
@@ -1808,15 +1743,15 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 		as.Right.Type = rcvr
 		fn.Nbody.Append(as)
 		n := nod(ORETJMP, nil, nil)
-		n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
+		n.Left = newname(methodsym(method.Sym, methodrcvr, false))
 		fn.Nbody.Append(n)
 		// When tail-calling, we can't use a frame pointer.
-		fn.Func.NoFramePointer = true
+		fn.Func.SetNoFramePointer(true)
 	} else {
-		fn.Func.Wrapper = true // ignore frame for panic+recover matching
+		fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
 		call := nod(OCALL, dot, nil)
 		call.List.Set(args)
-		call.Isddd = isddd
+		call.SetIsddd(isddd)
 		if method.Type.Results().NumFields() > 0 {
 			n := nod(ORETURN, nil, nil)
 			n.List.Set1(call)
@@ -1832,14 +1767,14 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 
 	funcbody(fn)
 	Curfn = fn
-	popdcl()
+	types.Popdcl()
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
 
 	// wrappers where T is anonymous (struct or interface) can be duplicated.
 	if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
-		fn.Func.Dupok = true
+		fn.Func.SetDupok(true)
 	}
 	fn = typecheck(fn, Etop)
 	typecheckslice(fn.Nbody.Slice(), Etop)
@@ -1851,29 +1786,29 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 	funccompile(fn)
 }
 
-func hashmem(t *Type) *Node {
-	sym := Pkglookup("memhash", Runtimepkg)
+func hashmem(t *types.Type) *Node {
+	sym := Runtimepkg.Lookup("memhash")
 
 	n := newname(sym)
-	n.Class = PFUNC
+	n.SetClass(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.List.Append(nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
-	tfn.Rlist.Append(nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.List.Append(anonfield(types.NewPtr(t)))
+	tfn.List.Append(anonfield(types.Types[TUINTPTR]))
+	tfn.List.Append(anonfield(types.Types[TUINTPTR]))
+	tfn.Rlist.Append(anonfield(types.Types[TUINTPTR]))
 	tfn = typecheck(tfn, Etype)
 	n.Type = tfn.Type
 	return n
 }
 
-func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
+func ifacelookdot(s *types.Sym, t *types.Type, followptr *bool, ignorecase bool) *types.Field {
 	*followptr = false
 
 	if t == nil {
 		return nil
 	}
 
-	var m *Field
+	var m *types.Field
 	path, ambig := dotpath(s, t, &m, ignorecase)
 	if path == nil {
 		if ambig {
@@ -1897,7 +1832,7 @@ func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
 	return m
 }
 
-func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
+func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
 	t0 := t
 	if t == nil {
 		return false
@@ -1936,12 +1871,12 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
 		expandmeth(t)
 	}
 	for _, im := range iface.Fields().Slice() {
-		if im.Broke {
+		if im.Broke() {
 			continue
 		}
 		var followptr bool
 		tm := ifacelookdot(im.Sym, t, &followptr, false)
-		if tm == nil || tm.Nointerface || !eqtype(tm.Type, im.Type) {
+		if tm == nil || tm.Nointerface() || !eqtype(tm.Type, im.Type) {
 			if tm == nil {
 				tm = ifacelookdot(im.Sym, t, &followptr, true)
 			}
@@ -1967,36 +1902,21 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
 		}
 	}
 
-	return true
-}
-
-// even simpler simtype; get rid of ptr, bool.
-// assuming that the front end has rejected
-// all the invalid conversions (like ptr -> bool)
-func Simsimtype(t *Type) EType {
-	if t == nil {
-		return 0
+	// We're going to emit an OCONVIFACE.
+	// Call itabname so that (t, iface)
+	// gets added to itabs early, which allows
+	// us to de-virtualize calls through this
+	// type/interface pair later. See peekitabs in reflect.go
+	if isdirectiface(t0) && !iface.IsEmptyInterface() {
+		itabname(t0, iface)
 	}
-
-	et := simtype[t.Etype]
-	switch et {
-	case TPTR32:
-		et = TUINT32
-
-	case TPTR64:
-		et = TUINT64
-
-	case TBOOL:
-		et = TUINT8
-	}
-
-	return et
+	return true
 }
 
-func listtreecopy(l []*Node, lineno int32) []*Node {
+func listtreecopy(l []*Node, pos src.XPos) []*Node {
 	var out []*Node
 	for _, n := range l {
-		out = append(out, treecopy(n, lineno))
+		out = append(out, treecopy(n, pos))
 	}
 	return out
 }
@@ -2005,116 +1925,42 @@ func liststmt(l []*Node) *Node {
 	n := nod(OBLOCK, nil, nil)
 	n.List.Set(l)
 	if len(l) != 0 {
-		n.Lineno = l[0].Lineno
+		n.Pos = l[0].Pos
 	}
 	return n
 }
 
-// return power of 2 of the constant
-// operand. -1 if it is not a power of 2.
-// 1000+ if it is a -(power of 2)
-func powtwo(n *Node) int {
-	if n == nil || n.Op != OLITERAL || n.Type == nil {
-		return -1
-	}
-	if !n.Type.IsInteger() {
-		return -1
-	}
-
-	v := uint64(n.Int64())
-	b := uint64(1)
-	for i := 0; i < 64; i++ {
-		if b == v {
-			return i
-		}
-		b = b << 1
-	}
-
-	if !n.Type.IsSigned() {
-		return -1
-	}
-
-	v = -v
-	b = 1
-	for i := 0; i < 64; i++ {
-		if b == v {
-			return i + 1000
-		}
-		b = b << 1
+func (l Nodes) asblock() *Node {
+	n := nod(OBLOCK, nil, nil)
+	n.List = l
+	if l.Len() != 0 {
+		n.Pos = l.First().Pos
 	}
-
-	return -1
+	return n
 }
 
-func ngotype(n *Node) *Sym {
+func ngotype(n *Node) *types.Sym {
 	if n.Type != nil {
 		return typenamesym(n.Type)
 	}
 	return nil
 }
 
-// Convert raw string to the prefix that will be used in the symbol
-// table. All control characters, space, '%' and '"', as well as
-// non-7-bit clean bytes turn into %xx. The period needs escaping
-// only in the last segment of the path, and it makes for happier
-// users if we escape that as little as possible.
-//
-// If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
-func pathtoprefix(s string) string {
-	slash := strings.LastIndex(s, "/")
-	for i := 0; i < len(s); i++ {
-		c := s[i]
-		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			var buf bytes.Buffer
-			for i := 0; i < len(s); i++ {
-				c := s[i]
-				if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-					fmt.Fprintf(&buf, "%%%02x", c)
-					continue
-				}
-				buf.WriteByte(c)
-			}
-			return buf.String()
-		}
-	}
-	return s
-}
-
-var pkgMap = make(map[string]*Pkg)
-var pkgs []*Pkg
-
-func mkpkg(path string) *Pkg {
-	if p := pkgMap[path]; p != nil {
-		return p
-	}
-
-	p := new(Pkg)
-	p.Path = path
-	p.Prefix = pathtoprefix(path)
-	p.Syms = make(map[string]*Sym)
-	pkgMap[path] = p
-	pkgs = append(pkgs, p)
-	return p
-}
-
 // 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
 	}
-
-	switch n.Op {
-	// There may be multiple refs to this node;
-	// introduce OCONVNOP to hold init list.
-	case ONAME, OLITERAL:
+	if n.mayBeShared() {
+		// Introduce OCONVNOP to hold init list.
 		n = nod(OCONVNOP, n, nil)
 		n.Type = n.Left.Type
-		n.Typecheck = 1
+		n.SetTypecheck(1)
 	}
 
 	n.Ninit.Prepend(init...)
-	n.Ullman = UINF
+	n.SetHasCall(true)
 	return n
 }
 
@@ -2174,13 +2020,13 @@ func checknil(x *Node, init *Nodes) {
 	}
 
 	n := nod(OCHECKNIL, x, nil)
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 	init.Append(n)
 }
 
 // Can this type be stored directly in an interface word?
 // Yes, if the representation is a single pointer.
-func isdirectiface(t *Type) bool {
+func isdirectiface(t *types.Type) bool {
 	switch t.Etype {
 	case TPTR32,
 		TPTR64,
@@ -2205,41 +2051,28 @@ func isdirectiface(t *Type) bool {
 // itabType loads the _type field from a runtime.itab struct.
 func itabType(itab *Node) *Node {
 	typ := nodSym(ODOTPTR, itab, nil)
-	typ.Type = ptrto(Types[TUINT8])
-	typ.Typecheck = 1
+	typ.Type = types.NewPtr(types.Types[TUINT8])
+	typ.SetTypecheck(1)
 	typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
-	typ.Bounded = true            // guaranteed not to fault
+	typ.SetBounded(true)          // guaranteed not to fault
 	return typ
 }
 
 // ifaceData loads the data field from an interface.
 // The concrete type must be known to have type t.
 // It follows the pointer if !isdirectiface(t).
-func ifaceData(n *Node, t *Type) *Node {
+func ifaceData(n *Node, t *types.Type) *Node {
 	ptr := nodSym(OIDATA, n, nil)
 	if isdirectiface(t) {
 		ptr.Type = t
-		ptr.Typecheck = 1
+		ptr.SetTypecheck(1)
 		return ptr
 	}
-	ptr.Type = ptrto(t)
-	ptr.Bounded = true
-	ptr.Typecheck = 1
+	ptr.Type = types.NewPtr(t)
+	ptr.SetBounded(true)
+	ptr.SetTypecheck(1)
 	ind := nod(OIND, ptr, nil)
 	ind.Type = t
-	ind.Typecheck = 1
+	ind.SetTypecheck(1)
 	return ind
 }
-
-// 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 (t *Type) iet() byte {
-	if t.IsEmptyInterface() {
-		return 'E'
-	}
-	if t.IsInterface() {
-		return 'I'
-	}
-	return 'T'
-}
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 3d3496d..1b76650 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -4,7 +4,11 @@
 
 package gc
 
-import "sort"
+import (
+	"cmd/compile/internal/types"
+	"fmt"
+	"sort"
+)
 
 const (
 	// expression switch
@@ -52,12 +56,11 @@ type caseClauses struct {
 
 // typecheckswitch typechecks a switch statement.
 func typecheckswitch(n *Node) {
-	lno := lineno
 	typecheckslice(n.Ninit.Slice(), Etop)
 
 	var nilonly string
 	var top int
-	var t *Type
+	var t *types.Type
 
 	if n.Left != nil && n.Left.Op == OTYPESW {
 		// type switch
@@ -65,7 +68,7 @@ func typecheckswitch(n *Node) {
 		n.Left.Right = typecheck(n.Left.Right, Erv)
 		t = n.Left.Right.Type
 		if t != nil && !t.IsInterface() {
-			yyerror("cannot type switch on non-interface value %L", n.Left.Right)
+			yyerrorl(n.Pos, "cannot type switch on non-interface value %L", n.Left.Right)
 		}
 	} else {
 		// expression switch
@@ -75,19 +78,19 @@ func typecheckswitch(n *Node) {
 			n.Left = defaultlit(n.Left, nil)
 			t = n.Left.Type
 		} else {
-			t = Types[TBOOL]
+			t = types.Types[TBOOL]
 		}
 		if t != nil {
 			switch {
 			case !okforeq[t.Etype]:
-				yyerror("cannot switch on %L", n.Left)
+				yyerrorl(n.Pos, "cannot switch on %L", n.Left)
 			case t.IsSlice():
 				nilonly = "slice"
-			case t.IsArray() && !t.IsComparable():
-				yyerror("cannot switch on %L", n.Left)
+			case t.IsArray() && !IsComparable(t):
+				yyerrorl(n.Pos, "cannot switch on %L", n.Left)
 			case t.IsStruct():
-				if f := t.IncomparableField(); f != nil {
-					yyerror("cannot switch on %L (struct containing %v cannot be compared)", n.Left, f.Type)
+				if f := IncomparableField(t); f != nil {
+					yyerrorl(n.Pos, "cannot switch on %L (struct containing %v cannot be compared)", n.Left, f.Type)
 				}
 			case t.Etype == TFUNC:
 				nilonly = "func"
@@ -101,12 +104,11 @@ func typecheckswitch(n *Node) {
 
 	var def, niltype *Node
 	for _, ncase := range n.List.Slice() {
-		setlineno(n)
 		if ncase.List.Len() == 0 {
 			// default
 			if def != nil {
 				setlineno(ncase)
-				yyerror("multiple defaults in switch (first at %v)", def.Line())
+				yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", def.Line())
 			} else {
 				def = ncase
 			}
@@ -119,6 +121,7 @@ func typecheckswitch(n *Node) {
 				if n1.Type == nil || t == nil {
 					continue
 				}
+
 				setlineno(ncase)
 				switch top {
 				// expression switch
@@ -127,70 +130,85 @@ func typecheckswitch(n *Node) {
 					n1 = ls[i1]
 					switch {
 					case n1.Op == OTYPE:
-						yyerror("type %v is not an expression", n1.Type)
+						yyerrorl(ncase.Pos, "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)", n1, n.Left, n1.Type, t)
+							yyerrorl(ncase.Pos, "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)", n1, n1.Type)
+							yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
 						}
 					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 %L in switch (incomparable type)", n1)
+						yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
+					case t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type):
+						yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
 					}
 
 				// type switch
 				case Etype:
-					var missing, have *Field
+					var missing, have *types.Field
 					var ptr int
 					switch {
 					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())
+							yyerrorl(ncase.Pos, "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("%L is not a type", n1)
+						yyerrorl(ncase.Pos, "%L is not a type", n1)
 						// reset to original type
 						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: %L cannot have dynamic type %v"+
+						if have != nil && !missing.Broke() && !have.Broke() {
+							yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
 								" (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left.Right, n1.Type, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
-						} else if !missing.Broke {
-							yyerror("impossible type switch case: %L cannot have dynamic type %v"+
-								" (missing %v method)", n.Left.Right, n1.Type, missing.Sym)
+						} else if !missing.Broke() {
+							if ptr != 0 {
+								yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
+									" (%v method has pointer receiver)", n.Left.Right, n1.Type, missing.Sym)
+							} else {
+								yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
+									" (missing %v method)", n.Left.Right, n1.Type, missing.Sym)
+							}
 						}
 					}
 				}
 			}
 		}
 
-		if top == Etype && n.Type != nil {
+		if n.Type == nil || n.Type.IsUntyped() {
+			// if the value we're switching on has no type or is untyped,
+			// we've already printed an error and don't need to continue
+			// typechecking the body
+			return
+		}
+
+		if top == Etype {
 			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.First().Type)
+					nvar.Type = ll.First().Type
 				} else {
 					// multiple entry type switch or default
-					nvar.Name.Param.Ntype = typenod(n.Type)
+					nvar.Type = n.Type
 				}
 
 				nvar = typecheck(nvar, Erv|Easgn)
-				ncase.Rlist.SetIndex(0, nvar)
+				ncase.Rlist.SetFirst(nvar)
 			}
 		}
 
 		typecheckslice(ncase.Nbody.Slice(), Etop)
 	}
-
-	lineno = lno
+	switch top {
+	// expression switch
+	case Erv:
+		checkDupExprCases(n.Left, n.List.Slice())
+	}
 }
 
 // walkswitch walks a switch statement.
@@ -511,9 +529,6 @@ func (s *exprSwitch) genCaseClauses(clauses []*Node) caseClauses {
 	if cc.defjmp == nil {
 		cc.defjmp = nod(OBREAK, nil, nil)
 	}
-
-	// diagnose duplicate cases
-	s.checkDupCases(cc.list)
 	return cc
 }
 
@@ -578,7 +593,7 @@ Outer:
 		}
 		for _, n := range prev {
 			if eqtype(n.Left.Type, c.node.Left.Type) {
-				yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
+				yyerrorl(c.node.Pos, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
 				// avoid double-reporting errors
 				continue Outer
 			}
@@ -587,20 +602,18 @@ Outer:
 	}
 }
 
-func (s *exprSwitch) checkDupCases(cc []caseClause) {
-	if len(cc) < 2 {
+func checkDupExprCases(exprname *Node, clauses []*Node) {
+	// boolean (naked) switch, nothing to do.
+	if exprname == nil {
 		return
 	}
 	// The common case is that s's expression is not an interface.
 	// In that case, all constant clauses have the same type,
 	// so checking for duplicates can be done solely by value.
-	if !s.exprname.Type.IsInterface() {
+	if !exprname.Type.IsInterface() {
 		seen := make(map[interface{}]*Node)
-		for _, c := range cc {
-			switch {
-			case c.node.Left != nil:
-				// Single constant.
-
+		for _, ncase := range clauses {
+			for _, n := range ncase.List.Slice() {
 				// Can't check for duplicates that aren't constants, per the spec. Issue 15896.
 				// Don't check for duplicate bools. Although the spec allows it,
 				// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
@@ -608,35 +621,18 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
 				//       case GOARCH == "arm" && GOARM == "5":
 				//       case GOARCH == "arm":
 				//     which would both evaluate to false for non-ARM compiles.
-				if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
+				if ct := consttype(n); ct < 0 || ct == CTBOOL {
 					continue
 				}
 
-				val := c.node.Left.Val().Interface()
+				val := n.Val().Interface()
 				prev, dup := seen[val]
 				if !dup {
-					seen[val] = c.node
+					seen[val] = n
 					continue
 				}
-				setlineno(c.node)
-				yyerror("duplicate case %#v in switch\n\tprevious case at %v", val, prev.Line())
-
-			case c.node.List.Len() == 2:
-				// Range of integers.
-				low := c.node.List.Index(0).Int64()
-				high := c.node.List.Index(1).Int64()
-				for i := low; i <= high; i++ {
-					prev, dup := seen[i]
-					if !dup {
-						seen[i] = c.node
-						continue
-					}
-					setlineno(c.node)
-					yyerror("duplicate case %d in switch\n\tprevious case at %v", i, prev.Line())
-				}
-
-			default:
-				Fatalf("bad caseClause node in checkDupCases: %v", c.node)
+				yyerrorl(ncase.Pos, "duplicate case %s in switch\n\tprevious case at %v",
+					nodeAndVal(n), prev.Line())
 			}
 		}
 		return
@@ -648,27 +644,35 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
 		val interface{}
 	}
 	seen := make(map[typeVal]*Node)
-	for _, c := range cc {
-		if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
-			continue
-		}
-		n := c.node.Left
-		tv := typeVal{
-			// n.Type.tconv(FmtLeft | FmtUnsigned) here serves to completely describe the type.
-			// See the comments in func typehash.
-			typ: n.Type.tconv(FmtLeft | FmtUnsigned),
-			val: n.Val().Interface(),
-		}
-		prev, dup := seen[tv]
-		if !dup {
-			seen[tv] = c.node
-			continue
+	for _, ncase := range clauses {
+		for _, n := range ncase.List.Slice() {
+			if ct := consttype(n); ct < 0 || ct == CTBOOL {
+				continue
+			}
+			tv := typeVal{
+				typ: n.Type.LongString(),
+				val: n.Val().Interface(),
+			}
+			prev, dup := seen[tv]
+			if !dup {
+				seen[tv] = n
+				continue
+			}
+			yyerrorl(ncase.Pos, "duplicate case %s in switch\n\tprevious case at %v",
+				nodeAndVal(n), prev.Line())
 		}
-		setlineno(c.node)
-		yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line())
 	}
 }
 
+func nodeAndVal(n *Node) string {
+	show := n.String()
+	val := n.Val().Interface()
+	if s := fmt.Sprintf("%#v", val); show != s {
+		show += " (value " + s + ")"
+	}
+	return show
+}
+
 // walk generates an AST that implements sw,
 // where sw is a type switch.
 // The AST is generally of the form of a linear
@@ -703,10 +707,10 @@ func (s *typeSwitch) walk(sw *Node) {
 	a = typecheck(a, Etop)
 	cas = append(cas, a)
 
-	s.okname = temp(Types[TBOOL])
+	s.okname = temp(types.Types[TBOOL])
 	s.okname = typecheck(s.okname, Erv)
 
-	s.hashname = temp(Types[TUINT32])
+	s.hashname = temp(types.Types[TUINT32])
 	s.hashname = typecheck(s.hashname, Erv)
 
 	// set up labels and jumps
@@ -724,11 +728,13 @@ func (s *typeSwitch) walk(sw *Node) {
 	// Use a similar strategy for non-empty interfaces.
 
 	// Get interface descriptor word.
-	typ := nod(OITAB, s.facename, nil)
+	// For empty interfaces this will be the type.
+	// For non-empty interfaces this will be the itab.
+	itab := nod(OITAB, s.facename, nil)
 
 	// Check for nil first.
 	i := nod(OIF, nil, nil)
-	i.Left = nod(OEQ, typ, nodnil())
+	i.Left = nod(OEQ, itab, nodnil())
 	if clauses.niljmp != nil {
 		// Do explicit nil case right here.
 		i.Nbody.Set1(clauses.niljmp)
@@ -738,22 +744,22 @@ func (s *typeSwitch) walk(sw *Node) {
 		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})
+		blk.List.Set2(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 = itabType(typ)
+	// Load hash from type or itab.
+	h := nodSym(ODOTPTR, itab, nil)
+	h.Type = types.Types[TUINT32]
+	h.SetTypecheck(1)
+	if cond.Right.Type.IsEmptyInterface() {
+		h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
+	} else {
+		h.Xoffset = int64(3 * Widthptr) // offset of hash in runtime.itab
 	}
-	// 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
+	h.SetBounded(true) // guaranteed not to fault
 	a = nod(OAS, s.hashname, h)
 	a = typecheck(a, Etop)
 	cas = append(cas, a)
@@ -820,31 +826,33 @@ 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 []*Node
+	var init Nodes
 	if t.Rlist.Len() == 0 {
 		name = nblank
 		nblank = typecheck(nblank, Erv|Easgn)
 	} else {
 		name = t.Rlist.First()
-		init = []*Node{nod(ODCL, name, nil)}
+		init.Append(nod(ODCL, name, nil))
 		a := nod(OAS, name, nil)
 		a = typecheck(a, Etop)
-		init = append(init, a)
+		init.Append(a)
 	}
 
 	a := nod(OAS2, nil, nil)
-	a.List.Set([]*Node{name, s.okname}) // name, ok =
+	a.List.Set2(name, s.okname) // name, ok =
 	b := nod(ODOTTYPE, s.facename, nil)
 	b.Type = t.Left.Type // interface.(type)
 	a.Rlist.Set1(b)
 	a = typecheck(a, Etop)
-	init = append(init, a)
+	a = walkexpr(a, &init)
+	init.Append(a)
 
 	c := nod(OIF, nil, nil)
 	c.Left = s.okname
 	c.Nbody.Set1(t.Right) // if ok { goto l }
 
-	return liststmt(append(init, c))
+	init.Append(c)
+	return init.asblock()
 }
 
 // walkCases generates an AST implementing the cases in cc.
diff --git a/src/cmd/compile/internal/gc/swt_test.go b/src/cmd/compile/internal/gc/swt_test.go
index 4139898..7441959 100644
--- a/src/cmd/compile/internal/gc/swt_test.go
+++ b/src/cmd/compile/internal/gc/swt_test.go
@@ -5,16 +5,20 @@
 package gc
 
 import (
-	"math/big"
 	"testing"
 )
 
 func nodrune(r rune) *Node {
-	return nodlit(Val{&Mpint{Val: *big.NewInt(int64(r)), Rune: true}})
+	v := new(Mpint)
+	v.SetInt64(int64(r))
+	v.Rune = true
+	return nodlit(Val{v})
 }
 
 func nodflt(f float64) *Node {
-	return nodlit(Val{&Mpflt{Val: *big.NewFloat(f)}})
+	v := new(Mpflt)
+	v.SetFloat64(f)
+	return nodlit(Val{v})
 }
 
 func TestCaseClauseByConstVal(t *testing.T) {
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 8848bb5..0fd146b 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -6,10 +6,17 @@
 
 package gc
 
+import (
+	"cmd/compile/internal/syntax"
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
+	"cmd/internal/src"
+)
+
 // A Node is a single node in the syntax tree.
 // Actually the syntax tree is a syntax DAG, because there is only one
 // node with Op=ONAME for a given instance of a variable x.
-// The same is true for Op=OTYPE and Op=OLITERAL.
+// The same is true for Op=OTYPE and Op=OLITERAL. See Node.mayBeShared.
 type Node struct {
 	// Tree structure.
 	// Generic recursive walks should follow these fields.
@@ -21,16 +28,16 @@ type Node struct {
 	Rlist Nodes
 
 	// most nodes
-	Type *Type
+	Type *types.Type
 	Orig *Node // original form, for printing, and tracking copies of ONAMEs
 
 	// func
 	Func *Func
 
-	// ONAME
+	// ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
 	Name *Name
 
-	Sym *Sym        // various
+	Sym *types.Sym  // various
 	E   interface{} // Opt or Val, see methods below
 
 	// Various. Usually an offset into a struct. For example:
@@ -38,38 +45,18 @@ type Node struct {
 	// - ODOT, ODOTPTR, and OINDREGSP use it to indicate offset relative to their base address.
 	// - OSTRUCTKEY uses it to store the named field's offset.
 	// - OXCASE and OXFALL use it to validate the use of fallthrough.
-	// - ONONAME uses it to store the current value of iota, see Node.Iota
+	// - Named OLITERALs use it to to store their ambient iota value.
 	// Possibly still more uses. If you find any, document them.
 	Xoffset int64
 
-	Lineno int32
+	Pos src.XPos
+
+	flags bitset32
 
 	Esc uint16 // EscXXX
 
-	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, for OINDEXMAP 1=LHS,0=RHS
-	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      bool  // already printed error about this
-	Noescape  bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
-	Walkdef   uint8 // tracks state during typecheckdef; 2 == loop detected
-	Typecheck uint8 // tracks state during typechecking; 2 == loop detected
-	Local     bool
-	IsStatic  bool // whether this Node will be converted to purely static data
-	Initorder uint8
-	Used      bool // for variable/label declared and not used error
-	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
+	Op    Op
+	Etype types.EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN, for OINDEXMAP 1=LHS,0=RHS
 }
 
 // IsAutoTmp indicates if n was created by the compiler as a temporary,
@@ -78,61 +65,96 @@ func (n *Node) IsAutoTmp() bool {
 	if n == nil || n.Op != ONAME {
 		return false
 	}
-	return n.Name.AutoTemp
+	return n.Name.AutoTemp()
 }
 
 const (
-	hasBreak = 1 << iota
-	isClosureVar
-	isOutputParamHeapAddr
-	noInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
+	nodeClass, _     = iota, 1 << iota // PPARAM, PAUTO, PEXTERN, etc; three bits; first in the list because frequently accessed
+	_, _                               // second nodeClass bit
+	_, _                               // third nodeClass bit
+	nodeWalkdef, _                     // tracks state during typecheckdef; 2 == loop detected; two bits
+	_, _                               // second nodeWalkdef bit
+	nodeTypecheck, _                   // tracks state during typechecking; 2 == loop detected; two bits
+	_, _                               // second nodeTypecheck bit
+	nodeInitorder, _                   // tracks state during init1; two bits
+	_, _                               // second nodeInitorder bit
+	_, nodeHasBreak
+	_, nodeIsClosureVar
+	_, nodeIsOutputParamHeapAddr
+	_, nodeNoInline  // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
+	_, nodeAssigned  // is the variable ever assigned to
+	_, nodeAddrtaken // address taken, even if not moved to heap
+	_, nodeImplicit
+	_, nodeIsddd    // is the argument variadic
+	_, nodeLocal    // type created in this file (see also Type.Local)
+	_, nodeDiag     // already printed error about this
+	_, nodeColas    // OAS resulting from :=
+	_, nodeNonNil   // guaranteed to be non-nil
+	_, nodeNoescape // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
+	_, nodeBounded  // bounds check unnecessary
+	_, nodeAddable  // addressable
+	_, nodeHasCall  // expression contains a function call
+	_, nodeLikely   // if statement condition likely
+	_, nodeHasVal   // node.E contains a Val
+	_, nodeHasOpt   // node.E contains an Opt
+	_, nodeEmbedded // ODCLFIELD embedded type
 )
 
-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) 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) noInline() bool {
-	return n.flags&noInline != 0
-}
-func (n *Node) setNoInline(b bool) {
-	if b {
-		n.flags |= noInline
-	} else {
-		n.flags &^= noInline
-	}
-}
-
-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
-	}
-}
+func (n *Node) Class() Class     { return Class(n.flags.get3(nodeClass)) }
+func (n *Node) Walkdef() uint8   { return n.flags.get2(nodeWalkdef) }
+func (n *Node) Typecheck() uint8 { return n.flags.get2(nodeTypecheck) }
+func (n *Node) Initorder() uint8 { return n.flags.get2(nodeInitorder) }
+
+func (n *Node) HasBreak() bool              { return n.flags&nodeHasBreak != 0 }
+func (n *Node) IsClosureVar() bool          { return n.flags&nodeIsClosureVar != 0 }
+func (n *Node) NoInline() bool              { return n.flags&nodeNoInline != 0 }
+func (n *Node) IsOutputParamHeapAddr() bool { return n.flags&nodeIsOutputParamHeapAddr != 0 }
+func (n *Node) Assigned() bool              { return n.flags&nodeAssigned != 0 }
+func (n *Node) Addrtaken() bool             { return n.flags&nodeAddrtaken != 0 }
+func (n *Node) Implicit() bool              { return n.flags&nodeImplicit != 0 }
+func (n *Node) Isddd() bool                 { return n.flags&nodeIsddd != 0 }
+func (n *Node) Local() bool                 { return n.flags&nodeLocal != 0 }
+func (n *Node) Diag() bool                  { return n.flags&nodeDiag != 0 }
+func (n *Node) Colas() bool                 { return n.flags&nodeColas != 0 }
+func (n *Node) NonNil() bool                { return n.flags&nodeNonNil != 0 }
+func (n *Node) Noescape() bool              { return n.flags&nodeNoescape != 0 }
+func (n *Node) Bounded() bool               { return n.flags&nodeBounded != 0 }
+func (n *Node) Addable() bool               { return n.flags&nodeAddable != 0 }
+func (n *Node) HasCall() bool               { return n.flags&nodeHasCall != 0 }
+func (n *Node) Likely() bool                { return n.flags&nodeLikely != 0 }
+func (n *Node) HasVal() bool                { return n.flags&nodeHasVal != 0 }
+func (n *Node) HasOpt() bool                { return n.flags&nodeHasOpt != 0 }
+func (n *Node) Embedded() bool              { return n.flags&nodeEmbedded != 0 }
+
+func (n *Node) SetClass(b Class)     { n.flags.set3(nodeClass, uint8(b)) }
+func (n *Node) SetWalkdef(b uint8)   { n.flags.set2(nodeWalkdef, b) }
+func (n *Node) SetTypecheck(b uint8) { n.flags.set2(nodeTypecheck, b) }
+func (n *Node) SetInitorder(b uint8) { n.flags.set2(nodeInitorder, b) }
+
+func (n *Node) SetHasBreak(b bool)              { n.flags.set(nodeHasBreak, b) }
+func (n *Node) SetIsClosureVar(b bool)          { n.flags.set(nodeIsClosureVar, b) }
+func (n *Node) SetNoInline(b bool)              { n.flags.set(nodeNoInline, b) }
+func (n *Node) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nodeIsOutputParamHeapAddr, b) }
+func (n *Node) SetAssigned(b bool)              { n.flags.set(nodeAssigned, b) }
+func (n *Node) SetAddrtaken(b bool)             { n.flags.set(nodeAddrtaken, b) }
+func (n *Node) SetImplicit(b bool)              { n.flags.set(nodeImplicit, b) }
+func (n *Node) SetIsddd(b bool)                 { n.flags.set(nodeIsddd, b) }
+func (n *Node) SetLocal(b bool)                 { n.flags.set(nodeLocal, b) }
+func (n *Node) SetDiag(b bool)                  { n.flags.set(nodeDiag, b) }
+func (n *Node) SetColas(b bool)                 { n.flags.set(nodeColas, b) }
+func (n *Node) SetNonNil(b bool)                { n.flags.set(nodeNonNil, b) }
+func (n *Node) SetNoescape(b bool)              { n.flags.set(nodeNoescape, b) }
+func (n *Node) SetBounded(b bool)               { n.flags.set(nodeBounded, b) }
+func (n *Node) SetAddable(b bool)               { n.flags.set(nodeAddable, b) }
+func (n *Node) SetHasCall(b bool)               { n.flags.set(nodeHasCall, b) }
+func (n *Node) SetLikely(b bool)                { n.flags.set(nodeLikely, b) }
+func (n *Node) SetHasVal(b bool)                { n.flags.set(nodeHasVal, b) }
+func (n *Node) SetHasOpt(b bool)                { n.flags.set(nodeHasOpt, b) }
+func (n *Node) SetEmbedded(b bool)              { n.flags.set(nodeEmbedded, b) }
 
 // Val returns the Val for the node.
 func (n *Node) Val() Val {
-	if n.hasVal != +1 {
+	if !n.HasVal() {
 		return Val{}
 	}
 	return Val{n.E}
@@ -140,18 +162,18 @@ func (n *Node) Val() Val {
 
 // SetVal sets the Val for the node, which must not have been used with SetOpt.
 func (n *Node) SetVal(v Val) {
-	if n.hasVal == -1 {
+	if n.HasOpt() {
 		Debug['h'] = 1
 		Dump("have Opt", n)
 		Fatalf("have Opt")
 	}
-	n.hasVal = +1
+	n.SetHasVal(true)
 	n.E = v.U
 }
 
 // Opt returns the optimizer data for the node.
 func (n *Node) Opt() interface{} {
-	if n.hasVal != -1 {
+	if !n.HasOpt() {
 		return nil
 	}
 	return n.E
@@ -160,15 +182,15 @@ func (n *Node) Opt() interface{} {
 // SetOpt sets the optimizer data for the node, which must not have been used with SetVal.
 // SetOpt(nil) is ignored for Vals to simplify call sites that are clearing Opts.
 func (n *Node) SetOpt(x interface{}) {
-	if x == nil && n.hasVal >= 0 {
+	if x == nil && n.HasVal() {
 		return
 	}
-	if n.hasVal == +1 {
+	if n.HasVal() {
 		Debug['h'] = 1
 		Dump("have Val", n)
 		Fatalf("have Val")
 	}
-	n.hasVal = -1
+	n.SetHasOpt(true)
 	n.E = x
 }
 
@@ -180,33 +202,73 @@ func (n *Node) SetIota(x int64) {
 	n.Xoffset = x
 }
 
-// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
+// mayBeShared reports whether n may occur in multiple places in the AST.
+// Extra care must be taken when mutating such a node.
+func (n *Node) mayBeShared() bool {
+	switch n.Op {
+	case ONAME, OLITERAL, OTYPE:
+		return true
+	}
+	return false
+}
+
+// funcname returns the name of the function n.
+func (n *Node) funcname() string {
+	if n == nil || n.Func == nil || n.Func.Nname == nil {
+		return "<nil>"
+	}
+	return n.Func.Nname.Sym.Name
+}
+
+// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, 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 (could move to Param?)
-	Defn      *Node  // initializing assignment
-	Curfn     *Node  // function for local variables
-	Param     *Param // additional fields for ONAME
-	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.
+	Pack      *Node      // real package for import . names
+	Pkg       *types.Pkg // pkg for OPACK nodes
+	Defn      *Node      // initializing assignment
+	Curfn     *Node      // function for local variables
+	Param     *Param     // additional fields for ONAME, OTYPE
+	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.
 	Funcdepth int32
-	Readonly  bool
-	Captured  bool // is the variable captured by a closure
-	Byval     bool // is the variable captured by value or by reference
-	Needzero  bool // if it contains pointers, needs to be zeroed on function entry
-	Keepalive bool // mark value live across unknown assembly call
-	AutoTemp  bool // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
+
+	used  bool // for variable declared and not used error
+	flags bitset8
 }
 
+const (
+	nameCaptured = 1 << iota // is the variable captured by a closure
+	nameReadonly
+	nameByval     // is the variable captured by value or by reference
+	nameNeedzero  // if it contains pointers, needs to be zeroed on function entry
+	nameKeepalive // mark value live across unknown assembly call
+	nameAutoTemp  // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
+)
+
+func (n *Name) Captured() bool  { return n.flags&nameCaptured != 0 }
+func (n *Name) Readonly() bool  { return n.flags&nameReadonly != 0 }
+func (n *Name) Byval() bool     { return n.flags&nameByval != 0 }
+func (n *Name) Needzero() bool  { return n.flags&nameNeedzero != 0 }
+func (n *Name) Keepalive() bool { return n.flags&nameKeepalive != 0 }
+func (n *Name) AutoTemp() bool  { return n.flags&nameAutoTemp != 0 }
+func (n *Name) Used() bool      { return n.used }
+
+func (n *Name) SetCaptured(b bool)  { n.flags.set(nameCaptured, b) }
+func (n *Name) SetReadonly(b bool)  { n.flags.set(nameReadonly, b) }
+func (n *Name) SetByval(b bool)     { n.flags.set(nameByval, b) }
+func (n *Name) SetNeedzero(b bool)  { n.flags.set(nameNeedzero, b) }
+func (n *Name) SetKeepalive(b bool) { n.flags.set(nameKeepalive, b) }
+func (n *Name) SetAutoTemp(b bool)  { n.flags.set(nameAutoTemp, b) }
+func (n *Name) SetUsed(b bool)      { n.used = b }
+
 type Param struct {
-	Ntype *Node
+	Ntype    *Node
+	Heapaddr *Node // temp holding heap address of param
 
 	// ONAME PAUTOHEAP
 	Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
 
 	// ONAME PPARAM
-	Field *Field // TFIELD in arg struct
+	Field *types.Field // TFIELD in arg struct
 
 	// ONAME closure linkage
 	// Consider:
@@ -235,10 +297,10 @@ type Param struct {
 	//
 	//   - 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
+	//   - x1.IsClosureVar() = false
 	//
 	//   - xN.Defn = x1, N > 1
-	//   - xN.isClosureVar() = true, N > 1
+	//   - xN.IsClosureVar() = true, N > 1
 	//   - x2.Outer = nil
 	//   - xN.Outer = x(N-1), N > 2
 	//
@@ -280,27 +342,38 @@ type Param struct {
 	Innermost *Node
 	Outer     *Node
 
-	// OTYPE pragmas
+	// OTYPE
 	//
 	// TODO: Should Func pragmas also be stored on the Name?
-	Pragma Pragma
+	Pragma syntax.Pragma
+	Alias  bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
 }
 
 // Func holds Node fields used only with function-like nodes.
 type Func struct {
-	Shortname  *Node
-	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
+	Shortname *types.Sym
+	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
+
+	// Parents records the parent scope of each scope within a
+	// function. The root scope (0) has no parent, so the i'th
+	// scope's parent is stored at Parents[i-1].
+	Parents []ScopeID
+
+	// Marks records scope boundary changes.
+	Marks []Mark
+
 	Closgen    int
 	Outerfunc  *Node // outer function (for closure)
-	FieldTrack map[*Sym]struct{}
+	FieldTrack map[*types.Sym]struct{}
 	Ntype      *Node // signature
 	Top        int   // top context (Ecall, Eproc, etc)
 	Closure    *Node // OCLOSURE <-> ODCLFUNC
 	Nname      *Node
+	lsym       *obj.LSym
 
 	Inl     Nodes // copy of the body for use in inlining
 	InlCost int32
@@ -308,18 +381,56 @@ type Func struct {
 
 	Label int32 // largest auto-generated label in this function
 
-	Endlineno int32
-	WBLineno  int32 // line number of first write barrier
+	Endlineno src.XPos
+	WBPos     src.XPos // position 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
-	IsHiddenClosure bool
-	NoFramePointer  bool // Must not use a frame pointer for this function
+	Pragma syntax.Pragma // go:xxx function annotations
+
+	flags bitset8
+}
+
+// A Mark represents a scope boundary.
+type Mark struct {
+	// Pos is the position of the token that marks the scope
+	// change.
+	Pos src.XPos
+
+	// Scope identifies the innermost scope to the right of Pos.
+	Scope ScopeID
 }
 
+// A ScopeID represents a lexical scope within a function.
+type ScopeID int32
+
+const (
+	funcDupok         = 1 << iota // duplicate definitions ok
+	funcWrapper                   // is method wrapper
+	funcNeedctxt                  // function uses context register (has closure variables)
+	funcReflectMethod             // function calls reflect.Type.Method or MethodByName
+	funcIsHiddenClosure
+	funcNoFramePointer   // Must not use a frame pointer for this function
+	funcHasDefer         // contains a defer statement
+	funcNilCheckDisabled // disable nil checks when compiling this function
+)
+
+func (f *Func) Dupok() bool            { return f.flags&funcDupok != 0 }
+func (f *Func) Wrapper() bool          { return f.flags&funcWrapper != 0 }
+func (f *Func) Needctxt() bool         { return f.flags&funcNeedctxt != 0 }
+func (f *Func) ReflectMethod() bool    { return f.flags&funcReflectMethod != 0 }
+func (f *Func) IsHiddenClosure() bool  { return f.flags&funcIsHiddenClosure != 0 }
+func (f *Func) NoFramePointer() bool   { return f.flags&funcNoFramePointer != 0 }
+func (f *Func) HasDefer() bool         { return f.flags&funcHasDefer != 0 }
+func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
+
+func (f *Func) SetDupok(b bool)            { f.flags.set(funcDupok, b) }
+func (f *Func) SetWrapper(b bool)          { f.flags.set(funcWrapper, b) }
+func (f *Func) SetNeedctxt(b bool)         { f.flags.set(funcNeedctxt, b) }
+func (f *Func) SetReflectMethod(b bool)    { f.flags.set(funcReflectMethod, b) }
+func (f *Func) SetIsHiddenClosure(b bool)  { f.flags.set(funcIsHiddenClosure, b) }
+func (f *Func) SetNoFramePointer(b bool)   { f.flags.set(funcNoFramePointer, b) }
+func (f *Func) SetHasDefer(b bool)         { f.flags.set(funcHasDefer, b) }
+func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
+
 type Op uint8
 
 // Node ops.
@@ -341,7 +452,7 @@ const (
 	OADDSTR          // +{List} (string addition, list elements are strings)
 	OADDR            // &Left
 	OANDAND          // Left && Right
-	OAPPEND          // append(List)
+	OAPPEND          // append(List); after walk, Left may contain elem type descriptor
 	OARRAYBYTESTR    // Type(Left) (Type is string, Left is a []byte)
 	OARRAYBYTESTRTMP // Type(Left) (Type is string, Left is a []byte, ephemeral)
 	OARRAYRUNESTR    // Type(Left) (Type is string, Left is a []rune)
@@ -355,7 +466,6 @@ const (
 	OAS2MAPR         // List = Rlist (x, ok = m["foo"])
 	OAS2DOTTYPE      // List = Rlist (x, ok = I.(int))
 	OASOP            // Left Etype= Right (x += y)
-	OASWB            // Left = Right (with write barrier)
 	OCALL            // Left(List) (function call, method call or type conversion)
 	OCALLFUNC        // Left(List) (function call f(args))
 	OCALLMETH        // Left(List) (direct method call x.Method(args))
@@ -382,7 +492,7 @@ const (
 	ODCLFUNC  // func f() or func (r) f()
 	ODCLFIELD // struct field, interface field, or func/method argument/return value.
 	ODCLCONST // const pi = 3.14
-	ODCLTYPE  // type Int int
+	ODCLTYPE  // type Int int or type Int = int
 
 	ODELETE    // delete(Left, Right)
 	ODOT       // Left.Sym (Left is of struct type)
@@ -390,8 +500,8 @@ const (
 	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)
+	ODOTTYPE   // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
+	ODOTTYPE2  // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
 	OEQ        // Left == Right
 	ONE        // Left != Right
 	OLT        // Left < Right
@@ -455,6 +565,7 @@ const (
 	OFALL     // fallthrough (after processing)
 	OXFALL    // fallthrough (before processing)
 	OFOR      // for Ninit; Left; Right { Nbody }
+	OFORUNTIL // for Ninit; Left; Right { Nbody } ; test applied after executing body, not before
 	OGOTO     // goto Left
 	OIF       // if Ninit; Left { Nbody } else { Rlist }
 	OLABEL    // Left:
@@ -489,17 +600,7 @@ const (
 	OINDREGSP   // offset plus indirect of REGSP, such as 8(SP).
 
 	// arch-specific opcodes
-	OCMP    // compare: ACMP.
-	ODEC    // decrement: ADEC.
-	OINC    // increment: AINC.
-	OEXTEND // extend: ACWD/ACDQ/ACQO.
-	OHMUL   // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
-	OLROT   // left rotate: AROL.
-	ORROTC  // right rotate-carry: ARCR.
 	ORETJMP // return to other function
-	OPS     // compare parity set (for x86 NaN check)
-	OPC     // compare parity clear (for x86 NaN check)
-	OSQRT   // sqrt(float64), on systems that have hw support
 	OGETG   // runtime.getg() (read g pointer)
 
 	OEND
@@ -561,8 +662,8 @@ func (n *Nodes) Set(s []*Node) {
 }
 
 // Set1 sets n to a slice containing a single node.
-func (n *Nodes) Set1(node *Node) {
-	n.slice = &[]*Node{node}
+func (n *Nodes) Set1(n1 *Node) {
+	n.slice = &[]*Node{n1}
 }
 
 // Set2 sets n to a slice containing two nodes.
@@ -570,6 +671,11 @@ func (n *Nodes) Set2(n1, n2 *Node) {
 	n.slice = &[]*Node{n1, n2}
 }
 
+// Set3 sets n to a slice containing three nodes.
+func (n *Nodes) Set3(n1, n2, n3 *Node) {
+	n.slice = &[]*Node{n1, n2, n3}
+}
+
 // MoveNodes sets n to the contents of n2, then clears n2.
 func (n *Nodes) MoveNodes(n2 *Nodes) {
 	n.slice = n2.slice
@@ -582,6 +688,18 @@ func (n Nodes) SetIndex(i int, node *Node) {
 	(*n.slice)[i] = node
 }
 
+// SetFirst sets the first element of Nodes to node.
+// It panics if n does not have at least one elements.
+func (n Nodes) SetFirst(node *Node) {
+	(*n.slice)[0] = node
+}
+
+// SetSecond sets the second element of Nodes to node.
+// It panics if n does not have at least two elements.
+func (n Nodes) SetSecond(node *Node) {
+	(*n.slice)[1] = node
+}
+
 // 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 {
@@ -589,16 +707,17 @@ func (n Nodes) Addr(i int) **Node {
 }
 
 // Append appends entries to Nodes.
-// If a slice is passed in, this will take ownership of it.
 func (n *Nodes) Append(a ...*Node) {
 	if len(a) == 0 {
 		return
 	}
 	if n.slice == nil {
-		n.slice = &a
-	} else {
-		*n.slice = append(*n.slice, a...)
+		s := make([]*Node, len(a))
+		copy(s, a)
+		n.slice = &s
+		return
 	}
+	*n.slice = append(*n.slice, a...)
 }
 
 // Prepend prepends entries to Nodes.
diff --git a/src/cmd/compile/internal/gc/testdata/arith.go b/src/cmd/compile/internal/gc/testdata/arith.go
index f260d45..d850ce2 100644
--- a/src/cmd/compile/internal/gc/testdata/arith.go
+++ b/src/cmd/compile/internal/gc/testdata/arith.go
@@ -488,17 +488,6 @@ func testLrot() {
 			wantA, wantB, wantC, wantD, ", got", a, b, c, d)
 		failed = true
 	}
-	// Also test inputs with the top bit set, and make sure
-	// sub-word right shift has high bits cleared first.
-	// See issue #19270.
-	wantA, wantB, wantC, wantD = uint8(0xdf), uint16(0xdfff),
-		uint32(0xdfffffff), uint64(0xdfffffffffffffff)
-	a, b, c, d = lrot1_ssa(0xfe, 0xfffe, 0xfffffffe, 0xfffffffffffffffe)
-	if a != wantA || b != wantB || c != wantC || d != wantD {
-		println("lrot1_ssa(0xfe, 0xfffe, 0xfffffffe, 0xfffffffffffffffe)=",
-			wantA, wantB, wantC, wantD, ", got", a, b, c, d)
-		failed = true
-	}
 	x := lrot2_ssa(0xb0000001, 32)
 	wantX := uint32(0xb0000001)
 	if x != wantX {
diff --git a/src/cmd/compile/internal/gc/testdata/arithBoundary.go b/src/cmd/compile/internal/gc/testdata/arithBoundary.go
index 929e4e1..4a7afe6 100644
--- a/src/cmd/compile/internal/gc/testdata/arithBoundary.go
+++ b/src/cmd/compile/internal/gc/testdata/arithBoundary.go
@@ -1,3 +1,6 @@
+// run
+// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.
+
 package main
 
 import "fmt"
diff --git a/src/cmd/compile/internal/gc/testdata/arithConst.go b/src/cmd/compile/internal/gc/testdata/arithConst.go
index 21bcd63..cadea7b 100644
--- a/src/cmd/compile/internal/gc/testdata/arithConst.go
+++ b/src/cmd/compile/internal/gc/testdata/arithConst.go
@@ -1,3 +1,6 @@
+// run
+// Code generated by gen/arithConstGen.go. DO NOT EDIT.
+
 package main
 
 import "fmt"
diff --git a/src/cmd/compile/internal/gc/testdata/copy.go b/src/cmd/compile/internal/gc/testdata/copy.go
index 0b6f878..d8bb266 100644
--- a/src/cmd/compile/internal/gc/testdata/copy.go
+++ b/src/cmd/compile/internal/gc/testdata/copy.go
@@ -1,5 +1,6 @@
 // run
-// autogenerated from gen/copyGen.go - do not edit!
+// Code generated by gen/copyGen.go. DO NOT EDIT.
+
 package main
 
 import "fmt"
@@ -655,6 +656,108 @@ func testCopy1041() {
 	}
 }
 
+//go:noinline
+func tu2copy_ssa(docopy bool, data [2]byte, x *[2]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy2() {
+	var a [2]byte
+	t2 := [2]byte{2, 3}
+	tu2copy_ssa(true, t2, &a)
+	want2 := [2]byte{2, 3}
+	if a != want2 {
+		fmt.Printf("tu2copy got=%v, want %v\n", a, want2)
+		failed = true
+	}
+}
+
+//go:noinline
+func tu3copy_ssa(docopy bool, data [3]byte, x *[3]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy3() {
+	var a [3]byte
+	t3 := [3]byte{3, 4, 5}
+	tu3copy_ssa(true, t3, &a)
+	want3 := [3]byte{3, 4, 5}
+	if a != want3 {
+		fmt.Printf("tu3copy got=%v, want %v\n", a, want3)
+		failed = true
+	}
+}
+
+//go:noinline
+func tu4copy_ssa(docopy bool, data [4]byte, x *[4]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy4() {
+	var a [4]byte
+	t4 := [4]byte{4, 5, 6, 7}
+	tu4copy_ssa(true, t4, &a)
+	want4 := [4]byte{4, 5, 6, 7}
+	if a != want4 {
+		fmt.Printf("tu4copy got=%v, want %v\n", a, want4)
+		failed = true
+	}
+}
+
+//go:noinline
+func tu5copy_ssa(docopy bool, data [5]byte, x *[5]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy5() {
+	var a [5]byte
+	t5 := [5]byte{5, 6, 7, 8, 9}
+	tu5copy_ssa(true, t5, &a)
+	want5 := [5]byte{5, 6, 7, 8, 9}
+	if a != want5 {
+		fmt.Printf("tu5copy got=%v, want %v\n", a, want5)
+		failed = true
+	}
+}
+
+//go:noinline
+func tu6copy_ssa(docopy bool, data [6]byte, x *[6]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy6() {
+	var a [6]byte
+	t6 := [6]byte{6, 7, 8, 9, 10, 11}
+	tu6copy_ssa(true, t6, &a)
+	want6 := [6]byte{6, 7, 8, 9, 10, 11}
+	if a != want6 {
+		fmt.Printf("tu6copy got=%v, want %v\n", a, want6)
+		failed = true
+	}
+}
+
+//go:noinline
+func tu7copy_ssa(docopy bool, data [7]byte, x *[7]byte) {
+	if docopy {
+		*x = data
+	}
+}
+func testUnalignedCopy7() {
+	var a [7]byte
+	t7 := [7]byte{7, 8, 9, 10, 11, 12, 13}
+	tu7copy_ssa(true, t7, &a)
+	want7 := [7]byte{7, 8, 9, 10, 11, 12, 13}
+	if a != want7 {
+		fmt.Printf("tu7copy got=%v, want %v\n", a, want7)
+		failed = true
+	}
+}
+
 var failed bool
 
 func main() {
@@ -689,6 +792,12 @@ func main() {
 	testCopy1039()
 	testCopy1040()
 	testCopy1041()
+	testUnalignedCopy2()
+	testUnalignedCopy3()
+	testUnalignedCopy4()
+	testUnalignedCopy5()
+	testUnalignedCopy6()
+	testUnalignedCopy7()
 	if failed {
 		panic("failed")
 	}
diff --git a/src/cmd/compile/internal/gc/testdata/fp.go b/src/cmd/compile/internal/gc/testdata/fp.go
index 91656be..18082c5 100644
--- a/src/cmd/compile/internal/gc/testdata/fp.go
+++ b/src/cmd/compile/internal/gc/testdata/fp.go
@@ -232,6 +232,141 @@ func integer2floatConversions() int {
 	return fails
 }
 
+func multiplyAdd() int {
+	fails := 0
+	{
+		// Test that a multiply-accumulate operation with intermediate
+		// rounding forced by a float32() cast produces the expected
+		// result.
+		// Test cases generated experimentally on a system (s390x) that
+		// supports fused multiply-add instructions.
+		var tests = [...]struct{ x, y, z, res float32 }{
+			{0.6046603, 0.9405091, 0.6645601, 1.2332485},      // fused multiply-add result: 1.2332486
+			{0.67908466, 0.21855305, 0.20318687, 0.3516029},   // fused multiply-add result: 0.35160288
+			{0.29311424, 0.29708257, 0.752573, 0.8396522},     // fused multiply-add result: 0.8396521
+			{0.5305857, 0.2535405, 0.282081, 0.41660595},      // fused multiply-add result: 0.41660598
+			{0.29711226, 0.89436173, 0.097454615, 0.36318043}, // fused multiply-add result: 0.36318046
+			{0.6810783, 0.24151509, 0.31152245, 0.47601312},   // fused multiply-add result: 0.47601315
+			{0.73023146, 0.18292491, 0.4283571, 0.5619346},    // fused multiply-add result: 0.56193465
+			{0.89634174, 0.32208398, 0.7211478, 1.009845},     // fused multiply-add result: 1.0098451
+			{0.6280982, 0.12675293, 0.2813303, 0.36094356},    // fused multiply-add result: 0.3609436
+			{0.29400632, 0.75316125, 0.15096405, 0.3723982},   // fused multiply-add result: 0.37239823
+		}
+		check := func(s string, got, expected float32) int {
+			if got != expected {
+				fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got)
+				return 1
+			}
+			return 0
+		}
+		for _, t := range tests {
+			fails += check(
+				fmt.Sprintf("float32(%v * %v) + %v", t.x, t.y, t.z),
+				func(x, y, z float32) float32 {
+					return float32(x*y) + z
+				}(t.x, t.y, t.z),
+				t.res)
+
+			fails += check(
+				fmt.Sprintf("%v += float32(%v * %v)", t.z, t.x, t.y),
+				func(x, y, z float32) float32 {
+					z += float32(x * y)
+					return z
+				}(t.x, t.y, t.z),
+				t.res)
+		}
+	}
+	{
+		// Test that a multiply-accumulate operation with intermediate
+		// rounding forced by a float64() cast produces the expected
+		// result.
+		// Test cases generated experimentally on a system (s390x) that
+		// supports fused multiply-add instructions.
+		var tests = [...]struct{ x, y, z, res float64 }{
+			{0.4688898449024232, 0.28303415118044517, 0.29310185733681576, 0.42581369658590373}, // fused multiply-add result: 0.4258136965859037
+			{0.7886049150193449, 0.3618054804803169, 0.8805431227416171, 1.1658647029293308},    // fused multiply-add result: 1.1658647029293305
+			{0.7302314772948083, 0.18292491645390843, 0.4283570818068078, 0.5619346137829748},   // fused multiply-add result: 0.5619346137829747
+			{0.6908388315056789, 0.7109071952999951, 0.5637795958152644, 1.0549018919252924},    // fused multiply-add result: 1.0549018919252926
+			{0.4584424785756506, 0.6001655953233308, 0.02626515060968944, 0.3014065536855481},   // fused multiply-add result: 0.30140655368554814
+			{0.539210105890946, 0.9756748149873165, 0.7507630564795985, 1.2768567767840384},     // fused multiply-add result: 1.2768567767840386
+			{0.7830349733960021, 0.3932509992288867, 0.1304138461737918, 0.4383431318929343},    // fused multiply-add result: 0.43834313189293433
+			{0.6841751300974551, 0.6530402051353608, 0.524499759549865, 0.9712936268572192},     // fused multiply-add result: 0.9712936268572193
+			{0.3691117091643448, 0.826454125634742, 0.34768170859156955, 0.6527356034505334},    // fused multiply-add result: 0.6527356034505333
+			{0.16867966833433606, 0.33136826030698385, 0.8279280961505588, 0.8838231843956668},  // fused multiply-add result: 0.8838231843956669
+		}
+		check := func(s string, got, expected float64) int {
+			if got != expected {
+				fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got)
+				return 1
+			}
+			return 0
+		}
+		for _, t := range tests {
+			fails += check(
+				fmt.Sprintf("float64(%v * %v) + %v", t.x, t.y, t.z),
+				func(x, y, z float64) float64 {
+					return float64(x*y) + z
+				}(t.x, t.y, t.z),
+				t.res)
+
+			fails += check(
+				fmt.Sprintf("%v += float64(%v * %v)", t.z, t.x, t.y),
+				func(x, y, z float64) float64 {
+					z += float64(x * y)
+					return z
+				}(t.x, t.y, t.z),
+				t.res)
+		}
+	}
+	{
+		// Test that a multiply-accumulate operation with intermediate
+		// rounding forced by a complex128() cast produces the expected
+		// result.
+		// Test cases generated experimentally on a system (s390x) that
+		// supports fused multiply-add instructions.
+		var tests = [...]struct {
+			x, y float64
+			res  complex128
+		}{
+			{0.6046602879796196, 0.9405090880450124, (2.754489951983871 + 3i)},    // fused multiply-add result: (2.7544899519838713 + 3i)
+			{0.09696951891448456, 0.30091186058528707, (0.5918204173287407 + 3i)}, // fused multiply-add result: (0.5918204173287408 + 3i)
+			{0.544155573000885, 0.27850762181610883, (1.910974340818764 + 3i)},    // fused multiply-add result: (1.9109743408187638 + 3i)
+			{0.9769168685862624, 0.07429099894984302, (3.0050416047086297 + 3i)},  // fused multiply-add result: (3.00504160470863 + 3i)
+			{0.9269868035744142, 0.9549454404167818, (3.735905851140024 + 3i)},    // fused multiply-add result: (3.7359058511400245 + 3i)
+			{0.7109071952999951, 0.5637795958152644, (2.69650118171525 + 3i)},     // fused multiply-add result: (2.6965011817152496 + 3i)
+			{0.7558235074915978, 0.40380328579570035, (2.671273808270494 + 3i)},   // fused multiply-add result: (2.6712738082704934 + 3i)
+			{0.13065111702897217, 0.9859647293402467, (1.3779180804271633 + 3i)},  // fused multiply-add result: (1.3779180804271631 + 3i)
+			{0.8963417453962161, 0.3220839705208817, (3.0111092067095298 + 3i)},   // fused multiply-add result: (3.01110920670953 + 3i)
+			{0.39998376285699544, 0.497868113342702, (1.697819401913688 + 3i)},    // fused multiply-add result: (1.6978194019136883 + 3i)
+		}
+		check := func(s string, got, expected complex128) int {
+			if got != expected {
+				fmt.Printf("multiplyAdd: %s, expected %v, got %v\n", s, expected, got)
+				return 1
+			}
+			return 0
+		}
+		for _, t := range tests {
+			fails += check(
+				fmt.Sprintf("complex128(complex(%v, 1)*3) + complex(%v, 0)", t.x, t.y),
+				func(x, y float64) complex128 {
+					return complex128(complex(x, 1)*3) + complex(y, 0)
+				}(t.x, t.y),
+				t.res)
+
+			fails += check(
+				fmt.Sprintf("z := complex(%v, 1); z += complex128(complex(%v, 1) * 3)", t.y, t.x),
+				func(x, y float64) complex128 {
+					z := complex(y, 0)
+					z += complex128(complex(x, 1) * 3)
+					return z
+				}(t.x, t.y),
+				t.res)
+		}
+	}
+	return fails
+}
+
 const (
 	aa = 0x1000000000000000
 	ab = 0x100000000000000
@@ -1658,6 +1793,8 @@ func main() {
 
 	fails += integer2floatConversions()
 
+	fails += multiplyAdd()
+
 	var zero64 float64 = 0.0
 	var one64 float64 = 1.0
 	var inf64 float64 = 1.0 / zero64
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
index 866431e..cbdd162 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
@@ -90,8 +90,9 @@ type op struct {
 var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, op{"mul", "*"}}
 
 func main() {
-
 	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "// run\n")
+	fmt.Fprintf(w, "// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.\n\n")
 	fmt.Fprintf(w, "package main;\n")
 	fmt.Fprintf(w, "import \"fmt\"\n")
 
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
index 97434ea..07a3749 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
@@ -30,24 +30,31 @@ type szD struct {
 	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,
+var szs = []szD{
+	{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+	{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,
+	{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+	{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}},
+	{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+	{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}},
+	{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+	{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", "%"}}
+var ops = []op{
+	{"add", "+"},
+	{"sub", "-"},
+	{"div", "/"},
+	{"mul", "*"},
+	{"lsh", "<<"},
+	{"rsh", ">>"},
+	{"mod", "%"},
+}
 
 // compute the result of i op j, cast as type t.
 func ansU(i, j uint64, t, op string) string {
@@ -118,9 +125,9 @@ func ansS(i, j int64, t, op string) string {
 }
 
 func main() {
-
 	w := new(bytes.Buffer)
-
+	fmt.Fprintf(w, "// run\n")
+	fmt.Fprintf(w, "// Code generated by gen/arithConstGen.go. DO NOT EDIT.\n\n")
 	fmt.Fprintf(w, "package main;\n")
 	fmt.Fprintf(w, "import \"fmt\"\n")
 
@@ -160,7 +167,14 @@ func main() {
 
 					// avoid division by zero
 					if o.name != "mod" && o.name != "div" || i != 0 {
+						// introduce uint64 cast for rhs shift operands
+						// if they are too large for default uint type
+						number := fd.Number
+						if (o.name == "lsh" || o.name == "rsh") && uint64(uint32(i)) != i {
+							fd.Number = fmt.Sprintf("uint64(%s)", number)
+						}
 						fncCnst1.Execute(w, fd)
+						fd.Number = number
 					}
 
 					fncCnst2.Execute(w, fd)
diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
index f266749..2b8a331 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
@@ -118,9 +118,9 @@ func ansS(i, j int64, t, op string) string {
 }
 
 func main() {
-
 	w := new(bytes.Buffer)
-
+	fmt.Fprintf(w, "// run\n")
+	fmt.Fprintf(w, "// Code generated by gen/constFoldGen.go. DO NOT EDIT.\n\n")
 	fmt.Fprintf(w, "package gc\n")
 	fmt.Fprintf(w, "import \"testing\"\n")
 
diff --git a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
index 2d2240c..800d081 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
@@ -20,10 +20,12 @@ import (
 
 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}
 
+var usizes = [...]int{2, 3, 4, 5, 6, 7}
+
 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, "// Code generated by gen/copyGen.go. DO NOT EDIT.\n\n")
 	fmt.Fprintf(w, "package main\n")
 	fmt.Fprintf(w, "import \"fmt\"\n")
 
@@ -36,8 +38,8 @@ func main() {
 		fmt.Fprintf(w, "}\n")
 
 		// function being tested
+		fmt.Fprintf(w, "//go:noinline\n")
 		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")
 
@@ -66,12 +68,45 @@ func main() {
 		fmt.Fprintf(w, "}\n")
 	}
 
+	for _, s := range usizes {
+		// function being tested
+		fmt.Fprintf(w, "//go:noinline\n")
+		fmt.Fprintf(w, "func tu%dcopy_ssa(docopy bool, data [%d]byte, x *[%d]byte) {\n", s, s, s)
+		fmt.Fprintf(w, "  if docopy {\n")
+		fmt.Fprintf(w, "    *x = data\n")
+		fmt.Fprintf(w, "  }\n")
+		fmt.Fprintf(w, "}\n")
+
+		// testing harness
+		fmt.Fprintf(w, "func testUnalignedCopy%d() {\n", s)
+		fmt.Fprintf(w, "  var a [%d]byte\n", s)
+		fmt.Fprintf(w, "  t%d := [%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, " %d,", s+i)
+		}
+		fmt.Fprintf(w, "}\n")
+		fmt.Fprintf(w, "  tu%dcopy_ssa(true, t%d, &a)\n", s, s)
+		fmt.Fprintf(w, "  want%d := [%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, " %d,", s+i)
+		}
+		fmt.Fprintf(w, "}\n")
+		fmt.Fprintf(w, "  if a != want%d {\n", s)
+		fmt.Fprintf(w, "    fmt.Printf(\"tu%dcopy got=%%v, want %%v\\n\", a, want%d)\n", s, 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)
 	}
+	for _, s := range usizes {
+		fmt.Fprintf(w, "  testUnalignedCopy%d()\n", s)
+	}
 	fmt.Fprintf(w, "  if failed {\n")
 	fmt.Fprintf(w, "    panic(\"failed\")\n")
 	fmt.Fprintf(w, "  }\n")
diff --git a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
index 6482f07..fa70b16 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
@@ -23,7 +23,7 @@ var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31,
 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, "// Code generated by gen/zeroGen.go. DO NOT EDIT.\n\n")
 	fmt.Fprintf(w, "package main\n")
 	fmt.Fprintf(w, "import \"fmt\"\n")
 
@@ -36,8 +36,8 @@ func main() {
 		fmt.Fprintf(w, "}\n")
 
 		// function being tested
+		fmt.Fprintf(w, "//go:noinline\n")
 		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")
 
diff --git a/src/cmd/compile/internal/gc/testdata/loadstore.go b/src/cmd/compile/internal/gc/testdata/loadstore.go
index 4d67864..dcb61d4 100644
--- a/src/cmd/compile/internal/gc/testdata/loadstore.go
+++ b/src/cmd/compile/internal/gc/testdata/loadstore.go
@@ -102,12 +102,120 @@ func testDeadStorePanic() {
 	}
 }
 
+//go:noinline
+func loadHitStore8(x int8, p *int8) int32 {
+	x *= x           // try to trash high bits (arch-dependent)
+	*p = x           // store
+	return int32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU8(x uint8, p *uint8) uint32 {
+	x *= x            // try to trash high bits (arch-dependent)
+	*p = x            // store
+	return uint32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStore16(x int16, p *int16) int32 {
+	x *= x           // try to trash high bits (arch-dependent)
+	*p = x           // store
+	return int32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU16(x uint16, p *uint16) uint32 {
+	x *= x            // try to trash high bits (arch-dependent)
+	*p = x            // store
+	return uint32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStore32(x int32, p *int32) int64 {
+	x *= x           // try to trash high bits (arch-dependent)
+	*p = x           // store
+	return int64(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU32(x uint32, p *uint32) uint64 {
+	x *= x            // try to trash high bits (arch-dependent)
+	*p = x            // store
+	return uint64(*p) // load and cast
+}
+
+func testLoadHitStore() {
+	// Test that sign/zero extensions are kept when a load-hit-store
+	// is replaced by a register-register move.
+	{
+		var in int8 = (1 << 6) + 1
+		var p int8
+		got := loadHitStore8(in, &p)
+		want := int32(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (int8) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+	{
+		var in uint8 = (1 << 6) + 1
+		var p uint8
+		got := loadHitStoreU8(in, &p)
+		want := uint32(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (uint8) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+	{
+		var in int16 = (1 << 10) + 1
+		var p int16
+		got := loadHitStore16(in, &p)
+		want := int32(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (int16) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+	{
+		var in uint16 = (1 << 10) + 1
+		var p uint16
+		got := loadHitStoreU16(in, &p)
+		want := uint32(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (uint16) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+	{
+		var in int32 = (1 << 30) + 1
+		var p int32
+		got := loadHitStore32(in, &p)
+		want := int64(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (int32) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+	{
+		var in uint32 = (1 << 30) + 1
+		var p uint32
+		got := loadHitStoreU32(in, &p)
+		want := uint64(in * in)
+		if got != want {
+			fmt.Println("testLoadHitStore (uint32) failed. want =", want, ", got =", got)
+			failed = true
+		}
+	}
+}
+
 func main() {
 
 	testLoadStoreOrder()
 	testStoreSize()
 	testExtStore()
 	testDeadStorePanic()
+	testLoadHitStore()
 
 	if failed {
 		panic("failed")
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go
new file mode 100644
index 0000000..3db0b8a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. 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 (
+	i0 uint8
+	b0 byte
+
+	i1 *uint8
+	b1 *byte
+
+	i2 **uint8
+	b2 **byte
+
+	i3 ***uint8
+	b3 ***byte
+
+	i4 ****uint8
+	b4 ****byte
+
+	i5 *****uint8
+	b5 *****byte
+
+	i6 ******uint8
+	b6 ******byte
+
+	i7 *******uint8
+	b7 *******byte
+
+	i8 ********uint8
+	b8 ********byte
+)
diff --git a/src/cmd/compile/internal/gc/testdata/zero.go b/src/cmd/compile/internal/gc/testdata/zero.go
index 68334db..f635486 100644
--- a/src/cmd/compile/internal/gc/testdata/zero.go
+++ b/src/cmd/compile/internal/gc/testdata/zero.go
@@ -1,5 +1,6 @@
 // run
-// autogenerated from gen/zeroGen.go - do not edit!
+// Code generated by gen/zeroGen.go. DO NOT EDIT.
+
 package main
 
 import "fmt"
diff --git a/src/cmd/compile/internal/gc/truncconst_test.go b/src/cmd/compile/internal/gc/truncconst_test.go
new file mode 100644
index 0000000..d153818
--- /dev/null
+++ b/src/cmd/compile/internal/gc/truncconst_test.go
@@ -0,0 +1,63 @@
+// Copyright 2017 The Go Authors. 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"
+
+var f52want float64 = 1.0 / (1 << 52)
+var f53want float64 = 1.0 / (1 << 53)
+
+func TestTruncFlt(t *testing.T) {
+	const f52 = 1 + 1.0/(1<<52)
+	const f53 = 1 + 1.0/(1<<53)
+
+	if got := f52 - 1; got != f52want {
+		t.Errorf("f52-1 = %g, want %g", got, f52want)
+	}
+	if got := float64(f52) - 1; got != f52want {
+		t.Errorf("float64(f52)-1 = %g, want %g", got, f52want)
+	}
+	if got := f53 - 1; got != f53want {
+		t.Errorf("f53-1 = %g, want %g", got, f53want)
+	}
+	if got := float64(f53) - 1; got != 0 {
+		t.Errorf("float64(f53)-1 = %g, want 0", got)
+	}
+}
+
+func TestTruncCmplx(t *testing.T) {
+	const r52 = complex(1+1.0/(1<<52), 0)
+	const r53 = complex(1+1.0/(1<<53), 0)
+
+	if got := real(r52 - 1); got != f52want {
+		t.Errorf("real(r52-1) = %g, want %g", got, f52want)
+	}
+	if got := real(complex128(r52) - 1); got != f52want {
+		t.Errorf("real(complex128(r52)-1) = %g, want %g", got, f52want)
+	}
+	if got := real(r53 - 1); got != f53want {
+		t.Errorf("real(r53-1) = %g, want %g", got, f53want)
+	}
+	if got := real(complex128(r53) - 1); got != 0 {
+		t.Errorf("real(complex128(r53)-1) = %g, want 0", got)
+	}
+
+	const i52 = complex(0, 1+1.0/(1<<52))
+	const i53 = complex(0, 1+1.0/(1<<53))
+
+	if got := imag(i52 - 1i); got != f52want {
+		t.Errorf("imag(i52-1i) = %g, want %g", got, f52want)
+	}
+	if got := imag(complex128(i52) - 1i); got != f52want {
+		t.Errorf("imag(complex128(i52)-1i) = %g, want %g", got, f52want)
+	}
+	if got := imag(i53 - 1i); got != f53want {
+		t.Errorf("imag(i53-1i) = %g, want %g", got, f53want)
+	}
+	if got := imag(complex128(i53) - 1i); got != 0 {
+		t.Errorf("imag(complex128(i53)-1i) = %g, want 0", got)
+	}
+
+}
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
deleted file mode 100644
index 5f04f68..0000000
--- a/src/cmd/compile/internal/gc/type.go
+++ /dev/null
@@ -1,1250 +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.
-
-// 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)
-
-	sliceOf *Type
-	ptrTo   *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
-	Local      bool  // created in this file
-	Deferwidth bool
-	Broke      bool  // broken type definition.
-	Align      uint8 // the required alignment of this type, in bytes
-	NotInHeap  bool  // type cannot be heap allocated
-}
-
-// 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 pseudo-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}
-	t.NotInHeap = elem.NotInHeap
-	return t
-}
-
-// typSlice returns the slice Type with element type elem.
-func typSlice(elem *Type) *Type {
-	if t := elem.sliceOf; t != nil {
-		if t.Elem() != elem {
-			Fatalf("elem mismatch")
-		}
-		return t
-	}
-
-	t := typ(TSLICE)
-	t.Extra = SliceType{Elem: elem}
-	elem.sliceOf = t
-	return t
-}
-
-// typDDDArray returns a new [...]T array Type.
-func typDDDArray(elem *Type) *Type {
-	t := typ(TARRAY)
-	t.Extra = &ArrayType{Elem: elem, Bound: -1}
-	t.NotInHeap = elem.NotInHeap
-	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 the pointer type pointing to t.
-func typPtr(elem *Type) *Type {
-	if t := elem.ptrTo; t != nil {
-		if t.Elem() != elem {
-			Fatalf("elem mismatch")
-		}
-		return t
-	}
-
-	t := typ(Tptr)
-	t.Extra = PtrType{Elem: elem}
-	t.Width = int64(Widthptr)
-	t.Align = uint8(Widthptr)
-	elem.ptrTo = t
-	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() {
-			t = t.Copy()
-			t.FuncType().Receiver = recvs
-			t.FuncType().Results = results
-			t.FuncType().Params = 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) Recvs() *Type   { return t.FuncType().Receiver }
-func (t *Type) Params() *Type  { return t.FuncType().Params }
-func (t *Type) Results() *Type { return t.FuncType().Results }
-
-// 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) {
-	for _, f := range fields {
-		// If type T contains a field F with a go:notinheap
-		// type, then T must also be go:notinheap. Otherwise,
-		// you could heap allocate T and then get a pointer F,
-		// which would be a heap pointer to a go:notinheap
-		// type.
-		if f.Type != nil && f.Type.NotInHeap {
-			t.NotInHeap = true
-			break
-		}
-	}
-	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 %v with %v", 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
-}
-
-var unsignedEType = [...]EType{
-	TINT8:    TUINT8,
-	TUINT8:   TUINT8,
-	TINT16:   TUINT16,
-	TUINT16:  TUINT16,
-	TINT32:   TUINT32,
-	TUINT32:  TUINT32,
-	TINT64:   TUINT64,
-	TUINT64:  TUINT64,
-	TINT:     TUINT,
-	TUINT:    TUINT,
-	TUINTPTR: TUINTPTR,
-}
-
-// toUnsigned returns the unsigned equivalent of integer type t.
-func (t *Type) toUnsigned() *Type {
-	if !t.IsInteger() {
-		Fatalf("unsignedType(%v)", t)
-	}
-	return Types[unsignedEType[t.Etype]]
-}
-
-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 }
-func (t *Type) IsTuple() 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 7cfd951..f21cc8f 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -5,7 +5,9 @@
 package gc
 
 import (
-	"cmd/internal/obj"
+	"cmd/compile/internal/types"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"fmt"
 	"math"
 	"strings"
@@ -21,22 +23,26 @@ const (
 	Ecomplit              // type in composite literal
 )
 
-// type check the whole tree of an expression.
+// type checks the whole tree of an expression.
 // calculates expression types.
 // evaluates compile time constants.
 // marks variables that escape the local frame.
-// rewrites n->op to be more specific in some cases.
+// rewrites n.Op to be more specific in some cases.
+
 var typecheckdefstack []*Node
 
 // resolve ONONAME to definition, if any.
 func resolve(n *Node) *Node {
 	if n != nil && n.Op == ONONAME && n.Sym != nil {
-		r := n.Sym.Def
+		r := asNode(n.Sym.Def)
 		if r != nil {
 			if r.Op != OIOTA {
 				n = r
-			} else if n.Iota() >= 0 {
-				n = nodintconst(n.Iota())
+			} else if len(typecheckdefstack) > 0 {
+				x := typecheckdefstack[len(typecheckdefstack)-1]
+				if x.Op == OLITERAL {
+					n = nodintconst(x.Iota())
+				}
 			}
 		}
 	}
@@ -82,7 +88,7 @@ var _typekind = []string{
 	TIDEAL:      "untyped number",
 }
 
-func typekind(t *Type) string {
+func typekind(t *types.Type) string {
 	if t.IsSlice() {
 		return "slice"
 	}
@@ -96,16 +102,16 @@ func typekind(t *Type) string {
 	return fmt.Sprintf("etype=%d", et)
 }
 
-// sprint_depchain prints a dependency chain of nodes into fmt.
+// sprint_depchain prints a dependency chain of nodes into trace.
 // It is used by typecheck in the case of OLITERAL nodes
 // to print constant definition loops.
-func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
+func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
 	for i := len(stack) - 1; i >= 0; i-- {
 		if n := stack[i]; n.Op == cur.Op {
 			if n != first {
-				sprint_depchain(fmt_, stack[:i], n, first)
+				sprint_depchain(trace, stack[:i], n, first)
 			}
-			*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
+			*trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
 			return
 		}
 	}
@@ -138,7 +144,7 @@ func typecheck(n *Node, top int) *Node {
 
 	// Skip typecheck if already done.
 	// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
-	if n.Typecheck == 1 {
+	if n.Typecheck() == 1 {
 		switch n.Op {
 		case ONAME, OTYPE, OLITERAL, OPACK:
 			break
@@ -149,10 +155,9 @@ func typecheck(n *Node, top int) *Node {
 		}
 	}
 
-	if n.Typecheck == 2 {
+	if n.Typecheck() == 2 {
 		// Typechecking loop. Trying printing a meaningful message,
 		// otherwise a stack trace of typechecking.
-		var fmt_ string
 		switch n.Op {
 		// We can already diagnose variables used as types.
 		case ONAME:
@@ -160,34 +165,42 @@ func typecheck(n *Node, top int) *Node {
 				yyerror("%v is not a type", n)
 			}
 
+		case OTYPE:
+			if top&Etype == Etype {
+				var trace string
+				sprint_depchain(&trace, typecheck_tcstack, n, n)
+				yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace)
+			}
+
 		case OLITERAL:
 			if top&(Erv|Etype) == Etype {
 				yyerror("%v is not a type", n)
 				break
 			}
-			sprint_depchain(&fmt_, typecheck_tcstack, n, n)
-			yyerrorl(n.Lineno, "constant definition loop%s", fmt_)
+			var trace string
+			sprint_depchain(&trace, typecheck_tcstack, n, n)
+			yyerrorl(n.Pos, "constant definition loop%s", trace)
 		}
 
 		if nsavederrors+nerrors == 0 {
-			fmt_ = ""
+			var trace string
 			for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
 				x := typecheck_tcstack[i]
-				fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+				trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
 			}
-			yyerror("typechecking loop involving %v%s", n, fmt_)
+			yyerror("typechecking loop involving %v%s", n, trace)
 		}
 
 		lineno = lno
 		return n
 	}
 
-	n.Typecheck = 2
+	n.SetTypecheck(2)
 
 	typecheck_tcstack = append(typecheck_tcstack, n)
 	n = typecheck1(n, top)
 
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 
 	last := len(typecheck_tcstack) - 1
 	typecheck_tcstack[last] = nil
@@ -242,7 +255,7 @@ func indexlit(n *Node) *Node {
 	}
 	switch consttype(n) {
 	case CTINT, CTRUNE, CTFLT, CTCPLX:
-		n = defaultlit(n, Types[TINT])
+		n = defaultlit(n, types.Types[TINT])
 	}
 
 	n = defaultlit(n, nil)
@@ -285,7 +298,7 @@ OpSwitch:
 		ok |= Erv
 
 		if n.Type == nil && n.Val().Ctype() == CTSTR {
-			n.Type = idealstring
+			n.Type = types.Idealstring
 		}
 		break OpSwitch
 
@@ -310,7 +323,7 @@ OpSwitch:
 				return n
 			}
 
-			n.Used = true
+			n.Name.SetUsed(true)
 		}
 
 		ok |= Erv
@@ -340,26 +353,29 @@ OpSwitch:
 			return n
 		}
 
-		var t *Type
+		var t *types.Type
 		if n.Left == nil {
-			t = typSlice(r.Type)
+			t = types.NewSlice(r.Type)
 		} else if n.Left.Op == ODDD {
 			if top&Ecomplit == 0 {
-				if !n.Diag {
-					n.Diag = true
+				if !n.Diag() {
+					n.SetDiag(true)
 					yyerror("use of [...] array outside of array literal")
 				}
 				n.Type = nil
 				return n
 			}
-			t = typDDDArray(r.Type)
+			t = types.NewDDDArray(r.Type)
 		} else {
 			n.Left = indexlit(typecheck(n.Left, Erv))
 			l := n.Left
 			if consttype(l) != CTINT {
-				if l.Type != nil && l.Type.IsInteger() && l.Op != OLITERAL {
+				switch {
+				case l.Type == nil:
+					// Error already reported elsewhere.
+				case l.Type.IsInteger() && l.Op != OLITERAL:
 					yyerror("non-constant array bound %v", l)
-				} else {
+				default:
 					yyerror("invalid array bound %v", l)
 				}
 				n.Type = nil
@@ -367,7 +383,7 @@ OpSwitch:
 			}
 
 			v := l.Val()
-			if doesoverflow(v, Types[TINT]) {
+			if doesoverflow(v, types.Types[TINT]) {
 				yyerror("array bound is too large")
 				n.Type = nil
 				return n
@@ -379,14 +395,14 @@ OpSwitch:
 				n.Type = nil
 				return n
 			}
-			t = typArray(r.Type, bound)
+			t = types.NewArray(r.Type, bound)
 		}
 
 		n.Op = OTYPE
 		n.Type = t
 		n.Left = nil
 		n.Right = nil
-		if !t.isDDDArray() {
+		if !t.IsDDDArray() {
 			checkwidth(t)
 		}
 
@@ -400,21 +416,21 @@ OpSwitch:
 			n.Type = nil
 			return n
 		}
-		if l.Type.NotInHeap {
+		if l.Type.NotInHeap() {
 			yyerror("go:notinheap map key not allowed")
 		}
-		if r.Type.NotInHeap {
+		if r.Type.NotInHeap() {
 			yyerror("go:notinheap map value not allowed")
 		}
 		n.Op = OTYPE
-		n.Type = typMap(l.Type, r.Type)
+		n.Type = types.NewMap(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})
+				mapqueue = append(mapqueue, mapqueueval{l, n.Pos})
 			} else if bad.Etype != TANY {
 				// no need to queue, key is already bad
 				yyerror("invalid map key type %v", l.Type)
@@ -431,10 +447,10 @@ OpSwitch:
 			n.Type = nil
 			return n
 		}
-		if l.Type.NotInHeap {
+		if l.Type.NotInHeap() {
 			yyerror("chan of go:notinheap type not allowed")
 		}
-		t := typChan(l.Type, ChanDir(n.Etype)) // TODO(marvin): Fix Node.EType type union.
+		t := types.NewChan(l.Type, types.ChanDir(n.Etype)) // TODO(marvin): Fix Node.EType type union.
 		n.Op = OTYPE
 		n.Type = t
 		n.Left = nil
@@ -444,7 +460,7 @@ OpSwitch:
 		ok |= Etype
 		n.Op = OTYPE
 		n.Type = tostruct(n.List.Slice())
-		if n.Type == nil || n.Type.Broke {
+		if n.Type == nil || n.Type.Broke() {
 			n.Type = nil
 			return n
 		}
@@ -481,7 +497,13 @@ OpSwitch:
 		if l.Op == OTYPE {
 			ok |= Etype
 			n.Op = OTYPE
-			n.Type = ptrto(l.Type)
+			n.Type = types.NewPtr(l.Type)
+			// Ensure l.Type gets dowidth'd for the backend. Issue 20174.
+			// Don't checkwidth [...] arrays, though, since they
+			// will be replaced by concrete-sized arrays. Issue 20333.
+			if !l.Type.IsDDDArray() {
+				checkwidth(l.Type)
+			}
 			n.Left = nil
 			break OpSwitch
 		}
@@ -510,7 +532,6 @@ OpSwitch:
 		OEQ,
 		OGE,
 		OGT,
-		OHMUL,
 		OLE,
 		OLT,
 		OLSH,
@@ -536,7 +557,7 @@ OpSwitch:
 				n.Type = nil
 				return n
 			}
-			if n.Implicit && !okforarith[l.Type.Etype] {
+			if n.Implicit() && !okforarith[l.Type.Etype] {
 				yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
 				n.Type = nil
 				return n
@@ -556,7 +577,7 @@ OpSwitch:
 			op = n.Op
 		}
 		if op == OLSH || op == ORSH {
-			r = defaultlit(r, Types[TUINT])
+			r = defaultlit(r, types.Types[TUINT])
 			n.Right = r
 			t := r.Type
 			if !t.IsInteger() || t.IsSigned() {
@@ -608,7 +629,7 @@ OpSwitch:
 			if r.Type.Etype != TBLANK {
 				aop = assignop(l.Type, r.Type, nil)
 				if aop != 0 {
-					if r.Type.IsInterface() && !l.Type.IsInterface() && !l.Type.IsComparable() {
+					if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
 						yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
 						n.Type = nil
 						return n
@@ -618,7 +639,7 @@ OpSwitch:
 					if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 {
 						l = nod(aop, l, nil)
 						l.Type = r.Type
-						l.Typecheck = 1
+						l.SetTypecheck(1)
 						n.Left = l
 					}
 
@@ -630,7 +651,7 @@ OpSwitch:
 			if l.Type.Etype != TBLANK {
 				aop = assignop(r.Type, l.Type, nil)
 				if aop != 0 {
-					if l.Type.IsInterface() && !r.Type.IsInterface() && !r.Type.IsComparable() {
+					if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
 						yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
 						n.Type = nil
 						return n
@@ -640,7 +661,7 @@ OpSwitch:
 					if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 {
 						r = nod(aop, r, nil)
 						r.Type = l.Type
-						r.Typecheck = 1
+						r.SetTypecheck(1)
 						n.Right = r
 					}
 
@@ -669,7 +690,7 @@ OpSwitch:
 
 		// okfor allows any array == array, map == map, func == func.
 		// restrict to slice/map/func == nil and nil == slice/map/func.
-		if l.Type.IsArray() && !l.Type.IsComparable() {
+		if l.Type.IsArray() && !IsComparable(l.Type) {
 			yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
 			n.Type = nil
 			return n
@@ -694,7 +715,7 @@ OpSwitch:
 		}
 
 		if l.Type.IsStruct() {
-			if f := l.Type.IncomparableField(); f != nil {
+			if f := IncomparableField(l.Type); f != nil {
 				yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
 				n.Type = nil
 				return n
@@ -704,7 +725,7 @@ OpSwitch:
 		t = l.Type
 		if iscmp[n.Op] {
 			evconst(n)
-			t = idealbool
+			t = types.Idealbool
 			if n.Op != OLITERAL {
 				l, r = defaultlit2(l, r, true)
 				n.Left = l
@@ -715,7 +736,7 @@ OpSwitch:
 		if et == TSTRING {
 			if iscmp[n.Op] {
 				// TODO(marvin): Fix Node.EType type union.
-				n.Etype = EType(n.Op)
+				n.Etype = types.EType(n.Op)
 				n.Op = OCMPSTR
 			} else if n.Op == OADD {
 				// create OADDSTR node with list of strings in x + y + z + (w + v) + ...
@@ -746,7 +767,7 @@ OpSwitch:
 			} else // leave alone for back end
 			if r.Type.IsInterface() == l.Type.IsInterface() {
 				// TODO(marvin): Fix Node.EType type union.
-				n.Etype = EType(n.Op)
+				n.Etype = types.EType(n.Op)
 				n.Op = OCMPIFACE
 			}
 		}
@@ -793,18 +814,23 @@ OpSwitch:
 		r := outervalue(n.Left)
 		var l *Node
 		for l = n.Left; l != r; l = l.Left {
-			l.Addrtaken = true
-			if l.isClosureVar() {
-				l.Name.Defn.Addrtaken = true
+			l.SetAddrtaken(true)
+			if l.IsClosureVar() && !capturevarscomplete {
+				// Mark the original variable as Addrtaken so that capturevars
+				// knows not to pass it by value.
+				// But if the capturevars phase is complete, don't touch it,
+				// in case l.Name's containing function has not yet been compiled.
+				l.Name.Defn.SetAddrtaken(true)
 			}
 		}
 
 		if l.Orig != l && l.Op == ONAME {
 			Fatalf("found non-orig name node %v", l)
 		}
-		l.Addrtaken = true
-		if l.isClosureVar() {
-			l.Name.Defn.Addrtaken = true
+		l.SetAddrtaken(true)
+		if l.IsClosureVar() && !capturevarscomplete {
+			// See comments above about closure variables.
+			l.Name.Defn.SetAddrtaken(true)
 		}
 		n.Left = defaultlit(n.Left, nil)
 		l = n.Left
@@ -813,7 +839,7 @@ OpSwitch:
 			n.Type = nil
 			return n
 		}
-		n.Type = ptrto(t)
+		n.Type = types.NewPtr(t)
 		break OpSwitch
 
 	case OCOMPLIT:
@@ -871,7 +897,7 @@ OpSwitch:
 			n.Right = newname(n.Sym)
 			n.Type = methodfunc(n.Type, n.Left.Type)
 			n.Xoffset = 0
-			n.Class = PFUNC
+			n.SetClass(PFUNC)
 			ok = Erv
 			break OpSwitch
 		}
@@ -886,7 +912,7 @@ OpSwitch:
 			checkwidth(t)
 		}
 
-		if isblanksym(n.Sym) {
+		if n.Sym.IsBlank() {
 			yyerror("cannot refer to blank field or method")
 			n.Type = nil
 			return n
@@ -958,7 +984,7 @@ OpSwitch:
 		}
 
 		if n.Type != nil && !n.Type.IsInterface() {
-			var missing, have *Field
+			var missing, have *types.Field
 			var ptr int
 			if !implements(n.Type, t, &missing, &have, &ptr) {
 				if have != nil && have.Sym == missing.Sym {
@@ -1001,7 +1027,7 @@ OpSwitch:
 		case TSTRING, TARRAY, TSLICE:
 			n.Right = indexlit(n.Right)
 			if t.IsString() {
-				n.Type = bytetype
+				n.Type = types.Bytetype
 			} else {
 				n.Type = t.Elem()
 			}
@@ -1017,7 +1043,7 @@ OpSwitch:
 				break
 			}
 
-			if !n.Bounded && Isconst(n.Right, CTINT) {
+			if !n.Bounded() && Isconst(n.Right, CTINT) {
 				x := n.Right.Int64()
 				if x < 0 {
 					yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
@@ -1131,12 +1157,12 @@ OpSwitch:
 			}
 
 			n.Left = nod(OADDR, n.Left, nil)
-			n.Left.Implicit = true
+			n.Left.SetImplicit(true)
 			n.Left = typecheck(n.Left, Erv)
 			l = n.Left
 		}
 		t := l.Type
-		var tp *Type
+		var tp *types.Type
 		if t.IsString() {
 			if hasmax {
 				yyerror("invalid operation %v (3-index slice of string)", n)
@@ -1147,7 +1173,7 @@ OpSwitch:
 			n.Op = OSLICESTR
 		} else if t.IsPtr() && t.Elem().IsArray() {
 			tp = t.Elem()
-			n.Type = typSlice(tp.Elem())
+			n.Type = types.NewSlice(tp.Elem())
 			dowidth(n.Type)
 			if hasmax {
 				n.Op = OSLICE3ARR
@@ -1183,15 +1209,15 @@ OpSwitch:
 	// call and call like
 	case OCALL:
 		n.Left = typecheck(n.Left, Erv|Etype|Ecall)
-		if n.Left.Diag {
-			n.Diag = true
+		if n.Left.Diag() {
+			n.SetDiag(true)
 		}
 
 		l := n.Left
 
 		if l.Op == ONAME && l.Etype != 0 {
 			// TODO(marvin): Fix Node.EType type union.
-			if n.Isddd && Op(l.Etype) != OAPPEND {
+			if n.Isddd() && Op(l.Etype) != OAPPEND {
 				yyerror("invalid use of ... with builtin %v", l)
 			}
 
@@ -1207,11 +1233,11 @@ OpSwitch:
 		n.Left = defaultlit(n.Left, nil)
 		l = n.Left
 		if l.Op == OTYPE {
-			if n.Isddd || l.Type.isDDDArray() {
-				if !l.Type.Broke {
+			if n.Isddd() || l.Type.IsDDDArray() {
+				if !l.Type.Broke() {
 					yyerror("invalid use of ... in type conversion to %v", l.Type)
 				}
-				n.Diag = true
+				n.SetDiag(true)
 			}
 
 			// pick off before type-checking arguments
@@ -1230,8 +1256,8 @@ OpSwitch:
 			return n
 		}
 
-		if n.List.Len() == 1 && !n.Isddd {
-			n.List.SetIndex(0, typecheck(n.List.Index(0), Erv|Efnstruct))
+		if n.List.Len() == 1 && !n.Isddd() {
+			n.List.SetFirst(typecheck(n.List.First(), Erv|Efnstruct))
 		} else {
 			typecheckslice(n.List.Slice(), Erv)
 		}
@@ -1268,7 +1294,7 @@ OpSwitch:
 			}
 		}
 
-		typecheckaste(OCALL, n.Left, n.Isddd, t.Params(), 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.Results().NumFields() == 0 {
 			break OpSwitch
@@ -1277,7 +1303,7 @@ OpSwitch:
 		if t.Results().NumFields() == 1 {
 			n.Type = l.Type.Results().Field(0).Type
 
-			if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+			if n.Op == OCALLFUNC && n.Left.Op == ONAME && isRuntimePkg(n.Left.Sym.Pkg) && 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
@@ -1309,18 +1335,19 @@ OpSwitch:
 
 		// any side effects disappear; ignore init
 		var r Node
-		Nodconst(&r, Types[TUINTPTR], evalunsafe(n))
+		nodconst(&r, types.Types[TUINTPTR], evalunsafe(n))
 		r.Orig = n
 		n = &r
 
 		break OpSwitch
 
-	case OCAP, OLEN, OREAL, OIMAG:
+	case OCAP, OLEN:
 		ok |= Erv
 		if !onearg(n, "%v", n.Op) {
 			n.Type = nil
 			return n
 		}
+
 		n.Left = typecheck(n.Left, Erv)
 		n.Left = defaultlit(n.Left, nil)
 		n.Left = implicitstar(n.Left)
@@ -1330,62 +1357,109 @@ OpSwitch:
 			n.Type = nil
 			return n
 		}
-		switch n.Op {
-		case OCAP:
-			if !okforcap[t.Etype] {
-				goto badcall1
-			}
-
-		case OLEN:
-			if !okforlen[t.Etype] {
-				goto badcall1
-			}
 
-		case OREAL, OIMAG:
-			if !t.IsComplex() {
-				goto badcall1
-			}
-			if Isconst(l, CTCPLX) {
-				r := n
-				if n.Op == OREAL {
-					n = nodfltconst(&l.Val().U.(*Mpcplx).Real)
-				} else {
-					n = nodfltconst(&l.Val().U.(*Mpcplx).Imag)
-				}
-				n.Orig = r
-			}
-
-			n.Type = Types[cplxsubtype(t.Etype)]
-			break OpSwitch
+		var ok bool
+		if n.Op == OLEN {
+			ok = okforlen[t.Etype]
+		} else {
+			ok = okforcap[t.Etype]
+		}
+		if !ok {
+			yyerror("invalid argument %L for %v", l, n.Op)
+			n.Type = nil
+			return n
 		}
 
-		// might be constant
+		// result might be constant
+		var res int64 = -1 // valid if >= 0
 		switch t.Etype {
 		case TSTRING:
 			if Isconst(l, CTSTR) {
-				var r Node
-				Nodconst(&r, Types[TINT], int64(len(l.Val().U.(string))))
-				r.Orig = n
-				n = &r
+				res = int64(len(l.Val().U.(string)))
 			}
 
 		case TARRAY:
-			if callrecv(l) { // has call or receive
-				break
+			if !callrecv(l) {
+				res = t.NumElem()
 			}
+		}
+		if res >= 0 {
 			var r Node
-			Nodconst(&r, Types[TINT], t.NumElem())
+			nodconst(&r, types.Types[TINT], res)
 			r.Orig = n
 			n = &r
 		}
 
-		n.Type = Types[TINT]
+		n.Type = types.Types[TINT]
 		break OpSwitch
 
-	badcall1:
-		yyerror("invalid argument %L for %v", n.Left, n.Op)
-		n.Type = nil
-		return n
+	case OREAL, OIMAG:
+		ok |= Erv
+		if !onearg(n, "%v", n.Op) {
+			n.Type = nil
+			return n
+		}
+
+		n.Left = typecheck(n.Left, Erv)
+		l := n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return n
+		}
+
+		if t.Etype != TIDEAL && !t.IsComplex() {
+			yyerror("invalid argument %L for %v", l, n.Op)
+			n.Type = nil
+			return n
+		}
+
+		// if the argument is a constant, the result is a constant
+		// (any untyped numeric constant can be represented as a
+		// complex number)
+		if l.Op == OLITERAL {
+			var re, im *Mpflt
+			switch consttype(l) {
+			case CTINT, CTRUNE:
+				re = newMpflt()
+				re.SetInt(l.Val().U.(*Mpint))
+				// im = 0
+			case CTFLT:
+				re = l.Val().U.(*Mpflt)
+				// im = 0
+			case CTCPLX:
+				re = &l.Val().U.(*Mpcplx).Real
+				im = &l.Val().U.(*Mpcplx).Imag
+			default:
+				yyerror("invalid argument %L for %v", l, n.Op)
+				n.Type = nil
+				return n
+			}
+			if n.Op == OIMAG {
+				if im == nil {
+					im = newMpflt()
+				}
+				re = im
+			}
+			orig := n
+			n = nodfltconst(re)
+			n.Orig = orig
+		}
+
+		// determine result type
+		et := t.Etype
+		switch et {
+		case TIDEAL:
+			// result is ideal
+		case TCOMPLEX64:
+			et = TFLOAT32
+		case TCOMPLEX128:
+			et = TFLOAT64
+		default:
+			Fatalf("unexpected Etype: %v\n", et)
+		}
+		n.Type = types.Types[et]
+		break OpSwitch
 
 	case OCOMPLEX:
 		ok |= Erv
@@ -1411,8 +1485,8 @@ OpSwitch:
 			}
 
 			t = n.List.First().Type
-			l = t.Field(0).Nname
-			r = t.Field(1).Nname
+			l = asNode(t.Field(0).Nname)
+			r = asNode(t.Field(1).Nname)
 		} else {
 			if !twoarg(n) {
 				n.Type = nil
@@ -1441,7 +1515,7 @@ OpSwitch:
 			return n
 		}
 
-		var t *Type
+		var t *types.Type
 		switch l.Type.Etype {
 		default:
 			yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
@@ -1449,13 +1523,13 @@ OpSwitch:
 			return n
 
 		case TIDEAL:
-			t = Types[TIDEAL]
+			t = types.Types[TIDEAL]
 
 		case TFLOAT32:
-			t = Types[TCOMPLEX64]
+			t = types.Types[TCOMPLEX64]
 
 		case TFLOAT64:
-			t = Types[TCOMPLEX128]
+			t = types.Types[TCOMPLEX128]
 		}
 
 		if l.Op == OLITERAL && r.Op == OLITERAL {
@@ -1527,7 +1601,7 @@ OpSwitch:
 			return n
 		}
 
-		args.SetIndex(1, assignconv(r, l.Type.Key(), "delete"))
+		args.SetSecond(assignconv(r, l.Type.Key(), "delete"))
 		break OpSwitch
 
 	case OAPPEND:
@@ -1539,8 +1613,8 @@ OpSwitch:
 			return n
 		}
 
-		if args.Len() == 1 && !n.Isddd {
-			args.SetIndex(0, typecheck(args.Index(0), Erv|Efnstruct))
+		if args.Len() == 1 && !n.Isddd() {
+			args.SetFirst(typecheck(args.First(), Erv|Efnstruct))
 		} else {
 			typecheckslice(args.Slice(), Erv)
 		}
@@ -1552,7 +1626,7 @@ OpSwitch:
 		}
 
 		// Unpack multiple-return result before type-checking.
-		var funarg *Type
+		var funarg *types.Type
 		if t.IsFuncArgStruct() {
 			funarg = t
 			t = t.Field(0).Type
@@ -1571,7 +1645,7 @@ OpSwitch:
 			return n
 		}
 
-		if n.Isddd {
+		if n.Isddd() {
 			if args.Len() == 1 {
 				yyerror("cannot use ... on first argument to append")
 				n.Type = nil
@@ -1585,17 +1659,16 @@ OpSwitch:
 			}
 
 			if t.Elem().IsKind(TUINT8) && args.Second().Type.IsString() {
-				args.SetIndex(1, defaultlit(args.Index(1), Types[TSTRING]))
+				args.SetSecond(defaultlit(args.Second(), types.Types[TSTRING]))
 				break OpSwitch
 			}
 
-			args.SetIndex(1, assignconv(args.Index(1), t.Orig, "append"))
+			args.SetSecond(assignconv(args.Second(), t.Orig, "append"))
 			break OpSwitch
 		}
 
 		if funarg != nil {
-			_, it := iterFields(funarg) // Skip first field
-			for t := it.Next(); t != nil; t = it.Next() {
+			for _, t := range funarg.FieldSlice()[1:] {
 				if assignop(t.Type, n.Type.Elem(), nil) == 0 {
 					yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
 				}
@@ -1607,6 +1680,7 @@ OpSwitch:
 					continue
 				}
 				as[i] = assignconv(n, t.Elem(), "append")
+				checkwidth(as[i].Type) // ensure width is calculated for backend
 			}
 		}
 
@@ -1630,7 +1704,7 @@ OpSwitch:
 		n.Left = args.First()
 		n.Right = args.Second()
 		n.List.Set(nil)
-		n.Type = Types[TINT]
+		n.Type = types.Types[TINT]
 		n.Left = typecheck(n.Left, Erv)
 		n.Right = typecheck(n.Right, Erv)
 		if n.Left.Type == nil || n.Right.Type == nil {
@@ -1646,7 +1720,7 @@ OpSwitch:
 
 		// copy([]byte, string)
 		if n.Left.Type.IsSlice() && n.Right.Type.IsString() {
-			if eqtype(n.Left.Type.Elem(), bytetype) {
+			if eqtype(n.Left.Type.Elem(), types.Bytetype) {
 				break OpSwitch
 			}
 			yyerror("arguments to copy have different element types: %L and string", n.Left.Type)
@@ -1677,6 +1751,7 @@ OpSwitch:
 	case OCONV:
 		ok |= Erv
 		saveorignode(n)
+		checkwidth(n.Type) // ensure width is calculated for backend
 		n.Left = typecheck(n.Left, Erv)
 		n.Left = convlit1(n.Left, n.Type, true, noReuse)
 		t := n.Left.Type
@@ -1687,9 +1762,9 @@ OpSwitch:
 		var why string
 		n.Op = convertop(t, n.Type, &why)
 		if n.Op == 0 {
-			if !n.Diag && !n.Type.Broke {
+			if !n.Diag() && !n.Type.Broke() {
 				yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
-				n.Diag = true
+				n.SetDiag(true)
 			}
 
 			n.Op = OCONV
@@ -1704,6 +1779,13 @@ OpSwitch:
 				*r = *n
 				n.Op = OLITERAL
 				n.SetVal(n.Left.Val())
+			} else if t.Etype == n.Type.Etype {
+				switch t.Etype {
+				case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
+					// Floating point casts imply rounding and
+					// so the conversion must be kept.
+					n.Op = OCONV
+				}
 			}
 
 		// do not use stringtoarraylit.
@@ -1784,7 +1866,7 @@ OpSwitch:
 				l = args[i]
 				i++
 				l = typecheck(l, Erv)
-				l = defaultlit(l, Types[TINT])
+				l = defaultlit(l, types.Types[TINT])
 				if l.Type == nil {
 					n.Type = nil
 					return n
@@ -1805,7 +1887,7 @@ OpSwitch:
 				l = args[i]
 				i++
 				l = typecheck(l, Erv)
-				l = defaultlit(l, Types[TINT])
+				l = defaultlit(l, types.Types[TINT])
 				if l.Type == nil {
 					n.Type = nil
 					return n
@@ -1854,7 +1936,7 @@ OpSwitch:
 		}
 
 		n.Left = l
-		n.Type = ptrto(t)
+		n.Type = types.NewPtr(t)
 		break OpSwitch
 
 	case OPRINT, OPRINTN:
@@ -1864,7 +1946,7 @@ OpSwitch:
 		for i1, n1 := range ls {
 			// Special case for print: int constant is int64, not int.
 			if Isconst(n1, CTINT) {
-				ls[i1] = defaultlit(ls[i1], Types[TINT64])
+				ls[i1] = defaultlit(ls[i1], types.Types[TINT64])
 			} else {
 				ls[i1] = defaultlit(ls[i1], nil)
 			}
@@ -1879,7 +1961,7 @@ OpSwitch:
 			return n
 		}
 		n.Left = typecheck(n.Left, Erv)
-		n.Left = defaultlit(n.Left, Types[TINTER])
+		n.Left = defaultlit(n.Left, types.Types[TINTER])
 		if n.Left.Type == nil {
 			n.Type = nil
 			return n
@@ -1894,7 +1976,7 @@ OpSwitch:
 			return n
 		}
 
-		n.Type = Types[TINTER]
+		n.Type = types.Types[TINTER]
 		break OpSwitch
 
 	case OCLOSURE:
@@ -1916,7 +1998,7 @@ OpSwitch:
 		if !t.IsInterface() {
 			Fatalf("OITAB of %v", t)
 		}
-		n.Type = ptrto(Types[TUINTPTR])
+		n.Type = types.NewPtr(types.Types[TUINTPTR])
 		break OpSwitch
 
 	case OIDATA:
@@ -1937,9 +2019,9 @@ OpSwitch:
 			Fatalf("OSPTR of %v", t)
 		}
 		if t.IsString() {
-			n.Type = ptrto(Types[TUINT8])
+			n.Type = types.NewPtr(types.Types[TUINT8])
 		} else {
-			n.Type = ptrto(t.Elem())
+			n.Type = types.NewPtr(t.Elem())
 		}
 		break OpSwitch
 
@@ -1950,7 +2032,7 @@ OpSwitch:
 	case OCFUNC:
 		ok |= Erv
 		n.Left = typecheck(n.Left, Erv)
-		n.Type = Types[TUINTPTR]
+		n.Type = types.Types[TUINTPTR]
 		break OpSwitch
 
 	case OCONVNOP:
@@ -1989,12 +2071,19 @@ OpSwitch:
 	case OLABEL:
 		ok |= Etop
 		decldepth++
+		if n.Left.Sym.IsBlank() {
+			// Empty identifier is valid but useless.
+			// Eliminate now to simplify life later.
+			// See issues 7538, 11589, 11593.
+			n.Op = OEMPTY
+			n.Left = nil
+		}
 		break OpSwitch
 
 	case ODEFER:
 		ok |= Etop
 		n.Left = typecheck(n.Left, Etop|Erv)
-		if !n.Left.Diag {
+		if !n.Left.Diag() {
 			checkdefergo(n)
 		}
 		break OpSwitch
@@ -2005,7 +2094,7 @@ OpSwitch:
 		checkdefergo(n)
 		break OpSwitch
 
-	case OFOR:
+	case OFOR, OFORUNTIL:
 		ok |= Etop
 		typecheckslice(n.Ninit.Slice(), Etop)
 		decldepth++
@@ -2098,7 +2187,7 @@ OpSwitch:
 		ok |= Etop
 		n.Left = typecheck(n.Left, Etype)
 		checkwidth(n.Left.Type)
-		if n.Left.Type != nil && n.Left.Type.NotInHeap && n.Left.Name.Param.Pragma&NotInHeap == 0 {
+		if n.Left.Type != nil && n.Left.Type.NotInHeap() && n.Left.Name.Param.Pragma&NotInHeap == 0 {
 			// The type contains go:notinheap types, so it
 			// must be marked as such (alternatively, we
 			// could silently propagate go:notinheap).
@@ -2119,13 +2208,15 @@ OpSwitch:
 		}
 	}
 
-	if safemode && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
+	if safemode && !inimport && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
 		yyerror("cannot use unsafe.Pointer")
 	}
 
 	evconst(n)
 	if n.Op == OTYPE && top&Etype == 0 {
-		yyerror("type %v is not an expression", n.Type)
+		if !n.Type.Broke() {
+			yyerror("type %v is not an expression", n.Type)
+		}
 		n.Type = nil
 		return n
 	}
@@ -2144,23 +2235,19 @@ OpSwitch:
 	}
 
 	if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
-		if !n.Diag {
+		if !n.Diag() {
 			yyerror("%v evaluated but not used", n)
-			n.Diag = true
+			n.SetDiag(true)
 		}
 
 		n.Type = nil
 		return n
 	}
 
-	/* TODO
-	if(n->type == T)
-		fatal("typecheck nil type");
-	*/
 	return n
 }
 
-func checksliceindex(l *Node, r *Node, tp *Type) bool {
+func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
 	t := r.Type
 	if t == nil {
 		return false
@@ -2239,14 +2326,14 @@ func checkdefergo(n *Node) {
 
 	// type is broken or missing, most likely a method call on a broken type
 	// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
-	if n.Left.Type == nil || n.Left.Type.Broke {
+	if n.Left.Type == nil || n.Left.Type.Broke() {
 		return
 	}
 
-	if !n.Diag {
+	if !n.Diag() {
 		// The syntax made sure it was a call, so this must be
 		// a conversion.
-		n.Diag = true
+		n.SetDiag(true)
 		yyerror("%s requires function call, not conversion", what)
 	}
 }
@@ -2267,7 +2354,7 @@ func implicitstar(n *Node) *Node {
 		return n
 	}
 	n = nod(OIND, n, nil)
-	n.Implicit = true
+	n.SetImplicit(true)
 	n = typecheck(n, Erv)
 	return n
 }
@@ -2322,8 +2409,8 @@ func twoarg(n *Node) bool {
 	return true
 }
 
-func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
-	var r *Field
+func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
+	var r *types.Field
 	for _, f := range fs.Slice() {
 		if dostrcmp != 0 && f.Sym.Name == s.Name {
 			return f
@@ -2351,7 +2438,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
 	return r
 }
 
-func looktypedot(n *Node, t *Type, dostrcmp int) bool {
+func looktypedot(n *Node, t *types.Type, dostrcmp int) bool {
 	s := n.Sym
 
 	if t.IsInterface() {
@@ -2360,7 +2447,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
 			return false
 		}
 
-		n.Sym = methodsym(n.Sym, t, 0)
+		n.Sym = methodsym(n.Sym, t, false)
 		n.Xoffset = f1.Offset
 		n.Type = f1.Type
 		n.Op = ODOTINTER
@@ -2386,44 +2473,42 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
 		return false
 	}
 
-	n.Sym = methodsym(n.Sym, t, 0)
+	n.Sym = methodsym(n.Sym, t, false)
 	n.Xoffset = f2.Offset
 	n.Type = f2.Type
 	n.Op = ODOTMETH
 	return true
 }
 
-func derefall(t *Type) *Type {
-	for t != nil && t.Etype == Tptr {
+func derefall(t *types.Type) *types.Type {
+	for t != nil && t.Etype == types.Tptr {
 		t = t.Elem()
 	}
 	return t
 }
 
-type typeSym struct {
-	t *Type
-	s *Sym
+type typeSymKey struct {
+	t *types.Type
+	s *types.Sym
 }
 
-// dotField maps (*Type, *Sym) pairs to the corresponding struct field (*Type with Etype==TFIELD).
+// dotField maps (*types.Type, *types.Sym) pairs to the corresponding struct field (*types.Type with Etype==TFIELD).
 // It is a cache for use during usefield in walk.go, only enabled when field tracking.
-var dotField = map[typeSym]*Field{}
+var dotField = map[typeSymKey]*types.Field{}
 
-func lookdot(n *Node, t *Type, dostrcmp int) *Field {
+func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
 	s := n.Sym
 
 	dowidth(t)
-	var f1 *Field
+	var f1 *types.Field
 	if t.IsStruct() || t.IsInterface() {
 		f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
 	}
 
-	var f2 *Field
+	var f2 *types.Field
 	if n.Left.Type == t || n.Left.Type.Sym == nil {
 		mt := methtype(t)
 		if mt != nil {
-			// Use f2->method, not f2->xmethod: adddot has
-			// already inserted all the necessary embedded dots.
 			f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
 		}
 	}
@@ -2441,13 +2526,13 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
 		}
 		n.Xoffset = f1.Offset
 		n.Type = f1.Type
-		if obj.Fieldtrack_enabled > 0 {
-			dotField[typeSym{t.Orig, s}] = f1
+		if objabi.Fieldtrack_enabled > 0 {
+			dotField[typeSymKey{t.Orig, s}] = f1
 		}
 		if t.IsInterface() {
 			if n.Left.Type.IsPtr() {
 				n.Left = nod(OIND, n.Left, nil) // implicitstar
-				n.Left.Implicit = true
+				n.Left.SetImplicit(true)
 				n.Left = typecheck(n.Left, Erv)
 			}
 
@@ -2466,24 +2551,24 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
 		dowidth(tt)
 		rcvr := f2.Type.Recv().Type
 		if !eqtype(rcvr, tt) {
-			if rcvr.Etype == Tptr && eqtype(rcvr.Elem(), tt) {
+			if rcvr.Etype == types.Tptr && eqtype(rcvr.Elem(), tt) {
 				checklvalue(n.Left, "call pointer method on")
 				n.Left = nod(OADDR, n.Left, nil)
-				n.Left.Implicit = true
+				n.Left.SetImplicit(true)
 				n.Left = typecheck(n.Left, Etype|Erv)
-			} else if tt.Etype == Tptr && rcvr.Etype != Tptr && eqtype(tt.Elem(), rcvr) {
+			} else if tt.Etype == types.Tptr && rcvr.Etype != types.Tptr && eqtype(tt.Elem(), rcvr) {
 				n.Left = nod(OIND, n.Left, nil)
-				n.Left.Implicit = true
+				n.Left.SetImplicit(true)
 				n.Left = typecheck(n.Left, Etype|Erv)
-			} else if tt.Etype == Tptr && tt.Elem().Etype == Tptr && eqtype(derefall(tt), derefall(rcvr)) {
+			} else if tt.Etype == types.Tptr && tt.Elem().Etype == types.Tptr && eqtype(derefall(tt), derefall(rcvr)) {
 				yyerror("calling method %v with receiver %L requires explicit dereference", n.Sym, n.Left)
-				for tt.Etype == Tptr {
+				for tt.Etype == types.Tptr {
 					// Stop one level early for method with pointer receiver.
-					if rcvr.Etype == Tptr && tt.Elem().Etype != Tptr {
+					if rcvr.Etype == types.Tptr && tt.Elem().Etype != types.Tptr {
 						break
 					}
 					n.Left = nod(OIND, n.Left, nil)
-					n.Left.Implicit = true
+					n.Left.SetImplicit(true)
 					n.Left = typecheck(n.Left, Etype|Erv)
 					tt = tt.Elem()
 				}
@@ -2498,18 +2583,17 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
 			pll = ll
 			ll = ll.Left
 		}
-		if pll.Implicit && ll.Type.IsPtr() && 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 && asNode(ll.Type.Sym.Def) != nil && asNode(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.
+			// Make n.Left == ll to clarify error message.
 			n.Left = ll
 			return nil
 		}
 
-		n.Sym = methodsym(n.Sym, n.Left.Type, 0)
+		n.Sym = methodsym(n.Sym, n.Left.Type, false)
 		n.Xoffset = f2.Offset
 		n.Type = f2.Type
 
-		//		print("lookdot found [%p] %T\n", f2->type, f2->type);
 		n.Op = ODOTMETH
 
 		return f2
@@ -2527,9 +2611,9 @@ func nokeys(l Nodes) bool {
 	return true
 }
 
-func hasddd(t *Type) bool {
+func hasddd(t *types.Type) bool {
 	for _, tl := range t.Fields().Slice() {
-		if tl.Isddd {
+		if tl.Isddd() {
 			return true
 		}
 	}
@@ -2538,8 +2622,8 @@ func hasddd(t *Type) bool {
 }
 
 // typecheck assignment: type list = expression list
-func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc func() string) {
-	var t *Type
+func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
+	var t *types.Type
 	var n *Node
 	var n1 int
 	var n2 int
@@ -2547,7 +2631,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
 
 	lno := lineno
 
-	if tstruct.Broke {
+	if tstruct.Broke() {
 		goto out
 	}
 
@@ -2567,11 +2651,12 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
 					}
 				}
 
-				tn, it := iterFields(n.Type)
+				lfs := tstruct.FieldSlice()
+				rfs := n.Type.FieldSlice()
 				var why string
-				for _, tl := range tstruct.Fields().Slice() {
-					if tl.Isddd {
-						for ; tn != nil; tn = it.Next() {
+				for i, tl := range lfs {
+					if tl.Isddd() {
+						for _, tn := range rfs[i:] {
 							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.Elem(), call, why)
@@ -2580,13 +2665,13 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
 								}
 							}
 						}
-
 						goto out
 					}
 
-					if tn == nil {
+					if i >= len(rfs) {
 						goto notenough
 					}
+					tn := rfs[i]
 					if assignop(tn.Type, tl.Type, &why) == 0 {
 						if call != nil {
 							yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
@@ -2594,11 +2679,9 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
 							yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
 						}
 					}
-
-					tn = it.Next()
 				}
 
-				if tn != nil {
+				if len(rfs) > len(lfs) {
 					goto toomany
 				}
 				goto out
@@ -2633,7 +2716,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
 	i = 0
 	for _, tl := range tstruct.Fields().Slice() {
 		t = tl.Type
-		if tl.Isddd {
+		if tl.Isddd() {
 			if isddd {
 				if i >= nl.Len() {
 					goto notenough
@@ -2687,52 +2770,69 @@ out:
 	return
 
 notenough:
-	if n == nil || !n.Diag {
+	if n == nil || !n.Diag() {
+		details := errorDetails(nl, tstruct, isddd)
 		if call != nil {
 			// call is the expression being called, not the overall call.
 			// Method expressions have the form T.M, and the compiler has
 			// rewritten those to ONAME nodes but left T in Left.
 			if call.Op == ONAME && call.Left != nil && call.Left.Op == OTYPE {
-				yyerror("not enough arguments in call to method expression %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
+				yyerror("not enough arguments in call to method expression %v%s", call, details)
 			} else {
-				yyerror("not enough arguments in call to %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
+				yyerror("not enough arguments in call to %v%s", call, details)
 			}
 		} else {
-			yyerror("not enough arguments to %v\n\thave %s\n\twant %v", op, nl.retsigerr(isddd), tstruct)
+			yyerror("not enough arguments to %v%s", op, details)
 		}
 		if n != nil {
-			n.Diag = true
+			n.SetDiag(true)
 		}
 	}
 
 	goto out
 
 toomany:
+	details := errorDetails(nl, tstruct, isddd)
 	if call != nil {
-		yyerror("too many arguments in call to %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
+		yyerror("too many arguments in call to %v%s", call, details)
 	} else {
-		yyerror("too many arguments to %v\n\thave %s\n\twant %v", op, nl.retsigerr(isddd), tstruct)
+		yyerror("too many arguments to %v%s", op, details)
 	}
 	goto out
 }
 
+func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
+	// If we don't know any type at a call site, let's suppress any return
+	// message signatures. See Issue https://golang.org/issues/19012.
+	if tstruct == nil {
+		return ""
+	}
+	// If any node has an unknown type, suppress it as well
+	for _, n := range nl.Slice() {
+		if n.Type == nil {
+			return ""
+		}
+	}
+	return fmt.Sprintf("\n\thave %s\n\twant %v", nl.retsigerr(isddd), tstruct)
+}
+
 // sigrepr is a type's representation to the outside world,
 // in string representations of return signatures
 // e.g in error messages about wrong arguments to return.
-func (t *Type) sigrepr() string {
+func sigrepr(t *types.Type) string {
 	switch t {
 	default:
 		return t.String()
 
-	case Types[TIDEAL]:
+	case types.Types[TIDEAL]:
 		// "untyped number" is not commonly used
 		// outside of the compiler, so let's use "number".
 		return "number"
 
-	case idealstring:
+	case types.Idealstring:
 		return "string"
 
-	case idealbool:
+	case types.Idealbool:
 		return "bool"
 	}
 }
@@ -2747,11 +2847,11 @@ func (nl Nodes) retsigerr(isddd bool) string {
 	var typeStrings []string
 	if nl.Len() == 1 && nl.First().Type != nil && nl.First().Type.IsFuncArgStruct() {
 		for _, f := range nl.First().Type.Fields().Slice() {
-			typeStrings = append(typeStrings, f.Type.sigrepr())
+			typeStrings = append(typeStrings, sigrepr(f.Type))
 		}
 	} else {
 		for _, n := range nl.Slice() {
-			typeStrings = append(typeStrings, n.Type.sigrepr())
+			typeStrings = append(typeStrings, sigrepr(n.Type))
 		}
 	}
 
@@ -2831,7 +2931,7 @@ func keydup(n *Node, hash map[uint32][]*Node) {
 
 // iscomptype reports whether type t is a composite literal type
 // or a pointer to one.
-func iscomptype(t *Type) bool {
+func iscomptype(t *types.Type) bool {
 	if t.IsPtr() {
 		t = t.Elem()
 	}
@@ -2844,15 +2944,15 @@ func iscomptype(t *Type) bool {
 	}
 }
 
-func pushtype(n *Node, t *Type) {
+func pushtype(n *Node, t *types.Type) {
 	if n == nil || n.Op != OCOMPLIT || !iscomptype(t) {
 		return
 	}
 
 	if n.Right == nil {
 		n.Right = typenod(t)
-		n.Implicit = true       // don't print
-		n.Right.Implicit = true // * is okay
+		n.SetImplicit(true)       // don't print
+		n.Right.SetImplicit(true) // * is okay
 	} else if Debug['s'] != 0 {
 		n.Right = typecheck(n.Right, Etype)
 		if n.Right.Type != nil && eqtype(n.Right.Type, t) {
@@ -2870,15 +2970,12 @@ func typecheckcomplit(n *Node) *Node {
 	}()
 
 	if n.Right == nil {
-		if n.List.Len() != 0 {
-			setlineno(n.List.First())
-		}
-		yyerror("missing type in composite literal")
+		yyerrorl(n.Pos, "missing type in composite literal")
 		n.Type = nil
 		return n
 	}
 
-	// Save original node (including n->right)
+	// Save original node (including n.Right)
 	norig := nod(n.Op, nil, nil)
 
 	*norig = *n
@@ -2897,7 +2994,7 @@ func typecheckcomplit(n *Node) *Node {
 	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 {
+		if !n.Right.Implicit() {
 			yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
 			n.Type = nil
 			return n
@@ -2930,7 +3027,7 @@ func typecheckcomplit(n *Node) *Node {
 		}
 
 		var length, i int64
-		checkBounds := t.IsArray() && !t.isDDDArray()
+		checkBounds := t.IsArray() && !t.IsDDDArray()
 		nl := n.List.Slice()
 		for i2, l := range nl {
 			setlineno(l)
@@ -2939,9 +3036,9 @@ func typecheckcomplit(n *Node) *Node {
 				l.Left = typecheck(l.Left, Erv)
 				evconst(l.Left)
 				i = nonnegintconst(l.Left)
-				if i < 0 && !l.Left.Diag {
+				if i < 0 && !l.Left.Diag() {
 					yyerror("index must be non-negative integer constant")
-					l.Left.Diag = true
+					l.Left.SetDiag(true)
 					i = -(1 << 30) // stay negative for a while
 				}
 				vp = &l.Right
@@ -2972,7 +3069,7 @@ func typecheckcomplit(n *Node) *Node {
 			}
 		}
 
-		if t.isDDDArray() {
+		if t.IsDDDArray() {
 			t.SetNumElem(length)
 		}
 		if t.IsSlice() {
@@ -3017,14 +3114,12 @@ func typecheckcomplit(n *Node) *Node {
 		bad := 0
 		if n.List.Len() != 0 && nokeys(n.List) {
 			// simple list of variables
-			f, it := iterFields(t)
-
 			ls := n.List.Slice()
-			for i1, n1 := range ls {
+			for i, n1 := range ls {
 				setlineno(n1)
-				ls[i1] = typecheck(ls[i1], Erv)
-				n1 = ls[i1]
-				if f == nil {
+				n1 = typecheck(n1, Erv)
+				ls[i] = n1
+				if i >= t.NumFields() {
 					if bad == 0 {
 						yyerror("too many values in struct initializer")
 					}
@@ -3032,6 +3127,7 @@ func typecheckcomplit(n *Node) *Node {
 					continue
 				}
 
+				f := t.Field(i)
 				s := f.Sym
 				if s != nil && !exportname(s.Name) && s.Pkg != localpkg {
 					yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
@@ -3040,11 +3136,9 @@ func typecheckcomplit(n *Node) *Node {
 				n1 = assignconv(n1, f.Type, "field value")
 				n1 = nodSym(OSTRUCTKEY, n1, f.Sym)
 				n1.Xoffset = f.Offset
-				ls[i1] = n1
-				f = it.Next()
+				ls[i] = n1
 			}
-
-			if f != nil {
+			if len(ls) < t.NumFields() {
 				yyerror("too few values in struct initializer")
 			}
 		} else {
@@ -3066,7 +3160,7 @@ func typecheckcomplit(n *Node) *Node {
 					// 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 key.Sym == nil || key.Op == OXDOT {
+					if key.Sym == nil || key.Op == OXDOT || key.Sym.IsBlank() {
 						yyerror("invalid field name %v in struct initializer", key)
 						l.Left = typecheck(l.Left, Erv)
 						continue
@@ -3118,10 +3212,10 @@ func typecheckcomplit(n *Node) *Node {
 	n.Orig = norig
 	if n.Type.IsPtr() {
 		n = nod(OPTRLIT, n, nil)
-		n.Typecheck = 1
+		n.SetTypecheck(1)
 		n.Type = n.Left.Type
 		n.Left.Type = t
-		n.Left.Typecheck = 1
+		n.Left.SetTypecheck(1)
 	}
 
 	n.Orig = norig
@@ -3146,7 +3240,7 @@ func islvalue(n *Node) bool {
 		return islvalue(n.Left)
 
 	case ONAME:
-		if n.Class == PFUNC {
+		if n.Class() == PFUNC {
 			return false
 		}
 		return true
@@ -3167,15 +3261,15 @@ func checkassign(stmt *Node, n *Node) {
 		r := outervalue(n)
 		var l *Node
 		for l = n; l != r; l = l.Left {
-			l.Assigned = true
-			if l.isClosureVar() {
-				l.Name.Defn.Assigned = true
+			l.SetAssigned(true)
+			if l.IsClosureVar() {
+				l.Name.Defn.SetAssigned(true)
 			}
 		}
 
-		l.Assigned = true
-		if l.isClosureVar() {
-			l.Name.Defn.Assigned = true
+		l.SetAssigned(true)
+		if l.IsClosureVar() {
+			l.Name.Defn.SetAssigned(true)
 		}
 	}
 
@@ -3187,8 +3281,8 @@ func checkassign(stmt *Node, n *Node) {
 		return
 	}
 
-	// have already complained about n being undefined
-	if n.Op == ONONAME {
+	// have already complained about n being invalid
+	if n.Type == nil {
 		return
 	}
 
@@ -3271,14 +3365,17 @@ func typecheckas(n *Node) {
 	// second half of dance.
 	// now that right is done, typecheck the left
 	// just to get it over with.  see dance above.
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 
-	if n.Left.Typecheck == 0 {
+	if n.Left.Typecheck() == 0 {
 		n.Left = typecheck(n.Left, Erv|Easgn)
 	}
+	if !isblank(n.Left) {
+		checkwidth(n.Left.Type) // ensure width is calculated for backend
+	}
 }
 
-func checkassignto(src *Type, dst *Node) {
+func checkassignto(src *types.Type, dst *Node) {
 	var why string
 
 	if assignop(src, dst.Type, &why) == 0 {
@@ -3302,7 +3399,7 @@ func typecheckas2(n *Node) {
 	cl := n.List.Len()
 	cr := n.Rlist.Len()
 	if cl > 1 && cr == 1 {
-		n.Rlist.SetIndex(0, typecheck(n.Rlist.Index(0), Erv|Efnstruct))
+		n.Rlist.SetFirst(typecheck(n.Rlist.First(), Erv|Efnstruct))
 	} else {
 		typecheckslice(n.Rlist.Slice(), Erv)
 	}
@@ -3346,17 +3443,15 @@ func typecheckas2(n *Node) {
 				goto mismatch
 			}
 			n.Op = OAS2FUNC
-			t, s := iterFields(r.Type)
-			for _, n3 := range n.List.Slice() {
-				if t.Type != nil && n3.Type != nil {
-					checkassignto(t.Type, n3)
+			for i, l := range n.List.Slice() {
+				f := r.Type.Field(i)
+				if f.Type != nil && l.Type != nil {
+					checkassignto(f.Type, l)
 				}
-				if n3.Name != nil && n3.Name.Defn == n && n3.Name.Param.Ntype == nil {
-					n3.Type = t.Type
+				if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
+					l.Type = f.Type
 				}
-				t = s.Next()
 			}
-
 			goto out
 		}
 	}
@@ -3388,24 +3483,24 @@ func typecheckas2(n *Node) {
 			}
 			l := n.List.Second()
 			if l.Type != nil && !l.Type.IsBoolean() {
-				checkassignto(Types[TBOOL], l)
+				checkassignto(types.Types[TBOOL], l)
 			}
 			if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
-				l.Type = Types[TBOOL]
+				l.Type = types.Types[TBOOL]
 			}
 			goto out
 		}
 	}
 
 mismatch:
-	yyerror("assignment count mismatch: %d = %d", cl, cr)
+	yyerror("cannot assign %d values to %d variables", cr, cl)
 
 	// second half of dance
 out:
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 	ls = n.List.Slice()
 	for i1, n1 := range ls {
-		if n1.Typecheck == 0 {
+		if n1.Typecheck() == 0 {
 			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
@@ -3414,7 +3509,7 @@ out:
 // type check function definition
 func typecheckfunc(n *Node) {
 	for _, ln := range n.Func.Dcl {
-		if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+		if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
 			ln.Name.Decldepth = 1
 		}
 	}
@@ -3425,10 +3520,17 @@ func typecheckfunc(n *Node) {
 		return
 	}
 	n.Type = t
-	t.SetNname(n.Func.Nname)
+	t.FuncType().Nname = asTypesNode(n.Func.Nname)
 	rcvr := t.Recv()
 	if rcvr != nil && n.Func.Shortname != nil {
-		addmethod(n.Func.Shortname.Sym, t, true, n.Func.Pragma&Nointerface != 0)
+		n.Func.Nname.Sym = methodname(n.Func.Shortname, rcvr.Type)
+		declare(n.Func.Nname, PFUNC)
+
+		addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
+	}
+
+	if Ctxt.Flag_dynlink && !inimport && n.Func.Nname != nil {
+		makefuncsym(n.Func.Nname.Sym)
 	}
 }
 
@@ -3463,90 +3565,64 @@ func stringtoarraylit(n *Node) *Node {
 
 var ntypecheckdeftype int
 
-var methodqueue []*Node
-
-func domethod(n *Node) {
-	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
-	}
-
-	// If we have
-	//	type I interface {
-	//		M(_ int)
-	//	}
-	// then even though I.M looks like it doesn't care about the
-	// value of its argument, a specific implementation of I may
-	// care. The _ would suppress the assignment to that argument
-	// while generating a call, so remove it.
-	for _, t := 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)
-}
-
 type mapqueueval struct {
 	n   *Node
-	lno int32
+	lno src.XPos
 }
 
 // tracks the line numbers at which forward types are first used as map keys
 var mapqueue []mapqueueval
 
-func copytype(n *Node, t *Type) {
+func copytype(n *Node, t *types.Type) {
 	if t.Etype == TFORW {
 		// This type isn't computed yet; when it is, update n.
-		t.ForwardType().Copyto = append(t.ForwardType().Copyto, n)
+		t.ForwardType().Copyto = append(t.ForwardType().Copyto, asTypesNode(n))
 		return
 	}
 
 	embedlineno := n.Type.ForwardType().Embedlineno
 	l := n.Type.ForwardType().Copyto
 
-	ptrTo := n.Type.ptrTo
-	sliceOf := n.Type.sliceOf
+	ptrBase := n.Type.PtrBase
+	sliceOf := n.Type.SliceOf
 
 	// TODO(mdempsky): Fix Type rekinding.
 	*n.Type = *t
 
 	t = n.Type
 	t.Sym = n.Sym
-	t.Local = n.Local
+	t.SetLocal(n.Local())
 	if n.Name != nil {
 		t.Vargen = n.Name.Vargen
 	}
-	t.methods = Fields{}
-	t.allMethods = Fields{}
-	t.nod = nil
-	t.Deferwidth = false
-	t.ptrTo = ptrTo
-	t.sliceOf = sliceOf
+
+	// spec: "The declared type does not inherit any methods bound
+	// to the existing type, but the method set of an interface
+	// type [...] remains unchanged."
+	if !t.IsInterface() {
+		*t.Methods() = types.Fields{}
+		*t.AllMethods() = types.Fields{}
+	}
+
+	t.Nod = asTypesNode(n)
+	t.SetDeferwidth(false)
+	t.PtrBase = ptrBase
+	t.SliceOf = sliceOf
 
 	// Propagate go:notinheap pragma from the Name to the Type.
 	if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 {
-		t.NotInHeap = true
+		t.SetNotInHeap(true)
 	}
 
 	// Update nodes waiting on this type.
 	for _, n := range l {
-		copytype(n, t)
+		copytype(asNode(n), t)
 	}
 
 	// Double-check use of type as embedded type.
 	lno := lineno
 
-	if embedlineno != 0 {
+	if embedlineno.IsKnown() {
 		lineno = embedlineno
 		if t.IsPtr() || t.IsUnsafePtr() {
 			yyerror("embedded type cannot be a pointer")
@@ -3561,46 +3637,34 @@ func typecheckdeftype(n *Node) {
 	lno := lineno
 	setlineno(n)
 	n.Type.Sym = n.Sym
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 	n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
 	t := n.Name.Param.Ntype.Type
 	if t == nil {
-		n.Diag = true
+		n.SetDiag(true)
 		n.Type = nil
 		goto ret
 	}
 
 	if n.Type == nil {
-		n.Diag = true
+		n.SetDiag(true)
 		goto ret
 	}
 
 	// copy new type and clear fields
 	// that don't come along.
-	// anything zeroed here must be zeroed in
-	// typedcl2 too.
 	copytype(n, t)
 
 ret:
 	lineno = lno
 
 	// if there are no type definitions going on, it's safe to
-	// try to resolve the method types for the interfaces
+	// try to validate the map key types for the interfaces
 	// we just read.
 	if ntypecheckdeftype == 1 {
-		for {
-			s := methodqueue
-			if len(s) == 0 {
-				break
-			}
-			methodqueue = nil
-			for _, n := range s {
-				domethod(n)
-			}
-		}
 		for _, e := range mapqueue {
 			lineno = e.lno
-			if !e.n.Type.IsComparable() {
+			if !IsComparable(e.n.Type) {
 				yyerror("invalid map key type %v", e.n.Type)
 			}
 		}
@@ -3611,24 +3675,15 @@ ret:
 	ntypecheckdeftype--
 }
 
-func queuemethod(n *Node) {
-	if ntypecheckdeftype == 0 {
-		domethod(n)
-		return
-	}
-
-	methodqueue = append(methodqueue, n)
-}
-
 func typecheckdef(n *Node) *Node {
 	lno := lineno
 	setlineno(n)
 
 	if n.Op == ONONAME {
-		if !n.Diag {
-			n.Diag = true
-			if n.Lineno != 0 {
-				lineno = n.Lineno
+		if !n.Diag() {
+			n.SetDiag(true)
+			if n.Pos.IsKnown() {
+				lineno = n.Pos
 			}
 
 			// Note: adderrorname looks for this string and
@@ -3639,12 +3694,12 @@ func typecheckdef(n *Node) *Node {
 		return n
 	}
 
-	if n.Walkdef == 1 {
+	if n.Walkdef() == 1 {
 		return n
 	}
 
 	typecheckdefstack = append(typecheckdefstack, n)
-	if n.Walkdef == 2 {
+	if n.Walkdef() == 2 {
 		flusherrors()
 		fmt.Printf("typecheckdef loop:")
 		for i := len(typecheckdefstack) - 1; i >= 0; i-- {
@@ -3655,7 +3710,7 @@ func typecheckdef(n *Node) *Node {
 		Fatalf("typecheckdef loop")
 	}
 
-	n.Walkdef = 2
+	n.SetWalkdef(2)
 
 	if n.Type != nil || n.Sym == nil { // builtin or no name
 		goto ret
@@ -3674,7 +3729,7 @@ func typecheckdef(n *Node) *Node {
 			n.Type = n.Name.Param.Ntype.Type
 			n.Name.Param.Ntype = nil
 			if n.Type == nil {
-				n.Diag = true
+				n.SetDiag(true)
 				goto ret
 			}
 		}
@@ -3682,7 +3737,7 @@ func typecheckdef(n *Node) *Node {
 		e := n.Name.Defn
 		n.Name.Defn = nil
 		if e == nil {
-			lineno = n.Lineno
+			lineno = n.Pos
 			Dump("typecheckdef nil defn", n)
 			yyerror("xxx")
 		}
@@ -3694,9 +3749,9 @@ func typecheckdef(n *Node) *Node {
 		}
 
 		if e.Type != nil && e.Op != OLITERAL || !isgoconst(e) {
-			if !e.Diag {
+			if !e.Diag() {
 				yyerror("const initializer %v is not a constant", e)
-				e.Diag = true
+				e.SetDiag(true)
 			}
 
 			goto ret
@@ -3725,7 +3780,7 @@ func typecheckdef(n *Node) *Node {
 			n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
 			n.Type = n.Name.Param.Ntype.Type
 			if n.Type == nil {
-				n.Diag = true
+				n.SetDiag(true)
 				goto ret
 			}
 		}
@@ -3739,7 +3794,7 @@ func typecheckdef(n *Node) *Node {
 			}
 			if nsavederrors+nerrors > 0 {
 				// Can have undefined variables in x := foo
-				// that make x have an n->ndefn == nil.
+				// that make x have an n.name.Defn == nil.
 				// If there are other errors anyway, don't
 				// bother adding to the noise.
 				break
@@ -3754,23 +3809,40 @@ func typecheckdef(n *Node) *Node {
 			break
 		}
 
-		n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
+		n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n.Type
 
 	case OTYPE:
+		if p := n.Name.Param; p.Alias {
+			// Type alias declaration: Simply use the rhs type - no need
+			// to create a new type.
+			// If we have a syntax error, p.Ntype may be nil.
+			if p.Ntype != nil {
+				p.Ntype = typecheck(p.Ntype, Etype)
+				n.Type = p.Ntype.Type
+				if n.Type == nil {
+					n.SetDiag(true)
+					goto ret
+				}
+				n.Sym.Def = asTypesNode(p.Ntype)
+			}
+			break
+		}
+
+		// regular type declaration
 		if Curfn != nil {
 			defercheckwidth()
 		}
-		n.Walkdef = 1
-		n.Type = typ(TFORW)
-		n.Type.Sym = n.Sym
+		n.SetWalkdef(1)
+		n.Type = types.New(TFORW)
+		n.Type.Nod = asTypesNode(n)
+		n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
 		nerrors0 := nerrors
 		typecheckdeftype(n)
 		if n.Type.Etype == TFORW && nerrors > nerrors0 {
 			// Something went wrong during type-checking,
 			// but it was reported. Silence future errors.
-			n.Type.Broke = true
+			n.Type.SetBroke(true)
 		}
-
 		if Curfn != nil {
 			resumecheckwidth()
 		}
@@ -3788,11 +3860,11 @@ ret:
 	typecheckdefstack = typecheckdefstack[:last]
 
 	lineno = lno
-	n.Walkdef = 1
+	n.SetWalkdef(1)
 	return n
 }
 
-func checkmake(t *Type, arg string, n *Node) bool {
+func checkmake(t *types.Type, arg string, n *Node) bool {
 	if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
 		yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
 		return false
@@ -3814,7 +3886,7 @@ func checkmake(t *Type, arg string, n *Node) bool {
 	}
 
 	// defaultlit is necessary for non-constants too: n might be 1.1<<k.
-	n = defaultlit(n, Types[TINT])
+	n = defaultlit(n, types.Types[TINT])
 
 	return true
 }
@@ -3831,17 +3903,12 @@ func markbreak(n *Node, implicit *Node) {
 				implicit.SetHasBreak(true)
 			}
 		} else {
-			lab := n.Left.Sym.Label
+			lab := asNode(n.Left.Sym.Label)
 			if lab != nil {
 				lab.SetHasBreak(true)
 			}
 		}
-
-	case OFOR,
-		OSWITCH,
-		OTYPESW,
-		OSELECT,
-		ORANGE:
+	case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
 		implicit = n
 		fallthrough
 	default:
@@ -3863,8 +3930,8 @@ func markbreaklist(l Nodes, implicit *Node) {
 		}
 		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:
-				n.Left.Sym.Label = n.Name.Defn
+			case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
+				n.Left.Sym.Label = asTypesNode(n.Name.Defn)
 				markbreak(n.Name.Defn, n.Name.Defn)
 				n.Left.Sym.Label = nil
 				i++
@@ -3876,8 +3943,7 @@ func markbreaklist(l Nodes, implicit *Node) {
 	}
 }
 
-// Isterminating whether the Nodes list ends with a terminating
-// statement.
+// isterminating reports whether the Nodes list ends with a terminating statement.
 func (l Nodes) isterminating() bool {
 	s := l.Slice()
 	c := len(s)
@@ -3887,7 +3953,7 @@ func (l Nodes) isterminating() bool {
 	return s[c-1].isterminating()
 }
 
-// Isterminating returns whether the node n, the last one in a
+// Isterminating reports whether the node n, the last one in a
 // statement list, is a terminating statement.
 func (n *Node) isterminating() bool {
 	switch n.Op {
@@ -3899,14 +3965,10 @@ func (n *Node) isterminating() bool {
 	case OBLOCK:
 		return n.List.isterminating()
 
-	case OGOTO,
-		ORETURN,
-		ORETJMP,
-		OPANIC,
-		OXFALL:
+	case OGOTO, ORETURN, ORETJMP, OPANIC, OXFALL:
 		return true
 
-	case OFOR:
+	case OFOR, OFORUNTIL:
 		if n.Left != nil {
 			return false
 		}
@@ -3941,6 +4003,7 @@ func (n *Node) isterminating() bool {
 	return false
 }
 
+// checkreturn makes sure that fn terminates appropriately.
 func checkreturn(fn *Node) {
 	if fn.Type.Results().NumFields() != 0 && fn.Nbody.Len() != 0 {
 		markbreaklist(fn.Nbody, nil)
@@ -3949,3 +4012,26 @@ func checkreturn(fn *Node) {
 		}
 	}
 }
+
+func deadcode(fn *Node) {
+	deadcodeslice(fn.Nbody)
+}
+
+func deadcodeslice(nn Nodes) {
+	for _, n := range nn.Slice() {
+		if n == nil {
+			continue
+		}
+		if n.Op == OIF && Isconst(n.Left, CTBOOL) {
+			if n.Left.Bool() {
+				n.Rlist = Nodes{}
+			} else {
+				n.Nbody = Nodes{}
+			}
+		}
+		deadcodeslice(n.Ninit)
+		deadcodeslice(n.Nbody)
+		deadcodeslice(n.List)
+		deadcodeslice(n.Rlist)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/types.go b/src/cmd/compile/internal/gc/types.go
new file mode 100644
index 0000000..aa0f066
--- /dev/null
+++ b/src/cmd/compile/internal/gc/types.go
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. 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/types"
+)
+
+// convenience constants
+const (
+	Txxx = types.Txxx
+
+	TINT8    = types.TINT8
+	TUINT8   = types.TUINT8
+	TINT16   = types.TINT16
+	TUINT16  = types.TUINT16
+	TINT32   = types.TINT32
+	TUINT32  = types.TUINT32
+	TINT64   = types.TINT64
+	TUINT64  = types.TUINT64
+	TINT     = types.TINT
+	TUINT    = types.TUINT
+	TUINTPTR = types.TUINTPTR
+
+	TCOMPLEX64  = types.TCOMPLEX64
+	TCOMPLEX128 = types.TCOMPLEX128
+
+	TFLOAT32 = types.TFLOAT32
+	TFLOAT64 = types.TFLOAT64
+
+	TBOOL = types.TBOOL
+
+	TPTR32 = types.TPTR32
+	TPTR64 = types.TPTR64
+
+	TFUNC      = types.TFUNC
+	TSLICE     = types.TSLICE
+	TARRAY     = types.TARRAY
+	TSTRUCT    = types.TSTRUCT
+	TCHAN      = types.TCHAN
+	TMAP       = types.TMAP
+	TINTER     = types.TINTER
+	TFORW      = types.TFORW
+	TANY       = types.TANY
+	TSTRING    = types.TSTRING
+	TUNSAFEPTR = types.TUNSAFEPTR
+
+	// pseudo-types for literals
+	TIDEAL = types.TIDEAL
+	TNIL   = types.TNIL
+	TBLANK = types.TBLANK
+
+	// pseudo-types for frame layout
+	TFUNCARGS = types.TFUNCARGS
+	TCHANARGS = types.TCHANARGS
+
+	// pseudo-types for import/export
+	TDDDFIELD = types.TDDDFIELD // wrapper: contained type is a ... field
+
+	NTYPE = types.NTYPE
+)
diff --git a/src/cmd/compile/internal/gc/types_acc.go b/src/cmd/compile/internal/gc/types_acc.go
new file mode 100644
index 0000000..7240f72
--- /dev/null
+++ b/src/cmd/compile/internal/gc/types_acc.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go 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 convertions between *types.Node and *Node.
+// TODO(gri) try to eliminate these soon
+
+package gc
+
+import (
+	"cmd/compile/internal/types"
+	"unsafe"
+)
+
+func asNode(n *types.Node) *Node      { return (*Node)(unsafe.Pointer(n)) }
+func asTypesNode(n *Node) *types.Node { return (*types.Node)(unsafe.Pointer(n)) }
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 30c9c37..31a15d2 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -2,16 +2,20 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(gri) This file should probably become part of package types.
+
 package gc
 
+import "cmd/compile/internal/types"
+
 // builtinpkg is a fake package that declares the universe block.
-var builtinpkg *Pkg
+var builtinpkg *types.Pkg
 
-var itable *Type // distinguished *byte
+var itable *types.Type // distinguished *byte
 
 var basicTypes = [...]struct {
 	name  string
-	etype EType
+	etype types.EType
 }{
 	{"int8", TINT8},
 	{"int16", TINT16},
@@ -31,14 +35,13 @@ var basicTypes = [...]struct {
 
 var typedefs = [...]struct {
 	name     string
-	etype    EType
-	width    *int
-	sameas32 EType
-	sameas64 EType
+	etype    types.EType
+	sameas32 types.EType
+	sameas64 types.EType
 }{
-	{"int", TINT, &Widthint, TINT32, TINT64},
-	{"uint", TUINT, &Widthint, TUINT32, TUINT64},
-	{"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
+	{"int", TINT, TINT32, TINT64},
+	{"uint", TUINT, TUINT32, TUINT64},
+	{"uintptr", TUINTPTR, TUINT32, TUINT64},
 }
 
 var builtinFuncs = [...]struct {
@@ -82,81 +85,77 @@ func initUniverse() {
 func lexinit() {
 	for _, s := range basicTypes {
 		etype := s.etype
-		if int(etype) >= len(Types) {
+		if int(etype) >= len(types.Types) {
 			Fatalf("lexinit: %s bad etype", s.name)
 		}
-		s2 := Pkglookup(s.name, builtinpkg)
-		t := Types[etype]
+		s2 := builtinpkg.Lookup(s.name)
+		t := types.Types[etype]
 		if t == nil {
-			t = typ(etype)
+			t = types.New(etype)
 			t.Sym = s2
 			if etype != TANY && etype != TSTRING {
 				dowidth(t)
 			}
-			Types[etype] = t
+			types.Types[etype] = t
 		}
-		s2.Def = typenod(t)
-		s2.Def.Name = new(Name)
+		s2.Def = asTypesNode(typenod(t))
+		asNode(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)
+		s2 := builtinpkg.Lookup(s.name)
+		s2.Def = asTypesNode(newname(s2))
+		asNode(s2.Def).Etype = types.EType(s.op)
 	}
 
 	for _, s := range unsafeFuncs {
-		s2 := Pkglookup(s.name, unsafepkg)
-		s2.Def = nod(ONAME, nil, nil)
-		s2.Def.Sym = s2
-		s2.Def.Etype = EType(s.op)
+		s2 := unsafepkg.Lookup(s.name)
+		s2.Def = asTypesNode(newname(s2))
+		asNode(s2.Def).Etype = types.EType(s.op)
 	}
 
-	idealstring = typ(TSTRING)
-	idealbool = typ(TBOOL)
-	Types[TANY] = typ(TANY)
+	types.Idealstring = types.New(TSTRING)
+	types.Idealbool = types.New(TBOOL)
+	types.Types[TANY] = types.New(TANY)
 
-	s := Pkglookup("true", builtinpkg)
-	s.Def = nodbool(true)
-	s.Def.Sym = lookup("true")
-	s.Def.Name = new(Name)
-	s.Def.Type = idealbool
+	s := builtinpkg.Lookup("true")
+	s.Def = asTypesNode(nodbool(true))
+	asNode(s.Def).Sym = lookup("true")
+	asNode(s.Def).Name = new(Name)
+	asNode(s.Def).Type = types.Idealbool
 
-	s = Pkglookup("false", builtinpkg)
-	s.Def = nodbool(false)
-	s.Def.Sym = lookup("false")
-	s.Def.Name = new(Name)
-	s.Def.Type = idealbool
+	s = builtinpkg.Lookup("false")
+	s.Def = asTypesNode(nodbool(false))
+	asNode(s.Def).Sym = lookup("false")
+	asNode(s.Def).Name = new(Name)
+	asNode(s.Def).Type = types.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.Def = asTypesNode(newname(s))
+	types.Types[TBLANK] = types.New(TBLANK)
+	asNode(s.Def).Type = types.Types[TBLANK]
+	nblank = asNode(s.Def)
 
-	s = Pkglookup("_", builtinpkg)
+	s = builtinpkg.Lookup("_")
 	s.Block = -100
-	s.Def = nod(ONAME, nil, nil)
-	s.Def.Sym = s
-	Types[TBLANK] = typ(TBLANK)
-	s.Def.Type = Types[TBLANK]
+	s.Def = asTypesNode(newname(s))
+	types.Types[TBLANK] = types.New(TBLANK)
+	asNode(s.Def).Type = types.Types[TBLANK]
 
-	Types[TNIL] = typ(TNIL)
-	s = Pkglookup("nil", builtinpkg)
+	types.Types[TNIL] = types.New(TNIL)
+	s = builtinpkg.Lookup("nil")
 	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)
+	s.Def = asTypesNode(nodlit(v))
+	asNode(s.Def).Sym = s
+	asNode(s.Def).Name = new(Name)
+
+	s = builtinpkg.Lookup("iota")
+	s.Def = asTypesNode(nod(OIOTA, nil, nil))
+	asNode(s.Def).Sym = s
+	asNode(s.Def).Name = new(Name)
 }
 
 func typeinit() {
@@ -164,26 +163,26 @@ func typeinit() {
 		Fatalf("typeinit before betypeinit")
 	}
 
-	for et := EType(0); et < NTYPE; et++ {
+	for et := types.EType(0); et < NTYPE; et++ {
 		simtype[et] = et
 	}
 
-	Types[TPTR32] = typ(TPTR32)
-	dowidth(Types[TPTR32])
+	types.Types[TPTR32] = types.New(TPTR32)
+	dowidth(types.Types[TPTR32])
 
-	Types[TPTR64] = typ(TPTR64)
-	dowidth(Types[TPTR64])
+	types.Types[TPTR64] = types.New(TPTR64)
+	dowidth(types.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])
+	t := types.New(TUNSAFEPTR)
+	types.Types[TUNSAFEPTR] = t
+	t.Sym = unsafepkg.Lookup("Pointer")
+	t.Sym.Def = asTypesNode(typenod(t))
+	asNode(t.Sym.Def).Name = new(Name)
+	dowidth(types.Types[TUNSAFEPTR])
 
-	Tptr = TPTR32
+	types.Tptr = TPTR32
 	if Widthptr == 8 {
-		Tptr = TPTR64
+		types.Tptr = TPTR64
 	}
 
 	for et := TINT8; et <= TUINT64; et++ {
@@ -202,7 +201,7 @@ func typeinit() {
 	isforw[TFORW] = true
 
 	// initialize okfor
-	for et := EType(0); et < NTYPE; et++ {
+	for et := types.EType(0); et < NTYPE; et++ {
 		if isInt[et] || et == TIDEAL {
 			okforeq[et] = true
 			okforcmp[et] = true
@@ -276,7 +275,6 @@ func typeinit() {
 
 	// binary
 	okfor[OADD] = okforadd[:]
-
 	okfor[OAND] = okforand[:]
 	okfor[OANDAND] = okforbool[:]
 	okfor[OANDNOT] = okforand[:]
@@ -287,7 +285,6 @@ func typeinit() {
 	okfor[OLE] = okforcmp[:]
 	okfor[OLT] = okforcmp[:]
 	okfor[OMOD] = okforand[:]
-	okfor[OHMUL] = okforarith[:]
 	okfor[OMUL] = okforarith[:]
 	okfor[ONE] = okforeq[:]
 	okfor[OOR] = okforand[:]
@@ -299,19 +296,16 @@ func typeinit() {
 
 	// 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
@@ -344,80 +338,87 @@ func typeinit() {
 	minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
 
 	// for walk to use in error messages
-	Types[TFUNC] = functype(nil, nil, nil)
+	types.Types[TFUNC] = functype(nil, nil, nil)
 
 	// types used in front end
-	// types[TNIL] got set early in lexinit
-	Types[TIDEAL] = typ(TIDEAL)
+	// types.Types[TNIL] got set early in lexinit
+	types.Types[TIDEAL] = types.New(TIDEAL)
 
-	Types[TINTER] = typ(TINTER)
+	types.Types[TINTER] = types.New(TINTER)
 
 	// simple aliases
-	simtype[TMAP] = Tptr
-
-	simtype[TCHAN] = Tptr
-	simtype[TFUNC] = Tptr
-	simtype[TUNSAFEPTR] = Tptr
+	simtype[TMAP] = types.Tptr
+	simtype[TCHAN] = types.Tptr
+	simtype[TFUNC] = types.Tptr
+	simtype[TUNSAFEPTR] = types.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)))
+	array_nel = int(Rnd(int64(array_array)+int64(Widthptr), int64(Widthptr)))
+	array_cap = int(Rnd(int64(array_nel)+int64(Widthptr), int64(Widthptr)))
+	sizeof_Array = int(Rnd(int64(array_cap)+int64(Widthptr), int64(Widthptr)))
 
 	// string is same as slice wo the cap
-	sizeof_String = int(Rnd(int64(array_nel)+int64(Widthint), int64(Widthptr)))
+	sizeof_String = int(Rnd(int64(array_nel)+int64(Widthptr), int64(Widthptr)))
 
-	dowidth(Types[TSTRING])
-	dowidth(idealstring)
+	dowidth(types.Types[TSTRING])
+	dowidth(types.Idealstring)
 
-	itable = typPtr(Types[TUINT8])
+	itable = types.NewPtr(types.Types[TUINT8])
 }
 
-func makeErrorInterface() *Type {
-	field := newField()
-	field.Type = Types[TSTRING]
-	f := functypefield(fakethisfield(), nil, []*Field{field})
+func makeErrorInterface() *types.Type {
+	field := types.NewField()
+	field.Type = types.Types[TSTRING]
+	f := functypefield(fakeRecvField(), nil, []*types.Field{field})
 
-	field = newField()
+	field = types.NewField()
 	field.Sym = lookup("Error")
 	field.Type = f
 
-	t := typ(TINTER)
-	t.SetFields([]*Field{field})
+	t := types.New(TINTER)
+	t.SetInterface([]*types.Field{field})
 	return t
 }
 
 func lexinit1() {
 	// error type
-	s := Pkglookup("error", builtinpkg)
-	errortype = makeErrorInterface()
-	errortype.Sym = s
+	s := builtinpkg.Lookup("error")
+	types.Errortype = makeErrorInterface()
+	types.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)
+	s.Def = asTypesNode(typenod(types.Errortype))
+
+	// We create separate byte and rune types for better error messages
+	// rather than just creating type alias *types.Sym's for the uint8 and
+	// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
+	// TODO(gri) Should we get rid of this special case (at the cost
+	// of less informative error messages involving bytes and runes)?
+	// (Alternatively, we could introduce an OTALIAS node representing
+	// type aliases, albeit at the cost of having to deal with it everywhere).
 
 	// byte alias
-	s = Pkglookup("byte", builtinpkg)
-	bytetype = typ(TUINT8)
-	bytetype.Sym = s
-	s.Def = typenod(bytetype)
-	s.Def.Name = new(Name)
+	s = builtinpkg.Lookup("byte")
+	types.Bytetype = types.New(TUINT8)
+	types.Bytetype.Sym = s
+	s.Def = asTypesNode(typenod(types.Bytetype))
+	asNode(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)
+	s = builtinpkg.Lookup("rune")
+	types.Runetype = types.New(TINT32)
+	types.Runetype.Sym = s
+	s.Def = asTypesNode(typenod(types.Runetype))
+	asNode(s.Def).Name = new(Name)
 
 	// backend-dependent builtin types (e.g. int).
 	for _, s := range typedefs {
-		s1 := Pkglookup(s.name, builtinpkg)
+		s1 := builtinpkg.Lookup(s.name)
 
 		sameas := s.sameas32
-		if *s.width == 8 {
+		if Widthptr == 8 {
 			sameas = s.sameas64
 		}
 
@@ -427,11 +428,11 @@ func lexinit1() {
 		minintval[s.etype] = minintval[sameas]
 		maxintval[s.etype] = maxintval[sameas]
 
-		t := typ(s.etype)
+		t := types.New(s.etype)
 		t.Sym = s1
-		Types[s.etype] = t
-		s1.Def = typenod(t)
-		s1.Def.Name = new(Name)
+		types.Types[s.etype] = t
+		s1.Def = asTypesNode(typenod(t))
+		asNode(s1.Def).Name = new(Name)
 		s1.Origpkg = builtinpkg
 
 		dowidth(t)
@@ -457,9 +458,8 @@ func finishUniverse() {
 		s1.Block = s.Block
 	}
 
-	nodfp = nod(ONAME, nil, nil)
-	nodfp.Type = Types[TINT32]
-	nodfp.Xoffset = 0
-	nodfp.Class = PPARAM
-	nodfp.Sym = lookup(".fp")
+	nodfp = newname(lookup(".fp"))
+	nodfp.Type = types.Types[TINT32]
+	nodfp.SetClass(PPARAM)
+	nodfp.Name.SetUsed(true)
 }
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
index c62bd00..58be2f8 100644
--- a/src/cmd/compile/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -10,8 +10,10 @@ import (
 	"runtime/pprof"
 )
 
+// Line returns n's position as a string. If n has been inlined,
+// it uses the outermost position where n has been inlined.
 func (n *Node) Line() string {
-	return Ctxt.LineHist.LineString(int(n.Lineno))
+	return linestr(n.Pos)
 }
 
 var atExitFuncs []func()
@@ -30,11 +32,13 @@ func Exit(code int) {
 }
 
 var (
+	blockprofile   string
 	cpuprofile     string
 	memprofile     string
 	memprofilerate int64
 	traceprofile   string
 	traceHandler   func(string)
+	mutexprofile   string
 )
 
 func startProfile() {
@@ -67,6 +71,31 @@ func startProfile() {
 				Fatalf("%v", err)
 			}
 		})
+	} else {
+		// Not doing memory profiling; disable it entirely.
+		runtime.MemProfileRate = 0
+	}
+	if blockprofile != "" {
+		f, err := os.Create(blockprofile)
+		if err != nil {
+			Fatalf("%v", err)
+		}
+		runtime.SetBlockProfileRate(1)
+		atExit(func() {
+			pprof.Lookup("block").WriteTo(f, 0)
+			f.Close()
+		})
+	}
+	if mutexprofile != "" {
+		f, err := os.Create(mutexprofile)
+		if err != nil {
+			Fatalf("%v", err)
+		}
+		startMutexProfiling()
+		atExit(func() {
+			pprof.Lookup("mutex").WriteTo(f, 0)
+			f.Close()
+		})
 	}
 	if traceprofile != "" && traceHandler != nil {
 		traceHandler(traceprofile)
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index d080d21..15108e6 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -5,7 +5,8 @@
 package gc
 
 import (
-	"cmd/internal/obj"
+	"cmd/compile/internal/types"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"strings"
@@ -28,7 +29,7 @@ func walk(fn *Node) {
 
 	// Final typecheck for any unused variables.
 	for i, ln := range fn.Func.Dcl {
-		if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) {
+		if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) {
 			ln = typecheck(ln, Erv|Easgn)
 			fn.Func.Dcl[i] = ln
 		}
@@ -36,25 +37,23 @@ func walk(fn *Node) {
 
 	// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
 	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
+		if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Name.Used() {
+			ln.Name.Defn.Left.Name.SetUsed(true)
 		}
 	}
 
 	for _, ln := range fn.Func.Dcl {
-		if ln.Op != ONAME || (ln.Class != PAUTO && ln.Class != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Used {
+		if ln.Op != ONAME || (ln.Class() != PAUTO && ln.Class() != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Name.Used() {
 			continue
 		}
 		if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
-			if defn.Left.Used {
+			if defn.Left.Name.Used() {
 				continue
 			}
-			lineno = defn.Left.Lineno
-			yyerror("%v declared and not used", ln.Sym)
-			defn.Left.Used = true // suppress repeats
+			yyerrorl(defn.Left.Pos, "%v declared and not used", ln.Sym)
+			defn.Left.Name.SetUsed(true) // suppress repeats
 		} else {
-			lineno = ln.Lineno
-			yyerror("%v declared and not used", ln.Sym)
+			yyerrorl(ln.Pos, "%v declared and not used", ln.Sym)
 		}
 	}
 
@@ -68,6 +67,7 @@ func walk(fn *Node) {
 		dumplist(s, Curfn.Nbody)
 	}
 
+	zeroResults()
 	heapmoves()
 	if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
 		s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
@@ -95,9 +95,9 @@ func samelist(a, b []*Node) bool {
 
 func paramoutheap(fn *Node) bool {
 	for _, ln := range fn.Func.Dcl {
-		switch ln.Class {
+		switch ln.Class() {
 		case PPARAMOUT:
-			if ln.isParamStackCopy() || ln.Addrtaken {
+			if ln.isParamStackCopy() || ln.Addrtaken() {
 				return true
 			}
 
@@ -119,7 +119,7 @@ func adjustargs(n *Node, adjust int) {
 	callfunc := n.Left
 	for _, arg = range callfunc.List.Slice() {
 		if arg.Op != OAS {
-			yyerror("call arg not assignment")
+			Fatalf("call arg not assignment")
 		}
 		lhs = arg.Left
 		if lhs.Op == ONAME {
@@ -129,12 +129,12 @@ func adjustargs(n *Node, adjust int) {
 		}
 
 		if lhs.Op != OINDREGSP {
-			yyerror("call argument store does not use OINDREGSP")
+			Fatalf("call argument store does not use OINDREGSP")
 		}
 
 		// can't really check this in machine-indep code.
 		//if(lhs->val.u.reg != D_SP)
-		//      yyerror("call arg assign not indreg(SP)");
+		//      Fatalf("call arg assign not indreg(SP)")
 		lhs.Xoffset += int64(adjust)
 	}
 }
@@ -145,9 +145,6 @@ func walkstmt(n *Node) *Node {
 	if n == nil {
 		return n
 	}
-	if n.IsStatic { // don't walk, generated by anylit.
-		return n
-	}
 
 	setlineno(n)
 
@@ -183,7 +180,7 @@ func walkstmt(n *Node) *Node {
 		OEMPTY,
 		ORECOVER,
 		OGETG:
-		if n.Typecheck == 0 {
+		if n.Typecheck() == 0 {
 			Fatalf("missing typecheck: %+v", n)
 		}
 		wascopy := n.Op == OCOPY
@@ -198,14 +195,14 @@ func walkstmt(n *Node) *Node {
 	// special case for a receive where we throw away
 	// the value received.
 	case ORECV:
-		if n.Typecheck == 0 {
+		if n.Typecheck() == 0 {
 			Fatalf("missing typecheck: %+v", n)
 		}
 		init := n.Ninit
 		n.Ninit.Set(nil)
 
 		n.Left = walkexpr(n.Left, &init)
-		n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
+		n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, n.Left, nodnil())
 		n = walkexpr(n, &init)
 
 		n = addinit(n, init.Slice())
@@ -224,15 +221,15 @@ func walkstmt(n *Node) *Node {
 
 	case ODCL:
 		v := n.Left
-		if v.Class == PAUTOHEAP {
+		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 := nod(OAS, v.Name.Param.Heapaddr, prealloc[v])
+			nn.SetColas(true)
 			nn = typecheck(nn, Etop)
 			return walkstmt(nn)
 		}
@@ -249,7 +246,7 @@ func walkstmt(n *Node) *Node {
 		n.Right = walkstmt(n.Right)
 
 	case ODEFER:
-		hasdefer = true
+		Curfn.Func.SetHasDefer(true)
 		switch n.Left.Op {
 		case OPRINT, OPRINTN:
 			n.Left = walkprintfunc(n.Left, &n.Ninit)
@@ -264,7 +261,7 @@ func walkstmt(n *Node) *Node {
 		// make room for size & fn arguments.
 		adjustargs(n, 2*Widthptr)
 
-	case OFOR:
+	case OFOR, OFORUNTIL:
 		if n.Left != nil {
 			walkstmtlist(n.Left.Ninit.Slice())
 			init := n.Left.Ninit
@@ -308,13 +305,13 @@ func walkstmt(n *Node) *Node {
 
 			var cl Class
 			for _, ln := range Curfn.Func.Dcl {
-				cl = ln.Class
+				cl = ln.Class()
 				if cl == PAUTO || cl == PAUTOHEAP {
 					break
 				}
 				if cl == PPARAMOUT {
 					if ln.isParamStackCopy() {
-						ln = walkexpr(typecheck(nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
+						ln = walkexpr(typecheck(nod(OIND, ln.Name.Param.Heapaddr, nil), Erv), nil)
 					}
 					rl = append(rl, ln)
 				}
@@ -338,14 +335,10 @@ func walkstmt(n *Node) *Node {
 
 			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, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
+		ll := ascompatte(nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
 		n.List.Set(ll)
 
 	case ORETJMP:
@@ -358,7 +351,7 @@ func walkstmt(n *Node) *Node {
 		walkswitch(n)
 
 	case ORANGE:
-		walkrange(n)
+		n = walkrange(n)
 
 	case OXFALL:
 		yyerror("fallthrough statement out of place")
@@ -413,9 +406,9 @@ func walkexprlistcheap(s []*Node, init *Nodes) {
 // Build name of function for interface conversion.
 // Not all names are possible
 // (e.g., we'll never generate convE2E or convE2I or convI2E).
-func convFuncName(from, to *Type) string {
-	tkind := to.iet()
-	switch from.iet() {
+func convFuncName(from, to *types.Type) string {
+	tkind := to.Tie()
+	switch from.Tie() {
 	case 'I':
 		switch tkind {
 		case 'I':
@@ -424,12 +417,40 @@ func convFuncName(from, to *Type) string {
 	case 'T':
 		switch tkind {
 		case 'E':
+			switch {
+			case from.Size() == 2 && from.Align == 2:
+				return "convT2E16"
+			case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
+				return "convT2E32"
+			case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
+				return "convT2E64"
+			case from.IsString():
+				return "convT2Estring"
+			case from.IsSlice():
+				return "convT2Eslice"
+			case !types.Haspointers(from):
+				return "convT2Enoptr"
+			}
 			return "convT2E"
 		case 'I':
+			switch {
+			case from.Size() == 2 && from.Align == 2:
+				return "convT2I16"
+			case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
+				return "convT2I32"
+			case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
+				return "convT2I64"
+			case from.IsString():
+				return "convT2Istring"
+			case from.IsSlice():
+				return "convT2Islice"
+			case !types.Haspointers(from):
+				return "convT2Inoptr"
+			}
 			return "convT2I"
 		}
 	}
-	Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
+	Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
 	panic("unreachable")
 }
 
@@ -440,6 +461,15 @@ func walkexpr(n *Node, init *Nodes) *Node {
 		return n
 	}
 
+	// Eagerly checkwidth all expressions for the back end.
+	if n.Type != nil && !n.Type.WidthCalculated() {
+		switch n.Type.Etype {
+		case TBLANK, TNIL, TIDEAL:
+		default:
+			checkwidth(n.Type)
+		}
+	}
+
 	if init == &n.Ninit {
 		// not okay to use n->ninit when walking n,
 		// because we might replace n with some other node
@@ -458,15 +488,15 @@ func walkexpr(n *Node, init *Nodes) *Node {
 		Dump("walk-before", n)
 	}
 
-	if n.Typecheck != 1 {
+	if n.Typecheck() != 1 {
 		Fatalf("missed typecheck: %+v", n)
 	}
 
-	if n.Op == ONAME && n.Class == PAUTOHEAP {
-		nn := nod(OIND, n.Name.Heapaddr, nil)
+	if n.Op == ONAME && n.Class() == PAUTOHEAP {
+		nn := nod(OIND, n.Name.Param.Heapaddr, nil)
 		nn = typecheck(nn, Erv)
 		nn = walkexpr(nn, init)
-		nn.Left.NonNil = true
+		nn.Left.SetNonNil(true)
 		return nn
 	}
 
@@ -476,29 +506,37 @@ opswitch:
 		Dump("walk", n)
 		Fatalf("walkexpr: switch 1 unknown op %+S", n)
 
-	case OTYPE,
-		ONONAME,
-		OINDREGSP,
-		OEMPTY,
-		OGETG:
+	case ONONAME, OINDREGSP, OEMPTY, OGETG:
 
-	case ONOT,
-		OMINUS,
-		OPLUS,
-		OCOM,
-		OREAL,
-		OIMAG,
-		ODOTMETH,
-		ODOTINTER:
+	case OTYPE, ONAME, OLITERAL:
+		// TODO(mdempsky): Just return n; see discussion on CL 38655.
+		// Perhaps refactor to use Node.mayBeShared for these instead.
+		// If these return early, make sure to still call
+		// stringsym for constant strings.
+
+	case ONOT, OMINUS, OPLUS, OCOM, OREAL, OIMAG, ODOTMETH, ODOTINTER,
+		OIND, OSPTR, OITAB, OIDATA, OADDR:
 		n.Left = walkexpr(n.Left, init)
 
-	case OIND:
+	case OEFACE, OAND, OSUB, OMUL, OLT, OLE, OGE, OGT, OADD, OOR, OXOR:
 		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 	case ODOT:
 		usefield(n)
 		n.Left = walkexpr(n.Left, init)
 
+	case ODOTTYPE, ODOTTYPE2:
+		n.Left = walkexpr(n.Left, init)
+		// Set up interface type addresses for back end.
+		n.Right = typename(n.Type)
+		if n.Op == ODOTTYPE {
+			n.Right.Right = typename(n.Left.Type)
+		}
+		if !n.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
+			n.List.Set1(itabname(n.Type, n.Left.Type))
+		}
+
 	case ODOTPTR:
 		usefield(n)
 		if n.Op == ODOTPTR && n.Left.Type.Elem().Width == 0 {
@@ -510,13 +548,6 @@ opswitch:
 
 		n.Left = walkexpr(n.Left, init)
 
-	case OEFACE:
-		n.Left = walkexpr(n.Left, init)
-		n.Right = walkexpr(n.Right, init)
-
-	case OSPTR, OITAB, OIDATA:
-		n.Left = walkexpr(n.Left, init)
-
 	case OLEN, OCAP:
 		n.Left = walkexpr(n.Left, init)
 
@@ -529,43 +560,28 @@ opswitch:
 		}
 		if t.IsArray() {
 			safeexpr(n.Left, init)
-			Nodconst(n, n.Type, t.NumElem())
-			n.Typecheck = 1
+			nodconst(n, n.Type, t.NumElem())
+			n.SetTypecheck(1)
 		}
 
 	case OLSH, ORSH:
 		n.Left = walkexpr(n.Left, init)
 		n.Right = walkexpr(n.Right, init)
 		t := n.Left.Type
-		n.Bounded = bounded(n.Right, 8*t.Width)
+		n.SetBounded(bounded(n.Right, 8*t.Width))
 		if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
 			Warn("shift bounds check elided")
 		}
 
+	case OCOMPLEX:
 		// Use results from call expression as arguments for complex.
-	case OAND,
-		OSUB,
-		OHMUL,
-		OLT,
-		OLE,
-		OGE,
-		OGT,
-		OADD,
-		OCOMPLEX,
-		OLROT:
-		if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
+		if n.Left == nil && n.Right == nil {
 			n.Left = n.List.First()
 			n.Right = n.List.Second()
 		}
-
 		n.Left = walkexpr(n.Left, init)
 		n.Right = walkexpr(n.Right, init)
 
-	case OOR, OXOR:
-		n.Left = walkexpr(n.Left, init)
-		n.Right = walkexpr(n.Right, init)
-		n = walkrotate(n)
-
 	case OEQ, ONE:
 		n.Left = walkexpr(n.Left, init)
 		n.Right = walkexpr(n.Right, init)
@@ -602,14 +618,8 @@ opswitch:
 	case ORECOVER:
 		n = mkcall("gorecover", n.Type, init, nod(OADDR, nodfp, nil))
 
-	case OLITERAL:
-		n.Addable = true
-
 	case OCLOSUREVAR, OCFUNC:
-		n.Addable = true
-
-	case ONAME:
-		n.Addable = true
+		n.SetAddable(true)
 
 	case OCALLINTER:
 		usemethod(n)
@@ -619,7 +629,7 @@ opswitch:
 		}
 		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)
+		ll := ascompatte(n, n.Isddd(), t.Params(), n.List.Slice(), 0, init)
 		n.List.Set(reorder1(ll))
 
 	case OCALLFUNC:
@@ -652,17 +662,7 @@ opswitch:
 		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" || n.Left.Sym.Pkg == localpkg && myimportpath == "math") {
-			if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X) {
-				n.Op = OSQRT
-				n.Left = n.List.First()
-				n.List.Set(nil)
-				break opswitch
-			}
-		}
-
-		ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
+		ll := ascompatte(n, n.Isddd(), t.Params(), n.List.Slice(), 0, init)
 		n.List.Set(reorder1(ll))
 
 	case OCALLMETH:
@@ -672,11 +672,11 @@ opswitch:
 		}
 		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 := ascompatte(n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
+		lr := ascompatte(n, n.Isddd(), t.Params(), n.List.Slice(), 0, init)
 		ll = append(ll, lr...)
 		n.Left.Left = nil
-		ullmancalc(n.Left)
+		updateHasCall(n.Left)
 		n.List.Set(reorder1(ll))
 
 	case OAS:
@@ -694,7 +694,7 @@ opswitch:
 			break
 		}
 
-		if !instrumenting && iszero(n.Right) && !needwritebarrier(n.Left, n.Right) {
+		if !instrumenting && iszero(n.Right) {
 			break
 		}
 
@@ -709,17 +709,17 @@ opswitch:
 
 			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)
+			n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, r, n1)
 			n = walkexpr(n, init)
 			break opswitch
 
 		case OAPPEND:
 			// x = append(...)
 			r := n.Right
-			if r.Type.Elem().NotInHeap {
+			if r.Type.Elem().NotInHeap() {
 				yyerror("%v is go:notinheap; heap allocation disallowed", r.Type.Elem())
 			}
-			if r.Isddd {
+			if r.Isddd() {
 				r = appendslice(r, init) // also works for append(slice, string).
 			} else {
 				r = walkappend(r, init, n)
@@ -728,6 +728,8 @@ opswitch:
 			if r.Op == OAPPEND {
 				// Left in place for back end.
 				// Do not add a new write barrier.
+				// Set up address of type for back end.
+				r.Left = typename(r.Type.Elem())
 				break opswitch
 			}
 			// Otherwise, lowered for race detector.
@@ -735,10 +737,7 @@ opswitch:
 		}
 
 		if n.Left != nil && n.Right != nil {
-			static := n.IsStatic
 			n = convas(n, init)
-			n.IsStatic = static
-			n = applywritebarrier(n)
 		}
 
 	case OAS2:
@@ -747,9 +746,6 @@ opswitch:
 		walkexprlistsafe(n.Rlist.Slice(), init)
 		ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
 		ll = reorder3(ll)
-		for i, n := range ll {
-			ll[i] = applywritebarrier(n)
-		}
 		n = liststmt(ll)
 
 	// a,b,... = fn()
@@ -767,9 +763,6 @@ opswitch:
 		init.Append(r)
 
 		ll := ascompatet(n.Op, n.List, r.Type)
-		for i, n := range ll {
-			ll[i] = applywritebarrier(n)
-		}
 		n = liststmt(ll)
 
 	// x, y = <-c
@@ -789,11 +782,11 @@ opswitch:
 		n1.Etype = 1 // addr does not escape
 		fn := chanfn("chanrecv2", 2, r.Left.Type)
 		ok := n.List.Second()
-		call := mkcall1(fn, ok.Type, init, typename(r.Left.Type), r.Left, n1)
+		call := mkcall1(fn, ok.Type, init, r.Left, n1)
 		n = nod(OAS, ok, call)
 		n = typecheck(n, Etop)
 
-		// a,b = m[i];
+	// a,b = m[i]
 	case OAS2MAPR:
 		init.AppendNodes(&n.Ninit)
 
@@ -802,28 +795,16 @@ opswitch:
 		r.Left = walkexpr(r.Left, init)
 		r.Right = walkexpr(r.Right, init)
 		t := r.Left.Type
-		p := ""
-		if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-			switch algtype(t.Key()) {
-			case AMEM32:
-				p = "mapaccess2_fast32"
-			case AMEM64:
-				p = "mapaccess2_fast64"
-			case ASTRING:
-				p = "mapaccess2_faststr"
-			}
-		}
 
+		fast := mapfast(t)
 		var key *Node
-		if p != "" {
+		if fast != mapslow {
 			// fast versions take key by value
 			key = r.Right
 		} else {
 			// standard version takes key by reference
 			// orderexpr made sure key is addressable.
 			key = nod(OADDR, r.Right, nil)
-
-			p = "mapaccess2"
 		}
 
 		// from:
@@ -834,7 +815,7 @@ opswitch:
 		a := n.List.First()
 
 		if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
-			fn := mapfn(p, t)
+			fn := mapfn(mapaccess2[fast], t)
 			r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
 		} else {
 			fn := mapfn("mapaccess2_fat", t)
@@ -853,10 +834,10 @@ opswitch:
 
 		// don't generate a = *var if a is _
 		if !isblank(a) {
-			var_ := temp(ptrto(t.Val()))
-			var_.Typecheck = 1
-			var_.NonNil = true // mapaccess always returns a non-nil pointer
-			n.List.SetIndex(0, var_)
+			var_ := temp(types.NewPtr(t.Val()))
+			var_.SetTypecheck(1)
+			var_.SetNonNil(true) // mapaccess always returns a non-nil pointer
+			n.List.SetFirst(var_)
 			n = walkexpr(n, init)
 			init.Append(n)
 			n = nod(OAS, a, nod(OIND, var_, nil))
@@ -872,19 +853,17 @@ opswitch:
 		map_ = walkexpr(map_, init)
 		key = walkexpr(key, init)
 
-		// orderstmt made sure key is addressable.
-		key = nod(OADDR, key, nil)
-
 		t := map_.Type
-		n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
+		fast := mapfast(t)
+		if fast == mapslow {
+			// orderstmt made sure key is addressable.
+			key = nod(OADDR, key, nil)
+		}
+		n = mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
 
 	case OAS2DOTTYPE:
 		walkexprlistsafe(n.List.Slice(), init)
-		e := n.Rlist.First() // i.(T)
-		e.Left = walkexpr(e.Left, init)
-
-	case ODOTTYPE, ODOTTYPE2:
-		n.Left = walkexpr(n.Left, init)
+		n.Rlist.SetFirst(walkexpr(n.Rlist.First(), init))
 
 	case OCONVIFACE:
 		n.Left = walkexpr(n.Left, init)
@@ -899,26 +878,55 @@ opswitch:
 			}
 			l := nod(OEFACE, t, n.Left)
 			l.Type = n.Type
-			l.Typecheck = n.Typecheck
+			l.SetTypecheck(n.Typecheck())
 			n = l
 			break
 		}
-		// Optimize convT2{E,I} when T is not pointer-shaped.
-		// We make the interface by initializing a stack temporary to
-		// the value we want to put in the interface, then using the address of
-		// that stack temporary for the interface data word.
-		if !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024 {
-			tmp := temp(n.Left.Type)
-			init.Append(typecheck(nod(OAS, tmp, n.Left), Etop))
+
+		if staticbytes == nil {
+			staticbytes = newname(Runtimepkg.Lookup("staticbytes"))
+			staticbytes.SetClass(PEXTERN)
+			staticbytes.Type = types.NewArray(types.Types[TUINT8], 256)
+			zerobase = newname(Runtimepkg.Lookup("zerobase"))
+			zerobase.SetClass(PEXTERN)
+			zerobase.Type = types.Types[TUINTPTR]
+		}
+
+		// Optimize convT2{E,I} for many cases in which T is not pointer-shaped,
+		// by using an existing addressable value identical to n.Left
+		// or creating one on the stack.
+		var value *Node
+		switch {
+		case n.Left.Type.Size() == 0:
+			// n.Left is zero-sized. Use zerobase.
+			cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
+			value = zerobase
+		case n.Left.Type.IsBoolean() || (n.Left.Type.Size() == 1 && n.Left.Type.IsInteger()):
+			// n.Left is a bool/byte. Use staticbytes[n.Left].
+			n.Left = cheapexpr(n.Left, init)
+			value = nod(OINDEX, staticbytes, byteindex(n.Left))
+			value.SetBounded(true)
+		case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
+			// n.Left is a readonly global; use it directly.
+			value = n.Left
+		case !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024:
+			// n.Left does not escape. Use a stack temporary initialized to n.Left.
+			value = temp(n.Left.Type)
+			init.Append(typecheck(nod(OAS, value, n.Left), Etop))
+		}
+
+		if value != nil {
+			// Value is identical to n.Left.
+			// Construct the interface directly: {type/itab, &value}.
 			var t *Node
 			if n.Type.IsEmptyInterface() {
 				t = typename(n.Left.Type)
 			} else {
 				t = itabname(n.Left.Type, n.Type)
 			}
-			l := nod(OEFACE, t, typecheck(nod(OADDR, tmp, nil), Erv))
+			l := nod(OEFACE, t, typecheck(nod(OADDR, value, nil), Erv))
 			l.Type = n.Type
-			l.Typecheck = n.Typecheck
+			l.SetTypecheck(n.Typecheck())
 			n = l
 			break
 		}
@@ -935,7 +943,7 @@ opswitch:
 			init.Append(nod(OAS, c, n.Left))
 
 			// Get the itab out of the interface.
-			tmp := temp(ptrto(Types[TUINT8]))
+			tmp := temp(types.NewPtr(types.Types[TUINT8]))
 			init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), Erv)))
 
 			// Get the type out of the itab.
@@ -944,9 +952,9 @@ opswitch:
 			init.Append(nif)
 
 			// Build the result.
-			e := nod(OEFACE, tmp, ifaceData(c, ptrto(Types[TUINT8])))
+			e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8])))
 			e.Type = n.Type // assign type manually, typecheck doesn't understand OEFACE.
-			e.Typecheck = 1
+			e.SetTypecheck(1)
 			n = e
 			break
 		}
@@ -990,60 +998,60 @@ opswitch:
 		n = walkexpr(n, init)
 
 	case OCONV, OCONVNOP:
-		if Thearch.LinkArch.Family == sys.ARM || Thearch.LinkArch.Family == sys.MIPS {
+		if thearch.LinkArch.Family == sys.ARM || thearch.LinkArch.Family == sys.MIPS {
 			if n.Left.Type.IsFloat() {
 				if n.Type.Etype == TINT64 {
-					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					n = mkcall("float64toint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64]))
 					break
 				}
 
 				if n.Type.Etype == TUINT64 {
-					n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					n = mkcall("float64touint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64]))
 					break
 				}
 			}
 
 			if n.Type.IsFloat() {
 				if n.Left.Type.Etype == TINT64 {
-					n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
+					n = conv(mkcall("int64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TINT64])), n.Type)
 					break
 				}
 
 				if n.Left.Type.Etype == TUINT64 {
-					n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
+					n = conv(mkcall("uint64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT64])), n.Type)
 					break
 				}
 			}
 		}
 
-		if Thearch.LinkArch.Family == sys.I386 {
+		if thearch.LinkArch.Family == sys.I386 {
 			if n.Left.Type.IsFloat() {
 				if n.Type.Etype == TINT64 {
-					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					n = mkcall("float64toint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64]))
 					break
 				}
 
 				if n.Type.Etype == TUINT64 {
-					n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					n = mkcall("float64touint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64]))
 					break
 				}
 				if n.Type.Etype == TUINT32 || n.Type.Etype == TUINT || n.Type.Etype == TUINTPTR {
-					n = mkcall("float64touint32", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					n = mkcall("float64touint32", n.Type, init, conv(n.Left, types.Types[TFLOAT64]))
 					break
 				}
 			}
 			if n.Type.IsFloat() {
 				if n.Left.Type.Etype == TINT64 {
-					n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
+					n = conv(mkcall("int64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TINT64])), n.Type)
 					break
 				}
 
 				if n.Left.Type.Etype == TUINT64 {
-					n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
+					n = conv(mkcall("uint64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT64])), n.Type)
 					break
 				}
 				if n.Left.Type.Etype == TUINT32 || n.Left.Type.Etype == TUINT || n.Left.Type.Etype == TUINTPTR {
-					n = conv(mkcall("uint32tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT32])), n.Type)
+					n = conv(mkcall("uint32tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT32])), n.Type)
 					break
 				}
 			}
@@ -1058,11 +1066,6 @@ opswitch:
 		n.Right = typecheck(n.Right, Erv)
 		n.Right = walkexpr(n.Right, init)
 
-	case OMUL:
-		n.Left = walkexpr(n.Left, init)
-		n.Right = walkexpr(n.Right, init)
-		n = walkmul(n, init)
-
 	case ODIV, OMOD:
 		n.Left = walkexpr(n.Left, init)
 		n.Right = walkexpr(n.Right, init)
@@ -1072,7 +1075,7 @@ opswitch:
 
 		if isComplex[et] && n.Op == ODIV {
 			t := n.Type
-			n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
+			n = mkcall("complex128div", types.Types[TCOMPLEX128], init, conv(n.Left, types.Types[TCOMPLEX128]), conv(n.Right, types.Types[TCOMPLEX128]))
 			n = conv(n, t)
 			break
 		}
@@ -1082,15 +1085,28 @@ opswitch:
 			break
 		}
 
-		// Try rewriting as shifts or magic multiplies.
-		n = walkdiv(n, init)
-
-		// rewrite 64-bit div and mod into function calls
-		// on 32-bit architectures.
-		switch n.Op {
-		case OMOD, ODIV:
-			if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
-				break opswitch
+		// rewrite 64-bit div and mod on 32-bit architectures.
+		// TODO: Remove this code once we can introduce
+		// runtime calls late in SSA processing.
+		if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
+			if n.Right.Op == OLITERAL {
+				// Leave div/mod by constant powers of 2.
+				// The SSA backend will handle those.
+				switch et {
+				case TINT64:
+					c := n.Right.Int64()
+					if c < 0 {
+						c = -c
+					}
+					if c != 0 && c&(c-1) == 0 {
+						break opswitch
+					}
+				case TUINT64:
+					c := uint64(n.Right.Int64())
+					if c != 0 && c&(c-1) == 0 {
+						break opswitch
+					}
+				}
 			}
 			var fn string
 			if et == TINT64 {
@@ -1103,7 +1119,7 @@ opswitch:
 			} else {
 				fn += "mod"
 			}
-			n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
+			n = mkcall(fn, n.Type, init, conv(n.Left, types.Types[et]), conv(n.Right, types.Types[et]))
 		}
 
 	case OINDEX:
@@ -1117,7 +1133,7 @@ opswitch:
 
 		// if range of type cannot exceed static array bound,
 		// disable bounds check.
-		if n.Bounded {
+		if n.Bounded() {
 			break
 		}
 		t := n.Left.Type
@@ -1125,19 +1141,19 @@ opswitch:
 			t = t.Elem()
 		}
 		if t.IsArray() {
-			n.Bounded = bounded(r, t.NumElem())
-			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
+			n.SetBounded(bounded(r, t.NumElem()))
+			if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
 				Warn("index bounds check elided")
 			}
-			if smallintconst(n.Right) && !n.Bounded {
+			if smallintconst(n.Right) && !n.Bounded() {
 				yyerror("index out of bounds")
 			}
 		} else if Isconst(n.Left, CTSTR) {
-			n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
-			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
+			n.SetBounded(bounded(r, int64(len(n.Left.Val().U.(string)))))
+			if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
 				Warn("index bounds check elided")
 			}
-			if smallintconst(n.Right) && !n.Bounded {
+			if smallintconst(n.Right) && !n.Bounded() {
 				yyerror("index out of bounds")
 			}
 		}
@@ -1157,43 +1173,34 @@ opswitch:
 		t := map_.Type
 		if n.Etype == 1 {
 			// This m[k] expression is on the left-hand side of an assignment.
-			// orderexpr made sure key is addressable.
-			key = nod(OADDR, key, nil)
-			n = mkcall1(mapfn("mapassign", t), nil, init, typename(t), map_, key)
+			fast := mapfast(t)
+			if fast == mapslow {
+				// standard version takes key by reference.
+				// orderexpr made sure key is addressable.
+				key = nod(OADDR, key, nil)
+			}
+			n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
 		} else {
 			// m[k] is not the target of an assignment.
-			p := ""
-			if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-				switch algtype(t.Key()) {
-				case AMEM32:
-					p = "mapaccess1_fast32"
-				case AMEM64:
-					p = "mapaccess1_fast64"
-				case ASTRING:
-					p = "mapaccess1_faststr"
-				}
-			}
-
-			if p == "" {
+			fast := mapfast(t)
+			if fast == mapslow {
 				// standard version takes key by reference.
 				// orderexpr made sure key is addressable.
 				key = nod(OADDR, key, nil)
-				p = "mapaccess1"
 			}
 
 			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), map_, key)
+				n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Val()), init, typename(t), map_, key)
 			} else {
-				p = "mapaccess1_fat"
 				z := zeroaddr(w)
-				n = mkcall1(mapfn(p, t), ptrto(t.Val()), init, typename(t), map_, key, z)
+				n = mkcall1(mapfn("mapaccess1_fat", t), types.NewPtr(t.Val()), init, typename(t), map_, key, z)
 			}
 		}
-		n.Type = ptrto(t.Val())
-		n.NonNil = true // mapaccess1* and mapassign always return non-nil pointers.
+		n.Type = types.NewPtr(t.Val())
+		n.SetNonNil(true) // mapaccess1* and mapassign always return non-nil pointers.
 		n = nod(OIND, n, nil)
 		n.Type = t.Val()
-		n.Typecheck = 1
+		n.SetTypecheck(1)
 
 	case ORECV:
 		Fatalf("walkexpr ORECV") // should see inside OAS only
@@ -1223,9 +1230,6 @@ opswitch:
 			n = reduceSlice(n)
 		}
 
-	case OADDR:
-		n.Left = walkexpr(n.Left, init)
-
 	case ONEW:
 		if n.Esc == EscNone {
 			if n.Type.Elem().Width >= 1<<16 {
@@ -1273,6 +1277,23 @@ opswitch:
 			// across most architectures.
 			// See the commit description for CL 26758 for details.
 			maxRewriteLen := 6
+			// Some architectures can load unaligned byte sequence as 1 word.
+			// So we can cover longer strings with the same amount of code.
+			canCombineLoads := false
+			combine64bit := false
+			// TODO: does this improve performance on any other architectures?
+			switch thearch.LinkArch.Family {
+			case sys.AMD64:
+				// Larger compare require longer instructions, so keep this reasonably low.
+				// Data from CL 26758 shows that longer strings are rare.
+				// If we really want we can do 16 byte SSE comparisons in the future.
+				maxRewriteLen = 16
+				canCombineLoads = true
+				combine64bit = true
+			case sys.I386:
+				maxRewriteLen = 8
+				canCombineLoads = true
+			}
 			var and Op
 			switch cmp {
 			case OEQ:
@@ -1291,10 +1312,47 @@ opswitch:
 				}
 				// TODO(marvin): Fix Node.EType type union.
 				r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s))))
-				for i := 0; i < len(s); i++ {
-					cb := nodintconst(int64(s[i]))
-					ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
-					r = nod(and, r, nod(cmp, ncb, cb))
+				remains := len(s)
+				for i := 0; remains > 0; {
+					if remains == 1 || !canCombineLoads {
+						cb := nodintconst(int64(s[i]))
+						ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
+						r = nod(and, r, nod(cmp, ncb, cb))
+						remains--
+						i++
+						continue
+					}
+					var step int
+					var convType *types.Type
+					switch {
+					case remains >= 8 && combine64bit:
+						convType = types.Types[TINT64]
+						step = 8
+					case remains >= 4:
+						convType = types.Types[TUINT32]
+						step = 4
+					case remains >= 2:
+						convType = types.Types[TUINT16]
+						step = 2
+					}
+					ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i)))
+					ncsubstr = conv(ncsubstr, convType)
+					csubstr := int64(s[i])
+					// Calculate large constant from bytes as sequence of shifts and ors.
+					// Like this:  uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
+					// ssa will combine this into a single large load.
+					for offset := 1; offset < step; offset++ {
+						b := nod(OINDEX, ncs, nodintconst(int64(i+offset)))
+						b = conv(b, convType)
+						b = nod(OLSH, b, nodintconst(int64(8*offset)))
+						ncsubstr = nod(OOR, ncsubstr, b)
+						csubstr = csubstr | int64(s[i+offset])<<uint8(8*offset)
+					}
+					csubstrPart := nodintconst(csubstr)
+					// Compare "step" bytes as once
+					r = nod(and, r, nod(cmp, csubstrPart, ncsubstr))
+					remains -= step
+					i += step
 				}
 				r = typecheck(r, Erv)
 				r = walkexpr(r, init)
@@ -1311,7 +1369,7 @@ opswitch:
 			n.Left = cheapexpr(n.Left, init)
 			n.Right = cheapexpr(n.Right, init)
 
-			r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
+			r = mkcall("eqstring", types.Types[TBOOL], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
 
 			// quick check of len before full compare for == or !=
 			// eqstring assumes that the lengths are equal
@@ -1329,7 +1387,7 @@ opswitch:
 			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]))
+			r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
 			// TODO(marvin): Fix Node.EType type union.
 			r = nod(Op(n.Etype), r, nodintconst(0))
 		}
@@ -1359,7 +1417,7 @@ opswitch:
 		n = mkcall1(fn, nil, init, n.Left)
 
 	case OMAKECHAN:
-		n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
+		n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, types.Types[TINT64]))
 
 	case OMAKEMAP:
 		t := n.Type
@@ -1388,7 +1446,7 @@ opswitch:
 
 		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)
+		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, types.Types[TINT64]), a, r)
 
 	case OMAKESLICE:
 		l := n.Left
@@ -1404,7 +1462,7 @@ opswitch:
 			}
 			// var arr [r]T
 			// n = arr[:l]
-			t = typArray(t.Elem(), nonnegintconst(r)) // [r]T
+			t = types.NewArray(t.Elem(), nonnegintconst(r)) // [r]T
 			var_ := temp(t)
 			a := nod(OAS, var_, nil) // zero temp
 			a = typecheck(a, Etop)
@@ -1420,14 +1478,14 @@ opswitch:
 			// When len and cap can fit into int, use makeslice instead of
 			// makeslice64, which is faster and shorter on 32 bit platforms.
 
-			if t.Elem().NotInHeap {
+			if t.Elem().NotInHeap() {
 				yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem())
 			}
 
 			len, cap := l, r
 
 			fnname := "makeslice64"
-			argtype := Types[TINT64]
+			argtype := types.Types[TINT64]
 
 			// typechecking guarantees that TIDEAL len/cap are positive and fit in an int.
 			// The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
@@ -1435,7 +1493,7 @@ opswitch:
 			if (len.Type.IsKind(TIDEAL) || maxintval[len.Type.Etype].Cmp(maxintval[TUINT]) <= 0) &&
 				(cap.Type.IsKind(TIDEAL) || maxintval[cap.Type.Etype].Cmp(maxintval[TUINT]) <= 0) {
 				fnname = "makeslice"
-				argtype = Types[TINT]
+				argtype = types.Types[TINT]
 			}
 
 			fn := syslook(fnname)
@@ -1446,19 +1504,19 @@ opswitch:
 	case ORUNESTR:
 		a := nodnil()
 		if n.Esc == EscNone {
-			t := typArray(Types[TUINT8], 4)
+			t := types.NewArray(types.Types[TUINT8], 4)
 			var_ := temp(t)
 			a = nod(OADDR, var_, nil)
 		}
 
 		// intstring(*[4]byte, rune)
-		n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
+		n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[TINT64]))
 
 	case OARRAYBYTESTR:
 		a := nodnil()
 		if n.Esc == EscNone {
 			// Create temporary buffer for string on stack.
-			t := typArray(Types[TUINT8], tmpstringbufsize)
+			t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
 
 			a = nod(OADDR, temp(t), nil)
 		}
@@ -1484,7 +1542,7 @@ opswitch:
 
 		if n.Esc == EscNone {
 			// Create temporary buffer for string on stack.
-			t := typArray(Types[TUINT8], tmpstringbufsize)
+			t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
 
 			a = nod(OADDR, temp(t), nil)
 		}
@@ -1497,12 +1555,12 @@ opswitch:
 
 		if n.Esc == EscNone {
 			// Create temporary buffer for slice on stack.
-			t := typArray(Types[TUINT8], tmpstringbufsize)
+			t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
 
 			a = nod(OADDR, temp(t), nil)
 		}
 
-		n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
+		n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
 
 	case OSTRARRAYBYTETMP:
 		// []byte(string) conversion that creates a slice
@@ -1520,7 +1578,7 @@ opswitch:
 
 		if n.Esc == EscNone {
 			// Create temporary buffer for slice on stack.
-			t := typArray(Types[TINT32], tmpstringbufsize)
+			t := types.NewArray(types.Types[TINT32], tmpstringbufsize)
 
 			a = nod(OADDR, temp(t), nil)
 		}
@@ -1541,31 +1599,36 @@ opswitch:
 
 		n.Right = cheapexpr(n.Right, init)
 		n.Left = cheapexpr(n.Left, init)
-		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 {
-			r = nod(ONOT, r, nil)
-		}
-
-		// check itable/type before full compare.
+		lt := nod(OITAB, n.Left, nil)
+		rt := nod(OITAB, n.Right, nil)
+		ld := nod(OIDATA, n.Left, nil)
+		rd := nod(OIDATA, n.Right, nil)
+		ld.Type = types.Types[TUNSAFEPTR]
+		rd.Type = types.Types[TUNSAFEPTR]
+		ld.SetTypecheck(1)
+		rd.SetTypecheck(1)
+		call := mkcall1(fn, n.Type, init, lt, ld, rd)
+
+		// Check itable/type before full compare.
+		// Note: short-circuited because order matters.
 		// TODO(marvin): Fix Node.EType type union.
+		var cmp *Node
 		if Op(n.Etype) == OEQ {
-			r = nod(OANDAND, nod(OEQ, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r)
+			cmp = nod(OANDAND, nod(OEQ, lt, rt), call)
 		} else {
-			r = nod(OOROR, nod(ONE, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r)
+			cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil))
 		}
-		r = typecheck(r, Erv)
-		r = walkexpr(r, init)
-		r.Type = n.Type
-		n = r
+		cmp = typecheck(cmp, Erv)
+		cmp = walkexpr(cmp, init)
+		cmp.Type = n.Type
+		n = cmp
 
 	case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
-		if isStaticCompositeLiteral(n) {
+		if isStaticCompositeLiteral(n) && !canSSAType(n.Type) {
 			// 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)
-			vstat.Name.Readonly = true
+			vstat.Name.SetReadonly(true)
 			fixedlit(inInitFunction, initKindStatic, n, vstat, init)
 			n = vstat
 			n = typecheck(n, Erv)
@@ -1580,7 +1643,7 @@ opswitch:
 		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)
+		n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, n.Left, n1)
 
 	case OCLOSURE:
 		n = walkclosure(n, init)
@@ -1595,14 +1658,20 @@ opswitch:
 	// walk of y%1 may have replaced it by 0.
 	// Check whether n with its updated args is itself now a constant.
 	t := n.Type
-
 	evconst(n)
-	n.Type = t
+	if n.Type != t {
+		Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type)
+	}
 	if n.Op == OLITERAL {
 		n = typecheck(n, Erv)
+		// Emit string symbol now to avoid emitting
+		// any concurrently during the backend.
+		if s, ok := n.Val().U.(string); ok {
+			_ = stringsym(s)
+		}
 	}
 
-	ullmancalc(n)
+	updateHasCall(n)
 
 	if Debug['w'] != 0 && n != nil {
 		Dump("walk", n)
@@ -1673,7 +1742,7 @@ func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
 		var nln, nrn Nodes
 		nln.Set(nl)
 		nrn.Set(nr)
-		yyerror("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
+		Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.funcname())
 	}
 	return nn
 }
@@ -1682,12 +1751,11 @@ func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
 // return 1 if this implies a function call
 // evaluating the lv or a function call
 // in the conversion of the types
-func fncall(l *Node, rt *Type) bool {
-	if l.Ullman >= UINF || l.Op == OINDEXMAP {
+func fncall(l *Node, rt *types.Type) bool {
+	if l.HasCall() || l.Op == OINDEXMAP {
 		return true
 	}
-	var r Node
-	if needwritebarrier(l, &r) {
+	if needwritebarrier(l) {
 		return true
 	}
 	if eqtype(l.Type, rt) {
@@ -1699,21 +1767,17 @@ func fncall(l *Node, rt *Type) bool {
 // check assign type list to
 // a expression list. called in
 //	expr-list = func()
-func ascompatet(op Op, nl Nodes, nr *Type) []*Node {
-	r, saver := iterFields(nr)
+func ascompatet(op Op, nl Nodes, nr *types.Type) []*Node {
+	if nl.Len() != nr.NumFields() {
+		Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
+	}
 
 	var nn, mm Nodes
-	var ullmanOverflow bool
-	var i int
-	for i = 0; i < nl.Len(); i++ {
-		if r == nil {
-			break
-		}
-		l := nl.Index(i)
+	for i, l := range nl.Slice() {
 		if isblank(l) {
-			r = saver.Next()
 			continue
 		}
+		r := nr.Field(i)
 
 		// any lv that causes a fn call must be
 		// deferred until all the return arguments
@@ -1729,188 +1793,212 @@ func ascompatet(op Op, nl Nodes, nr *Type) []*Node {
 
 		a := nod(OAS, l, nodarg(r, 0))
 		a = convas(a, &nn)
-		ullmancalc(a)
-		if a.Ullman >= UINF {
+		updateHasCall(a)
+		if a.HasCall() {
 			Dump("ascompatet ucount", a)
-			ullmanOverflow = true
+			Fatalf("ascompatet: too many function calls evaluating parameters")
 		}
 
 		nn.Append(a)
-		r = saver.Next()
 	}
+	return append(nn.Slice(), mm.Slice()...)
+}
 
-	if i < nl.Len() || r != nil {
-		yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
-	}
+// 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 *types.Type)
+// or a specific argument (t is a *types.Field within a struct *types.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
 
-	if ullmanOverflow {
-		Fatalf("ascompatet: too many function calls evaluating parameters")
+	var funarg types.Funarg
+	switch t := t.(type) {
+	default:
+		Fatalf("bad nodarg %T(%v)", t, t)
+
+	case *types.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 = newname(lookup(".args"))
+		n.Type = t
+		first := t.Field(0)
+		if first == nil {
+			Fatalf("nodarg: bad struct")
+		}
+		if first.Offset == BADWIDTH {
+			Fatalf("nodarg: offset not computed for %v", t)
+		}
+		n.Xoffset = first.Offset
+
+	case *types.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 := asNode(t.Nname)
+			if expect.isParamHeapCopy() {
+				expect = expect.Name.Param.Stackcopy
+			}
+
+			for _, n := range Curfn.Func.Dcl {
+				if (n.Class() == PPARAM || n.Class() == PPARAMOUT) && !t.Sym.IsBlank() && n.Sym == t.Sym {
+					if n != expect {
+						Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, asNode(t.Nname), asNode(t.Nname), asNode(t.Nname).Op)
+					}
+					return n
+				}
+			}
+
+			if !expect.Sym.IsBlank() {
+				Fatalf("nodarg: did not find node in dcl list: %v", expect)
+			}
+		}
+
+		// Build fake name for individual variable.
+		// This is safe because if there was a real declared name
+		// we'd have used it above.
+		n = newname(lookup("__"))
+		n.Type = t.Type
+		if t.Offset == BADWIDTH {
+			Fatalf("nodarg: offset not computed for %v", t)
+		}
+		n.Xoffset = t.Offset
+		n.Orig = asNode(t.Nname)
 	}
-	return append(nn.Slice(), mm.Slice()...)
-}
 
-// package all the arguments that match a ... T parameter into a []T.
-func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
-	esc := uint16(EscUnknown)
-	if ddd != nil {
-		esc = ddd.Esc
+	// Rewrite argument named _ to __,
+	// or else the assignment to _ will be
+	// discarded during code generation.
+	if isblank(n) {
+		n.Sym = lookup("__")
 	}
 
-	tslice := typSlice(l.Type.Elem())
+	switch fp {
+	default:
+		Fatalf("bad fp")
 
-	var n *Node
-	if len(lr0) == 0 {
-		n = nodnil()
-		n.Type = tslice
-	} else {
-		n = nod(OCOMPLIT, nil, typenod(tslice))
-		if ddd != nil && prealloc[ddd] != nil {
-			prealloc[n] = prealloc[ddd] // temporary to use
-		}
-		n.List.Set(lr0)
-		n.Esc = esc
-		n = typecheck(n, Erv)
-		if n.Type == nil {
-			Fatalf("mkdotargslice: typecheck failed")
+	case 0: // preparing arguments for call
+		n.Op = OINDREGSP
+		n.Xoffset += Ctxt.FixedFrameSize()
+
+	case 1: // reading arguments inside call
+		n.SetClass(PPARAM)
+		if funarg == types.FunargResults {
+			n.SetClass(PPARAMOUT)
 		}
-		n = walkexpr(n, init)
 	}
 
-	a := nod(OAS, nodarg(l, fp), n)
-	nn = append(nn, convas(a, init))
-	return nn
+	n.SetTypecheck(1)
+	n.SetAddrtaken(true) // keep optimizers at bay
+	return n
 }
 
-// helpers for shape errors
-func dumptypes(nl *Type, what string) string {
-	s := ""
-	for _, l := range nl.Fields().Slice() {
-		if s != "" {
-			s += ", "
-		}
-		s += fldconv(l, 0)
+// package all the arguments that match a ... T parameter into a []T.
+func mkdotargslice(typ *types.Type, args []*Node, init *Nodes, ddd *Node) *Node {
+	esc := uint16(EscUnknown)
+	if ddd != nil {
+		esc = ddd.Esc
 	}
-	if s == "" {
-		s = fmt.Sprintf("[no arguments %s]", what)
+
+	if len(args) == 0 {
+		n := nodnil()
+		n.Type = typ
+		return n
 	}
-	return s
-}
 
-func dumpnodetypes(l []*Node, what string) string {
-	s := ""
-	for _, r := range l {
-		if s != "" {
-			s += ", "
-		}
-		s += r.Type.String()
+	n := nod(OCOMPLIT, nil, typenod(typ))
+	if ddd != nil && prealloc[ddd] != nil {
+		prealloc[n] = prealloc[ddd] // temporary to use
 	}
-	if s == "" {
-		s = fmt.Sprintf("[no arguments %s]", what)
+	n.List.Set(args)
+	n.Esc = esc
+	n = typecheck(n, Erv)
+	if n.Type == nil {
+		Fatalf("mkdotargslice: typecheck failed")
 	}
-	return s
+	n = walkexpr(n, init)
+	return n
 }
 
 // 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 []*Node, fp int, init *Nodes) []*Node {
-	lr0 := lr
-	l, savel := iterFields(nl)
-	var r *Node
-	if len(lr) > 0 {
-		r = lr[0]
-	}
+func ascompatte(call *Node, isddd bool, lhs *types.Type, rhs []*Node, fp int, init *Nodes) []*Node {
 	var nn []*Node
 
 	// f(g()) where g has multiple return values
-	if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
+	if len(rhs) == 1 && rhs[0].Type.IsFuncArgStruct() {
 		// optimization - can do block copy
-		if eqtypenoname(r.Type, nl) {
-			arg := nodarg(nl, fp)
-			r = nod(OCONVNOP, r, nil)
-			r.Type = arg.Type
-			nn = []*Node{convas(nod(OAS, arg, r), init)}
+		if eqtypenoname(rhs[0].Type, lhs) {
+			nl := nodarg(lhs, fp)
+			nr := nod(OCONVNOP, rhs[0], nil)
+			nr.Type = nl.Type
+			nn = []*Node{convas(nod(OAS, nl, nr), init)}
 			goto ret
 		}
 
 		// conversions involved.
 		// copy into temporaries.
-		var alist []*Node
-
-		for _, l := range r.Type.Fields().Slice() {
-			tmp := temp(l.Type)
-			alist = append(alist, tmp)
+		var tmps []*Node
+		for _, nr := range rhs[0].Type.FieldSlice() {
+			tmps = append(tmps, temp(nr.Type))
 		}
 
 		a := nod(OAS2, nil, nil)
-		a.List.Set(alist)
-		a.Rlist.Set(lr)
+		a.List.Set(tmps)
+		a.Rlist.Set(rhs)
 		a = typecheck(a, Etop)
 		a = walkstmt(a)
 		init.Append(a)
-		lr = alist
-		r = lr[0]
-		l, savel = iterFields(nl)
-	}
-
-	for {
-		if l != nil && l.Isddd {
-			// the ddd parameter must be last
-			ll := savel.Next()
-
-			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 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)
-
-			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\t%s\n\t%s", op, l1, l2)
-				} else {
-					yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
-				}
-			}
+		rhs = tmps
+	}
 
-			break
+	// For each parameter (LHS), assign its corresponding argument (RHS).
+	// If there's a ... parameter (which is only valid as the final
+	// parameter) and this is not a ... call expression,
+	// then assign the remaining arguments as a slice.
+	for i, nl := range lhs.FieldSlice() {
+		var nr *Node
+		if nl.Isddd() && !isddd {
+			nr = mkdotargslice(nl.Type, rhs[i:], init, call.Right)
+		} else {
+			nr = rhs[i]
 		}
 
-		a := nod(OAS, nodarg(l, fp), r)
+		a := nod(OAS, nodarg(nl, fp), nr)
 		a = convas(a, init)
 		nn = append(nn, a)
-
-		l = savel.Next()
-		r = nil
-		lr = lr[1:]
-		if len(lr) > 0 {
-			r = lr[0]
-		}
 	}
 
 ret:
 	for _, n := range nn {
-		n.Typecheck = 1
+		n.SetTypecheck(1)
 	}
 	return nn
 }
@@ -1920,8 +2008,8 @@ func walkprint(nn *Node, init *Nodes) *Node {
 	var r *Node
 	var n *Node
 	var on *Node
-	var t *Type
-	var et EType
+	var t *types.Type
+	var et types.EType
 
 	op := nn.Op
 	all := nn.List
@@ -1943,18 +2031,18 @@ func walkprint(nn *Node, init *Nodes) *Node {
 		if n.Op == OLITERAL {
 			switch n.Val().Ctype() {
 			case CTRUNE:
-				n = defaultlit(n, runetype)
+				n = defaultlit(n, types.Runetype)
 
 			case CTINT:
-				n = defaultlit(n, Types[TINT64])
+				n = defaultlit(n, types.Types[TINT64])
 
 			case CTFLT:
-				n = defaultlit(n, Types[TFLOAT64])
+				n = defaultlit(n, types.Types[TFLOAT64])
 			}
 		}
 
 		if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
-			n = defaultlit(n, Types[TINT64])
+			n = defaultlit(n, types.Types[TINT64])
 		}
 		n = defaultlit(n, nil)
 		all.SetIndex(i1, n)
@@ -1979,7 +2067,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
 			on = substArgTypes(on, n.Type) // any-1
 		} else if isInt[et] {
 			if et == TUINT64 {
-				if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
+				if isRuntimePkg(t.Sym.Pkg) && t.Sym.Name == "hex" {
 					on = syslook("printhex")
 				} else {
 					on = syslook("printuint")
@@ -2028,15 +2116,15 @@ func walkprint(nn *Node, init *Nodes) *Node {
 	return r
 }
 
-func callnew(t *Type) *Node {
-	if t.NotInHeap {
+func callnew(t *types.Type) *Node {
+	if t.NotInHeap() {
 		yyerror("%v is go:notinheap; heap allocation disallowed", t)
 	}
 	dowidth(t)
 	fn := syslook("newobject")
 	fn = substArgTypes(fn, t)
-	v := mkcall1(fn, ptrto(t), nil, typename(t))
-	v.NonNil = true
+	v := mkcall1(fn, types.NewPtr(t), nil, typename(t))
+	v.SetNonNil(true)
 	return v
 }
 
@@ -2062,7 +2150,7 @@ func isstack(n *Node) bool {
 		return true
 
 	case ONAME:
-		switch n.Class {
+		switch n.Class() {
 		case PAUTO, PPARAM, PPARAMOUT:
 			return true
 		}
@@ -2074,11 +2162,11 @@ func isstack(n *Node) bool {
 // isReflectHeaderDataField reports whether l is an expression p.Data
 // where p has type reflect.SliceHeader or reflect.StringHeader.
 func isReflectHeaderDataField(l *Node) bool {
-	if l.Type != Types[TUINTPTR] {
+	if l.Type != types.Types[TUINTPTR] {
 		return false
 	}
 
-	var tsym *Sym
+	var tsym *types.Sym
 	switch l.Op {
 	case ODOT:
 		tsym = l.Left.Type.Sym
@@ -2094,8 +2182,8 @@ func isReflectHeaderDataField(l *Node) bool {
 	return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader"
 }
 
-// Do we need a write barrier for the assignment l = r?
-func needwritebarrier(l *Node, r *Node) bool {
+// Do we need a write barrier for assigning to l?
+func needwritebarrier(l *Node) bool {
 	if !use_writebarrier {
 		return false
 	}
@@ -2118,31 +2206,16 @@ func needwritebarrier(l *Node, r *Node) bool {
 
 	// No write barrier for write of non-pointers.
 	dowidth(l.Type)
-	if !haspointers(l.Type) {
+	if !types.Haspointers(l.Type) {
 		return false
 	}
 
 	// No write barrier if this is a pointer to a go:notinheap
 	// type, since the write barrier's inheap(ptr) check will fail.
-	if l.Type.IsPtr() && l.Type.Elem().NotInHeap {
+	if l.Type.IsPtr() && l.Type.Elem().NotInHeap() {
 		return false
 	}
 
-	// Implicit zeroing is still zeroing, so it needs write
-	// barriers. In practice, these are all to stack variables
-	// (even if isstack isn't smart enough to figure that out), so
-	// they'll be eliminated by the backend.
-	if r == nil {
-		return true
-	}
-
-	// Ignore no-op conversions when making decision.
-	// Ensures that xp = unsafe.Pointer(&x) is treated
-	// the same as xp = &x.
-	for r.Op == OCONVNOP {
-		r = r.Left
-	}
-
 	// TODO: We can eliminate write barriers if we know *both* the
 	// current and new content of the slot must already be shaded.
 	// We know a pointer is shaded if it's nil, or points to
@@ -2151,38 +2224,19 @@ func needwritebarrier(l *Node, r *Node) bool {
 	// writes to just-allocated objects. Unfortunately, knowing
 	// the "current" value of the slot requires flow analysis.
 
-	// No write barrier for storing address of stack values,
-	// which are guaranteed only to be written to the stack.
-	if r.Op == OADDR && isstack(r.Left) {
-		return false
-	}
-
 	// Otherwise, be conservative and use write barrier.
 	return true
 }
 
-// TODO(rsc): Perhaps componentgen should run before this.
-
-func applywritebarrier(n *Node) *Node {
-	if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
-		if Debug_wb > 1 {
-			Warnl(n.Lineno, "marking %v for barrier", n.Left)
-		}
-		n.Op = OASWB
-		return n
-	}
-	return n
-}
-
 func convas(n *Node, init *Nodes) *Node {
 	if n.Op != OAS {
 		Fatalf("convas: not OAS %v", n.Op)
 	}
 
-	n.Typecheck = 1
+	n.SetTypecheck(1)
 
-	var lt *Type
-	var rt *Type
+	var lt *types.Type
+	var rt *types.Type
 	if n.Left == nil || n.Right == nil {
 		goto out
 	}
@@ -2202,9 +2256,10 @@ func convas(n *Node, init *Nodes) *Node {
 		n.Right = assignconv(n.Right, lt, "assignment")
 		n.Right = walkexpr(n.Right, init)
 	}
+	dowidth(n.Right.Type)
 
 out:
-	ullmancalc(n)
+	updateHasCall(n)
 	return n
 }
 
@@ -2220,8 +2275,8 @@ func reorder1(all []*Node) []*Node {
 
 	for _, n := range all {
 		t++
-		ullmancalc(n)
-		if n.Ullman >= UINF {
+		updateHasCall(n)
+		if n.HasCall() {
 			c++
 		}
 	}
@@ -2236,7 +2291,7 @@ func reorder1(all []*Node) []*Node {
 	d := 0
 	var a *Node
 	for _, n := range all {
-		if n.Ullman < UINF {
+		if !n.HasCall() {
 			r = append(r, n)
 			continue
 		}
@@ -2402,13 +2457,13 @@ func aliased(n *Node, all []*Node, i int) bool {
 			continue
 		}
 
-		switch n.Class {
+		switch n.Class() {
 		default:
 			varwrite = 1
 			continue
 
 		case PAUTO, PPARAM, PPARAMOUT:
-			if n.Addrtaken {
+			if n.Addrtaken() {
 				varwrite = 1
 				continue
 			}
@@ -2454,9 +2509,9 @@ func varexpr(n *Node) bool {
 		return true
 
 	case ONAME:
-		switch n.Class {
+		switch n.Class() {
 		case PAUTO, PPARAM, PPARAMOUT:
-			if !n.Addrtaken {
+			if !n.Addrtaken() {
 				return true
 			}
 		}
@@ -2532,14 +2587,14 @@ func vmatch1(l *Node, r *Node) bool {
 	}
 	switch l.Op {
 	case ONAME:
-		switch l.Class {
+		switch l.Class() {
 		case PPARAM, PAUTO:
 			break
 
-		// assignment to non-stack variable
-		// must be delayed if right has function calls.
 		default:
-			if r.Ullman >= UINF {
+			// assignment to non-stack variable must be
+			// delayed if right has function calls.
+			if r.HasCall() {
 				return true
 			}
 		}
@@ -2565,22 +2620,11 @@ func vmatch1(l *Node, r *Node) bool {
 }
 
 // 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 {
+// and to copy non-result parameters' values from the stack.
+func paramstoheap(params *types.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 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 = append(nn, nod(OAS, nodarg(t, 1), nil))
-		}
-
-		v := t.Nname
+		v := asNode(t.Nname)
 		if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
 			v = nil
 		}
@@ -2590,7 +2634,7 @@ func paramstoheap(params *Type) []*Node {
 
 		if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
 			nn = append(nn, walkstmt(nod(ODCL, v, nil)))
-			if stackcopy.Class == PPARAM {
+			if stackcopy.Class() == PPARAM {
 				nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), Etop)))
 			}
 		}
@@ -2599,16 +2643,39 @@ func paramstoheap(params *Type) []*Node {
 	return nn
 }
 
+// zeroResults zeros the return values at the start of the function.
+// We need to do this very early in the function.  Defer might stop a
+// panic and show the return values as they exist at the time of
+// panic.  For precise stacks, the garbage collector assumes results
+// are always live, so we need to zero them before any allocations,
+// even allocations to move params/results to the heap.
+// The generated code is added to Curfn's Enter list.
+func zeroResults() {
+	lno := lineno
+	lineno = Curfn.Pos
+	for _, f := range Curfn.Type.Results().Fields().Slice() {
+		if v := asNode(f.Nname); v != nil && v.Name.Param.Heapaddr != nil {
+			// The local which points to the return value is the
+			// thing that needs zeroing. This is already handled
+			// by a Needzero annotation in plive.go:livenessepilogue.
+			continue
+		}
+		// Zero the stack location containing f.
+		Curfn.Func.Enter.Append(nod(OAS, nodarg(f, 1), nil))
+	}
+	lineno = lno
+}
+
 // returnsfromheap returns code to copy values for heap-escaped parameters
 // back to the stack.
-func returnsfromheap(params *Type) []*Node {
+func returnsfromheap(params *types.Type) []*Node {
 	var nn []*Node
 	for _, t := range params.Fields().Slice() {
-		v := t.Nname
+		v := asNode(t.Nname)
 		if v == nil {
 			continue
 		}
-		if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
+		if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == PPARAMOUT {
 			nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), Etop)))
 		}
 	}
@@ -2621,7 +2688,7 @@ func returnsfromheap(params *Type) []*Node {
 // Enter and Exit lists.
 func heapmoves() {
 	lno := lineno
-	lineno = Curfn.Lineno
+	lineno = Curfn.Pos
 	nn := paramstoheap(Curfn.Type.Recvs())
 	nn = append(nn, paramstoheap(Curfn.Type.Params())...)
 	nn = append(nn, paramstoheap(Curfn.Type.Results())...)
@@ -2631,7 +2698,7 @@ func heapmoves() {
 	lineno = lno
 }
 
-func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
+func vmkcall(fn *Node, t *types.Type, init *Nodes, va []*Node) *Node {
 	if fn.Type == nil || fn.Type.Etype != TFUNC {
 		Fatalf("mkcall %v %v", fn, fn.Type)
 	}
@@ -2650,15 +2717,15 @@ func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
 	return r
 }
 
-func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
+func mkcall(name string, t *types.Type, init *Nodes, args ...*Node) *Node {
 	return vmkcall(syslook(name), t, init, args)
 }
 
-func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
+func mkcall1(fn *Node, t *types.Type, init *Nodes, args ...*Node) *Node {
 	return vmkcall(fn, t, init, args)
 }
 
-func conv(n *Node, t *Type) *Node {
+func conv(n *Node, t *types.Type) *Node {
 	if eqtype(n.Type, t) {
 		return n
 	}
@@ -2668,7 +2735,20 @@ func conv(n *Node, t *Type) *Node {
 	return n
 }
 
-func chanfn(name string, n int, t *Type) *Node {
+// byteindex converts n, which is byte-sized, to a uint8.
+// We cannot use conv, because we allow converting bool to uint8 here,
+// which is forbidden in user code.
+func byteindex(n *Node) *Node {
+	if eqtype(n.Type, types.Types[TUINT8]) {
+		return n
+	}
+	n = nod(OCONV, n, nil)
+	n.Type = types.Types[TUINT8]
+	n.SetTypecheck(1)
+	return n
+}
+
+func chanfn(name string, n int, t *types.Type) *Node {
 	if !t.IsChan() {
 		Fatalf("chanfn %v", t)
 	}
@@ -2684,7 +2764,7 @@ func chanfn(name string, n int, t *Type) *Node {
 	return fn
 }
 
-func mapfn(name string, t *Type) *Node {
+func mapfn(name string, t *types.Type) *Node {
 	if !t.IsMap() {
 		Fatalf("mapfn %v", t)
 	}
@@ -2693,7 +2773,7 @@ func mapfn(name string, t *Type) *Node {
 	return fn
 }
 
-func mapfndel(name string, t *Type) *Node {
+func mapfndel(name string, t *types.Type) *Node {
 	if !t.IsMap() {
 		Fatalf("mapfn %v", t)
 	}
@@ -2702,7 +2782,42 @@ func mapfndel(name string, t *Type) *Node {
 	return fn
 }
 
-func writebarrierfn(name string, l *Type, r *Type) *Node {
+const (
+	mapslow = iota
+	mapfast32
+	mapfast64
+	mapfaststr
+	nmapfast
+)
+
+type mapnames [nmapfast]string
+
+func mkmapnames(base string) mapnames {
+	return mapnames{base, base + "_fast32", base + "_fast64", base + "_faststr"}
+}
+
+var mapaccess1 mapnames = mkmapnames("mapaccess1")
+var mapaccess2 mapnames = mkmapnames("mapaccess2")
+var mapassign mapnames = mkmapnames("mapassign")
+var mapdelete mapnames = mkmapnames("mapdelete")
+
+func mapfast(t *types.Type) int {
+	// Check ../../runtime/hashmap.go:maxValueSize before changing.
+	if t.Val().Width > 128 {
+		return mapslow
+	}
+	switch algtype(t.Key()) {
+	case AMEM32:
+		return mapfast32
+	case AMEM64:
+		return mapfast64
+	case ASTRING:
+		return mapfaststr
+	}
+	return mapslow
+}
+
+func writebarrierfn(name string, l *types.Type, r *types.Type) *Node {
 	fn := syslook(name)
 	fn = substArgTypes(fn, l, r)
 	return fn
@@ -2713,7 +2828,7 @@ func addstr(n *Node, init *Nodes) *Node {
 	c := n.List.Len()
 
 	if c < 2 {
-		yyerror("addstr count %d too small", c)
+		Fatalf("addstr count %d too small", c)
 	}
 
 	buf := nodnil()
@@ -2728,7 +2843,7 @@ func addstr(n *Node, init *Nodes) *Node {
 		// Don't allocate the buffer if the result won't fit.
 		if sz < tmpstringbufsize {
 			// Create temporary buffer for result string on stack.
-			t := typArray(Types[TUINT8], tmpstringbufsize)
+			t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
 
 			buf = nod(OADDR, temp(t), nil)
 		}
@@ -2737,7 +2852,7 @@ func addstr(n *Node, init *Nodes) *Node {
 	// build list of string arguments
 	args := []*Node{buf}
 	for _, n2 := range n.List.Slice() {
-		args = append(args, conv(n2, Types[TSTRING]))
+		args = append(args, conv(n2, types.Types[TSTRING]))
 	}
 
 	var fn string
@@ -2749,7 +2864,7 @@ func addstr(n *Node, init *Nodes) *Node {
 		// large numbers of strings are passed to the runtime as a slice.
 		fn = "concatstrings"
 
-		t := typSlice(Types[TSTRING])
+		t := types.NewSlice(types.Types[TSTRING])
 		slice := nod(OCOMPLIT, nil, typenod(t))
 		if prealloc[n] != nil {
 			prealloc[slice] = prealloc[n]
@@ -2804,14 +2919,14 @@ func appendslice(n *Node, init *Nodes) *Node {
 	l = append(l, nod(OAS, s, l1)) // s = l1
 
 	// n := len(s) + len(l2)
-	nn := temp(Types[TINT])
+	nn := temp(types.Types[TINT])
 	l = append(l, nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil))))
 
 	// 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]
+	nif.Left.Left.Type = types.Types[TUINT]
+	nif.Left.Right.Type = types.Types[TUINT]
 
 	// instantiate growslice(Type*, []any, int) []any
 	fn := syslook("growslice")
@@ -2827,7 +2942,7 @@ func appendslice(n *Node, init *Nodes) *Node {
 	nt.Etype = 1
 	l = append(l, nod(OAS, s, nt))
 
-	if haspointers(l1.Type.Elem()) {
+	if types.Haspointers(l1.Type.Elem()) {
 		// copy(s[len(l1):], l2)
 		nptr1 := nod(OSLICE, s, nil)
 		nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
@@ -2837,7 +2952,7 @@ func appendslice(n *Node, init *Nodes) *Node {
 		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)
+		nt := mkcall1(fn, types.Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
 		l = append(ln.Slice(), nt)
 	} else if instrumenting && !compiling_runtime {
 		// rely on runtime to instrument copy.
@@ -2855,12 +2970,12 @@ func appendslice(n *Node, init *Nodes) *Node {
 		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))
+		nt := mkcall1(fn, types.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.SetBounded(true)
 
 		nptr1 = nod(OADDR, nptr1, nil)
 
@@ -2871,7 +2986,7 @@ func appendslice(n *Node, init *Nodes) *Node {
 
 		var ln Nodes
 		ln.Set(l)
-		nwid := cheapexpr(conv(nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
+		nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &ln)
 
 		nwid = nod(OMUL, nwid, nodintconst(s.Type.Elem().Width))
 		nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
@@ -2907,8 +3022,8 @@ func appendslice(n *Node, init *Nodes) *Node {
 //   s
 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))
+		n.List.SetFirst(safeexpr(n.List.First(), init))
+		n.List.SetFirst(walkexpr(n.List.First(), init))
 	}
 	walkexprlistsafe(n.List.Slice()[1:], init)
 
@@ -2954,7 +3069,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
 
 	l = append(l, nx)
 
-	nn := temp(Types[TINT])
+	nn := temp(types.Types[TINT])
 	l = append(l, nod(OAS, nn, nod(OLEN, ns, nil))) // n = len(s)
 
 	nx = nod(OSLICE, ns, nil) // ...s[:n+argc]
@@ -2965,7 +3080,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
 	ls = n.List.Slice()[1:]
 	for i, n := range ls {
 		nx = nod(OINDEX, ns, nn) // s[n] ...
-		nx.Bounded = true
+		nx.SetBounded(true)
 		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
@@ -2990,7 +3105,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
 // Also works if b is a string.
 //
 func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
-	if haspointers(n.Left.Type.Elem()) {
+	if types.Haspointers(n.Left.Type.Elem()) {
 		fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
 		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
 	}
@@ -3017,7 +3132,7 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
 	nfrm := nod(OSPTR, nr, nil)
 	nto := nod(OSPTR, nl, nil)
 
-	nlen := temp(Types[TINT])
+	nlen := temp(types.Types[TINT])
 
 	// n = len(to)
 	l = append(l, nod(OAS, nlen, nod(OLEN, nl, nil)))
@@ -3033,8 +3148,8 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
 	fn := syslook("memmove")
 
 	fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
-	nwid := temp(Types[TUINTPTR])
-	l = append(l, nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
+	nwid := temp(types.Types[TUINTPTR])
+	l = append(l, nod(OAS, nwid, conv(nlen, types.Types[TUINTPTR])))
 	nwid = nod(OMUL, nwid, nodintconst(nl.Type.Elem().Width))
 	l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
 
@@ -3044,7 +3159,7 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
 	return nlen
 }
 
-func eqfor(t *Type, needsize *int) *Node {
+func eqfor(t *types.Type, needsize *int) *Node {
 	// Should only arrive here with large memory or
 	// a struct/array containing a non-memory field/element.
 	// Small memory is handled inline, and single non-memory
@@ -3058,11 +3173,11 @@ func eqfor(t *Type, needsize *int) *Node {
 	case ASPECIAL:
 		sym := typesymprefix(".eq", t)
 		n := newname(sym)
-		n.Class = PFUNC
+		n.SetClass(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.List.Append(anonfield(types.NewPtr(t)))
+		ntype.List.Append(anonfield(types.NewPtr(t)))
+		ntype.Rlist.Append(anonfield(types.Types[TBOOL]))
 		ntype = typecheck(ntype, Etype)
 		n.Type = ntype.Type
 		*needsize = 0
@@ -3106,8 +3221,8 @@ func walkcompare(n *Node, init *Nodes) *Node {
 		tab := nod(OITAB, l, nil)
 		rtyp := typename(r.Type)
 		if l.Type.IsEmptyInterface() {
-			tab.Type = ptrto(Types[TUINT8])
-			tab.Typecheck = 1
+			tab.Type = types.NewPtr(types.Types[TUINT8])
+			tab.SetTypecheck(1)
 			eqtype = nod(eq, tab, rtyp)
 		} else {
 			nonnil := nod(brcom(eq), nodnil(), tab)
@@ -3128,11 +3243,25 @@ func walkcompare(n *Node, init *Nodes) *Node {
 	// inline or call an eq alg.
 	t := n.Left.Type
 	var inline bool
+
+	maxcmpsize := int64(4)
+	unalignedLoad := false
+	switch thearch.LinkArch.Family {
+	case sys.AMD64, sys.ARM64, sys.S390X:
+		// Keep this low enough, to generate less code than function call.
+		maxcmpsize = 16
+		unalignedLoad = true
+	case sys.I386:
+		maxcmpsize = 8
+		unalignedLoad = true
+	}
+
 	switch t.Etype {
 	default:
 		return n
 	case TARRAY:
-		inline = t.NumElem() <= 1 || (t.NumElem() <= 4 && issimple[t.Elem().Etype])
+		// We can compare several elements at once with 2/4/8 byte integer compares
+		inline = t.NumElem() <= 1 || (issimple[t.Elem().Etype] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
 	case TSTRUCT:
 		inline = t.NumFields() <= 4
 	}
@@ -3148,18 +3277,28 @@ func walkcompare(n *Node, init *Nodes) *Node {
 
 	// Chose not to inline. Call equality function directly.
 	if !inline {
+		if isvaluelit(cmpl) {
+			var_ := temp(cmpl.Type)
+			anylit(cmpl, var_, init)
+			cmpl = var_
+		}
+		if isvaluelit(cmpr) {
+			var_ := temp(cmpr.Type)
+			anylit(cmpr, var_, init)
+			cmpr = var_
+		}
 		if !islvalue(cmpl) || !islvalue(cmpr) {
 			Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
 		}
 
 		// eq algs take pointers
-		pl := temp(ptrto(t))
+		pl := temp(types.NewPtr(t))
 		al := nod(OAS, pl, nod(OADDR, cmpl, nil))
 		al.Right.Etype = 1 // addr does not escape
 		al = typecheck(al, Etop)
 		init.Append(al)
 
-		pr := temp(ptrto(t))
+		pr := temp(types.NewPtr(t))
 		ar := nod(OAS, pr, nod(OADDR, cmpr, nil))
 		ar.Right.Etype = 1 // addr does not escape
 		ar = typecheck(ar, Etop)
@@ -3199,7 +3338,7 @@ func walkcompare(n *Node, init *Nodes) *Node {
 	if t.IsStruct() {
 		for _, f := range t.Fields().Slice() {
 			sym := f.Sym
-			if isblanksym(sym) {
+			if sym.IsBlank() {
 				continue
 			}
 			compare(
@@ -3208,11 +3347,54 @@ func walkcompare(n *Node, init *Nodes) *Node {
 			)
 		}
 	} else {
-		for i := 0; int64(i) < t.NumElem(); i++ {
-			compare(
-				nod(OINDEX, cmpl, nodintconst(int64(i))),
-				nod(OINDEX, cmpr, nodintconst(int64(i))),
-			)
+		step := int64(1)
+		remains := t.NumElem() * t.Elem().Width
+		combine64bit := unalignedLoad && Widthreg == 8 && t.Elem().Width <= 4 && t.Elem().IsInteger()
+		combine32bit := unalignedLoad && t.Elem().Width <= 2 && t.Elem().IsInteger()
+		combine16bit := unalignedLoad && t.Elem().Width == 1 && t.Elem().IsInteger()
+		for i := int64(0); remains > 0; {
+			var convType *types.Type
+			switch {
+			case remains >= 8 && combine64bit:
+				convType = types.Types[TINT64]
+				step = 8 / t.Elem().Width
+			case remains >= 4 && combine32bit:
+				convType = types.Types[TUINT32]
+				step = 4 / t.Elem().Width
+			case remains >= 2 && combine16bit:
+				convType = types.Types[TUINT16]
+				step = 2 / t.Elem().Width
+			default:
+				step = 1
+			}
+			if step == 1 {
+				compare(
+					nod(OINDEX, cmpl, nodintconst(int64(i))),
+					nod(OINDEX, cmpr, nodintconst(int64(i))),
+				)
+				i++
+				remains -= t.Elem().Width
+			} else {
+				cmplw := nod(OINDEX, cmpl, nodintconst(int64(i)))
+				cmplw = conv(cmplw, convType)
+				cmprw := nod(OINDEX, cmpr, nodintconst(int64(i)))
+				cmprw = conv(cmprw, convType)
+				// For code like this:  uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
+				// ssa will generate a single large load.
+				for offset := int64(1); offset < step; offset++ {
+					lb := nod(OINDEX, cmpl, nodintconst(int64(i+offset)))
+					lb = conv(lb, convType)
+					lb = nod(OLSH, lb, nodintconst(int64(8*t.Elem().Width*offset)))
+					cmplw = nod(OOR, cmplw, lb)
+					rb := nod(OINDEX, cmpr, nodintconst(int64(i+offset)))
+					rb = conv(rb, convType)
+					rb = nod(OLSH, rb, nodintconst(int64(8*t.Elem().Width*offset)))
+					cmprw = nod(OOR, cmprw, rb)
+				}
+				compare(cmplw, cmprw)
+				i += step
+				remains -= step * t.Elem().Width
+			}
 		}
 	}
 	if expr == nil {
@@ -3233,100 +3415,12 @@ func finishcompare(n, r *Node, init *Nodes) *Node {
 	if r.Type != n.Type {
 		r = nod(OCONVNOP, r, nil)
 		r.Type = n.Type
-		r.Typecheck = 1
+		r.SetTypecheck(1)
 		nn = r
 	}
 	return nn
 }
 
-func samecheap(a *Node, b *Node) bool {
-	var ar *Node
-	var br *Node
-	for a != nil && b != nil && a.Op == b.Op {
-		switch a.Op {
-		default:
-			return false
-
-		case ONAME:
-			return a == b
-
-		case ODOT, ODOTPTR:
-			if a.Sym != b.Sym {
-				return false
-			}
-
-		case OINDEX:
-			ar = a.Right
-			br = b.Right
-			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
-				return false
-			}
-		}
-
-		a = a.Left
-		b = b.Left
-	}
-
-	return false
-}
-
-// 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.MIPS, sys.MIPS64, sys.PPC64) {
-		return n
-	}
-
-	// 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 || 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 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(l.Right.Int64())
-		if sl >= 0 {
-			sr := int(r.Right.Int64())
-			if sr >= 0 && sl+sr == w {
-				// Rewrite left shift half to left rotate.
-				if l.Op == OLSH {
-					n = l
-				} else {
-					n = r
-				}
-				n.Op = OLROT
-
-				// Remove rotate 0 and rotate w.
-				s := int(n.Right.Int64())
-
-				if s == 0 || s == w {
-					n = n.Left
-				}
-				return n
-			}
-		}
-		return n
-	}
-
-	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
-	return n
-}
-
 // isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers.
 func (n *Node) isIntOrdering() bool {
 	switch n.Op {
@@ -3439,7 +3533,7 @@ func walkinrange(n *Node, init *Nodes) *Node {
 	// This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a),
 	// which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a),
 	// which is equivalent to uint(b-a) < uint(c-a).
-	ut := b.Type.toUnsigned()
+	ut := b.Type.ToUnsigned()
 	lhs := conv(nod(OSUB, b, a), ut)
 	rhs := nodintconst(bound)
 	if negateResult {
@@ -3447,7 +3541,7 @@ func walkinrange(n *Node, init *Nodes) *Node {
 		opr = brcom(opr)
 	}
 	cmp := nod(opr, lhs, rhs)
-	cmp.Lineno = n.Lineno
+	cmp.Pos = n.Pos
 	cmp = addinit(cmp, l.Ninit.Slice())
 	cmp = addinit(cmp, r.Ninit.Slice())
 	// Typecheck the AST rooted at cmp...
@@ -3458,333 +3552,6 @@ func walkinrange(n *Node, init *Nodes) *Node {
 	return cmp
 }
 
-// walkmul rewrites integer multiplication by powers of two as shifts.
-// 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
-	var nl *Node
-	if n.Right.Op == OLITERAL {
-		nl = n.Left
-		nr = n.Right
-	} else if n.Left.Op == OLITERAL {
-		nl = n.Right
-		nr = n.Left
-	} else {
-		return n
-	}
-
-	neg := 0
-
-	// x*0 is 0 (and side effects of x).
-	var pow int
-	var w int
-	if nr.Int64() == 0 {
-		cheapexpr(nl, init)
-		Nodconst(n, n.Type, 0)
-		goto ret
-	}
-
-	// nr is a constant.
-	pow = powtwo(nr)
-
-	if pow < 0 {
-		return n
-	}
-	if pow >= 1000 {
-		// negative power of 2, like -16
-		neg = 1
-
-		pow -= 1000
-	}
-
-	w = int(nl.Type.Width * 8)
-	if pow+1 >= w { // too big, shouldn't happen
-		return n
-	}
-
-	nl = cheapexpr(nl, init)
-
-	if pow == 0 {
-		// x*1 is x
-		n = nl
-
-		goto ret
-	}
-
-	n = nod(OLSH, nl, nodintconst(int64(pow)))
-
-ret:
-	if neg != 0 {
-		n = nod(OMINUS, n, nil)
-	}
-
-	n = typecheck(n, Erv)
-	n = walkexpr(n, init)
-	return n
-}
-
-// walkdiv rewrites division by a constant as less expensive
-// operations.
-// 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.
-
-	if n.Right.Op != OLITERAL {
-		return n
-	}
-
-	// nr is a constant.
-	nl := cheapexpr(n.Left, init)
-
-	nr := n.Right
-
-	// special cases of mod/div
-	// by a constant
-	w := int(nl.Type.Width * 8)
-
-	s := 0            // 1 if nr is negative.
-	pow := powtwo(nr) // if >= 0, nr is 1<<pow
-	if pow >= 1000 {
-		// negative power of 2
-		s = 1
-
-		pow -= 1000
-	}
-
-	if pow+1 >= w {
-		// divisor too large.
-		return n
-	}
-
-	if pow < 0 {
-		// try to do division by multiply by (2^w)/d
-		// see hacker's delight chapter 10
-		// TODO: support 64-bit magic multiply here.
-		var m Magic
-		m.W = w
-
-		if nl.Type.IsSigned() {
-			m.Sd = nr.Int64()
-			smagic(&m)
-		} else {
-			m.Ud = uint64(nr.Int64())
-			umagic(&m)
-		}
-
-		if m.Bad != 0 {
-			return n
-		}
-
-		// We have a quick division method so use it
-		// for modulo too.
-		if n.Op == OMOD {
-			// rewrite as A%B = A - (A/B*B).
-			n1 := nod(ODIV, nl, nr)
-
-			n2 := nod(OMUL, n1, nr)
-			n = nod(OSUB, nl, n2)
-			goto ret
-		}
-
-		switch simtype[nl.Type.Etype] {
-		default:
-			return n
-
-			// n1 = nl * magic >> w (HMUL)
-		case TUINT8, TUINT16, TUINT32:
-			var nc Node
-
-			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 n
-
-				case TUINT8, TUINT16:
-					twide = Types[TUINT32]
-
-				case TUINT32:
-					twide = Types[TUINT64]
-
-				case TINT8, TINT16:
-					twide = Types[TINT32]
-
-				case TINT32:
-					twide = Types[TINT64]
-				}
-
-				// add numerator (might overflow).
-				// n2 = (n1 + nl)
-				n2 := nod(OADD, conv(n1, twide), conv(nl, twide))
-
-				// shift by m.s
-				var nc Node
-
-				Nodconst(&nc, Types[TUINT], int64(m.S))
-				n = conv(nod(ORSH, n2, &nc), nl.Type)
-			} else {
-				// n = n1 >> m.s
-				var nc Node
-
-				Nodconst(&nc, Types[TUINT], int64(m.S))
-				n = nod(ORSH, n1, &nc)
-			}
-
-			// n1 = nl * magic >> w
-		case TINT8, TINT16, TINT32:
-			var nc Node
-
-			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
-			var ns Node
-
-			Nodconst(&ns, Types[TUINT], int64(m.S))
-			n2 := conv(nod(ORSH, n1, &ns), nl.Type)
-
-			// add 1 iff n1 is negative.
-			var nneg Node
-
-			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.
-			if m.Sd < 0 {
-				n = nod(OMINUS, n, nil)
-			}
-		}
-
-		goto ret
-	}
-
-	switch pow {
-	case 0:
-		if n.Op == OMOD {
-			// nl % 1 is zero.
-			Nodconst(n, n.Type, 0)
-		} else if s != 0 {
-			// divide by -1
-			n.Op = OMINUS
-
-			n.Right = nil
-		} else {
-			// divide by 1
-			n = nl
-		}
-
-	default:
-		if 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.
-				var nc Node
-
-				Nodconst(&nc, Types[simtype[TUINT]], int64(w)-1)
-				n1 := nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
-				if pow == 1 {
-					n1 = typecheck(n1, Erv)
-					n1 = cheapexpr(n1, init)
-
-					// n = (nl+ε)&1 -ε where ε=1 iff nl<0.
-					n2 := nod(OSUB, nl, n1)
-
-					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.
-					var nc Node
-
-					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)
-					n = nod(OSUB, n4, n2)
-				}
-
-				break
-			} else {
-				// arithmetic right shift does not give the correct rounding.
-				// if nl >= 0, nl >> n == nl / nr
-				// if nl < 0, we want to add 2^n-1 first.
-				var nc Node
-
-				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.
-					var nc Node
-
-					Nodconst(&nc, Types[simtype[TUINT]], int64(w)-int64(pow))
-					n2 := nod(ORSH, conv(n1, nl.Type.toUnsigned()), &nc)
-					n.Left = nod(OADD, nl, conv(n2, nl.Type))
-				}
-
-				// n = (nl + 2^pow-1) >> pow
-				n.Op = ORSH
-
-				var n2 Node
-				Nodconst(&n2, Types[simtype[TUINT]], int64(pow))
-				n.Right = &n2
-				n.Typecheck = 0
-			}
-
-			if s != 0 {
-				n = nod(OMINUS, n, nil)
-			}
-			break
-		}
-
-		var nc Node
-		if n.Op == OMOD {
-			// n = nl & (nr-1)
-			n.Op = OAND
-
-			Nodconst(&nc, nl.Type, nr.Int64()-1)
-		} else {
-			// n = nl >> pow
-			n.Op = ORSH
-
-			Nodconst(&nc, Types[simtype[TUINT]], int64(pow))
-		}
-
-		n.Typecheck = 0
-		n.Right = &nc
-	}
-
-	goto ret
-
-ret:
-	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 || !n.Type.IsInteger() {
@@ -3864,7 +3631,7 @@ func usemethod(n *Node) {
 	}
 	p0 := t.Params().Field(0)
 	res0 := t.Results().Field(0)
-	var res1 *Field
+	var res1 *types.Field
 	if t.Results().NumFields() == 2 {
 		res1 = t.Results().Field(1)
 	}
@@ -3885,11 +3652,11 @@ func usemethod(n *Node) {
 		return
 	}
 
-	Curfn.Func.ReflectMethod = true
+	Curfn.Func.SetReflectMethod(true)
 }
 
 func usefield(n *Node) {
-	if obj.Fieldtrack_enabled == 0 {
+	if objabi.Fieldtrack_enabled == 0 {
 		return
 	}
 
@@ -3910,7 +3677,7 @@ func usefield(n *Node) {
 	if t.IsPtr() {
 		t = t.Elem()
 	}
-	field := dotField[typeSym{t.Orig, n.Sym}]
+	field := dotField[typeSymKey{t.Orig, n.Sym}]
 	if field == nil {
 		Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
 	}
@@ -3931,7 +3698,7 @@ func usefield(n *Node) {
 
 	sym := tracksym(outer, field)
 	if Curfn.Func.FieldTrack == nil {
-		Curfn.Func.FieldTrack = make(map[*Sym]struct{})
+		Curfn.Func.FieldTrack = make(map[*types.Sym]struct{})
 	}
 	Curfn.Func.FieldTrack[sym] = struct{}{}
 }
@@ -4066,22 +3833,17 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
 	for _, n1 := range n.List.Slice() {
 		buf = fmt.Sprintf("a%d", num)
 		num++
-		a = nod(ODCLFIELD, newname(lookup(buf)), typenod(n1.Type))
+		a = namedfield(buf, n1.Type)
 		t.List.Append(a)
 		printargs = append(printargs, a.Left)
 	}
 
-	fn := nod(ODCLFUNC, nil, nil)
-	walkprintfunc_prgen++
-	buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
-	fn.Func.Nname = newname(lookup(buf))
-	fn.Func.Nname.Name.Defn = fn
-	fn.Func.Nname.Name.Param.Ntype = t
-	declare(fn.Func.Nname, PFUNC)
-
 	oldfn := Curfn
 	Curfn = nil
-	funchdr(fn)
+
+	walkprintfunc_prgen++
+	sym := lookupN("print·%d", walkprintfunc_prgen)
+	fn := dclfunc(sym, t)
 
 	a = nod(n.Op, nil, nil)
 	a.List.Set(printargs)
@@ -4104,3 +3866,21 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
 	a = walkexpr(a, init)
 	return a
 }
+
+// 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_ ...*types.Type) *Node {
+	n := *old // make shallow copy
+
+	for _, t := range types_ {
+		dowidth(t)
+	}
+	n.Type = types.SubstAny(n.Type, &types_)
+	if len(types_) > 0 {
+		Fatalf("substArgTypes: too many argument types")
+	}
+	return &n
+}
diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go
index e6d117a..77ec78a 100644
--- a/src/cmd/compile/internal/mips/galign.go
+++ b/src/cmd/compile/internal/mips/galign.go
@@ -7,21 +7,21 @@ package mips
 import (
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
-	"cmd/internal/obj"
 	"cmd/internal/obj/mips"
+	"cmd/internal/objabi"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &mips.Linkmips
-	if obj.GOARCH == "mipsle" {
-		gc.Thearch.LinkArch = &mips.Linkmipsle
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &mips.Linkmips
+	if objabi.GOARCH == "mipsle" {
+		arch.LinkArch = &mips.Linkmipsle
 	}
-	gc.Thearch.REGSP = mips.REGSP
-	gc.Thearch.MAXWIDTH = (1 << 31) - 1
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
-	gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.REGSP = mips.REGSP
+	arch.MAXWIDTH = (1 << 31) - 1
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
+	arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/mips/ggen.go b/src/cmd/compile/internal/mips/ggen.go
index a95db57..acbe4a9 100644
--- a/src/cmd/compile/internal/mips/ggen.go
+++ b/src/cmd/compile/internal/mips/ggen.go
@@ -10,64 +10,15 @@ import (
 	"cmd/internal/obj/mips"
 )
 
-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 %L has size %d offset %d", n, 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)
-}
-
 // TODO(mips): implement DUFFZERO
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 
-	cnt := hi - lo
 	if cnt == 0 {
 		return p
 	}
 	if cnt < int64(4*gc.Widthptr) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
-			p = gc.Appendpp(p, mips.AMOVW, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, gc.Ctxt.FixedFrameSize()+frame+lo+i)
+			p = pp.Appendpp(p, mips.AMOVW, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, gc.Ctxt.FixedFrameSize()+off+i)
 		}
 	} else {
 		//fmt.Printf("zerorange frame:%v, lo: %v, hi:%v \n", frame ,lo, hi)
@@ -77,14 +28,14 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 		//	MOVW	R0, (Widthptr)r1
 		//	ADD 	$Widthptr, r1
 		//	BNE		r1, r2, loop
-		p = gc.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-4, obj.TYPE_REG, mips.REGRT1, 0)
+		p = pp.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+off-4, obj.TYPE_REG, mips.REGRT1, 0)
 		p.Reg = mips.REGSP
-		p = gc.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
+		p = pp.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
 		p.Reg = mips.REGRT1
-		p = gc.Appendpp(p, mips.AMOVW, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
+		p = pp.Appendpp(p, mips.AMOVW, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
 		p1 := p
-		p = gc.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, int64(gc.Widthptr), obj.TYPE_REG, mips.REGRT1, 0)
-		p = gc.Appendpp(p, mips.ABNE, obj.TYPE_REG, mips.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, mips.AADD, obj.TYPE_CONST, 0, int64(gc.Widthptr), obj.TYPE_REG, mips.REGRT1, 0)
+		p = pp.Appendpp(p, mips.ABNE, obj.TYPE_REG, mips.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
 		p.Reg = mips.REGRT2
 		gc.Patch(p, p1)
 	}
@@ -92,13 +43,12 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += 4 {
-		p := gc.AddAsmAfter(mips.AMOVW, pp)
-		pp = p
+		p := pp.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -109,8 +59,8 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(mips.ANOR)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(mips.ANOR)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = mips.REG_R0
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/mips/prog.go b/src/cmd/compile/internal/mips/prog.go
deleted file mode 100644
index 32805f0..0000000
--- a/src/cmd/compile/internal/mips/prog.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2016 The Go Authors. 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
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/mips"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-var progtable = [mips.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// NOP is an internal no-op that also stands
-	// for USED and SET annotations, not the MIPS opcode.
-	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
-
-	// Integer
-	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.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.AAND & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AOR & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AXOR & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ANOR & obj.AMask:  {Flags: gc.SizeL | 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.ADIV & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.ADIVU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.ASLL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRA & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASGT & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASGTU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-
-	mips.ACLZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	mips.ACLO & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-
-	// Floating point.
-	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.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.ASQRTF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
-	mips.ASQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-
-	// Moves
-	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.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 | gc.Conv},
-
-	// Conditional moves
-	mips.ACMOVN & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
-	mips.ACMOVZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
-	mips.ACMOVT & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr},
-	mips.ACMOVF & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr},
-
-	// Conditional trap
-	mips.ATEQ & obj.AMask: {Flags: gc.SizeL | gc.RegRead | gc.RightRead},
-	mips.ATNE & obj.AMask: {Flags: gc.SizeL | gc.RegRead | gc.RightRead},
-
-	// Atomic
-	mips.ASYNC & obj.AMask: {Flags: gc.OK},
-	mips.ALL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-	mips.ASC & obj.AMask:   {Flags: gc.SizeL | LeftRdwr | gc.RightRead},
-
-	// Jumps
-	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) gc.ProgInfo {
-	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
-	}
-
-	if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	if p.As == mips.AMUL && p.To.Reg != 0 {
-		info.Flags |= gc.RightWrite
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/mips/ssa.go b/src/cmd/compile/internal/mips/ssa.go
index aef1f90..d2b4885 100644
--- a/src/cmd/compile/internal/mips/ssa.go
+++ b/src/cmd/compile/internal/mips/ssa.go
@@ -9,6 +9,7 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/mips"
 )
@@ -24,7 +25,7 @@ func isHILO(r int16) bool {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type, r int16) obj.As {
+func loadByType(t *types.Type, r int16) obj.As {
 	if isFPreg(r) {
 		if t.Size() == 4 { // float32 or int32
 			return mips.AMOVF
@@ -53,7 +54,7 @@ func loadByType(t ssa.Type, r int16) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type, r int16) obj.As {
+func storeByType(t *types.Type, r int16) obj.As {
 	if isFPreg(r) {
 		if t.Size() == 4 { // float32 or int32
 			return mips.AMOVF
@@ -74,16 +75,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
 }
 
 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, ssa.OpGetG:
-		// nothing to do
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.OpCopy, ssa.OpMIPSMOVWconvert, ssa.OpMIPSMOVWreg:
 		t := v.Type
 		if t.IsMemory() {
@@ -102,7 +94,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			}
 		}
 
-		p := gc.Prog(as)
+		p := s.Prog(as)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x
 		p.To.Type = obj.TYPE_REG
@@ -110,7 +102,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
 			// cannot move between special registers, use TMP as intermediate
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVW)
+			p = s.Prog(mips.AMOVW)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
@@ -127,14 +119,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			return
 		}
 		r := v.Reg()
-		p := gc.Prog(loadByType(v.Type, r))
+		p := s.Prog(loadByType(v.Type, r))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		if isHILO(r) {
 			// cannot directly load, load to TMP and move
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVW)
+			p = s.Prog(mips.AMOVW)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
@@ -148,14 +140,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Args[0].Reg()
 		if isHILO(r) {
 			// cannot directly store, move to TMP and store
-			p := gc.Prog(mips.AMOVW)
+			p := s.Prog(mips.AMOVW)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = r
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = mips.REGTMP
 			r = mips.REGTMP
 		}
-		p := gc.Prog(storeByType(v.Type, r))
+		p := s.Prog(storeByType(v.Type, r))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		gc.AddrAuto(&p.To, v)
@@ -177,7 +169,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSDIVF,
 		ssa.OpMIPSDIVD,
 		ssa.OpMIPSMUL:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[0].Reg()
@@ -185,7 +177,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPSSGT,
 		ssa.OpMIPSSGTU:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -193,7 +185,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPSSGTzero,
 		ssa.OpMIPSSGTUzero:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = mips.REGZERO
@@ -210,7 +202,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSSRAconst,
 		ssa.OpMIPSSGTconst,
 		ssa.OpMIPSSGTUconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
@@ -221,13 +213,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSDIV,
 		ssa.OpMIPSDIVU:
 		// result in hi,lo
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[0].Reg()
 	case ssa.OpMIPSMOVWconst:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -235,7 +227,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if isFPreg(r) || isHILO(r) {
 			// cannot move into FP or special registers, use TMP as intermediate
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVW)
+			p = s.Prog(mips.AMOVW)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
@@ -243,7 +235,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		}
 	case ssa.OpMIPSMOVFconst,
 		ssa.OpMIPSMOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
@@ -252,7 +244,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Reg() != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -262,7 +254,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Reg() != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = mips.REGZERO
@@ -274,12 +266,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSCMPGED,
 		ssa.OpMIPSCMPGTF,
 		ssa.OpMIPSCMPGTD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
 	case ssa.OpMIPSMOVWaddr:
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_ADDR
 		var wantreg string
 		// MOVW $sym+off(base), R
@@ -314,7 +306,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSMOVWload,
 		ssa.OpMIPSMOVFload,
 		ssa.OpMIPSMOVDload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -325,7 +317,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSMOVWstore,
 		ssa.OpMIPSMOVFstore,
 		ssa.OpMIPSMOVDstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -334,7 +326,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpMIPSMOVBstorezero,
 		ssa.OpMIPSMOVHstorezero,
 		ssa.OpMIPSMOVWstorezero:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -359,7 +351,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				if v.Reg() == v.Args[0].Reg() {
 					return
 				}
-				p := gc.Prog(mips.AMOVW)
+				p := s.Prog(mips.AMOVW)
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = v.Args[0].Reg()
 				p.To.Type = obj.TYPE_REG
@@ -379,14 +371,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPSNEGD,
 		ssa.OpMIPSSQRTD,
 		ssa.OpMIPSCLZ:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPSNEG:
 		// SUB from REGZERO
-		p := gc.Prog(mips.ASUBU)
+		p := s.Prog(mips.ASUBU)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = mips.REGZERO
@@ -411,23 +403,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = mips.AMOVB
 		}
-		p := gc.Prog(mips.ASUBU)
+		p := s.Prog(mips.ASUBU)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = sz
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REG_R1
-		p2 := gc.Prog(mov)
+		p2 := s.Prog(mov)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGZERO
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = mips.REG_R1
 		p2.To.Offset = sz
-		p3 := gc.Prog(mips.AADDU)
+		p3 := s.Prog(mips.AADDU)
 		p3.From.Type = obj.TYPE_CONST
 		p3.From.Offset = sz
 		p3.To.Type = obj.TYPE_REG
 		p3.To.Reg = mips.REG_R1
-		p4 := gc.Prog(mips.ABNE)
+		p4 := s.Prog(mips.ABNE)
 		p4.From.Type = obj.TYPE_REG
 		p4.From.Reg = v.Args[1].Reg()
 		p4.Reg = mips.REG_R1
@@ -454,119 +446,70 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = mips.AMOVB
 		}
-		p := gc.Prog(mips.ASUBU)
+		p := s.Prog(mips.ASUBU)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = sz
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REG_R1
-		p2 := gc.Prog(mov)
+		p2 := s.Prog(mov)
 		p2.From.Type = obj.TYPE_MEM
 		p2.From.Reg = mips.REG_R1
 		p2.From.Offset = sz
 		p2.To.Type = obj.TYPE_REG
 		p2.To.Reg = mips.REGTMP
-		p3 := gc.Prog(mov)
+		p3 := s.Prog(mov)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_MEM
 		p3.To.Reg = mips.REG_R2
-		p4 := gc.Prog(mips.AADDU)
+		p4 := s.Prog(mips.AADDU)
 		p4.From.Type = obj.TYPE_CONST
 		p4.From.Offset = sz
 		p4.To.Type = obj.TYPE_REG
 		p4.To.Reg = mips.REG_R1
-		p5 := gc.Prog(mips.AADDU)
+		p5 := s.Prog(mips.AADDU)
 		p5.From.Type = obj.TYPE_CONST
 		p5.From.Offset = sz
 		p5.To.Type = obj.TYPE_REG
 		p5.To.Reg = mips.REG_R2
-		p6 := gc.Prog(mips.ABNE)
+		p6 := s.Prog(mips.ABNE)
 		p6.From.Type = obj.TYPE_REG
 		p6.From.Reg = v.Args[2].Reg()
 		p6.Reg = mips.REG_R1
 		p6.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p6, p2)
-	case ssa.OpMIPSCALLstatic:
-		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.OpMIPSCALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.OpMIPSCALLdefer:
-		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.OpMIPSCALLgo:
-		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.OpMIPSCALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
+		s.Call(v)
 	case ssa.OpMIPSLoweredAtomicLoad:
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 	case ssa.OpMIPSLoweredAtomicStore:
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 	case ssa.OpMIPSLoweredAtomicStorezero:
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 	case ssa.OpMIPSLoweredAtomicExchange:
 		// SYNC
 		// MOVW Rarg1, Rtmp
@@ -574,33 +517,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// SC	Rtmp, (Rarg0)
 		// BEQ	Rtmp, -3(PC)
 		// SYNC
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REGTMP
 
-		p1 := gc.Prog(mips.ALL)
+		p1 := s.Prog(mips.ALL)
 		p1.From.Type = obj.TYPE_MEM
 		p1.From.Reg = v.Args[0].Reg()
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = v.Reg0()
 
-		p2 := gc.Prog(mips.ASC)
+		p2 := s.Prog(mips.ASC)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = v.Args[0].Reg()
 
-		p3 := gc.Prog(mips.ABEQ)
+		p3 := s.Prog(mips.ABEQ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 	case ssa.OpMIPSLoweredAtomicAdd:
 		// SYNC
 		// LL	(Rarg0), Rout
@@ -609,36 +552,36 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// BEQ	Rtmp, -3(PC)
 		// SYNC
 		// ADDU Rarg1, Rout
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.ALL)
+		p := s.Prog(mips.ALL)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 
-		p1 := gc.Prog(mips.AADDU)
+		p1 := s.Prog(mips.AADDU)
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = v.Args[1].Reg()
 		p1.Reg = v.Reg0()
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = mips.REGTMP
 
-		p2 := gc.Prog(mips.ASC)
+		p2 := s.Prog(mips.ASC)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = v.Args[0].Reg()
 
-		p3 := gc.Prog(mips.ABEQ)
+		p3 := s.Prog(mips.ABEQ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p4 := gc.Prog(mips.AADDU)
+		p4 := s.Prog(mips.AADDU)
 		p4.From.Type = obj.TYPE_REG
 		p4.From.Reg = v.Args[1].Reg()
 		p4.Reg = v.Reg0()
@@ -653,36 +596,36 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// BEQ	Rtmp, -3(PC)
 		// SYNC
 		// ADDU $auxInt, Rout
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.ALL)
+		p := s.Prog(mips.ALL)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 
-		p1 := gc.Prog(mips.AADDU)
+		p1 := s.Prog(mips.AADDU)
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = v.AuxInt
 		p1.Reg = v.Reg0()
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = mips.REGTMP
 
-		p2 := gc.Prog(mips.ASC)
+		p2 := s.Prog(mips.ASC)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = v.Args[0].Reg()
 
-		p3 := gc.Prog(mips.ABEQ)
+		p3 := s.Prog(mips.ABEQ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p4 := gc.Prog(mips.AADDU)
+		p4 := s.Prog(mips.AADDU)
 		p4.From.Type = obj.TYPE_CONST
 		p4.From.Offset = v.AuxInt
 		p4.Reg = v.Reg0()
@@ -697,34 +640,34 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// SC	Rtmp, (Rarg0)
 		// BEQ	Rtmp, -3(PC)
 		// SYNC
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p := gc.Prog(mips.ALL)
+		p := s.Prog(mips.ALL)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REGTMP
 
-		p1 := gc.Prog(v.Op.Asm())
+		p1 := s.Prog(v.Op.Asm())
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = v.Args[1].Reg()
 		p1.Reg = mips.REGTMP
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = mips.REGTMP
 
-		p2 := gc.Prog(mips.ASC)
+		p2 := s.Prog(mips.ASC)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGTMP
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = v.Args[0].Reg()
 
-		p3 := gc.Prog(mips.ABEQ)
+		p3 := s.Prog(mips.ABEQ)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p3, p)
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
 	case ssa.OpMIPSLoweredAtomicCas:
 		// MOVW $0, Rout
@@ -735,69 +678,59 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// SC	Rout, (Rarg0)
 		// BEQ	Rout, -4(PC)
 		// SYNC
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p1 := gc.Prog(mips.ALL)
+		p1 := s.Prog(mips.ALL)
 		p1.From.Type = obj.TYPE_MEM
 		p1.From.Reg = v.Args[0].Reg()
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = mips.REGTMP
 
-		p2 := gc.Prog(mips.ABNE)
+		p2 := s.Prog(mips.ABNE)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = v.Args[1].Reg()
 		p2.Reg = mips.REGTMP
 		p2.To.Type = obj.TYPE_BRANCH
 
-		p3 := gc.Prog(mips.AMOVW)
+		p3 := s.Prog(mips.AMOVW)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = v.Args[2].Reg()
 		p3.To.Type = obj.TYPE_REG
 		p3.To.Reg = v.Reg0()
 
-		p4 := gc.Prog(mips.ASC)
+		p4 := s.Prog(mips.ASC)
 		p4.From.Type = obj.TYPE_REG
 		p4.From.Reg = v.Reg0()
 		p4.To.Type = obj.TYPE_MEM
 		p4.To.Reg = v.Args[0].Reg()
 
-		p5 := gc.Prog(mips.ABEQ)
+		p5 := s.Prog(mips.ABEQ)
 		p5.From.Type = obj.TYPE_REG
 		p5.From.Reg = v.Reg0()
 		p5.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p5, p1)
 
-		gc.Prog(mips.ASYNC)
+		s.Prog(mips.ASYNC)
 
-		p6 := gc.Prog(obj.ANOP)
+		p6 := s.Prog(obj.ANOP)
 		gc.Patch(p2, p6)
 
-	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:
-		gc.KeepAlive(v)
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
 	case ssa.OpMIPSLoweredNilCheck:
 		// Issue a load which will fault if arg is nil.
-		p := gc.Prog(mips.AMOVB)
+		p := s.Prog(mips.AMOVB)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 	case ssa.OpMIPSFPFlagTrue,
 		ssa.OpMIPSFPFlagFalse:
@@ -808,12 +741,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Op == ssa.OpMIPSFPFlagFalse {
 			cmov = mips.ACMOVT
 		}
-		p := gc.Prog(mips.AMOVW)
+		p := s.Prog(mips.AMOVW)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		p1 := gc.Prog(cmov)
+		p1 := s.Prog(cmov)
 		p1.From.Type = obj.TYPE_REG
 		p1.From.Reg = mips.REGZERO
 		p1.To.Type = obj.TYPE_REG
@@ -822,6 +755,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpMIPSLoweredGetClosurePtr:
 		// Closure pointer is R22 (mips.REGCTXT).
 		gc.CheckLoweredGetClosurePtr(v)
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -841,12 +776,10 @@ var blockJump = map[ssa.BlockKind]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -854,26 +787,26 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in R1:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(mips.ABNE)
+		p := s.Prog(mips.ABNE)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.Reg = mips.REG_R1
 		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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.ARET)
+		p := s.Prog(obj.ARET)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 	case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
 		ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
 		ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
@@ -882,18 +815,18 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		var p *obj.Prog
 		switch next {
 		case b.Succs[0].Block():
-			p = gc.Prog(jmp.invasm)
+			p = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.Prog(obj.AJMP)
 			q.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 		}
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index e8ea073..910230f 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -7,23 +7,23 @@ package mips64
 import (
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
-	"cmd/internal/obj"
 	"cmd/internal/obj/mips"
+	"cmd/internal/objabi"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &mips.Linkmips64
-	if obj.GOARCH == "mips64le" {
-		gc.Thearch.LinkArch = &mips.Linkmips64le
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &mips.Linkmips64
+	if objabi.GOARCH == "mips64le" {
+		arch.LinkArch = &mips.Linkmips64le
 	}
-	gc.Thearch.REGSP = mips.REGSP
-	gc.Thearch.MAXWIDTH = 1 << 50
+	arch.REGSP = mips.REGSP
+	arch.MAXWIDTH = 1 << 50
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/mips64/ggen.go b/src/cmd/compile/internal/mips64/ggen.go
index eb48e2b..a7e07d3 100644
--- a/src/cmd/compile/internal/mips64/ggen.go
+++ b/src/cmd/compile/internal/mips64/ggen.go
@@ -10,68 +10,20 @@ import (
 	"cmd/internal/obj/mips"
 )
 
-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 %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
-		}
-
-		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
-			// merge with range we already have
-			lo = n.Xoffset
-
-			continue
-		}
-
-		// zero old range
-		p = zerorange(p, int64(frame), lo, hi)
-
-		// set new range
-		hi = n.Xoffset + n.Type.Width
-
-		lo = n.Xoffset
-	}
-
-	// zero final range
-	zerorange(p, int64(frame), lo, hi)
-}
-
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 	if cnt < int64(4*gc.Widthptr) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
-			p = gc.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, 8+frame+lo+i)
+			p = pp.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, 8+off+i)
 		}
 	} else if cnt <= int64(128*gc.Widthptr) {
-		p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, mips.REGRT1, 0)
+		p = pp.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+off-8, obj.TYPE_REG, mips.REGRT1, 0)
 		p.Reg = mips.REGSP
-		p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
-		gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = 8 * (128 - cnt/int64(gc.Widthptr))
 	} else {
 		//	ADDV	$(8+frame+lo-8), SP, r1
@@ -80,14 +32,14 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 		//	MOVV	R0, (Widthptr)r1
 		//	ADDV	$Widthptr, r1
 		//	BNE		r1, r2, loop
-		p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, mips.REGRT1, 0)
+		p = pp.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+off-8, obj.TYPE_REG, mips.REGRT1, 0)
 		p.Reg = mips.REGSP
-		p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
+		p = pp.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
 		p.Reg = mips.REGRT1
-		p = gc.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
+		p = pp.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
 		p1 := p
-		p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, int64(gc.Widthptr), obj.TYPE_REG, mips.REGRT1, 0)
-		p = gc.Appendpp(p, mips.ABNE, obj.TYPE_REG, mips.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, int64(gc.Widthptr), obj.TYPE_REG, mips.REGRT1, 0)
+		p = pp.Appendpp(p, mips.ABNE, obj.TYPE_REG, mips.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
 		p.Reg = mips.REGRT2
 		gc.Patch(p, p1)
 	}
@@ -95,13 +47,12 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += 8 {
-		p := gc.AddAsmAfter(mips.AMOVV, pp)
-		pp = p
+		p := pp.Prog(mips.AMOVV)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -112,8 +63,8 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(mips.ANOR)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(mips.ANOR)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = mips.REG_R0
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/mips64/prog.go b/src/cmd/compile/internal/mips64/prog.go
deleted file mode 100644
index 74c735c..0000000
--- a/src/cmd/compile/internal/mips64/prog.go
+++ /dev/null
@@ -1,154 +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 mips64
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/mips"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-var progtable = [mips.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// NOP is an internal no-op that also stands
-	// for USED and SET annotations, not the MIPS opcode.
-	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
-
-	// Integer
-	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 & 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 & 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 & 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) gc.ProgInfo {
-	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_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go
index 1432c6c..5a7a601 100644
--- a/src/cmd/compile/internal/mips64/ssa.go
+++ b/src/cmd/compile/internal/mips64/ssa.go
@@ -9,6 +9,7 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/mips"
 )
@@ -24,7 +25,7 @@ func isHILO(r int16) bool {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type, r int16) obj.As {
+func loadByType(t *types.Type, r int16) obj.As {
 	if isFPreg(r) {
 		if t.Size() == 4 { // float32 or int32
 			return mips.AMOVF
@@ -59,7 +60,7 @@ func loadByType(t ssa.Type, r int16) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type, r int16) obj.As {
+func storeByType(t *types.Type, r int16) obj.As {
 	if isFPreg(r) {
 		if t.Size() == 4 { // float32 or int32
 			return mips.AMOVF
@@ -82,14 +83,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
 }
 
 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, ssa.OpGetG:
-		// nothing to do
 	case ssa.OpCopy, ssa.OpMIPS64MOVVconvert, ssa.OpMIPS64MOVVreg:
 		if v.Type.IsMemory() {
 			return
@@ -103,7 +97,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if isFPreg(x) && isFPreg(y) {
 			as = mips.AMOVD
 		}
-		p := gc.Prog(as)
+		p := s.Prog(as)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x
 		p.To.Type = obj.TYPE_REG
@@ -111,7 +105,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
 			// cannot move between special registers, use TMP as intermediate
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVV)
+			p = s.Prog(mips.AMOVV)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
@@ -128,21 +122,19 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			return
 		}
 		r := v.Reg()
-		p := gc.Prog(loadByType(v.Type, r))
+		p := s.Prog(loadByType(v.Type, r))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		if isHILO(r) {
 			// cannot directly load, load to TMP and move
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVV)
+			p = s.Prog(mips.AMOVV)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = r
 		}
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
 	case ssa.OpStoreReg:
 		if v.Type.IsFlags() {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
@@ -151,14 +143,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Args[0].Reg()
 		if isHILO(r) {
 			// cannot directly store, move to TMP and store
-			p := gc.Prog(mips.AMOVV)
+			p := s.Prog(mips.AMOVV)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = r
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = mips.REGTMP
 			r = mips.REGTMP
 		}
-		p := gc.Prog(storeByType(v.Type, r))
+		p := s.Prog(storeByType(v.Type, r))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		gc.AddrAuto(&p.To, v)
@@ -179,7 +171,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64MULD,
 		ssa.OpMIPS64DIVF,
 		ssa.OpMIPS64DIVD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[0].Reg()
@@ -187,7 +179,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPS64SGT,
 		ssa.OpMIPS64SGTU:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
@@ -204,7 +196,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64SRAVconst,
 		ssa.OpMIPS64SGTconst,
 		ssa.OpMIPS64SGTUconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.Reg = v.Args[0].Reg()
@@ -215,13 +207,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64DIVV,
 		ssa.OpMIPS64DIVVU:
 		// result in hi,lo
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[0].Reg()
 	case ssa.OpMIPS64MOVVconst:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -229,7 +221,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if isFPreg(r) || isHILO(r) {
 			// cannot move into FP or special registers, use TMP as intermediate
 			p.To.Reg = mips.REGTMP
-			p = gc.Prog(mips.AMOVV)
+			p = s.Prog(mips.AMOVV)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = mips.REGTMP
 			p.To.Type = obj.TYPE_REG
@@ -237,7 +229,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		}
 	case ssa.OpMIPS64MOVFconst,
 		ssa.OpMIPS64MOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
@@ -248,12 +240,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64CMPGED,
 		ssa.OpMIPS64CMPGTF,
 		ssa.OpMIPS64CMPGTD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = v.Args[1].Reg()
 	case ssa.OpMIPS64MOVVaddr:
-		p := gc.Prog(mips.AMOVV)
+		p := s.Prog(mips.AMOVV)
 		p.From.Type = obj.TYPE_ADDR
 		var wantreg string
 		// MOVV $sym+off(base), R
@@ -290,7 +282,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64MOVVload,
 		ssa.OpMIPS64MOVFload,
 		ssa.OpMIPS64MOVDload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -302,7 +294,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64MOVVstore,
 		ssa.OpMIPS64MOVFstore,
 		ssa.OpMIPS64MOVDstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -312,7 +304,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64MOVHstorezero,
 		ssa.OpMIPS64MOVWstorezero,
 		ssa.OpMIPS64MOVVstorezero:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -341,7 +333,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				if v.Reg() == v.Args[0].Reg() {
 					return
 				}
-				p := gc.Prog(mips.AMOVV)
+				p := s.Prog(mips.AMOVV)
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = v.Args[0].Reg()
 				p.To.Type = obj.TYPE_REG
@@ -363,14 +355,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpMIPS64MOVDF,
 		ssa.OpMIPS64NEGF,
 		ssa.OpMIPS64NEGD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPS64NEGV:
 		// SUB from REGZERO
-		p := gc.Prog(mips.ASUBVU)
+		p := s.Prog(mips.ASUBVU)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.Reg = mips.REGZERO
@@ -378,16 +370,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.OpMIPS64DUFFZERO:
 		// runtime.duffzero expects start address - 8 in R1
-		p := gc.Prog(mips.ASUBVU)
+		p := s.Prog(mips.ASUBVU)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
 		p.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REG_R1
-		p = gc.Prog(obj.ADUFFZERO)
+		p = s.Prog(obj.ADUFFZERO)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = v.AuxInt
 	case ssa.OpMIPS64LoweredZero:
 		// SUBV	$8, R1
@@ -411,23 +403,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = mips.AMOVB
 		}
-		p := gc.Prog(mips.ASUBVU)
+		p := s.Prog(mips.ASUBVU)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = sz
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REG_R1
-		p2 := gc.Prog(mov)
+		p2 := s.Prog(mov)
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = mips.REGZERO
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = mips.REG_R1
 		p2.To.Offset = sz
-		p3 := gc.Prog(mips.AADDVU)
+		p3 := s.Prog(mips.AADDVU)
 		p3.From.Type = obj.TYPE_CONST
 		p3.From.Offset = sz
 		p3.To.Type = obj.TYPE_REG
 		p3.To.Reg = mips.REG_R1
-		p4 := gc.Prog(mips.ABNE)
+		p4 := s.Prog(mips.ABNE)
 		p4.From.Type = obj.TYPE_REG
 		p4.From.Reg = v.Args[1].Reg()
 		p4.Reg = mips.REG_R1
@@ -457,108 +449,51 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			sz = 1
 			mov = mips.AMOVB
 		}
-		p := gc.Prog(mips.ASUBVU)
+		p := s.Prog(mips.ASUBVU)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = sz
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REG_R1
-		p2 := gc.Prog(mov)
+		p2 := s.Prog(mov)
 		p2.From.Type = obj.TYPE_MEM
 		p2.From.Reg = mips.REG_R1
 		p2.From.Offset = sz
 		p2.To.Type = obj.TYPE_REG
 		p2.To.Reg = mips.REGTMP
-		p3 := gc.Prog(mov)
+		p3 := s.Prog(mov)
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = mips.REGTMP
 		p3.To.Type = obj.TYPE_MEM
 		p3.To.Reg = mips.REG_R2
-		p4 := gc.Prog(mips.AADDVU)
+		p4 := s.Prog(mips.AADDVU)
 		p4.From.Type = obj.TYPE_CONST
 		p4.From.Offset = sz
 		p4.To.Type = obj.TYPE_REG
 		p4.To.Reg = mips.REG_R1
-		p5 := gc.Prog(mips.AADDVU)
+		p5 := s.Prog(mips.AADDVU)
 		p5.From.Type = obj.TYPE_CONST
 		p5.From.Offset = sz
 		p5.To.Type = obj.TYPE_REG
 		p5.To.Reg = mips.REG_R2
-		p6 := gc.Prog(mips.ABNE)
+		p6 := s.Prog(mips.ABNE)
 		p6.From.Type = obj.TYPE_REG
 		p6.From.Reg = v.Args[2].Reg()
 		p6.Reg = mips.REG_R1
 		p6.To.Type = obj.TYPE_BRANCH
 		gc.Patch(p6, p2)
-	case ssa.OpMIPS64CALLstatic:
-		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.OpMIPS64CALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.OpMIPS64CALLdefer:
-		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.OpMIPS64CALLgo:
-		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.OpMIPS64CALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_MEM
-		p.To.Offset = 0
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter:
+		s.Call(v)
 	case ssa.OpMIPS64LoweredNilCheck:
 		// Issue a load which will fault if arg is nil.
-		p := gc.Prog(mips.AMOVB)
+		p := s.Prog(mips.AMOVB)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = mips.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
-	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:
-		gc.KeepAlive(v)
 	case ssa.OpMIPS64FPFlagTrue,
 		ssa.OpMIPS64FPFlagFalse:
 		// MOVV	$0, r
@@ -568,25 +503,25 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if v.Op == ssa.OpMIPS64FPFlagFalse {
 			branch = mips.ABFPT
 		}
-		p := gc.Prog(mips.AMOVV)
+		p := s.Prog(mips.AMOVV)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		p2 := gc.Prog(branch)
+		p2 := s.Prog(branch)
 		p2.To.Type = obj.TYPE_BRANCH
-		p3 := gc.Prog(mips.AMOVV)
+		p3 := s.Prog(mips.AMOVV)
 		p3.From.Type = obj.TYPE_CONST
 		p3.From.Offset = 1
 		p3.To.Type = obj.TYPE_REG
 		p3.To.Reg = v.Reg()
-		p4 := gc.Prog(obj.ANOP) // not a machine instruction, for branch to land
+		p4 := s.Prog(obj.ANOP) // not a machine instruction, for branch to land
 		gc.Patch(p2, p4)
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.OpMIPS64LoweredGetClosurePtr:
 		// Closure pointer is R22 (mips.REGCTXT).
 		gc.CheckLoweredGetClosurePtr(v)
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -606,12 +541,10 @@ var blockJump = map[ssa.BlockKind]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -619,26 +552,26 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in R1:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(mips.ABNE)
+		p := s.Prog(mips.ABNE)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = mips.REGZERO
 		p.Reg = mips.REG_R1
 		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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.ARET)
+		p := s.Prog(obj.ARET)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 	case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE,
 		ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ,
 		ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ,
@@ -647,18 +580,18 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		var p *obj.Prog
 		switch next {
 		case b.Succs[0].Block():
-			p = gc.Prog(jmp.invasm)
+			p = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.Prog(obj.AJMP)
 			q.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 		}
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index 3780247..ce805f4 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -6,26 +6,23 @@ package ppc64
 
 import (
 	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
+	"cmd/internal/objabi"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &ppc64.Linkppc64
-	if obj.GOARCH == "ppc64le" {
-		gc.Thearch.LinkArch = &ppc64.Linkppc64le
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &ppc64.Linkppc64
+	if objabi.GOARCH == "ppc64le" {
+		arch.LinkArch = &ppc64.Linkppc64le
 	}
-	gc.Thearch.REGSP = ppc64.REGSP
-	gc.Thearch.MAXWIDTH = 1 << 50
+	arch.REGSP = ppc64.REGSP
+	arch.MAXWIDTH = 1 << 50
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop2
 
-	gc.Thearch.SSAMarkMoves = ssaMarkMoves
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
-
-	initvariants()
-	initproginfo()
+	arch.SSAMarkMoves = ssaMarkMoves
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
index 4abd18d..5dda2d6 100644
--- a/src/cmd/compile/internal/ppc64/ggen.go
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -10,93 +10,44 @@ import (
 	"cmd/internal/obj/ppc64"
 )
 
-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 %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
-		}
-
-		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
-			// merge with range we already have
-			lo = n.Xoffset
-
-			continue
-		}
-
-		// zero old range
-		p = zerorange(p, int64(frame), lo, hi)
-
-		// set new range
-		hi = n.Xoffset + n.Type.Width
-
-		lo = n.Xoffset
-	}
-
-	// zero final range
-	zerorange(p, int64(frame), lo, hi)
-}
-
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 	if cnt < int64(4*gc.Widthptr) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
-			p = gc.Appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, gc.Ctxt.FixedFrameSize()+frame+lo+i)
+			p = pp.Appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, gc.Ctxt.FixedFrameSize()+off+i)
 		}
 	} else if cnt <= int64(128*gc.Widthptr) {
-		p = gc.Appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
+		p = pp.Appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+off-8, obj.TYPE_REG, ppc64.REGRT1, 0)
 		p.Reg = ppc64.REGSP
-		p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
-		gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
 	} else {
-		p = gc.Appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
-		p = gc.Appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
+		p = pp.Appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+off-8, obj.TYPE_REG, ppc64.REGTMP, 0)
+		p = pp.Appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
 		p.Reg = ppc64.REGSP
-		p = gc.Appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
-		p = gc.Appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
+		p = pp.Appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
+		p = pp.Appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
 		p.Reg = ppc64.REGRT1
-		p = gc.Appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
+		p = pp.Appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
 		p1 := p
-		p = gc.Appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
-		p = gc.Appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
+		p = pp.Appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
 		gc.Patch(p, p1)
 	}
 
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += 8 {
-		p := gc.AddAsmAfter(ppc64.AMOVD, pp)
-		pp = p
+		p := pp.Prog(ppc64.AMOVD)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = ppc64.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -107,10 +58,36 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(ppc64.AOR)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(ppc64.AOR)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = ppc64.REG_R0
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = ppc64.REG_R0
 }
+
+func ginsnop2(pp *gc.Progs) {
+	// PPC64 is unusual because TWO nops are required
+	// (see gc/cgen.go, gc/plive.go -- copy of comment below)
+	//
+	// On ppc64, when compiling Go into position
+	// independent code on ppc64le we insert an
+	// instruction to reload the TOC pointer from the
+	// stack as well. See the long comment near
+	// jmpdefer in runtime/asm_ppc64.s for why.
+	// 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.
+
+	ginsnop(pp)
+	if gc.Ctxt.Flag_shared {
+		p := pp.Prog(ppc64.AMOVD)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Offset = 24
+		p.From.Reg = ppc64.REGSP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = ppc64.REG_R2
+	} else {
+		ginsnop(pp)
+	}
+}
diff --git a/src/cmd/compile/internal/ppc64/prog.go b/src/cmd/compile/internal/ppc64/prog.go
deleted file mode 100644
index 59cbaa1..0000000
--- a/src/cmd/compile/internal/ppc64/prog.go
+++ /dev/null
@@ -1,304 +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 ppc64
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/ppc64"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-var progtable = [ppc64.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// 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},
-
-	// Integer
-	ppc64.AADD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AADDC & 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.AADDME & 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.AANDN & 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.AORN & 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.AEQV & 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.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULHDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULHW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULHWU & 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.ADIVW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ADIVWU & obj.AMask:  {Flags: gc.SizeL | 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.ASLW & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASRW & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASRAW & obj.AMask:   {Flags: gc.SizeL | 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.ACMPW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	ppc64.ACMPWU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	ppc64.ATD & obj.AMask:     {Flags: gc.SizeQ | gc.RightRead},
-
-	// Floating point.
-	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.AFCTIWZ & 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},
-	ppc64.AFNEG & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-
-	// Moves
-	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},
-
-	ppc64.AISEL & obj.AMask: {Flags: gc.SizeQ | gc.RegRead | gc.From3Read | gc.RightWrite},
-
-	// there is no AMOVWU.
-	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.AFMOVSX & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AFMOVSZ & 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 & obj.AMask:  {Flags: gc.Jump | gc.Break},
-	ppc64.ABL & obj.AMask:  {Flags: gc.Call},
-	ppc64.ABVS & obj.AMask: {Flags: gc.Cjmp},
-	ppc64.ABVC & obj.AMask: {Flags: gc.Cjmp},
-	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},
-}
-
-func initproginfo() {
-	var addvariant = []int{V_CC, V_V, V_CC | V_V}
-
-	// Perform one-time expansion of instructions in progtable to
-	// their CC, V, and VCC variants
-	for i := range progtable {
-		as := obj.As(i)
-		if progtable[as].Flags == 0 {
-			continue
-		}
-		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) gc.ProgInfo {
-	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_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	return info
-}
-
-// 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{}
-
-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() {
-	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)
-
-	for i := range varianttable {
-		vv := &varianttable[i]
-		if vv[0] == 0 {
-			// Instruction has no variants
-			varianttable[i][0] = obj.As(i)
-			continue
-		}
-
-		// Copy base form to other variants
-		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 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", 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 obj.As, flags int) obj.As {
-	return varianttable[as&obj.AMask][flags]
-}
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index 8387692..a95dabc 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -7,25 +7,12 @@ package ppc64
 import (
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"math"
 )
 
-var condOps = map[ssa.Op]obj.As{
-	ssa.OpPPC64Equal:        ppc64.ABEQ,
-	ssa.OpPPC64NotEqual:     ppc64.ABNE,
-	ssa.OpPPC64LessThan:     ppc64.ABLT,
-	ssa.OpPPC64GreaterEqual: ppc64.ABGE,
-	ssa.OpPPC64GreaterThan:  ppc64.ABGT,
-	ssa.OpPPC64LessEqual:    ppc64.ABLE,
-
-	ssa.OpPPC64FLessThan:     ppc64.ABLT, // 1 branch for FCMP
-	ssa.OpPPC64FGreaterThan:  ppc64.ABGT, // 1 branch for FCMP
-	ssa.OpPPC64FLessEqual:    ppc64.ABLT, // 2 branches for FCMP <=, second is BEQ
-	ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ
-}
-
 // iselOp encodes mapping of comparison operations onto ISEL operands
 type iselOp struct {
 	cond        int64
@@ -72,7 +59,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -108,7 +95,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -131,9 +118,9 @@ func storeByType(t ssa.Type) obj.As {
 	panic("bad store type")
 }
 
-func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
+func ssaGenISEL(s *gc.SSAGenState, v *ssa.Value, cr int64, r1, r2 int16) {
 	r := v.Reg()
-	p := gc.Prog(ppc64.AISEL)
+	p := s.Prog(ppc64.AISEL)
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = r
 	p.Reg = r1
@@ -143,15 +130,7 @@ func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
 }
 
 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, ssa.OpGetG:
-		// nothing to do
-
 	case ssa.OpCopy, ssa.OpPPC64MOVDconvert:
 		t := v.Type
 		if t.IsMemory() {
@@ -166,7 +145,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			if t.IsFloat() {
 				op = ppc64.AFMOVD
 			}
-			p := gc.Prog(op)
+			p := s.Prog(op)
 			p.From.Type = rt
 			p.From.Reg = x
 			p.To.Type = rt
@@ -177,43 +156,308 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		{
 			x := v.Args[0].Reg()
 			y := v.Reg()
-			p := gc.Prog(ppc64.AFMOVD)
+
+			p := s.Prog(ppc64.AMFVSRD)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = x
-			s.AddrScratch(&p.To)
-			p = gc.Prog(ppc64.AMOVD)
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = y
-			s.AddrScratch(&p.From)
 		}
 	case ssa.OpPPC64Xi2f64:
 		{
 			x := v.Args[0].Reg()
 			y := v.Reg()
-			p := gc.Prog(ppc64.AMOVD)
+
+			p := s.Prog(ppc64.AMTVSRD)
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = x
-			s.AddrScratch(&p.To)
-			p = gc.Prog(ppc64.AFMOVD)
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = y
-			s.AddrScratch(&p.From)
 		}
 
+	case ssa.OpPPC64LoweredAtomicAnd8,
+		ssa.OpPPC64LoweredAtomicOr8:
+		// SYNC
+		// LBAR		(Rarg0), Rtmp
+		// AND/OR	Rarg1, Rtmp
+		// STBCCC	Rtmp, (Rarg0)
+		// BNE		-3(PC)
+		// ISYNC
+		r0 := v.Args[0].Reg()
+		r1 := v.Args[1].Reg()
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		p := s.Prog(ppc64.ALBAR)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r0
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = ppc64.REGTMP
+		p1 := s.Prog(v.Op.Asm())
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = r1
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = ppc64.REGTMP
+		p2 := s.Prog(ppc64.ASTBCCC)
+		p2.From.Type = obj.TYPE_REG
+		p2.From.Reg = ppc64.REGTMP
+		p2.To.Type = obj.TYPE_MEM
+		p2.To.Reg = r0
+		p2.RegTo2 = ppc64.REGTMP
+		p3 := s.Prog(ppc64.ABNE)
+		p3.To.Type = obj.TYPE_BRANCH
+		gc.Patch(p3, p)
+		pisync := s.Prog(ppc64.AISYNC)
+		pisync.To.Type = obj.TYPE_NONE
+
+	case ssa.OpPPC64LoweredAtomicAdd32,
+		ssa.OpPPC64LoweredAtomicAdd64:
+		// SYNC
+		// LDAR/LWAR    (Rarg0), Rout
+		// ADD		Rarg1, Rout
+		// STDCCC/STWCCC Rout, (Rarg0)
+		// BNE         -3(PC)
+		// ISYNC
+		// MOVW		Rout,Rout (if Add32)
+		ld := ppc64.ALDAR
+		st := ppc64.ASTDCCC
+		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
+			ld = ppc64.ALWAR
+			st = ppc64.ASTWCCC
+		}
+		r0 := v.Args[0].Reg()
+		r1 := v.Args[1].Reg()
+		out := v.Reg0()
+		// SYNC
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		// LDAR or LWAR
+		p := s.Prog(ld)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r0
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = out
+		// ADD reg1,out
+		p1 := s.Prog(ppc64.AADD)
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = r1
+		p1.To.Reg = out
+		p1.To.Type = obj.TYPE_REG
+		// STDCCC or STWCCC
+		p3 := s.Prog(st)
+		p3.From.Type = obj.TYPE_REG
+		p3.From.Reg = out
+		p3.To.Type = obj.TYPE_MEM
+		p3.To.Reg = r0
+		// BNE retry
+		p4 := s.Prog(ppc64.ABNE)
+		p4.To.Type = obj.TYPE_BRANCH
+		gc.Patch(p4, p)
+		// ISYNC
+		pisync := s.Prog(ppc64.AISYNC)
+		pisync.To.Type = obj.TYPE_NONE
+
+		// Ensure a 32 bit result
+		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
+			p5 := s.Prog(ppc64.AMOVWZ)
+			p5.To.Type = obj.TYPE_REG
+			p5.To.Reg = out
+			p5.From.Type = obj.TYPE_REG
+			p5.From.Reg = out
+		}
+
+	case ssa.OpPPC64LoweredAtomicExchange32,
+		ssa.OpPPC64LoweredAtomicExchange64:
+		// SYNC
+		// LDAR/LWAR    (Rarg0), Rout
+		// STDCCC/STWCCC Rout, (Rarg0)
+		// BNE         -2(PC)
+		// ISYNC
+		ld := ppc64.ALDAR
+		st := ppc64.ASTDCCC
+		if v.Op == ssa.OpPPC64LoweredAtomicExchange32 {
+			ld = ppc64.ALWAR
+			st = ppc64.ASTWCCC
+		}
+		r0 := v.Args[0].Reg()
+		r1 := v.Args[1].Reg()
+		out := v.Reg0()
+		// SYNC
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		// LDAR or LWAR
+		p := s.Prog(ld)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r0
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = out
+		// STDCCC or STWCCC
+		p1 := s.Prog(st)
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = r1
+		p1.To.Type = obj.TYPE_MEM
+		p1.To.Reg = r0
+		// BNE retry
+		p2 := s.Prog(ppc64.ABNE)
+		p2.To.Type = obj.TYPE_BRANCH
+		gc.Patch(p2, p)
+		// ISYNC
+		pisync := s.Prog(ppc64.AISYNC)
+		pisync.To.Type = obj.TYPE_NONE
+
+	case ssa.OpPPC64LoweredAtomicLoad32,
+		ssa.OpPPC64LoweredAtomicLoad64,
+		ssa.OpPPC64LoweredAtomicLoadPtr:
+		// SYNC
+		// MOVD/MOVW (Rarg0), Rout
+		// CMP Rout,Rout
+		// BNE 1(PC)
+		// ISYNC
+		ld := ppc64.AMOVD
+		cmp := ppc64.ACMP
+		if v.Op == ssa.OpPPC64LoweredAtomicLoad32 {
+			ld = ppc64.AMOVW
+			cmp = ppc64.ACMPW
+		}
+		arg0 := v.Args[0].Reg()
+		out := v.Reg0()
+		// SYNC
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		// Load
+		p := s.Prog(ld)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = arg0
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = out
+		// CMP
+		p1 := s.Prog(cmp)
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = out
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = out
+		// BNE
+		p2 := s.Prog(ppc64.ABNE)
+		p2.To.Type = obj.TYPE_BRANCH
+		// ISYNC
+		pisync := s.Prog(ppc64.AISYNC)
+		pisync.To.Type = obj.TYPE_NONE
+		gc.Patch(p2, pisync)
+
+	case ssa.OpPPC64LoweredAtomicStore32,
+		ssa.OpPPC64LoweredAtomicStore64:
+		// SYNC
+		// MOVD/MOVW arg1,(arg0)
+		st := ppc64.AMOVD
+		if v.Op == ssa.OpPPC64LoweredAtomicStore32 {
+			st = ppc64.AMOVW
+		}
+		arg0 := v.Args[0].Reg()
+		arg1 := v.Args[1].Reg()
+		// SYNC
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		// Store
+		p := s.Prog(st)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = arg0
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = arg1
+
+	case ssa.OpPPC64LoweredAtomicCas64,
+		ssa.OpPPC64LoweredAtomicCas32:
+		// SYNC
+		// loop:
+		// LDAR        (Rarg0), Rtmp
+		// CMP         Rarg1, Rtmp
+		// BNE         fail
+		// STDCCC      Rarg2, (Rarg0)
+		// BNE         loop
+		// ISYNC
+		// MOVD        $1, Rout
+		// BR          end
+		// fail:
+		// MOVD        $0, Rout
+		// end:
+		ld := ppc64.ALDAR
+		st := ppc64.ASTDCCC
+		cmp := ppc64.ACMP
+		if v.Op == ssa.OpPPC64LoweredAtomicCas32 {
+			ld = ppc64.ALWAR
+			st = ppc64.ASTWCCC
+			cmp = ppc64.ACMPW
+		}
+		r0 := v.Args[0].Reg()
+		r1 := v.Args[1].Reg()
+		r2 := v.Args[2].Reg()
+		out := v.Reg0()
+		// SYNC
+		psync := s.Prog(ppc64.ASYNC)
+		psync.To.Type = obj.TYPE_NONE
+		// LDAR or LWAR
+		p := s.Prog(ld)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r0
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = ppc64.REGTMP
+		// CMP reg1,reg2
+		p1 := s.Prog(cmp)
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = r1
+		p1.To.Reg = ppc64.REGTMP
+		p1.To.Type = obj.TYPE_REG
+		// BNE cas_fail
+		p2 := s.Prog(ppc64.ABNE)
+		p2.To.Type = obj.TYPE_BRANCH
+		// STDCCC or STWCCC
+		p3 := s.Prog(st)
+		p3.From.Type = obj.TYPE_REG
+		p3.From.Reg = r2
+		p3.To.Type = obj.TYPE_MEM
+		p3.To.Reg = r0
+		// BNE retry
+		p4 := s.Prog(ppc64.ABNE)
+		p4.To.Type = obj.TYPE_BRANCH
+		gc.Patch(p4, p)
+		// ISYNC
+		pisync := s.Prog(ppc64.AISYNC)
+		pisync.To.Type = obj.TYPE_NONE
+		// return true
+		p5 := s.Prog(ppc64.AMOVD)
+		p5.From.Type = obj.TYPE_CONST
+		p5.From.Offset = 1
+		p5.To.Type = obj.TYPE_REG
+		p5.To.Reg = out
+		// BR done
+		p6 := s.Prog(obj.AJMP)
+		p6.To.Type = obj.TYPE_BRANCH
+		// return false
+		p7 := s.Prog(ppc64.AMOVD)
+		p7.From.Type = obj.TYPE_CONST
+		p7.From.Offset = 0
+		p7.To.Type = obj.TYPE_REG
+		p7.To.Reg = out
+		gc.Patch(p2, p7)
+		// done (label)
+		p8 := s.Prog(obj.ANOP)
+		gc.Patch(p6, p8)
+
 	case ssa.OpPPC64LoweredGetClosurePtr:
 		// Closure pointer is R11 (already)
 		gc.CheckLoweredGetClosurePtr(v)
 
+	case ssa.OpPPC64LoweredRound32F, ssa.OpPPC64LoweredRound64F:
+		// input is already rounded
+
 	case ssa.OpLoadReg:
 		loadOp := loadByType(v.Type)
-		p := gc.Prog(loadOp)
+		p := s.Prog(loadOp)
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 	case ssa.OpStoreReg:
 		storeOp := storeByType(v.Type)
-		p := gc.Prog(storeOp)
+		p := s.Prog(storeOp)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
@@ -231,33 +475,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r0 := v.Args[0].Reg()
 		r1 := v.Args[1].Reg()
 
-		p := gc.Prog(ppc64.ACMP)
+		p := s.Prog(ppc64.ACMP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r1
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = -1
 
-		pbahead := gc.Prog(ppc64.ABEQ)
+		pbahead := s.Prog(ppc64.ABEQ)
 		pbahead.To.Type = obj.TYPE_BRANCH
 
-		p = gc.Prog(v.Op.Asm())
+		p = s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r1
 		p.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 
-		pbover := gc.Prog(obj.AJMP)
+		pbover := s.Prog(obj.AJMP)
 		pbover.To.Type = obj.TYPE_BRANCH
 
-		p = gc.Prog(ppc64.ANEG)
+		p = s.Prog(ppc64.ANEG)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r0
 		gc.Patch(pbahead, p)
 
-		p = gc.Prog(obj.ANOP)
+		p = s.Prog(obj.ANOP)
 		gc.Patch(pbover, p)
 
 	case ssa.OpPPC64DIVW:
@@ -266,33 +510,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r0 := v.Args[0].Reg()
 		r1 := v.Args[1].Reg()
 
-		p := gc.Prog(ppc64.ACMPW)
+		p := s.Prog(ppc64.ACMPW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r1
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = -1
 
-		pbahead := gc.Prog(ppc64.ABEQ)
+		pbahead := s.Prog(ppc64.ABEQ)
 		pbahead.To.Type = obj.TYPE_BRANCH
 
-		p = gc.Prog(v.Op.Asm())
+		p = s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r1
 		p.Reg = r0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 
-		pbover := gc.Prog(obj.AJMP)
+		pbover := s.Prog(obj.AJMP)
 		pbover.To.Type = obj.TYPE_BRANCH
 
-		p = gc.Prog(ppc64.ANEG)
+		p = s.Prog(ppc64.ANEG)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r0
 		gc.Patch(pbahead, p)
 
-		p = gc.Prog(obj.ANOP)
+		p = s.Prog(obj.ANOP)
 		gc.Patch(pbover, p)
 
 	case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS,
@@ -300,20 +544,44 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpPPC64SRAD, ssa.OpPPC64SRAW, ssa.OpPPC64SRD, ssa.OpPPC64SRW, ssa.OpPPC64SLD, ssa.OpPPC64SLW,
 		ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
 		ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS,
-		ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
+		ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r2
 		p.Reg = r1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 
+	case ssa.OpPPC64ROTLconst, ssa.OpPPC64ROTLWconst:
+		p := s.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.Reg = v.Args[0].Reg()
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = v.Reg()
+
+	case ssa.OpPPC64FMADD, ssa.OpPPC64FMADDS, ssa.OpPPC64FMSUB, ssa.OpPPC64FMSUBS:
+		r := v.Reg()
+		r1 := v.Args[0].Reg()
+		r2 := v.Args[1].Reg()
+		r3 := v.Args[2].Reg()
+		// r = r1*r2 ± r3
+		p := s.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = r1
+		p.Reg = r3
+		p.From3 = new(obj.Addr)
+		p.From3.Type = obj.TYPE_REG
+		p.From3.Reg = r2
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+
 	case ssa.OpPPC64MaskIfNotCarry:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = ppc64.REGZERO
 		p.To.Type = obj.TYPE_REG
@@ -321,16 +589,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 	case ssa.OpPPC64ADDconstForCarry:
 		r1 := v.Args[0].Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Reg = r1
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect.
 
-	case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP:
+	case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP, ssa.OpPPC64CNTLZD, ssa.OpPPC64CNTLZW, ssa.OpPPC64POPCNTD, ssa.OpPPC64POPCNTW, ssa.OpPPC64POPCNTB:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 		p.From.Type = obj.TYPE_REG
@@ -338,7 +606,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 	case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
 		ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Reg = v.Args[0].Reg()
 
 		if v.Aux != nil {
@@ -353,7 +621,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 
 	case ssa.OpPPC64ANDCCconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Reg = v.Args[0].Reg()
 
 		if v.Aux != nil {
@@ -368,7 +636,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = ppc64.REGTMP // discard result
 
 	case ssa.OpPPC64MOVDaddr:
-		p := gc.Prog(ppc64.AMOVD)
+		p := s.Prog(ppc64.AMOVD)
 		p.From.Type = obj.TYPE_ADDR
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -400,28 +668,28 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		}
 
 	case ssa.OpPPC64MOVDconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 	case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.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 = v.Reg()
 
 	case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Args[1].Reg()
 
 	case ssa.OpPPC64CMPconst, ssa.OpPPC64CMPUconst, ssa.OpPPC64CMPWconst, ssa.OpPPC64CMPWUconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_CONST
@@ -429,14 +697,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 	case ssa.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg:
 		// Shift in register to required size
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Reg = v.Reg()
 		p.To.Type = obj.TYPE_REG
 
 	case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -444,7 +712,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 
 	case ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -452,7 +720,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 
 	case ssa.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = ppc64.REGZERO
 		p.To.Type = obj.TYPE_MEM
@@ -460,14 +728,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		gc.AddAux(&p.To, v)
 
 	case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -492,243 +760,329 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		//   rtmp := 1
 		//   isel rt,0,rtmp,!cond // rt is target in ppc asm
 
-		if v.Block.Func.Config.OldArch {
-			p := gc.Prog(ppc64.AMOVD)
-			p.From.Type = obj.TYPE_CONST
-			p.From.Offset = 1
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = v.Reg()
-
-			pb := gc.Prog(condOps[v.Op])
-			pb.To.Type = obj.TYPE_BRANCH
-
-			p = gc.Prog(ppc64.AMOVD)
-			p.From.Type = obj.TYPE_CONST
-			p.From.Offset = 0
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = v.Reg()
-
-			p = gc.Prog(obj.ANOP)
-			gc.Patch(pb, p)
-			break
-		}
-		// Modern PPC uses ISEL
-		p := gc.Prog(ppc64.AMOVD)
+		p := s.Prog(ppc64.AMOVD)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = iselRegs[1]
 		iop := iselOps[v.Op]
-		ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
+		ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
 
 	case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
 		ssa.OpPPC64FGreaterEqual:
 
-		if v.Block.Func.Config.OldArch {
-			p := gc.Prog(ppc64.AMOVW)
-			p.From.Type = obj.TYPE_CONST
-			p.From.Offset = 1
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = v.Reg()
-
-			pb0 := gc.Prog(condOps[v.Op])
-			pb0.To.Type = obj.TYPE_BRANCH
-			pb1 := gc.Prog(ppc64.ABEQ)
-			pb1.To.Type = obj.TYPE_BRANCH
-
-			p = gc.Prog(ppc64.AMOVW)
-			p.From.Type = obj.TYPE_CONST
-			p.From.Offset = 0
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = v.Reg()
-
-			p = gc.Prog(obj.ANOP)
-			gc.Patch(pb0, p)
-			gc.Patch(pb1, p)
-			break
-		}
-		// Modern PPC uses ISEL
-		p := gc.Prog(ppc64.AMOVD)
+		p := s.Prog(ppc64.AMOVD)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = iselRegs[1]
 		iop := iselOps[v.Op]
-		ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
-		ssaGenISEL(v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
+		ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
+		ssaGenISEL(s, v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
 
 	case ssa.OpPPC64LoweredZero:
-		// Similar to how this is done on ARM,
-		// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off
-		// not store-and-increment.
-		// Therefore R3 should be dest-align
-		// and arg1 should be dest+size-align
-		// HOWEVER, the input dest address cannot be dest-align because
-		// that does not necessarily address valid memory and it's not
-		// known how that might be optimized.  Therefore, correct it in
-		// in the expansion:
-		//
-		// ADD    -8,R3,R3
-		// MOVDU  R0, 8(R3)
-		// CMP	  R3, Rarg1
-		// BL	  -2(PC)
-		// arg1 is the address of the last element to zero
-		// auxint is alignment
-		var sz int64
-		var movu obj.As
-		switch {
-		case v.AuxInt%8 == 0:
-			sz = 8
-			movu = ppc64.AMOVDU
-		case v.AuxInt%4 == 0:
-			sz = 4
-			movu = ppc64.AMOVWZU // MOVWU instruction not implemented
-		case v.AuxInt%2 == 0:
-			sz = 2
-			movu = ppc64.AMOVHU
-		default:
-			sz = 1
-			movu = ppc64.AMOVBU
-		}
 
-		p := gc.Prog(ppc64.AADD)
-		p.Reg = v.Args[0].Reg()
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = -sz
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
+		// unaligned data doesn't hurt performance
+		// for these instructions on power8 or later
+
+		// for sizes >= 64 generate a loop as follows:
+
+		// set up loop counter in CTR, used by BC
+		//	 MOVD len/32,REG_TMP
+		//	 MOVD REG_TMP,CTR
+		//	 loop:
+		//	 MOVD R0,(R3)
+		//	 MOVD R0,8(R3)
+		//	 MOVD R0,16(R3)
+		//	 MOVD R0,24(R3)
+		//	 ADD  $32,R3
+		//	 BC   16, 0, loop
+		//
+		// any remainder is done as described below
 
-		p = gc.Prog(movu)
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = ppc64.REG_R0
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = v.Args[0].Reg()
-		p.To.Offset = sz
+		// for sizes < 64 bytes, first clear as many doublewords as possible,
+		// then handle the remainder
+		//	MOVD R0,(R3)
+		//	MOVD R0,8(R3)
+		// .... etc.
+		//
+		// the remainder bytes are cleared using one or more
+		// of the following instructions with the appropriate
+		// offsets depending which instructions are needed
+		//
+		//	MOVW R0,n1(R3)	4 bytes
+		//	MOVH R0,n2(R3)	2 bytes
+		//	MOVB R0,n3(R3)	1 byte
+		//
+		// 7 bytes: MOVW, MOVH, MOVB
+		// 6 bytes: MOVW, MOVH
+		// 5 bytes: MOVW, MOVB
+		// 3 bytes: MOVH, MOVB
+
+		// each loop iteration does 32 bytes
+		ctr := v.AuxInt / 32
+
+		// remainder bytes
+		rem := v.AuxInt % 32
+
+		// only generate a loop if there is more
+		// than 1 iteration.
+		if ctr > 1 {
+			// Set up CTR loop counter
+			p := s.Prog(ppc64.AMOVD)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = ctr
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REGTMP
 
-		p2 := gc.Prog(ppc64.ACMPU)
-		p2.From.Type = obj.TYPE_REG
-		p2.From.Reg = v.Args[0].Reg()
-		p2.To.Reg = v.Args[1].Reg()
-		p2.To.Type = obj.TYPE_REG
+			p = s.Prog(ppc64.AMOVD)
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = ppc64.REGTMP
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REG_CTR
+
+			// generate 4 MOVDs
+			// when this is a loop then the top must be saved
+			var top *obj.Prog
+			for offset := int64(0); offset < 32; offset += 8 {
+				// This is the top of loop
+				p := s.Prog(ppc64.AMOVD)
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = ppc64.REG_R0
+				p.To.Type = obj.TYPE_MEM
+				p.To.Reg = v.Args[0].Reg()
+				p.To.Offset = offset
+				// Save the top of loop
+				if top == nil {
+					top = p
+				}
+			}
 
-		p3 := gc.Prog(ppc64.ABLT)
-		p3.To.Type = obj.TYPE_BRANCH
-		gc.Patch(p3, p)
+			// Increment address for the
+			// 4 doublewords just zeroed.
+			p = s.Prog(ppc64.AADD)
+			p.Reg = v.Args[0].Reg()
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 32
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = v.Args[0].Reg()
 
-	case ssa.OpPPC64LoweredMove:
-		// Similar to how this is done on ARM,
-		// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off,
-		// not store-and-increment.
-		// Inputs must be valid pointers to memory,
-		// so adjust arg0 and arg1 as part of the expansion.
-		// arg2 should be src+size-align,
-		//
-		// ADD    -8,R3,R3
-		// ADD    -8,R4,R4
-		// MOVDU	8(R4), Rtmp
-		// MOVDU 	Rtmp, 8(R3)
-		// CMP	R4, Rarg2
-		// BL	-3(PC)
-		// arg2 is the address of the last element of src
-		// auxint is alignment
-		var sz int64
-		var movu obj.As
-		switch {
-		case v.AuxInt%8 == 0:
-			sz = 8
-			movu = ppc64.AMOVDU
-		case v.AuxInt%4 == 0:
-			sz = 4
-			movu = ppc64.AMOVWZU // MOVWU instruction not implemented
-		case v.AuxInt%2 == 0:
-			sz = 2
-			movu = ppc64.AMOVHU
-		default:
-			sz = 1
-			movu = ppc64.AMOVBU
+			// Branch back to top of loop
+			// based on CTR
+			// BC with BO_BCTR generates bdnz
+			p = s.Prog(ppc64.ABC)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = ppc64.BO_BCTR
+			p.Reg = ppc64.REG_R0
+			p.To.Type = obj.TYPE_BRANCH
+			gc.Patch(p, top)
 		}
 
-		p := gc.Prog(ppc64.AADD)
-		p.Reg = v.Args[0].Reg()
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = -sz
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
-
-		p = gc.Prog(ppc64.AADD)
-		p.Reg = v.Args[1].Reg()
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = -sz
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[1].Reg()
+		// when ctr == 1 the loop was not generated but
+		// there are at least 32 bytes to clear, so add
+		// that to the remainder to generate the code
+		// to clear those doublewords
+		if ctr == 1 {
+			rem += 32
+		}
 
-		p = gc.Prog(movu)
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = v.Args[1].Reg()
-		p.From.Offset = sz
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = ppc64.REGTMP
+		// clear the remainder starting at offset zero
+		offset := int64(0)
+
+		// first clear as many doublewords as possible
+		// then clear remaining sizes as available
+		for rem > 0 {
+			op, size := ppc64.AMOVB, int64(1)
+			switch {
+			case rem >= 8:
+				op, size = ppc64.AMOVD, 8
+			case rem >= 4:
+				op, size = ppc64.AMOVW, 4
+			case rem >= 2:
+				op, size = ppc64.AMOVH, 2
+			}
+			p := s.Prog(op)
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = ppc64.REG_R0
+			p.To.Type = obj.TYPE_MEM
+			p.To.Reg = v.Args[0].Reg()
+			p.To.Offset = offset
+			rem -= size
+			offset += size
+		}
 
-		p2 := gc.Prog(movu)
-		p2.From.Type = obj.TYPE_REG
-		p2.From.Reg = ppc64.REGTMP
-		p2.To.Type = obj.TYPE_MEM
-		p2.To.Reg = v.Args[0].Reg()
-		p2.To.Offset = sz
+	case ssa.OpPPC64LoweredMove:
 
-		p3 := gc.Prog(ppc64.ACMPU)
-		p3.From.Reg = v.Args[1].Reg()
-		p3.From.Type = obj.TYPE_REG
-		p3.To.Reg = v.Args[2].Reg()
-		p3.To.Type = obj.TYPE_REG
+		// This will be used when moving more
+		// than 8 bytes.  Moves start with as
+		// as many 8 byte moves as possible, then
+		// 4, 2, or 1 byte(s) as remaining.  This will
+		// work and be efficient for power8 or later.
+		// If there are 64 or more bytes, then a
+		// loop is generated to move 32 bytes and
+		// update the src and dst addresses on each
+		// iteration. When < 64 bytes, the appropriate
+		// number of moves are generated based on the
+		// size.
+		// When moving >= 64 bytes a loop is used
+		//	MOVD len/32,REG_TMP
+		//	MOVD REG_TMP,CTR
+		// top:
+		//	MOVD (R4),R7
+		//	MOVD 8(R4),R8
+		//	MOVD 16(R4),R9
+		//	MOVD 24(R4),R10
+		//	ADD  R4,$32
+		//	MOVD R7,(R3)
+		//	MOVD R8,8(R3)
+		//	MOVD R9,16(R3)
+		//	MOVD R10,24(R3)
+		//	ADD  R3,$32
+		//	BC 16,0,top
+		// Bytes not moved by this loop are moved
+		// with a combination of the following instructions,
+		// starting with the largest sizes and generating as
+		// many as needed, using the appropriate offset value.
+		//	MOVD  n(R4),R7
+		//	MOVD  R7,n(R3)
+		//	MOVW  n1(R4),R7
+		//	MOVW  R7,n1(R3)
+		//	MOVH  n2(R4),R7
+		//	MOVH  R7,n2(R3)
+		//	MOVB  n3(R4),R7
+		//	MOVB  R7,n3(R3)
+
+		// Each loop iteration moves 32 bytes
+		ctr := v.AuxInt / 32
+
+		// Remainder after the loop
+		rem := v.AuxInt % 32
+
+		dst_reg := v.Args[0].Reg()
+		src_reg := v.Args[1].Reg()
+
+		// The set of registers used here, must match the clobbered reg list
+		// in PPC64Ops.go.
+		useregs := []int16{ppc64.REG_R7, ppc64.REG_R8, ppc64.REG_R9, ppc64.REG_R10}
+		offset := int64(0)
+
+		// top of the loop
+		var top *obj.Prog
+		// Only generate looping code when loop counter is > 1 for >= 64 bytes
+		if ctr > 1 {
+			// Set up the CTR
+			p := s.Prog(ppc64.AMOVD)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = ctr
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REGTMP
 
-		p4 := gc.Prog(ppc64.ABLT)
-		p4.To.Type = obj.TYPE_BRANCH
-		gc.Patch(p4, p)
+			p = s.Prog(ppc64.AMOVD)
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = ppc64.REGTMP
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REG_CTR
 
-	case ssa.OpPPC64CALLstatic:
-		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 two actual hardware NOPs 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.
-			// PPC64 is unusual because TWO nops are required
-			// (see gc/cgen.go, gc/plive.go -- copy of comment below)
-			//
-			// On ppc64, when compiling Go into position
-			// independent code on ppc64le we insert an
-			// instruction to reload the TOC pointer from the
-			// stack as well. See the long comment near
-			// jmpdefer in runtime/asm_ppc64.s for why.
-			// 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.
-			ginsnop()
-			if gc.Ctxt.Flag_shared {
-				p := gc.Prog(ppc64.AMOVD)
+			// Generate all the MOVDs for loads
+			// based off the same register, increasing
+			// the offset by 8 for each instruction
+			for _, rg := range useregs {
+				p := s.Prog(ppc64.AMOVD)
 				p.From.Type = obj.TYPE_MEM
-				p.From.Offset = 24
-				p.From.Reg = ppc64.REGSP
+				p.From.Reg = src_reg
+				p.From.Offset = offset
 				p.To.Type = obj.TYPE_REG
-				p.To.Reg = ppc64.REG_R2
-			} else {
-				ginsnop()
+				p.To.Reg = rg
+				if top == nil {
+					top = p
+				}
+				offset += 8
+			}
+			// increment the src_reg for next iteration
+			p = s.Prog(ppc64.AADD)
+			p.Reg = src_reg
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 32
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = src_reg
+
+			// generate the MOVDs for stores, based
+			// off the same register, using the same
+			// offsets as in the loads.
+			offset = int64(0)
+			for _, rg := range useregs {
+				p := s.Prog(ppc64.AMOVD)
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = rg
+				p.To.Type = obj.TYPE_MEM
+				p.To.Reg = dst_reg
+				p.To.Offset = offset
+				offset += 8
 			}
+			// increment the dst_reg for next iteration
+			p = s.Prog(ppc64.AADD)
+			p.Reg = dst_reg
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 32
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = dst_reg
+
+			// BC with BO_BCTR generates bdnz to branch on nonzero CTR
+			// to loop top.
+			p = s.Prog(ppc64.ABC)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = ppc64.BO_BCTR
+			p.Reg = ppc64.REG_R0
+			p.To.Type = obj.TYPE_BRANCH
+			gc.Patch(p, top)
+
+			// src_reg and dst_reg were incremented in the loop, so
+			// later instructions start with offset 0.
+			offset = int64(0)
 		}
-		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
+
+		// No loop was generated for one iteration, so
+		// add 32 bytes to the remainder to move those bytes.
+		if ctr == 1 {
+			rem += 32
 		}
 
+		// Generate all the remaining load and store pairs, starting with
+		// as many 8 byte moves as possible, then 4, 2, 1.
+		for rem > 0 {
+			op, size := ppc64.AMOVB, int64(1)
+			switch {
+			case rem >= 8:
+				op, size = ppc64.AMOVD, 8
+			case rem >= 4:
+				op, size = ppc64.AMOVW, 4
+			case rem >= 2:
+				op, size = ppc64.AMOVH, 2
+			}
+			// Load
+			p := s.Prog(op)
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REG_R7
+			p.From.Type = obj.TYPE_MEM
+			p.From.Reg = src_reg
+			p.From.Offset = offset
+
+			// Store
+			p = s.Prog(op)
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = ppc64.REG_R7
+			p.To.Type = obj.TYPE_MEM
+			p.To.Reg = dst_reg
+			p.To.Offset = offset
+			rem -= size
+			offset += size
+		}
+
+	case ssa.OpPPC64CALLstatic:
+		s.Call(v)
+
 	case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
-		p := gc.Prog(ppc64.AMOVD)
+		p := s.Prog(ppc64.AMOVD)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
@@ -741,14 +1095,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			// change the register allocation to put the value in
 			// R12 already, but I don't know how to do that.
 			// TODO: We have the technology now to implement TODO above.
-			q := gc.Prog(ppc64.AMOVD)
+			q := s.Prog(ppc64.AMOVD)
 			q.From = p.From
 			q.To.Type = obj.TYPE_REG
 			q.To.Reg = ppc64.REG_R12
 		}
 
-		pp := gc.Prog(obj.ACALL)
-		pp.To.Type = obj.TYPE_REG
+		pp := s.Call(v)
 		pp.To.Reg = ppc64.REG_CTR
 
 		if gc.Ctxt.Flag_shared {
@@ -756,7 +1109,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			// called via pointer might have been implemented in
 			// a separate module and so overwritten the TOC
 			// pointer in R2; reload it.
-			q := gc.Prog(ppc64.AMOVD)
+			q := s.Prog(ppc64.AMOVD)
 			q.From.Type = obj.TYPE_MEM
 			q.From.Offset = 24
 			q.From.Reg = ppc64.REGSP
@@ -764,54 +1117,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			q.To.Reg = ppc64.REG_R2
 		}
 
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-
-	case ssa.OpPPC64CALLdefer:
-		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.OpPPC64CALLgo:
-		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.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:
-		gc.KeepAlive(v)
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
-
 	case ssa.OpPPC64LoweredNilCheck:
 		// Issue a load which will fault if arg is nil.
-		p := gc.Prog(ppc64.AMOVBZ)
+		p := s.Prog(ppc64.AMOVBZ)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = ppc64.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 
 	case ssa.OpPPC64InvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
 	case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT:
 		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
-
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -837,44 +1160,41 @@ var blockJump = [...]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
-
 	case ssa.BlockDefer:
 		// defer returns in R3:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(ppc64.ACMP)
+		p := s.Prog(ppc64.ACMP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = ppc64.REG_R3
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = ppc64.REG_R0
 
-		p = gc.Prog(ppc64.ABNE)
+		p = s.Prog(ppc64.ABNE)
 		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 := s.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.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.AJMP)
+		p := s.Prog(obj.AJMP)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 
 	case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
 		ssa.BlockPPC64LT, ssa.BlockPPC64GE,
@@ -882,56 +1202,41 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		ssa.BlockPPC64FLT, ssa.BlockPPC64FGE,
 		ssa.BlockPPC64FLE, ssa.BlockPPC64FGT:
 		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 = s.Prog(jmp.invasm)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
 			if jmp.invasmun {
 				// TODO: The second branch is probably predict-not-taken since it is for FP unordered
-				q := gc.Prog(ppc64.ABVS)
+				q := s.Prog(ppc64.ABVS)
 				q.To.Type = obj.TYPE_BRANCH
 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 			}
 		case b.Succs[1].Block():
-			p = gc.Prog(jmp.asm)
+			p = s.Prog(jmp.asm)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 			if jmp.asmeq {
-				q := gc.Prog(ppc64.ABEQ)
+				q := s.Prog(ppc64.ABEQ)
 				q.To.Type = obj.TYPE_BRANCH
 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
 			}
 		default:
-			p = gc.Prog(jmp.asm)
+			p = s.Prog(jmp.asm)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 			if jmp.asmeq {
-				q := gc.Prog(ppc64.ABEQ)
+				q := s.Prog(ppc64.ABEQ)
 				q.To.Type = obj.TYPE_BRANCH
 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
 			}
-			q := gc.Prog(obj.AJMP)
+			q := s.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.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
 	}
diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go
index 9424d20..3f62469 100644
--- a/src/cmd/compile/internal/s390x/galign.go
+++ b/src/cmd/compile/internal/s390x/galign.go
@@ -9,16 +9,16 @@ import (
 	"cmd/internal/obj/s390x"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &s390x.Links390x
-	gc.Thearch.REGSP = s390x.REGSP
-	gc.Thearch.MAXWIDTH = 1 << 50
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &s390x.Links390x
+	arch.REGSP = s390x.REGSP
+	arch.MAXWIDTH = 1 << 50
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = ssaMarkMoves
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = ssaMarkMoves
+	arch.SSAGenValue = ssaGenValue
+	arch.SSAGenBlock = ssaGenBlock
 }
diff --git a/src/cmd/compile/internal/s390x/ggen.go b/src/cmd/compile/internal/s390x/ggen.go
index 5ecfaa5..636ab16 100644
--- a/src/cmd/compile/internal/s390x/ggen.go
+++ b/src/cmd/compile/internal/s390x/ggen.go
@@ -16,90 +16,37 @@ import (
 // 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 %L has size %d offset %d", n, 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
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 
 	// Adjust the frame to account for LR.
-	frame += gc.Ctxt.FixedFrameSize()
-	offset := frame + lo
+	off += gc.Ctxt.FixedFrameSize()
 	reg := int16(s390x.REGSP)
 
-	// If the offset cannot fit in a 12-bit unsigned displacement then we
+	// If the off 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 = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
+	if off < 0 || off > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
+		p = pp.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, off, obj.TYPE_REG, s390x.REGRT1, 0)
 		p.Reg = int16(s390x.REGSP)
 		reg = s390x.REGRT1
-		offset = 0
+		off = 0
 	}
 
 	// Generate a loop of large clears.
 	if cnt > clearLoopCutoff {
 		n := cnt - (cnt % 256)
 		end := int16(s390x.REGRT2)
-		p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
+		p = pp.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, off+n, obj.TYPE_REG, end, 0)
 		p.Reg = reg
-		p = gc.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
+		p = pp.Appendpp(p, s390x.ACLEAR, obj.TYPE_CONST, 0, 256, obj.TYPE_MEM, reg, off)
 		pl := p
-		p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
-		p = gc.Appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
-		p = gc.Appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		p = pp.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
+		p = pp.Appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
+		p = pp.Appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
 		gc.Patch(p, pl)
 
 		cnt -= n
@@ -126,38 +73,39 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 			case 2:
 				ins = s390x.AMOVH
 			}
-			p = gc.Appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
+			p = pp.Appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, off)
 
-		// Handle clears that would require multiple move instructions with XC.
+		// Handle clears that would require multiple move instructions with CLEAR (assembled as XC).
 		default:
-			p = gc.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
+			p = pp.Appendpp(p, s390x.ACLEAR, obj.TYPE_CONST, 0, n, obj.TYPE_MEM, reg, off)
 		}
 
 		cnt -= n
-		offset += n
+		off += n
 	}
 
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
-	// Note: this code must not clobber any registers.
-	p := gc.AddAsmAfter(s390x.ACLEAR, pp)
-	pp = p
-	p.From.Type = obj.TYPE_CONST
-	p.From.Offset = n.Type.Size()
-	p.To.Type = obj.TYPE_MEM
-	p.To.Name = obj.NAME_AUTO
-	p.To.Reg = s390x.REGSP
-	p.To.Offset = n.Xoffset
-	p.To.Sym = gc.Linksym(n.Sym)
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
+	// Note: this code must not clobber any registers or the
+	// condition code.
+	sym := n.Sym.Linksym()
+	size := n.Type.Size()
+	for i := int64(0); i < size; i += int64(gc.Widthptr) {
+		p := pp.Prog(s390x.AMOVD)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 0
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_AUTO
+		p.To.Reg = s390x.REGSP
+		p.To.Offset = n.Xoffset + i
+		p.To.Sym = sym
+	}
 }
 
-func ginsnop() {
-	p := gc.Prog(s390x.AOR)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(s390x.AOR)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = int16(s390x.REG_R0)
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/s390x/prog.go b/src/cmd/compile/internal/s390x/prog.go
deleted file mode 100644
index f356617..0000000
--- a/src/cmd/compile/internal/s390x/prog.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2016 The Go Authors. 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]gc.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.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.ASUBE & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AADDW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASUBW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ANEG & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ANEGW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AAND & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AANDW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AOR & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AORW & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AXOR & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AXORW & obj.AMask:   {Flags: gc.SizeL | 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.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AMULHDU & obj.AMask: {Flags: gc.SizeQ | 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.ADIVW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ADIVWU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASLD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASLW & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASRD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASRW & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASRAD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.ASRAW & obj.AMask:   {Flags: gc.SizeL | 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},
-	s390x.ACMPW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	s390x.ACMPWU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	s390x.AMODD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AMODDU & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AMODW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AMODWU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	s390x.AFLOGR & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
-
-	// 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},
-	s390x.AFNEG & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-	s390x.AFNEGS & obj.AMask: {Flags: gc.SizeF | 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.AMOVHBR & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	s390x.AMOVWBR & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	s390x.AMOVDBR & 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},
-	s390x.AMOVDEQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	s390x.AMOVDGE & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	s390x.AMOVDGT & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	s390x.AMOVDLE & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	s390x.AMOVDLT & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	s390x.AMOVDNE & obj.AMask: {Flags: gc.SizeQ | 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.ABLEU & obj.AMask:    {Flags: gc.Cjmp},
-	s390x.ABLTU & 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},
-
-	// Atomic
-	s390x.ACS & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.LeftWrite | gc.RegRead | gc.RightRead | gc.RightWrite},
-	s390x.ACSG & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.LeftWrite | gc.RegRead | gc.RightRead | gc.RightWrite},
-	s390x.ALAA & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.RightWrite},
-	s390x.ALAAG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.RightWrite},
-
-	// 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) gc.ProgInfo {
-	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_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
-		info.Flags &^= gc.LeftRead
-		info.Flags |= gc.LeftAddr
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go
index a9dafa8..8722345 100644
--- a/src/cmd/compile/internal/s390x/ssa.go
+++ b/src/cmd/compile/internal/s390x/ssa.go
@@ -9,6 +9,7 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/s390x"
 )
@@ -37,7 +38,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -73,7 +74,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	width := t.Size()
 	if t.IsFloat() {
 		switch width {
@@ -98,7 +99,7 @@ func storeByType(t ssa.Type) obj.As {
 }
 
 // moveByType returns the reg->reg move instruction of the given type.
-func moveByType(t ssa.Type) obj.As {
+func moveByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		return s390x.AFMOVD
 	} else {
@@ -132,8 +133,8 @@ func moveByType(t ssa.Type) obj.As {
 //     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)
+func opregreg(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog {
+	p := s.Prog(op)
 	p.From.Type = obj.TYPE_REG
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = dest
@@ -145,8 +146,8 @@ func opregreg(op obj.As, dest, src int16) *obj.Prog {
 //	dest := src(From) op off
 // and also returns the created obj.Prog so it
 // may be further adjusted (offset, scale, etc).
-func opregregimm(op obj.As, dest, src int16, off int64) *obj.Prog {
-	p := gc.Prog(op)
+func opregregimm(s *gc.SSAGenState, op obj.As, dest, src int16, off int64) *obj.Prog {
+	p := s.Prog(op)
 	p.From.Type = obj.TYPE_CONST
 	p.From.Offset = off
 	p.Reg = src
@@ -156,7 +157,6 @@ func opregregimm(op obj.As, dest, src int16, off int64) *obj.Prog {
 }
 
 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
-	s.SetLineno(v.Line)
 	switch v.Op {
 	case ssa.OpS390XSLD, ssa.OpS390XSLW,
 		ssa.OpS390XSRD, ssa.OpS390XSRW,
@@ -167,7 +167,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r2 == s390x.REG_R0 {
 			v.Fatalf("cannot use R0 as shift value %s", v.LongString())
 		}
-		p := opregreg(v.Op.Asm(), r, r2)
+		p := opregreg(s, v.Op.Asm(), r, r2)
 		if r != r1 {
 			p.Reg = r1
 		}
@@ -179,7 +179,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r := v.Reg()
 		r1 := v.Args[0].Reg()
 		r2 := v.Args[1].Reg()
-		p := opregreg(v.Op.Asm(), r, r2)
+		p := opregreg(s, v.Op.Asm(), r, r2)
 		if r != r1 {
 			p.Reg = r1
 		}
@@ -192,7 +192,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		opregreg(v.Op.Asm(), r, v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
+	case ssa.OpS390XFMADD, ssa.OpS390XFMADDS,
+		ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS:
+		r := v.Reg()
+		if r != v.Args[0].Reg() {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		r1 := v.Args[1].Reg()
+		r2 := v.Args[2].Reg()
+		p := s.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.OpS390XDIVD, ssa.OpS390XDIVW,
 		ssa.OpS390XDIVDU, ssa.OpS390XDIVWU,
 		ssa.OpS390XMODD, ssa.OpS390XMODW,
@@ -209,8 +223,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW {
 
 			var c *obj.Prog
-			c = gc.Prog(s390x.ACMP)
-			j = gc.Prog(s390x.ABEQ)
+			c = s.Prog(s390x.ACMP)
+			j = s.Prog(s390x.ABEQ)
 
 			c.From.Type = obj.TYPE_REG
 			c.From.Reg = divisor
@@ -221,7 +235,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 		}
 
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = divisor
 		p.Reg = 0
@@ -230,18 +244,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 		// signed division, rest of the check for -1 case
 		if j != nil {
-			j2 := gc.Prog(s390x.ABR)
+			j2 := s.Prog(s390x.ABR)
 			j2.To.Type = obj.TYPE_BRANCH
 
 			var n *obj.Prog
 			if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW {
 				// n * -1 = -n
-				n = gc.Prog(s390x.ANEG)
+				n = s.Prog(s390x.ANEG)
 				n.To.Type = obj.TYPE_REG
 				n.To.Reg = dividend
 			} else {
 				// n % -1 == 0
-				n = gc.Prog(s390x.AXOR)
+				n = s.Prog(s390x.AXOR)
 				n.From.Type = obj.TYPE_REG
 				n.From.Reg = dividend
 				n.To.Type = obj.TYPE_REG
@@ -252,7 +266,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			j2.To.Val = s.Pc()
 		}
 	case ssa.OpS390XADDconst, ssa.OpS390XADDWconst:
-		opregregimm(v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
+		opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
 	case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst,
 		ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst,
 		ssa.OpS390XANDconst, ssa.OpS390XANDWconst,
@@ -262,7 +276,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -271,7 +285,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
 		ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
 		ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		r := v.Reg()
@@ -283,7 +297,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = r
 	case ssa.OpS390XSUBEcarrymask, ssa.OpS390XSUBEWcarrymask:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		p.To.Type = obj.TYPE_REG
@@ -291,7 +305,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpS390XMOVDaddridx:
 		r := v.Args[0].Reg()
 		i := v.Args[1].Reg()
-		p := gc.Prog(s390x.AMOVD)
+		p := s.Prog(s390x.AMOVD)
 		p.From.Scale = 1
 		if i == s390x.REGSP {
 			r, i = i, r
@@ -303,32 +317,32 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpS390XMOVDaddr:
-		p := gc.Prog(s390x.AMOVD)
+		p := s.Prog(s390x.AMOVD)
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU:
-		opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
 	case ssa.OpS390XFCMPS, ssa.OpS390XFCMP:
-		opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
 	case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst, ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = v.AuxInt
 	case ssa.OpS390XMOVDconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.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
 	case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
@@ -343,7 +357,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[1].Reg()
 		gc.AddAux(&p.From, v)
@@ -354,7 +368,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload,
 		ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload,
 		ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -368,7 +382,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == s390x.REGSP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r
 		p.From.Scale = 1
@@ -379,7 +393,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore,
 		ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore,
 		ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -393,7 +407,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == s390x.REGSP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -402,7 +416,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = i
 		gc.AddAux(&p.To, v)
 	case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -415,9 +429,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA,
 		ssa.OpS390XLDEBR, ssa.OpS390XLEDBR,
 		ssa.OpS390XFNEG, ssa.OpS390XFNEGS:
-		opregreg(v.Op.Asm(), v.Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
 	case ssa.OpS390XCLEAR:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -431,7 +445,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		x := v.Args[0].Reg()
 		y := v.Reg()
 		if x != y {
-			opregreg(moveByType(v.Type), y, x)
+			opregreg(s, moveByType(v.Type), y, x)
 		}
 	case ssa.OpS390XMOVDnop:
 		if v.Reg() != v.Args[0].Reg() {
@@ -443,7 +457,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("load flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(loadByType(v.Type))
+		p := s.Prog(loadByType(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -452,78 +466,27 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(storeByType(v.Type))
+		p := s.Prog(storeByType(v.Type))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
-	case ssa.OpInitMem:
-		// memory arg needs no code
-	case ssa.OpArg:
-		// input args need no code
 	case ssa.OpS390XLoweredGetClosurePtr:
 		// Closure pointer is R12 (already)
 		gc.CheckLoweredGetClosurePtr(v)
+	case ssa.OpS390XLoweredRound32F, ssa.OpS390XLoweredRound64F:
+		// input is already rounded
 	case ssa.OpS390XLoweredGetG:
 		r := v.Reg()
-		p := gc.Prog(s390x.AMOVD)
+		p := s.Prog(s390x.AMOVD)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = s390x.REGG
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
-	case ssa.OpS390XCALLstatic:
-		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.OpS390XCALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.OpS390XCALLdefer:
-		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.OpS390XCALLgo:
-		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.OpS390XCALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
+		s.Call(v)
 	case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW,
 		ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
@@ -538,29 +501,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 	case ssa.OpS390XFSQRT:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpSP, ssa.OpSB:
-		// nothing to do
-	case ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
-	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:
-		gc.KeepAlive(v)
 	case ssa.OpS390XInvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
 	case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT:
@@ -569,27 +520,27 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString())
 	case ssa.OpS390XLoweredNilCheck:
 		// Issue a load which will fault if the input is nil.
-		p := gc.Prog(s390x.AMOVBZ)
+		p := s.Prog(s390x.AMOVBZ)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = s390x.REGTMP
-		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
-			gc.Warnl(v.Line, "generated nil check")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 	case ssa.OpS390XMVC:
 		vo := v.AuxValAndOff()
-		p := gc.Prog(s390x.AMVC)
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = v.Args[1].Reg()
-		p.From.Offset = vo.Off()
+		p := s.Prog(s390x.AMVC)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = vo.Val()
+		p.From3 = new(obj.Addr)
+		p.From3.Type = obj.TYPE_MEM
+		p.From3.Reg = v.Args[1].Reg()
+		p.From3.Offset = vo.Off()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		p.To.Offset = vo.Off()
-		p.From3 = new(obj.Addr)
-		p.From3.Type = obj.TYPE_CONST
-		p.From3.Offset = vo.Val()
 	case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4,
 		ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4:
 		for i := 2; i < len(v.Args)-1; i++ {
@@ -597,7 +548,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 				v.Fatalf("invalid store multiple %s", v.LongString())
 			}
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.Reg = v.Args[len(v.Args)-2].Reg()
@@ -616,17 +567,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		//      BNE  mvc
 		//      MVC  $rem, 0(R2), 0(R1) // if rem > 0
 		// arg2 is the last address to move in the loop + 256
-		mvc := gc.Prog(s390x.AMVC)
-		mvc.From.Type = obj.TYPE_MEM
-		mvc.From.Reg = v.Args[1].Reg()
+		mvc := s.Prog(s390x.AMVC)
+		mvc.From.Type = obj.TYPE_CONST
+		mvc.From.Offset = 256
+		mvc.From3 = new(obj.Addr)
+		mvc.From3.Type = obj.TYPE_MEM
+		mvc.From3.Reg = v.Args[1].Reg()
 		mvc.To.Type = obj.TYPE_MEM
 		mvc.To.Reg = v.Args[0].Reg()
-		mvc.From3 = new(obj.Addr)
-		mvc.From3.Type = obj.TYPE_CONST
-		mvc.From3.Offset = 256
 
 		for i := 0; i < 2; i++ {
-			movd := gc.Prog(s390x.AMOVD)
+			movd := s.Prog(s390x.AMOVD)
 			movd.From.Type = obj.TYPE_ADDR
 			movd.From.Reg = v.Args[i].Reg()
 			movd.From.Offset = 256
@@ -634,25 +585,25 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			movd.To.Reg = v.Args[i].Reg()
 		}
 
-		cmpu := gc.Prog(s390x.ACMPU)
+		cmpu := s.Prog(s390x.ACMPU)
 		cmpu.From.Reg = v.Args[1].Reg()
 		cmpu.From.Type = obj.TYPE_REG
 		cmpu.To.Reg = v.Args[2].Reg()
 		cmpu.To.Type = obj.TYPE_REG
 
-		bne := gc.Prog(s390x.ABLT)
+		bne := s.Prog(s390x.ABLT)
 		bne.To.Type = obj.TYPE_BRANCH
 		gc.Patch(bne, mvc)
 
 		if v.AuxInt > 0 {
-			mvc := gc.Prog(s390x.AMVC)
-			mvc.From.Type = obj.TYPE_MEM
-			mvc.From.Reg = v.Args[1].Reg()
+			mvc := s.Prog(s390x.AMVC)
+			mvc.From.Type = obj.TYPE_CONST
+			mvc.From.Offset = v.AuxInt
+			mvc.From3 = new(obj.Addr)
+			mvc.From3.Type = obj.TYPE_MEM
+			mvc.From3.Reg = v.Args[1].Reg()
 			mvc.To.Type = obj.TYPE_MEM
 			mvc.To.Reg = v.Args[0].Reg()
-			mvc.From3 = new(obj.Addr)
-			mvc.From3.Type = obj.TYPE_CONST
-			mvc.From3.Offset = v.AuxInt
 		}
 	case ssa.OpS390XLoweredZero:
 		// Input must be valid pointers to memory,
@@ -665,52 +616,52 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		//        BNE   clear
 		//        CLEAR $rem, 0(R1) // if rem > 0
 		// arg1 is the last address to zero in the loop + 256
-		clear := gc.Prog(s390x.ACLEAR)
+		clear := s.Prog(s390x.ACLEAR)
 		clear.From.Type = obj.TYPE_CONST
 		clear.From.Offset = 256
 		clear.To.Type = obj.TYPE_MEM
 		clear.To.Reg = v.Args[0].Reg()
 
-		movd := gc.Prog(s390x.AMOVD)
+		movd := s.Prog(s390x.AMOVD)
 		movd.From.Type = obj.TYPE_ADDR
 		movd.From.Reg = v.Args[0].Reg()
 		movd.From.Offset = 256
 		movd.To.Type = obj.TYPE_REG
 		movd.To.Reg = v.Args[0].Reg()
 
-		cmpu := gc.Prog(s390x.ACMPU)
+		cmpu := s.Prog(s390x.ACMPU)
 		cmpu.From.Reg = v.Args[0].Reg()
 		cmpu.From.Type = obj.TYPE_REG
 		cmpu.To.Reg = v.Args[1].Reg()
 		cmpu.To.Type = obj.TYPE_REG
 
-		bne := gc.Prog(s390x.ABLT)
+		bne := s.Prog(s390x.ABLT)
 		bne.To.Type = obj.TYPE_BRANCH
 		gc.Patch(bne, clear)
 
 		if v.AuxInt > 0 {
-			clear := gc.Prog(s390x.ACLEAR)
+			clear := s.Prog(s390x.ACLEAR)
 			clear.From.Type = obj.TYPE_CONST
 			clear.From.Offset = v.AuxInt
 			clear.To.Type = obj.TYPE_MEM
 			clear.To.Reg = v.Args[0].Reg()
 		}
 	case ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg0()
 	case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.OpS390XLAA, ssa.OpS390XLAAG:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.Reg = v.Reg0()
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
@@ -726,7 +677,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		//    NOP (so the BNE has somewhere to land)
 
 		// CS{,G} arg1, arg2, arg0
-		cs := gc.Prog(v.Op.Asm())
+		cs := s.Prog(v.Op.Asm())
 		cs.From.Type = obj.TYPE_REG
 		cs.From.Reg = v.Args[1].Reg() // old
 		cs.Reg = v.Args[2].Reg()      // new
@@ -735,25 +686,25 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		gc.AddAux(&cs.To, v)
 
 		// MOVD $0, ret
-		movd := gc.Prog(s390x.AMOVD)
+		movd := s.Prog(s390x.AMOVD)
 		movd.From.Type = obj.TYPE_CONST
 		movd.From.Offset = 0
 		movd.To.Type = obj.TYPE_REG
 		movd.To.Reg = v.Reg0()
 
 		// BNE 2(PC)
-		bne := gc.Prog(s390x.ABNE)
+		bne := s.Prog(s390x.ABNE)
 		bne.To.Type = obj.TYPE_BRANCH
 
 		// MOVD $1, ret
-		movd = gc.Prog(s390x.AMOVD)
+		movd = s.Prog(s390x.AMOVD)
 		movd.From.Type = obj.TYPE_CONST
 		movd.From.Offset = 1
 		movd.To.Type = obj.TYPE_REG
 		movd.To.Reg = v.Reg0()
 
 		// NOP (so the BNE has somewhere to land)
-		nop := gc.Prog(obj.ANOP)
+		nop := s.Prog(obj.ANOP)
 		gc.Patch(bne, nop)
 	case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64:
 		// Loop until the CS{,G} succeeds.
@@ -762,7 +713,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		//     BNE       cs
 
 		// MOV{WZ,D} arg0, ret
-		load := gc.Prog(loadByType(v.Type.FieldType(0)))
+		load := s.Prog(loadByType(v.Type.FieldType(0)))
 		load.From.Type = obj.TYPE_MEM
 		load.From.Reg = v.Args[0].Reg()
 		load.To.Type = obj.TYPE_REG
@@ -770,7 +721,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		gc.AddAux(&load.From, v)
 
 		// CS{,G} ret, arg1, arg0
-		cs := gc.Prog(v.Op.Asm())
+		cs := s.Prog(v.Op.Asm())
 		cs.From.Type = obj.TYPE_REG
 		cs.From.Reg = v.Reg0()   // old
 		cs.Reg = v.Args[1].Reg() // new
@@ -779,9 +730,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		gc.AddAux(&cs.To, v)
 
 		// BNE cs
-		bne := gc.Prog(s390x.ABNE)
+		bne := s.Prog(s390x.ABNE)
 		bne.To.Type = obj.TYPE_BRANCH
 		gc.Patch(bne, cs)
+	case ssa.OpClobber:
+		// TODO: implement for clobberdead experiment. Nop is ok for now.
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -801,12 +754,10 @@ var blockJump = [...]struct {
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(s390x.ABR)
+			p := s.Prog(s390x.ABR)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -814,50 +765,48 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in R3:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(s390x.ACMPW)
+		p := s.Prog(s390x.ACMPW)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = s390x.REG_R3
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = 0
-		p = gc.Prog(s390x.ABNE)
+		p = s.Prog(s390x.ABNE)
 		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(s390x.ABR)
+			p := s.Prog(s390x.ABR)
 			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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(s390x.ABR)
+		p := s.Prog(s390x.ABR)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 	case ssa.BlockS390XEQ, ssa.BlockS390XNE,
 		ssa.BlockS390XLT, ssa.BlockS390XGE,
 		ssa.BlockS390XLE, ssa.BlockS390XGT,
 		ssa.BlockS390XGEF, ssa.BlockS390XGTF:
 		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 = s.Prog(jmp.invasm)
 			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 = s.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 = s.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(s390x.ABR)
+			q := s.Prog(s390x.ABR)
 			q.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
 		}
diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
index e1c2f6d..10f07ce 100644
--- a/src/cmd/compile/internal/ssa/block.go
+++ b/src/cmd/compile/internal/ssa/block.go
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "fmt"
+import (
+	"cmd/internal/src"
+	"fmt"
+)
 
 // Block represents a basic block in the control flow graph of a function.
 type Block struct {
@@ -12,8 +15,8 @@ type Block struct {
 	// these IDs densely, but no guarantees.
 	ID ID
 
-	// Line number for block's control operation
-	Line int32
+	// Source position for block's control operation
+	Pos src.XPos
 
 	// The kind of block this is.
 	Kind BlockKind
@@ -98,7 +101,7 @@ func (e Edge) Index() int {
 //     Exit        return mem                []
 //    Plain               nil            [next]
 //       If   a boolean Value      [then, else]
-//    Defer               mem  [nopanic, panic]  (control opcode should be OpDeferCall)
+//    Defer               mem  [nopanic, panic]  (control opcode should be OpStaticCall to runtime.deferproc)
 type BlockKind int8
 
 // short form print
diff --git a/src/cmd/compile/internal/ssa/cache.go b/src/cmd/compile/internal/ssa/cache.go
new file mode 100644
index 0000000..f1018da
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/cache.go
@@ -0,0 +1,41 @@
+// Copyright 2017 The Go Authors. 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 "sort"
+
+// A Cache holds reusable compiler state.
+// It is intended to be re-used for multiple Func compilations.
+type Cache struct {
+	// Storage for low-numbered values and blocks.
+	values [2000]Value
+	blocks [200]Block
+	locs   [2000]Location
+
+	// 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.
+}
+
+func (c *Cache) Reset() {
+	nv := sort.Search(len(c.values), func(i int) bool { return c.values[i].ID == 0 })
+	xv := c.values[:nv]
+	for i := range xv {
+		xv[i] = Value{}
+	}
+	nb := sort.Search(len(c.blocks), func(i int) bool { return c.blocks[i].ID == 0 })
+	xb := c.blocks[:nb]
+	for i := range xb {
+		xb[i] = Block{}
+	}
+	nl := sort.Search(len(c.locs), func(i int) bool { return c.locs[i] == nil })
+	xl := c.locs[:nl]
+	for i := range xl {
+		xl[i] = nil
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
index d6d39ae..17f683f 100644
--- a/src/cmd/compile/internal/ssa/check.go
+++ b/src/cmd/compile/internal/ssa/check.go
@@ -145,11 +145,9 @@ func checkFunc(f *Func) {
 				if !isExactFloat32(v) {
 					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
 				}
-			case auxSizeAndAlign:
-				canHaveAuxInt = true
-			case auxString, auxSym:
+			case auxString, auxSym, auxTyp:
 				canHaveAux = true
-			case auxSymOff, auxSymValAndOff, auxSymSizeAndAlign:
+			case auxSymOff, auxSymValAndOff, auxTypSize:
 				canHaveAuxInt = true
 				canHaveAux = true
 			case auxSymInt32:
@@ -275,6 +273,23 @@ func checkFunc(f *Func) {
 		}
 	}
 
+	// Check loop construction
+	if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
+		ln := f.loopnest()
+		po := f.postorder() // use po to avoid unreachable blocks.
+		for _, b := range po {
+			for _, s := range b.Succs {
+				bb := s.Block()
+				if ln.b2l[b.ID] == nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header {
+					f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String())
+				}
+				if ln.b2l[b.ID] != nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header && !ln.b2l[b.ID].isWithinOrEq(ln.b2l[bb.ID]) {
+					f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String())
+				}
+			}
+		}
+	}
+
 	// Check use counts
 	uses := make([]int32, f.NumValues())
 	for _, b := range f.Blocks {
@@ -295,6 +310,10 @@ func checkFunc(f *Func) {
 		}
 	}
 
+	memCheck(f)
+}
+
+func memCheck(f *Func) {
 	// Check that if a tuple has a memory type, it is second.
 	for _, b := range f.Blocks {
 		for _, v := range b.Values {
@@ -304,29 +323,143 @@ func checkFunc(f *Func) {
 		}
 	}
 
+	// Single live memory checks.
+	// These checks only work if there are no memory copies.
+	// (Memory copies introduce ambiguity about which mem value is really live.
+	// probably fixable, but it's easier to avoid the problem.)
+	// For the same reason, disable this check if some memory ops are unused.
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if (v.Op == OpCopy || v.Uses == 0) && v.Type.IsMemory() {
+				return
+			}
+		}
+		if b != f.Entry && len(b.Preds) == 0 {
+			return
+		}
+	}
+
+	// Compute live memory at the end of each block.
+	lastmem := make([]*Value, f.NumBlocks())
+	ss := newSparseSet(f.NumValues())
+	for _, b := range f.Blocks {
+		// Mark overwritten memory values. Those are args of other
+		// ops that generate memory values.
+		ss.clear()
+		for _, v := range b.Values {
+			if v.Op == OpPhi || !v.Type.IsMemory() {
+				continue
+			}
+			if m := v.MemoryArg(); m != nil {
+				ss.add(m.ID)
+			}
+		}
+		// There should be at most one remaining unoverwritten memory value.
+		for _, v := range b.Values {
+			if !v.Type.IsMemory() {
+				continue
+			}
+			if ss.contains(v.ID) {
+				continue
+			}
+			if lastmem[b.ID] != nil {
+				f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v)
+			}
+			lastmem[b.ID] = v
+		}
+		// If there is no remaining memory value, that means there was no memory update.
+		// Take any memory arg.
+		if lastmem[b.ID] == nil {
+			for _, v := range b.Values {
+				if v.Op == OpPhi {
+					continue
+				}
+				m := v.MemoryArg()
+				if m == nil {
+					continue
+				}
+				if lastmem[b.ID] != nil && lastmem[b.ID] != m {
+					f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m)
+				}
+				lastmem[b.ID] = m
+			}
+		}
+	}
+	// Propagate last live memory through storeless blocks.
+	for {
+		changed := false
+		for _, b := range f.Blocks {
+			if lastmem[b.ID] != nil {
+				continue
+			}
+			for _, e := range b.Preds {
+				p := e.b
+				if lastmem[p.ID] != nil {
+					lastmem[b.ID] = lastmem[p.ID]
+					changed = true
+					break
+				}
+			}
+		}
+		if !changed {
+			break
+		}
+	}
+	// Check merge points.
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Op == OpPhi && v.Type.IsMemory() {
+				for i, a := range v.Args {
+					if a != lastmem[b.Preds[i].b.ID] {
+						f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].b.ID])
+					}
+				}
+			}
+		}
+	}
+
 	// Check that only one memory is live at any point.
-	// TODO: make this check examine interblock.
 	if f.scheduled {
 		for _, b := range f.Blocks {
-			var mem *Value // the live memory
+			var mem *Value // the current live memory in the block
 			for _, v := range b.Values {
-				if v.Op != OpPhi {
-					for _, a := range v.Args {
-						if a.Type.IsMemory() || a.Type.IsTuple() && a.Type.FieldType(1).IsMemory() {
-							if mem == nil {
-								mem = a
-							} else if mem != a {
-								f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
-							}
-						}
+				if v.Op == OpPhi {
+					if v.Type.IsMemory() {
+						mem = v
+					}
+					continue
+				}
+				if mem == nil && len(b.Preds) > 0 {
+					// If no mem phi, take mem of any predecessor.
+					mem = lastmem[b.Preds[0].b.ID]
+				}
+				for _, a := range v.Args {
+					if a.Type.IsMemory() && a != mem {
+						f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
 					}
 				}
-				if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
+				if v.Type.IsMemory() {
 					mem = v
 				}
 			}
 		}
 	}
+
+	// Check that after scheduling, phis are always first in the block.
+	if f.scheduled {
+		for _, b := range f.Blocks {
+			seenNonPhi := false
+			for _, v := range b.Values {
+				if v.Op == OpPhi {
+					if seenNonPhi {
+						f.Fatalf("phi after non-phi @ %s: %s", b, v)
+					}
+				} else {
+					seenNonPhi = true
+				}
+			}
+		}
+	}
 }
 
 // domCheck reports whether x dominates y (including x==y).
diff --git a/src/cmd/compile/internal/ssa/checkbce.go b/src/cmd/compile/internal/ssa/checkbce.go
index 3b15d5a..ab842b4 100644
--- a/src/cmd/compile/internal/ssa/checkbce.go
+++ b/src/cmd/compile/internal/ssa/checkbce.go
@@ -16,7 +16,7 @@ func checkbce(f *Func) {
 	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)
+				f.Warnl(v.Pos, "Found %v", v.Op)
 			}
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 5b461ba..315416b 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -5,7 +5,8 @@
 package ssa
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"fmt"
 	"log"
 	"os"
@@ -42,7 +43,7 @@ func Compile(f *Func) {
 
 	// Run all the passes
 	printFunc(f)
-	f.Config.HTML.WriteFunc("start", f)
+	f.HTMLWriter.WriteFunc("start", f)
 	if BuildDump != "" && BuildDump == f.Name {
 		f.dumpFile("build")
 	}
@@ -70,7 +71,7 @@ func Compile(f *Func) {
 		tEnd := time.Now()
 
 		// Need something less crude than "Log the whole intermediate result".
-		if f.Log() || f.Config.HTML != nil {
+		if f.Log() || f.HTMLWriter != nil {
 			time := tEnd.Sub(tStart).Nanoseconds()
 			var stats string
 			if logMemStats {
@@ -85,7 +86,7 @@ func Compile(f *Func) {
 
 			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)
+			f.HTMLWriter.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.
@@ -129,7 +130,7 @@ func (f *Func) dumpFile(phaseName string) {
 
 	fi, err := os.Create(fname)
 	if err != nil {
-		f.Config.Warnl(0, "Unable to create after-phase dump file %s", fname)
+		f.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
 		return
 	}
 
@@ -203,7 +204,7 @@ func PhaseOption(phase, flag string, val int, valString string) string {
 			}
 		}
 		return "" +
-			`GcFlag -d=ssa/<phase>/<flag>[=<value>]|[:<function_name>]
+			`GcFlag -d=ssa/<phase>/<flag>[=<value>|<function_name>]
 <phase> is one of:
 ` + phasenames + `
 <flag> is one of on, off, debug, mem, time, test, stats, dump
@@ -347,11 +348,11 @@ var passes = [...]pass{
 	{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: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
 	{name: "fuse", fn: fuse},
 	{name: "dse", fn: dse},
+	{name: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
 	{name: "insert resched checks", fn: insertLoopReschedChecks,
-		disabled: obj.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
+		disabled: objabi.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
 	{name: "tighten", fn: tighten}, // move values closer to their uses
 	{name: "lower", fn: lower, required: true},
 	{name: "lowered cse", fn: cse},
@@ -368,6 +369,7 @@ var passes = [...]pass{
 	{name: "late nilcheck", fn: nilcheckelim2},
 	{name: "flagalloc", fn: flagalloc, required: true}, // allocate flags register
 	{name: "regalloc", fn: regalloc, required: true},   // allocate int & float registers + stack slots
+	{name: "loop rotate", fn: loopRotate},
 	{name: "stackframe", fn: stackframe, required: true},
 	{name: "trim", fn: trim}, // remove empty blocks
 }
@@ -426,6 +428,8 @@ var passOrder = [...]constraint{
 	{"schedule", "flagalloc"},
 	// regalloc needs flags to be allocated first.
 	{"flagalloc", "regalloc"},
+	// loopRotate will confuse regalloc.
+	{"regalloc", "loop rotate"},
 	// stackframe needs to know about spilled registers.
 	{"regalloc", "stackframe"},
 	// trim needs regalloc to be done first.
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 4931da8..6587c40 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -5,78 +5,69 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
-	"crypto/sha1"
-	"fmt"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"os"
 	"strconv"
-	"strings"
 )
 
+// A Config holds readonly compilation information.
+// It is created once, early during compilation,
+// and shared across all compilations.
 type Config struct {
-	arch            string                     // "amd64", etc.
-	IntSize         int64                      // 4 or 8
-	PtrSize         int64                      // 4 or 8
-	RegSize         int64                      // 4 or 8
-	lowerBlock      func(*Block, *Config) bool // lowering function
-	lowerValue      func(*Value, *Config) bool // lowering function
-	registers       []Register                 // machine registers
-	gpRegMask       regMask                    // general purpose integer register mask
-	fpRegMask       regMask                    // floating point register mask
-	specialRegMask  regMask                    // special register mask
-	FPReg           int8                       // register number of frame pointer, -1 if not used
-	LinkReg         int8                       // register number of link register if it is a general purpose register, -1 if not used
-	hasGReg         bool                       // has hardware g register
-	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
-	nacl            bool                       // GOOS=nacl
-	use387          bool                       // GO386=387
-	OldArch         bool                       // True for older versions of architecture, e.g. true for PPC64BE, false for PPC64LE
-	NeedsFpScratch  bool                       // No direct move between GP and FP register sets
-	BigEndian       bool                       //
-	DebugTest       bool                       // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
-	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.
+	arch            string // "amd64", etc.
+	PtrSize         int64  // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize
+	RegSize         int64  // 4 or 8; copy of cmd/internal/sys.Arch.RegSize
+	Types           Types
+	lowerBlock      blockRewriter // lowering function
+	lowerValue      valueRewriter // lowering function
+	registers       []Register    // machine registers
+	gpRegMask       regMask       // general purpose integer register mask
+	fpRegMask       regMask       // floating point register mask
+	specialRegMask  regMask       // special register mask
+	FPReg           int8          // register number of frame pointer, -1 if not used
+	LinkReg         int8          // register number of link register if it is a general purpose register, -1 if not used
+	hasGReg         bool          // has hardware g register
+	ctxt            *obj.Link     // Generic arch information
+	optimize        bool          // Do optimization
+	noDuffDevice    bool          // Don't use Duff's device
+	nacl            bool          // GOOS=nacl
+	use387          bool          // GO386=387
+	NeedsFpScratch  bool          // No direct move between GP and FP register sets
+	BigEndian       bool          //
+	sparsePhiCutoff uint64        // Sparse phi location algorithm used above this #blocks*#variables score
 }
 
-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?
+type (
+	blockRewriter func(*Block) bool
+	valueRewriter func(*Value) bool
+)
 
-	CanSSA(t Type) bool
+type Types struct {
+	Bool       *types.Type
+	Int8       *types.Type
+	Int16      *types.Type
+	Int32      *types.Type
+	Int64      *types.Type
+	UInt8      *types.Type
+	UInt16     *types.Type
+	UInt32     *types.Type
+	UInt64     *types.Type
+	Int        *types.Type
+	Float32    *types.Type
+	Float64    *types.Type
+	Uintptr    *types.Type
+	String     *types.Type
+	BytePtr    *types.Type // TODO: use unsafe.Pointer instead?
+	Int32Ptr   *types.Type
+	UInt32Ptr  *types.Type
+	IntPtr     *types.Type
+	UintptrPtr *types.Type
+	Float32Ptr *types.Type
+	Float64Ptr *types.Type
+	BytePtrPtr *types.Type
 }
 
 type Logger interface {
@@ -88,10 +79,10 @@ type Logger interface {
 	Log() bool
 
 	// Fatal reports a compiler error and exits.
-	Fatalf(line int32, msg string, args ...interface{})
+	Fatalf(pos src.XPos, msg string, args ...interface{})
 
 	// Warnl writes compiler messages in the form expected by "errorcheck" tests
-	Warnl(line int32, fmt_ string, args ...interface{})
+	Warnl(pos src.XPos, fmt_ string, args ...interface{})
 
 	// Forwards the Debug flags from gc
 	Debug_checknil() bool
@@ -99,7 +90,8 @@ type Logger interface {
 }
 
 type Frontend interface {
-	TypeSource
+	CanSSA(t *types.Type) bool
+
 	Logger
 
 	// StringData returns a symbol pointing to the given string's contents.
@@ -107,7 +99,7 @@ type Frontend interface {
 
 	// 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
+	Auto(src.XPos, *types.Type) GCNode
 
 	// Given the name for a compound type, returns the name we should use
 	// for the parts of that compound type.
@@ -119,30 +111,38 @@ type Frontend interface {
 	SplitArray(LocalSlot) LocalSlot              // array must be length 1
 	SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
 
-	// Line returns a string describing the given line number.
-	Line(int32) string
+	// DerefItab dereferences an itab function
+	// entry, given the symbol of the itab and
+	// the byte offset of the function pointer.
+	// It may return nil.
+	DerefItab(sym *obj.LSym, offset int64) *obj.LSym
+
+	// Line returns a string describing the given position.
+	Line(src.XPos) string
 
 	// AllocFrame assigns frame offsets to all live auto variables.
 	AllocFrame(f *Func)
 
 	// Syslook returns a symbol of the runtime function/variable with the
 	// given name.
-	Syslook(string) interface{} // returns *gc.Sym
+	Syslook(string) *obj.LSym
+
+	// UseWriteBarrier returns whether write barrier is enabled
+	UseWriteBarrier() bool
 }
 
 // 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
+	Typ() *types.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}
+func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
+	c := &Config{arch: arch, Types: types}
 	switch arch {
 	case "amd64":
-		c.IntSize = 8
 		c.PtrSize = 8
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockAMD64
@@ -154,7 +154,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.LinkReg = linkRegAMD64
 		c.hasGReg = false
 	case "amd64p32":
-		c.IntSize = 4
 		c.PtrSize = 4
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockAMD64
@@ -167,7 +166,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.hasGReg = false
 		c.noDuffDevice = true
 	case "386":
-		c.IntSize = 4
 		c.PtrSize = 4
 		c.RegSize = 4
 		c.lowerBlock = rewriteBlock386
@@ -179,7 +177,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.LinkReg = linkReg386
 		c.hasGReg = false
 	case "arm":
-		c.IntSize = 4
 		c.PtrSize = 4
 		c.RegSize = 4
 		c.lowerBlock = rewriteBlockARM
@@ -191,7 +188,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.LinkReg = linkRegARM
 		c.hasGReg = true
 	case "arm64":
-		c.IntSize = 8
 		c.PtrSize = 8
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockARM64
@@ -202,13 +198,11 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.FPReg = framepointerRegARM64
 		c.LinkReg = linkRegARM64
 		c.hasGReg = true
-		c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
+		c.noDuffDevice = objabi.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
 	case "ppc64":
-		c.OldArch = true
 		c.BigEndian = true
 		fallthrough
 	case "ppc64le":
-		c.IntSize = 8
 		c.PtrSize = 8
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockPPC64
@@ -219,13 +213,11 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.FPReg = framepointerRegPPC64
 		c.LinkReg = linkRegPPC64
 		c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
-		c.NeedsFpScratch = true
 		c.hasGReg = true
 	case "mips64":
 		c.BigEndian = true
 		fallthrough
 	case "mips64le":
-		c.IntSize = 8
 		c.PtrSize = 8
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockMIPS64
@@ -238,7 +230,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.LinkReg = linkRegMIPS64
 		c.hasGReg = true
 	case "s390x":
-		c.IntSize = 8
 		c.PtrSize = 8
 		c.RegSize = 8
 		c.lowerBlock = rewriteBlockS390X
@@ -255,7 +246,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.BigEndian = true
 		fallthrough
 	case "mipsle":
-		c.IntSize = 4
 		c.PtrSize = 4
 		c.RegSize = 4
 		c.lowerBlock = rewriteBlockMIPS
@@ -269,15 +259,15 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.hasGReg = true
 		c.noDuffDevice = true
 	default:
-		fe.Fatalf(0, "arch %s not implemented", arch)
+		ctxt.Diag("arch %s not implemented", arch)
 	}
 	c.ctxt = ctxt
 	c.optimize = optimize
-	c.nacl = obj.GOOS == "nacl"
+	c.nacl = objabi.GOOS == "nacl"
 
 	// Don't use Duff's device on Plan 9 AMD64, because floating
 	// point operations are not allowed in note handler.
-	if obj.GOOS == "plan9" && arch == "amd64" {
+	if objabi.GOOS == "plan9" && arch == "amd64" {
 		c.noDuffDevice = true
 	}
 
@@ -285,19 +275,9 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 		c.noDuffDevice = true // Don't use Duff's device on NaCl
 
 		// runtime call clobber R12 on nacl
-		opcodeTable[OpARMUDIVrtcall].reg.clobbers |= 1 << 12 // R12
+		opcodeTable[OpARMCALLudiv].reg.clobbers |= 1 << 12 // R12
 	}
 
-	// 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.
@@ -309,7 +289,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
 	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)
+			ctxt.Diag("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
 	}
@@ -322,104 +302,5 @@ func (c *Config) Set387(b bool) {
 	c.use387 = b
 }
 
-func (c *Config) Frontend() Frontend      { return c.fe }
 func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
 func (c *Config) Ctxt() *obj.Link         { return c.ctxt }
-
-// 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) 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) Debug_wb() bool                                     { return c.fe.Debug_wb() }
-
-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_test.go b/src/cmd/compile/internal/ssa/copyelim_test.go
index 96f5846..fe31b12 100644
--- a/src/cmd/compile/internal/ssa/copyelim_test.go
+++ b/src/cmd/compile/internal/ssa/copyelim_test.go
@@ -5,6 +5,7 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"testing"
 )
@@ -20,11 +21,11 @@ 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))
+	values = append(values, Valu("mem", OpInitMem, types.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))
+		values = append(values, Valu(name, OpCopy, types.TypeMem, 0, nil, last))
 		last = name
 	}
 	values = append(values, Exit(last))
@@ -34,8 +35,7 @@ func benchmarkCopyElim(b *testing.B, n int) {
 	}
 
 	for i := 0; i < b.N; i++ {
-		fun := Fun(c, "entry", Bloc("entry", values...))
+		fun := c.Fun("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
index 38cd3cb..b85721e 100644
--- a/src/cmd/compile/internal/ssa/critical.go
+++ b/src/cmd/compile/internal/ssa/critical.go
@@ -60,10 +60,10 @@ func critical(f *Func) {
 					// 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
+					d.Pos = p.Pos
 					blocks[argID] = d
 					if f.pass.debug > 0 {
-						f.Config.Warnl(p.Line, "split critical edge")
+						f.Warnl(p.Pos, "split critical edge")
 					}
 				} else {
 					reusedBlock = true
@@ -72,9 +72,9 @@ func critical(f *Func) {
 				// no existing block, so allocate a new block
 				// to place on the edge
 				d = f.NewBlock(BlockPlain)
-				d.Line = p.Line
+				d.Pos = p.Pos
 				if f.pass.debug > 0 {
-					f.Config.Warnl(p.Line, "split critical edge")
+					f.Warnl(p.Pos, "split critical edge")
 				}
 			}
 
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
index 9ab18d8..7e9c4f4 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -5,6 +5,7 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"sort"
 )
@@ -30,23 +31,21 @@ func cse(f *Func) {
 
 	// Make initial coarse partitions by using a subset of the conditions above.
 	a := make([]*Value, 0, f.NumValues())
-	auxIDs := auxmap{}
+	if f.auxmap == nil {
+		f.auxmap = 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]
+			if f.auxmap[v.Aux] == 0 {
+				f.auxmap[v.Aux] = int32(len(f.auxmap)) + 1
 			}
 			a = append(a, v)
 		}
 	}
-	partition := partitionValues(a, auxIDs)
+	partition := partitionValues(a, f.auxmap)
 
 	// map from value id back to eqclass id
 	valueEqClass := make([]ID, f.NumValues())
@@ -92,6 +91,15 @@ func cse(f *Func) {
 		for i := 0; i < len(partition); i++ {
 			e := partition[i]
 
+			if opcodeTable[e[0].Op].commutative {
+				// Order the first two args before comparison.
+				for _, v := range e {
+					if valueEqClass[v.Args[0].ID] > valueEqClass[v.Args[1].ID] {
+						v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
+					}
+				}
+			}
+
 			// Sort by eq class of arguments.
 			byArgClass.a = e
 			byArgClass.eqClass = valueEqClass
@@ -101,6 +109,7 @@ func cse(f *Func) {
 			splitPoints = append(splitPoints[:0], 0)
 			for j := 1; j < len(e); j++ {
 				v, w := e[j-1], e[j]
+				// Note: commutative args already correctly ordered by byArgClass.
 				eqArgs := true
 				for k, a := range v.Args {
 					b := w.Args[k]
@@ -273,7 +282,7 @@ func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
 		j := 1
 		for ; j < len(a); j++ {
 			w := a[j]
-			if cmpVal(v, w, auxIDs) != CMPeq {
+			if cmpVal(v, w, auxIDs) != types.CMPeq {
 				break
 			}
 		}
@@ -285,16 +294,16 @@ func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
 
 	return partition
 }
-func lt2Cmp(isLt bool) Cmp {
+func lt2Cmp(isLt bool) types.Cmp {
 	if isLt {
-		return CMPlt
+		return types.CMPlt
 	}
-	return CMPgt
+	return types.CMPgt
 }
 
 type auxmap map[interface{}]int32
 
-func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
+func cmpVal(v, w *Value, auxIDs auxmap) types.Cmp {
 	// Try to order these comparison by cost (cheaper first)
 	if v.Op != w.Op {
 		return lt2Cmp(v.Op < w.Op)
@@ -313,26 +322,26 @@ func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
 		// that generate memory.
 		return lt2Cmp(v.ID < w.ID)
 	}
-	// OpSelect is a pseudo-op. We need to be more agressive
+	// OpSelect is a pseudo-op. We need to be more aggressive
 	// regarding CSE to keep multiple OpSelect's of the same
 	// argument from existing.
 	if v.Op != OpSelect0 && v.Op != OpSelect1 {
-		if tc := v.Type.Compare(w.Type); tc != CMPeq {
+		if tc := v.Type.Compare(w.Type); tc != types.CMPeq {
 			return tc
 		}
 	}
 
 	if v.Aux != w.Aux {
 		if v.Aux == nil {
-			return CMPlt
+			return types.CMPlt
 		}
 		if w.Aux == nil {
-			return CMPgt
+			return types.CMPgt
 		}
 		return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
 	}
 
-	return CMPeq
+	return types.CMPeq
 }
 
 // Sort values to make the initial partition.
@@ -346,8 +355,8 @@ 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); cmp != CMPeq {
-		return cmp == CMPlt
+	if cmp := cmpVal(v, w, sv.auxIDs); cmp != types.CMPeq {
+		return cmp == types.CMPlt
 	}
 
 	// Sort by value ID last to keep the sort result deterministic.
diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go
index 905939f..aab50eb 100644
--- a/src/cmd/compile/internal/ssa/cse_test.go
+++ b/src/cmd/compile/internal/ssa/cse_test.go
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 type tstAux struct {
 	s string
@@ -19,26 +22,26 @@ func TestCSEAuxPartitionBug(t *testing.T) {
 
 	// construct lots of values with args that have aux values and place
 	// them in an order that triggers the bug
-	fun := Fun(c, "entry",
+	fun := c.Fun("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"),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sp", OpSP, c.config.Types.BytePtr, 0, nil),
+			Valu("r7", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg1"),
+			Valu("r1", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"),
+			Valu("arg1", OpArg, c.config.Types.Int64, 0, arg1Aux),
+			Valu("arg2", OpArg, c.config.Types.Int64, 0, arg2Aux),
+			Valu("arg3", OpArg, c.config.Types.Int64, 0, arg3Aux),
+			Valu("r9", OpAdd64, c.config.Types.Int64, 0, nil, "r7", "r8"),
+			Valu("r4", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"),
+			Valu("r8", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg2"),
+			Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"),
+			Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"),
+			Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"),
+			Valu("r6", OpAdd64, c.config.Types.Int64, 0, nil, "r4", "r5"),
+			Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"),
+			Valu("r5", OpAdd64, c.config.Types.Int64, 0, nil, "r2", "r3"),
+			Valu("r10", OpAdd64, c.config.Types.Int64, 0, nil, "r6", "r9"),
+			Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r10", "raddrdef"),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("rstore")))
@@ -87,24 +90,24 @@ func TestCSEAuxPartitionBug(t *testing.T) {
 func TestZCSE(t *testing.T) {
 	c := testConfig(t)
 
-	fun := Fun(c, "entry",
+	fun := c.Fun("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"),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sp", OpSP, c.config.Types.BytePtr, 0, nil),
+			Valu("sb1", OpSB, c.config.Types.BytePtr, 0, nil),
+			Valu("sb2", OpSB, c.config.Types.BytePtr, 0, nil),
+			Valu("addr1", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sb1"),
+			Valu("addr2", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sb2"),
+			Valu("a1ld", OpLoad, c.config.Types.Int64, 0, nil, "addr1", "start"),
+			Valu("a2ld", OpLoad, c.config.Types.Int64, 0, nil, "addr2", "start"),
+			Valu("c1", OpConst64, c.config.Types.Int64, 1, nil),
+			Valu("r1", OpAdd64, c.config.Types.Int64, 0, nil, "a1ld", "c1"),
+			Valu("c2", OpConst64, c.config.Types.Int64, 1, nil),
+			Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "a2ld", "c2"),
+			Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"),
+			Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"),
+			Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"),
+			Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r3", "raddrdef"),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("rstore")))
diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
index ce786a9..b24ecaa 100644
--- a/src/cmd/compile/internal/ssa/deadcode.go
+++ b/src/cmd/compile/internal/ssa/deadcode.go
@@ -6,13 +6,13 @@ package ssa
 
 // findlive returns the reachable blocks and live values in f.
 func findlive(f *Func) (reachable []bool, live []bool) {
-	reachable = reachableBlocks(f)
+	reachable = ReachableBlocks(f)
 	live = liveValues(f, reachable)
 	return
 }
 
-// reachableBlocks returns the reachable blocks in f.
-func reachableBlocks(f *Func) []bool {
+// 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
@@ -106,7 +106,7 @@ func deadcode(f *Func) {
 	}
 
 	// Find reachable blocks.
-	reachable := reachableBlocks(f)
+	reachable := ReachableBlocks(f)
 
 	// Get rid of edges from dead to live code.
 	for _, b := range f.Blocks {
diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go
index b1d8d0f..5777b84 100644
--- a/src/cmd/compile/internal/ssa/deadcode_test.go
+++ b/src/cmd/compile/internal/ssa/deadcode_test.go
@@ -5,6 +5,7 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"strconv"
 	"testing"
@@ -12,16 +13,16 @@ import (
 
 func TestDeadLoop(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("mem")),
 		// dead loop
 		Bloc("deadblock",
 			// dead value in dead block
-			Valu("deadval", OpConstBool, TypeBool, 1, nil),
+			Valu("deadval", OpConstBool, c.config.Types.Bool, 1, nil),
 			If("deadval", "deadblock", "exit")))
 
 	CheckFunc(fun.f)
@@ -42,10 +43,10 @@ func TestDeadLoop(t *testing.T) {
 
 func TestDeadValue(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("deadval", OpConst64, TypeInt64, 37, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("deadval", OpConst64, c.config.Types.Int64, 37, nil),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("mem")))
@@ -65,10 +66,10 @@ func TestDeadValue(t *testing.T) {
 
 func TestNeverTaken(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("cond", OpConstBool, TypeBool, 0, nil),
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			If("cond", "then", "else")),
 		Bloc("then",
 			Goto("exit")),
@@ -100,10 +101,10 @@ func TestNeverTaken(t *testing.T) {
 
 func TestNestedDeadBlocks(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("cond", OpConstBool, TypeBool, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil),
 			If("cond", "b2", "b4")),
 		Bloc("b2",
 			If("cond", "b3", "b4")),
@@ -144,7 +145,7 @@ func BenchmarkDeadCode(b *testing.B) {
 			blocks := make([]bloc, 0, n+2)
 			blocks = append(blocks,
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit")))
 			blocks = append(blocks, Bloc("exit", Exit("mem")))
 			for i := 0; i < n; i++ {
@@ -152,9 +153,8 @@ func BenchmarkDeadCode(b *testing.B) {
 			}
 			b.ResetTimer()
 			for i := 0; i < b.N; i++ {
-				fun := Fun(c, "entry", blocks...)
+				fun := c.Fun("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
index 89ab17a..08a2c6d 100644
--- a/src/cmd/compile/internal/ssa/deadstore.go
+++ b/src/cmd/compile/internal/ssa/deadstore.go
@@ -4,6 +4,11 @@
 
 package ssa
 
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+)
+
 // 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.
@@ -29,10 +34,6 @@ func dse(f *Func) {
 			}
 			if v.Type.IsMemory() {
 				stores = append(stores, v)
-				if v.Op == OpSelect1 {
-					// Use the args of the tuple-generating op.
-					v = v.Args[0]
-				}
 				for _, a := range v.Args {
 					if a.Block == b && a.Type.IsMemory() {
 						storeUse.add(a.ID)
@@ -62,7 +63,7 @@ func dse(f *Func) {
 				continue
 			}
 			if last != nil {
-				b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
+				b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
 			}
 			last = v
 		}
@@ -86,9 +87,9 @@ func dse(f *Func) {
 		if v.Op == OpStore || v.Op == OpZero {
 			var sz int64
 			if v.Op == OpStore {
-				sz = v.AuxInt
+				sz = v.Aux.(*types.Type).Size()
 			} else { // OpZero
-				sz = SizeAndAlign(v.AuxInt).Size()
+				sz = v.AuxInt
 			}
 			if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
 				// Modify store into a copy
@@ -111,12 +112,16 @@ func dse(f *Func) {
 				if sz > 0x7fffffff { // work around sparseMap's int32 value type
 					sz = 0x7fffffff
 				}
-				shadowed.set(v.Args[0].ID, int32(sz), 0)
+				shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
 			}
 		}
 		// walk to previous store
 		if v.Op == OpPhi {
-			continue // At start of block.  Move on to next block.
+			// At start of block.  Move on to next block.
+			// The memory phi, if it exists, is always
+			// the first logical store in the block.
+			// (Even if it isn't the first in the current b.Values order.)
+			continue
 		}
 		for _, a := range v.Args {
 			if a.Block == b && a.Type.IsMemory() {
diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go
index beb6de0..2326c6c 100644
--- a/src/cmd/compile/internal/ssa/deadstore_test.go
+++ b/src/cmd/compile/internal/ssa/deadstore_test.go
@@ -4,25 +4,28 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 func TestDeadStore(t *testing.T) {
 	c := testConfig(t)
-	elemType := &TypeImpl{Size_: 1, Name: "testtype"}
-	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
-	fun := Fun(c, "entry",
+	ptrType := c.config.Types.BytePtr
+	t.Logf("PTRTYPE %v", ptrType)
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("start", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
-			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, c.config.Types.Bool, 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, 1, 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"),
+			Valu("zero1", OpZero, types.TypeMem, 1, c.config.Types.Bool, "addr3", "start"),
+			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "zero1"),
+			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
+			Valu("store3", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store2"),
+			Valu("store4", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr3", "v", "store3"),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("store3")))
@@ -44,17 +47,17 @@ func TestDeadStore(t *testing.T) {
 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",
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("start", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
-			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, c.config.Types.Bool, 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"),
+			Valu("phi", OpPhi, types.TypeMem, 0, nil, "start", "store"),
+			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr", "v", "phi"),
 			If("v", "loop", "exit")),
 		Bloc("exit",
 			Exit("store")))
@@ -70,17 +73,17 @@ func TestDeadStoreTypes(t *testing.T) {
 	// 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",
+	t1 := c.config.Types.UInt64.PtrTo()
+	t2 := c.config.Types.UInt32.PtrTo()
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("start", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
-			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, c.config.Types.Bool, 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"),
+			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "start"),
+			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("store2")))
@@ -101,15 +104,15 @@ func TestDeadStoreUnsafe(t *testing.T) {
 	// covers the case of two different types, but unsafe pointer casting
 	// can get to a point where the size is changed but type unchanged.
 	c := testConfig(t)
-	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
-	fun := Fun(c, "entry",
+	ptrType := c.config.Types.UInt64.PtrTo()
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("start", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
-			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
 			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
-			Valu("store1", OpStore, TypeMem, 8, nil, "addr1", "v", "start"),  // store 8 bytes
-			Valu("store2", OpStore, TypeMem, 1, nil, "addr1", "v", "store1"), // store 1 byte
+			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "addr1", "v", "start"), // store 8 bytes
+			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store1"), // store 1 byte
 			Goto("exit")),
 		Bloc("exit",
 			Exit("store2")))
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
index b2ee2f0..2b3f16c 100644
--- a/src/cmd/compile/internal/ssa/decompose.go
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -4,6 +4,8 @@
 
 package ssa
 
+import "cmd/compile/internal/types"
+
 // decompose converts phi ops on compound builtin types into phi
 // ops on simple types.
 // (The remaining compound ops are decomposed with rewrite rules.)
@@ -25,78 +27,78 @@ func decomposeBuiltIn(f *Func) {
 	for _, name := range f.Names {
 		t := name.Type
 		switch {
-		case t.IsInteger() && t.Size() == 8 && f.Config.IntSize == 4:
-			var elemType Type
+		case t.IsInteger() && t.Size() > f.Config.RegSize:
+			var elemType *types.Type
 			if t.IsSigned() {
-				elemType = f.Config.fe.TypeInt32()
+				elemType = f.Config.Types.Int32
 			} else {
-				elemType = f.Config.fe.TypeUInt32()
+				elemType = f.Config.Types.UInt32
 			}
-			hiName, loName := f.Config.fe.SplitInt64(name)
+			hiName, loName := f.fe.SplitInt64(name)
 			newNames = append(newNames, hiName, loName)
 			for _, v := range f.NamedValues[name] {
-				hi := v.Block.NewValue1(v.Line, OpInt64Hi, elemType, v)
-				lo := v.Block.NewValue1(v.Line, OpInt64Lo, f.Config.fe.TypeUInt32(), v)
+				hi := v.Block.NewValue1(v.Pos, OpInt64Hi, elemType, v)
+				lo := v.Block.NewValue1(v.Pos, OpInt64Lo, f.Config.Types.UInt32, v)
 				f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
 				f.NamedValues[loName] = append(f.NamedValues[loName], lo)
 			}
 			delete(f.NamedValues, name)
 		case t.IsComplex():
-			var elemType Type
+			var elemType *types.Type
 			if t.Size() == 16 {
-				elemType = f.Config.fe.TypeFloat64()
+				elemType = f.Config.Types.Float64
 			} else {
-				elemType = f.Config.fe.TypeFloat32()
+				elemType = f.Config.Types.Float32
 			}
-			rName, iName := f.Config.fe.SplitComplex(name)
+			rName, iName := f.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)
+				r := v.Block.NewValue1(v.Pos, OpComplexReal, elemType, v)
+				i := v.Block.NewValue1(v.Pos, 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)
+			ptrType := f.Config.Types.BytePtr
+			lenType := f.Config.Types.Int
+			ptrName, lenName := f.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)
+				ptr := v.Block.NewValue1(v.Pos, OpStringPtr, ptrType, v)
+				len := v.Block.NewValue1(v.Pos, 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)
+			ptrType := f.Config.Types.BytePtr
+			lenType := f.Config.Types.Int
+			ptrName, lenName, capName := f.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)
+				ptr := v.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, v)
+				len := v.Block.NewValue1(v.Pos, OpSliceLen, lenType, v)
+				cap := v.Block.NewValue1(v.Pos, 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)
+			ptrType := f.Config.Types.BytePtr
+			typeName, dataName := f.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)
+				typ := v.Block.NewValue1(v.Pos, OpITab, ptrType, v)
+				data := v.Block.NewValue1(v.Pos, 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.IsFloat():
-			// floats are never decomposed, even ones bigger than IntSize
-		case t.Size() > f.Config.IntSize:
+			// floats are never decomposed, even ones bigger than RegSize
+		case t.Size() > f.Config.RegSize:
 			f.Fatalf("undecomposed named type %v %v", name, t)
 		default:
 			newNames = append(newNames, name)
@@ -107,11 +109,7 @@ func decomposeBuiltIn(f *Func) {
 
 func decomposeBuiltInPhi(v *Value) {
 	switch {
-	case v.Type.IsInteger() && v.Type.Size() == 8 && v.Block.Func.Config.IntSize == 4:
-		if v.Block.Func.Config.arch == "amd64p32" {
-			// Even though ints are 32 bits, we have 64-bit ops.
-			break
-		}
+	case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
 		decomposeInt64Phi(v)
 	case v.Type.IsComplex():
 		decomposeComplexPhi(v)
@@ -122,22 +120,22 @@ func decomposeBuiltInPhi(v *Value) {
 	case v.Type.IsInterface():
 		decomposeInterfacePhi(v)
 	case v.Type.IsFloat():
-		// floats are never decomposed, even ones bigger than IntSize
-	case v.Type.Size() > v.Block.Func.Config.IntSize:
+		// floats are never decomposed, even ones bigger than RegSize
+	case v.Type.Size() > v.Block.Func.Config.RegSize:
 		v.Fatalf("undecomposed type %s", v.Type)
 	}
 }
 
 func decomposeStringPhi(v *Value) {
-	fe := v.Block.Func.Config.fe
-	ptrType := fe.TypeBytePtr()
-	lenType := fe.TypeInt()
+	types := &v.Block.Func.Config.Types
+	ptrType := types.BytePtr
+	lenType := types.Int
 
-	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
-	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
+	ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
+	len := v.Block.NewValue0(v.Pos, 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))
+		ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
+		len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
 	}
 	v.reset(OpStringMake)
 	v.AddArg(ptr)
@@ -145,17 +143,17 @@ func decomposeStringPhi(v *Value) {
 }
 
 func decomposeSlicePhi(v *Value) {
-	fe := v.Block.Func.Config.fe
-	ptrType := fe.TypeBytePtr()
-	lenType := fe.TypeInt()
+	types := &v.Block.Func.Config.Types
+	ptrType := types.BytePtr
+	lenType := types.Int
 
-	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
-	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
-	cap := v.Block.NewValue0(v.Line, OpPhi, lenType)
+	ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
+	len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
+	cap := v.Block.NewValue0(v.Pos, 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))
+		ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
+		len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
+		cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
 	}
 	v.reset(OpSliceMake)
 	v.AddArg(ptr)
@@ -164,19 +162,19 @@ func decomposeSlicePhi(v *Value) {
 }
 
 func decomposeInt64Phi(v *Value) {
-	fe := v.Block.Func.Config.fe
-	var partType Type
+	cfgtypes := &v.Block.Func.Config.Types
+	var partType *types.Type
 	if v.Type.IsSigned() {
-		partType = fe.TypeInt32()
+		partType = cfgtypes.Int32
 	} else {
-		partType = fe.TypeUInt32()
+		partType = cfgtypes.UInt32
 	}
 
-	hi := v.Block.NewValue0(v.Line, OpPhi, partType)
-	lo := v.Block.NewValue0(v.Line, OpPhi, fe.TypeUInt32())
+	hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
+	lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32)
 	for _, a := range v.Args {
-		hi.AddArg(a.Block.NewValue1(v.Line, OpInt64Hi, partType, a))
-		lo.AddArg(a.Block.NewValue1(v.Line, OpInt64Lo, fe.TypeUInt32(), a))
+		hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
+		lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a))
 	}
 	v.reset(OpInt64Make)
 	v.AddArg(hi)
@@ -184,22 +182,22 @@ func decomposeInt64Phi(v *Value) {
 }
 
 func decomposeComplexPhi(v *Value) {
-	fe := v.Block.Func.Config.fe
-	var partType Type
+	cfgtypes := &v.Block.Func.Config.Types
+	var partType *types.Type
 	switch z := v.Type.Size(); z {
 	case 8:
-		partType = fe.TypeFloat32()
+		partType = cfgtypes.Float32
 	case 16:
-		partType = fe.TypeFloat64()
+		partType = cfgtypes.Float64
 	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)
+	real := v.Block.NewValue0(v.Pos, OpPhi, partType)
+	imag := v.Block.NewValue0(v.Pos, 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))
+		real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
+		imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
 	}
 	v.reset(OpComplexMake)
 	v.AddArg(real)
@@ -207,13 +205,13 @@ func decomposeComplexPhi(v *Value) {
 }
 
 func decomposeInterfacePhi(v *Value) {
-	ptrType := v.Block.Func.Config.fe.TypeBytePtr()
+	ptrType := v.Block.Func.Config.Types.BytePtr
 
-	itab := v.Block.NewValue0(v.Line, OpPhi, ptrType)
-	data := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+	itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
+	data := v.Block.NewValue0(v.Pos, 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))
+		itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, a))
+		data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
 	}
 	v.reset(OpIMake)
 	v.AddArg(itab)
@@ -243,11 +241,11 @@ func decomposeUser(f *Func) {
 			n := t.NumFields()
 			fnames = fnames[:0]
 			for i := 0; i < n; i++ {
-				fnames = append(fnames, f.Config.fe.SplitStruct(name, i))
+				fnames = append(fnames, f.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)
+					x := v.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), v)
 					f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
 				}
 			}
@@ -262,9 +260,9 @@ func decomposeUser(f *Func) {
 			if t.NumElem() != 1 {
 				f.Fatalf("array not of size 1")
 			}
-			elemName := f.Config.fe.SplitArray(name)
+			elemName := f.fe.SplitArray(name)
 			for _, v := range f.NamedValues[name] {
-				e := v.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, v)
+				e := v.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, v)
 				f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
 			}
 
@@ -293,11 +291,11 @@ func decomposeStructPhi(v *Value) {
 	n := t.NumFields()
 	var fields [MaxStruct]*Value
 	for i := 0; i < n; i++ {
-		fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i))
+		fields[i] = v.Block.NewValue0(v.Pos, 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))
+			fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
 		}
 	}
 	v.reset(StructMakeOp(n))
@@ -320,9 +318,9 @@ func decomposeArrayPhi(v *Value) {
 	if t.NumElem() != 1 {
 		v.Fatalf("SSAable array must have no more than 1 element")
 	}
-	elem := v.Block.NewValue0(v.Line, OpPhi, t.ElemType())
+	elem := v.Block.NewValue0(v.Pos, OpPhi, t.ElemType())
 	for _, a := range v.Args {
-		elem.AddArg(a.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, a))
+		elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, a))
 	}
 	v.reset(OpArrayMake1)
 	v.AddArg(elem)
diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go
index 4790e33..db991f6 100644
--- a/src/cmd/compile/internal/ssa/dom.go
+++ b/src/cmd/compile/internal/ssa/dom.go
@@ -22,40 +22,42 @@ const (
 func postorder(f *Func) []*Block {
 	return postorderWithNumbering(f, []int32{})
 }
+
+type blockAndIndex struct {
+	b     *Block
+	index int // index is the number of successor edges of b that have already been explored.
+}
+
+// postorderWithNumbering provides a DFS postordering.
+// This seems to make loop-finding more robust.
 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
+	// stack of blocks and next child to visit
+	var s []blockAndIndex
+	s = append(s, blockAndIndex{b: f.Entry})
+	mark[f.Entry.ID] = explored
 	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
+		tos := len(s) - 1
+		x := s[tos]
+		b := x.b
+		i := x.index
+		if i < len(b.Succs) {
+			s[tos].index++
+			bb := b.Succs[i].Block()
+			if mark[bb.ID] == notFound {
+				mark[bb.ID] = explored
+				s = append(s, blockAndIndex{b: bb})
+			}
+		} else {
+			s = s[:tos]
 			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
@@ -70,9 +72,9 @@ const nscratchslices = 7
 // in make.bash.
 const minscratchblocks = 512
 
-func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) {
+func (cache *Cache) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) {
 	tot := maxBlockID * nscratchslices
-	scratch := cfg.domblockstore
+	scratch := cache.domblockstore
 	if len(scratch) < tot {
 		// req = min(1.5*tot, nscratchslices*minscratchblocks)
 		// 50% padding allows for graph growth in later phases.
@@ -81,7 +83,7 @@ func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID
 			req = nscratchslices * minscratchblocks
 		}
 		scratch = make([]ID, req)
-		cfg.domblockstore = scratch
+		cache.domblockstore = scratch
 	} else {
 		// Clear as much of scratch as we will (re)use
 		scratch = scratch[0:tot]
@@ -117,7 +119,7 @@ func (f *Func) dominatorsLTOrig(entry *Block, predFn linkedBlocks, succFn linked
 	// 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)
+	semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Cache.scratchBlocksForDom(maxBlockID)
 
 	// This version uses integers for most of the computation,
 	// to make the work arrays smaller and pointer-free.
@@ -296,7 +298,8 @@ func dominatorsSimple(f *Func) []*Block {
 // 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*.
+	// TODO: This loop is O(n^2). It used to be used in nilcheck,
+	// see BenchmarkNilCheckDeep*.
 	for b != c {
 		if postnum[b.ID] < postnum[c.ID] {
 			b = idom[b.ID]
diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go
index 6ecbe92..fa51718 100644
--- a/src/cmd/compile/internal/ssa/dom_test.go
+++ b/src/cmd/compile/internal/ssa/dom_test.go
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 func BenchmarkDominatorsLinear(b *testing.B)     { benchmarkDominators(b, 10000, genLinear) }
 func BenchmarkDominatorsFwdBack(b *testing.B)    { benchmarkDominators(b, 10000, genFwdBack) }
@@ -20,7 +23,7 @@ func genLinear(size int) []bloc {
 	var blocs []bloc
 	blocs = append(blocs,
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Goto(blockn(0)),
 		),
 	)
@@ -43,8 +46,8 @@ 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),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto(blockn(0)),
 		),
 	)
@@ -73,8 +76,8 @@ 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),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto(blockn(0)),
 		),
 	)
@@ -85,15 +88,15 @@ func genManyPred(size int) []bloc {
 		switch i % 3 {
 		case 0:
 			blocs = append(blocs, Bloc(blockn(i),
-				Valu("a", OpConstBool, TypeBool, 1, nil),
+				Valu("a", OpConstBool, types.Types[types.TBOOL], 1, nil),
 				Goto(blockn(i+1))))
 		case 1:
 			blocs = append(blocs, Bloc(blockn(i),
-				Valu("a", OpConstBool, TypeBool, 1, nil),
+				Valu("a", OpConstBool, types.Types[types.TBOOL], 1, nil),
 				If("p", blockn(i+1), blockn(0))))
 		case 2:
 			blocs = append(blocs, Bloc(blockn(i),
-				Valu("a", OpConstBool, TypeBool, 1, nil),
+				Valu("a", OpConstBool, types.Types[types.TBOOL], 1, nil),
 				If("p", blockn(i+1), blockn(size))))
 		}
 	}
@@ -111,8 +114,8 @@ 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),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto(blockn(0)),
 		),
 	)
@@ -136,15 +139,15 @@ 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),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto(blockn(0)),
 		),
 	)
 
 	for i := 0; i < size; i++ {
 		blocs = append(blocs, Bloc(blockn(i),
-			Valu("a", OpConstBool, TypeBool, 1, nil),
+			Valu("a", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			If("p", blockn(i+1), "exit")))
 	}
 
@@ -160,8 +163,8 @@ func genMaxPredValue(size int) []bloc {
 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)...)
+	c := testConfig(b)
+	fun := c.Fun("entry", bg(size)...)
 
 	CheckFunc(fun.f)
 	b.SetBytes(int64(size))
@@ -221,9 +224,9 @@ func verifyDominators(t *testing.T, fut fun, domFn domFunc, doms map[string]stri
 
 func TestDominatorsSingleBlock(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Exit("mem")))
 
 	doms := map[string]string{}
@@ -236,9 +239,9 @@ func TestDominatorsSingleBlock(t *testing.T) {
 
 func TestDominatorsSimple(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Goto("a")),
 		Bloc("a",
 			Goto("b")),
@@ -264,10 +267,10 @@ func TestDominatorsSimple(t *testing.T) {
 
 func TestDominatorsMultPredFwd(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			If("p", "a", "c")),
 		Bloc("a",
 			If("p", "b", "c")),
@@ -292,10 +295,10 @@ func TestDominatorsMultPredFwd(t *testing.T) {
 
 func TestDominatorsDeadCode(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 0, nil),
 			If("p", "b3", "b5")),
 		Bloc("b2", Exit("mem")),
 		Bloc("b3", Goto("b2")),
@@ -315,12 +318,12 @@ func TestDominatorsDeadCode(t *testing.T) {
 
 func TestDominatorsMultPredRev(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
 			Goto("first")),
 		Bloc("first",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto("a")),
 		Bloc("a",
 			If("p", "b", "first")),
@@ -346,10 +349,10 @@ func TestDominatorsMultPredRev(t *testing.T) {
 
 func TestDominatorsMultPred(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			If("p", "a", "c")),
 		Bloc("a",
 			If("p", "b", "c")),
@@ -375,10 +378,10 @@ func TestDominatorsMultPred(t *testing.T) {
 func TestInfiniteLoop(t *testing.T) {
 	c := testConfig(t)
 	// note lack of an exit block
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			Goto("a")),
 		Bloc("a",
 			Goto("b")),
@@ -411,10 +414,11 @@ func TestDomTricky(t *testing.T) {
 		b := 1 & i >> 1
 		c := 1 & i >> 2
 
-		fun := Fun(testConfig(t), "1",
+		cfg := testConfig(t)
+		fun := cfg.Fun("1",
 			Bloc("1",
-				Valu("mem", OpInitMem, TypeMem, 0, nil),
-				Valu("p", OpConstBool, TypeBool, 1, nil),
+				Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+				Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 				Goto("4")),
 			Bloc("2",
 				Goto("11")),
@@ -453,23 +457,55 @@ func generateDominatorMap(fut fun) map[string]string {
 	return doms
 }
 
-func TestDominatorsPostTricky(t *testing.T) {
+func TestDominatorsPostTrickyA(t *testing.T) {
+	testDominatorsPostTricky(t, "b8", "b11", "b10", "b8", "b14", "b15")
+}
+
+func TestDominatorsPostTrickyB(t *testing.T) {
+	testDominatorsPostTricky(t, "b11", "b8", "b10", "b8", "b14", "b15")
+}
+
+func TestDominatorsPostTrickyC(t *testing.T) {
+	testDominatorsPostTricky(t, "b8", "b11", "b8", "b10", "b14", "b15")
+}
+
+func TestDominatorsPostTrickyD(t *testing.T) {
+	testDominatorsPostTricky(t, "b11", "b8", "b8", "b10", "b14", "b15")
+}
+
+func TestDominatorsPostTrickyE(t *testing.T) {
+	testDominatorsPostTricky(t, "b8", "b11", "b10", "b8", "b15", "b14")
+}
+
+func TestDominatorsPostTrickyF(t *testing.T) {
+	testDominatorsPostTricky(t, "b11", "b8", "b10", "b8", "b15", "b14")
+}
+
+func TestDominatorsPostTrickyG(t *testing.T) {
+	testDominatorsPostTricky(t, "b8", "b11", "b8", "b10", "b15", "b14")
+}
+
+func TestDominatorsPostTrickyH(t *testing.T) {
+	testDominatorsPostTricky(t, "b11", "b8", "b8", "b10", "b15", "b14")
+}
+
+func testDominatorsPostTricky(t *testing.T, b7then, b7else, b12then, b12else, b13then, b13else string) {
 	c := testConfig(t)
-	fun := Fun(c, "b1",
+	fun := c.Fun("b1",
 		Bloc("b1",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("p", OpConstBool, types.Types[types.TBOOL], 1, nil),
 			If("p", "b3", "b2")),
 		Bloc("b3",
 			If("p", "b5", "b6")),
 		Bloc("b5",
 			Goto("b7")),
 		Bloc("b7",
-			If("p", "b8", "b11")),
+			If("p", b7then, b7else)),
 		Bloc("b8",
 			Goto("b13")),
 		Bloc("b13",
-			If("p", "b14", "b15")),
+			If("p", b13then, b13else)),
 		Bloc("b14",
 			Goto("b10")),
 		Bloc("b15",
@@ -481,7 +517,7 @@ func TestDominatorsPostTricky(t *testing.T) {
 		Bloc("b11",
 			Goto("b12")),
 		Bloc("b12",
-			If("p", "b10", "b8")),
+			If("p", b12then, b12else)),
 		Bloc("b10",
 			Goto("b6")),
 		Bloc("b6",
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 80fa92d..3bb67a9 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -5,73 +5,104 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/s390x"
 	"cmd/internal/obj/x86"
+	"cmd/internal/src"
+	"fmt"
 	"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{Arch: &x86.Linkamd64}
-	return NewConfig("amd64", DummyFrontend{t}, testCtxt, true)
+var testCtxts = map[string]*obj.Link{
+	"amd64": obj.Linknew(&x86.Linkamd64),
+	"s390x": obj.Linknew(&s390x.Links390x),
 }
 
-func testConfigS390X(t testing.TB) *Config {
-	return NewConfig("s390x", DummyFrontend{t}, obj.Linknew(&s390x.Links390x), true)
+func testConfig(tb testing.TB) *Conf      { return testConfigArch(tb, "amd64") }
+func testConfigS390X(tb testing.TB) *Conf { return testConfigArch(tb, "s390x") }
+
+func testConfigArch(tb testing.TB, arch string) *Conf {
+	ctxt, ok := testCtxts[arch]
+	if !ok {
+		tb.Fatalf("unknown arch %s", arch)
+	}
+	if ctxt.Arch.PtrSize != 8 {
+		tb.Fatal("dummyTypes is 64-bit only")
+	}
+	c := &Conf{
+		config: NewConfig(arch, dummyTypes, ctxt, true),
+		tb:     tb,
+	}
+	return c
+}
+
+type Conf struct {
+	config *Config
+	tb     testing.TB
+	fe     Frontend
+}
+
+func (c *Conf) Frontend() Frontend {
+	if c.fe == nil {
+		c.fe = DummyFrontend{t: c.tb, ctxt: c.config.ctxt}
+	}
+	return c.fe
 }
 
 // DummyFrontend is a test-only frontend.
 // It assumes 64 bit integers and pointers.
 type DummyFrontend struct {
-	t testing.TB
+	t    testing.TB
+	ctxt *obj.Link
 }
 
-func (DummyFrontend) StringData(s string) interface{} {
-	return nil
+type DummyAuto struct {
+	t *types.Type
+	s string
 }
 
-type dummyGCNode struct {
-	typ  Type
-	name string
+func (d *DummyAuto) Typ() *types.Type {
+	return d.t
 }
 
-func (d *dummyGCNode) Typ() Type {
-	return d.typ
+func (d *DummyAuto) String() string {
+	return d.s
 }
-func (d *dummyGCNode) String() string {
-	return d.name
+
+func (DummyFrontend) StringData(s string) interface{} {
+	return nil
 }
-func (d DummyFrontend) Auto(t Type) GCNode {
-	return &dummyGCNode{typ: t, name: "dummy"}
+func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
+	return &DummyAuto{t: t, s: "aDummyAuto"}
 }
 func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
-	return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeInt(), s.Off + 8}
+	return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.Int, 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}
+	return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.BytePtr, 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}
+		LocalSlot{s.N, dummyTypes.Int, s.Off + 8},
+		LocalSlot{s.N, dummyTypes.Int, 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, dummyTypes.Float64, s.Off}, LocalSlot{s.N, dummyTypes.Float64, s.Off + 8}
 	}
-	return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
+	return LocalSlot{s.N, dummyTypes.Float32, s.Off}, LocalSlot{s.N, dummyTypes.Float32, s.Off + 4}
 }
 func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
 	if s.Type.IsSigned() {
-		return LocalSlot{s.N, d.TypeInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
+		return LocalSlot{s.N, dummyTypes.Int32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
 	}
-	return LocalSlot{s.N, d.TypeUInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
+	return LocalSlot{s.N, dummyTypes.UInt32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
 }
 func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
 	return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
@@ -79,44 +110,101 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
 func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
 	return LocalSlot{s.N, s.Type.ElemType(), s.Off}
 }
-func (DummyFrontend) Line(line int32) string {
+func (DummyFrontend) Line(_ src.XPos) string {
 	return "unknown.go:0"
 }
 func (DummyFrontend) AllocFrame(f *Func) {
 }
-func (DummyFrontend) Syslook(s string) interface{} {
-	return DummySym(s)
+func (d DummyFrontend) Syslook(s string) *obj.LSym {
+	return d.ctxt.Lookup(s)
+}
+func (DummyFrontend) UseWriteBarrier() bool {
+	return true // only writebarrier_test cares
 }
 
 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) Warnl(line int32, msg string, args ...interface{})  { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Warnl(_ src.XPos, msg string, args ...interface{})  { d.t.Logf(msg, args...) }
 func (d DummyFrontend) Debug_checknil() bool                               { return false }
 func (d DummyFrontend) Debug_wb() 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
+var dummyTypes Types
+
+func init() {
+	// Initialize just enough of the universe and the types package to make our tests function.
+	// TODO(josharian): move universe initialization to the types package,
+	// so this test setup can share it.
+
+	types.Tconv = func(t *types.Type, flag, mode, depth int) string {
+		return t.Etype.String()
+	}
+	types.Sconv = func(s *types.Sym, flag, mode int) string {
+		return "sym"
+	}
+	types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
+		fmt.Fprintf(s, "sym")
+	}
+	types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
+		fmt.Fprintf(s, "%v", t.Etype)
+	}
+	types.Dowidth = func(t *types.Type) {}
+
+	types.Tptr = types.TPTR64
+	for _, typ := range [...]struct {
+		width int64
+		et    types.EType
+	}{
+		{1, types.TINT8},
+		{1, types.TUINT8},
+		{1, types.TBOOL},
+		{2, types.TINT16},
+		{2, types.TUINT16},
+		{4, types.TINT32},
+		{4, types.TUINT32},
+		{4, types.TFLOAT32},
+		{4, types.TFLOAT64},
+		{8, types.TUINT64},
+		{8, types.TINT64},
+		{8, types.TINT},
+		{8, types.TUINTPTR},
+	} {
+		t := types.New(typ.et)
+		t.Width = typ.width
+		t.Align = uint8(typ.width)
+		types.Types[typ.et] = t
+	}
+
+	dummyTypes = Types{
+		Bool:       types.Types[types.TBOOL],
+		Int8:       types.Types[types.TINT8],
+		Int16:      types.Types[types.TINT16],
+		Int32:      types.Types[types.TINT32],
+		Int64:      types.Types[types.TINT64],
+		UInt8:      types.Types[types.TUINT8],
+		UInt16:     types.Types[types.TUINT16],
+		UInt32:     types.Types[types.TUINT32],
+		UInt64:     types.Types[types.TUINT64],
+		Float32:    types.Types[types.TFLOAT32],
+		Float64:    types.Types[types.TFLOAT64],
+		Int:        types.Types[types.TINT],
+		Uintptr:    types.Types[types.TUINTPTR],
+		String:     types.Types[types.TSTRING],
+		BytePtr:    types.NewPtr(types.Types[types.TUINT8]),
+		Int32Ptr:   types.NewPtr(types.Types[types.TINT32]),
+		UInt32Ptr:  types.NewPtr(types.Types[types.TUINT32]),
+		IntPtr:     types.NewPtr(types.Types[types.TINT]),
+		UintptrPtr: types.NewPtr(types.Types[types.TUINTPTR]),
+		Float32Ptr: types.NewPtr(types.Types[types.TFLOAT32]),
+		Float64Ptr: types.NewPtr(types.Types[types.TFLOAT64]),
+		BytePtrPtr: types.NewPtr(types.NewPtr(types.Types[types.TUINT8])),
+	}
 }
 
-type DummySym string
+func (d DummyFrontend) DerefItab(sym *obj.LSym, off int64) *obj.LSym { return nil }
 
-func (s DummySym) String() string { return string(s) }
+func (d DummyFrontend) CanSSA(t *types.Type) bool {
+	// There are no un-SSAable types in dummy land.
+	return true
+}
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index df29aa3..7ec5963 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -5,27 +5,47 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+	"crypto/sha1"
 	"fmt"
+	"io"
 	"math"
+	"os"
 	"strings"
 )
 
-// A Func represents a Go func declaration (or function literal) and
-// its body. This package compiles each Func independently.
+type writeSyncer interface {
+	io.Writer
+	Sync() error
+}
+
+// A Func represents a Go func declaration (or function literal) and its body.
+// This package compiles each Func independently.
+// Funcs are single-use; a new Func must be created for every compiled function.
 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
+	Config *Config     // architecture information
+	Cache  *Cache      // re-usable cache
+	fe     Frontend    // frontend state associated with this Func, callbacks into compiler frontend
+	pass   *pass       // current pass information (name, options, etc.)
+	Name   string      // e.g. bytes·Compare
+	Type   *types.Type // type signature of the function.
+	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
+
+	// Given an environment variable used for debug hash match,
+	// what file (if any) receives the yes/no logging?
+	logfiles   map[string]writeSyncer
+	HTMLWriter *HTMLWriter // html writer, for debugging
+	DebugTest  bool        // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
 
 	scheduled bool // Values in Blocks are in final order
 	NoSplit   bool // true if function is marked as nosplit.  Used by schedule check pass.
 
+	WBPos src.XPos // line number of first write barrier
+
 	// when register allocation is done, maps value ids to locations
 	RegAlloc []Location
 
@@ -43,9 +63,17 @@ type Func struct {
 	cachedSdom      SparseTree // cached dominator tree
 	cachedLoopnest  *loopnest  // cached loop nest information
 
+	auxmap auxmap // map from aux values to opaque ids used by CSE
+
 	constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
 }
 
+// NewFunc returns a new, empty function object.
+// Caller must set f.Config and f.Cache before using f.
+func NewFunc(fe Frontend) *Func {
+	return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value)}
+}
+
 // NumBlocks returns an integer larger than the id of any Block in the Func.
 func (f *Func) NumBlocks() int {
 	return f.bid.num()
@@ -58,9 +86,9 @@ func (f *Func) NumValues() int {
 
 // 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 {
+	for i, scr := range f.Cache.scrSparse {
 		if scr != nil && scr.cap() >= n {
-			f.Config.scrSparse[i] = nil
+			f.Cache.scrSparse[i] = nil
 			scr.clear()
 			return scr
 		}
@@ -70,17 +98,17 @@ func (f *Func) newSparseSet(n int) *sparseSet {
 
 // 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 {
+	for i, scr := range f.Cache.scrSparse {
 		if scr == nil {
-			f.Config.scrSparse[i] = ss
+			f.Cache.scrSparse[i] = ss
 			return
 		}
 	}
-	f.Config.scrSparse = append(f.Config.scrSparse, ss)
+	f.Cache.scrSparse = append(f.Cache.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 {
+func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
 	var v *Value
 	if f.freeValues != nil {
 		v = f.freeValues
@@ -88,8 +116,9 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
 		v.argstorage[0] = nil
 	} else {
 		ID := f.vid.get()
-		if int(ID) < len(f.Config.values) {
-			v = &f.Config.values[ID]
+		if int(ID) < len(f.Cache.values) {
+			v = &f.Cache.values[ID]
+			v.ID = ID
 		} else {
 			v = &Value{ID: ID}
 		}
@@ -97,11 +126,37 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
 	v.Op = op
 	v.Type = t
 	v.Block = b
-	v.Line = line
+	v.Pos = pos
 	b.Values = append(b.Values, v)
 	return v
 }
 
+// newValueNoBlock allocates a new Value with the given fields.
+// The returned value is not placed in any block.  Once the caller
+// decides on a block b, it must set b.Block and append
+// the returned value to b.Values.
+func (f *Func) newValueNoBlock(op Op, t *types.Type, pos src.XPos) *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.Cache.values) {
+			v = &f.Cache.values[ID]
+			v.ID = ID
+		} else {
+			v = &Value{ID: ID}
+		}
+	}
+	v.Op = op
+	v.Type = t
+	v.Block = nil // caller must fix this.
+	v.Pos = pos
+	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 (?)
@@ -117,7 +172,7 @@ func (f *Func) LogStat(key string, args ...interface{}) {
 	if f.pass != nil {
 		n = strings.Replace(f.pass.name, " ", "_", -1)
 	}
-	f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name)
+	f.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
 }
 
 // freeValue frees a value. It must no longer be referenced.
@@ -131,13 +186,14 @@ func (f *Func) freeValue(v *Value) {
 	// Clear everything but ID (which we reuse).
 	id := v.ID
 
-	// Zero argument values might be cached, so remove them there.
+	// Values with zero arguments and OpOffPtr values might be cached, so remove them there.
 	nArgs := opcodeTable[v.Op].argLen
-	if nArgs == 0 {
+	if nArgs == 0 || v.Op == OpOffPtr {
 		vv := f.constants[v.AuxInt]
 		for i, cv := range vv {
 			if v == cv {
 				vv[i] = vv[len(vv)-1]
+				vv[len(vv)-1] = nil
 				f.constants[v.AuxInt] = vv[0 : len(vv)-1]
 				break
 			}
@@ -158,8 +214,9 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
 		b.succstorage[0].b = nil
 	} else {
 		ID := f.bid.get()
-		if int(ID) < len(f.Config.blocks) {
-			b = &f.Config.blocks[ID]
+		if int(ID) < len(f.Cache.blocks) {
+			b = &f.Cache.blocks[ID]
+			b.ID = ID
 		} else {
 			b = &Block{ID: ID}
 		}
@@ -187,30 +244,30 @@ func (f *Func) freeBlock(b *Block) {
 }
 
 // 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)
+func (b *Block) NewValue0(pos src.XPos, op Op, t *types.Type) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	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)
+func (b *Block) NewValue0I(pos src.XPos, op Op, t *types.Type, auxint int64) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	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 {
+func (b *Block) NewValue0A(pos src.XPos, op Op, t *types.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 := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Aux = aux
 	v.Args = v.argstorage[:0]
@@ -218,8 +275,8 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
 }
 
 // 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)
+func (b *Block) NewValue0IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = auxint
 	v.Aux = aux
 	v.Args = v.argstorage[:0]
@@ -227,8 +284,8 @@ func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interfa
 }
 
 // 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)
+func (b *Block) NewValue1(pos src.XPos, op Op, t *types.Type, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Args = v.argstorage[:1]
 	v.argstorage[0] = arg
@@ -237,8 +294,8 @@ func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
 }
 
 // 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)
+func (b *Block) NewValue1I(pos src.XPos, op Op, t *types.Type, auxint int64, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = auxint
 	v.Args = v.argstorage[:1]
 	v.argstorage[0] = arg
@@ -247,8 +304,8 @@ func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value)
 }
 
 // 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)
+func (b *Block) NewValue1A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Aux = aux
 	v.Args = v.argstorage[:1]
@@ -258,8 +315,8 @@ func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Valu
 }
 
 // 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)
+func (b *Block) NewValue1IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = auxint
 	v.Aux = aux
 	v.Args = v.argstorage[:1]
@@ -269,8 +326,8 @@ func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interfa
 }
 
 // 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)
+func (b *Block) NewValue2(pos src.XPos, op Op, t *types.Type, arg0, arg1 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Args = v.argstorage[:2]
 	v.argstorage[0] = arg0
@@ -281,8 +338,8 @@ func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
 }
 
 // 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)
+func (b *Block) NewValue2I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = auxint
 	v.Args = v.argstorage[:2]
 	v.argstorage[0] = arg0
@@ -293,8 +350,8 @@ func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *
 }
 
 // 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)
+func (b *Block) NewValue3(pos src.XPos, op Op, t *types.Type, arg0, arg1, arg2 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Args = v.argstorage[:3]
 	v.argstorage[0] = arg0
@@ -307,8 +364,8 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *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)
+func (b *Block) NewValue3I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = auxint
 	v.Args = v.argstorage[:3]
 	v.argstorage[0] = arg0
@@ -320,9 +377,24 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1,
 	return v
 }
 
+// NewValue3A returns a new value in the block with three argument and an aux value.
+func (b *Block) NewValue3A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
+	v.AuxInt = 0
+	v.Aux = aux
+	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
+}
+
 // NewValue4 returns a new value in the block with four arguments and zero aux values.
-func (b *Block) NewValue4(line int32, op Op, t Type, arg0, arg1, arg2, arg3 *Value) *Value {
-	v := b.Func.newValue(op, t, b, line)
+func (b *Block) NewValue4(pos src.XPos, op Op, t *types.Type, arg0, arg1, arg2, arg3 *Value) *Value {
+	v := b.Func.newValue(op, t, b, pos)
 	v.AuxInt = 0
 	v.Args = []*Value{arg0, arg1, arg2, arg3}
 	arg0.Uses++
@@ -333,24 +405,24 @@ func (b *Block) NewValue4(line int32, op Op, t Type, arg0, arg1, arg2, arg3 *Val
 }
 
 // constVal returns a constant value for c.
-func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value {
+func (f *Func) constVal(pos src.XPos, op Op, t *types.Type, c int64, setAuxInt 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 {
+		if v.Op == op && v.Type.Compare(t) == types.CMPeq {
+			if setAuxInt && 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)
+	if setAuxInt {
+		v = f.Entry.NewValue0I(pos, op, t, c)
 	} else {
-		v = f.Entry.NewValue0(line, op, t)
+		v = f.Entry.NewValue0(pos, op, t)
 	}
 	f.constants[c] = append(vv, v)
 	return v
@@ -368,83 +440,61 @@ const (
 )
 
 // ConstInt returns an int constant representing its argument.
-func (f *Func) ConstBool(line int32, t Type, c bool) *Value {
+func (f *Func) ConstBool(pos src.XPos, t *types.Type, c bool) *Value {
 	i := int64(0)
 	if c {
 		i = 1
 	}
-	return f.constVal(line, OpConstBool, t, i, true)
+	return f.constVal(pos, 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) ConstInt8(pos src.XPos, t *types.Type, c int8) *Value {
+	return f.constVal(pos, 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) ConstInt16(pos src.XPos, t *types.Type, c int16) *Value {
+	return f.constVal(pos, 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) ConstInt32(pos src.XPos, t *types.Type, c int32) *Value {
+	return f.constVal(pos, 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) ConstInt64(pos src.XPos, t *types.Type, c int64) *Value {
+	return f.constVal(pos, 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) ConstFloat32(pos src.XPos, t *types.Type, c float64) *Value {
+	return f.constVal(pos, 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) ConstFloat64(pos src.XPos, t *types.Type, c float64) *Value {
+	return f.constVal(pos, 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) ConstSlice(pos src.XPos, t *types.Type) *Value {
+	return f.constVal(pos, OpConstSlice, t, constSliceMagic, false)
 }
-func (f *Func) ConstInterface(line int32, t Type) *Value {
-	return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false)
+func (f *Func) ConstInterface(pos src.XPos, t *types.Type) *Value {
+	return f.constVal(pos, OpConstInterface, t, constInterfaceMagic, false)
 }
-func (f *Func) ConstNil(line int32, t Type) *Value {
-	return f.constVal(line, OpConstNil, t, constNilMagic, false)
+func (f *Func) ConstNil(pos src.XPos, t *types.Type) *Value {
+	return f.constVal(pos, OpConstNil, t, constNilMagic, false)
 }
-func (f *Func) ConstEmptyString(line int32, t Type) *Value {
-	v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false)
+func (f *Func) ConstEmptyString(pos src.XPos, t *types.Type) *Value {
+	v := f.constVal(pos, 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) Free() {
-	// Clear cached CFG info.
-	f.invalidateCFG()
-
-	// 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)
+func (f *Func) ConstOffPtrSP(pos src.XPos, t *types.Type, c int64, sp *Value) *Value {
+	v := f.constVal(pos, OpOffPtr, t, c, true)
+	if len(v.Args) == 0 {
+		v.AddArg(sp)
 	}
+	return v
 
-	// 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
 }
 
+func (f *Func) Frontend() Frontend                                  { return f.fe }
+func (f *Func) Warnl(pos src.XPos, msg string, args ...interface{}) { f.fe.Warnl(pos, msg, args...) }
+func (f *Func) Logf(msg string, args ...interface{})                { f.fe.Logf(msg, args...) }
+func (f *Func) Log() bool                                           { return f.fe.Log() }
+func (f *Func) Fatalf(msg string, args ...interface{})              { f.fe.Fatalf(f.Entry.Pos, msg, args...) }
+
 // postorder returns the reachable blocks in f in a postorder traversal.
 func (f *Func) postorder() []*Block {
 	if f.cachedPostorder == nil {
@@ -453,6 +503,10 @@ func (f *Func) postorder() []*Block {
 	return f.cachedPostorder
 }
 
+func (f *Func) Postorder() []*Block {
+	return f.postorder()
+}
+
 // Idom returns a map from block ID to the immediate dominator of that block.
 // f.Entry.ID maps to nil. Unreachable blocks map to nil as well.
 func (f *Func) Idom() []*Block {
@@ -486,3 +540,81 @@ func (f *Func) invalidateCFG() {
 	f.cachedSdom = nil
 	f.cachedLoopnest = nil
 }
+
+// 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 (f *Func) DebugHashMatch(evname, name string) bool {
+	evhash := os.Getenv(evname)
+	switch evhash {
+	case "":
+		return true // default behavior with no EV is "on"
+	case "y", "Y":
+		f.logDebugHashMatch(evname, name)
+		return true
+	case "n", "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) {
+		f.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) {
+			f.logDebugHashMatch(ev, name)
+			return true
+		}
+	}
+	return false
+}
+
+func (f *Func) logDebugHashMatch(evname, name string) {
+	if f.logfiles == nil {
+		f.logfiles = make(map[string]writeSyncer)
+	}
+	file := f.logfiles[evname]
+	if file == nil {
+		file = os.Stdout
+		if tmpfile := os.Getenv("GSHS_LOGFILE"); tmpfile != "" {
+			var err error
+			file, err = os.Create(tmpfile)
+			if err != nil {
+				f.Fatalf("could not open hash-testing logfile %s", tmpfile)
+			}
+		}
+		f.logfiles[evname] = file
+	}
+	fmt.Fprintf(file, "%s triggered %s\n", evname, name)
+	file.Sync()
+}
+
+func DebugNameMatch(evname, name string) bool {
+	return os.Getenv(evname) == name
+}
diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go
index 7136d8f..94ff27e 100644
--- a/src/cmd/compile/internal/ssa/func_test.go
+++ b/src/cmd/compile/internal/ssa/func_test.go
@@ -18,12 +18,12 @@
 //
 //   fun := Fun("entry",
 //       Bloc("entry",
-//           Valu("mem", OpInitMem, TypeMem, 0, nil),
+//           Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 //           Goto("exit")),
 //       Bloc("exit",
 //           Exit("mem")),
 //       Bloc("deadblock",
-//          Valu("deadval", OpConstBool, TypeBool, 0, true),
+//          Valu("deadval", OpConstBool, c.config.Types.Bool, 0, true),
 //          If("deadval", "deadblock", "exit")))
 //
 // and the Blocks or Values used in the Func can be accessed
@@ -37,6 +37,8 @@ package ssa
 //                the parser can be used instead of Fun.
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"fmt"
 	"reflect"
 	"testing"
@@ -142,8 +144,13 @@ var emptyPass pass = pass{
 // 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()
+func (c *Conf) Fun(entry string, blocs ...bloc) fun {
+	f := NewFunc(c.Frontend())
+	f.Config = c.config
+	// TODO: Either mark some SSA tests as t.Parallel,
+	// or set up a shared Cache and Reset it between tests.
+	// But not both.
+	f.Cache = new(Cache)
 	f.pass = &emptyPass
 
 	blocks := make(map[string]*Block)
@@ -154,7 +161,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun {
 		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)
+			values[valu.name] = b.NewValue0IA(src.NoXPos, valu.op, valu.t, valu.auxint, valu.aux)
 		}
 	}
 	// Connect the blocks together and specify control values.
@@ -217,7 +224,7 @@ func Bloc(name string, entries ...interface{}) bloc {
 }
 
 // Valu defines a value in a block.
-func Valu(name string, op Op, t Type, auxint int64, aux interface{}, args ...string) valu {
+func Valu(name string, op Op, t *types.Type, auxint int64, aux interface{}, args ...string) valu {
 	return valu{name, op, t, auxint, aux, args}
 }
 
@@ -260,7 +267,7 @@ type ctrl struct {
 type valu struct {
 	name   string
 	op     Op
-	t      Type
+	t      *types.Type
 	auxint int64
 	aux    interface{}
 	args   []string
@@ -268,12 +275,12 @@ type valu struct {
 
 func TestArgs(t *testing.T) {
 	c := testConfig(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("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),
+			Valu("a", OpConst64, c.config.Types.Int64, 14, nil),
+			Valu("b", OpConst64, c.config.Types.Int64, 26, nil),
+			Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "a", "b"),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Goto("exit")),
 		Bloc("exit",
 			Exit("mem")))
@@ -287,47 +294,48 @@ func TestArgs(t *testing.T) {
 }
 
 func TestEquiv(t *testing.T) {
+	cfg := testConfig(t)
 	equivalentCases := []struct{ f, g fun }{
 		// simple case
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit")),
 				Bloc("exit",
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit")),
 				Bloc("exit",
 					Exit("mem"))),
 		},
 		// block order changed
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit")),
 				Bloc("exit",
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit"))),
 		},
 	}
@@ -342,73 +350,73 @@ func TestEquiv(t *testing.T) {
 	differentCases := []struct{ f, g fun }{
 		// different shape
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Goto("exit")),
 				Bloc("exit",
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 					Exit("mem"))),
 		},
 		// value order changed
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("b", OpConst64, TypeInt64, 26, nil),
-					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("a", OpConst64, TypeInt64, 14, nil),
-					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
 					Exit("mem"))),
 		},
 		// value auxint different
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("a", OpConst64, TypeInt64, 26, nil),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 26, nil),
 					Exit("mem"))),
 		},
 		// value aux different
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("a", OpConst64, TypeInt64, 0, 14),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 0, 14),
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("entry",
 				Bloc("entry",
-					Valu("mem", OpInitMem, TypeMem, 0, nil),
-					Valu("a", OpConst64, TypeInt64, 0, 26),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 0, 26),
 					Exit("mem"))),
 		},
 		// value args different
 		{
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
 					Exit("mem"))),
-			Fun(testConfig(t), "entry",
+			cfg.Fun("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"),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("a", OpConst64, cfg.config.Types.Int64, 0, nil),
+					Valu("b", OpConst64, cfg.config.Types.Int64, 14, nil),
+					Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "b", "a"),
 					Exit("mem"))),
 		},
 	}
@@ -424,16 +432,17 @@ func TestEquiv(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	f := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
 			Exit("mem")))
-	v1 := f.f.ConstBool(0, TypeBool, false)
-	v2 := f.f.ConstBool(0, TypeBool, true)
+	v1 := f.f.ConstBool(src.NoXPos, c.config.Types.Bool, false)
+	v2 := f.f.ConstBool(src.NoXPos, c.config.Types.Bool, true)
 	f.f.freeValue(v1)
 	f.f.freeValue(v2)
-	v3 := f.f.ConstBool(0, TypeBool, false)
-	v4 := f.f.ConstBool(0, TypeBool, true)
+	v3 := f.f.ConstBool(src.NoXPos, c.config.Types.Bool, false)
+	v4 := f.f.ConstBool(src.NoXPos, c.config.Types.Bool, true)
 	if v3.AuxInt != 0 {
 		t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
 	}
diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
index d5940da..f00356a 100644
--- a/src/cmd/compile/internal/ssa/fuse.go
+++ b/src/cmd/compile/internal/ssa/fuse.go
@@ -8,7 +8,9 @@ package ssa
 func fuse(f *Func) {
 	for changed := true; changed; {
 		changed = false
-		for _, b := range f.Blocks {
+		// Fuse from end to beginning, to avoid quadratic behavior in fuseBlockPlain. See issue 13554.
+		for i := len(f.Blocks) - 1; i >= 0; i-- {
+			b := f.Blocks[i]
 			changed = fuseBlockIf(b) || changed
 			changed = fuseBlockPlain(b) || changed
 		}
@@ -121,7 +123,14 @@ func fuseBlockPlain(b *Block) bool {
 	// move all of b's values to c.
 	for _, v := range b.Values {
 		v.Block = c
-		c.Values = append(c.Values, v)
+	}
+	// Use whichever value slice is larger, in the hopes of avoiding growth.
+	// However, take care to avoid c.Values pointing to b.valstorage.
+	// See golang.org/issue/18602.
+	if cap(c.Values) >= cap(b.Values) || len(b.Values) <= len(b.valstorage) {
+		c.Values = append(c.Values, b.Values...)
+	} else {
+		c.Values = append(b.Values, c.Values...)
 	}
 
 	// replace b->c edge with preds(b) -> c
diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go
index b316a48..beae15a 100644
--- a/src/cmd/compile/internal/ssa/fuse_test.go
+++ b/src/cmd/compile/internal/ssa/fuse_test.go
@@ -1,23 +1,24 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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"),
+			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
 			If("bool1", "then", "exit")),
 		Bloc("then",
 			Goto("exit")),
@@ -35,17 +36,17 @@ func TestFuseEliminatesOneBranch(t *testing.T) {
 }
 
 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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"),
+			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
 			If("bool1", "then", "else")),
 		Bloc("then",
 			Goto("exit")),
@@ -68,17 +69,17 @@ func TestFuseEliminatesBothBranches(t *testing.T) {
 }
 
 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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"),
+			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
 			If("bool1", "then", "else")),
 		Bloc("then",
 			Goto("exit")),
@@ -102,11 +103,11 @@ func TestFuseHandlesPhis(t *testing.T) {
 }
 
 func TestFuseEliminatesEmptyBlocks(t *testing.T) {
-	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
-	fun := Fun(c, "entry",
+	c := testConfig(t)
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("z0")),
 		Bloc("z1",
 			Goto("z2")),
@@ -138,9 +139,9 @@ func BenchmarkFuse(b *testing.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),
+					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+					Valu("cond", OpArg, c.config.Types.Bool, 0, nil),
+					Valu("x", OpArg, c.config.Types.Int64, 0, nil),
 					Goto("exit")))
 
 			phiArgs := make([]string, 0, 2*n)
@@ -153,16 +154,15 @@ func BenchmarkFuse(b *testing.B) {
 			}
 			blocks = append(blocks,
 				Bloc("merge",
-					Valu("phi", OpPhi, TypeMem, 0, nil, phiArgs...),
+					Valu("phi", OpPhi, types.TypeMem, 0, nil, phiArgs...),
 					Goto("exit")),
 				Bloc("exit",
 					Exit("mem")))
 
 			b.ResetTimer()
 			for i := 0; i < b.N; i++ {
-				fun := Fun(c, "entry", blocks...)
+				fun := c.Fun("entry", blocks...)
 				fuse(fun.f)
-				fun.f.Free()
 			}
 		})
 	}
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index a3f2ecb..49fcd36 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -31,6 +31,8 @@
 
 (Mul32uhilo x y) -> (MULLQU x y)
 
+(Avg32u x y) -> (AVGLU x y)
+
 (Div32F x y) -> (DIVSS x y)
 (Div64F x y) -> (DIVSD x y)
 
@@ -43,10 +45,6 @@
 
 (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)
 
 (Mod32  x y) -> (MODL  x y)
 (Mod32u x y) -> (MODLU x y)
@@ -70,8 +68,8 @@
 (Neg32  x) -> (NEGL x)
 (Neg16  x) -> (NEGL x)
 (Neg8   x) -> (NEGL x)
-(Neg32F x) && !config.use387 -> (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
-(Neg64F x) && !config.use387 -> (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
+(Neg32F x) && !config.use387 -> (PXOR x (MOVSSconst <typ.Float32> [f2i(math.Copysign(0, -1))]))
+(Neg64F x) && !config.use387 -> (PXOR x (MOVSDconst <typ.Float64> [f2i(math.Copysign(0, -1))]))
 (Neg32F x) && config.use387 -> (FCHS x)
 (Neg64F x) && config.use387 -> (FCHS x)
 
@@ -102,7 +100,7 @@
 
 (Signmask x) -> (SARLconst x [31])
 (Zeromask <t> x) -> (XORLconst [-1] (SBBLcarrymask <t> (CMPLconst x [1])))
-(Slicemask <t> x) -> (XORLconst [-1] (SARLconst <t> (SUBLconst <t> x [1]) [31]))
+(Slicemask <t> x) -> (SARLconst (NEGL <t> x) [31])
 
 // Lowering truncation
 // Because we ignore high parts of registers, truncates are just copies.
@@ -120,6 +118,9 @@
 (Cvt32Fto64F x) -> (CVTSS2SD x)
 (Cvt64Fto32F x) -> (CVTSD2SS x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // Lowering shifts
 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
 //   result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
@@ -135,10 +136,6 @@
 (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])))
 
-(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)
-
 (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])))
@@ -259,47 +256,47 @@
 
 // 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 {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVSDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (MOVSSstore 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)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 -> (MOVLstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
 
 // Lowering moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVLstore dst (MOVLload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(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 [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBload [2] src mem)
 		(MOVWstore dst (MOVWload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+(Move [5] dst src mem) ->
 	(MOVBstore [4] dst (MOVBload [4] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+(Move [6] dst src mem) ->
 	(MOVWstore [4] dst (MOVWload [4] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+(Move [7] dst src mem) ->
 	(MOVLstore [3] dst (MOVLload [3] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 ->
+(Move [8] dst src mem) ->
 	(MOVLstore [4] dst (MOVLload [4] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
 
 // Adjust moves to be a multiple of 4 bytes.
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size()%4 != 0 ->
-	(Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%4]
-		(ADDLconst <dst.Type> dst [SizeAndAlign(s).Size()%4])
-		(ADDLconst <src.Type> src [SizeAndAlign(s).Size()%4])
+	&& s > 8 && s%4 != 0 ->
+	(Move [s-s%4]
+		(ADDLconst <dst.Type> dst [s%4])
+		(ADDLconst <src.Type> src [s%4])
 		(MOVLstore dst (MOVLload src mem) mem))
 
 // Medium copying uses a duff device.
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() <= 4*128 && SizeAndAlign(s).Size()%4 == 0
+	&& s > 8 && s <= 4*128 && s%4 == 0
 	&& !config.noDuffDevice ->
-	(DUFFCOPY [10*(128-SizeAndAlign(s).Size()/4)] dst src mem)
+	(DUFFCOPY [10*(128-s/4)] dst src mem)
 // 10 and 128 are magic constants.  10 is the number of bytes to encode:
 //	MOVL	(SI), CX
 //	ADDL	$4, SI
@@ -308,42 +305,42 @@
 // and 128 is the number of such blocks. See src/runtime/duff_386.s:duffcopy.
 
 // Large copying uses REP MOVSL.
-(Move [s] dst src mem) && (SizeAndAlign(s).Size() > 4*128 || config.noDuffDevice) && SizeAndAlign(s).Size()%4 == 0 ->
-	(REPMOVSL dst src (MOVLconst [SizeAndAlign(s).Size()/4]) mem)
+(Move [s] dst src mem) && (s > 4*128 || config.noDuffDevice) && s%4 == 0 ->
+	(REPMOVSL dst src (MOVLconst [s/4]) mem)
 
 // Lowering Zero instructions
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVWstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVLstoreconst [0] destptr mem)
+(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 [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,2)] destptr
 		(MOVWstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
+(Zero [5] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,4)] destptr
 		(MOVLstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
+(Zero [6] destptr mem) ->
 	(MOVWstoreconst [makeValAndOff(0,4)] destptr
 		(MOVLstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
+(Zero [7] destptr mem) ->
 	(MOVLstoreconst [makeValAndOff(0,3)] destptr
 		(MOVLstoreconst [0] destptr mem))
 
 // Strip off any fractional word zeroing.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size()%4 != 0 && SizeAndAlign(s).Size() > 4 ->
-	(Zero [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%4] (ADDLconst destptr [SizeAndAlign(s).Size()%4])
+(Zero [s] destptr mem) && s%4 != 0 && s > 4 ->
+	(Zero [s-s%4] (ADDLconst destptr [s%4])
 		(MOVLstoreconst [0] destptr mem))
 
 // Zero small numbers of words directly.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 ->
+(Zero [8] destptr mem) ->
 	(MOVLstoreconst [makeValAndOff(0,4)] destptr
 		(MOVLstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 12 ->
+(Zero [12] destptr mem) ->
 	(MOVLstoreconst [makeValAndOff(0,8)] destptr
 		(MOVLstoreconst [makeValAndOff(0,4)] destptr
 			(MOVLstoreconst [0] destptr mem)))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 ->
+(Zero [16] destptr mem) ->
 	(MOVLstoreconst [makeValAndOff(0,12)] destptr
 		(MOVLstoreconst [makeValAndOff(0,8)] destptr
 			(MOVLstoreconst [makeValAndOff(0,4)] destptr
@@ -351,20 +348,18 @@
 
 // Medium zeroing uses a duff device.
 (Zero [s] destptr mem)
-  && SizeAndAlign(s).Size() > 16
-  && SizeAndAlign(s).Size() <= 4*128
-  && SizeAndAlign(s).Size()%4 == 0
+  && s > 16 && s <= 4*128 && s%4 == 0
   && !config.noDuffDevice ->
-	(DUFFZERO [1*(128-SizeAndAlign(s).Size()/4)] destptr (MOVLconst [0]) mem)
+	(DUFFZERO [1*(128-s/4)] destptr (MOVLconst [0]) mem)
 // 1 and 128 are magic constants.  1 is the number of bytes to encode STOSL.
 // 128 is the number of STOSL instructions in duffzero.
 // See src/runtime/duff_386.s:duffzero.
 
 // Large zeroing uses REP STOSQ.
 (Zero [s] destptr mem)
-  && (SizeAndAlign(s).Size() > 4*128 || (config.noDuffDevice && SizeAndAlign(s).Size() > 16))
-  && SizeAndAlign(s).Size()%4 == 0 ->
-	(REPSTOSL destptr (MOVLconst [SizeAndAlign(s).Size()/4]) (MOVLconst [0]) mem)
+  && (s > 4*128 || (config.noDuffDevice && s > 16))
+  && s%4 == 0 ->
+	(REPSTOSL destptr (MOVLconst [s/4]) (MOVLconst [0]) mem)
 
 // Lowering constants
 (Const8   [val]) -> (MOVLconst [val])
@@ -378,8 +373,6 @@
 // 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
@@ -438,9 +431,7 @@
 
 // fold constants into instructions
 (ADDL x (MOVLconst [c])) -> (ADDLconst [c] x)
-(ADDL (MOVLconst [c]) x) -> (ADDLconst [c] x)
 (ADDLcarry x (MOVLconst [c])) -> (ADDLconstcarry [c] x)
-(ADDLcarry (MOVLconst [c]) x) -> (ADDLconstcarry [c] x)
 (ADCL x (MOVLconst [c]) f) -> (ADCLconst [c] x f)
 (ADCL (MOVLconst [c]) x f) -> (ADCLconst [c] x f)
 
@@ -450,10 +441,8 @@
 (SBBL x (MOVLconst [c]) f) -> (SBBLconst [c] x f)
 
 (MULL x (MOVLconst [c])) -> (MULLconst [c] x)
-(MULL (MOVLconst [c]) x) -> (MULLconst [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)
 
@@ -462,31 +451,19 @@
 (MULLconst [c] (MULLconst [d] x)) -> (MULLconst [int64(int32(c * d))] x)
 
 (ORL x (MOVLconst [c])) -> (ORLconst [c] x)
-(ORL (MOVLconst [c]) x) -> (ORLconst [c] x)
 
 (XORL x (MOVLconst [c])) -> (XORLconst [c] x)
-(XORL (MOVLconst [c]) x) -> (XORLconst [c] x)
 
 (SHLL x (MOVLconst [c])) -> (SHLLconst [c&31] x)
-(SHLL x (MOVLconst [c])) -> (SHLLconst [c&31] x)
-
-(SHRL x (MOVLconst [c])) -> (SHRLconst [c&31] x)
 (SHRL x (MOVLconst [c])) -> (SHRLconst [c&31] x)
+(SHRW x (MOVLconst [c])) && c&31 < 16 -> (SHRWconst [c&31] x)
+(SHRW _ (MOVLconst [c])) && c&31 >= 16 -> (MOVLconst [0])
+(SHRB x (MOVLconst [c])) && c&31 < 8 -> (SHRBconst [c&31] x)
+(SHRB _ (MOVLconst [c])) && c&31 >= 8 -> (MOVLconst [0])
 
-(SHRW x (MOVLconst [c])) -> (SHRWconst [c&31] x)
-(SHRW x (MOVLconst [c])) -> (SHRWconst [c&31] x)
-
-(SHRB x (MOVLconst [c])) -> (SHRBconst [c&31] x)
-(SHRB x (MOVLconst [c])) -> (SHRBconst [c&31] x)
-
-(SARL x (MOVLconst [c])) -> (SARLconst [c&31] x)
 (SARL x (MOVLconst [c])) -> (SARLconst [c&31] x)
-
-(SARW x (MOVLconst [c])) -> (SARWconst [c&31] x)
-(SARW x (MOVLconst [c])) -> (SARWconst [c&31] x)
-
-(SARB x (MOVLconst [c])) -> (SARBconst [c&31] x)
-(SARB x (MOVLconst [c])) -> (SARBconst [c&31] x)
+(SARW x (MOVLconst [c])) -> (SARWconst [min(c&31,15)] x)
+(SARB x (MOVLconst [c])) -> (SARBconst [min(c&31,7)] x)
 
 (SARL x (ANDLconst [31] y)) -> (SARL x y)
 
@@ -494,10 +471,36 @@
 
 (SHRL x (ANDLconst [31] y)) -> (SHRL x y)
 
+// Rotate instructions
+
+(ADDL (SHLLconst [c] x) (SHRLconst [d] x)) && d == 32-c -> (ROLLconst [c] x)
+( ORL (SHLLconst [c] x) (SHRLconst [d] x)) && d == 32-c -> (ROLLconst [c] x)
+(XORL (SHLLconst [c] x) (SHRLconst [d] x)) && d == 32-c -> (ROLLconst [c] x)
+
+(ADDL <t> (SHLLconst x [c]) (SHRWconst x [d])) && c < 16 && d == 16-c && t.Size() == 2 -> (ROLWconst x [c])
+( ORL <t> (SHLLconst x [c]) (SHRWconst x [d])) && c < 16 && d == 16-c && t.Size() == 2 -> (ROLWconst x [c])
+(XORL <t> (SHLLconst x [c]) (SHRWconst x [d])) && c < 16 && d == 16-c && t.Size() == 2 -> (ROLWconst x [c])
+
+(ADDL <t> (SHLLconst x [c]) (SHRBconst x [d])) && c < 8 && d == 8-c && t.Size() == 1 -> (ROLBconst x [c])
+( ORL <t> (SHLLconst x [c]) (SHRBconst x [d])) && c < 8 && d == 8-c && t.Size() == 1 -> (ROLBconst x [c])
+(XORL <t> (SHLLconst x [c]) (SHRBconst x [d])) && c < 8 && d == 8-c && t.Size() == 1 -> (ROLBconst x [c])
+
 (ROLLconst [c] (ROLLconst [d] x)) -> (ROLLconst [(c+d)&31] x)
 (ROLWconst [c] (ROLWconst [d] x)) -> (ROLWconst [(c+d)&15] x)
 (ROLBconst [c] (ROLBconst [d] x)) -> (ROLBconst [(c+d)& 7] x)
 
+// Constant shift simplifications
+
+(SHLLconst x [0]) -> x
+(SHRLconst x [0]) -> x
+(SARLconst x [0]) -> x
+
+(SHRWconst x [0]) -> x
+(SARWconst x [0]) -> x
+
+(SHRBconst x [0]) -> x
+(SARBconst x [0]) -> x
+
 (ROLLconst [0] x) -> x
 (ROLWconst [0] x) -> x
 (ROLBconst [0] x) -> x
@@ -541,9 +544,9 @@
 (MULLconst [c] x) && isPowerOfTwo(c-2) && c >= 34 -> (LEAL2 (SHLLconst <v.Type> [log2(c-2)] x) x)
 (MULLconst [c] x) && isPowerOfTwo(c-4) && c >= 68 -> (LEAL4 (SHLLconst <v.Type> [log2(c-4)] x) x)
 (MULLconst [c] x) && isPowerOfTwo(c-8) && c >= 136 -> (LEAL8 (SHLLconst <v.Type> [log2(c-8)] x) x)
-(MULLconst [c] x) && c%3 == 0 && isPowerOfTwo(c/3)-> (SHLLconst [log2(c/3)] (LEAL2 <v.Type> x x))
-(MULLconst [c] x) && c%5 == 0 && isPowerOfTwo(c/5)-> (SHLLconst [log2(c/5)] (LEAL4 <v.Type> x x))
-(MULLconst [c] x) && c%9 == 0 && isPowerOfTwo(c/9)-> (SHLLconst [log2(c/9)] (LEAL8 <v.Type> x x))
+(MULLconst [c] x) && c%3 == 0 && isPowerOfTwo(c/3) -> (SHLLconst [log2(c/3)] (LEAL2 <v.Type> x x))
+(MULLconst [c] x) && c%5 == 0 && isPowerOfTwo(c/5) -> (SHLLconst [log2(c/5)] (LEAL4 <v.Type> x x))
+(MULLconst [c] x) && c%9 == 0 && isPowerOfTwo(c/9) -> (SHLLconst [log2(c/9)] (LEAL8 <v.Type> x x))
 
 // combine add/shift into LEAL
 (ADDL x (SHLLconst [3] y)) -> (LEAL8 x y)
@@ -551,19 +554,16 @@
 (ADDL x (SHLLconst [1] y)) -> (LEAL2 x y)
 (ADDL x (ADDL y y)) -> (LEAL2 x y)
 (ADDL x (ADDL x y)) -> (LEAL2 y x)
-(ADDL x (ADDL y x)) -> (LEAL2 y x)
 
 // combine ADDL/ADDLconst into LEAL1
 (ADDLconst [c] (ADDL x y)) -> (LEAL1 [c] x y)
 (ADDL (ADDLconst [c] x) y) -> (LEAL1 [c] x y)
-(ADDL x (ADDLconst [c] y)) -> (LEAL1 [c] x y)
 
 // fold ADDL into LEAL
 (ADDLconst [c] (LEAL [d] {s} x)) && is32Bit(c+d) -> (LEAL [c+d] {s} x)
 (LEAL [c] {s} (ADDLconst [d] x)) && is32Bit(c+d) -> (LEAL [c+d] {s} x)
 (LEAL [c] {s} (ADDL x y)) && x.Op != OpSB && y.Op != OpSB -> (LEAL1 [c] {s} x y)
 (ADDL x (LEAL [c] {s} y)) && x.Op != OpSB && y.Op != OpSB -> (LEAL1 [c] {s} x y)
-(ADDL (LEAL [c] {s} x) y) && x.Op != OpSB && y.Op != OpSB -> (LEAL1 [c] {s} x y)
 
 // fold ADDLconst into LEALx
 (ADDLconst [c] (LEAL1 [d] {s} x y)) && is32Bit(c+d) -> (LEAL1 [c+d] {s} x y)
@@ -571,7 +571,6 @@
 (ADDLconst [c] (LEAL4 [d] {s} x y)) && is32Bit(c+d) -> (LEAL4 [c+d] {s} x y)
 (ADDLconst [c] (LEAL8 [d] {s} x y)) && is32Bit(c+d) -> (LEAL8 [c+d] {s} x y)
 (LEAL1 [c] {s} (ADDLconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAL1 [c+d] {s} x y)
-(LEAL1 [c] {s} x (ADDLconst [d] y)) && is32Bit(c+d)   && y.Op != OpSB -> (LEAL1 [c+d] {s} x y)
 (LEAL2 [c] {s} (ADDLconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAL2 [c+d] {s} x y)
 (LEAL2 [c] {s} x (ADDLconst [d] y)) && is32Bit(c+2*d) && y.Op != OpSB -> (LEAL2 [c+2*d] {s} x y)
 (LEAL4 [c] {s} (ADDLconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAL4 [c+d] {s} x y)
@@ -581,12 +580,8 @@
 
 // fold shifts into LEALx
 (LEAL1 [c] {s} x (SHLLconst [1] y)) -> (LEAL2 [c] {s} x y)
-(LEAL1 [c] {s} (SHLLconst [1] x) y) -> (LEAL2 [c] {s} y x)
 (LEAL1 [c] {s} x (SHLLconst [2] y)) -> (LEAL4 [c] {s} x y)
-(LEAL1 [c] {s} (SHLLconst [2] x) y) -> (LEAL4 [c] {s} y x)
 (LEAL1 [c] {s} x (SHLLconst [3] y)) -> (LEAL8 [c] {s} x y)
-(LEAL1 [c] {s} (SHLLconst [3] x) y) -> (LEAL8 [c] {s} y x)
-
 (LEAL2 [c] {s} x (SHLLconst [1] y)) -> (LEAL4 [c] {s} x y)
 (LEAL2 [c] {s} x (SHLLconst [2] y)) -> (LEAL8 [c] {s} x y)
 (LEAL4 [c] {s} x (SHLLconst [1] y)) -> (LEAL8 [c] {s} x y)
@@ -620,10 +615,12 @@
 (MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
 (MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <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
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
+(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
 (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLSX x)
+(MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLSX x)
 
 // Fold extensions and ANDs together.
 (MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
@@ -870,8 +867,6 @@
 // LEAL into LEAL1
 (LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
        (LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
-(LEAL1 [off1] {sym1} x (LEAL [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB ->
-       (LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
 
 // LEAL1 into LEAL
 (LEAL [off1] {sym1} (LEAL1 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
@@ -1113,8 +1108,9 @@
 // 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)))
+(ORL                  x0:(MOVBload [i0] {s} p mem)
+    s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
+  && i1 == i0+1
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
@@ -1122,12 +1118,14 @@
   && clobber(x0)
   && clobber(x1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+  -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
 
 (ORL o0:(ORL
-                       x0:(MOVWload [i]   {s} p mem)
-    s0:(SHLLconst [16] x1:(MOVBload [i+2] {s} p mem)))
-    s1:(SHLLconst [24] x2:(MOVBload [i+3] {s} p mem)))
+                       x0:(MOVWload [i0] {s} p mem)
+    s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem)))
+    s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)))
+  && i2 == i0+2
+  && i3 == i0+3
   && x0.Uses == 1
   && x1.Uses == 1
   && x2.Uses == 1
@@ -1141,10 +1139,11 @@
   && clobber(s0)
   && clobber(s1)
   && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p mem)
+  -> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
 
-(ORL                  x0:(MOVBloadidx1 [i]   {s} p idx mem)
-    s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+(ORL                  x0:(MOVBloadidx1 [i0] {s} p idx mem)
+    s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+  && i1==i0+1
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
@@ -1152,12 +1151,14 @@
   && clobber(x0)
   && clobber(x1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+  -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 
 (ORL o0:(ORL
-                       x0:(MOVWloadidx1 [i]   {s} p idx mem)
-    s0:(SHLLconst [16] x1:(MOVBloadidx1 [i+2] {s} p idx mem)))
-    s1:(SHLLconst [24] x2:(MOVBloadidx1 [i+3] {s} p idx mem)))
+                       x0:(MOVWloadidx1 [i0] {s} p idx mem)
+    s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)))
+    s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+  && i2 == i0+2
+  && i3 == i0+3
   && x0.Uses == 1
   && x1.Uses == 1
   && x2.Uses == 1
@@ -1171,7 +1172,7 @@
   && clobber(s0)
   && clobber(s1)
   && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+  -> @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
 
 // Combine constant stores into larger (unaligned) stores.
 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
index d09f497..8965d62 100644
--- a/src/cmd/compile/internal/ssa/gen/386Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -157,21 +157,21 @@ func init() {
 		{name: "DIVSS", argLength: 2, reg: fp21, asm: "DIVSS", resultInArg0: true, usesScratch: true},                    // fp32 div
 		{name: "DIVSD", argLength: 2, reg: fp21, asm: "DIVSD", resultInArg0: true},                                       // fp64 div
 
-		{name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true}, // fp32 load
-		{name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true}, // 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", faultOnNilArg0: true}, // fp32 store
-		{name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true}, // 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
+		{name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load
+		{name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // 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", symEffect: "Read"},                // fp32 load indexed by i
+		{name: "MOVSSloadidx4", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff", symEffect: "Read"},                // fp32 load indexed by 4*i
+		{name: "MOVSDloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff", symEffect: "Read"},                // fp64 load indexed by i
+		{name: "MOVSDloadidx8", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff", symEffect: "Read"},                // fp64 load indexed by 8*i
+
+		{name: "MOVSSstore", argLength: 3, reg: fpstore, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp32 store
+		{name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp64 store
+		{name: "MOVSSstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff", symEffect: "Write"},                // fp32 indexed by i store
+		{name: "MOVSSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff", symEffect: "Write"},                // fp32 indexed by 4i store
+		{name: "MOVSDstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff", symEffect: "Write"},                // fp64 indexed by i store
+		{name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff", symEffect: "Write"},                // fp64 indexed by 8i store
 
 		// binary ops
 		{name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true},                // arg0 + arg1
@@ -193,14 +193,12 @@ func init() {
 		{name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1
 		{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 * auxint
 
-		{name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULW", argLength: 2, reg: gp21hmul, asm: "IMULW", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULB", argLength: 2, reg: gp21hmul, asm: "IMULB", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULWU", argLength: 2, reg: gp21hmul, asm: "MULW", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULBU", argLength: 2, reg: gp21hmul, asm: "MULB", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULL", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULLU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
 
-		{name: "MULLQU", argLength: 2, reg: gp21mul, asm: "MULL", clobberFlags: true}, // arg0 * arg1, high 32 in result[0], low 32 in result[1]
+		{name: "MULLQU", argLength: 2, reg: gp21mul, commutative: true, asm: "MULL", clobberFlags: true}, // arg0 * arg1, high 32 in result[0], low 32 in result[1]
+
+		{name: "AVGLU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 + arg1) / 2 as unsigned, all 32 result bits
 
 		{name: "DIVL", argLength: 2, reg: gp11div, asm: "IDIVL", clobberFlags: true}, // arg0 / arg1
 		{name: "DIVW", argLength: 2, reg: gp11div, asm: "IDIVW", clobberFlags: true}, // arg0 / arg1
@@ -231,9 +229,9 @@ func init() {
 		{name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f32
 		{name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f64
 
-		{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: "TESTL", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
+		{name: "TESTW", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
+		{name: "TESTB", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) 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
@@ -246,15 +244,15 @@ func init() {
 		{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 32
 		{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 32
 		{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
-		{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
-		{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // unsigned arg0 >> auxint, shift amount 0-31
+		{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-15
+		{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // unsigned arg0 >> auxint, shift amount 0-7
 
 		{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
 		{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
 		{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
 		{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
-		{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
-		{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // signed arg0 >> auxint, shift amount 0-31
+		{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-15
+		{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // signed arg0 >> auxint, shift amount 0-7
 
 		{name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-31
 		{name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-15
@@ -315,49 +313,49 @@ func init() {
 
 		{name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true}, // exclusive or, applied to X regs for float negation.
 
-		{name: "LEAL", argLength: 1, reg: gp11sb, aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux
-		{name: "LEAL1", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + arg1 + auxint + aux
-		{name: "LEAL2", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 2*arg1 + auxint + aux
-		{name: "LEAL4", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 4*arg1 + auxint + aux
-		{name: "LEAL8", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 8*arg1 + auxint + aux
+		{name: "LEAL", argLength: 1, reg: gp11sb, aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxint + offset encoded in aux
+		{name: "LEAL1", argLength: 2, reg: gp21sb, commutative: true, aux: "SymOff", symEffect: "Addr"},      // arg0 + arg1 + auxint + aux
+		{name: "LEAL2", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                         // arg0 + 2*arg1 + auxint + aux
+		{name: "LEAL4", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                         // arg0 + 4*arg1 + auxint + aux
+		{name: "LEAL8", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                         // arg0 + 8*arg1 + auxint + aux
 		// Note: LEAL{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", faultOnNilArg0: true},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVBLSXload", argLength: 2, reg: gpload, asm: "MOVBLSX", aux: "SymOff", faultOnNilArg0: true},             // ditto, sign extend to int32
-		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVWLSXload", argLength: 2, reg: gpload, asm: "MOVWLSX", aux: "SymOff", faultOnNilArg0: true},             // ditto, sign extend to int32
-		{name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store byte in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVBLSXload", argLength: 2, reg: gpload, asm: "MOVBLSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int32
+		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVWLSXload", argLength: 2, reg: gpload, asm: "MOVWLSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int32
+		{name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store byte in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 4 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: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", aux: "SymOff", symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", aux: "SymOff", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", aux: "SymOff", symEffect: "Read"},                    // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", aux: "SymOff", symEffect: "Read"},    // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", aux: "SymOff", symEffect: "Read"},                       // load 4 bytes from arg0+4*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: "MOVBstoreidx1", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVB", aux: "SymOff", symEffect: "Write"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx1", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVW", aux: "SymOff", symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff", symEffect: "Write"},                    // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx1", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVL", aux: "SymOff", symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx4", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff", symEffect: "Write"},                    // store 4 bytes in arg2 to arg0+4*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", faultOnNilArg0: true}, // 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", faultOnNilArg0: true}, // store low 2 bytes of ...
-		{name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true}, // store low 4 bytes of ...
+		{name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 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", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
+		{name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 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: "MOVBstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // 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", symEffect: "Write"}, // store low 2 bytes of ... arg1 ...
+		{name: "MOVWstoreconstidx2", argLength: 3, reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 2 bytes of ... 2*arg1 ...
+		{name: "MOVLstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 4 bytes of ... arg1 ...
+		{name: "MOVLstoreconstidx4", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 4 bytes of ... 4*arg1 ...
 
 		// arg0 = pointer to start of memory to zero
 		// arg1 = value to store (will always be zero)
@@ -373,6 +371,7 @@ func init() {
 				clobbers: buildReg("DI CX"),
 				// Note: CX is only clobbered when dynamic linking.
 			},
+			faultOnNilArg0: true,
 		},
 
 		// arg0 = address of memory to zero
@@ -387,12 +386,11 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
 				clobbers: buildReg("DI CX"),
 			},
+			faultOnNilArg0: true,
 		},
 
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                             // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                          // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                               // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                  // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// arg0 = destination pointer
@@ -408,7 +406,9 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("SI")},
 				clobbers: buildReg("DI SI CX"), // uses CX as a temporary
 			},
-			clobberFlags: true,
+			clobberFlags:   true,
+			faultOnNilArg0: true,
+			faultOnNilArg1: true,
 		},
 
 		// arg0 = destination pointer
@@ -423,6 +423,8 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")},
 				clobbers: buildReg("DI SI CX"),
 			},
+			faultOnNilArg0: true,
+			faultOnNilArg1: true,
 		},
 
 		// (InvertFlags (CMPL a b)) == (CMPL b a)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 5b4649c..5887a94 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -44,10 +44,6 @@
 (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)
 
 (Mul64uhilo x y) -> (MULQU2 x y)
 (Div128u xhi xlo y) -> (DIVQU2 xhi xlo y)
@@ -82,8 +78,8 @@
 (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))]))
+(Neg32F x) -> (PXOR x (MOVSSconst <typ.Float32> [f2i(math.Copysign(0, -1))]))
+(Neg64F x) -> (PXOR x (MOVSDconst <typ.Float64> [f2i(math.Copysign(0, -1))]))
 
 (Com64 x) -> (NOTQ x)
 (Com32 x) -> (NOTL x)
@@ -101,12 +97,20 @@
 (OffPtr [off] ptr) && config.PtrSize == 4 -> (ADDLconst [off] ptr)
 
 // Lowering other arithmetic
-(Ctz64 <t> x) -> (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <TypeFlags> (BSFQ x)))
-(Ctz32 <t> x) -> (CMOVLEQ (Select0 <t> (BSFL x)) (MOVLconst <t> [32]) (Select1 <TypeFlags> (BSFL x)))
+(Ctz64 <t> x) -> (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <types.TypeFlags> (BSFQ x)))
+(Ctz32 x) -> (Select0 (BSFQ (ORQ <typ.UInt64> (MOVQconst [1<<32]) x)))
+
+(BitLen64 <t> x) -> (ADDQconst [1] (CMOVQEQ <t> (Select0 <t> (BSRQ x)) (MOVQconst <t> [-1]) (Select1 <types.TypeFlags> (BSRQ x))))
+(BitLen32 x) -> (BitLen64 (MOVLQZX <typ.UInt64> x))
 
 (Bswap64 x) -> (BSWAPQ x)
 (Bswap32 x) -> (BSWAPL x)
 
+(PopCount64 x) -> (POPCNTQ x)
+(PopCount32 x) -> (POPCNTL x)
+(PopCount16 x) -> (POPCNTL (MOVWQZX <typ.UInt32> x))
+(PopCount8 x) -> (POPCNTL (MOVBQZX <typ.UInt32> x))
+
 (Sqrt x) -> (SQRTSD x)
 
 // Lowering extension
@@ -125,7 +129,7 @@
 (ZeroExt16to64 x) -> (MOVWQZX x)
 (ZeroExt32to64 x) -> (MOVLQZX x)
 
-(Slicemask <t> x) -> (XORQconst [-1] (SARQconst <t> (SUBQconst <t> x [1]) [63]))
+(Slicemask <t> x) -> (SARQconst (NEGQ <t> x) [63])
 
 // Lowering truncation
 // Because we ignore high parts of registers, truncates are just copies.
@@ -150,6 +154,9 @@
 (Cvt32Fto64F x) -> (CVTSS2SD x)
 (Cvt64Fto32F x) -> (CVTSD2SS x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // Lowering shifts
 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
 //   result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
@@ -173,11 +180,6 @@
 (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])))
@@ -303,56 +305,56 @@
 
 // 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 {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVSDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && 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)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 -> (MOVQstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 -> (MOVLstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
 
 // Lowering moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVLstore dst (MOVLload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 -> (MOVQstore dst (MOVQload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 -> (MOVOstore dst (MOVOload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(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 [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+(Move [5] dst src mem) ->
 	(MOVBstore [4] dst (MOVBload [4] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+(Move [6] dst src mem) ->
 	(MOVWstore [4] dst (MOVWload [4] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+(Move [7] dst src mem) ->
 	(MOVLstore [3] dst (MOVLload [3] src mem)
 		(MOVLstore dst (MOVLload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() < 16 ->
-	(MOVQstore [SizeAndAlign(s).Size()-8] dst (MOVQload [SizeAndAlign(s).Size()-8] src mem)
+(Move [s] dst src mem) && s > 8 && s < 16 ->
+	(MOVQstore [s-8] dst (MOVQload [s-8] src mem)
 		(MOVQstore dst (MOVQload src mem) mem))
 
 // Adjust moves to be a multiple of 16 bytes.
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 <= 8 ->
-	(Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%16]
-		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()%16])
-		(OffPtr <src.Type> src [SizeAndAlign(s).Size()%16])
+	&& s > 16 && s%16 != 0 && s%16 <= 8 ->
+	(Move [s-s%16]
+		(OffPtr <dst.Type> dst [s%16])
+		(OffPtr <src.Type> src [s%16])
 		(MOVQstore dst (MOVQload src mem) mem))
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 > 8 ->
-	(Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%16]
-		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()%16])
-		(OffPtr <src.Type> src [SizeAndAlign(s).Size()%16])
+	&& s > 16 && s%16 != 0 && s%16 > 8 ->
+	(Move [s-s%16]
+		(OffPtr <dst.Type> dst [s%16])
+		(OffPtr <src.Type> src [s%16])
 		(MOVOstore dst (MOVOload src mem) mem))
 
 // Medium copying uses a duff device.
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() >= 32 && SizeAndAlign(s).Size() <= 16*64 && SizeAndAlign(s).Size()%16 == 0
+	&& s >= 32 && s <= 16*64 && s%16 == 0
 	&& !config.noDuffDevice ->
-	(DUFFCOPY [14*(64-SizeAndAlign(s).Size()/16)] dst src mem)
+	(DUFFCOPY [14*(64-s/16)] dst src mem)
 // 14 and 64 are magic constants.  14 is the number of bytes to encode:
 //	MOVUPS	(SI), X0
 //	ADDQ	$16, SI
@@ -361,43 +363,43 @@
 // and 64 is the number of such blocks. See src/runtime/duff_amd64.s:duffcopy.
 
 // Large copying uses REP MOVSQ.
-(Move [s] dst src mem) && (SizeAndAlign(s).Size() > 16*64 || config.noDuffDevice) && SizeAndAlign(s).Size()%8 == 0 ->
-	(REPMOVSQ dst src (MOVQconst [SizeAndAlign(s).Size()/8]) mem)
+(Move [s] dst src mem) && (s > 16*64 || config.noDuffDevice) && s%8 == 0 ->
+	(REPMOVSQ dst src (MOVQconst [s/8]) mem)
 
 // Lowering Zero instructions
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVWstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVLstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 -> (MOVQstoreconst [0] destptr mem)
+(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 [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,2)] destptr
 		(MOVWstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
+(Zero [5] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,4)] destptr
 		(MOVLstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
+(Zero [6] destptr mem) ->
 	(MOVWstoreconst [makeValAndOff(0,4)] destptr
 		(MOVLstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
+(Zero [7] destptr mem) ->
 	(MOVLstoreconst [makeValAndOff(0,3)] destptr
 		(MOVLstoreconst [0] destptr mem))
 
 // Strip off any fractional word zeroing.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8 ->
-	(Zero [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8] (OffPtr <destptr.Type> destptr [SizeAndAlign(s).Size()%8])
+(Zero [s] destptr mem) && s%8 != 0 && s > 8 ->
+	(Zero [s-s%8] (OffPtr <destptr.Type> destptr [s%8])
 		(MOVQstoreconst [0] destptr mem))
 
 // Zero small numbers of words directly.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 ->
+(Zero [16] destptr mem) ->
 	(MOVQstoreconst [makeValAndOff(0,8)] destptr
 		(MOVQstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 24 ->
+(Zero [24] destptr mem) ->
 	(MOVQstoreconst [makeValAndOff(0,16)] destptr
 		(MOVQstoreconst [makeValAndOff(0,8)] destptr
 			(MOVQstoreconst [0] destptr mem)))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 32 ->
+(Zero [32] destptr mem) ->
 	(MOVQstoreconst [makeValAndOff(0,24)] destptr
 		(MOVQstoreconst [makeValAndOff(0,16)] destptr
 			(MOVQstoreconst [makeValAndOff(0,8)] destptr
@@ -405,18 +407,18 @@
 
 // Medium zeroing uses a duff device.
 (Zero [s] destptr mem)
-	&& SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size()%16 != 0
+	&& s <= 1024 && s%8 == 0 && s%16 != 0
 	&& !config.noDuffDevice ->
-	(Zero [SizeAndAlign(s).Size()-8] (OffPtr <destptr.Type> [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+	(Zero [s-8] (OffPtr <destptr.Type> [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
 (Zero [s] destptr mem)
-	&& SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice ->
-	(DUFFZERO [SizeAndAlign(s).Size()] destptr (MOVOconst [0]) mem)
+	&& s <= 1024 && s%16 == 0 && !config.noDuffDevice ->
+	(DUFFZERO [s] destptr (MOVOconst [0]) mem)
 
 // Large zeroing uses REP STOSQ.
 (Zero [s] destptr mem)
-	&& (SizeAndAlign(s).Size() > 1024 || (config.noDuffDevice && SizeAndAlign(s).Size() > 32))
-	&& SizeAndAlign(s).Size()%8 == 0 ->
-	(REPSTOSQ destptr (MOVQconst [SizeAndAlign(s).Size()/8]) (MOVQconst [0]) mem)
+	&& (s > 1024 || (config.noDuffDevice && s > 32))
+	&& s%8 == 0 ->
+	(REPSTOSQ destptr (MOVQconst [s/8]) (MOVQconst [0]) mem)
 
 // Lowering constants
 (Const8   [val]) -> (MOVLconst [val])
@@ -432,8 +434,6 @@
 // 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
@@ -477,22 +477,22 @@
 
 // Atomic stores.  We use XCHG to prevent the hardware reordering a subsequent load.
 // TODO: most runtime uses of atomic stores don't need that property.  Use normal stores for those?
-(AtomicStore32 ptr val mem) -> (Select1 (XCHGL <MakeTuple(config.Frontend().TypeUInt32(),TypeMem)> val ptr mem))
-(AtomicStore64 ptr val mem) -> (Select1 (XCHGQ <MakeTuple(config.Frontend().TypeUInt64(),TypeMem)> val ptr mem))
-(AtomicStorePtrNoWB ptr val mem) && config.PtrSize == 8 -> (Select1 (XCHGQ <MakeTuple(config.Frontend().TypeBytePtr(),TypeMem)> val ptr mem))
-(AtomicStorePtrNoWB ptr val mem) && config.PtrSize == 4 -> (Select1 (XCHGL <MakeTuple(config.Frontend().TypeBytePtr(),TypeMem)> val ptr mem))
+(AtomicStore32 ptr val mem) -> (Select1 (XCHGL <types.NewTuple(typ.UInt32,types.TypeMem)> val ptr mem))
+(AtomicStore64 ptr val mem) -> (Select1 (XCHGQ <types.NewTuple(typ.UInt64,types.TypeMem)> val ptr mem))
+(AtomicStorePtrNoWB ptr val mem) && config.PtrSize == 8 -> (Select1 (XCHGQ <types.NewTuple(typ.BytePtr,types.TypeMem)> val ptr mem))
+(AtomicStorePtrNoWB ptr val mem) && config.PtrSize == 4 -> (Select1 (XCHGL <types.NewTuple(typ.BytePtr,types.TypeMem)> val ptr mem))
 
 // Atomic exchanges.
 (AtomicExchange32 ptr val mem) -> (XCHGL val ptr mem)
 (AtomicExchange64 ptr val mem) -> (XCHGQ val ptr mem)
 
 // Atomic adds.
-(AtomicAdd32 ptr val mem) -> (AddTupleFirst32 (XADDLlock val ptr mem) val)
-(AtomicAdd64 ptr val mem) -> (AddTupleFirst64 (XADDQlock val ptr mem) val)
-(Select0 <t> (AddTupleFirst32 tuple val)) -> (ADDL val (Select0 <t> tuple))
-(Select1     (AddTupleFirst32 tuple _  )) -> (Select1 tuple)
-(Select0 <t> (AddTupleFirst64 tuple val)) -> (ADDQ val (Select0 <t> tuple))
-(Select1     (AddTupleFirst64 tuple _  )) -> (Select1 tuple)
+(AtomicAdd32 ptr val mem) -> (AddTupleFirst32 val (XADDLlock val ptr mem))
+(AtomicAdd64 ptr val mem) -> (AddTupleFirst64 val (XADDQlock val ptr mem))
+(Select0 <t> (AddTupleFirst32 val tuple)) -> (ADDL val (Select0 <t> tuple))
+(Select1     (AddTupleFirst32   _ tuple)) -> (Select1 tuple)
+(Select0 <t> (AddTupleFirst64 val tuple)) -> (ADDQ val (Select0 <t> tuple))
+(Select1     (AddTupleFirst64   _ tuple)) -> (Select1 tuple)
 
 // Atomic compare and swap.
 (AtomicCompareAndSwap32 ptr old new_ mem) -> (CMPXCHGLlock ptr old new_ mem)
@@ -520,6 +520,45 @@
 (NE (TESTB (SETA  cmp) (SETA  cmp)) yes no) -> (UGT cmp yes no)
 (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
 
+// Recognize bit tests: a&(1<<b) != 0 for b suitably bounded
+// Note that ULT and SETB check the carry flag; they are identical to CS and SETCS.
+// Same, mutatis mutandis, for UGE and SETAE, and CC and SETCC.
+(NE (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (ULT (BTL x y))
+(EQ (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (UGE (BTL x y))
+(NE (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (ULT (BTQ x y))
+(EQ (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (UGE (BTQ x y))
+(NE (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (ULT (BTLconst [log2(c)] x))
+(EQ (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (UGE (BTLconst [log2(c)] x))
+(NE (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (ULT (BTQconst [log2(c)] x))
+(EQ (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (UGE (BTQconst [log2(c)] x))
+(NE (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (ULT (BTQconst [log2(c)] x))
+(EQ (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (UGE (BTQconst [log2(c)] x))
+(SETNE (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (SETB  (BTL x y))
+(SETEQ (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (SETAE (BTL x y))
+(SETNE (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (SETB  (BTQ x y))
+(SETEQ (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (SETAE (BTQ x y))
+(SETNE (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (SETB  (BTLconst [log2(c)] x))
+(SETEQ (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (SETAE (BTLconst [log2(c)] x))
+(SETNE (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETB  (BTQconst [log2(c)] x))
+(SETEQ (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETAE (BTQconst [log2(c)] x))
+(SETNE (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETB  (BTQconst [log2(c)] x))
+(SETEQ (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETAE (BTQconst [log2(c)] x))
+
+// Fold boolean negation into SETcc.
+(XORLconst [1] (SETNE x)) -> (SETEQ x)
+(XORLconst [1] (SETEQ x)) -> (SETNE x)
+(XORLconst [1] (SETL  x)) -> (SETGE x)
+(XORLconst [1] (SETGE x)) -> (SETL  x)
+(XORLconst [1] (SETLE x)) -> (SETG  x)
+(XORLconst [1] (SETG  x)) -> (SETLE x)
+(XORLconst [1] (SETB  x)) -> (SETAE x)
+(XORLconst [1] (SETAE x)) -> (SETB  x)
+(XORLconst [1] (SETBE x)) -> (SETA  x)
+(XORLconst [1] (SETA  x)) -> (SETBE x)
+
+// Convert BTQconst to BTLconst if possible. It has a shorter encoding.
+(BTQconst [c] x) && c < 32 -> (BTLconst [c] x)
+
 // 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)
@@ -527,14 +566,12 @@
 (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))
+// (SETNEF x) -> (ORQ (SETNE <typ.Int8> x) (SETNAN <typ.Int8> x))
+// (SETEQF x) -> (ANDQ (SETEQ <typ.Int8> x) (SETORD <typ.Int8> 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]))
@@ -542,14 +579,10 @@
 (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)
@@ -561,14 +594,10 @@
 (MULQconst [c] (MULQconst [d] x)) && is32Bit(c*d) -> (MULQconst [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)
@@ -582,11 +611,15 @@
 (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)
+(SHRW x (MOVQconst [c])) && c&31 < 16 -> (SHRWconst [c&31] x)
+(SHRW x (MOVLconst [c])) && c&31 < 16 -> (SHRWconst [c&31] x)
+(SHRW _ (MOVQconst [c])) && c&31 >= 16 -> (MOVLconst [0])
+(SHRW _ (MOVLconst [c])) && c&31 >= 16 -> (MOVLconst [0])
 
-(SHRB x (MOVQconst [c])) -> (SHRBconst [c&31] x)
-(SHRB x (MOVLconst [c])) -> (SHRBconst [c&31] x)
+(SHRB x (MOVQconst [c])) && c&31 < 8 -> (SHRBconst [c&31] x)
+(SHRB x (MOVLconst [c])) && c&31 < 8 -> (SHRBconst [c&31] x)
+(SHRB _ (MOVQconst [c])) && c&31 >= 8 -> (MOVLconst [0])
+(SHRB _ (MOVLconst [c])) && c&31 >= 8 -> (MOVLconst [0])
 
 (SARQ x (MOVQconst [c])) -> (SARQconst [c&63] x)
 (SARQ x (MOVLconst [c])) -> (SARQconst [c&63] x)
@@ -594,30 +627,208 @@
 (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)
+(SARW x (MOVQconst [c])) -> (SARWconst [min(c&31,15)] x)
+(SARW x (MOVLconst [c])) -> (SARWconst [min(c&31,15)] x)
+
+(SARB x (MOVQconst [c])) -> (SARBconst [min(c&31,7)] x)
+(SARB x (MOVLconst [c])) -> (SARBconst [min(c&31,7)] x)
+
+// Operations which don't affect the low 6/5 bits of the shift amount are NOPs.
+(SHLQ x (ADDQconst [c] y)) && c & 63 == 0 -> (SHLQ x y)
+(SHRQ x (ADDQconst [c] y)) && c & 63 == 0 -> (SHRQ x y)
+(SARQ x (ADDQconst [c] y)) && c & 63 == 0 -> (SARQ x y)
+(SHLQ x (NEGQ <t> (ADDQconst [c] y))) && c & 63 == 0 -> (SHLQ x (NEGQ <t> y))
+(SHRQ x (NEGQ <t> (ADDQconst [c] y))) && c & 63 == 0 -> (SHRQ x (NEGQ <t> y))
+(SARQ x (NEGQ <t> (ADDQconst [c] y))) && c & 63 == 0 -> (SARQ x (NEGQ <t> y))
+(SHLQ x (ANDQconst [c] y)) && c & 63 == 63 -> (SHLQ x y)
+(SHRQ x (ANDQconst [c] y)) && c & 63 == 63 -> (SHRQ x y)
+(SARQ x (ANDQconst [c] y)) && c & 63 == 63 -> (SARQ x y)
+(SHLQ x (NEGQ <t> (ANDQconst [c] y))) && c & 63 == 63 -> (SHLQ x (NEGQ <t> y))
+(SHRQ x (NEGQ <t> (ANDQconst [c] y))) && c & 63 == 63 -> (SHRQ x (NEGQ <t> y))
+(SARQ x (NEGQ <t> (ANDQconst [c] y))) && c & 63 == 63 -> (SARQ x (NEGQ <t> y))
+
+(SHLL x (ADDQconst [c] y)) && c & 31 == 0 -> (SHLL x y)
+(SHRL x (ADDQconst [c] y)) && c & 31 == 0 -> (SHRL x y)
+(SARL x (ADDQconst [c] y)) && c & 31 == 0 -> (SARL x y)
+(SHLL x (NEGQ <t> (ADDQconst [c] y))) && c & 31 == 0 -> (SHLL x (NEGQ <t> y))
+(SHRL x (NEGQ <t> (ADDQconst [c] y))) && c & 31 == 0 -> (SHRL x (NEGQ <t> y))
+(SARL x (NEGQ <t> (ADDQconst [c] y))) && c & 31 == 0 -> (SARL x (NEGQ <t> y))
+(SHLL x (ANDQconst [c] y)) && c & 31 == 31 -> (SHLL x y)
+(SHRL x (ANDQconst [c] y)) && c & 31 == 31 -> (SHRL x y)
+(SARL x (ANDQconst [c] y)) && c & 31 == 31 -> (SARL x y)
+(SHLL x (NEGQ <t> (ANDQconst [c] y))) && c & 31 == 31 -> (SHLL x (NEGQ <t> y))
+(SHRL x (NEGQ <t> (ANDQconst [c] y))) && c & 31 == 31 -> (SHRL x (NEGQ <t> y))
+(SARL x (NEGQ <t> (ANDQconst [c] y))) && c & 31 == 31 -> (SARL x (NEGQ <t> y))
+
+(SHLQ x (ADDLconst [c] y)) && c & 63 == 0 -> (SHLQ x y)
+(SHRQ x (ADDLconst [c] y)) && c & 63 == 0 -> (SHRQ x y)
+(SARQ x (ADDLconst [c] y)) && c & 63 == 0 -> (SARQ x y)
+(SHLQ x (NEGL <t> (ADDLconst [c] y))) && c & 63 == 0 -> (SHLQ x (NEGL <t> y))
+(SHRQ x (NEGL <t> (ADDLconst [c] y))) && c & 63 == 0 -> (SHRQ x (NEGL <t> y))
+(SARQ x (NEGL <t> (ADDLconst [c] y))) && c & 63 == 0 -> (SARQ x (NEGL <t> y))
+(SHLQ x (ANDLconst [c] y)) && c & 63 == 63 -> (SHLQ x y)
+(SHRQ x (ANDLconst [c] y)) && c & 63 == 63 -> (SHRQ x y)
+(SARQ x (ANDLconst [c] y)) && c & 63 == 63 -> (SARQ x y)
+(SHLQ x (NEGL <t> (ANDLconst [c] y))) && c & 63 == 63 -> (SHLQ x (NEGL <t> y))
+(SHRQ x (NEGL <t> (ANDLconst [c] y))) && c & 63 == 63 -> (SHRQ x (NEGL <t> y))
+(SARQ x (NEGL <t> (ANDLconst [c] y))) && c & 63 == 63 -> (SARQ x (NEGL <t> y))
+
+(SHLL x (ADDLconst [c] y)) && c & 31 == 0 -> (SHLL x y)
+(SHRL x (ADDLconst [c] y)) && c & 31 == 0 -> (SHRL x y)
+(SARL x (ADDLconst [c] y)) && c & 31 == 0 -> (SARL x y)
+(SHLL x (NEGL <t> (ADDLconst [c] y))) && c & 31 == 0 -> (SHLL x (NEGL <t> y))
+(SHRL x (NEGL <t> (ADDLconst [c] y))) && c & 31 == 0 -> (SHRL x (NEGL <t> y))
+(SARL x (NEGL <t> (ADDLconst [c] y))) && c & 31 == 0 -> (SARL x (NEGL <t> y))
+(SHLL x (ANDLconst [c] y)) && c & 31 == 31 -> (SHLL x y)
+(SHRL x (ANDLconst [c] y)) && c & 31 == 31 -> (SHRL x y)
+(SARL x (ANDLconst [c] y)) && c & 31 == 31 -> (SARL x y)
+(SHLL x (NEGL <t> (ANDLconst [c] y))) && c & 31 == 31 -> (SHLL x (NEGL <t> y))
+(SHRL x (NEGL <t> (ANDLconst [c] y))) && c & 31 == 31 -> (SHRL x (NEGL <t> y))
+(SARL x (NEGL <t> (ANDLconst [c] y))) && c & 31 == 31 -> (SARL x (NEGL <t> y))
+
+// Constant rotate instructions
+(ADDQ (SHLQconst x [c]) (SHRQconst x [d])) && d==64-c -> (ROLQconst x [c])
+( ORQ (SHLQconst x [c]) (SHRQconst x [d])) && d==64-c -> (ROLQconst x [c])
+(XORQ (SHLQconst x [c]) (SHRQconst x [d])) && d==64-c -> (ROLQconst x [c])
+
+(ADDL (SHLLconst x [c]) (SHRLconst x [d])) && d==32-c -> (ROLLconst x [c])
+( ORL (SHLLconst x [c]) (SHRLconst x [d])) && d==32-c -> (ROLLconst x [c])
+(XORL (SHLLconst x [c]) (SHRLconst x [d])) && d==32-c -> (ROLLconst x [c])
+
+(ADDL <t> (SHLLconst x [c]) (SHRWconst x [d])) && d==16-c && c < 16 && t.Size() == 2 -> (ROLWconst x [c])
+( ORL <t> (SHLLconst x [c]) (SHRWconst x [d])) && d==16-c && c < 16 && t.Size() == 2 -> (ROLWconst x [c])
+(XORL <t> (SHLLconst x [c]) (SHRWconst x [d])) && d==16-c && c < 16 && t.Size() == 2 -> (ROLWconst x [c])
+
+(ADDL <t> (SHLLconst x [c]) (SHRBconst x [d])) && d==8-c  && c < 8 && t.Size() == 1 -> (ROLBconst x [c])
+( ORL <t> (SHLLconst x [c]) (SHRBconst x [d])) && d==8-c  && c < 8 && t.Size() == 1 -> (ROLBconst x [c])
+(XORL <t> (SHLLconst x [c]) (SHRBconst x [d])) && d==8-c  && c < 8 && t.Size() == 1 -> (ROLBconst x [c])
 
 (ROLQconst [c] (ROLQconst [d] x)) -> (ROLQconst [(c+d)&63] x)
 (ROLLconst [c] (ROLLconst [d] x)) -> (ROLLconst [(c+d)&31] x)
 (ROLWconst [c] (ROLWconst [d] x)) -> (ROLWconst [(c+d)&15] x)
 (ROLBconst [c] (ROLBconst [d] x)) -> (ROLBconst [(c+d)& 7] x)
 
-(ROLQconst [0] x) -> x
-(ROLLconst [0] x) -> x
-(ROLWconst [0] x) -> x
-(ROLBconst [0] x) -> x
+// Non-constant rotates.
+// We want to issue a rotate when the Go source contains code like
+//     y &= 63
+//     x << y | x >> (64-y)
+// The shift rules above convert << to SHLx and >> to SHRx.
+// SHRx converts its shift argument from 64-y to -y.
+// A tricky situation occurs when y==0. Then the original code would be:
+//     x << 0 | x >> 64
+// But x >> 64 is 0, not x. So there's an additional mask that is ANDed in
+// to force the second term to 0. We don't need that mask, but we must match
+// it in order to strip it out.
+(ORQ (SHLQ x y) (ANDQ (SHRQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])))) -> (ROLQ x y)
+(ORQ (SHLQ x y) (ANDQ (SHRQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])))) -> (ROLQ x y)
+(ORQ (SHRQ x y) (ANDQ (SHLQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])))) -> (RORQ x y)
+(ORQ (SHRQ x y) (ANDQ (SHLQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])))) -> (RORQ x y)
+
+(ORL (SHLL x y) (ANDL (SHRL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])))) -> (ROLL x y)
+(ORL (SHLL x y) (ANDL (SHRL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])))) -> (ROLL x y)
+(ORL (SHRL x y) (ANDL (SHLL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])))) -> (RORL x y)
+(ORL (SHRL x y) (ANDL (SHLL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])))) -> (RORL x y)
+
+// Help with rotate detection
+(CMPQconst (NEGQ (ADDQconst [-16] (ANDQconst [15] _))) [32]) -> (FlagLT_ULT)
+(CMPQconst (NEGQ (ADDQconst [ -8] (ANDQconst  [7] _))) [32]) -> (FlagLT_ULT)
+
+(ORL (SHLL x (ANDQconst y [15]))
+     (ANDL (SHRW x (NEGQ (ADDQconst (ANDQconst y [15]) [-16])))
+           (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [15]) [-16])) [16]))))
+  && v.Type.Size() == 2
+  -> (ROLW x y)
+(ORL (SHLL x (ANDLconst y [15]))
+     (ANDL (SHRW x (NEGL (ADDLconst (ANDLconst y [15]) [-16])))
+           (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [15]) [-16])) [16]))))
+  && v.Type.Size() == 2
+  -> (ROLW x y)
+(ORL (SHRW x (ANDQconst y [15]))
+     (SHLL x (NEGQ (ADDQconst (ANDQconst y [15]) [-16]))))
+  && v.Type.Size() == 2
+  -> (RORW x y)
+(ORL (SHRW x (ANDLconst y [15]))
+     (SHLL x (NEGL (ADDLconst (ANDLconst y [15]) [-16]))))
+  && v.Type.Size() == 2
+  -> (RORW x y)
+
+(ORL (SHLL x (ANDQconst y [ 7]))
+     (ANDL (SHRB x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])))
+           (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])) [ 8]))))
+  && v.Type.Size() == 1
+  -> (ROLB x y)
+(ORL (SHLL x (ANDLconst y [ 7]))
+     (ANDL (SHRB x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])))
+           (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])) [ 8]))))
+  && v.Type.Size() == 1
+  -> (ROLB x y)
+(ORL (SHRB x (ANDQconst y [ 7]))
+     (SHLL x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8]))))
+  && v.Type.Size() == 1
+  -> (RORB x y)
+(ORL (SHRB x (ANDLconst y [ 7]))
+     (SHLL x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8]))))
+  && v.Type.Size() == 1
+  -> (RORB x y)
+
+// rotate left negative = rotate right
+(ROLQ x (NEGQ y)) -> (RORQ x y)
+(ROLQ x (NEGL y)) -> (RORQ x y)
+(ROLL x (NEGQ y)) -> (RORL x y)
+(ROLL x (NEGL y)) -> (RORL x y)
+(ROLW x (NEGQ y)) -> (RORW x y)
+(ROLW x (NEGL y)) -> (RORW x y)
+(ROLB x (NEGQ y)) -> (RORB x y)
+(ROLB x (NEGL y)) -> (RORB x y)
+
+// rotate right negative = rotate left
+(RORQ x (NEGQ y)) -> (ROLQ x y)
+(RORQ x (NEGL y)) -> (ROLQ x y)
+(RORL x (NEGQ y)) -> (ROLL x y)
+(RORL x (NEGL y)) -> (ROLL x y)
+(RORW x (NEGQ y)) -> (ROLW x y)
+(RORW x (NEGL y)) -> (ROLW x y)
+(RORB x (NEGQ y)) -> (ROLB x y)
+(RORB x (NEGL y)) -> (ROLB x y)
+
+// rotate by constants
+(ROLQ x (MOVQconst [c])) -> (ROLQconst [c&63] x)
+(ROLQ x (MOVLconst [c])) -> (ROLQconst [c&63] x)
+(ROLL x (MOVQconst [c])) -> (ROLLconst [c&31] x)
+(ROLL x (MOVLconst [c])) -> (ROLLconst [c&31] x)
+(ROLW x (MOVQconst [c])) -> (ROLWconst [c&15] x)
+(ROLW x (MOVLconst [c])) -> (ROLWconst [c&15] x)
+(ROLB x (MOVQconst [c])) -> (ROLBconst [c&7 ] x)
+(ROLB x (MOVLconst [c])) -> (ROLBconst [c&7 ] x)
+
+(RORQ x (MOVQconst [c])) -> (ROLQconst [(-c)&63] x)
+(RORQ x (MOVLconst [c])) -> (ROLQconst [(-c)&63] x)
+(RORL x (MOVQconst [c])) -> (ROLLconst [(-c)&31] x)
+(RORL x (MOVLconst [c])) -> (ROLLconst [(-c)&31] x)
+(RORW x (MOVQconst [c])) -> (ROLWconst [(-c)&15] x)
+(RORW x (MOVLconst [c])) -> (ROLWconst [(-c)&15] x)
+(RORB x (MOVQconst [c])) -> (ROLBconst [(-c)&7 ] x)
+(RORB x (MOVLconst [c])) -> (ROLBconst [(-c)&7 ] x)
+
+// Constant shift simplifications
+(SHLQconst x [0]) -> x
+(SHRQconst x [0]) -> x
+(SARQconst x [0]) -> x
+
+(SHLLconst x [0]) -> x
+(SHRLconst x [0]) -> x
+(SARLconst x [0]) -> x
+
+(SHRWconst x [0]) -> x
+(SARWconst x [0]) -> x
+
+(SHRBconst x [0]) -> x
+(SARBconst x [0]) -> x
+
+(ROLQconst x [0]) -> x
+(ROLLconst x [0]) -> x
+(ROLWconst x [0]) -> x
+(ROLBconst x [0]) -> x
 
 // 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
@@ -667,9 +878,9 @@
 (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))
+(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)
@@ -677,19 +888,16 @@
 (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)
@@ -697,7 +905,6 @@
 (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)
@@ -707,12 +914,8 @@
 
 // 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)
@@ -762,11 +965,14 @@
 (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
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
+(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
+(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQZX x)
 (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQSX x)
+(MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQSX x)
+(MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQSX x)
 
 // Fold extensions and ANDs together.
 (MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
@@ -1054,8 +1260,6 @@
 // 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) ->
@@ -1118,9 +1322,11 @@
 (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)
+(CMPQconst (ANDLconst _ [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.
@@ -1319,6 +1525,7 @@
 (ORL x x) -> x
 (XORQ x x) -> (MOVQconst [0])
 (XORL x x) -> (MOVLconst [0])
+(NEGQ (ADDQconst [c] (NEGQ x))) && c != -(1<<31) -> (ADDQconst [-c] x)
 
 // checking AND against 0.
 (CMPQconst (ANDQ x y) [0]) -> (TESTQ x y)
@@ -1330,6 +1537,12 @@
 (CMPWconst (ANDLconst [c] x) [0]) -> (TESTWconst [int64(int16(c))] x)
 (CMPBconst (ANDLconst [c] x) [0]) -> (TESTBconst [int64(int8(c))] x)
 
+// Convert TESTx to TESTxconst if possible.
+(TESTQ (MOVQconst [c]) x) && is32Bit(c) -> (TESTQconst [c] x)
+(TESTL (MOVLconst [c]) x) -> (TESTLconst [c] x)
+(TESTW (MOVLconst [c]) x) -> (TESTWconst [c] x)
+(TESTB (MOVLconst [c]) x) -> (TESTBconst [c] x)
+
 // TEST %reg,%reg is shorter than CMP
 (CMPQconst x [0]) -> (TESTQ x x)
 (CMPLconst x [0]) -> (TESTL x x)
@@ -1339,334 +1552,561 @@
 // 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)))
+
+// Little-endian loads
+
+(ORL                  x0:(MOVBload [i0] {s} p mem)
+    sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
+
+(ORQ                  x0:(MOVBload [i0] {s} p mem)
+    sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
+
+(ORL                   x0:(MOVWload [i0] {s} p mem)
+    sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem)))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
+
+(ORQ                   x0:(MOVWload [i0] {s} p mem)
+    sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem)))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
+
+(ORQ                   x0:(MOVLload [i0] {s} p mem)
+    sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem)))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem)
+
+(ORL
+    s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
+    or:(ORL
+        s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
+
+(ORQ
+    s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
+    or:(ORQ
+        s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
+
+(ORQ
+    s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem))
+    or:(ORQ
+        s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem))
+	y))
+  && i1 == i0+2
+  && j1 == j0+16
+  && j0 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
   && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
+
+// Little-endian indexed loads
 
-(ORL o0:(ORL
-                       x0:(MOVWload [i]   {s} p mem)
-    s0:(SHLLconst [16] x1:(MOVBload [i+2] {s} p mem)))
-    s1:(SHLLconst [24] x2:(MOVBload [i+3] {s} p mem)))
+(ORL                  x0:(MOVBloadidx1 [i0] {s} p idx mem)
+    sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
+
+(ORQ                  x0:(MOVBloadidx1 [i0] {s} p idx mem)
+    sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
+
+(ORL                   x0:(MOVWloadidx1 [i0] {s} p idx mem)
+    sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
+
+(ORQ                   x0:(MOVWloadidx1 [i0] {s} p idx mem)
+    sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
+
+(ORQ                   x0:(MOVLloadidx1 [i0] {s} p idx mem)
+    sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
+
+(ORL
+    s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
+    or:(ORL
+        s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
+
+(ORQ
+    s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
+    or:(ORQ
+        s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
+
+(ORQ
+    s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem))
+    or:(ORQ
+        s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))
+	y))
+  && i1 == i0+2
+  && j1 == j0+16
+  && j0 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
+  && s1.Uses == 1
+  && or.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)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
+
+// Big-endian loads
 
-(ORL o0:(ORL
-                       x0:(MOVWloadidx1 [i]   {s} p idx mem)
-    s0:(SHLLconst [16] x1:(MOVBloadidx1 [i+2] {s} p idx mem)))
-    s1:(SHLLconst [24] x2:(MOVBloadidx1 [i+3] {s} p idx mem)))
+(ORL
+                       x1:(MOVBload [i1] {s} p mem)
+    sh:(SHLLconst [8]  x0:(MOVBload [i0] {s} p mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
+
+(ORQ
+                       x1:(MOVBload [i1] {s} p mem)
+    sh:(SHLQconst [8]  x0:(MOVBload [i0] {s} p mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
+
+(ORL
+                        r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
+    sh:(SHLLconst [16]  r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
+
+(ORQ
+                        r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
+    sh:(SHLQconst [16]  r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
+
+(ORQ
+                        r1:(BSWAPL x1:(MOVLload [i1] {s} p mem))
+    sh:(SHLQconst [32]  r0:(BSWAPL x0:(MOVLload [i0] {s} p mem))))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem))
+
+(ORL
+    s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
+    or:(ORL
+        s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
+
+(ORQ
+    s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
+    or:(ORQ
+        s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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 byte loads + shifts into larger (unaligned) loads + bswap
-(ORL o1:(ORL o0:(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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
+
+(ORQ
+    s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem)))
+    or:(ORQ
+        s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))
+	y))
+  && i1 == i0+2
+  && j1 == j0-16
+  && j1 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
-  && x3.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && s2.Uses == 1
-  && o0.Uses == 1
-  && o1.Uses == 1
-  && mergePoint(b,x0,x1,x2,x3) != nil
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
-  && clobber(x3)
+  && clobber(r0)
+  && clobber(r1)
   && clobber(s0)
   && clobber(s1)
-  && clobber(s2)
-  && clobber(o0)
-  && clobber(o1)
-  -> @mergePoint(b,x0,x1,x2,x3) (BSWAPL <v.Type> (MOVLload [i-3] {s} p mem))
-
-(ORL o1:(ORL o0:(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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
+
+// Big-endian indexed loads
+
+(ORL
+                       x1:(MOVBloadidx1 [i1] {s} p idx mem)
+    sh:(SHLLconst [8]  x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
+
+(ORQ
+                       x1:(MOVBloadidx1 [i1] {s} p idx mem)
+    sh:(SHLQconst [8]  x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
+
+(ORL
+                        r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))
+    sh:(SHLLconst [16]  r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+
+(ORQ
+                        r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))
+    sh:(SHLQconst [16]  r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+
+(ORQ
+                        r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem))
+    sh:(SHLQconst [32]  r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+
+(ORL
+    s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
+    or:(ORL
+        s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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) (BSWAPL <v.Type> (MOVLloadidx1 <v.Type> [i-3] {s} p idx mem))
-
-(ORQ o5:(ORQ o4:(ORQ o3:(ORQ o2:(ORQ o1:(ORQ o0:(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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+
+(ORQ
+    s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
+    or:(ORQ
+        s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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) (BSWAPQ <v.Type> (MOVQload [i-7] {s} p mem))
-
-(ORQ o5:(ORQ o4:(ORQ o3:(ORQ o2:(ORQ o1:(ORQ o0:(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)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+
+(ORQ
+    s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem)))
+    or:(ORQ
+        s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	y))
+  && i1 == i0+2
+  && j1 == j0-16
+  && j1 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
-  && x3.Uses == 1
-  && x4.Uses == 1
-  && x5.Uses == 1
-  && x6.Uses == 1
-  && x7.Uses == 1
+  && r0.Uses == 1
+  && r1.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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
-  && clobber(x3)
-  && clobber(x4)
-  && clobber(x5)
-  && clobber(x6)
-  && clobber(x7)
+  && clobber(r0)
+  && clobber(r1)
   && 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) (BSWAPQ <v.Type> (MOVQloadidx1 <v.Type> [i-7] {s} p idx mem))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+
+// Combine 2 byte stores + shift into rolw 8 + word store
+(MOVBstore [i] {s} p w
+  x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
+  && x0.Uses == 1
+  && clobber(x0)
+  -> (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
+
+(MOVBstoreidx1 [i] {s} p idx w
+  x0:(MOVBstoreidx1 [i-1] {s} p idx (SHRWconst [8] w) mem))
+  && x0.Uses == 1
+  && clobber(x0)
+  -> (MOVWstoreidx1 [i-1] {s} p idx (ROLWconst <w.Type> [8] w) mem)
 
 // Combine stores + shifts into bswap and larger (unaligned) stores
 (MOVBstore [i] {s} p w
@@ -1681,6 +2121,18 @@
   && clobber(x2)
   -> (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
 
+(MOVBstoreidx1 [i] {s} p idx w
+  x2:(MOVBstoreidx1 [i-1] {s} p idx (SHRLconst [8] w)
+  x1:(MOVBstoreidx1 [i-2] {s} p idx (SHRLconst [16] w)
+  x0:(MOVBstoreidx1 [i-3] {s} p idx (SHRLconst [24] w) mem))))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  -> (MOVLstoreidx1 [i-3] {s} p idx (BSWAPL <w.Type> w) mem)
+
 (MOVBstore [i] {s} p w
   x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w)
   x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w)
@@ -1705,6 +2157,30 @@
   && clobber(x6)
   -> (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
 
+(MOVBstoreidx1 [i] {s} p idx w
+  x6:(MOVBstoreidx1 [i-1] {s} p idx (SHRQconst [8] w)
+  x5:(MOVBstoreidx1 [i-2] {s} p idx (SHRQconst [16] w)
+  x4:(MOVBstoreidx1 [i-3] {s} p idx (SHRQconst [24] w)
+  x3:(MOVBstoreidx1 [i-4] {s} p idx (SHRQconst [32] w)
+  x2:(MOVBstoreidx1 [i-5] {s} p idx (SHRQconst [40] w)
+  x1:(MOVBstoreidx1 [i-6] {s} p idx (SHRQconst [48] w)
+  x0:(MOVBstoreidx1 [i-7] {s} p idx (SHRQconst [56] w) mem))))))))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && x3.Uses == 1
+  && x4.Uses == 1
+  && x5.Uses == 1
+  && x6.Uses == 1
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  && clobber(x3)
+  && clobber(x4)
+  && clobber(x5)
+  && clobber(x6)
+  -> (MOVQstoreidx1 [i-7] {s} p idx (BSWAPQ <w.Type> w) mem)
+
 // Combine constant stores into larger (unaligned) stores.
 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
   && x.Uses == 1
@@ -1867,6 +2343,25 @@
 (MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
 	(MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 
+// Merge load and op
+// TODO: add indexed variants?
+(ADDQ x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ADDQmem x [off] {sym} ptr mem)
+(ADDL x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ADDLmem x [off] {sym} ptr mem)
+(SUBQ x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (SUBQmem x [off] {sym} ptr mem)
+(SUBL x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (SUBLmem x [off] {sym} ptr mem)
+(ANDQ x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ANDQmem x [off] {sym} ptr mem)
+(ANDL x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ANDLmem x [off] {sym} ptr mem)
+(ORQ  x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ORQmem x [off] {sym} ptr mem)
+(ORL  x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ORLmem x [off] {sym} ptr mem)
+(XORQ x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (XORQmem x [off] {sym} ptr mem)
+(XORL x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (XORLmem x [off] {sym} ptr mem)
+(ADDSD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ADDSDmem x [off] {sym} ptr mem)
+(ADDSS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (ADDSSmem x [off] {sym} ptr mem)
+(SUBSD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (SUBSDmem x [off] {sym} ptr mem)
+(SUBSS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (SUBSSmem x [off] {sym} ptr mem)
+(MULSD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (MULSDmem x [off] {sym} ptr mem)
+(MULSS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (MULSSmem x [off] {sym} ptr mem)
+
 // Merge ADDQconst and LEAQ into atomic loads.
 (MOVQatomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
 	(MOVQatomicload [off1+off2] {sym} ptr mem)
@@ -1900,3 +2395,23 @@
 	(CMPXCHGQlock [off1+off2] {sym} ptr old new_ mem)
 (CMPXCHGLlock [off1] {sym} (ADDQconst [off2] ptr) old new_ mem) && is32Bit(off1+off2) ->
 	(CMPXCHGLlock [off1+off2] {sym} ptr old new_ mem)
+
+// We don't need the conditional move if we know the arg of BSF is not zero.
+(CMOVQEQ x _ (Select1 (BSFQ (ORQconst [c] _)))) && c != 0 -> x
+// Extension is unnecessary for trailing zeros.
+(BSFQ (ORQconst <t> [1<<8] (MOVBQZX x))) -> (BSFQ (ORQconst <t> [1<<8] x))
+(BSFQ (ORQconst <t> [1<<16] (MOVWQZX x))) -> (BSFQ (ORQconst <t> [1<<16] x))
+
+// Redundant sign/zero extensions
+(MOVLQSX x:(MOVLQSX _)) -> x
+(MOVLQSX x:(MOVWQSX _)) -> x
+(MOVLQSX x:(MOVBQSX _)) -> x
+(MOVWQSX x:(MOVWQSX _)) -> x
+(MOVWQSX x:(MOVBQSX _)) -> x
+(MOVBQSX x:(MOVBQSX _)) -> x
+(MOVLQZX x:(MOVLQZX _)) -> x
+(MOVLQZX x:(MOVWQZX _)) -> x
+(MOVLQZX x:(MOVBQZX _)) -> x
+(MOVWQZX x:(MOVWQZX _)) -> x
+(MOVWQZX x:(MOVBQZX _)) -> x
+(MOVBQZX x:(MOVBQZX _)) -> x
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 016ed4f..28131db 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -127,17 +127,19 @@ func init() {
 		flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
 
 		gpload    = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
+		gp21load  = regInfo{inputs: []regMask{gp, 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}}
-		gpstorexchg     = regInfo{inputs: []regMask{gp, gp, 0}, outputs: []regMask{gp}}
+		gpstorexchg     = regInfo{inputs: []regMask{gp, gpspsb, 0}, outputs: []regMask{gp}}
 		cmpxchg         = regInfo{inputs: []regMask{gp, ax, gp, 0}, outputs: []regMask{gp, 0}, clobbers: ax}
 
 		fp01     = regInfo{inputs: nil, outputs: fponly}
 		fp21     = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+		fp21load = regInfo{inputs: []regMask{fp, gpspsb, 0}, outputs: fponly}
 		fpgp     = regInfo{inputs: fponly, outputs: gponly}
 		gpfp     = regInfo{inputs: gponly, outputs: fponly}
 		fp11     = regInfo{inputs: fponly, outputs: fponly}
@@ -161,21 +163,28 @@ func init() {
 		{name: "DIVSS", argLength: 2, reg: fp21, asm: "DIVSS", resultInArg0: true},                    // fp32 div
 		{name: "DIVSD", argLength: 2, reg: fp21, asm: "DIVSD", resultInArg0: true},                    // fp64 div
 
-		{name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true}, // fp32 load
-		{name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true}, // 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", faultOnNilArg0: true}, // fp32 store
-		{name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true}, // 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
+		{name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load
+		{name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // 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", symEffect: "Read"},                // fp32 load indexed by i
+		{name: "MOVSSloadidx4", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff", symEffect: "Read"},                // fp32 load indexed by 4*i
+		{name: "MOVSDloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff", symEffect: "Read"},                // fp64 load indexed by i
+		{name: "MOVSDloadidx8", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff", symEffect: "Read"},                // fp64 load indexed by 8*i
+
+		{name: "MOVSSstore", argLength: 3, reg: fpstore, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp32 store
+		{name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp64 store
+		{name: "MOVSSstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff", symEffect: "Write"},                // fp32 indexed by i store
+		{name: "MOVSSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff", symEffect: "Write"},                // fp32 indexed by 4i store
+		{name: "MOVSDstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff", symEffect: "Write"},                // fp64 indexed by i store
+		{name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff", symEffect: "Write"},                // fp64 indexed by 8i store
+
+		{name: "ADDSDmem", argLength: 3, reg: fp21load, asm: "ADDSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+		{name: "ADDSSmem", argLength: 3, reg: fp21load, asm: "ADDSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+		{name: "SUBSSmem", argLength: 3, reg: fp21load, asm: "SUBSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+		{name: "SUBSDmem", argLength: 3, reg: fp21load, asm: "SUBSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+		{name: "MULSSmem", argLength: 3, reg: fp21load, asm: "MULSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+		{name: "MULSDmem", argLength: 3, reg: fp21load, asm: "MULSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
 
 		// binary ops
 		{name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true, clobberFlags: true},                // arg0 + arg1
@@ -193,14 +202,10 @@ func init() {
 		{name: "MULQconst", argLength: 1, reg: gp11, asm: "IMULQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 * auxint
 		{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 * auxint
 
-		{name: "HMULQ", argLength: 2, reg: gp21hmul, asm: "IMULQ", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULW", argLength: 2, reg: gp21hmul, asm: "IMULW", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULB", argLength: 2, reg: gp21hmul, asm: "IMULB", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULQU", argLength: 2, reg: gp21hmul, asm: "MULQ", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULWU", argLength: 2, reg: gp21hmul, asm: "MULW", clobberFlags: true}, // (arg0 * arg1) >> width
-		{name: "HMULBU", argLength: 2, reg: gp21hmul, asm: "MULB", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULQ", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULQ", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULL", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULQU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULQ", clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "HMULLU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
 
 		{name: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
 
@@ -211,8 +216,8 @@ func init() {
 		{name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
 		{name: "DIVWU", argLength: 2, reg: gp11div, typ: "(UInt16,UInt16)", asm: "DIVW", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
 
-		{name: "MULQU2", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}, asm: "MULQ", clobberFlags: true},     // arg0 * arg1, returns (hi, lo)
-		{name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)
+		{name: "MULQU2", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}, commutative: true, asm: "MULQ", clobberFlags: true}, // arg0 * arg1, returns (hi, lo)
+		{name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true},                // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)
 
 		{name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1
 		{name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1
@@ -241,43 +246,67 @@ func init() {
 		{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: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"},                   // test whether bit arg0 % 32 in arg1 is set
+		{name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"},                   // test whether bit arg0 % 64 in arg1 is set
+		{name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32
+		{name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64
+
+		{name: "TESTQ", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
+		{name: "TESTL", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
+		{name: "TESTW", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
+		{name: "TESTB", argLength: 2, reg: gp2flags, commutative: true, 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, clobberFlags: true},               // arg0 << arg1, shift amount is mod 64
-		{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true},               // arg0 << arg1, shift amount is mod 32
-		{name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 << auxint, shift amount 0-63
-		{name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 << auxint, shift amount 0-31
+		{name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true, clobberFlags: true},              // arg0 << arg1, shift amount is mod 64
+		{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true},              // arg0 << arg1, shift amount is mod 32
+		{name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 << auxint, shift amount 0-63
+		{name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: 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, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 64
-		{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 32
-		{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 32
-		{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true},               // unsigned arg0 >> arg1, shift amount is mod 32
-		{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
-		{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
-		{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
-		{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // unsigned arg0 >> auxint, shift amount 0-31
-
-		{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 64
-		{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
-		{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
-		{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true},               // signed arg0 >> arg1, shift amount is mod 32
-		{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
-		{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
-		{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
-		{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // signed arg0 >> auxint, shift amount 0-31
-
-		{name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-63
-		{name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-31
-		{name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-15
-		{name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true},  // arg0 rotate left auxint, rotate amount 0-7
+		{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true},              // unsigned arg0 >> arg1, shift amount is mod 64
+		{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true},              // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true},              // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true},              // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
+		{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
+		{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-15
+		{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-7
+
+		{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true},              // signed arg0 >> arg1, shift amount is mod 64
+		{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true},              // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true},              // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true},              // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
+		{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
+		{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-15
+		{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-7
+
+		{name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true},              // arg0 rotate left arg1 bits.
+		{name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true},              // arg0 rotate left arg1 bits.
+		{name: "ROLW", argLength: 2, reg: gp21shift, asm: "ROLW", resultInArg0: true, clobberFlags: true},              // arg0 rotate left arg1 bits.
+		{name: "ROLB", argLength: 2, reg: gp21shift, asm: "ROLB", resultInArg0: true, clobberFlags: true},              // arg0 rotate left arg1 bits.
+		{name: "RORQ", argLength: 2, reg: gp21shift, asm: "RORQ", resultInArg0: true, clobberFlags: true},              // arg0 rotate right arg1 bits.
+		{name: "RORL", argLength: 2, reg: gp21shift, asm: "RORL", resultInArg0: true, clobberFlags: true},              // arg0 rotate right arg1 bits.
+		{name: "RORW", argLength: 2, reg: gp21shift, asm: "RORW", resultInArg0: true, clobberFlags: true},              // arg0 rotate right arg1 bits.
+		{name: "RORB", argLength: 2, reg: gp21shift, asm: "RORB", resultInArg0: true, clobberFlags: true},              // arg0 rotate right arg1 bits.
+		{name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-63
+		{name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-31
+		{name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-15
+		{name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-7
+
+		{name: "ADDLmem", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "ADDQmem", argLength: 3, reg: gp21load, asm: "ADDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "SUBQmem", argLength: 3, reg: gp21load, asm: "SUBQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "SUBLmem", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "ANDLmem", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "ANDQmem", argLength: 3, reg: gp21load, asm: "ANDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "ORQmem", argLength: 3, reg: gp21load, asm: "ORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 | tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "ORLmem", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 | tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "XORQmem", argLength: 3, reg: gp21load, asm: "XORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
+		{name: "XORLmem", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from  arg1+auxint+aux, arg2 = mem
 
 		// unary ops
 		{name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true}, // -arg0
@@ -291,6 +320,8 @@ func init() {
 		// flags are set to "equal" if the input is zero, "not equal" otherwise.
 		{name: "BSFQ", argLength: 1, reg: gp11flags, asm: "BSFQ", typ: "(UInt64,Flags)"}, // # of low-order zeroes in 64-bit arg
 		{name: "BSFL", argLength: 1, reg: gp11flags, asm: "BSFL", typ: "(UInt32,Flags)"}, // # of low-order zeroes in 32-bit arg
+		{name: "BSRQ", argLength: 1, reg: gp11flags, asm: "BSRQ", typ: "(UInt64,Flags)"}, // # of high-order zeroes in 64-bit arg
+		{name: "BSRL", argLength: 1, reg: gp11flags, asm: "BSRL", typ: "(UInt32,Flags)"}, // # of high-order zeroes in 32-bit arg
 
 		// Note ASM for ops moves whole register
 		//
@@ -300,6 +331,11 @@ func init() {
 		{name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
 		{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
 
+		// POPCNT instructions aren't guaranteed to be on the target platform (they are SSE4).
+		// Any use must be preceded by a successful check of runtime.support_popcnt.
+		{name: "POPCNTQ", argLength: 1, reg: gp11, asm: "POPCNTQ", clobberFlags: true}, // count number of set bits in arg0
+		{name: "POPCNTL", argLength: 1, reg: gp11, asm: "POPCNTL", clobberFlags: true}, // count number of set bits in arg0
+
 		{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.
@@ -350,63 +386,64 @@ func init() {
 
 		{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, asm: "LEAQ", 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
+		{name: "LEAQ", argLength: 1, reg: gp11sb, asm: "LEAQ", aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxint + offset encoded in aux
+		{name: "LEAQ1", argLength: 2, reg: gp21sb, commutative: true, aux: "SymOff", symEffect: "Addr"},                   // arg0 + arg1 + auxint + aux
+		{name: "LEAQ2", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                                      // arg0 + 2*arg1 + auxint + aux
+		{name: "LEAQ4", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                                      // arg0 + 4*arg1 + auxint + aux
+		{name: "LEAQ8", argLength: 2, reg: gp21sb, aux: "SymOff", symEffect: "Addr"},                                      // arg0 + 8*arg1 + auxint + aux
 		// Note: LEAQ{1,2,4,8} must not have OpSB as either argument.
 
-		{name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux
+		{name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxint + offset encoded in aux
 
 		// 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", faultOnNilArg0: true},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true},             // ditto, sign extend to int64
-		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true},             // ditto, sign extend to int64
-		{name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true},             // ditto, sign extend to int64
-		{name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true},    // load 8 bytes from arg0+auxint+aux. arg1=mem
-		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store byte in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},     // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128", faultOnNilArg0: true},  // load 16 bytes from arg0+auxint+aux. arg1=mem
-		{name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},   // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+		{name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+		{name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},    // load 8 bytes from arg0+auxint+aux. arg1=mem
+		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store byte in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128", faultOnNilArg0: true, symEffect: "Read"},  // load 16 bytes from arg0+auxint+aux. arg1=mem
+		{name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 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
+		{name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", symEffect: "Read"},  // load a byte from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", symEffect: "Read"},                    // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", aux: "SymOff", typ: "UInt32", symEffect: "Read"},    // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", aux: "SymOff", typ: "UInt32", symEffect: "Read"},                       // load 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem
+		{name: "MOVQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVQ", aux: "SymOff", typ: "UInt64", symEffect: "Read"},    // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVQ", aux: "SymOff", typ: "UInt64", symEffect: "Read"},                       // 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: mark the MOVXstoreidx1 ops as commutative.  Generates too many rewrite rules at the moment.
+		{name: "MOVBstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVB", aux: "SymOff", symEffect: "Write"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff", symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff", symEffect: "Write"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff", symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx4", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff", symEffect: "Write"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem
+		{name: "MOVQstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVQ", aux: "SymOff", symEffect: "Write"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVQstoreidx8", argLength: 4, reg: gpstoreidx, asm: "MOVQ", aux: "SymOff", symEffect: "Write"}, // 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", faultOnNilArg0: true}, // 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", faultOnNilArg0: true}, // store low 2 bytes of ...
-		{name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true}, // store low 4 bytes of ...
-		{name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true}, // 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 ...
+		{name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 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", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
+		{name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
+		{name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
+
+		{name: "MOVBstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // 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", symEffect: "Write"}, // store low 2 bytes of ... arg1 ...
+		{name: "MOVWstoreconstidx2", argLength: 3, reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 2 bytes of ... 2*arg1 ...
+		{name: "MOVLstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 4 bytes of ... arg1 ...
+		{name: "MOVLstoreconstidx4", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 4 bytes of ... 4*arg1 ...
+		{name: "MOVQstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store 8 bytes of ... arg1 ...
+		{name: "MOVQstoreconstidx8", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store 8 bytes of ... 8*arg1 ...
 
 		// arg0 = pointer to start of memory to zero
 		// arg1 = value to store (will always be zero)
@@ -421,7 +458,8 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("X0")},
 				clobbers: buildReg("DI"),
 			},
-			clobberFlags: true,
+			clobberFlags:   true,
+			faultOnNilArg0: true,
 		},
 		{name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", aux: "Int128", rematerializeable: true},
 
@@ -437,12 +475,11 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
 				clobbers: buildReg("DI CX"),
 			},
+			faultOnNilArg0: true,
 		},
 
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                             // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                          // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                               // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                  // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// arg0 = destination pointer
@@ -458,7 +495,9 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("SI")},
 				clobbers: buildReg("DI SI X0"), // uses X0 as a temporary
 			},
-			clobberFlags: true,
+			clobberFlags:   true,
+			faultOnNilArg0: true,
+			faultOnNilArg1: true,
 		},
 
 		// arg0 = destination pointer
@@ -473,6 +512,8 @@ func init() {
 				inputs:   []regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")},
 				clobbers: buildReg("DI SI CX"),
 			},
+			faultOnNilArg0: true,
+			faultOnNilArg1: true,
 		},
 
 		// (InvertFlags (CMPQ a b)) == (CMPQ b a)
@@ -515,24 +556,24 @@ func init() {
 		// Atomic loads.  These are just normal loads but return <value,memory> tuples
 		// so they can be properly ordered with other loads.
 		// load from arg0+auxint+aux.  arg1=mem.
-		{name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true},
-		{name: "MOVQatomicload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", faultOnNilArg0: true},
+		{name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},
+		{name: "MOVQatomicload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},
 
 		// Atomic stores and exchanges.  Stores use XCHG to get the right memory ordering semantics.
 		// store arg0 to arg1+auxint+aux, arg2=mem.
 		// These ops return a tuple of <old contents of *(arg1+auxint+aux), memory>.
 		// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
-		{name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true},
-		{name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true},
+		{name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
 
 		// Atomic adds.
 		// *(arg1+auxint+aux) += arg0.  arg2=mem.
 		// Returns a tuple of <old contents of *(arg1+auxint+aux), memory>.
 		// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
-		{name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true},
-		{name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true},
-		{name: "AddTupleFirst32", argLength: 2}, // arg0=tuple <x,y>.  Returns <x+arg1,y>.
-		{name: "AddTupleFirst64", argLength: 2}, // arg0=tuple <x,y>.  Returns <x+arg1,y>.
+		{name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>.  Returns <x+arg0,y>.
+		{name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>.  Returns <x+arg0,y>.
 
 		// Compare and swap.
 		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
@@ -553,12 +594,12 @@ func init() {
 		//    JEQ ...
 		// but we can't do that because memory-using ops can't generate flags yet
 		// (flagalloc wants to move flag-generating instructions around).
-		{name: "CMPXCHGLlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
-		{name: "CMPXCHGQlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "CMPXCHGLlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "CMPXCHGQlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
 
 		// Atomic memory updates.
-		{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, // *(arg0+auxint+aux) &= arg1
-		{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},   // *(arg0+auxint+aux) |= arg1
+		{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
+		{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},   // *(arg0+auxint+aux) |= arg1
 	}
 
 	var AMD64blocks = []blockData{
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index aad2587..d66e50f 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -30,20 +30,16 @@
 
 (Hmul32 x y) -> (HMUL x y)
 (Hmul32u x y) -> (HMULU x y)
-(Hmul16 x y) -> (SRAconst (MUL <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-(Hmul16u x y) -> (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-(Hmul8 x y) -> (SRAconst (MUL <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-(Hmul8u x y) -> (SRLconst (MUL <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
 
 (Mul32uhilo x y) -> (MULLU x y)
 
 (Div32 x y) ->
-	(SUB (XOR <config.fe.TypeUInt32()>                                                                  // negate the result if one operand is negative
-		(Select0 <config.fe.TypeUInt32()> (UDIVrtcall
-			(SUB <config.fe.TypeUInt32()> (XOR x <config.fe.TypeUInt32()> (Signmask x)) (Signmask x))   // negate x if negative
-			(SUB <config.fe.TypeUInt32()> (XOR y <config.fe.TypeUInt32()> (Signmask y)) (Signmask y)))) // negate y if negative
-		(Signmask (XOR <config.fe.TypeUInt32()> x y))) (Signmask (XOR <config.fe.TypeUInt32()> x y)))
-(Div32u x y) -> (Select0 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+	(SUB (XOR <typ.UInt32>                                                        // negate the result if one operand is negative
+		(Select0 <typ.UInt32> (CALLudiv
+			(SUB <typ.UInt32> (XOR x <typ.UInt32> (Signmask x)) (Signmask x))   // negate x if negative
+			(SUB <typ.UInt32> (XOR y <typ.UInt32> (Signmask y)) (Signmask y)))) // negate y if negative
+		(Signmask (XOR <typ.UInt32> x y))) (Signmask (XOR <typ.UInt32> x y)))
+(Div32u x y) -> (Select0 <typ.UInt32> (CALLudiv x y))
 (Div16 x y) -> (Div32 (SignExt16to32 x) (SignExt16to32 y))
 (Div16u x y) -> (Div32u (ZeroExt16to32 x) (ZeroExt16to32 y))
 (Div8 x y) -> (Div32 (SignExt8to32 x) (SignExt8to32 y))
@@ -52,17 +48,20 @@
 (Div64F x y) -> (DIVD x y)
 
 (Mod32 x y) ->
-	(SUB (XOR <config.fe.TypeUInt32()>                                                                  // negate the result if x is negative
-		(Select1 <config.fe.TypeUInt32()> (UDIVrtcall
-			(SUB <config.fe.TypeUInt32()> (XOR <config.fe.TypeUInt32()> x (Signmask x)) (Signmask x))   // negate x if negative
-			(SUB <config.fe.TypeUInt32()> (XOR <config.fe.TypeUInt32()> y (Signmask y)) (Signmask y)))) // negate y if negative
+	(SUB (XOR <typ.UInt32>                                                        // negate the result if x is negative
+		(Select1 <typ.UInt32> (CALLudiv
+			(SUB <typ.UInt32> (XOR <typ.UInt32> x (Signmask x)) (Signmask x))   // negate x if negative
+			(SUB <typ.UInt32> (XOR <typ.UInt32> y (Signmask y)) (Signmask y)))) // negate y if negative
 		(Signmask x)) (Signmask x))
-(Mod32u x y) -> (Select1 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+(Mod32u x y) -> (Select1 <typ.UInt32> (CALLudiv x y))
 (Mod16 x y) -> (Mod32 (SignExt16to32 x) (SignExt16to32 y))
 (Mod16u x y) -> (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))
 (Mod8 x y) -> (Mod32 (SignExt8to32 x) (SignExt8to32 y))
 (Mod8u x y) -> (Mod32u (ZeroExt8to32 x) (ZeroExt8to32 y))
 
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg32u <t> x y) -> (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
+
 (And32 x y) -> (AND x y)
 (And16 x y) -> (AND x y)
 (And8 x y) -> (AND x y)
@@ -88,11 +87,17 @@
 
 (Sqrt x) -> (SQRTD x)
 
-// count trailing zero
+// count trailing zero for ARMv5 and ARMv6
 // 32 - CLZ(x&-x - 1)
-(Ctz32 <t> x) -> (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
+(Ctz32 <t> x) && objabi.GOARM<=6 -> (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
+
+// count trailing zero for ARMv7
+(Ctz32 <t> x) && objabi.GOARM==7 -> (CLZ <t> (RBIT <t> x))
+
+// bit length
+(BitLen32 <t> x) -> (RSBconst [32] (CLZ <t> x))
 
-// byte swap
+// byte swap for ARMv5
 // let (a, b, c, d) be the bytes of x from high to low
 // t1 = x right rotate 16 bits -- (c,   d,   a,   b  )
 // t2 = x ^ t1                 -- (a^c, b^d, a^c, b^d)
@@ -101,15 +106,18 @@
 // t5 = x right rotate 8 bits  -- (d,   a,   b,   c  )
 // result = t4 ^ t5            -- (d,   c,   b,   a  )
 // using shifted ops this can be done in 4 instructions.
-(Bswap32 <t> x) ->
+(Bswap32 <t> x) && objabi.GOARM==5 ->
 	(XOR <t>
 		(SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8])
 		(SRRconst <t> x [8]))
 
+// byte swap for ARMv6 and above
+(Bswap32 x) && objabi.GOARM>=6 -> (REV x)
+
 // boolean ops -- booleans are represented with 0=false, 1=true
 (AndB x y) -> (AND x y)
 (OrB x y) -> (OR x y)
-(EqB x y) -> (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+(EqB x y) -> (XORconst [1] (XOR <typ.Bool> x y))
 (NeqB x y) -> (XOR x y)
 (Not x) -> (XORconst [1] x)
 
@@ -158,11 +166,11 @@
 (Rsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SRAconst x [c])
 (Rsh32Ux64 x (Const64 [c])) && uint64(c) < 32 -> (SRLconst x [c])
 (Lsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SLLconst x [c])
-(Rsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
-(Rsh16Ux64 x (Const64 [c])) && uint64(c) < 16 -> (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+(Rsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SRAconst (SLLconst <typ.UInt32> x [16]) [c+16])
+(Rsh16Ux64 x (Const64 [c])) && uint64(c) < 16 -> (SRLconst (SLLconst <typ.UInt32> x [16]) [c+16])
 (Lsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SLLconst x [c])
-(Rsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
-(Rsh8Ux64 x (Const64 [c])) && uint64(c) < 8 -> (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+(Rsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SRAconst (SLLconst <typ.UInt32> x [24]) [c+24])
+(Rsh8Ux64 x (Const64 [c])) && uint64(c) < 8 -> (SRLconst (SLLconst <typ.UInt32> x [24]) [c+24])
 
 // large constant shifts
 (Lsh32x64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
@@ -174,12 +182,8 @@
 
 // large constant signed right shift, we leave the sign bit
 (Rsh32x64 x (Const64 [c])) && uint64(c) >= 32 -> (SRAconst x [31])
-(Rsh16x64 x (Const64 [c])) && uint64(c) >= 16 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
-(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
-
-(Lrot32 x [c]) -> (SRRconst x [32-c&31])
-(Lrot16 <t> x [c]) -> (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to32 x) [16-c&15]))
-(Lrot8 <t> x [c]) -> (OR (SLLconst <t> x [c&7]) (SRLconst <t> (ZeroExt8to32 x) [8-c&7]))
+(Rsh16x64 x (Const64 [c])) && uint64(c) >= 16 -> (SRAconst (SLLconst <typ.UInt32> x [16]) [31])
+(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 -> (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
 
 // constants
 (Const8 [val]) -> (MOVWconst [val])
@@ -206,8 +210,8 @@
 (SignExt16to32 x) -> (MOVHreg x)
 
 (Signmask x) -> (SRAconst x [31])
-(Zeromask x) -> (SRAconst (RSBshiftRL <config.fe.TypeInt32()> x x [1]) [31]) // sign bit of uint32(x)>>1 - x
-(Slicemask <t> x) -> (MVN (SRAconst <t> (SUBconst <t> x [1]) [31]))
+(Zeromask x) -> (SRAconst (RSBshiftRL <typ.Int32> x x [1]) [31]) // sign bit of uint32(x)>>1 - x
+(Slicemask <t> x) -> (SRAconst (RSBconst <t> [0] x) [31])
 
 // float <-> int conversion
 (Cvt32to32F x) -> (MOVWF x)
@@ -221,6 +225,9 @@
 (Cvt32Fto64F x) -> (MOVFD x)
 (Cvt64Fto32F x) -> (MOVDF x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // comparisons
 (Eq8 x y)  -> (Equal (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 (Eq16 x y) -> (Equal (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
@@ -292,97 +299,95 @@
 (Load <t> ptr mem) && is64BitFloat(t) -> (MOVDload ptr mem)
 
 // stores
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [4] ptr val mem) && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
 
 // zero instructions
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [0] _ mem) -> mem
+(Zero [1] ptr mem) -> (MOVBstore ptr (MOVWconst [0]) mem)
+(Zero [2] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+(Zero [2] ptr mem) ->
 	(MOVBstore [1] ptr (MOVWconst [0])
 		(MOVBstore [0] ptr (MOVWconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] ptr (MOVWconst [0])
 		(MOVHstore [0] ptr (MOVWconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+(Zero [4] ptr mem) ->
 	(MOVBstore [3] ptr (MOVWconst [0])
 		(MOVBstore [2] ptr (MOVWconst [0])
 			(MOVBstore [1] ptr (MOVWconst [0])
 				(MOVBstore [0] ptr (MOVWconst [0]) mem))))
 
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] ptr mem) ->
 	(MOVBstore [2] ptr (MOVWconst [0])
 		(MOVBstore [1] ptr (MOVWconst [0])
 			(MOVBstore [0] ptr (MOVWconst [0]) mem)))
 
 // Medium zeroing uses a duff device
 // 4 and 128 are magic constants, see runtime/mkduff.go
-(Zero [s] ptr mem)
-	&& SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512
-	&& SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice ->
-	(DUFFZERO [4 * (128 - int64(SizeAndAlign(s).Size()/4))] ptr (MOVWconst [0]) mem)
+(Zero [s] {t} ptr mem)
+	&& s%4 == 0 && s > 4 && s <= 512
+	&& t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice ->
+	(DUFFZERO [4 * (128 - int64(s/4))] ptr (MOVWconst [0]) mem)
 
 // Large zeroing uses a loop
-(Zero [s] ptr mem)
-	&& (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0 ->
-	(LoweredZero [SizeAndAlign(s).Align()]
+(Zero [s] {t} ptr mem)
+	&& (s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0 ->
+	(LoweredZero [t.(*types.Type).Alignment()]
 		ptr
-		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)])
 		(MOVWconst [0])
 		mem)
 
 // moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBUload src mem) mem)
+(Move [2] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore dst (MOVHUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+(Move [2] dst src mem) ->
 	(MOVBstore [1] dst (MOVBUload [1] src mem)
 		(MOVBstore dst (MOVBUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] dst (MOVHUload [2] src mem)
 		(MOVHstore dst (MOVHUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+(Move [4] dst src mem) ->
 	(MOVBstore [3] dst (MOVBUload [3] src mem)
 		(MOVBstore [2] dst (MOVBUload [2] src mem)
 			(MOVBstore [1] dst (MOVBUload [1] src mem)
 				(MOVBstore dst (MOVBUload src mem) mem))))
 
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(Move [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBUload [2] src mem)
 		(MOVBstore [1] dst (MOVBUload [1] src mem)
 			(MOVBstore dst (MOVBUload src mem) mem)))
 
 // Medium move uses a duff device
 // 8 and 128 are magic constants, see runtime/mkduff.go
-(Move [s] dst src mem)
-	&& SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512
-	&& SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice ->
-	(DUFFCOPY [8 * (128 - int64(SizeAndAlign(s).Size()/4))] dst src mem)
+(Move [s] {t} dst src mem)
+	&& s%4 == 0 && s > 4 && s <= 512
+	&& t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice ->
+	(DUFFCOPY [8 * (128 - int64(s/4))] dst src mem)
 
 // Large move uses a loop
-(Move [s] dst src mem)
-	&& (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0 ->
-	(LoweredMove [SizeAndAlign(s).Align()]
+(Move [s] {t} dst src mem)
+	&& (s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0 ->
+	(LoweredMove [t.(*types.Type).Alignment()]
 		dst
 		src
-		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)])
 		mem)
 
 // 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)
 
 // checks
@@ -425,21 +430,34 @@
 
 // fold offset into address
 (ADDconst [off1] (MOVWaddr [off2] {sym} ptr)) -> (MOVWaddr [off1+off2] {sym} ptr)
+(SUBconst [off1] (MOVWaddr [off2] {sym} ptr)) -> (MOVWaddr [off2-off1] {sym} ptr)
 
 // fold address into load/store
 (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVBload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVBload [off1-off2] {sym} ptr mem)
 (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
+(MOVBUload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVBUload [off1-off2] {sym} ptr mem)
 (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVHload [off1-off2] {sym} ptr mem)
 (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHUload [off1+off2] {sym} ptr mem)
+(MOVHUload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVHUload [off1-off2] {sym} ptr mem)
 (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVWload [off1-off2] {sym} ptr mem)
 (MOVFload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVFload [off1+off2] {sym} ptr mem)
+(MOVFload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVFload [off1-off2] {sym} ptr mem)
 (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVDload [off1+off2] {sym} ptr mem)
+(MOVDload [off1] {sym} (SUBconst [off2] ptr) mem) -> (MOVDload [off1-off2] {sym} ptr mem)
 
 (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVBstore [off1] {sym} (SUBconst [off2] ptr) val mem) -> (MOVBstore [off1-off2] {sym} ptr val mem)
 (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVHstore [off1+off2] {sym} ptr val mem)
+(MOVHstore [off1] {sym} (SUBconst [off2] ptr) val mem) -> (MOVHstore [off1-off2] {sym} ptr val mem)
 (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (SUBconst [off2] ptr) val mem) -> (MOVWstore [off1-off2] {sym} ptr val mem)
 (MOVFstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVFstore [off1+off2] {sym} ptr val mem)
+(MOVFstore [off1] {sym} (SUBconst [off2] ptr) val mem) -> (MOVFstore [off1-off2] {sym} ptr val mem)
 (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVDstore [off1+off2] {sym} ptr val mem)
+(MOVDstore [off1] {sym} (SUBconst [off2] ptr) val mem) -> (MOVDstore [off1-off2] {sym} ptr val mem)
 
 (MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
 	(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
@@ -467,12 +485,13 @@
 (MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
 	(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val 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) && isSigned(x.Type) -> x
-(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
-(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
-(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
+(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
+(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
+(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
 (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+
 (MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 
@@ -482,16 +501,13 @@
 (MOVWloadshiftRA ptr idx [c] (MOVWstoreshiftRA ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
 
 // fold constant into arithmatic ops
-(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
 (ADD x (MOVWconst [c])) -> (ADDconst [c] x)
 (SUB (MOVWconst [c]) x) -> (RSBconst [c] x)
 (SUB x (MOVWconst [c])) -> (SUBconst [c] x)
 (RSB (MOVWconst [c]) x) -> (SUBconst [c] x)
 (RSB x (MOVWconst [c])) -> (RSBconst [c] x)
 
-(ADDS (MOVWconst [c]) x) -> (ADDSconst [c] x)
 (ADDS x (MOVWconst [c])) -> (ADDSconst [c] x)
-(SUBS (MOVWconst [c]) x) -> (RSBSconst [c] x)
 (SUBS x (MOVWconst [c])) -> (SUBSconst [c] x)
 
 (ADC (MOVWconst [c]) x flags) -> (ADCconst [c] x flags)
@@ -499,11 +515,8 @@
 (SBC (MOVWconst [c]) x flags) -> (RSCconst [c] x flags)
 (SBC x (MOVWconst [c]) flags) -> (SBCconst [c] x flags)
 
-(AND (MOVWconst [c]) x) -> (ANDconst [c] x)
 (AND x (MOVWconst [c])) -> (ANDconst [c] x)
-(OR (MOVWconst [c]) x) -> (ORconst [c] x)
-(OR x (MOVWconst [c])) -> (ORconst [c] x)
-(XOR (MOVWconst [c]) x) -> (XORconst [c] x)
+(OR  x (MOVWconst [c])) -> (ORconst [c] x)
 (XOR x (MOVWconst [c])) -> (XORconst [c] x)
 (BIC x (MOVWconst [c])) -> (BICconst [c] x)
 
@@ -563,17 +576,6 @@
 (MUL x (MOVWconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
 (MUL x (MOVWconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 
-(MUL (MOVWconst [c]) x) && int32(c) == -1 -> (RSBconst [0] x)
-(MUL (MOVWconst [0]) _) -> (MOVWconst [0])
-(MUL (MOVWconst [1]) x) -> x
-(MUL (MOVWconst [c]) x) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
-(MUL (MOVWconst [c]) x) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
-(MUL (MOVWconst [c]) x) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (RSBshiftLL x x [log2(c+1)])
-(MUL (MOVWconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-(MUL (MOVWconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-(MUL (MOVWconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
-(MUL (MOVWconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
-
 (MULA x (MOVWconst [c]) a) && int32(c) == -1 -> (SUB a x)
 (MULA _ (MOVWconst [0]) a) -> a
 (MULA x (MOVWconst [1]) a) -> (ADD x a)
@@ -597,10 +599,10 @@
 (MULA (MOVWconst [c]) x a) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
 
 // div by constant
-(Select0 (UDIVrtcall x (MOVWconst [1]))) -> x
-(Select1 (UDIVrtcall _ (MOVWconst [1]))) -> (MOVWconst [0])
-(Select0 (UDIVrtcall x (MOVWconst [c]))) && isPowerOfTwo(c) -> (SRLconst [log2(c)] x)
-(Select1 (UDIVrtcall x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
+(Select0 (CALLudiv x (MOVWconst [1]))) -> x
+(Select1 (CALLudiv _ (MOVWconst [1]))) -> (MOVWconst [0])
+(Select0 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (SRLconst [log2(c)] x)
+(Select1 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
 
 // constant comparisons
 (CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
@@ -795,6 +797,10 @@
 (BICconst [c] _) && int32(c)==-1 -> (MOVWconst [0])
 
 // generic constant folding
+(ADDconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c)) -> (SUBconst [int64(int32(-c))] x)
+(SUBconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c)) -> (ADDconst [int64(int32(-c))] x)
+(ANDconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c)) -> (BICconst [int64(^uint32(c))] x)
+(BICconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c)) -> (ANDconst [int64(^uint32(c))] x)
 (ADDconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(c+d))])
 (ADDconst [c] (ADDconst [d] x)) -> (ADDconst [int64(int32(c+d))] x)
 (ADDconst [c] (SUBconst [d] x)) -> (ADDconst [int64(int32(c-d))] x)
@@ -818,8 +824,8 @@
 (SRAconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d)>>uint64(c))])
 (MUL (MOVWconst [c]) (MOVWconst [d])) -> (MOVWconst [int64(int32(c*d))])
 (MULA (MOVWconst [c]) (MOVWconst [d]) a) -> (ADDconst [int64(int32(c*d))] a)
-(Select0 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)/uint32(d))])
-(Select1 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)%uint32(d))])
+(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)/uint32(d))])
+(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)%uint32(d))])
 (ANDconst [c] (MOVWconst [d])) -> (MOVWconst [c&d])
 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
 (ORconst [c] (MOVWconst [d])) -> (MOVWconst [c|d])
@@ -827,6 +833,7 @@
 (XORconst [c] (MOVWconst [d])) -> (MOVWconst [c^d])
 (XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
 (BICconst [c] (MOVWconst [d])) -> (MOVWconst [d&^c])
+(BICconst [c] (BICconst [d] x)) -> (BICconst [int64(int32(c|d))] x)
 (MVN (MOVWconst [c])) -> (MOVWconst [^c])
 (MOVBreg (MOVWconst [c])) -> (MOVWconst [int64(int8(c))])
 (MOVBUreg (MOVWconst [c])) -> (MOVWconst [int64(uint8(c))])
@@ -836,17 +843,11 @@
 
 // absorb shifts into ops
 (ADD x (SLLconst [c] y)) -> (ADDshiftLL x y [c])
-(ADD (SLLconst [c] y) x) -> (ADDshiftLL x y [c])
 (ADD x (SRLconst [c] y)) -> (ADDshiftRL x y [c])
-(ADD (SRLconst [c] y) x) -> (ADDshiftRL x y [c])
 (ADD x (SRAconst [c] y)) -> (ADDshiftRA x y [c])
-(ADD (SRAconst [c] y) x) -> (ADDshiftRA x y [c])
 (ADD x (SLL y z)) -> (ADDshiftLLreg x y z)
-(ADD (SLL y z) x) -> (ADDshiftLLreg x y z)
 (ADD x (SRL y z)) -> (ADDshiftRLreg x y z)
-(ADD (SRL y z) x) -> (ADDshiftRLreg x y z)
 (ADD x (SRA y z)) -> (ADDshiftRAreg x y z)
-(ADD (SRA y z) x) -> (ADDshiftRAreg x y z)
 (ADC x (SLLconst [c] y) flags) -> (ADCshiftLL x y [c] flags)
 (ADC (SLLconst [c] y) x flags) -> (ADCshiftLL x y [c] flags)
 (ADC x (SRLconst [c] y) flags) -> (ADCshiftRL x y [c] flags)
@@ -860,17 +861,11 @@
 (ADC x (SRA y z) flags) -> (ADCshiftRAreg x y z flags)
 (ADC (SRA y z) x flags) -> (ADCshiftRAreg x y z flags)
 (ADDS x (SLLconst [c] y)) -> (ADDSshiftLL x y [c])
-(ADDS (SLLconst [c] y) x) -> (ADDSshiftLL x y [c])
 (ADDS x (SRLconst [c] y)) -> (ADDSshiftRL x y [c])
-(ADDS (SRLconst [c] y) x) -> (ADDSshiftRL x y [c])
 (ADDS x (SRAconst [c] y)) -> (ADDSshiftRA x y [c])
-(ADDS (SRAconst [c] y) x) -> (ADDSshiftRA x y [c])
 (ADDS x (SLL y z)) -> (ADDSshiftLLreg x y z)
-(ADDS (SLL y z) x) -> (ADDSshiftLLreg x y z)
 (ADDS x (SRL y z)) -> (ADDSshiftRLreg x y z)
-(ADDS (SRL y z) x) -> (ADDSshiftRLreg x y z)
 (ADDS x (SRA y z)) -> (ADDSshiftRAreg x y z)
-(ADDS (SRA y z) x) -> (ADDSshiftRAreg x y z)
 (SUB x (SLLconst [c] y)) -> (SUBshiftLL x y [c])
 (SUB (SLLconst [c] y) x) -> (RSBshiftLL x y [c])
 (SUB x (SRLconst [c] y)) -> (SUBshiftRL x y [c])
@@ -920,43 +915,24 @@
 (RSB x (SRA y z)) -> (RSBshiftRAreg x y z)
 (RSB (SRA y z) x) -> (SUBshiftRAreg x y z)
 (AND x (SLLconst [c] y)) -> (ANDshiftLL x y [c])
-(AND (SLLconst [c] y) x) -> (ANDshiftLL x y [c])
 (AND x (SRLconst [c] y)) -> (ANDshiftRL x y [c])
-(AND (SRLconst [c] y) x) -> (ANDshiftRL x y [c])
 (AND x (SRAconst [c] y)) -> (ANDshiftRA x y [c])
-(AND (SRAconst [c] y) x) -> (ANDshiftRA x y [c])
 (AND x (SLL y z)) -> (ANDshiftLLreg x y z)
-(AND (SLL y z) x) -> (ANDshiftLLreg x y z)
 (AND x (SRL y z)) -> (ANDshiftRLreg x y z)
-(AND (SRL y z) x) -> (ANDshiftRLreg x y z)
 (AND x (SRA y z)) -> (ANDshiftRAreg x y z)
-(AND (SRA y z) x) -> (ANDshiftRAreg x y z)
 (OR x (SLLconst [c] y)) -> (ORshiftLL x y [c])
-(OR (SLLconst [c] y) x) -> (ORshiftLL x y [c])
 (OR x (SRLconst [c] y)) -> (ORshiftRL x y [c])
-(OR (SRLconst [c] y) x) -> (ORshiftRL x y [c])
 (OR x (SRAconst [c] y)) -> (ORshiftRA x y [c])
-(OR (SRAconst [c] y) x) -> (ORshiftRA x y [c])
 (OR x (SLL y z)) -> (ORshiftLLreg x y z)
-(OR (SLL y z) x) -> (ORshiftLLreg x y z)
 (OR x (SRL y z)) -> (ORshiftRLreg x y z)
-(OR (SRL y z) x) -> (ORshiftRLreg x y z)
 (OR x (SRA y z)) -> (ORshiftRAreg x y z)
-(OR (SRA y z) x) -> (ORshiftRAreg x y z)
 (XOR x (SLLconst [c] y)) -> (XORshiftLL x y [c])
-(XOR (SLLconst [c] y) x) -> (XORshiftLL x y [c])
 (XOR x (SRLconst [c] y)) -> (XORshiftRL x y [c])
-(XOR (SRLconst [c] y) x) -> (XORshiftRL x y [c])
 (XOR x (SRAconst [c] y)) -> (XORshiftRA x y [c])
-(XOR (SRAconst [c] y) x) -> (XORshiftRA x y [c])
 (XOR x (SRRconst [c] y)) -> (XORshiftRR x y [c])
-(XOR (SRRconst [c] y) x) -> (XORshiftRR x y [c])
 (XOR x (SLL y z)) -> (XORshiftLLreg x y z)
-(XOR (SLL y z) x) -> (XORshiftLLreg x y z)
 (XOR x (SRL y z)) -> (XORshiftRLreg x y z)
-(XOR (SRL y z) x) -> (XORshiftRLreg x y z)
 (XOR x (SRA y z)) -> (XORshiftRAreg x y z)
-(XOR (SRA y z) x) -> (XORshiftRAreg x y z)
 (BIC x (SLLconst [c] y)) -> (BICshiftLL x y [c])
 (BIC x (SRLconst [c] y)) -> (BICshiftRL x y [c])
 (BIC x (SRAconst [c] y)) -> (BICshiftRA x y [c])
@@ -1159,6 +1135,14 @@
 (CMPshiftRLreg x y (MOVWconst [c])) -> (CMPshiftRL x y [c])
 (CMPshiftRAreg x y (MOVWconst [c])) -> (CMPshiftRA x y [c])
 
+// Generate rotates
+(ADDshiftLL [c] (SRLconst x [32-c]) x) -> (SRRconst [32-c] x)
+( ORshiftLL [c] (SRLconst x [32-c]) x) -> (SRRconst [32-c] x)
+(XORshiftLL [c] (SRLconst x [32-c]) x) -> (SRRconst [32-c] x)
+(ADDshiftRL [c] (SLLconst x [32-c]) x) -> (SRRconst [   c] x)
+( ORshiftRL [c] (SLLconst x [32-c]) x) -> (SRRconst [   c] x)
+(XORshiftRL [c] (SLLconst x [32-c]) x) -> (SRRconst [   c] x)
+
 // use indexed loads and stores
 (MOVWload [0] {sym} (ADD ptr idx) mem) && sym == nil && !config.nacl -> (MOVWloadidx ptr idx mem)
 (MOVWstore [0] {sym} (ADD ptr idx) val mem) && sym == nil && !config.nacl -> (MOVWstoreidx ptr idx val mem)
@@ -1200,7 +1184,7 @@
 
 // generic simplifications
 (ADD x (RSBconst [0] y)) -> (SUB x y)
-(ADD (RSBconst [0] y) x) -> (SUB x y)
+(ADD <t> (RSBconst [c] x) (RSBconst [d] y)) -> (RSBconst [c+d] (ADD <t> x y))
 (SUB x x) -> (MOVWconst [0])
 (RSB x x) -> (MOVWconst [0])
 (AND x x) -> x
@@ -1209,10 +1193,8 @@
 (BIC x x) -> (MOVWconst [0])
 
 (ADD (MUL x y) a) -> (MULA x y a)
-(ADD a (MUL x y)) -> (MULA x y a)
 
 (AND x (MVN y)) -> (BIC x y)
-(AND (MVN y) x) -> (BIC x y)
 
 // simplification with *shift ops
 (SUBshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
@@ -1234,11 +1216,8 @@
 (BICshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
 (BICshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
 (AND x (MVNshiftLL y [c])) -> (BICshiftLL x y [c])
-(AND (MVNshiftLL y [c]) x) -> (BICshiftLL x y [c])
 (AND x (MVNshiftRL y [c])) -> (BICshiftRL x y [c])
-(AND (MVNshiftRL y [c]) x) -> (BICshiftRL x y [c])
 (AND x (MVNshiftRA y [c])) -> (BICshiftRA x y [c])
-(AND (MVNshiftRA y [c]) x) -> (BICshiftRA x y [c])
 
 // floating point optimizations
 (CMPF x (MOVFconst [0])) -> (CMPF0 x)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index bc58a1f..4831ff2 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -27,12 +27,8 @@
 
 (Hmul64 x y) -> (MULH x y)
 (Hmul64u x y) -> (UMULH x y)
-(Hmul32 x y) -> (SRAconst (MULL <config.fe.TypeInt64()> x y) [32])
-(Hmul32u x y) -> (SRAconst (UMULL <config.fe.TypeUInt64()> x y) [32])
-(Hmul16 x y) -> (SRAconst (MULW <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-(Hmul16u x y) -> (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-(Hmul8 x y) -> (SRAconst (MULW <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-(Hmul8u x y) -> (SRLconst (MUL <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
+(Hmul32 x y) -> (SRAconst (MULL <typ.Int64> x y) [32])
+(Hmul32u x y) -> (SRAconst (UMULL <typ.UInt64> x y) [32])
 
 (Div64 x y) -> (DIV x y)
 (Div64u x y) -> (UDIV x y)
@@ -54,7 +50,8 @@
 (Mod8 x y) -> (MODW (SignExt8to32 x) (SignExt8to32 y))
 (Mod8u x y) -> (UMODW (ZeroExt8to32 x) (ZeroExt8to32 y))
 
-(Avg64u <t> x y) -> (ADD (ADD <t> (SRLconst <t> x [1]) (SRLconst <t> y [1])) (AND <t> (AND <t> x y) (MOVDconst [1])))
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg64u <t> x y) -> (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
 
 (And64 x y) -> (AND x y)
 (And32 x y) -> (AND x y)
@@ -89,13 +86,20 @@
 (Ctz64 <t> x) -> (CLZ (RBIT <t> x))
 (Ctz32 <t> x) -> (CLZW (RBITW <t> x))
 
+(BitLen64 x) -> (SUB (MOVDconst [64]) (CLZ <typ.Int> x))
+
 (Bswap64 x) -> (REV x)
 (Bswap32 x) -> (REVW x)
 
+(BitRev64 x) -> (RBIT x)
+(BitRev32 x) -> (RBITW x)
+(BitRev16 x) -> (SRLconst [48] (RBIT <typ.UInt64> x))
+(BitRev8 x) -> (SRLconst [56] (RBIT <typ.UInt64> x))
+
 // boolean ops -- booleans are represented with 0=false, 1=true
 (AndB x y) -> (AND x y)
 (OrB x y) -> (OR x y)
-(EqB x y) -> (XOR (MOVDconst [1]) (XOR <config.fe.TypeBool()> x y))
+(EqB x y) -> (XOR (MOVDconst [1]) (XOR <typ.Bool> x y))
 (NeqB x y) -> (XOR x y)
 (Not x) -> (XOR (MOVDconst [1]) x)
 
@@ -192,11 +196,6 @@
 (Rsh8x16 x y) -> (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
 (Rsh8x8  x y) -> (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt8to64  y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64  y))))
 
-(Lrot64 x [c]) -> (RORconst  x [64-c&63])
-(Lrot32 x [c]) -> (RORWconst x [32-c&31])
-(Lrot16 <t> x [c]) -> (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to64 x) [16-c&15]))
-(Lrot8  <t> x [c]) -> (OR (SLLconst <t> x [c&7])  (SRLconst <t> (ZeroExt8to64  x) [8-c&7]))
-
 // constants
 (Const64 [val]) -> (MOVDconst [val])
 (Const32 [val]) -> (MOVDconst [val])
@@ -207,7 +206,7 @@
 (ConstNil) -> (MOVDconst [0])
 (ConstBool [b]) -> (MOVDconst [b])
 
-(Slicemask <t> x) -> (MVN (SRAconst <t> (SUBconst <t> x [1]) [63]))
+(Slicemask <t> x) -> (SRAconst (NEG <t> x) [63])
 
 // truncations
 // Because we ignore high parts of registers, truncates are just copies.
@@ -253,6 +252,9 @@
 (Cvt32Fto64F x) -> (FCVTSD x)
 (Cvt64Fto32F x) -> (FCVTDS x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // comparisons
 (Eq8 x y)  -> (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 (Eq16 x y) -> (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
@@ -336,124 +338,122 @@
 (Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
 
 // stores
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [4] ptr val mem) && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
-(Store [8] ptr val mem) && !is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
 
 // zeroing
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVDconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstore ptr (MOVDconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstore ptr (MOVDconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstore ptr (MOVDconst [0]) mem)
+(Zero [0] _ mem) -> mem
+(Zero [1] ptr mem) -> (MOVBstore ptr (MOVDconst [0]) mem)
+(Zero [2] ptr mem) -> (MOVHstore ptr (MOVDconst [0]) mem)
+(Zero [4] ptr mem) -> (MOVWstore ptr (MOVDconst [0]) mem)
+(Zero [8] ptr mem) -> (MOVDstore ptr (MOVDconst [0]) mem)
 
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] ptr mem) ->
 	(MOVBstore [2] ptr (MOVDconst [0])
 		(MOVHstore ptr (MOVDconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 5 ->
+(Zero [5] ptr mem) ->
 	(MOVBstore [4] ptr (MOVDconst [0])
 		(MOVWstore ptr (MOVDconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 ->
+(Zero [6] ptr mem) ->
 	(MOVHstore [4] ptr (MOVDconst [0])
 		(MOVWstore ptr (MOVDconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 7 ->
+(Zero [7] ptr mem) ->
 	(MOVBstore [6] ptr (MOVDconst [0])
 		(MOVHstore [4] ptr (MOVDconst [0])
 			(MOVWstore ptr (MOVDconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 ->
+(Zero [12] ptr mem) ->
 	(MOVWstore [8] ptr (MOVDconst [0])
 		(MOVDstore ptr (MOVDconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 ->
+(Zero [16] ptr mem) ->
 	(MOVDstore [8] ptr (MOVDconst [0])
 		(MOVDstore ptr (MOVDconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 ->
+(Zero [24] ptr mem) ->
 	(MOVDstore [16] ptr (MOVDconst [0])
 		(MOVDstore [8] ptr (MOVDconst [0])
 			(MOVDstore ptr (MOVDconst [0]) mem)))
 
 // strip off fractional word zeroing
-(Zero [s] ptr mem) && SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8 ->
-	(Zero [MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()]
-		(OffPtr <ptr.Type> ptr [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8])
-		(Zero [MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()] ptr mem))
+(Zero [s] ptr mem) && s%8 != 0 && s > 8 ->
+	(Zero [s%8]
+		(OffPtr <ptr.Type> ptr [s-s%8])
+		(Zero [s-s%8] ptr mem))
 
 // medium zeroing uses a duff device
 // 4, 8, and 128 are magic constants, see runtime/mkduff.go
 (Zero [s] ptr mem)
-	&& SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128
+	&& s%8 == 0 && s > 24 && s <= 8*128
 	&& !config.noDuffDevice ->
-	(DUFFZERO [4 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
+	(DUFFZERO [4 * (128 - int64(s/8))] ptr mem)
 
 // large zeroing uses a loop
 (Zero [s] ptr mem)
-	&& SizeAndAlign(s).Size()%8 == 0 && (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) ->
+	&& s%8 == 0 && (s > 8*128 || config.noDuffDevice) ->
 	(LoweredZero
 		ptr
-		(ADDconst <ptr.Type> [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)] ptr)
+		(ADDconst <ptr.Type> [s-8] ptr)
 		mem)
 
 // moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstore dst (MOVHUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstore dst (MOVWUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstore dst (MOVDload src mem) mem)
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBUload src mem) mem)
+(Move [2] dst src mem) -> (MOVHstore dst (MOVHUload src mem) mem)
+(Move [4] dst src mem) -> (MOVWstore dst (MOVWUload src mem) mem)
+(Move [8] dst src mem) -> (MOVDstore dst (MOVDload src mem) mem)
 
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(Move [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBUload [2] src mem)
 		(MOVHstore dst (MOVHUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+(Move [5] dst src mem) ->
 	(MOVBstore [4] dst (MOVBUload [4] src mem)
 		(MOVWstore dst (MOVWUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+(Move [6] dst src mem) ->
 	(MOVHstore [4] dst (MOVHUload [4] src mem)
 		(MOVWstore dst (MOVWUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+(Move [7] dst src mem) ->
 	(MOVBstore [6] dst (MOVBUload [6] src mem)
 		(MOVHstore [4] dst (MOVHUload [4] src mem)
 			(MOVWstore dst (MOVWUload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 12 ->
+(Move [12] dst src mem) ->
 	(MOVWstore [8] dst (MOVWUload [8] src mem)
 		(MOVDstore dst (MOVDload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 ->
+(Move [16] dst src mem) ->
 	(MOVDstore [8] dst (MOVDload [8] src mem)
 		(MOVDstore dst (MOVDload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 ->
+(Move [24] dst src mem) ->
 	(MOVDstore [16] dst (MOVDload [16] src mem)
 		(MOVDstore [8] dst (MOVDload [8] src mem)
 			(MOVDstore dst (MOVDload src mem) mem)))
 
 // strip off fractional word move
-(Move [s] dst src mem) && SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8 ->
-	(Move [MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()]
-		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8])
-		(OffPtr <src.Type> src [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8])
-		(Move [MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()] dst src mem))
+(Move [s] dst src mem) && s%8 != 0 && s > 8 ->
+	(Move [s%8]
+		(OffPtr <dst.Type> dst [s-s%8])
+		(OffPtr <src.Type> src [s-s%8])
+		(Move [s-s%8] dst src mem))
 
 // medium move uses a duff device
 // 8 and 128 are magic constants, see runtime/mkduff.go
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128
+	&& s%8 == 0 && s > 24 && s <= 8*128
 	&& !config.noDuffDevice ->
-	(DUFFCOPY [8 * (128 - int64(SizeAndAlign(s).Size()/8))] dst src mem)
+	(DUFFCOPY [8 * (128 - int64(s/8))] dst src mem)
 
 // large move uses a loop
 (Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size()%8 == 0 ->
+	&& s > 24 && s%8 == 0 ->
 	(LoweredMove
 		dst
 		src
-		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDconst <src.Type> src [s-8])
 		mem)
 
 // 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)
 
 // checks
@@ -525,152 +525,141 @@
 (ADDconst [off1] (MOVDaddr [off2] {sym} ptr)) -> (MOVDaddr [off1+off2] {sym} ptr)
 
 // fold address into load/store
-// only small offset (between -256 and 256) or offset that is a multiple of data size
-// can be encoded in the instructions
-// since this rewriting takes place before stack allocation, the offset to SP is unknown,
-// so don't do it for args and locals with unaligned offset
-(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBload [off1+off2] {sym} ptr mem)
-(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBUload [off1+off2] {sym} ptr mem)
-(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHload [off1+off2] {sym} ptr mem)
-(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHUload [off1+off2] {sym} ptr mem)
-(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWload [off1+off2] {sym} ptr mem)
-(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWUload [off1+off2] {sym} ptr mem)
-(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDload [off1+off2] {sym} ptr mem)
-(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVSload [off1+off2] {sym} ptr mem)
-(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVDload [off1+off2] {sym} ptr mem)
 
-(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2) ->
+(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBstore [off1+off2] {sym} ptr val mem)
-(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHstore [off1+off2] {sym} ptr val mem)
-(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWstore [off1+off2] {sym} ptr val mem)
-(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDstore [off1+off2] {sym} ptr val mem)
-(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVSstore [off1+off2] {sym} ptr val mem)
-(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVDstore [off1+off2] {sym} ptr val mem)
-(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBstorezero [off1+off2] {sym} ptr mem)
-(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHstorezero [off1+off2] {sym} ptr mem)
-(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWstorezero [off1+off2] {sym} ptr mem)
-(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	&& is32Bit(off1+off2) && !isArg(sym)
-	&& ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
+(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDstorezero [off1+off2] {sym} ptr mem)
 
-(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) ->
+(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) ->
+(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 
-(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) ->
+(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
-(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) ->
+(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
-	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
-	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
+(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+	&& canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
 	(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 
 // store zero
@@ -679,14 +668,14 @@
 (MOVWstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
 (MOVDstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVDstorezero [off] {sym} ptr mem)
 
-// replace load from same location as preceding store with copy
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
 // these seem to have bad interaction with other rules, resulting in slower code
-//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-//(MOVHUload [off] {sym} ptr (MOVHstore [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
-//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
+//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
+//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
+//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
+//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWreg x)
+//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWUreg x)
 //(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 //(FMOVSload [off] {sym} ptr (FMOVSstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 //(FMOVDload [off] {sym} ptr (FMOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
@@ -752,14 +741,10 @@
 (MOVDreg x) && x.Uses == 1 -> (MOVDnop x)
 
 // fold constant into arithmatic ops
-(ADD (MOVDconst [c]) x) -> (ADDconst [c] x)
 (ADD x (MOVDconst [c])) -> (ADDconst [c] x)
 (SUB x (MOVDconst [c])) -> (SUBconst [c] x)
-(AND (MOVDconst [c]) x) -> (ANDconst [c] x)
 (AND x (MOVDconst [c])) -> (ANDconst [c] x)
-(OR  (MOVDconst [c]) x) -> (ORconst  [c] x)
 (OR  x (MOVDconst [c])) -> (ORconst  [c] x)
-(XOR (MOVDconst [c]) x) -> (XORconst [c] x)
 (XOR x (MOVDconst [c])) -> (XORconst [c] x)
 (BIC x (MOVDconst [c])) -> (BICconst [c] x)
 
@@ -784,18 +769,6 @@
 (MUL x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) -> (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
 (MUL x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 
-(MUL (MOVDconst [-1]) x) -> (NEG x)
-(MUL (MOVDconst [0]) _) -> (MOVDconst [0])
-(MUL (MOVDconst [1]) x) -> x
-(MUL (MOVDconst [c]) x) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
-(MUL (MOVDconst [c]) x) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
-(MUL (MOVDconst [c]) x) && isPowerOfTwo(c-1) && c >= 3 -> (ADDshiftLL x x [log2(c-1)])
-(MUL (MOVDconst [c]) x) && isPowerOfTwo(c+1) && c >= 7 -> (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
-(MUL (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-(MUL (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-(MUL (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) -> (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
-(MUL (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
-
 (MULW x (MOVDconst [c])) && int32(c)==-1 -> (NEG x)
 (MULW _ (MOVDconst [c])) && int32(c)==0 -> (MOVDconst [0])
 (MULW x (MOVDconst [c])) && int32(c)==1 -> x
@@ -807,17 +780,6 @@
 (MULW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
 (MULW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 
-(MULW (MOVDconst [c]) x) && int32(c)==-1 -> (NEG x)
-(MULW (MOVDconst [c]) _) && int32(c)==0 -> (MOVDconst [0])
-(MULW (MOVDconst [c]) x) && int32(c)==1 -> x
-(MULW (MOVDconst [c]) x) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
-(MULW (MOVDconst [c]) x) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
-(MULW (MOVDconst [c]) x) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
-(MULW (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-(MULW (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-(MULW (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
-(MULW (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
-
 // div by constant
 (UDIV x (MOVDconst [1])) -> x
 (UDIV x (MOVDconst [c])) && isPowerOfTwo(c) -> (SRLconst [log2(c)] x)
@@ -830,7 +792,6 @@
 
 // generic simplifications
 (ADD x (NEG y)) -> (SUB x y)
-(ADD (NEG y) x) -> (SUB x y)
 (SUB x x) -> (MOVDconst [0])
 (AND x x) -> x
 (OR  x x) -> x
@@ -838,6 +799,8 @@
 (BIC x x) -> (MOVDconst [0])
 (AND x (MVN y)) -> (BIC x y)
 (CSELULT x (MOVDconst [0]) flag) -> (CSELULT0 x flag)
+(SUB x (SUB y z)) -> (SUB (ADD <v.Type> x z) y)
+(SUB (SUB x y) z) -> (SUB x (ADD <y.Type> y z))
 
 // remove redundant *const ops
 (ADDconst [0]  x) -> x
@@ -1078,34 +1041,20 @@
 
 // absorb shifts into ops
 (ADD x (SLLconst [c] y)) -> (ADDshiftLL x y [c])
-(ADD (SLLconst [c] y) x) -> (ADDshiftLL x y [c])
 (ADD x (SRLconst [c] y)) -> (ADDshiftRL x y [c])
-(ADD (SRLconst [c] y) x) -> (ADDshiftRL x y [c])
 (ADD x (SRAconst [c] y)) -> (ADDshiftRA x y [c])
-(ADD (SRAconst [c] y) x) -> (ADDshiftRA x y [c])
 (SUB x (SLLconst [c] y)) -> (SUBshiftLL x y [c])
 (SUB x (SRLconst [c] y)) -> (SUBshiftRL x y [c])
 (SUB x (SRAconst [c] y)) -> (SUBshiftRA x y [c])
 (AND x (SLLconst [c] y)) -> (ANDshiftLL x y [c])
-(AND (SLLconst [c] y) x) -> (ANDshiftLL x y [c])
 (AND x (SRLconst [c] y)) -> (ANDshiftRL x y [c])
-(AND (SRLconst [c] y) x) -> (ANDshiftRL x y [c])
 (AND x (SRAconst [c] y)) -> (ANDshiftRA x y [c])
-(AND (SRAconst [c] y) x) -> (ANDshiftRA x y [c])
-(OR  x s:(SLLconst [c] y)) && s.Uses == 1 && clobber(s) -> (ORshiftLL  x y [c]) // useful for combined load
-(OR  s:(SLLconst [c] y) x) && s.Uses == 1 && clobber(s) -> (ORshiftLL  x y [c])
-(OR  x (SLLconst [c] y)) -> (ORshiftLL  x y [c])
-(OR  (SLLconst [c] y) x) -> (ORshiftLL  x y [c])
+(OR  x (SLLconst [c] y)) -> (ORshiftLL  x y [c]) // useful for combined load
 (OR  x (SRLconst [c] y)) -> (ORshiftRL  x y [c])
-(OR  (SRLconst [c] y) x) -> (ORshiftRL  x y [c])
 (OR  x (SRAconst [c] y)) -> (ORshiftRA  x y [c])
-(OR  (SRAconst [c] y) x) -> (ORshiftRA  x y [c])
 (XOR x (SLLconst [c] y)) -> (XORshiftLL x y [c])
-(XOR (SLLconst [c] y) x) -> (XORshiftLL x y [c])
 (XOR x (SRLconst [c] y)) -> (XORshiftRL x y [c])
-(XOR (SRLconst [c] y) x) -> (XORshiftRL x y [c])
 (XOR x (SRAconst [c] y)) -> (XORshiftRA x y [c])
-(XOR (SRAconst [c] y) x) -> (XORshiftRA x y [c])
 (BIC x (SLLconst [c] y)) -> (BICshiftLL x y [c])
 (BIC x (SRLconst [c] y)) -> (BICshiftRL x y [c])
 (BIC x (SRAconst [c] y)) -> (BICshiftRA x y [c])
@@ -1173,24 +1122,48 @@
 (BICshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVDconst [0])
 (BICshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVDconst [0])
 
+// Generate rotates
+(ADDshiftLL [c] (SRLconst x [64-c]) x) -> (RORconst [64-c] x)
+( ORshiftLL [c] (SRLconst x [64-c]) x) -> (RORconst [64-c] x)
+(XORshiftLL [c] (SRLconst x [64-c]) x) -> (RORconst [64-c] x)
+(ADDshiftRL [c] (SLLconst x [64-c]) x) -> (RORconst [   c] x)
+( ORshiftRL [c] (SLLconst x [64-c]) x) -> (RORconst [   c] x)
+(XORshiftRL [c] (SLLconst x [64-c]) x) -> (RORconst [   c] x)
+
+(ADDshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x) && c < 32 && t.Size() == 4 -> (RORWconst [32-c] x)
+( ORshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x) && c < 32 && t.Size() == 4 -> (RORWconst [32-c] x)
+(XORshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x) && c < 32 && t.Size() == 4 -> (RORWconst [32-c] x)
+(ADDshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x)) && c < 32 && t.Size() == 4 -> (RORWconst [   c] x)
+( ORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x)) && c < 32 && t.Size() == 4 -> (RORWconst [   c] x)
+(XORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x)) && c < 32 && t.Size() == 4 -> (RORWconst [   c] x)
+
+// Generic rules rewrite certain AND to a pair of shifts.
+// However, on ARM64 the bitmask can fit into an instruction.
+// Rewrite it back to AND.
+(SRLconst [c] (SLLconst [c] x)) && 0 < c && c < 64 -> (ANDconst [1<<uint(64-c)-1] x) // mask out high bits
+(SLLconst [c] (SRLconst [c] x)) && 0 < c && c < 64 -> (ANDconst [^(1<<uint(c)-1)] x) // mask out low bits
+
 // do combined loads
 // little endian loads
 // b[0] | b[1]<<8 -> load 16-bit
 (ORshiftLL <t> [8]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))
-	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem)))
+	y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem))
+	y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem)))
+	&& i1 == i0+1
 	&& x0.Uses == 1 && x1.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1
 	&& mergePoint(b,x0,x1) != nil
 	&& clobber(x0) && clobber(x1)
 	&& clobber(y0) && clobber(y1)
-	-> @mergePoint(b,x0,x1) (MOVHUload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	-> @mergePoint(b,x0,x1) (MOVHUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 
 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit
 (ORshiftLL <t> [24] o0:(ORshiftLL [16]
-	            x0:(MOVHUload [i]   {s} p mem)
-	y1:(MOVDnop x1:(MOVBUload [i+2] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i+3] {s} p mem)))
+	            x0:(MOVHUload [i0] {s} p mem)
+	y1:(MOVDnop x1:(MOVBUload [i2] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i3] {s} p mem)))
+	&& i2 == i0+2
+	&& i3 == i0+3
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1
 	&& y1.Uses == 1 && y2.Uses == 1
 	&& o0.Uses == 1
@@ -1198,15 +1171,19 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2)
 	&& clobber(y1) && clobber(y2)
 	&& clobber(o0)
-	-> @mergePoint(b,x0,x1,x2) (MOVWUload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	-> @mergePoint(b,x0,x1,x2) (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 
 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 | b[4]<<32 | b[5]<<40 | b[6]<<48 | b[7]<<56 -> load 64-bit
 (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32]
-	            x0:(MOVWUload [i]   {s} p mem)
-	y1:(MOVDnop x1:(MOVBUload [i+4] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i+5] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i+6] {s} p mem)))
-	y4:(MOVDnop x4:(MOVBUload [i+7] {s} p mem)))
+	            x0:(MOVWUload [i0] {s} p mem)
+	y1:(MOVDnop x1:(MOVBUload [i4] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i5] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i6] {s} p mem)))
+	y4:(MOVDnop x4:(MOVBUload [i7] {s} p mem)))
+	&& i4 == i0+4
+	&& i5 == i0+5
+	&& i6 == i0+6
+	&& i7 == i0+7
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1
 	&& y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1
 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1
@@ -1214,14 +1191,17 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4)
 	&& clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4)
 	&& clobber(o0) && clobber(o1) && clobber(o2)
-	-> @mergePoint(b,x0,x1,x2,x3,x4) (MOVDload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	-> @mergePoint(b,x0,x1,x2,x3,x4) (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 
 // b[3]<<24 | b[2]<<16 | b[1]<<8 | b[0] -> load 32-bit
 (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)))
-	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem)))
+	y0:(MOVDnop x0:(MOVBUload [i3] {s} p mem)))
+	y1:(MOVDnop x1:(MOVBUload [i2] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i1] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i0] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
+	&& i3 == i0+3
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1
 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1
@@ -1229,18 +1209,25 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3)
 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3)
 	&& clobber(o0) && clobber(o1) && clobber(s0)
-	-> @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i-3] p) mem)
+	-> @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 
 // b[7]<<56 | b[6]<<48 | b[5]<<40 | b[4]<<32 | b[3]<<24 | b[2]<<16 | b[1]<<8 | b[0] -> load 64-bit, reverse
 (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)))
-	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem)))
-	y4:(MOVDnop x4:(MOVBUload [i-4] {s} p mem)))
-	y5:(MOVDnop x5:(MOVBUload [i-5] {s} p mem)))
-	y6:(MOVDnop x6:(MOVBUload [i-6] {s} p mem)))
-	y7:(MOVDnop x7:(MOVBUload [i-7] {s} p mem)))
+	y0:(MOVDnop x0:(MOVBUload [i7] {s} p mem)))
+	y1:(MOVDnop x1:(MOVBUload [i6] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i5] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i4] {s} p mem)))
+	y4:(MOVDnop x4:(MOVBUload [i3] {s} p mem)))
+	y5:(MOVDnop x5:(MOVBUload [i2] {s} p mem)))
+	y6:(MOVDnop x6:(MOVBUload [i1] {s} p mem)))
+	y7:(MOVDnop x7:(MOVBUload [i0] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
+	&& i3 == i0+3
+	&& i4 == i0+4
+	&& i5 == i0+5
+	&& i6 == i0+6
+	&& i7 == i0+7
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1
 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1
@@ -1254,26 +1241,28 @@
 	&& clobber(y4) && clobber(y5) && clobber(y6) && clobber(y7)
 	&& clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3)
 	&& clobber(o4) && clobber(o5) && clobber(s0)
-	-> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i-7] p) mem))
+	-> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 
 // big endian loads
 // b[1] | b[0]<<8 -> load 16-bit, reverse
 (ORshiftLL <t> [8]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))
-	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	&& ((i-1)%2 == 0 || i-1<256 && i-1>-256 && !isArg(s) && !isAuto(s))
+	y0:(MOVDnop x0:(MOVBUload [i1] {s} p mem))
+	y1:(MOVDnop x1:(MOVBUload [i0] {s} p mem)))
+	&& i1 == i0+1
 	&& x0.Uses == 1 && x1.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1
 	&& mergePoint(b,x0,x1) != nil
 	&& clobber(x0) && clobber(x1)
 	&& clobber(y0) && clobber(y1)
-	-> @mergePoint(b,x0,x1) (REV16W <t> (MOVHUload <t> [i-1] {s} p mem))
+	-> @mergePoint(b,x0,x1) (REV16W <t> (MOVHUload <t> [i0] {s} p mem))
 
 // b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit, reverse
 (ORshiftLL <t> [24] o0:(ORshiftLL [16]
-	y0:(REV16W  x0:(MOVHUload [i]   {s} p mem))
-	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem)))
+	y0:(REV16W  x0:(MOVHUload [i2] {s} p mem))
+	y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i0] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1
 	&& o0.Uses == 1
@@ -1281,15 +1270,19 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2)
 	&& clobber(y0) && clobber(y1) && clobber(y2)
 	&& clobber(o0)
-	-> @mergePoint(b,x0,x1,x2) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i-2] p) mem))
+	-> @mergePoint(b,x0,x1,x2) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 
 // b[7] | b[6]<<8 | b[5]<<16 | b[4]<<24 | b[3]<<32 | b[2]<<40 | b[1]<<48 | b[0]<<56 -> load 64-bit, reverse
 (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32]
-	y0:(REVW    x0:(MOVWUload [i]   {s} p mem))
-	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem)))
-	y4:(MOVDnop x4:(MOVBUload [i-4] {s} p mem)))
+	y0:(REVW    x0:(MOVWUload [i4] {s} p mem))
+	y1:(MOVDnop x1:(MOVBUload [i3] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i1] {s} p mem)))
+	y4:(MOVDnop x4:(MOVBUload [i0] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
+	&& i3 == i0+3
+	&& i4 == i0+4
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1
 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1
@@ -1297,14 +1290,17 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4)
 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4)
 	&& clobber(o0) && clobber(o1) && clobber(o2)
-	-> @mergePoint(b,x0,x1,x2,x3,x4) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i-4] p) mem))
+	-> @mergePoint(b,x0,x1,x2,x3,x4) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 
 // b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3] -> load 32-bit, reverse
 (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)))
-	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i+2] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i+3] {s} p mem)))
+	y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem)))
+	y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
+	&& i3 == i0+3
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1
 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1
@@ -1312,18 +1308,25 @@
 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3)
 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3)
 	&& clobber(o0) && clobber(o1) && clobber(s0)
-	-> @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i] p) mem))
+	-> @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 
 // b[0]<<56 | b[1]<<48 | b[2]<<40 | b[3]<<32 | b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7] -> load 64-bit, reverse
 (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56]
-	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)))
-	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem)))
-	y2:(MOVDnop x2:(MOVBUload [i+2] {s} p mem)))
-	y3:(MOVDnop x3:(MOVBUload [i+3] {s} p mem)))
-	y4:(MOVDnop x4:(MOVBUload [i+4] {s} p mem)))
-	y5:(MOVDnop x5:(MOVBUload [i+5] {s} p mem)))
-	y6:(MOVDnop x6:(MOVBUload [i+6] {s} p mem)))
-	y7:(MOVDnop x7:(MOVBUload [i+7] {s} p mem)))
+	y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem)))
+	y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem)))
+	y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem)))
+	y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem)))
+	y4:(MOVDnop x4:(MOVBUload [i4] {s} p mem)))
+	y5:(MOVDnop x5:(MOVBUload [i5] {s} p mem)))
+	y6:(MOVDnop x6:(MOVBUload [i6] {s} p mem)))
+	y7:(MOVDnop x7:(MOVBUload [i7] {s} p mem)))
+	&& i1 == i0+1
+	&& i2 == i0+2
+	&& i3 == i0+3
+	&& i4 == i0+4
+	&& i5 == i0+5
+	&& i6 == i0+6
+	&& i7 == i0+7
 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1
 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1
 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1
@@ -1337,4 +1340,4 @@
 	&& clobber(y4) && clobber(y5) && clobber(y6) && clobber(y7)
 	&& clobber(o0) && clobber(o1) && clobber(o2) && clobber(o3)
 	&& clobber(o4) && clobber(o5) && clobber(s0)
-	-> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i] p) mem))
+	-> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index 0986ac6..832bea2 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -259,29 +259,29 @@ func init() {
 		{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVS", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
 		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
 
-		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
-
-		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true},      // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true},   // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true},     // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true},     // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true},    // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-
-		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true},   // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true},   // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true},   // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVDstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true},   // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "FMOVSstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVS", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-
-		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
+		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
+
+		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},      // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+
+		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVDstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "FMOVSstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVS", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+
+		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
 
 		// conversions
 		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
@@ -318,10 +318,8 @@ func init() {
 		{name: "CSELULT0", argLength: 2, reg: gp1flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, 0 otherwise, arg1=flags
 
 		// function calls
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                              // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                           // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                   // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// pseudo-ops
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index 6d9a90a..40be5d6 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -143,7 +143,7 @@ func init() {
 		// output0 = arg0/arg1, output1 = arg0%arg1
 		// see ../../../../../runtime/vlop_arm.s
 		{
-			name:      "UDIVrtcall",
+			name:      "CALLudiv",
 			argLength: 2,
 			reg: regInfo{
 				inputs:   []regMask{buildReg("R1"), buildReg("R0")},
@@ -152,6 +152,7 @@ func init() {
 			},
 			clobberFlags: true,
 			typ:          "(UInt32,UInt32)",
+			call:         false, // TODO(mdempsky): Should this be true?
 		},
 
 		{name: "ADDS", argLength: 2, reg: gp21carry, asm: "ADD", commutative: true}, // arg0 + arg1, set carry flag
@@ -193,7 +194,9 @@ func init() {
 		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
 		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
 
-		{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero
+		{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},   // count leading zero
+		{name: "REV", argLength: 1, reg: gp11, asm: "REV"},   // reverse byte order
+		{name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT"}, // reverse bit order
 
 		// shifts
 		{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 256
@@ -323,21 +326,21 @@ func init() {
 		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
 		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
 
-		{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
+		{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
 
-		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true},     // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true},    // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true},   // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
 
-		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
 
 		{name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW"},                   // load from arg0 + arg1. arg2=mem
 		{name: "MOVWloadshiftLL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1<<auxInt. arg2=mem
@@ -374,10 +377,8 @@ func init() {
 		{name: "SRAcond", argLength: 3, reg: gp2flags1, asm: "SRA"},                                         // arg0 >> 31 if flags indicates HS, arg0 >> arg1 otherwise, signed shift, arg2=flags
 
 		// function calls
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                             // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                          // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                               // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                  // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// pseudo-ops
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules
index ad7a954..60a3722 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules
@@ -10,7 +10,7 @@
 (Add64F x y) -> (ADDD x y)
 
 (Select0 (Add32carry <t> x y)) -> (ADD <t.FieldType(0)> x y)
-(Select1 (Add32carry <t> x y)) -> (SGTU <config.fe.TypeBool()> x (ADD <t.FieldType(0)> x y))
+(Select1 (Add32carry <t> x y)) -> (SGTU <typ.Bool> x (ADD <t.FieldType(0)> x y))
 (Add32withcarry <t> x y c) -> (ADD c (ADD <t> x y))
 
 (SubPtr x y) -> (SUB x y)
@@ -21,7 +21,7 @@
 (Sub64F x y) -> (SUBD x y)
 
 (Select0 (Sub32carry <t> x y)) -> (SUB <t.FieldType(0)> x y)
-(Select1 (Sub32carry <t> x y)) -> (SGTU <config.fe.TypeBool()> (SUB <t.FieldType(0)> x y) x)
+(Select1 (Sub32carry <t> x y)) -> (SGTU <typ.Bool> (SUB <t.FieldType(0)> x y) x)
 (Sub32withcarry <t> x y c) -> (SUB (SUB <t> x y) c)
 
 (Mul32 x y) -> (MUL x y)
@@ -32,10 +32,6 @@
 
 (Hmul32 x y) -> (Select0 (MULT x y))
 (Hmul32u x y) -> (Select0 (MULTU x y))
-(Hmul16 x y) -> (SRAconst (MUL <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-(Hmul16u x y) -> (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-(Hmul8 x y) -> (SRAconst  (MUL <config.fe.TypeInt32()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-(Hmul8u x y) -> (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
 
 (Mul32uhilo x y) -> (MULTU x y)
 
@@ -55,6 +51,9 @@
 (Mod8 x y) -> (Select0 (DIV (SignExt8to32 x) (SignExt8to32 y)))
 (Mod8u x y) -> (Select0 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg32u <t> x y) -> (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
+
 (And32 x y) -> (AND x y)
 (And16 x y) -> (AND x y)
 (And8 x y) -> (AND x y)
@@ -73,11 +72,11 @@
 (Rsh32x64 x (Const64 [c])) && uint32(c) < 32 -> (SRAconst x [c])
 (Rsh32Ux64 x (Const64 [c])) && uint32(c) < 32 -> (SRLconst x [c])
 (Lsh16x64 x (Const64 [c])) && uint32(c) < 16 -> (SLLconst x [c])
-(Rsh16x64 x (Const64 [c])) && uint32(c) < 16 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
-(Rsh16Ux64 x (Const64 [c])) && uint32(c) < 16 -> (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+(Rsh16x64 x (Const64 [c])) && uint32(c) < 16 -> (SRAconst (SLLconst <typ.UInt32> x [16]) [c+16])
+(Rsh16Ux64 x (Const64 [c])) && uint32(c) < 16 -> (SRLconst (SLLconst <typ.UInt32> x [16]) [c+16])
 (Lsh8x64 x (Const64 [c])) && uint32(c) < 8 -> (SLLconst x [c])
-(Rsh8x64 x (Const64 [c])) && uint32(c) < 8 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
-(Rsh8Ux64 x (Const64 [c])) && uint32(c) < 8 -> (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+(Rsh8x64 x (Const64 [c])) && uint32(c) < 8 -> (SRAconst (SLLconst <typ.UInt32> x [24]) [c+24])
+(Rsh8Ux64 x (Const64 [c])) && uint32(c) < 8 -> (SRLconst (SLLconst <typ.UInt32> x [24]) [c+24])
 
 // large constant shifts
 (Lsh32x64 _ (Const64 [c])) && uint32(c) >= 32 -> (MOVWconst [0])
@@ -89,8 +88,8 @@
 
 // large constant signed right shift, we leave the sign bit
 (Rsh32x64 x (Const64 [c])) && uint32(c) >= 32 -> (SRAconst x [31])
-(Rsh16x64 x (Const64 [c])) && uint32(c) >= 16 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
-(Rsh8x64 x (Const64 [c])) && uint32(c) >= 8 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
+(Rsh16x64 x (Const64 [c])) && uint32(c) >= 16 -> (SRAconst (SLLconst <typ.UInt32> x [16]) [31])
+(Rsh8x64 x (Const64 [c])) && uint32(c) >= 8 -> (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
 
 // shifts
 // hardware instruction uses only the low 5 bits of the shift
@@ -119,17 +118,17 @@
 (Rsh8Ux16 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 (Rsh8Ux8 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 
-(Rsh32x32 x y) -> (SRA x ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
-(Rsh32x16 x y) -> (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
-(Rsh32x8 x y) -> (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+(Rsh32x32 x y) -> (SRA x ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
+(Rsh32x16 x y) -> (SRA x ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+(Rsh32x8 x y) -> (SRA x ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 
-(Rsh16x32 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
-(Rsh16x16 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
-(Rsh16x8 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+(Rsh16x32 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
+(Rsh16x16 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+(Rsh16x8 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 
-(Rsh8x32 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
-(Rsh8x16 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
-(Rsh8x8 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+(Rsh8x32 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
+(Rsh8x16 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+(Rsh8x8 x y) -> (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 
 // unary ops
 (Neg32 x) -> (NEG x)
@@ -148,10 +147,13 @@
 // 32 - CLZ(x&-x - 1)
 (Ctz32 <t> x) -> (SUB (MOVWconst [32]) (CLZ <t> (SUBconst <t> [1] (AND <t> x (NEG <t> x)))))
 
+// bit length
+(BitLen32 <t> x) -> (SUB (MOVWconst [32]) (CLZ <t> x))
+
 // boolean ops -- booleans are represented with 0=false, 1=true
 (AndB x y) -> (AND x y)
 (OrB x y) -> (OR x y)
-(EqB x y) -> (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+(EqB x y) -> (XORconst [1] (XOR <typ.Bool> x y))
 (NeqB x y) -> (XOR x y)
 (Not x) -> (XORconst [1] x)
 
@@ -181,7 +183,7 @@
 
 (Signmask x) -> (SRAconst x [31])
 (Zeromask x) -> (NEG (SGTU x (MOVWconst [0])))
-(Slicemask x) -> (NEG (SGT x (MOVWconst [0])))
+(Slicemask <t> x) -> (SRAconst (NEG <t> x) [31])
 
 // float <-> int conversion
 (Cvt32to32F x) -> (MOVWF x)
@@ -191,6 +193,9 @@
 (Cvt32Fto64F x) -> (MOVFD x)
 (Cvt64Fto32F x) -> (MOVDF x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // comparisons
 (Eq8 x y)  -> (SGTUconst [1] (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)))
 (Eq16 x y) -> (SGTUconst [1] (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)))
@@ -262,99 +267,98 @@
 (Load <t> ptr mem) && is64BitFloat(t) -> (MOVDload ptr mem)
 
 // stores
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [4] ptr val mem) && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
-(Store [8] ptr val mem) && !is64BitFloat(val.Type) -> (MOVWstore ptr val mem)
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
 
 // zero instructions
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [0] _ mem) -> mem
+(Zero [1] ptr mem) -> (MOVBstore ptr (MOVWconst [0]) mem)
+(Zero [2] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+(Zero [2] ptr mem) ->
 	(MOVBstore [1] ptr (MOVWconst [0])
 		(MOVBstore [0] ptr (MOVWconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore ptr (MOVWconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] ptr (MOVWconst [0])
 		(MOVHstore [0] ptr (MOVWconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+(Zero [4] ptr mem) ->
 	(MOVBstore [3] ptr (MOVWconst [0])
 		(MOVBstore [2] ptr (MOVWconst [0])
 			(MOVBstore [1] ptr (MOVWconst [0])
 				(MOVBstore [0] ptr (MOVWconst [0]) mem))))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] ptr mem) ->
 	(MOVBstore [2] ptr (MOVWconst [0])
 		(MOVBstore [1] ptr (MOVWconst [0])
 			(MOVBstore [0] ptr (MOVWconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [6] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [4] ptr (MOVWconst [0])
 		(MOVHstore [2] ptr (MOVWconst [0])
 			(MOVHstore [0] ptr (MOVWconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 		(MOVWstore [4] ptr (MOVWconst [0])
 			(MOVWstore [0] ptr (MOVWconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [12] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [8] ptr (MOVWconst [0])
 		(MOVWstore [4] ptr (MOVWconst [0])
 			(MOVWstore [0] ptr (MOVWconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [16] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [12] ptr (MOVWconst [0])
 		(MOVWstore [8] ptr (MOVWconst [0])
 			(MOVWstore [4] ptr (MOVWconst [0])
 				(MOVWstore [0] ptr (MOVWconst [0]) mem))))
 
 // large or unaligned zeroing uses a loop
-(Zero [s] ptr mem)
-	&& (SizeAndAlign(s).Size() > 16  || SizeAndAlign(s).Align()%4 != 0) ->
-	(LoweredZero [SizeAndAlign(s).Align()]
+(Zero [s] {t} ptr mem)
+	&& (s > 16  || t.(*types.Type).Alignment()%4 != 0) ->
+	(LoweredZero [t.(*types.Type).Alignment()]
 		ptr
-		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)])
 		mem)
 
 // moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBUload src mem) mem)
+(Move [2] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore dst (MOVHUload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+(Move [2] dst src mem) ->
 	(MOVBstore [1] dst (MOVBUload [1] src mem)
 		(MOVBstore dst (MOVBUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] dst (MOVHUload [2] src mem)
 		(MOVHstore dst (MOVHUload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+(Move [4] dst src mem) ->
 	(MOVBstore [3] dst (MOVBUload [3] src mem)
 		(MOVBstore [2] dst (MOVBUload [2] src mem)
 			(MOVBstore [1] dst (MOVBUload [1] src mem)
 				(MOVBstore dst (MOVBUload src mem) mem))))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(Move [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBUload [2] src mem)
 		(MOVBstore [1] dst (MOVBUload [1] src mem)
 			(MOVBstore dst (MOVBUload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [4] dst (MOVWload [4] src mem)
 		(MOVWstore dst (MOVWload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [6] dst (MOVHload [6] src mem)
 		(MOVHstore [4] dst (MOVHload [4] src mem)
 			(MOVHstore [2] dst (MOVHload [2] src mem)
 				(MOVHstore dst (MOVHload src mem) mem))))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [6] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [4] dst (MOVHload [4] src mem)
 		(MOVHstore [2] dst (MOVHload [2] src mem)
 			(MOVHstore dst (MOVHload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [12] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [8] dst (MOVWload [8] src mem)
 		(MOVWstore [4] dst (MOVWload [4] src mem)
 			(MOVWstore dst (MOVWload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [16] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [12] dst (MOVWload [12] src mem)
 		(MOVWstore [8] dst (MOVWload [8] src mem)
 			(MOVWstore [4] dst (MOVWload [4] src mem)
@@ -362,19 +366,17 @@
 
 
 // large or unaligned move uses a loop
-(Move [s] dst src mem)
-	&& (SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0) ->
-	(LoweredMove [SizeAndAlign(s).Align()]
+(Move [s] {t} dst src mem)
+	&& (s > 16 || t.(*types.Type).Alignment()%4 != 0) ->
+	(LoweredMove [t.(*types.Type).Alignment()]
 		dst
 		src
-		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)])
 		mem)
 
 // 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)
 
 // atomic intrinsics
@@ -391,40 +393,40 @@
 
 // AtomicOr8(ptr,val) -> LoweredAtomicOr(ptr&^3,uint32(val) << ((ptr & 3) * 8))
 (AtomicOr8 ptr val mem) && !config.BigEndian ->
-	(LoweredAtomicOr (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr)
-		(SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val)
-			(SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst <config.fe.TypeUInt32()> [3] ptr))) mem)
+	(LoweredAtomicOr (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr)
+		(SLL <typ.UInt32> (ZeroExt8to32 val)
+			(SLLconst <typ.UInt32> [3]
+				(ANDconst <typ.UInt32> [3] ptr))) mem)
 
 // AtomicAnd8(ptr,val) -> LoweredAtomicAnd(ptr&^3,(uint32(val) << ((ptr & 3) * 8)) | ^(uint32(0xFF) << ((ptr & 3) * 8))))
 (AtomicAnd8  ptr val mem) && !config.BigEndian ->
-	(LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr)
-		(OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val)
-			(SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst  <config.fe.TypeUInt32()> [3] ptr)))
-		(NORconst [0] <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()>
-			(MOVWconst [0xff]) (SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst <config.fe.TypeUInt32()> [3] ptr))))) mem)
+	(LoweredAtomicAnd (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr)
+		(OR <typ.UInt32> (SLL <typ.UInt32> (ZeroExt8to32 val)
+			(SLLconst <typ.UInt32> [3]
+				(ANDconst  <typ.UInt32> [3] ptr)))
+		(NORconst [0] <typ.UInt32> (SLL <typ.UInt32>
+			(MOVWconst [0xff]) (SLLconst <typ.UInt32> [3]
+				(ANDconst <typ.UInt32> [3] ptr))))) mem)
 
 // AtomicOr8(ptr,val) -> LoweredAtomicOr(ptr&^3,uint32(val) << (((ptr^3) & 3) * 8))
 (AtomicOr8 ptr val mem) && config.BigEndian ->
-	(LoweredAtomicOr (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr)
-		(SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val)
-			(SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst <config.fe.TypeUInt32()> [3]
-					(XORconst <config.fe.TypeUInt32()> [3] ptr)))) mem)
+	(LoweredAtomicOr (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr)
+		(SLL <typ.UInt32> (ZeroExt8to32 val)
+			(SLLconst <typ.UInt32> [3]
+				(ANDconst <typ.UInt32> [3]
+					(XORconst <typ.UInt32> [3] ptr)))) mem)
 
 // AtomicAnd8(ptr,val) -> LoweredAtomicAnd(ptr&^3,(uint32(val) << (((ptr^3) & 3) * 8)) | ^(uint32(0xFF) << (((ptr^3) & 3) * 8))))
 (AtomicAnd8  ptr val mem) && config.BigEndian ->
-	(LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr)
-		(OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val)
-			(SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst  <config.fe.TypeUInt32()> [3]
-					(XORconst <config.fe.TypeUInt32()> [3] ptr))))
-		(NORconst [0] <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()>
-			(MOVWconst [0xff]) (SLLconst <config.fe.TypeUInt32()> [3]
-				(ANDconst <config.fe.TypeUInt32()> [3]
-					(XORconst <config.fe.TypeUInt32()> [3] ptr)))))) mem)
+	(LoweredAtomicAnd (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr)
+		(OR <typ.UInt32> (SLL <typ.UInt32> (ZeroExt8to32 val)
+			(SLLconst <typ.UInt32> [3]
+				(ANDconst  <typ.UInt32> [3]
+					(XORconst <typ.UInt32> [3] ptr))))
+		(NORconst [0] <typ.UInt32> (SLL <typ.UInt32>
+			(MOVWconst [0xff]) (SLLconst <typ.UInt32> [3]
+				(ANDconst <typ.UInt32> [3]
+					(XORconst <typ.UInt32> [3] ptr)))))) mem)
 
 
 // checks
@@ -522,11 +524,11 @@
 (MOVWstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
 	(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr 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) && isSigned(x.Type) -> x
-(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
-(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
-(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
+(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
+(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
+(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
 (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 (MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
@@ -589,16 +591,11 @@
 (MOVWreg x) && x.Uses == 1 -> (MOVWnop x)
 
 // fold constant into arithmatic ops
-(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
 (ADD x (MOVWconst [c])) -> (ADDconst [c] x)
 (SUB x (MOVWconst [c])) -> (SUBconst [c] x)
-(AND (MOVWconst [c]) x) -> (ANDconst [c] x)
 (AND x (MOVWconst [c])) -> (ANDconst [c] x)
-(OR  (MOVWconst [c]) x) -> (ORconst  [c] x)
 (OR  x (MOVWconst [c])) -> (ORconst  [c] x)
-(XOR (MOVWconst [c]) x) -> (XORconst [c] x)
 (XOR x (MOVWconst [c])) -> (XORconst [c] x)
-(NOR (MOVWconst [c]) x) -> (NORconst [c] x)
 (NOR x (MOVWconst [c])) -> (NORconst [c] x)
 
 (SLL _ (MOVWconst [c])) && uint32(c)>=32 -> (MOVWconst [0])
@@ -614,9 +611,6 @@
 (SGTU x (MOVWconst [0])) -> (SGTUzero x)
 
 // mul with constant
-(Select1 (MULTU x (MOVWconst [c]))) && x.Op != OpMIPSMOVWconst-> (Select1 (MULTU (MOVWconst [c]) x ))
-(Select0 (MULTU x (MOVWconst [c]))) && x.Op != OpMIPSMOVWconst-> (Select0 (MULTU (MOVWconst [c]) x ))
-
 (Select1 (MULTU (MOVWconst [0]) _ )) -> (MOVWconst [0])
 (Select0 (MULTU (MOVWconst [0]) _ )) -> (MOVWconst [0])
 (Select1 (MULTU (MOVWconst [1]) x )) -> x
@@ -633,7 +627,6 @@
 
 // generic simplifications
 (ADD x (NEG y)) -> (SUB x y)
-(ADD (NEG y) x) -> (SUB x y)
 (SUB x x) -> (MOVWconst [0])
 (SUB (MOVWconst [0]) x) -> (NEG x)
 (AND x x) -> x
@@ -727,12 +720,12 @@
 
 // conditional move
 (CMOVZ _ b (MOVWconst [0])) -> b
-(CMOVZ a _ (MOVWconst [c])) && c!=0-> a
+(CMOVZ a _ (MOVWconst [c])) && c!=0 -> a
 (CMOVZzero _ (MOVWconst [0])) -> (MOVWconst [0])
-(CMOVZzero a (MOVWconst [c])) && c!=0-> a
+(CMOVZzero a (MOVWconst [c])) && c!=0 -> a
 (CMOVZ a (MOVWconst [0]) c) -> (CMOVZzero a c)
 
 // atomic
 (LoweredAtomicStore ptr (MOVWconst [0]) mem) -> (LoweredAtomicStorezero ptr mem)
-(LoweredAtomicAdd ptr (MOVWconst [c]) mem) && is16Bit(c)-> (LoweredAtomicAddconst [c] ptr mem)
+(LoweredAtomicAdd ptr (MOVWconst [c]) mem) && is16Bit(c) -> (LoweredAtomicAddconst [c] ptr mem)
 
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
index 7a496be..2a3a9c2 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
@@ -27,12 +27,8 @@
 
 (Hmul64 x y) -> (Select0 (MULV x y))
 (Hmul64u x y) -> (Select0 (MULVU x y))
-(Hmul32 x y) -> (SRAVconst (Select1 <config.fe.TypeInt64()> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
-(Hmul32u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt64()> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
-(Hmul16 x y) -> (SRAVconst (Select1 <config.fe.TypeInt32()> (MULV (SignExt16to64 x) (SignExt16to64 y))) [16])
-(Hmul16u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt32()> (MULVU (ZeroExt16to64 x) (ZeroExt16to64 y))) [16])
-(Hmul8 x y) -> (SRAVconst (Select1 <config.fe.TypeInt16()> (MULV (SignExt8to64 x) (SignExt8to64 y))) [8])
-(Hmul8u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt16()> (MULVU (ZeroExt8to64 x) (ZeroExt8to64 y))) [8])
+(Hmul32 x y) -> (SRAVconst (Select1 <typ.Int64> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
+(Hmul32u x y) -> (SRLVconst (Select1 <typ.UInt64> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
 
 (Div64 x y) -> (Select1 (DIVV x y))
 (Div64u x y) -> (Select1 (DIVVU x y))
@@ -54,7 +50,8 @@
 (Mod8 x y) -> (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
 (Mod8u x y) -> (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
 
-(Avg64u <t> x y) -> (ADDV (ADDV <t> (SRLVconst <t> x [1]) (SRLVconst <t> y [1])) (AND <t> (AND <t> x y) (MOVVconst [1])))
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg64u <t> x y) -> (ADDV (SRLVconst <t> (SUBV <t> x y) [1]) y)
 
 (And64 x y) -> (AND x y)
 (And32 x y) -> (AND x y)
@@ -74,65 +71,65 @@
 // shifts
 // hardware instruction uses only the low 6 bits of the shift
 // we compare to 64 to ensure Go semantics for large shifts
-(Lsh64x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
-(Lsh64x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
-(Lsh64x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
-(Lsh64x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
-
-(Lsh32x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
-(Lsh32x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
-(Lsh32x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
-(Lsh32x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
-
-(Lsh16x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
-(Lsh16x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
-(Lsh16x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
-(Lsh16x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
-
-(Lsh8x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
-(Lsh8x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
-(Lsh8x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
-(Lsh8x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
-
-(Rsh64Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> x y))
-(Rsh64Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
-(Rsh64Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
-(Rsh64Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
-
-(Rsh32Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
-(Rsh32Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
-(Rsh32Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
-(Rsh32Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
-
-(Rsh16Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
-(Rsh16Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
-(Rsh16Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
-(Rsh16Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
-
-(Rsh8Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
-(Rsh8Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
-(Rsh8Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
-(Rsh8Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
-
-(Rsh64x64 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
-(Rsh64x32 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
-(Rsh64x16 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
-(Rsh64x8  <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
-
-(Rsh32x64 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
-(Rsh32x32 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
-(Rsh32x16 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
-(Rsh32x8  <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
-
-(Rsh16x64 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
-(Rsh16x32 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
-(Rsh16x16 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
-(Rsh16x8  <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
-
-(Rsh8x64 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
-(Rsh8x32 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
-(Rsh8x16 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
-(Rsh8x8  <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
+(Lsh64x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
+(Lsh64x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+(Lsh64x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+(Lsh64x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+
+(Lsh32x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
+(Lsh32x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+(Lsh32x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+(Lsh32x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+
+(Lsh16x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
+(Lsh16x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+(Lsh16x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+(Lsh16x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+
+(Lsh8x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
+(Lsh8x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+(Lsh8x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+(Lsh8x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+
+(Rsh64Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> x y))
+(Rsh64Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
+(Rsh64Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
+(Rsh64Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
+
+(Rsh32Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
+(Rsh32Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
+(Rsh32Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
+(Rsh32Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
+
+(Rsh16Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
+(Rsh16Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
+(Rsh16Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Rsh16Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
+
+(Rsh8Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
+(Rsh8Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
+(Rsh8Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
+(Rsh8Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
+
+(Rsh64x64 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
+(Rsh64x32 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
+(Rsh64x16 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
+(Rsh64x8  <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
+
+(Rsh32x64 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
+(Rsh32x32 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
+(Rsh32x16 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
+(Rsh32x8  <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
+
+(Rsh16x64 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
+(Rsh16x32 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
+(Rsh16x16 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
+(Rsh16x8  <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
+
+(Rsh8x64 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
+(Rsh8x32 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
+(Rsh8x16 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
+(Rsh8x8  <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
 
 // unary ops
 (Neg64 x) -> (NEGV x)
@@ -150,7 +147,7 @@
 // boolean ops -- booleans are represented with 0=false, 1=true
 (AndB x y) -> (AND x y)
 (OrB x y) -> (OR x y)
-(EqB x y) -> (XOR (MOVVconst [1]) (XOR <config.fe.TypeBool()> x y))
+(EqB x y) -> (XOR (MOVVconst [1]) (XOR <typ.Bool> x y))
 (NeqB x y) -> (XOR x y)
 (Not x) -> (XORconst [1] x)
 
@@ -164,7 +161,7 @@
 (ConstNil) -> (MOVVconst [0])
 (ConstBool [b]) -> (MOVVconst [b])
 
-(Slicemask <t> x) -> (NORconst [0] (SRAVconst <t> (SUBVconst <t> x [1]) [63]))
+(Slicemask <t> x) -> (SRAVconst (NEGV <t> x) [63])
 
 // truncations
 // Because we ignore high parts of registers, truncates are just copies.
@@ -202,6 +199,9 @@
 (Cvt32Fto64F x) -> (MOVFD x)
 (Cvt64Fto32F x) -> (MOVDF x)
 
+(Round32F x) -> x
+(Round64F x) -> x
+
 // comparisons
 (Eq8 x y)  -> (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
 (Eq16 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
@@ -285,140 +285,138 @@
 (Load <t> ptr mem) && is64BitFloat(t) -> (MOVDload ptr mem)
 
 // stores
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [4] ptr val mem) && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
-(Store [8] ptr val mem) && !is64BitFloat(val.Type) -> (MOVVstore ptr val mem)
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type) -> (MOVVstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
 
 // zeroing
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVVconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [0] _ mem) -> mem
+(Zero [1] ptr mem) -> (MOVBstore ptr (MOVVconst [0]) mem)
+(Zero [2] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore ptr (MOVVconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+(Zero [2] ptr mem) ->
 	(MOVBstore [1] ptr (MOVVconst [0])
 		(MOVBstore [0] ptr (MOVVconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore ptr (MOVVconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] ptr (MOVVconst [0])
 		(MOVHstore [0] ptr (MOVVconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+(Zero [4] ptr mem) ->
 	(MOVBstore [3] ptr (MOVVconst [0])
 		(MOVBstore [2] ptr (MOVVconst [0])
 			(MOVBstore [1] ptr (MOVVconst [0])
 				(MOVBstore [0] ptr (MOVVconst [0]) mem))))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore ptr (MOVVconst [0]) mem)
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [4] ptr (MOVVconst [0])
 		(MOVWstore [0] ptr (MOVVconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [6] ptr (MOVVconst [0])
 		(MOVHstore [4] ptr (MOVVconst [0])
 			(MOVHstore [2] ptr (MOVVconst [0])
 				(MOVHstore [0] ptr (MOVVconst [0]) mem))))
 
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [3] ptr mem) ->
 	(MOVBstore [2] ptr (MOVVconst [0])
 		(MOVBstore [1] ptr (MOVVconst [0])
 			(MOVBstore [0] ptr (MOVVconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
+(Zero [6] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [4] ptr (MOVVconst [0])
 		(MOVHstore [2] ptr (MOVVconst [0])
 			(MOVHstore [0] ptr (MOVVconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [12] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [8] ptr (MOVVconst [0])
 		(MOVWstore [4] ptr (MOVVconst [0])
 			(MOVWstore [0] ptr (MOVVconst [0]) mem)))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [16] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore [8] ptr (MOVVconst [0])
 		(MOVVstore [0] ptr (MOVVconst [0]) mem))
-(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [24] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore [16] ptr (MOVVconst [0])
 		(MOVVstore [8] ptr (MOVVconst [0])
 			(MOVVstore [0] ptr (MOVVconst [0]) mem)))
 
 // medium zeroing uses a duff device
 // 8, and 128 are magic constants, see runtime/mkduff.go
-(Zero [s] ptr mem)
-	&& SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128
-	&& SizeAndAlign(s).Align()%8 == 0 && !config.noDuffDevice ->
-	(DUFFZERO [8 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
+(Zero [s] {t} ptr mem)
+	&& s%8 == 0 && s > 24 && s <= 8*128
+	&& t.(*types.Type).Alignment()%8 == 0 && !config.noDuffDevice ->
+	(DUFFZERO [8 * (128 - int64(s/8))] ptr mem)
 
 // large or unaligned zeroing uses a loop
-(Zero [s] ptr mem)
-	&& (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0 ->
-	(LoweredZero [SizeAndAlign(s).Align()]
+(Zero [s] {t} ptr mem)
+	&& (s > 8*128 || config.noDuffDevice) || t.(*types.Type).Alignment()%8 != 0 ->
+	(LoweredZero [t.(*types.Type).Alignment()]
 		ptr
-		(ADDVconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDVconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)])
 		mem)
 
 // moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBload src mem) mem)
+(Move [2] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore dst (MOVHload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+(Move [2] dst src mem) ->
 	(MOVBstore [1] dst (MOVBload [1] src mem)
 		(MOVBstore dst (MOVBload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [2] dst (MOVHload [2] src mem)
 		(MOVHstore dst (MOVHload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+(Move [4] dst src mem) ->
 	(MOVBstore [3] dst (MOVBload [3] src mem)
 		(MOVBstore [2] dst (MOVBload [2] src mem)
 			(MOVBstore [1] dst (MOVBload [1] src mem)
 				(MOVBstore dst (MOVBload src mem) mem))))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore dst (MOVVload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [4] dst (MOVWload [4] src mem)
 		(MOVWstore dst (MOVWload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [6] dst (MOVHload [6] src mem)
 		(MOVHstore [4] dst (MOVHload [4] src mem)
 			(MOVHstore [2] dst (MOVHload [2] src mem)
 				(MOVHstore dst (MOVHload src mem) mem))))
 
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+(Move [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBload [2] src mem)
 		(MOVBstore [1] dst (MOVBload [1] src mem)
 			(MOVBstore dst (MOVBload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
+(Move [6] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
 	(MOVHstore [4] dst (MOVHload [4] src mem)
 		(MOVHstore [2] dst (MOVHload [2] src mem)
 			(MOVHstore dst (MOVHload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [12] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVWstore [8] dst (MOVWload [8] src mem)
 		(MOVWstore [4] dst (MOVWload [4] src mem)
 			(MOVWstore dst (MOVWload src mem) mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
+(Move [16] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore [8] dst (MOVVload [8] src mem)
 		(MOVVstore dst (MOVVload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
+(Move [24] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
 	(MOVVstore [16] dst (MOVVload [16] src mem)
 		(MOVVstore [8] dst (MOVVload [8] src mem)
 			(MOVVstore dst (MOVVload src mem) mem)))
 
 // large or unaligned move uses a loop
-(Move [s] dst src mem)
-	&& SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0 ->
-	(LoweredMove [SizeAndAlign(s).Align()]
+(Move [s] {t} dst src mem)
+	&& s > 24 || t.(*types.Type).Alignment()%8 != 0 ->
+	(LoweredMove [t.(*types.Type).Alignment()]
 		dst
 		src
-		(ADDVconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
+		(ADDVconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)])
 		mem)
 
 // 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)
 
 // checks
@@ -581,16 +579,11 @@
 (MOVVreg x) && x.Uses == 1 -> (MOVVnop x)
 
 // fold constant into arithmatic ops
-(ADDV (MOVVconst [c]) x) && is32Bit(c) -> (ADDVconst [c] x)
 (ADDV x (MOVVconst [c])) && is32Bit(c) -> (ADDVconst [c] x)
 (SUBV x (MOVVconst [c])) && is32Bit(c) -> (SUBVconst [c] x)
-(AND (MOVVconst [c]) x) && is32Bit(c) -> (ANDconst [c] x)
 (AND x (MOVVconst [c])) && is32Bit(c) -> (ANDconst [c] x)
-(OR  (MOVVconst [c]) x) && is32Bit(c) -> (ORconst  [c] x)
 (OR  x (MOVVconst [c])) && is32Bit(c) -> (ORconst  [c] x)
-(XOR (MOVVconst [c]) x) && is32Bit(c) -> (XORconst [c] x)
 (XOR x (MOVVconst [c])) && is32Bit(c) -> (XORconst [c] x)
-(NOR (MOVVconst [c]) x) && is32Bit(c) -> (NORconst [c] x)
 (NOR x (MOVVconst [c])) && is32Bit(c) -> (NORconst [c] x)
 
 (SLLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
@@ -622,7 +615,6 @@
 
 // generic simplifications
 (ADDV x (NEGV y)) -> (SUBV x y)
-(ADDV (NEGV y) x) -> (SUBV x y)
 (SUBV x x) -> (MOVVconst [0])
 (SUBV (MOVVconst [0]) x) -> (NEGV x)
 (AND x x) -> x
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
index 020d693..b0e6564 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
@@ -217,29 +217,29 @@ func init() {
 		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
 		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
 
-		{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
-
-		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true},     // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true},    // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true},    // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true},   // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-
-		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-
-		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
+		{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
+
+		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+
+		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+
+		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
 
 		// conversions
 		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
@@ -264,10 +264,8 @@ func init() {
 		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
 
 		// function calls
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                              // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                           // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                   // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// duffzero
diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go
index 3d88b71..b632c6b 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPSOps.go
+++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.go
@@ -206,25 +206,25 @@ func init() {
 		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
 		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
 
-		{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
-
-		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true},     // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true},    // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true}, // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true},   // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true},  // load from arg0 + auxInt + aux.  arg1=mem.
-
-		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
-
-		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
-		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
+
+		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
+
+		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+
+		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
 
 		// conversions
 		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
@@ -248,11 +248,9 @@ func init() {
 		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
 
 		// function calls
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                              // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int32", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int32", clobberFlags: true, call: true},                                                // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int32", clobberFlags: true, call: true},                                                   // call newproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int32", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                           // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
+		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// atomic ops
 
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index cad753e..81ac3c2 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -28,7 +28,8 @@
 (Mod32 x y) -> (SUB x (MULLW y (DIVW x y)))
 (Mod32u x y) -> (SUB x (MULLW y (DIVWU x y)))
 
-(Avg64u <t> x y) -> (ADD (ADD <t> (SRD <t> x (MOVDconst <t> [1])) (SRD <t> y (MOVDconst <t> [1]))) (ANDconst <t> (AND <t> x y) [1]))
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg64u <t> x y) -> (ADD (SRDconst <t> (SUB <t> x y) [1]) y)
 
 (Mul64  x y) -> (MULLD  x y)
 (Mul32  x y) -> (MULLW  x y)
@@ -48,10 +49,6 @@
 (Hmul64u  x y) -> (MULHDU x y)
 (Hmul32  x y) -> (MULHW  x y)
 (Hmul32u  x y) -> (MULHWU x y)
-(Hmul16 x y) -> (SRAWconst (MULLW <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-(Hmul16u x y) -> (SRWconst (MULLW <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-(Hmul8 x y) -> (SRAWconst (MULLW <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-(Hmul8u x y) -> (SRWconst (MULLW <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
 
 (Mul32F x y) -> (FMULS x y)
 (Mul64F x y) -> (FMUL x y)
@@ -73,6 +70,9 @@
 (Cvt32Fto64F x) -> x // Note x will have the wrong type for patterns dependent on Float32/Float64
 (Cvt64Fto32F x) -> (FRSP x)
 
+(Round32F x) -> (LoweredRound32F x)
+(Round64F x) -> (LoweredRound64F x)
+
 (Sqrt x) -> (FSQRT x)
 
 // Lowering constants
@@ -85,6 +85,15 @@
 (ConstNil) -> (MOVDconst [0])
 (ConstBool [b]) -> (MOVDconst [b])
 
+// Rotate generation
+(ADD (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (ROTLconst [c] x)
+( OR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (ROTLconst [c] x)
+(XOR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (ROTLconst [c] x)
+
+(ADD (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (ROTLWconst [c] x)
+( OR (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (ROTLWconst [c] x)
+(XOR (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (ROTLWconst [c] x)
+
 (Lsh64x64  x (Const64 [c])) && uint64(c) < 64 -> (SLDconst x [c])
 (Rsh64x64  x (Const64 [c])) && uint64(c) < 64 -> (SRADconst x [c])
 (Rsh64Ux64 x (Const64 [c])) && uint64(c) < 64 -> (SRDconst x [c])
@@ -154,72 +163,72 @@
 (Rsh8x32   x (MOVDconst [c])) && uint32(c) < 8  -> (SRAWconst (SignExt8to32  x) [c])
 (Rsh8Ux32  x (MOVDconst [c])) && uint32(c) < 8  -> (SRWconst (ZeroExt8to32  x) [c])
 
-(Rsh64x64 x y)  -> (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
-(Rsh64Ux64 x y) -> (SRD  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
-(Lsh64x64 x y)  -> (SLD  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+(Rsh64x64 x y)  -> (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+(Rsh64Ux64 x y) -> (SRD  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+(Lsh64x64 x y)  -> (SLD  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
 
-(Rsh32x64 x y)  -> (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
-(Rsh32Ux64 x y) -> (SRW  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
-(Lsh32x64 x y)  -> (SLW  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+(Rsh32x64 x y)  -> (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+(Rsh32Ux64 x y) -> (SRW  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+(Lsh32x64 x y)  -> (SLW  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
 
-(Rsh16x64 x y)  -> (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
-(Rsh16Ux64 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
-(Lsh16x64 x y)  -> (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+(Rsh16x64 x y)  -> (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+(Rsh16Ux64 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+(Lsh16x64 x y)  -> (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
 
-(Rsh8x64 x y)  -> (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
-(Rsh8Ux64 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
-(Lsh8x64 x y)  -> (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+(Rsh8x64 x y)  -> (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+(Rsh8Ux64 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+(Lsh8x64 x y)  -> (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
 
 
-(Rsh64x32 x y)  -> (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
-(Rsh64Ux32 x y) -> (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
-(Lsh64x32 x y)  -> (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+(Rsh64x32 x y)  -> (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+(Rsh64Ux32 x y) -> (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+(Lsh64x32 x y)  -> (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
 
-(Rsh32x32 x y)  -> (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
-(Rsh32Ux32 x y) -> (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
-(Lsh32x32 x y)  -> (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+(Rsh32x32 x y)  -> (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+(Rsh32Ux32 x y) -> (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+(Lsh32x32 x y)  -> (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
 
-(Rsh16x32 x y)  -> (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
-(Rsh16Ux32 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
-(Lsh16x32 x y)  -> (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+(Rsh16x32 x y)  -> (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+(Rsh16Ux32 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+(Lsh16x32 x y)  -> (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
 
-(Rsh8x32 x y)  -> (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
-(Rsh8Ux32 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
-(Lsh8x32 x y)  -> (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+(Rsh8x32 x y)  -> (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+(Rsh8Ux32 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+(Lsh8x32 x y)  -> (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
 
 
-(Rsh64x16 x y)  -> (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
-(Rsh64Ux16 x y) -> (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
-(Lsh64x16 x y)  -> (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+(Rsh64x16 x y)  -> (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+(Rsh64Ux16 x y) -> (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+(Lsh64x16 x y)  -> (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
 
-(Rsh32x16 x y)  -> (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
-(Rsh32Ux16 x y) -> (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
-(Lsh32x16 x y)  -> (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+(Rsh32x16 x y)  -> (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+(Rsh32Ux16 x y) -> (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+(Lsh32x16 x y)  -> (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
 
-(Rsh16x16 x y)  -> (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
-(Rsh16Ux16 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
-(Lsh16x16 x y)  -> (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+(Rsh16x16 x y)  -> (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+(Rsh16Ux16 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+(Lsh16x16 x y)  -> (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
 
-(Rsh8x16 x y)  -> (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
-(Rsh8Ux16 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
-(Lsh8x16 x y)  -> (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+(Rsh8x16 x y)  -> (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+(Rsh8Ux16 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+(Lsh8x16 x y)  -> (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
 
 
-(Rsh64x8 x y)  -> (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
-(Rsh64Ux8 x y) -> (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
-(Lsh64x8 x y)  -> (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+(Rsh64x8 x y)  -> (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+(Rsh64Ux8 x y) -> (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+(Lsh64x8 x y)  -> (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
 
-(Rsh32x8 x y)  -> (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
-(Rsh32Ux8 x y) -> (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
-(Lsh32x8 x y)  -> (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+(Rsh32x8 x y)  -> (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+(Rsh32Ux8 x y) -> (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+(Lsh32x8 x y)  -> (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
 
-(Rsh16x8 x y)  -> (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
-(Rsh16Ux8 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
-(Lsh16x8 x y)  -> (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+(Rsh16x8 x y)  -> (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+(Rsh16Ux8 x y) -> (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+(Lsh16x8 x y)  -> (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
 
-(Rsh8x8 x y)  -> (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
-(Rsh8Ux8 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
-(Lsh8x8 x y)  -> (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+(Rsh8x8 x y)  -> (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+(Rsh8Ux8 x y) -> (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+(Lsh8x8 x y)  -> (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
 
 // Cleaning up shift ops when input is masked
 (MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _))) && c < 0 && d > 0 && c + d < 0 -> (MOVDconst [-1])
@@ -233,7 +242,18 @@
 
 (Addr {sym} base) -> (MOVDaddr {sym} base)
 // (Addr {sym} base) -> (ADDconst {sym} base)
-(OffPtr [off] ptr) -> (ADD (MOVDconst <config.Frontend().TypeInt64()> [off]) ptr)
+(OffPtr [off] ptr) -> (ADD (MOVDconst <typ.Int64> [off]) ptr)
+
+(Ctz64 x) -> (POPCNTD (ANDN <typ.Int64> (ADDconst <typ.Int64> [-1] x) x))
+(Ctz32 x) -> (POPCNTW (MOVWZreg (ANDN <typ.Int> (ADDconst <typ.Int> [-1] x) x)))
+
+(BitLen64 x) -> (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
+(BitLen32 x) -> (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
+
+(PopCount64 x) -> (POPCNTD x)
+(PopCount32 x) -> (POPCNTW (MOVWZreg x))
+(PopCount16 x) -> (POPCNTW (MOVHZreg x))
+(PopCount8 x) -> (POPCNTB (MOVBreg x))
 
 (And64 x y) -> (AND x y)
 (And32 x y) -> (AND x y)
@@ -257,10 +277,10 @@
 (Neg16  x) -> (NEG x)
 (Neg8   x) -> (NEG x)
 
-(Com64 x) -> (XORconst [-1] x)
-(Com32 x) -> (XORconst [-1] x)
-(Com16 x) -> (XORconst [-1] x)
-(Com8  x) -> (XORconst [-1] x)
+(Com64 x) -> (NOR x x)
+(Com32 x) -> (NOR x x)
+(Com16 x) -> (NOR x x)
+(Com8  x) -> (NOR x x)
 
 // Lowering boolean ops
 (AndB x y) -> (AND x y)
@@ -268,7 +288,7 @@
 (Not x) -> (XORconst [1] x)
 
 // Use ANDN for AND x NOT y
-(AND x (XORconst [-1] y)) -> (ANDN x y)
+(AND x (NOR y y)) -> (ANDN x y)
 
 // Lowering comparisons
 (EqB x y)  -> (ANDconst [1] (EQV x y))
@@ -477,119 +497,121 @@
 (Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
 (Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
 
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
-(Store [8] ptr val mem) && is32BitFloat(val.Type) -> (FMOVDstore ptr val mem) // glitch from (Cvt32Fto64F x) -> x -- type is wrong
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
-(Store [8] ptr val mem) && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVDstore ptr val mem)
-(Store [4] ptr val mem) && is32BitInt(val.Type) -> (MOVWstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
-
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstorezero destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is32BitFloat(val.Type) -> (FMOVDstore ptr val mem) // glitch from (Cvt32Fto64F x) -> x -- type is wrong
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitInt(val.Type) -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
+
+// Using Zero instead of LoweredZero allows the
+// target address to be folded where possible.
+(Zero [0] _ mem) -> mem
+(Zero [1] destptr mem) -> (MOVBstorezero destptr mem)
+(Zero [2] destptr mem) ->
 	(MOVHstorezero destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 ->
-	(MOVBstorezero [1] destptr
-		(MOVBstorezero [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+(Zero [3] destptr mem) ->
+	(MOVBstorezero [2] destptr
+		(MOVHstorezero destptr mem))
+(Zero [4] destptr mem) ->
 	(MOVWstorezero destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
-	(MOVHstorezero [2] destptr
-		(MOVHstorezero [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 ->
-	(MOVBstorezero [3] destptr
-		(MOVBstorezero [2] destptr
-			(MOVBstorezero [1] destptr
-				(MOVBstorezero [0] destptr mem))))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
-	(MOVDstorezero [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
-	(MOVWstorezero [4] destptr
-		(MOVWstorezero [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0 ->
-	(MOVHstorezero [6] destptr
+(Zero [5] destptr mem) ->
+	(MOVBstorezero [4] destptr
+        	(MOVWstorezero destptr mem))
+(Zero [6] destptr mem) ->
+	(MOVHstorezero [4] destptr
+		(MOVWstorezero destptr mem))
+(Zero [7] destptr mem) ->
+	(MOVBstorezero [6] destptr
 		(MOVHstorezero [4] destptr
-			(MOVHstorezero [2] destptr
-				(MOVHstorezero [0] destptr mem))))
-
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
-	(MOVBstorezero [2] destptr
-		(MOVBstorezero [1] destptr
-			(MOVBstorezero [0] destptr mem)))
+			(MOVWstorezero destptr mem)))
+(Zero [8] destptr mem) ->
+	(MOVDstorezero destptr mem)
 
 // Zero small numbers of words directly.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [12] destptr mem) ->
+        (MOVWstorezero [8] destptr
+                (MOVDstorezero [0] destptr mem))
+(Zero [16] destptr mem) ->
 	(MOVDstorezero [8] destptr
                 (MOVDstorezero [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [24] destptr mem) ->
 	(MOVDstorezero [16] destptr
 		(MOVDstorezero [8] destptr
 			(MOVDstorezero [0] destptr mem)))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 32 && SizeAndAlign(s).Align()%8 == 0 ->
+(Zero [32] destptr mem) ->
 	(MOVDstorezero [24] destptr
 		(MOVDstorezero [16] destptr
 			(MOVDstorezero [8] destptr
 				(MOVDstorezero [0] destptr mem))))
 
-// Large zeroing uses a loop
-(Zero [s] ptr mem)
-	&& (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0 ->
-	(LoweredZero [SizeAndAlign(s).Align()]
-		ptr
-		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
-		mem)
+(Zero [40] destptr mem) ->
+	(MOVDstorezero [32] destptr
+		(MOVDstorezero [24] destptr
+			(MOVDstorezero [16] destptr
+				(MOVDstorezero [8] destptr
+					(MOVDstorezero [0] destptr mem)))))
+
+(Zero [48] destptr mem) ->
+	(MOVDstorezero [40] destptr
+		(MOVDstorezero [32] destptr
+			(MOVDstorezero [24] destptr
+				(MOVDstorezero [16] destptr
+					(MOVDstorezero [8] destptr
+						(MOVDstorezero [0] destptr mem))))))
+
+(Zero [56] destptr mem) ->
+	(MOVDstorezero [48] destptr
+		(MOVDstorezero [40] destptr
+			(MOVDstorezero [32] destptr
+				(MOVDstorezero [24] destptr
+					(MOVDstorezero [16] destptr
+						(MOVDstorezero [8] destptr
+							(MOVDstorezero [0] destptr mem)))))))
+
+// Handle cases not handled above
+(Zero [s] ptr mem) -> (LoweredZero [s] ptr mem)
 
 // moves
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBZload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
-	(MOVHstore dst (MOVHZload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
-	(MOVBstore [1] dst (MOVBZload [1] src mem)
-		(MOVBstore dst (MOVBZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
-	(MOVWstore dst (MOVWload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
-	(MOVHstore [2] dst (MOVHZload [2] src mem)
-		(MOVHstore dst (MOVHZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
-	(MOVBstore [3] dst (MOVBZload [3] src mem)
-		(MOVBstore [2] dst (MOVBZload [2] src mem)
-			(MOVBstore [1] dst (MOVBZload [1] src mem)
-				(MOVBstore dst (MOVBZload src mem) mem))))
-
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
+// Only the MOVD and MOVW instructions require 4 byte
+// alignment in the offset field.  The other MOVx instructions
+// allow any alignment.
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBZload src mem) mem)
+(Move [2] dst src mem) ->
+        (MOVHstore dst (MOVHZload src mem) mem)
+(Move [4] dst src mem) ->
+	(MOVWstore dst (MOVWZload src mem) mem)
+// MOVD for load and store must have offsets that are multiple of 4
+(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
 	(MOVDstore dst (MOVDload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+(Move [8] dst src mem) ->
 	(MOVWstore [4] dst (MOVWZload [4] src mem)
 		(MOVWstore dst (MOVWZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0->
-	(MOVHstore [6] dst (MOVHZload [6] src mem)
-		(MOVHstore [4] dst (MOVHZload [4] src mem)
-			(MOVHstore [2] dst (MOVHZload [2] src mem)
-				(MOVHstore dst (MOVHZload src mem) mem))))
-
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
-	(MOVBstore [2] dst (MOVBZload [2] src mem)
-		(MOVBstore [1] dst (MOVBZload [1] src mem)
-			(MOVBstore dst (MOVBZload src mem) mem)))
-
-// Large move uses a loop
-(Move [s] dst src mem)
-	&& (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0 ->
-	(LoweredMove [SizeAndAlign(s).Align()]
-		dst
-		src
-		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
-		mem)
+(Move [3] dst src mem) ->
+        (MOVBstore [2] dst (MOVBZload [2] src mem)
+                (MOVHstore dst (MOVHload src mem) mem))
+(Move [5] dst src mem) ->
+        (MOVBstore [4] dst (MOVBZload [4] src mem)
+                (MOVWstore dst (MOVWZload src mem) mem))
+(Move [6] dst src mem) ->
+        (MOVHstore [4] dst (MOVHZload [4] src mem)
+                (MOVWstore dst (MOVWZload src mem) mem))
+(Move [7] dst src mem) ->
+        (MOVBstore [6] dst (MOVBZload [6] src mem)
+                (MOVHstore [4] dst (MOVHZload [4] src mem)
+                        (MOVWstore dst (MOVWZload src mem) mem)))
+
+// Large move uses a loop. Since the address is computed and the
+// offset is zero, any alignment can be used.
+(Move [s] dst src mem) && s > 8 ->
+        (LoweredMove [s] dst src mem)
 
 // Calls
 // 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
@@ -613,9 +635,6 @@
 (AND x (MOVDconst [c])) && isU16Bit(c) -> (ANDconst [c] x)
 (XOR x (MOVDconst [c])) && isU32Bit(c) -> (XORconst [c] x)
 (OR x (MOVDconst [c])) && isU32Bit(c) -> (ORconst [c] x)
-(AND (MOVDconst [c]) x) && isU16Bit(c) -> (ANDconst [c] x)
-(XOR (MOVDconst [c]) x) && isU32Bit(c) -> (XORconst [c] x)
-(OR (MOVDconst [c]) x) && isU32Bit(c) -> (ORconst [c] x)
 
 // Simplify consts
 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
@@ -681,7 +700,6 @@
 
 // Arithmetic constant ops
 
-(ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x)
 (ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x)
 (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x)
 (ADDconst [0] x) -> x
@@ -767,6 +785,27 @@
 (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) ->
     (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
 
+// atomic intrinsics
+(AtomicLoad32  ptr mem) -> (LoweredAtomicLoad32 ptr mem)
+(AtomicLoad64  ptr mem) -> (LoweredAtomicLoad64 ptr mem)
+(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoadPtr ptr mem)
+
+(AtomicStore32      ptr val mem) -> (LoweredAtomicStore32 ptr val mem)
+(AtomicStore64      ptr val mem) -> (LoweredAtomicStore64 ptr val mem)
+//(AtomicStorePtrNoWB ptr val mem) -> (STLR  ptr val mem)
+
+(AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem)
+(AtomicExchange64 ptr val mem) -> (LoweredAtomicExchange64 ptr val mem)
+
+(AtomicAdd32 ptr val mem) -> (LoweredAtomicAdd32 ptr val mem)
+(AtomicAdd64 ptr val mem) -> (LoweredAtomicAdd64 ptr val mem)
+
+(AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem)
+(AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem)
+
+(AtomicAnd8 ptr val mem) -> (LoweredAtomicAnd8 ptr val mem)
+(AtomicOr8  ptr val mem) -> (LoweredAtomicOr8  ptr val mem)
+
 // Lowering extension
 // Note: we always extend to 64 bits even though some ops don't need that many result bits.
 (SignExt8to16  x) -> (MOVBreg x)
@@ -790,7 +829,7 @@
 (Trunc64to16 x) -> (MOVHreg x)
 (Trunc64to32 x) -> (MOVWreg x)
 
-(Slicemask <t> x) -> (XORconst [-1] (SRADconst <t> (ADDconst <t> x [-1]) [63]))
+(Slicemask <t> x) -> (SRADconst (NEG <t> x) [63])
 
 // Note that MOV??reg returns a 64-bit int, x is not necessarily that wide
 // This may interact with other patterns in the future. (Compare with arm64)
@@ -830,3 +869,9 @@
 // A particular pattern seen in cgo code:
 (AND (MOVDconst [c]) x:(MOVBZload _ _)) -> (ANDconst [c&0xFF] x)
 (AND x:(MOVBZload _ _) (MOVDconst [c])) -> (ANDconst [c&0xFF] x)
+
+// floating-point fused multiply-add/sub
+(FADD (FMUL x y) z) -> (FMADD x y z)
+(FSUB (FMUL x y) z) -> (FMSUB x y z)
+(FADDS (FMULS x y) z) -> (FMADDS x y z)
+(FSUBS (FMULS x y) z) -> (FMSUBS x y z)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index 0034797..2e8e239 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -140,24 +140,27 @@ func init() {
 		gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
 		gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
 		gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
+		gpxchg      = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
+		gpcas       = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
 		fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
 		fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
 		fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
 		gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
 		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
+		fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
 		fp2cr       = regInfo{inputs: []regMask{fp, fp}}
 		fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
 		fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
 		callerSave  = regMask(gp | fp | gr)
 	)
 	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: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},   // arg0+arg1
-		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
-		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                        // arg0-arg1
-		{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                      // arg0-arg1
-		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                    // arg0-arg1
+		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},                     // arg0 + arg1
+		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff", symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym)
+		{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},                   // arg0+arg1
+		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true},                 // arg0+arg1
+		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                                        // arg0-arg1
+		{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                                      // arg0-arg1
+		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                                    // arg0-arg1
 
 		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
 		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
@@ -170,6 +173,11 @@ func init() {
 		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1
 		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1
 
+		{name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"},   // arg0*arg1 + arg2
+		{name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1 + arg2
+		{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"},   // arg0*arg1 - arg2
+		{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
+
 		{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
 		{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
 		{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},   // arg0 >> arg1, 64 bits  (0 if arg1 & 64 != 0)
@@ -187,6 +195,16 @@ func init() {
 		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"},   // arg0 << aux, 64 bits
 		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},   // arg0 << aux, 32 bits
 
+		{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"},   // arg0 rotate left by auxInt bits
+		{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
+
+		{name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD", clobberFlags: true}, // count leading zeros
+		{name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW", clobberFlags: true}, // count leading zeros (32 bit)
+
+		{name: "POPCNTD", argLength: 1, reg: gp11, asm: "POPCNTD"}, // number of set bits in arg0
+		{name: "POPCNTW", argLength: 1, reg: gp11, asm: "POPCNTW"}, // number of set bits in each word of arg0 placed in corresponding word
+		{name: "POPCNTB", argLength: 1, reg: gp11, asm: "POPCNTB"}, // number of set bits in each byte of arg0 placed in corresonding byte
+
 		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1
 		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
 
@@ -209,13 +227,14 @@ func init() {
 		// There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use
 		// the word-load instructions.  (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr)
 
-		{name: "Xf2i64", argLength: 1, reg: fpgp, typ: "Int64", usesScratch: true},   // move 64 bits of F register into G register
-		{name: "Xi2f64", argLength: 1, reg: gpfp, typ: "Float64", usesScratch: true}, // move 64 bits of G register into F register
+		{name: "Xf2i64", argLength: 1, reg: fpgp, typ: "Int64"},   // move 64 bits of F register into G register
+		{name: "Xi2f64", argLength: 1, reg: gpfp, typ: "Float64"}, // move 64 bits of G register into F register
 
 		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},               // arg0&arg1
 		{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                // arg0&^arg1
 		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                 // arg0|arg1
 		{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                  // arg0|^arg1
+		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},               // ^(arg0|arg1)
 		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
 		{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
 		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                  // -arg0 (integer)
@@ -228,34 +247,34 @@ func init() {
 		{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", clobberFlags: true}, // arg0&aux // and-immediate sets CC on PPC, always.
 		{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}}, asm: "ANDCC", aux: "Int64", typ: "Flags"},                             // arg0&aux == 0 // and-immediate sets CC on PPC, always.
 
-		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},                                            // sign extend int8 to int64
-		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"},                                          // zero extend uint8 to uint64
-		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},                                            // sign extend int16 to int64
-		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"},                                          // zero extend uint16 to uint64
-		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},                                            // sign extend int32 to int64
-		{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"},                                          // zero extend uint32 to uint64
-		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true},  // zero extend uint8 to uint64
-		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true},    // sign extend int16 to int64
-		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // zero extend uint16 to uint64
-		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true},    // sign extend int32 to int64
-		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true}, // zero extend uint32 to uint64
-		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true},
-
-		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true},
-		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true},
-		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
-
-		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero byte to arg0+aux.  arg1=mem
-		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 2 bytes to ...
-		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 4 bytes to ...
-		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 8 bytes to ...
-
-		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
+		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},                                                               // sign extend int8 to int64
+		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"},                                                             // zero extend uint8 to uint64
+		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},                                                               // sign extend int16 to int64
+		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"},                                                             // zero extend uint16 to uint64
+		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},                                                               // sign extend int32 to int64
+		{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"},                                                             // zero extend uint32 to uint64
+		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // zero extend uint8 to uint64
+		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int16 to int64
+		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint16 to uint64
+		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int32 to int64
+		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint32 to uint64
+		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},
+
+		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},
+		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},
+		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
+
+		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero byte to arg0+aux.  arg1=mem
+		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 2 bytes to ...
+		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes to ...
+		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes to ...
+
+		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
 
 		{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
 		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           //
@@ -290,57 +309,91 @@ func init() {
 
 		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
 		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
+		// Round ops to block fused-multiply-add extraction.
+		{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true},
+		{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true},
 
 		// Convert pointer to integer, takes a memory operand for ordering.
 		{name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"},
 
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                      // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                   // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gp | sp, ctxt, 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                        // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                           // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                 // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// large or unaligned zeroing
 		// arg0 = address of memory to zero (in R3, changed as side effect)
-		// arg1 = address of the last element to zero
-		// arg2 = mem
 		// returns mem
-		//  ADD -8,R3,R3 // intermediate value not valid GC ptr, cannot expose to opt+GC
-		//	MOVDU	R0, 8(R3)
-		//	CMP	R3, Rarg1
-		//	BLE	-2(PC)
+		//
+		// a loop is generated when there is more than one iteration
+		// needed to clear 4 doublewords
+		//
+		// 	MOVD	$len/32,R31
+		//	MOVD	R31,CTR
+		//	loop:
+		//	MOVD	R0,(R3)
+		//	MOVD	R0,8(R3)
+		//	MOVD	R0,16(R3)
+		//	MOVD	R0,24(R3)
+		//	ADD	R3,32
+		//	BC	loop
+
+		// remaining doubleword clears generated as needed
+		//	MOVD	R0,(R3)
+		//	MOVD	R0,8(R3)
+		//	MOVD	R0,16(R3)
+		//	MOVD	R0,24(R3)
+
+		// one or more of these to clear remainder < 8 bytes
+		//	MOVW	R0,n1(R3)
+		//	MOVH	R0,n2(R3)
+		//	MOVB	R0,n3(R3)
 		{
 			name:      "LoweredZero",
 			aux:       "Int64",
-			argLength: 3,
+			argLength: 2,
 			reg: regInfo{
-				inputs:   []regMask{buildReg("R3"), gp},
+				inputs:   []regMask{buildReg("R3")},
 				clobbers: buildReg("R3"),
 			},
 			clobberFlags:   true,
 			typ:            "Mem",
 			faultOnNilArg0: true,
 		},
+		// Loop code:
+		//	MOVD len/32,REG_TMP  only for loop
+		//	MOVD REG_TMP,CTR     only for loop
+		// loop:
+		//	MOVD (R4),R7
+		//	MOVD 8(R4),R8
+		//	MOVD 16(R4),R9
+		//	MOVD 24(R4),R10
+		//	ADD  R4,$32          only with loop
+		//	MOVD R7,(R3)
+		//	MOVD R8,8(R3)
+		//	MOVD R9,16(R3)
+		//	MOVD R10,24(R3)
+		//	ADD  R3,$32          only with loop
+		//	BC 16,0,loop         only with loop
+		// Bytes not moved by this loop are moved
+		// with a combination of the following instructions,
+		// starting with the largest sizes and generating as
+		// many as needed, using the appropriate offset value.
+		//	MOVD  n(R4),R7
+		//	MOVD  R7,n(R3)
+		//	MOVW  n1(R4),R7
+		//	MOVW  R7,n1(R3)
+		//	MOVH  n2(R4),R7
+		//	MOVH  R7,n2(R3)
+		//	MOVB  n3(R4),R7
+		//	MOVB  R7,n3(R3)
 
-		// large or unaligned move
-		// arg0 = address of dst memory (in R3, changed as side effect)
-		// arg1 = address of src memory (in R4, changed as side effect)
-		// arg2 = address of the last element of src
-		// arg3 = mem
-		// returns mem
-		//  ADD -8,R3,R3 // intermediate value not valid GC ptr, cannot expose to opt+GC
-		//  ADD -8,R4,R4 // intermediate value not valid GC ptr, cannot expose to opt+GC
-		//	MOVDU	8(R4), Rtmp
-		//	MOVDU	Rtmp, 8(R3)
-		//	CMP	R4, Rarg2
-		//	BLT	-3(PC)
 		{
 			name:      "LoweredMove",
 			aux:       "Int64",
-			argLength: 4,
+			argLength: 3,
 			reg: regInfo{
-				inputs:   []regMask{buildReg("R3"), buildReg("R4"), gp},
-				clobbers: buildReg("R3 R4"),
+				inputs:   []regMask{buildReg("R3"), buildReg("R4")},
+				clobbers: buildReg("R3 R4 R7 R8 R9 R10"),
 			},
 			clobberFlags:   true,
 			typ:            "Mem",
@@ -348,6 +401,65 @@ func init() {
 			faultOnNilArg1: true,
 		},
 
+		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
+
+		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", clobberFlags: true, faultOnNilArg0: true},
+		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
+		{name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
+
+		// atomic add32, 64
+		// SYNC
+		// LDAR         (Rarg0), Rout
+		// ADD		Rarg1, Rout
+		// STDCCC       Rout, (Rarg0)
+		// BNE          -3(PC)
+		// ISYNC
+		// return new sum
+
+		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+
+		// atomic exchange32, 64
+		// SYNC
+		// LDAR         (Rarg0), Rout
+		// STDCCC       Rarg1, (Rarg0)
+		// BNE          -2(PC)
+		// ISYNC
+		// return old val
+
+		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+
+		// atomic compare and swap.
+		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
+		// if *arg0 == arg1 {
+		//   *arg0 = arg2
+		//   return (true, memory)
+		// } else {
+		//   return (false, memory)
+		// }
+		// SYNC
+		// LDAR		(Rarg0), Rtmp
+		// CMP		Rarg1, Rtmp
+		// BNE		3(PC)
+		// STDCCC	Rarg2, (Rarg0)
+		// BNE		-4(PC)
+		// CBNZ         Rtmp, -4(PC)
+		// CSET         EQ, Rout
+		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+
+		// atomic 8 and/or.
+		// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
+		// LBAR		(Rarg0), Rtmp
+		// AND/OR	Rarg1, Rtmp
+		// STBCCC	Rtmp, (Rarg0), Rtmp
+		// BNE		Rtmp, -3(PC)
+
+		{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
+
 		// (InvertFlags (CMP a b)) == (CMP b a)
 		// So if we want (LessThan (CMP a b)) but we can't do that because a is a constant,
 		// then we do (LessThan (InvertFlags (CMP b a))) instead.
diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules
index caea050..4ae21cd 100644
--- a/src/cmd/compile/internal/ssa/gen/S390X.rules
+++ b/src/cmd/compile/internal/ssa/gen/S390X.rules
@@ -44,10 +44,6 @@
 (Hmul64u x y) -> (MULHDU x y)
 (Hmul32  x y) -> (SRDconst [32] (MULLD (MOVWreg x) (MOVWreg y)))
 (Hmul32u x y) -> (SRDconst [32] (MULLD (MOVWZreg x) (MOVWZreg y)))
-(Hmul16  x y) -> (SRDconst [16] (MULLW (MOVHreg x) (MOVHreg y)))
-(Hmul16u x y) -> (SRDconst [16] (MULLW (MOVHZreg x) (MOVHZreg y)))
-(Hmul8   x y) -> (SRDconst [8] (MULLW (MOVBreg x) (MOVBreg y)))
-(Hmul8u  x y) -> (SRDconst [8] (MULLW (MOVBZreg x) (MOVBZreg y)))
 
 (Mod64  x y) -> (MODD  x y)
 (Mod64u x y) -> (MODDU x y)
@@ -60,7 +56,8 @@
 (Mod8   x y) -> (MODW  (MOVBreg x) (MOVBreg y))
 (Mod8u  x y) -> (MODWU (MOVBZreg x) (MOVBZreg y))
 
-(Avg64u <t> x y) -> (ADD (ADD <t> (SRDconst <t> x [1]) (SRDconst <t> y [1])) (ANDconst <t> (AND <t> x y) [1]))
+// (x + y) / 2 with x>=y -> (x - y) / 2 + y
+(Avg64u <t> x y) -> (ADD (SRDconst <t> (SUB <t> x y) [1]) y)
 
 (And64 x y) -> (AND x y)
 (And32 x y) -> (ANDW x y)
@@ -105,6 +102,8 @@
 (Ctz64 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (AND <t> (SUBconst <t> [1] x) (NOT <t> x))))
 (Ctz32 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (MOVWZreg (ANDW <t> (SUBWconst <t> [1] x) (NOTW <t> x)))))
 
+(BitLen64 x) -> (SUB (MOVDconst [64]) (FLOGR x))
+
 (Bswap64 x) -> (MOVDBR x)
 (Bswap32 x) -> (MOVWBR x)
 
@@ -121,12 +120,12 @@
 (AtomicStorePtrNoWB ptr val mem) -> (MOVDatomicstore ptr val mem)
 
 // Atomic adds.
-(AtomicAdd32 ptr val mem) -> (AddTupleFirst32 (LAA ptr val mem) val)
-(AtomicAdd64 ptr val mem) -> (AddTupleFirst64 (LAAG ptr val mem) val)
-(Select0 <t> (AddTupleFirst32 tuple val)) -> (ADDW val (Select0 <t> tuple))
-(Select1     (AddTupleFirst32 tuple _  )) -> (Select1 tuple)
-(Select0 <t> (AddTupleFirst64 tuple val)) -> (ADD val (Select0 <t> tuple))
-(Select1     (AddTupleFirst64 tuple _  )) -> (Select1 tuple)
+(AtomicAdd32 ptr val mem) -> (AddTupleFirst32 val (LAA ptr val mem))
+(AtomicAdd64 ptr val mem) -> (AddTupleFirst64 val (LAAG ptr val mem))
+(Select0 <t> (AddTupleFirst32 val tuple)) -> (ADDW val (Select0 <t> tuple))
+(Select1     (AddTupleFirst32   _ tuple)) -> (Select1 tuple)
+(Select0 <t> (AddTupleFirst64 val tuple)) -> (ADD val (Select0 <t> tuple))
+(Select1     (AddTupleFirst64   _ tuple)) -> (Select1 tuple)
 
 // Atomic exchanges.
 (AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem)
@@ -152,7 +151,7 @@
 (ZeroExt16to64 x) -> (MOVHZreg x)
 (ZeroExt32to64 x) -> (MOVWZreg x)
 
-(Slicemask <t> x) -> (XOR (MOVDconst [-1]) (SRADconst <t> (SUBconst <t> x [1]) [63]))
+(Slicemask <t> x) -> (SRADconst (NEG <t> x) [63])
 
 // Lowering truncation
 // Because we ignore high parts of registers, truncates are just copies.
@@ -177,6 +176,9 @@
 (Cvt32Fto64F x) -> (LDEBR x)
 (Cvt64Fto32F x) -> (LEDBR x)
 
+(Round32F x) -> (LoweredRound32F x)
+(Round64F x) -> (LoweredRound64F x)
+
 // Lowering shifts
 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
 //   result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
@@ -200,9 +202,6 @@
 (Lsh8x16 <t> x y)  -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
 (Lsh8x8  <t> x y)  -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
 
-(Lrot64 <t> x [c]) -> (RLLGconst <t> [c&63] x)
-(Lrot32 <t> x [c]) -> (RLLconst <t> [c&31] x)
-
 (Rsh64Ux64 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
 (Rsh64Ux32 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
 (Rsh64Ux16 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
@@ -323,82 +322,82 @@
 
 // Lowering stores
 // These more-specific FP versions of Store pattern should come first.
-(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
-(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
 
-(Store [8] ptr val mem) -> (MOVDstore ptr val mem)
-(Store [4] ptr val mem) -> (MOVWstore ptr val mem)
-(Store [2] ptr val mem) -> (MOVHstore ptr val mem)
-(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 -> (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 -> (MOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
+(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
 
 // Lowering moves
 
 // Load and store for small copies.
-(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBZload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstore dst (MOVHZload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstore dst (MOVWZload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstore dst (MOVDload src mem) mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 ->
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBZload src mem) mem)
+(Move [2] dst src mem) -> (MOVHstore dst (MOVHZload src mem) mem)
+(Move [4] dst src mem) -> (MOVWstore dst (MOVWZload src mem) mem)
+(Move [8] dst src mem) -> (MOVDstore dst (MOVDload src mem) mem)
+(Move [16] dst src mem) ->
 	(MOVDstore [8] dst (MOVDload [8] src mem)
 		(MOVDstore dst (MOVDload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 ->
+(Move [24] dst src mem) ->
         (MOVDstore [16] dst (MOVDload [16] src mem)
 	        (MOVDstore [8] dst (MOVDload [8] src mem)
                 (MOVDstore dst (MOVDload src mem) mem)))
-(Move [s] dst src mem)  && SizeAndAlign(s).Size() == 3 ->
+(Move [3] dst src mem) ->
 	(MOVBstore [2] dst (MOVBZload [2] src mem)
 		(MOVHstore dst (MOVHZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+(Move [5] dst src mem) ->
 	(MOVBstore [4] dst (MOVBZload [4] src mem)
 		(MOVWstore dst (MOVWZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+(Move [6] dst src mem) ->
 	(MOVHstore [4] dst (MOVHZload [4] src mem)
 		(MOVWstore dst (MOVWZload src mem) mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+(Move [7] dst src mem) ->
 	(MOVBstore [6] dst (MOVBZload [6] src mem)
 		(MOVHstore [4] dst (MOVHZload [4] src mem)
 			(MOVWstore dst (MOVWZload src mem) mem)))
 
 // MVC for other moves. Use up to 4 instructions (sizes up to 1024 bytes).
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256 ->
-	(MVC [makeValAndOff(SizeAndAlign(s).Size(), 0)] dst src mem)
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512 ->
-	(MVC [makeValAndOff(SizeAndAlign(s).Size()-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768 ->
-	(MVC [makeValAndOff(SizeAndAlign(s).Size()-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024 ->
-	(MVC [makeValAndOff(SizeAndAlign(s).Size()-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))))
+(Move [s] dst src mem) && s > 0 && s <= 256 ->
+	(MVC [makeValAndOff(s, 0)] dst src mem)
+(Move [s] dst src mem) && s > 256 && s <= 512 ->
+	(MVC [makeValAndOff(s-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))
+(Move [s] dst src mem) && s > 512 && s <= 768 ->
+	(MVC [makeValAndOff(s-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))
+(Move [s] dst src mem) && s > 768 && s <= 1024 ->
+	(MVC [makeValAndOff(s-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))))
 
 // Move more than 1024 bytes using a loop.
-(Move [s] dst src mem) && SizeAndAlign(s).Size() > 1024 ->
-	(LoweredMove [SizeAndAlign(s).Size()%256] dst src (ADDconst <src.Type> src [(SizeAndAlign(s).Size()/256)*256]) mem)
+(Move [s] dst src mem) && s > 1024 ->
+	(LoweredMove [s%256] dst src (ADDconst <src.Type> src [(s/256)*256]) mem)
 
 // Lowering Zero instructions
-(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstoreconst [0] destptr mem)
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
+(Zero [0] _ mem) -> mem
+(Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem)
+(Zero [2] destptr mem) -> (MOVHstoreconst [0] destptr mem)
+(Zero [4] destptr mem) -> (MOVWstoreconst [0] destptr mem)
+(Zero [8] destptr mem) -> (MOVDstoreconst [0] destptr mem)
+(Zero [3] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,2)] destptr
 		(MOVHstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
+(Zero [5] destptr mem) ->
 	(MOVBstoreconst [makeValAndOff(0,4)] destptr
 		(MOVWstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
+(Zero [6] destptr mem) ->
 	(MOVHstoreconst [makeValAndOff(0,4)] destptr
 		(MOVWstoreconst [0] destptr mem))
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
+(Zero [7] destptr mem) ->
 	(MOVWstoreconst [makeValAndOff(0,3)] destptr
 		(MOVWstoreconst [0] destptr mem))
 
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024 ->
-	(CLEAR [makeValAndOff(SizeAndAlign(s).Size(), 0)] destptr mem)
+(Zero [s] destptr mem) && s > 0 && s <= 1024 ->
+	(CLEAR [makeValAndOff(s, 0)] destptr mem)
 
 // Move more than 1024 bytes using a loop.
-(Zero [s] destptr mem) && SizeAndAlign(s).Size() > 1024 ->
-	(LoweredZero [SizeAndAlign(s).Size()%256] destptr (ADDconst <destptr.Type> destptr [(SizeAndAlign(s).Size()/256)*256]) mem)
+(Zero [s] destptr mem) && s > 1024 ->
+	(LoweredZero [s%256] destptr (ADDconst <destptr.Type> destptr [(s/256)*256]) mem)
 
 // Lowering constants
 (Const8   [val]) -> (MOVDconst [val])
@@ -413,8 +412,6 @@
 // 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
@@ -440,7 +437,7 @@
 (If (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GTF cmp yes no)
 (If (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GEF cmp yes no)
 
-(If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg <config.fe.TypeBool()> cond)) yes no)
+(If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg <typ.Bool> cond)) yes no)
 
 // ***************************
 // Above: lowering rules
@@ -449,8 +446,8 @@
 // TODO: Should the optimizations be a separate pass?
 
 // Fold unnecessary type conversions.
-(MOVDreg <t> x) && t.Compare(x.Type) == CMPeq -> x
-(MOVDnop <t> x) && t.Compare(x.Type) == CMPeq -> x
+(MOVDreg <t> x) && t.Compare(x.Type) == types.CMPeq -> x
+(MOVDnop <t> x) && t.Compare(x.Type) == types.CMPeq -> x
 
 // Propagate constants through type conversions.
 (MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
@@ -460,6 +457,40 @@
 // MOVDnop doesn't emit instruction, only for ensuring the type.
 (MOVDreg x) && x.Uses == 1 -> (MOVDnop x)
 
+// Fold type changes into loads.
+(MOVDreg <t> x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVBload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload  <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVHload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload  <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVWload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload  <t> [off] {sym} ptr mem)
+(MOVDreg <t> x:(MOVDload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDload  <t> [off] {sym} ptr mem)
+
+(MOVDnop <t> x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVBload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload  <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVHload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload  <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVWload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload  <t> [off] {sym} ptr mem)
+(MOVDnop <t> x:(MOVDload  [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDload  <t> [off] {sym} ptr mem)
+
+// TODO(mundaym): uncomment rules once signed indexed loads are added.
+(MOVDreg <t> x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDreg <t> x:(MOVBloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDreg <t> x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDreg <t> x:(MOVHloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDreg <t> x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDreg <t> x:(MOVWloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDreg <t> x:(MOVDloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDloadidx  <t> [off] {sym} ptr idx mem)
+
+(MOVDnop <t> x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDnop <t> x:(MOVBloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDnop <t> x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDnop <t> x:(MOVHloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDnop <t> x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem)
+//(MOVDnop <t> x:(MOVWloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx  <t> [off] {sym} ptr idx mem)
+(MOVDnop <t> x:(MOVDloadidx  [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDloadidx  <t> [off] {sym} ptr idx mem)
+
 // Fold sign extensions into conditional moves of constants.
 // Designed to remove the MOVBZreg inserted by the If lowering.
 (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
@@ -483,9 +514,7 @@
 
 // Fold constants into instructions.
 (ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x)
-(ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x)
 (ADDW x (MOVDconst [c])) -> (ADDWconst [c] x)
-(ADDW (MOVDconst [c]) x) -> (ADDWconst [c] x)
 
 (SUB x (MOVDconst [c])) && is32Bit(c) -> (SUBconst x [c])
 (SUB (MOVDconst [c]) x) && is32Bit(c) -> (NEG (SUBconst <v.Type> x [c]))
@@ -493,31 +522,23 @@
 (SUBW (MOVDconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [c]))
 
 (MULLD x (MOVDconst [c])) && is32Bit(c) -> (MULLDconst [c] x)
-(MULLD (MOVDconst [c]) x) && is32Bit(c) -> (MULLDconst [c] x)
 (MULLW x (MOVDconst [c])) -> (MULLWconst [c] x)
-(MULLW (MOVDconst [c]) x) -> (MULLWconst [c] x)
 
 // NILF instructions leave the high 32 bits unchanged which is
 // equivalent to the leftmost 32 bits being set.
 // TODO(mundaym): modify the assembler to accept 64-bit values
 // and use isU32Bit(^c).
 (AND x (MOVDconst [c])) && is32Bit(c) && c < 0 -> (ANDconst [c] x)
-(AND (MOVDconst [c]) x) && is32Bit(c) && c < 0 -> (ANDconst [c] x)
 (ANDW x (MOVDconst [c])) -> (ANDWconst [c] x)
-(ANDW (MOVDconst [c]) x) -> (ANDWconst [c] x)
 
 (ANDWconst [c] (ANDWconst [d] x)) -> (ANDWconst [c & d] x)
 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c & d] x)
 
 (OR x (MOVDconst [c])) && isU32Bit(c) -> (ORconst [c] x)
-(OR (MOVDconst [c]) x) && isU32Bit(c) -> (ORconst [c] x)
 (ORW x (MOVDconst [c])) -> (ORWconst [c] x)
-(ORW (MOVDconst [c]) x) -> (ORWconst [c] x)
 
 (XOR x (MOVDconst [c])) && isU32Bit(c) -> (XORconst [c] x)
-(XOR (MOVDconst [c]) x) && isU32Bit(c) -> (XORconst [c] x)
 (XORW x (MOVDconst [c])) -> (XORWconst [c] x)
-(XORW (MOVDconst [c]) x) -> (XORWconst [c] x)
 
 (SLD x (MOVDconst [c])) -> (SLDconst [c&63] x)
 (SLW x (MOVDconst [c])) -> (SLWconst [c&63] x)
@@ -533,6 +554,15 @@
 (SRW x (ANDWconst [63] y)) -> (SRW x y)
 (SRD x (ANDconst [63] y)) -> (SRD x y)
 
+// Rotate generation
+(ADD (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x)
+( OR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x)
+(XOR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x)
+
+(ADDW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x)
+( ORW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x)
+(XORW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x)
+
 (CMP x (MOVDconst [c])) && is32Bit(c) -> (CMPconst x [c])
 (CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c]))
 (CMPW x (MOVDconst [c])) -> (CMPWconst x [c])
@@ -543,11 +573,8 @@
 (CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(uint32(c))]))
 
 // Using MOV{W,H,B}Zreg instead of AND is cheaper.
-(AND (MOVDconst [0xFF]) x) -> (MOVBZreg x)
 (AND x (MOVDconst [0xFF])) -> (MOVBZreg x)
-(AND (MOVDconst [0xFFFF]) x) -> (MOVHZreg x)
 (AND x (MOVDconst [0xFFFF])) -> (MOVHZreg x)
-(AND (MOVDconst [0xFFFFFFFF]) x) -> (MOVWZreg x)
 (AND x (MOVDconst [0xFFFFFFFF])) -> (MOVWZreg x)
 (ANDWconst [0xFF] x) -> (MOVBZreg x)
 (ANDWconst [0xFFFF] x) -> (MOVHZreg x)
@@ -570,8 +597,7 @@
 // Fold ADD into MOVDaddr. Odd offsets from SB shouldn't be folded (LARL can't handle them).
 (ADDconst [c] (MOVDaddr [d] {s} x:(SB))) && ((c+d)&1 == 0) && is32Bit(c+d) -> (MOVDaddr [c+d] {s} x)
 (ADDconst [c] (MOVDaddr [d] {s} x)) && x.Op != OpSB && is20Bit(c+d) -> (MOVDaddr [c+d] {s} x)
-(ADD x (MOVDaddr [c] {s} y)) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y)
-(ADD (MOVDaddr [c] {s} x) y) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y)
+(ADD idx (MOVDaddr [c] {s} ptr)) && ptr.Op != OpSB && idx.Op != OpSB -> (MOVDaddridx [c] {s} ptr idx)
 
 // fold ADDconst into MOVDaddrx
 (ADDconst [c] (MOVDaddridx [d] {s} x y)) && is20Bit(c+d) -> (MOVDaddridx [c+d] {s} x y)
@@ -656,9 +682,9 @@
 (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
 
 // replace load from same location as preceding store with copy
-(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
-(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
-(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
+(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBZreg x)
+(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHZreg x)
+(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWZreg x)
 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
 
 // Don't extend before storing
@@ -692,23 +718,23 @@
 (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem)
 
 // Fold constants into stores.
-(MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB ->
+(MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB ->
 	(MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
-(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB ->
+(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB ->
 	(MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
-(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
+(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && isU12Bit(off) && ptr.Op != OpSB ->
 	(MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
-(MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
+(MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && is20Bit(off) && ptr.Op != OpSB ->
 	(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
 
 // Fold address offsets into constant stores.
-(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
 	(MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
 	(MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) ->
 	(MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && is20Bit(ValAndOff(sc).Off()+off) ->
 	(MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 
 // We need to fold MOVDaddr into the MOVx ops so that the live variable analysis knows
@@ -746,13 +772,14 @@
 (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
 	(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 
-(MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+// Cannot store constant to SB directly (no 'move relative long immediate' instructions).
+(MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
 	(MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
 	(MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
 	(MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+(MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
 	(MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
 
 // generating indexed loads and stores
@@ -963,6 +990,8 @@
 (XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d])
 (XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
 (XORWconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
+(LoweredRound32F x:(FMOVSconst)) -> x
+(LoweredRound64F x:(FMOVDconst)) -> x
 
 // generic simplifications
 // TODO: more of this
@@ -976,81 +1005,88 @@
 (ORW x x) -> x
 (XOR x x) -> (MOVDconst [0])
 (XORW x x) -> (MOVDconst [0])
+(NEG (ADDconst [c] (NEG x))) && c != -(1<<31) -> (ADDconst [-c] x)
+
+// fused multiply-add
+(FADD (FMUL y z) x) -> (FMADD x y z)
+(FADDS (FMULS y z) x) -> (FMADDS x y z)
+(FSUB (FMUL y z) x) -> (FMSUB x y z)
+(FSUBS (FMULS y z) x) -> (FMSUBS x y z)
 
 // Fold memory operations into operations.
 // Exclude global data (SB) because these instructions cannot handle relative addresses.
 // TODO(mundaym): use LARL in the assembler to handle SB?
 // TODO(mundaym): indexed versions of these?
-(ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDload <t> [off] {sym} x ptr mem)
-(ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDload <t> [off] {sym} x ptr mem)
-(ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDWload <t> [off] {sym} x ptr mem)
-(ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDWload <t> [off] {sym} x ptr mem)
-(ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDWload <t> [off] {sym} x ptr mem)
-(ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ADDWload <t> [off] {sym} x ptr mem)
-(MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLDload <t> [off] {sym} x ptr mem)
-(MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLDload <t> [off] {sym} x ptr mem)
-(MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLWload <t> [off] {sym} x ptr mem)
-(MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLWload <t> [off] {sym} x ptr mem)
-(MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLWload <t> [off] {sym} x ptr mem)
-(MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (MULLWload <t> [off] {sym} x ptr mem)
-(SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (SUBload <t> [off] {sym} x ptr mem)
-(SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (SUBWload <t> [off] {sym} x ptr mem)
-(SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (SUBWload <t> [off] {sym} x ptr mem)
-(AND <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(AND <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDload <t> [off] {sym} x ptr mem)
-(AND <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(AND <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDload <t> [off] {sym} x ptr mem)
-(ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDWload <t> [off] {sym} x ptr mem)
-(ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDWload <t> [off] {sym} x ptr mem)
-(ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDWload <t> [off] {sym} x ptr mem)
-(ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ANDWload <t> [off] {sym} x ptr mem)
-(OR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(OR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORload <t> [off] {sym} x ptr mem)
-(OR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(OR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORload <t> [off] {sym} x ptr mem)
-(ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORWload <t> [off] {sym} x ptr mem)
-(ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORWload <t> [off] {sym} x ptr mem)
-(ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORWload <t> [off] {sym} x ptr mem)
-(ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (ORWload <t> [off] {sym} x ptr mem)
-(XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORload <t> [off] {sym} x ptr mem)
-(XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORload <t> [off] {sym} x ptr mem)
-(XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORWload <t> [off] {sym} x ptr mem)
-(XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORWload <t> [off] {sym} x ptr mem)
-(XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORWload <t> [off] {sym} x ptr mem)
-(XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+(XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	-> (XORWload <t> [off] {sym} x ptr mem)
 
 // Combine constant stores into larger (unaligned) stores.
-// It doesn't work to global data (based on SB),
-// because STGRL doesn't support unaligned address
+// Avoid SB because constant stores to relative offsets are
+// emulated by the assembler and also can't handle unaligned offsets.
 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
   && p.Op != OpSB
   && x.Uses == 1
@@ -1062,7 +1098,7 @@
   && x.Uses == 1
   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
   && clobber(x)
-  -> (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+  -> (MOVWstore [ValAndOff(a).Off()] {s} p (MOVDconst [int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))]) mem)
 (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
   && p.Op != OpSB
   && x.Uses == 1
@@ -1256,363 +1292,555 @@
 
 // Combining byte loads into larger (unaligned) loads.
 
-// Little endian loads.
+// Big-endian loads
 
-// b[0] | b[1]<<8 -> load 16-bit, reverse bytes
-(ORW                 x0:(MOVBZload [i]   {s} p mem)
-    s0:(SLWconst [8] x1:(MOVBZload [i+1] {s} p mem)))
+(ORW                 x1:(MOVBZload [i1] {s} p mem)
+    sh:(SLWconst [8] x0:(MOVBZload [i0] {s} p mem)))
+  && i1 == i0+1
   && p.Op != OpSB
   && x0.Uses == 1
   && x1.Uses == 1
-  && s0.Uses == 1
+  && sh.Uses == 1
   && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i] {s} p mem))
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
+
+(OR                  x1:(MOVBZload [i1] {s} p mem)
+    sh:(SLDconst [8] x0:(MOVBZload [i0] {s} p mem)))
+  && i1 == i0+1
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
+
+(ORW                  x1:(MOVHZload [i1] {s} p mem)
+    sh:(SLWconst [16] x0:(MOVHZload [i0] {s} p mem)))
+  && i1 == i0+2
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
+
+(OR                   x1:(MOVHZload [i1] {s} p mem)
+    sh:(SLDconst [16] x0:(MOVHZload [i0] {s} p mem)))
+  && i1 == i0+2
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
 
-// b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes
-(ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRload [i] {s} p mem))
-    s0:(SLWconst [16] x1:(MOVBZload [i+2] {s} p mem)))
-    s1:(SLWconst [24] x2:(MOVBZload [i+3] {s} p mem)))
+(OR                   x1:(MOVWZload [i1] {s} p mem)
+    sh:(SLDconst [32] x0:(MOVWZload [i0] {s} p mem)))
+  && i1 == i0+4
   && p.Op != OpSB
-  && z0.Uses == 1
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVDload [i0] {s} p mem)
+
+(ORW
+    s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem))
+    or:(ORW
+        s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
+  && x0.Uses == 1
+  && x1.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
-  && clobber(z0)
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVWBRload [i] {s} p mem)
-
-// b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 | b[4]<<32 | b[5]<<40 | b[6]<<48 | b[7]<<56 -> load 64-bit, reverse bytes
-(OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
-                      x0:(MOVBZload [i]   {s} p mem)
-    s0:(SLDconst [8]  x1:(MOVBZload [i+1] {s} p mem)))
-    s1:(SLDconst [16] x2:(MOVBZload [i+2] {s} p mem)))
-    s2:(SLDconst [24] x3:(MOVBZload [i+3] {s} p mem)))
-    s3:(SLDconst [32] x4:(MOVBZload [i+4] {s} p mem)))
-    s4:(SLDconst [40] x5:(MOVBZload [i+5] {s} p mem)))
-    s5:(SLDconst [48] x6:(MOVBZload [i+6] {s} p mem)))
-    s6:(SLDconst [56] x7:(MOVBZload [i+7] {s} p mem)))
-  && p.Op != OpSB
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+
+(OR
+    s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem))
+    or:(OR
+        s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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) (MOVDBRload [i] {s} p mem)
-
-// b[0] | b[1]<<8 -> load 16-bit, reverse bytes
-(ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)
-    s0:(SLWconst [8] x1:(MOVBZloadidx [i+1] {s} p idx mem)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+
+(OR
+    s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem))
+    or:(OR
+        s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem))
+	y))
+  && i1 == i0+2
+  && j1 == j0-16
+  && j1 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
   && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx <v.Type> [i] {s} p idx mem))
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y)
 
-// b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes
-(ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRloadidx [i] {s} p idx mem))
-    s0:(SLWconst [16] x1:(MOVBZloadidx [i+2] {s} p idx mem)))
-    s1:(SLWconst [24] x2:(MOVBZloadidx [i+3] {s} p idx mem)))
-  && z0.Uses == 1
+// Big-endian indexed loads
+
+(ORW                 x1:(MOVBZloadidx [i1] {s} p idx mem)
+    sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+  && i1 == i0+1
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+
+(OR                  x1:(MOVBZloadidx [i1] {s} p idx mem)
+    sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+  && i1 == i0+1
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+
+(ORW                  x1:(MOVHZloadidx [i1] {s} p idx mem)
+    sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+  && i1 == i0+2
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+
+(OR                   x1:(MOVHZloadidx [i1] {s} p idx mem)
+    sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+  && i1 == i0+2
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+
+(OR                   x1:(MOVWZloadidx [i1] {s} p idx mem)
+    sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem)))
+  && i1 == i0+4
+  && p.Op != OpSB
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+
+(ORW
+    s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))
+    or:(ORW
+        s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
-  && clobber(z0)
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVWZreg (MOVWBRloadidx <v.Type> [i] {s} p idx mem))
-
-// b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 | b[4]<<32 | b[5]<<40 | b[6]<<48 | b[7]<<56 -> load 64-bit, reverse bytes
-(OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
-                      x0:(MOVBZloadidx [i]   {s} p idx mem)
-    s0:(SLDconst [8]  x1:(MOVBZloadidx [i+1] {s} p idx mem)))
-    s1:(SLDconst [16] x2:(MOVBZloadidx [i+2] {s} p idx mem)))
-    s2:(SLDconst [24] x3:(MOVBZloadidx [i+3] {s} p idx mem)))
-    s3:(SLDconst [32] x4:(MOVBZloadidx [i+4] {s} p idx mem)))
-    s4:(SLDconst [40] x5:(MOVBZloadidx [i+5] {s} p idx mem)))
-    s5:(SLDconst [48] x6:(MOVBZloadidx [i+6] {s} p idx mem)))
-    s6:(SLDconst [56] x7:(MOVBZloadidx [i+7] {s} p idx mem)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+
+(OR
+    s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))
+    or:(OR
+        s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))
+	y))
+  && i1 == i0+1
+  && j1 == j0-8
+  && j1 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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) (MOVDBRloadidx <v.Type> [i] {s} p idx mem)
-
-// Big endian loads.
-
-// b[1] | b[0]<<8 -> load 16-bit
-(ORW                  x0:(MOVBZload [i]   {s} p mem)
-    s0:(SLWconst [8] x1:(MOVBZload [i-1] {s} p mem)))
-  && p.Op != OpSB
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+
+(OR
+    s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem))
+    or:(OR
+        s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem))
+	y))
+  && i1 == i0+2
+  && j1 == j0-16
+  && j1 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
   && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
   && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVHZload [i-1] {s} p mem)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+
+// Little-endian loads
+
+(ORW                 x0:(MOVBZload [i0] {s} p mem)
+    sh:(SLWconst [8] x1:(MOVBZload [i1] {s} p mem)))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
 
-// b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit
-(ORW o0:(ORW x0:(MOVHZload [i] {s} p mem)
-    s0:(SLWconst [16] x1:(MOVBZload [i-1] {s} p mem)))
-    s1:(SLWconst [24] x2:(MOVBZload [i-2] {s} p mem)))
+(OR                  x0:(MOVBZload [i0] {s} p mem)
+    sh:(SLDconst [8] x1:(MOVBZload [i1] {s} p mem)))
   && p.Op != OpSB
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
+
+(ORW                  r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem))
+    sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWBRload [i0] {s} p mem)
+
+(OR                   r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem))
+    sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRload [i0] {s} p mem))
+
+(OR                   r0:(MOVWZreg x0:(MOVWBRload [i0] {s} p mem))
+    sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRload [i1] {s} p mem))))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVDBRload [i0] {s} p mem)
+
+(ORW
+    s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem))
+    or:(ORW
+        s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem))
+	y))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVWZload [i-2] {s} p mem)
-
-// b[7] | b[6]<<8 | b[5]<<16 | b[4]<<24 | b[3]<<32 | b[2]<<40 | b[1]<<48 | b[0]<<56 -> load 64-bit
-(OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
-                      x0:(MOVBZload [i]   {s} p mem)
-    s0:(SLDconst [8]  x1:(MOVBZload [i-1] {s} p mem)))
-    s1:(SLDconst [16] x2:(MOVBZload [i-2] {s} p mem)))
-    s2:(SLDconst [24] x3:(MOVBZload [i-3] {s} p mem)))
-    s3:(SLDconst [32] x4:(MOVBZload [i-4] {s} p mem)))
-    s4:(SLDconst [40] x5:(MOVBZload [i-5] {s} p mem)))
-    s5:(SLDconst [48] x6:(MOVBZload [i-6] {s} p mem)))
-    s6:(SLDconst [56] x7:(MOVBZload [i-7] {s} p mem)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+
+(OR
+    s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem))
+    or:(OR
+        s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem))
+	y))
   && p.Op != OpSB
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != 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) (MOVDload [i-7] {s} p mem)
-
-// b[1] | b[0]<<8 -> load 16-bit
-(ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)
-    s0:(SLWconst [8] x1:(MOVBZloadidx [i-1] {s} p idx mem)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+
+(OR
+    s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem)))
+    or:(OR
+        s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)))
+	y))
+  && i1 == i0+2
+  && j1 == j0+16
+  && j0 % 32 == 0
   && x0.Uses == 1
   && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
   && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
   && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
   && clobber(s0)
-  -> @mergePoint(b,x0,x1) (MOVHZloadidx <v.Type> [i-1] {s} p idx mem)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y)
+
+// Little-endian indexed loads
+
+(ORW                 x0:(MOVBZloadidx [i0] {s} p idx mem)
+    sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+
+(OR                  x0:(MOVBZloadidx [i0] {s} p idx mem)
+    sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
 
-// b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit
-(ORW o0:(ORW x0:(MOVHZloadidx [i] {s} p idx mem)
-    s0:(SLWconst [16] x1:(MOVBZloadidx [i-1] {s} p idx mem)))
-    s1:(SLWconst [24] x2:(MOVBZloadidx [i-2] {s} p idx mem)))
+(ORW                  r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))
+    sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+
+(OR                   r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))
+    sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+  && i1 == i0+2
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+
+(OR                   r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem))
+    sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem))))
+  && i1 == i0+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(r0)
+  && clobber(r1)
+  && clobber(sh)
+  -> @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+
+(ORW
+    s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))
+    or:(ORW
+        s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))
+	y))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && x0.Uses == 1
   && x1.Uses == 1
-  && x2.Uses == 1
   && s0.Uses == 1
   && s1.Uses == 1
-  && o0.Uses == 1
-  && mergePoint(b,x0,x1,x2) != nil
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
   && clobber(s0)
   && clobber(s1)
-  && clobber(o0)
-  -> @mergePoint(b,x0,x1,x2) (MOVWZloadidx <v.Type> [i-2] {s} p idx mem)
-
-// b[7] | b[6]<<8 | b[5]<<16 | b[4]<<24 | b[3]<<32 | b[2]<<40 | b[1]<<48 | b[0]<<56 -> load 64-bit
-(OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
-                      x0:(MOVBZloadidx [i]   {s} p idx mem)
-    s0:(SLDconst [8]  x1:(MOVBZloadidx [i-1] {s} p idx mem)))
-    s1:(SLDconst [16] x2:(MOVBZloadidx [i-2] {s} p idx mem)))
-    s2:(SLDconst [24] x3:(MOVBZloadidx [i-3] {s} p idx mem)))
-    s3:(SLDconst [32] x4:(MOVBZloadidx [i-4] {s} p idx mem)))
-    s4:(SLDconst [40] x5:(MOVBZloadidx [i-5] {s} p idx mem)))
-    s5:(SLDconst [48] x6:(MOVBZloadidx [i-6] {s} p idx mem)))
-    s6:(SLDconst [56] x7:(MOVBZloadidx [i-7] {s} p idx mem)))
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+
+(OR
+    s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))
+    or:(OR
+        s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))
+	y))
+  && p.Op != OpSB
+  && i1 == i0+1
+  && j1 == j0+8
+  && j0 % 16 == 0
   && 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
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+
+(OR
+    s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem)))
+    or:(OR
+        s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))
+	y))
+  && i1 == i0+2
+  && j1 == j0+16
+  && j0 % 32 == 0
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && r0.Uses == 1
+  && r1.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && or.Uses == 1
+  && mergePoint(b,x0,x1) != nil
   && clobber(x0)
   && clobber(x1)
-  && clobber(x2)
-  && clobber(x3)
-  && clobber(x4)
-  && clobber(x5)
-  && clobber(x6)
-  && clobber(x7)
+  && clobber(r0)
+  && clobber(r1)
   && 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) (MOVDloadidx <v.Type> [i-7] {s} p idx mem)
+  && clobber(or)
+  -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 
 // Combine stores into store multiples.
 // 32-bit
diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go
index 6fdeb2e..2a08a27 100644
--- a/src/cmd/compile/internal/ssa/gen/S390XOps.go
+++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go
@@ -15,14 +15,38 @@ import "strings"
 //  - 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
+//    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.
-// D (double word) = 64 bit (frequently omitted)
-// W (word)        = 32 bit
-// H (half word)   = 16 bit
-// B (byte)        = 8 bit
+//  - The SB 'register' is implemented using instruction-relative addressing. This
+//    places some limitations on when and how memory operands that are addressed
+//    relative to SB can be used:
+//
+//     1. Pseudo-instructions do not always map to a single machine instruction when
+//        using the SB 'register' to address data. This is because many machine
+//        instructions do not have relative long (RL suffix) equivalents. For example,
+//        ADDload, which is assembled as AG.
+//
+//     2. Loads and stores using relative addressing require the data be aligned
+//        according to its size (8-bytes for double words, 4-bytes for words
+//        and so on).
+//
+//    We can always work around these by inserting LARL instructions (load address
+//    relative long) in the assembler, but typically this results in worse code
+//    generation because the address can't be re-used. Inserting instructions in the
+//    assembler also means clobbering the temp register and it is a long-term goal
+//    to prevent the compiler doing this so that it can be allocated as a normal
+//    register.
+//
+// For more information about the z/Architecture, the instruction set and the
+// addressing modes it supports take a look at the z/Architecture Principles of
+// Operation: http://publibfp.boulder.ibm.com/epubs/pdf/dz9zr010.pdf
+//
+// Suffixes encode the bit width of pseudo-instructions.
+// D (double word)  = 64 bit (frequently omitted)
+// W (word)         = 32 bit
+// H (half word)    = 16 bit
+// B (byte)         = 8 bit
+// S (single prec.) = 32 bit (double precision is omitted)
 
 // copied from ../../s390x/reg.go
 var regNamesS390X = []string{
@@ -141,6 +165,7 @@ func init() {
 
 		fp01        = regInfo{inputs: []regMask{}, outputs: fponly}
 		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+		fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: fponly}
 		fp21clobber = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
 		fpgp        = regInfo{inputs: fponly, outputs: gponly}
 		gpfp        = regInfo{inputs: gponly, outputs: fponly}
@@ -166,53 +191,57 @@ func init() {
 
 	var S390Xops = []opData{
 		// fp ops
-		{name: "FADDS", argLength: 2, reg: fp21clobber, asm: "FADDS", commutative: true, resultInArg0: true, clobberFlags: true}, // fp32 add
-		{name: "FADD", argLength: 2, reg: fp21clobber, asm: "FADD", commutative: true, resultInArg0: true, clobberFlags: true},   // fp64 add
-		{name: "FSUBS", argLength: 2, reg: fp21clobber, asm: "FSUBS", resultInArg0: true, clobberFlags: true},                    // fp32 sub
-		{name: "FSUB", argLength: 2, reg: fp21clobber, asm: "FSUB", resultInArg0: true, clobberFlags: true},                      // fp64 sub
-		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, resultInArg0: true},                            // fp32 mul
-		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true, resultInArg0: true},                              // fp64 mul
-		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", resultInArg0: true},                                               // fp32 div
-		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV", resultInArg0: true},                                                 // fp64 div
-		{name: "FNEGS", argLength: 1, reg: fp11clobber, asm: "FNEGS", clobberFlags: true},                                        // fp32 neg
-		{name: "FNEG", argLength: 1, reg: fp11clobber, asm: "FNEG", clobberFlags: true},                                          // fp64 neg
-
-		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true}, // fp32 load
-		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true}, // fp64 load
-		{name: "FMOVSconst", reg: fp01, asm: "FMOVS", aux: "Float32", rematerializeable: true},            // fp32 constant
-		{name: "FMOVDconst", reg: fp01, asm: "FMOVD", aux: "Float64", rematerializeable: true},            // fp64 constant
-		{name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", aux: "SymOff"},                 // fp32 load indexed by i
-		{name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", aux: "SymOff"},                 // fp64 load indexed by i
-
-		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true}, // fp32 store
-		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true}, // fp64 store
-		{name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", aux: "SymOff"},                 // fp32 indexed by i store
-		{name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", aux: "SymOff"},                 // fp64 indexed by i store
+		{name: "FADDS", argLength: 2, reg: fp21clobber, asm: "FADDS", commutative: true, resultInArg0: true, clobberFlags: true}, // fp32 arg0 + arg1
+		{name: "FADD", argLength: 2, reg: fp21clobber, asm: "FADD", commutative: true, resultInArg0: true, clobberFlags: true},   // fp64 arg0 + arg1
+		{name: "FSUBS", argLength: 2, reg: fp21clobber, asm: "FSUBS", resultInArg0: true, clobberFlags: true},                    // fp32 arg0 - arg1
+		{name: "FSUB", argLength: 2, reg: fp21clobber, asm: "FSUB", resultInArg0: true, clobberFlags: true},                      // fp64 arg0 - arg1
+		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, resultInArg0: true},                            // fp32 arg0 * arg1
+		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true, resultInArg0: true},                              // fp64 arg0 * arg1
+		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", resultInArg0: true},                                               // fp32 arg0 / arg1
+		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV", resultInArg0: true},                                                 // fp64 arg0 / arg1
+		{name: "FNEGS", argLength: 1, reg: fp11clobber, asm: "FNEGS", clobberFlags: true},                                        // fp32 -arg0
+		{name: "FNEG", argLength: 1, reg: fp11clobber, asm: "FNEG", clobberFlags: true},                                          // fp64 -arg0
+		{name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", resultInArg0: true},                                             // fp32 arg1 * arg2 + arg0
+		{name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD", resultInArg0: true},                                               // fp64 arg1 * arg2 + arg0
+		{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", resultInArg0: true},                                             // fp32 arg1 * arg2 - arg0
+		{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB", resultInArg0: true},                                               // fp64 arg1 * arg2 - arg0
+
+		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load
+		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp64 load
+		{name: "FMOVSconst", reg: fp01, asm: "FMOVS", aux: "Float32", rematerializeable: true},                               // fp32 constant
+		{name: "FMOVDconst", reg: fp01, asm: "FMOVD", aux: "Float64", rematerializeable: true},                               // fp64 constant
+		{name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", aux: "SymOff", symEffect: "Read"},                 // fp32 load indexed by i
+		{name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", aux: "SymOff", symEffect: "Read"},                 // fp64 load indexed by i
+
+		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp32 store
+		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp64 store
+		{name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", aux: "SymOff", symEffect: "Write"},                 // fp32 indexed by i store
+		{name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", aux: "SymOff", symEffect: "Write"},                 // fp64 indexed by i store
 
 		// binary ops
-		{name: "ADD", argLength: 2, reg: gp21sp, asm: "ADD", commutative: true, clobberFlags: true},                                               // arg0 + arg1
-		{name: "ADDW", argLength: 2, reg: gp21sp, asm: "ADDW", commutative: true, clobberFlags: true},                                             // arg0 + arg1
-		{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", typ: "UInt64", clobberFlags: true},                                // arg0 + auxint
-		{name: "ADDWconst", argLength: 1, reg: gp11sp, asm: "ADDW", aux: "Int32", clobberFlags: true},                                             // arg0 + auxint
-		{name: "ADDload", argLength: 3, reg: gpopload, asm: "ADD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},   // arg0 + *arg1. arg2=mem
-		{name: "ADDWload", argLength: 3, reg: gpopload, asm: "ADDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 + *arg1. arg2=mem
-
-		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB", clobberFlags: true},                                                                    // arg0 - arg1
-		{name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW", clobberFlags: true},                                                                  // arg0 - arg1
-		{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", resultInArg0: true, clobberFlags: true},                             // arg0 - auxint
-		{name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBW", aux: "Int32", resultInArg0: true, clobberFlags: true},                           // arg0 - auxint
-		{name: "SUBload", argLength: 3, reg: gpopload, asm: "SUB", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},   // arg0 - *arg1. arg2=mem
-		{name: "SUBWload", argLength: 3, reg: gpopload, asm: "SUBW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 - *arg1. arg2=mem
-
-		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true},             // arg0 * arg1
-		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true, resultInArg0: true, clobberFlags: true},             // arg0 * arg1
-		{name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int64", typ: "Int64", resultInArg0: true, clobberFlags: true},             // arg0 * auxint
-		{name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int32", resultInArg0: true, clobberFlags: true},             // arg0 * auxint
-		{name: "MULLDload", argLength: 3, reg: gpopload, asm: "MULLD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 * *arg1. arg2=mem
-		{name: "MULLWload", argLength: 3, reg: gpopload, asm: "MULLW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 * *arg1. arg2=mem
-
-		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", typ: "Int64", resultInArg0: true, clobberFlags: true},   // (arg0 * arg1) >> width
-		{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", typ: "Int64", resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
+		{name: "ADD", argLength: 2, reg: gp21sp, asm: "ADD", commutative: true, clobberFlags: true},                                                                  // arg0 + arg1
+		{name: "ADDW", argLength: 2, reg: gp21sp, asm: "ADDW", commutative: true, clobberFlags: true},                                                                // arg0 + arg1
+		{name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", typ: "UInt64", clobberFlags: true},                                                   // arg0 + auxint
+		{name: "ADDWconst", argLength: 1, reg: gp11sp, asm: "ADDW", aux: "Int32", clobberFlags: true},                                                                // arg0 + auxint
+		{name: "ADDload", argLength: 3, reg: gpopload, asm: "ADD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 + *arg1. arg2=mem
+		{name: "ADDWload", argLength: 3, reg: gpopload, asm: "ADDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + *arg1. arg2=mem
+
+		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB", clobberFlags: true},                                                                                       // arg0 - arg1
+		{name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW", clobberFlags: true},                                                                                     // arg0 - arg1
+		{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", resultInArg0: true, clobberFlags: true},                                                // arg0 - auxint
+		{name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBW", aux: "Int32", resultInArg0: true, clobberFlags: true},                                              // arg0 - auxint
+		{name: "SUBload", argLength: 3, reg: gpopload, asm: "SUB", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 - *arg1. arg2=mem
+		{name: "SUBWload", argLength: 3, reg: gpopload, asm: "SUBW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - *arg1. arg2=mem
+
+		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true},                                // arg0 * arg1
+		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true, resultInArg0: true, clobberFlags: true},                                // arg0 * arg1
+		{name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int64", typ: "Int64", resultInArg0: true, clobberFlags: true},                                // arg0 * auxint
+		{name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int32", resultInArg0: true, clobberFlags: true},                                // arg0 * auxint
+		{name: "MULLDload", argLength: 3, reg: gpopload, asm: "MULLD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem
+		{name: "MULLWload", argLength: 3, reg: gpopload, asm: "MULLW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem
+
+		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true},   // (arg0 * arg1) >> width
+		{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
 
 		{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", resultInArg0: true, clobberFlags: true},   // arg0 / arg1
 		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", resultInArg0: true, clobberFlags: true},   // arg0 / arg1
@@ -225,26 +254,26 @@ func init() {
 		{name: "MODDU", argLength: 2, reg: gp21, asm: "MODDU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
 		{name: "MODWU", argLength: 2, reg: gp21, asm: "MODWU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
 
-		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true, clobberFlags: true},                                                 // arg0 & arg1
-		{name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW", commutative: true, clobberFlags: true},                                               // arg0 & arg1
-		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64", resultInArg0: true, clobberFlags: true},                             // arg0 & auxint
-		{name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDW", aux: "Int32", resultInArg0: true, clobberFlags: true},                           // arg0 & auxint
-		{name: "ANDload", argLength: 3, reg: gpopload, asm: "AND", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},   // arg0 & *arg1. arg2=mem
-		{name: "ANDWload", argLength: 3, reg: gpopload, asm: "ANDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 & *arg1. arg2=mem
-
-		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true, clobberFlags: true},                                                 // arg0 | arg1
-		{name: "ORW", argLength: 2, reg: gp21, asm: "ORW", commutative: true, clobberFlags: true},                                               // arg0 | arg1
-		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64", resultInArg0: true, clobberFlags: true},                             // arg0 | auxint
-		{name: "ORWconst", argLength: 1, reg: gp11, asm: "ORW", aux: "Int32", resultInArg0: true, clobberFlags: true},                           // arg0 | auxint
-		{name: "ORload", argLength: 3, reg: gpopload, asm: "OR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},   // arg0 | *arg1. arg2=mem
-		{name: "ORWload", argLength: 3, reg: gpopload, asm: "ORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 | *arg1. arg2=mem
-
-		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, clobberFlags: true},                                                 // arg0 ^ arg1
-		{name: "XORW", argLength: 2, reg: gp21, asm: "XORW", commutative: true, clobberFlags: true},                                               // arg0 ^ arg1
-		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", resultInArg0: true, clobberFlags: true},                             // arg0 ^ auxint
-		{name: "XORWconst", argLength: 1, reg: gp11, asm: "XORW", aux: "Int32", resultInArg0: true, clobberFlags: true},                           // arg0 ^ auxint
-		{name: "XORload", argLength: 3, reg: gpopload, asm: "XOR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},   // arg0 ^ *arg1. arg2=mem
-		{name: "XORWload", argLength: 3, reg: gpopload, asm: "XORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true}, // arg0 ^ *arg1. arg2=mem
+		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true, clobberFlags: true},                                                                    // arg0 & arg1
+		{name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW", commutative: true, clobberFlags: true},                                                                  // arg0 & arg1
+		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64", resultInArg0: true, clobberFlags: true},                                                // arg0 & auxint
+		{name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDW", aux: "Int32", resultInArg0: true, clobberFlags: true},                                              // arg0 & auxint
+		{name: "ANDload", argLength: 3, reg: gpopload, asm: "AND", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 & *arg1. arg2=mem
+		{name: "ANDWload", argLength: 3, reg: gpopload, asm: "ANDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & *arg1. arg2=mem
+
+		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true, clobberFlags: true},                                                                    // arg0 | arg1
+		{name: "ORW", argLength: 2, reg: gp21, asm: "ORW", commutative: true, clobberFlags: true},                                                                  // arg0 | arg1
+		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64", resultInArg0: true, clobberFlags: true},                                                // arg0 | auxint
+		{name: "ORWconst", argLength: 1, reg: gp11, asm: "ORW", aux: "Int32", resultInArg0: true, clobberFlags: true},                                              // arg0 | auxint
+		{name: "ORload", argLength: 3, reg: gpopload, asm: "OR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 | *arg1. arg2=mem
+		{name: "ORWload", argLength: 3, reg: gpopload, asm: "ORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | *arg1. arg2=mem
+
+		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, clobberFlags: true},                                                                    // arg0 ^ arg1
+		{name: "XORW", argLength: 2, reg: gp21, asm: "XORW", commutative: true, clobberFlags: true},                                                                  // arg0 ^ arg1
+		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", resultInArg0: true, clobberFlags: true},                                                // arg0 ^ auxint
+		{name: "XORWconst", argLength: 1, reg: gp11, asm: "XORW", aux: "Int32", resultInArg0: true, clobberFlags: true},                                              // arg0 ^ auxint
+		{name: "XORload", argLength: 3, reg: gpopload, asm: "XOR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"},   // arg0 ^ *arg1. arg2=mem
+		{name: "XORWload", argLength: 3, reg: gpopload, asm: "XORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ *arg1. arg2=mem
 
 		{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"},   // arg0 compare to arg1
 		{name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
@@ -260,24 +289,24 @@ func init() {
 		{name: "FCMPS", argLength: 2, reg: fp2flags, asm: "CEBR", typ: "Flags"}, // arg0 compare to arg1, f32
 		{name: "FCMP", argLength: 2, reg: fp2flags, asm: "FCMPU", typ: "Flags"}, // arg0 compare to arg1, f64
 
-		{name: "SLD", argLength: 2, reg: sh21, asm: "SLD"},                    // arg0 << arg1, shift amount is mod 64
-		{name: "SLW", argLength: 2, reg: sh21, asm: "SLW"},                    // arg0 << arg1, shift amount is mod 32
-		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxint, shift amount 0-63
-		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int32"}, // arg0 << auxint, shift amount 0-31
+		{name: "SLD", argLength: 2, reg: sh21, asm: "SLD"},                   // arg0 << arg1, shift amount is mod 64
+		{name: "SLW", argLength: 2, reg: sh21, asm: "SLW"},                   // arg0 << arg1, shift amount is mod 32
+		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int8"}, // arg0 << auxint, shift amount 0-63
+		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
 
-		{name: "SRD", argLength: 2, reg: sh21, asm: "SRD"},                    // unsigned arg0 >> arg1, shift amount is mod 64
-		{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"},                    // unsigned arg0 >> arg1, shift amount is mod 32
-		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxint, shift amount 0-63
-		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int32"}, // unsigned arg0 >> auxint, shift amount 0-31
+		{name: "SRD", argLength: 2, reg: sh21, asm: "SRD"},                   // unsigned arg0 >> arg1, shift amount is mod 64
+		{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"},                   // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63
+		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
 
 		// Arithmetic shifts clobber flags.
-		{name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true},                    // signed arg0 >> arg1, shift amount is mod 64
-		{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true},                    // signed arg0 >> arg1, shift amount is mod 32
-		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
-		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int32", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
+		{name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true},                   // signed arg0 >> arg1, shift amount is mod 64
+		{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true},                   // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
+		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
 
-		{name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int64"}, // arg0 rotate left auxint, rotate amount 0-63
-		{name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int32"},   // arg0 rotate left auxint, rotate amount 0-31
+		{name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63
+		{name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"},   // arg0 rotate left auxint, rotate amount 0-31
 
 		// unary ops
 		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG", clobberFlags: true},   // -arg0
@@ -328,66 +357,64 @@ func init() {
 		{name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"},   // convert float64 to float32
 		{name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"},   // convert float32 to float64
 
-		{name: "MOVDaddr", argLength: 1, reg: addr, aux: "SymOff", rematerializeable: true, clobberFlags: true}, // arg0 + auxint + offset encoded in aux
-		{name: "MOVDaddridx", argLength: 2, reg: addridx, aux: "SymOff", clobberFlags: true},                    // arg0 + arg1 + auxint + aux
+		{name: "MOVDaddr", argLength: 1, reg: addr, aux: "SymOff", rematerializeable: true, clobberFlags: true, symEffect: "Read"}, // arg0 + auxint + offset encoded in aux
+		{name: "MOVDaddridx", argLength: 2, reg: addridx, aux: "SymOff", clobberFlags: true, symEffect: "Read"},                    // arg0 + arg1 + auxint + aux
 
 		// auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
-		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", clobberFlags: true, faultOnNilArg0: true},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},                  // ditto, sign extend to int64
-		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},                  // ditto, sign extend to int64
-		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true}, // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},                  // ditto, sign extend to int64
-		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true},   // load 8 bytes from arg0+auxint+aux. arg1=mem
+		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"},                  // ditto, sign extend to int64
+		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"},                  // ditto, sign extend to int64
+		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"},                  // ditto, sign extend to int64
+		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"},   // load 8 bytes from arg0+auxint+aux. arg1=mem
 
 		{name: "MOVWBR", argLength: 1, reg: gp11, asm: "MOVWBR"}, // arg0 swap bytes
 		{name: "MOVDBR", argLength: 1, reg: gp11, asm: "MOVDBR"}, // arg0 swap bytes
 
-		{name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
-		{name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
-		{name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true}, // load 8 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
+		{name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
+		{name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
+		{name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes.
 
-		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},       // store byte in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},       // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},       // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},       // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
-		{name: "MOVHBRstore", argLength: 3, reg: gpstorebr, asm: "MOVHBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
-		{name: "MOVWBRstore", argLength: 3, reg: gpstorebr, asm: "MOVWBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
-		{name: "MOVDBRstore", argLength: 3, reg: gpstorebr, asm: "MOVDBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},       // store byte in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},       // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},       // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},       // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVHBRstore", argLength: 3, reg: gpstorebr, asm: "MOVHBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVWBRstore", argLength: 3, reg: gpstorebr, asm: "MOVWBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVDBRstore", argLength: 3, reg: gpstorebr, asm: "MOVDBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes.
 
-		{name: "MVC", argLength: 3, reg: gpmvc, asm: "MVC", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, faultOnNilArg1: true}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size,off
+		{name: "MVC", argLength: 3, reg: gpmvc, asm: "MVC", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, faultOnNilArg1: true, symEffect: "None"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size,off
 
 		// indexed loads/stores
 		// TODO(mundaym): add sign-extended indexed loads
-		{name: "MOVBZloadidx", argLength: 3, reg: gploadidx, asm: "MOVBZ", aux: "SymOff", clobberFlags: true},     // load a byte from arg0+arg1+auxint+aux. arg2=mem
-		{name: "MOVHZloadidx", argLength: 3, reg: gploadidx, asm: "MOVHZ", aux: "SymOff", clobberFlags: true},     // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
-		{name: "MOVWZloadidx", argLength: 3, reg: gploadidx, asm: "MOVWZ", aux: "SymOff", clobberFlags: true},     // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
-		{name: "MOVDloadidx", argLength: 3, reg: gploadidx, asm: "MOVD", aux: "SymOff", clobberFlags: true},       // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem
-		{name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVHBR", aux: "SymOff", clobberFlags: true},   // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
-		{name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVWBR", aux: "SymOff", clobberFlags: true},   // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
-		{name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVDBR", aux: "SymOff", clobberFlags: true},   // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
-		{name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVB", aux: "SymOff", clobberFlags: true},     // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
-		{name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVH", aux: "SymOff", clobberFlags: true},     // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
-		{name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff", clobberFlags: true},     // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
-		{name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVD", aux: "SymOff", clobberFlags: true},     // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
-		{name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVHBR", aux: "SymOff", clobberFlags: true}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
-		{name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVWBR", aux: "SymOff", clobberFlags: true}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
-		{name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVDBR", aux: "SymOff", clobberFlags: true}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
+		{name: "MOVBZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", clobberFlags: true, symEffect: "Read"},   // load a byte from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVHZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", clobberFlags: true, symEffect: "Read"},  // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", clobberFlags: true, symEffect: "Read"},  // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVDloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVD", aux: "SymOff", typ: "UInt64", clobberFlags: true, symEffect: "Read"},    // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHBR", aux: "SymOff", typ: "Int16", clobberFlags: true, symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWBR", aux: "SymOff", typ: "Int32", clobberFlags: true, symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVDBR", aux: "SymOff", typ: "Int64", clobberFlags: true, symEffect: "Read"}, // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes.
+		{name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVB", aux: "SymOff", clobberFlags: true, symEffect: "Write"},                // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVH", aux: "SymOff", clobberFlags: true, symEffect: "Write"},                // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVW", aux: "SymOff", clobberFlags: true, symEffect: "Write"},                // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVD", aux: "SymOff", clobberFlags: true, symEffect: "Write"},                // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVHBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"},            // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
+		{name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVWBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"},            // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
+		{name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVDBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"},            // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes.
 
 		// 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", clobberFlags: true, faultOnNilArg0: true}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
-		{name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store low 2 bytes of ...
-		{name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store low 4 bytes of ...
-		{name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true}, // store 8 bytes of ...
+		{name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
+		{name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
+		{name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
+		{name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
 
-		{name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},
+		{name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
 
-		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                               // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                            // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                 // call deferproc.  arg0=mem, auxint=argsize, returns mem
-		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                                    // call newproc.  arg0=mem, auxint=argsize, returns mem
 		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
 		// (InvertFlags (CMP a b)) == (CMP b a)
@@ -402,6 +429,9 @@ func init() {
 		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R12")}}},
 		// arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
 		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{ptrsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
+		// Round ops to block fused-multiply-add extraction.
+		{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true},
+		{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true},
 
 		// MOVDconvert converts between pointers and integers.
 		// We have a special op for this so as to not confuse GC
@@ -424,21 +454,21 @@ func init() {
 		// Atomic loads. These are just normal loads but return <value,memory> tuples
 		// so they can be properly ordered with other loads.
 		// load from arg0+auxint+aux.  arg1=mem.
-		{name: "MOVWZatomicload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", faultOnNilArg0: true},
-		{name: "MOVDatomicload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", faultOnNilArg0: true},
+		{name: "MOVWZatomicload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},
+		{name: "MOVDatomicload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},
 
 		// Atomic stores. These are just normal stores.
 		// store arg1 to arg0+auxint+aux. arg2=mem.
-		{name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
-		{name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"},
+		{name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"},
 
 		// Atomic adds.
 		// *(arg0+auxint+aux) += arg1.  arg2=mem.
 		// Returns a tuple of <old contents of *(arg0+auxint+aux), memory>.
-		{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true},
-		{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true},
-		{name: "AddTupleFirst32", argLength: 2}, // arg0=tuple <x,y>.  Returns <x+arg1,y>.
-		{name: "AddTupleFirst64", argLength: 2}, // arg0=tuple <x,y>.  Returns <x+arg1,y>.
+		{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>.  Returns <x+arg0,y>.
+		{name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>.  Returns <x+arg0,y>.
 
 		// Compare and swap.
 		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
@@ -461,13 +491,13 @@ func init() {
 		//    BEQ ...
 		// but we can't do that because memory-using ops can't generate flags yet
 		// (flagalloc wants to move flag-generating instructions around).
-		{name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
-		{name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
 
 		// Lowered atomic swaps, emulated using compare-and-swap.
 		// store arg1 to arg0+auxint+aux, arg2=mem.
-		{name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
-		{name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
+		{name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
+		{name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},
 
 		// find leftmost one
 		{
@@ -488,6 +518,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMG",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 		{
 			name:           "STMG3",
@@ -497,6 +528,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMG",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 		{
 			name:      "STMG4",
@@ -513,6 +545,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMG",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 		{
 			name:           "STM2",
@@ -522,6 +555,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMY",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 		{
 			name:           "STM3",
@@ -531,6 +565,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMY",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 		{
 			name:      "STM4",
@@ -547,6 +582,7 @@ func init() {
 			typ:            "Mem",
 			asm:            "STMY",
 			faultOnNilArg0: true,
+			symEffect:      "Write",
 		},
 
 		// large move
@@ -571,8 +607,10 @@ func init() {
 				inputs:   []regMask{buildReg("R1"), buildReg("R2"), gpsp},
 				clobbers: buildReg("R1 R2"),
 			},
-			clobberFlags: true,
-			typ:          "Mem",
+			clobberFlags:   true,
+			typ:            "Mem",
+			faultOnNilArg0: true,
+			faultOnNilArg1: true,
 		},
 
 		// large clear
@@ -595,8 +633,9 @@ func init() {
 				inputs:   []regMask{buildReg("R1"), gpsp},
 				clobbers: buildReg("R1"),
 			},
-			clobberFlags: true,
-			typ:          "Mem",
+			clobberFlags:   true,
+			typ:            "Mem",
+			faultOnNilArg0: true,
 		},
 	}
 
diff --git a/src/cmd/compile/internal/ssa/gen/dec.rules b/src/cmd/compile/internal/ssa/gen/dec.rules
index 401fba8..a475a2d 100644
--- a/src/cmd/compile/internal/ssa/gen/dec.rules
+++ b/src/cmd/compile/internal/ssa/gen/dec.rules
@@ -13,28 +13,28 @@
 
 (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)
+    (Load <typ.Float32> ptr mem)
+    (Load <typ.Float32>
+      (OffPtr <typ.Float32Ptr> [4] ptr)
       mem)
     )
-(Store [8] dst (ComplexMake real imag) mem) ->
-  (Store [4]
-    (OffPtr <config.fe.TypeFloat32().PtrTo()> [4] dst)
+(Store {t} dst (ComplexMake real imag) mem) && t.(*types.Type).Size() == 8 ->
+  (Store {typ.Float32}
+    (OffPtr <typ.Float32Ptr> [4] dst)
     imag
-    (Store [4] dst real mem))
+    (Store {typ.Float32} 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)
+    (Load <typ.Float64> ptr mem)
+    (Load <typ.Float64>
+      (OffPtr <typ.Float64Ptr> [8] ptr)
       mem)
     )
-(Store [16] dst (ComplexMake real imag) mem) ->
-  (Store [8]
-    (OffPtr <config.fe.TypeFloat64().PtrTo()> [8] dst)
+(Store {t} dst (ComplexMake real imag) mem) && t.(*types.Type).Size() == 16 ->
+  (Store {typ.Float64}
+    (OffPtr <typ.Float64Ptr> [8] dst)
     imag
-    (Store [8] dst real mem))
+    (Store {typ.Float64} dst real mem))
 
 // string ops
 (StringPtr (StringMake ptr _)) -> ptr
@@ -42,15 +42,15 @@
 
 (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)
+    (Load <typ.BytePtr> ptr mem)
+    (Load <typ.Int>
+      (OffPtr <typ.IntPtr> [config.PtrSize] ptr)
       mem))
-(Store [2*config.PtrSize] dst (StringMake ptr len) mem) ->
-  (Store [config.PtrSize]
-    (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)
+(Store dst (StringMake ptr len) mem) ->
+  (Store {typ.Int}
+    (OffPtr <typ.IntPtr> [config.PtrSize] dst)
     len
-    (Store [config.PtrSize] dst ptr mem))
+    (Store {typ.BytePtr} dst ptr mem))
 
 // slice ops
 (SlicePtr (SliceMake ptr _ _ )) -> ptr
@@ -60,20 +60,20 @@
 (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)
+    (Load <typ.Int>
+      (OffPtr <typ.IntPtr> [config.PtrSize] ptr)
       mem)
-    (Load <config.fe.TypeInt()>
-      (OffPtr <config.fe.TypeInt().PtrTo()> [2*config.PtrSize] ptr)
+    (Load <typ.Int>
+      (OffPtr <typ.IntPtr> [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)
+(Store dst (SliceMake ptr len cap) mem) ->
+  (Store {typ.Int}
+    (OffPtr <typ.IntPtr> [2*config.PtrSize] dst)
     cap
-    (Store [config.PtrSize]
-      (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)
+    (Store {typ.Int}
+      (OffPtr <typ.IntPtr> [config.PtrSize] dst)
       len
-      (Store [config.PtrSize] dst ptr mem)))
+      (Store {typ.BytePtr} dst ptr mem)))
 
 // interface ops
 (ITab (IMake itab _)) -> itab
@@ -81,12 +81,12 @@
 
 (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)
+    (Load <typ.BytePtr> ptr mem)
+    (Load <typ.BytePtr>
+      (OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr)
       mem))
-(Store [2*config.PtrSize] dst (IMake itab data) mem) ->
-  (Store [config.PtrSize]
-    (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)
+(Store dst (IMake itab data) mem) ->
+  (Store {typ.BytePtr}
+    (OffPtr <typ.BytePtrPtr> [config.PtrSize] dst)
     data
-    (Store [config.PtrSize] dst itab mem))
+    (Store {typ.Uintptr} dst itab mem))
diff --git a/src/cmd/compile/internal/ssa/gen/dec64.rules b/src/cmd/compile/internal/ssa/gen/dec64.rules
index 961ffc7..b9ac3de 100644
--- a/src/cmd/compile/internal/ssa/gen/dec64.rules
+++ b/src/cmd/compile/internal/ssa/gen/dec64.rules
@@ -4,7 +4,7 @@
 
 // This file contains rules to decompose [u]int64 types on 32-bit
 // architectures. These rules work together with the decomposeBuiltIn
-// pass which handles phis of these types.
+// pass which handles phis of these typ.
 
 (Int64Hi (Int64Make hi _)) -> hi
 (Int64Lo (Int64Make _ lo)) -> lo
@@ -12,120 +12,126 @@
 
 (Load <t> ptr mem) && is64BitInt(t) && !config.BigEndian && t.IsSigned() ->
 	(Int64Make
-		(Load <config.fe.TypeInt32()> (OffPtr <config.fe.TypeInt32().PtrTo()> [4] ptr) mem)
-		(Load <config.fe.TypeUInt32()> ptr mem))
+		(Load <typ.Int32> (OffPtr <typ.Int32Ptr> [4] ptr) mem)
+		(Load <typ.UInt32> ptr mem))
 
 (Load <t> ptr mem) && is64BitInt(t) && !config.BigEndian && !t.IsSigned() ->
 	(Int64Make
-		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem)
-		(Load <config.fe.TypeUInt32()> ptr mem))
+		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem)
+		(Load <typ.UInt32> ptr mem))
 
 (Load <t> ptr mem) && is64BitInt(t) && config.BigEndian && t.IsSigned() ->
 	(Int64Make
-		(Load <config.fe.TypeInt32()> ptr mem)
-		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem))
+		(Load <typ.Int32> ptr mem)
+		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem))
 
 (Load <t> ptr mem) && is64BitInt(t) && config.BigEndian && !t.IsSigned() ->
 	(Int64Make
-		(Load <config.fe.TypeUInt32()> ptr mem)
-		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem))
+		(Load <typ.UInt32> ptr mem)
+		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem))
 
-(Store [8] dst (Int64Make hi lo) mem) && !config.BigEndian ->
-	(Store [4]
+(Store {t} dst (Int64Make hi lo) mem) && t.(*types.Type).Size() == 8 && !config.BigEndian ->
+	(Store {hi.Type}
 		(OffPtr <hi.Type.PtrTo()> [4] dst)
 		hi
-		(Store [4] dst lo mem))
+		(Store {lo.Type} dst lo mem))
 
-(Store [8] dst (Int64Make hi lo) mem) && config.BigEndian ->
-	(Store [4]
+(Store {t} dst (Int64Make hi lo) mem) && t.(*types.Type).Size() == 8 && config.BigEndian ->
+	(Store {lo.Type}
 		(OffPtr <lo.Type.PtrTo()> [4] dst)
 		lo
-		(Store [4] dst hi mem))
+		(Store {hi.Type} dst hi mem))
 
 (Arg {n} [off]) && is64BitInt(v.Type) && !config.BigEndian && v.Type.IsSigned() ->
   (Int64Make
-    (Arg <config.fe.TypeInt32()> {n} [off+4])
-    (Arg <config.fe.TypeUInt32()> {n} [off]))
+    (Arg <typ.Int32> {n} [off+4])
+    (Arg <typ.UInt32> {n} [off]))
 (Arg {n} [off]) && is64BitInt(v.Type) && !config.BigEndian && !v.Type.IsSigned() ->
   (Int64Make
-    (Arg <config.fe.TypeUInt32()> {n} [off+4])
-    (Arg <config.fe.TypeUInt32()> {n} [off]))
+    (Arg <typ.UInt32> {n} [off+4])
+    (Arg <typ.UInt32> {n} [off]))
 
 (Arg {n} [off]) && is64BitInt(v.Type) && config.BigEndian && v.Type.IsSigned() ->
   (Int64Make
-    (Arg <config.fe.TypeInt32()> {n} [off])
-    (Arg <config.fe.TypeUInt32()> {n} [off+4]))
+    (Arg <typ.Int32> {n} [off])
+    (Arg <typ.UInt32> {n} [off+4]))
 (Arg {n} [off]) && is64BitInt(v.Type) && config.BigEndian && !v.Type.IsSigned() ->
   (Int64Make
-    (Arg <config.fe.TypeUInt32()> {n} [off])
-    (Arg <config.fe.TypeUInt32()> {n} [off+4]))
+    (Arg <typ.UInt32> {n} [off])
+    (Arg <typ.UInt32> {n} [off+4]))
 
 (Add64 x y) ->
 	(Int64Make
-		(Add32withcarry <config.fe.TypeInt32()>
+		(Add32withcarry <typ.Int32>
 			(Int64Hi x)
 			(Int64Hi y)
-			(Select1 <TypeFlags> (Add32carry (Int64Lo x) (Int64Lo y))))
-		(Select0 <config.fe.TypeUInt32()> (Add32carry (Int64Lo x) (Int64Lo y))))
+			(Select1 <types.TypeFlags> (Add32carry (Int64Lo x) (Int64Lo y))))
+		(Select0 <typ.UInt32> (Add32carry (Int64Lo x) (Int64Lo y))))
 
 (Sub64 x y) ->
 	(Int64Make
-		(Sub32withcarry <config.fe.TypeInt32()>
+		(Sub32withcarry <typ.Int32>
 			(Int64Hi x)
 			(Int64Hi y)
-			(Select1 <TypeFlags> (Sub32carry (Int64Lo x) (Int64Lo y))))
-		(Select0 <config.fe.TypeUInt32()> (Sub32carry (Int64Lo x) (Int64Lo y))))
+			(Select1 <types.TypeFlags> (Sub32carry (Int64Lo x) (Int64Lo y))))
+		(Select0 <typ.UInt32> (Sub32carry (Int64Lo x) (Int64Lo y))))
 
 (Mul64 x y) ->
 	(Int64Make
-		(Add32 <config.fe.TypeUInt32()>
-			(Mul32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Hi y))
-			(Add32 <config.fe.TypeUInt32()>
-				(Mul32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Lo y))
-				(Select0 <config.fe.TypeUInt32()> (Mul32uhilo (Int64Lo x) (Int64Lo y)))))
-		(Select1 <config.fe.TypeUInt32()> (Mul32uhilo (Int64Lo x) (Int64Lo y))))
+		(Add32 <typ.UInt32>
+			(Mul32 <typ.UInt32> (Int64Lo x) (Int64Hi y))
+			(Add32 <typ.UInt32>
+				(Mul32 <typ.UInt32> (Int64Hi x) (Int64Lo y))
+				(Select0 <typ.UInt32> (Mul32uhilo (Int64Lo x) (Int64Lo y)))))
+		(Select1 <typ.UInt32> (Mul32uhilo (Int64Lo x) (Int64Lo y))))
 
 (And64 x y) ->
 	(Int64Make
-		(And32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
-		(And32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+		(And32 <typ.UInt32> (Int64Hi x) (Int64Hi y))
+		(And32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 
 (Or64 x y) ->
 	(Int64Make
-		(Or32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
-		(Or32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+		(Or32 <typ.UInt32> (Int64Hi x) (Int64Hi y))
+		(Or32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 
 (Xor64 x y) ->
 	(Int64Make
-		(Xor32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
-		(Xor32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+		(Xor32 <typ.UInt32> (Int64Hi x) (Int64Hi y))
+		(Xor32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 
 (Neg64 <t> x) -> (Sub64 (Const64 <t> [0]) x)
 
 (Com64 x) ->
 	(Int64Make
-		(Com32 <config.fe.TypeUInt32()> (Int64Hi x))
-		(Com32 <config.fe.TypeUInt32()> (Int64Lo x)))
+		(Com32 <typ.UInt32> (Int64Hi x))
+		(Com32 <typ.UInt32> (Int64Lo x)))
 
 (Ctz64 x) ->
-	(Int64Make
-		(Const32 <config.fe.TypeUInt32()> [0])
-		(Add32 <config.fe.TypeUInt32()>
-			(Ctz32 <config.fe.TypeUInt32()> (Int64Lo x))
-			(And32 <config.fe.TypeUInt32()>
-				(Com32 <config.fe.TypeUInt32()> (Zeromask (Int64Lo x)))
-				(Ctz32 <config.fe.TypeUInt32()> (Int64Hi x)))))
+	(Add32 <typ.UInt32>
+		(Ctz32 <typ.UInt32> (Int64Lo x))
+		(And32 <typ.UInt32>
+			(Com32 <typ.UInt32> (Zeromask (Int64Lo x)))
+			(Ctz32 <typ.UInt32> (Int64Hi x))))
+
+(BitLen64 x) ->
+	(Add32 <typ.Int>
+		(BitLen32 <typ.Int> (Int64Hi x))
+		(BitLen32 <typ.Int>
+			(Or32 <typ.UInt32>
+				(Int64Lo x)
+				(Zeromask (Int64Hi x)))))
 
 (Bswap64 x) ->
 	(Int64Make
-		(Bswap32 <config.fe.TypeUInt32()> (Int64Lo x))
-		(Bswap32 <config.fe.TypeUInt32()> (Int64Hi x)))
+		(Bswap32 <typ.UInt32> (Int64Lo x))
+		(Bswap32 <typ.UInt32> (Int64Hi x)))
 
 (SignExt32to64 x) -> (Int64Make (Signmask x) x)
 (SignExt16to64 x) -> (SignExt32to64 (SignExt16to32 x))
 (SignExt8to64 x) -> (SignExt32to64 (SignExt8to32 x))
 
-(ZeroExt32to64 x) -> (Int64Make (Const32 <config.fe.TypeUInt32()> [0]) x)
+(ZeroExt32to64 x) -> (Int64Make (Const32 <typ.UInt32> [0]) x)
 (ZeroExt16to64 x) -> (ZeroExt32to64 (ZeroExt16to32 x))
 (ZeroExt8to64 x) -> (ZeroExt32to64 (ZeroExt8to32 x))
 
@@ -164,160 +170,160 @@
 // turn x64 non-constant shifts to x32 shifts
 // if high 32-bit of the shift is nonzero, make a huge shift
 (Lsh64x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Lsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Lsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh64x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh64Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh64Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Lsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Lsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Lsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh32Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh32Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Lsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Lsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Lsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh16Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh16Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Lsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Lsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Lsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 (Rsh8Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
-	(Rsh8Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	(Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 
 // 64x left shift
 // result.hi = hi<<s | lo>>(32-s) | lo<<(s-32) // >> is unsigned, large shifts result 0
 // result.lo = lo<<s
 (Lsh64x32 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Lsh32x32 <config.fe.TypeUInt32()> hi s)
-				(Rsh32Ux32 <config.fe.TypeUInt32()>
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Lsh32x32 <typ.UInt32> hi s)
+				(Rsh32Ux32 <typ.UInt32>
 					lo
-					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s)))
-			(Lsh32x32 <config.fe.TypeUInt32()>
+					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
+			(Lsh32x32 <typ.UInt32>
 				lo
-				(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32]))))
-		(Lsh32x32 <config.fe.TypeUInt32()> lo s))
+				(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32]))))
+		(Lsh32x32 <typ.UInt32> lo s))
 (Lsh64x16 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Lsh32x16 <config.fe.TypeUInt32()> hi s)
-				(Rsh32Ux16 <config.fe.TypeUInt32()>
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Lsh32x16 <typ.UInt32> hi s)
+				(Rsh32Ux16 <typ.UInt32>
 					lo
-					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s)))
-			(Lsh32x16 <config.fe.TypeUInt32()>
+					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
+			(Lsh32x16 <typ.UInt32>
 				lo
-				(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32]))))
-		(Lsh32x16 <config.fe.TypeUInt32()> lo s))
+				(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32]))))
+		(Lsh32x16 <typ.UInt32> lo s))
 (Lsh64x8 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Lsh32x8 <config.fe.TypeUInt32()> hi s)
-				(Rsh32Ux8 <config.fe.TypeUInt32()>
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Lsh32x8 <typ.UInt32> hi s)
+				(Rsh32Ux8 <typ.UInt32>
 					lo
-					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s)))
-			(Lsh32x8 <config.fe.TypeUInt32()>
+					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
+			(Lsh32x8 <typ.UInt32>
 				lo
-				(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32]))))
-		(Lsh32x8 <config.fe.TypeUInt32()> lo s))
+				(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32]))))
+		(Lsh32x8 <typ.UInt32> lo s))
 
 // 64x unsigned right shift
 // result.hi = hi>>s
 // result.lo = lo>>s | hi<<(32-s) | hi>>(s-32) // >> is unsigned, large shifts result 0
 (Rsh64Ux32 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32Ux32 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux32 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x32 <config.fe.TypeUInt32()>
+		(Rsh32Ux32 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux32 <typ.UInt32> lo s)
+				(Lsh32x32 <typ.UInt32>
 					hi
-					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s)))
-			(Rsh32Ux32 <config.fe.TypeUInt32()>
+					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
+			(Rsh32Ux32 <typ.UInt32>
 				hi
-				(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32])))))
+				(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))))
 (Rsh64Ux16 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32Ux16 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux16 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x16 <config.fe.TypeUInt32()>
+		(Rsh32Ux16 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux16 <typ.UInt32> lo s)
+				(Lsh32x16 <typ.UInt32>
 					hi
-					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s)))
-			(Rsh32Ux16 <config.fe.TypeUInt32()>
+					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
+			(Rsh32Ux16 <typ.UInt32>
 				hi
-				(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32])))))
+				(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))))
 (Rsh64Ux8 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32Ux8 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux8 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x8 <config.fe.TypeUInt32()>
+		(Rsh32Ux8 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux8 <typ.UInt32> lo s)
+				(Lsh32x8 <typ.UInt32>
 					hi
-					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s)))
-			(Rsh32Ux8 <config.fe.TypeUInt32()>
+					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
+			(Rsh32Ux8 <typ.UInt32>
 				hi
-				(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32])))))
+				(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))))
 
 // 64x signed right shift
 // result.hi = hi>>s
 // result.lo = lo>>s | hi<<(32-s) | (hi>>(s-32))&zeromask(s>>5) // hi>>(s-32) is signed, large shifts result 0/-1
 (Rsh64x32 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32x32 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux32 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x32 <config.fe.TypeUInt32()>
+		(Rsh32x32 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux32 <typ.UInt32> lo s)
+				(Lsh32x32 <typ.UInt32>
 					hi
-					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s)))
-			(And32 <config.fe.TypeUInt32()>
-				(Rsh32x32 <config.fe.TypeUInt32()>
+					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
+			(And32 <typ.UInt32>
+				(Rsh32x32 <typ.UInt32>
 					hi
-					(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32])))
+					(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))
 				(Zeromask
-					(Rsh32Ux32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [5]))))))
+					(Rsh32Ux32 <typ.UInt32> s (Const32 <typ.UInt32> [5]))))))
 (Rsh64x16 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32x16 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux16 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x16 <config.fe.TypeUInt32()>
+		(Rsh32x16 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux16 <typ.UInt32> lo s)
+				(Lsh32x16 <typ.UInt32>
 					hi
-					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s)))
-			(And32 <config.fe.TypeUInt32()>
-				(Rsh32x16 <config.fe.TypeUInt32()>
+					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
+			(And32 <typ.UInt32>
+				(Rsh32x16 <typ.UInt32>
 					hi
-					(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32])))
+					(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))
 				(Zeromask
 					(ZeroExt16to32
-						(Rsh16Ux32 <config.fe.TypeUInt16()> s (Const32 <config.fe.TypeUInt32()> [5])))))))
+						(Rsh16Ux32 <typ.UInt16> s (Const32 <typ.UInt32> [5])))))))
 (Rsh64x8 (Int64Make hi lo) s) ->
 	(Int64Make
-		(Rsh32x8 <config.fe.TypeUInt32()> hi s)
-		(Or32 <config.fe.TypeUInt32()>
-			(Or32 <config.fe.TypeUInt32()>
-				(Rsh32Ux8 <config.fe.TypeUInt32()> lo s)
-				(Lsh32x8 <config.fe.TypeUInt32()>
+		(Rsh32x8 <typ.UInt32> hi s)
+		(Or32 <typ.UInt32>
+			(Or32 <typ.UInt32>
+				(Rsh32Ux8 <typ.UInt32> lo s)
+				(Lsh32x8 <typ.UInt32>
 					hi
-					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s)))
-			(And32 <config.fe.TypeUInt32()>
-				(Rsh32x8 <config.fe.TypeUInt32()>
+					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
+			(And32 <typ.UInt32>
+				(Rsh32x8 <typ.UInt32>
 					hi
-					(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32])))
+					(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))
 				(Zeromask
 					(ZeroExt8to32
-						(Rsh8Ux32 <config.fe.TypeUInt8()> s (Const32 <config.fe.TypeUInt32()> [5])))))))
+						(Rsh8Ux32 <typ.UInt8> s (Const32 <typ.UInt32> [5])))))))
 
 // 64xConst32 shifts
 // we probably do not need them -- lateopt may take care of them just fine
@@ -327,58 +333,48 @@
 //
 //(Lsh64x32 x (Const32 [c])) && c < 64 && c > 32 ->
 //	(Int64Make
-//		(Lsh32x32 <config.fe.TypeUInt32()> (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [c-32]))
-//		(Const32 <config.fe.TypeUInt32()> [0]))
+//		(Lsh32x32 <typ.UInt32> (Int64Lo x) (Const32 <typ.UInt32> [c-32]))
+//		(Const32 <typ.UInt32> [0]))
 //(Rsh64x32 x (Const32 [c])) && c < 64 && c > 32 ->
 //	(Int64Make
 //		(Signmask (Int64Hi x))
-//		(Rsh32x32 <config.fe.TypeInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [c-32])))
+//		(Rsh32x32 <typ.Int32> (Int64Hi x) (Const32 <typ.UInt32> [c-32])))
 //(Rsh64Ux32 x (Const32 [c])) && c < 64 && c > 32 ->
 //	(Int64Make
-//		(Const32 <config.fe.TypeUInt32()> [0])
-//		(Rsh32Ux32 <config.fe.TypeUInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [c-32])))
+//		(Const32 <typ.UInt32> [0])
+//		(Rsh32Ux32 <typ.UInt32> (Int64Hi x) (Const32 <typ.UInt32> [c-32])))
 //
-//(Lsh64x32 x (Const32 [32])) -> (Int64Make (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [0]))
+//(Lsh64x32 x (Const32 [32])) -> (Int64Make (Int64Lo x) (Const32 <typ.UInt32> [0]))
 //(Rsh64x32 x (Const32 [32])) -> (Int64Make (Signmask (Int64Hi x)) (Int64Hi x))
-//(Rsh64Ux32 x (Const32 [32])) -> (Int64Make (Const32 <config.fe.TypeUInt32()> [0]) (Int64Hi x))
+//(Rsh64Ux32 x (Const32 [32])) -> (Int64Make (Const32 <typ.UInt32> [0]) (Int64Hi x))
 //
 //(Lsh64x32 x (Const32 [c])) && c < 32 && c > 0 ->
 //	(Int64Make
-//		(Or32 <config.fe.TypeUInt32()>
-//			(Lsh32x32 <config.fe.TypeUInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [c]))
-//			(Rsh32Ux32 <config.fe.TypeUInt32()> (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [32-c])))
-//		(Lsh32x32 <config.fe.TypeUInt32()> (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [c])))
+//		(Or32 <typ.UInt32>
+//			(Lsh32x32 <typ.UInt32> (Int64Hi x) (Const32 <typ.UInt32> [c]))
+//			(Rsh32Ux32 <typ.UInt32> (Int64Lo x) (Const32 <typ.UInt32> [32-c])))
+//		(Lsh32x32 <typ.UInt32> (Int64Lo x) (Const32 <typ.UInt32> [c])))
 //(Rsh64x32 x (Const32 [c])) && c < 32 && c > 0 ->
 //	(Int64Make
-//		(Rsh32x32 <config.fe.TypeInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [c]))
-//		(Or32 <config.fe.TypeUInt32()>
-//			(Rsh32Ux32 <config.fe.TypeUInt32()> (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [c]))
-//			(Lsh32x32 <config.fe.TypeUInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [32-c]))))
+//		(Rsh32x32 <typ.Int32> (Int64Hi x) (Const32 <typ.UInt32> [c]))
+//		(Or32 <typ.UInt32>
+//			(Rsh32Ux32 <typ.UInt32> (Int64Lo x) (Const32 <typ.UInt32> [c]))
+//			(Lsh32x32 <typ.UInt32> (Int64Hi x) (Const32 <typ.UInt32> [32-c]))))
 //(Rsh64Ux32 x (Const32 [c])) && c < 32 && c > 0 ->
 //	(Int64Make
-//		(Rsh32Ux32 <config.fe.TypeUInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [c]))
-//		(Or32 <config.fe.TypeUInt32()>
-//			(Rsh32Ux32 <config.fe.TypeUInt32()> (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [c]))
-//			(Lsh32x32 <config.fe.TypeUInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [32-c]))))
+//		(Rsh32Ux32 <typ.UInt32> (Int64Hi x) (Const32 <typ.UInt32> [c]))
+//		(Or32 <typ.UInt32>
+//			(Rsh32Ux32 <typ.UInt32> (Int64Lo x) (Const32 <typ.UInt32> [c]))
+//			(Lsh32x32 <typ.UInt32> (Int64Hi x) (Const32 <typ.UInt32> [32-c]))))
 //
 //(Lsh64x32 x (Const32 [0])) -> x
 //(Rsh64x32 x (Const32 [0])) -> x
 //(Rsh64Ux32 x (Const32 [0])) -> x
 
-(Lrot64 (Int64Make hi lo) [c]) && c <= 32 ->
-	(Int64Make
-		(Or32 <config.fe.TypeUInt32()>
-			(Lsh32x32 <config.fe.TypeUInt32()> hi (Const32 <config.fe.TypeUInt32()> [c]))
-			(Rsh32Ux32 <config.fe.TypeUInt32()> lo (Const32 <config.fe.TypeUInt32()> [32-c])))
-		(Or32 <config.fe.TypeUInt32()>
-			(Lsh32x32 <config.fe.TypeUInt32()> lo (Const32 <config.fe.TypeUInt32()> [c]))
-			(Rsh32Ux32 <config.fe.TypeUInt32()> hi (Const32 <config.fe.TypeUInt32()> [32-c]))))
-(Lrot64 (Int64Make hi lo) [c]) && c > 32 -> (Lrot64 (Int64Make lo hi) [c-32])
-
 (Const64 <t> [c]) && t.IsSigned() ->
-	(Int64Make (Const32 <config.fe.TypeInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+	(Int64Make (Const32 <typ.Int32> [c>>32]) (Const32 <typ.UInt32> [int64(int32(c))]))
 (Const64 <t> [c]) && !t.IsSigned() ->
-	(Int64Make (Const32 <config.fe.TypeUInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+	(Int64Make (Const32 <typ.UInt32> [c>>32]) (Const32 <typ.UInt32> [int64(int32(c))]))
 
 (Eq64 x y) ->
 	(AndB
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index 0137b10..b8d7381 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -46,6 +46,8 @@
 (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
+(Round32F x:(Const32F)) -> x
+(Round64F x:(Const64F)) -> x
 
 (Trunc16to8  (ZeroExt8to16  x)) -> x
 (Trunc32to8  (ZeroExt8to32  x)) -> x
@@ -68,13 +70,25 @@
 (Trunc64to32 (SignExt16to64 x)) -> (SignExt16to32 x)
 (Trunc64to32 (SignExt32to64 x)) -> x
 
-// 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))])
+(ZeroExt8to16  (Const8  [c])) -> (Const16 [int64( uint8(c))])
+(ZeroExt8to32  (Const8  [c])) -> (Const32 [int64( uint8(c))])
+(ZeroExt8to64  (Const8  [c])) -> (Const64 [int64( uint8(c))])
+(ZeroExt16to32 (Const16 [c])) -> (Const32 [int64(uint16(c))])
+(ZeroExt16to64 (Const16 [c])) -> (Const64 [int64(uint16(c))])
+(ZeroExt32to64 (Const32 [c])) -> (Const64 [int64(uint32(c))])
+(SignExt8to16  (Const8  [c])) -> (Const16 [int64(  int8(c))])
+(SignExt8to32  (Const8  [c])) -> (Const32 [int64(  int8(c))])
+(SignExt8to64  (Const8  [c])) -> (Const64 [int64(  int8(c))])
+(SignExt16to32 (Const16 [c])) -> (Const32 [int64( int16(c))])
+(SignExt16to64 (Const16 [c])) -> (Const64 [int64( int16(c))])
+(SignExt32to64 (Const32 [c])) -> (Const64 [int64( int32(c))])
+
+(Neg8   (Const8   [c])) -> (Const8   [int64( -int8(c))])
+(Neg16  (Const16  [c])) -> (Const16  [int64(-int16(c))])
+(Neg32  (Const32  [c])) -> (Const32  [int64(-int32(c))])
+(Neg64  (Const64  [c])) -> (Const64  [-c])
+(Neg32F (Const32F [c])) && i2f(c) != 0 -> (Const32F [f2i(-i2f(c))])
+(Neg64F (Const64F [c])) && i2f(c) != 0 -> (Const64F [f2i(-i2f(c))])
 
 (Add8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c+d))])
 (Add16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c+d))])
@@ -84,6 +98,7 @@
         (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])
+(AddPtr <t> x (Const32 [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))])
@@ -101,12 +116,54 @@
         (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
 (Mul64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) * i2f(d))])
 
-// Convert x * -1 to -x. The front-end catches some but not all of these.
+(And8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c&d))])
+(And16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c&d))])
+(And32  (Const32 [c])  (Const32 [d]))  -> (Const32 [int64(int32(c&d))])
+(And64  (Const64 [c])  (Const64 [d]))  -> (Const64 [c&d])
+
+(Or8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c|d))])
+(Or16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c|d))])
+(Or32  (Const32 [c])  (Const32 [d]))  -> (Const32 [int64(int32(c|d))])
+(Or64  (Const64 [c])  (Const64 [d]))  -> (Const64 [c|d])
+
+(Xor8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c^d))])
+(Xor16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c^d))])
+(Xor32  (Const32 [c])  (Const32 [d]))  -> (Const32 [int64(int32(c^d))])
+(Xor64  (Const64 [c])  (Const64 [d]))  -> (Const64 [c^d])
+
+(Div8   (Const8  [c])  (Const8  [d])) && d != 0 -> (Const8  [int64(int8(c)/int8(d))])
+(Div16  (Const16 [c])  (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c)/int16(d))])
+(Div32  (Const32 [c])  (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c)/int32(d))])
+(Div64  (Const64 [c])  (Const64 [d])) && d != 0 -> (Const64 [c/d])
+(Div8u  (Const8  [c])  (Const8  [d])) && d != 0 -> (Const8  [int64(int8(uint8(c)/uint8(d)))])
+(Div16u (Const16 [c])  (Const16 [d])) && d != 0 -> (Const16 [int64(int16(uint16(c)/uint16(d)))])
+(Div32u (Const32 [c])  (Const32 [d])) && d != 0 -> (Const32 [int64(int32(uint32(c)/uint32(d)))])
+(Div64u (Const64 [c])  (Const64 [d])) && d != 0 -> (Const64 [int64(uint64(c)/uint64(d))])
+(Div32F (Const32F [c]) (Const32F [d])) -> (Const32F [f2i(float64(i2f32(c) / i2f32(d)))])
+(Div64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) / i2f(d))])
+
+// Convert x * 1 to x.
+(Mul8  (Const8  [1]) x) -> x
+(Mul16 (Const16 [1]) x) -> x
+(Mul32 (Const32 [1]) x) -> x
+(Mul64 (Const64 [1]) x) -> x
+
+// Convert x * -1 to -x.
 (Mul8  (Const8  [-1]) x) -> (Neg8  x)
 (Mul16 (Const16 [-1]) x) -> (Neg16 x)
 (Mul32 (Const32 [-1]) x) -> (Neg32 x)
 (Mul64 (Const64 [-1]) x) -> (Neg64 x)
 
+// Convert multiplication by a power of two to a shift.
+(Mul8  <t> n (Const8  [c])) && isPowerOfTwo(c) -> (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(c)]))
+(Mul16 <t> n (Const16 [c])) && isPowerOfTwo(c) -> (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+(Mul32 <t> n (Const32 [c])) && isPowerOfTwo(c) -> (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+(Mul64 <t> n (Const64 [c])) && isPowerOfTwo(c) -> (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+(Mul8  <t> n (Const8  [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg8  (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(-c)])))
+(Mul16 <t> n (Const16 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg16 (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+(Mul32 <t> n (Const32 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg32 (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+(Mul64 <t> n (Const64 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg64 (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+
 (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))])
@@ -136,8 +193,16 @@
 (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                (And8  (Const8  [c]) _)  (Const8  [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt8to16  (And8  (Const8  [c]) _)) (Const16 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt8to32  (And8  (Const8  [c]) _)) (Const32 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt8to64  (And8  (Const8  [c]) _)) (Const64 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds                (And16 (Const16 [c]) _)  (Const16 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt16to32 (And16 (Const16 [c]) _)) (Const32 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt16to64 (And16 (Const16 [c]) _)) (Const64 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds                (And32 (Const32 [c]) _)  (Const32 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (ZeroExt32to64 (And32 (Const32 [c]) _)) (Const64 [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).
@@ -168,6 +233,7 @@
 (NeqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c != d)])
 (NeqB (ConstBool [0]) x) -> x
 (NeqB (ConstBool [1]) x) -> (Not x)
+(NeqB (Not x) (Not y)) -> (NeqB x y)
 
 (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)
@@ -179,48 +245,12 @@
 (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)
-
+// Canonicalize x-const to x+(-const)
 (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)
-
 // fold negation into comparison operators
 (Not (Eq64 x y)) -> (Neq64 x y)
 (Not (Eq32 x y)) -> (Neq32 x y)
@@ -416,30 +446,46 @@
 // ((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]))
+  -> (Rsh64Ux64 x (Const64 <typ.UInt64> [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]))
+  -> (Rsh32Ux64 x (Const64 <typ.UInt64> [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]))
+  -> (Rsh16Ux64 x (Const64 <typ.UInt64> [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]))
+  -> (Rsh8Ux64 x (Const64 <typ.UInt64> [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]))
+  -> (Lsh64x64 x (Const64 <typ.UInt64> [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]))
+  -> (Lsh32x64 x (Const64 <typ.UInt64> [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]))
+  -> (Lsh16x64 x (Const64 <typ.UInt64> [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]))
+  -> (Lsh8x64 x (Const64 <typ.UInt64> [c1-c2+c3]))
+
+// replace shifts with zero extensions
+(Rsh16Ux64 (Lsh16x64 x (Const64  [8])) (Const64  [8])) -> (ZeroExt8to16  (Trunc16to8  <typ.UInt8>  x))
+(Rsh32Ux64 (Lsh32x64 x (Const64 [24])) (Const64 [24])) -> (ZeroExt8to32  (Trunc32to8  <typ.UInt8>  x))
+(Rsh64Ux64 (Lsh64x64 x (Const64 [56])) (Const64 [56])) -> (ZeroExt8to64  (Trunc64to8  <typ.UInt8>  x))
+(Rsh32Ux64 (Lsh32x64 x (Const64 [16])) (Const64 [16])) -> (ZeroExt16to32 (Trunc32to16 <typ.UInt16> x))
+(Rsh64Ux64 (Lsh64x64 x (Const64 [48])) (Const64 [48])) -> (ZeroExt16to64 (Trunc64to16 <typ.UInt16> x))
+(Rsh64Ux64 (Lsh64x64 x (Const64 [32])) (Const64 [32])) -> (ZeroExt32to64 (Trunc64to32 <typ.UInt32> x))
+
+// replace shifts with sign extensions
+(Rsh16x64 (Lsh16x64 x (Const64  [8])) (Const64  [8])) -> (SignExt8to16  (Trunc16to8  <typ.Int8>  x))
+(Rsh32x64 (Lsh32x64 x (Const64 [24])) (Const64 [24])) -> (SignExt8to32  (Trunc32to8  <typ.Int8>  x))
+(Rsh64x64 (Lsh64x64 x (Const64 [56])) (Const64 [56])) -> (SignExt8to64  (Trunc64to8  <typ.Int8>  x))
+(Rsh32x64 (Lsh32x64 x (Const64 [16])) (Const64 [16])) -> (SignExt16to32 (Trunc32to16 <typ.Int16> x))
+(Rsh64x64 (Lsh64x64 x (Const64 [48])) (Const64 [48])) -> (SignExt16to64 (Trunc64to16 <typ.Int16> x))
+(Rsh64x64 (Lsh64x64 x (Const64 [32])) (Const64 [32])) -> (SignExt32to64 (Trunc64to32 <typ.Int32> x))
 
 // constant comparisons
 (Eq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c == d)])
@@ -541,59 +587,43 @@
 (Com16 (Com16 x)) -> x
 (Com32 (Com32 x)) -> x
 (Com64 (Com64 x)) -> x
+(Com8  (Const8  [c])) -> (Const8  [^c])
+(Com16 (Const16 [c])) -> (Const16 [^c])
+(Com32 (Const32 [c])) -> (Const32 [^c])
+(Com64 (Const64 [c])) -> (Const64 [^c])
 (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)
+(Add8  (Const8  [1]) (Com8  x)) -> (Neg8  x)
+(Add16 (Const16 [1]) (Com16 x)) -> (Neg16 x)
+(Add32 (Const32 [1]) (Com32 x)) -> (Neg32 x)
+(Add64 (Const64 [1]) (Com64 x)) -> (Neg64 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
+
+// Ands clear bits. Ors set bits.
+// If a subsequent Or will set all the bits
+// that an And cleared, we can skip the And.
+// This happens in bitmasking code like:
+//   x &^= 3 << shift // clear two old bits
+//   x  |= v << shift // set two new bits
+// when shift is a small constant and v ends up a constant 3.
+(Or8  (And8  x (Const8  [c2])) (Const8  <t> [c1])) && ^(c1 | c2) == 0 -> (Or8  (Const8  <t> [c1]) x)
+(Or16 (And16 x (Const16 [c2])) (Const16 <t> [c1])) && ^(c1 | c2) == 0 -> (Or16 (Const16 <t> [c1]) x)
+(Or32 (And32 x (Const32 [c2])) (Const32 <t> [c1])) && ^(c1 | c2) == 0 -> (Or32 (Const32 <t> [c1]) x)
+(Or64 (And64 x (Const64 [c2])) (Const64 <t> [c1])) && ^(c1 | c2) == 0 -> (Or64 (Const64 <t> [c1]) x)
 
 (Trunc64to8  (And64 (Const64 [y]) x)) && y&0xFF == 0xFF -> (Trunc64to8 x)
 (Trunc64to16 (And64 (Const64 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc64to16 x)
@@ -647,9 +677,8 @@
 
 // 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))
+(IsNonNil (ConstNil)) -> (ConstBool [0])
 
 // slice and interface comparisons
 // The frontend ensures that we can only compare against nil,
@@ -660,16 +689,43 @@
 (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
+(Load <t1> p1 (Store {t2} p2 x _)) && isSamePtr(p1,p2) && t1.Compare(x.Type) == types.CMPeq && t1.Size() == t2.(*types.Type).Size() -> x
+
+// Eliminate stores of values that have just been loaded from the same location.
+// We also handle the common case where there are some intermediate stores to non-overlapping struct fields.
+(Store {t1} p1 (Load <t2> p2 mem) mem) &&
+	isSamePtr(p1, p2) &&
+	t2.Size() == t1.(*types.Type).Size() -> mem
+(Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ oldmem)) &&
+	isSamePtr(p1, p2) &&
+	isSamePtr(p1, p3) &&
+	t2.Size() == t1.(*types.Type).Size() &&
+	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) -> mem
+(Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ (Store {t4} (OffPtr [o4] p4) _ oldmem))) &&
+	isSamePtr(p1, p2) &&
+	isSamePtr(p1, p3) &&
+	isSamePtr(p1, p4) &&
+	t2.Size() == t1.(*types.Type).Size() &&
+	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) &&
+	!overlap(o1, t2.Size(), o4, t4.(*types.Type).Size()) -> mem
+(Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ (Store {t4} (OffPtr [o4] p4) _ (Store {t5} (OffPtr [o5] p5) _ oldmem)))) &&
+	isSamePtr(p1, p2) &&
+	isSamePtr(p1, p3) &&
+	isSamePtr(p1, p4) &&
+	isSamePtr(p1, p5) &&
+	t2.Size() == t1.(*types.Type).Size() &&
+	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) &&
+	!overlap(o1, t2.Size(), o4, t4.(*types.Type).Size()) &&
+	!overlap(o1, t2.Size(), o5, t5.(*types.Type).Size()) -> mem
 
 // Collapse OffPtr
 (OffPtr (OffPtr p [b]) [a]) -> (OffPtr p [a+b])
-(OffPtr p [0]) && v.Type.Compare(p.Type) == CMPeq -> p
+(OffPtr p [0]) && v.Type.Compare(p.Type) == types.CMPeq -> p
 
 // indexing operations
 // Note: bounds check has already been done
-(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()])))
+(PtrIndex <t> ptr idx) && config.PtrSize == 4 -> (AddPtr ptr (Mul32 <typ.Int> idx (Const32 <typ.Int> [t.ElemType().Size()])))
+(PtrIndex <t> ptr idx) && config.PtrSize == 8 -> (AddPtr ptr (Mul64 <typ.Int> idx (Const64 <typ.Int> [t.ElemType().Size()])))
 
 // struct operations
 (StructSelect (StructMake1 x)) -> x
@@ -683,67 +739,73 @@
 (StructSelect [2] (StructMake4 _ _ x _)) -> x
 (StructSelect [3] (StructMake4 _ _ _ x)) -> x
 
-(Load <t> _ _) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
+(Load <t> _ _) && t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t) ->
   (StructMake0)
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && fe.CanSSA(t) ->
   (StructMake1
-    (Load <t.FieldType(0)> ptr mem))
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t) ->
+    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem))
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && fe.CanSSA(t) ->
   (StructMake2
-    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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) ->
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 3 && fe.CanSSA(t) ->
   (StructMake3
-    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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) ->
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 4 && fe.CanSSA(t) ->
   (StructMake4
-    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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) ->
+(StructSelect [i] x:(Load <t> ptr mem)) && !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 {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
 (Store dst (StructMake2 <t> f0 f1) mem) ->
-  (Store [t.FieldType(1).Size()]
+  (Store {t.FieldType(1)}
     (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
     f1
-    (Store [t.FieldType(0).Size()] dst f0 mem))
+    (Store {t.FieldType(0)}
+      (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
+        f0 mem))
 (Store dst (StructMake3 <t> f0 f1 f2) mem) ->
-  (Store [t.FieldType(2).Size()]
+  (Store {t.FieldType(2)}
     (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
     f2
-    (Store [t.FieldType(1).Size()]
+    (Store {t.FieldType(1)}
       (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
       f1
-      (Store [t.FieldType(0).Size()] dst f0 mem)))
+      (Store {t.FieldType(0)}
+        (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
+          f0 mem)))
 (Store dst (StructMake4 <t> f0 f1 f2 f3) mem) ->
-  (Store [t.FieldType(3).Size()]
+  (Store {t.FieldType(3)}
     (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
     f3
-    (Store [t.FieldType(2).Size()]
+    (Store {t.FieldType(2)}
       (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
       f2
-      (Store [t.FieldType(1).Size()]
+      (Store {t.FieldType(1)}
         (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
         f1
-        (Store [t.FieldType(0).Size()] dst f0 mem))))
+        (Store {t.FieldType(0)}
+          (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
+            f0 mem))))
 
 // Putting struct{*byte} and similar into direct interfaces.
 (IMake typ (StructMake1 val)) -> (IMake typ val)
 (StructSelect [0] x:(IData _)) -> x
 
 // un-SSAable values use mem->mem copies
-(Store [size] dst (Load <t> src mem) mem) && !config.fe.CanSSA(t) ->
-	(Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src mem)
-(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) ->
-	(Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src (VarDef {x} mem))
+(Store {t} dst (Load src mem) mem) && !fe.CanSSA(t.(*types.Type)) ->
+	(Move {t} [t.(*types.Type).Size()] dst src mem)
+(Store {t} dst (Load src mem) (VarDef {x} mem)) && !fe.CanSSA(t.(*types.Type)) ->
+	(Move {t} [t.(*types.Type).Size()] dst src (VarDef {x} mem))
 
 // array ops
 (ArraySelect (ArrayMake1 x)) -> x
@@ -751,11 +813,11 @@
 (Load <t> _ _) && t.IsArray() && t.NumElem() == 0 ->
   (ArrayMake0)
 
-(Load <t> ptr mem) && t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t) ->
+(Load <t> ptr mem) && t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t) ->
   (ArrayMake1 (Load <t.ElemType()> ptr mem))
 
 (Store _ (ArrayMake0) mem) -> mem
-(Store [size] dst (ArrayMake1 e) mem) -> (Store [size] dst e mem)
+(Store dst (ArrayMake1 e) mem) -> (Store {e.Type} dst e mem)
 
 (ArraySelect [0] (Load ptr mem)) -> (Load ptr mem)
 
@@ -770,19 +832,19 @@
 (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]))
+  (StringMake (ConstNil) (Const32 <typ.Int> [0]))
 (ConstString {s}) && config.PtrSize == 8 && s.(string) == "" ->
-  (StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
+  (StringMake (ConstNil) (Const64 <typ.Int> [0]))
 (ConstString {s}) && config.PtrSize == 4 && s.(string) != "" ->
   (StringMake
-    (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
+    (Addr <typ.BytePtr> {fe.StringData(s.(string))}
       (SB))
-    (Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+    (Const32 <typ.Int> [int64(len(s.(string)))]))
 (ConstString {s}) && config.PtrSize == 8 && s.(string) != "" ->
   (StringMake
-    (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
+    (Addr <typ.BytePtr> {fe.StringData(s.(string))}
       (SB))
-    (Const64 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+    (Const64 <typ.Int> [int64(len(s.(string)))]))
 
 // slice ops
 // Only a few slice rules are provided here.  See dec.rules for
@@ -798,19 +860,19 @@
 (ConstSlice) && config.PtrSize == 4 ->
   (SliceMake
     (ConstNil <v.Type.ElemType().PtrTo()>)
-    (Const32 <config.fe.TypeInt()> [0])
-    (Const32 <config.fe.TypeInt()> [0]))
+    (Const32 <typ.Int> [0])
+    (Const32 <typ.Int> [0]))
 (ConstSlice) && config.PtrSize == 8 ->
   (SliceMake
     (ConstNil <v.Type.ElemType().PtrTo()>)
-    (Const64 <config.fe.TypeInt()> [0])
-    (Const64 <config.fe.TypeInt()> [0]))
+    (Const64 <typ.Int> [0])
+    (Const64 <typ.Int> [0]))
 
 // interface ops
 (ConstInterface) ->
   (IMake
-    (ConstNil <config.fe.TypeBytePtr()>)
-    (ConstNil <config.fe.TypeBytePtr()>))
+    (ConstNil <typ.BytePtr>)
+    (ConstNil <typ.BytePtr>))
 
 (NilCheck (GetG mem) mem) -> mem
 
@@ -820,51 +882,50 @@
 
 // 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 <typ.BytePtr> {n} [off])
+    (Arg <typ.Int> {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 <typ.Int> {n} [off+config.PtrSize])
+    (Arg <typ.Int> {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 <typ.BytePtr> {n} [off])
+    (Arg <typ.BytePtr> {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 <typ.Float64> {n} [off])
+    (Arg <typ.Float64> {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 <typ.Float32> {n} [off])
+    (Arg <typ.Float32> {n} [off+4]))
 
-(Arg <t>) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
+(Arg <t>) && t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t) ->
   (StructMake0)
-(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 1 && 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) ->
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 2 && 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) ->
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 3 && 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) ->
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 4 && fe.CanSSA(t) ->
   (StructMake4
     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
     (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])
@@ -873,135 +934,427 @@
 
 (Arg <t>) && t.IsArray() && t.NumElem() == 0 ->
   (ArrayMake0)
-(Arg <t> {n} [off]) && t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t) ->
+(Arg <t> {n} [off]) && t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t) ->
   (ArrayMake1 (Arg <t.ElemType()> {n} [off]))
 
 // 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?
+// See ../magic.go for a detailed description of these algorithms.
 
-// 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 by power of 2.  Strength reduce to a shift.
+(Div8u  n (Const8  [c])) && isPowerOfTwo(c&0xff)       -> (Rsh8Ux64 n  (Const64 <typ.UInt64> [log2(c&0xff)]))
+(Div16u n (Const16 [c])) && isPowerOfTwo(c&0xffff)     -> (Rsh16Ux64 n (Const64 <typ.UInt64> [log2(c&0xffff)]))
+(Div32u n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (Rsh32Ux64 n (Const64 <typ.UInt64> [log2(c&0xffffffff)]))
+(Div64u n (Const64 [c])) && isPowerOfTwo(c)            -> (Rsh64Ux64 n (Const64 <typ.UInt64> [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)])
+// For 8-bit divides, we just do a direct 9-bit by 8-bit multiply.
+(Div8u x (Const8 [c])) && umagicOK(8, c) ->
+  (Trunc32to8
+    (Rsh32Ux64 <typ.UInt32>
+      (Mul32 <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(1<<8+umagic(8,c).m)])
+        (ZeroExt8to32 x))
+      (Const64 <typ.UInt64> [8+umagic(8,c).s])))
+
+// For 16-bit divides on 64-bit machines, we do a direct 17-bit by 16-bit multiply.
+(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 8 ->
+  (Trunc64to16
+    (Rsh64Ux64 <typ.UInt64>
+      (Mul64 <typ.UInt64>
+        (Const64 <typ.UInt64> [int64(1<<16+umagic(16,c).m)])
+        (ZeroExt16to64 x))
+      (Const64 <typ.UInt64> [16+umagic(16,c).s])))
+
+// For 16-bit divides on 32-bit machines
+(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && umagic(16,c).m&1 == 0 ->
+  (Trunc32to16
+    (Rsh32Ux64 <typ.UInt32>
+      (Mul32 <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(1<<15+umagic(16,c).m/2)])
+        (ZeroExt16to32 x))
+      (Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
+(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && c&1 == 0 ->
+  (Trunc32to16
+    (Rsh32Ux64 <typ.UInt32>
+      (Mul32 <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(1<<15+(umagic(16,c).m+1)/2)])
+        (Rsh32Ux64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [1])))
+      (Const64 <typ.UInt64> [16+umagic(16,c).s-2])))
+(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 ->
+  (Trunc32to16
+    (Rsh32Ux64 <typ.UInt32>
+      (Avg32u
+        (Lsh32x64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [16]))
+        (Mul32 <typ.UInt32>
+          (Const32 <typ.UInt32> [int64(umagic(16,c).m)])
+          (ZeroExt16to32 x)))
+      (Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
+
+// For 32-bit divides on 32-bit machines
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && umagic(32,c).m&1 == 0 ->
+  (Rsh32Ux64 <typ.UInt32>
+    (Hmul32u <typ.UInt32>
+      (Const32 <typ.UInt32> [int64(int32(1<<31+umagic(32,c).m/2))])
       x)
-    (Const64 <t> [umagic64s(c)]))
-(Div64u <t> x (Const64 [c])) && umagic64ok(c) && umagic64a(c) ->
-  (Rsh64Ux64
-    (Avg64u <t>
-      (Hmul64u <t>
-        x
-        (Const64 <t> [umagic64m(c)]))
+    (Const64 <typ.UInt64> [umagic(32,c).s-1]))
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && c&1 == 0 ->
+  (Rsh32Ux64 <typ.UInt32>
+    (Hmul32u <typ.UInt32>
+      (Const32 <typ.UInt32> [int64(int32(1<<31+(umagic(32,c).m+1)/2))])
+      (Rsh32Ux64 <typ.UInt32> x (Const64 <typ.UInt64> [1])))
+    (Const64 <typ.UInt64> [umagic(32,c).s-2]))
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 ->
+  (Rsh32Ux64 <typ.UInt32>
+    (Avg32u
+      x
+      (Hmul32u <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(int32(umagic(32,c).m))])
+        x))
+    (Const64 <typ.UInt64> [umagic(32,c).s-1]))
+
+// For 32-bit divides on 64-bit machines
+// We'll use a regular (non-hi) multiply for this case.
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && umagic(32,c).m&1 == 0 ->
+  (Trunc64to32
+    (Rsh64Ux64 <typ.UInt64>
+      (Mul64 <typ.UInt64>
+        (Const64 <typ.UInt64> [int64(1<<31+umagic(32,c).m/2)])
+        (ZeroExt32to64 x))
+      (Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && c&1 == 0 ->
+  (Trunc64to32
+    (Rsh64Ux64 <typ.UInt64>
+      (Mul64 <typ.UInt64>
+        (Const64 <typ.UInt64> [int64(1<<31+(umagic(32,c).m+1)/2)])
+        (Rsh64Ux64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [1])))
+      (Const64 <typ.UInt64> [32+umagic(32,c).s-2])))
+(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 ->
+  (Trunc64to32
+    (Rsh64Ux64 <typ.UInt64>
+      (Avg64u
+        (Lsh64x64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [32]))
+        (Mul64 <typ.UInt64>
+          (Const64 <typ.UInt32> [int64(umagic(32,c).m)])
+          (ZeroExt32to64 x)))
+      (Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
+
+// For 64-bit divides on 64-bit machines
+// (64-bit divides on 32-bit machines are lowered to a runtime call by the walk pass.)
+(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0 ->
+  (Rsh64Ux64 <typ.UInt64>
+    (Hmul64u <typ.UInt64>
+      (Const64 <typ.UInt64> [int64(1<<63+umagic(64,c).m/2)])
       x)
-    (Const64 <t> [umagic64s(c)-1]))
+    (Const64 <typ.UInt64> [umagic(64,c).s-1]))
+(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && c&1 == 0 ->
+  (Rsh64Ux64 <typ.UInt64>
+    (Hmul64u <typ.UInt64>
+      (Const64 <typ.UInt64> [int64(1<<63+(umagic(64,c).m+1)/2)])
+      (Rsh64Ux64 <typ.UInt64> x (Const64 <typ.UInt64> [1])))
+    (Const64 <typ.UInt64> [umagic(64,c).s-2]))
+(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 ->
+  (Rsh64Ux64 <typ.UInt64>
+    (Avg64u
+      x
+      (Hmul64u <typ.UInt64>
+        (Const64 <typ.UInt64> [int64(umagic(64,c).m)])
+        x))
+    (Const64 <typ.UInt64> [umagic(64,c).s-1]))
+
+// Signed divide by a negative constant.  Rewrite to divide by a positive constant.
+(Div8  <t> n (Const8  [c])) && c < 0 && c != -1<<7  -> (Neg8  (Div8  <t> n (Const8  <t> [-c])))
+(Div16 <t> n (Const16 [c])) && c < 0 && c != -1<<15 -> (Neg16 (Div16 <t> n (Const16 <t> [-c])))
+(Div32 <t> n (Const32 [c])) && c < 0 && c != -1<<31 -> (Neg32 (Div32 <t> n (Const32 <t> [-c])))
+(Div64 <t> n (Const64 [c])) && c < 0 && c != -1<<63 -> (Neg64 (Div64 <t> n (Const64 <t> [-c])))
+
+// Dividing by the most-negative number.  Result is always 0 except
+// if the input is also the most-negative number.
+// We can detect that using the sign bit of x & -x.
+(Div8  <t> x (Const8  [-1<<7 ])) -> (Rsh8Ux64  (And8  <t> x (Neg8  <t> x)) (Const64 <typ.UInt64> [7 ]))
+(Div16 <t> x (Const16 [-1<<15])) -> (Rsh16Ux64 (And16 <t> x (Neg16 <t> x)) (Const64 <typ.UInt64> [15]))
+(Div32 <t> x (Const32 [-1<<31])) -> (Rsh32Ux64 (And32 <t> x (Neg32 <t> x)) (Const64 <typ.UInt64> [31]))
+(Div64 <t> x (Const64 [-1<<63])) -> (Rsh64Ux64 (And64 <t> x (Neg64 <t> x)) (Const64 <typ.UInt64> [63]))
+
+// Signed divide by power of 2.
+// 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).
+(Div8  <t> n (Const8  [c])) && isPowerOfTwo(c) ->
+  (Rsh8x64
+    (Add8  <t> n (Rsh8Ux64  <t> (Rsh8x64  <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [ 8-log2(c)])))
+    (Const64 <typ.UInt64> [log2(c)]))
+(Div16 <t> n (Const16 [c])) && isPowerOfTwo(c) ->
+  (Rsh16x64
+    (Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [16-log2(c)])))
+    (Const64 <typ.UInt64> [log2(c)]))
+(Div32 <t> n (Const32 [c])) && isPowerOfTwo(c) ->
+  (Rsh32x64
+    (Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [32-log2(c)])))
+    (Const64 <typ.UInt64> [log2(c)]))
+(Div64 <t> n (Const64 [c])) && isPowerOfTwo(c) ->
+  (Rsh64x64
+    (Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [64-log2(c)])))
+    (Const64 <typ.UInt64> [log2(c)]))
 
 // Signed divide, not a power of 2.  Strength reduce to a multiply.
-(Div64 <t> x (Const64 [c])) && c > 0 && smagic64ok(c) && smagic64m(c) > 0 ->
+(Div8 <t> x (Const8 [c])) && smagicOK(8,c) ->
+  (Sub8 <t>
+    (Rsh32x64 <t>
+      (Mul32 <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(smagic(8,c).m)])
+        (SignExt8to32 x))
+      (Const64 <typ.UInt64> [8+smagic(8,c).s]))
+    (Rsh32x64 <t>
+      (SignExt8to32 x)
+      (Const64 <typ.UInt64> [31])))
+(Div16 <t> x (Const16 [c])) && smagicOK(16,c) ->
+  (Sub16 <t>
+    (Rsh32x64 <t>
+      (Mul32 <typ.UInt32>
+        (Const32 <typ.UInt32> [int64(smagic(16,c).m)])
+        (SignExt16to32 x))
+      (Const64 <typ.UInt64> [16+smagic(16,c).s]))
+    (Rsh32x64 <t>
+      (SignExt16to32 x)
+      (Const64 <typ.UInt64> [31])))
+(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 8 ->
+  (Sub32 <t>
+    (Rsh64x64 <t>
+      (Mul64 <typ.UInt64>
+        (Const64 <typ.UInt64> [int64(smagic(32,c).m)])
+        (SignExt32to64 x))
+      (Const64 <typ.UInt64> [32+smagic(32,c).s]))
+    (Rsh64x64 <t>
+      (SignExt32to64 x)
+      (Const64 <typ.UInt64> [63])))
+(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 == 0 ->
+  (Sub32 <t>
+    (Rsh32x64 <t>
+      (Hmul32 <t>
+        (Const32 <typ.UInt32> [int64(int32(smagic(32,c).m/2))])
+        x)
+      (Const64 <typ.UInt64> [smagic(32,c).s-1]))
+    (Rsh32x64 <t>
+      x
+      (Const64 <typ.UInt64> [31])))
+(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 != 0 ->
+  (Sub32 <t>
+    (Rsh32x64 <t>
+      (Add32 <t>
+        (Hmul32 <t>
+          (Const32 <typ.UInt32> [int64(int32(smagic(32,c).m))])
+          x)
+        x)
+      (Const64 <typ.UInt64> [smagic(32,c).s]))
+    (Rsh32x64 <t>
+      x
+      (Const64 <typ.UInt64> [31])))
+(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 == 0 ->
   (Sub64 <t>
     (Rsh64x64 <t>
       (Hmul64 <t>
-        (Const64 <t> [smagic64m(c)])
+        (Const64 <typ.UInt64> [int64(smagic(64,c).m/2)])
         x)
-      (Const64 <t> [smagic64s(c)]))
+      (Const64 <typ.UInt64> [smagic(64,c).s-1]))
     (Rsh64x64 <t>
       x
-      (Const64 <t> [63])))
-(Div64 <t> x (Const64 [c])) && c > 0 && smagic64ok(c) && smagic64m(c) < 0 ->
+      (Const64 <typ.UInt64> [63])))
+(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 != 0 ->
   (Sub64 <t>
     (Rsh64x64 <t>
       (Add64 <t>
         (Hmul64 <t>
-          (Const64 <t> [smagic64m(c)])
+          (Const64 <typ.UInt64> [int64(smagic(64,c).m)])
           x)
         x)
-      (Const64 <t> [smagic64s(c)]))
+      (Const64 <typ.UInt64> [smagic(64,c).s]))
     (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]))))
+      (Const64 <typ.UInt64> [63])))
 
-// A%B = A-(A/B*B).
+// Unsigned mod by power of 2 constant.
+(Mod8u  <t> n (Const8  [c])) && isPowerOfTwo(c&0xff)       -> (And8 n (Const8 <t> [(c&0xff)-1]))
+(Mod16u <t> n (Const16 [c])) && isPowerOfTwo(c&0xffff)     -> (And16 n (Const16 <t> [(c&0xffff)-1]))
+(Mod32u <t> n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (And32 n (Const32 <t> [(c&0xffffffff)-1]))
+(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c)            -> (And64 n (Const64 <t> [c-1]))
+
+// Signed mod by negative constant.
+(Mod8  <t> n (Const8  [c])) && c < 0 && c != -1<<7  -> (Mod8  <t> n (Const8  <t> [-c]))
+(Mod16 <t> n (Const16 [c])) && c < 0 && c != -1<<15 -> (Mod16 <t> n (Const16 <t> [-c]))
+(Mod32 <t> n (Const32 [c])) && c < 0 && c != -1<<31 -> (Mod32 <t> n (Const32 <t> [-c]))
+(Mod64 <t> n (Const64 [c])) && c < 0 && c != -1<<63 -> (Mod64 <t> n (Const64 <t> [-c]))
+
+// All other mods by constants, do 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)
+(Mod8   <t> x (Const8  [c])) && x.Op != OpConst8  && (c > 0 || c == -1<<7)
+  -> (Sub8  x (Mul8  <t> (Div8   <t> x (Const8  <t> [c])) (Const8  <t> [c])))
+(Mod16  <t> x (Const16 [c])) && x.Op != OpConst16 && (c > 0 || c == -1<<15)
+  -> (Sub16 x (Mul16 <t> (Div16  <t> x (Const16 <t> [c])) (Const16 <t> [c])))
+(Mod32  <t> x (Const32 [c])) && x.Op != OpConst32 && (c > 0 || c == -1<<31)
+  -> (Sub32 x (Mul32 <t> (Div32  <t> x (Const32 <t> [c])) (Const32 <t> [c])))
+(Mod64  <t> x (Const64 [c])) && x.Op != OpConst64 && (c > 0 || c == -1<<63)
   -> (Sub64 x (Mul64 <t> (Div64  <t> x (Const64 <t> [c])) (Const64 <t> [c])))
-(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && umagic64ok(c)
+(Mod8u  <t> x (Const8  [c])) && x.Op != OpConst8  && c > 0 && umagicOK(8 ,c)
+  -> (Sub8  x (Mul8  <t> (Div8u  <t> x (Const8  <t> [c])) (Const8  <t> [c])))
+(Mod16u <t> x (Const16 [c])) && x.Op != OpConst16 && c > 0 && umagicOK(16,c)
+  -> (Sub16 x (Mul16 <t> (Div16u <t> x (Const16 <t> [c])) (Const16 <t> [c])))
+(Mod32u <t> x (Const32 [c])) && x.Op != OpConst32 && c > 0 && umagicOK(32,c)
+  -> (Sub32 x (Mul32 <t> (Div32u <t> x (Const32 <t> [c])) (Const32 <t> [c])))
+(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && c > 0 && umagicOK(64,c)
   -> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
 
+// Reassociate expressions involving
+// constants such that constants come first,
+// exposing obvious constant-folding opportunities.
+// Reassociate (op (op y C) x) to (op C (op x y)) or similar, where C
+// is constant, which pushes constants to the outside
+// of the expression. At that point, any constant-folding
+// opportunities should be obvious.
+
+// x + (C + z) -> C + (x + z)
+(Add64 (Add64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Add64 <t> z x))
+(Add32 (Add32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Add32 <t> z x))
+(Add16 (Add16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Add16 <t> z x))
+(Add8  (Add8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Add8  i (Add8  <t> z x))
+
+// x + (C - z) -> C + (x - z)
+(Add64 (Sub64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
+(Add32 (Sub32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
+(Add16 (Sub16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
+(Add8  (Sub8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Add8  i (Sub8  <t> x z))
+(Add64 x (Sub64 i:(Const64 <t>) z)) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
+(Add32 x (Sub32 i:(Const32 <t>) z)) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
+(Add16 x (Sub16 i:(Const16 <t>) z)) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
+(Add8  x (Sub8  i:(Const8  <t>) z)) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Add8  i (Sub8  <t> x z))
+
+// x + (z - C) -> (x + z) - C
+(Add64 (Sub64 z i:(Const64 <t>)) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
+(Add32 (Sub32 z i:(Const32 <t>)) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
+(Add16 (Sub16 z i:(Const16 <t>)) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
+(Add8  (Sub8  z i:(Const8  <t>)) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Sub8  (Add8  <t> x z) i)
+(Add64 x (Sub64 z i:(Const64 <t>))) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
+(Add32 x (Sub32 z i:(Const32 <t>))) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
+(Add16 x (Sub16 z i:(Const16 <t>))) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
+(Add8  x (Sub8  z i:(Const8  <t>))) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Sub8  (Add8  <t> x z) i)
+
+// x - (C - z) -> x + (z - C) -> (x + z) - C
+(Sub64 x (Sub64 i:(Const64 <t>) z)) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
+(Sub32 x (Sub32 i:(Const32 <t>) z)) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
+(Sub16 x (Sub16 i:(Const16 <t>) z)) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
+(Sub8  x (Sub8  i:(Const8  <t>) z)) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Sub8  (Add8  <t> x z) i)
+
+// x - (z - C) -> x + (C - z) -> (x - z) + C
+(Sub64 x (Sub64 z i:(Const64 <t>))) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
+(Sub32 x (Sub32 z i:(Const32 <t>))) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
+(Sub16 x (Sub16 z i:(Const16 <t>))) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
+(Sub8  x (Sub8  z i:(Const8  <t>))) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Add8  i (Sub8  <t> x z))
+
+// x & (C & z) -> C & (x & z)
+(And64 (And64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (And64 i (And64 <t> z x))
+(And32 (And32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (And32 i (And32 <t> z x))
+(And16 (And16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (And16 i (And16 <t> z x))
+(And8  (And8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (And8  i (And8  <t> z x))
+
+// x | (C | z) -> C | (x | z)
+(Or64 (Or64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Or64 i (Or64 <t> z x))
+(Or32 (Or32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Or32 i (Or32 <t> z x))
+(Or16 (Or16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Or16 i (Or16 <t> z x))
+(Or8  (Or8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Or8  i (Or8  <t> z x))
+
+// x ^ (C ^ z) -> C ^ (x ^ z)
+(Xor64 (Xor64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Xor64 i (Xor64 <t> z x))
+(Xor32 (Xor32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Xor32 i (Xor32 <t> z x))
+(Xor16 (Xor16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Xor16 i (Xor16 <t> z x))
+(Xor8  (Xor8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  -> (Xor8  i (Xor8  <t> z x))
+
+// C + (D + x) -> (C + D) + x
+(Add64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Add64 (Const64 <t> [c+d]) x)
+(Add32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Add32 (Const32 <t> [int64(int32(c+d))]) x)
+(Add16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Add16 (Const16 <t> [int64(int16(c+d))]) x)
+(Add8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x)) -> (Add8  (Const8  <t> [int64(int8(c+d))]) x)
+
+// C + (D - x) -> (C + D) - x
+(Add64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x)) -> (Sub64 (Const64 <t> [c+d]) x)
+(Add32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x)) -> (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
+(Add16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) -> (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
+(Add8  (Const8  <t> [c]) (Sub8  (Const8  <t> [d]) x)) -> (Sub8  (Const8  <t> [int64(int8(c+d))]) x)
+
+// C + (x - D) -> (C - D) + x
+(Add64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d]))) -> (Add64 (Const64 <t> [c-d]) x)
+(Add32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d]))) -> (Add32 (Const32 <t> [int64(int32(c-d))]) x)
+(Add16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) -> (Add16 (Const16 <t> [int64(int16(c-d))]) x)
+(Add8  (Const8  <t> [c]) (Sub8  x (Const8  <t> [d]))) -> (Add8  (Const8  <t> [int64(int8(c-d))]) x)
+
+// C - (x - D) -> (C + D) - x
+(Sub64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d]))) -> (Sub64 (Const64 <t> [c+d]) x)
+(Sub32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d]))) -> (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
+(Sub16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) -> (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
+(Sub8  (Const8  <t> [c]) (Sub8  x (Const8  <t> [d]))) -> (Sub8  (Const8  <t> [int64(int8(c+d))]) x)
+
+// C - (D - x) -> (C - D) + x
+(Sub64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x)) -> (Add64 (Const64 <t> [c-d]) x)
+(Sub32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x)) -> (Add32 (Const32 <t> [int64(int32(c-d))]) x)
+(Sub16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) -> (Add16 (Const16 <t> [int64(int16(c-d))]) x)
+(Sub8  (Const8  <t> [c]) (Sub8  (Const8  <t> [d]) x)) -> (Add8  (Const8  <t> [int64(int8(c-d))]) x)
+
+// C & (D & x) -> (C & D) & x
+(And64 (Const64 <t> [c]) (And64 (Const64 <t> [d]) x)) -> (And64 (Const64 <t> [c&d]) x)
+(And32 (Const32 <t> [c]) (And32 (Const32 <t> [d]) x)) -> (And32 (Const32 <t> [int64(int32(c&d))]) x)
+(And16 (Const16 <t> [c]) (And16 (Const16 <t> [d]) x)) -> (And16 (Const16 <t> [int64(int16(c&d))]) x)
+(And8  (Const8  <t> [c]) (And8  (Const8  <t> [d]) x)) -> (And8  (Const8  <t> [int64(int8(c&d))]) x)
+
+// C | (D | x) -> (C | D) | x
+(Or64 (Const64 <t> [c]) (Or64 (Const64 <t> [d]) x)) -> (Or64 (Const64 <t> [c|d]) x)
+(Or32 (Const32 <t> [c]) (Or32 (Const32 <t> [d]) x)) -> (Or32 (Const32 <t> [int64(int32(c|d))]) x)
+(Or16 (Const16 <t> [c]) (Or16 (Const16 <t> [d]) x)) -> (Or16 (Const16 <t> [int64(int16(c|d))]) x)
+(Or8  (Const8  <t> [c]) (Or8  (Const8  <t> [d]) x)) -> (Or8  (Const8  <t> [int64(int8(c|d))]) x)
+
+// C ^ (D ^ x) -> (C ^ D) ^ x
+(Xor64 (Const64 <t> [c]) (Xor64 (Const64 <t> [d]) x)) -> (Xor64 (Const64 <t> [c^d]) x)
+(Xor32 (Const32 <t> [c]) (Xor32 (Const32 <t> [d]) x)) -> (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
+(Xor16 (Const16 <t> [c]) (Xor16 (Const16 <t> [d]) x)) -> (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
+(Xor8  (Const8  <t> [c]) (Xor8  (Const8  <t> [d]) x)) -> (Xor8  (Const8  <t> [int64(int8(c^d))]) x)
+
+// C * (D * x) = (C * D) * x
+(Mul64 (Const64 <t> [c]) (Mul64 (Const64 <t> [d]) x)) -> (Mul64 (Const64 <t> [c*d]) x)
+(Mul32 (Const32 <t> [c]) (Mul32 (Const32 <t> [d]) x)) -> (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
+(Mul16 (Const16 <t> [c]) (Mul16 (Const16 <t> [d]) x)) -> (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
+(Mul8  (Const8  <t> [c]) (Mul8  (Const8  <t> [d]) x)) -> (Mul8  (Const8  <t> [int64(int8(c*d))]) x)
+
 // floating point optimizations
 (Add32F x (Const32F [0])) -> x
-(Add32F (Const32F [0]) x) -> x
 (Add64F x (Const64F [0])) -> x
-(Add64F (Const64F [0]) x) -> x
 (Sub32F x (Const32F [0])) -> x
 (Sub64F x (Const64F [0])) -> x
 (Mul32F x (Const32F [f2i(1)])) -> x
-(Mul32F (Const32F [f2i(1)]) x) -> x
 (Mul64F x (Const64F [f2i(1)])) -> x
-(Mul64F (Const64F [f2i(1)]) x) -> x
 (Mul32F x (Const32F [f2i(-1)])) -> (Neg32F x)
-(Mul32F (Const32F [f2i(-1)]) x) -> (Neg32F x)
 (Mul64F x (Const64F [f2i(-1)])) -> (Neg64F x)
-(Mul64F (Const64F [f2i(-1)]) x) -> (Neg64F x)
-(Div32F x (Const32F [f2i(1)])) -> x
-(Div64F x (Const64F [f2i(1)])) -> x
-(Div32F x (Const32F [f2i(-1)])) -> (Neg32F x)
-(Div64F x (Const64F [f2i(-1)])) -> (Neg32F x)
+(Mul32F x (Const32F [f2i(2)])) -> (Add32F x x)
+(Mul64F x (Const64F [f2i(2)])) -> (Add64F x x)
+(Div32F x (Const32F <t> [c])) && reciprocalExact32(float32(i2f(c))) -> (Mul32F x (Const32F <t> [f2i(1/i2f(c))]))
+(Div64F x (Const64F <t> [c])) && reciprocalExact64(i2f(c))          -> (Mul64F x (Const64F <t> [f2i(1/i2f(c))]))
 
 (Sqrt (Const64F [c])) -> (Const64F [f2i(math.Sqrt(i2f(c)))])
 
 // recognize runtime.newobject and don't Zero/Nilcheck it
 (Zero (Load (OffPtr [c] (SP)) mem) mem)
-        && mem.Op == OpStaticCall
+	&& mem.Op == OpStaticCall
 	&& isSameSym(mem.Aux, "runtime.newobject")
-	&& c == config.ctxt.FixedFrameSize() + config.PtrSize // offset of return value
+	&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
+	-> mem
+(Store (Load (OffPtr [c] (SP)) mem) x mem)
+	&& isConstZero(x)
+	&& mem.Op == OpStaticCall
+	&& isSameSym(mem.Aux, "runtime.newobject")
+	&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
+	-> mem
+(Store (OffPtr (Load (OffPtr [c] (SP)) mem)) x mem)
+	&& isConstZero(x)
+	&& mem.Op == OpStaticCall
+	&& isSameSym(mem.Aux, "runtime.newobject")
+	&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
 	-> mem
 // nil checks just need to rewrite to something useless.
 // they will be deadcode eliminated soon afterwards.
@@ -1009,11 +1362,22 @@
 	&& mem.Op == OpStaticCall
 	&& isSameSym(mem.Aux, "runtime.newobject")
 	&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
-	&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
+	&& warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
 	-> (Invalid)
 (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
 	&& mem.Op == OpStaticCall
 	&& isSameSym(mem.Aux, "runtime.newobject")
 	&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
-	&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
+	&& warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
 	-> (Invalid)
+
+// Address comparison shows up in type assertions.
+(EqPtr x x) -> (ConstBool [1])
+(EqPtr (Addr {a} x) (Addr {b} x)) -> (ConstBool [b2i(a == b)])
+
+// De-virtualize interface calls into static calls.
+// Note that (ITab (IMake)) doesn't get
+// rewritten until after the first opt pass,
+// so this rule should trigger reliably.
+(InterCall [argsize] (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) mem) && devirt(v, itab, off) != nil ->
+	(StaticCall [argsize] {devirt(v, itab, off)} mem)
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index b1689df..d962e4a 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -28,8 +28,8 @@ var genericOps = []opData{
 	{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: "Add32F", argLength: 2, commutative: true},
+	{name: "Add64F", argLength: 2, commutative: true},
 
 	{name: "Sub8", argLength: 2}, // arg0 - arg1
 	{name: "Sub16", argLength: 2},
@@ -43,26 +43,27 @@ var genericOps = []opData{
 	{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: "Mul32F", argLength: 2, commutative: true},
+	{name: "Mul64F", argLength: 2, commutative: true},
 
 	{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},
+	{name: "Hmul32", argLength: 2, commutative: true},
+	{name: "Hmul32u", argLength: 2, commutative: true},
+	{name: "Hmul64", argLength: 2, commutative: true},
+	{name: "Hmul64u", argLength: 2, commutative: true},
 
-	{name: "Mul32uhilo", argLength: 2, typ: "(UInt32,UInt32)"}, // arg0 * arg1, returns (hi, lo)
-	{name: "Mul64uhilo", argLength: 2, typ: "(UInt64,UInt64)"}, // arg0 * arg1, returns (hi, lo)
+	{name: "Mul32uhilo", argLength: 2, typ: "(UInt32,UInt32)", commutative: true}, // arg0 * arg1, returns (hi, lo)
+	{name: "Mul64uhilo", argLength: 2, typ: "(UInt64,UInt64)", commutative: true}, // arg0 * arg1, returns (hi, lo)
 
-	// Weird special instruction for strength reduction of divides.
-	{name: "Avg64u", argLength: 2}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
+	// Weird special instructions for use in the strength reduction of divides.
+	// These ops compute unsigned (arg0 + arg1) / 2, correct to all
+	// 32/64 bits, even when the intermediate result of the add has 33/65 bits.
+	// These ops can assume arg0 >= arg1.
+	// Note: these ops aren't commutative!
+	{name: "Avg32u", argLength: 2, typ: "UInt32"}, // 32-bit platforms only
+	{name: "Avg64u", argLength: 2, typ: "UInt64"}, // 64-bit platforms only
 
 	{name: "Div8", argLength: 2},  // arg0 / arg1, signed
 	{name: "Div8u", argLength: 2}, // arg0 / arg1, unsigned
@@ -151,31 +152,6 @@ var genericOps = []opData{
 	{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, typ: "Bool"}, // arg0 == arg1
 	{name: "Eq16", argLength: 2, commutative: true, typ: "Bool"},
@@ -184,8 +160,8 @@ var genericOps = []opData{
 	{name: "EqPtr", argLength: 2, commutative: true, typ: "Bool"},
 	{name: "EqInter", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
 	{name: "EqSlice", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
-	{name: "Eq32F", argLength: 2, typ: "Bool"},
-	{name: "Eq64F", argLength: 2, typ: "Bool"},
+	{name: "Eq32F", argLength: 2, commutative: true, typ: "Bool"},
+	{name: "Eq64F", argLength: 2, commutative: true, typ: "Bool"},
 
 	{name: "Neq8", argLength: 2, commutative: true, typ: "Bool"}, // arg0 != arg1
 	{name: "Neq16", argLength: 2, commutative: true, typ: "Bool"},
@@ -194,8 +170,8 @@ var genericOps = []opData{
 	{name: "NeqPtr", argLength: 2, commutative: true, typ: "Bool"},
 	{name: "NeqInter", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
 	{name: "NeqSlice", argLength: 2, typ: "Bool"}, // arg0 or arg1 is nil; other cases handled by frontend
-	{name: "Neq32F", argLength: 2, typ: "Bool"},
-	{name: "Neq64F", argLength: 2},
+	{name: "Neq32F", argLength: 2, commutative: true, typ: "Bool"},
+	{name: "Neq64F", argLength: 2, commutative: true, typ: "Bool"},
 
 	{name: "Less8", argLength: 2, typ: "Bool"},  // arg0 < arg1, signed
 	{name: "Less8U", argLength: 2, typ: "Bool"}, // arg0 < arg1, unsigned
@@ -242,11 +218,11 @@ var genericOps = []opData{
 	{name: "Geq64F", argLength: 2, typ: "Bool"},
 
 	// boolean ops
-	{name: "AndB", argLength: 2, typ: "Bool"}, // arg0 && arg1 (not shortcircuited)
-	{name: "OrB", argLength: 2, typ: "Bool"},  // arg0 || arg1 (not shortcircuited)
-	{name: "EqB", argLength: 2, typ: "Bool"},  // arg0 == arg1
-	{name: "NeqB", argLength: 2, typ: "Bool"}, // arg0 != arg1
-	{name: "Not", argLength: 1, typ: "Bool"},  // !arg0, boolean
+	{name: "AndB", argLength: 2, commutative: true, typ: "Bool"}, // arg0 && arg1 (not shortcircuited)
+	{name: "OrB", argLength: 2, commutative: true, typ: "Bool"},  // arg0 || arg1 (not shortcircuited)
+	{name: "EqB", argLength: 2, commutative: true, typ: "Bool"},  // arg0 == arg1
+	{name: "NeqB", argLength: 2, commutative: true, typ: "Bool"}, // arg0 != arg1
+	{name: "Not", argLength: 1, typ: "Bool"},                     // !arg0, boolean
 
 	// 1-input ops
 	{name: "Neg8", argLength: 1}, // -arg0
@@ -261,12 +237,24 @@ var genericOps = []opData{
 	{name: "Com32", argLength: 1},
 	{name: "Com64", argLength: 1},
 
-	{name: "Ctz32", argLength: 1}, // Count trailing (low  order) zeroes (returns 0-32)
-	{name: "Ctz64", argLength: 1}, // Count trailing zeroes (returns 0-64)
+	{name: "Ctz32", argLength: 1},    // Count trailing (low order) zeroes (returns 0-32)
+	{name: "Ctz64", argLength: 1},    // Count trailing zeroes (returns 0-64)
+	{name: "BitLen32", argLength: 1}, // Number of bits in arg[0] (returns 0-32)
+	{name: "BitLen64", argLength: 1}, // Number of bits in arg[0] (returns 0-64)
 
 	{name: "Bswap32", argLength: 1}, // Swap bytes
 	{name: "Bswap64", argLength: 1}, // Swap bytes
 
+	{name: "BitRev8", argLength: 1},  // Reverse the bits in arg[0]
+	{name: "BitRev16", argLength: 1}, // Reverse the bits in arg[0]
+	{name: "BitRev32", argLength: 1}, // Reverse the bits in arg[0]
+	{name: "BitRev64", argLength: 1}, // Reverse the bits in arg[0]
+
+	{name: "PopCount8", argLength: 1},  // Count bits in arg[0]
+	{name: "PopCount16", argLength: 1}, // Count bits in arg[0]
+	{name: "PopCount32", argLength: 1}, // Count bits in arg[0]
+	{name: "PopCount64", argLength: 1}, // Count bits in arg[0]
+
 	{name: "Sqrt", argLength: 1}, // sqrt(arg0), float64 only
 
 	// Data movement, max argument length for Phi is indefinite so just pick
@@ -288,48 +276,46 @@ var genericOps = []opData{
 	{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
+	// Note: ConstX are sign-extended even when the type of the value is unsigned.
+	// For instance, uint8(0xaa) is stored as auxint=0xffffffffffffffaa.
+	{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.
+	{name: "InitMem"},                               // memory input to the function.
+	{name: "Arg", aux: "SymOff", symEffect: "None"}, // 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: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // 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
 	{name: "Invalid"},            // unused value
 
 	// 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, typ: "Mem", aux: "SizeAndAlign"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment.  Returns memory.
-	{name: "Zero", argLength: 2, typ: "Mem", aux: "SizeAndAlign"}, // arg0=destptr, arg1=mem, auxint=size+alignment. Returns memory.
+	{name: "Load", argLength: 2},                             // Load from arg0.  arg1=memory
+	{name: "Store", argLength: 3, typ: "Mem", aux: "Typ"},    // Store arg1 to arg0.  arg2=memory, aux=type.  Returns memory.
+	{name: "Move", argLength: 3, typ: "Mem", aux: "TypSize"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size, aux=type.  Returns memory.
+	{name: "Zero", argLength: 2, typ: "Mem", aux: "TypSize"}, // arg0=destptr, arg1=mem, auxint=size, aux=type. Returns memory.
 
 	// Memory operations with write barriers.
 	// Expand to runtime calls. Write barrier will be removed if write on stack.
-	{name: "StoreWB", argLength: 3, typ: "Mem", aux: "Int64"},                  // Store arg1 to arg0. arg2=memory, auxint=size.  Returns memory.
-	{name: "MoveWB", argLength: 3, typ: "Mem", aux: "SymSizeAndAlign"},         // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment, aux=symbol-of-type (for typedmemmove).  Returns memory.
-	{name: "MoveWBVolatile", argLength: 3, typ: "Mem", aux: "SymSizeAndAlign"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size+alignment, aux=symbol-of-type (for typedmemmove).  Returns memory. Src is volatile, i.e. needs to move to a temp space before calling typedmemmove.
-	{name: "ZeroWB", argLength: 2, typ: "Mem", aux: "SymSizeAndAlign"},         // arg0=destptr, arg1=mem, auxint=size+alignment, aux=symbol-of-type. Returns memory.
+	{name: "StoreWB", argLength: 3, typ: "Mem", aux: "Typ"},    // Store arg1 to arg0. arg2=memory, aux=type.  Returns memory.
+	{name: "MoveWB", argLength: 3, typ: "Mem", aux: "TypSize"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size, aux=type.  Returns memory.
+	{name: "ZeroWB", argLength: 2, typ: "Mem", aux: "TypSize"}, // arg0=destptr, arg1=mem, auxint=size, aux=type. 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", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory.  auxint=arg size.  Returns memory.
-	{name: "StaticCall", argLength: 1, aux: "SymOff", call: true}, // call function aux.(*gc.Sym), arg0=memory.  auxint=arg size.  Returns memory.
-	{name: "DeferCall", argLength: 1, aux: "Int64", call: true},   // defer call.  arg0=memory, auxint=arg size.  Returns memory.
-	{name: "GoCall", argLength: 1, aux: "Int64", call: true},      // go call.  arg0=memory, auxint=arg size.  Returns memory.
-	{name: "InterCall", argLength: 2, aux: "Int64", call: true},   // interface call.  arg0=code pointer, arg1=memory, auxint=arg size.  Returns memory.
+	{name: "ClosureCall", argLength: 3, aux: "Int64", call: true},                    // arg0=code pointer, arg1=context ptr, arg2=memory.  auxint=arg size.  Returns memory.
+	{name: "StaticCall", argLength: 1, aux: "SymOff", call: true, symEffect: "None"}, // call function aux.(*obj.LSym), arg0=memory.  auxint=arg size.  Returns memory.
+	{name: "InterCall", argLength: 2, aux: "Int64", call: true},                      // 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"},
@@ -362,6 +348,10 @@ var genericOps = []opData{
 	{name: "Cvt32Fto64F", argLength: 1},
 	{name: "Cvt64Fto32F", argLength: 1},
 
+	// Force rounding to precision of type.
+	{name: "Round32F", argLength: 1},
+	{name: "Round64F", 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.
@@ -418,15 +408,15 @@ var genericOps = []opData{
 	{name: "LoadReg", argLength: 1},
 
 	// Used during ssa construction. Like Copy, but the arg has not been specified yet.
-	{name: "FwdRef", aux: "Sym"},
+	{name: "FwdRef", aux: "Sym", symEffect: "None"},
 
 	// 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
+	{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem", symEffect: "None"}, // aux is a *gc.Node of a variable that is about to be initialized.  arg0=mem, returns mem
+	{name: "VarKill", argLength: 1, aux: "Sym", symEffect: "None"},            // aux is a *gc.Node of a variable that is known to be dead.  arg0=mem, returns mem
+	{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "None"},            // 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
 
 	// Ops for breaking 64-bit operations on 32-bit architectures
 	{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
@@ -474,6 +464,9 @@ var genericOps = []opData{
 	{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2.  Returns true iff store happens and new memory.
 	{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true},                    // *arg0 &= arg1.  arg2=memory.  Returns memory.
 	{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true},                     // *arg0 |= arg1.  arg2=memory.  Returns memory.
+
+	// Clobber experiment op
+	{name: "Clobber", argLength: 0, typ: "Void", aux: "SymOff", symEffect: "None"}, // write an invalid pointer value to the given pointer slot of a stack variable
 }
 
 //     kind           control    successors       implicit exit
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
index 19b904a..ea6fa87 100644
--- a/src/cmd/compile/internal/ssa/gen/main.go
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -18,6 +18,7 @@ import (
 	"path"
 	"regexp"
 	"sort"
+	"strings"
 )
 
 type arch struct {
@@ -42,17 +43,18 @@ type opData struct {
 	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 on its first 2 arguments (e.g. addition)
-	resultInArg0      bool  // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
-	resultNotInArgs   bool  // outputs must not be allocated to the same registers as inputs
-	clobberFlags      bool  // this op clobbers flags register
-	call              bool  // is a function call
-	nilCheck          bool  // this op is a nil check on arg0
-	faultOnNilArg0    bool  // this op will fault if arg0 is nil (and aux encodes a small offset)
-	faultOnNilArg1    bool  // this op will fault if arg1 is nil (and aux encodes a small offset)
-	usesScratch       bool  // this op requires scratch memory space
-	hasSideEffects    bool  // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
+	argLength         int32  // number of arguments, if -1, then this operation has a variable number of arguments
+	commutative       bool   // this operation is commutative on its first 2 arguments (e.g. addition)
+	resultInArg0      bool   // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
+	resultNotInArgs   bool   // outputs must not be allocated to the same registers as inputs
+	clobberFlags      bool   // this op clobbers flags register
+	call              bool   // is a function call
+	nilCheck          bool   // this op is a nil check on arg0
+	faultOnNilArg0    bool   // this op will fault if arg0 is nil (and aux encodes a small offset)
+	faultOnNilArg1    bool   // this op will fault if arg1 is nil (and aux encodes a small offset)
+	usesScratch       bool   // this op requires scratch memory space
+	hasSideEffects    bool   // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
+	symEffect         string // effect this op has on symbol in aux
 }
 
 type blockData struct {
@@ -93,8 +95,7 @@ func main() {
 
 func genOp() {
 	w := new(bytes.Buffer)
-	fmt.Fprintf(w, "// autogenerated: do not edit!\n")
-	fmt.Fprintf(w, "// generated from gen/*Ops.go\n")
+	fmt.Fprintf(w, "// Code generated from gen/*Ops.go; DO NOT EDIT.\n")
 	fmt.Fprintln(w)
 	fmt.Fprintln(w, "package ssa")
 
@@ -212,6 +213,15 @@ func genOp() {
 			if v.hasSideEffects {
 				fmt.Fprintln(w, "hasSideEffects: true,")
 			}
+			needEffect := strings.HasPrefix(v.aux, "Sym")
+			if v.symEffect != "" {
+				if !needEffect {
+					log.Fatalf("symEffect with aux %s not allowed", v.aux)
+				}
+				fmt.Fprintf(w, "symEffect: Sym%s,\n", v.symEffect)
+			} else if needEffect {
+				log.Fatalf("symEffect needed for aux %s", v.aux)
+			}
 			if a.name == "generic" {
 				fmt.Fprintln(w, "generic:true,")
 				fmt.Fprintln(w, "},") // close op
@@ -273,6 +283,9 @@ func genOp() {
 
 	fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }")
 
+	fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
+	fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
+
 	// generate registers
 	for _, a := range archs {
 		if a.generic {
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index f255f6b..4306f7e 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -30,7 +30,7 @@ import (
 //  sexpr [&& extra conditions] -> [@block] sexpr
 //
 // sexpr are s-expressions (lisp-like parenthesized groupings)
-// sexpr ::= (opcode sexpr*)
+// sexpr ::= [variable:](opcode sexpr*)
 //         | variable
 //         | <type>
 //         | [auxint]
@@ -39,7 +39,7 @@ import (
 // aux      ::= variable | {code}
 // type     ::= variable | {code}
 // variable ::= some token
-// opcode   ::= one of the opcodes from ../op.go (without the Op prefix)
+// opcode   ::= one of the opcodes from the *Ops.go files
 
 // 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
@@ -119,15 +119,17 @@ func genRules(arch arch) {
 		}
 
 		loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
-		r := Rule{rule: rule, loc: loc}
-		if rawop := strings.Split(rule, " ")[0][1:]; isBlock(rawop, arch) {
-			blockrules[rawop] = append(blockrules[rawop], r)
-		} else {
-			// Do fancier value op matching.
-			match, _, _ := r.parse()
-			op, oparch, _, _, _, _ := parseValue(match, arch, loc)
-			opname := fmt.Sprintf("Op%s%s", oparch, op.name)
-			oprules[opname] = append(oprules[opname], r)
+		for _, crule := range commute(rule, arch) {
+			r := Rule{rule: crule, loc: loc}
+			if rawop := strings.Split(crule, " ")[0][1:]; isBlock(rawop, arch) {
+				blockrules[rawop] = append(blockrules[rawop], r)
+			} else {
+				// Do fancier value op matching.
+				match, _, _ := r.parse()
+				op, oparch, _, _, _, _ := parseValue(match, arch, loc)
+				opname := fmt.Sprintf("Op%s%s", oparch, op.name)
+				oprules[opname] = append(oprules[opname], r)
+			}
 		}
 		rule = ""
 		ruleLineno = 0
@@ -148,19 +150,34 @@ func genRules(arch arch) {
 
 	// Start output buffer, write header.
 	w := new(bytes.Buffer)
-	fmt.Fprintf(w, "// autogenerated from gen/%s.rules: do not edit!\n", arch.name)
+	fmt.Fprintf(w, "// Code generated 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")
+	fmt.Fprintln(w, "import \"cmd/internal/obj\"")
+	fmt.Fprintln(w, "import \"cmd/internal/objabi\"")
+	fmt.Fprintln(w, "import \"cmd/compile/internal/types\"")
+	fmt.Fprintln(w, "var _ = math.MinInt8  // in case not otherwise used")
+	fmt.Fprintln(w, "var _ = obj.ANOP      // in case not otherwise used")
+	fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used")
+	fmt.Fprintln(w, "var _ = types.TypeMem // in case not otherwise used")
+	fmt.Fprintln(w)
 
+	const chunkSize = 10
 	// 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, "func rewriteValue%s(v *Value) bool {\n", arch.name)
 	fmt.Fprintf(w, "switch v.Op {\n")
 	for _, op := range ops {
 		fmt.Fprintf(w, "case %s:\n", op)
-		fmt.Fprintf(w, "return rewriteValue%s_%s(v, config)\n", arch.name, op)
+		fmt.Fprint(w, "return ")
+		for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
+			if chunk > 0 {
+				fmt.Fprint(w, " || ")
+			}
+			fmt.Fprintf(w, "rewriteValue%s_%s_%d(v)", arch.name, op, chunk)
+		}
+		fmt.Fprintln(w)
 	}
 	fmt.Fprintf(w, "}\n")
 	fmt.Fprintf(w, "return false\n")
@@ -169,47 +186,84 @@ func genRules(arch arch) {
 	// 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, op)
-		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
+		for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
+			buf := new(bytes.Buffer)
+			var canFail bool
+			endchunk := chunk + chunkSize
+			if endchunk > len(oprules[op]) {
+				endchunk = len(oprules[op])
 			}
+			for i, rule := range oprules[op][chunk:endchunk] {
+				match, cond, result := rule.parse()
+				fmt.Fprintf(buf, "// match: %s\n", match)
+				fmt.Fprintf(buf, "// cond: %s\n", cond)
+				fmt.Fprintf(buf, "// result: %s\n", result)
+
+				canFail = false
+				fmt.Fprintf(buf, "for {\n")
+				if genMatch(buf, arch, match, rule.loc) {
+					canFail = true
+				}
 
-			if cond != "" {
-				fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
-				canFail = true
+				if cond != "" {
+					fmt.Fprintf(buf, "if !(%s) {\nbreak\n}\n", cond)
+					canFail = true
+				}
+				if !canFail && i+chunk != len(oprules[op])-1 {
+					log.Fatalf("unconditional rule %s is followed by other rules", match)
+				}
+
+				genResult(buf, arch, result, rule.loc)
+				if *genLog {
+					fmt.Fprintf(buf, "logRule(\"%s\")\n", rule.loc)
+				}
+				fmt.Fprintf(buf, "return true\n")
+
+				fmt.Fprintf(buf, "}\n")
 			}
-			if !canFail && i != len(oprules[op])-1 {
-				log.Fatalf("unconditional rule %s is followed by other rules", match)
+			if canFail {
+				fmt.Fprintf(buf, "return false\n")
 			}
 
-			genResult(w, arch, result, rule.loc)
-			if *genLog {
-				fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
+			body := buf.String()
+			// Do a rough match to predict whether we need b, config, fe, and/or types.
+			// It's not precise--thus the blank assignments--but it's good enough
+			// to avoid generating needless code and doing pointless nil checks.
+			hasb := strings.Contains(body, "b.")
+			hasconfig := strings.Contains(body, "config.") || strings.Contains(body, "config)")
+			hasfe := strings.Contains(body, "fe.")
+			hastyps := strings.Contains(body, "typ.")
+			fmt.Fprintf(w, "func rewriteValue%s_%s_%d(v *Value) bool {\n", arch.name, op, chunk)
+			if hasb || hasconfig || hasfe || hastyps {
+				fmt.Fprintln(w, "b := v.Block")
+				fmt.Fprintln(w, "_ = b")
 			}
-			fmt.Fprintf(w, "return true\n")
-
+			if hasconfig {
+				fmt.Fprintln(w, "config := b.Func.Config")
+				fmt.Fprintln(w, "_ = config")
+			}
+			if hasfe {
+				fmt.Fprintln(w, "fe := b.Func.fe")
+				fmt.Fprintln(w, "_ = fe")
+			}
+			if hastyps {
+				fmt.Fprintln(w, "typ := &b.Func.Config.Types")
+				fmt.Fprintln(w, "_ = typ")
+			}
+			fmt.Fprint(w, body)
 			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, config *Config) bool {\n", arch.name)
+	fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
+	fmt.Fprintln(w, "config := b.Func.Config")
+	fmt.Fprintln(w, "_ = config")
+	fmt.Fprintln(w, "fe := b.Func.fe")
+	fmt.Fprintln(w, "_ = fe")
+	fmt.Fprintln(w, "typ := &config.Types")
+	fmt.Fprintln(w, "_ = typ")
 	fmt.Fprintf(w, "switch b.Kind {\n")
 	ops = nil
 	for op := range blockrules {
@@ -239,14 +293,6 @@ func genRules(arch arch) {
 				}
 			}
 
-			// 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)
 			}
@@ -256,6 +302,7 @@ func genRules(arch arch) {
 			newsuccs := t[2:]
 
 			// Check if newsuccs is the same set as succs.
+			succs := s[2:]
 			m := map[string]bool{}
 			for _, succ := range succs {
 				if m[succ] {
@@ -295,9 +342,6 @@ func genRules(arch arch) {
 				}
 				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)
@@ -398,6 +442,9 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
 		}
 	}
 
+	if n := len(args); n > 1 {
+		fmt.Fprintf(w, "_ = %s.Args[%d]\n", v, n-1) // combine some bounds checks
+	}
 	for i, arg := range args {
 		if arg == "_" {
 			continue
@@ -491,7 +538,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
 		}
 		v = fmt.Sprintf("v%d", *alloc)
 		*alloc++
-		fmt.Fprintf(w, "%s := b.NewValue0(v.Line, Op%s%s, %s)\n", v, oparch, op.name, typ)
+		fmt.Fprintf(w, "%s := b.NewValue0(v.Pos, Op%s%s, %s)\n", v, oparch, op.name, typ)
 		if move && top {
 			// Rewrite original into a copy
 			fmt.Fprintf(w, "v.reset(OpCopy)\n")
@@ -657,14 +704,14 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch string, ty
 	// Sanity check aux, auxint.
 	if auxint != "" {
 		switch op.aux {
-		case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "SizeAndAlign":
+		case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "TypSize":
 		default:
 			log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
 		}
 	}
 	if aux != "" {
 		switch op.aux {
-		case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+		case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32", "Typ", "TypSize":
 		default:
 			log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
 		}
@@ -689,13 +736,13 @@ func typeName(typ string) string {
 		if len(ts) != 2 {
 			panic("Tuple expect 2 arguments")
 		}
-		return "MakeTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
+		return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
 	}
 	switch typ {
 	case "Flags", "Mem", "Void", "Int128":
-		return "Type" + typ
+		return "types.Type" + typ
 	default:
-		return "config.fe.Type" + typ + "()"
+		return "typ." + typ
 	}
 }
 
@@ -721,3 +768,169 @@ func isVariable(s string) bool {
 	}
 	return b
 }
+
+// commute returns all equivalent rules to r after applying all possible
+// argument swaps to the commutable ops in r.
+// Potentially exponential, be careful.
+func commute(r string, arch arch) []string {
+	match, cond, result := Rule{rule: r}.parse()
+	a := commute1(match, varCount(match), arch)
+	for i, m := range a {
+		if cond != "" {
+			m += " && " + cond
+		}
+		m += " -> " + result
+		a[i] = m
+	}
+	if len(a) == 1 && normalizeWhitespace(r) != normalizeWhitespace(a[0]) {
+		fmt.Println(normalizeWhitespace(r))
+		fmt.Println(normalizeWhitespace(a[0]))
+		panic("commute() is not the identity for noncommuting rule")
+	}
+	if false && len(a) > 1 {
+		fmt.Println(r)
+		for _, x := range a {
+			fmt.Println("  " + x)
+		}
+	}
+	return a
+}
+
+func commute1(m string, cnt map[string]int, arch arch) []string {
+	if m[0] == '<' || m[0] == '[' || m[0] == '{' || isVariable(m) {
+		return []string{m}
+	}
+	// Split up input.
+	var prefix string
+	colon := strings.Index(m, ":")
+	if colon >= 0 && isVariable(m[:colon]) {
+		prefix = m[:colon+1]
+		m = m[colon+1:]
+	}
+	if m[0] != '(' || m[len(m)-1] != ')' {
+		panic("non-compound expr in commute1: " + m)
+	}
+	s := split(m[1 : len(m)-1])
+	op := s[0]
+
+	// Figure out if the op is commutative or not.
+	commutative := false
+	for _, x := range genericOps {
+		if op == x.name {
+			if x.commutative {
+				commutative = true
+			}
+			break
+		}
+	}
+	if arch.name != "generic" {
+		for _, x := range arch.ops {
+			if op == x.name {
+				if x.commutative {
+					commutative = true
+				}
+				break
+			}
+		}
+	}
+	var idx0, idx1 int
+	if commutative {
+		// Find indexes of two args we can swap.
+		for i, arg := range s {
+			if i == 0 || arg[0] == '<' || arg[0] == '[' || arg[0] == '{' {
+				continue
+			}
+			if idx0 == 0 {
+				idx0 = i
+				continue
+			}
+			if idx1 == 0 {
+				idx1 = i
+				break
+			}
+		}
+		if idx1 == 0 {
+			panic("couldn't find first two args of commutative op " + s[0])
+		}
+		if cnt[s[idx0]] == 1 && cnt[s[idx1]] == 1 || s[idx0] == s[idx1] && cnt[s[idx0]] == 2 {
+			// When we have (Add x y) with no ther uses of x and y in the matching rule,
+			// then we can skip the commutative match (Add y x).
+			commutative = false
+		}
+	}
+
+	// Recursively commute arguments.
+	a := make([][]string, len(s))
+	for i, arg := range s {
+		a[i] = commute1(arg, cnt, arch)
+	}
+
+	// Choose all possibilities from all args.
+	r := crossProduct(a)
+
+	// If commutative, do that again with its two args reversed.
+	if commutative {
+		a[idx0], a[idx1] = a[idx1], a[idx0]
+		r = append(r, crossProduct(a)...)
+	}
+
+	// Construct result.
+	for i, x := range r {
+		r[i] = prefix + "(" + x + ")"
+	}
+	return r
+}
+
+// varCount returns a map which counts the number of occurrences of
+// Value variables in m.
+func varCount(m string) map[string]int {
+	cnt := map[string]int{}
+	varCount1(m, cnt)
+	return cnt
+}
+func varCount1(m string, cnt map[string]int) {
+	if m[0] == '<' || m[0] == '[' || m[0] == '{' {
+		return
+	}
+	if isVariable(m) {
+		cnt[m]++
+		return
+	}
+	// Split up input.
+	colon := strings.Index(m, ":")
+	if colon >= 0 && isVariable(m[:colon]) {
+		cnt[m[:colon]]++
+		m = m[colon+1:]
+	}
+	if m[0] != '(' || m[len(m)-1] != ')' {
+		panic("non-compound expr in commute1: " + m)
+	}
+	s := split(m[1 : len(m)-1])
+	for _, arg := range s[1:] {
+		varCount1(arg, cnt)
+	}
+}
+
+// crossProduct returns all possible values
+// x[0][i] + " " + x[1][j] + " " + ... + " " + x[len(x)-1][k]
+// for all valid values of i, j, ..., k.
+func crossProduct(x [][]string) []string {
+	if len(x) == 1 {
+		return x[0]
+	}
+	var r []string
+	for _, tail := range crossProduct(x[1:]) {
+		for _, first := range x[0] {
+			r = append(r, first+" "+tail)
+		}
+	}
+	return r
+}
+
+// normalizeWhitespace replaces 2+ whitespace sequences with a single space.
+func normalizeWhitespace(x string) string {
+	x = strings.Join(strings.Fields(x), " ")
+	x = strings.Replace(x, "( ", "(", -1)
+	x = strings.Replace(x, " )", ")", -1)
+	return x
+}
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index 316fd2a..d554907 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -6,6 +6,7 @@ package ssa
 
 import (
 	"bytes"
+	"cmd/internal/src"
 	"fmt"
 	"html"
 	"io"
@@ -14,15 +15,15 @@ import (
 
 type HTMLWriter struct {
 	Logger
-	*os.File
+	w io.WriteCloser
 }
 
 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)
+		logger.Fatalf(src.NoXPos, "%v", err)
 	}
-	html := HTMLWriter{File: out, Logger: logger}
+	html := HTMLWriter{w: out, Logger: logger}
 	html.start(funcname)
 	return &html
 }
@@ -141,13 +142,13 @@ dd.ssa-prog {
 <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"
+    "highlight-lightgray",
+    "highlight-yellow"
 ];
 
 // state: which value is highlighted this color?
@@ -263,8 +264,6 @@ function toggle_visibility(id) {
 </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))
@@ -298,11 +297,11 @@ func (w *HTMLWriter) Close() {
 	if w == nil {
 		return
 	}
-	w.WriteString("</tr>")
-	w.WriteString("</table>")
-	w.WriteString("</body>")
-	w.WriteString("</html>")
-	w.File.Close()
+	io.WriteString(w.w, "</tr>")
+	io.WriteString(w.w, "</table>")
+	io.WriteString(w.w, "</body>")
+	io.WriteString(w.w, "</html>")
+	w.w.Close()
 }
 
 // WriteFunc writes f in a column headed by title.
@@ -327,14 +326,14 @@ func (w *HTMLWriter) WriteColumn(title string, html string) {
 }
 
 func (w *HTMLWriter) Printf(msg string, v ...interface{}) {
-	if _, err := fmt.Fprintf(w.File, msg, v...); err != nil {
-		w.Fatalf(0, "%v", err)
+	if _, err := fmt.Fprintf(w.w, msg, v...); err != nil {
+		w.Fatalf(src.NoXPos, "%v", err)
 	}
 }
 
 func (w *HTMLWriter) WriteString(s string) {
-	if _, err := w.File.WriteString(s); err != nil {
-		w.Fatalf(0, "%v", err)
+	if _, err := io.WriteString(w.w, s); err != nil {
+		w.Fatalf(src.NoXPos, "%v", err)
 	}
 }
 
@@ -470,5 +469,9 @@ func (p htmlFuncPrinter) endDepCycle() {
 }
 
 func (p htmlFuncPrinter) named(n LocalSlot, vals []*Value) {
-	// TODO
+	fmt.Fprintf(p.w, "<li>name %s: ", n.Name())
+	for _, val := range vals {
+		fmt.Fprintf(p.w, "%s ", val.HTML())
+	}
+	fmt.Fprintf(p.w, "</li>")
 }
diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
index 5545444..a2d4785 100644
--- a/src/cmd/compile/internal/ssa/layout.go
+++ b/src/cmd/compile/internal/ssa/layout.go
@@ -16,10 +16,18 @@ func layout(f *Func) {
 	defer f.retSparseSet(posdegree)
 	zerodegree := f.newSparseSet(f.NumBlocks()) // blocks with zero remaining degree
 	defer f.retSparseSet(zerodegree)
+	exit := f.newSparseSet(f.NumBlocks()) // exit blocks
+	defer f.retSparseSet(exit)
 
 	// Initialize indegree of each block
 	for _, b := range f.Blocks {
 		idToBlock[b.ID] = b
+		if b.Kind == BlockExit {
+			// exit blocks are always scheduled last
+			// TODO: also add blocks post-dominated by exit blocks
+			exit.add(b.ID)
+			continue
+		}
 		indegree[b.ID] = len(b.Preds)
 		if len(b.Preds) == 0 {
 			zerodegree.add(b.ID)
@@ -69,7 +77,7 @@ blockloop:
 		mindegree := f.NumBlocks()
 		for _, e := range order[len(order)-1].Succs {
 			c := e.b
-			if scheduled[c.ID] {
+			if scheduled[c.ID] || c.Kind == BlockExit {
 				continue
 			}
 			if indegree[c.ID] < mindegree {
@@ -90,14 +98,23 @@ blockloop:
 				continue blockloop
 			}
 		}
-		// Still nothing, pick any block.
-		for {
+		// Still nothing, pick any non-exit block.
+		for posdegree.size() > 0 {
 			cid := posdegree.pop()
 			if !scheduled[cid] {
 				bid = cid
 				continue blockloop
 			}
 		}
+		// Pick any exit block.
+		// TODO: Order these to minimize jump distances?
+		for {
+			cid := exit.pop()
+			if !scheduled[cid] {
+				bid = cid
+				continue blockloop
+			}
+		}
 	}
 	f.Blocks = order
 }
diff --git a/src/cmd/compile/internal/ssa/lca_test.go b/src/cmd/compile/internal/ssa/lca_test.go
index beb33e0..8221dc4 100644
--- a/src/cmd/compile/internal/ssa/lca_test.go
+++ b/src/cmd/compile/internal/ssa/lca_test.go
@@ -22,8 +22,8 @@ func lcaEqual(f *Func, lca1, lca2 lca) bool {
 }
 
 func testLCAgen(t *testing.T, bg blockGen, size int) {
-	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
-	fun := Fun(c, "entry", bg(size)...)
+	c := testConfig(t)
+	fun := c.Fun("entry", bg(size)...)
 	CheckFunc(fun.f)
 	if size == 4 {
 		t.Logf(fun.f.String())
diff --git a/src/cmd/compile/internal/ssa/likelyadjust.go b/src/cmd/compile/internal/ssa/likelyadjust.go
index a4e5534..323de3d 100644
--- a/src/cmd/compile/internal/ssa/likelyadjust.go
+++ b/src/cmd/compile/internal/ssa/likelyadjust.go
@@ -16,11 +16,6 @@ type loop struct {
 	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
@@ -35,6 +30,9 @@ type loop struct {
 func (sdom SparseTree) outerinner(outer, inner *loop) {
 	// There could be other outer loops found in some random order,
 	// locate the new outer loop appropriately among them.
+
+	// Outer loop headers dominate inner loop headers.
+	// Use this to put the "new" "outer" loop in the right place.
 	oldouter := inner.outer
 	for oldouter != nil && sdom.isAncestor(outer.header, oldouter.header) {
 		inner = oldouter
@@ -44,7 +42,7 @@ func (sdom SparseTree) outerinner(outer, inner *loop) {
 		return
 	}
 	if oldouter != nil {
-		outer.outer = oldouter
+		sdom.outerinner(oldouter, outer)
 	}
 
 	inner.outer = outer
@@ -119,7 +117,7 @@ func describePredictionAgrees(b *Block, prediction BranchPrediction) string {
 }
 
 func describeBranchPrediction(f *Func, b *Block, likely, not int8, prediction BranchPrediction) {
-	f.Config.Warnl(b.Line, "Branch prediction rule %s < %s%s",
+	f.Warnl(b.Pos, "Branch prediction rule %s < %s%s",
 		bllikelies[likely-blMin], bllikelies[not-blMin], describePredictionAgrees(b, prediction))
 }
 
@@ -194,7 +192,7 @@ func likelyadjust(f *Func) {
 						noprediction = true
 					}
 					if f.pass.debug > 0 && !noprediction {
-						f.Config.Warnl(b.Line, "Branch prediction rule stay in loop%s",
+						f.Warnl(b.Pos, "Branch prediction rule stay in loop%s",
 							describePredictionAgrees(b, prediction))
 					}
 
@@ -237,7 +235,7 @@ func likelyadjust(f *Func) {
 			}
 		}
 		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])
+			f.Warnl(b.Pos, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin])
 		}
 
 	}
@@ -259,6 +257,18 @@ func (l *loop) LongString() string {
 	return fmt.Sprintf("hdr:%s%s%s", l.header, i, o)
 }
 
+func (l *loop) isWithinOrEq(ll *loop) bool {
+	if ll == nil { // nil means whole program
+		return true
+	}
+	for ; l != nil; l = l.outer {
+		if l == ll {
+			return true
+		}
+	}
+	return false
+}
+
 // 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,
@@ -278,8 +288,8 @@ func loopnestfor(f *Func) *loopnest {
 
 	// Reducible-loop-nest-finding.
 	for _, b := range po {
-		if f.pass.debug > 3 {
-			fmt.Printf("loop finding (0) at %s\n", b)
+		if f.pass != nil && f.pass.debug > 3 {
+			fmt.Printf("loop finding at %s\n", b)
 		}
 
 		var innermost *loop // innermost header reachable from this block
@@ -290,7 +300,7 @@ func loopnestfor(f *Func) *loopnest {
 		//
 		// Choose the first/innermost such h.
 		//
-		// IF s itself dominates b, the s is a loop header;
+		// IF s itself dominates b, then 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.
@@ -299,6 +309,9 @@ func loopnestfor(f *Func) *loopnest {
 			l := b2l[bb.ID]
 
 			if sdom.isAncestorEq(bb, b) { // Found a loop header
+				if f.pass != nil && f.pass.debug > 4 {
+					fmt.Printf("loop finding    succ %s of %s is header\n", bb.String(), b.String())
+				}
 				if l == nil {
 					l = &loop{header: bb, isInner: true}
 					loops = append(loops, l)
@@ -311,6 +324,13 @@ func loopnestfor(f *Func) *loopnest {
 				if l != nil && !sdom.isAncestorEq(l.header, b) {
 					l = l.nearestOuterLoop(sdom, b)
 				}
+				if f.pass != nil && f.pass.debug > 4 {
+					if l == nil {
+						fmt.Printf("loop finding    succ %s of %s has no loop\n", bb.String(), b.String())
+					} else {
+						fmt.Printf("loop finding    succ %s of %s provides loop with header %s\n", bb.String(), b.String(), l.header.String())
+					}
+				}
 			}
 
 			if l == nil || innermost == l {
@@ -340,7 +360,7 @@ func loopnestfor(f *Func) *loopnest {
 	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 {
+	if f.pass != nil && f.pass.stats > 0 && len(loops) > 0 {
 		ln.assembleChildren()
 		ln.calculateDepths()
 		ln.findExits()
@@ -365,7 +385,7 @@ func loopnestfor(f *Func) *loopnest {
 		}
 	}
 
-	if f.pass.debug > 1 && len(loops) > 0 {
+	if f.pass != nil && 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())
@@ -443,6 +463,14 @@ func (ln *loopnest) findExits() {
 	ln.initializedExits = true
 }
 
+// depth returns the loop nesting level of block b.
+func (ln *loopnest) depth(b ID) int16 {
+	if l := ln.b2l[b]; l != nil {
+		return l.depth
+	}
+	return 0
+}
+
 // 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.
diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go
index f9eaedf..41b4894 100644
--- a/src/cmd/compile/internal/ssa/location.go
+++ b/src/cmd/compile/internal/ssa/location.go
@@ -4,7 +4,10 @@
 
 package ssa
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"fmt"
+)
 
 // A place that an ssa variable can reside.
 type Location interface {
@@ -26,9 +29,9 @@ func (r *Register) Name() string {
 // 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
+	N    GCNode      // an ONAME *gc.Node representing a variable on the stack
+	Type *types.Type // type of slot
+	Off  int64       // offset of slot in N
 }
 
 func (s LocalSlot) Name() string {
diff --git a/src/cmd/compile/internal/ssa/loop_test.go b/src/cmd/compile/internal/ssa/loop_test.go
index 69a4962..f8dcdb0 100644
--- a/src/cmd/compile/internal/ssa/loop_test.go
+++ b/src/cmd/compile/internal/ssa/loop_test.go
@@ -5,6 +5,8 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
 	"testing"
 )
 
@@ -44,29 +46,29 @@ func TestLoopConditionS390X(t *testing.T) {
 	//   done:
 	//
 	c := testConfigS390X(t)
-	fun := Fun(c, "entry",
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("SP", OpSP, TypeUInt64, 0, nil),
-			Valu("Nptr", OpOffPtr, TypeInt64Ptr, 8, nil, "SP"),
-			Valu("ret", OpOffPtr, TypeInt64Ptr, 16, nil, "SP"),
-			Valu("N", OpLoad, TypeInt64, 0, nil, "Nptr", "mem"),
-			Valu("starti", OpConst64, TypeInt64, 0, nil),
-			Valu("startsum", OpConst64, TypeInt64, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("SP", OpSP, c.config.Types.UInt64, 0, nil),
+			Valu("ret", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP"),
+			Valu("N", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
+			Valu("starti", OpConst64, c.config.Types.Int64, 0, nil),
+			Valu("startsum", OpConst64, c.config.Types.Int64, 0, nil),
 			Goto("b1")),
 		Bloc("b1",
-			Valu("phii", OpPhi, TypeInt64, 0, nil, "starti", "i"),
-			Valu("phisum", OpPhi, TypeInt64, 0, nil, "startsum", "sum"),
-			Valu("cmp1", OpLess64, TypeBool, 0, nil, "phii", "N"),
+			Valu("phii", OpPhi, c.config.Types.Int64, 0, nil, "starti", "i"),
+			Valu("phisum", OpPhi, c.config.Types.Int64, 0, nil, "startsum", "sum"),
+			Valu("cmp1", OpLess64, c.config.Types.Bool, 0, nil, "phii", "N"),
 			If("cmp1", "b2", "b3")),
 		Bloc("b2",
-			Valu("c1", OpConst64, TypeInt64, 1, nil),
-			Valu("i", OpAdd64, TypeInt64, 0, nil, "phii", "c1"),
-			Valu("c3", OpConst64, TypeInt64, 3, nil),
-			Valu("sum", OpAdd64, TypeInt64, 0, nil, "phisum", "c3"),
+			Valu("c1", OpConst64, c.config.Types.Int64, 1, nil),
+			Valu("i", OpAdd64, c.config.Types.Int64, 0, nil, "phii", "c1"),
+			Valu("c3", OpConst64, c.config.Types.Int64, 3, nil),
+			Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "phisum", "c3"),
 			Goto("b1")),
 		Bloc("b3",
-			Valu("store", OpStore, TypeMem, 8, nil, "ret", "phisum", "mem"),
+			Valu("retdef", OpVarDef, types.TypeMem, 0, nil, "mem"),
+			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ret", "phisum", "retdef"),
 			Exit("store")))
 	CheckFunc(fun.f)
 	Compile(fun.f)
@@ -82,6 +84,4 @@ func TestLoopConditionS390X(t *testing.T) {
 		OpS390XCMP:       1,
 		OpS390XCMPWconst: 0,
 	})
-
-	fun.f.Free()
 }
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
index 14d8834..a96d987 100644
--- a/src/cmd/compile/internal/ssa/loopbce.go
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -139,9 +139,9 @@ nextb:
 
 		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)
+				b.Func.Warnl(b.Pos, "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)
+				b.Func.Warnl(b.Pos, "Induction variable with non-const minimum and increment %d", inc.AuxInt)
 			}
 		}
 
@@ -205,7 +205,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
 			if iv, has := m[ind]; has && 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)
+						f.Warnl(b.Pos, "Found redundant %s", v.Op)
 					}
 					goto simplify
 				}
@@ -232,7 +232,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
 			if iv, has := m[ind]; has && 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)
+						f.Warnl(b.Pos, "Found redundant %s (len promoted to cap)", v.Op)
 					}
 					goto simplify
 				}
@@ -263,7 +263,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
 
 				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)
+						f.Warnl(b.Pos, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
 					}
 					goto simplify
 				}
diff --git a/src/cmd/compile/internal/ssa/loopreschedchecks.go b/src/cmd/compile/internal/ssa/loopreschedchecks.go
index 8f8055e..98b6e92 100644
--- a/src/cmd/compile/internal/ssa/loopreschedchecks.go
+++ b/src/cmd/compile/internal/ssa/loopreschedchecks.go
@@ -4,15 +4,17 @@
 
 package ssa
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"fmt"
+)
 
-// an edgeMemCtr records a backedge, together with the memory and
-// counter phi functions at the target of the backedge that must
+// an edgeMem records a backedge, together with the memory
+// phi functions at the target of the backedge that must
 // be updated when a rescheduling check replaces the backedge.
-type edgeMemCtr struct {
+type edgeMem struct {
 	e Edge
 	m *Value // phi for memory at dest of e
-	c *Value // phi for counter at dest of e
 }
 
 // a rewriteTarget is a a value-argindex pair indicating
@@ -38,32 +40,26 @@ func (r *rewrite) String() string {
 	return s
 }
 
-const initialRescheduleCounterValue = 1021 // Largest 10-bit prime. 97 nSec loop bodies will check every 100 uSec.
-
 // insertLoopReschedChecks inserts rescheduling checks on loop backedges.
 func insertLoopReschedChecks(f *Func) {
 	// TODO: when split information is recorded in export data, insert checks only on backedges that can be reached on a split-call-free path.
 
-	// Loop reschedule checks decrement a per-function counter
-	// shared by all loops, and when the counter becomes non-positive
-	// a call is made to a rescheduling check in the runtime.
+	// Loop reschedule checks compare the stack pointer with
+	// the per-g stack bound.  If the pointer appears invalid,
+	// that means a reschedule check is needed.
 	//
 	// Steps:
 	// 1. locate backedges.
 	// 2. Record memory definitions at block end so that
-	//    the SSA graph for mem can be prperly modified.
-	// 3. Define a counter and record its future uses (at backedges)
-	//    (Same process as 2, applied to a single definition of the counter.
-	//     difference for mem is that there are zero-to-many existing mem
-	//     definitions, versus exactly one for the new counter.)
-	// 4. Ensure that phi functions that will-be-needed for mem and counter
+	//    the SSA graph for mem can be properly modified.
+	// 3. Ensure that phi functions that will-be-needed for mem
 	//    are present in the graph, initially with trivial inputs.
-	// 5. Record all to-be-modified uses of mem and counter;
+	// 4. Record all to-be-modified uses of mem;
 	//    apply modifications (split into two steps to simplify and
 	//    avoided nagging order-dependences).
-	// 6. Rewrite backedges to include counter check, reschedule check,
+	// 5. Rewrite backedges to include reschedule check,
 	//    and modify destination phi function appropriately with new
-	//    definitions for mem and counter.
+	//    definitions for mem.
 
 	if f.NoSplit { // nosplit functions don't reschedule.
 		return
@@ -83,15 +79,15 @@ func insertLoopReschedChecks(f *Func) {
 		fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
 	}
 
-	tofixBackedges := []edgeMemCtr{}
+	tofixBackedges := []edgeMem{}
 
 	for _, e := range backedges { // TODO: could filter here by calls in loops, if declared and inferred nosplit are recorded in export data.
-		tofixBackedges = append(tofixBackedges, edgeMemCtr{e, nil, nil})
+		tofixBackedges = append(tofixBackedges, edgeMem{e, nil})
 	}
 
 	// It's possible that there is no memory state (no global/pointer loads/stores or calls)
 	if lastMems[f.Entry.ID] == nil {
-		lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Line, OpInitMem, TypeMem)
+		lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, types.TypeMem)
 	}
 
 	memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
@@ -108,40 +104,8 @@ func insertLoopReschedChecks(f *Func) {
 		memDefsAtBlockEnds[b.ID] = mem
 	}
 
-	// Set up counter.  There are no phis etc pre-existing for it.
-	counter0 := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
-	ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
-
-	// There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
-	// because the counter only matter for loops and code that reaches them, it is nil for blocks where the ctr is no
-	// longer live.  This will avoid creation of dead phi functions.  This optimization is ignored for the mem variable
-	// because it is harder and also less likely to be helpful, though dead code elimination ought to clean this out anyhow.
-
-	for _, emc := range tofixBackedges {
-		e := emc.e
-		// set initial uses of counter zero (note available-at-bottom and use are the same thing initially.)
-		// each back-edge will be rewritten to include a reschedule check, and that will use the counter.
-		src := e.b.Preds[e.i].b
-		ctrDefsAtBlockEnds[src.ID] = counter0
-	}
-
-	// Push uses towards root
-	for _, b := range f.postorder() {
-		bd := ctrDefsAtBlockEnds[b.ID]
-		if bd == nil {
-			continue
-		}
-		for _, e := range b.Preds {
-			p := e.b
-			if ctrDefsAtBlockEnds[p.ID] == nil {
-				ctrDefsAtBlockEnds[p.ID] = bd
-			}
-		}
-	}
-
 	// Maps from block to newly-inserted phi function in block.
 	newmemphis := make(map[*Block]rewrite)
-	newctrphis := make(map[*Block]rewrite)
 
 	// Insert phi functions as necessary for future changes to flow graph.
 	for i, emc := range tofixBackedges {
@@ -167,29 +131,14 @@ func insertLoopReschedChecks(f *Func) {
 		}
 		tofixBackedges[i].m = headerMemPhi
 
-		var headerCtrPhi *Value
-		rw, ok := newctrphis[h]
-		if !ok {
-			headerCtrPhi = newPhiFor(h, counter0)
-			newctrphis[h] = rewrite{before: counter0, after: headerCtrPhi}
-			addDFphis(counter0, h, h, f, ctrDefsAtBlockEnds, newctrphis)
-		} else {
-			headerCtrPhi = rw.after
-		}
-		tofixBackedges[i].c = headerCtrPhi
 	}
 
 	rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis)
-	rewriteNewPhis(f.Entry, f.Entry, f, ctrDefsAtBlockEnds, newctrphis)
 
 	if f.pass.debug > 0 {
 		for b, r := range newmemphis {
 			fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
 		}
-
-		for b, r := range newctrphis {
-			fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
-		}
 	}
 
 	// Apply collected rewrites.
@@ -199,26 +148,15 @@ func insertLoopReschedChecks(f *Func) {
 		}
 	}
 
-	for _, r := range newctrphis {
-		for _, rw := range r.rewrites {
-			rw.v.SetArg(rw.i, r.after)
-		}
-	}
-
-	zero := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 0)
-	one := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 1)
-
 	// Rewrite backedges to include reschedule checks.
 	for _, emc := range tofixBackedges {
 		e := emc.e
 		headerMemPhi := emc.m
-		headerCtrPhi := emc.c
 		h := e.b
 		i := e.i
 		p := h.Preds[i]
 		bb := p.b
 		mem0 := headerMemPhi.Args[i]
-		ctr0 := headerCtrPhi.Args[i]
 		// bb e->p h,
 		// Because we're going to insert a rare-call, make sure the
 		// looping edge still looks likely.
@@ -236,65 +174,73 @@ func insertLoopReschedChecks(f *Func) {
 		//
 		// new block(s):
 		// test:
-		//    ctr1 := ctr0 - 1
-		//    if ctr1 <= 0 { goto sched }
+		//    if sp < g.limit { goto sched }
 		//    goto join
 		// sched:
 		//    mem1 := call resched (mem0)
 		//    goto join
 		// join:
-		//    ctr2 := phi(ctr1, counter0) // counter0 is the constant
 		//    mem2 := phi(mem0, mem1)
 		//    goto h
 		//
 		// and correct arg i of headerMemPhi and headerCtrPhi
 		//
-		// EXCEPT: block containing only phi functions is bad
+		// EXCEPT: join block containing only phi functions is bad
 		// for the register allocator.  Therefore, there is no
-		// join, and instead branches targeting join instead target
+		// join, and branches targeting join must instead target
 		// the header, and the other phi functions within header are
 		// adjusted for the additional input.
 
 		test := f.NewBlock(BlockIf)
 		sched := f.NewBlock(BlockPlain)
 
-		test.Line = bb.Line
-		sched.Line = bb.Line
+		test.Pos = bb.Pos
+		sched.Pos = bb.Pos
 
-		//    ctr1 := ctr0 - 1
-		//    if ctr1 <= 0 { goto sched }
-		//    goto header
-		ctr1 := test.NewValue2(bb.Line, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
-		cmp := test.NewValue2(bb.Line, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
+		// if sp < g.limit { goto sched }
+		// goto header
+
+		cfgtypes := &f.Config.Types
+		pt := cfgtypes.Uintptr
+		g := test.NewValue1(bb.Pos, OpGetG, pt, mem0)
+		sp := test.NewValue0(bb.Pos, OpSP, pt)
+		cmpOp := OpLess64U
+		if pt.Size() == 4 {
+			cmpOp = OpLess32U
+		}
+		limaddr := test.NewValue1I(bb.Pos, OpOffPtr, pt, 2*pt.Size(), g)
+		lim := test.NewValue2(bb.Pos, OpLoad, pt, limaddr, mem0)
+		cmp := test.NewValue2(bb.Pos, cmpOp, cfgtypes.Bool, sp, lim)
 		test.SetControl(cmp)
-		test.AddEdgeTo(sched) // if true
-		// if false -- rewrite edge to header.
+
+		// if true, goto sched
+		test.AddEdgeTo(sched)
+
+		// if false, rewrite edge to header.
 		// do NOT remove+add, because that will perturb all the other phi functions
 		// as well as messing up other edges to the header.
 		test.Succs = append(test.Succs, Edge{h, i})
 		h.Preds[i] = Edge{test, 1}
 		headerMemPhi.SetArg(i, mem0)
-		headerCtrPhi.SetArg(i, ctr1)
 
 		test.Likely = BranchUnlikely
 
 		// sched:
 		//    mem1 := call resched (mem0)
 		//    goto header
-		resched := f.Config.fe.Syslook("goschedguarded")
-		mem1 := sched.NewValue1A(bb.Line, OpStaticCall, TypeMem, resched, mem0)
+		resched := f.fe.Syslook("goschedguarded")
+		mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeMem, resched, mem0)
 		sched.AddEdgeTo(h)
 		headerMemPhi.AddArg(mem1)
-		headerCtrPhi.AddArg(counter0)
 
 		bb.Succs[p.i] = Edge{test, 0}
 		test.Preds = append(test.Preds, Edge{bb, p.i})
 
 		// Must correct all the other phi functions in the header for new incoming edge.
-		// Except for mem and counter phis, it will be the same value seen on the original
+		// Except for mem phis, it will be the same value seen on the original
 		// backedge at index i.
 		for _, v := range h.Values {
-			if v.Op == OpPhi && v != headerMemPhi && v != headerCtrPhi {
+			if v.Op == OpPhi && v != headerMemPhi {
 				v.AddArg(v.Args[i])
 			}
 		}
@@ -313,7 +259,7 @@ func insertLoopReschedChecks(f *Func) {
 // newPhiFor inserts a new Phi function into b,
 // with all inputs set to v.
 func newPhiFor(b *Block, v *Value) *Value {
-	phiV := b.NewValue0(b.Line, OpPhi, v.Type)
+	phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
 
 	for range b.Preds {
 		phiV.AddArg(v)
@@ -354,7 +300,7 @@ func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Blo
 		// in dominance frontier, self, and dominated.
 		// If the variable def reaching uses in b is itself defined in b, then the new phi function
 		// does not reach the successors of b.  (This assumes a bit about the structure of the
-		// phi use-def graph, but it's true for memory and the inserted counter.)
+		// phi use-def graph, but it's true for memory.)
 		if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
 			for _, e := range b.Succs {
 				s := e.b
@@ -445,10 +391,6 @@ func findLastMems(f *Func) []*Value {
 			}
 			if v.Type.IsMemory() {
 				stores = append(stores, v)
-				if v.Op == OpSelect1 {
-					// Use the arg of the tuple-generating op.
-					v = v.Args[0]
-				}
 				for _, a := range v.Args {
 					if a.Block == b && a.Type.IsMemory() {
 						storeUse.add(a.ID)
diff --git a/src/cmd/compile/internal/ssa/looprotate.go b/src/cmd/compile/internal/ssa/looprotate.go
new file mode 100644
index 0000000..c5b7682
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/looprotate.go
@@ -0,0 +1,103 @@
+// Copyright 2017 The Go Authors. 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
+
+// loopRotate converts loops with a check-loop-condition-at-beginning
+// to loops with a check-loop-condition-at-end.
+// This helps loops avoid extra unnecessary jumps.
+//
+//   loop:
+//     CMPQ ...
+//     JGE exit
+//     ...
+//     JMP loop
+//   exit:
+//
+//    JMP entry
+//  loop:
+//    ...
+//  entry:
+//    CMPQ ...
+//    JLT loop
+func loopRotate(f *Func) {
+	loopnest := f.loopnest()
+	if len(loopnest.loops) == 0 {
+		return
+	}
+
+	idToIdx := make([]int, f.NumBlocks())
+	for i, b := range f.Blocks {
+		idToIdx[b.ID] = i
+	}
+
+	// Set of blocks we're moving, by ID.
+	move := map[ID]struct{}{}
+
+	// Map from block ID to the moving blocks that should
+	// come right after it.
+	after := map[ID][]*Block{}
+
+	// Check each loop header and decide if we want to move it.
+	for _, loop := range loopnest.loops {
+		b := loop.header
+		var p *Block // b's in-loop predecessor
+		for _, e := range b.Preds {
+			if e.b.Kind != BlockPlain {
+				continue
+			}
+			if loopnest.b2l[e.b.ID] != loop {
+				continue
+			}
+			p = e.b
+		}
+		if p == nil || p == b {
+			continue
+		}
+		after[p.ID] = []*Block{b}
+		for {
+			nextIdx := idToIdx[b.ID] + 1
+			if nextIdx >= len(f.Blocks) { // reached end of function (maybe impossible?)
+				break
+			}
+			nextb := f.Blocks[nextIdx]
+			if nextb == p { // original loop precedessor is next
+				break
+			}
+			if loopnest.b2l[nextb.ID] != loop { // about to leave loop
+				break
+			}
+			after[p.ID] = append(after[p.ID], nextb)
+			b = nextb
+		}
+
+		// Place b after p.
+		for _, b := range after[p.ID] {
+			move[b.ID] = struct{}{}
+		}
+	}
+
+	// Move blocks to their destinations in a single pass.
+	// We rely here on the fact that loop headers must come
+	// before the rest of the loop.  And that relies on the
+	// fact that we only identify reducible loops.
+	j := 0
+	for i, b := range f.Blocks {
+		if _, ok := move[b.ID]; ok {
+			continue
+		}
+		f.Blocks[j] = b
+		j++
+		for _, a := range after[b.ID] {
+			if j > i {
+				f.Fatalf("head before tail in loop %s", b)
+			}
+			f.Blocks[j] = a
+			j++
+		}
+	}
+	if j != len(f.Blocks) {
+		f.Fatalf("bad reordering in looprotate")
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/magic.go b/src/cmd/compile/internal/ssa/magic.go
index f6297fd..0457e90 100644
--- a/src/cmd/compile/internal/ssa/magic.go
+++ b/src/cmd/compile/internal/ssa/magic.go
@@ -4,257 +4,179 @@
 
 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
+import "math/big"
+
+// So you want to compute x / c for some constant c?
+// Machine division instructions are slow, so we try to
+// compute this division with a multiplication + a few
+// other cheap instructions instead.
+// (We assume here that c != 0, +/- 1, or +/- 2^i.  Those
+// cases are easy to handle in different ways).
+
+// Technique from https://gmplib.org/~tege/divcnst-pldi94.pdf
+
+// First consider unsigned division.
+// Our strategy is to precompute 1/c then do
+//   ⎣x / c⎦ = ⎣x * (1/c)⎦.
+// 1/c is less than 1, so we can't compute it directly in
+// integer arithmetic.  Let's instead compute 2^e/c
+// for a value of e TBD (^ = exponentiation).  Then
+//   ⎣x / c⎦ = ⎣x * (2^e/c) / 2^e⎦.
+// Dividing by 2^e is easy.  2^e/c isn't an integer, unfortunately.
+// So we must approximate it.  Let's call its approximation m.
+// We'll then compute
+//   ⎣x * m / 2^e⎦
+// Which we want to be equal to ⎣x / c⎦ for 0 <= x < 2^n-1
+// where n is the word size.
+// Setting x = c gives us c * m >= 2^e.
+// We'll chose m = ⎡2^e/c⎤ to satisfy that equation.
+// What remains is to choose e.
+// Let m = 2^e/c + delta, 0 <= delta < 1
+//   ⎣x * (2^e/c + delta) / 2^e⎦
+//   ⎣x / c + x * delta / 2^e⎦
+// We must have x * delta / 2^e < 1/c so that this
+// additional term never rounds differently than ⎣x / c⎦ does.
+// Rearranging,
+//   2^e > x * delta * c
+// x can be at most 2^n-1 and delta can be at most 1.
+// So it is sufficient to have 2^e >= 2^n*c.
+// So we'll choose e = n + s, with s = ⎡log2(c)⎤.
+//
+// An additional complication arises because m has n+1 bits in it.
+// Hardware restricts us to n bit by n bit multiplies.
+// We divide into 3 cases:
+//
+// Case 1: m is even.
+//   ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦
+//   ⎣x / c⎦ = ⎣x * (m/2) / 2^(n+s-1)⎦
+//   ⎣x / c⎦ = ⎣x * (m/2) / 2^n / 2^(s-1)⎦
+//   ⎣x / c⎦ = ⎣⎣x * (m/2) / 2^n⎦ / 2^(s-1)⎦
+//   multiply + shift
+//
+// Case 2: c is even.
+//   ⎣x / c⎦ = ⎣(x/2) / (c/2)⎦
+//   ⎣x / c⎦ = ⎣⎣x/2⎦ / (c/2)⎦
+//     This is just the original problem, with x' = ⎣x/2⎦, c' = c/2, n' = n-1.
+//       s' = s-1
+//       m' = ⎡2^(n'+s')/c'⎤
+//          = ⎡2^(n+s-1)/c⎤
+//          = ⎡m/2⎤
+//   ⎣x / c⎦ = ⎣x' * m' / 2^(n'+s')⎦
+//   ⎣x / c⎦ = ⎣⎣x/2⎦ * ⎡m/2⎤ / 2^(n+s-2)⎦
+//   ⎣x / c⎦ = ⎣⎣⎣x/2⎦ * ⎡m/2⎤ / 2^n⎦ / 2^(s-2)⎦
+//   shift + multiply + shift
+//
+// Case 3: everything else
+//   let k = m - 2^n. k fits in n bits.
+//   ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦
+//   ⎣x / c⎦ = ⎣x * (2^n + k) / 2^(n+s)⎦
+//   ⎣x / c⎦ = ⎣(x + x * k / 2^n) / 2^s⎦
+//   ⎣x / c⎦ = ⎣(x + ⎣x * k / 2^n⎦) / 2^s⎦
+//   ⎣x / c⎦ = ⎣(x + ⎣x * k / 2^n⎦) / 2^s⎦
+//   ⎣x / c⎦ = ⎣⎣(x + ⎣x * k / 2^n⎦) / 2⎦ / 2^(s-1)⎦
+//   multiply + avg + shift
+//
+// These can be implemented in hardware using:
+//  ⎣a * b / 2^n⎦ - aka high n bits of an n-bit by n-bit multiply.
+//  ⎣(a+b) / 2⎦   - aka "average" of two n-bit numbers.
+//                  (Not just a regular add & shift because the intermediate result
+//                   a+b has n+1 bits in it.  Nevertheless, can be done
+//                   in 2 instructions on x86.)
+
+// umagicOK returns whether we should strength reduce a n-bit divide by c.
+func umagicOK(n uint, c int64) bool {
+	// Convert from ConstX auxint values to the real uint64 constant they represent.
+	d := uint64(c) << (64 - n) >> (64 - n)
+
+	// Doesn't work for 0.
+	// Don't use for powers of 2.
+	return d&(d-1) != 0
 }
 
-// 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
+type umagicData struct {
+	s int64  // ⎡log2(c)⎤
+	m uint64 // ⎡2^(n+s)/c⎤ - 2^n
 }
 
-// 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
+// umagic computes the constants needed to strength reduce unsigned n-bit divides by the constant uint64(c).
+// The return values satisfy for all 0 <= x < 2^n
+//  floor(x / uint64(c)) = x * (m + 2^n) >> (n+s)
+func umagic(n uint, c int64) umagicData {
+	// Convert from ConstX auxint values to the real uint64 constant they represent.
+	d := uint64(c) << (64 - n) >> (64 - n)
+
+	C := new(big.Int).SetUint64(d)
+	s := C.BitLen()
+	M := big.NewInt(1)
+	M.Lsh(M, n+uint(s))     // 2^(n+s)
+	M.Add(M, C)             // 2^(n+s)+c
+	M.Sub(M, big.NewInt(1)) // 2^(n+s)+c-1
+	M.Div(M, C)             // ⎡2^(n+s)/c⎤
+	if M.Bit(int(n)) != 1 {
+		panic("n+1st bit isn't set")
 	}
+	M.SetBit(M, int(n), 0)
+	m := M.Uint64()
+	return umagicData{s: int64(s), m: m}
+}
 
-	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
+// For signed division, we use a similar strategy.
+// First, we enforce a positive c.
+//   x / c = -(x / (-c))
+// This will require an additional Neg op for c<0.
+//
+// If x is positive we're in a very similar state
+// to the unsigned case above.  We define:
+//   s = ⎡log2(c)⎤-1
+//   m = ⎡2^(n+s)/c⎤
+// Then
+//   ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦
+// If x is negative we have
+//   ⎡x / c⎤ = ⎣x * m / 2^(n+s)⎦ + 1
+// (TODO: derivation?)
+//
+// The multiply is a bit odd, as it is a signed n-bit value
+// times an unsigned n-bit value.  For n smaller than the
+// word size, we can extend x and m appropriately and use the
+// signed multiply instruction.  For n == word size,
+// we must use the signed multiply high and correct
+// the result by adding x*2^n.
+//
+// Adding 1 if x<0 is done by subtracting x>>(n-1).
+
+func smagicOK(n uint, c int64) bool {
+	if c < 0 {
+		// Doesn't work for negative c.
+		return false
 	}
-
-	m.Um = q2 + 1
-	m.S = p - m.W
+	// Doesn't work for 0.
+	// Don't use it for powers of 2.
+	return c&(c-1) != 0
 }
 
-// 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)
+type smagicData struct {
+	s int64  // ⎡log2(c)⎤-1
+	m uint64 // ⎡2^(n+s)/c⎤
 }
 
-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
+// magic computes the constants needed to strength reduce signed n-bit divides by the constant c.
+// Must have c>0.
+// The return values satisfy for all -2^(n-1) <= x < 2^(n-1)
+//  trunc(x / c) = x * m >> (n+s) + (x < 0 ? 1 : 0)
+func smagic(n uint, c int64) smagicData {
+	C := new(big.Int).SetInt64(c)
+	s := C.BitLen() - 1
+	M := big.NewInt(1)
+	M.Lsh(M, n+uint(s))     // 2^(n+s)
+	M.Add(M, C)             // 2^(n+s)+c
+	M.Sub(M, big.NewInt(1)) // 2^(n+s)+c-1
+	M.Div(M, C)             // ⎡2^(n+s)/c⎤
+	if M.Bit(int(n)) != 0 {
+		panic("n+1st bit is set")
+	}
+	if M.Bit(int(n-1)) == 0 {
+		panic("nth bit is not set")
+	}
+	m := M.Uint64()
+	return smagicData{s: int64(s), m: m}
 }
diff --git a/src/cmd/compile/internal/ssa/magic_test.go b/src/cmd/compile/internal/ssa/magic_test.go
new file mode 100644
index 0000000..9599524
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/magic_test.go
@@ -0,0 +1,205 @@
+// Copyright 2017 The Go Authors. 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/big"
+	"testing"
+)
+
+func TestMagicExhaustive8(t *testing.T) {
+	testMagicExhaustive(t, 8)
+}
+func TestMagicExhaustive8U(t *testing.T) {
+	testMagicExhaustiveU(t, 8)
+}
+func TestMagicExhaustive16(t *testing.T) {
+	if testing.Short() {
+		t.Skip("slow test; skipping")
+	}
+	testMagicExhaustive(t, 16)
+}
+func TestMagicExhaustive16U(t *testing.T) {
+	if testing.Short() {
+		t.Skip("slow test; skipping")
+	}
+	testMagicExhaustiveU(t, 16)
+}
+
+// exhaustive test of magic for n bits
+func testMagicExhaustive(t *testing.T, n uint) {
+	min := -int64(1) << (n - 1)
+	max := int64(1) << (n - 1)
+	for c := int64(1); c < max; c++ {
+		if !smagicOK(n, int64(c)) {
+			continue
+		}
+		m := int64(smagic(n, c).m)
+		s := smagic(n, c).s
+		for i := min; i < max; i++ {
+			want := i / c
+			got := (i * m) >> (n + uint(s))
+			if i < 0 {
+				got++
+			}
+			if want != got {
+				t.Errorf("signed magic wrong for %d / %d: got %d, want %d (m=%d,s=%d)\n", i, c, got, want, m, s)
+			}
+		}
+	}
+}
+func testMagicExhaustiveU(t *testing.T, n uint) {
+	max := uint64(1) << n
+	for c := uint64(1); c < max; c++ {
+		if !umagicOK(n, int64(c)) {
+			continue
+		}
+		m := umagic(n, int64(c)).m
+		s := umagic(n, int64(c)).s
+		for i := uint64(0); i < max; i++ {
+			want := i / c
+			got := (i * (max + m)) >> (n + uint(s))
+			if want != got {
+				t.Errorf("unsigned magic wrong for %d / %d: got %d, want %d (m=%d,s=%d)\n", i, c, got, want, m, s)
+			}
+		}
+	}
+}
+
+func TestMagicUnsigned(t *testing.T) {
+	One := new(big.Int).SetUint64(1)
+	for _, n := range [...]uint{8, 16, 32, 64} {
+		TwoN := new(big.Int).Lsh(One, n)
+		Max := new(big.Int).Sub(TwoN, One)
+		for _, c := range [...]uint64{
+			3,
+			5,
+			6,
+			7,
+			9,
+			10,
+			11,
+			12,
+			13,
+			14,
+			15,
+			17,
+			1<<8 - 1,
+			1<<8 + 1,
+			1<<16 - 1,
+			1<<16 + 1,
+			1<<32 - 1,
+			1<<32 + 1,
+			1<<64 - 1,
+		} {
+			if c>>n != 0 {
+				continue // not appropriate for the given n.
+			}
+			if !umagicOK(n, int64(c)) {
+				t.Errorf("expected n=%d c=%d to pass\n", n, c)
+			}
+			m := umagic(n, int64(c)).m
+			s := umagic(n, int64(c)).s
+
+			C := new(big.Int).SetUint64(c)
+			M := new(big.Int).SetUint64(m)
+			M.Add(M, TwoN)
+
+			// Find largest multiple of c.
+			Mul := new(big.Int).Div(Max, C)
+			Mul.Mul(Mul, C)
+			mul := Mul.Uint64()
+
+			// Try some input values, mostly around multiples of c.
+			for _, x := range [...]uint64{0, 1,
+				c - 1, c, c + 1,
+				2*c - 1, 2 * c, 2*c + 1,
+				mul - 1, mul, mul + 1,
+				uint64(1)<<n - 1,
+			} {
+				X := new(big.Int).SetUint64(x)
+				if X.Cmp(Max) > 0 {
+					continue
+				}
+				Want := new(big.Int).Quo(X, C)
+				Got := new(big.Int).Mul(X, M)
+				Got.Rsh(Got, n+uint(s))
+				if Want.Cmp(Got) != 0 {
+					t.Errorf("umagic for %d/%d n=%d doesn't work, got=%s, want %s\n", x, c, n, Got, Want)
+				}
+			}
+		}
+	}
+}
+
+func TestMagicSigned(t *testing.T) {
+	One := new(big.Int).SetInt64(1)
+	for _, n := range [...]uint{8, 16, 32, 64} {
+		TwoNMinusOne := new(big.Int).Lsh(One, n-1)
+		Max := new(big.Int).Sub(TwoNMinusOne, One)
+		Min := new(big.Int).Neg(TwoNMinusOne)
+		for _, c := range [...]int64{
+			3,
+			5,
+			6,
+			7,
+			9,
+			10,
+			11,
+			12,
+			13,
+			14,
+			15,
+			17,
+			1<<7 - 1,
+			1<<7 + 1,
+			1<<15 - 1,
+			1<<15 + 1,
+			1<<31 - 1,
+			1<<31 + 1,
+			1<<63 - 1,
+		} {
+			if c>>(n-1) != 0 {
+				continue // not appropriate for the given n.
+			}
+			if !smagicOK(n, int64(c)) {
+				t.Errorf("expected n=%d c=%d to pass\n", n, c)
+			}
+			m := smagic(n, int64(c)).m
+			s := smagic(n, int64(c)).s
+
+			C := new(big.Int).SetInt64(c)
+			M := new(big.Int).SetUint64(m)
+
+			// Find largest multiple of c.
+			Mul := new(big.Int).Div(Max, C)
+			Mul.Mul(Mul, C)
+			mul := Mul.Int64()
+
+			// Try some input values, mostly around multiples of c.
+			for _, x := range [...]int64{
+				-1, 1,
+				-c - 1, -c, -c + 1, c - 1, c, c + 1,
+				-2*c - 1, -2 * c, -2*c + 1, 2*c - 1, 2 * c, 2*c + 1,
+				-mul - 1, -mul, -mul + 1, mul - 1, mul, mul + 1,
+				int64(1)<<n - 1, -int64(1)<<n + 1,
+			} {
+				X := new(big.Int).SetInt64(x)
+				if X.Cmp(Min) < 0 || X.Cmp(Max) > 0 {
+					continue
+				}
+				Want := new(big.Int).Quo(X, C)
+				Got := new(big.Int).Mul(X, M)
+				Got.Rsh(Got, n+uint(s))
+				if x < 0 {
+					Got.Add(Got, One)
+				}
+				if Want.Cmp(Got) != 0 {
+					t.Errorf("smagic for %d/%d n=%d doesn't work, got=%s, want %s\n", x, c, n, Got, Want)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
index 0a34cd1..d01edcc 100644
--- a/src/cmd/compile/internal/ssa/nilcheck.go
+++ b/src/cmd/compile/internal/ssa/nilcheck.go
@@ -39,28 +39,46 @@ func nilcheckelim(f *Func) {
 
 	// 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 {
+			// 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
 			if v.Op == OpAddr || v.Op == OpAddPtr {
 				nonNilValues[v.ID] = true
-			} else if v.Op == OpPhi {
+			}
+		}
+	}
+
+	for changed := true; changed; {
+		changed = false
+		for _, b := range f.Blocks {
+			for _, v := range b.Values {
 				// phis whose arguments are all non-nil
 				// are non-nil
-				argsNonNil := true
-				for _, a := range v.Args {
-					if !nonNilValues[a.ID] {
-						argsNonNil = false
+				if v.Op == OpPhi {
+					argsNonNil := true
+					for _, a := range v.Args {
+						if !nonNilValues[a.ID] {
+							argsNonNil = false
+							break
+						}
+					}
+					if argsNonNil {
+						if !nonNilValues[v.ID] {
+							changed = true
+						}
+						nonNilValues[v.ID] = true
 					}
-				}
-				if argsNonNil {
-					nonNilValues[v.ID] = true
 				}
 			}
 		}
 	}
 
+	// allocate auxiliary date structures for computing store order
+	sset := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(sset)
+	storeNumber := make([]int32, f.NumValues())
+
 	// perform a depth first walk of the dominee tree
 	for len(work) > 0 {
 		node := work[len(work)-1]
@@ -82,7 +100,10 @@ func nilcheckelim(f *Func) {
 				}
 			}
 
-			// Next, eliminate any redundant nil checks in this block.
+			// Next, order values in the current block w.r.t. stores.
+			b.Values = storeOrder(b.Values, sset, storeNumber)
+
+			// Next, process values in the block.
 			i := 0
 			for _, v := range b.Values {
 				b.Values[i] = v
@@ -101,14 +122,18 @@ func nilcheckelim(f *Func) {
 						// This is a redundant implicit nil check.
 						// Logging in the style of the former compiler -- and omit line 1,
 						// which is usually in generated code.
-						if f.Config.Debug_checknil() && v.Line > 1 {
-							f.Config.Warnl(v.Line, "removed nil check")
+						if f.fe.Debug_checknil() && v.Pos.Line() > 1 {
+							f.Warnl(v.Pos, "removed nil check")
 						}
 						v.reset(OpUnknown)
 						// TODO: f.freeValue(v)
 						i--
 						continue
 					}
+					// Record the fact that we know ptr is non nil, and remember to
+					// undo that information when this dominator subtree is done.
+					nonNilValues[ptr.ID] = true
+					work = append(work, bp{op: ClearPtr, ptr: ptr})
 				}
 			}
 			for j := i; j < len(b.Values); j++ {
@@ -116,21 +141,6 @@ func nilcheckelim(f *Func) {
 			}
 			b.Values = b.Values[:i]
 
-			// Finally, find redundant nil checks for subsequent blocks.
-			// Note that we can't add these until the loop above is done, as the
-			// values in the block are not ordered in any way when this pass runs.
-			// This was the cause of issue #18725.
-			for _, v := range b.Values {
-				if v.Op != OpNilCheck {
-					continue
-				}
-				ptr := v.Args[0]
-				// Record the fact that we know ptr is non nil, and remember to
-				// undo that information when this dominator subtree is done.
-				nonNilValues[ptr.ID] = true
-				work = append(work, bp{op: ClearPtr, ptr: ptr})
-			}
-
 			// Add all dominated blocks to the work list.
 			for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling {
 				work = append(work, bp{op: Work, block: w})
@@ -161,8 +171,8 @@ func nilcheckelim2(f *Func) {
 		for i := len(b.Values) - 1; i >= 0; i-- {
 			v := b.Values[i]
 			if opcodeTable[v.Op].nilCheck && unnecessary.contains(v.Args[0].ID) {
-				if f.Config.Debug_checknil() && int(v.Line) > 1 {
-					f.Config.Warnl(v.Line, "removed nil check")
+				if f.fe.Debug_checknil() && v.Pos.Line() > 1 {
+					f.Warnl(v.Pos, "removed nil check")
 				}
 				v.reset(OpUnknown)
 				continue
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go
index f12c68c..1d9e5d1 100644
--- a/src/cmd/compile/internal/ssa/nilcheck_test.go
+++ b/src/cmd/compile/internal/ssa/nilcheck_test.go
@@ -1,6 +1,7 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"strconv"
 	"testing"
 )
@@ -16,13 +17,14 @@ func BenchmarkNilCheckDeep10000(b *testing.B) { benchmarkNilCheckDeep(b, 10000)
 // 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
+	c := testConfig(b)
+	ptrType := c.config.Types.BytePtr
 
 	var blocs []bloc
 	blocs = append(blocs,
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto(blockn(0)),
 		),
 	)
@@ -30,7 +32,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) {
 		blocs = append(blocs,
 			Bloc(blockn(i),
 				Valu(ptrn(i), OpAddr, ptrType, 0, nil, "sb"),
-				Valu(booln(i), OpIsNonNil, TypeBool, 0, nil, ptrn(i)),
+				Valu(booln(i), OpIsNonNil, c.config.Types.Bool, 0, nil, ptrn(i)),
 				If(booln(i), blockn(i+1), "exit"),
 			),
 		)
@@ -40,8 +42,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) {
 		Bloc("exit", Exit("mem")),
 	)
 
-	c := NewConfig("amd64", DummyFrontend{b}, nil, true)
-	fun := Fun(c, "entry", blocs...)
+	fun := c.Fun("entry", blocs...)
 
 	CheckFunc(fun.f)
 	b.SetBytes(int64(depth)) // helps for eyeballing linearity
@@ -63,19 +64,19 @@ func isNilCheck(b *Block) bool {
 
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
 			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "secondCheck", "exit")),
 		Bloc("secondCheck",
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool2", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -100,21 +101,21 @@ func TestNilcheckSimple(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
 			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "secondCheck", "exit")),
 		Bloc("exit",
 			Exit("mem")),
 		Bloc("secondCheck",
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool2", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")))
@@ -136,16 +137,16 @@ func TestNilcheckDomOrder(t *testing.T) {
 
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
 			Valu("ptr1", OpAddr, ptrType, 0, nil, "sb"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -169,17 +170,17 @@ func TestNilcheckAddr(t *testing.T) {
 
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
-			Valu("off", OpConst64, TypeInt64, 20, nil),
+			Valu("off", OpConst64, c.config.Types.Int64, 20, nil),
 			Valu("ptr1", OpAddPtr, ptrType, 0, nil, "sb", "off"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -204,15 +205,15 @@ func TestNilcheckAddPtr(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("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"),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("sp", OpSP, types.TypeInvalid, 0, nil),
+			Valu("baddr", OpAddr, c.config.Types.Bool, 0, "b", "sp"),
+			Valu("bool1", OpLoad, c.config.Types.Bool, 0, nil, "baddr", "mem"),
 			If("bool1", "b1", "b2")),
 		Bloc("b1",
 			Valu("ptr1", OpAddr, ptrType, 0, nil, "sb"),
@@ -223,7 +224,7 @@ func TestNilcheckPhi(t *testing.T) {
 		// 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"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "phi"),
 			If("bool2", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -248,23 +249,23 @@ func TestNilcheckPhi(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
 			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "differentCheck", "exit")),
 		Bloc("differentCheck",
 			Valu("ptr2", OpLoad, ptrType, 0, nil, "sb", "mem"),
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr2"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr2"),
 			If("bool2", "secondCheck", "exit")),
 		Bloc("secondCheck",
-			Valu("bool3", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool3", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool3", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -296,22 +297,22 @@ func TestNilcheckKeepRemove(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
 			Goto("checkPtr")),
 		Bloc("checkPtr",
 			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
-			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool1", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool1", "extra", "secondCheck")),
 		Bloc("secondCheck",
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool2", "extra", "thirdCheck")),
 		Bloc("thirdCheck",
-			Valu("bool3", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool3", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool3", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -347,20 +348,20 @@ func TestNilcheckInFalseBranch(t *testing.T) {
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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"),
+			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
 			If("bool1", "secondCheck", "exit")),
 		Bloc("secondCheck",
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool2", "extra", "exit")),
 		Bloc("extra",
 			Goto("exit")),
@@ -386,29 +387,29 @@ func TestNilcheckUser(t *testing.T) {
 
 // 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",
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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"),
+			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
 			If("bool1", "secondCheck", "couldBeNil")),
 		Bloc("couldBeNil",
 			Goto("secondCheck")),
 		Bloc("secondCheck",
-			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			Valu("bool2", OpIsNonNil, c.config.Types.Bool, 0, nil, "ptr1"),
 			If("bool2", "extra", "exit")),
 		Bloc("extra",
 			// prevent fuse from eliminating this block
-			Valu("store", OpStore, TypeMem, 8, nil, "ptr1", "nilptr", "mem"),
+			Valu("store", OpStore, types.TypeMem, 0, ptrType, "ptr1", "nilptr", "mem"),
 			Goto("exit")),
 		Bloc("exit",
-			Valu("phi", OpPhi, TypeMem, 0, nil, "mem", "store"),
+			Valu("phi", OpPhi, types.TypeMem, 0, nil, "mem", "store"),
 			Exit("phi")))
 
 	CheckFunc(fun.f)
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index 37b2f74..37c24ee 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -23,18 +23,19 @@ type opInfo struct {
 	auxType           auxType
 	argLen            int32 // the number of arguments, -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 // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
-	resultNotInArgs   bool // outputs must not be allocated to the same registers as inputs
-	clobberFlags      bool // this op clobbers flags register
-	call              bool // is a function call
-	nilCheck          bool // this op is a nil check on arg0
-	faultOnNilArg0    bool // this op will fault if arg0 is nil (and aux encodes a small offset)
-	faultOnNilArg1    bool // this op will fault if arg1 is nil (and aux encodes a small offset)
-	usesScratch       bool // this op requires scratch memory space
-	hasSideEffects    bool // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
+	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      // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
+	resultNotInArgs   bool      // outputs must not be allocated to the same registers as inputs
+	clobberFlags      bool      // this op clobbers flags register
+	call              bool      // is a function call
+	nilCheck          bool      // this op is a nil check on arg0
+	faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
+	faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
+	usesScratch       bool      // this op requires scratch memory space
+	hasSideEffects    bool      // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
+	symEffect         SymEffect // effect this op has on symbol in aux
 }
 
 type inputInfo struct {
@@ -56,25 +57,39 @@ type regInfo struct {
 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)
-	auxSizeAndAlign            // auxInt is a SizeAndAlign
-	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
-	auxSymSizeAndAlign         // aux is a symbol, auxInt is a SizeAndAlign
+	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
+	auxTyp                  // aux is a type
+	auxTypSize              // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
 
 	auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
 )
 
+// A SymEffect describes the effect that an SSA Value has on the variable
+// identified by the symbol in its Aux field.
+type SymEffect int8
+
+const (
+	SymRead SymEffect = 1 << iota
+	SymWrite
+	SymAddr
+
+	SymRdWr = SymRead | SymWrite
+
+	SymNone SymEffect = 0
+)
+
 // 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.
@@ -139,31 +154,3 @@ func (x ValAndOff) add(off int64) int64 {
 	}
 	return makeValAndOff(x.Val(), x.Off()+off)
 }
-
-// SizeAndAlign holds both the size and the alignment of a type,
-// used in Zero and Move ops.
-// The high 8 bits hold the alignment.
-// The low 56 bits hold the size.
-type SizeAndAlign int64
-
-func (x SizeAndAlign) Size() int64 {
-	return int64(x) & (1<<56 - 1)
-}
-func (x SizeAndAlign) Align() int64 {
-	return int64(uint64(x) >> 56)
-}
-func (x SizeAndAlign) Int64() int64 {
-	return int64(x)
-}
-func (x SizeAndAlign) String() string {
-	return fmt.Sprintf("size=%d,align=%d", x.Size(), x.Align())
-}
-func MakeSizeAndAlign(size, align int64) SizeAndAlign {
-	if size&^(1<<56-1) != 0 {
-		panic("size too big in SizeAndAlign")
-	}
-	if align >= 1<<8 {
-		panic("alignment too big in SizeAndAlign")
-	}
-	return SizeAndAlign(size | align<<56)
-}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 2938bd1..ae2dd5f 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -1,5 +1,4 @@
-// autogenerated: do not edit!
-// generated from gen/*Ops.go
+// Code generated from gen/*Ops.go; DO NOT EDIT.
 
 package ssa
 
@@ -268,11 +267,8 @@ const (
 	Op386MULLconst
 	Op386HMULL
 	Op386HMULLU
-	Op386HMULW
-	Op386HMULB
-	Op386HMULWU
-	Op386HMULBU
 	Op386MULLQU
+	Op386AVGLU
 	Op386DIVL
 	Op386DIVW
 	Op386DIVLU
@@ -390,8 +386,6 @@ const (
 	Op386REPSTOSL
 	Op386CALLstatic
 	Op386CALLclosure
-	Op386CALLdefer
-	Op386CALLgo
 	Op386CALLinter
 	Op386DUFFCOPY
 	Op386REPMOVSL
@@ -433,6 +427,12 @@ const (
 	OpAMD64MOVSSstoreidx4
 	OpAMD64MOVSDstoreidx1
 	OpAMD64MOVSDstoreidx8
+	OpAMD64ADDSDmem
+	OpAMD64ADDSSmem
+	OpAMD64SUBSSmem
+	OpAMD64SUBSDmem
+	OpAMD64MULSSmem
+	OpAMD64MULSDmem
 	OpAMD64ADDQ
 	OpAMD64ADDL
 	OpAMD64ADDQconst
@@ -447,12 +447,8 @@ const (
 	OpAMD64MULLconst
 	OpAMD64HMULQ
 	OpAMD64HMULL
-	OpAMD64HMULW
-	OpAMD64HMULB
 	OpAMD64HMULQU
 	OpAMD64HMULLU
-	OpAMD64HMULWU
-	OpAMD64HMULBU
 	OpAMD64AVGQU
 	OpAMD64DIVQ
 	OpAMD64DIVL
@@ -484,6 +480,10 @@ const (
 	OpAMD64CMPBconst
 	OpAMD64UCOMISS
 	OpAMD64UCOMISD
+	OpAMD64BTL
+	OpAMD64BTQ
+	OpAMD64BTLconst
+	OpAMD64BTQconst
 	OpAMD64TESTQ
 	OpAMD64TESTL
 	OpAMD64TESTW
@@ -512,20 +512,42 @@ const (
 	OpAMD64SARLconst
 	OpAMD64SARWconst
 	OpAMD64SARBconst
+	OpAMD64ROLQ
+	OpAMD64ROLL
+	OpAMD64ROLW
+	OpAMD64ROLB
+	OpAMD64RORQ
+	OpAMD64RORL
+	OpAMD64RORW
+	OpAMD64RORB
 	OpAMD64ROLQconst
 	OpAMD64ROLLconst
 	OpAMD64ROLWconst
 	OpAMD64ROLBconst
+	OpAMD64ADDLmem
+	OpAMD64ADDQmem
+	OpAMD64SUBQmem
+	OpAMD64SUBLmem
+	OpAMD64ANDLmem
+	OpAMD64ANDQmem
+	OpAMD64ORQmem
+	OpAMD64ORLmem
+	OpAMD64XORQmem
+	OpAMD64XORLmem
 	OpAMD64NEGQ
 	OpAMD64NEGL
 	OpAMD64NOTQ
 	OpAMD64NOTL
 	OpAMD64BSFQ
 	OpAMD64BSFL
+	OpAMD64BSRQ
+	OpAMD64BSRL
 	OpAMD64CMOVQEQ
 	OpAMD64CMOVLEQ
 	OpAMD64BSWAPQ
 	OpAMD64BSWAPL
+	OpAMD64POPCNTQ
+	OpAMD64POPCNTL
 	OpAMD64SQRTSD
 	OpAMD64SBBQcarrymask
 	OpAMD64SBBLcarrymask
@@ -613,8 +635,6 @@ const (
 	OpAMD64REPSTOSQ
 	OpAMD64CALLstatic
 	OpAMD64CALLclosure
-	OpAMD64CALLdefer
-	OpAMD64CALLgo
 	OpAMD64CALLinter
 	OpAMD64DUFFCOPY
 	OpAMD64REPMOVSQ
@@ -651,7 +671,7 @@ const (
 	OpARMMUL
 	OpARMHMUL
 	OpARMHMULU
-	OpARMUDIVrtcall
+	OpARMCALLudiv
 	OpARMADDS
 	OpARMADDSconst
 	OpARMADC
@@ -685,6 +705,8 @@ const (
 	OpARMNEGD
 	OpARMSQRTD
 	OpARMCLZ
+	OpARMREV
+	OpARMRBIT
 	OpARMSLL
 	OpARMSLLconst
 	OpARMSRL
@@ -840,8 +862,6 @@ const (
 	OpARMSRAcond
 	OpARMCALLstatic
 	OpARMCALLclosure
-	OpARMCALLdefer
-	OpARMCALLgo
 	OpARMCALLinter
 	OpARMLoweredNilCheck
 	OpARMEqual
@@ -1005,8 +1025,6 @@ const (
 	OpARM64CSELULT0
 	OpARM64CALLstatic
 	OpARM64CALLclosure
-	OpARM64CALLdefer
-	OpARM64CALLgo
 	OpARM64CALLinter
 	OpARM64LoweredNilCheck
 	OpARM64Equal
@@ -1127,8 +1145,6 @@ const (
 	OpMIPSMOVDF
 	OpMIPSCALLstatic
 	OpMIPSCALLclosure
-	OpMIPSCALLdefer
-	OpMIPSCALLgo
 	OpMIPSCALLinter
 	OpMIPSLoweredAtomicLoad
 	OpMIPSLoweredAtomicStore
@@ -1233,8 +1249,6 @@ const (
 	OpMIPS64MOVDF
 	OpMIPS64CALLstatic
 	OpMIPS64CALLclosure
-	OpMIPS64CALLdefer
-	OpMIPS64CALLgo
 	OpMIPS64CALLinter
 	OpMIPS64DUFFZERO
 	OpMIPS64LoweredZero
@@ -1260,6 +1274,10 @@ const (
 	OpPPC64MULHWU
 	OpPPC64FMUL
 	OpPPC64FMULS
+	OpPPC64FMADD
+	OpPPC64FMADDS
+	OpPPC64FMSUB
+	OpPPC64FMSUBS
 	OpPPC64SRAD
 	OpPPC64SRAW
 	OpPPC64SRD
@@ -1274,6 +1292,13 @@ const (
 	OpPPC64SRWconst
 	OpPPC64SLDconst
 	OpPPC64SLWconst
+	OpPPC64ROTLconst
+	OpPPC64ROTLWconst
+	OpPPC64CNTLZD
+	OpPPC64CNTLZW
+	OpPPC64POPCNTD
+	OpPPC64POPCNTW
+	OpPPC64POPCNTB
 	OpPPC64FDIV
 	OpPPC64FDIVS
 	OpPPC64DIVD
@@ -1290,6 +1315,7 @@ const (
 	OpPPC64ANDN
 	OpPPC64OR
 	OpPPC64ORN
+	OpPPC64NOR
 	OpPPC64XOR
 	OpPPC64EQV
 	OpPPC64NEG
@@ -1349,14 +1375,27 @@ const (
 	OpPPC64FGreaterEqual
 	OpPPC64LoweredGetClosurePtr
 	OpPPC64LoweredNilCheck
+	OpPPC64LoweredRound32F
+	OpPPC64LoweredRound64F
 	OpPPC64MOVDconvert
 	OpPPC64CALLstatic
 	OpPPC64CALLclosure
-	OpPPC64CALLdefer
-	OpPPC64CALLgo
 	OpPPC64CALLinter
 	OpPPC64LoweredZero
 	OpPPC64LoweredMove
+	OpPPC64LoweredAtomicStore32
+	OpPPC64LoweredAtomicStore64
+	OpPPC64LoweredAtomicLoad32
+	OpPPC64LoweredAtomicLoad64
+	OpPPC64LoweredAtomicLoadPtr
+	OpPPC64LoweredAtomicAdd32
+	OpPPC64LoweredAtomicAdd64
+	OpPPC64LoweredAtomicExchange32
+	OpPPC64LoweredAtomicExchange64
+	OpPPC64LoweredAtomicCas64
+	OpPPC64LoweredAtomicCas32
+	OpPPC64LoweredAtomicAnd8
+	OpPPC64LoweredAtomicOr8
 	OpPPC64InvertFlags
 	OpPPC64FlagEQ
 	OpPPC64FlagLT
@@ -1372,6 +1411,10 @@ const (
 	OpS390XFDIV
 	OpS390XFNEGS
 	OpS390XFNEG
+	OpS390XFMADDS
+	OpS390XFMADD
+	OpS390XFMSUBS
+	OpS390XFMSUB
 	OpS390XFMOVSload
 	OpS390XFMOVDload
 	OpS390XFMOVSconst
@@ -1529,13 +1572,13 @@ const (
 	OpS390XCLEAR
 	OpS390XCALLstatic
 	OpS390XCALLclosure
-	OpS390XCALLdefer
-	OpS390XCALLgo
 	OpS390XCALLinter
 	OpS390XInvertFlags
 	OpS390XLoweredGetG
 	OpS390XLoweredGetClosurePtr
 	OpS390XLoweredNilCheck
+	OpS390XLoweredRound32F
+	OpS390XLoweredRound64F
 	OpS390XMOVDconvert
 	OpS390XFlagEQ
 	OpS390XFlagLT
@@ -1584,16 +1627,13 @@ const (
 	OpMul64F
 	OpDiv32F
 	OpDiv64F
-	OpHmul8
-	OpHmul8u
-	OpHmul16
-	OpHmul16u
 	OpHmul32
 	OpHmul32u
 	OpHmul64
 	OpHmul64u
 	OpMul32uhilo
 	OpMul64uhilo
+	OpAvg32u
 	OpAvg64u
 	OpDiv8
 	OpDiv8u
@@ -1672,10 +1712,6 @@ const (
 	OpRsh64Ux16
 	OpRsh64Ux32
 	OpRsh64Ux64
-	OpLrot8
-	OpLrot16
-	OpLrot32
-	OpLrot64
 	OpEq8
 	OpEq16
 	OpEq32
@@ -1751,8 +1787,18 @@ const (
 	OpCom64
 	OpCtz32
 	OpCtz64
+	OpBitLen32
+	OpBitLen64
 	OpBswap32
 	OpBswap64
+	OpBitRev8
+	OpBitRev16
+	OpBitRev32
+	OpBitRev64
+	OpPopCount8
+	OpPopCount16
+	OpPopCount32
+	OpPopCount64
 	OpSqrt
 	OpPhi
 	OpCopy
@@ -1773,19 +1819,15 @@ const (
 	OpAddr
 	OpSP
 	OpSB
-	OpFunc
 	OpLoad
 	OpStore
 	OpMove
 	OpZero
 	OpStoreWB
 	OpMoveWB
-	OpMoveWBVolatile
 	OpZeroWB
 	OpClosureCall
 	OpStaticCall
-	OpDeferCall
-	OpGoCall
 	OpInterCall
 	OpSignExt8to16
 	OpSignExt8to32
@@ -1815,6 +1857,8 @@ const (
 	OpCvt64Fto64
 	OpCvt32Fto64F
 	OpCvt64Fto32F
+	OpRound32F
+	OpRound64F
 	OpIsNonNil
 	OpIsInBounds
 	OpIsSliceInBounds
@@ -1887,6 +1931,7 @@ const (
 	OpAtomicCompareAndSwap64
 	OpAtomicAnd8
 	OpAtomicOr8
+	OpClobber
 )
 
 var opcodeTable = [...]opInfo{
@@ -2025,6 +2070,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -2040,6 +2086,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -2075,10 +2122,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSloadidx1",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2090,10 +2138,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSloadidx4",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSloadidx4",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2105,10 +2154,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDloadidx1",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2120,10 +2170,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDloadidx8",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDloadidx8",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2139,6 +2190,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -2152,6 +2204,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -2161,10 +2214,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2174,10 +2228,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSstoreidx4",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSstoreidx4",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2187,10 +2242,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2200,10 +2256,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDstoreidx8",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDstoreidx8",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -2441,6 +2498,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "HMULL",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
 		asm:          x86.AIMULL,
 		reg: regInfo{
@@ -2457,6 +2515,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "HMULLU",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
 		asm:          x86.AMULL,
 		reg: regInfo{
@@ -2471,82 +2530,35 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "HMULW",
-		argLen:       2,
-		clobberFlags: true,
-		asm:          x86.AIMULW,
-		reg: regInfo{
-			inputs: []inputInfo{
-				{0, 1},   // AX
-				{1, 255}, // AX CX DX BX SP BP SI DI
-			},
-			clobbers: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULB",
-		argLen:       2,
-		clobberFlags: true,
-		asm:          x86.AIMULB,
-		reg: regInfo{
-			inputs: []inputInfo{
-				{0, 1},   // AX
-				{1, 255}, // AX CX DX BX SP BP SI DI
-			},
-			clobbers: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULWU",
-		argLen:       2,
-		clobberFlags: true,
-		asm:          x86.AMULW,
-		reg: regInfo{
-			inputs: []inputInfo{
-				{0, 1},   // AX
-				{1, 255}, // AX CX DX BX SP BP SI DI
-			},
-			clobbers: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULBU",
+		name:         "MULLQU",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
-		asm:          x86.AMULB,
+		asm:          x86.AMULL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1},   // AX
 				{1, 255}, // AX CX DX BX SP BP SI DI
 			},
-			clobbers: 1, // AX
 			outputs: []outputInfo{
 				{0, 4}, // DX
+				{1, 1}, // AX
 			},
 		},
 	},
 	{
-		name:         "MULLQU",
+		name:         "AVGLU",
 		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
 		clobberFlags: true,
-		asm:          x86.AMULL,
 		reg: regInfo{
 			inputs: []inputInfo{
-				{0, 1},   // AX
-				{1, 255}, // AX CX DX BX SP BP SI DI
+				{0, 239}, // AX CX DX BX BP SI DI
+				{1, 239}, // AX CX DX BX BP SI DI
 			},
 			outputs: []outputInfo{
-				{0, 4}, // DX
-				{1, 1}, // AX
+				{0, 239}, // AX CX DX BX BP SI DI
 			},
 		},
 	},
@@ -2868,9 +2880,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTL",
-		argLen: 2,
-		asm:    x86.ATESTL,
+		name:        "TESTL",
+		argLen:      2,
+		commutative: true,
+		asm:         x86.ATESTL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 255}, // AX CX DX BX SP BP SI DI
@@ -2879,9 +2892,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTW",
-		argLen: 2,
-		asm:    x86.ATESTW,
+		name:        "TESTW",
+		argLen:      2,
+		commutative: true,
+		asm:         x86.ATESTW,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 255}, // AX CX DX BX SP BP SI DI
@@ -2890,9 +2904,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTB",
-		argLen: 2,
-		asm:    x86.ATESTB,
+		name:        "TESTB",
+		argLen:      2,
+		commutative: true,
+		asm:         x86.ATESTB,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 255}, // AX CX DX BX SP BP SI DI
@@ -3661,6 +3676,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 65791}, // AX CX DX BX SP BP SI DI SB
@@ -3671,9 +3687,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAL1",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:        "LEAL1",
+		auxType:     auxSymOff,
+		argLen:      2,
+		commutative: true,
+		symEffect:   SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3685,9 +3703,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAL2",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAL2",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3699,9 +3718,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAL4",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAL4",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3713,9 +3733,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAL8",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAL8",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3731,6 +3752,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVBLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3746,6 +3768,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVBLSX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3761,6 +3784,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVWLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3776,6 +3800,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVWLSX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3791,6 +3816,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3806,6 +3832,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3819,6 +3846,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3832,6 +3860,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3841,10 +3870,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVBLZX,
+		name:        "MOVBloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		asm:         x86.AMOVBLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3856,10 +3887,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVWLZX,
+		name:        "MOVWloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		asm:         x86.AMOVWLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3871,10 +3904,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWloadidx2",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVWLZX,
+		name:      "MOVWloadidx2",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVWLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3886,10 +3920,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:        "MOVLloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		asm:         x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3901,10 +3937,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLloadidx4",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLloadidx4",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3916,10 +3953,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVB,
+		name:        "MOVBstoreidx1",
+		auxType:     auxSymOff,
+		argLen:      4,
+		commutative: true,
+		symEffect:   SymWrite,
+		asm:         x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3929,10 +3968,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVW,
+		name:        "MOVWstoreidx1",
+		auxType:     auxSymOff,
+		argLen:      4,
+		commutative: true,
+		symEffect:   SymWrite,
+		asm:         x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3942,10 +3983,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreidx2",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreidx2",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3955,10 +3997,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVL,
+		name:        "MOVLstoreidx1",
+		auxType:     auxSymOff,
+		argLen:      4,
+		commutative: true,
+		symEffect:   SymWrite,
+		asm:         x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3968,10 +4012,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreidx4",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreidx4",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -3985,6 +4030,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -3997,6 +4043,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4009,6 +4056,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4017,10 +4065,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVB,
+		name:      "MOVBstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		asm:       x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -4029,10 +4078,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		asm:       x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -4041,10 +4091,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreconstidx2",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreconstidx2",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		asm:       x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -4053,10 +4104,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		asm:       x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -4065,10 +4117,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreconstidx4",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreconstidx4",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		asm:       x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 255},   // AX CX DX BX SP BP SI DI
@@ -4077,9 +4130,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "DUFFZERO",
-		auxType: auxInt64,
-		argLen:  3,
+		name:           "DUFFZERO",
+		auxType:        auxInt64,
+		argLen:         3,
+		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -4089,8 +4143,9 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "REPSTOSL",
-		argLen: 4,
+		name:           "REPSTOSL",
+		argLen:         4,
+		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -4106,6 +4161,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
 		},
@@ -4125,26 +4181,6 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
-		},
-	},
-	{
 		name:         "CALLinter",
 		auxType:      auxInt64,
 		argLen:       2,
@@ -4158,10 +4194,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "DUFFCOPY",
-		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
+		name:           "DUFFCOPY",
+		auxType:        auxInt64,
+		argLen:         3,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -4171,8 +4209,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "REPMOVSL",
-		argLen: 4,
+		name:           "REPMOVSL",
+		argLen:         4,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -4443,6 +4483,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4458,6 +4499,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4493,10 +4535,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSloadidx1",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -4508,10 +4551,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSloadidx4",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSloadidx4",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -4523,10 +4567,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDloadidx1",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -4538,10 +4583,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDloadidx8",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDloadidx8",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -4557,6 +4603,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVSS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4570,6 +4617,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVSD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -4579,10 +4627,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -4592,10 +4641,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSSstoreidx4",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSS,
+		name:      "MOVSSstoreidx4",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -4605,10 +4655,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -4618,10 +4669,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVSDstoreidx8",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVSD,
+		name:      "MOVSDstoreidx8",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -4631,6 +4683,114 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:           "ADDSDmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:           "ADDSSmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:           "SUBSSmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		asm:            x86.ASUBSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:           "SUBSDmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		asm:            x86.ASUBSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:           "MULSSmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:           "MULSDmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
 		name:         "ADDQ",
 		argLen:       2,
 		commutative:  true,
@@ -4825,6 +4985,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "HMULQ",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
 		asm:          x86.AIMULQ,
 		reg: regInfo{
@@ -4841,6 +5002,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "HMULL",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
 		asm:          x86.AIMULL,
 		reg: regInfo{
@@ -4855,10 +5017,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "HMULW",
+		name:         "HMULQU",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
-		asm:          x86.AIMULW,
+		asm:          x86.AMULQ,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1},     // AX
@@ -4871,10 +5034,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "HMULB",
+		name:         "HMULLU",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
-		asm:          x86.AIMULB,
+		asm:          x86.AMULL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1},     // AX
@@ -4887,79 +5051,15 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "HMULQU",
+		name:         "AVGQU",
 		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
 		clobberFlags: true,
-		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: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULLU",
-		argLen:       2,
-		clobberFlags: true,
-		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: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULWU",
-		argLen:       2,
-		clobberFlags: true,
-		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: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "HMULBU",
-		argLen:       2,
-		clobberFlags: true,
-		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: 1, // AX
-			outputs: []outputInfo{
-				{0, 4}, // DX
-			},
-		},
-	},
-	{
-		name:         "AVGQU",
-		argLen:       2,
-		commutative:  true,
-		resultInArg0: true,
-		clobberFlags: 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
+				{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
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -5065,6 +5165,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "MULQU2",
 		argLen:       2,
+		commutative:  true,
 		clobberFlags: true,
 		asm:          x86.AMULQ,
 		reg: regInfo{
@@ -5404,9 +5505,9 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTQ",
+		name:   "BTL",
 		argLen: 2,
-		asm:    x86.ATESTQ,
+		asm:    x86.ABTL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -5415,9 +5516,9 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTL",
+		name:   "BTQ",
 		argLen: 2,
-		asm:    x86.ATESTL,
+		asm:    x86.ABTQ,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -5426,9 +5527,32 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTW",
-		argLen: 2,
-		asm:    x86.ATESTW,
+		name:    "BTLconst",
+		auxType: auxInt8,
+		argLen:  1,
+		asm:     x86.ABTL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "BTQconst",
+		auxType: auxInt8,
+		argLen:  1,
+		asm:     x86.ABTQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:        "TESTQ",
+		argLen:      2,
+		commutative: true,
+		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
@@ -5437,9 +5561,34 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "TESTB",
-		argLen: 2,
-		asm:    x86.ATESTB,
+		name:        "TESTL",
+		argLen:      2,
+		commutative: true,
+		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
+			},
+		},
+	},
+	{
+		name:        "TESTW",
+		argLen:      2,
+		commutative: true,
+		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
+			},
+		},
+	},
+	{
+		name:        "TESTB",
+		argLen:      2,
+		commutative: true,
+		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
@@ -5525,7 +5674,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SHLQconst",
-		auxType:      auxInt64,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5541,7 +5690,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SHLLconst",
-		auxType:      auxInt32,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5621,7 +5770,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SHRQconst",
-		auxType:      auxInt64,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5637,7 +5786,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SHRLconst",
-		auxType:      auxInt32,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5653,7 +5802,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SHRWconst",
-		auxType:      auxInt16,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5749,7 +5898,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SARQconst",
-		auxType:      auxInt64,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5765,7 +5914,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SARLconst",
-		auxType:      auxInt32,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5781,7 +5930,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SARWconst",
-		auxType:      auxInt16,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5812,8 +5961,136 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:         "ROLQ",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.AROLQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLL",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.AROLL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLW",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.AROLW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLB",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.AROLB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "RORQ",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.ARORQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "RORL",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.ARORL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "RORW",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.ARORW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "RORB",
+		argLen:       2,
+		resultInArg0: true,
+		clobberFlags: true,
+		asm:          x86.ARORB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
 		name:         "ROLQconst",
-		auxType:      auxInt64,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5829,7 +6106,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "ROLLconst",
-		auxType:      auxInt32,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5845,7 +6122,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "ROLWconst",
-		auxType:      auxInt16,
+		auxType:      auxInt8,
 		argLen:       1,
 		resultInArg0: true,
 		clobberFlags: true,
@@ -5876,6 +6153,196 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:           "ADDLmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		asm:            x86.AADDL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "ADDQmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		asm:            x86.AADDQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "SUBQmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "SUBLmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "ANDLmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "ANDQmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "ORQmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "ORLmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "XORQmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:           "XORLmem",
+		auxType:        auxSymOff,
+		argLen:         3,
+		resultInArg0:   true,
+		clobberFlags:   true,
+		faultOnNilArg1: true,
+		symEffect:      SymRead,
+		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, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
 		name:         "NEGQ",
 		argLen:       1,
 		resultInArg0: true,
@@ -5964,14 +6431,72 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		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
+			},
+			outputs: []outputInfo{
+				{1, 0},
+				{0, 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
+			},
+			outputs: []outputInfo{
+				{1, 0},
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
 		name:         "CMOVQEQ",
 		argLen:       3,
 		resultInArg0: true,
-		asm:          x86.ACMOVQEQ,
+		asm:          x86.ACMOVQEQ,
+		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
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVLEQ",
+		argLen:       3,
+		resultInArg0: true,
+		asm:          x86.ACMOVLEQ,
+		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
+			},
+			outputs: []outputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "BSWAPQ",
+		argLen:       1,
+		resultInArg0: true,
+		clobberFlags: 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
-				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -5979,14 +6504,14 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CMOVLEQ",
-		argLen:       3,
+		name:         "BSWAPL",
+		argLen:       1,
 		resultInArg0: true,
-		asm:          x86.ACMOVLEQ,
+		clobberFlags: 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
-				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -5994,11 +6519,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "BSWAPQ",
+		name:         "POPCNTQ",
 		argLen:       1,
-		resultInArg0: true,
 		clobberFlags: true,
-		asm:          x86.ABSWAPQ,
+		asm:          x86.APOPCNTQ,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6009,11 +6533,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "BSWAPL",
+		name:         "POPCNTL",
 		argLen:       1,
-		resultInArg0: true,
 		clobberFlags: true,
-		asm:          x86.ABSWAPL,
+		asm:          x86.APOPCNTL,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6473,6 +6996,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               x86.ALEAQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6484,9 +7008,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAQ1",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:        "LEAQ1",
+		auxType:     auxSymOff,
+		argLen:      2,
+		commutative: true,
+		symEffect:   SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6498,9 +7024,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAQ2",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAQ2",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6512,9 +7039,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAQ4",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAQ4",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6526,9 +7054,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "LEAQ8",
-		auxType: auxSymOff,
-		argLen:  2,
+		name:      "LEAQ8",
+		auxType:   auxSymOff,
+		argLen:    2,
+		symEffect: SymAddr,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -6544,6 +7073,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               x86.ALEAL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6559,6 +7089,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVBLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6574,6 +7105,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVBQSX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6589,6 +7121,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVWLZX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6604,6 +7137,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVWQSX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6619,6 +7153,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6634,6 +7169,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVLQSX,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6649,6 +7185,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6664,6 +7201,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6677,6 +7215,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6690,6 +7229,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6703,6 +7243,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6716,6 +7257,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVUPS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6731,6 +7273,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVUPS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6740,10 +7283,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVBLZX,
+		name:        "MOVBloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		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
@@ -6755,10 +7300,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVWLZX,
+		name:        "MOVWloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		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
@@ -6770,10 +7317,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWloadidx2",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVWLZX,
+		name:      "MOVWloadidx2",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -6785,10 +7333,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:        "MOVLloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		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
@@ -6800,10 +7350,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLloadidx4",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLloadidx4",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -6815,10 +7366,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQloadidx1",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVQ,
+		name:        "MOVQloadidx1",
+		auxType:     auxSymOff,
+		argLen:      3,
+		commutative: true,
+		symEffect:   SymRead,
+		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
@@ -6830,10 +7383,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQloadidx8",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     x86.AMOVQ,
+		name:      "MOVQloadidx8",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		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
@@ -6845,10 +7399,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVB,
+		name:      "MOVBstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6858,10 +7413,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6871,10 +7427,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreidx2",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreidx2",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6884,10 +7441,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6897,10 +7455,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreidx4",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreidx4",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6910,10 +7469,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQstoreidx1",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVQ,
+		name:      "MOVQstoreidx1",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6923,10 +7483,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQstoreidx8",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     x86.AMOVQ,
+		name:      "MOVQstoreidx8",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		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
@@ -6940,6 +7501,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6952,6 +7514,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6964,6 +7527,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6976,6 +7540,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymValAndOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            x86.AMOVQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -6984,10 +7549,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVBstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVB,
+		name:      "MOVBstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -6996,10 +7562,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7008,10 +7575,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVWstoreconstidx2",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVW,
+		name:      "MOVWstoreconstidx2",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7020,10 +7588,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7032,10 +7601,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVLstoreconstidx4",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVL,
+		name:      "MOVLstoreconstidx4",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7044,10 +7614,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQstoreconstidx1",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVQ,
+		name:      "MOVQstoreconstidx1",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7056,10 +7627,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "MOVQstoreconstidx8",
-		auxType: auxSymValAndOff,
-		argLen:  3,
-		asm:     x86.AMOVQ,
+		name:      "MOVQstoreconstidx8",
+		auxType:   auxSymValAndOff,
+		argLen:    3,
+		symEffect: SymWrite,
+		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
@@ -7068,10 +7640,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "DUFFZERO",
-		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
+		name:           "DUFFZERO",
+		auxType:        auxInt64,
+		argLen:         3,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128},   // DI
@@ -7092,8 +7665,9 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "REPSTOSQ",
-		argLen: 4,
+		name:           "REPSTOSQ",
+		argLen:         4,
+		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -7109,6 +7683,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 4294967279, // 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
 		},
@@ -7128,26 +7703,6 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4294967279, // 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
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4294967279, // 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
-		},
-	},
-	{
 		name:         "CALLinter",
 		auxType:      auxInt64,
 		argLen:       2,
@@ -7161,10 +7716,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "DUFFCOPY",
-		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
+		name:           "DUFFCOPY",
+		auxType:        auxInt64,
+		argLen:         3,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -7174,8 +7731,10 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "REPMOVSQ",
-		argLen: 4,
+		name:           "REPMOVSQ",
+		argLen:         4,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 128}, // DI
@@ -7276,6 +7835,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7291,6 +7851,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            x86.AMOVQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7308,11 +7869,12 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		faultOnNilArg1: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AXCHGL,
 		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
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -7326,11 +7888,12 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		faultOnNilArg1: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AXCHGQ,
 		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
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -7345,11 +7908,12 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg1: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AXADDL,
 		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
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -7364,11 +7928,12 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg1: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AXADDQ,
 		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
+				{0, 65519},      // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
 			},
 			outputs: []outputInfo{
 				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
@@ -7392,6 +7957,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.ACMPXCHGL,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7413,6 +7979,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.ACMPXCHGQ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7434,6 +8001,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AANDB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7449,6 +8017,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            x86.AORB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -7589,7 +8158,7 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "UDIVrtcall",
+		name:         "CALLudiv",
 		argLen:       2,
 		clobberFlags: true,
 		reg: regInfo{
@@ -8079,6 +8648,32 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:   "REV",
+		argLen: 1,
+		asm:    arm.AREV,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+			},
+			outputs: []outputInfo{
+				{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+			},
+		},
+	},
+	{
+		name:   "RBIT",
+		argLen: 1,
+		asm:    arm.ARBIT,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+			},
+			outputs: []outputInfo{
+				{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+			},
+		},
+	},
+	{
 		name:   "SLL",
 		argLen: 2,
 		asm:    arm.ASLL,
@@ -9707,6 +10302,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               arm.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9722,6 +10318,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9737,6 +10334,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVBU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9752,6 +10350,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9767,6 +10366,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVHU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9782,6 +10382,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9797,6 +10398,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9812,6 +10414,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9827,6 +10430,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9840,6 +10444,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9853,6 +10458,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9866,6 +10472,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -9879,6 +10486,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -10263,6 +10871,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 4294924287, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
 		},
@@ -10282,26 +10891,6 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4294924287, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4294924287, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
-		},
-	},
-	{
 		name:         "CALLinter",
 		auxType:      auxInt64,
 		argLen:       2,
@@ -11741,6 +12330,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               arm64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11756,6 +12346,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11771,6 +12362,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVBU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11786,6 +12378,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11801,6 +12394,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVHU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11816,6 +12410,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11831,6 +12426,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVWU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11846,6 +12442,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11861,6 +12458,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11876,6 +12474,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            arm64.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11891,6 +12490,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11904,6 +12504,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11917,6 +12518,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11930,6 +12532,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11943,6 +12546,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11956,6 +12560,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11969,6 +12574,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11981,6 +12587,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -11993,6 +12600,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -12005,6 +12613,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            arm64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -12383,6 +12992,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 9223372035512336383, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
 		},
@@ -12402,26 +13012,6 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 9223372035512336383, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 9223372035512336383, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
-		},
-	},
-	{
 		name:         "CALLinter",
 		auxType:      auxInt64,
 		argLen:       2,
@@ -13526,6 +14116,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13541,6 +14132,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13556,6 +14148,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVBU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13571,6 +14164,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13586,6 +14180,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVHU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13601,6 +14196,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13616,6 +14212,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13631,6 +14228,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13646,6 +14244,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13659,6 +14258,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13672,6 +14272,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13685,6 +14286,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13698,6 +14300,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13711,6 +14314,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13723,6 +14327,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13735,6 +14340,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -13935,13 +14541,14 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 140737421246462, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31 F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 HI LO
 		},
 	},
 	{
 		name:         "CALLclosure",
-		auxType:      auxInt32,
+		auxType:      auxInt64,
 		argLen:       3,
 		clobberFlags: true,
 		call:         true,
@@ -13954,28 +14561,8 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt32,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 140737421246462, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31 F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 HI LO
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt32,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 140737421246462, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31 F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 HI LO
-		},
-	},
-	{
 		name:         "CALLinter",
-		auxType:      auxInt32,
+		auxType:      auxInt64,
 		argLen:       2,
 		clobberFlags: true,
 		call:         true,
@@ -14829,6 +15416,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               mips.AMOVV,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14844,6 +15432,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14859,6 +15448,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVBU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14874,6 +15464,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14889,6 +15480,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVHU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14904,6 +15496,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14919,6 +15512,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVWU,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14934,6 +15528,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVV,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14949,6 +15544,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14964,6 +15560,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            mips.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14979,6 +15576,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -14992,6 +15590,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15005,6 +15604,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15018,6 +15618,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVV,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15031,6 +15632,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVF,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15044,6 +15646,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15057,6 +15660,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15069,6 +15673,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15081,6 +15686,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15093,6 +15699,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            mips.AMOVV,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -15340,6 +15947,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 4611686018393833470, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 HI LO
 		},
@@ -15359,26 +15967,6 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4611686018393833470, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 HI LO
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4611686018393833470, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 HI LO
-		},
-	},
-	{
 		name:         "CALLinter",
 		auxType:      auxInt64,
 		argLen:       2,
@@ -15501,10 +16089,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "ADDconst",
-		auxType: auxSymOff,
-		argLen:  1,
-		asm:     ppc64.AADD,
+		name:      "ADDconst",
+		auxType:   auxSymOff,
+		argLen:    1,
+		symEffect: SymAddr,
+		asm:       ppc64.AADD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
@@ -15707,6 +16296,66 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:   "FMADD",
+		argLen: 3,
+		asm:    ppc64.AFMADD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
+		name:   "FMADDS",
+		argLen: 3,
+		asm:    ppc64.AFMADDS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
+		name:   "FMSUB",
+		argLen: 3,
+		asm:    ppc64.AFMSUB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
+		name:   "FMSUBS",
+		argLen: 3,
+		asm:    ppc64.AFMSUBS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+				{2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
 		name:   "SRAD",
 		argLen: 2,
 		asm:    ppc64.ASRAD,
@@ -15897,6 +16546,101 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:    "ROTLconst",
+		auxType: auxInt64,
+		argLen:  1,
+		asm:     ppc64.AROTL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:    "ROTLWconst",
+		auxType: auxInt64,
+		argLen:  1,
+		asm:     ppc64.AROTLW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:         "CNTLZD",
+		argLen:       1,
+		clobberFlags: true,
+		asm:          ppc64.ACNTLZD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:         "CNTLZW",
+		argLen:       1,
+		clobberFlags: true,
+		asm:          ppc64.ACNTLZW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:   "POPCNTD",
+		argLen: 1,
+		asm:    ppc64.APOPCNTD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:   "POPCNTW",
+		argLen: 1,
+		asm:    ppc64.APOPCNTW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:   "POPCNTB",
+		argLen: 1,
+		asm:    ppc64.APOPCNTB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
 		name:   "FDIV",
 		argLen: 2,
 		asm:    ppc64.AFDIV,
@@ -16033,9 +16777,8 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:        "Xf2i64",
-		argLen:      1,
-		usesScratch: true,
+		name:   "Xf2i64",
+		argLen: 1,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
@@ -16046,9 +16789,8 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:        "Xi2f64",
-		argLen:      1,
-		usesScratch: true,
+		name:   "Xi2f64",
+		argLen: 1,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
@@ -16117,6 +16859,21 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:        "NOR",
+		argLen:      2,
+		commutative: true,
+		asm:         ppc64.ANOR,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
 		name:        "XOR",
 		argLen:      2,
 		commutative: true,
@@ -16335,6 +17092,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVBZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16350,6 +17108,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16365,6 +17124,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVHZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16380,6 +17140,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16395,6 +17156,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVWZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16410,6 +17172,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16425,6 +17188,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16440,6 +17204,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            ppc64.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16455,6 +17220,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16468,6 +17234,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16481,6 +17248,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16494,6 +17262,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16507,6 +17276,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16520,6 +17290,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16533,6 +17304,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16545,6 +17317,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16557,6 +17330,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16569,6 +17343,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            ppc64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16581,6 +17356,7 @@ var opcodeTable = [...]opInfo{
 		auxType:           auxSymOff,
 		argLen:            1,
 		rematerializeable: true,
+		symEffect:         SymAddr,
 		asm:               ppc64.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -16817,33 +17593,208 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:   "LoweredGetClosurePtr",
-		argLen: 0,
+		name:   "LoweredGetClosurePtr",
+		argLen: 0,
+		reg: regInfo{
+			outputs: []outputInfo{
+				{0, 2048}, // R11
+			},
+		},
+	},
+	{
+		name:           "LoweredNilCheck",
+		argLen:         2,
+		clobberFlags:   true,
+		nilCheck:       true,
+		faultOnNilArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			clobbers: 2147483648, // R31
+		},
+	},
+	{
+		name:         "LoweredRound32F",
+		argLen:       1,
+		resultInArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
+		name:         "LoweredRound64F",
+		argLen:       1,
+		resultInArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+			outputs: []outputInfo{
+				{0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			},
+		},
+	},
+	{
+		name:   "MOVDconvert",
+		argLen: 2,
+		asm:    ppc64.AMOVD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:         "CALLstatic",
+		auxType:      auxSymOff,
+		argLen:       1,
+		clobberFlags: true,
+		call:         true,
+		symEffect:    SymNone,
+		reg: regInfo{
+			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+		},
+	},
+	{
+		name:         "CALLclosure",
+		auxType:      auxInt64,
+		argLen:       3,
+		clobberFlags: true,
+		call:         true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2048},       // R11
+				{0, 1073733626}, // SP R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+		},
+	},
+	{
+		name:         "CALLinter",
+		auxType:      auxInt64,
+		argLen:       2,
+		clobberFlags: true,
+		call:         true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+		},
+	},
+	{
+		name:           "LoweredZero",
+		auxType:        auxInt64,
+		argLen:         2,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8}, // R3
+			},
+			clobbers: 8, // R3
+		},
+	},
+	{
+		name:           "LoweredMove",
+		auxType:        auxInt64,
+		argLen:         3,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8},  // R3
+				{1, 16}, // R4
+			},
+			clobbers: 1944, // R3 R4 R7 R8 R9 R10
+		},
+	},
+	{
+		name:           "LoweredAtomicStore32",
+		argLen:         3,
+		faultOnNilArg0: true,
+		hasSideEffects: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:           "LoweredAtomicStore64",
+		argLen:         3,
+		faultOnNilArg0: true,
+		hasSideEffects: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:           "LoweredAtomicLoad32",
+		argLen:         2,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+		},
+	},
+	{
+		name:           "LoweredAtomicLoad64",
+		argLen:         2,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
 		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
 			outputs: []outputInfo{
-				{0, 2048}, // R11
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
 		},
 	},
 	{
-		name:           "LoweredNilCheck",
+		name:           "LoweredAtomicLoadPtr",
 		argLen:         2,
 		clobberFlags:   true,
-		nilCheck:       true,
 		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
-			clobbers: 2147483648, // R31
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
 		},
 	},
 	{
-		name:   "MOVDconvert",
-		argLen: 2,
-		asm:    ppc64.AMOVD,
+		name:            "LoweredAtomicAdd32",
+		argLen:          3,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
 			inputs: []inputInfo{
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
 			outputs: []outputInfo{
@@ -16852,90 +17803,116 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "CALLstatic",
-		auxType:      auxSymOff,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
+		name:            "LoweredAtomicAdd64",
+		argLen:          3,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
-			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			inputs: []inputInfo{
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
 		},
 	},
 	{
-		name:         "CALLclosure",
-		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
-		call:         true,
+		name:            "LoweredAtomicExchange32",
+		argLen:          3,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
 			inputs: []inputInfo{
-				{1, 2048},       // R11
-				{0, 1073733626}, // SP R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
-			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
 		},
 	},
 	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
+		name:            "LoweredAtomicExchange64",
+		argLen:          3,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
-			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			inputs: []inputInfo{
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
 		},
 	},
 	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
+		name:            "LoweredAtomicCas64",
+		argLen:          4,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
-			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+			inputs: []inputInfo{
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{2, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
+				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
 		},
 	},
 	{
-		name:         "CALLinter",
-		auxType:      auxInt64,
-		argLen:       2,
-		clobberFlags: true,
-		call:         true,
+		name:            "LoweredAtomicCas32",
+		argLen:          4,
+		resultNotInArgs: true,
+		clobberFlags:    true,
+		faultOnNilArg0:  true,
+		hasSideEffects:  true,
 		reg: regInfo{
 			inputs: []inputInfo{
+				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{2, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+			},
+			outputs: []outputInfo{
 				{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
-			clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
 		},
 	},
 	{
-		name:           "LoweredZero",
-		auxType:        auxInt64,
+		name:           "LoweredAtomicAnd8",
 		argLen:         3,
-		clobberFlags:   true,
 		faultOnNilArg0: true,
+		hasSideEffects: true,
+		asm:            ppc64.AAND,
 		reg: regInfo{
 			inputs: []inputInfo{
-				{0, 8},          // R3
-				{1, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
-			clobbers: 8, // R3
 		},
 	},
 	{
-		name:           "LoweredMove",
-		auxType:        auxInt64,
-		argLen:         4,
-		clobberFlags:   true,
+		name:           "LoweredAtomicOr8",
+		argLen:         3,
 		faultOnNilArg0: true,
-		faultOnNilArg1: true,
+		hasSideEffects: true,
+		asm:            ppc64.AOR,
 		reg: regInfo{
 			inputs: []inputInfo{
-				{0, 8},          // R3
-				{1, 16},         // R4
-				{2, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+				{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
 			},
-			clobbers: 24, // R3 R4
 		},
 	},
 	{
@@ -17116,10 +18093,75 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:         "FMADDS",
+		argLen:       3,
+		resultInArg0: true,
+		asm:          s390x.AFMADDS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
+		name:         "FMADD",
+		argLen:       3,
+		resultInArg0: true,
+		asm:          s390x.AFMADD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
+		name:         "FMSUBS",
+		argLen:       3,
+		resultInArg0: true,
+		asm:          s390x.AFMSUBS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
+		name:         "FMSUB",
+		argLen:       3,
+		resultInArg0: true,
+		asm:          s390x.AFMSUB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+				{2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
 		name:           "FMOVSload",
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17135,6 +18177,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17170,10 +18213,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "FMOVSloadidx",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     s390x.AFMOVS,
+		name:      "FMOVSloadidx",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       s390x.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
@@ -17185,10 +18229,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "FMOVDloadidx",
-		auxType: auxSymOff,
-		argLen:  3,
-		asm:     s390x.AFMOVD,
+		name:      "FMOVDloadidx",
+		auxType:   auxSymOff,
+		argLen:    3,
+		symEffect: SymRead,
+		asm:       s390x.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
@@ -17204,6 +18249,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17217,6 +18263,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         3,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17226,10 +18273,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "FMOVSstoreidx",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     s390x.AFMOVS,
+		name:      "FMOVSstoreidx",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       s390x.AFMOVS,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 54270},      // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
@@ -17239,10 +18287,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:    "FMOVDstoreidx",
-		auxType: auxSymOff,
-		argLen:  4,
-		asm:     s390x.AFMOVD,
+		name:      "FMOVDstoreidx",
+		auxType:   auxSymOff,
+		argLen:    4,
+		symEffect: SymWrite,
+		asm:       s390x.AFMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 54270},      // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
@@ -17320,6 +18369,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AADD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17338,6 +18388,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AADDW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17418,6 +18469,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.ASUB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17436,6 +18488,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.ASUBW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17520,6 +18573,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMULLD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17538,6 +18592,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMULLW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17552,6 +18607,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "MULHD",
 		argLen:       2,
+		commutative:  true,
 		resultInArg0: true,
 		clobberFlags: true,
 		asm:          s390x.AMULHD,
@@ -17568,6 +18624,7 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "MULHDU",
 		argLen:       2,
+		commutative:  true,
 		resultInArg0: true,
 		clobberFlags: true,
 		asm:          s390x.AMULHDU,
@@ -17780,6 +18837,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AAND,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17798,6 +18856,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AANDW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17880,6 +18939,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AOR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17898,6 +18958,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AORW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17980,6 +19041,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AXOR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -17998,6 +19060,7 @@ var opcodeTable = [...]opInfo{
 		resultInArg0:   true,
 		clobberFlags:   true,
 		faultOnNilArg1: true,
+		symEffect:      SymRead,
 		asm:            s390x.AXORW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18149,7 +19212,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "SLDconst",
-		auxType: auxInt64,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ASLD,
 		reg: regInfo{
@@ -18163,7 +19226,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "SLWconst",
-		auxType: auxInt32,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ASLW,
 		reg: regInfo{
@@ -18205,7 +19268,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "SRDconst",
-		auxType: auxInt64,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ASRD,
 		reg: regInfo{
@@ -18219,7 +19282,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "SRWconst",
-		auxType: auxInt32,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ASRW,
 		reg: regInfo{
@@ -18263,7 +19326,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SRADconst",
-		auxType:      auxInt64,
+		auxType:      auxInt8,
 		argLen:       1,
 		clobberFlags: true,
 		asm:          s390x.ASRAD,
@@ -18278,7 +19341,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:         "SRAWconst",
-		auxType:      auxInt32,
+		auxType:      auxInt8,
 		argLen:       1,
 		clobberFlags: true,
 		asm:          s390x.ASRAW,
@@ -18293,7 +19356,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "RLLGconst",
-		auxType: auxInt64,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ARLLG,
 		reg: regInfo{
@@ -18307,7 +19370,7 @@ var opcodeTable = [...]opInfo{
 	},
 	{
 		name:    "RLLconst",
-		auxType: auxInt32,
+		auxType: auxInt8,
 		argLen:  1,
 		asm:     s390x.ARLL,
 		reg: regInfo{
@@ -18780,6 +19843,7 @@ var opcodeTable = [...]opInfo{
 		argLen:            1,
 		rematerializeable: true,
 		clobberFlags:      true,
+		symEffect:         SymRead,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 4295000064}, // SP SB
@@ -18794,6 +19858,7 @@ var opcodeTable = [...]opInfo{
 		auxType:      auxSymOff,
 		argLen:       2,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 4295000064}, // SP SB
@@ -18810,6 +19875,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVBZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18826,6 +19892,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18842,6 +19909,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVHZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18858,6 +19926,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18874,6 +19943,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVWZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18890,6 +19960,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18906,6 +19977,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18948,6 +20020,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVHBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18964,6 +20037,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVWBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18980,6 +20054,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVDBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -18996,6 +20071,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19010,6 +20086,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19024,6 +20101,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19038,6 +20116,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19052,6 +20131,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVHBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19066,6 +20146,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVWBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19080,6 +20161,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVDBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19095,6 +20177,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		faultOnNilArg1: true,
+		symEffect:      SymNone,
 		asm:            s390x.AMVC,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19107,7 +20190,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVBZloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVBZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19123,7 +20208,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVHZloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVHZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19139,7 +20226,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVWZloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVWZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19155,7 +20244,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVDloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19171,7 +20262,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVHBRloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVHBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19187,7 +20280,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVWBRloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVWBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19203,7 +20298,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVDBRloadidx",
 		auxType:      auxSymOff,
 		argLen:       3,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymRead,
 		asm:          s390x.AMOVDBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19219,7 +20316,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVBstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19233,7 +20332,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVHstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19247,7 +20348,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVWstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19261,7 +20364,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVDstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19275,7 +20380,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVHBRstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVHBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19289,7 +20396,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVWBRstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVWBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19303,7 +20412,9 @@ var opcodeTable = [...]opInfo{
 		name:         "MOVDBRstoreidx",
 		auxType:      auxSymOff,
 		argLen:       4,
+		commutative:  true,
 		clobberFlags: true,
+		symEffect:    SymWrite,
 		asm:          s390x.AMOVDBR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19317,8 +20428,8 @@ var opcodeTable = [...]opInfo{
 		name:           "MOVBstoreconst",
 		auxType:        auxSymValAndOff,
 		argLen:         2,
-		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVB,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19330,8 +20441,8 @@ var opcodeTable = [...]opInfo{
 		name:           "MOVHstoreconst",
 		auxType:        auxSymValAndOff,
 		argLen:         2,
-		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVH,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19343,8 +20454,8 @@ var opcodeTable = [...]opInfo{
 		name:           "MOVWstoreconst",
 		auxType:        auxSymValAndOff,
 		argLen:         2,
-		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19356,8 +20467,8 @@ var opcodeTable = [...]opInfo{
 		name:           "MOVDstoreconst",
 		auxType:        auxSymValAndOff,
 		argLen:         2,
-		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19371,6 +20482,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         2,
 		clobberFlags:   true,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ACLEAR,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19384,6 +20496,7 @@ var opcodeTable = [...]opInfo{
 		argLen:       1,
 		clobberFlags: true,
 		call:         true,
+		symEffect:    SymNone,
 		reg: regInfo{
 			clobbers: 4294923263, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
 		},
@@ -19391,34 +20504,14 @@ var opcodeTable = [...]opInfo{
 	{
 		name:         "CALLclosure",
 		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			inputs: []inputInfo{
-				{1, 4096},  // R12
-				{0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
-			},
-			clobbers: 4294923263, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
-		},
-	},
-	{
-		name:         "CALLdefer",
-		auxType:      auxInt64,
-		argLen:       1,
-		clobberFlags: true,
-		call:         true,
-		reg: regInfo{
-			clobbers: 4294923263, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
-		},
-	},
-	{
-		name:         "CALLgo",
-		auxType:      auxInt64,
-		argLen:       1,
+		argLen:       3,
 		clobberFlags: true,
 		call:         true,
 		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 4096},  // R12
+				{0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+			},
 			clobbers: 4294923263, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
 		},
 	},
@@ -19471,6 +20564,32 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
+		name:         "LoweredRound32F",
+		argLen:       1,
+		resultInArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
+		name:         "LoweredRound64F",
+		argLen:       1,
+		resultInArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+			outputs: []outputInfo{
+				{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+			},
+		},
+	},
+	{
 		name:   "MOVDconvert",
 		argLen: 2,
 		asm:    s390x.AMOVD,
@@ -19503,6 +20622,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVWZ,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19518,6 +20638,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         2,
 		faultOnNilArg0: true,
+		symEffect:      SymRead,
 		asm:            s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19535,6 +20656,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVW,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19550,6 +20672,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymWrite,
 		asm:            s390x.AMOVD,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19564,6 +20687,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ALAA,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19581,6 +20705,7 @@ var opcodeTable = [...]opInfo{
 		argLen:         3,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ALAAG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19609,6 +20734,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ACS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19630,6 +20756,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ACSG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19651,6 +20778,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ACS,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19670,6 +20798,7 @@ var opcodeTable = [...]opInfo{
 		clobberFlags:   true,
 		faultOnNilArg0: true,
 		hasSideEffects: true,
+		symEffect:      SymRdWr,
 		asm:            s390x.ACSG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19702,6 +20831,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         4,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19716,6 +20846,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         5,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19731,6 +20862,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         6,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMG,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19747,6 +20879,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         4,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMY,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19761,6 +20894,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         5,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMY,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19776,6 +20910,7 @@ var opcodeTable = [...]opInfo{
 		auxType:        auxSymOff,
 		argLen:         6,
 		faultOnNilArg0: true,
+		symEffect:      SymWrite,
 		asm:            s390x.ASTMY,
 		reg: regInfo{
 			inputs: []inputInfo{
@@ -19788,10 +20923,12 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "LoweredMove",
-		auxType:      auxInt64,
-		argLen:       4,
-		clobberFlags: true,
+		name:           "LoweredMove",
+		auxType:        auxInt64,
+		argLen:         4,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
+		faultOnNilArg1: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 2},     // R1
@@ -19802,10 +20939,11 @@ var opcodeTable = [...]opInfo{
 		},
 	},
 	{
-		name:         "LoweredZero",
-		auxType:      auxInt64,
-		argLen:       3,
-		clobberFlags: true,
+		name:           "LoweredZero",
+		auxType:        auxInt64,
+		argLen:         3,
+		clobberFlags:   true,
+		faultOnNilArg0: true,
 		reg: regInfo{
 			inputs: []inputInfo{
 				{0, 2},     // R1
@@ -19845,14 +20983,16 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "Add32F",
-		argLen:  2,
-		generic: true,
+		name:        "Add32F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Add64F",
-		argLen:  2,
-		generic: true,
+		name:        "Add64F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
 		name:    "Sub8",
@@ -19914,14 +21054,16 @@ var opcodeTable = [...]opInfo{
 		generic:     true,
 	},
 	{
-		name:    "Mul32F",
-		argLen:  2,
-		generic: true,
+		name:        "Mul32F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Mul64F",
-		argLen:  2,
-		generic: true,
+		name:        "Mul64F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
 		name:    "Div32F",
@@ -19934,52 +21076,43 @@ var opcodeTable = [...]opInfo{
 		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,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Hmul32",
-		argLen:  2,
-		generic: true,
+		name:        "Hmul32u",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Hmul32u",
-		argLen:  2,
-		generic: true,
+		name:        "Hmul64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Hmul64",
-		argLen:  2,
-		generic: true,
+		name:        "Hmul64u",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Hmul64u",
-		argLen:  2,
-		generic: true,
+		name:        "Mul32uhilo",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Mul32uhilo",
-		argLen:  2,
-		generic: true,
+		name:        "Mul64uhilo",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Mul64uhilo",
+		name:    "Avg32u",
 		argLen:  2,
 		generic: true,
 	},
@@ -20386,30 +21519,6 @@ var opcodeTable = [...]opInfo{
 		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,
@@ -20450,14 +21559,16 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "Eq32F",
-		argLen:  2,
-		generic: true,
+		name:        "Eq32F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Eq64F",
-		argLen:  2,
-		generic: true,
+		name:        "Eq64F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
 		name:        "Neq8",
@@ -20500,14 +21611,16 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "Neq32F",
-		argLen:  2,
-		generic: true,
+		name:        "Neq32F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "Neq64F",
-		argLen:  2,
-		generic: true,
+		name:        "Neq64F",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
 		name:    "Less8",
@@ -20710,24 +21823,28 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "AndB",
-		argLen:  2,
-		generic: true,
+		name:        "AndB",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "OrB",
-		argLen:  2,
-		generic: true,
+		name:        "OrB",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "EqB",
-		argLen:  2,
-		generic: true,
+		name:        "EqB",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
-		name:    "NeqB",
-		argLen:  2,
-		generic: true,
+		name:        "NeqB",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
 	},
 	{
 		name:    "Not",
@@ -20795,6 +21912,16 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
+		name:    "BitLen32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "BitLen64",
+		argLen:  1,
+		generic: true,
+	},
+	{
 		name:    "Bswap32",
 		argLen:  1,
 		generic: true,
@@ -20805,6 +21932,46 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
+		name:    "BitRev8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "BitRev16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "BitRev32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "BitRev64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "PopCount8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "PopCount16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "PopCount32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "PopCount64",
+		argLen:  1,
+		generic: true,
+	},
+	{
 		name:    "Sqrt",
 		argLen:  1,
 		generic: true,
@@ -20893,16 +22060,18 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "Arg",
-		auxType: auxSymOff,
-		argLen:  0,
-		generic: true,
+		name:      "Arg",
+		auxType:   auxSymOff,
+		argLen:    0,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
-		name:    "Addr",
-		auxType: auxSym,
-		argLen:  1,
-		generic: true,
+		name:      "Addr",
+		auxType:   auxSym,
+		argLen:    1,
+		symEffect: SymAddr,
+		generic:   true,
 	},
 	{
 		name:    "SP",
@@ -20915,55 +22084,43 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "Func",
-		auxType: auxSym,
-		argLen:  0,
-		generic: true,
-	},
-	{
 		name:    "Load",
 		argLen:  2,
 		generic: true,
 	},
 	{
 		name:    "Store",
-		auxType: auxInt64,
+		auxType: auxTyp,
 		argLen:  3,
 		generic: true,
 	},
 	{
 		name:    "Move",
-		auxType: auxSizeAndAlign,
+		auxType: auxTypSize,
 		argLen:  3,
 		generic: true,
 	},
 	{
 		name:    "Zero",
-		auxType: auxSizeAndAlign,
+		auxType: auxTypSize,
 		argLen:  2,
 		generic: true,
 	},
 	{
 		name:    "StoreWB",
-		auxType: auxInt64,
+		auxType: auxTyp,
 		argLen:  3,
 		generic: true,
 	},
 	{
 		name:    "MoveWB",
-		auxType: auxSymSizeAndAlign,
-		argLen:  3,
-		generic: true,
-	},
-	{
-		name:    "MoveWBVolatile",
-		auxType: auxSymSizeAndAlign,
+		auxType: auxTypSize,
 		argLen:  3,
 		generic: true,
 	},
 	{
 		name:    "ZeroWB",
-		auxType: auxSymSizeAndAlign,
+		auxType: auxTypSize,
 		argLen:  2,
 		generic: true,
 	},
@@ -20975,25 +22132,12 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "StaticCall",
-		auxType: auxSymOff,
-		argLen:  1,
-		call:    true,
-		generic: true,
-	},
-	{
-		name:    "DeferCall",
-		auxType: auxInt64,
-		argLen:  1,
-		call:    true,
-		generic: true,
-	},
-	{
-		name:    "GoCall",
-		auxType: auxInt64,
-		argLen:  1,
-		call:    true,
-		generic: true,
+		name:      "StaticCall",
+		auxType:   auxSymOff,
+		argLen:    1,
+		call:      true,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
 		name:    "InterCall",
@@ -21143,6 +22287,16 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
+		name:    "Round32F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Round64F",
+		argLen:  1,
+		generic: true,
+	},
+	{
 		name:    "IsNonNil",
 		argLen:  1,
 		generic: true,
@@ -21306,10 +22460,11 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "FwdRef",
-		auxType: auxSym,
-		argLen:  0,
-		generic: true,
+		name:      "FwdRef",
+		auxType:   auxSym,
+		argLen:    0,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
 		name:    "Unknown",
@@ -21317,22 +22472,25 @@ var opcodeTable = [...]opInfo{
 		generic: true,
 	},
 	{
-		name:    "VarDef",
-		auxType: auxSym,
-		argLen:  1,
-		generic: true,
+		name:      "VarDef",
+		auxType:   auxSym,
+		argLen:    1,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
-		name:    "VarKill",
-		auxType: auxSym,
-		argLen:  1,
-		generic: true,
+		name:      "VarKill",
+		auxType:   auxSym,
+		argLen:    1,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
-		name:    "VarLive",
-		auxType: auxSym,
-		argLen:  1,
-		generic: true,
+		name:      "VarLive",
+		auxType:   auxSym,
+		argLen:    1,
+		symEffect: SymNone,
+		generic:   true,
 	},
 	{
 		name:    "KeepAlive",
@@ -21522,11 +22680,20 @@ var opcodeTable = [...]opInfo{
 		hasSideEffects: true,
 		generic:        true,
 	},
+	{
+		name:      "Clobber",
+		auxType:   auxSymOff,
+		argLen:    0,
+		symEffect: SymNone,
+		generic:   true,
+	},
 }
 
-func (o Op) Asm() obj.As       { return opcodeTable[o].asm }
-func (o Op) String() string    { return opcodeTable[o].name }
-func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }
+func (o Op) Asm() obj.As          { return opcodeTable[o].asm }
+func (o Op) String() string       { return opcodeTable[o].name }
+func (o Op) UsesScratch() bool    { return opcodeTable[o].usesScratch }
+func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }
+func (o Op) IsCall() bool         { return opcodeTable[o].call }
 
 var registers386 = [...]Register{
 	{0, x86.REG_AX, "AX"},
diff --git a/src/cmd/compile/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go
index f211488..670b535 100644
--- a/src/cmd/compile/internal/ssa/opt.go
+++ b/src/cmd/compile/internal/ssa/opt.go
@@ -11,7 +11,7 @@ func opt(f *Func) {
 
 func dec(f *Func) {
 	applyRewrite(f, rewriteBlockdec, rewriteValuedec)
-	if f.Config.IntSize == 4 && f.Config.arch != "amd64p32" {
+	if f.Config.RegSize == 4 {
 		applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
 	}
 }
diff --git a/src/cmd/compile/internal/ssa/passbm_test.go b/src/cmd/compile/internal/ssa/passbm_test.go
index e4bb0b8..5e0a7eb 100644
--- a/src/cmd/compile/internal/ssa/passbm_test.go
+++ b/src/cmd/compile/internal/ssa/passbm_test.go
@@ -4,6 +4,7 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"fmt"
 	"testing"
 )
@@ -33,8 +34,8 @@ 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)...)
+	c := testConfig(b)
+	fun := c.Fun("entry", bg(size)...)
 	CheckFunc(fun.f)
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
@@ -48,8 +49,8 @@ func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) {
 // 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)...)
+	c := testConfig(b)
+	fun := c.Fun("entry", bg(b.N)...)
 	CheckFunc(fun.f)
 	b.ResetTimer()
 	for i := 0; i < passCount; i++ {
@@ -60,32 +61,32 @@ func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) {
 
 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
+	elemType := types.Types[types.TINT64]
+	ptrType := elemType.PtrTo()
 
 	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),
+			Valu(valn("store", 0, 4), OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.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("v", i, 0), OpConstBool, types.Types[types.TBOOL], 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),
+			Valu(valn("zero", i, 1), OpZero, types.TypeMem, 8, elemType, valn("addr", i, 3),
 				valn("store", i-1, 4)),
-			Valu(valn("store", i, 1), OpStore, TypeMem, 0, nil, valn("addr", i, 1),
+			Valu(valn("store", i, 1), OpStore, types.TypeMem, 0, elemType, 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),
+			Valu(valn("store", i, 2), OpStore, types.TypeMem, 0, elemType, 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),
+			Valu(valn("store", i, 3), OpStore, types.TypeMem, 0, elemType, 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),
+			Valu(valn("store", i, 4), OpStore, types.TypeMem, 0, elemType, valn("addr", i, 3),
 				valn("v", i, 0), valn("store", i, 3)),
 			Goto(blockn(i+1))))
 	}
diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go
index 5fccab9..761cb7a 100644
--- a/src/cmd/compile/internal/ssa/phielim.go
+++ b/src/cmd/compile/internal/ssa/phielim.go
@@ -63,7 +63,7 @@ func phielimValue(v *Value) bool {
 	v.SetArgs1(w)
 	f := v.Block.Func
 	if f.pass.debug > 0 {
-		f.Config.Warnl(v.Line, "eliminated phi")
+		f.Warnl(v.Pos, "eliminated phi")
 	}
 	return true
 }
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go
index 3e9f195..60c8e58 100644
--- a/src/cmd/compile/internal/ssa/phiopt.go
+++ b/src/cmd/compile/internal/ssa/phiopt.go
@@ -81,7 +81,7 @@ func phiopt(f *Func) {
 					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)
+						f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
 					}
 					continue
 				}
@@ -97,7 +97,7 @@ func phiopt(f *Func) {
 					v.reset(OpOrB)
 					v.SetArgs2(b0.Control, tmp)
 					if f.pass.debug > 0 {
-						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+						f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
 					}
 					continue
 				}
@@ -113,7 +113,7 @@ func phiopt(f *Func) {
 					v.reset(OpAndB)
 					v.SetArgs2(b0.Control, tmp)
 					if f.pass.debug > 0 {
-						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+						f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
 					}
 					continue
 				}
@@ -163,12 +163,12 @@ func phioptint(v *Value, b0 *Block, reverse int) {
 
 	a := b0.Control
 	if negate {
-		a = v.Block.NewValue1(v.Line, OpNot, a.Type, a)
+		a = v.Block.NewValue1(v.Pos, OpNot, a.Type, a)
 	}
 	v.AddArg(a)
 
 	f := b0.Func
 	if f.pass.debug > 0 {
-		f.Config.Warnl(v.Block.Line, "converted OpPhi bool -> int%d", v.Type.Size()*8)
+		f.Warnl(v.Block.Pos, "converted OpPhi bool -> int%d", v.Type.Size()*8)
 	}
 }
diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go
index 21e293c..d2a87eb 100644
--- a/src/cmd/compile/internal/ssa/print.go
+++ b/src/cmd/compile/internal/ssa/print.go
@@ -62,7 +62,7 @@ func (p stringFuncPrinter) endBlock(b *Block) {
 
 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, v.Block.Func.fe.Pos(v.Pos))
 	//fmt.Fprint(p.w, ": ")
 	fmt.Fprint(p.w, v.LongString())
 	if !live {
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 1925a61..a447331 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -97,6 +97,12 @@ type factsTable struct {
 	// known lower and upper bounds on individual values.
 	limits     map[ID]limit
 	limitStack []limitFact // previous entries
+
+	// For each slice s, a map from s to a len(s)/cap(s) value (if any)
+	// TODO: check if there are cases that matter where we have
+	// more than one len(s) for a slice. We could keep a list if necessary.
+	lens map[ID]*Value
+	caps map[ID]*Value
 }
 
 // checkpointFact is an invalid value used for checkpointing
@@ -301,7 +307,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
 		ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
 		ft.limits[v.ID] = lim
 		if v.Block.Func.pass.debug > 2 {
-			v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
+			v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
 		}
 	}
 }
@@ -432,7 +438,8 @@ var (
 	}
 )
 
-// prove removes redundant BlockIf controls that can be inferred in a straight line.
+// prove removes redundant BlockIf branches that can be inferred
+// from previous dominating comparisons.
 //
 // By far, the most common redundant pair are generated by bounds checking.
 // For example for the code:
@@ -455,6 +462,31 @@ var (
 // 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) {
+	ft := newFactsTable()
+
+	// Find length and capacity ops.
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Uses == 0 {
+				// We don't care about dead values.
+				// (There can be some that are CSEd but not removed yet.)
+				continue
+			}
+			switch v.Op {
+			case OpSliceLen:
+				if ft.lens == nil {
+					ft.lens = map[ID]*Value{}
+				}
+				ft.lens[v.Args[0].ID] = v
+			case OpSliceCap:
+				if ft.caps == nil {
+					ft.caps = map[ID]*Value{}
+				}
+				ft.caps[v.Args[0].ID] = v
+			}
+		}
+	}
+
 	// current node state
 	type walkState int
 	const (
@@ -472,7 +504,6 @@ func prove(f *Func) {
 		state: descend,
 	})
 
-	ft := newFactsTable()
 	idom := f.Idom()
 	sdom := f.sdom()
 
@@ -559,8 +590,34 @@ func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r
 		r = (lt | eq | gt) ^ r
 	}
 	for i := domain(1); i <= t; i <<= 1 {
-		if t&i != 0 {
-			ft.update(parent, v, w, i, r)
+		if t&i == 0 {
+			continue
+		}
+		ft.update(parent, v, w, i, r)
+
+		// Additional facts we know given the relationship between len and cap.
+		if i != signed && i != unsigned {
+			continue
+		}
+		if v.Op == OpSliceLen && r&lt == 0 && ft.caps[v.Args[0].ID] != nil {
+			// len(s) > w implies cap(s) > w
+			// len(s) >= w implies cap(s) >= w
+			// len(s) == w implies cap(s) >= w
+			ft.update(parent, ft.caps[v.Args[0].ID], w, i, r|gt)
+		}
+		if w.Op == OpSliceLen && r&gt == 0 && ft.caps[w.Args[0].ID] != nil {
+			// same, length on the RHS.
+			ft.update(parent, v, ft.caps[w.Args[0].ID], i, r|lt)
+		}
+		if v.Op == OpSliceCap && r&gt == 0 && ft.lens[v.Args[0].ID] != nil {
+			// cap(s) < w implies len(s) < w
+			// cap(s) <= w implies len(s) <= w
+			// cap(s) == w implies len(s) <= w
+			ft.update(parent, ft.lens[v.Args[0].ID], w, i, r|lt)
+		}
+		if w.Op == OpSliceCap && r&lt == 0 && ft.lens[w.Args[0].ID] != nil {
+			// same, capacity on the RHS.
+			ft.update(parent, v, ft.lens[w.Args[0].ID], i, r|gt)
 		}
 	}
 }
@@ -600,7 +657,7 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 				v.reset(OpConst32)
 			}
 			if b.Func.pass.debug > 0 {
-				b.Func.Config.Warnl(v.Line, "Proved slicemask not needed")
+				b.Func.Warnl(v.Pos, "Proved slicemask not needed")
 			}
 			v.AuxInt = -1
 		}
@@ -615,9 +672,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 	if m == lt|gt {
 		if b.Func.pass.debug > 0 {
 			if b.Func.pass.debug > 1 {
-				b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control)
+				b.Func.Warnl(b.Pos, "Proved boolean %s (%s)", b.Control.Op, b.Control)
 			} else {
-				b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
+				b.Func.Warnl(b.Pos, "Proved boolean %s", b.Control.Op)
 			}
 		}
 		return positive
@@ -625,9 +682,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 	if m == eq {
 		if b.Func.pass.debug > 0 {
 			if b.Func.pass.debug > 1 {
-				b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
+				b.Func.Warnl(b.Pos, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
 			} else {
-				b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
+				b.Func.Warnl(b.Pos, "Disproved boolean %s", b.Control.Op)
 			}
 		}
 		return negative
@@ -656,9 +713,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 		if m != 0 && tr.r&m == m {
 			if b.Func.pass.debug > 0 {
 				if b.Func.pass.debug > 1 {
-					b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c)
+					b.Func.Warnl(b.Pos, "Proved %s (%s)", c.Op, c)
 				} else {
-					b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
+					b.Func.Warnl(b.Pos, "Proved %s", c.Op)
 				}
 			}
 			return positive
@@ -666,9 +723,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 		if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
 			if b.Func.pass.debug > 0 {
 				if b.Func.pass.debug > 1 {
-					b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c)
+					b.Func.Warnl(b.Pos, "Disproved %s (%s)", c.Op, c)
 				} else {
-					b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
+					b.Func.Warnl(b.Pos, "Disproved %s", c.Op)
 				}
 			}
 			return negative
@@ -685,9 +742,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
 		if m != 0 && tr.r&m == m {
 			if b.Func.pass.debug > 0 {
 				if b.Func.pass.debug > 1 {
-					b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c)
+					b.Func.Warnl(b.Pos, "Proved non-negative bounds %s (%s)", c.Op, c)
 				} else {
-					b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
+					b.Func.Warnl(b.Pos, "Proved non-negative bounds %s", c.Op)
 				}
 			}
 			return positive
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 90b5947..137e5fc 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -26,28 +26,48 @@
 
 // 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.
+// During the normal course of the allocator, we might throw a still-live
+// value out of all registers. When that value is subsequently used, we must
+// load it from a slot on the stack. We must also issue an instruction to
+// initialize that stack location with a copy of v.
+//
+// pre-regalloc:
+//   (1) v = Op ...
+//   (2) x = Op ...
+//   (3) ... = Op v ...
+//
+// post-regalloc:
+//   (1) v = Op ...    : AX // computes v, store result in AX
+//       s = StoreReg v     // spill v to a stack slot
+//   (2) x = Op ...    : AX // some other op uses AX
+//       c = LoadReg s : CX // restore v from stack slot
+//   (3) ... = Op c ...     // use the restored value
+//
+// Allocation occurs normally until we reach (3) and we realize we have
+// a use of v and it isn't in any register. At that point, we allocate
+// a spill (a StoreReg) for v. We can't determine the correct place for
+// the spill at this point, so we allocate the spill as blockless initially.
+// The restore is then generated to load v back into a register so it can
+// be used. Subsequent uses of v will use the restored value c instead.
+//
+// What remains is the question of where to schedule the spill.
+// During allocation, we keep track of the dominator of all restores of v.
+// The spill of v must dominate that block. The spill must also be issued at
+// a point where v is still in a register.
+//
+// To find the right place, start at b, the block which dominates all restores.
+//  - If b is v.Block, then issue the spill right after v.
+//    It is known to be in a register at that point, and dominates any restores.
+//  - Otherwise, if v is in a register at the start of b,
+//    put the spill of v at the start of b.
+//  - Otherwise, set b = immediate dominator of b, and repeat.
 //
 // 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
+// same register. Register phis are spilled similarly to regular ops.
 //
 // 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
@@ -91,22 +111,12 @@
 // 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 (
-	"cmd/internal/obj"
+	"cmd/compile/internal/types"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"fmt"
 	"unsafe"
 )
@@ -180,19 +190,20 @@ func pickReg(r regMask) register {
 }
 
 type use struct {
-	dist int32 // distance from start of the block to a use of a value
-	line int32 // line number of the use
-	next *use  // linked list of uses of a value in nondecreasing dist order
+	dist int32    // distance from start of the block to a use of a value
+	pos  src.XPos // source position of the use
+	next *use     // linked list of uses of a value in nondecreasing dist order
 }
 
+// A valState records the register allocation state for a (pre-regalloc) value.
 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()
+	spill             *Value  // spilled copy of the Value (if any)
+	restoreMin        int32   // minimum of all restores' blocks' sdom.entry
+	restoreMax        int32   // maximum of all restores' blocks' sdom.exit
+	needReg           bool    // cached value of !v.Type.IsMemory() && !v.Type.IsVoid() && !.v.Type.IsFlags()
+	rematerializeable bool    // cached value of v.rematerializeable()
 }
 
 type regState struct {
@@ -204,6 +215,7 @@ type regState struct {
 type regAllocState struct {
 	f *Func
 
+	sdom        SparseTree
 	registers   []Register
 	numRegs     register
 	SPReg       register
@@ -230,6 +242,9 @@ type regAllocState struct {
 	// current state of each (preregalloc) Value
 	values []valState
 
+	// ID of SP, SB values
+	sp, sb ID
+
 	// For each Value, map from its value ID back to the
 	// preregalloc Value it was derived from.
 	orig []*Value
@@ -270,15 +285,6 @@ type regAllocState struct {
 	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?)
@@ -286,9 +292,10 @@ type endReg struct {
 }
 
 type startReg struct {
-	r    register
-	vid  ID    // pre-regalloc value needed in this register
-	line int32 // line number of use of this register
+	r   register
+	v   *Value   // pre-regalloc value needed in this register
+	c   *Value   // cached version of the value
+	pos src.XPos // source position of use of this register
 }
 
 // freeReg frees up register r. Any current user of r is kicked out.
@@ -392,7 +399,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
 	m := s.compatRegs(v2.Type) &^ s.used &^ s.tmpused &^ (regMask(1) << r)
 	if m != 0 && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
 		r2 := pickReg(m)
-		c := s.curBlock.NewValue1(v2.Line, OpCopy, v2.Type, s.regs[r].c)
+		c := s.curBlock.NewValue1(v2.Pos, OpCopy, v2.Type, s.regs[r].c)
 		s.copies[c] = false
 		if s.f.pass.debug > regDebug {
 			fmt.Printf("copy %s to %s : %s\n", v2, c, s.registers[r2].Name())
@@ -404,13 +411,35 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
 	return r
 }
 
+// makeSpill returns a Value which represents the spilled value of v.
+// b is the block in which the spill is used.
+func (s *regAllocState) makeSpill(v *Value, b *Block) *Value {
+	vi := &s.values[v.ID]
+	if vi.spill != nil {
+		// Final block not known - keep track of subtree where restores reside.
+		vi.restoreMin = min32(vi.restoreMin, s.sdom[b.ID].entry)
+		vi.restoreMax = max32(vi.restoreMax, s.sdom[b.ID].exit)
+		return vi.spill
+	}
+	// Make a spill for v. We don't know where we want
+	// to put it yet, so we leave it blockless for now.
+	spill := s.f.newValueNoBlock(OpStoreReg, v.Type, v.Pos)
+	// We also don't know what the spill's arg will be.
+	// Leave it argless for now.
+	s.setOrig(spill, v)
+	vi.spill = spill
+	vi.restoreMin = s.sdom[b.ID].entry
+	vi.restoreMax = s.sdom[b.ID].exit
+	return spill
+}
+
 // 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 {
+func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.XPos) *Value {
 	vi := &s.values[v.ID]
 
 	// Check if v is already in a requested register.
@@ -436,22 +465,17 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
 		if s.regs[r2].v != v {
 			panic("bad register state")
 		}
-		c = s.curBlock.NewValue1(line, OpCopy, v.Type, s.regs[r2].c)
+		c = s.curBlock.NewValue1(pos, OpCopy, v.Type, s.regs[r2].c)
 	} else if v.rematerializeable() {
 		// Rematerialize instead of loading from the spill location.
-		c = v.copyInto(s.curBlock)
+		c = v.copyIntoNoXPos(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())
+		spill := s.makeSpill(v, s.curBlock)
+		if s.f.pass.debug > logSpills {
+			s.f.Warnl(vi.spill.Pos, "load spill for %v from %v", v, spill)
 		}
+		c = s.curBlock.NewValue1(pos, OpLoadReg, v.Type, spill)
 	}
 	s.setOrig(c, v)
 	s.assignReg(r, v, c)
@@ -475,6 +499,7 @@ func isLeaf(f *Func) bool {
 
 func (s *regAllocState) init(f *Func) {
 	s.f = f
+	s.f.RegAlloc = s.f.Cache.locs[:0]
 	s.registers = f.Config.registers
 	if nr := len(s.registers); nr == 0 || nr > int(noRegister) || nr > int(unsafe.Sizeof(regMask(0))*8) {
 		s.f.Fatalf("bad number of registers: %d", nr)
@@ -528,7 +553,7 @@ func (s *regAllocState) init(f *Func) {
 			// Leaf functions don't save/restore the link register.
 			s.allocatable &^= 1 << uint(s.f.Config.LinkReg)
 		}
-		if s.f.Config.arch == "arm" && obj.GOARM == 5 {
+		if s.f.Config.arch == "arm" && objabi.GOARM == 5 {
 			// On ARMv5 we insert softfloat calls at each FP instruction.
 			// This clobbers LR almost everywhere. Disable allocating LR
 			// on ARMv5.
@@ -554,7 +579,7 @@ func (s *regAllocState) init(f *Func) {
 		case "s390x":
 			// nothing to do, R10 & R11 already reserved
 		default:
-			s.f.Config.fe.Fatalf(0, "arch %s not implemented", s.f.Config.arch)
+			s.f.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
 		}
 	}
 	if s.f.Config.nacl {
@@ -613,11 +638,12 @@ func (s *regAllocState) init(f *Func) {
 	s.endRegs = make([][]endReg, f.NumBlocks())
 	s.startRegs = make([][]startReg, f.NumBlocks())
 	s.spillLive = make([][]ID, f.NumBlocks())
+	s.sdom = f.sdom()
 }
 
 // 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, line int32) {
+func (s *regAllocState) addUse(id ID, dist int32, pos src.XPos) {
 	r := s.freeUseRecords
 	if r != nil {
 		s.freeUseRecords = r.next
@@ -625,7 +651,7 @@ func (s *regAllocState) addUse(id ID, dist int32, line int32) {
 		r = &use{}
 	}
 	r.dist = dist
-	r.line = line
+	r.pos = pos
 	r.next = s.values[id].uses
 	s.values[id].uses = r
 	if r.next != nil && dist > r.next.dist {
@@ -673,12 +699,12 @@ func (s *regAllocState) setState(regs []endReg) {
 }
 
 // compatRegs returns the set of registers which can store a type t.
-func (s *regAllocState) compatRegs(t Type) regMask {
+func (s *regAllocState) compatRegs(t *types.Type) regMask {
 	var m regMask
 	if t.IsTuple() || t.IsFlags() {
 		return 0
 	}
-	if t.IsFloat() || t == TypeInt128 {
+	if t.IsFloat() || t == types.TypeInt128 {
 		m = s.f.Config.fpRegMask
 	} else {
 		m = s.f.Config.gpRegMask
@@ -686,38 +712,14 @@ func (s *regAllocState) compatRegs(t Type) regMask {
 	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)
+	regValLiveSet := f.newSparseSet(f.NumValues()) // set of values that may be live in register
+	defer f.retSparseSet(regValLiveSet)
 	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
 
@@ -732,51 +734,45 @@ func (s *regAllocState) regalloc(f *Func) {
 		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.
+		// Initialize regValLiveSet and uses fields for this block.
 		// Walk backwards through the block doing liveness analysis.
-		liveSet.clear()
+		regValLiveSet.clear()
 		for _, e := range s.live[b.ID] {
-			s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block
-			liveSet.add(e.ID)
+			s.addUse(e.ID, int32(len(b.Values))+e.dist, e.pos) // pseudo-uses from beyond end of block
+			regValLiveSet.add(e.ID)
 		}
 		if v := b.Control; v != nil && s.values[v.ID].needReg {
-			s.addUse(v.ID, int32(len(b.Values)), b.Line) // pseudo-use by control value
-			liveSet.add(v.ID)
+			s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control value
+			regValLiveSet.add(v.ID)
 		}
 		for i := len(b.Values) - 1; i >= 0; i-- {
 			v := b.Values[i]
-			liveSet.remove(v.ID)
+			regValLiveSet.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
 			}
+			if opcodeTable[v.Op].call {
+				// Function call clobbers all the registers but SP and SB.
+				regValLiveSet.clear()
+				if s.sp != 0 && s.values[s.sp].uses != nil {
+					regValLiveSet.add(s.sp)
+				}
+				if s.sb != 0 && s.values[s.sb].uses != nil {
+					regValLiveSet.add(s.sb)
+				}
+			}
 			for _, a := range v.Args {
 				if !s.values[a.ID].needReg {
 					continue
 				}
-				s.addUse(a.ID, int32(i), v.Line)
-				liveSet.add(a.ID)
+				s.addUse(a.ID, int32(i), v.Pos)
+				regValLiveSet.add(a.ID)
 			}
 		}
 		if s.f.pass.debug > regDebug {
@@ -826,7 +822,7 @@ func (s *regAllocState) regalloc(f *Func) {
 			// 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) {
+				if v != nil && !regValLiveSet.contains(v.ID) {
 					s.freeReg(r)
 				}
 			}
@@ -882,7 +878,7 @@ func (s *regAllocState) regalloc(f *Func) {
 					continue
 				}
 				a := v.Args[idx]
-				if !liveSet.contains(a.ID) {
+				if !regValLiveSet.contains(a.ID) {
 					// Input is dead beyond the phi, deallocate
 					// anywhere else it might live.
 					s.freeRegs(s.values[a.ID].regs)
@@ -901,7 +897,7 @@ func (s *regAllocState) regalloc(f *Func) {
 					m := s.compatRegs(a.Type) &^ s.used &^ phiUsed
 					if m != 0 && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
 						r2 := pickReg(m)
-						c := p.NewValue1(a.Line, OpCopy, a.Type, s.regs[r].c)
+						c := p.NewValue1(a.Pos, OpCopy, a.Type, s.regs[r].c)
 						s.copies[c] = false
 						if s.f.pass.debug > regDebug {
 							fmt.Printf("copy %s to %s : %s\n", a, c, s.registers[r2].Name())
@@ -943,22 +939,22 @@ func (s *regAllocState) regalloc(f *Func) {
 				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
+					s.values[v.ID].spill = v // v starts life spilled
 					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++
+			}
+
+			// Deallocate any values which are no longer live. Phis are excluded.
+			for r := register(0); r < s.numRegs; r++ {
+				if phiUsed>>r&1 != 0 {
+					continue
+				}
+				v := s.regs[r].v
+				if v != nil && !regValLiveSet.contains(v.ID) {
+					s.freeReg(r)
 				}
-				nSpills++
 			}
 
 			// Save the starting state for use by merge edges.
@@ -973,14 +969,14 @@ func (s *regAllocState) regalloc(f *Func) {
 					// specially during merge edge processing.
 					continue
 				}
-				regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line})
+				regList = append(regList, startReg{r, v, s.regs[r].c, s.values[v.ID].uses.pos})
 			}
 			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)
+					fmt.Printf("  %s: v%d\n", s.registers[x.r].Name(), x.v.ID)
 				}
 			}
 		}
@@ -1003,7 +999,7 @@ func (s *regAllocState) regalloc(f *Func) {
 			succ := e.b
 			// TODO: prioritize likely successor?
 			for _, x := range s.startRegs[succ.ID] {
-				desired.add(x.vid, x.r)
+				desired.add(x.v.ID, x.r)
 			}
 			// Process phi ops in succ.
 			pidx := e.i
@@ -1063,12 +1059,14 @@ func (s *regAllocState) regalloc(f *Func) {
 				s.assignReg(s.SPReg, v, v)
 				b.Values = append(b.Values, v)
 				s.advanceUses(v)
+				s.sp = v.ID
 				continue
 			}
 			if v.Op == OpSB {
 				s.assignReg(s.SBReg, v, v)
 				b.Values = append(b.Values, v)
 				s.advanceUses(v)
+				s.sb = v.ID
 				continue
 			}
 			if v.Op == OpSelect0 || v.Op == OpSelect1 {
@@ -1098,7 +1096,6 @@ func (s *regAllocState) regalloc(f *Func) {
 				// 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
@@ -1107,7 +1104,7 @@ func (s *regAllocState) regalloc(f *Func) {
 				// Make sure the argument to v is still live here.
 				s.advanceUses(v)
 				vi := &s.values[v.Args[0].ID]
-				if vi.spillUsed {
+				if vi.spill != nil {
 					// Use the spill location.
 					v.SetArg(0, vi.spill)
 				} else {
@@ -1183,7 +1180,7 @@ func (s *regAllocState) regalloc(f *Func) {
 						mask &^= desired.avoid
 					}
 				}
-				args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Line)
+				args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Pos)
 			}
 
 			// If the output clobbers the input register, make sure we have
@@ -1235,7 +1232,7 @@ func (s *regAllocState) regalloc(f *Func) {
 				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)
+						args[0] = s.allocValToReg(v.Args[0], m, true, v.Pos)
 						// Note: we update args[0] so the instruction will
 						// use the register copy we just made.
 						goto ok
@@ -1246,7 +1243,7 @@ func (s *regAllocState) regalloc(f *Func) {
 				for _, r := range dinfo[idx].in[0] {
 					if r != noRegister && m>>r&1 != 0 {
 						m = regMask(1) << r
-						c := s.allocValToReg(v.Args[0], m, true, v.Line)
+						c := s.allocValToReg(v.Args[0], m, true, v.Pos)
 						s.copies[c] = false
 						// Note: no update to args[0] so the instruction will
 						// use the original copy.
@@ -1257,7 +1254,7 @@ func (s *regAllocState) regalloc(f *Func) {
 					for _, r := range dinfo[idx].in[1] {
 						if r != noRegister && m>>r&1 != 0 {
 							m = regMask(1) << r
-							c := s.allocValToReg(v.Args[1], m, true, v.Line)
+							c := s.allocValToReg(v.Args[1], m, true, v.Pos)
 							s.copies[c] = false
 							args[0], args[1] = args[1], args[0]
 							goto ok
@@ -1269,7 +1266,7 @@ func (s *regAllocState) regalloc(f *Func) {
 					m &^= desired.avoid
 				}
 				// Save input 0 to a new register so we can clobber it.
-				c := s.allocValToReg(v.Args[0], m, true, v.Line)
+				c := s.allocValToReg(v.Args[0], m, true, v.Pos)
 				s.copies[c] = false
 			}
 
@@ -1371,28 +1368,7 @@ func (s *regAllocState) regalloc(f *Func) {
 			}
 			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.
 		issueSpill:
-			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.
@@ -1403,7 +1379,7 @@ func (s *regAllocState) regalloc(f *Func) {
 			// We assume that a control input can be passed in any
 			// type-compatible register. If this turns out not to be true,
 			// we'll need to introduce a regspec for a block's control value.
-			b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Line)
+			b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos)
 			if b.Control != v {
 				v.Uses--
 				b.Control.Uses++
@@ -1458,7 +1434,7 @@ func (s *regAllocState) regalloc(f *Func) {
 					m &^= desired.avoid
 				}
 				if m != 0 {
-					s.allocValToReg(v, m, false, b.Line)
+					s.allocValToReg(v, m, false, b.Pos)
 				}
 			}
 		}
@@ -1486,106 +1462,39 @@ func (s *regAllocState) regalloc(f *Func) {
 		s.endRegs[b.ID] = regList
 
 		if checkEnabled {
-			liveSet.clear()
+			regValLiveSet.clear()
 			for _, x := range s.live[b.ID] {
-				liveSet.add(x.ID)
+				regValLiveSet.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) {
+				if !regValLiveSet.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
+		// isn't in a register, generate a use for the spill location.
+		// 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 {
+			vi := &s.values[e.ID]
+			if vi.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.
+			if vi.rematerializeable {
+				// we'll rematerialize during the merge.
 				continue
 			}
+			//fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b)
+			spill := s.makeSpill(s.orig[e.ID], b)
 			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
@@ -1604,52 +1513,8 @@ func (s *regAllocState) regalloc(f *Func) {
 		}
 	}
 
-	// Erase any spills we never used
-	for i := range s.values {
-		vi := s.values[i]
-		if vi.spillUsed {
-			if s.f.pass.debug > logSpills && vi.spill.Op != OpArg {
-				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
-		}
-	}
+	// Decide where the spills we generated will go.
+	s.placeSpills()
 
 	// Anything that didn't get a register gets a stack location here.
 	// (StoreReg, stack-based phis, inputs, ...)
@@ -1658,132 +1523,6 @@ func (s *regAllocState) regalloc(f *Func) {
 	// 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.
-
-			// Check that the spill value is still live at the start of d.
-			// If it isn't, we can't move the spill here because some other value
-			// may be using the same stack slot.  See issue 20472.
-			// The spill value can't be defined in d, so that makes our lives easier.
-			for _, x := range stacklive[d.ID] {
-				if x == vsp.ID {
-					goto stillLive
-				}
-			}
-			for _, v := range d.Values {
-				if v.Op == OpLoadReg && v.Args[0] == vsp {
-					goto stillLive
-				}
-			}
-			// Spill is not live - abort sinking this spill.
-			continue sinking
-		stillLive:
-
-			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
-
-		}
-	}
-
 	// Erase any copies we never used.
 	// Also, an unused copy might be the only use of another copy,
 	// so continue erasing until we reach a fixed point.
@@ -1816,38 +1555,143 @@ sinking:
 		}
 		b.Values = b.Values[:i]
 	}
+}
+
+func (s *regAllocState) placeSpills() {
+	f := s.f
 
-	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")
+	// Precompute some useful info.
+	phiRegs := make([]regMask, f.NumBlocks())
+	for _, b := range f.Blocks {
+		var m regMask
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				break
+			}
+			if r, ok := f.getHome(v.ID).(*Register); ok {
+				m |= regMask(1) << uint(r.num)
+			}
+		}
+		phiRegs[b.ID] = m
 	}
-}
 
-// 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
-}
+	// Start maps block IDs to the list of spills
+	// that go at the start of the block (but after any phis).
+	start := map[ID][]*Value{}
+	// After maps value IDs to the list of spills
+	// that go immediately after that value ID.
+	after := map[ID][]*Value{}
 
-// 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
+	for i := range s.values {
+		vi := s.values[i]
+		spill := vi.spill
+		if spill == nil {
+			continue
+		}
+		if spill.Block != nil {
+			// Some spills are already fully set up,
+			// like OpArgs and stack-based phis.
+			continue
+		}
+		v := s.orig[i]
+
+		// Walk down the dominator tree looking for a good place to
+		// put the spill of v.  At the start "best" is the best place
+		// we have found so far.
+		// TODO: find a way to make this O(1) without arbitrary cutoffs.
+		best := v.Block
+		bestArg := v
+		var bestDepth int16
+		if l := s.loopnest.b2l[best.ID]; l != nil {
+			bestDepth = l.depth
+		}
+		b := best
+		const maxSpillSearch = 100
+		for i := 0; i < maxSpillSearch; i++ {
+			// Find the child of b in the dominator tree which
+			// dominates all restores.
+			p := b
+			b = nil
+			for c := s.sdom.Child(p); c != nil && i < maxSpillSearch; c, i = s.sdom.Sibling(c), i+1 {
+				if s.sdom[c.ID].entry <= vi.restoreMin && s.sdom[c.ID].exit >= vi.restoreMax {
+					// c also dominates all restores.  Walk down into c.
+					b = c
+					break
+				}
+			}
+			if b == nil {
+				// Ran out of blocks which dominate all restores.
+				break
+			}
+
+			var depth int16
+			if l := s.loopnest.b2l[b.ID]; l != nil {
+				depth = l.depth
+			}
+			if depth > bestDepth {
+				// Don't push the spill into a deeper loop.
+				continue
+			}
+
+			// If v is in a register at the start of b, we can
+			// place the spill here (after the phis).
+			if len(b.Preds) == 1 {
+				for _, e := range s.endRegs[b.Preds[0].b.ID] {
+					if e.v == v {
+						// Found a better spot for the spill.
+						best = b
+						bestArg = e.c
+						bestDepth = depth
+						break
+					}
+				}
+			} else {
+				for _, e := range s.startRegs[b.ID] {
+					if e.v == v {
+						// Found a better spot for the spill.
+						best = b
+						bestArg = e.c
+						bestDepth = depth
+						break
+					}
+				}
+			}
+		}
+
+		// Put the spill in the best block we found.
+		spill.Block = best
+		spill.AddArg(bestArg)
+		if best == v.Block && v.Op != OpPhi {
+			// Place immediately after v.
+			after[v.ID] = append(after[v.ID], spill)
+		} else {
+			// Place at the start of best block.
+			start[best.ID] = append(start[best.ID], spill)
+		}
+	}
+
+	// Insert spill instructions into the block schedules.
+	var oldSched []*Value
+	for _, b := range f.Blocks {
+		nphi := 0
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				break
+			}
+			nphi++
+		}
+		oldSched = append(oldSched[:0], b.Values[nphi:]...)
+		b.Values = b.Values[:nphi]
+		for _, v := range start[b.ID] {
+			b.Values = append(b.Values, v)
+		}
+		for _, v := range oldSched {
+			b.Values = append(b.Values, v)
+			for _, w := range after[v.ID] {
+				b.Values = append(b.Values, w)
+			}
+		}
+	}
 }
 
 // shuffle fixes up all the merge edges (those going into blocks of indegree > 1).
@@ -1896,17 +1740,17 @@ type edgeState struct {
 }
 
 type contentRecord struct {
-	vid   ID     // pre-regalloc value
-	c     *Value // cached value
-	final bool   // this is a satisfied destination
-	line  int32  // line number of use of the value
+	vid   ID       // pre-regalloc value
+	c     *Value   // cached value
+	final bool     // this is a satisfied destination
+	pos   src.XPos // source position of use of the value
 }
 
 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
-	line   int32    // line number of use of this location
+	pos    src.XPos // source position of use of this location
 }
 
 // setup initializes the edge state for shuffling.
@@ -1929,19 +1773,30 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
 
 	// Live registers can be sources.
 	for _, x := range srcReg {
-		e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number of the source
+		e.set(&e.s.registers[x.r], x.v.ID, x.c, false, src.NoXPos) // don't care the position of the source
 	}
 	// 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, 0) // don't care the line number of the source
+		if !e.s.sdom.isAncestorEq(spill.Block, e.p) {
+			// Spills were placed that only dominate the uses found
+			// during the first regalloc pass. The edge fixup code
+			// can't use a spill location if the spill doesn't dominate
+			// the edge.
+			// We are guaranteed that if the spill doesn't dominate this edge,
+			// then the value is available in a register (because we called
+			// makeSpill for every value not in a register at the start
+			// of an edge).
+			continue
+		}
+		e.set(e.s.f.getHome(spillID), v.ID, spill, false, src.NoXPos) // don't care the position of the source
 	}
 
 	// 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, x.line})
+		dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.v.ID, nil, x.pos})
 	}
 	// Phis need their args to end up in a specific location.
 	for _, v := range e.b.Values {
@@ -1952,7 +1807,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
 		if loc == nil {
 			continue
 		}
-		dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line})
+		dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Pos})
 	}
 	e.destinations = dsts
 
@@ -1977,7 +1832,7 @@ func (e *edgeState) process() {
 	for len(dsts) > 0 {
 		i := 0
 		for _, d := range dsts {
-			if !e.processDest(d.loc, d.vid, d.splice, d.line) {
+			if !e.processDest(d.loc, d.vid, d.splice, d.pos) {
 				// Failed - save for next iteration.
 				dsts[i] = d
 				i++
@@ -2024,29 +1879,25 @@ func (e *edgeState) process() {
 			fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
 		}
 		if _, isReg := loc.(*Register); isReg {
-			c = e.p.NewValue1(d.line, OpCopy, c.Type, c)
+			c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
 		} else {
-			e.s.lateSpillUse(vid)
-			c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c)
+			c = e.p.NewValue1(d.pos, OpLoadReg, c.Type, c)
 		}
-		e.set(r, vid, c, false, d.line)
+		e.set(r, vid, c, false, d.pos)
 	}
 }
 
 // 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, line int32) bool {
+func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XPos) bool {
 	occupant := e.contents[loc]
 	if occupant.vid == vid {
 		// Value is already in the correct place.
-		e.contents[loc] = contentRecord{vid, occupant.c, true, line}
+		e.contents[loc] = contentRecord{vid, occupant.c, true, pos}
 		if splice != nil {
 			(*splice).Uses--
 			*splice = occupant.c
 			occupant.c.Uses++
-			if occupant.c.Op == OpStoreReg {
-				e.s.lateSpillUse(vid)
-			}
 		}
 		// Note: if splice==nil then c will appear dead. This is
 		// non-SSA formed code, so be careful after this pass not to run
@@ -2098,32 +1949,31 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
 			e.s.f.Fatalf("can't find source for %s->%s: %s\n", e.p, e.b, v.LongString())
 		}
 		if dstReg {
-			x = v.copyInto(e.p)
+			x = v.copyIntoNoXPos(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, line)
+			x = v.copyIntoNoXPos(e.p)
+			e.set(r, vid, x, false, pos)
 			// 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(line, OpStoreReg, loc.(LocalSlot).Type, x)
+			x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, x)
 		}
 	} else {
 		// Emit move from src to dst.
 		_, srcReg := src.(*Register)
 		if srcReg {
 			if dstReg {
-				x = e.p.NewValue1(line, OpCopy, c.Type, c)
+				x = e.p.NewValue1(pos, OpCopy, c.Type, c)
 			} else {
-				x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c)
+				x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, c)
 			}
 		} else {
 			if dstReg {
-				e.s.lateSpillUse(vid)
-				x = e.p.NewValue1(line, OpLoadReg, c.Type, c)
+				x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
 			} else {
 				// mem->mem. Use temp register.
 
@@ -2140,14 +1990,13 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
 				e.erase(loc)
 
 				r := e.findRegFor(c.Type)
-				e.s.lateSpillUse(vid)
-				t := e.p.NewValue1(line, OpLoadReg, c.Type, c)
-				e.set(r, vid, t, false, line)
-				x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, t)
+				t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
+				e.set(r, vid, t, false, pos)
+				x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
 			}
 		}
 	}
-	e.set(loc, vid, x, true, line)
+	e.set(loc, vid, x, true, pos)
 	if splice != nil {
 		(*splice).Uses--
 		*splice = x
@@ -2157,10 +2006,10 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
 }
 
 // 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, line int32) {
+func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
 	e.s.f.setHome(c, loc)
 	e.erase(loc)
-	e.contents[loc] = contentRecord{vid, c, final, line}
+	e.contents[loc] = contentRecord{vid, c, final, pos}
 	a := e.cache[vid]
 	if len(a) == 0 {
 		e.cachedVals = append(e.cachedVals, vid)
@@ -2199,7 +2048,7 @@ func (e *edgeState) erase(loc Location) {
 		// 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, cr.line})
+		e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.pos})
 	}
 
 	// Remove c from the list of cached values.
@@ -2230,19 +2079,21 @@ func (e *edgeState) erase(loc Location) {
 }
 
 // findRegFor finds a register we can use to make a temp copy of type typ.
-func (e *edgeState) findRegFor(typ Type) Location {
+func (e *edgeState) findRegFor(typ *types.Type) Location {
 	// Which registers are possibilities.
 	var m regMask
+	types := &e.s.f.Config.Types
 	if typ.IsFloat() {
-		m = e.s.compatRegs(e.s.f.Config.fe.TypeFloat64())
+		m = e.s.compatRegs(types.Float64)
 	} else {
-		m = e.s.compatRegs(e.s.f.Config.fe.TypeInt64())
+		m = e.s.compatRegs(types.Int64)
 	}
 
 	// 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
+	// 4) TODO: a register holding a rematerializeable value
 	x := m &^ e.usedRegs
 	if x != 0 {
 		return &e.s.registers[pickReg(x)]
@@ -2256,22 +2107,23 @@ func (e *edgeState) findRegFor(typ Type) Location {
 		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.
-
+	// No register is available.
 	// 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, c.Line)
-				if e.s.f.pass.debug > regDebug {
-					fmt.Printf("  SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
+				if !c.rematerializeable() {
+					x := e.p.NewValue1(c.Pos, OpStoreReg, c.Type, c)
+					// 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.
+					t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0}
+					// TODO: reuse these slots.
+					e.set(t, vid, x, false, c.Pos)
+					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
@@ -2308,9 +2160,9 @@ func (v *Value) rematerializeable() bool {
 }
 
 type liveInfo struct {
-	ID   ID    // ID of value
-	dist int32 // # of instructions before next use
-	line int32 // line number of next use
+	ID   ID       // ID of value
+	dist int32    // # of instructions before next use
+	pos  src.XPos // source position of next use
 }
 
 // dblock contains information about desired & avoid registers at the end of a block.
@@ -2350,6 +2202,7 @@ func (s *regAllocState) computeLive() {
 	// out to all of them.
 	po := f.postorder()
 	s.loopnest = f.loopnest()
+	s.loopnest.calculateDepths()
 	for {
 		changed := false
 
@@ -2359,12 +2212,12 @@ func (s *regAllocState) computeLive() {
 			// to beginning-of-block distance.
 			live.clear()
 			for _, e := range s.live[b.ID] {
-				live.set(e.ID, e.dist+int32(len(b.Values)), e.line)
+				live.set(e.ID, e.dist+int32(len(b.Values)), e.pos)
 			}
 
 			// Mark control value as live
 			if b.Control != nil && s.values[b.Control.ID].needReg {
-				live.set(b.Control.ID, int32(len(b.Values)), b.Line)
+				live.set(b.Control.ID, int32(len(b.Values)), b.Pos)
 			}
 
 			// Propagate backwards to the start of the block
@@ -2386,7 +2239,7 @@ func (s *regAllocState) computeLive() {
 				}
 				for _, a := range v.Args {
 					if s.values[a.ID].needReg {
-						live.set(a.ID, int32(i), v.Line)
+						live.set(a.ID, int32(i), v.Pos)
 					}
 				}
 			}
@@ -2445,7 +2298,7 @@ func (s *regAllocState) computeLive() {
 				// 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, e.line)
+					t.set(e.ID, e.dist, e.pos)
 				}
 				update := false
 
@@ -2464,7 +2317,7 @@ func (s *regAllocState) computeLive() {
 					id := v.Args[i].ID
 					if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
 						update = true
-						t.set(id, delta, v.Line)
+						t.set(id, delta, v.Pos)
 					}
 				}
 
@@ -2643,3 +2496,16 @@ func (d *desiredState) merge(x *desiredState) {
 		d.addList(e.ID, e.regs)
 	}
 }
+
+func min32(x, y int32) int32 {
+	if x < y {
+		return x
+	}
+	return y
+}
+func max32(x, y int32) int32 {
+	if x > y {
+		return x
+	}
+	return y
+}
diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go
index d3d1891..02751a9 100644
--- a/src/cmd/compile/internal/ssa/regalloc_test.go
+++ b/src/cmd/compile/internal/ssa/regalloc_test.go
@@ -4,17 +4,21 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+	"testing"
+)
 
 func TestLiveControlOps(t *testing.T) {
 	c := testConfig(t)
-	f := Fun(c, "entry",
+	f := c.Fun("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"),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("x", OpAMD64MOVLconst, c.config.Types.Int8, 1, nil),
+			Valu("y", OpAMD64MOVLconst, c.config.Types.Int8, 2, nil),
+			Valu("a", OpAMD64TESTB, types.TypeFlags, 0, nil, "x", "y"),
+			Valu("b", OpAMD64TESTB, types.TypeFlags, 0, nil, "y", "x"),
 			Eq("a", "if", "exit"),
 		),
 		Bloc("if",
@@ -32,24 +36,53 @@ func TestLiveControlOps(t *testing.T) {
 	checkFunc(f.f)
 }
 
-func TestSpillMove(t *testing.T) {
-	// Test for issue 20472. We shouldn't move a spill out to exit blocks
-	// if there is an exit block where the spill is dead but the pre-spill
-	// value is live.
+// Test to make sure we don't push spills into loops.
+// See issue #19595.
+func TestSpillWithLoop(t *testing.T) {
 	c := testConfig(t)
-	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
-	arg1Aux := c.fe.Auto(TypeInt64)
-	arg2Aux := c.fe.Auto(ptrType)
-	f := Fun(c, "entry",
+	f := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("x", OpArg, TypeInt64, 0, arg1Aux),
-			Valu("p", OpArg, ptrType, 0, arg2Aux),
-			Valu("a", OpAMD64TESTQ, TypeFlags, 0, nil, "x", "x"),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("ptr", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
+			Valu("cond", OpArg, c.config.Types.Bool, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Bool)),
+			Valu("ld", OpAMD64MOVQload, c.config.Types.Int64, 0, nil, "ptr", "mem"), // this value needs a spill
+			Goto("loop"),
+		),
+		Bloc("loop",
+			Valu("memphi", OpPhi, types.TypeMem, 0, nil, "mem", "call"),
+			Valu("call", OpAMD64CALLstatic, types.TypeMem, 0, nil, "memphi"),
+			Valu("test", OpAMD64CMPBconst, types.TypeFlags, 0, nil, "cond"),
+			Eq("test", "next", "exit"),
+		),
+		Bloc("next",
+			Goto("loop"),
+		),
+		Bloc("exit",
+			Valu("store", OpAMD64MOVQstore, types.TypeMem, 0, nil, "ptr", "ld", "call"),
+			Exit("store"),
+		),
+	)
+	regalloc(f.f)
+	checkFunc(f.f)
+	for _, v := range f.blocks["loop"].Values {
+		if v.Op == OpStoreReg {
+			t.Errorf("spill inside loop %s", v.LongString())
+		}
+	}
+}
+
+func TestSpillMove1(t *testing.T) {
+	c := testConfig(t)
+	f := c.Fun("entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("x", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
+			Valu("p", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64.PtrTo())),
+			Valu("a", OpAMD64TESTQ, types.TypeFlags, 0, nil, "x", "x"),
 			Goto("loop1"),
 		),
 		Bloc("loop1",
-			Valu("y", OpAMD64MULQ, TypeInt64, 0, nil, "x", "x"),
+			Valu("y", OpAMD64MULQ, c.config.Types.Int64, 0, nil, "x", "x"),
 			Eq("a", "loop2", "exit1"),
 		),
 		Bloc("loop2",
@@ -57,21 +90,71 @@ func TestSpillMove(t *testing.T) {
 		),
 		Bloc("exit1",
 			// store before call, y is available in a register
-			Valu("mem2", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem"),
-			Valu("mem3", OpAMD64CALLstatic, TypeMem, 0, nil, "mem2"),
+			Valu("mem2", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem"),
+			Valu("mem3", OpAMD64CALLstatic, types.TypeMem, 0, nil, "mem2"),
+			Exit("mem3"),
+		),
+		Bloc("exit2",
+			// store after call, y must be loaded from a spill location
+			Valu("mem4", OpAMD64CALLstatic, types.TypeMem, 0, nil, "mem"),
+			Valu("mem5", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem4"),
+			Exit("mem5"),
+		),
+	)
+	flagalloc(f.f)
+	regalloc(f.f)
+	checkFunc(f.f)
+	// Spill should be moved to exit2.
+	if numSpills(f.blocks["loop1"]) != 0 {
+		t.Errorf("spill present from loop1")
+	}
+	if numSpills(f.blocks["loop2"]) != 0 {
+		t.Errorf("spill present in loop2")
+	}
+	if numSpills(f.blocks["exit1"]) != 0 {
+		t.Errorf("spill present in exit1")
+	}
+	if numSpills(f.blocks["exit2"]) != 1 {
+		t.Errorf("spill missing in exit2")
+	}
+
+}
+
+func TestSpillMove2(t *testing.T) {
+	c := testConfig(t)
+	f := c.Fun("entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("x", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
+			Valu("p", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64.PtrTo())),
+			Valu("a", OpAMD64TESTQ, types.TypeFlags, 0, nil, "x", "x"),
+			Goto("loop1"),
+		),
+		Bloc("loop1",
+			Valu("y", OpAMD64MULQ, c.config.Types.Int64, 0, nil, "x", "x"),
+			Eq("a", "loop2", "exit1"),
+		),
+		Bloc("loop2",
+			Eq("a", "loop1", "exit2"),
+		),
+		Bloc("exit1",
+			// store after call, y must be loaded from a spill location
+			Valu("mem2", OpAMD64CALLstatic, types.TypeMem, 0, nil, "mem"),
+			Valu("mem3", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem2"),
 			Exit("mem3"),
 		),
 		Bloc("exit2",
 			// store after call, y must be loaded from a spill location
-			Valu("mem4", OpAMD64CALLstatic, TypeMem, 0, nil, "mem"),
-			Valu("mem5", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem4"),
+			Valu("mem4", OpAMD64CALLstatic, types.TypeMem, 0, nil, "mem"),
+			Valu("mem5", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem4"),
 			Exit("mem5"),
 		),
 	)
 	flagalloc(f.f)
 	regalloc(f.f)
 	checkFunc(f.f)
-	// There should still be a spill in Loop1, and nowhere else.
+	// There should be a spill in loop1, and nowhere else.
+	// TODO: resurrect moving spills out of loops? We could put spills at the start of both exit1 and exit2.
 	if numSpills(f.blocks["loop1"]) != 1 {
 		t.Errorf("spill missing from loop1")
 	}
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 1f9a90f..b42d530 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -5,26 +5,17 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
 	"fmt"
+	"io"
 	"math"
 	"os"
 	"path/filepath"
 )
 
-func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Config) bool) {
+func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
 	// 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 {
@@ -33,11 +24,9 @@ func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Confi
 					b.SetControl(b.Control.Args[0])
 				}
 			}
-			curb = b
-			if rb(b, config) {
+			if rb(b) {
 				change = true
 			}
-			curb = nil
 			for _, v := range b.Values {
 				change = phielimValue(v) || change
 
@@ -62,11 +51,9 @@ func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Confi
 				}
 
 				// apply rewrite function
-				curv = v
-				if rv(v, config) {
+				if rv(v) {
 					change = true
 				}
-				curv = nil
 			}
 		}
 		if !change {
@@ -98,39 +85,39 @@ func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Confi
 
 // Common functions called from rewriting rules
 
-func is64BitFloat(t Type) bool {
+func is64BitFloat(t *types.Type) bool {
 	return t.Size() == 8 && t.IsFloat()
 }
 
-func is32BitFloat(t Type) bool {
+func is32BitFloat(t *types.Type) bool {
 	return t.Size() == 4 && t.IsFloat()
 }
 
-func is64BitInt(t Type) bool {
+func is64BitInt(t *types.Type) bool {
 	return t.Size() == 8 && t.IsInteger()
 }
 
-func is32BitInt(t Type) bool {
+func is32BitInt(t *types.Type) bool {
 	return t.Size() == 4 && t.IsInteger()
 }
 
-func is16BitInt(t Type) bool {
+func is16BitInt(t *types.Type) bool {
 	return t.Size() == 2 && t.IsInteger()
 }
 
-func is8BitInt(t Type) bool {
+func is8BitInt(t *types.Type) bool {
 	return t.Size() == 1 && t.IsInteger()
 }
 
-func isPtr(t Type) bool {
+func isPtr(t *types.Type) bool {
 	return t.IsPtrShaped()
 }
 
-func isSigned(t Type) bool {
+func isSigned(t *types.Type) bool {
 	return t.IsSigned()
 }
 
-func typeSize(t Type) int64 {
+func typeSize(t *types.Type) int64 {
 	return t.Size()
 }
 
@@ -151,12 +138,37 @@ func canMergeSym(x, y interface{}) bool {
 
 // canMergeLoad reports whether the load can be merged into target without
 // invalidating the schedule.
-func canMergeLoad(target, load *Value) bool {
+// It also checks that the other non-load argument x is something we
+// are ok with clobbering (all our current load+op instructions clobber
+// their input register).
+func canMergeLoad(target, load, x *Value) bool {
 	if target.Block.ID != load.Block.ID {
 		// If the load is in a different block do not merge it.
 		return false
 	}
-	mem := load.Args[len(load.Args)-1]
+
+	// We can't merge the load into the target if the load
+	// has more than one use.
+	if load.Uses != 1 {
+		return false
+	}
+
+	// The register containing x is going to get clobbered.
+	// Don't merge if we still need the value of x.
+	// We don't have liveness information here, but we can
+	// approximate x dying with:
+	//  1) target is x's only use.
+	//  2) target is not in a deeper loop than x.
+	if x.Uses != 1 {
+		return false
+	}
+	loopnest := x.Block.Func.loopnest()
+	loopnest.calculateDepths()
+	if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
+		return false
+	}
+
+	mem := load.MemoryArg()
 
 	// We need the load's memory arg to still be alive at target. That
 	// can't be the case if one of target's args depends on a memory
@@ -199,6 +211,8 @@ search:
 		}
 		if v.Op == OpPhi {
 			// A Phi implies we have reached the top of the block.
+			// The memory phi, if it exists, is always
+			// the first logical store in the block.
 			continue search
 		}
 		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
@@ -216,6 +230,8 @@ search:
 				const limit = 50
 				for i := 0; i < limit; i++ {
 					if m.Op == OpPhi {
+						// The memory phi, if it exists, is always
+						// the first logical store in the block.
 						break
 					}
 					if m.Block.ID != target.Block.ID {
@@ -228,7 +244,7 @@ search:
 					if len(m.Args) == 0 {
 						break
 					}
-					m = m.Args[len(m.Args)-1]
+					m = m.MemoryArg()
 				}
 			}
 
@@ -256,6 +272,7 @@ search:
 			}
 		}
 	}
+
 	return true
 }
 
@@ -298,7 +315,7 @@ func nto(x int64) int64 {
 	return ntz(^x)
 }
 
-// log2 returns logarithm in base of uint64(n), with log2(0) = -1.
+// log2 returns logarithm in base 2 of uint64(n), with log2(0) = -1.
 // Rounds down.
 func log2(n int64) (l int64) {
 	l = -1
@@ -339,6 +356,11 @@ func is16Bit(n int64) bool {
 	return n == int64(int16(n))
 }
 
+// isU12Bit reports whether n can be represented as an unsigned 12 bit integer.
+func isU12Bit(n int64) bool {
+	return 0 <= n && n < (1<<12)
+}
+
 // isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
 func isU16Bit(n int64) bool {
 	return n == int64(uint16(n))
@@ -382,6 +404,25 @@ func uaddOvf(a, b int64) bool {
 	return uint64(a)+uint64(b) < uint64(a)
 }
 
+// de-virtualize an InterCall
+// 'sym' is the symbol for the itab
+func devirt(v *Value, sym interface{}, offset int64) *obj.LSym {
+	f := v.Block.Func
+	ext, ok := sym.(*ExternSymbol)
+	if !ok {
+		return nil
+	}
+	lsym := f.fe.DerefItab(ext.Sym, offset)
+	if f.pass.debug > 0 {
+		if lsym != nil {
+			f.Warnl(v.Pos, "de-virtualizing call")
+		} else {
+			f.Warnl(v.Pos, "couldn't de-virtualize call")
+		}
+	}
+	return lsym
+}
+
 // isSamePtr reports whether p1 and p2 point to the same address.
 func isSamePtr(p1, p2 *Value) bool {
 	if p1 == p2 {
@@ -406,7 +447,7 @@ func isSamePtr(p1, p2 *Value) bool {
 // moveSize returns the number of bytes an aligned MOV instruction moves
 func moveSize(align int64, c *Config) int64 {
 	switch {
-	case align%8 == 0 && c.IntSize == 8:
+	case align%8 == 0 && c.PtrSize == 8:
 		return 8
 	case align%4 == 0:
 		return 4
@@ -489,7 +530,7 @@ func noteRule(s string) bool {
 // cond is true and the rule is fired.
 func warnRule(cond bool, v *Value, s string) bool {
 	if cond {
-		v.Block.Func.Config.Warnl(v.Line, s)
+		v.Block.Func.Warnl(v.Pos, s)
 	}
 	return true
 }
@@ -517,4 +558,89 @@ func logRule(s string) {
 	}
 }
 
-var ruleFile *os.File
+var ruleFile io.Writer
+
+func min(x, y int64) int64 {
+	if x < y {
+		return x
+	}
+	return y
+}
+
+func isConstZero(v *Value) bool {
+	switch v.Op {
+	case OpConstNil:
+		return true
+	case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
+		return v.AuxInt == 0
+	}
+	return false
+}
+
+// reciprocalExact64 reports whether 1/c is exactly representable.
+func reciprocalExact64(c float64) bool {
+	b := math.Float64bits(c)
+	man := b & (1<<52 - 1)
+	if man != 0 {
+		return false // not a power of 2, denormal, or NaN
+	}
+	exp := b >> 52 & (1<<11 - 1)
+	// exponent bias is 0x3ff.  So taking the reciprocal of a number
+	// changes the exponent to 0x7fe-exp.
+	switch exp {
+	case 0:
+		return false // ±0
+	case 0x7ff:
+		return false // ±inf
+	case 0x7fe:
+		return false // exponent is not representable
+	default:
+		return true
+	}
+}
+
+// reciprocalExact32 reports whether 1/c is exactly representable.
+func reciprocalExact32(c float32) bool {
+	b := math.Float32bits(c)
+	man := b & (1<<23 - 1)
+	if man != 0 {
+		return false // not a power of 2, denormal, or NaN
+	}
+	exp := b >> 23 & (1<<8 - 1)
+	// exponent bias is 0x7f.  So taking the reciprocal of a number
+	// changes the exponent to 0xfe-exp.
+	switch exp {
+	case 0:
+		return false // ±0
+	case 0xff:
+		return false // ±inf
+	case 0xfe:
+		return false // exponent is not representable
+	default:
+		return true
+	}
+}
+
+// check if an immediate can be directly encoded into an ARM's instruction
+func isARMImmRot(v uint32) bool {
+	for i := 0; i < 16; i++ {
+		if v&^0xff == 0 {
+			return true
+		}
+		v = v<<2 | v>>30
+	}
+
+	return false
+}
+
+// overlap reports whether the ranges given by the given offset and
+// size pairs overlap.
+func overlap(offset1, size1, offset2, size2 int64) bool {
+	if offset1 >= offset2 && offset2+size2 > offset1 {
+		return true
+	}
+	if offset2 >= offset1 && offset1+size1 > offset2 {
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 741886d..f9cddd0 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -1,601 +1,603 @@
-// autogenerated from gen/386.rules: do not edit!
+// Code generated from gen/386.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValue386(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValue386(v *Value) bool {
 	switch v.Op {
 	case Op386ADCL:
-		return rewriteValue386_Op386ADCL(v, config)
+		return rewriteValue386_Op386ADCL_0(v)
 	case Op386ADDL:
-		return rewriteValue386_Op386ADDL(v, config)
+		return rewriteValue386_Op386ADDL_0(v) || rewriteValue386_Op386ADDL_10(v) || rewriteValue386_Op386ADDL_20(v)
 	case Op386ADDLcarry:
-		return rewriteValue386_Op386ADDLcarry(v, config)
+		return rewriteValue386_Op386ADDLcarry_0(v)
 	case Op386ADDLconst:
-		return rewriteValue386_Op386ADDLconst(v, config)
+		return rewriteValue386_Op386ADDLconst_0(v)
 	case Op386ANDL:
-		return rewriteValue386_Op386ANDL(v, config)
+		return rewriteValue386_Op386ANDL_0(v)
 	case Op386ANDLconst:
-		return rewriteValue386_Op386ANDLconst(v, config)
+		return rewriteValue386_Op386ANDLconst_0(v)
 	case Op386CMPB:
-		return rewriteValue386_Op386CMPB(v, config)
+		return rewriteValue386_Op386CMPB_0(v)
 	case Op386CMPBconst:
-		return rewriteValue386_Op386CMPBconst(v, config)
+		return rewriteValue386_Op386CMPBconst_0(v)
 	case Op386CMPL:
-		return rewriteValue386_Op386CMPL(v, config)
+		return rewriteValue386_Op386CMPL_0(v)
 	case Op386CMPLconst:
-		return rewriteValue386_Op386CMPLconst(v, config)
+		return rewriteValue386_Op386CMPLconst_0(v)
 	case Op386CMPW:
-		return rewriteValue386_Op386CMPW(v, config)
+		return rewriteValue386_Op386CMPW_0(v)
 	case Op386CMPWconst:
-		return rewriteValue386_Op386CMPWconst(v, config)
+		return rewriteValue386_Op386CMPWconst_0(v)
 	case Op386LEAL:
-		return rewriteValue386_Op386LEAL(v, config)
+		return rewriteValue386_Op386LEAL_0(v)
 	case Op386LEAL1:
-		return rewriteValue386_Op386LEAL1(v, config)
+		return rewriteValue386_Op386LEAL1_0(v)
 	case Op386LEAL2:
-		return rewriteValue386_Op386LEAL2(v, config)
+		return rewriteValue386_Op386LEAL2_0(v)
 	case Op386LEAL4:
-		return rewriteValue386_Op386LEAL4(v, config)
+		return rewriteValue386_Op386LEAL4_0(v)
 	case Op386LEAL8:
-		return rewriteValue386_Op386LEAL8(v, config)
+		return rewriteValue386_Op386LEAL8_0(v)
 	case Op386MOVBLSX:
-		return rewriteValue386_Op386MOVBLSX(v, config)
+		return rewriteValue386_Op386MOVBLSX_0(v)
 	case Op386MOVBLSXload:
-		return rewriteValue386_Op386MOVBLSXload(v, config)
+		return rewriteValue386_Op386MOVBLSXload_0(v)
 	case Op386MOVBLZX:
-		return rewriteValue386_Op386MOVBLZX(v, config)
+		return rewriteValue386_Op386MOVBLZX_0(v)
 	case Op386MOVBload:
-		return rewriteValue386_Op386MOVBload(v, config)
+		return rewriteValue386_Op386MOVBload_0(v)
 	case Op386MOVBloadidx1:
-		return rewriteValue386_Op386MOVBloadidx1(v, config)
+		return rewriteValue386_Op386MOVBloadidx1_0(v)
 	case Op386MOVBstore:
-		return rewriteValue386_Op386MOVBstore(v, config)
+		return rewriteValue386_Op386MOVBstore_0(v)
 	case Op386MOVBstoreconst:
-		return rewriteValue386_Op386MOVBstoreconst(v, config)
+		return rewriteValue386_Op386MOVBstoreconst_0(v)
 	case Op386MOVBstoreconstidx1:
-		return rewriteValue386_Op386MOVBstoreconstidx1(v, config)
+		return rewriteValue386_Op386MOVBstoreconstidx1_0(v)
 	case Op386MOVBstoreidx1:
-		return rewriteValue386_Op386MOVBstoreidx1(v, config)
+		return rewriteValue386_Op386MOVBstoreidx1_0(v) || rewriteValue386_Op386MOVBstoreidx1_10(v)
 	case Op386MOVLload:
-		return rewriteValue386_Op386MOVLload(v, config)
+		return rewriteValue386_Op386MOVLload_0(v)
 	case Op386MOVLloadidx1:
-		return rewriteValue386_Op386MOVLloadidx1(v, config)
+		return rewriteValue386_Op386MOVLloadidx1_0(v)
 	case Op386MOVLloadidx4:
-		return rewriteValue386_Op386MOVLloadidx4(v, config)
+		return rewriteValue386_Op386MOVLloadidx4_0(v)
 	case Op386MOVLstore:
-		return rewriteValue386_Op386MOVLstore(v, config)
+		return rewriteValue386_Op386MOVLstore_0(v)
 	case Op386MOVLstoreconst:
-		return rewriteValue386_Op386MOVLstoreconst(v, config)
+		return rewriteValue386_Op386MOVLstoreconst_0(v)
 	case Op386MOVLstoreconstidx1:
-		return rewriteValue386_Op386MOVLstoreconstidx1(v, config)
+		return rewriteValue386_Op386MOVLstoreconstidx1_0(v)
 	case Op386MOVLstoreconstidx4:
-		return rewriteValue386_Op386MOVLstoreconstidx4(v, config)
+		return rewriteValue386_Op386MOVLstoreconstidx4_0(v)
 	case Op386MOVLstoreidx1:
-		return rewriteValue386_Op386MOVLstoreidx1(v, config)
+		return rewriteValue386_Op386MOVLstoreidx1_0(v)
 	case Op386MOVLstoreidx4:
-		return rewriteValue386_Op386MOVLstoreidx4(v, config)
+		return rewriteValue386_Op386MOVLstoreidx4_0(v)
 	case Op386MOVSDconst:
-		return rewriteValue386_Op386MOVSDconst(v, config)
+		return rewriteValue386_Op386MOVSDconst_0(v)
 	case Op386MOVSDload:
-		return rewriteValue386_Op386MOVSDload(v, config)
+		return rewriteValue386_Op386MOVSDload_0(v)
 	case Op386MOVSDloadidx1:
-		return rewriteValue386_Op386MOVSDloadidx1(v, config)
+		return rewriteValue386_Op386MOVSDloadidx1_0(v)
 	case Op386MOVSDloadidx8:
-		return rewriteValue386_Op386MOVSDloadidx8(v, config)
+		return rewriteValue386_Op386MOVSDloadidx8_0(v)
 	case Op386MOVSDstore:
-		return rewriteValue386_Op386MOVSDstore(v, config)
+		return rewriteValue386_Op386MOVSDstore_0(v)
 	case Op386MOVSDstoreidx1:
-		return rewriteValue386_Op386MOVSDstoreidx1(v, config)
+		return rewriteValue386_Op386MOVSDstoreidx1_0(v)
 	case Op386MOVSDstoreidx8:
-		return rewriteValue386_Op386MOVSDstoreidx8(v, config)
+		return rewriteValue386_Op386MOVSDstoreidx8_0(v)
 	case Op386MOVSSconst:
-		return rewriteValue386_Op386MOVSSconst(v, config)
+		return rewriteValue386_Op386MOVSSconst_0(v)
 	case Op386MOVSSload:
-		return rewriteValue386_Op386MOVSSload(v, config)
+		return rewriteValue386_Op386MOVSSload_0(v)
 	case Op386MOVSSloadidx1:
-		return rewriteValue386_Op386MOVSSloadidx1(v, config)
+		return rewriteValue386_Op386MOVSSloadidx1_0(v)
 	case Op386MOVSSloadidx4:
-		return rewriteValue386_Op386MOVSSloadidx4(v, config)
+		return rewriteValue386_Op386MOVSSloadidx4_0(v)
 	case Op386MOVSSstore:
-		return rewriteValue386_Op386MOVSSstore(v, config)
+		return rewriteValue386_Op386MOVSSstore_0(v)
 	case Op386MOVSSstoreidx1:
-		return rewriteValue386_Op386MOVSSstoreidx1(v, config)
+		return rewriteValue386_Op386MOVSSstoreidx1_0(v)
 	case Op386MOVSSstoreidx4:
-		return rewriteValue386_Op386MOVSSstoreidx4(v, config)
+		return rewriteValue386_Op386MOVSSstoreidx4_0(v)
 	case Op386MOVWLSX:
-		return rewriteValue386_Op386MOVWLSX(v, config)
+		return rewriteValue386_Op386MOVWLSX_0(v)
 	case Op386MOVWLSXload:
-		return rewriteValue386_Op386MOVWLSXload(v, config)
+		return rewriteValue386_Op386MOVWLSXload_0(v)
 	case Op386MOVWLZX:
-		return rewriteValue386_Op386MOVWLZX(v, config)
+		return rewriteValue386_Op386MOVWLZX_0(v)
 	case Op386MOVWload:
-		return rewriteValue386_Op386MOVWload(v, config)
+		return rewriteValue386_Op386MOVWload_0(v)
 	case Op386MOVWloadidx1:
-		return rewriteValue386_Op386MOVWloadidx1(v, config)
+		return rewriteValue386_Op386MOVWloadidx1_0(v)
 	case Op386MOVWloadidx2:
-		return rewriteValue386_Op386MOVWloadidx2(v, config)
+		return rewriteValue386_Op386MOVWloadidx2_0(v)
 	case Op386MOVWstore:
-		return rewriteValue386_Op386MOVWstore(v, config)
+		return rewriteValue386_Op386MOVWstore_0(v)
 	case Op386MOVWstoreconst:
-		return rewriteValue386_Op386MOVWstoreconst(v, config)
+		return rewriteValue386_Op386MOVWstoreconst_0(v)
 	case Op386MOVWstoreconstidx1:
-		return rewriteValue386_Op386MOVWstoreconstidx1(v, config)
+		return rewriteValue386_Op386MOVWstoreconstidx1_0(v)
 	case Op386MOVWstoreconstidx2:
-		return rewriteValue386_Op386MOVWstoreconstidx2(v, config)
+		return rewriteValue386_Op386MOVWstoreconstidx2_0(v)
 	case Op386MOVWstoreidx1:
-		return rewriteValue386_Op386MOVWstoreidx1(v, config)
+		return rewriteValue386_Op386MOVWstoreidx1_0(v) || rewriteValue386_Op386MOVWstoreidx1_10(v)
 	case Op386MOVWstoreidx2:
-		return rewriteValue386_Op386MOVWstoreidx2(v, config)
+		return rewriteValue386_Op386MOVWstoreidx2_0(v)
 	case Op386MULL:
-		return rewriteValue386_Op386MULL(v, config)
+		return rewriteValue386_Op386MULL_0(v)
 	case Op386MULLconst:
-		return rewriteValue386_Op386MULLconst(v, config)
+		return rewriteValue386_Op386MULLconst_0(v) || rewriteValue386_Op386MULLconst_10(v) || rewriteValue386_Op386MULLconst_20(v)
 	case Op386NEGL:
-		return rewriteValue386_Op386NEGL(v, config)
+		return rewriteValue386_Op386NEGL_0(v)
 	case Op386NOTL:
-		return rewriteValue386_Op386NOTL(v, config)
+		return rewriteValue386_Op386NOTL_0(v)
 	case Op386ORL:
-		return rewriteValue386_Op386ORL(v, config)
+		return rewriteValue386_Op386ORL_0(v) || rewriteValue386_Op386ORL_10(v) || rewriteValue386_Op386ORL_20(v) || rewriteValue386_Op386ORL_30(v) || rewriteValue386_Op386ORL_40(v) || rewriteValue386_Op386ORL_50(v)
 	case Op386ORLconst:
-		return rewriteValue386_Op386ORLconst(v, config)
+		return rewriteValue386_Op386ORLconst_0(v)
 	case Op386ROLBconst:
-		return rewriteValue386_Op386ROLBconst(v, config)
+		return rewriteValue386_Op386ROLBconst_0(v)
 	case Op386ROLLconst:
-		return rewriteValue386_Op386ROLLconst(v, config)
+		return rewriteValue386_Op386ROLLconst_0(v)
 	case Op386ROLWconst:
-		return rewriteValue386_Op386ROLWconst(v, config)
+		return rewriteValue386_Op386ROLWconst_0(v)
 	case Op386SARB:
-		return rewriteValue386_Op386SARB(v, config)
+		return rewriteValue386_Op386SARB_0(v)
 	case Op386SARBconst:
-		return rewriteValue386_Op386SARBconst(v, config)
+		return rewriteValue386_Op386SARBconst_0(v)
 	case Op386SARL:
-		return rewriteValue386_Op386SARL(v, config)
+		return rewriteValue386_Op386SARL_0(v)
 	case Op386SARLconst:
-		return rewriteValue386_Op386SARLconst(v, config)
+		return rewriteValue386_Op386SARLconst_0(v)
 	case Op386SARW:
-		return rewriteValue386_Op386SARW(v, config)
+		return rewriteValue386_Op386SARW_0(v)
 	case Op386SARWconst:
-		return rewriteValue386_Op386SARWconst(v, config)
+		return rewriteValue386_Op386SARWconst_0(v)
 	case Op386SBBL:
-		return rewriteValue386_Op386SBBL(v, config)
+		return rewriteValue386_Op386SBBL_0(v)
 	case Op386SBBLcarrymask:
-		return rewriteValue386_Op386SBBLcarrymask(v, config)
+		return rewriteValue386_Op386SBBLcarrymask_0(v)
 	case Op386SETA:
-		return rewriteValue386_Op386SETA(v, config)
+		return rewriteValue386_Op386SETA_0(v)
 	case Op386SETAE:
-		return rewriteValue386_Op386SETAE(v, config)
+		return rewriteValue386_Op386SETAE_0(v)
 	case Op386SETB:
-		return rewriteValue386_Op386SETB(v, config)
+		return rewriteValue386_Op386SETB_0(v)
 	case Op386SETBE:
-		return rewriteValue386_Op386SETBE(v, config)
+		return rewriteValue386_Op386SETBE_0(v)
 	case Op386SETEQ:
-		return rewriteValue386_Op386SETEQ(v, config)
+		return rewriteValue386_Op386SETEQ_0(v)
 	case Op386SETG:
-		return rewriteValue386_Op386SETG(v, config)
+		return rewriteValue386_Op386SETG_0(v)
 	case Op386SETGE:
-		return rewriteValue386_Op386SETGE(v, config)
+		return rewriteValue386_Op386SETGE_0(v)
 	case Op386SETL:
-		return rewriteValue386_Op386SETL(v, config)
+		return rewriteValue386_Op386SETL_0(v)
 	case Op386SETLE:
-		return rewriteValue386_Op386SETLE(v, config)
+		return rewriteValue386_Op386SETLE_0(v)
 	case Op386SETNE:
-		return rewriteValue386_Op386SETNE(v, config)
+		return rewriteValue386_Op386SETNE_0(v)
 	case Op386SHLL:
-		return rewriteValue386_Op386SHLL(v, config)
+		return rewriteValue386_Op386SHLL_0(v)
+	case Op386SHLLconst:
+		return rewriteValue386_Op386SHLLconst_0(v)
 	case Op386SHRB:
-		return rewriteValue386_Op386SHRB(v, config)
+		return rewriteValue386_Op386SHRB_0(v)
+	case Op386SHRBconst:
+		return rewriteValue386_Op386SHRBconst_0(v)
 	case Op386SHRL:
-		return rewriteValue386_Op386SHRL(v, config)
+		return rewriteValue386_Op386SHRL_0(v)
+	case Op386SHRLconst:
+		return rewriteValue386_Op386SHRLconst_0(v)
 	case Op386SHRW:
-		return rewriteValue386_Op386SHRW(v, config)
+		return rewriteValue386_Op386SHRW_0(v)
+	case Op386SHRWconst:
+		return rewriteValue386_Op386SHRWconst_0(v)
 	case Op386SUBL:
-		return rewriteValue386_Op386SUBL(v, config)
+		return rewriteValue386_Op386SUBL_0(v)
 	case Op386SUBLcarry:
-		return rewriteValue386_Op386SUBLcarry(v, config)
+		return rewriteValue386_Op386SUBLcarry_0(v)
 	case Op386SUBLconst:
-		return rewriteValue386_Op386SUBLconst(v, config)
+		return rewriteValue386_Op386SUBLconst_0(v)
 	case Op386XORL:
-		return rewriteValue386_Op386XORL(v, config)
+		return rewriteValue386_Op386XORL_0(v)
 	case Op386XORLconst:
-		return rewriteValue386_Op386XORLconst(v, config)
+		return rewriteValue386_Op386XORLconst_0(v)
 	case OpAdd16:
-		return rewriteValue386_OpAdd16(v, config)
+		return rewriteValue386_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValue386_OpAdd32(v, config)
+		return rewriteValue386_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValue386_OpAdd32F(v, config)
+		return rewriteValue386_OpAdd32F_0(v)
 	case OpAdd32carry:
-		return rewriteValue386_OpAdd32carry(v, config)
+		return rewriteValue386_OpAdd32carry_0(v)
 	case OpAdd32withcarry:
-		return rewriteValue386_OpAdd32withcarry(v, config)
+		return rewriteValue386_OpAdd32withcarry_0(v)
 	case OpAdd64F:
-		return rewriteValue386_OpAdd64F(v, config)
+		return rewriteValue386_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValue386_OpAdd8(v, config)
+		return rewriteValue386_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValue386_OpAddPtr(v, config)
+		return rewriteValue386_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValue386_OpAddr(v, config)
+		return rewriteValue386_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValue386_OpAnd16(v, config)
+		return rewriteValue386_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValue386_OpAnd32(v, config)
+		return rewriteValue386_OpAnd32_0(v)
 	case OpAnd8:
-		return rewriteValue386_OpAnd8(v, config)
+		return rewriteValue386_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValue386_OpAndB(v, config)
+		return rewriteValue386_OpAndB_0(v)
+	case OpAvg32u:
+		return rewriteValue386_OpAvg32u_0(v)
 	case OpBswap32:
-		return rewriteValue386_OpBswap32(v, config)
+		return rewriteValue386_OpBswap32_0(v)
 	case OpClosureCall:
-		return rewriteValue386_OpClosureCall(v, config)
+		return rewriteValue386_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValue386_OpCom16(v, config)
+		return rewriteValue386_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValue386_OpCom32(v, config)
+		return rewriteValue386_OpCom32_0(v)
 	case OpCom8:
-		return rewriteValue386_OpCom8(v, config)
+		return rewriteValue386_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValue386_OpConst16(v, config)
+		return rewriteValue386_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValue386_OpConst32(v, config)
+		return rewriteValue386_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValue386_OpConst32F(v, config)
+		return rewriteValue386_OpConst32F_0(v)
 	case OpConst64F:
-		return rewriteValue386_OpConst64F(v, config)
+		return rewriteValue386_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValue386_OpConst8(v, config)
+		return rewriteValue386_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValue386_OpConstBool(v, config)
+		return rewriteValue386_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValue386_OpConstNil(v, config)
+		return rewriteValue386_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValue386_OpConvert(v, config)
+		return rewriteValue386_OpConvert_0(v)
 	case OpCvt32Fto32:
-		return rewriteValue386_OpCvt32Fto32(v, config)
+		return rewriteValue386_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValue386_OpCvt32Fto64F(v, config)
+		return rewriteValue386_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValue386_OpCvt32to32F(v, config)
+		return rewriteValue386_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValue386_OpCvt32to64F(v, config)
+		return rewriteValue386_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValue386_OpCvt64Fto32(v, config)
+		return rewriteValue386_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValue386_OpCvt64Fto32F(v, config)
-	case OpDeferCall:
-		return rewriteValue386_OpDeferCall(v, config)
+		return rewriteValue386_OpCvt64Fto32F_0(v)
 	case OpDiv16:
-		return rewriteValue386_OpDiv16(v, config)
+		return rewriteValue386_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValue386_OpDiv16u(v, config)
+		return rewriteValue386_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValue386_OpDiv32(v, config)
+		return rewriteValue386_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValue386_OpDiv32F(v, config)
+		return rewriteValue386_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValue386_OpDiv32u(v, config)
+		return rewriteValue386_OpDiv32u_0(v)
 	case OpDiv64F:
-		return rewriteValue386_OpDiv64F(v, config)
+		return rewriteValue386_OpDiv64F_0(v)
 	case OpDiv8:
-		return rewriteValue386_OpDiv8(v, config)
+		return rewriteValue386_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValue386_OpDiv8u(v, config)
+		return rewriteValue386_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValue386_OpEq16(v, config)
+		return rewriteValue386_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValue386_OpEq32(v, config)
+		return rewriteValue386_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValue386_OpEq32F(v, config)
+		return rewriteValue386_OpEq32F_0(v)
 	case OpEq64F:
-		return rewriteValue386_OpEq64F(v, config)
+		return rewriteValue386_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValue386_OpEq8(v, config)
+		return rewriteValue386_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValue386_OpEqB(v, config)
+		return rewriteValue386_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValue386_OpEqPtr(v, config)
+		return rewriteValue386_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValue386_OpGeq16(v, config)
+		return rewriteValue386_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValue386_OpGeq16U(v, config)
+		return rewriteValue386_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValue386_OpGeq32(v, config)
+		return rewriteValue386_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValue386_OpGeq32F(v, config)
+		return rewriteValue386_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValue386_OpGeq32U(v, config)
+		return rewriteValue386_OpGeq32U_0(v)
 	case OpGeq64F:
-		return rewriteValue386_OpGeq64F(v, config)
+		return rewriteValue386_OpGeq64F_0(v)
 	case OpGeq8:
-		return rewriteValue386_OpGeq8(v, config)
+		return rewriteValue386_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValue386_OpGeq8U(v, config)
+		return rewriteValue386_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValue386_OpGetClosurePtr(v, config)
+		return rewriteValue386_OpGetClosurePtr_0(v)
 	case OpGetG:
-		return rewriteValue386_OpGetG(v, config)
-	case OpGoCall:
-		return rewriteValue386_OpGoCall(v, config)
+		return rewriteValue386_OpGetG_0(v)
 	case OpGreater16:
-		return rewriteValue386_OpGreater16(v, config)
+		return rewriteValue386_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValue386_OpGreater16U(v, config)
+		return rewriteValue386_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValue386_OpGreater32(v, config)
+		return rewriteValue386_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValue386_OpGreater32F(v, config)
+		return rewriteValue386_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValue386_OpGreater32U(v, config)
+		return rewriteValue386_OpGreater32U_0(v)
 	case OpGreater64F:
-		return rewriteValue386_OpGreater64F(v, config)
+		return rewriteValue386_OpGreater64F_0(v)
 	case OpGreater8:
-		return rewriteValue386_OpGreater8(v, config)
+		return rewriteValue386_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValue386_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValue386_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValue386_OpHmul16u(v, config)
+		return rewriteValue386_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValue386_OpHmul32(v, config)
+		return rewriteValue386_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValue386_OpHmul32u(v, config)
-	case OpHmul8:
-		return rewriteValue386_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValue386_OpHmul8u(v, config)
+		return rewriteValue386_OpHmul32u_0(v)
 	case OpInterCall:
-		return rewriteValue386_OpInterCall(v, config)
+		return rewriteValue386_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValue386_OpIsInBounds(v, config)
+		return rewriteValue386_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValue386_OpIsNonNil(v, config)
+		return rewriteValue386_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValue386_OpIsSliceInBounds(v, config)
+		return rewriteValue386_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValue386_OpLeq16(v, config)
+		return rewriteValue386_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValue386_OpLeq16U(v, config)
+		return rewriteValue386_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValue386_OpLeq32(v, config)
+		return rewriteValue386_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValue386_OpLeq32F(v, config)
+		return rewriteValue386_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValue386_OpLeq32U(v, config)
+		return rewriteValue386_OpLeq32U_0(v)
 	case OpLeq64F:
-		return rewriteValue386_OpLeq64F(v, config)
+		return rewriteValue386_OpLeq64F_0(v)
 	case OpLeq8:
-		return rewriteValue386_OpLeq8(v, config)
+		return rewriteValue386_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValue386_OpLeq8U(v, config)
+		return rewriteValue386_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValue386_OpLess16(v, config)
+		return rewriteValue386_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValue386_OpLess16U(v, config)
+		return rewriteValue386_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValue386_OpLess32(v, config)
+		return rewriteValue386_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValue386_OpLess32F(v, config)
+		return rewriteValue386_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValue386_OpLess32U(v, config)
+		return rewriteValue386_OpLess32U_0(v)
 	case OpLess64F:
-		return rewriteValue386_OpLess64F(v, config)
+		return rewriteValue386_OpLess64F_0(v)
 	case OpLess8:
-		return rewriteValue386_OpLess8(v, config)
+		return rewriteValue386_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValue386_OpLess8U(v, config)
+		return rewriteValue386_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValue386_OpLoad(v, config)
-	case OpLrot16:
-		return rewriteValue386_OpLrot16(v, config)
-	case OpLrot32:
-		return rewriteValue386_OpLrot32(v, config)
-	case OpLrot8:
-		return rewriteValue386_OpLrot8(v, config)
+		return rewriteValue386_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValue386_OpLsh16x16(v, config)
+		return rewriteValue386_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValue386_OpLsh16x32(v, config)
+		return rewriteValue386_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValue386_OpLsh16x64(v, config)
+		return rewriteValue386_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValue386_OpLsh16x8(v, config)
+		return rewriteValue386_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValue386_OpLsh32x16(v, config)
+		return rewriteValue386_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValue386_OpLsh32x32(v, config)
+		return rewriteValue386_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValue386_OpLsh32x64(v, config)
+		return rewriteValue386_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValue386_OpLsh32x8(v, config)
+		return rewriteValue386_OpLsh32x8_0(v)
 	case OpLsh8x16:
-		return rewriteValue386_OpLsh8x16(v, config)
+		return rewriteValue386_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValue386_OpLsh8x32(v, config)
+		return rewriteValue386_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValue386_OpLsh8x64(v, config)
+		return rewriteValue386_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValue386_OpLsh8x8(v, config)
+		return rewriteValue386_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValue386_OpMod16(v, config)
+		return rewriteValue386_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValue386_OpMod16u(v, config)
+		return rewriteValue386_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValue386_OpMod32(v, config)
+		return rewriteValue386_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValue386_OpMod32u(v, config)
+		return rewriteValue386_OpMod32u_0(v)
 	case OpMod8:
-		return rewriteValue386_OpMod8(v, config)
+		return rewriteValue386_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValue386_OpMod8u(v, config)
+		return rewriteValue386_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValue386_OpMove(v, config)
+		return rewriteValue386_OpMove_0(v) || rewriteValue386_OpMove_10(v)
 	case OpMul16:
-		return rewriteValue386_OpMul16(v, config)
+		return rewriteValue386_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValue386_OpMul32(v, config)
+		return rewriteValue386_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValue386_OpMul32F(v, config)
+		return rewriteValue386_OpMul32F_0(v)
 	case OpMul32uhilo:
-		return rewriteValue386_OpMul32uhilo(v, config)
+		return rewriteValue386_OpMul32uhilo_0(v)
 	case OpMul64F:
-		return rewriteValue386_OpMul64F(v, config)
+		return rewriteValue386_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValue386_OpMul8(v, config)
+		return rewriteValue386_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValue386_OpNeg16(v, config)
+		return rewriteValue386_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValue386_OpNeg32(v, config)
+		return rewriteValue386_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValue386_OpNeg32F(v, config)
+		return rewriteValue386_OpNeg32F_0(v)
 	case OpNeg64F:
-		return rewriteValue386_OpNeg64F(v, config)
+		return rewriteValue386_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValue386_OpNeg8(v, config)
+		return rewriteValue386_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValue386_OpNeq16(v, config)
+		return rewriteValue386_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValue386_OpNeq32(v, config)
+		return rewriteValue386_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValue386_OpNeq32F(v, config)
+		return rewriteValue386_OpNeq32F_0(v)
 	case OpNeq64F:
-		return rewriteValue386_OpNeq64F(v, config)
+		return rewriteValue386_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValue386_OpNeq8(v, config)
+		return rewriteValue386_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValue386_OpNeqB(v, config)
+		return rewriteValue386_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValue386_OpNeqPtr(v, config)
+		return rewriteValue386_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValue386_OpNilCheck(v, config)
+		return rewriteValue386_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValue386_OpNot(v, config)
+		return rewriteValue386_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValue386_OpOffPtr(v, config)
+		return rewriteValue386_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValue386_OpOr16(v, config)
+		return rewriteValue386_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValue386_OpOr32(v, config)
+		return rewriteValue386_OpOr32_0(v)
 	case OpOr8:
-		return rewriteValue386_OpOr8(v, config)
+		return rewriteValue386_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValue386_OpOrB(v, config)
+		return rewriteValue386_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValue386_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValue386_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValue386_OpRsh16Ux16(v, config)
+		return rewriteValue386_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValue386_OpRsh16Ux32(v, config)
+		return rewriteValue386_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValue386_OpRsh16Ux64(v, config)
+		return rewriteValue386_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValue386_OpRsh16Ux8(v, config)
+		return rewriteValue386_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValue386_OpRsh16x16(v, config)
+		return rewriteValue386_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValue386_OpRsh16x32(v, config)
+		return rewriteValue386_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValue386_OpRsh16x64(v, config)
+		return rewriteValue386_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValue386_OpRsh16x8(v, config)
+		return rewriteValue386_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValue386_OpRsh32Ux16(v, config)
+		return rewriteValue386_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValue386_OpRsh32Ux32(v, config)
+		return rewriteValue386_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValue386_OpRsh32Ux64(v, config)
+		return rewriteValue386_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValue386_OpRsh32Ux8(v, config)
+		return rewriteValue386_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValue386_OpRsh32x16(v, config)
+		return rewriteValue386_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValue386_OpRsh32x32(v, config)
+		return rewriteValue386_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValue386_OpRsh32x64(v, config)
+		return rewriteValue386_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValue386_OpRsh32x8(v, config)
+		return rewriteValue386_OpRsh32x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValue386_OpRsh8Ux16(v, config)
+		return rewriteValue386_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValue386_OpRsh8Ux32(v, config)
+		return rewriteValue386_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValue386_OpRsh8Ux64(v, config)
+		return rewriteValue386_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValue386_OpRsh8Ux8(v, config)
+		return rewriteValue386_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValue386_OpRsh8x16(v, config)
+		return rewriteValue386_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValue386_OpRsh8x32(v, config)
+		return rewriteValue386_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValue386_OpRsh8x64(v, config)
+		return rewriteValue386_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValue386_OpRsh8x8(v, config)
+		return rewriteValue386_OpRsh8x8_0(v)
 	case OpSignExt16to32:
-		return rewriteValue386_OpSignExt16to32(v, config)
+		return rewriteValue386_OpSignExt16to32_0(v)
 	case OpSignExt8to16:
-		return rewriteValue386_OpSignExt8to16(v, config)
+		return rewriteValue386_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValue386_OpSignExt8to32(v, config)
+		return rewriteValue386_OpSignExt8to32_0(v)
 	case OpSignmask:
-		return rewriteValue386_OpSignmask(v, config)
+		return rewriteValue386_OpSignmask_0(v)
 	case OpSlicemask:
-		return rewriteValue386_OpSlicemask(v, config)
+		return rewriteValue386_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValue386_OpSqrt(v, config)
+		return rewriteValue386_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValue386_OpStaticCall(v, config)
+		return rewriteValue386_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValue386_OpStore(v, config)
+		return rewriteValue386_OpStore_0(v)
 	case OpSub16:
-		return rewriteValue386_OpSub16(v, config)
+		return rewriteValue386_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValue386_OpSub32(v, config)
+		return rewriteValue386_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValue386_OpSub32F(v, config)
+		return rewriteValue386_OpSub32F_0(v)
 	case OpSub32carry:
-		return rewriteValue386_OpSub32carry(v, config)
+		return rewriteValue386_OpSub32carry_0(v)
 	case OpSub32withcarry:
-		return rewriteValue386_OpSub32withcarry(v, config)
+		return rewriteValue386_OpSub32withcarry_0(v)
 	case OpSub64F:
-		return rewriteValue386_OpSub64F(v, config)
+		return rewriteValue386_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValue386_OpSub8(v, config)
+		return rewriteValue386_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValue386_OpSubPtr(v, config)
+		return rewriteValue386_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValue386_OpTrunc16to8(v, config)
+		return rewriteValue386_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValue386_OpTrunc32to16(v, config)
+		return rewriteValue386_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValue386_OpTrunc32to8(v, config)
+		return rewriteValue386_OpTrunc32to8_0(v)
 	case OpXor16:
-		return rewriteValue386_OpXor16(v, config)
+		return rewriteValue386_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValue386_OpXor32(v, config)
+		return rewriteValue386_OpXor32_0(v)
 	case OpXor8:
-		return rewriteValue386_OpXor8(v, config)
+		return rewriteValue386_OpXor8_0(v)
 	case OpZero:
-		return rewriteValue386_OpZero(v, config)
+		return rewriteValue386_OpZero_0(v) || rewriteValue386_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValue386_OpZeroExt16to32(v, config)
+		return rewriteValue386_OpZeroExt16to32_0(v)
 	case OpZeroExt8to16:
-		return rewriteValue386_OpZeroExt8to16(v, config)
+		return rewriteValue386_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValue386_OpZeroExt8to32(v, config)
+		return rewriteValue386_OpZeroExt8to32_0(v)
 	case OpZeromask:
-		return rewriteValue386_OpZeromask(v, config)
+		return rewriteValue386_OpZeromask_0(v)
 	}
 	return false
 }
-func rewriteValue386_Op386ADCL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ADCL_0(v *Value) bool {
 	// match: (ADCL x (MOVLconst [c]) f)
 	// cond:
 	// result: (ADCLconst [c] x f)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -613,6 +615,25 @@ func rewriteValue386_Op386ADCL(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCLconst [c] x f)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		f := v.Args[2]
+		v.reset(Op386ADCLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(f)
+		return true
+	}
+	// match: (ADCL (MOVLconst [c]) x f)
+	// cond:
+	// result: (ADCLconst [c] x f)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -626,15 +647,32 @@ func rewriteValue386_Op386ADCL(v *Value, config *Config) bool {
 		v.AddArg(f)
 		return true
 	}
+	// match: (ADCL x (MOVLconst [c]) f)
+	// cond:
+	// result: (ADCLconst [c] x f)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		f := v.Args[2]
+		v.reset(Op386ADCLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(f)
+		return true
+	}
 	return false
 }
-func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ADDL_0(v *Value) bool {
 	// match: (ADDL x (MOVLconst [c]))
 	// cond:
 	// result: (ADDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -650,6 +688,7 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -661,10 +700,177 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDL (SHLLconst [c] x) (SHRLconst [d] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRLconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL (SHRLconst [d] x) (SHLLconst [c] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRBconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRBconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ADDL x (SHLLconst [3] y))
 	// cond:
 	// result: (LEAL8 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -679,10 +885,33 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (SHLLconst [3] y) x)
+	// cond:
+	// result: (LEAL8 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		if v_0.AuxInt != 3 {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(Op386LEAL8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ADDL_10(v *Value) bool {
 	// match: (ADDL x (SHLLconst [2] y))
 	// cond:
 	// result: (LEAL4 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -697,10 +926,30 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (SHLLconst [2] y) x)
+	// cond:
+	// result: (LEAL4 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		if v_0.AuxInt != 2 {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(Op386LEAL4)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADDL x (SHLLconst [1] y))
 	// cond:
 	// result: (LEAL2 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -715,15 +964,36 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (SHLLconst [1] y) x)
+	// cond:
+	// result: (LEAL2 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(Op386LEAL2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADDL x (ADDL y y))
 	// cond:
 	// result: (LEAL2 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		if y != v_1.Args[1] {
 			break
@@ -733,15 +1003,37 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (ADDL y y) x)
+	// cond:
+	// result: (LEAL2 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		if y != v_0.Args[1] {
+			break
+		}
+		x := v.Args[1]
+		v.reset(Op386LEAL2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADDL x (ADDL x y))
 	// cond:
 	// result: (LEAL2 y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDL {
 			break
 		}
+		_ = v_1.Args[1]
 		if x != v_1.Args[0] {
 			break
 		}
@@ -755,11 +1047,13 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (LEAL2 y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		if x != v_1.Args[1] {
 			break
@@ -769,34 +1063,79 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADDL (ADDLconst [c] x) y)
+	// match: (ADDL (ADDL x y) x)
 	// cond:
-	// result: (LEAL1 [c] x y)
+	// result: (LEAL2 y x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		if v_0.Op != Op386ADDL {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v.Args[1]
-		v.reset(Op386LEAL1)
-		v.AuxInt = c
-		v.AddArg(x)
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(Op386LEAL2)
 		v.AddArg(y)
+		v.AddArg(x)
 		return true
 	}
-	// match: (ADDL x (ADDLconst [c] y))
+	// match: (ADDL (ADDL y x) x)
 	// cond:
-	// result: (LEAL1 [c] x y)
+	// result: (LEAL2 y x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(Op386LEAL2)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ADDL_20(v *Value) bool {
+	// match: (ADDL (ADDLconst [c] x) y)
+	// cond:
+	// result: (LEAL1 [c] x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		v.reset(Op386LEAL1)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDL y (ADDLconst [c] x))
+	// cond:
+	// result: (LEAL1 [c] x y)
+	for {
+		_ = v.Args[1]
+		y := v.Args[0]
+		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
 			break
 		}
 		c := v_1.AuxInt
-		y := v_1.Args[0]
+		x := v_1.Args[0]
 		v.reset(Op386LEAL1)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -807,6 +1146,7 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 	// cond: x.Op != OpSB && y.Op != OpSB
 	// result: (LEAL1 [c] {s} x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386LEAL {
@@ -825,18 +1165,19 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (ADDL (LEAL [c] {s} x) y)
+	// match: (ADDL (LEAL [c] {s} y) x)
 	// cond: x.Op != OpSB && y.Op != OpSB
 	// result: (LEAL1 [c] {s} x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
 		}
 		c := v_0.AuxInt
 		s := v_0.Aux
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		if !(x.Op != OpSB && y.Op != OpSB) {
 			break
 		}
@@ -851,6 +1192,7 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386NEGL {
@@ -862,15 +1204,30 @@ func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (NEGL y) x)
+	// cond:
+	// result: (SUBL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386NEGL {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(Op386SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	return false
 }
-func rewriteValue386_Op386ADDLcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ADDLcarry_0(v *Value) bool {
 	// match: (ADDLcarry x (MOVLconst [c]))
 	// cond:
 	// result: (ADDLconstcarry [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -886,6 +1243,7 @@ func rewriteValue386_Op386ADDLcarry(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDLconstcarry [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -899,9 +1257,7 @@ func rewriteValue386_Op386ADDLcarry(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ADDLconst_0(v *Value) bool {
 	// match: (ADDLconst [c] (ADDL x y))
 	// cond:
 	// result: (LEAL1 [c] x y)
@@ -911,6 +1267,7 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(Op386LEAL1)
@@ -951,6 +1308,7 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -974,6 +1332,7 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -997,6 +1356,7 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1020,6 +1380,7 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1078,13 +1439,12 @@ func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ANDL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ANDL_0(v *Value) bool {
 	// match: (ANDL x (MOVLconst [c]))
 	// cond:
 	// result: (ANDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -1100,6 +1460,7 @@ func rewriteValue386_Op386ANDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -1115,6 +1476,7 @@ func rewriteValue386_Op386ANDL(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -1126,9 +1488,7 @@ func rewriteValue386_Op386ANDL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ANDLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ANDLconst_0(v *Value) bool {
 	// match: (ANDLconst [c] (ANDLconst [d] x))
 	// cond:
 	// result: (ANDLconst [c & d] x)
@@ -1187,13 +1547,14 @@ func rewriteValue386_Op386ANDLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPB(v *Value, config *Config) bool {
+func rewriteValue386_Op386CMPB_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPB x (MOVLconst [c]))
 	// cond:
 	// result: (CMPBconst x [int64(int8(c))])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -1209,6 +1570,7 @@ func rewriteValue386_Op386CMPB(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPBconst x [int64(int8(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -1216,7 +1578,7 @@ func rewriteValue386_Op386CMPB(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(Op386InvertFlags)
-		v0 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v0.AuxInt = int64(int8(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1224,9 +1586,7 @@ func rewriteValue386_Op386CMPB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386CMPBconst_0(v *Value) bool {
 	// match: (CMPBconst (MOVLconst [x]) [y])
 	// cond: int8(x)==int8(y)
 	// result: (FlagEQ)
@@ -1334,6 +1694,7 @@ func rewriteValue386_Op386CMPBconst(v *Value, config *Config) bool {
 		if v_0.Op != Op386ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(Op386TESTB)
@@ -1374,13 +1735,14 @@ func rewriteValue386_Op386CMPBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPL(v *Value, config *Config) bool {
+func rewriteValue386_Op386CMPL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPL x (MOVLconst [c]))
 	// cond:
 	// result: (CMPLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -1396,6 +1758,7 @@ func rewriteValue386_Op386CMPL(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPLconst x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -1403,7 +1766,7 @@ func rewriteValue386_Op386CMPL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(Op386InvertFlags)
-		v0 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1411,9 +1774,7 @@ func rewriteValue386_Op386CMPL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386CMPLconst_0(v *Value) bool {
 	// match: (CMPLconst (MOVLconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -1537,6 +1898,7 @@ func rewriteValue386_Op386CMPLconst(v *Value, config *Config) bool {
 		if v_0.Op != Op386ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(Op386TESTL)
@@ -1577,13 +1939,14 @@ func rewriteValue386_Op386CMPLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPW(v *Value, config *Config) bool {
+func rewriteValue386_Op386CMPW_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPW x (MOVLconst [c]))
 	// cond:
 	// result: (CMPWconst x [int64(int16(c))])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -1599,6 +1962,7 @@ func rewriteValue386_Op386CMPW(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPWconst x [int64(int16(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -1606,7 +1970,7 @@ func rewriteValue386_Op386CMPW(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(Op386InvertFlags)
-		v0 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v0.AuxInt = int64(int16(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1614,9 +1978,7 @@ func rewriteValue386_Op386CMPW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386CMPWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386CMPWconst_0(v *Value) bool {
 	// match: (CMPWconst (MOVLconst [x]) [y])
 	// cond: int16(x)==int16(y)
 	// result: (FlagEQ)
@@ -1724,6 +2086,7 @@ func rewriteValue386_Op386CMPWconst(v *Value, config *Config) bool {
 		if v_0.Op != Op386ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(Op386TESTW)
@@ -1764,9 +2127,7 @@ func rewriteValue386_Op386CMPWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386LEAL_0(v *Value) bool {
 	// match: (LEAL [c] {s} (ADDLconst [d] x))
 	// cond: is32Bit(c+d)
 	// result: (LEAL [c+d] {s} x)
@@ -1798,6 +2159,7 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(x.Op != OpSB && y.Op != OpSB) {
@@ -1844,6 +2206,7 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -1868,6 +2231,7 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -1892,6 +2256,7 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -1916,6 +2281,7 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -1930,15 +2296,14 @@ func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386LEAL1_0(v *Value) bool {
 	// match: (LEAL1 [c] {s} (ADDLconst [d] x) y)
 	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAL1 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -1956,20 +2321,21 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAL1 [c] {s} x (ADDLconst [d] y))
-	// cond: is32Bit(c+d)   && y.Op != OpSB
+	// match: (LEAL1 [c] {s} y (ADDLconst [d] x))
+	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAL1 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
-		x := v.Args[0]
+		_ = v.Args[1]
+		y := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
 			break
 		}
 		d := v_1.AuxInt
-		y := v_1.Args[0]
-		if !(is32Bit(c+d) && y.Op != OpSB) {
+		x := v_1.Args[0]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
 			break
 		}
 		v.reset(Op386LEAL1)
@@ -1985,6 +2351,7 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2001,12 +2368,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAL1 [c] {s} (SHLLconst [1] x) y)
+	// match: (LEAL1 [c] {s} (SHLLconst [1] y) x)
 	// cond:
-	// result: (LEAL2 [c] {s} y x)
+	// result: (LEAL2 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386SHLLconst {
 			break
@@ -2014,13 +2382,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 1 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(Op386LEAL2)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAL1 [c] {s} x (SHLLconst [2] y))
@@ -2029,6 +2397,7 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2045,12 +2414,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAL1 [c] {s} (SHLLconst [2] x) y)
+	// match: (LEAL1 [c] {s} (SHLLconst [2] y) x)
 	// cond:
-	// result: (LEAL4 [c] {s} y x)
+	// result: (LEAL4 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386SHLLconst {
 			break
@@ -2058,13 +2428,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 2 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(Op386LEAL4)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAL1 [c] {s} x (SHLLconst [3] y))
@@ -2073,6 +2443,7 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2089,12 +2460,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAL1 [c] {s} (SHLLconst [3] x) y)
+	// match: (LEAL1 [c] {s} (SHLLconst [3] y) x)
 	// cond:
-	// result: (LEAL8 [c] {s} y x)
+	// result: (LEAL8 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386SHLLconst {
 			break
@@ -2102,13 +2474,13 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 3 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(Op386LEAL8)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y)
@@ -2117,6 +2489,7 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2135,21 +2508,22 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAL1 [off1] {sym1} x (LEAL [off2] {sym2} y))
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+	// match: (LEAL1 [off1] {sym1} y (LEAL [off2] {sym2} x))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
 	// result: (LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
-		x := v.Args[0]
+		_ = v.Args[1]
+		y := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386LEAL {
 			break
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
-		y := v_1.Args[0]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB) {
+		x := v_1.Args[0]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
 			break
 		}
 		v.reset(Op386LEAL1)
@@ -2161,15 +2535,14 @@ func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386LEAL2_0(v *Value) bool {
 	// match: (LEAL2 [c] {s} (ADDLconst [d] x) y)
 	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAL2 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2193,6 +2566,7 @@ func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -2216,6 +2590,7 @@ func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2238,6 +2613,7 @@ func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2260,6 +2636,7 @@ func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2280,15 +2657,14 @@ func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386LEAL4_0(v *Value) bool {
 	// match: (LEAL4 [c] {s} (ADDLconst [d] x) y)
 	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAL4 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2312,6 +2688,7 @@ func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -2335,6 +2712,7 @@ func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -2357,6 +2735,7 @@ func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2377,15 +2756,14 @@ func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386LEAL8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386LEAL8_0(v *Value) bool {
 	// match: (LEAL8 [c] {s} (ADDLconst [d] x) y)
 	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAL8 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2409,6 +2787,7 @@ func rewriteValue386_Op386LEAL8(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -2432,6 +2811,7 @@ func rewriteValue386_Op386LEAL8(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2452,7 +2832,7 @@ func rewriteValue386_Op386LEAL8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBLSX_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBLSX x:(MOVBload [off] {sym} ptr mem))
@@ -2465,13 +2845,14 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVBLSXload, v.Type)
+		v0 := b.NewValue0(v.Pos, Op386MOVBLSXload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -2500,15 +2881,42 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBLSXload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBLSX x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVBstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(Op386MOVBLSX)
+		v.AddArg(x)
+		return true
+	}
 	// match: (MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2529,7 +2937,7 @@ func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBLZX_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBLZX x:(MOVBload [off] {sym} ptr mem))
@@ -2542,13 +2950,14 @@ func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVBload, v.Type)
+		v0 := b.NewValue0(v.Pos, Op386MOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -2567,6 +2976,7 @@ func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[2]
 		ptr := x.Args[0]
 		idx := x.Args[1]
 		mem := x.Args[2]
@@ -2574,7 +2984,7 @@ func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVBloadidx1, v.Type)
+		v0 := b.NewValue0(v.Pos, Op386MOVBloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -2601,15 +3011,18 @@ func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
 	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: x
+	// result: (MOVBLZX x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVBstore {
@@ -2617,22 +3030,23 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		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.reset(Op386MOVBLZX)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// match: (MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2650,12 +3064,13 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2680,12 +3095,14 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -2706,10 +3123,12 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -2726,15 +3145,14 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386MOVBloadidx1_0(v *Value) bool {
 	// match: (MOVBloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
 	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2751,12 +3169,36 @@ func rewriteValue386_Op386MOVBloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBloadidx1 [c] {sym} idx (ADDLconst [d] ptr) mem)
+	// cond:
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVBloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
 	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -2773,17 +3215,43 @@ func rewriteValue386_Op386MOVBloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBloadidx1 [c] {sym} (ADDLconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVBloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
 	return false
 }
-func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBstore [off] {sym} ptr (MOVBLSX x) mem)
 	// cond:
 	// result: (MOVBstore [off] {sym} ptr x mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVBLSX {
@@ -2805,6 +3273,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVBLZX {
@@ -2820,12 +3289,13 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
+	// match: (MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -2851,6 +3321,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -2868,12 +3339,13 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// match: (MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -2900,12 +3372,14 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -2928,10 +3402,12 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -2954,6 +3430,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHRLconst {
@@ -2973,6 +3450,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -2997,6 +3475,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHRLconst {
@@ -3014,6 +3493,7 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -3041,15 +3521,18 @@ func rewriteValue386_Op386MOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVBstoreconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBstoreconst [sc] {s} (ADDLconst [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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -3073,6 +3556,7 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		sc := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -3097,12 +3581,14 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		x := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -3123,10 +3609,12 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -3144,6 +3632,7 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		p := v.Args[0]
 		x := v.Args[1]
 		if x.Op != Op386MOVBstoreconst {
@@ -3153,6 +3642,7 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[1]
 		if p != x.Args[0] {
 			break
 		}
@@ -3169,15 +3659,14 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386MOVBstoreconstidx1_0(v *Value) bool {
 	// match: (MOVBstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
 	// cond:
 	// result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
 		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -3200,6 +3689,7 @@ func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
 	for {
 		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -3222,6 +3712,7 @@ func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		i := v.Args[1]
 		x := v.Args[2]
@@ -3232,6 +3723,7 @@ func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -3252,15 +3744,14 @@ func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386MOVBstoreidx1_0(v *Value) bool {
 	// match: (MOVBstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
 	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -3279,12 +3770,38 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBstoreidx1 [c] {sym} idx (ADDLconst [d] ptr) val mem)
+	// cond:
+	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVBstoreidx1)
+		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 (ADDLconst [d] idx) val mem)
 	// cond:
 	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -3303,12 +3820,38 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBstoreidx1 [c] {sym} (ADDLconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVBstoreidx1)
+		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 (SHRLconst [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
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
@@ -3329,6 +3872,7 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
@@ -3351,19 +3895,22 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
+	// match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [8] w) x:(MOVBstoreidx1 [i-1] {s} idx p w mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		j := v_2.AuxInt
+		if v_2.AuxInt != 8 {
+			break
+		}
 		w := v_2.Args[0]
 		x := v.Args[3]
 		if x.Op != Op386MOVBstoreidx1 {
@@ -3375,20 +3922,14 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
-			break
-		}
-		if idx != x.Args[1] {
-			break
-		}
-		w0 := x.Args[2]
-		if w0.Op != Op386SHRLconst {
+		_ = x.Args[3]
+		if idx != x.Args[0] {
 			break
 		}
-		if w0.AuxInt != j-8 {
+		if p != x.Args[1] {
 			break
 		}
-		if w != w0.Args[0] {
+		if w != x.Args[2] {
 			break
 		}
 		mem := x.Args[3]
@@ -3400,342 +3941,396 @@ func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w0)
+		v.AddArg(w)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVLload(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
+	// match: (MOVBstoreidx1 [i] {s} idx p (SHRLconst [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 {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLstore {
-			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)) {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVLload  [off1] {sym} (ADDLconst [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 != Op386ADDLconst {
+		if v_2.AuxInt != 8 {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
 			break
 		}
-		v.reset(Op386MOVLload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// 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 != Op386LEAL {
+		if x.AuxInt != i-1 {
 			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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+		if x.Aux != s {
 			break
 		}
-		v.reset(Op386MOVLload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLload [off1] {sym1} (LEAL1 [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 != Op386LEAL1 {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			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)) {
+		if idx != x.Args[1] {
 			break
 		}
-		v.reset(Op386MOVLloadidx1)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLload [off1] {sym1} (LEAL4 [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 != Op386LEAL4 {
+		if w != x.Args[2] {
 			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)) {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVLloadidx4)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLload [off] {sym} (ADDL ptr idx) mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVLloadidx1 [off] {sym} ptr idx mem)
+	// match: (MOVBstoreidx1 [i] {s} idx p (SHRLconst [8] w) x:(MOVBstoreidx1 [i-1] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDL {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		if v_2.AuxInt != 8 {
 			break
 		}
-		v.reset(Op386MOVLloadidx1)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValue386_Op386MOVLloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLloadidx1 [c] {sym} ptr (SHLLconst [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 != Op386SHLLconst {
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
 			break
 		}
-		if v_1.AuxInt != 2 {
+		if x.AuxInt != i-1 {
 			break
 		}
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVLloadidx4)
-		v.AuxInt = c
-		v.Aux = sym
-		v.AddArg(ptr)
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+	// match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVLloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
-	// cond:
-	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+	// match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} idx p w0:(SHRLconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVLloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVLloadidx4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
+func rewriteValue386_Op386MOVBstoreidx1_10(v *Value) bool {
+	// match: (MOVBstoreidx1 [i] {s} idx p (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVLloadidx4)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem)
-	// cond:
-	// result: (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
+	// match: (MOVBstoreidx1 [i] {s} idx p (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} idx p w0:(SHRLconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVLloadidx4)
-		v.AuxInt = c + 4*d
-		v.Aux = sym
-		v.AddArg(ptr)
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVLstore(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVLload_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVLstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
 	for {
-		off1 := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLstore {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(Op386MOVLstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem)
-	// cond: validOff(off)
-	// result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+	// match: (MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLload  [off1+off2] {sym} ptr mem)
 	for {
-		off := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validOff(off)) {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386MOVLstoreconst)
-		v.AuxInt = makeValAndOff(int64(int32(c)), off)
+		v.reset(Op386MOVLload)
+		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// match: (MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// result: (MOVLload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -3743,237 +4338,109 @@ func rewriteValue386_Op386MOVLstore(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVLstore)
+		v.reset(Op386MOVLload)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVLload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVLstoreidx1)
+		v.reset(Op386MOVLloadidx1)
 		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} (LEAL4 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVLload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL4 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVLstoreidx4)
+		v.reset(Op386MOVLloadidx4)
 		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} (ADDL ptr idx) val mem)
+	// match: (MOVLload [off] {sym} (ADDL ptr idx) mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
+	// result: (MOVLloadidx1 [off] {sym} ptr idx mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(Op386MOVLstoreidx1)
+		v.reset(Op386MOVLloadidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVLstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLstoreconst [sc] {s} (ADDLconst [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 != Op386ADDLconst {
-			break
-		}
-		off := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
-			break
-		}
-		v.reset(Op386MOVLstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)   && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
-	// 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 != Op386LEAL {
-			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) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
-			break
-		}
-		v.reset(Op386MOVLstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLstoreconst [x] {sym1} (LEAL1 [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 != Op386LEAL1 {
-			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(Op386MOVLstoreconstidx1)
-		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} (LEAL4 [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 != Op386LEAL4 {
-			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(Op386MOVLstoreconstidx4)
-		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} (ADDL 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 != Op386ADDL {
-			break
-		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		v.reset(Op386MOVLstoreconstidx1)
-		v.AuxInt = x
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValue386_Op386MOVLstoreconstidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem)
+func rewriteValue386_Op386MOVLloadidx1_0(v *Value) bool {
+	// match: (MOVLloadidx1 [c] {sym} ptr (SHLLconst [2] idx) mem)
 	// cond:
-	// result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+	// result: (MOVLloadidx4 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386SHLLconst {
@@ -3984,7 +4451,7 @@ func rewriteValue386_Op386MOVLstoreconstidx1(v *Value, config *Config) bool {
 		}
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVLstoreconstidx4)
+		v.reset(Op386MOVLloadidx4)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -3992,136 +4459,133 @@ func rewriteValue386_Op386MOVLstoreconstidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// match: (MOVLloadidx1 [c] {sym} (SHLLconst [2] idx) ptr mem)
 	// cond:
-	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVLloadidx4 [c] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		if v_0.Op != Op386SHLLconst {
 			break
 		}
-		c := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
+		if v_0.AuxInt != 2 {
+			break
+		}
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVLstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVLloadidx4)
+		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// match: (MOVLloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
-		idx := v_1.Args[0]
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVLstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVLloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVLstoreconstidx4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// match: (MOVLloadidx1 [c] {sym} idx (ADDLconst [d] ptr) mem)
 	// cond:
-	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVLstoreconstidx4)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVLloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// match: (MOVLloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
-	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
+		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVLstoreconstidx4)
-		v.AuxInt = ValAndOff(x).add(4 * c)
+		v.reset(Op386MOVLloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVLstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem)
+	// match: (MOVLloadidx1 [c] {sym} (ADDLconst [d] idx) ptr mem)
 	// cond:
-	// result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
+	// 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 != Op386SHLLconst {
-			break
-		}
-		if v_1.AuxInt != 2 {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVLstoreidx4)
-		v.AuxInt = c
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVLloadidx1)
+		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} (ADDLconst [d] ptr) idx val mem)
+	return false
+}
+func rewriteValue386_Op386MOVLloadidx4_0(v *Value) bool {
+	// match: (MOVLloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4129,23 +4593,22 @@ func rewriteValue386_Op386MOVLstoreidx1(v *Value, config *Config) bool {
 		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVLstoreidx1)
+		mem := v.Args[2]
+		v.reset(Op386MOVLloadidx4)
 		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 (ADDLconst [d] idx) val mem)
+	// match: (MOVLloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
-	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -4153,123 +4616,79 @@ func rewriteValue386_Op386MOVLstoreidx1(v *Value, config *Config) bool {
 		}
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVLstoreidx1)
-		v.AuxInt = c + d
+		mem := v.Args[2]
+		v.reset(Op386MOVLloadidx4)
+		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 rewriteValue386_Op386MOVLstoreidx4(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVLstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVLstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
 	for {
-		c := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		d := v_0.AuxInt
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVLstoreidx4)
-		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 (ADDLconst [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 != Op386ADDLconst {
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVLstoreidx4)
-		v.AuxInt = c + 4*d
+		v.reset(Op386MOVLstore)
+		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVSDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDconst [c])
-	// cond: config.ctxt.Flag_shared
-	// result: (MOVSDconst2 (MOVSDconst1 [c]))
-	for {
-		c := v.AuxInt
-		if !(config.ctxt.Flag_shared) {
-			break
-		}
-		v.reset(Op386MOVSDconst2)
-		v0 := b.NewValue0(v.Line, Op386MOVSDconst1, config.fe.TypeUInt32())
-		v0.AuxInt = c
-		v.AddArg(v0)
-		return true
-	}
-	return false
-}
-func rewriteValue386_Op386MOVSDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDload [off1] {sym} (ADDLconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVSDload [off1+off2] {sym} ptr mem)
+	// match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
 	for {
-		off1 := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
 			break
 		}
-		v.reset(Op386MOVSDload)
-		v.AuxInt = off1 + off2
+		v.reset(Op386MOVLstoreconst)
+		v.AuxInt = makeValAndOff(int64(int32(c)), off)
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -4277,322 +4696,415 @@ func rewriteValue386_Op386MOVSDload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVSDload)
+		v.reset(Op386MOVLstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSDloadidx1)
+		v.reset(Op386MOVLstoreidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL8 {
+		if v_0.Op != Op386LEAL4 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSDloadidx8)
+		v.reset(Op386MOVLstoreidx4)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off] {sym} (ADDL ptr idx) mem)
+	// match: (MOVLstore [off] {sym} (ADDL ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
+	// result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(Op386MOVSDloadidx1)
+		v.reset(Op386MOVLstoreidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSDloadidx1(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVLstoreconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		d := v_0.AuxInt
+		off := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVSDloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(Op386MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)   && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL {
+			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) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
+			break
+		}
+		v.reset(Op386MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [x] {sym1} (LEAL1 [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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(Op386MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
-	// cond:
-	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+	// match: (MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL4 {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVSDloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(Op386MOVLstoreconstidx4)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVSDloadidx8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem)
+	// match: (MOVLstoreconst [x] {sym} (ADDL ptr idx) mem)
 	// cond:
-	// result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
+	// result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
 	for {
-		c := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		if v_0.Op != Op386ADDL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVSDloadidx8)
-		v.AuxInt = c + d
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(Op386MOVLstoreconstidx1)
+		v.AuxInt = x
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	return false
+}
+func rewriteValue386_Op386MOVLstoreconstidx1_0(v *Value) bool {
+	// match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem)
 	// cond:
-	// result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
+	// result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
 			break
 		}
-		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVSDloadidx8)
-		v.AuxInt = c + 8*d
+		v.reset(Op386MOVLstoreconstidx4)
+		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVSDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVSDstore [off1+off2] {sym} ptr val mem)
+	// match: (MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		off2 := v_0.AuxInt
+		c := v_0.AuxInt
 		ptr := v_0.Args[0]
-		val := v.Args[1]
+		idx := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
-			break
-		}
-		v.reset(Op386MOVSDstore)
-		v.AuxInt = off1 + off2
+		v.reset(Op386MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(val)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		val := v.Args[1]
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
-			break
-		}
-		v.reset(Op386MOVSDstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
+		v.reset(Op386MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	return false
+}
+func rewriteValue386_Op386MOVLstoreconstidx4_0(v *Value) bool {
+	// match: (MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL1 {
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
+		c := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
+		idx := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+		v.reset(Op386MOVLstoreconstidx4)
+		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 (ADDLconst [c] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		v.reset(Op386MOVSDstoreidx1)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVLstoreconstidx4)
+		v.AuxInt = ValAndOff(x).add(4 * c)
+		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	return false
+}
+func rewriteValue386_Op386MOVLstoreidx1_0(v *Value) bool {
+	// match: (MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem)
+	// cond:
+	// result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL8 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
 			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)) {
+		if v_1.AuxInt != 2 {
 			break
 		}
-		v.reset(Op386MOVSDstoreidx8)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVLstoreidx4)
+		v.AuxInt = c
+		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstore [off] {sym} (ADDL ptr idx) val mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+	// match: (MOVLstoreidx1 [c] {sym} (SHLLconst [2] idx) ptr val mem)
+	// cond:
+	// result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
 	for {
-		off := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDL {
+		if v_0.Op != Op386SHLLconst {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		if v_0.AuxInt != 2 {
 			break
 		}
-		v.reset(Op386MOVSDstoreidx1)
-		v.AuxInt = off
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVLstoreidx4)
+		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -4600,17 +5112,13 @@ func rewriteValue386_Op386MOVSDstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVSDstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+	// match: (MOVLstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4620,7 +5128,7 @@ func rewriteValue386_Op386MOVSDstoreidx1(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSDstoreidx1)
+		v.reset(Op386MOVLstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4629,12 +5137,38 @@ func rewriteValue386_Op386MOVSDstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
+	// match: (MOVLstoreidx1 [c] {sym} idx (ADDLconst [d] ptr) val mem)
 	// cond:
-	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVLstoreidx1)
+		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 (ADDLconst [d] idx) val mem)
+	// cond:
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -4644,7 +5178,32 @@ func rewriteValue386_Op386MOVSDstoreidx1(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSDstoreidx1)
+		v.reset(Op386MOVLstoreidx1)
+		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} (ADDLconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVLstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4655,15 +5214,14 @@ func rewriteValue386_Op386MOVSDstoreidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+func rewriteValue386_Op386MOVLstoreidx4_0(v *Value) bool {
+	// match: (MOVLstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4673,7 +5231,7 @@ func rewriteValue386_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSDstoreidx8)
+		v.reset(Op386MOVLstoreidx4)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4682,12 +5240,13 @@ func rewriteValue386_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem)
+	// match: (MOVLstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -4697,8 +5256,8 @@ func rewriteValue386_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSDstoreidx8)
-		v.AuxInt = c + 8*d
+		v.reset(Op386MOVLstoreidx4)
+		v.AuxInt = c + 4*d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -4708,34 +5267,41 @@ func rewriteValue386_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSconst(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVSDconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVSSconst [c])
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVSDconst [c])
 	// cond: config.ctxt.Flag_shared
-	// result: (MOVSSconst2 (MOVSSconst1 [c]))
+	// result: (MOVSDconst2 (MOVSDconst1 [c]))
 	for {
 		c := v.AuxInt
 		if !(config.ctxt.Flag_shared) {
 			break
 		}
-		v.reset(Op386MOVSSconst2)
-		v0 := b.NewValue0(v.Line, Op386MOVSSconst1, config.fe.TypeUInt32())
+		v.reset(Op386MOVSDconst2)
+		v0 := b.NewValue0(v.Pos, Op386MOVSDconst1, typ.UInt32)
 		v0.AuxInt = c
 		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVSDload_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVSSload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVSDload [off1] {sym} (ADDLconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVSSload [off1+off2] {sym} ptr mem)
+	// result: (MOVSDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4746,19 +5312,20 @@ func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386MOVSSload)
+		v.reset(Op386MOVSDload)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVSDload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -4770,32 +5337,34 @@ func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVSSload)
+		v.reset(Op386MOVSDload)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+	// match: (MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSSloadidx1)
+		v.reset(Op386MOVSDloadidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -4803,25 +5372,27 @@ func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem)
+	// match: (MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL4 {
+		if v_0.Op != Op386LEAL8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSSloadidx4)
+		v.reset(Op386MOVSDloadidx8)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -4829,23 +5400,25 @@ func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSload [off] {sym} (ADDL ptr idx) mem)
+	// match: (MOVSDload [off] {sym} (ADDL ptr idx) mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(Op386MOVSSloadidx1)
+		v.reset(Op386MOVSDloadidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4855,15 +5428,14 @@ func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
+func rewriteValue386_Op386MOVSDloadidx1_0(v *Value) bool {
+	// match: (MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4872,7 +5444,7 @@ func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVSSloadidx1)
+		v.reset(Op386MOVSDloadidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4880,12 +5452,13 @@ func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// match: (MOVSDloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
-	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -4894,7 +5467,7 @@ func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVSSloadidx1)
+		v.reset(Op386MOVSDloadidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4904,15 +5477,14 @@ func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSloadidx4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem)
+func rewriteValue386_Op386MOVSDloadidx8_0(v *Value) bool {
+	// match: (MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4921,7 +5493,7 @@ func rewriteValue386_Op386MOVSSloadidx4(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVSSloadidx4)
+		v.reset(Op386MOVSDloadidx8)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4929,12 +5501,13 @@ func rewriteValue386_Op386MOVSSloadidx4(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// match: (MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
-	// result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -4943,8 +5516,8 @@ func rewriteValue386_Op386MOVSSloadidx4(v *Value, config *Config) bool {
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVSSloadidx4)
-		v.AuxInt = c + 4*d
+		v.reset(Op386MOVSDloadidx8)
+		v.AuxInt = c + 8*d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -4953,15 +5526,18 @@ func rewriteValue386_Op386MOVSSloadidx4(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVSDstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVSDstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVSSstore [off1+off2] {sym} ptr val mem)
+	// result: (MOVSDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -4973,7 +5549,7 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386MOVSSstore)
+		v.reset(Op386MOVSDstore)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -4981,12 +5557,13 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// match: (MOVSDstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -4999,7 +5576,7 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVSSstore)
+		v.reset(Op386MOVSDstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
@@ -5007,18 +5584,20 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVSDstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -5026,7 +5605,7 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSSstoreidx1)
+		v.reset(Op386MOVSDstoreidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -5035,18 +5614,20 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL4 {
+		if v_0.Op != Op386LEAL8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -5054,7 +5635,7 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVSSstoreidx4)
+		v.reset(Op386MOVSDstoreidx8)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -5063,16 +5644,18 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off] {sym} (ADDL ptr idx) val mem)
+	// match: (MOVSDstore [off] {sym} (ADDL ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -5080,7 +5663,7 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(Op386MOVSSstoreidx1)
+		v.reset(Op386MOVSDstoreidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -5091,15 +5674,14 @@ func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+func rewriteValue386_Op386MOVSDstoreidx1_0(v *Value) bool {
+	// match: (MOVSDstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -5109,7 +5691,7 @@ func rewriteValue386_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSSstoreidx1)
+		v.reset(Op386MOVSDstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -5118,12 +5700,13 @@ func rewriteValue386_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
+	// match: (MOVSDstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -5133,7 +5716,7 @@ func rewriteValue386_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSSstoreidx1)
+		v.reset(Op386MOVSDstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -5144,15 +5727,14 @@ func rewriteValue386_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+func rewriteValue386_Op386MOVSDstoreidx8_0(v *Value) bool {
+	// match: (MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -5162,7 +5744,7 @@ func rewriteValue386_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSSstoreidx4)
+		v.reset(Op386MOVSDstoreidx8)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -5171,12 +5753,13 @@ func rewriteValue386_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem)
+	// match: (MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -5186,8 +5769,8 @@ func rewriteValue386_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(Op386MOVSSstoreidx4)
-		v.AuxInt = c + 4*d
+		v.reset(Op386MOVSDstoreidx8)
+		v.AuxInt = c + 8*d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -5197,63 +5780,65 @@ func rewriteValue386_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386MOVWLSX(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVSSconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVWLSX x:(MOVWload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem)
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVSSconst [c])
+	// cond: config.ctxt.Flag_shared
+	// result: (MOVSSconst2 (MOVSSconst1 [c]))
 	for {
-		x := v.Args[0]
-		if x.Op != Op386MOVWload {
-			break
-		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		c := v.AuxInt
+		if !(config.ctxt.Flag_shared) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVWLSXload, v.Type)
-		v.reset(OpCopy)
+		v.reset(Op386MOVSSconst2)
+		v0 := b.NewValue0(v.Pos, Op386MOVSSconst1, typ.UInt32)
+		v0.AuxInt = c
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWLSX (ANDLconst [c] x))
-	// cond: c & 0x8000 == 0
-	// result: (ANDLconst [c & 0x7fff] x)
+	return false
+}
+func rewriteValue386_Op386MOVSSload_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (MOVSSload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSSload [off1+off2] {sym} ptr mem)
 	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ANDLconst {
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v_0.Args[0]
-		if !(c&0x8000 == 0) {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386ANDLconst)
-		v.AuxInt = c & 0x7fff
-		v.AddArg(x)
+		v.reset(Op386MOVSSload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVSSload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -5265,169 +5850,233 @@ func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVWLSXload)
+		v.reset(Op386MOVSSload)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWLZX(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWLZX x:(MOVWload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+	// match: (MOVSSload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		x := v.Args[0]
-		if x.Op != Op386MOVWload {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL1 {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVWload, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		v.reset(Op386MOVSSloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
+	// match: (MOVSSload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		x := v.Args[0]
-		if x.Op != Op386MOVWloadidx1 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL4 {
 			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)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVWloadidx1, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v.reset(Op386MOVSSloadidx4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
+	// match: (MOVSSload [off] {sym} (ADDL ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
 	for {
-		x := v.Args[0]
-		if x.Op != Op386MOVWloadidx2 {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDL {
 			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)) {
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, Op386MOVWloadidx2, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v.reset(Op386MOVSSloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWLZX (ANDLconst [c] x))
+	return false
+}
+func rewriteValue386_Op386MOVSSloadidx1_0(v *Value) bool {
+	// match: (MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (ANDLconst [c & 0xffff] x)
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
 	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ANDLconst {
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(Op386ANDLconst)
-		v.AuxInt = c & 0xffff
-		v.AddArg(x)
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVSSloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWload(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
+	// match: (MOVSSloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// cond:
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVWstore {
+		if v_1.Op != Op386ADDLconst {
 			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)) {
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVSSloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MOVSSloadidx4_0(v *Value) bool {
+	// match: (MOVSSloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVSSloadidx4)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// cond:
+	// result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVSSloadidx4)
+		v.AuxInt = c + 4*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload  [off1] {sym} (ADDLconst [off2] ptr) mem)
+	return false
+}
+func rewriteValue386_Op386MOVSSstore_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVWload  [off1+off2] {sym} ptr mem)
+	// result: (MOVSSstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386MOVWload)
+		v.reset(Op386MOVSSstore)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVSSstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -5435,128 +6084,117 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVWload)
+		v.reset(Op386MOVSSstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+	// match: (MOVSSstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVWloadidx1)
+		v.reset(Op386MOVSSstoreidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem)
+	// match: (MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL2 {
+		if v_0.Op != Op386LEAL4 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVWloadidx2)
+		v.reset(Op386MOVSSstoreidx4)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload [off] {sym} (ADDL ptr idx) mem)
+	// match: (MOVSSstore [off] {sym} (ADDL ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVWloadidx1 [off] {sym} ptr idx mem)
+	// result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(Op386MOVWloadidx1)
+		v.reset(Op386MOVSSstoreidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVWloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWloadidx1 [c] {sym} ptr (SHLLconst [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 != Op386SHLLconst {
-			break
-		}
-		if v_1.AuxInt != 1 {
-			break
-		}
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVWloadidx2)
-		v.AuxInt = c
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
+func rewriteValue386_Op386MOVSSstoreidx1_0(v *Value) bool {
+	// match: (MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -5564,21 +6202,24 @@ func rewriteValue386_Op386MOVWloadidx1(v *Value, config *Config) bool {
 		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVWloadidx1)
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVSSstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// match: (MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -5586,26 +6227,27 @@ func rewriteValue386_Op386MOVWloadidx1(v *Value, config *Config) bool {
 		}
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVWloadidx1)
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVSSstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVWloadidx2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem)
+func rewriteValue386_Op386MOVSSstoreidx4_0(v *Value) bool {
+	// match: (MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+	// result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
@@ -5613,21 +6255,24 @@ func rewriteValue386_Op386MOVWloadidx2(v *Value, config *Config) bool {
 		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(Op386MOVWloadidx2)
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVSSstoreidx4)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// match: (MOVSSstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+	// result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
@@ -5635,116 +6280,104 @@ func rewriteValue386_Op386MOVWloadidx2(v *Value, config *Config) bool {
 		}
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVWloadidx2)
-		v.AuxInt = c + 2*d
-		v.Aux = sym
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVSSstoreidx4)
+		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 rewriteValue386_Op386MOVWstore(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVWLSX_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVWstore [off] {sym} ptr (MOVWLSX x) mem)
-	// cond:
-	// result: (MOVWstore [off] {sym} ptr x mem)
+	// match: (MOVWLSX x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVWLSX {
+		x := v.Args[0]
+		if x.Op != Op386MOVWload {
 			break
 		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVWstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [off] {sym} ptr (MOVWLZX 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 != Op386MOVWLZX {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(Op386MOVWstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, Op386MOVWLSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	// match: (MOVWLSX (ANDLconst [c] x))
+	// cond: c & 0x8000 == 0
+	// result: (ANDLconst [c & 0x7fff] x)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		if v_0.Op != Op386ANDLconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x8000 == 0) {
 			break
 		}
-		v.reset(Op386MOVWstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
+		v.reset(Op386ANDLconst)
+		v.AuxInt = c & 0x7fff
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
-	// cond: validOff(off)
-	// result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+	return false
+}
+func rewriteValue386_Op386MOVWLSXload_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVWLSX x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		if v_1.Op != Op386MOVWstore {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validOff(off)) {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(Op386MOVWstoreconst)
-		v.AuxInt = makeValAndOff(int64(int16(c)), off)
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		v.reset(Op386MOVWLSX)
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
@@ -5752,368 +6385,327 @@ func rewriteValue386_Op386MOVWstore(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVWstore)
+		v.reset(Op386MOVWLSXload)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	return false
+}
+func rewriteValue386_Op386MOVWLZX_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWLZX x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL1 {
+		x := v.Args[0]
+		if x.Op != Op386MOVWload {
 			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)) {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVWstoreidx1)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, Op386MOVWload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// match: (MOVWLZX 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 {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386LEAL2 {
+		x := v.Args[0]
+		if x.Op != Op386MOVWloadidx1 {
 			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)) {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVWstoreidx2)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, Op386MOVWloadidx1, 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: (MOVWstore [off] {sym} (ADDL ptr idx) val mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+	// match: (MOVWLZX 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 {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDL {
+		x := v.Args[0]
+		if x.Op != Op386MOVWloadidx2 {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVWstoreidx1)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, Op386MOVWloadidx2, 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: (MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVLstore [i-2] {s} p w mem)
+	// match: (MOVWLZX (ANDLconst [c] x))
+	// cond:
+	// result: (ANDLconst [c & 0xffff] x)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386SHRLconst {
-			break
-		}
-		if v_1.AuxInt != 16 {
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ANDLconst {
 			break
 		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != Op386MOVWstore {
-			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(Op386MOVLstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(Op386ANDLconst)
+		v.AuxInt = c & 0xffff
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVLstore [i-2] {s} p w0 mem)
+	return false
+}
+func rewriteValue386_Op386MOVWload_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVWLZX x)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386SHRLconst {
-			break
-		}
-		j := v_1.AuxInt
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != Op386MOVWstore {
-			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 != Op386SHRLconst {
-			break
-		}
-		if w0.AuxInt != j-16 {
-			break
-		}
-		if w != w0.Args[0] {
+		if v_1.Op != Op386MOVWstore {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(Op386MOVLstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		v.reset(Op386MOVWLZX)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
-	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	// match: (MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWload  [off1+off2] {sym} ptr mem)
 	for {
-		sc := v.AuxInt
-		s := v.Aux
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(Op386MOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
+		v.reset(Op386MOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)   && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
-	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	// match: (MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
+	// result: (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
-		sc := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
-		ptr := v_0.Args[0]
+		base := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		v.reset(Op386MOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
+		v.reset(Op386MOVWload)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
+		v.AddArg(base)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem)
-	// cond: canMergeSym(sym1, sym2)
-	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	// match: (MOVWload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		x := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL1 {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVWstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(off)
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem)
-	// cond: canMergeSym(sym1, sym2)
-	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	// match: (MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		x := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386LEAL2 {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(Op386MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(off)
+		v.reset(Op386MOVWloadidx2)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [x] {sym} (ADDL ptr idx) mem)
-	// cond:
-	// result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+	// match: (MOVWload [off] {sym} (ADDL ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWloadidx1 [off] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDL {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
-		v.reset(Op386MOVWstoreconstidx1)
-		v.AuxInt = x
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = off
 		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)
+	return false
+}
+func rewriteValue386_Op386MOVWloadidx1_0(v *Value) bool {
+	// match: (MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem)
+	// cond:
+	// result: (MOVWloadidx2 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		x := v.Args[1]
-		if x.Op != Op386MOVWstoreconst {
-			break
-		}
-		a := x.AuxInt
-		if x.Aux != s {
-			break
-		}
-		if p != x.Args[0] {
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
 			break
 		}
-		mem := x.Args[1]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		v.reset(Op386MOVLstoreconst)
-		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
-		v.Aux = s
-		v.AddArg(p)
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWloadidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWstoreconstidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem)
+	// match: (MOVWloadidx1 [c] {sym} (SHLLconst [1] idx) ptr mem)
 	// cond:
-	// result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+	// 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 != Op386SHLLconst {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		if v_0.AuxInt != 1 {
 			break
 		}
-		idx := v_1.Args[0]
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVWstoreconstidx2)
+		v.reset(Op386MOVWloadidx2)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -6121,396 +6713,356 @@ func rewriteValue386_Op386MOVWstoreconstidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// match: (MOVWloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVWstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// match: (MOVWloadidx1 [c] {sym} idx (ADDLconst [d] ptr) mem)
 	// cond:
-	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
+		_ = v.Args[2]
+		idx := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
-		idx := v_1.Args[0]
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVWstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = c + d
 		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)
+	// match: (MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
+	// cond:
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		i := v.Args[1]
-		x := v.Args[2]
-		if x.Op != Op386MOVWstoreconstidx1 {
-			break
-		}
-		a := x.AuxInt
-		if x.Aux != s {
-			break
-		}
-		if p != x.Args[0] {
-			break
-		}
-		if i != x.Args[1] {
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWloadidx1 [c] {sym} (ADDLconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		v.reset(Op386MOVLstoreconstidx1)
-		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(i)
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVWloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MOVWstoreconstidx2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem)
+func rewriteValue386_Op386MOVWloadidx2_0(v *Value) bool {
+	// match: (MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(Op386MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(Op386MOVWloadidx2)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// match: (MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem)
 	// cond:
-	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
+	// result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
+		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(Op386MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(2 * c)
+		v.reset(Op386MOVWloadidx2)
+		v.AuxInt = c + 2*d
 		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 (SHLLconst <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 != Op386MOVWstoreconstidx2 {
-			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(Op386MOVLstoreconstidx1)
-		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, Op386SHLLconst, i.Type)
-		v0.AuxInt = 1
-		v0.AddArg(i)
-		v.AddArg(v0)
-		v.AddArg(mem)
-		return true
-	}
 	return false
 }
-func rewriteValue386_Op386MOVWstoreidx1(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVWstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVWstore [off] {sym} ptr (MOVWLSX x) mem)
 	// cond:
-	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+	// result: (MOVWstore [off] {sym} ptr x mem)
 	for {
-		c := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386SHLLconst {
+		if v_1.Op != Op386MOVWLSX {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} ptr (MOVWLZX x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVWLZX {
 			break
 		}
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVWstoreidx2)
-		v.AuxInt = c
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstore)
+		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
+		v.AddArg(x)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	// match: (MOVWstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
 	for {
-		c := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		d := v_0.AuxInt
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVWstoreidx1)
-		v.AuxInt = c + d
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(Op386MOVWstore)
+		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
-	// cond:
-	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	// match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
 	for {
-		c := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386ADDLconst {
+		if v_1.Op != Op386MOVLconst {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVWstoreidx1)
-		v.AuxInt = c + d
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
+			break
+		}
+		v.reset(Op386MOVWstoreconst)
+		v.AuxInt = makeValAndOff(int64(int16(c)), off)
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [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)
+	// match: (MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
+	// result: (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val 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 != Op386SHRLconst {
-			break
-		}
-		if v_2.AuxInt != 16 {
-			break
-		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != Op386MOVWstoreidx1 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL {
 			break
 		}
-		if x.AuxInt != i-2 {
+		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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		if x.Aux != s {
+		v.reset(Op386MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym1} (LEAL1 [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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL1 {
 			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)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(Op386MOVLstoreidx1)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(w)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+	// match: (MOVWstore [off1] {sym1} (LEAL2 [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 {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != Op386SHRLconst {
-			break
-		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != Op386MOVWstoreidx1 {
-			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 != Op386SHRLconst {
-			break
-		}
-		if w0.AuxInt != j-16 {
-			break
-		}
-		if w != w0.Args[0] {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL2 {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(Op386MOVLstoreidx1)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
+		v.reset(Op386MOVWstoreidx2)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(w0)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MOVWstoreidx2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+	// match: (MOVWstore [off] {sym} (ADDL ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
 	for {
-		c := v.AuxInt
+		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386ADDLconst {
+		if v_0.Op != Op386ADDL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVWstoreidx2)
-		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 (ADDLconst [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 != Op386ADDLconst {
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(Op386MOVWstoreidx2)
-		v.AuxInt = c + 2*d
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -6518,24 +7070,24 @@ func rewriteValue386_Op386MOVWstoreidx2(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+	// match: (MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem)
+	// result: (MOVLstore [i-2] {s} p w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != Op386SHRLconst {
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRLconst {
 			break
 		}
-		if v_2.AuxInt != 16 {
+		if v_1.AuxInt != 16 {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != Op386MOVWstoreidx2 {
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != Op386MOVWstore {
 			break
 		}
 		if x.AuxInt != i-2 {
@@ -6544,47 +7096,41 @@ func rewriteValue386_Op386MOVWstoreidx2(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
-			break
-		}
-		if w != x.Args[2] {
+		if w != x.Args[1] {
 			break
 		}
-		mem := x.Args[3]
+		mem := x.Args[2]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVLstoreidx1)
+		v.reset(Op386MOVLstore)
 		v.AuxInt = i - 2
 		v.Aux = s
 		v.AddArg(p)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, 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 (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
+	// match: (MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem)
+	// result: (MOVLstore [i-2] {s} p w0 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != Op386SHRLconst {
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRLconst {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != Op386MOVWstoreidx2 {
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != Op386MOVWstore {
 			break
 		}
 		if x.AuxInt != i-2 {
@@ -6593,13 +7139,11 @@ func rewriteValue386_Op386MOVWstoreidx2(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
-			break
-		}
-		w0 := x.Args[2]
+		w0 := x.Args[1]
 		if w0.Op != Op386SHRLconst {
 			break
 		}
@@ -6609,593 +7153,5054 @@ func rewriteValue386_Op386MOVWstoreidx2(v *Value, config *Config) bool {
 		if w != w0.Args[0] {
 			break
 		}
-		mem := x.Args[3]
+		mem := x.Args[2]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(Op386MOVLstoreidx1)
+		v.reset(Op386MOVLstore)
 		v.AuxInt = i - 2
 		v.Aux = s
 		v.AddArg(p)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, idx.Type)
-		v0.AuxInt = 1
-		v0.AddArg(idx)
-		v.AddArg(v0)
 		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386MULL(v *Value, config *Config) bool {
+func rewriteValue386_Op386MOVWstoreconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MULL x (MOVLconst [c]))
-	// cond:
-	// result: (MULLconst [c] x)
+	config := b.Func.Config
+	_ = config
+	// match: (MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386MULLconst)
-		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 != Op386MOVLconst {
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(Op386MULLconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		v.reset(Op386MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386MULLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULLconst [c] (MULLconst [d] x))
-	// cond:
-	// result: (MULLconst [int64(int32(c * d))] x)
+	// match: (MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)   && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
+	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
 	for {
-		c := v.AuxInt
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386MULLconst {
+		if v_0.Op != Op386LEAL {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(Op386MULLconst)
-		v.AuxInt = int64(int32(c * d))
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [-1] x)
-	// cond:
-	// result: (NEGL x)
-	for {
-		if v.AuxInt != -1 {
+		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) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386NEGL)
-		v.AddArg(x)
+		v.reset(Op386MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [0] _)
-	// cond:
-	// result: (MOVLconst [0])
+	// match: (MOVWstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		if v.AuxInt != 0 {
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL1 {
 			break
 		}
-		v.reset(Op386MOVLconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (MULLconst [1] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 1 {
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(Op386MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [3] x)
-	// cond:
-	// result: (LEAL2 x x)
+	// match: (MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
-		if v.AuxInt != 3 {
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386LEAL2 {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL2)
-		v.AddArg(x)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [5] x)
-	// cond:
-	// result: (LEAL4 x x)
-	for {
-		if v.AuxInt != 5 {
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL4)
-		v.AddArg(x)
-		v.AddArg(x)
+		v.reset(Op386MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [7] x)
+	// match: (MOVWstoreconst [x] {sym} (ADDL ptr idx) mem)
 	// cond:
-	// result: (LEAL8 (NEGL <v.Type> x) x)
+	// result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 7 {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL8)
-		v0 := b.NewValue0(v.Line, Op386NEGL, v.Type)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(Op386MOVWstoreconstidx1)
+		v.AuxInt = x
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [9] x)
-	// cond:
-	// result: (LEAL8 x x)
+	// 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 {
-		if v.AuxInt != 9 {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != Op386MOVWstoreconst {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL8)
-		v.AddArg(x)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [11] x)
-	// cond:
-	// result: (LEAL2 x (LEAL4 <v.Type> x x))
-	for {
-		if v.AuxInt != 11 {
+		a := x.AuxInt
+		if x.Aux != s {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL2)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL4, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULLconst [13] x)
-	// cond:
-	// result: (LEAL4 x (LEAL2 <v.Type> x x))
-	for {
-		if v.AuxInt != 13 {
+		_ = x.Args[1]
+		if p != x.Args[0] {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL4)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL2, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULLconst [21] x)
-	// cond:
-	// result: (LEAL4 x (LEAL4 <v.Type> x x))
-	for {
-		if v.AuxInt != 21 {
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL4)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL4, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(Op386MOVLstoreconst)
+		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
 	}
-	// match: (MULLconst [25] x)
+	return false
+}
+func rewriteValue386_Op386MOVWstoreconstidx1_0(v *Value) bool {
+	// match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem)
 	// cond:
-	// result: (LEAL8 x (LEAL2 <v.Type> x x))
+	// result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 25 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL8)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL2, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULLconst [37] x)
-	// cond:
-	// result: (LEAL4 x (LEAL8 <v.Type> x x))
-	for {
-		if v.AuxInt != 37 {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL4)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL8, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstoreconstidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [41] x)
+	// match: (MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
 	// cond:
-	// result: (LEAL8 x (LEAL4 <v.Type> x x))
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 41 {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL8)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL4, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [73] x)
+	// match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
 	// cond:
-	// result: (LEAL8 x (LEAL8 <v.Type> x x))
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 73 {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		x := v.Args[0]
-		v.reset(Op386LEAL8)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386LEAL8, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c)
-	// result: (SHLLconst [log2(c)] x)
+	// 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
-		x := v.Args[0]
-		if !(isPowerOfTwo(c)) {
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != Op386MOVWstoreconstidx1 {
 			break
 		}
-		v.reset(Op386SHLLconst)
-		v.AuxInt = log2(c)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c+1) && c >= 15
-	// result: (SUBL (SHLLconst <v.Type> [log2(c+1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c+1) && c >= 15) {
+		a := x.AuxInt
+		if x.Aux != s {
 			break
 		}
-		v.reset(Op386SUBL)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, v.Type)
-		v0.AuxInt = log2(c + 1)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c-1) && c >= 17
-	// result: (LEAL1 (SHLLconst <v.Type> [log2(c-1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-1) && c >= 17) {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		v.reset(Op386LEAL1)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, v.Type)
-		v0.AuxInt = log2(c - 1)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c-2) && c >= 34
-	// result: (LEAL2 (SHLLconst <v.Type> [log2(c-2)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-2) && c >= 34) {
+		if i != x.Args[1] {
 			break
 		}
-		v.reset(Op386LEAL2)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, v.Type)
-		v0.AuxInt = log2(c - 2)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(Op386MOVLstoreconstidx1)
+		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
 	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c-4) && c >= 68
-	// result: (LEAL4 (SHLLconst <v.Type> [log2(c-4)] x) x)
+	return false
+}
+func rewriteValue386_Op386MOVWstoreconstidx2_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-4) && c >= 68) {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		v.reset(Op386LEAL4)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, v.Type)
-		v0.AuxInt = log2(c - 4)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] x)
-	// cond: isPowerOfTwo(c-8) && c >= 136
-	// result: (LEAL8 (SHLLconst <v.Type> [log2(c-8)] x) x)
+	// match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-8) && c >= 136) {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		v.reset(Op386LEAL8)
-		v0 := b.NewValue0(v.Line, Op386SHLLconst, v.Type)
-		v0.AuxInt = log2(c - 8)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(Op386MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(2 * c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] x)
-	// cond: c%3 == 0 && isPowerOfTwo(c/3)
-	// result: (SHLLconst [log2(c/3)] (LEAL2 <v.Type> x x))
+	// 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 (SHLLconst <i.Type> [1] i) mem)
 	for {
 		c := v.AuxInt
-		x := v.Args[0]
-		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != Op386MOVWstoreconstidx2 {
 			break
 		}
-		v.reset(Op386SHLLconst)
-		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, Op386LEAL2, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		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(Op386MOVLstoreconstidx1)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, i.Type)
+		v0.AuxInt = 1
+		v0.AddArg(i)
 		v.AddArg(v0)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] x)
-	// cond: c%5 == 0 && isPowerOfTwo(c/5)
-	// result: (SHLLconst [log2(c/5)] (LEAL4 <v.Type> x x))
+	return false
+}
+func rewriteValue386_Op386MOVWstoreidx1_0(v *Value) bool {
+	// match: (MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
-		x := v.Args[0]
-		if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
 			break
 		}
-		v.reset(Op386SHLLconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, Op386LEAL4, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		if v_1.AuxInt != 1 {
+			break
+		}
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] x)
-	// cond: c%9 == 0 && isPowerOfTwo(c/9)
-	// result: (SHLLconst [log2(c/9)] (LEAL8 <v.Type> x x))
+	// match: (MOVWstoreidx1 [c] {sym} (SHLLconst [1] idx) ptr val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
-		x := v.Args[0]
-		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
 			break
 		}
-		v.reset(Op386SHLLconst)
-		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, Op386LEAL8, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		if v_0.AuxInt != 1 {
+			break
+		}
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULLconst [c] (MOVLconst [d]))
+	// match: (MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVLconst [int64(int32(c*d))])
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386MOVLconst {
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
 		d := v_0.AuxInt
-		v.reset(Op386MOVLconst)
-		v.AuxInt = int64(int32(c * d))
-		return true
-	}
-	return false
-}
-func rewriteValue386_Op386NEGL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NEGL (MOVLconst [c]))
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx1)
+		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} idx (ADDLconst [d] ptr) val mem)
 	// cond:
-	// result: (MOVLconst [int64(int32(-c))])
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != Op386MOVLconst {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(Op386MOVLconst)
-		v.AuxInt = int64(int32(-c))
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386NOTL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOTL (MOVLconst [c]))
+	// match: (MOVWstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
 	// cond:
-	// result: (MOVLconst [^c])
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != Op386MOVLconst {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(Op386MOVLconst)
-		v.AuxInt = ^c
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORL x (MOVLconst [c]))
+	// match: (MOVWstoreidx1 [c] {sym} (ADDLconst [d] idx) ptr val mem)
 	// cond:
-	// result: (ORLconst [c] x)
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386ORLconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ORL (MOVLconst [c]) x)
-	// cond:
-	// result: (ORLconst [c] x)
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [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 {
-		v_0 := v.Args[0]
-		if v_0.Op != Op386MOVLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(Op386ORLconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ORL x x)
-	// cond:
-	// result: x
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p idx w mem)
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(Op386MOVLstoreidx1)
+		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} idx p (SHRLconst [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
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(Op386MOVLstoreidx1)
+		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} idx p (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MOVWstoreidx1_10(v *Value) bool {
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} idx p w0:(SHRLconst [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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [i] {s} idx p (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [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
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [i] {s} idx p (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} idx p w0:(SHRLconst [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
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MOVWstoreidx2_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386ADDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx2)
+		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 (ADDLconst [d] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386ADDLconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(Op386MOVWstoreidx2)
+		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 (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx2 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, 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 (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != Op386SHRLconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != Op386MOVWstoreidx2 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != Op386SHRLconst {
+			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(Op386MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, idx.Type)
+		v0.AuxInt = 1
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MULL_0(v *Value) bool {
+	// match: (MULL x (MOVLconst [c]))
+	// cond:
+	// result: (MULLconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(Op386MULLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULL (MOVLconst [c]) x)
+	// cond:
+	// result: (MULLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(Op386MULLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MULLconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLconst [c] (MULLconst [d] x))
+	// cond:
+	// result: (MULLconst [int64(int32(c * d))] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MULLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(Op386MULLconst)
+		v.AuxInt = int64(int32(c * d))
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [-1] x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386NEGL)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [0] _)
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(Op386MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MULLconst [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: (MULLconst [3] x)
+	// cond:
+	// result: (LEAL2 x x)
+	for {
+		if v.AuxInt != 3 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL2)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [5] x)
+	// cond:
+	// result: (LEAL4 x x)
+	for {
+		if v.AuxInt != 5 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL4)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [7] x)
+	// cond:
+	// result: (LEAL8 (NEGL <v.Type> x) x)
+	for {
+		if v.AuxInt != 7 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL8)
+		v0 := b.NewValue0(v.Pos, Op386NEGL, v.Type)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [9] x)
+	// cond:
+	// result: (LEAL8 x x)
+	for {
+		if v.AuxInt != 9 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL8)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [11] x)
+	// cond:
+	// result: (LEAL2 x (LEAL4 <v.Type> x x))
+	for {
+		if v.AuxInt != 11 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL2)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [13] x)
+	// cond:
+	// result: (LEAL4 x (LEAL2 <v.Type> x x))
+	for {
+		if v.AuxInt != 13 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MULLconst_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLconst [21] x)
+	// cond:
+	// result: (LEAL4 x (LEAL4 <v.Type> x x))
+	for {
+		if v.AuxInt != 21 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [25] x)
+	// cond:
+	// result: (LEAL8 x (LEAL2 <v.Type> x x))
+	for {
+		if v.AuxInt != 25 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [37] x)
+	// cond:
+	// result: (LEAL4 x (LEAL8 <v.Type> x x))
+	for {
+		if v.AuxInt != 37 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [41] x)
+	// cond:
+	// result: (LEAL8 x (LEAL4 <v.Type> x x))
+	for {
+		if v.AuxInt != 41 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [73] x)
+	// cond:
+	// result: (LEAL8 x (LEAL8 <v.Type> x x))
+	for {
+		if v.AuxInt != 73 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(Op386LEAL8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, Op386LEAL8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c)
+	// result: (SHLLconst [log2(c)] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(Op386SHLLconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c+1) && c >= 15
+	// result: (SUBL (SHLLconst <v.Type> [log2(c+1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c+1) && c >= 15) {
+			break
+		}
+		v.reset(Op386SUBL)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, v.Type)
+		v0.AuxInt = log2(c + 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c-1) && c >= 17
+	// result: (LEAL1 (SHLLconst <v.Type> [log2(c-1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-1) && c >= 17) {
+			break
+		}
+		v.reset(Op386LEAL1)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, v.Type)
+		v0.AuxInt = log2(c - 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c-2) && c >= 34
+	// result: (LEAL2 (SHLLconst <v.Type> [log2(c-2)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-2) && c >= 34) {
+			break
+		}
+		v.reset(Op386LEAL2)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, v.Type)
+		v0.AuxInt = log2(c - 2)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c-4) && c >= 68
+	// result: (LEAL4 (SHLLconst <v.Type> [log2(c-4)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-4) && c >= 68) {
+			break
+		}
+		v.reset(Op386LEAL4)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, v.Type)
+		v0.AuxInt = log2(c - 4)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386MULLconst_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLconst [c] x)
+	// cond: isPowerOfTwo(c-8) && c >= 136
+	// result: (LEAL8 (SHLLconst <v.Type> [log2(c-8)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-8) && c >= 136) {
+			break
+		}
+		v.reset(Op386LEAL8)
+		v0 := b.NewValue0(v.Pos, Op386SHLLconst, v.Type)
+		v0.AuxInt = log2(c - 8)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: c%3 == 0 && isPowerOfTwo(c/3)
+	// result: (SHLLconst [log2(c/3)] (LEAL2 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+			break
+		}
+		v.reset(Op386SHLLconst)
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, Op386LEAL2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: c%5 == 0 && isPowerOfTwo(c/5)
+	// result: (SHLLconst [log2(c/5)] (LEAL4 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+			break
+		}
+		v.reset(Op386SHLLconst)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, Op386LEAL4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULLconst [c] x)
+	// cond: c%9 == 0 && isPowerOfTwo(c/9)
+	// result: (SHLLconst [log2(c/9)] (LEAL8 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+			break
+		}
+		v.reset(Op386SHLLconst)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Pos, Op386LEAL8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// 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 != Op386MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(Op386MOVLconst)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386NEGL_0(v *Value) bool {
+	// match: (NEGL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [int64(int32(-c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(Op386MOVLconst)
+		v.AuxInt = int64(int32(-c))
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386NOTL_0(v *Value) bool {
+	// match: (NOTL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(Op386MOVLconst)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL x (MOVLconst [c]))
+	// cond:
+	// result: (ORLconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(Op386ORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (MOVLconst [c]) x)
+	// cond:
+	// result: (ORLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(Op386ORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (SHLLconst [c] x) (SHRLconst [d] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRLconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (SHRLconst [d] x) (SHLLconst [c] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRBconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRBconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL x x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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 [i0] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && 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 [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != Op386MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWload, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)) x0:(MOVBload [i0] {s} p mem))
+	// cond: i1 == i0+1   && 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 [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != Op386MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWload, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWload [i0] {s} p mem) s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem))) s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBload {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem)) x0:(MOVWload [i0] {s} p mem)) s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBload {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)) o0:(ORL x0:(MOVWload [i0] {s} p mem) s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBload {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[1]
+		p := x2.Args[0]
+		mem := x2.Args[1]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem)) x0:(MOVWload [i0] {s} p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBload {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[1]
+		p := x2.Args[0]
+		mem := x2.Args[1]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBload {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (ORL s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1==i0+1   && 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> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && 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.Pos, Op386MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_30(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s1 := v.Args[1]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[2]
+		if idx != x2.Args[0] {
+			break
+		}
+		if p != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_40(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		x0 := o0.Args[0]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		s0 := o0.Args[1]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
+			break
+		}
+		if s0.AuxInt != 16 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386ORL_50(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
+			break
+		}
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
 			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 != Op386MOVBload {
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := v.Args[1]
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
 		if s0.Op != Op386SHLLconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		if s0.AuxInt != 16 {
 			break
 		}
 		x1 := s0.Args[0]
-		if x1.Op != Op386MOVBload {
+		if x1.Op != Op386MOVBloadidx1 {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		i2 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x1.Aux != s {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if p != x1.Args[0] {
+		if p != x1.Args[1] {
 			break
 		}
-		if mem != x1.Args[1] {
+		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)) {
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
 			break
 		}
-		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, Op386MOVWload, config.fe.TypeUInt16())
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
+		v0.AuxInt = i0
 		v0.Aux = s
 		v0.AddArg(p)
+		v0.AddArg(idx)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (ORL o0:(ORL                        x0:(MOVWload [i]   {s} p mem)     s0:(SHLLconst [16] x1:(MOVBload [i+2] {s} p mem)))     s1:(SHLLconst [24] x2:(MOVBload [i+3] {s} p mem)))
-	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p mem)
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != Op386ORL {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != Op386MOVWload {
+		if s1.AuxInt != 24 {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
 		if s0.Op != Op386SHLLconst {
 			break
 		}
@@ -7203,87 +12208,98 @@ func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
 			break
 		}
 		x1 := s0.Args[0]
-		if x1.Op != Op386MOVBload {
-			break
-		}
-		if x1.AuxInt != i+2 {
+		if x1.Op != Op386MOVBloadidx1 {
 			break
 		}
+		i2 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
-		if mem != x1.Args[1] {
-			break
-		}
-		s1 := v.Args[1]
-		if s1.Op != Op386SHLLconst {
+		if idx != x1.Args[1] {
 			break
 		}
-		if s1.AuxInt != 24 {
+		if mem != x1.Args[2] {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != Op386MOVBload {
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x2.Aux != s {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if p != x2.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		if mem != x2.Args[1] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
+		v0.AuxInt = i0
 		v0.Aux = s
 		v0.AddArg(p)
+		v0.AddArg(idx)
 		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)
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x0 := v.Args[0]
-		if x0.Op != Op386MOVBloadidx1 {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		idx := x0.Args[1]
-		mem := x0.Args[2]
-		s0 := v.Args[1]
+		if s1.AuxInt != 24 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
 		if s0.Op != Op386SHLLconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		if s0.AuxInt != 16 {
 			break
 		}
 		x1 := s0.Args[0]
 		if x1.Op != Op386MOVBloadidx1 {
 			break
 		}
-		if x1.AuxInt != i+1 {
-			break
-		}
+		i2 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
@@ -7293,38 +12309,66 @@ func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
 		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)) {
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
 			break
 		}
-		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, Op386MOVWloadidx1, v.Type)
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
+		v0.AuxInt = i0
 		v0.Aux = s
 		v0.AddArg(p)
 		v0.AddArg(idx)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (ORL o0:(ORL                        x0:(MOVWloadidx1 [i]   {s} p idx mem)     s0:(SHLLconst [16] x1:(MOVBloadidx1 [i+2] {s} p idx mem)))     s1:(SHLLconst [24] x2:(MOVBloadidx1 [i+3] {s} p idx mem)))
-	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != Op386ORL {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != Op386SHLLconst {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != Op386MOVWloadidx1 {
+		if s1.AuxInt != 24 {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		idx := x0.Args[1]
-		mem := x0.Args[2]
-		s0 := o0.Args[1]
+		x2 := s1.Args[0]
+		if x2.Op != Op386MOVBloadidx1 {
+			break
+		}
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		p := x2.Args[0]
+		idx := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
+			break
+		}
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
 		if s0.Op != Op386SHLLconst {
 			break
 		}
@@ -7335,22 +12379,58 @@ func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
 		if x1.Op != Op386MOVBloadidx1 {
 			break
 		}
-		if x1.AuxInt != i+2 {
-			break
-		}
+		i2 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if idx != x1.Args[1] {
+		if p != x1.Args[1] {
 			break
 		}
 		if mem != x1.Args[2] {
 			break
 		}
-		s1 := v.Args[1]
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)))
+	// cond: i2 == i0+2   && i3 == i0+3   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
 		if s1.Op != Op386SHLLconst {
 			break
 		}
@@ -7361,29 +12441,68 @@ func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
 		if x2.Op != Op386MOVBloadidx1 {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		i3 := x2.AuxInt
+		s := x2.Aux
+		_ = x2.Args[2]
+		idx := x2.Args[0]
+		p := x2.Args[1]
+		mem := x2.Args[2]
+		o0 := v.Args[1]
+		if o0.Op != Op386ORL {
 			break
 		}
-		if x2.Aux != s {
+		_ = o0.Args[1]
+		s0 := o0.Args[0]
+		if s0.Op != Op386SHLLconst {
 			break
 		}
-		if p != x2.Args[0] {
+		if s0.AuxInt != 16 {
 			break
 		}
-		if idx != x2.Args[1] {
+		x1 := s0.Args[0]
+		if x1.Op != Op386MOVBloadidx1 {
 			break
 		}
-		if mem != x2.Args[2] {
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		x0 := o0.Args[1]
+		if x0.Op != Op386MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, Op386MOVLloadidx1, v.Type)
+		v0 := b.NewValue0(v.Pos, Op386MOVLloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
+		v0.AuxInt = i0
 		v0.Aux = s
 		v0.AddArg(p)
 		v0.AddArg(idx)
@@ -7392,9 +12511,7 @@ func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ORLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ORLconst_0(v *Value) bool {
 	// match: (ORLconst [c] x)
 	// cond: int32(c)==0
 	// result: x
@@ -7437,9 +12554,7 @@ func rewriteValue386_Op386ORLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ROLBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ROLBconst_0(v *Value) bool {
 	// match: (ROLBconst [c] (ROLBconst [d] x))
 	// cond:
 	// result: (ROLBconst [(c+d)& 7] x)
@@ -7471,9 +12586,7 @@ func rewriteValue386_Op386ROLBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ROLLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ROLLconst_0(v *Value) bool {
 	// match: (ROLLconst [c] (ROLLconst [d] x))
 	// cond:
 	// result: (ROLLconst [(c+d)&31] x)
@@ -7505,9 +12618,7 @@ func rewriteValue386_Op386ROLLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386ROLWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386ROLWconst_0(v *Value) bool {
 	// match: (ROLWconst [c] (ROLWconst [d] x))
 	// cond:
 	// result: (ROLWconst [(c+d)&15] x)
@@ -7539,13 +12650,12 @@ func rewriteValue386_Op386ROLWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SARB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SARB_0(v *Value) bool {
 	// match: (SARB x (MOVLconst [c]))
 	// cond:
-	// result: (SARBconst [c&31] x)
+	// result: (SARBconst [min(c&31,7)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -7553,30 +12663,26 @@ func rewriteValue386_Op386SARB(v *Value, config *Config) bool {
 		}
 		c := v_1.AuxInt
 		v.reset(Op386SARBconst)
-		v.AuxInt = c & 31
+		v.AuxInt = min(c&31, 7)
 		v.AddArg(x)
 		return true
 	}
-	// match: (SARB x (MOVLconst [c]))
+	return false
+}
+func rewriteValue386_Op386SARBconst_0(v *Value) bool {
+	// match: (SARBconst x [0])
 	// cond:
-	// result: (SARBconst [c&31] x)
+	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		if v.AuxInt != 0 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386SARBconst)
-		v.AuxInt = c & 31
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386SARBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
 	// match: (SARBconst [c] (MOVLconst [d]))
 	// cond:
 	// result: (MOVLconst [d>>uint64(c)])
@@ -7593,28 +12699,12 @@ func rewriteValue386_Op386SARBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SARL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// 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 != Op386MOVLconst {
-			break
-		}
-		c := v_1.AuxInt
-		v.reset(Op386SARLconst)
-		v.AuxInt = c & 31
-		v.AddArg(x)
-		return true
-	}
+func rewriteValue386_Op386SARL_0(v *Value) bool {
 	// match: (SARL x (MOVLconst [c]))
 	// cond:
 	// result: (SARLconst [c&31] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -7630,6 +12720,7 @@ func rewriteValue386_Op386SARL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SARL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ANDLconst {
@@ -7646,9 +12737,20 @@ func rewriteValue386_Op386SARL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SARLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SARLconst_0(v *Value) bool {
+	// match: (SARLconst x [0])
+	// 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: (SARLconst [c] (MOVLconst [d]))
 	// cond:
 	// result: (MOVLconst [d>>uint64(c)])
@@ -7665,13 +12767,12 @@ func rewriteValue386_Op386SARLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SARW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SARW_0(v *Value) bool {
 	// match: (SARW x (MOVLconst [c]))
 	// cond:
-	// result: (SARWconst [c&31] x)
+	// result: (SARWconst [min(c&31,15)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -7679,30 +12780,26 @@ func rewriteValue386_Op386SARW(v *Value, config *Config) bool {
 		}
 		c := v_1.AuxInt
 		v.reset(Op386SARWconst)
-		v.AuxInt = c & 31
+		v.AuxInt = min(c&31, 15)
 		v.AddArg(x)
 		return true
 	}
-	// match: (SARW x (MOVLconst [c]))
+	return false
+}
+func rewriteValue386_Op386SARWconst_0(v *Value) bool {
+	// match: (SARWconst x [0])
 	// cond:
-	// result: (SARWconst [c&31] x)
+	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		if v.AuxInt != 0 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386SARWconst)
-		v.AuxInt = c & 31
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValue386_Op386SARWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
 	// match: (SARWconst [c] (MOVLconst [d]))
 	// cond:
 	// result: (MOVLconst [d>>uint64(c)])
@@ -7719,13 +12816,12 @@ func rewriteValue386_Op386SARWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SBBL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SBBL_0(v *Value) bool {
 	// match: (SBBL x (MOVLconst [c]) f)
 	// cond:
 	// result: (SBBLconst [c] x f)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -7741,9 +12837,7 @@ func rewriteValue386_Op386SBBL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SBBLcarrymask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SBBLcarrymask_0(v *Value) bool {
 	// match: (SBBLcarrymask (FlagEQ))
 	// cond:
 	// result: (MOVLconst [0])
@@ -7806,9 +12900,7 @@ func rewriteValue386_Op386SBBLcarrymask(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETA_0(v *Value) bool {
 	// match: (SETA (InvertFlags x))
 	// cond:
 	// result: (SETB x)
@@ -7884,9 +12976,7 @@ func rewriteValue386_Op386SETA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETAE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETAE_0(v *Value) bool {
 	// match: (SETAE (InvertFlags x))
 	// cond:
 	// result: (SETBE x)
@@ -7962,9 +13052,7 @@ func rewriteValue386_Op386SETAE(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETB_0(v *Value) bool {
 	// match: (SETB (InvertFlags x))
 	// cond:
 	// result: (SETA x)
@@ -8040,9 +13128,7 @@ func rewriteValue386_Op386SETB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETBE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETBE_0(v *Value) bool {
 	// match: (SETBE (InvertFlags x))
 	// cond:
 	// result: (SETAE x)
@@ -8118,9 +13204,7 @@ func rewriteValue386_Op386SETBE(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETEQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETEQ_0(v *Value) bool {
 	// match: (SETEQ (InvertFlags x))
 	// cond:
 	// result: (SETEQ x)
@@ -8196,9 +13280,7 @@ func rewriteValue386_Op386SETEQ(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETG_0(v *Value) bool {
 	// match: (SETG (InvertFlags x))
 	// cond:
 	// result: (SETL x)
@@ -8274,9 +13356,7 @@ func rewriteValue386_Op386SETG(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETGE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETGE_0(v *Value) bool {
 	// match: (SETGE (InvertFlags x))
 	// cond:
 	// result: (SETLE x)
@@ -8352,9 +13432,7 @@ func rewriteValue386_Op386SETGE(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETL_0(v *Value) bool {
 	// match: (SETL (InvertFlags x))
 	// cond:
 	// result: (SETG x)
@@ -8430,9 +13508,7 @@ func rewriteValue386_Op386SETL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETLE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETLE_0(v *Value) bool {
 	// match: (SETLE (InvertFlags x))
 	// cond:
 	// result: (SETGE x)
@@ -8508,9 +13584,7 @@ func rewriteValue386_Op386SETLE(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SETNE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SETNE_0(v *Value) bool {
 	// match: (SETNE (InvertFlags x))
 	// cond:
 	// result: (SETNE x)
@@ -8586,28 +13660,12 @@ func rewriteValue386_Op386SETNE(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SHLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// 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 != Op386MOVLconst {
-			break
-		}
-		c := v_1.AuxInt
-		v.reset(Op386SHLLconst)
-		v.AuxInt = c & 31
-		v.AddArg(x)
-		return true
-	}
+func rewriteValue386_Op386SHLL_0(v *Value) bool {
 	// match: (SHLL x (MOVLconst [c]))
 	// cond:
 	// result: (SHLLconst [c&31] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -8623,6 +13681,7 @@ func rewriteValue386_Op386SHLL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SHLL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ANDLconst {
@@ -8639,63 +13698,83 @@ func rewriteValue386_Op386SHLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SHRB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SHRB x (MOVLconst [c]))
+func rewriteValue386_Op386SHLLconst_0(v *Value) bool {
+	// match: (SHLLconst x [0])
 	// 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
+	}
+	return false
+}
+func rewriteValue386_Op386SHRB_0(v *Value) bool {
+	// match: (SHRB x (MOVLconst [c]))
+	// cond: c&31 < 8
 	// result: (SHRBconst [c&31] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
 			break
 		}
 		c := v_1.AuxInt
+		if !(c&31 < 8) {
+			break
+		}
 		v.reset(Op386SHRBconst)
 		v.AuxInt = c & 31
 		v.AddArg(x)
 		return true
 	}
-	// match: (SHRB x (MOVLconst [c]))
-	// cond:
-	// result: (SHRBconst [c&31] x)
+	// match: (SHRB _ (MOVLconst [c]))
+	// cond: c&31 >= 8
+	// result: (MOVLconst [0])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(Op386SHRBconst)
-		v.AuxInt = c & 31
-		v.AddArg(x)
+		if !(c&31 >= 8) {
+			break
+		}
+		v.reset(Op386MOVLconst)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValue386_Op386SHRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SHRL x (MOVLconst [c]))
+func rewriteValue386_Op386SHRBconst_0(v *Value) bool {
+	// match: (SHRBconst x [0])
 	// cond:
-	// result: (SHRLconst [c&31] x)
+	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		if v.AuxInt != 0 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386SHRLconst)
-		v.AuxInt = c & 31
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
+	return false
+}
+func rewriteValue386_Op386SHRL_0(v *Value) bool {
 	// match: (SHRL x (MOVLconst [c]))
 	// cond:
 	// result: (SHRLconst [c&31] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -8711,6 +13790,7 @@ func rewriteValue386_Op386SHRL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SHRL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386ANDLconst {
@@ -8727,48 +13807,85 @@ func rewriteValue386_Op386SHRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SHRW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SHRW x (MOVLconst [c]))
+func rewriteValue386_Op386SHRLconst_0(v *Value) bool {
+	// match: (SHRLconst x [0])
 	// 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
+	}
+	return false
+}
+func rewriteValue386_Op386SHRW_0(v *Value) bool {
+	// match: (SHRW x (MOVLconst [c]))
+	// cond: c&31 < 16
 	// result: (SHRWconst [c&31] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
 			break
 		}
 		c := v_1.AuxInt
+		if !(c&31 < 16) {
+			break
+		}
 		v.reset(Op386SHRWconst)
 		v.AuxInt = c & 31
 		v.AddArg(x)
 		return true
 	}
-	// match: (SHRW x (MOVLconst [c]))
-	// cond:
-	// result: (SHRWconst [c&31] x)
+	// match: (SHRW _ (MOVLconst [c]))
+	// cond: c&31 >= 16
+	// result: (MOVLconst [0])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(Op386SHRWconst)
-		v.AuxInt = c & 31
+		if !(c&31 >= 16) {
+			break
+		}
+		v.reset(Op386MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValue386_Op386SHRWconst_0(v *Value) bool {
+	// match: (SHRWconst x [0])
+	// 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
 	}
 	return false
 }
-func rewriteValue386_Op386SUBL(v *Value, config *Config) bool {
+func rewriteValue386_Op386SUBL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBL x (MOVLconst [c]))
 	// cond:
 	// result: (SUBLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -8784,6 +13901,7 @@ func rewriteValue386_Op386SUBL(v *Value, config *Config) bool {
 	// cond:
 	// result: (NEGL (SUBLconst <v.Type> x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != Op386MOVLconst {
 			break
@@ -8791,7 +13909,7 @@ func rewriteValue386_Op386SUBL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(Op386NEGL)
-		v0 := b.NewValue0(v.Line, Op386SUBLconst, v.Type)
+		v0 := b.NewValue0(v.Pos, Op386SUBLconst, v.Type)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8801,6 +13919,7 @@ func rewriteValue386_Op386SUBL(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVLconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -8811,13 +13930,12 @@ func rewriteValue386_Op386SUBL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SUBLcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SUBLcarry_0(v *Value) bool {
 	// match: (SUBLcarry x (MOVLconst [c]))
 	// cond:
 	// result: (SUBLconstcarry [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != Op386MOVLconst {
@@ -8831,9 +13949,7 @@ func rewriteValue386_Op386SUBLcarry(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386SUBLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386SUBLconst_0(v *Value) bool {
 	// match: (SUBLconst [c] x)
 	// cond: int32(c) == 0
 	// result: x
@@ -8860,35 +13976,201 @@ func rewriteValue386_Op386SUBLconst(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_Op386XORL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386XORL_0(v *Value) bool {
 	// match: (XORL x (MOVLconst [c]))
 	// cond:
 	// result: (XORLconst [c] x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(Op386XORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL (MOVLconst [c]) x)
+	// cond:
+	// result: (XORLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(Op386XORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL (SHLLconst [c] x) (SHRLconst [d] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRLconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL (SHRLconst [d] x) (SHLLconst [c] x))
+	// cond: d == 32-c
+	// result: (ROLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(Op386ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: c < 16 && d == 16-c && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 16 && d == 16-c && t.Size() == 2) {
+			break
+		}
+		v.reset(Op386ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != Op386SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != Op386MOVLconst {
+		if v_1.Op != Op386SHRBconst {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(Op386XORLconst)
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XORL (MOVLconst [c]) x)
-	// cond:
-	// result: (XORLconst [c] x)
+	// match: (XORL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: c < 8 && d == 8-c && t.Size() == 1
+	// result: (ROLBconst x [c])
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != Op386MOVLconst {
+		if v_0.Op != Op386SHRBconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(Op386XORLconst)
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != Op386SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 8 && d == 8-c && t.Size() == 1) {
+			break
+		}
+		v.reset(Op386ROLBconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
@@ -8897,6 +14179,7 @@ func rewriteValue386_Op386XORL(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVLconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -8907,9 +14190,7 @@ func rewriteValue386_Op386XORL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_Op386XORLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_Op386XORLconst_0(v *Value) bool {
 	// match: (XORLconst [c] (XORLconst [d] x))
 	// cond:
 	// result: (XORLconst [c ^ d] x)
@@ -8956,13 +14237,12 @@ func rewriteValue386_Op386XORLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add16  x y)
+func rewriteValue386_OpAdd16_0(v *Value) bool {
+	// match: (Add16 x y)
 	// cond:
 	// result: (ADDL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDL)
@@ -8971,13 +14251,12 @@ func rewriteValue386_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add32  x y)
+func rewriteValue386_OpAdd32_0(v *Value) bool {
+	// match: (Add32 x y)
 	// cond:
 	// result: (ADDL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDL)
@@ -8986,13 +14265,12 @@ func rewriteValue386_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (ADDSS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDSS)
@@ -9001,13 +14279,12 @@ func rewriteValue386_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd32carry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAdd32carry_0(v *Value) bool {
 	// match: (Add32carry x y)
 	// cond:
 	// result: (ADDLcarry x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDLcarry)
@@ -9016,13 +14293,12 @@ func rewriteValue386_OpAdd32carry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd32withcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAdd32withcarry_0(v *Value) bool {
 	// match: (Add32withcarry x y c)
 	// cond:
 	// result: (ADCL x y c)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
@@ -9033,13 +14309,12 @@ func rewriteValue386_OpAdd32withcarry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (ADDSD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDSD)
@@ -9048,13 +14323,12 @@ func rewriteValue386_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add8   x y)
+func rewriteValue386_OpAdd8_0(v *Value) bool {
+	// match: (Add8 x y)
 	// cond:
 	// result: (ADDL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDL)
@@ -9063,13 +14337,12 @@ func rewriteValue386_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADDL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ADDL)
@@ -9078,9 +14351,7 @@ func rewriteValue386_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (LEAL {sym} base)
@@ -9093,13 +14364,12 @@ func rewriteValue386_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (ANDL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
@@ -9108,13 +14378,12 @@ func rewriteValue386_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (ANDL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
@@ -9123,13 +14392,12 @@ func rewriteValue386_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (And8  x y)
+func rewriteValue386_OpAnd8_0(v *Value) bool {
+	// match: (And8 x y)
 	// cond:
 	// result: (ANDL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
@@ -9138,13 +14406,12 @@ func rewriteValue386_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (ANDL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
@@ -9153,9 +14420,21 @@ func rewriteValue386_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpBswap32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpAvg32u_0(v *Value) bool {
+	// match: (Avg32u x y)
+	// cond:
+	// result: (AVGLU x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(Op386AVGLU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValue386_OpBswap32_0(v *Value) bool {
 	// match: (Bswap32 x)
 	// cond:
 	// result: (BSWAPL x)
@@ -9166,14 +14445,13 @@ func rewriteValue386_OpBswap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpClosureCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -9185,9 +14463,7 @@ func rewriteValue386_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
 	// result: (NOTL x)
@@ -9198,9 +14474,7 @@ func rewriteValue386_OpCom16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
 	// result: (NOTL x)
@@ -9211,10 +14485,8 @@ func rewriteValue386_OpCom32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com8  x)
+func rewriteValue386_OpCom8_0(v *Value) bool {
+	// match: (Com8 x)
 	// cond:
 	// result: (NOTL x)
 	for {
@@ -9224,10 +14496,8 @@ func rewriteValue386_OpCom8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const16  [val])
+func rewriteValue386_OpConst16_0(v *Value) bool {
+	// match: (Const16 [val])
 	// cond:
 	// result: (MOVLconst [val])
 	for {
@@ -9237,10 +14507,8 @@ func rewriteValue386_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const32  [val])
+func rewriteValue386_OpConst32_0(v *Value) bool {
+	// match: (Const32 [val])
 	// cond:
 	// result: (MOVLconst [val])
 	for {
@@ -9250,9 +14518,7 @@ func rewriteValue386_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (MOVSSconst [val])
@@ -9263,9 +14529,7 @@ func rewriteValue386_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (MOVSDconst [val])
@@ -9276,10 +14540,8 @@ func rewriteValue386_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const8   [val])
+func rewriteValue386_OpConst8_0(v *Value) bool {
+	// match: (Const8 [val])
 	// cond:
 	// result: (MOVLconst [val])
 	for {
@@ -9289,9 +14551,7 @@ func rewriteValue386_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVLconst [b])
@@ -9302,9 +14562,7 @@ func rewriteValue386_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVLconst [0])
@@ -9314,14 +14572,13 @@ func rewriteValue386_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpConvert_0(v *Value) bool {
 	// match: (Convert <t> x mem)
 	// cond:
 	// result: (MOVLconvert <t> x mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(Op386MOVLconvert)
@@ -9331,9 +14588,7 @@ func rewriteValue386_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (CVTTSS2SL x)
@@ -9344,9 +14599,7 @@ func rewriteValue386_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (CVTSS2SD x)
@@ -9357,9 +14610,7 @@ func rewriteValue386_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (CVTSL2SS x)
@@ -9370,9 +14621,7 @@ func rewriteValue386_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (CVTSL2SD x)
@@ -9383,9 +14632,7 @@ func rewriteValue386_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (CVTTSD2SL x)
@@ -9396,9 +14643,7 @@ func rewriteValue386_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (CVTSD2SS x)
@@ -9409,28 +14654,12 @@ func rewriteValue386_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_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(Op386CALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValue386_OpDiv16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div16  x y)
+func rewriteValue386_OpDiv16_0(v *Value) bool {
+	// match: (Div16 x y)
 	// cond:
 	// result: (DIVW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVW)
@@ -9439,13 +14668,12 @@ func rewriteValue386_OpDiv16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpDiv16u_0(v *Value) bool {
 	// match: (Div16u x y)
 	// cond:
 	// result: (DIVWU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVWU)
@@ -9454,13 +14682,12 @@ func rewriteValue386_OpDiv16u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div32  x y)
+func rewriteValue386_OpDiv32_0(v *Value) bool {
+	// match: (Div32 x y)
 	// cond:
 	// result: (DIVL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVL)
@@ -9469,13 +14696,12 @@ func rewriteValue386_OpDiv32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (DIVSS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVSS)
@@ -9484,13 +14710,12 @@ func rewriteValue386_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpDiv32u_0(v *Value) bool {
 	// match: (Div32u x y)
 	// cond:
 	// result: (DIVLU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVLU)
@@ -9499,13 +14724,12 @@ func rewriteValue386_OpDiv32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (DIVSD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVSD)
@@ -9514,302 +14738,321 @@ func rewriteValue386_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpDiv8(v *Value, config *Config) bool {
+func rewriteValue386_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8 x y)
 	// cond:
 	// result: (DIVW  (SignExt8to16 x) (SignExt8to16 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValue386_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValue386_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8u  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8u x y)
 	// cond:
 	// result: (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386DIVWU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValue386_OpEq16(v *Value, config *Config) bool {
+func rewriteValue386_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq16  x y)
+	// match: (Eq16 x y)
 	// cond:
 	// result: (SETEQ (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQ)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEq32(v *Value, config *Config) bool {
+func rewriteValue386_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq32  x y)
+	// match: (Eq32 x y)
 	// cond:
 	// result: (SETEQ (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQ)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEq32F(v *Value, config *Config) bool {
+func rewriteValue386_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (SETEQF (UCOMISS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEq64F(v *Value, config *Config) bool {
+func rewriteValue386_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (SETEQF (UCOMISD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEq8(v *Value, config *Config) bool {
+func rewriteValue386_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq8   x y)
+	// match: (Eq8 x y)
 	// cond:
 	// result: (SETEQ (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQ)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEqB(v *Value, config *Config) bool {
+func rewriteValue386_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (EqB   x y)
+	// match: (EqB x y)
 	// cond:
 	// result: (SETEQ (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQ)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValue386_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (EqPtr x y)
 	// cond:
 	// result: (SETEQ (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETEQ)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq16(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq16  x y)
+	// match: (Geq16 x y)
 	// cond:
 	// result: (SETGE (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGE)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq16U x y)
 	// cond:
 	// result: (SETAE (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETAE)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq32(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq32  x y)
+	// match: (Geq32 x y)
 	// cond:
 	// result: (SETGE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (SETGEF (UCOMISS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32U x y)
 	// cond:
 	// result: (SETAE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETAE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (SETGEF (UCOMISD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq8(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq8   x y)
+	// match: (Geq8 x y)
 	// cond:
 	// result: (SETGE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValue386_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq8U  x y)
+	// match: (Geq8U x y)
 	// cond:
 	// result: (SETAE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETAE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -9818,9 +15061,7 @@ func rewriteValue386_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpGetG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpGetG_0(v *Value) bool {
 	// match: (GetG mem)
 	// cond:
 	// result: (LoweredGetG mem)
@@ -9831,194 +15072,156 @@ func rewriteValue386_OpGetG(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpGoCall(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (GoCall [argwid] mem)
-	// cond:
-	// result: (CALLgo [argwid] mem)
-	for {
-		argwid := v.AuxInt
-		mem := v.Args[0]
-		v.reset(Op386CALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValue386_OpGreater16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater16  x y)
+	// match: (Greater16 x y)
 	// cond:
 	// result: (SETG (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETG)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater16U x y)
 	// cond:
 	// result: (SETA (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETA)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater32(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater32  x y)
+	// match: (Greater32 x y)
 	// cond:
 	// result: (SETG (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETG)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (SETGF (UCOMISS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32U x y)
 	// cond:
 	// result: (SETA (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETA)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (SETGF (UCOMISD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater8(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater8   x y)
+	// match: (Greater8 x y)
 	// cond:
 	// result: (SETG (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETG)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValue386_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater8U  x y)
+	// match: (Greater8U x y)
 	// cond:
 	// result: (SETA (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETA)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_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(Op386HMULW)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-}
-func rewriteValue386_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(Op386HMULWU)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-}
-func rewriteValue386_OpHmul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul32  x y)
+func rewriteValue386_OpHmul32_0(v *Value) bool {
+	// match: (Hmul32 x y)
 	// cond:
 	// result: (HMULL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386HMULL)
@@ -10027,13 +15230,12 @@ func rewriteValue386_OpHmul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpHmul32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpHmul32u_0(v *Value) bool {
 	// match: (Hmul32u x y)
 	// cond:
 	// result: (HMULLU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386HMULLU)
@@ -10042,44 +15244,13 @@ func rewriteValue386_OpHmul32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_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(Op386HMULB)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-}
-func rewriteValue386_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(Op386HMULBU)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-}
-func rewriteValue386_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(Op386CALLinter)
@@ -10089,24 +15260,25 @@ func rewriteValue386_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValue386_OpIsInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (SETB (CMPL idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(Op386SETB)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValue386_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsNonNil p)
@@ -10115,310 +15287,326 @@ func rewriteValue386_OpIsNonNil(v *Value, config *Config) bool {
 	for {
 		p := v.Args[0]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386TESTL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386TESTL, types.TypeFlags)
 		v0.AddArg(p)
 		v0.AddArg(p)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValue386_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (SETBE (CMPL idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(Op386SETBE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq16(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq16  x y)
+	// match: (Leq16 x y)
 	// cond:
 	// result: (SETLE (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETLE)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq16U x y)
 	// cond:
 	// result: (SETBE (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETBE)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq32(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq32  x y)
+	// match: (Leq32 x y)
 	// cond:
 	// result: (SETLE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETLE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (SETGEF (UCOMISS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32U x y)
 	// cond:
 	// result: (SETBE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETBE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (SETGEF (UCOMISD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq8(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq8   x y)
+	// match: (Leq8 x y)
 	// cond:
 	// result: (SETLE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETLE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValue386_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq8U  x y)
+	// match: (Leq8U x y)
 	// cond:
 	// result: (SETBE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETBE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess16(v *Value, config *Config) bool {
+func rewriteValue386_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less16  x y)
+	// match: (Less16 x y)
 	// cond:
 	// result: (SETL (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETL)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess16U(v *Value, config *Config) bool {
+func rewriteValue386_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less16U x y)
 	// cond:
 	// result: (SETB (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETB)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess32(v *Value, config *Config) bool {
+func rewriteValue386_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less32  x y)
+	// match: (Less32 x y)
 	// cond:
 	// result: (SETL (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETL)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess32F(v *Value, config *Config) bool {
+func rewriteValue386_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (SETGF (UCOMISS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess32U(v *Value, config *Config) bool {
+func rewriteValue386_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32U x y)
 	// cond:
 	// result: (SETB (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETB)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess64F(v *Value, config *Config) bool {
+func rewriteValue386_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (SETGF (UCOMISD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETGF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess8(v *Value, config *Config) bool {
+func rewriteValue386_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less8   x y)
+	// match: (Less8 x y)
 	// cond:
 	// result: (SETL (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETL)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLess8U(v *Value, config *Config) bool {
+func rewriteValue386_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less8U  x y)
+	// match: (Less8U x y)
 	// cond:
 	// result: (SETB (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETB)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: (is32BitInt(t) || isPtr(t))
 	// result: (MOVLload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) || isPtr(t)) {
@@ -10434,6 +15622,7 @@ func rewriteValue386_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t)) {
@@ -10449,6 +15638,7 @@ func rewriteValue386_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean() || is8BitInt(t)) {
@@ -10464,6 +15654,7 @@ func rewriteValue386_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVSSload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -10472,77 +15663,27 @@ func rewriteValue386_OpLoad(v *Value, config *Config) bool {
 		v.reset(Op386MOVSSload)
 		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(Op386MOVSDload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValue386_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
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(Op386ROLWconst)
-		v.Type = t
-		v.AuxInt = c & 15
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValue386_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
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(Op386ROLLconst)
-		v.Type = t
-		v.AuxInt = c & 31
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValue386_OpLrot8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot8  <t> x [c])
-	// cond:
-	// result: (ROLBconst <t> [c&7] x)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: is64BitFloat(t)
+	// result: (MOVSDload ptr mem)
 	for {
 		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(Op386ROLBconst)
-		v.Type = t
-		v.AuxInt = c & 7
-		v.AddArg(x)
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is64BitFloat(t)) {
+			break
+		}
+		v.reset(Op386MOVSDload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValue386_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh16x16 <t> x y)
@@ -10550,15 +15691,16 @@ func rewriteValue386_OpLsh16x16(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10566,7 +15708,7 @@ func rewriteValue386_OpLsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh16x32 <t> x y)
@@ -10574,15 +15716,16 @@ func rewriteValue386_OpLsh16x32(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10590,13 +15733,12 @@ func rewriteValue386_OpLsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpLsh16x64_0(v *Value) bool {
 	// match: (Lsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SHLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -10615,6 +15757,7 @@ func rewriteValue386_OpLsh16x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -10629,23 +15772,24 @@ func rewriteValue386_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8  <t> x y)
+	// match: (Lsh16x8 <t> x y)
 	// cond:
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10653,7 +15797,7 @@ func rewriteValue386_OpLsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh32x16 <t> x y)
@@ -10661,15 +15805,16 @@ func rewriteValue386_OpLsh32x16(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10677,7 +15822,7 @@ func rewriteValue386_OpLsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh32x32 <t> x y)
@@ -10685,15 +15830,16 @@ func rewriteValue386_OpLsh32x32(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10701,13 +15847,12 @@ func rewriteValue386_OpLsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpLsh32x64_0(v *Value) bool {
 	// match: (Lsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SHLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -10726,6 +15871,7 @@ func rewriteValue386_OpLsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -10740,23 +15886,24 @@ func rewriteValue386_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x8  <t> x y)
+	// match: (Lsh32x8 <t> x y)
 	// cond:
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10764,7 +15911,7 @@ func rewriteValue386_OpLsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh8x16 <t> x y)
@@ -10772,15 +15919,16 @@ func rewriteValue386_OpLsh8x16(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10788,7 +15936,7 @@ func rewriteValue386_OpLsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh8x32 <t> x y)
@@ -10796,15 +15944,16 @@ func rewriteValue386_OpLsh8x32(v *Value, config *Config) bool {
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10812,13 +15961,12 @@ func rewriteValue386_OpLsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpLsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpLsh8x64_0(v *Value) bool {
 	// match: (Lsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SHLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -10837,6 +15985,7 @@ func rewriteValue386_OpLsh8x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 8
 	// result: (Const8 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -10851,23 +16000,24 @@ func rewriteValue386_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValue386_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8  <t> x y)
+	// match: (Lsh8x8 <t> x y)
 	// cond:
 	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHLL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -10875,13 +16025,12 @@ func rewriteValue386_OpLsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMod16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod16  x y)
+func rewriteValue386_OpMod16_0(v *Value) bool {
+	// match: (Mod16 x y)
 	// cond:
 	// result: (MODW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODW)
@@ -10890,13 +16039,12 @@ func rewriteValue386_OpMod16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMod16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpMod16u_0(v *Value) bool {
 	// match: (Mod16u x y)
 	// cond:
 	// result: (MODWU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODWU)
@@ -10905,13 +16053,12 @@ func rewriteValue386_OpMod16u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMod32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod32  x y)
+func rewriteValue386_OpMod32_0(v *Value) bool {
+	// match: (Mod32 x y)
 	// cond:
 	// result: (MODL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODL)
@@ -10920,13 +16067,12 @@ func rewriteValue386_OpMod32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMod32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpMod32u_0(v *Value) bool {
 	// match: (Mod32u x y)
 	// cond:
 	// result: (MODLU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODLU)
@@ -10935,143 +16081,151 @@ func rewriteValue386_OpMod32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMod8(v *Value, config *Config) bool {
+func rewriteValue386_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8 x y)
 	// cond:
 	// result: (MODW  (SignExt8to16 x) (SignExt8to16 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValue386_OpMod8u(v *Value, config *Config) bool {
+func rewriteValue386_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod8u  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8u x y)
 	// cond:
 	// result: (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MODWU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValue386_OpMove(v *Value, config *Config) bool {
+func rewriteValue386_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(Op386MOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVBload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, Op386MOVBload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVWstore dst (MOVWload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(Op386MOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVWload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, Op386MOVWload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVLstore dst (MOVLload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(Op386MOVLstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBload [2] src mem) 		(MOVWstore dst (MOVWload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(Op386MOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVBload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, Op386MOVBload, typ.UInt8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, Op386MOVWload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, Op386MOVWload, typ.UInt16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -11079,28 +16233,28 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Move [5] dst src mem)
+	// cond:
 	// result: (MOVBstore [4] dst (MOVBload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 5 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 5) {
-			break
-		}
 		v.reset(Op386MOVBstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVBload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, Op386MOVBload, typ.UInt8)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -11108,28 +16262,28 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Move [6] dst src mem)
+	// cond:
 	// result: (MOVWstore [4] dst (MOVWload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6) {
-			break
-		}
 		v.reset(Op386MOVWstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVWload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, Op386MOVWload, typ.UInt16)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -11137,28 +16291,28 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	// match: (Move [7] dst src mem)
+	// cond:
 	// result: (MOVLstore [3] dst (MOVLload [3] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 7 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 7) {
-			break
-		}
 		v.reset(Op386MOVLstore)
 		v.AuxInt = 3
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v0.AuxInt = 3
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -11166,28 +16320,28 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Move [8] dst src mem)
+	// cond:
 	// result: (MOVLstore [4] dst (MOVLload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8) {
-			break
-		}
 		v.reset(Op386MOVLstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -11196,29 +16350,30 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size()%4 != 0
-	// result: (Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%4] 		(ADDLconst <dst.Type> dst [SizeAndAlign(s).Size()%4]) 		(ADDLconst <src.Type> src [SizeAndAlign(s).Size()%4]) 		(MOVLstore dst (MOVLload src mem) mem))
+	// cond: s > 8 && s%4 != 0
+	// result: (Move [s-s%4] 		(ADDLconst <dst.Type> dst [s%4]) 		(ADDLconst <src.Type> src [s%4]) 		(MOVLstore dst (MOVLload src mem) mem))
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size()%4 != 0) {
+		if !(s > 8 && s%4 != 0) {
 			break
 		}
 		v.reset(OpMove)
-		v.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%4
-		v0 := b.NewValue0(v.Line, Op386ADDLconst, dst.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() % 4
+		v.AuxInt = s - s%4
+		v0 := b.NewValue0(v.Pos, Op386ADDLconst, dst.Type)
+		v0.AuxInt = s % 4
 		v0.AddArg(dst)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386ADDLconst, src.Type)
-		v1.AuxInt = SizeAndAlign(s).Size() % 4
+		v1 := b.NewValue0(v.Pos, Op386ADDLconst, src.Type)
+		v1.AuxInt = s % 4
 		v1.AddArg(src)
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+		v2 := b.NewValue0(v.Pos, Op386MOVLstore, types.TypeMem)
 		v2.AddArg(dst)
-		v3 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
 		v3.AddArg(src)
 		v3.AddArg(mem)
 		v2.AddArg(v3)
@@ -11226,53 +16381,63 @@ func rewriteValue386_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v2)
 		return true
 	}
+	return false
+}
+func rewriteValue386_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() <= 4*128 && SizeAndAlign(s).Size()%4 == 0 	&& !config.noDuffDevice
-	// result: (DUFFCOPY [10*(128-SizeAndAlign(s).Size()/4)] dst src mem)
+	// cond: s > 8 && s <= 4*128 && s%4 == 0 	&& !config.noDuffDevice
+	// result: (DUFFCOPY [10*(128-s/4)] dst src mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() <= 4*128 && SizeAndAlign(s).Size()%4 == 0 && !config.noDuffDevice) {
+		if !(s > 8 && s <= 4*128 && s%4 == 0 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(Op386DUFFCOPY)
-		v.AuxInt = 10 * (128 - SizeAndAlign(s).Size()/4)
+		v.AuxInt = 10 * (128 - s/4)
 		v.AddArg(dst)
 		v.AddArg(src)
 		v.AddArg(mem)
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: (SizeAndAlign(s).Size() > 4*128 || config.noDuffDevice) && SizeAndAlign(s).Size()%4 == 0
-	// result: (REPMOVSL dst src (MOVLconst [SizeAndAlign(s).Size()/4]) mem)
+	// cond: (s > 4*128 || config.noDuffDevice) && s%4 == 0
+	// result: (REPMOVSL dst src (MOVLconst [s/4]) mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !((SizeAndAlign(s).Size() > 4*128 || config.noDuffDevice) && SizeAndAlign(s).Size()%4 == 0) {
+		if !((s > 4*128 || config.noDuffDevice) && s%4 == 0) {
 			break
 		}
 		v.reset(Op386REPMOVSL)
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
-		v0.AuxInt = SizeAndAlign(s).Size() / 4
+		v0 := b.NewValue0(v.Pos, Op386MOVLconst, typ.UInt32)
+		v0.AuxInt = s / 4
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValue386_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul16  x y)
+func rewriteValue386_OpMul16_0(v *Value) bool {
+	// match: (Mul16 x y)
 	// cond:
 	// result: (MULL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULL)
@@ -11281,13 +16446,12 @@ func rewriteValue386_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul32  x y)
+func rewriteValue386_OpMul32_0(v *Value) bool {
+	// match: (Mul32 x y)
 	// cond:
 	// result: (MULL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULL)
@@ -11296,13 +16460,12 @@ func rewriteValue386_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (MULSS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULSS)
@@ -11311,13 +16474,12 @@ func rewriteValue386_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMul32uhilo(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpMul32uhilo_0(v *Value) bool {
 	// match: (Mul32uhilo x y)
 	// cond:
 	// result: (MULLQU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULLQU)
@@ -11326,13 +16488,12 @@ func rewriteValue386_OpMul32uhilo(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (MULSD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULSD)
@@ -11341,13 +16502,12 @@ func rewriteValue386_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul8   x y)
+func rewriteValue386_OpMul8_0(v *Value) bool {
+	// match: (Mul8 x y)
 	// cond:
 	// result: (MULL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386MULL)
@@ -11356,10 +16516,8 @@ func rewriteValue386_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg16  x)
+func rewriteValue386_OpNeg16_0(v *Value) bool {
+	// match: (Neg16 x)
 	// cond:
 	// result: (NEGL x)
 	for {
@@ -11369,10 +16527,8 @@ func rewriteValue386_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg32  x)
+func rewriteValue386_OpNeg32_0(v *Value) bool {
+	// match: (Neg32 x)
 	// cond:
 	// result: (NEGL x)
 	for {
@@ -11382,12 +16538,16 @@ func rewriteValue386_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpNeg32F(v *Value, config *Config) bool {
+func rewriteValue386_OpNeg32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neg32F x)
 	// cond: !config.use387
-	// result: (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
+	// result: (PXOR x (MOVSSconst <typ.Float32> [f2i(math.Copysign(0, -1))]))
 	for {
 		x := v.Args[0]
 		if !(!config.use387) {
@@ -11395,7 +16555,7 @@ func rewriteValue386_OpNeg32F(v *Value, config *Config) bool {
 		}
 		v.reset(Op386PXOR)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386MOVSSconst, config.Frontend().TypeFloat32())
+		v0 := b.NewValue0(v.Pos, Op386MOVSSconst, typ.Float32)
 		v0.AuxInt = f2i(math.Copysign(0, -1))
 		v.AddArg(v0)
 		return true
@@ -11414,12 +16574,16 @@ func rewriteValue386_OpNeg32F(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpNeg64F(v *Value, config *Config) bool {
+func rewriteValue386_OpNeg64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neg64F x)
 	// cond: !config.use387
-	// result: (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
+	// result: (PXOR x (MOVSDconst <typ.Float64> [f2i(math.Copysign(0, -1))]))
 	for {
 		x := v.Args[0]
 		if !(!config.use387) {
@@ -11427,7 +16591,7 @@ func rewriteValue386_OpNeg64F(v *Value, config *Config) bool {
 		}
 		v.reset(Op386PXOR)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386MOVSDconst, config.Frontend().TypeFloat64())
+		v0 := b.NewValue0(v.Pos, Op386MOVSDconst, typ.Float64)
 		v0.AuxInt = f2i(math.Copysign(0, -1))
 		v.AddArg(v0)
 		return true
@@ -11446,10 +16610,8 @@ func rewriteValue386_OpNeg64F(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg8   x)
+func rewriteValue386_OpNeg8_0(v *Value) bool {
+	// match: (Neg8 x)
 	// cond:
 	// result: (NEGL x)
 	for {
@@ -11459,132 +16621,138 @@ func rewriteValue386_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpNeq16(v *Value, config *Config) bool {
+func rewriteValue386_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq16  x y)
+	// match: (Neq16 x y)
 	// cond:
 	// result: (SETNE (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeq32(v *Value, config *Config) bool {
+func rewriteValue386_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq32  x y)
+	// match: (Neq32 x y)
 	// cond:
 	// result: (SETNE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValue386_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (SETNEF (UCOMISS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValue386_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (SETNEF (UCOMISD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNEF)
-		v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386UCOMISD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeq8(v *Value, config *Config) bool {
+func rewriteValue386_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq8   x y)
+	// match: (Neq8 x y)
 	// cond:
 	// result: (SETNE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeqB(v *Value, config *Config) bool {
+func rewriteValue386_OpNeqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (NeqB   x y)
+	// match: (NeqB x y)
 	// cond:
 	// result: (SETNE (CMPB x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPB, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValue386_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (SETNE (CMPL x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SETNE)
-		v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386CMPL, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(Op386LoweredNilCheck)
@@ -11593,9 +16761,7 @@ func rewriteValue386_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORLconst [1] x)
@@ -11607,9 +16773,7 @@ func rewriteValue386_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpOffPtr_0(v *Value) bool {
 	// match: (OffPtr [off] ptr)
 	// cond:
 	// result: (ADDLconst [off] ptr)
@@ -11622,13 +16786,12 @@ func rewriteValue386_OpOffPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (ORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ORL)
@@ -11637,13 +16800,12 @@ func rewriteValue386_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (ORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ORL)
@@ -11652,13 +16814,12 @@ func rewriteValue386_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Or8  x y)
+func rewriteValue386_OpOr8_0(v *Value) bool {
+	// match: (Or8 x y)
 	// cond:
 	// result: (ORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ORL)
@@ -11667,13 +16828,12 @@ func rewriteValue386_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (ORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ORL)
@@ -11682,7 +16842,31 @@ func rewriteValue386_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValue386_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValue386_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValue386_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh16Ux16 <t> x y)
@@ -11690,15 +16874,16 @@ func rewriteValue386_OpRsh16Ux16(v *Value, config *Config) bool {
 	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRW, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 16
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -11706,7 +16891,7 @@ func rewriteValue386_OpRsh16Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh16Ux32 <t> x y)
@@ -11714,15 +16899,16 @@ func rewriteValue386_OpRsh16Ux32(v *Value, config *Config) bool {
 	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRW, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 16
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -11730,13 +16916,12 @@ func rewriteValue386_OpRsh16Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh16Ux64_0(v *Value) bool {
 	// match: (Rsh16Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SHRWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -11755,6 +16940,7 @@ func rewriteValue386_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -11769,23 +16955,24 @@ func rewriteValue386_OpRsh16Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux8  <t> x y)
+	// match: (Rsh16Ux8 <t> x y)
 	// cond:
 	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRW, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 16
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -11793,7 +16980,7 @@ func rewriteValue386_OpRsh16Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh16x16 <t> x y)
@@ -11801,16 +16988,17 @@ func rewriteValue386_OpRsh16x16(v *Value, config *Config) bool {
 	// result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v3.AuxInt = 16
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -11820,7 +17008,7 @@ func rewriteValue386_OpRsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh16x32 <t> x y)
@@ -11828,16 +17016,17 @@ func rewriteValue386_OpRsh16x32(v *Value, config *Config) bool {
 	// result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v3.AuxInt = 16
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -11847,13 +17036,12 @@ func rewriteValue386_OpRsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh16x64_0(v *Value) bool {
 	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SARWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -11872,6 +17060,7 @@ func rewriteValue386_OpRsh16x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (SARWconst x [15])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -11888,24 +17077,25 @@ func rewriteValue386_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x8  <t> x y)
+	// 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
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v3.AuxInt = 16
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -11915,7 +17105,7 @@ func rewriteValue386_OpRsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32Ux16 <t> x y)
@@ -11923,15 +17113,16 @@ func rewriteValue386_OpRsh32Ux16(v *Value, config *Config) bool {
 	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -11939,7 +17130,7 @@ func rewriteValue386_OpRsh32Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32Ux32 <t> x y)
@@ -11947,15 +17138,16 @@ func rewriteValue386_OpRsh32Ux32(v *Value, config *Config) bool {
 	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -11963,13 +17155,12 @@ func rewriteValue386_OpRsh32Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh32Ux64_0(v *Value) bool {
 	// match: (Rsh32Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SHRLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -11988,6 +17179,7 @@ func rewriteValue386_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -12002,23 +17194,24 @@ func rewriteValue386_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32Ux8  <t> x y)
+	// match: (Rsh32Ux8 <t> x y)
 	// cond:
 	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRL, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -12026,7 +17219,7 @@ func rewriteValue386_OpRsh32Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32x16 <t> x y)
@@ -12034,16 +17227,17 @@ func rewriteValue386_OpRsh32x16(v *Value, config *Config) bool {
 	// result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARL)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12053,7 +17247,7 @@ func rewriteValue386_OpRsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32x32 <t> x y)
@@ -12061,16 +17255,17 @@ func rewriteValue386_OpRsh32x32(v *Value, config *Config) bool {
 	// result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARL)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12080,13 +17275,12 @@ func rewriteValue386_OpRsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh32x64_0(v *Value) bool {
 	// match: (Rsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SARLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -12105,6 +17299,7 @@ func rewriteValue386_OpRsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (SARLconst x [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -12121,24 +17316,25 @@ func rewriteValue386_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x8  <t> x y)
+	// 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
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARL)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12148,7 +17344,7 @@ func rewriteValue386_OpRsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh8Ux16 <t> x y)
@@ -12156,15 +17352,16 @@ func rewriteValue386_OpRsh8Ux16(v *Value, config *Config) bool {
 	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRB, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRB, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v2.AuxInt = 8
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -12172,7 +17369,7 @@ func rewriteValue386_OpRsh8Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh8Ux32 <t> x y)
@@ -12180,15 +17377,16 @@ func rewriteValue386_OpRsh8Ux32(v *Value, config *Config) bool {
 	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRB, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRB, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v2.AuxInt = 8
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -12196,13 +17394,12 @@ func rewriteValue386_OpRsh8Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh8Ux64_0(v *Value) bool {
 	// match: (Rsh8Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SHRBconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -12221,6 +17418,7 @@ func rewriteValue386_OpRsh8Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 8
 	// result: (Const8 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -12235,23 +17433,24 @@ func rewriteValue386_OpRsh8Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux8  <t> x y)
+	// match: (Rsh8Ux8 <t> x y)
 	// cond:
 	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386ANDL)
-		v0 := b.NewValue0(v.Line, Op386SHRB, t)
+		v0 := b.NewValue0(v.Pos, Op386SHRB, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v2.AuxInt = 8
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -12259,7 +17458,7 @@ func rewriteValue386_OpRsh8Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh8x16 <t> x y)
@@ -12267,16 +17466,17 @@ func rewriteValue386_OpRsh8x16(v *Value, config *Config) bool {
 	// result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARB)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPWconst, types.TypeFlags)
 		v3.AuxInt = 8
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12286,7 +17486,7 @@ func rewriteValue386_OpRsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh8x32 <t> x y)
@@ -12294,16 +17494,17 @@ func rewriteValue386_OpRsh8x32(v *Value, config *Config) bool {
 	// result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARB)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v3.AuxInt = 8
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12313,13 +17514,12 @@ func rewriteValue386_OpRsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpRsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpRsh8x64_0(v *Value) bool {
 	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SARBconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -12338,6 +17538,7 @@ func rewriteValue386_OpRsh8x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 8
 	// result: (SARBconst x [7])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -12354,24 +17555,25 @@ func rewriteValue386_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValue386_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x8  <t> x y)
+	// 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
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SARB)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, Op386ORL, y.Type)
+		v0 := b.NewValue0(v.Pos, Op386ORL, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, Op386NOTL, y.Type)
-		v2 := b.NewValue0(v.Line, Op386SBBLcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, Op386NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, Op386SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, Op386CMPBconst, types.TypeFlags)
 		v3.AuxInt = 8
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -12381,9 +17583,7 @@ func rewriteValue386_OpRsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVWLSX x)
@@ -12394,10 +17594,8 @@ func rewriteValue386_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to16  x)
+func rewriteValue386_OpSignExt8to16_0(v *Value) bool {
+	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBLSX x)
 	for {
@@ -12407,10 +17605,8 @@ func rewriteValue386_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to32  x)
+func rewriteValue386_OpSignExt8to32_0(v *Value) bool {
+	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBLSX x)
 	for {
@@ -12420,9 +17616,7 @@ func rewriteValue386_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSignmask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSignmask_0(v *Value) bool {
 	// match: (Signmask x)
 	// cond:
 	// result: (SARLconst x [31])
@@ -12434,30 +17628,24 @@ func rewriteValue386_OpSignmask(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValue386_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (XORLconst [-1] (SARLconst <t> (SUBLconst <t> x [1]) [31]))
+	// result: (SARLconst (NEGL <t> x) [31])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(Op386XORLconst)
-		v.AuxInt = -1
-		v0 := b.NewValue0(v.Line, Op386SARLconst, t)
-		v0.AuxInt = 31
-		v1 := b.NewValue0(v.Line, Op386SUBLconst, t)
-		v1.AuxInt = 1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		v.reset(Op386SARLconst)
+		v.AuxInt = 31
+		v0 := b.NewValue0(v.Pos, Op386NEGL, t)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValue386_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (SQRTSD x)
@@ -12468,9 +17656,7 @@ func rewriteValue386_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -12485,20 +17671,17 @@ func rewriteValue386_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+func rewriteValue386_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (MOVSDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(Op386MOVSDstore)
@@ -12507,17 +17690,16 @@ func rewriteValue386_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (MOVSSstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(Op386MOVSSstore)
@@ -12526,48 +17708,54 @@ func rewriteValue386_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4
 	// result: (MOVLstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 4) {
+			break
+		}
 		v.reset(Op386MOVLstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(Op386MOVWstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [1] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(Op386MOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
@@ -12576,13 +17764,12 @@ func rewriteValue386_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub16  x y)
+func rewriteValue386_OpSub16_0(v *Value) bool {
+	// match: (Sub16 x y)
 	// cond:
 	// result: (SUBL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBL)
@@ -12591,13 +17778,12 @@ func rewriteValue386_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub32  x y)
+func rewriteValue386_OpSub32_0(v *Value) bool {
+	// match: (Sub32 x y)
 	// cond:
 	// result: (SUBL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBL)
@@ -12606,13 +17792,12 @@ func rewriteValue386_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (SUBSS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBSS)
@@ -12621,13 +17806,12 @@ func rewriteValue386_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub32carry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSub32carry_0(v *Value) bool {
 	// match: (Sub32carry x y)
 	// cond:
 	// result: (SUBLcarry x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBLcarry)
@@ -12636,13 +17820,12 @@ func rewriteValue386_OpSub32carry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub32withcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSub32withcarry_0(v *Value) bool {
 	// match: (Sub32withcarry x y c)
 	// cond:
 	// result: (SBBL x y c)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
@@ -12653,13 +17836,12 @@ func rewriteValue386_OpSub32withcarry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (SUBSD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBSD)
@@ -12668,13 +17850,12 @@ func rewriteValue386_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub8   x y)
+func rewriteValue386_OpSub8_0(v *Value) bool {
+	// match: (Sub8 x y)
 	// cond:
 	// result: (SUBL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBL)
@@ -12683,13 +17864,12 @@ func rewriteValue386_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUBL  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386SUBL)
@@ -12698,10 +17878,8 @@ func rewriteValue386_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc16to8  x)
+func rewriteValue386_OpTrunc16to8_0(v *Value) bool {
+	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
 	for {
@@ -12712,9 +17890,7 @@ func rewriteValue386_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -12726,10 +17902,8 @@ func rewriteValue386_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc32to8  x)
+func rewriteValue386_OpTrunc32to8_0(v *Value) bool {
+	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
 	for {
@@ -12740,13 +17914,12 @@ func rewriteValue386_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386XORL)
@@ -12755,13 +17928,12 @@ func rewriteValue386_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386XORL)
@@ -12770,13 +17942,12 @@ func rewriteValue386_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Xor8  x y)
+func rewriteValue386_OpXor8_0(v *Value) bool {
+	// match: (Xor8 x y)
 	// cond:
 	// result: (XORL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(Op386XORL)
@@ -12785,145 +17956,147 @@ func rewriteValue386_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpZero(v *Value, config *Config) bool {
+func rewriteValue386_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVBstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] destptr mem)
+	// cond:
 	// result: (MOVWstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVWstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] destptr mem)
+	// cond:
 	// result: (MOVLstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVLstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Zero [3] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [makeValAndOff(0,2)] destptr 		(MOVWstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVBstoreconst)
 		v.AuxInt = makeValAndOff(0, 2)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVWstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVWstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Zero [5] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 5) {
+		if v.AuxInt != 5 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVBstoreconst)
 		v.AuxInt = makeValAndOff(0, 4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Zero [6] destptr mem)
+	// cond:
 	// result: (MOVWstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6) {
+		if v.AuxInt != 6 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVWstoreconst)
 		v.AuxInt = makeValAndOff(0, 4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	// match: (Zero [7] destptr mem)
+	// cond:
 	// result: (MOVLstoreconst [makeValAndOff(0,3)] destptr 		(MOVLstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 7) {
+		if v.AuxInt != 7 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVLstoreconst)
 		v.AuxInt = makeValAndOff(0, 3)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
@@ -12931,65 +18104,75 @@ func rewriteValue386_OpZero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size()%4 != 0 && SizeAndAlign(s).Size() > 4
-	// result: (Zero [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%4] (ADDLconst destptr [SizeAndAlign(s).Size()%4]) 		(MOVLstoreconst [0] destptr mem))
+	// cond: s%4 != 0 && s > 4
+	// result: (Zero [s-s%4] (ADDLconst destptr [s%4]) 		(MOVLstoreconst [0] destptr mem))
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%4 != 0 && SizeAndAlign(s).Size() > 4) {
+		if !(s%4 != 0 && s > 4) {
 			break
 		}
 		v.reset(OpZero)
-		v.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%4
-		v0 := b.NewValue0(v.Line, Op386ADDLconst, config.fe.TypeUInt32())
-		v0.AuxInt = SizeAndAlign(s).Size() % 4
+		v.AuxInt = s - s%4
+		v0 := b.NewValue0(v.Pos, Op386ADDLconst, typ.UInt32)
+		v0.AuxInt = s % 4
 		v0.AddArg(destptr)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(destptr)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Zero [8] destptr mem)
+	// cond:
 	// result: (MOVLstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8) {
+		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVLstoreconst)
 		v.AuxInt = makeValAndOff(0, 4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 12
+	return false
+}
+func rewriteValue386_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [12] destptr mem)
+	// cond:
 	// result: (MOVLstoreconst [makeValAndOff(0,8)] destptr 		(MOVLstoreconst [makeValAndOff(0,4)] destptr 			(MOVLstoreconst [0] destptr mem)))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 12) {
+		if v.AuxInt != 12 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVLstoreconst)
 		v.AuxInt = makeValAndOff(0, 8)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = makeValAndOff(0, 4)
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(destptr)
 		v1.AddArg(mem)
@@ -12997,26 +18180,26 @@ func rewriteValue386_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 16
+	// match: (Zero [16] destptr mem)
+	// cond:
 	// result: (MOVLstoreconst [makeValAndOff(0,12)] destptr 		(MOVLstoreconst [makeValAndOff(0,8)] destptr 			(MOVLstoreconst [makeValAndOff(0,4)] destptr 				(MOVLstoreconst [0] destptr mem))))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16) {
+		if v.AuxInt != 16 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(Op386MOVLstoreconst)
 		v.AuxInt = makeValAndOff(0, 12)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v0.AuxInt = makeValAndOff(0, 8)
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v1 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v1.AuxInt = makeValAndOff(0, 4)
 		v1.AddArg(destptr)
-		v2 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+		v2 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem)
 		v2.AuxInt = 0
 		v2.AddArg(destptr)
 		v2.AddArg(mem)
@@ -13026,40 +18209,42 @@ func rewriteValue386_OpZero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() > 16   && SizeAndAlign(s).Size() <= 4*128   && SizeAndAlign(s).Size()%4 == 0   && !config.noDuffDevice
-	// result: (DUFFZERO [1*(128-SizeAndAlign(s).Size()/4)] destptr (MOVLconst [0]) mem)
+	// cond: s > 16 && s <= 4*128 && s%4 == 0   && !config.noDuffDevice
+	// result: (DUFFZERO [1*(128-s/4)] destptr (MOVLconst [0]) mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size() <= 4*128 && SizeAndAlign(s).Size()%4 == 0 && !config.noDuffDevice) {
+		if !(s > 16 && s <= 4*128 && s%4 == 0 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(Op386DUFFZERO)
-		v.AuxInt = 1 * (128 - SizeAndAlign(s).Size()/4)
+		v.AuxInt = 1 * (128 - s/4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, Op386MOVLconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
 	// match: (Zero [s] destptr mem)
-	// cond: (SizeAndAlign(s).Size() > 4*128 || (config.noDuffDevice && SizeAndAlign(s).Size() > 16))   && SizeAndAlign(s).Size()%4 == 0
-	// result: (REPSTOSL destptr (MOVLconst [SizeAndAlign(s).Size()/4]) (MOVLconst [0]) mem)
+	// cond: (s > 4*128 || (config.noDuffDevice && s > 16))   && s%4 == 0
+	// result: (REPSTOSL destptr (MOVLconst [s/4]) (MOVLconst [0]) mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !((SizeAndAlign(s).Size() > 4*128 || (config.noDuffDevice && SizeAndAlign(s).Size() > 16)) && SizeAndAlign(s).Size()%4 == 0) {
+		if !((s > 4*128 || (config.noDuffDevice && s > 16)) && s%4 == 0) {
 			break
 		}
 		v.reset(Op386REPSTOSL)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
-		v0.AuxInt = SizeAndAlign(s).Size() / 4
+		v0 := b.NewValue0(v.Pos, Op386MOVLconst, typ.UInt32)
+		v0.AuxInt = s / 4
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, Op386MOVLconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		v.AddArg(mem)
@@ -13067,9 +18252,7 @@ func rewriteValue386_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValue386_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValue386_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVWLZX x)
@@ -13080,10 +18263,8 @@ func rewriteValue386_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to16  x)
+func rewriteValue386_OpZeroExt8to16_0(v *Value) bool {
+	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBLZX x)
 	for {
@@ -13093,10 +18274,8 @@ func rewriteValue386_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to32  x)
+func rewriteValue386_OpZeroExt8to32_0(v *Value) bool {
+	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBLZX x)
 	for {
@@ -13106,7 +18285,7 @@ func rewriteValue386_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValue386_OpZeromask(v *Value, config *Config) bool {
+func rewriteValue386_OpZeromask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Zeromask <t> x)
@@ -13117,8 +18296,8 @@ func rewriteValue386_OpZeromask(v *Value, config *Config) bool {
 		x := v.Args[0]
 		v.reset(Op386XORLconst)
 		v.AuxInt = -1
-		v0 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
-		v1 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, Op386SBBLcarrymask, t)
+		v1 := b.NewValue0(v.Pos, Op386CMPLconst, types.TypeFlags)
 		v1.AuxInt = 1
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -13126,7 +18305,13 @@ func rewriteValue386_OpZeromask(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlock386(b *Block, config *Config) bool {
+func rewriteBlock386(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case Block386EQ:
 		// match: (EQ (InvertFlags cmp) yes no)
@@ -13138,12 +18323,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagEQ) yes no)
@@ -13154,12 +18335,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -13170,13 +18347,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13187,13 +18360,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13204,13 +18373,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -13221,13 +18386,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case Block386GE:
@@ -13240,12 +18401,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (FlagEQ) yes no)
@@ -13256,12 +18413,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -13272,13 +18425,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13289,13 +18438,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13306,12 +18451,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -13322,12 +18463,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case Block386GT:
@@ -13340,12 +18477,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GT (FlagEQ) yes no)
@@ -13356,13 +18489,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -13373,13 +18502,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13390,13 +18515,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -13407,12 +18528,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -13423,16 +18540,12 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
+		// match: (If (SETL cmp) yes no)
 		// cond:
 		// result: (LT  cmp yes no)
 		for {
@@ -13441,12 +18554,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (SETLE cmp) yes no)
@@ -13458,15 +18567,11 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETG  cmp) yes no)
+		// match: (If (SETG cmp) yes no)
 		// cond:
 		// result: (GT  cmp yes no)
 		for {
@@ -13475,12 +18580,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (SETGE cmp) yes no)
@@ -13492,12 +18593,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386GE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (SETEQ cmp) yes no)
@@ -13509,12 +18606,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (SETNE cmp) yes no)
@@ -13525,705 +18618,906 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386SETNE {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386NE
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			cmp := v.Args[0]
+			b.Kind = Block386NE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETB cmp) yes no)
+		// cond:
+		// result: (ULT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETB {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386ULT
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETBE cmp) yes no)
+		// cond:
+		// result: (ULE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETBE {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386ULE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETA cmp) yes no)
+		// cond:
+		// result: (UGT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETA {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386UGT
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETAE cmp) yes no)
+		// cond:
+		// result: (UGE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETAE {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386UGE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETGF cmp) yes no)
+		// cond:
+		// result: (UGT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETGF {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386UGT
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETGEF cmp) yes no)
+		// cond:
+		// result: (UGE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETGEF {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386UGE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETEQF cmp) yes no)
+		// cond:
+		// result: (EQF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETEQF {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386EQF
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETNEF cmp) yes no)
+		// cond:
+		// result: (NEF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386SETNEF {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386NEF
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If cond yes no)
+		// cond:
+		// result: (NE (TESTB cond cond) yes no)
+		for {
+			v := b.Control
+			_ = v
+			cond := b.Control
+			b.Kind = Block386NE
+			v0 := b.NewValue0(v.Pos, Op386TESTB, types.TypeFlags)
+			v0.AddArg(cond)
+			v0.AddArg(cond)
+			b.SetControl(v0)
+			return true
+		}
+	case Block386LE:
+		// match: (LE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (GE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			b.Kind = Block386GE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (LE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386FlagEQ {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (LE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386FlagLT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (LE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386FlagLT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (LE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != Op386FlagGT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
 			return true
 		}
-		// match: (If (SETB  cmp) yes no)
+		// match: (LE (FlagGT_UGT) yes no)
 		// cond:
-		// result: (ULT cmp yes no)
+		// result: (First nil no yes)
 		for {
 			v := b.Control
-			if v.Op != Op386SETB {
+			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386ULT
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
 			return true
 		}
-		// match: (If (SETBE cmp) yes no)
+	case Block386LT:
+		// match: (LT (InvertFlags cmp) yes no)
 		// cond:
-		// result: (ULE cmp yes no)
+		// result: (GT cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386SETBE {
+			if v.Op != Op386InvertFlags {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386ULE
+			b.Kind = Block386GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETA  cmp) yes no)
+		// match: (LT (FlagEQ) yes no)
 		// cond:
-		// result: (UGT cmp yes no)
+		// result: (First nil no yes)
 		for {
 			v := b.Control
-			if v.Op != Op386SETA {
+			if v.Op != Op386FlagEQ {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGT
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
 			return true
 		}
-		// match: (If (SETAE cmp) yes no)
+		// match: (LT (FlagLT_ULT) yes no)
 		// cond:
-		// result: (UGE cmp yes no)
+		// result: (First nil yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386SETAE {
+			if v.Op != Op386FlagLT_ULT {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGE
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
 			return true
 		}
-		// match: (If (SETGF  cmp) yes no)
+		// match: (LT (FlagLT_UGT) yes no)
 		// cond:
-		// result: (UGT  cmp yes no)
+		// result: (First nil yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386SETGF {
+			if v.Op != Op386FlagLT_UGT {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGT
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
 			return true
 		}
-		// match: (If (SETGEF cmp) yes no)
+		// match: (LT (FlagGT_ULT) yes no)
 		// cond:
-		// result: (UGE  cmp yes no)
+		// result: (First nil no yes)
 		for {
 			v := b.Control
-			if v.Op != Op386SETGEF {
+			if v.Op != Op386FlagGT_ULT {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGE
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
 			return true
 		}
-		// match: (If (SETEQF cmp) yes no)
+		// match: (LT (FlagGT_UGT) yes no)
 		// cond:
-		// result: (EQF  cmp yes no)
+		// result: (First nil no yes)
 		for {
 			v := b.Control
-			if v.Op != Op386SETEQF {
+			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386EQF
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
 			return true
 		}
-		// match: (If (SETNEF cmp) yes no)
+	case Block386NE:
+		// match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
 		// cond:
-		// result: (NEF  cmp yes no)
+		// result: (LT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386SETNEF {
+			if v.Op != Op386TESTB {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386NEF
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETL {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETL {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If cond yes no)
+		// match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
 		// cond:
-		// result: (NE (TESTB cond cond) yes no)
+		// result: (LT  cmp yes no)
 		for {
 			v := b.Control
-			_ = v
-			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386NE
-			v0 := b.NewValue0(v.Line, Op386TESTB, TypeFlags)
-			v0.AddArg(cond)
-			v0.AddArg(cond)
-			b.SetControl(v0)
-			_ = yes
-			_ = no
+			if v.Op != Op386TESTB {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETL {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETL {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386LT
+			b.SetControl(cmp)
 			return true
 		}
-	case Block386LE:
-		// match: (LE (InvertFlags cmp) yes no)
+		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
 		// cond:
-		// result: (GE cmp yes no)
+		// result: (LE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386InvertFlags {
+			if v.Op != Op386TESTB {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386GE
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETLE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETLE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (LE (FlagEQ) yes no)
+		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (LE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagEQ {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETLE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETLE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386LE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LE (FlagLT_ULT) yes no)
+		// match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (GT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagLT_ULT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETG {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETG {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386GT
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LE (FlagLT_UGT) yes no)
+		// match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (GT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagLT_UGT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETG {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETG {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386GT
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LE (FlagGT_ULT) yes no)
+		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (GE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagGT_ULT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETGE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETGE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386GE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LE (FlagGT_UGT) yes no)
+		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (GE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagGT_UGT {
+			if v.Op != Op386TESTB {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETGE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETGE {
+				break
+			}
+			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			b.Kind = Block386GE
+			b.SetControl(cmp)
 			return true
 		}
-	case Block386LT:
-		// match: (LT (InvertFlags cmp) yes no)
+		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
 		// cond:
-		// result: (GT cmp yes no)
+		// result: (EQ  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386InvertFlags {
+			if v.Op != Op386TESTB {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386GT
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETEQ {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETEQ {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (LT (FlagEQ) yes no)
+		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (EQ  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagEQ {
+			if v.Op != Op386TESTB {
 				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 != Op386FlagLT_ULT {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETEQ {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386EQ
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagLT_UGT) yes no)
+		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (NE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagLT_UGT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETNE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETNE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386NE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagGT_ULT) yes no)
+		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (NE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagGT_ULT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETNE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETNE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386NE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagGT_UGT) yes no)
+		// match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (ULT cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != Op386FlagGT_UGT {
+			if v.Op != Op386TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETB {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETB {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386ULT
+			b.SetControl(cmp)
 			return true
 		}
-	case Block386NE:
-		// match: (NE (TESTB (SETL  cmp) (SETL  cmp)) yes no)
+		// match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
 		// cond:
-		// result: (LT  cmp yes no)
+		// result: (ULT cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETL {
+			if v_0.Op != Op386SETB {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETL {
+			if v_1.Op != Op386SETB {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386LT
+			b.Kind = Block386ULT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
+		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
 		// cond:
-		// result: (LE  cmp yes no)
+		// result: (ULE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETLE {
+			if v_0.Op != Op386SETBE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETLE {
+			if v_1.Op != Op386SETBE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386LE
+			b.Kind = Block386ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETG  cmp) (SETG  cmp)) yes no)
+		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
 		// cond:
-		// result: (GT  cmp yes no)
+		// result: (ULE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETG {
+			if v_0.Op != Op386SETBE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETG {
+			if v_1.Op != Op386SETBE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386GT
+			b.Kind = Block386ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
+		// match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
 		// cond:
-		// result: (GE  cmp yes no)
+		// result: (UGT cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETGE {
+			if v_0.Op != Op386SETA {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETGE {
+			if v_1.Op != Op386SETA {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386GE
+			b.Kind = Block386UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
+		// match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
 		// cond:
-		// result: (EQ  cmp yes no)
+		// result: (UGT cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETEQ {
+			if v_0.Op != Op386SETA {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETEQ {
+			if v_1.Op != Op386SETA {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386EQ
+			b.Kind = Block386UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
+		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
 		// cond:
-		// result: (NE  cmp yes no)
+		// result: (UGE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETNE {
+			if v_0.Op != Op386SETAE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETNE {
+			if v_1.Op != Op386SETAE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386NE
+			b.Kind = Block386UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETB  cmp) (SETB  cmp)) yes no)
+		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
 		// cond:
-		// result: (ULT cmp yes no)
+		// result: (UGE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETB {
+			if v_0.Op != Op386SETAE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETB {
+			if v_1.Op != Op386SETAE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386ULT
+			b.Kind = Block386UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
+		// match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
 		// cond:
-		// result: (ULE cmp yes no)
+		// result: (UGT  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETBE {
+			if v_0.Op != Op386SETGF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETBE {
+			if v_1.Op != Op386SETGF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386ULE
+			b.Kind = Block386UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETA  cmp) (SETA  cmp)) yes no)
+		// match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
 		// cond:
-		// result: (UGT cmp yes no)
+		// result: (UGT  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETA {
+			if v_0.Op != Op386SETGF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETA {
+			if v_1.Op != Op386SETGF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
+		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
 		// cond:
-		// result: (UGE cmp yes no)
+		// result: (UGE  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETAE {
+			if v_0.Op != Op386SETGEF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETAE {
+			if v_1.Op != Op386SETGEF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETGF  cmp) (SETGF  cmp)) yes no)
+		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
 		// cond:
-		// result: (UGT  cmp yes no)
+		// result: (UGE  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETGF {
+			if v_0.Op != Op386SETGEF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETGF {
+			if v_1.Op != Op386SETGEF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGT
+			b.Kind = Block386UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
+		// match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
 		// cond:
-		// result: (UGE  cmp yes no)
+		// result: (EQF  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != Op386SETGEF {
+			if v_0.Op != Op386SETEQF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != Op386SETGEF {
+			if v_1.Op != Op386SETEQF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = Block386UGE
+			b.Kind = Block386EQF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
@@ -14234,6 +19528,7 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
 			if v_0.Op != Op386SETEQF {
 				break
@@ -14246,12 +19541,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386EQF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no)
@@ -14262,6 +19553,32 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386TESTB {
 				break
 			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != Op386SETNEF {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != Op386SETNEF {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = Block386NEF
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no)
+		// cond:
+		// result: (NEF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != Op386TESTB {
+				break
+			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
 			if v_0.Op != Op386SETNEF {
 				break
@@ -14274,12 +19591,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386NEF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (InvertFlags cmp) yes no)
@@ -14291,12 +19604,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagEQ) yes no)
@@ -14307,13 +19616,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -14324,12 +19629,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14340,12 +19641,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14356,12 +19653,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -14372,12 +19665,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case Block386UGE:
@@ -14390,12 +19679,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGE (FlagEQ) yes no)
@@ -14406,12 +19691,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -14422,13 +19703,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14439,12 +19716,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14455,13 +19728,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -14472,12 +19741,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case Block386UGT:
@@ -14490,12 +19755,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386ULT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGT (FlagEQ) yes no)
@@ -14506,13 +19767,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -14523,13 +19780,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14540,12 +19793,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14556,13 +19805,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -14573,12 +19818,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case Block386ULE:
@@ -14591,12 +19832,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (ULE (FlagEQ) yes no)
@@ -14607,12 +19844,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -14623,12 +19856,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14639,13 +19868,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14656,12 +19881,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -14672,13 +19893,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case Block386ULT:
@@ -14691,12 +19908,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = Block386UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (ULT (FlagEQ) yes no)
@@ -14707,13 +19920,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagEQ {
 				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)
@@ -14724,12 +19933,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14740,13 +19945,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagLT_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)
@@ -14757,12 +19958,8 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_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)
@@ -14773,13 +19970,9 @@ func rewriteBlock386(b *Block, config *Config) bool {
 			if v.Op != Op386FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 1257ec6..641dc11 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -1,813 +1,869 @@
-// autogenerated from gen/AMD64.rules: do not edit!
+// Code generated from gen/AMD64.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueAMD64(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueAMD64(v *Value) bool {
 	switch v.Op {
 	case OpAMD64ADDL:
-		return rewriteValueAMD64_OpAMD64ADDL(v, config)
+		return rewriteValueAMD64_OpAMD64ADDL_0(v) || rewriteValueAMD64_OpAMD64ADDL_10(v)
 	case OpAMD64ADDLconst:
-		return rewriteValueAMD64_OpAMD64ADDLconst(v, config)
+		return rewriteValueAMD64_OpAMD64ADDLconst_0(v)
 	case OpAMD64ADDQ:
-		return rewriteValueAMD64_OpAMD64ADDQ(v, config)
+		return rewriteValueAMD64_OpAMD64ADDQ_0(v) || rewriteValueAMD64_OpAMD64ADDQ_10(v) || rewriteValueAMD64_OpAMD64ADDQ_20(v)
 	case OpAMD64ADDQconst:
-		return rewriteValueAMD64_OpAMD64ADDQconst(v, config)
+		return rewriteValueAMD64_OpAMD64ADDQconst_0(v)
+	case OpAMD64ADDSD:
+		return rewriteValueAMD64_OpAMD64ADDSD_0(v)
+	case OpAMD64ADDSS:
+		return rewriteValueAMD64_OpAMD64ADDSS_0(v)
 	case OpAMD64ANDL:
-		return rewriteValueAMD64_OpAMD64ANDL(v, config)
+		return rewriteValueAMD64_OpAMD64ANDL_0(v)
 	case OpAMD64ANDLconst:
-		return rewriteValueAMD64_OpAMD64ANDLconst(v, config)
+		return rewriteValueAMD64_OpAMD64ANDLconst_0(v)
 	case OpAMD64ANDQ:
-		return rewriteValueAMD64_OpAMD64ANDQ(v, config)
+		return rewriteValueAMD64_OpAMD64ANDQ_0(v)
 	case OpAMD64ANDQconst:
-		return rewriteValueAMD64_OpAMD64ANDQconst(v, config)
+		return rewriteValueAMD64_OpAMD64ANDQconst_0(v)
+	case OpAMD64BSFQ:
+		return rewriteValueAMD64_OpAMD64BSFQ_0(v)
+	case OpAMD64BTQconst:
+		return rewriteValueAMD64_OpAMD64BTQconst_0(v)
+	case OpAMD64CMOVQEQ:
+		return rewriteValueAMD64_OpAMD64CMOVQEQ_0(v)
 	case OpAMD64CMPB:
-		return rewriteValueAMD64_OpAMD64CMPB(v, config)
+		return rewriteValueAMD64_OpAMD64CMPB_0(v)
 	case OpAMD64CMPBconst:
-		return rewriteValueAMD64_OpAMD64CMPBconst(v, config)
+		return rewriteValueAMD64_OpAMD64CMPBconst_0(v)
 	case OpAMD64CMPL:
-		return rewriteValueAMD64_OpAMD64CMPL(v, config)
+		return rewriteValueAMD64_OpAMD64CMPL_0(v)
 	case OpAMD64CMPLconst:
-		return rewriteValueAMD64_OpAMD64CMPLconst(v, config)
+		return rewriteValueAMD64_OpAMD64CMPLconst_0(v)
 	case OpAMD64CMPQ:
-		return rewriteValueAMD64_OpAMD64CMPQ(v, config)
+		return rewriteValueAMD64_OpAMD64CMPQ_0(v)
 	case OpAMD64CMPQconst:
-		return rewriteValueAMD64_OpAMD64CMPQconst(v, config)
+		return rewriteValueAMD64_OpAMD64CMPQconst_0(v) || rewriteValueAMD64_OpAMD64CMPQconst_10(v)
 	case OpAMD64CMPW:
-		return rewriteValueAMD64_OpAMD64CMPW(v, config)
+		return rewriteValueAMD64_OpAMD64CMPW_0(v)
 	case OpAMD64CMPWconst:
-		return rewriteValueAMD64_OpAMD64CMPWconst(v, config)
+		return rewriteValueAMD64_OpAMD64CMPWconst_0(v)
 	case OpAMD64CMPXCHGLlock:
-		return rewriteValueAMD64_OpAMD64CMPXCHGLlock(v, config)
+		return rewriteValueAMD64_OpAMD64CMPXCHGLlock_0(v)
 	case OpAMD64CMPXCHGQlock:
-		return rewriteValueAMD64_OpAMD64CMPXCHGQlock(v, config)
+		return rewriteValueAMD64_OpAMD64CMPXCHGQlock_0(v)
 	case OpAMD64LEAL:
-		return rewriteValueAMD64_OpAMD64LEAL(v, config)
+		return rewriteValueAMD64_OpAMD64LEAL_0(v)
 	case OpAMD64LEAQ:
-		return rewriteValueAMD64_OpAMD64LEAQ(v, config)
+		return rewriteValueAMD64_OpAMD64LEAQ_0(v)
 	case OpAMD64LEAQ1:
-		return rewriteValueAMD64_OpAMD64LEAQ1(v, config)
+		return rewriteValueAMD64_OpAMD64LEAQ1_0(v)
 	case OpAMD64LEAQ2:
-		return rewriteValueAMD64_OpAMD64LEAQ2(v, config)
+		return rewriteValueAMD64_OpAMD64LEAQ2_0(v)
 	case OpAMD64LEAQ4:
-		return rewriteValueAMD64_OpAMD64LEAQ4(v, config)
+		return rewriteValueAMD64_OpAMD64LEAQ4_0(v)
 	case OpAMD64LEAQ8:
-		return rewriteValueAMD64_OpAMD64LEAQ8(v, config)
+		return rewriteValueAMD64_OpAMD64LEAQ8_0(v)
 	case OpAMD64MOVBQSX:
-		return rewriteValueAMD64_OpAMD64MOVBQSX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBQSX_0(v)
 	case OpAMD64MOVBQSXload:
-		return rewriteValueAMD64_OpAMD64MOVBQSXload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBQSXload_0(v)
 	case OpAMD64MOVBQZX:
-		return rewriteValueAMD64_OpAMD64MOVBQZX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBQZX_0(v)
 	case OpAMD64MOVBload:
-		return rewriteValueAMD64_OpAMD64MOVBload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBload_0(v)
 	case OpAMD64MOVBloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVBloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBloadidx1_0(v)
 	case OpAMD64MOVBstore:
-		return rewriteValueAMD64_OpAMD64MOVBstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBstore_0(v) || rewriteValueAMD64_OpAMD64MOVBstore_10(v)
 	case OpAMD64MOVBstoreconst:
-		return rewriteValueAMD64_OpAMD64MOVBstoreconst(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBstoreconst_0(v)
 	case OpAMD64MOVBstoreconstidx1:
-		return rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBstoreconstidx1_0(v)
 	case OpAMD64MOVBstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVBstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVBstoreidx1_0(v)
 	case OpAMD64MOVLQSX:
-		return rewriteValueAMD64_OpAMD64MOVLQSX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLQSX_0(v)
 	case OpAMD64MOVLQSXload:
-		return rewriteValueAMD64_OpAMD64MOVLQSXload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLQSXload_0(v)
 	case OpAMD64MOVLQZX:
-		return rewriteValueAMD64_OpAMD64MOVLQZX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLQZX_0(v)
 	case OpAMD64MOVLatomicload:
-		return rewriteValueAMD64_OpAMD64MOVLatomicload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLatomicload_0(v)
 	case OpAMD64MOVLload:
-		return rewriteValueAMD64_OpAMD64MOVLload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLload_0(v)
 	case OpAMD64MOVLloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVLloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLloadidx1_0(v)
 	case OpAMD64MOVLloadidx4:
-		return rewriteValueAMD64_OpAMD64MOVLloadidx4(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLloadidx4_0(v)
 	case OpAMD64MOVLstore:
-		return rewriteValueAMD64_OpAMD64MOVLstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstore_0(v) || rewriteValueAMD64_OpAMD64MOVLstore_10(v)
 	case OpAMD64MOVLstoreconst:
-		return rewriteValueAMD64_OpAMD64MOVLstoreconst(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstoreconst_0(v)
 	case OpAMD64MOVLstoreconstidx1:
-		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx1_0(v)
 	case OpAMD64MOVLstoreconstidx4:
-		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx4_0(v)
 	case OpAMD64MOVLstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVLstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstoreidx1_0(v)
 	case OpAMD64MOVLstoreidx4:
-		return rewriteValueAMD64_OpAMD64MOVLstoreidx4(v, config)
+		return rewriteValueAMD64_OpAMD64MOVLstoreidx4_0(v)
 	case OpAMD64MOVOload:
-		return rewriteValueAMD64_OpAMD64MOVOload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVOload_0(v)
 	case OpAMD64MOVOstore:
-		return rewriteValueAMD64_OpAMD64MOVOstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVOstore_0(v)
 	case OpAMD64MOVQatomicload:
-		return rewriteValueAMD64_OpAMD64MOVQatomicload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQatomicload_0(v)
 	case OpAMD64MOVQload:
-		return rewriteValueAMD64_OpAMD64MOVQload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQload_0(v)
 	case OpAMD64MOVQloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVQloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQloadidx1_0(v)
 	case OpAMD64MOVQloadidx8:
-		return rewriteValueAMD64_OpAMD64MOVQloadidx8(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQloadidx8_0(v)
 	case OpAMD64MOVQstore:
-		return rewriteValueAMD64_OpAMD64MOVQstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstore_0(v)
 	case OpAMD64MOVQstoreconst:
-		return rewriteValueAMD64_OpAMD64MOVQstoreconst(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstoreconst_0(v)
 	case OpAMD64MOVQstoreconstidx1:
-		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx1_0(v)
 	case OpAMD64MOVQstoreconstidx8:
-		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx8_0(v)
 	case OpAMD64MOVQstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVQstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstoreidx1_0(v)
 	case OpAMD64MOVQstoreidx8:
-		return rewriteValueAMD64_OpAMD64MOVQstoreidx8(v, config)
+		return rewriteValueAMD64_OpAMD64MOVQstoreidx8_0(v)
 	case OpAMD64MOVSDload:
-		return rewriteValueAMD64_OpAMD64MOVSDload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDload_0(v)
 	case OpAMD64MOVSDloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVSDloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDloadidx1_0(v)
 	case OpAMD64MOVSDloadidx8:
-		return rewriteValueAMD64_OpAMD64MOVSDloadidx8(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDloadidx8_0(v)
 	case OpAMD64MOVSDstore:
-		return rewriteValueAMD64_OpAMD64MOVSDstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDstore_0(v)
 	case OpAMD64MOVSDstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDstoreidx1_0(v)
 	case OpAMD64MOVSDstoreidx8:
-		return rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSDstoreidx8_0(v)
 	case OpAMD64MOVSSload:
-		return rewriteValueAMD64_OpAMD64MOVSSload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSload_0(v)
 	case OpAMD64MOVSSloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVSSloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSloadidx1_0(v)
 	case OpAMD64MOVSSloadidx4:
-		return rewriteValueAMD64_OpAMD64MOVSSloadidx4(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSloadidx4_0(v)
 	case OpAMD64MOVSSstore:
-		return rewriteValueAMD64_OpAMD64MOVSSstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSstore_0(v)
 	case OpAMD64MOVSSstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSstoreidx1_0(v)
 	case OpAMD64MOVSSstoreidx4:
-		return rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v, config)
+		return rewriteValueAMD64_OpAMD64MOVSSstoreidx4_0(v)
 	case OpAMD64MOVWQSX:
-		return rewriteValueAMD64_OpAMD64MOVWQSX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWQSX_0(v)
 	case OpAMD64MOVWQSXload:
-		return rewriteValueAMD64_OpAMD64MOVWQSXload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWQSXload_0(v)
 	case OpAMD64MOVWQZX:
-		return rewriteValueAMD64_OpAMD64MOVWQZX(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWQZX_0(v)
 	case OpAMD64MOVWload:
-		return rewriteValueAMD64_OpAMD64MOVWload(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWload_0(v)
 	case OpAMD64MOVWloadidx1:
-		return rewriteValueAMD64_OpAMD64MOVWloadidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWloadidx1_0(v)
 	case OpAMD64MOVWloadidx2:
-		return rewriteValueAMD64_OpAMD64MOVWloadidx2(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWloadidx2_0(v)
 	case OpAMD64MOVWstore:
-		return rewriteValueAMD64_OpAMD64MOVWstore(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstore_0(v) || rewriteValueAMD64_OpAMD64MOVWstore_10(v)
 	case OpAMD64MOVWstoreconst:
-		return rewriteValueAMD64_OpAMD64MOVWstoreconst(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstoreconst_0(v)
 	case OpAMD64MOVWstoreconstidx1:
-		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx1_0(v)
 	case OpAMD64MOVWstoreconstidx2:
-		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx2_0(v)
 	case OpAMD64MOVWstoreidx1:
-		return rewriteValueAMD64_OpAMD64MOVWstoreidx1(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstoreidx1_0(v)
 	case OpAMD64MOVWstoreidx2:
-		return rewriteValueAMD64_OpAMD64MOVWstoreidx2(v, config)
+		return rewriteValueAMD64_OpAMD64MOVWstoreidx2_0(v)
 	case OpAMD64MULL:
-		return rewriteValueAMD64_OpAMD64MULL(v, config)
+		return rewriteValueAMD64_OpAMD64MULL_0(v)
 	case OpAMD64MULLconst:
-		return rewriteValueAMD64_OpAMD64MULLconst(v, config)
+		return rewriteValueAMD64_OpAMD64MULLconst_0(v)
 	case OpAMD64MULQ:
-		return rewriteValueAMD64_OpAMD64MULQ(v, config)
+		return rewriteValueAMD64_OpAMD64MULQ_0(v)
 	case OpAMD64MULQconst:
-		return rewriteValueAMD64_OpAMD64MULQconst(v, config)
+		return rewriteValueAMD64_OpAMD64MULQconst_0(v) || rewriteValueAMD64_OpAMD64MULQconst_10(v) || rewriteValueAMD64_OpAMD64MULQconst_20(v)
+	case OpAMD64MULSD:
+		return rewriteValueAMD64_OpAMD64MULSD_0(v)
+	case OpAMD64MULSS:
+		return rewriteValueAMD64_OpAMD64MULSS_0(v)
 	case OpAMD64NEGL:
-		return rewriteValueAMD64_OpAMD64NEGL(v, config)
+		return rewriteValueAMD64_OpAMD64NEGL_0(v)
 	case OpAMD64NEGQ:
-		return rewriteValueAMD64_OpAMD64NEGQ(v, config)
+		return rewriteValueAMD64_OpAMD64NEGQ_0(v)
 	case OpAMD64NOTL:
-		return rewriteValueAMD64_OpAMD64NOTL(v, config)
+		return rewriteValueAMD64_OpAMD64NOTL_0(v)
 	case OpAMD64NOTQ:
-		return rewriteValueAMD64_OpAMD64NOTQ(v, config)
+		return rewriteValueAMD64_OpAMD64NOTQ_0(v)
 	case OpAMD64ORL:
-		return rewriteValueAMD64_OpAMD64ORL(v, config)
+		return rewriteValueAMD64_OpAMD64ORL_0(v) || rewriteValueAMD64_OpAMD64ORL_10(v) || rewriteValueAMD64_OpAMD64ORL_20(v) || rewriteValueAMD64_OpAMD64ORL_30(v) || rewriteValueAMD64_OpAMD64ORL_40(v) || rewriteValueAMD64_OpAMD64ORL_50(v) || rewriteValueAMD64_OpAMD64ORL_60(v) || rewriteValueAMD64_OpAMD64ORL_70(v) || rewriteValueAMD64_OpAMD64ORL_80(v) || rewriteValueAMD64_OpAMD64ORL_90(v) || rewriteValueAMD64_OpAMD64ORL_100(v) || rewriteValueAMD64_OpAMD64ORL_110(v) || rewriteValueAMD64_OpAMD64O [...]
 	case OpAMD64ORLconst:
-		return rewriteValueAMD64_OpAMD64ORLconst(v, config)
+		return rewriteValueAMD64_OpAMD64ORLconst_0(v)
 	case OpAMD64ORQ:
-		return rewriteValueAMD64_OpAMD64ORQ(v, config)
+		return rewriteValueAMD64_OpAMD64ORQ_0(v) || rewriteValueAMD64_OpAMD64ORQ_10(v) || rewriteValueAMD64_OpAMD64ORQ_20(v) || rewriteValueAMD64_OpAMD64ORQ_30(v) || rewriteValueAMD64_OpAMD64ORQ_40(v) || rewriteValueAMD64_OpAMD64ORQ_50(v) || rewriteValueAMD64_OpAMD64ORQ_60(v) || rewriteValueAMD64_OpAMD64ORQ_70(v) || rewriteValueAMD64_OpAMD64ORQ_80(v) || rewriteValueAMD64_OpAMD64ORQ_90(v) || rewriteValueAMD64_OpAMD64ORQ_100(v) || rewriteValueAMD64_OpAMD64ORQ_110(v) || rewriteValueAMD64_OpAMD64O [...]
 	case OpAMD64ORQconst:
-		return rewriteValueAMD64_OpAMD64ORQconst(v, config)
+		return rewriteValueAMD64_OpAMD64ORQconst_0(v)
+	case OpAMD64ROLB:
+		return rewriteValueAMD64_OpAMD64ROLB_0(v)
 	case OpAMD64ROLBconst:
-		return rewriteValueAMD64_OpAMD64ROLBconst(v, config)
+		return rewriteValueAMD64_OpAMD64ROLBconst_0(v)
+	case OpAMD64ROLL:
+		return rewriteValueAMD64_OpAMD64ROLL_0(v)
 	case OpAMD64ROLLconst:
-		return rewriteValueAMD64_OpAMD64ROLLconst(v, config)
+		return rewriteValueAMD64_OpAMD64ROLLconst_0(v)
+	case OpAMD64ROLQ:
+		return rewriteValueAMD64_OpAMD64ROLQ_0(v)
 	case OpAMD64ROLQconst:
-		return rewriteValueAMD64_OpAMD64ROLQconst(v, config)
+		return rewriteValueAMD64_OpAMD64ROLQconst_0(v)
+	case OpAMD64ROLW:
+		return rewriteValueAMD64_OpAMD64ROLW_0(v)
 	case OpAMD64ROLWconst:
-		return rewriteValueAMD64_OpAMD64ROLWconst(v, config)
+		return rewriteValueAMD64_OpAMD64ROLWconst_0(v)
+	case OpAMD64RORB:
+		return rewriteValueAMD64_OpAMD64RORB_0(v)
+	case OpAMD64RORL:
+		return rewriteValueAMD64_OpAMD64RORL_0(v)
+	case OpAMD64RORQ:
+		return rewriteValueAMD64_OpAMD64RORQ_0(v)
+	case OpAMD64RORW:
+		return rewriteValueAMD64_OpAMD64RORW_0(v)
 	case OpAMD64SARB:
-		return rewriteValueAMD64_OpAMD64SARB(v, config)
+		return rewriteValueAMD64_OpAMD64SARB_0(v)
 	case OpAMD64SARBconst:
-		return rewriteValueAMD64_OpAMD64SARBconst(v, config)
+		return rewriteValueAMD64_OpAMD64SARBconst_0(v)
 	case OpAMD64SARL:
-		return rewriteValueAMD64_OpAMD64SARL(v, config)
+		return rewriteValueAMD64_OpAMD64SARL_0(v)
 	case OpAMD64SARLconst:
-		return rewriteValueAMD64_OpAMD64SARLconst(v, config)
+		return rewriteValueAMD64_OpAMD64SARLconst_0(v)
 	case OpAMD64SARQ:
-		return rewriteValueAMD64_OpAMD64SARQ(v, config)
+		return rewriteValueAMD64_OpAMD64SARQ_0(v)
 	case OpAMD64SARQconst:
-		return rewriteValueAMD64_OpAMD64SARQconst(v, config)
+		return rewriteValueAMD64_OpAMD64SARQconst_0(v)
 	case OpAMD64SARW:
-		return rewriteValueAMD64_OpAMD64SARW(v, config)
+		return rewriteValueAMD64_OpAMD64SARW_0(v)
 	case OpAMD64SARWconst:
-		return rewriteValueAMD64_OpAMD64SARWconst(v, config)
+		return rewriteValueAMD64_OpAMD64SARWconst_0(v)
 	case OpAMD64SBBLcarrymask:
-		return rewriteValueAMD64_OpAMD64SBBLcarrymask(v, config)
+		return rewriteValueAMD64_OpAMD64SBBLcarrymask_0(v)
 	case OpAMD64SBBQcarrymask:
-		return rewriteValueAMD64_OpAMD64SBBQcarrymask(v, config)
+		return rewriteValueAMD64_OpAMD64SBBQcarrymask_0(v)
 	case OpAMD64SETA:
-		return rewriteValueAMD64_OpAMD64SETA(v, config)
+		return rewriteValueAMD64_OpAMD64SETA_0(v)
 	case OpAMD64SETAE:
-		return rewriteValueAMD64_OpAMD64SETAE(v, config)
+		return rewriteValueAMD64_OpAMD64SETAE_0(v)
 	case OpAMD64SETB:
-		return rewriteValueAMD64_OpAMD64SETB(v, config)
+		return rewriteValueAMD64_OpAMD64SETB_0(v)
 	case OpAMD64SETBE:
-		return rewriteValueAMD64_OpAMD64SETBE(v, config)
+		return rewriteValueAMD64_OpAMD64SETBE_0(v)
 	case OpAMD64SETEQ:
-		return rewriteValueAMD64_OpAMD64SETEQ(v, config)
+		return rewriteValueAMD64_OpAMD64SETEQ_0(v) || rewriteValueAMD64_OpAMD64SETEQ_10(v)
 	case OpAMD64SETG:
-		return rewriteValueAMD64_OpAMD64SETG(v, config)
+		return rewriteValueAMD64_OpAMD64SETG_0(v)
 	case OpAMD64SETGE:
-		return rewriteValueAMD64_OpAMD64SETGE(v, config)
+		return rewriteValueAMD64_OpAMD64SETGE_0(v)
 	case OpAMD64SETL:
-		return rewriteValueAMD64_OpAMD64SETL(v, config)
+		return rewriteValueAMD64_OpAMD64SETL_0(v)
 	case OpAMD64SETLE:
-		return rewriteValueAMD64_OpAMD64SETLE(v, config)
+		return rewriteValueAMD64_OpAMD64SETLE_0(v)
 	case OpAMD64SETNE:
-		return rewriteValueAMD64_OpAMD64SETNE(v, config)
+		return rewriteValueAMD64_OpAMD64SETNE_0(v) || rewriteValueAMD64_OpAMD64SETNE_10(v)
 	case OpAMD64SHLL:
-		return rewriteValueAMD64_OpAMD64SHLL(v, config)
+		return rewriteValueAMD64_OpAMD64SHLL_0(v)
+	case OpAMD64SHLLconst:
+		return rewriteValueAMD64_OpAMD64SHLLconst_0(v)
 	case OpAMD64SHLQ:
-		return rewriteValueAMD64_OpAMD64SHLQ(v, config)
+		return rewriteValueAMD64_OpAMD64SHLQ_0(v)
+	case OpAMD64SHLQconst:
+		return rewriteValueAMD64_OpAMD64SHLQconst_0(v)
 	case OpAMD64SHRB:
-		return rewriteValueAMD64_OpAMD64SHRB(v, config)
+		return rewriteValueAMD64_OpAMD64SHRB_0(v)
+	case OpAMD64SHRBconst:
+		return rewriteValueAMD64_OpAMD64SHRBconst_0(v)
 	case OpAMD64SHRL:
-		return rewriteValueAMD64_OpAMD64SHRL(v, config)
+		return rewriteValueAMD64_OpAMD64SHRL_0(v)
+	case OpAMD64SHRLconst:
+		return rewriteValueAMD64_OpAMD64SHRLconst_0(v)
 	case OpAMD64SHRQ:
-		return rewriteValueAMD64_OpAMD64SHRQ(v, config)
+		return rewriteValueAMD64_OpAMD64SHRQ_0(v)
+	case OpAMD64SHRQconst:
+		return rewriteValueAMD64_OpAMD64SHRQconst_0(v)
 	case OpAMD64SHRW:
-		return rewriteValueAMD64_OpAMD64SHRW(v, config)
+		return rewriteValueAMD64_OpAMD64SHRW_0(v)
+	case OpAMD64SHRWconst:
+		return rewriteValueAMD64_OpAMD64SHRWconst_0(v)
 	case OpAMD64SUBL:
-		return rewriteValueAMD64_OpAMD64SUBL(v, config)
+		return rewriteValueAMD64_OpAMD64SUBL_0(v)
 	case OpAMD64SUBLconst:
-		return rewriteValueAMD64_OpAMD64SUBLconst(v, config)
+		return rewriteValueAMD64_OpAMD64SUBLconst_0(v)
 	case OpAMD64SUBQ:
-		return rewriteValueAMD64_OpAMD64SUBQ(v, config)
+		return rewriteValueAMD64_OpAMD64SUBQ_0(v)
 	case OpAMD64SUBQconst:
-		return rewriteValueAMD64_OpAMD64SUBQconst(v, config)
+		return rewriteValueAMD64_OpAMD64SUBQconst_0(v)
+	case OpAMD64SUBSD:
+		return rewriteValueAMD64_OpAMD64SUBSD_0(v)
+	case OpAMD64SUBSS:
+		return rewriteValueAMD64_OpAMD64SUBSS_0(v)
+	case OpAMD64TESTB:
+		return rewriteValueAMD64_OpAMD64TESTB_0(v)
+	case OpAMD64TESTL:
+		return rewriteValueAMD64_OpAMD64TESTL_0(v)
+	case OpAMD64TESTQ:
+		return rewriteValueAMD64_OpAMD64TESTQ_0(v)
+	case OpAMD64TESTW:
+		return rewriteValueAMD64_OpAMD64TESTW_0(v)
 	case OpAMD64XADDLlock:
-		return rewriteValueAMD64_OpAMD64XADDLlock(v, config)
+		return rewriteValueAMD64_OpAMD64XADDLlock_0(v)
 	case OpAMD64XADDQlock:
-		return rewriteValueAMD64_OpAMD64XADDQlock(v, config)
+		return rewriteValueAMD64_OpAMD64XADDQlock_0(v)
 	case OpAMD64XCHGL:
-		return rewriteValueAMD64_OpAMD64XCHGL(v, config)
+		return rewriteValueAMD64_OpAMD64XCHGL_0(v)
 	case OpAMD64XCHGQ:
-		return rewriteValueAMD64_OpAMD64XCHGQ(v, config)
+		return rewriteValueAMD64_OpAMD64XCHGQ_0(v)
 	case OpAMD64XORL:
-		return rewriteValueAMD64_OpAMD64XORL(v, config)
+		return rewriteValueAMD64_OpAMD64XORL_0(v) || rewriteValueAMD64_OpAMD64XORL_10(v)
 	case OpAMD64XORLconst:
-		return rewriteValueAMD64_OpAMD64XORLconst(v, config)
+		return rewriteValueAMD64_OpAMD64XORLconst_0(v) || rewriteValueAMD64_OpAMD64XORLconst_10(v)
 	case OpAMD64XORQ:
-		return rewriteValueAMD64_OpAMD64XORQ(v, config)
+		return rewriteValueAMD64_OpAMD64XORQ_0(v)
 	case OpAMD64XORQconst:
-		return rewriteValueAMD64_OpAMD64XORQconst(v, config)
+		return rewriteValueAMD64_OpAMD64XORQconst_0(v)
 	case OpAdd16:
-		return rewriteValueAMD64_OpAdd16(v, config)
+		return rewriteValueAMD64_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueAMD64_OpAdd32(v, config)
+		return rewriteValueAMD64_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueAMD64_OpAdd32F(v, config)
+		return rewriteValueAMD64_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValueAMD64_OpAdd64(v, config)
+		return rewriteValueAMD64_OpAdd64_0(v)
 	case OpAdd64F:
-		return rewriteValueAMD64_OpAdd64F(v, config)
+		return rewriteValueAMD64_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueAMD64_OpAdd8(v, config)
+		return rewriteValueAMD64_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueAMD64_OpAddPtr(v, config)
+		return rewriteValueAMD64_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueAMD64_OpAddr(v, config)
+		return rewriteValueAMD64_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueAMD64_OpAnd16(v, config)
+		return rewriteValueAMD64_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueAMD64_OpAnd32(v, config)
+		return rewriteValueAMD64_OpAnd32_0(v)
 	case OpAnd64:
-		return rewriteValueAMD64_OpAnd64(v, config)
+		return rewriteValueAMD64_OpAnd64_0(v)
 	case OpAnd8:
-		return rewriteValueAMD64_OpAnd8(v, config)
+		return rewriteValueAMD64_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueAMD64_OpAndB(v, config)
+		return rewriteValueAMD64_OpAndB_0(v)
 	case OpAtomicAdd32:
-		return rewriteValueAMD64_OpAtomicAdd32(v, config)
+		return rewriteValueAMD64_OpAtomicAdd32_0(v)
 	case OpAtomicAdd64:
-		return rewriteValueAMD64_OpAtomicAdd64(v, config)
+		return rewriteValueAMD64_OpAtomicAdd64_0(v)
 	case OpAtomicAnd8:
-		return rewriteValueAMD64_OpAtomicAnd8(v, config)
+		return rewriteValueAMD64_OpAtomicAnd8_0(v)
 	case OpAtomicCompareAndSwap32:
-		return rewriteValueAMD64_OpAtomicCompareAndSwap32(v, config)
+		return rewriteValueAMD64_OpAtomicCompareAndSwap32_0(v)
 	case OpAtomicCompareAndSwap64:
-		return rewriteValueAMD64_OpAtomicCompareAndSwap64(v, config)
+		return rewriteValueAMD64_OpAtomicCompareAndSwap64_0(v)
 	case OpAtomicExchange32:
-		return rewriteValueAMD64_OpAtomicExchange32(v, config)
+		return rewriteValueAMD64_OpAtomicExchange32_0(v)
 	case OpAtomicExchange64:
-		return rewriteValueAMD64_OpAtomicExchange64(v, config)
+		return rewriteValueAMD64_OpAtomicExchange64_0(v)
 	case OpAtomicLoad32:
-		return rewriteValueAMD64_OpAtomicLoad32(v, config)
+		return rewriteValueAMD64_OpAtomicLoad32_0(v)
 	case OpAtomicLoad64:
-		return rewriteValueAMD64_OpAtomicLoad64(v, config)
+		return rewriteValueAMD64_OpAtomicLoad64_0(v)
 	case OpAtomicLoadPtr:
-		return rewriteValueAMD64_OpAtomicLoadPtr(v, config)
+		return rewriteValueAMD64_OpAtomicLoadPtr_0(v)
 	case OpAtomicOr8:
-		return rewriteValueAMD64_OpAtomicOr8(v, config)
+		return rewriteValueAMD64_OpAtomicOr8_0(v)
 	case OpAtomicStore32:
-		return rewriteValueAMD64_OpAtomicStore32(v, config)
+		return rewriteValueAMD64_OpAtomicStore32_0(v)
 	case OpAtomicStore64:
-		return rewriteValueAMD64_OpAtomicStore64(v, config)
+		return rewriteValueAMD64_OpAtomicStore64_0(v)
 	case OpAtomicStorePtrNoWB:
-		return rewriteValueAMD64_OpAtomicStorePtrNoWB(v, config)
+		return rewriteValueAMD64_OpAtomicStorePtrNoWB_0(v)
 	case OpAvg64u:
-		return rewriteValueAMD64_OpAvg64u(v, config)
+		return rewriteValueAMD64_OpAvg64u_0(v)
+	case OpBitLen32:
+		return rewriteValueAMD64_OpBitLen32_0(v)
+	case OpBitLen64:
+		return rewriteValueAMD64_OpBitLen64_0(v)
 	case OpBswap32:
-		return rewriteValueAMD64_OpBswap32(v, config)
+		return rewriteValueAMD64_OpBswap32_0(v)
 	case OpBswap64:
-		return rewriteValueAMD64_OpBswap64(v, config)
+		return rewriteValueAMD64_OpBswap64_0(v)
 	case OpClosureCall:
-		return rewriteValueAMD64_OpClosureCall(v, config)
+		return rewriteValueAMD64_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueAMD64_OpCom16(v, config)
+		return rewriteValueAMD64_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueAMD64_OpCom32(v, config)
+		return rewriteValueAMD64_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValueAMD64_OpCom64(v, config)
+		return rewriteValueAMD64_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValueAMD64_OpCom8(v, config)
+		return rewriteValueAMD64_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueAMD64_OpConst16(v, config)
+		return rewriteValueAMD64_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueAMD64_OpConst32(v, config)
+		return rewriteValueAMD64_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueAMD64_OpConst32F(v, config)
+		return rewriteValueAMD64_OpConst32F_0(v)
 	case OpConst64:
-		return rewriteValueAMD64_OpConst64(v, config)
+		return rewriteValueAMD64_OpConst64_0(v)
 	case OpConst64F:
-		return rewriteValueAMD64_OpConst64F(v, config)
+		return rewriteValueAMD64_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueAMD64_OpConst8(v, config)
+		return rewriteValueAMD64_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueAMD64_OpConstBool(v, config)
+		return rewriteValueAMD64_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueAMD64_OpConstNil(v, config)
+		return rewriteValueAMD64_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueAMD64_OpConvert(v, config)
+		return rewriteValueAMD64_OpConvert_0(v)
 	case OpCtz32:
-		return rewriteValueAMD64_OpCtz32(v, config)
+		return rewriteValueAMD64_OpCtz32_0(v)
 	case OpCtz64:
-		return rewriteValueAMD64_OpCtz64(v, config)
+		return rewriteValueAMD64_OpCtz64_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueAMD64_OpCvt32Fto32(v, config)
+		return rewriteValueAMD64_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64:
-		return rewriteValueAMD64_OpCvt32Fto64(v, config)
+		return rewriteValueAMD64_OpCvt32Fto64_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueAMD64_OpCvt32Fto64F(v, config)
+		return rewriteValueAMD64_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueAMD64_OpCvt32to32F(v, config)
+		return rewriteValueAMD64_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueAMD64_OpCvt32to64F(v, config)
+		return rewriteValueAMD64_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueAMD64_OpCvt64Fto32(v, config)
+		return rewriteValueAMD64_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueAMD64_OpCvt64Fto32F(v, config)
+		return rewriteValueAMD64_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto64:
-		return rewriteValueAMD64_OpCvt64Fto64(v, config)
+		return rewriteValueAMD64_OpCvt64Fto64_0(v)
 	case OpCvt64to32F:
-		return rewriteValueAMD64_OpCvt64to32F(v, config)
+		return rewriteValueAMD64_OpCvt64to32F_0(v)
 	case OpCvt64to64F:
-		return rewriteValueAMD64_OpCvt64to64F(v, config)
-	case OpDeferCall:
-		return rewriteValueAMD64_OpDeferCall(v, config)
+		return rewriteValueAMD64_OpCvt64to64F_0(v)
 	case OpDiv128u:
-		return rewriteValueAMD64_OpDiv128u(v, config)
+		return rewriteValueAMD64_OpDiv128u_0(v)
 	case OpDiv16:
-		return rewriteValueAMD64_OpDiv16(v, config)
+		return rewriteValueAMD64_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueAMD64_OpDiv16u(v, config)
+		return rewriteValueAMD64_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueAMD64_OpDiv32(v, config)
+		return rewriteValueAMD64_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueAMD64_OpDiv32F(v, config)
+		return rewriteValueAMD64_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueAMD64_OpDiv32u(v, config)
+		return rewriteValueAMD64_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValueAMD64_OpDiv64(v, config)
+		return rewriteValueAMD64_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValueAMD64_OpDiv64F(v, config)
+		return rewriteValueAMD64_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValueAMD64_OpDiv64u(v, config)
+		return rewriteValueAMD64_OpDiv64u_0(v)
 	case OpDiv8:
-		return rewriteValueAMD64_OpDiv8(v, config)
+		return rewriteValueAMD64_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueAMD64_OpDiv8u(v, config)
+		return rewriteValueAMD64_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueAMD64_OpEq16(v, config)
+		return rewriteValueAMD64_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueAMD64_OpEq32(v, config)
+		return rewriteValueAMD64_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueAMD64_OpEq32F(v, config)
+		return rewriteValueAMD64_OpEq32F_0(v)
 	case OpEq64:
-		return rewriteValueAMD64_OpEq64(v, config)
+		return rewriteValueAMD64_OpEq64_0(v)
 	case OpEq64F:
-		return rewriteValueAMD64_OpEq64F(v, config)
+		return rewriteValueAMD64_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueAMD64_OpEq8(v, config)
+		return rewriteValueAMD64_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueAMD64_OpEqB(v, config)
+		return rewriteValueAMD64_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueAMD64_OpEqPtr(v, config)
+		return rewriteValueAMD64_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueAMD64_OpGeq16(v, config)
+		return rewriteValueAMD64_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueAMD64_OpGeq16U(v, config)
+		return rewriteValueAMD64_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueAMD64_OpGeq32(v, config)
+		return rewriteValueAMD64_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueAMD64_OpGeq32F(v, config)
+		return rewriteValueAMD64_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueAMD64_OpGeq32U(v, config)
+		return rewriteValueAMD64_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValueAMD64_OpGeq64(v, config)
+		return rewriteValueAMD64_OpGeq64_0(v)
 	case OpGeq64F:
-		return rewriteValueAMD64_OpGeq64F(v, config)
+		return rewriteValueAMD64_OpGeq64F_0(v)
 	case OpGeq64U:
-		return rewriteValueAMD64_OpGeq64U(v, config)
+		return rewriteValueAMD64_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValueAMD64_OpGeq8(v, config)
+		return rewriteValueAMD64_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueAMD64_OpGeq8U(v, config)
+		return rewriteValueAMD64_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueAMD64_OpGetClosurePtr(v, config)
+		return rewriteValueAMD64_OpGetClosurePtr_0(v)
 	case OpGetG:
-		return rewriteValueAMD64_OpGetG(v, config)
-	case OpGoCall:
-		return rewriteValueAMD64_OpGoCall(v, config)
+		return rewriteValueAMD64_OpGetG_0(v)
 	case OpGreater16:
-		return rewriteValueAMD64_OpGreater16(v, config)
+		return rewriteValueAMD64_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueAMD64_OpGreater16U(v, config)
+		return rewriteValueAMD64_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueAMD64_OpGreater32(v, config)
+		return rewriteValueAMD64_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueAMD64_OpGreater32F(v, config)
+		return rewriteValueAMD64_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueAMD64_OpGreater32U(v, config)
+		return rewriteValueAMD64_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValueAMD64_OpGreater64(v, config)
+		return rewriteValueAMD64_OpGreater64_0(v)
 	case OpGreater64F:
-		return rewriteValueAMD64_OpGreater64F(v, config)
+		return rewriteValueAMD64_OpGreater64F_0(v)
 	case OpGreater64U:
-		return rewriteValueAMD64_OpGreater64U(v, config)
+		return rewriteValueAMD64_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValueAMD64_OpGreater8(v, config)
+		return rewriteValueAMD64_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueAMD64_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueAMD64_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueAMD64_OpHmul16u(v, config)
+		return rewriteValueAMD64_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueAMD64_OpHmul32(v, config)
+		return rewriteValueAMD64_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueAMD64_OpHmul32u(v, config)
+		return rewriteValueAMD64_OpHmul32u_0(v)
 	case OpHmul64:
-		return rewriteValueAMD64_OpHmul64(v, config)
+		return rewriteValueAMD64_OpHmul64_0(v)
 	case OpHmul64u:
-		return rewriteValueAMD64_OpHmul64u(v, config)
-	case OpHmul8:
-		return rewriteValueAMD64_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueAMD64_OpHmul8u(v, config)
+		return rewriteValueAMD64_OpHmul64u_0(v)
 	case OpInt64Hi:
-		return rewriteValueAMD64_OpInt64Hi(v, config)
+		return rewriteValueAMD64_OpInt64Hi_0(v)
 	case OpInterCall:
-		return rewriteValueAMD64_OpInterCall(v, config)
+		return rewriteValueAMD64_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueAMD64_OpIsInBounds(v, config)
+		return rewriteValueAMD64_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueAMD64_OpIsNonNil(v, config)
+		return rewriteValueAMD64_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueAMD64_OpIsSliceInBounds(v, config)
+		return rewriteValueAMD64_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueAMD64_OpLeq16(v, config)
+		return rewriteValueAMD64_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueAMD64_OpLeq16U(v, config)
+		return rewriteValueAMD64_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueAMD64_OpLeq32(v, config)
+		return rewriteValueAMD64_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueAMD64_OpLeq32F(v, config)
+		return rewriteValueAMD64_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueAMD64_OpLeq32U(v, config)
+		return rewriteValueAMD64_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValueAMD64_OpLeq64(v, config)
+		return rewriteValueAMD64_OpLeq64_0(v)
 	case OpLeq64F:
-		return rewriteValueAMD64_OpLeq64F(v, config)
+		return rewriteValueAMD64_OpLeq64F_0(v)
 	case OpLeq64U:
-		return rewriteValueAMD64_OpLeq64U(v, config)
+		return rewriteValueAMD64_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValueAMD64_OpLeq8(v, config)
+		return rewriteValueAMD64_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueAMD64_OpLeq8U(v, config)
+		return rewriteValueAMD64_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueAMD64_OpLess16(v, config)
+		return rewriteValueAMD64_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueAMD64_OpLess16U(v, config)
+		return rewriteValueAMD64_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueAMD64_OpLess32(v, config)
+		return rewriteValueAMD64_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueAMD64_OpLess32F(v, config)
+		return rewriteValueAMD64_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueAMD64_OpLess32U(v, config)
+		return rewriteValueAMD64_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValueAMD64_OpLess64(v, config)
+		return rewriteValueAMD64_OpLess64_0(v)
 	case OpLess64F:
-		return rewriteValueAMD64_OpLess64F(v, config)
+		return rewriteValueAMD64_OpLess64F_0(v)
 	case OpLess64U:
-		return rewriteValueAMD64_OpLess64U(v, config)
+		return rewriteValueAMD64_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValueAMD64_OpLess8(v, config)
+		return rewriteValueAMD64_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueAMD64_OpLess8U(v, config)
+		return rewriteValueAMD64_OpLess8U_0(v)
 	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)
+		return rewriteValueAMD64_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueAMD64_OpLsh16x16(v, config)
+		return rewriteValueAMD64_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueAMD64_OpLsh16x32(v, config)
+		return rewriteValueAMD64_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueAMD64_OpLsh16x64(v, config)
+		return rewriteValueAMD64_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueAMD64_OpLsh16x8(v, config)
+		return rewriteValueAMD64_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueAMD64_OpLsh32x16(v, config)
+		return rewriteValueAMD64_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueAMD64_OpLsh32x32(v, config)
+		return rewriteValueAMD64_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueAMD64_OpLsh32x64(v, config)
+		return rewriteValueAMD64_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueAMD64_OpLsh32x8(v, config)
+		return rewriteValueAMD64_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValueAMD64_OpLsh64x16(v, config)
+		return rewriteValueAMD64_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValueAMD64_OpLsh64x32(v, config)
+		return rewriteValueAMD64_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValueAMD64_OpLsh64x64(v, config)
+		return rewriteValueAMD64_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValueAMD64_OpLsh64x8(v, config)
+		return rewriteValueAMD64_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueAMD64_OpLsh8x16(v, config)
+		return rewriteValueAMD64_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueAMD64_OpLsh8x32(v, config)
+		return rewriteValueAMD64_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueAMD64_OpLsh8x64(v, config)
+		return rewriteValueAMD64_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueAMD64_OpLsh8x8(v, config)
+		return rewriteValueAMD64_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValueAMD64_OpMod16(v, config)
+		return rewriteValueAMD64_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueAMD64_OpMod16u(v, config)
+		return rewriteValueAMD64_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueAMD64_OpMod32(v, config)
+		return rewriteValueAMD64_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueAMD64_OpMod32u(v, config)
+		return rewriteValueAMD64_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValueAMD64_OpMod64(v, config)
+		return rewriteValueAMD64_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValueAMD64_OpMod64u(v, config)
+		return rewriteValueAMD64_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValueAMD64_OpMod8(v, config)
+		return rewriteValueAMD64_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueAMD64_OpMod8u(v, config)
+		return rewriteValueAMD64_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueAMD64_OpMove(v, config)
+		return rewriteValueAMD64_OpMove_0(v) || rewriteValueAMD64_OpMove_10(v)
 	case OpMul16:
-		return rewriteValueAMD64_OpMul16(v, config)
+		return rewriteValueAMD64_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueAMD64_OpMul32(v, config)
+		return rewriteValueAMD64_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueAMD64_OpMul32F(v, config)
+		return rewriteValueAMD64_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValueAMD64_OpMul64(v, config)
+		return rewriteValueAMD64_OpMul64_0(v)
 	case OpMul64F:
-		return rewriteValueAMD64_OpMul64F(v, config)
+		return rewriteValueAMD64_OpMul64F_0(v)
 	case OpMul64uhilo:
-		return rewriteValueAMD64_OpMul64uhilo(v, config)
+		return rewriteValueAMD64_OpMul64uhilo_0(v)
 	case OpMul8:
-		return rewriteValueAMD64_OpMul8(v, config)
+		return rewriteValueAMD64_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueAMD64_OpNeg16(v, config)
+		return rewriteValueAMD64_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueAMD64_OpNeg32(v, config)
+		return rewriteValueAMD64_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueAMD64_OpNeg32F(v, config)
+		return rewriteValueAMD64_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValueAMD64_OpNeg64(v, config)
+		return rewriteValueAMD64_OpNeg64_0(v)
 	case OpNeg64F:
-		return rewriteValueAMD64_OpNeg64F(v, config)
+		return rewriteValueAMD64_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueAMD64_OpNeg8(v, config)
+		return rewriteValueAMD64_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueAMD64_OpNeq16(v, config)
+		return rewriteValueAMD64_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueAMD64_OpNeq32(v, config)
+		return rewriteValueAMD64_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueAMD64_OpNeq32F(v, config)
+		return rewriteValueAMD64_OpNeq32F_0(v)
 	case OpNeq64:
-		return rewriteValueAMD64_OpNeq64(v, config)
+		return rewriteValueAMD64_OpNeq64_0(v)
 	case OpNeq64F:
-		return rewriteValueAMD64_OpNeq64F(v, config)
+		return rewriteValueAMD64_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueAMD64_OpNeq8(v, config)
+		return rewriteValueAMD64_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueAMD64_OpNeqB(v, config)
+		return rewriteValueAMD64_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueAMD64_OpNeqPtr(v, config)
+		return rewriteValueAMD64_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueAMD64_OpNilCheck(v, config)
+		return rewriteValueAMD64_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueAMD64_OpNot(v, config)
+		return rewriteValueAMD64_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueAMD64_OpOffPtr(v, config)
+		return rewriteValueAMD64_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueAMD64_OpOr16(v, config)
+		return rewriteValueAMD64_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueAMD64_OpOr32(v, config)
+		return rewriteValueAMD64_OpOr32_0(v)
 	case OpOr64:
-		return rewriteValueAMD64_OpOr64(v, config)
+		return rewriteValueAMD64_OpOr64_0(v)
 	case OpOr8:
-		return rewriteValueAMD64_OpOr8(v, config)
+		return rewriteValueAMD64_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueAMD64_OpOrB(v, config)
+		return rewriteValueAMD64_OpOrB_0(v)
+	case OpPopCount16:
+		return rewriteValueAMD64_OpPopCount16_0(v)
+	case OpPopCount32:
+		return rewriteValueAMD64_OpPopCount32_0(v)
+	case OpPopCount64:
+		return rewriteValueAMD64_OpPopCount64_0(v)
+	case OpPopCount8:
+		return rewriteValueAMD64_OpPopCount8_0(v)
+	case OpRound32F:
+		return rewriteValueAMD64_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueAMD64_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueAMD64_OpRsh16Ux16(v, config)
+		return rewriteValueAMD64_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueAMD64_OpRsh16Ux32(v, config)
+		return rewriteValueAMD64_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueAMD64_OpRsh16Ux64(v, config)
+		return rewriteValueAMD64_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueAMD64_OpRsh16Ux8(v, config)
+		return rewriteValueAMD64_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueAMD64_OpRsh16x16(v, config)
+		return rewriteValueAMD64_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueAMD64_OpRsh16x32(v, config)
+		return rewriteValueAMD64_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueAMD64_OpRsh16x64(v, config)
+		return rewriteValueAMD64_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueAMD64_OpRsh16x8(v, config)
+		return rewriteValueAMD64_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueAMD64_OpRsh32Ux16(v, config)
+		return rewriteValueAMD64_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueAMD64_OpRsh32Ux32(v, config)
+		return rewriteValueAMD64_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueAMD64_OpRsh32Ux64(v, config)
+		return rewriteValueAMD64_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueAMD64_OpRsh32Ux8(v, config)
+		return rewriteValueAMD64_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueAMD64_OpRsh32x16(v, config)
+		return rewriteValueAMD64_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueAMD64_OpRsh32x32(v, config)
+		return rewriteValueAMD64_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueAMD64_OpRsh32x64(v, config)
+		return rewriteValueAMD64_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueAMD64_OpRsh32x8(v, config)
+		return rewriteValueAMD64_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValueAMD64_OpRsh64Ux16(v, config)
+		return rewriteValueAMD64_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValueAMD64_OpRsh64Ux32(v, config)
+		return rewriteValueAMD64_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValueAMD64_OpRsh64Ux64(v, config)
+		return rewriteValueAMD64_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValueAMD64_OpRsh64Ux8(v, config)
+		return rewriteValueAMD64_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValueAMD64_OpRsh64x16(v, config)
+		return rewriteValueAMD64_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValueAMD64_OpRsh64x32(v, config)
+		return rewriteValueAMD64_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValueAMD64_OpRsh64x64(v, config)
+		return rewriteValueAMD64_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValueAMD64_OpRsh64x8(v, config)
+		return rewriteValueAMD64_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueAMD64_OpRsh8Ux16(v, config)
+		return rewriteValueAMD64_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueAMD64_OpRsh8Ux32(v, config)
+		return rewriteValueAMD64_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueAMD64_OpRsh8Ux64(v, config)
+		return rewriteValueAMD64_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueAMD64_OpRsh8Ux8(v, config)
+		return rewriteValueAMD64_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueAMD64_OpRsh8x16(v, config)
+		return rewriteValueAMD64_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueAMD64_OpRsh8x32(v, config)
+		return rewriteValueAMD64_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueAMD64_OpRsh8x64(v, config)
+		return rewriteValueAMD64_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueAMD64_OpRsh8x8(v, config)
+		return rewriteValueAMD64_OpRsh8x8_0(v)
 	case OpSelect0:
-		return rewriteValueAMD64_OpSelect0(v, config)
+		return rewriteValueAMD64_OpSelect0_0(v)
 	case OpSelect1:
-		return rewriteValueAMD64_OpSelect1(v, config)
+		return rewriteValueAMD64_OpSelect1_0(v)
 	case OpSignExt16to32:
-		return rewriteValueAMD64_OpSignExt16to32(v, config)
+		return rewriteValueAMD64_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValueAMD64_OpSignExt16to64(v, config)
+		return rewriteValueAMD64_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValueAMD64_OpSignExt32to64(v, config)
+		return rewriteValueAMD64_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValueAMD64_OpSignExt8to16(v, config)
+		return rewriteValueAMD64_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueAMD64_OpSignExt8to32(v, config)
+		return rewriteValueAMD64_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValueAMD64_OpSignExt8to64(v, config)
+		return rewriteValueAMD64_OpSignExt8to64_0(v)
 	case OpSlicemask:
-		return rewriteValueAMD64_OpSlicemask(v, config)
+		return rewriteValueAMD64_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValueAMD64_OpSqrt(v, config)
+		return rewriteValueAMD64_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValueAMD64_OpStaticCall(v, config)
+		return rewriteValueAMD64_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueAMD64_OpStore(v, config)
+		return rewriteValueAMD64_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueAMD64_OpSub16(v, config)
+		return rewriteValueAMD64_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueAMD64_OpSub32(v, config)
+		return rewriteValueAMD64_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueAMD64_OpSub32F(v, config)
+		return rewriteValueAMD64_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValueAMD64_OpSub64(v, config)
+		return rewriteValueAMD64_OpSub64_0(v)
 	case OpSub64F:
-		return rewriteValueAMD64_OpSub64F(v, config)
+		return rewriteValueAMD64_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueAMD64_OpSub8(v, config)
+		return rewriteValueAMD64_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueAMD64_OpSubPtr(v, config)
+		return rewriteValueAMD64_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueAMD64_OpTrunc16to8(v, config)
+		return rewriteValueAMD64_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueAMD64_OpTrunc32to16(v, config)
+		return rewriteValueAMD64_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueAMD64_OpTrunc32to8(v, config)
+		return rewriteValueAMD64_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValueAMD64_OpTrunc64to16(v, config)
+		return rewriteValueAMD64_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValueAMD64_OpTrunc64to32(v, config)
+		return rewriteValueAMD64_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValueAMD64_OpTrunc64to8(v, config)
+		return rewriteValueAMD64_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValueAMD64_OpXor16(v, config)
+		return rewriteValueAMD64_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueAMD64_OpXor32(v, config)
+		return rewriteValueAMD64_OpXor32_0(v)
 	case OpXor64:
-		return rewriteValueAMD64_OpXor64(v, config)
+		return rewriteValueAMD64_OpXor64_0(v)
 	case OpXor8:
-		return rewriteValueAMD64_OpXor8(v, config)
+		return rewriteValueAMD64_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueAMD64_OpZero(v, config)
+		return rewriteValueAMD64_OpZero_0(v) || rewriteValueAMD64_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValueAMD64_OpZeroExt16to32(v, config)
+		return rewriteValueAMD64_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValueAMD64_OpZeroExt16to64(v, config)
+		return rewriteValueAMD64_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValueAMD64_OpZeroExt32to64(v, config)
+		return rewriteValueAMD64_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueAMD64_OpZeroExt8to16(v, config)
+		return rewriteValueAMD64_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueAMD64_OpZeroExt8to32(v, config)
+		return rewriteValueAMD64_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValueAMD64_OpZeroExt8to64(v, config)
+		return rewriteValueAMD64_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ADDL_0(v *Value) bool {
 	// match: (ADDL x (MOVLconst [c]))
 	// cond:
 	// result: (ADDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVLconst {
@@ -823,6 +879,7 @@ func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVLconst {
 			break
@@ -834,10 +891,177 @@ func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDL (SHLLconst x [c]) (SHRLconst x [d]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRLconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL (SHRLconst x [d]) (SHLLconst x [c]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRBconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRBconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ADDL x (NEGL y))
 	// cond:
 	// result: (SUBL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64NEGL {
@@ -849,11 +1073,80 @@ func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDL (NEGL y) x)
+	// cond:
+	// result: (SUBL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		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
+func rewriteValueAMD64_OpAMD64ADDL_10(v *Value) bool {
+	// match: (ADDL x l:(MOVLload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDL l:(MOVLload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDLconst_0(v *Value) bool {
 	// match: (ADDLconst [c] x)
 	// cond: int32(c)==0
 	// result: x
@@ -921,13 +1214,12 @@ func rewriteValueAMD64_OpAMD64ADDLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ADDQ_0(v *Value) bool {
 	// match: (ADDQ x (MOVQconst [c]))
 	// cond: is32Bit(c)
 	// result: (ADDQconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVQconst {
@@ -946,6 +1238,7 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (ADDQconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVQconst {
 			break
@@ -960,10 +1253,65 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDQ (SHLQconst x [c]) (SHRQconst x [d]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ (SHRQconst x [d]) (SHLQconst x [c]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ADDQ x (SHLQconst [3] y))
 	// cond:
 	// result: (LEAQ8 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -978,10 +1326,30 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDQ (SHLQconst [3] y) x)
+	// cond:
+	// result: (LEAQ8 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_0.AuxInt != 3 {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADDQ x (SHLQconst [2] y))
 	// cond:
 	// result: (LEAQ4 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -996,51 +1364,117 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (ADDQ x (SHLQconst [1] y))
+	// match: (ADDQ (SHLQconst [2] y) x)
 	// cond:
-	// result: (LEAQ2 x y)
+	// result: (LEAQ4 x y)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		if v_0.AuxInt != 2 {
 			break
 		}
-		y := v_1.Args[0]
-		v.reset(OpAMD64LEAQ2)
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpAMD64LEAQ4)
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (ADDQ x (ADDQ y y))
+	// match: (ADDQ x (SHLQconst [1] y))
 	// cond:
 	// result: (LEAQ2 x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQ {
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		y := v_1.Args[0]
-		if y != v_1.Args[1] {
+		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 x y))
+	// match: (ADDQ (SHLQconst [1] y) x)
 	// cond:
-	// result: (LEAQ2 y x)
+	// result: (LEAQ2 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDQ_10(v *Value) bool {
+	// match: (ADDQ x (ADDQ y y))
+	// cond:
+	// result: (LEAQ2 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		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 (ADDQ y y) x)
+	// cond:
+	// result: (LEAQ2 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		if y != v_0.Args[1] {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (ADDQ x y))
+	// cond:
+	// result: (LEAQ2 y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_1.Args[1]
 		if x != v_1.Args[0] {
 			break
 		}
@@ -1054,11 +1488,13 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 	// cond:
 	// result: (LEAQ2 y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		if x != v_1.Args[1] {
 			break
@@ -1068,10 +1504,51 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDQ (ADDQ x y) x)
+	// cond:
+	// result: (LEAQ2 y x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ (ADDQ y x) x)
+	// cond:
+	// result: (LEAQ2 y x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -1085,17 +1562,18 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (ADDQ x (ADDQconst [c] y))
+	// match: (ADDQ y (ADDQconst [c] x))
 	// cond:
 	// result: (LEAQ1 [c] x y)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		y := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
 		c := v_1.AuxInt
-		y := v_1.Args[0]
+		x := v_1.Args[0]
 		v.reset(OpAMD64LEAQ1)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -1106,6 +1584,7 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 	// cond: x.Op != OpSB && y.Op != OpSB
 	// result: (LEAQ1 [c] {s} x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64LEAQ {
@@ -1124,18 +1603,19 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (ADDQ (LEAQ [c] {s} x) y)
+	// match: (ADDQ (LEAQ [c] {s} y) x)
 	// cond: x.Op != OpSB && y.Op != OpSB
 	// result: (LEAQ1 [c] {s} x y)
 	for {
+		_ = v.Args[1]
 		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]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		if !(x.Op != OpSB && y.Op != OpSB) {
 			break
 		}
@@ -1146,10 +1626,14 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDQ_20(v *Value) bool {
 	// match: (ADDQ x (NEGQ y))
 	// cond:
 	// result: (SUBQ x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64NEGQ {
@@ -1161,11 +1645,77 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDQ (NEGQ y) x)
+	// cond:
+	// result: (SUBQ x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x l:(MOVQload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDQ l:(MOVQload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ADDQconst_0(v *Value) bool {
 	// match: (ADDQconst [c] (ADDQ x y))
 	// cond:
 	// result: (LEAQ1 [c] x y)
@@ -1175,6 +1725,7 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpAMD64LEAQ1)
@@ -1215,6 +1766,7 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1238,6 +1790,7 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1261,6 +1814,7 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1284,6 +1838,7 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(c + d)) {
@@ -1344,13 +1899,122 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ADDSD_0(v *Value) bool {
+	// match: (ADDSD x l:(MOVSDload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDSDmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSDload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDSDmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDSD l:(MOVSDload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDSDmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVSDload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDSDmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDSS_0(v *Value) bool {
+	// match: (ADDSS x l:(MOVSSload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDSSmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSSload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDSSmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDSS l:(MOVSSload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ADDSSmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVSSload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ADDSSmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ANDL_0(v *Value) bool {
 	// match: (ANDL x (MOVLconst [c]))
 	// cond:
 	// result: (ANDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVLconst {
@@ -1366,6 +2030,7 @@ func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVLconst {
 			break
@@ -1381,6 +2046,7 @@ func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -1390,11 +2056,61 @@ func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ANDL x l:(MOVLload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ANDLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ANDLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ANDL l:(MOVLload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ANDLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ANDLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ANDLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ANDLconst_0(v *Value) bool {
 	// match: (ANDLconst [c] (ANDLconst [d] x))
 	// cond:
 	// result: (ANDLconst [c & d] x)
@@ -1477,13 +2193,12 @@ func rewriteValueAMD64_OpAMD64ANDLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ANDQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ANDQ_0(v *Value) bool {
 	// match: (ANDQ x (MOVQconst [c]))
 	// cond: is32Bit(c)
 	// result: (ANDQconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVQconst {
@@ -1502,6 +2217,7 @@ func rewriteValueAMD64_OpAMD64ANDQ(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (ANDQconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVQconst {
 			break
@@ -1520,6 +2236,7 @@ func rewriteValueAMD64_OpAMD64ANDQ(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -1529,11 +2246,61 @@ func rewriteValueAMD64_OpAMD64ANDQ(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ANDQ x l:(MOVQload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ANDQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ANDQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ANDQ l:(MOVQload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ANDQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ANDQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ANDQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64ANDQconst_0(v *Value) bool {
 	// match: (ANDQconst [c] (ANDQconst [d] x))
 	// cond:
 	// result: (ANDQconst [c & d] x)
@@ -1626,19 +2393,120 @@ func rewriteValueAMD64_OpAMD64ANDQconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64BSFQ_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (CMPB x (MOVLconst [c]))
+	// match: (BSFQ (ORQconst <t> [1<<8] (MOVBQZX x)))
 	// cond:
-	// result: (CMPBconst x [int64(int8(c))])
+	// result: (BSFQ (ORQconst <t> [1<<8] x))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVLconst {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ORQconst {
 			break
 		}
-		c := v_1.AuxInt
+		t := v_0.Type
+		if v_0.AuxInt != 1<<8 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64MOVBQZX {
+			break
+		}
+		x := v_0_0.Args[0]
+		v.reset(OpAMD64BSFQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQconst, t)
+		v0.AuxInt = 1 << 8
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (BSFQ (ORQconst <t> [1<<16] (MOVWQZX x)))
+	// cond:
+	// result: (BSFQ (ORQconst <t> [1<<16] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ORQconst {
+			break
+		}
+		t := v_0.Type
+		if v_0.AuxInt != 1<<16 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64MOVWQZX {
+			break
+		}
+		x := v_0_0.Args[0]
+		v.reset(OpAMD64BSFQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQconst, t)
+		v0.AuxInt = 1 << 16
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64BTQconst_0(v *Value) bool {
+	// match: (BTQconst [c] x)
+	// cond: c < 32
+	// result: (BTLconst [c] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c < 32) {
+			break
+		}
+		v.reset(OpAMD64BTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMOVQEQ_0(v *Value) bool {
+	// match: (CMOVQEQ x _ (Select1 (BSFQ (ORQconst [c] _))))
+	// cond: c != 0
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpSelect1 {
+			break
+		}
+		v_2_0 := v_2.Args[0]
+		if v_2_0.Op != OpAMD64BSFQ {
+			break
+		}
+		v_2_0_0 := v_2_0.Args[0]
+		if v_2_0_0.Op != OpAMD64ORQconst {
+			break
+		}
+		c := v_2_0_0.AuxInt
+		if !(c != 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPB_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPB x (MOVLconst [c]))
+	// cond:
+	// result: (CMPBconst x [int64(int8(c))])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
 		v.reset(OpAMD64CMPBconst)
 		v.AuxInt = int64(int8(c))
 		v.AddArg(x)
@@ -1648,6 +2516,7 @@ func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPBconst x [int64(int8(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVLconst {
 			break
@@ -1655,7 +2524,7 @@ func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpAMD64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
 		v0.AuxInt = int64(int8(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1663,9 +2532,7 @@ func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPBconst_0(v *Value) bool {
 	// match: (CMPBconst (MOVLconst [x]) [y])
 	// cond: int8(x)==int8(y)
 	// result: (FlagEQ)
@@ -1773,6 +2640,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpAMD64TESTB)
@@ -1813,13 +2681,14 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPL x (MOVLconst [c]))
 	// cond:
 	// result: (CMPLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVLconst {
@@ -1835,6 +2704,7 @@ func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPLconst x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVLconst {
 			break
@@ -1842,7 +2712,7 @@ func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpAMD64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1850,9 +2720,7 @@ func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPLconst_0(v *Value) bool {
 	// match: (CMPLconst (MOVLconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -1976,6 +2844,7 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpAMD64TESTL)
@@ -2016,13 +2885,14 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPQ_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPQ x (MOVQconst [c]))
 	// cond: is32Bit(c)
 	// result: (CMPQconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVQconst {
@@ -2041,6 +2911,7 @@ func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (InvertFlags (CMPQconst x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVQconst {
 			break
@@ -2051,7 +2922,7 @@ func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpAMD64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2059,9 +2930,63 @@ func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPQconst_0(v *Value) bool {
+	// match: (CMPQconst (NEGQ (ADDQconst [-16] (ANDQconst [15] _))) [32])
+	// cond:
+	// result: (FlagLT_ULT)
+	for {
+		if v.AuxInt != 32 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0.AuxInt != -16 {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 15 {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (NEGQ (ADDQconst [ -8] (ANDQconst [7] _))) [32])
+	// cond:
+	// result: (FlagLT_ULT)
+	for {
+		if v.AuxInt != 32 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0.AuxInt != -8 {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 7 {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
 	// match: (CMPQconst (MOVQconst [x]) [y])
 	// cond: x==y
 	// result: (FlagEQ)
@@ -2187,6 +3112,9 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
 		v.reset(OpAMD64FlagLT_ULT)
 		return true
 	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPQconst_10(v *Value) bool {
 	// match: (CMPQconst (SHRQconst _ [c]) [n])
 	// cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
 	// result: (FlagLT_ULT)
@@ -2219,6 +3147,22 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
 		v.reset(OpAMD64FlagLT_ULT)
 		return true
 	}
+	// match: (CMPQconst (ANDLconst _ [m]) [n])
+	// cond: 0 <= m && m < n
+	// result: (FlagLT_ULT)
+	for {
+		n := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		m := v_0.AuxInt
+		if !(0 <= m && m < n) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
 	// match: (CMPQconst (ANDQ x y) [0])
 	// cond:
 	// result: (TESTQ x y)
@@ -2230,6 +3174,7 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ANDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpAMD64TESTQ)
@@ -2270,13 +3215,14 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPW_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPW x (MOVLconst [c]))
 	// cond:
 	// result: (CMPWconst x [int64(int16(c))])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVLconst {
@@ -2292,6 +3238,7 @@ func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPWconst x [int64(int16(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVLconst {
 			break
@@ -2299,7 +3246,7 @@ func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpAMD64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
 		v0.AuxInt = int64(int16(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2307,9 +3254,7 @@ func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPWconst_0(v *Value) bool {
 	// match: (CMPWconst (MOVLconst [x]) [y])
 	// cond: int16(x)==int16(y)
 	// result: (FlagEQ)
@@ -2417,6 +3362,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ANDL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpAMD64TESTW)
@@ -2457,15 +3403,14 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPXCHGLlock(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPXCHGLlock_0(v *Value) bool {
 	// match: (CMPXCHGLlock [off1] {sym} (ADDQconst [off2] ptr) old new_ mem)
 	// cond: is32Bit(off1+off2)
 	// result: (CMPXCHGLlock [off1+off2] {sym} ptr old new_ mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -2489,15 +3434,14 @@ func rewriteValueAMD64_OpAMD64CMPXCHGLlock(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64CMPXCHGQlock(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64CMPXCHGQlock_0(v *Value) bool {
 	// match: (CMPXCHGQlock [off1] {sym} (ADDQconst [off2] ptr) old new_ mem)
 	// cond: is32Bit(off1+off2)
 	// result: (CMPXCHGQlock [off1+off2] {sym} ptr old new_ mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -2521,9 +3465,7 @@ func rewriteValueAMD64_OpAMD64CMPXCHGQlock(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAL_0(v *Value) bool {
 	// match: (LEAL [c] {s} (ADDLconst [d] x))
 	// cond: is32Bit(c+d)
 	// result: (LEAL [c+d] {s} x)
@@ -2547,9 +3489,7 @@ func rewriteValueAMD64_OpAMD64LEAL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAQ_0(v *Value) bool {
 	// match: (LEAQ [c] {s} (ADDQconst [d] x))
 	// cond: is32Bit(c+d)
 	// result: (LEAQ [c+d] {s} x)
@@ -2581,6 +3521,7 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(x.Op != OpSB && y.Op != OpSB) {
@@ -2627,6 +3568,7 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -2651,6 +3593,7 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -2675,6 +3618,7 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -2699,6 +3643,7 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
@@ -2713,15 +3658,14 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAQ1_0(v *Value) bool {
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -2739,20 +3683,21 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAQ1 [c] {s} x (ADDQconst [d] y))
-	// cond: is32Bit(c+d)   && y.Op != OpSB
+	// match: (LEAQ1 [c] {s} y (ADDQconst [d] x))
+	// cond: is32Bit(c+d)   && x.Op != OpSB
 	// result: (LEAQ1 [c+d] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
-		x := v.Args[0]
+		_ = v.Args[1]
+		y := 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) {
+		x := v_1.Args[0]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
 			break
 		}
 		v.reset(OpAMD64LEAQ1)
@@ -2768,6 +3713,7 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -2784,12 +3730,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAQ1 [c] {s} (SHLQconst [1] x) y)
+	// match: (LEAQ1 [c] {s} (SHLQconst [1] y) x)
 	// cond:
-	// result: (LEAQ2 [c] {s} y x)
+	// result: (LEAQ2 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64SHLQconst {
 			break
@@ -2797,13 +3744,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 1 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(OpAMD64LEAQ2)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAQ1 [c] {s} x (SHLQconst [2] y))
@@ -2812,6 +3759,7 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -2828,12 +3776,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAQ1 [c] {s} (SHLQconst [2] x) y)
+	// match: (LEAQ1 [c] {s} (SHLQconst [2] y) x)
 	// cond:
-	// result: (LEAQ4 [c] {s} y x)
+	// result: (LEAQ4 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64SHLQconst {
 			break
@@ -2841,13 +3790,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 2 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(OpAMD64LEAQ4)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAQ1 [c] {s} x (SHLQconst [3] y))
@@ -2856,6 +3805,7 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -2872,12 +3822,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAQ1 [c] {s} (SHLQconst [3] x) y)
+	// match: (LEAQ1 [c] {s} (SHLQconst [3] y) x)
 	// cond:
-	// result: (LEAQ8 [c] {s} y x)
+	// result: (LEAQ8 [c] {s} x y)
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64SHLQconst {
 			break
@@ -2885,13 +3836,13 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		if v_0.AuxInt != 3 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v.Args[1]
+		y := v_0.Args[0]
+		x := v.Args[1]
 		v.reset(OpAMD64LEAQ8)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(y)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	// match: (LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
@@ -2900,6 +3851,7 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -2918,21 +3870,22 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (LEAQ1 [off1] {sym1} x (LEAQ [off2] {sym2} y))
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+	// match: (LEAQ1 [off1] {sym1} y (LEAQ [off2] {sym2} x))
+	// 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
-		x := v.Args[0]
+		_ = v.Args[1]
+		y := 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) {
+		x := v_1.Args[0]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
 			break
 		}
 		v.reset(OpAMD64LEAQ1)
@@ -2944,15 +3897,14 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAQ2_0(v *Value) bool {
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -2976,6 +3928,7 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -2999,6 +3952,7 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -3021,6 +3975,7 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -3043,6 +3998,7 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3063,15 +4019,14 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAQ4_0(v *Value) bool {
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -3095,6 +4050,7 @@ func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -3118,6 +4074,7 @@ func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -3140,6 +4097,7 @@ func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3160,15 +4118,14 @@ func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64LEAQ8_0(v *Value) bool {
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -3192,6 +4149,7 @@ func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -3215,6 +4173,7 @@ func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3235,7 +4194,7 @@ func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBQSX_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBQSX x:(MOVBload [off] {sym} ptr mem))
@@ -3248,13 +4207,14 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBQSXload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3273,13 +4233,14 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBQSXload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3298,13 +4259,14 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBQSXload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3323,13 +4285,14 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBQSXload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3356,17 +4319,53 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MOVBQSX x:(MOVBQSX _))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQSX {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64MOVBQSXload_0(v *Value) bool {
+	// match: (MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBQSX x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVBstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3387,7 +4386,7 @@ func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBQZX_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBQZX x:(MOVBload [off] {sym} ptr mem))
@@ -3400,13 +4399,14 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3425,13 +4425,14 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3450,13 +4451,14 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3475,13 +4477,14 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		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)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3500,6 +4503,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[2]
 		ptr := x.Args[0]
 		idx := x.Args[1]
 		mem := x.Args[2]
@@ -3507,7 +4511,7 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpAMD64MOVBloadidx1, v.Type)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3532,17 +4536,29 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MOVBQZX x:(MOVBQZX _))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQZX {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64MOVBload_0(v *Value) bool {
 	// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
 	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: x
+	// result: (MOVBQZX x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVBstore {
@@ -3550,22 +4566,23 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		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.reset(OpAMD64MOVBQZX)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -3583,12 +4600,13 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3613,12 +4631,14 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -3639,10 +4659,12 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -3657,12 +4679,13 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// match: (MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
 	// cond: canMergeSym(sym1, sym2)
 	// result: (MOVBload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAL {
 			break
@@ -3681,12 +4704,13 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBload  [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// match: (MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDLconst {
 			break
@@ -3706,15 +4730,14 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64MOVBloadidx1_0(v *Value) bool {
 	// 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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -3731,19 +4754,20 @@ func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// match: (MOVBloadidx1 [c] {sym} idx (ADDQconst [d] ptr) mem)
 	// cond:
 	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
+		_ = v.Args[2]
+		idx := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
 		d := v_1.AuxInt
-		idx := v_1.Args[0]
+		ptr := v_1.Args[0]
 		mem := v.Args[2]
 		v.reset(OpAMD64MOVBloadidx1)
 		v.AuxInt = c + d
@@ -3753,38 +4777,86 @@ func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
 		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)
+	// match: (MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVBstore [off] {sym} ptr x mem)
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVBQSX {
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		x := v_1.Args[0]
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVBstore)
-		v.AuxInt = off
+		v.reset(OpAMD64MOVBloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(x)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore [off] {sym} ptr (MOVBQZX x) mem)
+	// match: (MOVBloadidx1 [c] {sym} (ADDQconst [d] idx) ptr mem)
 	// cond:
-	// result: (MOVBstore [off] {sym} ptr x mem)
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off := v.AuxInt
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstore_0(v *Value) 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
+		_ = v.Args[2]
+		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
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVBQZX {
@@ -3800,12 +4872,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// 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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -3831,6 +4904,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVLconst {
@@ -3848,12 +4922,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// 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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -3880,12 +4955,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -3908,10 +4985,12 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -3928,12 +5007,61 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore [i] {s} p w   x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w)   x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w)   x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
+	// match: (MOVBstore [i] {s} p w x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
+	// cond: x0.Uses == 1   && clobber(x0)
+	// result: (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w := v.Args[1]
+		x0 := v.Args[2]
+		if x0.Op != OpAMD64MOVBstore {
+			break
+		}
+		if x0.AuxInt != i-1 {
+			break
+		}
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		x0_1 := x0.Args[1]
+		if x0_1.Op != OpAMD64SHRWconst {
+			break
+		}
+		if x0_1.AuxInt != 8 {
+			break
+		}
+		if w != x0_1.Args[0] {
+			break
+		}
+		mem := x0.Args[2]
+		if !(x0.Uses == 1 && clobber(x0)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, w.Type)
+		v0.AuxInt = 8
+		v0.AddArg(w)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [i] {s} p w x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w) x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w) x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
 	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && clobber(x0)   && clobber(x1)   && clobber(x2)
 	// result: (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w := v.Args[1]
 		x2 := v.Args[2]
@@ -3946,6 +5074,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[2]
 		if p != x2.Args[0] {
 			break
 		}
@@ -3969,6 +5098,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
@@ -3992,6 +5122,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x0.Aux != s {
 			break
 		}
+		_ = x0.Args[2]
 		if p != x0.Args[0] {
 			break
 		}
@@ -4013,18 +5144,19 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AuxInt = i - 3
 		v.Aux = s
 		v.AddArg(p)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPL, w.Type)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, w.Type)
 		v0.AddArg(w)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore [i] {s} p w   x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w)   x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w)   x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w)   x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w)   x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w)   x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w)   x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
+	// match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
 	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && x4.Uses == 1   && x5.Uses == 1   && x6.Uses == 1   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(x3)   && clobber(x4)   && clobber(x5)   && clobber(x6)
 	// result: (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w := v.Args[1]
 		x6 := v.Args[2]
@@ -4037,6 +5169,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x6.Aux != s {
 			break
 		}
+		_ = x6.Args[2]
 		if p != x6.Args[0] {
 			break
 		}
@@ -4060,6 +5193,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x5.Aux != s {
 			break
 		}
+		_ = x5.Args[2]
 		if p != x5.Args[0] {
 			break
 		}
@@ -4083,6 +5217,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x4.Aux != s {
 			break
 		}
+		_ = x4.Args[2]
 		if p != x4.Args[0] {
 			break
 		}
@@ -4106,6 +5241,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[2]
 		if p != x3.Args[0] {
 			break
 		}
@@ -4129,6 +5265,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[2]
 		if p != x2.Args[0] {
 			break
 		}
@@ -4152,6 +5289,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
@@ -4175,6 +5313,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x0.Aux != s {
 			break
 		}
+		_ = x0.Args[2]
 		if p != x0.Args[0] {
 			break
 		}
@@ -4196,18 +5335,22 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AuxInt = i - 7
 		v.Aux = s
 		v.AddArg(p)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPQ, w.Type)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, w.Type)
 		v0.AddArg(w)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstore_10(v *Value) bool {
 	// 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
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHRQconst {
@@ -4227,6 +5370,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -4251,6 +5395,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHRQconst {
@@ -4268,6 +5413,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -4293,12 +5439,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// match: (MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: canMergeSym(sym1, sym2)
 	// result: (MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAL {
 			break
@@ -4319,12 +5466,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
+	// match: (MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDLconst {
 			break
@@ -4346,15 +5494,14 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64MOVBstoreconst_0(v *Value) bool {
 	// 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -4378,6 +5525,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		sc := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -4402,12 +5550,14 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		x := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -4428,10 +5578,12 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -4449,6 +5601,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		p := v.Args[0]
 		x := v.Args[1]
 		if x.Op != OpAMD64MOVBstoreconst {
@@ -4458,6 +5611,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[1]
 		if p != x.Args[0] {
 			break
 		}
@@ -4478,6 +5632,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		sc := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAL {
 			break
@@ -4502,6 +5657,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		sc := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDLconst {
 			break
@@ -4521,15 +5677,14 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1_0(v *Value) bool {
 	// 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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -4552,6 +5707,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool
 	for {
 		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -4574,6 +5730,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		i := v.Args[1]
 		x := v.Args[2]
@@ -4584,6 +5741,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -4604,7 +5762,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBstoreidx1_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
@@ -4613,6 +5771,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -4637,6 +5796,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -4655,43 +5815,45 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
 		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)
+	// match: (MOVBstoreidx1 [i] {s} p idx w x0:(MOVBstoreidx1 [i-1] {s} p idx (SHRWconst [8] w) mem))
+	// cond: x0.Uses == 1   && clobber(x0)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx (ROLWconst <w.Type> [8] w) mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpAMD64SHRQconst {
+		w := v.Args[2]
+		x0 := v.Args[3]
+		if x0.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		if v_2.AuxInt != 8 {
+		if x0.AuxInt != i-1 {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpAMD64MOVBstoreidx1 {
+		if x0.Aux != s {
 			break
 		}
-		if x.AuxInt != i-1 {
+		_ = x0.Args[3]
+		if p != x0.Args[0] {
 			break
 		}
-		if x.Aux != s {
+		if idx != x0.Args[1] {
 			break
 		}
-		if p != x.Args[0] {
+		x0_2 := x0.Args[2]
+		if x0_2.Op != OpAMD64SHRWconst {
 			break
 		}
-		if idx != x.Args[1] {
+		if x0_2.AuxInt != 8 {
 			break
 		}
-		if w != x.Args[2] {
+		if w != x0_2.Args[0] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		mem := x0.Args[3]
+		if !(x0.Uses == 1 && clobber(x0)) {
 			break
 		}
 		v.reset(OpAMD64MOVWstoreidx1)
@@ -4699,1966 +5861,1328 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, w.Type)
+		v0.AuxInt = 8
+		v0.AddArg(w)
+		v.AddArg(v0)
 		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)
+	// match: (MOVBstoreidx1 [i] {s} p idx w x2:(MOVBstoreidx1 [i-1] {s} p idx (SHRLconst [8] w) x1:(MOVBstoreidx1 [i-2] {s} p idx (SHRLconst [16] w) x0:(MOVBstoreidx1 [i-3] {s} p idx (SHRLconst [24] w) mem))))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && clobber(x0)   && clobber(x1)   && clobber(x2)
+	// result: (MOVLstoreidx1 [i-3] {s} p idx (BSWAPL <w.Type> w) mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpAMD64SHRQconst {
+		w := v.Args[2]
+		x2 := v.Args[3]
+		if x2.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpAMD64MOVBstoreidx1 {
+		if x2.AuxInt != i-1 {
 			break
 		}
-		if x.AuxInt != i-1 {
+		if x2.Aux != s {
 			break
 		}
-		if x.Aux != s {
+		_ = x2.Args[3]
+		if p != x2.Args[0] {
 			break
 		}
-		if p != x.Args[0] {
+		if idx != x2.Args[1] {
 			break
 		}
-		if idx != x.Args[1] {
+		x2_2 := x2.Args[2]
+		if x2_2.Op != OpAMD64SHRLconst {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpAMD64SHRQconst {
+		if x2_2.AuxInt != 8 {
 			break
 		}
-		if w0.AuxInt != j-8 {
+		if w != x2_2.Args[0] {
 			break
 		}
-		if w != w0.Args[0] {
+		x1 := x2.Args[3]
+		if x1.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if x1.AuxInt != i-2 {
 			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 {
+		if x1.Aux != s {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x1.Args[3]
+		if p != x1.Args[0] {
 			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 x:(MOVQload [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 != OpAMD64MOVQload {
+		if idx != x1.Args[1] {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		x1_2 := x1.Args[2]
+		if x1_2.Op != OpAMD64SHRLconst {
 			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 {
+		if x1_2.AuxInt != 16 {
 			break
 		}
-		c := v_0.AuxInt
-		x := v_0.Args[0]
-		if !(c&0x80000000 == 0) {
+		if w != x1_2.Args[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 {
+		x0 := x1.Args[3]
+		if x0.Op != OpAMD64MOVBstoreidx1 {
 			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)) {
+		if x0.AuxInt != i-3 {
 			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 {
+		if x0.Aux != s {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x0.Args[3]
+		if p != x0.Args[0] {
 			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:(MOVQload [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 != OpAMD64MOVQload {
-			break
-		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		if idx != x0.Args[1] {
 			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 {
+		x0_2 := x0.Args[2]
+		if x0_2.Op != OpAMD64SHRLconst {
 			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)) {
+		if x0_2.AuxInt != 24 {
 			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 {
+		if w != x0_2.Args[0] {
 			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)) {
+		mem := x0.Args[3]
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0) && clobber(x1) && clobber(x2)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx4, v.Type)
-		v.reset(OpCopy)
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 3
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, w.Type)
+		v0.AddArg(w)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLQZX (ANDLconst [c] x))
-	// cond:
-	// result: (ANDLconst [c] x)
+	// match: (MOVBstoreidx1 [i] {s} p idx w x6:(MOVBstoreidx1 [i-1] {s} p idx (SHRQconst [8] w) x5:(MOVBstoreidx1 [i-2] {s} p idx (SHRQconst [16] w) x4:(MOVBstoreidx1 [i-3] {s} p idx (SHRQconst [24] w) x3:(MOVBstoreidx1 [i-4] {s} p idx (SHRQconst [32] w) x2:(MOVBstoreidx1 [i-5] {s} p idx (SHRQconst [40] w) x1:(MOVBstoreidx1 [i-6] {s} p idx (SHRQconst [48] w) x0:(MOVBstoreidx1 [i-7] {s} p idx (SHRQconst [56] w) mem))))))))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && x4.Uses == 1   && x5.Uses == 1   && x6.Uses == 1   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(x3)   && clobber(x4)   && clobber(x5)   && clobber(x6)
+	// result: (MOVQstoreidx1 [i-7] {s} p idx (BSWAPQ <w.Type> w) mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ANDLconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x6 := v.Args[3]
+		if x6.Op != OpAMD64MOVBstoreidx1 {
 			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_OpAMD64MOVLatomicload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVLatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVLatomicload [off1+off2] {sym} ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if x6.AuxInt != i-1 {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		if x6.Aux != s {
 			break
 		}
-		v.reset(OpAMD64MOVLatomicload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVLatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ {
+		_ = x6.Args[3]
+		if p != x6.Args[0] {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+		if idx != x6.Args[1] {
 			break
 		}
-		v.reset(OpAMD64MOVLatomicload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		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 {
+		x6_2 := x6.Args[2]
+		if x6_2.Op != OpAMD64SHRQconst {
 			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)) {
+		if x6_2.AuxInt != 8 {
 			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 {
+		if w != x6_2.Args[0] {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		x5 := x6.Args[3]
+		if x5.Op != OpAMD64MOVBstoreidx1 {
 			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 {
+		if x5.AuxInt != i-2 {
 			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)) {
+		if x5.Aux != s {
 			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 {
+		_ = x5.Args[3]
+		if p != x5.Args[0] {
 			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)) {
+		if idx != x5.Args[1] {
 			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 {
+		x5_2 := x5.Args[2]
+		if x5_2.Op != OpAMD64SHRQconst {
 			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)) {
+		if x5_2.AuxInt != 16 {
 			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 {
+		if w != x5_2.Args[0] {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		x4 := x5.Args[3]
+		if x4.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		v.reset(OpAMD64MOVLloadidx1)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-	// cond: 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 != OpAMD64LEAL {
+		if x4.AuxInt != i-3 {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2)) {
+		if x4.Aux != s {
 			break
 		}
-		v.reset(OpAMD64MOVLload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLload  [off1] {sym} (ADDLconst [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 != OpAMD64ADDLconst {
+		_ = x4.Args[3]
+		if p != x4.Args[0] {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		if idx != x4.Args[1] {
 			break
 		}
-		v.reset(OpAMD64MOVLload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		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 {
+		x4_2 := x4.Args[2]
+		if x4_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if v_1.AuxInt != 2 {
+		if x4_2.AuxInt != 24 {
 			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 {
+		if w != x4_2.Args[0] {
 			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 {
+		x3 := x4.Args[3]
+		if x3.Op != OpAMD64MOVBstoreidx1 {
 			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 {
+		if x3.AuxInt != i-4 {
 			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 {
+		if x3.Aux != s {
 			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 {
+		_ = x3.Args[3]
+		if p != x3.Args[0] {
 			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 {
+		if idx != x3.Args[1] {
 			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 {
+		x3_2 := x3.Args[2]
+		if x3_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		if x3_2.AuxInt != 32 {
 			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 {
+		if w != x3_2.Args[0] {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validOff(off)) {
+		x2 := x3.Args[3]
+		if x2.Op != OpAMD64MOVBstoreidx1 {
 			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 {
+		if x2.AuxInt != i-5 {
 			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)) {
+		if x2.Aux != s {
 			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 {
+		_ = x2.Args[3]
+		if p != x2.Args[0] {
 			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)) {
+		if idx != x2.Args[1] {
 			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 {
+		x2_2 := x2.Args[2]
+		if x2_2.Op != OpAMD64SHRQconst {
 			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)) {
+		if x2_2.AuxInt != 40 {
 			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 {
+		if w != x2_2.Args[0] {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		x1 := x2.Args[3]
+		if x1.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreidx1)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
+		if x1.AuxInt != i-6 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[3]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		x1_2 := x1.Args[2]
+		if x1_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if x1_2.AuxInt != 48 {
+			break
+		}
+		if w != x1_2.Args[0] {
+			break
+		}
+		x0 := x1.Args[3]
+		if x0.Op != OpAMD64MOVBstoreidx1 {
+			break
+		}
+		if x0.AuxInt != i-7 {
+			break
+		}
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[3]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		x0_2 := x0.Args[2]
+		if x0_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if x0_2.AuxInt != 56 {
+			break
+		}
+		if w != x0_2.Args[0] {
+			break
+		}
+		mem := x0.Args[3]
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = i - 7
+		v.Aux = s
+		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, w.Type)
+		v0.AddArg(w)
+		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
+	// 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: (MOVQstore [i-4] {s} p w mem)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHRQconst {
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if v_1.AuxInt != 32 {
+		if v_2.AuxInt != 8 {
 			break
 		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpAMD64MOVLstore {
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		if x.AuxInt != i-4 {
+		if x.AuxInt != i-1 {
 			break
 		}
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
-		if w != x.Args[1] {
+		if idx != x.Args[1] {
 			break
 		}
-		mem := x.Args[2]
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstore)
-		v.AuxInt = i - 4
+		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: (MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
+	// 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: (MOVQstore [i-4] {s} p w0 mem)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHRQconst {
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		j := v_1.AuxInt
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpAMD64MOVLstore {
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVBstoreidx1 {
 			break
 		}
-		if x.AuxInt != i-4 {
+		if x.AuxInt != i-1 {
 			break
 		}
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
-		w0 := x.Args[1]
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
 		if w0.Op != OpAMD64SHRQconst {
 			break
 		}
-		if w0.AuxInt != j-32 {
+		if w0.AuxInt != j-8 {
 			break
 		}
 		if w != w0.Args[0] {
 			break
 		}
-		mem := x.Args[2]
+		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstore)
-		v.AuxInt = i - 4
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = i - 1
 		v.Aux = s
 		v.AddArg(p)
+		v.AddArg(idx)
 		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-	// cond: canMergeSym(sym1, sym2)
-	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLQSX_0(v *Value) 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 {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAL {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLload {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2)) {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVLstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
+	// match: (MOVLQSX x:(MOVQload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDLconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVQload {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVLstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.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)
+	// match: (MOVLQSX (ANDLconst [c] x))
+	// cond: c & 0x80000000 == 0
+	// result: (ANDLconst [c & 0x7fffffff] x)
 	for {
-		sc := v.AuxInt
-		sym1 := v.Aux
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ {
+		if v_0.Op != OpAMD64ANDLconst {
 			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)) {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x80000000 == 0) {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0x7fffffff
+		v.AddArg(x)
 		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)
+	// match: (MOVLQSX x:(MOVLQSX _))
+	// cond:
+	// result: x
 	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)) {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLQSX {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+	// match: (MOVLQSX x:(MOVWQSX _))
+	// cond:
+	// result: x
 	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)) {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWQSX {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreconstidx4)
-		v.AuxInt = ValAndOff(x).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// match: (MOVLQSX x:(MOVBQSX _))
 	// cond:
-	// result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+	// result: x
 	for {
-		x := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQ {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQSX {
 			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)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLQSXload_0(v *Value) bool {
+	// match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVLQSX x)
 	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] {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLstore {
 			break
 		}
-		mem := x.Args[1]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			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)
+		v.reset(OpAMD64MOVLQSX)
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
-	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	// 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 {
-		sc := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAL {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
-		ptr := v_0.Args[0]
+		base := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
+		v.reset(OpAMD64MOVLQSXload)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVLstoreconst [sc] {s} (ADDLconst [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 != OpAMD64ADDLconst {
-			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(base)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLQZX_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
-	// cond:
-	// result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLload {
 			break
 		}
-		if v_1.AuxInt != 2 {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
-	// cond:
-	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// match: (MOVLQZX x:(MOVQload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
 	for {
-		x := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVQload {
 			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 {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.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)
+	// 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 {
-		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 {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLloadidx1 {
 			break
 		}
-		if p != x.Args[0] {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if i != x.Args[1] {
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, 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
+		_ = x.Args[2]
+		ptr := x.Args[0]
+		idx := x.Args[1]
 		mem := x.Args[2]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+		if !(x.Uses == 1 && 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
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(mem)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.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)
+	// match: (MOVLQZX (ANDLconst [c] x))
 	// cond:
-	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (ANDLconst [c] x)
 	for {
-		x := v.AuxInt
-		sym := v.Aux
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64ANDLconst {
 			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)
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// match: (MOVLQZX x:(MOVLQZX _))
 	// cond:
-	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+	// result: x
 	for {
-		x := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLQZX {
 			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)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+	// match: (MOVLQZX x:(MOVWQZX _))
+	// cond:
+	// result: x
 	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] {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWQZX {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVLQZX x:(MOVBQZX _))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQZX {
 			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)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+func rewriteValueAMD64_OpAMD64MOVLatomicload_0(v *Value) bool {
+	// match: (MOVLatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLatomicload [off1+off2] {sym} ptr mem)
 	for {
-		c := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if v_1.AuxInt != 2 {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64MOVLstoreidx4)
-		v.AuxInt = c
+		v.reset(OpAMD64MOVLatomicload)
+		v.AuxInt = off1 + off2
 		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)
+	// match: (MOVLatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		d := v_0.AuxInt
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
 		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 {
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			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.reset(OpAMD64MOVLatomicload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLload_0(v *Value) bool {
+	// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVLQZX x)
 	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 {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLstore {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpAMD64MOVLstoreidx1 {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		if x.AuxInt != i-4 {
+		v.reset(OpAMD64MOVLQZX)
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x.Aux != s {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		if p != x.Args[0] {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		if idx != x.Args[1] {
+		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
 		}
-		if w != x.Args[2] {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreidx1)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
 		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)
+	// 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 {
-		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] {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
 			break
 		}
-		if idx != x.Args[1] {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpAMD64SHRQconst {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
-		if w0.AuxInt != j-32 {
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
 			break
 		}
-		if w != w0.Args[0] {
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVLload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreidx1)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
+		v.reset(OpAMD64MOVLload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
 		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)
+	// match: (MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLload  [off1+off2] {sym} ptr mem)
 	for {
-		c := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		d := v_0.AuxInt
+		off2 := 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
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLload)
+		v.AuxInt = off1 + off2
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLloadidx1_0(v *Value) bool {
+	// match: (MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
 	// cond:
-	// result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
+	// result: (MOVLloadidx4 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
 			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
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = c
 		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)
+	// match: (MOVLloadidx1 [c] {sym} (SHLQconst [2] idx) ptr mem)
+	// cond:
+	// result: (MOVLloadidx4 [c] {sym} ptr idx 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] {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if v_0.AuxInt != 2 {
 			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)
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		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)
+	// match: (MOVLloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_0.AuxInt
+		d := v_0.AuxInt
 		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
-			break
-		}
-		v.reset(OpAMD64MOVOload)
-		v.AuxInt = off1 + off2
+		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: (MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// match: (MOVLloadidx1 [c] {sym} idx (ADDQconst [d] ptr) mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx 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)) {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVOload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
+		d := v_1.AuxInt
+		ptr := 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_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)
+	// match: (MOVLloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
 		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
-			break
-		}
-		v.reset(OpAMD64MOVOstore)
-		v.AuxInt = off1 + off2
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(val)
+		v.AddArg(idx)
 		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)
+	// match: (MOVLloadidx1 [c] {sym} (ADDQconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		val := v.Args[1]
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := 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.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVQatomicload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVQatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVQatomicload [off1+off2] {sym} ptr mem)
+func rewriteValueAMD64_OpAMD64MOVLloadidx4_0(v *Value) bool {
+	// match: (MOVLloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_0.AuxInt
+		d := v_0.AuxInt
 		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
-			break
-		}
-		v.reset(OpAMD64MOVQatomicload)
-		v.AuxInt = off1 + off2
+		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: (MOVQatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVQatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+	// match: (MOVLloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVLloadidx4 [c+4*d] {sym} ptr idx 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
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVQatomicload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		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_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
+func rewriteValueAMD64_OpAMD64MOVLstore_0(v *Value) bool {
+	// match: (MOVLstore [off] {sym} ptr (MOVLQSX x) mem)
+	// cond:
+	// result: (MOVLstore [off] {sym} ptr x mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVQstore {
+		if v_1.Op != OpAMD64MOVLQSX {
 			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)) {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLQZX {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		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: (MOVQload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// match: (MOVLstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVQload  [off1+off2] {sym} ptr mem)
+	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQload)
+		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
+		_ = v.Args[2]
+		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: (MOVQload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -6666,99 +7190,212 @@ func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQload)
+		v.reset(OpAMD64MOVLstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQloadidx1)
+		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: (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+	// match: (MOVLstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ8 {
+		if v_0.Op != OpAMD64LEAQ4 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQloadidx8)
+		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: (MOVQload [off] {sym} (ADDQ ptr idx) mem)
+	// match: (MOVLstore [off] {sym} (ADDQ ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVQloadidx1 [off] {sym} ptr idx mem)
+	// result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVQloadidx1)
+		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
+		_ = v.Args[2]
+		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
+		}
+		_ = x.Args[2]
+		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
+		_ = v.Args[2]
+		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
+		}
+		_ = x.Args[2]
+		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
 	}
-	// match: (MOVQload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
+	// match: (MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
 	// cond: canMergeSym(sym1, sym2)
-	// result: (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAL {
 			break
@@ -6766,705 +7403,672 @@ func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		mem := v.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQload)
+		v.reset(OpAMD64MOVLstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQload  [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// match: (MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVQload  [off1+off2] {sym} ptr mem)
+	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQload)
+		v.reset(OpAMD64MOVLstore)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVQloadidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLstoreconst_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
-	// cond:
-	// result: (MOVQloadidx8 [c] {sym} ptr idx mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVLstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if v_1.AuxInt != 3 {
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			break
 		}
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQloadidx8)
-		v.AuxInt = c
-		v.Aux = sym
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
 		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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		d := v_0.AuxInt
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
+		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(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
-	// cond:
-	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQloadidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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
 	}
-	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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64LEAQ4 {
 			break
 		}
-		d := v_0.AuxInt
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQloadidx8)
-		v.AuxInt = c + d
-		v.Aux = sym
+		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: (MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// match: (MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem)
 	// cond:
-	// result: (MOVQloadidx8 [c+8*d] {sym} ptr idx mem)
+	// result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
 	for {
-		c := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQloadidx8)
-		v.AuxInt = c + 8*d
+		_ = v_0.Args[1]
+		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
 	}
-	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)
+	// 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 {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpAMD64MOVLstoreconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		a := x.AuxInt
+		if x.Aux != s {
 			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 {
+		_ = x.Args[1]
+		if p != x.Args[0] {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validValAndOff(c, off)) {
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreconst)
-		v.AuxInt = makeValAndOff(c, off)
-		v.Aux = sym
-		v.AddArg(ptr)
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v0)
 		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)
+	// match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
 	for {
-		off1 := v.AuxInt
+		sc := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ {
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		off2 := v_0.AuxInt
+		off := 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)) {
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstore)
-		v.AuxInt = off1 + off2
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
 		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
+		v.AddArg(ptr)
 		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)
+	// match: (MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ1 {
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
+		off := v_0.AuxInt
 		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)) {
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreidx1)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ8 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			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)) {
+		if v_1.AuxInt != 2 {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreidx8)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		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(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)
+	// match: (MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQ {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
+		c := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
+		idx := v.Args[1]
 		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
-			break
-		}
-		v.reset(OpAMD64MOVQstoreidx1)
-		v.AuxInt = off
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-	// cond: 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 != OpAMD64LEAL {
-			break
-		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(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] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVQstore  [off1+off2] {sym} ptr val mem)
+	// match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDLconst {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
 		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
-			break
-		}
-		v.reset(OpAMD64MOVQstore)
-		v.AuxInt = off1 + off2
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(val)
+		v.AddArg(idx)
 		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)
+	// 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 {
-		sc := v.AuxInt
+		c := 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)) {
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstoreconstidx1 {
 			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 {
+		a := x.AuxInt
+		if x.Aux != s {
 			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)) {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			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 {
+		if i != x.Args[1] {
 			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)) {
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v0)
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx4_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVLstoreconstidx4 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
 		x := v.AuxInt
-		sym1 := v.Aux
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ8 {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off := v_0.AuxInt
-		sym2 := v_0.Aux
+		c := v_0.AuxInt
 		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)
+		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: (MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem)
 	// cond:
-	// result: (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
 	for {
 		x := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQ {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		v.reset(OpAMD64MOVQstoreconstidx1)
-		v.AuxInt = x
+		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: (MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
-	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	// 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 {
-		sc := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAL {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstoreconstidx4 {
 			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)) {
+		a := x.AuxInt
+		if x.Aux != s {
 			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 [sc] {s} (ADDLconst [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 != OpAMD64ADDLconst {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		off := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		if i != x.Args[1] {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
+		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(ptr)
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQconst, i.Type)
+		v0.AuxInt = 2
+		v0.AddArg(i)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v1.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v1)
 		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)
+func rewriteValueAMD64_OpAMD64MOVLstoreidx1_0(v *Value) bool {
+	// match: (MOVLstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem)
 	// cond:
-	// result: (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
+	// result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		if v_1.AuxInt != 3 {
+		if v_1.AuxInt != 2 {
 			break
 		}
 		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQstoreconstidx8)
+		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: (MOVQstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// match: (MOVLstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := 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)
+		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: (MOVQstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// match: (MOVLstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
 	// cond:
-	// result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_1.AuxInt
+		d := v_1.AuxInt
 		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVQstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		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
 	}
-	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)
+	// 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 {
-		x := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			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 {
+		if v_2.AuxInt != 32 {
 			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)
+		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
+		}
+		_ = x.Args[3]
+		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
 	}
-	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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if v_1.AuxInt != 3 {
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVLstoreidx1 {
 			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)
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(val)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreidx4_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -7474,7 +8078,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(OpAMD64MOVQstoreidx1)
+		v.reset(OpAMD64MOVLstoreidx4)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -7483,12 +8087,13 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVQstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// match: (MOVLstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
 	// cond:
-	// result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -7498,79 +8103,136 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(OpAMD64MOVQstoreidx1)
-		v.AuxInt = c + d
-		v.Aux = sym
+		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
 	}
-	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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			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)
+		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
+		}
+		_ = x.Args[3]
+		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.Pos, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 2
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w)
 		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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			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)
+		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
+		}
+		_ = x.Args[3]
+		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.Pos, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 2
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w0)
 		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)
+func rewriteValueAMD64_OpAMD64MOVOload_0(v *Value) bool {
+	// match: (MOVOload [off1] {sym} (ADDQconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVSDload [off1+off2] {sym} ptr mem)
+	// result: (MOVOload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -7581,19 +8243,20 @@ func rewriteValueAMD64_OpAMD64MOVSDload(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDload)
+		v.reset(OpAMD64MOVOload)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// match: (MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -7605,247 +8268,180 @@ func rewriteValueAMD64_OpAMD64MOVSDload(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDload)
+		v.reset(OpAMD64MOVOload)
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVOstore_0(v *Value) bool {
+	// 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
-		sym1 := v.Aux
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ1 {
+		if v_0.Op != OpAMD64ADDQconst {
 			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)) {
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDloadidx1)
+		v.reset(OpAMD64MOVOstore)
 		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+	// match: (MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVOstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ8 {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDloadidx8)
+		v.reset(OpAMD64MOVOstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
+		v.AddArg(base)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDload [off] {sym} (ADDQ ptr idx) mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQatomicload_0(v *Value) bool {
+	// match: (MOVQatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVQatomicload [off1+off2] {sym} ptr mem)
 	for {
-		off := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQ {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDloadidx1)
-		v.AuxInt = off
+		v.reset(OpAMD64MOVQatomicload)
+		v.AuxInt = off1 + off2
 		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} ptr (SHLQconst [3] idx) mem)
-	// cond:
-	// result: (MOVSDloadidx8 [c] {sym} ptr idx mem)
+	// match: (MOVQatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		if v_1.AuxInt != 3 {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpAMD64MOVSDloadidx8)
-		v.AuxInt = c
-		v.Aux = sym
+		v.reset(OpAMD64MOVQatomicload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQload_0(v *Value) bool {
+	// match: (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
 	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
+		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		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 {
+		if v_1.Op != OpAMD64MOVQstore {
 			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 {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			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)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+	// match: (MOVQload [off1] {sym} (ADDQconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVSDstore [off1+off2] {sym} ptr val mem)
+	// result: (MOVQload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		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]
+		mem := v.Args[1]
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDstore)
+		v.reset(OpAMD64MOVQload)
 		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)
+	// match: (MOVQload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// result: (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -7853,112 +8449,158 @@ func rewriteValueAMD64_OpAMD64MOVSDstore(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
 		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDstore)
+		v.reset(OpAMD64MOVQload)
 		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)
+	// match: (MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDstoreidx1)
+		v.reset(OpAMD64MOVQloadidx1)
 		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)
+	// match: (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSDstoreidx8)
+		v.reset(OpAMD64MOVQloadidx8)
 		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)
+	// match: (MOVQload [off] {sym} (ADDQ ptr idx) mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+	// result: (MOVQloadidx1 [off] {sym} ptr idx mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
+		mem := v.Args[1]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVSDstoreidx1)
+		v.reset(OpAMD64MOVQloadidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(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] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVQload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
+			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
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSDstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+func rewriteValueAMD64_OpAMD64MOVQloadidx1_0(v *Value) bool {
+	// match: (MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
 	// cond:
-	// result: (MOVSDstoreidx8 [c] {sym} ptr idx val mem)
+	// result: (MOVQloadidx8 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
@@ -7968,76 +8610,47 @@ func rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v *Value, config *Config) bool {
 			break
 		}
 		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64MOVSDstoreidx8)
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx8)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
-		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// match: (MOVQloadidx1 [c] {sym} (SHLQconst [3] idx) ptr mem)
 	// cond:
-	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVQloadidx8 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64SHLQconst {
 			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 {
+		if v_0.AuxInt != 3 {
 			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
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = c
 		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)
+	// match: (MOVQloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -8045,235 +8658,77 @@ func rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v *Value, config *Config) bool {
 		d := v_0.AuxInt
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64MOVSDstoreidx8)
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx1)
 		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)
+	// match: (MOVQloadidx1 [c] {sym} idx (ADDQconst [d] ptr) mem)
 	// cond:
-	// result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
+		_ = v.Args[2]
+		idx := 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
+		ptr := 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_OpAMD64MOVSSloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+	// match: (MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVSSloadidx4 [c] {sym} ptr idx mem)
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
-			break
-		}
-		if v_1.AuxInt != 2 {
+		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
+		v.reset(OpAMD64MOVQloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// match: (MOVQloadidx1 [c] {sym} (ADDQconst [d] idx) ptr mem)
 	// cond:
-	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		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]
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVSSloadidx1)
+		v.reset(OpAMD64MOVQloadidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -8283,15 +8738,14 @@ func rewriteValueAMD64_OpAMD64MOVSSloadidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+func rewriteValueAMD64_OpAMD64MOVQloadidx8_0(v *Value) bool {
+	// match: (MOVQloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+	// result: (MOVQloadidx8 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -8300,7 +8754,7 @@ func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVSSloadidx4)
+		v.reset(OpAMD64MOVQloadidx8)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -8308,12 +8762,13 @@ func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// match: (MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+	// result: (MOVQloadidx8 [c+8*d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -8322,8 +8777,8 @@ func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVSSloadidx4)
-		v.AuxInt = c + 4*d
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = c + 8*d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -8332,15 +8787,14 @@ func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+func rewriteValueAMD64_OpAMD64MOVQstore_0(v *Value) bool {
+	// match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVSSstore [off1+off2] {sym} ptr val mem)
+	// result: (MOVQstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -8352,7 +8806,7 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSSstore)
+		v.reset(OpAMD64MOVQstore)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -8360,12 +8814,37 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// 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
+		_ = v.Args[2]
+		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: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// result: (MOVQstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -8378,7 +8857,7 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSSstore)
+		v.reset(OpAMD64MOVQstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
@@ -8386,18 +8865,20 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVQstore [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)
+	// result: (MOVQstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -8405,7 +8886,7 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSSstoreidx1)
+		v.reset(OpAMD64MOVQstoreidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -8414,18 +8895,20 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVQstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ4 {
+		if v_0.Op != OpAMD64LEAQ8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -8433,7 +8916,7 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVSSstoreidx4)
+		v.reset(OpAMD64MOVQstoreidx8)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -8442,16 +8925,18 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstore [off] {sym} (ADDQ ptr idx) val mem)
+	// match: (MOVQstore [off] {sym} (ADDQ ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+	// result: (MOVQstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -8459,7 +8944,7 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVSSstoreidx1)
+		v.reset(OpAMD64MOVQstoreidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -8468,448 +8953,505 @@ func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVSSstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem)
-	// cond:
-	// result: (MOVSSstoreidx4 [c] {sym} ptr idx val mem)
+	// match: (MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVQstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
-		c := v.AuxInt
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(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] {sym} (ADDLconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVQstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64SHLQconst {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if v_1.AuxInt != 2 {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64MOVSSstoreidx4)
-		v.AuxInt = c
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconst_0(v *Value) bool {
+	// match: (MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		d := v_0.AuxInt
+		off := 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
+		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(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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			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
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
+		x := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		if v_0.Op != OpAMD64LEAQ8 {
 			break
 		}
-		d := v_0.AuxInt
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		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
+		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(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVSSstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// match: (MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem)
 	// cond:
-	// result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+	// result: (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
 	for {
-		c := v.AuxInt
+		x := v.AuxInt
 		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			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_0.Args[1]
+		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(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)
+	// match: (MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVWload {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		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
 		}
-		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)
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWQSX x:(MOVLload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+	// match: (MOVQstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVLload {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			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)
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWQSX x:(MOVQload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx1_0(v *Value) bool {
+	// match: (MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
+	// cond:
+	// result: (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVQload {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		if v_1.AuxInt != 3 {
 			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)
+		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: (MOVWQSX (ANDLconst [c] x))
-	// cond: c & 0x8000 == 0
-	// result: (ANDLconst [c & 0x7fff] x)
+	// 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.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ANDLconst {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v_0.Args[0]
-		if !(c&0x8000 == 0) {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64ANDLconst)
-		v.AuxInt = c & 0x7fff
-		v.AddArg(x)
+		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_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)
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx8_0(v *Value) bool {
+	// match: (MOVQstoreconstidx8 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVQstoreconstidx8 [ValAndOff(x).add(c)] {sym} ptr idx mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ {
+		if v_0.Op != OpAMD64ADDQconst {
 			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)) {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVWQSXload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
+		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_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)
+func rewriteValueAMD64_OpAMD64MOVQstoreidx1_0(v *Value) bool {
+	// match: (MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+	// cond:
+	// result: (MOVQstoreidx8 [c] {sym} ptr idx val mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVWload {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		if v_1.AuxInt != 3 {
 			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)
+		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: (MOVWQZX x:(MOVLload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+	// match: (MOVQstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVLload {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		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
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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)
+		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
 	}
-	// match: (MOVWQZX x:(MOVQload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreidx8_0(v *Value) bool {
+	// match: (MOVQstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVQstoreidx8 [c+d] {sym} ptr idx val mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpAMD64MOVQload {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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)
+		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: (MOVWQZX (ANDLconst [c] x))
+	// match: (MOVQstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
 	// 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
+	// result: (MOVQstoreidx8 [c+8*d] {sym} ptr idx val mem)
 	for {
-		off := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		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)) {
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		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
 	}
-	// match: (MOVWload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDload_0(v *Value) bool {
+	// match: (MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
-	// result: (MOVWload  [off1+off2] {sym} ptr mem)
+	// result: (MOVSDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -8920,19 +9462,20 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWload)
+		v.reset(OpAMD64MOVSDload)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// match: (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -8944,32 +9487,34 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWload)
+		v.reset(OpAMD64MOVSDload)
 		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)
+	// match: (MOVSDload [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)
+	// result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		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.reset(OpAMD64MOVSDloadidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -8977,25 +9522,27 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) mem)
+	// match: (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ2 {
+		if v_0.Op != OpAMD64LEAQ8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		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.reset(OpAMD64MOVSDloadidx8)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -9003,23 +9550,25 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload [off] {sym} (ADDQ ptr idx) mem)
+	// match: (MOVSDload [off] {sym} (ADDQ ptr idx) mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVWloadidx1 [off] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVWloadidx1)
+		v.reset(OpAMD64MOVSDloadidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9027,75 +9576,27 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWload  [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-	// cond: 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 != OpAMD64LEAL {
-			break
-		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		mem := v.Args[1]
-		if !(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] {sym} (ADDLconst [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 != OpAMD64ADDLconst {
-			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
-	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
+func rewriteValueAMD64_OpAMD64MOVSDloadidx1_0(v *Value) bool {
+	// match: (MOVSDloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
 	// cond:
-	// result: (MOVWloadidx2 [c] {sym} ptr idx mem)
+	// result: (MOVSDloadidx8 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		if v_1.AuxInt != 3 {
 			break
 		}
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWloadidx2)
+		v.reset(OpAMD64MOVSDloadidx8)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9103,12 +9604,13 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// match: (MOVSDloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -9117,7 +9619,7 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWloadidx1)
+		v.reset(OpAMD64MOVSDloadidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9125,12 +9627,13 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// match: (MOVSDloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -9139,7 +9642,7 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWloadidx1)
+		v.reset(OpAMD64MOVSDloadidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9149,15 +9652,14 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem)
+func rewriteValueAMD64_OpAMD64MOVSDloadidx8_0(v *Value) bool {
+	// match: (MOVSDloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -9166,7 +9668,7 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		idx := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWloadidx2)
+		v.reset(OpAMD64MOVSDloadidx8)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9174,12 +9676,13 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// match: (MOVSDloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+	// result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -9188,8 +9691,8 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
 		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWloadidx2)
-		v.AuxInt = c + 2*d
+		v.reset(OpAMD64MOVSDloadidx8)
+		v.AuxInt = c + 8*d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
@@ -9198,59 +9701,16 @@ func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
 	}
 	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)
+func rewriteValueAMD64_OpAMD64MOVSDstore_0(v *Value) bool {
+	// match: (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSDstore [off1+off2] {sym} ptr val mem)
 	for {
-		off := v.AuxInt
+		off1 := 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 {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
 		off2 := v_0.AuxInt
@@ -9260,7 +9720,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstore)
+		v.reset(OpAMD64MOVSDstore)
 		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9268,35 +9728,13 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		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)
+	// match: (MOVSDstore [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)
+	// result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ {
 			break
@@ -9309,7 +9747,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstore)
+		v.reset(OpAMD64MOVSDstore)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(base)
@@ -9317,18 +9755,20 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVSDstore [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)
+	// result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -9336,7 +9776,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreidx1)
+		v.reset(OpAMD64MOVSDstoreidx1)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -9345,18 +9785,20 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem)
+	// match: (MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ2 {
+		if v_0.Op != OpAMD64LEAQ8 {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -9364,7 +9806,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreidx2)
+		v.reset(OpAMD64MOVSDstoreidx8)
 		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
@@ -9373,16 +9815,18 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore [off] {sym} (ADDQ ptr idx) val mem)
+	// match: (MOVSDstore [off] {sym} (ADDQ ptr idx) val mem)
 	// cond: ptr.Op != OpSB
-	// result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+	// result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -9390,7 +9834,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreidx1)
+		v.reset(OpAMD64MOVSDstoreidx1)
 		v.AuxInt = off
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9399,371 +9843,294 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx1_0(v *Value) bool {
+	// match: (MOVSDstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+	// cond:
+	// result: (MOVSDstoreidx8 [c] {sym} ptr idx val mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := 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] {
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		if v_1.AuxInt != 3 {
 			break
 		}
-		v.reset(OpAMD64MOVLstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSDstoreidx8)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-	// cond: canMergeSym(sym1, sym2)
-	// result: (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	// match: (MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAL {
-			break
-		}
-		off2 := v_0.AuxInt
-		sym2 := v_0.Aux
-		base := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2)) {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVWstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
+		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: (MOVWstore  [off1] {sym} (ADDLconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
-	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	// match: (MOVSDstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
-		off1 := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDLconst {
-			break
-		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVWstore)
-		v.AuxInt = off1 + off2
+		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_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
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx8_0(v *Value) bool {
+	// 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.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off := v_0.AuxInt
+		d := 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
+		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: (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)
+	// match: (MOVSDstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val 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)) {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
+		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
 	}
-	// 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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSload_0(v *Value) bool {
+	// match: (MOVSSload [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSSload [off1+off2] {sym} ptr mem)
 	for {
-		x := v.AuxInt
-		sym1 := v.Aux
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ1 {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off := v_0.AuxInt
-		sym2 := v_0.Aux
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2)) {
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(off)
-		v.Aux = mergeSym(sym1, sym2)
+		v.reset(OpAMD64MOVSSload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
 		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)
+	// 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 {
-		x := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAQ2 {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
+		base := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(off)
+		v.reset(OpAMD64MOVSSload)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
+		v.AddArg(base)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem)
-	// cond:
-	// result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+	// 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 {
-		x := v.AuxInt
-		sym := v.Aux
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQ {
+		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		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)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			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.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
-	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	// 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 {
-		sc := v.AuxInt
+		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64LEAL {
+		if v_0.Op != OpAMD64LEAQ4 {
 			break
 		}
-		off := v_0.AuxInt
+		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
+		v.reset(OpAMD64MOVSSloadidx4)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
+		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
-	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	// match: (MOVSSload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
 	for {
-		sc := v.AuxInt
-		s := v.Aux
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDLconst {
+		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
-		off := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
 		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		if !(ptr.Op != OpSB) {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(ptr)
+		v.AddArg(idx)
 		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)
+func rewriteValueAMD64_OpAMD64MOVSSloadidx1_0(v *Value) bool {
+	// match: (MOVSSloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
 	// cond:
-	// result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+	// result: (MOVSSloadidx4 [c] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		if v_1.AuxInt != 2 {
 			break
 		}
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWstoreconstidx2)
+		v.reset(OpAMD64MOVSSloadidx4)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9771,193 +10138,267 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// match: (MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := 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.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
 		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// match: (MOVSSloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		x := v.AuxInt
+		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_1.AuxInt
+		d := v_1.AuxInt
 		idx := v_1.Args[0]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWstoreconstidx1)
-		v.AuxInt = ValAndOff(x).add(c)
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = c + d
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSloadidx4_0(v *Value) bool {
+	// match: (MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		i := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpAMD64MOVWstoreconstidx1 {
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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)) {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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)
+		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_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)
+func rewriteValueAMD64_OpAMD64MOVSSstore_0(v *Value) bool {
+	// match: (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSSstore [off1+off2] {sym} ptr val mem)
 	for {
-		x := v.AuxInt
+		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_0.AuxInt
+		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
-		idx := v.Args[1]
+		val := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(c)
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstore)
+		v.AuxInt = off1 + off2
 		v.Aux = sym
 		v.AddArg(ptr)
-		v.AddArg(idx)
+		v.AddArg(val)
 		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)
+	// 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 {
-		x := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		c := v_1.AuxInt
-		idx := v_1.Args[0]
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpAMD64MOVWstoreconstidx2)
-		v.AuxInt = ValAndOff(x).add(2 * c)
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
+		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: (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)
+	// 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 {
-		c := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		i := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpAMD64MOVWstoreconstidx2 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
-		a := x.AuxInt
-		if x.Aux != s {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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
 		}
-		if p != x.Args[0] {
+		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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
 			break
 		}
-		if i != x.Args[1] {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+		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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			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_0.Args[1]
+		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_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem)
+func rewriteValueAMD64_OpAMD64MOVSSstoreidx1_0(v *Value) bool {
+	// match: (MOVSSstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem)
 	// cond:
-	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+	// result: (MOVSSstoreidx4 [c] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		if v_1.AuxInt != 1 {
+		if v_1.AuxInt != 2 {
 			break
 		}
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(OpAMD64MOVWstoreidx2)
+		v.reset(OpAMD64MOVSSstoreidx4)
 		v.AuxInt = c
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9966,12 +10407,13 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// match: (MOVSSstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
 	// cond:
-	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64ADDQconst {
 			break
@@ -9981,7 +10423,7 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
 		idx := v.Args[1]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(OpAMD64MOVWstoreidx1)
+		v.reset(OpAMD64MOVSSstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -9990,12 +10432,13 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVWstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// match: (MOVSSstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
 	// cond:
-	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64ADDQconst {
@@ -10005,7 +10448,7 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
 		idx := v_1.Args[0]
 		val := v.Args[2]
 		mem := v.Args[3]
-		v.reset(OpAMD64MOVWstoreidx1)
+		v.reset(OpAMD64MOVSSstoreidx1)
 		v.AuxInt = c + d
 		v.Aux = sym
 		v.AddArg(ptr)
@@ -10014,1400 +10457,2001 @@ func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
 		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)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSstoreidx4_0(v *Value) bool {
+	// match: (MOVSSstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val 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 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if v_2.AuxInt != 16 {
+		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
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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] {
+		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_0(v *Value) 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
 		}
-		if idx != x.Args[1] {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if w != x.Args[2] {
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, 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 x:(MOVLload [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 != OpAMD64MOVLload {
 			break
 		}
-		mem := x.Args[3]
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
 		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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.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)
+	// match: (MOVWQSX x:(MOVQload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr 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 {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVQload {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpAMD64MOVWstoreidx1 {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if x.AuxInt != i-2 {
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if x.Aux != s {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x8000 == 0) {
 			break
 		}
-		if p != x.Args[0] {
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0x7fff
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWQSX x:(MOVWQSX _))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWQSX {
 			break
 		}
-		if idx != x.Args[1] {
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWQSX x:(MOVBQSX _))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQSX {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpAMD64SHRQconst {
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQSXload_0(v *Value) bool {
+	// match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVWQSX x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWstore {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		if w != w0.Args[0] {
+		v.reset(OpAMD64MOVWQSX)
+		v.AddArg(x)
+		return true
+	}
+	// 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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		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(OpAMD64MOVLstoreidx1)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
+		v.reset(OpAMD64MOVWQSXload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWQZX_0(v *Value) 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)
+	// 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 {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ADDQconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWload {
 			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 {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.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)
+	// match: (MOVWQZX x:(MOVLload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr 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] {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLload {
 			break
 		}
-		mem := x.Args[3]
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
 		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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(w)
-		v.AddArg(mem)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.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)
+	// match: (MOVWQZX x:(MOVQload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr 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 {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVQload {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if w != w0.Args[0] {
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		mem := x.Args[3]
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
 		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)
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.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)
+	// 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]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVLconst {
+		if x.Op != OpAMD64MOVWloadidx2 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpAMD64MULLconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, 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: (MULL (MOVLconst [c]) x)
+	// match: (MOVWQZX (ANDLconst [c] x))
 	// cond:
-	// result: (MULLconst [c] x)
+	// result: (ANDLconst [c & 0xffff] x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVLconst {
+		if v_0.Op != OpAMD64ANDLconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpAMD64MULLconst)
-		v.AuxInt = c
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0xffff
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64MULLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULLconst [c] (MULLconst [d] x))
+	// match: (MOVWQZX x:(MOVWQZX _))
 	// cond:
-	// result: (MULLconst [int64(int32(c * d))] x)
+	// result: x
 	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MULLconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWQZX {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(OpAMD64MULLconst)
-		v.AuxInt = int64(int32(c * d))
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (MULLconst [c] (MOVLconst [d]))
+	// match: (MOVWQZX x:(MOVBQZX _))
 	// cond:
-	// result: (MOVLconst [int64(int32(c*d))])
+	// result: x
 	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVLconst {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBQZX {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = int64(int32(c * d))
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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)
+func rewriteValueAMD64_OpAMD64MOVWload_0(v *Value) bool {
+	// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVWQZX x)
 	for {
-		x := v.Args[0]
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVQconst {
+		if v_1.Op != OpAMD64MOVWstore {
 			break
 		}
-		c := v_1.AuxInt
-		if !(is32Bit(c)) {
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpAMD64MULQconst)
-		v.AuxInt = c
+		v.reset(OpAMD64MOVWQZX)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MULQ (MOVQconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (MULQconst [c] x)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(is32Bit(c)) {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		v.reset(OpAMD64MULQconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		v.reset(OpAMD64MOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64MULQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULQconst [c] (MULQconst [d] x))
-	// cond: is32Bit(c*d)
-	// result: (MULQconst [c * d] x)
+	// 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 {
-		c := v.AuxInt
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MULQconst {
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		if !(is32Bit(c * d)) {
+		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(OpAMD64MULQconst)
-		v.AuxInt = c * d
-		v.AddArg(x)
+		v.reset(OpAMD64MOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULQconst [-1] x)
-	// cond:
-	// result: (NEGQ x)
+	// 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 {
-		if v.AuxInt != -1 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			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 {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
 			break
 		}
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = 0
+		v.reset(OpAMD64MOVWloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULQconst [1] x)
-	// cond:
-	// result: x
+	// 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 {
-		if v.AuxInt != 1 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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: (MULQconst [3] x)
-	// cond:
-	// result: (LEAQ2 x x)
+	// match: (MOVWload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWloadidx1 [off] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 3 {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpAMD64LEAQ2)
-		v.AddArg(x)
-		v.AddArg(x)
+		_ = v_0.Args[1]
+		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
 	}
-	// match: (MULQconst [5] x)
-	// cond:
-	// result: (LEAQ4 x x)
+	// match: (MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
-		if v.AuxInt != 5 {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpAMD64LEAQ4)
-		v.AddArg(x)
-		v.AddArg(x)
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(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: (MULQconst [7] x)
-	// cond:
-	// result: (LEAQ8 (NEGQ <v.Type> x) x)
+	// match: (MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWload  [off1+off2] {sym} ptr mem)
 	for {
-		if v.AuxInt != 7 {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
 			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)
+		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: (MULQconst [9] x)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWloadidx1_0(v *Value) bool {
+	// match: (MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
 	// cond:
-	// result: (LEAQ8 x x)
+	// result: (MOVWloadidx2 [c] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 9 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpAMD64LEAQ8)
-		v.AddArg(x)
-		v.AddArg(x)
+		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: (MULQconst [11] x)
+	// match: (MOVWloadidx1 [c] {sym} (SHLQconst [1] idx) ptr mem)
 	// cond:
-	// result: (LEAQ2 x (LEAQ4 <v.Type> x x))
+	// result: (MOVWloadidx2 [c] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 11 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
 			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)
+		if v_0.AuxInt != 1 {
+			break
+		}
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		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: (MULQconst [13] x)
+	// match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (LEAQ4 x (LEAQ2 <v.Type> x x))
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 13 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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)
+		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: (MULQconst [21] x)
+	// match: (MOVWloadidx1 [c] {sym} idx (ADDQconst [d] ptr) mem)
 	// cond:
-	// result: (LEAQ4 x (LEAQ4 <v.Type> x x))
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 21 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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)
+		d := v_1.AuxInt
+		ptr := 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
 	}
-	// match: (MULQconst [25] x)
+	// match: (MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (LEAQ8 x (LEAQ2 <v.Type> x x))
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 25 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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)
+		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
 	}
-	// match: (MULQconst [37] x)
+	// match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] idx) ptr mem)
 	// cond:
-	// result: (LEAQ4 x (LEAQ8 <v.Type> x x))
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 37 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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)
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := 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: (MULQconst [41] x)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWloadidx2_0(v *Value) bool {
+	// match: (MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem)
 	// cond:
-	// result: (LEAQ8 x (LEAQ4 <v.Type> x x))
+	// result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 41 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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)
+		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: (MULQconst [73] x)
+	// match: (MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem)
 	// cond:
-	// result: (LEAQ8 x (LEAQ8 <v.Type> x x))
+	// result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
 	for {
-		if v.AuxInt != 73 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			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)
+		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
 	}
-	// match: (MULQconst [c] x)
-	// cond: isPowerOfTwo(c)
-	// result: (SHLQconst [log2(c)] x)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstore_0(v *Value) bool {
+	// match: (MOVWstore [off] {sym} ptr (MOVWQSX x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c)) {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWQSX {
 			break
 		}
-		v.reset(OpAMD64SHLQconst)
-		v.AuxInt = log2(c)
+		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: (MULQconst [c] x)
-	// cond: isPowerOfTwo(c+1) && c >= 15
-	// result: (SUBQ (SHLQconst <v.Type> [log2(c+1)] x) x)
+	// match: (MOVWstore [off] {sym} ptr (MOVWQZX x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c+1) && c >= 15) {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWQZX {
 			break
 		}
-		v.reset(OpAMD64SUBQ)
-		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
-		v0.AuxInt = log2(c + 1)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		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: (MULQconst [c] x)
-	// cond: isPowerOfTwo(c-1) && c >= 17
-	// result: (LEAQ1 (SHLQconst <v.Type> [log2(c-1)] x) x)
+	// match: (MOVWstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-1) && c >= 17) {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			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) {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			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)
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULQconst [c] x)
-	// cond: isPowerOfTwo(c-4) && c >= 68
-	// result: (LEAQ4 (SHLQconst <v.Type> [log2(c-4)] x) x)
+	// match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-4) && c >= 68) {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
 			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) {
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
 			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)
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = makeValAndOff(int64(int16(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULQconst [c] x)
-	// cond: c%3 == 0 && isPowerOfTwo(c/3)
-	// result: (SHLQconst [log2(c/3)] (LEAQ2 <v.Type> x x))
+	// 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 {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			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)) {
+		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(OpAMD64SHLQconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MULQconst [c] x)
-	// cond: c%9 == 0 && isPowerOfTwo(c/9)
-	// result: (SHLQconst [log2(c/9)] (LEAQ8 <v.Type> x x))
+	// 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 {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			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 {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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
 		}
-		d := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = c * d
+		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
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64NEGL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NEGL (MOVLconst [c]))
-	// cond:
-	// result: (MOVLconst [int64(int32(-c))])
+	// 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.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVLconst {
+		if v_0.Op != OpAMD64LEAQ2 {
 			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 {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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
 		}
-		c := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = -c
+		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
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64NOTL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOTL (MOVLconst [c]))
-	// cond:
-	// result: (MOVLconst [^c])
+	// 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.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVLconst {
+		if v_0.Op != OpAMD64ADDQ {
 			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 {
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = ^c
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORL x (MOVLconst [c]))
-	// cond:
-	// result: (ORLconst [c] x)
+	// 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 {
-		x := v.Args[0]
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVLconst {
+		if v_1.Op != OpAMD64SHRQconst {
 			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 {
+		if v_1.AuxInt != 16 {
 			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] {
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstore {
 			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 {
+		if x.AuxInt != i-2 {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := v.Args[1]
-		if s0.Op != OpAMD64SHLLconst {
+		if x.Aux != s {
 			break
 		}
-		if s0.AuxInt != 8 {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBload {
+		if w != x.Args[1] {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if x1.Aux != s {
+		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
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
 			break
 		}
-		if p != x1.Args[0] {
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstore {
 			break
 		}
-		if mem != x1.Args[1] {
+		if x.AuxInt != i-2 {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+		if x.Aux != s {
 			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                        x0:(MOVWload [i]   {s} p mem)     s0:(SHLLconst [16] x1:(MOVBload [i+2] {s} p mem)))     s1:(SHLLconst [24] x2:(MOVBload [i+3] {s} p mem)))
-	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p mem)
-	for {
-		o0 := v.Args[0]
-		if o0.Op != OpAMD64ORL {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != OpAMD64MOVWload {
+		w0 := x.Args[1]
+		if w0.Op != OpAMD64SHRQconst {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
-		if s0.Op != OpAMD64SHLLconst {
+		if w0.AuxInt != j-16 {
 			break
 		}
-		if s0.AuxInt != 16 {
+		if w != w0.Args[0] {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBload {
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if x1.AuxInt != i+2 {
+		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_OpAMD64MOVWstore_10(v *Value) bool {
+	// match: (MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		if x1.Aux != s {
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		if p != x1.Args[0] {
+		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] {sym} (ADDLconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if mem != x1.Args[1] {
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
 			break
 		}
-		s1 := v.Args[1]
-		if s1.Op != OpAMD64SHLLconst {
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconst_0(v *Value) bool {
+	// 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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if s1.AuxInt != 24 {
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBload {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		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
 		}
-		if x2.Aux != s {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
 			break
 		}
-		if p != x2.Args[0] {
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		if mem != x2.Args[1] {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		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)
+		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: (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)
+	// match: (MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx1 [x] {sym} ptr 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 {
+		x := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
 			break
 		}
-		if s0.AuxInt != 8 {
+		_ = v_0.Args[1]
+		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
+		_ = v.Args[1]
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpAMD64MOVWstoreconst {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBloadidx1 {
+		a := x.AuxInt
+		if x.Aux != s {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		_ = x.Args[1]
+		if p != x.Args[0] {
 			break
 		}
-		if x1.Aux != s {
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		if p != x1.Args[0] {
+		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
+	}
+	// match: (MOVWstoreconst [sc] {sym1} (LEAL [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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAL {
 			break
 		}
-		if idx != x1.Args[1] {
+		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
 		}
-		if mem != x1.Args[2] {
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [sc] {s} (ADDLconst [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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
 			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)
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ORL o0:(ORL                        x0:(MOVWloadidx1 [i]   {s} p idx mem)     s0:(SHLLconst [16] x1:(MOVBloadidx1 [i+2] {s} p idx mem)))     s1:(SHLLconst [24] x2:(MOVBloadidx1 [i+3] {s} p idx mem)))
-	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1_0(v *Value) bool {
+	// match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpAMD64ORL {
-			break
-		}
-		x0 := o0.Args[0]
-		if x0.Op != OpAMD64MOVWloadidx1 {
-			break
-		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		idx := x0.Args[1]
-		mem := x0.Args[2]
-		s0 := o0.Args[1]
-		if s0.Op != OpAMD64SHLLconst {
-			break
-		}
-		if s0.AuxInt != 16 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBloadidx1 {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		if x1.AuxInt != i+2 {
+		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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x1.Aux != s {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		if p != x1.Args[0] {
+		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
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstoreconstidx1 {
 			break
 		}
-		if idx != x1.Args[1] {
+		a := x.AuxInt
+		if x.Aux != s {
 			break
 		}
-		if mem != x1.Args[2] {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		s1 := v.Args[1]
-		if s1.Op != OpAMD64SHLLconst {
+		if i != x.Args[1] {
 			break
 		}
-		if s1.AuxInt != 24 {
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBloadidx1 {
+		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_0(v *Value) 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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		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
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x2.Aux != s {
+		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
+		_ = v.Args[2]
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstoreconstidx2 {
 			break
 		}
-		if p != x2.Args[0] {
+		a := x.AuxInt
+		if x.Aux != s {
 			break
 		}
-		if idx != x2.Args[1] {
+		_ = x.Args[2]
+		if p != x.Args[0] {
 			break
 		}
-		if mem != x2.Args[2] {
+		if i != x.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
-		v.reset(OpCopy)
+		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.Pos, OpAMD64SHLQconst, i.Type)
+		v0.AuxInt = 1
+		v0.AddArg(i)
 		v.AddArg(v0)
-		v0.AuxInt = i
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ORL o1:(ORL o0:(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) (BSWAPL <v.Type> (MOVLload [i-3] {s} p mem))
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreidx1_0(v *Value) bool {
+	// match: (MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
 	for {
-		o1 := v.Args[0]
-		if o1.Op != OpAMD64ORL {
-			break
-		}
-		o0 := o1.Args[0]
-		if o0.Op != OpAMD64ORL {
-			break
-		}
-		x0 := o0.Args[0]
-		if x0.Op != OpAMD64MOVBload {
-			break
-		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
-		if s0.Op != OpAMD64SHLLconst {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBload {
+		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.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		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
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x1.Aux != s {
+		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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if p != x1.Args[0] {
+		if v_2.AuxInt != 16 {
 			break
 		}
-		if mem != x1.Args[1] {
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx1 {
 			break
 		}
-		s1 := o1.Args[1]
-		if s1.Op != OpAMD64SHLLconst {
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
 			break
 		}
-		if s1.AuxInt != 16 {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBload {
+		if idx != x.Args[1] {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		if w != x.Args[2] {
 			break
 		}
-		if x2.Aux != s {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if p != x2.Args[0] {
+		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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if mem != x2.Args[1] {
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx1 {
 			break
 		}
-		s2 := v.Args[1]
-		if s2.Op != OpAMD64SHLLconst {
+		if x.AuxInt != i-2 {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if x.Aux != s {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBload {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		if idx != x.Args[1] {
 			break
 		}
-		if x3.Aux != s {
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
 			break
 		}
-		if p != x3.Args[0] {
+		if w0.AuxInt != j-16 {
 			break
 		}
-		if mem != x3.Args[1] {
+		if w != w0.Args[0] {
 			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)) {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPL, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
-		v1.AuxInt = i - 3
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(mem)
-		v0.AddArg(v1)
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ORL o1:(ORL o0:(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) (BSWAPL <v.Type> (MOVLloadidx1 <v.Type> [i-3] {s} p idx mem))
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreidx2_0(v *Value) 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 {
-		o1 := v.Args[0]
-		if o1.Op != OpAMD64ORL {
-			break
-		}
-		o0 := o1.Args[0]
-		if o0.Op != OpAMD64ORL {
-			break
-		}
-		x0 := o0.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 := o0.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 {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if p != x1.Args[0] {
+		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
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
 			break
 		}
-		if idx != x1.Args[1] {
+		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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		if mem != x1.Args[2] {
+		if v_2.AuxInt != 16 {
 			break
 		}
-		s1 := o1.Args[1]
-		if s1.Op != OpAMD64SHLLconst {
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx2 {
 			break
 		}
-		if s1.AuxInt != 16 {
+		if x.AuxInt != i-2 {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBloadidx1 {
+		if x.Aux != s {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			break
 		}
-		if x2.Aux != s {
+		if idx != x.Args[1] {
 			break
 		}
-		if p != x2.Args[0] {
+		if w != x.Args[2] {
 			break
 		}
-		if idx != x2.Args[1] {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		if mem != x2.Args[2] {
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, 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
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
 			break
 		}
-		s2 := v.Args[1]
-		if s2.Op != OpAMD64SHLLconst {
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx2 {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if x.AuxInt != i-2 {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBloadidx1 {
+		if x.Aux != s {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			break
 		}
-		if x3.Aux != s {
+		if idx != x.Args[1] {
 			break
 		}
-		if p != x3.Args[0] {
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
 			break
 		}
-		if idx != x3.Args[1] {
+		if w0.AuxInt != j-16 {
 			break
 		}
-		if mem != x3.Args[2] {
+		if w != w0.Args[0] {
 			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)) {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPL, v.Type)
-		v.reset(OpCopy)
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 1
+		v0.AddArg(idx)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
-		v1.AuxInt = i - 3
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(idx)
-		v1.AddArg(mem)
-		v0.AddArg(v1)
+		v.AddArg(w0)
+		v.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
+func rewriteValueAMD64_OpAMD64MULL_0(v *Value) bool {
+	// match: (MULL x (MOVLconst [c]))
+	// cond:
+	// result: (MULLconst [c] x)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
-		if !(int32(c) == 0) {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		c := v_1.AuxInt
+		v.reset(OpAMD64MULLconst)
+		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORLconst [c] _)
-	// cond: int32(c)==-1
-	// result: (MOVLconst [-1])
+	// match: (MULL (MOVLconst [c]) x)
+	// cond:
+	// result: (MULLconst [c] x)
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (MULLconst [c] (MULLconst [d] x))
+	// cond:
+	// result: (MULLconst [int64(int32(c * d))] x)
 	for {
 		c := v.AuxInt
-		if !(int32(c) == -1) {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MULLconst {
 			break
 		}
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = -1
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64MULLconst)
+		v.AuxInt = int64(int32(c * d))
+		v.AddArg(x)
 		return true
 	}
-	// match: (ORLconst [c] (MOVLconst [d]))
+	// match: (MULLconst [c] (MOVLconst [d]))
 	// cond:
-	// result: (MOVLconst [c|d])
+	// result: (MOVLconst [int64(int32(c*d))])
 	for {
 		c := v.AuxInt
 		v_0 := v.Args[0]
@@ -11416,18 +12460,17 @@ func rewriteValueAMD64_OpAMD64ORLconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = c | d
+		v.AuxInt = int64(int32(c * d))
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORQ x (MOVQconst [c]))
+func rewriteValueAMD64_OpAMD64MULQ_0(v *Value) bool {
+	// match: (MULQ x (MOVQconst [c]))
 	// cond: is32Bit(c)
-	// result: (ORQconst [c] x)
+	// result: (MULQconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpAMD64MOVQconst {
@@ -11437,15 +12480,16 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
 		if !(is32Bit(c)) {
 			break
 		}
-		v.reset(OpAMD64ORQconst)
+		v.reset(OpAMD64MULQconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORQ (MOVQconst [c]) x)
+	// match: (MULQ (MOVQconst [c]) x)
 	// cond: is32Bit(c)
-	// result: (ORQconst [c] x)
+	// result: (MULQconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpAMD64MOVQconst {
 			break
@@ -11455,8843 +12499,31281 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
 		if !(is32Bit(c)) {
 			break
 		}
-		v.reset(OpAMD64ORQconst)
+		v.reset(OpAMD64MULQconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORQ x x)
-	// cond:
-	// result: x
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULQconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULQconst [c] (MULQconst [d] x))
+	// cond: is32Bit(c*d)
+	// result: (MULQconst [c * d] x)
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MULQconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(is32Bit(c * d)) {
+			break
+		}
+		v.reset(OpAMD64MULQconst)
+		v.AuxInt = c * d
 		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)
+	// match: (MULQconst [-1] x)
+	// cond:
+	// result: (NEGQ x)
 	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 {
+		if v.AuxInt != -1 {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpAMD64ORQ {
+		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
 		}
-		x0 := o5.Args[0]
-		if x0.Op != OpAMD64MOVBload {
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MULQconst [1] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 1 {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o5.Args[1]
-		if s0.Op != OpAMD64SHLQconst {
+		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
 		}
-		if s0.AuxInt != 8 {
+		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
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBload {
+		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
 		}
-		if x1.AuxInt != i+1 {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if x1.Aux != s {
+		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
 		}
-		if p != x1.Args[0] {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if mem != x1.Args[1] {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64LEAQ2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULQconst_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULQconst [21] x)
+	// cond:
+	// result: (LEAQ4 x (LEAQ4 <v.Type> x x))
+	for {
+		if v.AuxInt != 21 {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpAMD64SHLQconst {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if s1.AuxInt != 16 {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBload {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if x2.AuxInt != i+2 {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if x2.Aux != s {
-			break
-		}
-		if p != x2.Args[0] {
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if mem != x2.Args[1] {
+		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
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpAMD64SHLQconst {
+		v.reset(OpAMD64SUBQ)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if s2.AuxInt != 24 {
+		v.reset(OpAMD64LEAQ1)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBload {
+		v.reset(OpAMD64LEAQ2)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if x3.AuxInt != i+3 {
+		v.reset(OpAMD64LEAQ4)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c - 4)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULQconst_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// 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
 		}
-		if x3.Aux != s {
+		v.reset(OpAMD64LEAQ8)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if p != x3.Args[0] {
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if mem != x3.Args[1] {
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpAMD64SHLQconst {
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Pos, 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
 		}
-		if s3.AuxInt != 32 {
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c * d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULSD_0(v *Value) bool {
+	// match: (MULSD x l:(MOVSDload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (MULSDmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSDload {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpAMD64MOVBload {
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
 			break
 		}
-		if x4.AuxInt != i+4 {
+		v.reset(OpAMD64MULSDmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULSD l:(MOVSDload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (MULSDmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVSDload {
 			break
 		}
-		if x4.Aux != s {
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
 			break
 		}
-		if p != x4.Args[0] {
+		v.reset(OpAMD64MULSDmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULSS_0(v *Value) bool {
+	// match: (MULSS x l:(MOVSSload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (MULSSmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSSload {
 			break
 		}
-		if mem != x4.Args[1] {
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpAMD64SHLQconst {
+		v.reset(OpAMD64MULSSmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULSS l:(MOVSSload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (MULSSmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVSSload {
 			break
 		}
-		if s4.AuxInt != 40 {
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpAMD64MOVBload {
+		v.reset(OpAMD64MULSSmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NEGL_0(v *Value) bool {
+	// match: (NEGL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [int64(int32(-c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
 			break
 		}
-		if x5.AuxInt != i+5 {
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = int64(int32(-c))
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NEGQ_0(v *Value) bool {
+	// match: (NEGQ (MOVQconst [c]))
+	// cond:
+	// result: (MOVQconst [-c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
 			break
 		}
-		if x5.Aux != s {
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = -c
+		return true
+	}
+	// match: (NEGQ (ADDQconst [c] (NEGQ x)))
+	// cond: c != -(1<<31)
+	// result: (ADDQconst [-c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if p != x5.Args[0] {
+		c := v_0.AuxInt
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if mem != x5.Args[1] {
+		x := v_0_0.Args[0]
+		if !(c != -(1 << 31)) {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpAMD64SHLQconst {
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = -c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NOTL_0(v *Value) bool {
+	// match: (NOTL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
 			break
 		}
-		if s5.AuxInt != 48 {
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NOTQ_0(v *Value) bool {
+	// match: (NOTQ (MOVQconst [c]))
+	// cond:
+	// result: (MOVQconst [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpAMD64MOVBload {
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORL_0(v *Value) bool {
+	// match: (ORL x (MOVLconst [c]))
+	// cond:
+	// result: (ORLconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
 			break
 		}
-		if x6.AuxInt != i+6 {
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
 			break
 		}
-		if x6.Aux != s {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64ORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (SHLLconst x [c]) (SHRLconst x [d]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
 			break
 		}
-		if p != x6.Args[0] {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRLconst {
 			break
 		}
-		if mem != x6.Args[1] {
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpAMD64SHLQconst {
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (SHRLconst x [d]) (SHLLconst x [c]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRLconst {
 			break
 		}
-		if s6.AuxInt != 56 {
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpAMD64MOVBload {
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		if x7.AuxInt != i+7 {
+		if !(d == 32-c) {
 			break
 		}
-		if x7.Aux != s {
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
 			break
 		}
-		if p != x7.Args[0] {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRWconst {
 			break
 		}
-		if mem != x7.Args[1] {
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
 			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 [...]
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
 			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)
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		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)
+	// match: (ORL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpAMD64ORQ {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRWconst {
 			break
 		}
-		o1 := o0.Args[0]
-		if o1.Op != OpAMD64ORQ {
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
 			break
 		}
-		o2 := o1.Args[0]
-		if o2.Op != OpAMD64ORQ {
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		o3 := o2.Args[0]
-		if o3.Op != OpAMD64ORQ {
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
 			break
 		}
-		o4 := o3.Args[0]
-		if o4.Op != OpAMD64ORQ {
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpAMD64ORQ {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRBconst {
 			break
 		}
-		x0 := o5.Args[0]
-		if x0.Op != OpAMD64MOVBloadidx1 {
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
 			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 {
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
 			break
 		}
-		if s0.AuxInt != 8 {
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRBconst {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBloadidx1 {
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		if x1.Aux != s {
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
 			break
 		}
-		if p != x1.Args[0] {
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (SHLL x y) (ANDL (SHRL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32]))))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		if idx != x1.Args[1] {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if mem != x1.Args[2] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRL {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpAMD64SHLQconst {
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
 			break
 		}
-		if s1.AuxInt != 16 {
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBloadidx1 {
+		if y != v_1_0_1.Args[0] {
 			break
 		}
-		if x2.AuxInt != i+2 {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if x2.Aux != s {
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if p != x2.Args[0] {
+		if v_1_1_0.AuxInt != 32 {
 			break
 		}
-		if idx != x2.Args[1] {
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if mem != x2.Args[2] {
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpAMD64SHLQconst {
+		if v_1_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		if s2.AuxInt != 24 {
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBloadidx1 {
+		if v_1_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if x3.AuxInt != i+3 {
+		if y != v_1_1_0_0_0_0.Args[0] {
 			break
 		}
-		if x3.Aux != s {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (SHLL x y) (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])) (SHRL x (NEGQ y))))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		if p != x3.Args[0] {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if idx != x3.Args[1] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if mem != x3.Args[2] {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpAMD64SHLQconst {
+		if v_1_0_0.AuxInt != 32 {
 			break
 		}
-		if s3.AuxInt != 32 {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpAMD64MOVBloadidx1 {
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x4.AuxInt != i+4 {
+		if v_1_0_0_0_0.AuxInt != -32 {
 			break
 		}
-		if x4.Aux != s {
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		if p != x4.Args[0] {
+		if v_1_0_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if idx != x4.Args[1] {
+		if y != v_1_0_0_0_0_0.Args[0] {
 			break
 		}
-		if mem != x4.Args[2] {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRL {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpAMD64SHLQconst {
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
 			break
 		}
-		if s4.AuxInt != 40 {
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpAMD64MOVBloadidx1 {
+		if y != v_1_1_1.Args[0] {
 			break
 		}
-		if x5.AuxInt != i+5 {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORL_10(v *Value) bool {
+	// match: (ORL (ANDL (SHRL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32]))) (SHLL x y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		if x5.Aux != s {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRL {
 			break
 		}
-		if p != x5.Args[0] {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
 			break
 		}
-		if idx != x5.Args[1] {
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if mem != x5.Args[2] {
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpAMD64SHLQconst {
+		if v_0_1_0.AuxInt != 32 {
 			break
 		}
-		if s5.AuxInt != 48 {
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpAMD64MOVBloadidx1 {
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if x6.AuxInt != i+6 {
+		if v_0_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		if x6.Aux != s {
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		if p != x6.Args[0] {
+		if v_0_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if idx != x6.Args[1] {
+		if y != v_0_1_0_0_0_0.Args[0] {
 			break
 		}
-		if mem != x6.Args[2] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpAMD64SHLQconst {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		if s6.AuxInt != 56 {
+		if y != v_1.Args[1] {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpAMD64MOVBloadidx1 {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])) (SHRL x (NEGQ y))) (SHLL x y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		if x7.AuxInt != i+7 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if x7.Aux != s {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if p != x7.Args[0] {
+		if v_0_0_0.AuxInt != 32 {
 			break
 		}
-		if idx != x7.Args[1] {
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if mem != x7.Args[2] {
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
 			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 [...]
+		if v_0_0_0_0_0.AuxInt != -32 {
 			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
-	}
-	// match: (ORQ o5:(ORQ o4:(ORQ o3:(ORQ o2:(ORQ o1:(ORQ o0:(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)))
-	// 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) (BSWAPQ <v.Type> (MOVQload [i-7] {s} p mem))
-	for {
-		o5 := v.Args[0]
-		if o5.Op != OpAMD64ORQ {
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		o4 := o5.Args[0]
-		if o4.Op != OpAMD64ORQ {
+		if v_0_0_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		o3 := o4.Args[0]
-		if o3.Op != OpAMD64ORQ {
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRL {
 			break
 		}
-		o2 := o3.Args[0]
-		if o2.Op != OpAMD64ORQ {
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
 			break
 		}
-		o1 := o2.Args[0]
-		if o1.Op != OpAMD64ORQ {
+		if y != v_0_1_1.Args[0] {
 			break
 		}
-		o0 := o1.Args[0]
-		if o0.Op != OpAMD64ORQ {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != OpAMD64MOVBload {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
-		if s0.Op != OpAMD64SHLQconst {
+		if y != v_1.Args[1] {
 			break
 		}
-		if s0.AuxInt != 8 {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (SHLL x y) (ANDL (SHRL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32]))))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBload {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRL {
 			break
 		}
-		if x1.Aux != s {
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
 			break
 		}
-		if p != x1.Args[0] {
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
 			break
 		}
-		if mem != x1.Args[1] {
+		if y != v_1_0_1.Args[0] {
 			break
 		}
-		s1 := o1.Args[1]
-		if s1.Op != OpAMD64SHLQconst {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if s1.AuxInt != 16 {
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBload {
+		if v_1_1_0.AuxInt != 32 {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
 			break
 		}
-		if x2.Aux != s {
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if p != x2.Args[0] {
+		if v_1_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		if mem != x2.Args[1] {
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
 			break
 		}
-		s2 := o2.Args[1]
-		if s2.Op != OpAMD64SHLQconst {
+		if v_1_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if y != v_1_1_0_0_0_0.Args[0] {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBload {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (SHLL x y) (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])) (SHRL x (NEGL y))))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if x3.Aux != s {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if p != x3.Args[0] {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
 			break
 		}
-		if mem != x3.Args[1] {
+		if v_1_0_0.AuxInt != 32 {
 			break
 		}
-		s3 := o3.Args[1]
-		if s3.Op != OpAMD64SHLQconst {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
 			break
 		}
-		if s3.AuxInt != 32 {
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpAMD64MOVBload {
+		if v_1_0_0_0_0.AuxInt != -32 {
 			break
 		}
-		if x4.AuxInt != i-4 {
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
 			break
 		}
-		if x4.Aux != s {
+		if v_1_0_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if p != x4.Args[0] {
+		if y != v_1_0_0_0_0_0.Args[0] {
 			break
 		}
-		if mem != x4.Args[1] {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRL {
 			break
 		}
-		s4 := o4.Args[1]
-		if s4.Op != OpAMD64SHLQconst {
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
 			break
 		}
-		if s4.AuxInt != 40 {
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpAMD64MOVBload {
+		if y != v_1_1_1.Args[0] {
 			break
 		}
-		if x5.AuxInt != i-5 {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (ANDL (SHRL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32]))) (SHLL x y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		if x5.Aux != s {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRL {
 			break
 		}
-		if p != x5.Args[0] {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
 			break
 		}
-		if mem != x5.Args[1] {
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		s5 := o5.Args[1]
-		if s5.Op != OpAMD64SHLQconst {
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
 			break
 		}
-		if s5.AuxInt != 48 {
+		if v_0_1_0.AuxInt != 32 {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpAMD64MOVBload {
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
 			break
 		}
-		if x6.AuxInt != i-6 {
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if x6.Aux != s {
+		if v_0_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		if p != x6.Args[0] {
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
 			break
 		}
-		if mem != x6.Args[1] {
+		if v_0_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpAMD64SHLQconst {
+		if y != v_0_1_0_0_0_0.Args[0] {
 			break
 		}
-		if s6.AuxInt != 56 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpAMD64MOVBload {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		if x7.AuxInt != i-7 {
+		if y != v_1.Args[1] {
 			break
 		}
-		if x7.Aux != s {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])) (SHRL x (NEGL y))) (SHLL x y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		if p != x7.Args[0] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if mem != x7.Args[1] {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
 			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 [...]
+		if v_0_0_0.AuxInt != 32 {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPQ, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
-		v1.AuxInt = i - 7
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(mem)
-		v0.AddArg(v1)
-		return true
-	}
-	// match: (ORQ o5:(ORQ o4:(ORQ o3:(ORQ o2:(ORQ o1:(ORQ o0:(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 id [...]
-	// 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) (BSWAPQ <v.Type> (MOVQloadidx1 <v.Type> [i-7] {s} p idx mem))
-	for {
-		o5 := v.Args[0]
-		if o5.Op != OpAMD64ORQ {
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
 			break
 		}
-		o4 := o5.Args[0]
-		if o4.Op != OpAMD64ORQ {
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		o3 := o4.Args[0]
-		if o3.Op != OpAMD64ORQ {
+		if v_0_0_0_0_0.AuxInt != -32 {
 			break
 		}
-		o2 := o3.Args[0]
-		if o2.Op != OpAMD64ORQ {
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
 			break
 		}
-		o1 := o2.Args[0]
-		if o1.Op != OpAMD64ORQ {
+		if v_0_0_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		o0 := o1.Args[0]
-		if o0.Op != OpAMD64ORQ {
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRL {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != OpAMD64MOVBloadidx1 {
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		idx := x0.Args[1]
-		mem := x0.Args[2]
-		s0 := o0.Args[1]
-		if s0.Op != OpAMD64SHLQconst {
+		if y != v_0_1_1.Args[0] {
 			break
 		}
-		if s0.AuxInt != 8 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpAMD64MOVBloadidx1 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		if y != v_1.Args[1] {
 			break
 		}
-		if x1.Aux != s {
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (SHRL x y) (ANDL (SHLL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32]))))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRL {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if idx != x1.Args[1] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHLL {
 			break
 		}
-		if mem != x1.Args[2] {
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
 			break
 		}
-		s1 := o1.Args[1]
-		if s1.Op != OpAMD64SHLQconst {
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
 			break
 		}
-		if s1.AuxInt != 16 {
+		if y != v_1_0_1.Args[0] {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpAMD64MOVBloadidx1 {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if x2.Aux != s {
+		if v_1_1_0.AuxInt != 32 {
 			break
 		}
-		if p != x2.Args[0] {
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if idx != x2.Args[1] {
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if mem != x2.Args[2] {
+		if v_1_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		s2 := o2.Args[1]
-		if s2.Op != OpAMD64SHLQconst {
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if v_1_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpAMD64MOVBloadidx1 {
+		if y != v_1_1_0_0_0_0.Args[0] {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		v.reset(OpAMD64RORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (SHRL x y) (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])) (SHLL x (NEGQ y))))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRL {
 			break
 		}
-		if x3.Aux != s {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if p != x3.Args[0] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if idx != x3.Args[1] {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if mem != x3.Args[2] {
+		if v_1_0_0.AuxInt != 32 {
 			break
 		}
-		s3 := o3.Args[1]
-		if s3.Op != OpAMD64SHLQconst {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if s3.AuxInt != 32 {
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpAMD64MOVBloadidx1 {
+		if v_1_0_0_0_0.AuxInt != -32 {
 			break
 		}
-		if x4.AuxInt != i-4 {
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		if x4.Aux != s {
+		if v_1_0_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if p != x4.Args[0] {
+		if y != v_1_0_0_0_0_0.Args[0] {
 			break
 		}
-		if idx != x4.Args[1] {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHLL {
 			break
 		}
-		if mem != x4.Args[2] {
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
 			break
 		}
-		s4 := o4.Args[1]
-		if s4.Op != OpAMD64SHLQconst {
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
 			break
 		}
-		if s4.AuxInt != 40 {
+		if y != v_1_1_1.Args[0] {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpAMD64MOVBloadidx1 {
+		v.reset(OpAMD64RORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (ANDL (SHLL x (NEGQ y)) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32]))) (SHRL x y))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		if x5.AuxInt != i-5 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLL {
 			break
 		}
-		if x5.Aux != s {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
 			break
 		}
-		if p != x5.Args[0] {
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if idx != x5.Args[1] {
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if mem != x5.Args[2] {
+		if v_0_1_0.AuxInt != 32 {
 			break
 		}
-		s5 := o5.Args[1]
-		if s5.Op != OpAMD64SHLQconst {
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if s5.AuxInt != 48 {
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpAMD64MOVBloadidx1 {
+		if v_0_1_0_0_0.AuxInt != -32 {
 			break
 		}
-		if x6.AuxInt != i-6 {
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		if x6.Aux != s {
+		if v_0_1_0_0_0_0.AuxInt != 31 {
 			break
 		}
-		if p != x6.Args[0] {
+		if y != v_0_1_0_0_0_0.Args[0] {
 			break
 		}
-		if idx != x6.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRL {
 			break
 		}
-		if mem != x6.Args[2] {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpAMD64SHLQconst {
+		if y != v_1.Args[1] {
 			break
 		}
-		if s6.AuxInt != 56 {
+		v.reset(OpAMD64RORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ORL (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [31]) [-32])) [32])) (SHLL x (NEGQ y))) (SHRL x y))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpAMD64MOVBloadidx1 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		if x7.AuxInt != i-7 {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
 			break
 		}
-		if x7.Aux != s {
+		if v_0_0_0.AuxInt != 32 {
 			break
 		}
-		if p != x7.Args[0] {
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		if idx != x7.Args[1] {
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		if mem != x7.Args[2] {
+		if v_0_0_0_0_0.AuxInt != -32 {
 			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 [...]
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpAMD64BSWAPQ, v.Type)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64MOVQloadidx1, v.Type)
-		v1.AuxInt = i - 7
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(idx)
-		v1.AddArg(mem)
-		v0.AddArg(v1)
-		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 {
+		if v_0_0_0_0_0_0.AuxInt != 31 {
 			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 {
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLL {
 			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 {
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = c | d
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64ROLBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ROLBconst [c] (ROLBconst [d] x))
-	// cond:
-	// result: (ROLBconst [(c+d)& 7] x)
-	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ROLBconst {
+		if y != v_0_1_1.Args[0] {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(OpAMD64ROLBconst)
-		v.AuxInt = (c + d) & 7
-		v.AddArg(x)
-		return true
-	}
-	// match: (ROLBconst [0] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 0 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORL)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAMD64ROLLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ROLLconst [c] (ROLLconst [d] x))
+func rewriteValueAMD64_OpAMD64ORL_20(v *Value) bool {
+	// match: (ORL (SHRL x y) (ANDL (SHLL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32]))))
 	// cond:
-	// result: (ROLLconst [(c+d)&31] x)
+	// result: (RORL x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ROLLconst {
+		if v_0.Op != OpAMD64SHRL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpAMD64ROLLconst)
-		v.AuxInt = (c + d) & 31
-		v.AddArg(x)
-		return true
-	}
-	// match: (ROLLconst [0] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 0 {
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_0_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 32 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -32 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 31 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORL)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64ROLQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ROLQconst [c] (ROLQconst [d] x))
+	// match: (ORL (SHRL x y) (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])) (SHLL x (NEGL y))))
 	// cond:
-	// result: (ROLQconst [(c+d)&63] x)
+	// result: (RORL x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ROLQconst {
+		if v_0.Op != OpAMD64SHRL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpAMD64ROLQconst)
-		v.AuxInt = (c + d) & 63
-		v.AddArg(x)
-		return true
-	}
-	// match: (ROLQconst [0] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 0 {
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 32 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -32 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 31 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_1_1.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORL)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64ROLWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ROLWconst [c] (ROLWconst [d] x))
+	// match: (ORL (ANDL (SHLL x (NEGL y)) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32]))) (SHRL x y))
 	// cond:
-	// result: (ROLWconst [(c+d)&15] x)
+	// result: (RORL x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64ROLWconst {
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(OpAMD64ROLWconst)
-		v.AuxInt = (c + d) & 15
-		v.AddArg(x)
-		return true
-	}
-	// match: (ROLWconst [0] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 0 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-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 {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 32 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -32 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 31 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
 			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 {
+		if v_1.Op != OpAMD64SHRL {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpAMD64SARBconst)
-		v.AuxInt = c & 31
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORL)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64SARBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SARBconst [c] (MOVQconst [d]))
+	// match: (ORL (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [31]) [-32])) [32])) (SHLL x (NEGL y))) (SHRL x y))
 	// cond:
-	// result: (MOVQconst [d>>uint64(c)])
+	// result: (RORL x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64ANDL {
 			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 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			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 {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 32 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -32 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 31 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_0_1_1.Args[0] {
 			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 {
+		if v_1.Op != OpAMD64SHRL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		if v_1.AuxInt != 31 {
+		if y != v_1.Args[1] {
 			break
 		}
-		y := v_1.Args[0]
-		v.reset(OpAMD64SARL)
+		v.reset(OpAMD64RORL)
 		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)])
+	// match: (ORL (SHLL x (ANDQconst y [15])) (ANDL (SHRW x (NEGQ (ADDQconst (ANDQconst y [15]) [-16]))) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [15]) [-16])) [16]))))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64SHLL {
 			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 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
 			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 {
+		if v_0_1.AuxInt != 15 {
 			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]
+		y := v_0_1.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ANDQconst {
+		if v_1.Op != OpAMD64ANDL {
 			break
 		}
-		if v_1.AuxInt != 63 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRW {
 			break
 		}
-		y := v_1.Args[0]
-		v.reset(OpAMD64SARQ)
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_0_1_0 := v_1_0_1.Args[0]
+		if v_1_0_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_0_1_0.AuxInt != -16 {
+			break
+		}
+		v_1_0_1_0_0 := v_1_0_1_0.Args[0]
+		if v_1_0_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_0_1_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_1_0_1_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 16 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -16 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		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)])
+	// match: (ORL (SHLL x (ANDQconst y [15])) (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [15]) [-16])) [16])) (SHRW x (NEGQ (ADDQconst (ANDQconst y [15]) [-16])))))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64SHLL {
 			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_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1.AuxInt != 15 {
+			break
+		}
+		y := v_0_1.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVQconst {
+		if v_1.Op != OpAMD64ANDL {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
 			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 {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
 			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 {
+		if v_1_0_0.AuxInt != 16 {
 			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 {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
 			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 {
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_1_0_0_0_0.AuxInt != -16 {
 			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 {
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_1_0_0_0_0_0.AuxInt != 15 {
 			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 {
+		if y != v_1_0_0_0_0_0.Args[0] {
 			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 {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRW {
 			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 {
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
 			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 {
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
 			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 {
+		v_1_1_1_0 := v_1_1_1.Args[0]
+		if v_1_1_1_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_1_1_1_0.AuxInt != -16 {
 			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 {
+		v_1_1_1_0_0 := v_1_1_1_0.Args[0]
+		if v_1_1_1_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_1_1_1_0_0.AuxInt != 15 {
 			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 {
+		if y != v_1_1_1_0_0.Args[0] {
 			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 {
+		if !(v.Type.Size() == 2) {
 			break
 		}
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = 1
+		v.reset(OpAMD64ROLW)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SETAE (InvertFlags x))
-	// cond:
-	// result: (SETBE x)
+	// match: (ORL (ANDL (SHRW x (NEGQ (ADDQconst (ANDQconst y [15]) [-16]))) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [15]) [-16])) [16]))) (SHLL x (ANDQconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64InvertFlags {
+		if v_0.Op != OpAMD64ANDL {
 			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 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRW {
 			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 {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
 			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 {
+		v_0_0_1_0 := v_0_0_1.Args[0]
+		if v_0_0_1_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_0_0_1_0.AuxInt != -16 {
 			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 {
+		v_0_0_1_0_0 := v_0_0_1_0.Args[0]
+		if v_0_0_1_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_0_0_1_0_0.AuxInt != 15 {
 			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 {
+		y := v_0_0_1_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
 			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 {
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
 			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 {
+		if v_0_1_0.AuxInt != 16 {
 			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 {
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
 			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 {
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_0_1_0_0_0.AuxInt != -16 {
 			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 {
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_0_1_0_0_0_0.AuxInt != 15 {
 			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 {
+		if y != v_0_1_0_0_0_0.Args[0] {
 			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 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			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 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			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 {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpAMD64SETEQ)
+		if v_1_1.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (SETEQ (FlagEQ))
-	// cond:
-	// result: (MOVLconst [1])
+	// match: (ORL (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [15]) [-16])) [16])) (SHRW x (NEGQ (ADDQconst (ANDQconst y [15]) [-16])))) (SHLL x (ANDQconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64FlagEQ {
+		if v_0.Op != OpAMD64ANDL {
 			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 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			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 {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
 			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 {
+		if v_0_0_0.AuxInt != 16 {
 			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 {
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
 			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 {
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_0_0_0_0_0.AuxInt != -16 {
 			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 {
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_0_0_0_0_0_0.AuxInt != 15 {
 			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 {
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRW {
 			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 {
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
 			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 {
+		v_0_1_1_0 := v_0_1_1.Args[0]
+		if v_0_1_1_0.Op != OpAMD64ADDQconst {
 			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 {
+		if v_0_1_1_0.AuxInt != -16 {
 			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 {
+		v_0_1_1_0_0 := v_0_1_1_0.Args[0]
+		if v_0_1_1_0_0.Op != OpAMD64ANDQconst {
 			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 {
+		if v_0_1_1_0_0.AuxInt != 15 {
 			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 {
+		if y != v_0_1_1_0_0.Args[0] {
 			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 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			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 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpAMD64SETG)
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (SETL (FlagEQ))
-	// cond:
-	// result: (MOVLconst [0])
+	// match: (ORL (SHLL x (ANDLconst y [15])) (ANDL (SHRW x (NEGL (ADDLconst (ANDLconst y [15]) [-16]))) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [15]) [-16])) [16]))))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64FlagEQ {
+		if v_0.Op != OpAMD64SHLL {
 			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 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
 			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 {
+		if v_0_1.AuxInt != 15 {
 			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 {
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRW {
 			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 {
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
 			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 {
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
 			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 {
+		v_1_0_1_0 := v_1_0_1.Args[0]
+		if v_1_0_1_0.Op != OpAMD64ADDLconst {
 			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 {
+		if v_1_0_1_0.AuxInt != -16 {
 			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 {
+		v_1_0_1_0_0 := v_1_0_1_0.Args[0]
+		if v_1_0_1_0_0.Op != OpAMD64ANDLconst {
 			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 {
+		if v_1_0_1_0_0.AuxInt != 15 {
 			break
 		}
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = 0
+		if y != v_1_0_1_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 16 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -16 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SETNE (InvertFlags x))
-	// cond:
-	// result: (SETNE x)
+	// match: (ORL (SHLL x (ANDLconst y [15])) (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [15]) [-16])) [16])) (SHRW x (NEGL (ADDLconst (ANDLconst y [15]) [-16])))))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64InvertFlags {
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
+		_ = v_0.Args[1]
 		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 {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
 			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 {
+		if v_0_1.AuxInt != 15 {
 			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 {
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
 			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 {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
 			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 {
+		if v_1_0_0.AuxInt != 16 {
 			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 {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
 			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 {
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		if v_1.AuxInt != 31 {
+		if v_1_0_0_0_0.AuxInt != -16 {
 			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 {
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
 			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 {
+		if v_1_0_0_0_0_0.AuxInt != 15 {
 			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 {
+		if y != v_1_0_0_0_0_0.Args[0] {
 			break
 		}
-		if v_1.AuxInt != 63 {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRW {
 			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 {
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
 			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 {
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
 			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 {
+		v_1_1_1_0 := v_1_1_1.Args[0]
+		if v_1_1_1_0.Op != OpAMD64ADDLconst {
 			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 {
+		if v_1_1_1_0.AuxInt != -16 {
 			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 {
+		v_1_1_1_0_0 := v_1_1_1_0.Args[0]
+		if v_1_1_1_0_0.Op != OpAMD64ANDLconst {
 			break
 		}
-		if v_1.AuxInt != 31 {
+		if v_1_1_1_0_0.AuxInt != 15 {
 			break
 		}
-		y := v_1.Args[0]
-		v.reset(OpAMD64SHRL)
+		if y != v_1_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		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)
+func rewriteValueAMD64_OpAMD64ORL_30(v *Value) bool {
+	// match: (ORL (ANDL (SHRW x (NEGL (ADDLconst (ANDLconst y [15]) [-16]))) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [15]) [-16])) [16]))) (SHLL x (ANDLconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVQconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			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 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRW {
 			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 {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
 			break
 		}
-		if v_1.AuxInt != 63 {
+		v_0_0_1_0 := v_0_0_1.Args[0]
+		if v_0_0_1_0.Op != OpAMD64ADDLconst {
 			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 {
+		if v_0_0_1_0.AuxInt != -16 {
 			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 {
+		v_0_0_1_0_0 := v_0_0_1_0.Args[0]
+		if v_0_0_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_1_0_0.AuxInt != 15 {
+			break
+		}
+		y := v_0_0_1_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 16 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -16 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
 			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 {
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpAMD64SUBLconst)
-		v.AuxInt = c
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (SUBL (MOVLconst [c]) x)
-	// cond:
-	// result: (NEGL (SUBLconst <v.Type> x [c]))
+	// match: (ORL (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [15]) [-16])) [16])) (SHRW x (NEGL (ADDLconst (ANDLconst y [15]) [-16])))) (SHLL x (ANDLconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (ROLW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVLconst {
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpAMD64NEGL)
-		v0 := b.NewValue0(v.Line, OpAMD64SUBLconst, v.Type)
-		v0.AuxInt = c
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (SUBL x x)
-	// cond:
-	// result: (MOVLconst [0])
-	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			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) {
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 16 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -16 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 15 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRW {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_1_0 := v_0_1_1.Args[0]
+		if v_0_1_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_1_0.AuxInt != -16 {
+			break
+		}
+		v_0_1_1_0_0 := v_0_1_1_0.Args[0]
+		if v_0_1_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_1_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_0_1_1_0_0.Args[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 {
+		if v_1.Op != OpAMD64SHLL {
 			break
 		}
-		c := v_1.AuxInt
-		if !(is32Bit(c)) {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		v.reset(OpAMD64SUBQconst)
-		v.AuxInt = c
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (SUBQ (MOVQconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (NEGQ (SUBQconst <v.Type> x [c]))
+	// match: (ORL (SHRW x (ANDQconst y [15])) (SHLL x (NEGQ (ADDQconst (ANDQconst y [15]) [-16]))))
+	// cond: v.Type.Size() == 2
+	// result: (RORW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64SHRW {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(is32Bit(c)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
 			break
 		}
-		v.reset(OpAMD64NEGQ)
-		v0 := b.NewValue0(v.Line, OpAMD64SUBQconst, v.Type)
-		v0.AuxInt = c
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (SUBQ x x)
-	// cond:
-	// result: (MOVQconst [0])
-	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		if v_0_1.AuxInt != 15 {
 			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 {
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
 			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)) {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		v.reset(OpAMD64ADDQconst)
-		v.AuxInt = -c
-		v.AddArg(x)
-		return true
-	}
-	// match: (SUBQconst (MOVQconst [d]) [c])
-	// cond:
-	// result: (MOVQconst [d-c])
-	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64NEGQ {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = d - c
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != -16 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64RORW)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (SUBQconst (SUBQconst x [d]) [c])
-	// cond: is32Bit(-c-d)
-	// result: (ADDQconst [-c-d] x)
+	// match: (ORL (SHLL x (NEGQ (ADDQconst (ANDQconst y [15]) [-16]))) (SHRW x (ANDQconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (RORW x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64SUBQconst {
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		if !(is32Bit(-c - d)) {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64NEGQ {
 			break
 		}
-		v.reset(OpAMD64ADDQconst)
-		v.AuxInt = -c - d
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64XADDLlock(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XADDLlock [off1] {sym} val (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (XADDLlock [off1+off2] {sym} val ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		val := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64ADDQconst {
 			break
 		}
-		off2 := v_1.AuxInt
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		if v_0_1_0.AuxInt != -16 {
 			break
 		}
-		v.reset(OpAMD64XADDLlock)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64XADDQlock(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XADDQlock [off1] {sym} val (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (XADDQlock [off1+off2] {sym} val ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		val := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64ANDQconst {
 			break
 		}
-		off2 := v_1.AuxInt
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		if v_0_1_0_0.AuxInt != 15 {
 			break
 		}
-		v.reset(OpAMD64XADDQlock)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64XCHGL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (XCHGL [off1+off2] {sym} val ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		val := v.Args[0]
+		y := v_0_1_0_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		if v_1.Op != OpAMD64SHRW {
 			break
 		}
-		off2 := v_1.AuxInt
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		v.reset(OpAMD64XCHGL)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (XCHGL [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB
-	// result: (XCHGL [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		val := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64LEAQ {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
 			break
 		}
-		off2 := v_1.AuxInt
-		sym2 := v_1.Aux
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB) {
+		if v_1_1.AuxInt != 15 {
 			break
 		}
-		v.reset(OpAMD64XCHGL)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64XCHGQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
-	// result: (XCHGQ [off1+off2] {sym} val ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		val := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64ADDQconst {
+		if y != v_1_1.Args[0] {
 			break
 		}
-		off2 := v_1.AuxInt
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		if !(v.Type.Size() == 2) {
 			break
 		}
-		v.reset(OpAMD64XCHGQ)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		v.reset(OpAMD64RORW)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (XCHGQ [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB
-	// result: (XCHGQ [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
+	// match: (ORL (SHRW x (ANDLconst y [15])) (SHLL x (NEGL (ADDLconst (ANDLconst y [15]) [-16]))))
+	// cond: v.Type.Size() == 2
+	// result: (RORW x y)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		val := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64LEAQ {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRW {
 			break
 		}
-		off2 := v_1.AuxInt
-		sym2 := v_1.Aux
-		ptr := v_1.Args[0]
-		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
 			break
 		}
-		v.reset(OpAMD64XCHGQ)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-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]
+		if v_0_1.AuxInt != 15 {
+			break
+		}
+		y := v_0_1.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAMD64MOVLconst {
+		if v_1.Op != OpAMD64SHLL {
 			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 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			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] {
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64NEGL {
 			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] (XORLconst [d] x))
-	// cond:
-	// result: (XORLconst [c ^ d] x)
-	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64XORLconst {
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64ADDLconst {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		v.reset(OpAMD64XORLconst)
-		v.AuxInt = c ^ d
-		v.AddArg(x)
-		return true
-	}
-	// match: (XORLconst [c] x)
-	// cond: int32(c)==0
-	// result: x
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(int32(c) == 0) {
+		if v_1_1_0.AuxInt != -16 {
 			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 {
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64ANDLconst {
 			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 {
+		if v_1_1_0_0.AuxInt != 15 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(is32Bit(c)) {
+		if y != v_1_1_0_0.Args[0] {
 			break
 		}
-		v.reset(OpAMD64XORQconst)
-		v.AuxInt = c
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64RORW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (XORQ (MOVQconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (XORQconst [c] x)
+	// match: (ORL (SHLL x (NEGL (ADDLconst (ANDLconst y [15]) [-16]))) (SHRW x (ANDLconst y [15])))
+	// cond: v.Type.Size() == 2
+	// result: (RORW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(is32Bit(c)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64NEGL {
 			break
 		}
-		v.reset(OpAMD64XORQconst)
-		v.AuxInt = c
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != -16 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0.AuxInt != 15 {
+			break
+		}
+		y := v_0_1_0_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRW {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 15 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64RORW)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (XORQ x x)
-	// cond:
-	// result: (MOVQconst [0])
+	// match: (ORL (SHLL x (ANDQconst y [ 7])) (ANDL (SHRB x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8]))) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])) [ 8]))))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = 0
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_0_1_0 := v_1_0_1.Args[0]
+		if v_1_0_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_0_1_0_0 := v_1_0_1_0.Args[0]
+		if v_1_0_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_0_1_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 8 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XORQconst [c] (XORQconst [d] x))
-	// cond:
-	// result: (XORQconst [c ^ d] x)
+	// match: (ORL (SHLL x (ANDQconst y [ 7])) (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])) [ 8])) (SHRB x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])))))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64XORQconst {
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		d := v_0.AuxInt
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpAMD64XORQconst)
-		v.AuxInt = c ^ d
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 8 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_1_0 := v_1_1_1.Args[0]
+		if v_1_1_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_1_0_0 := v_1_1_1_0.Args[0]
+		if v_1_1_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (XORQconst [0] x)
-	// cond:
-	// result: x
+	// match: (ORL (ANDL (SHRB x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8]))) (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])) [ 8]))) (SHLL x (ANDQconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		if v.AuxInt != 0 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0_1_0 := v_0_0_1.Args[0]
+		if v_0_0_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_0_1_0_0 := v_0_0_1_0.Args[0]
+		if v_0_0_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_0_1_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 8 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (XORQconst [c] (MOVQconst [d]))
-	// cond:
-	// result: (MOVQconst [c^d])
+	// match: (ORL (ANDL (SBBLcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])) [ 8])) (SHRB x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8])))) (SHLL x (ANDQconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64MOVQconst {
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = c ^ d
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 8 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_1_1_0 := v_0_1_1.Args[0]
+		if v_0_1_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_1_0_0 := v_0_1_1_0.Args[0]
+		if v_0_1_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_0_1_1_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpAdd16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_40(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Add16  x y)
-	// cond:
-	// result: (ADDL  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL (SHLL x (ANDLconst y [ 7])) (ANDL (SHRB x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8]))) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])) [ 8]))))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB 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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_0_1_0 := v_1_0_1.Args[0]
+		if v_1_0_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_0_1_0_0 := v_1_0_1_0.Args[0]
+		if v_1_0_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_0_1_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 8 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		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: config.PtrSize == 8
-	// result: (ADDQ x y)
+	// match: (ORL (SHLL x (ANDLconst y [ 7])) (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])) [ 8])) (SHRB x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])))))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
 			break
 		}
-		v.reset(OpAMD64ADDQ)
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDL {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 8 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_1_0 := v_1_1_1.Args[0]
+		if v_1_1_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_1_0_0 := v_1_1_1_0.Args[0]
+		if v_1_1_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (AddPtr x y)
-	// cond: config.PtrSize == 4
-	// result: (ADDL x y)
+	// match: (ORL (ANDL (SHRB x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8]))) (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])) [ 8]))) (SHLL x (ANDLconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		v.reset(OpAMD64ADDL)
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_1_0 := v_0_0_1.Args[0]
+		if v_0_0_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_0_1_0_0 := v_0_0_1_0.Args[0]
+		if v_0_0_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_0_1_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBLcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 8 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Addr {sym} base)
-	// cond: config.PtrSize == 8
-	// result: (LEAQ {sym} base)
+	// match: (ORL (ANDL (SBBLcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])) [ 8])) (SHRB x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8])))) (SHLL x (ANDLconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (ROLB x y)
 	for {
-		sym := v.Aux
-		base := v.Args[0]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
 			break
 		}
-		v.reset(OpAMD64LEAQ)
-		v.Aux = sym
-		v.AddArg(base)
-		return true
-	}
-	// match: (Addr {sym} base)
-	// cond: config.PtrSize == 4
-	// result: (LEAL {sym} base)
-	for {
-		sym := v.Aux
-		base := v.Args[0]
-		if !(config.PtrSize == 4) {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBLcarrymask {
 			break
 		}
-		v.reset(OpAMD64LEAL)
-		v.Aux = sym
-		v.AddArg(base)
-		return true
-	}
-	return false
-}
-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_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 8 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -8 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_1_0 := v_0_1_1.Args[0]
+		if v_0_1_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_1_0_0 := v_0_1_1_0.Args[0]
+		if v_0_1_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_0_1_1_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLB)
 		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)
+	// match: (ORL (SHRB x (ANDQconst y [ 7])) (SHLL x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8]))))
+	// cond: v.Type.Size() == 1
+	// result: (RORB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ANDL)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64RORB)
 		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)
+	// match: (ORL (SHLL x (NEGQ (ADDQconst (ANDQconst y [ 7]) [ -8]))) (SHRB x (ANDQconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (RORB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ANDQ)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_1_0_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64RORB)
 		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)
+	// match: (ORL (SHRB x (ANDLconst y [ 7])) (SHLL x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8]))))
+	// cond: v.Type.Size() == 1
+	// result: (RORB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ANDL)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1.AuxInt != 7 {
+			break
+		}
+		y := v_0_1.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != -8 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1_0_0.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64RORB)
 		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)
+	// match: (ORL (SHLL x (NEGL (ADDLconst (ANDLconst y [ 7]) [ -8]))) (SHRB x (ANDLconst y [ 7])))
+	// cond: v.Type.Size() == 1
+	// result: (RORB x y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ANDL)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != -8 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0.AuxInt != 7 {
+			break
+		}
+		y := v_0_1_0_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRB {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1.AuxInt != 7 {
+			break
+		}
+		if y != v_1_1.Args[0] {
+			break
+		}
+		if !(v.Type.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64RORB)
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicAdd32 ptr val mem)
+	// match: (ORL x x)
 	// cond:
-	// result: (AddTupleFirst32 (XADDLlock val ptr mem) val)
+	// result: x
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64AddTupleFirst32)
-		v0 := b.NewValue0(v.Line, OpAMD64XADDLlock, MakeTuple(config.fe.TypeUInt32(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
-		v.AddArg(v0)
-		v.AddArg(val)
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicAdd64 ptr val mem)
-	// cond:
-	// result: (AddTupleFirst64 (XADDQlock val ptr mem) val)
+	// match: (ORL x0:(MOVBload [i0] {s} p mem) sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64AddTupleFirst64)
-		v0 := b.NewValue0(v.Line, OpAMD64XADDQlock, MakeTuple(config.fe.TypeUInt64(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(val)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpAtomicAnd8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_50(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (AtomicAnd8 ptr val mem)
-	// cond:
-	// result: (ANDBlock ptr val mem)
-	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64ANDBlock)
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueAMD64_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
-	// cond:
-	// result: (CMPXCHGLlock ptr old new_ mem)
-	for {
-		ptr := v.Args[0]
-		old := v.Args[1]
-		new_ := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64CMPXCHGLlock)
-		v.AddArg(ptr)
-		v.AddArg(old)
-		v.AddArg(new_)
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueAMD64_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicCompareAndSwap64 ptr old new_ mem)
-	// cond:
-	// result: (CMPXCHGQlock ptr old new_ mem)
-	for {
-		ptr := v.Args[0]
-		old := v.Args[1]
-		new_ := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpAMD64CMPXCHGQlock)
-		v.AddArg(ptr)
-		v.AddArg(old)
-		v.AddArg(new_)
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueAMD64_OpAtomicExchange32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicExchange32 ptr val mem)
-	// cond:
-	// result: (XCHGL val ptr mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)) x0:(MOVBload [i0] {s} p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64XCHGL)
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicExchange64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicExchange64 ptr val mem)
-	// cond:
-	// result: (XCHGQ val ptr mem)
+	// match: (ORL x0:(MOVWload [i0] {s} p mem) sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64XCHGQ)
-		v.AddArg(val)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicLoad32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoad32 ptr mem)
-	// cond:
-	// result: (MOVLatomicload ptr mem)
+	// match: (ORL sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem)) x0:(MOVWload [i0] {s} p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
 	for {
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		v.reset(OpAMD64MOVLatomicload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicLoad64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoad64 ptr mem)
-	// cond:
-	// result: (MOVQatomicload ptr mem)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		v.reset(OpAMD64MOVQatomicload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicLoadPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoadPtr ptr mem)
-	// cond: config.PtrSize == 8
-	// result: (MOVQatomicload ptr mem)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORL y s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
 			break
 		}
-		v.reset(OpAMD64MOVQatomicload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (AtomicLoadPtr ptr mem)
-	// cond: config.PtrSize == 4
-	// result: (MOVLatomicload ptr mem)
+	// match: (ORL or:(ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) y) s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
 			break
 		}
-		v.reset(OpAMD64MOVLatomicload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueAMD64_OpAtomicOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicOr8 ptr val mem)
-	// cond:
-	// result: (ORBlock ptr val mem)
-	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpAMD64ORBlock)
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicStore32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStore32 ptr val mem)
-	// cond:
-	// result: (Select1 (XCHGL <MakeTuple(config.Frontend().TypeUInt32(),TypeMem)> val ptr mem))
+	// match: (ORL or:(ORL y s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))) s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64XCHGL, MakeTuple(config.Frontend().TypeUInt32(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicStore64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStore64 ptr val mem)
-	// cond:
-	// result: (Select1 (XCHGQ <MakeTuple(config.Frontend().TypeUInt64(),TypeMem)> val ptr mem))
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64XCHGQ, MakeTuple(config.Frontend().TypeUInt64(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStorePtrNoWB ptr val mem)
-	// cond: config.PtrSize == 8
-	// result: (Select1 (XCHGQ <MakeTuple(config.Frontend().TypeBytePtr(),TypeMem)> val ptr mem))
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64XCHGQ, MakeTuple(config.Frontend().TypeBytePtr(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (AtomicStorePtrNoWB ptr val mem)
-	// cond: config.PtrSize == 4
-	// result: (Select1 (XCHGL <MakeTuple(config.Frontend().TypeBytePtr(),TypeMem)> val ptr mem))
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} p idx mem) sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64XCHGL, MakeTuple(config.Frontend().TypeBytePtr(), TypeMem))
-		v0.AddArg(val)
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
 	return false
 }
-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 {
+func rewriteValueAMD64_OpAMD64ORL_60(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Bswap32 x)
-	// cond:
-	// result: (BSWAPL x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	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_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)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com16 x)
-	// cond:
-	// result: (NOTL x)
+	// match: (ORL sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64NOTL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com32 x)
-	// cond:
-	// result: (NOTL x)
+	// match: (ORL sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64NOTL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCom64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com64 x)
-	// cond:
-	// result: (NOTQ x)
+	// match: (ORL sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64NOTQ)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com8  x)
-	// cond:
-	// result: (NOTL x)
+	// match: (ORL sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64NOTL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const16  [val])
-	// cond:
-	// result: (MOVLconst [val])
+	// match: (ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		val := v.AuxInt
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = val
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const32  [val])
-	// cond:
-	// result: (MOVLconst [val])
+	// match: (ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ConstBool [b])
-	// cond:
-	// result: (MOVLconst [b])
+	// match: (ORL x0:(MOVWloadidx1 [i0] {s} p idx mem) sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		b := v.AuxInt
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = b
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ConstNil)
-	// cond: config.PtrSize == 8
-	// result: (MOVQconst [0])
+	// match: (ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
 			break
 		}
-		v.reset(OpAMD64MOVQconst)
-		v.AuxInt = 0
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (ConstNil)
-	// cond: config.PtrSize == 4
-	// result: (MOVLconst [0])
+	// match: (ORL sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
 			break
 		}
-		v.reset(OpAMD64MOVLconst)
-		v.AuxInt = 0
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpConvert(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_70(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Convert <t> x mem)
-	// cond: config.PtrSize == 8
-	// result: (MOVQconvert <t> x mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		mem := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
 			break
 		}
-		v.reset(OpAMD64MOVQconvert)
-		v.Type = t
-		v.AddArg(x)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Convert <t> x mem)
-	// cond: config.PtrSize == 4
-	// result: (MOVLconvert <t> x mem)
-	for {
-		t := v.Type
-		x := v.Args[0]
-		mem := v.Args[1]
-		if !(config.PtrSize == 4) {
+		if sh.AuxInt != 16 {
 			break
 		}
-		v.reset(OpAMD64MOVLconvert)
-		v.Type = t
-		v.AddArg(x)
-		v.AddArg(mem)
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpCtz32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Ctz32 <t> x)
-	// cond:
-	// result: (CMOVLEQ (Select0 <t> (BSFL x)) (MOVLconst <t> [32]) (Select1 <TypeFlags> (BSFL x)))
+	// match: (ORL sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v.reset(OpAMD64CMOVLEQ)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
-		v1 := b.NewValue0(v.Line, OpAMD64BSFL, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpAMD64MOVLconst, t)
-		v2.AuxInt = 32
-		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSelect1, TypeFlags)
-		v4 := b.NewValue0(v.Line, OpAMD64BSFL, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v4.AddArg(x)
-		v3.AddArg(v4)
-		v.AddArg(v3)
-		return true
-	}
-}
-func rewriteValueAMD64_OpCtz64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Ctz64 <t> x)
-	// cond:
-	// result: (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <TypeFlags> (BSFQ x)))
-	for {
-		t := v.Type
-		x := v.Args[0]
-		v.reset(OpAMD64CMOVQEQ)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
-		v1 := b.NewValue0(v.Line, OpAMD64BSFQ, MakeTuple(config.fe.TypeUInt64(), TypeFlags))
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpAMD64MOVQconst, t)
-		v2.AuxInt = 64
-		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSelect1, TypeFlags)
-		v4 := b.NewValue0(v.Line, OpAMD64BSFQ, MakeTuple(config.fe.TypeUInt64(), TypeFlags))
-		v4.AddArg(x)
-		v3.AddArg(v4)
-		v.AddArg(v3)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32Fto32 x)
-	// cond:
-	// result: (CVTTSS2SL x)
+	// match: (ORL sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTTSS2SL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt32Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32Fto64 x)
-	// cond:
-	// result: (CVTTSS2SQ x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTTSS2SQ)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32Fto64F x)
-	// cond:
-	// result: (CVTSS2SD x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSS2SD)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32to32F x)
-	// cond:
-	// result: (CVTSL2SS x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSL2SS)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32to64F x)
-	// cond:
-	// result: (CVTSL2SD x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSL2SD)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt64Fto32 x)
-	// cond:
-	// result: (CVTTSD2SL x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTTSD2SL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt64Fto32F x)
-	// cond:
-	// result: (CVTSD2SS x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSD2SS)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt64Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt64Fto64 x)
-	// cond:
-	// result: (CVTTSD2SQ x)
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTTSD2SQ)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpCvt64to32F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_80(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Cvt64to32F x)
-	// cond:
-	// result: (CVTSQ2SS x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSQ2SS)
-		v.AddArg(x)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpCvt64to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt64to64F x)
-	// cond:
-	// result: (CVTSQ2SD x)
+	// match: (ORL or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64CVTSQ2SD)
-		v.AddArg(x)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDeferCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (DeferCall [argwid] mem)
-	// cond:
-	// result: (CALLdefer [argwid] mem)
+	// match: (ORL or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		argwid := v.AuxInt
-		mem := v.Args[0]
-		v.reset(OpAMD64CALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv128u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div128u xhi xlo y)
-	// cond:
-	// result: (DIVQU2 xhi xlo y)
-	for {
-		xhi := v.Args[0]
-		xlo := v.Args[1]
-		y := v.Args[2]
-		v.reset(OpAMD64DIVQU2)
-		v.AddArg(xhi)
-		v.AddArg(xlo)
-		v.AddArg(y)
-		return true
-	}
-}
-func rewriteValueAMD64_OpDiv16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div16  x y)
-	// cond:
-	// result: (Select0 (DIVW  x y))
+	// match: (ORL or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVW, MakeTuple(config.fe.TypeInt16(), config.fe.TypeInt16()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div16u x y)
-	// cond:
-	// result: (Select0 (DIVWU x y))
+	// match: (ORL or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVWU, MakeTuple(config.fe.TypeUInt16(), config.fe.TypeUInt16()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div32  x y)
-	// cond:
-	// result: (Select0 (DIVL  x y))
+	// match: (ORL or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVL, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.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)
+	// match: (ORL or:(ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64DIVSS)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div32u x y)
-	// cond:
-	// result: (Select0 (DIVLU x y))
+	// match: (ORL or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVLU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div64  x y)
-	// cond:
-	// result: (Select0 (DIVQ  x y))
+	// match: (ORL or:(ORL y s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))) s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVQ, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		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: (Select0 (DIVQU x y))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVQU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		v0.AddArg(y)
-		v.AddArg(v0)
 		return true
 	}
-}
-func rewriteValueAMD64_OpDiv8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div8   x y)
-	// cond:
-	// result: (Select0 (DIVW  (SignExt8to16 x) (SignExt8to16 y)))
+	// match: (ORL x1:(MOVBload [i1] {s} p mem) sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVW, MakeTuple(config.fe.TypeInt16(), config.fe.TypeInt16()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
-		v2.AddArg(y)
-		v0.AddArg(v2)
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueAMD64_OpDiv8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div8u  x y)
-	// cond:
-	// result: (Select0 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVWU, MakeTuple(config.fe.TypeUInt16(), config.fe.TypeUInt16()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
-		v1.AddArg(x)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpEq16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_90(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq16  x y)
-	// cond:
-	// result: (SETEQ (CMPW x y))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p mem)) x1:(MOVBload [i1] {s} p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEq32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Eq32  x y)
-	// cond:
-	// result: (SETEQ (CMPL x y))
+	// match: (ORL r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
 	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.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEq32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Eq32F x y)
-	// cond:
-	// result: (SETEQF (UCOMISS x y))
+	// match: (ORL sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEq64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Eq64  x y)
-	// cond:
-	// result: (SETEQ (CMPQ x y))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEq64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Eq64F x y)
-	// cond:
-	// result: (SETEQF (UCOMISD x y))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORL y s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEq8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Eq8   x y)
-	// cond:
-	// result: (SETEQ (CMPB x y))
+	// match: (ORL or:(ORL s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem)) y) s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (EqB   x y)
-	// cond:
-	// result: (SETEQ (CMPB x y))
+	// match: (ORL or:(ORL y s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))) s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpEqPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (EqPtr x y)
-	// cond: config.PtrSize == 8
-	// result: (SETEQ (CMPQ x y))
+	// match: (ORL x1:(MOVBloadidx1 [i1] {s} p idx mem) sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64SETEQ)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
-		v0.AddArg(x)
-		v0.AddArg(y)
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (EqPtr x y)
-	// cond: config.PtrSize == 4
-	// result: (SETEQ (CMPL x y))
+	// match: (ORL x1:(MOVBloadidx1 [i1] {s} idx p mem) sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64SETEQ)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
-		v0.AddArg(x)
-		v0.AddArg(y)
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpGeq16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq16  x y)
-	// cond:
-	// result: (SETGE (CMPW x y))
+	// match: (ORL x1:(MOVBloadidx1 [i1] {s} p idx mem) sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_100(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq16U x y)
-	// cond:
-	// result: (SETAE (CMPW x y))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL x1:(MOVBloadidx1 [i1] {s} idx p mem) sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq32  x y)
-	// cond:
-	// result: (SETGE (CMPL x y))
+	// match: (ORL sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)) x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq32F x y)
-	// cond:
-	// result: (SETGEF (UCOMISS x y))
+	// match: (ORL sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)) x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq32U x y)
-	// cond:
-	// result: (SETAE (CMPL x y))
+	// match: (ORL sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)) x1:(MOVBloadidx1 [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq64  x y)
-	// cond:
-	// result: (SETGE (CMPQ x y))
+	// match: (ORL sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)) x1:(MOVBloadidx1 [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq64F x y)
-	// cond:
-	// result: (SETGEF (UCOMISD x y))
+	// match: (ORL r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq64U x y)
-	// cond:
-	// result: (SETAE (CMPQ x y))
+	// match: (ORL r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq8   x y)
-	// cond:
-	// result: (SETGE (CMPB x y))
+	// match: (ORL r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGeq8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Geq8U  x y)
-	// cond:
-	// result: (SETAE (CMPB x y))
+	// match: (ORL r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)) sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		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)
+	// match: (ORL sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	for {
-		argwid := v.AuxInt
-		mem := v.Args[0]
-		v.reset(OpAMD64CALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_110(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater16  x y)
-	// cond:
-	// result: (SETG (CMPW x y))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGreater16U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater16U x y)
-	// cond:
-	// result: (SETA (CMPW x y))
+	// match: (ORL sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGreater32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater32  x y)
-	// cond:
-	// result: (SETG (CMPL x y))
+	// match: (ORL sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLLconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGreater32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater32F x y)
-	// cond:
-	// result: (SETGF (UCOMISS x y))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		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))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGreater64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater64F x y)
-	// cond:
-	// result: (SETGF (UCOMISD x y))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		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))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpGreater8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater8U  x y)
-	// cond:
-	// result: (SETA (CMPB x y))
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16  x y)
-	// cond:
-	// result: (HMULW  x y)
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64HMULW)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.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)
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64HMULWU)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpHmul32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL_120(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Hmul32  x y)
-	// cond:
-	// result: (HMULL  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORL s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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_OpInt64Hi(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Int64Hi x)
-	// cond:
-	// result: (SHRQconst [32] x)
-	for {
-		x := v.Args[0]
-		v.reset(OpAMD64SHRQconst)
-		v.AuxInt = 32
-		v.AddArg(x)
-		return true
-	}
-}
-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: config.PtrSize == 8
-	// result: (SETNE (TESTQ p p))
-	for {
-		p := v.Args[0]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLLconst {
 			break
 		}
-		v.reset(OpAMD64SETNE)
-		v0 := b.NewValue0(v.Line, OpAMD64TESTQ, TypeFlags)
-		v0.AddArg(p)
-		v0.AddArg(p)
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (IsNonNil p)
-	// cond: config.PtrSize == 4
-	// result: (SETNE (TESTL p p))
+	// match: (ORL or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	for {
-		p := v.Args[0]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
 			break
 		}
-		v.reset(OpAMD64SETNE)
-		v0 := b.NewValue0(v.Line, OpAMD64TESTL, TypeFlags)
-		v0.AddArg(p)
-		v0.AddArg(p)
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpIsSliceInBounds(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (IsSliceInBounds idx len)
-	// cond:
-	// result: (SETBE (CMPQ idx len))
+	// match: (ORL or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		return true
-	}
-}
-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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		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))
+	// match: (ORL or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		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))
+	// match: (ORL or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		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))
+	// match: (ORL or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLeq64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq64F x y)
-	// cond:
-	// result: (SETGEF (UCOMISD y x))
+	// match: (ORL or:(ORL s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLeq64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq64U x y)
-	// cond:
-	// result: (SETBE (CMPQ x y))
+	// match: (ORL or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLeq8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq8   x y)
-	// cond:
-	// result: (SETLE (CMPB x y))
+	// match: (ORL or:(ORL y s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))) s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) 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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORL {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLLconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLeq8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq8U  x y)
-	// cond:
-	// result: (SETBE (CMPB x y))
+	// match: (ORL x l:(MOVLload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ORLmem x [off] {sym} ptr mem)
 	for {
+		_ = v.Args[1]
 		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)
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ORLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpLess16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less16  x y)
-	// cond:
-	// result: (SETL (CMPW x y))
+func rewriteValueAMD64_OpAMD64ORL_130(v *Value) bool {
+	// match: (ORL l:(MOVLload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ORLmem x [off] {sym} ptr mem)
 	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)
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ORLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpLess16U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less16U x y)
-	// cond:
-	// result: (SETB (CMPW x y))
+func rewriteValueAMD64_OpAMD64ORLconst_0(v *Value) bool {
+	// match: (ORLconst [c] x)
+	// cond: int32(c)==0
+	// result: x
 	for {
+		c := v.AuxInt
 		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)
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLess32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less32  x y)
-	// cond:
-	// result: (SETL (CMPL x y))
+	// match: (ORLconst [c] _)
+	// cond: int32(c)==-1
+	// result: (MOVLconst [-1])
 	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)
+		c := v.AuxInt
+		if !(int32(c) == -1) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = -1
 		return true
 	}
-}
-func rewriteValueAMD64_OpLess32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less32F x y)
+	// match: (ORLconst [c] (MOVLconst [d]))
 	// cond:
-	// result: (SETGF (UCOMISS y x))
+	// result: (MOVLconst [c|d])
 	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)
+		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_OpLess32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less32U x y)
-	// cond:
-	// result: (SETB (CMPL x y))
+func rewriteValueAMD64_OpAMD64ORQ_0(v *Value) bool {
+	// match: (ORQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (ORQconst [c] x)
 	for {
+		_ = v.Args[1]
 		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)
+		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
 	}
-}
-func rewriteValueAMD64_OpLess64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less64  x y)
-	// cond:
-	// result: (SETL (CMPQ x y))
+	// match: (ORQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (ORQconst [c] x)
 	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)
+		_ = v.Args[1]
+		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
 	}
-}
-func rewriteValueAMD64_OpLess64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less64F x y)
-	// cond:
-	// result: (SETGF (UCOMISD y x))
+	// match: (ORQ (SHLQconst x [c]) (SHRQconst x [d]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
 	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)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLess64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less64U x y)
-	// cond:
-	// result: (SETB (CMPQ x y))
+	// match: (ORQ (SHRQconst x [d]) (SHLQconst x [c]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
 	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)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLess8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less8   x y)
+	// match: (ORQ (SHLQ x y) (ANDQ (SHRQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64]))))
 	// cond:
-	// result: (SETL (CMPB x y))
+	// result: (ROLQ 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)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_1_0_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 64 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLess8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less8U  x y)
+	// match: (ORQ (SHLQ x y) (ANDQ (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])) (SHRQ x (NEGQ y))))
 	// cond:
-	// result: (SETB (CMPB x y))
+	// result: (ROLQ 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) && config.PtrSize == 8)
-	// result: (MOVQload ptr mem)
-	for {
-		t := v.Type
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(is64BitInt(t) || isPtr(t) && config.PtrSize == 8) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQ {
 			break
 		}
-		v.reset(OpAMD64MOVQload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Load <t> ptr mem)
-	// cond: (is32BitInt(t) || isPtr(t) && config.PtrSize == 4)
-	// result: (MOVLload ptr mem)
-	for {
-		t := v.Type
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(is32BitInt(t) || isPtr(t) && config.PtrSize == 4) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
 			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)) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBQcarrymask {
 			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)) {
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
 			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)) {
+		if v_1_0_0.AuxInt != 64 {
 			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)) {
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
 			break
 		}
-		v.reset(OpAMD64MOVSDload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_1_1_1.Args[0] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpLrot16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot16 <t> x [c])
+	// match: (ORQ (ANDQ (SHRQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64]))) (SHLQ x y))
 	// cond:
-	// result: (ROLWconst <t> [c&15] x)
+	// result: (ROLQ x y)
 	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpAMD64ROLWconst)
-		v.Type = t
-		v.AuxInt = c & 15
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 64 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLrot32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot32 <t> x [c])
+	// match: (ORQ (ANDQ (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])) (SHRQ x (NEGQ y))) (SHLQ x y))
 	// cond:
-	// result: (ROLLconst <t> [c&31] x)
+	// result: (ROLQ x y)
 	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpAMD64ROLLconst)
-		v.Type = t
-		v.AuxInt = c & 31
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 64 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_0_1_1.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLrot64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot64 <t> x [c])
+	// match: (ORQ (SHLQ x y) (ANDQ (SHRQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64]))))
 	// cond:
-	// result: (ROLQconst <t> [c&63] x)
+	// result: (ROLQ x y)
 	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpAMD64ROLQconst)
-		v.Type = t
-		v.AuxInt = c & 63
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_0_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 64 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLrot8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot8  <t> x [c])
+	// match: (ORQ (SHLQ x y) (ANDQ (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])) (SHRQ x (NEGL y))))
 	// cond:
-	// result: (ROLBconst <t> [c&7] x)
+	// result: (ROLQ x y)
 	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpAMD64ROLBconst)
-		v.Type = t
-		v.AuxInt = c & 7
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 64 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_1_1.Args[0] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x16 <t> x y)
+func rewriteValueAMD64_OpAMD64ORQ_10(v *Value) bool {
+	// match: (ORQ (ANDQ (SHRQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64]))) (SHLQ x y))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	// result: (ROLQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 64 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x32 <t> x y)
+	// match: (ORQ (ANDQ (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])) (SHRQ x (NEGL y))) (SHLQ x y))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	// result: (ROLQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 64 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_0_1_1.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x64 <t> x y)
+	// match: (ORQ (SHRQ x y) (ANDQ (SHLQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64]))))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_1_0_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 64 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x8  <t> x y)
+	// match: (ORQ (SHRQ x y) (ANDQ (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])) (SHLQ x (NEGQ y))))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
-		return true
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 64 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_1_1_1.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
 	}
-}
-func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh32x16 <t> x y)
+	// match: (ORQ (ANDQ (SHLQ x (NEGQ y)) (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64]))) (SHRQ x y))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 64 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh32x32 <t> x y)
+	// match: (ORQ (ANDQ (SBBQcarrymask (CMPQconst (NEGQ (ADDQconst (ANDQconst y [63]) [-64])) [64])) (SHLQ x (NEGQ y))) (SHRQ x y))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 64 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGQ {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGQ {
+			break
+		}
+		if y != v_0_1_1.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh32x64 <t> x y)
+	// match: (ORQ (SHRQ x y) (ANDQ (SHLQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64]))))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1_0.Args[1]
+		if x != v_1_0.Args[0] {
+			break
+		}
+		v_1_0_1 := v_1_0.Args[1]
+		if v_1_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_0_1.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_1_0 := v_1_1.Args[0]
+		if v_1_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_1_0.AuxInt != 64 {
+			break
+		}
+		v_1_1_0_0 := v_1_1_0.Args[0]
+		if v_1_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_1_0_0_0 := v_1_1_0_0.Args[0]
+		if v_1_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_1_0_0_0_0 := v_1_1_0_0_0.Args[0]
+		if v_1_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_1_0_0_0_0.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh32x8  <t> x y)
+	// match: (ORQ (SHRQ x y) (ANDQ (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])) (SHLQ x (NEGL y))))
 	// cond:
-	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	// result: (RORQ x y)
 	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.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_1_0_0 := v_1_0.Args[0]
+		if v_1_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_1_0_0.AuxInt != 64 {
+			break
+		}
+		v_1_0_0_0 := v_1_0_0.Args[0]
+		if v_1_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_1_0_0_0_0 := v_1_0_0_0.Args[0]
+		if v_1_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_1_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_1_0_0_0_0_0 := v_1_0_0_0_0.Args[0]
+		if v_1_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_1_0_0_0_0_0.Args[0] {
+			break
+		}
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_1_1.Args[1]
+		if x != v_1_1.Args[0] {
+			break
+		}
+		v_1_1_1 := v_1_1.Args[1]
+		if v_1_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_1_1_1.Args[0] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh64x16 <t> x y)
+	// match: (ORQ (ANDQ (SHLQ x (NEGL y)) (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64]))) (SHRQ x y))
 	// cond:
-	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+	// result: (RORQ x y)
 	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.AuxInt = 64
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_0_0_1.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 64 {
+			break
+		}
+		v_0_1_0_0 := v_0_1_0.Args[0]
+		if v_0_1_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_1_0_0_0 := v_0_1_0_0.Args[0]
+		if v_0_1_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_1_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_1_0_0_0_0 := v_0_1_0_0_0.Args[0]
+		if v_0_1_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_1_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		if y != v_0_1_0_0_0_0.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh64x32 <t> x y)
+	// match: (ORQ (ANDQ (SBBQcarrymask (CMPLconst (NEGL (ADDLconst (ANDLconst y [63]) [-64])) [64])) (SHLQ x (NEGL y))) (SHRQ x y))
 	// cond:
-	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+	// result: (RORQ x y)
 	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.AuxInt = 64
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SBBQcarrymask {
+			break
+		}
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64CMPLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 64 {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpAMD64NEGL {
+			break
+		}
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		if v_0_0_0_0_0.AuxInt != -64 {
+			break
+		}
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_0_0_0_0_0_0.AuxInt != 63 {
+			break
+		}
+		y := v_0_0_0_0_0_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		x := v_0_1.Args[0]
+		v_0_1_1 := v_0_1.Args[1]
+		if v_0_1_1.Op != OpAMD64NEGL {
+			break
+		}
+		if y != v_0_1_1.Args[0] {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQ {
+			break
+		}
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
+			break
+		}
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x64 <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ x x)
 	// cond:
-	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+	// result: x
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		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.AuxInt = 64
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		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])))
+	// match: (ORQ x0:(MOVBload [i0] {s} p mem) sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 64
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		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])))
+	// match: (ORQ sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem)) x0:(MOVBload [i0] {s} p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		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])))
+	// match: (ORQ x0:(MOVWload [i0] {s} p mem) sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		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])))
+	// match: (ORQ sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem)) x0:(MOVWload [i0] {s} p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		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])))
+	// match: (ORQ x0:(MOVLload [i0] {s} p mem) sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVLload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMod16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod16  x y)
-	// cond:
-	// result: (Select1 (DIVW  x y))
+	// match: (ORQ sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem)) x0:(MOVLload [i0] {s} p mem))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVW, MakeTuple(config.fe.TypeInt16(), config.fe.TypeInt16()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVLload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMod16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod16u x y)
-	// cond:
-	// result: (Select1 (DIVWU x y))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVWU, MakeTuple(config.fe.TypeUInt16(), config.fe.TypeUInt16()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueAMD64_OpMod32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod32  x y)
-	// cond:
-	// result: (Select1 (DIVL  x y))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVL, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		v0.AddArg(y)
-		v.AddArg(v0)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMod32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod32u x y)
-	// cond:
-	// result: (Select1 (DIVLU x y))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVLU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMod64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod64  x y)
-	// cond:
-	// result: (Select1 (DIVQ  x y))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) y) s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVQ, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v0.AddArg(x)
-		v0.AddArg(y)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpMod64u(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_30(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod64u x y)
-	// cond:
-	// result: (Select1 (DIVQU x y))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))) s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVQU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v0.AddArg(x)
-		v0.AddArg(y)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueAMD64_OpMod8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod8   x y)
-	// cond:
-	// result: (Select1 (DIVW  (SignExt8to16 x) (SignExt8to16 y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVW, MakeTuple(config.fe.TypeInt16(), config.fe.TypeInt16()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueAMD64_OpMod8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod8u  x y)
-	// cond:
-	// result: (Select1 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpAMD64DIVWU, MakeTuple(config.fe.TypeUInt16(), config.fe.TypeUInt16()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueAMD64_OpMove(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
-	// result: mem
-	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = mem.Type
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
-	// result: (MOVBstore dst (MOVBload src mem) mem)
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
 			break
 		}
-		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 [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
-	// result: (MOVWstore dst (MOVWload src mem) mem)
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
 			break
 		}
-		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 [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
-	// result: (MOVLstore dst (MOVLload src mem) mem)
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
 			break
 		}
-		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 [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8
-	// result: (MOVQstore dst (MOVQload src mem) mem)
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
 			break
 		}
-		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 [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 16
-	// result: (MOVOstore dst (MOVOload src mem) mem)
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 16) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		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 [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
-	// result: (MOVBstore [2] dst (MOVBload [2] src mem) 		(MOVWstore dst (MOVWload src mem) mem))
-	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
 			break
 		}
-		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)
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 5
-	// result: (MOVBstore [4] dst (MOVBload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 5) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
 			break
 		}
-		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)
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6
-	// result: (MOVWstore [4] dst (MOVWload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
 			break
 		}
-		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)
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 7
-	// result: (MOVLstore [3] dst (MOVLload [3] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem)) y) s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 7) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		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)
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() < 16
-	// result: (MOVQstore [SizeAndAlign(s).Size()-8] dst (MOVQload [SizeAndAlign(s).Size()-8] src mem) 		(MOVQstore dst (MOVQload src mem) mem))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem))) s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() < 16) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		v.reset(OpAMD64MOVQstore)
-		v.AuxInt = SizeAndAlign(s).Size() - 8
-		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
-		v0.AuxInt = SizeAndAlign(s).Size() - 8
-		v0.AddArg(src)
-		v0.AddArg(mem)
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 <= 8
-	// result: (Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%16] 		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()%16]) 		(OffPtr <src.Type> src [SizeAndAlign(s).Size()%16]) 		(MOVQstore dst (MOVQload src mem) mem))
+	// match: (ORQ x0:(MOVBloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 <= 8) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpMove)
-		v.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%16
-		v0 := b.NewValue0(v.Line, OpOffPtr, dst.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() % 16
-		v0.AddArg(dst)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOffPtr, src.Type)
-		v1.AuxInt = SizeAndAlign(s).Size() % 16
-		v1.AddArg(src)
-		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)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 > 8
-	// result: (Move [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%16] 		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()%16]) 		(OffPtr <src.Type> src [SizeAndAlign(s).Size()%16]) 		(MOVOstore dst (MOVOload src mem) mem))
+	// match: (ORQ x0:(MOVBloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 16 && SizeAndAlign(s).Size()%16 != 0 && SizeAndAlign(s).Size()%16 > 8) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpMove)
-		v.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%16
-		v0 := b.NewValue0(v.Line, OpOffPtr, dst.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() % 16
-		v0.AddArg(dst)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOffPtr, src.Type)
-		v1.AuxInt = SizeAndAlign(s).Size() % 16
-		v1.AddArg(src)
-		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)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() >= 32 && SizeAndAlign(s).Size() <= 16*64 && SizeAndAlign(s).Size()%16 == 0 	&& !config.noDuffDevice
-	// result: (DUFFCOPY [14*(64-SizeAndAlign(s).Size()/16)] dst src mem)
+	// match: (ORQ x0:(MOVBloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() >= 32 && SizeAndAlign(s).Size() <= 16*64 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64DUFFCOPY)
-		v.AuxInt = 14 * (64 - SizeAndAlign(s).Size()/16)
-		v.AddArg(dst)
-		v.AddArg(src)
-		v.AddArg(mem)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: (SizeAndAlign(s).Size() > 16*64 || config.noDuffDevice) && SizeAndAlign(s).Size()%8 == 0
-	// result: (REPMOVSQ dst src (MOVQconst [SizeAndAlign(s).Size()/8]) mem)
+	// match: (ORQ x0:(MOVBloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !((SizeAndAlign(s).Size() > 16*64 || config.noDuffDevice) && SizeAndAlign(s).Size()%8 == 0) {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64REPMOVSQ)
-		v.AddArg(dst)
-		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
-		v0.AuxInt = SizeAndAlign(s).Size() / 8
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(mem)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.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)
+	// match: (ORQ sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	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)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpMul32F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_40(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mul32F x y)
-	// cond:
-	// result: (MULSS x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64MULSS)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64  x y)
-	// cond:
-	// result: (MULQ  x y)
+	// match: (ORQ sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64MULQ)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64F x y)
-	// cond:
-	// result: (MULSD x y)
+	// match: (ORQ sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)) x0:(MOVBloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64MULSD)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMul64uhilo(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64uhilo x y)
-	// cond:
-	// result: (MULQU2 x y)
+	// match: (ORQ x0:(MOVWloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64MULQU2)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul8   x y)
-	// cond:
-	// result: (MULL  x y)
+	// match: (ORQ x0:(MOVWloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64MULL)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg16  x)
-	// cond:
-	// result: (NEGL x)
+	// match: (ORQ x0:(MOVWloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		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))]))
+	// match: (ORQ x0:(MOVWloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg8   x)
-	// cond:
-	// result: (NEGL x)
+	// match: (ORQ sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64NEGL)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeq16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neq16  x y)
-	// cond:
-	// result: (SETNE (CMPW x y))
+	// match: (ORQ sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeq32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neq32  x y)
-	// cond:
-	// result: (SETNE (CMPL x y))
+	// match: (ORQ sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_50(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq32F x y)
-	// cond:
-	// result: (SETNEF (UCOMISS x y))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeq64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neq64  x y)
-	// cond:
-	// result: (SETNE (CMPQ x y))
+	// match: (ORQ x0:(MOVLloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeq64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neq64F x y)
-	// cond:
-	// result: (SETNEF (UCOMISD x y))
+	// match: (ORQ x0:(MOVLloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeq8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neq8   x y)
-	// cond:
-	// result: (SETNE (CMPB x y))
+	// match: (ORQ x0:(MOVLloadidx1 [i0] {s} p idx mem) sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NeqB   x y)
-	// cond:
-	// result: (SETNE (CMPB x y))
+	// match: (ORQ x0:(MOVLloadidx1 [i0] {s} idx p mem) sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	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.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-}
-func rewriteValueAMD64_OpNeqPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NeqPtr x y)
-	// cond: config.PtrSize == 8
-	// result: (SETNE (CMPQ x y))
+	// match: (ORQ sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)) x0:(MOVLloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64SETNE)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
-		v0.AddArg(x)
-		v0.AddArg(y)
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (NeqPtr x y)
-	// cond: config.PtrSize == 4
-	// result: (SETNE (CMPL x y))
+	// match: (ORQ sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} idx p mem)) x0:(MOVLloadidx1 [i0] {s} p idx mem))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64SETNE)
-		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
-		v0.AddArg(x)
-		v0.AddArg(y)
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-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)
+	// match: (ORQ sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)) x0:(MOVLloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64XORLconst)
-		v.AuxInt = 1
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueAMD64_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (OffPtr [off] ptr)
-	// cond: config.PtrSize == 8 && is32Bit(off)
-	// result: (ADDQconst [off] ptr)
-	for {
-		off := v.AuxInt
-		ptr := v.Args[0]
-		if !(config.PtrSize == 8 && is32Bit(off)) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64ADDQconst)
-		v.AuxInt = off
-		v.AddArg(ptr)
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (OffPtr [off] ptr)
-	// cond: config.PtrSize == 8
-	// result: (ADDQ (MOVQconst [off]) ptr)
+	// match: (ORQ sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} idx p mem)) x0:(MOVLloadidx1 [i0] {s} idx p mem))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
 	for {
-		off := v.AuxInt
-		ptr := v.Args[0]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64ADDQ)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
-		v0.AuxInt = off
+		if sh.AuxInt != 32 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(ptr)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (OffPtr [off] ptr)
-	// cond: config.PtrSize == 4
-	// result: (ADDLconst [off] ptr)
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		off := v.AuxInt
-		ptr := v.Args[0]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64ADDLconst)
-		v.AuxInt = off
-		v.AddArg(ptr)
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-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 {
+func rewriteValueAMD64_OpAMD64ORQ_60(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Or32 x y)
-	// cond:
-	// result: (ORL x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ORL)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.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)
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ORQ)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.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)
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64ORL)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.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)
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) 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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
-		v2.AuxInt = 16
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
-		v2.AuxInt = 16
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
-		v2.AuxInt = 16
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 16
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 16
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 16
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 16
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_70(v *Value) 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])))))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 16
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) y) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) y) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		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(v1)
 		v0.AddArg(y)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 32
-		v2.AddArg(y)
-		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])))))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem))) s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 32
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 32
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem)) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 32
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 32
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)) or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
-		v2.AuxInt = 64
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		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(v1)
 		v0.AddArg(y)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
-		v2.AuxInt = 64
-		v2.AddArg(y)
-		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])))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
-		v2.AuxInt = 64
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		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(v1)
 		v0.AddArg(y)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 64
-		v2.AddArg(y)
-		v1.AddArg(v2)
-		v.AddArg(v1)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_80(v *Value) 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])))))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 64
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 64
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)) or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 64
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem)) y) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 64
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem)) y) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
-		v2.AuxInt = 8
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
-		v2.AuxInt = 8
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem))) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
-		v2.AuxInt = 8
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem)) y) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
-		v2.AuxInt = 8
-		v2.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem)) y) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 8
-		v3.AddArg(y)
-		v2.AddArg(v3)
-		v1.AddArg(v2)
-		v0.AddArg(v1)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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.AuxInt = 8
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		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])))))
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 8
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_90(v *Value) 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])))))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} idx p mem))) s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
 	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.AuxInt = 8
-		v3.AddArg(y)
-		v2.AddArg(v3)
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpSelect0(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Select0 <t> (AddTupleFirst32 tuple val))
-	// cond:
-	// result: (ADDL val (Select0 <t> tuple))
+	// match: (ORQ x1:(MOVBload [i1] {s} p mem) sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
 	for {
-		t := v.Type
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64AddTupleFirst32 {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBload {
 			break
 		}
-		tuple := v_0.Args[0]
-		val := v_0.Args[1]
-		v.reset(OpAMD64ADDL)
-		v.AddArg(val)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
-		v0.AddArg(tuple)
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (Select0 <t> (AddTupleFirst64 tuple val))
-	// cond:
-	// result: (ADDQ val (Select0 <t> tuple))
+	// match: (ORQ sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p mem)) x1:(MOVBload [i1] {s} p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
 	for {
-		t := v.Type
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64AddTupleFirst64 {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		tuple := v_0.Args[0]
-		val := v_0.Args[1]
-		v.reset(OpAMD64ADDQ)
-		v.AddArg(val)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
-		v0.AddArg(tuple)
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	return false
-}
-func rewriteValueAMD64_OpSelect1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Select1     (AddTupleFirst32 tuple _  ))
-	// cond:
-	// result: (Select1 tuple)
+	// match: (ORQ r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64AddTupleFirst32 {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
 			break
 		}
-		tuple := v_0.Args[0]
-		v.reset(OpSelect1)
-		v.AddArg(tuple)
-		return true
-	}
-	// match: (Select1     (AddTupleFirst64 tuple _  ))
-	// cond:
-	// result: (Select1 tuple)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpAMD64AddTupleFirst64 {
+		if r1.AuxInt != 8 {
 			break
 		}
-		tuple := v_0.Args[0]
-		v.reset(OpSelect1)
-		v.AddArg(tuple)
-		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_OpSlicemask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Slicemask <t> x)
-	// cond:
-	// result: (XORQconst [-1] (SARQconst <t> (SUBQconst <t> x [1]) [63]))
-	for {
-		t := v.Type
-		x := v.Args[0]
-		v.reset(OpAMD64XORQconst)
-		v.AuxInt = -1
-		v0 := b.NewValue0(v.Line, OpAMD64SARQconst, t)
-		v0.AuxInt = 63
-		v1 := b.NewValue0(v.Line, OpAMD64SUBQconst, t)
-		v1.AuxInt = 1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		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)
+	// match: (ORQ sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
 	for {
-		if v.AuxInt != 8 {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			break
 		}
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if sh.AuxInt != 16 {
 			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 {
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
 			break
 		}
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if r0.AuxInt != 8 {
 			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 {
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
 			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 {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
 			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)
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
-	// result: (MOVWstore ptr val mem)
+	// match: (ORQ r1:(BSWAPL x1:(MOVLload [i1] {s} p mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem))
 	for {
-		if v.AuxInt != 2 {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64BSWAPL {
 			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)
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (Store [1] ptr val mem)
-	// cond:
-	// result: (MOVBstore ptr val mem)
+	// match: (ORQ sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem))) r1:(BSWAPL x1:(MOVLload [i1] {s} p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem))
 	for {
-		if v.AuxInt != 1 {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
 			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)
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub8   x y)
-	// cond:
-	// result: (SUBL  x y)
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpAMD64SUBL)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-}
-func rewriteValueAMD64_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SubPtr x y)
-	// cond: config.PtrSize == 8
-	// result: (SUBQ x y)
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)) or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64SUBQ)
-		v.AddArg(x)
-		v.AddArg(y)
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (SubPtr x y)
-	// cond: config.PtrSize == 4
-	// result: (SUBL x y)
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem)) y) s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		v.reset(OpAMD64SUBL)
-		v.AddArg(x)
-		v.AddArg(y)
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueAMD64_OpTrunc16to8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_100(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Trunc16to8  x)
-	// cond:
-	// result: x
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))) s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
 	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_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 [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
-	// result: mem
-	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = mem.Type
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
-	// result: (MOVBstoreconst [0] destptr mem)
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64MOVBstoreconst)
-		v.AuxInt = 0
-		v.AddArg(destptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
-	// result: (MOVWstoreconst [0] destptr mem)
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBload {
 			break
 		}
-		v.reset(OpAMD64MOVWstoreconst)
-		v.AuxInt = 0
-		v.AddArg(destptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
-	// result: (MOVLstoreconst [0] destptr mem)
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpAMD64MOVLstoreconst)
-		v.AuxInt = 0
-		v.AddArg(destptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8
-	// result: (MOVQstoreconst [0] destptr mem)
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBload {
 			break
 		}
-		v.reset(OpAMD64MOVQstoreconst)
-		v.AuxInt = 0
-		v.AddArg(destptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
-	// result: (MOVBstoreconst [makeValAndOff(0,2)] destptr 		(MOVWstoreconst [0] destptr mem))
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		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 [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 5
-	// result: (MOVBstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 5) {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		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 [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 6
-	// result: (MOVWstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6) {
+		if mem != x0.Args[1] {
 			break
 		}
-		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 [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 7
-	// result: (MOVLstoreconst [makeValAndOff(0,3)] destptr 		(MOVLstoreconst [0] destptr mem))
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 7) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		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)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8
-	// result: (Zero [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8] (OffPtr <destptr.Type> destptr [SizeAndAlign(s).Size()%8]) 		(MOVQstoreconst [0] destptr mem))
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8) {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
 			break
 		}
-		v.reset(OpZero)
-		v.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%8
-		v0 := b.NewValue0(v.Line, OpOffPtr, destptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() % 8
-		v0.AddArg(destptr)
-		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 [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 16
-	// result: (MOVQstoreconst [makeValAndOff(0,8)] destptr 		(MOVQstoreconst [0] destptr mem))
-	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16) {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
 			break
 		}
-		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)
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 24
-	// result: (MOVQstoreconst [makeValAndOff(0,16)] destptr 		(MOVQstoreconst [makeValAndOff(0,8)] destptr 			(MOVQstoreconst [0] destptr mem)))
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))) or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 24) {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
 			break
 		}
-		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)
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 32
-	// result: (MOVQstoreconst [makeValAndOff(0,24)] destptr 		(MOVQstoreconst [makeValAndOff(0,16)] destptr 			(MOVQstoreconst [makeValAndOff(0,8)] destptr 				(MOVQstoreconst [0] destptr mem))))
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))) y) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 32) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		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)
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v.AddArg(v0)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size()%16 != 0 	&& !config.noDuffDevice
-	// result: (Zero [SizeAndAlign(s).Size()-8] (OffPtr <destptr.Type> [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size()%16 != 0 && !config.noDuffDevice) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
 			break
 		}
-		v.reset(OpZero)
-		v.AuxInt = SizeAndAlign(s).Size() - 8
-		v0 := b.NewValue0(v.Line, OpOffPtr, destptr.Type)
-		v0.AuxInt = 8
-		v0.AddArg(destptr)
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
 		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 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice
-	// result: (DUFFZERO [SizeAndAlign(s).Size()] destptr (MOVOconst [0]) mem)
+	// match: (ORQ x1:(MOVBloadidx1 [i1] {s} p idx mem) sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice) {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64DUFFZERO)
-		v.AuxInt = SizeAndAlign(s).Size()
-		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVOconst, TypeInt128)
-		v0.AuxInt = 0
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(mem)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: (SizeAndAlign(s).Size() > 1024 || (config.noDuffDevice && SizeAndAlign(s).Size() > 32)) 	&& SizeAndAlign(s).Size()%8 == 0
-	// result: (REPSTOSQ destptr (MOVQconst [SizeAndAlign(s).Size()/8]) (MOVQconst [0]) mem)
+	// match: (ORQ x1:(MOVBloadidx1 [i1] {s} idx p mem) sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !((SizeAndAlign(s).Size() > 1024 || (config.noDuffDevice && SizeAndAlign(s).Size() > 32)) && SizeAndAlign(s).Size()%8 == 0) {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
 			break
 		}
-		v.reset(OpAMD64REPSTOSQ)
-		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
-		v0.AuxInt = SizeAndAlign(s).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)
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt16to64 x)
-	// cond:
-	// result: (MOVWQZX x)
+	// match: (ORQ x1:(MOVBloadidx1 [i1] {s} p idx mem) sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64MOVWQZX)
-		v.AddArg(x)
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt32to64 x)
-	// cond:
-	// result: (MOVLQZX x)
+	// match: (ORQ x1:(MOVBloadidx1 [i1] {s} idx p mem) sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64MOVLQZX)
-		v.AddArg(x)
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to16  x)
-	// cond:
-	// result: (MOVBQZX x)
+	// match: (ORQ sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)) x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64MOVBQZX)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
+	return false
 }
-func rewriteValueAMD64_OpZeroExt8to32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ_110(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (ZeroExt8to32  x)
-	// cond:
-	// result: (MOVBQZX x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)) x1:(MOVBloadidx1 [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64MOVBQZX)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteValueAMD64_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to64  x)
-	// cond:
-	// result: (MOVBQZX x)
+	// match: (ORQ sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)) x1:(MOVBloadidx1 [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
 	for {
-		x := v.Args[0]
-		v.reset(OpAMD64MOVBQZX)
-		v.AddArg(x)
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-}
-func rewriteBlockAMD64(b *Block, config *Config) 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
+	// match: (ORQ sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} idx p mem)) x1:(MOVBloadidx1 [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ROLWconst, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)) sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ_120(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPL, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} idx p mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} idx p mem)) sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r1 := v.Args[0]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))) r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} idx p mem))) r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))) r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} idx p mem))) r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpAMD64SHLQconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r0 := sh.Args[0]
+		if r0.Op != OpAMD64BSWAPL {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		r1 := v.Args[1]
+		if r1.Op != OpAMD64BSWAPL {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSWAPQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ_130(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)) or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)) or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ_140(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem)) y) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem)) y) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} idx p mem))) s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64ROLWconst, typ.UInt16)
+		v2.AuxInt = 8
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ_150(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))) or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))) or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))) y) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem))) y) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))) y) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem))) y) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ_160(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORQ or:(ORQ y s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} idx p mem)))) s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpAMD64ORQ {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r1.AuxInt != 8 {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpAMD64ROLWconst {
+			break
+		}
+		if r0.AuxInt != 8 {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SHLQconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpAMD64BSWAPL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORQ x l:(MOVQload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ORQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ORQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ORQ l:(MOVQload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (ORQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64ORQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQconst_0(v *Value) bool {
+	// 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_OpAMD64ROLB_0(v *Value) bool {
+	// match: (ROLB x (NEGQ y))
+	// cond:
+	// result: (RORB x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLB x (NEGL y))
+	// cond:
+	// result: (RORB x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLB x (MOVQconst [c]))
+	// cond:
+	// result: (ROLBconst [c&7 ] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c & 7
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLB x (MOVLconst [c]))
+	// cond:
+	// result: (ROLBconst [c&7 ] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c & 7
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLBconst_0(v *Value) bool {
+	// match: (ROLBconst [c] (ROLBconst [d] x))
+	// cond:
+	// result: (ROLBconst [(c+d)& 7] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ROLBconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = (c + d) & 7
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLBconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLL_0(v *Value) bool {
+	// match: (ROLL x (NEGQ y))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLL x (NEGL y))
+	// cond:
+	// result: (RORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLL x (MOVQconst [c]))
+	// cond:
+	// result: (ROLLconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLL x (MOVLconst [c]))
+	// cond:
+	// result: (ROLLconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLLconst_0(v *Value) bool {
+	// match: (ROLLconst [c] (ROLLconst [d] x))
+	// cond:
+	// result: (ROLLconst [(c+d)&31] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ROLLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = (c + d) & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLLconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLQ_0(v *Value) bool {
+	// match: (ROLQ x (NEGQ y))
+	// cond:
+	// result: (RORQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLQ x (NEGL y))
+	// cond:
+	// result: (RORQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLQ x (MOVQconst [c]))
+	// cond:
+	// result: (ROLQconst [c&63] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLQ x (MOVLconst [c]))
+	// cond:
+	// result: (ROLQconst [c&63] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLQconst_0(v *Value) bool {
+	// match: (ROLQconst [c] (ROLQconst [d] x))
+	// cond:
+	// result: (ROLQconst [(c+d)&63] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ROLQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = (c + d) & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLQconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLW_0(v *Value) bool {
+	// match: (ROLW x (NEGQ y))
+	// cond:
+	// result: (RORW x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLW x (NEGL y))
+	// cond:
+	// result: (RORW x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64RORW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ROLW x (MOVQconst [c]))
+	// cond:
+	// result: (ROLWconst [c&15] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c & 15
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLW x (MOVLconst [c]))
+	// cond:
+	// result: (ROLWconst [c&15] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c & 15
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ROLWconst_0(v *Value) bool {
+	// match: (ROLWconst [c] (ROLWconst [d] x))
+	// cond:
+	// result: (ROLWconst [(c+d)&15] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ROLWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = (c + d) & 15
+		v.AddArg(x)
+		return true
+	}
+	// match: (ROLWconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64RORB_0(v *Value) bool {
+	// match: (RORB x (NEGQ y))
+	// cond:
+	// result: (ROLB x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORB x (NEGL y))
+	// cond:
+	// result: (ROLB x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORB x (MOVQconst [c]))
+	// cond:
+	// result: (ROLBconst [(-c)&7 ] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = (-c) & 7
+		v.AddArg(x)
+		return true
+	}
+	// match: (RORB x (MOVLconst [c]))
+	// cond:
+	// result: (ROLBconst [(-c)&7 ] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = (-c) & 7
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64RORL_0(v *Value) bool {
+	// match: (RORL x (NEGQ y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORL x (NEGL y))
+	// cond:
+	// result: (ROLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORL x (MOVQconst [c]))
+	// cond:
+	// result: (ROLLconst [(-c)&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = (-c) & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (RORL x (MOVLconst [c]))
+	// cond:
+	// result: (ROLLconst [(-c)&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = (-c) & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64RORQ_0(v *Value) bool {
+	// match: (RORQ x (NEGQ y))
+	// cond:
+	// result: (ROLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORQ x (NEGL y))
+	// cond:
+	// result: (ROLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORQ x (MOVQconst [c]))
+	// cond:
+	// result: (ROLQconst [(-c)&63] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = (-c) & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (RORQ x (MOVLconst [c]))
+	// cond:
+	// result: (ROLQconst [(-c)&63] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = (-c) & 63
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64RORW_0(v *Value) bool {
+	// match: (RORW x (NEGQ y))
+	// cond:
+	// result: (ROLW x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORW x (NEGL y))
+	// cond:
+	// result: (ROLW x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64ROLW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (RORW x (MOVQconst [c]))
+	// cond:
+	// result: (ROLWconst [(-c)&15] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = (-c) & 15
+		v.AddArg(x)
+		return true
+	}
+	// match: (RORW x (MOVLconst [c]))
+	// cond:
+	// result: (ROLWconst [(-c)&15] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = (-c) & 15
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARB_0(v *Value) bool {
+	// match: (SARB x (MOVQconst [c]))
+	// cond:
+	// result: (SARBconst [min(c&31,7)] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARBconst)
+		v.AuxInt = min(c&31, 7)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARB x (MOVLconst [c]))
+	// cond:
+	// result: (SARBconst [min(c&31,7)] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARBconst)
+		v.AuxInt = min(c&31, 7)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
+	// match: (SARBconst x [0])
+	// 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: (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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SARL x (MOVQconst [c]))
+	// cond:
+	// result: (SARLconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SARL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARL x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SARL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARL x (ANDQconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SARL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARL x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SARL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARL x (ADDLconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SARL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARL x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SARL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARL x (ANDLconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SARL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARL x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SARL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
+	// match: (SARLconst x [0])
+	// 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: (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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SARQ x (MOVQconst [c]))
+	// cond:
+	// result: (SARQconst [c&63] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SARQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARQ x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SARQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARQ x (ANDQconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SARQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARQ x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SARQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARQ x (ADDLconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SARQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARQ x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SARQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SARQ x (ANDLconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SARQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SARQ x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SARQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARQconst_0(v *Value) bool {
+	// match: (SARQconst x [0])
+	// 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: (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_0(v *Value) bool {
+	// match: (SARW x (MOVQconst [c]))
+	// cond:
+	// result: (SARWconst [min(c&31,15)] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARWconst)
+		v.AuxInt = min(c&31, 15)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARW x (MOVLconst [c]))
+	// cond:
+	// result: (SARWconst [min(c&31,15)] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARWconst)
+		v.AuxInt = min(c&31, 15)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
+	// match: (SARWconst x [0])
+	// 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: (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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (SETEQ (TESTL (SHLL (MOVLconst [1]) x) y))
+	// cond: !config.nacl
+	// result: (SETAE (BTL x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTL {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_0.Args[1]
+		y := v_0.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTL y (SHLL (MOVLconst [1]) x)))
+	// cond: !config.nacl
+	// result: (SETAE (BTL x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0_1.Args[1]
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_1.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTQ (SHLQ (MOVQconst [1]) x) y))
+	// cond: !config.nacl
+	// result: (SETAE (BTQ x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_0.Args[1]
+		y := v_0.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTQ y (SHLQ (MOVQconst [1]) x)))
+	// cond: !config.nacl
+	// result: (SETAE (BTQ x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_1.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTLconst [c] x))
+	// cond: isPowerOfTwo(c) && log2(c) < 32 && !config.nacl
+	// result: (SETAE (BTLconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(isPowerOfTwo(c) && log2(c) < 32 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTLconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTQconst [c] x))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETAE (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTQ (MOVQconst [c]) x))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETAE (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETEQ (TESTQ x (MOVQconst [c])))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETAE (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETEQ_10(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (SETNE (TESTL (SHLL (MOVLconst [1]) x) y))
+	// cond: !config.nacl
+	// result: (SETB  (BTL x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTL {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_0.Args[1]
+		y := v_0.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTL y (SHLL (MOVLconst [1]) x)))
+	// cond: !config.nacl
+	// result: (SETB  (BTL x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLL {
+			break
+		}
+		_ = v_0_1.Args[1]
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_1.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTQ (SHLQ (MOVQconst [1]) x) y))
+	// cond: !config.nacl
+	// result: (SETB  (BTQ x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		if v_0_0_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_0.Args[1]
+		y := v_0.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTQ y (SHLQ (MOVQconst [1]) x)))
+	// cond: !config.nacl
+	// result: (SETB  (BTQ x y))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64SHLQ {
+			break
+		}
+		_ = v_0_1.Args[1]
+		v_0_1_0 := v_0_1.Args[0]
+		if v_0_1_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		if v_0_1_0.AuxInt != 1 {
+			break
+		}
+		x := v_0_1.Args[1]
+		if !(!config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTLconst [c] x))
+	// cond: isPowerOfTwo(c) && log2(c) < 32 && !config.nacl
+	// result: (SETB  (BTLconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(isPowerOfTwo(c) && log2(c) < 32 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTLconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTQconst [c] x))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETB  (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTQ (MOVQconst [c]) x))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETB  (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SETNE (TESTQ x (MOVQconst [c])))
+	// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+	// result: (SETB  (BTQconst [log2(c)] x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64TESTQ {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+			break
+		}
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+		v0.AuxInt = log2(c)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETNE_10(v *Value) bool {
+	// 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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SHLL x (MOVQconst [c]))
+	// cond:
+	// result: (SHLLconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SHLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLL x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SHLL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLL x (ANDQconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SHLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLL x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SHLL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLL x (ADDLconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SHLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLL x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SHLL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLL x (ANDLconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SHLL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLL x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SHLL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHLLconst_0(v *Value) bool {
+	// match: (SHLLconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHLQ_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SHLQ x (MOVQconst [c]))
+	// cond:
+	// result: (SHLQconst [c&63] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SHLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLQ x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SHLQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLQ x (ANDQconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SHLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLQ x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SHLQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLQ x (ADDLconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SHLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLQ x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SHLQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHLQ x (ANDLconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SHLQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHLQ x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SHLQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHLQconst_0(v *Value) bool {
+	// match: (SHLQconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRB_0(v *Value) bool {
+	// match: (SHRB x (MOVQconst [c]))
+	// cond: c&31 < 8
+	// result: (SHRBconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 < 8) {
+			break
+		}
+		v.reset(OpAMD64SHRBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRB x (MOVLconst [c]))
+	// cond: c&31 < 8
+	// result: (SHRBconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 < 8) {
+			break
+		}
+		v.reset(OpAMD64SHRBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRB _ (MOVQconst [c]))
+	// cond: c&31 >= 8
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 >= 8) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SHRB _ (MOVLconst [c]))
+	// cond: c&31 >= 8
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 >= 8) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRBconst_0(v *Value) bool {
+	// match: (SHRBconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRL_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRL x (MOVQconst [c]))
+	// cond:
+	// result: (SHRLconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SHRL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRL x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SHRL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRL x (ANDQconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SHRL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRL x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SHRL x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRL x (ADDLconst [c] y))
+	// cond: c & 31 == 0
+	// result: (SHRL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRL x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 31 == 0
+	// result: (SHRL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRL x (ANDLconst [c] y))
+	// cond: c & 31 == 31
+	// result: (SHRL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRL x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 31 == 31
+	// result: (SHRL x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&31 == 31) {
+			break
+		}
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRLconst_0(v *Value) bool {
+	// match: (SHRLconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRQ_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRQ x (MOVQconst [c]))
+	// cond:
+	// result: (SHRQconst [c&63] x)
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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 (ADDQconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SHRQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRQ x (NEGQ <t> (ADDQconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SHRQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRQ x (ANDQconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SHRQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRQ x (NEGQ <t> (ANDQconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SHRQ x (NEGQ <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRQ x (ADDLconst [c] y))
+	// cond: c & 63 == 0
+	// result: (SHRQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRQ x (NEGL <t> (ADDLconst [c] y)))
+	// cond: c & 63 == 0
+	// result: (SHRQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 0) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SHRQ x (ANDLconst [c] y))
+	// cond: c & 63 == 63
+	// result: (SHRQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SHRQ x (NEGL <t> (ANDLconst [c] y)))
+	// cond: c & 63 == 63
+	// result: (SHRQ x (NEGL <t> y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		t := v_1.Type
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_1_0.AuxInt
+		y := v_1_0.Args[0]
+		if !(c&63 == 63) {
+			break
+		}
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGL, t)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRQconst_0(v *Value) bool {
+	// match: (SHRQconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRW_0(v *Value) bool {
+	// match: (SHRW x (MOVQconst [c]))
+	// cond: c&31 < 16
+	// result: (SHRWconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 < 16) {
+			break
+		}
+		v.reset(OpAMD64SHRWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRW x (MOVLconst [c]))
+	// cond: c&31 < 16
+	// result: (SHRWconst [c&31] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 < 16) {
+			break
+		}
+		v.reset(OpAMD64SHRWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRW _ (MOVQconst [c]))
+	// cond: c&31 >= 16
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 >= 16) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SHRW _ (MOVLconst [c]))
+	// cond: c&31 >= 16
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c&31 >= 16) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRWconst_0(v *Value) bool {
+	// match: (SHRWconst x [0])
+	// 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
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBL_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBL x (MOVLconst [c]))
+	// cond:
+	// result: (SUBLconst x [c])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SUBLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBL (MOVLconst [c]) x)
+	// cond:
+	// result: (NEGL (SUBLconst <v.Type> x [c]))
+	for {
+		_ = v.Args[1]
+		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.Pos, OpAMD64SUBLconst, v.Type)
+		v0.AuxInt = c
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SUBL x x)
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SUBL x l:(MOVLload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (SUBLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64SUBLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBLconst_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (SUBQconst x [c])
+	for {
+		_ = v.Args[1]
+		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.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (NEGQ (SUBQconst <v.Type> x [c]))
+	for {
+		_ = v.Args[1]
+		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.Pos, OpAMD64SUBQconst, v.Type)
+		v0.AuxInt = c
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SUBQ x x)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SUBQ x l:(MOVQload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (SUBQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64SUBQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBQconst_0(v *Value) bool {
+	// 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 {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.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 {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SUBQconst {
+			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_OpAMD64SUBSD_0(v *Value) bool {
+	// match: (SUBSD x l:(MOVSDload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (SUBSDmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSDload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64SUBSDmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBSS_0(v *Value) bool {
+	// match: (SUBSS x l:(MOVSSload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (SUBSSmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVSSload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64SUBSSmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64TESTB_0(v *Value) bool {
+	// match: (TESTB (MOVLconst [c]) x)
+	// cond:
+	// result: (TESTBconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64TESTBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (TESTB x (MOVLconst [c]))
+	// cond:
+	// result: (TESTBconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64TESTBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64TESTL_0(v *Value) bool {
+	// match: (TESTL (MOVLconst [c]) x)
+	// cond:
+	// result: (TESTLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64TESTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (TESTL x (MOVLconst [c]))
+	// cond:
+	// result: (TESTLconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64TESTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64TESTQ_0(v *Value) bool {
+	// match: (TESTQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (TESTQconst [c] x)
+	for {
+		_ = v.Args[1]
+		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(OpAMD64TESTQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (TESTQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (TESTQconst [c] x)
+	for {
+		_ = v.Args[1]
+		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(OpAMD64TESTQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64TESTW_0(v *Value) bool {
+	// match: (TESTW (MOVLconst [c]) x)
+	// cond:
+	// result: (TESTWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64TESTWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (TESTW x (MOVLconst [c]))
+	// cond:
+	// result: (TESTWconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64TESTWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XADDLlock_0(v *Value) bool {
+	// match: (XADDLlock [off1] {sym} val (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (XADDLlock [off1+off2] {sym} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64XADDLlock)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XADDQlock_0(v *Value) bool {
+	// match: (XADDQlock [off1] {sym} val (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (XADDQlock [off1+off2] {sym} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64XADDQlock)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XCHGL_0(v *Value) bool {
+	// match: (XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (XCHGL [off1+off2] {sym} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64XCHGL)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (XCHGL [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB
+	// result: (XCHGL [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64XCHGL)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XCHGQ_0(v *Value) bool {
+	// match: (XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (XCHGQ [off1+off2] {sym} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64XCHGQ)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (XCHGQ [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB
+	// result: (XCHGQ [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		val := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64XCHGQ)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORL_0(v *Value) bool {
+	// match: (XORL x (MOVLconst [c]))
+	// cond:
+	// result: (XORLconst [c] x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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 (SHLLconst x [c]) (SHRLconst x [d]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRLconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL (SHRLconst x [d]) (SHLLconst x [c]))
+	// cond: d==32-c
+	// result: (ROLLconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpAMD64ROLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHLLconst x [c]) (SHRWconst x [d]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHRWconst x [d]) (SHLLconst x [c]))
+	// cond: d==16-c && c < 16 && t.Size() == 2
+	// result: (ROLWconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 16-c && c < 16 && t.Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64ROLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHLLconst x [c]) (SHRBconst x [d]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRBconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL <t> (SHRBconst x [d]) (SHLLconst x [c]))
+	// cond: d==8-c  && c < 8 && t.Size() == 1
+	// result: (ROLBconst x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRBconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 8-c && c < 8 && t.Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64ROLBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL x x)
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (XORL x l:(MOVLload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (XORLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64XORLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORL_10(v *Value) bool {
+	// match: (XORL l:(MOVLload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (XORLmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVLload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64XORLmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORLconst_0(v *Value) bool {
+	// match: (XORLconst [1] (SETNE x))
+	// cond:
+	// result: (SETEQ x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETNE {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETEQ)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETEQ x))
+	// cond:
+	// result: (SETNE x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETEQ {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETNE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETL x))
+	// cond:
+	// result: (SETGE x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETL {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETGE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETGE x))
+	// cond:
+	// result: (SETL  x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETGE {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETL)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETLE x))
+	// cond:
+	// result: (SETG  x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETLE {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETG)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETG x))
+	// cond:
+	// result: (SETLE x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETG {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETLE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETB x))
+	// cond:
+	// result: (SETAE x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETB {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETAE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETAE x))
+	// cond:
+	// result: (SETB  x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETAE {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETB)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETBE x))
+	// cond:
+	// result: (SETA  x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETBE {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETA)
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [1] (SETA x))
+	// cond:
+	// result: (SETBE x)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SETA {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETBE)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORLconst_10(v *Value) bool {
+	// match: (XORLconst [c] (XORLconst [d] x))
+	// cond:
+	// result: (XORLconst [c ^ d] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64XORLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64XORLconst)
+		v.AuxInt = c ^ d
+		v.AddArg(x)
+		return true
+	}
+	// 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_0(v *Value) bool {
+	// match: (XORQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (XORQconst [c] x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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 (SHLQconst x [c]) (SHRQconst x [d]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORQ (SHRQconst x [d]) (SHLQconst x [c]))
+	// cond: d==64-c
+	// result: (ROLQconst x [c])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpAMD64ROLQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORQ x x)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (XORQ x l:(MOVQload [off] {sym} ptr mem))
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (XORQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		l := v.Args[1]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64XORQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (XORQ l:(MOVQload [off] {sym} ptr mem) x)
+	// cond: canMergeLoad(v, l, x) && clobber(l)
+	// result: (XORQmem x [off] {sym} ptr mem)
+	for {
+		_ = v.Args[1]
+		l := v.Args[0]
+		if l.Op != OpAMD64MOVQload {
+			break
+		}
+		off := l.AuxInt
+		sym := l.Aux
+		_ = l.Args[1]
+		ptr := l.Args[0]
+		mem := l.Args[1]
+		x := v.Args[1]
+		if !(canMergeLoad(v, l, x) && clobber(l)) {
+			break
+		}
+		v.reset(OpAMD64XORQmem)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORQconst_0(v *Value) bool {
+	// match: (XORQconst [c] (XORQconst [d] x))
+	// cond:
+	// result: (XORQconst [c ^ d] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64XORQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64XORQconst)
+		v.AuxInt = c ^ d
+		v.AddArg(x)
+		return true
+	}
+	// 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_OpAdd16_0(v *Value) bool {
+	// match: (Add16 x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd32_0(v *Value) bool {
+	// match: (Add32 x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd32F_0(v *Value) bool {
+	// match: (Add32F x y)
+	// cond:
+	// result: (ADDSS x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd64_0(v *Value) bool {
+	// match: (Add64 x y)
+	// cond:
+	// result: (ADDQ  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd64F_0(v *Value) bool {
+	// match: (Add64F x y)
+	// cond:
+	// result: (ADDSD x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd8_0(v *Value) bool {
+	// match: (Add8 x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAddPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (AddPtr x y)
+	// cond: config.PtrSize == 8
+	// result: (ADDQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64ADDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (AddPtr x y)
+	// cond: config.PtrSize == 4
+	// result: (ADDL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAddr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (Addr {sym} base)
+	// cond: config.PtrSize == 8
+	// result: (LEAQ {sym} base)
+	for {
+		sym := v.Aux
+		base := v.Args[0]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64LEAQ)
+		v.Aux = sym
+		v.AddArg(base)
+		return true
+	}
+	// match: (Addr {sym} base)
+	// cond: config.PtrSize == 4
+	// result: (LEAL {sym} base)
+	for {
+		sym := v.Aux
+		base := v.Args[0]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64LEAL)
+		v.Aux = sym
+		v.AddArg(base)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAnd16_0(v *Value) bool {
+	// match: (And16 x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd32_0(v *Value) bool {
+	// match: (And32 x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd64_0(v *Value) bool {
+	// match: (And64 x y)
+	// cond:
+	// result: (ANDQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd8_0(v *Value) bool {
+	// match: (And8 x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAndB_0(v *Value) bool {
+	// match: (AndB x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicAdd32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicAdd32 ptr val mem)
+	// cond:
+	// result: (AddTupleFirst32 val (XADDLlock val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64AddTupleFirst32)
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpAMD64XADDLlock, types.NewTuple(typ.UInt32, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicAdd64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicAdd64 ptr val mem)
+	// cond:
+	// result: (AddTupleFirst64 val (XADDQlock val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64AddTupleFirst64)
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpAMD64XADDQlock, types.NewTuple(typ.UInt64, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicAnd8_0(v *Value) bool {
+	// match: (AtomicAnd8 ptr val mem)
+	// cond:
+	// result: (ANDBlock ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64ANDBlock)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicCompareAndSwap32_0(v *Value) bool {
+	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
+	// cond:
+	// result: (CMPXCHGLlock ptr old new_ mem)
+	for {
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		old := v.Args[1]
+		new_ := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64CMPXCHGLlock)
+		v.AddArg(ptr)
+		v.AddArg(old)
+		v.AddArg(new_)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicCompareAndSwap64_0(v *Value) bool {
+	// match: (AtomicCompareAndSwap64 ptr old new_ mem)
+	// cond:
+	// result: (CMPXCHGQlock ptr old new_ mem)
+	for {
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		old := v.Args[1]
+		new_ := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64CMPXCHGQlock)
+		v.AddArg(ptr)
+		v.AddArg(old)
+		v.AddArg(new_)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicExchange32_0(v *Value) bool {
+	// match: (AtomicExchange32 ptr val mem)
+	// cond:
+	// result: (XCHGL val ptr mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64XCHGL)
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicExchange64_0(v *Value) bool {
+	// match: (AtomicExchange64 ptr val mem)
+	// cond:
+	// result: (XCHGQ val ptr mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64XCHGQ)
+		v.AddArg(val)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicLoad32_0(v *Value) bool {
+	// match: (AtomicLoad32 ptr mem)
+	// cond:
+	// result: (MOVLatomicload ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVLatomicload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicLoad64_0(v *Value) bool {
+	// match: (AtomicLoad64 ptr mem)
+	// cond:
+	// result: (MOVQatomicload ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQatomicload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicLoadPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (AtomicLoadPtr ptr mem)
+	// cond: config.PtrSize == 8
+	// result: (MOVQatomicload ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64MOVQatomicload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (AtomicLoadPtr ptr mem)
+	// cond: config.PtrSize == 4
+	// result: (MOVLatomicload ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64MOVLatomicload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAtomicOr8_0(v *Value) bool {
+	// match: (AtomicOr8 ptr val mem)
+	// cond:
+	// result: (ORBlock ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64ORBlock)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicStore32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicStore32 ptr val mem)
+	// cond:
+	// result: (Select1 (XCHGL <types.NewTuple(typ.UInt32,types.TypeMem)> val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64XCHGL, types.NewTuple(typ.UInt32, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicStore64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicStore64 ptr val mem)
+	// cond:
+	// result: (Select1 (XCHGQ <types.NewTuple(typ.UInt64,types.TypeMem)> val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64XCHGQ, types.NewTuple(typ.UInt64, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAtomicStorePtrNoWB_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicStorePtrNoWB ptr val mem)
+	// cond: config.PtrSize == 8
+	// result: (Select1 (XCHGQ <types.NewTuple(typ.BytePtr,types.TypeMem)> val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64XCHGQ, types.NewTuple(typ.BytePtr, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (AtomicStorePtrNoWB ptr val mem)
+	// cond: config.PtrSize == 4
+	// result: (Select1 (XCHGL <types.NewTuple(typ.BytePtr,types.TypeMem)> val ptr mem))
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64XCHGL, types.NewTuple(typ.BytePtr, types.TypeMem))
+		v0.AddArg(val)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAvg64u_0(v *Value) bool {
+	// match: (Avg64u x y)
+	// cond:
+	// result: (AVGQU x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64AVGQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBitLen32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen32 x)
+	// cond:
+	// result: (BitLen64 (MOVLQZX <typ.UInt64> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpBitLen64)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLQZX, typ.UInt64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBitLen64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen64 <t> x)
+	// cond:
+	// result: (ADDQconst [1] (CMOVQEQ <t> (Select0 <t> (BSRQ x)) (MOVQconst <t> [-1]) (Select1 <types.TypeFlags> (BSRQ x))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpAMD64CMOVQEQ, t)
+		v1 := b.NewValue0(v.Pos, OpSelect0, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64BSRQ, types.NewTuple(typ.UInt64, types.TypeFlags))
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVQconst, t)
+		v3.AuxInt = -1
+		v0.AddArg(v3)
+		v4 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+		v5 := b.NewValue0(v.Pos, OpAMD64BSRQ, types.NewTuple(typ.UInt64, types.TypeFlags))
+		v5.AddArg(x)
+		v4.AddArg(v5)
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBswap32_0(v *Value) bool {
+	// match: (Bswap32 x)
+	// cond:
+	// result: (BSWAPL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64BSWAPL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBswap64_0(v *Value) bool {
+	// match: (Bswap64 x)
+	// cond:
+	// result: (BSWAPQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64BSWAPQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpClosureCall_0(v *Value) bool {
+	// match: (ClosureCall [argwid] entry closure mem)
+	// cond:
+	// result: (CALLclosure [argwid] entry closure mem)
+	for {
+		argwid := v.AuxInt
+		_ = v.Args[2]
+		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_0(v *Value) bool {
+	// match: (Com16 x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom32_0(v *Value) bool {
+	// match: (Com32 x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom64_0(v *Value) bool {
+	// match: (Com64 x)
+	// cond:
+	// result: (NOTQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom8_0(v *Value) bool {
+	// match: (Com8 x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst16_0(v *Value) bool {
+	// match: (Const16 [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst32_0(v *Value) bool {
+	// match: (Const32 [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst32F_0(v *Value) bool {
+	// match: (Const32F [val])
+	// cond:
+	// result: (MOVSSconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVSSconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst64_0(v *Value) bool {
+	// match: (Const64 [val])
+	// cond:
+	// result: (MOVQconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst64F_0(v *Value) bool {
+	// match: (Const64F [val])
+	// cond:
+	// result: (MOVSDconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVSDconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst8_0(v *Value) bool {
+	// match: (Const8 [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConstBool_0(v *Value) bool {
+	// match: (ConstBool [b])
+	// cond:
+	// result: (MOVLconst [b])
+	for {
+		b := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = b
+		return true
+	}
+}
+func rewriteValueAMD64_OpConstNil_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (ConstNil)
+	// cond: config.PtrSize == 8
+	// result: (MOVQconst [0])
+	for {
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (ConstNil)
+	// cond: config.PtrSize == 4
+	// result: (MOVLconst [0])
+	for {
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpConvert_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (Convert <t> x mem)
+	// cond: config.PtrSize == 8
+	// result: (MOVQconvert <t> x mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		mem := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64MOVQconvert)
+		v.Type = t
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Convert <t> x mem)
+	// cond: config.PtrSize == 4
+	// result: (MOVLconvert <t> x mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		mem := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64MOVLconvert)
+		v.Type = t
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpCtz32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Ctz32 x)
+	// cond:
+	// result: (Select0 (BSFQ (ORQ <typ.UInt64> (MOVQconst [1<<32]) x)))
+	for {
+		x := v.Args[0]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
+		v1 := b.NewValue0(v.Pos, OpAMD64ORQ, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v2.AuxInt = 1 << 32
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCtz64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Ctz64 <t> x)
+	// cond:
+	// result: (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <types.TypeFlags> (BSFQ x)))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64CMOVQEQ)
+		v0 := b.NewValue0(v.Pos, OpSelect0, t)
+		v1 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQconst, t)
+		v2.AuxInt = 64
+		v.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
+		v4.AddArg(x)
+		v3.AddArg(v4)
+		v.AddArg(v3)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto32_0(v *Value) bool {
+	// match: (Cvt32Fto32 x)
+	// cond:
+	// result: (CVTTSS2SL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSS2SL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto64_0(v *Value) bool {
+	// match: (Cvt32Fto64 x)
+	// cond:
+	// result: (CVTTSS2SQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSS2SQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto64F_0(v *Value) bool {
+	// match: (Cvt32Fto64F x)
+	// cond:
+	// result: (CVTSS2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSS2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32to32F_0(v *Value) bool {
+	// match: (Cvt32to32F x)
+	// cond:
+	// result: (CVTSL2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSL2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32to64F_0(v *Value) bool {
+	// match: (Cvt32to64F x)
+	// cond:
+	// result: (CVTSL2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSL2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto32_0(v *Value) bool {
+	// match: (Cvt64Fto32 x)
+	// cond:
+	// result: (CVTTSD2SL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSD2SL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto32F_0(v *Value) bool {
+	// match: (Cvt64Fto32F x)
+	// cond:
+	// result: (CVTSD2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSD2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto64_0(v *Value) bool {
+	// match: (Cvt64Fto64 x)
+	// cond:
+	// result: (CVTTSD2SQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSD2SQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64to32F_0(v *Value) bool {
+	// match: (Cvt64to32F x)
+	// cond:
+	// result: (CVTSQ2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSQ2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64to64F_0(v *Value) bool {
+	// match: (Cvt64to64F x)
+	// cond:
+	// result: (CVTSQ2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSQ2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv128u_0(v *Value) bool {
+	// match: (Div128u xhi xlo y)
+	// cond:
+	// result: (DIVQU2 xhi xlo y)
+	for {
+		_ = v.Args[2]
+		xhi := v.Args[0]
+		xlo := v.Args[1]
+		y := v.Args[2]
+		v.reset(OpAMD64DIVQU2)
+		v.AddArg(xhi)
+		v.AddArg(xlo)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16 x y)
+	// cond:
+	// result: (Select0 (DIVW  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVW, types.NewTuple(typ.Int16, typ.Int16))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv16u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16u x y)
+	// cond:
+	// result: (Select0 (DIVWU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVWU, types.NewTuple(typ.UInt16, typ.UInt16))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div32 x y)
+	// cond:
+	// result: (Select0 (DIVL  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVL, types.NewTuple(typ.Int32, typ.Int32))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32F_0(v *Value) bool {
+	// match: (Div32F x y)
+	// cond:
+	// result: (DIVSS x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div32u x y)
+	// cond:
+	// result: (Select0 (DIVLU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVLU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div64 x y)
+	// cond:
+	// result: (Select0 (DIVQ  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVQ, types.NewTuple(typ.Int64, typ.Int64))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64F_0(v *Value) bool {
+	// match: (Div64F x y)
+	// cond:
+	// result: (DIVSD x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div64u x y)
+	// cond:
+	// result: (Select0 (DIVQU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVQU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8 x y)
+	// cond:
+	// result: (Select0 (DIVW  (SignExt8to16 x) (SignExt8to16 y)))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVW, types.NewTuple(typ.Int16, typ.Int16))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
+		v2.AddArg(y)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv8u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8u x y)
+	// cond:
+	// result: (Select0 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect0)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVWU, types.NewTuple(typ.UInt16, typ.UInt16))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
+		v2.AddArg(y)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq16 x y)
+	// cond:
+	// result: (SETEQ (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32 x y)
+	// cond:
+	// result: (SETEQ (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32F x y)
+	// cond:
+	// result: (SETEQF (UCOMISS x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64 x y)
+	// cond:
+	// result: (SETEQ (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64F x y)
+	// cond:
+	// result: (SETEQF (UCOMISD x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq8 x y)
+	// cond:
+	// result: (SETEQ (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEqB_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (EqB x y)
+	// cond:
+	// result: (SETEQ (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEqPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (EqPtr x y)
+	// cond: config.PtrSize == 8
+	// result: (SETEQ (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (EqPtr x y)
+	// cond: config.PtrSize == 4
+	// result: (SETEQ (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpGeq16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16 x y)
+	// cond:
+	// result: (SETGE (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq16U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16U x y)
+	// cond:
+	// result: (SETAE (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32 x y)
+	// cond:
+	// result: (SETGE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32F x y)
+	// cond:
+	// result: (SETGEF (UCOMISS x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32U x y)
+	// cond:
+	// result: (SETAE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64 x y)
+	// cond:
+	// result: (SETGE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64F x y)
+	// cond:
+	// result: (SETGEF (UCOMISD x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64U x y)
+	// cond:
+	// result: (SETAE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8 x y)
+	// cond:
+	// result: (SETGE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq8U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8U x y)
+	// cond:
+	// result: (SETAE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGetClosurePtr_0(v *Value) bool {
+	// match: (GetClosurePtr)
+	// cond:
+	// result: (LoweredGetClosurePtr)
+	for {
+		v.reset(OpAMD64LoweredGetClosurePtr)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGetG_0(v *Value) bool {
+	// match: (GetG mem)
+	// cond:
+	// result: (LoweredGetG mem)
+	for {
+		mem := v.Args[0]
+		v.reset(OpAMD64LoweredGetG)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16 x y)
+	// cond:
+	// result: (SETG (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater16U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16U x y)
+	// cond:
+	// result: (SETA (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32 x y)
+	// cond:
+	// result: (SETG (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32F x y)
+	// cond:
+	// result: (SETGF (UCOMISS x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32U x y)
+	// cond:
+	// result: (SETA (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64 x y)
+	// cond:
+	// result: (SETG (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64F x y)
+	// cond:
+	// result: (SETGF (UCOMISD x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64U x y)
+	// cond:
+	// result: (SETA (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8 x y)
+	// cond:
+	// result: (SETG (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater8U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8U x y)
+	// cond:
+	// result: (SETA (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul32_0(v *Value) bool {
+	// match: (Hmul32 x y)
+	// cond:
+	// result: (HMULL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul32u_0(v *Value) bool {
+	// match: (Hmul32u x y)
+	// cond:
+	// result: (HMULLU x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULLU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul64_0(v *Value) bool {
+	// match: (Hmul64 x y)
+	// cond:
+	// result: (HMULQ  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul64u_0(v *Value) bool {
+	// match: (Hmul64u x y)
+	// cond:
+	// result: (HMULQU x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpInt64Hi_0(v *Value) bool {
+	// match: (Int64Hi x)
+	// cond:
+	// result: (SHRQconst [32] x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64SHRQconst)
+		v.AuxInt = 32
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpInterCall_0(v *Value) bool {
+	// match: (InterCall [argwid] entry mem)
+	// cond:
+	// result: (CALLinter [argwid] entry mem)
+	for {
+		argwid := v.AuxInt
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (IsInBounds idx len)
+	// cond:
+	// result: (SETB (CMPQ idx len))
+	for {
+		_ = v.Args[1]
+		idx := v.Args[0]
+		len := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(idx)
+		v0.AddArg(len)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpIsNonNil_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (IsNonNil p)
+	// cond: config.PtrSize == 8
+	// result: (SETNE (TESTQ p p))
+	for {
+		p := v.Args[0]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64TESTQ, types.TypeFlags)
+		v0.AddArg(p)
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (IsNonNil p)
+	// cond: config.PtrSize == 4
+	// result: (SETNE (TESTL p p))
+	for {
+		p := v.Args[0]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64TESTL, types.TypeFlags)
+		v0.AddArg(p)
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpIsSliceInBounds_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (IsSliceInBounds idx len)
+	// cond:
+	// result: (SETBE (CMPQ idx len))
+	for {
+		_ = v.Args[1]
+		idx := v.Args[0]
+		len := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(idx)
+		v0.AddArg(len)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16 x y)
+	// cond:
+	// result: (SETLE (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq16U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16U x y)
+	// cond:
+	// result: (SETBE (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32 x y)
+	// cond:
+	// result: (SETLE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32F x y)
+	// cond:
+	// result: (SETGEF (UCOMISS y x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32U x y)
+	// cond:
+	// result: (SETBE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64 x y)
+	// cond:
+	// result: (SETLE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64F x y)
+	// cond:
+	// result: (SETGEF (UCOMISD y x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64U x y)
+	// cond:
+	// result: (SETBE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8 x y)
+	// cond:
+	// result: (SETLE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq8U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8U x y)
+	// cond:
+	// result: (SETBE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16 x y)
+	// cond:
+	// result: (SETL (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess16U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16U x y)
+	// cond:
+	// result: (SETB (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32 x y)
+	// cond:
+	// result: (SETL (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32F x y)
+	// cond:
+	// result: (SETGF (UCOMISS y x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32U x y)
+	// cond:
+	// result: (SETB (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64 x y)
+	// cond:
+	// result: (SETL (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64F x y)
+	// cond:
+	// result: (SETGF (UCOMISD y x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64U x y)
+	// cond:
+	// result: (SETB (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8 x y)
+	// cond:
+	// result: (SETL (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess8U_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8U x y)
+	// cond:
+	// result: (SETB (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLoad_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (Load <t> ptr mem)
+	// cond: (is64BitInt(t) || isPtr(t) && config.PtrSize == 8)
+	// result: (MOVQload ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is64BitInt(t) || isPtr(t) && config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64MOVQload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: (is32BitInt(t) || isPtr(t) && config.PtrSize == 4)
+	// result: (MOVLload ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is32BitInt(t) || isPtr(t) && config.PtrSize == 4) {
+			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
+		_ = v.Args[1]
+		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
+		_ = v.Args[1]
+		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
+		_ = v.Args[1]
+		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
+		_ = v.Args[1]
+		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_OpLsh16x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod16 x y)
+	// cond:
+	// result: (Select1 (DIVW  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVW, types.NewTuple(typ.Int16, typ.Int16))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod16u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod16u x y)
+	// cond:
+	// result: (Select1 (DIVWU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVWU, types.NewTuple(typ.UInt16, typ.UInt16))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod32 x y)
+	// cond:
+	// result: (Select1 (DIVL  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVL, types.NewTuple(typ.Int32, typ.Int32))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod32u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod32u x y)
+	// cond:
+	// result: (Select1 (DIVLU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVLU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod64 x y)
+	// cond:
+	// result: (Select1 (DIVQ  x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVQ, types.NewTuple(typ.Int64, typ.Int64))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod64u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod64u x y)
+	// cond:
+	// result: (Select1 (DIVQU x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVQU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8 x y)
+	// cond:
+	// result: (Select1 (DIVW  (SignExt8to16 x) (SignExt8to16 y)))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVW, types.NewTuple(typ.Int16, typ.Int16))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpSignExt8to16, typ.Int16)
+		v2.AddArg(y)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod8u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8u x y)
+	// cond:
+	// result: (Select1 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpSelect1)
+		v0 := b.NewValue0(v.Pos, OpAMD64DIVWU, types.NewTuple(typ.UInt16, typ.UInt16))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to16, typ.UInt16)
+		v2.AddArg(y)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMove_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
+	// result: mem
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		_ = v.Args[2]
+		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
+		}
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, typ.UInt8)
+		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
+		}
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		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
+		}
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		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
+		}
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		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
+		}
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVOstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVOload, types.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
+		}
+		_ = v.Args[2]
+		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.Pos, OpAMD64MOVBload, typ.UInt8)
+		v0.AuxInt = 2
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVWstore, types.TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+		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
+		}
+		_ = v.Args[2]
+		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.Pos, OpAMD64MOVBload, typ.UInt8)
+		v0.AuxInt = 4
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLstore, types.TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		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
+		}
+		_ = v.Args[2]
+		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.Pos, OpAMD64MOVWload, typ.UInt16)
+		v0.AuxInt = 4
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLstore, types.TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		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
+		}
+		_ = v.Args[2]
+		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.Pos, OpAMD64MOVLload, typ.UInt32)
+		v0.AuxInt = 3
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVLstore, types.TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [s] dst src mem)
+	// cond: s > 8 && s < 16
+	// result: (MOVQstore [s-8] dst (MOVQload [s-8] src mem) 		(MOVQstore dst (MOVQload src mem) mem))
+	for {
+		s := v.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(s > 8 && s < 16) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = s - 8
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v0.AuxInt = s - 8
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQstore, types.TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [s] dst src mem)
+	// cond: s > 16 && s%16 != 0 && s%16 <= 8
+	// result: (Move [s-s%16] 		(OffPtr <dst.Type> dst [s%16]) 		(OffPtr <src.Type> src [s%16]) 		(MOVQstore dst (MOVQload src mem) mem))
+	for {
+		s := v.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(s > 16 && s%16 != 0 && s%16 <= 8) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = s - s%16
+		v0 := b.NewValue0(v.Pos, OpOffPtr, dst.Type)
+		v0.AuxInt = s % 16
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpOffPtr, src.Type)
+		v1.AuxInt = s % 16
+		v1.AddArg(src)
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQstore, types.TypeMem)
+		v2.AddArg(dst)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+		v3.AddArg(src)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Move [s] dst src mem)
+	// cond: s > 16 && s%16 != 0 && s%16 > 8
+	// result: (Move [s-s%16] 		(OffPtr <dst.Type> dst [s%16]) 		(OffPtr <src.Type> src [s%16]) 		(MOVOstore dst (MOVOload src mem) mem))
+	for {
+		s := v.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(s > 16 && s%16 != 0 && s%16 > 8) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = s - s%16
+		v0 := b.NewValue0(v.Pos, OpOffPtr, dst.Type)
+		v0.AuxInt = s % 16
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpOffPtr, src.Type)
+		v1.AuxInt = s % 16
+		v1.AddArg(src)
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVOstore, types.TypeMem)
+		v2.AddArg(dst)
+		v3 := b.NewValue0(v.Pos, OpAMD64MOVOload, types.TypeInt128)
+		v3.AddArg(src)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Move [s] dst src mem)
+	// cond: s >= 32 && s <= 16*64 && s%16 == 0 	&& !config.noDuffDevice
+	// result: (DUFFCOPY [14*(64-s/16)] dst src mem)
+	for {
+		s := v.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(s >= 32 && s <= 16*64 && s%16 == 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpAMD64DUFFCOPY)
+		v.AuxInt = 14 * (64 - s/16)
+		v.AddArg(dst)
+		v.AddArg(src)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [s] dst src mem)
+	// cond: (s > 16*64 || config.noDuffDevice) && s%8 == 0
+	// result: (REPMOVSQ dst src (MOVQconst [s/8]) mem)
+	for {
+		s := v.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !((s > 16*64 || config.noDuffDevice) && s%8 == 0) {
+			break
+		}
+		v.reset(OpAMD64REPMOVSQ)
+		v.AddArg(dst)
+		v.AddArg(src)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v0.AuxInt = s / 8
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpMul16_0(v *Value) bool {
+	// match: (Mul16 x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul32_0(v *Value) bool {
+	// match: (Mul32 x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul32F_0(v *Value) bool {
+	// match: (Mul32F x y)
+	// cond:
+	// result: (MULSS x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul64_0(v *Value) bool {
+	// match: (Mul64 x y)
+	// cond:
+	// result: (MULQ  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul64F_0(v *Value) bool {
+	// match: (Mul64F x y)
+	// cond:
+	// result: (MULSD x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul64uhilo_0(v *Value) bool {
+	// match: (Mul64uhilo x y)
+	// cond:
+	// result: (MULQU2 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULQU2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul8_0(v *Value) bool {
+	// match: (Mul8 x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg16_0(v *Value) bool {
+	// match: (Neg16 x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg32_0(v *Value) bool {
+	// match: (Neg32 x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neg32F x)
+	// cond:
+	// result: (PXOR x (MOVSSconst <typ.Float32> [f2i(math.Copysign(0, -1))]))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64PXOR)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVSSconst, typ.Float32)
+		v0.AuxInt = f2i(math.Copysign(0, -1))
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg64_0(v *Value) bool {
+	// match: (Neg64 x)
+	// cond:
+	// result: (NEGQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neg64F x)
+	// cond:
+	// result: (PXOR x (MOVSDconst <typ.Float64> [f2i(math.Copysign(0, -1))]))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64PXOR)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVSDconst, typ.Float64)
+		v0.AuxInt = f2i(math.Copysign(0, -1))
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg8_0(v *Value) bool {
+	// match: (Neg8 x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq16 x y)
+	// cond:
+	// result: (SETNE (CMPW x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPW, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32 x y)
+	// cond:
+	// result: (SETNE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32F x y)
+	// cond:
+	// result: (SETNEF (UCOMISS x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISS, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64 x y)
+	// cond:
+	// result: (SETNE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64F x y)
+	// cond:
+	// result: (SETNEF (UCOMISD x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNEF)
+		v0 := b.NewValue0(v.Pos, OpAMD64UCOMISD, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq8 x y)
+	// cond:
+	// result: (SETNE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeqB_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqB x y)
+	// cond:
+	// result: (SETNE (CMPB x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPB, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeqPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (NeqPtr x y)
+	// cond: config.PtrSize == 8
+	// result: (SETNE (CMPQ x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPQ, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (NeqPtr x y)
+	// cond: config.PtrSize == 4
+	// result: (SETNE (CMPL x y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Pos, OpAMD64CMPL, types.TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpNilCheck_0(v *Value) bool {
+	// match: (NilCheck ptr mem)
+	// cond:
+	// result: (LoweredNilCheck ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64LoweredNilCheck)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNot_0(v *Value) bool {
+	// 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_OpOffPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OffPtr [off] ptr)
+	// cond: config.PtrSize == 8 && is32Bit(off)
+	// result: (ADDQconst [off] ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		if !(config.PtrSize == 8 && is32Bit(off)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = off
+		v.AddArg(ptr)
+		return true
+	}
+	// match: (OffPtr [off] ptr)
+	// cond: config.PtrSize == 8
+	// result: (ADDQ (MOVQconst [off]) ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64ADDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v.AddArg(ptr)
+		return true
+	}
+	// match: (OffPtr [off] ptr)
+	// cond: config.PtrSize == 4
+	// result: (ADDLconst [off] ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64ADDLconst)
+		v.AuxInt = off
+		v.AddArg(ptr)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpOr16_0(v *Value) bool {
+	// match: (Or16 x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr32_0(v *Value) bool {
+	// match: (Or32 x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr64_0(v *Value) bool {
+	// match: (Or64 x y)
+	// cond:
+	// result: (ORQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr8_0(v *Value) bool {
+	// match: (Or8 x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOrB_0(v *Value) bool {
+	// match: (OrB x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpPopCount16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PopCount16 x)
+	// cond:
+	// result: (POPCNTL (MOVWQZX <typ.UInt32> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64POPCNTL)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWQZX, typ.UInt32)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpPopCount32_0(v *Value) bool {
+	// match: (PopCount32 x)
+	// cond:
+	// result: (POPCNTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64POPCNTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpPopCount64_0(v *Value) bool {
+	// match: (PopCount64 x)
+	// cond:
+	// result: (POPCNTQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64POPCNTQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpPopCount8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PopCount8 x)
+	// cond:
+	// result: (POPCNTL (MOVBQZX <typ.UInt32> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64POPCNTL)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVBQZX, typ.UInt32)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 16
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 16
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 16
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 16
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v3.AuxInt = 16
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v3.AuxInt = 16
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v3.AuxInt = 16
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v3.AuxInt = 16
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 32
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v3.AuxInt = 32
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v3.AuxInt = 32
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v3.AuxInt = 32
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v3.AuxInt = 32
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 64
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v3.AuxInt = 64
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v3.AuxInt = 64
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v3.AuxInt = 64
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v3.AuxInt = 64
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v2.AuxInt = 8
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v2.AuxInt = 8
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v2.AuxInt = 8
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Pos, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v2.AuxInt = 8
+		v2.AddArg(y)
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x16_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPWconst, types.TypeFlags)
+		v3.AuxInt = 8
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x32_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
+		v3.AuxInt = 8
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x64_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+		v3.AuxInt = 8
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x8_0(v *Value) 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
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Pos, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Pos, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpAMD64CMPBconst, types.TypeFlags)
+		v3.AuxInt = 8
+		v3.AddArg(y)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSelect0_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Select0 <t> (AddTupleFirst32 val tuple))
+	// cond:
+	// result: (ADDL val (Select0 <t> tuple))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64AddTupleFirst32 {
+			break
+		}
+		_ = v_0.Args[1]
+		val := v_0.Args[0]
+		tuple := v_0.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpSelect0, t)
+		v0.AddArg(tuple)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Select0 <t> (AddTupleFirst64 val tuple))
+	// cond:
+	// result: (ADDQ val (Select0 <t> tuple))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64AddTupleFirst64 {
+			break
+		}
+		_ = v_0.Args[1]
+		val := v_0.Args[0]
+		tuple := v_0.Args[1]
+		v.reset(OpAMD64ADDQ)
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpSelect0, t)
+		v0.AddArg(tuple)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpSelect1_0(v *Value) bool {
+	// match: (Select1 (AddTupleFirst32 _ tuple))
+	// cond:
+	// result: (Select1 tuple)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64AddTupleFirst32 {
+			break
+		}
+		_ = v_0.Args[1]
+		tuple := v_0.Args[1]
+		v.reset(OpSelect1)
+		v.AddArg(tuple)
+		return true
+	}
+	// match: (Select1 (AddTupleFirst64 _ tuple))
+	// cond:
+	// result: (Select1 tuple)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64AddTupleFirst64 {
+			break
+		}
+		_ = v_0.Args[1]
+		tuple := v_0.Args[1]
+		v.reset(OpSelect1)
+		v.AddArg(tuple)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpSignExt16to32_0(v *Value) bool {
+	// match: (SignExt16to32 x)
+	// cond:
+	// result: (MOVWQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt16to64_0(v *Value) bool {
+	// match: (SignExt16to64 x)
+	// cond:
+	// result: (MOVWQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt32to64_0(v *Value) bool {
+	// match: (SignExt32to64 x)
+	// cond:
+	// result: (MOVLQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVLQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to16_0(v *Value) bool {
+	// match: (SignExt8to16 x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to32_0(v *Value) bool {
+	// match: (SignExt8to32 x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to64_0(v *Value) bool {
+	// match: (SignExt8to64 x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSlicemask_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Slicemask <t> x)
+	// cond:
+	// result: (SARQconst (NEGQ <t> x) [63])
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64SARQconst)
+		v.AuxInt = 63
+		v0 := b.NewValue0(v.Pos, OpAMD64NEGQ, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSqrt_0(v *Value) bool {
+	// match: (Sqrt x)
+	// cond:
+	// result: (SQRTSD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64SQRTSD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpStaticCall_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
+	// result: (MOVSDstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
+	// result: (MOVSSstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8
+	// result: (MOVQstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 8) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4
+	// result: (MOVLstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 4) {
+			break
+		}
+		v.reset(OpAMD64MOVLstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
+	// result: (MOVWstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
+	// result: (MOVBstore ptr val mem)
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
+		v.reset(OpAMD64MOVBstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpSub16_0(v *Value) bool {
+	// match: (Sub16 x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub32_0(v *Value) bool {
+	// match: (Sub32 x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub32F_0(v *Value) bool {
+	// match: (Sub32F x y)
+	// cond:
+	// result: (SUBSS x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub64_0(v *Value) bool {
+	// match: (Sub64 x y)
+	// cond:
+	// result: (SUBQ  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub64F_0(v *Value) bool {
+	// match: (Sub64F x y)
+	// cond:
+	// result: (SUBSD x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub8_0(v *Value) bool {
+	// match: (Sub8 x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSubPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	// match: (SubPtr x y)
+	// cond: config.PtrSize == 8
+	// result: (SUBQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SubPtr x y)
+	// cond: config.PtrSize == 4
+	// result: (SUBL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpTrunc16to8_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_OpXor16_0(v *Value) bool {
+	// match: (Xor16 x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor32_0(v *Value) bool {
+	// match: (Xor32 x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor64_0(v *Value) bool {
+	// match: (Xor64 x y)
+	// cond:
+	// result: (XORQ x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor8_0(v *Value) bool {
+	// match: (Xor8 x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZero_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Zero [0] _ mem)
+	// cond:
+	// result: mem
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		_ = v.Args[1]
+		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
+		}
+		_ = v.Args[1]
+		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
+		}
+		_ = v.Args[1]
+		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
+		}
+		_ = v.Args[1]
+		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
+		}
+		_ = v.Args[1]
+		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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = makeValAndOff(0, 2)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVWstoreconst, types.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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = makeValAndOff(0, 4)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = makeValAndOff(0, 4)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = makeValAndOff(0, 3)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [s] destptr mem)
+	// cond: s%8 != 0 && s > 8
+	// result: (Zero [s-s%8] (OffPtr <destptr.Type> destptr [s%8]) 		(MOVQstoreconst [0] destptr mem))
+	for {
+		s := v.AuxInt
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(s%8 != 0 && s > 8) {
+			break
+		}
+		v.reset(OpZero)
+		v.AuxInt = s - s%8
+		v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
+		v0.AuxInt = s % 8
+		v0.AddArg(destptr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+		v1.AuxInt = 0
+		v1.AddArg(destptr)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [16] destptr mem)
+	// cond:
+	// result: (MOVQstoreconst [makeValAndOff(0,8)] destptr 		(MOVQstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 16 {
+			break
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 8)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 16)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+		v0.AuxInt = makeValAndOff(0, 8)
+		v0.AddArg(destptr)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.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
+		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 24)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+		v0.AuxInt = makeValAndOff(0, 16)
+		v0.AddArg(destptr)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+		v1.AuxInt = makeValAndOff(0, 8)
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+		v2.AuxInt = 0
+		v2.AddArg(destptr)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [s] destptr mem)
+	// cond: s <= 1024 && s%8 == 0 && s%16 != 0 	&& !config.noDuffDevice
+	// result: (Zero [s-8] (OffPtr <destptr.Type> [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+	for {
+		s := v.AuxInt
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(s <= 1024 && s%8 == 0 && s%16 != 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpZero)
+		v.AuxInt = s - 8
+		v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
+		v0.AuxInt = 8
+		v0.AddArg(destptr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQstore, types.TypeMem)
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v2.AuxInt = 0
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Zero [s] destptr mem)
+	// cond: s <= 1024 && s%16 == 0 && !config.noDuffDevice
+	// result: (DUFFZERO [s] destptr (MOVOconst [0]) mem)
+	for {
+		s := v.AuxInt
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(s <= 1024 && s%16 == 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpAMD64DUFFZERO)
+		v.AuxInt = s
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVOconst, types.TypeInt128)
+		v0.AuxInt = 0
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [s] destptr mem)
+	// cond: (s > 1024 || (config.noDuffDevice && s > 32)) 	&& s%8 == 0
+	// result: (REPSTOSQ destptr (MOVQconst [s/8]) (MOVQconst [0]) mem)
+	for {
+		s := v.AuxInt
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !((s > 1024 || (config.noDuffDevice && s > 32)) && s%8 == 0) {
+			break
+		}
+		v.reset(OpAMD64REPSTOSQ)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v0.AuxInt = s / 8
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpAMD64MOVQconst, typ.UInt64)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpZeroExt16to32_0(v *Value) bool {
+	// match: (ZeroExt16to32 x)
+	// cond:
+	// result: (MOVWQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt16to64_0(v *Value) bool {
+	// match: (ZeroExt16to64 x)
+	// cond:
+	// result: (MOVWQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt32to64_0(v *Value) bool {
+	// match: (ZeroExt32to64 x)
+	// cond:
+	// result: (MOVLQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVLQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to16_0(v *Value) bool {
+	// match: (ZeroExt8to16 x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to32_0(v *Value) bool {
+	// match: (ZeroExt8to32 x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to64_0(v *Value) bool {
+	// 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 {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
+	switch b.Kind {
+	case BlockAMD64EQ:
+		// match: (EQ (TESTL (SHLL (MOVLconst [1]) x) y))
+		// cond: !config.nacl
+		// result: (UGE (BTL x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTL {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SHLL {
+				break
+			}
+			_ = v_0.Args[1]
+			v_0_0 := v_0.Args[0]
+			if v_0_0.Op != OpAMD64MOVLconst {
+				break
+			}
+			if v_0_0.AuxInt != 1 {
+				break
+			}
+			x := v_0.Args[1]
+			y := v.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTL y (SHLL (MOVLconst [1]) x)))
+		// cond: !config.nacl
+		// result: (UGE (BTL x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTL {
+				break
+			}
+			_ = v.Args[1]
+			y := v.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SHLL {
+				break
+			}
+			_ = v_1.Args[1]
+			v_1_0 := v_1.Args[0]
+			if v_1_0.Op != OpAMD64MOVLconst {
+				break
+			}
+			if v_1_0.AuxInt != 1 {
+				break
+			}
+			x := v_1.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTQ (SHLQ (MOVQconst [1]) x) y))
+		// cond: !config.nacl
+		// result: (UGE (BTQ x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SHLQ {
+				break
+			}
+			_ = v_0.Args[1]
+			v_0_0 := v_0.Args[0]
+			if v_0_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			if v_0_0.AuxInt != 1 {
+				break
+			}
+			x := v_0.Args[1]
+			y := v.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTQ y (SHLQ (MOVQconst [1]) x)))
+		// cond: !config.nacl
+		// result: (UGE (BTQ x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			y := v.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SHLQ {
+				break
+			}
+			_ = v_1.Args[1]
+			v_1_0 := v_1.Args[0]
+			if v_1_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			if v_1_0.AuxInt != 1 {
+				break
+			}
+			x := v_1.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTLconst [c] x))
+		// cond: isPowerOfTwo(c) && log2(c) < 32 && !config.nacl
+		// result: (UGE (BTLconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTLconst {
+				break
+			}
+			c := v.AuxInt
+			x := v.Args[0]
+			if !(isPowerOfTwo(c) && log2(c) < 32 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTLconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTQconst [c] x))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (UGE (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQconst {
+				break
+			}
+			c := v.AuxInt
+			x := v.Args[0]
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTQ (MOVQconst [c]) x))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (UGE (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			c := v_0.AuxInt
+			x := v.Args[1]
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (EQ (TESTQ x (MOVQconst [c])))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (UGE (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			x := v.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64MOVQconst {
+				break
+			}
+			c := v_1.AuxInt
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64UGE
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// 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]
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (EQ (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (EQ (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (EQ (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (EQ (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (EQ (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			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]
+			b.Kind = BlockAMD64LE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (GE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (GE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (GE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (GE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (GE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			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]
+			b.Kind = BlockAMD64LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (EQ (FlagEQ) yes no)
+		// match: (GT (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (GT (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (GT (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			return true
+		}
+		// match: (GT (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			return true
+		}
+		// match: (GT (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			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]
+			b.Kind = BlockAMD64LT
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64LE
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64GT
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64GE
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64ULE
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			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]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			return true
+		}
+		// match: (If (SETGF cmp) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (UGT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagEQ {
+			if v.Op != OpAMD64SETGF {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			cmp := v.Args[0]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (EQ (FlagLT_ULT) yes no)
+		// match: (If (SETGEF cmp) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (UGE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagLT_ULT {
+			if v.Op != OpAMD64SETGEF {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			cmp := v.Args[0]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (EQ (FlagLT_UGT) yes no)
+		// match: (If (SETEQF cmp) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (EQF  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagLT_UGT {
+			if v.Op != OpAMD64SETEQF {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			cmp := v.Args[0]
+			b.Kind = BlockAMD64EQF
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (EQ (FlagGT_ULT) yes no)
+		// match: (If (SETNEF cmp) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (NEF  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagGT_ULT {
+			if v.Op != OpAMD64SETNEF {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			cmp := v.Args[0]
+			b.Kind = BlockAMD64NEF
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (EQ (FlagGT_UGT) yes no)
+		// match: (If cond yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (NE (TESTB cond cond) 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)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v
+			cond := b.Control
+			b.Kind = BlockAMD64NE
+			v0 := b.NewValue0(v.Pos, OpAMD64TESTB, types.TypeFlags)
+			v0.AddArg(cond)
+			v0.AddArg(cond)
+			b.SetControl(v0)
 			return true
 		}
-	case BlockAMD64GE:
-		// match: (GE (InvertFlags cmp) yes no)
+	case BlockAMD64LE:
+		// match: (LE (InvertFlags cmp) yes no)
 		// cond:
-		// result: (LE cmp yes no)
+		// 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 = BlockAMD64LE
+			b.Kind = BlockAMD64GE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (GE (FlagEQ) yes no)
+		// match: (LE (FlagEQ) yes no)
 		// cond:
 		// result: (First nil yes no)
 		for {
@@ -20299,99 +43781,75 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
+		// match: (LE (FlagLT_ULT) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// 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)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (GE (FlagLT_UGT) yes no)
+		// match: (LE (FlagLT_UGT) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// 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)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (GE (FlagGT_ULT) yes no)
+		// match: (LE (FlagGT_ULT) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// 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)
-			_ = yes
-			_ = no
+			b.swapSuccessors()
 			return true
 		}
-		// match: (GE (FlagGT_UGT) yes no)
+		// match: (LE (FlagGT_UGT) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// 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)
-			_ = yes
-			_ = no
+			b.swapSuccessors()
 			return true
 		}
-	case BlockAMD64GT:
-		// match: (GT (InvertFlags cmp) yes no)
+	case BlockAMD64LT:
+		// match: (LT (InvertFlags cmp) yes no)
 		// cond:
-		// result: (LT cmp yes no)
+		// 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 = BlockAMD64LT
+			b.Kind = BlockAMD64GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (GT (FlagEQ) yes no)
+		// match: (LT (FlagEQ) yes no)
 		// cond:
 		// result: (First nil no yes)
 		for {
@@ -20399,874 +43857,907 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
+		// match: (LT (FlagLT_ULT) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// 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)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (GT (FlagLT_UGT) yes no)
+		// match: (LT (FlagLT_UGT) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// 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)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (GT (FlagGT_ULT) yes no)
+		// match: (LT (FlagGT_ULT) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// 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)
-			_ = yes
-			_ = no
+			b.swapSuccessors()
 			return true
 		}
-		// match: (GT (FlagGT_UGT) yes no)
+		// match: (LT (FlagGT_UGT) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// 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)
-			_ = yes
-			_ = no
+			b.swapSuccessors()
 			return true
 		}
-	case BlockIf:
-		// match: (If (SETL  cmp) yes no)
+	case BlockAMD64NE:
+		// match: (NE (TESTB (SETL cmp) (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 {
+			if v.Op != OpAMD64TESTB {
 				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 {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETL {
 				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 {
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETL {
 				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 {
+			if cmp != v_1.Args[0] {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64EQ
+			b.Kind = BlockAMD64LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETNE cmp) yes no)
+		// match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
 		// cond:
-		// result: (NE  cmp yes no)
+		// result: (LT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64SETNE {
+			if v.Op != OpAMD64TESTB {
 				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 {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETL {
 				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 {
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETL {
 				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 {
+			if cmp != v_1.Args[0] {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64UGT
+			b.Kind = BlockAMD64LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETAE cmp) yes no)
+		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
 		// cond:
-		// result: (UGE cmp yes no)
+		// result: (LE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64SETAE {
+			if v.Op != OpAMD64TESTB {
 				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 {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETLE {
 				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 {
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETLE {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64UGE
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = BlockAMD64LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETEQF cmp) yes no)
+		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
 		// cond:
-		// result: (EQF  cmp yes no)
+		// result: (LE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64SETEQF {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64EQF
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If (SETNEF cmp) yes no)
+		// match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
 		// cond:
-		// result: (NEF  cmp yes no)
+		// result: (GT  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64SETNEF {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64NEF
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (If cond yes no)
+		// match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
 		// cond:
-		// result: (NE (TESTB cond cond) yes no)
+		// result: (GT  cmp yes no)
 		for {
 			v := b.Control
-			_ = v
-			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
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64GT
+			b.SetControl(cmp)
 			return true
 		}
-	case BlockAMD64LE:
-		// match: (LE (InvertFlags cmp) yes no)
+		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
 		// cond:
-		// result: (GE cmp yes no)
+		// result: (GE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64InvertFlags {
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			_ = v.Args[1]
+			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
 			}
-			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)
+		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (GE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagEQ {
+			if v.Op != OpAMD64TESTB {
 				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 {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETGE {
 				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 {
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETGE {
 				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 {
+			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			b.Kind = BlockAMD64GE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LE (FlagGT_UGT) yes no)
+		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (EQ  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagGT_UGT {
+			if v.Op != OpAMD64TESTB {
 				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 {
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETEQ {
 				break
 			}
-			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64GT
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETEQ {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			b.Kind = BlockAMD64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (LT (FlagEQ) yes no)
+		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (EQ  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagEQ {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagLT_ULT) yes no)
+		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (NE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagLT_ULT {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagLT_UGT) yes no)
+		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
 		// cond:
-		// result: (First nil yes no)
+		// result: (NE  cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagLT_UGT {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			_ = yes
-			_ = no
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagGT_ULT) yes no)
+		// match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (ULT cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagGT_ULT {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
 			return true
 		}
-		// match: (LT (FlagGT_UGT) yes no)
+		// match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
 		// cond:
-		// result: (First nil no yes)
+		// result: (ULT cmp yes no)
 		for {
 			v := b.Control
-			if v.Op != OpAMD64FlagGT_UGT {
+			if v.Op != OpAMD64TESTB {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockFirst
-			b.SetControl(nil)
-			b.swapSuccessors()
-			_ = no
-			_ = yes
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
 			return true
 		}
-	case BlockAMD64NE:
-		// match: (NE (TESTB (SETL  cmp) (SETL  cmp)) yes no)
+		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
 		// cond:
-		// result: (LT  cmp yes no)
+		// result: (ULE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETL {
+			if v_0.Op != OpAMD64SETBE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETL {
+			if v_1.Op != OpAMD64SETBE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64LT
+			b.Kind = BlockAMD64ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
+		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
 		// cond:
-		// result: (LE  cmp yes no)
+		// result: (ULE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETLE {
+			if v_0.Op != OpAMD64SETBE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETLE {
+			if v_1.Op != OpAMD64SETBE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64LE
+			b.Kind = BlockAMD64ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETG  cmp) (SETG  cmp)) yes no)
+		// match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
 		// cond:
-		// result: (GT  cmp yes no)
+		// result: (UGT cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETG {
+			if v_0.Op != OpAMD64SETA {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETG {
+			if v_1.Op != OpAMD64SETA {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64GT
+			b.Kind = BlockAMD64UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
+		// match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
 		// cond:
-		// result: (GE  cmp yes no)
+		// result: (UGT cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETGE {
+			if v_0.Op != OpAMD64SETA {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETGE {
+			if v_1.Op != OpAMD64SETA {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64GE
+			b.Kind = BlockAMD64UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
+		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
 		// cond:
-		// result: (EQ  cmp yes no)
+		// result: (UGE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETEQ {
+			if v_0.Op != OpAMD64SETAE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETEQ {
+			if v_1.Op != OpAMD64SETAE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64EQ
+			b.Kind = BlockAMD64UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
+		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
 		// cond:
-		// result: (NE  cmp yes no)
+		// result: (UGE cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETNE {
+			if v_0.Op != OpAMD64SETAE {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETNE {
+			if v_1.Op != OpAMD64SETAE {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64NE
+			b.Kind = BlockAMD64UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETB  cmp) (SETB  cmp)) yes no)
-		// cond:
-		// result: (ULT cmp yes no)
+		// match: (NE (TESTL (SHLL (MOVLconst [1]) x) y))
+		// cond: !config.nacl
+		// result: (ULT (BTL x y))
 		for {
 			v := b.Control
-			if v.Op != OpAMD64TESTB {
+			if v.Op != OpAMD64TESTL {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETB {
+			if v_0.Op != OpAMD64SHLL {
 				break
 			}
-			cmp := v_0.Args[0]
+			_ = v_0.Args[1]
+			v_0_0 := v_0.Args[0]
+			if v_0_0.Op != OpAMD64MOVLconst {
+				break
+			}
+			if v_0_0.AuxInt != 1 {
+				break
+			}
+			x := v_0.Args[1]
+			y := v.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTL y (SHLL (MOVLconst [1]) x)))
+		// cond: !config.nacl
+		// result: (ULT (BTL x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTL {
+				break
+			}
+			_ = v.Args[1]
+			y := v.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETB {
+			if v_1.Op != OpAMD64SHLL {
 				break
 			}
-			if cmp != v_1.Args[0] {
+			_ = v_1.Args[1]
+			v_1_0 := v_1.Args[0]
+			if v_1_0.Op != OpAMD64MOVLconst {
+				break
+			}
+			if v_1_0.AuxInt != 1 {
+				break
+			}
+			x := v_1.Args[1]
+			if !(!config.nacl) {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockAMD64ULT
-			b.SetControl(cmp)
-			_ = yes
-			_ = no
+			v0 := b.NewValue0(v.Pos, OpAMD64BTL, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
 			return true
 		}
-		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
+		// match: (NE (TESTQ (SHLQ (MOVQconst [1]) x) y))
+		// cond: !config.nacl
+		// result: (ULT (BTQ x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SHLQ {
+				break
+			}
+			_ = v_0.Args[1]
+			v_0_0 := v_0.Args[0]
+			if v_0_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			if v_0_0.AuxInt != 1 {
+				break
+			}
+			x := v_0.Args[1]
+			y := v.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTQ y (SHLQ (MOVQconst [1]) x)))
+		// cond: !config.nacl
+		// result: (ULT (BTQ x y))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			y := v.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SHLQ {
+				break
+			}
+			_ = v_1.Args[1]
+			v_1_0 := v_1.Args[0]
+			if v_1_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			if v_1_0.AuxInt != 1 {
+				break
+			}
+			x := v_1.Args[1]
+			if !(!config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQ, types.TypeFlags)
+			v0.AddArg(x)
+			v0.AddArg(y)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTLconst [c] x))
+		// cond: isPowerOfTwo(c) && log2(c) < 32 && !config.nacl
+		// result: (ULT (BTLconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTLconst {
+				break
+			}
+			c := v.AuxInt
+			x := v.Args[0]
+			if !(isPowerOfTwo(c) && log2(c) < 32 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTLconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTQconst [c] x))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (ULT (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQconst {
+				break
+			}
+			c := v.AuxInt
+			x := v.Args[0]
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTQ (MOVQconst [c]) x))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (ULT (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64MOVQconst {
+				break
+			}
+			c := v_0.AuxInt
+			x := v.Args[1]
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTQ x (MOVQconst [c])))
+		// cond: isPowerOfTwo(c) && log2(c) < 64 && !config.nacl
+		// result: (ULT (BTQconst [log2(c)] x))
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTQ {
+				break
+			}
+			_ = v.Args[1]
+			x := v.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64MOVQconst {
+				break
+			}
+			c := v_1.AuxInt
+			if !(isPowerOfTwo(c) && log2(c) < 64 && !config.nacl) {
+				break
+			}
+			b.Kind = BlockAMD64ULT
+			v0 := b.NewValue0(v.Pos, OpAMD64BTQconst, types.TypeFlags)
+			v0.AuxInt = log2(c)
+			v0.AddArg(x)
+			b.SetControl(v0)
+			return true
+		}
+		// match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
 		// cond:
-		// result: (ULE cmp yes no)
+		// result: (UGT  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETBE {
+			if v_0.Op != OpAMD64SETGF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETBE {
+			if v_1.Op != OpAMD64SETGF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64ULE
+			b.Kind = BlockAMD64UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETA  cmp) (SETA  cmp)) yes no)
+		// match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
 		// cond:
-		// result: (UGT cmp yes no)
+		// result: (UGT  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETA {
+			if v_0.Op != OpAMD64SETGF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETA {
+			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 (SETAE cmp) (SETAE cmp)) yes no)
+		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
 		// cond:
-		// result: (UGE cmp yes no)
+		// result: (UGE  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETAE {
+			if v_0.Op != OpAMD64SETGEF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETAE {
+			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 (SETGF  cmp) (SETGF  cmp)) yes no)
+		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
 		// cond:
-		// result: (UGT  cmp yes no)
+		// result: (UGE  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETGF {
+			if v_0.Op != OpAMD64SETGEF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETGF {
+			if v_1.Op != OpAMD64SETGEF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64UGT
+			b.Kind = BlockAMD64UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
+		// match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
 		// cond:
-		// result: (UGE  cmp yes no)
+		// result: (EQF  cmp yes no)
 		for {
 			v := b.Control
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
-			if v_0.Op != OpAMD64SETGEF {
+			if v_0.Op != OpAMD64SETEQF {
 				break
 			}
 			cmp := v_0.Args[0]
 			v_1 := v.Args[1]
-			if v_1.Op != OpAMD64SETGEF {
+			if v_1.Op != OpAMD64SETEQF {
 				break
 			}
 			if cmp != v_1.Args[0] {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
-			b.Kind = BlockAMD64UGE
+			b.Kind = BlockAMD64EQF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
@@ -21277,6 +44768,7 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
 			v_0 := v.Args[0]
 			if v_0.Op != OpAMD64SETEQF {
 				break
@@ -21289,12 +44781,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21305,6 +44793,32 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			if v.Op != OpAMD64TESTB {
 				break
 			}
+			_ = v.Args[1]
+			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
+			}
+			b.Kind = BlockAMD64NEF
+			b.SetControl(cmp)
+			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.Args[1]
 			v_0 := v.Args[0]
 			if v_0.Op != OpAMD64SETNEF {
 				break
@@ -21317,12 +44831,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21334,12 +44844,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 				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)
@@ -21350,13 +44856,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21367,12 +44869,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21383,12 +44881,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21399,12 +44893,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21415,12 +44905,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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:
@@ -21433,12 +44919,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 				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)
@@ -21449,12 +44931,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21465,13 +44943,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21482,12 +44956,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21498,13 +44968,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21515,12 +44981,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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:
@@ -21533,12 +44995,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 				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)
@@ -21549,13 +45007,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21566,13 +45020,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21583,12 +45033,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21599,13 +45045,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21616,12 +45058,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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:
@@ -21634,12 +45072,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 				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)
@@ -21650,12 +45084,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21666,12 +45096,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21682,13 +45108,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21699,12 +45121,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21715,13 +45133,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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:
@@ -21734,12 +45148,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 				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)
@@ -21750,13 +45160,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21767,12 +45173,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21783,13 +45185,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21800,12 +45198,8 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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)
@@ -21816,13 +45210,9 @@ func rewriteBlockAMD64(b *Block, config *Config) bool {
 			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
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 234783b..6bb8da5 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -1,745 +1,741 @@
-// autogenerated from gen/ARM.rules: do not edit!
+// Code generated from gen/ARM.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueARM(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueARM(v *Value) bool {
 	switch v.Op {
 	case OpARMADC:
-		return rewriteValueARM_OpARMADC(v, config)
+		return rewriteValueARM_OpARMADC_0(v) || rewriteValueARM_OpARMADC_10(v) || rewriteValueARM_OpARMADC_20(v)
 	case OpARMADCconst:
-		return rewriteValueARM_OpARMADCconst(v, config)
+		return rewriteValueARM_OpARMADCconst_0(v)
 	case OpARMADCshiftLL:
-		return rewriteValueARM_OpARMADCshiftLL(v, config)
+		return rewriteValueARM_OpARMADCshiftLL_0(v)
 	case OpARMADCshiftLLreg:
-		return rewriteValueARM_OpARMADCshiftLLreg(v, config)
+		return rewriteValueARM_OpARMADCshiftLLreg_0(v)
 	case OpARMADCshiftRA:
-		return rewriteValueARM_OpARMADCshiftRA(v, config)
+		return rewriteValueARM_OpARMADCshiftRA_0(v)
 	case OpARMADCshiftRAreg:
-		return rewriteValueARM_OpARMADCshiftRAreg(v, config)
+		return rewriteValueARM_OpARMADCshiftRAreg_0(v)
 	case OpARMADCshiftRL:
-		return rewriteValueARM_OpARMADCshiftRL(v, config)
+		return rewriteValueARM_OpARMADCshiftRL_0(v)
 	case OpARMADCshiftRLreg:
-		return rewriteValueARM_OpARMADCshiftRLreg(v, config)
+		return rewriteValueARM_OpARMADCshiftRLreg_0(v)
 	case OpARMADD:
-		return rewriteValueARM_OpARMADD(v, config)
+		return rewriteValueARM_OpARMADD_0(v) || rewriteValueARM_OpARMADD_10(v)
 	case OpARMADDS:
-		return rewriteValueARM_OpARMADDS(v, config)
+		return rewriteValueARM_OpARMADDS_0(v) || rewriteValueARM_OpARMADDS_10(v)
 	case OpARMADDSshiftLL:
-		return rewriteValueARM_OpARMADDSshiftLL(v, config)
+		return rewriteValueARM_OpARMADDSshiftLL_0(v)
 	case OpARMADDSshiftLLreg:
-		return rewriteValueARM_OpARMADDSshiftLLreg(v, config)
+		return rewriteValueARM_OpARMADDSshiftLLreg_0(v)
 	case OpARMADDSshiftRA:
-		return rewriteValueARM_OpARMADDSshiftRA(v, config)
+		return rewriteValueARM_OpARMADDSshiftRA_0(v)
 	case OpARMADDSshiftRAreg:
-		return rewriteValueARM_OpARMADDSshiftRAreg(v, config)
+		return rewriteValueARM_OpARMADDSshiftRAreg_0(v)
 	case OpARMADDSshiftRL:
-		return rewriteValueARM_OpARMADDSshiftRL(v, config)
+		return rewriteValueARM_OpARMADDSshiftRL_0(v)
 	case OpARMADDSshiftRLreg:
-		return rewriteValueARM_OpARMADDSshiftRLreg(v, config)
+		return rewriteValueARM_OpARMADDSshiftRLreg_0(v)
 	case OpARMADDconst:
-		return rewriteValueARM_OpARMADDconst(v, config)
+		return rewriteValueARM_OpARMADDconst_0(v)
 	case OpARMADDshiftLL:
-		return rewriteValueARM_OpARMADDshiftLL(v, config)
+		return rewriteValueARM_OpARMADDshiftLL_0(v)
 	case OpARMADDshiftLLreg:
-		return rewriteValueARM_OpARMADDshiftLLreg(v, config)
+		return rewriteValueARM_OpARMADDshiftLLreg_0(v)
 	case OpARMADDshiftRA:
-		return rewriteValueARM_OpARMADDshiftRA(v, config)
+		return rewriteValueARM_OpARMADDshiftRA_0(v)
 	case OpARMADDshiftRAreg:
-		return rewriteValueARM_OpARMADDshiftRAreg(v, config)
+		return rewriteValueARM_OpARMADDshiftRAreg_0(v)
 	case OpARMADDshiftRL:
-		return rewriteValueARM_OpARMADDshiftRL(v, config)
+		return rewriteValueARM_OpARMADDshiftRL_0(v)
 	case OpARMADDshiftRLreg:
-		return rewriteValueARM_OpARMADDshiftRLreg(v, config)
+		return rewriteValueARM_OpARMADDshiftRLreg_0(v)
 	case OpARMAND:
-		return rewriteValueARM_OpARMAND(v, config)
+		return rewriteValueARM_OpARMAND_0(v) || rewriteValueARM_OpARMAND_10(v) || rewriteValueARM_OpARMAND_20(v)
 	case OpARMANDconst:
-		return rewriteValueARM_OpARMANDconst(v, config)
+		return rewriteValueARM_OpARMANDconst_0(v)
 	case OpARMANDshiftLL:
-		return rewriteValueARM_OpARMANDshiftLL(v, config)
+		return rewriteValueARM_OpARMANDshiftLL_0(v)
 	case OpARMANDshiftLLreg:
-		return rewriteValueARM_OpARMANDshiftLLreg(v, config)
+		return rewriteValueARM_OpARMANDshiftLLreg_0(v)
 	case OpARMANDshiftRA:
-		return rewriteValueARM_OpARMANDshiftRA(v, config)
+		return rewriteValueARM_OpARMANDshiftRA_0(v)
 	case OpARMANDshiftRAreg:
-		return rewriteValueARM_OpARMANDshiftRAreg(v, config)
+		return rewriteValueARM_OpARMANDshiftRAreg_0(v)
 	case OpARMANDshiftRL:
-		return rewriteValueARM_OpARMANDshiftRL(v, config)
+		return rewriteValueARM_OpARMANDshiftRL_0(v)
 	case OpARMANDshiftRLreg:
-		return rewriteValueARM_OpARMANDshiftRLreg(v, config)
+		return rewriteValueARM_OpARMANDshiftRLreg_0(v)
 	case OpARMBIC:
-		return rewriteValueARM_OpARMBIC(v, config)
+		return rewriteValueARM_OpARMBIC_0(v)
 	case OpARMBICconst:
-		return rewriteValueARM_OpARMBICconst(v, config)
+		return rewriteValueARM_OpARMBICconst_0(v)
 	case OpARMBICshiftLL:
-		return rewriteValueARM_OpARMBICshiftLL(v, config)
+		return rewriteValueARM_OpARMBICshiftLL_0(v)
 	case OpARMBICshiftLLreg:
-		return rewriteValueARM_OpARMBICshiftLLreg(v, config)
+		return rewriteValueARM_OpARMBICshiftLLreg_0(v)
 	case OpARMBICshiftRA:
-		return rewriteValueARM_OpARMBICshiftRA(v, config)
+		return rewriteValueARM_OpARMBICshiftRA_0(v)
 	case OpARMBICshiftRAreg:
-		return rewriteValueARM_OpARMBICshiftRAreg(v, config)
+		return rewriteValueARM_OpARMBICshiftRAreg_0(v)
 	case OpARMBICshiftRL:
-		return rewriteValueARM_OpARMBICshiftRL(v, config)
+		return rewriteValueARM_OpARMBICshiftRL_0(v)
 	case OpARMBICshiftRLreg:
-		return rewriteValueARM_OpARMBICshiftRLreg(v, config)
+		return rewriteValueARM_OpARMBICshiftRLreg_0(v)
 	case OpARMCMOVWHSconst:
-		return rewriteValueARM_OpARMCMOVWHSconst(v, config)
+		return rewriteValueARM_OpARMCMOVWHSconst_0(v)
 	case OpARMCMOVWLSconst:
-		return rewriteValueARM_OpARMCMOVWLSconst(v, config)
+		return rewriteValueARM_OpARMCMOVWLSconst_0(v)
 	case OpARMCMP:
-		return rewriteValueARM_OpARMCMP(v, config)
+		return rewriteValueARM_OpARMCMP_0(v) || rewriteValueARM_OpARMCMP_10(v)
 	case OpARMCMPD:
-		return rewriteValueARM_OpARMCMPD(v, config)
+		return rewriteValueARM_OpARMCMPD_0(v)
 	case OpARMCMPF:
-		return rewriteValueARM_OpARMCMPF(v, config)
+		return rewriteValueARM_OpARMCMPF_0(v)
 	case OpARMCMPconst:
-		return rewriteValueARM_OpARMCMPconst(v, config)
+		return rewriteValueARM_OpARMCMPconst_0(v)
 	case OpARMCMPshiftLL:
-		return rewriteValueARM_OpARMCMPshiftLL(v, config)
+		return rewriteValueARM_OpARMCMPshiftLL_0(v)
 	case OpARMCMPshiftLLreg:
-		return rewriteValueARM_OpARMCMPshiftLLreg(v, config)
+		return rewriteValueARM_OpARMCMPshiftLLreg_0(v)
 	case OpARMCMPshiftRA:
-		return rewriteValueARM_OpARMCMPshiftRA(v, config)
+		return rewriteValueARM_OpARMCMPshiftRA_0(v)
 	case OpARMCMPshiftRAreg:
-		return rewriteValueARM_OpARMCMPshiftRAreg(v, config)
+		return rewriteValueARM_OpARMCMPshiftRAreg_0(v)
 	case OpARMCMPshiftRL:
-		return rewriteValueARM_OpARMCMPshiftRL(v, config)
+		return rewriteValueARM_OpARMCMPshiftRL_0(v)
 	case OpARMCMPshiftRLreg:
-		return rewriteValueARM_OpARMCMPshiftRLreg(v, config)
+		return rewriteValueARM_OpARMCMPshiftRLreg_0(v)
 	case OpARMEqual:
-		return rewriteValueARM_OpARMEqual(v, config)
+		return rewriteValueARM_OpARMEqual_0(v)
 	case OpARMGreaterEqual:
-		return rewriteValueARM_OpARMGreaterEqual(v, config)
+		return rewriteValueARM_OpARMGreaterEqual_0(v)
 	case OpARMGreaterEqualU:
-		return rewriteValueARM_OpARMGreaterEqualU(v, config)
+		return rewriteValueARM_OpARMGreaterEqualU_0(v)
 	case OpARMGreaterThan:
-		return rewriteValueARM_OpARMGreaterThan(v, config)
+		return rewriteValueARM_OpARMGreaterThan_0(v)
 	case OpARMGreaterThanU:
-		return rewriteValueARM_OpARMGreaterThanU(v, config)
+		return rewriteValueARM_OpARMGreaterThanU_0(v)
 	case OpARMLessEqual:
-		return rewriteValueARM_OpARMLessEqual(v, config)
+		return rewriteValueARM_OpARMLessEqual_0(v)
 	case OpARMLessEqualU:
-		return rewriteValueARM_OpARMLessEqualU(v, config)
+		return rewriteValueARM_OpARMLessEqualU_0(v)
 	case OpARMLessThan:
-		return rewriteValueARM_OpARMLessThan(v, config)
+		return rewriteValueARM_OpARMLessThan_0(v)
 	case OpARMLessThanU:
-		return rewriteValueARM_OpARMLessThanU(v, config)
+		return rewriteValueARM_OpARMLessThanU_0(v)
 	case OpARMMOVBUload:
-		return rewriteValueARM_OpARMMOVBUload(v, config)
+		return rewriteValueARM_OpARMMOVBUload_0(v)
 	case OpARMMOVBUreg:
-		return rewriteValueARM_OpARMMOVBUreg(v, config)
+		return rewriteValueARM_OpARMMOVBUreg_0(v)
 	case OpARMMOVBload:
-		return rewriteValueARM_OpARMMOVBload(v, config)
+		return rewriteValueARM_OpARMMOVBload_0(v)
 	case OpARMMOVBreg:
-		return rewriteValueARM_OpARMMOVBreg(v, config)
+		return rewriteValueARM_OpARMMOVBreg_0(v)
 	case OpARMMOVBstore:
-		return rewriteValueARM_OpARMMOVBstore(v, config)
+		return rewriteValueARM_OpARMMOVBstore_0(v)
 	case OpARMMOVDload:
-		return rewriteValueARM_OpARMMOVDload(v, config)
+		return rewriteValueARM_OpARMMOVDload_0(v)
 	case OpARMMOVDstore:
-		return rewriteValueARM_OpARMMOVDstore(v, config)
+		return rewriteValueARM_OpARMMOVDstore_0(v)
 	case OpARMMOVFload:
-		return rewriteValueARM_OpARMMOVFload(v, config)
+		return rewriteValueARM_OpARMMOVFload_0(v)
 	case OpARMMOVFstore:
-		return rewriteValueARM_OpARMMOVFstore(v, config)
+		return rewriteValueARM_OpARMMOVFstore_0(v)
 	case OpARMMOVHUload:
-		return rewriteValueARM_OpARMMOVHUload(v, config)
+		return rewriteValueARM_OpARMMOVHUload_0(v)
 	case OpARMMOVHUreg:
-		return rewriteValueARM_OpARMMOVHUreg(v, config)
+		return rewriteValueARM_OpARMMOVHUreg_0(v)
 	case OpARMMOVHload:
-		return rewriteValueARM_OpARMMOVHload(v, config)
+		return rewriteValueARM_OpARMMOVHload_0(v)
 	case OpARMMOVHreg:
-		return rewriteValueARM_OpARMMOVHreg(v, config)
+		return rewriteValueARM_OpARMMOVHreg_0(v)
 	case OpARMMOVHstore:
-		return rewriteValueARM_OpARMMOVHstore(v, config)
+		return rewriteValueARM_OpARMMOVHstore_0(v)
 	case OpARMMOVWload:
-		return rewriteValueARM_OpARMMOVWload(v, config)
+		return rewriteValueARM_OpARMMOVWload_0(v)
 	case OpARMMOVWloadidx:
-		return rewriteValueARM_OpARMMOVWloadidx(v, config)
+		return rewriteValueARM_OpARMMOVWloadidx_0(v)
 	case OpARMMOVWloadshiftLL:
-		return rewriteValueARM_OpARMMOVWloadshiftLL(v, config)
+		return rewriteValueARM_OpARMMOVWloadshiftLL_0(v)
 	case OpARMMOVWloadshiftRA:
-		return rewriteValueARM_OpARMMOVWloadshiftRA(v, config)
+		return rewriteValueARM_OpARMMOVWloadshiftRA_0(v)
 	case OpARMMOVWloadshiftRL:
-		return rewriteValueARM_OpARMMOVWloadshiftRL(v, config)
+		return rewriteValueARM_OpARMMOVWloadshiftRL_0(v)
 	case OpARMMOVWreg:
-		return rewriteValueARM_OpARMMOVWreg(v, config)
+		return rewriteValueARM_OpARMMOVWreg_0(v)
 	case OpARMMOVWstore:
-		return rewriteValueARM_OpARMMOVWstore(v, config)
+		return rewriteValueARM_OpARMMOVWstore_0(v)
 	case OpARMMOVWstoreidx:
-		return rewriteValueARM_OpARMMOVWstoreidx(v, config)
+		return rewriteValueARM_OpARMMOVWstoreidx_0(v)
 	case OpARMMOVWstoreshiftLL:
-		return rewriteValueARM_OpARMMOVWstoreshiftLL(v, config)
+		return rewriteValueARM_OpARMMOVWstoreshiftLL_0(v)
 	case OpARMMOVWstoreshiftRA:
-		return rewriteValueARM_OpARMMOVWstoreshiftRA(v, config)
+		return rewriteValueARM_OpARMMOVWstoreshiftRA_0(v)
 	case OpARMMOVWstoreshiftRL:
-		return rewriteValueARM_OpARMMOVWstoreshiftRL(v, config)
+		return rewriteValueARM_OpARMMOVWstoreshiftRL_0(v)
 	case OpARMMUL:
-		return rewriteValueARM_OpARMMUL(v, config)
+		return rewriteValueARM_OpARMMUL_0(v) || rewriteValueARM_OpARMMUL_10(v) || rewriteValueARM_OpARMMUL_20(v)
 	case OpARMMULA:
-		return rewriteValueARM_OpARMMULA(v, config)
+		return rewriteValueARM_OpARMMULA_0(v) || rewriteValueARM_OpARMMULA_10(v) || rewriteValueARM_OpARMMULA_20(v)
 	case OpARMMVN:
-		return rewriteValueARM_OpARMMVN(v, config)
+		return rewriteValueARM_OpARMMVN_0(v)
 	case OpARMMVNshiftLL:
-		return rewriteValueARM_OpARMMVNshiftLL(v, config)
+		return rewriteValueARM_OpARMMVNshiftLL_0(v)
 	case OpARMMVNshiftLLreg:
-		return rewriteValueARM_OpARMMVNshiftLLreg(v, config)
+		return rewriteValueARM_OpARMMVNshiftLLreg_0(v)
 	case OpARMMVNshiftRA:
-		return rewriteValueARM_OpARMMVNshiftRA(v, config)
+		return rewriteValueARM_OpARMMVNshiftRA_0(v)
 	case OpARMMVNshiftRAreg:
-		return rewriteValueARM_OpARMMVNshiftRAreg(v, config)
+		return rewriteValueARM_OpARMMVNshiftRAreg_0(v)
 	case OpARMMVNshiftRL:
-		return rewriteValueARM_OpARMMVNshiftRL(v, config)
+		return rewriteValueARM_OpARMMVNshiftRL_0(v)
 	case OpARMMVNshiftRLreg:
-		return rewriteValueARM_OpARMMVNshiftRLreg(v, config)
+		return rewriteValueARM_OpARMMVNshiftRLreg_0(v)
 	case OpARMNotEqual:
-		return rewriteValueARM_OpARMNotEqual(v, config)
+		return rewriteValueARM_OpARMNotEqual_0(v)
 	case OpARMOR:
-		return rewriteValueARM_OpARMOR(v, config)
+		return rewriteValueARM_OpARMOR_0(v) || rewriteValueARM_OpARMOR_10(v)
 	case OpARMORconst:
-		return rewriteValueARM_OpARMORconst(v, config)
+		return rewriteValueARM_OpARMORconst_0(v)
 	case OpARMORshiftLL:
-		return rewriteValueARM_OpARMORshiftLL(v, config)
+		return rewriteValueARM_OpARMORshiftLL_0(v)
 	case OpARMORshiftLLreg:
-		return rewriteValueARM_OpARMORshiftLLreg(v, config)
+		return rewriteValueARM_OpARMORshiftLLreg_0(v)
 	case OpARMORshiftRA:
-		return rewriteValueARM_OpARMORshiftRA(v, config)
+		return rewriteValueARM_OpARMORshiftRA_0(v)
 	case OpARMORshiftRAreg:
-		return rewriteValueARM_OpARMORshiftRAreg(v, config)
+		return rewriteValueARM_OpARMORshiftRAreg_0(v)
 	case OpARMORshiftRL:
-		return rewriteValueARM_OpARMORshiftRL(v, config)
+		return rewriteValueARM_OpARMORshiftRL_0(v)
 	case OpARMORshiftRLreg:
-		return rewriteValueARM_OpARMORshiftRLreg(v, config)
+		return rewriteValueARM_OpARMORshiftRLreg_0(v)
 	case OpARMRSB:
-		return rewriteValueARM_OpARMRSB(v, config)
+		return rewriteValueARM_OpARMRSB_0(v) || rewriteValueARM_OpARMRSB_10(v)
 	case OpARMRSBSshiftLL:
-		return rewriteValueARM_OpARMRSBSshiftLL(v, config)
+		return rewriteValueARM_OpARMRSBSshiftLL_0(v)
 	case OpARMRSBSshiftLLreg:
-		return rewriteValueARM_OpARMRSBSshiftLLreg(v, config)
+		return rewriteValueARM_OpARMRSBSshiftLLreg_0(v)
 	case OpARMRSBSshiftRA:
-		return rewriteValueARM_OpARMRSBSshiftRA(v, config)
+		return rewriteValueARM_OpARMRSBSshiftRA_0(v)
 	case OpARMRSBSshiftRAreg:
-		return rewriteValueARM_OpARMRSBSshiftRAreg(v, config)
+		return rewriteValueARM_OpARMRSBSshiftRAreg_0(v)
 	case OpARMRSBSshiftRL:
-		return rewriteValueARM_OpARMRSBSshiftRL(v, config)
+		return rewriteValueARM_OpARMRSBSshiftRL_0(v)
 	case OpARMRSBSshiftRLreg:
-		return rewriteValueARM_OpARMRSBSshiftRLreg(v, config)
+		return rewriteValueARM_OpARMRSBSshiftRLreg_0(v)
 	case OpARMRSBconst:
-		return rewriteValueARM_OpARMRSBconst(v, config)
+		return rewriteValueARM_OpARMRSBconst_0(v)
 	case OpARMRSBshiftLL:
-		return rewriteValueARM_OpARMRSBshiftLL(v, config)
+		return rewriteValueARM_OpARMRSBshiftLL_0(v)
 	case OpARMRSBshiftLLreg:
-		return rewriteValueARM_OpARMRSBshiftLLreg(v, config)
+		return rewriteValueARM_OpARMRSBshiftLLreg_0(v)
 	case OpARMRSBshiftRA:
-		return rewriteValueARM_OpARMRSBshiftRA(v, config)
+		return rewriteValueARM_OpARMRSBshiftRA_0(v)
 	case OpARMRSBshiftRAreg:
-		return rewriteValueARM_OpARMRSBshiftRAreg(v, config)
+		return rewriteValueARM_OpARMRSBshiftRAreg_0(v)
 	case OpARMRSBshiftRL:
-		return rewriteValueARM_OpARMRSBshiftRL(v, config)
+		return rewriteValueARM_OpARMRSBshiftRL_0(v)
 	case OpARMRSBshiftRLreg:
-		return rewriteValueARM_OpARMRSBshiftRLreg(v, config)
+		return rewriteValueARM_OpARMRSBshiftRLreg_0(v)
 	case OpARMRSCconst:
-		return rewriteValueARM_OpARMRSCconst(v, config)
+		return rewriteValueARM_OpARMRSCconst_0(v)
 	case OpARMRSCshiftLL:
-		return rewriteValueARM_OpARMRSCshiftLL(v, config)
+		return rewriteValueARM_OpARMRSCshiftLL_0(v)
 	case OpARMRSCshiftLLreg:
-		return rewriteValueARM_OpARMRSCshiftLLreg(v, config)
+		return rewriteValueARM_OpARMRSCshiftLLreg_0(v)
 	case OpARMRSCshiftRA:
-		return rewriteValueARM_OpARMRSCshiftRA(v, config)
+		return rewriteValueARM_OpARMRSCshiftRA_0(v)
 	case OpARMRSCshiftRAreg:
-		return rewriteValueARM_OpARMRSCshiftRAreg(v, config)
+		return rewriteValueARM_OpARMRSCshiftRAreg_0(v)
 	case OpARMRSCshiftRL:
-		return rewriteValueARM_OpARMRSCshiftRL(v, config)
+		return rewriteValueARM_OpARMRSCshiftRL_0(v)
 	case OpARMRSCshiftRLreg:
-		return rewriteValueARM_OpARMRSCshiftRLreg(v, config)
+		return rewriteValueARM_OpARMRSCshiftRLreg_0(v)
 	case OpARMSBC:
-		return rewriteValueARM_OpARMSBC(v, config)
+		return rewriteValueARM_OpARMSBC_0(v) || rewriteValueARM_OpARMSBC_10(v)
 	case OpARMSBCconst:
-		return rewriteValueARM_OpARMSBCconst(v, config)
+		return rewriteValueARM_OpARMSBCconst_0(v)
 	case OpARMSBCshiftLL:
-		return rewriteValueARM_OpARMSBCshiftLL(v, config)
+		return rewriteValueARM_OpARMSBCshiftLL_0(v)
 	case OpARMSBCshiftLLreg:
-		return rewriteValueARM_OpARMSBCshiftLLreg(v, config)
+		return rewriteValueARM_OpARMSBCshiftLLreg_0(v)
 	case OpARMSBCshiftRA:
-		return rewriteValueARM_OpARMSBCshiftRA(v, config)
+		return rewriteValueARM_OpARMSBCshiftRA_0(v)
 	case OpARMSBCshiftRAreg:
-		return rewriteValueARM_OpARMSBCshiftRAreg(v, config)
+		return rewriteValueARM_OpARMSBCshiftRAreg_0(v)
 	case OpARMSBCshiftRL:
-		return rewriteValueARM_OpARMSBCshiftRL(v, config)
+		return rewriteValueARM_OpARMSBCshiftRL_0(v)
 	case OpARMSBCshiftRLreg:
-		return rewriteValueARM_OpARMSBCshiftRLreg(v, config)
+		return rewriteValueARM_OpARMSBCshiftRLreg_0(v)
 	case OpARMSLL:
-		return rewriteValueARM_OpARMSLL(v, config)
+		return rewriteValueARM_OpARMSLL_0(v)
 	case OpARMSLLconst:
-		return rewriteValueARM_OpARMSLLconst(v, config)
+		return rewriteValueARM_OpARMSLLconst_0(v)
 	case OpARMSRA:
-		return rewriteValueARM_OpARMSRA(v, config)
+		return rewriteValueARM_OpARMSRA_0(v)
 	case OpARMSRAcond:
-		return rewriteValueARM_OpARMSRAcond(v, config)
+		return rewriteValueARM_OpARMSRAcond_0(v)
 	case OpARMSRAconst:
-		return rewriteValueARM_OpARMSRAconst(v, config)
+		return rewriteValueARM_OpARMSRAconst_0(v)
 	case OpARMSRL:
-		return rewriteValueARM_OpARMSRL(v, config)
+		return rewriteValueARM_OpARMSRL_0(v)
 	case OpARMSRLconst:
-		return rewriteValueARM_OpARMSRLconst(v, config)
+		return rewriteValueARM_OpARMSRLconst_0(v)
 	case OpARMSUB:
-		return rewriteValueARM_OpARMSUB(v, config)
+		return rewriteValueARM_OpARMSUB_0(v) || rewriteValueARM_OpARMSUB_10(v)
 	case OpARMSUBS:
-		return rewriteValueARM_OpARMSUBS(v, config)
+		return rewriteValueARM_OpARMSUBS_0(v) || rewriteValueARM_OpARMSUBS_10(v)
 	case OpARMSUBSshiftLL:
-		return rewriteValueARM_OpARMSUBSshiftLL(v, config)
+		return rewriteValueARM_OpARMSUBSshiftLL_0(v)
 	case OpARMSUBSshiftLLreg:
-		return rewriteValueARM_OpARMSUBSshiftLLreg(v, config)
+		return rewriteValueARM_OpARMSUBSshiftLLreg_0(v)
 	case OpARMSUBSshiftRA:
-		return rewriteValueARM_OpARMSUBSshiftRA(v, config)
+		return rewriteValueARM_OpARMSUBSshiftRA_0(v)
 	case OpARMSUBSshiftRAreg:
-		return rewriteValueARM_OpARMSUBSshiftRAreg(v, config)
+		return rewriteValueARM_OpARMSUBSshiftRAreg_0(v)
 	case OpARMSUBSshiftRL:
-		return rewriteValueARM_OpARMSUBSshiftRL(v, config)
+		return rewriteValueARM_OpARMSUBSshiftRL_0(v)
 	case OpARMSUBSshiftRLreg:
-		return rewriteValueARM_OpARMSUBSshiftRLreg(v, config)
+		return rewriteValueARM_OpARMSUBSshiftRLreg_0(v)
 	case OpARMSUBconst:
-		return rewriteValueARM_OpARMSUBconst(v, config)
+		return rewriteValueARM_OpARMSUBconst_0(v)
 	case OpARMSUBshiftLL:
-		return rewriteValueARM_OpARMSUBshiftLL(v, config)
+		return rewriteValueARM_OpARMSUBshiftLL_0(v)
 	case OpARMSUBshiftLLreg:
-		return rewriteValueARM_OpARMSUBshiftLLreg(v, config)
+		return rewriteValueARM_OpARMSUBshiftLLreg_0(v)
 	case OpARMSUBshiftRA:
-		return rewriteValueARM_OpARMSUBshiftRA(v, config)
+		return rewriteValueARM_OpARMSUBshiftRA_0(v)
 	case OpARMSUBshiftRAreg:
-		return rewriteValueARM_OpARMSUBshiftRAreg(v, config)
+		return rewriteValueARM_OpARMSUBshiftRAreg_0(v)
 	case OpARMSUBshiftRL:
-		return rewriteValueARM_OpARMSUBshiftRL(v, config)
+		return rewriteValueARM_OpARMSUBshiftRL_0(v)
 	case OpARMSUBshiftRLreg:
-		return rewriteValueARM_OpARMSUBshiftRLreg(v, config)
+		return rewriteValueARM_OpARMSUBshiftRLreg_0(v)
 	case OpARMXOR:
-		return rewriteValueARM_OpARMXOR(v, config)
+		return rewriteValueARM_OpARMXOR_0(v) || rewriteValueARM_OpARMXOR_10(v)
 	case OpARMXORconst:
-		return rewriteValueARM_OpARMXORconst(v, config)
+		return rewriteValueARM_OpARMXORconst_0(v)
 	case OpARMXORshiftLL:
-		return rewriteValueARM_OpARMXORshiftLL(v, config)
+		return rewriteValueARM_OpARMXORshiftLL_0(v)
 	case OpARMXORshiftLLreg:
-		return rewriteValueARM_OpARMXORshiftLLreg(v, config)
+		return rewriteValueARM_OpARMXORshiftLLreg_0(v)
 	case OpARMXORshiftRA:
-		return rewriteValueARM_OpARMXORshiftRA(v, config)
+		return rewriteValueARM_OpARMXORshiftRA_0(v)
 	case OpARMXORshiftRAreg:
-		return rewriteValueARM_OpARMXORshiftRAreg(v, config)
+		return rewriteValueARM_OpARMXORshiftRAreg_0(v)
 	case OpARMXORshiftRL:
-		return rewriteValueARM_OpARMXORshiftRL(v, config)
+		return rewriteValueARM_OpARMXORshiftRL_0(v)
 	case OpARMXORshiftRLreg:
-		return rewriteValueARM_OpARMXORshiftRLreg(v, config)
+		return rewriteValueARM_OpARMXORshiftRLreg_0(v)
 	case OpARMXORshiftRR:
-		return rewriteValueARM_OpARMXORshiftRR(v, config)
+		return rewriteValueARM_OpARMXORshiftRR_0(v)
 	case OpAdd16:
-		return rewriteValueARM_OpAdd16(v, config)
+		return rewriteValueARM_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueARM_OpAdd32(v, config)
+		return rewriteValueARM_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueARM_OpAdd32F(v, config)
+		return rewriteValueARM_OpAdd32F_0(v)
 	case OpAdd32carry:
-		return rewriteValueARM_OpAdd32carry(v, config)
+		return rewriteValueARM_OpAdd32carry_0(v)
 	case OpAdd32withcarry:
-		return rewriteValueARM_OpAdd32withcarry(v, config)
+		return rewriteValueARM_OpAdd32withcarry_0(v)
 	case OpAdd64F:
-		return rewriteValueARM_OpAdd64F(v, config)
+		return rewriteValueARM_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueARM_OpAdd8(v, config)
+		return rewriteValueARM_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueARM_OpAddPtr(v, config)
+		return rewriteValueARM_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueARM_OpAddr(v, config)
+		return rewriteValueARM_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueARM_OpAnd16(v, config)
+		return rewriteValueARM_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueARM_OpAnd32(v, config)
+		return rewriteValueARM_OpAnd32_0(v)
 	case OpAnd8:
-		return rewriteValueARM_OpAnd8(v, config)
+		return rewriteValueARM_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueARM_OpAndB(v, config)
+		return rewriteValueARM_OpAndB_0(v)
+	case OpAvg32u:
+		return rewriteValueARM_OpAvg32u_0(v)
+	case OpBitLen32:
+		return rewriteValueARM_OpBitLen32_0(v)
 	case OpBswap32:
-		return rewriteValueARM_OpBswap32(v, config)
+		return rewriteValueARM_OpBswap32_0(v)
 	case OpClosureCall:
-		return rewriteValueARM_OpClosureCall(v, config)
+		return rewriteValueARM_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueARM_OpCom16(v, config)
+		return rewriteValueARM_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueARM_OpCom32(v, config)
+		return rewriteValueARM_OpCom32_0(v)
 	case OpCom8:
-		return rewriteValueARM_OpCom8(v, config)
+		return rewriteValueARM_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueARM_OpConst16(v, config)
+		return rewriteValueARM_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueARM_OpConst32(v, config)
+		return rewriteValueARM_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueARM_OpConst32F(v, config)
+		return rewriteValueARM_OpConst32F_0(v)
 	case OpConst64F:
-		return rewriteValueARM_OpConst64F(v, config)
+		return rewriteValueARM_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueARM_OpConst8(v, config)
+		return rewriteValueARM_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueARM_OpConstBool(v, config)
+		return rewriteValueARM_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueARM_OpConstNil(v, config)
+		return rewriteValueARM_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueARM_OpConvert(v, config)
+		return rewriteValueARM_OpConvert_0(v)
 	case OpCtz32:
-		return rewriteValueARM_OpCtz32(v, config)
+		return rewriteValueARM_OpCtz32_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueARM_OpCvt32Fto32(v, config)
+		return rewriteValueARM_OpCvt32Fto32_0(v)
 	case OpCvt32Fto32U:
-		return rewriteValueARM_OpCvt32Fto32U(v, config)
+		return rewriteValueARM_OpCvt32Fto32U_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueARM_OpCvt32Fto64F(v, config)
+		return rewriteValueARM_OpCvt32Fto64F_0(v)
 	case OpCvt32Uto32F:
-		return rewriteValueARM_OpCvt32Uto32F(v, config)
+		return rewriteValueARM_OpCvt32Uto32F_0(v)
 	case OpCvt32Uto64F:
-		return rewriteValueARM_OpCvt32Uto64F(v, config)
+		return rewriteValueARM_OpCvt32Uto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueARM_OpCvt32to32F(v, config)
+		return rewriteValueARM_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueARM_OpCvt32to64F(v, config)
+		return rewriteValueARM_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueARM_OpCvt64Fto32(v, config)
+		return rewriteValueARM_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueARM_OpCvt64Fto32F(v, config)
+		return rewriteValueARM_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto32U:
-		return rewriteValueARM_OpCvt64Fto32U(v, config)
-	case OpDeferCall:
-		return rewriteValueARM_OpDeferCall(v, config)
+		return rewriteValueARM_OpCvt64Fto32U_0(v)
 	case OpDiv16:
-		return rewriteValueARM_OpDiv16(v, config)
+		return rewriteValueARM_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueARM_OpDiv16u(v, config)
+		return rewriteValueARM_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueARM_OpDiv32(v, config)
+		return rewriteValueARM_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueARM_OpDiv32F(v, config)
+		return rewriteValueARM_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueARM_OpDiv32u(v, config)
+		return rewriteValueARM_OpDiv32u_0(v)
 	case OpDiv64F:
-		return rewriteValueARM_OpDiv64F(v, config)
+		return rewriteValueARM_OpDiv64F_0(v)
 	case OpDiv8:
-		return rewriteValueARM_OpDiv8(v, config)
+		return rewriteValueARM_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueARM_OpDiv8u(v, config)
+		return rewriteValueARM_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueARM_OpEq16(v, config)
+		return rewriteValueARM_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueARM_OpEq32(v, config)
+		return rewriteValueARM_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueARM_OpEq32F(v, config)
+		return rewriteValueARM_OpEq32F_0(v)
 	case OpEq64F:
-		return rewriteValueARM_OpEq64F(v, config)
+		return rewriteValueARM_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueARM_OpEq8(v, config)
+		return rewriteValueARM_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueARM_OpEqB(v, config)
+		return rewriteValueARM_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueARM_OpEqPtr(v, config)
+		return rewriteValueARM_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueARM_OpGeq16(v, config)
+		return rewriteValueARM_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueARM_OpGeq16U(v, config)
+		return rewriteValueARM_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueARM_OpGeq32(v, config)
+		return rewriteValueARM_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueARM_OpGeq32F(v, config)
+		return rewriteValueARM_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueARM_OpGeq32U(v, config)
+		return rewriteValueARM_OpGeq32U_0(v)
 	case OpGeq64F:
-		return rewriteValueARM_OpGeq64F(v, config)
+		return rewriteValueARM_OpGeq64F_0(v)
 	case OpGeq8:
-		return rewriteValueARM_OpGeq8(v, config)
+		return rewriteValueARM_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueARM_OpGeq8U(v, config)
+		return rewriteValueARM_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueARM_OpGetClosurePtr(v, config)
-	case OpGoCall:
-		return rewriteValueARM_OpGoCall(v, config)
+		return rewriteValueARM_OpGetClosurePtr_0(v)
 	case OpGreater16:
-		return rewriteValueARM_OpGreater16(v, config)
+		return rewriteValueARM_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueARM_OpGreater16U(v, config)
+		return rewriteValueARM_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueARM_OpGreater32(v, config)
+		return rewriteValueARM_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueARM_OpGreater32F(v, config)
+		return rewriteValueARM_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueARM_OpGreater32U(v, config)
+		return rewriteValueARM_OpGreater32U_0(v)
 	case OpGreater64F:
-		return rewriteValueARM_OpGreater64F(v, config)
+		return rewriteValueARM_OpGreater64F_0(v)
 	case OpGreater8:
-		return rewriteValueARM_OpGreater8(v, config)
+		return rewriteValueARM_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueARM_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueARM_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueARM_OpHmul16u(v, config)
+		return rewriteValueARM_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueARM_OpHmul32(v, config)
+		return rewriteValueARM_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueARM_OpHmul32u(v, config)
-	case OpHmul8:
-		return rewriteValueARM_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueARM_OpHmul8u(v, config)
+		return rewriteValueARM_OpHmul32u_0(v)
 	case OpInterCall:
-		return rewriteValueARM_OpInterCall(v, config)
+		return rewriteValueARM_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueARM_OpIsInBounds(v, config)
+		return rewriteValueARM_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueARM_OpIsNonNil(v, config)
+		return rewriteValueARM_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueARM_OpIsSliceInBounds(v, config)
+		return rewriteValueARM_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueARM_OpLeq16(v, config)
+		return rewriteValueARM_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueARM_OpLeq16U(v, config)
+		return rewriteValueARM_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueARM_OpLeq32(v, config)
+		return rewriteValueARM_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueARM_OpLeq32F(v, config)
+		return rewriteValueARM_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueARM_OpLeq32U(v, config)
+		return rewriteValueARM_OpLeq32U_0(v)
 	case OpLeq64F:
-		return rewriteValueARM_OpLeq64F(v, config)
+		return rewriteValueARM_OpLeq64F_0(v)
 	case OpLeq8:
-		return rewriteValueARM_OpLeq8(v, config)
+		return rewriteValueARM_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueARM_OpLeq8U(v, config)
+		return rewriteValueARM_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueARM_OpLess16(v, config)
+		return rewriteValueARM_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueARM_OpLess16U(v, config)
+		return rewriteValueARM_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueARM_OpLess32(v, config)
+		return rewriteValueARM_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueARM_OpLess32F(v, config)
+		return rewriteValueARM_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueARM_OpLess32U(v, config)
+		return rewriteValueARM_OpLess32U_0(v)
 	case OpLess64F:
-		return rewriteValueARM_OpLess64F(v, config)
+		return rewriteValueARM_OpLess64F_0(v)
 	case OpLess8:
-		return rewriteValueARM_OpLess8(v, config)
+		return rewriteValueARM_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueARM_OpLess8U(v, config)
+		return rewriteValueARM_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValueARM_OpLoad(v, config)
-	case OpLrot16:
-		return rewriteValueARM_OpLrot16(v, config)
-	case OpLrot32:
-		return rewriteValueARM_OpLrot32(v, config)
-	case OpLrot8:
-		return rewriteValueARM_OpLrot8(v, config)
+		return rewriteValueARM_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueARM_OpLsh16x16(v, config)
+		return rewriteValueARM_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueARM_OpLsh16x32(v, config)
+		return rewriteValueARM_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueARM_OpLsh16x64(v, config)
+		return rewriteValueARM_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueARM_OpLsh16x8(v, config)
+		return rewriteValueARM_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueARM_OpLsh32x16(v, config)
+		return rewriteValueARM_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueARM_OpLsh32x32(v, config)
+		return rewriteValueARM_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueARM_OpLsh32x64(v, config)
+		return rewriteValueARM_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueARM_OpLsh32x8(v, config)
+		return rewriteValueARM_OpLsh32x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueARM_OpLsh8x16(v, config)
+		return rewriteValueARM_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueARM_OpLsh8x32(v, config)
+		return rewriteValueARM_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueARM_OpLsh8x64(v, config)
+		return rewriteValueARM_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueARM_OpLsh8x8(v, config)
+		return rewriteValueARM_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValueARM_OpMod16(v, config)
+		return rewriteValueARM_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueARM_OpMod16u(v, config)
+		return rewriteValueARM_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueARM_OpMod32(v, config)
+		return rewriteValueARM_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueARM_OpMod32u(v, config)
+		return rewriteValueARM_OpMod32u_0(v)
 	case OpMod8:
-		return rewriteValueARM_OpMod8(v, config)
+		return rewriteValueARM_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueARM_OpMod8u(v, config)
+		return rewriteValueARM_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueARM_OpMove(v, config)
+		return rewriteValueARM_OpMove_0(v)
 	case OpMul16:
-		return rewriteValueARM_OpMul16(v, config)
+		return rewriteValueARM_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueARM_OpMul32(v, config)
+		return rewriteValueARM_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueARM_OpMul32F(v, config)
+		return rewriteValueARM_OpMul32F_0(v)
 	case OpMul32uhilo:
-		return rewriteValueARM_OpMul32uhilo(v, config)
+		return rewriteValueARM_OpMul32uhilo_0(v)
 	case OpMul64F:
-		return rewriteValueARM_OpMul64F(v, config)
+		return rewriteValueARM_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValueARM_OpMul8(v, config)
+		return rewriteValueARM_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueARM_OpNeg16(v, config)
+		return rewriteValueARM_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueARM_OpNeg32(v, config)
+		return rewriteValueARM_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueARM_OpNeg32F(v, config)
+		return rewriteValueARM_OpNeg32F_0(v)
 	case OpNeg64F:
-		return rewriteValueARM_OpNeg64F(v, config)
+		return rewriteValueARM_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueARM_OpNeg8(v, config)
+		return rewriteValueARM_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueARM_OpNeq16(v, config)
+		return rewriteValueARM_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueARM_OpNeq32(v, config)
+		return rewriteValueARM_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueARM_OpNeq32F(v, config)
+		return rewriteValueARM_OpNeq32F_0(v)
 	case OpNeq64F:
-		return rewriteValueARM_OpNeq64F(v, config)
+		return rewriteValueARM_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueARM_OpNeq8(v, config)
+		return rewriteValueARM_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueARM_OpNeqB(v, config)
+		return rewriteValueARM_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueARM_OpNeqPtr(v, config)
+		return rewriteValueARM_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueARM_OpNilCheck(v, config)
+		return rewriteValueARM_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueARM_OpNot(v, config)
+		return rewriteValueARM_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueARM_OpOffPtr(v, config)
+		return rewriteValueARM_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueARM_OpOr16(v, config)
+		return rewriteValueARM_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueARM_OpOr32(v, config)
+		return rewriteValueARM_OpOr32_0(v)
 	case OpOr8:
-		return rewriteValueARM_OpOr8(v, config)
+		return rewriteValueARM_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueARM_OpOrB(v, config)
+		return rewriteValueARM_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValueARM_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueARM_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueARM_OpRsh16Ux16(v, config)
+		return rewriteValueARM_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueARM_OpRsh16Ux32(v, config)
+		return rewriteValueARM_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueARM_OpRsh16Ux64(v, config)
+		return rewriteValueARM_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueARM_OpRsh16Ux8(v, config)
+		return rewriteValueARM_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueARM_OpRsh16x16(v, config)
+		return rewriteValueARM_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueARM_OpRsh16x32(v, config)
+		return rewriteValueARM_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueARM_OpRsh16x64(v, config)
+		return rewriteValueARM_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueARM_OpRsh16x8(v, config)
+		return rewriteValueARM_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueARM_OpRsh32Ux16(v, config)
+		return rewriteValueARM_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueARM_OpRsh32Ux32(v, config)
+		return rewriteValueARM_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueARM_OpRsh32Ux64(v, config)
+		return rewriteValueARM_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueARM_OpRsh32Ux8(v, config)
+		return rewriteValueARM_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueARM_OpRsh32x16(v, config)
+		return rewriteValueARM_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueARM_OpRsh32x32(v, config)
+		return rewriteValueARM_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueARM_OpRsh32x64(v, config)
+		return rewriteValueARM_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueARM_OpRsh32x8(v, config)
+		return rewriteValueARM_OpRsh32x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueARM_OpRsh8Ux16(v, config)
+		return rewriteValueARM_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueARM_OpRsh8Ux32(v, config)
+		return rewriteValueARM_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueARM_OpRsh8Ux64(v, config)
+		return rewriteValueARM_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueARM_OpRsh8Ux8(v, config)
+		return rewriteValueARM_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueARM_OpRsh8x16(v, config)
+		return rewriteValueARM_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueARM_OpRsh8x32(v, config)
+		return rewriteValueARM_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueARM_OpRsh8x64(v, config)
+		return rewriteValueARM_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueARM_OpRsh8x8(v, config)
+		return rewriteValueARM_OpRsh8x8_0(v)
 	case OpSelect0:
-		return rewriteValueARM_OpSelect0(v, config)
+		return rewriteValueARM_OpSelect0_0(v)
 	case OpSelect1:
-		return rewriteValueARM_OpSelect1(v, config)
+		return rewriteValueARM_OpSelect1_0(v)
 	case OpSignExt16to32:
-		return rewriteValueARM_OpSignExt16to32(v, config)
+		return rewriteValueARM_OpSignExt16to32_0(v)
 	case OpSignExt8to16:
-		return rewriteValueARM_OpSignExt8to16(v, config)
+		return rewriteValueARM_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueARM_OpSignExt8to32(v, config)
+		return rewriteValueARM_OpSignExt8to32_0(v)
 	case OpSignmask:
-		return rewriteValueARM_OpSignmask(v, config)
+		return rewriteValueARM_OpSignmask_0(v)
 	case OpSlicemask:
-		return rewriteValueARM_OpSlicemask(v, config)
+		return rewriteValueARM_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValueARM_OpSqrt(v, config)
+		return rewriteValueARM_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValueARM_OpStaticCall(v, config)
+		return rewriteValueARM_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueARM_OpStore(v, config)
+		return rewriteValueARM_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueARM_OpSub16(v, config)
+		return rewriteValueARM_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueARM_OpSub32(v, config)
+		return rewriteValueARM_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueARM_OpSub32F(v, config)
+		return rewriteValueARM_OpSub32F_0(v)
 	case OpSub32carry:
-		return rewriteValueARM_OpSub32carry(v, config)
+		return rewriteValueARM_OpSub32carry_0(v)
 	case OpSub32withcarry:
-		return rewriteValueARM_OpSub32withcarry(v, config)
+		return rewriteValueARM_OpSub32withcarry_0(v)
 	case OpSub64F:
-		return rewriteValueARM_OpSub64F(v, config)
+		return rewriteValueARM_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueARM_OpSub8(v, config)
+		return rewriteValueARM_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueARM_OpSubPtr(v, config)
+		return rewriteValueARM_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueARM_OpTrunc16to8(v, config)
+		return rewriteValueARM_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueARM_OpTrunc32to16(v, config)
+		return rewriteValueARM_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueARM_OpTrunc32to8(v, config)
+		return rewriteValueARM_OpTrunc32to8_0(v)
 	case OpXor16:
-		return rewriteValueARM_OpXor16(v, config)
+		return rewriteValueARM_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueARM_OpXor32(v, config)
+		return rewriteValueARM_OpXor32_0(v)
 	case OpXor8:
-		return rewriteValueARM_OpXor8(v, config)
+		return rewriteValueARM_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueARM_OpZero(v, config)
+		return rewriteValueARM_OpZero_0(v)
 	case OpZeroExt16to32:
-		return rewriteValueARM_OpZeroExt16to32(v, config)
+		return rewriteValueARM_OpZeroExt16to32_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueARM_OpZeroExt8to16(v, config)
+		return rewriteValueARM_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueARM_OpZeroExt8to32(v, config)
+		return rewriteValueARM_OpZeroExt8to32_0(v)
 	case OpZeromask:
-		return rewriteValueARM_OpZeromask(v, config)
+		return rewriteValueARM_OpZeromask_0(v)
 	}
 	return false
 }
-func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMADC_0(v *Value) bool {
 	// match: (ADC (MOVWconst [c]) x flags)
 	// cond:
 	// result: (ADCconst [c] x flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -757,6 +753,25 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCconst [c] x flags)
 	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_1.AuxInt
+		flags := v.Args[2]
+		v.reset(OpARMADCconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADC x (MOVWconst [c]) flags)
+	// cond:
+	// result: (ADCconst [c] x flags)
+	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -770,10 +785,29 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC (MOVWconst [c]) x flags)
+	// cond:
+	// result: (ADCconst [c] x flags)
+	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(flags)
+		return true
+	}
 	// match: (ADC x (SLLconst [c] y) flags)
 	// cond:
 	// result: (ADCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -793,6 +827,27 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSLLconst {
+			break
+		}
+		c := v_0.AuxInt
+		y := v_0.Args[0]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftLL)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADC (SLLconst [c] y) x flags)
+	// cond:
+	// result: (ADCshiftLL x y [c] flags)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -808,10 +863,31 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC x (SLLconst [c] y) flags)
+	// cond:
+	// result: (ADCshiftLL x y [c] flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSLLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftLL)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
 	// match: (ADC x (SRLconst [c] y) flags)
 	// cond:
 	// result: (ADCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -831,6 +907,30 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRLconst {
+			break
+		}
+		c := v_0.AuxInt
+		y := v_0.Args[0]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRL)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMADC_10(v *Value) bool {
+	// match: (ADC (SRLconst [c] y) x flags)
+	// cond:
+	// result: (ADCshiftRL x y [c] flags)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -846,10 +946,31 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC x (SRLconst [c] y) flags)
+	// cond:
+	// result: (ADCshiftRL x y [c] flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSRLconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRL)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
 	// match: (ADC x (SRAconst [c] y) flags)
 	// cond:
 	// result: (ADCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -869,6 +990,27 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRAconst {
+			break
+		}
+		c := v_0.AuxInt
+		y := v_0.Args[0]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRA)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADC (SRAconst [c] y) x flags)
+	// cond:
+	// result: (ADCshiftRA x y [c] flags)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -884,15 +1026,37 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC x (SRAconst [c] y) flags)
+	// cond:
+	// result: (ADCshiftRA x y [c] flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSRAconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRA)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(flags)
+		return true
+	}
 	// match: (ADC x (SLL y z) flags)
 	// cond:
 	// result: (ADCshiftLLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -907,10 +1071,33 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftLLreg x y z flags)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSLL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftLLreg)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADC (SLL y z) x flags)
+	// cond:
+	// result: (ADCshiftLLreg x y z flags)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -922,15 +1109,41 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC x (SLL y z) flags)
+	// cond:
+	// result: (ADCshiftLLreg x y z flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSLL {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftLLreg)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		v.AddArg(flags)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMADC_20(v *Value) bool {
 	// match: (ADC x (SRL y z) flags)
 	// cond:
 	// result: (ADCshiftRLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -945,10 +1158,33 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRLreg x y z flags)
 	for {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRLreg)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADC (SRL y z) x flags)
+	// cond:
+	// result: (ADCshiftRLreg x y z flags)
+	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -960,15 +1196,38 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	// match: (ADC x (SRL y z) flags)
+	// cond:
+	// result: (ADCshiftRLreg x y z flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSRL {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRLreg)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		v.AddArg(flags)
+		return true
+	}
 	// match: (ADC x (SRA y z) flags)
 	// cond:
 	// result: (ADCshiftRAreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -983,10 +1242,12 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRAreg x y z flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -998,34 +1259,76 @@ func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
-	return false
-}
-func rewriteValueARM_OpARMADCconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADCconst [c] (ADDconst [d] x) flags)
+	// match: (ADC (SRA y z) x flags)
 	// cond:
-	// result: (ADCconst [int64(int32(c+d))] x flags)
+	// result: (ADCshiftRAreg x y z flags)
 	for {
-		c := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMADDconst {
+		if v_0.Op != OpARMSRA {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		flags := v.Args[1]
-		v.reset(OpARMADCconst)
-		v.AuxInt = int64(int32(c + d))
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRAreg)
 		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
 		v.AddArg(flags)
 		return true
 	}
-	// match: (ADCconst [c] (SUBconst [d] x) flags)
+	// match: (ADC x (SRA y z) flags)
+	// cond:
+	// result: (ADCshiftRAreg x y z flags)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMSRA {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		flags := v.Args[2]
+		v.reset(OpARMADCshiftRAreg)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		v.AddArg(flags)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMADCconst_0(v *Value) bool {
+	// match: (ADCconst [c] (ADDconst [d] x) flags)
+	// cond:
+	// result: (ADCconst [int64(int32(c+d))] x flags)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		flags := v.Args[1]
+		v.reset(OpARMADCconst)
+		v.AuxInt = int64(int32(c + d))
+		v.AddArg(x)
+		v.AddArg(flags)
+		return true
+	}
+	// match: (ADCconst [c] (SUBconst [d] x) flags)
 	// cond:
 	// result: (ADCconst [int64(int32(c-d))] x flags)
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSUBconst {
 			break
@@ -1041,7 +1344,7 @@ func rewriteValueARM_OpARMADCconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftLL (MOVWconst [c]) x [d] flags)
@@ -1049,6 +1352,7 @@ func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
 	// result: (ADCconst [c] (SLLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1058,7 +1362,7 @@ func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1070,6 +1374,7 @@ func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
 	// result: (ADCconst x [int64(uint32(c)<<uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -1085,13 +1390,14 @@ func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftLLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (ADCconst [c] (SLL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1102,7 +1408,7 @@ func rewriteValueARM_OpARMADCshiftLLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -1113,6 +1419,7 @@ func rewriteValueARM_OpARMADCshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -1130,7 +1437,7 @@ func rewriteValueARM_OpARMADCshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftRA (MOVWconst [c]) x [d] flags)
@@ -1138,6 +1445,7 @@ func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
 	// result: (ADCconst [c] (SRAconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1147,7 +1455,7 @@ func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1159,6 +1467,7 @@ func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
 	// result: (ADCconst x [int64(int32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -1174,13 +1483,14 @@ func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftRAreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (ADCconst [c] (SRA <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1191,7 +1501,7 @@ func rewriteValueARM_OpARMADCshiftRAreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -1202,6 +1512,7 @@ func rewriteValueARM_OpARMADCshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -1219,7 +1530,7 @@ func rewriteValueARM_OpARMADCshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftRL (MOVWconst [c]) x [d] flags)
@@ -1227,6 +1538,7 @@ func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
 	// result: (ADCconst [c] (SRLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1236,7 +1548,7 @@ func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1248,6 +1560,7 @@ func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
 	// result: (ADCconst x [int64(uint32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -1263,13 +1576,14 @@ func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADCshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADCshiftRLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (ADCconst [c] (SRL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1280,7 +1594,7 @@ func rewriteValueARM_OpARMADCshiftRLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMADCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -1291,6 +1605,7 @@ func rewriteValueARM_OpARMADCshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -1308,34 +1623,34 @@ func rewriteValueARM_OpARMADCshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADD (MOVWconst [c]) x)
+func rewriteValueARM_OpARMADD_0(v *Value) bool {
+	// match: (ADD x (MOVWconst [c]))
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADD x (MOVWconst [c]))
+	// match: (ADD (MOVWconst [c]) x)
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -1345,6 +1660,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -1362,6 +1678,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -1379,6 +1696,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -1396,6 +1714,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -1413,6 +1732,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -1430,6 +1750,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -1447,11 +1768,13 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDshiftLLreg)
@@ -1464,10 +1787,12 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1477,15 +1802,22 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMADD_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (ADD x (SRL y z))
 	// cond:
 	// result: (ADDshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDshiftRLreg)
@@ -1498,10 +1830,12 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1515,11 +1849,13 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDshiftRAreg)
@@ -1532,10 +1868,12 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1549,6 +1887,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMRSBconst {
@@ -1567,6 +1906,7 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMRSBconst {
 			break
@@ -1581,14 +1921,68 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADD <t> (RSBconst [c] x) (RSBconst [d] y))
+	// cond:
+	// result: (RSBconst [c+d] (ADD <t> x y))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMRSBconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMRSBconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		v.reset(OpARMRSBconst)
+		v.AuxInt = c + d
+		v0 := b.NewValue0(v.Pos, OpARMADD, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (ADD <t> (RSBconst [d] y) (RSBconst [c] x))
+	// cond:
+	// result: (RSBconst [c+d] (ADD <t> x y))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMRSBconst {
+			break
+		}
+		d := v_0.AuxInt
+		y := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMRSBconst {
+			break
+		}
+		c := v_1.AuxInt
+		x := v_1.Args[0]
+		v.reset(OpARMRSBconst)
+		v.AuxInt = c + d
+		v0 := b.NewValue0(v.Pos, OpARMADD, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
 	// match: (ADD (MUL x y) a)
 	// cond:
 	// result: (MULA x y a)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMUL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		a := v.Args[1]
@@ -1602,11 +1996,13 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (MULA x y a)
 	for {
+		_ = v.Args[1]
 		a := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMUL {
 			break
 		}
+		_ = v_1.Args[1]
 		x := v_1.Args[0]
 		y := v_1.Args[1]
 		v.reset(OpARMMULA)
@@ -1617,34 +2013,34 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADDS (MOVWconst [c]) x)
+func rewriteValueARM_OpARMADDS_0(v *Value) bool {
+	// match: (ADDS x (MOVWconst [c]))
 	// cond:
 	// result: (ADDSconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADDS x (MOVWconst [c]))
+	// match: (ADDS (MOVWconst [c]) x)
 	// cond:
 	// result: (ADDSconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -1654,6 +2050,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -1671,6 +2068,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -1688,6 +2086,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -1705,6 +2104,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -1722,6 +2122,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -1739,6 +2140,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -1756,11 +2158,13 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDSshiftLLreg)
@@ -1773,10 +2177,12 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1786,15 +2192,20 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMADDS_10(v *Value) bool {
 	// match: (ADDS x (SRL y z))
 	// cond:
 	// result: (ADDSshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDSshiftRLreg)
@@ -1807,10 +2218,12 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1824,11 +2237,13 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMADDSshiftRAreg)
@@ -1841,10 +2256,12 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -1856,7 +2273,7 @@ func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftLL (MOVWconst [c]) x [d])
@@ -1864,6 +2281,7 @@ func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
 	// result: (ADDSconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1872,7 +2290,7 @@ func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1883,6 +2301,7 @@ func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
 	// result: (ADDSconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -1896,13 +2315,14 @@ func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDSconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1912,7 +2332,7 @@ func rewriteValueARM_OpARMADDSshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -1922,6 +2342,7 @@ func rewriteValueARM_OpARMADDSshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -1937,7 +2358,7 @@ func rewriteValueARM_OpARMADDSshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftRA (MOVWconst [c]) x [d])
@@ -1945,6 +2366,7 @@ func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
 	// result: (ADDSconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1953,7 +2375,7 @@ func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1964,6 +2386,7 @@ func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
 	// result: (ADDSconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -1977,13 +2400,14 @@ func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDSconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -1993,7 +2417,7 @@ func rewriteValueARM_OpARMADDSshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2003,6 +2427,7 @@ func rewriteValueARM_OpARMADDSshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2018,7 +2443,7 @@ func rewriteValueARM_OpARMADDSshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftRL (MOVWconst [c]) x [d])
@@ -2026,6 +2451,7 @@ func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
 	// result: (ADDSconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2034,7 +2460,7 @@ func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2045,6 +2471,7 @@ func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
 	// result: (ADDSconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -2058,13 +2485,14 @@ func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDSshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDSshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDSshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDSconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2074,7 +2502,7 @@ func rewriteValueARM_OpARMADDSshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2084,6 +2512,7 @@ func rewriteValueARM_OpARMADDSshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDSshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2099,9 +2528,7 @@ func rewriteValueARM_OpARMADDSshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMADDconst_0(v *Value) bool {
 	// match: (ADDconst [off1] (MOVWaddr [off2] {sym} ptr))
 	// cond:
 	// result: (MOVWaddr [off1+off2] {sym} ptr)
@@ -2133,6 +2560,20 @@ func rewriteValueARM_OpARMADDconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDconst [c] x)
+	// cond: !isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c))
+	// result: (SUBconst [int64(int32(-c))] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(!isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c))) {
+			break
+		}
+		v.reset(OpARMSUBconst)
+		v.AuxInt = int64(int32(-c))
+		v.AddArg(x)
+		return true
+	}
 	// match: (ADDconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(c+d))])
@@ -2197,7 +2638,7 @@ func rewriteValueARM_OpARMADDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftLL (MOVWconst [c]) x [d])
@@ -2205,6 +2646,7 @@ func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2213,7 +2655,7 @@ func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2224,6 +2666,7 @@ func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -2235,15 +2678,38 @@ func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDshiftLL [c] (SRLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [32-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2253,7 +2719,7 @@ func rewriteValueARM_OpARMADDshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2263,6 +2729,7 @@ func rewriteValueARM_OpARMADDshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2278,7 +2745,7 @@ func rewriteValueARM_OpARMADDshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRA (MOVWconst [c]) x [d])
@@ -2286,6 +2753,7 @@ func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2294,7 +2762,7 @@ func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2305,6 +2773,7 @@ func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -2318,13 +2787,14 @@ func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2334,7 +2804,7 @@ func rewriteValueARM_OpARMADDshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2344,6 +2814,7 @@ func rewriteValueARM_OpARMADDshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2359,7 +2830,7 @@ func rewriteValueARM_OpARMADDshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRL (MOVWconst [c]) x [d])
@@ -2367,6 +2838,7 @@ func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2375,7 +2847,7 @@ func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2386,6 +2858,7 @@ func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -2397,15 +2870,38 @@ func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDshiftRL [c] (SLLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [   c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM_OpARMADDshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADDshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ADDconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2415,7 +2911,7 @@ func rewriteValueARM_OpARMADDshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2425,6 +2921,7 @@ func rewriteValueARM_OpARMADDshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2440,34 +2937,34 @@ func rewriteValueARM_OpARMADDshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AND (MOVWconst [c]) x)
+func rewriteValueARM_OpARMAND_0(v *Value) bool {
+	// match: (AND x (MOVWconst [c]))
 	// cond:
 	// result: (ANDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVWconst [c]))
+	// match: (AND (MOVWconst [c]) x)
 	// cond:
 	// result: (ANDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -2477,6 +2974,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -2494,6 +2992,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -2511,6 +3010,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -2528,6 +3028,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -2545,6 +3046,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -2562,6 +3064,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -2579,11 +3082,13 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMANDshiftLLreg)
@@ -2596,10 +3101,12 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -2609,15 +3116,20 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMAND_10(v *Value) bool {
 	// match: (AND x (SRL y z))
 	// cond:
 	// result: (ANDshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMANDshiftRLreg)
@@ -2630,10 +3142,12 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -2647,11 +3161,13 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMANDshiftRAreg)
@@ -2664,10 +3180,12 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -2681,6 +3199,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -2694,6 +3213,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BIC x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMVN {
@@ -2709,6 +3229,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BIC x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMVN {
 			break
@@ -2724,6 +3245,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMVNshiftLL {
@@ -2741,6 +3263,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMVNshiftLL {
 			break
@@ -2758,6 +3281,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMVNshiftRL {
@@ -2771,10 +3295,14 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMAND_20(v *Value) bool {
 	// match: (AND (MVNshiftRL y [c]) x)
 	// cond:
 	// result: (BICshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMVNshiftRL {
 			break
@@ -2792,6 +3320,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMVNshiftRA {
@@ -2809,6 +3338,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMVNshiftRA {
 			break
@@ -2824,9 +3354,7 @@ func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMANDconst_0(v *Value) bool {
 	// match: (ANDconst [0] _)
 	// cond:
 	// result: (MOVWconst [0])
@@ -2852,6 +3380,20 @@ func rewriteValueARM_OpARMANDconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ANDconst [c] x)
+	// cond: !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c))
+	// result: (BICconst [int64(^uint32(c))] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(!isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c))) {
+			break
+		}
+		v.reset(OpARMBICconst)
+		v.AuxInt = int64(^uint32(c))
+		v.AddArg(x)
+		return true
+	}
 	// match: (ANDconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [c&d])
@@ -2884,7 +3426,7 @@ func rewriteValueARM_OpARMANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftLL (MOVWconst [c]) x [d])
@@ -2892,6 +3434,7 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2900,7 +3443,7 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -2911,6 +3454,7 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -2927,6 +3471,7 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSLLconst {
@@ -2946,13 +3491,14 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ANDconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -2962,7 +3508,7 @@ func rewriteValueARM_OpARMANDshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -2972,6 +3518,7 @@ func rewriteValueARM_OpARMANDshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -2987,7 +3534,7 @@ func rewriteValueARM_OpARMANDshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRA (MOVWconst [c]) x [d])
@@ -2995,6 +3542,7 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -3003,7 +3551,7 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -3014,6 +3562,7 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3030,6 +3579,7 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSRAconst {
@@ -3049,13 +3599,14 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ANDconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -3065,7 +3616,7 @@ func rewriteValueARM_OpARMANDshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -3075,6 +3626,7 @@ func rewriteValueARM_OpARMANDshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -3090,7 +3642,7 @@ func rewriteValueARM_OpARMANDshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRL (MOVWconst [c]) x [d])
@@ -3098,6 +3650,7 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -3106,7 +3659,7 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -3117,6 +3670,7 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3133,6 +3687,7 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSRLconst {
@@ -3152,13 +3707,14 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMANDshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMANDshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ANDconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -3168,7 +3724,7 @@ func rewriteValueARM_OpARMANDshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -3178,6 +3734,7 @@ func rewriteValueARM_OpARMANDshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -3193,13 +3750,12 @@ func rewriteValueARM_OpARMANDshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBIC_0(v *Value) bool {
 	// match: (BIC x (MOVWconst [c]))
 	// cond:
 	// result: (BICconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3215,6 +3771,7 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -3232,6 +3789,7 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -3249,6 +3807,7 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -3266,11 +3825,13 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMBICshiftLLreg)
@@ -3283,11 +3844,13 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMBICshiftRLreg)
@@ -3300,11 +3863,13 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMBICshiftRAreg)
@@ -3317,6 +3882,7 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -3327,9 +3893,7 @@ func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICconst_0(v *Value) bool {
 	// match: (BICconst [0] x)
 	// cond:
 	// result: x
@@ -3355,6 +3919,20 @@ func rewriteValueARM_OpARMBICconst(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (BICconst [c] x)
+	// cond: !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c))
+	// result: (ANDconst [int64(^uint32(c))] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(!isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c))) {
+			break
+		}
+		v.reset(OpARMANDconst)
+		v.AuxInt = int64(^uint32(c))
+		v.AddArg(x)
+		return true
+	}
 	// match: (BICconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [d&^c])
@@ -3369,16 +3947,31 @@ func rewriteValueARM_OpARMBICconst(v *Value, config *Config) bool {
 		v.AuxInt = d &^ c
 		return true
 	}
+	// match: (BICconst [c] (BICconst [d] x))
+	// cond:
+	// result: (BICconst [int64(int32(c|d))] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMBICconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpARMBICconst)
+		v.AuxInt = int64(int32(c | d))
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftLL_0(v *Value) bool {
 	// match: (BICshiftLL x (MOVWconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3395,6 +3988,7 @@ func rewriteValueARM_OpARMBICshiftLL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -3413,13 +4007,12 @@ func rewriteValueARM_OpARMBICshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftLLreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftLLreg_0(v *Value) bool {
 	// match: (BICshiftLLreg x y (MOVWconst [c]))
 	// cond:
 	// result: (BICshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -3435,14 +4028,13 @@ func rewriteValueARM_OpARMBICshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftRA_0(v *Value) bool {
 	// match: (BICshiftRA x (MOVWconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3459,6 +4051,7 @@ func rewriteValueARM_OpARMBICshiftRA(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -3477,13 +4070,12 @@ func rewriteValueARM_OpARMBICshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftRAreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftRAreg_0(v *Value) bool {
 	// match: (BICshiftRAreg x y (MOVWconst [c]))
 	// cond:
 	// result: (BICshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -3499,14 +4091,13 @@ func rewriteValueARM_OpARMBICshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftRL_0(v *Value) bool {
 	// match: (BICshiftRL x (MOVWconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3523,6 +4114,7 @@ func rewriteValueARM_OpARMBICshiftRL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -3541,13 +4133,12 @@ func rewriteValueARM_OpARMBICshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMBICshiftRLreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMBICshiftRLreg_0(v *Value) bool {
 	// match: (BICshiftRLreg x y (MOVWconst [c]))
 	// cond:
 	// result: (BICshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -3563,14 +4154,13 @@ func rewriteValueARM_OpARMBICshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMCMOVWHSconst_0(v *Value) bool {
 	// match: (CMOVWHSconst _ (FlagEQ) [c])
 	// cond:
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagEQ {
 			break
@@ -3583,6 +4173,7 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagLT_ULT {
@@ -3598,6 +4189,7 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagLT_UGT {
 			break
@@ -3610,6 +4202,7 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagGT_ULT {
@@ -3625,6 +4218,7 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagGT_UGT {
 			break
@@ -3638,6 +4232,7 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	// result: (CMOVWLSconst x flags [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMInvertFlags {
@@ -3652,14 +4247,13 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMCMOVWLSconst_0(v *Value) bool {
 	// match: (CMOVWLSconst _ (FlagEQ) [c])
 	// cond:
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagEQ {
 			break
@@ -3673,6 +4267,7 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagLT_ULT {
 			break
@@ -3685,6 +4280,7 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagLT_UGT {
@@ -3700,6 +4296,7 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	// result: (MOVWconst [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagGT_ULT {
 			break
@@ -3712,6 +4309,7 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMFlagGT_UGT {
@@ -3727,6 +4325,7 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	// result: (CMOVWHSconst x flags [c])
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMInvertFlags {
@@ -3741,13 +4340,14 @@ func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMP_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMP x (MOVWconst [c]))
 	// cond:
 	// result: (CMPconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -3763,6 +4363,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPconst [c] x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -3770,7 +4371,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -3780,6 +4381,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -3797,6 +4399,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftLL x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -3805,7 +4408,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftLL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -3816,6 +4419,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -3833,6 +4437,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRL x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -3841,7 +4446,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftRL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -3852,6 +4457,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -3869,6 +4475,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRA x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -3877,7 +4484,7 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftRA, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -3888,11 +4495,13 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMCMPshiftLLreg)
@@ -3905,30 +4514,39 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftLLreg x y z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftLLreg, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v0.AddArg(z)
 		v.AddArg(v0)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMCMP_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (CMP x (SRL y z))
 	// cond:
 	// result: (CMPshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMCMPshiftRLreg)
@@ -3941,15 +4559,17 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRLreg x y z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftRLreg, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v0.AddArg(z)
@@ -3960,11 +4580,13 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMCMPshiftRAreg)
@@ -3977,15 +4599,17 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRAreg x y z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPshiftRAreg, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v0.AddArg(z)
@@ -3994,13 +4618,12 @@ func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMCMPD_0(v *Value) bool {
 	// match: (CMPD x (MOVDconst [0]))
 	// cond:
 	// result: (CMPD0 x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVDconst {
@@ -4015,13 +4638,12 @@ func rewriteValueARM_OpARMCMPD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPF(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMCMPF_0(v *Value) bool {
 	// match: (CMPF x (MOVFconst [0]))
 	// cond:
 	// result: (CMPF0 x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVFconst {
@@ -4036,9 +4658,7 @@ func rewriteValueARM_OpARMCMPF(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMCMPconst_0(v *Value) bool {
 	// match: (CMPconst (MOVWconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -4183,7 +4803,7 @@ func rewriteValueARM_OpARMCMPconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftLL (MOVWconst [c]) x [d])
@@ -4191,6 +4811,7 @@ func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4198,9 +4819,9 @@ func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -4212,6 +4833,7 @@ func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -4225,13 +4847,14 @@ func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (InvertFlags (CMPconst [c] (SLL <x.Type> x y)))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4240,9 +4863,9 @@ func rewriteValueARM_OpARMCMPshiftLLreg(v *Value, config *Config) bool {
 		x := v.Args[1]
 		y := v.Args[2]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -4253,6 +4876,7 @@ func rewriteValueARM_OpARMCMPshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -4268,7 +4892,7 @@ func rewriteValueARM_OpARMCMPshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRA (MOVWconst [c]) x [d])
@@ -4276,6 +4900,7 @@ func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4283,9 +4908,9 @@ func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -4297,6 +4922,7 @@ func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -4310,13 +4936,14 @@ func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (InvertFlags (CMPconst [c] (SRA <x.Type> x y)))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4325,9 +4952,9 @@ func rewriteValueARM_OpARMCMPshiftRAreg(v *Value, config *Config) bool {
 		x := v.Args[1]
 		y := v.Args[2]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -4338,6 +4965,7 @@ func rewriteValueARM_OpARMCMPshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -4353,7 +4981,7 @@ func rewriteValueARM_OpARMCMPshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRL (MOVWconst [c]) x [d])
@@ -4361,6 +4989,7 @@ func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4368,9 +4997,9 @@ func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -4382,6 +5011,7 @@ func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -4395,13 +5025,14 @@ func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMCMPshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMCMPshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (InvertFlags (CMPconst [c] (SRL <x.Type> x y)))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -4410,9 +5041,9 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value, config *Config) bool {
 		x := v.Args[1]
 		y := v.Args[2]
 		v.reset(OpARMInvertFlags)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -4423,6 +5054,7 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -4438,9 +5070,7 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMEqual_0(v *Value) bool {
 	// match: (Equal (FlagEQ))
 	// cond:
 	// result: (MOVWconst [1])
@@ -4516,9 +5146,7 @@ func rewriteValueARM_OpARMEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMGreaterEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMGreaterEqual_0(v *Value) bool {
 	// match: (GreaterEqual (FlagEQ))
 	// cond:
 	// result: (MOVWconst [1])
@@ -4594,9 +5222,7 @@ func rewriteValueARM_OpARMGreaterEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMGreaterEqualU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMGreaterEqualU_0(v *Value) bool {
 	// match: (GreaterEqualU (FlagEQ))
 	// cond:
 	// result: (MOVWconst [1])
@@ -4672,9 +5298,7 @@ func rewriteValueARM_OpARMGreaterEqualU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMGreaterThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMGreaterThan_0(v *Value) bool {
 	// match: (GreaterThan (FlagEQ))
 	// cond:
 	// result: (MOVWconst [0])
@@ -4750,9 +5374,7 @@ func rewriteValueARM_OpARMGreaterThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMGreaterThanU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMGreaterThanU_0(v *Value) bool {
 	// match: (GreaterThanU (FlagEQ))
 	// cond:
 	// result: (MOVWconst [0])
@@ -4828,9 +5450,7 @@ func rewriteValueARM_OpARMGreaterThanU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMLessEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMLessEqual_0(v *Value) bool {
 	// match: (LessEqual (FlagEQ))
 	// cond:
 	// result: (MOVWconst [1])
@@ -4906,9 +5526,7 @@ func rewriteValueARM_OpARMLessEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMLessEqualU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMLessEqualU_0(v *Value) bool {
 	// match: (LessEqualU (FlagEQ))
 	// cond:
 	// result: (MOVWconst [1])
@@ -4984,9 +5602,7 @@ func rewriteValueARM_OpARMLessEqualU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMLessThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMLessThan_0(v *Value) bool {
 	// match: (LessThan (FlagEQ))
 	// cond:
 	// result: (MOVWconst [0])
@@ -5062,9 +5678,7 @@ func rewriteValueARM_OpARMLessThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMLessThanU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMLessThanU_0(v *Value) bool {
 	// match: (LessThanU (FlagEQ))
 	// cond:
 	// result: (MOVWconst [0])
@@ -5140,15 +5754,14 @@ func rewriteValueARM_OpARMLessThanU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVBUload_0(v *Value) bool {
 	// match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVBUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5163,12 +5776,34 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBUload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVBUload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVBUload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5188,11 +5823,12 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBUreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVBstore {
@@ -5200,21 +5836,19 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpARMMOVBUreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVBUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVBUreg_0(v *Value) bool {
 	// match: (MOVBUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVWreg x)
@@ -5223,6 +5857,7 @@ func rewriteValueARM_OpARMMOVBUreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -5269,15 +5904,14 @@ func rewriteValueARM_OpARMMOVBUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVBload_0(v *Value) bool {
 	// match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVBload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5292,12 +5926,34 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVBload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVBload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5317,11 +5973,12 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVBstore {
@@ -5329,21 +5986,19 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpARMMOVBreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVBreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVBreg_0(v *Value) bool {
 	// match: (MOVBreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVWreg x)
@@ -5352,6 +6007,7 @@ func rewriteValueARM_OpARMMOVBreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -5401,15 +6057,14 @@ func rewriteValueARM_OpARMMOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVBstore_0(v *Value) bool {
 	// match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond:
 	// result: (MOVBstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5426,12 +6081,36 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBstore [off1] {sym} (SUBconst [off2] ptr) val mem)
+	// cond:
+	// result: (MOVBstore [off1-off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpARMMOVBstore)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5458,6 +6137,7 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVBreg {
@@ -5479,6 +6159,7 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVBUreg {
@@ -5500,6 +6181,7 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHreg {
@@ -5521,6 +6203,7 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHUreg {
@@ -5538,15 +6221,14 @@ func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVDload_0(v *Value) bool {
 	// match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5561,12 +6243,34 @@ func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVDload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVDload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVDload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5591,6 +6295,7 @@ func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVDstore {
@@ -5598,6 +6303,7 @@ func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -5610,15 +6316,14 @@ func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVDstore_0(v *Value) bool {
 	// match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond:
 	// result: (MOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5635,12 +6340,36 @@ func rewriteValueARM_OpARMMOVDstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVDstore [off1] {sym} (SUBconst [off2] ptr) val mem)
+	// cond:
+	// result: (MOVDstore [off1-off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpARMMOVDstore)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5663,15 +6392,14 @@ func rewriteValueARM_OpARMMOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVFload_0(v *Value) bool {
 	// match: (MOVFload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVFload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5686,12 +6414,34 @@ func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVFload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVFload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVFload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5716,6 +6466,7 @@ func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVFstore {
@@ -5723,6 +6474,7 @@ func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -5735,15 +6487,14 @@ func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVFstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVFstore_0(v *Value) bool {
 	// match: (MOVFstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond:
 	// result: (MOVFstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5760,12 +6511,36 @@ func rewriteValueARM_OpARMMOVFstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVFstore [off1] {sym} (SUBconst [off2] ptr) val mem)
+	// cond:
+	// result: (MOVFstore [off1-off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpARMMOVFstore)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5788,15 +6563,14 @@ func rewriteValueARM_OpARMMOVFstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVHUload_0(v *Value) bool {
 	// match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVHUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5811,12 +6585,34 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVHUload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVHUload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVHUload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5836,11 +6632,12 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVHUreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHstore {
@@ -5848,21 +6645,19 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpARMMOVHUreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVHUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVHUreg_0(v *Value) bool {
 	// match: (MOVHUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVWreg x)
@@ -5871,6 +6666,7 @@ func rewriteValueARM_OpARMMOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -5883,6 +6679,7 @@ func rewriteValueARM_OpARMMOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -5941,15 +6738,14 @@ func rewriteValueARM_OpARMMOVHUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVHload_0(v *Value) bool {
 	// match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVHload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -5964,12 +6760,34 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVHload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVHload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVHload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -5989,11 +6807,12 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVHreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHstore {
@@ -6001,21 +6820,19 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpARMMOVHreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVHreg_0(v *Value) bool {
 	// match: (MOVHreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVWreg x)
@@ -6024,6 +6841,7 @@ func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -6036,6 +6854,7 @@ func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -6048,6 +6867,7 @@ func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARMMOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARMMOVWreg)
 		v.AddArg(x)
 		return true
@@ -6121,15 +6941,14 @@ func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVHstore_0(v *Value) bool {
 	// match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond:
 	// result: (MOVHstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -6146,26 +6965,50 @@ func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2)
-	// result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+	// match: (MOVHstore [off1] {sym} (SUBconst [off2] ptr) val mem)
+	// cond:
+	// result: (MOVHstore [off1-off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
-		sym1 := v.Aux
+		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWaddr {
+		if v_0.Op != OpARMSUBconst {
 			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(OpARMMOVHstore)
-		v.AuxInt = off1 + off2
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem)
+	// cond: canMergeSym(sym1,sym2)
+	// result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWaddr {
+			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(OpARMMOVHstore)
+		v.AuxInt = off1 + off2
 		v.Aux = mergeSym(sym1, sym2)
 		v.AddArg(ptr)
 		v.AddArg(val)
@@ -6178,6 +7021,7 @@ func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHreg {
@@ -6199,6 +7043,7 @@ func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVHUreg {
@@ -6216,15 +7061,18 @@ func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMMOVWload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond:
 	// result: (MOVWload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -6239,12 +7087,34 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVWload [off1] {sym} (SUBconst [off2] ptr) mem)
+	// cond:
+	// result: (MOVWload [off1-off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		v.reset(OpARMMOVWload)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVWload [off1] {sym1} (MOVWaddr [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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -6269,6 +7139,7 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWstore {
@@ -6276,6 +7147,7 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -6294,10 +7166,12 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -6318,11 +7192,13 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftLL {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -6344,11 +7220,13 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftRL {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -6370,11 +7248,13 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftRA {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -6390,19 +7270,19 @@ func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWloadidx_0(v *Value) bool {
 	// match: (MOVWloadidx ptr idx (MOVWstoreidx ptr2 idx x _))
 	// cond: isSamePtr(ptr, ptr2)
 	// result: x
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARMMOVWstoreidx {
 			break
 		}
+		_ = v_2.Args[3]
 		ptr2 := v_2.Args[0]
 		if idx != v_2.Args[1] {
 			break
@@ -6420,6 +7300,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWload [c] ptr mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -6437,6 +7318,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWload [c] ptr mem)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -6454,6 +7336,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftLL ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -6473,6 +7356,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftLL ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -6492,6 +7376,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftRL ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -6511,6 +7396,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftRL ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -6530,6 +7416,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftRA ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -6549,6 +7436,7 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWloadshiftRA ptr idx [c] mem)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -6566,14 +7454,13 @@ func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWloadshiftLL_0(v *Value) bool {
 	// match: (MOVWloadshiftLL ptr idx [c] (MOVWstoreshiftLL ptr2 idx [d] x _))
 	// cond: c==d && isSamePtr(ptr, ptr2)
 	// result: x
 	for {
 		c := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
@@ -6581,6 +7468,7 @@ func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value, config *Config) bool {
 			break
 		}
 		d := v_2.AuxInt
+		_ = v_2.Args[3]
 		ptr2 := v_2.Args[0]
 		if idx != v_2.Args[1] {
 			break
@@ -6599,6 +7487,7 @@ func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value, config *Config) bool {
 	// result: (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -6614,14 +7503,13 @@ func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWloadshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWloadshiftRA_0(v *Value) bool {
 	// match: (MOVWloadshiftRA ptr idx [c] (MOVWstoreshiftRA ptr2 idx [d] x _))
 	// cond: c==d && isSamePtr(ptr, ptr2)
 	// result: x
 	for {
 		c := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
@@ -6629,6 +7517,7 @@ func rewriteValueARM_OpARMMOVWloadshiftRA(v *Value, config *Config) bool {
 			break
 		}
 		d := v_2.AuxInt
+		_ = v_2.Args[3]
 		ptr2 := v_2.Args[0]
 		if idx != v_2.Args[1] {
 			break
@@ -6647,6 +7536,7 @@ func rewriteValueARM_OpARMMOVWloadshiftRA(v *Value, config *Config) bool {
 	// result: (MOVWload [int64(int32(c)>>uint64(d))] ptr mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -6662,14 +7552,13 @@ func rewriteValueARM_OpARMMOVWloadshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWloadshiftRL_0(v *Value) bool {
 	// match: (MOVWloadshiftRL ptr idx [c] (MOVWstoreshiftRL ptr2 idx [d] x _))
 	// cond: c==d && isSamePtr(ptr, ptr2)
 	// result: x
 	for {
 		c := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		idx := v.Args[1]
 		v_2 := v.Args[2]
@@ -6677,6 +7566,7 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value, config *Config) bool {
 			break
 		}
 		d := v_2.AuxInt
+		_ = v_2.Args[3]
 		ptr2 := v_2.Args[0]
 		if idx != v_2.Args[1] {
 			break
@@ -6695,6 +7585,7 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value, config *Config) bool {
 	// result: (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -6710,9 +7601,7 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWreg_0(v *Value) bool {
 	// match: (MOVWreg x)
 	// cond: x.Uses == 1
 	// result: (MOVWnop x)
@@ -6740,15 +7629,18 @@ func rewriteValueARM_OpARMMOVWreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMMOVWstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond:
 	// result: (MOVWstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -6765,12 +7657,36 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVWstore [off1] {sym} (SUBconst [off2] ptr) val mem)
+	// cond:
+	// result: (MOVWstore [off1-off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSUBconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpARMMOVWstore)
+		v.AuxInt = off1 - off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVWstore [off1] {sym1} (MOVWaddr [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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWaddr {
 			break
@@ -6799,10 +7715,12 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -6825,11 +7743,13 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftLL {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -6853,11 +7773,13 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftRL {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -6881,11 +7803,13 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 			break
 		}
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDshiftRA {
 			break
 		}
 		c := v_0.AuxInt
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -6903,13 +7827,12 @@ func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWstoreidx_0(v *Value) bool {
 	// match: (MOVWstoreidx ptr (MOVWconst [c]) val mem)
 	// cond:
 	// result: (MOVWstore [c] ptr val mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -6929,6 +7852,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstore [c] ptr val mem)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -6948,6 +7872,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftLL ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -6969,6 +7894,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftLL ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -6990,6 +7916,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftRL ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -7011,6 +7938,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftRL ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -7032,6 +7960,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftRA ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -7053,6 +7982,7 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWstoreshiftRA ptr idx [c] val mem)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -7072,14 +8002,13 @@ func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWstoreshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWstoreshiftLL_0(v *Value) bool {
 	// match: (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem)
 	// cond:
 	// result: (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7097,14 +8026,13 @@ func rewriteValueARM_OpARMMOVWstoreshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWstoreshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWstoreshiftRA_0(v *Value) bool {
 	// match: (MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem)
 	// cond:
 	// result: (MOVWstore [int64(int32(c)>>uint64(d))] ptr val mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7122,14 +8050,13 @@ func rewriteValueARM_OpARMMOVWstoreshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMOVWstoreshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMOVWstoreshiftRL_0(v *Value) bool {
 	// match: (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem)
 	// cond:
 	// result: (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
 	for {
 		d := v.AuxInt
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7147,13 +8074,12 @@ func rewriteValueARM_OpARMMOVWstoreshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMUL_0(v *Value) bool {
 	// match: (MUL x (MOVWconst [c]))
 	// cond: int32(c) == -1
 	// result: (RSBconst [0] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7168,10 +8094,30 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVWconst [c]) x)
+	// cond: int32(c) == -1
+	// result: (RSBconst [0] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(int32(c) == -1) {
+			break
+		}
+		v.reset(OpARMRSBconst)
+		v.AuxInt = 0
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL _ (MOVWconst [0]))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
 			break
@@ -7183,10 +8129,27 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (MUL (MOVWconst [0]) _)
+	// cond:
+	// result: (MOVWconst [0])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpARMMOVWconst)
+		v.AuxInt = 0
+		return true
+	}
 	// match: (MUL x (MOVWconst [1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7200,10 +8163,29 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVWconst [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL x (MOVWconst [c]))
 	// cond: isPowerOfTwo(c)
 	// result: (SLLconst [log2(c)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7218,10 +8200,30 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVWconst [c]) x)
+	// cond: isPowerOfTwo(c)
+	// result: (SLLconst [log2(c)] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpARMSLLconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL x (MOVWconst [c]))
 	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
 	// result: (ADDshiftLL x x [log2(c-1)])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7237,10 +8239,36 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVWconst [c]) x)
+	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
+	// result: (ADDshiftLL x x [log2(c-1)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+			break
+		}
+		v.reset(OpARMADDshiftLL)
+		v.AuxInt = log2(c - 1)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMMUL_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (MUL x (MOVWconst [c]))
 	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
 	// result: (RSBshiftLL x x [log2(c+1)])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7256,260 +8284,181 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL x (MOVWconst [c]))
-	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
-	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+	// match: (MUL (MOVWconst [c]) x)
+	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
+	// result: (RSBshiftLL x x [log2(c+1)])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
 			break
 		}
-		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
-		v0.AuxInt = 1
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpARMRSBshiftLL)
+		v.AuxInt = log2(c + 1)
+		v.AddArg(x)
+		v.AddArg(x)
 		return true
 	}
 	// match: (MUL x (MOVWconst [c]))
-	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
-	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
-		v0.AuxInt = 2
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
+		v0.AuxInt = 1
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (MUL x (MOVWconst [c]))
-	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
-	// result: (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
+	// match: (MUL (MOVWconst [c]) x)
+	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
-		v0.AuxInt = 3
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
+		v0.AuxInt = 1
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (MUL x (MOVWconst [c]))
-	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
-	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
-		v0.AuxInt = 3
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
+		v0.AuxInt = 2
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (MUL (MOVWconst [c]) x)
-	// cond: int32(c) == -1
-	// result: (RSBconst [0] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(int32(c) == -1) {
-			break
-		}
-		v.reset(OpARMRSBconst)
-		v.AuxInt = 0
-		v.AddArg(x)
-		return true
-	}
-	// match: (MUL (MOVWconst [0]) _)
-	// cond:
-	// result: (MOVWconst [0])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		if v_0.AuxInt != 0 {
-			break
-		}
-		v.reset(OpARMMOVWconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (MUL (MOVWconst [1]) x)
-	// cond:
-	// result: x
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		if v_0.AuxInt != 1 {
-			break
-		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MUL (MOVWconst [c]) x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLLconst [log2(c)] x)
+	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(isPowerOfTwo(c)) {
+		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MUL (MOVWconst [c]) x)
-	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
-	// result: (ADDshiftLL x x [log2(c-1)])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
-			break
-		}
-		v.reset(OpARMADDshiftLL)
-		v.AuxInt = log2(c - 1)
-		v.AddArg(x)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MUL (MOVWconst [c]) x)
-	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
-	// result: (RSBshiftLL x x [log2(c+1)])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
-			break
-		}
-		v.reset(OpARMRSBshiftLL)
-		v.AuxInt = log2(c + 1)
-		v.AddArg(x)
-		v.AddArg(x)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
+		v0.AuxInt = 2
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (MUL (MOVWconst [c]) x)
-	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
-	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+	// match: (MUL x (MOVWconst [c]))
+	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+	// result: (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+		c := v_1.AuxInt
+		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
-		v0.AuxInt = 1
+		v.AuxInt = log2(c / 7)
+		v0 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
+		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (MUL (MOVWconst [c]) x)
-	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
-	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+	// result: (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
-		v0.AuxInt = 2
+		v.AuxInt = log2(c / 7)
+		v0 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
+		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (MUL (MOVWconst [c]) x)
-	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
-	// result: (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
+	// match: (MUL x (MOVWconst [c]))
+	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+		c := v_1.AuxInt
+		if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARMSLLconst)
-		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -7520,6 +8469,7 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
 	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7531,17 +8481,21 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSLLconst)
 		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMMUL_20(v *Value) bool {
 	// match: (MUL (MOVWconst [c]) (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(c*d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7556,15 +8510,35 @@ func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
 		v.AuxInt = int64(int32(c * d))
 		return true
 	}
+	// match: (MUL (MOVWconst [d]) (MOVWconst [c]))
+	// cond:
+	// result: (MOVWconst [int64(int32(c*d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpARMMOVWconst)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
 	return false
 }
-func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMMULA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MULA x (MOVWconst [c]) a)
 	// cond: int32(c) == -1
 	// result: (SUB a x)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7584,6 +8558,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond:
 	// result: a
 	for {
+		_ = v.Args[2]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
 			break
@@ -7601,6 +8576,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADD x a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7619,6 +8595,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c)] x) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7630,7 +8607,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c)
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7641,6 +8618,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
 	// result: (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7652,7 +8630,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v0.AuxInt = log2(c - 1)
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -7664,6 +8642,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
 	// result: (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7675,7 +8654,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
 		v0.AuxInt = log2(c + 1)
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -7687,6 +8666,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7698,9 +8678,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 3)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 1
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7713,6 +8693,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7724,9 +8705,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 5)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 2
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7739,6 +8720,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7750,9 +8732,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 7)
-		v1 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
 		v1.AuxInt = 3
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7765,6 +8747,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -7776,9 +8759,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 9)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 3
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7787,10 +8770,16 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 		v.AddArg(a)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMMULA_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (MULA (MOVWconst [c]) x a)
 	// cond: int32(c) == -1
 	// result: (SUB a x)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7810,6 +8799,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond:
 	// result: a
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7827,6 +8817,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADD x a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7845,6 +8836,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c)] x) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7856,7 +8848,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c)
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7867,6 +8859,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
 	// result: (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7878,7 +8871,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v0.AuxInt = log2(c - 1)
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -7890,6 +8883,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
 	// result: (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7901,7 +8895,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
 		v0.AuxInt = log2(c + 1)
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -7913,6 +8907,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7924,9 +8919,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 3)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 1
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7939,6 +8934,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7950,9 +8946,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 5)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 2
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7965,6 +8961,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -7976,9 +8973,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 7)
-		v1 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMRSBshiftLL, x.Type)
 		v1.AuxInt = 3
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -7991,6 +8988,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
 	// result: (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8002,9 +9000,9 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpARMADD)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = log2(c / 9)
-		v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARMADDshiftLL, x.Type)
 		v1.AuxInt = 3
 		v1.AddArg(x)
 		v1.AddArg(x)
@@ -8013,10 +9011,14 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 		v.AddArg(a)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMMULA_20(v *Value) bool {
 	// match: (MULA (MOVWconst [c]) (MOVWconst [d]) a)
 	// cond:
 	// result: (ADDconst [int64(int32(c*d))] a)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8035,9 +9037,7 @@ func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVN_0(v *Value) bool {
 	// match: (MVN (MOVWconst [c]))
 	// cond:
 	// result: (MOVWconst [^c])
@@ -8104,6 +9104,7 @@ func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpARMMVNshiftLLreg)
@@ -8119,6 +9120,7 @@ func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpARMMVNshiftRLreg)
@@ -8134,6 +9136,7 @@ func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpARMMVNshiftRAreg)
@@ -8143,9 +9146,7 @@ func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftLL_0(v *Value) bool {
 	// match: (MVNshiftLL (MOVWconst [c]) [d])
 	// cond:
 	// result: (MOVWconst [^int64(uint32(c)<<uint64(d))])
@@ -8162,13 +9163,12 @@ func rewriteValueARM_OpARMMVNshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftLLreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftLLreg_0(v *Value) bool {
 	// match: (MVNshiftLLreg x (MOVWconst [c]))
 	// cond:
 	// result: (MVNshiftLL x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8182,9 +9182,7 @@ func rewriteValueARM_OpARMMVNshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftRA_0(v *Value) bool {
 	// match: (MVNshiftRA (MOVWconst [c]) [d])
 	// cond:
 	// result: (MOVWconst [^int64(int32(c)>>uint64(d))])
@@ -8201,13 +9199,12 @@ func rewriteValueARM_OpARMMVNshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftRAreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftRAreg_0(v *Value) bool {
 	// match: (MVNshiftRAreg x (MOVWconst [c]))
 	// cond:
 	// result: (MVNshiftRA x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8221,9 +9218,7 @@ func rewriteValueARM_OpARMMVNshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftRL_0(v *Value) bool {
 	// match: (MVNshiftRL (MOVWconst [c]) [d])
 	// cond:
 	// result: (MOVWconst [^int64(uint32(c)>>uint64(d))])
@@ -8240,13 +9235,12 @@ func rewriteValueARM_OpARMMVNshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMMVNshiftRLreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMMVNshiftRLreg_0(v *Value) bool {
 	// match: (MVNshiftRLreg x (MOVWconst [c]))
 	// cond:
 	// result: (MVNshiftRL x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8260,9 +9254,7 @@ func rewriteValueARM_OpARMMVNshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMNotEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMNotEqual_0(v *Value) bool {
 	// match: (NotEqual (FlagEQ))
 	// cond:
 	// result: (MOVWconst [0])
@@ -8338,34 +9330,34 @@ func rewriteValueARM_OpARMNotEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (OR (MOVWconst [c]) x)
+func rewriteValueARM_OpARMOR_0(v *Value) bool {
+	// match: (OR x (MOVWconst [c]))
 	// cond:
 	// result: (ORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARMORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR x (MOVWconst [c]))
+	// match: (OR (MOVWconst [c]) x)
 	// cond:
 	// result: (ORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -8375,6 +9367,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -8392,6 +9385,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -8409,6 +9403,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -8426,6 +9421,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -8443,6 +9439,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -8460,6 +9457,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -8477,11 +9475,13 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMORshiftLLreg)
@@ -8494,10 +9494,12 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -8507,15 +9509,20 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMOR_10(v *Value) bool {
 	// match: (OR x (SRL y z))
 	// cond:
 	// result: (ORshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMORshiftRLreg)
@@ -8528,10 +9535,12 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -8545,11 +9554,13 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMORshiftRAreg)
@@ -8562,10 +9573,12 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -8579,6 +9592,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -8590,9 +9604,7 @@ func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMORconst_0(v *Value) bool {
 	// match: (ORconst [0] x)
 	// cond:
 	// result: x
@@ -8650,7 +9662,7 @@ func rewriteValueARM_OpARMORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftLL (MOVWconst [c]) x [d])
@@ -8658,6 +9670,7 @@ func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
 	// result: (ORconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8666,7 +9679,7 @@ func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8677,6 +9690,7 @@ func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
 	// result: (ORconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8688,11 +9702,34 @@ func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ORshiftLL [c] (SRLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [32-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ORshiftLL x y:(SLLconst x [c]) [d])
 	// cond: c==d
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSLLconst {
@@ -8712,13 +9749,14 @@ func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ORconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8728,7 +9766,7 @@ func rewriteValueARM_OpARMORshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -8738,6 +9776,7 @@ func rewriteValueARM_OpARMORshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -8753,7 +9792,7 @@ func rewriteValueARM_OpARMORshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftRA (MOVWconst [c]) x [d])
@@ -8761,6 +9800,7 @@ func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
 	// result: (ORconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8769,7 +9809,7 @@ func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8780,6 +9820,7 @@ func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
 	// result: (ORconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8796,6 +9837,7 @@ func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSRAconst {
@@ -8815,13 +9857,14 @@ func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ORconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8831,7 +9874,7 @@ func rewriteValueARM_OpARMORshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -8841,6 +9884,7 @@ func rewriteValueARM_OpARMORshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -8856,7 +9900,7 @@ func rewriteValueARM_OpARMORshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftRL (MOVWconst [c]) x [d])
@@ -8864,6 +9908,7 @@ func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
 	// result: (ORconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8872,7 +9917,7 @@ func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8883,6 +9928,7 @@ func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
 	// result: (ORconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8894,11 +9940,34 @@ func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ORshiftRL [c] (SLLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [   c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ORshiftRL x y:(SRLconst x [c]) [d])
 	// cond: c==d
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARMSRLconst {
@@ -8918,13 +9987,14 @@ func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMORshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMORshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ORshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (ORconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8934,7 +10004,7 @@ func rewriteValueARM_OpARMORshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -8944,6 +10014,7 @@ func rewriteValueARM_OpARMORshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (ORshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -8959,13 +10030,12 @@ func rewriteValueARM_OpARMORshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMRSB_0(v *Value) bool {
 	// match: (RSB (MOVWconst [c]) x)
 	// cond:
 	// result: (SUBconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -8981,6 +10051,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -8996,6 +10067,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -9013,6 +10085,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -9030,6 +10103,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -9047,6 +10121,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -9064,6 +10139,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -9081,6 +10157,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -9098,11 +10175,13 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMRSBshiftLLreg)
@@ -9115,10 +10194,12 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -9128,15 +10209,20 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMRSB_10(v *Value) bool {
 	// match: (RSB x (SRL y z))
 	// cond:
 	// result: (RSBshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMRSBshiftRLreg)
@@ -9149,10 +10235,12 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -9166,11 +10254,13 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMRSBshiftRAreg)
@@ -9183,10 +10273,12 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -9200,6 +10292,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -9210,7 +10303,7 @@ func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftLL (MOVWconst [c]) x [d])
@@ -9218,6 +10311,7 @@ func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
 	// result: (SUBSconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9226,7 +10320,7 @@ func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9237,6 +10331,7 @@ func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
 	// result: (RSBSconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9250,13 +10345,14 @@ func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBSconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9266,7 +10362,7 @@ func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9276,6 +10372,7 @@ func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9291,7 +10388,7 @@ func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftRA (MOVWconst [c]) x [d])
@@ -9299,6 +10396,7 @@ func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
 	// result: (SUBSconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9307,7 +10405,7 @@ func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9318,6 +10416,7 @@ func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
 	// result: (RSBSconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9331,13 +10430,14 @@ func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBSconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9347,7 +10447,7 @@ func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9357,6 +10457,7 @@ func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9372,7 +10473,7 @@ func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftRL (MOVWconst [c]) x [d])
@@ -9380,6 +10481,7 @@ func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
 	// result: (SUBSconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9388,7 +10490,7 @@ func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9399,6 +10501,7 @@ func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
 	// result: (RSBSconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9412,13 +10515,14 @@ func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBSshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBSshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBSconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9428,7 +10532,7 @@ func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9438,6 +10542,7 @@ func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9453,9 +10558,7 @@ func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMRSBconst_0(v *Value) bool {
 	// match: (RSBconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(c-d))])
@@ -9520,7 +10623,7 @@ func rewriteValueARM_OpARMRSBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftLL (MOVWconst [c]) x [d])
@@ -9528,6 +10631,7 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
 	// result: (SUBconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9536,7 +10640,7 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9547,6 +10651,7 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
 	// result: (RSBconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9563,6 +10668,7 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -9581,13 +10687,14 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9597,7 +10704,7 @@ func rewriteValueARM_OpARMRSBshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9607,6 +10714,7 @@ func rewriteValueARM_OpARMRSBshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9622,7 +10730,7 @@ func rewriteValueARM_OpARMRSBshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftRA (MOVWconst [c]) x [d])
@@ -9630,6 +10738,7 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
 	// result: (SUBconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9638,7 +10747,7 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9649,6 +10758,7 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
 	// result: (RSBconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9665,6 +10775,7 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -9683,13 +10794,14 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9699,7 +10811,7 @@ func rewriteValueARM_OpARMRSBshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9709,6 +10821,7 @@ func rewriteValueARM_OpARMRSBshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9724,7 +10837,7 @@ func rewriteValueARM_OpARMRSBshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftRL (MOVWconst [c]) x [d])
@@ -9732,6 +10845,7 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
 	// result: (SUBconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9740,7 +10854,7 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9751,6 +10865,7 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
 	// result: (RSBconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9767,6 +10882,7 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -9785,13 +10901,14 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSBshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSBshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSBshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (SUBconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9801,7 +10918,7 @@ func rewriteValueARM_OpARMRSBshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMSUBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9811,6 +10928,7 @@ func rewriteValueARM_OpARMRSBshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9826,14 +10944,13 @@ func rewriteValueARM_OpARMRSBshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMRSCconst_0(v *Value) bool {
 	// match: (RSCconst [c] (ADDconst [d] x) flags)
 	// cond:
 	// result: (RSCconst [int64(int32(c-d))] x flags)
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -9852,6 +10969,7 @@ func rewriteValueARM_OpARMRSCconst(v *Value, config *Config) bool {
 	// result: (RSCconst [int64(int32(c+d))] x flags)
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSUBconst {
 			break
@@ -9867,7 +10985,7 @@ func rewriteValueARM_OpARMRSCconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftLL (MOVWconst [c]) x [d] flags)
@@ -9875,6 +10993,7 @@ func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
 	// result: (SBCconst [c] (SLLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9884,7 +11003,7 @@ func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9896,6 +11015,7 @@ func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
 	// result: (RSCconst x [int64(uint32(c)<<uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -9911,13 +11031,14 @@ func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftLLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (SBCconst [c] (SLL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9928,7 +11049,7 @@ func rewriteValueARM_OpARMRSCshiftLLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -9939,6 +11060,7 @@ func rewriteValueARM_OpARMRSCshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -9956,7 +11078,7 @@ func rewriteValueARM_OpARMRSCshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftRA (MOVWconst [c]) x [d] flags)
@@ -9964,6 +11086,7 @@ func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
 	// result: (SBCconst [c] (SRAconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -9973,7 +11096,7 @@ func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -9985,6 +11108,7 @@ func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
 	// result: (RSCconst x [int64(int32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10000,13 +11124,14 @@ func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftRAreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (SBCconst [c] (SRA <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10017,7 +11142,7 @@ func rewriteValueARM_OpARMRSCshiftRAreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -10028,6 +11153,7 @@ func rewriteValueARM_OpARMRSCshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10045,7 +11171,7 @@ func rewriteValueARM_OpARMRSCshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftRL (MOVWconst [c]) x [d] flags)
@@ -10053,6 +11179,7 @@ func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
 	// result: (SBCconst [c] (SRLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10062,7 +11189,7 @@ func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -10074,6 +11201,7 @@ func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
 	// result: (RSCconst x [int64(uint32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10089,13 +11217,14 @@ func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMRSCshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMRSCshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (RSCshiftRLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (SBCconst [c] (SRL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10106,7 +11235,7 @@ func rewriteValueARM_OpARMRSCshiftRLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMSBCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -10117,6 +11246,7 @@ func rewriteValueARM_OpARMRSCshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10134,13 +11264,12 @@ func rewriteValueARM_OpARMRSCshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSBC_0(v *Value) bool {
 	// match: (SBC (MOVWconst [c]) x flags)
 	// cond:
 	// result: (RSCconst [c] x flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10158,6 +11287,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCconst [c] x flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10175,6 +11305,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -10194,6 +11325,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -10213,6 +11345,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -10232,6 +11365,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -10251,6 +11385,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -10270,6 +11405,7 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -10289,11 +11425,13 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftLLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -10308,10 +11446,12 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftLLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -10323,15 +11463,20 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 		v.AddArg(flags)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMSBC_10(v *Value) bool {
 	// match: (SBC x (SRL y z) flags)
 	// cond:
 	// result: (SBCshiftRLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -10346,10 +11491,12 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRLreg x y z flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -10365,11 +11512,13 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftRAreg x y z flags)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		flags := v.Args[2]
@@ -10384,10 +11533,12 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSCshiftRAreg x y z flags)
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -10401,14 +11552,13 @@ func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSBCconst_0(v *Value) bool {
 	// match: (SBCconst [c] (ADDconst [d] x) flags)
 	// cond:
 	// result: (SBCconst [int64(int32(c-d))] x flags)
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMADDconst {
 			break
@@ -10427,6 +11577,7 @@ func rewriteValueARM_OpARMSBCconst(v *Value, config *Config) bool {
 	// result: (SBCconst [int64(int32(c+d))] x flags)
 	for {
 		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSUBconst {
 			break
@@ -10442,7 +11593,7 @@ func rewriteValueARM_OpARMSBCconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftLL (MOVWconst [c]) x [d] flags)
@@ -10450,6 +11601,7 @@ func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
 	// result: (RSCconst [c] (SLLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10459,7 +11611,7 @@ func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -10471,6 +11623,7 @@ func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
 	// result: (SBCconst x [int64(uint32(c)<<uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10486,13 +11639,14 @@ func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftLLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (RSCconst [c] (SLL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10503,7 +11657,7 @@ func rewriteValueARM_OpARMSBCshiftLLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -10514,6 +11668,7 @@ func rewriteValueARM_OpARMSBCshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftLL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10531,7 +11686,7 @@ func rewriteValueARM_OpARMSBCshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftRA (MOVWconst [c]) x [d] flags)
@@ -10539,6 +11694,7 @@ func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
 	// result: (RSCconst [c] (SRAconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10548,7 +11704,7 @@ func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -10560,6 +11716,7 @@ func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
 	// result: (SBCconst x [int64(int32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10575,13 +11732,14 @@ func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftRAreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (RSCconst [c] (SRA <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10592,7 +11750,7 @@ func rewriteValueARM_OpARMSBCshiftRAreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -10603,6 +11761,7 @@ func rewriteValueARM_OpARMSBCshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftRA x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10620,7 +11779,7 @@ func rewriteValueARM_OpARMSBCshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftRL (MOVWconst [c]) x [d] flags)
@@ -10628,6 +11787,7 @@ func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
 	// result: (RSCconst [c] (SRLconst <x.Type> x [d]) flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10637,7 +11797,7 @@ func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
 		flags := v.Args[2]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -10649,6 +11809,7 @@ func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
 	// result: (SBCconst x [int64(uint32(c)>>uint64(d))] flags)
 	for {
 		d := v.AuxInt
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10664,13 +11825,14 @@ func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSBCshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSBCshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SBCshiftRLreg (MOVWconst [c]) x y flags)
 	// cond:
 	// result: (RSCconst [c] (SRL <x.Type> x y) flags)
 	for {
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10681,7 +11843,7 @@ func rewriteValueARM_OpARMSBCshiftRLreg(v *Value, config *Config) bool {
 		flags := v.Args[3]
 		v.reset(OpARMRSCconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -10692,6 +11854,7 @@ func rewriteValueARM_OpARMSBCshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SBCshiftRL x y [c] flags)
 	for {
+		_ = v.Args[3]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10709,13 +11872,12 @@ func rewriteValueARM_OpARMSBCshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSLL_0(v *Value) bool {
 	// match: (SLL x (MOVWconst [c]))
 	// cond:
 	// result: (SLLconst x [c&31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10729,9 +11891,7 @@ func rewriteValueARM_OpARMSLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSLLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSLLconst_0(v *Value) bool {
 	// match: (SLLconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(uint32(d)<<uint64(c))])
@@ -10748,13 +11908,12 @@ func rewriteValueARM_OpARMSLLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSRA_0(v *Value) bool {
 	// match: (SRA x (MOVWconst [c]))
 	// cond:
 	// result: (SRAconst x [c&31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10768,13 +11927,12 @@ func rewriteValueARM_OpARMSRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSRAcond_0(v *Value) bool {
 	// match: (SRAcond x _ (FlagEQ))
 	// cond:
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARMFlagEQ {
@@ -10789,6 +11947,7 @@ func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA x y)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10804,6 +11963,7 @@ func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARMFlagLT_UGT {
@@ -10818,6 +11978,7 @@ func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA x y)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -10833,6 +11994,7 @@ func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARMFlagGT_UGT {
@@ -10845,9 +12007,7 @@ func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSRAconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSRAconst_0(v *Value) bool {
 	// match: (SRAconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(d)>>uint64(c))])
@@ -10864,13 +12024,12 @@ func rewriteValueARM_OpARMSRAconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSRL_0(v *Value) bool {
 	// match: (SRL x (MOVWconst [c]))
 	// cond:
 	// result: (SRLconst x [c&31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10884,9 +12043,7 @@ func rewriteValueARM_OpARMSRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSRLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSRLconst_0(v *Value) bool {
 	// match: (SRLconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(uint32(d)>>uint64(c))])
@@ -10903,13 +12060,12 @@ func rewriteValueARM_OpARMSRLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSUB_0(v *Value) bool {
 	// match: (SUB (MOVWconst [c]) x)
 	// cond:
 	// result: (RSBconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -10925,6 +12081,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -10940,6 +12097,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -10957,6 +12115,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -10974,6 +12133,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -10991,6 +12151,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -11008,6 +12169,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -11025,6 +12187,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -11042,11 +12205,13 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBshiftLLreg)
@@ -11059,10 +12224,12 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11072,15 +12239,20 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMSUB_10(v *Value) bool {
 	// match: (SUB x (SRL y z))
 	// cond:
 	// result: (SUBshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBshiftRLreg)
@@ -11093,10 +12265,12 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11110,11 +12284,13 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBshiftRAreg)
@@ -11127,10 +12303,12 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11144,6 +12322,7 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -11154,28 +12333,12 @@ func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBS (MOVWconst [c]) x)
-	// cond:
-	// result: (RSBSconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpARMRSBSconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
+func rewriteValueARM_OpARMSUBS_0(v *Value) bool {
 	// match: (SUBS x (MOVWconst [c]))
 	// cond:
 	// result: (SUBSconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11191,6 +12354,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -11208,6 +12372,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -11225,6 +12390,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -11242,6 +12408,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -11259,6 +12426,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -11276,6 +12444,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -11293,11 +12462,13 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBSshiftLLreg)
@@ -11310,10 +12481,12 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11327,11 +12500,13 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBSshiftRLreg)
@@ -11340,14 +12515,19 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 		v.AddArg(z)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMSUBS_10(v *Value) bool {
 	// match: (SUBS (SRL y z) x)
 	// cond:
 	// result: (RSBSshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11361,11 +12541,13 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMSUBSshiftRAreg)
@@ -11378,10 +12560,12 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	// cond:
 	// result: (RSBSshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -11393,7 +12577,7 @@ func rewriteValueARM_OpARMSUBS(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftLL (MOVWconst [c]) x [d])
@@ -11401,6 +12585,7 @@ func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
 	// result: (RSBSconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11409,7 +12594,7 @@ func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11420,6 +12605,7 @@ func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
 	// result: (SUBSconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11433,13 +12619,14 @@ func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBSconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11449,7 +12636,7 @@ func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -11459,6 +12646,7 @@ func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -11474,7 +12662,7 @@ func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftRA (MOVWconst [c]) x [d])
@@ -11482,6 +12670,7 @@ func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
 	// result: (RSBSconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11490,7 +12679,7 @@ func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11501,6 +12690,7 @@ func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
 	// result: (SUBSconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11514,13 +12704,14 @@ func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBSconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11530,7 +12721,7 @@ func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -11540,6 +12731,7 @@ func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -11555,7 +12747,7 @@ func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftRL (MOVWconst [c]) x [d])
@@ -11563,6 +12755,7 @@ func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
 	// result: (RSBSconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11571,7 +12764,7 @@ func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11582,6 +12775,7 @@ func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
 	// result: (SUBSconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11595,13 +12789,14 @@ func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBSshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBSshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBSconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11611,7 +12806,7 @@ func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBSconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -11621,6 +12816,7 @@ func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBSshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -11636,9 +12832,25 @@ func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMSUBconst_0(v *Value) bool {
+	// match: (SUBconst [off1] (MOVWaddr [off2] {sym} ptr))
+	// cond:
+	// result: (MOVWaddr [off2-off1] {sym} ptr)
+	for {
+		off1 := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWaddr {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym := v_0.Aux
+		ptr := v_0.Args[0]
+		v.reset(OpARMMOVWaddr)
+		v.AuxInt = off2 - off1
+		v.Aux = sym
+		v.AddArg(ptr)
+		return true
+	}
 	// match: (SUBconst [0] x)
 	// cond:
 	// result: x
@@ -11652,6 +12864,20 @@ func rewriteValueARM_OpARMSUBconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (SUBconst [c] x)
+	// cond: !isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c))
+	// result: (ADDconst [int64(int32(-c))] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(!isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c))) {
+			break
+		}
+		v.reset(OpARMADDconst)
+		v.AuxInt = int64(int32(-c))
+		v.AddArg(x)
+		return true
+	}
 	// match: (SUBconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(d-c))])
@@ -11716,7 +12942,7 @@ func rewriteValueARM_OpARMSUBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftLL (MOVWconst [c]) x [d])
@@ -11724,6 +12950,7 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
 	// result: (RSBconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11732,7 +12959,7 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11743,6 +12970,7 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
 	// result: (SUBconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11759,6 +12987,7 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -11777,13 +13006,14 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11793,7 +13023,7 @@ func rewriteValueARM_OpARMSUBshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -11803,6 +13033,7 @@ func rewriteValueARM_OpARMSUBshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -11818,7 +13049,7 @@ func rewriteValueARM_OpARMSUBshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftRA (MOVWconst [c]) x [d])
@@ -11826,6 +13057,7 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
 	// result: (RSBconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11834,7 +13066,7 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11845,6 +13077,7 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
 	// result: (SUBconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11861,6 +13094,7 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -11879,13 +13113,14 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11895,7 +13130,7 @@ func rewriteValueARM_OpARMSUBshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -11905,6 +13140,7 @@ func rewriteValueARM_OpARMSUBshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -11920,7 +13156,7 @@ func rewriteValueARM_OpARMSUBshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftRL (MOVWconst [c]) x [d])
@@ -11928,6 +13164,7 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
 	// result: (RSBconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11936,7 +13173,7 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -11947,6 +13184,7 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
 	// result: (SUBconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -11963,6 +13201,7 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -11981,13 +13220,14 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMSUBshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMSUBshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUBshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (RSBconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -11997,7 +13237,7 @@ func rewriteValueARM_OpARMSUBshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMRSBconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -12007,6 +13247,7 @@ func rewriteValueARM_OpARMSUBshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -12022,34 +13263,34 @@ func rewriteValueARM_OpARMSUBshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR (MOVWconst [c]) x)
+func rewriteValueARM_OpARMXOR_0(v *Value) bool {
+	// match: (XOR x (MOVWconst [c]))
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x (MOVWconst [c]))
+	// match: (XOR (MOVWconst [c]) x)
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARMMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -12059,6 +13300,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -12076,6 +13318,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLLconst {
 			break
@@ -12093,6 +13336,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -12110,6 +13354,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRLconst {
 			break
@@ -12127,6 +13372,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -12144,6 +13390,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRAconst {
 			break
@@ -12161,6 +13408,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRR x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRRconst {
@@ -12178,6 +13426,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRR x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRRconst {
 			break
@@ -12191,15 +13440,20 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	return false
+}
+func rewriteValueARM_OpARMXOR_10(v *Value) bool {
 	// match: (XOR x (SLL y z))
 	// cond:
 	// result: (XORshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMXORshiftLLreg)
@@ -12212,10 +13466,12 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSLL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -12229,11 +13485,13 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRL {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMXORshiftRLreg)
@@ -12246,10 +13504,12 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRLreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRL {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -12263,11 +13523,13 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRA {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		z := v_1.Args[1]
 		v.reset(OpARMXORshiftRAreg)
@@ -12280,10 +13542,12 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRAreg x y z)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMSRA {
 			break
 		}
+		_ = v_0.Args[1]
 		y := v_0.Args[0]
 		z := v_0.Args[1]
 		x := v.Args[1]
@@ -12297,6 +13561,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -12307,9 +13572,7 @@ func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpARMXORconst_0(v *Value) bool {
 	// match: (XORconst [0] x)
 	// cond:
 	// result: x
@@ -12355,7 +13618,7 @@ func rewriteValueARM_OpARMXORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftLL (MOVWconst [c]) x [d])
@@ -12363,6 +13626,7 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12371,7 +13635,7 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -12382,6 +13646,7 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(uint32(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -12393,11 +13658,34 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (XORshiftLL [c] (SRLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [32-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
 	// match: (XORshiftLL x (SLLconst x [c]) [d])
 	// cond: c==d
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSLLconst {
@@ -12416,13 +13704,14 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftLLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftLLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftLLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (XORconst [c] (SLL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12432,7 +13721,7 @@ func rewriteValueARM_OpARMXORshiftLLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -12442,6 +13731,7 @@ func rewriteValueARM_OpARMXORshiftLLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -12457,7 +13747,7 @@ func rewriteValueARM_OpARMXORshiftLLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRA (MOVWconst [c]) x [d])
@@ -12465,6 +13755,7 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12473,7 +13764,7 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -12484,6 +13775,7 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(int32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -12500,6 +13792,7 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRAconst {
@@ -12518,13 +13811,14 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftRAreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftRAreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRAreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (XORconst [c] (SRA <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12534,7 +13828,7 @@ func rewriteValueARM_OpARMXORshiftRAreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRA, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -12544,6 +13838,7 @@ func rewriteValueARM_OpARMXORshiftRAreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRA x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -12559,7 +13854,7 @@ func rewriteValueARM_OpARMXORshiftRAreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRL (MOVWconst [c]) x [d])
@@ -12567,6 +13862,7 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12575,7 +13871,7 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -12586,6 +13882,7 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(uint32(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -12597,11 +13894,34 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (XORshiftRL [c] (SLLconst x [32-c]) x)
+	// cond:
+	// result: (SRRconst [   c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMSLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARMSRRconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (XORshiftRL x (SRLconst x [c]) [d])
 	// cond: c==d
 	// result: (MOVWconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMSRLconst {
@@ -12620,13 +13940,14 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftRLreg(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftRLreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRLreg (MOVWconst [c]) x y)
 	// cond:
 	// result: (XORconst [c] (SRL <x.Type> x y))
 	for {
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12636,7 +13957,7 @@ func rewriteValueARM_OpARMXORshiftRLreg(v *Value, config *Config) bool {
 		y := v.Args[2]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -12646,6 +13967,7 @@ func rewriteValueARM_OpARMXORshiftRLreg(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRL x y [c])
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		v_2 := v.Args[2]
@@ -12661,7 +13983,7 @@ func rewriteValueARM_OpARMXORshiftRLreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMXORshiftRR_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRR (MOVWconst [c]) x [d])
@@ -12669,6 +13991,7 @@ func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SRRconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARMMOVWconst {
 			break
@@ -12677,7 +14000,7 @@ func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARMSRRconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRRconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -12688,6 +14011,7 @@ func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(uint32(c)>>uint64(d)|uint32(c)<<uint64(32-d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARMMOVWconst {
@@ -12701,13 +14025,12 @@ func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd16_0(v *Value) bool {
 	// match: (Add16 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADD)
@@ -12716,13 +14039,12 @@ func rewriteValueARM_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd32_0(v *Value) bool {
 	// match: (Add32 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADD)
@@ -12731,13 +14053,12 @@ func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (ADDF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADDF)
@@ -12746,13 +14067,12 @@ func rewriteValueARM_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAdd32carry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd32carry_0(v *Value) bool {
 	// match: (Add32carry x y)
 	// cond:
 	// result: (ADDS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADDS)
@@ -12761,13 +14081,12 @@ func rewriteValueARM_OpAdd32carry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAdd32withcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd32withcarry_0(v *Value) bool {
 	// match: (Add32withcarry x y c)
 	// cond:
 	// result: (ADC x y c)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
@@ -12778,13 +14097,12 @@ func rewriteValueARM_OpAdd32withcarry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (ADDD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADDD)
@@ -12792,14 +14110,13 @@ func rewriteValueARM_OpAdd64F(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-}
-func rewriteValueARM_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+}
+func rewriteValueARM_OpAdd8_0(v *Value) bool {
 	// match: (Add8 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADD)
@@ -12808,13 +14125,12 @@ func rewriteValueARM_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMADD)
@@ -12823,9 +14139,7 @@ func rewriteValueARM_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVWaddr {sym} base)
@@ -12838,13 +14152,12 @@ func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMAND)
@@ -12853,13 +14166,12 @@ func rewriteValueARM_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMAND)
@@ -12868,13 +14180,12 @@ func rewriteValueARM_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAnd8_0(v *Value) bool {
 	// match: (And8 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMAND)
@@ -12883,13 +14194,12 @@ func rewriteValueARM_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMAND)
@@ -12898,45 +14208,100 @@ func rewriteValueARM_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpBswap32(v *Value, config *Config) bool {
+func rewriteValueARM_OpAvg32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Bswap32 <t> x)
+	// match: (Avg32u <t> x y)
+	// cond:
+	// result: (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpARMADD)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpARMSUB, t)
+		v1.AddArg(x)
+		v1.AddArg(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueARM_OpBitLen32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (BitLen32 <t> x)
 	// cond:
+	// result: (RSBconst [32] (CLZ <t> x))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpARMRSBconst)
+		v.AuxInt = 32
+		v0 := b.NewValue0(v.Pos, OpARMCLZ, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueARM_OpBswap32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Bswap32 <t> x)
+	// cond: objabi.GOARM==5
 	// result: (XOR <t> 		(SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8]) 		(SRRconst <t> x [8]))
 	for {
 		t := v.Type
 		x := v.Args[0]
+		if !(objabi.GOARM == 5) {
+			break
+		}
 		v.reset(OpARMXOR)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpARMSRLconst, t)
+		v0 := b.NewValue0(v.Pos, OpARMSRLconst, t)
 		v0.AuxInt = 8
-		v1 := b.NewValue0(v.Line, OpARMBICconst, t)
+		v1 := b.NewValue0(v.Pos, OpARMBICconst, t)
 		v1.AuxInt = 0xff0000
-		v2 := b.NewValue0(v.Line, OpARMXOR, t)
+		v2 := b.NewValue0(v.Pos, OpARMXOR, t)
 		v2.AddArg(x)
-		v3 := b.NewValue0(v.Line, OpARMSRRconst, t)
+		v3 := b.NewValue0(v.Pos, OpARMSRRconst, t)
 		v3.AuxInt = 16
 		v3.AddArg(x)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpARMSRRconst, t)
+		v4 := b.NewValue0(v.Pos, OpARMSRRconst, t)
 		v4.AuxInt = 8
 		v4.AddArg(x)
 		v.AddArg(v4)
 		return true
 	}
+	// match: (Bswap32 x)
+	// cond: objabi.GOARM>=6
+	// result: (REV x)
+	for {
+		x := v.Args[0]
+		if !(objabi.GOARM >= 6) {
+			break
+		}
+		v.reset(OpARMREV)
+		v.AddArg(x)
+		return true
+	}
+	return false
 }
-func rewriteValueARM_OpClosureCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -12948,9 +14313,7 @@ func rewriteValueARM_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
 	// result: (MVN x)
@@ -12961,9 +14324,7 @@ func rewriteValueARM_OpCom16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
 	// result: (MVN x)
@@ -12974,9 +14335,7 @@ func rewriteValueARM_OpCom32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCom8_0(v *Value) bool {
 	// match: (Com8 x)
 	// cond:
 	// result: (MVN x)
@@ -12987,9 +14346,7 @@ func rewriteValueARM_OpCom8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConst16_0(v *Value) bool {
 	// match: (Const16 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -13000,9 +14357,7 @@ func rewriteValueARM_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConst32_0(v *Value) bool {
 	// match: (Const32 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -13013,9 +14368,7 @@ func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (MOVFconst [val])
@@ -13026,9 +14379,7 @@ func rewriteValueARM_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -13039,9 +14390,7 @@ func rewriteValueARM_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConst8_0(v *Value) bool {
 	// match: (Const8 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -13052,9 +14401,7 @@ func rewriteValueARM_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVWconst [b])
@@ -13065,9 +14412,7 @@ func rewriteValueARM_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVWconst [0])
@@ -13077,13 +14422,12 @@ func rewriteValueARM_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpConvert_0(v *Value) bool {
 	// match: (Convert x mem)
 	// cond:
 	// result: (MOVWconvert x mem)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARMMOVWconvert)
@@ -13092,23 +14436,26 @@ func rewriteValueARM_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCtz32(v *Value, config *Config) bool {
+func rewriteValueARM_OpCtz32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Ctz32 <t> x)
-	// cond:
+	// cond: objabi.GOARM<=6
 	// result: (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
 	for {
 		t := v.Type
 		x := v.Args[0]
+		if !(objabi.GOARM <= 6) {
+			break
+		}
 		v.reset(OpARMRSBconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpARMCLZ, t)
-		v1 := b.NewValue0(v.Line, OpARMSUBconst, t)
+		v0 := b.NewValue0(v.Pos, OpARMCLZ, t)
+		v1 := b.NewValue0(v.Pos, OpARMSUBconst, t)
 		v1.AuxInt = 1
-		v2 := b.NewValue0(v.Line, OpARMAND, t)
+		v2 := b.NewValue0(v.Pos, OpARMAND, t)
 		v2.AddArg(x)
-		v3 := b.NewValue0(v.Line, OpARMRSBconst, t)
+		v3 := b.NewValue0(v.Pos, OpARMRSBconst, t)
 		v3.AuxInt = 0
 		v3.AddArg(x)
 		v2.AddArg(v3)
@@ -13117,10 +14464,25 @@ func rewriteValueARM_OpCtz32(v *Value, config *Config) bool {
 		v.AddArg(v0)
 		return true
 	}
+	// match: (Ctz32 <t> x)
+	// cond: objabi.GOARM==7
+	// result: (CLZ <t> (RBIT <t> x))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if !(objabi.GOARM == 7) {
+			break
+		}
+		v.reset(OpARMCLZ)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpARMRBIT, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	return false
 }
-func rewriteValueARM_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (MOVFW x)
@@ -13131,9 +14493,7 @@ func rewriteValueARM_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32Fto32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32Fto32U_0(v *Value) bool {
 	// match: (Cvt32Fto32U x)
 	// cond:
 	// result: (MOVFWU x)
@@ -13144,9 +14504,7 @@ func rewriteValueARM_OpCvt32Fto32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (MOVFD x)
@@ -13157,9 +14515,7 @@ func rewriteValueARM_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32Uto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32Uto32F_0(v *Value) bool {
 	// match: (Cvt32Uto32F x)
 	// cond:
 	// result: (MOVWUF x)
@@ -13170,9 +14526,7 @@ func rewriteValueARM_OpCvt32Uto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32Uto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32Uto64F_0(v *Value) bool {
 	// match: (Cvt32Uto64F x)
 	// cond:
 	// result: (MOVWUD x)
@@ -13183,9 +14537,7 @@ func rewriteValueARM_OpCvt32Uto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (MOVWF x)
@@ -13196,9 +14548,7 @@ func rewriteValueARM_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (MOVWD x)
@@ -13209,9 +14559,7 @@ func rewriteValueARM_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (MOVDW x)
@@ -13222,9 +14570,7 @@ func rewriteValueARM_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (MOVDF x)
@@ -13235,9 +14581,7 @@ func rewriteValueARM_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpCvt64Fto32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpCvt64Fto32U_0(v *Value) bool {
 	// match: (Cvt64Fto32U x)
 	// cond:
 	// result: (MOVDWU x)
@@ -13248,105 +14592,99 @@ func rewriteValueARM_OpCvt64Fto32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_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(OpARMCALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueARM_OpDiv16(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16 x y)
 	// cond:
 	// result: (Div32 (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpDiv32)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (Div32u (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpDiv32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpDiv32(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32 x y)
 	// cond:
-	// result: (SUB (XOR <config.fe.TypeUInt32()> 		(Select0 <config.fe.TypeUInt32()> (UDIVrtcall 			(SUB <config.fe.TypeUInt32()> (XOR x <config.fe.TypeUInt32()> (Signmask x)) (Signmask x)) 			(SUB <config.fe.TypeUInt32()> (XOR y <config.fe.TypeUInt32()> (Signmask y)) (Signmask y)))) 		(Signmask (XOR <config.fe.TypeUInt32()> x y))) (Signmask (XOR <config.fe.TypeUInt32()> x y)))
+	// result: (SUB (XOR <typ.UInt32> 		(Select0 <typ.UInt32> (CALLudiv 			(SUB <typ.UInt32> (XOR x <typ.UInt32> (Signmask x)) (Signmask x)) 			(SUB <typ.UInt32> (XOR y <typ.UInt32> (Signmask y)) (Signmask y)))) 		(Signmask (XOR <typ.UInt32> x y))) (Signmask (XOR <typ.UInt32> x y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
-		v0 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpSelect0, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpARMUDIVrtcall, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v3 := b.NewValue0(v.Line, OpARMSUB, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpSelect0, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpARMCALLudiv, types.NewTuple(typ.UInt32, typ.UInt32))
+		v3 := b.NewValue0(v.Pos, OpARMSUB, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v5 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
-		v6 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v6 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v6.AddArg(x)
 		v3.AddArg(v6)
 		v2.AddArg(v3)
-		v7 := b.NewValue0(v.Line, OpARMSUB, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpARMSUB, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v8.AddArg(y)
-		v9 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v9 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v9.AddArg(y)
 		v8.AddArg(v9)
 		v7.AddArg(v8)
-		v10 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v10 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v10.AddArg(y)
 		v7.AddArg(v10)
 		v2.AddArg(v7)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v11 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
-		v12 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v11 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
+		v12 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v12.AddArg(x)
 		v12.AddArg(y)
 		v11.AddArg(v12)
 		v0.AddArg(v11)
 		v.AddArg(v0)
-		v13 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
-		v14 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v13 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
+		v14 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v14.AddArg(x)
 		v14.AddArg(y)
 		v13.AddArg(v14)
@@ -13354,13 +14692,12 @@ func rewriteValueARM_OpDiv32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (DIVF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMDIVF)
@@ -13369,31 +14706,33 @@ func rewriteValueARM_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpDiv32u(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32u x y)
 	// cond:
-	// result: (Select0 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+	// result: (Select0 <typ.UInt32> (CALLudiv x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v.Type = config.fe.TypeUInt32()
-		v0 := b.NewValue0(v.Line, OpARMUDIVrtcall, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpARMCALLudiv, types.NewTuple(typ.UInt32, typ.UInt32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (DIVD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMDIVD)
@@ -13402,327 +14741,360 @@ func rewriteValueARM_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpDiv8(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8 x y)
 	// cond:
 	// result: (Div32 (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpDiv32)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValueARM_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8u x y)
 	// cond:
 	// result: (Div32u (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpDiv32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpEq16(v *Value, config *Config) bool {
+func rewriteValueARM_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq16 x y)
 	// cond:
 	// result: (Equal (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEq32(v *Value, config *Config) bool {
+func rewriteValueARM_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32 x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEq32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (Equal (CMPF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEq64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (Equal (CMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEq8(v *Value, config *Config) bool {
+func rewriteValueARM_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq8 x y)
 	// cond:
 	// result: (Equal (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEqB(v *Value, config *Config) bool {
+func rewriteValueARM_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqB x y)
 	// cond:
-	// result: (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+	// result: (XORconst [1] (XOR <typ.Bool> x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpARMXOR, typ.Bool)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValueARM_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (EqPtr x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq16(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16 x y)
 	// cond:
 	// result: (GreaterEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (GreaterEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq32(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32 x y)
 	// cond:
 	// result: (GreaterEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (GreaterEqual (CMPF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32U x y)
 	// cond:
 	// result: (GreaterEqualU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (GreaterEqual (CMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq8(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8 x y)
 	// cond:
 	// result: (GreaterEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8U x y)
 	// cond:
 	// result: (GreaterEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -13731,224 +15103,180 @@ func rewriteValueARM_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_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(OpARMCALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueARM_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16 x y)
 	// cond:
 	// result: (GreaterThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (GreaterThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater32(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32 x y)
 	// cond:
 	// result: (GreaterThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (GreaterThan (CMPF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32U x y)
 	// cond:
 	// result: (GreaterThanU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (GreaterThan (CMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater8(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8 x y)
 	// cond:
 	// result: (GreaterThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValueARM_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8U x y)
 	// cond:
 	// result: (GreaterThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16 x y)
-	// cond:
-	// result: (SRAconst (MUL <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARMSRAconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpARMMUL, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARMSRLconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpARMMUL, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpHmul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpHmul32_0(v *Value) bool {
 	// match: (Hmul32 x y)
 	// cond:
 	// result: (HMUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMHMUL)
@@ -13957,13 +15285,12 @@ func rewriteValueARM_OpHmul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpHmul32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpHmul32u_0(v *Value) bool {
 	// match: (Hmul32u x y)
 	// cond:
 	// result: (HMULU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMHMULU)
@@ -13972,58 +15299,13 @@ func rewriteValueARM_OpHmul32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8 x y)
-	// cond:
-	// result: (SRAconst (MUL <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARMSRAconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpARMMUL, config.fe.TypeInt16())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARMSRLconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpARMMUL, config.fe.TypeUInt16())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARMCALLinter)
@@ -14033,24 +15315,25 @@ func rewriteValueARM_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValueARM_OpIsInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (LessThanU (CMP idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpARMLessThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValueARM_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsNonNil ptr)
@@ -14059,342 +15342,374 @@ func rewriteValueARM_OpIsNonNil(v *Value, config *Config) bool {
 	for {
 		ptr := v.Args[0]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = 0
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValueARM_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (LessEqualU (CMP idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpARMLessEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq16(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16 x y)
 	// cond:
 	// result: (LessEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq32(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32 x y)
 	// cond:
 	// result: (LessEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (GreaterEqual (CMPF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32U x y)
 	// cond:
 	// result: (LessEqualU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (GreaterEqual (CMPD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq8(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8 x y)
 	// cond:
 	// result: (LessEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8U x y)
 	// cond:
 	// result: (LessEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessEqualU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess16(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16 x y)
 	// cond:
 	// result: (LessThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (LessThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess32(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32 x y)
 	// cond:
 	// result: (LessThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (GreaterThan (CMPF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess32U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32U x y)
 	// cond:
 	// result: (LessThanU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (GreaterThan (CMPD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMGreaterThan)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess8(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8 x y)
 	// cond:
 	// result: (LessThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThan)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLess8U(v *Value, config *Config) bool {
+func rewriteValueARM_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8U x y)
 	// cond:
 	// result: (LessThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMLessThanU)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: t.IsBoolean()
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean()) {
@@ -14410,6 +15725,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
@@ -14425,6 +15741,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && !isSigned(t)) {
@@ -14440,6 +15757,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -14455,6 +15773,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -14470,6 +15789,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) || isPtr(t)) {
@@ -14485,6 +15805,7 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVFload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -14495,141 +15816,82 @@ func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Load <t> ptr mem)
-	// cond: is64BitFloat(t)
-	// result: (MOVDload ptr mem)
-	for {
-		t := v.Type
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(is64BitFloat(t)) {
-			break
-		}
-		v.reset(OpARMMOVDload)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueARM_OpLrot16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot16 <t> x [c])
-	// cond:
-	// result: (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to32 x) [16-c&15]))
-	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARMOR)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, t)
-		v0.AuxInt = c & 15
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMSRLconst, t)
-		v1.AuxInt = 16 - c&15
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v.AddArg(v1)
-		return true
-	}
-}
-func rewriteValueARM_OpLrot32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot32 x [c])
-	// cond:
-	// result: (SRRconst x [32-c&31])
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARMSRRconst)
-		v.AuxInt = 32 - c&31
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueARM_OpLrot8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot8 <t> x [c])
-	// cond:
-	// result: (OR (SLLconst <t> x [c&7]) (SRLconst <t> (ZeroExt8to32 x) [8-c&7]))
+	// match: (Load <t> ptr mem)
+	// cond: is64BitFloat(t)
+	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARMOR)
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, t)
-		v0.AuxInt = c & 7
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMSRLconst, t)
-		v1.AuxInt = 8 - c&7
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v.AddArg(v1)
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is64BitFloat(t)) {
+			break
+		}
+		v.reset(OpARMMOVDload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueARM_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh16x32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpLsh16x64_0(v *Value) bool {
 	// match: (Lsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -14648,6 +15910,7 @@ func rewriteValueARM_OpLsh16x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -14662,78 +15925,84 @@ func rewriteValueARM_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x8 x y)
 	// cond:
 	// result: (SLL x (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSLL)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh32x32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpLsh32x64_0(v *Value) bool {
 	// match: (Lsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -14752,6 +16021,7 @@ func rewriteValueARM_OpLsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -14766,78 +16036,84 @@ func rewriteValueARM_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x8 x y)
 	// cond:
 	// result: (SLL x (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSLL)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh8x32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSLL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpLsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpLsh8x64_0(v *Value) bool {
 	// match: (Lsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -14856,6 +16132,7 @@ func rewriteValueARM_OpLsh8x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 8
 	// result: (Const8 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -14870,243 +16147,272 @@ func rewriteValueARM_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x8 x y)
 	// cond:
 	// result: (SLL x (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSLL)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpMod16(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16 x y)
 	// cond:
 	// result: (Mod32 (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpMod16u(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpMod32(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32 x y)
 	// cond:
-	// result: (SUB (XOR <config.fe.TypeUInt32()> 		(Select1 <config.fe.TypeUInt32()> (UDIVrtcall 			(SUB <config.fe.TypeUInt32()> (XOR <config.fe.TypeUInt32()> x (Signmask x)) (Signmask x)) 			(SUB <config.fe.TypeUInt32()> (XOR <config.fe.TypeUInt32()> y (Signmask y)) (Signmask y)))) 		(Signmask x)) (Signmask x))
+	// result: (SUB (XOR <typ.UInt32> 		(Select1 <typ.UInt32> (CALLudiv 			(SUB <typ.UInt32> (XOR <typ.UInt32> x (Signmask x)) (Signmask x)) 			(SUB <typ.UInt32> (XOR <typ.UInt32> y (Signmask y)) (Signmask y)))) 		(Signmask x)) (Signmask x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
-		v0 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpARMUDIVrtcall, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v3 := b.NewValue0(v.Line, OpARMSUB, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpSelect1, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpARMCALLudiv, types.NewTuple(typ.UInt32, typ.UInt32))
+		v3 := b.NewValue0(v.Pos, OpARMSUB, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v5 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
-		v6 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v6 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v6.AddArg(x)
 		v3.AddArg(v6)
 		v2.AddArg(v3)
-		v7 := b.NewValue0(v.Line, OpARMSUB, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpARMSUB, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpARMXOR, typ.UInt32)
 		v8.AddArg(y)
-		v9 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v9 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v9.AddArg(y)
 		v8.AddArg(v9)
 		v7.AddArg(v8)
-		v10 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v10 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v10.AddArg(y)
 		v7.AddArg(v10)
 		v2.AddArg(v7)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v11 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v11 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v11.AddArg(x)
 		v0.AddArg(v11)
 		v.AddArg(v0)
-		v12 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v12 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v12.AddArg(x)
 		v.AddArg(v12)
 		return true
 	}
 }
-func rewriteValueARM_OpMod32u(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32u x y)
 	// cond:
-	// result: (Select1 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+	// result: (Select1 <typ.UInt32> (CALLudiv x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v.Type = config.fe.TypeUInt32()
-		v0 := b.NewValue0(v.Line, OpARMUDIVrtcall, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpARMCALLudiv, types.NewTuple(typ.UInt32, typ.UInt32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpMod8(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8 x y)
 	// cond:
 	// result: (Mod32 (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpMod8u(v *Value, config *Config) bool {
+func rewriteValueARM_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8u x y)
 	// cond:
 	// result: (Mod32u (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpMove(v *Value, config *Config) bool {
+func rewriteValueARM_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpARMMOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [2] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore dst (MOVHUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpARMMOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpARMMOVHUload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVBstore [1] dst (MOVBUload [1] src mem) 		(MOVBstore dst (MOVBUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 1
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v0.AuxInt = 1
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -15114,48 +16420,56 @@ func rewriteValueARM_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore dst (MOVWload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpARMMOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVWload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] dst (MOVHUload [2] src mem) 		(MOVHstore dst (MOVHUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpARMMOVHstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpARMMOVHUload, typ.UInt16)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARMMOVHUload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpARMMOVHUload, typ.UInt16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -15163,44 +16477,44 @@ func rewriteValueARM_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVBstore [3] dst (MOVBUload [3] src mem) 		(MOVBstore [2] dst (MOVBUload [2] src mem) 			(MOVBstore [1] dst (MOVBUload [1] src mem) 				(MOVBstore dst (MOVBUload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 3
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v0.AuxInt = 3
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v2.AuxInt = 2
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v4.AuxInt = 1
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v6 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -15210,36 +16524,36 @@ func rewriteValueARM_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBUload [2] src mem) 		(MOVBstore [1] dst (MOVBUload [1] src mem) 			(MOVBstore dst (MOVBUload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v2.AuxInt = 1
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpARMMOVBUload, typ.UInt8)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -15248,41 +16562,45 @@ func rewriteValueARM_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512 	&& SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice
-	// result: (DUFFCOPY [8 * (128 - int64(SizeAndAlign(s).Size()/4))] dst src mem)
+	// match: (Move [s] {t} dst src mem)
+	// cond: s%4 == 0 && s > 4 && s <= 512 	&& t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice
+	// result: (DUFFCOPY [8 * (128 - int64(s/4))] dst src mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512 && SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice) {
+		if !(s%4 == 0 && s > 4 && s <= 512 && t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(OpARMDUFFCOPY)
-		v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/4))
+		v.AuxInt = 8 * (128 - int64(s/4))
 		v.AddArg(dst)
 		v.AddArg(src)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0
-	// result: (LoweredMove [SizeAndAlign(s).Align()] 		dst 		src 		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// match: (Move [s] {t} dst src mem)
+	// cond: (s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0
+	// result: (LoweredMove [t.(*types.Type).Alignment()] 		dst 		src 		(ADDconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0) {
+		if !((s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0) {
 			break
 		}
 		v.reset(OpARMLoweredMove)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpARMADDconst, src.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpARMADDconst, src.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(src)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -15290,13 +16608,12 @@ func rewriteValueARM_OpMove(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul16_0(v *Value) bool {
 	// match: (Mul16 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMUL)
@@ -15305,13 +16622,12 @@ func rewriteValueARM_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul32_0(v *Value) bool {
 	// match: (Mul32 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMUL)
@@ -15320,13 +16636,12 @@ func rewriteValueARM_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (MULF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMULF)
@@ -15335,13 +16650,12 @@ func rewriteValueARM_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpMul32uhilo(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul32uhilo_0(v *Value) bool {
 	// match: (Mul32uhilo x y)
 	// cond:
 	// result: (MULLU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMULLU)
@@ -15350,13 +16664,12 @@ func rewriteValueARM_OpMul32uhilo(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (MULD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMULD)
@@ -15365,13 +16678,12 @@ func rewriteValueARM_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpMul8_0(v *Value) bool {
 	// match: (Mul8 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMMUL)
@@ -15380,9 +16692,7 @@ func rewriteValueARM_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeg16_0(v *Value) bool {
 	// match: (Neg16 x)
 	// cond:
 	// result: (RSBconst [0] x)
@@ -15394,9 +16704,7 @@ func rewriteValueARM_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeg32_0(v *Value) bool {
 	// match: (Neg32 x)
 	// cond:
 	// result: (RSBconst [0] x)
@@ -15408,9 +16716,7 @@ func rewriteValueARM_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (NEGF x)
@@ -15421,9 +16727,7 @@ func rewriteValueARM_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (NEGD x)
@@ -15434,9 +16738,7 @@ func rewriteValueARM_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeg8_0(v *Value) bool {
 	// match: (Neg8 x)
 	// cond:
 	// result: (RSBconst [0] x)
@@ -15448,106 +16750,114 @@ func rewriteValueARM_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeq16(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq16 x y)
 	// cond:
 	// result: (NotEqual (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNeq32(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32 x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (NotEqual (CMPF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (NotEqual (CMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNeq8(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq8 x y)
 	// cond:
 	// result: (NotEqual (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNeqB_0(v *Value) bool {
 	// match: (NeqB x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMXOR)
@@ -15556,30 +16866,30 @@ func rewriteValueARM_OpNeqB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValueARM_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMNotEqual)
-		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARMLoweredNilCheck)
@@ -15588,9 +16898,7 @@ func rewriteValueARM_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORconst [1] x)
@@ -15602,9 +16910,7 @@ func rewriteValueARM_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpOffPtr_0(v *Value) bool {
 	// match: (OffPtr [off] ptr:(SP))
 	// cond:
 	// result: (MOVWaddr [off] ptr)
@@ -15631,13 +16937,12 @@ func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMOR)
@@ -15646,13 +16951,12 @@ func rewriteValueARM_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMOR)
@@ -15661,13 +16965,12 @@ func rewriteValueARM_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpOr8_0(v *Value) bool {
 	// match: (Or8 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMOR)
@@ -15676,13 +16979,12 @@ func rewriteValueARM_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMOR)
@@ -15691,65 +16993,98 @@ func rewriteValueARM_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueARM_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueARM_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v3.AuxInt = 256
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 16
-	// result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+	// result: (SRLconst (SLLconst <typ.UInt32> x [16]) [c+16])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -15761,7 +17096,7 @@ func rewriteValueARM_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRLconst)
 		v.AuxInt = c + 16
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -15771,6 +17106,7 @@ func rewriteValueARM_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -15785,78 +17121,90 @@ func rewriteValueARM_OpRsh16Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux8 x y)
 	// cond:
 	// result: (SRL (ZeroExt16to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRL)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 x y)
 	// cond:
 	// result: (SRAcond (SignExt16to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x32 x y)
 	// cond:
 	// result: (SRAcond (SignExt16to32 x) y (CMPconst [256] y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [16]) [c+16])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -15868,7 +17216,7 @@ func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRAconst)
 		v.AuxInt = c + 16
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -15876,8 +17224,9 @@ func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint64(c) >= 16
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [16]) [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -15889,7 +17238,7 @@ func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRAconst)
 		v.AuxInt = 31
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -15897,80 +17246,86 @@ func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x8 x y)
 	// cond:
 	// result: (SRA (SignExt16to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32Ux32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> x y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpRsh32Ux64_0(v *Value) bool {
 	// match: (Rsh32Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SRLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -15989,6 +17344,7 @@ func rewriteValueARM_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -16003,72 +17359,78 @@ func rewriteValueARM_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32Ux8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32Ux8 x y)
 	// cond:
 	// result: (SRL x (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRL)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 x y)
 	// cond:
 	// result: (SRAcond x (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v1.AddArg(v2)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32x32 x y)
 	// cond:
 	// result: (SRAcond x y (CMPconst [256] y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
 		v.AddArg(x)
 		v.AddArg(y)
-		v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v0.AuxInt = 256
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpRsh32x64_0(v *Value) bool {
 	// match: (Rsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SRAconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -16087,6 +17449,7 @@ func rewriteValueARM_OpRsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -16103,82 +17466,94 @@ func rewriteValueARM_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x8 x y)
 	// cond:
 	// result: (SRA x (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v3.AuxInt = 256
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux32 x y)
 	// cond:
 	// result: (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) y) (CMPconst [256] y) [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMCMOVWHSconst)
 		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSRL, x.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 8
-	// result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+	// result: (SRLconst (SLLconst <typ.UInt32> x [24]) [c+24])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -16190,7 +17565,7 @@ func rewriteValueARM_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRLconst)
 		v.AuxInt = c + 24
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -16200,6 +17575,7 @@ func rewriteValueARM_OpRsh8Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 8
 	// result: (Const8 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -16214,78 +17590,90 @@ func rewriteValueARM_OpRsh8Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux8 x y)
 	// cond:
 	// result: (SRL (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRL)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 x y)
 	// cond:
 	// result: (SRAcond (SignExt8to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v2.AuxInt = 256
-		v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x32 x y)
 	// cond:
 	// result: (SRAcond (SignExt8to32 x) y (CMPconst [256] y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRAcond)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 		v1.AuxInt = 256
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [24]) [c+24])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -16297,7 +17685,7 @@ func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRAconst)
 		v.AuxInt = c + 24
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -16305,8 +17693,9 @@ func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint64(c) >= 8
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -16318,7 +17707,7 @@ func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARMSRAconst)
 		v.AuxInt = 31
-		v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -16326,36 +17715,38 @@ func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueARM_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x8 x y)
 	// cond:
 	// result: (SRA (SignExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM_OpSelect0(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Select0 (UDIVrtcall x (MOVWconst [1])))
+func rewriteValueARM_OpSelect0_0(v *Value) bool {
+	// match: (Select0 (CALLudiv x (MOVWconst [1])))
 	// cond:
 	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpARMMOVWconst {
@@ -16369,14 +17760,15 @@ func rewriteValueARM_OpSelect0(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select0 (UDIVrtcall x (MOVWconst [c])))
+	// match: (Select0 (CALLudiv x (MOVWconst [c])))
 	// cond: isPowerOfTwo(c)
 	// result: (SRLconst [log2(c)] x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpARMMOVWconst {
@@ -16391,14 +17783,15 @@ func rewriteValueARM_OpSelect0(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select0 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d])))
 	// cond:
 	// result: (MOVWconst [int64(uint32(c)/uint32(d))])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpARMMOVWconst {
 			break
@@ -16415,17 +17808,16 @@ func rewriteValueARM_OpSelect0(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpSelect1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Select1 (UDIVrtcall _ (MOVWconst [1])))
+func rewriteValueARM_OpSelect1_0(v *Value) bool {
+	// match: (Select1 (CALLudiv _ (MOVWconst [1])))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpARMMOVWconst {
 			break
@@ -16437,14 +17829,15 @@ func rewriteValueARM_OpSelect1(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Select1 (UDIVrtcall x (MOVWconst [c])))
+	// match: (Select1 (CALLudiv x (MOVWconst [c])))
 	// cond: isPowerOfTwo(c)
 	// result: (ANDconst [c-1] x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpARMMOVWconst {
@@ -16459,14 +17852,15 @@ func rewriteValueARM_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select1 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d])))
 	// cond:
 	// result: (MOVWconst [int64(uint32(c)%uint32(d))])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpARMUDIVrtcall {
+		if v_0.Op != OpARMCALLudiv {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpARMMOVWconst {
 			break
@@ -16483,9 +17877,7 @@ func rewriteValueARM_OpSelect1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -16496,9 +17888,7 @@ func rewriteValueARM_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSignExt8to16_0(v *Value) bool {
 	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -16509,9 +17899,7 @@ func rewriteValueARM_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSignExt8to32_0(v *Value) bool {
 	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -16522,9 +17910,7 @@ func rewriteValueARM_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSignmask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSignmask_0(v *Value) bool {
 	// match: (Signmask x)
 	// cond:
 	// result: (SRAconst x [31])
@@ -16536,29 +17922,25 @@ func rewriteValueARM_OpSignmask(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValueARM_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (MVN (SRAconst <t> (SUBconst <t> x [1]) [31]))
+	// result: (SRAconst (RSBconst <t> [0] x) [31])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(OpARMMVN)
-		v0 := b.NewValue0(v.Line, OpARMSRAconst, t)
-		v0.AuxInt = 31
-		v1 := b.NewValue0(v.Line, OpARMSUBconst, t)
-		v1.AuxInt = 1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		v.reset(OpARMSRAconst)
+		v.AuxInt = 31
+		v0 := b.NewValue0(v.Pos, OpARMRSBconst, t)
+		v0.AuxInt = 0
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (SQRTD x)
@@ -16569,9 +17951,7 @@ func rewriteValueARM_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -16586,52 +17966,53 @@ func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [1] ptr val mem)
-	// cond:
+func rewriteValueARM_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(OpARMMOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(OpARMMOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: !is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARMMOVWstore)
@@ -16640,17 +18021,16 @@ func rewriteValueARM_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (MOVFstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARMMOVFstore)
@@ -16659,17 +18039,16 @@ func rewriteValueARM_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARMMOVDstore)
@@ -16680,13 +18059,12 @@ func rewriteValueARM_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub16_0(v *Value) bool {
 	// match: (Sub16 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
@@ -16695,13 +18073,12 @@ func rewriteValueARM_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub32_0(v *Value) bool {
 	// match: (Sub32 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
@@ -16710,13 +18087,12 @@ func rewriteValueARM_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (SUBF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUBF)
@@ -16725,13 +18101,12 @@ func rewriteValueARM_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub32carry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub32carry_0(v *Value) bool {
 	// match: (Sub32carry x y)
 	// cond:
 	// result: (SUBS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUBS)
@@ -16740,13 +18115,12 @@ func rewriteValueARM_OpSub32carry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub32withcarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub32withcarry_0(v *Value) bool {
 	// match: (Sub32withcarry x y c)
 	// cond:
 	// result: (SBC x y c)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
@@ -16757,13 +18131,12 @@ func rewriteValueARM_OpSub32withcarry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (SUBD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUBD)
@@ -16772,13 +18145,12 @@ func rewriteValueARM_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSub8_0(v *Value) bool {
 	// match: (Sub8 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
@@ -16787,13 +18159,12 @@ func rewriteValueARM_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMSUB)
@@ -16802,9 +18173,7 @@ func rewriteValueARM_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpTrunc16to8_0(v *Value) bool {
 	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
@@ -16816,9 +18185,7 @@ func rewriteValueARM_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -16830,9 +18197,7 @@ func rewriteValueARM_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpTrunc32to8_0(v *Value) bool {
 	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
@@ -16844,13 +18209,12 @@ func rewriteValueARM_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMXOR)
@@ -16859,13 +18223,12 @@ func rewriteValueARM_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMXOR)
@@ -16874,13 +18237,12 @@ func rewriteValueARM_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpXor8_0(v *Value) bool {
 	// match: (Xor8 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARMXOR)
@@ -16889,161 +18251,177 @@ func rewriteValueARM_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpZero(v *Value, config *Config) bool {
+func rewriteValueARM_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] ptr mem)
+	// cond:
 	// result: (MOVBstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARMMOVBstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [2] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpARMMOVHstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] ptr mem)
+	// cond:
 	// result: (MOVBstore [1] ptr (MOVWconst [0]) 		(MOVBstore [0] ptr (MOVWconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 1
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpARMMOVWstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] ptr (MOVWconst [0]) 		(MOVHstore [0] ptr (MOVWconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpARMMOVHstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVHstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] ptr mem)
+	// cond:
 	// result: (MOVBstore [3] ptr (MOVWconst [0]) 		(MOVBstore [2] ptr (MOVWconst [0]) 			(MOVBstore [1] ptr (MOVWconst [0]) 				(MOVBstore [0] ptr (MOVWconst [0]) mem))))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 3
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v5.AuxInt = 0
 		v5.AddArg(ptr)
-		v6 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v6.AuxInt = 0
 		v5.AddArg(v6)
 		v5.AddArg(mem)
@@ -17052,32 +18430,32 @@ func rewriteValueARM_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Zero [3] ptr mem)
+	// cond:
 	// result: (MOVBstore [2] ptr (MOVWconst [0]) 		(MOVBstore [1] ptr (MOVWconst [0]) 			(MOVBstore [0] ptr (MOVWconst [0]) mem)))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARMMOVBstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARMMOVBstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -17085,43 +18463,47 @@ func rewriteValueARM_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512 	&& SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice
-	// result: (DUFFZERO [4 * (128 - int64(SizeAndAlign(s).Size()/4))] ptr (MOVWconst [0]) mem)
+	// match: (Zero [s] {t} ptr mem)
+	// cond: s%4 == 0 && s > 4 && s <= 512 	&& t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice
+	// result: (DUFFZERO [4 * (128 - int64(s/4))] ptr (MOVWconst [0]) mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%4 == 0 && SizeAndAlign(s).Size() > 4 && SizeAndAlign(s).Size() <= 512 && SizeAndAlign(s).Align()%4 == 0 && !config.noDuffDevice) {
+		if !(s%4 == 0 && s > 4 && s <= 512 && t.(*types.Type).Alignment()%4 == 0 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(OpARMDUFFZERO)
-		v.AuxInt = 4 * (128 - int64(SizeAndAlign(s).Size()/4))
+		v.AuxInt = 4 * (128 - int64(s/4))
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0
-	// result: (LoweredZero [SizeAndAlign(s).Align()] 		ptr 		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		(MOVWconst [0]) 		mem)
+	// match: (Zero [s] {t} ptr mem)
+	// cond: (s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0
+	// result: (LoweredZero [t.(*types.Type).Alignment()] 		ptr 		(ADDconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)]) 		(MOVWconst [0]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0) {
+		if !((s > 512 || config.noDuffDevice) || t.(*types.Type).Alignment()%4 != 0) {
 			break
 		}
 		v.reset(OpARMLoweredZero)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARMADDconst, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpARMADDconst, ptr.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpARMMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		v.AddArg(mem)
@@ -17129,9 +18511,7 @@ func rewriteValueARM_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -17142,9 +18522,7 @@ func rewriteValueARM_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpZeroExt8to16_0(v *Value) bool {
 	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -17155,9 +18533,7 @@ func rewriteValueARM_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM_OpZeroExt8to32_0(v *Value) bool {
 	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -17168,17 +18544,19 @@ func rewriteValueARM_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM_OpZeromask(v *Value, config *Config) bool {
+func rewriteValueARM_OpZeromask_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Zeromask x)
 	// cond:
-	// result: (SRAconst (RSBshiftRL <config.fe.TypeInt32()> x x [1]) [31])
+	// result: (SRAconst (RSBshiftRL <typ.Int32> x x [1]) [31])
 	for {
 		x := v.Args[0]
 		v.reset(OpARMSRAconst)
 		v.AuxInt = 31
-		v0 := b.NewValue0(v.Line, OpARMRSBshiftRL, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARMRSBshiftRL, typ.Int32)
 		v0.AuxInt = 1
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -17186,7 +18564,13 @@ func rewriteValueARM_OpZeromask(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlockARM(b *Block, config *Config) bool {
+func rewriteBlockARM(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockARMEQ:
 		// match: (EQ (FlagEQ) yes no)
@@ -17197,12 +18581,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -17213,13 +18593,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17230,13 +18606,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17247,13 +18619,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -17264,13 +18632,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (EQ (InvertFlags cmp) yes no)
@@ -17282,12 +18646,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMGE:
@@ -17299,12 +18659,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -17315,13 +18671,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17332,13 +18684,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17349,12 +18697,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -17365,12 +18709,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (InvertFlags cmp) yes no)
@@ -17382,12 +18722,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMGT:
@@ -17399,13 +18735,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -17416,13 +18748,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17433,13 +18761,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17450,12 +18774,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -17466,12 +18786,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GT (InvertFlags cmp) yes no)
@@ -17483,12 +18799,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockIf:
@@ -17501,12 +18813,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMEQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (NotEqual cc) yes no)
@@ -17518,12 +18826,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMNE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessThan cc) yes no)
@@ -17535,12 +18839,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessThanU cc) yes no)
@@ -17552,12 +18852,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessEqual cc) yes no)
@@ -17569,12 +18865,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessEqualU cc) yes no)
@@ -17586,12 +18878,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterThan cc) yes no)
@@ -17603,12 +18891,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterThanU cc) yes no)
@@ -17620,12 +18904,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterEqual cc) yes no)
@@ -17637,12 +18917,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterEqualU cc) yes no)
@@ -17654,12 +18930,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If cond yes no)
@@ -17669,15 +18941,11 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMNE
-			v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags)
 			v0.AuxInt = 0
 			v0.AddArg(cond)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMLE:
@@ -17689,12 +18957,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -17705,12 +18969,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17721,12 +18981,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17737,13 +18993,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -17754,13 +19006,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LE (InvertFlags cmp) yes no)
@@ -17772,12 +19020,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMLT:
@@ -17789,13 +19033,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -17806,12 +19046,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17822,12 +19058,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -17838,13 +19070,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -17855,13 +19083,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LT (InvertFlags cmp) yes no)
@@ -17873,12 +19097,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMNE:
@@ -17898,12 +19118,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMEQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (NotEqual cc)) yes no)
@@ -17922,12 +19138,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMNE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (LessThan cc)) yes no)
@@ -17946,12 +19158,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (LessThanU cc)) yes no)
@@ -17970,12 +19178,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (LessEqual cc)) yes no)
@@ -17994,12 +19198,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMLE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (LessEqualU cc)) yes no)
@@ -18018,12 +19218,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (GreaterThan cc)) yes no)
@@ -18042,12 +19238,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (GreaterThanU cc)) yes no)
@@ -18066,12 +19258,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (GreaterEqual cc)) yes no)
@@ -18090,12 +19278,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (GreaterEqualU cc)) yes no)
@@ -18114,12 +19298,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagEQ) yes no)
@@ -18130,13 +19310,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -18147,12 +19323,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18163,12 +19335,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18179,12 +19347,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -18195,12 +19359,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (InvertFlags cmp) yes no)
@@ -18212,12 +19372,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMUGE:
@@ -18229,12 +19385,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -18245,13 +19397,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18262,12 +19410,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18278,13 +19422,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -18295,12 +19435,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGE (InvertFlags cmp) yes no)
@@ -18312,12 +19448,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMUGT:
@@ -18329,13 +19461,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -18346,13 +19474,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18363,12 +19487,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18379,13 +19499,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -18396,12 +19512,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGT (InvertFlags cmp) yes no)
@@ -18413,12 +19525,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMULT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMULE:
@@ -18430,12 +19538,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -18446,12 +19550,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18462,13 +19562,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18479,12 +19575,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -18495,13 +19587,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (ULE (InvertFlags cmp) yes no)
@@ -18513,12 +19601,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARMULT:
@@ -18530,13 +19614,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagEQ {
 				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)
@@ -18547,12 +19627,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18563,13 +19639,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagLT_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)
@@ -18580,12 +19652,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_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)
@@ -18596,13 +19664,9 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 			if v.Op != OpARMFlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (ULT (InvertFlags cmp) yes no)
@@ -18614,12 +19678,8 @@ func rewriteBlockARM(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARMUGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 5c49636..2be3d11 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -1,752 +1,753 @@
-// autogenerated from gen/ARM64.rules: do not edit!
+// Code generated from gen/ARM64.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueARM64(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueARM64(v *Value) bool {
 	switch v.Op {
 	case OpARM64ADD:
-		return rewriteValueARM64_OpARM64ADD(v, config)
+		return rewriteValueARM64_OpARM64ADD_0(v)
 	case OpARM64ADDconst:
-		return rewriteValueARM64_OpARM64ADDconst(v, config)
+		return rewriteValueARM64_OpARM64ADDconst_0(v)
 	case OpARM64ADDshiftLL:
-		return rewriteValueARM64_OpARM64ADDshiftLL(v, config)
+		return rewriteValueARM64_OpARM64ADDshiftLL_0(v)
 	case OpARM64ADDshiftRA:
-		return rewriteValueARM64_OpARM64ADDshiftRA(v, config)
+		return rewriteValueARM64_OpARM64ADDshiftRA_0(v)
 	case OpARM64ADDshiftRL:
-		return rewriteValueARM64_OpARM64ADDshiftRL(v, config)
+		return rewriteValueARM64_OpARM64ADDshiftRL_0(v)
 	case OpARM64AND:
-		return rewriteValueARM64_OpARM64AND(v, config)
+		return rewriteValueARM64_OpARM64AND_0(v) || rewriteValueARM64_OpARM64AND_10(v)
 	case OpARM64ANDconst:
-		return rewriteValueARM64_OpARM64ANDconst(v, config)
+		return rewriteValueARM64_OpARM64ANDconst_0(v)
 	case OpARM64ANDshiftLL:
-		return rewriteValueARM64_OpARM64ANDshiftLL(v, config)
+		return rewriteValueARM64_OpARM64ANDshiftLL_0(v)
 	case OpARM64ANDshiftRA:
-		return rewriteValueARM64_OpARM64ANDshiftRA(v, config)
+		return rewriteValueARM64_OpARM64ANDshiftRA_0(v)
 	case OpARM64ANDshiftRL:
-		return rewriteValueARM64_OpARM64ANDshiftRL(v, config)
+		return rewriteValueARM64_OpARM64ANDshiftRL_0(v)
 	case OpARM64BIC:
-		return rewriteValueARM64_OpARM64BIC(v, config)
+		return rewriteValueARM64_OpARM64BIC_0(v)
 	case OpARM64BICconst:
-		return rewriteValueARM64_OpARM64BICconst(v, config)
+		return rewriteValueARM64_OpARM64BICconst_0(v)
 	case OpARM64BICshiftLL:
-		return rewriteValueARM64_OpARM64BICshiftLL(v, config)
+		return rewriteValueARM64_OpARM64BICshiftLL_0(v)
 	case OpARM64BICshiftRA:
-		return rewriteValueARM64_OpARM64BICshiftRA(v, config)
+		return rewriteValueARM64_OpARM64BICshiftRA_0(v)
 	case OpARM64BICshiftRL:
-		return rewriteValueARM64_OpARM64BICshiftRL(v, config)
+		return rewriteValueARM64_OpARM64BICshiftRL_0(v)
 	case OpARM64CMP:
-		return rewriteValueARM64_OpARM64CMP(v, config)
+		return rewriteValueARM64_OpARM64CMP_0(v)
 	case OpARM64CMPW:
-		return rewriteValueARM64_OpARM64CMPW(v, config)
+		return rewriteValueARM64_OpARM64CMPW_0(v)
 	case OpARM64CMPWconst:
-		return rewriteValueARM64_OpARM64CMPWconst(v, config)
+		return rewriteValueARM64_OpARM64CMPWconst_0(v)
 	case OpARM64CMPconst:
-		return rewriteValueARM64_OpARM64CMPconst(v, config)
+		return rewriteValueARM64_OpARM64CMPconst_0(v)
 	case OpARM64CMPshiftLL:
-		return rewriteValueARM64_OpARM64CMPshiftLL(v, config)
+		return rewriteValueARM64_OpARM64CMPshiftLL_0(v)
 	case OpARM64CMPshiftRA:
-		return rewriteValueARM64_OpARM64CMPshiftRA(v, config)
+		return rewriteValueARM64_OpARM64CMPshiftRA_0(v)
 	case OpARM64CMPshiftRL:
-		return rewriteValueARM64_OpARM64CMPshiftRL(v, config)
+		return rewriteValueARM64_OpARM64CMPshiftRL_0(v)
 	case OpARM64CSELULT:
-		return rewriteValueARM64_OpARM64CSELULT(v, config)
+		return rewriteValueARM64_OpARM64CSELULT_0(v)
 	case OpARM64CSELULT0:
-		return rewriteValueARM64_OpARM64CSELULT0(v, config)
+		return rewriteValueARM64_OpARM64CSELULT0_0(v)
 	case OpARM64DIV:
-		return rewriteValueARM64_OpARM64DIV(v, config)
+		return rewriteValueARM64_OpARM64DIV_0(v)
 	case OpARM64DIVW:
-		return rewriteValueARM64_OpARM64DIVW(v, config)
+		return rewriteValueARM64_OpARM64DIVW_0(v)
 	case OpARM64Equal:
-		return rewriteValueARM64_OpARM64Equal(v, config)
+		return rewriteValueARM64_OpARM64Equal_0(v)
 	case OpARM64FMOVDload:
-		return rewriteValueARM64_OpARM64FMOVDload(v, config)
+		return rewriteValueARM64_OpARM64FMOVDload_0(v)
 	case OpARM64FMOVDstore:
-		return rewriteValueARM64_OpARM64FMOVDstore(v, config)
+		return rewriteValueARM64_OpARM64FMOVDstore_0(v)
 	case OpARM64FMOVSload:
-		return rewriteValueARM64_OpARM64FMOVSload(v, config)
+		return rewriteValueARM64_OpARM64FMOVSload_0(v)
 	case OpARM64FMOVSstore:
-		return rewriteValueARM64_OpARM64FMOVSstore(v, config)
+		return rewriteValueARM64_OpARM64FMOVSstore_0(v)
 	case OpARM64GreaterEqual:
-		return rewriteValueARM64_OpARM64GreaterEqual(v, config)
+		return rewriteValueARM64_OpARM64GreaterEqual_0(v)
 	case OpARM64GreaterEqualU:
-		return rewriteValueARM64_OpARM64GreaterEqualU(v, config)
+		return rewriteValueARM64_OpARM64GreaterEqualU_0(v)
 	case OpARM64GreaterThan:
-		return rewriteValueARM64_OpARM64GreaterThan(v, config)
+		return rewriteValueARM64_OpARM64GreaterThan_0(v)
 	case OpARM64GreaterThanU:
-		return rewriteValueARM64_OpARM64GreaterThanU(v, config)
+		return rewriteValueARM64_OpARM64GreaterThanU_0(v)
 	case OpARM64LessEqual:
-		return rewriteValueARM64_OpARM64LessEqual(v, config)
+		return rewriteValueARM64_OpARM64LessEqual_0(v)
 	case OpARM64LessEqualU:
-		return rewriteValueARM64_OpARM64LessEqualU(v, config)
+		return rewriteValueARM64_OpARM64LessEqualU_0(v)
 	case OpARM64LessThan:
-		return rewriteValueARM64_OpARM64LessThan(v, config)
+		return rewriteValueARM64_OpARM64LessThan_0(v)
 	case OpARM64LessThanU:
-		return rewriteValueARM64_OpARM64LessThanU(v, config)
+		return rewriteValueARM64_OpARM64LessThanU_0(v)
 	case OpARM64MOD:
-		return rewriteValueARM64_OpARM64MOD(v, config)
+		return rewriteValueARM64_OpARM64MOD_0(v)
 	case OpARM64MODW:
-		return rewriteValueARM64_OpARM64MODW(v, config)
+		return rewriteValueARM64_OpARM64MODW_0(v)
 	case OpARM64MOVBUload:
-		return rewriteValueARM64_OpARM64MOVBUload(v, config)
+		return rewriteValueARM64_OpARM64MOVBUload_0(v)
 	case OpARM64MOVBUreg:
-		return rewriteValueARM64_OpARM64MOVBUreg(v, config)
+		return rewriteValueARM64_OpARM64MOVBUreg_0(v)
 	case OpARM64MOVBload:
-		return rewriteValueARM64_OpARM64MOVBload(v, config)
+		return rewriteValueARM64_OpARM64MOVBload_0(v)
 	case OpARM64MOVBreg:
-		return rewriteValueARM64_OpARM64MOVBreg(v, config)
+		return rewriteValueARM64_OpARM64MOVBreg_0(v)
 	case OpARM64MOVBstore:
-		return rewriteValueARM64_OpARM64MOVBstore(v, config)
+		return rewriteValueARM64_OpARM64MOVBstore_0(v)
 	case OpARM64MOVBstorezero:
-		return rewriteValueARM64_OpARM64MOVBstorezero(v, config)
+		return rewriteValueARM64_OpARM64MOVBstorezero_0(v)
 	case OpARM64MOVDload:
-		return rewriteValueARM64_OpARM64MOVDload(v, config)
+		return rewriteValueARM64_OpARM64MOVDload_0(v)
 	case OpARM64MOVDreg:
-		return rewriteValueARM64_OpARM64MOVDreg(v, config)
+		return rewriteValueARM64_OpARM64MOVDreg_0(v)
 	case OpARM64MOVDstore:
-		return rewriteValueARM64_OpARM64MOVDstore(v, config)
+		return rewriteValueARM64_OpARM64MOVDstore_0(v)
 	case OpARM64MOVDstorezero:
-		return rewriteValueARM64_OpARM64MOVDstorezero(v, config)
+		return rewriteValueARM64_OpARM64MOVDstorezero_0(v)
 	case OpARM64MOVHUload:
-		return rewriteValueARM64_OpARM64MOVHUload(v, config)
+		return rewriteValueARM64_OpARM64MOVHUload_0(v)
 	case OpARM64MOVHUreg:
-		return rewriteValueARM64_OpARM64MOVHUreg(v, config)
+		return rewriteValueARM64_OpARM64MOVHUreg_0(v)
 	case OpARM64MOVHload:
-		return rewriteValueARM64_OpARM64MOVHload(v, config)
+		return rewriteValueARM64_OpARM64MOVHload_0(v)
 	case OpARM64MOVHreg:
-		return rewriteValueARM64_OpARM64MOVHreg(v, config)
+		return rewriteValueARM64_OpARM64MOVHreg_0(v)
 	case OpARM64MOVHstore:
-		return rewriteValueARM64_OpARM64MOVHstore(v, config)
+		return rewriteValueARM64_OpARM64MOVHstore_0(v)
 	case OpARM64MOVHstorezero:
-		return rewriteValueARM64_OpARM64MOVHstorezero(v, config)
+		return rewriteValueARM64_OpARM64MOVHstorezero_0(v)
 	case OpARM64MOVWUload:
-		return rewriteValueARM64_OpARM64MOVWUload(v, config)
+		return rewriteValueARM64_OpARM64MOVWUload_0(v)
 	case OpARM64MOVWUreg:
-		return rewriteValueARM64_OpARM64MOVWUreg(v, config)
+		return rewriteValueARM64_OpARM64MOVWUreg_0(v)
 	case OpARM64MOVWload:
-		return rewriteValueARM64_OpARM64MOVWload(v, config)
+		return rewriteValueARM64_OpARM64MOVWload_0(v)
 	case OpARM64MOVWreg:
-		return rewriteValueARM64_OpARM64MOVWreg(v, config)
+		return rewriteValueARM64_OpARM64MOVWreg_0(v) || rewriteValueARM64_OpARM64MOVWreg_10(v)
 	case OpARM64MOVWstore:
-		return rewriteValueARM64_OpARM64MOVWstore(v, config)
+		return rewriteValueARM64_OpARM64MOVWstore_0(v)
 	case OpARM64MOVWstorezero:
-		return rewriteValueARM64_OpARM64MOVWstorezero(v, config)
+		return rewriteValueARM64_OpARM64MOVWstorezero_0(v)
 	case OpARM64MUL:
-		return rewriteValueARM64_OpARM64MUL(v, config)
+		return rewriteValueARM64_OpARM64MUL_0(v) || rewriteValueARM64_OpARM64MUL_10(v) || rewriteValueARM64_OpARM64MUL_20(v)
 	case OpARM64MULW:
-		return rewriteValueARM64_OpARM64MULW(v, config)
+		return rewriteValueARM64_OpARM64MULW_0(v) || rewriteValueARM64_OpARM64MULW_10(v) || rewriteValueARM64_OpARM64MULW_20(v)
 	case OpARM64MVN:
-		return rewriteValueARM64_OpARM64MVN(v, config)
+		return rewriteValueARM64_OpARM64MVN_0(v)
 	case OpARM64NEG:
-		return rewriteValueARM64_OpARM64NEG(v, config)
+		return rewriteValueARM64_OpARM64NEG_0(v)
 	case OpARM64NotEqual:
-		return rewriteValueARM64_OpARM64NotEqual(v, config)
+		return rewriteValueARM64_OpARM64NotEqual_0(v)
 	case OpARM64OR:
-		return rewriteValueARM64_OpARM64OR(v, config)
+		return rewriteValueARM64_OpARM64OR_0(v) || rewriteValueARM64_OpARM64OR_10(v)
 	case OpARM64ORconst:
-		return rewriteValueARM64_OpARM64ORconst(v, config)
+		return rewriteValueARM64_OpARM64ORconst_0(v)
 	case OpARM64ORshiftLL:
-		return rewriteValueARM64_OpARM64ORshiftLL(v, config)
+		return rewriteValueARM64_OpARM64ORshiftLL_0(v) || rewriteValueARM64_OpARM64ORshiftLL_10(v)
 	case OpARM64ORshiftRA:
-		return rewriteValueARM64_OpARM64ORshiftRA(v, config)
+		return rewriteValueARM64_OpARM64ORshiftRA_0(v)
 	case OpARM64ORshiftRL:
-		return rewriteValueARM64_OpARM64ORshiftRL(v, config)
+		return rewriteValueARM64_OpARM64ORshiftRL_0(v)
 	case OpARM64SLL:
-		return rewriteValueARM64_OpARM64SLL(v, config)
+		return rewriteValueARM64_OpARM64SLL_0(v)
 	case OpARM64SLLconst:
-		return rewriteValueARM64_OpARM64SLLconst(v, config)
+		return rewriteValueARM64_OpARM64SLLconst_0(v)
 	case OpARM64SRA:
-		return rewriteValueARM64_OpARM64SRA(v, config)
+		return rewriteValueARM64_OpARM64SRA_0(v)
 	case OpARM64SRAconst:
-		return rewriteValueARM64_OpARM64SRAconst(v, config)
+		return rewriteValueARM64_OpARM64SRAconst_0(v)
 	case OpARM64SRL:
-		return rewriteValueARM64_OpARM64SRL(v, config)
+		return rewriteValueARM64_OpARM64SRL_0(v)
 	case OpARM64SRLconst:
-		return rewriteValueARM64_OpARM64SRLconst(v, config)
+		return rewriteValueARM64_OpARM64SRLconst_0(v)
 	case OpARM64SUB:
-		return rewriteValueARM64_OpARM64SUB(v, config)
+		return rewriteValueARM64_OpARM64SUB_0(v)
 	case OpARM64SUBconst:
-		return rewriteValueARM64_OpARM64SUBconst(v, config)
+		return rewriteValueARM64_OpARM64SUBconst_0(v)
 	case OpARM64SUBshiftLL:
-		return rewriteValueARM64_OpARM64SUBshiftLL(v, config)
+		return rewriteValueARM64_OpARM64SUBshiftLL_0(v)
 	case OpARM64SUBshiftRA:
-		return rewriteValueARM64_OpARM64SUBshiftRA(v, config)
+		return rewriteValueARM64_OpARM64SUBshiftRA_0(v)
 	case OpARM64SUBshiftRL:
-		return rewriteValueARM64_OpARM64SUBshiftRL(v, config)
+		return rewriteValueARM64_OpARM64SUBshiftRL_0(v)
 	case OpARM64UDIV:
-		return rewriteValueARM64_OpARM64UDIV(v, config)
+		return rewriteValueARM64_OpARM64UDIV_0(v)
 	case OpARM64UDIVW:
-		return rewriteValueARM64_OpARM64UDIVW(v, config)
+		return rewriteValueARM64_OpARM64UDIVW_0(v)
 	case OpARM64UMOD:
-		return rewriteValueARM64_OpARM64UMOD(v, config)
+		return rewriteValueARM64_OpARM64UMOD_0(v)
 	case OpARM64UMODW:
-		return rewriteValueARM64_OpARM64UMODW(v, config)
+		return rewriteValueARM64_OpARM64UMODW_0(v)
 	case OpARM64XOR:
-		return rewriteValueARM64_OpARM64XOR(v, config)
+		return rewriteValueARM64_OpARM64XOR_0(v)
 	case OpARM64XORconst:
-		return rewriteValueARM64_OpARM64XORconst(v, config)
+		return rewriteValueARM64_OpARM64XORconst_0(v)
 	case OpARM64XORshiftLL:
-		return rewriteValueARM64_OpARM64XORshiftLL(v, config)
+		return rewriteValueARM64_OpARM64XORshiftLL_0(v)
 	case OpARM64XORshiftRA:
-		return rewriteValueARM64_OpARM64XORshiftRA(v, config)
+		return rewriteValueARM64_OpARM64XORshiftRA_0(v)
 	case OpARM64XORshiftRL:
-		return rewriteValueARM64_OpARM64XORshiftRL(v, config)
+		return rewriteValueARM64_OpARM64XORshiftRL_0(v)
 	case OpAdd16:
-		return rewriteValueARM64_OpAdd16(v, config)
+		return rewriteValueARM64_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueARM64_OpAdd32(v, config)
+		return rewriteValueARM64_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueARM64_OpAdd32F(v, config)
+		return rewriteValueARM64_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValueARM64_OpAdd64(v, config)
+		return rewriteValueARM64_OpAdd64_0(v)
 	case OpAdd64F:
-		return rewriteValueARM64_OpAdd64F(v, config)
+		return rewriteValueARM64_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueARM64_OpAdd8(v, config)
+		return rewriteValueARM64_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueARM64_OpAddPtr(v, config)
+		return rewriteValueARM64_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueARM64_OpAddr(v, config)
+		return rewriteValueARM64_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueARM64_OpAnd16(v, config)
+		return rewriteValueARM64_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueARM64_OpAnd32(v, config)
+		return rewriteValueARM64_OpAnd32_0(v)
 	case OpAnd64:
-		return rewriteValueARM64_OpAnd64(v, config)
+		return rewriteValueARM64_OpAnd64_0(v)
 	case OpAnd8:
-		return rewriteValueARM64_OpAnd8(v, config)
+		return rewriteValueARM64_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueARM64_OpAndB(v, config)
+		return rewriteValueARM64_OpAndB_0(v)
 	case OpAtomicAdd32:
-		return rewriteValueARM64_OpAtomicAdd32(v, config)
+		return rewriteValueARM64_OpAtomicAdd32_0(v)
 	case OpAtomicAdd64:
-		return rewriteValueARM64_OpAtomicAdd64(v, config)
+		return rewriteValueARM64_OpAtomicAdd64_0(v)
 	case OpAtomicAnd8:
-		return rewriteValueARM64_OpAtomicAnd8(v, config)
+		return rewriteValueARM64_OpAtomicAnd8_0(v)
 	case OpAtomicCompareAndSwap32:
-		return rewriteValueARM64_OpAtomicCompareAndSwap32(v, config)
+		return rewriteValueARM64_OpAtomicCompareAndSwap32_0(v)
 	case OpAtomicCompareAndSwap64:
-		return rewriteValueARM64_OpAtomicCompareAndSwap64(v, config)
+		return rewriteValueARM64_OpAtomicCompareAndSwap64_0(v)
 	case OpAtomicExchange32:
-		return rewriteValueARM64_OpAtomicExchange32(v, config)
+		return rewriteValueARM64_OpAtomicExchange32_0(v)
 	case OpAtomicExchange64:
-		return rewriteValueARM64_OpAtomicExchange64(v, config)
+		return rewriteValueARM64_OpAtomicExchange64_0(v)
 	case OpAtomicLoad32:
-		return rewriteValueARM64_OpAtomicLoad32(v, config)
+		return rewriteValueARM64_OpAtomicLoad32_0(v)
 	case OpAtomicLoad64:
-		return rewriteValueARM64_OpAtomicLoad64(v, config)
+		return rewriteValueARM64_OpAtomicLoad64_0(v)
 	case OpAtomicLoadPtr:
-		return rewriteValueARM64_OpAtomicLoadPtr(v, config)
+		return rewriteValueARM64_OpAtomicLoadPtr_0(v)
 	case OpAtomicOr8:
-		return rewriteValueARM64_OpAtomicOr8(v, config)
+		return rewriteValueARM64_OpAtomicOr8_0(v)
 	case OpAtomicStore32:
-		return rewriteValueARM64_OpAtomicStore32(v, config)
+		return rewriteValueARM64_OpAtomicStore32_0(v)
 	case OpAtomicStore64:
-		return rewriteValueARM64_OpAtomicStore64(v, config)
+		return rewriteValueARM64_OpAtomicStore64_0(v)
 	case OpAtomicStorePtrNoWB:
-		return rewriteValueARM64_OpAtomicStorePtrNoWB(v, config)
+		return rewriteValueARM64_OpAtomicStorePtrNoWB_0(v)
 	case OpAvg64u:
-		return rewriteValueARM64_OpAvg64u(v, config)
+		return rewriteValueARM64_OpAvg64u_0(v)
+	case OpBitLen64:
+		return rewriteValueARM64_OpBitLen64_0(v)
+	case OpBitRev16:
+		return rewriteValueARM64_OpBitRev16_0(v)
+	case OpBitRev32:
+		return rewriteValueARM64_OpBitRev32_0(v)
+	case OpBitRev64:
+		return rewriteValueARM64_OpBitRev64_0(v)
+	case OpBitRev8:
+		return rewriteValueARM64_OpBitRev8_0(v)
 	case OpBswap32:
-		return rewriteValueARM64_OpBswap32(v, config)
+		return rewriteValueARM64_OpBswap32_0(v)
 	case OpBswap64:
-		return rewriteValueARM64_OpBswap64(v, config)
+		return rewriteValueARM64_OpBswap64_0(v)
 	case OpClosureCall:
-		return rewriteValueARM64_OpClosureCall(v, config)
+		return rewriteValueARM64_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueARM64_OpCom16(v, config)
+		return rewriteValueARM64_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueARM64_OpCom32(v, config)
+		return rewriteValueARM64_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValueARM64_OpCom64(v, config)
+		return rewriteValueARM64_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValueARM64_OpCom8(v, config)
+		return rewriteValueARM64_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueARM64_OpConst16(v, config)
+		return rewriteValueARM64_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueARM64_OpConst32(v, config)
+		return rewriteValueARM64_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueARM64_OpConst32F(v, config)
+		return rewriteValueARM64_OpConst32F_0(v)
 	case OpConst64:
-		return rewriteValueARM64_OpConst64(v, config)
+		return rewriteValueARM64_OpConst64_0(v)
 	case OpConst64F:
-		return rewriteValueARM64_OpConst64F(v, config)
+		return rewriteValueARM64_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueARM64_OpConst8(v, config)
+		return rewriteValueARM64_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueARM64_OpConstBool(v, config)
+		return rewriteValueARM64_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueARM64_OpConstNil(v, config)
+		return rewriteValueARM64_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueARM64_OpConvert(v, config)
+		return rewriteValueARM64_OpConvert_0(v)
 	case OpCtz32:
-		return rewriteValueARM64_OpCtz32(v, config)
+		return rewriteValueARM64_OpCtz32_0(v)
 	case OpCtz64:
-		return rewriteValueARM64_OpCtz64(v, config)
+		return rewriteValueARM64_OpCtz64_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueARM64_OpCvt32Fto32(v, config)
+		return rewriteValueARM64_OpCvt32Fto32_0(v)
 	case OpCvt32Fto32U:
-		return rewriteValueARM64_OpCvt32Fto32U(v, config)
+		return rewriteValueARM64_OpCvt32Fto32U_0(v)
 	case OpCvt32Fto64:
-		return rewriteValueARM64_OpCvt32Fto64(v, config)
+		return rewriteValueARM64_OpCvt32Fto64_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueARM64_OpCvt32Fto64F(v, config)
+		return rewriteValueARM64_OpCvt32Fto64F_0(v)
 	case OpCvt32Fto64U:
-		return rewriteValueARM64_OpCvt32Fto64U(v, config)
+		return rewriteValueARM64_OpCvt32Fto64U_0(v)
 	case OpCvt32Uto32F:
-		return rewriteValueARM64_OpCvt32Uto32F(v, config)
+		return rewriteValueARM64_OpCvt32Uto32F_0(v)
 	case OpCvt32Uto64F:
-		return rewriteValueARM64_OpCvt32Uto64F(v, config)
+		return rewriteValueARM64_OpCvt32Uto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueARM64_OpCvt32to32F(v, config)
+		return rewriteValueARM64_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueARM64_OpCvt32to64F(v, config)
+		return rewriteValueARM64_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueARM64_OpCvt64Fto32(v, config)
+		return rewriteValueARM64_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueARM64_OpCvt64Fto32F(v, config)
+		return rewriteValueARM64_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto32U:
-		return rewriteValueARM64_OpCvt64Fto32U(v, config)
+		return rewriteValueARM64_OpCvt64Fto32U_0(v)
 	case OpCvt64Fto64:
-		return rewriteValueARM64_OpCvt64Fto64(v, config)
+		return rewriteValueARM64_OpCvt64Fto64_0(v)
 	case OpCvt64Fto64U:
-		return rewriteValueARM64_OpCvt64Fto64U(v, config)
+		return rewriteValueARM64_OpCvt64Fto64U_0(v)
 	case OpCvt64Uto32F:
-		return rewriteValueARM64_OpCvt64Uto32F(v, config)
+		return rewriteValueARM64_OpCvt64Uto32F_0(v)
 	case OpCvt64Uto64F:
-		return rewriteValueARM64_OpCvt64Uto64F(v, config)
+		return rewriteValueARM64_OpCvt64Uto64F_0(v)
 	case OpCvt64to32F:
-		return rewriteValueARM64_OpCvt64to32F(v, config)
+		return rewriteValueARM64_OpCvt64to32F_0(v)
 	case OpCvt64to64F:
-		return rewriteValueARM64_OpCvt64to64F(v, config)
-	case OpDeferCall:
-		return rewriteValueARM64_OpDeferCall(v, config)
+		return rewriteValueARM64_OpCvt64to64F_0(v)
 	case OpDiv16:
-		return rewriteValueARM64_OpDiv16(v, config)
+		return rewriteValueARM64_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueARM64_OpDiv16u(v, config)
+		return rewriteValueARM64_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueARM64_OpDiv32(v, config)
+		return rewriteValueARM64_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueARM64_OpDiv32F(v, config)
+		return rewriteValueARM64_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueARM64_OpDiv32u(v, config)
+		return rewriteValueARM64_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValueARM64_OpDiv64(v, config)
+		return rewriteValueARM64_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValueARM64_OpDiv64F(v, config)
+		return rewriteValueARM64_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValueARM64_OpDiv64u(v, config)
+		return rewriteValueARM64_OpDiv64u_0(v)
 	case OpDiv8:
-		return rewriteValueARM64_OpDiv8(v, config)
+		return rewriteValueARM64_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueARM64_OpDiv8u(v, config)
+		return rewriteValueARM64_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueARM64_OpEq16(v, config)
+		return rewriteValueARM64_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueARM64_OpEq32(v, config)
+		return rewriteValueARM64_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueARM64_OpEq32F(v, config)
+		return rewriteValueARM64_OpEq32F_0(v)
 	case OpEq64:
-		return rewriteValueARM64_OpEq64(v, config)
+		return rewriteValueARM64_OpEq64_0(v)
 	case OpEq64F:
-		return rewriteValueARM64_OpEq64F(v, config)
+		return rewriteValueARM64_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueARM64_OpEq8(v, config)
+		return rewriteValueARM64_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueARM64_OpEqB(v, config)
+		return rewriteValueARM64_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueARM64_OpEqPtr(v, config)
+		return rewriteValueARM64_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueARM64_OpGeq16(v, config)
+		return rewriteValueARM64_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueARM64_OpGeq16U(v, config)
+		return rewriteValueARM64_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueARM64_OpGeq32(v, config)
+		return rewriteValueARM64_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueARM64_OpGeq32F(v, config)
+		return rewriteValueARM64_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueARM64_OpGeq32U(v, config)
+		return rewriteValueARM64_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValueARM64_OpGeq64(v, config)
+		return rewriteValueARM64_OpGeq64_0(v)
 	case OpGeq64F:
-		return rewriteValueARM64_OpGeq64F(v, config)
+		return rewriteValueARM64_OpGeq64F_0(v)
 	case OpGeq64U:
-		return rewriteValueARM64_OpGeq64U(v, config)
+		return rewriteValueARM64_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValueARM64_OpGeq8(v, config)
+		return rewriteValueARM64_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueARM64_OpGeq8U(v, config)
+		return rewriteValueARM64_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueARM64_OpGetClosurePtr(v, config)
-	case OpGoCall:
-		return rewriteValueARM64_OpGoCall(v, config)
+		return rewriteValueARM64_OpGetClosurePtr_0(v)
 	case OpGreater16:
-		return rewriteValueARM64_OpGreater16(v, config)
+		return rewriteValueARM64_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueARM64_OpGreater16U(v, config)
+		return rewriteValueARM64_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueARM64_OpGreater32(v, config)
+		return rewriteValueARM64_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueARM64_OpGreater32F(v, config)
+		return rewriteValueARM64_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueARM64_OpGreater32U(v, config)
+		return rewriteValueARM64_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValueARM64_OpGreater64(v, config)
+		return rewriteValueARM64_OpGreater64_0(v)
 	case OpGreater64F:
-		return rewriteValueARM64_OpGreater64F(v, config)
+		return rewriteValueARM64_OpGreater64F_0(v)
 	case OpGreater64U:
-		return rewriteValueARM64_OpGreater64U(v, config)
+		return rewriteValueARM64_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValueARM64_OpGreater8(v, config)
+		return rewriteValueARM64_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueARM64_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueARM64_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueARM64_OpHmul16u(v, config)
+		return rewriteValueARM64_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueARM64_OpHmul32(v, config)
+		return rewriteValueARM64_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueARM64_OpHmul32u(v, config)
+		return rewriteValueARM64_OpHmul32u_0(v)
 	case OpHmul64:
-		return rewriteValueARM64_OpHmul64(v, config)
+		return rewriteValueARM64_OpHmul64_0(v)
 	case OpHmul64u:
-		return rewriteValueARM64_OpHmul64u(v, config)
-	case OpHmul8:
-		return rewriteValueARM64_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueARM64_OpHmul8u(v, config)
+		return rewriteValueARM64_OpHmul64u_0(v)
 	case OpInterCall:
-		return rewriteValueARM64_OpInterCall(v, config)
+		return rewriteValueARM64_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueARM64_OpIsInBounds(v, config)
+		return rewriteValueARM64_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueARM64_OpIsNonNil(v, config)
+		return rewriteValueARM64_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueARM64_OpIsSliceInBounds(v, config)
+		return rewriteValueARM64_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueARM64_OpLeq16(v, config)
+		return rewriteValueARM64_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueARM64_OpLeq16U(v, config)
+		return rewriteValueARM64_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueARM64_OpLeq32(v, config)
+		return rewriteValueARM64_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueARM64_OpLeq32F(v, config)
+		return rewriteValueARM64_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueARM64_OpLeq32U(v, config)
+		return rewriteValueARM64_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValueARM64_OpLeq64(v, config)
+		return rewriteValueARM64_OpLeq64_0(v)
 	case OpLeq64F:
-		return rewriteValueARM64_OpLeq64F(v, config)
+		return rewriteValueARM64_OpLeq64F_0(v)
 	case OpLeq64U:
-		return rewriteValueARM64_OpLeq64U(v, config)
+		return rewriteValueARM64_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValueARM64_OpLeq8(v, config)
+		return rewriteValueARM64_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueARM64_OpLeq8U(v, config)
+		return rewriteValueARM64_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueARM64_OpLess16(v, config)
+		return rewriteValueARM64_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueARM64_OpLess16U(v, config)
+		return rewriteValueARM64_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueARM64_OpLess32(v, config)
+		return rewriteValueARM64_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueARM64_OpLess32F(v, config)
+		return rewriteValueARM64_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueARM64_OpLess32U(v, config)
+		return rewriteValueARM64_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValueARM64_OpLess64(v, config)
+		return rewriteValueARM64_OpLess64_0(v)
 	case OpLess64F:
-		return rewriteValueARM64_OpLess64F(v, config)
+		return rewriteValueARM64_OpLess64F_0(v)
 	case OpLess64U:
-		return rewriteValueARM64_OpLess64U(v, config)
+		return rewriteValueARM64_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValueARM64_OpLess8(v, config)
+		return rewriteValueARM64_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueARM64_OpLess8U(v, config)
+		return rewriteValueARM64_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValueARM64_OpLoad(v, config)
-	case OpLrot16:
-		return rewriteValueARM64_OpLrot16(v, config)
-	case OpLrot32:
-		return rewriteValueARM64_OpLrot32(v, config)
-	case OpLrot64:
-		return rewriteValueARM64_OpLrot64(v, config)
-	case OpLrot8:
-		return rewriteValueARM64_OpLrot8(v, config)
+		return rewriteValueARM64_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueARM64_OpLsh16x16(v, config)
+		return rewriteValueARM64_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueARM64_OpLsh16x32(v, config)
+		return rewriteValueARM64_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueARM64_OpLsh16x64(v, config)
+		return rewriteValueARM64_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueARM64_OpLsh16x8(v, config)
+		return rewriteValueARM64_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueARM64_OpLsh32x16(v, config)
+		return rewriteValueARM64_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueARM64_OpLsh32x32(v, config)
+		return rewriteValueARM64_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueARM64_OpLsh32x64(v, config)
+		return rewriteValueARM64_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueARM64_OpLsh32x8(v, config)
+		return rewriteValueARM64_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValueARM64_OpLsh64x16(v, config)
+		return rewriteValueARM64_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValueARM64_OpLsh64x32(v, config)
+		return rewriteValueARM64_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValueARM64_OpLsh64x64(v, config)
+		return rewriteValueARM64_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValueARM64_OpLsh64x8(v, config)
+		return rewriteValueARM64_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueARM64_OpLsh8x16(v, config)
+		return rewriteValueARM64_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueARM64_OpLsh8x32(v, config)
+		return rewriteValueARM64_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueARM64_OpLsh8x64(v, config)
+		return rewriteValueARM64_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueARM64_OpLsh8x8(v, config)
+		return rewriteValueARM64_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValueARM64_OpMod16(v, config)
+		return rewriteValueARM64_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueARM64_OpMod16u(v, config)
+		return rewriteValueARM64_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueARM64_OpMod32(v, config)
+		return rewriteValueARM64_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueARM64_OpMod32u(v, config)
+		return rewriteValueARM64_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValueARM64_OpMod64(v, config)
+		return rewriteValueARM64_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValueARM64_OpMod64u(v, config)
+		return rewriteValueARM64_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValueARM64_OpMod8(v, config)
+		return rewriteValueARM64_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueARM64_OpMod8u(v, config)
+		return rewriteValueARM64_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueARM64_OpMove(v, config)
+		return rewriteValueARM64_OpMove_0(v) || rewriteValueARM64_OpMove_10(v)
 	case OpMul16:
-		return rewriteValueARM64_OpMul16(v, config)
+		return rewriteValueARM64_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueARM64_OpMul32(v, config)
+		return rewriteValueARM64_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueARM64_OpMul32F(v, config)
+		return rewriteValueARM64_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValueARM64_OpMul64(v, config)
+		return rewriteValueARM64_OpMul64_0(v)
 	case OpMul64F:
-		return rewriteValueARM64_OpMul64F(v, config)
+		return rewriteValueARM64_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValueARM64_OpMul8(v, config)
+		return rewriteValueARM64_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueARM64_OpNeg16(v, config)
+		return rewriteValueARM64_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueARM64_OpNeg32(v, config)
+		return rewriteValueARM64_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueARM64_OpNeg32F(v, config)
+		return rewriteValueARM64_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValueARM64_OpNeg64(v, config)
+		return rewriteValueARM64_OpNeg64_0(v)
 	case OpNeg64F:
-		return rewriteValueARM64_OpNeg64F(v, config)
+		return rewriteValueARM64_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueARM64_OpNeg8(v, config)
+		return rewriteValueARM64_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueARM64_OpNeq16(v, config)
+		return rewriteValueARM64_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueARM64_OpNeq32(v, config)
+		return rewriteValueARM64_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueARM64_OpNeq32F(v, config)
+		return rewriteValueARM64_OpNeq32F_0(v)
 	case OpNeq64:
-		return rewriteValueARM64_OpNeq64(v, config)
+		return rewriteValueARM64_OpNeq64_0(v)
 	case OpNeq64F:
-		return rewriteValueARM64_OpNeq64F(v, config)
+		return rewriteValueARM64_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueARM64_OpNeq8(v, config)
+		return rewriteValueARM64_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueARM64_OpNeqB(v, config)
+		return rewriteValueARM64_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueARM64_OpNeqPtr(v, config)
+		return rewriteValueARM64_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueARM64_OpNilCheck(v, config)
+		return rewriteValueARM64_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueARM64_OpNot(v, config)
+		return rewriteValueARM64_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueARM64_OpOffPtr(v, config)
+		return rewriteValueARM64_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueARM64_OpOr16(v, config)
+		return rewriteValueARM64_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueARM64_OpOr32(v, config)
+		return rewriteValueARM64_OpOr32_0(v)
 	case OpOr64:
-		return rewriteValueARM64_OpOr64(v, config)
+		return rewriteValueARM64_OpOr64_0(v)
 	case OpOr8:
-		return rewriteValueARM64_OpOr8(v, config)
+		return rewriteValueARM64_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueARM64_OpOrB(v, config)
+		return rewriteValueARM64_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValueARM64_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueARM64_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueARM64_OpRsh16Ux16(v, config)
+		return rewriteValueARM64_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueARM64_OpRsh16Ux32(v, config)
+		return rewriteValueARM64_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueARM64_OpRsh16Ux64(v, config)
+		return rewriteValueARM64_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueARM64_OpRsh16Ux8(v, config)
+		return rewriteValueARM64_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueARM64_OpRsh16x16(v, config)
+		return rewriteValueARM64_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueARM64_OpRsh16x32(v, config)
+		return rewriteValueARM64_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueARM64_OpRsh16x64(v, config)
+		return rewriteValueARM64_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueARM64_OpRsh16x8(v, config)
+		return rewriteValueARM64_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueARM64_OpRsh32Ux16(v, config)
+		return rewriteValueARM64_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueARM64_OpRsh32Ux32(v, config)
+		return rewriteValueARM64_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueARM64_OpRsh32Ux64(v, config)
+		return rewriteValueARM64_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueARM64_OpRsh32Ux8(v, config)
+		return rewriteValueARM64_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueARM64_OpRsh32x16(v, config)
+		return rewriteValueARM64_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueARM64_OpRsh32x32(v, config)
+		return rewriteValueARM64_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueARM64_OpRsh32x64(v, config)
+		return rewriteValueARM64_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueARM64_OpRsh32x8(v, config)
+		return rewriteValueARM64_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValueARM64_OpRsh64Ux16(v, config)
+		return rewriteValueARM64_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValueARM64_OpRsh64Ux32(v, config)
+		return rewriteValueARM64_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValueARM64_OpRsh64Ux64(v, config)
+		return rewriteValueARM64_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValueARM64_OpRsh64Ux8(v, config)
+		return rewriteValueARM64_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValueARM64_OpRsh64x16(v, config)
+		return rewriteValueARM64_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValueARM64_OpRsh64x32(v, config)
+		return rewriteValueARM64_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValueARM64_OpRsh64x64(v, config)
+		return rewriteValueARM64_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValueARM64_OpRsh64x8(v, config)
+		return rewriteValueARM64_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueARM64_OpRsh8Ux16(v, config)
+		return rewriteValueARM64_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueARM64_OpRsh8Ux32(v, config)
+		return rewriteValueARM64_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueARM64_OpRsh8Ux64(v, config)
+		return rewriteValueARM64_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueARM64_OpRsh8Ux8(v, config)
+		return rewriteValueARM64_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueARM64_OpRsh8x16(v, config)
+		return rewriteValueARM64_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueARM64_OpRsh8x32(v, config)
+		return rewriteValueARM64_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueARM64_OpRsh8x64(v, config)
+		return rewriteValueARM64_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueARM64_OpRsh8x8(v, config)
+		return rewriteValueARM64_OpRsh8x8_0(v)
 	case OpSignExt16to32:
-		return rewriteValueARM64_OpSignExt16to32(v, config)
+		return rewriteValueARM64_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValueARM64_OpSignExt16to64(v, config)
+		return rewriteValueARM64_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValueARM64_OpSignExt32to64(v, config)
+		return rewriteValueARM64_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValueARM64_OpSignExt8to16(v, config)
+		return rewriteValueARM64_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueARM64_OpSignExt8to32(v, config)
+		return rewriteValueARM64_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValueARM64_OpSignExt8to64(v, config)
+		return rewriteValueARM64_OpSignExt8to64_0(v)
 	case OpSlicemask:
-		return rewriteValueARM64_OpSlicemask(v, config)
+		return rewriteValueARM64_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValueARM64_OpSqrt(v, config)
+		return rewriteValueARM64_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValueARM64_OpStaticCall(v, config)
+		return rewriteValueARM64_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueARM64_OpStore(v, config)
+		return rewriteValueARM64_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueARM64_OpSub16(v, config)
+		return rewriteValueARM64_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueARM64_OpSub32(v, config)
+		return rewriteValueARM64_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueARM64_OpSub32F(v, config)
+		return rewriteValueARM64_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValueARM64_OpSub64(v, config)
+		return rewriteValueARM64_OpSub64_0(v)
 	case OpSub64F:
-		return rewriteValueARM64_OpSub64F(v, config)
+		return rewriteValueARM64_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueARM64_OpSub8(v, config)
+		return rewriteValueARM64_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueARM64_OpSubPtr(v, config)
+		return rewriteValueARM64_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueARM64_OpTrunc16to8(v, config)
+		return rewriteValueARM64_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueARM64_OpTrunc32to16(v, config)
+		return rewriteValueARM64_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueARM64_OpTrunc32to8(v, config)
+		return rewriteValueARM64_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValueARM64_OpTrunc64to16(v, config)
+		return rewriteValueARM64_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValueARM64_OpTrunc64to32(v, config)
+		return rewriteValueARM64_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValueARM64_OpTrunc64to8(v, config)
+		return rewriteValueARM64_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValueARM64_OpXor16(v, config)
+		return rewriteValueARM64_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueARM64_OpXor32(v, config)
+		return rewriteValueARM64_OpXor32_0(v)
 	case OpXor64:
-		return rewriteValueARM64_OpXor64(v, config)
+		return rewriteValueARM64_OpXor64_0(v)
 	case OpXor8:
-		return rewriteValueARM64_OpXor8(v, config)
+		return rewriteValueARM64_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueARM64_OpZero(v, config)
+		return rewriteValueARM64_OpZero_0(v) || rewriteValueARM64_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValueARM64_OpZeroExt16to32(v, config)
+		return rewriteValueARM64_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValueARM64_OpZeroExt16to64(v, config)
+		return rewriteValueARM64_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValueARM64_OpZeroExt32to64(v, config)
+		return rewriteValueARM64_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueARM64_OpZeroExt8to16(v, config)
+		return rewriteValueARM64_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueARM64_OpZeroExt8to32(v, config)
+		return rewriteValueARM64_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValueARM64_OpZeroExt8to64(v, config)
+		return rewriteValueARM64_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADD (MOVDconst [c]) x)
+func rewriteValueARM64_OpARM64ADD_0(v *Value) bool {
+	// match: (ADD x (MOVDconst [c]))
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARM64ADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADD x (MOVDconst [c]))
+	// match: (ADD (MOVDconst [c]) x)
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARM64ADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -756,6 +757,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64NEG {
@@ -771,6 +773,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64NEG {
 			break
@@ -786,6 +789,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -803,6 +807,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SLLconst {
 			break
@@ -820,6 +825,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -837,6 +843,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRLconst {
 			break
@@ -854,6 +861,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -871,6 +879,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRAconst {
 			break
@@ -886,9 +895,7 @@ func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ADDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64ADDconst_0(v *Value) bool {
 	// match: (ADDconst [off1] (MOVDaddr [off2] {sym} ptr))
 	// cond:
 	// result: (MOVDaddr [off1+off2] {sym} ptr)
@@ -907,7 +914,7 @@ func rewriteValueARM64_OpARM64ADDconst(v *Value, config *Config) bool {
 		v.AddArg(ptr)
 		return true
 	}
-	// match: (ADDconst [0]  x)
+	// match: (ADDconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -968,7 +975,7 @@ func rewriteValueARM64_OpARM64ADDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ADDshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftLL (MOVDconst [c]) x [d])
@@ -976,6 +983,7 @@ func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -984,7 +992,7 @@ func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -995,6 +1003,7 @@ func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1006,9 +1015,61 @@ func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDshiftLL [c] (SRLconst x [64-c]) x)
+	// cond:
+	// result: (RORconst [64-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = 64 - c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x)
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [32-c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpARM64MOVWUreg {
+			break
+		}
+		x := v_0_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ADDshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRA (MOVDconst [c]) x [d])
@@ -1016,6 +1077,7 @@ func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1024,7 +1086,7 @@ func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1035,6 +1097,7 @@ func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1048,7 +1111,7 @@ func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ADDshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ADDshiftRL (MOVDconst [c]) x [d])
@@ -1056,6 +1119,7 @@ func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
 	// result: (ADDconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1064,7 +1128,7 @@ func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ADDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1075,6 +1139,7 @@ func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
 	// result: (ADDconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1086,30 +1151,66 @@ func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AND (MOVDconst [c]) x)
+	// match: (ADDshiftRL [c] (SLLconst x [64-c]) x)
 	// cond:
-	// result: (ANDconst [c] x)
+	// result: (RORconst [   c] x)
 	for {
+		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		if v_0.Op != OpARM64SLLconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpARM64ANDconst)
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x))
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [   c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVWUreg {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
+	return false
+}
+func rewriteValueARM64_OpARM64AND_0(v *Value) bool {
 	// match: (AND x (MOVDconst [c]))
 	// cond:
 	// result: (ANDconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1121,10 +1222,27 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (AND (MOVDconst [c]) x)
+	// cond:
+	// result: (ANDconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpARM64ANDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (AND x x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -1138,6 +1256,7 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (BIC x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MVN {
@@ -1149,10 +1268,27 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (AND (MVN y) x)
+	// cond:
+	// result: (BIC x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MVN {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpARM64BIC)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (AND x (SLLconst [c] y))
 	// cond:
 	// result: (ANDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -1170,6 +1306,7 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SLLconst {
 			break
@@ -1187,6 +1324,7 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -1204,6 +1342,7 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRLconst {
 			break
@@ -1221,6 +1360,7 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -1234,10 +1374,14 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	return false
+}
+func rewriteValueARM64_OpARM64AND_10(v *Value) bool {
 	// match: (AND (SRAconst [c] y) x)
 	// cond:
 	// result: (ANDshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRAconst {
 			break
@@ -1253,10 +1397,8 @@ func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ANDconst [0]  _)
+func rewriteValueARM64_OpARM64ANDconst_0(v *Value) bool {
+	// match: (ANDconst [0] _)
 	// cond:
 	// result: (MOVDconst [0])
 	for {
@@ -1312,7 +1454,7 @@ func rewriteValueARM64_OpARM64ANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ANDshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftLL (MOVDconst [c]) x [d])
@@ -1320,6 +1462,7 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1328,7 +1471,7 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1339,6 +1482,7 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1355,6 +1499,7 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SLLconst {
@@ -1374,7 +1519,7 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ANDshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRA (MOVDconst [c]) x [d])
@@ -1382,6 +1527,7 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1390,7 +1536,7 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1401,6 +1547,7 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1417,6 +1564,7 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SRAconst {
@@ -1436,7 +1584,7 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ANDshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ANDshiftRL (MOVDconst [c]) x [d])
@@ -1444,6 +1592,7 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
 	// result: (ANDconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1452,7 +1601,7 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ANDconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1463,6 +1612,7 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
 	// result: (ANDconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1479,6 +1629,7 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SRLconst {
@@ -1498,13 +1649,12 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64BIC_0(v *Value) bool {
 	// match: (BIC x (MOVDconst [c]))
 	// cond:
 	// result: (BICconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1520,6 +1670,7 @@ func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -1532,6 +1683,7 @@ func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -1549,6 +1701,7 @@ func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -1566,6 +1719,7 @@ func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
 	// cond:
 	// result: (BICshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -1581,10 +1735,8 @@ func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64BICconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (BICconst [0]  x)
+func rewriteValueARM64_OpARM64BICconst_0(v *Value) bool {
+	// match: (BICconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -1624,14 +1776,13 @@ func rewriteValueARM64_OpARM64BICconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64BICshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64BICshiftLL_0(v *Value) bool {
 	// match: (BICshiftLL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1648,6 +1799,7 @@ func rewriteValueARM64_OpARM64BICshiftLL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -1666,14 +1818,13 @@ func rewriteValueARM64_OpARM64BICshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64BICshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64BICshiftRA_0(v *Value) bool {
 	// match: (BICshiftRA x (MOVDconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1690,6 +1841,7 @@ func rewriteValueARM64_OpARM64BICshiftRA(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -1708,14 +1860,13 @@ func rewriteValueARM64_OpARM64BICshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64BICshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64BICshiftRL_0(v *Value) bool {
 	// match: (BICshiftRL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (BICconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1732,6 +1883,7 @@ func rewriteValueARM64_OpARM64BICshiftRL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -1750,13 +1902,14 @@ func rewriteValueARM64_OpARM64BICshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64CMP_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMP x (MOVDconst [c]))
 	// cond:
 	// result: (CMPconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1772,6 +1925,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPconst [c] x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1779,7 +1933,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1789,6 +1943,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -1806,6 +1961,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftLL x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SLLconst {
 			break
@@ -1814,7 +1970,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPshiftLL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPshiftLL, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -1825,6 +1981,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -1842,6 +1999,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRL x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRLconst {
 			break
@@ -1850,7 +2008,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPshiftRL, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPshiftRL, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -1861,6 +2019,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -1878,6 +2037,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPshiftRA x y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRAconst {
 			break
@@ -1886,7 +2046,7 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 		y := v_0.Args[0]
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPshiftRA, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPshiftRA, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v0.AddArg(y)
@@ -1895,13 +2055,14 @@ func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPW(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64CMPW_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPW x (MOVDconst [c]))
 	// cond:
 	// result: (CMPWconst [int64(int32(c))] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -1917,6 +2078,7 @@ func rewriteValueARM64_OpARM64CMPW(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPWconst [int64(int32(c))] x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -1924,7 +2086,7 @@ func rewriteValueARM64_OpARM64CMPW(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPWconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPWconst, types.TypeFlags)
 		v0.AuxInt = int64(int32(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -1932,9 +2094,7 @@ func rewriteValueARM64_OpARM64CMPW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64CMPWconst_0(v *Value) bool {
 	// match: (CMPWconst (MOVDconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -2047,10 +2207,8 @@ func rewriteValueARM64_OpARM64CMPWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (CMPconst  (MOVDconst [x]) [y])
+func rewriteValueARM64_OpARM64CMPconst_0(v *Value) bool {
+	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: x==y
 	// result: (FlagEQ)
 	for {
@@ -2066,7 +2224,7 @@ func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
 		v.reset(OpARM64FlagEQ)
 		return true
 	}
-	// match: (CMPconst  (MOVDconst [x]) [y])
+	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: int64(x)<int64(y) && uint64(x)<uint64(y)
 	// result: (FlagLT_ULT)
 	for {
@@ -2082,7 +2240,7 @@ func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
 		v.reset(OpARM64FlagLT_ULT)
 		return true
 	}
-	// match: (CMPconst  (MOVDconst [x]) [y])
+	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: int64(x)<int64(y) && uint64(x)>uint64(y)
 	// result: (FlagLT_UGT)
 	for {
@@ -2098,7 +2256,7 @@ func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
 		v.reset(OpARM64FlagLT_UGT)
 		return true
 	}
-	// match: (CMPconst  (MOVDconst [x]) [y])
+	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: int64(x)>int64(y) && uint64(x)<uint64(y)
 	// result: (FlagGT_ULT)
 	for {
@@ -2114,7 +2272,7 @@ func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
 		v.reset(OpARM64FlagGT_ULT)
 		return true
 	}
-	// match: (CMPconst  (MOVDconst [x]) [y])
+	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: int64(x)>int64(y) && uint64(x)>uint64(y)
 	// result: (FlagGT_UGT)
 	for {
@@ -2209,7 +2367,7 @@ func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64CMPshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftLL (MOVDconst [c]) x [d])
@@ -2217,6 +2375,7 @@ func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -2224,9 +2383,9 @@ func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64SLLconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -2238,6 +2397,7 @@ func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -2251,7 +2411,7 @@ func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64CMPshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRA (MOVDconst [c]) x [d])
@@ -2259,6 +2419,7 @@ func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -2266,9 +2427,9 @@ func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64SRAconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -2280,6 +2441,7 @@ func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -2293,7 +2455,7 @@ func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64CMPshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPshiftRL (MOVDconst [c]) x [d])
@@ -2301,6 +2463,7 @@ func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
 	// result: (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -2308,9 +2471,9 @@ func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpARM64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v0.AuxInt = c
-		v1 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64SRLconst, x.Type)
 		v1.AuxInt = d
 		v1.AddArg(x)
 		v0.AddArg(v1)
@@ -2322,6 +2485,7 @@ func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
 	// result: (CMPconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -2335,13 +2499,12 @@ func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64CSELULT_0(v *Value) bool {
 	// match: (CSELULT x (MOVDconst [0]) flag)
 	// cond:
 	// result: (CSELULT0 x flag)
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -2360,6 +2523,7 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[2]
 		y := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARM64FlagEQ {
@@ -2374,6 +2538,7 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARM64FlagLT_ULT {
@@ -2388,6 +2553,7 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[2]
 		y := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARM64FlagLT_UGT {
@@ -2402,6 +2568,7 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[2]
 		x := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARM64FlagGT_ULT {
@@ -2416,6 +2583,7 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[2]
 		y := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != OpARM64FlagGT_UGT {
@@ -2428,13 +2596,12 @@ func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64CSELULT0_0(v *Value) bool {
 	// match: (CSELULT0 _ (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64FlagEQ {
 			break
@@ -2447,6 +2614,7 @@ func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64FlagLT_ULT {
@@ -2461,6 +2629,7 @@ func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64FlagLT_UGT {
 			break
@@ -2473,6 +2642,7 @@ func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64FlagGT_ULT {
@@ -2487,6 +2657,7 @@ func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64FlagGT_UGT {
 			break
@@ -2497,13 +2668,12 @@ func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64DIV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (DIV   (MOVDconst [c]) (MOVDconst [d]))
+func rewriteValueARM64_OpARM64DIV_0(v *Value) bool {
+	// match: (DIV (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(c)/int64(d)])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -2520,13 +2690,12 @@ func rewriteValueARM64_OpARM64DIV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64DIVW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (DIVW  (MOVDconst [c]) (MOVDconst [d]))
+func rewriteValueARM64_OpARM64DIVW_0(v *Value) bool {
+	// match: (DIVW (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(int32(c)/int32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -2543,9 +2712,7 @@ func rewriteValueARM64_OpARM64DIVW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64Equal(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64Equal_0(v *Value) bool {
 	// match: (Equal (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -2621,15 +2788,18 @@ func rewriteValueARM64_OpARM64Equal(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64FMOVDload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -2637,7 +2807,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVDload)
@@ -2648,11 +2818,12 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -2661,7 +2832,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVDload)
@@ -2673,15 +2844,18 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64FMOVDstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -2690,7 +2864,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVDstore)
@@ -2702,11 +2876,12 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -2716,7 +2891,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVDstore)
@@ -2729,15 +2904,18 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64FMOVSload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVSload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -2745,7 +2923,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVSload)
@@ -2756,11 +2934,12 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -2769,7 +2948,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVSload)
@@ -2781,15 +2960,18 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64FMOVSstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVSstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -2798,7 +2980,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVSstore)
@@ -2810,11 +2992,12 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -2824,7 +3007,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64FMOVSstore)
@@ -2837,9 +3020,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64GreaterEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64GreaterEqual_0(v *Value) bool {
 	// match: (GreaterEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -2915,9 +3096,7 @@ func rewriteValueARM64_OpARM64GreaterEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64GreaterEqualU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64GreaterEqualU_0(v *Value) bool {
 	// match: (GreaterEqualU (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -2993,9 +3172,7 @@ func rewriteValueARM64_OpARM64GreaterEqualU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64GreaterThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64GreaterThan_0(v *Value) bool {
 	// match: (GreaterThan (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -3071,9 +3248,7 @@ func rewriteValueARM64_OpARM64GreaterThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64GreaterThanU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64GreaterThanU_0(v *Value) bool {
 	// match: (GreaterThanU (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -3149,9 +3324,7 @@ func rewriteValueARM64_OpARM64GreaterThanU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64LessEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64LessEqual_0(v *Value) bool {
 	// match: (LessEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -3227,9 +3400,7 @@ func rewriteValueARM64_OpARM64LessEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64LessEqualU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64LessEqualU_0(v *Value) bool {
 	// match: (LessEqualU (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -3305,9 +3476,7 @@ func rewriteValueARM64_OpARM64LessEqualU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64LessThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64LessThan_0(v *Value) bool {
 	// match: (LessThan (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -3383,9 +3552,7 @@ func rewriteValueARM64_OpARM64LessThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64LessThanU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64LessThanU_0(v *Value) bool {
 	// match: (LessThanU (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -3461,13 +3628,12 @@ func rewriteValueARM64_OpARM64LessThanU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOD   (MOVDconst [c]) (MOVDconst [d]))
+func rewriteValueARM64_OpARM64MOD_0(v *Value) bool {
+	// match: (MOD (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(c)%int64(d)])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -3484,13 +3650,12 @@ func rewriteValueARM64_OpARM64MOD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MODW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MODW  (MOVDconst [c]) (MOVDconst [d]))
+func rewriteValueARM64_OpARM64MODW_0(v *Value) bool {
+	// match: (MODW (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(int32(c)%int32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -3507,15 +3672,18 @@ func rewriteValueARM64_OpARM64MODW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVBUload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -3523,7 +3691,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBUload)
@@ -3534,11 +3702,12 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2)
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -3547,7 +3716,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBUload)
@@ -3563,6 +3732,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVBstorezero {
@@ -3570,6 +3740,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -3580,9 +3751,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVBUreg_0(v *Value) bool {
 	// match: (MOVBUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -3591,6 +3760,7 @@ func rewriteValueARM64_OpARM64MOVBUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -3622,15 +3792,18 @@ func rewriteValueARM64_OpARM64MOVBUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVBload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -3638,7 +3811,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBload)
@@ -3649,11 +3822,12 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2)
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -3662,7 +3836,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBload)
@@ -3678,6 +3852,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVBstorezero {
@@ -3685,6 +3860,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -3695,9 +3871,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVBreg_0(v *Value) bool {
 	// match: (MOVBreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -3706,6 +3880,7 @@ func rewriteValueARM64_OpARM64MOVBreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -3722,7 +3897,7 @@ func rewriteValueARM64_OpARM64MOVBreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVBreg  (MOVDconst [c]))
+	// match: (MOVBreg (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [int64(int8(c))])
 	for {
@@ -3737,15 +3912,18 @@ func rewriteValueARM64_OpARM64MOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVBstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2)
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -3754,7 +3932,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1 + off2)) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBstore)
@@ -3766,11 +3944,12 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2)
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -3780,7 +3959,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBstore)
@@ -3797,6 +3976,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -3819,6 +3999,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVBreg {
@@ -3840,6 +4021,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVBUreg {
@@ -3861,6 +4043,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHreg {
@@ -3882,6 +4065,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHUreg {
@@ -3903,6 +4087,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWreg {
@@ -3924,6 +4109,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWUreg {
@@ -3941,15 +4127,18 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVBstorezero_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2)
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -3957,7 +4146,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1 + off2)) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBstorezero)
@@ -3968,11 +4157,12 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2)
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -3981,7 +4171,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVBstorezero)
@@ -3993,15 +4183,18 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVDload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4009,7 +4202,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDload)
@@ -4020,11 +4213,12 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4033,7 +4227,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDload)
@@ -4049,6 +4243,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDstorezero {
@@ -4056,6 +4251,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -4066,9 +4262,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVDreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVDreg_0(v *Value) bool {
 	// match: (MOVDreg x)
 	// cond: x.Uses == 1
 	// result: (MOVDnop x)
@@ -4081,7 +4275,7 @@ func rewriteValueARM64_OpARM64MOVDreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVDreg  (MOVDconst [c]))
+	// match: (MOVDreg (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [c])
 	for {
@@ -4096,15 +4290,18 @@ func rewriteValueARM64_OpARM64MOVDreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVDstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4113,7 +4310,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDstore)
@@ -4125,11 +4322,12 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4139,7 +4337,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDstore)
@@ -4156,6 +4354,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -4174,15 +4373,18 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVDstorezero_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4190,7 +4392,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDstorezero)
@@ -4201,11 +4403,12 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4214,7 +4417,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVDstorezero)
@@ -4226,15 +4429,18 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVHUload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4242,7 +4448,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHUload)
@@ -4253,11 +4459,12 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4266,7 +4473,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHUload)
@@ -4282,6 +4489,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHstorezero {
@@ -4289,6 +4497,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -4299,9 +4508,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVHUreg_0(v *Value) bool {
 	// match: (MOVHUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -4310,6 +4517,7 @@ func rewriteValueARM64_OpARM64MOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4322,6 +4530,7 @@ func rewriteValueARM64_OpARM64MOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4365,15 +4574,18 @@ func rewriteValueARM64_OpARM64MOVHUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVHload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4381,7 +4593,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHload)
@@ -4392,11 +4604,12 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4405,7 +4618,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHload)
@@ -4421,6 +4634,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHstorezero {
@@ -4428,6 +4642,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -4438,9 +4653,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVHreg_0(v *Value) bool {
 	// match: (MOVHreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -4449,6 +4662,7 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4461,6 +4675,7 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4473,6 +4688,7 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4513,7 +4729,7 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVHreg  (MOVDconst [c]))
+	// match: (MOVHreg (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [int64(int16(c))])
 	for {
@@ -4528,15 +4744,18 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVHstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4545,7 +4764,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHstore)
@@ -4557,11 +4776,12 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4571,7 +4791,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHstore)
@@ -4588,6 +4808,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -4610,6 +4831,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHreg {
@@ -4631,6 +4853,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVHUreg {
@@ -4652,6 +4875,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWreg {
@@ -4673,6 +4897,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWUreg {
@@ -4690,15 +4915,18 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVHstorezero_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4706,7 +4934,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHstorezero)
@@ -4717,11 +4945,12 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4730,7 +4959,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVHstorezero)
@@ -4742,15 +4971,18 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVWUload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4758,7 +4990,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWUload)
@@ -4769,11 +5001,12 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4782,7 +5015,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWUload)
@@ -4798,6 +5031,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWstorezero {
@@ -4805,6 +5039,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -4815,9 +5050,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVWUreg_0(v *Value) bool {
 	// match: (MOVWUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -4826,6 +5059,7 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4838,6 +5072,7 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4850,6 +5085,7 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVWUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -4905,15 +5141,18 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVWload_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -4921,7 +5160,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWload)
@@ -4932,11 +5171,12 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -4945,7 +5185,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWload)
@@ -4961,6 +5201,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWstorezero {
@@ -4968,6 +5209,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[1]
 		ptr2 := v_1.Args[0]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
@@ -4978,9 +5220,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MOVWreg_0(v *Value) bool {
 	// match: (MOVWreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVDreg x)
@@ -4989,6 +5229,7 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -5001,6 +5242,7 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -5013,6 +5255,7 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -5025,6 +5268,7 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -5037,6 +5281,7 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpARM64MOVWload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpARM64MOVDreg)
 		v.AddArg(x)
 		return true
@@ -5101,7 +5346,10 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWreg  (MOVDconst [c]))
+	return false
+}
+func rewriteValueARM64_OpARM64MOVWreg_10(v *Value) bool {
+	// match: (MOVWreg (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [int64(int32(c))])
 	for {
@@ -5116,15 +5364,18 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVWstore_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -5133,7 +5384,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWstore)
@@ -5145,11 +5396,12 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -5159,7 +5411,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 		ptr := v_0.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWstore)
@@ -5176,6 +5428,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5198,6 +5451,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWreg {
@@ -5219,6 +5473,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVWUreg {
@@ -5236,15 +5491,18 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64MOVWstorezero_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is32Bit(off1+off2) && !isArg(sym) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
+	// cond: is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64ADDconst {
 			break
@@ -5252,7 +5510,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
 		off2 := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
+		if !(is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWstorezero)
@@ -5263,11 +5521,12 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1,sym2) 	&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) 	&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
+	// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) 	&& (ptr.Op != OpSB || !config.ctxt.Flag_shared)
 	// result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDaddr {
 			break
@@ -5276,7 +5535,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
+		if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)) {
 			break
 		}
 		v.reset(OpARM64MOVWstorezero)
@@ -5288,13 +5547,12 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MUL_0(v *Value) bool {
 	// match: (MUL x (MOVDconst [-1]))
 	// cond:
 	// result: (NEG x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5307,10 +5565,28 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVDconst [-1]) x)
+	// cond:
+	// result: (NEG x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpARM64NEG)
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL _ (MOVDconst [0]))
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -5322,10 +5598,27 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (MUL (MOVDconst [0]) _)
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpARM64MOVDconst)
+		v.AuxInt = 0
+		return true
+	}
 	// match: (MUL x (MOVDconst [1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5339,10 +5632,29 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVDconst [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL x (MOVDconst [c]))
 	// cond: isPowerOfTwo(c)
 	// result: (SLLconst [log2(c)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5357,11 +5669,31 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL x (MOVDconst [c]))
-	// cond: isPowerOfTwo(c-1) && c >= 3
-	// result: (ADDshiftLL x x [log2(c-1)])
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c)
+	// result: (SLLconst [log2(c)] x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MUL x (MOVDconst [c]))
+	// cond: isPowerOfTwo(c-1) && c >= 3
+	// result: (ADDshiftLL x x [log2(c-1)])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -5376,10 +5708,36 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c-1) && c >= 3
+	// result: (ADDshiftLL x x [log2(c-1)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c-1) && c >= 3) {
+			break
+		}
+		v.reset(OpARM64ADDshiftLL)
+		v.AuxInt = log2(c - 1)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueARM64_OpARM64MUL_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (MUL x (MOVDconst [c]))
 	// cond: isPowerOfTwo(c+1) && c >= 7
 	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5391,7 +5749,29 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64ADDshiftLL)
 		v.AuxInt = log2(c + 1)
-		v0 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c+1) && c >= 7
+	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c+1) && c >= 7) {
+			break
+		}
+		v.reset(OpARM64ADDshiftLL)
+		v.AuxInt = log2(c + 1)
+		v0 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(x)
@@ -5401,6 +5781,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 	// cond: c%3 == 0 && isPowerOfTwo(c/3)
 	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5412,7 +5793,30 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 1
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: c%3 == 0 && isPowerOfTwo(c/3)
+	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 1
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -5423,6 +5827,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 	// cond: c%5 == 0 && isPowerOfTwo(c/5)
 	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5434,7 +5839,30 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 2
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: c%5 == 0 && isPowerOfTwo(c/5)
+	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 2
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -5445,6 +5873,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 	// cond: c%7 == 0 && isPowerOfTwo(c/7)
 	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5456,9 +5885,34 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 3
+		v1 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: c%7 == 0 && isPowerOfTwo(c/7)
+	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 7)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 3
-		v1 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(x)
@@ -5469,6 +5923,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 	// cond: c%9 == 0 && isPowerOfTwo(c/9)
 	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5480,375 +5935,355 @@ func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (MUL (MOVDconst [-1]) x)
-	// cond:
-	// result: (NEG x)
+	// match: (MUL (MOVDconst [c]) x)
+	// cond: c%9 == 0 && isPowerOfTwo(c/9)
+	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpARM64NEG)
-		v.AddArg(x)
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 3
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (MUL (MOVDconst [0]) _)
+	return false
+}
+func rewriteValueARM64_OpARM64MUL_20(v *Value) bool {
+	// match: (MUL (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
-	// result: (MOVDconst [0])
+	// result: (MOVDconst [c*d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
+		d := v_1.AuxInt
 		v.reset(OpARM64MOVDconst)
-		v.AuxInt = 0
+		v.AuxInt = c * d
 		return true
 	}
-	// match: (MUL (MOVDconst [1]) x)
+	// match: (MUL (MOVDconst [d]) (MOVDconst [c]))
 	// cond:
-	// result: x
+	// result: (MOVDconst [c*d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		if v_0.AuxInt != 1 {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		c := v_1.AuxInt
+		v.reset(OpARM64MOVDconst)
+		v.AuxInt = c * d
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLLconst [log2(c)] x)
+	return false
+}
+func rewriteValueARM64_OpARM64MULW_0(v *Value) bool {
+	// match: (MULW x (MOVDconst [c]))
+	// cond: int32(c)==-1
+	// result: (NEG x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c)) {
+		c := v_1.AuxInt
+		if !(int32(c) == -1) {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c)
+		v.reset(OpARM64NEG)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLLconst [log2(c)] x)
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: int32(c)==-1
+	// result: (NEG x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(isPowerOfTwo(c)) {
+		if !(int32(c) == -1) {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c)
+		v.reset(OpARM64NEG)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c-1) && c >= 3
-	// result: (ADDshiftLL x x [log2(c-1)])
+	// match: (MULW _ (MOVDconst [c]))
+	// cond: int32(c)==0
+	// result: (MOVDconst [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c-1) && c >= 3) {
+		c := v_1.AuxInt
+		if !(int32(c) == 0) {
 			break
 		}
-		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c - 1)
-		v.AddArg(x)
-		v.AddArg(x)
+		v.reset(OpARM64MOVDconst)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c+1) && c >= 7
-	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+	// match: (MULW (MOVDconst [c]) _)
+	// cond: int32(c)==0
+	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c+1) && c >= 7) {
+		if !(int32(c) == 0) {
 			break
 		}
-		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c + 1)
-		v0 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
+		v.reset(OpARM64MOVDconst)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: c%3 == 0 && isPowerOfTwo(c/3)
-	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+	// match: (MULW x (MOVDconst [c]))
+	// cond: int32(c)==1
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+		c := v_1.AuxInt
+		if !(int32(c) == 1) {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 1
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: c%5 == 0 && isPowerOfTwo(c/5)
-	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: int32(c)==1
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+		if !(int32(c) == 1) {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 2
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: c%7 == 0 && isPowerOfTwo(c/7)
-	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+	// match: (MULW x (MOVDconst [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (SLLconst [log2(c)] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
 			break
 		}
 		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 3
-		v1 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVDconst [c]) x)
-	// cond: c%9 == 0 && isPowerOfTwo(c/9)
-	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c)
+	// result: (SLLconst [log2(c)] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+		if !(isPowerOfTwo(c)) {
 			break
 		}
 		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 3
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MUL   (MOVDconst [c]) (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [c*d])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
-			break
-		}
-		d := v_1.AuxInt
-		v.reset(OpARM64MOVDconst)
-		v.AuxInt = c * d
+		v.AuxInt = log2(c)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
 	// match: (MULW x (MOVDconst [c]))
-	// cond: int32(c)==-1
-	// result: (NEG x)
+	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
+	// result: (ADDshiftLL x x [log2(c-1)])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(int32(c) == -1) {
+		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
 			break
 		}
-		v.reset(OpARM64NEG)
+		v.reset(OpARM64ADDshiftLL)
+		v.AuxInt = log2(c - 1)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MULW _ (MOVDconst [c]))
-	// cond: int32(c)==0
-	// result: (MOVDconst [0])
-	for {
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_1.AuxInt
-		if !(int32(c) == 0) {
-			break
-		}
-		v.reset(OpARM64MOVDconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (MULW x (MOVDconst [c]))
-	// cond: int32(c)==1
-	// result: x
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
+	// result: (ADDshiftLL x x [log2(c-1)])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
-		if !(int32(c) == 1) {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpARM64ADDshiftLL)
+		v.AuxInt = log2(c - 1)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
+	return false
+}
+func rewriteValueARM64_OpARM64MULW_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (MULW x (MOVDconst [c]))
-	// cond: isPowerOfTwo(c)
-	// result: (SLLconst [log2(c)] x)
+	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
+	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(isPowerOfTwo(c)) {
+		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c)
+		v.reset(OpARM64ADDshiftLL)
+		v.AuxInt = log2(c + 1)
+		v0 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (MULW x (MOVDconst [c]))
-	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
-	// result: (ADDshiftLL x x [log2(c-1)])
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
+	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
-		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
 			break
 		}
 		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c - 1)
-		v.AddArg(x)
+		v.AuxInt = log2(c + 1)
+		v0 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	// match: (MULW x (MOVDconst [c]))
-	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
-	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
 			break
 		}
-		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c + 1)
-		v0 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 1
+		v0.AddArg(x)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (MULW x (MOVDconst [c]))
+	// match: (MULW (MOVDconst [c]) x)
 	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
 	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
 			break
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 1
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -5859,6 +6294,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
 	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5870,7 +6306,30 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 2
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 2
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -5881,6 +6340,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
 	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5892,9 +6352,34 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 3
+		v1 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULW (MOVDconst [c]) x)
+	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+			break
+		}
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 7)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 3
-		v1 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64NEG, x.Type)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(x)
@@ -5905,6 +6390,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
 	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -5916,7 +6402,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SLLconst)
 		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
 		v0.AuxInt = 3
 		v0.AddArg(x)
 		v0.AddArg(x)
@@ -5924,227 +6410,72 @@ func rewriteValueARM64_OpARM64MULW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MULW (MOVDconst [c]) x)
-	// cond: int32(c)==-1
-	// result: (NEG x)
+	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(int32(c) == -1) {
+		if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
 			break
 		}
-		v.reset(OpARM64NEG)
-		v.AddArg(x)
+		v.reset(OpARM64SLLconst)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDshiftLL, x.Type)
+		v0.AuxInt = 3
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (MULW (MOVDconst [c]) _)
-	// cond: int32(c)==0
-	// result: (MOVDconst [0])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		if !(int32(c) == 0) {
-			break
-		}
-		v.reset(OpARM64MOVDconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: int32(c)==1
-	// result: x
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(int32(c) == 1) {
-			break
-		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLLconst [log2(c)] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c)) {
-			break
-		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c-1) && int32(c) >= 3
-	// result: (ADDshiftLL x x [log2(c-1)])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
-			break
-		}
-		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c - 1)
-		v.AddArg(x)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: isPowerOfTwo(c+1) && int32(c) >= 7
-	// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
-			break
-		}
-		v.reset(OpARM64ADDshiftLL)
-		v.AuxInt = log2(c + 1)
-		v0 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
-	// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
-			break
-		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 3)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 1
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
-	// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
-			break
-		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 5)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 2
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
-	// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
-			break
-		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 7)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 3
-		v1 := b.NewValue0(v.Line, OpARM64NEG, x.Type)
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		return true
-	}
-	// match: (MULW (MOVDconst [c]) x)
-	// cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
-	// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+	return false
+}
+func rewriteValueARM64_OpARM64MULW_20(v *Value) bool {
+	// match: (MULW (MOVDconst [c]) (MOVDconst [d]))
+	// cond:
+	// result: (MOVDconst [int64(int32(c)*int32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		v.reset(OpARM64SLLconst)
-		v.AuxInt = log2(c / 9)
-		v0 := b.NewValue0(v.Line, OpARM64ADDshiftLL, x.Type)
-		v0.AuxInt = 3
-		v0.AddArg(x)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		d := v_1.AuxInt
+		v.reset(OpARM64MOVDconst)
+		v.AuxInt = int64(int32(c) * int32(d))
 		return true
 	}
-	// match: (MULW  (MOVDconst [c]) (MOVDconst [d]))
+	// match: (MULW (MOVDconst [d]) (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [int64(int32(c)*int32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		d := v_1.AuxInt
+		c := v_1.AuxInt
 		v.reset(OpARM64MOVDconst)
 		v.AuxInt = int64(int32(c) * int32(d))
 		return true
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64MVN(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64MVN_0(v *Value) bool {
 	// match: (MVN (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [^c])
@@ -6160,9 +6491,7 @@ func rewriteValueARM64_OpARM64MVN(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64NEG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64NEG_0(v *Value) bool {
 	// match: (NEG (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [-c])
@@ -6178,9 +6507,7 @@ func rewriteValueARM64_OpARM64NEG(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64NotEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64NotEqual_0(v *Value) bool {
 	// match: (NotEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -6256,43 +6583,46 @@ func rewriteValueARM64_OpARM64NotEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64OR_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (OR  (MOVDconst [c]) x)
+	// match: (OR x (MOVDconst [c]))
 	// cond:
 	// result: (ORconst  [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARM64ORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x (MOVDconst [c]))
+	// match: (OR (MOVDconst [c]) x)
 	// cond:
 	// result: (ORconst  [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARM64ORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x x)
+	// match: (OR x x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6302,153 +6632,801 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x s:(SLLconst [c] y))
-	// cond: s.Uses == 1 && clobber(s)
+	// match: (OR x (SLLconst [c] y))
+	// cond:
 	// result: (ORshiftLL  x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		s := v.Args[1]
-		if s.Op != OpARM64SLLconst {
-			break
-		}
-		c := s.AuxInt
-		y := s.Args[0]
-		if !(s.Uses == 1 && clobber(s)) {
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64SLLconst {
 			break
 		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
 		v.reset(OpARM64ORshiftLL)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  s:(SLLconst [c] y) x)
-	// cond: s.Uses == 1 && clobber(s)
+	// match: (OR (SLLconst [c] y) x)
+	// cond:
 	// result: (ORshiftLL  x y [c])
 	for {
-		s := v.Args[0]
-		if s.Op != OpARM64SLLconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
 			break
 		}
-		c := s.AuxInt
-		y := s.Args[0]
+		c := v_0.AuxInt
+		y := v_0.Args[0]
 		x := v.Args[1]
-		if !(s.Uses == 1 && clobber(s)) {
-			break
-		}
 		v.reset(OpARM64ORshiftLL)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  x (SLLconst [c] y))
+	// match: (OR x (SRLconst [c] y))
 	// cond:
-	// result: (ORshiftLL  x y [c])
+	// result: (ORshiftRL  x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpARM64SLLconst {
+		if v_1.Op != OpARM64SRLconst {
 			break
 		}
 		c := v_1.AuxInt
 		y := v_1.Args[0]
-		v.reset(OpARM64ORshiftLL)
+		v.reset(OpARM64ORshiftRL)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  (SLLconst [c] y) x)
+	// match: (OR (SRLconst [c] y) x)
 	// cond:
-	// result: (ORshiftLL  x y [c])
+	// result: (ORshiftRL  x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpARM64SLLconst {
+		if v_0.Op != OpARM64SRLconst {
 			break
 		}
 		c := v_0.AuxInt
 		y := v_0.Args[0]
 		x := v.Args[1]
-		v.reset(OpARM64ORshiftLL)
+		v.reset(OpARM64ORshiftRL)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  x (SRLconst [c] y))
+	// match: (OR x (SRAconst [c] y))
 	// cond:
-	// result: (ORshiftRL  x y [c])
+	// result: (ORshiftRA  x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpARM64SRLconst {
+		if v_1.Op != OpARM64SRAconst {
 			break
 		}
 		c := v_1.AuxInt
 		y := v_1.Args[0]
-		v.reset(OpARM64ORshiftRL)
+		v.reset(OpARM64ORshiftRA)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  (SRLconst [c] y) x)
+	// match: (OR (SRAconst [c] y) x)
 	// cond:
-	// result: (ORshiftRL  x y [c])
+	// result: (ORshiftRA  x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpARM64SRLconst {
+		if v_0.Op != OpARM64SRAconst {
 			break
 		}
 		c := v_0.AuxInt
 		y := v_0.Args[0]
 		x := v.Args[1]
-		v.reset(OpARM64ORshiftRL)
+		v.reset(OpARM64ORshiftRA)
 		v.AuxInt = c
 		v.AddArg(x)
 		v.AddArg(y)
 		return true
 	}
-	// match: (OR  x (SRAconst [c] y))
-	// cond:
-	// result: (ORshiftRA  x y [c])
+	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] y0:(MOVDnop x0:(MOVBUload [i3] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i2] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i1] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i0] {s} p mem)))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
+	// result: @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64SRAconst {
+		t := v.Type
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o0.AuxInt != 8 {
+			break
+		}
+		_ = o0.Args[1]
+		o1 := o0.Args[0]
+		if o1.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o1.AuxInt != 16 {
+			break
+		}
+		_ = o1.Args[1]
+		s0 := o1.Args[0]
+		if s0.Op != OpARM64SLLconst {
+			break
+		}
+		if s0.AuxInt != 24 {
+			break
+		}
+		y0 := s0.Args[0]
+		if y0.Op != OpARM64MOVDnop {
+			break
+		}
+		x0 := y0.Args[0]
+		if x0.Op != OpARM64MOVBUload {
+			break
+		}
+		i3 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y1 := o1.Args[1]
+		if y1.Op != OpARM64MOVDnop {
+			break
+		}
+		x1 := y1.Args[0]
+		if x1.Op != OpARM64MOVBUload {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y2 := o0.Args[1]
+		if y2.Op != OpARM64MOVDnop {
+			break
+		}
+		x2 := y2.Args[0]
+		if x2.Op != OpARM64MOVBUload {
+			break
+		}
+		i1 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		y3 := v.Args[1]
+		if y3.Op != OpARM64MOVDnop {
+			break
+		}
+		x3 := y3.Args[0]
+		if x3.Op != OpARM64MOVBUload {
+			break
+		}
+		i0 := x3.AuxInt
+		if x3.Aux != s {
+			break
+		}
+		_ = x3.Args[1]
+		if p != x3.Args[0] {
+			break
+		}
+		if mem != x3.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.Aux = s
+		v1 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v1.AuxInt = i0
+		v1.AddArg(p)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueARM64_OpARM64OR_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (OR <t> y3:(MOVDnop x3:(MOVBUload [i0] {s} p mem)) o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] y0:(MOVDnop x0:(MOVBUload [i3] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i2] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i1] {s} p mem))))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
+	// result: @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		y3 := v.Args[0]
+		if y3.Op != OpARM64MOVDnop {
+			break
+		}
+		x3 := y3.Args[0]
+		if x3.Op != OpARM64MOVBUload {
+			break
+		}
+		i0 := x3.AuxInt
+		s := x3.Aux
+		_ = x3.Args[1]
+		p := x3.Args[0]
+		mem := x3.Args[1]
+		o0 := v.Args[1]
+		if o0.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o0.AuxInt != 8 {
+			break
+		}
+		_ = o0.Args[1]
+		o1 := o0.Args[0]
+		if o1.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o1.AuxInt != 16 {
+			break
+		}
+		_ = o1.Args[1]
+		s0 := o1.Args[0]
+		if s0.Op != OpARM64SLLconst {
+			break
+		}
+		if s0.AuxInt != 24 {
+			break
+		}
+		y0 := s0.Args[0]
+		if y0.Op != OpARM64MOVDnop {
+			break
+		}
+		x0 := y0.Args[0]
+		if x0.Op != OpARM64MOVBUload {
+			break
+		}
+		i3 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y1 := o1.Args[1]
+		if y1.Op != OpARM64MOVDnop {
+			break
+		}
+		x1 := y1.Args[0]
+		if x1.Op != OpARM64MOVBUload {
+			break
+		}
+		i2 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y2 := o0.Args[1]
+		if y2.Op != OpARM64MOVDnop {
+			break
+		}
+		x2 := y2.Args[0]
+		if x2.Op != OpARM64MOVBUload {
+			break
+		}
+		i1 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.Aux = s
+		v1 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v1.AuxInt = i0
+		v1.AddArg(p)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] y0:(MOVDnop x0:(MOVBUload [i7] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i6] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i5] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i4] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i3] {s} p mem))) y5:(MOVDnop x5:(MOVBUload [i2] {s} p mem))) y6:(MOVDnop x6:(MOVBUload [i1] {s} p mem))) y7:(MOVDnop x7:(MOVBUload [i0] {s} [...]
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& i4 == i0+4 	&& i5 == i0+5 	&& i6 == i0+6 	&& i7 == i0+7 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mer [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		o0 := v.Args[0]
+		if o0.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o0.AuxInt != 8 {
+			break
+		}
+		_ = o0.Args[1]
+		o1 := o0.Args[0]
+		if o1.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o1.AuxInt != 16 {
+			break
+		}
+		_ = o1.Args[1]
+		o2 := o1.Args[0]
+		if o2.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o2.AuxInt != 24 {
+			break
+		}
+		_ = o2.Args[1]
+		o3 := o2.Args[0]
+		if o3.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o3.AuxInt != 32 {
+			break
+		}
+		_ = o3.Args[1]
+		o4 := o3.Args[0]
+		if o4.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o4.AuxInt != 40 {
+			break
+		}
+		_ = o4.Args[1]
+		o5 := o4.Args[0]
+		if o5.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o5.AuxInt != 48 {
+			break
+		}
+		_ = o5.Args[1]
+		s0 := o5.Args[0]
+		if s0.Op != OpARM64SLLconst {
+			break
+		}
+		if s0.AuxInt != 56 {
+			break
+		}
+		y0 := s0.Args[0]
+		if y0.Op != OpARM64MOVDnop {
+			break
+		}
+		x0 := y0.Args[0]
+		if x0.Op != OpARM64MOVBUload {
+			break
+		}
+		i7 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y1 := o5.Args[1]
+		if y1.Op != OpARM64MOVDnop {
+			break
+		}
+		x1 := y1.Args[0]
+		if x1.Op != OpARM64MOVBUload {
+			break
+		}
+		i6 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y2 := o4.Args[1]
+		if y2.Op != OpARM64MOVDnop {
+			break
+		}
+		x2 := y2.Args[0]
+		if x2.Op != OpARM64MOVBUload {
+			break
+		}
+		i5 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		y3 := o3.Args[1]
+		if y3.Op != OpARM64MOVDnop {
+			break
+		}
+		x3 := y3.Args[0]
+		if x3.Op != OpARM64MOVBUload {
+			break
+		}
+		i4 := x3.AuxInt
+		if x3.Aux != s {
+			break
+		}
+		_ = x3.Args[1]
+		if p != x3.Args[0] {
+			break
+		}
+		if mem != x3.Args[1] {
+			break
+		}
+		y4 := o2.Args[1]
+		if y4.Op != OpARM64MOVDnop {
+			break
+		}
+		x4 := y4.Args[0]
+		if x4.Op != OpARM64MOVBUload {
+			break
+		}
+		i3 := x4.AuxInt
+		if x4.Aux != s {
+			break
+		}
+		_ = x4.Args[1]
+		if p != x4.Args[0] {
+			break
+		}
+		if mem != x4.Args[1] {
+			break
+		}
+		y5 := o1.Args[1]
+		if y5.Op != OpARM64MOVDnop {
+			break
+		}
+		x5 := y5.Args[0]
+		if x5.Op != OpARM64MOVBUload {
+			break
+		}
+		i2 := x5.AuxInt
+		if x5.Aux != s {
+			break
+		}
+		_ = x5.Args[1]
+		if p != x5.Args[0] {
+			break
+		}
+		if mem != x5.Args[1] {
+			break
+		}
+		y6 := o0.Args[1]
+		if y6.Op != OpARM64MOVDnop {
+			break
+		}
+		x6 := y6.Args[0]
+		if x6.Op != OpARM64MOVBUload {
+			break
+		}
+		i1 := x6.AuxInt
+		if x6.Aux != s {
+			break
+		}
+		_ = x6.Args[1]
+		if p != x6.Args[0] {
+			break
+		}
+		if mem != x6.Args[1] {
+			break
+		}
+		y7 := v.Args[1]
+		if y7.Op != OpARM64MOVDnop {
+			break
+		}
+		x7 := y7.Args[0]
+		if x7.Op != OpARM64MOVBUload {
+			break
+		}
+		i0 := x7.AuxInt
+		if x7.Aux != s {
+			break
+		}
+		_ = x7.Args[1]
+		if p != x7.Args[0] {
+			break
+		}
+		if mem != x7.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x [...]
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+		v0 := b.NewValue0(v.Pos, OpARM64REV, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
+		v1.Aux = s
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
+		v2.AddArg(p)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR <t> y7:(MOVDnop x7:(MOVBUload [i0] {s} p mem)) o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] y0:(MOVDnop x0:(MOVBUload [i7] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i6] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i5] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i4] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i3] {s} p mem))) y5:(MOVDnop x5:(MOVBUload [i2] {s} p mem))) y6:(MOVDnop x6:(MOVBUload [i1] {s}  [...]
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& i4 == i0+4 	&& i5 == i0+5 	&& i6 == i0+6 	&& i7 == i0+7 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mer [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		y7 := v.Args[0]
+		if y7.Op != OpARM64MOVDnop {
+			break
+		}
+		x7 := y7.Args[0]
+		if x7.Op != OpARM64MOVBUload {
+			break
+		}
+		i0 := x7.AuxInt
+		s := x7.Aux
+		_ = x7.Args[1]
+		p := x7.Args[0]
+		mem := x7.Args[1]
+		o0 := v.Args[1]
+		if o0.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o0.AuxInt != 8 {
+			break
+		}
+		_ = o0.Args[1]
+		o1 := o0.Args[0]
+		if o1.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o1.AuxInt != 16 {
+			break
+		}
+		_ = o1.Args[1]
+		o2 := o1.Args[0]
+		if o2.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o2.AuxInt != 24 {
+			break
+		}
+		_ = o2.Args[1]
+		o3 := o2.Args[0]
+		if o3.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o3.AuxInt != 32 {
+			break
+		}
+		_ = o3.Args[1]
+		o4 := o3.Args[0]
+		if o4.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o4.AuxInt != 40 {
+			break
+		}
+		_ = o4.Args[1]
+		o5 := o4.Args[0]
+		if o5.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o5.AuxInt != 48 {
+			break
+		}
+		_ = o5.Args[1]
+		s0 := o5.Args[0]
+		if s0.Op != OpARM64SLLconst {
+			break
+		}
+		if s0.AuxInt != 56 {
+			break
+		}
+		y0 := s0.Args[0]
+		if y0.Op != OpARM64MOVDnop {
+			break
+		}
+		x0 := y0.Args[0]
+		if x0.Op != OpARM64MOVBUload {
+			break
+		}
+		i7 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y1 := o5.Args[1]
+		if y1.Op != OpARM64MOVDnop {
+			break
+		}
+		x1 := y1.Args[0]
+		if x1.Op != OpARM64MOVBUload {
+			break
+		}
+		i6 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y2 := o4.Args[1]
+		if y2.Op != OpARM64MOVDnop {
+			break
+		}
+		x2 := y2.Args[0]
+		if x2.Op != OpARM64MOVBUload {
+			break
+		}
+		i5 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		y3 := o3.Args[1]
+		if y3.Op != OpARM64MOVDnop {
+			break
+		}
+		x3 := y3.Args[0]
+		if x3.Op != OpARM64MOVBUload {
+			break
+		}
+		i4 := x3.AuxInt
+		if x3.Aux != s {
+			break
+		}
+		_ = x3.Args[1]
+		if p != x3.Args[0] {
+			break
+		}
+		if mem != x3.Args[1] {
+			break
+		}
+		y4 := o2.Args[1]
+		if y4.Op != OpARM64MOVDnop {
+			break
+		}
+		x4 := y4.Args[0]
+		if x4.Op != OpARM64MOVBUload {
+			break
+		}
+		i3 := x4.AuxInt
+		if x4.Aux != s {
+			break
+		}
+		_ = x4.Args[1]
+		if p != x4.Args[0] {
+			break
+		}
+		if mem != x4.Args[1] {
+			break
+		}
+		y5 := o1.Args[1]
+		if y5.Op != OpARM64MOVDnop {
+			break
+		}
+		x5 := y5.Args[0]
+		if x5.Op != OpARM64MOVBUload {
+			break
+		}
+		i2 := x5.AuxInt
+		if x5.Aux != s {
+			break
+		}
+		_ = x5.Args[1]
+		if p != x5.Args[0] {
+			break
+		}
+		if mem != x5.Args[1] {
+			break
+		}
+		y6 := o0.Args[1]
+		if y6.Op != OpARM64MOVDnop {
+			break
+		}
+		x6 := y6.Args[0]
+		if x6.Op != OpARM64MOVBUload {
+			break
+		}
+		i1 := x6.AuxInt
+		if x6.Aux != s {
 			break
 		}
-		c := v_1.AuxInt
-		y := v_1.Args[0]
-		v.reset(OpARM64ORshiftRA)
-		v.AuxInt = c
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-	// match: (OR  (SRAconst [c] y) x)
-	// cond:
-	// result: (ORshiftRA  x y [c])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64SRAconst {
+		_ = x6.Args[1]
+		if p != x6.Args[0] {
 			break
 		}
-		c := v_0.AuxInt
-		y := v_0.Args[0]
-		x := v.Args[1]
-		v.reset(OpARM64ORshiftRA)
-		v.AuxInt = c
-		v.AddArg(x)
-		v.AddArg(y)
+		if mem != x6.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x [...]
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+		v0 := b.NewValue0(v.Pos, OpARM64REV, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
+		v1.Aux = s
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
+		v2.AddArg(p)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))) 	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
-	// result: @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i-3] p) mem)
+	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem)))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
+	// result: @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -6456,6 +7434,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o0.AuxInt != 8 {
 			break
 		}
+		_ = o0.Args[1]
 		o1 := o0.Args[0]
 		if o1.Op != OpARM64ORshiftLL {
 			break
@@ -6463,6 +7442,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o1.AuxInt != 16 {
 			break
 		}
+		_ = o1.Args[1]
 		s0 := o1.Args[0]
 		if s0.Op != OpARM64SLLconst {
 			break
@@ -6478,8 +7458,9 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVBUload {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o1.Args[1]
@@ -6490,12 +7471,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i-1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -6510,12 +7490,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i-2 {
-			break
-		}
+		i2 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
@@ -6530,38 +7509,156 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x3.Op != OpARM64MOVBUload {
 			break
 		}
-		if x3.AuxInt != i-3 {
-			break
-		}
+		i3 := x3.AuxInt
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[1]
 		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 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2, x3)
-		v0 := b.NewValue0(v.Line, OpARM64MOVWUload, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REVW, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.Aux = s
-		v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v1.AuxInt = i - 3
-		v1.AddArg(p)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
+		v1.Aux = s
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
+		v2.AddArg(p)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR <t> y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem)) o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem))))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
+	// result: @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		y3 := v.Args[0]
+		if y3.Op != OpARM64MOVDnop {
+			break
+		}
+		x3 := y3.Args[0]
+		if x3.Op != OpARM64MOVBUload {
+			break
+		}
+		i3 := x3.AuxInt
+		s := x3.Aux
+		_ = x3.Args[1]
+		p := x3.Args[0]
+		mem := x3.Args[1]
+		o0 := v.Args[1]
+		if o0.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o0.AuxInt != 8 {
+			break
+		}
+		_ = o0.Args[1]
+		o1 := o0.Args[0]
+		if o1.Op != OpARM64ORshiftLL {
+			break
+		}
+		if o1.AuxInt != 16 {
+			break
+		}
+		_ = o1.Args[1]
+		s0 := o1.Args[0]
+		if s0.Op != OpARM64SLLconst {
+			break
+		}
+		if s0.AuxInt != 24 {
+			break
+		}
+		y0 := s0.Args[0]
+		if y0.Op != OpARM64MOVDnop {
+			break
+		}
+		x0 := y0.Args[0]
+		if x0.Op != OpARM64MOVBUload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y1 := o1.Args[1]
+		if y1.Op != OpARM64MOVDnop {
+			break
+		}
+		x1 := y1.Args[0]
+		if x1.Op != OpARM64MOVBUload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y2 := o0.Args[1]
+		if y2.Op != OpARM64MOVDnop {
+			break
+		}
+		x2 := y2.Args[0]
+		if x2.Op != OpARM64MOVBUload {
+			break
+		}
+		i2 := x2.AuxInt
+		if x2.Aux != s {
+			break
+		}
+		_ = x2.Args[1]
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3)
+		v0 := b.NewValue0(v.Pos, OpARM64REVW, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
+		v1.Aux = s
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
+		v2.AddArg(p)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
 		v0.AddArg(v1)
-		v0.AddArg(mem)
 		return true
 	}
-	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))) 	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem))) 	y4:(MOVDnop x4:(MOVBUload [i-4] {s} p mem))) 	y5:(MOVDnop x5:(MOVBUload [i-5] {s} p mem))) 	y6:(MOVDnop x6:(MOVBUload [i-6] {s} p mem))) 	y7:(MOVDnop x7:(MOV [...]
-	// 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 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	& [...]
-	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i-7] p) mem))
+	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i4] {s} p mem))) y5:(MOVDnop x5:(MOVBUload [i5] {s} p mem))) y6:(MOVDnop x6:(MOVBUload [i6] {s} p mem))) y7:(MOVDnop x7:(MOVBUload [i7] {s} [...]
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& i4 == i0+4 	&& i5 == i0+5 	&& i6 == i0+6 	&& i7 == i0+7 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mer [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -6569,6 +7666,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o0.AuxInt != 8 {
 			break
 		}
+		_ = o0.Args[1]
 		o1 := o0.Args[0]
 		if o1.Op != OpARM64ORshiftLL {
 			break
@@ -6576,6 +7674,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o1.AuxInt != 16 {
 			break
 		}
+		_ = o1.Args[1]
 		o2 := o1.Args[0]
 		if o2.Op != OpARM64ORshiftLL {
 			break
@@ -6583,6 +7682,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o2.AuxInt != 24 {
 			break
 		}
+		_ = o2.Args[1]
 		o3 := o2.Args[0]
 		if o3.Op != OpARM64ORshiftLL {
 			break
@@ -6590,6 +7690,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o3.AuxInt != 32 {
 			break
 		}
+		_ = o3.Args[1]
 		o4 := o3.Args[0]
 		if o4.Op != OpARM64ORshiftLL {
 			break
@@ -6597,6 +7698,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o4.AuxInt != 40 {
 			break
 		}
+		_ = o4.Args[1]
 		o5 := o4.Args[0]
 		if o5.Op != OpARM64ORshiftLL {
 			break
@@ -6604,6 +7706,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o5.AuxInt != 48 {
 			break
 		}
+		_ = o5.Args[1]
 		s0 := o5.Args[0]
 		if s0.Op != OpARM64SLLconst {
 			break
@@ -6619,8 +7722,9 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVBUload {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o5.Args[1]
@@ -6631,12 +7735,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i-1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -6651,12 +7754,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i-2 {
-			break
-		}
+		i2 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
@@ -6671,12 +7773,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x3.Op != OpARM64MOVBUload {
 			break
 		}
-		if x3.AuxInt != i-3 {
-			break
-		}
+		i3 := x3.AuxInt
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[1]
 		if p != x3.Args[0] {
 			break
 		}
@@ -6691,12 +7792,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x4.Op != OpARM64MOVBUload {
 			break
 		}
-		if x4.AuxInt != i-4 {
-			break
-		}
+		i4 := x4.AuxInt
 		if x4.Aux != s {
 			break
 		}
+		_ = x4.Args[1]
 		if p != x4.Args[0] {
 			break
 		}
@@ -6711,12 +7811,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x5.Op != OpARM64MOVBUload {
 			break
 		}
-		if x5.AuxInt != i-5 {
-			break
-		}
+		i5 := x5.AuxInt
 		if x5.Aux != s {
 			break
 		}
+		_ = x5.Args[1]
 		if p != x5.Args[0] {
 			break
 		}
@@ -6731,12 +7830,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x6.Op != OpARM64MOVBUload {
 			break
 		}
-		if x6.AuxInt != i-6 {
-			break
-		}
+		i6 := x6.AuxInt
 		if x6.Aux != s {
 			break
 		}
+		_ = x6.Args[1]
 		if p != x6.Args[0] {
 			break
 		}
@@ -6751,162 +7849,61 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x7.Op != OpARM64MOVBUload {
 			break
 		}
-		if x7.AuxInt != i-7 {
-			break
-		}
+		i7 := x7.AuxInt
 		if x7.Aux != s {
 			break
 		}
+		_ = x7.Args[1]
 		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 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && c [...]
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x [...]
 			break
 		}
 		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpARM64REV, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REV, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
 		v1.Aux = s
-		v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v2.AuxInt = i - 7
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
 		v2.AddArg(p)
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v0.AddArg(v1)
 		return true
 	}
-	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] s0:(SLLconst [24] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))) 	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i+2] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i+3] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) 	&& clobber(o0) && clobber(o1) && clobber(s0)
-	// result: @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i] p) mem))
+	// match: (OR <t> y7:(MOVDnop x7:(MOVBUload [i7] {s} p mem)) o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem))) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i3] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i4] {s} p mem))) y5:(MOVDnop x5:(MOVBUload [i5] {s} p mem))) y6:(MOVDnop x6:(MOVBUload [i6] {s}  [...]
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& i4 == i0+4 	&& i5 == i0+5 	&& i6 == i0+6 	&& i7 == i0+7 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 	&& x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mer [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 	for {
 		t := v.Type
-		o0 := v.Args[0]
-		if o0.Op != OpARM64ORshiftLL {
-			break
-		}
-		if o0.AuxInt != 8 {
-			break
-		}
-		o1 := o0.Args[0]
-		if o1.Op != OpARM64ORshiftLL {
-			break
-		}
-		if o1.AuxInt != 16 {
-			break
-		}
-		s0 := o1.Args[0]
-		if s0.Op != OpARM64SLLconst {
-			break
-		}
-		if s0.AuxInt != 24 {
-			break
-		}
-		y0 := s0.Args[0]
-		if y0.Op != OpARM64MOVDnop {
-			break
-		}
-		x0 := y0.Args[0]
-		if x0.Op != OpARM64MOVBUload {
-			break
-		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		y1 := o1.Args[1]
-		if y1.Op != OpARM64MOVDnop {
-			break
-		}
-		x1 := y1.Args[0]
-		if x1.Op != OpARM64MOVBUload {
-			break
-		}
-		if x1.AuxInt != i+1 {
-			break
-		}
-		if x1.Aux != s {
-			break
-		}
-		if p != x1.Args[0] {
-			break
-		}
-		if mem != x1.Args[1] {
-			break
-		}
-		y2 := o0.Args[1]
-		if y2.Op != OpARM64MOVDnop {
-			break
-		}
-		x2 := y2.Args[0]
-		if x2.Op != OpARM64MOVBUload {
-			break
-		}
-		if x2.AuxInt != i+2 {
-			break
-		}
-		if x2.Aux != s {
-			break
-		}
-		if p != x2.Args[0] {
-			break
-		}
-		if mem != x2.Args[1] {
-			break
-		}
-		y3 := v.Args[1]
-		if y3.Op != OpARM64MOVDnop {
-			break
-		}
-		x3 := y3.Args[0]
-		if x3.Op != OpARM64MOVBUload {
-			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 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(o0) && clobber(o1) && clobber(s0)) {
+		_ = v.Args[1]
+		y7 := v.Args[0]
+		if y7.Op != OpARM64MOVDnop {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3)
-		v0 := b.NewValue0(v.Line, OpARM64REVW, t)
-		v.reset(OpCopy)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWUload, t)
-		v1.Aux = s
-		v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v2.AuxInt = i
-		v2.AddArg(p)
-		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v0.AddArg(v1)
-		return true
-	}
-	// match: (OR <t> o0:(ORshiftLL [8] o1:(ORshiftLL [16] o2:(ORshiftLL [24] o3:(ORshiftLL [32] o4:(ORshiftLL [40] o5:(ORshiftLL [48] s0:(SLLconst [56] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem))) 	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i+2] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i+3] {s} p mem))) 	y4:(MOVDnop x4:(MOVBUload [i+4] {s} p mem))) 	y5:(MOVDnop x5:(MOVBUload [i+5] {s} p mem))) 	y6:(MOVDnop x6:(MOVBUload [i+6] {s} p mem))) 	y7:(MOVDnop x7:(MOV [...]
-	// 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 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 	&& y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 	&& o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) 	& [...]
-	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i] p) mem))
-	for {
-		t := v.Type
-		o0 := v.Args[0]
+		x7 := y7.Args[0]
+		if x7.Op != OpARM64MOVBUload {
+			break
+		}
+		i7 := x7.AuxInt
+		s := x7.Aux
+		_ = x7.Args[1]
+		p := x7.Args[0]
+		mem := x7.Args[1]
+		o0 := v.Args[1]
 		if o0.Op != OpARM64ORshiftLL {
 			break
 		}
 		if o0.AuxInt != 8 {
 			break
 		}
+		_ = o0.Args[1]
 		o1 := o0.Args[0]
 		if o1.Op != OpARM64ORshiftLL {
 			break
@@ -6914,6 +7911,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o1.AuxInt != 16 {
 			break
 		}
+		_ = o1.Args[1]
 		o2 := o1.Args[0]
 		if o2.Op != OpARM64ORshiftLL {
 			break
@@ -6921,6 +7919,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o2.AuxInt != 24 {
 			break
 		}
+		_ = o2.Args[1]
 		o3 := o2.Args[0]
 		if o3.Op != OpARM64ORshiftLL {
 			break
@@ -6928,6 +7927,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o3.AuxInt != 32 {
 			break
 		}
+		_ = o3.Args[1]
 		o4 := o3.Args[0]
 		if o4.Op != OpARM64ORshiftLL {
 			break
@@ -6935,6 +7935,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o4.AuxInt != 40 {
 			break
 		}
+		_ = o4.Args[1]
 		o5 := o4.Args[0]
 		if o5.Op != OpARM64ORshiftLL {
 			break
@@ -6942,6 +7943,7 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if o5.AuxInt != 48 {
 			break
 		}
+		_ = o5.Args[1]
 		s0 := o5.Args[0]
 		if s0.Op != OpARM64SLLconst {
 			break
@@ -6957,10 +7959,17 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVBUload {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
 		y1 := o5.Args[1]
 		if y1.Op != OpARM64MOVDnop {
 			break
@@ -6969,12 +7978,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i+1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -6989,12 +7997,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i+2 {
-			break
-		}
+		i2 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
@@ -7009,12 +8016,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x3.Op != OpARM64MOVBUload {
 			break
 		}
-		if x3.AuxInt != i+3 {
-			break
-		}
+		i3 := x3.AuxInt
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[1]
 		if p != x3.Args[0] {
 			break
 		}
@@ -7029,12 +8035,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x4.Op != OpARM64MOVBUload {
 			break
 		}
-		if x4.AuxInt != i+4 {
-			break
-		}
+		i4 := x4.AuxInt
 		if x4.Aux != s {
 			break
 		}
+		_ = x4.Args[1]
 		if p != x4.Args[0] {
 			break
 		}
@@ -7049,12 +8054,11 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x5.Op != OpARM64MOVBUload {
 			break
 		}
-		if x5.AuxInt != i+5 {
-			break
-		}
+		i5 := x5.AuxInt
 		if x5.Aux != s {
 			break
 		}
+		_ = x5.Args[1]
 		if p != x5.Args[0] {
 			break
 		}
@@ -7069,49 +8073,28 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 		if x6.Op != OpARM64MOVBUload {
 			break
 		}
-		if x6.AuxInt != i+6 {
-			break
-		}
+		i6 := x6.AuxInt
 		if x6.Aux != s {
 			break
 		}
+		_ = x6.Args[1]
 		if p != x6.Args[0] {
 			break
 		}
 		if mem != x6.Args[1] {
 			break
 		}
-		y7 := v.Args[1]
-		if y7.Op != OpARM64MOVDnop {
-			break
-		}
-		x7 := y7.Args[0]
-		if x7.Op != OpARM64MOVBUload {
-			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 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && c [...]
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && y5.Uses == 1 && y6.Uses == 1 && y7.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x [...]
 			break
 		}
 		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpARM64REV, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REV, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
 		v1.Aux = s
-		v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v2.AuxInt = i
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
 		v2.AddArg(p)
 		v1.AddArg(v2)
 		v1.AddArg(mem)
@@ -7120,10 +8103,8 @@ func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORconst  [0]  x)
+func rewriteValueARM64_OpARM64ORconst_0(v *Value) bool {
+	// match: (ORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -7136,7 +8117,7 @@ func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORconst  [-1] _)
+	// match: (ORconst [-1] _)
 	// cond:
 	// result: (MOVDconst [-1])
 	for {
@@ -7147,7 +8128,7 @@ func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
 		v.AuxInt = -1
 		return true
 	}
-	// match: (ORconst  [c] (MOVDconst [d]))
+	// match: (ORconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [c|d])
 	for {
@@ -7161,7 +8142,7 @@ func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
 		v.AuxInt = c | d
 		return true
 	}
-	// match: (ORconst  [c] (ORconst [d] x))
+	// match: (ORconst [c] (ORconst [d] x))
 	// cond:
 	// result: (ORconst [c|d] x)
 	for {
@@ -7179,14 +8160,15 @@ func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ORshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (ORshiftLL  (MOVDconst [c]) x [d])
+	// match: (ORshiftLL (MOVDconst [c]) x [d])
 	// cond:
 	// result: (ORconst  [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -7195,17 +8177,18 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (ORshiftLL  x (MOVDconst [c]) [d])
+	// match: (ORshiftLL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (ORconst  x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -7217,11 +8200,12 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORshiftLL  x y:(SLLconst x [c]) [d])
+	// match: (ORshiftLL x y:(SLLconst x [c]) [d])
 	// cond: c==d
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SLLconst {
@@ -7239,14 +8223,67 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (ORshiftLL <t> [8] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)) 	y1:(MOVDnop x1:(MOVBUload [i+1] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 	&& mergePoint(b,x0,x1) != nil 	&& clobber(x0) && clobber(x1) 	&& clobber(y0) && clobber(y1)
-	// result: @mergePoint(b,x0,x1) (MOVHUload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	// match: (ORshiftLL [c] (SRLconst x [64-c]) x)
+	// cond:
+	// result: (RORconst [64-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = 64 - c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x)
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [32-c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpARM64MOVWUreg {
+			break
+		}
+		x := v_0_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORshiftLL <t> [8] y0:(MOVDnop x0:(MOVBUload [i0] {s} p mem)) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem)))
+	// cond: i1 == i0+1 	&& x0.Uses == 1 && x1.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 	&& mergePoint(b,x0,x1) != nil 	&& clobber(x0) && clobber(x1) 	&& clobber(y0) && clobber(y1)
+	// result: @mergePoint(b,x0,x1) (MOVHUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 	for {
 		t := v.Type
 		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
 		y0 := v.Args[0]
 		if y0.Op != OpARM64MOVDnop {
 			break
@@ -7255,8 +8292,9 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVBUload {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := v.Args[1]
@@ -7267,41 +8305,41 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i+1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
 		if mem != x1.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(y0) && clobber(y1)) {
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(y0) && clobber(y1)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpARM64MOVHUload, t)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVHUload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.Aux = s
-		v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v1.AuxInt = i
+		v1 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v1.AuxInt = i0
 		v1.AddArg(p)
 		v0.AddArg(v1)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (ORshiftLL <t> [24] o0:(ORshiftLL [16] 	            x0:(MOVHUload [i]   {s} p mem) 	y1:(MOVDnop x1:(MOVBUload [i+2] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i+3] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 	&& y1.Uses == 1 && y2.Uses == 1 	&& o0.Uses == 1 	&& mergePoint(b,x0,x1,x2) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) 	&& clobber(y1) && clobber(y2) 	&& clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVWUload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	// match: (ORshiftLL <t> [24] o0:(ORshiftLL [16] x0:(MOVHUload [i0] {s} p mem) y1:(MOVDnop x1:(MOVBUload [i2] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i3] {s} p mem)))
+	// cond: i2 == i0+2 	&& i3 == i0+3 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 	&& y1.Uses == 1 && y2.Uses == 1 	&& o0.Uses == 1 	&& mergePoint(b,x0,x1,x2) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) 	&& clobber(y1) && clobber(y2) 	&& clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 	for {
 		t := v.Type
 		if v.AuxInt != 24 {
 			break
 		}
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -7309,12 +8347,14 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o0.AuxInt != 16 {
 			break
 		}
+		_ = o0.Args[1]
 		x0 := o0.Args[0]
 		if x0.Op != OpARM64MOVHUload {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o0.Args[1]
@@ -7325,12 +8365,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i+2 {
-			break
-		}
+		i2 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -7345,41 +8384,41 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i+3 {
-			break
-		}
+		i3 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
 		if mem != x2.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(y1) && clobber(y2) && clobber(o0)) {
+		if !(i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(y1) && clobber(y2) && clobber(o0)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpARM64MOVWUload, t)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.Aux = s
-		v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v1.AuxInt = i
+		v1 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v1.AuxInt = i0
 		v1.AddArg(p)
 		v0.AddArg(v1)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32] 	            x0:(MOVWUload [i]   {s} p mem) 	y1:(MOVDnop x1:(MOVBUload [i+4] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i+5] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i+6] {s} p mem))) 	y4:(MOVDnop x4:(MOVBUload [i+7] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 	&& y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) 	&& clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) 	&& clobber(o0) && clobber(o1) && clobber(o2)
-	// result: @mergePoint(b,x0,x1,x2,x3,x4) (MOVDload <t> {s} (OffPtr <p.Type> [i] p) mem)
+	// match: (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32] x0:(MOVWUload [i0] {s} p mem) y1:(MOVDnop x1:(MOVBUload [i4] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i5] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i6] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i7] {s} p mem)))
+	// cond: i4 == i0+4 	&& i5 == i0+5 	&& i6 == i0+6 	&& i7 == i0+7 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 	&& y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) 	&& clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) 	&& clobber(o0) && clobber(o1) && clobber(o2)
+	// result: @mergePoint(b,x0,x1,x2,x3,x4) (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem)
 	for {
 		t := v.Type
 		if v.AuxInt != 56 {
 			break
 		}
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -7387,6 +8426,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o0.AuxInt != 48 {
 			break
 		}
+		_ = o0.Args[1]
 		o1 := o0.Args[0]
 		if o1.Op != OpARM64ORshiftLL {
 			break
@@ -7394,6 +8434,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o1.AuxInt != 40 {
 			break
 		}
+		_ = o1.Args[1]
 		o2 := o1.Args[0]
 		if o2.Op != OpARM64ORshiftLL {
 			break
@@ -7401,12 +8442,14 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o2.AuxInt != 32 {
 			break
 		}
+		_ = o2.Args[1]
 		x0 := o2.Args[0]
 		if x0.Op != OpARM64MOVWUload {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o2.Args[1]
@@ -7417,12 +8460,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i+4 {
-			break
-		}
+		i4 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -7437,12 +8479,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i+5 {
-			break
-		}
+		i5 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
@@ -7457,12 +8498,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x3.Op != OpARM64MOVBUload {
 			break
 		}
-		if x3.AuxInt != i+6 {
-			break
-		}
+		i6 := x3.AuxInt
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[1]
 		if p != x3.Args[0] {
 			break
 		}
@@ -7477,41 +8517,41 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x4.Op != OpARM64MOVBUload {
 			break
 		}
-		if x4.AuxInt != i+7 {
-			break
-		}
+		i7 := x4.AuxInt
 		if x4.Aux != s {
 			break
 		}
+		_ = x4.Args[1]
 		if p != x4.Args[0] {
 			break
 		}
 		if mem != x4.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) && clobber(o0) && clobber(o1) && clobber(o2)) {
+		if !(i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) && clobber(o0) && clobber(o1) && clobber(o2)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2, x3, x4)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.Aux = s
-		v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v1.AuxInt = i
+		v1 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v1.AuxInt = i0
 		v1.AddArg(p)
 		v0.AddArg(v1)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (ORshiftLL <t> [8] 	y0:(MOVDnop x0:(MOVBUload [i]   {s} p mem)) 	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem)))
-	// cond: ((i-1)%2 == 0 || i-1<256 && i-1>-256 && !isArg(s) && !isAuto(s)) 	&& x0.Uses == 1 && x1.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 	&& mergePoint(b,x0,x1) != nil 	&& clobber(x0) && clobber(x1) 	&& clobber(y0) && clobber(y1)
-	// result: @mergePoint(b,x0,x1) (REV16W <t> (MOVHUload <t> [i-1] {s} p mem))
+	// match: (ORshiftLL <t> [8] y0:(MOVDnop x0:(MOVBUload [i1] {s} p mem)) y1:(MOVDnop x1:(MOVBUload [i0] {s} p mem)))
+	// cond: i1 == i0+1 	&& x0.Uses == 1 && x1.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 	&& mergePoint(b,x0,x1) != nil 	&& clobber(x0) && clobber(x1) 	&& clobber(y0) && clobber(y1)
+	// result: @mergePoint(b,x0,x1) (REV16W <t> (MOVHUload <t> [i0] {s} p mem))
 	for {
 		t := v.Type
 		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
 		y0 := v.Args[0]
 		if y0.Op != OpARM64MOVDnop {
 			break
@@ -7520,8 +8560,9 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVBUload {
 			break
 		}
-		i := x0.AuxInt
+		i1 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := v.Args[1]
@@ -7532,41 +8573,41 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i-1 {
-			break
-		}
+		i0 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
 		if mem != x1.Args[1] {
 			break
 		}
-		if !(((i-1)%2 == 0 || i-1 < 256 && i-1 > -256 && !isArg(s) && !isAuto(s)) && x0.Uses == 1 && x1.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(y0) && clobber(y1)) {
+		if !(i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(y0) && clobber(y1)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpARM64REV16W, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REV16W, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVHUload, t)
-		v1.AuxInt = i - 1
+		v1 := b.NewValue0(v.Pos, OpARM64MOVHUload, t)
+		v1.AuxInt = i0
 		v1.Aux = s
 		v1.AddArg(p)
 		v1.AddArg(mem)
 		v0.AddArg(v1)
 		return true
 	}
-	// match: (ORshiftLL <t> [24] o0:(ORshiftLL [16] 	y0:(REV16W  x0:(MOVHUload [i]   {s} p mem)) 	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 	&& o0.Uses == 1 	&& mergePoint(b,x0,x1,x2) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) 	&& clobber(y0) && clobber(y1) && clobber(y2) 	&& clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i-2] p) mem))
+	// match: (ORshiftLL <t> [24] o0:(ORshiftLL [16] y0:(REV16W x0:(MOVHUload [i2] {s} p mem)) y1:(MOVDnop x1:(MOVBUload [i1] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i0] {s} p mem)))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 	&& o0.Uses == 1 	&& mergePoint(b,x0,x1,x2) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) 	&& clobber(y0) && clobber(y1) && clobber(y2) 	&& clobber(o0)
+	// result: @mergePoint(b,x0,x1,x2) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 	for {
 		t := v.Type
 		if v.AuxInt != 24 {
 			break
 		}
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -7574,6 +8615,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o0.AuxInt != 16 {
 			break
 		}
+		_ = o0.Args[1]
 		y0 := o0.Args[0]
 		if y0.Op != OpARM64REV16W {
 			break
@@ -7582,8 +8624,9 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVHUload {
 			break
 		}
-		i := x0.AuxInt
+		i2 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o0.Args[1]
@@ -7594,12 +8637,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i-1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -7614,43 +8656,48 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i-2 {
-			break
-		}
+		i0 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
 		if mem != x2.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(o0)) {
+		if !(i1 == i0+1 && i2 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(o0)) {
 			break
 		}
 		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpARM64REVW, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REVW, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWUload, t)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWUload, t)
 		v1.Aux = s
-		v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v2.AuxInt = i - 2
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
 		v2.AddArg(p)
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v0.AddArg(v1)
 		return true
 	}
-	// match: (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32] 	y0:(REVW    x0:(MOVWUload [i]   {s} p mem)) 	y1:(MOVDnop x1:(MOVBUload [i-1] {s} p mem))) 	y2:(MOVDnop x2:(MOVBUload [i-2] {s} p mem))) 	y3:(MOVDnop x3:(MOVBUload [i-3] {s} p mem))) 	y4:(MOVDnop x4:(MOVBUload [i-4] {s} p mem)))
-	// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) 	&& clobber(o0) && clobber(o1) && clobber(o2)
-	// result: @mergePoint(b,x0,x1,x2,x3,x4) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i-4] p) mem))
+	return false
+}
+func rewriteValueARM64_OpARM64ORshiftLL_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (ORshiftLL <t> [56] o0:(ORshiftLL [48] o1:(ORshiftLL [40] o2:(ORshiftLL [32] y0:(REVW x0:(MOVWUload [i4] {s} p mem)) y1:(MOVDnop x1:(MOVBUload [i3] {s} p mem))) y2:(MOVDnop x2:(MOVBUload [i2] {s} p mem))) y3:(MOVDnop x3:(MOVBUload [i1] {s} p mem))) y4:(MOVDnop x4:(MOVBUload [i0] {s} p mem)))
+	// cond: i1 == i0+1 	&& i2 == i0+2 	&& i3 == i0+3 	&& i4 == i0+4 	&& x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 	&& y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 	&& o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 	&& mergePoint(b,x0,x1,x2,x3,x4) != nil 	&& clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) 	&& clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) 	&& clobber(o0) && clob [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i0] p) mem))
 	for {
 		t := v.Type
 		if v.AuxInt != 56 {
 			break
 		}
+		_ = v.Args[1]
 		o0 := v.Args[0]
 		if o0.Op != OpARM64ORshiftLL {
 			break
@@ -7658,6 +8705,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o0.AuxInt != 48 {
 			break
 		}
+		_ = o0.Args[1]
 		o1 := o0.Args[0]
 		if o1.Op != OpARM64ORshiftLL {
 			break
@@ -7665,6 +8713,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o1.AuxInt != 40 {
 			break
 		}
+		_ = o1.Args[1]
 		o2 := o1.Args[0]
 		if o2.Op != OpARM64ORshiftLL {
 			break
@@ -7672,6 +8721,7 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if o2.AuxInt != 32 {
 			break
 		}
+		_ = o2.Args[1]
 		y0 := o2.Args[0]
 		if y0.Op != OpARM64REVW {
 			break
@@ -7680,8 +8730,9 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x0.Op != OpARM64MOVWUload {
 			break
 		}
-		i := x0.AuxInt
+		i4 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[1]
 		p := x0.Args[0]
 		mem := x0.Args[1]
 		y1 := o2.Args[1]
@@ -7692,12 +8743,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x1.Op != OpARM64MOVBUload {
 			break
 		}
-		if x1.AuxInt != i-1 {
-			break
-		}
+		i3 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[1]
 		if p != x1.Args[0] {
 			break
 		}
@@ -7712,12 +8762,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x2.Op != OpARM64MOVBUload {
 			break
 		}
-		if x2.AuxInt != i-2 {
-			break
-		}
+		i2 := x2.AuxInt
 		if x2.Aux != s {
 			break
 		}
+		_ = x2.Args[1]
 		if p != x2.Args[0] {
 			break
 		}
@@ -7732,12 +8781,11 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x3.Op != OpARM64MOVBUload {
 			break
 		}
-		if x3.AuxInt != i-3 {
-			break
-		}
+		i1 := x3.AuxInt
 		if x3.Aux != s {
 			break
 		}
+		_ = x3.Args[1]
 		if p != x3.Args[0] {
 			break
 		}
@@ -7752,29 +8800,28 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 		if x4.Op != OpARM64MOVBUload {
 			break
 		}
-		if x4.AuxInt != i-4 {
-			break
-		}
+		i0 := x4.AuxInt
 		if x4.Aux != s {
 			break
 		}
+		_ = x4.Args[1]
 		if p != x4.Args[0] {
 			break
 		}
 		if mem != x4.Args[1] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) && clobber(o0) && clobber(o1) && clobber(o2)) {
+		if !(i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && y0.Uses == 1 && y1.Uses == 1 && y2.Uses == 1 && y3.Uses == 1 && y4.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3) && clobber(y4) && clobber(o0) && clobber(o1)  [...]
 			break
 		}
 		b = mergePoint(b, x0, x1, x2, x3, x4)
-		v0 := b.NewValue0(v.Line, OpARM64REV, t)
+		v0 := b.NewValue0(v.Pos, OpARM64REV, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDload, t)
 		v1.Aux = s
-		v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
-		v2.AuxInt = i - 4
+		v2 := b.NewValue0(v.Pos, OpOffPtr, p.Type)
+		v2.AuxInt = i0
 		v2.AddArg(p)
 		v1.AddArg(v2)
 		v1.AddArg(mem)
@@ -7783,14 +8830,15 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ORshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ORshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (ORshiftRA  (MOVDconst [c]) x [d])
+	// match: (ORshiftRA (MOVDconst [c]) x [d])
 	// cond:
 	// result: (ORconst  [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -7799,17 +8847,18 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (ORshiftRA  x (MOVDconst [c]) [d])
+	// match: (ORshiftRA x (MOVDconst [c]) [d])
 	// cond:
 	// result: (ORconst  x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -7821,11 +8870,12 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORshiftRA  x y:(SRAconst x [c]) [d])
+	// match: (ORshiftRA x y:(SRAconst x [c]) [d])
 	// cond: c==d
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SRAconst {
@@ -7845,14 +8895,15 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64ORshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64ORshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (ORshiftRL  (MOVDconst [c]) x [d])
+	// match: (ORshiftRL (MOVDconst [c]) x [d])
 	// cond:
 	// result: (ORconst  [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -7861,17 +8912,18 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64ORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (ORshiftRL  x (MOVDconst [c]) [d])
+	// match: (ORshiftRL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (ORconst  x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -7883,11 +8935,12 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORshiftRL  x y:(SRLconst x [c]) [d])
+	// match: (ORshiftRL x y:(SRLconst x [c]) [d])
 	// cond: c==d
 	// result: y
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if y.Op != OpARM64SRLconst {
@@ -7905,15 +8958,66 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ORshiftRL [c] (SLLconst x [64-c]) x)
+	// cond:
+	// result: (RORconst [   c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x))
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [   c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVWUreg {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpARM64SLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SLL_0(v *Value) bool {
 	// match: (SLL x (MOVDconst [c]))
 	// cond:
 	// result: (SLLconst x [c&63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -7927,9 +9031,7 @@ func rewriteValueARM64_OpARM64SLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SLLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SLLconst_0(v *Value) bool {
 	// match: (SLLconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(d)<<uint64(c)])
@@ -7944,15 +9046,35 @@ func rewriteValueARM64_OpARM64SLLconst(v *Value, config *Config) bool {
 		v.AuxInt = int64(d) << uint64(c)
 		return true
 	}
+	// match: (SLLconst [c] (SRLconst [c] x))
+	// cond: 0 < c && c < 64
+	// result: (ANDconst [^(1<<uint(c)-1)] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != c {
+			break
+		}
+		x := v_0.Args[0]
+		if !(0 < c && c < 64) {
+			break
+		}
+		v.reset(OpARM64ANDconst)
+		v.AuxInt = ^(1<<uint(c) - 1)
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpARM64SRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SRA_0(v *Value) bool {
 	// match: (SRA x (MOVDconst [c]))
 	// cond:
 	// result: (SRAconst x [c&63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -7966,9 +9088,7 @@ func rewriteValueARM64_OpARM64SRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SRAconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SRAconst_0(v *Value) bool {
 	// match: (SRAconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(d)>>uint64(c)])
@@ -7985,13 +9105,12 @@ func rewriteValueARM64_OpARM64SRAconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SRL_0(v *Value) bool {
 	// match: (SRL x (MOVDconst [c]))
 	// cond:
 	// result: (SRLconst x [c&63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8005,9 +9124,7 @@ func rewriteValueARM64_OpARM64SRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SRLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SRLconst_0(v *Value) bool {
 	// match: (SRLconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(uint64(d)>>uint64(c))])
@@ -8022,15 +9139,37 @@ func rewriteValueARM64_OpARM64SRLconst(v *Value, config *Config) bool {
 		v.AuxInt = int64(uint64(d) >> uint64(c))
 		return true
 	}
+	// match: (SRLconst [c] (SLLconst [c] x))
+	// cond: 0 < c && c < 64
+	// result: (ANDconst [1<<uint(64-c)-1] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != c {
+			break
+		}
+		x := v_0.Args[0]
+		if !(0 < c && c < 64) {
+			break
+		}
+		v.reset(OpARM64ANDconst)
+		v.AuxInt = 1<<uint(64-c) - 1
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64SUB_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (SUB x (MOVDconst [c]))
 	// cond:
 	// result: (SUBconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8046,6 +9185,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -8054,10 +9194,53 @@ func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (SUB x (SUB y z))
+	// cond:
+	// result: (SUB (ADD <v.Type> x z) y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64SUB {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		v.reset(OpARM64SUB)
+		v0 := b.NewValue0(v.Pos, OpARM64ADD, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(y)
+		return true
+	}
+	// match: (SUB (SUB x y) z)
+	// cond:
+	// result: (SUB x (ADD <y.Type> y z))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SUB {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		z := v.Args[1]
+		v.reset(OpARM64SUB)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpARM64ADD, y.Type)
+		v0.AddArg(y)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		return true
+	}
 	// match: (SUB x (SLLconst [c] y))
 	// cond:
 	// result: (SUBshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -8075,6 +9258,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -8092,6 +9276,7 @@ func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -8107,10 +9292,8 @@ func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SUBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBconst [0]  x)
+func rewriteValueARM64_OpARM64SUBconst_0(v *Value) bool {
+	// match: (SUBconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -8171,14 +9354,13 @@ func rewriteValueARM64_OpARM64SUBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SUBshiftLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SUBshiftLL_0(v *Value) bool {
 	// match: (SUBshiftLL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (SUBconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8195,6 +9377,7 @@ func rewriteValueARM64_OpARM64SUBshiftLL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -8213,14 +9396,13 @@ func rewriteValueARM64_OpARM64SUBshiftLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SUBshiftRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SUBshiftRA_0(v *Value) bool {
 	// match: (SUBshiftRA x (MOVDconst [c]) [d])
 	// cond:
 	// result: (SUBconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8237,6 +9419,7 @@ func rewriteValueARM64_OpARM64SUBshiftRA(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -8255,14 +9438,13 @@ func rewriteValueARM64_OpARM64SUBshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64SUBshiftRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64SUBshiftRL_0(v *Value) bool {
 	// match: (SUBshiftRL x (MOVDconst [c]) [d])
 	// cond:
 	// result: (SUBconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8279,6 +9461,7 @@ func rewriteValueARM64_OpARM64SUBshiftRL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -8297,13 +9480,12 @@ func rewriteValueARM64_OpARM64SUBshiftRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64UDIV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64UDIV_0(v *Value) bool {
 	// match: (UDIV x (MOVDconst [1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8321,6 +9503,7 @@ func rewriteValueARM64_OpARM64UDIV(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c)
 	// result: (SRLconst [log2(c)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8335,10 +9518,11 @@ func rewriteValueARM64_OpARM64UDIV(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (UDIV  (MOVDconst [c]) (MOVDconst [d]))
+	// match: (UDIV (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(uint64(c)/uint64(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8355,13 +9539,12 @@ func rewriteValueARM64_OpARM64UDIV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64UDIVW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64UDIVW_0(v *Value) bool {
 	// match: (UDIVW x (MOVDconst [c]))
 	// cond: uint32(c)==1
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8380,6 +9563,7 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c) && is32Bit(c)
 	// result: (SRLconst [log2(c)] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8398,6 +9582,7 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [int64(uint32(c)/uint32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8414,13 +9599,12 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64UMOD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64UMOD_0(v *Value) bool {
 	// match: (UMOD _ (MOVDconst [1]))
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -8436,6 +9620,7 @@ func rewriteValueARM64_OpARM64UMOD(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c)
 	// result: (ANDconst [c-1] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8450,10 +9635,11 @@ func rewriteValueARM64_OpARM64UMOD(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (UMOD  (MOVDconst [c]) (MOVDconst [d]))
+	// match: (UMOD (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [int64(uint64(c)%uint64(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8470,13 +9656,12 @@ func rewriteValueARM64_OpARM64UMOD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64UMODW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpARM64UMODW_0(v *Value) bool {
 	// match: (UMODW _ (MOVDconst [c]))
 	// cond: uint32(c)==1
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -8493,6 +9678,7 @@ func rewriteValueARM64_OpARM64UMODW(v *Value, config *Config) bool {
 	// cond: isPowerOfTwo(c) && is32Bit(c)
 	// result: (ANDconst [c-1] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8511,6 +9697,7 @@ func rewriteValueARM64_OpARM64UMODW(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [int64(uint32(c)%uint32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8527,34 +9714,34 @@ func rewriteValueARM64_OpARM64UMODW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR (MOVDconst [c]) x)
+func rewriteValueARM64_OpARM64XOR_0(v *Value) bool {
+	// match: (XOR x (MOVDconst [c]))
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpARM64XORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x (MOVDconst [c]))
+	// match: (XOR (MOVDconst [c]) x)
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpARM64MOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64MOVDconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpARM64XORconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -8564,6 +9751,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -8576,6 +9764,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -8593,6 +9782,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftLL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SLLconst {
 			break
@@ -8610,6 +9800,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -8627,6 +9818,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRL x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRLconst {
 			break
@@ -8644,6 +9836,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -8661,6 +9854,7 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (XORshiftRA x y [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64SRAconst {
 			break
@@ -8676,10 +9870,8 @@ func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64XORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XORconst [0]  x)
+func rewriteValueARM64_OpARM64XORconst_0(v *Value) bool {
+	// match: (XORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -8736,7 +9928,7 @@ func rewriteValueARM64_OpARM64XORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64XORshiftLL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftLL (MOVDconst [c]) x [d])
@@ -8744,6 +9936,7 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SLLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8752,7 +9945,7 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64XORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SLLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8763,6 +9956,7 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(uint64(c)<<uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8779,6 +9973,7 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SLLconst {
@@ -8795,9 +9990,61 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (XORshiftLL [c] (SRLconst x [64-c]) x)
+	// cond:
+	// result: (RORconst [64-c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = 64 - c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORshiftLL <t> [c] (SRLconst (MOVWUreg x) [32-c]) x)
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [32-c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SRLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpARM64MOVWUreg {
+			break
+		}
+		x := v_0_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
+		v.AuxInt = 32 - c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64XORshiftRA_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRA (MOVDconst [c]) x [d])
@@ -8805,6 +10052,7 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SRAconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8813,7 +10061,7 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64XORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRAconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8824,6 +10072,7 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(int64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8840,6 +10089,7 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRAconst {
@@ -8858,7 +10108,7 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
+func rewriteValueARM64_OpARM64XORshiftRL_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (XORshiftRL (MOVDconst [c]) x [d])
@@ -8866,6 +10116,7 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
 	// result: (XORconst [c] (SRLconst <x.Type> x [d]))
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpARM64MOVDconst {
 			break
@@ -8874,7 +10125,7 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
 		x := v.Args[1]
 		v.reset(OpARM64XORconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64SRLconst, x.Type)
 		v0.AuxInt = d
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -8885,6 +10136,7 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
 	// result: (XORconst x [int64(uint64(c)>>uint64(d))])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -8901,6 +10153,7 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
 	// result: (MOVDconst [0])
 	for {
 		d := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64SRLconst {
@@ -8917,15 +10170,66 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (XORshiftRL [c] (SLLconst x [64-c]) x)
+	// cond:
+	// result: (RORconst [   c] x)
+	for {
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != 64-c {
+			break
+		}
+		x := v_0.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpARM64RORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x))
+	// cond: c < 32 && t.Size() == 4
+	// result: (RORWconst [   c] x)
+	for {
+		t := v.Type
+		c := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpARM64SLLconst {
+			break
+		}
+		if v_0.AuxInt != 32-c {
+			break
+		}
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARM64MOVWUreg {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(c < 32 && t.Size() == 4) {
+			break
+		}
+		v.reset(OpARM64RORWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValueARM64_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd16_0(v *Value) bool {
 	// match: (Add16 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
@@ -8934,13 +10238,12 @@ func rewriteValueARM64_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd32_0(v *Value) bool {
 	// match: (Add32 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
@@ -8949,13 +10252,12 @@ func rewriteValueARM64_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (FADDS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FADDS)
@@ -8964,13 +10266,12 @@ func rewriteValueARM64_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd64_0(v *Value) bool {
 	// match: (Add64 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
@@ -8979,13 +10280,12 @@ func rewriteValueARM64_OpAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (FADDD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FADDD)
@@ -8994,13 +10294,12 @@ func rewriteValueARM64_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAdd8_0(v *Value) bool {
 	// match: (Add8 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
@@ -9009,13 +10308,12 @@ func rewriteValueARM64_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
@@ -9024,9 +10322,7 @@ func rewriteValueARM64_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVDaddr {sym} base)
@@ -9039,13 +10335,12 @@ func rewriteValueARM64_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64AND)
@@ -9054,13 +10349,12 @@ func rewriteValueARM64_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64AND)
@@ -9069,13 +10363,12 @@ func rewriteValueARM64_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAnd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAnd64_0(v *Value) bool {
 	// match: (And64 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64AND)
@@ -9084,13 +10377,12 @@ func rewriteValueARM64_OpAnd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAnd8_0(v *Value) bool {
 	// match: (And8 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64AND)
@@ -9099,13 +10391,12 @@ func rewriteValueARM64_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64AND)
@@ -9114,13 +10405,12 @@ func rewriteValueARM64_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicAdd32_0(v *Value) bool {
 	// match: (AtomicAdd32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicAdd32 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9131,13 +10421,12 @@ func rewriteValueARM64_OpAtomicAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool {
 	// match: (AtomicAdd64 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicAdd64 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9148,13 +10437,12 @@ func rewriteValueARM64_OpAtomicAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool {
 	// match: (AtomicAnd8 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicAnd8 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9165,13 +10453,12 @@ func rewriteValueARM64_OpAtomicAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicCompareAndSwap32_0(v *Value) bool {
 	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
 	// cond:
 	// result: (LoweredAtomicCas32 ptr old new_ mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		old := v.Args[1]
 		new_ := v.Args[2]
@@ -9184,13 +10471,12 @@ func rewriteValueARM64_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicCompareAndSwap64_0(v *Value) bool {
 	// match: (AtomicCompareAndSwap64 ptr old new_ mem)
 	// cond:
 	// result: (LoweredAtomicCas64 ptr old new_ mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		old := v.Args[1]
 		new_ := v.Args[2]
@@ -9203,13 +10489,12 @@ func rewriteValueARM64_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicExchange32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicExchange32_0(v *Value) bool {
 	// match: (AtomicExchange32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicExchange32 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9220,13 +10505,12 @@ func rewriteValueARM64_OpAtomicExchange32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicExchange64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicExchange64_0(v *Value) bool {
 	// match: (AtomicExchange64 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicExchange64 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9237,13 +10521,12 @@ func rewriteValueARM64_OpAtomicExchange64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicLoad32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoad32  ptr mem)
+func rewriteValueARM64_OpAtomicLoad32_0(v *Value) bool {
+	// match: (AtomicLoad32 ptr mem)
 	// cond:
 	// result: (LDARW ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64LDARW)
@@ -9252,13 +10535,12 @@ func rewriteValueARM64_OpAtomicLoad32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicLoad64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoad64  ptr mem)
+func rewriteValueARM64_OpAtomicLoad64_0(v *Value) bool {
+	// match: (AtomicLoad64 ptr mem)
 	// cond:
 	// result: (LDAR  ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64LDAR)
@@ -9267,13 +10549,12 @@ func rewriteValueARM64_OpAtomicLoad64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicLoadPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicLoadPtr_0(v *Value) bool {
 	// match: (AtomicLoadPtr ptr mem)
 	// cond:
 	// result: (LDAR  ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64LDAR)
@@ -9282,13 +10563,12 @@ func rewriteValueARM64_OpAtomicLoadPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicOr8  ptr val mem)
+func rewriteValueARM64_OpAtomicOr8_0(v *Value) bool {
+	// match: (AtomicOr8 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicOr8  ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9299,13 +10579,12 @@ func rewriteValueARM64_OpAtomicOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicStore32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStore32      ptr val mem)
+func rewriteValueARM64_OpAtomicStore32_0(v *Value) bool {
+	// match: (AtomicStore32 ptr val mem)
 	// cond:
 	// result: (STLRW ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9316,13 +10595,12 @@ func rewriteValueARM64_OpAtomicStore32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicStore64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStore64      ptr val mem)
+func rewriteValueARM64_OpAtomicStore64_0(v *Value) bool {
+	// match: (AtomicStore64 ptr val mem)
 	// cond:
 	// result: (STLR  ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9333,13 +10611,12 @@ func rewriteValueARM64_OpAtomicStore64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpAtomicStorePtrNoWB_0(v *Value) bool {
 	// match: (AtomicStorePtrNoWB ptr val mem)
 	// cond:
 	// result: (STLR  ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -9350,42 +10627,108 @@ func rewriteValueARM64_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpAvg64u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpAvg64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Avg64u <t> x y)
 	// cond:
-	// result: (ADD (ADD <t> (SRLconst <t> x [1]) (SRLconst <t> y [1])) (AND <t> (AND <t> x y) (MOVDconst [1])))
+	// result: (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64ADD)
-		v0 := b.NewValue0(v.Line, OpARM64ADD, t)
-		v1 := b.NewValue0(v.Line, OpARM64SRLconst, t)
-		v1.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpARM64SRLconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpARM64SUB, t)
 		v1.AddArg(x)
+		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64SRLconst, t)
-		v2.AuxInt = 1
-		v2.AddArg(y)
-		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpARM64AND, t)
-		v4 := b.NewValue0(v.Line, OpARM64AND, t)
-		v4.AddArg(x)
-		v4.AddArg(y)
-		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
-		v5.AuxInt = 1
-		v3.AddArg(v5)
-		v.AddArg(v3)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueARM64_OpBitLen64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen64 x)
+	// cond:
+	// result: (SUB (MOVDconst [64]) (CLZ <typ.Int> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpARM64SUB)
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
+		v0.AuxInt = 64
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpARM64CLZ, typ.Int)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueARM64_OpBitRev16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitRev16 x)
+	// cond:
+	// result: (SRLconst [48] (RBIT <typ.UInt64> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpARM64SRLconst)
+		v.AuxInt = 48
+		v0 := b.NewValue0(v.Pos, OpARM64RBIT, typ.UInt64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueARM64_OpBitRev32_0(v *Value) bool {
+	// match: (BitRev32 x)
+	// cond:
+	// result: (RBITW x)
+	for {
+		x := v.Args[0]
+		v.reset(OpARM64RBITW)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueARM64_OpBitRev64_0(v *Value) bool {
+	// match: (BitRev64 x)
+	// cond:
+	// result: (RBIT x)
+	for {
+		x := v.Args[0]
+		v.reset(OpARM64RBIT)
+		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueARM64_OpBswap32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpBitRev8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitRev8 x)
+	// cond:
+	// result: (SRLconst [56] (RBIT <typ.UInt64> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpARM64SRLconst)
+		v.AuxInt = 56
+		v0 := b.NewValue0(v.Pos, OpARM64RBIT, typ.UInt64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueARM64_OpBswap32_0(v *Value) bool {
 	// match: (Bswap32 x)
 	// cond:
 	// result: (REVW x)
@@ -9396,9 +10739,7 @@ func rewriteValueARM64_OpBswap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpBswap64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpBswap64_0(v *Value) bool {
 	// match: (Bswap64 x)
 	// cond:
 	// result: (REV x)
@@ -9409,14 +10750,13 @@ func rewriteValueARM64_OpBswap64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpClosureCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -9428,9 +10768,7 @@ func rewriteValueARM64_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
 	// result: (MVN x)
@@ -9441,9 +10779,7 @@ func rewriteValueARM64_OpCom16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
 	// result: (MVN x)
@@ -9454,9 +10790,7 @@ func rewriteValueARM64_OpCom32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCom64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCom64_0(v *Value) bool {
 	// match: (Com64 x)
 	// cond:
 	// result: (MVN x)
@@ -9467,9 +10801,7 @@ func rewriteValueARM64_OpCom64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCom8_0(v *Value) bool {
 	// match: (Com8 x)
 	// cond:
 	// result: (MVN x)
@@ -9480,9 +10812,7 @@ func rewriteValueARM64_OpCom8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst16_0(v *Value) bool {
 	// match: (Const16 [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -9493,9 +10823,7 @@ func rewriteValueARM64_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst32_0(v *Value) bool {
 	// match: (Const32 [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -9506,9 +10834,7 @@ func rewriteValueARM64_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (FMOVSconst [val])
@@ -9519,9 +10845,7 @@ func rewriteValueARM64_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst64_0(v *Value) bool {
 	// match: (Const64 [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -9532,9 +10856,7 @@ func rewriteValueARM64_OpConst64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (FMOVDconst [val])
@@ -9545,9 +10867,7 @@ func rewriteValueARM64_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConst8_0(v *Value) bool {
 	// match: (Const8 [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -9558,9 +10878,7 @@ func rewriteValueARM64_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVDconst [b])
@@ -9571,9 +10889,7 @@ func rewriteValueARM64_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVDconst [0])
@@ -9583,13 +10899,12 @@ func rewriteValueARM64_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpConvert_0(v *Value) bool {
 	// match: (Convert x mem)
 	// cond:
 	// result: (MOVDconvert x mem)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64MOVDconvert)
@@ -9598,7 +10913,7 @@ func rewriteValueARM64_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCtz32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpCtz32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Ctz32 <t> x)
@@ -9608,13 +10923,13 @@ func rewriteValueARM64_OpCtz32(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpARM64CLZW)
-		v0 := b.NewValue0(v.Line, OpARM64RBITW, t)
+		v0 := b.NewValue0(v.Pos, OpARM64RBITW, t)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpCtz64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpCtz64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Ctz64 <t> x)
@@ -9624,15 +10939,13 @@ func rewriteValueARM64_OpCtz64(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpARM64CLZ)
-		v0 := b.NewValue0(v.Line, OpARM64RBIT, t)
+		v0 := b.NewValue0(v.Pos, OpARM64RBIT, t)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (FCVTZSSW x)
@@ -9643,9 +10956,7 @@ func rewriteValueARM64_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Fto32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Fto32U_0(v *Value) bool {
 	// match: (Cvt32Fto32U x)
 	// cond:
 	// result: (FCVTZUSW x)
@@ -9656,9 +10967,7 @@ func rewriteValueARM64_OpCvt32Fto32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Fto64_0(v *Value) bool {
 	// match: (Cvt32Fto64 x)
 	// cond:
 	// result: (FCVTZSS x)
@@ -9669,9 +10978,7 @@ func rewriteValueARM64_OpCvt32Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (FCVTSD x)
@@ -9682,9 +10989,7 @@ func rewriteValueARM64_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Fto64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Fto64U_0(v *Value) bool {
 	// match: (Cvt32Fto64U x)
 	// cond:
 	// result: (FCVTZUS x)
@@ -9695,9 +11000,7 @@ func rewriteValueARM64_OpCvt32Fto64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Uto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Uto32F_0(v *Value) bool {
 	// match: (Cvt32Uto32F x)
 	// cond:
 	// result: (UCVTFWS x)
@@ -9708,9 +11011,7 @@ func rewriteValueARM64_OpCvt32Uto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32Uto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32Uto64F_0(v *Value) bool {
 	// match: (Cvt32Uto64F x)
 	// cond:
 	// result: (UCVTFWD x)
@@ -9721,9 +11022,7 @@ func rewriteValueARM64_OpCvt32Uto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (SCVTFWS x)
@@ -9734,9 +11033,7 @@ func rewriteValueARM64_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (SCVTFWD x)
@@ -9747,9 +11044,7 @@ func rewriteValueARM64_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (FCVTZSDW x)
@@ -9760,9 +11055,7 @@ func rewriteValueARM64_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (FCVTDS x)
@@ -9773,9 +11066,7 @@ func rewriteValueARM64_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Fto32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Fto32U_0(v *Value) bool {
 	// match: (Cvt64Fto32U x)
 	// cond:
 	// result: (FCVTZUDW x)
@@ -9786,9 +11077,7 @@ func rewriteValueARM64_OpCvt64Fto32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Fto64_0(v *Value) bool {
 	// match: (Cvt64Fto64 x)
 	// cond:
 	// result: (FCVTZSD x)
@@ -9799,9 +11088,7 @@ func rewriteValueARM64_OpCvt64Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Fto64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Fto64U_0(v *Value) bool {
 	// match: (Cvt64Fto64U x)
 	// cond:
 	// result: (FCVTZUD x)
@@ -9812,9 +11099,7 @@ func rewriteValueARM64_OpCvt64Fto64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64Uto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64Uto32F_0(v *Value) bool {
 	// match: (Cvt64Uto32F x)
 	// cond:
 	// result: (UCVTFS x)
@@ -9824,10 +11109,8 @@ func rewriteValueARM64_OpCvt64Uto32F(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-}
-func rewriteValueARM64_OpCvt64Uto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+}
+func rewriteValueARM64_OpCvt64Uto64F_0(v *Value) bool {
 	// match: (Cvt64Uto64F x)
 	// cond:
 	// result: (UCVTFD x)
@@ -9838,9 +11121,7 @@ func rewriteValueARM64_OpCvt64Uto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64to32F_0(v *Value) bool {
 	// match: (Cvt64to32F x)
 	// cond:
 	// result: (SCVTFS x)
@@ -9851,9 +11132,7 @@ func rewriteValueARM64_OpCvt64to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpCvt64to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpCvt64to64F_0(v *Value) bool {
 	// match: (Cvt64to64F x)
 	// cond:
 	// result: (SCVTFD x)
@@ -9864,66 +11143,56 @@ func rewriteValueARM64_OpCvt64to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_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(OpARM64CALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueARM64_OpDiv16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16 x y)
 	// cond:
 	// result: (DIVW (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64DIVW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (UDIVW (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UDIVW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv32_0(v *Value) bool {
 	// match: (Div32 x y)
 	// cond:
 	// result: (DIVW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64DIVW)
@@ -9932,13 +11201,12 @@ func rewriteValueARM64_OpDiv32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (FDIVS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FDIVS)
@@ -9947,13 +11215,12 @@ func rewriteValueARM64_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv32u_0(v *Value) bool {
 	// match: (Div32u x y)
 	// cond:
 	// result: (UDIVW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UDIVW)
@@ -9962,13 +11229,12 @@ func rewriteValueARM64_OpDiv32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv64_0(v *Value) bool {
 	// match: (Div64 x y)
 	// cond:
 	// result: (DIV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64DIV)
@@ -9977,13 +11243,12 @@ func rewriteValueARM64_OpDiv64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (FDIVD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FDIVD)
@@ -9992,13 +11257,12 @@ func rewriteValueARM64_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpDiv64u_0(v *Value) bool {
 	// match: (Div64u x y)
 	// cond:
 	// result: (UDIV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UDIV)
@@ -10007,380 +11271,416 @@ func rewriteValueARM64_OpDiv64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8 x y)
 	// cond:
 	// result: (DIVW (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64DIVW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8u x y)
 	// cond:
 	// result: (UDIVW (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UDIVW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq16 x y)
 	// cond:
 	// result: (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32 x y)
 	// cond:
 	// result: (Equal (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (Equal (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64 x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (Equal (FCMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEq8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq8 x y)
 	// cond:
 	// result: (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpEqB(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqB x y)
 	// cond:
-	// result: (XOR (MOVDconst [1]) (XOR <config.fe.TypeBool()> x y))
+	// result: (XOR (MOVDconst [1]) (XOR <typ.Bool> x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64XOR, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpARM64XOR, typ.Bool)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValueARM64_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (EqPtr x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64Equal)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (GreaterEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (GreaterEqual (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32U x y)
 	// cond:
 	// result: (GreaterEqualU (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64 x y)
 	// cond:
 	// result: (GreaterEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (GreaterEqual (FCMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq64U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64U x y)
 	// cond:
 	// result: (GreaterEqualU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8U x y)
 	// cond:
 	// result: (GreaterEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -10389,294 +11689,258 @@ func rewriteValueARM64_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_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(OpARM64CALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueARM64_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16 x y)
 	// cond:
 	// result: (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (GreaterThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32 x y)
 	// cond:
 	// result: (GreaterThan (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (GreaterThan (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32U x y)
 	// cond:
 	// result: (GreaterThanU (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64 x y)
 	// cond:
 	// result: (GreaterThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (GreaterThan (FCMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater64U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64U x y)
 	// cond:
 	// result: (GreaterThanU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8 x y)
 	// cond:
 	// result: (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8U x y)
 	// cond:
 	// result: (GreaterThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM64_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16 x y)
-	// cond:
-	// result: (SRAconst (MULW <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARM64SRAconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpARM64MULW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM64_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARM64SRLconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpARM64MUL, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpHmul32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpHmul32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32 x y)
 	// cond:
-	// result: (SRAconst (MULL <config.fe.TypeInt64()> x y) [32])
+	// result: (SRAconst (MULL <typ.Int64> x y) [32])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpARM64MULL, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MULL, typ.Int64)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpHmul32u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpHmul32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32u x y)
 	// cond:
-	// result: (SRAconst (UMULL <config.fe.TypeUInt64()> x y) [32])
+	// result: (SRAconst (UMULL <typ.UInt64> x y) [32])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpARM64UMULL, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64UMULL, typ.UInt64)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpHmul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpHmul64_0(v *Value) bool {
 	// match: (Hmul64 x y)
 	// cond:
 	// result: (MULH x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MULH)
@@ -10685,13 +11949,12 @@ func rewriteValueARM64_OpHmul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpHmul64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpHmul64u_0(v *Value) bool {
 	// match: (Hmul64u x y)
 	// cond:
 	// result: (UMULH x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UMULH)
@@ -10700,58 +11963,13 @@ func rewriteValueARM64_OpHmul64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8 x y)
-	// cond:
-	// result: (SRAconst (MULW <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARM64SRAconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpARM64MULW, config.fe.TypeInt16())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM64_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpARM64SRLconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpARM64MUL, config.fe.TypeUInt16())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueARM64_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64CALLinter)
@@ -10761,24 +11979,25 @@ func rewriteValueARM64_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValueARM64_OpIsInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (LessThanU (CMP idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpARM64LessThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValueARM64_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsNonNil ptr)
@@ -10787,410 +12006,446 @@ func rewriteValueARM64_OpIsNonNil(v *Value, config *Config) bool {
 	for {
 		ptr := v.Args[0]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v0.AuxInt = 0
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValueARM64_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (LessEqualU (CMP idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpARM64LessEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16 x y)
 	// cond:
 	// result: (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (LessEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32 x y)
 	// cond:
 	// result: (LessEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (GreaterEqual (FCMPS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32U x y)
 	// cond:
 	// result: (LessEqualU (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64 x y)
 	// cond:
 	// result: (LessEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (GreaterEqual (FCMPD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq64U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64U x y)
 	// cond:
 	// result: (LessEqualU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8 x y)
 	// cond:
 	// result: (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8U x y)
 	// cond:
 	// result: (LessEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessEqualU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16 x y)
 	// cond:
 	// result: (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (LessThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32 x y)
 	// cond:
 	// result: (LessThan (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (GreaterThan (FCMPS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess32U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32U x y)
 	// cond:
 	// result: (LessThanU (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64 x y)
 	// cond:
 	// result: (LessThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (GreaterThan (FCMPD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess64U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64U x y)
 	// cond:
 	// result: (LessThanU (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8 x y)
 	// cond:
 	// result: (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThan)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLess8U(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8U x y)
 	// cond:
 	// result: (LessThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64LessThanU)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: t.IsBoolean()
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean()) {
@@ -11206,6 +12461,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
@@ -11221,6 +12477,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && !isSigned(t)) {
@@ -11236,6 +12493,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -11251,6 +12509,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -11266,6 +12525,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && isSigned(t)) {
@@ -11281,6 +12541,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && !isSigned(t)) {
@@ -11296,6 +12557,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) || isPtr(t)) {
@@ -11311,6 +12573,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVSload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -11326,6 +12589,7 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitFloat(t)) {
@@ -11338,149 +12602,78 @@ func rewriteValueARM64_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpLrot16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot16 <t> x [c])
-	// cond:
-	// result: (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to64 x) [16-c&15]))
-	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARM64OR)
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, t)
-		v0.AuxInt = c & 15
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64SRLconst, t)
-		v1.AuxInt = 16 - c&15
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v.AddArg(v1)
-		return true
-	}
-}
-func rewriteValueARM64_OpLrot32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot32 x [c])
-	// cond:
-	// result: (RORWconst x [32-c&31])
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARM64RORWconst)
-		v.AuxInt = 32 - c&31
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueARM64_OpLrot64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot64 x [c])
-	// cond:
-	// result: (RORconst  x [64-c&63])
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARM64RORconst)
-		v.AuxInt = 64 - c&63
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueARM64_OpLrot8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot8  <t> x [c])
-	// cond:
-	// result: (OR (SLLconst <t> x [c&7])  (SRLconst <t> (ZeroExt8to64  x) [8-c&7]))
-	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpARM64OR)
-		v0 := b.NewValue0(v.Line, OpARM64SLLconst, t)
-		v0.AuxInt = c & 7
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64SRLconst, t)
-		v1.AuxInt = 8 - c&7
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v.AddArg(v1)
-		return true
-	}
-}
-func rewriteValueARM64_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x32 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x64  x (MOVDconst [c]))
+	// match: (Lsh16x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 16
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -11495,10 +12688,11 @@ func rewriteValueARM64_OpLsh16x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x64  _ (MOVDconst [c]))
+	// match: (Lsh16x64 _ (MOVDconst [c]))
 	// cond: uint64(c) >= 16
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -11516,117 +12710,128 @@ func rewriteValueARM64_OpLsh16x64(v *Value, config *Config) bool {
 	// result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x8 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x32 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh32x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x64  x (MOVDconst [c]))
+	// match: (Lsh32x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 32
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -11641,10 +12846,11 @@ func rewriteValueARM64_OpLsh32x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh32x64  _ (MOVDconst [c]))
+	// match: (Lsh32x64 _ (MOVDconst [c]))
 	// cond: uint64(c) >= 32
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -11662,117 +12868,128 @@ func rewriteValueARM64_OpLsh32x64(v *Value, config *Config) bool {
 	// result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x8 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh64x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x16 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh64x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x32 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x64  x (MOVDconst [c]))
+	// match: (Lsh64x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 64
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -11787,10 +13004,11 @@ func rewriteValueARM64_OpLsh64x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x64  _ (MOVDconst [c]))
+	// match: (Lsh64x64 _ (MOVDconst [c]))
 	// cond: uint64(c) >= 64
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -11808,117 +13026,128 @@ func rewriteValueARM64_OpLsh64x64(v *Value, config *Config) bool {
 	// result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x8 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x32 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh8x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x64   x (MOVDconst [c]))
+	// match: (Lsh8x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -11933,10 +13162,11 @@ func rewriteValueARM64_OpLsh8x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh8x64   _ (MOVDconst [c]))
+	// match: (Lsh8x64 _ (MOVDconst [c]))
 	// cond: uint64(c) >= 8
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -11954,97 +13184,106 @@ func rewriteValueARM64_OpLsh8x64(v *Value, config *Config) bool {
 	// result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM64_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x8 <t> x y)
 	// cond:
 	// result: (CSELULT (SLL <t> x (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpMod16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16 x y)
 	// cond:
 	// result: (MODW (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MODW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpMod16u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (UMODW (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UMODW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpMod32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMod32_0(v *Value) bool {
 	// match: (Mod32 x y)
 	// cond:
 	// result: (MODW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MODW)
@@ -12053,13 +13292,12 @@ func rewriteValueARM64_OpMod32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMod32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMod32u_0(v *Value) bool {
 	// match: (Mod32u x y)
 	// cond:
 	// result: (UMODW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UMODW)
@@ -12068,13 +13306,12 @@ func rewriteValueARM64_OpMod32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMod64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMod64_0(v *Value) bool {
 	// match: (Mod64 x y)
 	// cond:
 	// result: (MOD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MOD)
@@ -12083,13 +13320,12 @@ func rewriteValueARM64_OpMod64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMod64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMod64u_0(v *Value) bool {
 	// match: (Mod64u x y)
 	// cond:
 	// result: (UMOD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UMOD)
@@ -12098,163 +13334,171 @@ func rewriteValueARM64_OpMod64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMod8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8 x y)
 	// cond:
 	// result: (MODW (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MODW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpMod8u(v *Value, config *Config) bool {
+func rewriteValueARM64_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8u x y)
 	// cond:
 	// result: (UMODW (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64UMODW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
+func rewriteValueARM64_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpARM64MOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVBUload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVHstore dst (MOVHUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(OpARM64MOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVHUload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVWstore dst (MOVWUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpARM64MOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVWUload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Move [8] dst src mem)
+	// cond:
 	// result: (MOVDstore dst (MOVDload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8) {
-			break
-		}
 		v.reset(OpARM64MOVDstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBUload [2] src mem) 		(MOVHstore dst (MOVHUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVBUload, typ.UInt8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVHUload, typ.UInt16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -12262,28 +13506,28 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Move [5] dst src mem)
+	// cond:
 	// result: (MOVBstore [4] dst (MOVBUload [4] src mem) 		(MOVWstore dst (MOVWUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 5 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 5) {
-			break
-		}
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVBUload, typ.UInt8)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVWUload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -12291,28 +13535,28 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Move [6] dst src mem)
+	// cond:
 	// result: (MOVHstore [4] dst (MOVHUload [4] src mem) 		(MOVWstore dst (MOVWUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6) {
-			break
-		}
 		v.reset(OpARM64MOVHstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVHUload, typ.UInt16)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVWUload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -12320,36 +13564,36 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	// match: (Move [7] dst src mem)
+	// cond:
 	// result: (MOVBstore [6] dst (MOVBUload [6] src mem) 		(MOVHstore [4] dst (MOVHUload [4] src mem) 			(MOVWstore dst (MOVWUload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 7 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 7) {
-			break
-		}
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 6
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVBUload, typ.UInt8)
 		v0.AuxInt = 6
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVHUload, typ.UInt16)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpARM64MOVWUload, typ.UInt32)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -12358,28 +13602,28 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 12
+	// match: (Move [12] dst src mem)
+	// cond:
 	// result: (MOVWstore [8] dst (MOVWUload [8] src mem) 		(MOVDstore dst (MOVDload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 12 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 12) {
-			break
-		}
 		v.reset(OpARM64MOVWstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVWUload, typ.UInt32)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -12387,28 +13631,37 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 16
+	return false
+}
+func rewriteValueARM64_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [16] dst src mem)
+	// cond:
 	// result: (MOVDstore [8] dst (MOVDload [8] src mem) 		(MOVDstore dst (MOVDload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 16) {
-			break
-		}
 		v.reset(OpARM64MOVDstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -12416,36 +13669,36 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 24
+	// match: (Move [24] dst src mem)
+	// cond:
 	// result: (MOVDstore [16] dst (MOVDload [16] src mem) 		(MOVDstore [8] dst (MOVDload [8] src mem) 			(MOVDstore dst (MOVDload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 24 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 24) {
-			break
-		}
 		v.reset(OpARM64MOVDstore)
 		v.AuxInt = 16
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v0.AuxInt = 16
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v2.AuxInt = 8
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpARM64MOVDload, typ.UInt64)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -12455,28 +13708,29 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8
-	// result: (Move [MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()] 		(OffPtr <dst.Type> dst [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8]) 		(OffPtr <src.Type> src [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8]) 		(Move [MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()] dst src mem))
+	// cond: s%8 != 0 && s > 8
+	// result: (Move [s%8] 		(OffPtr <dst.Type> dst [s-s%8]) 		(OffPtr <src.Type> src [s-s%8]) 		(Move [s-s%8] dst src mem))
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8) {
+		if !(s%8 != 0 && s > 8) {
 			break
 		}
 		v.reset(OpMove)
-		v.AuxInt = MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()
-		v0 := b.NewValue0(v.Line, OpOffPtr, dst.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%8
+		v.AuxInt = s % 8
+		v0 := b.NewValue0(v.Pos, OpOffPtr, dst.Type)
+		v0.AuxInt = s - s%8
 		v0.AddArg(dst)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOffPtr, src.Type)
-		v1.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%8
+		v1 := b.NewValue0(v.Pos, OpOffPtr, src.Type)
+		v1.AuxInt = s - s%8
 		v1.AddArg(src)
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMove, TypeMem)
-		v2.AuxInt = MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()
+		v2 := b.NewValue0(v.Pos, OpMove, types.TypeMem)
+		v2.AuxInt = s - s%8
 		v2.AddArg(dst)
 		v2.AddArg(src)
 		v2.AddArg(mem)
@@ -12484,39 +13738,41 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 	&& !config.noDuffDevice
-	// result: (DUFFCOPY [8 * (128 - int64(SizeAndAlign(s).Size()/8))] dst src mem)
+	// cond: s%8 == 0 && s > 24 && s <= 8*128 	&& !config.noDuffDevice
+	// result: (DUFFCOPY [8 * (128 - int64(s/8))] dst src mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 && !config.noDuffDevice) {
+		if !(s%8 == 0 && s > 24 && s <= 8*128 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(OpARM64DUFFCOPY)
-		v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/8))
+		v.AuxInt = 8 * (128 - int64(s/8))
 		v.AddArg(dst)
 		v.AddArg(src)
 		v.AddArg(mem)
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size()%8 == 0
-	// result: (LoweredMove 		dst 		src 		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// cond: s > 24 && s%8 == 0
+	// result: (LoweredMove 		dst 		src 		(ADDconst <src.Type> src [s-8]) 		mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size()%8 == 0) {
+		if !(s > 24 && s%8 == 0) {
 			break
 		}
 		v.reset(OpARM64LoweredMove)
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpARM64ADDconst, src.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDconst, src.Type)
+		v0.AuxInt = s - 8
 		v0.AddArg(src)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -12524,13 +13780,12 @@ func rewriteValueARM64_OpMove(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul16_0(v *Value) bool {
 	// match: (Mul16 x y)
 	// cond:
 	// result: (MULW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MULW)
@@ -12539,13 +13794,12 @@ func rewriteValueARM64_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul32_0(v *Value) bool {
 	// match: (Mul32 x y)
 	// cond:
 	// result: (MULW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MULW)
@@ -12554,13 +13808,12 @@ func rewriteValueARM64_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (FMULS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FMULS)
@@ -12569,13 +13822,12 @@ func rewriteValueARM64_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul64_0(v *Value) bool {
 	// match: (Mul64 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MUL)
@@ -12584,13 +13836,12 @@ func rewriteValueARM64_OpMul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (FMULD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FMULD)
@@ -12599,13 +13850,12 @@ func rewriteValueARM64_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpMul8_0(v *Value) bool {
 	// match: (Mul8 x y)
 	// cond:
 	// result: (MULW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64MULW)
@@ -12614,9 +13864,7 @@ func rewriteValueARM64_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg16_0(v *Value) bool {
 	// match: (Neg16 x)
 	// cond:
 	// result: (NEG x)
@@ -12627,9 +13875,7 @@ func rewriteValueARM64_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg32_0(v *Value) bool {
 	// match: (Neg32 x)
 	// cond:
 	// result: (NEG x)
@@ -12640,9 +13886,7 @@ func rewriteValueARM64_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (FNEGS x)
@@ -12653,9 +13897,7 @@ func rewriteValueARM64_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg64_0(v *Value) bool {
 	// match: (Neg64 x)
 	// cond:
 	// result: (NEG x)
@@ -12666,9 +13908,7 @@ func rewriteValueARM64_OpNeg64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (FNEGD x)
@@ -12679,9 +13919,7 @@ func rewriteValueARM64_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeg8_0(v *Value) bool {
 	// match: (Neg8 x)
 	// cond:
 	// result: (NEG x)
@@ -12692,123 +13930,132 @@ func rewriteValueARM64_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq16 x y)
 	// cond:
 	// result: (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32 x y)
 	// cond:
 	// result: (NotEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (NotEqual (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPS, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64 x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (NotEqual (FCMPD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64FCMPD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeq8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq8 x y)
 	// cond:
 	// result: (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNeqB_0(v *Value) bool {
 	// match: (NeqB x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
@@ -12817,30 +14064,30 @@ func rewriteValueARM64_OpNeqB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64NotEqual)
-		v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpARM64LoweredNilCheck)
@@ -12849,25 +14096,25 @@ func rewriteValueARM64_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpNot(v *Value, config *Config) bool {
+func rewriteValueARM64_OpNot_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Not x)
 	// cond:
 	// result: (XOR (MOVDconst [1]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpARM64XOR)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueARM64_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOffPtr_0(v *Value) bool {
 	// match: (OffPtr [off] ptr:(SP))
 	// cond:
 	// result: (MOVDaddr [off] ptr)
@@ -12894,13 +14141,12 @@ func rewriteValueARM64_OpOffPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64OR)
@@ -12909,13 +14155,12 @@ func rewriteValueARM64_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64OR)
@@ -12924,13 +14169,12 @@ func rewriteValueARM64_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpOr64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOr64_0(v *Value) bool {
 	// match: (Or64 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64OR)
@@ -12939,13 +14183,12 @@ func rewriteValueARM64_OpOr64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOr8_0(v *Value) bool {
 	// match: (Or8 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64OR)
@@ -12954,13 +14197,12 @@ func rewriteValueARM64_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64OR)
@@ -12969,75 +14211,108 @@ func rewriteValueARM64_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueARM64_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueARM64_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux16 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 x (MOVDconst [c]))
 	// cond: uint64(c) < 16
 	// result: (SRLconst (ZeroExt16to64 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13049,7 +14324,7 @@ func rewriteValueARM64_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRLconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13058,6 +14333,7 @@ func rewriteValueARM64_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -13075,79 +14351,86 @@ func rewriteValueARM64_OpRsh16Ux64(v *Value, config *Config) bool {
 	// result: (CSELULT (SRL <t> (ZeroExt16to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux8 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 x y)
 	// cond:
 	// result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13155,29 +14438,32 @@ func rewriteValueARM64_OpRsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x32 x y)
 	// cond:
 	// result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13185,13 +14471,16 @@ func rewriteValueARM64_OpRsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x64  x (MOVDconst [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 16
 	// result: (SRAconst (SignExt16to64 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13203,7 +14492,7 @@ func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13212,6 +14501,7 @@ func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (SRAconst (SignExt16to64 x) [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13223,7 +14513,7 @@ func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = 63
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13232,18 +14522,19 @@ func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA (SignExt16to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v1.AddArg(v3)
@@ -13251,29 +14542,32 @@ func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x8 x y)
 	// cond:
 	// result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt8to64  y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64  y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13281,75 +14575,84 @@ func rewriteValueARM64_OpRsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux32 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux64 x (MOVDconst [c]))
 	// cond: uint64(c) < 32
 	// result: (SRLconst (ZeroExt32to64 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13361,7 +14664,7 @@ func rewriteValueARM64_OpRsh32Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRLconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13370,6 +14673,7 @@ func rewriteValueARM64_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -13387,79 +14691,86 @@ func rewriteValueARM64_OpRsh32Ux64(v *Value, config *Config) bool {
 	// result: (CSELULT (SRL <t> (ZeroExt32to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32Ux8 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 x y)
 	// cond:
 	// result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13467,29 +14778,32 @@ func rewriteValueARM64_OpRsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x32 x y)
 	// cond:
 	// result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13497,13 +14811,16 @@ func rewriteValueARM64_OpRsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x64  x (MOVDconst [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 32
 	// result: (SRAconst (SignExt32to64 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13515,7 +14832,7 @@ func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13524,6 +14841,7 @@ func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (SRAconst (SignExt32to64 x) [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13535,7 +14853,7 @@ func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = 63
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -13544,18 +14862,19 @@ func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA (SignExt32to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v1.AddArg(v3)
@@ -13563,29 +14882,32 @@ func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x8 x y)
 	// cond:
 	// result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt8to64  y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64  y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -13593,71 +14915,78 @@ func rewriteValueARM64_OpRsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux16 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux32 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh64Ux64 x (MOVDconst [c]))
 	// cond: uint64(c) < 64
 	// result: (SRLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13676,6 +15005,7 @@ func rewriteValueARM64_OpRsh64Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 64
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -13693,73 +15023,80 @@ func rewriteValueARM64_OpRsh64Ux64(v *Value, config *Config) bool {
 	// result: (CSELULT (SRL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64Ux8 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> x (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x16 x y)
 	// cond:
 	// result: (SRA x (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
@@ -13767,27 +15104,30 @@ func rewriteValueARM64_OpRsh64x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x32 x y)
 	// cond:
 	// result: (SRA x (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
@@ -13795,13 +15135,14 @@ func rewriteValueARM64_OpRsh64x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x64  x (MOVDconst [c]))
+	// match: (Rsh64x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 64
 	// result: (SRAconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13820,6 +15161,7 @@ func rewriteValueARM64_OpRsh64x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 64
 	// result: (SRAconst x [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13838,16 +15180,17 @@ func rewriteValueARM64_OpRsh64x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA x (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+		v0 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v1 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v1.AuxInt = 63
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v2.AuxInt = 64
 		v2.AddArg(y)
 		v0.AddArg(v2)
@@ -13855,27 +15198,30 @@ func rewriteValueARM64_OpRsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh64x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x8 x y)
 	// cond:
 	// result: (SRA x (CSELULT <y.Type> (ZeroExt8to64  y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64  y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
@@ -13883,75 +15229,84 @@ func rewriteValueARM64_OpRsh64x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux32 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux64  x (MOVDconst [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SRLconst (ZeroExt8to64  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -13963,15 +15318,16 @@ func rewriteValueARM64_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRLconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8Ux64  _ (MOVDconst [c]))
+	// match: (Rsh8Ux64 _ (MOVDconst [c]))
 	// cond: uint64(c) >= 8
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
 			break
@@ -13989,79 +15345,86 @@ func rewriteValueARM64_OpRsh8Ux64(v *Value, config *Config) bool {
 	// result: (CSELULT (SRL <t> (ZeroExt8to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux8 <t> x y)
 	// cond:
 	// result: (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt8to64  y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64CSELULT)
-		v0 := b.NewValue0(v.Line, OpARM64SRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64SRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 x y)
 	// cond:
 	// result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -14069,29 +15432,32 @@ func rewriteValueARM64_OpRsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x32 x y)
 	// cond:
 	// result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -14099,13 +15465,16 @@ func rewriteValueARM64_OpRsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x64   x (MOVDconst [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SRAconst (SignExt8to64  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -14117,15 +15486,16 @@ func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8x64  x (MOVDconst [c]))
+	// match: (Rsh8x64 x (MOVDconst [c]))
 	// cond: uint64(c) >= 8
 	// result: (SRAconst (SignExt8to64  x) [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpARM64MOVDconst {
@@ -14137,7 +15507,7 @@ func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpARM64SRAconst)
 		v.AuxInt = 63
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -14146,18 +15516,19 @@ func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRA (SignExt8to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v2 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v2.AuxInt = 63
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v3.AuxInt = 64
 		v3.AddArg(y)
 		v1.AddArg(v3)
@@ -14165,29 +15536,32 @@ func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueARM64_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x8  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x8 x y)
 	// cond:
 	// result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt8to64  y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64  y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SRA)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpARM64CSELULT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+		v3 := b.NewValue0(v.Pos, OpConst64, y.Type)
 		v3.AuxInt = 63
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpARM64CMPconst, types.TypeFlags)
 		v4.AuxInt = 64
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -14195,9 +15569,7 @@ func rewriteValueARM64_OpRsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -14208,9 +15580,7 @@ func rewriteValueARM64_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt16to64_0(v *Value) bool {
 	// match: (SignExt16to64 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -14221,9 +15591,7 @@ func rewriteValueARM64_OpSignExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt32to64_0(v *Value) bool {
 	// match: (SignExt32to64 x)
 	// cond:
 	// result: (MOVWreg x)
@@ -14234,9 +15602,7 @@ func rewriteValueARM64_OpSignExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt8to16_0(v *Value) bool {
 	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -14247,9 +15613,7 @@ func rewriteValueARM64_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt8to32_0(v *Value) bool {
 	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -14260,9 +15624,7 @@ func rewriteValueARM64_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSignExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSignExt8to64_0(v *Value) bool {
 	// match: (SignExt8to64 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -14273,29 +15635,24 @@ func rewriteValueARM64_OpSignExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValueARM64_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (MVN (SRAconst <t> (SUBconst <t> x [1]) [63]))
+	// result: (SRAconst (NEG <t> x) [63])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(OpARM64MVN)
-		v0 := b.NewValue0(v.Line, OpARM64SRAconst, t)
-		v0.AuxInt = 63
-		v1 := b.NewValue0(v.Line, OpARM64SUBconst, t)
-		v1.AuxInt = 1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		v.reset(OpARM64SRAconst)
+		v.AuxInt = 63
+		v0 := b.NewValue0(v.Pos, OpARM64NEG, t)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueARM64_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (FSQRTD x)
@@ -14306,9 +15663,7 @@ func rewriteValueARM64_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -14323,52 +15678,53 @@ func rewriteValueARM64_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [1] ptr val mem)
-	// cond:
+func rewriteValueARM64_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(OpARM64MOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(OpARM64MOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: !is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARM64MOVWstore)
@@ -14377,17 +15733,16 @@ func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: !is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type)
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARM64MOVDstore)
@@ -14396,17 +15751,16 @@ func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (FMOVSstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARM64FMOVSstore)
@@ -14415,17 +15769,16 @@ func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (FMOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpARM64FMOVDstore)
@@ -14436,13 +15789,12 @@ func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub16_0(v *Value) bool {
 	// match: (Sub16 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SUB)
@@ -14451,13 +15803,12 @@ func rewriteValueARM64_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub32_0(v *Value) bool {
 	// match: (Sub32 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SUB)
@@ -14466,13 +15817,12 @@ func rewriteValueARM64_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (FSUBS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FSUBS)
@@ -14481,13 +15831,12 @@ func rewriteValueARM64_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSub64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub64_0(v *Value) bool {
 	// match: (Sub64 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SUB)
@@ -14496,13 +15845,12 @@ func rewriteValueARM64_OpSub64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (FSUBD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64FSUBD)
@@ -14511,13 +15859,12 @@ func rewriteValueARM64_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSub8_0(v *Value) bool {
 	// match: (Sub8 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SUB)
@@ -14526,13 +15873,12 @@ func rewriteValueARM64_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64SUB)
@@ -14541,9 +15887,7 @@ func rewriteValueARM64_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc16to8_0(v *Value) bool {
 	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
@@ -14555,9 +15899,7 @@ func rewriteValueARM64_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -14569,9 +15911,7 @@ func rewriteValueARM64_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc32to8_0(v *Value) bool {
 	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
@@ -14583,9 +15923,7 @@ func rewriteValueARM64_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc64to16_0(v *Value) bool {
 	// match: (Trunc64to16 x)
 	// cond:
 	// result: x
@@ -14597,9 +15935,7 @@ func rewriteValueARM64_OpTrunc64to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc64to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc64to32_0(v *Value) bool {
 	// match: (Trunc64to32 x)
 	// cond:
 	// result: x
@@ -14611,9 +15947,7 @@ func rewriteValueARM64_OpTrunc64to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpTrunc64to8_0(v *Value) bool {
 	// match: (Trunc64to8 x)
 	// cond:
 	// result: x
@@ -14625,13 +15959,12 @@ func rewriteValueARM64_OpTrunc64to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
@@ -14640,13 +15973,12 @@ func rewriteValueARM64_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
@@ -14655,13 +15987,12 @@ func rewriteValueARM64_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpXor64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpXor64_0(v *Value) bool {
 	// match: (Xor64 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
@@ -14670,13 +16001,12 @@ func rewriteValueARM64_OpXor64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpXor8_0(v *Value) bool {
 	// match: (Xor8 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpARM64XOR)
@@ -14685,195 +16015,197 @@ func rewriteValueARM64_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZero(v *Value, config *Config) bool {
+func rewriteValueARM64_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] ptr mem)
+	// cond:
 	// result: (MOVBstore ptr (MOVDconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVBstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] ptr mem)
+	// cond:
 	// result: (MOVHstore ptr (MOVDconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVHstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] ptr mem)
+	// cond:
 	// result: (MOVWstore ptr (MOVDconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVWstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Zero [8] ptr mem)
+	// cond:
 	// result: (MOVDstore ptr (MOVDconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8) {
+		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVDstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Zero [3] ptr mem)
+	// cond:
 	// result: (MOVBstore [2] ptr (MOVDconst [0]) 		(MOVHstore ptr (MOVDconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVHstore, types.TypeMem)
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Zero [5] ptr mem)
+	// cond:
 	// result: (MOVBstore [4] ptr (MOVDconst [0]) 		(MOVWstore ptr (MOVDconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 5) {
+		if v.AuxInt != 5 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Zero [6] ptr mem)
+	// cond:
 	// result: (MOVHstore [4] ptr (MOVDconst [0]) 		(MOVWstore ptr (MOVDconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6) {
+		if v.AuxInt != 6 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVHstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	// match: (Zero [7] ptr mem)
+	// cond:
 	// result: (MOVBstore [6] ptr (MOVDconst [0]) 		(MOVHstore [4] ptr (MOVDconst [0]) 			(MOVWstore ptr (MOVDconst [0]) mem)))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 7) {
+		if v.AuxInt != 7 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVBstore)
 		v.AuxInt = 6
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARM64MOVWstore, types.TypeMem)
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -14881,81 +16213,90 @@ func rewriteValueARM64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 12
+	// match: (Zero [12] ptr mem)
+	// cond:
 	// result: (MOVWstore [8] ptr (MOVDconst [0]) 		(MOVDstore ptr (MOVDconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 12) {
+		if v.AuxInt != 12 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVWstore)
 		v.AuxInt = 8
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 16
+	return false
+}
+func rewriteValueARM64_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [16] ptr mem)
+	// cond:
 	// result: (MOVDstore [8] ptr (MOVDconst [0]) 		(MOVDstore ptr (MOVDconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16) {
+		if v.AuxInt != 16 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVDstore)
 		v.AuxInt = 8
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 24
+	// match: (Zero [24] ptr mem)
+	// cond:
 	// result: (MOVDstore [16] ptr (MOVDconst [0]) 		(MOVDstore [8] ptr (MOVDconst [0]) 			(MOVDstore ptr (MOVDconst [0]) mem)))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 24) {
+		if v.AuxInt != 24 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpARM64MOVDstore)
 		v.AuxInt = 16
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpARM64MOVDstore, types.TypeMem)
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpARM64MOVDconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -14964,58 +16305,61 @@ func rewriteValueARM64_OpZero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8
-	// result: (Zero [MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()] 		(OffPtr <ptr.Type> ptr [SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8]) 		(Zero [MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()] ptr mem))
+	// cond: s%8 != 0 && s > 8
+	// result: (Zero [s%8] 		(OffPtr <ptr.Type> ptr [s-s%8]) 		(Zero [s-s%8] ptr mem))
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8) {
+		if !(s%8 != 0 && s > 8) {
 			break
 		}
 		v.reset(OpZero)
-		v.AuxInt = MakeSizeAndAlign(SizeAndAlign(s).Size()%8, 1).Int64()
-		v0 := b.NewValue0(v.Line, OpOffPtr, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%8
+		v.AuxInt = s % 8
+		v0 := b.NewValue0(v.Pos, OpOffPtr, ptr.Type)
+		v0.AuxInt = s - s%8
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZero, TypeMem)
-		v1.AuxInt = MakeSizeAndAlign(SizeAndAlign(s).Size()-SizeAndAlign(s).Size()%8, 1).Int64()
+		v1 := b.NewValue0(v.Pos, OpZero, types.TypeMem)
+		v1.AuxInt = s - s%8
 		v1.AddArg(ptr)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
 	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 	&& !config.noDuffDevice
-	// result: (DUFFZERO [4 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
+	// cond: s%8 == 0 && s > 24 && s <= 8*128 	&& !config.noDuffDevice
+	// result: (DUFFZERO [4 * (128 - int64(s/8))] ptr mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 && !config.noDuffDevice) {
+		if !(s%8 == 0 && s > 24 && s <= 8*128 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(OpARM64DUFFZERO)
-		v.AuxInt = 4 * (128 - int64(SizeAndAlign(s).Size()/8))
+		v.AuxInt = 4 * (128 - int64(s/8))
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
 	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size()%8 == 0 && (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice)
-	// result: (LoweredZero 		ptr 		(ADDconst <ptr.Type> [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)] ptr) 		mem)
+	// cond: s%8 == 0 && (s > 8*128 || config.noDuffDevice)
+	// result: (LoweredZero 		ptr 		(ADDconst <ptr.Type> [s-8] ptr) 		mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%8 == 0 && (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice)) {
+		if !(s%8 == 0 && (s > 8*128 || config.noDuffDevice)) {
 			break
 		}
 		v.reset(OpARM64LoweredZero)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpARM64ADDconst, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpARM64ADDconst, ptr.Type)
+		v0.AuxInt = s - 8
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -15023,9 +16367,7 @@ func rewriteValueARM64_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueARM64_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -15036,9 +16378,7 @@ func rewriteValueARM64_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt16to64_0(v *Value) bool {
 	// match: (ZeroExt16to64 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -15049,9 +16389,7 @@ func rewriteValueARM64_OpZeroExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt32to64_0(v *Value) bool {
 	// match: (ZeroExt32to64 x)
 	// cond:
 	// result: (MOVWUreg x)
@@ -15062,9 +16400,7 @@ func rewriteValueARM64_OpZeroExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt8to16_0(v *Value) bool {
 	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -15075,9 +16411,7 @@ func rewriteValueARM64_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt8to32_0(v *Value) bool {
 	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -15088,9 +16422,7 @@ func rewriteValueARM64_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueARM64_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueARM64_OpZeroExt8to64_0(v *Value) bool {
 	// match: (ZeroExt8to64 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -15101,7 +16433,13 @@ func rewriteValueARM64_OpZeroExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlockARM64(b *Block, config *Config) bool {
+func rewriteBlockARM64(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockARM64EQ:
 		// match: (EQ (CMPconst [0] x) yes no)
@@ -15116,12 +16454,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64Z
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (CMPWconst [0] x) yes no)
@@ -15136,12 +16470,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ZW
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagEQ) yes no)
@@ -15152,12 +16482,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15168,13 +16494,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15185,13 +16507,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15202,13 +16520,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15219,13 +16533,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (EQ (InvertFlags cmp) yes no)
@@ -15237,12 +16547,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64GE:
@@ -15254,12 +16560,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15270,13 +16572,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15287,13 +16585,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15304,12 +16598,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15320,12 +16610,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (InvertFlags cmp) yes no)
@@ -15337,12 +16623,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64GT:
@@ -15354,13 +16636,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15371,13 +16649,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15388,13 +16662,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15405,12 +16675,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15421,12 +16687,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GT (InvertFlags cmp) yes no)
@@ -15438,12 +16700,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockIf:
@@ -15456,12 +16714,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64EQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (NotEqual cc) yes no)
@@ -15473,12 +16727,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessThan cc) yes no)
@@ -15490,12 +16740,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessThanU cc) yes no)
@@ -15507,12 +16753,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessEqual cc) yes no)
@@ -15524,12 +16766,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessEqualU cc) yes no)
@@ -15541,12 +16779,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterThan cc) yes no)
@@ -15558,12 +16792,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterThanU cc) yes no)
@@ -15575,12 +16805,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterEqual cc) yes no)
@@ -15592,12 +16818,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterEqualU cc) yes no)
@@ -15609,12 +16831,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If cond yes no)
@@ -15624,12 +16842,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NZ
 			b.SetControl(cond)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64LE:
@@ -15641,12 +16855,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15657,12 +16867,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15673,12 +16879,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15689,13 +16891,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15706,13 +16904,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LE (InvertFlags cmp) yes no)
@@ -15724,12 +16918,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64LT:
@@ -15741,13 +16931,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15758,12 +16944,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15774,12 +16956,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15790,13 +16968,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15807,13 +16981,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LT (InvertFlags cmp) yes no)
@@ -15825,12 +16995,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64NE:
@@ -15846,12 +17012,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] x) yes no)
@@ -15866,12 +17028,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NZW
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagEQ) yes no)
@@ -15882,13 +17040,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -15899,12 +17053,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15915,12 +17065,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -15931,12 +17077,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -15947,12 +17089,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (InvertFlags cmp) yes no)
@@ -15964,12 +17102,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64NZ:
@@ -15982,12 +17116,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64EQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (NotEqual cc) yes no)
@@ -15999,12 +17129,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64NE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (LessThan cc) yes no)
@@ -16016,12 +17142,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (LessThanU cc) yes no)
@@ -16033,12 +17155,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (LessEqual cc) yes no)
@@ -16050,12 +17168,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64LE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (LessEqualU cc) yes no)
@@ -16067,12 +17181,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (GreaterThan cc) yes no)
@@ -16084,12 +17194,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (GreaterThanU cc) yes no)
@@ -16101,12 +17207,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (GreaterEqual cc) yes no)
@@ -16118,12 +17220,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64GE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (GreaterEqualU cc) yes no)
@@ -16135,12 +17233,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NZ (MOVDconst [0]) yes no)
@@ -16154,13 +17248,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (NZ (MOVDconst [c]) yes no)
@@ -16172,15 +17262,11 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c != 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64NZW:
@@ -16193,16 +17279,12 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) == 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (NZW (MOVDconst [c]) yes no)
@@ -16214,15 +17296,11 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) != 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64UGE:
@@ -16234,12 +17312,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -16250,13 +17324,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16267,12 +17337,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16283,13 +17349,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -16300,12 +17362,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGE (InvertFlags cmp) yes no)
@@ -16317,12 +17375,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64UGT:
@@ -16334,13 +17388,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -16351,13 +17401,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16368,12 +17414,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16384,13 +17426,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -16401,12 +17439,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (UGT (InvertFlags cmp) yes no)
@@ -16418,12 +17452,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64ULT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64ULE:
@@ -16435,12 +17465,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -16451,12 +17477,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16467,13 +17489,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16484,12 +17502,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -16500,13 +17514,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (ULE (InvertFlags cmp) yes no)
@@ -16518,12 +17528,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64ULT:
@@ -16535,13 +17541,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagEQ {
 				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)
@@ -16552,12 +17554,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16568,13 +17566,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagLT_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)
@@ -16585,12 +17579,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_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)
@@ -16601,13 +17591,9 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.Op != OpARM64FlagGT_UGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (ULT (InvertFlags cmp) yes no)
@@ -16619,12 +17605,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockARM64UGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockARM64Z:
@@ -16639,12 +17621,8 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (Z (MOVDconst [c]) yes no)
@@ -16656,16 +17634,12 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockARM64ZW:
@@ -16678,15 +17652,11 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) == 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (ZW (MOVDconst [c]) yes no)
@@ -16698,16 +17668,12 @@ func rewriteBlockARM64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) != 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go
index 76eac5b..0874975 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go
@@ -1,517 +1,519 @@
-// autogenerated from gen/MIPS.rules: do not edit!
+// Code generated from gen/MIPS.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueMIPS(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueMIPS(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
-		return rewriteValueMIPS_OpAdd16(v, config)
+		return rewriteValueMIPS_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueMIPS_OpAdd32(v, config)
+		return rewriteValueMIPS_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueMIPS_OpAdd32F(v, config)
+		return rewriteValueMIPS_OpAdd32F_0(v)
 	case OpAdd32withcarry:
-		return rewriteValueMIPS_OpAdd32withcarry(v, config)
+		return rewriteValueMIPS_OpAdd32withcarry_0(v)
 	case OpAdd64F:
-		return rewriteValueMIPS_OpAdd64F(v, config)
+		return rewriteValueMIPS_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueMIPS_OpAdd8(v, config)
+		return rewriteValueMIPS_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueMIPS_OpAddPtr(v, config)
+		return rewriteValueMIPS_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueMIPS_OpAddr(v, config)
+		return rewriteValueMIPS_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueMIPS_OpAnd16(v, config)
+		return rewriteValueMIPS_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueMIPS_OpAnd32(v, config)
+		return rewriteValueMIPS_OpAnd32_0(v)
 	case OpAnd8:
-		return rewriteValueMIPS_OpAnd8(v, config)
+		return rewriteValueMIPS_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueMIPS_OpAndB(v, config)
+		return rewriteValueMIPS_OpAndB_0(v)
 	case OpAtomicAdd32:
-		return rewriteValueMIPS_OpAtomicAdd32(v, config)
+		return rewriteValueMIPS_OpAtomicAdd32_0(v)
 	case OpAtomicAnd8:
-		return rewriteValueMIPS_OpAtomicAnd8(v, config)
+		return rewriteValueMIPS_OpAtomicAnd8_0(v)
 	case OpAtomicCompareAndSwap32:
-		return rewriteValueMIPS_OpAtomicCompareAndSwap32(v, config)
+		return rewriteValueMIPS_OpAtomicCompareAndSwap32_0(v)
 	case OpAtomicExchange32:
-		return rewriteValueMIPS_OpAtomicExchange32(v, config)
+		return rewriteValueMIPS_OpAtomicExchange32_0(v)
 	case OpAtomicLoad32:
-		return rewriteValueMIPS_OpAtomicLoad32(v, config)
+		return rewriteValueMIPS_OpAtomicLoad32_0(v)
 	case OpAtomicLoadPtr:
-		return rewriteValueMIPS_OpAtomicLoadPtr(v, config)
+		return rewriteValueMIPS_OpAtomicLoadPtr_0(v)
 	case OpAtomicOr8:
-		return rewriteValueMIPS_OpAtomicOr8(v, config)
+		return rewriteValueMIPS_OpAtomicOr8_0(v)
 	case OpAtomicStore32:
-		return rewriteValueMIPS_OpAtomicStore32(v, config)
+		return rewriteValueMIPS_OpAtomicStore32_0(v)
 	case OpAtomicStorePtrNoWB:
-		return rewriteValueMIPS_OpAtomicStorePtrNoWB(v, config)
+		return rewriteValueMIPS_OpAtomicStorePtrNoWB_0(v)
+	case OpAvg32u:
+		return rewriteValueMIPS_OpAvg32u_0(v)
+	case OpBitLen32:
+		return rewriteValueMIPS_OpBitLen32_0(v)
 	case OpClosureCall:
-		return rewriteValueMIPS_OpClosureCall(v, config)
+		return rewriteValueMIPS_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueMIPS_OpCom16(v, config)
+		return rewriteValueMIPS_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueMIPS_OpCom32(v, config)
+		return rewriteValueMIPS_OpCom32_0(v)
 	case OpCom8:
-		return rewriteValueMIPS_OpCom8(v, config)
+		return rewriteValueMIPS_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueMIPS_OpConst16(v, config)
+		return rewriteValueMIPS_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueMIPS_OpConst32(v, config)
+		return rewriteValueMIPS_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueMIPS_OpConst32F(v, config)
+		return rewriteValueMIPS_OpConst32F_0(v)
 	case OpConst64F:
-		return rewriteValueMIPS_OpConst64F(v, config)
+		return rewriteValueMIPS_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueMIPS_OpConst8(v, config)
+		return rewriteValueMIPS_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueMIPS_OpConstBool(v, config)
+		return rewriteValueMIPS_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueMIPS_OpConstNil(v, config)
+		return rewriteValueMIPS_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueMIPS_OpConvert(v, config)
+		return rewriteValueMIPS_OpConvert_0(v)
 	case OpCtz32:
-		return rewriteValueMIPS_OpCtz32(v, config)
+		return rewriteValueMIPS_OpCtz32_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueMIPS_OpCvt32Fto32(v, config)
+		return rewriteValueMIPS_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueMIPS_OpCvt32Fto64F(v, config)
+		return rewriteValueMIPS_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueMIPS_OpCvt32to32F(v, config)
+		return rewriteValueMIPS_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueMIPS_OpCvt32to64F(v, config)
+		return rewriteValueMIPS_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueMIPS_OpCvt64Fto32(v, config)
+		return rewriteValueMIPS_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueMIPS_OpCvt64Fto32F(v, config)
-	case OpDeferCall:
-		return rewriteValueMIPS_OpDeferCall(v, config)
+		return rewriteValueMIPS_OpCvt64Fto32F_0(v)
 	case OpDiv16:
-		return rewriteValueMIPS_OpDiv16(v, config)
+		return rewriteValueMIPS_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueMIPS_OpDiv16u(v, config)
+		return rewriteValueMIPS_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueMIPS_OpDiv32(v, config)
+		return rewriteValueMIPS_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueMIPS_OpDiv32F(v, config)
+		return rewriteValueMIPS_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueMIPS_OpDiv32u(v, config)
+		return rewriteValueMIPS_OpDiv32u_0(v)
 	case OpDiv64F:
-		return rewriteValueMIPS_OpDiv64F(v, config)
+		return rewriteValueMIPS_OpDiv64F_0(v)
 	case OpDiv8:
-		return rewriteValueMIPS_OpDiv8(v, config)
+		return rewriteValueMIPS_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueMIPS_OpDiv8u(v, config)
+		return rewriteValueMIPS_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueMIPS_OpEq16(v, config)
+		return rewriteValueMIPS_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueMIPS_OpEq32(v, config)
+		return rewriteValueMIPS_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueMIPS_OpEq32F(v, config)
+		return rewriteValueMIPS_OpEq32F_0(v)
 	case OpEq64F:
-		return rewriteValueMIPS_OpEq64F(v, config)
+		return rewriteValueMIPS_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueMIPS_OpEq8(v, config)
+		return rewriteValueMIPS_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueMIPS_OpEqB(v, config)
+		return rewriteValueMIPS_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueMIPS_OpEqPtr(v, config)
+		return rewriteValueMIPS_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueMIPS_OpGeq16(v, config)
+		return rewriteValueMIPS_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueMIPS_OpGeq16U(v, config)
+		return rewriteValueMIPS_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueMIPS_OpGeq32(v, config)
+		return rewriteValueMIPS_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueMIPS_OpGeq32F(v, config)
+		return rewriteValueMIPS_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueMIPS_OpGeq32U(v, config)
+		return rewriteValueMIPS_OpGeq32U_0(v)
 	case OpGeq64F:
-		return rewriteValueMIPS_OpGeq64F(v, config)
+		return rewriteValueMIPS_OpGeq64F_0(v)
 	case OpGeq8:
-		return rewriteValueMIPS_OpGeq8(v, config)
+		return rewriteValueMIPS_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueMIPS_OpGeq8U(v, config)
+		return rewriteValueMIPS_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueMIPS_OpGetClosurePtr(v, config)
-	case OpGoCall:
-		return rewriteValueMIPS_OpGoCall(v, config)
+		return rewriteValueMIPS_OpGetClosurePtr_0(v)
 	case OpGreater16:
-		return rewriteValueMIPS_OpGreater16(v, config)
+		return rewriteValueMIPS_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueMIPS_OpGreater16U(v, config)
+		return rewriteValueMIPS_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueMIPS_OpGreater32(v, config)
+		return rewriteValueMIPS_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueMIPS_OpGreater32F(v, config)
+		return rewriteValueMIPS_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueMIPS_OpGreater32U(v, config)
+		return rewriteValueMIPS_OpGreater32U_0(v)
 	case OpGreater64F:
-		return rewriteValueMIPS_OpGreater64F(v, config)
+		return rewriteValueMIPS_OpGreater64F_0(v)
 	case OpGreater8:
-		return rewriteValueMIPS_OpGreater8(v, config)
+		return rewriteValueMIPS_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueMIPS_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueMIPS_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueMIPS_OpHmul16u(v, config)
+		return rewriteValueMIPS_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueMIPS_OpHmul32(v, config)
+		return rewriteValueMIPS_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueMIPS_OpHmul32u(v, config)
-	case OpHmul8:
-		return rewriteValueMIPS_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueMIPS_OpHmul8u(v, config)
+		return rewriteValueMIPS_OpHmul32u_0(v)
 	case OpInterCall:
-		return rewriteValueMIPS_OpInterCall(v, config)
+		return rewriteValueMIPS_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueMIPS_OpIsInBounds(v, config)
+		return rewriteValueMIPS_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueMIPS_OpIsNonNil(v, config)
+		return rewriteValueMIPS_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueMIPS_OpIsSliceInBounds(v, config)
+		return rewriteValueMIPS_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueMIPS_OpLeq16(v, config)
+		return rewriteValueMIPS_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueMIPS_OpLeq16U(v, config)
+		return rewriteValueMIPS_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueMIPS_OpLeq32(v, config)
+		return rewriteValueMIPS_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueMIPS_OpLeq32F(v, config)
+		return rewriteValueMIPS_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueMIPS_OpLeq32U(v, config)
+		return rewriteValueMIPS_OpLeq32U_0(v)
 	case OpLeq64F:
-		return rewriteValueMIPS_OpLeq64F(v, config)
+		return rewriteValueMIPS_OpLeq64F_0(v)
 	case OpLeq8:
-		return rewriteValueMIPS_OpLeq8(v, config)
+		return rewriteValueMIPS_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueMIPS_OpLeq8U(v, config)
+		return rewriteValueMIPS_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueMIPS_OpLess16(v, config)
+		return rewriteValueMIPS_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueMIPS_OpLess16U(v, config)
+		return rewriteValueMIPS_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueMIPS_OpLess32(v, config)
+		return rewriteValueMIPS_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueMIPS_OpLess32F(v, config)
+		return rewriteValueMIPS_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueMIPS_OpLess32U(v, config)
+		return rewriteValueMIPS_OpLess32U_0(v)
 	case OpLess64F:
-		return rewriteValueMIPS_OpLess64F(v, config)
+		return rewriteValueMIPS_OpLess64F_0(v)
 	case OpLess8:
-		return rewriteValueMIPS_OpLess8(v, config)
+		return rewriteValueMIPS_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueMIPS_OpLess8U(v, config)
+		return rewriteValueMIPS_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValueMIPS_OpLoad(v, config)
+		return rewriteValueMIPS_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueMIPS_OpLsh16x16(v, config)
+		return rewriteValueMIPS_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueMIPS_OpLsh16x32(v, config)
+		return rewriteValueMIPS_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueMIPS_OpLsh16x64(v, config)
+		return rewriteValueMIPS_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueMIPS_OpLsh16x8(v, config)
+		return rewriteValueMIPS_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueMIPS_OpLsh32x16(v, config)
+		return rewriteValueMIPS_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueMIPS_OpLsh32x32(v, config)
+		return rewriteValueMIPS_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueMIPS_OpLsh32x64(v, config)
+		return rewriteValueMIPS_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueMIPS_OpLsh32x8(v, config)
+		return rewriteValueMIPS_OpLsh32x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueMIPS_OpLsh8x16(v, config)
+		return rewriteValueMIPS_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueMIPS_OpLsh8x32(v, config)
+		return rewriteValueMIPS_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueMIPS_OpLsh8x64(v, config)
+		return rewriteValueMIPS_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueMIPS_OpLsh8x8(v, config)
+		return rewriteValueMIPS_OpLsh8x8_0(v)
 	case OpMIPSADD:
-		return rewriteValueMIPS_OpMIPSADD(v, config)
+		return rewriteValueMIPS_OpMIPSADD_0(v)
 	case OpMIPSADDconst:
-		return rewriteValueMIPS_OpMIPSADDconst(v, config)
+		return rewriteValueMIPS_OpMIPSADDconst_0(v)
 	case OpMIPSAND:
-		return rewriteValueMIPS_OpMIPSAND(v, config)
+		return rewriteValueMIPS_OpMIPSAND_0(v)
 	case OpMIPSANDconst:
-		return rewriteValueMIPS_OpMIPSANDconst(v, config)
+		return rewriteValueMIPS_OpMIPSANDconst_0(v)
 	case OpMIPSCMOVZ:
-		return rewriteValueMIPS_OpMIPSCMOVZ(v, config)
+		return rewriteValueMIPS_OpMIPSCMOVZ_0(v)
 	case OpMIPSCMOVZzero:
-		return rewriteValueMIPS_OpMIPSCMOVZzero(v, config)
+		return rewriteValueMIPS_OpMIPSCMOVZzero_0(v)
 	case OpMIPSLoweredAtomicAdd:
-		return rewriteValueMIPS_OpMIPSLoweredAtomicAdd(v, config)
+		return rewriteValueMIPS_OpMIPSLoweredAtomicAdd_0(v)
 	case OpMIPSLoweredAtomicStore:
-		return rewriteValueMIPS_OpMIPSLoweredAtomicStore(v, config)
+		return rewriteValueMIPS_OpMIPSLoweredAtomicStore_0(v)
 	case OpMIPSMOVBUload:
-		return rewriteValueMIPS_OpMIPSMOVBUload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBUload_0(v)
 	case OpMIPSMOVBUreg:
-		return rewriteValueMIPS_OpMIPSMOVBUreg(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBUreg_0(v)
 	case OpMIPSMOVBload:
-		return rewriteValueMIPS_OpMIPSMOVBload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBload_0(v)
 	case OpMIPSMOVBreg:
-		return rewriteValueMIPS_OpMIPSMOVBreg(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBreg_0(v)
 	case OpMIPSMOVBstore:
-		return rewriteValueMIPS_OpMIPSMOVBstore(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBstore_0(v)
 	case OpMIPSMOVBstorezero:
-		return rewriteValueMIPS_OpMIPSMOVBstorezero(v, config)
+		return rewriteValueMIPS_OpMIPSMOVBstorezero_0(v)
 	case OpMIPSMOVDload:
-		return rewriteValueMIPS_OpMIPSMOVDload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVDload_0(v)
 	case OpMIPSMOVDstore:
-		return rewriteValueMIPS_OpMIPSMOVDstore(v, config)
+		return rewriteValueMIPS_OpMIPSMOVDstore_0(v)
 	case OpMIPSMOVFload:
-		return rewriteValueMIPS_OpMIPSMOVFload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVFload_0(v)
 	case OpMIPSMOVFstore:
-		return rewriteValueMIPS_OpMIPSMOVFstore(v, config)
+		return rewriteValueMIPS_OpMIPSMOVFstore_0(v)
 	case OpMIPSMOVHUload:
-		return rewriteValueMIPS_OpMIPSMOVHUload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHUload_0(v)
 	case OpMIPSMOVHUreg:
-		return rewriteValueMIPS_OpMIPSMOVHUreg(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHUreg_0(v)
 	case OpMIPSMOVHload:
-		return rewriteValueMIPS_OpMIPSMOVHload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHload_0(v)
 	case OpMIPSMOVHreg:
-		return rewriteValueMIPS_OpMIPSMOVHreg(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHreg_0(v)
 	case OpMIPSMOVHstore:
-		return rewriteValueMIPS_OpMIPSMOVHstore(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHstore_0(v)
 	case OpMIPSMOVHstorezero:
-		return rewriteValueMIPS_OpMIPSMOVHstorezero(v, config)
+		return rewriteValueMIPS_OpMIPSMOVHstorezero_0(v)
 	case OpMIPSMOVWload:
-		return rewriteValueMIPS_OpMIPSMOVWload(v, config)
+		return rewriteValueMIPS_OpMIPSMOVWload_0(v)
 	case OpMIPSMOVWreg:
-		return rewriteValueMIPS_OpMIPSMOVWreg(v, config)
+		return rewriteValueMIPS_OpMIPSMOVWreg_0(v)
 	case OpMIPSMOVWstore:
-		return rewriteValueMIPS_OpMIPSMOVWstore(v, config)
+		return rewriteValueMIPS_OpMIPSMOVWstore_0(v)
 	case OpMIPSMOVWstorezero:
-		return rewriteValueMIPS_OpMIPSMOVWstorezero(v, config)
+		return rewriteValueMIPS_OpMIPSMOVWstorezero_0(v)
 	case OpMIPSMUL:
-		return rewriteValueMIPS_OpMIPSMUL(v, config)
+		return rewriteValueMIPS_OpMIPSMUL_0(v)
 	case OpMIPSNEG:
-		return rewriteValueMIPS_OpMIPSNEG(v, config)
+		return rewriteValueMIPS_OpMIPSNEG_0(v)
 	case OpMIPSNOR:
-		return rewriteValueMIPS_OpMIPSNOR(v, config)
+		return rewriteValueMIPS_OpMIPSNOR_0(v)
 	case OpMIPSNORconst:
-		return rewriteValueMIPS_OpMIPSNORconst(v, config)
+		return rewriteValueMIPS_OpMIPSNORconst_0(v)
 	case OpMIPSOR:
-		return rewriteValueMIPS_OpMIPSOR(v, config)
+		return rewriteValueMIPS_OpMIPSOR_0(v)
 	case OpMIPSORconst:
-		return rewriteValueMIPS_OpMIPSORconst(v, config)
+		return rewriteValueMIPS_OpMIPSORconst_0(v)
 	case OpMIPSSGT:
-		return rewriteValueMIPS_OpMIPSSGT(v, config)
+		return rewriteValueMIPS_OpMIPSSGT_0(v)
 	case OpMIPSSGTU:
-		return rewriteValueMIPS_OpMIPSSGTU(v, config)
+		return rewriteValueMIPS_OpMIPSSGTU_0(v)
 	case OpMIPSSGTUconst:
-		return rewriteValueMIPS_OpMIPSSGTUconst(v, config)
+		return rewriteValueMIPS_OpMIPSSGTUconst_0(v)
 	case OpMIPSSGTUzero:
-		return rewriteValueMIPS_OpMIPSSGTUzero(v, config)
+		return rewriteValueMIPS_OpMIPSSGTUzero_0(v)
 	case OpMIPSSGTconst:
-		return rewriteValueMIPS_OpMIPSSGTconst(v, config)
+		return rewriteValueMIPS_OpMIPSSGTconst_0(v) || rewriteValueMIPS_OpMIPSSGTconst_10(v)
 	case OpMIPSSGTzero:
-		return rewriteValueMIPS_OpMIPSSGTzero(v, config)
+		return rewriteValueMIPS_OpMIPSSGTzero_0(v)
 	case OpMIPSSLL:
-		return rewriteValueMIPS_OpMIPSSLL(v, config)
+		return rewriteValueMIPS_OpMIPSSLL_0(v)
 	case OpMIPSSLLconst:
-		return rewriteValueMIPS_OpMIPSSLLconst(v, config)
+		return rewriteValueMIPS_OpMIPSSLLconst_0(v)
 	case OpMIPSSRA:
-		return rewriteValueMIPS_OpMIPSSRA(v, config)
+		return rewriteValueMIPS_OpMIPSSRA_0(v)
 	case OpMIPSSRAconst:
-		return rewriteValueMIPS_OpMIPSSRAconst(v, config)
+		return rewriteValueMIPS_OpMIPSSRAconst_0(v)
 	case OpMIPSSRL:
-		return rewriteValueMIPS_OpMIPSSRL(v, config)
+		return rewriteValueMIPS_OpMIPSSRL_0(v)
 	case OpMIPSSRLconst:
-		return rewriteValueMIPS_OpMIPSSRLconst(v, config)
+		return rewriteValueMIPS_OpMIPSSRLconst_0(v)
 	case OpMIPSSUB:
-		return rewriteValueMIPS_OpMIPSSUB(v, config)
+		return rewriteValueMIPS_OpMIPSSUB_0(v)
 	case OpMIPSSUBconst:
-		return rewriteValueMIPS_OpMIPSSUBconst(v, config)
+		return rewriteValueMIPS_OpMIPSSUBconst_0(v)
 	case OpMIPSXOR:
-		return rewriteValueMIPS_OpMIPSXOR(v, config)
+		return rewriteValueMIPS_OpMIPSXOR_0(v)
 	case OpMIPSXORconst:
-		return rewriteValueMIPS_OpMIPSXORconst(v, config)
+		return rewriteValueMIPS_OpMIPSXORconst_0(v)
 	case OpMod16:
-		return rewriteValueMIPS_OpMod16(v, config)
+		return rewriteValueMIPS_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueMIPS_OpMod16u(v, config)
+		return rewriteValueMIPS_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueMIPS_OpMod32(v, config)
+		return rewriteValueMIPS_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueMIPS_OpMod32u(v, config)
+		return rewriteValueMIPS_OpMod32u_0(v)
 	case OpMod8:
-		return rewriteValueMIPS_OpMod8(v, config)
+		return rewriteValueMIPS_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueMIPS_OpMod8u(v, config)
+		return rewriteValueMIPS_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueMIPS_OpMove(v, config)
+		return rewriteValueMIPS_OpMove_0(v) || rewriteValueMIPS_OpMove_10(v)
 	case OpMul16:
-		return rewriteValueMIPS_OpMul16(v, config)
+		return rewriteValueMIPS_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueMIPS_OpMul32(v, config)
+		return rewriteValueMIPS_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueMIPS_OpMul32F(v, config)
+		return rewriteValueMIPS_OpMul32F_0(v)
 	case OpMul32uhilo:
-		return rewriteValueMIPS_OpMul32uhilo(v, config)
+		return rewriteValueMIPS_OpMul32uhilo_0(v)
 	case OpMul64F:
-		return rewriteValueMIPS_OpMul64F(v, config)
+		return rewriteValueMIPS_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValueMIPS_OpMul8(v, config)
+		return rewriteValueMIPS_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueMIPS_OpNeg16(v, config)
+		return rewriteValueMIPS_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueMIPS_OpNeg32(v, config)
+		return rewriteValueMIPS_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueMIPS_OpNeg32F(v, config)
+		return rewriteValueMIPS_OpNeg32F_0(v)
 	case OpNeg64F:
-		return rewriteValueMIPS_OpNeg64F(v, config)
+		return rewriteValueMIPS_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueMIPS_OpNeg8(v, config)
+		return rewriteValueMIPS_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueMIPS_OpNeq16(v, config)
+		return rewriteValueMIPS_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueMIPS_OpNeq32(v, config)
+		return rewriteValueMIPS_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueMIPS_OpNeq32F(v, config)
+		return rewriteValueMIPS_OpNeq32F_0(v)
 	case OpNeq64F:
-		return rewriteValueMIPS_OpNeq64F(v, config)
+		return rewriteValueMIPS_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueMIPS_OpNeq8(v, config)
+		return rewriteValueMIPS_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueMIPS_OpNeqB(v, config)
+		return rewriteValueMIPS_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueMIPS_OpNeqPtr(v, config)
+		return rewriteValueMIPS_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueMIPS_OpNilCheck(v, config)
+		return rewriteValueMIPS_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueMIPS_OpNot(v, config)
+		return rewriteValueMIPS_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueMIPS_OpOffPtr(v, config)
+		return rewriteValueMIPS_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueMIPS_OpOr16(v, config)
+		return rewriteValueMIPS_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueMIPS_OpOr32(v, config)
+		return rewriteValueMIPS_OpOr32_0(v)
 	case OpOr8:
-		return rewriteValueMIPS_OpOr8(v, config)
+		return rewriteValueMIPS_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueMIPS_OpOrB(v, config)
+		return rewriteValueMIPS_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValueMIPS_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueMIPS_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueMIPS_OpRsh16Ux16(v, config)
+		return rewriteValueMIPS_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueMIPS_OpRsh16Ux32(v, config)
+		return rewriteValueMIPS_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueMIPS_OpRsh16Ux64(v, config)
+		return rewriteValueMIPS_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueMIPS_OpRsh16Ux8(v, config)
+		return rewriteValueMIPS_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueMIPS_OpRsh16x16(v, config)
+		return rewriteValueMIPS_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueMIPS_OpRsh16x32(v, config)
+		return rewriteValueMIPS_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueMIPS_OpRsh16x64(v, config)
+		return rewriteValueMIPS_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueMIPS_OpRsh16x8(v, config)
+		return rewriteValueMIPS_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueMIPS_OpRsh32Ux16(v, config)
+		return rewriteValueMIPS_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueMIPS_OpRsh32Ux32(v, config)
+		return rewriteValueMIPS_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueMIPS_OpRsh32Ux64(v, config)
+		return rewriteValueMIPS_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueMIPS_OpRsh32Ux8(v, config)
+		return rewriteValueMIPS_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueMIPS_OpRsh32x16(v, config)
+		return rewriteValueMIPS_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueMIPS_OpRsh32x32(v, config)
+		return rewriteValueMIPS_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueMIPS_OpRsh32x64(v, config)
+		return rewriteValueMIPS_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueMIPS_OpRsh32x8(v, config)
+		return rewriteValueMIPS_OpRsh32x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueMIPS_OpRsh8Ux16(v, config)
+		return rewriteValueMIPS_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueMIPS_OpRsh8Ux32(v, config)
+		return rewriteValueMIPS_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueMIPS_OpRsh8Ux64(v, config)
+		return rewriteValueMIPS_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueMIPS_OpRsh8Ux8(v, config)
+		return rewriteValueMIPS_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueMIPS_OpRsh8x16(v, config)
+		return rewriteValueMIPS_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueMIPS_OpRsh8x32(v, config)
+		return rewriteValueMIPS_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueMIPS_OpRsh8x64(v, config)
+		return rewriteValueMIPS_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueMIPS_OpRsh8x8(v, config)
+		return rewriteValueMIPS_OpRsh8x8_0(v)
 	case OpSelect0:
-		return rewriteValueMIPS_OpSelect0(v, config)
+		return rewriteValueMIPS_OpSelect0_0(v) || rewriteValueMIPS_OpSelect0_10(v)
 	case OpSelect1:
-		return rewriteValueMIPS_OpSelect1(v, config)
+		return rewriteValueMIPS_OpSelect1_0(v) || rewriteValueMIPS_OpSelect1_10(v)
 	case OpSignExt16to32:
-		return rewriteValueMIPS_OpSignExt16to32(v, config)
+		return rewriteValueMIPS_OpSignExt16to32_0(v)
 	case OpSignExt8to16:
-		return rewriteValueMIPS_OpSignExt8to16(v, config)
+		return rewriteValueMIPS_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueMIPS_OpSignExt8to32(v, config)
+		return rewriteValueMIPS_OpSignExt8to32_0(v)
 	case OpSignmask:
-		return rewriteValueMIPS_OpSignmask(v, config)
+		return rewriteValueMIPS_OpSignmask_0(v)
 	case OpSlicemask:
-		return rewriteValueMIPS_OpSlicemask(v, config)
+		return rewriteValueMIPS_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValueMIPS_OpSqrt(v, config)
+		return rewriteValueMIPS_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValueMIPS_OpStaticCall(v, config)
+		return rewriteValueMIPS_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueMIPS_OpStore(v, config)
+		return rewriteValueMIPS_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueMIPS_OpSub16(v, config)
+		return rewriteValueMIPS_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueMIPS_OpSub32(v, config)
+		return rewriteValueMIPS_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueMIPS_OpSub32F(v, config)
+		return rewriteValueMIPS_OpSub32F_0(v)
 	case OpSub32withcarry:
-		return rewriteValueMIPS_OpSub32withcarry(v, config)
+		return rewriteValueMIPS_OpSub32withcarry_0(v)
 	case OpSub64F:
-		return rewriteValueMIPS_OpSub64F(v, config)
+		return rewriteValueMIPS_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueMIPS_OpSub8(v, config)
+		return rewriteValueMIPS_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueMIPS_OpSubPtr(v, config)
+		return rewriteValueMIPS_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueMIPS_OpTrunc16to8(v, config)
+		return rewriteValueMIPS_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueMIPS_OpTrunc32to16(v, config)
+		return rewriteValueMIPS_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueMIPS_OpTrunc32to8(v, config)
+		return rewriteValueMIPS_OpTrunc32to8_0(v)
 	case OpXor16:
-		return rewriteValueMIPS_OpXor16(v, config)
+		return rewriteValueMIPS_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueMIPS_OpXor32(v, config)
+		return rewriteValueMIPS_OpXor32_0(v)
 	case OpXor8:
-		return rewriteValueMIPS_OpXor8(v, config)
+		return rewriteValueMIPS_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueMIPS_OpZero(v, config)
+		return rewriteValueMIPS_OpZero_0(v) || rewriteValueMIPS_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValueMIPS_OpZeroExt16to32(v, config)
+		return rewriteValueMIPS_OpZeroExt16to32_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueMIPS_OpZeroExt8to16(v, config)
+		return rewriteValueMIPS_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueMIPS_OpZeroExt8to32(v, config)
+		return rewriteValueMIPS_OpZeroExt8to32_0(v)
 	case OpZeromask:
-		return rewriteValueMIPS_OpZeromask(v, config)
+		return rewriteValueMIPS_OpZeromask_0(v)
 	}
 	return false
 }
-func rewriteValueMIPS_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAdd16_0(v *Value) bool {
 	// match: (Add16 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADD)
@@ -520,13 +522,12 @@ func rewriteValueMIPS_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAdd32_0(v *Value) bool {
 	// match: (Add32 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADD)
@@ -535,13 +536,12 @@ func rewriteValueMIPS_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (ADDF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADDF)
@@ -550,7 +550,7 @@ func rewriteValueMIPS_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAdd32withcarry(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpAdd32withcarry_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Add32withcarry <t> x y c)
@@ -558,25 +558,25 @@ func rewriteValueMIPS_OpAdd32withcarry(v *Value, config *Config) bool {
 	// result: (ADD c (ADD <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
 		v.reset(OpMIPSADD)
 		v.AddArg(c)
-		v0 := b.NewValue0(v.Line, OpMIPSADD, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSADD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (ADDD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADDD)
@@ -585,13 +585,12 @@ func rewriteValueMIPS_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAdd8_0(v *Value) bool {
 	// match: (Add8 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADD)
@@ -600,13 +599,12 @@ func rewriteValueMIPS_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSADD)
@@ -615,9 +613,7 @@ func rewriteValueMIPS_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVWaddr {sym} base)
@@ -630,13 +626,12 @@ func rewriteValueMIPS_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSAND)
@@ -645,13 +640,12 @@ func rewriteValueMIPS_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSAND)
@@ -660,13 +654,12 @@ func rewriteValueMIPS_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAnd8_0(v *Value) bool {
 	// match: (And8 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSAND)
@@ -675,13 +668,12 @@ func rewriteValueMIPS_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSAND)
@@ -690,13 +682,12 @@ func rewriteValueMIPS_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAtomicAdd32_0(v *Value) bool {
 	// match: (AtomicAdd32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicAdd ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -707,13 +698,18 @@ func rewriteValueMIPS_OpAtomicAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpAtomicAnd8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (AtomicAnd8  ptr val mem)
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (AtomicAnd8 ptr val mem)
 	// cond: !config.BigEndian
-	// result: (LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) 		(OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) 			(SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst  <config.fe.TypeUInt32()> [3] ptr))) 		(NORconst [0] <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> 			(MOVWconst [0xff]) (SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst <config.fe.TypeUInt32()> [3] ptr))))) mem)
+	// result: (LoweredAtomicAnd (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr) 		(OR <typ.UInt32> (SLL <typ.UInt32> (ZeroExt8to32 val) 			(SLLconst <typ.UInt32> [3] 				(ANDconst  <typ.UInt32> [3] ptr))) 		(NORconst [0] <typ.UInt32> (SLL <typ.UInt32> 			(MOVWconst [0xff]) (SLLconst <typ.UInt32> [3] 				(ANDconst <typ.UInt32> [3] ptr))))) mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -721,34 +717,34 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpMIPSLoweredAtomicAnd)
-		v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSAND, typ.UInt32Ptr)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = ^3
 		v0.AddArg(v1)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSOR, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSOR, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(val)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v5.AuxInt = 3
-		v6 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v6.AuxInt = 3
 		v6.AddArg(ptr)
 		v5.AddArg(v6)
 		v3.AddArg(v5)
 		v2.AddArg(v3)
-		v7 := b.NewValue0(v.Line, OpMIPSNORconst, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpMIPSNORconst, typ.UInt32)
 		v7.AuxInt = 0
-		v8 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v9 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v8 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v9 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v9.AuxInt = 0xff
 		v8.AddArg(v9)
-		v10 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v10 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v10.AuxInt = 3
-		v11 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v11 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v11.AuxInt = 3
 		v11.AddArg(ptr)
 		v10.AddArg(v11)
@@ -759,10 +755,11 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (AtomicAnd8  ptr val mem)
+	// match: (AtomicAnd8 ptr val mem)
 	// cond: config.BigEndian
-	// result: (LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) 		(OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) 			(SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst  <config.fe.TypeUInt32()> [3] 					(XORconst <config.fe.TypeUInt32()> [3] ptr)))) 		(NORconst [0] <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> 			(MOVWconst [0xff]) (SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst <config.fe.TypeUInt32()> [3] 					(XOR [...]
+	// result: (LoweredAtomicAnd (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr) 		(OR <typ.UInt32> (SLL <typ.UInt32> (ZeroExt8to32 val) 			(SLLconst <typ.UInt32> [3] 				(ANDconst  <typ.UInt32> [3] 					(XORconst <typ.UInt32> [3] ptr)))) 		(NORconst [0] <typ.UInt32> (SLL <typ.UInt32> 			(MOVWconst [0xff]) (SLLconst <typ.UInt32> [3] 				(ANDconst <typ.UInt32> [3] 					(XORconst <typ.UInt32> [3] ptr)))))) mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -770,39 +767,39 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpMIPSLoweredAtomicAnd)
-		v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSAND, typ.UInt32Ptr)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = ^3
 		v0.AddArg(v1)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSOR, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSOR, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(val)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v5.AuxInt = 3
-		v6 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v6.AuxInt = 3
-		v7 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpMIPSXORconst, typ.UInt32)
 		v7.AuxInt = 3
 		v7.AddArg(ptr)
 		v6.AddArg(v7)
 		v5.AddArg(v6)
 		v3.AddArg(v5)
 		v2.AddArg(v3)
-		v8 := b.NewValue0(v.Line, OpMIPSNORconst, config.fe.TypeUInt32())
+		v8 := b.NewValue0(v.Pos, OpMIPSNORconst, typ.UInt32)
 		v8.AuxInt = 0
-		v9 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v10 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v10 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v10.AuxInt = 0xff
 		v9.AddArg(v10)
-		v11 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v11 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v11.AuxInt = 3
-		v12 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v12 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v12.AuxInt = 3
-		v13 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+		v13 := b.NewValue0(v.Pos, OpMIPSXORconst, typ.UInt32)
 		v13.AuxInt = 3
 		v13.AddArg(ptr)
 		v12.AddArg(v13)
@@ -816,13 +813,12 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAtomicCompareAndSwap32_0(v *Value) bool {
 	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
 	// cond:
 	// result: (LoweredAtomicCas ptr old new_ mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		old := v.Args[1]
 		new_ := v.Args[2]
@@ -835,13 +831,12 @@ func rewriteValueMIPS_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicExchange32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAtomicExchange32_0(v *Value) bool {
 	// match: (AtomicExchange32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicExchange ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -852,13 +847,12 @@ func rewriteValueMIPS_OpAtomicExchange32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicLoad32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicLoad32  ptr mem)
+func rewriteValueMIPS_OpAtomicLoad32_0(v *Value) bool {
+	// match: (AtomicLoad32 ptr mem)
 	// cond:
 	// result: (LoweredAtomicLoad ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPSLoweredAtomicLoad)
@@ -867,13 +861,12 @@ func rewriteValueMIPS_OpAtomicLoad32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicLoadPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAtomicLoadPtr_0(v *Value) bool {
 	// match: (AtomicLoadPtr ptr mem)
 	// cond:
 	// result: (LoweredAtomicLoad  ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPSLoweredAtomicLoad)
@@ -882,13 +875,18 @@ func rewriteValueMIPS_OpAtomicLoadPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpAtomicOr8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (AtomicOr8 ptr val mem)
 	// cond: !config.BigEndian
-	// result: (LoweredAtomicOr (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) 		(SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) 			(SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst <config.fe.TypeUInt32()> [3] ptr))) mem)
+	// result: (LoweredAtomicOr (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr) 		(SLL <typ.UInt32> (ZeroExt8to32 val) 			(SLLconst <typ.UInt32> [3] 				(ANDconst <typ.UInt32> [3] ptr))) mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -896,19 +894,19 @@ func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpMIPSLoweredAtomicOr)
-		v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSAND, typ.UInt32Ptr)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = ^3
 		v0.AddArg(v1)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v3.AddArg(val)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v4.AuxInt = 3
-		v5 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v5.AuxInt = 3
 		v5.AddArg(ptr)
 		v4.AddArg(v5)
@@ -919,8 +917,9 @@ func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
 	}
 	// match: (AtomicOr8 ptr val mem)
 	// cond: config.BigEndian
-	// result: (LoweredAtomicOr (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) 		(SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) 			(SLLconst <config.fe.TypeUInt32()> [3] 				(ANDconst <config.fe.TypeUInt32()> [3] 					(XORconst <config.fe.TypeUInt32()> [3] ptr)))) mem)
+	// result: (LoweredAtomicOr (AND <typ.UInt32Ptr> (MOVWconst [^3]) ptr) 		(SLL <typ.UInt32> (ZeroExt8to32 val) 			(SLLconst <typ.UInt32> [3] 				(ANDconst <typ.UInt32> [3] 					(XORconst <typ.UInt32> [3] ptr)))) mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -928,21 +927,21 @@ func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpMIPSLoweredAtomicOr)
-		v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSAND, typ.UInt32Ptr)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = ^3
 		v0.AddArg(v1)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSSLL, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v3.AddArg(val)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v4.AuxInt = 3
-		v5 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpMIPSANDconst, typ.UInt32)
 		v5.AuxInt = 3
-		v6 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSXORconst, typ.UInt32)
 		v6.AuxInt = 3
 		v6.AddArg(ptr)
 		v5.AddArg(v6)
@@ -954,13 +953,12 @@ func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpAtomicStore32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AtomicStore32      ptr val mem)
+func rewriteValueMIPS_OpAtomicStore32_0(v *Value) bool {
+	// match: (AtomicStore32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicStore ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -971,13 +969,12 @@ func rewriteValueMIPS_OpAtomicStore32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpAtomicStorePtrNoWB_0(v *Value) bool {
 	// match: (AtomicStorePtrNoWB ptr val mem)
 	// cond:
 	// result: (LoweredAtomicStore  ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -988,14 +985,57 @@ func rewriteValueMIPS_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpClosureCall(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpAvg32u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Avg32u <t> x y)
+	// cond:
+	// result: (ADD (SRLconst <t> (SUB <t> x y) [1]) y)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpMIPSADD)
+		v0 := b.NewValue0(v.Pos, OpMIPSSRLconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpMIPSSUB, t)
+		v1.AddArg(x)
+		v1.AddArg(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueMIPS_OpBitLen32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen32 <t> x)
+	// cond:
+	// result: (SUB (MOVWconst [32]) (CLZ <t> x))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpMIPSSUB)
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
+		v0.AuxInt = 32
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMIPSCLZ, t)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueMIPS_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -1007,9 +1047,7 @@ func rewriteValueMIPS_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
 	// result: (NORconst [0] x)
@@ -1021,9 +1059,7 @@ func rewriteValueMIPS_OpCom16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
 	// result: (NORconst [0] x)
@@ -1035,9 +1071,7 @@ func rewriteValueMIPS_OpCom32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCom8_0(v *Value) bool {
 	// match: (Com8 x)
 	// cond:
 	// result: (NORconst [0] x)
@@ -1049,9 +1083,7 @@ func rewriteValueMIPS_OpCom8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConst16_0(v *Value) bool {
 	// match: (Const16 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -1062,9 +1094,7 @@ func rewriteValueMIPS_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConst32_0(v *Value) bool {
 	// match: (Const32 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -1075,9 +1105,7 @@ func rewriteValueMIPS_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (MOVFconst [val])
@@ -1088,9 +1116,7 @@ func rewriteValueMIPS_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -1101,9 +1127,7 @@ func rewriteValueMIPS_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConst8_0(v *Value) bool {
 	// match: (Const8 [val])
 	// cond:
 	// result: (MOVWconst [val])
@@ -1114,9 +1138,7 @@ func rewriteValueMIPS_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVWconst [b])
@@ -1127,9 +1149,7 @@ func rewriteValueMIPS_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVWconst [0])
@@ -1139,13 +1159,12 @@ func rewriteValueMIPS_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpConvert_0(v *Value) bool {
 	// match: (Convert x mem)
 	// cond:
 	// result: (MOVWconvert x mem)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPSMOVWconvert)
@@ -1154,9 +1173,11 @@ func rewriteValueMIPS_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCtz32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpCtz32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Ctz32 <t> x)
 	// cond:
 	// result: (SUB (MOVWconst [32]) (CLZ <t> (SUBconst <t> [1] (AND <t> x (NEG <t> x)))))
@@ -1164,15 +1185,15 @@ func rewriteValueMIPS_OpCtz32(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpMIPSSUB)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 32
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCLZ, t)
-		v2 := b.NewValue0(v.Line, OpMIPSSUBconst, t)
+		v1 := b.NewValue0(v.Pos, OpMIPSCLZ, t)
+		v2 := b.NewValue0(v.Pos, OpMIPSSUBconst, t)
 		v2.AuxInt = 1
-		v3 := b.NewValue0(v.Line, OpMIPSAND, t)
+		v3 := b.NewValue0(v.Pos, OpMIPSAND, t)
 		v3.AddArg(x)
-		v4 := b.NewValue0(v.Line, OpMIPSNEG, t)
+		v4 := b.NewValue0(v.Pos, OpMIPSNEG, t)
 		v4.AddArg(x)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -1181,9 +1202,7 @@ func rewriteValueMIPS_OpCtz32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (TRUNCFW x)
@@ -1194,9 +1213,7 @@ func rewriteValueMIPS_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (MOVFD x)
@@ -1207,9 +1224,7 @@ func rewriteValueMIPS_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (MOVWF x)
@@ -1220,9 +1235,7 @@ func rewriteValueMIPS_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (MOVWD x)
@@ -1233,9 +1246,7 @@ func rewriteValueMIPS_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (TRUNCDW x)
@@ -1246,9 +1257,7 @@ func rewriteValueMIPS_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (MOVDF x)
@@ -1259,87 +1268,80 @@ func rewriteValueMIPS_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_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(OpMIPSCALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueMIPS_OpDiv16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16 x y)
 	// cond:
 	// result: (Select1 (DIV (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (Select1 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32 x y)
 	// cond:
 	// result: (Select1 (DIV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (DIVF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSDIVF)
@@ -1348,30 +1350,32 @@ func rewriteValueMIPS_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv32u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32u x y)
 	// cond:
 	// result: (Select1 (DIVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (DIVD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSDIVD)
@@ -1380,341 +1384,382 @@ func rewriteValueMIPS_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8 x y)
 	// cond:
 	// result: (Select1 (DIV (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8u x y)
 	// cond:
 	// result: (Select1 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEq16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq16 x y)
 	// cond:
 	// result: (SGTUconst [1] (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTUconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEq32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq32 x y)
 	// cond:
 	// result: (SGTUconst [1] (XOR x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTUconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPEQF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPEQF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPEQF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPEQD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPEQD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPEQD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEq8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq8 x y)
 	// cond:
 	// result: (SGTUconst [1] (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTUconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEqB(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqB x y)
 	// cond:
-	// result: (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+	// result: (XORconst [1] (XOR <typ.Bool> x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.Bool)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqPtr x y)
 	// cond:
 	// result: (SGTUconst [1] (XOR x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTUconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16 x y)
 	// cond:
 	// result: (XORconst [1] (SGT (SignExt16to32 y) (SignExt16to32 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(x)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(x)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32 x y)
 	// cond:
 	// result: (XORconst [1] (SGT y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGEF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGEF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGEF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGED x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGED, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGED, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8 x y)
 	// cond:
 	// result: (XORconst [1] (SGT (SignExt8to32 y) (SignExt8to32 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(x)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(x)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -1723,66 +1768,56 @@ func rewriteValueMIPS_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_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(OpMIPSCALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueMIPS_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16 x y)
 	// cond:
 	// result: (SGT (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpGreater32_0(v *Value) bool {
 	// match: (Greater32 x y)
 	// cond:
 	// result: (SGT x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
@@ -1791,30 +1826,30 @@ func rewriteValueMIPS_OpGreater32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGTF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGTF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpGreater32U_0(v *Value) bool {
 	// match: (Greater32U x y)
 	// cond:
 	// result: (SGTU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
@@ -1823,191 +1858,115 @@ func rewriteValueMIPS_OpGreater32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGTD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGTD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8 x y)
 	// cond:
 	// result: (SGT (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8U x y)
 	// cond:
 	// result: (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16 x y)
-	// cond:
-	// result: (SRAconst (MUL <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPSSRAconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpMIPSMUL, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPSSRLconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpMIPSMUL, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS_OpHmul32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpHmul32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32 x y)
 	// cond:
 	// result: (Select0 (MULT x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSMULT, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSMULT, types.NewTuple(typ.Int32, typ.Int32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpHmul32u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpHmul32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32u x y)
 	// cond:
 	// result: (Select0 (MULTU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSMULTU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSMULTU, types.NewTuple(typ.UInt32, typ.UInt32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8 x y)
-	// cond:
-	// result: (SRAconst  (MUL <config.fe.TypeInt32()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPSSRAconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpMIPSMUL, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u x y)
-	// cond:
-	// result: (SRLconst (MUL <config.fe.TypeUInt32()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPSSRLconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpMIPSMUL, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPSCALLinter)
@@ -2017,13 +1976,12 @@ func rewriteValueMIPS_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpIsInBounds(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpIsInBounds_0(v *Value) bool {
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (SGTU len idx)
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpMIPSSGTU)
@@ -2032,9 +1990,11 @@ func rewriteValueMIPS_OpIsInBounds(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsNonNil ptr)
 	// cond:
 	// result: (SGTU ptr (MOVWconst [0]))
@@ -2042,233 +2002,261 @@ func rewriteValueMIPS_OpIsNonNil(v *Value, config *Config) bool {
 		ptr := v.Args[0]
 		v.reset(OpMIPSSGTU)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (XORconst [1] (SGTU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16 x y)
 	// cond:
 	// result: (XORconst [1] (SGT (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32 x y)
 	// cond:
 	// result: (XORconst [1] (SGT x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGEF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGEF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGEF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGED y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGED, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGED, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8 x y)
 	// cond:
 	// result: (XORconst [1] (SGT (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGT, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8U x y)
 	// cond:
 	// result: (XORconst [1] (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16 x y)
 	// cond:
 	// result: (SGT (SignExt16to32 y) (SignExt16to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLess32_0(v *Value) bool {
 	// match: (Less32 x y)
 	// cond:
 	// result: (SGT y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
@@ -2277,30 +2265,30 @@ func rewriteValueMIPS_OpLess32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGTF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGTF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLess32U_0(v *Value) bool {
 	// match: (Less32U x y)
 	// cond:
 	// result: (SGTU y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
@@ -2309,69 +2297,75 @@ func rewriteValueMIPS_OpLess32U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPGTD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPGTD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8 x y)
 	// cond:
 	// result: (SGT (SignExt8to32 y) (SignExt8to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGT)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLess8U(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8U x y)
 	// cond:
 	// result: (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: t.IsBoolean()
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean()) {
@@ -2387,6 +2381,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
@@ -2402,6 +2397,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && !isSigned(t)) {
@@ -2417,6 +2413,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -2432,6 +2429,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -2447,6 +2445,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) || isPtr(t)) {
@@ -2462,6 +2461,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVFload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -2477,6 +2477,7 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitFloat(t)) {
@@ -2489,67 +2490,72 @@ func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v2 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLsh16x64_0(v *Value) bool {
 	// match: (Lsh16x64 x (Const64 [c]))
 	// cond: uint32(c) < 16
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2568,6 +2574,7 @@ func rewriteValueMIPS_OpLsh16x64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 16
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -2582,96 +2589,104 @@ func rewriteValueMIPS_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v2 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLsh32x64_0(v *Value) bool {
 	// match: (Lsh32x64 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2690,6 +2705,7 @@ func rewriteValueMIPS_OpLsh32x64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 32
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -2704,96 +2720,104 @@ func rewriteValueMIPS_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v2 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueMIPS_OpLsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpLsh8x64_0(v *Value) bool {
 	// match: (Lsh8x64 x (Const64 [c]))
 	// cond: uint32(c) < 8
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2812,6 +2836,7 @@ func rewriteValueMIPS_OpLsh8x64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 8
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -2826,63 +2851,66 @@ func rewriteValueMIPS_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSLL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMIPSADD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADD (MOVWconst [c]) x)
+func rewriteValueMIPS_OpMIPSADD_0(v *Value) bool {
+	// match: (ADD x (MOVWconst [c]))
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpMIPSADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADD x (MOVWconst [c]))
+	// match: (ADD (MOVWconst [c]) x)
 	// cond:
 	// result: (ADDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpMIPSADDconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -2892,6 +2920,7 @@ func rewriteValueMIPS_OpMIPSADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSNEG {
@@ -2907,6 +2936,7 @@ func rewriteValueMIPS_OpMIPSADD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSNEG {
 			break
@@ -2920,9 +2950,7 @@ func rewriteValueMIPS_OpMIPSADD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSADDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSADDconst_0(v *Value) bool {
 	// match: (ADDconst [off1] (MOVWaddr [off2] {sym} ptr))
 	// cond:
 	// result: (MOVWaddr [off1+off2] {sym} ptr)
@@ -2941,7 +2969,7 @@ func rewriteValueMIPS_OpMIPSADDconst(v *Value, config *Config) bool {
 		v.AddArg(ptr)
 		return true
 	}
-	// match: (ADDconst [0]  x)
+	// match: (ADDconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -3002,34 +3030,36 @@ func rewriteValueMIPS_OpMIPSADDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSAND(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSAND_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (AND (MOVWconst [c]) x)
+	// match: (AND x (MOVWconst [c]))
 	// cond:
 	// result: (ANDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpMIPSANDconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVWconst [c]))
+	// match: (AND (MOVWconst [c]) x)
 	// cond:
 	// result: (ANDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpMIPSANDconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -3039,6 +3069,7 @@ func rewriteValueMIPS_OpMIPSAND(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -3052,6 +3083,7 @@ func rewriteValueMIPS_OpMIPSAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (SGTUconst [1] (OR <x.Type> x y))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSSGTUconst {
 			break
@@ -3070,18 +3102,45 @@ func rewriteValueMIPS_OpMIPSAND(v *Value, config *Config) bool {
 		y := v_1.Args[0]
 		v.reset(OpMIPSSGTUconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpMIPSOR, x.Type)
+		v0 := b.NewValue0(v.Pos, OpMIPSOR, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValueMIPS_OpMIPSANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ANDconst [0]  _)
+	// match: (AND (SGTUconst [1] y) (SGTUconst [1] x))
+	// cond:
+	// result: (SGTUconst [1] (OR <x.Type> x y))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSSGTUconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		y := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSSGTUconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpMIPSSGTUconst)
+		v.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpMIPSOR, x.Type)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueMIPS_OpMIPSANDconst_0(v *Value) bool {
+	// match: (ANDconst [0] _)
 	// cond:
 	// result: (MOVWconst [0])
 	for {
@@ -3137,13 +3196,14 @@ func rewriteValueMIPS_OpMIPSANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSCMOVZ(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSCMOVZ_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMOVZ _ b (MOVWconst [0]))
 	// cond:
 	// result: b
 	for {
+		_ = v.Args[2]
 		b := v.Args[1]
 		v_2 := v.Args[2]
 		if v_2.Op != OpMIPSMOVWconst {
@@ -3161,6 +3221,7 @@ func rewriteValueMIPS_OpMIPSCMOVZ(v *Value, config *Config) bool {
 	// cond: c!=0
 	// result: a
 	for {
+		_ = v.Args[2]
 		a := v.Args[0]
 		v_2 := v.Args[2]
 		if v_2.Op != OpMIPSMOVWconst {
@@ -3179,6 +3240,7 @@ func rewriteValueMIPS_OpMIPSCMOVZ(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMOVZzero a c)
 	for {
+		_ = v.Args[2]
 		a := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -3195,13 +3257,12 @@ func rewriteValueMIPS_OpMIPSCMOVZ(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSCMOVZzero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSCMOVZzero_0(v *Value) bool {
 	// match: (CMOVZzero _ (MOVWconst [0]))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
 			break
@@ -3217,6 +3278,7 @@ func rewriteValueMIPS_OpMIPSCMOVZzero(v *Value, config *Config) bool {
 	// cond: c!=0
 	// result: a
 	for {
+		_ = v.Args[1]
 		a := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -3233,13 +3295,12 @@ func rewriteValueMIPS_OpMIPSCMOVZzero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSLoweredAtomicAdd(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSLoweredAtomicAdd_0(v *Value) bool {
 	// match: (LoweredAtomicAdd ptr (MOVWconst [c]) mem)
 	// cond: is16Bit(c)
 	// result: (LoweredAtomicAddconst [c] ptr mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -3258,13 +3319,12 @@ func rewriteValueMIPS_OpMIPSLoweredAtomicAdd(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSLoweredAtomicStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSLoweredAtomicStore_0(v *Value) bool {
 	// match: (LoweredAtomicStore ptr (MOVWconst [0]) mem)
 	// cond:
 	// result: (LoweredAtomicStorezero ptr mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -3281,15 +3341,14 @@ func rewriteValueMIPS_OpMIPSLoweredAtomicStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVBUload_0(v *Value) bool {
 	// match: (MOVBUload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVBUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3313,6 +3372,7 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3332,11 +3392,12 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBUreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVBstore {
@@ -3344,19 +3405,19 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpMIPSMOVBUreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBUreg(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSMOVBUreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBUreg x:(MOVBUload _ _))
@@ -3367,6 +3428,7 @@ func rewriteValueMIPS_OpMIPSMOVBUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -3394,13 +3456,14 @@ func rewriteValueMIPS_OpMIPSMOVBUreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBUload, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBUload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3439,15 +3502,14 @@ func rewriteValueMIPS_OpMIPSMOVBUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVBload  [off1] {sym} x:(ADDconst [off2] ptr) mem)
+func rewriteValueMIPS_OpMIPSMOVBload_0(v *Value) bool {
+	// match: (MOVBload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVBload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3471,6 +3533,7 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3490,11 +3553,12 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVBstore {
@@ -3502,19 +3566,19 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpMIPSMOVBreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSMOVBreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBreg x:(MOVBload _ _))
@@ -3525,6 +3589,7 @@ func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -3552,13 +3617,14 @@ func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBload, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -3585,7 +3651,7 @@ func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVBreg  (MOVWconst [c]))
+	// match: (MOVBreg (MOVWconst [c]))
 	// cond:
 	// result: (MOVWconst [int64(int8(c))])
 	for {
@@ -3600,15 +3666,14 @@ func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVBstore_0(v *Value) bool {
 	// match: (MOVBstore [off1] {sym} x:(ADDconst [off2] ptr) val mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVBstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3634,6 +3699,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3660,6 +3726,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -3682,6 +3749,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVBreg {
@@ -3703,6 +3771,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVBUreg {
@@ -3724,6 +3793,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHreg {
@@ -3745,6 +3815,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHUreg {
@@ -3766,6 +3837,7 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWreg {
@@ -3783,15 +3855,14 @@ func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVBstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVBstorezero_0(v *Value) bool {
 	// match: (MOVBstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVBstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3815,6 +3886,7 @@ func rewriteValueMIPS_OpMIPSMOVBstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3835,15 +3907,14 @@ func rewriteValueMIPS_OpMIPSMOVBstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDload  [off1] {sym} x:(ADDconst [off2] ptr) mem)
+func rewriteValueMIPS_OpMIPSMOVDload_0(v *Value) bool {
+	// match: (MOVDload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVDload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3867,6 +3938,7 @@ func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3891,6 +3963,7 @@ func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVDstore {
@@ -3898,6 +3971,7 @@ func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -3910,15 +3984,14 @@ func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVDstore_0(v *Value) bool {
 	// match: (MOVDstore [off1] {sym} x:(ADDconst [off2] ptr) val mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3944,6 +4017,7 @@ func rewriteValueMIPS_OpMIPSMOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -3966,15 +4040,14 @@ func rewriteValueMIPS_OpMIPSMOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVFload  [off1] {sym} x:(ADDconst [off2] ptr) mem)
+func rewriteValueMIPS_OpMIPSMOVFload_0(v *Value) bool {
+	// match: (MOVFload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVFload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -3998,6 +4071,7 @@ func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4022,6 +4096,7 @@ func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVFstore {
@@ -4029,6 +4104,7 @@ func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -4041,15 +4117,14 @@ func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVFstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVFstore_0(v *Value) bool {
 	// match: (MOVFstore [off1] {sym} x:(ADDconst [off2] ptr) val mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVFstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4075,6 +4150,7 @@ func rewriteValueMIPS_OpMIPSMOVFstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4097,15 +4173,14 @@ func rewriteValueMIPS_OpMIPSMOVFstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVHUload_0(v *Value) bool {
 	// match: (MOVHUload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVHUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4129,6 +4204,7 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4148,11 +4224,12 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVHUreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHstore {
@@ -4160,19 +4237,19 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpMIPSMOVHUreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSMOVHUreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVHUreg x:(MOVBUload _ _))
@@ -4183,6 +4260,7 @@ func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -4195,6 +4273,7 @@ func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -4234,13 +4313,14 @@ func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHUload, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHUload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -4279,15 +4359,14 @@ func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHload  [off1] {sym} x:(ADDconst [off2] ptr) mem)
+func rewriteValueMIPS_OpMIPSMOVHload_0(v *Value) bool {
+	// match: (MOVHload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVHload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4311,6 +4390,7 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4330,11 +4410,12 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-	// result: x
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVHreg x)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHstore {
@@ -4342,19 +4423,19 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
-		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpMIPSMOVHreg)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSMOVHreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVHreg x:(MOVBload _ _))
@@ -4365,6 +4446,7 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -4377,6 +4459,7 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -4389,6 +4472,7 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPSMOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPSMOVWreg)
 		v.AddArg(x)
 		return true
@@ -4440,13 +4524,14 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHload, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHload, t)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -4473,7 +4558,7 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVHreg  (MOVWconst [c]))
+	// match: (MOVHreg (MOVWconst [c]))
 	// cond:
 	// result: (MOVWconst [int64(int16(c))])
 	for {
@@ -4488,15 +4573,14 @@ func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVHstore_0(v *Value) bool {
 	// match: (MOVHstore [off1] {sym} x:(ADDconst [off2] ptr) val mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVHstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4522,6 +4606,7 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4548,6 +4633,7 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -4570,6 +4656,7 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHreg {
@@ -4591,6 +4678,7 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVHUreg {
@@ -4612,6 +4700,7 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWreg {
@@ -4629,15 +4718,14 @@ func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVHstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVHstorezero_0(v *Value) bool {
 	// match: (MOVHstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVHstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4661,6 +4749,7 @@ func rewriteValueMIPS_OpMIPSMOVHstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4681,15 +4770,14 @@ func rewriteValueMIPS_OpMIPSMOVHstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWload  [off1] {sym} x:(ADDconst [off2] ptr) mem)
+func rewriteValueMIPS_OpMIPSMOVWload_0(v *Value) bool {
+	// match: (MOVWload [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVWload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4713,6 +4801,7 @@ func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4737,6 +4826,7 @@ func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWstore {
@@ -4744,6 +4834,7 @@ func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
 		}
 		off2 := v_1.AuxInt
 		sym2 := v_1.Aux
+		_ = v_1.Args[2]
 		ptr2 := v_1.Args[0]
 		x := v_1.Args[1]
 		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
@@ -4756,9 +4847,7 @@ func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVWreg_0(v *Value) bool {
 	// match: (MOVWreg x)
 	// cond: x.Uses == 1
 	// result: (MOVWnop x)
@@ -4771,7 +4860,7 @@ func rewriteValueMIPS_OpMIPSMOVWreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWreg  (MOVWconst [c]))
+	// match: (MOVWreg (MOVWconst [c]))
 	// cond:
 	// result: (MOVWconst [c])
 	for {
@@ -4786,15 +4875,14 @@ func rewriteValueMIPS_OpMIPSMOVWreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVWstore_0(v *Value) bool {
 	// match: (MOVWstore [off1] {sym} x:(ADDconst [off2] ptr) val mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVWstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4820,6 +4908,7 @@ func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4846,6 +4935,7 @@ func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -4868,6 +4958,7 @@ func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWreg {
@@ -4885,15 +4976,14 @@ func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMOVWstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSMOVWstorezero_0(v *Value) bool {
 	// match: (MOVWstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem)
 	// cond: (is16Bit(off1+off2) || x.Uses == 1)
 	// result: (MOVWstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpMIPSADDconst {
 			break
@@ -4917,6 +5007,7 @@ func rewriteValueMIPS_OpMIPSMOVWstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWaddr {
 			break
@@ -4937,13 +5028,12 @@ func rewriteValueMIPS_OpMIPSMOVWstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MUL (MOVWconst [0]) _ )
+func rewriteValueMIPS_OpMIPSMUL_0(v *Value) bool {
+	// match: (MUL (MOVWconst [0]) _)
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -4955,10 +5045,27 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (MUL (MOVWconst [1]) x )
+	// match: (MUL _ (MOVWconst [0]))
+	// cond:
+	// result: (MOVWconst [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MUL (MOVWconst [1]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -4972,10 +5079,29 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVWconst [-1]) x )
+	// match: (MUL x (MOVWconst [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MUL (MOVWconst [-1]) x)
 	// cond:
 	// result: (NEG x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -4988,10 +5114,28 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MUL (MOVWconst [c]) x )
+	// match: (MUL x (MOVWconst [-1]))
+	// cond:
+	// result: (NEG x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpMIPSNEG)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MUL (MOVWconst [c]) x)
 	// cond: isPowerOfTwo(int64(uint32(c)))
 	// result: (SLLconst [log2(int64(uint32(c)))] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -5006,10 +5150,30 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (MUL x (MOVWconst [c]))
+	// cond: isPowerOfTwo(int64(uint32(c)))
+	// result: (SLLconst [log2(int64(uint32(c)))] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(int64(uint32(c)))) {
+			break
+		}
+		v.reset(OpMIPSSLLconst)
+		v.AuxInt = log2(int64(uint32(c)))
+		v.AddArg(x)
+		return true
+	}
 	// match: (MUL (MOVWconst [c]) (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(c)*int32(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -5024,11 +5188,28 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
 		v.AuxInt = int64(int32(c) * int32(d))
 		return true
 	}
+	// match: (MUL (MOVWconst [d]) (MOVWconst [c]))
+	// cond:
+	// result: (MOVWconst [int64(int32(c)*int32(d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = int64(int32(c) * int32(d))
+		return true
+	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSNEG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSNEG_0(v *Value) bool {
 	// match: (NEG (MOVWconst [c]))
 	// cond:
 	// result: (MOVWconst [int64(int32(-c))])
@@ -5044,34 +5225,34 @@ func rewriteValueMIPS_OpMIPSNEG(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSNOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOR (MOVWconst [c]) x)
+func rewriteValueMIPS_OpMIPSNOR_0(v *Value) bool {
+	// match: (NOR x (MOVWconst [c]))
 	// cond:
 	// result: (NORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpMIPSNORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (NOR x (MOVWconst [c]))
+	// match: (NOR (MOVWconst [c]) x)
 	// cond:
 	// result: (NORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpMIPSNORconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -5079,9 +5260,7 @@ func rewriteValueMIPS_OpMIPSNOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSNORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSNORconst_0(v *Value) bool {
 	// match: (NORconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [^(c|d)])
@@ -5098,43 +5277,46 @@ func rewriteValueMIPS_OpMIPSNORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSOR(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMIPSOR_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (OR  (MOVWconst [c]) x)
+	// match: (OR x (MOVWconst [c]))
 	// cond:
 	// result: (ORconst  [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpMIPSORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x (MOVWconst [c]))
+	// match: (OR (MOVWconst [c]) x)
 	// cond:
 	// result: (ORconst  [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpMIPSORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x x)
+	// match: (OR x x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -5148,6 +5330,7 @@ func rewriteValueMIPS_OpMIPSOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (SGTUzero (OR <x.Type> x y))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSSGTUzero {
 			break
@@ -5159,7 +5342,29 @@ func rewriteValueMIPS_OpMIPSOR(v *Value, config *Config) bool {
 		}
 		y := v_1.Args[0]
 		v.reset(OpMIPSSGTUzero)
-		v0 := b.NewValue0(v.Line, OpMIPSOR, x.Type)
+		v0 := b.NewValue0(v.Pos, OpMIPSOR, x.Type)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (OR (SGTUzero y) (SGTUzero x))
+	// cond:
+	// result: (SGTUzero (OR <x.Type> x y))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSSGTUzero {
+			break
+		}
+		y := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSSGTUzero {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpMIPSSGTUzero)
+		v0 := b.NewValue0(v.Pos, OpMIPSOR, x.Type)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -5167,10 +5372,8 @@ func rewriteValueMIPS_OpMIPSOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORconst  [0]  x)
+func rewriteValueMIPS_OpMIPSORconst_0(v *Value) bool {
+	// match: (ORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -5183,7 +5386,7 @@ func rewriteValueMIPS_OpMIPSORconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORconst  [-1] _)
+	// match: (ORconst [-1] _)
 	// cond:
 	// result: (MOVWconst [-1])
 	for {
@@ -5226,13 +5429,12 @@ func rewriteValueMIPS_OpMIPSORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SGT  (MOVWconst [c]) x)
+func rewriteValueMIPS_OpMIPSSGT_0(v *Value) bool {
+	// match: (SGT (MOVWconst [c]) x)
 	// cond:
 	// result: (SGTconst  [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -5248,6 +5450,7 @@ func rewriteValueMIPS_OpMIPSSGT(v *Value, config *Config) bool {
 	// cond:
 	// result: (SGTzero x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5262,13 +5465,12 @@ func rewriteValueMIPS_OpMIPSSGT(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGTU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSGTU_0(v *Value) bool {
 	// match: (SGTU (MOVWconst [c]) x)
 	// cond:
 	// result: (SGTUconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -5284,6 +5486,7 @@ func rewriteValueMIPS_OpMIPSSGTU(v *Value, config *Config) bool {
 	// cond:
 	// result: (SGTUzero x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5298,9 +5501,7 @@ func rewriteValueMIPS_OpMIPSSGTU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGTUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSGTUconst_0(v *Value) bool {
 	// match: (SGTUconst [c] (MOVWconst [d]))
 	// cond: uint32(c)>uint32(d)
 	// result: (MOVWconst [1])
@@ -5403,9 +5604,7 @@ func rewriteValueMIPS_OpMIPSSGTUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGTUzero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSGTUzero_0(v *Value) bool {
 	// match: (SGTUzero (MOVWconst [d]))
 	// cond: uint32(d) != 0
 	// result: (MOVWconst [1])
@@ -5440,9 +5639,7 @@ func rewriteValueMIPS_OpMIPSSGTUzero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGTconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSGTconst_0(v *Value) bool {
 	// match: (SGTconst [c] (MOVWconst [d]))
 	// cond: int32(c) > int32(d)
 	// result: (MOVWconst [1])
@@ -5605,6 +5802,9 @@ func rewriteValueMIPS_OpMIPSSGTconst(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	return false
+}
+func rewriteValueMIPS_OpMIPSSGTconst_10(v *Value) bool {
 	// match: (SGTconst [c] (ANDconst [m] _))
 	// cond: 0 <= int32(m) && int32(m) < int32(c)
 	// result: (MOVWconst [1])
@@ -5641,9 +5841,7 @@ func rewriteValueMIPS_OpMIPSSGTconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSGTzero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSGTzero_0(v *Value) bool {
 	// match: (SGTzero (MOVWconst [d]))
 	// cond: int32(d) > 0
 	// result: (MOVWconst [1])
@@ -5678,13 +5876,12 @@ func rewriteValueMIPS_OpMIPSSGTzero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSLL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSLL_0(v *Value) bool {
 	// match: (SLL _ (MOVWconst [c]))
 	// cond: uint32(c)>=32
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
 			break
@@ -5701,6 +5898,7 @@ func rewriteValueMIPS_OpMIPSSLL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SLLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5714,9 +5912,7 @@ func rewriteValueMIPS_OpMIPSSLL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSLLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSLLconst_0(v *Value) bool {
 	// match: (SLLconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(uint32(d)<<uint32(c)))])
@@ -5733,13 +5929,12 @@ func rewriteValueMIPS_OpMIPSSLLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSRA(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSRA_0(v *Value) bool {
 	// match: (SRA x (MOVWconst [c]))
 	// cond: uint32(c)>=32
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5758,6 +5953,7 @@ func rewriteValueMIPS_OpMIPSSRA(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5771,9 +5967,7 @@ func rewriteValueMIPS_OpMIPSSRA(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSRAconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSRAconst_0(v *Value) bool {
 	// match: (SRAconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(int32(d)>>uint32(c))])
@@ -5790,13 +5984,12 @@ func rewriteValueMIPS_OpMIPSSRAconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSRL(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSRL_0(v *Value) bool {
 	// match: (SRL _ (MOVWconst [c]))
 	// cond: uint32(c)>=32
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
 			break
@@ -5813,6 +6006,7 @@ func rewriteValueMIPS_OpMIPSSRL(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5826,9 +6020,7 @@ func rewriteValueMIPS_OpMIPSSRL(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSRLconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSRLconst_0(v *Value) bool {
 	// match: (SRLconst [c] (MOVWconst [d]))
 	// cond:
 	// result: (MOVWconst [int64(uint32(d)>>uint32(c))])
@@ -5845,13 +6037,12 @@ func rewriteValueMIPS_OpMIPSSRLconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSUB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMIPSSUB_0(v *Value) bool {
 	// match: (SUB x (MOVWconst [c]))
 	// cond:
 	// result: (SUBconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPSMOVWconst {
@@ -5867,6 +6058,7 @@ func rewriteValueMIPS_OpMIPSSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -5879,6 +6071,7 @@ func rewriteValueMIPS_OpMIPSSUB(v *Value, config *Config) bool {
 	// cond:
 	// result: (NEG x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMOVWconst {
 			break
@@ -5893,10 +6086,8 @@ func rewriteValueMIPS_OpMIPSSUB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSSUBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBconst [0]  x)
+func rewriteValueMIPS_OpMIPSSUBconst_0(v *Value) bool {
+	// match: (SUBconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -5957,34 +6148,34 @@ func rewriteValueMIPS_OpMIPSSUBconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSXOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR (MOVWconst [c]) x)
+func rewriteValueMIPS_OpMIPSXOR_0(v *Value) bool {
+	// match: (XOR x (MOVWconst [c]))
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x (MOVWconst [c]))
+	// match: (XOR (MOVWconst [c]) x)
 	// cond:
 	// result: (XORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPSMOVWconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		v.reset(OpMIPSXORconst)
 		v.AuxInt = c
 		v.AddArg(x)
@@ -5994,6 +6185,7 @@ func rewriteValueMIPS_OpMIPSXOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6004,10 +6196,8 @@ func rewriteValueMIPS_OpMIPSXOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMIPSXORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XORconst [0]  x)
+func rewriteValueMIPS_OpMIPSXORconst_0(v *Value) bool {
+	// match: (XORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -6065,203 +6255,227 @@ func rewriteValueMIPS_OpMIPSXORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMod16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16 x y)
 	// cond:
 	// result: (Select0 (DIV (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMod16u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (Select0 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMod32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32 x y)
 	// cond:
 	// result: (Select0 (DIV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMod32u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32u x y)
 	// cond:
 	// result: (Select0 (DIVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMod8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8 x y)
 	// cond:
 	// result: (Select0 (DIV (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIV, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIV, types.NewTuple(typ.Int32, typ.Int32))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMod8u(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8u x y)
 	// cond:
 	// result: (Select0 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSDIVU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSDIVU, types.NewTuple(typ.UInt32, typ.UInt32))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpMIPSMOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [2] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore dst (MOVHUload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHUload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVBstore [1] dst (MOVBUload [1] src mem) 		(MOVBstore dst (MOVBUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 1
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v0.AuxInt = 1
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6269,48 +6483,56 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore dst (MOVWload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] dst (MOVHUload [2] src mem) 		(MOVHstore dst (MOVHUload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHUload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHUload, typ.UInt16)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVHUload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVHUload, typ.UInt16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6318,44 +6540,44 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVBstore [3] dst (MOVBUload [3] src mem) 		(MOVBstore [2] dst (MOVBUload [2] src mem) 			(MOVBstore [1] dst (MOVBUload [1] src mem) 				(MOVBstore dst (MOVBUload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 3
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v0.AuxInt = 3
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v2.AuxInt = 2
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v4.AuxInt = 1
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v6 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -6365,36 +6587,36 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBUload [2] src mem) 		(MOVBstore [1] dst (MOVBUload [1] src mem) 			(MOVBstore dst (MOVBUload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v2.AuxInt = 1
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVBUload, typ.UInt8)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6403,28 +6625,32 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [4] dst (MOVWload [4] src mem) 		(MOVWstore dst (MOVWload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6432,44 +6658,48 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [6] dst (MOVHload [6] src mem) 		(MOVHstore [4] dst (MOVHload [4] src mem) 			(MOVHstore [2] dst (MOVHload [2] src mem) 				(MOVHstore dst (MOVHload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AuxInt = 6
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v0.AuxInt = 6
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v3.AuxInt = 2
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v4.AuxInt = 2
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v6 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -6479,36 +6709,49 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+	return false
+}
+func rewriteValueMIPS_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [6] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [4] dst (MOVHload [4] src mem) 		(MOVHstore [2] dst (MOVHload [2] src mem) 			(MOVHstore dst (MOVHload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v2.AuxInt = 2
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVHload, typ.Int16)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6517,36 +6760,40 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [12] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [8] dst (MOVWload [8] src mem) 		(MOVWstore [4] dst (MOVWload [4] src mem) 			(MOVWstore dst (MOVWload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 12 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6555,44 +6802,48 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [16] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [12] dst (MOVWload [12] src mem) 		(MOVWstore [8] dst (MOVWload [8] src mem) 			(MOVWstore [4] dst (MOVWload [4] src mem) 				(MOVWstore dst (MOVWload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 12
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v0.AuxInt = 12
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v2.AuxInt = 8
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v3.AuxInt = 4
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v4.AuxInt = 4
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSMOVWload, typ.UInt32)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -6602,23 +6853,25 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: (SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0)
-	// result: (LoweredMove [SizeAndAlign(s).Align()] 		dst 		src 		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// match: (Move [s] {t} dst src mem)
+	// cond: (s > 16 || t.(*types.Type).Alignment()%4 != 0)
+	// result: (LoweredMove [t.(*types.Type).Alignment()] 		dst 		src 		(ADDconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0) {
+		if !(s > 16 || t.(*types.Type).Alignment()%4 != 0) {
 			break
 		}
 		v.reset(OpMIPSLoweredMove)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpMIPSADDconst, src.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpMIPSADDconst, src.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(src)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -6626,13 +6879,12 @@ func rewriteValueMIPS_OpMove(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul16_0(v *Value) bool {
 	// match: (Mul16 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMUL)
@@ -6641,13 +6893,12 @@ func rewriteValueMIPS_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul32_0(v *Value) bool {
 	// match: (Mul32 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMUL)
@@ -6656,13 +6907,12 @@ func rewriteValueMIPS_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (MULF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMULF)
@@ -6671,13 +6921,12 @@ func rewriteValueMIPS_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpMul32uhilo(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul32uhilo_0(v *Value) bool {
 	// match: (Mul32uhilo x y)
 	// cond:
 	// result: (MULTU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMULTU)
@@ -6686,13 +6935,12 @@ func rewriteValueMIPS_OpMul32uhilo(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (MULD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMULD)
@@ -6701,13 +6949,12 @@ func rewriteValueMIPS_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpMul8_0(v *Value) bool {
 	// match: (Mul8 x y)
 	// cond:
 	// result: (MUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSMUL)
@@ -6716,9 +6963,7 @@ func rewriteValueMIPS_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeg16_0(v *Value) bool {
 	// match: (Neg16 x)
 	// cond:
 	// result: (NEG x)
@@ -6729,9 +6974,7 @@ func rewriteValueMIPS_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeg32_0(v *Value) bool {
 	// match: (Neg32 x)
 	// cond:
 	// result: (NEG x)
@@ -6742,9 +6985,7 @@ func rewriteValueMIPS_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (NEGF x)
@@ -6755,9 +6996,7 @@ func rewriteValueMIPS_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (NEGD x)
@@ -6768,9 +7007,7 @@ func rewriteValueMIPS_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeg8_0(v *Value) bool {
 	// match: (Neg8 x)
 	// cond:
 	// result: (NEG x)
@@ -6781,115 +7018,125 @@ func rewriteValueMIPS_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq16 x y)
 	// cond:
 	// result: (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)) (MOVWconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq32 x y)
 	// cond:
 	// result: (SGTU (XOR x y) (MOVWconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (FPFlagFalse (CMPEQF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagFalse)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPEQF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPEQF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (FPFlagFalse (CMPEQD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSFPFlagFalse)
-		v0 := b.NewValue0(v.Line, OpMIPSCMPEQD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPSCMPEQD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq8 x y)
 	// cond:
 	// result: (SGTU (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)) (MOVWconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNeqB_0(v *Value) bool {
 	// match: (NeqB x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXOR)
@@ -6898,33 +7145,35 @@ func rewriteValueMIPS_OpNeqB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (SGTU (XOR x y) (MOVWconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSGTU)
-		v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSXOR, typ.UInt32)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPSLoweredNilCheck)
@@ -6933,9 +7182,7 @@ func rewriteValueMIPS_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORconst [1] x)
@@ -6947,9 +7194,7 @@ func rewriteValueMIPS_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpOffPtr_0(v *Value) bool {
 	// match: (OffPtr [off] ptr:(SP))
 	// cond:
 	// result: (MOVWaddr [off] ptr)
@@ -6976,13 +7221,12 @@ func rewriteValueMIPS_OpOffPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSOR)
@@ -6991,13 +7235,12 @@ func rewriteValueMIPS_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSOR)
@@ -7006,13 +7249,12 @@ func rewriteValueMIPS_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpOr8_0(v *Value) bool {
 	// match: (Or8 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSOR)
@@ -7021,13 +7263,12 @@ func rewriteValueMIPS_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSOR)
@@ -7036,71 +7277,104 @@ func rewriteValueMIPS_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueMIPS_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueMIPS_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt16to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 x (Const64 [c]))
 	// cond: uint32(c) < 16
-	// result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+	// result: (SRLconst (SLLconst <typ.UInt32> x [16]) [c+16])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7112,7 +7386,7 @@ func rewriteValueMIPS_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRLconst)
 		v.AuxInt = c + 16
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7122,6 +7396,7 @@ func rewriteValueMIPS_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 16
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -7136,60 +7411,66 @@ func rewriteValueMIPS_OpRsh16Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = -1
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -7197,25 +7478,28 @@ func rewriteValueMIPS_OpRsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x32 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = -1
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v1.AddArg(v3)
@@ -7223,13 +7507,16 @@ func rewriteValueMIPS_OpRsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint32(c) < 16
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [16]) [c+16])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7241,7 +7528,7 @@ func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRAconst)
 		v.AuxInt = c + 16
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7249,8 +7536,9 @@ func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint32(c) >= 16
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [16]) [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7262,7 +7550,7 @@ func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRAconst)
 		v.AuxInt = 31
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 16
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7270,29 +7558,32 @@ func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x8 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = -1
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -7300,67 +7591,72 @@ func rewriteValueMIPS_OpRsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v2 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpRsh32Ux64_0(v *Value) bool {
 	// match: (Rsh32Ux64 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SRLconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7379,6 +7675,7 @@ func rewriteValueMIPS_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 32
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -7393,56 +7690,62 @@ func rewriteValueMIPS_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 x y)
 	// cond:
-	// result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+	// result: (SRA x ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = -1
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
@@ -7450,23 +7753,26 @@ func rewriteValueMIPS_OpRsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x32 x y)
 	// cond:
-	// result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+	// result: (SRA x ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = -1
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v2 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v2.AuxInt = 32
 		v2.AddArg(y)
 		v0.AddArg(v2)
@@ -7474,13 +7780,12 @@ func rewriteValueMIPS_OpRsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpRsh32x64_0(v *Value) bool {
 	// match: (Rsh32x64 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SRAconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7499,6 +7804,7 @@ func rewriteValueMIPS_OpRsh32x64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 32
 	// result: (SRAconst x [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7515,27 +7821,30 @@ func rewriteValueMIPS_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x8 x y)
 	// cond:
-	// result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+	// result: (SRA x ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = -1
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
-		v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
@@ -7543,71 +7852,80 @@ func rewriteValueMIPS_OpRsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux32 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt8to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux64 x (Const64 [c]))
 	// cond: uint32(c) < 8
-	// result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+	// result: (SRLconst (SLLconst <typ.UInt32> x [24]) [c+24])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7619,7 +7937,7 @@ func rewriteValueMIPS_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRLconst)
 		v.AuxInt = c + 24
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7629,6 +7947,7 @@ func rewriteValueMIPS_OpRsh8Ux64(v *Value, config *Config) bool {
 	// cond: uint32(c) >= 8
 	// result: (MOVWconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -7643,60 +7962,66 @@ func rewriteValueMIPS_OpRsh8Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux8 <t> x y)
 	// cond:
 	// result: (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSRL, t)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = 0
 		v.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = -1
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -7704,25 +8029,28 @@ func rewriteValueMIPS_OpRsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x32 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> y (MOVWconst [-1]) (SGTUconst [32] y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = -1
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v3 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v3.AuxInt = 32
 		v3.AddArg(y)
 		v1.AddArg(v3)
@@ -7730,13 +8058,16 @@ func rewriteValueMIPS_OpRsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint32(c) < 8
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [24]) [c+24])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7748,7 +8079,7 @@ func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRAconst)
 		v.AuxInt = c + 24
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7756,8 +8087,9 @@ func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint32(c) >= 8
-	// result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
+	// result: (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7769,7 +8101,7 @@ func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpMIPSSRAconst)
 		v.AuxInt = 31
-		v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSSLLconst, typ.UInt32)
 		v0.AuxInt = 24
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -7777,29 +8109,32 @@ func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x8 x y)
 	// cond:
-	// result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+	// result: (SRA (SignExt16to32 x) ( CMOVZ <typ.UInt32> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSRA)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSCMOVZ, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v3.AuxInt = -1
 		v1.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+		v4 := b.NewValue0(v.Pos, OpMIPSSGTUconst, typ.Bool)
 		v4.AuxInt = 32
-		v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v1.AddArg(v4)
@@ -7807,9 +8142,11 @@ func rewriteValueMIPS_OpRsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpSelect0_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Select0 (Add32carry <t> x y))
 	// cond:
 	// result: (ADD <t.FieldType(0)> x y)
@@ -7819,6 +8156,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 			break
 		}
 		t := v_0.Type
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpMIPSADD)
@@ -7836,6 +8174,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 			break
 		}
 		t := v_0.Type
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpMIPSSUB)
@@ -7844,33 +8183,47 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Select0 (MULTU x (MOVWconst [c])))
-	// cond: x.Op != OpMIPSMOVWconst
-	// result: (Select0 (MULTU (MOVWconst [c]) x ))
+	// match: (Select0 (MULTU (MOVWconst [0]) _))
+	// cond:
+	// result: (MOVWconst [0])
 	for {
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
-		x := v_0.Args[0]
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_0_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Select0 (MULTU _ (MOVWconst [0])))
+	// cond:
+	// result: (MOVWconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0_1.AuxInt
-		if !(x.Op != OpMIPSMOVWconst) {
+		if v_0_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPSMULTU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
-		v1.AuxInt = c
-		v0.AddArg(v1)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Select0 (MULTU (MOVWconst [0]) _ ))
+	// match: (Select0 (MULTU (MOVWconst [1]) _))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
@@ -7878,18 +8231,19 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		if v_0_0.AuxInt != 0 {
+		if v_0_0.AuxInt != 1 {
 			break
 		}
 		v.reset(OpMIPSMOVWconst)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Select0 (MULTU (MOVWconst [1]) _ ))
+	// match: (Select0 (MULTU _ (MOVWconst [1])))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
@@ -7897,18 +8251,19 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpMIPSMOVWconst {
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		if v_0_0.AuxInt != 1 {
+		if v_0_1.AuxInt != 1 {
 			break
 		}
 		v.reset(OpMIPSMOVWconst)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Select0 (MULTU (MOVWconst [-1]) x ))
+	// match: (Select0 (MULTU (MOVWconst [-1]) x))
 	// cond:
 	// result: (CMOVZ (ADDconst <x.Type> [-1] x) (MOVWconst [0]) x)
 	for {
@@ -7916,6 +8271,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -7925,17 +8281,45 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		}
 		x := v_0.Args[1]
 		v.reset(OpMIPSCMOVZ)
-		v0 := b.NewValue0(v.Line, OpMIPSADDconst, x.Type)
+		v0 := b.NewValue0(v.Pos, OpMIPSADDconst, x.Type)
+		v0.AuxInt = -1
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Select0 (MULTU x (MOVWconst [-1])))
+	// cond:
+	// result: (CMOVZ (ADDconst <x.Type> [-1] x) (MOVWconst [0]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_0_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpMIPSCMOVZ)
+		v0 := b.NewValue0(v.Pos, OpMIPSADDconst, x.Type)
 		v0.AuxInt = -1
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select0 (MULTU (MOVWconst [c]) x ))
+	// match: (Select0 (MULTU (MOVWconst [c]) x))
 	// cond: isPowerOfTwo(int64(uint32(c)))
 	// result: (SRLconst [32-log2(int64(uint32(c)))] x)
 	for {
@@ -7943,6 +8327,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -7957,7 +8342,33 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select0 (MULTU  (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select0 (MULTU x (MOVWconst [c])))
+	// cond: isPowerOfTwo(int64(uint32(c)))
+	// result: (SRLconst [32-log2(int64(uint32(c)))] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		if !(isPowerOfTwo(int64(uint32(c)))) {
+			break
+		}
+		v.reset(OpMIPSSRLconst)
+		v.AuxInt = 32 - log2(int64(uint32(c)))
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueMIPS_OpSelect0_10(v *Value) bool {
+	// match: (Select0 (MULTU (MOVWconst [c]) (MOVWconst [d])))
 	// cond:
 	// result: (MOVWconst [(c*d)>>32])
 	for {
@@ -7965,6 +8376,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -7979,26 +8391,50 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		v.AuxInt = (c * d) >> 32
 		return true
 	}
-	// match: (Select0 (DIV  (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select0 (MULTU (MOVWconst [d]) (MOVWconst [c])))
 	// cond:
-	// result: (MOVWconst [int64(int32(c)%int32(d))])
+	// result: (MOVWconst [(c*d)>>32])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpMIPSDIV {
+		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0_0.AuxInt
+		d := v_0_0.AuxInt
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		d := v_0_1.AuxInt
+		c := v_0_1.AuxInt
 		v.reset(OpMIPSMOVWconst)
-		v.AuxInt = int64(int32(c) % int32(d))
+		v.AuxInt = (c * d) >> 32
+		return true
+	}
+	// match: (Select0 (DIV (MOVWconst [c]) (MOVWconst [d])))
+	// cond:
+	// result: (MOVWconst [int64(int32(c)%int32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSDIV {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		d := v_0_1.AuxInt
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = int64(int32(c) % int32(d))
 		return true
 	}
 	// match: (Select0 (DIVU (MOVWconst [c]) (MOVWconst [d])))
@@ -8009,6 +8445,7 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSDIVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8025,24 +8462,27 @@ func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpSelect1_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Select1 (Add32carry <t> x y))
 	// cond:
-	// result: (SGTU <config.fe.TypeBool()> x (ADD <t.FieldType(0)> x y))
+	// result: (SGTU <typ.Bool> x (ADD <t.FieldType(0)> x y))
 	for {
 		v_0 := v.Args[0]
 		if v_0.Op != OpAdd32carry {
 			break
 		}
 		t := v_0.Type
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpMIPSSGTU)
-		v.Type = config.fe.TypeBool()
+		v.Type = typ.Bool
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPSADD, t.FieldType(0))
+		v0 := b.NewValue0(v.Pos, OpMIPSADD, t.FieldType(0))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -8050,51 +8490,46 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 	}
 	// match: (Select1 (Sub32carry <t> x y))
 	// cond:
-	// result: (SGTU <config.fe.TypeBool()> (SUB <t.FieldType(0)> x y) x)
+	// result: (SGTU <typ.Bool> (SUB <t.FieldType(0)> x y) x)
 	for {
 		v_0 := v.Args[0]
 		if v_0.Op != OpSub32carry {
 			break
 		}
 		t := v_0.Type
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		v.reset(OpMIPSSGTU)
-		v.Type = config.fe.TypeBool()
-		v0 := b.NewValue0(v.Line, OpMIPSSUB, t.FieldType(0))
+		v.Type = typ.Bool
+		v0 := b.NewValue0(v.Pos, OpMIPSSUB, t.FieldType(0))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select1 (MULTU x (MOVWconst [c])))
-	// cond: x.Op != OpMIPSMOVWconst
-	// result: (Select1 (MULTU (MOVWconst [c]) x ))
+	// match: (Select1 (MULTU (MOVWconst [0]) _))
+	// cond:
+	// result: (MOVWconst [0])
 	for {
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpMIPSMOVWconst {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPSMOVWconst {
 			break
 		}
-		c := v_0_1.AuxInt
-		if !(x.Op != OpMIPSMOVWconst) {
+		if v_0_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPSMULTU, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
-		v1.AuxInt = c
-		v0.AddArg(v1)
-		v0.AddArg(x)
-		v.AddArg(v0)
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Select1 (MULTU (MOVWconst [0]) _ ))
+	// match: (Select1 (MULTU _ (MOVWconst [0])))
 	// cond:
 	// result: (MOVWconst [0])
 	for {
@@ -8102,18 +8537,19 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpMIPSMOVWconst {
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
 			break
 		}
-		if v_0_0.AuxInt != 0 {
+		if v_0_1.AuxInt != 0 {
 			break
 		}
 		v.reset(OpMIPSMOVWconst)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Select1 (MULTU (MOVWconst [1]) x ))
+	// match: (Select1 (MULTU (MOVWconst [1]) x))
 	// cond:
 	// result: x
 	for {
@@ -8121,6 +8557,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8134,7 +8571,29 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select1 (MULTU (MOVWconst [-1]) x ))
+	// match: (Select1 (MULTU x (MOVWconst [1])))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_0_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Select1 (MULTU (MOVWconst [-1]) x))
 	// cond:
 	// result: (NEG <x.Type> x)
 	for {
@@ -8142,6 +8601,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8155,7 +8615,29 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select1 (MULTU (MOVWconst [c]) x ))
+	// match: (Select1 (MULTU x (MOVWconst [-1])))
+	// cond:
+	// result: (NEG <x.Type> x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		if v_0_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpMIPSNEG)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Select1 (MULTU (MOVWconst [c]) x))
 	// cond: isPowerOfTwo(int64(uint32(c)))
 	// result: (SLLconst [log2(int64(uint32(c)))] x)
 	for {
@@ -8163,6 +8645,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8177,7 +8660,33 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select1 (MULTU  (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select1 (MULTU x (MOVWconst [c])))
+	// cond: isPowerOfTwo(int64(uint32(c)))
+	// result: (SLLconst [log2(int64(uint32(c)))] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		if !(isPowerOfTwo(int64(uint32(c)))) {
+			break
+		}
+		v.reset(OpMIPSSLLconst)
+		v.AuxInt = log2(int64(uint32(c)))
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueMIPS_OpSelect1_10(v *Value) bool {
+	// match: (Select1 (MULTU (MOVWconst [c]) (MOVWconst [d])))
 	// cond:
 	// result: (MOVWconst [int64(int32(uint32(c)*uint32(d)))])
 	for {
@@ -8185,6 +8694,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSMULTU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8199,7 +8709,30 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		v.AuxInt = int64(int32(uint32(c) * uint32(d)))
 		return true
 	}
-	// match: (Select1 (DIV  (MOVWconst [c]) (MOVWconst [d])))
+	// match: (Select1 (MULTU (MOVWconst [d]) (MOVWconst [c])))
+	// cond:
+	// result: (MOVWconst [int64(int32(uint32(c)*uint32(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPSMULTU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPSMOVWconst {
+			break
+		}
+		d := v_0_0.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPSMOVWconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		v.reset(OpMIPSMOVWconst)
+		v.AuxInt = int64(int32(uint32(c) * uint32(d)))
+		return true
+	}
+	// match: (Select1 (DIV (MOVWconst [c]) (MOVWconst [d])))
 	// cond:
 	// result: (MOVWconst [int64(int32(c)/int32(d))])
 	for {
@@ -8207,6 +8740,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSDIV {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8229,6 +8763,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPSDIVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPSMOVWconst {
 			break
@@ -8245,9 +8780,7 @@ func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -8258,9 +8791,7 @@ func rewriteValueMIPS_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSignExt8to16_0(v *Value) bool {
 	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -8271,9 +8802,7 @@ func rewriteValueMIPS_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSignExt8to32_0(v *Value) bool {
 	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -8284,9 +8813,7 @@ func rewriteValueMIPS_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSignmask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSignmask_0(v *Value) bool {
 	// match: (Signmask x)
 	// cond:
 	// result: (SRAconst x [31])
@@ -8298,27 +8825,24 @@ func rewriteValueMIPS_OpSignmask(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Slicemask x)
+	// match: (Slicemask <t> x)
 	// cond:
-	// result: (NEG (SGT x (MOVWconst [0])))
+	// result: (SRAconst (NEG <t> x) [31])
 	for {
+		t := v.Type
 		x := v.Args[0]
-		v.reset(OpMIPSNEG)
-		v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+		v.reset(OpMIPSSRAconst)
+		v.AuxInt = 31
+		v0 := b.NewValue0(v.Pos, OpMIPSNEG, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
-		v1.AuxInt = 0
-		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (SQRTD x)
@@ -8329,9 +8853,7 @@ func rewriteValueMIPS_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -8346,71 +8868,53 @@ func rewriteValueMIPS_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [1] ptr val mem)
-	// cond:
+func rewriteValueMIPS_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		v.reset(OpMIPSMOVBstore)
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Store [2] ptr val mem)
-	// cond:
-	// result: (MOVHstore ptr val mem)
-	for {
-		if v.AuxInt != 2 {
+		if !(t.(*types.Type).Size() == 1) {
 			break
 		}
-		ptr := v.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpMIPSMOVHstore)
+		v.reset(OpMIPSMOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: !is32BitFloat(val.Type)
-	// result: (MOVWstore ptr val mem)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
+	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 2) {
 			break
 		}
-		v.reset(OpMIPSMOVWstore)
+		v.reset(OpMIPSMOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: !is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
@@ -8419,17 +8923,16 @@ func rewriteValueMIPS_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (MOVFstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPSMOVFstore)
@@ -8438,17 +8941,16 @@ func rewriteValueMIPS_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPSMOVDstore)
@@ -8459,13 +8961,12 @@ func rewriteValueMIPS_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSub16_0(v *Value) bool {
 	// match: (Sub16 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUB)
@@ -8474,13 +8975,12 @@ func rewriteValueMIPS_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSub32_0(v *Value) bool {
 	// match: (Sub32 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUB)
@@ -8489,13 +8989,12 @@ func rewriteValueMIPS_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (SUBF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUBF)
@@ -8504,7 +9003,7 @@ func rewriteValueMIPS_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSub32withcarry(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpSub32withcarry_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Sub32withcarry <t> x y c)
@@ -8512,11 +9011,12 @@ func rewriteValueMIPS_OpSub32withcarry(v *Value, config *Config) bool {
 	// result: (SUB (SUB <t> x y) c)
 	for {
 		t := v.Type
+		_ = v.Args[2]
 		x := v.Args[0]
 		y := v.Args[1]
 		c := v.Args[2]
 		v.reset(OpMIPSSUB)
-		v0 := b.NewValue0(v.Line, OpMIPSSUB, t)
+		v0 := b.NewValue0(v.Pos, OpMIPSSUB, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -8524,13 +9024,12 @@ func rewriteValueMIPS_OpSub32withcarry(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (SUBD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUBD)
@@ -8539,13 +9038,12 @@ func rewriteValueMIPS_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSub8_0(v *Value) bool {
 	// match: (Sub8 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUB)
@@ -8554,13 +9052,12 @@ func rewriteValueMIPS_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSSUB)
@@ -8569,9 +9066,7 @@ func rewriteValueMIPS_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpTrunc16to8_0(v *Value) bool {
 	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
@@ -8583,9 +9078,7 @@ func rewriteValueMIPS_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -8597,9 +9090,7 @@ func rewriteValueMIPS_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpTrunc32to8_0(v *Value) bool {
 	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
@@ -8611,13 +9102,12 @@ func rewriteValueMIPS_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXOR)
@@ -8626,13 +9116,12 @@ func rewriteValueMIPS_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXOR)
@@ -8641,13 +9130,12 @@ func rewriteValueMIPS_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpXor8_0(v *Value) bool {
 	// match: (Xor8 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPSXOR)
@@ -8656,161 +9144,175 @@ func rewriteValueMIPS_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] ptr mem)
+	// cond:
 	// result: (MOVBstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPSMOVBstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [2] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] ptr mem)
+	// cond:
 	// result: (MOVBstore [1] ptr (MOVWconst [0]) 		(MOVBstore [0] ptr (MOVWconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 1
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore ptr (MOVWconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] ptr (MOVWconst [0]) 		(MOVHstore [0] ptr (MOVWconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] ptr mem)
+	// cond:
 	// result: (MOVBstore [3] ptr (MOVWconst [0]) 		(MOVBstore [2] ptr (MOVWconst [0]) 			(MOVBstore [1] ptr (MOVWconst [0]) 				(MOVBstore [0] ptr (MOVWconst [0]) mem))))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 3
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v5.AuxInt = 0
 		v5.AddArg(ptr)
-		v6 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v6.AuxInt = 0
 		v5.AddArg(v6)
 		v5.AddArg(mem)
@@ -8819,32 +9321,32 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Zero [3] ptr mem)
+	// cond:
 	// result: (MOVBstore [2] ptr (MOVWconst [0]) 		(MOVBstore [1] ptr (MOVWconst [0]) 			(MOVBstore [0] ptr (MOVWconst [0]) mem)))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPSMOVBstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVBstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -8852,32 +9354,36 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [6] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [4] ptr (MOVWconst [0]) 		(MOVHstore [2] ptr (MOVWconst [0]) 			(MOVHstore [0] ptr (MOVWconst [0]) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVHstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVHstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -8885,58 +9391,75 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [8] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [4] ptr (MOVWconst [0]) 			(MOVWstore [0] ptr (MOVWconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0
+	return false
+}
+func rewriteValueMIPS_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [12] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [8] ptr (MOVWconst [0]) 		(MOVWstore [4] ptr (MOVWconst [0]) 			(MOVWstore [0] ptr (MOVWconst [0]) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 12 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 8
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -8944,38 +9467,42 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [16] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [12] ptr (MOVWconst [0]) 		(MOVWstore [8] ptr (MOVWconst [0]) 			(MOVWstore [4] ptr (MOVWconst [0]) 				(MOVWstore [0] ptr (MOVWconst [0]) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPSMOVWstore)
 		v.AuxInt = 12
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v3.AuxInt = 4
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPSMOVWstore, types.TypeMem)
 		v5.AuxInt = 0
 		v5.AddArg(ptr)
-		v6 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v6.AuxInt = 0
 		v5.AddArg(v6)
 		v5.AddArg(mem)
@@ -8984,21 +9511,23 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: (SizeAndAlign(s).Size() > 16  || SizeAndAlign(s).Align()%4 != 0)
-	// result: (LoweredZero [SizeAndAlign(s).Align()] 		ptr 		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// match: (Zero [s] {t} ptr mem)
+	// cond: (s > 16  || t.(*types.Type).Alignment()%4 != 0)
+	// result: (LoweredZero [t.(*types.Type).Alignment()] 		ptr 		(ADDconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0) {
+		if !(s > 16 || t.(*types.Type).Alignment()%4 != 0) {
 			break
 		}
 		v.reset(OpMIPSLoweredZero)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPSADDconst, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpMIPSADDconst, ptr.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -9006,9 +9535,7 @@ func rewriteValueMIPS_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -9019,9 +9546,7 @@ func rewriteValueMIPS_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpZeroExt8to16_0(v *Value) bool {
 	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -9032,9 +9557,7 @@ func rewriteValueMIPS_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS_OpZeroExt8to32_0(v *Value) bool {
 	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -9045,25 +9568,33 @@ func rewriteValueMIPS_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS_OpZeromask(v *Value, config *Config) bool {
+func rewriteValueMIPS_OpZeromask_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Zeromask x)
 	// cond:
 	// result: (NEG (SGTU x (MOVWconst [0])))
 	for {
 		x := v.Args[0]
 		v.reset(OpMIPSNEG)
-		v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPSSGTU, typ.Bool)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpMIPSMOVWconst, typ.UInt32)
 		v1.AuxInt = 0
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteBlockMIPS(b *Block, config *Config) bool {
+func rewriteBlockMIPS(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockMIPSEQ:
 		// match: (EQ (FPFlagTrue cmp) yes no)
@@ -9075,12 +9606,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSFPF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FPFlagFalse cmp) yes no)
@@ -9092,12 +9619,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSFPT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGT _ _)) yes no)
@@ -9115,12 +9638,9 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
@@ -9138,12 +9658,9 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTU {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
@@ -9161,12 +9678,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTUconst _)) yes no)
@@ -9184,12 +9697,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTUconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTzero _)) yes no)
@@ -9207,12 +9716,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTzero {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTUzero _)) yes no)
@@ -9230,12 +9735,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTUzero {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTUconst [1] x) yes no)
@@ -9250,12 +9751,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTUzero x) yes no)
@@ -9267,12 +9764,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTconst [0] x) yes no)
@@ -9287,12 +9780,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSGEZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTzero x) yes no)
@@ -9304,15 +9793,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSLEZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (EQ  (MOVWconst [0]) yes no)
+		// match: (EQ (MOVWconst [0]) yes no)
 		// cond:
 		// result: (First nil yes no)
 		for {
@@ -9323,15 +9808,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (EQ  (MOVWconst [c]) yes no)
+		// match: (EQ (MOVWconst [c]) yes no)
 		// cond: c != 0
 		// result: (First nil no yes)
 		for {
@@ -9340,16 +9821,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				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
 		}
 	case BlockMIPSGEZ:
@@ -9362,15 +9839,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) >= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GEZ (MOVWconst [c]) yes no)
@@ -9382,16 +9855,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) < 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockMIPSGTZ:
@@ -9404,15 +9873,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) > 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GTZ (MOVWconst [c]) yes no)
@@ -9424,16 +9889,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) <= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockIf:
@@ -9444,12 +9905,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(cond)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockMIPSLEZ:
@@ -9462,15 +9919,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) <= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LEZ (MOVWconst [c]) yes no)
@@ -9482,16 +9935,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) > 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockMIPSLTZ:
@@ -9504,15 +9953,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) < 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LTZ (MOVWconst [c]) yes no)
@@ -9524,16 +9969,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(int32(c) >= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockMIPSNE:
@@ -9546,12 +9987,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSFPT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FPFlagFalse cmp) yes no)
@@ -9563,12 +10000,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSFPF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGT _ _)) yes no)
@@ -9586,12 +10019,9 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
@@ -9609,12 +10039,9 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTU {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
@@ -9632,12 +10059,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTUconst _)) yes no)
@@ -9655,12 +10078,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTUconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTzero _)) yes no)
@@ -9678,12 +10097,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTzero {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTUzero _)) yes no)
@@ -9701,12 +10116,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPSSGTUzero {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTUconst [1] x) yes no)
@@ -9721,12 +10132,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSEQ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTUzero x) yes no)
@@ -9738,12 +10145,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSNE
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTconst [0] x) yes no)
@@ -9758,12 +10161,8 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSLTZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTzero x) yes no)
@@ -9775,15 +10174,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPSGTZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE  (MOVWconst [0]) yes no)
+		// match: (NE (MOVWconst [0]) yes no)
 		// cond:
 		// result: (First nil no yes)
 		for {
@@ -9794,16 +10189,12 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (NE  (MOVWconst [c]) yes no)
+		// match: (NE (MOVWconst [c]) yes no)
 		// cond: c != 0
 		// result: (First nil yes no)
 		for {
@@ -9812,15 +10203,11 @@ func rewriteBlockMIPS(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c != 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index 76c6412..82919a1 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -1,585 +1,583 @@
-// autogenerated from gen/MIPS64.rules: do not edit!
+// Code generated from gen/MIPS64.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueMIPS64(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueMIPS64(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
-		return rewriteValueMIPS64_OpAdd16(v, config)
+		return rewriteValueMIPS64_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueMIPS64_OpAdd32(v, config)
+		return rewriteValueMIPS64_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueMIPS64_OpAdd32F(v, config)
+		return rewriteValueMIPS64_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValueMIPS64_OpAdd64(v, config)
+		return rewriteValueMIPS64_OpAdd64_0(v)
 	case OpAdd64F:
-		return rewriteValueMIPS64_OpAdd64F(v, config)
+		return rewriteValueMIPS64_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueMIPS64_OpAdd8(v, config)
+		return rewriteValueMIPS64_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueMIPS64_OpAddPtr(v, config)
+		return rewriteValueMIPS64_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueMIPS64_OpAddr(v, config)
+		return rewriteValueMIPS64_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueMIPS64_OpAnd16(v, config)
+		return rewriteValueMIPS64_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueMIPS64_OpAnd32(v, config)
+		return rewriteValueMIPS64_OpAnd32_0(v)
 	case OpAnd64:
-		return rewriteValueMIPS64_OpAnd64(v, config)
+		return rewriteValueMIPS64_OpAnd64_0(v)
 	case OpAnd8:
-		return rewriteValueMIPS64_OpAnd8(v, config)
+		return rewriteValueMIPS64_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueMIPS64_OpAndB(v, config)
+		return rewriteValueMIPS64_OpAndB_0(v)
 	case OpAvg64u:
-		return rewriteValueMIPS64_OpAvg64u(v, config)
+		return rewriteValueMIPS64_OpAvg64u_0(v)
 	case OpClosureCall:
-		return rewriteValueMIPS64_OpClosureCall(v, config)
+		return rewriteValueMIPS64_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueMIPS64_OpCom16(v, config)
+		return rewriteValueMIPS64_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueMIPS64_OpCom32(v, config)
+		return rewriteValueMIPS64_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValueMIPS64_OpCom64(v, config)
+		return rewriteValueMIPS64_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValueMIPS64_OpCom8(v, config)
+		return rewriteValueMIPS64_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueMIPS64_OpConst16(v, config)
+		return rewriteValueMIPS64_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueMIPS64_OpConst32(v, config)
+		return rewriteValueMIPS64_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueMIPS64_OpConst32F(v, config)
+		return rewriteValueMIPS64_OpConst32F_0(v)
 	case OpConst64:
-		return rewriteValueMIPS64_OpConst64(v, config)
+		return rewriteValueMIPS64_OpConst64_0(v)
 	case OpConst64F:
-		return rewriteValueMIPS64_OpConst64F(v, config)
+		return rewriteValueMIPS64_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueMIPS64_OpConst8(v, config)
+		return rewriteValueMIPS64_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueMIPS64_OpConstBool(v, config)
+		return rewriteValueMIPS64_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueMIPS64_OpConstNil(v, config)
+		return rewriteValueMIPS64_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueMIPS64_OpConvert(v, config)
+		return rewriteValueMIPS64_OpConvert_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueMIPS64_OpCvt32Fto32(v, config)
+		return rewriteValueMIPS64_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64:
-		return rewriteValueMIPS64_OpCvt32Fto64(v, config)
+		return rewriteValueMIPS64_OpCvt32Fto64_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueMIPS64_OpCvt32Fto64F(v, config)
+		return rewriteValueMIPS64_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueMIPS64_OpCvt32to32F(v, config)
+		return rewriteValueMIPS64_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueMIPS64_OpCvt32to64F(v, config)
+		return rewriteValueMIPS64_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueMIPS64_OpCvt64Fto32(v, config)
+		return rewriteValueMIPS64_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueMIPS64_OpCvt64Fto32F(v, config)
+		return rewriteValueMIPS64_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto64:
-		return rewriteValueMIPS64_OpCvt64Fto64(v, config)
+		return rewriteValueMIPS64_OpCvt64Fto64_0(v)
 	case OpCvt64to32F:
-		return rewriteValueMIPS64_OpCvt64to32F(v, config)
+		return rewriteValueMIPS64_OpCvt64to32F_0(v)
 	case OpCvt64to64F:
-		return rewriteValueMIPS64_OpCvt64to64F(v, config)
-	case OpDeferCall:
-		return rewriteValueMIPS64_OpDeferCall(v, config)
+		return rewriteValueMIPS64_OpCvt64to64F_0(v)
 	case OpDiv16:
-		return rewriteValueMIPS64_OpDiv16(v, config)
+		return rewriteValueMIPS64_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueMIPS64_OpDiv16u(v, config)
+		return rewriteValueMIPS64_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueMIPS64_OpDiv32(v, config)
+		return rewriteValueMIPS64_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueMIPS64_OpDiv32F(v, config)
+		return rewriteValueMIPS64_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueMIPS64_OpDiv32u(v, config)
+		return rewriteValueMIPS64_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValueMIPS64_OpDiv64(v, config)
+		return rewriteValueMIPS64_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValueMIPS64_OpDiv64F(v, config)
+		return rewriteValueMIPS64_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValueMIPS64_OpDiv64u(v, config)
+		return rewriteValueMIPS64_OpDiv64u_0(v)
 	case OpDiv8:
-		return rewriteValueMIPS64_OpDiv8(v, config)
+		return rewriteValueMIPS64_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueMIPS64_OpDiv8u(v, config)
+		return rewriteValueMIPS64_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueMIPS64_OpEq16(v, config)
+		return rewriteValueMIPS64_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueMIPS64_OpEq32(v, config)
+		return rewriteValueMIPS64_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueMIPS64_OpEq32F(v, config)
+		return rewriteValueMIPS64_OpEq32F_0(v)
 	case OpEq64:
-		return rewriteValueMIPS64_OpEq64(v, config)
+		return rewriteValueMIPS64_OpEq64_0(v)
 	case OpEq64F:
-		return rewriteValueMIPS64_OpEq64F(v, config)
+		return rewriteValueMIPS64_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueMIPS64_OpEq8(v, config)
+		return rewriteValueMIPS64_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueMIPS64_OpEqB(v, config)
+		return rewriteValueMIPS64_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueMIPS64_OpEqPtr(v, config)
+		return rewriteValueMIPS64_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueMIPS64_OpGeq16(v, config)
+		return rewriteValueMIPS64_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueMIPS64_OpGeq16U(v, config)
+		return rewriteValueMIPS64_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueMIPS64_OpGeq32(v, config)
+		return rewriteValueMIPS64_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueMIPS64_OpGeq32F(v, config)
+		return rewriteValueMIPS64_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueMIPS64_OpGeq32U(v, config)
+		return rewriteValueMIPS64_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValueMIPS64_OpGeq64(v, config)
+		return rewriteValueMIPS64_OpGeq64_0(v)
 	case OpGeq64F:
-		return rewriteValueMIPS64_OpGeq64F(v, config)
+		return rewriteValueMIPS64_OpGeq64F_0(v)
 	case OpGeq64U:
-		return rewriteValueMIPS64_OpGeq64U(v, config)
+		return rewriteValueMIPS64_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValueMIPS64_OpGeq8(v, config)
+		return rewriteValueMIPS64_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueMIPS64_OpGeq8U(v, config)
+		return rewriteValueMIPS64_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueMIPS64_OpGetClosurePtr(v, config)
-	case OpGoCall:
-		return rewriteValueMIPS64_OpGoCall(v, config)
+		return rewriteValueMIPS64_OpGetClosurePtr_0(v)
 	case OpGreater16:
-		return rewriteValueMIPS64_OpGreater16(v, config)
+		return rewriteValueMIPS64_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueMIPS64_OpGreater16U(v, config)
+		return rewriteValueMIPS64_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueMIPS64_OpGreater32(v, config)
+		return rewriteValueMIPS64_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueMIPS64_OpGreater32F(v, config)
+		return rewriteValueMIPS64_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueMIPS64_OpGreater32U(v, config)
+		return rewriteValueMIPS64_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValueMIPS64_OpGreater64(v, config)
+		return rewriteValueMIPS64_OpGreater64_0(v)
 	case OpGreater64F:
-		return rewriteValueMIPS64_OpGreater64F(v, config)
+		return rewriteValueMIPS64_OpGreater64F_0(v)
 	case OpGreater64U:
-		return rewriteValueMIPS64_OpGreater64U(v, config)
+		return rewriteValueMIPS64_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValueMIPS64_OpGreater8(v, config)
+		return rewriteValueMIPS64_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueMIPS64_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueMIPS64_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueMIPS64_OpHmul16u(v, config)
+		return rewriteValueMIPS64_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueMIPS64_OpHmul32(v, config)
+		return rewriteValueMIPS64_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueMIPS64_OpHmul32u(v, config)
+		return rewriteValueMIPS64_OpHmul32u_0(v)
 	case OpHmul64:
-		return rewriteValueMIPS64_OpHmul64(v, config)
+		return rewriteValueMIPS64_OpHmul64_0(v)
 	case OpHmul64u:
-		return rewriteValueMIPS64_OpHmul64u(v, config)
-	case OpHmul8:
-		return rewriteValueMIPS64_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueMIPS64_OpHmul8u(v, config)
+		return rewriteValueMIPS64_OpHmul64u_0(v)
 	case OpInterCall:
-		return rewriteValueMIPS64_OpInterCall(v, config)
+		return rewriteValueMIPS64_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueMIPS64_OpIsInBounds(v, config)
+		return rewriteValueMIPS64_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueMIPS64_OpIsNonNil(v, config)
+		return rewriteValueMIPS64_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueMIPS64_OpIsSliceInBounds(v, config)
+		return rewriteValueMIPS64_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueMIPS64_OpLeq16(v, config)
+		return rewriteValueMIPS64_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueMIPS64_OpLeq16U(v, config)
+		return rewriteValueMIPS64_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueMIPS64_OpLeq32(v, config)
+		return rewriteValueMIPS64_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueMIPS64_OpLeq32F(v, config)
+		return rewriteValueMIPS64_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueMIPS64_OpLeq32U(v, config)
+		return rewriteValueMIPS64_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValueMIPS64_OpLeq64(v, config)
+		return rewriteValueMIPS64_OpLeq64_0(v)
 	case OpLeq64F:
-		return rewriteValueMIPS64_OpLeq64F(v, config)
+		return rewriteValueMIPS64_OpLeq64F_0(v)
 	case OpLeq64U:
-		return rewriteValueMIPS64_OpLeq64U(v, config)
+		return rewriteValueMIPS64_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValueMIPS64_OpLeq8(v, config)
+		return rewriteValueMIPS64_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueMIPS64_OpLeq8U(v, config)
+		return rewriteValueMIPS64_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueMIPS64_OpLess16(v, config)
+		return rewriteValueMIPS64_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueMIPS64_OpLess16U(v, config)
+		return rewriteValueMIPS64_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueMIPS64_OpLess32(v, config)
+		return rewriteValueMIPS64_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueMIPS64_OpLess32F(v, config)
+		return rewriteValueMIPS64_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueMIPS64_OpLess32U(v, config)
+		return rewriteValueMIPS64_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValueMIPS64_OpLess64(v, config)
+		return rewriteValueMIPS64_OpLess64_0(v)
 	case OpLess64F:
-		return rewriteValueMIPS64_OpLess64F(v, config)
+		return rewriteValueMIPS64_OpLess64F_0(v)
 	case OpLess64U:
-		return rewriteValueMIPS64_OpLess64U(v, config)
+		return rewriteValueMIPS64_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValueMIPS64_OpLess8(v, config)
+		return rewriteValueMIPS64_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueMIPS64_OpLess8U(v, config)
+		return rewriteValueMIPS64_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValueMIPS64_OpLoad(v, config)
+		return rewriteValueMIPS64_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueMIPS64_OpLsh16x16(v, config)
+		return rewriteValueMIPS64_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueMIPS64_OpLsh16x32(v, config)
+		return rewriteValueMIPS64_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueMIPS64_OpLsh16x64(v, config)
+		return rewriteValueMIPS64_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueMIPS64_OpLsh16x8(v, config)
+		return rewriteValueMIPS64_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueMIPS64_OpLsh32x16(v, config)
+		return rewriteValueMIPS64_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueMIPS64_OpLsh32x32(v, config)
+		return rewriteValueMIPS64_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueMIPS64_OpLsh32x64(v, config)
+		return rewriteValueMIPS64_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueMIPS64_OpLsh32x8(v, config)
+		return rewriteValueMIPS64_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValueMIPS64_OpLsh64x16(v, config)
+		return rewriteValueMIPS64_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValueMIPS64_OpLsh64x32(v, config)
+		return rewriteValueMIPS64_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValueMIPS64_OpLsh64x64(v, config)
+		return rewriteValueMIPS64_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValueMIPS64_OpLsh64x8(v, config)
+		return rewriteValueMIPS64_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueMIPS64_OpLsh8x16(v, config)
+		return rewriteValueMIPS64_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueMIPS64_OpLsh8x32(v, config)
+		return rewriteValueMIPS64_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueMIPS64_OpLsh8x64(v, config)
+		return rewriteValueMIPS64_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueMIPS64_OpLsh8x8(v, config)
+		return rewriteValueMIPS64_OpLsh8x8_0(v)
 	case OpMIPS64ADDV:
-		return rewriteValueMIPS64_OpMIPS64ADDV(v, config)
+		return rewriteValueMIPS64_OpMIPS64ADDV_0(v)
 	case OpMIPS64ADDVconst:
-		return rewriteValueMIPS64_OpMIPS64ADDVconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64ADDVconst_0(v)
 	case OpMIPS64AND:
-		return rewriteValueMIPS64_OpMIPS64AND(v, config)
+		return rewriteValueMIPS64_OpMIPS64AND_0(v)
 	case OpMIPS64ANDconst:
-		return rewriteValueMIPS64_OpMIPS64ANDconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64ANDconst_0(v)
 	case OpMIPS64MOVBUload:
-		return rewriteValueMIPS64_OpMIPS64MOVBUload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBUload_0(v)
 	case OpMIPS64MOVBUreg:
-		return rewriteValueMIPS64_OpMIPS64MOVBUreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBUreg_0(v)
 	case OpMIPS64MOVBload:
-		return rewriteValueMIPS64_OpMIPS64MOVBload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBload_0(v)
 	case OpMIPS64MOVBreg:
-		return rewriteValueMIPS64_OpMIPS64MOVBreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBreg_0(v)
 	case OpMIPS64MOVBstore:
-		return rewriteValueMIPS64_OpMIPS64MOVBstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBstore_0(v)
 	case OpMIPS64MOVBstorezero:
-		return rewriteValueMIPS64_OpMIPS64MOVBstorezero(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVBstorezero_0(v)
 	case OpMIPS64MOVDload:
-		return rewriteValueMIPS64_OpMIPS64MOVDload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVDload_0(v)
 	case OpMIPS64MOVDstore:
-		return rewriteValueMIPS64_OpMIPS64MOVDstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVDstore_0(v)
 	case OpMIPS64MOVFload:
-		return rewriteValueMIPS64_OpMIPS64MOVFload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVFload_0(v)
 	case OpMIPS64MOVFstore:
-		return rewriteValueMIPS64_OpMIPS64MOVFstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVFstore_0(v)
 	case OpMIPS64MOVHUload:
-		return rewriteValueMIPS64_OpMIPS64MOVHUload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHUload_0(v)
 	case OpMIPS64MOVHUreg:
-		return rewriteValueMIPS64_OpMIPS64MOVHUreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHUreg_0(v)
 	case OpMIPS64MOVHload:
-		return rewriteValueMIPS64_OpMIPS64MOVHload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHload_0(v)
 	case OpMIPS64MOVHreg:
-		return rewriteValueMIPS64_OpMIPS64MOVHreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHreg_0(v)
 	case OpMIPS64MOVHstore:
-		return rewriteValueMIPS64_OpMIPS64MOVHstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHstore_0(v)
 	case OpMIPS64MOVHstorezero:
-		return rewriteValueMIPS64_OpMIPS64MOVHstorezero(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVHstorezero_0(v)
 	case OpMIPS64MOVVload:
-		return rewriteValueMIPS64_OpMIPS64MOVVload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVVload_0(v)
 	case OpMIPS64MOVVreg:
-		return rewriteValueMIPS64_OpMIPS64MOVVreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVVreg_0(v)
 	case OpMIPS64MOVVstore:
-		return rewriteValueMIPS64_OpMIPS64MOVVstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVVstore_0(v)
 	case OpMIPS64MOVVstorezero:
-		return rewriteValueMIPS64_OpMIPS64MOVVstorezero(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVVstorezero_0(v)
 	case OpMIPS64MOVWUload:
-		return rewriteValueMIPS64_OpMIPS64MOVWUload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWUload_0(v)
 	case OpMIPS64MOVWUreg:
-		return rewriteValueMIPS64_OpMIPS64MOVWUreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWUreg_0(v)
 	case OpMIPS64MOVWload:
-		return rewriteValueMIPS64_OpMIPS64MOVWload(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWload_0(v)
 	case OpMIPS64MOVWreg:
-		return rewriteValueMIPS64_OpMIPS64MOVWreg(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWreg_0(v) || rewriteValueMIPS64_OpMIPS64MOVWreg_10(v)
 	case OpMIPS64MOVWstore:
-		return rewriteValueMIPS64_OpMIPS64MOVWstore(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWstore_0(v)
 	case OpMIPS64MOVWstorezero:
-		return rewriteValueMIPS64_OpMIPS64MOVWstorezero(v, config)
+		return rewriteValueMIPS64_OpMIPS64MOVWstorezero_0(v)
 	case OpMIPS64NEGV:
-		return rewriteValueMIPS64_OpMIPS64NEGV(v, config)
+		return rewriteValueMIPS64_OpMIPS64NEGV_0(v)
 	case OpMIPS64NOR:
-		return rewriteValueMIPS64_OpMIPS64NOR(v, config)
+		return rewriteValueMIPS64_OpMIPS64NOR_0(v)
 	case OpMIPS64NORconst:
-		return rewriteValueMIPS64_OpMIPS64NORconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64NORconst_0(v)
 	case OpMIPS64OR:
-		return rewriteValueMIPS64_OpMIPS64OR(v, config)
+		return rewriteValueMIPS64_OpMIPS64OR_0(v)
 	case OpMIPS64ORconst:
-		return rewriteValueMIPS64_OpMIPS64ORconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64ORconst_0(v)
 	case OpMIPS64SGT:
-		return rewriteValueMIPS64_OpMIPS64SGT(v, config)
+		return rewriteValueMIPS64_OpMIPS64SGT_0(v)
 	case OpMIPS64SGTU:
-		return rewriteValueMIPS64_OpMIPS64SGTU(v, config)
+		return rewriteValueMIPS64_OpMIPS64SGTU_0(v)
 	case OpMIPS64SGTUconst:
-		return rewriteValueMIPS64_OpMIPS64SGTUconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SGTUconst_0(v)
 	case OpMIPS64SGTconst:
-		return rewriteValueMIPS64_OpMIPS64SGTconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SGTconst_0(v) || rewriteValueMIPS64_OpMIPS64SGTconst_10(v)
 	case OpMIPS64SLLV:
-		return rewriteValueMIPS64_OpMIPS64SLLV(v, config)
+		return rewriteValueMIPS64_OpMIPS64SLLV_0(v)
 	case OpMIPS64SLLVconst:
-		return rewriteValueMIPS64_OpMIPS64SLLVconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SLLVconst_0(v)
 	case OpMIPS64SRAV:
-		return rewriteValueMIPS64_OpMIPS64SRAV(v, config)
+		return rewriteValueMIPS64_OpMIPS64SRAV_0(v)
 	case OpMIPS64SRAVconst:
-		return rewriteValueMIPS64_OpMIPS64SRAVconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SRAVconst_0(v)
 	case OpMIPS64SRLV:
-		return rewriteValueMIPS64_OpMIPS64SRLV(v, config)
+		return rewriteValueMIPS64_OpMIPS64SRLV_0(v)
 	case OpMIPS64SRLVconst:
-		return rewriteValueMIPS64_OpMIPS64SRLVconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SRLVconst_0(v)
 	case OpMIPS64SUBV:
-		return rewriteValueMIPS64_OpMIPS64SUBV(v, config)
+		return rewriteValueMIPS64_OpMIPS64SUBV_0(v)
 	case OpMIPS64SUBVconst:
-		return rewriteValueMIPS64_OpMIPS64SUBVconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64SUBVconst_0(v)
 	case OpMIPS64XOR:
-		return rewriteValueMIPS64_OpMIPS64XOR(v, config)
+		return rewriteValueMIPS64_OpMIPS64XOR_0(v)
 	case OpMIPS64XORconst:
-		return rewriteValueMIPS64_OpMIPS64XORconst(v, config)
+		return rewriteValueMIPS64_OpMIPS64XORconst_0(v)
 	case OpMod16:
-		return rewriteValueMIPS64_OpMod16(v, config)
+		return rewriteValueMIPS64_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueMIPS64_OpMod16u(v, config)
+		return rewriteValueMIPS64_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueMIPS64_OpMod32(v, config)
+		return rewriteValueMIPS64_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueMIPS64_OpMod32u(v, config)
+		return rewriteValueMIPS64_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValueMIPS64_OpMod64(v, config)
+		return rewriteValueMIPS64_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValueMIPS64_OpMod64u(v, config)
+		return rewriteValueMIPS64_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValueMIPS64_OpMod8(v, config)
+		return rewriteValueMIPS64_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueMIPS64_OpMod8u(v, config)
+		return rewriteValueMIPS64_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueMIPS64_OpMove(v, config)
+		return rewriteValueMIPS64_OpMove_0(v) || rewriteValueMIPS64_OpMove_10(v)
 	case OpMul16:
-		return rewriteValueMIPS64_OpMul16(v, config)
+		return rewriteValueMIPS64_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueMIPS64_OpMul32(v, config)
+		return rewriteValueMIPS64_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueMIPS64_OpMul32F(v, config)
+		return rewriteValueMIPS64_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValueMIPS64_OpMul64(v, config)
+		return rewriteValueMIPS64_OpMul64_0(v)
 	case OpMul64F:
-		return rewriteValueMIPS64_OpMul64F(v, config)
+		return rewriteValueMIPS64_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValueMIPS64_OpMul8(v, config)
+		return rewriteValueMIPS64_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueMIPS64_OpNeg16(v, config)
+		return rewriteValueMIPS64_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueMIPS64_OpNeg32(v, config)
+		return rewriteValueMIPS64_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueMIPS64_OpNeg32F(v, config)
+		return rewriteValueMIPS64_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValueMIPS64_OpNeg64(v, config)
+		return rewriteValueMIPS64_OpNeg64_0(v)
 	case OpNeg64F:
-		return rewriteValueMIPS64_OpNeg64F(v, config)
+		return rewriteValueMIPS64_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueMIPS64_OpNeg8(v, config)
+		return rewriteValueMIPS64_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueMIPS64_OpNeq16(v, config)
+		return rewriteValueMIPS64_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueMIPS64_OpNeq32(v, config)
+		return rewriteValueMIPS64_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueMIPS64_OpNeq32F(v, config)
+		return rewriteValueMIPS64_OpNeq32F_0(v)
 	case OpNeq64:
-		return rewriteValueMIPS64_OpNeq64(v, config)
+		return rewriteValueMIPS64_OpNeq64_0(v)
 	case OpNeq64F:
-		return rewriteValueMIPS64_OpNeq64F(v, config)
+		return rewriteValueMIPS64_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueMIPS64_OpNeq8(v, config)
+		return rewriteValueMIPS64_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueMIPS64_OpNeqB(v, config)
+		return rewriteValueMIPS64_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueMIPS64_OpNeqPtr(v, config)
+		return rewriteValueMIPS64_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueMIPS64_OpNilCheck(v, config)
+		return rewriteValueMIPS64_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueMIPS64_OpNot(v, config)
+		return rewriteValueMIPS64_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueMIPS64_OpOffPtr(v, config)
+		return rewriteValueMIPS64_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueMIPS64_OpOr16(v, config)
+		return rewriteValueMIPS64_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueMIPS64_OpOr32(v, config)
+		return rewriteValueMIPS64_OpOr32_0(v)
 	case OpOr64:
-		return rewriteValueMIPS64_OpOr64(v, config)
+		return rewriteValueMIPS64_OpOr64_0(v)
 	case OpOr8:
-		return rewriteValueMIPS64_OpOr8(v, config)
+		return rewriteValueMIPS64_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueMIPS64_OpOrB(v, config)
+		return rewriteValueMIPS64_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValueMIPS64_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueMIPS64_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueMIPS64_OpRsh16Ux16(v, config)
+		return rewriteValueMIPS64_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueMIPS64_OpRsh16Ux32(v, config)
+		return rewriteValueMIPS64_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueMIPS64_OpRsh16Ux64(v, config)
+		return rewriteValueMIPS64_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueMIPS64_OpRsh16Ux8(v, config)
+		return rewriteValueMIPS64_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueMIPS64_OpRsh16x16(v, config)
+		return rewriteValueMIPS64_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueMIPS64_OpRsh16x32(v, config)
+		return rewriteValueMIPS64_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueMIPS64_OpRsh16x64(v, config)
+		return rewriteValueMIPS64_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueMIPS64_OpRsh16x8(v, config)
+		return rewriteValueMIPS64_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueMIPS64_OpRsh32Ux16(v, config)
+		return rewriteValueMIPS64_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueMIPS64_OpRsh32Ux32(v, config)
+		return rewriteValueMIPS64_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueMIPS64_OpRsh32Ux64(v, config)
+		return rewriteValueMIPS64_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueMIPS64_OpRsh32Ux8(v, config)
+		return rewriteValueMIPS64_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueMIPS64_OpRsh32x16(v, config)
+		return rewriteValueMIPS64_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueMIPS64_OpRsh32x32(v, config)
+		return rewriteValueMIPS64_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueMIPS64_OpRsh32x64(v, config)
+		return rewriteValueMIPS64_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueMIPS64_OpRsh32x8(v, config)
+		return rewriteValueMIPS64_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValueMIPS64_OpRsh64Ux16(v, config)
+		return rewriteValueMIPS64_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValueMIPS64_OpRsh64Ux32(v, config)
+		return rewriteValueMIPS64_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValueMIPS64_OpRsh64Ux64(v, config)
+		return rewriteValueMIPS64_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValueMIPS64_OpRsh64Ux8(v, config)
+		return rewriteValueMIPS64_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValueMIPS64_OpRsh64x16(v, config)
+		return rewriteValueMIPS64_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValueMIPS64_OpRsh64x32(v, config)
+		return rewriteValueMIPS64_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValueMIPS64_OpRsh64x64(v, config)
+		return rewriteValueMIPS64_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValueMIPS64_OpRsh64x8(v, config)
+		return rewriteValueMIPS64_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueMIPS64_OpRsh8Ux16(v, config)
+		return rewriteValueMIPS64_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueMIPS64_OpRsh8Ux32(v, config)
+		return rewriteValueMIPS64_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueMIPS64_OpRsh8Ux64(v, config)
+		return rewriteValueMIPS64_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueMIPS64_OpRsh8Ux8(v, config)
+		return rewriteValueMIPS64_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueMIPS64_OpRsh8x16(v, config)
+		return rewriteValueMIPS64_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueMIPS64_OpRsh8x32(v, config)
+		return rewriteValueMIPS64_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueMIPS64_OpRsh8x64(v, config)
+		return rewriteValueMIPS64_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueMIPS64_OpRsh8x8(v, config)
+		return rewriteValueMIPS64_OpRsh8x8_0(v)
 	case OpSelect0:
-		return rewriteValueMIPS64_OpSelect0(v, config)
+		return rewriteValueMIPS64_OpSelect0_0(v)
 	case OpSelect1:
-		return rewriteValueMIPS64_OpSelect1(v, config)
+		return rewriteValueMIPS64_OpSelect1_0(v) || rewriteValueMIPS64_OpSelect1_10(v) || rewriteValueMIPS64_OpSelect1_20(v)
 	case OpSignExt16to32:
-		return rewriteValueMIPS64_OpSignExt16to32(v, config)
+		return rewriteValueMIPS64_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValueMIPS64_OpSignExt16to64(v, config)
+		return rewriteValueMIPS64_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValueMIPS64_OpSignExt32to64(v, config)
+		return rewriteValueMIPS64_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValueMIPS64_OpSignExt8to16(v, config)
+		return rewriteValueMIPS64_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueMIPS64_OpSignExt8to32(v, config)
+		return rewriteValueMIPS64_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValueMIPS64_OpSignExt8to64(v, config)
+		return rewriteValueMIPS64_OpSignExt8to64_0(v)
 	case OpSlicemask:
-		return rewriteValueMIPS64_OpSlicemask(v, config)
+		return rewriteValueMIPS64_OpSlicemask_0(v)
 	case OpStaticCall:
-		return rewriteValueMIPS64_OpStaticCall(v, config)
+		return rewriteValueMIPS64_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueMIPS64_OpStore(v, config)
+		return rewriteValueMIPS64_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueMIPS64_OpSub16(v, config)
+		return rewriteValueMIPS64_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueMIPS64_OpSub32(v, config)
+		return rewriteValueMIPS64_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueMIPS64_OpSub32F(v, config)
+		return rewriteValueMIPS64_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValueMIPS64_OpSub64(v, config)
+		return rewriteValueMIPS64_OpSub64_0(v)
 	case OpSub64F:
-		return rewriteValueMIPS64_OpSub64F(v, config)
+		return rewriteValueMIPS64_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueMIPS64_OpSub8(v, config)
+		return rewriteValueMIPS64_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueMIPS64_OpSubPtr(v, config)
+		return rewriteValueMIPS64_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueMIPS64_OpTrunc16to8(v, config)
+		return rewriteValueMIPS64_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueMIPS64_OpTrunc32to16(v, config)
+		return rewriteValueMIPS64_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueMIPS64_OpTrunc32to8(v, config)
+		return rewriteValueMIPS64_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValueMIPS64_OpTrunc64to16(v, config)
+		return rewriteValueMIPS64_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValueMIPS64_OpTrunc64to32(v, config)
+		return rewriteValueMIPS64_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValueMIPS64_OpTrunc64to8(v, config)
+		return rewriteValueMIPS64_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValueMIPS64_OpXor16(v, config)
+		return rewriteValueMIPS64_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueMIPS64_OpXor32(v, config)
+		return rewriteValueMIPS64_OpXor32_0(v)
 	case OpXor64:
-		return rewriteValueMIPS64_OpXor64(v, config)
+		return rewriteValueMIPS64_OpXor64_0(v)
 	case OpXor8:
-		return rewriteValueMIPS64_OpXor8(v, config)
+		return rewriteValueMIPS64_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueMIPS64_OpZero(v, config)
+		return rewriteValueMIPS64_OpZero_0(v) || rewriteValueMIPS64_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValueMIPS64_OpZeroExt16to32(v, config)
+		return rewriteValueMIPS64_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValueMIPS64_OpZeroExt16to64(v, config)
+		return rewriteValueMIPS64_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValueMIPS64_OpZeroExt32to64(v, config)
+		return rewriteValueMIPS64_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueMIPS64_OpZeroExt8to16(v, config)
+		return rewriteValueMIPS64_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueMIPS64_OpZeroExt8to32(v, config)
+		return rewriteValueMIPS64_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValueMIPS64_OpZeroExt8to64(v, config)
+		return rewriteValueMIPS64_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValueMIPS64_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd16_0(v *Value) bool {
 	// match: (Add16 x y)
 	// cond:
 	// result: (ADDV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
@@ -588,13 +586,12 @@ func rewriteValueMIPS64_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd32_0(v *Value) bool {
 	// match: (Add32 x y)
 	// cond:
 	// result: (ADDV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
@@ -603,13 +600,12 @@ func rewriteValueMIPS64_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (ADDF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDF)
@@ -618,13 +614,12 @@ func rewriteValueMIPS64_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd64_0(v *Value) bool {
 	// match: (Add64 x y)
 	// cond:
 	// result: (ADDV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
@@ -633,13 +628,12 @@ func rewriteValueMIPS64_OpAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (ADDD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDD)
@@ -648,13 +642,12 @@ func rewriteValueMIPS64_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAdd8_0(v *Value) bool {
 	// match: (Add8 x y)
 	// cond:
 	// result: (ADDV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
@@ -663,13 +656,12 @@ func rewriteValueMIPS64_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADDV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
@@ -678,9 +670,7 @@ func rewriteValueMIPS64_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVVaddr {sym} base)
@@ -693,13 +683,12 @@ func rewriteValueMIPS64_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
@@ -708,13 +697,12 @@ func rewriteValueMIPS64_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
@@ -723,13 +711,12 @@ func rewriteValueMIPS64_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAnd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAnd64_0(v *Value) bool {
 	// match: (And64 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
@@ -738,13 +725,12 @@ func rewriteValueMIPS64_OpAnd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAnd8_0(v *Value) bool {
 	// match: (And8 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
@@ -753,13 +739,12 @@ func rewriteValueMIPS64_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
@@ -768,47 +753,36 @@ func rewriteValueMIPS64_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpAvg64u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpAvg64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Avg64u <t> x y)
 	// cond:
-	// result: (ADDV (ADDV <t> (SRLVconst <t> x [1]) (SRLVconst <t> y [1])) (AND <t> (AND <t> x y) (MOVVconst [1])))
+	// result: (ADDV (SRLVconst <t> (SUBV <t> x y) [1]) y)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64ADDV)
-		v0 := b.NewValue0(v.Line, OpMIPS64ADDV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SRLVconst, t)
-		v1.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpMIPS64SRLVconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpMIPS64SUBV, t)
 		v1.AddArg(x)
+		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpMIPS64SRLVconst, t)
-		v2.AuxInt = 1
-		v2.AddArg(y)
-		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64AND, t)
-		v4 := b.NewValue0(v.Line, OpMIPS64AND, t)
-		v4.AddArg(x)
-		v4.AddArg(y)
-		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
-		v5.AuxInt = 1
-		v3.AddArg(v5)
-		v.AddArg(v3)
+		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpClosureCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -820,73 +794,79 @@ func rewriteValueMIPS64_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCom16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpCom16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Com16 x)
 	// cond:
 	// result: (NOR (MOVVconst [0]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpMIPS64NOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCom32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpCom32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Com32 x)
 	// cond:
 	// result: (NOR (MOVVconst [0]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpMIPS64NOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCom64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpCom64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Com64 x)
 	// cond:
 	// result: (NOR (MOVVconst [0]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpMIPS64NOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCom8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpCom8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Com8 x)
 	// cond:
 	// result: (NOR (MOVVconst [0]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpMIPS64NOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst16_0(v *Value) bool {
 	// match: (Const16 [val])
 	// cond:
 	// result: (MOVVconst [val])
@@ -897,9 +877,7 @@ func rewriteValueMIPS64_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst32_0(v *Value) bool {
 	// match: (Const32 [val])
 	// cond:
 	// result: (MOVVconst [val])
@@ -910,9 +888,7 @@ func rewriteValueMIPS64_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (MOVFconst [val])
@@ -923,9 +899,7 @@ func rewriteValueMIPS64_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst64_0(v *Value) bool {
 	// match: (Const64 [val])
 	// cond:
 	// result: (MOVVconst [val])
@@ -936,9 +910,7 @@ func rewriteValueMIPS64_OpConst64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (MOVDconst [val])
@@ -949,9 +921,7 @@ func rewriteValueMIPS64_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConst8_0(v *Value) bool {
 	// match: (Const8 [val])
 	// cond:
 	// result: (MOVVconst [val])
@@ -962,9 +932,7 @@ func rewriteValueMIPS64_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVVconst [b])
@@ -975,9 +943,7 @@ func rewriteValueMIPS64_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVVconst [0])
@@ -987,13 +953,12 @@ func rewriteValueMIPS64_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpConvert_0(v *Value) bool {
 	// match: (Convert x mem)
 	// cond:
 	// result: (MOVVconvert x mem)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPS64MOVVconvert)
@@ -1002,9 +967,7 @@ func rewriteValueMIPS64_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (TRUNCFW x)
@@ -1015,9 +978,7 @@ func rewriteValueMIPS64_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt32Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt32Fto64_0(v *Value) bool {
 	// match: (Cvt32Fto64 x)
 	// cond:
 	// result: (TRUNCFV x)
@@ -1028,9 +989,7 @@ func rewriteValueMIPS64_OpCvt32Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (MOVFD x)
@@ -1041,9 +1000,7 @@ func rewriteValueMIPS64_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (MOVWF x)
@@ -1054,9 +1011,7 @@ func rewriteValueMIPS64_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (MOVWD x)
@@ -1067,9 +1022,7 @@ func rewriteValueMIPS64_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (TRUNCDW x)
@@ -1080,9 +1033,7 @@ func rewriteValueMIPS64_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (MOVDF x)
@@ -1093,9 +1044,7 @@ func rewriteValueMIPS64_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt64Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt64Fto64_0(v *Value) bool {
 	// match: (Cvt64Fto64 x)
 	// cond:
 	// result: (TRUNCDV x)
@@ -1106,9 +1055,7 @@ func rewriteValueMIPS64_OpCvt64Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt64to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt64to32F_0(v *Value) bool {
 	// match: (Cvt64to32F x)
 	// cond:
 	// result: (MOVVF x)
@@ -1119,9 +1066,7 @@ func rewriteValueMIPS64_OpCvt64to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpCvt64to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpCvt64to64F_0(v *Value) bool {
 	// match: (Cvt64to64F x)
 	// cond:
 	// result: (MOVVD x)
@@ -1132,91 +1077,84 @@ func rewriteValueMIPS64_OpCvt64to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_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(OpMIPS64CALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpDiv16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16 x y)
 	// cond:
 	// result: (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32 x y)
 	// cond:
 	// result: (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (DIVF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64DIVF)
@@ -1225,51 +1163,56 @@ func rewriteValueMIPS64_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv32u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32u x y)
 	// cond:
 	// result: (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div64 x y)
 	// cond:
 	// result: (Select1 (DIVV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (DIVD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64DIVD)
@@ -1278,452 +1221,505 @@ func rewriteValueMIPS64_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv64u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div64u x y)
 	// cond:
 	// result: (Select1 (DIVVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8 x y)
 	// cond:
 	// result: (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div8u x y)
 	// cond:
 	// result: (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq16 x y)
 	// cond:
 	// result: (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq32 x y)
 	// cond:
 	// result: (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPEQF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPEQF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPEQF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq64 x y)
 	// cond:
 	// result: (SGTU (MOVVconst [1]) (XOR x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPEQD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPEQD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPEQD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEq8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq8 x y)
 	// cond:
 	// result: (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEqB(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqB x y)
 	// cond:
-	// result: (XOR (MOVVconst [1]) (XOR <config.fe.TypeBool()> x y))
+	// result: (XOR (MOVVconst [1]) (XOR <typ.Bool> x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.Bool)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqPtr x y)
 	// cond:
 	// result: (SGTU (MOVVconst [1]) (XOR x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt16to64 y) (SignExt16to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt32to64 y) (SignExt32to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGEF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGEF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGEF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
 		v1.AddArg(y)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGED x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGED, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGED, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq64U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v1.AddArg(y)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt8to64 y) (SignExt8to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(x)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -1732,121 +1728,118 @@ func rewriteValueMIPS64_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_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(OpMIPS64CALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16 x y)
 	// cond:
 	// result: (SGT (SignExt16to64 x) (SignExt16to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater32 x y)
 	// cond:
 	// result: (SGT (SignExt32to64 x) (SignExt32to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGTF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGTF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater32U x y)
 	// cond:
 	// result: (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpGreater64_0(v *Value) bool {
 	// match: (Greater64 x y)
 	// cond:
 	// result: (SGT x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
@@ -1855,30 +1848,30 @@ func rewriteValueMIPS64_OpGreater64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGTD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGTD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpGreater64U_0(v *Value) bool {
 	// match: (Greater64U x y)
 	// cond:
 	// result: (SGTU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
@@ -1887,109 +1880,70 @@ func rewriteValueMIPS64_OpGreater64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8 x y)
 	// cond:
 	// result: (SGT (SignExt8to64 x) (SignExt8to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8U x y)
 	// cond:
 	// result: (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16 x y)
-	// cond:
-	// result: (SRAVconst (Select1 <config.fe.TypeInt32()> (MULV (SignExt16to64 x) (SignExt16to64 y))) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPS64SRAVconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
-		v3.AddArg(y)
-		v1.AddArg(v3)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRLVconst (Select1 <config.fe.TypeUInt32()> (MULVU (ZeroExt16to64 x) (ZeroExt16to64 y))) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPS64SRLVconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v3.AddArg(y)
-		v1.AddArg(v3)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpHmul32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpHmul32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32 x y)
 	// cond:
-	// result: (SRAVconst (Select1 <config.fe.TypeInt64()> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
+	// result: (SRAVconst (Select1 <typ.Int64> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAVconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeInt64())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSelect1, typ.Int64)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MULV, types.NewTuple(typ.Int64, typ.Int64))
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
@@ -1997,23 +1951,26 @@ func rewriteValueMIPS64_OpHmul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpHmul32u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpHmul32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32u x y)
 	// cond:
-	// result: (SRLVconst (Select1 <config.fe.TypeUInt64()> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
+	// result: (SRLVconst (Select1 <typ.UInt64> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRLVconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeUInt64())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpSelect1, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
@@ -2021,96 +1978,53 @@ func rewriteValueMIPS64_OpHmul32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpHmul64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpHmul64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul64 x y)
 	// cond:
 	// result: (Select0 (MULV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULV, types.NewTuple(typ.Int64, typ.Int64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpHmul64u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpHmul64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul64u x y)
 	// cond:
 	// result: (Select0 (MULVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8 x y)
-	// cond:
-	// result: (SRAVconst (Select1 <config.fe.TypeInt16()> (MULV (SignExt8to64 x) (SignExt8to64 y))) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPS64SRAVconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeInt16())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
-		v3.AddArg(y)
-		v1.AddArg(v3)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u x y)
-	// cond:
-	// result: (SRLVconst (Select1 <config.fe.TypeUInt16()> (MULVU (ZeroExt8to64 x) (ZeroExt8to64 y))) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPS64SRLVconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeUInt16())
-		v1 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
-		v3.AddArg(y)
-		v1.AddArg(v3)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueMIPS64_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPS64CALLinter)
@@ -2120,13 +2034,12 @@ func rewriteValueMIPS64_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpIsInBounds(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpIsInBounds_0(v *Value) bool {
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (SGTU len idx)
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpMIPS64SGTU)
@@ -2135,9 +2048,11 @@ func rewriteValueMIPS64_OpIsInBounds(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsNonNil ptr)
 	// cond:
 	// result: (SGTU ptr (MOVVconst [0]))
@@ -2145,350 +2060,391 @@ func rewriteValueMIPS64_OpIsNonNil(v *Value, config *Config) bool {
 		ptr := v.Args[0]
 		v.reset(OpMIPS64SGTU)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v1.AddArg(idx)
 		v1.AddArg(len)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt16to64 x) (SignExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt32to64 x) (SignExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGEF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGEF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGEF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGED y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGED, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGED, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq64U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8 x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGT (SignExt8to64 x) (SignExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGT, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v3 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8U x y)
 	// cond:
 	// result: (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 1
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16 x y)
 	// cond:
 	// result: (SGT (SignExt16to64 y) (SignExt16to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less32 x y)
 	// cond:
 	// result: (SGT (SignExt32to64 y) (SignExt32to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTF y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGTF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGTF, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess32U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less32U x y)
 	// cond:
 	// result: (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpLess64_0(v *Value) bool {
 	// match: (Less64 x y)
 	// cond:
 	// result: (SGT y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
@@ -2497,30 +2453,30 @@ func rewriteValueMIPS64_OpLess64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (FPFlagTrue (CMPGTD y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagTrue)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPGTD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPGTD, types.TypeFlags)
 		v0.AddArg(y)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpLess64U_0(v *Value) bool {
 	// match: (Less64U x y)
 	// cond:
 	// result: (SGTU y x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
@@ -2529,52 +2485,57 @@ func rewriteValueMIPS64_OpLess64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8 x y)
 	// cond:
 	// result: (SGT (SignExt8to64 y) (SignExt8to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGT)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLess8U(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8U x y)
 	// cond:
 	// result: (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: t.IsBoolean()
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean()) {
@@ -2590,6 +2551,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
@@ -2605,6 +2567,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && !isSigned(t)) {
@@ -2620,6 +2583,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -2635,6 +2599,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -2650,6 +2615,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && isSigned(t)) {
@@ -2665,6 +2631,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWUload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && !isSigned(t)) {
@@ -2680,6 +2647,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVVload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) || isPtr(t)) {
@@ -2695,6 +2663,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVFload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -2710,6 +2679,7 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitFloat(t)) {
@@ -2722,483 +2692,530 @@ func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v3.AddArg(x)
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh32x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v3.AddArg(x)
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh64x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh64x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v3.AddArg(x)
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh8x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SLLV <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v3.AddArg(x)
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SLLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMIPS64ADDV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADDV (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64ADDV_0(v *Value) bool {
+	// match: (ADDV x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (ADDVconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		if !(is32Bit(c)) {
 			break
 		}
@@ -3207,16 +3224,17 @@ func rewriteValueMIPS64_OpMIPS64ADDV(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADDV x (MOVVconst [c]))
+	// match: (ADDV (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (ADDVconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(is32Bit(c)) {
 			break
 		}
@@ -3229,6 +3247,7 @@ func rewriteValueMIPS64_OpMIPS64ADDV(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64NEGV {
@@ -3244,6 +3263,7 @@ func rewriteValueMIPS64_OpMIPS64ADDV(v *Value, config *Config) bool {
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64NEGV {
 			break
@@ -3257,9 +3277,7 @@ func rewriteValueMIPS64_OpMIPS64ADDV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64ADDVconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64ADDVconst_0(v *Value) bool {
 	// match: (ADDVconst [off1] (MOVVaddr [off2] {sym} ptr))
 	// cond:
 	// result: (MOVVaddr [off1+off2] {sym} ptr)
@@ -3278,7 +3296,7 @@ func rewriteValueMIPS64_OpMIPS64ADDVconst(v *Value, config *Config) bool {
 		v.AddArg(ptr)
 		return true
 	}
-	// match: (ADDVconst [0]  x)
+	// match: (ADDVconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -3345,19 +3363,18 @@ func rewriteValueMIPS64_OpMIPS64ADDVconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64AND(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AND (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64AND_0(v *Value) bool {
+	// match: (AND x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (ANDconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		if !(is32Bit(c)) {
 			break
 		}
@@ -3366,16 +3383,17 @@ func rewriteValueMIPS64_OpMIPS64AND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVVconst [c]))
+	// match: (AND (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (ANDconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(is32Bit(c)) {
 			break
 		}
@@ -3388,6 +3406,7 @@ func rewriteValueMIPS64_OpMIPS64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -3399,10 +3418,8 @@ func rewriteValueMIPS64_OpMIPS64AND(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64ANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ANDconst [0]  _)
+func rewriteValueMIPS64_OpMIPS64ANDconst_0(v *Value) bool {
+	// match: (ANDconst [0] _)
 	// cond:
 	// result: (MOVVconst [0])
 	for {
@@ -3458,15 +3475,14 @@ func rewriteValueMIPS64_OpMIPS64ANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVBUload_0(v *Value) bool {
 	// match: (MOVBUload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3490,6 +3506,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBUload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -3510,9 +3527,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVBUreg_0(v *Value) bool {
 	// match: (MOVBUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -3521,6 +3536,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -3552,15 +3568,14 @@ func rewriteValueMIPS64_OpMIPS64MOVBUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVBload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVBload_0(v *Value) bool {
+	// match: (MOVBload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3584,6 +3599,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -3604,9 +3620,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVBreg_0(v *Value) bool {
 	// match: (MOVBreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -3615,6 +3629,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -3631,7 +3646,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVBreg  (MOVVconst [c]))
+	// match: (MOVBreg (MOVVconst [c]))
 	// cond:
 	// result: (MOVVconst [int64(int8(c))])
 	for {
@@ -3646,15 +3661,14 @@ func rewriteValueMIPS64_OpMIPS64MOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVBstore_0(v *Value) bool {
 	// match: (MOVBstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3680,6 +3694,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -3706,6 +3721,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -3728,6 +3744,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVBreg {
@@ -3749,6 +3766,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVBUreg {
@@ -3770,6 +3788,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVHreg {
@@ -3791,6 +3810,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVHUreg {
@@ -3812,6 +3832,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWreg {
@@ -3833,6 +3854,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWUreg {
@@ -3850,15 +3872,14 @@ func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVBstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVBstorezero_0(v *Value) bool {
 	// match: (MOVBstorezero [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVBstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3882,6 +3903,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -3902,15 +3924,14 @@ func rewriteValueMIPS64_OpMIPS64MOVBstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVDload_0(v *Value) bool {
+	// match: (MOVDload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVDload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3934,6 +3955,7 @@ func rewriteValueMIPS64_OpMIPS64MOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -3954,15 +3976,14 @@ func rewriteValueMIPS64_OpMIPS64MOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVDstore_0(v *Value) bool {
 	// match: (MOVDstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -3988,6 +4009,7 @@ func rewriteValueMIPS64_OpMIPS64MOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4010,15 +4032,14 @@ func rewriteValueMIPS64_OpMIPS64MOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVFload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVFload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVFload_0(v *Value) bool {
+	// match: (MOVFload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVFload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4042,6 +4063,7 @@ func rewriteValueMIPS64_OpMIPS64MOVFload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4062,15 +4084,14 @@ func rewriteValueMIPS64_OpMIPS64MOVFload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVFstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVFstore_0(v *Value) bool {
 	// match: (MOVFstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVFstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4096,6 +4117,7 @@ func rewriteValueMIPS64_OpMIPS64MOVFstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4118,15 +4140,14 @@ func rewriteValueMIPS64_OpMIPS64MOVFstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVHUload_0(v *Value) bool {
 	// match: (MOVHUload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVHUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4150,6 +4171,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHUload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4170,9 +4192,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVHUreg_0(v *Value) bool {
 	// match: (MOVHUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -4181,6 +4201,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4193,6 +4214,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4236,15 +4258,14 @@ func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVHload_0(v *Value) bool {
+	// match: (MOVHload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVHload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4268,6 +4289,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4288,9 +4310,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVHreg_0(v *Value) bool {
 	// match: (MOVHreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -4299,6 +4319,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4311,6 +4332,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4323,6 +4345,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4363,7 +4386,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVHreg  (MOVVconst [c]))
+	// match: (MOVHreg (MOVVconst [c]))
 	// cond:
 	// result: (MOVVconst [int64(int16(c))])
 	for {
@@ -4378,15 +4401,14 @@ func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVHstore_0(v *Value) bool {
 	// match: (MOVHstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVHstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4412,6 +4434,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4438,6 +4461,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -4460,6 +4484,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVHreg {
@@ -4481,6 +4506,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVHUreg {
@@ -4502,6 +4528,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWreg {
@@ -4523,6 +4550,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWUreg {
@@ -4540,15 +4568,14 @@ func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVHstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVHstorezero_0(v *Value) bool {
 	// match: (MOVHstorezero [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVHstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4572,6 +4599,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4592,15 +4620,14 @@ func rewriteValueMIPS64_OpMIPS64MOVHstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVVload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVVload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVVload_0(v *Value) bool {
+	// match: (MOVVload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVVload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4624,6 +4651,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4644,9 +4672,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVVreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVVreg_0(v *Value) bool {
 	// match: (MOVVreg x)
 	// cond: x.Uses == 1
 	// result: (MOVVnop x)
@@ -4659,7 +4685,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVVreg  (MOVVconst [c]))
+	// match: (MOVVreg (MOVVconst [c]))
 	// cond:
 	// result: (MOVVconst [c])
 	for {
@@ -4674,15 +4700,14 @@ func rewriteValueMIPS64_OpMIPS64MOVVreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVVstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVVstore_0(v *Value) bool {
 	// match: (MOVVstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVVstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4708,6 +4733,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4734,6 +4760,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -4752,15 +4779,14 @@ func rewriteValueMIPS64_OpMIPS64MOVVstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVVstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVVstorezero_0(v *Value) bool {
 	// match: (MOVVstorezero [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVVstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4784,6 +4810,7 @@ func rewriteValueMIPS64_OpMIPS64MOVVstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4804,15 +4831,14 @@ func rewriteValueMIPS64_OpMIPS64MOVVstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWUload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVWUload_0(v *Value) bool {
 	// match: (MOVWUload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVWUload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4836,6 +4862,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWUload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4856,9 +4883,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWUload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVWUreg_0(v *Value) bool {
 	// match: (MOVWUreg x:(MOVBUload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -4867,6 +4892,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4879,6 +4905,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4891,6 +4918,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVWUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -4946,15 +4974,14 @@ func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWload  [off1] {sym} (ADDVconst [off2] ptr) mem)
+func rewriteValueMIPS64_OpMIPS64MOVWload_0(v *Value) bool {
+	// match: (MOVWload [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVWload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -4978,6 +5005,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -4998,9 +5026,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVWreg_0(v *Value) bool {
 	// match: (MOVWreg x:(MOVBload _ _))
 	// cond:
 	// result: (MOVVreg x)
@@ -5009,6 +5035,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -5021,6 +5048,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVBUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -5033,6 +5061,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -5045,6 +5074,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVHUload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -5057,6 +5087,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		if x.Op != OpMIPS64MOVWload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpMIPS64MOVVreg)
 		v.AddArg(x)
 		return true
@@ -5121,7 +5152,10 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVWreg  (MOVVconst [c]))
+	return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWreg_10(v *Value) bool {
+	// match: (MOVWreg (MOVVconst [c]))
 	// cond:
 	// result: (MOVVconst [int64(int32(c))])
 	for {
@@ -5136,15 +5170,14 @@ func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVWstore_0(v *Value) bool {
 	// match: (MOVWstore [off1] {sym} (ADDVconst [off2] ptr) val mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVWstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -5170,6 +5203,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -5196,6 +5230,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -5218,6 +5253,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWreg {
@@ -5239,6 +5275,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVWUreg {
@@ -5256,15 +5293,14 @@ func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64MOVWstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64MOVWstorezero_0(v *Value) bool {
 	// match: (MOVWstorezero [off1] {sym} (ADDVconst [off2] ptr) mem)
 	// cond: is32Bit(off1+off2)
 	// result: (MOVWstorezero [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64ADDVconst {
 			break
@@ -5288,6 +5324,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVaddr {
 			break
@@ -5308,9 +5345,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64NEGV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64NEGV_0(v *Value) bool {
 	// match: (NEGV (MOVVconst [c]))
 	// cond:
 	// result: (MOVVconst [-c])
@@ -5326,19 +5361,18 @@ func rewriteValueMIPS64_OpMIPS64NEGV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64NOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOR (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64NOR_0(v *Value) bool {
+	// match: (NOR x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (NORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		if !(is32Bit(c)) {
 			break
 		}
@@ -5347,16 +5381,17 @@ func rewriteValueMIPS64_OpMIPS64NOR(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (NOR x (MOVVconst [c]))
+	// match: (NOR (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (NORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(is32Bit(c)) {
 			break
 		}
@@ -5367,9 +5402,7 @@ func rewriteValueMIPS64_OpMIPS64NOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64NORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64NORconst_0(v *Value) bool {
 	// match: (NORconst [c] (MOVVconst [d]))
 	// cond:
 	// result: (MOVVconst [^(c|d)])
@@ -5386,19 +5419,18 @@ func rewriteValueMIPS64_OpMIPS64NORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64OR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (OR  (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64OR_0(v *Value) bool {
+	// match: (OR x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (ORconst  [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		if !(is32Bit(c)) {
 			break
 		}
@@ -5407,16 +5439,17 @@ func rewriteValueMIPS64_OpMIPS64OR(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x (MOVVconst [c]))
+	// match: (OR (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (ORconst  [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(is32Bit(c)) {
 			break
 		}
@@ -5425,10 +5458,11 @@ func rewriteValueMIPS64_OpMIPS64OR(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (OR  x x)
+	// match: (OR x x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -5440,10 +5474,8 @@ func rewriteValueMIPS64_OpMIPS64OR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64ORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ORconst  [0]  x)
+func rewriteValueMIPS64_OpMIPS64ORconst_0(v *Value) bool {
+	// match: (ORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -5456,7 +5488,7 @@ func rewriteValueMIPS64_OpMIPS64ORconst(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ORconst  [-1] _)
+	// match: (ORconst [-1] _)
 	// cond:
 	// result: (MOVVconst [-1])
 	for {
@@ -5502,13 +5534,12 @@ func rewriteValueMIPS64_OpMIPS64ORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SGT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SGT  (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64SGT_0(v *Value) bool {
+	// match: (SGT (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (SGTconst  [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVconst {
 			break
@@ -5525,13 +5556,12 @@ func rewriteValueMIPS64_OpMIPS64SGT(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SGTU(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SGTU_0(v *Value) bool {
 	// match: (SGTU (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (SGTUconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVconst {
 			break
@@ -5548,9 +5578,7 @@ func rewriteValueMIPS64_OpMIPS64SGTU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SGTUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SGTUconst_0(v *Value) bool {
 	// match: (SGTUconst [c] (MOVVconst [d]))
 	// cond: uint64(c)>uint64(d)
 	// result: (MOVVconst [1])
@@ -5653,9 +5681,7 @@ func rewriteValueMIPS64_OpMIPS64SGTUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SGTconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SGTconst_0(v *Value) bool {
 	// match: (SGTconst [c] (MOVVconst [d]))
 	// cond: int64(c)>int64(d)
 	// result: (MOVVconst [1])
@@ -5818,6 +5844,9 @@ func rewriteValueMIPS64_OpMIPS64SGTconst(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	return false
+}
+func rewriteValueMIPS64_OpMIPS64SGTconst_10(v *Value) bool {
 	// match: (SGTconst [c] (MOVWUreg _))
 	// cond: int64(c) < 0
 	// result: (MOVVconst [0])
@@ -5870,13 +5899,12 @@ func rewriteValueMIPS64_OpMIPS64SGTconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SLLV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SLLV_0(v *Value) bool {
 	// match: (SLLV _ (MOVVconst [c]))
 	// cond: uint64(c)>=64
 	// result: (MOVVconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
 			break
@@ -5893,6 +5921,7 @@ func rewriteValueMIPS64_OpMIPS64SLLV(v *Value, config *Config) bool {
 	// cond:
 	// result: (SLLVconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -5906,9 +5935,7 @@ func rewriteValueMIPS64_OpMIPS64SLLV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SLLVconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SLLVconst_0(v *Value) bool {
 	// match: (SLLVconst [c] (MOVVconst [d]))
 	// cond:
 	// result: (MOVVconst [int64(d)<<uint64(c)])
@@ -5925,13 +5952,12 @@ func rewriteValueMIPS64_OpMIPS64SLLVconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SRAV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SRAV_0(v *Value) bool {
 	// match: (SRAV x (MOVVconst [c]))
 	// cond: uint64(c)>=64
 	// result: (SRAVconst x [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -5950,6 +5976,7 @@ func rewriteValueMIPS64_OpMIPS64SRAV(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAVconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -5963,9 +5990,7 @@ func rewriteValueMIPS64_OpMIPS64SRAV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SRAVconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SRAVconst_0(v *Value) bool {
 	// match: (SRAVconst [c] (MOVVconst [d]))
 	// cond:
 	// result: (MOVVconst [int64(d)>>uint64(c)])
@@ -5982,13 +6007,12 @@ func rewriteValueMIPS64_OpMIPS64SRAVconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SRLV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SRLV_0(v *Value) bool {
 	// match: (SRLV _ (MOVVconst [c]))
 	// cond: uint64(c)>=64
 	// result: (MOVVconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
 			break
@@ -6005,6 +6029,7 @@ func rewriteValueMIPS64_OpMIPS64SRLV(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRLVconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -6018,9 +6043,7 @@ func rewriteValueMIPS64_OpMIPS64SRLV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SRLVconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SRLVconst_0(v *Value) bool {
 	// match: (SRLVconst [c] (MOVVconst [d]))
 	// cond:
 	// result: (MOVVconst [int64(uint64(d)>>uint64(c))])
@@ -6037,13 +6060,12 @@ func rewriteValueMIPS64_OpMIPS64SRLVconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SUBV(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMIPS64SUBV_0(v *Value) bool {
 	// match: (SUBV x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (SUBVconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpMIPS64MOVVconst {
@@ -6062,6 +6084,7 @@ func rewriteValueMIPS64_OpMIPS64SUBV(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVVconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6074,6 +6097,7 @@ func rewriteValueMIPS64_OpMIPS64SUBV(v *Value, config *Config) bool {
 	// cond:
 	// result: (NEGV x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpMIPS64MOVVconst {
 			break
@@ -6088,10 +6112,8 @@ func rewriteValueMIPS64_OpMIPS64SUBV(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64SUBVconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBVconst [0]  x)
+func rewriteValueMIPS64_OpMIPS64SUBVconst_0(v *Value) bool {
+	// match: (SUBVconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -6158,19 +6180,18 @@ func rewriteValueMIPS64_OpMIPS64SUBVconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64XOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR (MOVVconst [c]) x)
+func rewriteValueMIPS64_OpMIPS64XOR_0(v *Value) bool {
+	// match: (XOR x (MOVVconst [c]))
 	// cond: is32Bit(c)
 	// result: (XORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
+		c := v_1.AuxInt
 		if !(is32Bit(c)) {
 			break
 		}
@@ -6179,16 +6200,17 @@ func rewriteValueMIPS64_OpMIPS64XOR(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x (MOVVconst [c]))
+	// match: (XOR (MOVVconst [c]) x)
 	// cond: is32Bit(c)
 	// result: (XORconst [c] x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpMIPS64MOVVconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MOVVconst {
 			break
 		}
-		c := v_1.AuxInt
+		c := v_0.AuxInt
+		x := v.Args[1]
 		if !(is32Bit(c)) {
 			break
 		}
@@ -6201,6 +6223,7 @@ func rewriteValueMIPS64_OpMIPS64XOR(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVVconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6211,10 +6234,8 @@ func rewriteValueMIPS64_OpMIPS64XOR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMIPS64XORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XORconst [0]  x)
+func rewriteValueMIPS64_OpMIPS64XORconst_0(v *Value) bool {
+	// match: (XORconst [0] x)
 	// cond:
 	// result: x
 	for {
@@ -6275,245 +6296,275 @@ func rewriteValueMIPS64_OpMIPS64XORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMod16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16 x y)
 	// cond:
 	// result: (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod16u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32 x y)
 	// cond:
 	// result: (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod32u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32u x y)
 	// cond:
 	// result: (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod64 x y)
 	// cond:
 	// result: (Select0 (DIVV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod64u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod64u x y)
 	// cond:
 	// result: (Select0 (DIVVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8 x y)
 	// cond:
 	// result: (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVV, MakeTuple(config.fe.TypeInt64(), config.fe.TypeInt64()))
-		v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVV, types.NewTuple(typ.Int64, typ.Int64))
+		v1 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMod8u(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8u x y)
 	// cond:
 	// result: (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect0)
-		v0 := b.NewValue0(v.Line, OpMIPS64DIVVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64DIVVU, types.NewTuple(typ.UInt64, typ.UInt64))
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpMIPS64MOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [2] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore dst (MOVHload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVBstore [1] dst (MOVBload [1] src mem) 		(MOVBstore dst (MOVBload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 1
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v0.AuxInt = 1
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6521,48 +6572,56 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore dst (MOVWload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [4] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] dst (MOVHload [2] src mem) 		(MOVHstore dst (MOVHload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6570,44 +6629,44 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVBstore [3] dst (MOVBload [3] src mem) 		(MOVBstore [2] dst (MOVBload [2] src mem) 			(MOVBstore [1] dst (MOVBload [1] src mem) 				(MOVBstore dst (MOVBload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 3
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v0.AuxInt = 3
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v2.AuxInt = 2
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v4.AuxInt = 1
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v6 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -6617,48 +6676,56 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore dst (MOVVload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [4] dst (MOVWload [4] src mem) 		(MOVWstore dst (MOVWload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6666,44 +6733,48 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [6] dst (MOVHload [6] src mem) 		(MOVHstore [4] dst (MOVHload [4] src mem) 			(MOVHstore [2] dst (MOVHload [2] src mem) 				(MOVHstore dst (MOVHload src mem) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 6
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v0.AuxInt = 6
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v3.AuxInt = 2
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v4.AuxInt = 2
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v6 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v6.AddArg(src)
 		v6.AddArg(mem)
 		v5.AddArg(v6)
@@ -6713,36 +6784,45 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	return false
+}
+func rewriteValueMIPS64_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBload [2] src mem) 		(MOVBstore [1] dst (MOVBload [1] src mem) 			(MOVBstore dst (MOVBload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v2.AuxInt = 1
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVBload, typ.Int8)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6751,36 +6831,40 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [6] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [4] dst (MOVHload [4] src mem) 		(MOVHstore [2] dst (MOVHload [2] src mem) 			(MOVHstore dst (MOVHload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v2.AuxInt = 2
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVHload, typ.Int16)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6789,36 +6873,40 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Move [12] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [8] dst (MOVWload [8] src mem) 		(MOVWstore [4] dst (MOVWload [4] src mem) 			(MOVWstore dst (MOVWload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 12 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVWload, typ.Int32)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6827,28 +6915,32 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Move [16] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore [8] dst (MOVVload [8] src mem) 		(MOVVstore dst (MOVVload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -6856,36 +6948,40 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Move [24] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore [16] dst (MOVVload [16] src mem) 		(MOVVstore [8] dst (MOVVload [8] src mem) 			(MOVVstore dst (MOVVload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 24 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AuxInt = 16
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v0.AuxInt = 16
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v2.AuxInt = 8
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVload, typ.UInt64)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -6894,23 +6990,25 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0
-	// result: (LoweredMove [SizeAndAlign(s).Align()] 		dst 		src 		(ADDVconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// match: (Move [s] {t} dst src mem)
+	// cond: s > 24 || t.(*types.Type).Alignment()%8 != 0
+	// result: (LoweredMove [t.(*types.Type).Alignment()] 		dst 		src 		(ADDVconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0) {
+		if !(s > 24 || t.(*types.Type).Alignment()%8 != 0) {
 			break
 		}
 		v.reset(OpMIPS64LoweredMove)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpMIPS64ADDVconst, src.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpMIPS64ADDVconst, src.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(src)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -6918,47 +7016,52 @@ func rewriteValueMIPS64_OpMove(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpMul16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMul16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mul16 x y)
 	// cond:
 	// result: (Select1 (MULVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMul32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMul32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mul32 x y)
 	// cond:
 	// result: (Select1 (MULVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (MULF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64MULF)
@@ -6967,30 +7070,32 @@ func rewriteValueMIPS64_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMul64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMul64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mul64 x y)
 	// cond:
 	// result: (Select1 (MULVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (MULD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64MULD)
@@ -6999,26 +7104,27 @@ func rewriteValueMIPS64_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpMul8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpMul8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mul8 x y)
 	// cond:
 	// result: (Select1 (MULVU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpSelect1)
-		v0 := b.NewValue0(v.Line, OpMIPS64MULVU, MakeTuple(config.fe.TypeUInt64(), config.fe.TypeUInt64()))
+		v0 := b.NewValue0(v.Pos, OpMIPS64MULVU, types.NewTuple(typ.UInt64, typ.UInt64))
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg16_0(v *Value) bool {
 	// match: (Neg16 x)
 	// cond:
 	// result: (NEGV x)
@@ -7029,9 +7135,7 @@ func rewriteValueMIPS64_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg32_0(v *Value) bool {
 	// match: (Neg32 x)
 	// cond:
 	// result: (NEGV x)
@@ -7042,9 +7146,7 @@ func rewriteValueMIPS64_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (NEGF x)
@@ -7055,9 +7157,7 @@ func rewriteValueMIPS64_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg64_0(v *Value) bool {
 	// match: (Neg64 x)
 	// cond:
 	// result: (NEGV x)
@@ -7068,9 +7168,7 @@ func rewriteValueMIPS64_OpNeg64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (NEGD x)
@@ -7081,9 +7179,7 @@ func rewriteValueMIPS64_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeg8_0(v *Value) bool {
 	// match: (Neg8 x)
 	// cond:
 	// result: (NEGV x)
@@ -7094,139 +7190,152 @@ func rewriteValueMIPS64_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq16 x y)
 	// cond:
 	// result: (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v3.AuxInt = 0
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq32 x y)
 	// cond:
 	// result: (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v3.AuxInt = 0
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (FPFlagFalse (CMPEQF x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagFalse)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPEQF, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPEQF, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq64 x y)
 	// cond:
 	// result: (SGTU (XOR x y) (MOVVconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (FPFlagFalse (CMPEQD x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64FPFlagFalse)
-		v0 := b.NewValue0(v.Line, OpMIPS64CMPEQD, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpMIPS64CMPEQD, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeq8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq8 x y)
 	// cond:
 	// result: (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v3.AuxInt = 0
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNeqB_0(v *Value) bool {
 	// match: (NeqB x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
@@ -7235,33 +7344,35 @@ func rewriteValueMIPS64_OpNeqB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (SGTU (XOR x y) (MOVVconst [0]))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SGTU)
-		v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64XOR, typ.UInt64)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v1.AuxInt = 0
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpMIPS64LoweredNilCheck)
@@ -7270,9 +7381,7 @@ func rewriteValueMIPS64_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORconst [1] x)
@@ -7284,9 +7393,7 @@ func rewriteValueMIPS64_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOffPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOffPtr_0(v *Value) bool {
 	// match: (OffPtr [off] ptr:(SP))
 	// cond:
 	// result: (MOVVaddr [off] ptr)
@@ -7313,13 +7420,12 @@ func rewriteValueMIPS64_OpOffPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64OR)
@@ -7328,13 +7434,12 @@ func rewriteValueMIPS64_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64OR)
@@ -7343,13 +7448,12 @@ func rewriteValueMIPS64_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOr64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOr64_0(v *Value) bool {
 	// match: (Or64 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64OR)
@@ -7358,13 +7462,12 @@ func rewriteValueMIPS64_OpOr64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOr8_0(v *Value) bool {
 	// match: (Or8 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64OR)
@@ -7373,13 +7476,12 @@ func rewriteValueMIPS64_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64OR)
@@ -7388,91 +7490,124 @@ func rewriteValueMIPS64_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16Ux16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh16Ux16 <t> x y)
+func rewriteValueMIPS64_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+	// result: x
 	for {
-		t := v.Type
 		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v2.AuxInt = 64
-		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v3.AddArg(y)
-		v1.AddArg(v3)
-		v0.AddArg(v1)
-		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v5.AddArg(x)
-		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
-		v6.AddArg(y)
-		v4.AddArg(v6)
-		v.AddArg(v4)
-		return true
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueMIPS64_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueMIPS64_OpRsh16Ux16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux16 <t> x y)
+	// cond:
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpMIPS64AND)
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+		v3.AddArg(y)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+		v5.AddArg(x)
+		v4.AddArg(v5)
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+		v6.AddArg(y)
+		v4.AddArg(v6)
+		v.AddArg(v4)
+		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(x)
 		v3.AddArg(v4)
 		v3.AddArg(y)
@@ -7480,121 +7615,133 @@ func rewriteValueMIPS64_OpRsh16Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x32 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x64 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v3.AddArg(y)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7604,123 +7751,135 @@ func rewriteValueMIPS64_OpRsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x8 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
+	// result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(x)
 		v3.AddArg(v4)
 		v3.AddArg(y)
@@ -7728,121 +7887,133 @@ func rewriteValueMIPS64_OpRsh32Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32Ux8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x32 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x64 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v3.AddArg(y)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7852,231 +8023,255 @@ func rewriteValueMIPS64_OpRsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x8 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
+	// result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> x y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> x y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
 		v3.AddArg(x)
 		v3.AddArg(y)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64Ux8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
 		v4.AddArg(x)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x16 <t> x y)
 	// cond:
-	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v2.AddArg(v4)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v5.AddArg(y)
 		v0.AddArg(v5)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x32 <t> x y)
 	// cond:
-	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v2.AddArg(v4)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v5.AddArg(y)
 		v0.AddArg(v5)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x64 <t> x y)
 	// cond:
-	// result: (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+	// result: (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v0 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v2.AddArg(y)
-		v3 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v3.AuxInt = 63
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8086,121 +8281,133 @@ func rewriteValueMIPS64_OpRsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh64x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x8 <t> x y)
 	// cond:
-	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
+	// result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v2.AddArg(v4)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(y)
 		v0.AddArg(v5)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux32 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux64 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
 		v1.AddArg(y)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(x)
 		v3.AddArg(v4)
 		v3.AddArg(y)
@@ -8208,121 +8415,133 @@ func rewriteValueMIPS64_OpRsh8Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux8 <t> x y)
 	// cond:
-	// result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
+	// result: (AND (NEGV <t> (SGTU (Const64 <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64AND)
-		v0 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v1 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v2.AuxInt = 64
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
-		v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64SRLV, t)
+		v5 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v.AddArg(v4)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt16to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x32 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <typ.UInt64> [63]))) (ZeroExt32to64 y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x64 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <typ.UInt64> [63]))) y))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
 		v3.AddArg(y)
-		v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v4.AuxInt = 63
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8332,41 +8551,42 @@ func rewriteValueMIPS64_OpRsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x8 <t> x y)
 	// cond:
-	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
+	// result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <typ.UInt64> [63]))) (ZeroExt8to64  y)))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SRAV)
-		v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to64, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64OR, t)
-		v2 := b.NewValue0(v.Line, OpMIPS64NEGV, t)
-		v3 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpMIPS64OR, t)
+		v2 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v3 := b.NewValue0(v.Pos, OpMIPS64SGTU, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
 		v5.AuxInt = 63
 		v3.AddArg(v5)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
-		v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v6.AddArg(y)
 		v1.AddArg(v6)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSelect0_0(v *Value) bool {
 	// match: (Select0 (DIVVU _ (MOVVconst [1])))
 	// cond:
 	// result: (MOVVconst [0])
@@ -8375,6 +8595,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
 			break
@@ -8394,6 +8615,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8408,7 +8630,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Select0 (DIVV  (MOVVconst [c]) (MOVVconst [d])))
+	// match: (Select0 (DIVV (MOVVconst [c]) (MOVVconst [d])))
 	// cond:
 	// result: (MOVVconst [int64(c)%int64(d)])
 	for {
@@ -8416,6 +8638,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVV {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8438,6 +8661,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8454,9 +8678,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSelect1_0(v *Value) bool {
 	// match: (Select1 (MULVU x (MOVVconst [-1])))
 	// cond:
 	// result: (NEGV x)
@@ -8465,6 +8687,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8477,6 +8700,27 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU (MOVVconst [-1]) x))
+	// cond:
+	// result: (NEGV x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_0.AuxInt != -1 {
+			break
+		}
+		x := v_0.Args[1]
+		v.reset(OpMIPS64NEGV)
+		v.AddArg(x)
+		return true
+	}
 	// match: (Select1 (MULVU _ (MOVVconst [0])))
 	// cond:
 	// result: (MOVVconst [0])
@@ -8485,6 +8729,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
 			break
@@ -8496,6 +8741,26 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (Select1 (MULVU (MOVVconst [0]) _))
+	// cond:
+	// result: (MOVVconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpMIPS64MOVVconst)
+		v.AuxInt = 0
+		return true
+	}
 	// match: (Select1 (MULVU x (MOVVconst [1])))
 	// cond:
 	// result: x
@@ -8504,6 +8769,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8517,6 +8783,28 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU (MOVVconst [1]) x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_0.AuxInt != 1 {
+			break
+		}
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	// match: (Select1 (MULVU x (MOVVconst [c])))
 	// cond: isPowerOfTwo(c)
 	// result: (SLLVconst [log2(c)] x)
@@ -8525,6 +8813,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8539,6 +8828,29 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU (MOVVconst [c]) x))
+	// cond: isPowerOfTwo(c)
+	// result: (SLLVconst [log2(c)] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPS64MOVVconst {
+			break
+		}
+		c := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpMIPS64SLLVconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
 	// match: (Select1 (MULVU (MOVVconst [-1]) x))
 	// cond:
 	// result: (NEGV x)
@@ -8547,6 +8859,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8559,6 +8872,30 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU x (MOVVconst [-1])))
+	// cond:
+	// result: (NEGV x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpMIPS64NEGV)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueMIPS64_OpSelect1_10(v *Value) bool {
 	// match: (Select1 (MULVU (MOVVconst [0]) _))
 	// cond:
 	// result: (MOVVconst [0])
@@ -8567,6 +8904,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8578,6 +8916,26 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
+	// match: (Select1 (MULVU _ (MOVVconst [0])))
+	// cond:
+	// result: (MOVVconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpMIPS64MOVVconst)
+		v.AuxInt = 0
+		return true
+	}
 	// match: (Select1 (MULVU (MOVVconst [1]) x))
 	// cond:
 	// result: x
@@ -8586,6 +8944,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8599,6 +8958,28 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU x (MOVVconst [1])))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPS64MOVVconst {
+			break
+		}
+		if v_0_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
 	// match: (Select1 (MULVU (MOVVconst [c]) x))
 	// cond: isPowerOfTwo(c)
 	// result: (SLLVconst [log2(c)] x)
@@ -8607,6 +8988,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8621,6 +9003,29 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (Select1 (MULVU x (MOVVconst [c])))
+	// cond: isPowerOfTwo(c)
+	// result: (SLLVconst [log2(c)] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPS64MOVVconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpMIPS64SLLVconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
 	// match: (Select1 (DIVVU x (MOVVconst [1])))
 	// cond:
 	// result: x
@@ -8629,6 +9034,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8650,6 +9056,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
 		if v_0_1.Op != OpMIPS64MOVVconst {
@@ -8672,6 +9079,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64MULVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8686,7 +9094,33 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		v.AuxInt = c * d
 		return true
 	}
-	// match: (Select1 (DIVV  (MOVVconst [c]) (MOVVconst [d])))
+	// match: (Select1 (MULVU (MOVVconst [d]) (MOVVconst [c])))
+	// cond:
+	// result: (MOVVconst [c*d])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMIPS64MULVU {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpMIPS64MOVVconst {
+			break
+		}
+		d := v_0_0.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpMIPS64MOVVconst {
+			break
+		}
+		c := v_0_1.AuxInt
+		v.reset(OpMIPS64MOVVconst)
+		v.AuxInt = c * d
+		return true
+	}
+	return false
+}
+func rewriteValueMIPS64_OpSelect1_20(v *Value) bool {
+	// match: (Select1 (DIVV (MOVVconst [c]) (MOVVconst [d])))
 	// cond:
 	// result: (MOVVconst [int64(c)/int64(d)])
 	for {
@@ -8694,6 +9128,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVV {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8716,6 +9151,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpMIPS64DIVVU {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpMIPS64MOVVconst {
 			break
@@ -8732,9 +9168,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -8745,9 +9179,7 @@ func rewriteValueMIPS64_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSignExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt16to64_0(v *Value) bool {
 	// match: (SignExt16to64 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -8758,9 +9190,7 @@ func rewriteValueMIPS64_OpSignExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSignExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt32to64_0(v *Value) bool {
 	// match: (SignExt32to64 x)
 	// cond:
 	// result: (MOVWreg x)
@@ -8771,9 +9201,7 @@ func rewriteValueMIPS64_OpSignExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt8to16_0(v *Value) bool {
 	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -8784,9 +9212,7 @@ func rewriteValueMIPS64_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt8to32_0(v *Value) bool {
 	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -8797,9 +9223,7 @@ func rewriteValueMIPS64_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSignExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSignExt8to64_0(v *Value) bool {
 	// match: (SignExt8to64 x)
 	// cond:
 	// result: (MOVBreg x)
@@ -8810,30 +9234,24 @@ func rewriteValueMIPS64_OpSignExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (NORconst [0] (SRAVconst <t> (SUBVconst <t> x [1]) [63]))
+	// result: (SRAVconst (NEGV <t> x) [63])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(OpMIPS64NORconst)
-		v.AuxInt = 0
-		v0 := b.NewValue0(v.Line, OpMIPS64SRAVconst, t)
-		v0.AuxInt = 63
-		v1 := b.NewValue0(v.Line, OpMIPS64SUBVconst, t)
-		v1.AuxInt = 1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		v.reset(OpMIPS64SRAVconst)
+		v.AuxInt = 63
+		v0 := b.NewValue0(v.Pos, OpMIPS64NEGV, t)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueMIPS64_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -8848,52 +9266,53 @@ func rewriteValueMIPS64_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [1] ptr val mem)
-	// cond:
+func rewriteValueMIPS64_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(OpMIPS64MOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: !is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
@@ -8902,17 +9321,16 @@ func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: !is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type)
 	// result: (MOVVstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(!is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
@@ -8921,17 +9339,16 @@ func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (MOVFstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPS64MOVFstore)
@@ -8940,17 +9357,16 @@ func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpMIPS64MOVDstore)
@@ -8961,13 +9377,12 @@ func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub16_0(v *Value) bool {
 	// match: (Sub16 x y)
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBV)
@@ -8976,13 +9391,12 @@ func rewriteValueMIPS64_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub32_0(v *Value) bool {
 	// match: (Sub32 x y)
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBV)
@@ -8991,13 +9405,12 @@ func rewriteValueMIPS64_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (SUBF x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBF)
@@ -9006,13 +9419,12 @@ func rewriteValueMIPS64_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSub64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub64_0(v *Value) bool {
 	// match: (Sub64 x y)
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBV)
@@ -9021,13 +9433,12 @@ func rewriteValueMIPS64_OpSub64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (SUBD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBD)
@@ -9036,13 +9447,12 @@ func rewriteValueMIPS64_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSub8_0(v *Value) bool {
 	// match: (Sub8 x y)
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBV)
@@ -9051,13 +9461,12 @@ func rewriteValueMIPS64_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUBV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64SUBV)
@@ -9066,9 +9475,7 @@ func rewriteValueMIPS64_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc16to8_0(v *Value) bool {
 	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
@@ -9080,9 +9487,7 @@ func rewriteValueMIPS64_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -9094,9 +9499,7 @@ func rewriteValueMIPS64_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc32to8_0(v *Value) bool {
 	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
@@ -9108,9 +9511,7 @@ func rewriteValueMIPS64_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc64to16_0(v *Value) bool {
 	// match: (Trunc64to16 x)
 	// cond:
 	// result: x
@@ -9122,9 +9523,7 @@ func rewriteValueMIPS64_OpTrunc64to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc64to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc64to32_0(v *Value) bool {
 	// match: (Trunc64to32 x)
 	// cond:
 	// result: x
@@ -9136,9 +9535,7 @@ func rewriteValueMIPS64_OpTrunc64to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpTrunc64to8_0(v *Value) bool {
 	// match: (Trunc64to8 x)
 	// cond:
 	// result: x
@@ -9150,13 +9547,12 @@ func rewriteValueMIPS64_OpTrunc64to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
@@ -9165,13 +9561,12 @@ func rewriteValueMIPS64_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
@@ -9180,13 +9575,12 @@ func rewriteValueMIPS64_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpXor64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpXor64_0(v *Value) bool {
 	// match: (Xor64 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
@@ -9195,13 +9589,12 @@ func rewriteValueMIPS64_OpXor64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpXor8_0(v *Value) bool {
 	// match: (Xor8 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMIPS64XOR)
@@ -9210,161 +9603,175 @@ func rewriteValueMIPS64_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
+func rewriteValueMIPS64_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] ptr mem)
+	// cond:
 	// result: (MOVBstore ptr (MOVVconst [0]) mem)
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPS64MOVBstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [2] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore ptr (MOVVconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] ptr mem)
+	// cond:
 	// result: (MOVBstore [1] ptr (MOVVconst [0]) 		(MOVBstore [0] ptr (MOVVconst [0]) mem))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 1
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore ptr (MOVVconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [4] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [2] ptr (MOVVconst [0]) 		(MOVHstore [0] ptr (MOVVconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] ptr mem)
+	// cond:
 	// result: (MOVBstore [3] ptr (MOVVconst [0]) 		(MOVBstore [2] ptr (MOVVconst [0]) 			(MOVBstore [1] ptr (MOVVconst [0]) 				(MOVBstore [0] ptr (MOVVconst [0]) mem))))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 3
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v3.AuxInt = 1
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v5.AuxInt = 0
 		v5.AddArg(ptr)
-		v6 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v6.AuxInt = 0
 		v5.AddArg(v6)
 		v5.AddArg(mem)
@@ -9373,82 +9780,94 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Zero [8] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore ptr (MOVVconst [0]) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [8] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [4] ptr (MOVVconst [0]) 		(MOVWstore [0] ptr (MOVVconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [8] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [6] ptr (MOVVconst [0]) 		(MOVHstore [4] ptr (MOVVconst [0]) 			(MOVHstore [2] ptr (MOVVconst [0]) 				(MOVHstore [0] ptr (MOVVconst [0]) mem))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 6
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v3.AuxInt = 2
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v5 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v5.AuxInt = 0
 		v5.AddArg(ptr)
-		v6 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v6 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v6.AuxInt = 0
 		v5.AddArg(v6)
 		v5.AddArg(mem)
@@ -9457,32 +9876,41 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	return false
+}
+func rewriteValueMIPS64_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Zero [3] ptr mem)
+	// cond:
 	// result: (MOVBstore [2] ptr (MOVVconst [0]) 		(MOVBstore [1] ptr (MOVVconst [0]) 			(MOVBstore [0] ptr (MOVVconst [0]) mem)))
 	for {
-		s := v.AuxInt
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpMIPS64MOVBstore)
 		v.AuxInt = 2
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v1.AuxInt = 1
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVBstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -9490,32 +9918,36 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [6] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%2 == 0
 	// result: (MOVHstore [4] ptr (MOVVconst [0]) 		(MOVHstore [2] ptr (MOVVconst [0]) 			(MOVHstore [0] ptr (MOVVconst [0]) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+		if !(t.(*types.Type).Alignment()%2 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVHstore)
 		v.AuxInt = 4
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v1.AuxInt = 2
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVHstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -9523,32 +9955,36 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [12] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
 	// result: (MOVWstore [8] ptr (MOVVconst [0]) 		(MOVWstore [4] ptr (MOVVconst [0]) 			(MOVWstore [0] ptr (MOVVconst [0]) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 12 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVWstore)
 		v.AuxInt = 8
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVWstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -9556,58 +9992,66 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Zero [16] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore [8] ptr (MOVVconst [0]) 		(MOVVstore [0] ptr (MOVVconst [0]) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AuxInt = 8
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0
+	// match: (Zero [24] {t} ptr mem)
+	// cond: t.(*types.Type).Alignment()%8 == 0
 	// result: (MOVVstore [16] ptr (MOVVconst [0]) 		(MOVVstore [8] ptr (MOVVconst [0]) 			(MOVVstore [0] ptr (MOVVconst [0]) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 24 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+		if !(t.(*types.Type).Alignment()%8 == 0) {
 			break
 		}
 		v.reset(OpMIPS64MOVVstore)
 		v.AuxInt = 16
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(ptr)
-		v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v2.AuxInt = 0
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpMIPS64MOVVstore, types.TypeMem)
 		v3.AuxInt = 0
 		v3.AddArg(ptr)
-		v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpMIPS64MOVVconst, typ.UInt64)
 		v4.AuxInt = 0
 		v3.AddArg(v4)
 		v3.AddArg(mem)
@@ -9615,37 +10059,41 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 	&& SizeAndAlign(s).Align()%8 == 0 && !config.noDuffDevice
-	// result: (DUFFZERO [8 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
+	// match: (Zero [s] {t} ptr mem)
+	// cond: s%8 == 0 && s > 24 && s <= 8*128 	&& t.(*types.Type).Alignment()%8 == 0 && !config.noDuffDevice
+	// result: (DUFFZERO [8 * (128 - int64(s/8))] ptr mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128 && SizeAndAlign(s).Align()%8 == 0 && !config.noDuffDevice) {
+		if !(s%8 == 0 && s > 24 && s <= 8*128 && t.(*types.Type).Alignment()%8 == 0 && !config.noDuffDevice) {
 			break
 		}
 		v.reset(OpMIPS64DUFFZERO)
-		v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/8))
+		v.AuxInt = 8 * (128 - int64(s/8))
 		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] ptr mem)
-	// cond: (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0
-	// result: (LoweredZero [SizeAndAlign(s).Align()] 		ptr 		(ADDVconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// match: (Zero [s] {t} ptr mem)
+	// cond: (s > 8*128 || config.noDuffDevice) || t.(*types.Type).Alignment()%8 != 0
+	// result: (LoweredZero [t.(*types.Type).Alignment()] 		ptr 		(ADDVconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)]) 		mem)
 	for {
 		s := v.AuxInt
+		t := v.Aux
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !((SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0) {
+		if !((s > 8*128 || config.noDuffDevice) || t.(*types.Type).Alignment()%8 != 0) {
 			break
 		}
 		v.reset(OpMIPS64LoweredZero)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = t.(*types.Type).Alignment()
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpMIPS64ADDVconst, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+		v0 := b.NewValue0(v.Pos, OpMIPS64ADDVconst, ptr.Type)
+		v0.AuxInt = s - moveSize(t.(*types.Type).Alignment(), config)
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -9653,9 +10101,7 @@ func rewriteValueMIPS64_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueMIPS64_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -9666,9 +10112,7 @@ func rewriteValueMIPS64_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt16to64_0(v *Value) bool {
 	// match: (ZeroExt16to64 x)
 	// cond:
 	// result: (MOVHUreg x)
@@ -9679,9 +10123,7 @@ func rewriteValueMIPS64_OpZeroExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt32to64_0(v *Value) bool {
 	// match: (ZeroExt32to64 x)
 	// cond:
 	// result: (MOVWUreg x)
@@ -9692,9 +10134,7 @@ func rewriteValueMIPS64_OpZeroExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt8to16_0(v *Value) bool {
 	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -9705,9 +10145,7 @@ func rewriteValueMIPS64_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt8to32_0(v *Value) bool {
 	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -9718,9 +10156,7 @@ func rewriteValueMIPS64_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueMIPS64_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueMIPS64_OpZeroExt8to64_0(v *Value) bool {
 	// match: (ZeroExt8to64 x)
 	// cond:
 	// result: (MOVBUreg x)
@@ -9731,7 +10167,13 @@ func rewriteValueMIPS64_OpZeroExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlockMIPS64(b *Block, config *Config) bool {
+func rewriteBlockMIPS64(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockMIPS64EQ:
 		// match: (EQ (FPFlagTrue cmp) yes no)
@@ -9743,12 +10185,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64FPF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FPFlagFalse cmp) yes no)
@@ -9760,12 +10198,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64FPT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGT _ _)) yes no)
@@ -9783,12 +10217,9 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
@@ -9806,12 +10237,9 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTU {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
@@ -9829,12 +10257,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (XORconst [1] cmp:(SGTUconst _)) yes no)
@@ -9852,12 +10276,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTUconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTUconst [1] x) yes no)
@@ -9872,12 +10292,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTU x (MOVVconst [0])) yes no)
@@ -9888,6 +10304,7 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.Op != OpMIPS64SGTU {
 				break
 			}
+			_ = v.Args[1]
 			x := v.Args[0]
 			v_1 := v.Args[1]
 			if v_1.Op != OpMIPS64MOVVconst {
@@ -9896,12 +10313,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v_1.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGTconst [0] x) yes no)
@@ -9916,12 +10329,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64GEZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (SGT x (MOVVconst [0])) yes no)
@@ -9932,6 +10341,7 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.Op != OpMIPS64SGT {
 				break
 			}
+			_ = v.Args[1]
 			x := v.Args[0]
 			v_1 := v.Args[1]
 			if v_1.Op != OpMIPS64MOVVconst {
@@ -9940,15 +10350,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v_1.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64LEZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (EQ  (MOVVconst [0]) yes no)
+		// match: (EQ (MOVVconst [0]) yes no)
 		// cond:
 		// result: (First nil yes no)
 		for {
@@ -9959,15 +10365,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (EQ  (MOVVconst [c]) yes no)
+		// match: (EQ (MOVVconst [c]) yes no)
 		// cond: c != 0
 		// result: (First nil no yes)
 		for {
@@ -9976,16 +10378,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockMIPS64GEZ:
@@ -9998,15 +10396,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c >= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GEZ (MOVVconst [c]) yes no)
@@ -10018,16 +10412,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockMIPS64GTZ:
@@ -10040,15 +10430,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c > 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GTZ (MOVVconst [c]) yes no)
@@ -10060,16 +10446,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockIf:
@@ -10080,12 +10462,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(cond)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockMIPS64LEZ:
@@ -10098,15 +10476,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c <= 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LEZ (MOVVconst [c]) yes no)
@@ -10118,16 +10492,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockMIPS64LTZ:
@@ -10140,15 +10510,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c < 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LTZ (MOVVconst [c]) yes no)
@@ -10160,16 +10526,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				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
 		}
 	case BlockMIPS64NE:
@@ -10182,12 +10544,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64FPT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FPFlagFalse cmp) yes no)
@@ -10199,12 +10557,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64FPF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGT _ _)) yes no)
@@ -10222,12 +10576,9 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
@@ -10245,12 +10596,9 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTU {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
+			_ = cmp.Args[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
@@ -10268,12 +10616,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (XORconst [1] cmp:(SGTUconst _)) yes no)
@@ -10291,12 +10635,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if cmp.Op != OpMIPS64SGTUconst {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTUconst [1] x) yes no)
@@ -10311,12 +10651,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64EQ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTU x (MOVVconst [0])) yes no)
@@ -10327,6 +10663,7 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.Op != OpMIPS64SGTU {
 				break
 			}
+			_ = v.Args[1]
 			x := v.Args[0]
 			v_1 := v.Args[1]
 			if v_1.Op != OpMIPS64MOVVconst {
@@ -10335,12 +10672,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v_1.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64NE
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGTconst [0] x) yes no)
@@ -10355,12 +10688,8 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			x := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64LTZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (SGT x (MOVVconst [0])) yes no)
@@ -10371,6 +10700,7 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.Op != OpMIPS64SGT {
 				break
 			}
+			_ = v.Args[1]
 			x := v.Args[0]
 			v_1 := v.Args[1]
 			if v_1.Op != OpMIPS64MOVVconst {
@@ -10379,15 +10709,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v_1.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockMIPS64GTZ
 			b.SetControl(x)
-			_ = yes
-			_ = no
 			return true
 		}
-		// match: (NE  (MOVVconst [0]) yes no)
+		// match: (NE (MOVVconst [0]) yes no)
 		// cond:
 		// result: (First nil no yes)
 		for {
@@ -10398,16 +10724,12 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 			if v.AuxInt != 0 {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
-		// match: (NE  (MOVVconst [c]) yes no)
+		// match: (NE (MOVVconst [c]) yes no)
 		// cond: c != 0
 		// result: (First nil yes no)
 		for {
@@ -10416,15 +10738,11 @@ func rewriteBlockMIPS64(b *Block, config *Config) bool {
 				break
 			}
 			c := v.AuxInt
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			if !(c != 0) {
 				break
 			}
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 031459c..20e354c 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -1,583 +1,631 @@
-// autogenerated from gen/PPC64.rules: do not edit!
+// Code generated from gen/PPC64.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValuePPC64(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValuePPC64(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
-		return rewriteValuePPC64_OpAdd16(v, config)
+		return rewriteValuePPC64_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValuePPC64_OpAdd32(v, config)
+		return rewriteValuePPC64_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValuePPC64_OpAdd32F(v, config)
+		return rewriteValuePPC64_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValuePPC64_OpAdd64(v, config)
+		return rewriteValuePPC64_OpAdd64_0(v)
 	case OpAdd64F:
-		return rewriteValuePPC64_OpAdd64F(v, config)
+		return rewriteValuePPC64_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValuePPC64_OpAdd8(v, config)
+		return rewriteValuePPC64_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValuePPC64_OpAddPtr(v, config)
+		return rewriteValuePPC64_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValuePPC64_OpAddr(v, config)
+		return rewriteValuePPC64_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValuePPC64_OpAnd16(v, config)
+		return rewriteValuePPC64_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValuePPC64_OpAnd32(v, config)
+		return rewriteValuePPC64_OpAnd32_0(v)
 	case OpAnd64:
-		return rewriteValuePPC64_OpAnd64(v, config)
+		return rewriteValuePPC64_OpAnd64_0(v)
 	case OpAnd8:
-		return rewriteValuePPC64_OpAnd8(v, config)
+		return rewriteValuePPC64_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValuePPC64_OpAndB(v, config)
+		return rewriteValuePPC64_OpAndB_0(v)
+	case OpAtomicAdd32:
+		return rewriteValuePPC64_OpAtomicAdd32_0(v)
+	case OpAtomicAdd64:
+		return rewriteValuePPC64_OpAtomicAdd64_0(v)
+	case OpAtomicAnd8:
+		return rewriteValuePPC64_OpAtomicAnd8_0(v)
+	case OpAtomicCompareAndSwap32:
+		return rewriteValuePPC64_OpAtomicCompareAndSwap32_0(v)
+	case OpAtomicCompareAndSwap64:
+		return rewriteValuePPC64_OpAtomicCompareAndSwap64_0(v)
+	case OpAtomicExchange32:
+		return rewriteValuePPC64_OpAtomicExchange32_0(v)
+	case OpAtomicExchange64:
+		return rewriteValuePPC64_OpAtomicExchange64_0(v)
+	case OpAtomicLoad32:
+		return rewriteValuePPC64_OpAtomicLoad32_0(v)
+	case OpAtomicLoad64:
+		return rewriteValuePPC64_OpAtomicLoad64_0(v)
+	case OpAtomicLoadPtr:
+		return rewriteValuePPC64_OpAtomicLoadPtr_0(v)
+	case OpAtomicOr8:
+		return rewriteValuePPC64_OpAtomicOr8_0(v)
+	case OpAtomicStore32:
+		return rewriteValuePPC64_OpAtomicStore32_0(v)
+	case OpAtomicStore64:
+		return rewriteValuePPC64_OpAtomicStore64_0(v)
 	case OpAvg64u:
-		return rewriteValuePPC64_OpAvg64u(v, config)
+		return rewriteValuePPC64_OpAvg64u_0(v)
+	case OpBitLen32:
+		return rewriteValuePPC64_OpBitLen32_0(v)
+	case OpBitLen64:
+		return rewriteValuePPC64_OpBitLen64_0(v)
 	case OpClosureCall:
-		return rewriteValuePPC64_OpClosureCall(v, config)
+		return rewriteValuePPC64_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValuePPC64_OpCom16(v, config)
+		return rewriteValuePPC64_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValuePPC64_OpCom32(v, config)
+		return rewriteValuePPC64_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValuePPC64_OpCom64(v, config)
+		return rewriteValuePPC64_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValuePPC64_OpCom8(v, config)
+		return rewriteValuePPC64_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValuePPC64_OpConst16(v, config)
+		return rewriteValuePPC64_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValuePPC64_OpConst32(v, config)
+		return rewriteValuePPC64_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValuePPC64_OpConst32F(v, config)
+		return rewriteValuePPC64_OpConst32F_0(v)
 	case OpConst64:
-		return rewriteValuePPC64_OpConst64(v, config)
+		return rewriteValuePPC64_OpConst64_0(v)
 	case OpConst64F:
-		return rewriteValuePPC64_OpConst64F(v, config)
+		return rewriteValuePPC64_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValuePPC64_OpConst8(v, config)
+		return rewriteValuePPC64_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValuePPC64_OpConstBool(v, config)
+		return rewriteValuePPC64_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValuePPC64_OpConstNil(v, config)
+		return rewriteValuePPC64_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValuePPC64_OpConvert(v, config)
+		return rewriteValuePPC64_OpConvert_0(v)
+	case OpCtz32:
+		return rewriteValuePPC64_OpCtz32_0(v)
+	case OpCtz64:
+		return rewriteValuePPC64_OpCtz64_0(v)
 	case OpCvt32Fto32:
-		return rewriteValuePPC64_OpCvt32Fto32(v, config)
+		return rewriteValuePPC64_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64:
-		return rewriteValuePPC64_OpCvt32Fto64(v, config)
+		return rewriteValuePPC64_OpCvt32Fto64_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValuePPC64_OpCvt32Fto64F(v, config)
+		return rewriteValuePPC64_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValuePPC64_OpCvt32to32F(v, config)
+		return rewriteValuePPC64_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValuePPC64_OpCvt32to64F(v, config)
+		return rewriteValuePPC64_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValuePPC64_OpCvt64Fto32(v, config)
+		return rewriteValuePPC64_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValuePPC64_OpCvt64Fto32F(v, config)
+		return rewriteValuePPC64_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto64:
-		return rewriteValuePPC64_OpCvt64Fto64(v, config)
+		return rewriteValuePPC64_OpCvt64Fto64_0(v)
 	case OpCvt64to32F:
-		return rewriteValuePPC64_OpCvt64to32F(v, config)
+		return rewriteValuePPC64_OpCvt64to32F_0(v)
 	case OpCvt64to64F:
-		return rewriteValuePPC64_OpCvt64to64F(v, config)
-	case OpDeferCall:
-		return rewriteValuePPC64_OpDeferCall(v, config)
+		return rewriteValuePPC64_OpCvt64to64F_0(v)
 	case OpDiv16:
-		return rewriteValuePPC64_OpDiv16(v, config)
+		return rewriteValuePPC64_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValuePPC64_OpDiv16u(v, config)
+		return rewriteValuePPC64_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValuePPC64_OpDiv32(v, config)
+		return rewriteValuePPC64_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValuePPC64_OpDiv32F(v, config)
+		return rewriteValuePPC64_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValuePPC64_OpDiv32u(v, config)
+		return rewriteValuePPC64_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValuePPC64_OpDiv64(v, config)
+		return rewriteValuePPC64_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValuePPC64_OpDiv64F(v, config)
+		return rewriteValuePPC64_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValuePPC64_OpDiv64u(v, config)
+		return rewriteValuePPC64_OpDiv64u_0(v)
 	case OpDiv8:
-		return rewriteValuePPC64_OpDiv8(v, config)
+		return rewriteValuePPC64_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValuePPC64_OpDiv8u(v, config)
+		return rewriteValuePPC64_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValuePPC64_OpEq16(v, config)
+		return rewriteValuePPC64_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValuePPC64_OpEq32(v, config)
+		return rewriteValuePPC64_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValuePPC64_OpEq32F(v, config)
+		return rewriteValuePPC64_OpEq32F_0(v)
 	case OpEq64:
-		return rewriteValuePPC64_OpEq64(v, config)
+		return rewriteValuePPC64_OpEq64_0(v)
 	case OpEq64F:
-		return rewriteValuePPC64_OpEq64F(v, config)
+		return rewriteValuePPC64_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValuePPC64_OpEq8(v, config)
+		return rewriteValuePPC64_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValuePPC64_OpEqB(v, config)
+		return rewriteValuePPC64_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValuePPC64_OpEqPtr(v, config)
+		return rewriteValuePPC64_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValuePPC64_OpGeq16(v, config)
+		return rewriteValuePPC64_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValuePPC64_OpGeq16U(v, config)
+		return rewriteValuePPC64_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValuePPC64_OpGeq32(v, config)
+		return rewriteValuePPC64_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValuePPC64_OpGeq32F(v, config)
+		return rewriteValuePPC64_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValuePPC64_OpGeq32U(v, config)
+		return rewriteValuePPC64_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValuePPC64_OpGeq64(v, config)
+		return rewriteValuePPC64_OpGeq64_0(v)
 	case OpGeq64F:
-		return rewriteValuePPC64_OpGeq64F(v, config)
+		return rewriteValuePPC64_OpGeq64F_0(v)
 	case OpGeq64U:
-		return rewriteValuePPC64_OpGeq64U(v, config)
+		return rewriteValuePPC64_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValuePPC64_OpGeq8(v, config)
+		return rewriteValuePPC64_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValuePPC64_OpGeq8U(v, config)
+		return rewriteValuePPC64_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValuePPC64_OpGetClosurePtr(v, config)
-	case OpGoCall:
-		return rewriteValuePPC64_OpGoCall(v, config)
+		return rewriteValuePPC64_OpGetClosurePtr_0(v)
 	case OpGreater16:
-		return rewriteValuePPC64_OpGreater16(v, config)
+		return rewriteValuePPC64_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValuePPC64_OpGreater16U(v, config)
+		return rewriteValuePPC64_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValuePPC64_OpGreater32(v, config)
+		return rewriteValuePPC64_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValuePPC64_OpGreater32F(v, config)
+		return rewriteValuePPC64_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValuePPC64_OpGreater32U(v, config)
+		return rewriteValuePPC64_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValuePPC64_OpGreater64(v, config)
+		return rewriteValuePPC64_OpGreater64_0(v)
 	case OpGreater64F:
-		return rewriteValuePPC64_OpGreater64F(v, config)
+		return rewriteValuePPC64_OpGreater64F_0(v)
 	case OpGreater64U:
-		return rewriteValuePPC64_OpGreater64U(v, config)
+		return rewriteValuePPC64_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValuePPC64_OpGreater8(v, config)
+		return rewriteValuePPC64_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValuePPC64_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValuePPC64_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValuePPC64_OpHmul16u(v, config)
+		return rewriteValuePPC64_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValuePPC64_OpHmul32(v, config)
+		return rewriteValuePPC64_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValuePPC64_OpHmul32u(v, config)
+		return rewriteValuePPC64_OpHmul32u_0(v)
 	case OpHmul64:
-		return rewriteValuePPC64_OpHmul64(v, config)
+		return rewriteValuePPC64_OpHmul64_0(v)
 	case OpHmul64u:
-		return rewriteValuePPC64_OpHmul64u(v, config)
-	case OpHmul8:
-		return rewriteValuePPC64_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValuePPC64_OpHmul8u(v, config)
+		return rewriteValuePPC64_OpHmul64u_0(v)
 	case OpInterCall:
-		return rewriteValuePPC64_OpInterCall(v, config)
+		return rewriteValuePPC64_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValuePPC64_OpIsInBounds(v, config)
+		return rewriteValuePPC64_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValuePPC64_OpIsNonNil(v, config)
+		return rewriteValuePPC64_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValuePPC64_OpIsSliceInBounds(v, config)
+		return rewriteValuePPC64_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValuePPC64_OpLeq16(v, config)
+		return rewriteValuePPC64_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValuePPC64_OpLeq16U(v, config)
+		return rewriteValuePPC64_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValuePPC64_OpLeq32(v, config)
+		return rewriteValuePPC64_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValuePPC64_OpLeq32F(v, config)
+		return rewriteValuePPC64_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValuePPC64_OpLeq32U(v, config)
+		return rewriteValuePPC64_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValuePPC64_OpLeq64(v, config)
+		return rewriteValuePPC64_OpLeq64_0(v)
 	case OpLeq64F:
-		return rewriteValuePPC64_OpLeq64F(v, config)
+		return rewriteValuePPC64_OpLeq64F_0(v)
 	case OpLeq64U:
-		return rewriteValuePPC64_OpLeq64U(v, config)
+		return rewriteValuePPC64_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValuePPC64_OpLeq8(v, config)
+		return rewriteValuePPC64_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValuePPC64_OpLeq8U(v, config)
+		return rewriteValuePPC64_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValuePPC64_OpLess16(v, config)
+		return rewriteValuePPC64_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValuePPC64_OpLess16U(v, config)
+		return rewriteValuePPC64_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValuePPC64_OpLess32(v, config)
+		return rewriteValuePPC64_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValuePPC64_OpLess32F(v, config)
+		return rewriteValuePPC64_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValuePPC64_OpLess32U(v, config)
+		return rewriteValuePPC64_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValuePPC64_OpLess64(v, config)
+		return rewriteValuePPC64_OpLess64_0(v)
 	case OpLess64F:
-		return rewriteValuePPC64_OpLess64F(v, config)
+		return rewriteValuePPC64_OpLess64F_0(v)
 	case OpLess64U:
-		return rewriteValuePPC64_OpLess64U(v, config)
+		return rewriteValuePPC64_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValuePPC64_OpLess8(v, config)
+		return rewriteValuePPC64_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValuePPC64_OpLess8U(v, config)
+		return rewriteValuePPC64_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValuePPC64_OpLoad(v, config)
+		return rewriteValuePPC64_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValuePPC64_OpLsh16x16(v, config)
+		return rewriteValuePPC64_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValuePPC64_OpLsh16x32(v, config)
+		return rewriteValuePPC64_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValuePPC64_OpLsh16x64(v, config)
+		return rewriteValuePPC64_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValuePPC64_OpLsh16x8(v, config)
+		return rewriteValuePPC64_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValuePPC64_OpLsh32x16(v, config)
+		return rewriteValuePPC64_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValuePPC64_OpLsh32x32(v, config)
+		return rewriteValuePPC64_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValuePPC64_OpLsh32x64(v, config)
+		return rewriteValuePPC64_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValuePPC64_OpLsh32x8(v, config)
+		return rewriteValuePPC64_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValuePPC64_OpLsh64x16(v, config)
+		return rewriteValuePPC64_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValuePPC64_OpLsh64x32(v, config)
+		return rewriteValuePPC64_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValuePPC64_OpLsh64x64(v, config)
+		return rewriteValuePPC64_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValuePPC64_OpLsh64x8(v, config)
+		return rewriteValuePPC64_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValuePPC64_OpLsh8x16(v, config)
+		return rewriteValuePPC64_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValuePPC64_OpLsh8x32(v, config)
+		return rewriteValuePPC64_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValuePPC64_OpLsh8x64(v, config)
+		return rewriteValuePPC64_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValuePPC64_OpLsh8x8(v, config)
+		return rewriteValuePPC64_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValuePPC64_OpMod16(v, config)
+		return rewriteValuePPC64_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValuePPC64_OpMod16u(v, config)
+		return rewriteValuePPC64_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValuePPC64_OpMod32(v, config)
+		return rewriteValuePPC64_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValuePPC64_OpMod32u(v, config)
+		return rewriteValuePPC64_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValuePPC64_OpMod64(v, config)
+		return rewriteValuePPC64_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValuePPC64_OpMod64u(v, config)
+		return rewriteValuePPC64_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValuePPC64_OpMod8(v, config)
+		return rewriteValuePPC64_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValuePPC64_OpMod8u(v, config)
+		return rewriteValuePPC64_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValuePPC64_OpMove(v, config)
+		return rewriteValuePPC64_OpMove_0(v) || rewriteValuePPC64_OpMove_10(v)
 	case OpMul16:
-		return rewriteValuePPC64_OpMul16(v, config)
+		return rewriteValuePPC64_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValuePPC64_OpMul32(v, config)
+		return rewriteValuePPC64_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValuePPC64_OpMul32F(v, config)
+		return rewriteValuePPC64_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValuePPC64_OpMul64(v, config)
+		return rewriteValuePPC64_OpMul64_0(v)
 	case OpMul64F:
-		return rewriteValuePPC64_OpMul64F(v, config)
+		return rewriteValuePPC64_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValuePPC64_OpMul8(v, config)
+		return rewriteValuePPC64_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValuePPC64_OpNeg16(v, config)
+		return rewriteValuePPC64_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValuePPC64_OpNeg32(v, config)
+		return rewriteValuePPC64_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValuePPC64_OpNeg32F(v, config)
+		return rewriteValuePPC64_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValuePPC64_OpNeg64(v, config)
+		return rewriteValuePPC64_OpNeg64_0(v)
 	case OpNeg64F:
-		return rewriteValuePPC64_OpNeg64F(v, config)
+		return rewriteValuePPC64_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValuePPC64_OpNeg8(v, config)
+		return rewriteValuePPC64_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValuePPC64_OpNeq16(v, config)
+		return rewriteValuePPC64_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValuePPC64_OpNeq32(v, config)
+		return rewriteValuePPC64_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValuePPC64_OpNeq32F(v, config)
+		return rewriteValuePPC64_OpNeq32F_0(v)
 	case OpNeq64:
-		return rewriteValuePPC64_OpNeq64(v, config)
+		return rewriteValuePPC64_OpNeq64_0(v)
 	case OpNeq64F:
-		return rewriteValuePPC64_OpNeq64F(v, config)
+		return rewriteValuePPC64_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValuePPC64_OpNeq8(v, config)
+		return rewriteValuePPC64_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValuePPC64_OpNeqB(v, config)
+		return rewriteValuePPC64_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValuePPC64_OpNeqPtr(v, config)
+		return rewriteValuePPC64_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValuePPC64_OpNilCheck(v, config)
+		return rewriteValuePPC64_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValuePPC64_OpNot(v, config)
+		return rewriteValuePPC64_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValuePPC64_OpOffPtr(v, config)
+		return rewriteValuePPC64_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValuePPC64_OpOr16(v, config)
+		return rewriteValuePPC64_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValuePPC64_OpOr32(v, config)
+		return rewriteValuePPC64_OpOr32_0(v)
 	case OpOr64:
-		return rewriteValuePPC64_OpOr64(v, config)
+		return rewriteValuePPC64_OpOr64_0(v)
 	case OpOr8:
-		return rewriteValuePPC64_OpOr8(v, config)
+		return rewriteValuePPC64_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValuePPC64_OpOrB(v, config)
+		return rewriteValuePPC64_OpOrB_0(v)
 	case OpPPC64ADD:
-		return rewriteValuePPC64_OpPPC64ADD(v, config)
+		return rewriteValuePPC64_OpPPC64ADD_0(v)
 	case OpPPC64ADDconst:
-		return rewriteValuePPC64_OpPPC64ADDconst(v, config)
+		return rewriteValuePPC64_OpPPC64ADDconst_0(v)
 	case OpPPC64AND:
-		return rewriteValuePPC64_OpPPC64AND(v, config)
+		return rewriteValuePPC64_OpPPC64AND_0(v)
 	case OpPPC64ANDconst:
-		return rewriteValuePPC64_OpPPC64ANDconst(v, config)
+		return rewriteValuePPC64_OpPPC64ANDconst_0(v)
 	case OpPPC64CMP:
-		return rewriteValuePPC64_OpPPC64CMP(v, config)
+		return rewriteValuePPC64_OpPPC64CMP_0(v)
 	case OpPPC64CMPU:
-		return rewriteValuePPC64_OpPPC64CMPU(v, config)
+		return rewriteValuePPC64_OpPPC64CMPU_0(v)
 	case OpPPC64CMPUconst:
-		return rewriteValuePPC64_OpPPC64CMPUconst(v, config)
+		return rewriteValuePPC64_OpPPC64CMPUconst_0(v)
 	case OpPPC64CMPW:
-		return rewriteValuePPC64_OpPPC64CMPW(v, config)
+		return rewriteValuePPC64_OpPPC64CMPW_0(v)
 	case OpPPC64CMPWU:
-		return rewriteValuePPC64_OpPPC64CMPWU(v, config)
+		return rewriteValuePPC64_OpPPC64CMPWU_0(v)
 	case OpPPC64CMPWUconst:
-		return rewriteValuePPC64_OpPPC64CMPWUconst(v, config)
+		return rewriteValuePPC64_OpPPC64CMPWUconst_0(v)
 	case OpPPC64CMPWconst:
-		return rewriteValuePPC64_OpPPC64CMPWconst(v, config)
+		return rewriteValuePPC64_OpPPC64CMPWconst_0(v)
 	case OpPPC64CMPconst:
-		return rewriteValuePPC64_OpPPC64CMPconst(v, config)
+		return rewriteValuePPC64_OpPPC64CMPconst_0(v)
 	case OpPPC64Equal:
-		return rewriteValuePPC64_OpPPC64Equal(v, config)
+		return rewriteValuePPC64_OpPPC64Equal_0(v)
+	case OpPPC64FADD:
+		return rewriteValuePPC64_OpPPC64FADD_0(v)
+	case OpPPC64FADDS:
+		return rewriteValuePPC64_OpPPC64FADDS_0(v)
 	case OpPPC64FMOVDload:
-		return rewriteValuePPC64_OpPPC64FMOVDload(v, config)
+		return rewriteValuePPC64_OpPPC64FMOVDload_0(v)
 	case OpPPC64FMOVDstore:
-		return rewriteValuePPC64_OpPPC64FMOVDstore(v, config)
+		return rewriteValuePPC64_OpPPC64FMOVDstore_0(v)
 	case OpPPC64FMOVSload:
-		return rewriteValuePPC64_OpPPC64FMOVSload(v, config)
+		return rewriteValuePPC64_OpPPC64FMOVSload_0(v)
 	case OpPPC64FMOVSstore:
-		return rewriteValuePPC64_OpPPC64FMOVSstore(v, config)
+		return rewriteValuePPC64_OpPPC64FMOVSstore_0(v)
+	case OpPPC64FSUB:
+		return rewriteValuePPC64_OpPPC64FSUB_0(v)
+	case OpPPC64FSUBS:
+		return rewriteValuePPC64_OpPPC64FSUBS_0(v)
 	case OpPPC64GreaterEqual:
-		return rewriteValuePPC64_OpPPC64GreaterEqual(v, config)
+		return rewriteValuePPC64_OpPPC64GreaterEqual_0(v)
 	case OpPPC64GreaterThan:
-		return rewriteValuePPC64_OpPPC64GreaterThan(v, config)
+		return rewriteValuePPC64_OpPPC64GreaterThan_0(v)
 	case OpPPC64LessEqual:
-		return rewriteValuePPC64_OpPPC64LessEqual(v, config)
+		return rewriteValuePPC64_OpPPC64LessEqual_0(v)
 	case OpPPC64LessThan:
-		return rewriteValuePPC64_OpPPC64LessThan(v, config)
+		return rewriteValuePPC64_OpPPC64LessThan_0(v)
 	case OpPPC64MOVBZload:
-		return rewriteValuePPC64_OpPPC64MOVBZload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVBZload_0(v)
 	case OpPPC64MOVBZreg:
-		return rewriteValuePPC64_OpPPC64MOVBZreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVBZreg_0(v)
 	case OpPPC64MOVBreg:
-		return rewriteValuePPC64_OpPPC64MOVBreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVBreg_0(v)
 	case OpPPC64MOVBstore:
-		return rewriteValuePPC64_OpPPC64MOVBstore(v, config)
+		return rewriteValuePPC64_OpPPC64MOVBstore_0(v)
 	case OpPPC64MOVBstorezero:
-		return rewriteValuePPC64_OpPPC64MOVBstorezero(v, config)
+		return rewriteValuePPC64_OpPPC64MOVBstorezero_0(v)
 	case OpPPC64MOVDload:
-		return rewriteValuePPC64_OpPPC64MOVDload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVDload_0(v)
 	case OpPPC64MOVDstore:
-		return rewriteValuePPC64_OpPPC64MOVDstore(v, config)
+		return rewriteValuePPC64_OpPPC64MOVDstore_0(v)
 	case OpPPC64MOVDstorezero:
-		return rewriteValuePPC64_OpPPC64MOVDstorezero(v, config)
+		return rewriteValuePPC64_OpPPC64MOVDstorezero_0(v)
 	case OpPPC64MOVHZload:
-		return rewriteValuePPC64_OpPPC64MOVHZload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHZload_0(v)
 	case OpPPC64MOVHZreg:
-		return rewriteValuePPC64_OpPPC64MOVHZreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHZreg_0(v)
 	case OpPPC64MOVHload:
-		return rewriteValuePPC64_OpPPC64MOVHload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHload_0(v)
 	case OpPPC64MOVHreg:
-		return rewriteValuePPC64_OpPPC64MOVHreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHreg_0(v)
 	case OpPPC64MOVHstore:
-		return rewriteValuePPC64_OpPPC64MOVHstore(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHstore_0(v)
 	case OpPPC64MOVHstorezero:
-		return rewriteValuePPC64_OpPPC64MOVHstorezero(v, config)
+		return rewriteValuePPC64_OpPPC64MOVHstorezero_0(v)
 	case OpPPC64MOVWZload:
-		return rewriteValuePPC64_OpPPC64MOVWZload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWZload_0(v)
 	case OpPPC64MOVWZreg:
-		return rewriteValuePPC64_OpPPC64MOVWZreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWZreg_0(v)
 	case OpPPC64MOVWload:
-		return rewriteValuePPC64_OpPPC64MOVWload(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWload_0(v)
 	case OpPPC64MOVWreg:
-		return rewriteValuePPC64_OpPPC64MOVWreg(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWreg_0(v)
 	case OpPPC64MOVWstore:
-		return rewriteValuePPC64_OpPPC64MOVWstore(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWstore_0(v)
 	case OpPPC64MOVWstorezero:
-		return rewriteValuePPC64_OpPPC64MOVWstorezero(v, config)
+		return rewriteValuePPC64_OpPPC64MOVWstorezero_0(v)
 	case OpPPC64MaskIfNotCarry:
-		return rewriteValuePPC64_OpPPC64MaskIfNotCarry(v, config)
+		return rewriteValuePPC64_OpPPC64MaskIfNotCarry_0(v)
 	case OpPPC64NotEqual:
-		return rewriteValuePPC64_OpPPC64NotEqual(v, config)
+		return rewriteValuePPC64_OpPPC64NotEqual_0(v)
 	case OpPPC64OR:
-		return rewriteValuePPC64_OpPPC64OR(v, config)
+		return rewriteValuePPC64_OpPPC64OR_0(v)
 	case OpPPC64ORN:
-		return rewriteValuePPC64_OpPPC64ORN(v, config)
+		return rewriteValuePPC64_OpPPC64ORN_0(v)
 	case OpPPC64ORconst:
-		return rewriteValuePPC64_OpPPC64ORconst(v, config)
+		return rewriteValuePPC64_OpPPC64ORconst_0(v)
 	case OpPPC64SUB:
-		return rewriteValuePPC64_OpPPC64SUB(v, config)
+		return rewriteValuePPC64_OpPPC64SUB_0(v)
 	case OpPPC64XOR:
-		return rewriteValuePPC64_OpPPC64XOR(v, config)
+		return rewriteValuePPC64_OpPPC64XOR_0(v)
 	case OpPPC64XORconst:
-		return rewriteValuePPC64_OpPPC64XORconst(v, config)
+		return rewriteValuePPC64_OpPPC64XORconst_0(v)
+	case OpPopCount16:
+		return rewriteValuePPC64_OpPopCount16_0(v)
+	case OpPopCount32:
+		return rewriteValuePPC64_OpPopCount32_0(v)
+	case OpPopCount64:
+		return rewriteValuePPC64_OpPopCount64_0(v)
+	case OpPopCount8:
+		return rewriteValuePPC64_OpPopCount8_0(v)
+	case OpRound32F:
+		return rewriteValuePPC64_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValuePPC64_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValuePPC64_OpRsh16Ux16(v, config)
+		return rewriteValuePPC64_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValuePPC64_OpRsh16Ux32(v, config)
+		return rewriteValuePPC64_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValuePPC64_OpRsh16Ux64(v, config)
+		return rewriteValuePPC64_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValuePPC64_OpRsh16Ux8(v, config)
+		return rewriteValuePPC64_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValuePPC64_OpRsh16x16(v, config)
+		return rewriteValuePPC64_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValuePPC64_OpRsh16x32(v, config)
+		return rewriteValuePPC64_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValuePPC64_OpRsh16x64(v, config)
+		return rewriteValuePPC64_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValuePPC64_OpRsh16x8(v, config)
+		return rewriteValuePPC64_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValuePPC64_OpRsh32Ux16(v, config)
+		return rewriteValuePPC64_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValuePPC64_OpRsh32Ux32(v, config)
+		return rewriteValuePPC64_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValuePPC64_OpRsh32Ux64(v, config)
+		return rewriteValuePPC64_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValuePPC64_OpRsh32Ux8(v, config)
+		return rewriteValuePPC64_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValuePPC64_OpRsh32x16(v, config)
+		return rewriteValuePPC64_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValuePPC64_OpRsh32x32(v, config)
+		return rewriteValuePPC64_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValuePPC64_OpRsh32x64(v, config)
+		return rewriteValuePPC64_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValuePPC64_OpRsh32x8(v, config)
+		return rewriteValuePPC64_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValuePPC64_OpRsh64Ux16(v, config)
+		return rewriteValuePPC64_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValuePPC64_OpRsh64Ux32(v, config)
+		return rewriteValuePPC64_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValuePPC64_OpRsh64Ux64(v, config)
+		return rewriteValuePPC64_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValuePPC64_OpRsh64Ux8(v, config)
+		return rewriteValuePPC64_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValuePPC64_OpRsh64x16(v, config)
+		return rewriteValuePPC64_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValuePPC64_OpRsh64x32(v, config)
+		return rewriteValuePPC64_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValuePPC64_OpRsh64x64(v, config)
+		return rewriteValuePPC64_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValuePPC64_OpRsh64x8(v, config)
+		return rewriteValuePPC64_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValuePPC64_OpRsh8Ux16(v, config)
+		return rewriteValuePPC64_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValuePPC64_OpRsh8Ux32(v, config)
+		return rewriteValuePPC64_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValuePPC64_OpRsh8Ux64(v, config)
+		return rewriteValuePPC64_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValuePPC64_OpRsh8Ux8(v, config)
+		return rewriteValuePPC64_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValuePPC64_OpRsh8x16(v, config)
+		return rewriteValuePPC64_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValuePPC64_OpRsh8x32(v, config)
+		return rewriteValuePPC64_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValuePPC64_OpRsh8x64(v, config)
+		return rewriteValuePPC64_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValuePPC64_OpRsh8x8(v, config)
+		return rewriteValuePPC64_OpRsh8x8_0(v)
 	case OpSignExt16to32:
-		return rewriteValuePPC64_OpSignExt16to32(v, config)
+		return rewriteValuePPC64_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValuePPC64_OpSignExt16to64(v, config)
+		return rewriteValuePPC64_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValuePPC64_OpSignExt32to64(v, config)
+		return rewriteValuePPC64_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValuePPC64_OpSignExt8to16(v, config)
+		return rewriteValuePPC64_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValuePPC64_OpSignExt8to32(v, config)
+		return rewriteValuePPC64_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValuePPC64_OpSignExt8to64(v, config)
+		return rewriteValuePPC64_OpSignExt8to64_0(v)
 	case OpSlicemask:
-		return rewriteValuePPC64_OpSlicemask(v, config)
+		return rewriteValuePPC64_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValuePPC64_OpSqrt(v, config)
+		return rewriteValuePPC64_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValuePPC64_OpStaticCall(v, config)
+		return rewriteValuePPC64_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValuePPC64_OpStore(v, config)
+		return rewriteValuePPC64_OpStore_0(v)
 	case OpSub16:
-		return rewriteValuePPC64_OpSub16(v, config)
+		return rewriteValuePPC64_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValuePPC64_OpSub32(v, config)
+		return rewriteValuePPC64_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValuePPC64_OpSub32F(v, config)
+		return rewriteValuePPC64_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValuePPC64_OpSub64(v, config)
+		return rewriteValuePPC64_OpSub64_0(v)
 	case OpSub64F:
-		return rewriteValuePPC64_OpSub64F(v, config)
+		return rewriteValuePPC64_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValuePPC64_OpSub8(v, config)
+		return rewriteValuePPC64_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValuePPC64_OpSubPtr(v, config)
+		return rewriteValuePPC64_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValuePPC64_OpTrunc16to8(v, config)
+		return rewriteValuePPC64_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValuePPC64_OpTrunc32to16(v, config)
+		return rewriteValuePPC64_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValuePPC64_OpTrunc32to8(v, config)
+		return rewriteValuePPC64_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValuePPC64_OpTrunc64to16(v, config)
+		return rewriteValuePPC64_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValuePPC64_OpTrunc64to32(v, config)
+		return rewriteValuePPC64_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValuePPC64_OpTrunc64to8(v, config)
+		return rewriteValuePPC64_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValuePPC64_OpXor16(v, config)
+		return rewriteValuePPC64_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValuePPC64_OpXor32(v, config)
+		return rewriteValuePPC64_OpXor32_0(v)
 	case OpXor64:
-		return rewriteValuePPC64_OpXor64(v, config)
+		return rewriteValuePPC64_OpXor64_0(v)
 	case OpXor8:
-		return rewriteValuePPC64_OpXor8(v, config)
+		return rewriteValuePPC64_OpXor8_0(v)
 	case OpZero:
-		return rewriteValuePPC64_OpZero(v, config)
+		return rewriteValuePPC64_OpZero_0(v) || rewriteValuePPC64_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValuePPC64_OpZeroExt16to32(v, config)
+		return rewriteValuePPC64_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValuePPC64_OpZeroExt16to64(v, config)
+		return rewriteValuePPC64_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValuePPC64_OpZeroExt32to64(v, config)
+		return rewriteValuePPC64_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValuePPC64_OpZeroExt8to16(v, config)
+		return rewriteValuePPC64_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValuePPC64_OpZeroExt8to32(v, config)
+		return rewriteValuePPC64_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValuePPC64_OpZeroExt8to64(v, config)
+		return rewriteValuePPC64_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValuePPC64_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add16  x y)
+func rewriteValuePPC64_OpAdd16_0(v *Value) bool {
+	// match: (Add16 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
@@ -586,13 +634,12 @@ func rewriteValuePPC64_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add32  x y)
+func rewriteValuePPC64_OpAdd32_0(v *Value) bool {
+	// match: (Add32 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
@@ -601,13 +648,12 @@ func rewriteValuePPC64_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (FADDS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FADDS)
@@ -616,13 +662,12 @@ func rewriteValuePPC64_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add64  x y)
+func rewriteValuePPC64_OpAdd64_0(v *Value) bool {
+	// match: (Add64 x y)
 	// cond:
 	// result: (ADD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
@@ -631,13 +676,12 @@ func rewriteValuePPC64_OpAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (FADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FADD)
@@ -646,13 +690,12 @@ func rewriteValuePPC64_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add8   x y)
+func rewriteValuePPC64_OpAdd8_0(v *Value) bool {
+	// match: (Add8 x y)
 	// cond:
 	// result: (ADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
@@ -661,13 +704,12 @@ func rewriteValuePPC64_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
@@ -676,9 +718,7 @@ func rewriteValuePPC64_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVDaddr {sym} base)
@@ -691,13 +731,12 @@ func rewriteValuePPC64_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64AND)
@@ -706,13 +745,12 @@ func rewriteValuePPC64_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64AND)
@@ -721,13 +759,12 @@ func rewriteValuePPC64_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAnd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAnd64_0(v *Value) bool {
 	// match: (And64 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64AND)
@@ -736,13 +773,12 @@ func rewriteValuePPC64_OpAnd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (And8  x y)
+func rewriteValuePPC64_OpAnd8_0(v *Value) bool {
+	// match: (And8 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64AND)
@@ -751,13 +787,12 @@ func rewriteValuePPC64_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64AND)
@@ -766,49 +801,282 @@ func rewriteValuePPC64_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpAvg64u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpAtomicAdd32_0(v *Value) bool {
+	// match: (AtomicAdd32 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicAdd32 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicAdd32)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicAdd64_0(v *Value) bool {
+	// match: (AtomicAdd64 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicAdd64 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicAdd64)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicAnd8_0(v *Value) bool {
+	// match: (AtomicAnd8 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicAnd8 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicAnd8)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicCompareAndSwap32_0(v *Value) bool {
+	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
+	// cond:
+	// result: (LoweredAtomicCas32 ptr old new_ mem)
+	for {
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		old := v.Args[1]
+		new_ := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpPPC64LoweredAtomicCas32)
+		v.AddArg(ptr)
+		v.AddArg(old)
+		v.AddArg(new_)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicCompareAndSwap64_0(v *Value) bool {
+	// match: (AtomicCompareAndSwap64 ptr old new_ mem)
+	// cond:
+	// result: (LoweredAtomicCas64 ptr old new_ mem)
+	for {
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		old := v.Args[1]
+		new_ := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpPPC64LoweredAtomicCas64)
+		v.AddArg(ptr)
+		v.AddArg(old)
+		v.AddArg(new_)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicExchange32_0(v *Value) bool {
+	// match: (AtomicExchange32 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicExchange32 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicExchange32)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicExchange64_0(v *Value) bool {
+	// match: (AtomicExchange64 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicExchange64 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicExchange64)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicLoad32_0(v *Value) bool {
+	// match: (AtomicLoad32 ptr mem)
+	// cond:
+	// result: (LoweredAtomicLoad32 ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpPPC64LoweredAtomicLoad32)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicLoad64_0(v *Value) bool {
+	// match: (AtomicLoad64 ptr mem)
+	// cond:
+	// result: (LoweredAtomicLoad64 ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpPPC64LoweredAtomicLoad64)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicLoadPtr_0(v *Value) bool {
+	// match: (AtomicLoadPtr ptr mem)
+	// cond:
+	// result: (LoweredAtomicLoadPtr ptr mem)
+	for {
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpPPC64LoweredAtomicLoadPtr)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicOr8_0(v *Value) bool {
+	// match: (AtomicOr8 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicOr8  ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicOr8)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicStore32_0(v *Value) bool {
+	// match: (AtomicStore32 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicStore32 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicStore32)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAtomicStore64_0(v *Value) bool {
+	// match: (AtomicStore64 ptr val mem)
+	// cond:
+	// result: (LoweredAtomicStore64 ptr val mem)
+	for {
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpPPC64LoweredAtomicStore64)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValuePPC64_OpAvg64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Avg64u <t> x y)
 	// cond:
-	// result: (ADD (ADD <t> (SRD <t> x (MOVDconst <t> [1])) (SRD <t> y (MOVDconst <t> [1]))) (ANDconst <t> (AND <t> x y) [1]))
+	// result: (ADD (SRDconst <t> (SUB <t> x y) [1]) y)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ADD)
-		v0 := b.NewValue0(v.Line, OpPPC64ADD, t)
-		v1 := b.NewValue0(v.Line, OpPPC64SRD, t)
+		v0 := b.NewValue0(v.Pos, OpPPC64SRDconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpPPC64SUB, t)
 		v1.AddArg(x)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVDconst, t)
-		v2.AuxInt = 1
-		v1.AddArg(v2)
+		v1.AddArg(y)
 		v0.AddArg(v1)
-		v3 := b.NewValue0(v.Line, OpPPC64SRD, t)
-		v3.AddArg(y)
-		v4 := b.NewValue0(v.Line, OpPPC64MOVDconst, t)
-		v4.AuxInt = 1
-		v3.AddArg(v4)
-		v0.AddArg(v3)
 		v.AddArg(v0)
-		v5 := b.NewValue0(v.Line, OpPPC64ANDconst, t)
-		v5.AuxInt = 1
-		v6 := b.NewValue0(v.Line, OpPPC64AND, t)
-		v6.AddArg(x)
-		v6.AddArg(y)
-		v5.AddArg(v6)
-		v.AddArg(v5)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValuePPC64_OpBitLen32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen32 x)
+	// cond:
+	// result: (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64SUB)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
+		v0.AuxInt = 32
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpPPC64CNTLZW, typ.Int)
+		v1.AddArg(x)
+		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpClosureCall(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpBitLen64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen64 x)
+	// cond:
+	// result: (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64SUB)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
+		v0.AuxInt = 64
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpPPC64CNTLZD, typ.Int)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuePPC64_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -820,66 +1088,56 @@ func rewriteValuePPC64_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
-	// result: (XORconst [-1] x)
+	// result: (NOR x x)
 	for {
 		x := v.Args[0]
-		v.reset(OpPPC64XORconst)
-		v.AuxInt = -1
+		v.reset(OpPPC64NOR)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
-	// result: (XORconst [-1] x)
+	// result: (NOR x x)
 	for {
 		x := v.Args[0]
-		v.reset(OpPPC64XORconst)
-		v.AuxInt = -1
+		v.reset(OpPPC64NOR)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCom64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpCom64_0(v *Value) bool {
 	// match: (Com64 x)
 	// cond:
-	// result: (XORconst [-1] x)
+	// result: (NOR x x)
 	for {
 		x := v.Args[0]
-		v.reset(OpPPC64XORconst)
-		v.AuxInt = -1
+		v.reset(OpPPC64NOR)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com8  x)
+func rewriteValuePPC64_OpCom8_0(v *Value) bool {
+	// match: (Com8 x)
 	// cond:
-	// result: (XORconst [-1] x)
+	// result: (NOR x x)
 	for {
 		x := v.Args[0]
-		v.reset(OpPPC64XORconst)
-		v.AuxInt = -1
+		v.reset(OpPPC64NOR)
+		v.AddArg(x)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const16  [val])
+func rewriteValuePPC64_OpConst16_0(v *Value) bool {
+	// match: (Const16 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -889,10 +1147,8 @@ func rewriteValuePPC64_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const32  [val])
+func rewriteValuePPC64_OpConst32_0(v *Value) bool {
+	// match: (Const32 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -902,9 +1158,7 @@ func rewriteValuePPC64_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (FMOVSconst [val])
@@ -915,10 +1169,8 @@ func rewriteValuePPC64_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const64  [val])
+func rewriteValuePPC64_OpConst64_0(v *Value) bool {
+	// match: (Const64 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -928,9 +1180,7 @@ func rewriteValuePPC64_OpConst64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (FMOVDconst [val])
@@ -941,10 +1191,8 @@ func rewriteValuePPC64_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const8   [val])
+func rewriteValuePPC64_OpConst8_0(v *Value) bool {
+	// match: (Const8 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -954,9 +1202,7 @@ func rewriteValuePPC64_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVDconst [b])
@@ -967,9 +1213,7 @@ func rewriteValuePPC64_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVDconst [0])
@@ -979,14 +1223,13 @@ func rewriteValuePPC64_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpConvert_0(v *Value) bool {
 	// match: (Convert <t> x mem)
 	// cond:
 	// result: (MOVDconvert <t> x mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpPPC64MOVDconvert)
@@ -996,39 +1239,85 @@ func rewriteValuePPC64_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt32Fto32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCtz32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Ctz32 x)
+	// cond:
+	// result: (POPCNTW (MOVWZreg (ANDN <typ.Int> (ADDconst <typ.Int> [-1] x) x)))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTW)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWZreg, typ.Int64)
+		v1 := b.NewValue0(v.Pos, OpPPC64ANDN, typ.Int)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconst, typ.Int)
+		v2.AuxInt = -1
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValuePPC64_OpCtz64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Ctz64 x)
+	// cond:
+	// result: (POPCNTD (ANDN <typ.Int64> (ADDconst <typ.Int64> [-1] x) x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTD)
+		v0 := b.NewValue0(v.Pos, OpPPC64ANDN, typ.Int64)
+		v1 := b.NewValue0(v.Pos, OpPPC64ADDconst, typ.Int64)
+		v1.AuxInt = -1
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValuePPC64_OpCvt32Fto32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (Xf2i64 (FCTIWZ x))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64Xf2i64)
-		v0 := b.NewValue0(v.Line, OpPPC64FCTIWZ, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCTIWZ, typ.Float64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt32Fto64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt32Fto64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt32Fto64 x)
 	// cond:
 	// result: (Xf2i64 (FCTIDZ x))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64Xf2i64)
-		v0 := b.NewValue0(v.Line, OpPPC64FCTIDZ, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCTIDZ, typ.Float64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: x
@@ -1040,18 +1329,20 @@ func rewriteValuePPC64_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt32to32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt32to32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (FRSP (FCFID (Xi2f64 (SignExt32to64 x))))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64FRSP)
-		v0 := b.NewValue0(v.Line, OpPPC64FCFID, config.fe.TypeFloat64())
-		v1 := b.NewValue0(v.Line, OpPPC64Xi2f64, config.fe.TypeFloat64())
-		v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCFID, typ.Float64)
+		v1 := b.NewValue0(v.Pos, OpPPC64Xi2f64, typ.Float64)
+		v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v2.AddArg(x)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
@@ -1059,41 +1350,43 @@ func rewriteValuePPC64_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt32to64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt32to64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (FCFID (Xi2f64 (SignExt32to64 x)))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64FCFID)
-		v0 := b.NewValue0(v.Line, OpPPC64Xi2f64, config.fe.TypeFloat64())
-		v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64Xi2f64, typ.Float64)
+		v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt64Fto32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt64Fto32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (Xf2i64 (FCTIWZ x))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64Xf2i64)
-		v0 := b.NewValue0(v.Line, OpPPC64FCTIWZ, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCTIWZ, typ.Float64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (FRSP x)
@@ -1104,113 +1397,109 @@ func rewriteValuePPC64_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt64Fto64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt64Fto64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt64Fto64 x)
 	// cond:
 	// result: (Xf2i64 (FCTIDZ x))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64Xf2i64)
-		v0 := b.NewValue0(v.Line, OpPPC64FCTIDZ, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCTIDZ, typ.Float64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt64to32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt64to32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt64to32F x)
 	// cond:
 	// result: (FRSP (FCFID (Xi2f64 x)))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64FRSP)
-		v0 := b.NewValue0(v.Line, OpPPC64FCFID, config.fe.TypeFloat64())
-		v1 := b.NewValue0(v.Line, OpPPC64Xi2f64, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64FCFID, typ.Float64)
+		v1 := b.NewValue0(v.Pos, OpPPC64Xi2f64, typ.Float64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpCvt64to64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpCvt64to64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Cvt64to64F x)
 	// cond:
 	// result: (FCFID (Xi2f64 x))
 	for {
 		x := v.Args[0]
 		v.reset(OpPPC64FCFID)
-		v0 := b.NewValue0(v.Line, OpPPC64Xi2f64, config.fe.TypeFloat64())
+		v0 := b.NewValue0(v.Pos, OpPPC64Xi2f64, typ.Float64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpDeferCall(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (DeferCall [argwid] mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16 x y)
 	// cond:
-	// result: (CALLdefer [argwid] mem)
-	for {
-		argwid := v.AuxInt
-		mem := v.Args[0]
-		v.reset(OpPPC64CALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValuePPC64_OpDiv16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div16  x y)
-	// cond:
-	// result: (DIVW  (SignExt16to32 x) (SignExt16to32 y))
+	// result: (DIVW  (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (DIVWU (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVWU)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div32  x y)
+func rewriteValuePPC64_OpDiv32_0(v *Value) bool {
+	// match: (Div32 x y)
 	// cond:
 	// result: (DIVW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVW)
@@ -1219,13 +1508,12 @@ func rewriteValuePPC64_OpDiv32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (FDIVS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FDIVS)
@@ -1234,13 +1522,12 @@ func rewriteValuePPC64_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpDiv32u_0(v *Value) bool {
 	// match: (Div32u x y)
 	// cond:
 	// result: (DIVWU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVWU)
@@ -1249,13 +1536,12 @@ func rewriteValuePPC64_OpDiv32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div64  x y)
+func rewriteValuePPC64_OpDiv64_0(v *Value) bool {
+	// match: (Div64 x y)
 	// cond:
 	// result: (DIVD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVD)
@@ -1264,13 +1550,12 @@ func rewriteValuePPC64_OpDiv64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (FDIV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FDIV)
@@ -1279,13 +1564,12 @@ func rewriteValuePPC64_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpDiv64u_0(v *Value) bool {
 	// match: (Div64u x y)
 	// cond:
 	// result: (DIVDU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVDU)
@@ -1294,62 +1578,71 @@ func rewriteValuePPC64_OpDiv64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8 x y)
 	// cond:
 	// result: (DIVW  (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8u  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8u x y)
 	// cond:
 	// result: (DIVWU (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64DIVWU)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq16 x y)
 	// cond: isSigned(x.Type) && isSigned(y.Type)
 	// result: (Equal (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if !(isSigned(x.Type) && isSigned(y.Type)) {
 			break
 		}
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
@@ -1359,106 +1652,114 @@ func rewriteValuePPC64_OpEq16(v *Value, config *Config) bool {
 	// cond:
 	// result: (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32 x y)
 	// cond:
 	// result: (Equal (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq32F x y)
 	// cond:
 	// result: (Equal (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64 x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Eq64F x y)
 	// cond:
 	// result: (Equal (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEq8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq8 x y)
 	// cond: isSigned(x.Type) && isSigned(y.Type)
 	// result: (Equal (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if !(isSigned(x.Type) && isSigned(y.Type)) {
 			break
 		}
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
@@ -1468,244 +1769,265 @@ func rewriteValuePPC64_OpEq8(v *Value, config *Config) bool {
 	// cond:
 	// result: (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEqB(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqB x y)
 	// cond:
 	// result: (ANDconst [1] (EQV x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64ANDconst)
 		v.AuxInt = 1
-		v0 := b.NewValue0(v.Line, OpPPC64EQV, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64EQV, typ.Int64)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (EqPtr x y)
 	// cond:
 	// result: (Equal (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64Equal)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32F x y)
 	// cond:
 	// result: (FGreaterEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq32U x y)
 	// cond:
 	// result: (GreaterEqual (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64 x y)
 	// cond:
 	// result: (GreaterEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64F x y)
 	// cond:
 	// result: (FGreaterEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FGreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq64U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Geq64U x y)
 	// cond:
 	// result: (GreaterEqual (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8 x y)
 	// cond:
 	// result: (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq8U x y)
 	// cond:
 	// result: (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -1714,258 +2036,216 @@ func rewriteValuePPC64_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_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(OpPPC64CALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValuePPC64_OpGreater16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16 x y)
 	// cond:
 	// result: (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (GreaterThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32 x y)
 	// cond:
 	// result: (GreaterThan (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32F x y)
 	// cond:
 	// result: (FGreaterThan (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FGreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater32U x y)
 	// cond:
 	// result: (GreaterThan (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64 x y)
 	// cond:
 	// result: (GreaterThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64F x y)
 	// cond:
 	// result: (FGreaterThan (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FGreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater64U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Greater64U x y)
 	// cond:
 	// result: (GreaterThan (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8 x y)
 	// cond:
 	// result: (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater8U x y)
 	// cond:
 	// result: (GreaterThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64GreaterThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValuePPC64_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16 x y)
-	// cond:
-	// result: (SRAWconst (MULLW <config.fe.TypeInt32()> (SignExt16to32 x) (SignExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpPPC64SRAWconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValuePPC64_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRWconst (MULLW <config.fe.TypeUInt32()> (ZeroExt16to32 x) (ZeroExt16to32 y)) [16])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpPPC64SRWconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpHmul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul32  x y)
+func rewriteValuePPC64_OpHmul32_0(v *Value) bool {
+	// match: (Hmul32 x y)
 	// cond:
 	// result: (MULHW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULHW)
@@ -1974,13 +2254,12 @@ func rewriteValuePPC64_OpHmul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpHmul32u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul32u  x y)
+func rewriteValuePPC64_OpHmul32u_0(v *Value) bool {
+	// match: (Hmul32u x y)
 	// cond:
 	// result: (MULHWU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULHWU)
@@ -1989,13 +2268,12 @@ func rewriteValuePPC64_OpHmul32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpHmul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul64  x y)
+func rewriteValuePPC64_OpHmul64_0(v *Value) bool {
+	// match: (Hmul64 x y)
 	// cond:
 	// result: (MULHD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULHD)
@@ -2004,13 +2282,12 @@ func rewriteValuePPC64_OpHmul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpHmul64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul64u  x y)
+func rewriteValuePPC64_OpHmul64u_0(v *Value) bool {
+	// match: (Hmul64u x y)
 	// cond:
 	// result: (MULHDU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULHDU)
@@ -2019,58 +2296,13 @@ func rewriteValuePPC64_OpHmul64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8 x y)
-	// cond:
-	// result: (SRAWconst (MULLW <config.fe.TypeInt16()> (SignExt8to32 x) (SignExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpPPC64SRAWconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt16())
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValuePPC64_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u x y)
-	// cond:
-	// result: (SRWconst (MULLW <config.fe.TypeUInt16()> (ZeroExt8to32 x) (ZeroExt8to32 y)) [8])
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpPPC64SRWconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeUInt16())
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValuePPC64_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpPPC64CALLinter)
@@ -2080,24 +2312,25 @@ func rewriteValuePPC64_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpIsInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (LessThan (CMPU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsNonNil ptr)
@@ -2106,410 +2339,450 @@ func rewriteValuePPC64_OpIsNonNil(v *Value, config *Config) bool {
 	for {
 		ptr := v.Args[0]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPconst, types.TypeFlags)
 		v0.AuxInt = 0
 		v0.AddArg(ptr)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (LessEqual (CMPU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(idx)
 		v0.AddArg(len)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16 x y)
 	// cond:
 	// result: (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (LessEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32 x y)
 	// cond:
 	// result: (LessEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32F x y)
 	// cond:
 	// result: (FLessEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FLessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq32U x y)
 	// cond:
 	// result: (LessEqual (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64 x y)
 	// cond:
 	// result: (LessEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64F x y)
 	// cond:
 	// result: (FLessEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FLessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq64U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Leq64U x y)
 	// cond:
 	// result: (LessEqual (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8 x y)
 	// cond:
 	// result: (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq8U x y)
 	// cond:
 	// result: (LessEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16 x y)
 	// cond:
 	// result: (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess16U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (LessThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32 x y)
 	// cond:
 	// result: (LessThan (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32F x y)
 	// cond:
 	// result: (FLessThan (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FLessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess32U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less32U x y)
 	// cond:
 	// result: (LessThan (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64 x y)
 	// cond:
 	// result: (LessThan (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64F x y)
 	// cond:
 	// result: (FLessThan (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FLessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess64U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Less64U x y)
 	// cond:
 	// result: (LessThan (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8 x y)
 	// cond:
 	// result: (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLess8U(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less8U x y)
 	// cond:
 	// result: (LessThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64LessThan)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWU, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLoad_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Load <t> ptr mem)
 	// cond: (is64BitInt(t) || isPtr(t))
 	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) || isPtr(t)) {
@@ -2525,6 +2798,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && isSigned(t)) {
@@ -2540,6 +2814,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && !isSigned(t)) {
@@ -2555,6 +2830,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -2570,6 +2846,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -2585,6 +2862,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean()) {
@@ -2600,13 +2878,14 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBreg (MOVBZload ptr mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
 			break
 		}
 		v.reset(OpPPC64MOVBreg)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBZload, typ.UInt8)
 		v0.AddArg(ptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
@@ -2617,6 +2896,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && !isSigned(t)) {
@@ -2632,6 +2912,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVSload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -2647,6 +2928,7 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitFloat(t)) {
@@ -2659,23 +2941,26 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 x y)
 	// cond:
-	// result: (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+	// result: (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -16
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -2684,13 +2969,16 @@ func rewriteValuePPC64_OpLsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x32 x (Const64 [c]))
 	// cond: uint32(c) < 16
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2705,10 +2993,11 @@ func rewriteValuePPC64_OpLsh16x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x32  x (MOVDconst [c]))
+	// match: (Lsh16x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 16
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -2725,18 +3014,19 @@ func rewriteValuePPC64_OpLsh16x32(v *Value, config *Config) bool {
 	}
 	// match: (Lsh16x32 x y)
 	// cond:
-	// result: (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+	// result: (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -16
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -2745,13 +3035,16 @@ func rewriteValuePPC64_OpLsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2766,10 +3059,11 @@ func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x64  _ (Const64 [c]))
+	// match: (Lsh16x64 _ (Const64 [c]))
 	// cond: uint64(c) >= 16
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -2782,10 +3076,11 @@ func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh16x64  x (MOVDconst [c]))
+	// match: (Lsh16x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 16
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -2802,16 +3097,17 @@ func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh16x64 x y)
 	// cond:
-	// result: (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+	// result: (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -16
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -2820,23 +3116,26 @@ func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x8 x y)
 	// cond:
-	// result: (SLW  x                 (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+	// result: (SLW  x                 (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -16
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -2845,23 +3144,26 @@ func rewriteValuePPC64_OpLsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 x y)
 	// cond:
-	// result: (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+	// result: (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -2870,13 +3172,16 @@ func rewriteValuePPC64_OpLsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x32 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2891,10 +3196,11 @@ func rewriteValuePPC64_OpLsh32x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh32x32  x (MOVDconst [c]))
+	// match: (Lsh32x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 32
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -2911,18 +3217,19 @@ func rewriteValuePPC64_OpLsh32x32(v *Value, config *Config) bool {
 	}
 	// match: (Lsh32x32 x y)
 	// cond:
-	// result: (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+	// result: (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -2931,13 +3238,16 @@ func rewriteValuePPC64_OpLsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -2952,10 +3262,11 @@ func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh32x64  _ (Const64 [c]))
+	// match: (Lsh32x64 _ (Const64 [c]))
 	// cond: uint64(c) >= 32
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -2968,10 +3279,11 @@ func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh32x64  x (MOVDconst [c]))
+	// match: (Lsh32x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 32
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -2988,16 +3300,17 @@ func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh32x64 x y)
 	// cond:
-	// result: (SLW  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+	// result: (SLW  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3006,23 +3319,26 @@ func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x8 x y)
 	// cond:
-	// result: (SLW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+	// result: (SLW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3031,23 +3347,26 @@ func rewriteValuePPC64_OpLsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh64x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x16 x y)
 	// cond:
-	// result: (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+	// result: (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3056,13 +3375,16 @@ func rewriteValuePPC64_OpLsh64x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh64x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x32 x (Const64 [c]))
 	// cond: uint32(c) < 64
 	// result: (SLDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -3077,10 +3399,11 @@ func rewriteValuePPC64_OpLsh64x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x32  x (MOVDconst [c]))
+	// match: (Lsh64x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 64
 	// result: (SLDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -3097,18 +3420,19 @@ func rewriteValuePPC64_OpLsh64x32(v *Value, config *Config) bool {
 	}
 	// match: (Lsh64x32 x y)
 	// cond:
-	// result: (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+	// result: (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3117,13 +3441,16 @@ func rewriteValuePPC64_OpLsh64x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x64 x (Const64 [c]))
 	// cond: uint64(c) < 64
 	// result: (SLDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -3138,10 +3465,11 @@ func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x64  _ (Const64 [c]))
+	// match: (Lsh64x64 _ (Const64 [c]))
 	// cond: uint64(c) >= 64
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -3154,10 +3482,11 @@ func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh64x64  x (MOVDconst [c]))
+	// match: (Lsh64x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 64
 	// result: (SLDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -3174,16 +3503,17 @@ func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh64x64 x y)
 	// cond:
-	// result: (SLD  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+	// result: (SLD  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3192,23 +3522,26 @@ func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x8 x y)
 	// cond:
-	// result: (SLD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+	// result: (SLD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3217,23 +3550,26 @@ func rewriteValuePPC64_OpLsh64x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 x y)
 	// cond:
-	// result: (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+	// result: (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -8
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3242,13 +3578,16 @@ func rewriteValuePPC64_OpLsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x32   x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x32 x (Const64 [c]))
 	// cond: uint32(c) < 8
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -3263,10 +3602,11 @@ func rewriteValuePPC64_OpLsh8x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh8x32   x (MOVDconst [c]))
+	// match: (Lsh8x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 8
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -3283,18 +3623,19 @@ func rewriteValuePPC64_OpLsh8x32(v *Value, config *Config) bool {
 	}
 	// match: (Lsh8x32 x y)
 	// cond:
-	// result: (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+	// result: (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -8
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3303,13 +3644,16 @@ func rewriteValuePPC64_OpLsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x64   x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -3324,10 +3668,11 @@ func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh8x64   _ (Const64 [c]))
+	// match: (Lsh8x64 _ (Const64 [c]))
 	// cond: uint64(c) >= 8
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -3340,10 +3685,11 @@ func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh8x64   x (MOVDconst [c]))
+	// match: (Lsh8x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SLWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -3360,16 +3706,17 @@ func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh8x64 x y)
 	// cond:
-	// result: (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+	// result: (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -8
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3378,23 +3725,26 @@ func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x8 x y)
 	// cond:
-	// result: (SLW  x                (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+	// result: (SLW  x                (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SLW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -8
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3403,58 +3753,67 @@ func rewriteValuePPC64_OpLsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16 x y)
 	// cond:
 	// result: (Mod32 (SignExt16to32 x) (SignExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod16u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32 x y)
 	// cond:
 	// result: (SUB x (MULLW y (DIVW x y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64MULLW, typ.Int32)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64DIVW, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpPPC64DIVW, typ.Int32)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -3462,20 +3821,23 @@ func rewriteValuePPC64_OpMod32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod32u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32u x y)
 	// cond:
 	// result: (SUB x (MULLW y (DIVWU x y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64MULLW, typ.Int32)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64DIVWU, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpPPC64DIVWU, typ.Int32)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -3483,20 +3845,23 @@ func rewriteValuePPC64_OpMod32u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod64 x y)
 	// cond:
 	// result: (SUB x (MULLD y (DIVD x y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64MULLD, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64MULLD, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64DIVD, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64DIVD, typ.Int64)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -3504,20 +3869,23 @@ func rewriteValuePPC64_OpMod64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod64u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod64u x y)
 	// cond:
 	// result: (SUB x (MULLD y (DIVDU x y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64MULLD, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64MULLD, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64DIVDU, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64DIVDU, typ.Int64)
 		v1.AddArg(x)
 		v1.AddArg(y)
 		v0.AddArg(v1)
@@ -3525,172 +3893,175 @@ func rewriteValuePPC64_OpMod64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8 x y)
 	// cond:
 	// result: (Mod32 (SignExt8to32 x) (SignExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpMod8u(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod8u x y)
 	// cond:
 	// result: (Mod32u (ZeroExt8to32 x) (ZeroExt8to32 y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpMod32u)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValuePPC64_OpMove(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpPPC64MOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBZload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVHstore dst (MOVHZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
-			break
-		}
 		v.reset(OpPPC64MOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVHZload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
-	// result: (MOVBstore [1] dst (MOVBZload [1] src mem) 		(MOVBstore dst (MOVBZload src mem) mem))
+	// match: (Move [4] dst src mem)
+	// cond:
+	// result: (MOVWstore dst (MOVWZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
-		v.reset(OpPPC64MOVBstore)
-		v.AuxInt = 1
+		v.reset(OpPPC64MOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v0.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
-		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v2.AddArg(src)
-		v2.AddArg(mem)
-		v1.AddArg(v2)
-		v1.AddArg(mem)
-		v.AddArg(v1)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
-	// result: (MOVWstore dst (MOVWload src mem) mem)
+	// match: (Move [8] {t} dst src mem)
+	// cond: t.(*types.Type).Alignment()%4 == 0
+	// result: (MOVDstore dst (MOVDload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if !(t.(*types.Type).Alignment()%4 == 0) {
 			break
 		}
-		v.reset(OpPPC64MOVWstore)
+		v.reset(OpPPC64MOVDstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVWload, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDload, typ.Int64)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
-	// result: (MOVHstore [2] dst (MOVHZload [2] src mem) 		(MOVHstore dst (MOVHZload src mem) mem))
+	// match: (Move [8] dst src mem)
+	// cond:
+	// result: (MOVWstore [4] dst (MOVWZload [4] src mem) 		(MOVWstore dst (MOVWZload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
-			break
-		}
-		v.reset(OpPPC64MOVHstore)
-		v.AuxInt = 2
+		v.reset(OpPPC64MOVWstore)
+		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
-		v0.AuxInt = 2
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
+		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -3698,95 +4069,57 @@ func rewriteValuePPC64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
-	// result: (MOVBstore [3] dst (MOVBZload [3] src mem) 		(MOVBstore [2] dst (MOVBZload [2] src mem) 			(MOVBstore [1] dst (MOVBZload [1] src mem) 				(MOVBstore dst (MOVBZload src mem) mem))))
+	// match: (Move [3] dst src mem)
+	// cond:
+	// result: (MOVBstore [2] dst (MOVBZload [2] src mem)                 (MOVHstore dst (MOVHload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpPPC64MOVBstore)
-		v.AuxInt = 3
+		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v0.AuxInt = 3
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBZload, typ.UInt8)
+		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
-		v1.AuxInt = 2
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v2.AuxInt = 2
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVHload, typ.Int16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
-		v3.AuxInt = 1
-		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v4.AuxInt = 1
-		v4.AddArg(src)
-		v4.AddArg(mem)
-		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
-		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v6.AddArg(src)
-		v6.AddArg(mem)
-		v5.AddArg(v6)
-		v5.AddArg(mem)
-		v3.AddArg(v5)
-		v1.AddArg(v3)
+		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
-	// result: (MOVDstore dst (MOVDload src mem) mem)
+	// match: (Move [5] dst src mem)
+	// cond:
+	// result: (MOVBstore [4] dst (MOVBZload [4] src mem)                 (MOVWstore dst (MOVWZload src mem) mem))
 	for {
-		s := v.AuxInt
-		dst := v.Args[0]
-		src := v.Args[1]
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+		if v.AuxInt != 5 {
 			break
 		}
-		v.reset(OpPPC64MOVDstore)
-		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVDload, config.fe.TypeInt64())
-		v0.AddArg(src)
-		v0.AddArg(mem)
-		v.AddArg(v0)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
-	// result: (MOVWstore [4] dst (MOVWZload [4] src mem) 		(MOVWstore dst (MOVWZload src mem) mem))
-	for {
-		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
-			break
-		}
-		v.reset(OpPPC64MOVWstore)
+		v.reset(OpPPC64MOVBstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVWZload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBZload, typ.UInt8)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVWZload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -3794,83 +4127,65 @@ func rewriteValuePPC64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0
-	// result: (MOVHstore [6] dst (MOVHZload [6] src mem) 		(MOVHstore [4] dst (MOVHZload [4] src mem) 			(MOVHstore [2] dst (MOVHZload [2] src mem) 				(MOVHstore dst (MOVHZload src mem) mem))))
+	// match: (Move [6] dst src mem)
+	// cond:
+	// result: (MOVHstore [4] dst (MOVHZload [4] src mem)                 (MOVWstore dst (MOVWZload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0) {
-			break
-		}
 		v.reset(OpPPC64MOVHstore)
-		v.AuxInt = 6
+		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
-		v0.AuxInt = 6
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVHZload, typ.UInt16)
+		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
-		v1.AuxInt = 4
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
-		v2.AuxInt = 4
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
-		v3.AuxInt = 2
-		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
-		v4.AuxInt = 2
-		v4.AddArg(src)
-		v4.AddArg(mem)
-		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
-		v5.AddArg(dst)
-		v6 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
-		v6.AddArg(src)
-		v6.AddArg(mem)
-		v5.AddArg(v6)
-		v5.AddArg(mem)
-		v3.AddArg(v5)
-		v1.AddArg(v3)
+		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
-	// result: (MOVBstore [2] dst (MOVBZload [2] src mem) 		(MOVBstore [1] dst (MOVBZload [1] src mem) 			(MOVBstore dst (MOVBZload src mem) mem)))
+	// match: (Move [7] dst src mem)
+	// cond:
+	// result: (MOVBstore [6] dst (MOVBZload [6] src mem)                 (MOVHstore [4] dst (MOVHZload [4] src mem)                         (MOVWstore dst (MOVWZload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 7 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpPPC64MOVBstore)
-		v.AuxInt = 2
+		v.AuxInt = 6
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v0.AuxInt = 2
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBZload, typ.UInt8)
+		v0.AuxInt = 6
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
-		v1.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVHstore, types.TypeMem)
+		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
-		v2.AuxInt = 1
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVHZload, typ.UInt16)
+		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpPPC64MOVWstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -3879,37 +4194,36 @@ func rewriteValuePPC64_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
+	return false
+}
+func rewriteValuePPC64_OpMove_10(v *Value) bool {
 	// match: (Move [s] dst src mem)
-	// cond: (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0
-	// result: (LoweredMove [SizeAndAlign(s).Align()] 		dst 		src 		(ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// cond: s > 8
+	// result: (LoweredMove [s] dst src mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0) {
+		if !(s > 8) {
 			break
 		}
 		v.reset(OpPPC64LoweredMove)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = s
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpPPC64ADDconst, src.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
-		v0.AddArg(src)
-		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValuePPC64_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul16  x y)
+func rewriteValuePPC64_OpMul16_0(v *Value) bool {
+	// match: (Mul16 x y)
 	// cond:
 	// result: (MULLW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULLW)
@@ -3918,13 +4232,12 @@ func rewriteValuePPC64_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul32  x y)
+func rewriteValuePPC64_OpMul32_0(v *Value) bool {
+	// match: (Mul32 x y)
 	// cond:
 	// result: (MULLW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULLW)
@@ -3933,13 +4246,12 @@ func rewriteValuePPC64_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (FMULS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FMULS)
@@ -3948,13 +4260,12 @@ func rewriteValuePPC64_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64  x y)
+func rewriteValuePPC64_OpMul64_0(v *Value) bool {
+	// match: (Mul64 x y)
 	// cond:
 	// result: (MULLD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULLD)
@@ -3963,13 +4274,12 @@ func rewriteValuePPC64_OpMul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (FMUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FMUL)
@@ -3978,13 +4288,12 @@ func rewriteValuePPC64_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul8   x y)
+func rewriteValuePPC64_OpMul8_0(v *Value) bool {
+	// match: (Mul8 x y)
 	// cond:
 	// result: (MULLW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64MULLW)
@@ -3993,10 +4302,8 @@ func rewriteValuePPC64_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg16  x)
+func rewriteValuePPC64_OpNeg16_0(v *Value) bool {
+	// match: (Neg16 x)
 	// cond:
 	// result: (NEG x)
 	for {
@@ -4006,10 +4313,8 @@ func rewriteValuePPC64_OpNeg16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg32  x)
+func rewriteValuePPC64_OpNeg32_0(v *Value) bool {
+	// match: (Neg32 x)
 	// cond:
 	// result: (NEG x)
 	for {
@@ -4019,9 +4324,7 @@ func rewriteValuePPC64_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (FNEG x)
@@ -4032,10 +4335,8 @@ func rewriteValuePPC64_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg64  x)
+func rewriteValuePPC64_OpNeg64_0(v *Value) bool {
+	// match: (Neg64 x)
 	// cond:
 	// result: (NEG x)
 	for {
@@ -4045,9 +4346,7 @@ func rewriteValuePPC64_OpNeg64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (FNEG x)
@@ -4058,10 +4357,8 @@ func rewriteValuePPC64_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeg8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg8   x)
+func rewriteValuePPC64_OpNeg8_0(v *Value) bool {
+	// match: (Neg8 x)
 	// cond:
 	// result: (NEG x)
 	for {
@@ -4071,24 +4368,27 @@ func rewriteValuePPC64_OpNeg8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq16 x y)
 	// cond: isSigned(x.Type) && isSigned(y.Type)
 	// result: (NotEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if !(isSigned(x.Type) && isSigned(y.Type)) {
 			break
 		}
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
@@ -4098,106 +4398,114 @@ func rewriteValuePPC64_OpNeq16(v *Value, config *Config) bool {
 	// cond:
 	// result: (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32 x y)
 	// cond:
 	// result: (NotEqual (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq32F x y)
 	// cond:
 	// result: (NotEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64 x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neq64F x y)
 	// cond:
 	// result: (NotEqual (FCMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64FCMPU, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeq8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq8 x y)
 	// cond: isSigned(x.Type) && isSigned(y.Type)
 	// result: (NotEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		if !(isSigned(x.Type) && isSigned(y.Type)) {
 			break
 		}
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v2 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
@@ -4207,27 +4515,27 @@ func rewriteValuePPC64_OpNeq8(v *Value, config *Config) bool {
 	// cond:
 	// result: (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
-		v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPW, types.TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpNeqB_0(v *Value) bool {
 	// match: (NeqB x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64XOR)
@@ -4236,30 +4544,30 @@ func rewriteValuePPC64_OpNeqB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (NotEqual (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64NotEqual)
-		v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMP, types.TypeFlags)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpPPC64LoweredNilCheck)
@@ -4268,9 +4576,7 @@ func rewriteValuePPC64_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORconst [1] x)
@@ -4282,30 +4588,31 @@ func rewriteValuePPC64_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpOffPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (OffPtr [off] ptr)
 	// cond:
-	// result: (ADD (MOVDconst <config.Frontend().TypeInt64()> [off]) ptr)
+	// result: (ADD (MOVDconst <typ.Int64> [off]) ptr)
 	for {
 		off := v.AuxInt
 		ptr := v.Args[0]
 		v.reset(OpPPC64ADD)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVDconst, config.Frontend().TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
 		v0.AuxInt = off
 		v.AddArg(v0)
 		v.AddArg(ptr)
 		return true
 	}
 }
-func rewriteValuePPC64_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64OR)
@@ -4314,13 +4621,12 @@ func rewriteValuePPC64_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64OR)
@@ -4329,13 +4635,12 @@ func rewriteValuePPC64_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpOr64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpOr64_0(v *Value) bool {
 	// match: (Or64 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64OR)
@@ -4344,13 +4649,12 @@ func rewriteValuePPC64_OpOr64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Or8  x y)
+func rewriteValuePPC64_OpOr8_0(v *Value) bool {
+	// match: (Or8 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64OR)
@@ -4359,13 +4663,12 @@ func rewriteValuePPC64_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64OR)
@@ -4374,23 +4677,111 @@ func rewriteValuePPC64_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpPPC64ADD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ADD (MOVDconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (ADDconst [c] x)
+func rewriteValuePPC64_OpPPC64ADD_0(v *Value) bool {
+	// match: (ADD (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpPPC64MOVDconst {
+		if v_0.Op != OpPPC64SLDconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(is32Bit(c)) {
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SRDconst {
 			break
 		}
-		v.reset(OpPPC64ADDconst)
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SLDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SLWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SLWconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
@@ -4399,6 +4790,7 @@ func rewriteValuePPC64_OpPPC64ADD(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (ADDconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4413,11 +4805,28 @@ func rewriteValuePPC64_OpPPC64ADD(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADD (MOVDconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (ADDconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpPPC64ADDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64ADDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64ADDconst_0(v *Value) bool {
 	// match: (ADDconst [c] (ADDconst [d] x))
 	// cond: is32Bit(c+d)
 	// result: (ADDconst [c+d] x)
@@ -4470,22 +4879,42 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (AND x (XORconst [-1] y))
+func rewriteValuePPC64_OpPPC64AND_0(v *Value) bool {
+	// match: (AND x (NOR y y))
 	// cond:
 	// result: (ANDN x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpPPC64XORconst {
+		if v_1.Op != OpPPC64NOR {
 			break
 		}
-		if v_1.AuxInt != -1 {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if y != v_1.Args[1] {
 			break
 		}
-		y := v_1.Args[0]
+		v.reset(OpPPC64ANDN)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (AND (NOR y y) x)
+	// cond:
+	// result: (ANDN x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64NOR {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		if y != v_0.Args[1] {
+			break
+		}
+		x := v.Args[1]
 		v.reset(OpPPC64ANDN)
 		v.AddArg(x)
 		v.AddArg(y)
@@ -4495,6 +4924,7 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVDconst [c&d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4509,10 +4939,30 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 		v.AuxInt = c & d
 		return true
 	}
+	// match: (AND (MOVDconst [d]) (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c&d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpPPC64MOVDconst)
+		v.AuxInt = c & d
+		return true
+	}
 	// match: (AND x (MOVDconst [c]))
 	// cond: isU16Bit(c)
 	// result: (ANDconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4531,6 +4981,7 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 	// cond: isU16Bit(c)
 	// result: (ANDconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4549,6 +5000,7 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDconst [c&0xFF] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4558,6 +5010,27 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 		if x.Op != OpPPC64MOVBZload {
 			break
 		}
+		_ = x.Args[1]
+		v.reset(OpPPC64ANDconst)
+		v.AuxInt = c & 0xFF
+		v.AddArg(x)
+		return true
+	}
+	// match: (AND x:(MOVBZload _ _) (MOVDconst [c]))
+	// cond:
+	// result: (ANDconst [c&0xFF] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x.Op != OpPPC64MOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_1.AuxInt
 		v.reset(OpPPC64ANDconst)
 		v.AuxInt = c & 0xFF
 		v.AddArg(x)
@@ -4567,10 +5040,12 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 	// cond:
 	// result: (ANDconst [c&0xFF] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x.Op != OpPPC64MOVBZload {
 			break
 		}
+		_ = x.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
 			break
@@ -4581,11 +5056,29 @@ func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (AND (MOVDconst [c]) x:(MOVBZload _ _))
+	// cond:
+	// result: (ANDconst [c&0xFF] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if x.Op != OpPPC64MOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpPPC64ANDconst)
+		v.AuxInt = c & 0xFF
+		v.AddArg(x)
+		return true
+	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64ANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64ANDconst_0(v *Value) bool {
 	// match: (ANDconst [c] (ANDconst [d] x))
 	// cond:
 	// result: (ANDconst [c&d] x)
@@ -4724,13 +5217,14 @@ func rewriteValuePPC64_OpPPC64ANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMP(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpPPC64CMP_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMP x (MOVDconst [c]))
 	// cond: is16Bit(c)
 	// result: (CMPconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4749,6 +5243,7 @@ func rewriteValuePPC64_OpPPC64CMP(v *Value, config *Config) bool {
 	// cond: is16Bit(c)
 	// result: (InvertFlags (CMPconst y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4759,7 +5254,7 @@ func rewriteValuePPC64_OpPPC64CMP(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpPPC64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -4767,13 +5262,14 @@ func rewriteValuePPC64_OpPPC64CMP(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPU(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpPPC64CMPU_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPU x (MOVDconst [c]))
 	// cond: isU16Bit(c)
 	// result: (CMPUconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4792,6 +5288,7 @@ func rewriteValuePPC64_OpPPC64CMPU(v *Value, config *Config) bool {
 	// cond: isU16Bit(c)
 	// result: (InvertFlags (CMPUconst y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4802,7 +5299,7 @@ func rewriteValuePPC64_OpPPC64CMPU(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpPPC64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPUconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPUconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -4810,9 +5307,7 @@ func rewriteValuePPC64_OpPPC64CMPU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64CMPUconst_0(v *Value) bool {
 	// match: (CMPUconst (MOVDconst [x]) [y])
 	// cond: int64(x)==int64(y)
 	// result: (FlagEQ)
@@ -4863,13 +5358,14 @@ func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpPPC64CMPW_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPW x (MOVWreg y))
 	// cond:
 	// result: (CMPW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVWreg {
@@ -4885,6 +5381,7 @@ func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPW x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVWreg {
 			break
@@ -4900,6 +5397,7 @@ func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
 	// cond: is16Bit(c)
 	// result: (CMPWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4918,6 +5416,7 @@ func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
 	// cond: is16Bit(c)
 	// result: (InvertFlags (CMPWconst y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -4928,7 +5427,7 @@ func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpPPC64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -4936,13 +5435,14 @@ func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpPPC64CMPWU_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPWU x (MOVWZreg y))
 	// cond:
 	// result: (CMPWU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVWZreg {
@@ -4958,6 +5458,7 @@ func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
 	// cond:
 	// result: (CMPWU x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVWZreg {
 			break
@@ -4973,6 +5474,7 @@ func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
 	// cond: isU16Bit(c)
 	// result: (CMPWUconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -4991,6 +5493,7 @@ func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
 	// cond: isU16Bit(c)
 	// result: (InvertFlags (CMPWUconst y [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -5001,7 +5504,7 @@ func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpPPC64InvertFlags)
-		v0 := b.NewValue0(v.Line, OpPPC64CMPWUconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpPPC64CMPWUconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(y)
 		v.AddArg(v0)
@@ -5009,9 +5512,7 @@ func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64CMPWUconst_0(v *Value) bool {
 	// match: (CMPWUconst (MOVDconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -5062,9 +5563,7 @@ func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64CMPWconst_0(v *Value) bool {
 	// match: (CMPWconst (MOVDconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -5115,9 +5614,7 @@ func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64CMPconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64CMPconst_0(v *Value) bool {
 	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: int64(x)==int64(y)
 	// result: (FlagEQ)
@@ -5168,9 +5665,7 @@ func rewriteValuePPC64_OpPPC64CMPconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64Equal(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64Equal_0(v *Value) bool {
 	// match: (Equal (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -5222,15 +5717,96 @@ func rewriteValuePPC64_OpPPC64Equal(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64FMOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64FADD_0(v *Value) bool {
+	// match: (FADD (FMUL x y) z)
+	// cond:
+	// result: (FMADD x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64FMUL {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		z := v.Args[1]
+		v.reset(OpPPC64FMADD)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	// match: (FADD z (FMUL x y))
+	// cond:
+	// result: (FMADD x y z)
+	for {
+		_ = v.Args[1]
+		z := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64FMUL {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		y := v_1.Args[1]
+		v.reset(OpPPC64FMADD)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValuePPC64_OpPPC64FADDS_0(v *Value) bool {
+	// match: (FADDS (FMULS x y) z)
+	// cond:
+	// result: (FMADDS x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64FMULS {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		z := v.Args[1]
+		v.reset(OpPPC64FMADDS)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	// match: (FADDS z (FMULS x y))
+	// cond:
+	// result: (FMADDS x y z)
+	for {
+		_ = v.Args[1]
+		z := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64FMULS {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		y := v_1.Args[1]
+		v.reset(OpPPC64FMADDS)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValuePPC64_OpPPC64FMOVDload_0(v *Value) bool {
 	// match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5255,6 +5831,7 @@ func rewriteValuePPC64_OpPPC64FMOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5274,15 +5851,14 @@ func rewriteValuePPC64_OpPPC64FMOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64FMOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64FMOVDstore_0(v *Value) bool {
 	// match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (FMOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5308,6 +5884,7 @@ func rewriteValuePPC64_OpPPC64FMOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5330,15 +5907,14 @@ func rewriteValuePPC64_OpPPC64FMOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64FMOVSload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64FMOVSload_0(v *Value) bool {
 	// match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5363,6 +5939,7 @@ func rewriteValuePPC64_OpPPC64FMOVSload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5382,15 +5959,14 @@ func rewriteValuePPC64_OpPPC64FMOVSload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64FMOVSstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64FMOVSstore_0(v *Value) bool {
 	// match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (FMOVSstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5416,6 +5992,7 @@ func rewriteValuePPC64_OpPPC64FMOVSstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5438,9 +6015,51 @@ func rewriteValuePPC64_OpPPC64FMOVSstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64GreaterEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64FSUB_0(v *Value) bool {
+	// match: (FSUB (FMUL x y) z)
+	// cond:
+	// result: (FMSUB x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64FMUL {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		z := v.Args[1]
+		v.reset(OpPPC64FMSUB)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValuePPC64_OpPPC64FSUBS_0(v *Value) bool {
+	// match: (FSUBS (FMULS x y) z)
+	// cond:
+	// result: (FMSUBS x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64FMULS {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		z := v.Args[1]
+		v.reset(OpPPC64FMSUBS)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValuePPC64_OpPPC64GreaterEqual_0(v *Value) bool {
 	// match: (GreaterEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -5492,9 +6111,7 @@ func rewriteValuePPC64_OpPPC64GreaterEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64GreaterThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64GreaterThan_0(v *Value) bool {
 	// match: (GreaterThan (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -5546,9 +6163,7 @@ func rewriteValuePPC64_OpPPC64GreaterThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64LessEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64LessEqual_0(v *Value) bool {
 	// match: (LessEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [1])
@@ -5600,9 +6215,7 @@ func rewriteValuePPC64_OpPPC64LessEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64LessThan(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64LessThan_0(v *Value) bool {
 	// match: (LessThan (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -5654,15 +6267,14 @@ func rewriteValuePPC64_OpPPC64LessThan(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVBZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVBZload_0(v *Value) bool {
 	// match: (MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5687,6 +6299,7 @@ func rewriteValuePPC64_OpPPC64MOVBZload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5706,9 +6319,7 @@ func rewriteValuePPC64_OpPPC64MOVBZload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVBZreg_0(v *Value) bool {
 	// match: (MOVBZreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0xFF
 	// result: y
@@ -5760,6 +6371,7 @@ func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpPPC64MOVBZload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
@@ -5780,9 +6392,7 @@ func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVBreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVBreg_0(v *Value) bool {
 	// match: (MOVBreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0x7F
 	// result: y
@@ -5841,15 +6451,14 @@ func rewriteValuePPC64_OpPPC64MOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVBstore_0(v *Value) bool {
 	// match: (MOVBstore [off1] {sym} (ADDconst [off2] x) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVBstore [off1+off2] {sym} x val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5875,6 +6484,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -5901,6 +6511,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -5924,6 +6535,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVBreg {
@@ -5945,6 +6557,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVBZreg {
@@ -5962,15 +6575,14 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVBstorezero_0(v *Value) bool {
 	// match: (MOVBstorezero [off1] {sym} (ADDconst [off2] x) mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVBstorezero [off1+off2] {sym} x mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -5994,6 +6606,7 @@ func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6014,15 +6627,14 @@ func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVDload_0(v *Value) bool {
 	// match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6047,6 +6659,7 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6066,15 +6679,14 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVDstore_0(v *Value) bool {
 	// match: (MOVDstore [off1] {sym} (ADDconst [off2] x) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVDstore [off1+off2] {sym} x val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6100,6 +6712,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6126,6 +6739,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -6145,15 +6759,14 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVDstorezero_0(v *Value) bool {
 	// match: (MOVDstorezero [off1] {sym} (ADDconst [off2] x) mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVDstorezero [off1+off2] {sym} x mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6177,6 +6790,7 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6197,15 +6811,14 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHZload_0(v *Value) bool {
 	// match: (MOVHZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6230,6 +6843,7 @@ func rewriteValuePPC64_OpPPC64MOVHZload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6249,9 +6863,7 @@ func rewriteValuePPC64_OpPPC64MOVHZload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHZreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHZreg_0(v *Value) bool {
 	// match: (MOVHZreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0xFFFF
 	// result: y
@@ -6316,6 +6928,7 @@ func rewriteValuePPC64_OpPPC64MOVHZreg(v *Value, config *Config) bool {
 		if x.Op != OpPPC64MOVHZload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
@@ -6336,15 +6949,14 @@ func rewriteValuePPC64_OpPPC64MOVHZreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHload_0(v *Value) bool {
 	// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6369,6 +6981,7 @@ func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6388,9 +7001,7 @@ func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHreg_0(v *Value) bool {
 	// match: (MOVHreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0x7FFF
 	// result: y
@@ -6455,6 +7066,7 @@ func rewriteValuePPC64_OpPPC64MOVHreg(v *Value, config *Config) bool {
 		if x.Op != OpPPC64MOVHload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
@@ -6475,15 +7087,14 @@ func rewriteValuePPC64_OpPPC64MOVHreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHstore_0(v *Value) bool {
 	// match: (MOVHstore [off1] {sym} (ADDconst [off2] x) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVHstore [off1+off2] {sym} x val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6509,6 +7120,7 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6535,6 +7147,7 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -6558,6 +7171,7 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVHreg {
@@ -6579,6 +7193,7 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVHZreg {
@@ -6596,15 +7211,14 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVHstorezero_0(v *Value) bool {
 	// match: (MOVHstorezero [off1] {sym} (ADDconst [off2] x) mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVHstorezero [off1+off2] {sym} x mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6628,6 +7242,7 @@ func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6648,15 +7263,14 @@ func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWZload_0(v *Value) bool {
 	// match: (MOVWZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
 	// cond: canMergeSym(sym1,sym2)
 	// result: (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6681,6 +7295,7 @@ func rewriteValuePPC64_OpPPC64MOVWZload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6700,9 +7315,7 @@ func rewriteValuePPC64_OpPPC64MOVWZload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWZreg_0(v *Value) bool {
 	// match: (MOVWZreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0xFFFFFFFF
 	// result: y
@@ -6728,6 +7341,7 @@ func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value, config *Config) bool {
 		if y.Op != OpPPC64AND {
 			break
 		}
+		_ = y.Args[1]
 		y_0 := y.Args[0]
 		if y_0.Op != OpPPC64MOVDconst {
 			break
@@ -6741,6 +7355,28 @@ func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (MOVWZreg y:(AND _ (MOVDconst [c])))
+	// cond: uint64(c) <= 0xFFFFFFFF
+	// result: y
+	for {
+		y := v.Args[0]
+		if y.Op != OpPPC64AND {
+			break
+		}
+		_ = y.Args[1]
+		y_1 := y.Args[1]
+		if y_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := y_1.AuxInt
+		if !(uint64(c) <= 0xFFFFFFFF) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
 	// match: (MOVWZreg y:(MOVWZreg _))
 	// cond:
 	// result: y
@@ -6795,15 +7431,14 @@ func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWload_0(v *Value) bool {
 	// match: (MOVWload [off1] {sym1} (MOVDaddr [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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -6828,6 +7463,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6847,9 +7483,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWreg_0(v *Value) bool {
 	// match: (MOVWreg y:(ANDconst [c] _))
 	// cond: uint64(c) <= 0xFFFF
 	// result: y
@@ -6875,6 +7509,7 @@ func rewriteValuePPC64_OpPPC64MOVWreg(v *Value, config *Config) bool {
 		if y.Op != OpPPC64AND {
 			break
 		}
+		_ = y.Args[1]
 		y_0 := y.Args[0]
 		if y_0.Op != OpPPC64MOVDconst {
 			break
@@ -6888,6 +7523,28 @@ func rewriteValuePPC64_OpPPC64MOVWreg(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (MOVWreg y:(AND _ (MOVDconst [c])))
+	// cond: uint64(c) <= 0x7FFFFFFF
+	// result: y
+	for {
+		y := v.Args[0]
+		if y.Op != OpPPC64AND {
+			break
+		}
+		_ = y.Args[1]
+		y_1 := y.Args[1]
+		if y_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := y_1.AuxInt
+		if !(uint64(c) <= 0x7FFFFFFF) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
 	// match: (MOVWreg y:(MOVWreg _))
 	// cond:
 	// result: y
@@ -6942,15 +7599,14 @@ func rewriteValuePPC64_OpPPC64MOVWreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWstore_0(v *Value) bool {
 	// match: (MOVWstore [off1] {sym} (ADDconst [off2] x) val mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVWstore [off1+off2] {sym} x val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -6976,6 +7632,7 @@ func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -7002,6 +7659,7 @@ func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7025,6 +7683,7 @@ func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVWreg {
@@ -7046,6 +7705,7 @@ func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVWZreg {
@@ -7063,15 +7723,14 @@ func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MOVWstorezero(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MOVWstorezero_0(v *Value) bool {
 	// match: (MOVWstorezero [off1] {sym} (ADDconst [off2] x) mem)
 	// cond: is16Bit(off1+off2)
 	// result: (MOVWstorezero [off1+off2] {sym} x mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64ADDconst {
 			break
@@ -7095,6 +7754,7 @@ func rewriteValuePPC64_OpPPC64MOVWstorezero(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDaddr {
 			break
@@ -7115,9 +7775,7 @@ func rewriteValuePPC64_OpPPC64MOVWstorezero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64MaskIfNotCarry(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64MaskIfNotCarry_0(v *Value) bool {
 	// match: (MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _)))
 	// cond: c < 0 && d > 0 && c + d < 0
 	// result: (MOVDconst [-1])
@@ -7141,9 +7799,7 @@ func rewriteValuePPC64_OpPPC64MaskIfNotCarry(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64NotEqual(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64NotEqual_0(v *Value) bool {
 	// match: (NotEqual (FlagEQ))
 	// cond:
 	// result: (MOVDconst [0])
@@ -7195,13 +7851,120 @@ func rewriteValuePPC64_OpPPC64NotEqual(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64OR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64OR_0(v *Value) bool {
+	// match: (OR (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SLDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SRDconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SLDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SLWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SLWconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (OR (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [c|d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -7216,10 +7979,30 @@ func rewriteValuePPC64_OpPPC64OR(v *Value, config *Config) bool {
 		v.AuxInt = c | d
 		return true
 	}
+	// match: (OR (MOVDconst [d]) (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c|d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpPPC64MOVDconst)
+		v.AuxInt = c | d
+		return true
+	}
 	// match: (OR x (MOVDconst [c]))
 	// cond: isU32Bit(c)
 	// result: (ORconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7238,6 +8021,7 @@ func rewriteValuePPC64_OpPPC64OR(v *Value, config *Config) bool {
 	// cond: isU32Bit(c)
 	// result: (ORconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpPPC64MOVDconst {
 			break
@@ -7254,13 +8038,12 @@ func rewriteValuePPC64_OpPPC64OR(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64ORN(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64ORN_0(v *Value) bool {
 	// match: (ORN x (MOVDconst [-1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7276,9 +8059,7 @@ func rewriteValuePPC64_OpPPC64ORN(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64ORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64ORconst_0(v *Value) bool {
 	// match: (ORconst [c] (ORconst [d] x))
 	// cond:
 	// result: (ORconst [c|d] x)
@@ -7321,13 +8102,12 @@ func rewriteValuePPC64_OpPPC64ORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64SUB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpPPC64SUB_0(v *Value) bool {
 	// match: (SUB x (MOVDconst [c]))
 	// cond: is32Bit(-c)
 	// result: (ADDconst [-c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7344,68 +8124,194 @@ func rewriteValuePPC64_OpPPC64SUB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpPPC64XOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR (MOVDconst [c]) (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [c^d])
+func rewriteValuePPC64_OpPPC64XOR_0(v *Value) bool {
+	// match: (XOR (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpPPC64MOVDconst {
+		if v_0.Op != OpPPC64SLDconst {
 			break
 		}
 		c := v_0.AuxInt
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpPPC64MOVDconst {
+		if v_1.Op != OpPPC64SRDconst {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpPPC64MOVDconst)
-		v.AuxInt = c ^ d
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x (MOVDconst [c]))
-	// cond: isU32Bit(c)
-	// result: (XORconst [c] x)
+	// match: (XOR (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (ROTLconst [c] x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpPPC64MOVDconst {
+		if v_1.Op != OpPPC64SLDconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(isU32Bit(c)) {
+		if x != v_1.Args[0] {
 			break
 		}
-		v.reset(OpPPC64XORconst)
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR (MOVDconst [c]) x)
-	// cond: isU32Bit(c)
-	// result: (XORconst [c] x)
+	// match: (XOR (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpPPC64MOVDconst {
+		if v_0.Op != OpPPC64SLWconst {
 			break
 		}
 		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isU32Bit(c)) {
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SRWconst {
 			break
 		}
-		v.reset(OpPPC64XORconst)
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuePPC64_OpPPC64XORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+	// match: (XOR (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (ROTLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64SRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64SLWconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpPPC64ROTLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XOR (MOVDconst [c]) (MOVDconst [d]))
+	// cond:
+	// result: (MOVDconst [c^d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpPPC64MOVDconst)
+		v.AuxInt = c ^ d
+		return true
+	}
+	// match: (XOR (MOVDconst [d]) (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c^d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpPPC64MOVDconst)
+		v.AuxInt = c ^ d
+		return true
+	}
+	// match: (XOR x (MOVDconst [c]))
+	// cond: isU32Bit(c)
+	// result: (XORconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpPPC64XORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XOR (MOVDconst [c]) x)
+	// cond: isU32Bit(c)
+	// result: (XORconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpPPC64MOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpPPC64XORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuePPC64_OpPPC64XORconst_0(v *Value) bool {
 	// match: (XORconst [c] (XORconst [d] x))
 	// cond:
 	// result: (XORconst [c^d] x)
@@ -7437,25 +8343,112 @@ func rewriteValuePPC64_OpPPC64XORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpPopCount16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PopCount16 x)
+	// cond:
+	// result: (POPCNTW (MOVHZreg x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTW)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVHZreg, typ.Int64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValuePPC64_OpPopCount32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PopCount32 x)
+	// cond:
+	// result: (POPCNTW (MOVWZreg x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTW)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWZreg, typ.Int64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValuePPC64_OpPopCount64_0(v *Value) bool {
+	// match: (PopCount64 x)
+	// cond:
+	// result: (POPCNTD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValuePPC64_OpPopCount8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PopCount8 x)
+	// cond:
+	// result: (POPCNTB (MOVBreg x))
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64POPCNTB)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVBreg, typ.Int64)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValuePPC64_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: (LoweredRound32F x)
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64LoweredRound32F)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValuePPC64_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: (LoweredRound64F x)
+	for {
+		x := v.Args[0]
+		v.reset(OpPPC64LoweredRound64F)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValuePPC64_OpRsh16Ux16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux16 x y)
 	// cond:
-	// result: (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+	// result: (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7464,13 +8457,16 @@ func rewriteValuePPC64_OpRsh16Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 x (Const64 [c]))
 	// cond: uint32(c) < 16
 	// result: (SRWconst (ZeroExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7482,7 +8478,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -7491,6 +8487,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
 	// cond: uint32(c) < 16
 	// result: (SRWconst (ZeroExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7502,27 +8499,28 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh16Ux32 x y)
 	// cond:
-	// result: (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+	// result: (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7531,13 +8529,16 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SRWconst (ZeroExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7549,7 +8550,7 @@ func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -7558,6 +8559,7 @@ func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -7574,6 +8576,7 @@ func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) < 16
 	// result: (SRWconst (ZeroExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7585,25 +8588,26 @@ func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh16Ux64 x y)
 	// cond:
-	// result: (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+	// result: (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -7612,25 +8616,28 @@ func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux8 x y)
 	// cond:
-	// result: (SRW  (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+	// result: (SRW  (ZeroExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7639,25 +8646,28 @@ func rewriteValuePPC64_OpRsh16Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 x y)
 	// cond:
-	// result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+	// result: (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7666,13 +8676,16 @@ func rewriteValuePPC64_OpRsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x32 x (Const64 [c]))
 	// cond: uint32(c) < 16
 	// result: (SRAWconst (SignExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7684,15 +8697,16 @@ func rewriteValuePPC64_OpRsh16x32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16x32  x (MOVDconst [c]))
+	// match: (Rsh16x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 16
 	// result: (SRAWconst (SignExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7704,27 +8718,28 @@ func rewriteValuePPC64_OpRsh16x32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh16x32 x y)
 	// cond:
-	// result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+	// result: (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7733,13 +8748,16 @@ func rewriteValuePPC64_OpRsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x64 x (Const64 [c]))
 	// cond: uint64(c) < 16
 	// result: (SRAWconst (SignExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7751,7 +8769,7 @@ func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -7760,6 +8778,7 @@ func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 16
 	// result: (SRAWconst (SignExt16to32 x) [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7771,15 +8790,16 @@ func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = 63
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16x64  x (MOVDconst [c]))
+	// match: (Rsh16x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 16
 	// result: (SRAWconst (SignExt16to32 x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7791,25 +8811,26 @@ func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh16x64 x y)
 	// cond:
-	// result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+	// result: (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -7818,25 +8839,28 @@ func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x8 x y)
 	// cond:
-	// result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+	// result: (SRAW (SignExt16to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -16
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -7845,23 +8869,26 @@ func rewriteValuePPC64_OpRsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 x y)
 	// cond:
-	// result: (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+	// result: (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -7870,13 +8897,16 @@ func rewriteValuePPC64_OpRsh32Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux32 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SRWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7895,6 +8925,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value, config *Config) bool {
 	// cond: uint32(c) < 32
 	// result: (SRWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7911,18 +8942,19 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32Ux32 x y)
 	// cond:
-	// result: (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+	// result: (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -7931,13 +8963,16 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SRWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -7956,6 +8991,7 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -7972,6 +9008,7 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) < 32
 	// result: (SRWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -7988,16 +9025,17 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32Ux64 x y)
 	// cond:
-	// result: (SRW  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+	// result: (SRW  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -8006,23 +9044,26 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux8 x y)
 	// cond:
-	// result: (SRW x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+	// result: (SRW x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8031,23 +9072,26 @@ func rewriteValuePPC64_OpRsh32Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 x y)
 	// cond:
-	// result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+	// result: (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8056,13 +9100,16 @@ func rewriteValuePPC64_OpRsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x32 x (Const64 [c]))
 	// cond: uint32(c) < 32
 	// result: (SRAWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8077,10 +9124,11 @@ func rewriteValuePPC64_OpRsh32x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh32x32  x (MOVDconst [c]))
+	// match: (Rsh32x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 32
 	// result: (SRAWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8097,18 +9145,19 @@ func rewriteValuePPC64_OpRsh32x32(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32x32 x y)
 	// cond:
-	// result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+	// result: (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8117,13 +9166,16 @@ func rewriteValuePPC64_OpRsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x64 x (Const64 [c]))
 	// cond: uint64(c) < 32
 	// result: (SRAWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8142,6 +9194,7 @@ func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 32
 	// result: (SRAWconst x [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8156,10 +9209,11 @@ func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh32x64  x (MOVDconst [c]))
+	// match: (Rsh32x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 32
 	// result: (SRAWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8176,16 +9230,17 @@ func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32x64 x y)
 	// cond:
-	// result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+	// result: (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -8194,23 +9249,26 @@ func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x8 x y)
 	// cond:
-	// result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+	// result: (SRAW x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -32
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8219,23 +9277,26 @@ func rewriteValuePPC64_OpRsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux16 x y)
 	// cond:
-	// result: (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+	// result: (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8244,13 +9305,16 @@ func rewriteValuePPC64_OpRsh64Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux32 x (Const64 [c]))
 	// cond: uint32(c) < 64
 	// result: (SRDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8269,6 +9333,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value, config *Config) bool {
 	// cond: uint32(c) < 64
 	// result: (SRDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8285,18 +9350,19 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64Ux32 x y)
 	// cond:
-	// result: (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+	// result: (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8305,13 +9371,16 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 64
 	// result: (SRDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8330,6 +9399,7 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 64
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -8346,6 +9416,7 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
 	// cond: uint64(c) < 64
 	// result: (SRDconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8362,16 +9433,17 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64Ux64 x y)
 	// cond:
-	// result: (SRD  x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+	// result: (SRD  x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -8380,23 +9452,26 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux8 x y)
 	// cond:
-	// result: (SRD x  (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+	// result: (SRD x  (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8405,23 +9480,26 @@ func rewriteValuePPC64_OpRsh64Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x16 x y)
 	// cond:
-	// result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+	// result: (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8430,13 +9508,16 @@ func rewriteValuePPC64_OpRsh64x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x32 x (Const64 [c]))
 	// cond: uint32(c) < 64
 	// result: (SRADconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8451,10 +9532,11 @@ func rewriteValuePPC64_OpRsh64x32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64x32  x (MOVDconst [c]))
+	// match: (Rsh64x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 64
 	// result: (SRADconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8471,18 +9553,19 @@ func rewriteValuePPC64_OpRsh64x32(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64x32 x y)
 	// cond:
-	// result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+	// result: (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8491,13 +9574,16 @@ func rewriteValuePPC64_OpRsh64x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x64 x (Const64 [c]))
 	// cond: uint64(c) < 64
 	// result: (SRADconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8516,6 +9602,7 @@ func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
 	// cond: uint64(c) >= 64
 	// result: (SRADconst x [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8530,10 +9617,11 @@ func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64x64  x (MOVDconst [c]))
+	// match: (Rsh64x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 64
 	// result: (SRADconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8550,16 +9638,17 @@ func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64x64 x y)
 	// cond:
-	// result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+	// result: (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -8568,23 +9657,26 @@ func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh64x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x8 x y)
 	// cond:
-	// result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+	// result: (SRAD x (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAD)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v2 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v2.AuxInt = -64
-		v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -8593,25 +9685,28 @@ func rewriteValuePPC64_OpRsh64x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 x y)
 	// cond:
-	// result: (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+	// result: (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8620,13 +9715,16 @@ func rewriteValuePPC64_OpRsh8Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux32  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux32 x (Const64 [c]))
 	// cond: uint32(c) < 8
 	// result: (SRWconst (ZeroExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8638,15 +9736,16 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8Ux32  x (MOVDconst [c]))
+	// match: (Rsh8Ux32 x (MOVDconst [c]))
 	// cond: uint32(c) < 8
 	// result: (SRWconst (ZeroExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8658,27 +9757,28 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh8Ux32 x y)
 	// cond:
-	// result: (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+	// result: (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8687,13 +9787,16 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux64  x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SRWconst (ZeroExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8705,15 +9808,16 @@ func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8Ux64  _ (Const64 [c]))
+	// match: (Rsh8Ux64 _ (Const64 [c]))
 	// cond: uint64(c) >= 8
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
@@ -8726,10 +9830,11 @@ func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Rsh8Ux64  x (MOVDconst [c]))
+	// match: (Rsh8Ux64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SRWconst (ZeroExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8741,25 +9846,26 @@ func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh8Ux64 x y)
 	// cond:
-	// result: (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+	// result: (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -8768,25 +9874,28 @@ func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux8 x y)
 	// cond:
-	// result: (SRW  (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+	// result: (SRW  (ZeroExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRW)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8795,25 +9904,28 @@ func rewriteValuePPC64_OpRsh8Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 x y)
 	// cond:
-	// result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+	// result: (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8822,13 +9934,16 @@ func rewriteValuePPC64_OpRsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x32   x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x32 x (Const64 [c]))
 	// cond: uint32(c) < 8
 	// result: (SRAWconst (SignExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8840,15 +9955,16 @@ func rewriteValuePPC64_OpRsh8x32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8x32   x (MOVDconst [c]))
+	// match: (Rsh8x32 x (MOVDconst [c]))
 	// cond: uint32(c) < 8
 	// result: (SRAWconst (SignExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8860,27 +9976,28 @@ func rewriteValuePPC64_OpRsh8x32(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh8x32 x y)
 	// cond:
-	// result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+	// result: (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -8889,13 +10006,16 @@ func rewriteValuePPC64_OpRsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x64   x (Const64 [c]))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint64(c) < 8
 	// result: (SRAWconst (SignExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8907,15 +10027,16 @@ func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8x64  x (Const64 [c]))
+	// match: (Rsh8x64 x (Const64 [c]))
 	// cond: uint64(c) >= 8
 	// result: (SRAWconst (SignExt8to32  x) [63])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
@@ -8927,15 +10048,16 @@ func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = 63
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8x64   x (MOVDconst [c]))
+	// match: (Rsh8x64 x (MOVDconst [c]))
 	// cond: uint64(c) < 8
 	// result: (SRAWconst (SignExt8to32  x) [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpPPC64MOVDconst {
@@ -8947,25 +10069,26 @@ func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpPPC64SRAWconst)
 		v.AuxInt = c
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Rsh8x64 x y)
 	// cond:
-	// result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+	// result: (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -8974,25 +10097,28 @@ func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x8 x y)
 	// cond:
-	// result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+	// result: (SRAW (SignExt8to32 x) (ORN y <typ.Int64> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SRAW)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpPPC64ORN, typ.Int64)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
-		v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpPPC64MaskIfNotCarry, typ.Int64)
+		v3 := b.NewValue0(v.Pos, OpPPC64ADDconstForCarry, types.TypeFlags)
 		v3.AuxInt = -8
-		v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -9001,9 +10127,7 @@ func rewriteValuePPC64_OpRsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -9014,9 +10138,7 @@ func rewriteValuePPC64_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSignExt16to64_0(v *Value) bool {
 	// match: (SignExt16to64 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -9027,9 +10149,7 @@ func rewriteValuePPC64_OpSignExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSignExt32to64_0(v *Value) bool {
 	// match: (SignExt32to64 x)
 	// cond:
 	// result: (MOVWreg x)
@@ -9040,10 +10160,8 @@ func rewriteValuePPC64_OpSignExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to16  x)
+func rewriteValuePPC64_OpSignExt8to16_0(v *Value) bool {
+	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9053,10 +10171,8 @@ func rewriteValuePPC64_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to32  x)
+func rewriteValuePPC64_OpSignExt8to32_0(v *Value) bool {
+	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9066,10 +10182,8 @@ func rewriteValuePPC64_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSignExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to64  x)
+func rewriteValuePPC64_OpSignExt8to64_0(v *Value) bool {
+	// match: (SignExt8to64 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9079,30 +10193,24 @@ func rewriteValuePPC64_OpSignExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (XORconst [-1] (SRADconst <t> (ADDconst <t> x [-1]) [63]))
+	// result: (SRADconst (NEG <t> x) [63])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(OpPPC64XORconst)
-		v.AuxInt = -1
-		v0 := b.NewValue0(v.Line, OpPPC64SRADconst, t)
-		v0.AuxInt = 63
-		v1 := b.NewValue0(v.Line, OpPPC64ADDconst, t)
-		v1.AuxInt = -1
-		v1.AddArg(x)
-		v0.AddArg(v1)
+		v.reset(OpPPC64SRADconst)
+		v.AuxInt = 63
+		v0 := b.NewValue0(v.Pos, OpPPC64NEG, t)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuePPC64_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (FSQRT x)
@@ -9113,9 +10221,7 @@ func rewriteValuePPC64_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -9130,20 +10236,17 @@ func rewriteValuePPC64_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+func rewriteValuePPC64_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (FMOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpPPC64FMOVDstore)
@@ -9152,17 +10255,16 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is32BitFloat(val.Type)
 	// result: (FMOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpPPC64FMOVDstore)
@@ -9171,17 +10273,16 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (FMOVSstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpPPC64FMOVSstore)
@@ -9190,17 +10291,16 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond: (is64BitInt(val.Type) || isPtr(val.Type))
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type))
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitInt(val.Type) || isPtr(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type))) {
 			break
 		}
 		v.reset(OpPPC64MOVDstore)
@@ -9209,17 +10309,16 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitInt(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitInt(val.Type)
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitInt(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitInt(val.Type)) {
 			break
 		}
 		v.reset(OpPPC64MOVWstore)
@@ -9228,32 +10327,36 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(OpPPC64MOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [1] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(OpPPC64MOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
@@ -9262,13 +10365,12 @@ func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuePPC64_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub16  x y)
+func rewriteValuePPC64_OpSub16_0(v *Value) bool {
+	// match: (Sub16 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
@@ -9277,13 +10379,12 @@ func rewriteValuePPC64_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub32  x y)
+func rewriteValuePPC64_OpSub32_0(v *Value) bool {
+	// match: (Sub32 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
@@ -9292,13 +10393,12 @@ func rewriteValuePPC64_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (FSUBS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FSUBS)
@@ -9307,13 +10407,12 @@ func rewriteValuePPC64_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSub64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub64  x y)
+func rewriteValuePPC64_OpSub64_0(v *Value) bool {
+	// match: (Sub64 x y)
 	// cond:
 	// result: (SUB  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
@@ -9322,13 +10421,12 @@ func rewriteValuePPC64_OpSub64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (FSUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64FSUB)
@@ -9337,13 +10435,12 @@ func rewriteValuePPC64_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub8   x y)
+func rewriteValuePPC64_OpSub8_0(v *Value) bool {
+	// match: (Sub8 x y)
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
@@ -9352,13 +10449,12 @@ func rewriteValuePPC64_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUB  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64SUB)
@@ -9367,10 +10463,8 @@ func rewriteValuePPC64_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc16to8  x)
+func rewriteValuePPC64_OpTrunc16to8_0(v *Value) bool {
+	// match: (Trunc16to8 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9380,9 +10474,7 @@ func rewriteValuePPC64_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -9393,10 +10485,8 @@ func rewriteValuePPC64_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc32to8  x)
+func rewriteValuePPC64_OpTrunc32to8_0(v *Value) bool {
+	// match: (Trunc32to8 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9406,9 +10496,7 @@ func rewriteValuePPC64_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpTrunc64to16_0(v *Value) bool {
 	// match: (Trunc64to16 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -9419,9 +10507,7 @@ func rewriteValuePPC64_OpTrunc64to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc64to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpTrunc64to32_0(v *Value) bool {
 	// match: (Trunc64to32 x)
 	// cond:
 	// result: (MOVWreg x)
@@ -9432,10 +10518,8 @@ func rewriteValuePPC64_OpTrunc64to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc64to8  x)
+func rewriteValuePPC64_OpTrunc64to8_0(v *Value) bool {
+	// match: (Trunc64to8 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -9445,13 +10529,12 @@ func rewriteValuePPC64_OpTrunc64to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64XOR)
@@ -9460,13 +10543,12 @@ func rewriteValuePPC64_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64XOR)
@@ -9475,13 +10557,12 @@ func rewriteValuePPC64_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpXor64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpXor64_0(v *Value) bool {
 	// match: (Xor64 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64XOR)
@@ -9490,13 +10571,12 @@ func rewriteValuePPC64_OpXor64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Xor8  x y)
+func rewriteValuePPC64_OpXor8_0(v *Value) bool {
+	// match: (Xor8 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpPPC64XOR)
@@ -9505,217 +10585,225 @@ func rewriteValuePPC64_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZero(v *Value, config *Config) bool {
+func rewriteValuePPC64_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] destptr mem)
+	// cond:
 	// result: (MOVBstorezero destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVBstorezero)
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0
+	// match: (Zero [2] destptr mem)
+	// cond:
 	// result: (MOVHstorezero destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVHstorezero)
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
-	// result: (MOVBstorezero [1] destptr 		(MOVBstorezero [0] destptr mem))
+	// match: (Zero [3] destptr mem)
+	// cond:
+	// result: (MOVBstorezero [2] destptr 		(MOVHstorezero destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVBstorezero)
-		v.AuxInt = 1
+		v.AuxInt = 2
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
-		v0.AuxInt = 0
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVHstorezero, types.TypeMem)
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0
+	// match: (Zero [4] destptr mem)
+	// cond:
 	// result: (MOVWstorezero destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVWstorezero)
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0
-	// result: (MOVHstorezero [2] destptr 		(MOVHstorezero [0] destptr mem))
+	// match: (Zero [5] destptr mem)
+	// cond:
+	// result: (MOVBstorezero [4] destptr         	(MOVWstorezero destptr mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 5 {
+			break
+		}
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+		v.reset(OpPPC64MOVBstorezero)
+		v.AuxInt = 4
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWstorezero, types.TypeMem)
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [6] destptr mem)
+	// cond:
+	// result: (MOVHstorezero [4] destptr 		(MOVWstorezero destptr mem))
+	for {
+		if v.AuxInt != 6 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVHstorezero)
-		v.AuxInt = 2
+		v.AuxInt = 4
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
-		v0.AuxInt = 0
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVWstorezero, types.TypeMem)
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
-	// result: (MOVBstorezero [3] destptr 		(MOVBstorezero [2] destptr 			(MOVBstorezero [1] destptr 				(MOVBstorezero [0] destptr mem))))
+	// match: (Zero [7] destptr mem)
+	// cond:
+	// result: (MOVBstorezero [6] destptr 		(MOVHstorezero [4] destptr 			(MOVWstorezero destptr mem)))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 7 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVBstorezero)
-		v.AuxInt = 3
+		v.AuxInt = 6
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
-		v0.AuxInt = 2
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVHstorezero, types.TypeMem)
+		v0.AuxInt = 4
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
-		v1.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVWstorezero, types.TypeMem)
 		v1.AddArg(destptr)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
-		v2.AuxInt = 0
-		v2.AddArg(destptr)
-		v2.AddArg(mem)
-		v1.AddArg(v2)
+		v1.AddArg(mem)
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
-	// result: (MOVDstorezero [0] destptr mem)
+	// match: (Zero [8] destptr mem)
+	// cond:
+	// result: (MOVDstorezero destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVDstorezero)
-		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
-	// result: (MOVWstorezero [4] destptr 		(MOVWstorezero [0] destptr mem))
+	// match: (Zero [12] destptr mem)
+	// cond:
+	// result: (MOVWstorezero [8] destptr                 (MOVDstorezero [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+		if v.AuxInt != 12 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVWstorezero)
-		v.AuxInt = 4
+		v.AuxInt = 8
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVWstorezero, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0
-	// result: (MOVHstorezero [6] destptr 		(MOVHstorezero [4] destptr 			(MOVHstorezero [2] destptr 				(MOVHstorezero [0] destptr mem))))
+	return false
+}
+func rewriteValuePPC64_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Zero [16] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [8] destptr                 (MOVDstorezero [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0) {
+		if v.AuxInt != 16 {
 			break
 		}
-		v.reset(OpPPC64MOVHstorezero)
-		v.AuxInt = 6
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpPPC64MOVDstorezero)
+		v.AuxInt = 8
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
-		v0.AuxInt = 4
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 0
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
-		v1.AuxInt = 2
-		v1.AddArg(destptr)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
-		v2.AuxInt = 0
-		v2.AddArg(destptr)
-		v2.AddArg(mem)
-		v1.AddArg(v2)
-		v0.AddArg(v1)
+		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
-	// result: (MOVBstorezero [2] destptr 		(MOVBstorezero [1] destptr 			(MOVBstorezero [0] destptr mem)))
+	// match: (Zero [24] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [16] destptr 		(MOVDstorezero [8] destptr 			(MOVDstorezero [0] destptr mem)))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 24 {
 			break
 		}
-		v.reset(OpPPC64MOVBstorezero)
-		v.AuxInt = 2
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpPPC64MOVDstorezero)
+		v.AuxInt = 16
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
-		v0.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 8
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
 		v1.AuxInt = 0
 		v1.AddArg(destptr)
 		v1.AddArg(mem)
@@ -9723,103 +10811,158 @@ func rewriteValuePPC64_OpZero(v *Value, config *Config) bool {
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0
-	// result: (MOVDstorezero [8] destptr                 (MOVDstorezero [0] destptr mem))
+	// match: (Zero [32] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [24] destptr 		(MOVDstorezero [16] destptr 			(MOVDstorezero [8] destptr 				(MOVDstorezero [0] destptr mem))))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+		if v.AuxInt != 32 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVDstorezero)
-		v.AuxInt = 8
+		v.AuxInt = 24
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v0.AuxInt = 0
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 16
 		v0.AddArg(destptr)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v1.AuxInt = 8
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v2.AuxInt = 0
+		v2.AddArg(destptr)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0
-	// result: (MOVDstorezero [16] destptr 		(MOVDstorezero [8] destptr 			(MOVDstorezero [0] destptr mem)))
+	// match: (Zero [40] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [32] destptr 		(MOVDstorezero [24] destptr 			(MOVDstorezero [16] destptr 				(MOVDstorezero [8] destptr 					(MOVDstorezero [0] destptr mem)))))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+		if v.AuxInt != 40 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVDstorezero)
-		v.AuxInt = 16
+		v.AuxInt = 32
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v0.AuxInt = 8
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 24
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v1.AuxInt = 0
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v1.AuxInt = 16
 		v1.AddArg(destptr)
-		v1.AddArg(mem)
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v2.AuxInt = 8
+		v2.AddArg(destptr)
+		v3 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v3.AuxInt = 0
+		v3.AddArg(destptr)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 32 && SizeAndAlign(s).Align()%8 == 0
-	// result: (MOVDstorezero [24] destptr 		(MOVDstorezero [16] destptr 			(MOVDstorezero [8] destptr 				(MOVDstorezero [0] destptr mem))))
+	// match: (Zero [48] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [40] destptr 		(MOVDstorezero [32] destptr 			(MOVDstorezero [24] destptr 				(MOVDstorezero [16] destptr 					(MOVDstorezero [8] destptr 						(MOVDstorezero [0] destptr mem))))))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 48 {
+			break
+		}
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 32 && SizeAndAlign(s).Align()%8 == 0) {
+		v.reset(OpPPC64MOVDstorezero)
+		v.AuxInt = 40
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 32
+		v0.AddArg(destptr)
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v1.AuxInt = 24
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v2.AuxInt = 16
+		v2.AddArg(destptr)
+		v3 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v3.AuxInt = 8
+		v3.AddArg(destptr)
+		v4 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v4.AuxInt = 0
+		v4.AddArg(destptr)
+		v4.AddArg(mem)
+		v3.AddArg(v4)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [56] destptr mem)
+	// cond:
+	// result: (MOVDstorezero [48] destptr 		(MOVDstorezero [40] destptr 			(MOVDstorezero [32] destptr 				(MOVDstorezero [24] destptr 					(MOVDstorezero [16] destptr 						(MOVDstorezero [8] destptr 							(MOVDstorezero [0] destptr mem)))))))
+	for {
+		if v.AuxInt != 56 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpPPC64MOVDstorezero)
-		v.AuxInt = 24
+		v.AuxInt = 48
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v0.AuxInt = 16
+		v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v0.AuxInt = 40
 		v0.AddArg(destptr)
-		v1 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v1.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v1.AuxInt = 32
 		v1.AddArg(destptr)
-		v2 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
-		v2.AuxInt = 0
+		v2 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v2.AuxInt = 24
 		v2.AddArg(destptr)
-		v2.AddArg(mem)
+		v3 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v3.AuxInt = 16
+		v3.AddArg(destptr)
+		v4 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v4.AuxInt = 8
+		v4.AddArg(destptr)
+		v5 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem)
+		v5.AuxInt = 0
+		v5.AddArg(destptr)
+		v5.AddArg(mem)
+		v4.AddArg(v5)
+		v3.AddArg(v4)
+		v2.AddArg(v3)
 		v1.AddArg(v2)
 		v0.AddArg(v1)
 		v.AddArg(v0)
 		return true
 	}
 	// match: (Zero [s] ptr mem)
-	// cond: (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0
-	// result: (LoweredZero [SizeAndAlign(s).Align()] 		ptr 		(ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)]) 		mem)
+	// cond:
+	// result: (LoweredZero [s] ptr mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
-		if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0) {
-			break
-		}
 		v.reset(OpPPC64LoweredZero)
-		v.AuxInt = SizeAndAlign(s).Align()
+		v.AuxInt = s
 		v.AddArg(ptr)
-		v0 := b.NewValue0(v.Line, OpPPC64ADDconst, ptr.Type)
-		v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
-		v0.AddArg(ptr)
-		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	return false
 }
-func rewriteValuePPC64_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHZreg x)
@@ -9830,9 +10973,7 @@ func rewriteValuePPC64_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpZeroExt16to64_0(v *Value) bool {
 	// match: (ZeroExt16to64 x)
 	// cond:
 	// result: (MOVHZreg x)
@@ -9843,9 +10984,7 @@ func rewriteValuePPC64_OpZeroExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuePPC64_OpZeroExt32to64_0(v *Value) bool {
 	// match: (ZeroExt32to64 x)
 	// cond:
 	// result: (MOVWZreg x)
@@ -9856,10 +10995,8 @@ func rewriteValuePPC64_OpZeroExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to16  x)
+func rewriteValuePPC64_OpZeroExt8to16_0(v *Value) bool {
+	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -9869,10 +11006,8 @@ func rewriteValuePPC64_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to32  x)
+func rewriteValuePPC64_OpZeroExt8to32_0(v *Value) bool {
+	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -9882,10 +11017,8 @@ func rewriteValuePPC64_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuePPC64_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to64  x)
+func rewriteValuePPC64_OpZeroExt8to64_0(v *Value) bool {
+	// match: (ZeroExt8to64 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -9895,7 +11028,13 @@ func rewriteValuePPC64_OpZeroExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlockPPC64(b *Block, config *Config) bool {
+func rewriteBlockPPC64(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockPPC64EQ:
 		// match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no)
@@ -9915,15 +11054,11 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			}
 			c := v_0.AuxInt
 			x := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64EQ
-			v0 := b.NewValue0(v.Line, OpPPC64ANDCCconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
 			v0.AuxInt = c
 			v0.AddArg(x)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (CMPWconst [0] (ANDconst [c] x)) yes no)
@@ -9943,15 +11078,11 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			}
 			c := v_0.AuxInt
 			x := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64EQ
-			v0 := b.NewValue0(v.Line, OpPPC64ANDCCconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
 			v0.AuxInt = c
 			v0.AddArg(x)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagEQ) yes no)
@@ -9962,12 +11093,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagLT) yes no)
@@ -9978,13 +11105,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (EQ (FlagGT) yes no)
@@ -9995,13 +11118,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (EQ (InvertFlags cmp) yes no)
@@ -10013,12 +11132,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64EQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockPPC64GE:
@@ -10030,12 +11145,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (FlagLT) yes no)
@@ -10046,13 +11157,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GE (FlagGT) yes no)
@@ -10063,12 +11170,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (InvertFlags cmp) yes no)
@@ -10080,12 +11183,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockPPC64GT:
@@ -10097,13 +11196,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GT (FlagLT) yes no)
@@ -10114,13 +11209,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GT (FlagGT) yes no)
@@ -10131,12 +11222,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GT (InvertFlags cmp) yes no)
@@ -10148,12 +11235,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockIf:
@@ -10166,12 +11249,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64EQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (NotEqual cc) yes no)
@@ -10183,12 +11262,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessThan cc) yes no)
@@ -10200,12 +11275,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (LessEqual cc) yes no)
@@ -10217,12 +11288,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterThan cc) yes no)
@@ -10234,12 +11301,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (GreaterEqual cc) yes no)
@@ -10251,12 +11314,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (FLessThan cc) yes no)
@@ -10268,12 +11327,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FLT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (FLessEqual cc) yes no)
@@ -10285,12 +11340,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FLE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (FGreaterThan cc) yes no)
@@ -10302,12 +11353,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (FGreaterEqual cc) yes no)
@@ -10319,12 +11366,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If cond yes no)
@@ -10334,15 +11377,11 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
-			v0 := b.NewValue0(v.Line, OpPPC64CMPWconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpPPC64CMPWconst, types.TypeFlags)
 			v0.AuxInt = 0
 			v0.AddArg(cond)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockPPC64LE:
@@ -10354,12 +11393,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LE (FlagLT) yes no)
@@ -10370,12 +11405,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LE (FlagGT) yes no)
@@ -10386,13 +11417,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LE (InvertFlags cmp) yes no)
@@ -10404,12 +11431,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockPPC64LT:
@@ -10421,13 +11444,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LT (FlagLT) yes no)
@@ -10438,12 +11457,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LT (FlagGT) yes no)
@@ -10454,13 +11469,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LT (InvertFlags cmp) yes no)
@@ -10472,12 +11483,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockPPC64NE:
@@ -10497,12 +11504,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64EQ
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (NotEqual cc)) yes no)
@@ -10521,12 +11524,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (LessThan cc)) yes no)
@@ -10545,12 +11544,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (LessEqual cc)) yes no)
@@ -10569,12 +11564,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64LE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (GreaterThan cc)) yes no)
@@ -10593,12 +11584,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (GreaterEqual cc)) yes no)
@@ -10617,12 +11604,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64GE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (FLessThan cc)) yes no)
@@ -10641,12 +11624,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FLT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (FLessEqual cc)) yes no)
@@ -10665,12 +11644,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FLE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (FGreaterThan cc)) yes no)
@@ -10689,12 +11664,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FGT
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (FGreaterEqual cc)) yes no)
@@ -10713,12 +11684,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cc := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64FGE
 			b.SetControl(cc)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPconst [0] (ANDconst [c] x)) yes no)
@@ -10738,15 +11705,11 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			}
 			c := v_0.AuxInt
 			x := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
-			v0 := b.NewValue0(v.Line, OpPPC64ANDCCconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
 			v0.AuxInt = c
 			v0.AddArg(x)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (ANDconst [c] x)) yes no)
@@ -10766,15 +11729,11 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			}
 			c := v_0.AuxInt
 			x := v_0.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
-			v0 := b.NewValue0(v.Line, OpPPC64ANDCCconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
 			v0.AuxInt = c
 			v0.AddArg(x)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagEQ) yes no)
@@ -10785,13 +11744,9 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (NE (FlagLT) yes no)
@@ -10802,12 +11757,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagGT) yes no)
@@ -10818,12 +11769,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 			if v.Op != OpPPC64FlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (InvertFlags cmp) yes no)
@@ -10835,12 +11782,8 @@ func rewriteBlockPPC64(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockPPC64NE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go
index af8fd1d..2254674 100644
--- a/src/cmd/compile/internal/ssa/rewriteS390X.go
+++ b/src/cmd/compile/internal/ssa/rewriteS390X.go
@@ -1,725 +1,733 @@
-// autogenerated from gen/S390X.rules: do not edit!
+// Code generated from gen/S390X.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValueS390X(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValueS390X(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
-		return rewriteValueS390X_OpAdd16(v, config)
+		return rewriteValueS390X_OpAdd16_0(v)
 	case OpAdd32:
-		return rewriteValueS390X_OpAdd32(v, config)
+		return rewriteValueS390X_OpAdd32_0(v)
 	case OpAdd32F:
-		return rewriteValueS390X_OpAdd32F(v, config)
+		return rewriteValueS390X_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValueS390X_OpAdd64(v, config)
+		return rewriteValueS390X_OpAdd64_0(v)
 	case OpAdd64F:
-		return rewriteValueS390X_OpAdd64F(v, config)
+		return rewriteValueS390X_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValueS390X_OpAdd8(v, config)
+		return rewriteValueS390X_OpAdd8_0(v)
 	case OpAddPtr:
-		return rewriteValueS390X_OpAddPtr(v, config)
+		return rewriteValueS390X_OpAddPtr_0(v)
 	case OpAddr:
-		return rewriteValueS390X_OpAddr(v, config)
+		return rewriteValueS390X_OpAddr_0(v)
 	case OpAnd16:
-		return rewriteValueS390X_OpAnd16(v, config)
+		return rewriteValueS390X_OpAnd16_0(v)
 	case OpAnd32:
-		return rewriteValueS390X_OpAnd32(v, config)
+		return rewriteValueS390X_OpAnd32_0(v)
 	case OpAnd64:
-		return rewriteValueS390X_OpAnd64(v, config)
+		return rewriteValueS390X_OpAnd64_0(v)
 	case OpAnd8:
-		return rewriteValueS390X_OpAnd8(v, config)
+		return rewriteValueS390X_OpAnd8_0(v)
 	case OpAndB:
-		return rewriteValueS390X_OpAndB(v, config)
+		return rewriteValueS390X_OpAndB_0(v)
 	case OpAtomicAdd32:
-		return rewriteValueS390X_OpAtomicAdd32(v, config)
+		return rewriteValueS390X_OpAtomicAdd32_0(v)
 	case OpAtomicAdd64:
-		return rewriteValueS390X_OpAtomicAdd64(v, config)
+		return rewriteValueS390X_OpAtomicAdd64_0(v)
 	case OpAtomicCompareAndSwap32:
-		return rewriteValueS390X_OpAtomicCompareAndSwap32(v, config)
+		return rewriteValueS390X_OpAtomicCompareAndSwap32_0(v)
 	case OpAtomicCompareAndSwap64:
-		return rewriteValueS390X_OpAtomicCompareAndSwap64(v, config)
+		return rewriteValueS390X_OpAtomicCompareAndSwap64_0(v)
 	case OpAtomicExchange32:
-		return rewriteValueS390X_OpAtomicExchange32(v, config)
+		return rewriteValueS390X_OpAtomicExchange32_0(v)
 	case OpAtomicExchange64:
-		return rewriteValueS390X_OpAtomicExchange64(v, config)
+		return rewriteValueS390X_OpAtomicExchange64_0(v)
 	case OpAtomicLoad32:
-		return rewriteValueS390X_OpAtomicLoad32(v, config)
+		return rewriteValueS390X_OpAtomicLoad32_0(v)
 	case OpAtomicLoad64:
-		return rewriteValueS390X_OpAtomicLoad64(v, config)
+		return rewriteValueS390X_OpAtomicLoad64_0(v)
 	case OpAtomicLoadPtr:
-		return rewriteValueS390X_OpAtomicLoadPtr(v, config)
+		return rewriteValueS390X_OpAtomicLoadPtr_0(v)
 	case OpAtomicStore32:
-		return rewriteValueS390X_OpAtomicStore32(v, config)
+		return rewriteValueS390X_OpAtomicStore32_0(v)
 	case OpAtomicStore64:
-		return rewriteValueS390X_OpAtomicStore64(v, config)
+		return rewriteValueS390X_OpAtomicStore64_0(v)
 	case OpAtomicStorePtrNoWB:
-		return rewriteValueS390X_OpAtomicStorePtrNoWB(v, config)
+		return rewriteValueS390X_OpAtomicStorePtrNoWB_0(v)
 	case OpAvg64u:
-		return rewriteValueS390X_OpAvg64u(v, config)
+		return rewriteValueS390X_OpAvg64u_0(v)
+	case OpBitLen64:
+		return rewriteValueS390X_OpBitLen64_0(v)
 	case OpBswap32:
-		return rewriteValueS390X_OpBswap32(v, config)
+		return rewriteValueS390X_OpBswap32_0(v)
 	case OpBswap64:
-		return rewriteValueS390X_OpBswap64(v, config)
+		return rewriteValueS390X_OpBswap64_0(v)
 	case OpClosureCall:
-		return rewriteValueS390X_OpClosureCall(v, config)
+		return rewriteValueS390X_OpClosureCall_0(v)
 	case OpCom16:
-		return rewriteValueS390X_OpCom16(v, config)
+		return rewriteValueS390X_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValueS390X_OpCom32(v, config)
+		return rewriteValueS390X_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValueS390X_OpCom64(v, config)
+		return rewriteValueS390X_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValueS390X_OpCom8(v, config)
+		return rewriteValueS390X_OpCom8_0(v)
 	case OpConst16:
-		return rewriteValueS390X_OpConst16(v, config)
+		return rewriteValueS390X_OpConst16_0(v)
 	case OpConst32:
-		return rewriteValueS390X_OpConst32(v, config)
+		return rewriteValueS390X_OpConst32_0(v)
 	case OpConst32F:
-		return rewriteValueS390X_OpConst32F(v, config)
+		return rewriteValueS390X_OpConst32F_0(v)
 	case OpConst64:
-		return rewriteValueS390X_OpConst64(v, config)
+		return rewriteValueS390X_OpConst64_0(v)
 	case OpConst64F:
-		return rewriteValueS390X_OpConst64F(v, config)
+		return rewriteValueS390X_OpConst64F_0(v)
 	case OpConst8:
-		return rewriteValueS390X_OpConst8(v, config)
+		return rewriteValueS390X_OpConst8_0(v)
 	case OpConstBool:
-		return rewriteValueS390X_OpConstBool(v, config)
+		return rewriteValueS390X_OpConstBool_0(v)
 	case OpConstNil:
-		return rewriteValueS390X_OpConstNil(v, config)
+		return rewriteValueS390X_OpConstNil_0(v)
 	case OpConvert:
-		return rewriteValueS390X_OpConvert(v, config)
+		return rewriteValueS390X_OpConvert_0(v)
 	case OpCtz32:
-		return rewriteValueS390X_OpCtz32(v, config)
+		return rewriteValueS390X_OpCtz32_0(v)
 	case OpCtz64:
-		return rewriteValueS390X_OpCtz64(v, config)
+		return rewriteValueS390X_OpCtz64_0(v)
 	case OpCvt32Fto32:
-		return rewriteValueS390X_OpCvt32Fto32(v, config)
+		return rewriteValueS390X_OpCvt32Fto32_0(v)
 	case OpCvt32Fto64:
-		return rewriteValueS390X_OpCvt32Fto64(v, config)
+		return rewriteValueS390X_OpCvt32Fto64_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValueS390X_OpCvt32Fto64F(v, config)
+		return rewriteValueS390X_OpCvt32Fto64F_0(v)
 	case OpCvt32to32F:
-		return rewriteValueS390X_OpCvt32to32F(v, config)
+		return rewriteValueS390X_OpCvt32to32F_0(v)
 	case OpCvt32to64F:
-		return rewriteValueS390X_OpCvt32to64F(v, config)
+		return rewriteValueS390X_OpCvt32to64F_0(v)
 	case OpCvt64Fto32:
-		return rewriteValueS390X_OpCvt64Fto32(v, config)
+		return rewriteValueS390X_OpCvt64Fto32_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValueS390X_OpCvt64Fto32F(v, config)
+		return rewriteValueS390X_OpCvt64Fto32F_0(v)
 	case OpCvt64Fto64:
-		return rewriteValueS390X_OpCvt64Fto64(v, config)
+		return rewriteValueS390X_OpCvt64Fto64_0(v)
 	case OpCvt64to32F:
-		return rewriteValueS390X_OpCvt64to32F(v, config)
+		return rewriteValueS390X_OpCvt64to32F_0(v)
 	case OpCvt64to64F:
-		return rewriteValueS390X_OpCvt64to64F(v, config)
-	case OpDeferCall:
-		return rewriteValueS390X_OpDeferCall(v, config)
+		return rewriteValueS390X_OpCvt64to64F_0(v)
 	case OpDiv16:
-		return rewriteValueS390X_OpDiv16(v, config)
+		return rewriteValueS390X_OpDiv16_0(v)
 	case OpDiv16u:
-		return rewriteValueS390X_OpDiv16u(v, config)
+		return rewriteValueS390X_OpDiv16u_0(v)
 	case OpDiv32:
-		return rewriteValueS390X_OpDiv32(v, config)
+		return rewriteValueS390X_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValueS390X_OpDiv32F(v, config)
+		return rewriteValueS390X_OpDiv32F_0(v)
 	case OpDiv32u:
-		return rewriteValueS390X_OpDiv32u(v, config)
+		return rewriteValueS390X_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValueS390X_OpDiv64(v, config)
+		return rewriteValueS390X_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValueS390X_OpDiv64F(v, config)
+		return rewriteValueS390X_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValueS390X_OpDiv64u(v, config)
+		return rewriteValueS390X_OpDiv64u_0(v)
 	case OpDiv8:
-		return rewriteValueS390X_OpDiv8(v, config)
+		return rewriteValueS390X_OpDiv8_0(v)
 	case OpDiv8u:
-		return rewriteValueS390X_OpDiv8u(v, config)
+		return rewriteValueS390X_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValueS390X_OpEq16(v, config)
+		return rewriteValueS390X_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValueS390X_OpEq32(v, config)
+		return rewriteValueS390X_OpEq32_0(v)
 	case OpEq32F:
-		return rewriteValueS390X_OpEq32F(v, config)
+		return rewriteValueS390X_OpEq32F_0(v)
 	case OpEq64:
-		return rewriteValueS390X_OpEq64(v, config)
+		return rewriteValueS390X_OpEq64_0(v)
 	case OpEq64F:
-		return rewriteValueS390X_OpEq64F(v, config)
+		return rewriteValueS390X_OpEq64F_0(v)
 	case OpEq8:
-		return rewriteValueS390X_OpEq8(v, config)
+		return rewriteValueS390X_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValueS390X_OpEqB(v, config)
+		return rewriteValueS390X_OpEqB_0(v)
 	case OpEqPtr:
-		return rewriteValueS390X_OpEqPtr(v, config)
+		return rewriteValueS390X_OpEqPtr_0(v)
 	case OpGeq16:
-		return rewriteValueS390X_OpGeq16(v, config)
+		return rewriteValueS390X_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValueS390X_OpGeq16U(v, config)
+		return rewriteValueS390X_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValueS390X_OpGeq32(v, config)
+		return rewriteValueS390X_OpGeq32_0(v)
 	case OpGeq32F:
-		return rewriteValueS390X_OpGeq32F(v, config)
+		return rewriteValueS390X_OpGeq32F_0(v)
 	case OpGeq32U:
-		return rewriteValueS390X_OpGeq32U(v, config)
+		return rewriteValueS390X_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValueS390X_OpGeq64(v, config)
+		return rewriteValueS390X_OpGeq64_0(v)
 	case OpGeq64F:
-		return rewriteValueS390X_OpGeq64F(v, config)
+		return rewriteValueS390X_OpGeq64F_0(v)
 	case OpGeq64U:
-		return rewriteValueS390X_OpGeq64U(v, config)
+		return rewriteValueS390X_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValueS390X_OpGeq8(v, config)
+		return rewriteValueS390X_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValueS390X_OpGeq8U(v, config)
+		return rewriteValueS390X_OpGeq8U_0(v)
 	case OpGetClosurePtr:
-		return rewriteValueS390X_OpGetClosurePtr(v, config)
+		return rewriteValueS390X_OpGetClosurePtr_0(v)
 	case OpGetG:
-		return rewriteValueS390X_OpGetG(v, config)
-	case OpGoCall:
-		return rewriteValueS390X_OpGoCall(v, config)
+		return rewriteValueS390X_OpGetG_0(v)
 	case OpGreater16:
-		return rewriteValueS390X_OpGreater16(v, config)
+		return rewriteValueS390X_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValueS390X_OpGreater16U(v, config)
+		return rewriteValueS390X_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValueS390X_OpGreater32(v, config)
+		return rewriteValueS390X_OpGreater32_0(v)
 	case OpGreater32F:
-		return rewriteValueS390X_OpGreater32F(v, config)
+		return rewriteValueS390X_OpGreater32F_0(v)
 	case OpGreater32U:
-		return rewriteValueS390X_OpGreater32U(v, config)
+		return rewriteValueS390X_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValueS390X_OpGreater64(v, config)
+		return rewriteValueS390X_OpGreater64_0(v)
 	case OpGreater64F:
-		return rewriteValueS390X_OpGreater64F(v, config)
+		return rewriteValueS390X_OpGreater64F_0(v)
 	case OpGreater64U:
-		return rewriteValueS390X_OpGreater64U(v, config)
+		return rewriteValueS390X_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValueS390X_OpGreater8(v, config)
+		return rewriteValueS390X_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValueS390X_OpGreater8U(v, config)
-	case OpHmul16:
-		return rewriteValueS390X_OpHmul16(v, config)
-	case OpHmul16u:
-		return rewriteValueS390X_OpHmul16u(v, config)
+		return rewriteValueS390X_OpGreater8U_0(v)
 	case OpHmul32:
-		return rewriteValueS390X_OpHmul32(v, config)
+		return rewriteValueS390X_OpHmul32_0(v)
 	case OpHmul32u:
-		return rewriteValueS390X_OpHmul32u(v, config)
+		return rewriteValueS390X_OpHmul32u_0(v)
 	case OpHmul64:
-		return rewriteValueS390X_OpHmul64(v, config)
+		return rewriteValueS390X_OpHmul64_0(v)
 	case OpHmul64u:
-		return rewriteValueS390X_OpHmul64u(v, config)
-	case OpHmul8:
-		return rewriteValueS390X_OpHmul8(v, config)
-	case OpHmul8u:
-		return rewriteValueS390X_OpHmul8u(v, config)
+		return rewriteValueS390X_OpHmul64u_0(v)
 	case OpITab:
-		return rewriteValueS390X_OpITab(v, config)
+		return rewriteValueS390X_OpITab_0(v)
 	case OpInterCall:
-		return rewriteValueS390X_OpInterCall(v, config)
+		return rewriteValueS390X_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValueS390X_OpIsInBounds(v, config)
+		return rewriteValueS390X_OpIsInBounds_0(v)
 	case OpIsNonNil:
-		return rewriteValueS390X_OpIsNonNil(v, config)
+		return rewriteValueS390X_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValueS390X_OpIsSliceInBounds(v, config)
+		return rewriteValueS390X_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValueS390X_OpLeq16(v, config)
+		return rewriteValueS390X_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValueS390X_OpLeq16U(v, config)
+		return rewriteValueS390X_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValueS390X_OpLeq32(v, config)
+		return rewriteValueS390X_OpLeq32_0(v)
 	case OpLeq32F:
-		return rewriteValueS390X_OpLeq32F(v, config)
+		return rewriteValueS390X_OpLeq32F_0(v)
 	case OpLeq32U:
-		return rewriteValueS390X_OpLeq32U(v, config)
+		return rewriteValueS390X_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValueS390X_OpLeq64(v, config)
+		return rewriteValueS390X_OpLeq64_0(v)
 	case OpLeq64F:
-		return rewriteValueS390X_OpLeq64F(v, config)
+		return rewriteValueS390X_OpLeq64F_0(v)
 	case OpLeq64U:
-		return rewriteValueS390X_OpLeq64U(v, config)
+		return rewriteValueS390X_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValueS390X_OpLeq8(v, config)
+		return rewriteValueS390X_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValueS390X_OpLeq8U(v, config)
+		return rewriteValueS390X_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValueS390X_OpLess16(v, config)
+		return rewriteValueS390X_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValueS390X_OpLess16U(v, config)
+		return rewriteValueS390X_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValueS390X_OpLess32(v, config)
+		return rewriteValueS390X_OpLess32_0(v)
 	case OpLess32F:
-		return rewriteValueS390X_OpLess32F(v, config)
+		return rewriteValueS390X_OpLess32F_0(v)
 	case OpLess32U:
-		return rewriteValueS390X_OpLess32U(v, config)
+		return rewriteValueS390X_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValueS390X_OpLess64(v, config)
+		return rewriteValueS390X_OpLess64_0(v)
 	case OpLess64F:
-		return rewriteValueS390X_OpLess64F(v, config)
+		return rewriteValueS390X_OpLess64F_0(v)
 	case OpLess64U:
-		return rewriteValueS390X_OpLess64U(v, config)
+		return rewriteValueS390X_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValueS390X_OpLess8(v, config)
+		return rewriteValueS390X_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValueS390X_OpLess8U(v, config)
+		return rewriteValueS390X_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValueS390X_OpLoad(v, config)
-	case OpLrot32:
-		return rewriteValueS390X_OpLrot32(v, config)
-	case OpLrot64:
-		return rewriteValueS390X_OpLrot64(v, config)
+		return rewriteValueS390X_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValueS390X_OpLsh16x16(v, config)
+		return rewriteValueS390X_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValueS390X_OpLsh16x32(v, config)
+		return rewriteValueS390X_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValueS390X_OpLsh16x64(v, config)
+		return rewriteValueS390X_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValueS390X_OpLsh16x8(v, config)
+		return rewriteValueS390X_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValueS390X_OpLsh32x16(v, config)
+		return rewriteValueS390X_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValueS390X_OpLsh32x32(v, config)
+		return rewriteValueS390X_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValueS390X_OpLsh32x64(v, config)
+		return rewriteValueS390X_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValueS390X_OpLsh32x8(v, config)
+		return rewriteValueS390X_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValueS390X_OpLsh64x16(v, config)
+		return rewriteValueS390X_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValueS390X_OpLsh64x32(v, config)
+		return rewriteValueS390X_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValueS390X_OpLsh64x64(v, config)
+		return rewriteValueS390X_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValueS390X_OpLsh64x8(v, config)
+		return rewriteValueS390X_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValueS390X_OpLsh8x16(v, config)
+		return rewriteValueS390X_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValueS390X_OpLsh8x32(v, config)
+		return rewriteValueS390X_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValueS390X_OpLsh8x64(v, config)
+		return rewriteValueS390X_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValueS390X_OpLsh8x8(v, config)
+		return rewriteValueS390X_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValueS390X_OpMod16(v, config)
+		return rewriteValueS390X_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValueS390X_OpMod16u(v, config)
+		return rewriteValueS390X_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValueS390X_OpMod32(v, config)
+		return rewriteValueS390X_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValueS390X_OpMod32u(v, config)
+		return rewriteValueS390X_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValueS390X_OpMod64(v, config)
+		return rewriteValueS390X_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValueS390X_OpMod64u(v, config)
+		return rewriteValueS390X_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValueS390X_OpMod8(v, config)
+		return rewriteValueS390X_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValueS390X_OpMod8u(v, config)
+		return rewriteValueS390X_OpMod8u_0(v)
 	case OpMove:
-		return rewriteValueS390X_OpMove(v, config)
+		return rewriteValueS390X_OpMove_0(v) || rewriteValueS390X_OpMove_10(v)
 	case OpMul16:
-		return rewriteValueS390X_OpMul16(v, config)
+		return rewriteValueS390X_OpMul16_0(v)
 	case OpMul32:
-		return rewriteValueS390X_OpMul32(v, config)
+		return rewriteValueS390X_OpMul32_0(v)
 	case OpMul32F:
-		return rewriteValueS390X_OpMul32F(v, config)
+		return rewriteValueS390X_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValueS390X_OpMul64(v, config)
+		return rewriteValueS390X_OpMul64_0(v)
 	case OpMul64F:
-		return rewriteValueS390X_OpMul64F(v, config)
+		return rewriteValueS390X_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValueS390X_OpMul8(v, config)
+		return rewriteValueS390X_OpMul8_0(v)
 	case OpNeg16:
-		return rewriteValueS390X_OpNeg16(v, config)
+		return rewriteValueS390X_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValueS390X_OpNeg32(v, config)
+		return rewriteValueS390X_OpNeg32_0(v)
 	case OpNeg32F:
-		return rewriteValueS390X_OpNeg32F(v, config)
+		return rewriteValueS390X_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValueS390X_OpNeg64(v, config)
+		return rewriteValueS390X_OpNeg64_0(v)
 	case OpNeg64F:
-		return rewriteValueS390X_OpNeg64F(v, config)
+		return rewriteValueS390X_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValueS390X_OpNeg8(v, config)
+		return rewriteValueS390X_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValueS390X_OpNeq16(v, config)
+		return rewriteValueS390X_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValueS390X_OpNeq32(v, config)
+		return rewriteValueS390X_OpNeq32_0(v)
 	case OpNeq32F:
-		return rewriteValueS390X_OpNeq32F(v, config)
+		return rewriteValueS390X_OpNeq32F_0(v)
 	case OpNeq64:
-		return rewriteValueS390X_OpNeq64(v, config)
+		return rewriteValueS390X_OpNeq64_0(v)
 	case OpNeq64F:
-		return rewriteValueS390X_OpNeq64F(v, config)
+		return rewriteValueS390X_OpNeq64F_0(v)
 	case OpNeq8:
-		return rewriteValueS390X_OpNeq8(v, config)
+		return rewriteValueS390X_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValueS390X_OpNeqB(v, config)
+		return rewriteValueS390X_OpNeqB_0(v)
 	case OpNeqPtr:
-		return rewriteValueS390X_OpNeqPtr(v, config)
+		return rewriteValueS390X_OpNeqPtr_0(v)
 	case OpNilCheck:
-		return rewriteValueS390X_OpNilCheck(v, config)
+		return rewriteValueS390X_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValueS390X_OpNot(v, config)
+		return rewriteValueS390X_OpNot_0(v)
 	case OpOffPtr:
-		return rewriteValueS390X_OpOffPtr(v, config)
+		return rewriteValueS390X_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValueS390X_OpOr16(v, config)
+		return rewriteValueS390X_OpOr16_0(v)
 	case OpOr32:
-		return rewriteValueS390X_OpOr32(v, config)
+		return rewriteValueS390X_OpOr32_0(v)
 	case OpOr64:
-		return rewriteValueS390X_OpOr64(v, config)
+		return rewriteValueS390X_OpOr64_0(v)
 	case OpOr8:
-		return rewriteValueS390X_OpOr8(v, config)
+		return rewriteValueS390X_OpOr8_0(v)
 	case OpOrB:
-		return rewriteValueS390X_OpOrB(v, config)
+		return rewriteValueS390X_OpOrB_0(v)
+	case OpRound32F:
+		return rewriteValueS390X_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValueS390X_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValueS390X_OpRsh16Ux16(v, config)
+		return rewriteValueS390X_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValueS390X_OpRsh16Ux32(v, config)
+		return rewriteValueS390X_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValueS390X_OpRsh16Ux64(v, config)
+		return rewriteValueS390X_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValueS390X_OpRsh16Ux8(v, config)
+		return rewriteValueS390X_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValueS390X_OpRsh16x16(v, config)
+		return rewriteValueS390X_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValueS390X_OpRsh16x32(v, config)
+		return rewriteValueS390X_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValueS390X_OpRsh16x64(v, config)
+		return rewriteValueS390X_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValueS390X_OpRsh16x8(v, config)
+		return rewriteValueS390X_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValueS390X_OpRsh32Ux16(v, config)
+		return rewriteValueS390X_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValueS390X_OpRsh32Ux32(v, config)
+		return rewriteValueS390X_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValueS390X_OpRsh32Ux64(v, config)
+		return rewriteValueS390X_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValueS390X_OpRsh32Ux8(v, config)
+		return rewriteValueS390X_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValueS390X_OpRsh32x16(v, config)
+		return rewriteValueS390X_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValueS390X_OpRsh32x32(v, config)
+		return rewriteValueS390X_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValueS390X_OpRsh32x64(v, config)
+		return rewriteValueS390X_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValueS390X_OpRsh32x8(v, config)
+		return rewriteValueS390X_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValueS390X_OpRsh64Ux16(v, config)
+		return rewriteValueS390X_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValueS390X_OpRsh64Ux32(v, config)
+		return rewriteValueS390X_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValueS390X_OpRsh64Ux64(v, config)
+		return rewriteValueS390X_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValueS390X_OpRsh64Ux8(v, config)
+		return rewriteValueS390X_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValueS390X_OpRsh64x16(v, config)
+		return rewriteValueS390X_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValueS390X_OpRsh64x32(v, config)
+		return rewriteValueS390X_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValueS390X_OpRsh64x64(v, config)
+		return rewriteValueS390X_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValueS390X_OpRsh64x8(v, config)
+		return rewriteValueS390X_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValueS390X_OpRsh8Ux16(v, config)
+		return rewriteValueS390X_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValueS390X_OpRsh8Ux32(v, config)
+		return rewriteValueS390X_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValueS390X_OpRsh8Ux64(v, config)
+		return rewriteValueS390X_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValueS390X_OpRsh8Ux8(v, config)
+		return rewriteValueS390X_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValueS390X_OpRsh8x16(v, config)
+		return rewriteValueS390X_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValueS390X_OpRsh8x32(v, config)
+		return rewriteValueS390X_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValueS390X_OpRsh8x64(v, config)
+		return rewriteValueS390X_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValueS390X_OpRsh8x8(v, config)
+		return rewriteValueS390X_OpRsh8x8_0(v)
 	case OpS390XADD:
-		return rewriteValueS390X_OpS390XADD(v, config)
+		return rewriteValueS390X_OpS390XADD_0(v) || rewriteValueS390X_OpS390XADD_10(v)
 	case OpS390XADDW:
-		return rewriteValueS390X_OpS390XADDW(v, config)
+		return rewriteValueS390X_OpS390XADDW_0(v) || rewriteValueS390X_OpS390XADDW_10(v)
 	case OpS390XADDWconst:
-		return rewriteValueS390X_OpS390XADDWconst(v, config)
+		return rewriteValueS390X_OpS390XADDWconst_0(v)
 	case OpS390XADDconst:
-		return rewriteValueS390X_OpS390XADDconst(v, config)
+		return rewriteValueS390X_OpS390XADDconst_0(v)
 	case OpS390XAND:
-		return rewriteValueS390X_OpS390XAND(v, config)
+		return rewriteValueS390X_OpS390XAND_0(v) || rewriteValueS390X_OpS390XAND_10(v)
 	case OpS390XANDW:
-		return rewriteValueS390X_OpS390XANDW(v, config)
+		return rewriteValueS390X_OpS390XANDW_0(v) || rewriteValueS390X_OpS390XANDW_10(v)
 	case OpS390XANDWconst:
-		return rewriteValueS390X_OpS390XANDWconst(v, config)
+		return rewriteValueS390X_OpS390XANDWconst_0(v)
 	case OpS390XANDconst:
-		return rewriteValueS390X_OpS390XANDconst(v, config)
+		return rewriteValueS390X_OpS390XANDconst_0(v)
 	case OpS390XCMP:
-		return rewriteValueS390X_OpS390XCMP(v, config)
+		return rewriteValueS390X_OpS390XCMP_0(v)
 	case OpS390XCMPU:
-		return rewriteValueS390X_OpS390XCMPU(v, config)
+		return rewriteValueS390X_OpS390XCMPU_0(v)
 	case OpS390XCMPUconst:
-		return rewriteValueS390X_OpS390XCMPUconst(v, config)
+		return rewriteValueS390X_OpS390XCMPUconst_0(v)
 	case OpS390XCMPW:
-		return rewriteValueS390X_OpS390XCMPW(v, config)
+		return rewriteValueS390X_OpS390XCMPW_0(v)
 	case OpS390XCMPWU:
-		return rewriteValueS390X_OpS390XCMPWU(v, config)
+		return rewriteValueS390X_OpS390XCMPWU_0(v)
 	case OpS390XCMPWUconst:
-		return rewriteValueS390X_OpS390XCMPWUconst(v, config)
+		return rewriteValueS390X_OpS390XCMPWUconst_0(v)
 	case OpS390XCMPWconst:
-		return rewriteValueS390X_OpS390XCMPWconst(v, config)
+		return rewriteValueS390X_OpS390XCMPWconst_0(v)
 	case OpS390XCMPconst:
-		return rewriteValueS390X_OpS390XCMPconst(v, config)
+		return rewriteValueS390X_OpS390XCMPconst_0(v)
+	case OpS390XFADD:
+		return rewriteValueS390X_OpS390XFADD_0(v)
+	case OpS390XFADDS:
+		return rewriteValueS390X_OpS390XFADDS_0(v)
 	case OpS390XFMOVDload:
-		return rewriteValueS390X_OpS390XFMOVDload(v, config)
+		return rewriteValueS390X_OpS390XFMOVDload_0(v)
 	case OpS390XFMOVDloadidx:
-		return rewriteValueS390X_OpS390XFMOVDloadidx(v, config)
+		return rewriteValueS390X_OpS390XFMOVDloadidx_0(v)
 	case OpS390XFMOVDstore:
-		return rewriteValueS390X_OpS390XFMOVDstore(v, config)
+		return rewriteValueS390X_OpS390XFMOVDstore_0(v)
 	case OpS390XFMOVDstoreidx:
-		return rewriteValueS390X_OpS390XFMOVDstoreidx(v, config)
+		return rewriteValueS390X_OpS390XFMOVDstoreidx_0(v)
 	case OpS390XFMOVSload:
-		return rewriteValueS390X_OpS390XFMOVSload(v, config)
+		return rewriteValueS390X_OpS390XFMOVSload_0(v)
 	case OpS390XFMOVSloadidx:
-		return rewriteValueS390X_OpS390XFMOVSloadidx(v, config)
+		return rewriteValueS390X_OpS390XFMOVSloadidx_0(v)
 	case OpS390XFMOVSstore:
-		return rewriteValueS390X_OpS390XFMOVSstore(v, config)
+		return rewriteValueS390X_OpS390XFMOVSstore_0(v)
 	case OpS390XFMOVSstoreidx:
-		return rewriteValueS390X_OpS390XFMOVSstoreidx(v, config)
+		return rewriteValueS390X_OpS390XFMOVSstoreidx_0(v)
+	case OpS390XFSUB:
+		return rewriteValueS390X_OpS390XFSUB_0(v)
+	case OpS390XFSUBS:
+		return rewriteValueS390X_OpS390XFSUBS_0(v)
+	case OpS390XLoweredRound32F:
+		return rewriteValueS390X_OpS390XLoweredRound32F_0(v)
+	case OpS390XLoweredRound64F:
+		return rewriteValueS390X_OpS390XLoweredRound64F_0(v)
 	case OpS390XMOVBZload:
-		return rewriteValueS390X_OpS390XMOVBZload(v, config)
+		return rewriteValueS390X_OpS390XMOVBZload_0(v)
 	case OpS390XMOVBZloadidx:
-		return rewriteValueS390X_OpS390XMOVBZloadidx(v, config)
+		return rewriteValueS390X_OpS390XMOVBZloadidx_0(v)
 	case OpS390XMOVBZreg:
-		return rewriteValueS390X_OpS390XMOVBZreg(v, config)
+		return rewriteValueS390X_OpS390XMOVBZreg_0(v) || rewriteValueS390X_OpS390XMOVBZreg_10(v)
 	case OpS390XMOVBload:
-		return rewriteValueS390X_OpS390XMOVBload(v, config)
+		return rewriteValueS390X_OpS390XMOVBload_0(v)
 	case OpS390XMOVBreg:
-		return rewriteValueS390X_OpS390XMOVBreg(v, config)
+		return rewriteValueS390X_OpS390XMOVBreg_0(v)
 	case OpS390XMOVBstore:
-		return rewriteValueS390X_OpS390XMOVBstore(v, config)
+		return rewriteValueS390X_OpS390XMOVBstore_0(v) || rewriteValueS390X_OpS390XMOVBstore_10(v)
 	case OpS390XMOVBstoreconst:
-		return rewriteValueS390X_OpS390XMOVBstoreconst(v, config)
+		return rewriteValueS390X_OpS390XMOVBstoreconst_0(v)
 	case OpS390XMOVBstoreidx:
-		return rewriteValueS390X_OpS390XMOVBstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVBstoreidx_0(v) || rewriteValueS390X_OpS390XMOVBstoreidx_10(v) || rewriteValueS390X_OpS390XMOVBstoreidx_20(v) || rewriteValueS390X_OpS390XMOVBstoreidx_30(v)
 	case OpS390XMOVDEQ:
-		return rewriteValueS390X_OpS390XMOVDEQ(v, config)
+		return rewriteValueS390X_OpS390XMOVDEQ_0(v)
 	case OpS390XMOVDGE:
-		return rewriteValueS390X_OpS390XMOVDGE(v, config)
+		return rewriteValueS390X_OpS390XMOVDGE_0(v)
 	case OpS390XMOVDGT:
-		return rewriteValueS390X_OpS390XMOVDGT(v, config)
+		return rewriteValueS390X_OpS390XMOVDGT_0(v)
 	case OpS390XMOVDLE:
-		return rewriteValueS390X_OpS390XMOVDLE(v, config)
+		return rewriteValueS390X_OpS390XMOVDLE_0(v)
 	case OpS390XMOVDLT:
-		return rewriteValueS390X_OpS390XMOVDLT(v, config)
+		return rewriteValueS390X_OpS390XMOVDLT_0(v)
 	case OpS390XMOVDNE:
-		return rewriteValueS390X_OpS390XMOVDNE(v, config)
+		return rewriteValueS390X_OpS390XMOVDNE_0(v)
 	case OpS390XMOVDaddridx:
-		return rewriteValueS390X_OpS390XMOVDaddridx(v, config)
+		return rewriteValueS390X_OpS390XMOVDaddridx_0(v)
 	case OpS390XMOVDload:
-		return rewriteValueS390X_OpS390XMOVDload(v, config)
+		return rewriteValueS390X_OpS390XMOVDload_0(v)
 	case OpS390XMOVDloadidx:
-		return rewriteValueS390X_OpS390XMOVDloadidx(v, config)
+		return rewriteValueS390X_OpS390XMOVDloadidx_0(v)
 	case OpS390XMOVDnop:
-		return rewriteValueS390X_OpS390XMOVDnop(v, config)
+		return rewriteValueS390X_OpS390XMOVDnop_0(v) || rewriteValueS390X_OpS390XMOVDnop_10(v)
 	case OpS390XMOVDreg:
-		return rewriteValueS390X_OpS390XMOVDreg(v, config)
+		return rewriteValueS390X_OpS390XMOVDreg_0(v) || rewriteValueS390X_OpS390XMOVDreg_10(v)
 	case OpS390XMOVDstore:
-		return rewriteValueS390X_OpS390XMOVDstore(v, config)
+		return rewriteValueS390X_OpS390XMOVDstore_0(v)
 	case OpS390XMOVDstoreconst:
-		return rewriteValueS390X_OpS390XMOVDstoreconst(v, config)
+		return rewriteValueS390X_OpS390XMOVDstoreconst_0(v)
 	case OpS390XMOVDstoreidx:
-		return rewriteValueS390X_OpS390XMOVDstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVDstoreidx_0(v)
 	case OpS390XMOVHBRstore:
-		return rewriteValueS390X_OpS390XMOVHBRstore(v, config)
+		return rewriteValueS390X_OpS390XMOVHBRstore_0(v)
 	case OpS390XMOVHBRstoreidx:
-		return rewriteValueS390X_OpS390XMOVHBRstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVHBRstoreidx_0(v) || rewriteValueS390X_OpS390XMOVHBRstoreidx_10(v)
 	case OpS390XMOVHZload:
-		return rewriteValueS390X_OpS390XMOVHZload(v, config)
+		return rewriteValueS390X_OpS390XMOVHZload_0(v)
 	case OpS390XMOVHZloadidx:
-		return rewriteValueS390X_OpS390XMOVHZloadidx(v, config)
+		return rewriteValueS390X_OpS390XMOVHZloadidx_0(v)
 	case OpS390XMOVHZreg:
-		return rewriteValueS390X_OpS390XMOVHZreg(v, config)
+		return rewriteValueS390X_OpS390XMOVHZreg_0(v)
 	case OpS390XMOVHload:
-		return rewriteValueS390X_OpS390XMOVHload(v, config)
+		return rewriteValueS390X_OpS390XMOVHload_0(v)
 	case OpS390XMOVHreg:
-		return rewriteValueS390X_OpS390XMOVHreg(v, config)
+		return rewriteValueS390X_OpS390XMOVHreg_0(v)
 	case OpS390XMOVHstore:
-		return rewriteValueS390X_OpS390XMOVHstore(v, config)
+		return rewriteValueS390X_OpS390XMOVHstore_0(v) || rewriteValueS390X_OpS390XMOVHstore_10(v)
 	case OpS390XMOVHstoreconst:
-		return rewriteValueS390X_OpS390XMOVHstoreconst(v, config)
+		return rewriteValueS390X_OpS390XMOVHstoreconst_0(v)
 	case OpS390XMOVHstoreidx:
-		return rewriteValueS390X_OpS390XMOVHstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVHstoreidx_0(v) || rewriteValueS390X_OpS390XMOVHstoreidx_10(v)
 	case OpS390XMOVWBRstore:
-		return rewriteValueS390X_OpS390XMOVWBRstore(v, config)
+		return rewriteValueS390X_OpS390XMOVWBRstore_0(v)
 	case OpS390XMOVWBRstoreidx:
-		return rewriteValueS390X_OpS390XMOVWBRstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVWBRstoreidx_0(v)
 	case OpS390XMOVWZload:
-		return rewriteValueS390X_OpS390XMOVWZload(v, config)
+		return rewriteValueS390X_OpS390XMOVWZload_0(v)
 	case OpS390XMOVWZloadidx:
-		return rewriteValueS390X_OpS390XMOVWZloadidx(v, config)
+		return rewriteValueS390X_OpS390XMOVWZloadidx_0(v)
 	case OpS390XMOVWZreg:
-		return rewriteValueS390X_OpS390XMOVWZreg(v, config)
+		return rewriteValueS390X_OpS390XMOVWZreg_0(v)
 	case OpS390XMOVWload:
-		return rewriteValueS390X_OpS390XMOVWload(v, config)
+		return rewriteValueS390X_OpS390XMOVWload_0(v)
 	case OpS390XMOVWreg:
-		return rewriteValueS390X_OpS390XMOVWreg(v, config)
+		return rewriteValueS390X_OpS390XMOVWreg_0(v) || rewriteValueS390X_OpS390XMOVWreg_10(v)
 	case OpS390XMOVWstore:
-		return rewriteValueS390X_OpS390XMOVWstore(v, config)
+		return rewriteValueS390X_OpS390XMOVWstore_0(v) || rewriteValueS390X_OpS390XMOVWstore_10(v)
 	case OpS390XMOVWstoreconst:
-		return rewriteValueS390X_OpS390XMOVWstoreconst(v, config)
+		return rewriteValueS390X_OpS390XMOVWstoreconst_0(v)
 	case OpS390XMOVWstoreidx:
-		return rewriteValueS390X_OpS390XMOVWstoreidx(v, config)
+		return rewriteValueS390X_OpS390XMOVWstoreidx_0(v) || rewriteValueS390X_OpS390XMOVWstoreidx_10(v)
 	case OpS390XMULLD:
-		return rewriteValueS390X_OpS390XMULLD(v, config)
+		return rewriteValueS390X_OpS390XMULLD_0(v)
 	case OpS390XMULLDconst:
-		return rewriteValueS390X_OpS390XMULLDconst(v, config)
+		return rewriteValueS390X_OpS390XMULLDconst_0(v)
 	case OpS390XMULLW:
-		return rewriteValueS390X_OpS390XMULLW(v, config)
+		return rewriteValueS390X_OpS390XMULLW_0(v)
 	case OpS390XMULLWconst:
-		return rewriteValueS390X_OpS390XMULLWconst(v, config)
+		return rewriteValueS390X_OpS390XMULLWconst_0(v)
 	case OpS390XNEG:
-		return rewriteValueS390X_OpS390XNEG(v, config)
+		return rewriteValueS390X_OpS390XNEG_0(v)
 	case OpS390XNEGW:
-		return rewriteValueS390X_OpS390XNEGW(v, config)
+		return rewriteValueS390X_OpS390XNEGW_0(v)
 	case OpS390XNOT:
-		return rewriteValueS390X_OpS390XNOT(v, config)
+		return rewriteValueS390X_OpS390XNOT_0(v)
 	case OpS390XNOTW:
-		return rewriteValueS390X_OpS390XNOTW(v, config)
+		return rewriteValueS390X_OpS390XNOTW_0(v)
 	case OpS390XOR:
-		return rewriteValueS390X_OpS390XOR(v, config)
+		return rewriteValueS390X_OpS390XOR_0(v) || rewriteValueS390X_OpS390XOR_10(v) || rewriteValueS390X_OpS390XOR_20(v) || rewriteValueS390X_OpS390XOR_30(v) || rewriteValueS390X_OpS390XOR_40(v) || rewriteValueS390X_OpS390XOR_50(v) || rewriteValueS390X_OpS390XOR_60(v) || rewriteValueS390X_OpS390XOR_70(v) || rewriteValueS390X_OpS390XOR_80(v) || rewriteValueS390X_OpS390XOR_90(v) || rewriteValueS390X_OpS390XOR_100(v) || rewriteValueS390X_OpS390XOR_110(v) || rewriteValueS390X_OpS390XOR_120(v) ||  [...]
 	case OpS390XORW:
-		return rewriteValueS390X_OpS390XORW(v, config)
+		return rewriteValueS390X_OpS390XORW_0(v) || rewriteValueS390X_OpS390XORW_10(v) || rewriteValueS390X_OpS390XORW_20(v) || rewriteValueS390X_OpS390XORW_30(v) || rewriteValueS390X_OpS390XORW_40(v) || rewriteValueS390X_OpS390XORW_50(v) || rewriteValueS390X_OpS390XORW_60(v) || rewriteValueS390X_OpS390XORW_70(v) || rewriteValueS390X_OpS390XORW_80(v) || rewriteValueS390X_OpS390XORW_90(v)
 	case OpS390XORWconst:
-		return rewriteValueS390X_OpS390XORWconst(v, config)
+		return rewriteValueS390X_OpS390XORWconst_0(v)
 	case OpS390XORconst:
-		return rewriteValueS390X_OpS390XORconst(v, config)
+		return rewriteValueS390X_OpS390XORconst_0(v)
 	case OpS390XSLD:
-		return rewriteValueS390X_OpS390XSLD(v, config)
+		return rewriteValueS390X_OpS390XSLD_0(v)
 	case OpS390XSLW:
-		return rewriteValueS390X_OpS390XSLW(v, config)
+		return rewriteValueS390X_OpS390XSLW_0(v)
 	case OpS390XSRAD:
-		return rewriteValueS390X_OpS390XSRAD(v, config)
+		return rewriteValueS390X_OpS390XSRAD_0(v)
 	case OpS390XSRADconst:
-		return rewriteValueS390X_OpS390XSRADconst(v, config)
+		return rewriteValueS390X_OpS390XSRADconst_0(v)
 	case OpS390XSRAW:
-		return rewriteValueS390X_OpS390XSRAW(v, config)
+		return rewriteValueS390X_OpS390XSRAW_0(v)
 	case OpS390XSRAWconst:
-		return rewriteValueS390X_OpS390XSRAWconst(v, config)
+		return rewriteValueS390X_OpS390XSRAWconst_0(v)
 	case OpS390XSRD:
-		return rewriteValueS390X_OpS390XSRD(v, config)
+		return rewriteValueS390X_OpS390XSRD_0(v)
 	case OpS390XSRW:
-		return rewriteValueS390X_OpS390XSRW(v, config)
+		return rewriteValueS390X_OpS390XSRW_0(v)
 	case OpS390XSTM2:
-		return rewriteValueS390X_OpS390XSTM2(v, config)
+		return rewriteValueS390X_OpS390XSTM2_0(v)
 	case OpS390XSTMG2:
-		return rewriteValueS390X_OpS390XSTMG2(v, config)
+		return rewriteValueS390X_OpS390XSTMG2_0(v)
 	case OpS390XSUB:
-		return rewriteValueS390X_OpS390XSUB(v, config)
+		return rewriteValueS390X_OpS390XSUB_0(v)
 	case OpS390XSUBEWcarrymask:
-		return rewriteValueS390X_OpS390XSUBEWcarrymask(v, config)
+		return rewriteValueS390X_OpS390XSUBEWcarrymask_0(v)
 	case OpS390XSUBEcarrymask:
-		return rewriteValueS390X_OpS390XSUBEcarrymask(v, config)
+		return rewriteValueS390X_OpS390XSUBEcarrymask_0(v)
 	case OpS390XSUBW:
-		return rewriteValueS390X_OpS390XSUBW(v, config)
+		return rewriteValueS390X_OpS390XSUBW_0(v)
 	case OpS390XSUBWconst:
-		return rewriteValueS390X_OpS390XSUBWconst(v, config)
+		return rewriteValueS390X_OpS390XSUBWconst_0(v)
 	case OpS390XSUBconst:
-		return rewriteValueS390X_OpS390XSUBconst(v, config)
+		return rewriteValueS390X_OpS390XSUBconst_0(v)
 	case OpS390XXOR:
-		return rewriteValueS390X_OpS390XXOR(v, config)
+		return rewriteValueS390X_OpS390XXOR_0(v) || rewriteValueS390X_OpS390XXOR_10(v)
 	case OpS390XXORW:
-		return rewriteValueS390X_OpS390XXORW(v, config)
+		return rewriteValueS390X_OpS390XXORW_0(v) || rewriteValueS390X_OpS390XXORW_10(v)
 	case OpS390XXORWconst:
-		return rewriteValueS390X_OpS390XXORWconst(v, config)
+		return rewriteValueS390X_OpS390XXORWconst_0(v)
 	case OpS390XXORconst:
-		return rewriteValueS390X_OpS390XXORconst(v, config)
+		return rewriteValueS390X_OpS390XXORconst_0(v)
 	case OpSelect0:
-		return rewriteValueS390X_OpSelect0(v, config)
+		return rewriteValueS390X_OpSelect0_0(v)
 	case OpSelect1:
-		return rewriteValueS390X_OpSelect1(v, config)
+		return rewriteValueS390X_OpSelect1_0(v)
 	case OpSignExt16to32:
-		return rewriteValueS390X_OpSignExt16to32(v, config)
+		return rewriteValueS390X_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValueS390X_OpSignExt16to64(v, config)
+		return rewriteValueS390X_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValueS390X_OpSignExt32to64(v, config)
+		return rewriteValueS390X_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValueS390X_OpSignExt8to16(v, config)
+		return rewriteValueS390X_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValueS390X_OpSignExt8to32(v, config)
+		return rewriteValueS390X_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValueS390X_OpSignExt8to64(v, config)
+		return rewriteValueS390X_OpSignExt8to64_0(v)
 	case OpSlicemask:
-		return rewriteValueS390X_OpSlicemask(v, config)
+		return rewriteValueS390X_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValueS390X_OpSqrt(v, config)
+		return rewriteValueS390X_OpSqrt_0(v)
 	case OpStaticCall:
-		return rewriteValueS390X_OpStaticCall(v, config)
+		return rewriteValueS390X_OpStaticCall_0(v)
 	case OpStore:
-		return rewriteValueS390X_OpStore(v, config)
+		return rewriteValueS390X_OpStore_0(v)
 	case OpSub16:
-		return rewriteValueS390X_OpSub16(v, config)
+		return rewriteValueS390X_OpSub16_0(v)
 	case OpSub32:
-		return rewriteValueS390X_OpSub32(v, config)
+		return rewriteValueS390X_OpSub32_0(v)
 	case OpSub32F:
-		return rewriteValueS390X_OpSub32F(v, config)
+		return rewriteValueS390X_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValueS390X_OpSub64(v, config)
+		return rewriteValueS390X_OpSub64_0(v)
 	case OpSub64F:
-		return rewriteValueS390X_OpSub64F(v, config)
+		return rewriteValueS390X_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValueS390X_OpSub8(v, config)
+		return rewriteValueS390X_OpSub8_0(v)
 	case OpSubPtr:
-		return rewriteValueS390X_OpSubPtr(v, config)
+		return rewriteValueS390X_OpSubPtr_0(v)
 	case OpTrunc16to8:
-		return rewriteValueS390X_OpTrunc16to8(v, config)
+		return rewriteValueS390X_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValueS390X_OpTrunc32to16(v, config)
+		return rewriteValueS390X_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValueS390X_OpTrunc32to8(v, config)
+		return rewriteValueS390X_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValueS390X_OpTrunc64to16(v, config)
+		return rewriteValueS390X_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValueS390X_OpTrunc64to32(v, config)
+		return rewriteValueS390X_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValueS390X_OpTrunc64to8(v, config)
+		return rewriteValueS390X_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValueS390X_OpXor16(v, config)
+		return rewriteValueS390X_OpXor16_0(v)
 	case OpXor32:
-		return rewriteValueS390X_OpXor32(v, config)
+		return rewriteValueS390X_OpXor32_0(v)
 	case OpXor64:
-		return rewriteValueS390X_OpXor64(v, config)
+		return rewriteValueS390X_OpXor64_0(v)
 	case OpXor8:
-		return rewriteValueS390X_OpXor8(v, config)
+		return rewriteValueS390X_OpXor8_0(v)
 	case OpZero:
-		return rewriteValueS390X_OpZero(v, config)
+		return rewriteValueS390X_OpZero_0(v) || rewriteValueS390X_OpZero_10(v)
 	case OpZeroExt16to32:
-		return rewriteValueS390X_OpZeroExt16to32(v, config)
+		return rewriteValueS390X_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValueS390X_OpZeroExt16to64(v, config)
+		return rewriteValueS390X_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValueS390X_OpZeroExt32to64(v, config)
+		return rewriteValueS390X_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValueS390X_OpZeroExt8to16(v, config)
+		return rewriteValueS390X_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValueS390X_OpZeroExt8to32(v, config)
+		return rewriteValueS390X_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValueS390X_OpZeroExt8to64(v, config)
+		return rewriteValueS390X_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValueS390X_OpAdd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add16  x y)
+func rewriteValueS390X_OpAdd16_0(v *Value) bool {
+	// match: (Add16 x y)
 	// cond:
 	// result: (ADDW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADDW)
@@ -728,13 +736,12 @@ func rewriteValueS390X_OpAdd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAdd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add32  x y)
+func rewriteValueS390X_OpAdd32_0(v *Value) bool {
+	// match: (Add32 x y)
 	// cond:
 	// result: (ADDW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADDW)
@@ -743,13 +750,12 @@ func rewriteValueS390X_OpAdd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAdd32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAdd32F_0(v *Value) bool {
 	// match: (Add32F x y)
 	// cond:
 	// result: (FADDS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFADDS)
@@ -758,13 +764,12 @@ func rewriteValueS390X_OpAdd32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAdd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add64  x y)
+func rewriteValueS390X_OpAdd64_0(v *Value) bool {
+	// match: (Add64 x y)
 	// cond:
 	// result: (ADD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADD)
@@ -773,13 +778,12 @@ func rewriteValueS390X_OpAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAdd64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAdd64F_0(v *Value) bool {
 	// match: (Add64F x y)
 	// cond:
 	// result: (FADD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFADD)
@@ -788,13 +792,12 @@ func rewriteValueS390X_OpAdd64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAdd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Add8   x y)
+func rewriteValueS390X_OpAdd8_0(v *Value) bool {
+	// match: (Add8 x y)
 	// cond:
 	// result: (ADDW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADDW)
@@ -803,13 +806,12 @@ func rewriteValueS390X_OpAdd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAddPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAddPtr_0(v *Value) bool {
 	// match: (AddPtr x y)
 	// cond:
 	// result: (ADD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADD)
@@ -818,9 +820,7 @@ func rewriteValueS390X_OpAddPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAddr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAddr_0(v *Value) bool {
 	// match: (Addr {sym} base)
 	// cond:
 	// result: (MOVDaddr {sym} base)
@@ -833,13 +833,12 @@ func rewriteValueS390X_OpAddr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAnd16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAnd16_0(v *Value) bool {
 	// match: (And16 x y)
 	// cond:
 	// result: (ANDW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
@@ -848,13 +847,12 @@ func rewriteValueS390X_OpAnd16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAnd32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAnd32_0(v *Value) bool {
 	// match: (And32 x y)
 	// cond:
 	// result: (ANDW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
@@ -863,13 +861,12 @@ func rewriteValueS390X_OpAnd32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAnd64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAnd64_0(v *Value) bool {
 	// match: (And64 x y)
 	// cond:
 	// result: (AND x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
@@ -878,13 +875,12 @@ func rewriteValueS390X_OpAnd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAnd8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (And8  x y)
+func rewriteValueS390X_OpAnd8_0(v *Value) bool {
+	// match: (And8 x y)
 	// cond:
 	// result: (ANDW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
@@ -893,13 +889,12 @@ func rewriteValueS390X_OpAnd8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAndB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAndB_0(v *Value) bool {
 	// match: (AndB x y)
 	// cond:
 	// result: (ANDW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
@@ -908,53 +903,58 @@ func rewriteValueS390X_OpAndB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicAdd32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpAtomicAdd32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (AtomicAdd32 ptr val mem)
 	// cond:
-	// result: (AddTupleFirst32 (LAA ptr val mem) val)
+	// result: (AddTupleFirst32 val (LAA ptr val mem))
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
 		v.reset(OpS390XAddTupleFirst32)
-		v0 := b.NewValue0(v.Line, OpS390XLAA, MakeTuple(config.fe.TypeUInt32(), TypeMem))
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpS390XLAA, types.NewTuple(typ.UInt32, types.TypeMem))
 		v0.AddArg(ptr)
 		v0.AddArg(val)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v.AddArg(val)
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicAdd64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpAtomicAdd64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (AtomicAdd64 ptr val mem)
 	// cond:
-	// result: (AddTupleFirst64 (LAAG ptr val mem) val)
+	// result: (AddTupleFirst64 val (LAAG ptr val mem))
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
 		v.reset(OpS390XAddTupleFirst64)
-		v0 := b.NewValue0(v.Line, OpS390XLAAG, MakeTuple(config.fe.TypeUInt64(), TypeMem))
+		v.AddArg(val)
+		v0 := b.NewValue0(v.Pos, OpS390XLAAG, types.NewTuple(typ.UInt64, types.TypeMem))
 		v0.AddArg(ptr)
 		v0.AddArg(val)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v.AddArg(val)
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicCompareAndSwap32_0(v *Value) bool {
 	// match: (AtomicCompareAndSwap32 ptr old new_ mem)
 	// cond:
 	// result: (LoweredAtomicCas32 ptr old new_ mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		old := v.Args[1]
 		new_ := v.Args[2]
@@ -967,13 +967,12 @@ func rewriteValueS390X_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicCompareAndSwap64_0(v *Value) bool {
 	// match: (AtomicCompareAndSwap64 ptr old new_ mem)
 	// cond:
 	// result: (LoweredAtomicCas64 ptr old new_ mem)
 	for {
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		old := v.Args[1]
 		new_ := v.Args[2]
@@ -986,13 +985,12 @@ func rewriteValueS390X_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicExchange32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicExchange32_0(v *Value) bool {
 	// match: (AtomicExchange32 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicExchange32 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -1003,13 +1001,12 @@ func rewriteValueS390X_OpAtomicExchange32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicExchange64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicExchange64_0(v *Value) bool {
 	// match: (AtomicExchange64 ptr val mem)
 	// cond:
 	// result: (LoweredAtomicExchange64 ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -1020,13 +1017,12 @@ func rewriteValueS390X_OpAtomicExchange64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicLoad32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicLoad32_0(v *Value) bool {
 	// match: (AtomicLoad32 ptr mem)
 	// cond:
 	// result: (MOVWZatomicload ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XMOVWZatomicload)
@@ -1035,13 +1031,12 @@ func rewriteValueS390X_OpAtomicLoad32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicLoad64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicLoad64_0(v *Value) bool {
 	// match: (AtomicLoad64 ptr mem)
 	// cond:
 	// result: (MOVDatomicload ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XMOVDatomicload)
@@ -1050,13 +1045,12 @@ func rewriteValueS390X_OpAtomicLoad64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicLoadPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicLoadPtr_0(v *Value) bool {
 	// match: (AtomicLoadPtr ptr mem)
 	// cond:
 	// result: (MOVDatomicload ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XMOVDatomicload)
@@ -1065,13 +1059,12 @@ func rewriteValueS390X_OpAtomicLoadPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicStore32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicStore32_0(v *Value) bool {
 	// match: (AtomicStore32 ptr val mem)
 	// cond:
 	// result: (MOVWatomicstore ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -1082,13 +1075,12 @@ func rewriteValueS390X_OpAtomicStore32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicStore64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicStore64_0(v *Value) bool {
 	// match: (AtomicStore64 ptr val mem)
 	// cond:
 	// result: (MOVDatomicstore ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -1099,13 +1091,12 @@ func rewriteValueS390X_OpAtomicStore64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpAtomicStorePtrNoWB_0(v *Value) bool {
 	// match: (AtomicStorePtrNoWB ptr val mem)
 	// cond:
 	// result: (MOVDatomicstore ptr val mem)
 	for {
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
@@ -1116,40 +1107,50 @@ func rewriteValueS390X_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpAvg64u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpAvg64u_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Avg64u <t> x y)
 	// cond:
-	// result: (ADD (ADD <t> (SRDconst <t> x [1]) (SRDconst <t> y [1])) (ANDconst <t> (AND <t> x y) [1]))
+	// result: (ADD (SRDconst <t> (SUB <t> x y) [1]) y)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XADD)
-		v0 := b.NewValue0(v.Line, OpS390XADD, t)
-		v1 := b.NewValue0(v.Line, OpS390XSRDconst, t)
-		v1.AuxInt = 1
+		v0 := b.NewValue0(v.Pos, OpS390XSRDconst, t)
+		v0.AuxInt = 1
+		v1 := b.NewValue0(v.Pos, OpS390XSUB, t)
 		v1.AddArg(x)
+		v1.AddArg(y)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XSRDconst, t)
-		v2.AuxInt = 1
-		v2.AddArg(y)
-		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpS390XANDconst, t)
-		v3.AuxInt = 1
-		v4 := b.NewValue0(v.Line, OpS390XAND, t)
-		v4.AddArg(x)
-		v4.AddArg(y)
-		v3.AddArg(v4)
-		v.AddArg(v3)
+		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueS390X_OpBswap32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpBitLen64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen64 x)
+	// cond:
+	// result: (SUB (MOVDconst [64]) (FLOGR x))
+	for {
+		x := v.Args[0]
+		v.reset(OpS390XSUB)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
+		v0.AuxInt = 64
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XFLOGR, typ.UInt64)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueS390X_OpBswap32_0(v *Value) bool {
 	// match: (Bswap32 x)
 	// cond:
 	// result: (MOVWBR x)
@@ -1160,9 +1161,7 @@ func rewriteValueS390X_OpBswap32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpBswap64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpBswap64_0(v *Value) bool {
 	// match: (Bswap64 x)
 	// cond:
 	// result: (MOVDBR x)
@@ -1173,14 +1172,13 @@ func rewriteValueS390X_OpBswap64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpClosureCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpClosureCall_0(v *Value) bool {
 	// match: (ClosureCall [argwid] entry closure mem)
 	// cond:
 	// result: (CALLclosure [argwid] entry closure mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[2]
 		entry := v.Args[0]
 		closure := v.Args[1]
 		mem := v.Args[2]
@@ -1192,9 +1190,7 @@ func rewriteValueS390X_OpClosureCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCom16_0(v *Value) bool {
 	// match: (Com16 x)
 	// cond:
 	// result: (NOTW x)
@@ -1205,9 +1201,7 @@ func rewriteValueS390X_OpCom16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCom32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCom32_0(v *Value) bool {
 	// match: (Com32 x)
 	// cond:
 	// result: (NOTW x)
@@ -1218,9 +1212,7 @@ func rewriteValueS390X_OpCom32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCom64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCom64_0(v *Value) bool {
 	// match: (Com64 x)
 	// cond:
 	// result: (NOT x)
@@ -1231,10 +1223,8 @@ func rewriteValueS390X_OpCom64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com8  x)
+func rewriteValueS390X_OpCom8_0(v *Value) bool {
+	// match: (Com8 x)
 	// cond:
 	// result: (NOTW x)
 	for {
@@ -1244,10 +1234,8 @@ func rewriteValueS390X_OpCom8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const16  [val])
+func rewriteValueS390X_OpConst16_0(v *Value) bool {
+	// match: (Const16 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -1257,10 +1245,8 @@ func rewriteValueS390X_OpConst16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const32  [val])
+func rewriteValueS390X_OpConst32_0(v *Value) bool {
+	// match: (Const32 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -1270,9 +1256,7 @@ func rewriteValueS390X_OpConst32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpConst32F_0(v *Value) bool {
 	// match: (Const32F [val])
 	// cond:
 	// result: (FMOVSconst [val])
@@ -1283,10 +1267,8 @@ func rewriteValueS390X_OpConst32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const64  [val])
+func rewriteValueS390X_OpConst64_0(v *Value) bool {
+	// match: (Const64 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -1296,9 +1278,7 @@ func rewriteValueS390X_OpConst64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpConst64F_0(v *Value) bool {
 	// match: (Const64F [val])
 	// cond:
 	// result: (FMOVDconst [val])
@@ -1309,10 +1289,8 @@ func rewriteValueS390X_OpConst64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConst8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Const8   [val])
+func rewriteValueS390X_OpConst8_0(v *Value) bool {
+	// match: (Const8 [val])
 	// cond:
 	// result: (MOVDconst [val])
 	for {
@@ -1322,9 +1300,7 @@ func rewriteValueS390X_OpConst8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConstBool(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpConstBool_0(v *Value) bool {
 	// match: (ConstBool [b])
 	// cond:
 	// result: (MOVDconst [b])
@@ -1335,9 +1311,7 @@ func rewriteValueS390X_OpConstBool(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConstNil(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpConstNil_0(v *Value) bool {
 	// match: (ConstNil)
 	// cond:
 	// result: (MOVDconst [0])
@@ -1347,14 +1321,13 @@ func rewriteValueS390X_OpConstNil(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpConvert(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpConvert_0(v *Value) bool {
 	// match: (Convert <t> x mem)
 	// cond:
 	// result: (MOVDconvert <t> x mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XMOVDconvert)
@@ -1364,9 +1337,11 @@ func rewriteValueS390X_OpConvert(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCtz32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpCtz32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Ctz32 <t> x)
 	// cond:
 	// result: (SUB (MOVDconst [64]) (FLOGR (MOVWZreg (ANDW <t> (SUBWconst <t> [1] x) (NOTW <t> x)))))
@@ -1374,17 +1349,17 @@ func rewriteValueS390X_OpCtz32(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpS390XSUB)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 64
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XFLOGR, config.fe.TypeUInt64())
-		v2 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
-		v3 := b.NewValue0(v.Line, OpS390XANDW, t)
-		v4 := b.NewValue0(v.Line, OpS390XSUBWconst, t)
+		v1 := b.NewValue0(v.Pos, OpS390XFLOGR, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XANDW, t)
+		v4 := b.NewValue0(v.Pos, OpS390XSUBWconst, t)
 		v4.AuxInt = 1
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpS390XNOTW, t)
+		v5 := b.NewValue0(v.Pos, OpS390XNOTW, t)
 		v5.AddArg(x)
 		v3.AddArg(v5)
 		v2.AddArg(v3)
@@ -1393,9 +1368,11 @@ func rewriteValueS390X_OpCtz32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCtz64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpCtz64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Ctz64 <t> x)
 	// cond:
 	// result: (SUB (MOVDconst [64]) (FLOGR (AND <t> (SUBconst <t> [1] x) (NOT <t> x))))
@@ -1403,16 +1380,16 @@ func rewriteValueS390X_OpCtz64(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpS390XSUB)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 64
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XFLOGR, config.fe.TypeUInt64())
-		v2 := b.NewValue0(v.Line, OpS390XAND, t)
-		v3 := b.NewValue0(v.Line, OpS390XSUBconst, t)
+		v1 := b.NewValue0(v.Pos, OpS390XFLOGR, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpS390XAND, t)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBconst, t)
 		v3.AuxInt = 1
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XNOT, t)
+		v4 := b.NewValue0(v.Pos, OpS390XNOT, t)
 		v4.AddArg(x)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
@@ -1420,9 +1397,7 @@ func rewriteValueS390X_OpCtz64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt32Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt32Fto32_0(v *Value) bool {
 	// match: (Cvt32Fto32 x)
 	// cond:
 	// result: (CFEBRA x)
@@ -1433,9 +1408,7 @@ func rewriteValueS390X_OpCvt32Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt32Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt32Fto64_0(v *Value) bool {
 	// match: (Cvt32Fto64 x)
 	// cond:
 	// result: (CGEBRA x)
@@ -1446,9 +1419,7 @@ func rewriteValueS390X_OpCvt32Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt32Fto64F_0(v *Value) bool {
 	// match: (Cvt32Fto64F x)
 	// cond:
 	// result: (LDEBR x)
@@ -1459,9 +1430,7 @@ func rewriteValueS390X_OpCvt32Fto64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt32to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt32to32F_0(v *Value) bool {
 	// match: (Cvt32to32F x)
 	// cond:
 	// result: (CEFBRA x)
@@ -1472,9 +1441,7 @@ func rewriteValueS390X_OpCvt32to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt32to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt32to64F_0(v *Value) bool {
 	// match: (Cvt32to64F x)
 	// cond:
 	// result: (CDFBRA x)
@@ -1485,9 +1452,7 @@ func rewriteValueS390X_OpCvt32to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt64Fto32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt64Fto32_0(v *Value) bool {
 	// match: (Cvt64Fto32 x)
 	// cond:
 	// result: (CFDBRA x)
@@ -1498,9 +1463,7 @@ func rewriteValueS390X_OpCvt64Fto32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt64Fto32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt64Fto32F_0(v *Value) bool {
 	// match: (Cvt64Fto32F x)
 	// cond:
 	// result: (LEDBR x)
@@ -1511,9 +1474,7 @@ func rewriteValueS390X_OpCvt64Fto32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt64Fto64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt64Fto64_0(v *Value) bool {
 	// match: (Cvt64Fto64 x)
 	// cond:
 	// result: (CGDBRA x)
@@ -1524,9 +1485,7 @@ func rewriteValueS390X_OpCvt64Fto64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt64to32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt64to32F_0(v *Value) bool {
 	// match: (Cvt64to32F x)
 	// cond:
 	// result: (CEGBRA x)
@@ -1537,9 +1496,7 @@ func rewriteValueS390X_OpCvt64to32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpCvt64to64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpCvt64to64F_0(v *Value) bool {
 	// match: (Cvt64to64F x)
 	// cond:
 	// result: (CDGBRA x)
@@ -1550,83 +1507,76 @@ func rewriteValueS390X_OpCvt64to64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_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(OpS390XCALLdefer)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueS390X_OpDiv16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16 x y)
 	// cond:
 	// result: (DIVW  (MOVHreg x) (MOVHreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div16u x y)
 	// cond:
 	// result: (DIVWU (MOVHZreg x) (MOVHZreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div32 x y)
 	// cond:
 	// result: (DIVW  (MOVWreg x) y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpDiv32F_0(v *Value) bool {
 	// match: (Div32F x y)
 	// cond:
 	// result: (FDIVS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFDIVS)
@@ -1635,30 +1585,32 @@ func rewriteValueS390X_OpDiv32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv32u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Div32u x y)
 	// cond:
 	// result: (DIVWU (MOVWZreg x) y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div64  x y)
+func rewriteValueS390X_OpDiv64_0(v *Value) bool {
+	// match: (Div64 x y)
 	// cond:
 	// result: (DIVD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVD)
@@ -1667,13 +1619,12 @@ func rewriteValueS390X_OpDiv64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpDiv64F_0(v *Value) bool {
 	// match: (Div64F x y)
 	// cond:
 	// result: (FDIV x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFDIV)
@@ -1682,13 +1633,12 @@ func rewriteValueS390X_OpDiv64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpDiv64u_0(v *Value) bool {
 	// match: (Div64u x y)
 	// cond:
 	// result: (DIVDU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVDU)
@@ -1697,489 +1647,547 @@ func rewriteValueS390X_OpDiv64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8 x y)
 	// cond:
 	// result: (DIVW  (MOVBreg x) (MOVBreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpDiv8u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpDiv8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div8u  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8u x y)
 	// cond:
 	// result: (DIVWU (MOVBZreg x) (MOVBZreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XDIVWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Eq16 x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Eq32 x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq32F x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Eq64 x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq64F x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEq8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Eq8 x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEqB(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (EqB   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (EqB x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpEqPtr(v *Value, config *Config) bool {
+func rewriteValueS390X_OpEqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (EqPtr x y)
 	// cond:
 	// result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDEQ)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Geq16 x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq16U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq16U x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Geq32 x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32F x y)
 	// cond:
 	// result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGEnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq32U x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Geq64 x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64F x y)
 	// cond:
 	// result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGEnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq64U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64U x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Geq8 x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq8U  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Geq8U x y)
 	// cond:
 	// result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGetClosurePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpGetClosurePtr_0(v *Value) bool {
 	// match: (GetClosurePtr)
 	// cond:
 	// result: (LoweredGetClosurePtr)
@@ -2188,9 +2196,7 @@ func rewriteValueS390X_OpGetClosurePtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpGetG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpGetG_0(v *Value) bool {
 	// match: (GetG mem)
 	// cond:
 	// result: (LoweredGetG mem)
@@ -2201,362 +2207,338 @@ func rewriteValueS390X_OpGetG(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpGoCall(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (GoCall [argwid] mem)
-	// cond:
-	// result: (CALLgo [argwid] mem)
-	for {
-		argwid := v.AuxInt
-		mem := v.Args[0]
-		v.reset(OpS390XCALLgo)
-		v.AuxInt = argwid
-		v.AddArg(mem)
-		return true
-	}
-}
-func rewriteValueS390X_OpGreater16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Greater16 x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater16U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater16U x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Greater32 x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater32F x y)
 	// cond:
 	// result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGTnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater32U x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Greater64 x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater64F x y)
 	// cond:
 	// result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGTnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater64U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater64U x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Greater8 x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpGreater8U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpGreater8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater8U  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Greater8U x y)
 	// cond:
 	// result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpHmul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16  x y)
-	// cond:
-	// result: (SRDconst [16] (MULLW (MOVHreg x) (MOVHreg y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpS390XSRDconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpS390XMULLW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueS390X_OpHmul16u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul16u x y)
-	// cond:
-	// result: (SRDconst [16] (MULLW (MOVHZreg x) (MOVHZreg y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpS390XSRDconst)
-		v.AuxInt = 16
-		v0 := b.NewValue0(v.Line, OpS390XMULLW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueS390X_OpHmul32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpHmul32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Hmul32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Hmul32 x y)
 	// cond:
 	// result: (SRDconst [32] (MULLD (MOVWreg x) (MOVWreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRDconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpS390XMULLD, config.fe.TypeInt64())
-		v1 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMULLD, typ.Int64)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWreg, typ.Int64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWreg, typ.Int64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueS390X_OpHmul32u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpHmul32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Hmul32u x y)
 	// cond:
 	// result: (SRDconst [32] (MULLD (MOVWZreg x) (MOVWZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRDconst)
 		v.AuxInt = 32
-		v0 := b.NewValue0(v.Line, OpS390XMULLD, config.fe.TypeInt64())
-		v1 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMULLD, typ.Int64)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueS390X_OpHmul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul64  x y)
+func rewriteValueS390X_OpHmul64_0(v *Value) bool {
+	// match: (Hmul64 x y)
 	// cond:
 	// result: (MULHD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULHD)
@@ -2565,13 +2547,12 @@ func rewriteValueS390X_OpHmul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpHmul64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpHmul64u_0(v *Value) bool {
 	// match: (Hmul64u x y)
 	// cond:
 	// result: (MULHDU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULHDU)
@@ -2580,53 +2561,7 @@ func rewriteValueS390X_OpHmul64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpHmul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8   x y)
-	// cond:
-	// result: (SRDconst [8] (MULLW (MOVBreg x) (MOVBreg y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpS390XSRDconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpS390XMULLW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueS390X_OpHmul8u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Hmul8u  x y)
-	// cond:
-	// result: (SRDconst [8] (MULLW (MOVBZreg x) (MOVBZreg y)))
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpS390XSRDconst)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpS390XMULLW, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
-		v1.AddArg(x)
-		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
-		v2.AddArg(y)
-		v0.AddArg(v2)
-		v.AddArg(v0)
-		return true
-	}
-}
-func rewriteValueS390X_OpITab(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpITab_0(v *Value) bool {
 	// match: (ITab (Load ptr mem))
 	// cond:
 	// result: (MOVDload ptr mem)
@@ -2635,6 +2570,7 @@ func rewriteValueS390X_OpITab(v *Value, config *Config) bool {
 		if v_0.Op != OpLoad {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		mem := v_0.Args[1]
 		v.reset(OpS390XMOVDload)
@@ -2644,14 +2580,13 @@ func rewriteValueS390X_OpITab(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpInterCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpInterCall_0(v *Value) bool {
 	// match: (InterCall [argwid] entry mem)
 	// cond:
 	// result: (CALLinter [argwid] entry mem)
 	for {
 		argwid := v.AuxInt
+		_ = v.Args[1]
 		entry := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XCALLinter)
@@ -2661,574 +2596,641 @@ func rewriteValueS390X_OpInterCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValueS390X_OpIsInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsInBounds idx len)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(idx)
 		v2.AddArg(len)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpIsNonNil(v *Value, config *Config) bool {
+func rewriteValueS390X_OpIsNonNil_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsNonNil p)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPconst p [0]))
 	for {
 		p := v.Args[0]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPconst, types.TypeFlags)
 		v2.AuxInt = 0
 		v2.AddArg(p)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValueS390X_OpIsSliceInBounds_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (IsSliceInBounds idx len)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
 	for {
+		_ = v.Args[1]
 		idx := v.Args[0]
 		len := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(idx)
 		v2.AddArg(len)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Leq16 x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq16U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq16U x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Leq32 x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32F x y)
 	// cond:
 	// result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGEnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(y)
 		v2.AddArg(x)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq32U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq32U x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Leq64 x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64F x y)
 	// cond:
 	// result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGEnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(y)
 		v2.AddArg(x)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq64U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64U x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Leq8 x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLeq8U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLeq8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Leq8U  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Leq8U x y)
 	// cond:
 	// result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Less16 x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess16U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less16U x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Less32 x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less32F x y)
 	// cond:
 	// result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGTnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(y)
 		v2.AddArg(x)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess32U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess32U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less32U x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Less64 x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less64F x y)
 	// cond:
 	// result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDGTnoinv)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(y)
 		v2.AddArg(x)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess64U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less64U x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Less8 x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLess8U(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLess8U_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less8U  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Less8U x y)
 	// cond:
 	// result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDLT)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMPU, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpLoad_0(v *Value) bool {
 	// match: (Load <t> ptr mem)
 	// cond: (is64BitInt(t) || isPtr(t))
 	// result: (MOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) || isPtr(t)) {
@@ -3244,6 +3246,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && isSigned(t)) {
@@ -3259,6 +3262,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVWZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitInt(t) && !isSigned(t)) {
@@ -3274,6 +3278,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && isSigned(t)) {
@@ -3289,6 +3294,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVHZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is16BitInt(t) && !isSigned(t)) {
@@ -3304,6 +3310,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is8BitInt(t) && isSigned(t)) {
@@ -3319,6 +3326,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (MOVBZload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) {
@@ -3334,6 +3342,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVSload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is32BitFloat(t)) {
@@ -3349,6 +3358,7 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	// result: (FMOVDload ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitFloat(t)) {
@@ -3361,59 +3371,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpLrot32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot32 <t> x [c])
-	// cond:
-	// result: (RLLconst <t> [c&31] x)
-	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpS390XRLLconst)
-		v.Type = t
-		v.AuxInt = c & 31
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueS390X_OpLrot64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot64 <t> x [c])
-	// cond:
-	// result: (RLLGconst <t> [c&63] x)
-	for {
-		t := v.Type
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpS390XRLLGconst)
-		v.Type = t
-		v.AuxInt = c & 63
-		v.AddArg(x)
-		return true
-	}
-}
-func rewriteValueS390X_OpLsh16x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x16 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3421,7 +3400,7 @@ func rewriteValueS390X_OpLsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh16x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh16x32 <t> x y)
@@ -3429,15 +3408,16 @@ func rewriteValueS390X_OpLsh16x32(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3445,7 +3425,7 @@ func rewriteValueS390X_OpLsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh16x64 <t> x y)
@@ -3453,15 +3433,16 @@ func rewriteValueS390X_OpLsh16x64(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3469,25 +3450,28 @@ func rewriteValueS390X_OpLsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x8 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3495,25 +3479,28 @@ func rewriteValueS390X_OpLsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x16 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3521,7 +3508,7 @@ func rewriteValueS390X_OpLsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh32x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh32x32 <t> x y)
@@ -3529,15 +3516,16 @@ func rewriteValueS390X_OpLsh32x32(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3545,7 +3533,7 @@ func rewriteValueS390X_OpLsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh32x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh32x64 <t> x y)
@@ -3553,15 +3541,16 @@ func rewriteValueS390X_OpLsh32x64(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3569,25 +3558,28 @@ func rewriteValueS390X_OpLsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh32x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh32x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x8 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3595,25 +3587,28 @@ func rewriteValueS390X_OpLsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh64x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x16 <t> x y)
 	// cond:
 	// result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSLD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3621,7 +3616,7 @@ func rewriteValueS390X_OpLsh64x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh64x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh64x32 <t> x y)
@@ -3629,15 +3624,16 @@ func rewriteValueS390X_OpLsh64x32(v *Value, config *Config) bool {
 	// result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSLD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3645,7 +3641,7 @@ func rewriteValueS390X_OpLsh64x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh64x64 <t> x y)
@@ -3653,15 +3649,16 @@ func rewriteValueS390X_OpLsh64x64(v *Value, config *Config) bool {
 	// result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSLD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 63
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3669,25 +3666,28 @@ func rewriteValueS390X_OpLsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x8 <t> x y)
 	// cond:
 	// result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSLD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3695,25 +3695,28 @@ func rewriteValueS390X_OpLsh64x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x16 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3721,7 +3724,7 @@ func rewriteValueS390X_OpLsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh8x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh8x32 <t> x y)
@@ -3729,15 +3732,16 @@ func rewriteValueS390X_OpLsh8x32(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3745,7 +3749,7 @@ func rewriteValueS390X_OpLsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh8x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Lsh8x64 <t> x y)
@@ -3753,15 +3757,16 @@ func rewriteValueS390X_OpLsh8x64(v *Value, config *Config) bool {
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -3769,25 +3774,28 @@ func rewriteValueS390X_OpLsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpLsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x8 <t> x y)
 	// cond:
 	// result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSLW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -3795,85 +3803,96 @@ func rewriteValueS390X_OpLsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMod16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod16 x y)
 	// cond:
 	// result: (MODW  (MOVHreg x) (MOVHreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpMod16u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod16u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod16u x y)
 	// cond:
 	// result: (MODWU (MOVHZreg x) (MOVHZreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpMod32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod32 x y)
 	// cond:
 	// result: (MODW  (MOVWreg x) y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueS390X_OpMod32u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod32u_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mod32u x y)
 	// cond:
 	// result: (MODWU (MOVWZreg x) y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(y)
 		return true
 	}
 }
-func rewriteValueS390X_OpMod64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mod64  x y)
+func rewriteValueS390X_OpMod64_0(v *Value) bool {
+	// match: (Mod64 x y)
 	// cond:
 	// result: (MODD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODD)
@@ -3882,13 +3901,12 @@ func rewriteValueS390X_OpMod64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMod64u(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpMod64u_0(v *Value) bool {
 	// match: (Mod64u x y)
 	// cond:
 	// result: (MODDU x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODDU)
@@ -3897,163 +3915,171 @@ func rewriteValueS390X_OpMod64u(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMod8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8 x y)
 	// cond:
 	// result: (MODW  (MOVBreg x) (MOVBreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpMod8u(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMod8u_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod8u  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mod8u x y)
 	// cond:
 	// result: (MODWU (MOVBZreg x) (MOVBZreg y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMODWU)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(y)
 		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
+func rewriteValueS390X_OpMove_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Move [s] _ _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [0] _ _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[2]
+		mem := v.Args[2]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Move [1] dst src mem)
+	// cond:
 	// result: (MOVBstore dst (MOVBZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 1 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 1) {
-			break
-		}
 		v.reset(OpS390XMOVBstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, typ.UInt8)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Move [2] dst src mem)
+	// cond:
 	// result: (MOVHstore dst (MOVHZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 2 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 2) {
-			break
-		}
 		v.reset(OpS390XMOVHstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Move [4] dst src mem)
+	// cond:
 	// result: (MOVWstore dst (MOVWZload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 4 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 4) {
-			break
-		}
 		v.reset(OpS390XMOVWstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Move [8] dst src mem)
+	// cond:
 	// result: (MOVDstore dst (MOVDload src mem) mem)
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 8 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 8) {
-			break
-		}
 		v.reset(OpS390XMOVDstore)
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 16
+	// match: (Move [16] dst src mem)
+	// cond:
 	// result: (MOVDstore [8] dst (MOVDload [8] src mem) 		(MOVDstore dst (MOVDload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 16 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 16) {
-			break
-		}
 		v.reset(OpS390XMOVDstore)
 		v.AuxInt = 8
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v0.AuxInt = 8
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -4061,36 +4087,36 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 24
+	// match: (Move [24] dst src mem)
+	// cond:
 	// result: (MOVDstore [16] dst (MOVDload [16] src mem) 	        (MOVDstore [8] dst (MOVDload [8] src mem)                 (MOVDstore dst (MOVDload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 24 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 24) {
-			break
-		}
 		v.reset(OpS390XMOVDstore)
 		v.AuxInt = 16
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v0.AuxInt = 16
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDstore, types.TypeMem)
 		v1.AuxInt = 8
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v2.AuxInt = 8
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVDstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -4099,28 +4125,28 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Move [3] dst src mem)
+	// cond:
 	// result: (MOVBstore [2] dst (MOVBZload [2] src mem) 		(MOVHstore dst (MOVHZload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 3 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 3) {
-			break
-		}
 		v.reset(OpS390XMOVBstore)
 		v.AuxInt = 2
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, typ.UInt8)
 		v0.AuxInt = 2
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -4128,28 +4154,28 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Move [5] dst src mem)
+	// cond:
 	// result: (MOVBstore [4] dst (MOVBZload [4] src mem) 		(MOVWstore dst (MOVWZload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 5 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 5) {
-			break
-		}
 		v.reset(OpS390XMOVBstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, typ.UInt8)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -4157,28 +4183,28 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Move [6] dst src mem)
+	// cond:
 	// result: (MOVHstore [4] dst (MOVHZload [4] src mem) 		(MOVWstore dst (MOVWZload src mem) mem))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 6 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 6) {
-			break
-		}
 		v.reset(OpS390XMOVHstore)
 		v.AuxInt = 4
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v0.AuxInt = 4
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWstore, types.TypeMem)
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
@@ -4186,36 +4212,43 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	return false
+}
+func rewriteValueS390X_OpMove_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Move [7] dst src mem)
+	// cond:
 	// result: (MOVBstore [6] dst (MOVBZload [6] src mem) 		(MOVHstore [4] dst (MOVHZload [4] src mem) 			(MOVWstore dst (MOVWZload src mem) mem)))
 	for {
-		s := v.AuxInt
+		if v.AuxInt != 7 {
+			break
+		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() == 7) {
-			break
-		}
 		v.reset(OpS390XMOVBstore)
 		v.AuxInt = 6
 		v.AddArg(dst)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZload, config.fe.TypeUInt8())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, typ.UInt8)
 		v0.AuxInt = 6
 		v0.AddArg(src)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHstore, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHstore, types.TypeMem)
 		v1.AuxInt = 4
 		v1.AddArg(dst)
-		v2 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v2.AuxInt = 4
 		v2.AddArg(src)
 		v2.AddArg(mem)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWstore, types.TypeMem)
 		v3.AddArg(dst)
-		v4 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
 		v4.AddArg(src)
 		v4.AddArg(mem)
 		v3.AddArg(v4)
@@ -4225,39 +4258,41 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256
-	// result: (MVC [makeValAndOff(SizeAndAlign(s).Size(), 0)] dst src mem)
+	// cond: s > 0 && s <= 256
+	// result: (MVC [makeValAndOff(s, 0)] dst src mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256) {
+		if !(s > 0 && s <= 256) {
 			break
 		}
 		v.reset(OpS390XMVC)
-		v.AuxInt = makeValAndOff(SizeAndAlign(s).Size(), 0)
+		v.AuxInt = makeValAndOff(s, 0)
 		v.AddArg(dst)
 		v.AddArg(src)
 		v.AddArg(mem)
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512
-	// result: (MVC [makeValAndOff(SizeAndAlign(s).Size()-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))
+	// cond: s > 256 && s <= 512
+	// result: (MVC [makeValAndOff(s-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512) {
+		if !(s > 256 && s <= 512) {
 			break
 		}
 		v.reset(OpS390XMVC)
-		v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-256, 256)
+		v.AuxInt = makeValAndOff(s-256, 256)
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v0.AuxInt = makeValAndOff(256, 0)
 		v0.AddArg(dst)
 		v0.AddArg(src)
@@ -4266,25 +4301,26 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768
-	// result: (MVC [makeValAndOff(SizeAndAlign(s).Size()-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))
+	// cond: s > 512 && s <= 768
+	// result: (MVC [makeValAndOff(s-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768) {
+		if !(s > 512 && s <= 768) {
 			break
 		}
 		v.reset(OpS390XMVC)
-		v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-512, 512)
+		v.AuxInt = makeValAndOff(s-512, 512)
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v0.AuxInt = makeValAndOff(256, 256)
 		v0.AddArg(dst)
 		v0.AddArg(src)
-		v1 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v1.AuxInt = makeValAndOff(256, 0)
 		v1.AddArg(dst)
 		v1.AddArg(src)
@@ -4294,29 +4330,30 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024
-	// result: (MVC [makeValAndOff(SizeAndAlign(s).Size()-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))))
+	// cond: s > 768 && s <= 1024
+	// result: (MVC [makeValAndOff(s-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))))
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024) {
+		if !(s > 768 && s <= 1024) {
 			break
 		}
 		v.reset(OpS390XMVC)
-		v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-768, 768)
+		v.AuxInt = makeValAndOff(s-768, 768)
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v0.AuxInt = makeValAndOff(256, 512)
 		v0.AddArg(dst)
 		v0.AddArg(src)
-		v1 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v1 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v1.AuxInt = makeValAndOff(256, 256)
 		v1.AddArg(dst)
 		v1.AddArg(src)
-		v2 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+		v2 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem)
 		v2.AuxInt = makeValAndOff(256, 0)
 		v2.AddArg(dst)
 		v2.AddArg(src)
@@ -4327,22 +4364,23 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Move [s] dst src mem)
-	// cond: SizeAndAlign(s).Size() > 1024
-	// result: (LoweredMove [SizeAndAlign(s).Size()%256] dst src (ADDconst <src.Type> src [(SizeAndAlign(s).Size()/256)*256]) mem)
+	// cond: s > 1024
+	// result: (LoweredMove [s%256] dst src (ADDconst <src.Type> src [(s/256)*256]) mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[2]
 		dst := v.Args[0]
 		src := v.Args[1]
 		mem := v.Args[2]
-		if !(SizeAndAlign(s).Size() > 1024) {
+		if !(s > 1024) {
 			break
 		}
 		v.reset(OpS390XLoweredMove)
-		v.AuxInt = SizeAndAlign(s).Size() % 256
+		v.AuxInt = s % 256
 		v.AddArg(dst)
 		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpS390XADDconst, src.Type)
-		v0.AuxInt = (SizeAndAlign(s).Size() / 256) * 256
+		v0 := b.NewValue0(v.Pos, OpS390XADDconst, src.Type)
+		v0.AuxInt = (s / 256) * 256
 		v0.AddArg(src)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -4350,13 +4388,12 @@ func rewriteValueS390X_OpMove(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpMul16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul16  x y)
+func rewriteValueS390X_OpMul16_0(v *Value) bool {
+	// match: (Mul16 x y)
 	// cond:
 	// result: (MULLW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULLW)
@@ -4365,13 +4402,12 @@ func rewriteValueS390X_OpMul16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMul32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul32  x y)
+func rewriteValueS390X_OpMul32_0(v *Value) bool {
+	// match: (Mul32 x y)
 	// cond:
 	// result: (MULLW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULLW)
@@ -4380,13 +4416,12 @@ func rewriteValueS390X_OpMul32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMul32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpMul32F_0(v *Value) bool {
 	// match: (Mul32F x y)
 	// cond:
 	// result: (FMULS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFMULS)
@@ -4395,13 +4430,12 @@ func rewriteValueS390X_OpMul32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64  x y)
+func rewriteValueS390X_OpMul64_0(v *Value) bool {
+	// match: (Mul64 x y)
 	// cond:
 	// result: (MULLD  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULLD)
@@ -4410,13 +4444,12 @@ func rewriteValueS390X_OpMul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpMul64F_0(v *Value) bool {
 	// match: (Mul64F x y)
 	// cond:
 	// result: (FMUL x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFMUL)
@@ -4425,13 +4458,12 @@ func rewriteValueS390X_OpMul64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpMul8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul8   x y)
+func rewriteValueS390X_OpMul8_0(v *Value) bool {
+	// match: (Mul8 x y)
 	// cond:
 	// result: (MULLW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMULLW)
@@ -4440,25 +4472,25 @@ func rewriteValueS390X_OpMul8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeg16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neg16  x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neg16 x)
 	// cond:
 	// result: (NEGW (MOVHreg x))
 	for {
 		x := v.Args[0]
 		v.reset(OpS390XNEGW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg32  x)
+func rewriteValueS390X_OpNeg32_0(v *Value) bool {
+	// match: (Neg32 x)
 	// cond:
 	// result: (NEGW x)
 	for {
@@ -4468,9 +4500,7 @@ func rewriteValueS390X_OpNeg32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpNeg32F_0(v *Value) bool {
 	// match: (Neg32F x)
 	// cond:
 	// result: (FNEGS x)
@@ -4481,10 +4511,8 @@ func rewriteValueS390X_OpNeg32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Neg64  x)
+func rewriteValueS390X_OpNeg64_0(v *Value) bool {
+	// match: (Neg64 x)
 	// cond:
 	// result: (NEG x)
 	for {
@@ -4494,9 +4522,7 @@ func rewriteValueS390X_OpNeg64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpNeg64F_0(v *Value) bool {
 	// match: (Neg64F x)
 	// cond:
 	// result: (FNEG x)
@@ -4507,224 +4533,249 @@ func rewriteValueS390X_OpNeg64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNeg8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeg8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neg8   x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neg8 x)
 	// cond:
 	// result: (NEGW (MOVBreg x))
 	for {
 		x := v.Args[0]
 		v.reset(OpS390XNEGW)
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq16  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neq16 x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq32  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neq32 x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPW, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq32F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq32F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq32F x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMPS, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq64  x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neq64 x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq64F(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq64F_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq64F x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XFCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeq8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeq8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq8   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Neq8 x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeqB(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeqB_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (NeqB   x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (NeqB x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
-		v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v3.AddArg(x)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v4.AddArg(y)
 		v2.AddArg(v4)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValueS390X_OpNeqPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (NeqPtr x y)
 	// cond:
 	// result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XMOVDNE)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = 0
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v1 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v1.AuxInt = 1
 		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XCMP, types.TypeFlags)
 		v2.AddArg(x)
 		v2.AddArg(y)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValueS390X_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpNilCheck_0(v *Value) bool {
 	// match: (NilCheck ptr mem)
 	// cond:
 	// result: (LoweredNilCheck ptr mem)
 	for {
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		v.reset(OpS390XLoweredNilCheck)
@@ -4733,9 +4784,7 @@ func rewriteValueS390X_OpNilCheck(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpNot_0(v *Value) bool {
 	// match: (Not x)
 	// cond:
 	// result: (XORWconst [1] x)
@@ -4747,9 +4796,11 @@ func rewriteValueS390X_OpNot(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValueS390X_OpOffPtr_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (OffPtr [off] ptr:(SP))
 	// cond:
 	// result: (MOVDaddr [off] ptr)
@@ -4785,20 +4836,19 @@ func rewriteValueS390X_OpOffPtr(v *Value, config *Config) bool {
 		off := v.AuxInt
 		ptr := v.Args[0]
 		v.reset(OpS390XADD)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
 		v0.AuxInt = off
 		v.AddArg(v0)
 		v.AddArg(ptr)
 		return true
 	}
 }
-func rewriteValueS390X_OpOr16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpOr16_0(v *Value) bool {
 	// match: (Or16 x y)
 	// cond:
 	// result: (ORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XORW)
@@ -4807,13 +4857,12 @@ func rewriteValueS390X_OpOr16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpOr32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpOr32_0(v *Value) bool {
 	// match: (Or32 x y)
 	// cond:
 	// result: (ORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XORW)
@@ -4822,13 +4871,12 @@ func rewriteValueS390X_OpOr32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpOr64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpOr64_0(v *Value) bool {
 	// match: (Or64 x y)
 	// cond:
 	// result: (OR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XOR)
@@ -4837,13 +4885,12 @@ func rewriteValueS390X_OpOr64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpOr8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Or8  x y)
+func rewriteValueS390X_OpOr8_0(v *Value) bool {
+	// match: (Or8 x y)
 	// cond:
 	// result: (ORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XORW)
@@ -4852,13 +4899,12 @@ func rewriteValueS390X_OpOr8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpOrB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpOrB_0(v *Value) bool {
 	// match: (OrB x y)
 	// cond:
 	// result: (ORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XORW)
@@ -4867,27 +4913,52 @@ func rewriteValueS390X_OpOrB(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x)
+	// cond:
+	// result: (LoweredRound32F x)
+	for {
+		x := v.Args[0]
+		v.reset(OpS390XLoweredRound32F)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueS390X_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x)
+	// cond:
+	// result: (LoweredRound64F x)
+	for {
+		x := v.Args[0]
+		v.reset(OpS390XLoweredRound64F)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueS390X_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux16 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [15])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 15
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -4895,25 +4966,28 @@ func rewriteValueS390X_OpRsh16Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux32 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [15])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 15
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -4921,25 +4995,28 @@ func rewriteValueS390X_OpRsh16Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [15])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v3.AuxInt = 15
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -4947,27 +5024,30 @@ func rewriteValueS390X_OpRsh16Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux8 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [15])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 15
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -4975,28 +5055,31 @@ func rewriteValueS390X_OpRsh16Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x16 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [15])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 15
-		v5 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
@@ -5006,26 +5089,29 @@ func rewriteValueS390X_OpRsh16x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x32 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [15])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 15
 		v4.AddArg(y)
 		v3.AddArg(v4)
@@ -5035,26 +5121,29 @@ func rewriteValueS390X_OpRsh16x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x64 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVHreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [15])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XOR, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XOR, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOT, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOT, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v4.AuxInt = 15
 		v4.AddArg(y)
 		v3.AddArg(v4)
@@ -5064,28 +5153,31 @@ func rewriteValueS390X_OpRsh16x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh16x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x8 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [15])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 15
-		v5 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
@@ -5095,25 +5187,28 @@ func rewriteValueS390X_OpRsh16x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux16 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -5121,7 +5216,7 @@ func rewriteValueS390X_OpRsh32Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32Ux32 <t> x y)
@@ -5129,15 +5224,16 @@ func rewriteValueS390X_OpRsh32Ux32(v *Value, config *Config) bool {
 	// result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -5145,7 +5241,7 @@ func rewriteValueS390X_OpRsh32Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32Ux64 <t> x y)
@@ -5153,15 +5249,16 @@ func rewriteValueS390X_OpRsh32Ux64(v *Value, config *Config) bool {
 	// result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 31
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -5169,25 +5266,28 @@ func rewriteValueS390X_OpRsh32Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32Ux8 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 31
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -5195,26 +5295,29 @@ func rewriteValueS390X_OpRsh32Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x16 <t> x y)
 	// cond:
 	// result: (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [31])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 31
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5224,7 +5327,7 @@ func rewriteValueS390X_OpRsh32x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32x32 <t> x y)
@@ -5232,16 +5335,17 @@ func rewriteValueS390X_OpRsh32x32(v *Value, config *Config) bool {
 	// result: (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [31])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 31
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5251,7 +5355,7 @@ func rewriteValueS390X_OpRsh32x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh32x64 <t> x y)
@@ -5259,16 +5363,17 @@ func rewriteValueS390X_OpRsh32x64(v *Value, config *Config) bool {
 	// result: (SRAW <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [31])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XOR, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOT, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v3.AuxInt = 31
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5278,26 +5383,29 @@ func rewriteValueS390X_OpRsh32x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh32x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh32x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x8 <t> x y)
 	// cond:
 	// result: (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [31])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 31
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5307,25 +5415,28 @@ func rewriteValueS390X_OpRsh32x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux16 <t> x y)
 	// cond:
 	// result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSRD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
-		v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -5333,7 +5444,7 @@ func rewriteValueS390X_OpRsh64Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh64Ux32 <t> x y)
@@ -5341,15 +5452,16 @@ func rewriteValueS390X_OpRsh64Ux32(v *Value, config *Config) bool {
 	// result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSRD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -5357,7 +5469,7 @@ func rewriteValueS390X_OpRsh64Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh64Ux64 <t> x y)
@@ -5365,15 +5477,16 @@ func rewriteValueS390X_OpRsh64Ux64(v *Value, config *Config) bool {
 	// result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSRD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v2.AuxInt = 63
 		v2.AddArg(y)
 		v1.AddArg(v2)
@@ -5381,25 +5494,28 @@ func rewriteValueS390X_OpRsh64Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64Ux8 <t> x y)
 	// cond:
 	// result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XAND)
-		v0 := b.NewValue0(v.Line, OpS390XSRD, t)
+		v0 := b.NewValue0(v.Pos, OpS390XSRD, t)
 		v0.AddArg(x)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, t)
-		v2 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, t)
+		v2 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v2.AuxInt = 63
-		v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v3 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v3.AddArg(y)
 		v2.AddArg(v3)
 		v1.AddArg(v2)
@@ -5407,26 +5523,29 @@ func rewriteValueS390X_OpRsh64Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x16 <t> x y)
 	// cond:
 	// result: (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [63])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAD)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 63
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5436,7 +5555,7 @@ func rewriteValueS390X_OpRsh64x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh64x32 <t> x y)
@@ -5444,16 +5563,17 @@ func rewriteValueS390X_OpRsh64x32(v *Value, config *Config) bool {
 	// result: (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [63])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAD)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 63
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5463,7 +5583,7 @@ func rewriteValueS390X_OpRsh64x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Rsh64x64 <t> x y)
@@ -5471,16 +5591,17 @@ func rewriteValueS390X_OpRsh64x64(v *Value, config *Config) bool {
 	// result: (SRAD <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [63])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAD)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XOR, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOT, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOT, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v3.AuxInt = 63
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5490,26 +5611,29 @@ func rewriteValueS390X_OpRsh64x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh64x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x8 <t> x y)
 	// cond:
 	// result: (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [63])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAD)
 		v.Type = t
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v0.AddArg(y)
-		v1 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v1 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 63
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5519,27 +5643,30 @@ func rewriteValueS390X_OpRsh64x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux16 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [7])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 7
-		v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5547,25 +5674,28 @@ func rewriteValueS390X_OpRsh8Ux16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux32 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [7])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 7
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5573,25 +5703,28 @@ func rewriteValueS390X_OpRsh8Ux32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux64 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [7])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v3.AuxInt = 7
 		v3.AddArg(y)
 		v2.AddArg(v3)
@@ -5599,27 +5732,30 @@ func rewriteValueS390X_OpRsh8Ux64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux8 <t> x y)
 	// cond:
 	// result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [7])))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XANDW)
-		v0 := b.NewValue0(v.Line, OpS390XSRW, t)
-		v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XSRW, t)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v0.AddArg(y)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, t)
-		v3 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, t)
+		v3 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v3.AuxInt = 7
-		v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v4 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v4.AddArg(y)
 		v3.AddArg(v4)
 		v2.AddArg(v3)
@@ -5627,28 +5763,31 @@ func rewriteValueS390X_OpRsh8Ux8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x16 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [7])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 7
-		v5 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
@@ -5658,26 +5797,29 @@ func rewriteValueS390X_OpRsh8x16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x32 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [7])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 7
 		v4.AddArg(y)
 		v3.AddArg(v4)
@@ -5687,26 +5829,29 @@ func rewriteValueS390X_OpRsh8x32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x64 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVBreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [7])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XOR, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XOR, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOT, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOT, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v4.AuxInt = 7
 		v4.AddArg(y)
 		v3.AddArg(v4)
@@ -5716,28 +5861,31 @@ func rewriteValueS390X_OpRsh8x64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueS390X_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x8  <t> x y)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8x8 <t> x y)
 	// cond:
 	// result: (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [7])))))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSRAW)
 		v.Type = t
-		v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBreg, typ.Int64)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XORW, y.Type)
+		v1 := b.NewValue0(v.Pos, OpS390XORW, y.Type)
 		v1.AddArg(y)
-		v2 := b.NewValue0(v.Line, OpS390XNOTW, y.Type)
-		v3 := b.NewValue0(v.Line, OpS390XSUBEWcarrymask, y.Type)
-		v4 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v2 := b.NewValue0(v.Pos, OpS390XNOTW, y.Type)
+		v3 := b.NewValue0(v.Pos, OpS390XSUBEWcarrymask, y.Type)
+		v4 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v4.AuxInt = 7
-		v5 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+		v5 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64)
 		v5.AddArg(y)
 		v4.AddArg(v5)
 		v3.AddArg(v4)
@@ -5747,13 +5895,12 @@ func rewriteValueS390X_OpRsh8x8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XADD_0(v *Value) bool {
 	// match: (ADD x (MOVDconst [c]))
 	// cond: is32Bit(c)
 	// result: (ADDconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -5772,6 +5919,7 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (ADDconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -5786,54 +5934,111 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (ADD x (MOVDaddr [c] {s} y))
-	// cond: x.Op != OpSB && y.Op != OpSB
-	// result: (MOVDaddridx [c] {s} x y)
+	// match: (ADD (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSLDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSLDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD idx (MOVDaddr [c] {s} ptr))
+	// cond: ptr.Op != OpSB && idx.Op != OpSB
+	// result: (MOVDaddridx [c] {s} ptr idx)
+	for {
+		_ = v.Args[1]
+		idx := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDaddr {
 			break
 		}
 		c := v_1.AuxInt
 		s := v_1.Aux
-		y := v_1.Args[0]
-		if !(x.Op != OpSB && y.Op != OpSB) {
+		ptr := v_1.Args[0]
+		if !(ptr.Op != OpSB && idx.Op != OpSB) {
 			break
 		}
 		v.reset(OpS390XMOVDaddridx)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(x)
-		v.AddArg(y)
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		return true
 	}
-	// match: (ADD (MOVDaddr [c] {s} x) y)
-	// cond: x.Op != OpSB && y.Op != OpSB
-	// result: (MOVDaddridx [c] {s} x y)
+	// match: (ADD (MOVDaddr [c] {s} ptr) idx)
+	// cond: ptr.Op != OpSB && idx.Op != OpSB
+	// result: (MOVDaddridx [c] {s} ptr idx)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			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) {
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		if !(ptr.Op != OpSB && idx.Op != OpSB) {
 			break
 		}
 		v.reset(OpS390XMOVDaddridx)
 		v.AuxInt = c
 		v.Aux = s
-		v.AddArg(x)
-		v.AddArg(y)
+		v.AddArg(ptr)
+		v.AddArg(idx)
 		return true
 	}
 	// match: (ADD x (NEG y))
 	// cond:
 	// result: (SUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XNEG {
@@ -5845,11 +6050,28 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADD (NEG y) x)
+	// cond:
+	// result: (SUB x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XNEG {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpS390XSUB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADD <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVDload {
@@ -5857,9 +6079,10 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDload)
@@ -5872,20 +6095,22 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ADD <t> g:(MOVDload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVDload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDload)
@@ -5899,13 +6124,71 @@ func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XADD_10(v *Value) bool {
+	// match: (ADD <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADD <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XADDW_0(v *Value) bool {
 	// match: (ADDW x (MOVDconst [c]))
 	// cond:
 	// result: (ADDWconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -5921,6 +6204,7 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 	// cond:
 	// result: (ADDWconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -5932,10 +6216,65 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (ADDW (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSLWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRWconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpS390XRLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDW (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSLWconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpS390XRLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
 	// match: (ADDW x (NEGW y))
 	// cond:
 	// result: (SUBW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XNEGW {
@@ -5947,11 +6286,28 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
+	// match: (ADDW (NEGW y) x)
+	// cond:
+	// result: (SUBW x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XNEGW {
+			break
+		}
+		y := v_0.Args[0]
+		x := v.Args[1]
+		v.reset(OpS390XSUBW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
 	// match: (ADDW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVWload {
@@ -5959,9 +6315,38 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDWload)
@@ -5974,20 +6359,50 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVWload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDWload)
@@ -5999,11 +6414,15 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	return false
+}
+func rewriteValueS390X_OpS390XADDW_10(v *Value) bool {
 	// match: (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVWZload {
@@ -6011,9 +6430,38 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDWload)
@@ -6026,20 +6474,50 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ADDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XADDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ADDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XADDWload)
@@ -6053,9 +6531,7 @@ func rewriteValueS390X_OpS390XADDW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XADDWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XADDWconst_0(v *Value) bool {
 	// match: (ADDWconst [c] x)
 	// cond: int32(c)==0
 	// result: x
@@ -6102,9 +6578,7 @@ func rewriteValueS390X_OpS390XADDWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XADDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XADDconst_0(v *Value) bool {
 	// match: (ADDconst [c] (MOVDaddr [d] {s} x:(SB)))
 	// cond: ((c+d)&1 == 0) && is32Bit(c+d)
 	// result: (MOVDaddr [c+d] {s} x)
@@ -6161,6 +6635,7 @@ func rewriteValueS390X_OpS390XADDconst(v *Value, config *Config) bool {
 		}
 		d := v_0.AuxInt
 		s := v_0.Aux
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if !(is20Bit(c + d)) {
@@ -6221,13 +6696,12 @@ func rewriteValueS390X_OpS390XADDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XAND_0(v *Value) bool {
 	// match: (AND x (MOVDconst [c]))
 	// cond: is32Bit(c) && c < 0
 	// result: (ANDconst [c] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -6246,6 +6720,7 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 	// cond: is32Bit(c) && c < 0
 	// result: (ANDconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6260,10 +6735,28 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	// match: (AND x (MOVDconst [0xFF]))
+	// cond:
+	// result: (MOVBZreg x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		if v_1.AuxInt != 0xFF {
+			break
+		}
+		v.reset(OpS390XMOVBZreg)
+		v.AddArg(x)
+		return true
+	}
 	// match: (AND (MOVDconst [0xFF]) x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6276,19 +6769,20 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVDconst [0xFF]))
+	// match: (AND x (MOVDconst [0xFFFF]))
 	// cond:
-	// result: (MOVBZreg x)
+	// result: (MOVHZreg x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		if v_1.AuxInt != 0xFF {
+		if v_1.AuxInt != 0xFFFF {
 			break
 		}
-		v.reset(OpS390XMOVBZreg)
+		v.reset(OpS390XMOVHZreg)
 		v.AddArg(x)
 		return true
 	}
@@ -6296,6 +6790,7 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVHZreg x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6308,19 +6803,20 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVDconst [0xFFFF]))
+	// match: (AND x (MOVDconst [0xFFFFFFFF]))
 	// cond:
-	// result: (MOVHZreg x)
+	// result: (MOVWZreg x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		if v_1.AuxInt != 0xFFFF {
+		if v_1.AuxInt != 0xFFFFFFFF {
 			break
 		}
-		v.reset(OpS390XMOVHZreg)
+		v.reset(OpS390XMOVWZreg)
 		v.AddArg(x)
 		return true
 	}
@@ -6328,6 +6824,7 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 	// cond:
 	// result: (MOVWZreg x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6340,44 +6837,52 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (AND x (MOVDconst [0xFFFFFFFF]))
+	// match: (AND (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
-	// result: (MOVWZreg x)
+	// result: (MOVDconst [c&d])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		if v_1.AuxInt != 0xFFFFFFFF {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		v.reset(OpS390XMOVWZreg)
-		v.AddArg(x)
+		d := v_1.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c & d
 		return true
 	}
-	// match: (AND (MOVDconst [c]) (MOVDconst [d]))
+	// match: (AND (MOVDconst [d]) (MOVDconst [c]))
 	// cond:
 	// result: (MOVDconst [c&d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		d := v_1.AuxInt
+		c := v_1.AuxInt
 		v.reset(OpS390XMOVDconst)
 		v.AuxInt = c & d
 		return true
 	}
+	return false
+}
+func rewriteValueS390X_OpS390XAND_10(v *Value) bool {
 	// match: (AND x x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6388,10 +6893,11 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (AND <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVDload {
@@ -6399,9 +6905,10 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDload)
@@ -6414,20 +6921,22 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (AND <t> g:(MOVDload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVDload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDload)
@@ -6439,35 +6948,91 @@ func rewriteValueS390X_OpS390XAND(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ANDW x (MOVDconst [c]))
-	// cond:
-	// result: (ANDWconst [c] x)
+	// match: (AND <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDload <t> [off] {sym} x ptr mem)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpS390XANDWconst)
-		v.AuxInt = c
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (ANDW (MOVDconst [c]) x)
-	// cond:
-	// result: (ANDWconst [c] x)
+	// match: (AND <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDload <t> [off] {sym} x ptr mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
 			break
 		}
-		c := v_0.AuxInt
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XANDW_0(v *Value) bool {
+	// match: (ANDW x (MOVDconst [c]))
+	// cond:
+	// result: (ANDWconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpS390XANDWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDW (MOVDconst [c]) x)
+	// cond:
+	// result: (ANDWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpS390XANDWconst)
 		v.AuxInt = c
@@ -6478,6 +7043,7 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -6488,10 +7054,11 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ANDW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVWload {
@@ -6499,9 +7066,38 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDWload)
@@ -6514,20 +7110,50 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVWload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ANDW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDWload)
@@ -6540,10 +7166,11 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
 		if g.Op != OpS390XMOVWZload {
@@ -6551,9 +7178,38 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDWload)
@@ -6566,20 +7222,22 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (ANDWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
 		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XANDWload)
@@ -6593,9 +7251,38 @@ func rewriteValueS390X_OpS390XANDW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XANDWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XANDW_10(v *Value) bool {
+	// match: (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ANDWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XANDWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XANDWconst_0(v *Value) bool {
 	// match: (ANDWconst [c] (ANDWconst [d] x))
 	// cond:
 	// result: (ANDWconst [c & d] x)
@@ -6678,9 +7365,7 @@ func rewriteValueS390X_OpS390XANDWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XANDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XANDconst_0(v *Value) bool {
 	// match: (ANDconst [c] (ANDconst [d] x))
 	// cond:
 	// result: (ANDconst [c & d] x)
@@ -6737,13 +7422,14 @@ func rewriteValueS390X_OpS390XANDconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMP(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XCMP_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMP x (MOVDconst [c]))
 	// cond: is32Bit(c)
 	// result: (CMPconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -6762,6 +7448,7 @@ func rewriteValueS390X_OpS390XCMP(v *Value, config *Config) bool {
 	// cond: is32Bit(c)
 	// result: (InvertFlags (CMPconst x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6772,7 +7459,7 @@ func rewriteValueS390X_OpS390XCMP(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpS390XInvertFlags)
-		v0 := b.NewValue0(v.Line, OpS390XCMPconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpS390XCMPconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -6780,13 +7467,14 @@ func rewriteValueS390X_OpS390XCMP(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XCMPU_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPU x (MOVDconst [c]))
 	// cond: isU32Bit(c)
 	// result: (CMPUconst x [int64(uint32(c))])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -6805,6 +7493,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
 	// cond: isU32Bit(c)
 	// result: (InvertFlags (CMPUconst x [int64(uint32(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6815,7 +7504,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpS390XInvertFlags)
-		v0 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpS390XCMPUconst, types.TypeFlags)
 		v0.AuxInt = int64(uint32(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -6823,9 +7512,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XCMPUconst_0(v *Value) bool {
 	// match: (CMPUconst (MOVDconst [x]) [y])
 	// cond: uint64(x)==uint64(y)
 	// result: (FlagEQ)
@@ -6876,13 +7563,14 @@ func rewriteValueS390X_OpS390XCMPUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPW(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XCMPW_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPW x (MOVDconst [c]))
 	// cond:
 	// result: (CMPWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -6898,6 +7586,7 @@ func rewriteValueS390X_OpS390XCMPW(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPWconst x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6905,7 +7594,7 @@ func rewriteValueS390X_OpS390XCMPW(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpS390XInvertFlags)
-		v0 := b.NewValue0(v.Line, OpS390XCMPWconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpS390XCMPWconst, types.TypeFlags)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -6913,13 +7602,14 @@ func rewriteValueS390X_OpS390XCMPW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPWU(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XCMPWU_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (CMPWU x (MOVDconst [c]))
 	// cond:
 	// result: (CMPWUconst x [int64(uint32(c))])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -6935,6 +7625,7 @@ func rewriteValueS390X_OpS390XCMPWU(v *Value, config *Config) bool {
 	// cond:
 	// result: (InvertFlags (CMPWUconst x [int64(uint32(c))]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
@@ -6942,7 +7633,7 @@ func rewriteValueS390X_OpS390XCMPWU(v *Value, config *Config) bool {
 		c := v_0.AuxInt
 		x := v.Args[1]
 		v.reset(OpS390XInvertFlags)
-		v0 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+		v0 := b.NewValue0(v.Pos, OpS390XCMPWUconst, types.TypeFlags)
 		v0.AuxInt = int64(uint32(c))
 		v0.AddArg(x)
 		v.AddArg(v0)
@@ -6950,9 +7641,7 @@ func rewriteValueS390X_OpS390XCMPWU(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPWUconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XCMPWUconst_0(v *Value) bool {
 	// match: (CMPWUconst (MOVDconst [x]) [y])
 	// cond: uint32(x)==uint32(y)
 	// result: (FlagEQ)
@@ -7003,9 +7692,7 @@ func rewriteValueS390X_OpS390XCMPWUconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XCMPWconst_0(v *Value) bool {
 	// match: (CMPWconst (MOVDconst [x]) [y])
 	// cond: int32(x)==int32(y)
 	// result: (FlagEQ)
@@ -7088,9 +7775,7 @@ func rewriteValueS390X_OpS390XCMPWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XCMPconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XCMPconst_0(v *Value) bool {
 	// match: (CMPconst (MOVDconst [x]) [y])
 	// cond: x==y
 	// result: (FlagEQ)
@@ -7218,15 +7903,96 @@ func rewriteValueS390X_OpS390XCMPconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (FMOVDload  [off1] {sym} (ADDconst [off2] ptr) mem)
+func rewriteValueS390X_OpS390XFADD_0(v *Value) bool {
+	// match: (FADD (FMUL y z) x)
+	// cond:
+	// result: (FMADD x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFMUL {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		v.reset(OpS390XFMADD)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	// match: (FADD x (FMUL y z))
+	// cond:
+	// result: (FMADD x y z)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XFMUL {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		v.reset(OpS390XFMADD)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XFADDS_0(v *Value) bool {
+	// match: (FADDS (FMULS y z) x)
+	// cond:
+	// result: (FMADDS x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFMULS {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		v.reset(OpS390XFMADDS)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	// match: (FADDS x (FMULS y z))
+	// cond:
+	// result: (FMADDS x y z)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XFMULS {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		z := v_1.Args[1]
+		v.reset(OpS390XFMADDS)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XFMOVDload_0(v *Value) bool {
+	// match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond: is20Bit(off1+off2)
 	// result: (FMOVDload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7250,6 +8016,7 @@ func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -7274,12 +8041,14 @@ func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7300,10 +8069,12 @@ func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7320,15 +8091,14 @@ func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVDloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVDloadidx_0(v *Value) bool {
 	// match: (FMOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
 	// cond:
 	// result: (FMOVDloadidx [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7351,6 +8121,7 @@ func rewriteValueS390X_OpS390XFMOVDloadidx(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -7369,15 +8140,14 @@ func rewriteValueS390X_OpS390XFMOVDloadidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVDstore_0(v *Value) bool {
 	// match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond: is20Bit(off1+off2)
 	// result: (FMOVDstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7403,6 +8173,7 @@ func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -7429,12 +8200,14 @@ func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -7457,10 +8230,12 @@ func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -7479,15 +8254,14 @@ func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVDstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVDstoreidx_0(v *Value) bool {
 	// match: (FMOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
 	// cond:
 	// result: (FMOVDstoreidx [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7512,6 +8286,7 @@ func rewriteValueS390X_OpS390XFMOVDstoreidx(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -7532,15 +8307,14 @@ func rewriteValueS390X_OpS390XFMOVDstoreidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVSload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (FMOVSload  [off1] {sym} (ADDconst [off2] ptr) mem)
+func rewriteValueS390X_OpS390XFMOVSload_0(v *Value) bool {
+	// match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond: is20Bit(off1+off2)
 	// result: (FMOVSload [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7564,6 +8338,7 @@ func rewriteValueS390X_OpS390XFMOVSload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -7588,12 +8363,14 @@ func rewriteValueS390X_OpS390XFMOVSload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7614,10 +8391,12 @@ func rewriteValueS390X_OpS390XFMOVSload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7634,15 +8413,14 @@ func rewriteValueS390X_OpS390XFMOVSload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVSloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVSloadidx_0(v *Value) bool {
 	// match: (FMOVSloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
 	// cond:
 	// result: (FMOVSloadidx [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7665,6 +8443,7 @@ func rewriteValueS390X_OpS390XFMOVSloadidx(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -7683,15 +8462,14 @@ func rewriteValueS390X_OpS390XFMOVSloadidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVSstore_0(v *Value) bool {
 	// match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond: is20Bit(off1+off2)
 	// result: (FMOVSstore [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7717,6 +8495,7 @@ func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -7743,12 +8522,14 @@ func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -7771,10 +8552,12 @@ func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -7793,15 +8576,14 @@ func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XFMOVSstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XFMOVSstoreidx_0(v *Value) bool {
 	// match: (FMOVSstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
 	// cond:
 	// result: (FMOVSstoreidx [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7826,6 +8608,7 @@ func rewriteValueS390X_OpS390XFMOVSstoreidx(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -7846,43 +8629,120 @@ func rewriteValueS390X_OpS390XFMOVSstoreidx(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: (MOVDreg x)
+func rewriteValueS390X_OpS390XFSUB_0(v *Value) bool {
+	// match: (FSUB (FMUL y z) x)
+	// cond:
+	// result: (FMSUB x y z)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVBstore {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFMUL {
 			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)) {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		v.reset(OpS390XFMSUB)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XFSUBS_0(v *Value) bool {
+	// match: (FSUBS (FMULS y z) x)
+	// cond:
+	// result: (FMSUBS x y z)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFMULS {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		z := v_0.Args[1]
+		x := v.Args[1]
+		v.reset(OpS390XFMSUBS)
 		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(z)
 		return true
 	}
-	// match: (MOVBZload  [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVBZload [off1+off2] {sym} ptr mem)
+	return false
+}
+func rewriteValueS390X_OpS390XLoweredRound32F_0(v *Value) bool {
+	// match: (LoweredRound32F x:(FMOVSconst))
+	// cond:
+	// result: x
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		x := v.Args[0]
+		if x.Op != OpS390XFMOVSconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XLoweredRound64F_0(v *Value) bool {
+	// match: (LoweredRound64F x:(FMOVDconst))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XFMOVDconst {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBZload_0(v *Value) bool {
+	// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVBZreg x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVBstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpS390XMOVBZreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVBZload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVBZload [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
 		mem := v.Args[1]
 		if !(is20Bit(off1 + off2)) {
 			break
@@ -7894,12 +8754,13 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+	// match: (MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
 	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
 	// result: (MOVBZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -7924,12 +8785,14 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7950,10 +8813,12 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		mem := v.Args[1]
@@ -7970,15 +8835,14 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBZloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XMOVBZloadidx_0(v *Value) bool {
 	// match: (MOVBZloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
 	// cond:
 	// result: (MOVBZloadidx [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -7995,12 +8859,36 @@ func rewriteValueS390X_OpS390XMOVBZloadidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBZloadidx [c] {sym} idx (ADDconst [d] ptr) mem)
+	// cond:
+	// result: (MOVBZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVBZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBZloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
 	// cond:
 	// result: (MOVBZloadidx [c+d] {sym} ptr idx mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -8017,11 +8905,32 @@ func rewriteValueS390X_OpS390XMOVBZloadidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBZloadidx [c] {sym} (ADDconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVBZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVBZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XMOVBZreg_0(v *Value) bool {
 	// match: (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _))
 	// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
 	// result: (MOVDreg x)
@@ -8030,6 +8939,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDLT {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8055,6 +8965,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDLE {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8080,6 +8991,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDGT {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8105,6 +9017,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDGE {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8130,6 +9043,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDEQ {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8155,6 +9069,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDNE {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8180,6 +9095,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDGTnoinv {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8205,6 +9121,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVDGEnoinv {
 			break
 		}
+		_ = x.Args[2]
 		x_0 := x.Args[0]
 		if x_0.Op != OpS390XMOVDconst {
 			break
@@ -8230,6 +9147,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVBZload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpS390XMOVDreg)
 		v.AddArg(x)
 		return true
@@ -8250,6 +9168,11 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBZreg_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (MOVBZreg x:(MOVBZreg _))
 	// cond:
 	// result: (MOVDreg x)
@@ -8285,13 +9208,14 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZload, v.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -8310,6 +9234,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[2]
 		ptr := x.Args[0]
 		idx := x.Args[1]
 		mem := x.Args[2]
@@ -8317,7 +9242,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVBZloadidx, v.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZloadidx, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -8329,15 +9254,14 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVBload   [off1] {sym} (ADDconst [off2] ptr) mem)
+func rewriteValueS390X_OpS390XMOVBload_0(v *Value) bool {
+	// match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
 	// cond: is20Bit(off1+off2)
 	// result: (MOVBload  [off1+off2] {sym} ptr mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -8361,6 +9285,7 @@ func rewriteValueS390X_OpS390XMOVBload(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -8381,7 +9306,7 @@ func rewriteValueS390X_OpS390XMOVBload(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XMOVBreg_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (MOVBreg x:(MOVBload _ _))
@@ -8392,6 +9317,7 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
 		if x.Op != OpS390XMOVBload {
 			break
 		}
+		_ = x.Args[1]
 		v.reset(OpS390XMOVDreg)
 		v.AddArg(x)
 		return true
@@ -8447,13 +9373,14 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
 		}
 		off := x.AuxInt
 		sym := x.Aux
+		_ = x.Args[1]
 		ptr := x.Args[0]
 		mem := x.Args[1]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
 		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVBload, v.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBload, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
 		v0.AuxInt = off
@@ -8464,15 +9391,14 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XMOVBstore_0(v *Value) bool {
 	// match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
 	// cond:
 	// result: (MOVBstore [off] {sym} ptr x mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVBreg {
@@ -8494,6 +9420,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVBZreg {
@@ -8509,12 +9436,13 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym} (ADDconst [off2] ptr) val mem)
+	// match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem)
 	// cond: is20Bit(off1+off2)
 	// result: (MOVBstore  [off1+off2] {sym} ptr val mem)
 	for {
 		off1 := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -8535,11 +9463,12 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem)
-	// cond: validOff(off) && ptr.Op != OpSB
+	// cond: is20Bit(off) && ptr.Op != OpSB
 	// result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -8547,7 +9476,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		}
 		c := v_1.AuxInt
 		mem := v.Args[2]
-		if !(validOff(off) && ptr.Op != OpSB) {
+		if !(is20Bit(off) && ptr.Op != OpSB) {
 			break
 		}
 		v.reset(OpS390XMOVBstoreconst)
@@ -8557,12 +9486,13 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
+	// match: (MOVBstore [off1] {sym1} (MOVDaddr [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.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -8589,12 +9519,14 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		off1 := v.AuxInt
 		sym1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddridx {
 			break
 		}
 		off2 := v_0.AuxInt
 		sym2 := v_0.Aux
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -8617,10 +9549,12 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		off := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADD {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		idx := v_0.Args[1]
 		val := v.Args[1]
@@ -8643,6 +9577,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w := v.Args[1]
 		x := v.Args[2]
@@ -8655,6 +9590,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8686,6 +9622,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w0 := v.Args[1]
 		if w0.Op != OpS390XSRDconst {
@@ -8703,6 +9640,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8734,6 +9672,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w := v.Args[1]
 		x := v.Args[2]
@@ -8746,6 +9685,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8771,12 +9711,16 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBstore_10(v *Value) bool {
 	// match: (MOVBstore [i] {s} p w0:(SRWconst [j] w) x:(MOVBstore [i-1] {s} p (SRWconst [j+8] w) mem))
 	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
 	// result: (MOVHstore [i-1] {s} p w0 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		w0 := v.Args[1]
 		if w0.Op != OpS390XSRWconst {
@@ -8794,6 +9738,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8825,6 +9770,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XSRDconst {
@@ -8844,6 +9790,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8868,6 +9815,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XSRDconst {
@@ -8885,6 +9833,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8916,6 +9865,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XSRWconst {
@@ -8935,6 +9885,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -8959,6 +9910,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[2]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XSRWconst {
@@ -8976,6 +9928,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[2]
 		if p != x.Args[0] {
 			break
 		}
@@ -9003,15 +9956,14 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XMOVBstoreconst_0(v *Value) bool {
 	// match: (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
+	// cond: is20Bit(ValAndOff(sc).Off()+off)
 	// result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
 	for {
 		sc := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -9019,7 +9971,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 		off := v_0.AuxInt
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		if !(is20Bit(ValAndOff(sc).Off() + off)) {
 			break
 		}
 		v.reset(OpS390XMOVBstoreconst)
@@ -9030,11 +9982,12 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// cond: ptr.Op != OpSB && 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.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDaddr {
 			break
@@ -9043,7 +9996,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 		sym2 := v_0.Aux
 		ptr := v_0.Args[0]
 		mem := v.Args[1]
-		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+		if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
 			break
 		}
 		v.reset(OpS390XMOVBstoreconst)
@@ -9059,6 +10012,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 	for {
 		c := v.AuxInt
 		s := v.Aux
+		_ = v.Args[1]
 		p := v.Args[0]
 		x := v.Args[1]
 		if x.Op != OpS390XMOVBstoreconst {
@@ -9068,6 +10022,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[1]
 		if p != x.Args[0] {
 			break
 		}
@@ -9084,15 +10039,14 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XMOVBstoreidx_0(v *Value) bool {
 	// match: (MOVBstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
 	// cond:
 	// result: (MOVBstoreidx [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XADDconst {
 			break
@@ -9111,12 +10065,38 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBstoreidx [c] {sym} idx (ADDconst [d] ptr) val mem)
+	// cond:
+	// result: (MOVBstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVBstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
 	// cond:
 	// result: (MOVBstoreidx [c+d] {sym} ptr idx val mem)
 	for {
 		c := v.AuxInt
 		sym := v.Aux
+		_ = v.Args[3]
 		ptr := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XADDconst {
@@ -9135,12 +10115,38 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
+	// match: (MOVBstoreidx [c] {sym} (ADDconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVBstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVBstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
 	// match: (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
 	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
 		w := v.Args[2]
@@ -9154,6 +10160,7 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
@@ -9183,20 +10190,16 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem))
+	// match: (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} idx p (SRDconst [8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
-		w0 := v.Args[2]
-		if w0.Op != OpS390XSRDconst {
-			break
-		}
-		j := w0.AuxInt
-		w := w0.Args[0]
+		w := v.Args[2]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9207,17 +10210,18 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x.Args[3]
+		if idx != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
+		if p != x.Args[1] {
 			break
 		}
 		x_2 := x.Args[2]
 		if x_2.Op != OpS390XSRDconst {
 			break
 		}
-		if x_2.AuxInt != j+8 {
+		if x_2.AuxInt != 8 {
 			break
 		}
 		if w != x_2.Args[0] {
@@ -9232,18 +10236,19 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w0)
+		v.AddArg(w)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem))
+	// match: (MOVBstoreidx [i] {s} idx p w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
 	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
 		w := v.Args[2]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
@@ -9255,6 +10260,7 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
@@ -9262,7 +10268,7 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 			break
 		}
 		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRWconst {
+		if x_2.Op != OpS390XSRDconst {
 			break
 		}
 		if x_2.AuxInt != 8 {
@@ -9284,20 +10290,16 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem))
+	// match: (MOVBstoreidx [i] {s} idx p w x:(MOVBstoreidx [i-1] {s} idx p (SRDconst [8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w0 := v.Args[2]
-		if w0.Op != OpS390XSRWconst {
-			break
-		}
-		j := w0.AuxInt
-		w := w0.Args[0]
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9308,17 +10310,18 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x.Args[3]
+		if idx != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
+		if p != x.Args[1] {
 			break
 		}
 		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRWconst {
+		if x_2.Op != OpS390XSRDconst {
 			break
 		}
-		if x_2.AuxInt != j+8 {
+		if x_2.AuxInt != 8 {
 			break
 		}
 		if w != x_2.Args[0] {
@@ -9333,26 +10336,25 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w0)
+		v.AddArg(w)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	// match: (MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XSRDconst {
-			break
-		}
-		if v_2.AuxInt != 8 {
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
 			break
 		}
-		w := v_2.Args[0]
+		j := w0.AuxInt
+		w := w0.Args[0]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9363,42 +10365,51 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
 		if idx != x.Args[1] {
 			break
 		}
-		if w != x.Args[2] {
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
 			break
 		}
 		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpS390XMOVHBRstoreidx)
+		v.reset(OpS390XMOVHstoreidx)
 		v.AuxInt = i - 1
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem))
+	// match: (MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p (SRDconst [j+8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XSRDconst {
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
+		j := w0.AuxInt
+		w := w0.Args[0]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9409,27 +10420,28 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x.Args[3]
+		if idx != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
+		if p != x.Args[1] {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpS390XSRDconst {
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
 			break
 		}
-		if w0.AuxInt != j-8 {
+		if x_2.AuxInt != j+8 {
 			break
 		}
-		if w != w0.Args[0] {
+		if w != x_2.Args[0] {
 			break
 		}
 		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpS390XMOVHBRstoreidx)
+		v.reset(OpS390XMOVHstoreidx)
 		v.AuxInt = i - 1
 		v.Aux = s
 		v.AddArg(p)
@@ -9438,22 +10450,24 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBstoreidx_10(v *Value) bool {
+	// match: (MOVBstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	// result: (MOVHstoreidx [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 != OpS390XSRWconst {
-			break
-		}
-		if v_2.AuxInt != 8 {
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
 			break
 		}
-		w := v_2.Args[0]
+		j := w0.AuxInt
+		w := w0.Args[0]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9464,42 +10478,51 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
 		if idx != x.Args[1] {
 			break
 		}
-		if w != x.Args[2] {
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
 			break
 		}
 		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpS390XMOVHBRstoreidx)
+		v.reset(OpS390XMOVHstoreidx)
 		v.AuxInt = i - 1
 		v.Aux = s
 		v.AddArg(p)
 		v.AddArg(idx)
-		v.AddArg(w)
+		v.AddArg(w0)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem))
+	// match: (MOVBstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p (SRDconst [j+8] w) mem))
 	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	// result: (MOVHstoreidx [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 != OpS390XSRWconst {
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
+		j := w0.AuxInt
+		w := w0.Args[0]
 		x := v.Args[3]
 		if x.Op != OpS390XMOVBstoreidx {
 			break
@@ -9510,27 +10533,28 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x.Args[3]
+		if idx != x.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
+		if p != x.Args[1] {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpS390XSRWconst {
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
 			break
 		}
-		if w0.AuxInt != j-8 {
+		if x_2.AuxInt != j+8 {
 			break
 		}
-		if w != w0.Args[0] {
+		if w != x_2.Args[0] {
 			break
 		}
 		mem := x.Args[3]
 		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		v.reset(OpS390XMOVHBRstoreidx)
+		v.reset(OpS390XMOVHstoreidx)
 		v.AuxInt = i - 1
 		v.Aux = s
 		v.AddArg(p)
@@ -9539,5939 +10563,23231 @@ func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDEQ(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDEQ x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDEQ x y cmp)
+	// match: (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDEQ)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
-		return true
-	}
-	// match: (MOVDEQ _ x (FlagEQ))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		if x.AuxInt != i-1 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDEQ y _ (FlagLT))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		if x.Aux != s {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDEQ y _ (FlagGT))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		_ = x.Args[3]
+		if p != x.Args[0] {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDGE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDGE x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDLE x y cmp)
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		if idx != x.Args[1] {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDLE)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
-		return true
-	}
-	// match: (MOVDGE _ x (FlagEQ))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDGE y _ (FlagLT))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		if x_2.AuxInt != 8 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDGE _ x (FlagGT))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		if w != x_2.Args[0] {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDGT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDGT x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDLT x y cmp)
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDLT)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVDGT y _ (FlagEQ))
-	// cond:
-	// result: y
+	// match: (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} idx p (SRWconst [8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
 	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDGT y _ (FlagLT))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		if x.AuxInt != i-1 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDGT _ x (FlagGT))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		if x.Aux != s {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDLE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDLE x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDGE x y cmp)
-	for {
-		x := v.Args[0]
-		y := v.Args[1]
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p w x:(MOVBstoreidx [i-1] {s} idx p (SRWconst [8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p (SRWconst [j+8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p (SRWconst [j+8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+8 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBstoreidx_20(v *Value) bool {
+	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p w0:(SRDconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p w0:(SRDconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVBstoreidx_30(v *Value) bool {
+	// match: (MOVBstoreidx [i] {s} idx p (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p w0:(SRWconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx [i] {s} idx p (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} idx p w0:(SRWconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVBstoreidx {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVHBRstoreidx)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDEQ_0(v *Value) bool {
+	// match: (MOVDEQ x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDEQ x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDEQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDEQ _ x (FlagEQ))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDEQ y _ (FlagLT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDEQ y _ (FlagGT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDGE_0(v *Value) bool {
+	// match: (MOVDGE x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDLE x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDLE)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDGE _ x (FlagEQ))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDGE y _ (FlagLT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDGE _ x (FlagGT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDGT_0(v *Value) bool {
+	// match: (MOVDGT x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDLT x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDLT)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDGT y _ (FlagEQ))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDGT y _ (FlagLT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDGT _ x (FlagGT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDLE_0(v *Value) bool {
+	// match: (MOVDLE x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDGE x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDGE)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDLE _ x (FlagEQ))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDLE _ x (FlagLT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDLE y _ (FlagGT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDLT_0(v *Value) bool {
+	// match: (MOVDLT x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDGT x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDGT)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDLT y _ (FlagEQ))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDLT _ x (FlagLT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDLT y _ (FlagGT))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDNE_0(v *Value) bool {
+	// match: (MOVDNE x y (InvertFlags cmp))
+	// cond:
+	// result: (MOVDNE x y cmp)
+	for {
+		_ = v.Args[2]
+		x := v.Args[0]
+		y := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XInvertFlags {
+			break
+		}
+		cmp := v_2.Args[0]
+		v.reset(OpS390XMOVDNE)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AddArg(cmp)
+		return true
+	}
+	// match: (MOVDNE y _ (FlagEQ))
+	// cond:
+	// result: y
+	for {
+		_ = v.Args[2]
+		y := v.Args[0]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDNE _ x (FlagLT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDNE _ x (FlagGT))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[2]
+		x := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDaddridx_0(v *Value) bool {
+	// match: (MOVDaddridx [c] {s} (ADDconst [d] x) y)
+	// cond: is20Bit(c+d) && x.Op != OpSB
+	// result: (MOVDaddridx [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is20Bit(c+d) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVDaddridx)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDaddridx [c] {s} x (ADDconst [d] y))
+	// cond: is20Bit(c+d) && y.Op != OpSB
+	// result: (MOVDaddridx [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(is20Bit(c+d) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVDaddridx)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+	// result: (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVDaddridx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+	// result: (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVDaddridx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDload_0(v *Value) bool {
+	// match: (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVDreg x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVDload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVDload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVDload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVDload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDload [off] {sym} (ADD ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVDloadidx [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDloadidx_0(v *Value) bool {
+	// match: (MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVDloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDloadidx [c] {sym} idx (ADDconst [d] ptr) mem)
+	// cond:
+	// result: (MOVDloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
+	// cond:
+	// result: (MOVDloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDloadidx [c] {sym} (ADDconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVDloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVDloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDnop_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVDnop <t> x)
+	// cond: t.Compare(x.Type) == types.CMPeq
+	// result: x
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if !(t.Compare(x.Type) == types.CMPeq) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDnop (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVBZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVBload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVHZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVHload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVWZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVDload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVDload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVDload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVBZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVBZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDnop_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVDnop <t> x:(MOVHZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVHZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVWZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVWZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDnop <t> x:(MOVDloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVDloadidx  <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVDloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVDloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDreg_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVDreg <t> x)
+	// cond: t.Compare(x.Type) == types.CMPeq
+	// result: x
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if !(t.Compare(x.Type) == types.CMPeq) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDreg (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c
+		return true
+	}
+	// match: (MOVDreg x)
+	// cond: x.Uses == 1
+	// result: (MOVDnop x)
+	for {
+		x := v.Args[0]
+		if !(x.Uses == 1) {
+			break
+		}
+		v.reset(OpS390XMOVDnop)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVBZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVBload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVBload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVHZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVHload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVWZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZload <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVDload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVDload  <t> [off] {sym} ptr mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVDload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDreg_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVDreg <t> x:(MOVBZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVBZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVHZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVHZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVWZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVWZloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVDreg <t> x:(MOVDloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVDloadidx  <t> [off] {sym} ptr idx mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		if x.Op != OpS390XMOVDloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVDloadidx, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDstore_0(v *Value) bool {
+	// match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVDstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVDstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem)
+	// cond: is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB
+	// result: (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreconst)
+		v.AuxInt = makeValAndOff(c, off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVDstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVDstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(OpS390XMOVDstoreidx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [off] {sym} (ADD ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVDstoreidx [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		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(OpS390XMOVDstoreidx)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && is20Bit(i-8)   && clobber(x)
+	// result: (STMG2 [i-8] {s} p w0 w1 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w1 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVDstore {
+			break
+		}
+		if x.AuxInt != i-8 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && is20Bit(i-8) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTMG2)
+		v.AuxInt = i - 8
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem))
+	// cond: x.Uses == 1   && is20Bit(i-16)   && clobber(x)
+	// result: (STMG3 [i-16] {s} p w0 w1 w2 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w2 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XSTMG2 {
+			break
+		}
+		if x.AuxInt != i-16 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		w1 := x.Args[2]
+		mem := x.Args[3]
+		if !(x.Uses == 1 && is20Bit(i-16) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTMG3)
+		v.AuxInt = i - 16
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(w2)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem))
+	// cond: x.Uses == 1   && is20Bit(i-24)   && clobber(x)
+	// result: (STMG4 [i-24] {s} p w0 w1 w2 w3 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w3 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XSTMG3 {
+			break
+		}
+		if x.AuxInt != i-24 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[4]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		w1 := x.Args[2]
+		w2 := x.Args[3]
+		mem := x.Args[4]
+		if !(x.Uses == 1 && is20Bit(i-24) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTMG4)
+		v.AuxInt = i - 24
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(w2)
+		v.AddArg(w3)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDstoreconst_0(v *Value) bool {
+	// match: (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem)
+	// cond: isU12Bit(ValAndOff(sc).Off()+off)
+	// result: (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(isU12Bit(ValAndOff(sc).Off() + off)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
+	// cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVDstoreidx_0(v *Value) bool {
+	// match: (MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstoreidx [c] {sym} idx (ADDconst [d] ptr) val mem)
+	// cond:
+	// result: (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
+	// cond:
+	// result: (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVDstoreidx [c] {sym} (ADDconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHBRstore_0(v *Value) bool {
+	// match: (MOVHBRstore [i] {s} p (SRDconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstore [i-2] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		if v_1.AuxInt != 16 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHBRstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		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(OpS390XMOVWBRstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstore [i] {s} p (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstore [i-2] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHBRstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVWBRstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstore [i-2] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRWconst {
+			break
+		}
+		if v_1.AuxInt != 16 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHBRstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		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(OpS390XMOVWBRstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstore [i-2] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHBRstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVWBRstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHBRstoreidx_0(v *Value) bool {
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} idx p w0:(SRDconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} idx p w0:(SRDconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHBRstoreidx_10(v *Value) bool {
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} idx p w0:(SRWconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHBRstoreidx [i] {s} idx p (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} idx p w0:(SRWconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRWconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			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(OpS390XMOVWBRstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHZload_0(v *Value) bool {
+	// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVHZreg x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVHstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpS390XMOVHZreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVHZload [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVHZload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVHZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVHZload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZload [off] {sym} (ADD ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVHZloadidx [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHZloadidx_0(v *Value) bool {
+	// match: (MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZloadidx [c] {sym} idx (ADDconst [d] ptr) mem)
+	// cond:
+	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
+	// cond:
+	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZloadidx [c] {sym} (ADDconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHZreg_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVHZreg x:(MOVBZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZreg x:(MOVHZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZreg x:(Arg <t>))
+	// cond: (is8BitInt(t) || is16BitInt(t)) && !isSigned(t)
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpArg {
+			break
+		}
+		t := x.Type
+		if !((is8BitInt(t) || is16BitInt(t)) && !isSigned(t)) {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZreg x:(MOVBZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZreg x:(MOVHZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHZreg (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [int64(uint16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(uint16(c))
+		return true
+	}
+	// match: (MOVHZreg x:(MOVHZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVHZloadidx, 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
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHload_0(v *Value) bool {
+	// match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVHload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVHload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVHload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHreg_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVHreg x:(MOVBload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(MOVBZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(MOVHload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(Arg <t>))
+	// cond: (is8BitInt(t) || is16BitInt(t)) && isSigned(t)
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpArg {
+			break
+		}
+		t := x.Type
+		if !((is8BitInt(t) || is16BitInt(t)) && isSigned(t)) {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(MOVBreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(MOVBZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg x:(MOVHreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVHreg (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [int64(int16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(int16(c))
+		return true
+	}
+	// match: (MOVHreg x:(MOVHZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVHload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHstore_0(v *Value) bool {
+	// match: (MOVHstore [off] {sym} ptr (MOVHreg x) mem)
+	// cond:
+	// result: (MOVHstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVHreg {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off] {sym} ptr (MOVHZreg x) mem)
+	// cond:
+	// result: (MOVHstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVHstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVHstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVHstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem)
+	// cond: isU12Bit(off) && ptr.Op != OpSB
+	// result: (MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(isU12Bit(off) && ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreconst)
+		v.AuxInt = makeValAndOff(int64(int16(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVHstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVHstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(OpS390XMOVHstoreidx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [off] {sym} (ADD ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVHstoreidx [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		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(OpS390XMOVHstoreidx)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-2] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		x_1 := x.Args[1]
+		if x_1.Op != OpS390XSRDconst {
+			break
+		}
+		if x_1.AuxInt != 16 {
+			break
+		}
+		if w != x_1.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-2] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w0 := v.Args[1]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		x_1 := x.Args[1]
+		if x_1.Op != OpS390XSRDconst {
+			break
+		}
+		if x_1.AuxInt != j+16 {
+			break
+		}
+		if w != x_1.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-2] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		x_1 := x.Args[1]
+		if x_1.Op != OpS390XSRWconst {
+			break
+		}
+		if x_1.AuxInt != 16 {
+			break
+		}
+		if w != x_1.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHstore_10(v *Value) bool {
+	// match: (MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-2] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w0 := v.Args[1]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVHstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		x_1 := x.Args[1]
+		if x_1.Op != OpS390XSRWconst {
+			break
+		}
+		if x_1.AuxInt != j+16 {
+			break
+		}
+		if w != x_1.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHstoreconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem)
+	// cond: isU12Bit(ValAndOff(sc).Off()+off)
+	// result: (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(isU12Bit(ValAndOff(sc).Off() + off)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
+	// cond: ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpS390XMOVHstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVWstore [ValAndOff(a).Off()] {s} p (MOVDconst [int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))]) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpS390XMOVHstoreconst {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[1]
+		if p != x.Args[0] {
+			break
+		}
+		mem := x.Args[1]
+		if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
+		v0.AuxInt = int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHstoreidx_0(v *Value) bool {
+	// match: (MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [c] {sym} idx (ADDconst [d] ptr) val mem)
+	// cond:
+	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
+	// cond:
+	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [c] {sym} (ADDconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVHstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} idx p (SRDconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w x:(MOVHstoreidx [i-2] {s} idx p (SRDconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} idx p (SRDconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVHstoreidx_10(v *Value) bool {
+	// match: (MOVHstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} idx p (SRDconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} idx p (SRWconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w x:(MOVHstoreidx [i-2] {s} idx p (SRWconst [16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != 16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} idx p (SRWconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVHstoreidx [i] {s} idx p w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} idx p (SRWconst [j+16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRWconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVHstoreidx {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRWconst {
+			break
+		}
+		if x_2.AuxInt != j+16 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWBRstore_0(v *Value) bool {
+	// match: (MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstore [i-4] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		if v_1.AuxInt != 32 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVWBRstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		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(OpS390XMOVDBRstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstore [i-4] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVWBRstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVDBRstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWBRstoreidx_0(v *Value) bool {
+	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} idx p (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} idx p (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} idx p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
 		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} idx p w0:(SRDconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWBRstoreidx [i] {s} idx p (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} idx p w0:(SRDconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpS390XSRDconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWBRstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			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(OpS390XMOVDBRstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWZload_0(v *Value) bool {
+	// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: (MOVWZreg x)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVWstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		_ = v_1.Args[2]
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpS390XMOVWZreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVWZload [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVWZload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVWZload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZload [off] {sym} (ADD ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWZloadidx [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWZloadidx_0(v *Value) bool {
+	// match: (MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZloadidx [c] {sym} idx (ADDconst [d] ptr) mem)
+	// cond:
+	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
+	// cond:
+	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZloadidx [c] {sym} (ADDconst [d] idx) ptr mem)
+	// cond:
+	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWZloadidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWZreg_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWZreg x:(MOVBZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVHZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVWZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(Arg <t>))
+	// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpArg {
+			break
+		}
+		t := x.Type
+		if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)) {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVBZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVHZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVWZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWZreg (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [int64(uint32(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(uint32(c))
+		return true
+	}
+	// match: (MOVWZreg x:(MOVWZload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[2]
+		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.Pos, OpS390XMOVWZloadidx, 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
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWload_0(v *Value) bool {
+	// match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVWload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWload [off1] {sym1} (MOVDaddr [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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWreg_0(v *Value) bool {
+	// match: (MOVWreg x:(MOVBload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVBZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVHload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVHZload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHZload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVWload _ _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWload {
+			break
+		}
+		_ = x.Args[1]
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(Arg <t>))
+	// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpArg {
+			break
+		}
+		t := x.Type
+		if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)) {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVBreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVBZreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVBZreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVHreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg x:(MOVHreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVHreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWreg_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWreg x:(MOVWreg _))
+	// cond:
+	// result: (MOVDreg x)
+	for {
+		x := v.Args[0]
+		if x.Op != OpS390XMOVWreg {
+			break
+		}
+		v.reset(OpS390XMOVDreg)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWreg (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [int64(int32(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(int32(c))
+		return true
+	}
+	// match: (MOVWreg x:(MOVWZload [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 != OpS390XMOVWZload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWstore_0(v *Value) bool {
+	// match: (MOVWstore [off] {sym} ptr (MOVWreg x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVWreg {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} ptr (MOVWZreg x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+	// cond: is20Bit(off1+off2)
+	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is20Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpS390XMOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem)
+	// cond: is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB
+	// result: (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreconst)
+		v.AuxInt = makeValAndOff(int64(int32(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym1} (MOVDaddr [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.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			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(OpS390XMOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddridx {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		_ = v_0.Args[1]
+		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(OpS390XMOVWstoreidx)
+		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} (ADD ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWstoreidx [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADD {
+			break
+		}
+		_ = v_0.Args[1]
+		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(OpS390XMOVWstoreidx)
+		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 (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVDstore [i-4] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		if v_1.AuxInt != 32 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVWstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		if w != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
+	// result: (MOVDstore [i-4] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w0 := v.Args[1]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVWstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		x_1 := x.Args[1]
+		if x_1.Op != OpS390XSRDconst {
+			break
+		}
+		if x_1.AuxInt != j+32 {
+			break
+		}
+		if w != x_1.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && is20Bit(i-4)   && clobber(x)
+	// result: (STM2 [i-4] {s} p w0 w1 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w1 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XMOVWstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[2]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		mem := x.Args[2]
+		if !(p.Op != OpSB && x.Uses == 1 && is20Bit(i-4) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTM2)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWstore_10(v *Value) bool {
+	// match: (MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem))
+	// cond: x.Uses == 1   && is20Bit(i-8)   && clobber(x)
+	// result: (STM3 [i-8] {s} p w0 w1 w2 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w2 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XSTM2 {
+			break
+		}
+		if x.AuxInt != i-8 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		w1 := x.Args[2]
+		mem := x.Args[3]
+		if !(x.Uses == 1 && is20Bit(i-8) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTM3)
+		v.AuxInt = i - 8
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(w2)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem))
+	// cond: x.Uses == 1   && is20Bit(i-12)   && clobber(x)
+	// result: (STM4 [i-12] {s} p w0 w1 w2 w3 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[2]
+		p := v.Args[0]
+		w3 := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpS390XSTM3 {
+			break
+		}
+		if x.AuxInt != i-12 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[4]
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		w1 := x.Args[2]
+		w2 := x.Args[3]
+		mem := x.Args[4]
+		if !(x.Uses == 1 && is20Bit(i-12) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTM4)
+		v.AuxInt = i - 12
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(w2)
+		v.AddArg(w3)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWstoreconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem)
+	// cond: isU12Bit(ValAndOff(sc).Off()+off)
+	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(isU12Bit(ValAndOff(sc).Off() + off)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
+	// cond: ptr.Op != OpSB && 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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDaddr {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpS390XMOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+	// cond: p.Op != OpSB   && x.Uses == 1   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		_ = v.Args[1]
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpS390XMOVWstoreconst {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[1]
+		if p != x.Args[0] {
+			break
+		}
+		mem := x.Args[1]
+		if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstore)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
+		v0.AuxInt = ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWstoreidx_0(v *Value) bool {
+	// match: (MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [c] {sym} idx (ADDconst [d] ptr) val mem)
+	// cond:
+	// result: (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		ptr := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XADDconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [c] {sym} (ADDconst [d] idx) ptr val mem)
+	// cond:
+	// result: (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		_ = v.Args[3]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		d := v_0.AuxInt
+		idx := v_0.Args[0]
+		ptr := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpS390XMOVWstoreidx)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} idx p (SRDconst [32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} idx p w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} idx p w x:(MOVWstoreidx [i-4] {s} idx p (SRDconst [32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w := v.Args[2]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != 32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} idx p (SRDconst [j+32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		p := v.Args[0]
+		idx := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMOVWstoreidx_10(v *Value) bool {
+	// match: (MOVWstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx [i] {s} idx p w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} idx p (SRDconst [j+32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVDstoreidx [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		_ = v.Args[3]
+		idx := v.Args[0]
+		p := v.Args[1]
+		w0 := v.Args[2]
+		if w0.Op != OpS390XSRDconst {
+			break
+		}
+		j := w0.AuxInt
+		w := w0.Args[0]
+		x := v.Args[3]
+		if x.Op != OpS390XMOVWstoreidx {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		_ = x.Args[3]
+		if idx != x.Args[0] {
+			break
+		}
+		if p != x.Args[1] {
+			break
+		}
+		x_2 := x.Args[2]
+		if x_2.Op != OpS390XSRDconst {
+			break
+		}
+		if x_2.AuxInt != j+32 {
+			break
+		}
+		if w != x_2.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XMOVDstoreidx)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMULLD_0(v *Value) bool {
+	// match: (MULLD x (MOVDconst [c]))
+	// cond: is32Bit(c)
+	// result: (MULLDconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XMULLDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLD (MOVDconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (MULLDconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XMULLDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLD <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLD <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLDload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLDload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMULLDconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLDconst [-1] x)
+	// cond:
+	// result: (NEG x)
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpS390XNEG)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLDconst [0] _)
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MULLDconst [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: (MULLDconst [c] x)
+	// cond: isPowerOfTwo(c)
+	// result: (SLDconst [log2(c)] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpS390XSLDconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLDconst [c] x)
+	// cond: isPowerOfTwo(c+1) && c >= 15
+	// result: (SUB (SLDconst <v.Type> [log2(c+1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c+1) && c >= 15) {
+			break
+		}
+		v.reset(OpS390XSUB)
+		v0 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v0.AuxInt = log2(c + 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLDconst [c] x)
+	// cond: isPowerOfTwo(c-1) && c >= 17
+	// result: (ADD (SLDconst <v.Type> [log2(c-1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-1) && c >= 17) {
+			break
+		}
+		v.reset(OpS390XADD)
+		v0 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v0.AuxInt = log2(c - 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLDconst [c] (MOVDconst [d]))
+	// cond:
+	// result: (MOVDconst [c*d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c * d
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMULLW_0(v *Value) bool {
+	// match: (MULLW x (MOVDconst [c]))
+	// cond:
+	// result: (MULLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpS390XMULLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLW (MOVDconst [c]) x)
+	// cond:
+	// result: (MULLWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpS390XMULLWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (MULLWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XMULLWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XMULLWconst_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLWconst [-1] x)
+	// cond:
+	// result: (NEGW x)
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpS390XNEGW)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLWconst [0] _)
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MULLWconst [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: (MULLWconst [c] x)
+	// cond: isPowerOfTwo(c)
+	// result: (SLWconst [log2(c)] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpS390XSLWconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLWconst [c] x)
+	// cond: isPowerOfTwo(c+1) && c >= 15
+	// result: (SUBW (SLWconst <v.Type> [log2(c+1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c+1) && c >= 15) {
+			break
+		}
+		v.reset(OpS390XSUBW)
+		v0 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v0.AuxInt = log2(c + 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLWconst [c] x)
+	// cond: isPowerOfTwo(c-1) && c >= 17
+	// result: (ADDW (SLWconst <v.Type> [log2(c-1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-1) && c >= 17) {
+			break
+		}
+		v.reset(OpS390XADDW)
+		v0 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v0.AuxInt = log2(c - 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULLWconst [c] (MOVDconst [d]))
+	// cond:
+	// result: (MOVDconst [int64(int32(c*d))])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XNEG_0(v *Value) bool {
+	// match: (NEG (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [-c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = -c
+		return true
+	}
+	// match: (NEG (ADDconst [c] (NEG x)))
+	// cond: c != -(1<<31)
+	// result: (ADDconst [-c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XADDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpS390XNEG {
+			break
+		}
+		x := v_0_0.Args[0]
+		if !(c != -(1 << 31)) {
+			break
+		}
+		v.reset(OpS390XADDconst)
+		v.AuxInt = -c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XNEGW_0(v *Value) bool {
+	// match: (NEGW (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [int64(int32(-c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = int64(int32(-c))
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XNOT_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (NOT x)
+	// cond: true
+	// result: (XOR (MOVDconst [-1]) x)
+	for {
+		x := v.Args[0]
+		if !(true) {
+			break
+		}
+		v.reset(OpS390XXOR)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDconst, typ.UInt64)
+		v0.AuxInt = -1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XNOTW_0(v *Value) bool {
+	// match: (NOTW x)
+	// cond: true
+	// result: (XORWconst [-1] x)
+	for {
+		x := v.Args[0]
+		if !(true) {
+			break
+		}
+		v.reset(OpS390XXORWconst)
+		v.AuxInt = -1
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_0(v *Value) bool {
+	// match: (OR x (MOVDconst [c]))
+	// cond: isU32Bit(c)
+	// result: (ORconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (MOVDconst [c]) x)
+	// cond: isU32Bit(c)
+	// result: (ORconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XORconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSLDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSLDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR (MOVDconst [c]) (MOVDconst [d]))
+	// cond:
+	// result: (MOVDconst [c|d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c | d
+		return true
+	}
+	// match: (OR (MOVDconst [d]) (MOVDconst [c]))
+	// cond:
+	// result: (MOVDconst [c|d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c | d
+		return true
+	}
+	// match: (OR x x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (OR <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (OR <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (OR <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVBZload [i1] {s} p mem) sh:(SLDconst [8] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x0:(MOVBZload [i0] {s} p mem)) x1:(MOVBZload [i1] {s} p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVHZload [i1] {s} p mem) sh:(SLDconst [16] x0:(MOVHZload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] x0:(MOVHZload [i0] {s} p mem)) x1:(MOVHZload [i1] {s} p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVWZload [i1] {s} p mem) sh:(SLDconst [32] x0:(MOVWZload [i0] {s} p mem)))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVWZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] x0:(MOVWZload [i0] {s} p mem)) x1:(MOVWZload [i1] {s} p mem))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVWZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDload, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) y) s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem))) s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem)) y) s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem))) s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR x1:(MOVBZloadidx [i1] {s} p idx mem) sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVBZloadidx [i1] {s} idx p mem) sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVBZloadidx [i1] {s} p idx mem) sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVBZloadidx [i1] {s} idx p mem) sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)) x1:(MOVBZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_30(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)) x1:(MOVBZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)) x1:(MOVBZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)) x1:(MOVBZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVHZloadidx [i1] {s} p idx mem) sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVHZloadidx [i1] {s} idx p mem) sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVHZloadidx [i1] {s} p idx mem) sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVHZloadidx [i1] {s} idx p mem) sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)) x1:(MOVHZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)) x1:(MOVHZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)) x1:(MOVHZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_40(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)) x1:(MOVHZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVWZloadidx [i1] {s} p idx mem) sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVWZloadidx [i1] {s} idx p mem) sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVWZloadidx [i1] {s} p idx mem) sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR x1:(MOVWZloadidx [i1] {s} idx p mem) sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem)) x1:(MOVWZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} idx p mem)) x1:(MOVWZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem)) x1:(MOVWZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} idx p mem)) x1:(MOVWZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+4   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVWZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDloadidx, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_50(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_60(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))) s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)) or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)) or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)) or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_70(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)) or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem)) y) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem)) y) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem))) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem))) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem)) y) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem)) y) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem))) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_80(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} idx p mem))) s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && j1 == j0-16   && j1 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0-16 && j1%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR x0:(MOVBZload [i0] {s} p mem) sh:(SLDconst [8] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x1:(MOVBZload [i1] {s} p mem)) x0:(MOVBZload [i0] {s} p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)) sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRload [i0] {s} p mem))
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))) r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRload [i0] {s} p mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVWZreg x0:(MOVWBRload [i0] {s} p mem)) sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRload [i1] {s} p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRload, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRload [i1] {s} p mem))) r0:(MOVWZreg x0:(MOVWBRload [i0] {s} p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRload, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) or:(OR s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) or:(OR y s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) y) s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_90(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem))) s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))) or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))) or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem))) y) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)))) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR x0:(MOVBZloadidx [i0] {s} p idx mem) sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR x0:(MOVBZloadidx [i0] {s} idx p mem) sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR x0:(MOVBZloadidx [i0] {s} p idx mem) sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR x0:(MOVBZloadidx [i0] {s} idx p mem) sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)) x0:(MOVBZloadidx [i0] {s} p idx mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_100(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)) x0:(MOVBZloadidx [i0] {s} p idx mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)) x0:(MOVBZloadidx [i0] {s} idx p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)) x0:(MOVBZloadidx [i0] {s} idx p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)) sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)) sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_110(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 16 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (OR r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem)) sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} idx p mem)) sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem)) sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} idx p mem)) sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem))) r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} idx p mem))) r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem))) r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} idx p mem))) r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+4   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLDconst {
+			break
+		}
+		if sh.AuxInt != 32 {
+			break
+		}
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVWZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVWZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVWBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+4 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVDBRloadidx, typ.Int64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_120(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDGE)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDLE _ x (FlagEQ))
-	// cond:
-	// result: x
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (OR or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XOR_130(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDLE _ x (FlagLT))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDLE y _ (FlagGT))
-	// cond:
-	// result: y
+	// match: (OR or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDLT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDLT x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDGT x y cmp)
+	// match: (OR or:(OR s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDGT)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
-		return true
-	}
-	// match: (MOVDLT y _ (FlagEQ))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDLT _ x (FlagLT))
-	// cond:
-	// result: x
+	// match: (OR or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDLT y _ (FlagGT))
-	// cond:
-	// result: y
+	// match: (OR or:(OR y s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))) s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDNE(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDNE x y (InvertFlags cmp))
-	// cond:
-	// result: (MOVDNE x y cmp)
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[0]
-		y := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XInvertFlags {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		cmp := v_2.Args[0]
-		v.reset(OpS390XMOVDNE)
-		v.AddArg(x)
-		v.AddArg(y)
-		v.AddArg(cmp)
-		return true
-	}
-	// match: (MOVDNE y _ (FlagEQ))
-	// cond:
-	// result: y
-	for {
-		y := v.Args[0]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagEQ {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
 			break
 		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDNE _ x (FlagLT))
-	// cond:
-	// result: x
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagLT {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
+			break
+		}
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDNE _ x (FlagGT))
-	// cond:
-	// result: x
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XFlagGT {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
 			break
 		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDaddridx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDaddridx [c] {s} (ADDconst [d] x) y)
-	// cond: is20Bit(c+d) && x.Op != OpSB
-	// result: (MOVDaddridx [c+d] {s} x y)
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem))) y))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		c := v.AuxInt
-		s := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		d := v_0.AuxInt
-		x := v_0.Args[0]
-		y := v.Args[1]
-		if !(is20Bit(c+d) && x.Op != OpSB) {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		v.reset(OpS390XMOVDaddridx)
-		v.AuxInt = c + d
-		v.Aux = s
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDaddridx [c] {s} x (ADDconst [d] y))
-	// cond: is20Bit(c+d) && y.Op != OpSB
-	// result: (MOVDaddridx [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 != OpS390XADDconst {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		d := v_1.AuxInt
-		y := v_1.Args[0]
-		if !(is20Bit(c+d) && y.Op != OpSB) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
 			break
 		}
-		v.reset(OpS390XMOVDaddridx)
-		v.AuxInt = c + d
-		v.Aux = s
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
-	// result: (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
 			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) {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		v.reset(OpS390XMOVDaddridx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-	// match: (MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y))
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
-	// result: (MOVDaddridx [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 != OpS390XMOVDaddr {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		off2 := v_1.AuxInt
-		sym2 := v_1.Aux
-		y := v_1.Args[0]
-		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDaddridx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(x)
-		v.AddArg(y)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: (MOVDreg x)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDstore {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			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)) {
+		if p != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDload   [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVDload  [off1+off2] {sym} ptr mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if mem != x0.Args[2] {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is20Bit(off1 + off2)) {
+		y := or.Args[1]
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVDload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVDload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			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)) {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		v.reset(OpS390XMOVDload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddridx {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			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)) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDloadidx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDload [off] {sym} (ADD ptr idx) mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVDloadidx [off] {sym} ptr idx mem)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		if idx != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDloadidx)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVDloadidx [c+d] {sym} ptr idx mem)
-	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if mem != x0.Args[2] {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVDloadidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
-	// cond:
-	// result: (MOVDloadidx [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 != OpS390XADDconst {
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVDloadidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVDnop(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XOR_140(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVDnop <t> x)
-	// cond: t.Compare(x.Type) == CMPeq
-	// result: x
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		if !(t.Compare(x.Type) == CMPeq) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDnop (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [c])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = c
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDreg <t> x)
-	// cond: t.Compare(x.Type) == CMPeq
-	// result: x
-	for {
-		t := v.Type
-		x := v.Args[0]
-		if !(t.Compare(x.Type) == CMPeq) {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVDreg (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [c])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = c
-		return true
-	}
-	// match: (MOVDreg x)
-	// cond: x.Uses == 1
-	// result: (MOVDnop x)
-	for {
-		x := v.Args[0]
-		if !(x.Uses == 1) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		v.reset(OpS390XMOVDnop)
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDstore  [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVDstore  [off1+off2] {sym} ptr val mem)
-	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is20Bit(off1 + off2)) {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem)
-	// cond: validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB
-	// result: (MOVDstoreconst [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 != OpS390XMOVDconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validValAndOff(c, off) && int64(int16(c)) == c && ptr.Op != OpSB) {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDstoreconst)
-		v.AuxInt = makeValAndOff(c, off)
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVDstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		if idx != x0.Args[1] {
 			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)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
-		v.AddArg(mem)
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddridx {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			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)) {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstore [off] {sym} (ADD ptr idx) val mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVDstoreidx [off] {sym} ptr idx val mem)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
+			break
+		}
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && is20Bit(i-8)   && clobber(x)
-	// result: (STMG2 [i-8] {s} p w0 w1 mem)
+	// match: (OR s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w1 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVDstore {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		if x.AuxInt != i-8 {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.Aux != s {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XOR {
 			break
 		}
-		w0 := x.Args[1]
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && is20Bit(i-8) && clobber(x)) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		v.reset(OpS390XSTMG2)
-		v.AuxInt = i - 8
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem))
-	// cond: x.Uses == 1   && is20Bit(i-16)   && clobber(x)
-	// result: (STMG3 [i-16] {s} p w0 w1 w2 mem)
-	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w2 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XSTMG2 {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.AuxInt != i-16 {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		w0 := x.Args[1]
-		w1 := x.Args[2]
-		mem := x.Args[3]
-		if !(x.Uses == 1 && is20Bit(i-16) && clobber(x)) {
+		if p != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XSTMG3)
-		v.AuxInt = i - 16
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(w2)
-		v.AddArg(mem)
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem))
-	// cond: x.Uses == 1   && is20Bit(i-24)   && clobber(x)
-	// result: (STMG4 [i-24] {s} p w0 w1 w2 w3 mem)
+	// match: (OR or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))) y) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w3 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XSTMG3 {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		if x.AuxInt != i-24 {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		if x.Aux != s {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if p != x.Args[0] {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		w0 := x.Args[1]
-		w1 := x.Args[2]
-		w2 := x.Args[3]
-		mem := x.Args[4]
-		if !(x.Uses == 1 && is20Bit(i-24) && clobber(x)) {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		v.reset(OpS390XSTMG4)
-		v.AuxInt = i - 24
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(w2)
-		v.AddArg(w3)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
-	// result: (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-	for {
-		sc := v.AuxInt
-		s := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		off := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
-	// result: (MOVDstoreconst [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 != OpS390XMOVDaddr {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			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)) {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVDstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVDstoreidx [c+d] {sym} ptr idx val mem)
-	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if idx != x1.Args[1] {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
-	// cond:
-	// result: (MOVDstoreidx [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 != OpS390XADDconst {
+		if mem != x1.Args[2] {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHBRstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHBRstore [i] {s} p (SRDconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstore [i-2] {s} p w mem)
+	// match: (OR or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem))) y) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		if v_1.AuxInt != 16 {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHBRstore {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
+			break
+		}
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x.AuxInt != i-2 {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x.Aux != s {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if p != x.Args[0] {
+		if idx != x1.Args[1] {
 			break
 		}
-		if w != x.Args[1] {
+		if mem != x1.Args[2] {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVWBRstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHBRstore [i] {s} p (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstore [i-2] {s} p w0 mem)
+	// match: (OR or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		j := v_1.AuxInt
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHBRstore {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.Aux != s {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		w0 := x.Args[1]
-		if w0.Op != OpS390XSRDconst {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if w != w0.Args[0] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVWBRstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstore [i-2] {s} p w mem)
+	// match: (OR or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRWconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		if v_1.AuxInt != 16 {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHBRstore {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.AuxInt != i-2 {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		if p != x.Args[0] {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if w != x.Args[1] {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVWBRstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstore [i-2] {s} p w0 mem)
+	// match: (OR or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))) y) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRWconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		j := v_1.AuxInt
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHBRstore {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.Aux != s {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		w0 := x.Args[1]
-		if w0.Op != OpS390XSRWconst {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if w != w0.Args[0] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVWBRstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHBRstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	// match: (OR or:(OR s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem))) y) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		if v_2.AuxInt != 16 {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHBRstoreidx {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.AuxInt != i-2 {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		if p != x.Args[0] {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if idx != x.Args[1] {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if w != x.Args[2] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVWBRstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+	// match: (OR or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHBRstoreidx {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
+			break
+		}
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		if x.Aux != s {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if p != x.Args[0] {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpS390XSRDconst {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		if p != x1.Args[1] {
 			break
 		}
-		if w != w0.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVWBRstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstoreidx [i-2] {s} p idx w mem)
+	return false
+}
+func rewriteValueS390X_OpS390XOR_150(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (OR or:(OR y s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))) s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && j1 == j0+16   && j0 % 32 == 0   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		v_2 := v.Args[2]
-		if v_2.Op != OpS390XSRWconst {
-			break
-		}
-		if v_2.AuxInt != 16 {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XOR {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHBRstoreidx {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLDconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		j0 := s0.AuxInt
+		r0 := s0.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x.Aux != s {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLDconst {
 			break
 		}
-		if idx != x.Args[1] {
+		j1 := s1.AuxInt
+		r1 := s1.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if w != x.Args[2] {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVWBRstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWBRstoreidx [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 != OpS390XSRWconst {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHBRstoreidx {
+		if p != x1.Args[1] {
 			break
 		}
-		if x.AuxInt != i-2 {
+		if mem != x1.Args[2] {
 			break
 		}
-		if x.Aux != s {
+		if !(i1 == i0+2 && j1 == j0+16 && j0%32 == 0 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if p != x.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XOR, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLDconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XORW_0(v *Value) bool {
+	// match: (ORW x (MOVDconst [c]))
+	// cond:
+	// result: (ORWconst [c] x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		if idx != x.Args[1] {
+		c := v_1.AuxInt
+		v.reset(OpS390XORWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORW (MOVDconst [c]) x)
+	// cond:
+	// result: (ORWconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpS390XSRWconst {
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpS390XORWconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORW (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSLWconst {
 			break
 		}
-		if w0.AuxInt != j-16 {
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRWconst {
 			break
 		}
-		if w != w0.Args[0] {
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(d == 32-c) {
 			break
 		}
-		v.reset(OpS390XMOVWBRstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		v.reset(OpS390XRLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: (MOVDreg x)
+	// match: (ORW (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSRWconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVHstore {
+		if v_1.Op != OpS390XSLWconst {
 			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)) {
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
+		if !(d == 32-c) {
+			break
+		}
+		v.reset(OpS390XRLLconst)
+		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (MOVHZload  [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVHZload [off1+off2] {sym} ptr mem)
+	// match: (ORW x x)
+	// cond:
+	// result: x
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
-			break
-		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is20Bit(off1 + off2)) {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVHZload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (MOVHZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVHZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	// match: (ORW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
 			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)) {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVHZload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	// match: (ORW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddridx {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
 			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)) {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVHZloadidx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZload [off] {sym} (ADD ptr idx) mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVHZloadidx [off] {sym} ptr idx mem)
+	// match: (ORW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVHZloadidx)
+		v.reset(OpS390XORWload)
+		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
+		v.AddArg(x)
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHZloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	// match: (ORW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVHZloadidx)
-		v.AuxInt = c + d
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
 		v.Aux = sym
+		v.AddArg(x)
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
-	// cond:
-	// result: (MOVHZloadidx [c+d] {sym} ptr idx mem)
+	// match: (ORW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XADDconst {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVHZloadidx)
-		v.AuxInt = c + d
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
 		v.Aux = sym
+		v.AddArg(x)
 		v.AddArg(ptr)
-		v.AddArg(idx)
 		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XORW_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVHZreg x:(MOVBZload _ _))
-	// cond:
-	// result: (MOVDreg x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZload {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHZreg x:(MOVHZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZload {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZreg x:(Arg <t>))
-	// cond: (is8BitInt(t) || is16BitInt(t)) && !isSigned(t)
-	// result: (MOVDreg x)
+	// match: (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpArg {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
-		t := x.Type
-		if !((is8BitInt(t) || is16BitInt(t)) && !isSigned(t)) {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZreg x:(MOVBZreg _))
-	// cond:
-	// result: (MOVDreg x)
+	// match: (ORW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (ORWload <t> [off] {sym} x ptr mem)
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x.Op != OpS390XMOVBZreg {
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHZreg x:(MOVHZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZreg {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
+		v.reset(OpS390XORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZreg (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [int64(uint16(c))])
+	// match: (ORW x1:(MOVBZload [i1] {s} p mem) sh:(SLWconst [8] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(uint16(c))
-		return true
-	}
-	// match: (MOVHZreg x:(MOVHZload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZload {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		if sh.AuxInt != 8 {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZload, v.Type)
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem)
+	// match: (ORW sh:(SLWconst [8] x0:(MOVBZload [i0] {s} p mem)) x1:(MOVBZload [i1] {s} p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZloadidx {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			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)) {
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZloadidx, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(idx)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
 		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHload   [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVHload  [off1+off2] {sym} ptr mem)
+	// match: (ORW x1:(MOVHZload [i1] {s} p mem) sh:(SLWconst [16] x0:(MOVHZload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZload {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is20Bit(off1 + off2)) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVHload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		if sh.AuxInt != 16 {
 			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)) {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZload {
 			break
 		}
-		v.reset(OpS390XMOVHload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHreg x:(MOVBload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBload {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg x:(MOVBZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZload {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg x:(MOVHload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHload {
+		if mem != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHreg x:(Arg <t>))
-	// cond: (is8BitInt(t) || is16BitInt(t)) && isSigned(t)
-	// result: (MOVDreg x)
+	// match: (ORW sh:(SLWconst [16] x0:(MOVHZload [i0] {s} p mem)) x1:(MOVHZload [i1] {s} p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem)
 	for {
-		x := v.Args[0]
-		if x.Op != OpArg {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		t := x.Type
-		if !((is8BitInt(t) || is16BitInt(t)) && isSigned(t)) {
+		if sh.AuxInt != 16 {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg x:(MOVBreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBreg {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZload {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg x:(MOVBZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZreg {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZload {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg x:(MOVHreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHreg {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVHreg (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [int64(int16(c))])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(int16(c))
-		return true
-	}
-	// match: (MOVHreg x:(MOVHZload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVHload <v.Type> [off] {sym} ptr mem)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZload {
+		if mem != x1.Args[1] {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVHload, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZload, typ.UInt32)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
 		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHstore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHstore [off] {sym} ptr (MOVHreg x) mem)
-	// cond:
-	// result: (MOVHstore [off] {sym} ptr x mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) or:(ORW s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
 	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVHreg {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVHstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstore [off] {sym} ptr (MOVHZreg x) mem)
-	// cond:
-	// result: (MOVHstore [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 != OpS390XMOVHZreg {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVHstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHstore  [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVHstore  [off1+off2] {sym} ptr val mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) or:(ORW y s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is20Bit(off1 + off2)) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		v.reset(OpS390XMOVHstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem)
-	// cond: validOff(off) && ptr.Op != OpSB
-	// result: (MOVHstoreconst [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 != OpS390XMOVDconst {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validOff(off) && ptr.Op != OpSB) {
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVHstoreconst)
-		v.AuxInt = makeValAndOff(int64(int16(c)), off)
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVHstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		if mem != x1.Args[1] {
 			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)) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVHstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	// match: (ORW or:(ORW s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) y) s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
 	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddridx {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			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)) {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVHstoreidx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstore [off] {sym} (ADD ptr idx) val mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVHstoreidx [off] {sym} ptr idx val mem)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVHstoreidx)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
+			break
+		}
+		if mem != x0.Args[1] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVWstore [i-2] {s} p w mem)
+	return false
+}
+func rewriteValueS390X_OpS390XORW_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW or:(ORW y s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem))) s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHstore {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if x.AuxInt != i-2 {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x.Aux != s {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		if p != x.Args[0] {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpS390XSRDconst {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		if x_1.AuxInt != 16 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if w != x_1.Args[0] {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		if mem != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZload, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVWstore [i-2] {s} p w0 mem)
+	// match: (ORW x1:(MOVBZloadidx [i1] {s} p idx mem) sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w0 := v.Args[1]
-		if w0.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHstore {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if x.Aux != s {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpS390XSRDconst {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x_1.AuxInt != j+16 {
+		if idx != x0.Args[1] {
 			break
 		}
-		if w != x_1.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVWstore [i-2] {s} p w mem)
+	// match: (ORW x1:(MOVBZloadidx [i1] {s} idx p mem) sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHstore {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x.AuxInt != i-2 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.Aux != s {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if p != x.Args[0] {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpS390XSRWconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x_1.AuxInt != 16 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if w != x_1.Args[0] {
+		if idx != x0.Args[1] {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVWstore [i-2] {s} p w0 mem)
+	// match: (ORW x1:(MOVBZloadidx [i1] {s} p idx mem) sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w0 := v.Args[1]
-		if w0.Op != OpS390XSRWconst {
-			break
-		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVHstore {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x.AuxInt != i-2 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.Aux != s {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if p != x.Args[0] {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpS390XSRWconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x_1.AuxInt != j+16 {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if w != x_1.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
-	// result: (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	// match: (ORW x1:(MOVBZloadidx [i1] {s} idx p mem) sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		sc := v.AuxInt
-		s := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		off := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVHstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
-	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
-	// result: (MOVHstoreconst [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 != OpS390XMOVDaddr {
+		if sh.AuxInt != 8 {
 			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)) {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVHstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
-	// result: (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).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 != OpS390XMOVHstoreconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		a := x.AuxInt
-		if x.Aux != s {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if p != x.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		mem := x.Args[1]
-		if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVWstoreconst)
-		v.AuxInt = makeValAndOff(ValAndOff(c).Val()&0xffff|ValAndOff(a).Val()<<16, ValAndOff(a).Off())
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVHstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
-	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVHstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
-	// cond:
-	// result: (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+	// match: (ORW sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)) x1:(MOVBZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVHstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		if sh.AuxInt != 8 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	// match: (ORW sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)) x1:(MOVBZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w := v.Args[2]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHstoreidx {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if x.Aux != s {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRDconst {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if x_2.AuxInt != 16 {
+		if idx != x1.Args[1] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	// match: (ORW sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem)) x1:(MOVBZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w0 := v.Args[2]
-		if w0.Op != OpS390XSRDconst {
-			break
-		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHstoreidx {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if x.Aux != s {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRDconst {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if x_2.AuxInt != j+16 {
+		if p != x1.Args[1] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWstoreidx [i-2] {s} p idx w mem)
+	// match: (ORW sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} idx p mem)) x1:(MOVBZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+1   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w := v.Args[2]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHstoreidx {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-2 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if x.Aux != s {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRWconst {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if x_2.AuxInt != 16 {
+		if p != x1.Args[1] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+1 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVWstoreidx [i-2] {s} p idx w0 mem)
+	// match: (ORW x1:(MOVHZloadidx [i1] {s} p idx mem) sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w0 := v.Args[2]
-		if w0.Op != OpS390XSRWconst {
-			break
-		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVHstoreidx {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if x.AuxInt != i-2 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.Aux != s {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if p != x.Args[0] {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRWconst {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x_2.AuxInt != j+16 {
+		if idx != x0.Args[1] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = i - 2
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVWBRstore(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XORW_30(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDBRstore [i-4] {s} p w mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW x1:(MOVHZloadidx [i1] {s} idx p mem) sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if v_1.AuxInt != 32 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVWBRstore {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if x.AuxInt != i-4 {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if w != x.Args[1] {
+		if idx != x0.Args[1] {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDBRstore)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDBRstore [i-4] {s} p w0 mem)
+	// match: (ORW x1:(MOVHZloadidx [i1] {s} p idx mem) sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		j := v_1.AuxInt
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVWBRstore {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-4 {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if x.Aux != s {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		w0 := x.Args[1]
-		if w0.Op != OpS390XSRDconst {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if w0.AuxInt != j-32 {
+		if p != x0.Args[1] {
 			break
 		}
-		if w != w0.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		mem := x.Args[2]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVDBRstore)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWBRstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDBRstoreidx [i-4] {s} p idx w mem)
+	// match: (ORW x1:(MOVHZloadidx [i1] {s} idx p mem) sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx 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 != OpS390XSRDconst {
+		_ = v.Args[1]
+		x1 := v.Args[0]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if v_2.AuxInt != 32 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVWBRstoreidx {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if x.AuxInt != i-4 {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if idx != x.Args[1] {
+		if p != x0.Args[1] {
 			break
 		}
-		if w != x.Args[2] {
+		if mem != x0.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVDBRstoreidx)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+	// match: (ORW sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)) x1:(MOVHZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx 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 != OpS390XSRDconst {
-			break
-		}
-		j := v_2.AuxInt
-		w := v_2.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVWBRstoreidx {
-			break
-		}
-		if x.AuxInt != i-4 {
-			break
-		}
-		if x.Aux != s {
-			break
-		}
-		if p != x.Args[0] {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x.Args[1] {
+		if sh.AuxInt != 16 {
 			break
 		}
-		w0 := x.Args[2]
-		if w0.Op != OpS390XSRDconst {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if w0.AuxInt != j-32 {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		if w != w0.Args[0] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDBRstoreidx)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
-	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-	// result: (MOVDreg x)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVWstore {
+		if idx != x1.Args[1] {
 			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)) {
+		}
+		if mem != x1.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWZload  [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVWZload [off1+off2] {sym} ptr mem)
+	// match: (ORW sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)) x1:(MOVHZloadidx [i1] {s} p idx mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is20Bit(off1 + off2)) {
+		if sh.AuxInt != 16 {
 			break
 		}
-		v.reset(OpS390XMOVWZload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddr {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			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)) {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVWZload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-	for {
-		off1 := v.AuxInt
-		sym1 := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDaddridx {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			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)) {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVWZloadidx)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWZload [off] {sym} (ADD ptr idx) mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVWZloadidx [off] {sym} ptr idx mem)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		if idx != x1.Args[1] {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		mem := v.Args[1]
-		if !(ptr.Op != OpSB) {
+		if mem != x1.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVWZloadidx)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWZloadidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem)
-	// cond:
-	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
-	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVWZloadidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
-	// cond:
-	// result: (MOVWZloadidx [c+d] {sym} ptr idx mem)
+	// match: (ORW sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem)) x1:(MOVHZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		c := v.AuxInt
-		sym := v.Aux
-		ptr := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVWZloadidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWZreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWZreg x:(MOVBZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZload {
+		if sh.AuxInt != 16 {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(MOVHZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZload {
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(MOVWZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWZload {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(Arg <t>))
-	// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpArg {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		t := x.Type
-		if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)) {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(MOVBZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZreg {
+		if p != x1.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(MOVHZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZreg {
+		if mem != x1.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWZreg x:(MOVWZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWZreg {
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWZreg (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [int64(uint32(c))])
+	// match: (ORW sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} idx p mem)) x1:(MOVHZloadidx [i1] {s} idx p mem))
+	// cond: i1 == i0+2   && p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(uint32(c))
-		return true
-	}
-	// match: (MOVWZreg x:(MOVWZload [off] {sym} ptr mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWZload {
+		if sh.AuxInt != 16 {
+			break
+		}
+		x0 := sh.Args[0]
+		if x0.Op != OpS390XMOVHZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		x1 := v.Args[1]
+		if x1.Op != OpS390XMOVHZloadidx {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZload, v.Type)
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
+			break
+		}
+		if p != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(i1 == i0+2 && p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWZloadidx, typ.UInt32)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem))
-	// cond: x.Uses == 1 && clobber(x)
-	// result: @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWZloadidx {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			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)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZloadidx, v.Type)
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWload(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWload   [off1] {sym} (ADDconst [off2] ptr) mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVWload  [off1+off2] {sym} ptr mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(is20Bit(off1 + off2)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVWload)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWload [off1] {sym1} (MOVDaddr [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 != OpS390XMOVDaddr {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			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)) {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVWload)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWreg(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWreg x:(MOVBload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBload {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVBZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZload {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVHload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHload {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVHZload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHZload {
+		if idx != x1.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVWload _ _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWload {
+		if mem != x1.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVWreg x:(Arg <t>))
-	// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)
-	// result: (MOVDreg x)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		if x.Op != OpArg {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		t := x.Type
-		if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVBreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBreg {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVBZreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVBZreg {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVHreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHreg {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVHreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVHreg {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg x:(MOVWreg _))
-	// cond:
-	// result: (MOVDreg x)
-	for {
-		x := v.Args[0]
-		if x.Op != OpS390XMOVWreg {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		v.reset(OpS390XMOVDreg)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MOVWreg (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [int64(int32(c))])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		if p != x1.Args[1] {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(int32(c))
-		return true
-	}
-	// match: (MOVWreg x:(MOVWZload [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 != OpS390XMOVWZload {
+		if mem != x1.Args[2] {
 			break
 		}
-		off := x.AuxInt
-		sym := x.Aux
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(x.Uses == 1 && clobber(x)) {
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = x.Block
-		v0 := b.NewValue0(v.Line, OpS390XMOVWload, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = off
-		v0.Aux = sym
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMOVWstore(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XORW_40(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MOVWstore [off] {sym} ptr (MOVWreg 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 != OpS390XMOVWreg {
-			break
-		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [off] {sym} ptr (MOVWZreg 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 != OpS390XMOVWZreg {
-			break
-		}
-		x := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(x)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore  [off1] {sym} (ADDconst [off2] ptr) val mem)
-	// cond: is20Bit(off1+off2)
-	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		off1 := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		off2 := v_0.AuxInt
-		ptr := v_0.Args[0]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(is20Bit(off1 + off2)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = off1 + off2
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem)
-	// cond: validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB
-	// result: (MOVWstoreconst [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 != OpS390XMOVDconst {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		c := v_1.AuxInt
-		mem := v.Args[2]
-		if !(validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB) {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVWstoreconst)
-		v.AuxInt = makeValAndOff(int64(int32(c)), off)
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore  [off1] {sym1} (MOVDaddr [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 != OpS390XMOVDaddr {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			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)) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVWstore)
-		v.AuxInt = off1 + off2
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(base)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
-	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
-	// result: (MOVWstoreidx [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 != OpS390XMOVDaddridx {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			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)) {
+		if p != x1.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		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} (ADD ptr idx) val mem)
-	// cond: ptr.Op != OpSB
-	// result: (MOVWstoreidx [off] {sym} ptr idx val mem)
-	for {
-		off := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADD {
+		if mem != x1.Args[2] {
 			break
 		}
-		ptr := v_0.Args[0]
-		idx := v_0.Args[1]
-		val := v.Args[1]
-		mem := v.Args[2]
-		if !(ptr.Op != OpSB) {
+		y := or.Args[1]
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVWstore [i] {s} p (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVDstore [i-4] {s} p w mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XSRDconst {
-			break
-		}
-		if v_1.AuxInt != 32 {
-			break
-		}
-		w := v_1.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVWstore {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-4 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if p != x.Args[0] {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if w != x.Args[1] {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		v.reset(OpS390XMOVDstore)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && clobber(x)
-	// result: (MOVDstore [i-4] {s} p w0 mem)
-	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w0 := v.Args[1]
-		if w0.Op != OpS390XSRDconst {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVWstore {
+		if idx != x1.Args[1] {
 			break
 		}
-		if x.AuxInt != i-4 {
+		if mem != x1.Args[2] {
 			break
 		}
-		if x.Aux != s {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if p != x.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
+	for {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpS390XSRDconst {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x_1.AuxInt != j+32 {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if w != x_1.Args[0] {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVDstore)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && is20Bit(i-4)   && clobber(x)
-	// result: (STM2 [i-4] {s} p w0 w1 mem)
-	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w1 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XMOVWstore {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x.AuxInt != i-4 {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if x.Aux != s {
+		if idx != x1.Args[1] {
 			break
 		}
-		if p != x.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		w0 := x.Args[1]
-		mem := x.Args[2]
-		if !(p.Op != OpSB && x.Uses == 1 && is20Bit(i-4) && clobber(x)) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XSTM2)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem))
-	// cond: x.Uses == 1   && is20Bit(i-8)   && clobber(x)
-	// result: (STM3 [i-8] {s} p w0 w1 w2 mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w2 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XSTM2 {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-8 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x.Aux != s {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if p != x.Args[0] {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		w0 := x.Args[1]
-		w1 := x.Args[2]
-		mem := x.Args[3]
-		if !(x.Uses == 1 && is20Bit(i-8) && clobber(x)) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XSTM3)
-		v.AuxInt = i - 8
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(w2)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem))
-	// cond: x.Uses == 1   && is20Bit(i-12)   && clobber(x)
-	// result: (STM4 [i-12] {s} p w0 w1 w2 w3 mem)
-	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		w3 := v.Args[1]
-		x := v.Args[2]
-		if x.Op != OpS390XSTM3 {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x.AuxInt != i-12 {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if x.Aux != s {
+		if p != x1.Args[1] {
 			break
 		}
-		if p != x.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		w0 := x.Args[1]
-		w1 := x.Args[2]
-		w2 := x.Args[3]
-		mem := x.Args[4]
-		if !(x.Uses == 1 && is20Bit(i-12) && clobber(x)) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XSTM4)
-		v.AuxInt = i - 12
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(w2)
-		v.AddArg(w3)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWstoreconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem)
-	// cond: ValAndOff(sc).canAdd(off)
-	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	// match: (ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		sc := v.AuxInt
-		s := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		_ = v.Args[1]
+		s0 := v.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		off := v_0.AuxInt
-		ptr := v_0.Args[0]
-		mem := v.Args[1]
-		if !(ValAndOff(sc).canAdd(off)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XMOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = s
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstoreconst [sc] {sym1} (MOVDaddr [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 != OpS390XMOVDaddr {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			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)) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVWstoreconst)
-		v.AuxInt = ValAndOff(sc).add(off)
-		v.Aux = mergeSym(sym1, sym2)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
-	// cond: p.Op != OpSB   && x.Uses == 1   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()   && clobber(x)
-	// result: (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem)
-	for {
-		c := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		x := v.Args[1]
-		if x.Op != OpS390XMOVWstoreconst {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		a := x.AuxInt
-		if x.Aux != s {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if p != x.Args[0] {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		mem := x.Args[1]
-		if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+		if p != x1.Args[1] {
 			break
 		}
-		v.reset(OpS390XMOVDstore)
-		v.AuxInt = ValAndOff(a).Off()
-		v.Aux = s
-		v.AddArg(p)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
-		v0.AuxInt = ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32
-		v.AddArg(v0)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMOVWstoreidx(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem)
-	// cond:
-	// result: (MOVWstoreidx [c+d] {sym} ptr idx val mem)
-	for {
-		c := v.AuxInt
-		sym := v.Aux
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XADDconst {
+		if mem != x1.Args[2] {
 			break
 		}
-		d := v_0.AuxInt
-		ptr := v_0.Args[0]
-		idx := v.Args[1]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
-	// cond:
-	// result: (MOVWstoreidx [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 != OpS390XADDconst {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		d := v_1.AuxInt
-		idx := v_1.Args[0]
-		val := v.Args[2]
-		mem := v.Args[3]
-		v.reset(OpS390XMOVWstoreidx)
-		v.AuxInt = c + d
-		v.Aux = sym
-		v.AddArg(ptr)
-		v.AddArg(idx)
-		v.AddArg(val)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDstoreidx [i-4] {s} p idx w mem)
+	// match: (ORW or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w := v.Args[2]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVWstoreidx {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if x.AuxInt != i-4 {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x.Aux != s {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x.Args[0] {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x.Args[1] {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRDconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x_2.AuxInt != 32 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if idx != x0.Args[1] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w)
-		v.AddArg(mem)
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem))
-	// cond: x.Uses == 1   && clobber(x)
-	// result: (MOVDstoreidx [i-4] {s} p idx w0 mem)
+	// match: (ORW or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		i := v.AuxInt
-		s := v.Aux
-		p := v.Args[0]
-		idx := v.Args[1]
-		w0 := v.Args[2]
-		if w0.Op != OpS390XSRDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		j := w0.AuxInt
-		w := w0.Args[0]
-		x := v.Args[3]
-		if x.Op != OpS390XMOVWstoreidx {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x.AuxInt != i-4 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x.Aux != s {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if p != x.Args[0] {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if idx != x.Args[1] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		x_2 := x.Args[2]
-		if x_2.Op != OpS390XSRDconst {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x_2.AuxInt != j+32 {
+		if idx != x0.Args[1] {
 			break
 		}
-		if w != x_2.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		mem := x.Args[3]
-		if !(x.Uses == 1 && clobber(x)) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVDstoreidx)
-		v.AuxInt = i - 4
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(idx)
-		v.AddArg(w0)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMULLD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULLD x (MOVDconst [c]))
-	// cond: is32Bit(c)
-	// result: (MULLDconst [c] x)
+	// match: (ORW or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		c := v_1.AuxInt
-		if !(is32Bit(c)) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMULLDconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLD (MOVDconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (MULLDconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(is32Bit(c)) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMULLDconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLD <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLDload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVDload {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMULLDload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLDload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVDload {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if idx != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMULLDload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XMULLDconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULLDconst [-1] x)
-	// cond:
-	// result: (NEG x)
-	for {
-		if v.AuxInt != -1 {
+		if mem != x0.Args[2] {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpS390XNEG)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLDconst [0] _)
-	// cond:
-	// result: (MOVDconst [0])
-	for {
-		if v.AuxInt != 0 {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = 0
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MULLDconst [1] x)
-	// cond:
-	// result: x
+	// match: (ORW or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		if v.AuxInt != 1 {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLDconst [c] x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLDconst [log2(c)] x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c)) {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XSLDconst)
-		v.AuxInt = log2(c)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLDconst [c] x)
-	// cond: isPowerOfTwo(c+1) && c >= 15
-	// result: (SUB (SLDconst <v.Type> [log2(c+1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c+1) && c >= 15) {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XSUB)
-		v0 := b.NewValue0(v.Line, OpS390XSLDconst, v.Type)
-		v0.AuxInt = log2(c + 1)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLDconst [c] x)
-	// cond: isPowerOfTwo(c-1) && c >= 17
-	// result: (ADD (SLDconst <v.Type> [log2(c-1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-1) && c >= 17) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		v.reset(OpS390XADD)
-		v0 := b.NewValue0(v.Line, OpS390XSLDconst, v.Type)
-		v0.AuxInt = log2(c - 1)
-		v0.AddArg(x)
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MULLDconst [c] (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [c*d])
+	// match: (ORW or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) y) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = c * d
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XMULLW(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XORW_50(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (MULLW x (MOVDconst [c]))
-	// cond:
-	// result: (MULLWconst [c] x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW or:(ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) y) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpS390XMULLWconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLW (MOVDconst [c]) x)
-	// cond:
-	// result: (MULLWconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = or.Args[1]
+		s1 := or.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpS390XMULLWconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVWload {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		y := or.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMULLWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVWload {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XMULLWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVWZload {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if p != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XMULLWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (MULLWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVWZload {
+		if mem != x0.Args[2] {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		v.reset(OpS390XMULLWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XMULLWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (MULLWconst [-1] x)
-	// cond:
-	// result: (NEGW x)
+	// match: (ORW or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem))) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		if v.AuxInt != -1 {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpS390XNEGW)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLWconst [0] _)
-	// cond:
-	// result: (MOVDconst [0])
-	for {
-		if v.AuxInt != 0 {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (MULLWconst [1] x)
-	// cond:
-	// result: x
-	for {
-		if v.AuxInt != 1 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x := v.Args[0]
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
+			break
+		}
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MULLWconst [c] x)
-	// cond: isPowerOfTwo(c)
-	// result: (SLWconst [log2(c)] x)
+	// match: (ORW or:(ORW y s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem))) s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+1   && j1 == j0-8   && j1 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c)) {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		y := or.Args[0]
+		s1 := or.Args[1]
+		if s1.Op != OpS390XSLWconst {
+			break
+		}
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		if x0.Aux != s {
+			break
+		}
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		v.reset(OpS390XSLWconst)
-		v.AuxInt = log2(c)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLWconst [c] x)
-	// cond: isPowerOfTwo(c+1) && c >= 15
-	// result: (SUBW (SLWconst <v.Type> [log2(c+1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c+1) && c >= 15) {
+		if p != x0.Args[1] {
 			break
 		}
-		v.reset(OpS390XSUBW)
-		v0 := b.NewValue0(v.Line, OpS390XSLWconst, v.Type)
-		v0.AuxInt = log2(c + 1)
-		v0.AddArg(x)
-		v.AddArg(v0)
-		v.AddArg(x)
-		return true
-	}
-	// match: (MULLWconst [c] x)
-	// cond: isPowerOfTwo(c-1) && c >= 17
-	// result: (ADDW (SLWconst <v.Type> [log2(c-1)] x) x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(isPowerOfTwo(c-1) && c >= 17) {
+		if mem != x0.Args[2] {
 			break
 		}
-		v.reset(OpS390XADDW)
-		v0 := b.NewValue0(v.Line, OpS390XSLWconst, v.Type)
-		v0.AuxInt = log2(c - 1)
-		v0.AddArg(x)
+		if !(i1 == i0+1 && j1 == j0-8 && j1%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j1
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZloadidx, typ.UInt16)
+		v2.AuxInt = i0
+		v2.Aux = s
+		v2.AddArg(p)
+		v2.AddArg(idx)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (MULLWconst [c] (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [int64(int32(c*d))])
+	// match: (ORW x0:(MOVBZload [i0] {s} p mem) sh:(SLWconst [8] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
 	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(int32(c * d))
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XNEG(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NEG (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [-c])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = -c
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XNEGW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NEGW (MOVDconst [c]))
-	// cond:
-	// result: (MOVDconst [int64(int32(-c))])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		if sh.AuxInt != 8 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = int64(int32(-c))
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XNOT(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOT x)
-	// cond: true
-	// result: (XOR (MOVDconst [-1]) x)
-	for {
-		x := v.Args[0]
-		if !(true) {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		v.reset(OpS390XXOR)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
-		v0.AuxInt = -1
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
 		v.AddArg(v0)
-		v.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XNOTW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NOTW x)
-	// cond: true
-	// result: (XORWconst [-1] x)
+	// match: (ORW sh:(SLWconst [8] x1:(MOVBZload [i1] {s} p mem)) x0:(MOVBZload [i0] {s} p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem))
 	for {
-		x := v.Args[0]
-		if !(true) {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XXORWconst)
-		v.AuxInt = -1
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (OR x (MOVDconst [c]))
-	// cond: isU32Bit(c)
-	// result: (ORconst [c] x)
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		if sh.AuxInt != 8 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(isU32Bit(c)) {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		v.reset(OpS390XORconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (OR (MOVDconst [c]) x)
-	// cond: isU32Bit(c)
-	// result: (ORconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isU32Bit(c)) {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		v.reset(OpS390XORconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (OR (MOVDconst [c]) (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [c|d])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		if mem != x0.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = c | d
-		return true
-	}
-	// match: (OR x x)
-	// cond:
-	// result: x
-	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (OR <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORload <t> [off] {sym} x ptr mem)
+	// match: (ORW r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)) sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRload [i0] {s} p mem)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVDload {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
 			break
 		}
-		v.reset(OpS390XORload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (OR <t> g:(MOVDload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVDload {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if sh.AuxInt != 16 {
 			break
 		}
-		v.reset(OpS390XORload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR                       x0:(MOVBZload [i]   {s} p mem)     s0:(SLDconst [8]  x1:(MOVBZload [i+1] {s} p mem)))     s1:(SLDconst [16] x2:(MOVBZload [i+2] {s} p mem)))     s2:(SLDconst [24] x3:(MOVBZload [i+3] {s} p mem)))     s3:(SLDconst [32] x4:(MOVBZload [i+4] {s} p mem)))     s4:(SLDconst [40] x5:(MOVBZload [i+5] {s} p mem)))     s5:(SLDconst [48] x6:(MOVBZload [i+6] {s} p mem)))     s6:(SLDconst [56] x7:(MOVBZload [i+7] {s} p mem)))
-	// cond: p.Op != OpSB   && 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)   && cl [...]
-	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDBRload [i] {s} p mem)
-	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XOR {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
+			break
+		}
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
+			break
+		}
+		i1 := x1.AuxInt
+		if x1.Aux != s {
+			break
+		}
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
 			break
 		}
-		o1 := o0.Args[0]
-		if o1.Op != OpS390XOR {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		o2 := o1.Args[0]
-		if o2.Op != OpS390XOR {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))) r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRload [i0] {s} p mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		o3 := o2.Args[0]
-		if o3.Op != OpS390XOR {
+		if sh.AuxInt != 16 {
 			break
 		}
-		o4 := o3.Args[0]
-		if o4.Op != OpS390XOR {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpS390XOR {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRload {
 			break
 		}
-		x0 := o5.Args[0]
-		if x0.Op != OpS390XMOVBZload {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o5.Args[1]
-		if s0.Op != OpS390XSLDconst {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRload {
 			break
 		}
-		if s0.AuxInt != 8 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		if mem != x0.Args[1] {
 			break
 		}
-		if x1.Aux != s {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if p != x1.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRload, typ.UInt32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) or:(ORW s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x1.Args[1] {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpS390XSLDconst {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if s1.AuxInt != 16 {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZload {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		if x2.AuxInt != i+2 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x2.Aux != s {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		if p != x2.Args[0] {
+		if mem != x0.Args[1] {
 			break
 		}
-		if mem != x2.Args[1] {
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpS390XSLDconst {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) or:(ORW y s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if s2.AuxInt != 24 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpS390XMOVBZload {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[1]
+		p := x1.Args[0]
+		mem := x1.Args[1]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if x3.AuxInt != i+3 {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x3.Aux != s {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		if p != x3.Args[0] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if mem != x3.Args[1] {
+		_ = x0.Args[1]
+		if p != x0.Args[0] {
 			break
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpS390XSLDconst {
+		if mem != x0.Args[1] {
 			break
 		}
-		if s3.AuxInt != 32 {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpS390XMOVBZload {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW or:(ORW s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) y) s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if x4.AuxInt != i+4 {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x4.Aux != s {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		if p != x4.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x4.Args[1] {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpS390XSLDconst {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if s4.AuxInt != 40 {
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpS390XMOVBZload {
+		if mem != x1.Args[1] {
 			break
 		}
-		if x5.AuxInt != i+5 {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if x5.Aux != s {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XORW_60(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW or:(ORW y s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem))) s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if p != x5.Args[0] {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x5.Args[1] {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZload {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpS390XSLDconst {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[1]
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if s5.AuxInt != 48 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZload {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpS390XMOVBZload {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x6.AuxInt != i+6 {
+		_ = x1.Args[1]
+		if p != x1.Args[0] {
 			break
 		}
-		if x6.Aux != s {
+		if mem != x1.Args[1] {
 			break
 		}
-		if p != x6.Args[0] {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if mem != x6.Args[1] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRload, typ.UInt16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW x0:(MOVBZloadidx [i0] {s} p idx mem) sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpS390XSLDconst {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if s6.AuxInt != 56 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpS390XMOVBZload {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x7.AuxInt != i+7 {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x7.Aux != s {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if p != x7.Args[0] {
+		if idx != x1.Args[1] {
 			break
 		}
-		if mem != x7.Args[1] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && 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) && cl [...]
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDBRload, config.fe.TypeUInt64())
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR                       x0:(MOVBZloadidx [i]   {s} p idx mem)     s0:(SLDconst [8]  x1:(MOVBZloadidx [i+1] {s} p idx mem)))     s1:(SLDconst [16] x2:(MOVBZloadidx [i+2] {s} p idx mem)))     s2:(SLDconst [24] x3:(MOVBZloadidx [i+3] {s} p idx mem)))     s3:(SLDconst [32] x4:(MOVBZloadidx [i+4] {s} p idx mem)))     s4:(SLDconst [40] x5:(MOVBZloadidx [i+5] {s} p idx mem)))     s5:(SLDconst [48] x6:(MOVBZloadidx [i+6] {s} p idx mem)))     [...]
-	// 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) (MOVDBRloadidx <v.Type> [i] {s} p idx mem)
+	// match: (ORW x0:(MOVBZloadidx [i0] {s} idx p mem) sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XOR {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
+			break
+		}
+		if sh.AuxInt != 8 {
+			break
+		}
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		o1 := o0.Args[0]
-		if o1.Op != OpS390XOR {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		o2 := o1.Args[0]
-		if o2.Op != OpS390XOR {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		o3 := o2.Args[0]
-		if o3.Op != OpS390XOR {
+		if idx != x1.Args[1] {
 			break
 		}
-		o4 := o3.Args[0]
-		if o4.Op != OpS390XOR {
+		if mem != x1.Args[2] {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpS390XOR {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		x0 := o5.Args[0]
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW x0:(MOVBZloadidx [i0] {s} p idx mem) sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
 		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[2]
 		p := x0.Args[0]
 		idx := x0.Args[1]
 		mem := x0.Args[2]
-		s0 := o5.Args[1]
-		if s0.Op != OpS390XSLDconst {
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		x1 := s0.Args[0]
+		x1 := sh.Args[0]
 		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x1.AuxInt != i+1 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if idx != x1.Args[1] {
+		if p != x1.Args[1] {
 			break
 		}
 		if mem != x1.Args[2] {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpS390XSLDconst {
-			break
-		}
-		if s1.AuxInt != 16 {
-			break
-		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZloadidx {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		if x2.AuxInt != i+2 {
-			break
-		}
-		if x2.Aux != s {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW x0:(MOVBZloadidx [i0] {s} idx p mem) sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		x0 := v.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x2.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x2.Args[1] {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if mem != x2.Args[2] {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpS390XSLDconst {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if s2.AuxInt != 24 {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpS390XMOVBZloadidx {
+		if p != x1.Args[1] {
 			break
 		}
-		if x3.AuxInt != i+3 {
+		if mem != x1.Args[2] {
 			break
 		}
-		if x3.Aux != s {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		if p != x3.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)) x0:(MOVBZloadidx [i0] {s} p idx mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x3.Args[1] {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if mem != x3.Args[2] {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpS390XSLDconst {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s3.AuxInt != 32 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpS390XMOVBZloadidx {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x4.AuxInt != i+4 {
+		if idx != x0.Args[1] {
 			break
 		}
-		if x4.Aux != s {
+		if mem != x0.Args[2] {
 			break
 		}
-		if p != x4.Args[0] {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		if idx != x4.Args[1] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)) x0:(MOVBZloadidx [i0] {s} p idx mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x4.Args[2] {
+		if sh.AuxInt != 8 {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpS390XSLDconst {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s4.AuxInt != 40 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpS390XMOVBZloadidx {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x5.AuxInt != i+5 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x5.Aux != s {
+		if idx != x0.Args[1] {
 			break
 		}
-		if p != x5.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if idx != x5.Args[1] {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		if mem != x5.Args[2] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem)) x0:(MOVBZloadidx [i0] {s} idx p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpS390XSLDconst {
+		if sh.AuxInt != 8 {
 			break
 		}
-		if s5.AuxInt != 48 {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpS390XMOVBZloadidx {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x6.AuxInt != i+6 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x6.Aux != s {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if p != x6.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		if idx != x6.Args[1] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if mem != x6.Args[2] {
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpS390XSLDconst {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} idx p mem)) x0:(MOVBZloadidx [i0] {s} idx p mem))
+	// cond: p.Op != OpSB   && i1 == i0+1   && x0.Uses == 1   && x1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if s6.AuxInt != 56 {
+		if sh.AuxInt != 8 {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpS390XMOVBZloadidx {
+		x1 := sh.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x7.AuxInt != i+7 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		x0 := v.Args[1]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x7.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x7.Args[0] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if idx != x7.Args[1] {
+		if p != x0.Args[1] {
 			break
 		}
-		if mem != x7.Args[2] {
+		if mem != x0.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 [...]
+		if !(p.Op != OpSB && i1 == i0+1 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(sh)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDBRloadidx, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v1.AuxInt = i0
+		v1.Aux = s
+		v1.AddArg(p)
+		v1.AddArg(idx)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
 		return true
 	}
-	// match: (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR                       x0:(MOVBZload [i]   {s} p mem)     s0:(SLDconst [8]  x1:(MOVBZload [i-1] {s} p mem)))     s1:(SLDconst [16] x2:(MOVBZload [i-2] {s} p mem)))     s2:(SLDconst [24] x3:(MOVBZload [i-3] {s} p mem)))     s3:(SLDconst [32] x4:(MOVBZload [i-4] {s} p mem)))     s4:(SLDconst [40] x5:(MOVBZload [i-5] {s} p mem)))     s5:(SLDconst [48] x6:(MOVBZload [i-6] {s} p mem)))     s6:(SLDconst [56] x7:(MOVBZload [i-7] {s} p mem)))
-	// cond: p.Op != OpSB   && 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)   && cl [...]
-	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDload [i-7] {s} p mem)
+	// match: (ORW r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XOR {
-			break
-		}
-		o1 := o0.Args[0]
-		if o1.Op != OpS390XOR {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		o2 := o1.Args[0]
-		if o2.Op != OpS390XOR {
-			break
-		}
-		o3 := o2.Args[0]
-		if o3.Op != OpS390XOR {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		o4 := o3.Args[0]
-		if o4.Op != OpS390XOR {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpS390XOR {
+		if sh.AuxInt != 16 {
 			break
 		}
-		x0 := o5.Args[0]
-		if x0.Op != OpS390XMOVBZload {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o5.Args[1]
-		if s0.Op != OpS390XSLDconst {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if s0.AuxInt != 8 {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		if idx != x1.Args[1] {
 			break
 		}
-		if x1.Aux != s {
+		if mem != x1.Args[2] {
 			break
 		}
-		if p != x1.Args[0] {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if mem != x1.Args[1] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XORW_70(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)) sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpS390XSLDconst {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if s1.AuxInt != 16 {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZload {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x2.Aux != s {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x2.Args[0] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if mem != x2.Args[1] {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpS390XSLDconst {
+		if idx != x1.Args[1] {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if mem != x1.Args[2] {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpS390XMOVBZload {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x3.Aux != s {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if p != x3.Args[0] {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x3.Args[1] {
+		if sh.AuxInt != 16 {
 			break
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpS390XSLDconst {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if s3.AuxInt != 32 {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpS390XMOVBZload {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x4.AuxInt != i-4 {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if x4.Aux != s {
+		if p != x1.Args[1] {
 			break
 		}
-		if p != x4.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if mem != x4.Args[1] {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpS390XSLDconst {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)) sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		r0 := v.Args[0]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if s4.AuxInt != 40 {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpS390XMOVBZload {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		sh := v.Args[1]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if x5.AuxInt != i-5 {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if x5.Aux != s {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if p != x5.Args[0] {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if mem != x5.Args[1] {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpS390XSLDconst {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if s5.AuxInt != 48 {
+		if p != x1.Args[1] {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpS390XMOVBZload {
+		if mem != x1.Args[2] {
 			break
 		}
-		if x6.AuxInt != i-6 {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if x6.Aux != s {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if p != x6.Args[0] {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if mem != x6.Args[1] {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpS390XSLDconst {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if s6.AuxInt != 56 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpS390XMOVBZload {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x7.AuxInt != i-7 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x7.Aux != s {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if p != x7.Args[0] {
+		if idx != x0.Args[1] {
 			break
 		}
-		if mem != x7.Args[1] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && 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) && cl [...]
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 7
+		v0.AuxInt = i0
 		v0.Aux = s
 		v0.AddArg(p)
+		v0.AddArg(idx)
 		v0.AddArg(mem)
 		return true
 	}
-	// match: (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR                       x0:(MOVBZloadidx [i]   {s} p idx mem)     s0:(SLDconst [8]  x1:(MOVBZloadidx [i-1] {s} p idx mem)))     s1:(SLDconst [16] x2:(MOVBZloadidx [i-2] {s} p idx mem)))     s2:(SLDconst [24] x3:(MOVBZloadidx [i-3] {s} p idx mem)))     s3:(SLDconst [32] x4:(MOVBZloadidx [i-4] {s} p idx mem)))     s4:(SLDconst [40] x5:(MOVBZloadidx [i-5] {s} p idx mem)))     s5:(SLDconst [48] x6:(MOVBZloadidx [i-6] {s} p idx mem)))     [...]
-	// 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) (MOVDloadidx <v.Type> [i-7] {s} p idx mem)
+	// match: (ORW sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XOR {
-			break
-		}
-		o1 := o0.Args[0]
-		if o1.Op != OpS390XOR {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		o2 := o1.Args[0]
-		if o2.Op != OpS390XOR {
+		if sh.AuxInt != 16 {
 			break
 		}
-		o3 := o2.Args[0]
-		if o3.Op != OpS390XOR {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		o4 := o3.Args[0]
-		if o4.Op != OpS390XOR {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		o5 := o4.Args[0]
-		if o5.Op != OpS390XOR {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		x0 := o5.Args[0]
-		if x0.Op != OpS390XMOVBZloadidx {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			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 != OpS390XSLDconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if s0.AuxInt != 8 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZloadidx {
+		if idx != x0.Args[1] {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		if mem != x0.Args[2] {
 			break
 		}
-		if x1.Aux != s {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if p != x1.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x1.Args[1] {
+		if sh.AuxInt != 16 {
 			break
 		}
-		if mem != x1.Args[2] {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		s1 := o4.Args[1]
-		if s1.Op != OpS390XSLDconst {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if s1.AuxInt != 16 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZloadidx {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x2.Aux != s {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if p != x2.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		if idx != x2.Args[1] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if mem != x2.Args[2] {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		s2 := o3.Args[1]
-		if s2.Op != OpS390XSLDconst {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} idx p mem))) r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} idx p mem)))
+	// cond: i1 == i0+2   && x0.Uses == 1   && x1.Uses == 1   && r0.Uses == 1   && r1.Uses == 1   && sh.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(r0)   && clobber(r1)   && clobber(sh)
+	// result: @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem)
+	for {
+		_ = v.Args[1]
+		sh := v.Args[0]
+		if sh.Op != OpS390XSLWconst {
 			break
 		}
-		if s2.AuxInt != 24 {
+		if sh.AuxInt != 16 {
 			break
 		}
-		x3 := s2.Args[0]
-		if x3.Op != OpS390XMOVBZloadidx {
+		r1 := sh.Args[0]
+		if r1.Op != OpS390XMOVHZreg {
 			break
 		}
-		if x3.AuxInt != i-3 {
+		x1 := r1.Args[0]
+		if x1.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if x3.Aux != s {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		r0 := v.Args[1]
+		if r0.Op != OpS390XMOVHZreg {
 			break
 		}
-		if p != x3.Args[0] {
+		x0 := r0.Args[0]
+		if x0.Op != OpS390XMOVHBRloadidx {
 			break
 		}
-		if idx != x3.Args[1] {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if mem != x3.Args[2] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		s3 := o2.Args[1]
-		if s3.Op != OpS390XSLDconst {
+		if p != x0.Args[1] {
 			break
 		}
-		if s3.AuxInt != 32 {
+		if mem != x0.Args[2] {
 			break
 		}
-		x4 := s3.Args[0]
-		if x4.Op != OpS390XMOVBZloadidx {
+		if !(i1 == i0+2 && x0.Uses == 1 && x1.Uses == 1 && r0.Uses == 1 && r1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(r0) && clobber(r1) && clobber(sh)) {
 			break
 		}
-		if x4.AuxInt != i-4 {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWBRloadidx, typ.Int32)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i0
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x4.Aux != s {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if p != x4.Args[0] {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		if idx != x4.Args[1] {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if mem != x4.Args[2] {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		s4 := o1.Args[1]
-		if s4.Op != OpS390XSLDconst {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if s4.AuxInt != 40 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		x5 := s4.Args[0]
-		if x5.Op != OpS390XMOVBZloadidx {
+		if idx != x0.Args[1] {
 			break
 		}
-		if x5.AuxInt != i-5 {
+		if mem != x0.Args[2] {
 			break
 		}
-		if x5.Aux != s {
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if p != x5.Args[0] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if idx != x5.Args[1] {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if mem != x5.Args[2] {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		s5 := o0.Args[1]
-		if s5.Op != OpS390XSLDconst {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s5.AuxInt != 48 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x6 := s5.Args[0]
-		if x6.Op != OpS390XMOVBZloadidx {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x6.AuxInt != i-6 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x6.Aux != s {
+		if idx != x0.Args[1] {
 			break
 		}
-		if p != x6.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if idx != x6.Args[1] {
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if mem != x6.Args[2] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		s6 := v.Args[1]
-		if s6.Op != OpS390XSLDconst {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s6.AuxInt != 56 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x7 := s6.Args[0]
-		if x7.Op != OpS390XMOVBZloadidx {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x7.AuxInt != i-7 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x7.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x7.Args[0] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if idx != x7.Args[1] {
+		if p != x0.Args[1] {
 			break
 		}
-		if mem != x7.Args[2] {
+		if mem != x0.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 [...]
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDloadidx, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 7
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XORW(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XORW_80(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (ORW x (MOVDconst [c]))
-	// cond:
-	// result: (ORWconst [c] x)
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
-			break
-		}
-		c := v_1.AuxInt
-		v.reset(OpS390XORWconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (ORW (MOVDconst [c]) x)
-	// cond:
-	// result: (ORWconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
-			break
-		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpS390XORWconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (ORW 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: (ORW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORWload <t> [off] {sym} x ptr mem)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVWload {
-			break
-		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XORWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (ORW <t> g:(MOVWload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVWload {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		v.reset(OpS390XORWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (ORW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVWZload {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		v.reset(OpS390XORWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
-		return true
-	}
-	// match: (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (ORWload <t> [off] {sym} x ptr mem)
-	for {
-		t := v.Type
-		g := v.Args[0]
-		if g.Op != OpS390XMOVWZload {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		off := g.AuxInt
-		sym := g.Aux
-		ptr := g.Args[0]
-		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		v.reset(OpS390XORWload)
-		v.Type = t
-		v.AuxInt = off
-		v.Aux = sym
-		v.AddArg(x)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		if p != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
+			break
+		}
+		y := or.Args[1]
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW                 x0:(MOVBZload [i]   {s} p mem)     s0:(SLWconst [8] x1:(MOVBZload [i+1] {s} p mem)))
-	// cond: p.Op != OpSB   && 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) (MOVHZreg (MOVHBRload [i] {s} p mem))
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x0 := v.Args[0]
-		if x0.Op != OpS390XMOVBZload {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := v.Args[1]
-		if s0.Op != OpS390XSLWconst {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s0.AuxInt != 8 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x1.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if mem != x1.Args[1] {
+		if idx != x0.Args[1] {
+			break
+		}
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHBRload, config.fe.TypeUInt16())
-		v1.AuxInt = i
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
 		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRload [i] {s} p mem))     s0:(SLWconst [16] x1:(MOVBZload [i+2] {s} p mem)))     s1:(SLWconst [24] x2:(MOVBZload [i+3] {s} p mem)))
-	// cond: p.Op != OpSB   && z0.Uses == 1   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(z0)   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVWBRload [i] {s} p mem)
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XORW {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		z0 := o0.Args[0]
-		if z0.Op != OpS390XMOVHZreg {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x0 := z0.Args[0]
-		if x0.Op != OpS390XMOVHBRload {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
 		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 16 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x1.AuxInt != i+2 {
+		_ = x0.Args[2]
+		if p != x0.Args[0] {
 			break
 		}
-		if x1.Aux != s {
+		if idx != x0.Args[1] {
 			break
 		}
-		if p != x1.Args[0] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if mem != x1.Args[1] {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		s1 := v.Args[1]
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		s1 := v.Args[0]
 		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if s1.AuxInt != 24 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
+			break
+		}
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		p := x1.Args[0]
+		idx := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZload {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if x2.Aux != s {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if p != x2.Args[0] {
+		if p != x0.Args[1] {
 			break
 		}
-		if mem != x2.Args[1] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && z0.Uses == 1 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(z0) && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWBRload, config.fe.TypeUInt32())
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)     s0:(SLWconst [8] x1:(MOVBZloadidx [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) (MOVHZreg (MOVHBRloadidx <v.Type> [i] {s} p idx mem))
+	// match: (ORW s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)) or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x0 := v.Args[0]
-		if x0.Op != OpS390XMOVBZloadidx {
+		_ = v.Args[1]
+		s1 := v.Args[0]
+		if s1.Op != OpS390XSLWconst {
 			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 != OpS390XSLWconst {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s0.AuxInt != 8 {
+		i1 := x1.AuxInt
+		s := x1.Aux
+		_ = x1.Args[2]
+		idx := x1.Args[0]
+		p := x1.Args[1]
+		mem := x1.Args[2]
+		or := v.Args[1]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZloadidx {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if x1.AuxInt != i+1 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x1.Aux != s {
+		i0 := x0.AuxInt
+		if x0.Aux != s {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = x0.Args[2]
+		if idx != x0.Args[0] {
 			break
 		}
-		if idx != x1.Args[1] {
+		if p != x0.Args[1] {
 			break
 		}
-		if mem != x1.Args[2] {
+		if mem != x0.Args[2] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVHBRloadidx, v.Type)
-		v1.AuxInt = i
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(idx)
-		v1.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
 		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRloadidx [i] {s} p idx mem))     s0:(SLWconst [16] x1:(MOVBZloadidx [i+2] {s} p idx mem)))     s1:(SLWconst [24] x2:(MOVBZloadidx [i+3] {s} p idx mem)))
-	// cond: z0.Uses == 1   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(z0)   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVWZreg (MOVWBRloadidx <v.Type> [i] {s} p idx mem))
+	// match: (ORW or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XORW {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		z0 := o0.Args[0]
-		if z0.Op != OpS390XMOVHZreg {
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		x0 := z0.Args[0]
-		if x0.Op != OpS390XMOVHBRloadidx {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[2]
 		p := x0.Args[0]
 		idx := x0.Args[1]
 		mem := x0.Args[2]
-		s0 := o0.Args[1]
-		if s0.Op != OpS390XSLWconst {
-			break
-		}
-		if s0.AuxInt != 16 {
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		x1 := s0.Args[0]
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
 		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x1.AuxInt != i+2 {
-			break
-		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
@@ -15481,312 +33797,535 @@ func rewriteValueS390X_OpS390XORW(v *Value, config *Config) bool {
 		if mem != x1.Args[2] {
 			break
 		}
-		s1 := v.Args[1]
-		if s1.Op != OpS390XSLWconst {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s1.AuxInt != 24 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZloadidx {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x2.AuxInt != i+3 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x2.Aux != s {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if p != x2.Args[0] {
+		_ = x1.Args[2]
+		if p != x1.Args[0] {
 			break
 		}
-		if idx != x2.Args[1] {
+		if idx != x1.Args[1] {
 			break
 		}
-		if mem != x2.Args[2] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if !(z0.Uses == 1 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(z0) && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XMOVWBRloadidx, v.Type)
-		v1.AuxInt = i
-		v1.Aux = s
-		v1.AddArg(p)
-		v1.AddArg(idx)
-		v1.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
 		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW                  x0:(MOVBZload [i]   {s} p mem)     s0:(SLWconst [8] x1:(MOVBZload [i-1] {s} p mem)))
-	// cond: p.Op != OpSB   && 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) (MOVHZload [i-1] {s} p mem)
+	// match: (ORW or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x0 := v.Args[0]
-		if x0.Op != OpS390XMOVBZload {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := v.Args[1]
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
 		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
-		if mem != x1.Args[1] {
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 1
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW o0:(ORW x0:(MOVHZload [i] {s} p mem)     s0:(SLWconst [16] x1:(MOVBZload [i-1] {s} p mem)))     s1:(SLWconst [24] x2:(MOVBZload [i-2] {s} p mem)))
-	// cond: p.Op != OpSB   && x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVWZload [i-2] {s} p mem)
+	// match: (ORW or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XORW {
-			break
-		}
-		x0 := o0.Args[0]
-		if x0.Op != OpS390XMOVHZload {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		mem := x0.Args[1]
-		s0 := o0.Args[1]
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
 		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 16 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZload {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
+		_ = x1.Args[2]
 		if p != x1.Args[0] {
 			break
 		}
-		if mem != x1.Args[1] {
+		if idx != x1.Args[1] {
 			break
 		}
-		s1 := v.Args[1]
-		if s1.Op != OpS390XSLWconst {
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) y) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
+			break
+		}
+		_ = or.Args[1]
+		s0 := or.Args[0]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if s1.AuxInt != 24 {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZload {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x2.Aux != s {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if p != x2.Args[0] {
+		if p != x1.Args[1] {
 			break
 		}
-		if mem != x2.Args[1] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if !(p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 2
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)     s0:(SLWconst [8] x1:(MOVBZloadidx [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) (MOVHZloadidx <v.Type> [i-1] {s} p idx mem)
+	return false
+}
+func rewriteValueS390X_OpS390XORW_90(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ORW or:(ORW s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem)) y) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		x0 := v.Args[0]
-		if x0.Op != OpS390XMOVBZloadidx {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		i := x0.AuxInt
-		s := x0.Aux
-		p := x0.Args[0]
-		idx := x0.Args[1]
-		mem := x0.Args[2]
-		s0 := v.Args[1]
+		_ = or.Args[1]
+		s0 := or.Args[0]
 		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 8 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZloadidx {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		y := or.Args[1]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
+		i1 := x1.AuxInt
 		if x1.Aux != s {
 			break
 		}
-		if p != x1.Args[0] {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if idx != x1.Args[1] {
+		if p != 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)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
 		b = mergePoint(b, x0, x1)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHZloadidx, v.Type)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 1
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
-	// match: (ORW o0:(ORW x0:(MOVHZloadidx [i] {s} p idx mem)     s0:(SLWconst [16] x1:(MOVBZloadidx [i-1] {s} p idx mem)))     s1:(SLWconst [24] x2:(MOVBZloadidx [i-2] {s} p idx mem)))
-	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && o0.Uses == 1   && mergePoint(b,x0,x1,x2) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(s0)   && clobber(s1)   && clobber(o0)
-	// result: @mergePoint(b,x0,x1,x2) (MOVWZloadidx <v.Type> [i-2] {s} p idx mem)
+	// match: (ORW or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem))) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
 	for {
-		o0 := v.Args[0]
-		if o0.Op != OpS390XORW {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		x0 := o0.Args[0]
-		if x0.Op != OpS390XMOVHZloadidx {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
+			break
+		}
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		i := x0.AuxInt
+		i0 := x0.AuxInt
 		s := x0.Aux
+		_ = x0.Args[2]
 		p := x0.Args[0]
 		idx := x0.Args[1]
 		mem := x0.Args[2]
-		s0 := o0.Args[1]
-		if s0.Op != OpS390XSLWconst {
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if s0.AuxInt != 16 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x1 := s0.Args[0]
-		if x1.Op != OpS390XMOVBZloadidx {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if x1.AuxInt != i-1 {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if x1.Aux != s {
+		if p != x1.Args[1] {
 			break
 		}
-		if p != x1.Args[0] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if idx != x1.Args[1] {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		if mem != x1.Args[2] {
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
+		return true
+	}
+	// match: (ORW or:(ORW y s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} idx p mem))) s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} idx p mem)))
+	// cond: p.Op != OpSB   && i1 == i0+1   && j1 == j0+8   && j0 % 16 == 0   && x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && or.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)   && clobber(s1)   && clobber(or)
+	// result: @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y)
+	for {
+		_ = v.Args[1]
+		or := v.Args[0]
+		if or.Op != OpS390XORW {
 			break
 		}
-		s1 := v.Args[1]
-		if s1.Op != OpS390XSLWconst {
+		_ = or.Args[1]
+		y := or.Args[0]
+		s0 := or.Args[1]
+		if s0.Op != OpS390XSLWconst {
 			break
 		}
-		if s1.AuxInt != 24 {
+		j0 := s0.AuxInt
+		x0 := s0.Args[0]
+		if x0.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		x2 := s1.Args[0]
-		if x2.Op != OpS390XMOVBZloadidx {
+		i0 := x0.AuxInt
+		s := x0.Aux
+		_ = x0.Args[2]
+		idx := x0.Args[0]
+		p := x0.Args[1]
+		mem := x0.Args[2]
+		s1 := v.Args[1]
+		if s1.Op != OpS390XSLWconst {
 			break
 		}
-		if x2.AuxInt != i-2 {
+		j1 := s1.AuxInt
+		x1 := s1.Args[0]
+		if x1.Op != OpS390XMOVBZloadidx {
 			break
 		}
-		if x2.Aux != s {
+		i1 := x1.AuxInt
+		if x1.Aux != s {
 			break
 		}
-		if p != x2.Args[0] {
+		_ = x1.Args[2]
+		if idx != x1.Args[0] {
 			break
 		}
-		if idx != x2.Args[1] {
+		if p != x1.Args[1] {
 			break
 		}
-		if mem != x2.Args[2] {
+		if mem != x1.Args[2] {
 			break
 		}
-		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b, x0, x1, x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)) {
+		if !(p.Op != OpSB && i1 == i0+1 && j1 == j0+8 && j0%16 == 0 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && or.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0) && clobber(s1) && clobber(or)) {
 			break
 		}
-		b = mergePoint(b, x0, x1, x2)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWZloadidx, v.Type)
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Pos, OpS390XORW, v.Type)
 		v.reset(OpCopy)
 		v.AddArg(v0)
-		v0.AuxInt = i - 2
-		v0.Aux = s
-		v0.AddArg(p)
-		v0.AddArg(idx)
-		v0.AddArg(mem)
+		v1 := b.NewValue0(v.Pos, OpS390XSLWconst, v.Type)
+		v1.AuxInt = j0
+		v2 := b.NewValue0(v.Pos, OpS390XMOVHZreg, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpS390XMOVHBRloadidx, typ.Int16)
+		v3.AuxInt = i0
+		v3.Aux = s
+		v3.AddArg(p)
+		v3.AddArg(idx)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XORWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XORWconst_0(v *Value) bool {
 	// match: (ORWconst [c] x)
 	// cond: int32(c)==0
 	// result: x
@@ -15829,9 +34368,7 @@ func rewriteValueS390X_OpS390XORWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XORconst_0(v *Value) bool {
 	// match: (ORconst [0] x)
 	// cond:
 	// result: x
@@ -15872,13 +34409,12 @@ func rewriteValueS390X_OpS390XORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSLD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSLD_0(v *Value) bool {
 	// match: (SLD x (MOVDconst [c]))
 	// cond:
 	// result: (SLDconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -15894,6 +34430,7 @@ func rewriteValueS390X_OpS390XSLD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SLD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDconst {
@@ -15910,13 +34447,12 @@ func rewriteValueS390X_OpS390XSLD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSLW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSLW_0(v *Value) bool {
 	// match: (SLW x (MOVDconst [c]))
 	// cond:
 	// result: (SLWconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -15932,6 +34468,7 @@ func rewriteValueS390X_OpS390XSLW(v *Value, config *Config) bool {
 	// cond:
 	// result: (SLW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDWconst {
@@ -15948,13 +34485,12 @@ func rewriteValueS390X_OpS390XSLW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRAD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRAD_0(v *Value) bool {
 	// match: (SRAD x (MOVDconst [c]))
 	// cond:
 	// result: (SRADconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -15970,6 +34506,7 @@ func rewriteValueS390X_OpS390XSRAD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDconst {
@@ -15986,9 +34523,7 @@ func rewriteValueS390X_OpS390XSRAD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRADconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRADconst_0(v *Value) bool {
 	// match: (SRADconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [d>>uint64(c)])
@@ -16005,13 +34540,12 @@ func rewriteValueS390X_OpS390XSRADconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRAW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRAW_0(v *Value) bool {
 	// match: (SRAW x (MOVDconst [c]))
 	// cond:
 	// result: (SRAWconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -16027,6 +34561,7 @@ func rewriteValueS390X_OpS390XSRAW(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRAW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDWconst {
@@ -16043,9 +34578,7 @@ func rewriteValueS390X_OpS390XSRAW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRAWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
 	// match: (SRAWconst [c] (MOVDconst [d]))
 	// cond:
 	// result: (MOVDconst [d>>uint64(c)])
@@ -16062,13 +34595,12 @@ func rewriteValueS390X_OpS390XSRAWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRD(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRD_0(v *Value) bool {
 	// match: (SRD x (MOVDconst [c]))
 	// cond:
 	// result: (SRDconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -16084,6 +34616,7 @@ func rewriteValueS390X_OpS390XSRD(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRD x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDconst {
@@ -16100,13 +34633,12 @@ func rewriteValueS390X_OpS390XSRD(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSRW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSRW_0(v *Value) bool {
 	// match: (SRW x (MOVDconst [c]))
 	// cond:
 	// result: (SRWconst [c&63] x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
@@ -16122,6 +34654,7 @@ func rewriteValueS390X_OpS390XSRW(v *Value, config *Config) bool {
 	// cond:
 	// result: (SRW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XANDWconst {
@@ -16138,15 +34671,14 @@ func rewriteValueS390X_OpS390XSRW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSTM2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSTM2_0(v *Value) bool {
 	// match: (STM2 [i] {s} p w2 w3 x:(STM2 [i-8] {s} p w0 w1 mem))
 	// cond: x.Uses == 1   && is20Bit(i-8)   && clobber(x)
 	// result: (STM4 [i-8] {s} p w0 w1 w2 w3 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		w2 := v.Args[1]
 		w3 := v.Args[2]
@@ -16160,6 +34692,7 @@ func rewriteValueS390X_OpS390XSTM2(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
@@ -16186,6 +34719,7 @@ func rewriteValueS390X_OpS390XSTM2(v *Value, config *Config) bool {
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XSRDconst {
@@ -16209,15 +34743,14 @@ func rewriteValueS390X_OpS390XSTM2(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSTMG2(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XSTMG2_0(v *Value) bool {
 	// match: (STMG2 [i] {s} p w2 w3 x:(STMG2 [i-16] {s} p w0 w1 mem))
 	// cond: x.Uses == 1   && is20Bit(i-16)   && clobber(x)
 	// result: (STMG4 [i-16] {s} p w0 w1 w2 w3 mem)
 	for {
 		i := v.AuxInt
 		s := v.Aux
+		_ = v.Args[3]
 		p := v.Args[0]
 		w2 := v.Args[1]
 		w3 := v.Args[2]
@@ -16231,73 +34764,235 @@ func rewriteValueS390X_OpS390XSTMG2(v *Value, config *Config) bool {
 		if x.Aux != s {
 			break
 		}
+		_ = x.Args[3]
 		if p != x.Args[0] {
 			break
 		}
-		w0 := x.Args[1]
-		w1 := x.Args[2]
-		mem := x.Args[3]
-		if !(x.Uses == 1 && is20Bit(i-16) && clobber(x)) {
+		w0 := x.Args[1]
+		w1 := x.Args[2]
+		mem := x.Args[3]
+		if !(x.Uses == 1 && is20Bit(i-16) && clobber(x)) {
+			break
+		}
+		v.reset(OpS390XSTMG4)
+		v.AuxInt = i - 16
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(w1)
+		v.AddArg(w2)
+		v.AddArg(w3)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XSUB_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (SUB x (MOVDconst [c]))
+	// cond: is32Bit(c)
+	// result: (SUBconst x [c])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XSUBconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUB (MOVDconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (NEG (SUBconst <v.Type> x [c]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XNEG)
+		v0 := b.NewValue0(v.Pos, OpS390XSUBconst, v.Type)
+		v0.AuxInt = c
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SUB x x)
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SUB <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (SUBload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XSUBload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XSUBEWcarrymask_0(v *Value) bool {
+	// match: (SUBEWcarrymask (FlagEQ))
+	// cond:
+	// result: (MOVDconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SUBEWcarrymask (FlagLT))
+	// cond:
+	// result: (MOVDconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SUBEWcarrymask (FlagGT))
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagGT {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueS390X_OpS390XSUBEcarrymask_0(v *Value) bool {
+	// match: (SUBEcarrymask (FlagEQ))
+	// cond:
+	// result: (MOVDconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagEQ {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SUBEcarrymask (FlagLT))
+	// cond:
+	// result: (MOVDconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagLT {
+			break
+		}
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SUBEcarrymask (FlagGT))
+	// cond:
+	// result: (MOVDconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XFlagGT {
 			break
 		}
-		v.reset(OpS390XSTMG4)
-		v.AuxInt = i - 16
-		v.Aux = s
-		v.AddArg(p)
-		v.AddArg(w0)
-		v.AddArg(w1)
-		v.AddArg(w2)
-		v.AddArg(w3)
-		v.AddArg(mem)
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSUB(v *Value, config *Config) bool {
+func rewriteValueS390X_OpS390XSUBW_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (SUB x (MOVDconst [c]))
-	// cond: is32Bit(c)
-	// result: (SUBconst x [c])
+	// match: (SUBW x (MOVDconst [c]))
+	// cond:
+	// result: (SUBWconst x [c])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
 		c := v_1.AuxInt
-		if !(is32Bit(c)) {
-			break
-		}
-		v.reset(OpS390XSUBconst)
+		v.reset(OpS390XSUBWconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (SUB (MOVDconst [c]) x)
-	// cond: is32Bit(c)
-	// result: (NEG (SUBconst <v.Type> x [c]))
+	// match: (SUBW (MOVDconst [c]) x)
+	// cond:
+	// result: (NEGW (SUBWconst <v.Type> x [c]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
 		c := v_0.AuxInt
 		x := v.Args[1]
-		if !(is32Bit(c)) {
-			break
-		}
-		v.reset(OpS390XNEG)
-		v0 := b.NewValue0(v.Line, OpS390XSUBconst, v.Type)
+		v.reset(OpS390XNEGW)
+		v0 := b.NewValue0(v.Pos, OpS390XSUBWconst, v.Type)
 		v0.AuxInt = c
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (SUB x x)
+	// match: (SUBW x x)
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -16306,24 +35001,54 @@ func rewriteValueS390X_OpS390XSUB(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (SUB <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (SUBload <t> [off] {sym} x ptr mem)
+	// match: (SUBW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (SUBWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
-		if g.Op != OpS390XMOVDload {
+		if g.Op != OpS390XMOVWload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XSUBload)
+		v.reset(OpS390XSUBWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (SUBWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWZload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XSUBWload)
 		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
@@ -16334,127 +35059,232 @@ func rewriteValueS390X_OpS390XSUB(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSUBEWcarrymask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBEWcarrymask (FlagEQ))
+func rewriteValueS390X_OpS390XSUBWconst_0(v *Value) bool {
+	// match: (SUBWconst [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: (SUBWconst [c] x)
 	// cond:
-	// result: (MOVDconst [-1])
+	// result: (ADDWconst [int64(int32(-c))] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagEQ {
+		c := v.AuxInt
+		x := v.Args[0]
+		v.reset(OpS390XADDWconst)
+		v.AuxInt = int64(int32(-c))
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueS390X_OpS390XSUBconst_0(v *Value) bool {
+	// match: (SUBconst [0] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = -1
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (SUBEWcarrymask (FlagLT))
+	// match: (SUBconst [c] x)
+	// cond: c != -(1<<31)
+	// result: (ADDconst [-c] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c != -(1 << 31)) {
+			break
+		}
+		v.reset(OpS390XADDconst)
+		v.AuxInt = -c
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBconst (MOVDconst [d]) [c])
 	// cond:
-	// result: (MOVDconst [-1])
+	// result: (MOVDconst [d-c])
 	for {
+		c := v.AuxInt
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagLT {
+		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
+		d := v_0.AuxInt
 		v.reset(OpS390XMOVDconst)
-		v.AuxInt = -1
+		v.AuxInt = d - c
 		return true
 	}
-	// match: (SUBEWcarrymask (FlagGT))
-	// cond:
-	// result: (MOVDconst [0])
+	// match: (SUBconst (SUBconst x [d]) [c])
+	// cond: is32Bit(-c-d)
+	// result: (ADDconst [-c-d] x)
 	for {
+		c := v.AuxInt
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagGT {
+		if v_0.Op != OpS390XSUBconst {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = 0
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(is32Bit(-c - d)) {
+			break
+		}
+		v.reset(OpS390XADDconst)
+		v.AuxInt = -c - d
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XSUBEcarrymask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBEcarrymask (FlagEQ))
-	// cond:
-	// result: (MOVDconst [-1])
+func rewriteValueS390X_OpS390XXOR_0(v *Value) bool {
+	// match: (XOR x (MOVDconst [c]))
+	// cond: isU32Bit(c)
+	// result: (XORconst [c] x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagEQ {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = -1
+		c := v_1.AuxInt
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XXORconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (SUBEcarrymask (FlagLT))
-	// cond:
-	// result: (MOVDconst [-1])
+	// match: (XOR (MOVDconst [c]) x)
+	// cond: isU32Bit(c)
+	// result: (XORconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagLT {
+		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = -1
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(isU32Bit(c)) {
+			break
+		}
+		v.reset(OpS390XXORconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (SUBEcarrymask (FlagGT))
-	// cond:
-	// result: (MOVDconst [0])
+	// match: (XOR (SLDconst x [c]) (SRDconst x [d]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XFlagGT {
+		if v_0.Op != OpS390XSLDconst {
 			break
 		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = 0
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XSUBW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBW x (MOVDconst [c]))
+	// match: (XOR (SRDconst x [d]) (SLDconst x [c]))
+	// cond: d == 64-c
+	// result: (RLLGconst [c] x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XSRDconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSLDconst {
+			break
+		}
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
+			break
+		}
+		if !(d == 64-c) {
+			break
+		}
+		v.reset(OpS390XRLLGconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XOR (MOVDconst [c]) (MOVDconst [d]))
 	// cond:
-	// result: (SUBWconst x [c])
+	// result: (MOVDconst [c^d])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_0.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpS390XSUBWconst)
-		v.AuxInt = c
-		v.AddArg(x)
+		d := v_1.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c ^ d
 		return true
 	}
-	// match: (SUBW (MOVDconst [c]) x)
+	// match: (XOR (MOVDconst [d]) (MOVDconst [c]))
 	// cond:
-	// result: (NEGW (SUBWconst <v.Type> x [c]))
+	// result: (MOVDconst [c^d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpS390XNEGW)
-		v0 := b.NewValue0(v.Line, OpS390XSUBWconst, v.Type)
-		v0.AuxInt = c
-		v0.AddArg(x)
-		v.AddArg(v0)
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpS390XMOVDconst)
+		v.AuxInt = c ^ d
 		return true
 	}
-	// match: (SUBW x x)
+	// match: (XOR x x)
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -16463,24 +35293,26 @@ func rewriteValueS390X_OpS390XSUBW(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (SUBW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (SUBWload <t> [off] {sym} x ptr mem)
+	// match: (XOR <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
-		if g.Op != OpS390XMOVWload {
+		if g.Op != OpS390XMOVDload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XSUBWload)
+		v.reset(OpS390XXORload)
 		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
@@ -16489,24 +35321,26 @@ func rewriteValueS390X_OpS390XSUBW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (SUBWload <t> [off] {sym} x ptr mem)
+	// match: (XOR <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
-		if g.Op != OpS390XMOVWZload {
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XSUBWload)
+		v.reset(OpS390XXORload)
 		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
@@ -16515,163 +35349,159 @@ func rewriteValueS390X_OpS390XSUBW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XSUBWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBWconst [c] x)
-	// cond: int32(c) == 0
-	// result: x
+	// match: (XOR <t> g:(MOVDload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORload <t> [off] {sym} x ptr mem)
 	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		if !(int32(c) == 0) {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVDload {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (SUBWconst [c] x)
-	// cond:
-	// result: (ADDWconst [int64(int32(-c))] x)
-	for {
-		c := v.AuxInt
-		x := v.Args[0]
-		v.reset(OpS390XADDWconst)
-		v.AuxInt = int64(int32(-c))
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XXORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
+	return false
 }
-func rewriteValueS390X_OpS390XSUBconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SUBconst [0] x)
-	// cond:
-	// result: x
+func rewriteValueS390X_OpS390XXOR_10(v *Value) bool {
+	// match: (XOR <t> x g:(MOVDload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORload <t> [off] {sym} x ptr mem)
 	for {
-		if v.AuxInt != 0 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
+		if g.Op != OpS390XMOVDload {
 			break
 		}
-		x := v.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XXORload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (SUBconst [c] x)
-	// cond: c != -(1<<31)
-	// result: (ADDconst [-c] x)
+	return false
+}
+func rewriteValueS390X_OpS390XXORW_0(v *Value) bool {
+	// match: (XORW x (MOVDconst [c]))
+	// cond:
+	// result: (XORWconst [c] x)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		x := v.Args[0]
-		if !(c != -(1 << 31)) {
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XMOVDconst {
 			break
 		}
-		v.reset(OpS390XADDconst)
-		v.AuxInt = -c
+		c := v_1.AuxInt
+		v.reset(OpS390XXORWconst)
+		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (SUBconst (MOVDconst [d]) [c])
+	// match: (XORW (MOVDconst [c]) x)
 	// cond:
-	// result: (MOVDconst [d-c])
+	// result: (XORWconst [c] x)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpS390XMOVDconst {
 			break
 		}
-		d := v_0.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = d - c
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpS390XXORWconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (SUBconst (SUBconst x [d]) [c])
-	// cond: is32Bit(-c-d)
-	// result: (ADDconst [-c-d] x)
+	// match: (XORW (SLWconst x [c]) (SRWconst x [d]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
 	for {
-		c := v.AuxInt
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XSUBconst {
+		if v_0.Op != OpS390XSLWconst {
 			break
 		}
-		d := v_0.AuxInt
+		c := v_0.AuxInt
 		x := v_0.Args[0]
-		if !(is32Bit(-c - d)) {
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSRWconst {
 			break
 		}
-		v.reset(OpS390XADDconst)
-		v.AuxInt = -c - d
-		v.AddArg(x)
-		return true
-	}
-	return false
-}
-func rewriteValueS390X_OpS390XXOR(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XOR x (MOVDconst [c]))
-	// cond: isU32Bit(c)
-	// result: (XORconst [c] x)
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		d := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		c := v_1.AuxInt
-		if !(isU32Bit(c)) {
+		if !(d == 32-c) {
 			break
 		}
-		v.reset(OpS390XXORconst)
+		v.reset(OpS390XRLLconst)
 		v.AuxInt = c
 		v.AddArg(x)
 		return true
 	}
-	// match: (XOR (MOVDconst [c]) x)
-	// cond: isU32Bit(c)
-	// result: (XORconst [c] x)
+	// match: (XORW (SRWconst x [d]) (SLWconst x [c]))
+	// cond: d == 32-c
+	// result: (RLLconst [c] x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		if v_0.Op != OpS390XSRWconst {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		if !(isU32Bit(c)) {
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpS390XSLWconst {
 			break
 		}
-		v.reset(OpS390XXORconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (XOR (MOVDconst [c]) (MOVDconst [d]))
-	// cond:
-	// result: (MOVDconst [c^d])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		c := v_1.AuxInt
+		if x != v_1.Args[0] {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		if !(d == 32-c) {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = c ^ d
+		v.reset(OpS390XRLLconst)
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (XOR x x)
+	// match: (XORW x x)
 	// cond:
 	// result: (MOVDconst [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
@@ -16680,24 +35510,26 @@ func rewriteValueS390X_OpS390XXOR(v *Value, config *Config) bool {
 		v.AuxInt = 0
 		return true
 	}
-	// match: (XOR <t> x g:(MOVDload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (XORload <t> [off] {sym} x ptr mem)
+	// match: (XORW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
-		if g.Op != OpS390XMOVDload {
+		if g.Op != OpS390XMOVWload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XXORload)
+		v.reset(OpS390XXORWload)
 		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
@@ -16706,24 +35538,54 @@ func rewriteValueS390X_OpS390XXOR(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (XOR <t> g:(MOVDload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
-	// result: (XORload <t> [off] {sym} x ptr mem)
+	// match: (XORW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORWload <t> [off] {sym} x ptr mem)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		g := v.Args[0]
+		if g.Op != OpS390XMOVWload {
+			break
+		}
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
+			break
+		}
+		v.reset(OpS390XXORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (XORW <t> g:(MOVWload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
-		if g.Op != OpS390XMOVDload {
+		if g.Op != OpS390XMOVWload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		v.reset(OpS390XXORload)
+		v.reset(OpS390XXORWload)
 		v.Type = t
 		v.AuxInt = off
 		v.Aux = sym
@@ -16732,68 +35594,51 @@ func rewriteValueS390X_OpS390XXOR(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValueS390X_OpS390XXORW(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (XORW x (MOVDconst [c]))
-	// cond:
-	// result: (XORWconst [c] x)
+	// match: (XORW <t> x g:(MOVWload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
+	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpS390XMOVDconst {
+		g := v.Args[1]
+		if g.Op != OpS390XMOVWload {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpS390XXORWconst)
-		v.AuxInt = c
-		v.AddArg(x)
-		return true
-	}
-	// match: (XORW (MOVDconst [c]) x)
-	// cond:
-	// result: (XORWconst [c] x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpS390XMOVDconst {
+		off := g.AuxInt
+		sym := g.Aux
+		_ = g.Args[1]
+		ptr := g.Args[0]
+		mem := g.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
-		c := v_0.AuxInt
-		x := v.Args[1]
-		v.reset(OpS390XXORWconst)
-		v.AuxInt = c
+		v.reset(OpS390XXORWload)
+		v.Type = t
+		v.AuxInt = off
+		v.Aux = sym
 		v.AddArg(x)
+		v.AddArg(ptr)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (XORW x x)
-	// cond:
-	// result: (MOVDconst [0])
-	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
-			break
-		}
-		v.reset(OpS390XMOVDconst)
-		v.AuxInt = 0
-		return true
-	}
-	// match: (XORW <t> x g:(MOVWload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// match: (XORW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		g := v.Args[1]
-		if g.Op != OpS390XMOVWload {
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XXORWload)
@@ -16805,21 +35650,26 @@ func rewriteValueS390X_OpS390XXORW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (XORW <t> g:(MOVWload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	return false
+}
+func rewriteValueS390X_OpS390XXORW_10(v *Value) bool {
+	// match: (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		g := v.Args[0]
-		if g.Op != OpS390XMOVWload {
+		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
 		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XXORWload)
@@ -16831,21 +35681,23 @@ func rewriteValueS390X_OpS390XXORW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (XORW <t> x g:(MOVWZload [off] {sym} ptr mem))
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// match: (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
-		x := v.Args[0]
-		g := v.Args[1]
+		_ = v.Args[1]
+		g := v.Args[0]
 		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		x := v.Args[1]
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XXORWload)
@@ -16857,21 +35709,23 @@ func rewriteValueS390X_OpS390XXORW(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x)
-	// cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+	// match: (XORW <t> x g:(MOVWZload [off] {sym} ptr mem))
+	// cond: ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)
 	// result: (XORWload <t> [off] {sym} x ptr mem)
 	for {
 		t := v.Type
-		g := v.Args[0]
+		_ = v.Args[1]
+		x := v.Args[0]
+		g := v.Args[1]
 		if g.Op != OpS390XMOVWZload {
 			break
 		}
 		off := g.AuxInt
 		sym := g.Aux
+		_ = g.Args[1]
 		ptr := g.Args[0]
 		mem := g.Args[1]
-		x := v.Args[1]
-		if !(g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)) {
+		if !(ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g, x) && clobber(g)) {
 			break
 		}
 		v.reset(OpS390XXORWload)
@@ -16885,9 +35739,7 @@ func rewriteValueS390X_OpS390XXORW(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XXORWconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XXORWconst_0(v *Value) bool {
 	// match: (XORWconst [c] x)
 	// cond: int32(c)==0
 	// result: x
@@ -16918,9 +35770,7 @@ func rewriteValueS390X_OpS390XXORWconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpS390XXORconst(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpS390XXORconst_0(v *Value) bool {
 	// match: (XORconst [0] x)
 	// cond:
 	// result: x
@@ -16950,10 +35800,10 @@ func rewriteValueS390X_OpS390XXORconst(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpSelect0(v *Value, config *Config) bool {
+func rewriteValueS390X_OpSelect0_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Select0 <t> (AddTupleFirst32 tuple val))
+	// match: (Select0 <t> (AddTupleFirst32 val tuple))
 	// cond:
 	// result: (ADDW val (Select0 <t> tuple))
 	for {
@@ -16962,16 +35812,17 @@ func rewriteValueS390X_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpS390XAddTupleFirst32 {
 			break
 		}
-		tuple := v_0.Args[0]
-		val := v_0.Args[1]
+		_ = v_0.Args[1]
+		val := v_0.Args[0]
+		tuple := v_0.Args[1]
 		v.reset(OpS390XADDW)
 		v.AddArg(val)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
+		v0 := b.NewValue0(v.Pos, OpSelect0, t)
 		v0.AddArg(tuple)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Select0 <t> (AddTupleFirst64 tuple val))
+	// match: (Select0 <t> (AddTupleFirst64 val tuple))
 	// cond:
 	// result: (ADD val (Select0 <t> tuple))
 	for {
@@ -16980,21 +35831,20 @@ func rewriteValueS390X_OpSelect0(v *Value, config *Config) bool {
 		if v_0.Op != OpS390XAddTupleFirst64 {
 			break
 		}
-		tuple := v_0.Args[0]
-		val := v_0.Args[1]
+		_ = v_0.Args[1]
+		val := v_0.Args[0]
+		tuple := v_0.Args[1]
 		v.reset(OpS390XADD)
 		v.AddArg(val)
-		v0 := b.NewValue0(v.Line, OpSelect0, t)
+		v0 := b.NewValue0(v.Pos, OpSelect0, t)
 		v0.AddArg(tuple)
 		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpSelect1(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Select1     (AddTupleFirst32 tuple _  ))
+func rewriteValueS390X_OpSelect1_0(v *Value) bool {
+	// match: (Select1 (AddTupleFirst32 _ tuple))
 	// cond:
 	// result: (Select1 tuple)
 	for {
@@ -17002,12 +35852,13 @@ func rewriteValueS390X_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpS390XAddTupleFirst32 {
 			break
 		}
-		tuple := v_0.Args[0]
+		_ = v_0.Args[1]
+		tuple := v_0.Args[1]
 		v.reset(OpSelect1)
 		v.AddArg(tuple)
 		return true
 	}
-	// match: (Select1     (AddTupleFirst64 tuple _  ))
+	// match: (Select1 (AddTupleFirst64 _ tuple))
 	// cond:
 	// result: (Select1 tuple)
 	for {
@@ -17015,16 +35866,15 @@ func rewriteValueS390X_OpSelect1(v *Value, config *Config) bool {
 		if v_0.Op != OpS390XAddTupleFirst64 {
 			break
 		}
-		tuple := v_0.Args[0]
+		_ = v_0.Args[1]
+		tuple := v_0.Args[1]
 		v.reset(OpSelect1)
 		v.AddArg(tuple)
 		return true
 	}
 	return false
 }
-func rewriteValueS390X_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSignExt16to32_0(v *Value) bool {
 	// match: (SignExt16to32 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -17035,9 +35885,7 @@ func rewriteValueS390X_OpSignExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSignExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSignExt16to64_0(v *Value) bool {
 	// match: (SignExt16to64 x)
 	// cond:
 	// result: (MOVHreg x)
@@ -17048,9 +35896,7 @@ func rewriteValueS390X_OpSignExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSignExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSignExt32to64_0(v *Value) bool {
 	// match: (SignExt32to64 x)
 	// cond:
 	// result: (MOVWreg x)
@@ -17061,10 +35907,8 @@ func rewriteValueS390X_OpSignExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to16  x)
+func rewriteValueS390X_OpSignExt8to16_0(v *Value) bool {
+	// match: (SignExt8to16 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -17074,10 +35918,8 @@ func rewriteValueS390X_OpSignExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSignExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to32  x)
+func rewriteValueS390X_OpSignExt8to32_0(v *Value) bool {
+	// match: (SignExt8to32 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -17087,10 +35929,8 @@ func rewriteValueS390X_OpSignExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSignExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to64  x)
+func rewriteValueS390X_OpSignExt8to64_0(v *Value) bool {
+	// match: (SignExt8to64 x)
 	// cond:
 	// result: (MOVBreg x)
 	for {
@@ -17100,32 +35940,24 @@ func rewriteValueS390X_OpSignExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSlicemask(v *Value, config *Config) bool {
+func rewriteValueS390X_OpSlicemask_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Slicemask <t> x)
 	// cond:
-	// result: (XOR (MOVDconst [-1]) (SRADconst <t> (SUBconst <t> x [1]) [63]))
+	// result: (SRADconst (NEG <t> x) [63])
 	for {
 		t := v.Type
 		x := v.Args[0]
-		v.reset(OpS390XXOR)
-		v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
-		v0.AuxInt = -1
+		v.reset(OpS390XSRADconst)
+		v.AuxInt = 63
+		v0 := b.NewValue0(v.Pos, OpS390XNEG, t)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpS390XSRADconst, t)
-		v1.AuxInt = 63
-		v2 := b.NewValue0(v.Line, OpS390XSUBconst, t)
-		v2.AuxInt = 1
-		v2.AddArg(x)
-		v1.AddArg(v2)
-		v.AddArg(v1)
 		return true
 	}
 }
-func rewriteValueS390X_OpSqrt(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSqrt_0(v *Value) bool {
 	// match: (Sqrt x)
 	// cond:
 	// result: (FSQRT x)
@@ -17136,9 +35968,7 @@ func rewriteValueS390X_OpSqrt(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpStaticCall(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpStaticCall_0(v *Value) bool {
 	// match: (StaticCall [argwid] {target} mem)
 	// cond:
 	// result: (CALLstatic [argwid] {target} mem)
@@ -17153,20 +35983,17 @@ func rewriteValueS390X_OpStaticCall(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpStore(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Store [8] ptr val mem)
-	// cond: is64BitFloat(val.Type)
+func rewriteValueS390X_OpStore_0(v *Value) bool {
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)
 	// result: (FMOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is64BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 8 && is64BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpS390XFMOVDstore)
@@ -17175,17 +36002,16 @@ func rewriteValueS390X_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond: is32BitFloat(val.Type)
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)
 	// result: (FMOVSstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
-		if !(is32BitFloat(val.Type)) {
+		if !(t.(*types.Type).Size() == 4 && is32BitFloat(val.Type)) {
 			break
 		}
 		v.reset(OpS390XFMOVSstore)
@@ -17194,64 +36020,72 @@ func rewriteValueS390X_OpStore(v *Value, config *Config) bool {
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [8] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 8
 	// result: (MOVDstore ptr val mem)
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 8) {
+			break
+		}
 		v.reset(OpS390XMOVDstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [4] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 4
 	// result: (MOVWstore ptr val mem)
 	for {
-		if v.AuxInt != 4 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 4) {
+			break
+		}
 		v.reset(OpS390XMOVWstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [2] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 2
 	// result: (MOVHstore ptr val mem)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 2) {
+			break
+		}
 		v.reset(OpS390XMOVHstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Store [1] ptr val mem)
-	// cond:
+	// match: (Store {t} ptr val mem)
+	// cond: t.(*types.Type).Size() == 1
 	// result: (MOVBstore ptr val mem)
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		ptr := v.Args[0]
 		val := v.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 1) {
+			break
+		}
 		v.reset(OpS390XMOVBstore)
 		v.AddArg(ptr)
 		v.AddArg(val)
@@ -17260,13 +36094,12 @@ func rewriteValueS390X_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub16  x y)
+func rewriteValueS390X_OpSub16_0(v *Value) bool {
+	// match: (Sub16 x y)
 	// cond:
 	// result: (SUBW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSUBW)
@@ -17275,13 +36108,12 @@ func rewriteValueS390X_OpSub16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSub32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub32  x y)
+func rewriteValueS390X_OpSub32_0(v *Value) bool {
+	// match: (Sub32 x y)
 	// cond:
 	// result: (SUBW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSUBW)
@@ -17290,13 +36122,12 @@ func rewriteValueS390X_OpSub32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSub32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSub32F_0(v *Value) bool {
 	// match: (Sub32F x y)
 	// cond:
 	// result: (FSUBS x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFSUBS)
@@ -17305,13 +36136,12 @@ func rewriteValueS390X_OpSub32F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSub64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub64  x y)
+func rewriteValueS390X_OpSub64_0(v *Value) bool {
+	// match: (Sub64 x y)
 	// cond:
 	// result: (SUB  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSUB)
@@ -17320,13 +36150,12 @@ func rewriteValueS390X_OpSub64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSub64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSub64F_0(v *Value) bool {
 	// match: (Sub64F x y)
 	// cond:
 	// result: (FSUB x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XFSUB)
@@ -17335,13 +36164,12 @@ func rewriteValueS390X_OpSub64F(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub8   x y)
+func rewriteValueS390X_OpSub8_0(v *Value) bool {
+	// match: (Sub8 x y)
 	// cond:
 	// result: (SUBW  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSUBW)
@@ -17350,13 +36178,12 @@ func rewriteValueS390X_OpSub8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpSubPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpSubPtr_0(v *Value) bool {
 	// match: (SubPtr x y)
 	// cond:
 	// result: (SUB  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XSUB)
@@ -17365,10 +36192,8 @@ func rewriteValueS390X_OpSubPtr(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc16to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc16to8  x)
+func rewriteValueS390X_OpTrunc16to8_0(v *Value) bool {
+	// match: (Trunc16to8 x)
 	// cond:
 	// result: x
 	for {
@@ -17379,9 +36204,7 @@ func rewriteValueS390X_OpTrunc16to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpTrunc32to16_0(v *Value) bool {
 	// match: (Trunc32to16 x)
 	// cond:
 	// result: x
@@ -17393,10 +36216,8 @@ func rewriteValueS390X_OpTrunc32to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc32to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc32to8  x)
+func rewriteValueS390X_OpTrunc32to8_0(v *Value) bool {
+	// match: (Trunc32to8 x)
 	// cond:
 	// result: x
 	for {
@@ -17407,9 +36228,7 @@ func rewriteValueS390X_OpTrunc32to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpTrunc64to16_0(v *Value) bool {
 	// match: (Trunc64to16 x)
 	// cond:
 	// result: x
@@ -17421,9 +36240,7 @@ func rewriteValueS390X_OpTrunc64to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc64to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpTrunc64to32_0(v *Value) bool {
 	// match: (Trunc64to32 x)
 	// cond:
 	// result: x
@@ -17435,10 +36252,8 @@ func rewriteValueS390X_OpTrunc64to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc64to8  x)
+func rewriteValueS390X_OpTrunc64to8_0(v *Value) bool {
+	// match: (Trunc64to8 x)
 	// cond:
 	// result: x
 	for {
@@ -17449,13 +36264,12 @@ func rewriteValueS390X_OpTrunc64to8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpXor16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpXor16_0(v *Value) bool {
 	// match: (Xor16 x y)
 	// cond:
 	// result: (XORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XXORW)
@@ -17464,13 +36278,12 @@ func rewriteValueS390X_OpXor16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpXor32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpXor32_0(v *Value) bool {
 	// match: (Xor32 x y)
 	// cond:
 	// result: (XORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XXORW)
@@ -17479,13 +36292,12 @@ func rewriteValueS390X_OpXor32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpXor64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpXor64_0(v *Value) bool {
 	// match: (Xor64 x y)
 	// cond:
 	// result: (XOR x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XXOR)
@@ -17494,13 +36306,12 @@ func rewriteValueS390X_OpXor64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpXor8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Xor8  x y)
+func rewriteValueS390X_OpXor8_0(v *Value) bool {
+	// match: (Xor8 x y)
 	// cond:
 	// result: (XORW x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpS390XXORW)
@@ -17509,161 +36320,161 @@ func rewriteValueS390X_OpXor8(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZero(v *Value, config *Config) bool {
+func rewriteValueS390X_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Zero [s] _ mem)
-	// cond: SizeAndAlign(s).Size() == 0
+	// match: (Zero [0] _ mem)
+	// cond:
 	// result: mem
 	for {
-		s := v.AuxInt
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 0) {
+		if v.AuxInt != 0 {
 			break
 		}
+		_ = v.Args[1]
+		mem := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = mem.Type
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 1
+	// match: (Zero [1] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 1) {
+		if v.AuxInt != 1 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVBstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 2
+	// match: (Zero [2] destptr mem)
+	// cond:
 	// result: (MOVHstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 2) {
+		if v.AuxInt != 2 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVHstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 4
+	// match: (Zero [4] destptr mem)
+	// cond:
 	// result: (MOVWstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 4) {
+		if v.AuxInt != 4 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVWstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 8
+	// match: (Zero [8] destptr mem)
+	// cond:
 	// result: (MOVDstoreconst [0] destptr mem)
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 8) {
+		if v.AuxInt != 8 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVDstoreconst)
 		v.AuxInt = 0
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 3
+	// match: (Zero [3] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [makeValAndOff(0,2)] destptr 		(MOVHstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 3) {
+		if v.AuxInt != 3 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVBstoreconst)
 		v.AuxInt = makeValAndOff(0, 2)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpS390XMOVHstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVHstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 5
+	// match: (Zero [5] destptr mem)
+	// cond:
 	// result: (MOVBstoreconst [makeValAndOff(0,4)] destptr 		(MOVWstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 5) {
+		if v.AuxInt != 5 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVBstoreconst)
 		v.AuxInt = makeValAndOff(0, 4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 6
+	// match: (Zero [6] destptr mem)
+	// cond:
 	// result: (MOVHstoreconst [makeValAndOff(0,4)] destptr 		(MOVWstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 6) {
+		if v.AuxInt != 6 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVHstoreconst)
 		v.AuxInt = makeValAndOff(0, 4)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() == 7
+	// match: (Zero [7] destptr mem)
+	// cond:
 	// result: (MOVWstoreconst [makeValAndOff(0,3)] destptr 		(MOVWstoreconst [0] destptr mem))
 	for {
-		s := v.AuxInt
-		destptr := v.Args[0]
-		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() == 7) {
+		if v.AuxInt != 7 {
 			break
 		}
+		_ = v.Args[1]
+		destptr := v.Args[0]
+		mem := v.Args[1]
 		v.reset(OpS390XMOVWstoreconst)
 		v.AuxInt = makeValAndOff(0, 3)
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, TypeMem)
+		v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem)
 		v0.AuxInt = 0
 		v0.AddArg(destptr)
 		v0.AddArg(mem)
@@ -17671,36 +36482,43 @@ func rewriteValueS390X_OpZero(v *Value, config *Config) bool {
 		return true
 	}
 	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024
-	// result: (CLEAR [makeValAndOff(SizeAndAlign(s).Size(), 0)] destptr mem)
+	// cond: s > 0 && s <= 1024
+	// result: (CLEAR [makeValAndOff(s, 0)] destptr mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024) {
+		if !(s > 0 && s <= 1024) {
 			break
 		}
 		v.reset(OpS390XCLEAR)
-		v.AuxInt = makeValAndOff(SizeAndAlign(s).Size(), 0)
+		v.AuxInt = makeValAndOff(s, 0)
 		v.AddArg(destptr)
 		v.AddArg(mem)
 		return true
 	}
+	return false
+}
+func rewriteValueS390X_OpZero_10(v *Value) bool {
+	b := v.Block
+	_ = b
 	// match: (Zero [s] destptr mem)
-	// cond: SizeAndAlign(s).Size() > 1024
-	// result: (LoweredZero [SizeAndAlign(s).Size()%256] destptr (ADDconst <destptr.Type> destptr [(SizeAndAlign(s).Size()/256)*256]) mem)
+	// cond: s > 1024
+	// result: (LoweredZero [s%256] destptr (ADDconst <destptr.Type> destptr [(s/256)*256]) mem)
 	for {
 		s := v.AuxInt
+		_ = v.Args[1]
 		destptr := v.Args[0]
 		mem := v.Args[1]
-		if !(SizeAndAlign(s).Size() > 1024) {
+		if !(s > 1024) {
 			break
 		}
 		v.reset(OpS390XLoweredZero)
-		v.AuxInt = SizeAndAlign(s).Size() % 256
+		v.AuxInt = s % 256
 		v.AddArg(destptr)
-		v0 := b.NewValue0(v.Line, OpS390XADDconst, destptr.Type)
-		v0.AuxInt = (SizeAndAlign(s).Size() / 256) * 256
+		v0 := b.NewValue0(v.Pos, OpS390XADDconst, destptr.Type)
+		v0.AuxInt = (s / 256) * 256
 		v0.AddArg(destptr)
 		v.AddArg(v0)
 		v.AddArg(mem)
@@ -17708,9 +36526,7 @@ func rewriteValueS390X_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValueS390X_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpZeroExt16to32_0(v *Value) bool {
 	// match: (ZeroExt16to32 x)
 	// cond:
 	// result: (MOVHZreg x)
@@ -17721,9 +36537,7 @@ func rewriteValueS390X_OpZeroExt16to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpZeroExt16to64_0(v *Value) bool {
 	// match: (ZeroExt16to64 x)
 	// cond:
 	// result: (MOVHZreg x)
@@ -17734,9 +36548,7 @@ func rewriteValueS390X_OpZeroExt16to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValueS390X_OpZeroExt32to64_0(v *Value) bool {
 	// match: (ZeroExt32to64 x)
 	// cond:
 	// result: (MOVWZreg x)
@@ -17747,10 +36559,8 @@ func rewriteValueS390X_OpZeroExt32to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to16  x)
+func rewriteValueS390X_OpZeroExt8to16_0(v *Value) bool {
+	// match: (ZeroExt8to16 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -17760,10 +36570,8 @@ func rewriteValueS390X_OpZeroExt8to16(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to32  x)
+func rewriteValueS390X_OpZeroExt8to32_0(v *Value) bool {
+	// match: (ZeroExt8to32 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -17773,10 +36581,8 @@ func rewriteValueS390X_OpZeroExt8to32(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValueS390X_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to64  x)
+func rewriteValueS390X_OpZeroExt8to64_0(v *Value) bool {
+	// match: (ZeroExt8to64 x)
 	// cond:
 	// result: (MOVBZreg x)
 	for {
@@ -17786,7 +36592,13 @@ func rewriteValueS390X_OpZeroExt8to64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteBlockS390X(b *Block, config *Config) bool {
+func rewriteBlockS390X(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockS390XEQ:
 		// match: (EQ (InvertFlags cmp) yes no)
@@ -17798,12 +36610,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagEQ) yes no)
@@ -17814,12 +36622,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (EQ (FlagLT) yes no)
@@ -17830,13 +36634,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (EQ (FlagGT) yes no)
@@ -17847,13 +36647,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockS390XGE:
@@ -17866,12 +36662,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (FlagEQ) yes no)
@@ -17882,12 +36674,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GE (FlagLT) yes no)
@@ -17898,13 +36686,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GE (FlagGT) yes no)
@@ -17915,12 +36699,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockS390XGT:
@@ -17933,12 +36713,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (GT (FlagEQ) yes no)
@@ -17949,13 +36725,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GT (FlagLT) yes no)
@@ -17966,13 +36738,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (GT (FlagGT) yes no)
@@ -17983,12 +36751,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockIf:
@@ -18000,6 +36764,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDLT {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18015,12 +36780,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18031,6 +36792,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDLE {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18046,12 +36808,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18062,6 +36820,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDGT {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18077,12 +36836,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18093,6 +36848,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDGE {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18108,12 +36864,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18124,6 +36876,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDEQ {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18139,12 +36892,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18155,6 +36904,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDNE {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18170,12 +36920,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18186,6 +36932,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDGTnoinv {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18201,12 +36948,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGTF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
@@ -18217,6 +36960,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XMOVDGEnoinv {
 				break
 			}
+			_ = v.Args[2]
 			v_0 := v.Args[0]
 			if v_0.Op != OpS390XMOVDconst {
 				break
@@ -18232,32 +36976,24 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGEF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (If cond yes no)
 		// cond:
-		// result: (NE (CMPWconst [0] (MOVBZreg <config.fe.TypeBool()> cond)) yes no)
+		// result: (NE (CMPWconst [0] (MOVBZreg <typ.Bool> cond)) yes no)
 		for {
 			v := b.Control
 			_ = v
 			cond := b.Control
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XNE
-			v0 := b.NewValue0(v.Line, OpS390XCMPWconst, TypeFlags)
+			v0 := b.NewValue0(v.Pos, OpS390XCMPWconst, types.TypeFlags)
 			v0.AuxInt = 0
-			v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeBool())
+			v1 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.Bool)
 			v1.AddArg(cond)
 			v0.AddArg(v1)
 			b.SetControl(v0)
-			_ = yes
-			_ = no
 			return true
 		}
 	case BlockS390XLE:
@@ -18270,12 +37006,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LE (FlagEQ) yes no)
@@ -18286,12 +37018,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LE (FlagLT) yes no)
@@ -18302,12 +37030,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LE (FlagGT) yes no)
@@ -18318,13 +37042,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockS390XLT:
@@ -18337,12 +37057,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LT (FlagEQ) yes no)
@@ -18353,13 +37069,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (LT (FlagLT) yes no)
@@ -18370,12 +37082,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (LT (FlagGT) yes no)
@@ -18386,13 +37094,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 	case BlockS390XNE:
@@ -18411,6 +37115,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDLT {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18426,12 +37131,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18449,6 +37150,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDLE {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18464,12 +37166,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XLE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18487,6 +37185,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDGT {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18502,12 +37201,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGT
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18525,6 +37220,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDGE {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18540,12 +37236,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18563,6 +37255,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDEQ {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18578,12 +37271,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XEQ
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18601,6 +37290,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDNE {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18616,12 +37306,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18639,6 +37325,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDGTnoinv {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18654,12 +37341,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGTF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (CMPWconst [0] (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
@@ -18677,6 +37360,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v_0.Op != OpS390XMOVDGEnoinv {
 				break
 			}
+			_ = v_0.Args[2]
 			v_0_0 := v_0.Args[0]
 			if v_0_0.Op != OpS390XMOVDconst {
 				break
@@ -18692,12 +37376,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v_0.Args[2]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XGEF
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (InvertFlags cmp) yes no)
@@ -18709,12 +37389,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 				break
 			}
 			cmp := v.Args[0]
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockS390XNE
 			b.SetControl(cmp)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagEQ) yes no)
@@ -18725,13 +37401,9 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagEQ {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
 			b.swapSuccessors()
-			_ = no
-			_ = yes
 			return true
 		}
 		// match: (NE (FlagLT) yes no)
@@ -18742,12 +37414,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagLT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 		// match: (NE (FlagGT) yes no)
@@ -18758,12 +37426,8 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
 			if v.Op != OpS390XFlagGT {
 				break
 			}
-			yes := b.Succs[0]
-			no := b.Succs[1]
 			b.Kind = BlockFirst
 			b.SetControl(nil)
-			_ = yes
-			_ = no
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go
index 7bd32ff..c21c64b 100644
--- a/src/cmd/compile/internal/ssa/rewrite_test.go
+++ b/src/cmd/compile/internal/ssa/rewrite_test.go
@@ -25,7 +25,7 @@ func TestNlzNto(t *testing.T) {
 	// 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
+		// nto should be the number of bits we've shifted on, with an extra bit
 		// at iter 32
 		ntoExp := i
 		if ntoExp == 32 {
diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go
index fd52751..5ace63b 100644
--- a/src/cmd/compile/internal/ssa/rewritedec.go
+++ b/src/cmd/compile/internal/ssa/rewritedec.go
@@ -1,42 +1,47 @@
-// autogenerated from gen/dec.rules: do not edit!
+// Code generated from gen/dec.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValuedec(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValuedec(v *Value) bool {
 	switch v.Op {
 	case OpComplexImag:
-		return rewriteValuedec_OpComplexImag(v, config)
+		return rewriteValuedec_OpComplexImag_0(v)
 	case OpComplexReal:
-		return rewriteValuedec_OpComplexReal(v, config)
+		return rewriteValuedec_OpComplexReal_0(v)
 	case OpIData:
-		return rewriteValuedec_OpIData(v, config)
+		return rewriteValuedec_OpIData_0(v)
 	case OpITab:
-		return rewriteValuedec_OpITab(v, config)
+		return rewriteValuedec_OpITab_0(v)
 	case OpLoad:
-		return rewriteValuedec_OpLoad(v, config)
+		return rewriteValuedec_OpLoad_0(v)
 	case OpSliceCap:
-		return rewriteValuedec_OpSliceCap(v, config)
+		return rewriteValuedec_OpSliceCap_0(v)
 	case OpSliceLen:
-		return rewriteValuedec_OpSliceLen(v, config)
+		return rewriteValuedec_OpSliceLen_0(v)
 	case OpSlicePtr:
-		return rewriteValuedec_OpSlicePtr(v, config)
+		return rewriteValuedec_OpSlicePtr_0(v)
 	case OpStore:
-		return rewriteValuedec_OpStore(v, config)
+		return rewriteValuedec_OpStore_0(v)
 	case OpStringLen:
-		return rewriteValuedec_OpStringLen(v, config)
+		return rewriteValuedec_OpStringLen_0(v)
 	case OpStringPtr:
-		return rewriteValuedec_OpStringPtr(v, config)
+		return rewriteValuedec_OpStringPtr_0(v)
 	}
 	return false
 }
-func rewriteValuedec_OpComplexImag(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ComplexImag (ComplexMake _ imag ))
+func rewriteValuedec_OpComplexImag_0(v *Value) bool {
+	// match: (ComplexImag (ComplexMake _ imag))
 	// cond:
 	// result: imag
 	for {
@@ -44,6 +49,7 @@ func rewriteValuedec_OpComplexImag(v *Value, config *Config) bool {
 		if v_0.Op != OpComplexMake {
 			break
 		}
+		_ = v_0.Args[1]
 		imag := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = imag.Type
@@ -52,10 +58,8 @@ func rewriteValuedec_OpComplexImag(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpComplexReal(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ComplexReal (ComplexMake real _  ))
+func rewriteValuedec_OpComplexReal_0(v *Value) bool {
+	// match: (ComplexReal (ComplexMake real _))
 	// cond:
 	// result: real
 	for {
@@ -63,6 +67,7 @@ func rewriteValuedec_OpComplexReal(v *Value, config *Config) bool {
 		if v_0.Op != OpComplexMake {
 			break
 		}
+		_ = v_0.Args[1]
 		real := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = real.Type
@@ -71,9 +76,7 @@ func rewriteValuedec_OpComplexReal(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpIData(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec_OpIData_0(v *Value) bool {
 	// match: (IData (IMake _ data))
 	// cond:
 	// result: data
@@ -82,6 +85,7 @@ func rewriteValuedec_OpIData(v *Value, config *Config) bool {
 		if v_0.Op != OpIMake {
 			break
 		}
+		_ = v_0.Args[1]
 		data := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = data.Type
@@ -90,7 +94,7 @@ func rewriteValuedec_OpIData(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpITab(v *Value, config *Config) bool {
+func rewriteValuedec_OpITab_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (ITab (IMake itab _))
@@ -101,6 +105,7 @@ func rewriteValuedec_OpITab(v *Value, config *Config) bool {
 		if v_0.Op != OpIMake {
 			break
 		}
+		_ = v_0.Args[1]
 		itab := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = itab.Type
@@ -109,26 +114,31 @@ func rewriteValuedec_OpITab(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
+func rewriteValuedec_OpLoad_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// 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)     )
+	// result: (ComplexMake     (Load <typ.Float32> ptr mem)     (Load <typ.Float32>       (OffPtr <typ.Float32Ptr> [4] ptr)       mem)     )
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		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 := b.NewValue0(v.Pos, OpLoad, typ.Float32)
 		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())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.Float32)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.Float32Ptr)
 		v2.AuxInt = 4
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -138,21 +148,22 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
 	}
 	// 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)     )
+	// result: (ComplexMake     (Load <typ.Float64> ptr mem)     (Load <typ.Float64>       (OffPtr <typ.Float64Ptr> [8] ptr)       mem)     )
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		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 := b.NewValue0(v.Pos, OpLoad, typ.Float64)
 		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())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.Float64)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.Float64Ptr)
 		v2.AuxInt = 8
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -162,21 +173,22 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
 	}
 	// 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))
+	// result: (StringMake     (Load <typ.BytePtr> ptr mem)     (Load <typ.Int>       (OffPtr <typ.IntPtr> [config.PtrSize] ptr)       mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		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 := b.NewValue0(v.Pos, OpLoad, typ.BytePtr)
 		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())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.Int)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		v2.AuxInt = config.PtrSize
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -186,28 +198,29 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
 	}
 	// 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))
+	// result: (SliceMake     (Load <t.ElemType().PtrTo()> ptr mem)     (Load <typ.Int>       (OffPtr <typ.IntPtr> [config.PtrSize] ptr)       mem)     (Load <typ.Int>       (OffPtr <typ.IntPtr> [2*config.PtrSize] ptr)       mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		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 := b.NewValue0(v.Pos, 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())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.Int)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		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())
+		v3 := b.NewValue0(v.Pos, OpLoad, typ.Int)
+		v4 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		v4.AuxInt = 2 * config.PtrSize
 		v4.AddArg(ptr)
 		v3.AddArg(v4)
@@ -217,21 +230,22 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
 	}
 	// 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))
+	// result: (IMake     (Load <typ.BytePtr> ptr mem)     (Load <typ.BytePtr>       (OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr)       mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		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 := b.NewValue0(v.Pos, OpLoad, typ.BytePtr)
 		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())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.BytePtr)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.BytePtrPtr)
 		v2.AuxInt = config.PtrSize
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -241,9 +255,7 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpSliceCap(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec_OpSliceCap_0(v *Value) bool {
 	// match: (SliceCap (SliceMake _ _ cap))
 	// cond:
 	// result: cap
@@ -252,6 +264,7 @@ func rewriteValuedec_OpSliceCap(v *Value, config *Config) bool {
 		if v_0.Op != OpSliceMake {
 			break
 		}
+		_ = v_0.Args[2]
 		cap := v_0.Args[2]
 		v.reset(OpCopy)
 		v.Type = cap.Type
@@ -260,9 +273,7 @@ func rewriteValuedec_OpSliceCap(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpSliceLen(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec_OpSliceLen_0(v *Value) bool {
 	// match: (SliceLen (SliceMake _ len _))
 	// cond:
 	// result: len
@@ -271,6 +282,7 @@ func rewriteValuedec_OpSliceLen(v *Value, config *Config) bool {
 		if v_0.Op != OpSliceMake {
 			break
 		}
+		_ = v_0.Args[2]
 		len := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = len.Type
@@ -279,10 +291,8 @@ func rewriteValuedec_OpSliceLen(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpSlicePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SlicePtr (SliceMake ptr _ _ ))
+func rewriteValuedec_OpSlicePtr_0(v *Value) bool {
+	// match: (SlicePtr (SliceMake ptr _ _))
 	// cond:
 	// result: ptr
 	for {
@@ -290,6 +300,7 @@ func rewriteValuedec_OpSlicePtr(v *Value, config *Config) bool {
 		if v_0.Op != OpSliceMake {
 			break
 		}
+		_ = v_0.Args[2]
 		ptr := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = ptr.Type
@@ -298,131 +309,139 @@ func rewriteValuedec_OpSlicePtr(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpStore(v *Value, config *Config) bool {
+func rewriteValuedec_OpStore_0(v *Value) 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))
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Store {t} dst (ComplexMake real imag) mem)
+	// cond: t.(*types.Type).Size() == 8
+	// result: (Store {typ.Float32}     (OffPtr <typ.Float32Ptr> [4] dst)     imag     (Store {typ.Float32} dst real mem))
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpComplexMake {
 			break
 		}
+		_ = v_1.Args[1]
 		real := v_1.Args[0]
 		imag := v_1.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 8) {
+			break
+		}
 		v.reset(OpStore)
-		v.AuxInt = 4
-		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo())
+		v.Aux = typ.Float32
+		v0 := b.NewValue0(v.Pos, OpOffPtr, typ.Float32Ptr)
 		v0.AuxInt = 4
 		v0.AddArg(dst)
 		v.AddArg(v0)
 		v.AddArg(imag)
-		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
-		v1.AuxInt = 4
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = typ.Float32
 		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))
+	// match: (Store {t} dst (ComplexMake real imag) mem)
+	// cond: t.(*types.Type).Size() == 16
+	// result: (Store {typ.Float64}     (OffPtr <typ.Float64Ptr> [8] dst)     imag     (Store {typ.Float64} dst real mem))
 	for {
-		if v.AuxInt != 16 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpComplexMake {
 			break
 		}
+		_ = v_1.Args[1]
 		real := v_1.Args[0]
 		imag := v_1.Args[1]
 		mem := v.Args[2]
+		if !(t.(*types.Type).Size() == 16) {
+			break
+		}
 		v.reset(OpStore)
-		v.AuxInt = 8
-		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo())
+		v.Aux = typ.Float64
+		v0 := b.NewValue0(v.Pos, OpOffPtr, typ.Float64Ptr)
 		v0.AuxInt = 8
 		v0.AddArg(dst)
 		v.AddArg(v0)
 		v.AddArg(imag)
-		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
-		v1.AuxInt = 8
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = typ.Float64
 		v1.AddArg(dst)
 		v1.AddArg(real)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Store [2*config.PtrSize] dst (StringMake ptr len) mem)
+	// match: (Store 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))
+	// result: (Store {typ.Int}     (OffPtr <typ.IntPtr> [config.PtrSize] dst)     len     (Store {typ.BytePtr} dst ptr mem))
 	for {
-		if v.AuxInt != 2*config.PtrSize {
-			break
-		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpStringMake {
 			break
 		}
+		_ = v_1.Args[1]
 		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())
+		v.Aux = typ.Int
+		v0 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		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 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = typ.BytePtr
 		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)
+	// match: (Store 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)))
+	// result: (Store {typ.Int}     (OffPtr <typ.IntPtr> [2*config.PtrSize] dst)     cap     (Store {typ.Int}       (OffPtr <typ.IntPtr> [config.PtrSize] dst)       len       (Store {typ.BytePtr} dst ptr mem)))
 	for {
-		if v.AuxInt != 3*config.PtrSize {
-			break
-		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpSliceMake {
 			break
 		}
+		_ = v_1.Args[2]
 		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())
+		v.Aux = typ.Int
+		v0 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		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())
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = typ.Int
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.IntPtr)
 		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 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v3.Aux = typ.BytePtr
 		v3.AddArg(dst)
 		v3.AddArg(ptr)
 		v3.AddArg(mem)
@@ -430,30 +449,29 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Store [2*config.PtrSize] dst (IMake itab data) mem)
+	// match: (Store 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))
+	// result: (Store {typ.BytePtr}     (OffPtr <typ.BytePtrPtr> [config.PtrSize] dst)     data     (Store {typ.Uintptr} dst itab mem))
 	for {
-		if v.AuxInt != 2*config.PtrSize {
-			break
-		}
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpIMake {
 			break
 		}
+		_ = v_1.Args[1]
 		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())
+		v.Aux = typ.BytePtr
+		v0 := b.NewValue0(v.Pos, OpOffPtr, typ.BytePtrPtr)
 		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 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = typ.Uintptr
 		v1.AddArg(dst)
 		v1.AddArg(itab)
 		v1.AddArg(mem)
@@ -462,9 +480,7 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpStringLen(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec_OpStringLen_0(v *Value) bool {
 	// match: (StringLen (StringMake _ len))
 	// cond:
 	// result: len
@@ -473,6 +489,7 @@ func rewriteValuedec_OpStringLen(v *Value, config *Config) bool {
 		if v_0.Op != OpStringMake {
 			break
 		}
+		_ = v_0.Args[1]
 		len := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = len.Type
@@ -481,9 +498,7 @@ func rewriteValuedec_OpStringLen(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec_OpStringPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec_OpStringPtr_0(v *Value) bool {
 	// match: (StringPtr (StringMake ptr _))
 	// cond:
 	// result: ptr
@@ -492,6 +507,7 @@ func rewriteValuedec_OpStringPtr(v *Value, config *Config) bool {
 		if v_0.Op != OpStringMake {
 			break
 		}
+		_ = v_0.Args[1]
 		ptr := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = ptr.Type
@@ -500,7 +516,13 @@ func rewriteValuedec_OpStringPtr(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteBlockdec(b *Block, config *Config) bool {
+func rewriteBlockdec(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritedec64.go b/src/cmd/compile/internal/ssa/rewritedec64.go
index deca007..5666b1f 100644
--- a/src/cmd/compile/internal/ssa/rewritedec64.go
+++ b/src/cmd/compile/internal/ssa/rewritedec64.go
@@ -1,164 +1,174 @@
-// autogenerated from gen/dec64.rules: do not edit!
+// Code generated from gen/dec64.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValuedec64(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValuedec64(v *Value) bool {
 	switch v.Op {
 	case OpAdd64:
-		return rewriteValuedec64_OpAdd64(v, config)
+		return rewriteValuedec64_OpAdd64_0(v)
 	case OpAnd64:
-		return rewriteValuedec64_OpAnd64(v, config)
+		return rewriteValuedec64_OpAnd64_0(v)
 	case OpArg:
-		return rewriteValuedec64_OpArg(v, config)
+		return rewriteValuedec64_OpArg_0(v)
+	case OpBitLen64:
+		return rewriteValuedec64_OpBitLen64_0(v)
 	case OpBswap64:
-		return rewriteValuedec64_OpBswap64(v, config)
+		return rewriteValuedec64_OpBswap64_0(v)
 	case OpCom64:
-		return rewriteValuedec64_OpCom64(v, config)
+		return rewriteValuedec64_OpCom64_0(v)
 	case OpConst64:
-		return rewriteValuedec64_OpConst64(v, config)
+		return rewriteValuedec64_OpConst64_0(v)
 	case OpCtz64:
-		return rewriteValuedec64_OpCtz64(v, config)
+		return rewriteValuedec64_OpCtz64_0(v)
 	case OpEq64:
-		return rewriteValuedec64_OpEq64(v, config)
+		return rewriteValuedec64_OpEq64_0(v)
 	case OpGeq64:
-		return rewriteValuedec64_OpGeq64(v, config)
+		return rewriteValuedec64_OpGeq64_0(v)
 	case OpGeq64U:
-		return rewriteValuedec64_OpGeq64U(v, config)
+		return rewriteValuedec64_OpGeq64U_0(v)
 	case OpGreater64:
-		return rewriteValuedec64_OpGreater64(v, config)
+		return rewriteValuedec64_OpGreater64_0(v)
 	case OpGreater64U:
-		return rewriteValuedec64_OpGreater64U(v, config)
+		return rewriteValuedec64_OpGreater64U_0(v)
 	case OpInt64Hi:
-		return rewriteValuedec64_OpInt64Hi(v, config)
+		return rewriteValuedec64_OpInt64Hi_0(v)
 	case OpInt64Lo:
-		return rewriteValuedec64_OpInt64Lo(v, config)
+		return rewriteValuedec64_OpInt64Lo_0(v)
 	case OpLeq64:
-		return rewriteValuedec64_OpLeq64(v, config)
+		return rewriteValuedec64_OpLeq64_0(v)
 	case OpLeq64U:
-		return rewriteValuedec64_OpLeq64U(v, config)
+		return rewriteValuedec64_OpLeq64U_0(v)
 	case OpLess64:
-		return rewriteValuedec64_OpLess64(v, config)
+		return rewriteValuedec64_OpLess64_0(v)
 	case OpLess64U:
-		return rewriteValuedec64_OpLess64U(v, config)
+		return rewriteValuedec64_OpLess64U_0(v)
 	case OpLoad:
-		return rewriteValuedec64_OpLoad(v, config)
-	case OpLrot64:
-		return rewriteValuedec64_OpLrot64(v, config)
+		return rewriteValuedec64_OpLoad_0(v)
 	case OpLsh16x64:
-		return rewriteValuedec64_OpLsh16x64(v, config)
+		return rewriteValuedec64_OpLsh16x64_0(v)
 	case OpLsh32x64:
-		return rewriteValuedec64_OpLsh32x64(v, config)
+		return rewriteValuedec64_OpLsh32x64_0(v)
 	case OpLsh64x16:
-		return rewriteValuedec64_OpLsh64x16(v, config)
+		return rewriteValuedec64_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValuedec64_OpLsh64x32(v, config)
+		return rewriteValuedec64_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValuedec64_OpLsh64x64(v, config)
+		return rewriteValuedec64_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValuedec64_OpLsh64x8(v, config)
+		return rewriteValuedec64_OpLsh64x8_0(v)
 	case OpLsh8x64:
-		return rewriteValuedec64_OpLsh8x64(v, config)
+		return rewriteValuedec64_OpLsh8x64_0(v)
 	case OpMul64:
-		return rewriteValuedec64_OpMul64(v, config)
+		return rewriteValuedec64_OpMul64_0(v)
 	case OpNeg64:
-		return rewriteValuedec64_OpNeg64(v, config)
+		return rewriteValuedec64_OpNeg64_0(v)
 	case OpNeq64:
-		return rewriteValuedec64_OpNeq64(v, config)
+		return rewriteValuedec64_OpNeq64_0(v)
 	case OpOr64:
-		return rewriteValuedec64_OpOr64(v, config)
+		return rewriteValuedec64_OpOr64_0(v)
 	case OpRsh16Ux64:
-		return rewriteValuedec64_OpRsh16Ux64(v, config)
+		return rewriteValuedec64_OpRsh16Ux64_0(v)
 	case OpRsh16x64:
-		return rewriteValuedec64_OpRsh16x64(v, config)
+		return rewriteValuedec64_OpRsh16x64_0(v)
 	case OpRsh32Ux64:
-		return rewriteValuedec64_OpRsh32Ux64(v, config)
+		return rewriteValuedec64_OpRsh32Ux64_0(v)
 	case OpRsh32x64:
-		return rewriteValuedec64_OpRsh32x64(v, config)
+		return rewriteValuedec64_OpRsh32x64_0(v)
 	case OpRsh64Ux16:
-		return rewriteValuedec64_OpRsh64Ux16(v, config)
+		return rewriteValuedec64_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValuedec64_OpRsh64Ux32(v, config)
+		return rewriteValuedec64_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValuedec64_OpRsh64Ux64(v, config)
+		return rewriteValuedec64_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValuedec64_OpRsh64Ux8(v, config)
+		return rewriteValuedec64_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValuedec64_OpRsh64x16(v, config)
+		return rewriteValuedec64_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValuedec64_OpRsh64x32(v, config)
+		return rewriteValuedec64_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValuedec64_OpRsh64x64(v, config)
+		return rewriteValuedec64_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValuedec64_OpRsh64x8(v, config)
+		return rewriteValuedec64_OpRsh64x8_0(v)
 	case OpRsh8Ux64:
-		return rewriteValuedec64_OpRsh8Ux64(v, config)
+		return rewriteValuedec64_OpRsh8Ux64_0(v)
 	case OpRsh8x64:
-		return rewriteValuedec64_OpRsh8x64(v, config)
+		return rewriteValuedec64_OpRsh8x64_0(v)
 	case OpSignExt16to64:
-		return rewriteValuedec64_OpSignExt16to64(v, config)
+		return rewriteValuedec64_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValuedec64_OpSignExt32to64(v, config)
+		return rewriteValuedec64_OpSignExt32to64_0(v)
 	case OpSignExt8to64:
-		return rewriteValuedec64_OpSignExt8to64(v, config)
+		return rewriteValuedec64_OpSignExt8to64_0(v)
 	case OpStore:
-		return rewriteValuedec64_OpStore(v, config)
+		return rewriteValuedec64_OpStore_0(v)
 	case OpSub64:
-		return rewriteValuedec64_OpSub64(v, config)
+		return rewriteValuedec64_OpSub64_0(v)
 	case OpTrunc64to16:
-		return rewriteValuedec64_OpTrunc64to16(v, config)
+		return rewriteValuedec64_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValuedec64_OpTrunc64to32(v, config)
+		return rewriteValuedec64_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValuedec64_OpTrunc64to8(v, config)
+		return rewriteValuedec64_OpTrunc64to8_0(v)
 	case OpXor64:
-		return rewriteValuedec64_OpXor64(v, config)
+		return rewriteValuedec64_OpXor64_0(v)
 	case OpZeroExt16to64:
-		return rewriteValuedec64_OpZeroExt16to64(v, config)
+		return rewriteValuedec64_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValuedec64_OpZeroExt32to64(v, config)
+		return rewriteValuedec64_OpZeroExt32to64_0(v)
 	case OpZeroExt8to64:
-		return rewriteValuedec64_OpZeroExt8to64(v, config)
+		return rewriteValuedec64_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValuedec64_OpAdd64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpAdd64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Add64 x y)
 	// cond:
-	// result: (Int64Make 		(Add32withcarry <config.fe.TypeInt32()> 			(Int64Hi x) 			(Int64Hi y) 			(Select1 <TypeFlags> (Add32carry (Int64Lo x) (Int64Lo y)))) 		(Select0 <config.fe.TypeUInt32()> (Add32carry (Int64Lo x) (Int64Lo y))))
+	// result: (Int64Make 		(Add32withcarry <typ.Int32> 			(Int64Hi x) 			(Int64Hi y) 			(Select1 <types.TypeFlags> (Add32carry (Int64Lo x) (Int64Lo y)))) 		(Select0 <typ.UInt32> (Add32carry (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpAdd32withcarry, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpAdd32withcarry, typ.Int32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSelect1, TypeFlags)
-		v4 := b.NewValue0(v.Line, OpAdd32carry, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpAdd32carry, types.NewTuple(typ.UInt32, types.TypeFlags))
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
 		v.AddArg(v0)
-		v7 := b.NewValue0(v.Line, OpSelect0, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpAdd32carry, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpSelect0, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpAdd32carry, types.NewTuple(typ.UInt32, types.TypeFlags))
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(x)
 		v8.AddArg(v9)
-		v10 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v10 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v10.AddArg(y)
 		v8.AddArg(v10)
 		v7.AddArg(v8)
@@ -166,41 +176,48 @@ func rewriteValuedec64_OpAdd64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpAnd64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpAnd64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (And64 x y)
 	// cond:
-	// result: (Int64Make 		(And32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) 		(And32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+	// result: (Int64Make 		(And32 <typ.UInt32> (Int64Hi x) (Int64Hi y)) 		(And32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(y)
 		v3.AddArg(v5)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
+func rewriteValuedec64_OpArg_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Arg {n} [off])
 	// cond: is64BitInt(v.Type) && !config.BigEndian && v.Type.IsSigned()
-	// result: (Int64Make     (Arg <config.fe.TypeInt32()> {n} [off+4])     (Arg <config.fe.TypeUInt32()> {n} [off]))
+	// result: (Int64Make     (Arg <typ.Int32> {n} [off+4])     (Arg <typ.UInt32> {n} [off]))
 	for {
 		off := v.AuxInt
 		n := v.Aux
@@ -208,11 +225,11 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpArg, typ.Int32)
 		v0.AuxInt = off + 4
 		v0.Aux = n
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v1.AuxInt = off
 		v1.Aux = n
 		v.AddArg(v1)
@@ -220,7 +237,7 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 	}
 	// match: (Arg {n} [off])
 	// cond: is64BitInt(v.Type) && !config.BigEndian && !v.Type.IsSigned()
-	// result: (Int64Make     (Arg <config.fe.TypeUInt32()> {n} [off+4])     (Arg <config.fe.TypeUInt32()> {n} [off]))
+	// result: (Int64Make     (Arg <typ.UInt32> {n} [off+4])     (Arg <typ.UInt32> {n} [off]))
 	for {
 		off := v.AuxInt
 		n := v.Aux
@@ -228,11 +245,11 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v0.AuxInt = off + 4
 		v0.Aux = n
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v1.AuxInt = off
 		v1.Aux = n
 		v.AddArg(v1)
@@ -240,7 +257,7 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 	}
 	// match: (Arg {n} [off])
 	// cond: is64BitInt(v.Type) && config.BigEndian && v.Type.IsSigned()
-	// result: (Int64Make     (Arg <config.fe.TypeInt32()> {n} [off])     (Arg <config.fe.TypeUInt32()> {n} [off+4]))
+	// result: (Int64Make     (Arg <typ.Int32> {n} [off])     (Arg <typ.UInt32> {n} [off+4]))
 	for {
 		off := v.AuxInt
 		n := v.Aux
@@ -248,11 +265,11 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpArg, typ.Int32)
 		v0.AuxInt = off
 		v0.Aux = n
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v1.AuxInt = off + 4
 		v1.Aux = n
 		v.AddArg(v1)
@@ -260,7 +277,7 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 	}
 	// match: (Arg {n} [off])
 	// cond: is64BitInt(v.Type) && config.BigEndian && !v.Type.IsSigned()
-	// result: (Int64Make     (Arg <config.fe.TypeUInt32()> {n} [off])     (Arg <config.fe.TypeUInt32()> {n} [off+4]))
+	// result: (Int64Make     (Arg <typ.UInt32> {n} [off])     (Arg <typ.UInt32> {n} [off+4]))
 	for {
 		off := v.AuxInt
 		n := v.Aux
@@ -268,11 +285,11 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v0.AuxInt = off
 		v0.Aux = n
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpArg, typ.UInt32)
 		v1.AuxInt = off + 4
 		v1.Aux = n
 		v.AddArg(v1)
@@ -280,56 +297,94 @@ func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpBswap64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpBitLen64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (BitLen64 x)
+	// cond:
+	// result: (Add32 <typ.Int> 		(BitLen32 <typ.Int> (Int64Hi x)) 		(BitLen32 <typ.Int> 			(Or32 <typ.UInt32> 				(Int64Lo x) 				(Zeromask (Int64Hi x)))))
+	for {
+		x := v.Args[0]
+		v.reset(OpAdd32)
+		v.Type = typ.Int
+		v0 := b.NewValue0(v.Pos, OpBitLen32, typ.Int)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpBitLen32, typ.Int)
+		v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+		v4.AddArg(x)
+		v3.AddArg(v4)
+		v5 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+		v6.AddArg(x)
+		v5.AddArg(v6)
+		v3.AddArg(v5)
+		v2.AddArg(v3)
+		v.AddArg(v2)
+		return true
+	}
+}
+func rewriteValuedec64_OpBswap64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Bswap64 x)
 	// cond:
-	// result: (Int64Make 		(Bswap32 <config.fe.TypeUInt32()> (Int64Lo x)) 		(Bswap32 <config.fe.TypeUInt32()> (Int64Hi x)))
+	// result: (Int64Make 		(Bswap32 <typ.UInt32> (Int64Lo x)) 		(Bswap32 <typ.UInt32> (Int64Hi x)))
 	for {
 		x := v.Args[0]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpBswap32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpBswap32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpBswap32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpBswap32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v3.AddArg(x)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValuedec64_OpCom64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpCom64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Com64 x)
 	// cond:
-	// result: (Int64Make 		(Com32 <config.fe.TypeUInt32()> (Int64Hi x)) 		(Com32 <config.fe.TypeUInt32()> (Int64Lo x)))
+	// result: (Int64Make 		(Com32 <typ.UInt32> (Int64Hi x)) 		(Com32 <typ.UInt32> (Int64Lo x)))
 	for {
 		x := v.Args[0]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpCom32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpCom32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpCom32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpCom32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v3.AddArg(x)
 		v2.AddArg(v3)
 		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValuedec64_OpConst64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpConst64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Const64 <t> [c])
 	// cond: t.IsSigned()
-	// result: (Int64Make (Const32 <config.fe.TypeInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+	// result: (Int64Make (Const32 <typ.Int32> [c>>32]) (Const32 <typ.UInt32> [int64(int32(c))]))
 	for {
 		t := v.Type
 		c := v.AuxInt
@@ -337,17 +392,17 @@ func rewriteValuedec64_OpConst64(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpConst32, typ.Int32)
 		v0.AuxInt = c >> 32
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v1.AuxInt = int64(int32(c))
 		v.AddArg(v1)
 		return true
 	}
 	// match: (Const64 <t> [c])
 	// cond: !t.IsSigned()
-	// result: (Int64Make (Const32 <config.fe.TypeUInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+	// result: (Int64Make (Const32 <typ.UInt32> [c>>32]) (Const32 <typ.UInt32> [int64(int32(c))]))
 	for {
 		t := v.Type
 		c := v.AuxInt
@@ -355,113 +410,117 @@ func rewriteValuedec64_OpConst64(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v0.AuxInt = c >> 32
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v1.AuxInt = int64(int32(c))
 		v.AddArg(v1)
 		return true
 	}
 	return false
 }
-func rewriteValuedec64_OpCtz64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpCtz64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Ctz64 x)
 	// cond:
-	// result: (Int64Make 		(Const32 <config.fe.TypeUInt32()> [0]) 		(Add32 <config.fe.TypeUInt32()> 			(Ctz32 <config.fe.TypeUInt32()> (Int64Lo x)) 			(And32 <config.fe.TypeUInt32()> 				(Com32 <config.fe.TypeUInt32()> (Zeromask (Int64Lo x))) 				(Ctz32 <config.fe.TypeUInt32()> (Int64Hi x)))))
+	// result: (Add32 <typ.UInt32> 		(Ctz32 <typ.UInt32> (Int64Lo x)) 		(And32 <typ.UInt32> 			(Com32 <typ.UInt32> (Zeromask (Int64Lo x))) 			(Ctz32 <typ.UInt32> (Int64Hi x))))
 	for {
 		x := v.Args[0]
-		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
-		v0.AuxInt = 0
+		v.reset(OpAdd32)
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpCtz32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+		v1.AddArg(x)
+		v0.AddArg(v1)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpAdd32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpCtz32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
-		v3.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpCom32, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+		v5.AddArg(x)
+		v4.AddArg(v5)
+		v3.AddArg(v4)
 		v2.AddArg(v3)
-		v1.AddArg(v2)
-		v4 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v5 := b.NewValue0(v.Line, OpCom32, config.fe.TypeUInt32())
-		v6 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
-		v7 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpCtz32, typ.UInt32)
+		v7 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v7.AddArg(x)
 		v6.AddArg(v7)
-		v5.AddArg(v6)
-		v4.AddArg(v5)
-		v8 := b.NewValue0(v.Line, OpCtz32, config.fe.TypeUInt32())
-		v9 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
-		v9.AddArg(x)
-		v8.AddArg(v9)
-		v4.AddArg(v8)
-		v1.AddArg(v4)
-		v.AddArg(v1)
+		v2.AddArg(v6)
+		v.AddArg(v2)
 		return true
 	}
 }
-func rewriteValuedec64_OpEq64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpEq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Eq64 x y)
 	// cond:
 	// result: (AndB 		(Eq32 (Int64Hi x) (Int64Hi y)) 		(Eq32 (Int64Lo x) (Int64Lo y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpAndB)
-		v0 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(y)
 		v3.AddArg(v5)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValuedec64_OpGeq64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpGeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64 x y)
 	// cond:
 	// result: (OrB 		(Greater32 (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Geq32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpGreater32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpGreater32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpGeq32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpGeq32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -469,38 +528,41 @@ func rewriteValuedec64_OpGeq64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpGeq64U(v *Value, config *Config) bool {
+func rewriteValuedec64_OpGeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Geq64U x y)
 	// cond:
 	// result: (OrB 		(Greater32U (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Geq32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpGreater32U, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpGreater32U, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpGeq32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpGeq32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -508,38 +570,41 @@ func rewriteValuedec64_OpGeq64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpGreater64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpGreater64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater64 x y)
 	// cond:
 	// result: (OrB 		(Greater32 (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Greater32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpGreater32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpGreater32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpGreater32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpGreater32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -547,38 +612,41 @@ func rewriteValuedec64_OpGreater64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpGreater64U(v *Value, config *Config) bool {
+func rewriteValuedec64_OpGreater64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Greater64U x y)
 	// cond:
 	// result: (OrB 		(Greater32U (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Greater32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpGreater32U, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpGreater32U, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpGreater32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpGreater32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -586,9 +654,7 @@ func rewriteValuedec64_OpGreater64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpInt64Hi(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec64_OpInt64Hi_0(v *Value) bool {
 	// match: (Int64Hi (Int64Make hi _))
 	// cond:
 	// result: hi
@@ -597,6 +663,7 @@ func rewriteValuedec64_OpInt64Hi(v *Value, config *Config) bool {
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = hi.Type
@@ -605,9 +672,7 @@ func rewriteValuedec64_OpInt64Hi(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpInt64Lo(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec64_OpInt64Lo_0(v *Value) bool {
 	// match: (Int64Lo (Int64Make _ lo))
 	// cond:
 	// result: lo
@@ -616,6 +681,7 @@ func rewriteValuedec64_OpInt64Lo(v *Value, config *Config) bool {
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		lo := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = lo.Type
@@ -624,38 +690,41 @@ func rewriteValuedec64_OpInt64Lo(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLeq64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64 x y)
 	// cond:
 	// result: (OrB 		(Less32 (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Leq32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpLess32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpLess32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpLeq32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpLeq32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -663,38 +732,41 @@ func rewriteValuedec64_OpLeq64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpLeq64U(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLeq64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Leq64U x y)
 	// cond:
 	// result: (OrB 		(Less32U (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Leq32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpLess32U, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpLess32U, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpLeq32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpLeq32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -702,38 +774,41 @@ func rewriteValuedec64_OpLeq64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpLess64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLess64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less64 x y)
 	// cond:
 	// result: (OrB 		(Less32 (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Less32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpLess32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpLess32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpLess32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpLess32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -741,38 +816,41 @@ func rewriteValuedec64_OpLess64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpLess64U(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLess64U_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Less64U x y)
 	// cond:
 	// result: (OrB 		(Less32U (Int64Hi x) (Int64Hi y)) 		(AndB 			(Eq32 (Int64Hi x) (Int64Hi y)) 			(Less32U (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpLess32U, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpLess32U, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpAndB, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpEq32, config.fe.TypeBool())
-		v5 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpAndB, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+		v5 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
-		v7 := b.NewValue0(v.Line, OpLess32U, config.fe.TypeBool())
-		v8 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpLess32U, typ.Bool)
+		v8 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v8.AddArg(x)
 		v7.AddArg(v8)
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(y)
 		v7.AddArg(v9)
 		v3.AddArg(v7)
@@ -780,28 +858,33 @@ func rewriteValuedec64_OpLess64U(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLoad_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Load <t> ptr mem)
 	// cond: is64BitInt(t) && !config.BigEndian && t.IsSigned()
-	// result: (Int64Make 		(Load <config.fe.TypeInt32()> (OffPtr <config.fe.TypeInt32().PtrTo()> [4] ptr) mem) 		(Load <config.fe.TypeUInt32()> ptr mem))
+	// result: (Int64Make 		(Load <typ.Int32> (OffPtr <typ.Int32Ptr> [4] ptr) mem) 		(Load <typ.UInt32> ptr mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) && !config.BigEndian && t.IsSigned()) {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt32().PtrTo())
+		v0 := b.NewValue0(v.Pos, OpLoad, typ.Int32)
+		v1 := b.NewValue0(v.Pos, OpOffPtr, typ.Int32Ptr)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
 		v0.AddArg(v1)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
 		v2.AddArg(ptr)
 		v2.AddArg(mem)
 		v.AddArg(v2)
@@ -809,23 +892,24 @@ func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
 	}
 	// match: (Load <t> ptr mem)
 	// cond: is64BitInt(t) && !config.BigEndian && !t.IsSigned()
-	// result: (Int64Make 		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem) 		(Load <config.fe.TypeUInt32()> ptr mem))
+	// result: (Int64Make 		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem) 		(Load <typ.UInt32> ptr mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) && !config.BigEndian && !t.IsSigned()) {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeUInt32().PtrTo())
+		v0 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpOffPtr, typ.UInt32Ptr)
 		v1.AuxInt = 4
 		v1.AddArg(ptr)
 		v0.AddArg(v1)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
 		v2.AddArg(ptr)
 		v2.AddArg(mem)
 		v.AddArg(v2)
@@ -833,21 +917,22 @@ func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
 	}
 	// match: (Load <t> ptr mem)
 	// cond: is64BitInt(t) && config.BigEndian && t.IsSigned()
-	// result: (Int64Make 		(Load <config.fe.TypeInt32()> ptr mem) 		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem))
+	// result: (Int64Make 		(Load <typ.Int32> ptr mem) 		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) && config.BigEndian && t.IsSigned()) {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpLoad, typ.Int32)
 		v0.AddArg(ptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeUInt32().PtrTo())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.UInt32Ptr)
 		v2.AuxInt = 4
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -857,21 +942,22 @@ func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
 	}
 	// match: (Load <t> ptr mem)
 	// cond: is64BitInt(t) && config.BigEndian && !t.IsSigned()
-	// result: (Int64Make 		(Load <config.fe.TypeUInt32()> ptr mem) 		(Load <config.fe.TypeUInt32()> (OffPtr <config.fe.TypeUInt32().PtrTo()> [4] ptr) mem))
+	// result: (Int64Make 		(Load <typ.UInt32> ptr mem) 		(Load <typ.UInt32> (OffPtr <typ.UInt32Ptr> [4] ptr) mem))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		ptr := v.Args[0]
 		mem := v.Args[1]
 		if !(is64BitInt(t) && config.BigEndian && !t.IsSigned()) {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
 		v0.AddArg(ptr)
 		v0.AddArg(mem)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeUInt32().PtrTo())
+		v1 := b.NewValue0(v.Pos, OpLoad, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, typ.UInt32Ptr)
 		v2.AuxInt = 4
 		v2.AddArg(ptr)
 		v1.AddArg(v2)
@@ -881,89 +967,21 @@ func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLrot64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lrot64 (Int64Make hi lo) [c])
-	// cond: c <= 32
-	// result: (Int64Make 		(Or32 <config.fe.TypeUInt32()> 			(Lsh32x32 <config.fe.TypeUInt32()> hi (Const32 <config.fe.TypeUInt32()> [c])) 			(Rsh32Ux32 <config.fe.TypeUInt32()> lo (Const32 <config.fe.TypeUInt32()> [32-c]))) 		(Or32 <config.fe.TypeUInt32()> 			(Lsh32x32 <config.fe.TypeUInt32()> lo (Const32 <config.fe.TypeUInt32()> [c])) 			(Rsh32Ux32 <config.fe.TypeUInt32()> hi (Const32 <config.fe.TypeUInt32()> [32-c]))))
-	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpInt64Make {
-			break
-		}
-		hi := v_0.Args[0]
-		lo := v_0.Args[1]
-		if !(c <= 32) {
-			break
-		}
-		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
-		v1.AddArg(hi)
-		v2 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
-		v2.AuxInt = c
-		v1.AddArg(v2)
-		v0.AddArg(v1)
-		v3 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
-		v3.AddArg(lo)
-		v4 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
-		v4.AuxInt = 32 - c
-		v3.AddArg(v4)
-		v0.AddArg(v3)
-		v.AddArg(v0)
-		v5 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v6 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
-		v6.AddArg(lo)
-		v7 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
-		v7.AuxInt = c
-		v6.AddArg(v7)
-		v5.AddArg(v6)
-		v8 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
-		v8.AddArg(hi)
-		v9 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
-		v9.AuxInt = 32 - c
-		v8.AddArg(v9)
-		v5.AddArg(v8)
-		v.AddArg(v5)
-		return true
-	}
-	// match: (Lrot64 (Int64Make hi lo) [c])
-	// cond: c > 32
-	// result: (Lrot64 (Int64Make lo hi) [c-32])
-	for {
-		c := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpInt64Make {
-			break
-		}
-		hi := v_0.Args[0]
-		lo := v_0.Args[1]
-		if !(c > 32) {
-			break
-		}
-		v.reset(OpLrot64)
-		v.AuxInt = c - 32
-		v0 := b.NewValue0(v.Line, OpInt64Make, config.fe.TypeUInt64())
-		v0.AddArg(lo)
-		v0.AddArg(hi)
-		v.AddArg(v0)
-		return true
-	}
-	return false
-}
-func rewriteValuedec64_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh16x64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -980,11 +998,13 @@ func rewriteValuedec64_OpLsh16x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Lsh16x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1000,13 +1020,15 @@ func rewriteValuedec64_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh16x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Lsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Lsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1014,8 +1036,8 @@ func rewriteValuedec64_OpLsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpLsh16x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1024,17 +1046,21 @@ func rewriteValuedec64_OpLsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh32x64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1051,11 +1077,13 @@ func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Lsh32x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1071,13 +1099,15 @@ func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh32x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Lsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Lsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1085,8 +1115,8 @@ func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpLsh32x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1095,48 +1125,52 @@ func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh64x16(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x16 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Lsh32x16 <config.fe.TypeUInt32()> hi s) 				(Rsh32Ux16 <config.fe.TypeUInt32()> 					lo 					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s))) 			(Lsh32x16 <config.fe.TypeUInt32()> 				lo 				(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32])))) 		(Lsh32x16 <config.fe.TypeUInt32()> lo s))
+	// result: (Int64Make 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Lsh32x16 <typ.UInt32> hi s) 				(Rsh32Ux16 <typ.UInt32> 					lo 					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) 			(Lsh32x16 <typ.UInt32> 				lo 				(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))) 		(Lsh32x16 <typ.UInt32> lo s))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
 		v2.AddArg(hi)
 		v2.AddArg(s)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
 		v3.AddArg(lo)
-		v4 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
-		v5 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v4 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+		v5 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v5.AuxInt = 32
 		v4.AddArg(v5)
 		v4.AddArg(s)
 		v3.AddArg(v4)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
-		v6 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
 		v6.AddArg(lo)
-		v7 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+		v7 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
 		v7.AddArg(s)
-		v8 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v8 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v8.AuxInt = 32
 		v7.AddArg(v8)
 		v6.AddArg(v7)
 		v0.AddArg(v6)
 		v.AddArg(v0)
-		v9 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
 		v9.AddArg(lo)
 		v9.AddArg(s)
 		v.AddArg(v9)
@@ -1144,48 +1178,52 @@ func rewriteValuedec64_OpLsh64x16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh64x32(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x32 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Lsh32x32 <config.fe.TypeUInt32()> hi s) 				(Rsh32Ux32 <config.fe.TypeUInt32()> 					lo 					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s))) 			(Lsh32x32 <config.fe.TypeUInt32()> 				lo 				(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32])))) 		(Lsh32x32 <config.fe.TypeUInt32()> lo s))
+	// result: (Int64Make 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Lsh32x32 <typ.UInt32> hi s) 				(Rsh32Ux32 <typ.UInt32> 					lo 					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) 			(Lsh32x32 <typ.UInt32> 				lo 				(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))) 		(Lsh32x32 <typ.UInt32> lo s))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
 		v2.AddArg(hi)
 		v2.AddArg(s)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v3.AddArg(lo)
-		v4 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
-		v5 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+		v5 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v5.AuxInt = 32
 		v4.AddArg(v5)
 		v4.AddArg(s)
 		v3.AddArg(v4)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
-		v6 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
 		v6.AddArg(lo)
-		v7 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
 		v7.AddArg(s)
-		v8 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v8 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v8.AuxInt = 32
 		v7.AddArg(v8)
 		v6.AddArg(v7)
 		v0.AddArg(v6)
 		v.AddArg(v0)
-		v9 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
 		v9.AddArg(lo)
 		v9.AddArg(s)
 		v.AddArg(v9)
@@ -1193,17 +1231,21 @@ func rewriteValuedec64_OpLsh64x32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1220,11 +1262,13 @@ func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Lsh64x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1240,13 +1284,15 @@ func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh64x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Lsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Lsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1254,8 +1300,8 @@ func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpLsh64x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1264,48 +1310,52 @@ func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh64x8 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Lsh32x8 <config.fe.TypeUInt32()> hi s) 				(Rsh32Ux8 <config.fe.TypeUInt32()> 					lo 					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s))) 			(Lsh32x8 <config.fe.TypeUInt32()> 				lo 				(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32])))) 		(Lsh32x8 <config.fe.TypeUInt32()> lo s))
+	// result: (Int64Make 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Lsh32x8 <typ.UInt32> hi s) 				(Rsh32Ux8 <typ.UInt32> 					lo 					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) 			(Lsh32x8 <typ.UInt32> 				lo 				(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))) 		(Lsh32x8 <typ.UInt32> lo s))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
 		v2.AddArg(hi)
 		v2.AddArg(s)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
 		v3.AddArg(lo)
-		v4 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
-		v5 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v4 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+		v5 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v5.AuxInt = 32
 		v4.AddArg(v5)
 		v4.AddArg(s)
 		v3.AddArg(v4)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
-		v6 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
 		v6.AddArg(lo)
-		v7 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+		v7 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
 		v7.AddArg(s)
-		v8 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v8 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v8.AuxInt = 32
 		v7.AddArg(v8)
 		v6.AddArg(v7)
 		v0.AddArg(v6)
 		v.AddArg(v0)
-		v9 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
 		v9.AddArg(lo)
 		v9.AddArg(s)
 		v.AddArg(v9)
@@ -1313,17 +1363,21 @@ func rewriteValuedec64_OpLsh64x8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpLsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Lsh8x64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1340,11 +1394,13 @@ func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Lsh8x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1360,13 +1416,15 @@ func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	// match: (Lsh8x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Lsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Lsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1374,8 +1432,8 @@ func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpLsh8x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1384,52 +1442,55 @@ func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpMul64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpMul64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Mul64 x y)
 	// cond:
-	// result: (Int64Make 		(Add32 <config.fe.TypeUInt32()> 			(Mul32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Hi y)) 			(Add32 <config.fe.TypeUInt32()> 				(Mul32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Lo y)) 				(Select0 <config.fe.TypeUInt32()> (Mul32uhilo (Int64Lo x) (Int64Lo y))))) 		(Select1 <config.fe.TypeUInt32()> (Mul32uhilo (Int64Lo x) (Int64Lo y))))
+	// result: (Int64Make 		(Add32 <typ.UInt32> 			(Mul32 <typ.UInt32> (Int64Lo x) (Int64Hi y)) 			(Add32 <typ.UInt32> 				(Mul32 <typ.UInt32> (Int64Hi x) (Int64Lo y)) 				(Select0 <typ.UInt32> (Mul32uhilo (Int64Lo x) (Int64Lo y))))) 		(Select1 <typ.UInt32> (Mul32uhilo (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpAdd32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpMul32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpAdd32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v2.AddArg(x)
 		v1.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v3.AddArg(y)
 		v1.AddArg(v3)
 		v0.AddArg(v1)
-		v4 := b.NewValue0(v.Line, OpAdd32, config.fe.TypeUInt32())
-		v5 := b.NewValue0(v.Line, OpMul32, config.fe.TypeUInt32())
-		v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpAdd32, typ.UInt32)
+		v5 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v6 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v6.AddArg(x)
 		v5.AddArg(v6)
-		v7 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v7.AddArg(y)
 		v5.AddArg(v7)
 		v4.AddArg(v5)
-		v8 := b.NewValue0(v.Line, OpSelect0, config.fe.TypeUInt32())
-		v9 := b.NewValue0(v.Line, OpMul32uhilo, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v10 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v8 := b.NewValue0(v.Pos, OpSelect0, typ.UInt32)
+		v9 := b.NewValue0(v.Pos, OpMul32uhilo, types.NewTuple(typ.UInt32, typ.UInt32))
+		v10 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v10.AddArg(x)
 		v9.AddArg(v10)
-		v11 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v11 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v11.AddArg(y)
 		v9.AddArg(v11)
 		v8.AddArg(v9)
 		v4.AddArg(v8)
 		v0.AddArg(v4)
 		v.AddArg(v0)
-		v12 := b.NewValue0(v.Line, OpSelect1, config.fe.TypeUInt32())
-		v13 := b.NewValue0(v.Line, OpMul32uhilo, MakeTuple(config.fe.TypeUInt32(), config.fe.TypeUInt32()))
-		v14 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v12 := b.NewValue0(v.Pos, OpSelect1, typ.UInt32)
+		v13 := b.NewValue0(v.Pos, OpMul32uhilo, types.NewTuple(typ.UInt32, typ.UInt32))
+		v14 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v14.AddArg(x)
 		v13.AddArg(v14)
-		v15 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v15 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v15.AddArg(y)
 		v13.AddArg(v15)
 		v12.AddArg(v13)
@@ -1437,7 +1498,7 @@ func rewriteValuedec64_OpMul64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpNeg64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpNeg64_0(v *Value) bool {
 	b := v.Block
 	_ = b
 	// match: (Neg64 <t> x)
@@ -1447,82 +1508,92 @@ func rewriteValuedec64_OpNeg64(v *Value, config *Config) bool {
 		t := v.Type
 		x := v.Args[0]
 		v.reset(OpSub64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuedec64_OpNeq64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpNeq64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Neq64 x y)
 	// cond:
 	// result: (OrB 		(Neq32 (Int64Hi x) (Int64Hi y)) 		(Neq32 (Int64Lo x) (Int64Lo y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpOrB)
-		v0 := b.NewValue0(v.Line, OpNeq32, config.fe.TypeBool())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpNeq32, typ.Bool)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpNeq32, config.fe.TypeBool())
-		v4 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpNeq32, typ.Bool)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(y)
 		v3.AddArg(v5)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValuedec64_OpOr64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpOr64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Or64 x y)
 	// cond:
-	// result: (Int64Make 		(Or32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) 		(Or32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+	// result: (Int64Make 		(Or32 <typ.UInt32> (Int64Hi x) (Int64Hi y)) 		(Or32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(y)
 		v3.AddArg(v5)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16Ux64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1539,11 +1610,13 @@ func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh16Ux32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1559,13 +1632,15 @@ func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh16Ux64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh16Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1573,8 +1648,8 @@ func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh16Ux32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1583,18 +1658,22 @@ func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh16x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh16x64 x (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Signmask (SignExt16to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1604,7 +1683,7 @@ func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpSignmask)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -1613,11 +1692,13 @@ func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh16x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1633,13 +1714,15 @@ func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh16x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1647,8 +1730,8 @@ func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh16x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1657,17 +1740,21 @@ func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh32Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32Ux64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1684,11 +1771,13 @@ func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh32Ux32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1704,13 +1793,15 @@ func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32Ux64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh32Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1718,8 +1809,8 @@ func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh32Ux32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1728,18 +1819,22 @@ func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh32x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh32x64 x (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Signmask x)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1756,11 +1851,13 @@ func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh32x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1776,13 +1873,15 @@ func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh32x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1790,8 +1889,8 @@ func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh32x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1800,46 +1899,50 @@ func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux16 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32Ux16 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux16 <config.fe.TypeUInt32()> lo s) 				(Lsh32x16 <config.fe.TypeUInt32()> 					hi 					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s))) 			(Rsh32Ux16 <config.fe.TypeUInt32()> 				hi 				(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32])))))
+	// result: (Int64Make 		(Rsh32Ux16 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux16 <typ.UInt32> lo s) 				(Lsh32x16 <typ.UInt32> 					hi 					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) 			(Rsh32Ux16 <typ.UInt32> 				hi 				(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
-		v6 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v5 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+		v6 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
 		v7.AddArg(hi)
-		v8 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+		v8 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
 		v8.AddArg(s)
-		v9 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v9 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v9.AuxInt = 32
 		v8.AddArg(v9)
 		v7.AddArg(v8)
@@ -1849,46 +1952,50 @@ func rewriteValuedec64_OpRsh64Ux16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux32 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32Ux32 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux32 <config.fe.TypeUInt32()> lo s) 				(Lsh32x32 <config.fe.TypeUInt32()> 					hi 					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s))) 			(Rsh32Ux32 <config.fe.TypeUInt32()> 				hi 				(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32])))))
+	// result: (Int64Make 		(Rsh32Ux32 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux32 <typ.UInt32> lo s) 				(Lsh32x32 <typ.UInt32> 					hi 					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) 			(Rsh32Ux32 <typ.UInt32> 				hi 				(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
-		v6 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+		v6 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v7.AddArg(hi)
-		v8 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+		v8 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
 		v8.AddArg(s)
-		v9 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v9.AuxInt = 32
 		v8.AddArg(v9)
 		v7.AddArg(v8)
@@ -1898,17 +2005,21 @@ func rewriteValuedec64_OpRsh64Ux32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1925,11 +2036,13 @@ func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh64Ux32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -1945,13 +2058,15 @@ func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64Ux64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh64Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -1959,8 +2074,8 @@ func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh64Ux32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -1969,46 +2084,50 @@ func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64Ux8 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32Ux8 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux8 <config.fe.TypeUInt32()> lo s) 				(Lsh32x8 <config.fe.TypeUInt32()> 					hi 					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s))) 			(Rsh32Ux8 <config.fe.TypeUInt32()> 				hi 				(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32])))))
+	// result: (Int64Make 		(Rsh32Ux8 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux8 <typ.UInt32> lo s) 				(Lsh32x8 <typ.UInt32> 					hi 					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) 			(Rsh32Ux8 <typ.UInt32> 				hi 				(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
-		v6 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v5 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+		v6 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
 		v7.AddArg(hi)
-		v8 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+		v8 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
 		v8.AddArg(s)
-		v9 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v9 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v9.AuxInt = 32
 		v8.AddArg(v9)
 		v7.AddArg(v8)
@@ -2018,56 +2137,60 @@ func rewriteValuedec64_OpRsh64Ux8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64x16_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x16 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32x16 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux16 <config.fe.TypeUInt32()> lo s) 				(Lsh32x16 <config.fe.TypeUInt32()> 					hi 					(Sub16 <config.fe.TypeUInt16()> (Const16 <config.fe.TypeUInt16()> [32]) s))) 			(And32 <config.fe.TypeUInt32()> 				(Rsh32x16 <config.fe.TypeUInt32()> 					hi 					(Sub16 <config.fe.TypeUInt16()> s (Const16 <config.fe.TypeUInt16()> [32]))) 				(Zeromask 					(Z [...]
+	// result: (Int64Make 		(Rsh32x16 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux16 <typ.UInt32> lo s) 				(Lsh32x16 <typ.UInt32> 					hi 					(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) 			(And32 <typ.UInt32> 				(Rsh32x16 <typ.UInt32> 					hi 					(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32]))) 				(Zeromask 					(ZeroExt16to32 						(Rsh16Ux32 <typ.UInt16> s (Const32 <typ.UInt32> [5])))))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32x16, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32x16, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
-		v6 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v5 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+		v6 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpRsh32x16, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpRsh32x16, typ.UInt32)
 		v8.AddArg(hi)
-		v9 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+		v9 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
 		v9.AddArg(s)
-		v10 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+		v10 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
 		v10.AuxInt = 32
 		v9.AddArg(v10)
 		v8.AddArg(v9)
 		v7.AddArg(v8)
-		v11 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
-		v12 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
-		v13 := b.NewValue0(v.Line, OpRsh16Ux32, config.fe.TypeUInt16())
+		v11 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+		v12 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+		v13 := b.NewValue0(v.Pos, OpRsh16Ux32, typ.UInt16)
 		v13.AddArg(s)
-		v14 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v14 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v14.AuxInt = 5
 		v13.AddArg(v14)
 		v12.AddArg(v13)
@@ -2079,55 +2202,59 @@ func rewriteValuedec64_OpRsh64x16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64x32(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64x32_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x32 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32x32 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux32 <config.fe.TypeUInt32()> lo s) 				(Lsh32x32 <config.fe.TypeUInt32()> 					hi 					(Sub32 <config.fe.TypeUInt32()> (Const32 <config.fe.TypeUInt32()> [32]) s))) 			(And32 <config.fe.TypeUInt32()> 				(Rsh32x32 <config.fe.TypeUInt32()> 					hi 					(Sub32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [32]))) 				(Zeromask 					(R [...]
+	// result: (Int64Make 		(Rsh32x32 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux32 <typ.UInt32> lo s) 				(Lsh32x32 <typ.UInt32> 					hi 					(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) 			(And32 <typ.UInt32> 				(Rsh32x32 <typ.UInt32> 					hi 					(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32]))) 				(Zeromask 					(Rsh32Ux32 <typ.UInt32> s (Const32 <typ.UInt32> [5]))))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32x32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32x32, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
-		v6 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+		v6 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpRsh32x32, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpRsh32x32, typ.UInt32)
 		v8.AddArg(hi)
-		v9 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+		v9 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
 		v9.AddArg(s)
-		v10 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v10 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v10.AuxInt = 32
 		v9.AddArg(v10)
 		v8.AddArg(v9)
 		v7.AddArg(v8)
-		v11 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
-		v12 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+		v11 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+		v12 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
 		v12.AddArg(s)
-		v13 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v13 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v13.AuxInt = 5
 		v12.AddArg(v13)
 		v11.AddArg(v12)
@@ -2138,18 +2265,22 @@ func rewriteValuedec64_OpRsh64x32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x64 x (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Int64Make (Signmask (Int64Hi x)) (Signmask (Int64Hi x)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2159,13 +2290,13 @@ func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
-		v3 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
+		v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v3.AddArg(x)
 		v2.AddArg(v3)
 		v.AddArg(v2)
@@ -2175,11 +2306,13 @@ func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh64x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2195,13 +2328,15 @@ func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh64x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -2209,8 +2344,8 @@ func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh64x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -2219,56 +2354,60 @@ func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh64x8(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh64x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh64x8 (Int64Make hi lo) s)
 	// cond:
-	// result: (Int64Make 		(Rsh32x8 <config.fe.TypeUInt32()> hi s) 		(Or32 <config.fe.TypeUInt32()> 			(Or32 <config.fe.TypeUInt32()> 				(Rsh32Ux8 <config.fe.TypeUInt32()> lo s) 				(Lsh32x8 <config.fe.TypeUInt32()> 					hi 					(Sub8 <config.fe.TypeUInt8()> (Const8 <config.fe.TypeUInt8()> [32]) s))) 			(And32 <config.fe.TypeUInt32()> 				(Rsh32x8 <config.fe.TypeUInt32()> 					hi 					(Sub8 <config.fe.TypeUInt8()> s (Const8 <config.fe.TypeUInt8()> [32]))) 				(Zeromask 					(ZeroExt8to32  [...]
+	// result: (Int64Make 		(Rsh32x8 <typ.UInt32> hi s) 		(Or32 <typ.UInt32> 			(Or32 <typ.UInt32> 				(Rsh32Ux8 <typ.UInt32> lo s) 				(Lsh32x8 <typ.UInt32> 					hi 					(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) 			(And32 <typ.UInt32> 				(Rsh32x8 <typ.UInt32> 					hi 					(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32]))) 				(Zeromask 					(ZeroExt8to32 						(Rsh8Ux32 <typ.UInt8> s (Const32 <typ.UInt32> [5])))))))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		hi := v_0.Args[0]
 		lo := v_0.Args[1]
 		s := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpRsh32x8, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpRsh32x8, typ.UInt32)
 		v0.AddArg(hi)
 		v0.AddArg(s)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v2 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v3 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+		v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
 		v3.AddArg(lo)
 		v3.AddArg(s)
 		v2.AddArg(v3)
-		v4 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+		v4 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
 		v4.AddArg(hi)
-		v5 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
-		v6 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v5 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+		v6 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v6.AuxInt = 32
 		v5.AddArg(v6)
 		v5.AddArg(s)
 		v4.AddArg(v5)
 		v2.AddArg(v4)
 		v1.AddArg(v2)
-		v7 := b.NewValue0(v.Line, OpAnd32, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpRsh32x8, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpRsh32x8, typ.UInt32)
 		v8.AddArg(hi)
-		v9 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+		v9 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
 		v9.AddArg(s)
-		v10 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+		v10 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
 		v10.AuxInt = 32
 		v9.AddArg(v10)
 		v8.AddArg(v9)
 		v7.AddArg(v8)
-		v11 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
-		v12 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
-		v13 := b.NewValue0(v.Line, OpRsh8Ux32, config.fe.TypeUInt8())
+		v11 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+		v12 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
+		v13 := b.NewValue0(v.Pos, OpRsh8Ux32, typ.UInt8)
 		v13.AddArg(s)
-		v14 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v14 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v14.AuxInt = 5
 		v13.AddArg(v14)
 		v12.AddArg(v13)
@@ -2280,17 +2419,21 @@ func rewriteValuedec64_OpRsh64x8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh8Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8Ux64 _ (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2307,11 +2450,13 @@ func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh8Ux32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2327,13 +2472,15 @@ func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh8Ux64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh8Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -2341,8 +2488,8 @@ func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh8Ux32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -2351,18 +2498,22 @@ func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpRsh8x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Rsh8x64 x (Int64Make (Const32 [c]) _))
 	// cond: c != 0
 	// result: (Signmask (SignExt8to32 x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2372,7 +2523,7 @@ func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
 			break
 		}
 		v.reset(OpSignmask)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
@@ -2381,11 +2532,13 @@ func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
 	// cond:
 	// result: (Rsh8x32 x lo)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
 		if v_1_0.Op != OpConst32 {
 			break
@@ -2401,13 +2554,15 @@ func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	// match: (Rsh8x64 x (Int64Make hi lo))
 	// cond: hi.Op != OpConst32
-	// result: (Rsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+	// result: (Rsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		if !(hi.Op != OpConst32) {
@@ -2415,8 +2570,8 @@ func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
 		}
 		v.reset(OpRsh8x32)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
 		v1.AddArg(hi)
 		v0.AddArg(v1)
 		v0.AddArg(lo)
@@ -2425,115 +2580,123 @@ func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpSignExt16to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpSignExt16to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (SignExt16to64 x)
 	// cond:
 	// result: (SignExt32to64 (SignExt16to32 x))
 	for {
 		x := v.Args[0]
 		v.reset(OpSignExt32to64)
-		v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuedec64_OpSignExt32to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpSignExt32to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (SignExt32to64 x)
 	// cond:
 	// result: (Int64Make (Signmask x) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignmask, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuedec64_OpSignExt8to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpSignExt8to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (SignExt8to64 x)
 	// cond:
 	// result: (SignExt32to64 (SignExt8to32 x))
 	for {
 		x := v.Args[0]
 		v.reset(OpSignExt32to64)
-		v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+		v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuedec64_OpStore(v *Value, config *Config) bool {
+func rewriteValuedec64_OpStore_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Store [8] dst (Int64Make hi lo) mem)
-	// cond: !config.BigEndian
-	// result: (Store [4] 		(OffPtr <hi.Type.PtrTo()> [4] dst) 		hi 		(Store [4] dst lo mem))
-	for {
-		if v.AuxInt != 8 {
-			break
-		}
+	config := b.Func.Config
+	_ = config
+	// match: (Store {t} dst (Int64Make hi lo) mem)
+	// cond: t.(*types.Type).Size() == 8 && !config.BigEndian
+	// result: (Store {hi.Type} 		(OffPtr <hi.Type.PtrTo()> [4] dst) 		hi 		(Store {lo.Type} dst lo mem))
+	for {
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		mem := v.Args[2]
-		if !(!config.BigEndian) {
+		if !(t.(*types.Type).Size() == 8 && !config.BigEndian) {
 			break
 		}
 		v.reset(OpStore)
-		v.AuxInt = 4
-		v0 := b.NewValue0(v.Line, OpOffPtr, hi.Type.PtrTo())
+		v.Aux = hi.Type
+		v0 := b.NewValue0(v.Pos, OpOffPtr, hi.Type.PtrTo())
 		v0.AuxInt = 4
 		v0.AddArg(dst)
 		v.AddArg(v0)
 		v.AddArg(hi)
-		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
-		v1.AuxInt = 4
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = lo.Type
 		v1.AddArg(dst)
 		v1.AddArg(lo)
 		v1.AddArg(mem)
 		v.AddArg(v1)
 		return true
 	}
-	// match: (Store [8] dst (Int64Make hi lo) mem)
-	// cond: config.BigEndian
-	// result: (Store [4] 		(OffPtr <lo.Type.PtrTo()> [4] dst) 		lo 		(Store [4] dst hi mem))
+	// match: (Store {t} dst (Int64Make hi lo) mem)
+	// cond: t.(*types.Type).Size() == 8 && config.BigEndian
+	// result: (Store {lo.Type} 		(OffPtr <lo.Type.PtrTo()> [4] dst) 		lo 		(Store {hi.Type} dst hi mem))
 	for {
-		if v.AuxInt != 8 {
-			break
-		}
+		t := v.Aux
+		_ = v.Args[2]
 		dst := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpInt64Make {
 			break
 		}
+		_ = v_1.Args[1]
 		hi := v_1.Args[0]
 		lo := v_1.Args[1]
 		mem := v.Args[2]
-		if !(config.BigEndian) {
+		if !(t.(*types.Type).Size() == 8 && config.BigEndian) {
 			break
 		}
 		v.reset(OpStore)
-		v.AuxInt = 4
-		v0 := b.NewValue0(v.Line, OpOffPtr, lo.Type.PtrTo())
+		v.Aux = lo.Type
+		v0 := b.NewValue0(v.Pos, OpOffPtr, lo.Type.PtrTo())
 		v0.AuxInt = 4
 		v0.AddArg(dst)
 		v.AddArg(v0)
 		v.AddArg(lo)
-		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
-		v1.AuxInt = 4
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = hi.Type
 		v1.AddArg(dst)
 		v1.AddArg(hi)
 		v1.AddArg(mem)
@@ -2542,40 +2705,43 @@ func rewriteValuedec64_OpStore(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpSub64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpSub64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Sub64 x y)
 	// cond:
-	// result: (Int64Make 		(Sub32withcarry <config.fe.TypeInt32()> 			(Int64Hi x) 			(Int64Hi y) 			(Select1 <TypeFlags> (Sub32carry (Int64Lo x) (Int64Lo y)))) 		(Select0 <config.fe.TypeUInt32()> (Sub32carry (Int64Lo x) (Int64Lo y))))
+	// result: (Int64Make 		(Sub32withcarry <typ.Int32> 			(Int64Hi x) 			(Int64Hi y) 			(Select1 <types.TypeFlags> (Sub32carry (Int64Lo x) (Int64Lo y)))) 		(Select0 <typ.UInt32> (Sub32carry (Int64Lo x) (Int64Lo y))))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpSub32withcarry, config.fe.TypeInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpSub32withcarry, typ.Int32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpSelect1, TypeFlags)
-		v4 := b.NewValue0(v.Line, OpSub32carry, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+		v4 := b.NewValue0(v.Pos, OpSub32carry, types.NewTuple(typ.UInt32, types.TypeFlags))
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(x)
 		v4.AddArg(v5)
-		v6 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v6 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v6.AddArg(y)
 		v4.AddArg(v6)
 		v3.AddArg(v4)
 		v0.AddArg(v3)
 		v.AddArg(v0)
-		v7 := b.NewValue0(v.Line, OpSelect0, config.fe.TypeUInt32())
-		v8 := b.NewValue0(v.Line, OpSub32carry, MakeTuple(config.fe.TypeUInt32(), TypeFlags))
-		v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v7 := b.NewValue0(v.Pos, OpSelect0, typ.UInt32)
+		v8 := b.NewValue0(v.Pos, OpSub32carry, types.NewTuple(typ.UInt32, types.TypeFlags))
+		v9 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v9.AddArg(x)
 		v8.AddArg(v9)
-		v10 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v10 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v10.AddArg(y)
 		v8.AddArg(v10)
 		v7.AddArg(v8)
@@ -2583,9 +2749,7 @@ func rewriteValuedec64_OpSub64(v *Value, config *Config) bool {
 		return true
 	}
 }
-func rewriteValuedec64_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec64_OpTrunc64to16_0(v *Value) bool {
 	// match: (Trunc64to16 (Int64Make _ lo))
 	// cond:
 	// result: (Trunc32to16 lo)
@@ -2594,6 +2758,7 @@ func rewriteValuedec64_OpTrunc64to16(v *Value, config *Config) bool {
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		lo := v_0.Args[1]
 		v.reset(OpTrunc32to16)
 		v.AddArg(lo)
@@ -2601,9 +2766,7 @@ func rewriteValuedec64_OpTrunc64to16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpTrunc64to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec64_OpTrunc64to32_0(v *Value) bool {
 	// match: (Trunc64to32 (Int64Make _ lo))
 	// cond:
 	// result: lo
@@ -2612,6 +2775,7 @@ func rewriteValuedec64_OpTrunc64to32(v *Value, config *Config) bool {
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		lo := v_0.Args[1]
 		v.reset(OpCopy)
 		v.Type = lo.Type
@@ -2620,9 +2784,7 @@ func rewriteValuedec64_OpTrunc64to32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuedec64_OpTrunc64to8_0(v *Value) bool {
 	// match: (Trunc64to8 (Int64Make _ lo))
 	// cond:
 	// result: (Trunc32to8 lo)
@@ -2631,6 +2793,7 @@ func rewriteValuedec64_OpTrunc64to8(v *Value, config *Config) bool {
 		if v_0.Op != OpInt64Make {
 			break
 		}
+		_ = v_0.Args[1]
 		lo := v_0.Args[1]
 		v.reset(OpTrunc32to8)
 		v.AddArg(lo)
@@ -2638,82 +2801,97 @@ func rewriteValuedec64_OpTrunc64to8(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuedec64_OpXor64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpXor64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (Xor64 x y)
 	// cond:
-	// result: (Int64Make 		(Xor32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) 		(Xor32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+	// result: (Int64Make 		(Xor32 <typ.UInt32> (Int64Hi x) (Int64Hi y)) 		(Xor32 <typ.UInt32> (Int64Lo x) (Int64Lo y)))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		y := v.Args[1]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpXor32, config.fe.TypeUInt32())
-		v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpXor32, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v1.AddArg(x)
 		v0.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+		v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
 		v2.AddArg(y)
 		v0.AddArg(v2)
 		v.AddArg(v0)
-		v3 := b.NewValue0(v.Line, OpXor32, config.fe.TypeUInt32())
-		v4 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v3 := b.NewValue0(v.Pos, OpXor32, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v4.AddArg(x)
 		v3.AddArg(v4)
-		v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+		v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
 		v5.AddArg(y)
 		v3.AddArg(v5)
 		v.AddArg(v3)
 		return true
 	}
 }
-func rewriteValuedec64_OpZeroExt16to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpZeroExt16to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (ZeroExt16to64 x)
 	// cond:
 	// result: (ZeroExt32to64 (ZeroExt16to32 x))
 	for {
 		x := v.Args[0]
 		v.reset(OpZeroExt32to64)
-		v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteValuedec64_OpZeroExt32to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpZeroExt32to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (ZeroExt32to64 x)
 	// cond:
-	// result: (Int64Make (Const32 <config.fe.TypeUInt32()> [0]) x)
+	// result: (Int64Make (Const32 <typ.UInt32> [0]) x)
 	for {
 		x := v.Args[0]
 		v.reset(OpInt64Make)
-		v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
 		v0.AuxInt = 0
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 }
-func rewriteValuedec64_OpZeroExt8to64(v *Value, config *Config) bool {
+func rewriteValuedec64_OpZeroExt8to64_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
 	// match: (ZeroExt8to64 x)
 	// cond:
 	// result: (ZeroExt32to64 (ZeroExt8to32 x))
 	for {
 		x := v.Args[0]
 		v.reset(OpZeroExt32to64)
-		v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+		v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
 		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
 }
-func rewriteBlockdec64(b *Block, config *Config) bool {
+func rewriteBlockdec64(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 1a2eacc..95b2c62 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -1,407 +1,439 @@
-// autogenerated from gen/generic.rules: do not edit!
+// Code generated from gen/generic.rules; DO NOT EDIT.
 // generated with: cd gen; go run *.go
 
 package ssa
 
 import "math"
+import "cmd/internal/obj"
+import "cmd/internal/objabi"
+import "cmd/compile/internal/types"
 
-var _ = math.MinInt8 // in case not otherwise used
-func rewriteValuegeneric(v *Value, config *Config) bool {
+var _ = math.MinInt8  // in case not otherwise used
+var _ = obj.ANOP      // in case not otherwise used
+var _ = objabi.GOROOT // in case not otherwise used
+var _ = types.TypeMem // in case not otherwise used
+
+func rewriteValuegeneric(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
-		return rewriteValuegeneric_OpAdd16(v, config)
+		return rewriteValuegeneric_OpAdd16_0(v) || rewriteValuegeneric_OpAdd16_10(v) || rewriteValuegeneric_OpAdd16_20(v)
 	case OpAdd32:
-		return rewriteValuegeneric_OpAdd32(v, config)
+		return rewriteValuegeneric_OpAdd32_0(v) || rewriteValuegeneric_OpAdd32_10(v) || rewriteValuegeneric_OpAdd32_20(v)
 	case OpAdd32F:
-		return rewriteValuegeneric_OpAdd32F(v, config)
+		return rewriteValuegeneric_OpAdd32F_0(v)
 	case OpAdd64:
-		return rewriteValuegeneric_OpAdd64(v, config)
+		return rewriteValuegeneric_OpAdd64_0(v) || rewriteValuegeneric_OpAdd64_10(v) || rewriteValuegeneric_OpAdd64_20(v)
 	case OpAdd64F:
-		return rewriteValuegeneric_OpAdd64F(v, config)
+		return rewriteValuegeneric_OpAdd64F_0(v)
 	case OpAdd8:
-		return rewriteValuegeneric_OpAdd8(v, config)
+		return rewriteValuegeneric_OpAdd8_0(v) || rewriteValuegeneric_OpAdd8_10(v) || rewriteValuegeneric_OpAdd8_20(v)
 	case OpAddPtr:
-		return rewriteValuegeneric_OpAddPtr(v, config)
+		return rewriteValuegeneric_OpAddPtr_0(v)
 	case OpAnd16:
-		return rewriteValuegeneric_OpAnd16(v, config)
+		return rewriteValuegeneric_OpAnd16_0(v) || rewriteValuegeneric_OpAnd16_10(v)
 	case OpAnd32:
-		return rewriteValuegeneric_OpAnd32(v, config)
+		return rewriteValuegeneric_OpAnd32_0(v) || rewriteValuegeneric_OpAnd32_10(v)
 	case OpAnd64:
-		return rewriteValuegeneric_OpAnd64(v, config)
+		return rewriteValuegeneric_OpAnd64_0(v) || rewriteValuegeneric_OpAnd64_10(v) || rewriteValuegeneric_OpAnd64_20(v)
 	case OpAnd8:
-		return rewriteValuegeneric_OpAnd8(v, config)
+		return rewriteValuegeneric_OpAnd8_0(v) || rewriteValuegeneric_OpAnd8_10(v)
 	case OpArg:
-		return rewriteValuegeneric_OpArg(v, config)
+		return rewriteValuegeneric_OpArg_0(v) || rewriteValuegeneric_OpArg_10(v)
 	case OpArraySelect:
-		return rewriteValuegeneric_OpArraySelect(v, config)
+		return rewriteValuegeneric_OpArraySelect_0(v)
 	case OpCom16:
-		return rewriteValuegeneric_OpCom16(v, config)
+		return rewriteValuegeneric_OpCom16_0(v)
 	case OpCom32:
-		return rewriteValuegeneric_OpCom32(v, config)
+		return rewriteValuegeneric_OpCom32_0(v)
 	case OpCom64:
-		return rewriteValuegeneric_OpCom64(v, config)
+		return rewriteValuegeneric_OpCom64_0(v)
 	case OpCom8:
-		return rewriteValuegeneric_OpCom8(v, config)
+		return rewriteValuegeneric_OpCom8_0(v)
 	case OpConstInterface:
-		return rewriteValuegeneric_OpConstInterface(v, config)
+		return rewriteValuegeneric_OpConstInterface_0(v)
 	case OpConstSlice:
-		return rewriteValuegeneric_OpConstSlice(v, config)
+		return rewriteValuegeneric_OpConstSlice_0(v)
 	case OpConstString:
-		return rewriteValuegeneric_OpConstString(v, config)
+		return rewriteValuegeneric_OpConstString_0(v)
 	case OpConvert:
-		return rewriteValuegeneric_OpConvert(v, config)
+		return rewriteValuegeneric_OpConvert_0(v)
 	case OpCvt32Fto64F:
-		return rewriteValuegeneric_OpCvt32Fto64F(v, config)
+		return rewriteValuegeneric_OpCvt32Fto64F_0(v)
 	case OpCvt64Fto32F:
-		return rewriteValuegeneric_OpCvt64Fto32F(v, config)
+		return rewriteValuegeneric_OpCvt64Fto32F_0(v)
+	case OpDiv16:
+		return rewriteValuegeneric_OpDiv16_0(v)
+	case OpDiv16u:
+		return rewriteValuegeneric_OpDiv16u_0(v)
+	case OpDiv32:
+		return rewriteValuegeneric_OpDiv32_0(v)
 	case OpDiv32F:
-		return rewriteValuegeneric_OpDiv32F(v, config)
+		return rewriteValuegeneric_OpDiv32F_0(v)
+	case OpDiv32u:
+		return rewriteValuegeneric_OpDiv32u_0(v)
 	case OpDiv64:
-		return rewriteValuegeneric_OpDiv64(v, config)
+		return rewriteValuegeneric_OpDiv64_0(v)
 	case OpDiv64F:
-		return rewriteValuegeneric_OpDiv64F(v, config)
+		return rewriteValuegeneric_OpDiv64F_0(v)
 	case OpDiv64u:
-		return rewriteValuegeneric_OpDiv64u(v, config)
+		return rewriteValuegeneric_OpDiv64u_0(v)
+	case OpDiv8:
+		return rewriteValuegeneric_OpDiv8_0(v)
+	case OpDiv8u:
+		return rewriteValuegeneric_OpDiv8u_0(v)
 	case OpEq16:
-		return rewriteValuegeneric_OpEq16(v, config)
+		return rewriteValuegeneric_OpEq16_0(v)
 	case OpEq32:
-		return rewriteValuegeneric_OpEq32(v, config)
+		return rewriteValuegeneric_OpEq32_0(v)
 	case OpEq64:
-		return rewriteValuegeneric_OpEq64(v, config)
+		return rewriteValuegeneric_OpEq64_0(v)
 	case OpEq8:
-		return rewriteValuegeneric_OpEq8(v, config)
+		return rewriteValuegeneric_OpEq8_0(v)
 	case OpEqB:
-		return rewriteValuegeneric_OpEqB(v, config)
+		return rewriteValuegeneric_OpEqB_0(v)
 	case OpEqInter:
-		return rewriteValuegeneric_OpEqInter(v, config)
+		return rewriteValuegeneric_OpEqInter_0(v)
 	case OpEqPtr:
-		return rewriteValuegeneric_OpEqPtr(v, config)
+		return rewriteValuegeneric_OpEqPtr_0(v)
 	case OpEqSlice:
-		return rewriteValuegeneric_OpEqSlice(v, config)
+		return rewriteValuegeneric_OpEqSlice_0(v)
 	case OpGeq16:
-		return rewriteValuegeneric_OpGeq16(v, config)
+		return rewriteValuegeneric_OpGeq16_0(v)
 	case OpGeq16U:
-		return rewriteValuegeneric_OpGeq16U(v, config)
+		return rewriteValuegeneric_OpGeq16U_0(v)
 	case OpGeq32:
-		return rewriteValuegeneric_OpGeq32(v, config)
+		return rewriteValuegeneric_OpGeq32_0(v)
 	case OpGeq32U:
-		return rewriteValuegeneric_OpGeq32U(v, config)
+		return rewriteValuegeneric_OpGeq32U_0(v)
 	case OpGeq64:
-		return rewriteValuegeneric_OpGeq64(v, config)
+		return rewriteValuegeneric_OpGeq64_0(v)
 	case OpGeq64U:
-		return rewriteValuegeneric_OpGeq64U(v, config)
+		return rewriteValuegeneric_OpGeq64U_0(v)
 	case OpGeq8:
-		return rewriteValuegeneric_OpGeq8(v, config)
+		return rewriteValuegeneric_OpGeq8_0(v)
 	case OpGeq8U:
-		return rewriteValuegeneric_OpGeq8U(v, config)
+		return rewriteValuegeneric_OpGeq8U_0(v)
 	case OpGreater16:
-		return rewriteValuegeneric_OpGreater16(v, config)
+		return rewriteValuegeneric_OpGreater16_0(v)
 	case OpGreater16U:
-		return rewriteValuegeneric_OpGreater16U(v, config)
+		return rewriteValuegeneric_OpGreater16U_0(v)
 	case OpGreater32:
-		return rewriteValuegeneric_OpGreater32(v, config)
+		return rewriteValuegeneric_OpGreater32_0(v)
 	case OpGreater32U:
-		return rewriteValuegeneric_OpGreater32U(v, config)
+		return rewriteValuegeneric_OpGreater32U_0(v)
 	case OpGreater64:
-		return rewriteValuegeneric_OpGreater64(v, config)
+		return rewriteValuegeneric_OpGreater64_0(v)
 	case OpGreater64U:
-		return rewriteValuegeneric_OpGreater64U(v, config)
+		return rewriteValuegeneric_OpGreater64U_0(v)
 	case OpGreater8:
-		return rewriteValuegeneric_OpGreater8(v, config)
+		return rewriteValuegeneric_OpGreater8_0(v)
 	case OpGreater8U:
-		return rewriteValuegeneric_OpGreater8U(v, config)
+		return rewriteValuegeneric_OpGreater8U_0(v)
 	case OpIMake:
-		return rewriteValuegeneric_OpIMake(v, config)
+		return rewriteValuegeneric_OpIMake_0(v)
+	case OpInterCall:
+		return rewriteValuegeneric_OpInterCall_0(v)
 	case OpIsInBounds:
-		return rewriteValuegeneric_OpIsInBounds(v, config)
+		return rewriteValuegeneric_OpIsInBounds_0(v) || rewriteValuegeneric_OpIsInBounds_10(v) || rewriteValuegeneric_OpIsInBounds_20(v)
+	case OpIsNonNil:
+		return rewriteValuegeneric_OpIsNonNil_0(v)
 	case OpIsSliceInBounds:
-		return rewriteValuegeneric_OpIsSliceInBounds(v, config)
+		return rewriteValuegeneric_OpIsSliceInBounds_0(v)
 	case OpLeq16:
-		return rewriteValuegeneric_OpLeq16(v, config)
+		return rewriteValuegeneric_OpLeq16_0(v)
 	case OpLeq16U:
-		return rewriteValuegeneric_OpLeq16U(v, config)
+		return rewriteValuegeneric_OpLeq16U_0(v)
 	case OpLeq32:
-		return rewriteValuegeneric_OpLeq32(v, config)
+		return rewriteValuegeneric_OpLeq32_0(v)
 	case OpLeq32U:
-		return rewriteValuegeneric_OpLeq32U(v, config)
+		return rewriteValuegeneric_OpLeq32U_0(v)
 	case OpLeq64:
-		return rewriteValuegeneric_OpLeq64(v, config)
+		return rewriteValuegeneric_OpLeq64_0(v)
 	case OpLeq64U:
-		return rewriteValuegeneric_OpLeq64U(v, config)
+		return rewriteValuegeneric_OpLeq64U_0(v)
 	case OpLeq8:
-		return rewriteValuegeneric_OpLeq8(v, config)
+		return rewriteValuegeneric_OpLeq8_0(v)
 	case OpLeq8U:
-		return rewriteValuegeneric_OpLeq8U(v, config)
+		return rewriteValuegeneric_OpLeq8U_0(v)
 	case OpLess16:
-		return rewriteValuegeneric_OpLess16(v, config)
+		return rewriteValuegeneric_OpLess16_0(v)
 	case OpLess16U:
-		return rewriteValuegeneric_OpLess16U(v, config)
+		return rewriteValuegeneric_OpLess16U_0(v)
 	case OpLess32:
-		return rewriteValuegeneric_OpLess32(v, config)
+		return rewriteValuegeneric_OpLess32_0(v)
 	case OpLess32U:
-		return rewriteValuegeneric_OpLess32U(v, config)
+		return rewriteValuegeneric_OpLess32U_0(v)
 	case OpLess64:
-		return rewriteValuegeneric_OpLess64(v, config)
+		return rewriteValuegeneric_OpLess64_0(v)
 	case OpLess64U:
-		return rewriteValuegeneric_OpLess64U(v, config)
+		return rewriteValuegeneric_OpLess64U_0(v)
 	case OpLess8:
-		return rewriteValuegeneric_OpLess8(v, config)
+		return rewriteValuegeneric_OpLess8_0(v)
 	case OpLess8U:
-		return rewriteValuegeneric_OpLess8U(v, config)
+		return rewriteValuegeneric_OpLess8U_0(v)
 	case OpLoad:
-		return rewriteValuegeneric_OpLoad(v, config)
+		return rewriteValuegeneric_OpLoad_0(v)
 	case OpLsh16x16:
-		return rewriteValuegeneric_OpLsh16x16(v, config)
+		return rewriteValuegeneric_OpLsh16x16_0(v)
 	case OpLsh16x32:
-		return rewriteValuegeneric_OpLsh16x32(v, config)
+		return rewriteValuegeneric_OpLsh16x32_0(v)
 	case OpLsh16x64:
-		return rewriteValuegeneric_OpLsh16x64(v, config)
+		return rewriteValuegeneric_OpLsh16x64_0(v)
 	case OpLsh16x8:
-		return rewriteValuegeneric_OpLsh16x8(v, config)
+		return rewriteValuegeneric_OpLsh16x8_0(v)
 	case OpLsh32x16:
-		return rewriteValuegeneric_OpLsh32x16(v, config)
+		return rewriteValuegeneric_OpLsh32x16_0(v)
 	case OpLsh32x32:
-		return rewriteValuegeneric_OpLsh32x32(v, config)
+		return rewriteValuegeneric_OpLsh32x32_0(v)
 	case OpLsh32x64:
-		return rewriteValuegeneric_OpLsh32x64(v, config)
+		return rewriteValuegeneric_OpLsh32x64_0(v)
 	case OpLsh32x8:
-		return rewriteValuegeneric_OpLsh32x8(v, config)
+		return rewriteValuegeneric_OpLsh32x8_0(v)
 	case OpLsh64x16:
-		return rewriteValuegeneric_OpLsh64x16(v, config)
+		return rewriteValuegeneric_OpLsh64x16_0(v)
 	case OpLsh64x32:
-		return rewriteValuegeneric_OpLsh64x32(v, config)
+		return rewriteValuegeneric_OpLsh64x32_0(v)
 	case OpLsh64x64:
-		return rewriteValuegeneric_OpLsh64x64(v, config)
+		return rewriteValuegeneric_OpLsh64x64_0(v)
 	case OpLsh64x8:
-		return rewriteValuegeneric_OpLsh64x8(v, config)
+		return rewriteValuegeneric_OpLsh64x8_0(v)
 	case OpLsh8x16:
-		return rewriteValuegeneric_OpLsh8x16(v, config)
+		return rewriteValuegeneric_OpLsh8x16_0(v)
 	case OpLsh8x32:
-		return rewriteValuegeneric_OpLsh8x32(v, config)
+		return rewriteValuegeneric_OpLsh8x32_0(v)
 	case OpLsh8x64:
-		return rewriteValuegeneric_OpLsh8x64(v, config)
+		return rewriteValuegeneric_OpLsh8x64_0(v)
 	case OpLsh8x8:
-		return rewriteValuegeneric_OpLsh8x8(v, config)
+		return rewriteValuegeneric_OpLsh8x8_0(v)
 	case OpMod16:
-		return rewriteValuegeneric_OpMod16(v, config)
+		return rewriteValuegeneric_OpMod16_0(v)
 	case OpMod16u:
-		return rewriteValuegeneric_OpMod16u(v, config)
+		return rewriteValuegeneric_OpMod16u_0(v)
 	case OpMod32:
-		return rewriteValuegeneric_OpMod32(v, config)
+		return rewriteValuegeneric_OpMod32_0(v)
 	case OpMod32u:
-		return rewriteValuegeneric_OpMod32u(v, config)
+		return rewriteValuegeneric_OpMod32u_0(v)
 	case OpMod64:
-		return rewriteValuegeneric_OpMod64(v, config)
+		return rewriteValuegeneric_OpMod64_0(v)
 	case OpMod64u:
-		return rewriteValuegeneric_OpMod64u(v, config)
+		return rewriteValuegeneric_OpMod64u_0(v)
 	case OpMod8:
-		return rewriteValuegeneric_OpMod8(v, config)
+		return rewriteValuegeneric_OpMod8_0(v)
 	case OpMod8u:
-		return rewriteValuegeneric_OpMod8u(v, config)
+		return rewriteValuegeneric_OpMod8u_0(v)
 	case OpMul16:
-		return rewriteValuegeneric_OpMul16(v, config)
+		return rewriteValuegeneric_OpMul16_0(v) || rewriteValuegeneric_OpMul16_10(v)
 	case OpMul32:
-		return rewriteValuegeneric_OpMul32(v, config)
+		return rewriteValuegeneric_OpMul32_0(v) || rewriteValuegeneric_OpMul32_10(v)
 	case OpMul32F:
-		return rewriteValuegeneric_OpMul32F(v, config)
+		return rewriteValuegeneric_OpMul32F_0(v)
 	case OpMul64:
-		return rewriteValuegeneric_OpMul64(v, config)
+		return rewriteValuegeneric_OpMul64_0(v) || rewriteValuegeneric_OpMul64_10(v)
 	case OpMul64F:
-		return rewriteValuegeneric_OpMul64F(v, config)
+		return rewriteValuegeneric_OpMul64F_0(v)
 	case OpMul8:
-		return rewriteValuegeneric_OpMul8(v, config)
+		return rewriteValuegeneric_OpMul8_0(v) || rewriteValuegeneric_OpMul8_10(v)
 	case OpNeg16:
-		return rewriteValuegeneric_OpNeg16(v, config)
+		return rewriteValuegeneric_OpNeg16_0(v)
 	case OpNeg32:
-		return rewriteValuegeneric_OpNeg32(v, config)
+		return rewriteValuegeneric_OpNeg32_0(v)
+	case OpNeg32F:
+		return rewriteValuegeneric_OpNeg32F_0(v)
 	case OpNeg64:
-		return rewriteValuegeneric_OpNeg64(v, config)
+		return rewriteValuegeneric_OpNeg64_0(v)
+	case OpNeg64F:
+		return rewriteValuegeneric_OpNeg64F_0(v)
 	case OpNeg8:
-		return rewriteValuegeneric_OpNeg8(v, config)
+		return rewriteValuegeneric_OpNeg8_0(v)
 	case OpNeq16:
-		return rewriteValuegeneric_OpNeq16(v, config)
+		return rewriteValuegeneric_OpNeq16_0(v)
 	case OpNeq32:
-		return rewriteValuegeneric_OpNeq32(v, config)
+		return rewriteValuegeneric_OpNeq32_0(v)
 	case OpNeq64:
-		return rewriteValuegeneric_OpNeq64(v, config)
+		return rewriteValuegeneric_OpNeq64_0(v)
 	case OpNeq8:
-		return rewriteValuegeneric_OpNeq8(v, config)
+		return rewriteValuegeneric_OpNeq8_0(v)
 	case OpNeqB:
-		return rewriteValuegeneric_OpNeqB(v, config)
+		return rewriteValuegeneric_OpNeqB_0(v)
 	case OpNeqInter:
-		return rewriteValuegeneric_OpNeqInter(v, config)
+		return rewriteValuegeneric_OpNeqInter_0(v)
 	case OpNeqPtr:
-		return rewriteValuegeneric_OpNeqPtr(v, config)
+		return rewriteValuegeneric_OpNeqPtr_0(v)
 	case OpNeqSlice:
-		return rewriteValuegeneric_OpNeqSlice(v, config)
+		return rewriteValuegeneric_OpNeqSlice_0(v)
 	case OpNilCheck:
-		return rewriteValuegeneric_OpNilCheck(v, config)
+		return rewriteValuegeneric_OpNilCheck_0(v)
 	case OpNot:
-		return rewriteValuegeneric_OpNot(v, config)
+		return rewriteValuegeneric_OpNot_0(v) || rewriteValuegeneric_OpNot_10(v) || rewriteValuegeneric_OpNot_20(v) || rewriteValuegeneric_OpNot_30(v) || rewriteValuegeneric_OpNot_40(v)
 	case OpOffPtr:
-		return rewriteValuegeneric_OpOffPtr(v, config)
+		return rewriteValuegeneric_OpOffPtr_0(v)
 	case OpOr16:
-		return rewriteValuegeneric_OpOr16(v, config)
+		return rewriteValuegeneric_OpOr16_0(v) || rewriteValuegeneric_OpOr16_10(v) || rewriteValuegeneric_OpOr16_20(v)
 	case OpOr32:
-		return rewriteValuegeneric_OpOr32(v, config)
+		return rewriteValuegeneric_OpOr32_0(v) || rewriteValuegeneric_OpOr32_10(v) || rewriteValuegeneric_OpOr32_20(v)
 	case OpOr64:
-		return rewriteValuegeneric_OpOr64(v, config)
+		return rewriteValuegeneric_OpOr64_0(v) || rewriteValuegeneric_OpOr64_10(v) || rewriteValuegeneric_OpOr64_20(v)
 	case OpOr8:
-		return rewriteValuegeneric_OpOr8(v, config)
+		return rewriteValuegeneric_OpOr8_0(v) || rewriteValuegeneric_OpOr8_10(v) || rewriteValuegeneric_OpOr8_20(v)
 	case OpPhi:
-		return rewriteValuegeneric_OpPhi(v, config)
+		return rewriteValuegeneric_OpPhi_0(v)
 	case OpPtrIndex:
-		return rewriteValuegeneric_OpPtrIndex(v, config)
+		return rewriteValuegeneric_OpPtrIndex_0(v)
+	case OpRound32F:
+		return rewriteValuegeneric_OpRound32F_0(v)
+	case OpRound64F:
+		return rewriteValuegeneric_OpRound64F_0(v)
 	case OpRsh16Ux16:
-		return rewriteValuegeneric_OpRsh16Ux16(v, config)
+		return rewriteValuegeneric_OpRsh16Ux16_0(v)
 	case OpRsh16Ux32:
-		return rewriteValuegeneric_OpRsh16Ux32(v, config)
+		return rewriteValuegeneric_OpRsh16Ux32_0(v)
 	case OpRsh16Ux64:
-		return rewriteValuegeneric_OpRsh16Ux64(v, config)
+		return rewriteValuegeneric_OpRsh16Ux64_0(v)
 	case OpRsh16Ux8:
-		return rewriteValuegeneric_OpRsh16Ux8(v, config)
+		return rewriteValuegeneric_OpRsh16Ux8_0(v)
 	case OpRsh16x16:
-		return rewriteValuegeneric_OpRsh16x16(v, config)
+		return rewriteValuegeneric_OpRsh16x16_0(v)
 	case OpRsh16x32:
-		return rewriteValuegeneric_OpRsh16x32(v, config)
+		return rewriteValuegeneric_OpRsh16x32_0(v)
 	case OpRsh16x64:
-		return rewriteValuegeneric_OpRsh16x64(v, config)
+		return rewriteValuegeneric_OpRsh16x64_0(v)
 	case OpRsh16x8:
-		return rewriteValuegeneric_OpRsh16x8(v, config)
+		return rewriteValuegeneric_OpRsh16x8_0(v)
 	case OpRsh32Ux16:
-		return rewriteValuegeneric_OpRsh32Ux16(v, config)
+		return rewriteValuegeneric_OpRsh32Ux16_0(v)
 	case OpRsh32Ux32:
-		return rewriteValuegeneric_OpRsh32Ux32(v, config)
+		return rewriteValuegeneric_OpRsh32Ux32_0(v)
 	case OpRsh32Ux64:
-		return rewriteValuegeneric_OpRsh32Ux64(v, config)
+		return rewriteValuegeneric_OpRsh32Ux64_0(v)
 	case OpRsh32Ux8:
-		return rewriteValuegeneric_OpRsh32Ux8(v, config)
+		return rewriteValuegeneric_OpRsh32Ux8_0(v)
 	case OpRsh32x16:
-		return rewriteValuegeneric_OpRsh32x16(v, config)
+		return rewriteValuegeneric_OpRsh32x16_0(v)
 	case OpRsh32x32:
-		return rewriteValuegeneric_OpRsh32x32(v, config)
+		return rewriteValuegeneric_OpRsh32x32_0(v)
 	case OpRsh32x64:
-		return rewriteValuegeneric_OpRsh32x64(v, config)
+		return rewriteValuegeneric_OpRsh32x64_0(v)
 	case OpRsh32x8:
-		return rewriteValuegeneric_OpRsh32x8(v, config)
+		return rewriteValuegeneric_OpRsh32x8_0(v)
 	case OpRsh64Ux16:
-		return rewriteValuegeneric_OpRsh64Ux16(v, config)
+		return rewriteValuegeneric_OpRsh64Ux16_0(v)
 	case OpRsh64Ux32:
-		return rewriteValuegeneric_OpRsh64Ux32(v, config)
+		return rewriteValuegeneric_OpRsh64Ux32_0(v)
 	case OpRsh64Ux64:
-		return rewriteValuegeneric_OpRsh64Ux64(v, config)
+		return rewriteValuegeneric_OpRsh64Ux64_0(v)
 	case OpRsh64Ux8:
-		return rewriteValuegeneric_OpRsh64Ux8(v, config)
+		return rewriteValuegeneric_OpRsh64Ux8_0(v)
 	case OpRsh64x16:
-		return rewriteValuegeneric_OpRsh64x16(v, config)
+		return rewriteValuegeneric_OpRsh64x16_0(v)
 	case OpRsh64x32:
-		return rewriteValuegeneric_OpRsh64x32(v, config)
+		return rewriteValuegeneric_OpRsh64x32_0(v)
 	case OpRsh64x64:
-		return rewriteValuegeneric_OpRsh64x64(v, config)
+		return rewriteValuegeneric_OpRsh64x64_0(v)
 	case OpRsh64x8:
-		return rewriteValuegeneric_OpRsh64x8(v, config)
+		return rewriteValuegeneric_OpRsh64x8_0(v)
 	case OpRsh8Ux16:
-		return rewriteValuegeneric_OpRsh8Ux16(v, config)
+		return rewriteValuegeneric_OpRsh8Ux16_0(v)
 	case OpRsh8Ux32:
-		return rewriteValuegeneric_OpRsh8Ux32(v, config)
+		return rewriteValuegeneric_OpRsh8Ux32_0(v)
 	case OpRsh8Ux64:
-		return rewriteValuegeneric_OpRsh8Ux64(v, config)
+		return rewriteValuegeneric_OpRsh8Ux64_0(v)
 	case OpRsh8Ux8:
-		return rewriteValuegeneric_OpRsh8Ux8(v, config)
+		return rewriteValuegeneric_OpRsh8Ux8_0(v)
 	case OpRsh8x16:
-		return rewriteValuegeneric_OpRsh8x16(v, config)
+		return rewriteValuegeneric_OpRsh8x16_0(v)
 	case OpRsh8x32:
-		return rewriteValuegeneric_OpRsh8x32(v, config)
+		return rewriteValuegeneric_OpRsh8x32_0(v)
 	case OpRsh8x64:
-		return rewriteValuegeneric_OpRsh8x64(v, config)
+		return rewriteValuegeneric_OpRsh8x64_0(v)
 	case OpRsh8x8:
-		return rewriteValuegeneric_OpRsh8x8(v, config)
+		return rewriteValuegeneric_OpRsh8x8_0(v)
 	case OpSignExt16to32:
-		return rewriteValuegeneric_OpSignExt16to32(v, config)
+		return rewriteValuegeneric_OpSignExt16to32_0(v)
 	case OpSignExt16to64:
-		return rewriteValuegeneric_OpSignExt16to64(v, config)
+		return rewriteValuegeneric_OpSignExt16to64_0(v)
 	case OpSignExt32to64:
-		return rewriteValuegeneric_OpSignExt32to64(v, config)
+		return rewriteValuegeneric_OpSignExt32to64_0(v)
 	case OpSignExt8to16:
-		return rewriteValuegeneric_OpSignExt8to16(v, config)
+		return rewriteValuegeneric_OpSignExt8to16_0(v)
 	case OpSignExt8to32:
-		return rewriteValuegeneric_OpSignExt8to32(v, config)
+		return rewriteValuegeneric_OpSignExt8to32_0(v)
 	case OpSignExt8to64:
-		return rewriteValuegeneric_OpSignExt8to64(v, config)
+		return rewriteValuegeneric_OpSignExt8to64_0(v)
 	case OpSliceCap:
-		return rewriteValuegeneric_OpSliceCap(v, config)
+		return rewriteValuegeneric_OpSliceCap_0(v)
 	case OpSliceLen:
-		return rewriteValuegeneric_OpSliceLen(v, config)
+		return rewriteValuegeneric_OpSliceLen_0(v)
 	case OpSlicePtr:
-		return rewriteValuegeneric_OpSlicePtr(v, config)
+		return rewriteValuegeneric_OpSlicePtr_0(v)
 	case OpSlicemask:
-		return rewriteValuegeneric_OpSlicemask(v, config)
+		return rewriteValuegeneric_OpSlicemask_0(v)
 	case OpSqrt:
-		return rewriteValuegeneric_OpSqrt(v, config)
+		return rewriteValuegeneric_OpSqrt_0(v)
 	case OpStore:
-		return rewriteValuegeneric_OpStore(v, config)
+		return rewriteValuegeneric_OpStore_0(v) || rewriteValuegeneric_OpStore_10(v)
 	case OpStringLen:
-		return rewriteValuegeneric_OpStringLen(v, config)
+		return rewriteValuegeneric_OpStringLen_0(v)
 	case OpStringPtr:
-		return rewriteValuegeneric_OpStringPtr(v, config)
+		return rewriteValuegeneric_OpStringPtr_0(v)
 	case OpStructSelect:
-		return rewriteValuegeneric_OpStructSelect(v, config)
+		return rewriteValuegeneric_OpStructSelect_0(v) || rewriteValuegeneric_OpStructSelect_10(v)
 	case OpSub16:
-		return rewriteValuegeneric_OpSub16(v, config)
+		return rewriteValuegeneric_OpSub16_0(v) || rewriteValuegeneric_OpSub16_10(v)
 	case OpSub32:
-		return rewriteValuegeneric_OpSub32(v, config)
+		return rewriteValuegeneric_OpSub32_0(v) || rewriteValuegeneric_OpSub32_10(v)
 	case OpSub32F:
-		return rewriteValuegeneric_OpSub32F(v, config)
+		return rewriteValuegeneric_OpSub32F_0(v)
 	case OpSub64:
-		return rewriteValuegeneric_OpSub64(v, config)
+		return rewriteValuegeneric_OpSub64_0(v) || rewriteValuegeneric_OpSub64_10(v)
 	case OpSub64F:
-		return rewriteValuegeneric_OpSub64F(v, config)
+		return rewriteValuegeneric_OpSub64F_0(v)
 	case OpSub8:
-		return rewriteValuegeneric_OpSub8(v, config)
+		return rewriteValuegeneric_OpSub8_0(v) || rewriteValuegeneric_OpSub8_10(v)
 	case OpTrunc16to8:
-		return rewriteValuegeneric_OpTrunc16to8(v, config)
+		return rewriteValuegeneric_OpTrunc16to8_0(v)
 	case OpTrunc32to16:
-		return rewriteValuegeneric_OpTrunc32to16(v, config)
+		return rewriteValuegeneric_OpTrunc32to16_0(v)
 	case OpTrunc32to8:
-		return rewriteValuegeneric_OpTrunc32to8(v, config)
+		return rewriteValuegeneric_OpTrunc32to8_0(v)
 	case OpTrunc64to16:
-		return rewriteValuegeneric_OpTrunc64to16(v, config)
+		return rewriteValuegeneric_OpTrunc64to16_0(v)
 	case OpTrunc64to32:
-		return rewriteValuegeneric_OpTrunc64to32(v, config)
+		return rewriteValuegeneric_OpTrunc64to32_0(v)
 	case OpTrunc64to8:
-		return rewriteValuegeneric_OpTrunc64to8(v, config)
+		return rewriteValuegeneric_OpTrunc64to8_0(v)
 	case OpXor16:
-		return rewriteValuegeneric_OpXor16(v, config)
+		return rewriteValuegeneric_OpXor16_0(v) || rewriteValuegeneric_OpXor16_10(v)
 	case OpXor32:
-		return rewriteValuegeneric_OpXor32(v, config)
+		return rewriteValuegeneric_OpXor32_0(v) || rewriteValuegeneric_OpXor32_10(v)
 	case OpXor64:
-		return rewriteValuegeneric_OpXor64(v, config)
+		return rewriteValuegeneric_OpXor64_0(v) || rewriteValuegeneric_OpXor64_10(v)
 	case OpXor8:
-		return rewriteValuegeneric_OpXor8(v, config)
+		return rewriteValuegeneric_OpXor8_0(v) || rewriteValuegeneric_OpXor8_10(v)
 	case OpZero:
-		return rewriteValuegeneric_OpZero(v, config)
+		return rewriteValuegeneric_OpZero_0(v)
 	case OpZeroExt16to32:
-		return rewriteValuegeneric_OpZeroExt16to32(v, config)
+		return rewriteValuegeneric_OpZeroExt16to32_0(v)
 	case OpZeroExt16to64:
-		return rewriteValuegeneric_OpZeroExt16to64(v, config)
+		return rewriteValuegeneric_OpZeroExt16to64_0(v)
 	case OpZeroExt32to64:
-		return rewriteValuegeneric_OpZeroExt32to64(v, config)
+		return rewriteValuegeneric_OpZeroExt32to64_0(v)
 	case OpZeroExt8to16:
-		return rewriteValuegeneric_OpZeroExt8to16(v, config)
+		return rewriteValuegeneric_OpZeroExt8to16_0(v)
 	case OpZeroExt8to32:
-		return rewriteValuegeneric_OpZeroExt8to32(v, config)
+		return rewriteValuegeneric_OpZeroExt8to32_0(v)
 	case OpZeroExt8to64:
-		return rewriteValuegeneric_OpZeroExt8to64(v, config)
+		return rewriteValuegeneric_OpZeroExt8to64_0(v)
 	}
 	return false
 }
-func rewriteValuegeneric_OpAdd16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Add16  (Const16 [c])  (Const16 [d]))
+	// match: (Add16 (Const16 [c]) (Const16 [d]))
 	// cond:
 	// result: (Const16 [int64(int16(c+d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst16 {
 			break
@@ -416,31 +448,30 @@ func rewriteValuegeneric_OpAdd16(v *Value, config *Config) bool {
 		v.AuxInt = int64(int16(c + d))
 		return true
 	}
-	// match: (Add16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Add16 (Const16 <t> [c]) x)
+	// match: (Add16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [int64(int16(c+d))])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		d := v_0.AuxInt
 		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)
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c + d))
 		return true
 	}
 	// match: (Add16 (Const16 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst16 {
 			break
@@ -454,516 +485,721 @@ func rewriteValuegeneric_OpAdd16(v *Value, config *Config) bool {
 		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]))
+	// match: (Add16 x (Const16 [0]))
 	// 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)
+	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpAdd32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Add32 (Const32 [0]) x)
+	// match: (Add16 (Const16 [1]) (Com16 x))
 	// cond:
-	// result: x
+	// result: (Neg16 x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_0.AuxInt != 1 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v_1 := v.Args[1]
+		if v_1.Op != OpCom16 {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpNeg16)
 		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]))
+	// match: (Add16 (Com16 x) (Const16 [1]))
 	// cond:
-	// result: (Const32F [f2i(float64(i2f32(c) + i2f32(d)))])
+	// result: (Neg16 x)
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpCom16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32F)
-		v.AuxInt = f2i(float64(i2f32(c) + i2f32(d)))
-		return true
-	}
-	// match: (Add32F x (Const32F [0]))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[0]
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpNeg16)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Add32F (Const32F [0]) x)
-	// cond:
-	// result: x
+	// match: (Add16 (Add16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Add16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
+		t := i.Type
+		z := v_0.Args[1]
 		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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])
+	// match: (Add16 (Add16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Add16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = c + d
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Add64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Add64 (Const64 <t> [c]) x)
+	// match: (Add16 x (Add16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Add16 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpAdd16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpAdd64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Add64 (Const64 [0]) x)
-	// cond:
-	// result: x
+	// match: (Add16 x (Add16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Add16 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpAdd64F(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd16_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Add64F (Const64F [c]) (Const64F [d]))
-	// cond:
-	// result: (Const64F [f2i(i2f(c) + i2f(d))])
+	// match: (Add16 (Sub16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Sub16 <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpSub16 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Add16 x (Sub16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Sub16 <t> x z))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_1.Op != OpSub16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64F)
-		v.AuxInt = f2i(i2f(c) + i2f(d))
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Add64F x (Const64F [0]))
-	// cond:
-	// result: x
+	// match: (Add16 x (Sub16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Sub16 <t> x z))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_1.Op != OpSub16 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Add64F (Const64F [0]) x)
-	// cond:
-	// result: x
+	// match: (Add16 (Sub16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Sub16 <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpSub16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
+		t := i.Type
+		z := v_0.Args[1]
 		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		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))])
+	// match: (Add16 (Sub16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Sub16 (Add16 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpSub16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c + d))
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	// match: (Add8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Add8  (Const8  <t> [c]) x)
+	// match: (Add16 x (Sub16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Sub16 (Add16 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpSub16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpAdd8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		v.AddArg(v0)
-		v.AddArg(x)
+		v.AddArg(i)
 		return true
 	}
-	// match: (Add8  (Const8  [0]) x)
-	// cond:
-	// result: x
+	// match: (Add16 x (Sub16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Sub16 (Add16 <t> x z) i)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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])
+	// match: (Add16 (Sub16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Sub16 (Add16 <t> x z) i)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub16 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpOffPtr)
-		v.Type = t
-		v.AuxInt = c
-		v.AddArg(x)
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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)
+	// match: (Add16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
+	// cond:
+	// result: (Add16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst16 {
+		if v_1.Op != OpAdd16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
 			break
 		}
-		v.reset(OpAnd16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = c
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (And16 x x)
+	// match: (Add16 (Const16 <t> [c]) (Add16 x (Const16 <t> [d])))
 	// cond:
-	// result: x
+	// result: (Add16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd16 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (And16 (Const16 [-1]) x)
+	return false
+}
+func rewriteValuegeneric_OpAdd16_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Add16 (Add16 (Const16 <t> [d]) x) (Const16 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Add16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (And16 (Const16 [0]) _)
+	// match: (Add16 (Add16 x (Const16 <t> [d])) (Const16 <t> [c]))
 	// cond:
-	// result: (Const16 [0])
+	// result: (Add16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (And16 x (And16 x y))
+	// match: (Add16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x))
 	// cond:
-	// result: (And16 x y)
+	// result: (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpAnd16 {
+		if v_1.Op != OpSub16 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpAnd16)
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And16 x (And16 y x))
+	// match: (Add16 (Sub16 (Const16 <t> [d]) x) (Const16 <t> [c]))
 	// cond:
-	// result: (And16 x y)
+	// result: (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAnd16 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpAnd16)
+		c := v_1.AuxInt
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And16 (And16 x y) x)
+	// match: (Add16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d])))
 	// cond:
-	// result: (And16 x y)
+	// result: (Add16 (Const16 <t> [int64(int16(c-d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd16 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub16 {
 			break
 		}
-		v.reset(OpAnd16)
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And16 (And16 x y) y)
+	// match: (Add16 (Sub16 x (Const16 <t> [d])) (Const16 <t> [c]))
 	// cond:
-	// result: (And16 x y)
+	// result: (Add16 (Const16 <t> [int64(int16(c-d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd16 {
+		if v_0.Op != OpSub16 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
 			break
 		}
-		v.reset(OpAnd16)
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpAnd32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (And32 x (Const32 <t> [c]))
-	// cond: x.Op != OpConst32
-	// result: (And32 (Const32 <t> [c]) x)
+	// match: (Add32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c+d))])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c + d))
 		return true
 	}
-	// match: (And32 x x)
+	// match: (Add32 (Const32 [d]) (Const32 [c]))
 	// cond:
-	// result: x
+	// result: (Const32 [int64(int32(c+d))])
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c + d))
 		return true
 	}
-	// match: (And32 (Const32 [-1]) x)
+	// match: (Add32 (Const32 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		if v_0.AuxInt != 0 {
 			break
 		}
 		x := v.Args[1]
@@ -972,717 +1208,720 @@ func rewriteValuegeneric_OpAnd32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (And32 (Const32 [0]) _)
+	// match: (Add32 x (Const32 [0]))
 	// cond:
-	// result: (Const32 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (And32 x (And32 x y))
+	// match: (Add32 (Const32 [1]) (Com32 x))
 	// cond:
-	// result: (And32 x y)
+	// result: (Neg32 x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpAnd32 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			break
 		}
-		if x != v_1.Args[0] {
+		if v_0.AuxInt != 1 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpAnd32)
+		v_1 := v.Args[1]
+		if v_1.Op != OpCom32 {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpNeg32)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And32 x (And32 y x))
+	// match: (Add32 (Com32 x) (Const32 [1]))
 	// cond:
-	// result: (And32 x y)
+	// result: (Neg32 x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom32 {
+			break
+		}
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAnd32 {
+		if v_1.Op != OpConst32 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		if v_1.AuxInt != 1 {
 			break
 		}
-		v.reset(OpAnd32)
+		v.reset(OpNeg32)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And32 (And32 x y) x)
-	// cond:
-	// result: (And32 x y)
+	// match: (Add32 (Add32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Add32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd32 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd32)
-		v.AddArg(x)
-		v.AddArg(y)
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (And32 (And32 x y) y)
-	// cond:
-	// result: (And32 x y)
+	// match: (Add32 (Add32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Add32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd32 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd32)
-		v.AddArg(x)
-		v.AddArg(y)
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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)
+	// match: (Add32 x (Add32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Add32 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpAdd32 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (And64 x x)
-	// cond:
-	// result: x
+	// match: (Add32 x (Add32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Add32 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd32 {
 			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 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (And64 (Const64 [0]) _)
-	// cond:
-	// result: (Const64 [0])
+	return false
+}
+func rewriteValuegeneric_OpAdd32_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32 (Sub32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Sub32 <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpSub32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (And64 x (And64 x y))
-	// cond:
-	// result: (And64 x y)
+	// match: (Add32 x (Sub32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Sub32 <t> x z))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAnd64 {
+		if v_1.Op != OpSub32 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpAnd64)
-		v.AddArg(x)
-		v.AddArg(y)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (And64 x (And64 y x))
-	// cond:
-	// result: (And64 x y)
+	// match: (Add32 x (Sub32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Sub32 <t> x z))
 	for {
+		_ = v.Args[1]
 		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] {
+		if v_1.Op != OpSub32 {
 			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 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpAnd64)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (And64 (And64 x y) y)
-	// cond:
-	// result: (And64 x y)
+	// match: (Add32 (Sub32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Sub32 <t> x z))
 	for {
+		_ = v.Args[1]
 		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] {
+		if v_0.Op != OpSub32 {
 			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 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		y := v_0.AuxInt
+		t := i.Type
+		z := v_0.Args[1]
 		x := v.Args[1]
-		if !(nlz(y)+nto(y) == 64 && nto(y) >= 32) {
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpRsh64Ux64)
-		v0 := b.NewValue0(v.Line, OpLsh64x64, t)
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub32, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
-		v1.AuxInt = nlz(y)
-		v0.AddArg(v1)
+		v0.AddArg(z)
 		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)]))
+	// match: (Add32 (Sub32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Sub32 (Add32 <t> x z) i)
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpSub32 {
 			break
 		}
-		y := v_0.AuxInt
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
 		x := v.Args[1]
-		if !(nlo(y)+ntz(y) == 64 && ntz(y) >= 32) {
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpLsh64x64)
-		v0 := b.NewValue0(v.Line, OpRsh64Ux64, t)
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
 		v0.AddArg(x)
-		v1 := b.NewValue0(v.Line, OpConst64, t)
-		v1.AuxInt = ntz(y)
-		v0.AddArg(v1)
+		v0.AddArg(z)
 		v.AddArg(v0)
-		v2 := b.NewValue0(v.Line, OpConst64, t)
-		v2.AuxInt = ntz(y)
-		v.AddArg(v2)
+		v.AddArg(i)
 		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)
+	// match: (Add32 x (Sub32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Sub32 (Add32 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpSub32 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		v.AddArg(v0)
-		v.AddArg(x)
+		v.AddArg(i)
 		return true
 	}
-	// match: (And8  x x)
-	// cond:
-	// result: x
+	// match: (Add32 x (Sub32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Sub32 (Add32 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub32 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	// match: (And8  (Const8  [-1]) x)
-	// cond:
-	// result: x
+	// match: (Add32 (Sub32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Sub32 (Add32 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpSub32 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
+		t := i.Type
 		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	// match: (And8  (Const8  [0]) _)
+	// match: (Add32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
 	// cond:
-	// result: (Const8  [0])
+	// result: (Add32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd32 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		_ = v_1.Args[1]
+		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.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (And8  x (And8  x y))
+	// match: (Add32 (Const32 <t> [c]) (Add32 x (Const32 <t> [d])))
 	// cond:
-	// result: (And8  x y)
+	// result: (Add32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpAnd8 {
+		if v_1.Op != OpAdd32 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpAnd8)
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And8  x (And8  y x))
+	return false
+}
+func rewriteValuegeneric_OpAdd32_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32 (Add32 (Const32 <t> [d]) x) (Const32 <t> [c]))
 	// cond:
-	// result: (And8  x y)
+	// result: (Add32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAnd8 {
+		if v_1.Op != OpConst32 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpAnd8)
+		c := v_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And8  (And8  x y) x)
+	// match: (Add32 (Add32 x (Const32 <t> [d])) (Const32 <t> [c]))
 	// cond:
-	// result: (And8  x y)
+	// result: (Add32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd8 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpAnd8)
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
+		v.AddArg(v0)
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (And8  (And8  x y) y)
+	// match: (Add32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x))
 	// cond:
-	// result: (And8  x y)
+	// result: (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub32 {
 			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 {
-		off := v.AuxInt
-		n := v.Aux
-		if !(v.Type.IsString()) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
 			break
 		}
-		v.reset(OpStringMake)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
-		v0.AuxInt = off
-		v0.Aux = n
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
-		v1.AuxInt = off + config.PtrSize
-		v1.Aux = n
-		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 {
-		off := v.AuxInt
-		n := v.Aux
-		if !(v.Type.IsSlice()) {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpSliceMake)
-		v0 := b.NewValue0(v.Line, OpArg, v.Type.ElemType().PtrTo())
-		v0.AuxInt = off
-		v0.Aux = n
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
-		v1.AuxInt = off + config.PtrSize
-		v1.Aux = n
-		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
-		v2.AuxInt = off + 2*config.PtrSize
-		v2.Aux = n
-		v.AddArg(v2)
+		v.AddArg(x)
 		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]))
+	// match: (Add32 (Sub32 (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
-		off := v.AuxInt
-		n := v.Aux
-		if !(v.Type.IsInterface()) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub32 {
 			break
 		}
-		v.reset(OpIMake)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
-		v0.AuxInt = off
-		v0.Aux = n
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
-		v1.AuxInt = off + config.PtrSize
-		v1.Aux = n
-		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 {
-		off := v.AuxInt
-		n := v.Aux
-		if !(v.Type.IsComplex() && v.Type.Size() == 16) {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
 			break
 		}
-		v.reset(OpComplexMake)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
-		v0.AuxInt = off
-		v0.Aux = n
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
-		v1.AuxInt = off + 8
-		v1.Aux = n
-		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 {
-		off := v.AuxInt
-		n := v.Aux
-		if !(v.Type.IsComplex() && v.Type.Size() == 8) {
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpComplexMake)
-		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
-		v0.AuxInt = off
-		v0.Aux = n
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
-		v1.AuxInt = off + 4
-		v1.Aux = n
-		v.AddArg(v1)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Arg <t>)
-	// cond: t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)
-	// result: (StructMake0)
+	// match: (Add32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d])))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c-d))]) x)
 	for {
-		t := v.Type
-		if !(t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			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
-		off := v.AuxInt
-		n := v.Aux
-		if !(t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)) {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub32 {
 			break
 		}
-		v.reset(OpStructMake1)
-		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
-		v0.AuxInt = off + t.FieldOff(0)
-		v0.Aux = n
-		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
-		off := v.AuxInt
-		n := v.Aux
-		if !(t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)) {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpStructMake2)
-		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
-		v0.AuxInt = off + t.FieldOff(0)
-		v0.Aux = n
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
-		v1.AuxInt = off + t.FieldOff(1)
-		v1.Aux = n
-		v.AddArg(v1)
+		v.AddArg(x)
 		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)]))
+	// match: (Add32 (Sub32 x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c-d))]) x)
 	for {
-		t := v.Type
-		off := v.AuxInt
-		n := v.Aux
-		if !(t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub32 {
 			break
 		}
-		v.reset(OpStructMake3)
-		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
-		v0.AuxInt = off + t.FieldOff(0)
-		v0.Aux = n
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
-		v1.AuxInt = off + t.FieldOff(1)
-		v1.Aux = n
-		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
-		v2.AuxInt = off + t.FieldOff(2)
-		v2.Aux = n
-		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
-		off := v.AuxInt
-		n := v.Aux
-		if !(t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpStructMake4)
-		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
-		v0.AuxInt = off + t.FieldOff(0)
-		v0.Aux = n
-		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
-		v1.AuxInt = off + t.FieldOff(1)
-		v1.Aux = n
-		v.AddArg(v1)
-		v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
-		v2.AuxInt = off + t.FieldOff(2)
-		v2.Aux = n
-		v.AddArg(v2)
-		v3 := b.NewValue0(v.Line, OpArg, t.FieldType(3))
-		v3.AuxInt = off + t.FieldOff(3)
-		v3.Aux = n
-		v.AddArg(v3)
-		return true
-	}
-	// match: (Arg <t>)
-	// cond: t.IsArray() && t.NumElem() == 0
-	// result: (ArrayMake0)
-	for {
-		t := v.Type
-		if !(t.IsArray() && t.NumElem() == 0) {
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpArrayMake0)
-		return true
-	}
-	// match: (Arg <t> {n} [off])
-	// cond: t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t)
-	// result: (ArrayMake1 (Arg <t.ElemType()> {n} [off]))
-	for {
-		t := v.Type
-		off := v.AuxInt
-		n := v.Aux
-		if !(t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t)) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpArrayMake1)
-		v0 := b.NewValue0(v.Line, OpArg, t.ElemType())
-		v0.AuxInt = off
-		v0.Aux = n
+		c := v_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpArraySelect(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ArraySelect (ArrayMake1 x))
+func rewriteValuegeneric_OpAdd32F_0(v *Value) bool {
+	// match: (Add32F (Const32F [c]) (Const32F [d]))
 	// cond:
-	// result: x
+	// result: (Const32F [f2i(float64(i2f32(c) + i2f32(d)))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpArrayMake1 {
+		if v_0.Op != OpConst32F {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		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
 	}
-	// match: (ArraySelect [0] (Load ptr mem))
+	// match: (Add32F (Const32F [d]) (Const32F [c]))
 	// cond:
-	// result: (Load ptr mem)
+	// result: (Const32F [f2i(float64(i2f32(c) + i2f32(d)))])
 	for {
-		if v.AuxInt != 0 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
 			break
 		}
-		v_0 := v.Args[0]
-		if v_0.Op != OpLoad {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
 			break
 		}
-		ptr := v_0.Args[0]
-		mem := v_0.Args[1]
-		v.reset(OpLoad)
-		v.AddArg(ptr)
-		v.AddArg(mem)
+		c := v_1.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) + i2f32(d)))
 		return true
 	}
-	// match: (ArraySelect [0] x:(IData _))
+	// match: (Add32F x (Const32F [0]))
 	// cond:
 	// result: x
 	for {
-		if v.AuxInt != 0 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
 			break
 		}
-		x := v.Args[0]
-		if x.Op != OpIData {
+		if v_1.AuxInt != 0 {
 			break
 		}
 		v.reset(OpCopy)
@@ -1690,20 +1929,19 @@ func rewriteValuegeneric_OpArraySelect(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpCom16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com16 (Com16 x))
+	// match: (Add32F (Const32F [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpCom16 {
+		if v_0.Op != OpConst32F {
 			break
 		}
-		x := v_0.Args[0]
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
@@ -1711,642 +1949,617 @@ func rewriteValuegeneric_OpCom16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpCom32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Com32 (Com32 x))
+	// match: (Add64 (Const64 [c]) (Const64 [d]))
 	// cond:
-	// result: x
+	// result: (Const64 [c+d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpCom32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		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
 	}
-	return false
-}
-func rewriteValuegeneric_OpCom64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com64 (Com64 x))
+	// match: (Add64 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (Const64 [c+d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c + d
+		return true
+	}
+	// match: (Add64 (Const64 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpCom64 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
+		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_OpCom8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Com8  (Com8  x))
+	// match: (Add64 x (Const64 [0]))
 	// cond:
 	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpCom8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
 			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)
+	// match: (Add64 (Const64 [1]) (Com64 x))
 	// cond:
-	// result: (IMake     (ConstNil <config.fe.TypeBytePtr()>)     (ConstNil <config.fe.TypeBytePtr()>))
+	// result: (Neg64 x)
 	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)
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpCom64 {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpNeg64)
+		v.AddArg(x)
 		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]))
+	// match: (Add64 (Com64 x) (Const64 [1]))
+	// cond:
+	// result: (Neg64 x)
 	for {
-		if !(config.PtrSize == 4) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom64 {
 			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)
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpNeg64)
+		v.AddArg(x)
 		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]))
+	// match: (Add64 (Add64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Add64 <t> z x))
 	for {
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		v.reset(OpSliceMake)
-		v0 := b.NewValue0(v.Line, OpConstNil, v.Type.ElemType().PtrTo())
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		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]))
+	// match: (Add64 (Add64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Add64 <t> z x))
 	for {
-		s := v.Aux
-		if !(config.PtrSize == 4 && s.(string) == "") {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
 			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) == "") {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpStringMake)
-		v0 := b.NewValue0(v.Line, OpConstNil, config.fe.TypeBytePtr())
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		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)))]))
+	// match: (Add64 x (Add64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Add64 <t> z x))
 	for {
-		s := v.Aux
-		if !(config.PtrSize == 4 && s.(string) != "") {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd64 {
 			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_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		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)))]))
+	// match: (Add64 x (Add64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Add64 <t> z x))
 	for {
-		s := v.Aux
-		if !(config.PtrSize == 8 && s.(string) != "") {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd64 {
 			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_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		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 {
+func rewriteValuegeneric_OpAdd64_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Convert (Add64 (Convert ptr mem) off) mem)
-	// cond:
-	// result: (Add64 ptr off)
+	// match: (Add64 (Sub64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Sub64 <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd64 {
+		if v_0.Op != OpSub64 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConvert {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		ptr := v_0_0.Args[0]
-		mem := v_0_0.Args[1]
-		off := v_0.Args[1]
-		if mem != v.Args[1] {
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
 		v.reset(OpAdd64)
-		v.AddArg(ptr)
-		v.AddArg(off)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Convert (Add64 off (Convert ptr mem)) mem)
-	// cond:
-	// result: (Add64 ptr off)
+	// match: (Add64 x (Sub64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Sub64 <t> x z))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpAdd64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		off := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConvert {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		ptr := v_0_1.Args[0]
-		mem := v_0_1.Args[1]
-		if mem != v.Args[1] {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
 		v.reset(OpAdd64)
-		v.AddArg(ptr)
-		v.AddArg(off)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Convert (Convert ptr mem) mem)
-	// cond:
-	// result: ptr
+	// match: (Add64 x (Sub64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Sub64 <t> x z))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConvert {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		ptr := v_0.Args[0]
-		mem := v_0.Args[1]
-		if mem != v.Args[1] {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = ptr.Type
-		v.AddArg(ptr)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpCvt32Fto64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Cvt32Fto64F (Const32F [c]))
-	// cond:
-	// result: (Const64F [c])
+	// match: (Add64 (Sub64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Sub64 <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpSub64 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpConst64F)
-		v.AuxInt = c
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		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)))])
+	// match: (Add64 (Sub64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Sub64 (Add64 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpSub64 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpConst32F)
-		v.AuxInt = f2i(float64(i2f32(c)))
-		return true
-	}
-	return false
-}
-func rewriteValuegeneric_OpDiv32F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Div32F x (Const32F [f2i(1)]))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		if v_1.AuxInt != f2i(1) {
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	// match: (Div32F x (Const32F [f2i(-1)]))
-	// cond:
-	// result: (Neg32F x)
+	// match: (Add64 x (Sub64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Sub64 (Add64 <t> x z) i)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		if v_1.Op != OpSub64 {
 			break
 		}
-		if v_1.AuxInt != f2i(-1) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpNeg32F)
-		v.AddArg(x)
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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])))
+	// match: (Add64 x (Sub64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Sub64 (Add64 <t> x z) i)
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpSub64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c > 0 && smagic64ok(c) && smagic64m(c) > 0) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			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)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		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)
+		v.AddArg(i)
 		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])))
+	// match: (Add64 (Sub64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Sub64 (Add64 <t> x z) i)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c > 0 && smagic64ok(c) && smagic64m(c) < 0) {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			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)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		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)
+		v.AddArg(i)
 		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]))))
+	// match: (Add64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (Add64 (Const64 <t> [c+d]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst64 {
+		if v_1.Op != OpAdd64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c < 0 && smagic64ok(c) && smagic64m(c) > 0) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
 			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)
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
 		v.AddArg(v0)
+		v.AddArg(x)
 		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]))))
+	// match: (Add64 (Const64 <t> [c]) (Add64 x (Const64 <t> [d])))
+	// cond:
+	// result: (Add64 (Const64 <t> [c+d]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst64 {
+		if v_1.Op != OpAdd64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(c < 0 && smagic64ok(c) && smagic64m(c) < 0) {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			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)
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpDiv64F(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd64_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Div64F x (Const64F [f2i(1)]))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
-			break
-		}
-		if v_1.AuxInt != f2i(1) {
-			break
-		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (Div64F x (Const64F [f2i(-1)]))
+	// match: (Add64 (Add64 (Const64 <t> [d]) x) (Const64 <t> [c]))
 	// cond:
-	// result: (Neg32F x)
+	// result: (Add64 (Const64 <t> [c+d]) x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		if v_1.AuxInt != f2i(-1) {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			break
 		}
-		v.reset(OpNeg32F)
-		v.AddArg(x)
-		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]
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(isPowerOfTwo(c)) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpRsh64Ux64)
-		v.AddArg(n)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = log2(c)
+		c := v_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
 		v.AddArg(v0)
+		v.AddArg(x)
 		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)]))
+	// match: (Add64 (Add64 x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Add64 (Const64 <t> [c+d]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(umagic64ok(c) && !umagic64a(c)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			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]
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(umagic64ok(c) && umagic64a(c)) {
+		if v_1.Type != t {
 			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)
+		c := v_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
 		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
+		v.AddArg(x)
 		return true
 	}
-	// match: (Eq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
+	// match: (Add64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x))
 	// cond:
-	// result: (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+	// result: (Sub64 (Const64 <t> [c+d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
 		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd16 {
+		if v_1.Op != OpSub64 {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst16 {
+		if v_1_0.Op != OpConst64 {
 			break
 		}
 		if v_1_0.Type != t {
@@ -2354,1265 +2567,1404 @@ func rewriteValuegeneric_OpEq16(v *Value, config *Config) bool {
 		}
 		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.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Eq16 (Const16 [c]) (Const16 [d]))
+	// match: (Add64 (Sub64 (Const64 <t> [d]) x) (Const64 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(c == d)])
+	// result: (Sub64 (Const64 <t> [c+d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSub64 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpConst64 {
 			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] {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		c := v_1.AuxInt
+		v.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Eq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
+	// match: (Add64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d])))
 	// cond:
-	// result: (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+	// result: (Add64 (Const64 <t> [c-d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
 		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd32 {
+		if v_1.Op != OpSub64 {
 			break
 		}
-		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst32 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		if v_1_0.Type != t {
+		if v_1_1.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))
+		d := v_1_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = 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)
+	// match: (Add64 (Sub64 x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Add64 (Const64 <t> [c-d]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpEq32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
+		c := v_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Eq32 (Const32 [c]) (Const32 [d]))
+	return false
+}
+func rewriteValuegeneric_OpAdd64F_0(v *Value) bool {
+	// match: (Add64F (Const64F [c]) (Const64F [d]))
 	// cond:
-	// result: (ConstBool [b2i(c == d)])
+	// result: (Const64F [f2i(i2f(c) + i2f(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64F {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst64F {
 			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
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) + i2f(d))
 		return true
 	}
-	// match: (Eq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+	// match: (Add64F (Const64F [d]) (Const64F [c]))
 	// cond:
-	// result: (Eq64 (Const64 <t> [c-d]) x)
+	// result: (Const64F [f2i(i2f(c) + i2f(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst64F {
 			break
 		}
-		t := v_0.Type
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd64 {
+		if v_1.Op != OpConst64F {
 			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)
+		c := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) + i2f(d))
 		return true
 	}
-	// match: (Eq64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Eq64 (Const64 <t> [c]) x)
+	// match: (Add64F x (Const64F [0]))
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst64F {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpEq64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Eq64 (Const64 [c]) (Const64 [d]))
+	// match: (Add64F (Const64F [0]) x)
 	// cond:
-	// result: (ConstBool [b2i(c == d)])
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst64F {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c == d)
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpEq8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Eq8  x x)
+	// match: (Add8 (Const8 [c]) (Const8 [d]))
 	// cond:
-	// result: (ConstBool [1])
+	// result: (Const8  [int64(int8(c+d))])
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		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: (Eq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x))
+	// match: (Add8 (Const8 [d]) (Const8 [c]))
 	// cond:
-	// result: (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+	// result: (Const8  [int64(int8(c+d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
 		}
-		t := v_0.Type
-		c := v_0.AuxInt
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd8 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst8 {
+		c := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c + d))
+		return true
+	}
+	// match: (Add8 (Const8 [0]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_1_0.Type != t {
+		if v_0.AuxInt != 0 {
 			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)
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Eq8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Eq8  (Const8  <t> [c]) x)
+	// match: (Add8 x (Const8 [0]))
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		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) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpEq8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Eq8  (Const8  [c]) (Const8  [d]))
+	// match: (Add8 (Const8 [1]) (Com8 x))
 	// cond:
-	// result: (ConstBool [b2i(c == d)])
+	// result: (Neg8  x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
 		}
-		c := v_0.AuxInt
+		if v_0.AuxInt != 1 {
+			break
+		}
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpCom8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c == d)
+		x := v_1.Args[0]
+		v.reset(OpNeg8)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpEqB(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (EqB (ConstBool [c]) (ConstBool [d]))
+	// match: (Add8 (Com8 x) (Const8 [1]))
 	// cond:
-	// result: (ConstBool [b2i(c == d)])
+	// result: (Neg8  x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
+		if v_0.Op != OpCom8 {
 			break
 		}
-		c := v_0.AuxInt
+		x := v_0.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConstBool {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c == d)
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpNeg8)
+		v.AddArg(x)
 		return true
 	}
-	// match: (EqB (ConstBool [0]) x)
-	// cond:
-	// result: (Not x)
+	// match: (Add8 (Add8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Add8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
+		t := i.Type
+		z := v_0.Args[1]
 		x := v.Args[1]
-		v.reset(OpNot)
-		v.AddArg(x)
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (EqB (ConstBool [1]) x)
-	// cond:
-	// result: x
+	// match: (Add8 (Add8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Add8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		if v_0.AuxInt != 1 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
+		t := i.Type
 		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())
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(z)
 		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))
+	// match: (Add8 x (Add8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Add8  <t> z x))
 	for {
-		p := v.Args[0]
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConstNil {
+		if v_1.Op != OpAdd8 {
 			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 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		p := v.Args[1]
-		v.reset(OpNot)
-		v0 := b.NewValue0(v.Line, OpIsNonNil, config.fe.TypeBool())
-		v0.AddArg(p)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		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))
+	// match: (Add8 x (Add8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Add8  <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		y := v.Args[1]
-		v.reset(OpEqPtr)
-		v0 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd8 {
+			break
+		}
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(z)
 		v0.AddArg(x)
 		v.AddArg(v0)
-		v1 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
-		v1.AddArg(y)
-		v.AddArg(v1)
 		return true
 	}
+	return false
 }
-func rewriteValuegeneric_OpGeq16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd8_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Geq16 (Const16 [c]) (Const16 [d]))
-	// cond:
-	// result: (ConstBool [b2i(c >= d)])
+	// match: (Add8 (Sub8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Sub8  <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c >= d)
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		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))])
+	// match: (Add8 x (Sub8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Sub8  <t> x z))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint16(c) >= uint16(d))
-		return true
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		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)])
+	// match: (Add8 x (Sub8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Sub8  <t> x z))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c >= d)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		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))])
+	// match: (Add8 (Sub8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Sub8  <t> x z))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint32(c) >= uint32(d))
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		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)])
+	// match: (Add8 (Sub8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Sub8  (Add8  <t> x z) i)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c >= d)
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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))])
+	// match: (Add8 x (Sub8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Sub8  (Add8  <t> x z) i)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint64(c) >= uint64(d))
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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)])
+	// match: (Add8 x (Sub8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Sub8  (Add8  <t> x z) i)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c >= d)
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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))])
+	// match: (Add8 (Sub8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Sub8  (Add8  <t> x z) i)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint8(c) >= uint8(d))
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater16 (Const16 [c]) (Const16 [d]))
+	// match: (Add8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x))
 	// cond:
-	// result: (ConstBool [b2i(c > d)])
+	// result: (Add8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst8 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpAdd8 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1_0.Type != t {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint16(c) > uint16(d))
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater32 (Const32 [c]) (Const32 [d]))
+	// match: (Add8 (Const8 <t> [c]) (Add8 x (Const8 <t> [d])))
 	// cond:
-	// result: (ConstBool [b2i(c > d)])
+	// result: (Add8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst8 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpAdd8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c > d)
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpGreater32U(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAdd8_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Greater32U (Const32 [c]) (Const32 [d]))
+	// match: (Add8 (Add8 (Const8 <t> [d]) x) (Const8 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(uint32(c) > uint32(d))])
+	// result: (Add8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint32(c) > uint32(d))
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater64 (Const64 [c]) (Const64 [d]))
+	// match: (Add8 (Add8 x (Const8 <t> [d])) (Const8 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(c > d)])
+	// result: (Add8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c > d)
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater64U (Const64 [c]) (Const64 [d]))
+	// match: (Add8 (Const8 <t> [c]) (Sub8 (Const8 <t> [d]) x))
 	// cond:
-	// result: (ConstBool [b2i(uint64(c) > uint64(d))])
+	// result: (Sub8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpSub8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint64(c) > uint64(d))
-		return true
+		_ = v_1.Args[1]
+		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(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater8  (Const8  [c]) (Const8  [d]))
+	// match: (Add8 (Sub8 (Const8 <t> [d]) x) (Const8 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(c > d)])
+	// result: (Sub8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpSub8 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c > d)
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpGreater8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Greater8U  (Const8  [c]) (Const8  [d]))
+	// match: (Add8 (Const8 <t> [c]) (Sub8 x (Const8 <t> [d])))
 	// cond:
-	// result: (ConstBool [b2i(uint8(c)  > uint8(d))])
+	// result: (Add8  (Const8  <t> [int64(int8(c-d))]) x)
 	for {
+		_ = v.Args[1]
 		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 != OpConst8 {
+		if v_1.Op != OpSub8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint8(c) > uint8(d))
-		return true
-	}
-	return false
-}
-func rewriteValuegeneric_OpIMake(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (IMake typ (StructMake1 val))
-	// cond:
-	// result: (IMake typ val)
-	for {
-		typ := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpStructMake1 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
 			break
 		}
-		val := v_1.Args[0]
-		v.reset(OpIMake)
-		v.AddArg(typ)
-		v.AddArg(val)
-		return true
-	}
-	// match: (IMake typ (ArrayMake1 val))
-	// cond:
-	// result: (IMake typ val)
-	for {
-		typ := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpArrayMake1 {
+		if v_1_1.Type != t {
 			break
 		}
-		val := v_1.Args[0]
-		v.reset(OpIMake)
-		v.AddArg(typ)
-		v.AddArg(val)
+		d := v_1_1.AuxInt
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		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])
+	// match: (Add8 (Sub8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (Add8  (Const8  <t> [int64(int8(c-d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to32 {
+		if v_0.Op != OpSub8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
 			break
 		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		c := v_1.AuxInt
-		if !((1 << 8) <= c) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		c := v_1.AuxInt
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (IsInBounds (ZeroExt8to64  _) (Const64 [c]))
-	// cond: (1 << 8)  <= c
-	// result: (ConstBool [1])
+	return false
+}
+func rewriteValuegeneric_OpAddPtr_0(v *Value) bool {
+	// match: (AddPtr <t> x (Const64 [c]))
+	// cond:
+	// result: (OffPtr <t> x [c])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to64 {
-			break
-		}
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
 		c := v_1.AuxInt
-		if !((1 << 8) <= c) {
+		v.reset(OpOffPtr)
+		v.Type = t
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (AddPtr <t> x (Const32 [c]))
+	// cond:
+	// result: (OffPtr <t> x [c])
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		c := v_1.AuxInt
+		v.reset(OpOffPtr)
+		v.Type = t
+		v.AuxInt = c
+		v.AddArg(x)
 		return true
 	}
-	// match: (IsInBounds (ZeroExt16to32 _) (Const32 [c]))
-	// cond: (1 << 16) <= c
-	// result: (ConstBool [1])
+	return false
+}
+func rewriteValuegeneric_OpAnd16_0(v *Value) bool {
+	// match: (And16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c&d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt16to32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
+		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
-			break
-		}
-		c := v_1.AuxInt
-		if !((1 << 16) <= c) {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c & d))
 		return true
 	}
-	// match: (IsInBounds (ZeroExt16to64 _) (Const64 [c]))
-	// cond: (1 << 16) <= c
-	// result: (ConstBool [1])
+	// match: (And16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [int64(int16(c&d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt16to64 {
+		if v_0.Op != OpConst16 {
 			break
 		}
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst16 {
 			break
 		}
 		c := v_1.AuxInt
-		if !((1 << 16) <= c) {
-			break
-		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c & d))
 		return true
 	}
-	// match: (IsInBounds x x)
+	// match: (And16 x x)
 	// cond:
-	// result: (ConstBool [0])
+	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (IsInBounds (And32 (Const32 [c]) _) (Const32 [d]))
-	// cond: 0 <= c && c < d
-	// result: (ConstBool [1])
+	// match: (And16 (Const16 [-1]) x)
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst32 {
+		if v_0.AuxInt != -1 {
 			break
 		}
-		c := v_0_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And16 x (Const16 [-1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(0 <= c && c < d) {
+		if v_1.AuxInt != -1 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (IsInBounds (And64 (Const64 [c]) _) (Const64 [d]))
-	// cond: 0 <= c && c < d
-	// result: (ConstBool [1])
+	// match: (And16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd64 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst64 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		c := v_0_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (And16 _ (Const16 [0]))
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(0 <= c && c < d) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (IsInBounds (Const32 [c]) (Const32 [d]))
+	// match: (And16 x (And16 x y))
 	// cond:
-	// result: (ConstBool [b2i(0 <= c && c < d)])
+	// result: (And16 x y)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(0 <= c && c < d)
+		y := v_1.Args[1]
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (IsInBounds (Const64 [c]) (Const64 [d]))
+	// match: (And16 x (And16 y x))
 	// cond:
-	// result: (ConstBool [b2i(0 <= c && c < d)])
+	// result: (And16 x y)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
-			break
-		}
-		c := v_0.AuxInt
+		_ = v.Args[1]
+		x := v.Args[0]
 		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 {
+		if v_1.Op != OpAnd16 {
 			break
 		}
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (IsInBounds (Mod64u _ y) y)
+	// match: (And16 (And16 x y) x)
 	// cond:
-	// result: (ConstBool [1])
+	// result: (And16 x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpMod64u {
+		if v_0.Op != OpAnd16 {
 			break
 		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
 		y := v_0.Args[1]
-		if y != v.Args[1] {
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAnd16_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (IsSliceInBounds x x)
+	// match: (And16 (And16 y x) x)
 	// cond:
-	// result: (ConstBool [1])
+	// result: (And16 x y)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d]))
-	// cond: 0 <= c && c <= d
-	// result: (ConstBool [1])
+	// match: (And16 (And16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (And16 i (And16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd32 {
-			break
-		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst32 {
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		c := v_0_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(0 <= c && c <= d) {
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpAnd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d]))
-	// cond: 0 <= c && c <= d
-	// result: (ConstBool [1])
+	// match: (And16 (And16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (And16 i (And16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd64 {
-			break
-		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst64 {
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		c := v_0_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(0 <= c && c <= d) {
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		v.reset(OpAnd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (IsSliceInBounds (Const32 [0]) _)
-	// cond:
-	// result: (ConstBool [1])
+	// match: (And16 x (And16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (And16 i (And16 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (IsSliceInBounds (Const64 [0]) _)
-	// cond:
-	// result: (ConstBool [1])
+	// match: (And16 x (And16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (And16 i (And16 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (IsSliceInBounds (Const32 [c]) (Const32 [d]))
+	// match: (And16 (Const16 <t> [c]) (And16 (Const16 <t> [d]) x))
 	// cond:
-	// result: (ConstBool [b2i(0 <= c && c <= d)])
+	// result: (And16 (Const16 <t> [int64(int16(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpAnd16 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1_0.Type != t {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(0 <= c && c <= d)
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAnd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (IsSliceInBounds (SliceLen x) (SliceCap x))
+	// match: (And16 (Const16 <t> [c]) (And16 x (Const16 <t> [d])))
 	// cond:
-	// result: (ConstBool [1])
+	// result: (And16 (Const16 <t> [int64(int16(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceLen {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
+		t := v_0.Type
+		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpSliceCap {
+		if v_1.Op != OpAnd16 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 1
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAnd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq16 (Const16 [c]) (Const16 [d]))
+	// match: (And16 (And16 (Const16 <t> [d]) x) (Const16 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(c <= d)])
+	// result: (And16 (Const16 <t> [int64(int16(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c <= d)
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAnd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq16U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq16U (Const16 [c]) (Const16 [d]))
+	// match: (And16 (And16 x (Const16 <t> [d])) (Const16 <t> [c]))
 	// cond:
-	// result: (ConstBool [b2i(uint16(c) <= uint16(d))])
+	// result: (And16 (Const16 <t> [int64(int16(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.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))
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAnd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLeq32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq32 (Const32 [c]) (Const32 [d]))
+func rewriteValuegeneric_OpAnd32_0(v *Value) bool {
+	// match: (And32 (Const32 [c]) (Const32 [d]))
 	// cond:
-	// result: (ConstBool [b2i(c <= d)])
+	// result: (Const32 [int64(int32(c&d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst32 {
 			break
@@ -3623,593 +3975,520 @@ func rewriteValuegeneric_OpLeq32(v *Value, config *Config) bool {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c <= d)
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c & d))
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq32U (Const32 [c]) (Const32 [d]))
+	// match: (And32 (Const32 [d]) (Const32 [c]))
 	// cond:
-	// result: (ConstBool [b2i(uint32(c) <= uint32(d))])
+	// result: (Const32 [int64(int32(c&d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
+		d := 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))
+		c := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c & d))
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq64 (Const64 [c]) (Const64 [d]))
+	// match: (And32 x x)
 	// cond:
-	// result: (ConstBool [b2i(c <= d)])
+	// result: x
 	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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c <= d)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq64U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq64U (Const64 [c]) (Const64 [d]))
+	// match: (And32 (Const32 [-1]) x)
 	// cond:
-	// result: (ConstBool [b2i(uint64(c) <= uint64(d))])
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_0.AuxInt != -1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint64(c) <= uint64(d))
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq8  (Const8  [c]) (Const8  [d]))
+	// match: (And32 x (Const32 [-1]))
 	// cond:
-	// result: (ConstBool [b2i(c <= d)])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.AuxInt != -1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c <= d)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLeq8U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Leq8U  (Const8  [c]) (Const8  [d]))
+	// match: (And32 (Const32 [0]) _)
 	// cond:
-	// result: (ConstBool [b2i(uint8(c)  <= uint8(d))])
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint8(c) <= uint8(d))
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLess16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less16 (Const16 [c]) (Const16 [d]))
+	// match: (And32 _ (Const32 [0]))
 	// cond:
-	// result: (ConstBool [b2i(c < d)])
+	// result: (Const32 [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c < d)
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLess16U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less16U (Const16 [c]) (Const16 [d]))
+	// match: (And32 x (And32 x y))
 	// cond:
-	// result: (ConstBool [b2i(uint16(c) < uint16(d))])
+	// result: (And32 x y)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint16(c) < uint16(d))
+		y := v_1.Args[1]
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLess32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less32 (Const32 [c]) (Const32 [d]))
+	// match: (And32 x (And32 y x))
 	// cond:
-	// result: (ConstBool [b2i(c < d)])
+	// result: (And32 x y)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c < d)
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLess32U(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Less32U (Const32 [c]) (Const32 [d]))
+	// match: (And32 (And32 x y) x)
 	// cond:
-	// result: (ConstBool [b2i(uint32(c) < uint32(d))])
+	// result: (And32 x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint32(c) < uint32(d))
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLess64(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAnd32_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Less64 (Const64 [c]) (Const64 [d]))
+	// match: (And32 (And32 y x) x)
 	// cond:
-	// result: (ConstBool [b2i(c < d)])
+	// result: (And32 x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c < d)
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
 		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))])
+	// match: (And32 (And32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (And32 i (And32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint64(c) < uint64(d))
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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)])
+	// match: (And32 (And32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (And32 i (And32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c < d)
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))])
+	// match: (And32 x (And32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (And32 i (And32 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(uint8(c) < uint8(d))
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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
+	// match: (And32 x (And32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (And32 i (And32 <t> z x))
 	for {
-		t1 := v.Type
-		p1 := v.Args[0]
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpStore {
+		if v_1.Op != OpAnd32 {
 			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()) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
 			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)) {
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpStructMake0)
+		v.reset(OpAnd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))
+	// match: (And32 (Const32 <t> [c]) (And32 (Const32 <t> [d]) x))
+	// cond:
+	// result: (And32 (Const32 <t> [int64(int32(c&d))]) x)
 	for {
-		t := v.Type
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			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)) {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
 			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)) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
 			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)) {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpStructMake4)
-		v0 := b.NewValue0(v.Line, OpLoad, t.FieldType(0))
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAnd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c & d))
 		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)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Load <t> _ _)
-	// cond: t.IsArray() && t.NumElem() == 0
-	// result: (ArrayMake0)
+	// match: (And32 (Const32 <t> [c]) (And32 x (Const32 <t> [d])))
+	// cond:
+	// result: (And32 (Const32 <t> [int64(int32(c&d))]) x)
 	for {
-		t := v.Type
-		if !(t.IsArray() && t.NumElem() == 0) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			break
 		}
-		v.reset(OpArrayMake0)
-		return true
-	}
-	// match: (Load <t> ptr mem)
-	// cond: t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t)
-	// result: (ArrayMake1 (Load <t.ElemType()> ptr mem))
-	for {
-		t := v.Type
-		ptr := v.Args[0]
-		mem := v.Args[1]
-		if !(t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t)) {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
 			break
 		}
-		v.reset(OpArrayMake1)
-		v0 := b.NewValue0(v.Line, OpLoad, t.ElemType())
-		v0.AddArg(ptr)
-		v0.AddArg(mem)
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAnd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c & d))
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh16x16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x16  <t> x (Const16 [c]))
+	// match: (And32 (And32 (Const32 <t> [d]) x) (Const32 <t> [c]))
 	// cond:
-	// result: (Lsh16x64  x (Const64 <t> [int64(uint16(c))]))
+	// result: (And32 (Const32 <t> [int64(int32(c&d))]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(OpLsh16x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
+		v.reset(OpAnd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c & d))
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x16  (Const16 [0]) _)
+	// match: (And32 (And32 x (Const32 <t> [d])) (Const32 <t> [c]))
 	// cond:
-	// result: (Const16 [0])
+	// result: (And32 (Const32 <t> [int64(int32(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAnd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLsh16x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x32  <t> x (Const32 [c]))
+func rewriteValuegeneric_OpAnd64_0(v *Value) bool {
+	// match: (And64 (Const64 [c]) (Const64 [d]))
 	// cond:
-	// result: (Lsh16x64  x (Const64 <t> [int64(uint32(c))]))
+	// result: (Const64 [c&d])
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst64 {
 			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)
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c & d
 		return true
 	}
-	// match: (Lsh16x32  (Const16 [0]) _)
+	// match: (And64 (Const64 [d]) (Const64 [c]))
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const64 [c&d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		c := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c & d
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh16x64  (Const16 [c]) (Const64 [d]))
+	// match: (And64 x x)
 	// cond:
-	// result: (Const16 [int64(int16(c) << uint64(d))])
+	// result: x
+	for {
+		_ = v.Args[1]
+		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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_0.AuxInt != -1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c) << uint64(d))
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x64  x (Const64 [0]))
+	// match: (And64 x (Const64 [-1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		if v_1.AuxInt != -1 {
 			break
 		}
 		v.reset(OpCopy)
@@ -4217,505 +4496,560 @@ func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh16x64  (Const16 [0]) _)
+	// match: (And64 (Const64 [0]) _)
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
 		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst16)
+		v.reset(OpConst64)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh16x64  _ (Const64 [c]))
-	// cond: uint64(c) >= 16
-	// result: (Const16 [0])
+	// match: (And64 _ (Const64 [0]))
+	// cond:
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 16) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst16)
+		v.reset(OpConst64)
 		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 {
+	// match: (And64 x (And64 x y))
+	// cond:
+	// result: (And64 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		c := v_0_1.AuxInt
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		v.reset(OpLsh16x64)
+		v.reset(OpAnd64)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
-		v.AddArg(v0)
+		v.AddArg(y)
 		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]))
+	// match: (And64 (And64 x y) x)
+	// cond:
+	// result: (And64 x y)
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpLsh16x64)
+		v.reset(OpAnd64)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v0.AuxInt = c1 - c2 + c3
-		v.AddArg(v0)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLsh16x8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAnd64_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh16x8   <t> x (Const8  [c]))
+	// match: (And64 (And64 y x) x)
 	// cond:
-	// result: (Lsh16x64  x (Const64 <t> [int64(uint8(c))]))
+	// result: (And64 x y)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh16x64)
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd64)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
-		v.AddArg(v0)
+		v.AddArg(y)
 		return true
 	}
-	// match: (Lsh16x8  (Const16 [0]) _)
-	// cond:
-	// result: (Const16 [0])
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		y := v_0.AuxInt
+		x := v.Args[1]
+		if !(nlz(y)+nto(y) == 64 && nto(y) >= 32) {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Pos, OpLsh64x64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
+		v1.AuxInt = nlz(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = nlz(y)
+		v.AddArg(v2)
 		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))]))
+	// match: (And64 <t> x (Const64 [y]))
+	// 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.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
+		y := v_1.AuxInt
+		if !(nlz(y)+nto(y) == 64 && nto(y) >= 32) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Pos, OpLsh64x64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
+		v1.AuxInt = nlz(y)
+		v0.AddArg(v1)
 		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = nlz(y)
+		v.AddArg(v2)
 		return true
 	}
-	// match: (Lsh32x16  (Const32 [0]) _)
-	// cond:
-	// result: (Const32 [0])
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		y := v_0.AuxInt
+		x := v.Args[1]
+		if !(nlo(y)+ntz(y) == 64 && ntz(y) >= 32) {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		v.reset(OpLsh64x64)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
+		v1.AuxInt = ntz(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = ntz(y)
+		v.AddArg(v2)
 		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))]))
+	// match: (And64 <t> x (Const64 [y]))
+	// 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.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
+		y := v_1.AuxInt
+		if !(nlo(y)+ntz(y) == 64 && ntz(y) >= 32) {
+			break
+		}
+		v.reset(OpLsh64x64)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
+		v1.AuxInt = ntz(y)
+		v0.AddArg(v1)
 		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = ntz(y)
+		v.AddArg(v2)
 		return true
 	}
-	// match: (Lsh32x32  (Const32 [0]) _)
-	// cond:
-	// result: (Const32 [0])
+	// match: (And64 (And64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (And64 i (And64 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))])
+	// match: (And64 (And64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (And64 i (And64 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c) << uint64(d))
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Lsh32x64  x (Const64 [0]))
-	// cond:
-	// result: x
+	// match: (And64 x (And64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (And64 i (And64 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
-			break
-		}
-		if v_1.AuxInt != 0 {
+		if v_1.Op != OpAnd64 {
 			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 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		v.reset(OpAnd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Lsh32x64  _ (Const64 [c]))
-	// cond: uint64(c) >= 32
-	// result: (Const32 [0])
+	// match: (And64 x (And64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (And64 i (And64 <t> z x))
 	for {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 32) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Lsh32x64 <t> (Lsh32x64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Lsh32x64 x (Const64 <t> [c+d]))
+	// match: (And64 (Const64 <t> [c]) (And64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (And64 (Const64 <t> [c&d]) x)
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLsh32x64 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		c := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpLsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAnd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c & d
 		v.AddArg(v0)
+		v.AddArg(x)
 		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]))
+	return false
+}
+func rewriteValuegeneric_OpAnd64_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (And64 (Const64 <t> [c]) (And64 x (Const64 <t> [d])))
+	// cond:
+	// result: (And64 (Const64 <t> [c&d]) x)
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		c1 := v_0_0_1.AuxInt
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		c2 := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpLsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v0.AuxInt = c1 - c2 + c3
+		d := v_1_1.AuxInt
+		v.reset(OpAnd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c & d
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh32x8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh32x8   <t> x (Const8  [c]))
+	// match: (And64 (And64 (Const64 <t> [d]) x) (Const64 <t> [c]))
 	// cond:
-	// result: (Lsh32x64  x (Const64 <t> [int64(uint8(c))]))
+	// result: (And64 (Const64 <t> [c&d]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(OpLsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
+		v.reset(OpAnd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c & d
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh32x8  (Const32 [0]) _)
+	// match: (And64 (And64 x (Const64 <t> [d])) (Const64 <t> [c]))
 	// cond:
-	// result: (Const32 [0])
+	// result: (And64 (Const64 <t> [c&d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			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]
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(OpLsh64x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
+		v.reset(OpAnd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c & d
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x16  (Const64 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpAnd8_0(v *Value) bool {
+	// match: (And8 (Const8 [c]) (Const8 [d]))
 	// cond:
-	// result: (Const64 [0])
+	// result: (Const8  [int64(int8(c&d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c & d))
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh64x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh64x32  <t> x (Const32 [c]))
+	// match: (And8 (Const8 [d]) (Const8 [c]))
 	// cond:
-	// result: (Lsh64x64  x (Const64 <t> [int64(uint32(c))]))
+	// result: (Const8  [int64(int8(c&d))])
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		d := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		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(uint32(c))
-		v.AddArg(v0)
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c & d))
 		return true
 	}
-	// match: (Lsh64x32  (Const64 [0]) _)
+	// match: (And8 x x)
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
-			break
-		}
-		if v_0.AuxInt != 0 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh64x64  (Const64 [c]) (Const64 [d]))
+	// match: (And8 (Const8 [-1]) x)
 	// cond:
-	// result: (Const64 [c << uint64(d)])
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_0.AuxInt != -1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = c << uint64(d)
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x64  x (Const64 [0]))
+	// match: (And8 x (Const8 [-1]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		if v_1.AuxInt != -1 {
 			break
 		}
 		v.reset(OpCopy)
@@ -4723,509 +5057,12418 @@ func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh64x64  (Const64 [0]) _)
+	// match: (And8 (Const8 [0]) _)
 	// cond:
-	// result: (Const64 [0])
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst64)
+		v.reset(OpConst8)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Lsh64x64  _ (Const64 [c]))
-	// cond: uint64(c) >= 64
-	// result: (Const64 [0])
+	// match: (And8 _ (Const8 [0]))
+	// cond:
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 64) {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst64)
+		v.reset(OpConst8)
 		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]))
+	// match: (And8 x (And8 x y))
+	// cond:
+	// result: (And8  x y)
 	for {
-		t := v.Type
-		v_0 := v.Args[0]
-		if v_0.Op != OpLsh64x64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		c := v_0_1.AuxInt
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpAnd8 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		v.reset(OpLsh64x64)
+		v.reset(OpAnd8)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
-		v.AddArg(v0)
+		v.AddArg(y)
 		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]))
+	// match: (And8 (And8 x y) x)
+	// cond:
+	// result: (And8  x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpRsh64Ux64 {
-			break
-		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpLsh64x64 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		x := v_0_0.Args[0]
-		v_0_0_1 := v_0_0.Args[1]
-		if v_0_0_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			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.reset(OpAnd8)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v0.AuxInt = c1 - c2 + c3
-		v.AddArg(v0)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLsh64x8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpAnd8_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh64x8   <t> x (Const8  [c]))
+	// match: (And8 (And8 y x) x)
 	// cond:
-	// result: (Lsh64x64  x (Const64 <t> [int64(uint8(c))]))
+	// result: (And8  x y)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh64x64)
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd8)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
-		v.AddArg(v0)
+		v.AddArg(y)
 		return true
 	}
-	// match: (Lsh64x8  (Const64 [0]) _)
-	// cond:
-	// result: (Const64 [0])
+	// match: (And8 (And8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (And8  i (And8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
 			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 {
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
+		v.reset(OpAnd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Lsh8x16   (Const8 [0]) _)
-	// cond:
-	// result: (Const8  [0])
+	// match: (And8 (And8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (And8  i (And8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))]))
+	// match: (And8 x (And8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (And8  i (And8  <t> z x))
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpAnd8 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Lsh8x32   (Const8 [0]) _)
-	// cond:
-	// result: (Const8  [0])
+	// match: (And8 x (And8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (And8  i (And8  <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpAnd8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Lsh8x64   (Const8  [c]) (Const64 [d]))
+	// match: (And8 (Const8 <t> [c]) (And8 (Const8 <t> [d]) x))
 	// cond:
-	// result: (Const8  [int64(int8(c) << uint64(d))])
+	// result: (And8  (Const8  <t> [int64(int8(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		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 != OpConst64 {
+		if v_1.Op != OpAnd8 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAnd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c & d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh8x64   (Const8 [0]) _)
+	// match: (And8 (Const8 <t> [c]) (And8 x (Const8 <t> [d])))
 	// cond:
-	// result: (Const8  [0])
+	// result: (And8  (Const8  <t> [int64(int8(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
 			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 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 8) {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		d := v_1_1.AuxInt
+		v.reset(OpAnd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c & d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Lsh8x64  <t> (Lsh8x64  x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Lsh8x64  x (Const64 <t> [c+d]))
+	// match: (And8 (And8 (Const8 <t> [d]) x) (Const8 <t> [c]))
+	// cond:
+	// result: (And8  (Const8  <t> [int64(int8(c&d))]) x)
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLsh8x64 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
 			break
 		}
-		c := v_0_1.AuxInt
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpLsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
+		c := v_1.AuxInt
+		v.reset(OpAnd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c & d))
 		v.AddArg(v0)
+		v.AddArg(x)
 		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]))
+	// match: (And8 (And8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (And8  (Const8  <t> [int64(int8(c&d))]) x)
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		c1 := v_0_0_1.AuxInt
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
 		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		if v_0_1.Op != OpConst8 {
 			break
 		}
-		c2 := v_0_1.AuxInt
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpLsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v0.AuxInt = c1 - c2 + c3
+		c := v_1.AuxInt
+		v.reset(OpAnd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c & d))
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpLsh8x8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpArg_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Lsh8x8   <t> x (Const8  [c]))
-	// cond:
-	// result: (Lsh8x64  x (Const64 <t> [int64(uint8(c))]))
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsString()
+	// result: (StringMake     (Arg <typ.BytePtr> {n} [off])     (Arg <typ.Int> {n} [off+config.PtrSize]))
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		off := v.AuxInt
+		n := v.Aux
+		if !(v.Type.IsString()) {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpLsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Pos, OpArg, typ.BytePtr)
+		v0.AuxInt = off
+		v0.Aux = n
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, typ.Int)
+		v1.AuxInt = off + config.PtrSize
+		v1.Aux = n
+		v.AddArg(v1)
 		return true
 	}
-	// match: (Lsh8x8   (Const8 [0]) _)
-	// cond:
-	// result: (Const8  [0])
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsSlice()
+	// result: (SliceMake     (Arg <v.Type.ElemType().PtrTo()> {n} [off])     (Arg <typ.Int> {n} [off+config.PtrSize])     (Arg <typ.Int> {n} [off+2*config.PtrSize]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
-			break
-		}
-		if v_0.AuxInt != 0 {
+		off := v.AuxInt
+		n := v.Aux
+		if !(v.Type.IsSlice()) {
 			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))])
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Pos, OpArg, v.Type.ElemType().PtrTo())
+		v0.AuxInt = off
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, typ.Int)
+		v1.AuxInt = off + config.PtrSize
+		v1.Aux = n
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpArg, typ.Int)
+		v2.AuxInt = off + 2*config.PtrSize
+		v2.Aux = n
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsInterface()
+	// result: (IMake     (Arg <typ.BytePtr> {n} [off])     (Arg <typ.BytePtr> {n} [off+config.PtrSize]))
+	for {
+		off := v.AuxInt
+		n := v.Aux
+		if !(v.Type.IsInterface()) {
+			break
+		}
+		v.reset(OpIMake)
+		v0 := b.NewValue0(v.Pos, OpArg, typ.BytePtr)
+		v0.AuxInt = off
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, typ.BytePtr)
+		v1.AuxInt = off + config.PtrSize
+		v1.Aux = n
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsComplex() && v.Type.Size() == 16
+	// result: (ComplexMake     (Arg <typ.Float64> {n} [off])     (Arg <typ.Float64> {n} [off+8]))
+	for {
+		off := v.AuxInt
+		n := v.Aux
+		if !(v.Type.IsComplex() && v.Type.Size() == 16) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Pos, OpArg, typ.Float64)
+		v0.AuxInt = off
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, typ.Float64)
+		v1.AuxInt = off + 8
+		v1.Aux = n
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsComplex() && v.Type.Size() == 8
+	// result: (ComplexMake     (Arg <typ.Float32> {n} [off])     (Arg <typ.Float32> {n} [off+4]))
+	for {
+		off := v.AuxInt
+		n := v.Aux
+		if !(v.Type.IsComplex() && v.Type.Size() == 8) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Pos, OpArg, typ.Float32)
+		v0.AuxInt = off
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, typ.Float32)
+		v1.AuxInt = off + 4
+		v1.Aux = n
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg <t>)
+	// cond: t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t)
+	// result: (StructMake0)
+	for {
+		t := v.Type
+		if !(t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake0)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 1 && fe.CanSSA(t)
+	// result: (StructMake1     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]))
+	for {
+		t := v.Type
+		off := v.AuxInt
+		n := v.Aux
+		if !(t.IsStruct() && t.NumFields() == 1 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake1)
+		v0 := b.NewValue0(v.Pos, OpArg, t.FieldType(0))
+		v0.AuxInt = off + t.FieldOff(0)
+		v0.Aux = n
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 2 && 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
+		off := v.AuxInt
+		n := v.Aux
+		if !(t.IsStruct() && t.NumFields() == 2 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake2)
+		v0 := b.NewValue0(v.Pos, OpArg, t.FieldType(0))
+		v0.AuxInt = off + t.FieldOff(0)
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, t.FieldType(1))
+		v1.AuxInt = off + t.FieldOff(1)
+		v1.Aux = n
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 3 && 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
+		off := v.AuxInt
+		n := v.Aux
+		if !(t.IsStruct() && t.NumFields() == 3 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake3)
+		v0 := b.NewValue0(v.Pos, OpArg, t.FieldType(0))
+		v0.AuxInt = off + t.FieldOff(0)
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, t.FieldType(1))
+		v1.AuxInt = off + t.FieldOff(1)
+		v1.Aux = n
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpArg, t.FieldType(2))
+		v2.AuxInt = off + t.FieldOff(2)
+		v2.Aux = n
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 4 && 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
+		off := v.AuxInt
+		n := v.Aux
+		if !(t.IsStruct() && t.NumFields() == 4 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake4)
+		v0 := b.NewValue0(v.Pos, OpArg, t.FieldType(0))
+		v0.AuxInt = off + t.FieldOff(0)
+		v0.Aux = n
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpArg, t.FieldType(1))
+		v1.AuxInt = off + t.FieldOff(1)
+		v1.Aux = n
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpArg, t.FieldType(2))
+		v2.AuxInt = off + t.FieldOff(2)
+		v2.Aux = n
+		v.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpArg, t.FieldType(3))
+		v3.AuxInt = off + t.FieldOff(3)
+		v3.Aux = n
+		v.AddArg(v3)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpArg_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	fe := b.Func.fe
+	_ = fe
+	// match: (Arg <t>)
+	// cond: t.IsArray() && t.NumElem() == 0
+	// result: (ArrayMake0)
+	for {
+		t := v.Type
+		if !(t.IsArray() && t.NumElem() == 0) {
+			break
+		}
+		v.reset(OpArrayMake0)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t)
+	// result: (ArrayMake1 (Arg <t.ElemType()> {n} [off]))
+	for {
+		t := v.Type
+		off := v.AuxInt
+		n := v.Aux
+		if !(t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpArrayMake1)
+		v0 := b.NewValue0(v.Pos, OpArg, t.ElemType())
+		v0.AuxInt = off
+		v0.Aux = n
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpArraySelect_0(v *Value) bool {
+	// match: (ArraySelect (ArrayMake1 x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpArrayMake1 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ArraySelect [0] (Load ptr mem))
+	// cond:
+	// result: (Load ptr mem)
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpLoad {
+			break
+		}
+		_ = v_0.Args[1]
+		ptr := v_0.Args[0]
+		mem := v_0.Args[1]
+		v.reset(OpLoad)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (ArraySelect [0] x:(IData _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		if x.Op != OpIData {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom16_0(v *Value) bool {
+	// 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
+	}
+	// match: (Com16 (Const16 [c]))
+	// cond:
+	// result: (Const16 [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom32_0(v *Value) bool {
+	// 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
+	}
+	// match: (Com32 (Const32 [c]))
+	// cond:
+	// result: (Const32 [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom64_0(v *Value) bool {
+	// 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
+	}
+	// match: (Com64 (Const64 [c]))
+	// cond:
+	// result: (Const64 [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom8_0(v *Value) bool {
+	// 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
+	}
+	// match: (Com8 (Const8 [c]))
+	// cond:
+	// result: (Const8  [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConstInterface_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ConstInterface)
+	// cond:
+	// result: (IMake     (ConstNil <typ.BytePtr>)     (ConstNil <typ.BytePtr>))
+	for {
+		v.reset(OpIMake)
+		v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpConstSlice_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ConstSlice)
+	// cond: config.PtrSize == 4
+	// result: (SliceMake     (ConstNil <v.Type.ElemType().PtrTo()>)     (Const32 <typ.Int> [0])     (Const32 <typ.Int> [0]))
+	for {
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Pos, OpConstNil, v.Type.ElemType().PtrTo())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.Int)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.Int)
+		v2.AuxInt = 0
+		v.AddArg(v2)
+		return true
+	}
+	// match: (ConstSlice)
+	// cond: config.PtrSize == 8
+	// result: (SliceMake     (ConstNil <v.Type.ElemType().PtrTo()>)     (Const64 <typ.Int> [0])     (Const64 <typ.Int> [0]))
+	for {
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Pos, OpConstNil, v.Type.ElemType().PtrTo())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.Int)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.Int)
+		v2.AuxInt = 0
+		v.AddArg(v2)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConstString_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 4 && s.(string) == ""
+	// result: (StringMake (ConstNil) (Const32 <typ.Int> [0]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 4 && s.(string) == "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.Int)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 8 && s.(string) == ""
+	// result: (StringMake (ConstNil) (Const64 <typ.Int> [0]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 8 && s.(string) == "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.Int)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 4 && s.(string) != ""
+	// result: (StringMake     (Addr <typ.BytePtr> {fe.StringData(s.(string))}       (SB))     (Const32 <typ.Int> [int64(len(s.(string)))]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 4 && s.(string) != "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
+		v0.Aux = fe.StringData(s.(string))
+		v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.Int)
+		v2.AuxInt = int64(len(s.(string)))
+		v.AddArg(v2)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 8 && s.(string) != ""
+	// result: (StringMake     (Addr <typ.BytePtr> {fe.StringData(s.(string))}       (SB))     (Const64 <typ.Int> [int64(len(s.(string)))]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 8 && s.(string) != "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
+		v0.Aux = fe.StringData(s.(string))
+		v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.Int)
+		v2.AuxInt = int64(len(s.(string)))
+		v.AddArg(v2)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConvert_0(v *Value) bool {
+	// match: (Convert (Add64 (Convert ptr mem) off) mem)
+	// cond:
+	// result: (Add64 ptr off)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConvert {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		off := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConvert {
+			break
+		}
+		_ = v_0_1.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConvert {
+			break
+		}
+		_ = v_0.Args[1]
+		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_0(v *Value) bool {
+	// 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_0(v *Value) bool {
+	// 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_OpDiv16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16 (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(int16(c)/int16(d))])
+	for {
+		_ = v.Args[1]
+		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) / int16(d))
+		return true
+	}
+	// match: (Div16 <t> n (Const16 [c]))
+	// cond: c < 0 && c != -1<<15
+	// result: (Neg16 (Div16 <t> n (Const16 <t> [-c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<15) {
+			break
+		}
+		v.reset(OpNeg16)
+		v0 := b.NewValue0(v.Pos, OpDiv16, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst16, t)
+		v1.AuxInt = -c
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div16 <t> x (Const16 [-1<<15]))
+	// cond:
+	// result: (Rsh16Ux64 (And16 <t> x (Neg16 <t> x)) (Const64 <typ.UInt64> [15]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != -1<<15 {
+			break
+		}
+		v.reset(OpRsh16Ux64)
+		v0 := b.NewValue0(v.Pos, OpAnd16, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpNeg16, t)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = 15
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div16 <t> n (Const16 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh16x64     (Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [16-log2(c)])))     (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpRsh16x64)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpRsh16Ux64, t)
+		v2 := b.NewValue0(v.Pos, OpRsh16x64, t)
+		v2.AddArg(n)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 15
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 16 - log2(c)
+		v1.AddArg(v4)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = log2(c)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div16 <t> x (Const16 [c]))
+	// cond: smagicOK(16,c)
+	// result: (Sub16 <t>     (Rsh32x64 <t>       (Mul32 <typ.UInt32>         (Const32 <typ.UInt32> [int64(smagic(16,c).m)])         (SignExt16to32 x))       (Const64 <typ.UInt64> [16+smagic(16,c).s]))     (Rsh32x64 <t>       (SignExt16to32 x)       (Const64 <typ.UInt64> [31])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(16, c)) {
+			break
+		}
+		v.reset(OpSub16)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(smagic(16, c).m)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 16 + smagic(16, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v6 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
+		v6.AddArg(x)
+		v5.AddArg(v6)
+		v7 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v7.AuxInt = 31
+		v5.AddArg(v7)
+		v.AddArg(v5)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv16u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div16u (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(int16(uint16(c)/uint16(d)))])
+	for {
+		_ = v.Args[1]
+		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(uint16(c) / uint16(d)))
+		return true
+	}
+	// match: (Div16u n (Const16 [c]))
+	// cond: isPowerOfTwo(c&0xffff)
+	// result: (Rsh16Ux64 n (Const64 <typ.UInt64> [log2(c&0xffff)]))
+	for {
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xffff)) {
+			break
+		}
+		v.reset(OpRsh16Ux64)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c & 0xffff)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div16u x (Const16 [c]))
+	// cond: umagicOK(16, c) && config.RegSize == 8
+	// result: (Trunc64to16     (Rsh64Ux64 <typ.UInt64>       (Mul64 <typ.UInt64>         (Const64 <typ.UInt64> [int64(1<<16+umagic(16,c).m)])         (ZeroExt16to64 x))       (Const64 <typ.UInt64> [16+umagic(16,c).s])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(16, c) && config.RegSize == 8) {
+			break
+		}
+		v.reset(OpTrunc64to16)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpMul64, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(1<<16 + umagic(16, c).m)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 16 + umagic(16, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div16u x (Const16 [c]))
+	// cond: umagicOK(16, c) && config.RegSize == 4 && umagic(16,c).m&1 == 0
+	// result: (Trunc32to16     (Rsh32Ux64 <typ.UInt32>       (Mul32 <typ.UInt32>         (Const32 <typ.UInt32> [int64(1<<15+umagic(16,c).m/2)])         (ZeroExt16to32 x))       (Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(16, c) && config.RegSize == 4 && umagic(16, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpTrunc32to16)
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(1<<15 + umagic(16, c).m/2)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 16 + umagic(16, c).s - 1
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div16u x (Const16 [c]))
+	// cond: umagicOK(16, c) && config.RegSize == 4 && c&1 == 0
+	// result: (Trunc32to16     (Rsh32Ux64 <typ.UInt32>       (Mul32 <typ.UInt32>         (Const32 <typ.UInt32> [int64(1<<15+(umagic(16,c).m+1)/2)])         (Rsh32Ux64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [1])))       (Const64 <typ.UInt64> [16+umagic(16,c).s-2])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(16, c) && config.RegSize == 4 && c&1 == 0) {
+			break
+		}
+		v.reset(OpTrunc32to16)
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(1<<15 + (umagic(16, c).m+1)/2)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v4 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+		v4.AddArg(x)
+		v3.AddArg(v4)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = 1
+		v3.AddArg(v5)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v6 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v6.AuxInt = 16 + umagic(16, c).s - 2
+		v0.AddArg(v6)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div16u x (Const16 [c]))
+	// cond: umagicOK(16, c) && config.RegSize == 4
+	// result: (Trunc32to16     (Rsh32Ux64 <typ.UInt32>       (Avg32u         (Lsh32x64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [16]))         (Mul32 <typ.UInt32>           (Const32 <typ.UInt32> [int64(umagic(16,c).m)])           (ZeroExt16to32 x)))       (Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(16, c) && config.RegSize == 4) {
+			break
+		}
+		v.reset(OpTrunc32to16)
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpAvg32u, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpLsh32x64, typ.UInt32)
+		v3 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+		v3.AddArg(x)
+		v2.AddArg(v3)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 16
+		v2.AddArg(v4)
+		v1.AddArg(v2)
+		v5 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v6 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v6.AuxInt = int64(umagic(16, c).m)
+		v5.AddArg(v6)
+		v7 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+		v7.AddArg(x)
+		v5.AddArg(v7)
+		v1.AddArg(v5)
+		v0.AddArg(v1)
+		v8 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v8.AuxInt = 16 + umagic(16, c).s - 1
+		v0.AddArg(v8)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div32 (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(int32(c)/int32(d))])
+	for {
+		_ = v.Args[1]
+		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) / int32(d))
+		return true
+	}
+	// match: (Div32 <t> n (Const32 [c]))
+	// cond: c < 0 && c != -1<<31
+	// result: (Neg32 (Div32 <t> n (Const32 <t> [-c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<31) {
+			break
+		}
+		v.reset(OpNeg32)
+		v0 := b.NewValue0(v.Pos, OpDiv32, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst32, t)
+		v1.AuxInt = -c
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div32 <t> x (Const32 [-1<<31]))
+	// cond:
+	// result: (Rsh32Ux64 (And32 <t> x (Neg32 <t> x)) (Const64 <typ.UInt64> [31]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != -1<<31 {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v0 := b.NewValue0(v.Pos, OpAnd32, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpNeg32, t)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = 31
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div32 <t> n (Const32 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh32x64     (Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [32-log2(c)])))     (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpRsh32x64)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpRsh32Ux64, t)
+		v2 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v2.AddArg(n)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 31
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 32 - log2(c)
+		v1.AddArg(v4)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = log2(c)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div32 <t> x (Const32 [c]))
+	// cond: smagicOK(32,c) && config.RegSize == 8
+	// result: (Sub32 <t>     (Rsh64x64 <t>       (Mul64 <typ.UInt64>         (Const64 <typ.UInt64> [int64(smagic(32,c).m)])         (SignExt32to64 x))       (Const64 <typ.UInt64> [32+smagic(32,c).s]))     (Rsh64x64 <t>       (SignExt32to64 x)       (Const64 <typ.UInt64> [63])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(32, c) && config.RegSize == 8) {
+			break
+		}
+		v.reset(OpSub32)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v1 := b.NewValue0(v.Pos, OpMul64, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(smagic(32, c).m)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 32 + smagic(32, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v6 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+		v6.AddArg(x)
+		v5.AddArg(v6)
+		v7 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v7.AuxInt = 63
+		v5.AddArg(v7)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div32 <t> x (Const32 [c]))
+	// cond: smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 == 0
+	// result: (Sub32 <t>     (Rsh32x64 <t>       (Hmul32 <t>         (Const32 <typ.UInt32> [int64(int32(smagic(32,c).m/2))])         x)       (Const64 <typ.UInt64> [smagic(32,c).s-1]))     (Rsh32x64 <t>       x       (Const64 <typ.UInt64> [31])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(32, c) && config.RegSize == 4 && smagic(32, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpSub32)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v1 := b.NewValue0(v.Pos, OpHmul32, t)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(int32(smagic(32, c).m / 2))
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = smagic(32, c).s - 1
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v4.AddArg(x)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = 31
+		v4.AddArg(v5)
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Div32 <t> x (Const32 [c]))
+	// cond: smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 != 0
+	// result: (Sub32 <t>     (Rsh32x64 <t>       (Add32 <t>         (Hmul32 <t>           (Const32 <typ.UInt32> [int64(int32(smagic(32,c).m))])           x)         x)       (Const64 <typ.UInt64> [smagic(32,c).s]))     (Rsh32x64 <t>       x       (Const64 <typ.UInt64> [31])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(32, c) && config.RegSize == 4 && smagic(32, c).m&1 != 0) {
+			break
+		}
+		v.reset(OpSub32)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v1 := b.NewValue0(v.Pos, OpAdd32, t)
+		v2 := b.NewValue0(v.Pos, OpHmul32, t)
+		v3 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v3.AuxInt = int64(int32(smagic(32, c).m))
+		v2.AddArg(v3)
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = smagic(32, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v5.AddArg(x)
+		v6 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v6.AuxInt = 31
+		v5.AddArg(v6)
+		v.AddArg(v5)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv32F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Div32F (Const32F [c]) (Const32F [d]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) / i2f32(d)))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Div32F x (Const32F <t> [c]))
+	// cond: reciprocalExact32(float32(i2f(c)))
+	// result: (Mul32F x (Const32F <t> [f2i(1/i2f(c))]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(reciprocalExact32(float32(i2f(c)))) {
+			break
+		}
+		v.reset(OpMul32F)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst32F, t)
+		v0.AuxInt = f2i(1 / i2f(c))
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv32u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div32u (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(int32(uint32(c)/uint32(d)))])
+	for {
+		_ = v.Args[1]
+		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(uint32(c) / uint32(d)))
+		return true
+	}
+	// match: (Div32u n (Const32 [c]))
+	// cond: isPowerOfTwo(c&0xffffffff)
+	// result: (Rsh32Ux64 n (Const64 <typ.UInt64> [log2(c&0xffffffff)]))
+	for {
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xffffffff)) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c & 0xffffffff)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 4 && umagic(32,c).m&1 == 0
+	// result: (Rsh32Ux64 <typ.UInt32>     (Hmul32u <typ.UInt32>       (Const32 <typ.UInt32> [int64(int32(1<<31+umagic(32,c).m/2))])       x)     (Const64 <typ.UInt64> [umagic(32,c).s-1]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 4 && umagic(32, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpHmul32u, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v1.AuxInt = int64(int32(1<<31 + umagic(32, c).m/2))
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = umagic(32, c).s - 1
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 4 && c&1 == 0
+	// result: (Rsh32Ux64 <typ.UInt32>     (Hmul32u <typ.UInt32>       (Const32 <typ.UInt32> [int64(int32(1<<31+(umagic(32,c).m+1)/2))])       (Rsh32Ux64 <typ.UInt32> x (Const64 <typ.UInt64> [1])))     (Const64 <typ.UInt64> [umagic(32,c).s-2]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 4 && c&1 == 0) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpHmul32u, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v1.AuxInt = int64(int32(1<<31 + (umagic(32, c).m+1)/2))
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v2.AddArg(x)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 1
+		v2.AddArg(v3)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = umagic(32, c).s - 2
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 4
+	// result: (Rsh32Ux64 <typ.UInt32>     (Avg32u       x       (Hmul32u <typ.UInt32>         (Const32 <typ.UInt32> [int64(int32(umagic(32,c).m))])         x))     (Const64 <typ.UInt64> [umagic(32,c).s-1]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 4) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.Type = typ.UInt32
+		v0 := b.NewValue0(v.Pos, OpAvg32u, typ.UInt32)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpHmul32u, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(int32(umagic(32, c).m))
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = umagic(32, c).s - 1
+		v.AddArg(v3)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 8 && umagic(32,c).m&1 == 0
+	// result: (Trunc64to32     (Rsh64Ux64 <typ.UInt64>       (Mul64 <typ.UInt64>         (Const64 <typ.UInt64> [int64(1<<31+umagic(32,c).m/2)])         (ZeroExt32to64 x))       (Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 8 && umagic(32, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpTrunc64to32)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpMul64, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(1<<31 + umagic(32, c).m/2)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 32 + umagic(32, c).s - 1
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 8 && c&1 == 0
+	// result: (Trunc64to32     (Rsh64Ux64 <typ.UInt64>       (Mul64 <typ.UInt64>         (Const64 <typ.UInt64> [int64(1<<31+(umagic(32,c).m+1)/2)])         (Rsh64Ux64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [1])))       (Const64 <typ.UInt64> [32+umagic(32,c).s-2])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 8 && c&1 == 0) {
+			break
+		}
+		v.reset(OpTrunc64to32)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpMul64, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(1<<31 + (umagic(32, c).m+1)/2)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v4 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
+		v4.AddArg(x)
+		v3.AddArg(v4)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = 1
+		v3.AddArg(v5)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v6 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v6.AuxInt = 32 + umagic(32, c).s - 2
+		v0.AddArg(v6)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div32u x (Const32 [c]))
+	// cond: umagicOK(32, c) && config.RegSize == 8
+	// result: (Trunc64to32     (Rsh64Ux64 <typ.UInt64>       (Avg64u         (Lsh64x64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [32]))         (Mul64 <typ.UInt64>           (Const64 <typ.UInt32> [int64(umagic(32,c).m)])           (ZeroExt32to64 x)))       (Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(32, c) && config.RegSize == 8) {
+			break
+		}
+		v.reset(OpTrunc64to32)
+		v0 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpAvg64u, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpLsh64x64, typ.UInt64)
+		v3 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
+		v3.AddArg(x)
+		v2.AddArg(v3)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 32
+		v2.AddArg(v4)
+		v1.AddArg(v2)
+		v5 := b.NewValue0(v.Pos, OpMul64, typ.UInt64)
+		v6 := b.NewValue0(v.Pos, OpConst64, typ.UInt32)
+		v6.AuxInt = int64(umagic(32, c).m)
+		v5.AddArg(v6)
+		v7 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
+		v7.AddArg(x)
+		v5.AddArg(v7)
+		v1.AddArg(v5)
+		v0.AddArg(v1)
+		v8 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v8.AuxInt = 32 + umagic(32, c).s - 1
+		v0.AddArg(v8)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div64 (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [c/d])
+	for {
+		_ = v.Args[1]
+		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: (Div64 <t> n (Const64 [c]))
+	// cond: c < 0 && c != -1<<63
+	// result: (Neg64 (Div64 <t> n (Const64 <t> [-c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<63) {
+			break
+		}
+		v.reset(OpNeg64)
+		v0 := b.NewValue0(v.Pos, OpDiv64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, t)
+		v1.AuxInt = -c
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [-1<<63]))
+	// cond:
+	// result: (Rsh64Ux64 (And64 <t> x (Neg64 <t> x)) (Const64 <typ.UInt64> [63]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != -1<<63 {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Pos, OpAnd64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpNeg64, t)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = 63
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div64 <t> n (Const64 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh64x64     (Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [64-log2(c)])))     (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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(OpRsh64x64)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpRsh64Ux64, t)
+		v2 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v2.AddArg(n)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 63
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 64 - log2(c)
+		v1.AddArg(v4)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = log2(c)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: smagicOK(64,c) && smagic(64,c).m&1 == 0
+	// result: (Sub64 <t>     (Rsh64x64 <t>       (Hmul64 <t>         (Const64 <typ.UInt64> [int64(smagic(64,c).m/2)])         x)       (Const64 <typ.UInt64> [smagic(64,c).s-1]))     (Rsh64x64 <t>       x       (Const64 <typ.UInt64> [63])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(64, c) && smagic(64, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpSub64)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v1 := b.NewValue0(v.Pos, OpHmul64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(smagic(64, c).m / 2)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = smagic(64, c).s - 1
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v4.AddArg(x)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = 63
+		v4.AddArg(v5)
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: smagicOK(64,c) && smagic(64,c).m&1 != 0
+	// result: (Sub64 <t>     (Rsh64x64 <t>       (Add64 <t>         (Hmul64 <t>           (Const64 <typ.UInt64> [int64(smagic(64,c).m)])           x)         x)       (Const64 <typ.UInt64> [smagic(64,c).s]))     (Rsh64x64 <t>       x       (Const64 <typ.UInt64> [63])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(64, c) && smagic(64, c).m&1 != 0) {
+			break
+		}
+		v.reset(OpSub64)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v1 := b.NewValue0(v.Pos, OpAdd64, t)
+		v2 := b.NewValue0(v.Pos, OpHmul64, t)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = int64(smagic(64, c).m)
+		v2.AddArg(v3)
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = smagic(64, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpRsh64x64, t)
+		v5.AddArg(x)
+		v6 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v6.AuxInt = 63
+		v5.AddArg(v6)
+		v.AddArg(v5)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv64F_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) / i2f(d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Div64F x (Const64F <t> [c]))
+	// cond: reciprocalExact64(i2f(c))
+	// result: (Mul64F x (Const64F <t> [f2i(1/i2f(c))]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(reciprocalExact64(i2f(c))) {
+			break
+		}
+		v.reset(OpMul64F)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64F, t)
+		v0.AuxInt = f2i(1 / i2f(c))
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv64u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div64u (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [int64(uint64(c)/uint64(d))])
+	for {
+		_ = v.Args[1]
+		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: (Div64u n (Const64 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh64Ux64 n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		_ = v.Args[1]
+		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.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div64u x (Const64 [c]))
+	// cond: umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0
+	// result: (Rsh64Ux64 <typ.UInt64>     (Hmul64u <typ.UInt64>       (Const64 <typ.UInt64> [int64(1<<63+umagic(64,c).m/2)])       x)     (Const64 <typ.UInt64> [umagic(64,c).s-1]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(64, c) && config.RegSize == 8 && umagic(64, c).m&1 == 0) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.Type = typ.UInt64
+		v0 := b.NewValue0(v.Pos, OpHmul64u, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = int64(1<<63 + umagic(64, c).m/2)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = umagic(64, c).s - 1
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div64u x (Const64 [c]))
+	// cond: umagicOK(64, c) && config.RegSize == 8 && c&1 == 0
+	// result: (Rsh64Ux64 <typ.UInt64>     (Hmul64u <typ.UInt64>       (Const64 <typ.UInt64> [int64(1<<63+(umagic(64,c).m+1)/2)])       (Rsh64Ux64 <typ.UInt64> x (Const64 <typ.UInt64> [1])))     (Const64 <typ.UInt64> [umagic(64,c).s-2]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(64, c) && config.RegSize == 8 && c&1 == 0) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.Type = typ.UInt64
+		v0 := b.NewValue0(v.Pos, OpHmul64u, typ.UInt64)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = int64(1<<63 + (umagic(64, c).m+1)/2)
+		v0.AddArg(v1)
+		v2 := b.NewValue0(v.Pos, OpRsh64Ux64, typ.UInt64)
+		v2.AddArg(x)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 1
+		v2.AddArg(v3)
+		v0.AddArg(v2)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = umagic(64, c).s - 2
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Div64u x (Const64 [c]))
+	// cond: umagicOK(64, c) && config.RegSize == 8
+	// result: (Rsh64Ux64 <typ.UInt64>     (Avg64u       x       (Hmul64u <typ.UInt64>         (Const64 <typ.UInt64> [int64(umagic(64,c).m)])         x))     (Const64 <typ.UInt64> [umagic(64,c).s-1]))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(64, c) && config.RegSize == 8) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.Type = typ.UInt64
+		v0 := b.NewValue0(v.Pos, OpAvg64u, typ.UInt64)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpHmul64u, typ.UInt64)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = int64(umagic(64, c).m)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = umagic(64, c).s - 1
+		v.AddArg(v3)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8 (Const8 [c]) (Const8 [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(int8(c)/int8(d))])
+	for {
+		_ = v.Args[1]
+		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) / int8(d))
+		return true
+	}
+	// match: (Div8 <t> n (Const8 [c]))
+	// cond: c < 0 && c != -1<<7
+	// result: (Neg8  (Div8  <t> n (Const8  <t> [-c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<7) {
+			break
+		}
+		v.reset(OpNeg8)
+		v0 := b.NewValue0(v.Pos, OpDiv8, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst8, t)
+		v1.AuxInt = -c
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div8 <t> x (Const8 [-1<<7 ]))
+	// cond:
+	// result: (Rsh8Ux64  (And8  <t> x (Neg8  <t> x)) (Const64 <typ.UInt64> [7 ]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != -1<<7 {
+			break
+		}
+		v.reset(OpRsh8Ux64)
+		v0 := b.NewValue0(v.Pos, OpAnd8, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Pos, OpNeg8, t)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v2.AuxInt = 7
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div8 <t> n (Const8 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh8x64     (Add8  <t> n (Rsh8Ux64  <t> (Rsh8x64  <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [ 8-log2(c)])))     (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpRsh8x64)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpRsh8Ux64, t)
+		v2 := b.NewValue0(v.Pos, OpRsh8x64, t)
+		v2.AddArg(n)
+		v3 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v3.AuxInt = 7
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 8 - log2(c)
+		v1.AddArg(v4)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v5.AuxInt = log2(c)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div8 <t> x (Const8 [c]))
+	// cond: smagicOK(8,c)
+	// result: (Sub8 <t>     (Rsh32x64 <t>       (Mul32 <typ.UInt32>         (Const32 <typ.UInt32> [int64(smagic(8,c).m)])         (SignExt8to32 x))       (Const64 <typ.UInt64> [8+smagic(8,c).s]))     (Rsh32x64 <t>       (SignExt8to32 x)       (Const64 <typ.UInt64> [31])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(smagicOK(8, c)) {
+			break
+		}
+		v.reset(OpSub8)
+		v.Type = t
+		v0 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(smagic(8, c).m)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 8 + smagic(8, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Pos, OpRsh32x64, t)
+		v6 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
+		v6.AddArg(x)
+		v5.AddArg(v6)
+		v7 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v7.AuxInt = 31
+		v5.AddArg(v7)
+		v.AddArg(v5)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv8u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Div8u (Const8 [c]) (Const8 [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(int8(uint8(c)/uint8(d)))])
+	for {
+		_ = v.Args[1]
+		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(uint8(c) / uint8(d)))
+		return true
+	}
+	// match: (Div8u n (Const8 [c]))
+	// cond: isPowerOfTwo(c&0xff)
+	// result: (Rsh8Ux64 n  (Const64 <typ.UInt64> [log2(c&0xff)]))
+	for {
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xff)) {
+			break
+		}
+		v.reset(OpRsh8Ux64)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c & 0xff)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div8u x (Const8 [c]))
+	// cond: umagicOK(8, c)
+	// result: (Trunc32to8     (Rsh32Ux64 <typ.UInt32>       (Mul32 <typ.UInt32>         (Const32 <typ.UInt32> [int64(1<<8+umagic(8,c).m)])         (ZeroExt8to32 x))       (Const64 <typ.UInt64> [8+umagic(8,c).s])))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagicOK(8, c)) {
+			break
+		}
+		v.reset(OpTrunc32to8)
+		v0 := b.NewValue0(v.Pos, OpRsh32Ux64, typ.UInt32)
+		v1 := b.NewValue0(v.Pos, OpMul32, typ.UInt32)
+		v2 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+		v2.AuxInt = int64(1<<8 + umagic(8, c).m)
+		v1.AddArg(v2)
+		v3 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
+		v3.AddArg(x)
+		v1.AddArg(v3)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v4.AuxInt = 8 + umagic(8, c).s
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq16 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 (Const16 <t> [c]) (Add16 x (Const16 <t> [d])))
+	// cond:
+	// result: (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpEq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 (Add16 (Const16 <t> [d]) x) (Const16 <t> [c]))
+	// cond:
+	// result: (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 (Add16 x (Const16 <t> [d])) (Const16 <t> [c]))
+	// cond:
+	// result: (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Eq16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 (Const32 <t> [c]) (Add32 x (Const32 <t> [d])))
+	// cond:
+	// result: (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpEq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 (Add32 (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 (Add32 x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Eq32 (Const32 [d]) (Const32 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 (Const64 <t> [c]) (Add64 x (Const64 <t> [d])))
+	// cond:
+	// result: (Eq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpEq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 (Add64 (Const64 <t> [d]) x) (Const64 <t> [c]))
+	// cond:
+	// result: (Eq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 (Add64 x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Eq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Eq64 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq8 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8 (Const8 <t> [c]) (Add8 x (Const8 <t> [d])))
+	// cond:
+	// result: (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpEq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8 (Add8 (Const8 <t> [d]) x) (Const8 <t> [c]))
+	// cond:
+	// result: (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8 (Add8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpEq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Eq8 (Const8 [d]) (Const8 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqB_0(v *Value) bool {
+	// match: (EqB (ConstBool [c]) (ConstBool [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		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 [d]) (ConstBool [c]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	// match: (EqB (ConstBool [0]) x)
+	// cond:
+	// result: (Not x)
+	for {
+		_ = v.Args[1]
+		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 x (ConstBool [0]))
+	// cond:
+	// result: (Not x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpNot)
+		v.AddArg(x)
+		return true
+	}
+	// match: (EqB (ConstBool [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (EqB x (ConstBool [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqInter_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (EqInter x y)
+	// cond:
+	// result: (EqPtr  (ITab x) (ITab y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpEqPtr)
+		v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpEqPtr_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (EqPtr p (ConstNil))
+	// cond:
+	// result: (Not (IsNonNil p))
+	for {
+		_ = v.Args[1]
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstNil {
+			break
+		}
+		v.reset(OpNot)
+		v0 := b.NewValue0(v.Pos, OpIsNonNil, typ.Bool)
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (EqPtr (ConstNil) p)
+	// cond:
+	// result: (Not (IsNonNil p))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstNil {
+			break
+		}
+		p := v.Args[1]
+		v.reset(OpNot)
+		v0 := b.NewValue0(v.Pos, OpIsNonNil, typ.Bool)
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (EqPtr x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (EqPtr (Addr {a} x) (Addr {b} x))
+	// cond:
+	// result: (ConstBool [b2i(a == b)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAddr {
+			break
+		}
+		a := v_0.Aux
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAddr {
+			break
+		}
+		b := v_1.Aux
+		if x != v_1.Args[0] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(a == b)
+		return true
+	}
+	// match: (EqPtr (Addr {b} x) (Addr {a} x))
+	// cond:
+	// result: (ConstBool [b2i(a == b)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAddr {
+			break
+		}
+		b := v_0.Aux
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAddr {
+			break
+		}
+		a := v_1.Aux
+		if x != v_1.Args[0] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(a == b)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqSlice_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (EqSlice x y)
+	// cond:
+	// result: (EqPtr  (SlicePtr x) (SlicePtr y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpEqPtr)
+		v0 := b.NewValue0(v.Pos, OpSlicePtr, typ.BytePtr)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpSlicePtr, typ.BytePtr)
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpGeq16_0(v *Value) bool {
+	// match: (Geq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) >= uint16(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) >= uint32(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) >= uint64(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Geq8U (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  >= uint8(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) > uint16(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) > uint32(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) > uint64(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Greater8U (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  > uint8(d))])
+	for {
+		_ = v.Args[1]
+		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_OpIMake_0(v *Value) bool {
+	// match: (IMake typ (StructMake1 val))
+	// cond:
+	// result: (IMake typ val)
+	for {
+		_ = v.Args[1]
+		typ := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake1 {
+			break
+		}
+		val := v_1.Args[0]
+		v.reset(OpIMake)
+		v.AddArg(typ)
+		v.AddArg(val)
+		return true
+	}
+	// match: (IMake typ (ArrayMake1 val))
+	// cond:
+	// result: (IMake typ val)
+	for {
+		_ = v.Args[1]
+		typ := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpArrayMake1 {
+			break
+		}
+		val := v_1.Args[0]
+		v.reset(OpIMake)
+		v.AddArg(typ)
+		v.AddArg(val)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpInterCall_0(v *Value) bool {
+	// match: (InterCall [argsize] (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) mem)
+	// cond: devirt(v, itab, off) != nil
+	// result: (StaticCall [argsize] {devirt(v, itab, off)} mem)
+	for {
+		argsize := v.AuxInt
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLoad {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpOffPtr {
+			break
+		}
+		off := v_0_0.AuxInt
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpITab {
+			break
+		}
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpIMake {
+			break
+		}
+		_ = v_0_0_0_0.Args[1]
+		v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+		if v_0_0_0_0_0.Op != OpAddr {
+			break
+		}
+		itab := v_0_0_0_0_0.Aux
+		v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+		if v_0_0_0_0_0_0.Op != OpSB {
+			break
+		}
+		mem := v.Args[1]
+		if !(devirt(v, itab, off) != nil) {
+			break
+		}
+		v.reset(OpStaticCall)
+		v.AuxInt = argsize
+		v.Aux = devirt(v, itab, off)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsInBounds_0(v *Value) bool {
+	// match: (IsInBounds (ZeroExt8to32 _) (Const32 [c]))
+	// cond: (1 << 8)  <= c
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (IsInBounds (And8 (Const8 [c]) _) (Const8 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (And8 _ (Const8 [c])) (Const8 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt8to16 (And8 (Const8 [c]) _)) (Const16 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to16 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst8 {
+			break
+		}
+		c := v_0_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt8to16 (And8 _ (Const8 [c]))) (Const16 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to16 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst8 {
+			break
+		}
+		c := v_0_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt8to32 (And8 (Const8 [c]) _)) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst8 {
+			break
+		}
+		c := v_0_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
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsInBounds_10(v *Value) bool {
+	// match: (IsInBounds (ZeroExt8to32 (And8 _ (Const8 [c]))) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst8 {
+			break
+		}
+		c := v_0_0_1.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 (ZeroExt8to64 (And8 (Const8 [c]) _)) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst8 {
+			break
+		}
+		c := v_0_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 (ZeroExt8to64 (And8 _ (Const8 [c]))) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst8 {
+			break
+		}
+		c := v_0_0_1.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 (And16 (Const16 [c]) _) (Const16 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (And16 _ (Const16 [c])) (Const16 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt16to32 (And16 (Const16 [c]) _)) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst16 {
+			break
+		}
+		c := v_0_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 (ZeroExt16to32 (And16 _ (Const16 [c]))) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst16 {
+			break
+		}
+		c := v_0_0_1.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 (ZeroExt16to64 (And16 (Const16 [c]) _)) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst16 {
+			break
+		}
+		c := v_0_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 (ZeroExt16to64 (And16 _ (Const16 [c]))) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst16 {
+			break
+		}
+		c := v_0_0_1.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 (And32 (Const32 [c]) _) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		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
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsInBounds_20(v *Value) bool {
+	// match: (IsInBounds (And32 _ (Const32 [c])) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		c := v_0_1.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 (ZeroExt32to64 (And32 (Const32 [c]) _)) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt32to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpConst32 {
+			break
+		}
+		c := v_0_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 (ZeroExt32to64 (And32 _ (Const32 [c]))) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt32to64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst32 {
+			break
+		}
+		c := v_0_0_1.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 (And64 (Const64 [c]) _) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 (And64 _ (Const64 [c])) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 !(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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMod32u {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMod64u {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsNonNil_0(v *Value) bool {
+	// match: (IsNonNil (ConstNil))
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstNil {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsSliceInBounds_0(v *Value) bool {
+	// match: (IsSliceInBounds x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 (And32 _ (Const32 [c])) (Const32 [d]))
+	// cond: 0 <= c && c <= d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		c := v_0_1.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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 (And64 _ (Const64 [c])) (Const64 [d]))
+	// cond: 0 <= c && c <= d
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 !(0 <= c && c <= d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (Const32 [0]) _)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) <= uint16(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) <= uint32(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) <= uint64(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Leq8U (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  <= uint8(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) < uint16(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) < uint32(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) < uint64(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	// match: (Less8U (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  < uint8(d))])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	fe := b.Func.fe
+	_ = fe
+	// match: (Load <t1> p1 (Store {t2} p2 x _))
+	// cond: isSamePtr(p1,p2) && t1.Compare(x.Type) == types.CMPeq && t1.Size() == t2.(*types.Type).Size()
+	// result: x
+	for {
+		t1 := v.Type
+		_ = v.Args[1]
+		p1 := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStore {
+			break
+		}
+		t2 := v_1.Aux
+		_ = v_1.Args[2]
+		p2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(isSamePtr(p1, p2) && t1.Compare(x.Type) == types.CMPeq && t1.Size() == t2.(*types.Type).Size()) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Load <t> _ _)
+	// cond: t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t)
+	// result: (StructMake0)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 0 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake0)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 1 && fe.CanSSA(t)
+	// result: (StructMake1     (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 1 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake1)
+		v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0))
+		v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v1.AuxInt = 0
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 2 && fe.CanSSA(t)
+	// result: (StructMake2     (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0]             ptr) mem)     (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 2 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake2)
+		v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0))
+		v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v1.AuxInt = 0
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1))
+		v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v3.AuxInt = t.FieldOff(1)
+		v3.AddArg(ptr)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 3 && fe.CanSSA(t)
+	// result: (StructMake3     (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 3 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake3)
+		v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0))
+		v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v1.AuxInt = 0
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1))
+		v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v3.AuxInt = t.FieldOff(1)
+		v3.AddArg(ptr)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpLoad, t.FieldType(2))
+		v5 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo())
+		v5.AuxInt = t.FieldOff(2)
+		v5.AddArg(ptr)
+		v4.AddArg(v5)
+		v4.AddArg(mem)
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 4 && fe.CanSSA(t)
+	// result: (StructMake4     (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 4 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake4)
+		v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0))
+		v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v1.AuxInt = 0
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1))
+		v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v3.AuxInt = t.FieldOff(1)
+		v3.AddArg(ptr)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		v4 := b.NewValue0(v.Pos, OpLoad, t.FieldType(2))
+		v5 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo())
+		v5.AuxInt = t.FieldOff(2)
+		v5.AddArg(ptr)
+		v4.AddArg(v5)
+		v4.AddArg(mem)
+		v.AddArg(v4)
+		v6 := b.NewValue0(v.Pos, OpLoad, t.FieldType(3))
+		v7 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(3).PtrTo())
+		v7.AuxInt = t.FieldOff(3)
+		v7.AddArg(ptr)
+		v6.AddArg(v7)
+		v6.AddArg(mem)
+		v.AddArg(v6)
+		return true
+	}
+	// match: (Load <t> _ _)
+	// cond: t.IsArray() && t.NumElem() == 0
+	// result: (ArrayMake0)
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		if !(t.IsArray() && t.NumElem() == 0) {
+			break
+		}
+		v.reset(OpArrayMake0)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t)
+	// result: (ArrayMake1 (Load <t.ElemType()> ptr mem))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsArray() && t.NumElem() == 1 && fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpArrayMake1)
+		v0 := b.NewValue0(v.Pos, OpLoad, t.ElemType())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x32 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh16x64 (Const16 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c) << uint64(d))])
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh16x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Pos, 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 <typ.UInt64> [c1-c2+c3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh16Ux64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh16x64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x8 <t> x (Const8 [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x8 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x16 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x32 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh32x64 (Const32 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c) << uint64(d))])
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh32x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Pos, 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 <typ.UInt64> [c1-c2+c3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh32Ux64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh32x64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh32x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x8 <t> x (Const8 [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x8 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x16 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x32 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh64x64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c << uint64(d)])
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Pos, 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 <typ.UInt64> [c1-c2+c3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh64Ux64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh64x64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh64x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x8 <t> x (Const8 [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x8 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x16 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x32 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Lsh8x64 (Const8 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c) << uint64(d))])
+	for {
+		_ = v.Args[1]
+		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 {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh8x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Pos, 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 <typ.UInt64> [c1-c2+c3]))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh8Ux64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh8x64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh8x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x8 <t> x (Const8 [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x8 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16 (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(int16(c % d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod16 <t> n (Const16 [c]))
+	// cond: c < 0 && c != -1<<15
+	// result: (Mod16 <t> n (Const16 <t> [-c]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<15) {
+			break
+		}
+		v.reset(OpMod16)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = -c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod16 <t> x (Const16 [c]))
+	// cond: x.Op != OpConst16 && (c > 0 || c == -1<<15)
+	// result: (Sub16 x (Mul16 <t> (Div16  <t> x (Const16 <t> [c])) (Const16 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16 && (c > 0 || c == -1<<15)) {
+			break
+		}
+		v.reset(OpSub16)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul16, t)
+		v1 := b.NewValue0(v.Pos, OpDiv16, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst16, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst16, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod16u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16u (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(uint16(c) % uint16(d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod16u <t> n (Const16 [c]))
+	// cond: isPowerOfTwo(c&0xffff)
+	// result: (And16 n (Const16 <t> [(c&0xffff)-1]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xffff)) {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = (c & 0xffff) - 1
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod16u <t> x (Const16 [c]))
+	// cond: x.Op != OpConst16 && c > 0 && umagicOK(16,c)
+	// result: (Sub16 x (Mul16 <t> (Div16u <t> x (Const16 <t> [c])) (Const16 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16 && c > 0 && umagicOK(16, c)) {
+			break
+		}
+		v.reset(OpSub16)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul16, t)
+		v1 := b.NewValue0(v.Pos, OpDiv16u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst16, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst16, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32 (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(int32(c % d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod32 <t> n (Const32 [c]))
+	// cond: c < 0 && c != -1<<31
+	// result: (Mod32 <t> n (Const32 <t> [-c]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<31) {
+			break
+		}
+		v.reset(OpMod32)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = -c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod32 <t> x (Const32 [c]))
+	// cond: x.Op != OpConst32 && (c > 0 || c == -1<<31)
+	// result: (Sub32 x (Mul32 <t> (Div32  <t> x (Const32 <t> [c])) (Const32 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32 && (c > 0 || c == -1<<31)) {
+			break
+		}
+		v.reset(OpSub32)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul32, t)
+		v1 := b.NewValue0(v.Pos, OpDiv32, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst32, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod32u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32u (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(uint32(c) % uint32(d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod32u <t> n (Const32 [c]))
+	// cond: isPowerOfTwo(c&0xffffffff)
+	// result: (And32 n (Const32 <t> [(c&0xffffffff)-1]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xffffffff)) {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = (c & 0xffffffff) - 1
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod32u <t> x (Const32 [c]))
+	// cond: x.Op != OpConst32 && c > 0 && umagicOK(32,c)
+	// result: (Sub32 x (Mul32 <t> (Div32u <t> x (Const32 <t> [c])) (Const32 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32 && c > 0 && umagicOK(32, c)) {
+			break
+		}
+		v.reset(OpSub32)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul32, t)
+		v1 := b.NewValue0(v.Pos, OpDiv32u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst32, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64 (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [c % d])
+	for {
+		_ = v.Args[1]
+		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> n (Const64 [c]))
+	// cond: c < 0 && c != -1<<63
+	// result: (Mod64 <t> n (Const64 <t> [-c]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<63) {
+			break
+		}
+		v.reset(OpMod64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = -c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod64 <t> x (Const64 [c]))
+	// cond: x.Op != OpConst64 && (c > 0 || c == -1<<63)
+	// result: (Sub64 x (Mul64 <t> (Div64  <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64 && (c > 0 || c == -1<<63)) {
+			break
+		}
+		v.reset(OpSub64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul64, t)
+		v1 := b.NewValue0(v.Pos, OpDiv64, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod64u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64u (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [int64(uint64(c) % uint64(d))])
+	for {
+		_ = v.Args[1]
+		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
+		_ = v.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c - 1
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod64u <t> x (Const64 [c]))
+	// cond: x.Op != OpConst64 && c > 0 && umagicOK(64,c)
+	// result: (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64 && c > 0 && umagicOK(64, c)) {
+			break
+		}
+		v.reset(OpSub64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul64, t)
+		v1 := b.NewValue0(v.Pos, OpDiv64u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst64, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8 (Const8 [c]) (Const8 [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(int8(c % d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod8 <t> n (Const8 [c]))
+	// cond: c < 0 && c != -1<<7
+	// result: (Mod8  <t> n (Const8  <t> [-c]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && c != -1<<7) {
+			break
+		}
+		v.reset(OpMod8)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = -c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod8 <t> x (Const8 [c]))
+	// cond: x.Op != OpConst8  && (c > 0 || c == -1<<7)
+	// result: (Sub8  x (Mul8  <t> (Div8   <t> x (Const8  <t> [c])) (Const8  <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8 && (c > 0 || c == -1<<7)) {
+			break
+		}
+		v.reset(OpSub8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul8, t)
+		v1 := b.NewValue0(v.Pos, OpDiv8, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst8, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst8, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod8u_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8u (Const8 [c]) (Const8 [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(uint8(c) % uint8(d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mod8u <t> n (Const8 [c]))
+	// cond: isPowerOfTwo(c&0xff)
+	// result: (And8 n (Const8 <t> [(c&0xff)-1]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c & 0xff)) {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = (c & 0xff) - 1
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod8u <t> x (Const8 [c]))
+	// cond: x.Op != OpConst8  && c > 0 && umagicOK(8 ,c)
+	// result: (Sub8  x (Mul8  <t> (Div8u  <t> x (Const8  <t> [c])) (Const8  <t> [c])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8 && c > 0 && umagicOK(8, c)) {
+			break
+		}
+		v.reset(OpSub8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpMul8, t)
+		v1 := b.NewValue0(v.Pos, OpDiv8u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Pos, OpConst8, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Pos, OpConst8, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mul16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c*d))])
+	for {
+		_ = v.Args[1]
+		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 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [int64(int16(c*d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c * d))
+		return true
+	}
+	// match: (Mul16 (Const16 [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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: (Mul16 x (Const16 [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 (Const16 [-1]) x)
+	// cond:
+	// result: (Neg16 x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg16)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 x (Const16 [-1]))
+	// cond:
+	// result: (Neg16 x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpNeg16)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 <t> n (Const16 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh16x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul16 <t> (Const16 [c]) n)
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh16x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul16 <t> n (Const16 [c]))
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg16 (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg16)
+		v0 := b.NewValue0(v.Pos, OpLsh16x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul16 <t> (Const16 [c]) n)
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg16 (Lsh16x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg16)
+		v0 := b.NewValue0(v.Pos, OpLsh16x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul16_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
+		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: (Mul16 _ (Const16 [0]))
+	// cond:
+	// result: (Const16 [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Mul16 (Const16 <t> [c]) (Mul16 (Const16 <t> [d]) x))
+	// cond:
+	// result: (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul16 {
+			break
+		}
+		_ = v_1.Args[1]
+		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(OpMul16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 (Const16 <t> [c]) (Mul16 x (Const16 <t> [d])))
+	// cond:
+	// result: (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul16 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpMul16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 (Mul16 (Const16 <t> [d]) x) (Const16 <t> [c]))
+	// cond:
+	// result: (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 (Mul16 x (Const16 <t> [d])) (Const16 <t> [c]))
+	// cond:
+	// result: (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mul32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c*d))])
+	for {
+		_ = v.Args[1]
+		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 (Const32 [d]) (Const32 [c]))
+	// cond:
+	// result: (Const32 [int64(int32(c*d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
+	// match: (Mul32 (Const32 [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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: (Mul32 x (Const32 [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 (Const32 [-1]) x)
+	// cond:
+	// result: (Neg32 x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg32)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 x (Const32 [-1]))
+	// cond:
+	// result: (Neg32 x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpNeg32)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 <t> n (Const32 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh32x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul32 <t> (Const32 [c]) n)
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh32x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul32 <t> n (Const32 [c]))
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg32 (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg32)
+		v0 := b.NewValue0(v.Pos, OpLsh32x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul32 <t> (Const32 [c]) n)
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg32 (Lsh32x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg32)
+		v0 := b.NewValue0(v.Pos, OpLsh32x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul32_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// 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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul32, t)
+		v2 := b.NewValue0(v.Pos, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul32 (Const32 <t> [c]) (Add32 <t> x (Const32 <t> [d])))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul32, t)
+		v2 := b.NewValue0(v.Pos, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul32 (Add32 <t> (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		t := v_0.Type
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		if v_0_0.Type != t {
+			break
+		}
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul32, t)
+		v2 := b.NewValue0(v.Pos, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul32 (Add32 <t> x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		t := v_0.Type
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		if v_0_1.Type != t {
+			break
+		}
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul32, t)
+		v2 := b.NewValue0(v.Pos, 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.Args[1]
+		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: (Mul32 _ (Const32 [0]))
+	// cond:
+	// result: (Const32 [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Mul32 (Const32 <t> [c]) (Mul32 (Const32 <t> [d]) x))
+	// cond:
+	// result: (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul32 {
+			break
+		}
+		_ = v_1.Args[1]
+		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(OpMul32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 (Const32 <t> [c]) (Mul32 x (Const32 <t> [d])))
+	// cond:
+	// result: (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul32 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpMul32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 (Mul32 (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 (Mul32 x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul32F_0(v *Value) bool {
+	// match: (Mul32F (Const32F [c]) (Const32F [d]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mul32F (Const32F [d]) (Const32F [c]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) * i2f32(d)))
+		return true
+	}
+	// match: (Mul32F x (Const32F [f2i(1)]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		if v_1.AuxInt != f2i(1) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32F (Const32F [f2i(1)]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		if v_0.AuxInt != f2i(1) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32F x (Const32F [f2i(-1)]))
+	// cond:
+	// result: (Neg32F x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		if v_1.AuxInt != f2i(-1) {
+			break
+		}
+		v.reset(OpNeg32F)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32F (Const32F [f2i(-1)]) x)
+	// cond:
+	// result: (Neg32F x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		if v_0.AuxInt != f2i(-1) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg32F)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32F x (Const32F [f2i(2)]))
+	// cond:
+	// result: (Add32F x x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		if v_1.AuxInt != f2i(2) {
+			break
+		}
+		v.reset(OpAdd32F)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32F (Const32F [f2i(2)]) x)
+	// cond:
+	// result: (Add32F x x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		if v_0.AuxInt != f2i(2) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpAdd32F)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mul64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c*d])
+	for {
+		_ = v.Args[1]
+		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 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (Const64 [c*d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c * d
+		return true
+	}
+	// match: (Mul64 (Const64 [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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: (Mul64 x (Const64 [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 (Const64 [-1]) x)
+	// cond:
+	// result: (Neg64 x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg64)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 x (Const64 [-1]))
+	// cond:
+	// result: (Neg64 x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpNeg64)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 <t> n (Const64 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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(OpLsh64x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul64 <t> (Const64 [c]) n)
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh64x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul64 <t> n (Const64 [c]))
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg64 (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg64)
+		v0 := b.NewValue0(v.Pos, OpLsh64x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul64 <t> (Const64 [c]) n)
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg64 (Lsh64x64 <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg64)
+		v0 := b.NewValue0(v.Pos, OpLsh64x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul64_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// 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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul64 (Const64 <t> [c]) (Add64 <t> x (Const64 <t> [d])))
+	// cond:
+	// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul64 (Add64 <t> (Const64 <t> [d]) x) (Const64 <t> [c]))
+	// cond:
+	// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		t := v_0.Type
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		if v_0_0.Type != t {
+			break
+		}
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul64, t)
+		v2 := b.NewValue0(v.Pos, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul64 (Add64 <t> x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		t := v_0.Type
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.Type != t {
+			break
+		}
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpMul64, t)
+		v2 := b.NewValue0(v.Pos, 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.Args[1]
+		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: (Mul64 _ (Const64 [0]))
+	// cond:
+	// result: (Const64 [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Mul64 (Const64 <t> [c]) (Mul64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (Mul64 (Const64 <t> [c*d]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul64 {
+			break
+		}
+		_ = v_1.Args[1]
+		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(OpMul64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 (Const64 <t> [c]) (Mul64 x (Const64 <t> [d])))
+	// cond:
+	// result: (Mul64 (Const64 <t> [c*d]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul64 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpMul64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 (Mul64 (Const64 <t> [d]) x) (Const64 <t> [c]))
+	// cond:
+	// result: (Mul64 (Const64 <t> [c*d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 (Mul64 x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Mul64 (Const64 <t> [c*d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul64F_0(v *Value) bool {
+	// match: (Mul64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) * i2f(d))])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Mul64F (Const64F [d]) (Const64F [c]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) * i2f(d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) * i2f(d))
+		return true
+	}
+	// match: (Mul64F x (Const64F [f2i(1)]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		if v_1.AuxInt != f2i(1) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64F (Const64F [f2i(1)]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		if v_0.AuxInt != f2i(1) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64F x (Const64F [f2i(-1)]))
+	// cond:
+	// result: (Neg64F x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		if v_1.AuxInt != f2i(-1) {
+			break
+		}
+		v.reset(OpNeg64F)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64F (Const64F [f2i(-1)]) x)
+	// cond:
+	// result: (Neg64F x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		if v_0.AuxInt != f2i(-1) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg64F)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64F x (Const64F [f2i(2)]))
+	// cond:
+	// result: (Add64F x x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		if v_1.AuxInt != f2i(2) {
+			break
+		}
+		v.reset(OpAdd64F)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64F (Const64F [f2i(2)]) x)
+	// cond:
+	// result: (Add64F x x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		if v_0.AuxInt != f2i(2) {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpAdd64F)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Mul8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c*d))])
+	for {
+		_ = v.Args[1]
+		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 (Const8 [d]) (Const8 [c]))
+	// cond:
+	// result: (Const8  [int64(int8(c*d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c * d))
+		return true
+	}
+	// match: (Mul8 (Const8 [1]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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: (Mul8 x (Const8 [1]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 (Const8 [-1]) x)
+	// cond:
+	// result: (Neg8  x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNeg8)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 x (Const8 [-1]))
+	// cond:
+	// result: (Neg8  x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpNeg8)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 <t> n (Const8 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh8x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul8 <t> (Const8 [c]) n)
+	// cond: isPowerOfTwo(c)
+	// result: (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(c)]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpLsh8x64)
+		v.Type = t
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul8 <t> n (Const8 [c]))
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg8  (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg8)
+		v0 := b.NewValue0(v.Pos, OpLsh8x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mul8 <t> (Const8 [c]) n)
+	// cond: t.IsSigned() && isPowerOfTwo(-c)
+	// result: (Neg8  (Lsh8x64  <t> n (Const64 <typ.UInt64> [log2(-c)])))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.Args[1]
+		if !(t.IsSigned() && isPowerOfTwo(-c)) {
+			break
+		}
+		v.reset(OpNeg8)
+		v0 := b.NewValue0(v.Pos, OpLsh8x64, t)
+		v0.AddArg(n)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v1.AuxInt = log2(-c)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul8_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul8 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		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: (Mul8 _ (Const8 [0]))
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Mul8 (Const8 <t> [c]) (Mul8 (Const8 <t> [d]) x))
+	// cond:
+	// result: (Mul8  (Const8  <t> [int64(int8(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul8 {
+			break
+		}
+		_ = v_1.Args[1]
+		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(OpMul8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 (Const8 <t> [c]) (Mul8 x (Const8 <t> [d])))
+	// cond:
+	// result: (Mul8  (Const8  <t> [int64(int8(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpMul8 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpMul8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 (Mul8 (Const8 <t> [d]) x) (Const8 <t> [c]))
+	// cond:
+	// result: (Mul8  (Const8  <t> [int64(int8(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul8 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8 (Mul8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (Mul8  (Const8  <t> [int64(int8(c*d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpMul8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpMul8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c * d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg16_0(v *Value) bool {
+	// match: (Neg16 (Const16 [c]))
+	// cond:
+	// result: (Const16  [int64(-int16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(-int16(c))
+		return true
+	}
+	// match: (Neg16 (Sub16 x y))
+	// cond:
+	// result: (Sub16 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub16 {
+			break
+		}
+		_ = v_0.Args[1]
+		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_0(v *Value) bool {
+	// match: (Neg32 (Const32 [c]))
+	// cond:
+	// result: (Const32  [int64(-int32(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(-int32(c))
+		return true
+	}
+	// match: (Neg32 (Sub32 x y))
+	// cond:
+	// result: (Sub32 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub32 {
+			break
+		}
+		_ = v_0.Args[1]
+		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_OpNeg32F_0(v *Value) bool {
+	// match: (Neg32F (Const32F [c]))
+	// cond: i2f(c) != 0
+	// result: (Const32F [f2i(-i2f(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		c := v_0.AuxInt
+		if !(i2f(c) != 0) {
+			break
+		}
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(-i2f(c))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg64_0(v *Value) bool {
+	// match: (Neg64 (Const64 [c]))
+	// cond:
+	// result: (Const64  [-c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = -c
+		return true
+	}
+	// match: (Neg64 (Sub64 x y))
+	// cond:
+	// result: (Sub64 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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_OpNeg64F_0(v *Value) bool {
+	// match: (Neg64F (Const64F [c]))
+	// cond: i2f(c) != 0
+	// result: (Const64F [f2i(-i2f(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		c := v_0.AuxInt
+		if !(i2f(c) != 0) {
+			break
+		}
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(-i2f(c))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg8_0(v *Value) bool {
+	// match: (Neg8 (Const8 [c]))
+	// cond:
+	// result: (Const8   [int64( -int8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(-int8(c))
+		return true
+	}
+	// match: (Neg8 (Sub8 x y))
+	// cond:
+	// result: (Sub8  y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub8 {
+			break
+		}
+		_ = v_0.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq16 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 (Const16 <t> [c]) (Add16 x (Const16 <t> [d])))
+	// cond:
+	// result: (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpNeq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 (Add16 (Const16 <t> [d]) x) (Const16 <t> [c]))
+	// cond:
+	// result: (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 (Add16 x (Const16 <t> [d])) (Const16 <t> [c]))
+	// cond:
+	// result: (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Neq16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 (Const32 <t> [c]) (Add32 x (Const32 <t> [d])))
+	// cond:
+	// result: (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpNeq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 (Add32 (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 (Add32 x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Neq32 (Const32 [d]) (Const32 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 (Const64 <t> [c]) (Add64 x (Const64 <t> [d])))
+	// cond:
+	// result: (Neq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpNeq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 (Add64 (Const64 <t> [d]) x) (Const64 <t> [c]))
+	// cond:
+	// result: (Neq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 (Add64 x (Const64 <t> [d])) (Const64 <t> [c]))
+	// cond:
+	// result: (Neq64 (Const64 <t> [c-d]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Neq64 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq8 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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.Args[1]
+		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.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8 (Const8 <t> [c]) (Add8 x (Const8 <t> [d])))
+	// cond:
+	// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpNeq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8 (Add8 (Const8 <t> [d]) x) (Const8 <t> [c]))
+	// cond:
+	// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8 (Add8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpNeq8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (Neq8 (Const8 [d]) (Const8 [c]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeqB_0(v *Value) bool {
+	// match: (NeqB (ConstBool [c]) (ConstBool [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		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 [d]) (ConstBool [c]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	// match: (NeqB (ConstBool [0]) x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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 x (ConstBool [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (NeqB (ConstBool [1]) x)
+	// cond:
+	// result: (Not x)
+	for {
+		_ = v.Args[1]
+		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
+	}
+	// match: (NeqB x (ConstBool [1]))
+	// cond:
+	// result: (Not x)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		v.reset(OpNot)
+		v.AddArg(x)
+		return true
+	}
+	// match: (NeqB (Not x) (Not y))
+	// cond:
+	// result: (NeqB x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpNot {
+			break
+		}
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpNot {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpNeqB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (NeqB (Not y) (Not x))
+	// cond:
+	// result: (NeqB x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpNot {
+			break
+		}
+		y := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpNot {
+			break
+		}
+		x := v_1.Args[0]
+		v.reset(OpNeqB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeqInter_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (NeqInter x y)
+	// cond:
+	// result: (NeqPtr (ITab x) (ITab y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpNeqPtr)
+		v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool {
+	// match: (NeqPtr p (ConstNil))
+	// cond:
+	// result: (IsNonNil p)
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (NeqSlice x y)
+	// cond:
+	// result: (NeqPtr (SlicePtr x) (SlicePtr y))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpNeqPtr)
+		v0 := b.NewValue0(v.Pos, OpSlicePtr, typ.BytePtr)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpSlicePtr, typ.BytePtr)
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpNilCheck_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	// match: (NilCheck (GetG mem) mem)
+	// cond:
+	// result: mem
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpGetG {
+			break
+		}
+		mem := v_0.Args[0]
+		if mem != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
+		return true
+	}
+	// match: (NilCheck (Load (OffPtr [c] (SP)) mem) mem)
+	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize 	&& warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
+	// result: (Invalid)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLoad {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpOffPtr {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpSP {
+			break
+		}
+		mem := v_0.Args[1]
+		if mem != v.Args[1] {
+			break
+		}
+		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")) {
+			break
+		}
+		v.reset(OpInvalid)
+		return true
+	}
+	// match: (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
+	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize 	&& warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
+	// result: (Invalid)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOffPtr {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLoad {
+			break
+		}
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpOffPtr {
+			break
+		}
+		c := v_0_0_0.AuxInt
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpSP {
+			break
+		}
+		mem := v_0_0.Args[1]
+		if mem != v.Args[1] {
+			break
+		}
+		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")) {
+			break
+		}
+		v.reset(OpInvalid)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNot_0(v *Value) bool {
+	// match: (Not (Eq64 x y))
+	// cond:
+	// result: (Neq64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpEq64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpNeq64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Eq32 x y))
+	// cond:
+	// result: (Neq32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpEq32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpNeq32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Eq16 x y))
+	// cond:
+	// result: (Neq16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpEq16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpNeq16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Eq8 x y))
+	// cond:
+	// result: (Neq8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpEq8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpNeq8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (EqB x y))
+	// cond:
+	// result: (NeqB  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpEqB {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpNeqB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Neq64 x y))
+	// cond:
+	// result: (Eq64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpNeq64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpEq64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Neq32 x y))
+	// cond:
+	// result: (Eq32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpNeq32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpEq32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Neq16 x y))
+	// cond:
+	// result: (Eq16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpNeq16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpEq16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Neq8 x y))
+	// cond:
+	// result: (Eq8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpNeq8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpEq8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (NeqB x y))
+	// cond:
+	// result: (EqB  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpNeqB {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpEqB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNot_10(v *Value) bool {
+	// match: (Not (Greater64 x y))
+	// cond:
+	// result: (Leq64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater32 x y))
+	// cond:
+	// result: (Leq32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater16 x y))
+	// cond:
+	// result: (Leq16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater8 x y))
+	// cond:
+	// result: (Leq8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater64U x y))
+	// cond:
+	// result: (Leq64U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater64U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq64U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater32U x y))
+	// cond:
+	// result: (Leq32U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater32U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq32U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater16U x y))
+	// cond:
+	// result: (Leq16U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater16U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq16U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Greater8U x y))
+	// cond:
+	// result: (Leq8U  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGreater8U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLeq8U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq64 x y))
+	// cond:
+	// result: (Less64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq32 x y))
+	// cond:
+	// result: (Less32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNot_20(v *Value) bool {
+	// match: (Not (Geq16 x y))
+	// cond:
+	// result: (Less16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq8 x y))
+	// cond:
+	// result: (Less8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq64U x y))
+	// cond:
+	// result: (Less64U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq64U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess64U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq32U x y))
+	// cond:
+	// result: (Less32U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq32U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess32U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq16U x y))
+	// cond:
+	// result: (Less16U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq16U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess16U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Geq8U x y))
+	// cond:
+	// result: (Less8U  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpGeq8U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpLess8U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less64 x y))
+	// cond:
+	// result: (Geq64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less32 x y))
+	// cond:
+	// result: (Geq32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less16 x y))
+	// cond:
+	// result: (Geq16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less8 x y))
+	// cond:
+	// result: (Geq8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNot_30(v *Value) bool {
+	// match: (Not (Less64U x y))
+	// cond:
+	// result: (Geq64U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess64U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq64U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less32U x y))
+	// cond:
+	// result: (Geq32U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess32U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq32U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less16U x y))
+	// cond:
+	// result: (Geq16U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess16U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq16U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Less8U x y))
+	// cond:
+	// result: (Geq8U  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLess8U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGeq8U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq64 x y))
+	// cond:
+	// result: (Greater64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq32 x y))
+	// cond:
+	// result: (Greater32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq16 x y))
+	// cond:
+	// result: (Greater16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq8 x y))
+	// cond:
+	// result: (Greater8 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq64U x y))
+	// cond:
+	// result: (Greater64U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq64U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater64U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq32U x y))
+	// cond:
+	// result: (Greater32U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq32U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater32U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNot_40(v *Value) bool {
+	// match: (Not (Leq16U x y))
+	// cond:
+	// result: (Greater16U x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq16U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater16U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Not (Leq8U x y))
+	// cond:
+	// result: (Greater8U  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLeq8U {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpGreater8U)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOffPtr_0(v *Value) bool {
+	// match: (OffPtr (OffPtr p [b]) [a])
+	// cond:
+	// result: (OffPtr p [a+b])
+	for {
+		a := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpOffPtr {
+			break
+		}
+		b := v_0.AuxInt
+		p := v_0.Args[0]
+		v.reset(OpOffPtr)
+		v.AuxInt = a + b
+		v.AddArg(p)
+		return true
+	}
+	// match: (OffPtr p [0])
+	// cond: v.Type.Compare(p.Type) == types.CMPeq
+	// result: p
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		p := v.Args[0]
+		if !(v.Type.Compare(p.Type) == types.CMPeq) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = p.Type
+		v.AddArg(p)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr16_0(v *Value) bool {
+	// match: (Or16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c|d))])
+	for {
+		_ = v.Args[1]
+		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: (Or16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [int64(int16(c|d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c | d))
+		return true
+	}
+	// match: (Or16 x x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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 x (Const16 [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Const16 [-1]) _)
+	// cond:
+	// result: (Const16 [-1])
+	for {
+		_ = v.Args[1]
+		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 _ (Const16 [-1]))
+	// cond:
+	// result: (Const16 [-1])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or16 x (Or16 x y))
+	// cond:
+	// result: (Or16 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		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
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr16_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Or16 (Or16 y x) x)
+	// cond:
+	// result: (Or16 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or16 (And16 x (Const16 [c2])) (Const16 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or16 (Const16 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (And16 (Const16 [c2]) x) (Const16 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or16 (Const16 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		c2 := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Const16 <t> [c1]) (And16 x (Const16 [c2])))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or16 (Const16 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		c2 := v_1_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Const16 <t> [c1]) (And16 (Const16 [c2]) x))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or16 (Const16 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
+			break
+		}
+		c2 := v_1_0.AuxInt
+		x := v_1.Args[1]
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Or16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Or16 i (Or16 <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or16 (Or16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Or16 i (Or16 <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or16 x (Or16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Or16 i (Or16 <t> z x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or16 x (Or16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Or16 i (Or16 <t> z x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or16 (Const16 <t> [c]) (Or16 (Const16 <t> [d]) x))
+	// cond:
+	// result: (Or16 (Const16 <t> [int64(int16(c|d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		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(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr16_20(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Or16 (Const16 <t> [c]) (Or16 x (Const16 <t> [d])))
+	// cond:
+	// result: (Or16 (Const16 <t> [int64(int16(c|d))]) x)
+	for {
+		_ = v.Args[1]
+		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 != OpOr16 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Or16 (Const16 <t> [d]) x) (Const16 <t> [c]))
+	// cond:
+	// result: (Or16 (Const16 <t> [int64(int16(c|d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Or16 x (Const16 <t> [d])) (Const16 <t> [c]))
+	// cond:
+	// result: (Or16 (Const16 <t> [int64(int16(c|d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr32_0(v *Value) bool {
+	// match: (Or32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c|d))])
+	for {
+		_ = v.Args[1]
+		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: (Or32 (Const32 [d]) (Const32 [c]))
+	// cond:
+	// result: (Const32 [int64(int32(c|d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c | d))
+		return true
+	}
+	// match: (Or32 x x)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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.Args[1]
+		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 x (Const32 [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Const32 [-1]) _)
+	// cond:
+	// result: (Const32 [-1])
+	for {
+		_ = v.Args[1]
+		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 _ (Const32 [-1]))
+	// cond:
+	// result: (Const32 [-1])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or32 x (Or32 x y))
+	// cond:
+	// result: (Or32 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr32 {
+			break
+		}
+		_ = v_1.Args[1]
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr32 {
+			break
+		}
+		_ = v_1.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		_ = v_0.Args[1]
+		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
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr32_10(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Or32 (Or32 y x) x)
+	// cond:
+	// result: (Or32 x y)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or32 (And32 x (Const32 [c2])) (Const32 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or32 (Const32 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (And32 (Const32 [c2]) x) (Const32 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or32 (Const32 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		c2 := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Const32 <t> [c1]) (And32 x (Const32 [c2])))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or32 (Const32 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		c2 := v_1_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Const32 <t> [c1]) (And32 (Const32 [c2]) x))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or32 (Const32 <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
+			break
+		}
+		c2 := v_1_0.AuxInt
+		x := v_1.Args[1]
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Or32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Or32 i (Or32 <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or32 (Or32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Or32 i (Or32 <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or32 x (Or32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Or32 i (Or32 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr32 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Or32 x (Or32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Or32 i (Or32 <t> z x))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpOr32 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c % d))
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))])
+	// match: (Or32 (Const32 <t> [c]) (Or32 (Const32 <t> [d]) x))
+	// cond:
+	// result: (Or32 (Const32 <t> [int64(int32(c|d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst32 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpOr32 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = int64(uint16(c) % uint16(d))
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpMod32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpOr32_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod32 (Const32 [c]) (Const32 [d]))
-	// cond: d != 0
-	// result: (Const32 [int64(int32(c % d))])
+	// match: (Or32 (Const32 <t> [c]) (Or32 x (Const32 <t> [d])))
+	// cond:
+	// result: (Or32 (Const32 <t> [int64(int32(c|d))]) x)
 	for {
+		_ = v.Args[1]
 		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 != OpOr32 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Or32 (Const32 <t> [d]) x) (Const32 <t> [c]))
+	// cond:
+	// result: (Or32 (Const32 <t> [int64(int32(c|d))]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
 		if v_1.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c % d))
+		c := v_1.AuxInt
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		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))])
+	// match: (Or32 (Or32 x (Const32 <t> [d])) (Const32 <t> [c]))
+	// cond:
+	// result: (Or32 (Const32 <t> [int64(int32(c|d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpOr32 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = int64(uint32(c) % uint32(d))
+		c := v_1.AuxInt
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		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])
+func rewriteValuegeneric_OpOr64_0(v *Value) bool {
+	// match: (Or64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c|d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst64 {
 			break
@@ -5236,324 +17479,454 @@ func rewriteValuegeneric_OpMod64(v *Value, config *Config) bool {
 			break
 		}
 		d := v_1.AuxInt
-		if !(d != 0) {
+		v.reset(OpConst64)
+		v.AuxInt = c | d
+		return true
+	}
+	// match: (Or64 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (Const64 [c|d])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
 		v.reset(OpConst64)
-		v.AuxInt = c % d
+		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])))
+	// match: (Or64 x x)
+	// cond:
+	// result: x
 	for {
-		t := v.Type
+		_ = v.Args[1]
+		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.Args[1]
+		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 x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
 		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)) {
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or64 (Const64 [-1]) _)
+	// cond:
+	// result: (Const64 [-1])
+	for {
+		_ = v.Args[1]
+		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 _ (Const64 [-1]))
+	// cond:
+	// result: (Const64 [-1])
+	for {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or64 x (Or64 x y))
+	// cond:
+	// result: (Or64 x y)
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr64 {
+			break
+		}
+		_ = v_1.Args[1]
+		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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr64 {
+			break
+		}
+		_ = v_1.Args[1]
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpSub64)
+		v.reset(OpOr64)
 		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)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpMod64u(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpOr64_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mod64u (Const64 [c]) (Const64 [d]))
-	// cond: d != 0
-	// result: (Const64 [int64(uint64(c) % uint64(d))])
+	// match: (Or64 (Or64 y x) x)
+	// cond:
+	// result: (Or64 x y)
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpOr64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = int64(uint64(c) % uint64(d))
+		v.reset(OpOr64)
+		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (Mod64u <t> n (Const64 [c]))
-	// cond: isPowerOfTwo(c)
-	// result: (And64 n (Const64 <t> [c-1]))
+	// match: (Or64 (And64 x (Const64 [c2])) (Const64 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or64 (Const64 <t> [c1]) x)
 	for {
-		t := v.Type
-		n := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(isPowerOfTwo(c)) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			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]
+		c2 := v_0_1.AuxInt
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64 && umagic64ok(c)) {
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
 			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.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c1
 		v.AddArg(v0)
+		v.AddArg(x)
 		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))])
+	// match: (Or64 (And64 (Const64 [c2]) x) (Const64 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or64 (Const64 <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c % d))
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
 		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))])
+	// match: (Or64 (Const64 <t> [c1]) (And64 x (Const64 [c2])))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or64 (Const64 <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		c := v_0.AuxInt
+		t := v_0.Type
+		c1 := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(d != 0) {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = int64(uint8(c) % uint8(d))
+		c2 := v_1_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
 		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))])
+	// match: (Or64 (Const64 <t> [c1]) (And64 (Const64 [c2]) x))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or64 (Const64 <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		c := v_0.AuxInt
+		t := v_0.Type
+		c1 := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpAnd64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c * d))
-		return true
-	}
-	// match: (Mul16 (Const16 [-1]) x)
-	// cond:
-	// result: (Neg16 x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		c2 := v_1_0.AuxInt
+		x := v_1.Args[1]
+		if !(^(c1 | c2) == 0) {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg16)
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Mul16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Mul16 (Const16 <t> [c]) x)
+	// match: (Or64 (Or64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Or64 i (Or64 <t> z x))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpMul16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = c
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Mul16 (Const16 [0]) _)
-	// cond:
-	// result: (Const16 [0])
+	// match: (Or64 (Or64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Or64 i (Or64 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpOr64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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))])
+	// match: (Or64 x (Or64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Or64 i (Or64 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
-			break
-		}
-		c := v_0.AuxInt
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpOr64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c * d))
-		return true
-	}
-	// match: (Mul32 (Const32 [-1]) x)
-	// cond:
-	// result: (Neg32 x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg32)
-		v.AddArg(x)
+		v.reset(OpOr64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Mul32 x (Const32 <t> [c]))
-	// cond: x.Op != OpConst32
-	// result: (Mul32 (Const32 <t> [c]) x)
+	// match: (Or64 x (Or64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Or64 i (Or64 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpOr64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpMul32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x))
+	// match: (Or64 (Const64 <t> [c]) (Or64 (Const64 <t> [d]) x))
 	// cond:
-	// result: (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+	// result: (Or64 (Const64 <t> [c|d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64 {
 			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 {
+		if v_1.Op != OpOr64 {
 			break
 		}
+		_ = v_1.Args[1]
 		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst32 {
+		if v_1_0.Op != OpConst64 {
 			break
 		}
 		if v_1_0.Type != t {
@@ -5561,723 +17934,775 @@ func rewriteValuegeneric_OpMul32(v *Value, config *Config) bool {
 		}
 		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.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = 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
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpMul32F(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpOr64_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mul32F (Const32F [c]) (Const32F [d]))
+	// match: (Or64 (Const64 <t> [c]) (Or64 x (Const64 <t> [d])))
 	// cond:
-	// result: (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
+	// result: (Or64 (Const64 <t> [c|d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpConst64 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		if v_1.Op != OpOr64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32F)
-		v.AuxInt = f2i(float64(i2f32(c) * i2f32(d)))
-		return true
-	}
-	// match: (Mul32F x (Const32F [f2i(1)]))
-	// cond:
-	// result: x
-	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		if v_1.AuxInt != f2i(1) {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		d := v_1_1.AuxInt
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c | d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Mul32F (Const32F [f2i(1)]) x)
+	// match: (Or64 (Or64 (Const64 <t> [d]) x) (Const64 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Or64 (Const64 <t> [c|d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpOr64 {
 			break
 		}
-		if v_0.AuxInt != f2i(1) {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (Mul32F x (Const32F [f2i(-1)]))
-	// cond:
-	// result: (Neg32F x)
-	for {
-		x := v.Args[0]
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if v_1.AuxInt != f2i(-1) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpNeg32F)
+		c := v_1.AuxInt
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c | d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Mul32F (Const32F [f2i(-1)]) x)
+	// match: (Or64 (Or64 x (Const64 <t> [d])) (Const64 <t> [c]))
 	// cond:
-	// result: (Neg32F x)
+	// result: (Or64 (Const64 <t> [c|d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpOr64 {
 			break
 		}
-		if v_0.AuxInt != f2i(-1) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg32F)
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c | d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpMul64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64  (Const64 [c])  (Const64 [d]))
+func rewriteValuegeneric_OpOr8_0(v *Value) bool {
+	// match: (Or8 (Const8 [c]) (Const8 [d]))
 	// cond:
-	// result: (Const64 [c*d])
+	// result: (Const8  [int64(int8(c|d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst8 {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = c * d
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c | d))
 		return true
 	}
-	// match: (Mul64 (Const64 [-1]) x)
+	// match: (Or8 (Const8 [d]) (Const8 [c]))
 	// cond:
-	// result: (Neg64 x)
+	// result: (Const8  [int64(int8(c|d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg64)
-		v.AddArg(x)
+		c := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c | d))
 		return true
 	}
-	// match: (Mul64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Mul64 (Const64 <t> [c]) x)
+	// match: (Or8 x x)
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		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) {
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpMul64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x))
+	// match: (Or8 (Const8 [0]) x)
 	// cond:
-	// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+	// result: x
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_1_0.Type != t {
+		if v_0.AuxInt != 0 {
 			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)
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Mul64 (Const64 [0]) _)
+	// match: (Or8 x (Const8 [0]))
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpMul64F(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Mul64F (Const64F [c]) (Const64F [d]))
+	// match: (Or8 (Const8 [-1]) _)
 	// cond:
-	// result: (Const64F [f2i(i2f(c) * i2f(d))])
+	// result: (Const8  [-1])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_0.AuxInt != -1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64F)
-		v.AuxInt = f2i(i2f(c) * i2f(d))
+		v.reset(OpConst8)
+		v.AuxInt = -1
 		return true
 	}
-	// match: (Mul64F x (Const64F [f2i(1)]))
+	// match: (Or8 _ (Const8 [-1]))
 	// cond:
-	// result: x
+	// result: (Const8  [-1])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		if v_1.AuxInt != f2i(1) {
+		if v_1.AuxInt != -1 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpConst8)
+		v.AuxInt = -1
 		return true
 	}
-	// match: (Mul64F (Const64F [f2i(1)]) x)
+	// match: (Or8 x (Or8 x y))
 	// cond:
-	// result: x
+	// result: (Or8  x y)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr8 {
 			break
 		}
-		if v_0.AuxInt != f2i(1) {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		y := v_1.Args[1]
+		v.reset(OpOr8)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (Mul64F x (Const64F [f2i(-1)]))
+	// match: (Or8 x (Or8 y x))
 	// cond:
-	// result: (Neg64F x)
+	// result: (Or8  x y)
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_1.Op != OpOr8 {
 			break
 		}
-		if v_1.AuxInt != f2i(-1) {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		v.reset(OpNeg64F)
+		v.reset(OpOr8)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
-	// match: (Mul64F (Const64F [f2i(-1)]) x)
+	// match: (Or8 (Or8 x y) x)
 	// cond:
-	// result: (Neg64F x)
+	// result: (Or8  x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpOr8 {
 			break
 		}
-		if v_0.AuxInt != f2i(-1) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg64F)
+		v.reset(OpOr8)
 		v.AddArg(x)
+		v.AddArg(y)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpMul8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpOr8_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Mul8   (Const8 [c])   (Const8 [d]))
+	// match: (Or8 (Or8 y x) x)
 	// cond:
-	// result: (Const8  [int64(int8(c*d))])
+	// result: (Or8  x y)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpOr8 {
 			break
 		}
-		c := v_0.AuxInt
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or8 (And8 x (Const8 [c2])) (Const8 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or8  (Const8  <t> [c1]) x)
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		c2 := v_0_1.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))
+		t := v_1.Type
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Mul8  (Const8  [-1]) x)
-	// cond:
-	// result: (Neg8  x)
+	// match: (Or8 (And8 (Const8 [c2]) x) (Const8 <t> [c1]))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or8  (Const8  <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAnd8 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNeg8)
-		v.AddArg(x)
-		return true
-	}
-	// match: (Mul8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Mul8  (Const8  <t> [c]) x)
-	for {
-		x := v.Args[0]
+		c2 := v_0_0.AuxInt
+		x := v_0.Args[1]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst8 {
 			break
 		}
 		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		c1 := v_1.AuxInt
+		if !(^(c1 | c2) == 0) {
 			break
 		}
-		v.reset(OpMul8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = c1
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Mul8  (Const8  [0]) _)
-	// cond:
-	// result: (Const8  [0])
+	// match: (Or8 (Const8 <t> [c1]) (And8 x (Const8 [c2])))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or8  (Const8  <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
 			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 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpSub16)
-		v.AddArg(y)
+		c2 := v_1_1.AuxInt
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
 		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)
+	// match: (Or8 (Const8 <t> [c1]) (And8 (Const8 [c2]) x))
+	// cond: ^(c1 | c2) == 0
+	// result: (Or8  (Const8  <t> [c1]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSub32 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpSub32)
-		v.AddArg(y)
+		t := v_0.Type
+		c1 := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
+			break
+		}
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
+			break
+		}
+		c2 := v_1_0.AuxInt
+		x := v_1.Args[1]
+		if !(^(c1 | c2) == 0) {
+			break
+		}
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = c1
+		v.AddArg(v0)
 		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)
+	// match: (Or8 (Or8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Or8  i (Or8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSub64 {
+		if v_0.Op != OpOr8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpSub64)
-		v.AddArg(y)
-		v.AddArg(x)
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		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)
+	// match: (Or8 (Or8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Or8  i (Or8  <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSub8 {
+		if v_0.Op != OpOr8 {
 			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] {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 0
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Neq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
-	// cond:
-	// result: (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+	// match: (Or8 x (Or8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Or8  i (Or8  <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
-			break
-		}
-		t := v_0.Type
-		c := v_0.AuxInt
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd16 {
+		if v_1.Op != OpOr8 {
 			break
 		}
-		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst16 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		if v_1_0.Type != t {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
 			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.reset(OpOr8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Neq16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Neq16 (Const16 <t> [c]) x)
+	// match: (Or8 x (Or8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Or8  i (Or8  <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpOr8 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpNeq16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = c
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpOr8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Neq16 (Const16 [c]) (Const16 [d]))
+	// match: (Or8 (Const8 <t> [c]) (Or8 (Const8 <t> [d]) x))
 	// cond:
-	// result: (ConstBool [b2i(c != d)])
+	// result: (Or8  (Const8  <t> [int64(int8(c|d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst8 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpOr8 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c != d)
+		_ = v_1.Args[1]
+		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(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpNeq32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpOr8_20(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq32 x x)
+	// match: (Or8 (Const8 <t> [c]) (Or8 x (Const8 <t> [d])))
 	// cond:
-	// result: (ConstBool [0])
+	// result: (Or8  (Const8  <t> [int64(int8(c|d))]) x)
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 0
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr8 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c | d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Neq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
+	// match: (Or8 (Or8 (Const8 <t> [d]) x) (Const8 <t> [c]))
 	// cond:
-	// result: (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+	// result: (Or8  (Const8  <t> [int64(int8(c|d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpOr8 {
 			break
 		}
-		t := v_0.Type
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpAdd32 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
 			break
 		}
-		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst32 {
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		if v_1_0.Type != t {
+		if v_1.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))
+		c := v_1.AuxInt
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(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)
+	// match: (Or8 (Or8 x (Const8 <t> [d])) (Const8 <t> [c]))
+	// cond:
+	// result: (Or8  (Const8  <t> [int64(int8(c|d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr8 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
+			break
+		}
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpNeq32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
+		c := v_1.AuxInt
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c | d))
 		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Neq32 (Const32 [c]) (Const32 [d]))
+	return false
+}
+func rewriteValuegeneric_OpPhi_0(v *Value) bool {
+	// match: (Phi (Const8 [c]) (Const8 [c]))
 	// cond:
-	// result: (ConstBool [b2i(c != d)])
+	// result: (Const8  [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst8 {
 			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] {
+		if v_1.AuxInt != c {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 0
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = c
 		return true
 	}
-	// match: (Neq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+	// match: (Phi (Const16 [c]) (Const16 [c]))
 	// cond:
-	// result: (Neq64 (Const64 <t> [c-d]) x)
+	// result: (Const16 [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		t := v_0.Type
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpAdd64 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		v_1_0 := v_1.Args[0]
-		if v_1_0.Op != OpConst64 {
+		if v_1.AuxInt != c {
 			break
 		}
-		if v_1_0.Type != t {
+		if len(v.Args) != 2 {
 			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)
+		v.reset(OpConst16)
+		v.AuxInt = c
 		return true
 	}
-	// match: (Neq64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Neq64 (Const64 <t> [c]) x)
+	// match: (Phi (Const32 [c]) (Const32 [c]))
+	// cond:
+	// result: (Const32 [c])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 {
+		if v_1.Op != OpConst32 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		if v_1.AuxInt != c {
 			break
 		}
-		v.reset(OpNeq64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = c
 		return true
 	}
-	// match: (Neq64 (Const64 [c]) (Const64 [d]))
+	// match: (Phi (Const64 [c]) (Const64 [c]))
 	// cond:
-	// result: (ConstBool [b2i(c != d)])
+	// result: (Const64 [c])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst64 {
 			break
@@ -6287,1006 +18712,1366 @@ func rewriteValuegeneric_OpNeq64(v *Value, config *Config) bool {
 		if v_1.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c != d)
+		if v_1.AuxInt != c {
+			break
+		}
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = c
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpNeq8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpPtrIndex_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Neq8  x x)
-	// cond:
-	// result: (ConstBool [0])
+	config := b.Func.Config
+	_ = config
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (PtrIndex <t> ptr idx)
+	// cond: config.PtrSize == 4
+	// result: (AddPtr ptr (Mul32 <typ.Int> idx (Const32 <typ.Int> [t.ElemType().Size()])))
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		idx := v.Args[1]
+		if !(config.PtrSize == 4) {
 			break
 		}
-		v.reset(OpConstBool)
-		v.AuxInt = 0
+		v.reset(OpAddPtr)
+		v.AddArg(ptr)
+		v0 := b.NewValue0(v.Pos, OpMul32, typ.Int)
+		v0.AddArg(idx)
+		v1 := b.NewValue0(v.Pos, OpConst32, typ.Int)
+		v1.AuxInt = t.ElemType().Size()
+		v0.AddArg(v1)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Neq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x))
-	// cond:
-	// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+	// match: (PtrIndex <t> ptr idx)
+	// cond: config.PtrSize == 8
+	// result: (AddPtr ptr (Mul64 <typ.Int> idx (Const64 <typ.Int> [t.ElemType().Size()])))
 	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 {
+		t := v.Type
+		_ = v.Args[1]
+		ptr := v.Args[0]
+		idx := v.Args[1]
+		if !(config.PtrSize == 8) {
 			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.reset(OpAddPtr)
+		v.AddArg(ptr)
+		v0 := b.NewValue0(v.Pos, OpMul64, typ.Int)
+		v0.AddArg(idx)
+		v1 := b.NewValue0(v.Pos, OpConst64, typ.Int)
+		v1.AuxInt = t.ElemType().Size()
+		v0.AddArg(v1)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Neq8  x (Const8 <t>  [c]))
-	// cond: x.Op != OpConst8
-	// result: (Neq8  (Const8  <t> [c]) x)
+	return false
+}
+func rewriteValuegeneric_OpRound32F_0(v *Value) bool {
+	// match: (Round32F x:(Const32F))
+	// cond:
+	// result: 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) {
+		if x.Op != OpConst32F {
 			break
 		}
-		v.reset(OpNeq8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Neq8  (Const8  [c]) (Const8  [d]))
+	return false
+}
+func rewriteValuegeneric_OpRound64F_0(v *Value) bool {
+	// match: (Round64F x:(Const64F))
 	// cond:
-	// result: (ConstBool [b2i(c != d)])
+	// result: x
 	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 {
+		x := v.Args[0]
+		if x.Op != OpConst64F {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c != d)
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpNeqB(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh16Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (NeqB (ConstBool [c]) (ConstBool [d]))
+	// match: (Rsh16Ux16 <t> x (Const16 [c]))
 	// cond:
-	// result: (ConstBool [b2i(c != d)])
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
-			break
-		}
-		c := v_0.AuxInt
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConstBool {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConstBool)
-		v.AuxInt = b2i(c != d)
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (NeqB (ConstBool [0]) x)
+	// match: (Rsh16Ux16 (Const16 [0]) _)
 	// cond:
-	// result: x
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
+		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)
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (NeqB (ConstBool [1]) x)
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Not x)
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint32(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConstBool {
-			break
-		}
-		if v_0.AuxInt != 1 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpNot)
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
 		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpNeqInter(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NeqInter x y)
+	// match: (Rsh16Ux32 (Const16 [0]) _)
 	// cond:
-	// result: (NeqPtr (ITab x) (ITab y))
+	// result: (Const16 [0])
 	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)
+		_ = v.Args[1]
+		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_OpNeqPtr(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh16Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (NeqPtr p (ConstNil))
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16Ux64 (Const16 [c]) (Const64 [d]))
 	// cond:
-	// result: (IsNonNil p)
+	// result: (Const16 [int64(int16(uint16(c) >> uint64(d)))])
 	for {
-		p := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConstNil {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpIsNonNil)
-		v.AddArg(p)
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(uint16(c) >> uint64(d)))
 		return true
 	}
-	// match: (NeqPtr (ConstNil) p)
+	// match: (Rsh16Ux64 x (Const64 [0]))
 	// cond:
-	// result: (IsNonNil p)
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConstNil {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		p := v.Args[1]
-		v.reset(OpIsNonNil)
-		v.AddArg(p)
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpNeqSlice(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NeqSlice x y)
+	// match: (Rsh16Ux64 (Const16 [0]) _)
 	// cond:
-	// result: (NeqPtr (SlicePtr x) (SlicePtr y))
+	// result: (Const16 [0])
 	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)
+		_ = v.Args[1]
+		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
 	}
-}
-func rewriteValuegeneric_OpNilCheck(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (NilCheck (GetG mem) mem)
-	// cond:
-	// result: mem
+	// match: (Rsh16Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 16
+	// result: (Const16 [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGetG {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		mem := v_0.Args[0]
-		if mem != v.Args[1] {
+		c := v_1.AuxInt
+		if !(uint64(c) >= 16) {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = mem.Type
-		v.AddArg(mem)
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (NilCheck (Load (OffPtr [c] (SP)) mem) mem)
-	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize 	&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
-	// result: (Invalid)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLoad {
-			break
-		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpOffPtr {
+		if v_0.Op != OpRsh16Ux64 {
 			break
 		}
-		c := v_0_0.AuxInt
-		v_0_0_0 := v_0_0.Args[0]
-		if v_0_0_0.Op != OpSP {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		mem := v_0.Args[1]
-		if mem != v.Args[1] {
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")) {
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
 			break
 		}
-		v.reset(OpInvalid)
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
-	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize 	&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
-	// result: (Invalid)
+	// 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 <typ.UInt64> [c1-c2+c3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOffPtr {
+		if v_0.Op != OpLsh16x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpLoad {
+		if v_0_0.Op != OpRsh16Ux64 {
 			break
 		}
-		v_0_0_0 := v_0_0.Args[0]
-		if v_0_0_0.Op != OpOffPtr {
+		_ = v_0_0.Args[1]
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
 			break
 		}
-		c := v_0_0_0.AuxInt
-		v_0_0_0_0 := v_0_0_0.Args[0]
-		if v_0_0_0_0.Op != OpSP {
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		mem := v_0_0.Args[1]
-		if mem != v.Args[1] {
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")) {
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
 			break
 		}
-		v.reset(OpInvalid)
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpNot(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Not (Eq64 x y))
+	// match: (Rsh16Ux64 (Lsh16x64 x (Const64 [8])) (Const64 [8]))
 	// cond:
-	// result: (Neq64 x y)
+	// result: (ZeroExt8to16  (Trunc16to8  <typ.UInt8>  x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpEq64 {
+		if v_0.Op != OpLsh16x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpNeq64)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 8 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 8 {
+			break
+		}
+		v.reset(OpZeroExt8to16)
+		v0 := b.NewValue0(v.Pos, OpTrunc16to8, typ.UInt8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Eq32 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Neq32 x y)
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpEq32 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpNeq32)
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Eq16 x y))
+	// match: (Rsh16Ux8 (Const16 [0]) _)
 	// cond:
-	// result: (Neq16 x y)
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpEq16 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpNeq16)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Eq8  x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh16x16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Neq8  x y)
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpEq8 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpNeq8)
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (EqB  x y))
+	// match: (Rsh16x16 (Const16 [0]) _)
 	// cond:
-	// result: (NeqB  x y)
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpEqB {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpNeqB)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Neq64 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh16x32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Eq64 x y)
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint32(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpNeq64 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpEq64)
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Neq32 x y))
+	// match: (Rsh16x32 (Const16 [0]) _)
 	// cond:
-	// result: (Eq32 x y)
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpNeq32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpEq32)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Neq16 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh16x64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh16x64 (Const16 [c]) (Const64 [d]))
 	// cond:
-	// result: (Eq16 x y)
+	// result: (Const16 [int64(int16(c) >> uint64(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpNeq16 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpEq16)
-		v.AddArg(x)
-		v.AddArg(y)
+		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: (Not (Neq8  x y))
+	// match: (Rsh16x64 x (Const64 [0]))
 	// cond:
-	// result: (Eq8  x y)
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpNeq8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpEq8)
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (Not (NeqB  x y))
+	// match: (Rsh16x64 (Const16 [0]) _)
 	// cond:
-	// result: (EqB  x y)
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpNeqB {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpEqB)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Greater64 x y))
-	// cond:
-	// result: (Leq64 x y)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGreater64 {
+		if v_0.Op != OpRsh16x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq64)
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Greater32 x y))
+	// match: (Rsh16x64 (Lsh16x64 x (Const64 [8])) (Const64 [8]))
 	// cond:
-	// result: (Leq32 x y)
+	// result: (SignExt8to16  (Trunc16to8  <typ.Int8>  x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGreater32 {
+		if v_0.Op != OpLsh16x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq32)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 8 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 8 {
+			break
+		}
+		v.reset(OpSignExt8to16)
+		v0 := b.NewValue0(v.Pos, OpTrunc16to8, typ.Int8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Greater16 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh16x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Leq16 x y)
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGreater16 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq16)
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Greater8  x y))
+	// match: (Rsh16x8 (Const16 [0]) _)
 	// cond:
-	// result: (Leq8  x y)
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGreater8 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq8)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Greater64U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Leq64U x y)
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGreater64U {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq64U)
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Greater32U x y))
+	// match: (Rsh32Ux16 (Const32 [0]) _)
 	// cond:
-	// result: (Leq32U x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGreater32U {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq32U)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Greater16U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Leq16U x y)
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint32(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGreater16U {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq16U)
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Greater8U  x y))
+	// match: (Rsh32Ux32 (Const32 [0]) _)
 	// cond:
-	// result: (Leq8U  x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGreater8U {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLeq8U)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Geq64 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32Ux64 (Const32 [c]) (Const64 [d]))
 	// cond:
-	// result: (Less64 x y)
+	// result: (Const32 [int64(int32(uint32(c) >> uint64(d)))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq64 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess64)
-		v.AddArg(x)
-		v.AddArg(y)
+		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: (Not (Geq32 x y))
+	// match: (Rsh32Ux64 x (Const64 [0]))
 	// cond:
-	// result: (Less32 x y)
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGeq32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess32)
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (Not (Geq16 x y))
+	// match: (Rsh32Ux64 (Const32 [0]) _)
 	// cond:
-	// result: (Less16 x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq16 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess16)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Geq8  x y))
-	// cond:
-	// result: (Less8  x y)
+	// match: (Rsh32Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 32
+	// result: (Const32 [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpGeq8 {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess8)
-		v.AddArg(x)
-		v.AddArg(y)
+		c := v_1.AuxInt
+		if !(uint64(c) >= 32) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Geq64U x y))
-	// cond:
-	// result: (Less64U x y)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq64U {
+		if v_0.Op != OpRsh32Ux64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess64U)
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Geq32U x y))
-	// cond:
-	// result: (Less32U x y)
+	// 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 <typ.UInt64> [c1-c2+c3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq32U {
+		if v_0.Op != OpLsh32x64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess32U)
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh32Ux64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Geq16U x y))
+	// match: (Rsh32Ux64 (Lsh32x64 x (Const64 [24])) (Const64 [24]))
 	// cond:
-	// result: (Less16U x y)
+	// result: (ZeroExt8to32  (Trunc32to8  <typ.UInt8>  x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq16U {
+		if v_0.Op != OpLsh32x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess16U)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 24 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 24 {
+			break
+		}
+		v.reset(OpZeroExt8to32)
+		v0 := b.NewValue0(v.Pos, OpTrunc32to8, typ.UInt8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Geq8U  x y))
+	// match: (Rsh32Ux64 (Lsh32x64 x (Const64 [16])) (Const64 [16]))
 	// cond:
-	// result: (Less8U  x y)
+	// result: (ZeroExt16to32 (Trunc32to16 <typ.UInt16> x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpGeq8U {
+		if v_0.Op != OpLsh32x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpLess8U)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 16 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 16 {
+			break
+		}
+		v.reset(OpZeroExt16to32)
+		v0 := b.NewValue0(v.Pos, OpTrunc32to16, typ.UInt16)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Less64 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Geq64 x y)
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLess64 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq64)
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Less32 x y))
+	// match: (Rsh32Ux8 (Const32 [0]) _)
 	// cond:
-	// result: (Geq32 x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLess32 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq32)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Less16 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32x16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Geq16 x y)
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLess16 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq16)
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Less8  x y))
+	// match: (Rsh32x16 (Const32 [0]) _)
 	// cond:
-	// result: (Geq8  x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLess8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq8)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Less64U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32x32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Geq64U x y)
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint32(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLess64U {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq64U)
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Less32U x y))
+	// match: (Rsh32x32 (Const32 [0]) _)
 	// cond:
-	// result: (Geq32U x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLess32U {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq32U)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Less16U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32x64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh32x64 (Const32 [c]) (Const64 [d]))
 	// cond:
-	// result: (Geq16U x y)
+	// result: (Const32 [int64(int32(c) >> uint64(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLess16U {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq16U)
-		v.AddArg(x)
-		v.AddArg(y)
+		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: (Not (Less8U  x y))
+	// match: (Rsh32x64 x (Const64 [0]))
 	// cond:
-	// result: (Geq8U  x y)
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLess8U {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGeq8U)
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (Not (Leq64 x y))
+	// match: (Rsh32x64 (Const32 [0]) _)
 	// cond:
-	// result: (Greater64 x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq64 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater64)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Leq32 x y))
-	// cond:
-	// result: (Greater32 x y)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq32 {
+		if v_0.Op != OpRsh32x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater32)
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Leq16 x y))
+	// match: (Rsh32x64 (Lsh32x64 x (Const64 [24])) (Const64 [24]))
 	// cond:
-	// result: (Greater16 x y)
+	// result: (SignExt8to32  (Trunc32to8  <typ.Int8>  x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq16 {
+		if v_0.Op != OpLsh32x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater16)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 24 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 24 {
+			break
+		}
+		v.reset(OpSignExt8to32)
+		v0 := b.NewValue0(v.Pos, OpTrunc32to8, typ.Int8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Leq8  x y))
+	// match: (Rsh32x64 (Lsh32x64 x (Const64 [16])) (Const64 [16]))
 	// cond:
-	// result: (Greater8 x y)
+	// result: (SignExt16to32 (Trunc32to16 <typ.Int16> x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq8 {
+		if v_0.Op != OpLsh32x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater8)
-		v.AddArg(x)
-		v.AddArg(y)
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 16 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 16 {
+			break
+		}
+		v.reset(OpSignExt16to32)
+		v0 := b.NewValue0(v.Pos, OpTrunc32to16, typ.Int16)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Leq64U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh32x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Greater64U x y)
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLeq64U {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater64U)
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Leq32U x y))
+	// match: (Rsh32x8 (Const32 [0]) _)
 	// cond:
-	// result: (Greater32U x y)
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq32U {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater32U)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Not (Leq16U x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Greater16U x y)
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLeq16U {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater16U)
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Not (Leq8U  x y))
+	// match: (Rsh64Ux16 (Const64 [0]) _)
 	// cond:
-	// result: (Greater8U  x y)
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLeq8U {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		v.reset(OpGreater8U)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh64Ux32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (OffPtr (OffPtr p [b]) [a])
+	// match: (Rsh64Ux32 <t> x (Const32 [c]))
 	// cond:
-	// result: (OffPtr p [a+b])
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint32(c))]))
 	for {
-		a := v.AuxInt
-		v_0 := v.Args[0]
-		if v_0.Op != OpOffPtr {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		b := v_0.AuxInt
-		p := v_0.Args[0]
-		v.reset(OpOffPtr)
-		v.AuxInt = a + b
-		v.AddArg(p)
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (OffPtr p [0])
-	// cond: v.Type.Compare(p.Type) == CMPeq
-	// result: p
+	// match: (Rsh64Ux32 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
 	for {
-		if v.AuxInt != 0 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		p := v.Args[0]
-		if !(v.Type.Compare(p.Type) == CMPeq) {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = p.Type
-		v.AddArg(p)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh64Ux64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Or16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Or16 (Const16 <t> [c]) x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64Ux64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [int64(uint64(c) >> uint64(d))])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpOr16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint64(c) >> uint64(d))
 		return true
 	}
-	// match: (Or16 x x)
+	// match: (Rsh64Ux64 x (Const64 [0]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
 			break
 		}
 		v.reset(OpCopy)
@@ -7294,285 +20079,362 @@ func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Or16 (Const16 [0]) x)
+	// match: (Rsh64Ux64 (Const64 [0]) _)
 	// cond:
-	// result: x
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		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)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or16 (Const16 [-1]) _)
-	// cond:
-	// result: (Const16 [-1])
+	// match: (Rsh64Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 64
+	// result: (Const64 [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		_ = v.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		c := v_1.AuxInt
+		if !(uint64(c) >= 64) {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = -1
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or16 x (Or16 x y))
-	// cond:
-	// result: (Or16 x y)
+	// match: (Rsh64Ux64 <t> (Rsh64Ux64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh64Ux64 x (Const64 <t> [c+d]))
 	for {
-		x := v.Args[0]
+		t := v.Type
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh64Ux64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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 != OpOr16 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if x != v_1.Args[0] {
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpOr16)
+		v.reset(OpRsh64Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or16 x (Or16 y x))
-	// cond:
-	// result: (Or16 x y)
+	// 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 <typ.UInt64> [c1-c2+c3]))
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh64Ux64 {
+			break
+		}
+		_ = v_0_0.Args[1]
+		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 != OpOr16 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
 			break
 		}
-		v.reset(OpOr16)
+		v.reset(OpRsh64Ux64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or16 (Or16 x y) x)
+	// match: (Rsh64Ux64 (Lsh64x64 x (Const64 [56])) (Const64 [56]))
 	// cond:
-	// result: (Or16 x y)
+	// result: (ZeroExt8to64  (Trunc64to8  <typ.UInt8>  x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr16 {
+		if v_0.Op != OpLsh64x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpOr16)
-		v.AddArg(x)
-		v.AddArg(y)
+		if v_0_1.AuxInt != 56 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 56 {
+			break
+		}
+		v.reset(OpZeroExt8to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to8, typ.UInt8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or16 (Or16 x y) y)
+	// match: (Rsh64Ux64 (Lsh64x64 x (Const64 [48])) (Const64 [48]))
 	// cond:
-	// result: (Or16 x y)
+	// result: (ZeroExt16to64 (Trunc64to16 <typ.UInt16> x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr16 {
+		if v_0.Op != OpLsh64x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 48 {
 			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 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		if v_1.AuxInt != 48 {
 			break
 		}
-		v.reset(OpOr32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
+		v.reset(OpZeroExt16to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to16, typ.UInt16)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Or32 x x)
+	// match: (Rsh64Ux64 (Lsh64x64 x (Const64 [32])) (Const64 [32]))
 	// cond:
-	// result: x
+	// result: (ZeroExt32to64 (Trunc64to32 <typ.UInt32> x))
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 32 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 32 {
+			break
+		}
+		v.reset(OpZeroExt32to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to32, typ.UInt32)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or32 (Const32 [0]) x)
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux8 <t> x (Const8 [c]))
 	// cond:
-	// result: x
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
-			break
-		}
-		if v_0.AuxInt != 0 {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
 		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or32 (Const32 [-1]) _)
+	// match: (Rsh64Ux8 (Const64 [0]) _)
 	// cond:
-	// result: (Const32 [-1])
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = -1
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or32 x (Or32 x y))
+	return false
+}
+func rewriteValuegeneric_OpRsh64x16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Or32 x y)
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint16(c))]))
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpOr32 {
-			break
-		}
-		if x != v_1.Args[0] {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpOr32)
+		c := v_1.AuxInt
+		v.reset(OpRsh64x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or32 x (Or32 y x))
+	// match: (Rsh64x16 (Const64 [0]) _)
 	// cond:
-	// result: (Or32 x y)
+	// result: (Const64 [0])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpOr32 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpOr32)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or32 (Or32 x y) x)
+	return false
+}
+func rewriteValuegeneric_OpRsh64x32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Or32 x y)
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint32(c))]))
 	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] {
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpOr32)
+		c := v_1.AuxInt
+		v.reset(OpRsh64x64)
 		v.AddArg(x)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or32 (Or32 x y) y)
+	// match: (Rsh64x32 (Const64 [0]) _)
 	// cond:
-	// result: (Or32 x y)
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpOr32)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh64x64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Or64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Or64 (Const64 <t> [c]) x)
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh64x64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c >> uint64(d)])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpOr64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c >> uint64(d)
 		return true
 	}
-	// match: (Or64 x x)
+	// match: (Rsh64x64 x (Const64 [0]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
 			break
 		}
 		v.reset(OpCopy)
@@ -7580,10 +20442,11 @@ func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Or64 (Const64 [0]) x)
+	// match: (Rsh64x64 (Const64 [0]) _)
 	// cond:
-	// result: x
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst64 {
 			break
@@ -7591,142 +20454,244 @@ func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
 		if v_0.AuxInt != 0 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or64 (Const64 [-1]) _)
-	// cond:
-	// result: (Const64 [-1])
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpRsh64x64 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = -1
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or64 x (Or64 x y))
+	// match: (Rsh64x64 (Lsh64x64 x (Const64 [56])) (Const64 [56]))
 	// cond:
-	// result: (Or64 x y)
+	// result: (SignExt8to64  (Trunc64to8  <typ.Int8>  x))
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 56 {
+			break
+		}
 		v_1 := v.Args[1]
-		if v_1.Op != OpOr64 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if x != v_1.Args[0] {
+		if v_1.AuxInt != 56 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpOr64)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpSignExt8to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to8, typ.Int8)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or64 x (Or64 y x))
+	// match: (Rsh64x64 (Lsh64x64 x (Const64 [48])) (Const64 [48]))
 	// cond:
-	// result: (Or64 x y)
+	// result: (SignExt16to64 (Trunc64to16 <typ.Int16> x))
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		if v_0_1.AuxInt != 48 {
+			break
+		}
 		v_1 := v.Args[1]
-		if v_1.Op != OpOr64 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		if v_1.AuxInt != 48 {
 			break
 		}
-		v.reset(OpOr64)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpSignExt16to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to16, typ.Int16)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or64 (Or64 x y) x)
+	// match: (Rsh64x64 (Lsh64x64 x (Const64 [32])) (Const64 [32]))
 	// cond:
-	// result: (Or64 x y)
+	// result: (SignExt32to64 (Trunc64to32 <typ.Int32> x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr64 {
+		if v_0.Op != OpLsh64x64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpOr64)
+		if v_0_1.AuxInt != 32 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 32 {
+			break
+		}
+		v.reset(OpSignExt32to64)
+		v0 := b.NewValue0(v.Pos, OpTrunc64to32, typ.Int32)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64x8_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x8 <t> x (Const8 [c]))
+	// cond:
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		_ = v.Args[1]
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or64 (Or64 x y) y)
+	// match: (Rsh64x8 (Const64 [0]) _)
 	// cond:
-	// result: (Or64 x y)
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr64 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpOr64)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh8Ux16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Or8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Or8  (Const8  <t> [c]) x)
+	// match: (Rsh8Ux16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint16(c))]))
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpConst16 {
 			break
 		}
-		t := v_1.Type
 		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux16 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		v.reset(OpOr8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or8  x x)
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux32 <t> x (Const32 [c]))
 	// cond:
-	// result: x
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint32(c))]))
 	for {
+		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		c := v_1.AuxInt
+		v.reset(OpRsh8Ux64)
 		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or8  (Const8  [0]) x)
+	// match: (Rsh8Ux32 (Const8 [0]) _)
 	// cond:
-	// result: x
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
@@ -7734,350 +20699,445 @@ func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
 		if v_0.AuxInt != 0 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or8  (Const8  [-1]) _)
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	typ := &b.Func.Config.Types
+	_ = typ
+	// match: (Rsh8Ux64 (Const8 [c]) (Const64 [d]))
 	// cond:
-	// result: (Const8  [-1])
+	// result: (Const8  [int64(int8(uint8(c) >> uint64(d)))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != -1 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
+		d := v_1.AuxInt
 		v.reset(OpConst8)
-		v.AuxInt = -1
+		v.AuxInt = int64(int8(uint8(c) >> uint64(d)))
 		return true
 	}
-	// match: (Or8  x (Or8  x y))
+	// match: (Rsh8Ux64 x (Const64 [0]))
 	// cond:
-	// result: (Or8  x y)
+	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpOr8 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		if x != v_1.Args[0] {
+		if v_1.AuxInt != 0 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpOr8)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v.AddArg(y)
 		return true
 	}
-	// match: (Or8  x (Or8  y x))
+	// match: (Rsh8Ux64 (Const8 [0]) _)
 	// cond:
-	// result: (Or8  x y)
+	// result: (Const8  [0])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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.Args[1]
 		v_1 := v.Args[1]
-		if v_1.Op != OpOr8 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		c := v_1.AuxInt
+		if !(uint64(c) >= 8) {
 			break
 		}
-		v.reset(OpOr8)
-		v.AddArg(x)
-		v.AddArg(y)
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Or8  (Or8  x y) x)
-	// cond:
-	// result: (Or8  x y)
+	// 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.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr8 {
+		if v_0.Op != OpRsh8Ux64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpOr8)
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Or8  (Or8  x y) y)
-	// cond:
-	// result: (Or8  x y)
+	// 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 <typ.UInt64> [c1-c2+c3]))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpOr8 {
+		if v_0.Op != OpLsh8x64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh8Ux64 {
 			break
 		}
-		v.reset(OpOr8)
+		_ = v_0_0.Args[1]
+		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)
-		v.AddArg(y)
+		v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpPhi(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh8Ux8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Phi (Const8  [c]) (Const8  [c]))
+	// match: (Rsh8Ux8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Const8  [c])
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint8(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
-			break
-		}
-		c := v_0.AuxInt
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst8 {
 			break
 		}
-		if v_1.AuxInt != c {
+		c := v_1.AuxInt
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux8 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if len(v.Args) != 2 {
+		if v_0.AuxInt != 0 {
 			break
 		}
 		v.reset(OpConst8)
-		v.AuxInt = c
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Phi (Const16 [c]) (Const16 [c]))
+	return false
+}
+func rewriteValuegeneric_OpRsh8x16_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x16 <t> x (Const16 [c]))
 	// cond:
-	// result: (Const16 [c])
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint16(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
-			break
-		}
-		c := v_0.AuxInt
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst16 {
 			break
 		}
-		if v_1.AuxInt != c {
+		c := v_1.AuxInt
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8x16 (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if len(v.Args) != 2 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = c
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Phi (Const32 [c]) (Const32 [c]))
+	return false
+}
+func rewriteValuegeneric_OpRsh8x32_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x32 <t> x (Const32 [c]))
 	// cond:
-	// result: (Const32 [c])
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint32(c))]))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
-			break
-		}
-		c := v_0.AuxInt
+		t := v.Type
+		_ = v.Args[1]
+		x := v.Args[0]
 		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
+		c := v_1.AuxInt
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Phi (Const64 [c]) (Const64 [c]))
+	// match: (Rsh8x32 (Const8 [0]) _)
 	// cond:
-	// result: (Const64 [c])
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		if len(v.Args) != 2 {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = c
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpPtrIndex(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh8x64_0(v *Value) 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()])))
+	// match: (Rsh8x64 (Const8 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c) >> uint64(d))])
 	for {
-		t := v.Type
-		ptr := v.Args[0]
-		idx := v.Args[1]
-		if !(config.PtrSize == 8) {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			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)
+		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
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh16Ux16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh16Ux16 <t> x (Const16 [c]))
+	// match: (Rsh8x64 x (Const64 [0]))
 	// cond:
-	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint16(c))]))
+	// result: x
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh16Ux64)
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
-		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16Ux16 (Const16 [0]) _)
+	// match: (Rsh8x64 (Const8 [0]) _)
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst16)
+		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.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh8x64 {
+			break
+		}
+		_ = v_0.Args[1]
+		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.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
 	return false
 }
-func rewriteValuegeneric_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpRsh8x8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh16Ux32 <t> x (Const32 [c]))
+	// match: (Rsh8x8 <t> x (Const8 [c]))
 	// cond:
-	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint32(c))]))
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint8(c))]))
 	for {
 		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if v_1.Op != OpConst8 {
 			break
 		}
 		c := v_1.AuxInt
-		v.reset(OpRsh16Ux64)
+		v.reset(OpRsh8x64)
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16Ux32 (Const16 [0]) _)
+	// match: (Rsh8x8 (Const8 [0]) _)
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst16)
+		v.reset(OpConst8)
 		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]))
+func rewriteValuegeneric_OpSignExt16to32_0(v *Value) bool {
+	// match: (SignExt16to32 (Const16 [c]))
 	// cond:
-	// result: (Const16 [int64(int16(uint16(c) >> uint64(d)))])
+	// result: (Const32 [int64( int16(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 != OpConst64 {
-			break
-		}
-		d := v_1.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(uint16(c) >> uint64(d)))
+		v.reset(OpConst32)
+		v.AuxInt = int64(int16(c))
 		return true
 	}
-	// match: (Rsh16Ux64 x (Const64 [0]))
-	// cond:
+	// match: (SignExt16to32 (Trunc32to16 x:(Rsh32x64 _ (Const64 [s]))))
+	// cond: s >= 16
 	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpTrunc32to16 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		x := v_0.Args[0]
+		if x.Op != OpRsh32x64 {
+			break
+		}
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
+			break
+		}
+		s := x_1.AuxInt
+		if !(s >= 16) {
 			break
 		}
 		v.reset(OpCopy)
@@ -8085,366 +21145,397 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh16Ux64 (Const16 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpSignExt16to64_0(v *Value) bool {
+	// match: (SignExt16to64 (Const16 [c]))
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const64 [int64( int16(c))])
 	for {
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
-			break
-		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(int16(c))
 		return true
 	}
-	// match: (Rsh16Ux64 _ (Const64 [c]))
-	// cond: uint64(c) >= 16
-	// result: (Const16 [0])
+	// match: (SignExt16to64 (Trunc64to16 x:(Rsh64x64 _ (Const64 [s]))))
+	// cond: s >= 48
+	// result: x
 	for {
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpTrunc64to16 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 16) {
+		x := v_0.Args[0]
+		if x.Op != OpRsh64x64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
+			break
+		}
+		s := x_1.AuxInt
+		if !(s >= 48) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh16Ux64 <t> (Rsh16Ux64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh16Ux64 x (Const64 <t> [c+d]))
+	return false
+}
+func rewriteValuegeneric_OpSignExt32to64_0(v *Value) bool {
+	// match: (SignExt32to64 (Const32 [c]))
+	// cond:
+	// result: (Const64 [int64( int32(c))])
 	for {
-		t := v.Type
 		v_0 := v.Args[0]
-		if v_0.Op != OpRsh16Ux64 {
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(int32(c))
+		return true
+	}
+	// match: (SignExt32to64 (Trunc64to32 x:(Rsh64x64 _ (Const64 [s]))))
+	// cond: s >= 32
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpTrunc64to32 {
 			break
 		}
 		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		if x.Op != OpRsh64x64 {
 			break
 		}
-		c := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		s := x_1.AuxInt
+		if !(s >= 32) {
 			break
 		}
-		v.reset(OpRsh16Ux64)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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]))
+	return false
+}
+func rewriteValuegeneric_OpSignExt8to16_0(v *Value) bool {
+	// match: (SignExt8to16 (Const8 [c]))
+	// cond:
+	// result: (Const16 [int64(  int8(c))])
 	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 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		x := v_0_0.Args[0]
-		v_0_0_1 := v_0_0.Args[1]
-		if v_0_0_1.Op != OpConst64 {
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int8(c))
+		return true
+	}
+	// match: (SignExt8to16 (Trunc16to8 x:(Rsh16x64 _ (Const64 [s]))))
+	// cond: s >= 8
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpTrunc16to8 {
 			break
 		}
-		c1 := v_0_0_1.AuxInt
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		x := v_0.Args[0]
+		if x.Op != OpRsh16x64 {
 			break
 		}
-		c2 := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		s := x_1.AuxInt
+		if !(s >= 8) {
 			break
 		}
-		v.reset(OpRsh16Ux64)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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]))
+func rewriteValuegeneric_OpSignExt8to32_0(v *Value) bool {
+	// match: (SignExt8to32 (Const8 [c]))
 	// cond:
-	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint8(c))]))
+	// result: (Const32 [int64(  int8(c))])
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		v_0 := v.Args[0]
+		if v_0.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)
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int8(c))
 		return true
 	}
-	// match: (Rsh16Ux8 (Const16 [0]) _)
-	// cond:
-	// result: (Const16 [0])
+	// match: (SignExt8to32 (Trunc32to8 x:(Rsh32x64 _ (Const64 [s]))))
+	// cond: s >= 24
+	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpTrunc32to8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		x := v_0.Args[0]
+		if x.Op != OpRsh32x64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
+			break
+		}
+		s := x_1.AuxInt
+		if !(s >= 24) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh16x16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh16x16  <t> x (Const16 [c]))
+func rewriteValuegeneric_OpSignExt8to64_0(v *Value) bool {
+	// match: (SignExt8to64 (Const8 [c]))
 	// cond:
-	// result: (Rsh16x64  x (Const64 <t> [int64(uint16(c))]))
+	// result: (Const64 [int64(  int8(c))])
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			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)
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(int8(c))
 		return true
 	}
-	// match: (Rsh16x16  (Const16 [0]) _)
-	// cond:
-	// result: (Const16 [0])
+	// match: (SignExt8to64 (Trunc64to8 x:(Rsh64x64 _ (Const64 [s]))))
+	// cond: s >= 56
+	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpTrunc64to8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		x := v_0.Args[0]
+		if x.Op != OpRsh64x64 {
 			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 {
+		_ = x.Args[1]
+		x_1 := x.Args[1]
+		if x_1.Op != OpConst64 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh16x64)
+		s := x_1.AuxInt
+		if !(s >= 56) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
-		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16x32  (Const16 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpSliceCap_0(v *Value) bool {
+	// match: (SliceCap (SliceMake _ _ (Const64 <t> [c])))
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const64 <t> [c])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[2]
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		t := v_0_2.Type
+		c := v_0_2.AuxInt
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh16x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh16x64  (Const16 [c]) (Const64 [d]))
+	// match: (SliceCap (SliceMake _ _ (Const32 <t> [c])))
 	// cond:
-	// result: (Const16 [int64(int16(c) >> uint64(d))])
+	// result: (Const32 <t> [c])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[2]
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpConst32 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c) >> uint64(d))
+		t := v_0_2.Type
+		c := v_0_2.AuxInt
+		v.reset(OpConst32)
+		v.Type = t
+		v.AuxInt = c
 		return true
 	}
-	// match: (Rsh16x64  x (Const64 [0]))
+	// match: (SliceCap (SliceMake _ _ (SliceCap x)))
 	// cond:
-	// result: x
+	// result: (SliceCap x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		_ = v_0.Args[2]
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpSliceCap {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		x := v_0_2.Args[0]
+		v.reset(OpSliceCap)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh16x64  (Const16 [0]) _)
+	// match: (SliceCap (SliceMake _ _ (SliceLen x)))
 	// cond:
-	// result: (Const16 [0])
+	// result: (SliceLen x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[2]
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpSliceLen {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		x := v_0_2.Args[0]
+		v.reset(OpSliceLen)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh16x64 <t> (Rsh16x64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh16x64 x (Const64 <t> [c+d]))
+	return false
+}
+func rewriteValuegeneric_OpSliceLen_0(v *Value) bool {
+	// match: (SliceLen (SliceMake _ (Const64 <t> [c]) _))
+	// cond:
+	// result: (Const64 <t> [c])
 	for {
-		t := v.Type
 		v_0 := v.Args[0]
-		if v_0.Op != OpRsh16x64 {
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		x := v_0.Args[0]
+		_ = v_0.Args[2]
 		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_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
+		return true
+	}
+	// match: (SliceLen (SliceMake _ (Const32 <t> [c]) _))
+	// cond:
+	// result: (Const32 <t> [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		_ = v_0.Args[2]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		v.reset(OpRsh16x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
-		v.AddArg(v0)
+		t := v_0_1.Type
+		c := v_0_1.AuxInt
+		v.reset(OpConst32)
+		v.Type = t
+		v.AuxInt = c
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh16x8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh16x8   <t> x (Const8  [c]))
+	// match: (SliceLen (SliceMake _ (SliceLen x) _))
 	// cond:
-	// result: (Rsh16x64  x (Const64 <t> [int64(uint8(c))]))
+	// result: (SliceLen x)
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh16x64)
+		_ = v_0.Args[2]
+		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)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
-		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh16x8  (Const16 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpSlicePtr_0(v *Value) bool {
+	// match: (SlicePtr (SliceMake (SlicePtr x) _ _))
 	// cond:
-	// result: (Const16 [0])
+	// result: (SlicePtr x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpSliceMake {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[2]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpSlicePtr {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		x := v_0_0.Args[0]
+		v.reset(OpSlicePtr)
+		v.AddArg(x)
 		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))]))
+func rewriteValuegeneric_OpSlicemask_0(v *Value) bool {
+	// match: (Slicemask (Const32 [x]))
+	// cond: x > 0
+	// result: (Const32 [-1])
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			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)
+		x := v_0.AuxInt
+		if !(x > 0) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = -1
 		return true
 	}
-	// match: (Rsh32Ux16 (Const32 [0]) _)
+	// match: (Slicemask (Const32 [0]))
 	// cond:
 	// result: (Const32 [0])
 	for {
@@ -8459,782 +21550,998 @@ func rewriteValuegeneric_OpRsh32Ux16(v *Value, config *Config) bool {
 		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))]))
+	// match: (Slicemask (Const64 [x]))
+	// cond: x > 0
+	// result: (Const64 [-1])
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			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)
+		x := v_0.AuxInt
+		if !(x > 0) {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = -1
 		return true
 	}
-	// match: (Rsh32Ux32 (Const32 [0]) _)
+	// match: (Slicemask (Const64 [0]))
 	// cond:
-	// result: (Const32 [0])
+	// result: (Const64 [0])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64 {
 			break
 		}
 		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpConst32)
+		v.reset(OpConst64)
 		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]))
+func rewriteValuegeneric_OpSqrt_0(v *Value) bool {
+	// match: (Sqrt (Const64F [c]))
 	// cond:
-	// result: (Const32 [int64(int32(uint32(c) >> uint64(d)))])
+	// result: (Const64F [f2i(math.Sqrt(i2f(c)))])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst64F {
 			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)))
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(math.Sqrt(i2f(c)))
 		return true
 	}
-	// match: (Rsh32Ux64 x (Const64 [0]))
-	// cond:
-	// result: x
+	return false
+}
+func rewriteValuegeneric_OpStore_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	fe := b.Func.fe
+	_ = fe
+	// match: (Store {t1} p1 (Load <t2> p2 mem) mem)
+	// cond: isSamePtr(p1, p2) && 	t2.Size() == t1.(*types.Type).Size()
+	// result: mem
 	for {
-		x := v.Args[0]
+		t1 := v.Aux
+		_ = v.Args[2]
+		p1 := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpLoad {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		t2 := v_1.Type
+		_ = v_1.Args[1]
+		p2 := v_1.Args[0]
+		mem := v_1.Args[1]
+		if mem != v.Args[2] {
+			break
+		}
+		if !(isSamePtr(p1, p2) && t2.Size() == t1.(*types.Type).Size()) {
 			break
 		}
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		return true
 	}
-	// match: (Rsh32Ux64 (Const32 [0]) _)
-	// cond:
-	// result: (Const32 [0])
+	// match: (Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ oldmem))
+	// cond: isSamePtr(p1, p2) && 	isSamePtr(p1, p3) && 	t2.Size() == t1.(*types.Type).Size() && 	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size())
+	// result: mem
 	for {
+		t1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpOffPtr {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		o1 := v_0.AuxInt
+		p1 := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
 			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 {
+		t2 := v_1.Type
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpOffPtr {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 32) {
+		if v_1_0.AuxInt != o1 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		p2 := v_1_0.Args[0]
+		oldmem := v_1.Args[1]
+		mem := v.Args[2]
+		if mem.Op != OpStore {
+			break
+		}
+		t3 := mem.Aux
+		_ = mem.Args[2]
+		mem_0 := mem.Args[0]
+		if mem_0.Op != OpOffPtr {
+			break
+		}
+		o3 := mem_0.AuxInt
+		p3 := mem_0.Args[0]
+		if oldmem != mem.Args[2] {
+			break
+		}
+		if !(isSamePtr(p1, p2) && isSamePtr(p1, p3) && t2.Size() == t1.(*types.Type).Size() && !overlap(o1, t2.Size(), o3, t3.(*types.Type).Size())) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		return true
 	}
-	// match: (Rsh32Ux64 <t> (Rsh32Ux64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh32Ux64 x (Const64 <t> [c+d]))
+	// match: (Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ (Store {t4} (OffPtr [o4] p4) _ oldmem)))
+	// cond: isSamePtr(p1, p2) && 	isSamePtr(p1, p3) && 	isSamePtr(p1, p4) && 	t2.Size() == t1.(*types.Type).Size() && 	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) && 	!overlap(o1, t2.Size(), o4, t4.(*types.Type).Size())
+	// result: mem
 	for {
-		t := v.Type
+		t1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpRsh32Ux64 {
+		if v_0.Op != OpOffPtr {
 			break
 		}
-		x := v_0.Args[0]
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		o1 := v_0.AuxInt
+		p1 := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
 			break
 		}
-		c := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		t2 := v_1.Type
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpOffPtr {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		if v_1_0.AuxInt != o1 {
 			break
 		}
-		v.reset(OpRsh32Ux64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
-		v.AddArg(v0)
+		p2 := v_1_0.Args[0]
+		oldmem := v_1.Args[1]
+		mem := v.Args[2]
+		if mem.Op != OpStore {
+			break
+		}
+		t3 := mem.Aux
+		_ = mem.Args[2]
+		mem_0 := mem.Args[0]
+		if mem_0.Op != OpOffPtr {
+			break
+		}
+		o3 := mem_0.AuxInt
+		p3 := mem_0.Args[0]
+		mem_2 := mem.Args[2]
+		if mem_2.Op != OpStore {
+			break
+		}
+		t4 := mem_2.Aux
+		_ = mem_2.Args[2]
+		mem_2_0 := mem_2.Args[0]
+		if mem_2_0.Op != OpOffPtr {
+			break
+		}
+		o4 := mem_2_0.AuxInt
+		p4 := mem_2_0.Args[0]
+		if oldmem != mem_2.Args[2] {
+			break
+		}
+		if !(isSamePtr(p1, p2) && isSamePtr(p1, p3) && isSamePtr(p1, p4) && t2.Size() == t1.(*types.Type).Size() && !overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) && !overlap(o1, t2.Size(), o4, t4.(*types.Type).Size())) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		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]))
+	// match: (Store {t1} (OffPtr [o1] p1) (Load <t2> (OffPtr [o1] p2) oldmem) mem:(Store {t3} (OffPtr [o3] p3) _ (Store {t4} (OffPtr [o4] p4) _ (Store {t5} (OffPtr [o5] p5) _ oldmem))))
+	// cond: isSamePtr(p1, p2) && 	isSamePtr(p1, p3) && 	isSamePtr(p1, p4) && 	isSamePtr(p1, p5) && 	t2.Size() == t1.(*types.Type).Size() && 	!overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) && 	!overlap(o1, t2.Size(), o4, t4.(*types.Type).Size()) && 	!overlap(o1, t2.Size(), o5, t5.(*types.Type).Size())
+	// result: mem
 	for {
+		t1 := v.Aux
+		_ = v.Args[2]
 		v_0 := v.Args[0]
-		if v_0.Op != OpLsh32x64 {
+		if v_0.Op != OpOffPtr {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpRsh32Ux64 {
+		o1 := v_0.AuxInt
+		p1 := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
 			break
 		}
-		x := v_0_0.Args[0]
-		v_0_0_1 := v_0_0.Args[1]
-		if v_0_0_1.Op != OpConst64 {
+		t2 := v_1.Type
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpOffPtr {
 			break
 		}
-		c1 := v_0_0_1.AuxInt
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		if v_1_0.AuxInt != o1 {
 			break
 		}
-		c2 := v_0_1.AuxInt
+		p2 := v_1_0.Args[0]
+		oldmem := v_1.Args[1]
+		mem := v.Args[2]
+		if mem.Op != OpStore {
+			break
+		}
+		t3 := mem.Aux
+		_ = mem.Args[2]
+		mem_0 := mem.Args[0]
+		if mem_0.Op != OpOffPtr {
+			break
+		}
+		o3 := mem_0.AuxInt
+		p3 := mem_0.Args[0]
+		mem_2 := mem.Args[2]
+		if mem_2.Op != OpStore {
+			break
+		}
+		t4 := mem_2.Aux
+		_ = mem_2.Args[2]
+		mem_2_0 := mem_2.Args[0]
+		if mem_2_0.Op != OpOffPtr {
+			break
+		}
+		o4 := mem_2_0.AuxInt
+		p4 := mem_2_0.Args[0]
+		mem_2_2 := mem_2.Args[2]
+		if mem_2_2.Op != OpStore {
+			break
+		}
+		t5 := mem_2_2.Aux
+		_ = mem_2_2.Args[2]
+		mem_2_2_0 := mem_2_2.Args[0]
+		if mem_2_2_0.Op != OpOffPtr {
+			break
+		}
+		o5 := mem_2_2_0.AuxInt
+		p5 := mem_2_2_0.Args[0]
+		if oldmem != mem_2_2.Args[2] {
+			break
+		}
+		if !(isSamePtr(p1, p2) && isSamePtr(p1, p3) && isSamePtr(p1, p4) && isSamePtr(p1, p5) && t2.Size() == t1.(*types.Type).Size() && !overlap(o1, t2.Size(), o3, t3.(*types.Type).Size()) && !overlap(o1, t2.Size(), o4, t4.(*types.Type).Size()) && !overlap(o1, t2.Size(), o5, t5.(*types.Type).Size())) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store _ (StructMake0) mem)
+	// cond:
+	// result: mem
+	for {
+		_ = v.Args[2]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpStructMake0 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		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)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
+	for {
+		_ = v.Args[2]
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake1 {
 			break
 		}
-		v.reset(OpRsh32Ux64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
-		v0.AuxInt = c1 - c2 + c3
+		t := v_1.Type
+		f0 := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.Aux = t.FieldType(0)
+		v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v0.AuxInt = 0
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(f0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store dst (StructMake2 <t> f0 f1) mem)
+	// cond:
+	// result: (Store {t.FieldType(1)}     (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)     f1     (Store {t.FieldType(0)}       (OffPtr <t.FieldType(0).PtrTo()> [0] dst)         f0 mem))
+	for {
+		_ = v.Args[2]
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake2 {
+			break
+		}
+		t := v_1.Type
+		_ = v_1.Args[1]
+		f0 := v_1.Args[0]
+		f1 := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.Aux = t.FieldType(1)
+		v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v0.AuxInt = t.FieldOff(1)
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(f1)
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = t.FieldType(0)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v2.AuxInt = 0
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		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)}     (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)     f2     (Store {t.FieldType(1)}       (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)       f1       (Store {t.FieldType(0)}         (OffPtr <t.FieldType(0).PtrTo()> [0] dst)           f0 mem)))
+	for {
+		_ = v.Args[2]
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake3 {
+			break
+		}
+		t := v_1.Type
+		_ = v_1.Args[2]
+		f0 := v_1.Args[0]
+		f1 := v_1.Args[1]
+		f2 := v_1.Args[2]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.Aux = t.FieldType(2)
+		v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo())
+		v0.AuxInt = t.FieldOff(2)
+		v0.AddArg(dst)
 		v.AddArg(v0)
+		v.AddArg(f2)
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = t.FieldType(1)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v2.AuxInt = t.FieldOff(1)
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		v1.AddArg(f1)
+		v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v3.Aux = t.FieldType(0)
+		v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v4.AuxInt = 0
+		v4.AddArg(dst)
+		v3.AddArg(v4)
+		v3.AddArg(f0)
+		v3.AddArg(mem)
+		v1.AddArg(v3)
+		v.AddArg(v1)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh32Ux8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh32Ux8  <t> x (Const8  [c]))
+	// match: (Store dst (StructMake4 <t> f0 f1 f2 f3) mem)
 	// cond:
-	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint8(c))]))
+	// result: (Store {t.FieldType(3)}     (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)     f3     (Store {t.FieldType(2)}       (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)       f2       (Store {t.FieldType(1)}         (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)         f1         (Store {t.FieldType(0)}           (OffPtr <t.FieldType(0).PtrTo()> [0] dst)             f0 mem))))
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[2]
+		dst := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpStructMake4 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh32Ux64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
+		t := v_1.Type
+		_ = v_1.Args[3]
+		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.Aux = t.FieldType(3)
+		v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(3).PtrTo())
+		v0.AuxInt = t.FieldOff(3)
+		v0.AddArg(dst)
 		v.AddArg(v0)
+		v.AddArg(f3)
+		v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v1.Aux = t.FieldType(2)
+		v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo())
+		v2.AuxInt = t.FieldOff(2)
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		v1.AddArg(f2)
+		v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v3.Aux = t.FieldType(1)
+		v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo())
+		v4.AuxInt = t.FieldOff(1)
+		v4.AddArg(dst)
+		v3.AddArg(v4)
+		v3.AddArg(f1)
+		v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
+		v5.Aux = t.FieldType(0)
+		v6 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo())
+		v6.AuxInt = 0
+		v6.AddArg(dst)
+		v5.AddArg(v6)
+		v5.AddArg(f0)
+		v5.AddArg(mem)
+		v3.AddArg(v5)
+		v1.AddArg(v3)
+		v.AddArg(v1)
 		return true
 	}
-	// match: (Rsh32Ux8 (Const32 [0]) _)
-	// cond:
-	// result: (Const32 [0])
+	// match: (Store {t} dst (Load src mem) mem)
+	// cond: !fe.CanSSA(t.(*types.Type))
+	// result: (Move {t} [t.(*types.Type).Size()] dst src mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		t := v.Aux
+		_ = v.Args[2]
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		src := v_1.Args[0]
+		mem := v_1.Args[1]
+		if mem != v.Args[2] {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		if !(!fe.CanSSA(t.(*types.Type))) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = t.(*types.Type).Size()
+		v.Aux = t
+		v.AddArg(dst)
+		v.AddArg(src)
+		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpStore_10(v *Value) 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]
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	// match: (Store {t} dst (Load src mem) (VarDef {x} mem))
+	// cond: !fe.CanSSA(t.(*types.Type))
+	// result: (Move {t} [t.(*types.Type).Size()] dst src (VarDef {x} mem))
+	for {
+		t := v.Aux
+		_ = v.Args[2]
+		dst := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpLoad {
 			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 {
+		_ = v_1.Args[1]
+		src := v_1.Args[0]
+		mem := v_1.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpVarDef {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		x := v_2.Aux
+		if mem != v_2.Args[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 {
+		if !(!fe.CanSSA(t.(*types.Type))) {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh32x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
+		v.reset(OpMove)
+		v.AuxInt = t.(*types.Type).Size()
+		v.Aux = t
+		v.AddArg(dst)
+		v.AddArg(src)
+		v0 := b.NewValue0(v.Pos, OpVarDef, types.TypeMem)
+		v0.Aux = x
+		v0.AddArg(mem)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh32x32  (Const32 [0]) _)
+	// match: (Store _ (ArrayMake0) mem)
 	// cond:
-	// result: (Const32 [0])
+	// result: mem
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
-			break
-		}
-		if v_0.AuxInt != 0 {
+		_ = v.Args[2]
+		v_1 := v.Args[1]
+		if v_1.Op != OpArrayMake0 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		mem := v.Args[2]
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh32x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh32x64  (Const32 [c]) (Const64 [d]))
+	// match: (Store dst (ArrayMake1 e) mem)
 	// cond:
-	// result: (Const32 [int64(int32(c) >> uint64(d))])
+	// result: (Store {e.Type} dst e mem)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
-			break
-		}
-		c := v_0.AuxInt
+		_ = v.Args[2]
+		dst := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpArrayMake1 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c) >> uint64(d))
+		e := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.Aux = e.Type
+		v.AddArg(dst)
+		v.AddArg(e)
+		v.AddArg(mem)
 		return true
 	}
-	// match: (Rsh32x64  x (Const64 [0]))
-	// cond:
-	// result: x
+	// match: (Store (Load (OffPtr [c] (SP)) mem) x mem)
+	// cond: isConstZero(x) 	&& mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize
+	// result: mem
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[2]
+		v_0 := v.Args[0]
+		if v_0.Op != OpLoad {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpOffPtr {
 			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 {
+		c := v_0_0.AuxInt
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpSP {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		mem := v_0.Args[1]
+		x := v.Args[1]
+		if mem != v.Args[2] {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		if !(isConstZero(x) && mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		return true
 	}
-	// match: (Rsh32x64 <t> (Rsh32x64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh32x64 x (Const64 <t> [c+d]))
+	// match: (Store (OffPtr (Load (OffPtr [c] (SP)) mem)) x mem)
+	// cond: isConstZero(x) 	&& mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize
+	// result: mem
 	for {
-		t := v.Type
+		_ = v.Args[2]
 		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 {
+		if v_0.Op != OpOffPtr {
 			break
 		}
-		c := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLoad {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		_ = v_0_0.Args[1]
+		v_0_0_0 := v_0_0.Args[0]
+		if v_0_0_0.Op != OpOffPtr {
 			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 {
+		c := v_0_0_0.AuxInt
+		v_0_0_0_0 := v_0_0_0.Args[0]
+		if v_0_0_0_0.Op != OpSP {
 			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 {
+		mem := v_0_0.Args[1]
+		x := v.Args[1]
+		if mem != v.Args[2] {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if !(isConstZero(x) && mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh64Ux16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh64Ux16 <t> x (Const16 [c]))
+func rewriteValuegeneric_OpStringLen_0(v *Value) bool {
+	// match: (StringLen (StringMake _ (Const64 <t> [c])))
 	// cond:
-	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint16(c))]))
+	// result: (Const64 <t> [c])
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStringMake {
 			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)
+		_ = v_0.Args[1]
+		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: (Rsh64Ux16 (Const64 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpStringPtr_0(v *Value) bool {
+	// match: (StringPtr (StringMake (Const64 <t> [c]) _))
 	// cond:
-	// result: (Const64 [0])
+	// result: (Const64 <t> [c])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpStringMake {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		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.AuxInt = 0
+		v.Type = t
+		v.AuxInt = c
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh64Ux32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh64Ux32 <t> x (Const32 [c]))
+func rewriteValuegeneric_OpStructSelect_0(v *Value) bool {
+	// match: (StructSelect (StructMake1 x))
 	// cond:
-	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint32(c))]))
+	// result: x
 	for {
-		t := v.Type
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake1 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh64Ux64)
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint32(c))
-		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh64Ux32 (Const64 [0]) _)
+	// match: (StructSelect [0] (StructMake2 x _))
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v.AuxInt != 0 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake2 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh64Ux64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh64Ux64 (Const64 [c]) (Const64 [d]))
+	// match: (StructSelect [1] (StructMake2 _ x))
 	// cond:
-	// result: (Const64 [int64(uint64(c) >> uint64(d))])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v.AuxInt != 1 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake2 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = int64(uint64(c) >> uint64(d))
+		_ = v_0.Args[1]
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64Ux64 x (Const64 [0]))
+	// match: (StructSelect [0] (StructMake3 x _ _))
 	// cond:
 	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v.AuxInt != 0 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
 			break
 		}
+		_ = v_0.Args[2]
+		x := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64Ux64 (Const64 [0]) _)
+	// match: (StructSelect [1] (StructMake3 _ x _))
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v.AuxInt != 1 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		_ = v_0.Args[2]
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64Ux64 _ (Const64 [c]))
-	// cond: uint64(c) >= 64
-	// result: (Const64 [0])
+	// match: (StructSelect [2] (StructMake3 _ _ x))
+	// cond:
+	// result: x
 	for {
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v.AuxInt != 2 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 64) {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		_ = v_0.Args[2]
+		x := v_0.Args[2]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64Ux64 <t> (Rsh64Ux64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh64Ux64 x (Const64 <t> [c+d]))
+	// match: (StructSelect [0] (StructMake4 x _ _ _))
+	// cond:
+	// result: x
 	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 {
+		if v.AuxInt != 0 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
 			break
 		}
-		v.reset(OpRsh64Ux64)
+		_ = v_0.Args[3]
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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]))
+	// match: (StructSelect [1] (StructMake4 _ x _ _))
+	// cond:
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpLsh64x64 {
+		if v.AuxInt != 1 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpRsh64Ux64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
 			break
 		}
-		x := v_0_0.Args[0]
-		v_0_0_1 := v_0_0.Args[1]
-		if v_0_0_1.Op != OpConst64 {
+		_ = v_0.Args[3]
+		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
 		}
-		c1 := v_0_0_1.AuxInt
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
 			break
 		}
-		c2 := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[3]
+		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
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
 			break
 		}
-		v.reset(OpRsh64Ux64)
+		_ = v_0.Args[3]
+		x := v_0.Args[3]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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 {
+func rewriteValuegeneric_OpStructSelect_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64Ux8  <t> x (Const8  [c]))
-	// cond:
-	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint8(c))]))
+	fe := b.Func.fe
+	_ = fe
+	// match: (StructSelect [i] x:(Load <t> ptr mem))
+	// cond: !fe.CanSSA(t)
+	// result: @x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
 	for {
-		t := v.Type
+		i := v.AuxInt
 		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if x.Op != OpLoad {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh64Ux64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint8(c))
+		t := x.Type
+		_ = x.Args[1]
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(!fe.CanSSA(t)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Pos, OpLoad, v.Type)
+		v.reset(OpCopy)
 		v.AddArg(v0)
+		v1 := b.NewValue0(v.Pos, OpOffPtr, v.Type.PtrTo())
+		v1.AuxInt = t.FieldOff(int(i))
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
 		return true
 	}
-	// match: (Rsh64Ux8 (Const64 [0]) _)
+	// match: (StructSelect [0] x:(IData _))
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v.AuxInt != 0 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		x := v.Args[0]
+		if x.Op != OpIData {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh64x16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh64x16  <t> x (Const16 [c]))
+	// match: (Sub16 (Const16 [c]) (Const16 [d]))
 	// cond:
-	// result: (Rsh64x64  x (Const64 <t> [int64(uint16(c))]))
+	// result: (Const16 [int64(int16(c-d))])
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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
 		}
-		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)
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c - d))
 		return true
 	}
-	// match: (Rsh64x16  (Const64 [0]) _)
-	// cond:
-	// result: (Const64 [0])
+	// match: (Sub16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Add16 (Const16 <t> [int64(int16(-c))]) x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(-c))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh64x32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh64x32  <t> x (Const32 [c]))
+	// match: (Sub16 x x)
 	// cond:
-	// result: (Rsh64x64  x (Const64 <t> [int64(uint32(c))]))
+	// result: (Const16 [0])
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		if x != v.Args[1] {
 			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)
+		v.reset(OpConst16)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Rsh64x32  (Const64 [0]) _)
+	// match: (Sub16 (Add16 x y) x)
 	// cond:
-	// result: (Const64 [0])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh64x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh64x64  (Const64 [c]) (Const64 [d]))
+	// match: (Sub16 (Add16 y x) x)
 	// cond:
-	// result: (Const64 [c >> uint64(d)])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = c >> uint64(d)
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Rsh64x64  x (Const64 [0]))
+	// match: (Sub16 (Add16 x y) y)
 	// cond:
 	// result: x
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
 		v.reset(OpCopy)
@@ -9242,448 +22549,445 @@ func rewriteValuegeneric_OpRsh64x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64x64  (Const64 [0]) _)
+	// match: (Sub16 (Add16 y x) y)
 	// cond:
-	// result: (Const64 [0])
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpAdd16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh64x64 <t> (Rsh64x64 x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh64x64 x (Const64 <t> [c+d]))
+	// match: (Sub16 x (Sub16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Sub16 (Add16 <t> x z) i)
 	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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub16 {
 			break
 		}
-		c := v_0_1.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpRsh64x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpAdd16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		v.AddArg(v0)
+		v.AddArg(i)
 		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))]))
+	// match: (Sub16 x (Sub16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Add16 i (Sub16 <t> x z))
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpSub16 {
 			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 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		v.reset(OpAdd16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub16, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh8Ux16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh8Ux16 <t> x (Const16 [c]))
+	// match: (Sub16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d])))
 	// cond:
-	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint16(c))]))
+	// result: (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst16 {
+		if v_1.Op != OpSub16 {
 			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 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		d := v_1_1.AuxInt
+		v.reset(OpSub16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub16_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux32 <t> x (Const32 [c]))
+	// match: (Sub16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x))
 	// cond:
-	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint32(c))]))
+	// result: (Add16 (Const16 <t> [int64(int16(c-d))]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst32 {
+		if v_1.Op != OpSub16 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8Ux64  (Const8  [c]) (Const64 [d]))
+	// match: (Sub32 (Const32 [c]) (Const32 [d]))
 	// cond:
-	// result: (Const8  [int64(int8(uint8(c) >> uint64(d)))])
+	// result: (Const32 [int64(int32(c-d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst32 {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(uint8(c) >> uint64(d)))
+		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 {
+		_ = v.Args[1]
+		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.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(-c))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh8Ux64  x (Const64 [0]))
+	// match: (Sub32 x x)
 	// cond:
-	// result: x
+	// result: (Const32 [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
-			break
-		}
-		if v_1.AuxInt != 0 {
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Rsh8Ux64  (Const8 [0]) _)
+	// match: (Sub32 (Add32 x y) x)
 	// cond:
-	// result: (Const8  [0])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Rsh8Ux64  _ (Const64 [c]))
-	// cond: uint64(c) >= 8
-	// result: (Const8  [0])
+	// match: (Sub32 (Add32 y x) x)
+	// cond:
+	// result: y
 	for {
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
 			break
 		}
-		c := v_1.AuxInt
-		if !(uint64(c) >= 8) {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Rsh8Ux64  <t> (Rsh8Ux64  x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh8Ux64  x (Const64 <t> [c+d]))
+	// match: (Sub32 (Add32 x y) y)
+	// cond:
+	// result: x
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpRsh8Ux64 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
+		_ = v_0.Args[1]
 		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)) {
+		y := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
-		v.reset(OpRsh8Ux64)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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]))
+	// match: (Sub32 (Add32 y x) y)
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		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 {
+		if v_0.Op != OpAdd32 {
 			break
 		}
-		c3 := v_1.AuxInt
-		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
-		v.reset(OpRsh8Ux64)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		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))]))
+	// match: (Sub32 x (Sub32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Sub32 (Add32 <t> x z) i)
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpSub32 {
 			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 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpAdd32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		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))]))
+	// match: (Sub32 x (Sub32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Add32 i (Sub32 <t> x z))
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		if v_1.Op != OpSub32 {
 			break
 		}
-		c := v_1.AuxInt
-		v.reset(OpRsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = int64(uint16(c))
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub32, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
 		v.AddArg(v0)
 		return true
 	}
-	// match: (Rsh8x16   (Const8 [0]) _)
+	// match: (Sub32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d])))
 	// cond:
-	// result: (Const8  [0])
+	// result: (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub32 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpSub32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub32_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Rsh8x32  <t> x (Const32 [c]))
+	// match: (Sub32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x))
 	// cond:
-	// result: (Rsh8x64  x (Const64 <t> [int64(uint32(c))]))
+	// result: (Add32 (Const32 <t> [int64(int32(c-d))]) x)
 	for {
-		t := v.Type
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpConst32 {
+		if v_1.Op != OpSub32 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpRsh8x64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh8x64   (Const8  [c]) (Const64 [d]))
+func rewriteValuegeneric_OpSub32F_0(v *Value) bool {
+	// match: (Sub32F (Const32F [c]) (Const32F [d]))
 	// cond:
-	// result: (Const8  [int64(int8(c) >> uint64(d))])
+	// result: (Const32F [f2i(float64(i2f32(c) - i2f32(d)))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst32F {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst32F {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c) >> uint64(d))
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) - i2f32(d)))
 		return true
 	}
-	// match: (Rsh8x64   x (Const64 [0]))
+	// match: (Sub32F x (Const32F [0]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst32F {
 			break
 		}
 		if v_1.AuxInt != 0 {
@@ -9694,112 +22998,118 @@ func rewriteValuegeneric_OpRsh8x64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Rsh8x64   (Const8 [0]) _)
+	return false
+}
+func rewriteValuegeneric_OpSub64_0(v *Value) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub64 (Const64 [c]) (Const64 [d]))
 	// cond:
-	// result: (Const8  [0])
+	// result: (Const64 [c-d])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c - d
 		return true
 	}
-	// match: (Rsh8x64  <t> (Rsh8x64  x (Const64 [c])) (Const64 [d]))
-	// cond: !uaddOvf(c,d)
-	// result: (Rsh8x64  x (Const64 <t> [c+d]))
+	// match: (Sub64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Add64 (Const64 <t> [-c]) x)
 	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.Args[1]
+		x := v.Args[0]
 		v_1 := v.Args[1]
 		if v_1.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		if !(!uaddOvf(c, d)) {
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
 			break
 		}
-		v.reset(OpRsh8x64)
-		v.AddArg(x)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c + d
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = -c
 		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpRsh8x8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Rsh8x8   <t> x (Const8  [c]))
+	// match: (Sub64 x x)
 	// cond:
-	// result: (Rsh8x64  x (Const64 <t> [int64(uint8(c))]))
+	// result: (Const64 [0])
 	for {
-		t := v.Type
+		_ = v.Args[1]
 		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if x != v.Args[1] {
 			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)
+		v.reset(OpConst64)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Rsh8x8   (Const8 [0]) _)
+	// match: (Sub64 (Add64 x y) x)
 	// cond:
-	// result: (Const8  [0])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSignExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt16to32 (Trunc32to16 x:(Rsh32x64 _ (Const64 [s]))))
-	// cond: s >= 16
-	// result: x
+	// match: (Sub64 (Add64 y x) x)
+	// cond:
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc32to16 {
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh32x64 {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Sub64 (Add64 x y) y)
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 16) {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
 		v.reset(OpCopy)
@@ -9807,29 +23117,19 @@ func rewriteValuegeneric_OpSignExt16to32(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSignExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt16to64 (Trunc64to16 x:(Rsh64x64 _ (Const64 [s]))))
-	// cond: s >= 48
+	// match: (Sub64 (Add64 y x) y)
+	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc64to16 {
-			break
-		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh64x64 {
-			break
-		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		if v_0.Op != OpAdd64 {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 48) {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
 		v.reset(OpCopy)
@@ -9837,119 +23137,164 @@ func rewriteValuegeneric_OpSignExt16to64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSignExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt32to64 (Trunc64to32 x:(Rsh64x64 _ (Const64 [s]))))
-	// cond: s >= 32
-	// result: x
+	// match: (Sub64 x (Sub64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Sub64 (Add64 <t> x z) i)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc64to32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh64x64 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 32) {
+		v.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpAdd64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
+		return true
+	}
+	// match: (Sub64 x (Sub64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Add64 i (Sub64 <t> x z))
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub64, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSignExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to16  (Trunc16to8  x:(Rsh16x64 _ (Const64 [s]))))
-	// cond: s >= 8
-	// result: x
+	// match: (Sub64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d])))
+	// cond:
+	// result: (Sub64 (Const64 <t> [c+d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc16to8 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh16x64 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 8) {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		d := v_1_1.AuxInt
+		v.reset(OpSub64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpSignExt8to32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub64_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (SignExt8to32  (Trunc32to8  x:(Rsh32x64 _ (Const64 [s]))))
-	// cond: s >= 24
-	// result: x
+	// match: (Sub64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (Add64 (Const64 <t> [c-d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc32to8 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh32x64 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub64 {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 24) {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpSignExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SignExt8to64  (Trunc64to8  x:(Rsh64x64 _ (Const64 [s]))))
-	// cond: s >= 56
-	// result: x
+func rewriteValuegeneric_OpSub64F_0(v *Value) bool {
+	// match: (Sub64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) - i2f(d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpTrunc64to8 {
+		if v_0.Op != OpConst64F {
 			break
 		}
-		x := v_0.Args[0]
-		if x.Op != OpRsh64x64 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
 			break
 		}
-		x_1 := x.Args[1]
-		if x_1.Op != OpConst64 {
+		d := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) - i2f(d))
+		return true
+	}
+	// match: (Sub64F x (Const64F [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
 			break
 		}
-		s := x_1.AuxInt
-		if !(s >= 56) {
+		if v_1.AuxInt != 0 {
 			break
 		}
 		v.reset(OpCopy)
@@ -9959,549 +23304,418 @@ func rewriteValuegeneric_OpSignExt8to64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub8_0(v *Value) 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 _ _ (Const32 <t> [c])))
+	// match: (Sub8 (Const8 [c]) (Const8 [d]))
 	// cond:
-	// result: (Const32 <t> [c])
+	// result: (Const8 [int64(int8(c-d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		v_0_2 := v_0.Args[2]
-		if v_0_2.Op != OpConst32 {
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
 		}
-		t := v_0_2.Type
-		c := v_0_2.AuxInt
-		v.reset(OpConst32)
-		v.Type = t
-		v.AuxInt = c
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c - d))
 		return true
 	}
-	// match: (SliceCap (SliceMake _ _ (SliceCap x)))
-	// cond:
-	// result: (SliceCap x)
+	// match: (Sub8 x (Const8 <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Add8  (Const8  <t> [int64(int8(-c))]) x)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
 			break
-		}
-		v_0_2 := v_0.Args[2]
-		if v_0_2.Op != OpSliceCap {
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
 			break
 		}
-		x := v_0_2.Args[0]
-		v.reset(OpSliceCap)
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(-c))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (SliceCap (SliceMake _ _ (SliceLen x)))
+	// match: (Sub8 x x)
 	// cond:
-	// result: (SliceLen x)
+	// result: (Const8  [0])
 	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 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
 			break
 		}
-		x := v_0_2.Args[0]
-		v.reset(OpSliceLen)
-		v.AddArg(x)
+		v.reset(OpConst8)
+		v.AuxInt = 0
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SliceLen (SliceMake _ (Const64 <t> [c]) _))
+	// match: (Sub8 (Add8 x y) x)
 	// cond:
-	// result: (Const64 <t> [c])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst64 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		t := v_0_1.Type
-		c := v_0_1.AuxInt
-		v.reset(OpConst64)
-		v.Type = t
-		v.AuxInt = c
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (SliceLen (SliceMake _ (Const32 <t> [c]) _))
+	// match: (Sub8 (Add8 y x) x)
 	// cond:
-	// result: (Const32 <t> [c])
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpConst32 {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		t := v_0_1.Type
-		c := v_0_1.AuxInt
-		v.reset(OpConst32)
-		v.Type = t
-		v.AuxInt = c
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (SliceLen (SliceMake _ (SliceLen x) _))
+	// match: (Sub8 (Add8 x y) y)
 	// cond:
-	// result: (SliceLen x)
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		v_0_1 := v_0.Args[1]
-		if v_0_1.Op != OpSliceLen {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
-		x := v_0_1.Args[0]
-		v.reset(OpSliceLen)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (SlicePtr (SliceMake (SlicePtr x) _ _))
+	// match: (Sub8 (Add8 y x) y)
 	// cond:
-	// result: (SlicePtr x)
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSliceMake {
+		if v_0.Op != OpAdd8 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpSlicePtr {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if y != v.Args[1] {
 			break
 		}
-		x := v_0_0.Args[0]
-		v.reset(OpSlicePtr)
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSlicemask(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Slicemask (Const32 [x]))
-	// cond: x > 0
-	// result: (Const32 [-1])
+	// match: (Sub8 x (Sub8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Sub8  (Add8  <t> x z) i)
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		x := v_0.AuxInt
-		if !(x > 0) {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = -1
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpAdd8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
+		v.AddArg(i)
 		return true
 	}
-	// match: (Slicemask (Const32 [0]))
-	// cond:
-	// result: (Const32 [0])
+	// match: (Sub8 x (Sub8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Add8  i (Sub8  <t> x z))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpSub8, t)
+		v0.AddArg(x)
+		v0.AddArg(z)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Slicemask (Const64 [x]))
-	// cond: x > 0
-	// result: (Const64 [-1])
+	// match: (Sub8 (Const8 <t> [c]) (Sub8 x (Const8 <t> [d])))
+	// cond:
+	// result: (Sub8  (Const8  <t> [int64(int8(c+d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
-		x := v_0.AuxInt
-		if !(x > 0) {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpSub8 {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = -1
-		return true
-	}
-	// match: (Slicemask (Const64 [0]))
-	// cond:
-	// result: (Const64 [0])
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		if v_1_1.Type != t {
 			break
 		}
-		v.reset(OpConst64)
-		v.AuxInt = 0
+		d := v_1_1.AuxInt
+		v.reset(OpSub8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c + d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpSqrt(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSub8_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Sqrt (Const64F [c]))
+	// match: (Sub8 (Const8 <t> [c]) (Sub8 (Const8 <t> [d]) x))
 	// cond:
-	// result: (Const64F [f2i(math.Sqrt(i2f(c)))])
+	// result: (Add8  (Const8  <t> [int64(int8(c-d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64F {
+		if v_0.Op != OpConst8 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
-		v.reset(OpConst64F)
-		v.AuxInt = f2i(math.Sqrt(i2f(c)))
-		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 {
+		if v_1.Op != OpSub8 {
 			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 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
 			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)
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Store dst (StructMake2 <t> f0 f1) mem)
+	return false
+}
+func rewriteValuegeneric_OpTrunc16to8_0(v *Value) bool {
+	// match: (Trunc16to8 (Const16 [c]))
 	// 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))
+	// result: (Const8   [int64(int8(c))])
 	for {
-		dst := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpStructMake2 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
 			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)
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c))
 		return true
 	}
-	// match: (Store dst (StructMake3 <t> f0 f1 f2) mem)
+	// match: (Trunc16to8 (ZeroExt8to16 x))
 	// 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)))
+	// result: x
 	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)
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to16 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Store dst (StructMake4 <t> f0 f1 f2 f3) mem)
+	// match: (Trunc16to8 (SignExt8to16 x))
 	// 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))))
+	// result: x
 	for {
-		dst := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpStructMake4 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSignExt8to16 {
 			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)
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Store [size] dst (Load <t> src mem) mem)
-	// cond: !config.fe.CanSSA(t)
-	// result: (Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src mem)
+	// match: (Trunc16to8 (And16 (Const16 [y]) x))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc16to8 x)
 	for {
-		size := v.AuxInt
-		dst := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpLoad {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		t := v_1.Type
-		src := v_1.Args[0]
-		mem := v_1.Args[1]
-		if mem != v.Args[2] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
 			break
 		}
-		if !(!config.fe.CanSSA(t)) {
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFF == 0xFF) {
 			break
 		}
-		v.reset(OpMove)
-		v.AuxInt = MakeSizeAndAlign(size, t.Alignment()).Int64()
-		v.AddArg(dst)
-		v.AddArg(src)
-		v.AddArg(mem)
+		v.reset(OpTrunc16to8)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Store [size] dst (Load <t> src mem) (VarDef {x} mem))
-	// cond: !config.fe.CanSSA(t)
-	// result: (Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src (VarDef {x} mem))
+	// match: (Trunc16to8 (And16 x (Const16 [y])))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc16to8 x)
 	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 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
 			break
 		}
-		x := v_2.Aux
-		if mem != v_2.Args[0] {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
 			break
 		}
-		if !(!config.fe.CanSSA(t)) {
+		y := v_0_1.AuxInt
+		if !(y&0xFF == 0xFF) {
 			break
 		}
-		v.reset(OpMove)
-		v.AuxInt = MakeSizeAndAlign(size, t.Alignment()).Int64()
-		v.AddArg(dst)
-		v.AddArg(src)
-		v0 := b.NewValue0(v.Line, OpVarDef, TypeMem)
-		v0.Aux = x
-		v0.AddArg(mem)
-		v.AddArg(v0)
+		v.reset(OpTrunc16to8)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Store _ (ArrayMake0) mem)
+	return false
+}
+func rewriteValuegeneric_OpTrunc32to16_0(v *Value) bool {
+	// match: (Trunc32to16 (Const32 [c]))
 	// cond:
-	// result: mem
+	// result: (Const16  [int64(int16(c))])
 	for {
-		v_1 := v.Args[1]
-		if v_1.Op != OpArrayMake0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
 			break
 		}
-		mem := v.Args[2]
-		v.reset(OpCopy)
-		v.Type = mem.Type
-		v.AddArg(mem)
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c))
 		return true
 	}
-	// match: (Store [size] dst (ArrayMake1 e) mem)
+	// match: (Trunc32to16 (ZeroExt8to32 x))
 	// cond:
-	// result: (Store [size] dst e mem)
+	// result: (ZeroExt8to16  x)
 	for {
-		size := v.AuxInt
-		dst := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpArrayMake1 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to32 {
 			break
 		}
-		e := v_1.Args[0]
-		mem := v.Args[2]
-		v.reset(OpStore)
-		v.AuxInt = size
-		v.AddArg(dst)
-		v.AddArg(e)
-		v.AddArg(mem)
+		x := v_0.Args[0]
+		v.reset(OpZeroExt8to16)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpStringLen(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (StringLen (StringMake _ (Const64 <t> [c])))
+	// match: (Trunc32to16 (ZeroExt16to32 x))
 	// cond:
-	// result: (Const64 <t> [c])
+	// result: x
 	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 {
+		if v_0.Op != OpZeroExt16to32 {
 			break
 		}
-		t := v_0_1.Type
-		c := v_0_1.AuxInt
-		v.reset(OpConst64)
-		v.Type = t
-		v.AuxInt = c
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpStringPtr(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (StringPtr (StringMake (Const64 <t> [c]) _))
+	// match: (Trunc32to16 (SignExt8to32 x))
 	// cond:
-	// result: (Const64 <t> [c])
+	// result: (SignExt8to16  x)
 	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 {
+		if v_0.Op != OpSignExt8to32 {
 			break
 		}
-		t := v_0_0.Type
-		c := v_0_0.AuxInt
-		v.reset(OpConst64)
-		v.Type = t
-		v.AuxInt = c
+		x := v_0.Args[0]
+		v.reset(OpSignExt8to16)
+		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpStructSelect(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (StructSelect (StructMake1 x))
+	// match: (Trunc32to16 (SignExt16to32 x))
 	// cond:
 	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake1 {
+		if v_0.Op != OpSignExt16to32 {
 			break
 		}
 		x := v_0.Args[0]
@@ -10510,49 +23724,86 @@ func rewriteValuegeneric_OpStructSelect(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [0] (StructMake2 x _))
-	// cond:
-	// result: x
+	// match: (Trunc32to16 (And32 (Const32 [y]) x))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc32to16 x)
 	for {
-		if v.AuxInt != 0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		_ = v_0.Args[1]
+		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
+	}
+	// match: (Trunc32to16 (And32 x (Const32 [y])))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc32to16 x)
+	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake2 {
+		if v_0.Op != OpAnd32 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
+			break
+		}
+		y := v_0_1.AuxInt
+		if !(y&0xFFFF == 0xFFFF) {
+			break
+		}
+		v.reset(OpTrunc32to16)
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [1] (StructMake2 _ x))
+	return false
+}
+func rewriteValuegeneric_OpTrunc32to8_0(v *Value) bool {
+	// match: (Trunc32to8 (Const32 [c]))
 	// cond:
-	// result: x
+	// result: (Const8   [int64(int8(c))])
 	for {
-		if v.AuxInt != 1 {
+		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 (ZeroExt8to32 x))
+	// cond:
+	// result: x
+	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake2 {
+		if v_0.Op != OpZeroExt8to32 {
 			break
 		}
-		x := v_0.Args[1]
+		x := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [0] (StructMake3 x _ _))
+	// match: (Trunc32to8 (SignExt8to32 x))
 	// cond:
 	// result: x
 	for {
-		if v.AuxInt != 0 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake3 {
+		if v_0.Op != OpSignExt8to32 {
 			break
 		}
 		x := v_0.Args[0]
@@ -10561,496 +23812,474 @@ func rewriteValuegeneric_OpStructSelect(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [1] (StructMake3 _ x _))
-	// cond:
-	// result: x
+	// 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.Args[1]
+		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
+	}
+	// match: (Trunc32to8 (And32 x (Const32 [y])))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc32to8 x)
 	for {
-		if v.AuxInt != 1 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
 			break
 		}
-		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake3 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		y := v_0_1.AuxInt
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc32to8)
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [2] (StructMake3 _ _ x))
+	return false
+}
+func rewriteValuegeneric_OpTrunc64to16_0(v *Value) bool {
+	// match: (Trunc64to16 (Const64 [c]))
 	// cond:
-	// result: x
+	// result: (Const16  [int64(int16(c))])
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake3 {
+		if v_0.Op != OpConst64 {
 			break
 		}
-		x := v_0.Args[2]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c))
 		return true
 	}
-	// match: (StructSelect [0] (StructMake4 x _ _ _))
+	// match: (Trunc64to16 (ZeroExt8to64 x))
 	// cond:
-	// result: x
+	// result: (ZeroExt8to16  x)
 	for {
-		if v.AuxInt != 0 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake4 {
+		if v_0.Op != OpZeroExt8to64 {
 			break
 		}
 		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		v.reset(OpZeroExt8to16)
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [1] (StructMake4 _ x _ _))
+	// match: (Trunc64to16 (ZeroExt16to64 x))
 	// cond:
 	// result: x
 	for {
-		if v.AuxInt != 1 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake4 {
+		if v_0.Op != OpZeroExt16to64 {
 			break
 		}
-		x := v_0.Args[1]
+		x := v_0.Args[0]
 		v.reset(OpCopy)
 		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [2] (StructMake4 _ _ x _))
+	// match: (Trunc64to16 (SignExt8to64 x))
 	// cond:
-	// result: x
+	// result: (SignExt8to16  x)
 	for {
-		if v.AuxInt != 2 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake4 {
+		if v_0.Op != OpSignExt8to64 {
 			break
 		}
-		x := v_0.Args[2]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		x := v_0.Args[0]
+		v.reset(OpSignExt8to16)
 		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [3] (StructMake4 _ _ _ x))
+	// match: (Trunc64to16 (SignExt16to64 x))
 	// cond:
 	// result: x
 	for {
-		if v.AuxInt != 3 {
-			break
-		}
 		v_0 := v.Args[0]
-		if v_0.Op != OpStructMake4 {
+		if v_0.Op != OpSignExt16to64 {
 			break
 		}
-		x := v_0.Args[3]
+		x := v_0.Args[0]
 		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)
+	// match: (Trunc64to16 (And64 (Const64 [y]) x))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc64to16 x)
 	for {
-		i := v.AuxInt
-		x := v.Args[0]
-		if x.Op != OpLoad {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		t := x.Type
-		ptr := x.Args[0]
-		mem := x.Args[1]
-		if !(!config.fe.CanSSA(t)) {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			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)
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFFFF == 0xFFFF) {
+			break
+		}
+		v.reset(OpTrunc64to16)
+		v.AddArg(x)
 		return true
 	}
-	// match: (StructSelect [0] x:(IData _))
-	// cond:
-	// result: x
+	// match: (Trunc64to16 (And64 x (Const64 [y])))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc64to16 x)
 	for {
-		if v.AuxInt != 0 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		x := v.Args[0]
-		if x.Op != OpIData {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		y := v_0_1.AuxInt
+		if !(y&0xFFFF == 0xFFFF) {
+			break
+		}
+		v.reset(OpTrunc64to16)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpSub16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub16  (Const16 [c]) (Const16 [d]))
+func rewriteValuegeneric_OpTrunc64to32_0(v *Value) bool {
+	// match: (Trunc64to32 (Const64 [c]))
 	// cond:
-	// result: (Const16 [int64(int16(c-d))])
+	// result: (Const32  [int64(int32(c))])
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			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))
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c))
 		return true
 	}
-	// match: (Sub16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Add16 (Const16 <t> [int64(int16(-c))]) x)
+	// match: (Trunc64to32 (ZeroExt8to64 x))
+	// cond:
+	// result: (ZeroExt8to32  x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		x := v_0.Args[0]
+		v.reset(OpZeroExt8to32)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Trunc64to32 (ZeroExt16to64 x))
+	// cond:
+	// result: (ZeroExt16to32 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to64 {
 			break
 		}
-		v.reset(OpAdd16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = int64(int16(-c))
-		v.AddArg(v0)
+		x := v_0.Args[0]
+		v.reset(OpZeroExt16to32)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Sub16 x x)
+	// match: (Trunc64to32 (ZeroExt32to64 x))
 	// cond:
-	// result: (Const16 [0])
+	// result: x
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt32to64 {
 			break
 		}
-		v.reset(OpConst16)
-		v.AuxInt = 0
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Sub16 (Add16 x y) x)
+	// match: (Trunc64to32 (SignExt8to64 x))
 	// cond:
-	// result: y
+	// result: (SignExt8to32  x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd16 {
+		if v_0.Op != OpSignExt8to64 {
 			break
 		}
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		v.reset(OpSignExt8to32)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Trunc64to32 (SignExt16to64 x))
+	// cond:
+	// result: (SignExt16to32 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSignExt16to64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		x := v_0.Args[0]
+		v.reset(OpSignExt16to32)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Sub16 (Add16 x y) y)
+	// match: (Trunc64to32 (SignExt32to64 x))
 	// cond:
 	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd16 {
+		if v_0.Op != OpSignExt32to64 {
 			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))])
+	// match: (Trunc64to32 (And64 (Const64 [y]) x))
+	// cond: y&0xFFFFFFFF == 0xFFFFFFFF
+	// result: (Trunc64to32 x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c - d))
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFFFFFFFF == 0xFFFFFFFF) {
+			break
+		}
+		v.reset(OpTrunc64to32)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Sub32 x (Const32 <t> [c]))
-	// cond: x.Op != OpConst32
-	// result: (Add32 (Const32 <t> [int64(int32(-c))]) x)
+	// match: (Trunc64to32 (And64 x (Const64 [y])))
+	// cond: y&0xFFFFFFFF == 0xFFFFFFFF
+	// result: (Trunc64to32 x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		y := v_0_1.AuxInt
+		if !(y&0xFFFFFFFF == 0xFFFFFFFF) {
 			break
 		}
-		v.reset(OpAdd32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = int64(int32(-c))
-		v.AddArg(v0)
+		v.reset(OpTrunc64to32)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Sub32 x x)
+	return false
+}
+func rewriteValuegeneric_OpTrunc64to8_0(v *Value) bool {
+	// match: (Trunc64to8 (Const64 [c]))
 	// cond:
-	// result: (Const32 [0])
+	// result: (Const8   [int64(int8(c))])
 	for {
-		x := v.Args[0]
-		if x != v.Args[1] {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c))
 		return true
 	}
-	// match: (Sub32 (Add32 x y) x)
+	// match: (Trunc64to8 (ZeroExt8to64 x))
 	// cond:
-	// result: y
+	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd32 {
+		if v_0.Op != OpZeroExt8to64 {
 			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)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Sub32 (Add32 x y) y)
+	// match: (Trunc64to8 (SignExt8to64 x))
 	// cond:
 	// result: x
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd32 {
+		if v_0.Op != OpSignExt8to64 {
 			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)))])
+	// match: (Trunc64to8 (And64 (Const64 [y]) x))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc64to8 x)
 	for {
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32F {
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst32F)
-		v.AuxInt = f2i(float64(i2f32(c) - i2f32(d)))
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc64to8)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Sub32F x (Const32F [0]))
-	// cond:
-	// result: x
+	// match: (Trunc64to8 (And64 x (Const64 [y])))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc64to8 x)
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32F {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
 			break
 		}
-		if v_1.AuxInt != 0 {
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		y := v_0_1.AuxInt
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc64to8)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpSub64(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor16_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Sub64  (Const64 [c]) (Const64 [d]))
+	// match: (Xor16 (Const16 [c]) (Const16 [d]))
 	// cond:
-	// result: (Const64 [c-d])
+	// result: (Const16 [int64(int16(c^d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst16 {
 			break
 		}
 		c := v_0.AuxInt
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		if v_1.Op != OpConst16 {
 			break
 		}
 		d := v_1.AuxInt
-		v.reset(OpConst64)
-		v.AuxInt = c - d
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c ^ d))
 		return true
 	}
-	// match: (Sub64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Add64 (Const64 <t> [-c]) x)
+	// match: (Xor16 (Const16 [d]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [int64(int16(c^d))])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst64 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		v.reset(OpAdd64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = -c
-		v.AddArg(v0)
-		v.AddArg(x)
+		c := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c ^ d))
 		return true
 	}
-	// match: (Sub64 x x)
+	// match: (Xor16 x x)
 	// cond:
-	// result: (Const64 [0])
+	// result: (Const16 [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
+		v.reset(OpConst16)
 		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)
+	// match: (Xor16 (Const16 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd64 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		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_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
-	}
-	// match: (Sub64F x (Const64F [0]))
+	// match: (Xor16 x (Const16 [0]))
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst64F {
+		if v_1.Op != OpConst16 {
 			break
 		}
 		if v_1.AuxInt != 0 {
@@ -11061,72 +24290,78 @@ func rewriteValuegeneric_OpSub64F(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpSub8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Sub8   (Const8 [c]) (Const8 [d]))
+	// match: (Xor16 x (Xor16 x y))
 	// cond:
-	// result: (Const8 [int64(int8(c-d))])
+	// result: y
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
 			break
 		}
-		c := v_0.AuxInt
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v_1.Args[1]
+		if x != v_1.Args[0] {
 			break
 		}
-		d := v_1.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c - d))
+		y := v_1.Args[1]
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Sub8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Add8  (Const8  <t> [int64(int8(-c))]) x)
+	// match: (Xor16 x (Xor16 y x))
+	// cond:
+	// result: y
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		if v_1.Op != OpXor16 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		v.reset(OpAdd8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = int64(int8(-c))
-		v.AddArg(v0)
-		v.AddArg(x)
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Sub8  x x)
+	// match: (Xor16 (Xor16 x y) x)
 	// cond:
-	// result: (Const8  [0])
+	// result: y
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor16 {
+			break
+		}
+		_ = v_0.Args[1]
+		x := v_0.Args[0]
+		y := v_0.Args[1]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Sub8  (Add8  x y) x)
+	// match: (Xor16 (Xor16 y x) x)
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd8 {
+		if v_0.Op != OpXor16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
 		if x != v.Args[1] {
 			break
 		}
@@ -11135,574 +24370,731 @@ func rewriteValuegeneric_OpSub8(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Sub8  (Add8  x y) y)
-	// cond:
-	// result: x
+	// match: (Xor16 (Xor16 i:(Const16 <t>) z) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Xor16 i (Xor16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAdd8 {
+		if v_0.Op != OpXor16 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst16 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpXor16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpTrunc16to8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor16_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Trunc16to8  (Const16 [c]))
-	// cond:
-	// result: (Const8   [int64(int8(c))])
+	// match: (Xor16 (Xor16 z i:(Const16 <t>)) x)
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Xor16 i (Xor16 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpXor16 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c))
-		return true
-	}
-	// match: (Trunc16to8  (ZeroExt8to16  x))
-	// cond:
-	// result: x
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to16 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpXor16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Trunc16to8  (SignExt8to16  x))
-	// cond:
-	// result: x
+	// match: (Xor16 x (Xor16 i:(Const16 <t>) z))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Xor16 i (Xor16 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to16 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst16 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpXor16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Trunc16to8  (And16 (Const16 [y]) x))
-	// cond: y&0xFF == 0xFF
-	// result: (Trunc16to8 x)
+	// match: (Xor16 x (Xor16 z i:(Const16 <t>)))
+	// cond: (z.Op != OpConst16 && x.Op != OpConst16)
+	// result: (Xor16 i (Xor16 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpAnd16 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst16 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst16 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFF == 0xFF) {
+		t := i.Type
+		if !(z.Op != OpConst16 && x.Op != OpConst16) {
 			break
 		}
-		v.reset(OpTrunc16to8)
-		v.AddArg(x)
+		v.reset(OpXor16)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor16, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpTrunc32to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc32to16 (Const32 [c]))
+	// match: (Xor16 (Const16 <t> [c]) (Xor16 (Const16 <t> [d]) x))
 	// cond:
-	// result: (Const16  [int64(int16(c))])
+	// result: (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c))
-		return true
-	}
-	// match: (Trunc32to16 (ZeroExt8to32  x))
-	// cond:
-	// result: (ZeroExt8to16  x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to32 {
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpZeroExt8to16)
+		_ = v_1.Args[1]
+		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(OpXor16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc32to16 (ZeroExt16to32 x))
+	// match: (Xor16 (Const16 <t> [c]) (Xor16 x (Const16 <t> [d])))
 	// cond:
-	// result: x
+	// result: (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt16to32 {
+		if v_0.Op != OpConst16 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst16 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpXor16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc32to16 (SignExt8to32  x))
+	// match: (Xor16 (Xor16 (Const16 <t> [d]) x) (Const16 <t> [c]))
 	// cond:
-	// result: (SignExt8to16  x)
+	// result: (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to32 {
+		if v_0.Op != OpXor16 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpSignExt8to16)
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc32to16 (SignExt16to32 x))
+	// match: (Xor16 (Xor16 x (Const16 <t> [d])) (Const16 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt16to32 {
+		if v_0.Op != OpXor16 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		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 {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst16 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst32 {
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFFFF == 0xFFFF) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpTrunc32to16)
+		c := v_1.AuxInt
+		v.reset(OpXor16)
+		v0 := b.NewValue0(v.Pos, OpConst16, t)
+		v0.AuxInt = int64(int16(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpTrunc32to8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor32_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Trunc32to8  (Const32 [c]))
+	// match: (Xor32 (Const32 [c]) (Const32 [d]))
 	// cond:
-	// result: (Const8   [int64(int8(c))])
+	// result: (Const32 [int64(int32(c^d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpConst32 {
 			break
 		}
 		c := v_0.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c))
+		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: (Trunc32to8  (ZeroExt8to32  x))
+	// match: (Xor32 (Const32 [d]) (Const32 [c]))
 	// cond:
-	// result: x
+	// result: (Const32 [int64(int32(c^d))])
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to32 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c ^ d))
 		return true
 	}
-	// match: (Trunc32to8  (SignExt8to32  x))
+	// match: (Xor32 x x)
 	// cond:
-	// result: x
+	// result: (Const32 [0])
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		if x != v.Args[1] {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.reset(OpConst32)
+		v.AuxInt = 0
 		return true
 	}
-	// match: (Trunc32to8  (And32 (Const32 [y]) x))
-	// cond: y&0xFF == 0xFF
-	// result: (Trunc32to8 x)
+	// match: (Xor32 (Const32 [0]) x)
+	// cond:
+	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd32 {
-			break
-		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst32 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFF == 0xFF) {
+		if v_0.AuxInt != 0 {
 			break
 		}
-		v.reset(OpTrunc32to8)
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpTrunc64to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc64to16 (Const64 [c]))
+	// match: (Xor32 x (Const32 [0]))
 	// cond:
-	// result: (Const16  [int64(int16(c))])
+	// result: x
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpConst16)
-		v.AuxInt = int64(int16(c))
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc64to16 (ZeroExt8to64  x))
+	// match: (Xor32 x (Xor32 x y))
 	// cond:
-	// result: (ZeroExt8to16  x)
+	// result: y
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpZeroExt8to16)
-		v.AddArg(x)
+		_ = v_1.Args[1]
+		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: (Trunc64to16 (ZeroExt16to64 x))
+	// match: (Xor32 x (Xor32 y x))
 	// cond:
-	// result: x
+	// result: y
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt16to64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
+			break
+		}
+		_ = v_1.Args[1]
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
 			break
 		}
-		x := v_0.Args[0]
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Trunc64to16 (SignExt8to64  x))
+	// match: (Xor32 (Xor32 x y) x)
 	// cond:
-	// result: (SignExt8to16  x)
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to64 {
+		if v_0.Op != OpXor32 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpSignExt8to16)
-		v.AddArg(x)
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Trunc64to16 (SignExt16to64 x))
+	// match: (Xor32 (Xor32 y x) x)
 	// cond:
-	// result: x
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt16to64 {
+		if v_0.Op != OpXor32 {
+			break
+		}
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
-		x := v_0.Args[0]
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.Type = y.Type
+		v.AddArg(y)
 		return true
 	}
-	// match: (Trunc64to16 (And64 (Const64 [y]) x))
-	// cond: y&0xFFFF == 0xFFFF
-	// result: (Trunc64to16 x)
+	// match: (Xor32 (Xor32 i:(Const32 <t>) z) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Xor32 i (Xor32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpAnd64 {
+		if v_0.Op != OpXor32 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst64 {
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFFFF == 0xFFFF) {
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		v.reset(OpTrunc64to16)
-		v.AddArg(x)
+		v.reset(OpXor32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpTrunc64to32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor32_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Trunc64to32 (Const64 [c]))
-	// cond:
-	// result: (Const32  [int64(int32(c))])
+	// match: (Xor32 (Xor32 z i:(Const32 <t>)) x)
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Xor32 i (Xor32 <t> z x))
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpXor32 {
 			break
 		}
-		c := v_0.AuxInt
-		v.reset(OpConst32)
-		v.AuxInt = int64(int32(c))
-		return true
-	}
-	// match: (Trunc64to32 (ZeroExt8to64  x))
-	// cond:
-	// result: (ZeroExt8to32  x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to64 {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpZeroExt8to32)
-		v.AddArg(x)
-		return true
-	}
-	// match: (Trunc64to32 (ZeroExt16to64 x))
-	// cond:
-	// result: (ZeroExt16to32 x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt16to64 {
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpZeroExt16to32)
-		v.AddArg(x)
+		v.reset(OpXor32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Trunc64to32 (ZeroExt32to64 x))
-	// cond:
-	// result: x
+	// match: (Xor32 x (Xor32 i:(Const32 <t>) z))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Xor32 i (Xor32 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt32to64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		return true
-	}
-	// match: (Trunc64to32 (SignExt8to64  x))
-	// cond:
-	// result: (SignExt8to32  x)
-	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to64 {
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpSignExt8to32)
-		v.AddArg(x)
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpXor32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Trunc64to32 (SignExt16to64 x))
-	// cond:
-	// result: (SignExt16to32 x)
+	// match: (Xor32 x (Xor32 z i:(Const32 <t>)))
+	// cond: (z.Op != OpConst32 && x.Op != OpConst32)
+	// result: (Xor32 i (Xor32 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt16to64 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpSignExt16to32)
-		v.AddArg(x)
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst32 {
+			break
+		}
+		t := i.Type
+		if !(z.Op != OpConst32 && x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpXor32)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor32, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Trunc64to32 (SignExt32to64 x))
+	// match: (Xor32 (Const32 <t> [c]) (Xor32 (Const32 <t> [d]) x))
 	// cond:
-	// result: x
+	// result: (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt32to64 {
+		if v_0.Op != OpConst32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		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 {
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst64 {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFFFFFFFF == 0xFFFFFFFF) {
+		if v_1_0.Type != t {
 			break
 		}
-		v.reset(OpTrunc64to32)
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpXor32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	return false
-}
-func rewriteValuegeneric_OpTrunc64to8(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (Trunc64to8  (Const64 [c]))
+	// match: (Xor32 (Const32 <t> [c]) (Xor32 x (Const32 <t> [d])))
 	// cond:
-	// result: (Const8   [int64(int8(c))])
+	// result: (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst32 {
 			break
 		}
+		t := v_0.Type
 		c := v_0.AuxInt
-		v.reset(OpConst8)
-		v.AuxInt = int64(int8(c))
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
+			break
+		}
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst32 {
+			break
+		}
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpXor32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c ^ d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc64to8  (ZeroExt8to64  x))
+	// match: (Xor32 (Xor32 (Const32 <t> [d]) x) (Const32 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpZeroExt8to64 {
+		if v_0.Op != OpXor32 {
 			break
 		}
-		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
-	// match: (Trunc64to8  (SignExt8to64  x))
+	// match: (Xor32 (Xor32 x (Const32 <t> [d])) (Const32 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpSignExt8to64 {
+		if v_0.Op != OpXor32 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
-		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 {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst32 {
 			break
 		}
-		v_0_0 := v_0.Args[0]
-		if v_0_0.Op != OpConst64 {
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
 			break
 		}
-		y := v_0_0.AuxInt
-		x := v_0.Args[1]
-		if !(y&0xFF == 0xFF) {
+		if v_1.Type != t {
 			break
 		}
-		v.reset(OpTrunc64to8)
+		c := v_1.AuxInt
+		v.reset(OpXor32)
+		v0 := b.NewValue0(v.Pos, OpConst32, t)
+		v0.AuxInt = int64(int32(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor64_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Xor16 x (Const16 <t> [c]))
-	// cond: x.Op != OpConst16
-	// result: (Xor16 (Const16 <t> [c]) x)
+	// match: (Xor64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c^d])
+	for {
+		_ = v.Args[1]
+		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: (Xor64 (Const64 [d]) (Const64 [c]))
+	// cond:
+	// result: (Const64 [c^d])
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst16 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst16) {
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpXor16)
-		v0 := b.NewValue0(v.Line, OpConst16, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		c := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c ^ d
 		return true
 	}
-	// match: (Xor16 x x)
+	// match: (Xor64 x x)
 	// cond:
-	// result: (Const16 [0])
+	// result: (Const64 [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst16)
+		v.reset(OpConst64)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Xor16 (Const16 [0]) x)
+	// match: (Xor64 (Const64 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst16 {
+		if v_0.Op != OpConst64 {
 			break
 		}
 		if v_0.AuxInt != 0 {
@@ -11714,15 +25106,35 @@ func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Xor16 x (Xor16 x y))
+	// match: (Xor64 x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		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: (Xor64 x (Xor64 x y))
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpXor16 {
+		if v_1.Op != OpXor64 {
 			break
 		}
+		_ = v_1.Args[1]
 		if x != v_1.Args[0] {
 			break
 		}
@@ -11732,15 +25144,17 @@ func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor16 x (Xor16 y x))
+	// match: (Xor64 x (Xor64 y x))
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpXor16 {
+		if v_1.Op != OpXor64 {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		if x != v_1.Args[1] {
 			break
@@ -11750,14 +25164,16 @@ func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor16 (Xor16 x y) x)
+	// match: (Xor64 (Xor64 x y) x)
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor16 {
+		if v_0.Op != OpXor64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if x != v.Args[1] {
@@ -11768,195 +25184,334 @@ func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor16 (Xor16 x y) y)
+	// match: (Xor64 (Xor64 y x) x)
 	// cond:
-	// result: x
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor16 {
+		if v_0.Op != OpXor64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor64 (Xor64 i:(Const64 <t>) z) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Xor64 i (Xor64 <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor64 {
+			break
+		}
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpXor64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpXor32(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor64_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Xor32 x (Const32 <t> [c]))
-	// cond: x.Op != OpConst32
-	// result: (Xor32 (Const32 <t> [c]) x)
+	// match: (Xor64 (Xor64 z i:(Const64 <t>)) x)
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Xor64 i (Xor64 <t> z x))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst32 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor64 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst32) {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		v.reset(OpXor32)
-		v0 := b.NewValue0(v.Line, OpConst32, t)
-		v0.AuxInt = c
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpXor64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Xor32 x x)
-	// cond:
-	// result: (Const32 [0])
+	// match: (Xor64 x (Xor64 i:(Const64 <t>) z))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Xor64 i (Xor64 <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor64 {
 			break
 		}
-		v.reset(OpConst32)
-		v.AuxInt = 0
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst64 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpXor64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Xor32 (Const32 [0]) x)
-	// cond:
-	// result: x
+	// match: (Xor64 x (Xor64 z i:(Const64 <t>)))
+	// cond: (z.Op != OpConst64 && x.Op != OpConst64)
+	// result: (Xor64 i (Xor64 <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst32 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor64 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst64 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		if !(z.Op != OpConst64 && x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpXor64)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor64, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Xor32 x (Xor32 x y))
+	// match: (Xor64 (Const64 <t> [c]) (Xor64 (Const64 <t> [d]) x))
 	// cond:
-	// result: y
+	// result: (Xor64 (Const64 <t> [c^d]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpXor32 {
+		if v_1.Op != OpXor64 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpXor64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c ^ d
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor32 x (Xor32 y x))
+	// match: (Xor64 (Const64 <t> [c]) (Xor64 x (Const64 <t> [d])))
 	// cond:
-	// result: y
+	// result: (Xor64 (Const64 <t> [c^d]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpXor32 {
+		if v_1.Op != OpXor64 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpXor64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c ^ d
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor32 (Xor32 x y) x)
+	// match: (Xor64 (Xor64 (Const64 <t> [d]) x) (Const64 <t> [c]))
 	// cond:
-	// result: y
+	// result: (Xor64 (Const64 <t> [c^d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor32 {
+		if v_0.Op != OpXor64 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if x != v.Args[1] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c ^ d
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor32 (Xor32 x y) y)
+	// match: (Xor64 (Xor64 x (Const64 <t> [d])) (Const64 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Xor64 (Const64 <t> [c^d]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor32 {
+		if v_0.Op != OpXor64 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor64)
+		v0 := b.NewValue0(v.Pos, OpConst64, t)
+		v0.AuxInt = c ^ d
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor8_0(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Xor64 x (Const64 <t> [c]))
-	// cond: x.Op != OpConst64
-	// result: (Xor64 (Const64 <t> [c]) x)
+	// match: (Xor8 (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c^d))])
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 {
+		if v_1.Op != OpConst8 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst64) {
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c ^ d))
+		return true
+	}
+	// match: (Xor8 (Const8 [d]) (Const8 [c]))
+	// cond:
+	// result: (Const8  [int64(int8(c^d))])
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
 			break
 		}
-		v.reset(OpXor64)
-		v0 := b.NewValue0(v.Line, OpConst64, t)
-		v0.AuxInt = c
-		v.AddArg(v0)
-		v.AddArg(x)
+		d := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c ^ d))
 		return true
 	}
-	// match: (Xor64 x x)
+	// match: (Xor8 x x)
 	// cond:
-	// result: (Const64 [0])
+	// result: (Const8  [0])
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		if x != v.Args[1] {
 			break
 		}
-		v.reset(OpConst64)
+		v.reset(OpConst8)
 		v.AuxInt = 0
 		return true
 	}
-	// match: (Xor64 (Const64 [0]) x)
+	// match: (Xor8 (Const8 [0]) x)
 	// cond:
 	// result: x
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpConst64 {
+		if v_0.Op != OpConst8 {
 			break
 		}
 		if v_0.AuxInt != 0 {
@@ -11968,15 +25523,35 @@ func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
 		v.AddArg(x)
 		return true
 	}
-	// match: (Xor64 x (Xor64 x y))
+	// match: (Xor8 x (Const8 [0]))
+	// cond:
+	// result: x
+	for {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor8 x (Xor8 x y))
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpXor64 {
+		if v_1.Op != OpXor8 {
 			break
 		}
+		_ = v_1.Args[1]
 		if x != v_1.Args[0] {
 			break
 		}
@@ -11986,15 +25561,17 @@ func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor64 x (Xor64 y x))
+	// match: (Xor8 x (Xor8 y x))
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
 		v_1 := v.Args[1]
-		if v_1.Op != OpXor64 {
+		if v_1.Op != OpXor8 {
 			break
 		}
+		_ = v_1.Args[1]
 		y := v_1.Args[0]
 		if x != v_1.Args[1] {
 			break
@@ -12004,14 +25581,16 @@ func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor64 (Xor64 x y) x)
+	// match: (Xor8 (Xor8 x y) x)
 	// cond:
 	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor64 {
+		if v_0.Op != OpXor8 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
 		y := v_0.Args[1]
 		if x != v.Args[1] {
@@ -12022,164 +25601,288 @@ func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
 		v.AddArg(y)
 		return true
 	}
-	// match: (Xor64 (Xor64 x y) y)
+	// match: (Xor8 (Xor8 y x) x)
 	// cond:
-	// result: x
+	// result: y
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
-		if v_0.Op != OpXor64 {
+		if v_0.Op != OpXor8 {
 			break
 		}
-		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		_ = v_0.Args[1]
+		y := v_0.Args[0]
+		x := v_0.Args[1]
+		if x != v.Args[1] {
 			break
 		}
 		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor8 (Xor8 i:(Const8 <t>) z) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Xor8  i (Xor8  <t> z x))
+	for {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor8 {
+			break
+		}
+		_ = v_0.Args[1]
+		i := v_0.Args[0]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		z := v_0.Args[1]
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpXor8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpXor8(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpXor8_10(v *Value) bool {
 	b := v.Block
 	_ = b
-	// match: (Xor8  x (Const8  <t> [c]))
-	// cond: x.Op != OpConst8
-	// result: (Xor8  (Const8  <t> [c]) x)
+	// match: (Xor8 (Xor8 z i:(Const8 <t>)) x)
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Xor8  i (Xor8  <t> z x))
 	for {
-		x := v.Args[0]
-		v_1 := v.Args[1]
-		if v_1.Op != OpConst8 {
+		_ = v.Args[1]
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor8 {
 			break
 		}
-		t := v_1.Type
-		c := v_1.AuxInt
-		if !(x.Op != OpConst8) {
+		_ = v_0.Args[1]
+		z := v_0.Args[0]
+		i := v_0.Args[1]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		x := v.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
 			break
 		}
 		v.reset(OpXor8)
-		v0 := b.NewValue0(v.Line, OpConst8, t)
-		v0.AuxInt = c
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
 		v.AddArg(v0)
-		v.AddArg(x)
 		return true
 	}
-	// match: (Xor8  x x)
-	// cond:
-	// result: (Const8  [0])
+	// match: (Xor8 x (Xor8 i:(Const8 <t>) z))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Xor8  i (Xor8  <t> z x))
 	for {
+		_ = v.Args[1]
 		x := v.Args[0]
-		if x != v.Args[1] {
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor8 {
 			break
 		}
-		v.reset(OpConst8)
-		v.AuxInt = 0
+		_ = v_1.Args[1]
+		i := v_1.Args[0]
+		if i.Op != OpConst8 {
+			break
+		}
+		t := i.Type
+		z := v_1.Args[1]
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpXor8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Xor8  (Const8  [0]) x)
-	// cond:
-	// result: x
+	// match: (Xor8 x (Xor8 z i:(Const8 <t>)))
+	// cond: (z.Op != OpConst8  && x.Op != OpConst8)
+	// result: (Xor8  i (Xor8  <t> z x))
 	for {
-		v_0 := v.Args[0]
-		if v_0.Op != OpConst8 {
+		_ = v.Args[1]
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor8 {
 			break
 		}
-		if v_0.AuxInt != 0 {
+		_ = v_1.Args[1]
+		z := v_1.Args[0]
+		i := v_1.Args[1]
+		if i.Op != OpConst8 {
 			break
 		}
-		x := v.Args[1]
-		v.reset(OpCopy)
-		v.Type = x.Type
-		v.AddArg(x)
+		t := i.Type
+		if !(z.Op != OpConst8 && x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpXor8)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Pos, OpXor8, t)
+		v0.AddArg(z)
+		v0.AddArg(x)
+		v.AddArg(v0)
 		return true
 	}
-	// match: (Xor8  x (Xor8  x y))
+	// match: (Xor8 (Const8 <t> [c]) (Xor8 (Const8 <t> [d]) x))
 	// cond:
-	// result: y
+	// result: (Xor8  (Const8  <t> [int64(int8(c^d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpXor8 {
 			break
 		}
-		if x != v_1.Args[0] {
+		_ = v_1.Args[1]
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
 			break
 		}
-		y := v_1.Args[1]
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpXor8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c ^ d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor8  x (Xor8  y x))
+	// match: (Xor8 (Const8 <t> [c]) (Xor8 x (Const8 <t> [d])))
 	// cond:
-	// result: y
+	// result: (Xor8  (Const8  <t> [int64(int8(c^d))]) x)
 	for {
-		x := v.Args[0]
+		_ = v.Args[1]
+		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 != OpXor8 {
 			break
 		}
-		y := v_1.Args[0]
-		if x != v_1.Args[1] {
+		_ = v_1.Args[1]
+		x := v_1.Args[0]
+		v_1_1 := v_1.Args[1]
+		if v_1_1.Op != OpConst8 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		if v_1_1.Type != t {
+			break
+		}
+		d := v_1_1.AuxInt
+		v.reset(OpXor8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c ^ d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor8  (Xor8  x y) x)
+	// match: (Xor8 (Xor8 (Const8 <t> [d]) x) (Const8 <t> [c]))
 	// cond:
-	// result: y
+	// result: (Xor8  (Const8  <t> [int64(int8(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		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] {
+		_ = v_0.Args[1]
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst8 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = y.Type
-		v.AddArg(y)
+		t := v_0_0.Type
+		d := v_0_0.AuxInt
+		x := v_0.Args[1]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c ^ d))
+		v.AddArg(v0)
+		v.AddArg(x)
 		return true
 	}
-	// match: (Xor8  (Xor8  x y) y)
+	// match: (Xor8 (Xor8 x (Const8 <t> [d])) (Const8 <t> [c]))
 	// cond:
-	// result: x
+	// result: (Xor8  (Const8  <t> [int64(int8(c^d))]) x)
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpXor8 {
 			break
 		}
+		_ = v_0.Args[1]
 		x := v_0.Args[0]
-		y := v_0.Args[1]
-		if y != v.Args[1] {
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst8 {
 			break
 		}
-		v.reset(OpCopy)
-		v.Type = x.Type
+		t := v_0_1.Type
+		d := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpXor8)
+		v0 := b.NewValue0(v.Pos, OpConst8, t)
+		v0.AuxInt = int64(int8(c ^ d))
+		v.AddArg(v0)
 		v.AddArg(x)
 		return true
 	}
 	return false
 }
-func rewriteValuegeneric_OpZero(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpZero_0(v *Value) bool {
 	b := v.Block
 	_ = b
+	config := b.Func.Config
+	_ = config
 	// match: (Zero (Load (OffPtr [c] (SP)) mem) mem)
-	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.PtrSize
+	// cond: mem.Op == OpStaticCall 	&& isSameSym(mem.Aux, "runtime.newobject") 	&& c == config.ctxt.FixedFrameSize() + config.RegSize
 	// result: mem
 	for {
+		_ = v.Args[1]
 		v_0 := v.Args[0]
 		if v_0.Op != OpLoad {
 			break
 		}
+		_ = v_0.Args[1]
 		v_0_0 := v_0.Args[0]
 		if v_0_0.Op != OpOffPtr {
 			break
@@ -12193,7 +25896,7 @@ func rewriteValuegeneric_OpZero(v *Value, config *Config) bool {
 		if mem != v.Args[1] {
 			break
 		}
-		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.PtrSize) {
+		if !(mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) {
 			break
 		}
 		v.reset(OpCopy)
@@ -12203,9 +25906,20 @@ func rewriteValuegeneric_OpZero(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt16to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuegeneric_OpZeroExt16to32_0(v *Value) bool {
+	// match: (ZeroExt16to32 (Const16 [c]))
+	// cond:
+	// result: (Const32 [int64(uint16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(uint16(c))
+		return true
+	}
 	// match: (ZeroExt16to32 (Trunc32to16 x:(Rsh32Ux64 _ (Const64 [s]))))
 	// cond: s >= 16
 	// result: x
@@ -12218,6 +25932,7 @@ func rewriteValuegeneric_OpZeroExt16to32(v *Value, config *Config) bool {
 		if x.Op != OpRsh32Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12233,9 +25948,20 @@ func rewriteValuegeneric_OpZeroExt16to32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt16to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuegeneric_OpZeroExt16to64_0(v *Value) bool {
+	// match: (ZeroExt16to64 (Const16 [c]))
+	// cond:
+	// result: (Const64 [int64(uint16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint16(c))
+		return true
+	}
 	// match: (ZeroExt16to64 (Trunc64to16 x:(Rsh64Ux64 _ (Const64 [s]))))
 	// cond: s >= 48
 	// result: x
@@ -12248,6 +25974,7 @@ func rewriteValuegeneric_OpZeroExt16to64(v *Value, config *Config) bool {
 		if x.Op != OpRsh64Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12263,9 +25990,20 @@ func rewriteValuegeneric_OpZeroExt16to64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt32to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
+func rewriteValuegeneric_OpZeroExt32to64_0(v *Value) bool {
+	// match: (ZeroExt32to64 (Const32 [c]))
+	// cond:
+	// result: (Const64 [int64(uint32(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint32(c))
+		return true
+	}
 	// match: (ZeroExt32to64 (Trunc64to32 x:(Rsh64Ux64 _ (Const64 [s]))))
 	// cond: s >= 32
 	// result: x
@@ -12278,6 +26016,7 @@ func rewriteValuegeneric_OpZeroExt32to64(v *Value, config *Config) bool {
 		if x.Op != OpRsh64Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12293,10 +26032,21 @@ func rewriteValuegeneric_OpZeroExt32to64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt8to16(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to16  (Trunc16to8  x:(Rsh16Ux64 _ (Const64 [s]))))
+func rewriteValuegeneric_OpZeroExt8to16_0(v *Value) bool {
+	// match: (ZeroExt8to16 (Const8 [c]))
+	// cond:
+	// result: (Const16 [int64( uint8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(uint8(c))
+		return true
+	}
+	// match: (ZeroExt8to16 (Trunc16to8 x:(Rsh16Ux64 _ (Const64 [s]))))
 	// cond: s >= 8
 	// result: x
 	for {
@@ -12308,6 +26058,7 @@ func rewriteValuegeneric_OpZeroExt8to16(v *Value, config *Config) bool {
 		if x.Op != OpRsh16Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12323,10 +26074,21 @@ func rewriteValuegeneric_OpZeroExt8to16(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt8to32(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to32  (Trunc32to8  x:(Rsh32Ux64 _ (Const64 [s]))))
+func rewriteValuegeneric_OpZeroExt8to32_0(v *Value) bool {
+	// match: (ZeroExt8to32 (Const8 [c]))
+	// cond:
+	// result: (Const32 [int64( uint8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(uint8(c))
+		return true
+	}
+	// match: (ZeroExt8to32 (Trunc32to8 x:(Rsh32Ux64 _ (Const64 [s]))))
 	// cond: s >= 24
 	// result: x
 	for {
@@ -12338,6 +26100,7 @@ func rewriteValuegeneric_OpZeroExt8to32(v *Value, config *Config) bool {
 		if x.Op != OpRsh32Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12353,10 +26116,21 @@ func rewriteValuegeneric_OpZeroExt8to32(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteValuegeneric_OpZeroExt8to64(v *Value, config *Config) bool {
-	b := v.Block
-	_ = b
-	// match: (ZeroExt8to64  (Trunc64to8  x:(Rsh64Ux64 _ (Const64 [s]))))
+func rewriteValuegeneric_OpZeroExt8to64_0(v *Value) bool {
+	// match: (ZeroExt8to64 (Const8 [c]))
+	// cond:
+	// result: (Const64 [int64( uint8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint8(c))
+		return true
+	}
+	// match: (ZeroExt8to64 (Trunc64to8 x:(Rsh64Ux64 _ (Const64 [s]))))
 	// cond: s >= 56
 	// result: x
 	for {
@@ -12368,6 +26142,7 @@ func rewriteValuegeneric_OpZeroExt8to64(v *Value, config *Config) bool {
 		if x.Op != OpRsh64Ux64 {
 			break
 		}
+		_ = x.Args[1]
 		x_1 := x.Args[1]
 		if x_1.Op != OpConst64 {
 			break
@@ -12383,7 +26158,13 @@ func rewriteValuegeneric_OpZeroExt8to64(v *Value, config *Config) bool {
 	}
 	return false
 }
-func rewriteBlockgeneric(b *Block, config *Config) bool {
+func rewriteBlockgeneric(b *Block) bool {
+	config := b.Func.Config
+	_ = config
+	fe := b.Func.fe
+	_ = fe
+	typ := &config.Types
+	_ = typ
 	switch b.Kind {
 	case BlockIf:
 		// match: (If (Not cond) yes no)
@@ -12395,13 +26176,9 @@ func rewriteBlockgeneric(b *Block, config *Config) bool {
 				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)
@@ -12413,15 +26190,11 @@ func rewriteBlockgeneric(b *Block, config *Config) bool {
 				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)
@@ -12433,16 +26206,12 @@ func rewriteBlockgeneric(b *Block, config *Config) bool {
 				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
 		}
 	}
diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
index 78b61f0..c44c243 100644
--- a/src/cmd/compile/internal/ssa/schedule.go
+++ b/src/cmd/compile/internal/ssa/schedule.go
@@ -14,7 +14,6 @@ const (
 	ScoreMemory
 	ScoreDefault
 	ScoreFlags
-	ScoreSelectCall
 	ScoreControl // towards bottom of block
 )
 
@@ -47,8 +46,8 @@ func (h ValHeap) Less(i, j int) bool {
 	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.Pos != y.Pos { // Favor in-order line stepping
+		return x.Pos.After(y.Pos)
 	}
 	if x.Op != OpPhi {
 		if c := len(x.Args) - len(y.Args); c != 0 {
@@ -111,25 +110,10 @@ func schedule(f *Func) {
 				// We want all the vardefs next.
 				score[v.ID] = ScoreVarDef
 			case v.Type.IsMemory():
-				// Don't schedule independent operations after call to those functions.
-				// runtime.selectgo will jump to next instruction after this call,
-				// causing extra execution of those operations. Prevent it, by setting
-				// priority to high value.
-				if (v.Op == OpAMD64CALLstatic || v.Op == OpPPC64CALLstatic ||
-					v.Op == OpARMCALLstatic || v.Op == OpARM64CALLstatic ||
-					v.Op == Op386CALLstatic || v.Op == OpMIPS64CALLstatic ||
-					v.Op == OpS390XCALLstatic || v.Op == OpMIPSCALLstatic) &&
-					(isSameSym(v.Aux, "runtime.selectrecv") ||
-						isSameSym(v.Aux, "runtime.selectrecv2") ||
-						isSameSym(v.Aux, "runtime.selectsend") ||
-						isSameSym(v.Aux, "runtime.selectdefault")) {
-					score[v.ID] = ScoreSelectCall
-				} else {
-					// 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
-				}
+				// 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.Op == OpSelect0 || v.Op == OpSelect1:
 				// Schedule the pseudo-op of reading part of a tuple
 				// immediately after the tuple-generating op, since
@@ -148,19 +132,14 @@ func schedule(f *Func) {
 		}
 	}
 
-	// TODO: make this logic permanent in types.IsMemory?
-	isMem := func(v *Value) bool {
-		return v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory()
-	}
-
 	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 && isMem(v) {
+			if v.Op != OpPhi && v.Type.IsMemory() {
 				for _, w := range v.Args {
-					if isMem(w) {
+					if w.Type.IsMemory() {
 						nextMem[w.ID] = v
 					}
 				}
@@ -180,7 +159,7 @@ func schedule(f *Func) {
 					uses[w.ID]++
 				}
 				// Any load must come before the following store.
-				if !isMem(v) && isMem(w) {
+				if !v.Type.IsMemory() && w.Type.IsMemory() {
 					// v is a load.
 					s := nextMem[w.ID]
 					if s == nil || s.Block != b {
@@ -294,3 +273,160 @@ func schedule(f *Func) {
 
 	f.scheduled = true
 }
+
+// storeOrder orders values with respect to stores. That is,
+// if v transitively depends on store s, v is ordered after s,
+// otherwise v is ordered before s.
+// Specifically, values are ordered like
+//   store1
+//   NilCheck that depends on store1
+//   other values that depends on store1
+//   store2
+//   NilCheck that depends on store2
+//   other values that depends on store2
+//   ...
+// The order of non-store and non-NilCheck values are undefined
+// (not necessarily dependency order). This should be cheaper
+// than a full scheduling as done above.
+// Note that simple dependency order won't work: there is no
+// dependency between NilChecks and values like IsNonNil.
+// Auxiliary data structures are passed in as arguments, so
+// that they can be allocated in the caller and be reused.
+// This function takes care of reset them.
+func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value {
+	if len(values) == 0 {
+		return values
+	}
+
+	f := values[0].Block.Func
+
+	// find all stores
+	var stores []*Value // members of values that are store values
+	hasNilCheck := false
+	sset.clear() // sset is the set of stores that are used in other values
+	for _, v := range values {
+		if v.Type.IsMemory() {
+			stores = append(stores, v)
+			if v.Op == OpInitMem || v.Op == OpPhi {
+				continue
+			}
+			sset.add(v.MemoryArg().ID) // record that v's memory arg is used
+		}
+		if v.Op == OpNilCheck {
+			hasNilCheck = true
+		}
+	}
+	if len(stores) == 0 || !hasNilCheck && f.pass.name == "nilcheckelim" {
+		// there is no store, the order does not matter
+		return values
+	}
+
+	// find last store, which is the one that is not used by other stores
+	var last *Value
+	for _, v := range stores {
+		if !sset.contains(v.ID) {
+			if last != nil {
+				f.Fatalf("two stores live simultaneously: %v and %v", v, last)
+			}
+			last = v
+		}
+	}
+
+	// We assign a store number to each value. Store number is the
+	// index of the latest store that this value transitively depends.
+	// The i-th store in the current block gets store number 3*i. A nil
+	// check that depends on the i-th store gets store number 3*i+1.
+	// Other values that depends on the i-th store gets store number 3*i+2.
+	// Special case: 0 -- unassigned, 1 or 2 -- the latest store it depends
+	// is in the previous block (or no store at all, e.g. value is Const).
+	// First we assign the number to all stores by walking back the store chain,
+	// then assign the number to other values in DFS order.
+	count := make([]int32, 3*(len(stores)+1))
+	sset.clear() // reuse sparse set to ensure that a value is pushed to stack only once
+	for n, w := len(stores), last; n > 0; n-- {
+		storeNumber[w.ID] = int32(3 * n)
+		count[3*n]++
+		sset.add(w.ID)
+		if w.Op == OpInitMem || w.Op == OpPhi {
+			if n != 1 {
+				f.Fatalf("store order is wrong: there are stores before %v", w)
+			}
+			break
+		}
+		w = w.MemoryArg()
+	}
+	var stack []*Value
+	for _, v := range values {
+		if sset.contains(v.ID) {
+			// in sset means v is a store, or already pushed to stack, or already assigned a store number
+			continue
+		}
+		stack = append(stack, v)
+		sset.add(v.ID)
+
+		for len(stack) > 0 {
+			w := stack[len(stack)-1]
+			if storeNumber[w.ID] != 0 {
+				stack = stack[:len(stack)-1]
+				continue
+			}
+			if w.Op == OpPhi {
+				// Phi value doesn't depend on store in the current block.
+				// Do this early to avoid dependency cycle.
+				storeNumber[w.ID] = 2
+				count[2]++
+				stack = stack[:len(stack)-1]
+				continue
+			}
+
+			max := int32(0) // latest store dependency
+			argsdone := true
+			for _, a := range w.Args {
+				if a.Block != w.Block {
+					continue
+				}
+				if !sset.contains(a.ID) {
+					stack = append(stack, a)
+					sset.add(a.ID)
+					argsdone = false
+					break
+				}
+				if storeNumber[a.ID]/3 > max {
+					max = storeNumber[a.ID] / 3
+				}
+			}
+			if !argsdone {
+				continue
+			}
+
+			n := 3*max + 2
+			if w.Op == OpNilCheck {
+				n = 3*max + 1
+			}
+			storeNumber[w.ID] = n
+			count[n]++
+			stack = stack[:len(stack)-1]
+		}
+	}
+
+	// convert count to prefix sum of counts: count'[i] = sum_{j<=i} count[i]
+	for i := range count {
+		if i == 0 {
+			continue
+		}
+		count[i] += count[i-1]
+	}
+	if count[len(count)-1] != int32(len(values)) {
+		f.Fatalf("storeOrder: value is missing, total count = %d, values = %v", count[len(count)-1], values)
+	}
+
+	// place values in count-indexed bins, which are in the desired store order
+	order := make([]*Value, len(values))
+	for _, v := range values {
+		s := storeNumber[v.ID]
+		order[count[s-1]] = v
+		count[s-1]++
+	}
+
+	return order
+}
diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go
index 0ff57e3..f7177dd 100644
--- a/src/cmd/compile/internal/ssa/schedule_test.go
+++ b/src/cmd/compile/internal/ssa/schedule_test.go
@@ -4,22 +4,25 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 func TestSchedule(t *testing.T) {
 	c := testConfig(t)
 	cases := []fun{
-		Fun(c, "entry",
+		c.Fun("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"),
+				Valu("mem0", OpInitMem, types.TypeMem, 0, nil),
+				Valu("ptr", OpConst64, c.config.Types.Int64, 0xABCD, nil),
+				Valu("v", OpConst64, c.config.Types.Int64, 12, nil),
+				Valu("mem1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem0"),
+				Valu("mem2", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem1"),
+				Valu("mem3", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "sum", "mem2"),
+				Valu("l1", OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem1"),
+				Valu("l2", OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem2"),
+				Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "l1", "l2"),
 				Goto("exit")),
 			Bloc("exit",
 				Exit("mem3"))),
@@ -55,3 +58,44 @@ func isSingleLiveMem(f *Func) bool {
 	}
 	return true
 }
+
+func TestStoreOrder(t *testing.T) {
+	// In the function below, v2 depends on v3 and v4, v4 depends on v3, and v3 depends on store v5.
+	// storeOrder did not handle this case correctly.
+	c := testConfig(t)
+	fun := c.Fun("entry",
+		Bloc("entry",
+			Valu("mem0", OpInitMem, types.TypeMem, 0, nil),
+			Valu("a", OpAdd64, c.config.Types.Int64, 0, nil, "b", "c"),                        // v2
+			Valu("b", OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem1"),                    // v3
+			Valu("c", OpNeg64, c.config.Types.Int64, 0, nil, "b"),                             // v4
+			Valu("mem1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem0"), // v5
+			Valu("mem2", OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "a", "mem1"),
+			Valu("ptr", OpConst64, c.config.Types.Int64, 0xABCD, nil),
+			Valu("v", OpConst64, c.config.Types.Int64, 12, nil),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem2")))
+
+	CheckFunc(fun.f)
+	order := storeOrder(fun.f.Blocks[0].Values, fun.f.newSparseSet(fun.f.NumValues()), make([]int32, fun.f.NumValues()))
+
+	// check that v2, v3, v4 is sorted after v5
+	var ai, bi, ci, si int
+	for i, v := range order {
+		switch v.ID {
+		case 2:
+			ai = i
+		case 3:
+			bi = i
+		case 4:
+			ci = i
+		case 5:
+			si = i
+		}
+	}
+	if ai < si || bi < si || ci < si {
+		t.Logf("Func: %s", fun.f)
+		t.Errorf("store order is wrong: got %v, want v2 v3 v4 after v5", order)
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go
index 8d5e62f..ffb5a59 100644
--- a/src/cmd/compile/internal/ssa/shift_test.go
+++ b/src/cmd/compile/internal/ssa/shift_test.go
@@ -5,43 +5,102 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
 	"testing"
 )
 
 func TestShiftConstAMD64(t *testing.T) {
 	c := testConfig(t)
-	fun := makeConstShiftFunc(c, 18, OpLsh64x64, TypeUInt64)
+	fun := makeConstShiftFunc(c, 18, OpLsh64x64, c.config.Types.UInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun.f.Free()
-	fun = makeConstShiftFunc(c, 66, OpLsh64x64, TypeUInt64)
+
+	fun = makeConstShiftFunc(c, 66, OpLsh64x64, c.config.Types.UInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun.f.Free()
-	fun = makeConstShiftFunc(c, 18, OpRsh64Ux64, TypeUInt64)
+
+	fun = makeConstShiftFunc(c, 18, OpRsh64Ux64, c.config.Types.UInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun.f.Free()
-	fun = makeConstShiftFunc(c, 66, OpRsh64Ux64, TypeUInt64)
+
+	fun = makeConstShiftFunc(c, 66, OpRsh64Ux64, c.config.Types.UInt64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
-	fun.f.Free()
-	fun = makeConstShiftFunc(c, 18, OpRsh64x64, TypeInt64)
+
+	fun = makeConstShiftFunc(c, 18, OpRsh64x64, c.config.Types.Int64)
 	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0})
-	fun.f.Free()
-	fun = makeConstShiftFunc(c, 66, OpRsh64x64, TypeInt64)
+
+	fun = makeConstShiftFunc(c, 66, OpRsh64x64, c.config.Types.Int64)
 	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",
+func makeConstShiftFunc(c *Conf, amount int64, op Op, typ *types.Type) fun {
+	ptyp := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("mem", OpInitMem, TypeMem, 0, nil),
-			Valu("SP", OpSP, TypeUInt64, 0, nil),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("SP", OpSP, c.config.Types.UInt64, 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("c", OpConst64, c.config.Types.UInt64, amount, nil),
 			Valu("shift", op, typ, 0, nil, "load", "c"),
-			Valu("store", OpStore, TypeMem, 8, nil, "resptr", "shift", "mem"),
+			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "shift", "mem"),
+			Exit("store")))
+	Compile(fun.f)
+	return fun
+}
+
+func TestShiftToExtensionAMD64(t *testing.T) {
+	c := testConfig(t)
+	// Test that eligible pairs of constant shifts are converted to extensions.
+	// For example:
+	//   (uint64(x) << 32) >> 32 -> uint64(uint32(x))
+	ops := map[Op]int{
+		OpAMD64SHLQconst: 0, OpAMD64SHLLconst: 0,
+		OpAMD64SHRQconst: 0, OpAMD64SHRLconst: 0,
+		OpAMD64SARQconst: 0, OpAMD64SARLconst: 0,
+	}
+	tests := [...]struct {
+		amount      int64
+		left, right Op
+		typ         *types.Type
+	}{
+		// unsigned
+		{56, OpLsh64x64, OpRsh64Ux64, c.config.Types.UInt64},
+		{48, OpLsh64x64, OpRsh64Ux64, c.config.Types.UInt64},
+		{32, OpLsh64x64, OpRsh64Ux64, c.config.Types.UInt64},
+		{24, OpLsh32x64, OpRsh32Ux64, c.config.Types.UInt32},
+		{16, OpLsh32x64, OpRsh32Ux64, c.config.Types.UInt32},
+		{8, OpLsh16x64, OpRsh16Ux64, c.config.Types.UInt16},
+		// signed
+		{56, OpLsh64x64, OpRsh64x64, c.config.Types.Int64},
+		{48, OpLsh64x64, OpRsh64x64, c.config.Types.Int64},
+		{32, OpLsh64x64, OpRsh64x64, c.config.Types.Int64},
+		{24, OpLsh32x64, OpRsh32x64, c.config.Types.Int32},
+		{16, OpLsh32x64, OpRsh32x64, c.config.Types.Int32},
+		{8, OpLsh16x64, OpRsh16x64, c.config.Types.Int16},
+	}
+	for _, tc := range tests {
+		fun := makeShiftExtensionFunc(c, tc.amount, tc.left, tc.right, tc.typ)
+		checkOpcodeCounts(t, fun.f, ops)
+	}
+}
+
+// makeShiftExtensionFunc generates a function containing:
+//
+//   (rshift (lshift (Const64 [amount])) (Const64 [amount]))
+//
+// This may be equivalent to a sign or zero extension.
+func makeShiftExtensionFunc(c *Conf, amount int64, lshift, rshift Op, typ *types.Type) fun {
+	ptyp := c.config.Types.BytePtr
+	fun := c.Fun("entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("SP", OpSP, c.config.Types.UInt64, 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, c.config.Types.UInt64, amount, nil),
+			Valu("lshift", lshift, typ, 0, nil, "load", "c"),
+			Valu("rshift", rshift, typ, 0, nil, "lshift", "c"),
+			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "rshift", "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
index ff05a04..506be4e 100644
--- a/src/cmd/compile/internal/ssa/shortcircuit.go
+++ b/src/cmd/compile/internal/ssa/shortcircuit.go
@@ -17,8 +17,7 @@ func shortcircuit(f *Func) {
 	//    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)
+	var ct, cf *Value
 	for _, b := range f.Blocks {
 		for _, v := range b.Values {
 			if v.Op != OpPhi {
@@ -37,8 +36,14 @@ func shortcircuit(f *Func) {
 					continue
 				}
 				if e.i == 0 {
+					if ct == nil {
+						ct = f.ConstBool(f.Entry.Pos, f.Config.Types.Bool, true)
+					}
 					v.SetArg(i, ct)
 				} else {
+					if cf == nil {
+						cf = f.ConstBool(f.Entry.Pos, f.Config.Types.Bool, false)
+					}
 					v.SetArg(i, cf)
 				}
 			}
diff --git a/src/cmd/compile/internal/ssa/shortcircuit_test.go b/src/cmd/compile/internal/ssa/shortcircuit_test.go
index f208801..b25eeb4 100644
--- a/src/cmd/compile/internal/ssa/shortcircuit_test.go
+++ b/src/cmd/compile/internal/ssa/shortcircuit_test.go
@@ -4,32 +4,35 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 func TestShortCircuit(t *testing.T) {
 	c := testConfig(t)
 
-	fun := Fun(c, "entry",
+	fun := c.Fun("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),
+			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
+			Valu("arg1", OpArg, c.config.Types.Int64, 0, nil),
+			Valu("arg2", OpArg, c.config.Types.Int64, 0, nil),
+			Valu("arg3", OpArg, c.config.Types.Int64, 0, nil),
 			Goto("b1")),
 		Bloc("b1",
-			Valu("cmp1", OpLess64, TypeBool, 0, nil, "arg1", "arg2"),
+			Valu("cmp1", OpLess64, c.config.Types.Bool, 0, nil, "arg1", "arg2"),
 			If("cmp1", "b2", "b3")),
 		Bloc("b2",
-			Valu("cmp2", OpLess64, TypeBool, 0, nil, "arg2", "arg3"),
+			Valu("cmp2", OpLess64, c.config.Types.Bool, 0, nil, "arg2", "arg3"),
 			Goto("b3")),
 		Bloc("b3",
-			Valu("phi2", OpPhi, TypeBool, 0, nil, "cmp1", "cmp2"),
+			Valu("phi2", OpPhi, c.config.Types.Bool, 0, nil, "cmp1", "cmp2"),
 			If("phi2", "b4", "b5")),
 		Bloc("b4",
-			Valu("cmp3", OpLess64, TypeBool, 0, nil, "arg3", "arg1"),
+			Valu("cmp3", OpLess64, c.config.Types.Bool, 0, nil, "arg3", "arg1"),
 			Goto("b5")),
 		Bloc("b5",
-			Valu("phi3", OpPhi, TypeBool, 0, nil, "phi2", "cmp3"),
+			Valu("phi3", OpPhi, c.config.Types.Bool, 0, nil, "phi2", "cmp3"),
 			If("phi3", "b6", "b7")),
 		Bloc("b6",
 			Exit("mem")),
diff --git a/src/cmd/compile/internal/ssa/sizeof_test.go b/src/cmd/compile/internal/ssa/sizeof_test.go
index 4aab923..9fab7b6 100644
--- a/src/cmd/compile/internal/ssa/sizeof_test.go
+++ b/src/cmd/compile/internal/ssa/sizeof_test.go
@@ -23,7 +23,8 @@ func TestSizeof(t *testing.T) {
 		_64bit uintptr     // size on 64bit platforms
 	}{
 		{Value{}, 68, 112},
-		{Block{}, 148, 288},
+		{Block{}, 152, 288},
+		{valState{}, 28, 40},
 	}
 
 	for _, tt := range tests {
diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go
index 70c4f61..973ab3d 100644
--- a/src/cmd/compile/internal/ssa/sparsemap.go
+++ b/src/cmd/compile/internal/ssa/sparsemap.go
@@ -4,13 +4,15 @@
 
 package ssa
 
+import "cmd/internal/src"
+
 // from http://research.swtch.com/sparse
 // in turn, from Briggs and Torczon
 
 type sparseEntry struct {
 	key ID
 	val int32
-	aux int32
+	aux src.XPos
 }
 
 type sparseMap struct {
@@ -43,7 +45,7 @@ func (s *sparseMap) get(k ID) int32 {
 	return -1
 }
 
-func (s *sparseMap) set(k ID, v, a int32) {
+func (s *sparseMap) set(k ID, v int32, a src.XPos) {
 	i := s.sparse[k]
 	if i < int32(len(s.dense)) && s.dense[i].key == k {
 		s.dense[i].val = v
@@ -64,7 +66,7 @@ func (s *sparseMap) setBit(k ID, v uint) {
 		s.dense[i].val |= 1 << v
 		return
 	}
-	s.dense = append(s.dense, sparseEntry{k, 1 << v, 0})
+	s.dense = append(s.dense, sparseEntry{k, 1 << v, src.NoXPos})
 	s.sparse[k] = int32(len(s.dense)) - 1
 }
 
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index dc2fd7d..3b44986 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -6,7 +6,11 @@
 
 package ssa
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/src"
+	"fmt"
+)
 
 type stackAllocState struct {
 	f *Func
@@ -32,12 +36,12 @@ type stackAllocState struct {
 }
 
 func newStackAllocState(f *Func) *stackAllocState {
-	s := f.Config.stackAllocState
+	s := f.Cache.stackAllocState
 	if s == nil {
 		return new(stackAllocState)
 	}
 	if s.f != nil {
-		f.Config.Fatalf(0, "newStackAllocState called without previous free")
+		f.fe.Fatalf(src.NoXPos, "newStackAllocState called without previous free")
 	}
 	return s
 }
@@ -58,14 +62,14 @@ func putStackAllocState(s *stackAllocState) {
 	for i := range s.used {
 		s.used[i] = false
 	}
-	s.f.Config.stackAllocState = s
+	s.f.Cache.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
+	typ      *types.Type
 	spill    *Value
 	needSlot bool
 }
@@ -159,7 +163,7 @@ func (s *stackAllocState) stackalloc() {
 	// 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{}
+	locations := map[*types.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].
@@ -201,7 +205,7 @@ func (s *stackAllocState) stackalloc() {
 			} else {
 				name = names[v.ID]
 			}
-			if name.N != nil && v.Type.Compare(name.Type) == CMPeq {
+			if name.N != nil && v.Type.Compare(name.Type) == types.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 {
@@ -243,7 +247,7 @@ func (s *stackAllocState) stackalloc() {
 			// 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})
+				locs = append(locs, LocalSlot{N: f.fe.Auto(v.Pos, v.Type), Type: v.Type, Off: 0})
 				locations[v.Type] = locs
 			}
 			// Use the stack variable at that index for v.
@@ -373,7 +377,7 @@ func (s *stackAllocState) buildInterferenceGraph() {
 			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 {
+					if s.values[v.ID].typ.Compare(s.values[id].typ) == types.CMPeq {
 						s.interfere[v.ID] = append(s.interfere[v.ID], id)
 						s.interfere[id] = append(s.interfere[id], v.ID)
 					}
diff --git a/src/cmd/compile/internal/ssa/stackframe.go b/src/cmd/compile/internal/ssa/stackframe.go
index de32c60..08be62a 100644
--- a/src/cmd/compile/internal/ssa/stackframe.go
+++ b/src/cmd/compile/internal/ssa/stackframe.go
@@ -6,5 +6,5 @@ package ssa
 
 // stackframe calls back into the frontend to assign frame offsets.
 func stackframe(f *Func) {
-	f.Config.fe.AllocFrame(f)
+	f.fe.AllocFrame(f)
 }
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
index 6f19263..45cfb06 100644
--- a/src/cmd/compile/internal/ssa/tighten.go
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -20,7 +20,7 @@ func tighten(f *Func) {
 				// Tuple selectors must stay with the tuple generator.
 				continue
 			}
-			if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
+			if v.MemoryArg() != nil {
 				// We can't move values which have a memory arg - it might
 				// make two memory values live across a block boundary.
 				continue
diff --git a/src/cmd/compile/internal/ssa/trim.go b/src/cmd/compile/internal/ssa/trim.go
index 09e80bd..04b4fd4 100644
--- a/src/cmd/compile/internal/ssa/trim.go
+++ b/src/cmd/compile/internal/ssa/trim.go
@@ -46,10 +46,24 @@ func trim(f *Func) {
 						v.resetArgs()
 						continue
 					}
-					// Pad the arguments of the remaining phi-ops, so
+					// Pad the arguments of the remaining phi-ops so
 					// they match the new predecessor count of `s`.
-					for len(v.Args) < len(s.Preds) {
-						v.AddArg(v.Args[0])
+					// Since s did not have a Phi op corresponding to
+					// the phi op in b, the other edges coming into s
+					// must be loopback edges from s, so v is the right
+					// argument to v!
+					args := make([]*Value, len(v.Args))
+					copy(args, v.Args)
+					v.resetArgs()
+					for x := 0; x < j; x++ {
+						v.AddArg(v)
+					}
+					v.AddArg(args[0])
+					for x := j + 1; x < ns; x++ {
+						v.AddArg(v)
+					}
+					for _, a := range args[1:] {
+						v.AddArg(a)
 					}
 				}
 				b.Values[k] = v
diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go
deleted file mode 100644
index 3ebee6a..0000000
--- a/src/cmd/compile/internal/ssa/type.go
+++ /dev/null
@@ -1,192 +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 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
-	IsTuple() 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 or ith part of a tuple
-	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) IsTuple() bool          { return false }
-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") }
-
-type TupleType struct {
-	first  Type
-	second Type
-	// Any tuple with a memory type must put that memory type second.
-}
-
-func (t *TupleType) Size() int64          { panic("not implemented") }
-func (t *TupleType) Alignment() int64     { panic("not implemented") }
-func (t *TupleType) IsBoolean() bool      { return false }
-func (t *TupleType) IsInteger() bool      { return false }
-func (t *TupleType) IsSigned() bool       { return false }
-func (t *TupleType) IsFloat() bool        { return false }
-func (t *TupleType) IsComplex() bool      { return false }
-func (t *TupleType) IsPtrShaped() bool    { return false }
-func (t *TupleType) IsString() bool       { return false }
-func (t *TupleType) IsSlice() bool        { return false }
-func (t *TupleType) IsArray() bool        { return false }
-func (t *TupleType) IsStruct() bool       { return false }
-func (t *TupleType) IsInterface() bool    { return false }
-func (t *TupleType) IsMemory() bool       { return false }
-func (t *TupleType) IsFlags() bool        { return false }
-func (t *TupleType) IsVoid() bool         { return false }
-func (t *TupleType) IsTuple() bool        { return true }
-func (t *TupleType) String() string       { return t.first.String() + "," + t.second.String() }
-func (t *TupleType) SimpleString() string { return "Tuple" }
-func (t *TupleType) ElemType() Type       { panic("not implemented") }
-func (t *TupleType) PtrTo() Type          { panic("not implemented") }
-func (t *TupleType) NumFields() int       { panic("not implemented") }
-func (t *TupleType) FieldType(i int) Type {
-	switch i {
-	case 0:
-		return t.first
-	case 1:
-		return t.second
-	default:
-		panic("bad tuple index")
-	}
-}
-func (t *TupleType) FieldOff(i int) int64   { panic("not implemented") }
-func (t *TupleType) FieldName(i int) string { panic("not implemented") }
-func (t *TupleType) 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
-}
-
-func (t *TupleType) Compare(u Type) Cmp {
-	// ssa.TupleType is greater than ssa.CompilerType
-	if _, ok := u.(*CompilerType); ok {
-		return CMPgt
-	}
-	// ssa.TupleType is smaller than any other type
-	x, ok := u.(*TupleType)
-	if !ok {
-		return CMPlt
-	}
-	if t == x {
-		return CMPeq
-	}
-	if c := t.first.Compare(x.first); c != CMPeq {
-		return c
-	}
-	return t.second.Compare(x.second)
-}
-
-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}
-)
-
-func MakeTuple(t0, t1 Type) *TupleType {
-	return &TupleType{first: t0, second: t1}
-}
diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go
deleted file mode 100644
index 2f91728..0000000
--- a/src/cmd/compile/internal/ssa/type_test.go
+++ /dev/null
@@ -1,102 +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 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) IsTuple() 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            { return TypeBytePtr }
-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
index 489ed35..7edc71b 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -5,6 +5,9 @@
 package ssa
 
 import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
+	"cmd/internal/src"
 	"fmt"
 	"math"
 )
@@ -22,7 +25,7 @@ type Value struct {
 
 	// 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
+	Type *types.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.
@@ -36,8 +39,8 @@ type Value struct {
 	// Containing basic block
 	Block *Block
 
-	// Source line number
-	Line int32
+	// Source position
+	Pos src.XPos
 
 	// Use count. Each appearance in Value.Args and Block.Control counts once.
 	Uses int32
@@ -126,17 +129,15 @@ func (v *Value) auxString() string {
 		return fmt.Sprintf(" [%d]", v.AuxInt32())
 	case auxInt64, auxInt128:
 		return fmt.Sprintf(" [%d]", v.AuxInt)
-	case auxSizeAndAlign:
-		return fmt.Sprintf(" [%s]", SizeAndAlign(v.AuxInt))
 	case auxFloat32, auxFloat64:
 		return fmt.Sprintf(" [%g]", v.AuxFloat())
 	case auxString:
 		return fmt.Sprintf(" {%q}", v.Aux)
-	case auxSym:
+	case auxSym, auxTyp:
 		if v.Aux != nil {
 			return fmt.Sprintf(" {%v}", v.Aux)
 		}
-	case auxSymOff, auxSymInt32:
+	case auxSymOff, auxSymInt32, auxTypSize:
 		s := ""
 		if v.Aux != nil {
 			s = fmt.Sprintf(" {%v}", v.Aux)
@@ -151,12 +152,6 @@ func (v *Value) auxString() string {
 			s = fmt.Sprintf(" {%v}", v.Aux)
 		}
 		return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
-	case auxSymSizeAndAlign:
-		s := ""
-		if v.Aux != nil {
-			s = fmt.Sprintf(" {%v}", v.Aux)
-		}
-		return s + fmt.Sprintf(" [%s]", SizeAndAlign(v.AuxInt))
 	}
 	return ""
 }
@@ -217,7 +212,23 @@ func (v *Value) reset(op Op) {
 
 // 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 := b.NewValue0(v.Pos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
+	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
+}
+
+// copyIntoNoXPos makes a new value identical to v and adds it to the end of b.
+// The copied value receives no source code position to avoid confusing changes
+// in debugger information (the intended user is the register allocator).
+func (v *Value) copyIntoNoXPos(b *Block) *Value {
+	c := b.NewValue0(src.NoXPos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
 	c.Aux = v.Aux
 	c.AuxInt = v.AuxInt
 	c.AddArgs(v.Args...)
@@ -232,7 +243,7 @@ func (v *Value) copyInto(b *Block) *Value {
 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...)
+	v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
 }
 
 // isGenericIntConst returns whether v is a generic integer constant.
@@ -243,8 +254,7 @@ func (v *Value) isGenericIntConst() bool {
 // 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
+	Sym *obj.LSym
 	// Note: the offset for an external symbol is not
 	// calculated until link time.
 }
@@ -252,14 +262,12 @@ type ExternSymbol struct {
 // 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.
 }
 
@@ -309,3 +317,20 @@ func (v *Value) RegName() string {
 	}
 	return reg.(*Register).name
 }
+
+// MemoryArg returns the memory argument for the Value.
+// The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
+// Otherwise, nil is returned.
+func (v *Value) MemoryArg() *Value {
+	if v.Op == OpPhi {
+		v.Fatalf("MemoryArg on Phi")
+	}
+	na := len(v.Args)
+	if na == 0 {
+		return nil
+	}
+	if m := v.Args[na-1]; m.Type.IsMemory() {
+		return m
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index 054ba1f..cf22724 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -4,10 +4,31 @@
 
 package ssa
 
-import "fmt"
+import (
+	"cmd/compile/internal/types"
+	"cmd/internal/obj"
+	"cmd/internal/src"
+)
 
-// writebarrier expands write barrier ops (StoreWB, MoveWB, etc.) into
-// branches and runtime calls, like
+// needwb returns whether we need write barrier for store op v.
+// v must be Store/Move/Zero.
+func needwb(v *Value) bool {
+	t, ok := v.Aux.(*types.Type)
+	if !ok {
+		v.Fatalf("store aux is not a type: %s", v.LongString())
+	}
+	if !t.HasPointer() {
+		return false
+	}
+	if IsStackAddr(v.Args[0]) {
+		return false // write on stack doesn't need write barrier
+	}
+	return true
+}
+
+// writebarrier pass inserts write barriers for store ops (Store, Move, Zero)
+// when necessary (the condition above). It rewrites store ops to branches
+// and runtime calls, like
 //
 // if writeBarrier.enabled {
 //   writebarrierptr(ptr, val)
@@ -15,221 +36,237 @@ import "fmt"
 //   *ptr = val
 // }
 //
-// If ptr is an address of a stack slot, write barrier will be removed
-// and a normal store will be used.
 // A sequence of WB stores for many pointer fields of a single type will
 // be emitted together, with a single branch.
-//
-// Expanding WB ops introduces new control flows, and we would need to
-// split a block into two if there were values after WB ops, which would
-// require scheduling the values. To avoid this complexity, when building
-// SSA, we make sure that WB ops are always at the end of a block. We do
-// this before fuse as it may merge blocks. It also helps to reduce
-// number of blocks as fuse merges blocks introduced in this phase.
 func writebarrier(f *Func) {
-	var sb, sp, wbaddr *Value
-	var writebarrierptr, typedmemmove, typedmemclr interface{} // *gc.Sym
-	var storeWBs, others []*Value
-	var wbs *sparseSet
-	for _, b := range f.Blocks { // range loop is safe since the blocks we added contain no WB stores
-	valueLoop:
-		for i, v := range b.Values {
+	if !f.fe.UseWriteBarrier() {
+		return
+	}
+
+	var sb, sp, wbaddr, const0 *Value
+	var writebarrierptr, typedmemmove, typedmemclr *obj.LSym
+	var stores, after []*Value
+	var sset *sparseSet
+	var storeNumber []int32
+
+	for _, b := range f.Blocks { // range loop is safe since the blocks we added contain no stores to expand
+		// first, identify all the stores that need to insert a write barrier.
+		// mark them with WB ops temporarily. record presence of WB ops.
+		hasStore := false
+		for _, v := range b.Values {
 			switch v.Op {
-			case OpStoreWB, OpMoveWB, OpMoveWBVolatile, OpZeroWB:
-				if IsStackAddr(v.Args[0]) {
+			case OpStore, OpMove, OpZero:
+				if needwb(v) {
 					switch v.Op {
-					case OpStoreWB:
-						v.Op = OpStore
-					case OpMoveWB, OpMoveWBVolatile:
-						v.Op = OpMove
-						v.Aux = nil
-					case OpZeroWB:
-						v.Op = OpZero
-						v.Aux = nil
+					case OpStore:
+						v.Op = OpStoreWB
+					case OpMove:
+						v.Op = OpMoveWB
+					case OpZero:
+						v.Op = OpZeroWB
 					}
-					continue
+					hasStore = true
 				}
+			}
+		}
+		if !hasStore {
+			continue
+		}
 
-				if wbaddr == nil {
-					// initalize global values for write barrier test and calls
-					// find SB and SP values in entry block
-					initln := f.Entry.Line
-					for _, v := range f.Entry.Values {
-						if v.Op == OpSB {
-							sb = v
-						}
-						if v.Op == OpSP {
-							sp = v
-						}
-					}
-					if sb == nil {
-						sb = f.Entry.NewValue0(initln, OpSB, f.Config.fe.TypeUintptr())
-					}
-					if sp == nil {
-						sp = f.Entry.NewValue0(initln, OpSP, f.Config.fe.TypeUintptr())
-					}
-					wbsym := &ExternSymbol{Typ: f.Config.fe.TypeBool(), Sym: f.Config.fe.Syslook("writeBarrier").(fmt.Stringer)}
-					wbaddr = f.Entry.NewValue1A(initln, OpAddr, f.Config.fe.TypeUInt32().PtrTo(), wbsym, sb)
-					writebarrierptr = f.Config.fe.Syslook("writebarrierptr")
-					typedmemmove = f.Config.fe.Syslook("typedmemmove")
-					typedmemclr = f.Config.fe.Syslook("typedmemclr")
-
-					wbs = f.newSparseSet(f.NumValues())
-					defer f.retSparseSet(wbs)
+		if wbaddr == nil {
+			// lazily initialize global values for write barrier test and calls
+			// find SB and SP values in entry block
+			initpos := f.Entry.Pos
+			for _, v := range f.Entry.Values {
+				if v.Op == OpSB {
+					sb = v
 				}
-
-				line := v.Line
-
-				// there may be a sequence of WB stores in the current block. find them.
-				storeWBs = storeWBs[:0]
-				others = others[:0]
-				wbs.clear()
-				for _, w := range b.Values[i:] {
-					if w.Op == OpStoreWB || w.Op == OpMoveWB || w.Op == OpMoveWBVolatile || w.Op == OpZeroWB {
-						storeWBs = append(storeWBs, w)
-						wbs.add(w.ID)
-					} else {
-						others = append(others, w)
-					}
+				if v.Op == OpSP {
+					sp = v
 				}
-
-				// make sure that no value in this block depends on WB stores
-				for _, w := range b.Values {
-					if w.Op == OpStoreWB || w.Op == OpMoveWB || w.Op == OpMoveWBVolatile || w.Op == OpZeroWB {
-						continue
-					}
-					for _, a := range w.Args {
-						if wbs.contains(a.ID) {
-							f.Fatalf("value %v depends on WB store %v in the same block %v", w, a, b)
-						}
-					}
+				if sb != nil && sp != nil {
+					break
 				}
+			}
+			if sb == nil {
+				sb = f.Entry.NewValue0(initpos, OpSB, f.Config.Types.Uintptr)
+			}
+			if sp == nil {
+				sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr)
+			}
+			wbsym := &ExternSymbol{Sym: f.fe.Syslook("writeBarrier")}
+			wbaddr = f.Entry.NewValue1A(initpos, OpAddr, f.Config.Types.UInt32Ptr, wbsym, sb)
+			writebarrierptr = f.fe.Syslook("writebarrierptr")
+			typedmemmove = f.fe.Syslook("typedmemmove")
+			typedmemclr = f.fe.Syslook("typedmemclr")
+			const0 = f.ConstInt32(initpos, f.Config.Types.UInt32, 0)
 
-				// find the memory before the WB stores
-				// this memory is not a WB store but it is used in a WB store.
-				var mem *Value
-				for _, w := range storeWBs {
-					a := w.Args[len(w.Args)-1]
-					if wbs.contains(a.ID) {
-						continue
-					}
-					if mem != nil {
-						b.Fatalf("two stores live simultaneously: %s, %s", mem, a)
-					}
-					mem = a
-				}
+			// allocate auxiliary data structures for computing store order
+			sset = f.newSparseSet(f.NumValues())
+			defer f.retSparseSet(sset)
+			storeNumber = make([]int32, f.NumValues())
+		}
 
-				b.Values = append(b.Values[:i], others...) // move WB ops out of this block
-
-				bThen := f.NewBlock(BlockPlain)
-				bElse := f.NewBlock(BlockPlain)
-				bEnd := f.NewBlock(b.Kind)
-				bThen.Line = line
-				bElse.Line = line
-				bEnd.Line = line
-
-				// set up control flow for end block
-				bEnd.SetControl(b.Control)
-				bEnd.Likely = b.Likely
-				for _, e := range b.Succs {
-					bEnd.Succs = append(bEnd.Succs, e)
-					e.b.Preds[e.i].b = bEnd
+		// order values in store order
+		b.Values = storeOrder(b.Values, sset, storeNumber)
+
+	again:
+		// find the start and end of the last contiguous WB store sequence.
+		// a branch will be inserted there. values after it will be moved
+		// to a new block.
+		var last *Value
+		var start, end int
+		values := b.Values
+	FindSeq:
+		for i := len(values) - 1; i >= 0; i-- {
+			w := values[i]
+			switch w.Op {
+			case OpStoreWB, OpMoveWB, OpZeroWB:
+				start = i
+				if last == nil {
+					last = w
+					end = i + 1
+				}
+			case OpVarDef, OpVarLive, OpVarKill:
+				continue
+			default:
+				if last == nil {
+					continue
 				}
+				break FindSeq
+			}
+		}
+		stores = append(stores[:0], b.Values[start:end]...) // copy to avoid aliasing
+		after = append(after[:0], b.Values[end:]...)
+		b.Values = b.Values[:start]
 
-				// set up control flow for write barrier test
-				// load word, test word, avoiding partial register write from load byte.
-				flag := b.NewValue2(line, OpLoad, f.Config.fe.TypeUInt32(), wbaddr, mem)
-				const0 := f.ConstInt32(line, f.Config.fe.TypeUInt32(), 0)
-				flag = b.NewValue2(line, OpNeq32, f.Config.fe.TypeBool(), flag, const0)
-				b.Kind = BlockIf
-				b.SetControl(flag)
-				b.Likely = BranchUnlikely
-				b.Succs = b.Succs[:0]
-				b.AddEdgeTo(bThen)
-				b.AddEdgeTo(bElse)
-				bThen.AddEdgeTo(bEnd)
-				bElse.AddEdgeTo(bEnd)
-
-				memThen := mem
-				memElse := mem
-				for _, w := range storeWBs {
-					var val *Value
-					ptr := w.Args[0]
-					siz := w.AuxInt
-					typ := w.Aux // only non-nil for MoveWB, MoveWBVolatile, ZeroWB
-
-					var op Op
-					var fn interface{} // *gc.Sym
-					switch w.Op {
-					case OpStoreWB:
-						op = OpStore
-						fn = writebarrierptr
-						val = w.Args[1]
-					case OpMoveWB, OpMoveWBVolatile:
-						op = OpMove
-						fn = typedmemmove
-						val = w.Args[1]
-					case OpZeroWB:
-						op = OpZero
-						fn = typedmemclr
-					}
+		// find the memory before the WB stores
+		mem := stores[0].MemoryArg()
+		pos := stores[0].Pos
+		bThen := f.NewBlock(BlockPlain)
+		bElse := f.NewBlock(BlockPlain)
+		bEnd := f.NewBlock(b.Kind)
+		bThen.Pos = pos
+		bElse.Pos = pos
+		bEnd.Pos = b.Pos
+		b.Pos = pos
 
-					// then block: emit write barrier call
-					memThen = wbcall(line, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile)
+		// set up control flow for end block
+		bEnd.SetControl(b.Control)
+		bEnd.Likely = b.Likely
+		for _, e := range b.Succs {
+			bEnd.Succs = append(bEnd.Succs, e)
+			e.b.Preds[e.i].b = bEnd
+		}
 
-					// else block: normal store
-					if op == OpZero {
-						memElse = bElse.NewValue2I(line, op, TypeMem, siz, ptr, memElse)
-					} else {
-						memElse = bElse.NewValue3I(line, op, TypeMem, siz, ptr, val, memElse)
-					}
-				}
+		// set up control flow for write barrier test
+		// load word, test word, avoiding partial register write from load byte.
+		cfgtypes := &f.Config.Types
+		flag := b.NewValue2(pos, OpLoad, cfgtypes.UInt32, wbaddr, mem)
+		flag = b.NewValue2(pos, OpNeq32, cfgtypes.Bool, flag, const0)
+		b.Kind = BlockIf
+		b.SetControl(flag)
+		b.Likely = BranchUnlikely
+		b.Succs = b.Succs[:0]
+		b.AddEdgeTo(bThen)
+		b.AddEdgeTo(bElse)
+		bThen.AddEdgeTo(bEnd)
+		bElse.AddEdgeTo(bEnd)
 
-				// merge memory
-				// Splice memory Phi into the last memory of the original sequence,
-				// which may be used in subsequent blocks. Other memories in the
-				// sequence must be dead after this block since there can be only
-				// one memory live.
-				last := storeWBs[0]
-				if len(storeWBs) > 1 {
-					// find the last store
-					last = nil
-					wbs.clear() // we reuse wbs to record WB stores that is used in another WB store
-					for _, w := range storeWBs {
-						wbs.add(w.Args[len(w.Args)-1].ID)
-					}
-					for _, w := range storeWBs {
-						if wbs.contains(w.ID) {
-							continue
-						}
-						if last != nil {
-							b.Fatalf("two stores live simultaneously: %s, %s", last, w)
-						}
-						last = w
-					}
+		// for each write barrier store, append write barrier version to bThen
+		// and simple store version to bElse
+		memThen := mem
+		memElse := mem
+		for _, w := range stores {
+			ptr := w.Args[0]
+			pos := w.Pos
+
+			var fn *obj.LSym
+			var typ *ExternSymbol
+			var val *Value
+			switch w.Op {
+			case OpStoreWB:
+				fn = writebarrierptr
+				val = w.Args[1]
+			case OpMoveWB:
+				fn = typedmemmove
+				val = w.Args[1]
+				typ = &ExternSymbol{Sym: w.Aux.(*types.Type).Symbol()}
+			case OpZeroWB:
+				fn = typedmemclr
+				typ = &ExternSymbol{Sym: w.Aux.(*types.Type).Symbol()}
+			case OpVarDef, OpVarLive, OpVarKill:
+			}
+
+			// then block: emit write barrier call
+			switch w.Op {
+			case OpStoreWB, OpMoveWB, OpZeroWB:
+				volatile := w.Op == OpMoveWB && isVolatile(val)
+				memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, volatile)
+			case OpVarDef, OpVarLive, OpVarKill:
+				memThen = bThen.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memThen)
+			}
+
+			// else block: normal store
+			switch w.Op {
+			case OpStoreWB:
+				memElse = bElse.NewValue3A(pos, OpStore, types.TypeMem, w.Aux, ptr, val, memElse)
+			case OpMoveWB:
+				memElse = bElse.NewValue3I(pos, OpMove, types.TypeMem, w.AuxInt, ptr, val, memElse)
+				memElse.Aux = w.Aux
+			case OpZeroWB:
+				memElse = bElse.NewValue2I(pos, OpZero, types.TypeMem, w.AuxInt, ptr, memElse)
+				memElse.Aux = w.Aux
+			case OpVarDef, OpVarLive, OpVarKill:
+				memElse = bElse.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memElse)
+			}
+
+			if fn != nil {
+				// Note that we set up a writebarrier function call.
+				if !f.WBPos.IsKnown() {
+					f.WBPos = pos
 				}
-				bEnd.Values = append(bEnd.Values, last)
-				last.Block = bEnd
-				last.reset(OpPhi)
-				last.Type = TypeMem
-				last.AddArg(memThen)
-				last.AddArg(memElse)
-				for _, w := range storeWBs {
-					if w != last {
-						w.resetArgs()
-					}
-				}
-				for _, w := range storeWBs {
-					if w != last {
-						f.freeValue(w)
-					}
+				if f.fe.Debug_wb() {
+					f.Warnl(pos, "write barrier")
 				}
+			}
+		}
 
-				if f.Config.fe.Debug_wb() {
-					f.Config.Warnl(line, "write barrier")
-				}
+		// merge memory
+		// Splice memory Phi into the last memory of the original sequence,
+		// which may be used in subsequent blocks. Other memories in the
+		// sequence must be dead after this block since there can be only
+		// one memory live.
+		bEnd.Values = append(bEnd.Values, last)
+		last.Block = bEnd
+		last.reset(OpPhi)
+		last.Type = types.TypeMem
+		last.AddArg(memThen)
+		last.AddArg(memElse)
+		for _, w := range stores {
+			if w != last {
+				w.resetArgs()
+			}
+		}
+		for _, w := range stores {
+			if w != last {
+				f.freeValue(w)
+			}
+		}
 
-				break valueLoop
+		// put values after the store sequence into the end block
+		bEnd.Values = append(bEnd.Values, after...)
+		for _, w := range after {
+			w.Block = bEnd
+		}
+
+		// if we have more stores in this block, do this block again
+		// check from end to beginning, to avoid quadratic behavior; issue 13554
+		// TODO: track the final value to avoid any looping here at all
+		for i := len(b.Values) - 1; i >= 0; i-- {
+			switch b.Values[i].Op {
+			case OpStoreWB, OpMoveWB, OpZeroWB:
+				goto again
 			}
 		}
 	}
@@ -237,7 +274,7 @@ func writebarrier(f *Func) {
 
 // wbcall emits write barrier runtime call in b, returns memory.
 // if valIsVolatile, it moves val into temp space before making the call.
-func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
+func wbcall(pos src.XPos, b *Block, fn *obj.LSym, typ *ExternSymbol, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
 	config := b.Func.Config
 
 	var tmp GCNode
@@ -246,12 +283,13 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
 		// a function call). Marshaling the args to typedmemmove might clobber the
 		// value we're trying to move.
 		t := val.Type.ElemType()
-		tmp = config.fe.Auto(t)
-		aux := &AutoSymbol{Typ: t, Node: tmp}
-		mem = b.NewValue1A(line, OpVarDef, TypeMem, tmp, mem)
-		tmpaddr := b.NewValue1A(line, OpAddr, t.PtrTo(), aux, sp)
-		siz := MakeSizeAndAlign(t.Size(), t.Alignment()).Int64()
-		mem = b.NewValue3I(line, OpMove, TypeMem, siz, tmpaddr, val, mem)
+		tmp = b.Func.fe.Auto(val.Pos, t)
+		aux := &AutoSymbol{Node: tmp}
+		mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem)
+		tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), aux, sp)
+		siz := t.Size()
+		mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem)
+		mem.Aux = t
 		val = tmpaddr
 	}
 
@@ -259,32 +297,32 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
 	off := config.ctxt.FixedFrameSize()
 
 	if typ != nil { // for typedmemmove
-		taddr := b.NewValue1A(line, OpAddr, config.fe.TypeUintptr(), typ, sb)
+		taddr := b.NewValue1A(pos, OpAddr, b.Func.Config.Types.Uintptr, typ, sb)
 		off = round(off, taddr.Type.Alignment())
-		arg := b.NewValue1I(line, OpOffPtr, taddr.Type.PtrTo(), off, sp)
-		mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, taddr, mem)
+		arg := b.NewValue1I(pos, OpOffPtr, taddr.Type.PtrTo(), off, sp)
+		mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, taddr, mem)
 		off += taddr.Type.Size()
 	}
 
 	off = round(off, ptr.Type.Alignment())
-	arg := b.NewValue1I(line, OpOffPtr, ptr.Type.PtrTo(), off, sp)
-	mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, ptr, mem)
+	arg := b.NewValue1I(pos, OpOffPtr, ptr.Type.PtrTo(), off, sp)
+	mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, ptr, mem)
 	off += ptr.Type.Size()
 
 	if val != nil {
 		off = round(off, val.Type.Alignment())
-		arg = b.NewValue1I(line, OpOffPtr, val.Type.PtrTo(), off, sp)
-		mem = b.NewValue3I(line, OpStore, TypeMem, val.Type.Size(), arg, val, mem)
+		arg = b.NewValue1I(pos, OpOffPtr, val.Type.PtrTo(), off, sp)
+		mem = b.NewValue3A(pos, OpStore, types.TypeMem, val.Type, arg, val, mem)
 		off += val.Type.Size()
 	}
 	off = round(off, config.PtrSize)
 
 	// issue call
-	mem = b.NewValue1A(line, OpStaticCall, TypeMem, fn, mem)
+	mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, fn, mem)
 	mem.AuxInt = off - config.ctxt.FixedFrameSize()
 
 	if valIsVolatile {
-		mem = b.NewValue1A(line, OpVarKill, TypeMem, tmp, mem) // mark temp dead
+		mem = b.NewValue1A(pos, OpVarKill, types.TypeMem, tmp, mem) // mark temp dead
 	}
 
 	return mem
@@ -308,3 +346,12 @@ func IsStackAddr(v *Value) bool {
 	}
 	return false
 }
+
+// isVolatile returns whether v is a pointer to argument region on stack which
+// will be clobbered by a function call.
+func isVolatile(v *Value) bool {
+	for v.Op == OpOffPtr || v.Op == OpAddPtr || v.Op == OpPtrIndex || v.Op == OpCopy {
+		v = v.Args[0]
+	}
+	return v.Op == OpSP
+}
diff --git a/src/cmd/compile/internal/ssa/writebarrier_test.go b/src/cmd/compile/internal/ssa/writebarrier_test.go
index c2ba695..c1f9ec7 100644
--- a/src/cmd/compile/internal/ssa/writebarrier_test.go
+++ b/src/cmd/compile/internal/ssa/writebarrier_test.go
@@ -4,21 +4,24 @@
 
 package ssa
 
-import "testing"
+import (
+	"cmd/compile/internal/types"
+	"testing"
+)
 
 func TestWriteBarrierStoreOrder(t *testing.T) {
 	// Make sure writebarrier phase works even StoreWB ops are not in dependency order
 	c := testConfig(t)
-	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
-	fun := Fun(c, "entry",
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
 		Bloc("entry",
-			Valu("start", OpInitMem, TypeMem, 0, nil),
-			Valu("sb", OpSB, TypeInvalid, 0, nil),
-			Valu("sp", OpSP, TypeInvalid, 0, nil),
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("sp", OpSP, types.TypeInvalid, 0, nil),
 			Valu("v", OpConstNil, ptrType, 0, nil),
 			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
-			Valu("wb2", OpStoreWB, TypeMem, 8, nil, "addr1", "v", "wb1"),
-			Valu("wb1", OpStoreWB, TypeMem, 8, nil, "addr1", "v", "start"), // wb1 and wb2 are out of order
+			Valu("wb2", OpStore, types.TypeMem, 0, ptrType, "addr1", "v", "wb1"),
+			Valu("wb1", OpStore, types.TypeMem, 0, ptrType, "addr1", "v", "start"), // wb1 and wb2 are out of order
 			Goto("exit")),
 		Bloc("exit",
 			Exit("wb2")))
@@ -27,3 +30,27 @@ func TestWriteBarrierStoreOrder(t *testing.T) {
 	writebarrier(fun.f)
 	CheckFunc(fun.f)
 }
+
+func TestWriteBarrierPhi(t *testing.T) {
+	// Make sure writebarrier phase works for single-block loop, where
+	// a Phi op takes the store in the same block as argument.
+	// See issue #19067.
+	c := testConfig(t)
+	ptrType := c.config.Types.BytePtr
+	fun := c.Fun("entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, types.TypeMem, 0, nil),
+			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
+			Valu("sp", OpSP, types.TypeInvalid, 0, nil),
+			Goto("loop")),
+		Bloc("loop",
+			Valu("phi", OpPhi, types.TypeMem, 0, nil, "start", "wb"),
+			Valu("v", OpConstNil, ptrType, 0, nil),
+			Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
+			Valu("wb", OpStore, types.TypeMem, 0, ptrType, "addr", "v", "phi"), // has write barrier
+			Goto("loop")))
+
+	CheckFunc(fun.f)
+	writebarrier(fun.f)
+	CheckFunc(fun.f)
+}
diff --git a/src/cmd/compile/internal/ssa/zcse.go b/src/cmd/compile/internal/ssa/zcse.go
index 16d5c10..44688d9 100644
--- a/src/cmd/compile/internal/ssa/zcse.go
+++ b/src/cmd/compile/internal/ssa/zcse.go
@@ -4,6 +4,8 @@
 
 package ssa
 
+import "cmd/compile/internal/types"
+
 // 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,
@@ -61,7 +63,7 @@ type vkey struct {
 	op Op
 	ai int64       // aux int
 	ax interface{} // aux
-	t  Type        // type
+	t  *types.Type // type
 }
 
 // keyFor returns the AuxInt portion of a  key structure uniquely identifying a
diff --git a/src/cmd/compile/internal/syntax/branches.go b/src/cmd/compile/internal/syntax/branches.go
new file mode 100644
index 0000000..5fecdd6
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/branches.go
@@ -0,0 +1,314 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+	"cmd/internal/src"
+	"fmt"
+)
+
+// TODO(gri) consider making this part of the parser code
+
+// checkBranches checks correct use of labels and branch
+// statements (break, continue, goto) in a function body.
+// It catches:
+//    - misplaced breaks and continues
+//    - bad labeled breaks and continues
+//    - invalid, unused, duplicate, and missing labels
+//    - gotos jumping over variable declarations and into blocks
+func checkBranches(body *BlockStmt, errh ErrorHandler) {
+	if body == nil {
+		return
+	}
+
+	// scope of all labels in this body
+	ls := &labelScope{errh: errh}
+	fwdGotos := ls.blockBranches(nil, targets{}, nil, body.Pos(), body.List)
+
+	// If there are any forward gotos left, no matching label was
+	// found for them. Either those labels were never defined, or
+	// they are inside blocks and not reachable from the gotos.
+	for _, fwd := range fwdGotos {
+		name := fwd.Label.Value
+		if l := ls.labels[name]; l != nil {
+			l.used = true // avoid "defined and not used" error
+			ls.err(fwd.Label.Pos(), "goto %s jumps into block starting at %s", name, l.parent.start)
+		} else {
+			ls.err(fwd.Label.Pos(), "label %s not defined", name)
+		}
+	}
+
+	// spec: "It is illegal to define a label that is never used."
+	for _, l := range ls.labels {
+		if !l.used {
+			l := l.lstmt.Label
+			ls.err(l.Pos(), "label %s defined and not used", l.Value)
+		}
+	}
+}
+
+type labelScope struct {
+	errh   ErrorHandler
+	labels map[string]*label // all label declarations inside the function; allocated lazily
+}
+
+type label struct {
+	parent *block       // block containing this label declaration
+	lstmt  *LabeledStmt // statement declaring the label
+	used   bool         // whether the label is used or not
+}
+
+type block struct {
+	parent *block       // immediately enclosing block, or nil
+	start  src.Pos      // start of block
+	lstmt  *LabeledStmt // labeled statement associated with this block, or nil
+}
+
+func (ls *labelScope) err(pos src.Pos, format string, args ...interface{}) {
+	ls.errh(Error{pos, fmt.Sprintf(format, args...)})
+}
+
+// declare declares the label introduced by s in block b and returns
+// the new label. If the label was already declared, declare reports
+// and error and the existing label is returned instead.
+func (ls *labelScope) declare(b *block, s *LabeledStmt) *label {
+	name := s.Label.Value
+	labels := ls.labels
+	if labels == nil {
+		labels = make(map[string]*label)
+		ls.labels = labels
+	} else if alt := labels[name]; alt != nil {
+		ls.err(s.Pos(), "label %s already defined at %s", name, alt.lstmt.Label.Pos().String())
+		return alt
+	}
+	l := &label{b, s, false}
+	labels[name] = l
+	return l
+}
+
+// gotoTarget returns the labeled statement matching the given name and
+// declared in block b or any of its enclosing blocks. The result is nil
+// if the label is not defined, or doesn't match a valid labeled statement.
+func (ls *labelScope) gotoTarget(b *block, name string) *LabeledStmt {
+	if l := ls.labels[name]; l != nil {
+		l.used = true // even if it's not a valid target
+		for ; b != nil; b = b.parent {
+			if l.parent == b {
+				return l.lstmt
+			}
+		}
+	}
+	return nil
+}
+
+var invalid = new(LabeledStmt) // singleton to signal invalid enclosing target
+
+// enclosingTarget returns the innermost enclosing labeled statement matching
+// the given name. The result is nil if the label is not defined, and invalid
+// if the label is defined but doesn't label a valid labeled statement.
+func (ls *labelScope) enclosingTarget(b *block, name string) *LabeledStmt {
+	if l := ls.labels[name]; l != nil {
+		l.used = true // even if it's not a valid target (see e.g., test/fixedbugs/bug136.go)
+		for ; b != nil; b = b.parent {
+			if l.lstmt == b.lstmt {
+				return l.lstmt
+			}
+		}
+		return invalid
+	}
+	return nil
+}
+
+// targets describes the target statements within which break
+// or continue statements are valid.
+type targets struct {
+	breaks    Stmt     // *ForStmt, *SwitchStmt, *SelectStmt, or nil
+	continues *ForStmt // or nil
+}
+
+// blockBranches processes a block's body starting at start and returns the
+// list of unresolved (forward) gotos. parent is the immediately enclosing
+// block (or nil), ctxt provides information about the enclosing statements,
+// and lstmt is the labeled statement asociated with this block, or nil.
+func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledStmt, start src.Pos, body []Stmt) []*BranchStmt {
+	b := &block{parent: parent, start: start, lstmt: lstmt}
+
+	var varPos src.Pos
+	var varName Expr
+	var fwdGotos, badGotos []*BranchStmt
+
+	recordVarDecl := func(pos src.Pos, name Expr) {
+		varPos = pos
+		varName = name
+		// Any existing forward goto jumping over the variable
+		// declaration is invalid. The goto may still jump out
+		// of the block and be ok, but we don't know that yet.
+		// Remember all forward gotos as potential bad gotos.
+		badGotos = append(badGotos[:0], fwdGotos...)
+	}
+
+	jumpsOverVarDecl := func(fwd *BranchStmt) bool {
+		if varPos.IsKnown() {
+			for _, bad := range badGotos {
+				if fwd == bad {
+					return true
+				}
+			}
+		}
+		return false
+	}
+
+	innerBlock := func(ctxt targets, start src.Pos, body []Stmt) {
+		// Unresolved forward gotos from the inner block
+		// become forward gotos for the current block.
+		fwdGotos = append(fwdGotos, ls.blockBranches(b, ctxt, lstmt, start, body)...)
+	}
+
+	for _, stmt := range body {
+		lstmt = nil
+	L:
+		switch s := stmt.(type) {
+		case *DeclStmt:
+			for _, d := range s.DeclList {
+				if v, ok := d.(*VarDecl); ok {
+					recordVarDecl(v.Pos(), v.NameList[0])
+					break // the first VarDecl will do
+				}
+			}
+
+		case *LabeledStmt:
+			// declare non-blank label
+			if name := s.Label.Value; name != "_" {
+				l := ls.declare(b, s)
+				// resolve matching forward gotos
+				i := 0
+				for _, fwd := range fwdGotos {
+					if fwd.Label.Value == name {
+						fwd.Target = s
+						l.used = true
+						if jumpsOverVarDecl(fwd) {
+							ls.err(
+								fwd.Label.Pos(),
+								"goto %s jumps over declaration of %s at %s",
+								name, String(varName), varPos,
+							)
+						}
+					} else {
+						// no match - keep forward goto
+						fwdGotos[i] = fwd
+						i++
+					}
+				}
+				fwdGotos = fwdGotos[:i]
+				lstmt = s
+			}
+			// process labeled statement
+			stmt = s.Stmt
+			goto L
+
+		case *BranchStmt:
+			// unlabeled branch statement
+			if s.Label == nil {
+				switch s.Tok {
+				case _Break:
+					if t := ctxt.breaks; t != nil {
+						s.Target = t
+					} else {
+						ls.err(s.Pos(), "break is not in a loop, switch, or select")
+					}
+				case _Continue:
+					if t := ctxt.continues; t != nil {
+						s.Target = t
+					} else {
+						ls.err(s.Pos(), "continue is not in a loop")
+					}
+				case _Fallthrough:
+					// nothing to do
+				case _Goto:
+					fallthrough // should always have a label
+				default:
+					panic("invalid BranchStmt")
+				}
+				break
+			}
+
+			// labeled branch statement
+			name := s.Label.Value
+			switch s.Tok {
+			case _Break:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for", "switch", or "select" statement, and that is the one
+				// whose execution terminates."
+				if t := ls.enclosingTarget(b, name); t != nil {
+					switch t := t.Stmt.(type) {
+					case *SwitchStmt, *SelectStmt, *ForStmt:
+						s.Target = t
+					default:
+						ls.err(s.Label.Pos(), "invalid break label %s", name)
+					}
+				} else {
+					ls.err(s.Label.Pos(), "break label not defined: %s", name)
+				}
+
+			case _Continue:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for" statement, and that is the one whose execution advances."
+				if t := ls.enclosingTarget(b, name); t != nil {
+					if t, ok := t.Stmt.(*ForStmt); ok {
+						s.Target = t
+					} else {
+						ls.err(s.Label.Pos(), "invalid continue label %s", name)
+					}
+				} else {
+					ls.err(s.Label.Pos(), "continue label not defined: %s", name)
+				}
+
+			case _Goto:
+				if t := ls.gotoTarget(b, name); t != nil {
+					s.Target = t
+				} else {
+					// label may be declared later - add goto to forward gotos
+					fwdGotos = append(fwdGotos, s)
+				}
+
+			case _Fallthrough:
+				fallthrough // should never have a label
+			default:
+				panic("invalid BranchStmt")
+			}
+
+		case *AssignStmt:
+			if s.Op == Def {
+				recordVarDecl(s.Pos(), s.Lhs)
+			}
+
+		case *BlockStmt:
+			innerBlock(ctxt, s.Pos(), s.List)
+
+		case *IfStmt:
+			innerBlock(ctxt, s.Then.Pos(), s.Then.List)
+			if s.Else != nil {
+				innerBlock(ctxt, s.Else.Pos(), []Stmt{s.Else})
+			}
+
+		case *ForStmt:
+			innerBlock(targets{s, s}, s.Body.Pos(), s.Body.List)
+
+		case *SwitchStmt:
+			inner := targets{s, ctxt.continues}
+			for _, cc := range s.Body {
+				innerBlock(inner, cc.Pos(), cc.Body)
+			}
+
+		case *SelectStmt:
+			inner := targets{s, ctxt.continues}
+			for _, cc := range s.Body {
+				innerBlock(inner, cc.Pos(), cc.Body)
+			}
+		}
+	}
+
+	return fwdGotos
+}
diff --git a/src/cmd/compile/internal/syntax/dumper.go b/src/cmd/compile/internal/syntax/dumper.go
index bb369fc..01453d5 100644
--- a/src/cmd/compile/internal/syntax/dumper.go
+++ b/src/cmd/compile/internal/syntax/dumper.go
@@ -119,7 +119,7 @@ func (p *dumper) dump(x reflect.Value, n Node) {
 
 		// special cases for identifiers w/o attached comments (common case)
 		if x, ok := x.Interface().(*Name); ok {
-			p.printf(x.Value)
+			p.printf("%s @ %v", x.Value, x.Pos())
 			return
 		}
 
diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go
index 2b20cbd..02116f5 100644
--- a/src/cmd/compile/internal/syntax/dumper_test.go
+++ b/src/cmd/compile/internal/syntax/dumper_test.go
@@ -14,7 +14,7 @@ func TestDump(t *testing.T) {
 		t.Skip("skipping test in short mode")
 	}
 
-	ast, err := ParseFile(*src, nil, nil, 0)
+	ast, err := ParseFile(*src_, nil, nil, CheckBranches)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go
index fadba84..7ab6df1 100644
--- a/src/cmd/compile/internal/syntax/nodes.go
+++ b/src/cmd/compile/internal/syntax/nodes.go
@@ -4,32 +4,32 @@
 
 package syntax
 
+import "cmd/internal/src"
+
 // ----------------------------------------------------------------------------
 // Nodes
 
 type Node interface {
-	Line() uint32
+	// Pos() returns the position associated with the node as follows:
+	// 1) The position of a node representing a terminal syntax production
+	//    (Name, BasicLit, etc.) is the position of the respective production
+	//    in the source.
+	// 2) The position of a node representing a non-terminal production
+	//    (IndexExpr, IfStmt, etc.) is the position of a token uniquely
+	//    associated with that production; usually the left-most one
+	//    ('[' for IndexExpr, 'if' for IfStmt, etc.)
+	Pos() src.Pos
 	aNode()
-	init(p *parser)
 }
 
 type node struct {
 	// commented out for now since not yet used
 	// doc  *Comment // nil means no comment(s) attached
-	pos  uint32
-	line uint32
-}
-
-func (*node) aNode() {}
-
-func (n *node) Line() uint32 {
-	return n.line
+	pos src.Pos
 }
 
-func (n *node) init(p *parser) {
-	n.pos = uint32(p.pos)
-	n.line = uint32(p.line)
-}
+func (n *node) Pos() src.Pos { return n.pos }
+func (*node) aNode()         {}
 
 // ----------------------------------------------------------------------------
 // Files
@@ -38,7 +38,7 @@ func (n *node) init(p *parser) {
 type File struct {
 	PkgName  *Name
 	DeclList []Decl
-	Lines    int
+	Lines    uint
 	node
 }
 
@@ -74,6 +74,7 @@ type (
 	// Name Type
 	TypeDecl struct {
 		Name   *Name
+		Alias  bool
 		Type   Expr
 		Group  *Group // nil means not part of a group
 		Pragma Pragma
@@ -96,13 +97,12 @@ type (
 	// func Receiver Name Type { Body }
 	// func Receiver Name Type
 	FuncDecl struct {
-		Attr    map[string]bool // go:attr map
-		Recv    *Field          // nil means regular function
-		Name    *Name
-		Type    *FuncType
-		Body    []Stmt // nil means no body (forward declaration)
-		Pragma  Pragma // TODO(mdempsky): Cleaner solution.
-		EndLine uint32 // TODO(mdempsky): Cleaner solution.
+		Attr   map[string]bool // go:attr map
+		Recv   *Field          // nil means regular function
+		Name   *Name
+		Type   *FuncType
+		Body   *BlockStmt // nil means no body (forward declaration)
+		Pragma Pragma     // TODO(mdempsky): Cleaner solution.
 		decl
 	}
 )
@@ -125,6 +125,12 @@ type (
 		aExpr()
 	}
 
+	// Placeholder for an expression that failed to parse
+	// correctly and where we can't provide a better node.
+	BadExpr struct {
+		expr
+	}
+
 	// Value
 	Name struct {
 		Value string
@@ -142,8 +148,8 @@ type (
 	CompositeLit struct {
 		Type     Expr // nil means no literal type
 		ElemList []Expr
-		NKeys    int    // number of elements with keys
-		EndLine  uint32 // TODO(mdempsky): Cleaner solution.
+		NKeys    int // number of elements with keys
+		Rbrace   src.Pos
 		expr
 	}
 
@@ -155,9 +161,8 @@ type (
 
 	// func Type { Body }
 	FuncLit struct {
-		Type    *FuncType
-		Body    []Stmt
-		EndLine uint32 // TODO(mdempsky): Cleaner solution.
+		Type *FuncType
+		Body *BlockStmt
 		expr
 	}
 
@@ -322,7 +327,8 @@ type (
 	}
 
 	BlockStmt struct {
-		Body []Stmt
+		List   []Stmt
+		Rbrace src.Pos
 		stmt
 	}
 
@@ -350,6 +356,12 @@ type (
 	BranchStmt struct {
 		Tok   token // Break, Continue, Fallthrough, or Goto
 		Label *Name
+		// Target is the continuation of the control flow after executing
+		// the branch; it is computed by the parser if CheckBranches is set.
+		// Target is a *LabeledStmt for gotos, and a *SwitchStmt, *SelectStmt,
+		// or *ForStmt for breaks and continues, depending on the context of
+		// the branch. Target is not set for fallthroughs.
+		Target Stmt
 		stmt
 	}
 
@@ -367,7 +379,7 @@ type (
 	IfStmt struct {
 		Init SimpleStmt
 		Cond Expr
-		Then []Stmt
+		Then *BlockStmt
 		Else Stmt // either *IfStmt or *BlockStmt
 		stmt
 	}
@@ -376,19 +388,21 @@ type (
 		Init SimpleStmt // incl. *RangeClause
 		Cond Expr
 		Post SimpleStmt
-		Body []Stmt
+		Body *BlockStmt
 		stmt
 	}
 
 	SwitchStmt struct {
-		Init SimpleStmt
-		Tag  Expr
-		Body []*CaseClause
+		Init   SimpleStmt
+		Tag    Expr
+		Body   []*CaseClause
+		Rbrace src.Pos
 		stmt
 	}
 
 	SelectStmt struct {
-		Body []*CommClause
+		Body   []*CommClause
+		Rbrace src.Pos
 		stmt
 	}
 )
@@ -411,12 +425,14 @@ type (
 	CaseClause struct {
 		Cases Expr // nil means default clause
 		Body  []Stmt
+		Colon src.Pos
 		node
 	}
 
 	CommClause struct {
-		Comm SimpleStmt // send or receive stmt; nil means default clause
-		Body []Stmt
+		Comm  SimpleStmt // send or receive stmt; nil means default clause
+		Body  []Stmt
+		Colon src.Pos
 		node
 	}
 )
diff --git a/src/cmd/compile/internal/syntax/nodes_test.go b/src/cmd/compile/internal/syntax/nodes_test.go
new file mode 100644
index 0000000..be9d5d8
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/nodes_test.go
@@ -0,0 +1,329 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+// A test is a source code snippet of a particular node type.
+// In the snippet, a '@' indicates the position recorded by
+// the parser when creating the respective node.
+type test struct {
+	nodetyp string
+	snippet string
+}
+
+var decls = []test{
+	// The position of declarations is always the
+	// position of the first token of an individual
+	// declaration, independent of grouping.
+	{"ImportDecl", `import @"math"`},
+	{"ImportDecl", `import @mymath "math"`},
+	{"ImportDecl", `import @. "math"`},
+	{"ImportDecl", `import (@"math")`},
+	{"ImportDecl", `import (@mymath "math")`},
+	{"ImportDecl", `import (@. "math")`},
+
+	{"ConstDecl", `const @x`},
+	{"ConstDecl", `const @x = 0`},
+	{"ConstDecl", `const @x, y, z = 0, 1, 2`},
+	{"ConstDecl", `const (@x)`},
+	{"ConstDecl", `const (@x = 0)`},
+	{"ConstDecl", `const (@x, y, z = 0, 1, 2)`},
+
+	{"TypeDecl", `type @T int`},
+	{"TypeDecl", `type @T = int`},
+	{"TypeDecl", `type (@T int)`},
+	{"TypeDecl", `type (@T = int)`},
+
+	{"VarDecl", `var @x int`},
+	{"VarDecl", `var @x, y, z int`},
+	{"VarDecl", `var @x int = 0`},
+	{"VarDecl", `var @x, y, z int = 1, 2, 3`},
+	{"VarDecl", `var @x = 0`},
+	{"VarDecl", `var @x, y, z = 1, 2, 3`},
+	{"VarDecl", `var (@x int)`},
+	{"VarDecl", `var (@x, y, z int)`},
+	{"VarDecl", `var (@x int = 0)`},
+	{"VarDecl", `var (@x, y, z int = 1, 2, 3)`},
+	{"VarDecl", `var (@x = 0)`},
+	{"VarDecl", `var (@x, y, z = 1, 2, 3)`},
+
+	{"FuncDecl", `func @f() {}`},
+	{"FuncDecl", `func @(T) f() {}`},
+	{"FuncDecl", `func @(x T) f() {}`},
+}
+
+var exprs = []test{
+	// The position of an expression is the position
+	// of the left-most token that identifies the
+	// kind of expression.
+	{"Name", `@x`},
+
+	{"BasicLit", `@0`},
+	{"BasicLit", `@0x123`},
+	{"BasicLit", `@3.1415`},
+	{"BasicLit", `@.2718`},
+	{"BasicLit", `@1i`},
+	{"BasicLit", `@'a'`},
+	{"BasicLit", `@"abc"`},
+	{"BasicLit", "@`abc`"},
+
+	{"CompositeLit", `@{}`},
+	{"CompositeLit", `T@{}`},
+	{"CompositeLit", `struct{x, y int}@{}`},
+
+	{"KeyValueExpr", `"foo"@: true`},
+	{"KeyValueExpr", `"a"@: b`},
+
+	{"FuncLit", `@func (){}`},
+	{"ParenExpr", `@(x)`},
+	{"SelectorExpr", `a at .b`},
+	{"IndexExpr", `a@[i]`},
+
+	{"SliceExpr", `a@[:]`},
+	{"SliceExpr", `a@[i:]`},
+	{"SliceExpr", `a@[:j]`},
+	{"SliceExpr", `a@[i:j]`},
+	{"SliceExpr", `a@[i:j:k]`},
+
+	{"AssertExpr", `x at .(T)`},
+
+	{"Operation", `@*b`},
+	{"Operation", `@+b`},
+	{"Operation", `@-b`},
+	{"Operation", `@!b`},
+	{"Operation", `@^b`},
+	{"Operation", `@&b`},
+	{"Operation", `@<-b`},
+
+	{"Operation", `a @|| b`},
+	{"Operation", `a @&& b`},
+	{"Operation", `a @== b`},
+	{"Operation", `a @+ b`},
+	{"Operation", `a @* b`},
+
+	{"CallExpr", `f@()`},
+	{"CallExpr", `f@(x, y, z)`},
+	{"CallExpr", `obj.f@(1, 2, 3)`},
+	{"CallExpr", `func(x int) int { return x + 1 }@(y)`},
+
+	// ListExpr: tested via multi-value const/var declarations
+}
+
+var types = []test{
+	{"Operation", `@*T`},
+	{"Operation", `@*struct{}`},
+
+	{"ArrayType", `@[10]T`},
+	{"ArrayType", `@[...]T`},
+
+	{"SliceType", `@[]T`},
+	{"DotsType", `@...T`},
+	{"StructType", `@struct{}`},
+	{"InterfaceType", `@interface{}`},
+	{"FuncType", `func@()`},
+	{"MapType", `@map[T]T`},
+
+	{"ChanType", `@chan T`},
+	{"ChanType", `@chan<- T`},
+	{"ChanType", `@<-chan T`},
+}
+
+var fields = []test{
+	{"Field", `@T`},
+	{"Field", `@(T)`},
+	{"Field", `@x T`},
+	{"Field", `@x *(T)`},
+	{"Field", `@x, y, z T`},
+	{"Field", `@x, y, z (*T)`},
+}
+
+var stmts = []test{
+	{"EmptyStmt", `@`},
+
+	{"LabeledStmt", `L@:`},
+	{"LabeledStmt", `L@: ;`},
+	{"LabeledStmt", `L@: f()`},
+
+	{"BlockStmt", `@{}`},
+
+	// The position of an ExprStmt is the position of the expression.
+	{"ExprStmt", `@<-ch`},
+	{"ExprStmt", `f@()`},
+	{"ExprStmt", `append@(s, 1, 2, 3)`},
+
+	{"SendStmt", `ch @<- x`},
+
+	{"DeclStmt", `@const x = 0`},
+	{"DeclStmt", `@const (x = 0)`},
+	{"DeclStmt", `@type T int`},
+	{"DeclStmt", `@type T = int`},
+	{"DeclStmt", `@type (T1 = int; T2 = float32)`},
+	{"DeclStmt", `@var x = 0`},
+	{"DeclStmt", `@var x, y, z int`},
+	{"DeclStmt", `@var (a, b = 1, 2)`},
+
+	{"AssignStmt", `x @= y`},
+	{"AssignStmt", `a, b, x @= 1, 2, 3`},
+	{"AssignStmt", `x @+= y`},
+	{"AssignStmt", `x @:= y`},
+	{"AssignStmt", `x, ok @:= f()`},
+	{"AssignStmt", `x at ++`},
+	{"AssignStmt", `a[i]@--`},
+
+	{"BranchStmt", `@break`},
+	{"BranchStmt", `@break L`},
+	{"BranchStmt", `@continue`},
+	{"BranchStmt", `@continue L`},
+	{"BranchStmt", `@fallthrough`},
+	{"BranchStmt", `@goto L`},
+
+	{"CallStmt", `@defer f()`},
+	{"CallStmt", `@go f()`},
+
+	{"ReturnStmt", `@return`},
+	{"ReturnStmt", `@return x`},
+	{"ReturnStmt", `@return a, b, a + b*f(1, 2, 3)`},
+
+	{"IfStmt", `@if cond {}`},
+	{"IfStmt", `@if cond { f() } else {}`},
+	{"IfStmt", `@if cond { f() } else { g(); h() }`},
+	{"ForStmt", `@for {}`},
+	{"ForStmt", `@for { f() }`},
+	{"SwitchStmt", `@switch {}`},
+	{"SwitchStmt", `@switch { default: }`},
+	{"SwitchStmt", `@switch { default: x++ }`},
+	{"SelectStmt", `@select {}`},
+	{"SelectStmt", `@select { default: }`},
+	{"SelectStmt", `@select { default: ch <- false }`},
+}
+
+var ranges = []test{
+	{"RangeClause", `@range s`},
+	{"RangeClause", `i = @range s`},
+	{"RangeClause", `i := @range s`},
+	{"RangeClause", `_, x = @range s`},
+	{"RangeClause", `i, x = @range s`},
+	{"RangeClause", `_, x := @range s.f`},
+	{"RangeClause", `i, x := @range f(i)`},
+}
+
+var guards = []test{
+	{"TypeSwitchGuard", `x at .(type)`},
+	{"TypeSwitchGuard", `x := x at .(type)`},
+}
+
+var cases = []test{
+	{"CaseClause", `@case x:`},
+	{"CaseClause", `@case x, y, z:`},
+	{"CaseClause", `@case x == 1, y == 2:`},
+	{"CaseClause", `@default:`},
+}
+
+var comms = []test{
+	{"CommClause", `@case <-ch:`},
+	{"CommClause", `@case x <- ch:`},
+	{"CommClause", `@case x = <-ch:`},
+	{"CommClause", `@case x := <-ch:`},
+	{"CommClause", `@case x, ok = <-ch: f(1, 2, 3)`},
+	{"CommClause", `@case x, ok := <-ch: x++`},
+	{"CommClause", `@default:`},
+	{"CommClause", `@default: ch <- true`},
+}
+
+func TestPos(t *testing.T) {
+	// TODO(gri) Once we have a general tree walker, we can use that to find
+	// the first occurrence of the respective node and we don't need to hand-
+	// extract the node for each specific kind of construct.
+
+	testPos(t, decls, "package p; ", "",
+		func(f *File) Node { return f.DeclList[0] },
+	)
+
+	// embed expressions in a composite literal so we can test key:value and naked composite literals
+	testPos(t, exprs, "package p; var _ = T{ ", " }",
+		func(f *File) Node { return f.DeclList[0].(*VarDecl).Values.(*CompositeLit).ElemList[0] },
+	)
+
+	// embed types in a function  signature so we can test ... types
+	testPos(t, types, "package p; func f(", ")",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0].Type },
+	)
+
+	testPos(t, fields, "package p; func f(", ")",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0] },
+	)
+
+	testPos(t, stmts, "package p; func _() { ", "; }",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0] },
+	)
+
+	testPos(t, ranges, "package p; func _() { for ", " {} }",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*ForStmt).Init.(*RangeClause) },
+	)
+
+	testPos(t, guards, "package p; func _() { switch ", " {} }",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Tag.(*TypeSwitchGuard) },
+	)
+
+	testPos(t, cases, "package p; func _() { switch { ", " } }",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Body[0] },
+	)
+
+	testPos(t, comms, "package p; func _() { select { ", " } }",
+		func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SelectStmt).Body[0] },
+	)
+}
+
+func testPos(t *testing.T, list []test, prefix, suffix string, extract func(*File) Node) {
+	for _, test := range list {
+		// complete source, compute @ position, and strip @ from source
+		src, index := stripAt(prefix + test.snippet + suffix)
+		if index < 0 {
+			t.Errorf("missing @: %s (%s)", src, test.nodetyp)
+			continue
+		}
+
+		// build syntaxt tree
+		file, err := ParseBytes(nil, []byte(src), nil, nil, 0)
+		if err != nil {
+			t.Errorf("parse error: %s: %v (%s)", src, err, test.nodetyp)
+			continue
+		}
+
+		// extract desired node
+		node := extract(file)
+		if typ := typeOf(node); typ != test.nodetyp {
+			t.Errorf("type error: %s: type = %s, want %s", src, typ, test.nodetyp)
+			continue
+		}
+
+		// verify node position with expected position as indicated by @
+		if pos := int(node.Pos().Col()); pos != index+colbase {
+			t.Errorf("pos error: %s: pos = %d, want %d (%s)", src, pos, index+colbase, test.nodetyp)
+			continue
+		}
+	}
+}
+
+func stripAt(s string) (string, int) {
+	if i := strings.Index(s, "@"); i >= 0 {
+		return s[:i] + s[i+1:], i
+	}
+	return s, -1
+}
+
+func typeOf(n Node) string {
+	const prefix = "*syntax."
+	k := fmt.Sprintf("%T", n)
+	if strings.HasPrefix(k, prefix) {
+		return k[len(prefix):]
+	}
+	return k
+}
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index e45ca05..fee52c8 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -5,35 +5,80 @@
 package syntax
 
 import (
+	"cmd/internal/src"
 	"fmt"
 	"io"
+	"strconv"
 	"strings"
 )
 
 const debug = false
 const trace = false
 
-// The old gc parser assigned line numbers very inconsistently depending
-// on when it happened to construct AST nodes. To make transitioning to the
-// new AST easier, we try to mimick the behavior as much as possible.
-const gcCompat = true
-
 type parser struct {
+	base *src.PosBase
+	errh ErrorHandler
+	mode Mode
 	scanner
 
+	first  error  // first error encountered
+	pragma Pragma // pragma flags
+
 	fnest  int    // function nesting level (for error handling)
 	xnest  int    // expression nesting level (for complit ambiguity resolution)
 	indent []byte // tracing support
 }
 
-func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
-	p.scanner.init(src, errh, pragh)
+func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) {
+	p.base = base
+	p.errh = errh
+	p.mode = mode
+	p.scanner.init(
+		r,
+		// Error and pragma handlers for scanner.
+		// Because the (line, col) positions passed to these
+		// handlers are always at or after the current reading
+		// position, it is save to use the most recent position
+		// base to compute the corresponding Pos value.
+		func(line, col uint, msg string) {
+			p.error_at(p.pos_at(line, col), msg)
+		},
+		func(line, col uint, text string) {
+			if strings.HasPrefix(text, "line ") {
+				p.updateBase(line, col+5, text[5:])
+				return
+			}
+			if pragh != nil {
+				p.pragma |= pragh(p.pos_at(line, col), text)
+			}
+		},
+	)
+
+	p.first = nil
+	p.pragma = 0
 
 	p.fnest = 0
 	p.xnest = 0
 	p.indent = nil
 }
 
+const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix
+
+func (p *parser) updateBase(line, col uint, text string) {
+	// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
+	i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
+	if i < 0 {
+		return // ignore (not a line directive)
+	}
+	nstr := text[i+1:]
+	n, err := strconv.Atoi(nstr)
+	if err != nil || n <= 0 || n > lineMax {
+		p.error_at(p.pos_at(line, col+uint(i+1)), "invalid line number: "+nstr)
+		return
+	}
+	p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), text[:i], uint(n))
+}
+
 func (p *parser) got(tok token) bool {
 	if p.tok == tok {
 		p.next()
@@ -52,13 +97,25 @@ func (p *parser) want(tok token) {
 // ----------------------------------------------------------------------------
 // Error handling
 
-// syntax_error reports a syntax error at the current line.
-func (p *parser) syntax_error(msg string) {
-	p.syntax_error_at(p.pos, p.line, msg)
+// pos_at returns the Pos value for (line, col) and the current position base.
+func (p *parser) pos_at(line, col uint) src.Pos {
+	return src.MakePos(p.base, line, col)
 }
 
-// Like syntax_error, but reports error at given line rather than current lexer line.
-func (p *parser) syntax_error_at(pos, line int, msg string) {
+// error reports an error at the given position.
+func (p *parser) error_at(pos src.Pos, msg string) {
+	err := Error{pos, msg}
+	if p.first == nil {
+		p.first = err
+	}
+	if p.errh == nil {
+		panic(p.first)
+	}
+	p.errh(err)
+}
+
+// syntax_error_at reports a syntax error at the given position.
+func (p *parser) syntax_error_at(pos src.Pos, msg string) {
 	if trace {
 		defer p.trace("syntax_error (" + msg + ")")()
 	}
@@ -77,14 +134,14 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
 		msg = ", " + msg
 	default:
 		// plain error - we don't care about current token
-		p.error_at(pos, line, "syntax error: "+msg)
+		p.error_at(pos, "syntax error: "+msg)
 		return
 	}
 
 	// determine token string
 	var tok string
 	switch p.tok {
-	case _Name:
+	case _Name, _Semi:
 		tok = p.lit
 	case _Literal:
 		tok = "literal " + p.lit
@@ -99,9 +156,14 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
 		tok = tokstring(p.tok)
 	}
 
-	p.error_at(pos, line, "syntax error: unexpected "+tok+msg)
+	p.error_at(pos, "syntax error: unexpected "+tok+msg)
 }
 
+// Convenience methods using the current token position.
+func (p *parser) pos() src.Pos            { return p.pos_at(p.line, p.col) }
+func (p *parser) error(msg string)        { p.error_at(p.pos(), msg) }
+func (p *parser) syntax_error(msg string) { p.syntax_error_at(p.pos(), msg) }
+
 // The stopset contains keywords that start a statement.
 // They are good synchronization points in case of syntax
 // errors and (usually) shouldn't be skipped over.
@@ -132,7 +194,7 @@ func (p *parser) advance(followlist ...token) {
 	}
 
 	// compute follow set
-	// TODO(gri) the args are constants - do as constant expressions?
+	// (not speed critical, advance is only called in error situations)
 	var followset uint64 = 1 << _EOF // never skip over EOF
 	for _, tok := range followlist {
 		followset |= 1 << tok
@@ -150,7 +212,7 @@ func tokstring(tok token) string {
 	case _Comma:
 		return "comma"
 	case _Semi:
-		return "semicolon or newline"
+		return "semicolon"
 	}
 	return tok.String()
 }
@@ -175,15 +237,18 @@ func (p *parser) trace(msg string) func() {
 // Parse methods are annotated with matching Go productions as appropriate.
 // The annotations are intended as guidelines only since a single Go grammar
 // rule may be covered by multiple parse methods and vice versa.
+//
+// Excluding methods returning slices, parse methods named xOrNil may return
+// nil; all others are expected to return a valid non-nil node.
 
 // SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
-func (p *parser) file() *File {
+func (p *parser) fileOrNil() *File {
 	if trace {
 		defer p.trace("file")()
 	}
 
 	f := new(File)
-	f.init(p)
+	f.pos = p.pos()
 
 	// PackageClause
 	if !p.got(_Package) {
@@ -221,10 +286,12 @@ func (p *parser) file() *File {
 
 		case _Func:
 			p.next()
-			f.DeclList = append(f.DeclList, p.funcDecl())
+			if d := p.funcDeclOrNil(); d != nil {
+				f.DeclList = append(f.DeclList, d)
+			}
 
 		default:
-			if p.tok == _Lbrace && len(f.DeclList) > 0 && emptyFuncDecl(f.DeclList[len(f.DeclList)-1]) {
+			if p.tok == _Lbrace && len(f.DeclList) > 0 && isEmptyFuncDecl(f.DeclList[len(f.DeclList)-1]) {
 				// opening { of function declaration on next line
 				p.syntax_error("unexpected semicolon or newline before {")
 			} else {
@@ -250,7 +317,7 @@ func (p *parser) file() *File {
 	return f
 }
 
-func emptyFuncDecl(dcl Decl) bool {
+func isEmptyFuncDecl(dcl Decl) bool {
 	f, ok := dcl.(*FuncDecl)
 	return ok && f.Body == nil
 }
@@ -269,35 +336,43 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
 			}
 		}
 		p.want(_Rparen)
-		return list
+	} else {
+		list = append(list, f(nil))
+	}
+
+	if debug {
+		for _, d := range list {
+			if d == nil {
+				panic("nil list entry")
+			}
+		}
 	}
 
-	return append(list, f(nil))
+	return list
 }
 
+// ImportSpec = [ "." | PackageName ] ImportPath .
+// ImportPath = string_lit .
 func (p *parser) importDecl(group *Group) Decl {
 	if trace {
 		defer p.trace("importDecl")()
 	}
 
 	d := new(ImportDecl)
-	d.init(p)
+	d.pos = p.pos()
 
 	switch p.tok {
 	case _Name:
 		d.LocalPkgName = p.name()
 	case _Dot:
-		n := new(Name)
-		n.init(p)
-		n.Value = "."
-		d.LocalPkgName = n
+		d.LocalPkgName = p.newName(".")
 		p.next()
 	}
-	if p.tok == _Literal && (gcCompat || p.kind == StringLit) {
-		d.Path = p.oliteral()
-	} else {
-		p.syntax_error("missing import path; require quoted string")
+	d.Path = p.oliteral()
+	if d.Path == nil {
+		p.syntax_error("missing import path")
 		p.advance(_Semi, _Rparen)
+		return nil
 	}
 	d.Group = group
 
@@ -311,11 +386,11 @@ func (p *parser) constDecl(group *Group) Decl {
 	}
 
 	d := new(ConstDecl)
-	d.init(p)
+	d.pos = p.pos()
 
 	d.NameList = p.nameList(p.name())
 	if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen {
-		d.Type = p.tryType()
+		d.Type = p.typeOrNil()
 		if p.got(_Assign) {
 			d.Values = p.exprList()
 		}
@@ -325,18 +400,20 @@ func (p *parser) constDecl(group *Group) Decl {
 	return d
 }
 
-// TypeSpec = identifier Type .
+// TypeSpec = identifier [ "=" ] Type .
 func (p *parser) typeDecl(group *Group) Decl {
 	if trace {
 		defer p.trace("typeDecl")()
 	}
 
 	d := new(TypeDecl)
-	d.init(p)
+	d.pos = p.pos()
 
 	d.Name = p.name()
-	d.Type = p.tryType()
+	d.Alias = p.got(_Assign)
+	d.Type = p.typeOrNil()
 	if d.Type == nil {
+		d.Type = p.bad()
 		p.syntax_error("in type declaration")
 		p.advance(_Semi, _Rparen)
 	}
@@ -353,7 +430,7 @@ func (p *parser) varDecl(group *Group) Decl {
 	}
 
 	d := new(VarDecl)
-	d.init(p)
+	d.pos = p.pos()
 
 	d.NameList = p.nameList(p.name())
 	if p.got(_Assign) {
@@ -365,9 +442,6 @@ func (p *parser) varDecl(group *Group) Decl {
 		}
 	}
 	d.Group = group
-	if gcCompat {
-		d.init(p)
-	}
 
 	return d
 }
@@ -377,26 +451,24 @@ func (p *parser) varDecl(group *Group) Decl {
 // Function     = Signature FunctionBody .
 // MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
 // Receiver     = Parameters .
-func (p *parser) funcDecl() *FuncDecl {
+func (p *parser) funcDeclOrNil() *FuncDecl {
 	if trace {
 		defer p.trace("funcDecl")()
 	}
 
 	f := new(FuncDecl)
-	f.init(p)
+	f.pos = p.pos()
 
-	badRecv := false
 	if p.tok == _Lparen {
 		rcvr := p.paramList()
 		switch len(rcvr) {
 		case 0:
 			p.error("method has no receiver")
-			badRecv = true
-		case 1:
-			f.Recv = rcvr[0]
 		default:
 			p.error("method has multiple receivers")
-			badRecv = true
+			fallthrough
+		case 1:
+			f.Recv = rcvr[0]
 		}
 	}
 
@@ -422,22 +494,20 @@ func (p *parser) funcDecl() *FuncDecl {
 
 	f.Name = p.name()
 	f.Type = p.funcType()
-	if gcCompat {
-		f.node = f.Type.node
+	if p.tok == _Lbrace {
+		f.Body = p.blockStmt("")
+		if p.mode&CheckBranches != 0 {
+			checkBranches(f.Body, p.errh)
+		}
 	}
-	f.Body = p.funcBody()
 
 	f.Pragma = p.pragma
-	f.EndLine = uint32(p.line)
 
 	// TODO(gri) deal with function properties
 	// if noescape && body != nil {
 	// 	p.error("can only use //go:noescape with external func implementations")
 	// }
 
-	if badRecv {
-		return nil // TODO(gri) better solution
-	}
 	return f
 }
 
@@ -459,15 +529,12 @@ func (p *parser) binaryExpr(prec int) Expr {
 	x := p.unaryExpr()
 	for (p.tok == _Operator || p.tok == _Star) && p.prec > prec {
 		t := new(Operation)
-		t.init(p)
+		t.pos = p.pos()
 		t.Op = p.op
 		t.X = x
 		tprec := p.prec
 		p.next()
 		t.Y = p.binaryExpr(tprec)
-		if gcCompat {
-			t.init(p)
-		}
 		x = t
 	}
 	return x
@@ -484,20 +551,17 @@ func (p *parser) unaryExpr() Expr {
 		switch p.op {
 		case Mul, Add, Sub, Not, Xor:
 			x := new(Operation)
-			x.init(p)
+			x.pos = p.pos()
 			x.Op = p.op
 			p.next()
 			x.X = p.unaryExpr()
-			if gcCompat {
-				x.init(p)
-			}
 			return x
 
 		case And:
-			p.next()
 			x := new(Operation)
-			x.init(p)
+			x.pos = p.pos()
 			x.Op = And
+			p.next()
 			// unaryExpr may have returned a parenthesized composite literal
 			// (see comment in operand) - remove parentheses if any
 			x.X = unparen(p.unaryExpr())
@@ -506,6 +570,7 @@ func (p *parser) unaryExpr() Expr {
 
 	case _Arrow:
 		// receive op (<-x) or receive-only channel (<-chan E)
+		pos := p.pos()
 		p.next()
 
 		// If the next token is _Chan we still don't know if it is
@@ -554,7 +619,11 @@ func (p *parser) unaryExpr() Expr {
 		}
 
 		// x is not a channel type => we have a receive op
-		return &Operation{Op: Recv, X: x}
+		o := new(Operation)
+		o.pos = pos
+		o.Op = Recv
+		o.X = x
+		return o
 	}
 
 	// TODO(mdempsky): We need parens here so we can report an
@@ -570,26 +639,28 @@ func (p *parser) callStmt() *CallStmt {
 	}
 
 	s := new(CallStmt)
-	s.init(p)
-	s.Tok = p.tok
+	s.pos = p.pos()
+	s.Tok = p.tok // _Defer or _Go
 	p.next()
 
 	x := p.pexpr(p.tok == _Lparen) // keep_parens so we can report error below
-	switch x := x.(type) {
-	case *CallExpr:
-		s.Call = x
-		if gcCompat {
-			s.node = x.node
-		}
-	case *ParenExpr:
+	if t := unparen(x); t != x {
 		p.error(fmt.Sprintf("expression in %s must not be parenthesized", s.Tok))
 		// already progressed, no need to advance
-	default:
+		x = t
+	}
+
+	cx, ok := x.(*CallExpr)
+	if !ok {
 		p.error(fmt.Sprintf("expression in %s must be function call", s.Tok))
 		// already progressed, no need to advance
+		cx := new(CallExpr)
+		cx.pos = x.Pos()
+		cx.Fun = p.bad()
 	}
 
-	return s // TODO(gri) should we return nil in case of failure?
+	s.Call = cx
+	return s
 }
 
 // Operand     = Literal | OperandName | MethodExpr | "(" Expression ")" .
@@ -609,9 +680,10 @@ func (p *parser) operand(keep_parens bool) Expr {
 		return p.oliteral()
 
 	case _Lparen:
+		pos := p.pos()
 		p.next()
 		p.xnest++
-		x := p.expr() // expr_or_type
+		x := p.expr()
 		p.xnest--
 		p.want(_Rparen)
 
@@ -637,23 +709,29 @@ func (p *parser) operand(keep_parens bool) Expr {
 		// in a go/defer statement. In that case, operand is called
 		// with keep_parens set.
 		if keep_parens {
-			x = &ParenExpr{X: x}
+			px := new(ParenExpr)
+			px.pos = pos
+			px.X = x
+			x = px
 		}
 		return x
 
 	case _Func:
+		pos := p.pos()
 		p.next()
 		t := p.funcType()
 		if p.tok == _Lbrace {
-			p.fnest++
 			p.xnest++
+
 			f := new(FuncLit)
-			f.init(p)
+			f.pos = pos
 			f.Type = t
-			f.Body = p.funcBody()
-			f.EndLine = uint32(p.line)
+			f.Body = p.blockStmt("")
+			if p.mode&CheckBranches != 0 {
+				checkBranches(f.Body, p.errh)
+			}
+
 			p.xnest--
-			p.fnest--
 			return f
 		}
 		return t
@@ -661,16 +739,11 @@ func (p *parser) operand(keep_parens bool) Expr {
 	case _Lbrack, _Chan, _Map, _Struct, _Interface:
 		return p.type_() // othertype
 
-	case _Lbrace:
-		// common case: p.header is missing simpleStmt before { in if, for, switch
-		p.syntax_error("missing operand")
-		// '{' will be consumed in pexpr - no need to consume it here
-		return nil
-
 	default:
+		x := p.bad()
 		p.syntax_error("expecting expression")
 		p.advance()
-		return nil
+		return x
 	}
 
 	// Syntactically, composite literals are operands. Because a complit
@@ -704,6 +777,7 @@ func (p *parser) pexpr(keep_parens bool) Expr {
 
 loop:
 	for {
+		pos := p.pos()
 		switch p.tok {
 		case _Dot:
 			p.next()
@@ -711,7 +785,7 @@ loop:
 			case _Name:
 				// pexpr '.' sym
 				t := new(SelectorExpr)
-				t.init(p)
+				t.pos = pos
 				t.X = x
 				t.Sel = p.name()
 				x = t
@@ -720,12 +794,12 @@ loop:
 				p.next()
 				if p.got(_Type) {
 					t := new(TypeSwitchGuard)
-					t.init(p)
+					t.pos = pos
 					t.X = x
 					x = t
 				} else {
 					t := new(AssertExpr)
-					t.init(p)
+					t.pos = pos
 					t.X = x
 					t.Type = p.expr()
 					x = t
@@ -736,9 +810,6 @@ loop:
 				p.syntax_error("expecting name or (")
 				p.advance(_Semi, _Rparen)
 			}
-			if gcCompat {
-				x.init(p)
-			}
 
 		case _Lbrack:
 			p.next()
@@ -750,7 +821,7 @@ loop:
 				if p.got(_Rbrack) {
 					// x[i]
 					t := new(IndexExpr)
-					t.init(p)
+					t.pos = pos
 					t.X = x
 					t.Index = i
 					x = t
@@ -761,7 +832,7 @@ loop:
 
 			// x[i:...
 			t := new(SliceExpr)
-			t.init(p)
+			t.pos = pos
 			t.X = x
 			t.Index[0] = i
 			p.want(_Colon)
@@ -794,12 +865,12 @@ loop:
 			// operand may have returned a parenthesized complit
 			// type; accept it but complain if we have a complit
 			t := unparen(x)
-			// determine if '{' belongs to a complit or a compound_stmt
+			// determine if '{' belongs to a composite literal or a block statement
 			complit_ok := false
 			switch t.(type) {
 			case *Name, *SelectorExpr:
 				if p.xnest >= 0 {
-					// x is considered a comptype
+					// x is considered a composite literal type
 					complit_ok = true
 				}
 			case *ArrayType, *SliceType, *StructType, *MapType:
@@ -846,7 +917,7 @@ func (p *parser) complitexpr() *CompositeLit {
 	}
 
 	x := new(CompositeLit)
-	x.init(p)
+	x.pos = p.pos()
 
 	p.want(_Lbrace)
 	p.xnest++
@@ -854,15 +925,13 @@ func (p *parser) complitexpr() *CompositeLit {
 	for p.tok != _EOF && p.tok != _Rbrace {
 		// value
 		e := p.bare_complitexpr()
-		if p.got(_Colon) {
+		if p.tok == _Colon {
 			// key ':' value
 			l := new(KeyValueExpr)
-			l.init(p)
+			l.pos = p.pos()
+			p.next()
 			l.Key = e
 			l.Value = p.bare_complitexpr()
-			if gcCompat {
-				l.init(p)
-			}
 			e = l
 			x.NKeys++
 		}
@@ -872,7 +941,7 @@ func (p *parser) complitexpr() *CompositeLit {
 		}
 	}
 
-	x.EndLine = uint32(p.line)
+	x.Rbrace = p.pos()
 	p.xnest--
 	p.want(_Rbrace)
 
@@ -887,43 +956,49 @@ func (p *parser) type_() Expr {
 		defer p.trace("type_")()
 	}
 
-	if typ := p.tryType(); typ != nil {
-		return typ
+	typ := p.typeOrNil()
+	if typ == nil {
+		typ = p.bad()
+		p.syntax_error("expecting type")
+		p.advance()
 	}
 
-	p.syntax_error("")
-	p.advance()
-	return nil
+	return typ
 }
 
-func indirect(typ Expr) Expr {
-	return &Operation{Op: Mul, X: typ}
+func newIndirect(pos src.Pos, typ Expr) Expr {
+	o := new(Operation)
+	o.pos = pos
+	o.Op = Mul
+	o.X = typ
+	return o
 }
 
-// tryType is like type_ but it returns nil if there was no type
+// typeOrNil is like type_ but it returns nil if there was no type
 // instead of reporting an error.
 //
 // Type     = TypeName | TypeLit | "(" Type ")" .
 // TypeName = identifier | QualifiedIdent .
 // TypeLit  = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
 // 	      SliceType | MapType | Channel_Type .
-func (p *parser) tryType() Expr {
+func (p *parser) typeOrNil() Expr {
 	if trace {
-		defer p.trace("tryType")()
+		defer p.trace("typeOrNil")()
 	}
 
+	pos := p.pos()
 	switch p.tok {
 	case _Star:
 		// ptrtype
 		p.next()
-		return indirect(p.type_())
+		return newIndirect(pos, p.type_())
 
 	case _Arrow:
 		// recvchantype
 		p.next()
 		p.want(_Chan)
 		t := new(ChanType)
-		t.init(p)
+		t.pos = pos
 		t.Dir = RecvOnly
 		t.Elem = p.chanElem()
 		return t
@@ -942,14 +1017,14 @@ func (p *parser) tryType() Expr {
 			// []T
 			p.xnest--
 			t := new(SliceType)
-			t.init(p)
+			t.pos = pos
 			t.Elem = p.type_()
 			return t
 		}
 
 		// [n]T
 		t := new(ArrayType)
-		t.init(p)
+		t.pos = pos
 		if !p.got(_DotDotDot) {
 			t.Len = p.expr()
 		}
@@ -963,7 +1038,7 @@ func (p *parser) tryType() Expr {
 		// _Chan _Comm ntype
 		p.next()
 		t := new(ChanType)
-		t.init(p)
+		t.pos = pos
 		if p.got(_Arrow) {
 			t.Dir = SendOnly
 		}
@@ -975,7 +1050,7 @@ func (p *parser) tryType() Expr {
 		p.next()
 		p.want(_Lbrack)
 		t := new(MapType)
-		t.init(p)
+		t.pos = pos
 		t.Key = p.type_()
 		p.want(_Rbrack)
 		t.Value = p.type_()
@@ -1006,12 +1081,10 @@ func (p *parser) funcType() *FuncType {
 	}
 
 	typ := new(FuncType)
-	typ.init(p)
+	typ.pos = p.pos()
 	typ.ParamList = p.paramList()
 	typ.ResultList = p.funcResult()
-	if gcCompat {
-		typ.init(p)
-	}
+
 	return typ
 }
 
@@ -1020,13 +1093,14 @@ func (p *parser) chanElem() Expr {
 		defer p.trace("chanElem")()
 	}
 
-	if typ := p.tryType(); typ != nil {
-		return typ
+	typ := p.typeOrNil()
+	if typ == nil {
+		typ = p.bad()
+		p.syntax_error("missing channel element type")
+		// assume element type is simply absent - don't advance
 	}
 
-	p.syntax_error("missing channel element type")
-	// assume element type is simply absent - don't advance
-	return nil
+	return typ
 }
 
 func (p *parser) dotname(name *Name) Expr {
@@ -1034,9 +1108,10 @@ func (p *parser) dotname(name *Name) Expr {
 		defer p.trace("dotname")()
 	}
 
-	if p.got(_Dot) {
+	if p.tok == _Dot {
 		s := new(SelectorExpr)
-		s.init(p)
+		s.pos = p.pos()
+		p.next()
 		s.X = name
 		s.Sel = p.name()
 		return s
@@ -1051,7 +1126,7 @@ func (p *parser) structType() *StructType {
 	}
 
 	typ := new(StructType)
-	typ.init(p)
+	typ.pos = p.pos()
 
 	p.want(_Struct)
 	p.want(_Lbrace)
@@ -1061,9 +1136,6 @@ func (p *parser) structType() *StructType {
 			break
 		}
 	}
-	if gcCompat {
-		typ.init(p)
-	}
 	p.want(_Rbrace)
 
 	return typ
@@ -1076,7 +1148,7 @@ func (p *parser) interfaceType() *InterfaceType {
 	}
 
 	typ := new(InterfaceType)
-	typ.init(p)
+	typ.pos = p.pos()
 
 	p.want(_Interface)
 	p.want(_Lbrace)
@@ -1088,9 +1160,6 @@ func (p *parser) interfaceType() *InterfaceType {
 			break
 		}
 	}
-	if gcCompat {
-		typ.init(p)
-	}
 	p.want(_Rbrace)
 
 	return typ
@@ -1102,18 +1171,14 @@ func (p *parser) funcBody() []Stmt {
 		defer p.trace("funcBody")()
 	}
 
-	if p.got(_Lbrace) {
-		p.fnest++
-		body := p.stmtList()
-		p.fnest--
-		p.want(_Rbrace)
-		if body == nil {
-			body = []Stmt{new(EmptyStmt)}
-		}
-		return body
-	}
+	p.fnest++
+	body := p.stmtList()
+	p.fnest--
 
-	return nil
+	if body == nil {
+		body = []Stmt{new(EmptyStmt)}
+	}
+	return body
 }
 
 // Result = Parameters | Type .
@@ -1126,17 +1191,18 @@ func (p *parser) funcResult() []*Field {
 		return p.paramList()
 	}
 
-	if result := p.tryType(); result != nil {
+	pos := p.pos()
+	if typ := p.typeOrNil(); typ != nil {
 		f := new(Field)
-		f.init(p)
-		f.Type = result
+		f.pos = pos
+		f.Type = typ
 		return []*Field{f}
 	}
 
 	return nil
 }
 
-func (p *parser) addField(styp *StructType, name *Name, typ Expr, tag *BasicLit) {
+func (p *parser) addField(styp *StructType, pos src.Pos, name *Name, typ Expr, tag *BasicLit) {
 	if tag != nil {
 		for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- {
 			styp.TagList = append(styp.TagList, nil)
@@ -1145,15 +1211,11 @@ func (p *parser) addField(styp *StructType, name *Name, typ Expr, tag *BasicLit)
 	}
 
 	f := new(Field)
-	f.init(p)
+	f.pos = pos
 	f.Name = name
 	f.Type = typ
 	styp.FieldList = append(styp.FieldList, f)
 
-	if gcCompat && name != nil {
-		f.node = name.node
-	}
-
 	if debug && tag != nil && len(styp.FieldList) != len(styp.TagList) {
 		panic("inconsistent struct field list")
 	}
@@ -1167,15 +1229,15 @@ func (p *parser) fieldDecl(styp *StructType) {
 		defer p.trace("fieldDecl")()
 	}
 
-	var name *Name
+	pos := p.pos()
 	switch p.tok {
 	case _Name:
-		name = p.name()
+		name := p.name()
 		if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
 			// embed oliteral
 			typ := p.qualifiedName(name)
 			tag := p.oliteral()
-			p.addField(styp, nil, typ, tag)
+			p.addField(styp, pos, nil, typ, tag)
 			return
 		}
 
@@ -1185,44 +1247,45 @@ func (p *parser) fieldDecl(styp *StructType) {
 		tag := p.oliteral()
 
 		for _, name := range names {
-			p.addField(styp, name, typ, tag)
+			p.addField(styp, name.Pos(), name, typ, tag)
 		}
 
 	case _Lparen:
 		p.next()
 		if p.tok == _Star {
 			// '(' '*' embed ')' oliteral
+			pos := p.pos()
 			p.next()
-			typ := indirect(p.qualifiedName(nil))
+			typ := newIndirect(pos, p.qualifiedName(nil))
 			p.want(_Rparen)
 			tag := p.oliteral()
-			p.addField(styp, nil, typ, tag)
-			p.error("cannot parenthesize embedded type")
+			p.addField(styp, pos, nil, typ, tag)
+			p.syntax_error("cannot parenthesize embedded type")
 
 		} else {
 			// '(' embed ')' oliteral
 			typ := p.qualifiedName(nil)
 			p.want(_Rparen)
 			tag := p.oliteral()
-			p.addField(styp, nil, typ, tag)
-			p.error("cannot parenthesize embedded type")
+			p.addField(styp, pos, nil, typ, tag)
+			p.syntax_error("cannot parenthesize embedded type")
 		}
 
 	case _Star:
 		p.next()
 		if p.got(_Lparen) {
 			// '*' '(' embed ')' oliteral
-			typ := indirect(p.qualifiedName(nil))
+			typ := newIndirect(pos, p.qualifiedName(nil))
 			p.want(_Rparen)
 			tag := p.oliteral()
-			p.addField(styp, nil, typ, tag)
-			p.error("cannot parenthesize embedded type")
+			p.addField(styp, pos, nil, typ, tag)
+			p.syntax_error("cannot parenthesize embedded type")
 
 		} else {
 			// '*' embed oliteral
-			typ := indirect(p.qualifiedName(nil))
+			typ := newIndirect(pos, p.qualifiedName(nil))
 			tag := p.oliteral()
-			p.addField(styp, nil, typ, tag)
+			p.addField(styp, pos, nil, typ, tag)
 		}
 
 	default:
@@ -1234,7 +1297,7 @@ func (p *parser) fieldDecl(styp *StructType) {
 func (p *parser) oliteral() *BasicLit {
 	if p.tok == _Literal {
 		b := new(BasicLit)
-		b.init(p)
+		b.pos = p.pos()
 		b.Value = p.lit
 		b.Kind = p.kind
 		p.next()
@@ -1267,7 +1330,7 @@ func (p *parser) methodDecl() *Field {
 		}
 
 		f := new(Field)
-		f.init(p)
+		f.pos = name.Pos()
 		if p.tok != _Lparen {
 			// packname
 			f.Type = p.qualifiedName(name)
@@ -1279,29 +1342,29 @@ func (p *parser) methodDecl() *Field {
 		return f
 
 	case _Lparen:
-		p.next()
+		p.syntax_error("cannot parenthesize embedded type")
 		f := new(Field)
-		f.init(p)
+		f.pos = p.pos()
+		p.next()
 		f.Type = p.qualifiedName(nil)
 		p.want(_Rparen)
-		p.error("cannot parenthesize embedded type")
 		return f
 
 	default:
-		p.syntax_error("")
+		p.syntax_error("expecting method or interface name")
 		p.advance(_Semi, _Rbrace)
 		return nil
 	}
 }
 
 // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) paramDecl() *Field {
+func (p *parser) paramDeclOrNil() *Field {
 	if trace {
 		defer p.trace("paramDecl")()
 	}
 
 	f := new(Field)
-	f.init(p)
+	f.pos = p.pos()
 
 	switch p.tok {
 	case _Name:
@@ -1346,12 +1409,13 @@ func (p *parser) dotsType() *DotsType {
 	}
 
 	t := new(DotsType)
-	t.init(p)
+	t.pos = p.pos()
 
 	p.want(_DotDotDot)
-	t.Elem = p.tryType()
+	t.Elem = p.typeOrNil()
 	if t.Elem == nil {
-		p.error("final argument in variadic function missing type")
+		t.Elem = p.bad()
+		p.syntax_error("final argument in variadic function missing type")
 	}
 
 	return t
@@ -1364,11 +1428,12 @@ func (p *parser) paramList() (list []*Field) {
 		defer p.trace("paramList")()
 	}
 
+	pos := p.pos()
 	p.want(_Lparen)
 
 	var named int // number of parameters that have an explicit name and type
 	for p.tok != _EOF && p.tok != _Rparen {
-		if par := p.paramDecl(); par != nil {
+		if par := p.paramDeclOrNil(); par != nil {
 			if debug && par.Name == nil && par.Type == nil {
 				panic("parameter without name or type")
 			}
@@ -1393,20 +1458,29 @@ func (p *parser) paramList() (list []*Field) {
 		}
 	} else if named != len(list) {
 		// some named => all must be named
+		ok := true
 		var typ Expr
 		for i := len(list) - 1; i >= 0; i-- {
 			if par := list[i]; par.Type != nil {
 				typ = par.Type
 				if par.Name == nil {
-					typ = nil // error
+					ok = false
+					n := p.newName("_")
+					n.pos = typ.Pos() // correct position
+					par.Name = n
 				}
-			} else {
+			} else if typ != nil {
 				par.Type = typ
+			} else {
+				// par.Type == nil && typ == nil => we only have a par.Name
+				ok = false
+				t := p.bad()
+				t.pos = par.Name.Pos() // correct position
+				par.Type = t
 			}
-			if typ == nil {
-				p.syntax_error("mixed named and unnamed function parameters")
-				break
-			}
+		}
+		if !ok {
+			p.syntax_error_at(pos, "mixed named and unnamed function parameters")
 		}
 	}
 
@@ -1414,6 +1488,12 @@ func (p *parser) paramList() (list []*Field) {
 	return
 }
 
+func (p *parser) bad() *BadExpr {
+	b := new(BadExpr)
+	b.pos = p.pos()
+	return b
+}
+
 // ----------------------------------------------------------------------------
 // Statements
 
@@ -1422,19 +1502,17 @@ func (p *parser) paramList() (list []*Field) {
 var ImplicitOne = &BasicLit{Value: "1"}
 
 // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
-//
-// simpleStmt may return missing_stmt if labelOk is set.
 func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
 	if trace {
 		defer p.trace("simpleStmt")()
 	}
 
-	if rangeOk && p.got(_Range) {
+	if rangeOk && p.tok == _Range {
 		// _Range expr
 		if debug && lhs != nil {
 			panic("invalid call of simpleStmt")
 		}
-		return p.rangeClause(nil, false)
+		return p.newRangeClause(nil, false)
 	}
 
 	if lhs == nil {
@@ -1443,58 +1521,58 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
 
 	if _, ok := lhs.(*ListExpr); !ok && p.tok != _Assign && p.tok != _Define {
 		// expr
+		pos := p.pos()
 		switch p.tok {
 		case _AssignOp:
 			// lhs op= rhs
 			op := p.op
 			p.next()
-			return p.newAssignStmt(op, lhs, p.expr())
+			return p.newAssignStmt(pos, op, lhs, p.expr())
 
 		case _IncOp:
 			// lhs++ or lhs--
 			op := p.op
 			p.next()
-			return p.newAssignStmt(op, lhs, ImplicitOne)
+			return p.newAssignStmt(pos, op, lhs, ImplicitOne)
 
 		case _Arrow:
 			// lhs <- rhs
-			p.next()
 			s := new(SendStmt)
-			s.init(p)
+			s.pos = pos
+			p.next()
 			s.Chan = lhs
 			s.Value = p.expr()
-			if gcCompat {
-				s.init(p)
-			}
 			return s
 
 		default:
 			// expr
-			return &ExprStmt{X: lhs}
+			s := new(ExprStmt)
+			s.pos = lhs.Pos()
+			s.X = lhs
+			return s
 		}
 	}
 
 	// expr_list
+	pos := p.pos()
 	switch p.tok {
 	case _Assign:
 		p.next()
 
-		if rangeOk && p.got(_Range) {
+		if rangeOk && p.tok == _Range {
 			// expr_list '=' _Range expr
-			return p.rangeClause(lhs, false)
+			return p.newRangeClause(lhs, false)
 		}
 
 		// expr_list '=' expr_list
-		return p.newAssignStmt(0, lhs, p.exprList())
+		return p.newAssignStmt(pos, 0, lhs, p.exprList())
 
 	case _Define:
-		var n node
-		n.init(p)
 		p.next()
 
-		if rangeOk && p.got(_Range) {
+		if rangeOk && p.tok == _Range {
 			// expr_list ':=' range expr
-			return p.rangeClause(lhs, true)
+			return p.newRangeClause(lhs, true)
 		}
 
 		// expr_list ':=' expr_list
@@ -1505,81 +1583,104 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt {
 			case *Name:
 				x.Lhs = lhs
 			case *ListExpr:
-				p.error(fmt.Sprintf("argument count mismatch: %d = %d", len(lhs.ElemList), 1))
+				p.error_at(lhs.Pos(), fmt.Sprintf("cannot assign 1 value to %d variables", len(lhs.ElemList)))
+				// make the best of what we have
+				if lhs, ok := lhs.ElemList[0].(*Name); ok {
+					x.Lhs = lhs
+				}
 			default:
-				// TODO(mdempsky): Have Expr types implement Stringer?
-				p.error(fmt.Sprintf("invalid variable name %s in type switch", lhs))
+				p.error_at(lhs.Pos(), fmt.Sprintf("invalid variable name %s in type switch", String(lhs)))
 			}
-			return &ExprStmt{X: x}
+			s := new(ExprStmt)
+			s.pos = x.Pos()
+			s.X = x
+			return s
 		}
 
-		as := p.newAssignStmt(Def, lhs, rhs)
-		if gcCompat {
-			as.node = n
-		}
+		as := p.newAssignStmt(pos, Def, lhs, rhs)
 		return as
 
 	default:
 		p.syntax_error("expecting := or = or comma")
 		p.advance(_Semi, _Rbrace)
-		return nil
+		// make the best of what we have
+		if x, ok := lhs.(*ListExpr); ok {
+			lhs = x.ElemList[0]
+		}
+		s := new(ExprStmt)
+		s.pos = lhs.Pos()
+		s.X = lhs
+		return s
 	}
 }
 
-func (p *parser) rangeClause(lhs Expr, def bool) *RangeClause {
+func (p *parser) newRangeClause(lhs Expr, def bool) *RangeClause {
 	r := new(RangeClause)
-	r.init(p)
+	r.pos = p.pos()
+	p.next() // consume _Range
 	r.Lhs = lhs
 	r.Def = def
 	r.X = p.expr()
-	if gcCompat {
-		r.init(p)
-	}
 	return r
 }
 
-func (p *parser) newAssignStmt(op Operator, lhs, rhs Expr) *AssignStmt {
+func (p *parser) newAssignStmt(pos src.Pos, op Operator, lhs, rhs Expr) *AssignStmt {
 	a := new(AssignStmt)
-	a.init(p)
+	a.pos = pos
 	a.Op = op
 	a.Lhs = lhs
 	a.Rhs = rhs
 	return a
 }
 
-func (p *parser) labeledStmt(label *Name) Stmt {
+func (p *parser) labeledStmtOrNil(label *Name) Stmt {
 	if trace {
 		defer p.trace("labeledStmt")()
 	}
 
 	s := new(LabeledStmt)
-	s.init(p)
+	s.pos = p.pos()
 	s.Label = label
 
 	p.want(_Colon)
 
-	if p.tok != _Rbrace && p.tok != _EOF {
-		s.Stmt = p.stmt()
-		if s.Stmt == missing_stmt {
-			// report error at line of ':' token
-			p.syntax_error_at(int(label.pos), int(label.line), "missing statement after label")
-			// we are already at the end of the labeled statement - no need to advance
-			return missing_stmt
-		}
+	if p.tok == _Rbrace {
+		// We expect a statement (incl. an empty statement), which must be
+		// terminated by a semicolon. Because semicolons may be omitted before
+		// an _Rbrace, seeing an _Rbrace implies an empty statement.
+		e := new(EmptyStmt)
+		e.pos = p.pos()
+		s.Stmt = e
+		return s
 	}
 
-	return s
+	s.Stmt = p.stmtOrNil()
+	if s.Stmt != nil {
+		return s
+	}
+
+	// report error at line of ':' token
+	p.syntax_error_at(s.pos, "missing statement after label")
+	// we are already at the end of the labeled statement - no need to advance
+	return nil // avoids follow-on errors (see e.g., fixedbugs/bug274.go)
 }
 
-func (p *parser) blockStmt() *BlockStmt {
+func (p *parser) blockStmt(context string) *BlockStmt {
 	if trace {
 		defer p.trace("blockStmt")()
 	}
 
 	s := new(BlockStmt)
-	s.init(p)
-	p.want(_Lbrace)
-	s.Body = p.stmtList()
+	s.pos = p.pos()
+
+	if !p.got(_Lbrace) {
+		p.syntax_error("expecting { after " + context)
+		p.advance(_Name, _Rbrace)
+		// TODO(gri) may be better to return here than to continue (#19663)
+	}
+
+	s.List = p.stmtList()
+	s.Rbrace = p.pos()
 	p.want(_Rbrace)
 
 	return s
@@ -1591,7 +1692,7 @@ func (p *parser) declStmt(f func(*Group) Decl) *DeclStmt {
 	}
 
 	s := new(DeclStmt)
-	s.init(p)
+	s.pos = p.pos()
 
 	p.next() // _Const, _Type, or _Var
 	s.DeclList = p.appendGroup(nil, f)
@@ -1605,52 +1706,38 @@ func (p *parser) forStmt() Stmt {
 	}
 
 	s := new(ForStmt)
-	s.init(p)
+	s.pos = p.pos()
 
-	p.want(_For)
-	s.Init, s.Cond, s.Post = p.header(true)
-	if gcCompat {
-		s.init(p)
-	}
-	s.Body = p.stmtBody("for clause")
+	s.Init, s.Cond, s.Post = p.header(_For)
+	s.Body = p.blockStmt("for clause")
 
 	return s
 }
 
-// stmtBody parses if and for statement bodies.
-func (p *parser) stmtBody(context string) []Stmt {
-	if trace {
-		defer p.trace("stmtBody")()
-	}
+// TODO(gri) This function is now so heavily influenced by the keyword that
+//           it may not make sense anymore to combine all three cases. It
+//           may be simpler to just split it up for each statement kind.
+func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
+	p.want(keyword)
 
-	if !p.got(_Lbrace) {
-		p.syntax_error("missing { after " + context)
-		p.advance(_Name, _Rbrace)
-	}
-
-	body := p.stmtList()
-	p.want(_Rbrace)
-
-	return body
-}
-
-var dummyCond = &Name{Value: "false"}
-
-func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
 	if p.tok == _Lbrace {
+		if keyword == _If {
+			p.syntax_error("missing condition in if statement")
+		}
 		return
 	}
+	// p.tok != _Lbrace
 
 	outer := p.xnest
 	p.xnest = -1
 
 	if p.tok != _Semi {
 		// accept potential varDecl but complain
-		if forStmt && p.got(_Var) {
-			p.error("var declaration not allowed in for initializer")
+		if p.got(_Var) {
+			p.syntax_error(fmt.Sprintf("var declaration not allowed in %s initializer", keyword.String()))
 		}
-		init = p.simpleStmt(nil, forStmt)
-		// If we have a range clause, we are done.
+		init = p.simpleStmt(nil, keyword == _For)
+		// If we have a range clause, we are done (can only happen for keyword == _For).
 		if _, ok := init.(*RangeClause); ok {
 			p.xnest = outer
 			return
@@ -1658,14 +1745,28 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
 	}
 
 	var condStmt SimpleStmt
-	if p.got(_Semi) {
-		if forStmt {
+	var semi struct {
+		pos src.Pos
+		lit string // valid if pos.IsKnown()
+	}
+	if p.tok == _Semi {
+		semi.pos = p.pos()
+		semi.lit = p.lit
+		p.next()
+		if keyword == _For {
 			if p.tok != _Semi {
+				if p.tok == _Lbrace {
+					p.syntax_error("expecting for loop condition")
+					goto done
+				}
 				condStmt = p.simpleStmt(nil, false)
 			}
 			p.want(_Semi)
 			if p.tok != _Lbrace {
 				post = p.simpleStmt(nil, false)
+				if a, _ := post.(*AssignStmt); a != nil && a.Op == Def {
+					p.syntax_error_at(a.Pos(), "cannot declare in post statement of for loop")
+				}
 			}
 		} else if p.tok != _Lbrace {
 			condStmt = p.simpleStmt(nil, false)
@@ -1675,15 +1776,21 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
 		init = nil
 	}
 
+done:
 	// unpack condStmt
 	switch s := condStmt.(type) {
 	case nil:
-		// nothing to do
+		if keyword == _If && semi.pos.IsKnown() {
+			if semi.lit != "semicolon" {
+				p.syntax_error_at(semi.pos, fmt.Sprintf("unexpected %s, expecting { after if clause", semi.lit))
+			} else {
+				p.syntax_error_at(semi.pos, "missing condition in if statement")
+			}
+		}
 	case *ExprStmt:
 		cond = s.X
 	default:
 		p.syntax_error(fmt.Sprintf("%s used as value", String(s)))
-		cond = dummyCond // avoid follow-up error for if statements
 	}
 
 	p.xnest = outer
@@ -1696,28 +1803,19 @@ func (p *parser) ifStmt() *IfStmt {
 	}
 
 	s := new(IfStmt)
-	s.init(p)
+	s.pos = p.pos()
 
-	p.want(_If)
-	s.Init, s.Cond, _ = p.header(false)
-	if s.Cond == nil {
-		p.error("missing condition in if statement")
-	}
-
-	if gcCompat {
-		s.init(p)
-	}
-
-	s.Then = p.stmtBody("if clause")
+	s.Init, s.Cond, _ = p.header(_If)
+	s.Then = p.blockStmt("if clause")
 
 	if p.got(_Else) {
 		switch p.tok {
 		case _If:
 			s.Else = p.ifStmt()
 		case _Lbrace:
-			s.Else = p.blockStmt()
+			s.Else = p.blockStmt("")
 		default:
-			p.error("else must be followed by if or statement block")
+			p.syntax_error("else must be followed by if or statement block")
 			p.advance(_Name, _Rbrace)
 		}
 	}
@@ -1730,11 +1828,10 @@ func (p *parser) switchStmt() *SwitchStmt {
 		defer p.trace("switchStmt")()
 	}
 
-	p.want(_Switch)
 	s := new(SwitchStmt)
-	s.init(p)
+	s.pos = p.pos()
 
-	s.Init, s.Tag, _ = p.header(false)
+	s.Init, s.Tag, _ = p.header(_Switch)
 
 	if !p.got(_Lbrace) {
 		p.syntax_error("missing { after switch clause")
@@ -1743,6 +1840,7 @@ func (p *parser) switchStmt() *SwitchStmt {
 	for p.tok != _EOF && p.tok != _Rbrace {
 		s.Body = append(s.Body, p.caseClause())
 	}
+	s.Rbrace = p.pos()
 	p.want(_Rbrace)
 
 	return s
@@ -1753,10 +1851,10 @@ func (p *parser) selectStmt() *SelectStmt {
 		defer p.trace("selectStmt")()
 	}
 
-	p.want(_Select)
 	s := new(SelectStmt)
-	s.init(p)
+	s.pos = p.pos()
 
+	p.want(_Select)
 	if !p.got(_Lbrace) {
 		p.syntax_error("missing { after select clause")
 		p.advance(_Case, _Default, _Rbrace)
@@ -1764,6 +1862,7 @@ func (p *parser) selectStmt() *SelectStmt {
 	for p.tok != _EOF && p.tok != _Rbrace {
 		s.Body = append(s.Body, p.commClause())
 	}
+	s.Rbrace = p.pos()
 	p.want(_Rbrace)
 
 	return s
@@ -1775,7 +1874,7 @@ func (p *parser) caseClause() *CaseClause {
 	}
 
 	c := new(CaseClause)
-	c.init(p)
+	c.pos = p.pos()
 
 	switch p.tok {
 	case _Case:
@@ -1787,12 +1886,10 @@ func (p *parser) caseClause() *CaseClause {
 
 	default:
 		p.syntax_error("expecting case or default or }")
-		p.advance(_Case, _Default, _Rbrace)
+		p.advance(_Colon, _Case, _Default, _Rbrace)
 	}
 
-	if gcCompat {
-		c.init(p)
-	}
+	c.Colon = p.pos()
 	p.want(_Colon)
 	c.Body = p.stmtList()
 
@@ -1805,7 +1902,7 @@ func (p *parser) commClause() *CommClause {
 	}
 
 	c := new(CommClause)
-	c.init(p)
+	c.pos = p.pos()
 
 	switch p.tok {
 	case _Case:
@@ -1829,29 +1926,22 @@ func (p *parser) commClause() *CommClause {
 
 	default:
 		p.syntax_error("expecting case or default or }")
-		p.advance(_Case, _Default, _Rbrace)
+		p.advance(_Colon, _Case, _Default, _Rbrace)
 	}
 
-	if gcCompat {
-		c.init(p)
-	}
+	c.Colon = p.pos()
 	p.want(_Colon)
 	c.Body = p.stmtList()
 
 	return c
 }
 
-// TODO(gri) find a better solution
-var missing_stmt Stmt = new(EmptyStmt) // = nod(OXXX, nil, nil)
-
 // Statement =
 // 	Declaration | LabeledStmt | SimpleStmt |
 // 	GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
 // 	FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
 // 	DeferStmt .
-//
-// stmt may return missing_stmt.
-func (p *parser) stmt() Stmt {
+func (p *parser) stmtOrNil() Stmt {
 	if trace {
 		defer p.trace("stmt " + p.tok.String())()
 	}
@@ -1861,14 +1951,14 @@ func (p *parser) stmt() Stmt {
 	if p.tok == _Name {
 		lhs := p.exprList()
 		if label, ok := lhs.(*Name); ok && p.tok == _Colon {
-			return p.labeledStmt(label)
+			return p.labeledStmtOrNil(label)
 		}
 		return p.simpleStmt(lhs, false)
 	}
 
 	switch p.tok {
 	case _Lbrace:
-		return p.blockStmt()
+		return p.blockStmt("")
 
 	case _Var:
 		return p.declStmt(p.varDecl)
@@ -1903,22 +1993,17 @@ func (p *parser) stmt() Stmt {
 		return p.ifStmt()
 
 	case _Fallthrough:
-		p.next()
 		s := new(BranchStmt)
-		s.init(p)
+		s.pos = p.pos()
+		p.next()
 		s.Tok = _Fallthrough
 		return s
-		// // will be converted to OFALL
-		// stmt := nod(OXFALL, nil, nil)
-		// stmt.Xoffset = int64(block)
-		// return stmt
 
 	case _Break, _Continue:
-		tok := p.tok
-		p.next()
 		s := new(BranchStmt)
-		s.init(p)
-		s.Tok = tok
+		s.pos = p.pos()
+		s.Tok = p.tok
+		p.next()
 		if p.tok == _Name {
 			s.Label = p.name()
 		}
@@ -1928,35 +2013,29 @@ func (p *parser) stmt() Stmt {
 		return p.callStmt()
 
 	case _Goto:
-		p.next()
 		s := new(BranchStmt)
-		s.init(p)
+		s.pos = p.pos()
 		s.Tok = _Goto
+		p.next()
 		s.Label = p.name()
 		return s
-		// stmt := nod(OGOTO, p.new_name(p.name()), nil)
-		// stmt.Sym = dclstack // context, for goto restrictions
-		// return stmt
 
 	case _Return:
-		p.next()
 		s := new(ReturnStmt)
-		s.init(p)
+		s.pos = p.pos()
+		p.next()
 		if p.tok != _Semi && p.tok != _Rbrace {
 			s.Results = p.exprList()
 		}
-		if gcCompat {
-			s.init(p)
-		}
 		return s
 
 	case _Semi:
 		s := new(EmptyStmt)
-		s.init(p)
+		s.pos = p.pos()
 		return s
 	}
 
-	return missing_stmt
+	return nil
 }
 
 // StatementList = { Statement ";" } .
@@ -1966,8 +2045,8 @@ func (p *parser) stmtList() (l []Stmt) {
 	}
 
 	for p.tok != _EOF && p.tok != _Rbrace && p.tok != _Case && p.tok != _Default {
-		s := p.stmt()
-		if s == missing_stmt {
+		s := p.stmtOrNil()
+		if s == nil {
 			break
 		}
 		l = append(l, s)
@@ -1993,14 +2072,14 @@ func (p *parser) call(fun Expr) *CallExpr {
 	// call or conversion
 	// convtype '(' expr ocomma ')'
 	c := new(CallExpr)
-	c.init(p)
+	c.pos = p.pos()
 	c.Fun = fun
 
 	p.want(_Lparen)
 	p.xnest++
 
 	for p.tok != _EOF && p.tok != _Rparen {
-		c.ArgList = append(c.ArgList, p.expr()) // expr_or_type
+		c.ArgList = append(c.ArgList, p.expr())
 		c.HasDots = p.got(_DotDotDot)
 		if !p.ocomma(_Rparen) || c.HasDots {
 			break
@@ -2008,9 +2087,6 @@ func (p *parser) call(fun Expr) *CallExpr {
 	}
 
 	p.xnest--
-	if gcCompat {
-		c.init(p)
-	}
 	p.want(_Rparen)
 
 	return c
@@ -2019,21 +2095,25 @@ func (p *parser) call(fun Expr) *CallExpr {
 // ----------------------------------------------------------------------------
 // Common productions
 
+func (p *parser) newName(value string) *Name {
+	n := new(Name)
+	n.pos = p.pos()
+	n.Value = value
+	return n
+}
+
 func (p *parser) name() *Name {
 	// no tracing to avoid overly verbose output
 
-	n := new(Name)
-	n.init(p)
-
 	if p.tok == _Name {
-		n.Value = p.lit
+		n := p.newName(p.lit)
 		p.next()
-	} else {
-		n.Value = "_"
-		p.syntax_error("expecting name")
-		p.advance()
+		return n
 	}
 
+	n := p.newName("_")
+	p.syntax_error("expecting name")
+	p.advance()
 	return n
 }
 
@@ -2068,8 +2148,7 @@ func (p *parser) qualifiedName(name *Name) Expr {
 	case p.tok == _Name:
 		name = p.name()
 	default:
-		name = new(Name)
-		name.init(p)
+		name = p.newName("_")
 		p.syntax_error("expecting name")
 		p.advance(_Dot, _Semi, _Rbrace)
 	}
@@ -2090,7 +2169,7 @@ func (p *parser) exprList() Expr {
 			list = append(list, p.expr())
 		}
 		t := new(ListExpr)
-		t.init(p) // TODO(gri) what is the correct thing here?
+		t.pos = x.Pos()
 		t.ElemList = list
 		x = t
 	}
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
index c4b43bf..4c317da 100644
--- a/src/cmd/compile/internal/syntax/parser_test.go
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -6,6 +6,7 @@ package syntax
 
 import (
 	"bytes"
+	"cmd/internal/src"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -18,14 +19,11 @@ import (
 )
 
 var fast = flag.Bool("fast", false, "parse package files in parallel")
-var src = flag.String("src", "parser.go", "source file to parse")
+var src_ = flag.String("src", "parser.go", "source file to parse")
 var verify = flag.Bool("verify", false, "verify idempotent printing")
 
 func TestParse(t *testing.T) {
-	_, err := ParseFile(*src, nil, nil, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
+	ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
 }
 
 func TestStdLib(t *testing.T) {
@@ -39,7 +37,7 @@ func TestStdLib(t *testing.T) {
 
 	type parseResult struct {
 		filename string
-		lines    int
+		lines    uint
 	}
 
 	results := make(chan parseResult)
@@ -65,7 +63,7 @@ func TestStdLib(t *testing.T) {
 		}
 	}()
 
-	var count, lines int
+	var count, lines uint
 	for res := range results {
 		count++
 		lines += res.lines
@@ -133,7 +131,7 @@ func verifyPrint(filename string, ast1 *File) {
 		panic(err)
 	}
 
-	ast2, err := ParseBytes(buf1.Bytes(), nil, nil, 0)
+	ast2, err := ParseBytes(src.NewFileBase(filename, filename), buf1.Bytes(), nil, nil, 0)
 	if err != nil {
 		panic(err)
 	}
@@ -157,7 +155,7 @@ func verifyPrint(filename string, ast1 *File) {
 }
 
 func TestIssue17697(t *testing.T) {
-	_, err := ParseBytes(nil, nil, nil, 0) // return with parser error, don't panic
+	_, err := ParseBytes(nil, nil, nil, nil, 0) // return with parser error, don't panic
 	if err == nil {
 		t.Errorf("no error reported")
 	}
@@ -182,3 +180,47 @@ func TestParseFile(t *testing.T) {
 		t.Errorf("got %v; want first error %v", err, first)
 	}
 }
+
+func TestLineDirectives(t *testing.T) {
+	for _, test := range []struct {
+		src, msg  string
+		filename  string
+		line, col uint // 0-based
+	}{
+		// test validity of //line directive
+		{`//line :`, "invalid line number: ", "", 0, 8},
+		{`//line :x`, "invalid line number: x", "", 0, 8},
+		{`//line foo :`, "invalid line number: ", "", 0, 12},
+		{`//line foo:123abc`, "invalid line number: 123abc", "", 0, 11},
+		{`/**///line foo:x`, "syntax error: package statement must be first", "", 0, 16}, //line directive not at start of line - ignored
+		{`//line foo:0`, "invalid line number: 0", "", 0, 11},
+		{fmt.Sprintf(`//line foo:%d`, lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 0, 11},
+
+		// test effect of //line directive on (relative) position information
+		{"//line foo:123\n   foo", "syntax error: package statement must be first", "foo", 123 - linebase, 3},
+		{"//line foo:123\n//line bar:345\nfoo", "syntax error: package statement must be first", "bar", 345 - linebase, 0},
+	} {
+		_, err := ParseBytes(nil, []byte(test.src), nil, nil, 0)
+		if err == nil {
+			t.Errorf("%s: no error reported", test.src)
+			continue
+		}
+		perr, ok := err.(Error)
+		if !ok {
+			t.Errorf("%s: got %v; want parser error", test.src, err)
+			continue
+		}
+		if msg := perr.Msg; msg != test.msg {
+			t.Errorf("%s: got msg = %q; want %q", test.src, msg, test.msg)
+		}
+		if filename := perr.Pos.RelFilename(); filename != test.filename {
+			t.Errorf("%s: got filename = %q; want %q", test.src, filename, test.filename)
+		}
+		if line := perr.Pos.RelLine(); line != test.line+linebase {
+			t.Errorf("%s: got line = %d; want %d", test.src, line, test.line+linebase)
+		}
+		if col := perr.Pos.Col(); col != test.col+colbase {
+			t.Errorf("%s: got col = %d; want %d", test.src, col, test.col+colbase)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/syntax/printer.go b/src/cmd/compile/internal/syntax/printer.go
index 0cacf1e..f4c2b6d 100644
--- a/src/cmd/compile/internal/syntax/printer.go
+++ b/src/cmd/compile/internal/syntax/printer.go
@@ -341,7 +341,13 @@ func (p *printer) printNode(n Node) {
 
 func (p *printer) printRawNode(n Node) {
 	switch n := n.(type) {
+	case nil:
+		// we should not reach here but don't crash
+
 	// expressions and types
+	case *BadExpr:
+		p.print(_Name, "<bad expr>")
+
 	case *Name:
 		p.print(_Name, n.Value) // _Name requires actual value following immediately
 
@@ -349,8 +355,7 @@ func (p *printer) printRawNode(n Node) {
 		p.print(_Name, n.Value) // _Name requires actual value following immediately
 
 	case *FuncLit:
-		p.print(n.Type, blank)
-		p.printBody(n.Body)
+		p.print(n.Type, blank, n.Body)
 
 	case *CompositeLit:
 		if n.Type != nil {
@@ -524,15 +529,20 @@ func (p *printer) printRawNode(n Node) {
 		}
 
 	case *BlockStmt:
-		p.printBody(n.Body)
+		p.print(_Lbrace)
+		if len(n.List) > 0 {
+			p.print(newline, indent)
+			p.printStmtList(n.List, true)
+			p.print(outdent, newline)
+		}
+		p.print(_Rbrace)
 
 	case *IfStmt:
 		p.print(_If, blank)
 		if n.Init != nil {
 			p.print(n.Init, _Semi, blank)
 		}
-		p.print(n.Cond, blank)
-		p.printBody(n.Then)
+		p.print(n.Cond, blank, n.Then)
 		if n.Else != nil {
 			p.print(blank, _Else, blank, n.Else)
 		}
@@ -578,8 +588,7 @@ func (p *printer) printRawNode(n Node) {
 				p.print(n.Init)
 				// TODO(gri) clean this up
 				if _, ok := n.Init.(*RangeClause); ok {
-					p.print(blank)
-					p.printBody(n.Body)
+					p.print(blank, n.Body)
 					break
 				}
 			}
@@ -592,7 +601,7 @@ func (p *printer) printRawNode(n Node) {
 				p.print(n.Post, blank)
 			}
 		}
-		p.printBody(n.Body)
+		p.print(n.Body)
 
 	case *ImportDecl:
 		if n.Group == nil {
@@ -619,7 +628,11 @@ func (p *printer) printRawNode(n Node) {
 		if n.Group == nil {
 			p.print(_Type, blank)
 		}
-		p.print(n.Name, blank, n.Type)
+		p.print(n.Name, blank)
+		if n.Alias {
+			p.print(_Assign, blank)
+		}
+		p.print(n.Type)
 
 	case *VarDecl:
 		if n.Group == nil {
@@ -646,8 +659,7 @@ func (p *printer) printRawNode(n Node) {
 		p.print(n.Name)
 		p.printSignature(n.Type)
 		if n.Body != nil {
-			p.print(blank)
-			p.printBody(n.Body)
+			p.print(blank, n.Body)
 		}
 
 	case *printGroup:
@@ -878,16 +890,6 @@ func (p *printer) printStmtList(list []Stmt, braces bool) {
 	}
 }
 
-func (p *printer) printBody(list []Stmt) {
-	p.print(_Lbrace)
-	if len(list) > 0 {
-		p.print(newline, indent)
-		p.printStmtList(list, true)
-		p.print(outdent, newline)
-	}
-	p.print(_Rbrace)
-}
-
 func (p *printer) printSwitchBody(list []*CaseClause) {
 	p.print(_Lbrace)
 	if len(list) > 0 {
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
index 5c0fc77..14652f4 100644
--- a/src/cmd/compile/internal/syntax/printer_test.go
+++ b/src/cmd/compile/internal/syntax/printer_test.go
@@ -15,10 +15,27 @@ func TestPrint(t *testing.T) {
 		t.Skip("skipping test in short mode")
 	}
 
-	ast, err := ParseFile(*src, nil, nil, 0)
+	ast, err := ParseFile(*src_, nil, nil, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
 	Fprint(os.Stdout, ast, true)
 	fmt.Println()
 }
+
+func TestPrintString(t *testing.T) {
+	for _, want := range []string{
+		"package p",
+		"package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
+		// TODO(gri) expand
+	} {
+		ast, err := ParseBytes(nil, []byte(want), nil, nil, 0)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		if got := String(ast); got != want {
+			t.Errorf("%q: got %q", want, got)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go
index b84fcc5..05391e5 100644
--- a/src/cmd/compile/internal/syntax/scanner.go
+++ b/src/cmd/compile/internal/syntax/scanner.go
@@ -2,38 +2,56 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This file implements scanner, a lexical tokenizer for
+// Go source. After initialization, consecutive calls of
+// next advance the scanner one token at a time.
+//
+// This file, source.go, and tokens.go are self-contained
+// (go tool compile scanner.go source.go tokens.go compiles)
+// and thus could be made into its own package.
+
 package syntax
 
 import (
 	"fmt"
 	"io"
-	"strings"
 	"unicode"
 	"unicode/utf8"
 )
 
 type scanner struct {
 	source
+	pragh  func(line, col uint, msg string)
 	nlsemi bool // if set '\n' and EOF translate to ';'
-	pragma Pragma
 
 	// current token, valid after calling next()
-	pos, line int
+	line, col uint
 	tok       token
-	lit       string   // valid if tok is _Name or _Literal
+	lit       string   // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF")
 	kind      LitKind  // valid if tok is _Literal
 	op        Operator // valid if tok is _Operator, _AssignOp, or _IncOp
 	prec      int      // valid if tok is _Operator, _AssignOp, or _IncOp
-
-	pragh PragmaHandler
 }
 
-func (s *scanner) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
+func (s *scanner) init(src io.Reader, errh, pragh func(line, col uint, msg string)) {
 	s.source.init(src, errh)
-	s.nlsemi = false
 	s.pragh = pragh
+	s.nlsemi = false
 }
 
+// next advances the scanner by reading the next token.
+//
+// If a read, source encoding, or lexical error occurs, next
+// calls the error handler installed with init. The handler
+// must exist.
+//
+// If a //line or //go: directive is encountered at the start
+// of a line, next calls the directive handler pragh installed
+// with init, if not nil.
+//
+// The (line, col) position passed to the error and directive
+// handler is always at or after the current source reading
+// position.
 func (s *scanner) next() {
 	nlsemi := s.nlsemi
 	s.nlsemi = false
@@ -46,9 +64,9 @@ redo:
 	}
 
 	// token start
-	s.pos, s.line = s.source.pos0(), s.source.line0
+	s.line, s.col = s.source.line0, s.source.col0
 
-	if isLetter(c) || c >= utf8.RuneSelf && (unicode.IsLetter(c) || s.isCompatRune(c, true)) {
+	if isLetter(c) || c >= utf8.RuneSelf && s.isIdentRune(c, true) {
 		s.ident()
 		return
 	}
@@ -56,12 +74,14 @@ redo:
 	switch c {
 	case -1:
 		if nlsemi {
+			s.lit = "EOF"
 			s.tok = _Semi
 			break
 		}
 		s.tok = _EOF
 
 	case '\n':
+		s.lit = "newline"
 		s.tok = _Semi
 
 	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
@@ -89,6 +109,7 @@ redo:
 		s.tok = _Comma
 
 	case ';':
+		s.lit = "semicolon"
 		s.tok = _Semi
 
 	case ')':
@@ -114,8 +135,7 @@ redo:
 	case '.':
 		c = s.getr()
 		if isDigit(c) {
-			s.ungetr()
-			s.source.r0-- // make sure '.' is part of literal (line cannot have changed)
+			s.ungetr2()
 			s.number('.')
 			break
 		}
@@ -125,8 +145,7 @@ redo:
 				s.tok = _DotDotDot
 				break
 			}
-			s.ungetr()
-			s.source.r0-- // make next ungetr work (line cannot have changed)
+			s.ungetr2()
 		}
 		s.ungetr()
 		s.tok = _Dot
@@ -170,6 +189,7 @@ redo:
 			if s.source.line > s.line && nlsemi {
 				// A multi-line comment acts like a newline;
 				// it translates to a ';' if nlsemi is set.
+				s.lit = "newline"
 				s.tok = _Semi
 				break
 			}
@@ -273,7 +293,7 @@ redo:
 
 	default:
 		s.tok = 0
-		s.error(fmt.Sprintf("illegal character %#U", c))
+		s.error(fmt.Sprintf("invalid character %#U", c))
 		goto redo
 	}
 
@@ -307,7 +327,7 @@ func (s *scanner) ident() {
 
 	// general case
 	if c >= utf8.RuneSelf {
-		for unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || s.isCompatRune(c, false) {
+		for s.isIdentRune(c, false) {
 			c = s.getr()
 		}
 	}
@@ -329,14 +349,18 @@ func (s *scanner) ident() {
 	s.tok = _Name
 }
 
-func (s *scanner) isCompatRune(c rune, start bool) bool {
-	if !gcCompat || c < utf8.RuneSelf {
-		return false
-	}
-	if start && unicode.IsNumber(c) {
-		s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c))
-	} else {
+func (s *scanner) isIdentRune(c rune, first bool) bool {
+	switch {
+	case unicode.IsLetter(c) || c == '_':
+		// ok
+	case unicode.IsDigit(c):
+		if first {
+			s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c))
+		}
+	case c >= utf8.RuneSelf:
 		s.error(fmt.Sprintf("invalid identifier character %#U", c))
+	default:
+		return false
 	}
 	return true
 }
@@ -442,6 +466,53 @@ done:
 	s.tok = _Literal
 }
 
+func (s *scanner) rune() {
+	s.startLit()
+
+	ok := true // only report errors if we're ok so far
+	n := 0
+	for ; ; n++ {
+		r := s.getr()
+		if r == '\'' {
+			break
+		}
+		if r == '\\' {
+			if !s.escape('\'') {
+				ok = false
+			}
+			continue
+		}
+		if r == '\n' {
+			s.ungetr() // assume newline is not part of literal
+			if ok {
+				s.error("newline in character literal")
+				ok = false
+			}
+			break
+		}
+		if r < 0 {
+			if ok {
+				s.errh(s.line, s.col, "invalid character literal (missing closing ')")
+				ok = false
+			}
+			break
+		}
+	}
+
+	if ok {
+		if n == 0 {
+			s.error("empty character literal or unescaped ' in character literal")
+		} else if n != 1 {
+			s.errh(s.line, s.col, "invalid character literal (more than one character)")
+		}
+	}
+
+	s.nlsemi = true
+	s.lit = string(s.stopLit())
+	s.kind = RuneLit
+	s.tok = _Literal
+}
+
 func (s *scanner) stdString() {
 	s.startLit()
 
@@ -460,7 +531,7 @@ func (s *scanner) stdString() {
 			break
 		}
 		if r < 0 {
-			s.error_at(s.pos, s.line, "string not terminated")
+			s.errh(s.line, s.col, "string not terminated")
 			break
 		}
 	}
@@ -480,7 +551,7 @@ func (s *scanner) rawString() {
 			break
 		}
 		if r < 0 {
-			s.error_at(s.pos, s.line, "string not terminated")
+			s.errh(s.line, s.col, "string not terminated")
 			break
 		}
 	}
@@ -494,80 +565,47 @@ func (s *scanner) rawString() {
 	s.tok = _Literal
 }
 
-func (s *scanner) rune() {
-	s.startLit()
-
-	r := s.getr()
-	ok := false
-	if r == '\'' {
-		s.error("empty character literal or unescaped ' in character literal")
-	} else if r == '\n' {
-		s.ungetr() // assume newline is not part of literal
-		s.error("newline in character literal")
-	} else {
-		ok = true
-		if r == '\\' {
-			ok = s.escape('\'')
-		}
-	}
-
-	r = s.getr()
-	if r != '\'' {
-		// only report error if we're ok so far
-		if ok {
-			s.error("missing '")
+func (s *scanner) skipLine(r rune) {
+	for r >= 0 {
+		if r == '\n' {
+			s.ungetr() // don't consume '\n' - needed for nlsemi logic
+			break
 		}
-		s.ungetr()
+		r = s.getr()
 	}
-
-	s.nlsemi = true
-	s.lit = string(s.stopLit())
-	s.kind = RuneLit
-	s.tok = _Literal
 }
 
 func (s *scanner) lineComment() {
-	// recognize pragmas
-	var prefix string
 	r := s.getr()
-	if s.pragh == nil {
-		goto skip
+	// directives must start at the beginning of the line (s.col == colbase)
+	if s.col != colbase || s.pragh == nil || (r != 'g' && r != 'l') {
+		s.skipLine(r)
+		return
 	}
+	// s.col == colbase && s.pragh != nil && (r == 'g' || r == 'l')
 
-	switch r {
-	case 'g':
-		prefix = "go:"
-	case 'l':
+	// recognize directives
+	prefix := "go:"
+	if r == 'l' {
 		prefix = "line "
-	default:
-		goto skip
 	}
-
-	s.startLit()
 	for _, m := range prefix {
 		if r != m {
-			s.stopLit()
-			goto skip
+			s.skipLine(r)
+			return
 		}
 		r = s.getr()
 	}
 
-	for r >= 0 {
-		if r == '\n' {
-			s.ungetr()
-			break
-		}
-		r = s.getr()
+	// directive text without line ending (which may be "\r\n" if Windows),
+	s.startLit()
+	s.skipLine(r)
+	text := s.stopLit()
+	if i := len(text) - 1; i >= 0 && text[i] == '\r' {
+		text = text[:i]
 	}
-	s.pragma |= s.pragh(0, s.line, strings.TrimSuffix(string(s.stopLit()), "\r"))
-	return
 
-skip:
-	// consume line
-	for r != '\n' && r >= 0 {
-		r = s.getr()
-	}
-	s.ungetr() // don't consume '\n' - needed for nlsemi logic
+	s.pragh(s.line, s.col+2, prefix+string(text)) // +2 since directive text starts after //
 }
 
 func (s *scanner) fullComment() {
@@ -580,7 +618,7 @@ func (s *scanner) fullComment() {
 			}
 		}
 		if r < 0 {
-			s.error_at(s.pos, s.line, "comment not terminated")
+			s.errh(s.line, s.col, "comment not terminated")
 			return
 		}
 	}
@@ -628,19 +666,11 @@ func (s *scanner) escape(quote rune) bool {
 			if c < 0 {
 				return true // complain in caller about EOF
 			}
-			if gcCompat {
-				name := "hex"
-				if base == 8 {
-					name = "octal"
-				}
-				s.error(fmt.Sprintf("non-%s character in escape sequence: %c", name, c))
-			} else {
-				if c != quote {
-					s.error(fmt.Sprintf("illegal character %#U in escape sequence", c))
-				} else {
-					s.error("escape sequence incomplete")
-				}
+			kind := "hex"
+			if base == 8 {
+				kind = "octal"
 			}
+			s.error(fmt.Sprintf("non-%s character in escape sequence: %c", kind, c))
 			s.ungetr()
 			return false
 		}
diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go
index 0e81c4e..e434db9 100644
--- a/src/cmd/compile/internal/syntax/scanner_test.go
+++ b/src/cmd/compile/internal/syntax/scanner_test.go
@@ -56,8 +56,8 @@ func TestTokens(t *testing.T) {
 	for i, want := range sampleTokens {
 		nlsemi := false
 
-		if got.line != i+1 {
-			t.Errorf("got line %d; want %d", got.line, i+1)
+		if got.line != uint(i+linebase) {
+			t.Errorf("got line %d; want %d", got.line, i+linebase)
 		}
 
 		if got.tok != want.tok {
@@ -66,6 +66,11 @@ func TestTokens(t *testing.T) {
 		}
 
 		switch want.tok {
+		case _Semi:
+			if got.lit != "semicolon" {
+				t.Errorf("got %s; want semicolon", got.lit)
+			}
+
 		case _Name, _Literal:
 			if got.lit != want.src {
 				t.Errorf("got lit = %q; want %q", got.lit, want.src)
@@ -94,6 +99,9 @@ func TestTokens(t *testing.T) {
 				t.Errorf("got tok = %s; want ;", got.tok)
 				continue
 			}
+			if got.lit != "newline" {
+				t.Errorf("got %s; want newline", got.lit)
+			}
 		}
 
 		got.next()
@@ -256,88 +264,94 @@ var sampleTokens = [...]struct {
 func TestScanErrors(t *testing.T) {
 	for _, test := range []struct {
 		src, msg  string
-		pos, line int
+		line, col uint // 0-based
 	}{
 		// Note: Positions for lexical errors are the earliest position
 		// where the error is apparent, not the beginning of the respective
 		// token.
 
 		// rune-level errors
-		{"fo\x00o", "invalid NUL character", 2, 1},
-		{"foo\n\ufeff bar", "invalid BOM in the middle of the file", 4, 2},
-		{"foo\n\n\xff    ", "invalid UTF-8 encoding", 5, 3},
+		{"fo\x00o", "invalid NUL character", 0, 2},
+		{"foo\n\ufeff bar", "invalid BOM in the middle of the file", 1, 0},
+		{"foo\n\n\xff    ", "invalid UTF-8 encoding", 2, 0},
 
 		// token-level errors
-		{"x + ~y", "bitwise complement operator is ^", 4, 1},
-		{"foo$bar = 0", "illegal character U+0024 '$'", 3, 1},
-		{"const x = 0xyz", "malformed hex constant", 12, 1},
-		{"0123456789", "malformed octal constant", 10, 1},
-		{"0123456789. /* foobar", "comment not terminated", 12, 1},   // valid float constant
-		{"0123456789e0 /*\nfoobar", "comment not terminated", 13, 1}, // valid float constant
-		{"var a, b = 08, 07\n", "malformed octal constant", 13, 1},
-		{"(x + 1.0e+x)", "malformed floating-point constant exponent", 10, 1},
-
-		{`''`, "empty character literal or unescaped ' in character literal", 1, 1},
-		{"'\n", "newline in character literal", 1, 1},
-		{`'\`, "missing '", 2, 1},
-		{`'\'`, "missing '", 3, 1},
-		{`'\x`, "missing '", 3, 1},
-		{`'\x'`, "non-hex character in escape sequence: '", 3, 1},
-		{`'\y'`, "unknown escape sequence", 2, 1},
-		{`'\x0'`, "non-hex character in escape sequence: '", 4, 1},
-		{`'\00'`, "non-octal character in escape sequence: '", 4, 1},
-		{`'\377' /*`, "comment not terminated", 7, 1}, // valid octal escape
-		{`'\378`, "non-octal character in escape sequence: 8", 4, 1},
-		{`'\400'`, "octal escape value > 255: 256", 5, 1},
-		{`'xx`, "missing '", 2, 1},
-
-		{"\"\n", "newline in string", 1, 1},
-		{`"`, "string not terminated", 0, 1},
-		{`"foo`, "string not terminated", 0, 1},
-		{"`", "string not terminated", 0, 1},
-		{"`foo", "string not terminated", 0, 1},
-		{"/*/", "comment not terminated", 0, 1},
-		{"/*\n\nfoo", "comment not terminated", 0, 1},
-		{"/*\n\nfoo", "comment not terminated", 0, 1},
-		{`"\`, "string not terminated", 0, 1},
-		{`"\"`, "string not terminated", 0, 1},
-		{`"\x`, "string not terminated", 0, 1},
-		{`"\x"`, "non-hex character in escape sequence: \"", 3, 1},
-		{`"\y"`, "unknown escape sequence", 2, 1},
-		{`"\x0"`, "non-hex character in escape sequence: \"", 4, 1},
-		{`"\00"`, "non-octal character in escape sequence: \"", 4, 1},
-		{`"\377" /*`, "comment not terminated", 7, 1}, // valid octal escape
-		{`"\378"`, "non-octal character in escape sequence: 8", 4, 1},
-		{`"\400"`, "octal escape value > 255: 256", 5, 1},
-
-		{`s := "foo\z"`, "unknown escape sequence", 10, 1},
-		{`s := "foo\z00\nbar"`, "unknown escape sequence", 10, 1},
-		{`"\x`, "string not terminated", 0, 1},
-		{`"\x"`, "non-hex character in escape sequence: \"", 3, 1},
-		{`var s string = "\x"`, "non-hex character in escape sequence: \"", 18, 1},
-		{`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 18, 1},
+		{"\u00BD" /* ½ */, "invalid identifier character U+00BD '½'", 0, 0},
+		{"\U0001d736\U0001d737\U0001d738_½" /* 𝜶𝜷𝜸_½ */, "invalid identifier character U+00BD '½'", 0, 13 /* byte offset */},
+		{"\U0001d7d8" /* 𝟘 */, "identifier cannot begin with digit U+1D7D8 '𝟘'", 0, 0},
+		{"foo\U0001d7d8_½" /* foo𝟘_½ */, "invalid identifier character U+00BD '½'", 0, 8 /* byte offset */},
+
+		{"x + ~y", "bitwise complement operator is ^", 0, 4},
+		{"foo$bar = 0", "invalid character U+0024 '$'", 0, 3},
+		{"const x = 0xyz", "malformed hex constant", 0, 12},
+		{"0123456789", "malformed octal constant", 0, 10},
+		{"0123456789. /* foobar", "comment not terminated", 0, 12},   // valid float constant
+		{"0123456789e0 /*\nfoobar", "comment not terminated", 0, 13}, // valid float constant
+		{"var a, b = 08, 07\n", "malformed octal constant", 0, 13},
+		{"(x + 1.0e+x)", "malformed floating-point constant exponent", 0, 10},
+
+		{`''`, "empty character literal or unescaped ' in character literal", 0, 1},
+		{"'\n", "newline in character literal", 0, 1},
+		{`'\`, "invalid character literal (missing closing ')", 0, 0},
+		{`'\'`, "invalid character literal (missing closing ')", 0, 0},
+		{`'\x`, "invalid character literal (missing closing ')", 0, 0},
+		{`'\x'`, "non-hex character in escape sequence: '", 0, 3},
+		{`'\y'`, "unknown escape sequence", 0, 2},
+		{`'\x0'`, "non-hex character in escape sequence: '", 0, 4},
+		{`'\00'`, "non-octal character in escape sequence: '", 0, 4},
+		{`'\377' /*`, "comment not terminated", 0, 7}, // valid octal escape
+		{`'\378`, "non-octal character in escape sequence: 8", 0, 4},
+		{`'\400'`, "octal escape value > 255: 256", 0, 5},
+		{`'xx`, "invalid character literal (missing closing ')", 0, 0},
+		{`'xx'`, "invalid character literal (more than one character)", 0, 0},
+
+		{"\"\n", "newline in string", 0, 1},
+		{`"`, "string not terminated", 0, 0},
+		{`"foo`, "string not terminated", 0, 0},
+		{"`", "string not terminated", 0, 0},
+		{"`foo", "string not terminated", 0, 0},
+		{"/*/", "comment not terminated", 0, 0},
+		{"/*\n\nfoo", "comment not terminated", 0, 0},
+		{"/*\n\nfoo", "comment not terminated", 0, 0},
+		{`"\`, "string not terminated", 0, 0},
+		{`"\"`, "string not terminated", 0, 0},
+		{`"\x`, "string not terminated", 0, 0},
+		{`"\x"`, "non-hex character in escape sequence: \"", 0, 3},
+		{`"\y"`, "unknown escape sequence", 0, 2},
+		{`"\x0"`, "non-hex character in escape sequence: \"", 0, 4},
+		{`"\00"`, "non-octal character in escape sequence: \"", 0, 4},
+		{`"\377" /*`, "comment not terminated", 0, 7}, // valid octal escape
+		{`"\378"`, "non-octal character in escape sequence: 8", 0, 4},
+		{`"\400"`, "octal escape value > 255: 256", 0, 5},
+
+		{`s := "foo\z"`, "unknown escape sequence", 0, 10},
+		{`s := "foo\z00\nbar"`, "unknown escape sequence", 0, 10},
+		{`"\x`, "string not terminated", 0, 0},
+		{`"\x"`, "non-hex character in escape sequence: \"", 0, 3},
+		{`var s string = "\x"`, "non-hex character in escape sequence: \"", 0, 18},
+		{`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 0, 18},
 
 		// former problem cases
-		{"package p\n\n\xef", "invalid UTF-8 encoding", 11, 3},
+		{"package p\n\n\xef", "invalid UTF-8 encoding", 2, 0},
 	} {
 		var s scanner
 		nerrors := 0
-		s.init(&bytesReader{[]byte(test.src)}, func(err error) {
+		s.init(&bytesReader{[]byte(test.src)}, func(line, col uint, msg string) {
 			nerrors++
 			// only check the first error
-			e := err.(Error) // we know it's an Error
 			if nerrors == 1 {
-				if e.Msg != test.msg {
-					t.Errorf("%q: got msg = %q; want %q", test.src, e.Msg, test.msg)
+				if msg != test.msg {
+					t.Errorf("%q: got msg = %q; want %q", test.src, msg, test.msg)
 				}
-				if e.Pos != test.pos {
-					t.Errorf("%q: got pos = %d; want %d", test.src, e.Pos, test.pos)
+				if line != test.line+linebase {
+					t.Errorf("%q: got line = %d; want %d", test.src, line, test.line+linebase)
 				}
-				if e.Line != test.line {
-					t.Errorf("%q: got line = %d; want %d", test.src, e.Line, test.line)
+				if col != test.col+colbase {
+					t.Errorf("%q: got col = %d; want %d", test.src, col, test.col+colbase)
 				}
 			} else if nerrors > 1 {
-				t.Errorf("%q: got unexpected %q at pos = %d, line = %d", test.src, e.Msg, e.Pos, e.Line)
+				// TODO(gri) make this use position info
+				t.Errorf("%q: got unexpected %q at line = %d", test.src, msg, line)
 			}
 		}, nil)
 
diff --git a/src/cmd/compile/internal/syntax/source.go b/src/cmd/compile/internal/syntax/source.go
index 05a1196..9354721 100644
--- a/src/cmd/compile/internal/syntax/source.go
+++ b/src/cmd/compile/internal/syntax/source.go
@@ -2,6 +2,15 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This file implements source, a buffered rune reader
+// which is specialized for the needs of the Go scanner:
+// Contiguous sequences of runes (literals) are extracted
+// directly as []byte without the need to re-encode the
+// runes in UTF-8 (as would be necessary with bufio.Reader).
+//
+// This file is self-contained (go tool compile source.go
+// compiles) and thus could be made into its own package.
+
 package syntax
 
 import (
@@ -9,70 +18,79 @@ import (
 	"unicode/utf8"
 )
 
+// starting points for line and column numbers
+const linebase = 1
+const colbase = 1
+
 // buf [...read...|...|...unread...|s|...free...]
 //         ^      ^   ^            ^
 //         |      |   |            |
 //        suf     r0  r            w
 
 type source struct {
-	src   io.Reader
-	errh  ErrorHandler
-	first error // first error encountered
+	src  io.Reader
+	errh func(line, pos uint, msg string)
 
 	// source buffer
 	buf         [4 << 10]byte
 	offs        int   // source offset of buf
 	r0, r, w    int   // previous/current read and write buf positions, excluding sentinel
-	line0, line int   // previous/current line
-	err         error // pending io error
+	line0, line uint  // previous/current line
+	col0, col   uint  // previous/current column (byte offsets from line start)
+	ioerr       error // pending io error
 
 	// literal buffer
 	lit []byte // literal prefix
 	suf int    // literal suffix; suf >= 0 means we are scanning a literal
 }
 
-func (s *source) init(src io.Reader, errh ErrorHandler) {
+// init initializes source to read from src and to report errors via errh.
+// errh must not be nil.
+func (s *source) init(src io.Reader, errh func(line, pos uint, msg string)) {
 	s.src = src
 	s.errh = errh
-	s.first = nil
 
 	s.buf[0] = utf8.RuneSelf // terminate with sentinel
 	s.offs = 0
 	s.r0, s.r, s.w = 0, 0, 0
-	s.line0, s.line = 1, 1
-	s.err = nil
+	s.line0, s.line = 0, linebase
+	s.col0, s.col = 0, colbase
+	s.ioerr = nil
 
 	s.lit = s.lit[:0]
 	s.suf = -1
 }
 
-func (s *source) error(msg string) {
-	s.error_at(s.pos0(), s.line0, msg)
-}
-
-func (s *source) error_at(pos, line int, msg string) {
-	err := Error{pos, line, msg}
-	if s.first == nil {
-		s.first = err
-	}
-	if s.errh == nil {
-		panic(s.first)
-	}
-	s.errh(err)
+// ungetr ungets the most recently read rune.
+func (s *source) ungetr() {
+	s.r, s.line, s.col = s.r0, s.line0, s.col0
 }
 
-// pos0 returns the byte position of the last character read.
-func (s *source) pos0() int {
-	return s.offs + s.r0
+// ungetr2 is like ungetr but enables a 2nd ungetr.
+// It must not be called if one of the runes seen
+// was a newline.
+func (s *source) ungetr2() {
+	s.ungetr()
+	// line must not have changed
+	s.r0--
+	s.col0--
 }
 
-func (s *source) ungetr() {
-	s.r, s.line = s.r0, s.line0
+func (s *source) error(msg string) {
+	s.errh(s.line0, s.col0, msg)
 }
 
+// getr reads and returns the next rune.
+//
+// If a read or source encoding error occurs, getr
+// calls the error handler installed with init.
+// The handler must exist.
+//
+// The (line, col) position passed to the error handler
+// is always at the current source reading position.
 func (s *source) getr() rune {
 redo:
-	s.r0, s.line0 = s.r, s.line
+	s.r0, s.line0, s.col0 = s.r, s.line, s.col
 
 	// We could avoid at least one test that is always taken in the
 	// for loop below by duplicating the common case code (ASCII)
@@ -80,7 +98,7 @@ redo:
 	// in the buffer. Measure and optimize if necessary.
 
 	// make sure we have at least one rune in buffer, or we are at EOF
-	for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.err == nil && s.w-s.r < len(s.buf) {
+	for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.ioerr == nil && s.w-s.r < len(s.buf) {
 		s.fill() // s.w-s.r < len(s.buf) => buffer is not full
 	}
 
@@ -88,20 +106,25 @@ redo:
 	// (invariant: s.buf[s.w] == utf8.RuneSelf)
 	if b := s.buf[s.r]; b < utf8.RuneSelf {
 		s.r++
+		// TODO(gri) Optimization: Instead of adjusting s.col for each character,
+		// remember the line offset instead and then compute the offset as needed
+		// (which is less often).
+		s.col++
 		if b == 0 {
 			s.error("invalid NUL character")
 			goto redo
 		}
 		if b == '\n' {
 			s.line++
+			s.col = colbase
 		}
 		return rune(b)
 	}
 
 	// EOF
 	if s.r == s.w {
-		if s.err != io.EOF {
-			s.error(s.err.Error())
+		if s.ioerr != io.EOF {
+			s.error(s.ioerr.Error())
 		}
 		return -1
 	}
@@ -109,6 +132,7 @@ redo:
 	// uncommon case: not ASCII
 	r, w := utf8.DecodeRune(s.buf[s.r:s.w])
 	s.r += w
+	s.col += uint(w)
 
 	if r == utf8.RuneError && w == 1 {
 		s.error("invalid UTF-8 encoding")
@@ -157,13 +181,13 @@ func (s *source) fill() {
 		if n > 0 || err != nil {
 			s.buf[s.w] = utf8.RuneSelf // sentinel
 			if err != nil {
-				s.err = err
+				s.ioerr = err
 			}
 			return
 		}
 	}
 
-	s.err = io.ErrNoProgress
+	s.ioerr = io.ErrNoProgress
 }
 
 func (s *source) startLit() {
diff --git a/src/cmd/compile/internal/syntax/syntax.go b/src/cmd/compile/internal/syntax/syntax.go
index b1e56ee..ed5e254 100644
--- a/src/cmd/compile/internal/syntax/syntax.go
+++ b/src/cmd/compile/internal/syntax/syntax.go
@@ -5,6 +5,7 @@
 package syntax
 
 import (
+	"cmd/internal/src"
 	"fmt"
 	"io"
 	"os"
@@ -13,16 +14,19 @@ import (
 // Mode describes the parser mode.
 type Mode uint
 
+// Modes supported by the parser.
+const (
+	CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
+)
+
 // Error describes a syntax error. Error implements the error interface.
 type Error struct {
-	// TODO(gri) decide what we really need here
-	Pos  int // byte offset from file start
-	Line int // line (starting with 1)
-	Msg  string
+	Pos src.Pos
+	Msg string
 }
 
 func (err Error) Error() string {
-	return fmt.Sprintf("%d: %s", err.Line, err.Msg)
+	return fmt.Sprintf("%s: %s", err.Pos, err.Msg)
 }
 
 var _ error = Error{} // verify that Error implements error
@@ -38,11 +42,12 @@ type Pragma uint16
 // A PragmaHandler is used to process //line and //go: directives as
 // they're scanned. The returned Pragma value will be unioned into the
 // next FuncDecl node.
-type PragmaHandler func(pos, line int, text string) Pragma
+type PragmaHandler func(pos src.Pos, text string) Pragma
 
 // Parse parses a single Go source file from src and returns the corresponding
-// syntax tree. If there are syntax errors, Parse will return the first error
-// encountered.
+// syntax tree. If there are errors, Parse will return the first error found,
+// and a possibly partially constructed syntax tree, or nil if no correct package
+// clause was found. The base argument is only used for position information.
 //
 // If errh != nil, it is called with each error encountered, and Parse will
 // process as much source as possible. If errh is nil, Parse will terminate
@@ -51,11 +56,11 @@ type PragmaHandler func(pos, line int, text string) Pragma
 // If a PragmaHandler is provided, it is called with each pragma encountered.
 //
 // The Mode argument is currently ignored.
-func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, err error) {
+func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
 	defer func() {
 		if p := recover(); p != nil {
-			var ok bool
-			if err, ok = p.(Error); ok {
+			if err, ok := p.(Error); ok {
+				first = err
 				return
 			}
 			panic(p)
@@ -63,14 +68,14 @@ func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_
 	}()
 
 	var p parser
-	p.init(src, errh, pragh)
+	p.init(base, src, errh, pragh, mode)
 	p.next()
-	return p.file(), p.first
+	return p.fileOrNil(), p.first
 }
 
 // ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
-func ParseBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
-	return Parse(&bytesReader{src}, errh, pragh, mode)
+func ParseBytes(base *src.PosBase, src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
+	return Parse(base, &bytesReader{src}, errh, pragh, mode)
 }
 
 type bytesReader struct {
@@ -88,13 +93,13 @@ func (r *bytesReader) Read(p []byte) (int, error) {
 
 // ParseFile behaves like Parse but it reads the source from the named file.
 func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
-	src, err := os.Open(filename)
+	f, err := os.Open(filename)
 	if err != nil {
 		if errh != nil {
 			errh(err)
 		}
 		return nil, err
 	}
-	defer src.Close()
-	return Parse(src, errh, pragh, mode)
+	defer f.Close()
+	return Parse(src.NewFileBase(filename, filename), f, errh, pragh, mode)
 }
diff --git a/src/cmd/compile/internal/types/pkg.go b/src/cmd/compile/internal/types/pkg.go
new file mode 100644
index 0000000..81bf72e
--- /dev/null
+++ b/src/cmd/compile/internal/types/pkg.go
@@ -0,0 +1,135 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"fmt"
+	"sort"
+	"sync"
+)
+
+// pkgMap maps a package path to a package.
+var pkgMap = make(map[string]*Pkg)
+
+type Pkg struct {
+	Path     string // string literal used in import statement, e.g. "runtime/internal/sys"
+	Name     string // package name, e.g. "sys"
+	Pathsym  *obj.LSym
+	Prefix   string // escaped path for use in symbol table
+	Imported bool   // export data of this package was parsed
+	Direct   bool   // imported directly
+	Syms     map[string]*Sym
+}
+
+// NewPkg returns a new Pkg for the given package path and name.
+// Unless name is the empty string, if the package exists already,
+// the existing package name and the provided name must match.
+func NewPkg(path, name string) *Pkg {
+	if p := pkgMap[path]; p != nil {
+		if name != "" && p.Name != name {
+			panic(fmt.Sprintf("conflicting package names %s and %s for path %q", p.Name, name, path))
+		}
+		return p
+	}
+
+	p := new(Pkg)
+	p.Path = path
+	p.Name = name
+	p.Prefix = objabi.PathToPrefix(path)
+	p.Syms = make(map[string]*Sym)
+	pkgMap[path] = p
+
+	return p
+}
+
+// ImportedPkgList returns the list of directly imported packages.
+// The list is sorted by package path.
+func ImportedPkgList() []*Pkg {
+	var list []*Pkg
+	for _, p := range pkgMap {
+		if p.Direct {
+			list = append(list, p)
+		}
+	}
+	sort.Sort(byPath(list))
+	return list
+}
+
+type byPath []*Pkg
+
+func (a byPath) Len() int           { return len(a) }
+func (a byPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
+func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+var nopkg = &Pkg{
+	Syms: make(map[string]*Sym),
+}
+
+func (pkg *Pkg) Lookup(name string) *Sym {
+	s, _ := pkg.LookupOK(name)
+	return s
+}
+
+var InitSyms []*Sym
+
+// LookupOK looks up name in pkg and reports whether it previously existed.
+func (pkg *Pkg) LookupOK(name string) (s *Sym, existed bool) {
+	// TODO(gri) remove this check in favor of specialized lookup
+	if pkg == nil {
+		pkg = nopkg
+	}
+	if s := pkg.Syms[name]; s != nil {
+		return s, true
+	}
+
+	s = &Sym{
+		Name: name,
+		Pkg:  pkg,
+	}
+	if name == "init" {
+		InitSyms = append(InitSyms, s)
+	}
+	pkg.Syms[name] = s
+	return s, false
+}
+
+func (pkg *Pkg) LookupBytes(name []byte) *Sym {
+	// TODO(gri) remove this check in favor of specialized lookup
+	if pkg == nil {
+		pkg = nopkg
+	}
+	if s := pkg.Syms[string(name)]; s != nil {
+		return s
+	}
+	str := InternString(name)
+	return pkg.Lookup(str)
+}
+
+var (
+	internedStringsmu sync.Mutex // protects internedStrings
+	internedStrings   = map[string]string{}
+)
+
+func InternString(b []byte) string {
+	internedStringsmu.Lock()
+	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
+	if !ok {
+		s = string(b)
+		internedStrings[s] = s
+	}
+	internedStringsmu.Unlock()
+	return s
+}
+
+// CleanroomDo invokes f in an environment with with no preexisting packages.
+// For testing of import/export only.
+func CleanroomDo(f func()) {
+	saved := pkgMap
+	pkgMap = make(map[string]*Pkg)
+	f()
+	pkgMap = saved
+}
diff --git a/src/cmd/compile/internal/types/scope.go b/src/cmd/compile/internal/types/scope.go
new file mode 100644
index 0000000..072b808
--- /dev/null
+++ b/src/cmd/compile/internal/types/scope.go
@@ -0,0 +1,70 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+// Declaration stack & operations
+
+var blockgen int32 = 1 // 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 Syms on this stack 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
+	a.Block = b.Block
+	a.Lastlineno = b.Lastlineno
+}
+
+func push() *Sym {
+	d := new(Sym)
+	dclstack = append(dclstack, d)
+	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) {
+	dcopy(push(), s)
+}
+
+// Popdcl pops the innermost block scope and restores all symbol declarations
+// to their previous state.
+func Popdcl() {
+	for i := len(dclstack); i > 0; i-- {
+		d := dclstack[i-1]
+		if d.Name == "" {
+			// pop stack mark
+			Block = d.Block
+			dclstack = dclstack[:i-1]
+			return
+		}
+		dcopy(d.Pkg.Lookup(d.Name), d)
+	}
+	Fatalf("popdcl: no stack mark")
+}
+
+// Markdcl records the start of a new block scope for declarations.
+func Markdcl() {
+	push().Block = Block // stack mark (Name == "")
+	blockgen++
+	Block = blockgen
+}
+
+func IsDclstackValid() bool {
+	for _, d := range dclstack {
+		if d.Name == "" {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/cmd/compile/internal/types/sizeof_test.go b/src/cmd/compile/internal/types/sizeof_test.go
new file mode 100644
index 0000000..04e2f01
--- /dev/null
+++ b/src/cmd/compile/internal/types/sizeof_test.go
@@ -0,0 +1,51 @@
+// Copyright 2017 The Go Authors. 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 types
+
+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
+	}{
+		{Sym{}, 52, 88},
+		{Type{}, 52, 88},
+		{Map{}, 20, 40},
+		{Forward{}, 20, 32},
+		{Func{}, 28, 48},
+		{Struct{}, 12, 24},
+		{Interface{}, 4, 8},
+		{Chan{}, 8, 16},
+		{Array{}, 12, 16},
+		{DDDField{}, 4, 8},
+		{FuncArgs{}, 4, 8},
+		{ChanArgs{}, 4, 8},
+		{Ptr{}, 4, 8},
+		{Slice{}, 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/types/sym.go b/src/cmd/compile/internal/types/sym.go
new file mode 100644
index 0000000..f79b07b
--- /dev/null
+++ b/src/cmd/compile/internal/types/sym.go
@@ -0,0 +1,81 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/src"
+)
+
+// 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 an 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 {
+	Importdef *Pkg   // where imported definition was found
+	Linkname  string // link name
+
+	// saved and restored by dcopy
+	Pkg        *Pkg
+	Name       string   // object name
+	Def        *Node    // definition: ONAME OTYPE OPACK or OLITERAL
+	Block      int32    // blocknumber to catch redeclaration
+	Lastlineno src.XPos // last declaration for diagnostic
+
+	flags   bitset8
+	Label   *Node // corresponding label (ephemeral)
+	Origpkg *Pkg  // original package for . import
+}
+
+const (
+	symExport = 1 << iota // added to exportlist (no need to add again)
+	symPackage
+	symExported // already written out by export
+	symUniq
+	symSiggen
+	symAsm
+	symAlgGen
+)
+
+func (sym *Sym) Export() bool   { return sym.flags&symExport != 0 }
+func (sym *Sym) Package() bool  { return sym.flags&symPackage != 0 }
+func (sym *Sym) Exported() bool { return sym.flags&symExported != 0 }
+func (sym *Sym) Uniq() bool     { return sym.flags&symUniq != 0 }
+func (sym *Sym) Siggen() bool   { return sym.flags&symSiggen != 0 }
+func (sym *Sym) Asm() bool      { return sym.flags&symAsm != 0 }
+func (sym *Sym) AlgGen() bool   { return sym.flags&symAlgGen != 0 }
+
+func (sym *Sym) SetExport(b bool)   { sym.flags.set(symExport, b) }
+func (sym *Sym) SetPackage(b bool)  { sym.flags.set(symPackage, b) }
+func (sym *Sym) SetExported(b bool) { sym.flags.set(symExported, b) }
+func (sym *Sym) SetUniq(b bool)     { sym.flags.set(symUniq, b) }
+func (sym *Sym) SetSiggen(b bool)   { sym.flags.set(symSiggen, b) }
+func (sym *Sym) SetAsm(b bool)      { sym.flags.set(symAsm, b) }
+func (sym *Sym) SetAlgGen(b bool)   { sym.flags.set(symAlgGen, b) }
+
+func (sym *Sym) IsBlank() bool {
+	return sym != nil && sym.Name == "_"
+}
+
+func (sym *Sym) LinksymName() string {
+	if sym.IsBlank() {
+		return "_"
+	}
+	if sym.Linkname != "" {
+		return sym.Linkname
+	}
+	return sym.Pkg.Prefix + "." + sym.Name
+}
+
+func (sym *Sym) Linksym() *obj.LSym {
+	if sym == nil {
+		return nil
+	}
+	return Ctxt.Lookup(sym.LinksymName())
+}
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
new file mode 100644
index 0000000..5c44e62
--- /dev/null
+++ b/src/cmd/compile/internal/types/type.go
@@ -0,0 +1,1416 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/src"
+	"fmt"
+)
+
+// Dummy Node so we can refer to *Node without actually
+// having a gc.Node. Necessary to break import cycles.
+// TODO(gri) try to eliminate soon
+type Node struct{ _ int }
+
+// 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
+
+	// pseudo-types for import/export
+	TDDDFIELD // wrapper: contained type is a ... field
+
+	// SSA backend types
+	TSSA   // internal types used by SSA backend (flags, memory, etc.)
+	TTUPLE // a pair of types, used by SSA backend
+
+	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     = New(TIDEAL)
+	Idealrune    = New(TIDEAL)
+	Idealfloat   = New(TIDEAL)
+	Idealcomplex = New(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: *Map
+	// TFORW: *Forward
+	// TFUNC: *Func
+	// TSTRUCT: *Struct
+	// TINTER: *Inter
+	// TDDDFIELD: DDDField
+	// TFUNCARGS: FuncArgs
+	// TCHANARGS: ChanArgs
+	// TCHAN: *Chan
+	// TPTR32, TPTR64: Ptr
+	// TARRAY: *Array
+	// TSLICE: Slice
+	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)
+
+	SliceOf *Type
+	PtrBase *Type
+
+	Sym    *Sym  // symbol containing name, for named types
+	Vargen int32 // unique name for OTYPE/ONAME
+
+	Etype EType // kind of type
+	Align uint8 // the required alignment of this type, in bytes
+
+	flags bitset8
+}
+
+const (
+	typeLocal     = 1 << iota // created in this file
+	typeNotInHeap             // type cannot be heap allocated
+	typeBroke                 // broken type definition
+	typeNoalg                 // suppress hash and eq algorithm generation
+	typeDeferwidth
+	typeRecur
+)
+
+func (t *Type) Local() bool      { return t.flags&typeLocal != 0 }
+func (t *Type) NotInHeap() bool  { return t.flags&typeNotInHeap != 0 }
+func (t *Type) Broke() bool      { return t.flags&typeBroke != 0 }
+func (t *Type) Noalg() bool      { return t.flags&typeNoalg != 0 }
+func (t *Type) Deferwidth() bool { return t.flags&typeDeferwidth != 0 }
+func (t *Type) Recur() bool      { return t.flags&typeRecur != 0 }
+
+func (t *Type) SetLocal(b bool)      { t.flags.set(typeLocal, b) }
+func (t *Type) SetNotInHeap(b bool)  { t.flags.set(typeNotInHeap, b) }
+func (t *Type) SetBroke(b bool)      { t.flags.set(typeBroke, b) }
+func (t *Type) SetNoalg(b bool)      { t.flags.set(typeNoalg, b) }
+func (t *Type) SetDeferwidth(b bool) { t.flags.set(typeDeferwidth, b) }
+func (t *Type) SetRecur(b bool)      { t.flags.set(typeRecur, b) }
+
+// Map contains Type fields specific to maps.
+type Map 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() *Map {
+	t.wantEtype(TMAP)
+	return t.Extra.(*Map)
+}
+
+// Forward contains Type fields specific to forward types.
+type Forward struct {
+	Copyto      []*Node  // where to copy the eventual value to
+	Embedlineno src.XPos // first use of this type as an embedded type
+}
+
+// ForwardType returns t's extra forward-type-specific fields.
+func (t *Type) ForwardType() *Forward {
+	t.wantEtype(TFORW)
+	return t.Extra.(*Forward)
+}
+
+// Func contains Type fields specific to func types.
+type Func 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() *Func {
+	t.wantEtype(TFUNC)
+	return t.Extra.(*Func)
+}
+
+// StructType contains Type fields specific to struct types.
+type Struct 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
+}
+
+// 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() *Struct {
+	t.wantEtype(TSTRUCT)
+	return t.Extra.(*Struct)
+}
+
+// Interface contains Type fields specific to interface types.
+type Interface struct {
+	Fields Fields
+}
+
+// Ptr contains Type fields specific to pointer types.
+type Ptr struct {
+	Elem *Type // element type
+}
+
+// DDDField contains Type fields specific to TDDDFIELD types.
+type DDDField struct {
+	T *Type // reference to a slice type for ... args
+}
+
+// ChanArgs contains Type fields specific to TCHANARGS types.
+type ChanArgs struct {
+	T *Type // reference to a chan type whose elements need a width check
+}
+
+// // FuncArgs contains Type fields specific to TFUNCARGS types.
+type FuncArgs struct {
+	T *Type // reference to a func type whose elements need a width check
+}
+
+// Chan contains Type fields specific to channel types.
+type Chan struct {
+	Elem *Type   // element type
+	Dir  ChanDir // channel direction
+}
+
+// ChanType returns t's extra channel-specific fields.
+func (t *Type) ChanType() *Chan {
+	t.wantEtype(TCHAN)
+	return t.Extra.(*Chan)
+}
+
+type Tuple struct {
+	first  *Type
+	second *Type
+	// Any tuple with a memory type must put that memory type second.
+}
+
+// Array contains Type fields specific to array types.
+type Array struct {
+	Elem  *Type // element type
+	Bound int64 // number of elements; <0 if unknown yet
+}
+
+// Slice contains Type fields specific to slice types.
+type Slice 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 {
+	flags bitset8
+
+	Embedded uint8 // embedded field
+	Funarg   Funarg
+
+	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
+}
+
+const (
+	fieldIsddd = 1 << iota // field is ... argument
+	fieldBroke             // broken field definition
+	fieldNointerface
+)
+
+func (f *Field) Isddd() bool       { return f.flags&fieldIsddd != 0 }
+func (f *Field) Broke() bool       { return f.flags&fieldBroke != 0 }
+func (f *Field) Nointerface() bool { return f.flags&fieldNointerface != 0 }
+
+func (f *Field) SetIsddd(b bool)       { f.flags.set(fieldIsddd, b) }
+func (f *Field) SetBroke(b bool)       { f.flags.set(fieldBroke, b) }
+func (f *Field) SetNointerface(b bool) { f.flags.set(fieldNointerface, b) }
+
+// 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...)
+}
+
+// New returns a new Type of the specified kind.
+func New(et EType) *Type {
+	t := &Type{
+		Etype: et,
+		Width: BADWIDTH,
+	}
+	t.Orig = t
+	// TODO(josharian): lazily initialize some of these?
+	switch t.Etype {
+	case TMAP:
+		t.Extra = new(Map)
+	case TFORW:
+		t.Extra = new(Forward)
+	case TFUNC:
+		t.Extra = new(Func)
+	case TSTRUCT:
+		t.Extra = new(Struct)
+	case TINTER:
+		t.Extra = new(Interface)
+	case TPTR32, TPTR64:
+		t.Extra = Ptr{}
+	case TCHANARGS:
+		t.Extra = ChanArgs{}
+	case TFUNCARGS:
+		t.Extra = FuncArgs{}
+	case TDDDFIELD:
+		t.Extra = DDDField{}
+	case TCHAN:
+		t.Extra = new(Chan)
+	case TTUPLE:
+		t.Extra = new(Tuple)
+	}
+	return t
+}
+
+// NewArray returns a new fixed-length array Type.
+func NewArray(elem *Type, bound int64) *Type {
+	if bound < 0 {
+		Fatalf("NewArray: invalid bound %v", bound)
+	}
+	t := New(TARRAY)
+	t.Extra = &Array{Elem: elem, Bound: bound}
+	t.SetNotInHeap(elem.NotInHeap())
+	return t
+}
+
+// NewSlice returns the slice Type with element type elem.
+func NewSlice(elem *Type) *Type {
+	if t := elem.SliceOf; t != nil {
+		if t.Elem() != elem {
+			Fatalf("elem mismatch")
+		}
+		return t
+	}
+
+	t := New(TSLICE)
+	t.Extra = Slice{Elem: elem}
+	elem.SliceOf = t
+	return t
+}
+
+// NewDDDArray returns a new [...]T array Type.
+func NewDDDArray(elem *Type) *Type {
+	t := New(TARRAY)
+	t.Extra = &Array{Elem: elem, Bound: -1}
+	t.SetNotInHeap(elem.NotInHeap())
+	return t
+}
+
+// NewChan returns a new chan Type with direction dir.
+func NewChan(elem *Type, dir ChanDir) *Type {
+	t := New(TCHAN)
+	ct := t.ChanType()
+	ct.Elem = elem
+	ct.Dir = dir
+	return t
+}
+
+func NewTuple(t1, t2 *Type) *Type {
+	t := New(TTUPLE)
+	t.Extra.(*Tuple).first = t1
+	t.Extra.(*Tuple).second = t2
+	return t
+}
+
+func newSSA(name string) *Type {
+	t := New(TSSA)
+	t.Extra = name
+	return t
+}
+
+// NewMap returns a new map Type with key type k and element (aka value) type v.
+func NewMap(k, v *Type) *Type {
+	t := New(TMAP)
+	mt := t.MapType()
+	mt.Key = k
+	mt.Val = v
+	return t
+}
+
+// NewPtrCacheEnabled controls whether *T Types are cached in T.
+// Caching is disabled just before starting the backend.
+// This allows the backend to run concurrently.
+var NewPtrCacheEnabled = true
+
+// NewPtr returns the pointer type pointing to t.
+func NewPtr(elem *Type) *Type {
+	if elem == nil {
+		Fatalf("NewPtr: pointer to elem Type is nil")
+	}
+
+	if t := elem.PtrBase; t != nil {
+		if t.Elem() != elem {
+			Fatalf("NewPtr: elem mismatch")
+		}
+		return t
+	}
+
+	if Tptr == 0 {
+		Fatalf("NewPtr: Tptr not initialized")
+	}
+
+	t := New(Tptr)
+	t.Extra = Ptr{Elem: elem}
+	t.Width = int64(Widthptr)
+	t.Align = uint8(Widthptr)
+	if NewPtrCacheEnabled {
+		elem.PtrBase = t
+	}
+	return t
+}
+
+// NewDDDField returns a new TDDDFIELD type for slice type s.
+func NewDDDField(s *Type) *Type {
+	t := New(TDDDFIELD)
+	t.Extra = DDDField{T: s}
+	return t
+}
+
+// NewChanArgs returns a new TCHANARGS type for channel type c.
+func NewChanArgs(c *Type) *Type {
+	t := New(TCHANARGS)
+	t.Extra = ChanArgs{T: c}
+	return t
+}
+
+// NewFuncArgs returns a new TFUNCARGS type for func type f.
+func NewFuncArgs(f *Type) *Type {
+	t := New(TFUNCARGS)
+	t.Extra = FuncArgs{T: f}
+	return t
+}
+
+func NewField() *Field {
+	return &Field{
+		Offset: BADWIDTH,
+	}
+}
+
+// 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 = Ptr{Elem: elem}
+		}
+
+	case TARRAY:
+		elem := SubstAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra.(*Array).Elem = elem
+		}
+
+	case TSLICE:
+		elem := SubstAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra = Slice{Elem: elem}
+		}
+
+	case TCHAN:
+		elem := SubstAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra.(*Chan).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.(*Map).Key = key
+			t.Extra.(*Map).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() {
+			t = t.Copy()
+			t.FuncType().Receiver = recvs
+			t.FuncType().Results = results
+			t.FuncType().Params = 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.(*Map)
+		nt.Extra = &x
+	case TFORW:
+		x := *t.Extra.(*Forward)
+		nt.Extra = &x
+	case TFUNC:
+		x := *t.Extra.(*Func)
+		nt.Extra = &x
+	case TSTRUCT:
+		x := *t.Extra.(*Struct)
+		nt.Extra = &x
+	case TINTER:
+		x := *t.Extra.(*Interface)
+		nt.Extra = &x
+	case TCHAN:
+		x := *t.Extra.(*Chan)
+		nt.Extra = &x
+	case TARRAY:
+		x := *t.Extra.(*Array)
+		nt.Extra = &x
+	case TTUPLE, TSSA:
+		Fatalf("ssa types cannot be copied")
+	}
+	// 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
+}
+
+func (t *Type) wantEtype(et EType) {
+	if t.Etype != et {
+		Fatalf("want %v, but have %v", et, t)
+	}
+}
+
+func (t *Type) Recvs() *Type   { return t.FuncType().Receiver }
+func (t *Type) Params() *Type  { return t.FuncType().Params }
+func (t *Type) Results() *Type { return t.FuncType().Results }
+
+// 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.(*Map).Key
+}
+
+// Val returns the value type of map type t.
+func (t *Type) Val() *Type {
+	t.wantEtype(TMAP)
+	return t.Extra.(*Map).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.(Ptr).Elem
+	case TARRAY:
+		return t.Extra.(*Array).Elem
+	case TSLICE:
+		return t.Extra.(Slice).Elem
+	case TCHAN:
+		return t.Extra.(*Chan).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.(DDDField).T
+}
+
+// ChanArgs returns the channel type for TCHANARGS type t.
+func (t *Type) ChanArgs() *Type {
+	t.wantEtype(TCHANARGS)
+	return t.Extra.(ChanArgs).T
+}
+
+// FuncArgs returns the channel type for TFUNCARGS type t.
+func (t *Type) FuncArgs() *Type {
+	t.wantEtype(TFUNCARGS)
+	return t.Extra.(FuncArgs).T
+}
+
+// Nname returns the associated function's nname.
+func (t *Type) Nname() *Node {
+	switch t.Etype {
+	case TFUNC:
+		return t.Extra.(*Func).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.(*Func).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.(*Struct).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.(*Struct).fields
+	case TINTER:
+		Dowidth(t)
+		return &t.Extra.(*Interface).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) {
+	// If we've calculated the width of t before,
+	// then some other type such as a function signature
+	// might now have the wrong type.
+	// Rather than try to track and invalidate those,
+	// enforce that SetFields cannot be called once
+	// t's width has been calculated.
+	if t.WidthCalculated() {
+		Fatalf("SetFields of %v: width previously calculated", t)
+	}
+	t.wantEtype(TSTRUCT)
+	for _, f := range fields {
+		// If type T contains a field F with a go:notinheap
+		// type, then T must also be go:notinheap. Otherwise,
+		// you could heap allocate T and then get a pointer F,
+		// which would be a heap pointer to a go:notinheap
+		// type.
+		if f.Type != nil && f.Type.NotInHeap() {
+			t.SetNotInHeap(true)
+			break
+		}
+	}
+	t.Fields().Set(fields)
+}
+
+func (t *Type) SetInterface(methods []*Field) {
+	t.wantEtype(TINTER)
+	t.Methods().Set(methods)
+}
+
+func (t *Type) IsDDDArray() bool {
+	if t.Etype != TARRAY {
+		return false
+	}
+	return t.Extra.(*Array).Bound < 0
+}
+
+func (t *Type) WidthCalculated() bool {
+	return t.Align > 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.(*Func).Argwid
+}
+
+func (t *Type) Size() int64 {
+	if t.Etype == TSSA {
+		if t == TypeInt128 {
+			return 16
+		}
+		return 0
+	}
+	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()
+}
+
+// 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)
+)
+
+// Compare compares types for purposes of the SSA back
+// end, returning a 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(x *Type) Cmp {
+	if x == t {
+		return CMPeq
+	}
+	return t.cmp(x)
+}
+
+func cmpForNe(x bool) Cmp {
+	if x {
+		return CMPlt
+	}
+	return CMPgt
+}
+
+func (r *Sym) cmpsym(s *Sym) Cmp {
+	if r == s {
+		return CMPeq
+	}
+	if r == nil {
+		return CMPlt
+	}
+	if s == nil {
+		return 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 CMPeq
+}
+
+// cmp compares two *Types t and x, returning CMPlt,
+// CMPeq, CMPgt as t<x, t==x, t>x, for an arbitrary
+// and optimizer-centric notion of comparison.
+// TODO(josharian): make this safe for recursive interface types
+// and use in signatlist sorting. See issue 19869.
+func (t *Type) cmp(x *Type) 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 CMPeq
+	}
+	if t == nil {
+		return CMPlt
+	}
+	if x == nil {
+		return 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 CMPeq
+			}
+
+		case TINT32:
+			if (t == Types[Runetype.Etype] || t == Runetype) && (x == Types[Runetype.Etype] || x == Runetype) {
+				return CMPeq
+			}
+		}
+	}
+
+	if c := t.Sym.cmpsym(x.Sym); c != 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 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 CMPeq
+
+	case TSSA:
+		tname := t.Extra.(string)
+		xname := t.Extra.(string)
+		// desire fast sorting, not pretty sorting.
+		if len(tname) == len(xname) {
+			if tname == xname {
+				return CMPeq
+			}
+			if tname < xname {
+				return CMPlt
+			}
+			return CMPgt
+		}
+		if len(tname) > len(xname) {
+			return CMPgt
+		}
+		return CMPlt
+
+	case TTUPLE:
+		xtup := x.Extra.(*Tuple)
+		ttup := t.Extra.(*Tuple)
+		if c := ttup.first.Compare(xtup.first); c != CMPeq {
+			return c
+		}
+		return ttup.second.Compare(xtup.second)
+
+	case TMAP:
+		if c := t.Key().cmp(x.Key()); c != 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 CMPlt // nil < non-nil
+			}
+			// to the fallthrough
+		} else if x.StructType().Map == nil {
+			return 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 CMPlt // bucket maps are least
+			}
+			return t.StructType().Map.cmp(x.StructType().Map)
+		} else if x.StructType().Map.MapType().Bucket == x {
+			return CMPgt // bucket maps are least
+		} // If t != t.Map.Bucket, fall through to general case
+
+		tfs := t.FieldSlice()
+		xfs := x.FieldSlice()
+		for i := 0; i < len(tfs) && i < len(xfs); i++ {
+			t1, x1 := tfs[i], xfs[i]
+			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 != CMPeq {
+				return c
+			}
+			if c := t1.Type.cmp(x1.Type); c != CMPeq {
+				return c
+			}
+		}
+		if len(tfs) != len(xfs) {
+			return cmpForNe(len(tfs) < len(xfs))
+		}
+		return CMPeq
+
+	case TINTER:
+		tfs := t.FieldSlice()
+		xfs := x.FieldSlice()
+		for i := 0; i < len(tfs) && i < len(xfs); i++ {
+			t1, x1 := tfs[i], xfs[i]
+			if c := t1.Sym.cmpsym(x1.Sym); c != CMPeq {
+				return c
+			}
+			if c := t1.Type.cmp(x1.Type); c != CMPeq {
+				return c
+			}
+		}
+		if len(tfs) != len(xfs) {
+			return cmpForNe(len(tfs) < len(xfs))
+		}
+		return CMPeq
+
+	case TFUNC:
+		for _, f := range RecvsParamsResults {
+			// Loop over fields in structs, ignoring argument names.
+			tfs := f(t).FieldSlice()
+			xfs := f(x).FieldSlice()
+			for i := 0; i < len(tfs) && i < len(xfs); i++ {
+				ta := tfs[i]
+				tb := xfs[i]
+				if ta.Isddd() != tb.Isddd() {
+					return cmpForNe(!ta.Isddd())
+				}
+				if c := ta.Type.cmp(tb.Type); c != CMPeq {
+					return c
+				}
+			}
+			if len(tfs) != len(xfs) {
+				return cmpForNe(len(tfs) < len(xfs))
+			}
+		}
+		return 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 %v with %v", 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
+}
+
+var unsignedEType = [...]EType{
+	TINT8:    TUINT8,
+	TUINT8:   TUINT8,
+	TINT16:   TUINT16,
+	TUINT16:  TUINT16,
+	TINT32:   TUINT32,
+	TUINT32:  TUINT32,
+	TINT64:   TUINT64,
+	TUINT64:  TUINT64,
+	TINT:     TUINT,
+	TUINT:    TUINT,
+	TUINTPTR: TUINTPTR,
+}
+
+// ToUnsigned returns the unsigned equivalent of integer type t.
+func (t *Type) ToUnsigned() *Type {
+	if !t.IsInteger() {
+		Fatalf("unsignedType(%v)", t)
+	}
+	return Types[unsignedEType[t.Etype]]
+}
+
+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() *Type {
+	// TODO(josharian): If Type ever moves to a shared
+	// internal package, remove this silly wrapper.
+	return t.Elem()
+}
+func (t *Type) PtrTo() *Type {
+	return NewPtr(t)
+}
+
+func (t *Type) NumFields() int {
+	return t.Fields().Len()
+}
+func (t *Type) FieldType(i int) *Type {
+	if t.Etype == TTUPLE {
+		switch i {
+		case 0:
+			return t.Extra.(*Tuple).first
+		case 1:
+			return t.Extra.(*Tuple).second
+		default:
+			panic("bad tuple index")
+		}
+	}
+	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.(*Array)
+	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 NewDDDArray.
+// For other uses, create a new array with NewArray instead.
+func (t *Type) SetNumElem(n int64) {
+	t.wantEtype(TARRAY)
+	at := t.Extra.(*Array)
+	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.(*Chan).Dir
+}
+
+func (t *Type) IsMemory() bool {
+	return t == TypeMem || t.Etype == TTUPLE && t.Extra.(*Tuple).second == TypeMem
+}
+func (t *Type) IsFlags() bool { return t == TypeFlags }
+func (t *Type) IsVoid() bool  { return t == TypeVoid }
+func (t *Type) IsTuple() bool { return t.Etype == TTUPLE }
+
+// 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
+}
+
+func Haspointers(t *Type) bool {
+	switch t.Etype {
+	case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
+		TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL:
+		return false
+
+	case TARRAY:
+		if t.NumElem() == 0 { // empty array has no pointers
+			return false
+		}
+		return Haspointers(t.Elem())
+
+	case TSTRUCT:
+		for _, t1 := range t.Fields().Slice() {
+			if Haspointers(t1.Type) {
+				return true
+			}
+		}
+		return false
+	}
+
+	return true
+}
+
+// HasPointer returns whether t contains heap pointer.
+// This is used for write barrier insertion, so we ignore
+// pointers to go:notinheap types.
+func (t *Type) HasPointer() bool {
+	if t.IsPtr() && t.Elem().NotInHeap() {
+		return false
+	}
+	return Haspointers(t)
+}
+
+func (t *Type) Symbol() *obj.LSym {
+	return TypeLinkSym(t)
+}
+
+// Tie 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 (t *Type) Tie() byte {
+	if t.IsEmptyInterface() {
+		return 'E'
+	}
+	if t.IsInterface() {
+		return 'I'
+	}
+	return 'T'
+}
+
+var recvType *Type
+
+// FakeRecvType returns the singleton type used for interface method receivers.
+func FakeRecvType() *Type {
+	if recvType == nil {
+		recvType = NewPtr(New(TSTRUCT))
+	}
+	return recvType
+}
+
+var (
+	TypeInvalid *Type = newSSA("invalid")
+	TypeMem     *Type = newSSA("mem")
+	TypeFlags   *Type = newSSA("flags")
+	TypeVoid    *Type = newSSA("void")
+	TypeInt128  *Type = newSSA("int128")
+)
diff --git a/src/cmd/compile/internal/types/utils.go b/src/cmd/compile/internal/types/utils.go
new file mode 100644
index 0000000..796cd44
--- /dev/null
+++ b/src/cmd/compile/internal/types/utils.go
@@ -0,0 +1,126 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+const BADWIDTH = -1000000000
+
+// Initialized by frontend. Exists only here.
+var Tptr EType // either TPTR32 or TPTR64
+
+// The following variables must be initialized early by the frontend.
+// They are here to break import cycles.
+// TODO(gri) eliminate these dependencies.
+var (
+	Widthptr    int
+	Dowidth     func(*Type)
+	Fatalf      func(string, ...interface{})
+	Sconv       func(*Sym, int, int) string       // orig: func sconv(s *Sym, flag FmtFlag, mode fmtMode) string
+	Tconv       func(*Type, int, int, int) string // orig: func tconv(t *Type, flag FmtFlag, mode fmtMode, depth int) string
+	FormatSym   func(*Sym, fmt.State, rune, int)  // orig: func symFormat(sym *Sym, s fmt.State, verb rune, mode fmtMode)
+	FormatType  func(*Type, fmt.State, rune, int) // orig: func typeFormat(t *Type, s fmt.State, verb rune, mode fmtMode)
+	TypeLinkSym func(*Type) *obj.LSym
+	Ctxt        *obj.Link
+
+	FmtLeft     int
+	FmtUnsigned int
+	FErr        int
+)
+
+func (s *Sym) String() string {
+	return Sconv(s, 0, FErr)
+}
+
+func (sym *Sym) Format(s fmt.State, verb rune) {
+	FormatSym(sym, s, verb, FErr)
+}
+
+func (t *Type) String() string {
+	// This is an external entry point, so we pass depth 0 to tconv.
+	// The implementation of tconv (including typefmt and fldconv)
+	// must take care not to use a type in a formatting string
+	// to avoid resetting the recursion counter.
+	return Tconv(t, 0, FErr, 0)
+}
+
+// ShortString generates a short description of t.
+// It is used in autogenerated method names, reflection,
+// and itab names.
+func (t *Type) ShortString() string {
+	return Tconv(t, FmtLeft, FErr, 0)
+}
+
+// LongString generates a complete description of t.
+// It is useful for reflection,
+// or when a unique fingerprint or hash of a type is required.
+func (t *Type) LongString() string {
+	return Tconv(t, FmtLeft|FmtUnsigned, FErr, 0)
+}
+
+func (t *Type) Format(s fmt.State, verb rune) {
+	FormatType(t, s, verb, FErr)
+}
+
+type bitset8 uint8
+
+func (f *bitset8) set(mask uint8, b bool) {
+	if b {
+		*(*uint8)(f) |= mask
+	} else {
+		*(*uint8)(f) &^= mask
+	}
+}
+
+var etnames = []string{
+	Txxx:        "Txxx",
+	TINT:        "INT",
+	TUINT:       "UINT",
+	TINT8:       "INT8",
+	TUINT8:      "UINT8",
+	TINT16:      "INT16",
+	TUINT16:     "UINT16",
+	TINT32:      "INT32",
+	TUINT32:     "UINT32",
+	TINT64:      "INT64",
+	TUINT64:     "UINT64",
+	TUINTPTR:    "UINTPTR",
+	TFLOAT32:    "FLOAT32",
+	TFLOAT64:    "FLOAT64",
+	TCOMPLEX64:  "COMPLEX64",
+	TCOMPLEX128: "COMPLEX128",
+	TBOOL:       "BOOL",
+	TPTR32:      "PTR32",
+	TPTR64:      "PTR64",
+	TFUNC:       "FUNC",
+	TARRAY:      "ARRAY",
+	TSLICE:      "SLICE",
+	TSTRUCT:     "STRUCT",
+	TCHAN:       "CHAN",
+	TMAP:        "MAP",
+	TINTER:      "INTER",
+	TFORW:       "FORW",
+	TSTRING:     "STRING",
+	TUNSAFEPTR:  "TUNSAFEPTR",
+	TANY:        "ANY",
+	TIDEAL:      "TIDEAL",
+	TNIL:        "TNIL",
+	TBLANK:      "TBLANK",
+	TFUNCARGS:   "TFUNCARGS",
+	TCHANARGS:   "TCHANARGS",
+	TDDDFIELD:   "TDDDFIELD",
+	TSSA:        "TSSA",
+	TTUPLE:      "TTUPLE",
+}
+
+func (et EType) String() string {
+	if int(et) < len(etnames) && etnames[et] != "" {
+		return etnames[et]
+	}
+	return fmt.Sprintf("E-%d", et)
+}
diff --git a/src/cmd/compile/internal/x86/387.go b/src/cmd/compile/internal/x86/387.go
index 248fec6..5bf1410 100644
--- a/src/cmd/compile/internal/x86/387.go
+++ b/src/cmd/compile/internal/x86/387.go
@@ -7,14 +7,14 @@ package x86
 import (
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"math"
 )
 
-// Generates code for v using 387 instructions.  Reports whether
-// the instruction was handled by this routine.
-func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
+// Generates code for v using 387 instructions.
+func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
 	// The SSA compiler pretends that it has an SSE backend.
 	// If we don't have one of those, we need to translate
 	// all the SSE ops to equivalent 387 ops. That's what this
@@ -22,24 +22,23 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 
 	switch v.Op {
 	case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
-		p := gc.Prog(loadPush(v.Type))
+		p := s.Prog(loadPush(v.Type))
 		p.From.Type = obj.TYPE_FCONST
 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		popAndSave(s, v)
-		return true
+
 	case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
-		p := gc.Prog(loadPush(v.Type))
+		p := s.Prog(loadPush(v.Type))
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1, ssa.Op386MOVSSloadidx4, ssa.Op386MOVSDloadidx8:
-		p := gc.Prog(loadPush(v.Type))
+		p := s.Prog(loadPush(v.Type))
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -57,7 +56,6 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore:
 		// Push to-be-stored value on top of stack.
@@ -71,13 +69,12 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		case ssa.Op386MOVSDstore:
 			op = x86.AFMOVDP
 		}
-		p := gc.Prog(op)
+		p := s.Prog(op)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
-		return true
 
 	case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVSDstoreidx8:
 		push(s, v.Args[2])
@@ -88,7 +85,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		case ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSDstoreidx8:
 			op = x86.AFMOVDP
 		}
-		p := gc.Prog(op)
+		p := s.Prog(op)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_MEM
@@ -105,7 +102,6 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 			p.To.Scale = 8
 			p.To.Index = v.Args[1].Reg()
 		}
-		return true
 
 	case ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
 		ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD:
@@ -119,12 +115,12 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		// Set precision if needed.  64 bits is the default.
 		switch v.Op {
 		case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
-			p := gc.Prog(x86.AFSTCW)
+			p := s.Prog(x86.AFSTCW)
 			s.AddrScratch(&p.To)
-			p = gc.Prog(x86.AFLDCW)
+			p = s.Prog(x86.AFLDCW)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Name = obj.NAME_EXTERN
-			p.From.Sym = gc.Linksym(gc.Pkglookup("controlWord32", gc.Runtimepkg))
+			p.From.Sym = gc.Sysfunc("controlWord32")
 		}
 
 		var op obj.As
@@ -138,7 +134,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		case ssa.Op386DIVSS, ssa.Op386DIVSD:
 			op = x86.AFDIVDP
 		}
-		p := gc.Prog(op)
+		p := s.Prog(op)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_REG
@@ -147,134 +143,125 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		// Restore precision if needed.
 		switch v.Op {
 		case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
-			p := gc.Prog(x86.AFLDCW)
+			p := s.Prog(x86.AFLDCW)
 			s.AddrScratch(&p.From)
 		}
 
-		return true
-
 	case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
 		push(s, v.Args[0])
 
 		// Compare.
-		p := gc.Prog(x86.AFUCOMP)
+		p := s.Prog(x86.AFUCOMP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = s.SSEto387[v.Args[1].Reg()] + 1
 
 		// Save AX.
-		p = gc.Prog(x86.AMOVL)
+		p = s.Prog(x86.AMOVL)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_AX
 		s.AddrScratch(&p.To)
 
 		// Move status word into AX.
-		p = gc.Prog(x86.AFSTSW)
+		p = s.Prog(x86.AFSTSW)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_AX
 
 		// Then move the flags we need to the integer flags.
-		gc.Prog(x86.ASAHF)
+		s.Prog(x86.ASAHF)
 
 		// Restore AX.
-		p = gc.Prog(x86.AMOVL)
+		p = s.Prog(x86.AMOVL)
 		s.AddrScratch(&p.From)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_AX
 
-		return true
-
 	case ssa.Op386SQRTSD:
 		push(s, v.Args[0])
-		gc.Prog(x86.AFSQRT)
+		s.Prog(x86.AFSQRT)
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386FCHS:
 		push(s, v.Args[0])
-		gc.Prog(x86.AFCHS)
+		s.Prog(x86.AFCHS)
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD:
-		p := gc.Prog(x86.AMOVL)
+		p := s.Prog(x86.AMOVL)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		s.AddrScratch(&p.To)
-		p = gc.Prog(x86.AFMOVL)
+		p = s.Prog(x86.AFMOVL)
 		s.AddrScratch(&p.From)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
 		push(s, v.Args[0])
 
 		// Save control word.
-		p := gc.Prog(x86.AFSTCW)
+		p := s.Prog(x86.AFSTCW)
 		s.AddrScratch(&p.To)
 		p.To.Offset += 4
 
 		// Load control word which truncates (rounds towards zero).
-		p = gc.Prog(x86.AFLDCW)
+		p = s.Prog(x86.AFLDCW)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Name = obj.NAME_EXTERN
-		p.From.Sym = gc.Linksym(gc.Pkglookup("controlWord64trunc", gc.Runtimepkg))
+		p.From.Sym = gc.Sysfunc("controlWord64trunc")
 
 		// Now do the conversion.
-		p = gc.Prog(x86.AFMOVLP)
+		p = s.Prog(x86.AFMOVLP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		s.AddrScratch(&p.To)
-		p = gc.Prog(x86.AMOVL)
+		p = s.Prog(x86.AMOVL)
 		s.AddrScratch(&p.From)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 		// Restore control word.
-		p = gc.Prog(x86.AFLDCW)
+		p = s.Prog(x86.AFLDCW)
 		s.AddrScratch(&p.From)
 		p.From.Offset += 4
-		return true
 
 	case ssa.Op386CVTSS2SD:
 		// float32 -> float64 is a nop
 		push(s, v.Args[0])
 		popAndSave(s, v)
-		return true
 
 	case ssa.Op386CVTSD2SS:
 		// Round to nearest float32.
 		push(s, v.Args[0])
-		p := gc.Prog(x86.AFMOVFP)
+		p := s.Prog(x86.AFMOVFP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		s.AddrScratch(&p.To)
-		p = gc.Prog(x86.AFMOVF)
+		p = s.Prog(x86.AFMOVF)
 		s.AddrScratch(&p.From)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		popAndSave(s, v)
-		return true
 
 	case ssa.OpLoadReg:
 		if !v.Type.IsFloat() {
-			return false
+			ssaGenValue(s, v)
+			return
 		}
 		// Load+push the value we need.
-		p := gc.Prog(loadPush(v.Type))
+		p := s.Prog(loadPush(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = x86.REG_F0
 		// Move the value to its assigned register.
 		popAndSave(s, v)
-		return true
 
 	case ssa.OpStoreReg:
 		if !v.Type.IsFloat() {
-			return false
+			ssaGenValue(s, v)
+			return
 		}
 		push(s, v.Args[0])
 		var op obj.As
@@ -284,30 +271,30 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
 		case 8:
 			op = x86.AFMOVDP
 		}
-		p := gc.Prog(op)
+		p := s.Prog(op)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		gc.AddrAuto(&p.To, v)
-		return true
 
 	case ssa.OpCopy:
 		if !v.Type.IsFloat() {
-			return false
+			ssaGenValue(s, v)
+			return
 		}
 		push(s, v.Args[0])
 		popAndSave(s, v)
-		return true
 
-	case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLdefer, ssa.Op386CALLgo, ssa.Op386CALLinter:
-		flush387(s)  // Calls must empty the the FP stack.
-		return false // then issue the call as normal
+	case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
+		flush387(s) // Calls must empty the FP stack.
+		fallthrough // then issue the call as normal
+	default:
+		ssaGenValue(s, v)
 	}
-	return false
 }
 
 // push pushes v onto the floating-point stack.  v must be in a register.
 func push(s *gc.SSAGenState, v *ssa.Value) {
-	p := gc.Prog(x86.AFMOVD)
+	p := s.Prog(x86.AFMOVD)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = s.SSEto387[v.Reg()]
 	p.To.Type = obj.TYPE_REG
@@ -320,7 +307,7 @@ func popAndSave(s *gc.SSAGenState, v *ssa.Value) {
 	r := v.Reg()
 	if _, ok := s.SSEto387[r]; ok {
 		// Pop value, write to correct register.
-		p := gc.Prog(x86.AFMOVDP)
+		p := s.Prog(x86.AFMOVDP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_REG
@@ -337,7 +324,7 @@ func popAndSave(s *gc.SSAGenState, v *ssa.Value) {
 }
 
 // loadPush returns the opcode for load+push of the given type.
-func loadPush(t ssa.Type) obj.As {
+func loadPush(t *types.Type) obj.As {
 	if t.Size() == 4 {
 		return x86.AFMOVF
 	}
@@ -347,7 +334,7 @@ func loadPush(t ssa.Type) obj.As {
 // flush387 removes all entries from the 387 floating-point stack.
 func flush387(s *gc.SSAGenState) {
 	for k := range s.SSEto387 {
-		p := gc.Prog(x86.AFMOVDP)
+		p := s.Prog(x86.AFMOVDP)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_F0
 		p.To.Type = obj.TYPE_REG
@@ -355,3 +342,10 @@ func flush387(s *gc.SSAGenState) {
 		delete(s.SSEto387, k)
 	}
 }
+
+func ssaGenBlock387(s *gc.SSAGenState, b, next *ssa.Block) {
+	// Empty the 387's FP stack before the block ends.
+	flush387(s)
+
+	ssaGenBlock(s, b, next)
+}
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index bb29d2a..56cc6c6 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -6,30 +6,32 @@ package x86
 
 import (
 	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
+	"cmd/internal/objabi"
 	"fmt"
 	"os"
 )
 
-func Init() {
-	gc.Thearch.LinkArch = &x86.Link386
-	gc.Thearch.REGSP = x86.REGSP
-	switch v := obj.GO386; v {
+func Init(arch *gc.Arch) {
+	arch.LinkArch = &x86.Link386
+	arch.REGSP = x86.REGSP
+	switch v := objabi.GO386; v {
 	case "387":
-		gc.Thearch.Use387 = true
+		arch.Use387 = true
+		arch.SSAGenValue = ssaGenValue387
+		arch.SSAGenBlock = ssaGenBlock387
 	case "sse2":
+		arch.SSAGenValue = ssaGenValue
+		arch.SSAGenBlock = ssaGenBlock
 	default:
 		fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
 		gc.Exit(1)
 	}
-	gc.Thearch.MAXWIDTH = (1 << 32) - 1
+	arch.MAXWIDTH = (1 << 32) - 1
 
-	gc.Thearch.Defframe = defframe
-	gc.Thearch.Proginfo = proginfo
+	arch.ZeroRange = zerorange
+	arch.ZeroAuto = zeroAuto
+	arch.Ginsnop = ginsnop
 
-	gc.Thearch.SSAMarkMoves = ssaMarkMoves
-	gc.Thearch.SSAGenValue = ssaGenValue
-	gc.Thearch.SSAGenBlock = ssaGenBlock
-	gc.Thearch.ZeroAuto = zeroAuto
+	arch.SSAMarkMoves = ssaMarkMoves
 }
diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
index 33ffc5f..ef380bd 100644
--- a/src/cmd/compile/internal/x86/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -10,87 +10,39 @@ import (
 	"cmd/internal/obj/x86"
 )
 
-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
-	ax := uint32(0)
-	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 %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
-		}
-		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) {
-			// merge with range we already have
-			lo = n.Xoffset
-
-			continue
-		}
-
-		// zero old range
-		p = zerorange(p, int64(frame), lo, hi, &ax)
-
-		// set new range
-		hi = n.Xoffset + n.Type.Width
-
-		lo = n.Xoffset
-	}
-
-	// zero final range
-	zerorange(p, int64(frame), lo, hi, &ax)
-}
-
-func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog {
-	cnt := hi - lo
+func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, ax *uint32) *obj.Prog {
 	if cnt == 0 {
 		return p
 	}
 	if *ax == 0 {
-		p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+		p = pp.Appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
 		*ax = 1
 	}
 
 	if cnt <= int64(4*gc.Widthreg) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthreg) {
-			p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
+			p = pp.Appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, off+i)
 		}
 	} else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) {
-		p = gc.Appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
-		p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg)))
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p = pp.Appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, off, obj.TYPE_REG, x86.REG_DI, 0)
+		p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg)))
+		p.To.Sym = gc.Duffzero
 	} else {
-		p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
-		p = gc.Appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
-		p = gc.Appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
-		p = gc.Appendpp(p, x86.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
+		p = pp.Appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, off, obj.TYPE_REG, x86.REG_DI, 0)
+		p = pp.Appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = pp.Appendpp(p, x86.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
 	}
 
 	return p
 }
 
-func zeroAuto(n *gc.Node, pp *obj.Prog) {
+func zeroAuto(pp *gc.Progs, n *gc.Node) {
 	// Note: this code must not clobber any registers.
-	sym := gc.Linksym(n.Sym)
+	sym := n.Sym.Linksym()
 	size := n.Type.Size()
 	for i := int64(0); i < size; i += 4 {
-		p := gc.AddAsmAfter(x86.AMOVL, pp)
-		pp = p
+		p := pp.Prog(x86.AMOVL)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 0
 		p.To.Type = obj.TYPE_MEM
@@ -101,8 +53,8 @@ func zeroAuto(n *gc.Node, pp *obj.Prog) {
 	}
 }
 
-func ginsnop() {
-	p := gc.Prog(x86.AXCHGL)
+func ginsnop(pp *gc.Progs) {
+	p := pp.Prog(x86.AXCHGL)
 	p.From.Type = obj.TYPE_REG
 	p.From.Reg = x86.REG_AX
 	p.To.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/x86/prog.go b/src/cmd/compile/internal/x86/prog.go
deleted file mode 100644
index e46bdb7..0000000
--- a/src/cmd/compile/internal/x86/prog.go
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package x86
-
-import (
-	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
-	"cmd/internal/obj/x86"
-)
-
-const (
-	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
-	RightRdwr uint32 = gc.RightRead | gc.RightWrite
-)
-
-// This table gives the basic information about instruction
-// generated by the compiler and processed in the optimizer.
-// See opt.h for bit definitions.
-//
-// Instructions not generated need not be listed.
-// As an exception to that rule, we typically write down all the
-// size variants of an operation even if we just use a subset.
-//
-// The table is formatted for 8-space tabs.
-var progtable = [x86.ALAST & obj.AMask]gc.ProgInfo{
-	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
-	obj.ATEXT:     {Flags: gc.Pseudo},
-	obj.AFUNCDATA: {Flags: gc.Pseudo},
-	obj.APCDATA:   {Flags: gc.Pseudo},
-	obj.AUNDEF:    {Flags: gc.Break},
-	obj.AUSEFIELD: {Flags: gc.OK},
-	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
-	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
-
-	// 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 & 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},
-	x86.ACWD & obj.AMask:       {Flags: gc.OK},
-	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},
-	x86.ADIVL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.ADIVW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	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&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 & 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 & 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},
-	x86.AIDIVL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.AIDIVW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	x86.AIMULB & obj.AMask:   {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry},
-	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},
-	x86.AMOVSL & obj.AMask:   {Flags: gc.OK},
-	x86.AMOVSW & obj.AMask:   {Flags: gc.OK},
-	obj.ADUFFCOPY:            {Flags: gc.OK},
-	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 & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMULB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry},
-	x86.AMULL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry},
-	x86.AMULW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry},
-	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},
-	x86.AREPN & obj.AMask:    {Flags: gc.OK},
-	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},
-	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},
-	x86.ASTOSL & obj.AMask:   {Flags: gc.OK},
-	x86.ASTOSW & obj.AMask:   {Flags: gc.OK},
-	obj.ADUFFZERO:            {Flags: gc.OK},
-	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) gc.ProgInfo {
-	info := progtable[p.As&obj.AMask]
-	if info.Flags == 0 {
-		gc.Fatalf("unknown instruction %v", p)
-	}
-
-	if info.Flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
-		info.Flags |= RightRdwr
-	}
-
-	return info
-}
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index 21be634..54a76bd 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -10,6 +10,7 @@ import (
 
 	"cmd/compile/internal/gc"
 	"cmd/compile/internal/ssa"
+	"cmd/compile/internal/types"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -38,7 +39,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
 }
 
 // loadByType returns the load instruction of the given type.
-func loadByType(t ssa.Type) obj.As {
+func loadByType(t *types.Type) obj.As {
 	// Avoid partial register write
 	if !t.IsFloat() && t.Size() <= 2 {
 		if t.Size() == 1 {
@@ -52,7 +53,7 @@ func loadByType(t ssa.Type) obj.As {
 }
 
 // storeByType returns the store instruction of the given type.
-func storeByType(t ssa.Type) obj.As {
+func storeByType(t *types.Type) obj.As {
 	width := t.Size()
 	if t.IsFloat() {
 		switch width {
@@ -75,7 +76,7 @@ func storeByType(t ssa.Type) obj.As {
 }
 
 // moveByType returns the reg->reg move instruction of the given type.
-func moveByType(t ssa.Type) obj.As {
+func moveByType(t *types.Type) obj.As {
 	if t.IsFloat() {
 		switch t.Size() {
 		case 4:
@@ -104,8 +105,8 @@ func moveByType(t ssa.Type) obj.As {
 //     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)
+func opregreg(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog {
+	p := s.Prog(op)
 	p.From.Type = obj.TYPE_REG
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = dest
@@ -114,14 +115,6 @@ func opregreg(op obj.As, dest, src int16) *obj.Prog {
 }
 
 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
-	s.SetLineno(v.Line)
-
-	if gc.Thearch.Use387 {
-		if ssaGenValue387(s, v) {
-			return // v was handled by 387 generation.
-		}
-	}
-
 	switch v.Op {
 	case ssa.Op386ADDL:
 		r := v.Reg()
@@ -129,19 +122,19 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		r2 := v.Args[1].Reg()
 		switch {
 		case r == r1:
-			p := gc.Prog(v.Op.Asm())
+			p := s.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 := s.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:
-			p := gc.Prog(x86.ALEAL)
+			p := s.Prog(x86.ALEAL)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = r1
 			p.From.Scale = 1
@@ -168,7 +161,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		opregreg(v.Op.Asm(), r, v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
 
 	case ssa.Op386ADDLcarry, ssa.Op386SUBLcarry:
 		// output 0 is carry/borrow, output 1 is the low 32 bits.
@@ -176,7 +169,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
 		}
-		opregreg(v.Op.Asm(), r, v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
 
 	case ssa.Op386ADDLconstcarry, ssa.Op386SUBLconstcarry:
 		// output 0 is carry/borrow, output 1 is the low 32 bits.
@@ -184,7 +177,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -208,14 +201,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			var c *obj.Prog
 			switch v.Op {
 			case ssa.Op386DIVL, ssa.Op386MODL:
-				c = gc.Prog(x86.ACMPL)
-				j = gc.Prog(x86.AJEQ)
-				gc.Prog(x86.ACDQ) //TODO: fix
+				c = s.Prog(x86.ACMPL)
+				j = s.Prog(x86.AJEQ)
+				s.Prog(x86.ACDQ) //TODO: fix
 
 			case ssa.Op386DIVW, ssa.Op386MODW:
-				c = gc.Prog(x86.ACMPW)
-				j = gc.Prog(x86.AJEQ)
-				gc.Prog(x86.ACWD)
+				c = s.Prog(x86.ACMPW)
+				j = s.Prog(x86.AJEQ)
+				s.Prog(x86.ACWD)
 			}
 			c.From.Type = obj.TYPE_REG
 			c.From.Reg = x
@@ -229,31 +222,31 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// signed ints were sign extended above
 		if v.Op == ssa.Op386DIVLU || v.Op == ssa.Op386MODLU ||
 			v.Op == ssa.Op386DIVWU || v.Op == ssa.Op386MODWU {
-			c := gc.Prog(x86.AXORL)
+			c := s.Prog(x86.AXORL)
 			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 := s.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 := s.Prog(obj.AJMP)
 			j2.To.Type = obj.TYPE_BRANCH
 
 			var n *obj.Prog
 			if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW {
 				// n * -1 = -n
-				n = gc.Prog(x86.ANEGL)
+				n = s.Prog(x86.ANEGL)
 				n.To.Type = obj.TYPE_REG
 				n.To.Reg = x86.REG_AX
 			} else {
 				// n % -1 == 0
-				n = gc.Prog(x86.AXORL)
+				n = s.Prog(x86.AXORL)
 				n.From.Type = obj.TYPE_REG
 				n.From.Reg = x86.REG_DX
 				n.To.Type = obj.TYPE_REG
@@ -264,22 +257,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			j2.To.Val = s.Pc()
 		}
 
-	case ssa.Op386HMULL, ssa.Op386HMULW, ssa.Op386HMULB,
-		ssa.Op386HMULLU, ssa.Op386HMULWU, ssa.Op386HMULBU:
+	case ssa.Op386HMULL, ssa.Op386HMULLU:
 		// 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 := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 
 		// 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 := s.Prog(x86.AMOVB)
 			m.From.Type = obj.TYPE_REG
 			m.From.Reg = x86.REG_AH
 			m.To.Type = obj.TYPE_REG
@@ -288,34 +280,53 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 
 	case ssa.Op386MULLQU:
 		// AX * args[1], high 32 bits in DX (result[0]), low 32 bits in AX (result[1]).
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 
+	case ssa.Op386AVGLU:
+		// compute (x+y)/2 unsigned.
+		// Do a 32-bit add, the overflow goes into the carry.
+		// Shift right once and pull the carry back into the 31st bit.
+		r := v.Reg()
+		if r != v.Args[0].Reg() {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		p := s.Prog(x86.AADDL)
+		p.From.Type = obj.TYPE_REG
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+		p.From.Reg = v.Args[1].Reg()
+		p = s.Prog(x86.ARCRL)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 1
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+
 	case ssa.Op386ADDLconst:
 		r := v.Reg()
 		a := v.Args[0].Reg()
 		if r == a {
 			if v.AuxInt == 1 {
-				p := gc.Prog(x86.AINCL)
+				p := s.Prog(x86.AINCL)
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = r
 				return
 			}
 			if v.AuxInt == -1 {
-				p := gc.Prog(x86.ADECL)
+				p := s.Prog(x86.ADECL)
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = r
 				return
 			}
-			p := gc.Prog(v.Op.Asm())
+			p := s.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
 		}
-		p := gc.Prog(x86.ALEAL)
+		p := s.Prog(x86.ALEAL)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = a
 		p.From.Offset = v.AuxInt
@@ -327,7 +338,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -352,14 +363,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.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.Op386SBBLcarrymask:
 		r := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = r
 		p.To.Type = obj.TYPE_REG
@@ -367,7 +378,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 	case ssa.Op386LEAL1, ssa.Op386LEAL2, ssa.Op386LEAL4, ssa.Op386LEAL8:
 		r := v.Args[0].Reg()
 		i := v.Args[1].Reg()
-		p := gc.Prog(x86.ALEAL)
+		p := s.Prog(x86.ALEAL)
 		switch v.Op {
 		case ssa.Op386LEAL1:
 			p.From.Scale = 1
@@ -388,7 +399,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386LEAL:
-		p := gc.Prog(x86.ALEAL)
+		p := s.Prog(x86.ALEAL)
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -396,26 +407,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Reg()
 	case ssa.Op386CMPL, ssa.Op386CMPW, ssa.Op386CMPB,
 		ssa.Op386TESTL, ssa.Op386TESTW, ssa.Op386TESTB:
-		opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
 	case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
 		// Go assembler has swapped operands for UCOMISx relative to CMP,
 		// must account for that right here.
-		opregreg(v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg())
+		opregreg(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg())
 	case ssa.Op386CMPLconst, ssa.Op386CMPWconst, ssa.Op386CMPBconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = v.AuxInt
 	case ssa.Op386TESTLconst, ssa.Op386TESTWconst, ssa.Op386TESTBconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Args[0].Reg()
 	case ssa.Op386MOVLconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = v.AuxInt
 		p.To.Type = obj.TYPE_REG
@@ -427,41 +438,39 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		}
 	case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
 		x := v.Reg()
-		p := gc.Prog(v.Op.Asm())
+		p := s.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.Op386MOVSSconst1, ssa.Op386MOVSDconst1:
-		var literal string
+		p := s.Prog(x86.ALEAL)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Name = obj.NAME_EXTERN
+		f := math.Float64frombits(uint64(v.AuxInt))
 		if v.Op == ssa.Op386MOVSDconst1 {
-			literal = fmt.Sprintf("$f64.%016x", uint64(v.AuxInt))
+			p.From.Sym = gc.Ctxt.Float64Sym(f)
 		} else {
-			literal = fmt.Sprintf("$f32.%08x", math.Float32bits(float32(math.Float64frombits(uint64(v.AuxInt)))))
+			p.From.Sym = gc.Ctxt.Float32Sym(float32(f))
 		}
-		p := gc.Prog(x86.ALEAL)
-		p.From.Type = obj.TYPE_MEM
-		p.From.Name = obj.NAME_EXTERN
-		p.From.Sym = obj.Linklookup(gc.Ctxt, literal, 0)
-		p.From.Sym.Set(obj.AttrLocal, true)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 	case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVLload, ssa.Op386MOVWload, ssa.Op386MOVBload, ssa.Op386MOVBLSXload, ssa.Op386MOVWLSXload:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386MOVSDloadidx8:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -470,7 +479,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -479,7 +488,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386MOVWloadidx2:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.From, v)
@@ -493,7 +502,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == x86.REG_SP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = r
 		p.From.Scale = 1
@@ -502,14 +511,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 	case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore, ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[1].Reg()
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.Op386MOVSDstoreidx8:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -518,7 +527,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = v.Args[1].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -527,7 +536,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = v.Args[1].Reg()
 		gc.AddAux(&p.To, v)
 	case ssa.Op386MOVWstoreidx2:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -541,7 +550,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if i == x86.REG_SP {
 			r, i = i, r
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[2].Reg()
 		p.To.Type = obj.TYPE_MEM
@@ -550,7 +559,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Index = i
 		gc.AddAux(&p.To, v)
 	case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -558,7 +567,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		p.To.Reg = v.Args[0].Reg()
 		gc.AddAux2(&p.To, v, sc.Off())
 	case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_CONST
 		sc := v.AuxValAndOff()
 		p.From.Offset = sc.Val()
@@ -583,16 +592,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD,
 		ssa.Op386CVTTSS2SL, ssa.Op386CVTTSD2SL,
 		ssa.Op386CVTSS2SD, ssa.Op386CVTSD2SS:
-		opregreg(v.Op.Asm(), v.Reg(), v.Args[0].Reg())
+		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
 	case ssa.Op386DUFFZERO:
-		p := gc.Prog(obj.ADUFFZERO)
+		p := s.Prog(obj.ADUFFZERO)
 		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Sym = gc.Duffzero
 		p.To.Offset = v.AuxInt
 	case ssa.Op386DUFFCOPY:
-		p := gc.Prog(obj.ADUFFCOPY)
+		p := s.Prog(obj.ADUFFCOPY)
 		p.To.Type = obj.TYPE_ADDR
-		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+		p.To.Sym = gc.Duffcopy
 		p.To.Offset = v.AuxInt
 
 	case ssa.OpCopy, ssa.Op386MOVLconvert: // TODO: use MOVLreg for reg->reg copies instead of OpCopy?
@@ -602,14 +611,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		x := v.Args[0].Reg()
 		y := v.Reg()
 		if x != y {
-			opregreg(moveByType(v.Type), y, x)
+			opregreg(s, moveByType(v.Type), y, x)
 		}
 	case ssa.OpLoadReg:
 		if v.Type.IsFlags() {
 			v.Fatalf("load flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(loadByType(v.Type))
+		p := s.Prog(loadByType(v.Type))
 		gc.AddrAuto(&p.From, v.Args[0])
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
@@ -619,16 +628,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			v.Fatalf("store flags not implemented: %v", v.LongString())
 			return
 		}
-		p := gc.Prog(storeByType(v.Type))
+		p := s.Prog(storeByType(v.Type))
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		gc.AddrAuto(&p.To, v)
-	case ssa.OpPhi:
-		gc.CheckLoweredPhi(v)
-	case ssa.OpInitMem:
-		// memory arg needs no code
-	case ssa.OpArg:
-		// input args need no code
 	case ssa.Op386LoweredGetClosurePtr:
 		// Closure pointer is DX.
 		gc.CheckLoweredGetClosurePtr(v)
@@ -638,7 +641,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// near CanUse1InsnTLS for a detailed explanation of these instructions.
 		if x86.CanUse1InsnTLS(gc.Ctxt) {
 			// MOVL (TLS), r
-			p := gc.Prog(x86.AMOVL)
+			p := s.Prog(x86.AMOVL)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = x86.REG_TLS
 			p.To.Type = obj.TYPE_REG
@@ -646,12 +649,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		} else {
 			// MOVL TLS, r
 			// MOVL (r)(TLS*1), r
-			p := gc.Prog(x86.AMOVL)
+			p := s.Prog(x86.AMOVL)
 			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.AMOVL)
+			q := s.Prog(x86.AMOVL)
 			q.From.Type = obj.TYPE_MEM
 			q.From.Reg = r
 			q.From.Index = x86.REG_TLS
@@ -659,55 +662,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 			q.To.Type = obj.TYPE_REG
 			q.To.Reg = r
 		}
-	case ssa.Op386CALLstatic:
-		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.Op386CALLclosure:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
-	case ssa.Op386CALLdefer:
-		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.Op386CALLgo:
-		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.Op386CALLinter:
-		p := gc.Prog(obj.ACALL)
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = v.Args[0].Reg()
-		if gc.Maxarg < v.AuxInt {
-			gc.Maxarg = v.AuxInt
-		}
+	case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
+		s.Call(v)
 	case ssa.Op386NEGL,
 		ssa.Op386BSWAPL,
 		ssa.Op386NOTL:
@@ -715,19 +671,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		if r != v.Args[0].Reg() {
 			v.Fatalf("input[0] and output not in same register %s", v.LongString())
 		}
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = r
 	case ssa.Op386BSFL, ssa.Op386BSFW,
 		ssa.Op386BSRL, ssa.Op386BSRW,
 		ssa.Op386SQRTSD:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = v.Args[0].Reg()
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-	case ssa.OpSP, ssa.OpSB, ssa.OpSelect0, ssa.OpSelect1:
-		// nothing to do
 	case ssa.Op386SETEQ, ssa.Op386SETNE,
 		ssa.Op386SETL, ssa.Op386SETLE,
 		ssa.Op386SETG, ssa.Op386SETGE,
@@ -735,46 +689,38 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		ssa.Op386SETB, ssa.Op386SETBE,
 		ssa.Op386SETORD, ssa.Op386SETNAN,
 		ssa.Op386SETA, ssa.Op386SETAE:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
 
 	case ssa.Op386SETNEF:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		q := gc.Prog(x86.ASETPS)
+		q := s.Prog(x86.ASETPS)
 		q.To.Type = obj.TYPE_REG
 		q.To.Reg = x86.REG_AX
-		opregreg(x86.AORL, v.Reg(), x86.REG_AX)
+		opregreg(s, x86.AORL, v.Reg(), x86.REG_AX)
 
 	case ssa.Op386SETEQF:
-		p := gc.Prog(v.Op.Asm())
+		p := s.Prog(v.Op.Asm())
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = v.Reg()
-		q := gc.Prog(x86.ASETPC)
+		q := s.Prog(x86.ASETPC)
 		q.To.Type = obj.TYPE_REG
 		q.To.Reg = x86.REG_AX
-		opregreg(x86.AANDL, v.Reg(), x86.REG_AX)
+		opregreg(s, x86.AANDL, v.Reg(), x86.REG_AX)
 
 	case ssa.Op386InvertFlags:
 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
 	case ssa.Op386FlagEQ, ssa.Op386FlagLT_ULT, ssa.Op386FlagLT_UGT, ssa.Op386FlagGT_ULT, ssa.Op386FlagGT_UGT:
 		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
 	case ssa.Op386REPSTOSL:
-		gc.Prog(x86.AREP)
-		gc.Prog(x86.ASTOSL)
+		s.Prog(x86.AREP)
+		s.Prog(x86.ASTOSL)
 	case ssa.Op386REPMOVSL:
-		gc.Prog(x86.AREP)
-		gc.Prog(x86.AMOVSL)
-	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:
-		gc.KeepAlive(v)
+		s.Prog(x86.AREP)
+		s.Prog(x86.AMOVSL)
 	case ssa.Op386LoweredNilCheck:
 		// Issue a load which will fault if the input is nil.
 		// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
@@ -782,17 +728,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
 		// 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 := s.Prog(x86.ATESTB)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = x86.REG_AX
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = v.Args[0].Reg()
 		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")
+		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
+			gc.Warnl(v.Pos, "generated nil check")
 		}
 	case ssa.Op386FCHS:
 		v.Fatalf("FCHS in non-387 mode")
+	case ssa.OpClobber:
+		p := s.Prog(x86.AMOVL)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 0xdeaddead
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = x86.REG_SP
+		gc.AddAux(&p.To, v)
 	default:
 		v.Fatalf("genValue not implemented: %s", v.LongString())
 	}
@@ -825,17 +778,10 @@ var nefJumps = [2][2]gc.FloatingEQNEJump{
 }
 
 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
-	s.SetLineno(b.Line)
-
-	if gc.Thearch.Use387 {
-		// Empty the 387's FP stack before the block ends.
-		flush387(s)
-	}
-
 	switch b.Kind {
 	case ssa.BlockPlain:
 		if b.Succs[0].Block() != next {
-			p := gc.Prog(obj.AJMP)
+			p := s.Prog(obj.AJMP)
 			p.To.Type = obj.TYPE_BRANCH
 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
 		}
@@ -843,34 +789,34 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		// defer returns in rax:
 		// 0 if we should continue executing
 		// 1 if we should jump to deferreturn call
-		p := gc.Prog(x86.ATESTL)
+		p := s.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 = s.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 := s.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
+		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
 	case ssa.BlockRet:
-		gc.Prog(obj.ARET)
+		s.Prog(obj.ARET)
 	case ssa.BlockRetJmp:
-		p := gc.Prog(obj.AJMP)
+		p := s.Prog(obj.AJMP)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Name = obj.NAME_EXTERN
-		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+		p.To.Sym = b.Aux.(*obj.LSym)
 
 	case ssa.Block386EQF:
-		gc.SSAGenFPJump(s, b, next, &eqfJumps)
+		s.FPJump(b, next, &eqfJumps)
 
 	case ssa.Block386NEF:
-		gc.SSAGenFPJump(s, b, next, &nefJumps)
+		s.FPJump(b, next, &nefJumps)
 
 	case ssa.Block386EQ, ssa.Block386NE,
 		ssa.Block386LT, ssa.Block386GE,
@@ -878,40 +824,25 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
 		ssa.Block386ULT, ssa.Block386UGT,
 		ssa.Block386ULE, ssa.Block386UGE:
 		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 = s.Prog(jmp.invasm)
 			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 = s.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 = s.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 := s.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.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
 	}
diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go
index c3c0b6a..e699b91 100644
--- a/src/cmd/compile/main.go
+++ b/src/cmd/compile/main.go
@@ -14,39 +14,38 @@ import (
 	"cmd/compile/internal/ppc64"
 	"cmd/compile/internal/s390x"
 	"cmd/compile/internal/x86"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"log"
 	"os"
 )
 
+var archInits = map[string]func(*gc.Arch){
+	"386":      x86.Init,
+	"amd64":    amd64.Init,
+	"amd64p32": amd64.Init,
+	"arm":      arm.Init,
+	"arm64":    arm64.Init,
+	"mips":     mips.Init,
+	"mipsle":   mips.Init,
+	"mips64":   mips64.Init,
+	"mips64le": mips64.Init,
+	"ppc64":    ppc64.Init,
+	"ppc64le":  ppc64.Init,
+	"s390x":    s390x.Init,
+}
+
 func main() {
 	// disable timestamps for reproducible output
 	log.SetFlags(0)
 	log.SetPrefix("compile: ")
 
-	switch obj.GOARCH {
-	default:
-		fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.GOARCH)
+	archInit, ok := archInits[objabi.GOARCH]
+	if !ok {
+		fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", objabi.GOARCH)
 		os.Exit(2)
-	case "386":
-		x86.Init()
-	case "amd64", "amd64p32":
-		amd64.Init()
-	case "arm":
-		arm.Init()
-	case "arm64":
-		arm64.Init()
-	case "mips", "mipsle":
-		mips.Init()
-	case "mips64", "mips64le":
-		mips64.Init()
-	case "ppc64", "ppc64le":
-		ppc64.Init()
-	case "s390x":
-		s390x.Init()
 	}
 
-	gc.Main()
+	gc.Main(archInit)
 	gc.Exit(0)
 }
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
index 81ac8ae..1584a73 100644
--- a/src/cmd/cover/cover_test.go
+++ b/src/cmd/cover/cover_test.go
@@ -26,10 +26,11 @@ const (
 
 var (
 	// Files we use.
-	testMain    = filepath.Join(testdata, "main.go")
-	testTest    = filepath.Join(testdata, "test.go")
-	coverInput  = filepath.Join(testdata, "test_line.go")
-	coverOutput = filepath.Join(testdata, "test_cover.go")
+	testMain     = filepath.Join(testdata, "main.go")
+	testTest     = filepath.Join(testdata, "test.go")
+	coverInput   = filepath.Join(testdata, "test_line.go")
+	coverOutput  = filepath.Join(testdata, "test_cover.go")
+	coverProfile = filepath.Join(testdata, "profile.cov")
 )
 
 var debug = false // Keeps the rewritten files around if set.
@@ -102,6 +103,25 @@ func TestCover(t *testing.T) {
 	}
 }
 
+// Makes sure that `cover -func=profile.cov` reports accurate coverage.
+// Issue #20515.
+func TestCoverFunc(t *testing.T) {
+	// go tool cover -func ./testdata/profile.cov
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "cover", "-func", coverProfile)
+	out, err := cmd.Output()
+	if err != nil {
+		if ee, ok := err.(*exec.ExitError); ok {
+			t.Logf("%s", ee.Stderr)
+		}
+		t.Fatal(err)
+	}
+
+	if got, err := regexp.Match(".*total:.*100.0.*", out); err != nil || !got {
+		t.Logf("%s", out)
+		t.Errorf("invalid coverage counts. got=(%v, %v); want=(true; nil)", got, err)
+	}
+}
+
 func run(c *exec.Cmd, t *testing.T) {
 	c.Stdout = os.Stdout
 	c.Stderr = os.Stderr
diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go
index 66ec242..05c7c12 100644
--- a/src/cmd/cover/func.go
+++ b/src/cmd/cover/func.go
@@ -66,12 +66,12 @@ func funcOutput(profile, outputFile string) error {
 		// Now match up functions and profile blocks.
 		for _, f := range funcs {
 			c, t := f.coverage(profile)
-			fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
+			fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, percent(c, t))
 			total += t
 			covered += c
 		}
 	}
-	fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
+	fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", percent(covered, total))
 
 	return nil
 }
@@ -147,9 +147,6 @@ func (f *FuncExtent) coverage(profile *Profile) (num, den int64) {
 			covered += int64(b.NumStmt)
 		}
 	}
-	if total == 0 {
-		total = 1 // Avoid zero denominator.
-	}
 	return covered, total
 }
 
@@ -162,3 +159,10 @@ func findFile(file string) (string, error) {
 	}
 	return filepath.Join(pkg.Dir, file), nil
 }
+
+func percent(covered, total int64) float64 {
+	if total == 0 {
+		total = 1 // Avoid zero denominator.
+	}
+	return 100.0 * float64(covered) / float64(total)
+}
diff --git a/src/cmd/cover/testdata/p.go b/src/cmd/cover/testdata/p.go
new file mode 100644
index 0000000..ce3a8c0
--- /dev/null
+++ b/src/cmd/cover/testdata/p.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go 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 package such that there are 3 functions with zero total and covered lines.
+// And one with 1 total and covered lines. Reproduces issue #20515.
+package p
+
+//go:noinline
+func A() {
+
+}
+
+//go:noinline
+func B() {
+
+}
+
+//go:noinline
+func C() {
+
+}
+
+//go:noinline
+func D() int64 {
+	return 42
+}
diff --git a/src/cmd/cover/testdata/profile.cov b/src/cmd/cover/testdata/profile.cov
new file mode 100644
index 0000000..db08602
--- /dev/null
+++ b/src/cmd/cover/testdata/profile.cov
@@ -0,0 +1,5 @@
+mode: set
+./testdata/p.go:10.10,12.2 0 0
+./testdata/p.go:15.10,17.2 0 0
+./testdata/p.go:20.10,22.2 0 0
+./testdata/p.go:25.16,27.2 1 1
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 4d0b1a0..76e42a4 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -471,7 +471,7 @@ var deptab = []struct {
 	prefix string   // prefix of target
 	dep    []string // dependency tweaks for targets with that prefix
 }{
-	{"cmd/go", []string{
+	{"cmd/go/internal/cfg", []string{
 		"zdefaultcc.go",
 		"zosarch.go",
 	}},
@@ -543,7 +543,7 @@ func install(dir string) {
 	path := pathf("%s/src/%s", goroot, dir)
 	name := filepath.Base(dir)
 
-	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/")
+	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
 
 	// Start final link command line.
 	// Note: code below knows that link.p[targ] is the target.
@@ -782,9 +782,8 @@ func matchtag(tag string) bool {
 
 // shouldbuild reports whether we should build this file.
 // It applies the same rules that are used with context tags
-// in package go/build, except that the GOOS and GOARCH
-// can appear anywhere in the file name, not just after _.
-// In particular, they can be the entire file name (like windows.c).
+// in package go/build, except it's less picky about the order
+// of GOOS and GOARCH.
 // We also allow the special tag cmd_go_bootstrap.
 // See ../go/bootstrap.go and package go/build.
 func shouldbuild(file, dir string) bool {
@@ -792,11 +791,11 @@ func shouldbuild(file, dir string) bool {
 	name := filepath.Base(file)
 	excluded := func(list []string, ok string) bool {
 		for _, x := range list {
-			if x == ok {
+			if x == ok || ok == "android" && x == "linux" {
 				continue
 			}
 			i := strings.Index(name, x)
-			if i < 0 {
+			if i <= 0 || name[i-1] != '_' {
 				continue
 			}
 			i += len(x)
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
index 27976fb..1de2c4e 100644
--- a/src/cmd/dist/buildgo.go
+++ b/src/cmd/dist/buildgo.go
@@ -25,7 +25,20 @@ import (
 // It is invoked to write cmd/go/zdefaultcc.go
 // but we also write cmd/cgo/zdefaultcc.go
 func mkzdefaultcc(dir, file string) {
-	out := fmt.Sprintf(
+	outGo := fmt.Sprintf(
+		"// auto generated by go tool dist\n"+
+			"\n"+
+			"package cfg\n"+
+			"\n"+
+			"const DefaultCC = `%s`\n"+
+			"const DefaultCXX = `%s`\n"+
+			"const DefaultPkgConfig = `%s`\n",
+		defaultcctarget, defaultcxxtarget, defaultpkgconfigtarget)
+
+	writefile(outGo, file, writeSkipSame)
+
+	// Convert file name to replace: turn go/internal/cfg into cgo.
+	outCgo := fmt.Sprintf(
 		"// auto generated by go tool dist\n"+
 			"\n"+
 			"package main\n"+
@@ -35,12 +48,9 @@ func mkzdefaultcc(dir, file string) {
 			"const defaultPkgConfig = `%s`\n",
 		defaultcctarget, defaultcxxtarget, defaultpkgconfigtarget)
 
-	writefile(out, file, writeSkipSame)
-
-	// Convert file name to replace: turn go into cgo.
-	i := len(file) - len("go/zdefaultcc.go")
-	file = file[:i] + "c" + file[i:]
-	writefile(out, file, writeSkipSame)
+	i := len(file) - len("go/internal/cfg/zdefaultcc.go")
+	file = file[:i] + "cgo/zdefaultcc.go"
+	writefile(outCgo, file, writeSkipSame)
 }
 
 // mkzcgo writes zosarch.go for cmd/go.
@@ -54,8 +64,8 @@ func mkzosarch(dir, file string) {
 
 	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")
+	buf.WriteString("package cfg\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])
 	}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index d696beb..1467c59 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -36,9 +36,9 @@ func mkzversion(dir, file string) {
 	writefile(out, file, writeSkipSame)
 }
 
-// mkzbootstrap writes cmd/internal/obj/zbootstrap.go:
+// mkzbootstrap writes cmd/internal/objabi/zbootstrap.go:
 //
-//	package obj
+//	package objabi
 //
 //	const defaultGOROOT = <goroot>
 //	const defaultGO386 = <go386>
@@ -63,7 +63,7 @@ func mkzbootstrap(file string) {
 	out := fmt.Sprintf(
 		"// auto generated by go tool dist\n"+
 			"\n"+
-			"package obj\n"+
+			"package objabi\n"+
 			"\n"+
 			"import \"runtime\"\n"+
 			"\n"+
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index b0b9b25..8a3db32 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -12,7 +12,10 @@
 package main
 
 import (
+	"fmt"
 	"os"
+	"path/filepath"
+	"runtime"
 	"strings"
 )
 
@@ -40,6 +43,7 @@ var bootstrapDirs = []string{
 	"cmd/compile/internal/mips",
 	"cmd/compile/internal/mips64",
 	"cmd/compile/internal/ppc64",
+	"cmd/compile/internal/types",
 	"cmd/compile/internal/s390x",
 	"cmd/compile/internal/ssa",
 	"cmd/compile/internal/syntax",
@@ -47,6 +51,7 @@ var bootstrapDirs = []string{
 	"cmd/internal/bio",
 	"cmd/internal/gcprog",
 	"cmd/internal/dwarf",
+	"cmd/internal/objabi",
 	"cmd/internal/obj",
 	"cmd/internal/obj/arm",
 	"cmd/internal/obj/arm64",
@@ -54,6 +59,7 @@ var bootstrapDirs = []string{
 	"cmd/internal/obj/ppc64",
 	"cmd/internal/obj/s390x",
 	"cmd/internal/obj/x86",
+	"cmd/internal/src",
 	"cmd/internal/sys",
 	"cmd/link",
 	"cmd/link/internal/amd64",
@@ -67,6 +73,14 @@ var bootstrapDirs = []string{
 	"cmd/link/internal/x86",
 	"debug/pe",
 	"math/big",
+	"math/bits",
+}
+
+// File prefixes that are ignored by go/build anyway, and cause
+// problems with editor generated temporary files (#18931).
+var ignorePrefixes = []string{
+	".",
+	"_",
 }
 
 // File suffixes that use build tags introduced since Go 1.4.
@@ -83,7 +97,7 @@ func bootstrapBuildTools() {
 	}
 	xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)
 
-	mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))
+	mkzbootstrap(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
 
 	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
 	// We use a subdirectory of $GOROOT/pkg because that's the
@@ -102,15 +116,21 @@ func bootstrapBuildTools() {
 		xmkdirall(dst)
 	Dir:
 		for _, name := range xreaddirfiles(src) {
+			for _, pre := range ignorePrefixes {
+				if strings.HasPrefix(name, pre) {
+					continue Dir
+				}
+			}
 			for _, suf := range ignoreSuffixes {
 				if strings.HasSuffix(name, suf) {
 					continue Dir
 				}
 			}
 			srcFile := pathf("%s/%s", src, name)
+			dstFile := pathf("%s/%s", dst, name)
 			text := readfile(srcFile)
-			text = bootstrapFixImports(text, srcFile)
-			writefile(text, pathf("%s/%s", dst, name), 0)
+			text = bootstrapRewriteFile(text, srcFile)
+			writefile(text, dstFile, 0)
 		}
 	}
 
@@ -143,7 +163,18 @@ func bootstrapBuildTools() {
 	// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
 	// Use the math_big_pure_go build tag to disable the assembly in math/big
 	// which may contain unsupported instructions.
-	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-gcflags=-l", "-tags=math_big_pure_go", "-v", "bootstrap/cmd/...")
+	cmd := []string{
+		pathf("%s/bin/go", goroot_bootstrap),
+		"install",
+		"-gcflags=-l",
+		"-tags=math_big_pure_go",
+		"-v",
+	}
+	if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
+		cmd = append(cmd, "-toolexec="+tool)
+	}
+	cmd = append(cmd, "bootstrap/cmd/...")
+	run(workspace, ShowOutput|CheckExit, cmd...)
 
 	// Copy binaries into tool binary directory.
 	for _, name := range bootstrapDirs {
@@ -159,6 +190,53 @@ func bootstrapBuildTools() {
 	xprintf("\n")
 }
 
+var ssaRewriteFileSubstring = filepath.ToSlash("src/cmd/compile/internal/ssa/rewrite")
+
+// isUnneededSSARewriteFile reports whether srcFile is a
+// src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an
+// architecture that isn't for the current runtime.GOARCH.
+//
+// When unneeded is true archCaps is the rewrite base filename without
+// the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc.
+func isUnneededSSARewriteFile(srcFile string) (archCaps string, unneeded bool) {
+	if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
+		return "", false
+	}
+	fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
+	if fileArch == "" {
+		return "", false
+	}
+	b := fileArch[0]
+	if b == '_' || ('a' <= b && b <= 'z') {
+		return "", false
+	}
+	archCaps = fileArch
+	fileArch = strings.ToLower(fileArch)
+	if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") {
+		return "", false
+	}
+	if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") {
+		return "", false
+	}
+	return archCaps, true
+}
+
+func bootstrapRewriteFile(text, srcFile string) string {
+	// During bootstrap, generate dummy rewrite files for
+	// irrelevant architectures. We only need to build a bootstrap
+	// binary that works for the current runtime.GOARCH.
+	// This saves 6+ seconds of bootstrap.
+	if archCaps, ok := isUnneededSSARewriteFile(srcFile); ok {
+		return fmt.Sprintf(`package ssa
+
+func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
+func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
+`, archCaps, archCaps)
+	}
+
+	return bootstrapFixImports(text, srcFile)
+}
+
 func bootstrapFixImports(text, srcFile string) string {
 	lines := strings.SplitAfter(text, "\n")
 	inBlock := false
diff --git a/src/cmd/dist/deps.go b/src/cmd/dist/deps.go
index 817484f..51dca05 100644
--- a/src/cmd/dist/deps.go
+++ b/src/cmd/dist/deps.go
@@ -3,64 +3,92 @@
 package main
 
 var builddeps = map[string][]string{
-	"bufio":                             {"bytes", "errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
-	"bytes":                             {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
-	"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":                    {"errors", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-	"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"},
-	"debug/elf":                         {"bufio", "bytes", "compress/flate", "compress/zlib", "debug/dwarf", "encoding/binary", "errors", "fmt", "hash", "hash/adler32", "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", "unicod [...]
-	"debug/macho":                       {"bytes", "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"},
+	"bufio":                             {"bytes", "errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"bytes":                             {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"cmd/go/internal/base":              {"bufio", "bytes", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect" [...]
+	"cmd/go/internal/bug":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/envcmd", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "cmd/internal/objabi", "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", " [...]
+	"cmd/go/internal/buildid":           {"bufio", "bytes", "cmd/go/internal/cfg", "cmd/internal/objabi", "compress/flate", "compress/zlib", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "lo [...]
+	"cmd/go/internal/cfg":               {"bufio", "bytes", "cmd/internal/objabi", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/inter [...]
+	"cmd/go/internal/clean":             {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler3 [...]
+	"cmd/go/internal/cmdflag":           {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "p [...]
+	"cmd/go/internal/doc":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "p [...]
+	"cmd/go/internal/envcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "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" [...]
+	"cmd/go/internal/fix":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/internal/objabi", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/cpu", "internal/poll", "inte [...]
+	"cmd/go/internal/fmtcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/internal/objabi", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/cpu", "internal/poll", "inte [...]
+	"cmd/go/internal/generate":          {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler3 [...]
+	"cmd/go/internal/get":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "encoding/xml", "errors", "flag", "fmt", "go/ [...]
+	"cmd/go/internal/help":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "p [...]
+	"cmd/go/internal/list":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "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" [...]
+	"cmd/go/internal/load":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/cpu", "internal/poll", "internal/race", "internal/sy [...]
+	"cmd/go/internal/run":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler3 [...]
+	"cmd/go/internal/str":               {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "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", "unicode/utf16", "unicode/utf8"},
+	"cmd/go/internal/test":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/cmdflag", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/t [...]
+	"cmd/go/internal/tool":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "p [...]
+	"cmd/go/internal/version":           {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "cmd/internal/objabi", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "p [...]
+	"cmd/go/internal/vet":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/cmdflag", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/t [...]
+	"cmd/go/internal/web":               {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
+	"cmd/go/internal/work":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/internal/objabi", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/cpu", "int [...]
+	"cmd/internal/objabi":               {"errors", "flag", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "log", "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"},
+	"compress/flate":                    {"bufio", "bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "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/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+	"container/heap":                    {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"context":                           {"errors", "fmt", "internal/cpu", "internal/poll", "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/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"crypto/sha1":                       {"crypto", "errors", "hash", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"debug/dwarf":                       {"encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "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"},
+	"debug/elf":                         {"bufio", "bytes", "compress/flate", "compress/zlib", "debug/dwarf", "encoding/binary", "errors", "fmt", "hash", "hash/adler32", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall [...]
+	"debug/macho":                       {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "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"},
 	"encoding":                          {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-	"encoding/base64":                   {"errors", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-	"encoding/binary":                   {"errors", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-	"encoding/json":                     {"bytes", "encoding", "encoding/base64", "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"},
+	"encoding/base64":                   {"errors", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"encoding/binary":                   {"errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"encoding/json":                     {"bytes", "encoding", "encoding/base64", "errors", "fmt", "internal/cpu", "internal/poll", "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"},
+	"encoding/xml":                      {"bufio", "bytes", "encoding", "errors", "fmt", "internal/cpu", "internal/poll", "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", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"errors":                            {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-	"flag":                              {"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/utf16", "unicode/utf8"},
-	"fmt":                               {"errors", "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"},
-	"go/ast":                            {"bytes", "errors", "fmt", "go/scanner", "go/token", "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"},
-	"go/build":                          {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "t [...]
-	"go/doc":                            {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", " [...]
-	"go/parser":                         {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "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"},
-	"go/scanner":                        {"bytes", "errors", "fmt", "go/token", "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"},
-	"go/token":                          {"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/utf16", "unicode/utf8"},
+	"flag":                              {"errors", "fmt", "internal/cpu", "internal/poll", "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/utf16", "unicode/utf8"},
+	"fmt":                               {"errors", "internal/cpu", "internal/poll", "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"},
+	"go/ast":                            {"bytes", "errors", "fmt", "go/scanner", "go/token", "internal/cpu", "internal/poll", "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"},
+	"go/build":                          {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sy [...]
+	"go/doc":                            {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/te [...]
+	"go/parser":                         {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "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"},
+	"go/scanner":                        {"bytes", "errors", "fmt", "go/token", "internal/cpu", "internal/poll", "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"},
+	"go/token":                          {"errors", "fmt", "internal/cpu", "internal/poll", "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/utf16", "unicode/utf8"},
 	"hash":                              {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
 	"hash/adler32":                      {"errors", "hash", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
+	"internal/cpu":                      {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
+	"internal/poll":                     {"errors", "internal/race", "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"},
 	"internal/race":                     {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"internal/singleflight":             {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
 	"internal/syscall/windows":          {"errors", "internal/race", "internal/syscall/windows/sysdll", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
 	"internal/syscall/windows/registry": {"errors", "internal/race", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
 	"internal/syscall/windows/sysdll":   {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"io":                      {"errors", "internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
-	"io/ioutil":               {"bytes", "errors", "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"},
-	"log":                     {"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"},
-	"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", "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", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-	"reflect":                 {"errors", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-	"regexp":                  {"bytes", "errors", "internal/race", "io", "math", "reflect", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
-	"regexp/syntax":           {"bytes", "errors", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"io/ioutil":               {"bytes", "errors", "internal/cpu", "internal/poll", "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"},
+	"log":                     {"errors", "fmt", "internal/cpu", "internal/poll", "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"},
+	"math":                    {"internal/cpu", "runtime", "runtime/internal/atomic", "runtime/internal/sys"},
+	"math/bits":               {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
+	"net/url":                 {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "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/poll", "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", "context", "errors", "fmt", "internal/cpu", "internal/poll", "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/poll", "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/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"path/filepath":           {"errors", "internal/cpu", "internal/poll", "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"},
+	"reflect":                 {"errors", "internal/cpu", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"regexp":                  {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"regexp/syntax":           {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
 	"runtime":                 {"runtime/internal/atomic", "runtime/internal/sys"},
 	"runtime/internal/atomic": {"runtime/internal/sys"},
 	"runtime/internal/sys":    {},
-	"sort":                    {"errors", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-	"strconv":                 {"errors", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "unicode/utf8"},
-	"strings":                 {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+	"sort":                    {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
+	"strconv":                 {"errors", "internal/cpu", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "unicode/utf8"},
+	"strings":                 {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
 	"sync":                    {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},
 	"sync/atomic":             {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"syscall":                 {"errors", "internal/race", "internal/syscall/windows/sysdll", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode/utf16"},
-	"text/template":           {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-	"text/template/parse":     {"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", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+	"text/template":           {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+	"text/template/parse":     {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "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", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"time":                    {"errors", "internal/race", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
 	"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", "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 [...]
+	"cmd/go":                  {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/bug", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/clean", "cmd/go/internal/cmdflag", "cmd/go/internal/doc", "cmd/go/internal/envcmd", "cmd/go/internal/fix", "cmd/go/internal/fmtcmd", "cmd/go/internal/generate", "cmd/go/internal/get", "cmd/go/internal/help", "cmd/go/internal/list", "cmd/go/internal/load", "cmd/go/internal/run", "cmd/go/internal/str", "cmd/go/internal/test", "cmd/ [...]
 }
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index c51dcea..b56495e 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -15,6 +15,7 @@ import (
 	"os/exec"
 	"path/filepath"
 	"regexp"
+	"runtime"
 	"strconv"
 	"strings"
 	"sync"
@@ -59,6 +60,7 @@ type tester struct {
 	goroot     string
 	goarch     string
 	gohostarch string
+	goarm      string
 	goos       string
 	gohostos   string
 	cgoEnabled bool
@@ -102,6 +104,7 @@ func (t *tester) run() {
 	t.gohostos = mustEnv("GOHOSTOS")
 	t.goarch = mustEnv("GOARCH")
 	t.gohostarch = mustEnv("GOHOSTARCH")
+	t.goarm = os.Getenv("GOARM")
 	slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
 	if err != nil {
 		log.Fatalf("Error running go env CGO_ENABLED: %v", err)
@@ -263,7 +266,7 @@ var (
 
 func (t *tester) registerStdTest(pkg string) {
 	testName := "go_test:" + pkg
-	if t.runRx == nil || t.runRx.MatchString(testName) {
+	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
 		stdMatches = append(stdMatches, pkg)
 	}
 	t.tests = append(t.tests, distTest{
@@ -299,7 +302,7 @@ func (t *tester) registerStdTest(pkg string) {
 
 func (t *tester) registerRaceBenchTest(pkg string) {
 	testName := "go_test_bench:" + pkg
-	if t.runRx == nil || t.runRx.MatchString(testName) {
+	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
 		benchMatches = append(benchMatches, pkg)
 	}
 	t.tests = append(t.tests, distTest{
@@ -338,16 +341,17 @@ var stdOutErrAreTerminals func() bool
 func (t *tester) registerTests() {
 	if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") {
 		// Run vet over std and cmd and call it quits.
-		t.tests = append(t.tests, distTest{
-			name:    "vet/all",
-			heading: "go vet std cmd",
-			fn: func(dt *distTest) error {
-				// This runs vet/all for the current platform.
-				// TODO: on a fast builder or builders, run over all platforms.
-				t.addCmd(dt, "src/cmd/vet/all", "go", "run", "main.go", "-all")
-				return nil
-			},
-		})
+		for k := range cgoEnabled {
+			osarch := k
+			t.tests = append(t.tests, distTest{
+				name:    "vet/" + osarch,
+				heading: "go vet std cmd",
+				fn: func(dt *distTest) error {
+					t.addCmd(dt, "src/cmd/vet/all", "go", "run", "main.go", "-p="+osarch)
+					return nil
+				},
+			})
+		}
 		return
 	}
 
@@ -426,7 +430,7 @@ func (t *tester) registerTests() {
 				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())
+				cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
 				return nil
 			},
 		})
@@ -462,7 +466,10 @@ func (t *tester) registerTests() {
 	}
 
 	// Test internal linking of PIE binaries where it is supported.
-	if t.goos == "linux" && t.goarch == "amd64" {
+	if t.goos == "linux" && t.goarch == "amd64" && !isAlpineLinux() {
+		// Issue 18243: We don't have a way to set the default
+		// dynamic linker used in internal linking mode. So
+		// this test is skipped on Alpine.
 		t.tests = append(t.tests, distTest{
 			name:    "pie_internal",
 			heading: "internal linking of -buildmode=pie",
@@ -590,7 +597,13 @@ func (t *tester) registerTests() {
 		t.registerTest("bench_go1", "../test/bench/go1", "go", "test", t.timeout(600), t.runFlag(""))
 	}
 	if t.goos != "android" && !t.iOS() {
-		const nShards = 5
+		// Only start multiple test dir shards on builders,
+		// where they get distributed to multiple machines.
+		// See issue 20141.
+		nShards := 1
+		if os.Getenv("GO_BUILDER_NAME") != "" {
+			nShards = 10
+		}
 		for shard := 0; shard < nShards; shard++ {
 			shard := shard
 			t.tests = append(t.tests, distTest{
@@ -743,6 +756,10 @@ func (t *tester) internalLink() bool {
 	if t.goarch == "arm64" || t.goarch == "mips64" || t.goarch == "mips64le" || t.goarch == "mips" || t.goarch == "mipsle" {
 		return false
 	}
+	if isAlpineLinux() {
+		// Issue 18243.
+		return false
+	}
 	return true
 }
 
@@ -755,7 +772,8 @@ func (t *tester) supportedBuildmode(mode string) bool {
 		}
 		switch pair {
 		case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
-			"linux-amd64", "linux-386", "windows-amd64", "windows-386":
+			"linux-amd64", "linux-386", "linux-ppc64le",
+			"windows-amd64", "windows-386":
 			return true
 		}
 		return false
@@ -782,10 +800,16 @@ func (t *tester) supportedBuildmode(mode string) bool {
 			return false
 		}
 
+		if pair == "linux-arm" && t.goarm == "5" {
+			// Skip the plugin tests for now on ARMv5 because it causes a
+			// SIGILL. See https://golang.org/issue/19674
+			return false
+		}
+
 		// linux-arm64 is missing because it causes the external linker
 		// to crash, see https://golang.org/issue/17138
 		switch pair {
-		case "linux-386", "linux-amd64", "linux-arm":
+		case "linux-386", "linux-amd64", "linux-arm", "linux-s390x":
 			return true
 		}
 		return false
@@ -807,10 +831,9 @@ func (t *tester) registerHostTest(name, heading, dir, pkg string) {
 }
 
 func (t *tester) runHostTest(dir, pkg string) error {
-	env := mergeEnvLists([]string{"GOARCH=" + t.gohostarch, "GOOS=" + t.gohostos}, os.Environ())
 	defer os.Remove(filepath.Join(t.goroot, dir, "test.test"))
 	cmd := t.dirCmd(dir, "go", "test", t.tags(), "-c", "-o", "test.test", pkg)
-	cmd.Env = env
+	cmd.Env = append(os.Environ(), "GOARCH="+t.gohostarch, "GOOS="+t.gohostos)
 	if err := cmd.Run(); err != nil {
 		return err
 	}
@@ -818,7 +841,7 @@ func (t *tester) runHostTest(dir, pkg string) error {
 }
 
 func (t *tester) cgoTest(dt *distTest) error {
-	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+	env := append(os.Environ(), "GOTRACEBACK=2")
 
 	cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag(""))
 	cmd.Env = env
@@ -1053,12 +1076,12 @@ func (t *tester) cgoTestSO(dt *distTest, testpath string) error {
 		if t.goos == "darwin" {
 			s = "DYLD_LIBRARY_PATH"
 		}
-		cmd.Env = mergeEnvLists([]string{s + "=."}, os.Environ())
+		cmd.Env = append(os.Environ(), s+"=.")
 
 		// On FreeBSD 64-bit architectures, the 32-bit linker looks for
 		// different environment variables.
 		if t.goos == "freebsd" && t.gohostarch == "386" {
-			cmd.Env = mergeEnvLists([]string{"LD_32_LIBRARY_PATH=."}, cmd.Env)
+			cmd.Env = append(cmd.Env, "LD_32_LIBRARY_PATH=.")
 		}
 	}
 	return cmd.Run()
@@ -1075,11 +1098,21 @@ func (t *tester) hasBash() bool {
 func (t *tester) raceDetectorSupported() bool {
 	switch t.gohostos {
 	case "linux", "darwin", "freebsd", "windows":
-		return t.cgoEnabled && t.goarch == "amd64" && t.gohostos == t.goos
+		// The race detector doesn't work on Alpine Linux:
+		// golang.org/issue/14481
+		return t.cgoEnabled && t.goarch == "amd64" && t.gohostos == t.goos && !isAlpineLinux()
 	}
 	return false
 }
 
+func isAlpineLinux() bool {
+	if runtime.GOOS != "linux" {
+		return false
+	}
+	fi, err := os.Lstat("/etc/alpine-release")
+	return err == nil && fi.Mode().IsRegular()
+}
+
 func (t *tester) runFlag(rx string) string {
 	if t.compileOnly {
 		return "-run=^$"
@@ -1088,18 +1121,17 @@ func (t *tester) runFlag(rx string) string {
 }
 
 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", "-i", "runtime/race", "flag", "os", "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|TestStdinCloseRace"), "flag", "os/exec")
+	t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace"), "flag", "os", "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.
 	// TODO(iant): Figure out how to catch this.
 	// 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", t.runFlag(""))
-		cmd.Env = env
+		cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
 	}
 	if t.extLink() {
 		// Test with external linking; see issue 9133.
@@ -1118,7 +1150,7 @@ func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
 	runtest.Do(func() {
 		const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
 		cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
-		cmd.Env = mergeEnvLists([]string{"GOOS=" + t.gohostos, "GOARCH=" + t.gohostarch, "GOMAXPROCS="}, os.Environ())
+		cmd.Env = append(os.Environ(), "GOOS="+t.gohostos, "GOARCH="+t.gohostarch)
 		runtest.exe = filepath.Join(cmd.Dir, exe)
 		if err := cmd.Run(); err != nil {
 			runtest.err = err
@@ -1141,24 +1173,6 @@ func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
 	return nil
 }
 
-// mergeEnvLists merges the two environment lists such that
-// variables with the same name in "in" replace those in "out".
-// out may be mutated.
-func mergeEnvLists(in, out []string) []string {
-NextVar:
-	for _, inkv := range in {
-		k := strings.SplitAfterN(inkv, "=", 2)[0]
-		for i, outkv := range out {
-			if strings.HasPrefix(outkv, k) {
-				out[i] = inkv
-				continue NextVar
-			}
-		}
-		out = append(out, inkv)
-	}
-	return out
-}
-
 // cgoPackages is the standard packages that use cgo.
 var cgoPackages = []string{
 	"crypto/x509",
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 1c054fd..e534bfe 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -71,6 +71,8 @@ var tests = []test{
 			`const MultiLineConst = ...`,                                   // Multi line constant.
 			`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`,  // Multi line variable.
 			`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
+			`var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`,  // Long list of arguments.
+			`type T1 = T2`, // Type alias
 		},
 		[]string{
 			`const internalConstant = 2`,        // No internal constants.
@@ -89,6 +91,8 @@ var tests = []test{
 			`unexportedTypedConstant`,           // No unexported typed constant.
 			`Field`,                             // No fields.
 			`Method`,                            // No methods.
+			`someArgument[5-8]`,                 // No truncated arguments.
+			`type T1 T2`,                        // Type alias does not display as type declaration.
 		},
 	},
 	// Package dump -u
@@ -265,6 +269,18 @@ var tests = []test{
 			`error`,                          // No embedded error.
 		},
 	},
+	// Type T1 dump (alias).
+	{
+		"type T1",
+		[]string{p + ".T1"},
+		[]string{
+			`type T1 = T2`,
+		},
+		[]string{
+			`type T1 T2`,
+			`type ExportedType`,
+		},
+	},
 	// Type -u with unexported fields.
 	{
 		"type with unexported fields and -u",
@@ -374,6 +390,29 @@ var tests = []test{
 		nil,
 	},
 
+	// Field.
+	{
+		"field",
+		[]string{p, `ExportedType.ExportedField`},
+		[]string{
+			`ExportedField int`,
+			`Comment before exported field.`,
+			`Comment on line with exported field.`,
+		},
+		nil,
+	},
+
+	// Field  with -u.
+	{
+		"method with -u",
+		[]string{"-u", p, `ExportedType.unexportedField`},
+		[]string{
+			`unexportedField int`,
+			`Comment on line with unexported field.`,
+		},
+		nil,
+	},
+
 	// Case matching off.
 	{
 		"case matching off",
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index df1890f..76c7dba 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -10,18 +10,18 @@
 //
 // One argument:
 //	go doc <pkg>
-//	go doc <sym>[.<method>]
-//	go doc [<pkg>.]<sym>[.<method>]
-//	go doc [<pkg>.][<sym>.]<method>
+//	go doc <sym>[.<methodOrField>]
+//	go doc [<pkg>.]<sym>[.<methodOrField>]
+//	go doc [<pkg>.][<sym>.]<methodOrField>
 // The first item in this list that succeeds is the one whose documentation
 // is printed. If there is a symbol but no package, the package in the current
 // directory is chosen. However, if the argument begins with a capital
 // letter it is always assumed to be a symbol in the current directory.
 //
 // Two arguments:
-//	go doc <pkg> <sym>[.<method>]
+//	go doc <pkg> <sym>[.<methodOrField>]
 //
-// Show the documentation for the package, symbol, and method. The
+// Show the documentation for the package, symbol, and method or field. The
 // first argument must be a full package path. This is similar to the
 // command-line usage for the godoc command.
 //
@@ -129,6 +129,9 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
 			if pkg.methodDoc(symbol, method) {
 				return
 			}
+			if pkg.fieldDoc(symbol, method) {
+				return
+			}
 		}
 	}
 }
@@ -149,7 +152,7 @@ func failMessage(paths []string, symbol, method string) error {
 	if method == "" {
 		return fmt.Errorf("no symbol %s in package%s", symbol, &b)
 	}
-	return fmt.Errorf("no method %s.%s in package%s", symbol, method, &b)
+	return fmt.Errorf("no method or field %s.%s in package%s", symbol, method, &b)
 }
 
 // parseArgs analyzes the arguments (if any) and returns the package
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index daa6ed3..7b0f9de 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -258,7 +258,11 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
 		return fmt.Sprintf("func %s%s%s", recv, name, fnc)
 
 	case *ast.TypeSpec:
-		return fmt.Sprintf("type %s %s", n.Name.Name, pkg.oneLineNodeDepth(n.Type, depth))
+		sep := " "
+		if n.Assign.IsValid() {
+			sep = " = "
+		}
+		return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
 
 	case *ast.FuncType:
 		var params []string
@@ -277,11 +281,11 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
 			}
 		}
 
-		param := strings.Join(params, ", ")
+		param := joinStrings(params)
 		if len(results) == 0 {
 			return fmt.Sprintf("func(%s)", param)
 		}
-		result := strings.Join(results, ", ")
+		result := joinStrings(results)
 		if !needParens {
 			return fmt.Sprintf("func(%s) %s", param, result)
 		}
@@ -334,7 +338,7 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
 		for _, arg := range n.Args {
 			args = append(args, pkg.oneLineNodeDepth(arg, depth))
 		}
-		return fmt.Sprintf("%s(%s)", fnc, strings.Join(args, ", "))
+		return fmt.Sprintf("%s(%s)", fnc, joinStrings(args))
 
 	case *ast.UnaryExpr:
 		return fmt.Sprintf("%s%s", n.Op, pkg.oneLineNodeDepth(n.X, depth))
@@ -363,7 +367,21 @@ func (pkg *Package) oneLineField(field *ast.Field, depth int) string {
 	if len(names) == 0 {
 		return pkg.oneLineNodeDepth(field.Type, depth)
 	}
-	return strings.Join(names, ", ") + " " + pkg.oneLineNodeDepth(field.Type, depth)
+	return joinStrings(names) + " " + pkg.oneLineNodeDepth(field.Type, depth)
+}
+
+// joinStrings formats the input as a comma-separated list,
+// but truncates the list at some reasonable length if necessary.
+func joinStrings(ss []string) string {
+	var n int
+	for i, s := range ss {
+		n += len(s) + len(", ")
+		if n > punchedCardWidth {
+			ss = append(ss[:i:i], "...")
+			break
+		}
+	}
+	return strings.Join(ss, ", ")
 }
 
 // packageDoc prints the docs for the package (package doc plus one-liners of the rest).
@@ -772,7 +790,6 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
 		inter, ok := spec.Type.(*ast.InterfaceType)
 		if !ok {
 			// Not an interface type.
-			// TODO? Maybe handle struct fields here.
 			continue
 		}
 		for _, iMethod := range inter.Methods.List {
@@ -783,7 +800,6 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
 			}
 			name := iMethod.Names[0].Name
 			if match(method, name) {
-				// pkg.oneLineField(iMethod, 0)
 				if iMethod.Doc != nil {
 					for _, comment := range iMethod.Doc.List {
 						doc.ToText(&pkg.buf, comment.Text, "", indent, indentedWidth)
@@ -804,12 +820,68 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
 	return found
 }
 
+// printFieldDoc prints the docs for matches of symbol.fieldName.
+// It reports whether it found any field.
+// Both symbol and fieldName must be non-empty or it returns false.
+func (pkg *Package) printFieldDoc(symbol, fieldName string) bool {
+	if symbol == "" || fieldName == "" {
+		return false
+	}
+	defer pkg.flush()
+	types := pkg.findTypes(symbol)
+	if types == nil {
+		pkg.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
+	}
+	found := false
+	for _, typ := range types {
+		// Type must be a struct.
+		spec := pkg.findTypeSpec(typ.Decl, typ.Name)
+		structType, ok := spec.Type.(*ast.StructType)
+		if !ok {
+			// Not a struct type.
+			continue
+		}
+		for _, field := range structType.Fields.List {
+			// TODO: Anonymous fields.
+			for _, name := range field.Names {
+				if match(fieldName, name.Name) {
+					if !found {
+						pkg.Printf("struct %s {\n", typ.Name)
+					}
+					if field.Doc != nil {
+						for _, comment := range field.Doc.List {
+							doc.ToText(&pkg.buf, comment.Text, indent, indent, indentedWidth)
+						}
+					}
+					s := pkg.oneLineNode(field.Type)
+					lineComment := ""
+					if field.Comment != nil {
+						lineComment = fmt.Sprintf("  %s", field.Comment.List[0].Text)
+					}
+					pkg.Printf("%s%s %s%s\n", indent, name, s, lineComment)
+					found = true
+				}
+			}
+		}
+	}
+	if found {
+		pkg.Printf("}\n")
+	}
+	return found
+}
+
 // methodDoc prints the docs for matches of symbol.method.
 func (pkg *Package) methodDoc(symbol, method string) bool {
 	defer pkg.flush()
 	return pkg.printMethodDoc(symbol, method)
 }
 
+// fieldDoc prints the docs for matches of symbol.field.
+func (pkg *Package) fieldDoc(symbol, field string) bool {
+	defer pkg.flush()
+	return pkg.printFieldDoc(symbol, field)
+}
+
 // match reports whether the user's symbol matches the program's.
 // A lower-case character in the user's string matches either case in the program's.
 // The program string must be exported.
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 924daa1..4e08c84 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -172,3 +172,20 @@ const (
 )
 
 const ConstGroup4 ExportedType = ExportedType{}
+
+func newLongLine(ss ...string)
+
+var LongLine = newLongLine(
+	"someArgument1",
+	"someArgument2",
+	"someArgument3",
+	"someArgument4",
+	"someArgument5",
+	"someArgument6",
+	"someArgument7",
+	"someArgument8",
+)
+
+type T2 int
+
+type T1 = T2
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index 3b4130b..f06abae 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -17,6 +17,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"strings"
 )
@@ -237,25 +238,41 @@ func isGoFile(f os.FileInfo) bool {
 	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
 }
 
+func writeTempFile(dir, prefix string, data []byte) (string, error) {
+	file, err := ioutil.TempFile(dir, prefix)
+	if err != nil {
+		return "", err
+	}
+	_, err = file.Write(data)
+	if err1 := file.Close(); err == nil {
+		err = err1
+	}
+	if err != nil {
+		os.Remove(file.Name())
+		return "", err
+	}
+	return file.Name(), nil
+}
+
 func diff(b1, b2 []byte) (data []byte, err error) {
-	f1, err := ioutil.TempFile("", "go-fix")
+	f1, err := writeTempFile("", "go-fix", b1)
 	if err != nil {
-		return nil, err
+		return
 	}
-	defer os.Remove(f1.Name())
-	defer f1.Close()
+	defer os.Remove(f1)
 
-	f2, err := ioutil.TempFile("", "go-fix")
+	f2, err := writeTempFile("", "go-fix", b2)
 	if err != nil {
-		return nil, err
+		return
 	}
-	defer os.Remove(f2.Name())
-	defer f2.Close()
+	defer os.Remove(f2)
 
-	f1.Write(b1)
-	f2.Write(b2)
+	cmd := "diff"
+	if runtime.GOOS == "plan9" {
+		cmd = "/bin/ape/diff"
+	}
 
-	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+	data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
 	if len(data) > 0 {
 		// diff exits with a non-zero status when the files don't match.
 		// Ignore that failure as long as we get output.
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 3d5dd2b..745ee31 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -118,8 +118,8 @@
 // 		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
+// 		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.
@@ -131,16 +131,17 @@
 // 		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
+// 		a space-separated 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.
+// All the flags that take a list of arguments 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,
@@ -208,12 +209,13 @@
 //
 // Usage:
 //
-// 	go doc [-u] [-c] [package|[package.]symbol[.method]]
+// 	go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]
 //
 // 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.).
+// arguments (a package, const, func, type, var, method, or struct field)
+// 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.
 //
@@ -231,9 +233,9 @@
 // which is schematically one of these:
 //
 // 	go doc <pkg>
-// 	go doc <sym>[.<method>]
-// 	go doc [<pkg>.]<sym>[.<method>]
-// 	go doc [<pkg>.][<sym>.]<method>
+// 	go doc <sym>[.<methodOrField>]
+// 	go doc [<pkg>.]<sym>[.<methodOrField>]
+// 	go doc [<pkg>.][<sym>.]<methodOrField>
 //
 // 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
@@ -241,7 +243,7 @@
 //
 // 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
+// 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
@@ -253,10 +255,10 @@
 // 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:
+// suffix), and the second is a symbol, or symbol with method or struct field.
+// This is similar to the syntax accepted by godoc:
 //
-// 	go doc <pkg> <sym>[.<method>]
+// 	go doc <pkg> <sym>[.<methodOrField>]
 //
 // 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
@@ -307,22 +309,25 @@
 // 		when showing the package's top-level documentation.
 // 	-u
 // 		Show documentation for unexported as well as exported
-// 		symbols and methods.
+// 		symbols, methods, and fields.
 //
 //
 // Print Go environment information
 //
 // Usage:
 //
-// 	go env [var ...]
+// 	go env [-json] [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
+// (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.
 //
+// The -json flag prints the environment in JSON format
+// instead of as a shell script.
+//
 //
 // Start a bug report
 //
@@ -357,7 +362,7 @@
 // 	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.
+// 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'.
@@ -427,7 +432,7 @@
 // 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
+// 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.
@@ -504,7 +509,7 @@
 // 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
+// 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.
 //
 // The -v flag enables verbose progress and debug output.
@@ -565,7 +570,7 @@
 //     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
+// syntax of package template. The default output is equivalent to -f
 // '{{.ImportPath}}'. The struct being passed to the template is:
 //
 //     type Package struct {
@@ -658,12 +663,12 @@
 // 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
+// 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
+// printing. Erroneous packages will have a non-empty ImportPath and
 // a non-nil Error field; other information may or may not be missing
 // (zeroed).
 //
@@ -716,7 +721,7 @@
 // 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.
+// 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
@@ -725,7 +730,7 @@
 // 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
+// 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
@@ -793,15 +798,13 @@
 //
 // Usage:
 //
-// 	go vet [-n] [-x] [build flags] [packages]
+// 	go vet [-n] [-x] [build flags] [vet 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 vet and its flags, 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.
 //
@@ -814,18 +817,18 @@
 //
 // 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
+// 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
+// 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
+// compiler. The CC or CXX environment variables may be set to determine
 // the C or C++ compiler, respectively, to use.
 //
 //
@@ -938,7 +941,7 @@
 //
 // Each directory listed in GOPATH must have a prescribed structure:
 //
-// The src directory holds source code.  The path below src
+// The src directory holds source code. The path below src
 // determines the import path or executable name.
 //
 // The pkg directory holds installed package objects.
@@ -952,11 +955,11 @@
 //
 // 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
+// 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
+// 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
+// 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.
 //
@@ -1099,7 +1102,7 @@
 // 	CC
 // 		The command to use to compile C code.
 // 	CGO_ENABLED
-// 		Whether the cgo command is supported.  Either 0 or 1.
+// 		Whether the cgo command is supported. Either 0 or 1.
 // 	CGO_CFLAGS
 // 		Flags that cgo will pass to the compiler when compiling
 // 		C code.
@@ -1148,7 +1151,7 @@
 // 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
+// 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 (For more
 // details see: 'go help gopath').
 //
@@ -1219,7 +1222,7 @@
 //
 // 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:
+// that repository. The supported version control systems are:
 //
 // 	Bazaar      .bzr
 // 	Git         .git
@@ -1239,7 +1242,7 @@
 // example.org/repo or repo.git.
 //
 // When a version control system supports multiple protocols,
-// each is tried in turn when downloading.  For example, a Git
+// each is tried in turn when downloading. For example, a Git
 // download tries https://, then git+ssh://.
 //
 // By default, downloads are restricted to known secure protocols
@@ -1357,17 +1360,28 @@
 //
 // 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
+// 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.
+// patterns.
+//
+// To make common patterns more convenient, there are two special cases.
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separated pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+// See golang.org/s/go15vendor for more about vendoring.
 //
 // An import path can also name a package to be downloaded from
-// a remote repository.  Run 'go help importpath' for details.
+// 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
+// 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'.
@@ -1396,7 +1410,7 @@
 //
 // 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
+// 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
@@ -1422,6 +1436,10 @@
 //
 // 	-cover
 // 	    Enable coverage analysis.
+// 	    Note that because coverage works by annotating the source
+// 	    code before compilation, compilation and test failures with
+// 	    coverage enabled may report line numbers that don't correspond
+// 	    to the original sources.
 //
 // 	-covermode set,count,atomic
 // 	    Set the mode for coverage analysis for the package[s]
@@ -1442,9 +1460,14 @@
 //
 // 	-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
+// 	    benchmarks should be executed. The default is the current value
 // 	    of GOMAXPROCS.
 //
+// 	-list regexp
+// 	    List tests, benchmarks, or examples matching the regular expression.
+// 	    No tests, benchmarks or examples will be run. This will only
+// 	    list top-level tests. No subtest or subbenchmarks will be shown.
+//
 // 	-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
@@ -1490,7 +1513,7 @@
 // 	    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,
+// 	    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.
 //
@@ -1508,7 +1531,7 @@
 //
 // 	-memprofilerate n
 // 	    Enable more precise (and expensive) memory profiles by setting
-// 	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
+// 	    runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
 // 	    To profile all memory allocations, use -test.memprofilerate=1
 // 	    and pass --alloc_space flag to the pprof tool.
 //
@@ -1611,8 +1634,8 @@
 // "Output:" is compiled, executed, and expected to produce no output.
 //
 // 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
+// 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.
 //
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
deleted file mode 100644
index 2148d12..0000000
--- a/src/cmd/go/bootstrap.go
+++ /dev/null
@@ -1,41 +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 cmd_go_bootstrap
-
-// This code is compiled only into the bootstrap 'go' binary.
-// These stubs avoid importing packages with large dependency
-// trees, like the use of "net/http" in vcs.go.
-
-package main
-
-import (
-	"errors"
-	"io"
-)
-
-var errHTTP = errors.New("no http in bootstrap go command")
-
-type httpError struct {
-	statusCode int
-}
-
-func (e *httpError) Error() string {
-	panic("unreachable")
-}
-
-func httpGET(url string) ([]byte, error) {
-	return nil, errHTTP
-}
-
-func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadCloser, error) {
-	return "", nil, errHTTP
-}
-
-func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
-	panic("unreachable")
-}
-
-func queryEscape(s string) string { panic("unreachable") }
-func openBrowser(url string) bool { panic("unreachable") }
diff --git a/src/cmd/go/bug.go b/src/cmd/go/bug.go
deleted file mode 100644
index 658f6da..0000000
--- a/src/cmd/go/bug.go
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2016 The Go Authors. 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"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"strings"
-)
-
-var cmdBug = &Command{
-	Run:       runBug,
-	UsageLine: "bug",
-	Short:     "start a bug report",
-	Long: `
-Bug opens the default browser and starts a new bug report.
-The report includes useful system information.
-	`,
-}
-
-func init() {
-	cmdBug.Flag.BoolVar(&buildV, "v", false, "")
-}
-
-func runBug(cmd *Command, args []string) {
-	var buf bytes.Buffer
-	buf.WriteString(bugHeader)
-	inspectGoVersion(&buf)
-	fmt.Fprint(&buf, "#### System details\n\n")
-	fmt.Fprintln(&buf, "```")
-	fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
-	env := newEnv
-	env = append(env, extraEnvVars()...)
-	for _, e := range env {
-		// Hide the TERM environment variable from "go bug".
-		// See issue #18128
-		if e.name != "TERM" {
-			fmt.Fprintf(&buf, "%s=\"%s\"\n", e.name, e.value)
-		}
-	}
-	printGoDetails(&buf)
-	printOSDetails(&buf)
-	printCDetails(&buf)
-	fmt.Fprintln(&buf, "```")
-
-	body := buf.String()
-	url := "https://github.com/golang/go/issues/new?body=" + queryEscape(body)
-	if !openBrowser(url) {
-		fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
-		fmt.Print(body)
-	}
-}
-
-const bugHeader = `Please answer these questions before submitting your issue. Thanks!
-
-#### What did you do?
-If possible, provide a recipe for reproducing the error.
-A complete runnable program is good.
-A link on play.golang.org is best.
-
-
-#### What did you expect to see?
-
-
-#### What did you see instead?
-
-
-`
-
-func printGoDetails(w io.Writer) {
-	printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
-	printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
-}
-
-func printOSDetails(w io.Writer) {
-	switch runtime.GOOS {
-	case "darwin":
-		printCmdOut(w, "uname -v: ", "uname", "-v")
-		printCmdOut(w, "", "sw_vers")
-	case "linux":
-		printCmdOut(w, "uname -sr: ", "uname", "-sr")
-		printCmdOut(w, "", "lsb_release", "-a")
-		printGlibcVersion(w)
-	case "openbsd", "netbsd", "freebsd", "dragonfly":
-		printCmdOut(w, "uname -v: ", "uname", "-v")
-	case "solaris":
-		out, err := ioutil.ReadFile("/etc/release")
-		if err == nil {
-			fmt.Fprintf(w, "/etc/release: %s\n", out)
-		} else {
-			if buildV {
-				fmt.Printf("failed to read /etc/release: %v\n", err)
-			}
-		}
-	}
-}
-
-func printCDetails(w io.Writer) {
-	printCmdOut(w, "lldb --version: ", "lldb", "--version")
-	cmd := exec.Command("gdb", "--version")
-	out, err := cmd.Output()
-	if err == nil {
-		// There's apparently no combination of command line flags
-		// to get gdb to spit out its version without the license and warranty.
-		// Print up to the first newline.
-		fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
-	} else {
-		if buildV {
-			fmt.Printf("failed to run gdb --version: %v\n", err)
-		}
-	}
-}
-
-func inspectGoVersion(w io.Writer) {
-	data, err := httpGET("https://golang.org/VERSION?m=text")
-	if err != nil {
-		if buildV {
-			fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
-		}
-		return
-	}
-
-	// golang.org/VERSION currently returns a whitespace-free string,
-	// but just in case, protect against that changing.
-	// Similarly so for runtime.Version.
-	release := string(bytes.TrimSpace(data))
-	vers := strings.TrimSpace(runtime.Version())
-
-	if vers == release {
-		// Up to date
-		return
-	}
-
-	// Devel version or outdated release. Either way, this request is apropos.
-	fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
-}
-
-// printCmdOut prints the output of running the given command.
-// It ignores failures; 'go bug' is best effort.
-func printCmdOut(w io.Writer, prefix, path string, args ...string) {
-	cmd := exec.Command(path, args...)
-	out, err := cmd.Output()
-	if err != nil {
-		if buildV {
-			fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
-		}
-		return
-	}
-	fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
-}
-
-// firstLine returns the first line of a given byte slice.
-func firstLine(buf []byte) []byte {
-	idx := bytes.IndexByte(buf, '\n')
-	if idx > 0 {
-		buf = buf[:idx]
-	}
-	return bytes.TrimSpace(buf)
-}
-
-// printGlibcVersion prints information about the glibc version.
-// It ignores failures.
-func printGlibcVersion(w io.Writer) {
-	tempdir := os.TempDir()
-	if tempdir == "" {
-		return
-	}
-	src := []byte(`int main() {}`)
-	srcfile := filepath.Join(tempdir, "go-bug.c")
-	outfile := filepath.Join(tempdir, "go-bug")
-	err := ioutil.WriteFile(srcfile, src, 0644)
-	if err != nil {
-		return
-	}
-	defer os.Remove(srcfile)
-	cmd := exec.Command("gcc", "-o", outfile, srcfile)
-	if _, err = cmd.CombinedOutput(); err != nil {
-		return
-	}
-	defer os.Remove(outfile)
-
-	cmd = exec.Command("ldd", outfile)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		return
-	}
-	re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
-	m := re.FindStringSubmatch(string(out))
-	if m == nil {
-		return
-	}
-	cmd = exec.Command(m[1])
-	out, err = cmd.Output()
-	if err != nil {
-		return
-	}
-	fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
-
-	// print another line (the one containing version string) in case of musl libc
-	if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
-		fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
-	}
-}
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
deleted file mode 100644
index cad578d..0000000
--- a/src/cmd/go/build.go
+++ /dev/null
@@ -1,3832 +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 main
-
-import (
-	"bufio"
-	"bytes"
-	"container/heap"
-	"debug/elf"
-	"errors"
-	"flag"
-	"fmt"
-	"go/build"
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-)
-
-var cmdBuild = &Command{
-	UsageLine: "build [-o output] [-i] [build flags] [packages]",
-	Short:     "compile packages and dependencies",
-	Long: `
-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.
-	`,
-}
-
-func init() {
-	// break init cycle
-	cmdBuild.Run = runBuild
-	cmdInstall.Run = runInstall
-
-	cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
-
-	addBuildFlags(cmdBuild)
-	addBuildFlags(cmdInstall)
-}
-
-// Flags set by multiple commands.
-var buildA bool               // -a flag
-var buildN bool               // -n flag
-var buildP = runtime.NumCPU() // -p flag
-var buildV bool               // -v flag
-var buildX bool               // -x flag
-var buildI bool               // -i flag
-var buildO = cmdBuild.Flag.String("o", "", "output file")
-var buildWork bool           // -work flag
-var buildAsmflags []string   // -asmflags flag
-var buildGcflags []string    // -gcflags flag
-var buildLdflags []string    // -ldflags flag
-var buildGccgoflags []string // -gccgoflags flag
-var buildRace bool           // -race flag
-var buildMSan bool           // -msan flag
-var buildToolExec []string   // -toolexec flag
-var buildBuildmode string    // -buildmode flag
-var buildLinkshared bool     // -linkshared flag
-var buildPkgdir string       // -pkgdir flag
-
-var buildContext = build.Default
-var buildToolchain toolchain = noToolchain{}
-var ldBuildmode string
-
-// buildCompiler implements flag.Var.
-// It implements Set by updating both
-// buildToolchain and buildContext.Compiler.
-type buildCompiler struct{}
-
-func (c buildCompiler) Set(value string) error {
-	switch value {
-	case "gc":
-		buildToolchain = gcToolchain{}
-	case "gccgo":
-		buildToolchain = gccgoToolchain{}
-	default:
-		return fmt.Errorf("unknown compiler %q", value)
-	}
-	buildContext.Compiler = value
-	return nil
-}
-
-func (c buildCompiler) String() string {
-	return buildContext.Compiler
-}
-
-func init() {
-	switch build.Default.Compiler {
-	case "gc":
-		buildToolchain = gcToolchain{}
-	case "gccgo":
-		buildToolchain = gccgoToolchain{}
-	}
-}
-
-// addBuildFlags adds the flags common to the build, clean, get,
-// install, list, run, and test commands.
-func addBuildFlags(cmd *Command) {
-	cmd.Flag.BoolVar(&buildA, "a", false, "")
-	cmd.Flag.BoolVar(&buildN, "n", false, "")
-	cmd.Flag.IntVar(&buildP, "p", buildP, "")
-	cmd.Flag.BoolVar(&buildV, "v", false, "")
-	cmd.Flag.BoolVar(&buildX, "x", false, "")
-
-	cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "")
-	cmd.Flag.Var(buildCompiler{}, "compiler", "")
-	cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
-	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
-	cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
-	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
-	cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "")
-	cmd.Flag.StringVar(&buildPkgdir, "pkgdir", "", "")
-	cmd.Flag.BoolVar(&buildRace, "race", false, "")
-	cmd.Flag.BoolVar(&buildMSan, "msan", false, "")
-	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
-	cmd.Flag.BoolVar(&buildWork, "work", false, "")
-}
-
-func addBuildFlagsNX(cmd *Command) {
-	cmd.Flag.BoolVar(&buildN, "n", false, "")
-	cmd.Flag.BoolVar(&buildX, "x", false, "")
-}
-
-func isSpaceByte(c byte) bool {
-	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
-}
-
-// fileExtSplit expects a filename and returns the name
-// and ext (without the dot). If the file has no
-// extension, ext will be empty.
-func fileExtSplit(file string) (name, ext string) {
-	dotExt := filepath.Ext(file)
-	name = file[:len(file)-len(dotExt)]
-	if dotExt != "" {
-		ext = dotExt[1:]
-	}
-	return
-}
-
-type stringsFlag []string
-
-func (v *stringsFlag) Set(s string) error {
-	var err error
-	*v, err = splitQuotedFields(s)
-	if *v == nil {
-		*v = []string{}
-	}
-	return err
-}
-
-func splitQuotedFields(s string) ([]string, error) {
-	// Split fields allowing '' or "" around elements.
-	// Quotes further inside the string do not count.
-	var f []string
-	for len(s) > 0 {
-		for len(s) > 0 && isSpaceByte(s[0]) {
-			s = s[1:]
-		}
-		if len(s) == 0 {
-			break
-		}
-		// Accepted quoted string. No unescaping inside.
-		if s[0] == '"' || s[0] == '\'' {
-			quote := s[0]
-			s = s[1:]
-			i := 0
-			for i < len(s) && s[i] != quote {
-				i++
-			}
-			if i >= len(s) {
-				return nil, fmt.Errorf("unterminated %c string", quote)
-			}
-			f = append(f, s[:i])
-			s = s[i+1:]
-			continue
-		}
-		i := 0
-		for i < len(s) && !isSpaceByte(s[i]) {
-			i++
-		}
-		f = append(f, s[:i])
-		s = s[i:]
-	}
-	return f, nil
-}
-
-func (v *stringsFlag) String() string {
-	return "<stringsFlag>"
-}
-
-func pkgsMain(pkgs []*Package) (res []*Package) {
-	for _, p := range pkgs {
-		if p.Name == "main" {
-			res = append(res, p)
-		}
-	}
-	return res
-}
-
-func pkgsNotMain(pkgs []*Package) (res []*Package) {
-	for _, p := range pkgs {
-		if p.Name != "main" {
-			res = append(res, p)
-		}
-	}
-	return res
-}
-
-var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
-
-func buildModeInit() {
-	_, gccgo := buildToolchain.(gccgoToolchain)
-	var codegenArg string
-	platform := goos + "/" + goarch
-	switch buildBuildmode {
-	case "archive":
-		pkgsFilter = pkgsNotMain
-	case "c-archive":
-		pkgsFilter = func(p []*Package) []*Package {
-			if len(p) != 1 || p[0].Name != "main" {
-				fatalf("-buildmode=c-archive requires exactly one main package")
-			}
-			return p
-		}
-		switch platform {
-		case "darwin/arm", "darwin/arm64":
-			codegenArg = "-shared"
-		default:
-			switch goos {
-			case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
-				// Use -shared so that the result is
-				// suitable for inclusion in a PIE or
-				// shared library.
-				codegenArg = "-shared"
-			}
-		}
-		exeSuffix = ".a"
-		ldBuildmode = "c-archive"
-	case "c-shared":
-		pkgsFilter = pkgsMain
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
-				"android/amd64", "android/arm", "android/arm64", "android/386":
-				codegenArg = "-shared"
-			case "darwin/amd64", "darwin/386":
-			default:
-				fatalf("-buildmode=c-shared not supported on %s\n", platform)
-			}
-		}
-		ldBuildmode = "c-shared"
-	case "default":
-		switch platform {
-		case "android/arm", "android/arm64", "android/amd64", "android/386":
-			codegenArg = "-shared"
-			ldBuildmode = "pie"
-		case "darwin/arm", "darwin/arm64":
-			codegenArg = "-shared"
-			fallthrough
-		default:
-			ldBuildmode = "exe"
-		}
-	case "exe":
-		pkgsFilter = pkgsMain
-		ldBuildmode = "exe"
-	case "pie":
-		if gccgo {
-			fatalf("-buildmode=pie not supported by gccgo")
-		} else {
-			switch platform {
-			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
-				"android/amd64", "android/arm", "android/arm64", "android/386":
-				codegenArg = "-shared"
-			default:
-				fatalf("-buildmode=pie not supported on %s\n", platform)
-			}
-		}
-		ldBuildmode = "pie"
-	case "shared":
-		pkgsFilter = pkgsNotMain
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
-			default:
-				fatalf("-buildmode=shared not supported on %s\n", platform)
-			}
-			codegenArg = "-dynlink"
-		}
-		if *buildO != "" {
-			fatalf("-buildmode=shared and -o not supported together")
-		}
-		ldBuildmode = "shared"
-	case "plugin":
-		pkgsFilter = pkgsMain
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
-				"android/amd64", "android/arm", "android/arm64", "android/386":
-			default:
-				fatalf("-buildmode=plugin not supported on %s\n", platform)
-			}
-			codegenArg = "-dynlink"
-		}
-		exeSuffix = ".so"
-		ldBuildmode = "plugin"
-	default:
-		fatalf("buildmode=%s not supported", buildBuildmode)
-	}
-	if buildLinkshared {
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			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)
-			}
-			codegenArg = "-dynlink"
-			// TODO(mwhudson): remove -w when that gets fixed in linker.
-			buildLdflags = append(buildLdflags, "-linkshared", "-w")
-		}
-	}
-	if codegenArg != "" {
-		if gccgo {
-			buildGccgoflags = append(buildGccgoflags, codegenArg)
-		} else {
-			buildAsmflags = append(buildAsmflags, codegenArg)
-			buildGcflags = append(buildGcflags, codegenArg)
-		}
-		// Don't alter InstallSuffix when modifying default codegen args.
-		if buildBuildmode != "default" || buildLinkshared {
-			if buildContext.InstallSuffix != "" {
-				buildContext.InstallSuffix += "_"
-			}
-			buildContext.InstallSuffix += codegenArg[1:]
-		}
-	}
-}
-
-func runBuild(cmd *Command, args []string) {
-	instrumentInit()
-	buildModeInit()
-	var b builder
-	b.init()
-
-	pkgs := packagesForBuild(args)
-
-	if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
-		_, *buildO = path.Split(pkgs[0].ImportPath)
-		*buildO += exeSuffix
-	}
-
-	// Special case -o /dev/null by not writing at all.
-	if *buildO == os.DevNull {
-		*buildO = ""
-	}
-
-	// sanity check some often mis-used options
-	switch buildContext.Compiler {
-	case "gccgo":
-		if len(buildGcflags) != 0 {
-			fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags")
-		}
-		if len(buildLdflags) != 0 {
-			fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags")
-		}
-	case "gc":
-		if len(buildGccgoflags) != 0 {
-			fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags")
-		}
-	}
-
-	depMode := modeBuild
-	if buildI {
-		depMode = modeInstall
-	}
-
-	if *buildO != "" {
-		if len(pkgs) > 1 {
-			fatalf("go build: cannot use -o with multiple packages")
-		} else if len(pkgs) == 0 {
-			fatalf("no packages to build")
-		}
-		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
-	}
-
-	var a *action
-	if buildBuildmode == "shared" {
-		pkgs := pkgsFilter(packages(args))
-		if libName, err := libname(args, pkgs); err != nil {
-			fatalf("%s", err.Error())
-		} else {
-			a = b.libaction(libName, pkgs, modeBuild, depMode)
-		}
-	} else {
-		a = &action{}
-		for _, p := range pkgsFilter(packages(args)) {
-			a.deps = append(a.deps, b.action(modeBuild, depMode, p))
-		}
-	}
-	b.do(a)
-}
-
-var cmdInstall = &Command{
-	UsageLine: "install [build flags] [packages]",
-	Short:     "compile and install packages and dependencies",
-	Long: `
-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.
-	`,
-}
-
-// isMetaPackage checks if name is a reserved package name that expands to multiple packages
-func isMetaPackage(name string) bool {
-	return name == "std" || name == "cmd" || name == "all"
-}
-
-// libname returns the filename to use for the shared library when using
-// -buildmode=shared. The rules we use are:
-// Use arguments for special 'meta' packages:
-//	std --> libstd.so
-//	std cmd --> libstd,cmd.so
-// A single non-meta argument with trailing "/..." is special cased:
-//	foo/... --> libfoo.so
-//	(A relative path like "./..."  expands the "." first)
-// Use import paths for other cases, changing '/' to '-':
-//	somelib --> libsubdir-somelib.so
-//	./ or ../ --> libsubdir-somelib.so
-//	gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
-//	a/... b/... ---> liba/c,b/d.so - all matching import paths
-// Name parts are joined with ','.
-func libname(args []string, pkgs []*Package) (string, error) {
-	var libname string
-	appendName := func(arg string) {
-		if libname == "" {
-			libname = arg
-		} else {
-			libname += "," + arg
-		}
-	}
-	var haveNonMeta bool
-	for _, arg := range args {
-		if isMetaPackage(arg) {
-			appendName(arg)
-		} else {
-			haveNonMeta = true
-		}
-	}
-	if len(libname) == 0 { // non-meta packages only. use import paths
-		if len(args) == 1 && strings.HasSuffix(args[0], "/...") {
-			// Special case of "foo/..." as mentioned above.
-			arg := strings.TrimSuffix(args[0], "/...")
-			if build.IsLocalImport(arg) {
-				cwd, _ := os.Getwd()
-				bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
-				if bp.ImportPath != "" && bp.ImportPath != "." {
-					arg = bp.ImportPath
-				}
-			}
-			appendName(strings.Replace(arg, "/", "-", -1))
-		} else {
-			for _, pkg := range pkgs {
-				appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
-			}
-		}
-	} else if haveNonMeta { // have both meta package and a non-meta one
-		return "", errors.New("mixing of meta and non-meta packages is not allowed")
-	}
-	// TODO(mwhudson): Needs to change for platforms that use different naming
-	// conventions...
-	return "lib" + libname + ".so", nil
-}
-
-func runInstall(cmd *Command, args []string) {
-	installPackages(args, false)
-}
-
-func installPackages(args []string, forGet bool) {
-	if gobin != "" && !filepath.IsAbs(gobin) {
-		fatalf("cannot install, GOBIN must be an absolute path")
-	}
-
-	instrumentInit()
-	buildModeInit()
-	pkgs := pkgsFilter(packagesForBuild(args))
-
-	for _, p := range pkgs {
-		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
-			switch {
-			case p.gobinSubdir:
-				errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
-			case p.cmdline:
-				errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
-			case p.ConflictDir != "":
-				errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
-			default:
-				errorf("go install: no install location for directory %s outside GOPATH\n"+
-					"\tFor more details see: 'go help gopath'", p.Dir)
-			}
-		}
-	}
-	exitIfErrors()
-
-	var b builder
-	b.init()
-	// Set the behavior for `go get` to not error on packages with test files only.
-	b.testFilesOnlyOK = forGet
-	var a *action
-	if buildBuildmode == "shared" {
-		if libName, err := libname(args, pkgs); err != nil {
-			fatalf("%s", err.Error())
-		} else {
-			a = b.libaction(libName, pkgs, modeInstall, modeInstall)
-		}
-	} else {
-		a = &action{}
-		var tools []*action
-		for _, p := range pkgs {
-			// If p is a tool, delay the installation until the end of the build.
-			// This avoids installing assemblers/compilers that are being executed
-			// by other steps in the build.
-			// cmd/cgo is handled specially in b.action, so that we can
-			// both build and use it in the same 'go install'.
-			action := b.action(modeInstall, modeInstall, p)
-			if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
-				a.deps = append(a.deps, action.deps...)
-				action.deps = append(action.deps, a)
-				tools = append(tools, action)
-				continue
-			}
-			a.deps = append(a.deps, action)
-		}
-		if len(tools) > 0 {
-			a = &action{
-				deps: tools,
-			}
-		}
-	}
-	b.do(a)
-	exitIfErrors()
-
-	// Success. If this command is 'go install' with no arguments
-	// and the current directory (the implicit argument) is a command,
-	// remove any leftover command binary from a previous 'go build'.
-	// The binary is installed; it's not needed here anymore.
-	// And worse it might be a stale copy, which you don't want to find
-	// instead of the installed one if $PATH contains dot.
-	// One way to view this behavior is that it is as if 'go install' first
-	// runs 'go build' and the moves the generated file to the install dir.
-	// See issue 9645.
-	if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
-		// Compute file 'go build' would have created.
-		// If it exists and is an executable file, remove it.
-		_, targ := filepath.Split(pkgs[0].ImportPath)
-		targ += exeSuffix
-		if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
-			fi, err := os.Stat(targ)
-			if err == nil {
-				m := fi.Mode()
-				if m.IsRegular() {
-					if m&0111 != 0 || goos == "windows" { // windows never sets executable bit
-						os.Remove(targ)
-					}
-				}
-			}
-		}
-	}
-}
-
-// Global build parameters (used during package load)
-var (
-	goarch    string
-	goos      string
-	exeSuffix string
-	gopath    []string
-)
-
-func init() {
-	goarch = buildContext.GOARCH
-	goos = buildContext.GOOS
-
-	if goos == "windows" {
-		exeSuffix = ".exe"
-	}
-	gopath = filepath.SplitList(buildContext.GOPATH)
-}
-
-// A builder holds global state about a build.
-// It does not hold per-package state, because we
-// build packages in parallel, and the builder is shared.
-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)
-
-	testFilesOnlyOK bool // do not error if the packages only have test files
-
-	output    sync.Mutex
-	scriptDir string // current directory in printed script
-
-	exec      sync.Mutex
-	readySema chan bool
-	ready     actionQueue
-}
-
-// An action represents a single action in the action graph.
-type action struct {
-	p          *Package      // the package this action works on
-	deps       []*action     // actions that must happen before this one
-	triggers   []*action     // inverse of deps
-	cgo        *action       // action for cgo binary if needed
-	args       []string      // additional args for runProgram
-	testOutput *bytes.Buffer // test output buffer
-
-	f          func(*builder, *action) error // the action itself (nil = no-op)
-	ignoreFail bool                          // whether to run f even if dependencies fail
-
-	// Generated files, directories.
-	link   bool   // target is executable, not just package
-	pkgdir string // the -I or -L argument to use when importing this package
-	objdir string // directory for intermediate objects
-	objpkg string // the intermediate package .a file created during the action
-	target string // goal of the action: the created package or executable
-
-	// Execution state.
-	pending  int  // number of deps yet to complete
-	priority int  // relative execution priority
-	failed   bool // whether the action failed
-}
-
-// cacheKey is the key for the action cache.
-type cacheKey struct {
-	mode  buildMode
-	p     *Package
-	shlib string
-}
-
-// buildMode specifies the build mode:
-// are we just building things or also installing the results?
-type buildMode int
-
-const (
-	modeBuild buildMode = iota
-	modeInstall
-)
-
-var (
-	goroot    = filepath.Clean(runtime.GOROOT())
-	gobin     = os.Getenv("GOBIN")
-	gorootBin = filepath.Join(goroot, "bin")
-	gorootPkg = filepath.Join(goroot, "pkg")
-	gorootSrc = filepath.Join(goroot, "src")
-)
-
-func (b *builder) init() {
-	var err error
-	b.print = func(a ...interface{}) (int, error) {
-		return fmt.Fprint(os.Stderr, a...)
-	}
-	b.actionCache = make(map[cacheKey]*action)
-	b.mkdirCache = make(map[string]bool)
-
-	if buildN {
-		b.work = "$WORK"
-	} else {
-		b.work, err = ioutil.TempDir("", "go-build")
-		if err != nil {
-			fatalf("%s", err)
-		}
-		if buildX || buildWork {
-			fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
-		}
-		if !buildWork {
-			workdir := b.work
-			atexit(func() { os.RemoveAll(workdir) })
-		}
-	}
-}
-
-// goFilesPackage creates a package for building a collection of Go files
-// (typically named on the command line).  The target is named p.a for
-// package p or named after the first Go file for package main.
-func goFilesPackage(gofiles []string) *Package {
-	// TODO: Remove this restriction.
-	for _, f := range gofiles {
-		if !strings.HasSuffix(f, ".go") {
-			fatalf("named files must be .go files")
-		}
-	}
-
-	var stk importStack
-	ctxt := buildContext
-	ctxt.UseAllFiles = true
-
-	// 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
-	// consistently, the files must all be in the same directory.
-	var dirent []os.FileInfo
-	var dir string
-	for _, file := range gofiles {
-		fi, err := os.Stat(file)
-		if err != nil {
-			fatalf("%s", err)
-		}
-		if fi.IsDir() {
-			fatalf("%s is a directory, should be a Go file", file)
-		}
-		dir1, _ := filepath.Split(file)
-		if dir1 == "" {
-			dir1 = "./"
-		}
-		if dir == "" {
-			dir = dir1
-		} else if dir != dir1 {
-			fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
-		}
-		dirent = append(dirent, fi)
-	}
-	ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
-
-	var err error
-	if dir == "" {
-		dir = cwd
-	}
-	dir, err = filepath.Abs(dir)
-	if err != nil {
-		fatalf("%s", err)
-	}
-
-	bp, err := ctxt.ImportDir(dir, 0)
-	pkg := new(Package)
-	pkg.local = true
-	pkg.cmdline = true
-	stk.push("main")
-	pkg.load(&stk, bp, err)
-	stk.pop()
-	pkg.localPrefix = dirToImportPath(dir)
-	pkg.ImportPath = "command-line-arguments"
-	pkg.target = ""
-
-	if pkg.Name == "main" {
-		_, elem := filepath.Split(gofiles[0])
-		exe := elem[:len(elem)-len(".go")] + exeSuffix
-		if *buildO == "" {
-			*buildO = exe
-		}
-		if gobin != "" {
-			pkg.target = filepath.Join(gobin, exe)
-		}
-	}
-
-	pkg.Target = pkg.target
-	pkg.Stale = true
-	pkg.StaleReason = "files named on command line"
-
-	computeStale(pkg)
-	return pkg
-}
-
-// readpkglist returns the list of packages that were built into the shared library
-// at shlibpath. For the native toolchain this list is stored, newline separated, in
-// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
-// .go_export section.
-func readpkglist(shlibpath string) (pkgs []*Package) {
-	var stk importStack
-	if _, gccgo := buildToolchain.(gccgoToolchain); gccgo {
-		f, _ := elf.Open(shlibpath)
-		sect := f.Section(".go_export")
-		data, _ := sect.Data()
-		scanner := bufio.NewScanner(bytes.NewBuffer(data))
-		for scanner.Scan() {
-			t := scanner.Text()
-			if strings.HasPrefix(t, "pkgpath ") {
-				t = strings.TrimPrefix(t, "pkgpath ")
-				t = strings.TrimSuffix(t, ";")
-				pkgs = append(pkgs, loadPackage(t, &stk))
-			}
-		}
-	} else {
-		pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
-		if err != nil {
-			fatalf("readELFNote failed: %v", err)
-		}
-		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
-		for scanner.Scan() {
-			t := scanner.Text()
-			pkgs = append(pkgs, loadPackage(t, &stk))
-		}
-	}
-	return
-}
-
-// action returns the action for applying the given operation (mode) to the package.
-// depMode is the action to use when building dependencies.
-// action never looks for p in a shared library, but may find p's dependencies in a
-// shared library if buildLinkshared is true.
-func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
-	return b.action1(mode, depMode, p, false, "")
-}
-
-// action1 returns the action for applying the given operation (mode) to the package.
-// depMode is the action to use when building dependencies.
-// action1 will look for p in a shared library if lookshared is true.
-// forShlib is the shared library that p will become part of, if any.
-func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool, forShlib string) *action {
-	shlib := ""
-	if lookshared {
-		shlib = p.Shlib
-	}
-	key := cacheKey{mode, p, shlib}
-
-	a := b.actionCache[key]
-	if a != nil {
-		return a
-	}
-	if shlib != "" {
-		key2 := cacheKey{modeInstall, nil, shlib}
-		a = b.actionCache[key2]
-		if a != nil {
-			b.actionCache[key] = a
-			return a
-		}
-		pkgs := readpkglist(shlib)
-		a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode)
-		b.actionCache[key2] = a
-		b.actionCache[key] = a
-		return a
-	}
-
-	a = &action{p: p, pkgdir: p.build.PkgRoot}
-	if p.pkgdir != "" { // overrides p.t
-		a.pkgdir = p.pkgdir
-	}
-	b.actionCache[key] = a
-
-	for _, p1 := range p.imports {
-		if forShlib != "" {
-			// p is part of a shared library.
-			if p1.Shlib != "" && p1.Shlib != forShlib {
-				// p1 is explicitly part of a different shared library.
-				// Put the action for that shared library into a.deps.
-				a.deps = append(a.deps, b.action1(depMode, depMode, p1, true, p1.Shlib))
-			} else {
-				// p1 is (implicitly or not) part of this shared library.
-				// Put the action for p1 into a.deps.
-				a.deps = append(a.deps, b.action1(depMode, depMode, p1, false, forShlib))
-			}
-		} else {
-			// p is not part of a shared library.
-			// If p1 is in a shared library, put the action for that into
-			// a.deps, otherwise put the action for p1 into a.deps.
-			a.deps = append(a.deps, b.action1(depMode, depMode, p1, buildLinkshared, p1.Shlib))
-		}
-	}
-
-	// 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
-	// 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" {
-			var stk importStack
-			p1 := loadPackage("cmd/cgo", &stk)
-			if p1.Error != nil {
-				fatalf("load cmd/cgo: %v", p1.Error)
-			}
-			a.cgo = b.action(depMode, depMode, p1)
-			a.deps = append(a.deps, a.cgo)
-		}
-	}
-
-	if p.Standard {
-		switch p.ImportPath {
-		case "builtin", "unsafe":
-			// Fake packages - nothing to build.
-			return a
-		}
-		// gccgo standard library is "fake" too.
-		if _, ok := buildToolchain.(gccgoToolchain); ok {
-			// the target name is needed for cgo.
-			a.target = p.target
-			return a
-		}
-	}
-
-	if !p.Stale && p.target != "" {
-		// p.Stale==false implies that p.target is up-to-date.
-		// Record target name for use by actions depending on this one.
-		a.target = p.target
-		return a
-	}
-
-	if p.local && p.target == "" {
-		// Imported via local path. No permanent target.
-		mode = modeBuild
-	}
-	work := p.pkgdir
-	if work == "" {
-		work = b.work
-	}
-	a.objdir = filepath.Join(work, a.p.ImportPath, "_obj") + string(filepath.Separator)
-	a.objpkg = buildToolchain.pkgpath(work, a.p)
-	a.link = p.Name == "main"
-
-	switch mode {
-	case modeInstall:
-		a.f = (*builder).install
-		a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)}
-		a.target = a.p.target
-
-		// Install header for cgo in c-archive and c-shared modes.
-		if p.usesCgo() && (buildBuildmode == "c-archive" || buildBuildmode == "c-shared") {
-			hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
-			if buildContext.Compiler == "gccgo" {
-				// For the header file, remove the "lib"
-				// added by go/build, so we generate pkg.h
-				// rather than libpkg.h.
-				dir, file := filepath.Split(hdrTarget)
-				file = strings.TrimPrefix(file, "lib")
-				hdrTarget = filepath.Join(dir, file)
-			}
-			ah := &action{
-				p:      a.p,
-				deps:   []*action{a.deps[0]},
-				f:      (*builder).installHeader,
-				pkgdir: a.pkgdir,
-				objdir: a.objdir,
-				target: hdrTarget,
-			}
-			a.deps = append(a.deps, ah)
-		}
-
-	case modeBuild:
-		a.f = (*builder).build
-		a.target = a.objpkg
-		if a.link {
-			// An executable file. (This is the name of a temporary file.)
-			// Because we run the temporary file in 'go run' and 'go test',
-			// 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
-			// to create a top-level package named exe.
-			name := "a.out"
-			if p.exeName != "" {
-				name = p.exeName
-			} else if goos == "darwin" && buildBuildmode == "c-shared" && p.target != "" {
-				// On OS X, the linker output name gets recorded in the
-				// shared library's LC_ID_DYLIB load command.
-				// The code invoking the linker knows to pass only the final
-				// path element. Arrange that the path element matches what
-				// we'll install it as; otherwise the library is only loadable as "a.out".
-				_, name = filepath.Split(p.target)
-			}
-			a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
-		}
-	}
-
-	return a
-}
-
-func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
-	a := &action{}
-	switch mode {
-	default:
-		fatalf("unrecognized mode %v", mode)
-
-	case modeBuild:
-		a.f = (*builder).linkShared
-		a.target = filepath.Join(b.work, libname)
-		for _, p := range pkgs {
-			if p.target == "" {
-				continue
-			}
-			a.deps = append(a.deps, b.action(depMode, depMode, p))
-		}
-
-	case modeInstall:
-		// Currently build mode shared forces external linking mode, and
-		// external linking mode forces an import of runtime/cgo (and
-		// math on arm). So if it was not passed on the command line and
-		// it is not present in another shared library, add it here.
-		_, gccgo := buildToolchain.(gccgoToolchain)
-		if !gccgo {
-			seencgo := false
-			for _, p := range pkgs {
-				seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
-			}
-			if !seencgo {
-				var stk importStack
-				p := loadPackage("runtime/cgo", &stk)
-				if p.Error != nil {
-					fatalf("load runtime/cgo: %v", p.Error)
-				}
-				computeStale(p)
-				// If runtime/cgo is in another shared library, then that's
-				// also the shared library that contains runtime, so
-				// something will depend on it and so runtime/cgo's staleness
-				// will be checked when processing that library.
-				if p.Shlib == "" || p.Shlib == libname {
-					pkgs = append([]*Package{}, pkgs...)
-					pkgs = append(pkgs, p)
-				}
-			}
-			if goarch == "arm" {
-				seenmath := false
-				for _, p := range pkgs {
-					seenmath = seenmath || (p.Standard && p.ImportPath == "math")
-				}
-				if !seenmath {
-					var stk importStack
-					p := loadPackage("math", &stk)
-					if p.Error != nil {
-						fatalf("load math: %v", p.Error)
-					}
-					computeStale(p)
-					// If math is in another shared library, then that's
-					// also the shared library that contains runtime, so
-					// something will depend on it and so math's staleness
-					// will be checked when processing that library.
-					if p.Shlib == "" || p.Shlib == libname {
-						pkgs = append([]*Package{}, pkgs...)
-						pkgs = append(pkgs, p)
-					}
-				}
-			}
-		}
-
-		// Figure out where the library will go.
-		var libdir string
-		for _, p := range pkgs {
-			plibdir := p.build.PkgTargetRoot
-			if gccgo {
-				plibdir = filepath.Join(plibdir, "shlibs")
-			}
-			if libdir == "" {
-				libdir = plibdir
-			} else if libdir != plibdir {
-				fatalf("multiple roots %s & %s", libdir, plibdir)
-			}
-		}
-		a.target = filepath.Join(libdir, libname)
-
-		// Now we can check whether we need to rebuild it.
-		stale := false
-		var built time.Time
-		if fi, err := os.Stat(a.target); err == nil {
-			built = fi.ModTime()
-		}
-		for _, p := range pkgs {
-			if p.target == "" {
-				continue
-			}
-			stale = stale || p.Stale
-			lstat, err := os.Stat(p.target)
-			if err != nil || lstat.ModTime().After(built) {
-				stale = true
-			}
-			a.deps = append(a.deps, b.action1(depMode, depMode, p, false, a.target))
-		}
-
-		if stale {
-			a.f = (*builder).install
-			buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
-			a.deps = []*action{buildAction}
-			for _, p := range pkgs {
-				if p.target == "" {
-					continue
-				}
-				shlibnameaction := &action{}
-				shlibnameaction.f = (*builder).installShlibname
-				shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
-				a.deps = append(a.deps, shlibnameaction)
-				shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
-			}
-		}
-	}
-	return a
-}
-
-// actionList returns the list of actions in the dag rooted at root
-// as visited in a depth-first post-order traversal.
-func actionList(root *action) []*action {
-	seen := map[*action]bool{}
-	all := []*action{}
-	var walk func(*action)
-	walk = func(a *action) {
-		if seen[a] {
-			return
-		}
-		seen[a] = true
-		for _, a1 := range a.deps {
-			walk(a1)
-		}
-		all = append(all, a)
-	}
-	walk(root)
-	return all
-}
-
-// allArchiveActions returns a list of the archive dependencies of root.
-// This is needed because if package p depends on package q that is in libr.so, the
-// action graph looks like p->libr.so->q and so just scanning through p's
-// dependencies does not find the import dir for q.
-func allArchiveActions(root *action) []*action {
-	seen := map[*action]bool{}
-	r := []*action{}
-	var walk func(*action)
-	walk = func(a *action) {
-		if seen[a] {
-			return
-		}
-		seen[a] = true
-		if strings.HasSuffix(a.target, ".so") || a == root {
-			for _, a1 := range a.deps {
-				walk(a1)
-			}
-		} else if strings.HasSuffix(a.target, ".a") {
-			r = append(r, a)
-		}
-	}
-	walk(root)
-	return r
-}
-
-// do runs the action graph rooted at root.
-func (b *builder) do(root *action) {
-	if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok && buildContext.Compiler == "gc" {
-		fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
-		os.Exit(2)
-	}
-
-	// Build list of all actions, assigning depth-first post-order priority.
-	// 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
-	// 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
-	// 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.
-	all := actionList(root)
-	for i, a := range all {
-		a.priority = i
-	}
-
-	b.readySema = make(chan bool, len(all))
-
-	// Initialize per-action execution state.
-	for _, a := range all {
-		for _, a1 := range a.deps {
-			a1.triggers = append(a1.triggers, a)
-		}
-		a.pending = len(a.deps)
-		if a.pending == 0 {
-			b.ready.push(a)
-			b.readySema <- true
-		}
-	}
-
-	// Handle runs a single action and takes care of triggering
-	// any actions that are runnable as a result.
-	handle := func(a *action) {
-		var err error
-		if a.f != nil && (!a.failed || a.ignoreFail) {
-			err = a.f(b, a)
-		}
-
-		// The actions run in parallel but all the updates to the
-		// shared work state are serialized through b.exec.
-		b.exec.Lock()
-		defer b.exec.Unlock()
-
-		if err != nil {
-			if err == errPrintedOutput {
-				setExitStatus(2)
-			} else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK {
-				// Ignore the "no buildable Go source files" error for a package with only test files.
-			} else {
-				errorf("%s", err)
-			}
-			a.failed = true
-		}
-
-		for _, a0 := range a.triggers {
-			if a.failed {
-				a0.failed = true
-			}
-			if a0.pending--; a0.pending == 0 {
-				b.ready.push(a0)
-				b.readySema <- true
-			}
-		}
-
-		if a == root {
-			close(b.readySema)
-		}
-	}
-
-	var wg sync.WaitGroup
-
-	// Kick off goroutines according to parallelism.
-	// If we are using the -n flag (just printing commands)
-	// drop the parallelism to 1, both to make the output
-	// deterministic and because there is no real work anyway.
-	par := buildP
-	if buildN {
-		par = 1
-	}
-	for i := 0; i < par; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			for {
-				select {
-				case _, ok := <-b.readySema:
-					if !ok {
-						return
-					}
-					// Receiving a value from b.readySema entitles
-					// us to take from the ready queue.
-					b.exec.Lock()
-					a := b.ready.pop()
-					b.exec.Unlock()
-					handle(a)
-				case <-interrupted:
-					setExitStatus(1)
-					return
-				}
-			}
-		}()
-	}
-
-	wg.Wait()
-}
-
-// 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.
-	if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
-		return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
-			a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
-	}
-	// Same as above for Objective-C files
-	if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
-		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 _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.p.TestGoFiles) > 0) {
-			err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
-		}
-	}()
-	if buildN {
-		// In -n mode, print a banner between packages.
-		// The banner is five lines so that when changes to
-		// different sections of the bootstrap script have to
-		// be merged, the banners give patch something
-		// to use to find its context.
-		b.print("\n#\n# " + a.p.ImportPath + "\n#\n\n")
-	}
-
-	if buildV {
-		b.print(a.p.ImportPath + "\n")
-	}
-
-	// Make build directory.
-	obj := a.objdir
-	if err := b.mkdir(obj); err != nil {
-		return err
-	}
-
-	// make target directory
-	dir, _ := filepath.Split(a.target)
-	if dir != "" {
-		if err := b.mkdir(dir); err != nil {
-			return err
-		}
-	}
-
-	var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
-
-	gofiles = append(gofiles, a.p.GoFiles...)
-	cgofiles = append(cgofiles, a.p.CgoFiles...)
-	cfiles = append(cfiles, a.p.CFiles...)
-	sfiles = append(sfiles, a.p.SFiles...)
-	cxxfiles = append(cxxfiles, a.p.CXXFiles...)
-
-	if a.p.usesCgo() || a.p.usesSwig() {
-		if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
-			return
-		}
-	}
-
-	// Run SWIG on each .swig and .swigcxx file.
-	// Each run will generate two files, a .go file and a .c or .cxx file.
-	// The .go file will use import "C" and is to be processed by cgo.
-	if a.p.usesSwig() {
-		outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
-		if err != nil {
-			return err
-		}
-		objdirCgofiles = append(objdirCgofiles, outGo...)
-		cfiles = append(cfiles, outC...)
-		cxxfiles = append(cxxfiles, outCXX...)
-	}
-
-	// Run cgo.
-	if a.p.usesCgo() || a.p.usesSwig() {
-		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
-		// There is one exception: runtime/cgo's job is to bridge the
-		// cgo and non-cgo worlds, so it necessarily has files in both.
-		// 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 {
-					if strings.HasPrefix(f, "gcc_") {
-						gcc = append(gcc, f)
-					} else {
-						nongcc = append(nongcc, f)
-					}
-				}
-				return nongcc, gcc
-			}
-			sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
-		} else {
-			gccfiles = append(gccfiles, sfiles...)
-			sfiles = nil
-		}
-
-		cgoExe := tool("cgo")
-		if a.cgo != nil && a.cgo.target != "" {
-			cgoExe = a.cgo.target
-		}
-		outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, 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...)
-	}
-
-	if len(gofiles) == 0 {
-		return &build.NoGoError{Dir: a.p.Dir}
-	}
-
-	// If we're doing coverage, preprocess the .go files and put them in the work directory
-	if a.p.coverMode != "" {
-		for i, file := range gofiles {
-			var sourceFile string
-			var coverFile string
-			var key string
-			if strings.HasSuffix(file, ".cgo1.go") {
-				// cgo files have absolute paths
-				base := filepath.Base(file)
-				sourceFile = file
-				coverFile = filepath.Join(obj, base)
-				key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
-			} else {
-				sourceFile = filepath.Join(a.p.Dir, file)
-				coverFile = filepath.Join(obj, file)
-				key = file
-			}
-			cover := a.p.coverVars[key]
-			if cover == nil || isTestFile(file) {
-				// Not covering this file.
-				continue
-			}
-			if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
-				return err
-			}
-			gofiles[i] = coverFile
-		}
-	}
-
-	// Prepare Go import path list.
-	inc := b.includeArgs("-I", allArchiveActions(a))
-
-	// Compile Go.
-	ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles)
-	if len(out) > 0 {
-		b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
-		if err != nil {
-			return errPrintedOutput
-		}
-	}
-	if err != nil {
-		return err
-	}
-	if ofile != a.objpkg {
-		objects = append(objects, ofile)
-	}
-
-	// Copy .h files named for goos or goarch or goos_goarch
-	// to names using GOOS and GOARCH.
-	// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
-	_goos_goarch := "_" + goos + "_" + goarch
-	_goos := "_" + goos
-	_goarch := "_" + goarch
-	for _, file := range a.p.HFiles {
-		name, ext := fileExtSplit(file)
-		switch {
-		case strings.HasSuffix(name, _goos_goarch):
-			targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
-				return err
-			}
-		case strings.HasSuffix(name, _goarch):
-			targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
-				return err
-			}
-		case strings.HasSuffix(name, _goos):
-			targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil {
-				return err
-			}
-		}
-	}
-
-	for _, file := range cfiles {
-		out := file[:len(file)-len(".c")] + ".o"
-		if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
-			return err
-		}
-		objects = append(objects, out)
-	}
-
-	// Assemble .s files.
-	if len(sfiles) > 0 {
-		ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
-		if err != nil {
-			return err
-		}
-		objects = append(objects, ofiles...)
-	}
-
-	// 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.
-	// https://golang.org/issue/2601
-	objects = append(objects, cgoObjects...)
-
-	// Add system object files.
-	for _, syso := range a.p.SysoFiles {
-		objects = append(objects, filepath.Join(a.p.Dir, syso))
-	}
-
-	// Pack into archive in obj directory.
-	// If the Go compiler wrote an archive, we only need to add the
-	// object files for non-Go sources to the archive.
-	// If the Go compiler wrote an archive and the package is entirely
-	// Go sources, there is no pack to execute at all.
-	if len(objects) > 0 {
-		if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
-			return err
-		}
-	}
-
-	// Link if needed.
-	if a.link {
-		// The compiler only cares about direct imports, but the
-		// linker needs the whole dependency tree.
-		all := actionList(a)
-		all = all[:len(all)-1] // drop a
-		if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// pkgconfigCmd returns a pkg-config binary name
-// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist.
-func (b *builder) pkgconfigCmd() string {
-	return envList("PKG_CONFIG", defaultPkgConfig)[0]
-}
-
-// splitPkgConfigOutput parses the pkg-config output into a slice of
-// flags. pkg-config always uses \ to escape special characters.
-func splitPkgConfigOutput(out []byte) []string {
-	if len(out) == 0 {
-		return nil
-	}
-	var flags []string
-	flag := make([]byte, len(out))
-	r, w := 0, 0
-	for r < len(out) {
-		switch out[r] {
-		case ' ', '\t', '\r', '\n':
-			if w > 0 {
-				flags = append(flags, string(flag[:w]))
-			}
-			w = 0
-		case '\\':
-			r++
-			fallthrough
-		default:
-			if r < len(out) {
-				flag[w] = out[r]
-				w++
-			}
-		}
-		r++
-	}
-	if w > 0 {
-		flags = append(flags, string(flag[:w]))
-	}
-	return flags
-}
-
-// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
-func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
-	if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
-		var out []byte
-		out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
-		if err != nil {
-			b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
-			b.print(err.Error() + "\n")
-			err = errPrintedOutput
-			return
-		}
-		if len(out) > 0 {
-			cflags = splitPkgConfigOutput(out)
-		}
-		out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
-		if err != nil {
-			b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
-			b.print(err.Error() + "\n")
-			err = errPrintedOutput
-			return
-		}
-		if len(out) > 0 {
-			ldflags = strings.Fields(string(out))
-		}
-	}
-	return
-}
-
-func (b *builder) installShlibname(a *action) error {
-	a1 := a.deps[0]
-	err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0666)
-	if err != nil {
-		return err
-	}
-	if buildX {
-		b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target)
-	}
-	return nil
-}
-
-func (b *builder) linkShared(a *action) (err error) {
-	allactions := actionList(a)
-	allactions = allactions[:len(allactions)-1]
-	return buildToolchain.ldShared(b, a.deps, a.target, allactions)
-}
-
-// install is the action for installing a single package or executable.
-func (b *builder) install(a *action) (err error) {
-	defer func() {
-		if err != nil && err != errPrintedOutput {
-			err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err)
-		}
-	}()
-	a1 := a.deps[0]
-	perm := os.FileMode(0666)
-	if a1.link {
-		switch buildBuildmode {
-		case "c-archive", "c-shared", "plugin":
-		default:
-			perm = 0777
-		}
-	}
-
-	// make target directory
-	dir, _ := filepath.Split(a.target)
-	if dir != "" {
-		if err := b.mkdir(dir); err != nil {
-			return err
-		}
-	}
-
-	// remove object dir to keep the amount of
-	// 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 {
-		defer os.RemoveAll(a1.objdir)
-		defer os.Remove(a1.target)
-	}
-
-	return b.moveOrCopyFile(a, a.target, a1.target, perm, false)
-}
-
-// includeArgs returns the -I or -L directory list for access
-// to the results of the list of actions.
-func (b *builder) includeArgs(flag string, all []*action) []string {
-	inc := []string{}
-	incMap := map[string]bool{
-		b.work:    true, // handled later
-		gorootPkg: true,
-		"":        true, // ignore empty strings
-	}
-
-	// Look in the temporary space for results of test-specific actions.
-	// This is the $WORK/my/package/_test directory for the
-	// package being built, so there are few of these.
-	for _, a1 := range all {
-		if a1.p == nil {
-			continue
-		}
-		if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
-			incMap[dir] = true
-			inc = append(inc, flag, dir)
-		}
-	}
-
-	// Also look in $WORK for any non-test packages that have
-	// been built but not installed.
-	inc = append(inc, flag, b.work)
-
-	// Finally, look in the installed package directories for each action.
-	// First add the package dirs corresponding to GOPATH entries
-	// in the original GOPATH order.
-	need := map[string]*build.Package{}
-	for _, a1 := range all {
-		if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot {
-			need[a1.p.build.Root] = a1.p.build
-		}
-	}
-	for _, root := range gopath {
-		if p := need[root]; p != nil && !incMap[p.PkgRoot] {
-			incMap[p.PkgRoot] = true
-			inc = append(inc, flag, p.PkgTargetRoot)
-		}
-	}
-
-	// Then add anything that's left.
-	for _, a1 := range all {
-		if a1.p == nil {
-			continue
-		}
-		if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
-			incMap[dir] = true
-			inc = append(inc, flag, a1.p.build.PkgTargetRoot)
-		}
-	}
-
-	return inc
-}
-
-// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
-func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, force bool) error {
-	if buildN {
-		b.showcmd("", "mv %s %s", src, dst)
-		return nil
-	}
-
-	// If we can update the mode and rename to the dst, do it.
-	// Otherwise fall back to standard copy.
-
-	// The perm argument is meant to be adjusted according to umask,
-	// but we don't know what the umask is.
-	// Create a dummy file to find out.
-	// This avoids build tags and works even on systems like Plan 9
-	// where the file mask computation incorporates other information.
-	mode := perm
-	f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
-	if err == nil {
-		fi, err := f.Stat()
-		if err == nil {
-			mode = fi.Mode() & 0777
-		}
-		name := f.Name()
-		f.Close()
-		os.Remove(name)
-	}
-
-	if err := os.Chmod(src, mode); err == nil {
-		if err := os.Rename(src, dst); err == nil {
-			if buildX {
-				b.showcmd("", "mv %s %s", src, dst)
-			}
-			return nil
-		}
-	}
-
-	return b.copyFile(a, dst, src, perm, force)
-}
-
-// copyFile is like 'cp src dst'.
-func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force bool) error {
-	if buildN || buildX {
-		b.showcmd("", "cp %s %s", src, dst)
-		if buildN {
-			return nil
-		}
-	}
-
-	sf, err := os.Open(src)
-	if err != nil {
-		return err
-	}
-	defer sf.Close()
-
-	// Be careful about removing/overwriting dst.
-	// Do not remove/overwrite if dst exists and is a directory
-	// or a non-object file.
-	if fi, err := os.Stat(dst); err == nil {
-		if fi.IsDir() {
-			return fmt.Errorf("build output %q already exists and is a directory", dst)
-		}
-		if !force && fi.Mode().IsRegular() && !isObject(dst) {
-			return fmt.Errorf("build output %q already exists and is not an object file", dst)
-		}
-	}
-
-	// On Windows, remove lingering ~ file from last attempt.
-	if toolIsWindows {
-		if _, err := os.Stat(dst + "~"); err == nil {
-			os.Remove(dst + "~")
-		}
-	}
-
-	mayberemovefile(dst)
-	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.
-		// 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 {
-			os.Remove(dst + "~")
-		}
-		df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
-	}
-	if err != nil {
-		return err
-	}
-
-	_, err = io.Copy(df, sf)
-	df.Close()
-	if err != nil {
-		mayberemovefile(dst)
-		return fmt.Errorf("copying %s to %s: %v", src, dst, err)
-	}
-	return nil
-}
-
-// Install the cgo export header file, if there is one.
-func (b *builder) installHeader(a *action) error {
-	src := a.objdir + "_cgo_install.h"
-	if _, err := os.Stat(src); os.IsNotExist(err) {
-		// If the file does not exist, there are no exported
-		// functions, and we do not install anything.
-		return nil
-	}
-
-	dir, _ := filepath.Split(a.target)
-	if dir != "" {
-		if err := b.mkdir(dir); err != nil {
-			return err
-		}
-	}
-
-	return b.moveOrCopyFile(a, a.target, src, 0666, true)
-}
-
-// cover runs, in effect,
-//	go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
-func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
-	return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
-		buildToolExec,
-		tool("cover"),
-		"-mode", a.p.coverMode,
-		"-var", varName,
-		"-o", dst,
-		src)
-}
-
-var objectMagic = [][]byte{
-	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
-	{'\x7F', 'E', 'L', 'F'},                   // ELF
-	{0xFE, 0xED, 0xFA, 0xCE},                  // Mach-O big-endian 32-bit
-	{0xFE, 0xED, 0xFA, 0xCF},                  // Mach-O big-endian 64-bit
-	{0xCE, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 32-bit
-	{0xCF, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 64-bit
-	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},      // PE (Windows) as generated by 6l/8l and gcc
-	{0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
-	{0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
-	{0x00, 0x00, 0x06, 0x47},                  // Plan 9 arm
-}
-
-func isObject(s string) bool {
-	f, err := os.Open(s)
-	if err != nil {
-		return false
-	}
-	defer f.Close()
-	buf := make([]byte, 64)
-	io.ReadFull(f, buf)
-	for _, magic := range objectMagic {
-		if bytes.HasPrefix(buf, magic) {
-			return true
-		}
-	}
-	return false
-}
-
-// mayberemovefile removes a file only if it is a regular file
-// When running as a user with sufficient privileges, we may delete
-// even device files, for example, which is not intended.
-func mayberemovefile(s string) {
-	if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
-		return
-	}
-	os.Remove(s)
-}
-
-// fmtcmd formats a command in the manner of fmt.Sprintf but also:
-//
-//	If dir is non-empty and the script is not in dir right now,
-//	fmtcmd inserts "cd dir\n" before the command.
-//
-//	fmtcmd replaces the value of b.work with $WORK.
-//	fmtcmd replaces the value of goroot with $GOROOT.
-//	fmtcmd replaces the value of b.gobin with $GOBIN.
-//
-//	fmtcmd replaces the name of the current directory with dot (.)
-//	but only when it is at the beginning of a space-separated token.
-//
-func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
-	cmd := fmt.Sprintf(format, args...)
-	if dir != "" && dir != "/" {
-		cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
-		if b.scriptDir != dir {
-			b.scriptDir = dir
-			cmd = "cd " + dir + "\n" + cmd
-		}
-	}
-	if b.work != "" {
-		cmd = strings.Replace(cmd, b.work, "$WORK", -1)
-	}
-	return cmd
-}
-
-// showcmd prints the given command to standard output
-// for the implementation of -n or -x.
-func (b *builder) showcmd(dir string, format string, args ...interface{}) {
-	b.output.Lock()
-	defer b.output.Unlock()
-	b.print(b.fmtcmd(dir, format, args...) + "\n")
-}
-
-// showOutput prints "# desc" followed by the given output.
-// 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.
-// For example, if fmt doesn't compile and we are in src/html,
-// the output is
-//
-//	$ go build
-//	# fmt
-//	../fmt/print.go:1090: undefined: asdf
-//	$
-//
-// instead of
-//
-//	$ go build
-//	# fmt
-//	/usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
-//	$
-//
-// showOutput also replaces references to the work directory with $WORK.
-//
-func (b *builder) showOutput(dir, desc, out string) {
-	prefix := "# " + desc
-	suffix := "\n" + out
-	if reldir := shortPath(dir); reldir != dir {
-		suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
-		suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
-	}
-	suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1)
-
-	b.output.Lock()
-	defer b.output.Unlock()
-	b.print(prefix, suffix)
-}
-
-// shortPath returns an absolute or relative name for path, whatever is shorter.
-func shortPath(path string) string {
-	if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
-		return rel
-	}
-	return path
-}
-
-// relPaths returns a copy of paths with absolute paths
-// made relative to the current directory if they would be shorter.
-func relPaths(paths []string) []string {
-	var out []string
-	pwd, _ := os.Getwd()
-	for _, p := range paths {
-		rel, err := filepath.Rel(pwd, p)
-		if err == nil && len(rel) < len(p) {
-			p = rel
-		}
-		out = append(out, p)
-	}
-	return out
-}
-
-// 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
-// print this error.
-var errPrintedOutput = errors.New("already printed output - no need to show error")
-
-var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
-var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
-
-// run runs the command given by cmdline in the directory dir.
-// If the command fails, run prints information about the failure
-// and returns a non-nil error.
-func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
-	out, err := b.runOut(dir, desc, env, cmdargs...)
-	if len(out) > 0 {
-		if desc == "" {
-			desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
-		}
-		b.showOutput(dir, desc, b.processOutput(out))
-		if err != nil {
-			err = errPrintedOutput
-		}
-	}
-	return err
-}
-
-// processOutput prepares the output of runOut to be output to the console.
-func (b *builder) processOutput(out []byte) string {
-	if out[len(out)-1] != '\n' {
-		out = append(out, '\n')
-	}
-	messages := string(out)
-	// Fix up output referring to cgo-generated code to be more readable.
-	// Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
-	// Replace *[100]_Ctype_foo with *[100]C.foo.
-	// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
-	if !buildX && cgoLine.MatchString(messages) {
-		messages = cgoLine.ReplaceAllString(messages, "")
-		messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
-	}
-	return messages
-}
-
-// runOut runs the command given by cmdline in the directory dir.
-// It returns the command output and any errors that occurred.
-func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
-	cmdline := stringList(cmdargs...)
-	if buildN || buildX {
-		var envcmdline string
-		for i := range env {
-			envcmdline += env[i]
-			envcmdline += " "
-		}
-		envcmdline += joinUnambiguously(cmdline)
-		b.showcmd(dir, "%s", envcmdline)
-		if buildN {
-			return nil, nil
-		}
-	}
-
-	nbusy := 0
-	for {
-		var buf bytes.Buffer
-		cmd := exec.Command(cmdline[0], cmdline[1:]...)
-		cmd.Stdout = &buf
-		cmd.Stderr = &buf
-		cmd.Dir = dir
-		cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir, os.Environ()))
-		err := cmd.Run()
-
-		// cmd.Run will fail on Unix if some other process has the binary
-		// 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
-		// a reference to the fd, keeping us from running exec.
-		//
-		// But, you might reasonably wonder, how can this happen?
-		// The cgo fd, like all our fds, is close-on-exec, so that we need
-		// not worry about other processes inheriting the fd accidentally.
-		// 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
-		// 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
-		// 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)
-		// only guarantees that when it returns, the exec is committed to
-		// 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
-		// guaranteed to be gone.
-		//
-		// Sleeping when we observe the race seems to be the most reliable
-		// option we have.
-		//
-		// https://golang.org/issue/3001
-		//
-		if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
-			time.Sleep(100 * time.Millisecond << uint(nbusy))
-			nbusy++
-			continue
-		}
-
-		// err can be something like 'exit status 1'.
-		// Add information about what program was running.
-		// Note that if buf.Bytes() is non-empty, the caller usually
-		// shows buf.Bytes() and does not print err at all, so the
-		// prefix here does not make most output any more verbose.
-		if err != nil {
-			err = errors.New(cmdline[0] + ": " + err.Error())
-		}
-		return buf.Bytes(), err
-	}
-}
-
-// joinUnambiguously prints the slice, quoting where necessary to make the
-// output unambiguous.
-// TODO: See issue 5279. The printing of commands needs a complete redo.
-func joinUnambiguously(a []string) string {
-	var buf bytes.Buffer
-	for i, s := range a {
-		if i > 0 {
-			buf.WriteByte(' ')
-		}
-		q := strconv.Quote(s)
-		if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 {
-			buf.WriteString(q)
-		} else {
-			buf.WriteString(s)
-		}
-	}
-	return buf.String()
-}
-
-// mkdir makes the named directory.
-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.
-	if b.mkdirCache[dir] {
-		return nil
-	}
-	b.mkdirCache[dir] = true
-
-	if buildN || buildX {
-		b.showcmd("", "mkdir -p %s", dir)
-		if buildN {
-			return nil
-		}
-	}
-
-	if err := os.MkdirAll(dir, 0777); err != nil {
-		return err
-	}
-	return nil
-}
-
-// mkAbs returns an absolute path corresponding to
-// evaluating f in the directory dir.
-// We always pass absolute paths of source files so that
-// the error messages will include the full path to a file
-// in need of attention.
-func mkAbs(dir, f string) string {
-	// Leave absolute paths alone.
-	// Also, during -n mode we use the pseudo-directory $WORK
-	// instead of creating an actual work directory that won't be used.
-	// Leave paths beginning with $WORK alone too.
-	if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
-		return f
-	}
-	return filepath.Join(dir, f)
-}
-
-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.
-	gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
-	// cc runs the toolchain's C compiler in a directory on a C file
-	// to produce an output file.
-	cc(b *builder, p *Package, objdir, ofile, cfile string) error
-	// asm runs the assembler in a specific directory on specific files
-	// and returns a list of named output files.
-	asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error)
-	// pkgpath builds an appropriate path for a temporary package file.
-	pkgpath(basedir string, p *Package) string
-	// pack runs the archive packer in a specific directory to create
-	// an archive from a set of object files.
-	// typically it is run in the object directory.
-	pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
-	// ld runs the linker to create an executable starting at mainpkg.
-	ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error
-	// ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
-	ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error
-
-	compiler() string
-	linker() string
-}
-
-type noToolchain struct{}
-
-func noCompiler() error {
-	log.Fatalf("unknown compiler %q", buildContext.Compiler)
-	return nil
-}
-
-func (noToolchain) compiler() string {
-	noCompiler()
-	return ""
-}
-
-func (noToolchain) linker() string {
-	noCompiler()
-	return ""
-}
-
-func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
-	return "", nil, noCompiler()
-}
-
-func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
-	return nil, noCompiler()
-}
-
-func (noToolchain) pkgpath(basedir string, p *Package) string {
-	noCompiler()
-	return ""
-}
-
-func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
-	return noCompiler()
-}
-
-func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
-	return noCompiler()
-}
-
-func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
-	return noCompiler()
-}
-
-func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	return noCompiler()
-}
-
-// The Go toolchain.
-type gcToolchain struct{}
-
-func (gcToolchain) compiler() string {
-	return tool("compile")
-}
-
-func (gcToolchain) linker() string {
-	return tool("link")
-}
-
-func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
-	if archive != "" {
-		ofile = archive
-	} else {
-		out := "_go_.o"
-		ofile = obj + out
-	}
-
-	gcargs := []string{"-p", p.ImportPath}
-	if p.Name == "main" {
-		gcargs[1] = "main"
-	}
-	if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) {
-		// runtime compiles with a special gc flag to emit
-		// additional reflect type data.
-		gcargs = append(gcargs, "-+")
-	}
-
-	// If we're giving the compiler the entire package (no C etc files), tell it that,
-	// 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.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":
-			extFiles++
-		}
-	}
-	if extFiles == 0 {
-		gcargs = append(gcargs, "-complete")
-	}
-	if buildContext.InstallSuffix != "" {
-		gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
-	}
-	if p.buildID != "" {
-		gcargs = append(gcargs, "-buildid", p.buildID)
-	}
-
-	for _, path := range p.Imports {
-		if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
-			gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
-		} else if strings.HasPrefix(path, "vendor/") {
-			gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
-		}
-	}
-
-	args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
-	if ofile == archive {
-		args = append(args, "-pack")
-	}
-	if asmhdr {
-		args = append(args, "-asmhdr", obj+"go_asm.h")
-	}
-	for _, f := range gofiles {
-		args = append(args, mkAbs(p.Dir, f))
-	}
-
-	output, err = b.runOut(p.Dir, p.ImportPath, nil, args...)
-	return ofile, output, err
-}
-
-func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
-	// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
-	inc := filepath.Join(goroot, "pkg", "include")
-	args := []interface{}{buildToolExec, tool("asm"), "-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")
-			}
-		}
-	}
-	var ofiles []string
-	for _, sfile := range sfiles {
-		ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
-		ofiles = append(ofiles, ofile)
-		a := append(args, "-o", ofile, mkAbs(p.Dir, sfile))
-		if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil {
-			return nil, err
-		}
-	}
-	return ofiles, nil
-}
-
-// toolVerify checks that the command line args writes the same output file
-// if run using newTool instead.
-// Unused now but kept around for future use.
-func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error {
-	newArgs := make([]interface{}, len(args))
-	copy(newArgs, args)
-	newArgs[1] = tool(newTool)
-	newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
-	if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
-		return err
-	}
-	data1, err := ioutil.ReadFile(ofile)
-	if err != nil {
-		return err
-	}
-	data2, err := ioutil.ReadFile(ofile + ".new")
-	if err != nil {
-		return err
-	}
-	if !bytes.Equal(data1, data2) {
-		return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(stringList(args...), " "), strings.Join(stringList(newArgs...), " "))
-	}
-	os.Remove(ofile + ".new")
-	return nil
-}
-
-func (gcToolchain) pkgpath(basedir string, p *Package) string {
-	end := filepath.FromSlash(p.ImportPath + ".a")
-	return filepath.Join(basedir, end)
-}
-
-func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
-	var absOfiles []string
-	for _, f := range ofiles {
-		absOfiles = append(absOfiles, mkAbs(objDir, f))
-	}
-	absAfile := mkAbs(objDir, afile)
-
-	// The archive file should have been created by the compiler.
-	// Since it used to not work that way, verify.
-	if !buildN {
-		if _, err := os.Stat(absAfile); err != nil {
-			fatalf("os.Stat of archive file failed: %v", err)
-		}
-	}
-
-	if buildN || buildX {
-		cmdline := stringList("pack", "r", absAfile, absOfiles)
-		b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
-	}
-	if buildN {
-		return nil
-	}
-	if err := packInternal(b, absAfile, absOfiles); err != nil {
-		b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
-		return errPrintedOutput
-	}
-	return nil
-}
-
-func packInternal(b *builder, afile string, ofiles []string) error {
-	dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
-	if err != nil {
-		return err
-	}
-	defer dst.Close() // only for error returns or panics
-	w := bufio.NewWriter(dst)
-
-	for _, ofile := range ofiles {
-		src, err := os.Open(ofile)
-		if err != nil {
-			return err
-		}
-		fi, err := src.Stat()
-		if err != nil {
-			src.Close()
-			return err
-		}
-		// Note: Not using %-16.16s format because we care
-		// about bytes, not runes.
-		name := fi.Name()
-		if len(name) > 16 {
-			name = name[:16]
-		} else {
-			name += strings.Repeat(" ", 16-len(name))
-		}
-		size := fi.Size()
-		fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
-			name, 0, 0, 0, 0644, size)
-		n, err := io.Copy(w, src)
-		src.Close()
-		if err == nil && n < size {
-			err = io.ErrUnexpectedEOF
-		} else if err == nil && n > size {
-			err = fmt.Errorf("file larger than size reported by stat")
-		}
-		if err != nil {
-			return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
-		}
-		if size&1 != 0 {
-			w.WriteByte(0)
-		}
-	}
-
-	if err := w.Flush(); err != nil {
-		return err
-	}
-	return dst.Close()
-}
-
-// setextld sets the appropriate linker flags for the specified compiler.
-func setextld(ldflags []string, compiler []string) []string {
-	for _, f := range ldflags {
-		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-			// don't override -extld if supplied
-			return ldflags
-		}
-	}
-	ldflags = append(ldflags, "-extld="+compiler[0])
-	if len(compiler) > 1 {
-		extldflags := false
-		add := strings.Join(compiler[1:], " ")
-		for i, f := range ldflags {
-			if f == "-extldflags" && i+1 < len(ldflags) {
-				ldflags[i+1] = add + " " + ldflags[i+1]
-				extldflags = true
-				break
-			} else if strings.HasPrefix(f, "-extldflags=") {
-				ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-				extldflags = true
-				break
-			}
-		}
-		if !extldflags {
-			ldflags = append(ldflags, "-extldflags="+add)
-		}
-	}
-	return ldflags
-}
-
-func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
-	importArgs := b.includeArgs("-L", allactions)
-	cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
-	for _, a := range allactions {
-		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
-			cxx = true
-		}
-	}
-	var ldflags []string
-	if buildContext.InstallSuffix != "" {
-		ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
-	}
-	if root.p.omitDWARF {
-		ldflags = append(ldflags, "-w")
-	}
-	if buildBuildmode == "plugin" {
-		pluginpath := root.p.ImportPath
-		if pluginpath == "command-line-arguments" {
-			pluginpath = "plugin/unnamed-" + root.p.buildID
-		}
-		ldflags = append(ldflags, "-pluginpath", pluginpath)
-	}
-
-	// If the user has not specified the -extld option, then specify the
-	// appropriate linker. In case of C++ code, use the compiler named
-	// by the CXX environment variable or defaultCXX if CXX is not set.
-	// Else, use the CC environment variable and defaultCC as fallback.
-	var compiler []string
-	if cxx {
-		compiler = envList("CXX", defaultCXX)
-	} else {
-		compiler = envList("CC", defaultCC)
-	}
-	ldflags = setextld(ldflags, compiler)
-	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
-	if root.p.buildID != "" {
-		ldflags = append(ldflags, "-buildid="+root.p.buildID)
-	}
-	ldflags = append(ldflags, buildLdflags...)
-
-	// On OS X when using external linking to build a shared library,
-	// the argument passed here to -o ends up recorded in the final
-	// shared library in the LC_ID_DYLIB load command.
-	// To avoid putting the temporary output directory name there
-	// (and making the resulting shared library useless),
-	// run the link in the output directory so that -o can name
-	// just the final path element.
-	dir := "."
-	if goos == "darwin" && buildBuildmode == "c-shared" {
-		dir, out = filepath.Split(out)
-	}
-
-	return b.run(dir, root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
-}
-
-func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
-	importArgs := b.includeArgs("-L", allactions)
-	ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
-	ldflags = append(ldflags, "-buildmode=shared")
-	ldflags = append(ldflags, buildLdflags...)
-	cxx := false
-	for _, a := range allactions {
-		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
-			cxx = true
-		}
-	}
-	// If the user has not specified the -extld option, then specify the
-	// appropriate linker. In case of C++ code, use the compiler named
-	// by the CXX environment variable or defaultCXX if CXX is not set.
-	// Else, use the CC environment variable and defaultCC as fallback.
-	var compiler []string
-	if cxx {
-		compiler = envList("CXX", defaultCXX)
-	} else {
-		compiler = envList("CC", defaultCC)
-	}
-	ldflags = setextld(ldflags, compiler)
-	for _, d := range toplevelactions {
-		if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
-			continue
-		}
-		ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
-	}
-	return b.run(".", out, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags)
-}
-
-func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
-}
-
-// The Gccgo toolchain.
-type gccgoToolchain struct{}
-
-var gccgoName, gccgoBin string
-
-func init() {
-	gccgoName = os.Getenv("GCCGO")
-	if gccgoName == "" {
-		gccgoName = "gccgo"
-	}
-	gccgoBin, _ = exec.LookPath(gccgoName)
-}
-
-func (gccgoToolchain) compiler() string {
-	return gccgoBin
-}
-
-func (gccgoToolchain) linker() string {
-	return gccgoBin
-}
-
-func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
-	out := "_go_.o"
-	ofile = obj + out
-	gcargs := []string{"-g"}
-	gcargs = append(gcargs, b.gccArchArgs()...)
-	if pkgpath := gccgoPkgpath(p); pkgpath != "" {
-		gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
-	}
-	if p.localPrefix != "" {
-		gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
-	}
-	args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
-	for _, f := range gofiles {
-		args = append(args, mkAbs(p.Dir, f))
-	}
-
-	output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
-	return ofile, output, err
-}
-
-func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
-	var ofiles []string
-	for _, sfile := range sfiles {
-		ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
-		ofiles = append(ofiles, ofile)
-		sfile = mkAbs(p.Dir, sfile)
-		defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
-		if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
-			defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
-		}
-		defs = tools.maybePIC(defs)
-		defs = append(defs, b.gccArchArgs()...)
-		err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return ofiles, nil
-}
-
-func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
-	end := filepath.FromSlash(p.ImportPath + ".a")
-	afile := filepath.Join(basedir, end)
-	// add "lib" to the final element
-	return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
-}
-
-func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
-	var absOfiles []string
-	for _, f := range ofiles {
-		absOfiles = append(absOfiles, mkAbs(objDir, f))
-	}
-	return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
-}
-
-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.
-	apackagePathsSeen := make(map[string]bool)
-	afiles := []string{}
-	shlibs := []string{}
-	ldflags := b.gccArchArgs()
-	cgoldflags := []string{}
-	usesCgo := false
-	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
-	// whether a shared library action has been seen on the way to an action (the
-	// construction of the graph means that if any path to a node passes through
-	// a shared library action, they all do).
-	var walk func(a *action, seenShlib bool)
-	var err error
-	walk = func(a *action, seenShlib bool) {
-		if actionsSeen[a] {
-			return
-		}
-		actionsSeen[a] = true
-		if a.p != nil && !seenShlib {
-			if a.p.Standard {
-				return
-			}
-			// We record the target of the first time we see a .a file
-			// for a package to make sure that we prefer the 'install'
-			// rather than the 'build' location (which may not exist any
-			// more). We still need to traverse the dependencies of the
-			// build action though so saying
-			// if apackagePathsSeen[a.p.ImportPath] { return }
-			// doesn't work.
-			if !apackagePathsSeen[a.p.ImportPath] {
-				apackagePathsSeen[a.p.ImportPath] = true
-				target := a.target
-				if len(a.p.CgoFiles) > 0 || a.p.usesSwig() {
-					target, err = readAndRemoveCgoFlags(target)
-					if err != nil {
-						return
-					}
-				}
-				afiles = append(afiles, target)
-			}
-		}
-		if strings.HasSuffix(a.target, ".so") {
-			shlibs = append(shlibs, a.target)
-			seenShlib = true
-		}
-		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
-		}
-	}
-
-	for _, a := range allactions {
-		// Gather CgoLDFLAGS, but not from standard packages.
-		// The go tool can dig up runtime/cgo from GOROOT and
-		// think that it should use its CgoLDFLAGS, but gccgo
-		// doesn't use runtime/cgo.
-		if a.p == nil {
-			continue
-		}
-		if !a.p.Standard {
-			cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
-		}
-		if len(a.p.CgoFiles) > 0 {
-			usesCgo = true
-		}
-		if a.p.usesSwig() {
-			usesCgo = true
-		}
-		if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
-			cxx = true
-		}
-		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")
-	ldflags = append(ldflags, afiles...)
-	ldflags = append(ldflags, "-Wl,--no-whole-archive")
-
-	ldflags = append(ldflags, cgoldflags...)
-	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
-	if root.p != nil {
-		ldflags = append(ldflags, root.p.CgoLDFLAGS...)
-	}
-
-	ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
-
-	for _, shlib := range shlibs {
-		ldflags = append(
-			ldflags,
-			"-L"+filepath.Dir(shlib),
-			"-Wl,-rpath="+filepath.Dir(shlib),
-			"-l"+strings.TrimSuffix(
-				strings.TrimPrefix(filepath.Base(shlib), "lib"),
-				".so"))
-	}
-
-	var realOut string
-	switch buildmode {
-	case "exe":
-		if usesCgo && goos == "linux" {
-			ldflags = append(ldflags, "-Wl,-E")
-		}
-
-	case "c-archive":
-		// Link the Go files into a single .o, and also link
-		// in -lgolibbegin.
-		//
-		// We need to use --whole-archive with -lgolibbegin
-		// because it doesn't define any symbols that will
-		// cause the contents to be pulled in; it's just
-		// initialization code.
-		//
-		// The user remains responsible for linking against
-		// -lgo -lpthread -lm in the final link. We can't use
-		// -r to pick them up because we can't combine
-		// split-stack and non-split-stack code in a single -r
-		// link, and libgo picks up non-split-stack code from
-		// libffi.
-		ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
-
-		if b.gccSupportsNoPie() {
-			ldflags = append(ldflags, "-no-pie")
-		}
-
-		// We are creating an object file, so we don't want a build ID.
-		ldflags = b.disableBuildID(ldflags)
-
-		realOut = out
-		out = out + ".o"
-
-	case "c-shared":
-		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
-	case "shared":
-		ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
-
-	default:
-		fatalf("-buildmode=%s not supported for gccgo", buildmode)
-	}
-
-	switch buildmode {
-	case "exe", "c-shared":
-		if cxx {
-			ldflags = append(ldflags, "-lstdc++")
-		}
-		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(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
-		return err
-	}
-
-	switch buildmode {
-	case "c-archive":
-		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 {
-	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 {
-	inc := filepath.Join(goroot, "pkg", "include")
-	cfile = mkAbs(p.Dir, cfile)
-	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
-	defs = append(defs, b.gccArchArgs()...)
-	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
-		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
-	}
-	switch goarch {
-	case "386", "amd64":
-		defs = append(defs, "-fsplit-stack")
-	}
-	defs = tools.maybePIC(defs)
-	return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
-		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
-}
-
-// maybePIC adds -fPIC to the list of arguments if needed.
-func (tools gccgoToolchain) maybePIC(args []string) []string {
-	switch buildBuildmode {
-	case "c-shared", "shared", "plugin":
-		args = append(args, "-fPIC")
-	}
-	return args
-}
-
-func gccgoPkgpath(p *Package) string {
-	if p.build.IsCommand() && !p.forceLibrary {
-		return ""
-	}
-	return p.ImportPath
-}
-
-func gccgoCleanPkgpath(p *Package) string {
-	clean := func(r rune) rune {
-		switch {
-		case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
-			'0' <= r && r <= '9':
-			return r
-		}
-		return '_'
-	}
-	return strings.Map(clean, gccgoPkgpath(p))
-}
-
-// gcc runs the gcc C compiler to create an object from a single C file.
-func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
-	return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir))
-}
-
-// gxx runs the g++ C++ compiler to create an object from a single C++ file.
-func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) error {
-	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, outfile string, flags []string, file string, compiler []string) error {
-	file = mkAbs(p.Dir, file)
-	desc := p.ImportPath
-	output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
-	if len(output) > 0 {
-		// On FreeBSD 11, when we pass -g to clang 3.8 it
-		// invokes its internal assembler with -dwarf-version=2.
-		// When it sees .section .note.GNU-stack, it warns
-		// "DWARF2 only supports one section per compilation unit".
-		// This warning makes no sense, since the section is empty,
-		// but it confuses people.
-		// We work around the problem by detecting the warning
-		// and dropping -g and trying again.
-		if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
-			newFlags := make([]string, 0, len(flags))
-			for _, f := range flags {
-				if !strings.HasPrefix(f, "-g") {
-					newFlags = append(newFlags, f)
-				}
-			}
-			if len(newFlags) < len(flags) {
-				return b.ccompile(p, outfile, newFlags, file, compiler)
-			}
-		}
-
-		b.showOutput(p.Dir, desc, b.processOutput(output))
-		if err != nil {
-			err = errPrintedOutput
-		} else if os.Getenv("GO_BUILDER_NAME") != "" {
-			return errors.New("C compiler warning promoted to error on Go builders")
-		}
-	}
-	return err
-}
-
-// gccld runs the gcc linker to create an executable from a set of object files.
-func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
-	var cmd []string
-	if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
-		cmd = b.gxxCmd(p.Dir)
-	} else {
-		cmd = b.gccCmd(p.Dir)
-	}
-	return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags)
-}
-
-// gccCmd returns a gcc command line prefix
-// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
-func (b *builder) gccCmd(objdir string) []string {
-	return b.ccompilerCmd("CC", defaultCC, objdir)
-}
-
-// gxxCmd returns a g++ command line prefix
-// defaultCXX is defined in zdefaultcc.go, written by cmd/dist.
-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 {
-	// NOTE: env.go's mkEnv knows that the first three
-	// strings returned are "gcc", "-I", objdir (and cuts them off).
-
-	compiler := envList(envvar, defcmd)
-	a := []string{compiler[0], "-I", objdir}
-	a = append(a, compiler[1:]...)
-
-	// Definitely want -fPIC but on Windows gcc complains
-	// "-fPIC ignored for target (all code is position independent)"
-	if goos != "windows" {
-		a = append(a, "-fPIC")
-	}
-	a = append(a, b.gccArchArgs()...)
-	// gcc-4.5 and beyond require explicit "-pthread" flag
-	// for multithreading with pthread library.
-	if buildContext.CgoEnabled {
-		switch goos {
-		case "windows":
-			a = append(a, "-mthreads")
-		default:
-			a = append(a, "-pthread")
-		}
-	}
-
-	if strings.Contains(a[0], "clang") {
-		// disable ASCII art in clang errors, if possible
-		a = append(a, "-fno-caret-diagnostics")
-		// clang is too smart about command-line arguments
-		a = append(a, "-Qunused-arguments")
-	}
-
-	// 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.
-	if goos == "darwin" {
-		a = append(a, "-fno-common")
-	}
-
-	return a
-}
-
-// On systems with PIE (position independent executables) enabled by default,
-// -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 {
-	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
-	}
-	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 := append(envList("CC", defaultCC), flag, "-c", "trivial.c")
-	if buildN || buildX {
-		b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
-		if buildN {
-			return false
-		}
-	}
-	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
-	cmd.Dir = b.work
-	cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ()))
-	out, err := cmd.CombinedOutput()
-	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.
-func (b *builder) gccArchArgs() []string {
-	switch goarch {
-	case "386":
-		return []string{"-m32"}
-	case "amd64", "amd64p32":
-		return []string{"-m64"}
-	case "arm":
-		return []string{"-marm"} // not thumb
-	case "s390x":
-		return []string{"-m64", "-march=z196"}
-	case "mips64", "mips64le":
-		return []string{"-mabi=64"}
-	case "mips", "mipsle":
-		return []string{"-mabi=32", "-march=mips32"}
-	}
-	return nil
-}
-
-// envList returns the value of the given environment variable broken
-// into fields, using the default value when the variable is empty.
-func envList(key, def string) []string {
-	v := os.Getenv(key)
-	if v == "" {
-		v = def
-	}
-	return strings.Fields(v)
-}
-
-// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
-func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
-	defaults := "-g -O2"
-
-	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(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
-	p := a.p
-	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p)
-	cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
-	cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
-	// If we are compiling Objective-C code, then we need to link against libobjc
-	if len(mfiles) > 0 {
-		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 {
-		cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
-		cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
-	}
-
-	// Allows including _cgo_export.h from .[ch] files in the package.
-	cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
-
-	// If we have cgo files in the object directory, then copy any
-	// other cgo files into the object directory, and pass a
-	// -srcdir option to cgo.
-	var srcdirarg []string
-	if len(objdirCgofiles) > 0 {
-		for _, fn := range cgofiles {
-			if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil {
-				return nil, nil, err
-			}
-		}
-		cgofiles = append(cgofiles, objdirCgofiles...)
-		srcdirarg = []string{"-srcdir", obj}
-	}
-
-	// cgo
-	// TODO: CGO_FLAGS?
-	gofiles := []string{obj + "_cgo_gotypes.go"}
-	cfiles := []string{"_cgo_export.c"}
-	for _, fn := range cgofiles {
-		f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
-		gofiles = append(gofiles, obj+f+"cgo1.go")
-		cfiles = append(cfiles, f+"cgo2.c")
-	}
-
-	// TODO: make cgo not depend on $GOARCH?
-
-	cgoflags := []string{}
-	if p.Standard && p.ImportPath == "runtime/cgo" {
-		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
-	}
-	if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") {
-		cgoflags = append(cgoflags, "-import_syscall=false")
-	}
-
-	// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
-	var cgoenv []string
-	if len(cgoLDFLAGS) > 0 {
-		flags := make([]string, len(cgoLDFLAGS))
-		for i, f := range cgoLDFLAGS {
-			flags[i] = strconv.Quote(f)
-		}
-		cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
-	}
-
-	if _, ok := buildToolchain.(gccgoToolchain); ok {
-		switch goarch {
-		case "386", "amd64":
-			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
-		}
-		cgoflags = append(cgoflags, "-gccgo")
-		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
-			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
-		}
-	}
-
-	switch buildBuildmode {
-	case "c-archive", "c-shared":
-		// Tell cgo that if there are any exported functions
-		// it should generate a header file that C code can
-		// #include.
-		cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
-	}
-
-	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
-		return nil, nil, err
-	}
-	outGo = append(outGo, gofiles...)
-
-	// gcc
-	cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
-	for _, cfile := range cfiles {
-		ofile := obj + cfile[:len(cfile)-1] + "o"
-		if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	for _, file := range gccfiles {
-		base := filepath.Base(file)
-		ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o"
-		if err := b.gcc(p, ofile, cflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
-	for _, file := range gxxfiles {
-		// Append .o to the file, just in case the pkg has file.c and file.cpp
-		ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
-		if err := b.gxx(p, ofile, cxxflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	for _, file := range mfiles {
-		// Append .o to the file, just in case the pkg has file.c and file.m
-		ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
-		if err := b.gcc(p, ofile, cflags, file); err != nil {
-			return nil, nil, err
-		}
-		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(filepath.Base(file), "_") + ".o"
-		if err := b.gfortran(p, ofile, fflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	switch buildToolchain.(type) {
-	case gcToolchain:
-		importGo := obj + "_cgo_import.go"
-		if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
-			return nil, nil, err
-		}
-		outGo = append(outGo, importGo)
-
-		ofile := obj + "_all.o"
-		if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil {
-			return nil, nil, err
-		}
-		outObj = []string{ofile}
-
-	case gccgoToolchain:
-		defunC := obj + "_cgo_defun.c"
-		defunObj := obj + "_cgo_defun.o"
-		if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, defunObj)
-
-	default:
-		noCompiler()
-	}
-
-	return outGo, outObj, nil
-}
-
-// dynimport creates a Go source file named importGo containing
-// //go:cgo_import_dynamic directives for each symbol or library
-// dynamically imported by the object files outObj.
-func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
-	cfile := obj + "_cgo_main.c"
-	ofile := obj + "_cgo_main.o"
-	if err := b.gcc(p, ofile, cflags, cfile); err != nil {
-		return err
-	}
-
-	linkobj := stringList(ofile, outObj, p.SysoFiles)
-	dynobj := obj + "_cgo_.o"
-
-	// we need to use -pie for Linux/ARM to get accurate imported sym
-	ldflags := cgoLDFLAGS
-	if (goarch == "arm" && goos == "linux") || goos == "android" {
-		ldflags = append(ldflags, "-pie")
-	}
-	if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil {
-		return err
-	}
-
-	// cgo -dynimport
-	var cgoflags []string
-	if p.Standard && p.ImportPath == "runtime/cgo" {
-		cgoflags = []string{"-dynlinker"} // record path to dynamic linker
-	}
-	return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
-}
-
-// collect partially links the object files outObj into a single
-// relocatable object file named ofile.
-func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []string) error {
-	// When linking relocatable objects, various flags need to be
-	// filtered out as they are inapplicable and can cause some linkers
-	// to fail.
-	var ldflags []string
-	for i := 0; i < len(cgoLDFLAGS); i++ {
-		f := cgoLDFLAGS[i]
-		switch {
-		// skip "-lc" or "-l somelib"
-		case strings.HasPrefix(f, "-l"):
-			if f == "-l" {
-				i++
-			}
-		// skip "-framework X" on Darwin
-		case goos == "darwin" && f == "-framework":
-			i++
-		// skip "*.{dylib,so,dll,o,a}"
-		case strings.HasSuffix(f, ".dylib"),
-			strings.HasSuffix(f, ".so"),
-			strings.HasSuffix(f, ".dll"),
-			strings.HasSuffix(f, ".o"),
-			strings.HasSuffix(f, ".a"):
-		// Remove any -fsanitize=foo flags.
-		// Otherwise the compiler driver thinks that we are doing final link
-		// and links sanitizer runtime into the object file. But we are not doing
-		// the final link, we will link the resulting object file again. And
-		// so the program ends up with two copies of sanitizer runtime.
-		// See issue 8788 for details.
-		case strings.HasPrefix(f, "-fsanitize="):
-			continue
-		// runpath flags not applicable unless building a shared
-		// 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.
-		case strings.HasPrefix(f, "-Wl,-rpath"):
-			if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
-				// Skip following argument to -rpath* too.
-				i++
-			}
-		default:
-			ldflags = append(ldflags, f)
-		}
-	}
-
-	ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
-
-	if b.gccSupportsNoPie() {
-		ldflags = append(ldflags, "-no-pie")
-	}
-
-	// We are creating an object file, so we don't want a build ID.
-	ldflags = b.disableBuildID(ldflags)
-
-	return b.gccld(p, ofile, ldflags, outObj)
-}
-
-// Run SWIG on all SWIG input files.
-// TODO: Don't build a shared library, once SWIG emits the necessary
-// pragmas for external linking.
-func (b *builder) swig(p *Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
-	if err := b.swigVersionCheck(); err != nil {
-		return nil, nil, nil, err
-	}
-
-	intgosize, err := b.swigIntSize(obj)
-	if err != nil {
-		return nil, nil, nil, err
-	}
-
-	for _, f := range p.SwigFiles {
-		goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
-		if err != nil {
-			return nil, nil, nil, err
-		}
-		if goFile != "" {
-			outGo = append(outGo, goFile)
-		}
-		if cFile != "" {
-			outC = append(outC, cFile)
-		}
-	}
-	for _, f := range p.SwigCXXFiles {
-		goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
-		if err != nil {
-			return nil, nil, nil, err
-		}
-		if goFile != "" {
-			outGo = append(outGo, goFile)
-		}
-		if cxxFile != "" {
-			outCXX = append(outCXX, cxxFile)
-		}
-	}
-	return outGo, outC, outCXX, nil
-}
-
-// Make sure SWIG is new enough.
-var (
-	swigCheckOnce sync.Once
-	swigCheck     error
-)
-
-func (b *builder) swigDoVersionCheck() error {
-	out, err := b.runOut("", "", nil, "swig", "-version")
-	if err != nil {
-		return err
-	}
-	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
-	matches := re.FindSubmatch(out)
-	if matches == nil {
-		// Can't find version number; hope for the best.
-		return nil
-	}
-
-	major, err := strconv.Atoi(string(matches[1]))
-	if err != nil {
-		// Can't find version number; hope for the best.
-		return nil
-	}
-	const errmsg = "must have SWIG version >= 3.0.6"
-	if major < 3 {
-		return errors.New(errmsg)
-	}
-	if major > 3 {
-		// 4.0 or later
-		return nil
-	}
-
-	// We have SWIG version 3.x.
-	if len(matches[2]) > 0 {
-		minor, err := strconv.Atoi(string(matches[2][1:]))
-		if err != nil {
-			return nil
-		}
-		if minor > 0 {
-			// 3.1 or later
-			return nil
-		}
-	}
-
-	// We have SWIG version 3.0.x.
-	if len(matches[3]) > 0 {
-		patch, err := strconv.Atoi(string(matches[3][1:]))
-		if err != nil {
-			return nil
-		}
-		if patch < 6 {
-			// Before 3.0.6.
-			return errors.New(errmsg)
-		}
-	}
-
-	return nil
-}
-
-func (b *builder) swigVersionCheck() error {
-	swigCheckOnce.Do(func() {
-		swigCheck = b.swigDoVersionCheck()
-	})
-	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
-const i int = 1 << 32
-`
-
-// Determine the size of int on the target system for the -intgosize option
-// of swig >= 2.0.9.  Run only once.
-func (b *builder) swigDoIntSize(obj string) (intsize string, err error) {
-	if buildN {
-		return "$INTBITS", nil
-	}
-	src := filepath.Join(b.work, "swig_intsize.go")
-	if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
-		return
-	}
-	srcs := []string{src}
-
-	p := goFilesPackage(srcs)
-
-	if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
-		return "32", nil
-	}
-	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)
-	var cflags []string
-	if cxx {
-		cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
-	} else {
-		cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
-	}
-
-	n := 5 // length of ".swig"
-	if cxx {
-		n = 8 // length of ".swigcxx"
-	}
-	base := file[:len(file)-n]
-	goFile := base + ".go"
-	gccBase := base + "_wrap."
-	gccExt := "c"
-	if cxx {
-		gccExt = "cxx"
-	}
-
-	_, gccgo := buildToolchain.(gccgoToolchain)
-
-	// swig
-	args := []string{
-		"-go",
-		"-cgo",
-		"-intgosize", intgosize,
-		"-module", base,
-		"-o", obj + gccBase + gccExt,
-		"-outdir", obj,
-	}
-
-	for _, f := range cflags {
-		if len(f) > 3 && f[:2] == "-I" {
-			args = append(args, f)
-		}
-	}
-
-	if gccgo {
-		args = append(args, "-gccgo")
-		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
-			args = append(args, "-go-pkgpath", pkgpath)
-		}
-	}
-	if cxx {
-		args = append(args, "-c++")
-	}
-
-	out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
-	if err != nil {
-		if len(out) > 0 {
-			if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
-				return "", "", errors.New("must have SWIG version >= 3.0.6")
-			}
-			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error
-			return "", "", errPrintedOutput
-		}
-		return "", "", err
-	}
-	if len(out) > 0 {
-		b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
-	}
-
-	return goFile, obj + gccBase + gccExt, nil
-}
-
-// disableBuildID adjusts a linker command line to avoid creating a
-// build ID when creating an object file rather than an executable or
-// shared library. Some systems, such as Ubuntu, always add
-// --build-id to every link, but we don't want a build ID when we are
-// producing an object file. On some of those system a plain -r (not
-// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
-// plain -r. I don't know how to turn off --build-id when using clang
-// other than passing a trailing --build-id=none. So that is what we
-// do, but only on systems likely to support it, which is to say,
-// systems that normally use gold or the GNU linker.
-func (b *builder) disableBuildID(ldflags []string) []string {
-	switch goos {
-	case "android", "dragonfly", "linux", "netbsd":
-		ldflags = append(ldflags, "-Wl,--build-id=none")
-	}
-	return ldflags
-}
-
-// An actionQueue is a priority queue of actions.
-type actionQueue []*action
-
-// Implement heap.Interface
-func (q *actionQueue) Len() int           { return len(*q) }
-func (q *actionQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
-func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
-func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) }
-func (q *actionQueue) Pop() interface{} {
-	n := len(*q) - 1
-	x := (*q)[n]
-	*q = (*q)[:n]
-	return x
-}
-
-func (q *actionQueue) push(a *action) {
-	heap.Push(q, a)
-}
-
-func (q *actionQueue) pop() *action {
-	return heap.Pop(q).(*action)
-}
-
-func instrumentInit() {
-	if !buildRace && !buildMSan {
-		return
-	}
-	if buildRace && buildMSan {
-		fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
-		os.Exit(2)
-	}
-	if buildMSan && (goos != "linux" || goarch != "amd64") {
-		fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", goos, goarch)
-		os.Exit(2)
-	}
-	if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
-		fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
-		os.Exit(2)
-	}
-	if !buildContext.CgoEnabled {
-		fmt.Fprintf(os.Stderr, "go %s: -race requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0])
-		os.Exit(2)
-	}
-	if buildRace {
-		buildGcflags = append(buildGcflags, "-race")
-		buildLdflags = append(buildLdflags, "-race")
-	} else {
-		buildGcflags = append(buildGcflags, "-msan")
-		buildLdflags = append(buildLdflags, "-msan")
-	}
-	if buildContext.InstallSuffix != "" {
-		buildContext.InstallSuffix += "_"
-	}
-
-	if buildRace {
-		buildContext.InstallSuffix += "race"
-		buildContext.BuildTags = append(buildContext.BuildTags, "race")
-	} else {
-		buildContext.InstallSuffix += "msan"
-		buildContext.BuildTags = append(buildContext.BuildTags, "msan")
-	}
-}
diff --git a/src/cmd/go/build_test.go b/src/cmd/go/build_test.go
deleted file mode 100644
index 79bbd54..0000000
--- a/src/cmd/go/build_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 The Go Authors. 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"
-	"reflect"
-	"testing"
-)
-
-func TestRemoveDevNull(t *testing.T) {
-	fi, err := os.Lstat(os.DevNull)
-	if err != nil {
-		t.Skip(err)
-	}
-	if fi.Mode().IsRegular() {
-		t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
-	}
-	mayberemovefile(os.DevNull)
-	_, err = os.Lstat(os.DevNull)
-	if err != nil {
-		t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
-	}
-}
-
-func TestSplitPkgConfigOutput(t *testing.T) {
-	for _, test := range []struct {
-		in   []byte
-		want []string
-	}{
-		{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
-		{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
-		{[]byte(`broken flag\`), []string{"broken", "flag"}},
-		{[]byte("\textra     whitespace\r\n"), []string{"extra", "whitespace"}},
-		{[]byte("     \r\n      "), nil},
-	} {
-		got := splitPkgConfigOutput(test.in)
-		if !reflect.DeepEqual(got, test.want) {
-			t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
-		}
-	}
-}
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
deleted file mode 100644
index 7b07150..0000000
--- a/src/cmd/go/clean.go
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"strings"
-)
-
-var cmdClean = &Command{
-	UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
-	Short:     "remove object files",
-	Long: `
-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'.
-	`,
-}
-
-var cleanI bool // clean -i flag
-var cleanR bool // clean -r flag
-
-func init() {
-	// break init cycle
-	cmdClean.Run = runClean
-
-	cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
-	cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
-	// -n and -x are important enough to be
-	// mentioned explicitly in the docs but they
-	// are part of the build flags.
-
-	addBuildFlags(cmdClean)
-}
-
-func runClean(cmd *Command, args []string) {
-	for _, pkg := range packagesAndErrors(args) {
-		clean(pkg)
-	}
-}
-
-var cleaned = map[*Package]bool{}
-
-// TODO: These are dregs left by Makefile-based builds.
-// Eventually, can stop deleting these.
-var cleanDir = map[string]bool{
-	"_test": true,
-	"_obj":  true,
-}
-
-var cleanFile = map[string]bool{
-	"_testmain.go": true,
-	"test.out":     true,
-	"build.out":    true,
-	"a.out":        true,
-}
-
-var cleanExt = map[string]bool{
-	".5":  true,
-	".6":  true,
-	".8":  true,
-	".a":  true,
-	".o":  true,
-	".so": true,
-}
-
-func clean(p *Package) {
-	if cleaned[p] {
-		return
-	}
-	cleaned[p] = true
-
-	if p.Dir == "" {
-		errorf("can't load package: %v", p.Error)
-		return
-	}
-	dirs, err := ioutil.ReadDir(p.Dir)
-	if err != nil {
-		errorf("go clean %s: %v", p.Dir, err)
-		return
-	}
-
-	var b builder
-	b.print = fmt.Print
-
-	packageFile := map[string]bool{}
-	if p.Name != "main" {
-		// Record which files are not in package main.
-		// The others are.
-		keep := func(list []string) {
-			for _, f := range list {
-				packageFile[f] = true
-			}
-		}
-		keep(p.GoFiles)
-		keep(p.CgoFiles)
-		keep(p.TestGoFiles)
-		keep(p.XTestGoFiles)
-	}
-
-	_, elem := filepath.Split(p.Dir)
-	var allRemove []string
-
-	// Remove dir-named executable only if this is package main.
-	if p.Name == "main" {
-		allRemove = append(allRemove,
-			elem,
-			elem+".exe",
-		)
-	}
-
-	// Remove package test executables.
-	allRemove = append(allRemove,
-		elem+".test",
-		elem+".test.exe",
-	)
-
-	// Remove a potential executable for each .go file in the directory that
-	// is not part of the directory's package.
-	for _, dir := range dirs {
-		name := dir.Name()
-		if packageFile[name] {
-			continue
-		}
-		if !dir.IsDir() && strings.HasSuffix(name, ".go") {
-			// TODO(adg,rsc): check that this .go file is actually
-			// in "package main", and therefore capable of building
-			// to an executable file.
-			base := name[:len(name)-len(".go")]
-			allRemove = append(allRemove, base, base+".exe")
-		}
-	}
-
-	if buildN || buildX {
-		b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
-	}
-
-	toRemove := map[string]bool{}
-	for _, name := range allRemove {
-		toRemove[name] = true
-	}
-	for _, dir := range dirs {
-		name := dir.Name()
-		if dir.IsDir() {
-			// TODO: Remove once Makefiles are forgotten.
-			if cleanDir[name] {
-				if buildN || buildX {
-					b.showcmd(p.Dir, "rm -r %s", name)
-					if buildN {
-						continue
-					}
-				}
-				if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
-					errorf("go clean: %v", err)
-				}
-			}
-			continue
-		}
-
-		if buildN {
-			continue
-		}
-
-		if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
-			removeFile(filepath.Join(p.Dir, name))
-		}
-	}
-
-	if cleanI && p.target != "" {
-		if buildN || buildX {
-			b.showcmd("", "rm -f %s", p.target)
-		}
-		if !buildN {
-			removeFile(p.target)
-		}
-	}
-
-	if cleanR {
-		for _, p1 := range p.imports {
-			clean(p1)
-		}
-	}
-}
-
-// removeFile tries to remove file f, if error other than file doesn't exist
-// occurs, it will report the error.
-func removeFile(f string) {
-	err := os.Remove(f)
-	if err == nil || os.IsNotExist(err) {
-		return
-	}
-	// Windows does not allow deletion of a binary file while it is executing.
-	if toolIsWindows {
-		// Remove lingering ~ file from last attempt.
-		if _, err2 := os.Stat(f + "~"); err2 == nil {
-			os.Remove(f + "~")
-		}
-		// 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 err2 := os.Rename(f, f+"~"); err2 == nil {
-			os.Remove(f + "~")
-			return
-		}
-	}
-	errorf("go clean: %v", err)
-}
diff --git a/src/cmd/go/context.go b/src/cmd/go/context.go
deleted file mode 100644
index 94cd54d..0000000
--- a/src/cmd/go/context.go
+++ /dev/null
@@ -1,37 +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 main
-
-import (
-	"go/build"
-)
-
-type Context struct {
-	GOARCH        string   `json:",omitempty"` // target architecture
-	GOOS          string   `json:",omitempty"` // target operating system
-	GOROOT        string   `json:",omitempty"` // Go root
-	GOPATH        string   `json:",omitempty"` // Go path
-	CgoEnabled    bool     `json:",omitempty"` // whether cgo can be used
-	UseAllFiles   bool     `json:",omitempty"` // use files regardless of +build lines, file names
-	Compiler      string   `json:",omitempty"` // compiler to assume when computing target paths
-	BuildTags     []string `json:",omitempty"` // build constraints to match in +build lines
-	ReleaseTags   []string `json:",omitempty"` // releases the current release is compatible with
-	InstallSuffix string   `json:",omitempty"` // suffix to use in the name of the install dir
-}
-
-func newContext(c *build.Context) *Context {
-	return &Context{
-		GOARCH:        c.GOARCH,
-		GOOS:          c.GOOS,
-		GOROOT:        c.GOROOT,
-		GOPATH:        c.GOPATH,
-		CgoEnabled:    c.CgoEnabled,
-		UseAllFiles:   c.UseAllFiles,
-		Compiler:      c.Compiler,
-		BuildTags:     c.BuildTags,
-		ReleaseTags:   c.ReleaseTags,
-		InstallSuffix: c.InstallSuffix,
-	}
-}
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
deleted file mode 100644
index b60eaef..0000000
--- a/src/cmd/go/discovery.go
+++ /dev/null
@@ -1,83 +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 !cmd_go_bootstrap
-
-// This code is compiled into the real 'go' binary, but it is not
-// compiled into the binary that is built during all.bash, so as
-// to avoid needing to build net (and thus use cgo) during the
-// bootstrap process.
-
-package main
-
-import (
-	"encoding/xml"
-	"fmt"
-	"io"
-	"strings"
-)
-
-// charsetReader returns a reader for the given charset. Currently
-// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
-// error which is printed by go get, so the user can find why the package
-// wasn't downloaded if the encoding is not supported. Note that, in
-// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
-// greater than 0x7f are not rejected).
-func charsetReader(charset string, input io.Reader) (io.Reader, error) {
-	switch strings.ToLower(charset) {
-	case "ascii":
-		return input, nil
-	default:
-		return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
-	}
-}
-
-// parseMetaGoImports returns meta imports from the HTML in r.
-// Parsing ends at the end of the <head> section or the beginning of the <body>.
-func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
-	d := xml.NewDecoder(r)
-	d.CharsetReader = charsetReader
-	d.Strict = false
-	var t xml.Token
-	for {
-		t, err = d.RawToken()
-		if err != nil {
-			if err == io.EOF || len(imports) > 0 {
-				err = nil
-			}
-			return
-		}
-		if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
-			return
-		}
-		if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
-			return
-		}
-		e, ok := t.(xml.StartElement)
-		if !ok || !strings.EqualFold(e.Name.Local, "meta") {
-			continue
-		}
-		if attrValue(e.Attr, "name") != "go-import" {
-			continue
-		}
-		if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
-			imports = append(imports, metaImport{
-				Prefix:   f[0],
-				VCS:      f[1],
-				RepoRoot: f[2],
-			})
-		}
-	}
-}
-
-// attrValue returns the attribute value for the case-insensitive key
-// `name', or the empty string if nothing is found.
-func attrValue(attrs []xml.Attr, name string) string {
-	for _, a := range attrs {
-		if strings.EqualFold(a.Name.Local, name) {
-			return a.Value
-		}
-	}
-	return ""
-}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
deleted file mode 100644
index 8299839..0000000
--- a/src/cmd/go/doc.go
+++ /dev/null
@@ -1,118 +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.
-
-//go:generate ./mkalldocs.sh
-
-package main
-
-var cmdDoc = &Command{
-	Run:         runDoc,
-	UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.method]]",
-	CustomFlags: true,
-	Short:       "show documentation for package or symbol",
-	Long: `
-Doc prints the documentation comments associated with the item identified by its
-arguments (a package, const, func, type, var, or method) followed by a one-line
-summary of each of the first-level items "under" that item (package-level
-declarations for a package, methods for a type, etc.).
-
-Doc accepts zero, one, or two arguments.
-
-Given no arguments, that is, when run as
-
-	go doc
-
-it prints the package documentation for the package in the current directory.
-If the package is a command (package main), the exported symbols of the package
-are elided from the presentation unless the -cmd flag is provided.
-
-When run with one argument, the argument is treated as a Go-syntax-like
-representation of the item to be documented. What the argument selects depends
-on what is installed in GOROOT and GOPATH, as well as the form of the argument,
-which is schematically one of these:
-
-	go doc <pkg>
-	go doc <sym>[.<method>]
-	go doc [<pkg>.]<sym>[.<method>]
-	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.
-`,
-}
-
-func runDoc(cmd *Command, args []string) {
-	run(buildToolExec, tool("doc"), args)
-}
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
deleted file mode 100644
index 31710b7..0000000
--- a/src/cmd/go/env.go
+++ /dev/null
@@ -1,138 +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 main
-
-import (
-	"fmt"
-	"os"
-	"runtime"
-	"strings"
-)
-
-var cmdEnv = &Command{
-	Run:       runEnv,
-	UsageLine: "env [var ...]",
-	Short:     "print Go environment information",
-	Long: `
-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.
-	`,
-}
-
-type envVar struct {
-	name, value string
-}
-
-func mkEnv() []envVar {
-	var b builder
-	b.init()
-
-	env := []envVar{
-		{"GOARCH", goarch},
-		{"GOBIN", gobin},
-		{"GOEXE", exeSuffix},
-		{"GOHOSTARCH", runtime.GOARCH},
-		{"GOHOSTOS", runtime.GOOS},
-		{"GOOS", goos},
-		{"GOPATH", buildContext.GOPATH},
-		{"GORACE", os.Getenv("GORACE")},
-		{"GOROOT", goroot},
-		{"GOTOOLDIR", toolDir},
-
-		// disable escape codes in clang errors
-		{"TERM", "dumb"},
-	}
-
-	if gccgoBin != "" {
-		env = append(env, envVar{"GCCGO", gccgoBin})
-	} else {
-		env = append(env, envVar{"GCCGO", gccgoName})
-	}
-
-	switch goarch {
-	case "arm":
-		env = append(env, envVar{"GOARM", os.Getenv("GOARM")})
-	case "386":
-		env = append(env, envVar{"GO386", os.Getenv("GO386")})
-	}
-
-	cmd := b.gccCmd(".")
-	env = append(env, envVar{"CC", cmd[0]})
-	env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
-	cmd = b.gxxCmd(".")
-	env = append(env, envVar{"CXX", cmd[0]})
-
-	if buildContext.CgoEnabled {
-		env = append(env, envVar{"CGO_ENABLED", "1"})
-	} else {
-		env = append(env, envVar{"CGO_ENABLED", "0"})
-	}
-
-	return env
-}
-
-func findEnv(env []envVar, name string) string {
-	for _, e := range env {
-		if e.name == name {
-			return e.value
-		}
-	}
-	return ""
-}
-
-// extraEnvVars returns environment variables that should not leak into child processes.
-func extraEnvVars() []envVar {
-	var b builder
-	b.init()
-	cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
-	return []envVar{
-		{"PKG_CONFIG", b.pkgconfigCmd()},
-		{"CGO_CFLAGS", strings.Join(cflags, " ")},
-		{"CGO_CPPFLAGS", strings.Join(cppflags, " ")},
-		{"CGO_CXXFLAGS", strings.Join(cxxflags, " ")},
-		{"CGO_FFLAGS", strings.Join(fflags, " ")},
-		{"CGO_LDFLAGS", strings.Join(ldflags, " ")},
-	}
-}
-
-func runEnv(cmd *Command, args []string) {
-	env := newEnv
-	env = append(env, extraEnvVars()...)
-	if len(args) > 0 {
-		for _, name := range args {
-			fmt.Printf("%s\n", findEnv(env, name))
-		}
-		return
-	}
-
-	for _, e := range env {
-		if e.name != "TERM" {
-			switch runtime.GOOS {
-			default:
-				fmt.Printf("%s=\"%s\"\n", e.name, e.value)
-			case "plan9":
-				if strings.IndexByte(e.value, '\x00') < 0 {
-					fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
-				} else {
-					v := strings.Split(e.value, "\x00")
-					fmt.Printf("%s=(", e.name)
-					for x, s := range v {
-						if x > 0 {
-							fmt.Printf(" ")
-						}
-						fmt.Printf("%s", s)
-					}
-					fmt.Printf(")\n")
-				}
-			case "windows":
-				fmt.Printf("set %s=%s\n", e.name, e.value)
-			}
-		}
-	}
-}
diff --git a/src/cmd/go/fix.go b/src/cmd/go/fix.go
deleted file mode 100644
index 3af7adb..0000000
--- a/src/cmd/go/fix.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-var cmdFix = &Command{
-	Run:       runFix,
-	UsageLine: "fix [packages]",
-	Short:     "run go tool fix on packages",
-	Long: `
-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.
-	`,
-}
-
-func runFix(cmd *Command, args []string) {
-	for _, pkg := range packages(args) {
-		// Use pkg.gofiles instead of pkg.Dir so that
-		// the command only applies to this package,
-		// not to packages in subdirectories.
-		run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
-	}
-}
diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go
deleted file mode 100644
index 4ed7722..0000000
--- a/src/cmd/go/fmt.go
+++ /dev/null
@@ -1,64 +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 main
-
-import (
-	"os"
-	"path/filepath"
-)
-
-func init() {
-	addBuildFlagsNX(cmdFmt)
-}
-
-var cmdFmt = &Command{
-	Run:       runFmt,
-	UsageLine: "fmt [-n] [-x] [packages]",
-	Short:     "run gofmt on package sources",
-	Long: `
-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.
-	`,
-}
-
-func runFmt(cmd *Command, args []string) {
-	gofmt := gofmtPath()
-	for _, pkg := range packages(args) {
-		// Use pkg.gofiles instead of pkg.Dir so that
-		// the command only applies to this package,
-		// not to packages in subdirectories.
-		run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
-	}
-}
-
-func gofmtPath() string {
-	gofmt := "gofmt"
-	if toolIsWindows {
-		gofmt += toolWindowsExtension
-	}
-
-	gofmtPath := filepath.Join(gobin, gofmt)
-	if _, err := os.Stat(gofmtPath); err == nil {
-		return gofmtPath
-	}
-
-	gofmtPath = filepath.Join(goroot, "bin", gofmt)
-	if _, err := os.Stat(gofmtPath); err == nil {
-		return gofmtPath
-	}
-
-	// fallback to looking for gofmt in $PATH
-	return "gofmt"
-}
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
deleted file mode 100644
index 2d92a0c..0000000
--- a/src/cmd/go/generate.go
+++ /dev/null
@@ -1,401 +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 main
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"io"
-	"log"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-var cmdGenerate = &Command{
-	Run:       runGenerate,
-	UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
-	Short:     "generate Go files by processing source",
-	Long: `
-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.
-
-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 foo go tool foo
-
-specifies that the command "foo" represents the generator
-"go tool foo".
-
-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'.
-	`,
-}
-
-var (
-	generateRunFlag string         // generate -run flag
-	generateRunRE   *regexp.Regexp // compiled expression for -run
-)
-
-func init() {
-	addBuildFlags(cmdGenerate)
-	cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
-}
-
-func runGenerate(cmd *Command, args []string) {
-	ignoreImports = true
-
-	if generateRunFlag != "" {
-		var err error
-		generateRunRE, err = regexp.Compile(generateRunFlag)
-		if err != nil {
-			log.Fatalf("generate: %s", err)
-		}
-	}
-	// Even if the arguments are .go files, this loop suffices.
-	for _, pkg := range packages(args) {
-		for _, file := range pkg.gofiles {
-			if !generate(pkg.Name, file) {
-				break
-			}
-		}
-	}
-}
-
-// generate runs the generation directives for a single file.
-func generate(pkg, absFile string) bool {
-	fd, err := os.Open(absFile)
-	if err != nil {
-		log.Fatalf("generate: %s", err)
-	}
-	defer fd.Close()
-	g := &Generator{
-		r:        fd,
-		path:     absFile,
-		pkg:      pkg,
-		commands: make(map[string][]string),
-	}
-	return g.run()
-}
-
-// A Generator represents the state of a single Go source file
-// being scanned for generator commands.
-type Generator struct {
-	r        io.Reader
-	path     string // full rooted path name.
-	dir      string // full rooted directory of file.
-	file     string // base name of file.
-	pkg      string
-	commands map[string][]string
-	lineNum  int // current line number.
-	env      []string
-}
-
-// run runs the generators in the current file.
-func (g *Generator) run() (ok bool) {
-	// Processing below here calls g.errorf on failure, which does panic(stop).
-	// If we encounter an error, we abort the package.
-	defer func() {
-		e := recover()
-		if e != nil {
-			ok = false
-			if e != stop {
-				panic(e)
-			}
-			setExitStatus(1)
-		}
-	}()
-	g.dir, g.file = filepath.Split(g.path)
-	g.dir = filepath.Clean(g.dir) // No final separator please.
-	if buildV {
-		fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
-	}
-
-	// Scan for lines that start "//go:generate".
-	// Can't use bufio.Scanner because it can't handle long lines,
-	// which are likely to appear when using generate.
-	input := bufio.NewReader(g.r)
-	var err error
-	// One line per loop.
-	for {
-		g.lineNum++ // 1-indexed.
-		var buf []byte
-		buf, err = input.ReadSlice('\n')
-		if err == bufio.ErrBufferFull {
-			// Line too long - consume and ignore.
-			if isGoGenerate(buf) {
-				g.errorf("directive too long")
-			}
-			for err == bufio.ErrBufferFull {
-				_, err = input.ReadSlice('\n')
-			}
-			if err != nil {
-				break
-			}
-			continue
-		}
-
-		if err != nil {
-			// Check for marker at EOF without final \n.
-			if err == io.EOF && isGoGenerate(buf) {
-				err = io.ErrUnexpectedEOF
-			}
-			break
-		}
-
-		if !isGoGenerate(buf) {
-			continue
-		}
-		if generateRunFlag != "" {
-			if !generateRunRE.Match(bytes.TrimSpace(buf)) {
-				continue
-			}
-		}
-
-		g.setEnv()
-		words := g.split(string(buf))
-		if len(words) == 0 {
-			g.errorf("no arguments to directive")
-		}
-		if words[0] == "-command" {
-			g.setShorthand(words)
-			continue
-		}
-		// Run the command line.
-		if buildN || buildX {
-			fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
-		}
-		if buildN {
-			continue
-		}
-		g.exec(words)
-	}
-	if err != nil && err != io.EOF {
-		g.errorf("error reading %s: %s", shortPath(g.path), err)
-	}
-	return true
-}
-
-func isGoGenerate(buf []byte) bool {
-	return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
-}
-
-// setEnv sets the extra environment variables used when executing a
-// single go:generate command.
-func (g *Generator) setEnv() {
-	g.env = []string{
-		"GOARCH=" + buildContext.GOARCH,
-		"GOOS=" + buildContext.GOOS,
-		"GOFILE=" + g.file,
-		"GOLINE=" + strconv.Itoa(g.lineNum),
-		"GOPACKAGE=" + g.pkg,
-		"DOLLAR=" + "$",
-	}
-}
-
-// split breaks the line into words, evaluating quoted
-// strings and evaluating environment variables.
-// The initial //go:generate element is present in line.
-func (g *Generator) split(line string) []string {
-	// Parse line, obeying quoted strings.
-	var words []string
-	line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
-	// There may still be a carriage return.
-	if len(line) > 0 && line[len(line)-1] == '\r' {
-		line = line[:len(line)-1]
-	}
-	// One (possibly quoted) word per iteration.
-Words:
-	for {
-		line = strings.TrimLeft(line, " \t")
-		if len(line) == 0 {
-			break
-		}
-		if line[0] == '"' {
-			for i := 1; i < len(line); i++ {
-				c := line[i] // Only looking for ASCII so this is OK.
-				switch c {
-				case '\\':
-					if i+1 == len(line) {
-						g.errorf("bad backslash")
-					}
-					i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
-				case '"':
-					word, err := strconv.Unquote(line[0 : i+1])
-					if err != nil {
-						g.errorf("bad quoted string")
-					}
-					words = append(words, word)
-					line = line[i+1:]
-					// Check the next character is space or end of line.
-					if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
-						g.errorf("expect space after quoted argument")
-					}
-					continue Words
-				}
-			}
-			g.errorf("mismatched quoted string")
-		}
-		i := strings.IndexAny(line, " \t")
-		if i < 0 {
-			i = len(line)
-		}
-		words = append(words, line[0:i])
-		line = line[i:]
-	}
-	// Substitute command if required.
-	if len(words) > 0 && g.commands[words[0]] != nil {
-		// Replace 0th word by command substitution.
-		words = append(g.commands[words[0]], words[1:]...)
-	}
-	// Substitute environment variables.
-	for i, word := range words {
-		words[i] = os.Expand(word, g.expandVar)
-	}
-	return words
-}
-
-var stop = fmt.Errorf("error in generation")
-
-// errorf logs an error message prefixed with the file and line number.
-// It then exits the program (with exit status 1) because generation stops
-// at the first error.
-func (g *Generator) errorf(format string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
-		fmt.Sprintf(format, args...))
-	panic(stop)
-}
-
-// expandVar expands the $XXX invocation in word. It is called
-// by os.Expand.
-func (g *Generator) expandVar(word string) string {
-	w := word + "="
-	for _, e := range g.env {
-		if strings.HasPrefix(e, w) {
-			return e[len(w):]
-		}
-	}
-	return os.Getenv(word)
-}
-
-// setShorthand installs a new shorthand as defined by a -command directive.
-func (g *Generator) setShorthand(words []string) {
-	// Create command shorthand.
-	if len(words) == 1 {
-		g.errorf("no command specified for -command")
-	}
-	command := words[1]
-	if g.commands[command] != nil {
-		g.errorf("command %q defined multiply defined", command)
-	}
-	g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
-}
-
-// exec runs the command specified by the argument. The first word is
-// the command name itself.
-func (g *Generator) exec(words []string) {
-	cmd := exec.Command(words[0], words[1:]...)
-	// Standard in and out of generator should be the usual.
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	// Run the command in the package directory.
-	cmd.Dir = g.dir
-	cmd.Env = mergeEnvLists(g.env, origEnv)
-	err := cmd.Run()
-	if err != nil {
-		g.errorf("running %q: %s", words[0], err)
-	}
-}
diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go
deleted file mode 100644
index dd116e6..0000000
--- a/src/cmd/go/generate_test.go
+++ /dev/null
@@ -1,56 +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 main
-
-import (
-	"reflect"
-	"runtime"
-	"testing"
-)
-
-type splitTest struct {
-	in  string
-	out []string
-}
-
-var splitTests = []splitTest{
-	{"", nil},
-	{"x", []string{"x"}},
-	{" a b\tc ", []string{"a", "b", "c"}},
-	{` " a " `, []string{" a "}},
-	{"$GOARCH", []string{runtime.GOARCH}},
-	{"$GOOS", []string{runtime.GOOS}},
-	{"$GOFILE", []string{"proc.go"}},
-	{"$GOPACKAGE", []string{"sys"}},
-	{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
-	{"/$XXNOTDEFINED/", []string{"//"}},
-	{"/$DOLLAR/", []string{"/$/"}},
-	{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
-}
-
-func TestGenerateCommandParse(t *testing.T) {
-	g := &Generator{
-		r:        nil, // Unused here.
-		path:     "/usr/ken/sys/proc.go",
-		dir:      "/usr/ken/sys",
-		file:     "proc.go",
-		pkg:      "sys",
-		commands: make(map[string][]string),
-	}
-	g.setEnv()
-	g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
-	for _, test := range splitTests {
-		// First with newlines.
-		got := g.split("//go:generate " + test.in + "\n")
-		if !reflect.DeepEqual(got, test.out) {
-			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
-		}
-		// Then with CRLFs, thank you Windows.
-		got = g.split("//go:generate " + test.in + "\r\n")
-		if !reflect.DeepEqual(got, test.out) {
-			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
-		}
-	}
-}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
deleted file mode 100644
index 6fb4235..0000000
--- a/src/cmd/go/get.go
+++ /dev/null
@@ -1,588 +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 main
-
-import (
-	"fmt"
-	"go/build"
-	"os"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"strconv"
-	"strings"
-)
-
-var cmdGet = &Command{
-	UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
-	Short:     "download and install packages and dependencies",
-	Long: `
-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.
-
-The -v flag enables verbose progress and debug output.
-
-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. For more details 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.
-	`,
-}
-
-var getD = cmdGet.Flag.Bool("d", false, "")
-var getF = cmdGet.Flag.Bool("f", false, "")
-var getT = cmdGet.Flag.Bool("t", false, "")
-var getU = cmdGet.Flag.Bool("u", false, "")
-var getFix = cmdGet.Flag.Bool("fix", false, "")
-var getInsecure = cmdGet.Flag.Bool("insecure", false, "")
-
-func init() {
-	addBuildFlags(cmdGet)
-	cmdGet.Run = runGet // break init loop
-}
-
-func runGet(cmd *Command, args []string) {
-	if *getF && !*getU {
-		fatalf("go get: cannot use -f flag without -u")
-	}
-
-	// Disable any prompting for passwords by Git.
-	// Only has an effect for 2.3.0 or later, but avoiding
-	// the prompt in earlier versions is just too hard.
-	// If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
-	// prompting.
-	// See golang.org/issue/9341 and golang.org/issue/12706.
-	if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
-		os.Setenv("GIT_TERMINAL_PROMPT", "0")
-	}
-
-	// Disable any ssh connection pooling by Git.
-	// If a Git subprocess forks a child into the background to cache a new connection,
-	// that child keeps stdout/stderr open. After the Git subprocess exits,
-	// os /exec expects to be able to read from the stdout/stderr pipe
-	// until EOF to get all the data that the Git subprocess wrote before exiting.
-	// The EOF doesn't come until the child exits too, because the child
-	// is holding the write end of the pipe.
-	// This is unfortunate, but it has come up at least twice
-	// (see golang.org/issue/13453 and golang.org/issue/16104)
-	// and confuses users when it does.
-	// If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
-	// assume they know what they are doing and don't step on it.
-	// But default to turning off ControlMaster.
-	if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
-		os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
-	}
-
-	// Phase 1.  Download/update.
-	var stk importStack
-	mode := 0
-	if *getT {
-		mode |= getTestDeps
-	}
-	args = downloadPaths(args)
-	for _, arg := range args {
-		download(arg, nil, &stk, mode)
-	}
-	exitIfErrors()
-
-	// Phase 2. Rescan packages and re-evaluate args list.
-
-	// 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
-	// track of the reverse dependency information, evict
-	// everything.
-	for name := range packageCache {
-		delete(packageCache, name)
-	}
-
-	// In order to rebuild packages information completely,
-	// we need to clear commands cache. Command packages are
-	// referring to evicted packages from the package cache.
-	// This leads to duplicated loads of the standard packages.
-	for name := range cmdCache {
-		delete(cmdCache, name)
-	}
-
-	args = importPaths(args)
-	packagesForBuild(args)
-
-	// Phase 3.  Install.
-	if *getD {
-		// Download only.
-		// Check delayed until now so that importPaths
-		// and packagesForBuild have a chance to print errors.
-		return
-	}
-
-	installPackages(args, true)
-}
-
-// downloadPaths prepares the list of paths to pass to download.
-// 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.
-func downloadPaths(args []string) []string {
-	args = importPathsNoDotExpansion(args)
-	var out []string
-	for _, a := range args {
-		if strings.Contains(a, "...") {
-			var expand []string
-			// Use matchPackagesInFS to avoid printing
-			// warnings. They will be printed by the
-			// eventual call to importPaths instead.
-			if build.IsLocalImport(a) {
-				expand = matchPackagesInFS(a)
-			} else {
-				expand = matchPackages(a)
-			}
-			if len(expand) > 0 {
-				out = append(out, expand...)
-				continue
-			}
-		}
-		out = append(out, a)
-	}
-	return out
-}
-
-// downloadCache records the import paths we have already
-// considered during the download, to avoid duplicate work when
-// there is more than one dependency sequence leading to
-// a particular package.
-var downloadCache = map[string]bool{}
-
-// downloadRootCache records the version control repository
-// root directories we have already considered during the download.
-// For example, all the packages in the github.com/google/codesearch repo
-// share the same root (the directory for that path), and we only need
-// to run the hg commands to consider each repository once.
-var downloadRootCache = map[string]bool{}
-
-// download runs the download half of the get command
-// for the package named by the argument.
-func download(arg string, parent *Package, stk *importStack, mode int) {
-	if mode&useVendor != 0 {
-		// Caller is responsible for expanding vendor paths.
-		panic("internal error: download mode has useVendor set")
-	}
-	load := func(path string, mode int) *Package {
-		if parent == nil {
-			return loadPackage(path, stk)
-		}
-		return loadImport(path, parent.Dir, parent, stk, nil, mode)
-	}
-
-	p := load(arg, mode)
-	if p.Error != nil && p.Error.hard {
-		errorf("%s", p.Error)
-		return
-	}
-
-	// loadPackage inferred the canonical ImportPath from arg.
-	// Use that in the following to prevent hysteresis effects
-	// in e.g. downloadCache and packageCache.
-	// This allows invocations such as:
-	//   mkdir -p $GOPATH/src/github.com/user
-	//   cd $GOPATH/src/github.com/user
-	//   go get ./foo
-	// see: golang.org/issue/9767
-	arg = p.ImportPath
-
-	// There's nothing to do if this is a package in the standard library.
-	if p.Standard {
-		return
-	}
-
-	// Only process each package once.
-	// (Unless we're fetching test dependencies for this package,
-	// in which case we want to process it again.)
-	if downloadCache[arg] && mode&getTestDeps == 0 {
-		return
-	}
-	downloadCache[arg] = true
-
-	pkgs := []*Package{p}
-	wildcardOkay := len(*stk) == 0
-	isWildcard := false
-
-	// Download if the package is missing, or update if we're using -u.
-	if p.Dir == "" || *getU {
-		// The actual download.
-		stk.push(arg)
-		err := downloadPackage(p)
-		if err != nil {
-			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
-			stk.pop()
-			return
-		}
-		stk.pop()
-
-		args := []string{arg}
-		// If the argument has a wildcard in it, re-evaluate the wildcard.
-		// We delay this until after reloadPackage so that the old entry
-		// for p has been replaced in the package cache.
-		if wildcardOkay && strings.Contains(arg, "...") {
-			if build.IsLocalImport(arg) {
-				args = matchPackagesInFS(arg)
-			} else {
-				args = matchPackages(arg)
-			}
-			isWildcard = true
-		}
-
-		// Clear all relevant package cache entries before
-		// doing any new loads.
-		for _, arg := range args {
-			p := packageCache[arg]
-			if p != nil {
-				delete(packageCache, p.Dir)
-				delete(packageCache, p.ImportPath)
-			}
-		}
-
-		pkgs = pkgs[:0]
-		for _, arg := range args {
-			// Note: load calls loadPackage or loadImport,
-			// which push arg onto stk already.
-			// Do not push here too, or else stk will say arg imports arg.
-			p := load(arg, mode)
-			if p.Error != nil {
-				errorf("%s", p.Error)
-				continue
-			}
-			pkgs = append(pkgs, p)
-		}
-	}
-
-	// Process package, which might now be multiple packages
-	// due to wildcard expansion.
-	for _, p := range pkgs {
-		if *getFix {
-			run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
-
-			// The imports might have changed, so reload again.
-			p = reloadPackage(arg, stk)
-			if p.Error != nil {
-				errorf("%s", p.Error)
-				return
-			}
-		}
-
-		if isWildcard {
-			// Report both the real package and the
-			// wildcard in any error message.
-			stk.push(p.ImportPath)
-		}
-
-		// Process dependencies, now that we know what they are.
-		imports := p.Imports
-		if mode&getTestDeps != 0 {
-			// Process test dependencies when -t is specified.
-			// (But don't get test dependencies for test dependencies:
-			// we always pass mode 0 to the recursive calls below.)
-			imports = stringList(imports, p.TestImports, p.XTestImports)
-		}
-		for i, path := range imports {
-			if path == "C" {
-				continue
-			}
-			// Fail fast on import naming full vendor path.
-			// Otherwise expand path as needed for test imports.
-			// Note that p.Imports can have additional entries beyond p.build.Imports.
-			orig := path
-			if i < len(p.build.Imports) {
-				orig = p.build.Imports[i]
-			}
-			if j, ok := findVendor(orig); ok {
-				stk.push(path)
-				err := &PackageError{
-					ImportStack: stk.copy(),
-					Err:         "must be imported as " + path[j+len("vendor/"):],
-				}
-				stk.pop()
-				errorf("%s", err)
-				continue
-			}
-			// If this is a test import, apply vendor lookup now.
-			// We cannot pass useVendor to download, because
-			// download does caching based on the value of path,
-			// so it must be the fully qualified path already.
-			if i >= len(p.Imports) {
-				path = vendoredImportPath(p, path)
-			}
-			download(path, p, stk, 0)
-		}
-
-		if isWildcard {
-			stk.pop()
-		}
-	}
-}
-
-// downloadPackage runs the create or download command
-// to make the first copy of or update a copy of the given package.
-func downloadPackage(p *Package) error {
-	var (
-		vcs            *vcsCmd
-		repo, rootPath string
-		err            error
-	)
-
-	security := secure
-	if *getInsecure {
-		security = insecure
-	}
-
-	if p.build.SrcRoot != "" {
-		// Directory exists. Look for checkout along path to src.
-		vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
-		if err != nil {
-			return err
-		}
-		repo = "<local>" // should be unused; make distinctive
-
-		// Double-check where it came from.
-		if *getU && vcs.remoteRepo != nil {
-			dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
-			remote, err := vcs.remoteRepo(vcs, dir)
-			if err != nil {
-				return err
-			}
-			repo = remote
-			if !*getF {
-				if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
-					repo := rr.repo
-					if rr.vcs.resolveRepo != nil {
-						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
-						if err == nil {
-							repo = resolved
-						}
-					}
-					if remote != repo && rr.isCustom {
-						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
-					}
-				}
-			}
-		}
-	} else {
-		// Analyze the import path to determine the version control system,
-		// repository, and the import path for the root of the repository.
-		rr, err := repoRootForImportPath(p.ImportPath, security)
-		if err != nil {
-			return err
-		}
-		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
-	}
-	if !vcs.isSecure(repo) && !*getInsecure {
-		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
-	}
-
-	if p.build.SrcRoot == "" {
-		// Package not found. Put in first directory of $GOPATH.
-		list := filepath.SplitList(buildContext.GOPATH)
-		if len(list) == 0 {
-			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
-		}
-		// Guard against people setting GOPATH=$GOROOT.
-		if filepath.Clean(list[0]) == filepath.Clean(goroot) {
-			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
-		}
-		if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
-			return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
-		}
-		p.build.Root = list[0]
-		p.build.SrcRoot = filepath.Join(list[0], "src")
-		p.build.PkgRoot = filepath.Join(list[0], "pkg")
-	}
-	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
-	}
-	downloadRootCache[root] = true
-
-	if buildV {
-		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
-	}
-
-	// Check that this is an appropriate place for the repo to be checked out.
-	// The target directory must either not exist or have a repo checked out already.
-	meta := filepath.Join(root, "."+vcs.cmd)
-	st, err := os.Stat(meta)
-	if err == nil && !st.IsDir() {
-		return fmt.Errorf("%s exists but is not a directory", meta)
-	}
-	if err != nil {
-		// 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 {
-			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
-		}
-
-		_, err := os.Stat(p.build.Root)
-		gopathExisted := err == nil
-
-		// Some version control tools require the parent of the target to exist.
-		parent, _ := filepath.Split(root)
-		if err = os.MkdirAll(parent, 0777); err != nil {
-			return err
-		}
-		if buildV && !gopathExisted && p.build.Root == buildContext.GOPATH {
-			fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
-		}
-
-		if err = vcs.create(root, repo); err != nil {
-			return err
-		}
-	} else {
-		// Metadata directory does exist; download incremental updates.
-		if err = vcs.download(root); err != nil {
-			return err
-		}
-	}
-
-	if buildN {
-		// Do not show tag sync in -n; it's noise more than anything,
-		// and since we're not running commands, no tag will be found.
-		// But avoid printing nothing.
-		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
-		return nil
-	}
-
-	// Select and sync to appropriate version of the repository.
-	tags, err := vcs.tags(root)
-	if err != nil {
-		return err
-	}
-	vers := runtime.Version()
-	if i := strings.Index(vers, " "); i >= 0 {
-		vers = vers[:i]
-	}
-	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// goTag matches go release tags such as go1 and go1.2.3.
-// The numbers involved must be small (at most 4 digits),
-// have no unnecessary leading zeros, and the version cannot
-// end in .0 - it is go1, not go1.0 or go1.0.0.
-var goTag = regexp.MustCompile(
-	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
-)
-
-// selectTag returns the closest matching tag for a given version.
-// Closest means the latest one that is not after the current release.
-// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
-// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
-// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
-//
-// NOTE(rsc): Eventually we will need to decide on some logic here.
-// For now, there is only "go1".  This matches the docs in go help get.
-func selectTag(goVersion string, tags []string) (match string) {
-	for _, t := range tags {
-		if t == "go1" {
-			return "go1"
-		}
-	}
-	return ""
-
-	/*
-		if goTag.MatchString(goVersion) {
-			v := goVersion
-			for _, t := range tags {
-				if !goTag.MatchString(t) {
-					continue
-				}
-				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
-					match = t
-				}
-			}
-		}
-
-		return match
-	*/
-}
-
-// cmpGoVersion returns -1, 0, +1 reporting whether
-// x < y, x == y, or x > y.
-func cmpGoVersion(x, y string) int {
-	// Malformed strings compare less than well-formed strings.
-	if !goTag.MatchString(x) {
-		return -1
-	}
-	if !goTag.MatchString(y) {
-		return +1
-	}
-
-	// Compare numbers in sequence.
-	xx := strings.Split(x[len("go"):], ".")
-	yy := strings.Split(y[len("go"):], ".")
-
-	for i := 0; i < len(xx) && i < len(yy); i++ {
-		// The Atoi are guaranteed to succeed
-		// because the versions match goTag.
-		xi, _ := strconv.Atoi(xx[i])
-		yi, _ := strconv.Atoi(yy[i])
-		if xi < yi {
-			return -1
-		} else if xi > yi {
-			return +1
-		}
-	}
-
-	if len(xx) < len(yy) {
-		return -1
-	}
-	if len(xx) > len(yy) {
-		return +1
-	}
-	return 0
-}
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index fa78578..a59da8b 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -7,7 +7,6 @@ package main_test
 import (
 	"bytes"
 	"fmt"
-	"go/build"
 	"go/format"
 	"internal/race"
 	"internal/testenv"
@@ -74,6 +73,13 @@ func init() {
 	}
 }
 
+// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
+// build from this process's current GOROOT, but run from a different
+// (temp) directory.
+var testGOROOT string
+
+var testCC string
+
 // The TestMain function creates a go command for testing purposes and
 // deletes it after the tests have been run.
 func TestMain(m *testing.M) {
@@ -88,6 +94,20 @@ func TestMain(m *testing.M) {
 			os.Exit(2)
 		}
 
+		out, err = exec.Command("go", "env", "GOROOT").CombinedOutput()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "could not find testing GOROOT: %v\n%s", err, out)
+			os.Exit(2)
+		}
+		testGOROOT = strings.TrimSpace(string(out))
+
+		out, err = exec.Command("go", "env", "CC").CombinedOutput()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out)
+			os.Exit(2)
+		}
+		testCC = strings.TrimSpace(string(out))
+
 		if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil {
 			fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
 			canRun = false
@@ -100,7 +120,9 @@ func TestMain(m *testing.M) {
 
 		switch runtime.GOOS {
 		case "linux", "darwin", "freebsd", "windows":
-			canRace = canCgo && runtime.GOARCH == "amd64"
+			// The race detector doesn't work on Alpine Linux:
+			// golang.org/issue/14481
+			canRace = canCgo && runtime.GOARCH == "amd64" && !isAlpineLinux()
 		}
 	}
 
@@ -111,7 +133,7 @@ func TestMain(m *testing.M) {
 	if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
 		// On some systems the default C compiler is ccache.
 		// Setting HOME to a non-existent directory will break
-		// those systems.  Set CCACHE_DIR to cope.  Issue 17668.
+		// those systems. Set CCACHE_DIR to cope. Issue 17668.
 		os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
 	}
 	os.Setenv("HOME", "/test-go-home-does-not-exist")
@@ -125,6 +147,14 @@ func TestMain(m *testing.M) {
 	os.Exit(r)
 }
 
+func isAlpineLinux() bool {
+	if runtime.GOOS != "linux" {
+		return false
+	}
+	fi, err := os.Lstat("/etc/alpine-release")
+	return err == nil && fi.Mode().IsRegular()
+}
+
 // 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.
@@ -244,6 +274,13 @@ func (tg *testgoData) unsetenv(name string) {
 	}
 }
 
+func (tg *testgoData) goTool() string {
+	if tg.wd == "" {
+		return "./testgo" + exeSuffix
+	}
+	return filepath.Join(tg.wd, "testgo"+exeSuffix)
+}
+
 // doRun runs the test go command, recording stdout and stderr and
 // returning exit status.
 func (tg *testgoData) doRun(args []string) error {
@@ -257,13 +294,20 @@ func (tg *testgoData) doRun(args []string) error {
 			}
 		}
 	}
-	tg.t.Logf("running testgo %v", args)
-	var prog string
-	if tg.wd == "" {
-		prog = "./testgo" + exeSuffix
-	} else {
-		prog = filepath.Join(tg.wd, "testgo"+exeSuffix)
+
+	hasGoroot := false
+	for _, v := range tg.env {
+		if strings.HasPrefix(v, "GOROOT=") {
+			hasGoroot = true
+			break
+		}
 	}
+	prog := tg.goTool()
+	if !hasGoroot {
+		tg.setenv("GOROOT", testGOROOT)
+	}
+
+	tg.t.Logf("running testgo %v", args)
 	cmd := exec.Command(prog, args...)
 	tg.stdout.Reset()
 	tg.stderr.Reset()
@@ -358,7 +402,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
-// searching, "output" or "error".  The msg argument is logged on
+// searching, "output" or "error". The msg argument is logged on
 // failure.
 func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
 	if !tg.doGrepMatch(match, b) {
@@ -1739,7 +1783,7 @@ func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
 	tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
 }
 
-// Issue 4186.  go get cannot be used to download packages to $GOROOT.
+// Issue 4186. go get cannot be used to download packages to $GOROOT.
 // Test that without GOPATH set, go get should fail.
 func TestGoGetIntoGOROOT(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
@@ -1873,10 +1917,7 @@ func TestGoTestDashIDashOWritesBinary(t *testing.T) {
 
 // Issue 4568.
 func TestSymlinksList(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("skipping symlink test on %s", runtime.GOOS)
-	}
+	testenv.MustHaveSymlink(t)
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -1894,10 +1935,7 @@ func TestSymlinksList(t *testing.T) {
 
 // Issue 14054.
 func TestSymlinksVendor(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("skipping symlink test on %s", runtime.GOOS)
-	}
+	testenv.MustHaveSymlink(t)
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -1921,10 +1959,7 @@ func TestSymlinksVendor(t *testing.T) {
 
 // Issue 15201.
 func TestSymlinksVendor15201(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("skipping symlink test on %s", runtime.GOOS)
-	}
+	testenv.MustHaveSymlink(t)
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -1941,10 +1976,7 @@ func TestSymlinksVendor15201(t *testing.T) {
 }
 
 func TestSymlinksInternal(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("skipping symlink test on %s", runtime.GOOS)
-	}
+	testenv.MustHaveSymlink(t)
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2172,29 +2204,6 @@ func TestCoverageUsesAtomicModeForRace(t *testing.T) {
 	checkCoverage(tg, data)
 }
 
-func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
-	if testing.Short() {
-		t.Skip("don't build libraries for coverage in short mode")
-	}
-	if !canRace {
-		t.Skip("skipping because race detector not supported")
-	}
-
-	tg := testgo(t)
-	defer tg.cleanup()
-	tg.creatingTemp("testdata/cover.out")
-	tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-covermode=count", "-coverprofile=testdata/cover.out")
-	data := tg.getStdout() + tg.getStderr()
-	if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
-		t.Error(err)
-	} else {
-		if !bytes.Contains(out, []byte("mode: count")) {
-			t.Error("missing mode: count")
-		}
-	}
-	checkCoverage(tg, data)
-}
-
 func TestCoverageImportMainLoop(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2205,6 +2214,20 @@ func TestCoverageImportMainLoop(t *testing.T) {
 	tg.grepStderr("not an importable package", "did not detect import main")
 }
 
+func TestPluginNonMain(t *testing.T) {
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	pkg := filepath.Join(wd, "testdata", "testdep", "p2")
+
+	tg := testgo(t)
+	defer tg.cleanup()
+
+	tg.runFail("build", "-buildmode=plugin", pkg)
+}
+
 func TestTestEmpty(t *testing.T) {
 	if !canRace {
 		t.Skip("no race detector")
@@ -2231,6 +2254,9 @@ func TestTestRaceInstall(t *testing.T) {
 	if !canRace {
 		t.Skip("no race detector")
 	}
+	if testing.Short() && testenv.Builder() == "" {
+		t.Skip("don't rebuild the standard library in short mode")
+	}
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2421,7 +2447,7 @@ import "C"
 func main() { C.f() }`)
 	tg.setenv("GOPATH", tg.path("."))
 	tg.run("build", "-n", "-compiler", "gccgo", "cgoref")
-	tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
+	tg.grepStderr(`gccgo.*\-L [^ ]*alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
 }
 
 func TestListTemplateContextFunction(t *testing.T) {
@@ -2538,6 +2564,17 @@ func TestGoTestFlagsAfterPackage(t *testing.T) {
 	tg.run("test", "-v", "testdata/flag_test.go", "-args", "-v=7") // Two distinct -v flags.
 }
 
+func TestGoTestShowInProgressOnInterrupt(t *testing.T) {
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		t.Skipf("skipping test on %s - lack of full unix-like signal support", runtime.GOOS)
+	}
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "-v", "testdata/inprogress_interrupt_test.go")
+	testsInProgress := "tests in progress: TestParallel, TestSerial"
+	tg.grepStdout(testsInProgress, "tests which haven't completed should be listed in progress")
+}
+
 func TestGoTestXtestonlyWorks(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2650,8 +2687,6 @@ func TestGoGetInternalWildcard(t *testing.T) {
 }
 
 func TestGoVetWithExternalTests(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.makeTempdir()
@@ -2662,19 +2697,36 @@ func TestGoVetWithExternalTests(t *testing.T) {
 }
 
 func TestGoVetWithTags(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.makeTempdir()
 	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")
+	tg.grepBoth(`c\.go.*wrong number of args for format`, "go vet vetpkg did not run scan tagged file")
 }
 
-// Issue 9767.
-func TestGoGetRscIoToolstash(t *testing.T) {
+func TestGoVetWithFlagsOn(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.run("install", "cmd/vet")
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("vet", "-printf", "vetpkg")
+	tg.grepBoth("missing argument for Printf", "go vet -printf vetpkg did not find missing argument for Printf")
+}
+
+func TestGoVetWithFlagsOff(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.run("install", "cmd/vet")
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.run("vet", "-printf=false", "vetpkg")
+}
+
+// Issue 9767, 19769.
+func TestGoGetDotSlashDownload(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
 	tg := testgo(t)
@@ -2682,7 +2734,7 @@ func TestGoGetRscIoToolstash(t *testing.T) {
 	tg.tempDir("src/rsc.io")
 	tg.setenv("GOPATH", tg.path("."))
 	tg.cd(tg.path("src/rsc.io"))
-	tg.run("get", "./toolstash")
+	tg.run("get", "./pprof_mac_fix")
 }
 
 // Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
@@ -3022,15 +3074,8 @@ func TestGoInstallPkgdir(t *testing.T) {
 }
 
 func TestGoTestRaceInstallCgo(t *testing.T) {
-	switch sys := runtime.GOOS + "/" + runtime.GOARCH; sys {
-	case "darwin/amd64", "freebsd/amd64", "linux/amd64", "windows/amd64":
-		// ok
-	default:
-		t.Skip("no race detector on %s", sys)
-	}
-
-	if !build.Default.CgoEnabled {
-		t.Skip("no race detector without cgo")
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
 	}
 
 	// golang.org/issue/10500.
@@ -3044,7 +3089,7 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
 	tg.run("test", "-race", "-i", "runtime/race")
 	new, err := os.Stat(cgo)
 	tg.must(err)
-	if new.ModTime() != old.ModTime() {
+	if !new.ModTime().Equal(old.ModTime()) {
 		t.Fatalf("go test -i runtime/race reinstalled cmd/cgo")
 	}
 }
@@ -3114,6 +3159,20 @@ func TestGoGetUpdate(t *testing.T) {
 	tg.run("get", "-d", "-u", "github.com/rsc/go-get-issue-9224-cmd")
 }
 
+// Issue #20512.
+func TestGoGetRace(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "-race", "github.com/rsc/go-get-issue-9224-cmd")
+}
+
 func TestGoGetDomainRoot(t *testing.T) {
 	// golang.org/issue/9357.
 	// go get foo.io (not foo.io/subdir) was not working consistently.
@@ -3646,6 +3705,28 @@ func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
 	tg.grepBoth(okPattern, "go test did not say ok")
 }
 
+func TestBenchmarkLabels(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	// TODO: tg.parallel()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.run("test", "-run", "^$", "-bench", ".", "bench")
+	tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
+	tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
+	tg.grepStdout(`(?m)^pkg: bench`, "go test did not say pkg: bench")
+	tg.grepBothNot(`(?s)pkg:.*pkg:`, "go test said pkg multiple times")
+}
+
+func TestBenchmarkLabelsOutsideGOPATH(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	// TODO: tg.parallel()
+	tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
+	tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
+	tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
+	tg.grepBothNot(`(?m)^pkg:`, "go test did say pkg:")
+}
+
 func TestMatchesOnlyTestIsOK(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -3773,3 +3854,343 @@ func TestA(t *testing.T) {}`)
 	tg.grepStdout("pkgs$", "expected package not listed")
 	tg.grepStdout("pkgs/a", "expected package not listed")
 }
+
+// Issue 18975.
+func TestFFLAGS(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+
+	tg.tempFile("p/src/p/main.go", `package main
+		// #cgo FFLAGS: -no-such-fortran-flag
+		import "C"
+		func main() {}
+	`)
+	tg.tempFile("p/src/p/a.f", `! comment`)
+	tg.setenv("GOPATH", tg.path("p"))
+
+	// This should normally fail because we are passing an unknown flag,
+	// but issue #19080 points to Fortran compilers that succeed anyhow.
+	// To work either way we call doRun directly rather than run or runFail.
+	tg.doRun([]string{"build", "-x", "p"})
+
+	tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`)
+}
+
+// Issue 19198.
+// This is really a cmd/link issue but this is a convenient place to test it.
+func TestDuplicateGlobalAsmSymbols(t *testing.T) {
+	if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
+		t.Skipf("skipping test on %s", runtime.GOARCH)
+	}
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+
+	asm := `
+#include "textflag.h"
+
+DATA sym<>+0x0(SB)/8,$0
+GLOBL sym<>(SB),(NOPTR+RODATA),$8
+
+TEXT ·Data(SB),NOSPLIT,$0
+	MOVB sym<>(SB), AX
+	MOVB AX, ret+0(FP)
+	RET
+`
+	tg.tempFile("go/src/a/a.s", asm)
+	tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`)
+	tg.tempFile("go/src/b/b.s", asm)
+	tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`)
+	tg.tempFile("go/src/p/p.go", `
+package main
+import "a"
+import "b"
+import "C"
+func main() {
+	_ = a.Data() + b.Data()
+}
+`)
+	tg.setenv("GOPATH", tg.path("go"))
+	exe := filepath.Join(tg.tempdir, "p.exe")
+	tg.creatingTemp(exe)
+	tg.run("build", "-o", exe, "p")
+}
+
+func TestBuildTagsNoComma(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("go"))
+	tg.run("install", "-tags", "tag1 tag2", "math")
+	tg.runFail("install", "-tags", "tag1,tag2", "math")
+	tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
+	tg.runFail("build", "-tags", "tag1,tag2", "math")
+	tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
+}
+
+func copyFile(src, dst string, perm os.FileMode) error {
+	sf, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sf.Close()
+
+	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+	if err != nil {
+		return err
+	}
+
+	_, err = io.Copy(df, sf)
+	err2 := df.Close()
+	if err != nil {
+		return err
+	}
+	return err2
+}
+
+func TestExecutableGOROOT(t *testing.T) {
+	if runtime.GOOS == "openbsd" {
+		t.Skipf("test case does not work on %s, missing os.Executable", runtime.GOOS)
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+
+	tg.makeTempdir()
+	tg.tempDir("newgoroot/bin")
+	newGoTool := tg.path("newgoroot/bin/go" + exeSuffix)
+	err := copyFile(tg.goTool(), newGoTool, 0775)
+	if err != nil {
+		t.Fatalf("error copying go tool %v", err)
+	}
+
+	goroot := func(goTool string) string {
+		cmd := exec.Command(goTool, "env", "GOROOT")
+		cmd.Env = os.Environ()
+		for i, val := range cmd.Env {
+			if strings.HasPrefix(val, "GOROOT=") {
+				cmd.Env = append(cmd.Env[:i], cmd.Env[i+1:]...)
+				break
+			}
+		}
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			t.Fatalf("copied go tool failed %v: %s", err, out)
+		}
+		root := strings.TrimSpace(string(out))
+		resolved, err := filepath.EvalSymlinks(root)
+		if err != nil {
+			t.Fatalf("EvalSymlinks(%q) failed: %v", root, err)
+		}
+		return resolved
+	}
+
+	// Filenames are case insensitive on Windows.
+	// There should probably be a path/filepath function for this.
+	equal := func(a, b string) bool { return a == b }
+	if runtime.GOOS == "windows" {
+		equal = strings.EqualFold
+	}
+
+	// macOS uses a symlink for /tmp.
+	resolvedTestGOROOT, err := filepath.EvalSymlinks(testGOROOT)
+	if err != nil {
+		t.Fatalf("could not eval testgoroot symlinks: %v", err)
+	}
+
+	// Missing GOROOT/pkg/tool, the go tool should fall back to
+	// its default path.
+	if got, want := goroot(newGoTool), resolvedTestGOROOT; !equal(got, want) {
+		t.Fatalf("%s env GOROOT = %q, want %q", newGoTool, got, want)
+	}
+
+	// Now the executable's path looks like a GOROOT.
+	tg.tempDir("newgoroot/pkg/tool")
+	resolvedNewGOROOT, err := filepath.EvalSymlinks(tg.path("newgoroot"))
+	if err != nil {
+		t.Fatalf("could not eval newgoroot symlinks: %v", err)
+	}
+	if got, want := goroot(newGoTool), resolvedNewGOROOT; !equal(got, want) {
+		t.Fatalf("%s env GOROOT = %q with pkg/tool, want %q", newGoTool, got, want)
+	}
+
+	testenv.MustHaveSymlink(t)
+
+	tg.tempDir("notgoroot/bin")
+	symGoTool := tg.path("notgoroot/bin/go" + exeSuffix)
+	tg.must(os.Symlink(newGoTool, symGoTool))
+
+	if got, want := goroot(symGoTool), resolvedNewGOROOT; !equal(got, want) {
+		t.Fatalf("%s env GOROOT = %q, want %q", symGoTool, got, want)
+	}
+}
+
+func TestNeedVersion(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("goversion.go", `package main; func main() {}`)
+	path := tg.path("goversion.go")
+	tg.setenv("TESTGO_VERSION", "go1.testgo")
+	tg.runFail("run", path)
+	tg.grepStderr("compile", "does not match go tool version")
+}
+
+// Test that user can override default code generation flags.
+func TestUserOverrideFlags(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+	if runtime.GOOS != "linux" {
+		// We are testing platform-independent code, so it's
+		// OK to skip cases that work differently.
+		t.Skipf("skipping on %s because test only works if c-archive implies -shared", runtime.GOOS)
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("override.go", `package main
+
+import "C"
+
+//export GoFunc
+func GoFunc() {}
+
+func main() {}`)
+	tg.creatingTemp("override.a")
+	tg.creatingTemp("override.h")
+	tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=-shared=false", tg.path("override.go"))
+	tg.grepStderr("compile .*-shared .*-shared=false", "user can not override code generation flag")
+}
+
+func TestCgoFlagContainsSpace(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+
+	ccName := filepath.Base(testCC)
+
+	tg.tempFile(fmt.Sprintf("src/%s/main.go", ccName), fmt.Sprintf(`package main
+		import (
+			"os"
+			"os/exec"
+			"strings"
+		)
+
+		func main() {
+			cmd := exec.Command(%q, os.Args[1:]...)
+			cmd.Stdin = os.Stdin
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			err := cmd.Run()
+			if err != nil {
+				panic(err)
+			}
+
+			if os.Args[len(os.Args)-1] == "trivial.c" {
+				return
+			}
+
+			var success bool
+			for _, arg := range os.Args {
+				switch {
+				case strings.Contains(arg, "c flags"):
+					if success {
+						panic("duplicate CFLAGS")
+					}
+					success = true
+				case strings.Contains(arg, "ld flags"):
+					if success {
+						panic("duplicate LDFLAGS")
+					}
+					success = true
+				}
+			}
+			if !success {
+				panic("args should contains '-Ic flags' or '-Lld flags'")
+			}
+		}
+	`, testCC))
+	tg.cd(tg.path(fmt.Sprintf("src/%s", ccName)))
+	tg.run("build")
+	tg.setenv("CC", tg.path(fmt.Sprintf("src/%s/%s", ccName, ccName)))
+
+	tg.tempFile("src/cgo/main.go", `package main
+		// #cgo CFLAGS: -I"c flags"
+		// #cgo LDFLAGS: -L"ld flags"
+		import "C"
+		func main() {}
+	`)
+	tg.cd(tg.path("src/cgo"))
+	tg.run("run", "main.go")
+}
+
+// Issue #20435.
+func TestGoTestRaceCoverModeFailures(t *testing.T) {
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
+	}
+
+	tg := testgo(t)
+	tg.parallel()
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+
+	tg.run("test", "testrace")
+
+	tg.runFail("test", "-race", "-covermode=set", "testrace")
+	tg.grepStderr(`-covermode must be "atomic", not "set", when -race is enabled`, "-race -covermode=set was allowed")
+	tg.grepBothNot("PASS", "something passed")
+}
+
+// Issue 9737: verify that GOARM and GO386 affect the computed build ID.
+func TestBuildIDContainsArchModeEnv(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+
+	var tg *testgoData
+	testWith := func(before, after func()) func(*testing.T) {
+		return func(t *testing.T) {
+			tg = testgo(t)
+			defer tg.cleanup()
+			tg.tempFile("src/mycmd/x.go", `package main
+func main() {}`)
+			tg.setenv("GOPATH", tg.path("."))
+
+			tg.cd(tg.path("src/mycmd"))
+			tg.setenv("GOOS", "linux")
+			before()
+			tg.run("install", "mycmd")
+			after()
+			tg.wantStale("mycmd", "build ID mismatch", "should be stale after environment variable change")
+		}
+	}
+
+	t.Run("386", testWith(func() {
+		tg.setenv("GOARCH", "386")
+		tg.setenv("GO386", "387")
+	}, func() {
+		tg.setenv("GO386", "sse2")
+	}))
+
+	t.Run("arm", testWith(func() {
+		tg.setenv("GOARCH", "arm")
+		tg.setenv("GOARM", "5")
+	}, func() {
+		tg.setenv("GOARM", "7")
+	}))
+}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
deleted file mode 100644
index 0c663ad..0000000
--- a/src/cmd/go/help.go
+++ /dev/null
@@ -1,607 +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 main
-
-var helpC = &Command{
-	UsageLine: "c",
-	Short:     "calling between Go and C",
-	Long: `
-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.
-	`,
-}
-
-var helpPackages = &Command{
-	UsageLine: "packages",
-	Short:     "description of package lists",
-	Long: `
-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 (For more details 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.
-
-Import paths beginning with "cmd/" only match source code in
-the Go repository.
-
-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".
-	`,
-}
-
-var helpImportPath = &Command{
-	UsageLine: "importpath",
-	Short:     "import path syntax",
-	Long: `
-
-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 (For more
-details 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://.
-
-By default, downloads are restricted to known secure protocols
-(e.g. https, ssh). To override this setting for Git downloads, the
-GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
-'go help environment').
-
-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 (For more details 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.
-	`,
-}
-
-var helpGopath = &Command{
-	UsageLine: "gopath",
-	Short:     "GOPATH environment variable",
-	Long: `
-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.
-
-If the environment variable is unset, GOPATH defaults
-to a subdirectory named "go" in the user's home directory
-($HOME/go on Unix, %USERPROFILE%\go on Windows),
-unless that directory holds a Go distribution.
-Run "go env GOPATH" to see the current GOPATH.
-
-See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
-
-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/go
-
-    /home/user/go/
-        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/go/
-        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/go/
-        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.
-	`,
-}
-
-var helpEnvironment = &Command{
-	UsageLine: "environment",
-	Short:     "environment variables",
-	Long: `
-
-The go command, and the tools it invokes, examine a few different
-environment variables. For many of these, you can see the default
-value of on your system by running 'go env NAME', where NAME is the
-name of the variable.
-
-General-purpose environment variables:
-
-	GCCGO
-		The gccgo command to run for 'go build -compiler=gccgo'.
-	GOARCH
-		The architecture, or processor, for which to compile code.
-		Examples are amd64, 386, arm, ppc64.
-	GOBIN
-		The directory where 'go install' will install a command.
-	GOOS
-		The operating system for which to compile code.
-		Examples are linux, darwin, windows, netbsd.
-	GOPATH
-		For more details 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_FFLAGS
-		Flags that cgo will pass to the compiler when compiling
-		Fortran code.
-	CGO_LDFLAGS
-		Flags that cgo will pass to the compiler when linking.
-	CXX
-		The command to use to compile C++ code.
-	PKG_CONFIG
-		Path to pkg-config tool.
-
-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.
-	GIT_ALLOW_PROTOCOL
-		Defined by Git. A colon-separated list of schemes that are allowed to be used
-		with git fetch/clone. If set, any scheme not explicitly mentioned will be
-		considered insecure by 'go get'.
-	`,
-}
-
-var helpFileType = &Command{
-	UsageLine: "filetype",
-	Short:     "file types",
-	Long: `
-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.
-	`,
-}
-
-var helpBuildmode = &Command{
-	UsageLine: "buildmode",
-	Short:     "description of build modes",
-	Long: `
-The 'go build' and 'go install' commands take a -buildmode argument which
-indicates which kind of object file is to be built. Currently supported values
-are:
-
-	-buildmode=archive
-		Build the listed non-main packages into .a files. Packages named
-		main are ignored.
-
-	-buildmode=c-archive
-		Build the listed main package, plus all packages it imports,
-		into a C archive file. The only callable symbols will be those
-		functions exported using a cgo //export comment. Requires
-		exactly one main package to be listed.
-
-	-buildmode=c-shared
-		Build the listed main packages, plus all packages that they
-		import, into C shared libraries. The only callable symbols will
-		be those functions exported using a cgo //export comment.
-		Non-main packages are ignored.
-
-	-buildmode=default
-		Listed main packages are built into executables and listed
-		non-main packages are built into .a files (the default
-		behavior).
-
-	-buildmode=shared
-		Combine all the listed non-main packages into a single shared
-		library that will be used when building with the -linkshared
-		option. Packages named main are ignored.
-
-	-buildmode=exe
-		Build the listed main packages and everything they import into
-		executables. Packages not named main are ignored.
-
-	-buildmode=pie
-		Build the listed main packages and everything they import into
-		position independent executables (PIE). Packages not named
-		main are ignored.
-
-	-buildmode=plugin
-		Build the listed main packages, plus all packages that they
-		import, into a Go plugin. Packages not named main are ignored.
-`,
-}
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
deleted file mode 100644
index dcb4e9f..0000000
--- a/src/cmd/go/http.go
+++ /dev/null
@@ -1,120 +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 !cmd_go_bootstrap
-
-// This code is compiled into the real 'go' binary, but it is not
-// compiled into the binary that is built during all.bash, so as
-// to avoid needing to build net (and thus use cgo) during the
-// bootstrap process.
-
-package main
-
-import (
-	"cmd/internal/browser"
-	"crypto/tls"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"net/url"
-	"time"
-)
-
-// httpClient is the default HTTP client, but a variable so it can be
-// changed by tests, without modifying http.DefaultClient.
-var httpClient = http.DefaultClient
-
-// impatientInsecureHTTPClient is used in -insecure mode,
-// when we're connecting to https servers that might not be there
-// or might be using self-signed certificates.
-var impatientInsecureHTTPClient = &http.Client{
-	Timeout: 5 * time.Second,
-	Transport: &http.Transport{
-		Proxy: http.ProxyFromEnvironment,
-		TLSClientConfig: &tls.Config{
-			InsecureSkipVerify: true,
-		},
-	},
-}
-
-type httpError struct {
-	status     string
-	statusCode int
-	url        string
-}
-
-func (e *httpError) Error() string {
-	return fmt.Sprintf("%s: %s", e.url, e.status)
-}
-
-// httpGET returns the data from an HTTP GET request for the given URL.
-func httpGET(url string) ([]byte, error) {
-	resp, err := httpClient.Get(url)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-	if resp.StatusCode != 200 {
-		err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url}
-
-		return nil, err
-	}
-	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, fmt.Errorf("%s: %v", url, err)
-	}
-	return b, nil
-}
-
-// httpsOrHTTP returns the body of either the importPath's
-// https resource or, if unavailable, the http resource.
-func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body io.ReadCloser, err error) {
-	fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
-		u, err := url.Parse(scheme + "://" + importPath)
-		if err != nil {
-			return "", nil, err
-		}
-		u.RawQuery = "go-get=1"
-		urlStr = u.String()
-		if buildV {
-			log.Printf("Fetching %s", urlStr)
-		}
-		if security == insecure && scheme == "https" { // fail earlier
-			res, err = impatientInsecureHTTPClient.Get(urlStr)
-		} else {
-			res, err = httpClient.Get(urlStr)
-		}
-		return
-	}
-	closeBody := func(res *http.Response) {
-		if res != nil {
-			res.Body.Close()
-		}
-	}
-	urlStr, res, err := fetch("https")
-	if err != nil {
-		if buildV {
-			log.Printf("https fetch failed: %v", err)
-		}
-		if security == insecure {
-			closeBody(res)
-			urlStr, res, err = fetch("http")
-		}
-	}
-	if err != nil {
-		closeBody(res)
-		return "", nil, err
-	}
-	// Note: accepting a non-200 OK here, so people can serve a
-	// meta import in their http 404 page.
-	if buildV {
-		log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
-	}
-	return urlStr, res.Body, nil
-}
-
-func queryEscape(s string) string { return url.QueryEscape(s) }
-func openBrowser(url string) bool { return browser.Open(url) }
diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go
new file mode 100644
index 0000000..aff33f7
--- /dev/null
+++ b/src/cmd/go/internal/base/base.go
@@ -0,0 +1,173 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package base defines shared basic pieces of the go command,
+// in particular logging and the Command structure.
+package base
+
+import (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/scanner"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/str"
+)
+
+// A Command is an implementation of a go command
+// like go build or go fix.
+type Command struct {
+	// Run runs the command.
+	// The args are the arguments after the command name.
+	Run func(cmd *Command, args []string)
+
+	// UsageLine is the one-line usage message.
+	// The first word in the line is taken to be the command name.
+	UsageLine string
+
+	// Short is the short description shown in the 'go help' output.
+	Short string
+
+	// Long is the long message shown in the 'go help <this-command>' output.
+	Long string
+
+	// Flag is a set of flags specific to this command.
+	Flag flag.FlagSet
+
+	// CustomFlags indicates that the command will do its own
+	// flag parsing.
+	CustomFlags bool
+}
+
+// Commands lists the available commands and help topics.
+// The order here is the order in which they are printed by 'go help'.
+var Commands []*Command
+
+// Name returns the command's name: the first word in the usage line.
+func (c *Command) Name() string {
+	name := c.UsageLine
+	i := strings.Index(name, " ")
+	if i >= 0 {
+		name = name[:i]
+	}
+	return name
+}
+
+func (c *Command) Usage() {
+	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
+	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
+	os.Exit(2)
+}
+
+// Runnable reports whether the command can be run; otherwise
+// it is a documentation pseudo-command such as importpath.
+func (c *Command) Runnable() bool {
+	return c.Run != nil
+}
+
+var atExitFuncs []func()
+
+func AtExit(f func()) {
+	atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit() {
+	for _, f := range atExitFuncs {
+		f()
+	}
+	os.Exit(exitStatus)
+}
+
+func Fatalf(format string, args ...interface{}) {
+	Errorf(format, args...)
+	Exit()
+}
+
+func Errorf(format string, args ...interface{}) {
+	log.Printf(format, args...)
+	SetExitStatus(1)
+}
+
+func ExitIfErrors() {
+	if exitStatus != 0 {
+		Exit()
+	}
+}
+
+var exitStatus = 0
+var exitMu sync.Mutex
+
+func SetExitStatus(n int) {
+	exitMu.Lock()
+	if exitStatus < n {
+		exitStatus = n
+	}
+	exitMu.Unlock()
+}
+
+// Run runs the command, with stdout and stderr
+// connected to the go command's own stdout and stderr.
+// If the command fails, Run reports the error using Errorf.
+func Run(cmdargs ...interface{}) {
+	cmdline := str.StringList(cmdargs...)
+	if cfg.BuildN || cfg.BuildX {
+		fmt.Printf("%s\n", strings.Join(cmdline, " "))
+		if cfg.BuildN {
+			return
+		}
+	}
+
+	cmd := exec.Command(cmdline[0], cmdline[1:]...)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Run(); err != nil {
+		Errorf("%v", err)
+	}
+}
+
+// RunStdin is like run but connects Stdin.
+func RunStdin(cmdline []string) {
+	cmd := exec.Command(cmdline[0], cmdline[1:]...)
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	cmd.Env = cfg.OrigEnv
+	StartSigHandlers()
+	if err := cmd.Run(); err != nil {
+		Errorf("%v", err)
+	}
+}
+
+// Usage is the usage-reporting function, filled in by package main
+// but here for reference by other packages.
+var Usage func()
+
+// ExpandScanner expands a scanner.List error into all the errors in the list.
+// The default Error method only shows the first error
+// and does not shorten paths.
+func ExpandScanner(err error) error {
+	// Look for parser errors.
+	if err, ok := err.(scanner.ErrorList); ok {
+		// 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
+		// instead of just the first, as err.Error does.
+		var buf bytes.Buffer
+		for _, e := range err {
+			e.Pos.Filename = ShortPath(e.Pos.Filename)
+			buf.WriteString("\n")
+			buf.WriteString(e.Error())
+		}
+		return errors.New(buf.String())
+	}
+	return err
+}
diff --git a/src/cmd/go/internal/base/env.go b/src/cmd/go/internal/base/env.go
new file mode 100644
index 0000000..fcade9d
--- /dev/null
+++ b/src/cmd/go/internal/base/env.go
@@ -0,0 +1,37 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import "strings"
+
+// EnvForDir returns a copy of the environment
+// suitable for running in the given directory.
+// The environment is the current process's environment
+// but with an updated $PWD, so that an os.Getwd in the
+// child will be faster.
+func EnvForDir(dir string, base []string) []string {
+	// Internally we only use rooted paths, so dir is rooted.
+	// Even if dir is not rooted, no harm done.
+	return MergeEnvLists([]string{"PWD=" + dir}, base)
+}
+
+// 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
+}
diff --git a/src/cmd/go/internal/base/flag.go b/src/cmd/go/internal/base/flag.go
new file mode 100644
index 0000000..5e03e64
--- /dev/null
+++ b/src/cmd/go/internal/base/flag.go
@@ -0,0 +1,35 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+	"flag"
+
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/str"
+)
+
+// A StringsFlag is a command-line flag that interprets its argument
+// as a space-separated list of possibly-quoted strings.
+type StringsFlag []string
+
+func (v *StringsFlag) Set(s string) error {
+	var err error
+	*v, err = str.SplitQuotedFields(s)
+	if *v == nil {
+		*v = []string{}
+	}
+	return err
+}
+
+func (v *StringsFlag) String() string {
+	return "<StringsFlag>"
+}
+
+// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
+func AddBuildFlagsNX(flags *flag.FlagSet) {
+	flags.BoolVar(&cfg.BuildN, "n", false, "")
+	flags.BoolVar(&cfg.BuildX, "x", false, "")
+}
diff --git a/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go
new file mode 100644
index 0000000..4f12fa8
--- /dev/null
+++ b/src/cmd/go/internal/base/path.go
@@ -0,0 +1,74 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+func getwd() string {
+	wd, err := os.Getwd()
+	if err != nil {
+		Fatalf("cannot determine current directory: %v", err)
+	}
+	return wd
+}
+
+var Cwd = getwd()
+
+// ShortPath returns an absolute or relative name for path, whatever is shorter.
+func ShortPath(path string) string {
+	if rel, err := filepath.Rel(Cwd, path); err == nil && len(rel) < len(path) {
+		return rel
+	}
+	return path
+}
+
+// RelPaths returns a copy of paths with absolute paths
+// made relative to the current directory if they would be shorter.
+func RelPaths(paths []string) []string {
+	var out []string
+	// TODO(rsc): Can this use Cwd from above?
+	pwd, _ := os.Getwd()
+	for _, p := range paths {
+		rel, err := filepath.Rel(pwd, p)
+		if err == nil && len(rel) < len(p) {
+			p = rel
+		}
+		out = append(out, p)
+	}
+	return out
+}
+
+// FilterDotUnderscoreFiles returns a slice containing all elements
+// of path whose base name doesn't begin with "." or "_".
+func FilterDotUnderscoreFiles(path []string) []string {
+	var out []string // lazily initialized
+	for i, p := range path {
+		base := filepath.Base(p)
+		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") {
+			if out == nil {
+				out = append(make([]string, 0, len(path)), path[:i]...)
+			}
+			continue
+		}
+		if out != nil {
+			out = append(out, p)
+		}
+	}
+	if out == nil {
+		return path
+	}
+	return out
+}
+
+// IsTestFile reports whether the source file is a set of tests and should therefore
+// be excluded from coverage analysis.
+func IsTestFile(file string) bool {
+	// We don't cover tests, only the code they test.
+	return strings.HasSuffix(file, "_test.go")
+}
diff --git a/src/cmd/go/internal/base/signal.go b/src/cmd/go/internal/base/signal.go
new file mode 100644
index 0000000..54d1187
--- /dev/null
+++ b/src/cmd/go/internal/base/signal.go
@@ -0,0 +1,31 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+	"os"
+	"os/signal"
+	"sync"
+)
+
+// Interrupted is closed when the go command receives an interrupt signal.
+var Interrupted = make(chan struct{})
+
+// processSignals setups signal handler.
+func processSignals() {
+	sig := make(chan os.Signal)
+	signal.Notify(sig, signalsToIgnore...)
+	go func() {
+		<-sig
+		close(Interrupted)
+	}()
+}
+
+var onceProcessSignals sync.Once
+
+// StartSigHandlers starts the signal handlers.
+func StartSigHandlers() {
+	onceProcessSignals.Do(processSignals)
+}
diff --git a/src/cmd/go/internal/base/signal_notunix.go b/src/cmd/go/internal/base/signal_notunix.go
new file mode 100644
index 0000000..9e869b0
--- /dev/null
+++ b/src/cmd/go/internal/base/signal_notunix.go
@@ -0,0 +1,17 @@
+// Copyright 2012 The Go Authors. 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 base
+
+import (
+	"os"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt}
+
+// SignalTrace is the signal to send to make a Go program
+// crash with a stack trace (no such signal in this case).
+var SignalTrace os.Signal = nil
diff --git a/src/cmd/go/internal/base/signal_unix.go b/src/cmd/go/internal/base/signal_unix.go
new file mode 100644
index 0000000..4ca3da9
--- /dev/null
+++ b/src/cmd/go/internal/base/signal_unix.go
@@ -0,0 +1,18 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package base
+
+import (
+	"os"
+	"syscall"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
+
+// SignalTrace is the signal to send to make a Go program
+// crash with a stack trace.
+var SignalTrace os.Signal = syscall.SIGQUIT
diff --git a/src/cmd/go/internal/base/tool.go b/src/cmd/go/internal/base/tool.go
new file mode 100644
index 0000000..c907772
--- /dev/null
+++ b/src/cmd/go/internal/base/tool.go
@@ -0,0 +1,53 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+	"fmt"
+	"go/build"
+	"os"
+	"path/filepath"
+	"runtime"
+
+	"cmd/go/internal/cfg"
+)
+
+// Configuration for finding tool binaries.
+var (
+	ToolGOOS      = runtime.GOOS
+	ToolGOARCH    = runtime.GOARCH
+	ToolIsWindows = ToolGOOS == "windows"
+	ToolDir       = build.ToolDir
+)
+
+const ToolWindowsExtension = ".exe"
+
+// Tool returns the path to the named tool (for example, "vet").
+// If the tool cannot be found, Tool exits the process.
+func Tool(toolName string) string {
+	toolPath := filepath.Join(ToolDir, toolName)
+	if ToolIsWindows {
+		toolPath += ToolWindowsExtension
+	}
+	if len(cfg.BuildToolexec) > 0 {
+		return toolPath
+	}
+	// Give a nice message if there is no tool with that name.
+	if _, err := os.Stat(toolPath); err != nil {
+		if isInGoToolsRepo(toolName) {
+			fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
+		} else {
+			fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
+		}
+		SetExitStatus(2)
+		Exit()
+	}
+	return toolPath
+}
+
+// TODO: Delete.
+func isInGoToolsRepo(toolName string) bool {
+	return false
+}
diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go
new file mode 100644
index 0000000..963da94
--- /dev/null
+++ b/src/cmd/go/internal/bug/bug.go
@@ -0,0 +1,218 @@
+// Copyright 2016 The Go Authors. 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 implements the ``go bug'' command.
+package bug
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/envcmd"
+	"cmd/go/internal/web"
+)
+
+var CmdBug = &base.Command{
+	Run:       runBug,
+	UsageLine: "bug",
+	Short:     "start a bug report",
+	Long: `
+Bug opens the default browser and starts a new bug report.
+The report includes useful system information.
+	`,
+}
+
+func init() {
+	CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+}
+
+func runBug(cmd *base.Command, args []string) {
+	var buf bytes.Buffer
+	buf.WriteString(bugHeader)
+	inspectGoVersion(&buf)
+	fmt.Fprint(&buf, "#### System details\n\n")
+	fmt.Fprintln(&buf, "```")
+	fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
+	env := cfg.CmdEnv
+	env = append(env, envcmd.ExtraEnvVars()...)
+	for _, e := range env {
+		// Hide the TERM environment variable from "go bug".
+		// See issue #18128
+		if e.Name != "TERM" {
+			fmt.Fprintf(&buf, "%s=\"%s\"\n", e.Name, e.Value)
+		}
+	}
+	printGoDetails(&buf)
+	printOSDetails(&buf)
+	printCDetails(&buf)
+	fmt.Fprintln(&buf, "```")
+
+	body := buf.String()
+	url := "https://github.com/golang/go/issues/new?body=" + web.QueryEscape(body)
+	if !web.OpenBrowser(url) {
+		fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
+		fmt.Print(body)
+	}
+}
+
+const bugHeader = `Please answer these questions before submitting your issue. Thanks!
+
+#### What did you do?
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+A link on play.golang.org is best.
+
+
+#### What did you expect to see?
+
+
+#### What did you see instead?
+
+
+`
+
+func printGoDetails(w io.Writer) {
+	printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
+	printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
+}
+
+func printOSDetails(w io.Writer) {
+	switch runtime.GOOS {
+	case "darwin":
+		printCmdOut(w, "uname -v: ", "uname", "-v")
+		printCmdOut(w, "", "sw_vers")
+	case "linux":
+		printCmdOut(w, "uname -sr: ", "uname", "-sr")
+		printCmdOut(w, "", "lsb_release", "-a")
+		printGlibcVersion(w)
+	case "openbsd", "netbsd", "freebsd", "dragonfly":
+		printCmdOut(w, "uname -v: ", "uname", "-v")
+	case "solaris":
+		out, err := ioutil.ReadFile("/etc/release")
+		if err == nil {
+			fmt.Fprintf(w, "/etc/release: %s\n", out)
+		} else {
+			if cfg.BuildV {
+				fmt.Printf("failed to read /etc/release: %v\n", err)
+			}
+		}
+	}
+}
+
+func printCDetails(w io.Writer) {
+	printCmdOut(w, "lldb --version: ", "lldb", "--version")
+	cmd := exec.Command("gdb", "--version")
+	out, err := cmd.Output()
+	if err == nil {
+		// There's apparently no combination of command line flags
+		// to get gdb to spit out its version without the license and warranty.
+		// Print up to the first newline.
+		fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
+	} else {
+		if cfg.BuildV {
+			fmt.Printf("failed to run gdb --version: %v\n", err)
+		}
+	}
+}
+
+func inspectGoVersion(w io.Writer) {
+	data, err := web.Get("https://golang.org/VERSION?m=text")
+	if err != nil {
+		if cfg.BuildV {
+			fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
+		}
+		return
+	}
+
+	// golang.org/VERSION currently returns a whitespace-free string,
+	// but just in case, protect against that changing.
+	// Similarly so for runtime.Version.
+	release := string(bytes.TrimSpace(data))
+	vers := strings.TrimSpace(runtime.Version())
+
+	if vers == release {
+		// Up to date
+		return
+	}
+
+	// Devel version or outdated release. Either way, this request is apropos.
+	fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
+}
+
+// printCmdOut prints the output of running the given command.
+// It ignores failures; 'go bug' is best effort.
+func printCmdOut(w io.Writer, prefix, path string, args ...string) {
+	cmd := exec.Command(path, args...)
+	out, err := cmd.Output()
+	if err != nil {
+		if cfg.BuildV {
+			fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
+		}
+		return
+	}
+	fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
+}
+
+// firstLine returns the first line of a given byte slice.
+func firstLine(buf []byte) []byte {
+	idx := bytes.IndexByte(buf, '\n')
+	if idx > 0 {
+		buf = buf[:idx]
+	}
+	return bytes.TrimSpace(buf)
+}
+
+// printGlibcVersion prints information about the glibc version.
+// It ignores failures.
+func printGlibcVersion(w io.Writer) {
+	tempdir := os.TempDir()
+	if tempdir == "" {
+		return
+	}
+	src := []byte(`int main() {}`)
+	srcfile := filepath.Join(tempdir, "go-bug.c")
+	outfile := filepath.Join(tempdir, "go-bug")
+	err := ioutil.WriteFile(srcfile, src, 0644)
+	if err != nil {
+		return
+	}
+	defer os.Remove(srcfile)
+	cmd := exec.Command("gcc", "-o", outfile, srcfile)
+	if _, err = cmd.CombinedOutput(); err != nil {
+		return
+	}
+	defer os.Remove(outfile)
+
+	cmd = exec.Command("ldd", outfile)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return
+	}
+	re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
+	m := re.FindStringSubmatch(string(out))
+	if m == nil {
+		return
+	}
+	cmd = exec.Command(m[1])
+	out, err = cmd.Output()
+	if err != nil {
+		return
+	}
+	fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
+
+	// print another line (the one containing version string) in case of musl libc
+	if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
+		fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
+	}
+}
diff --git a/src/cmd/go/internal/buildid/buildid.go b/src/cmd/go/internal/buildid/buildid.go
new file mode 100644
index 0000000..091c909
--- /dev/null
+++ b/src/cmd/go/internal/buildid/buildid.go
@@ -0,0 +1,201 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buildid
+
+import (
+	"bytes"
+	"cmd/go/internal/cfg"
+	"fmt"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+)
+
+var (
+	errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
+	errBuildIDMalformed = fmt.Errorf("malformed object file")
+	errBuildIDUnknown   = fmt.Errorf("lost build ID")
+)
+
+var (
+	bangArch = []byte("!<arch>")
+	pkgdef   = []byte("__.PKGDEF")
+	goobject = []byte("go object ")
+	buildid  = []byte("build id ")
+)
+
+// ReadBuildID reads the build ID from an archive or binary.
+// It only supports the gc toolchain.
+// Other toolchain maintainers should adjust this function.
+func ReadBuildID(name, target string) (id string, err error) {
+	if cfg.BuildToolchainName != "gc" {
+		return "", errBuildIDToolchain
+	}
+
+	// For commands, read build ID directly from binary.
+	if name == "main" {
+		return ReadBuildIDFromBinary(target)
+	}
+
+	// Otherwise, we expect to have an archive (.a) file,
+	// and we can read the build ID from the Go export data.
+	if !strings.HasSuffix(target, ".a") {
+		return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDUnknown}
+	}
+
+	// Read just enough of the target to fetch the build ID.
+	// The archive is expected to look like:
+	//
+	//	!<arch>
+	//	__.PKGDEF       0           0     0     644     7955      `
+	//	go object darwin amd64 devel X:none
+	//	build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224"
+	//
+	// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
+	// Reading the first 1024 bytes should be plenty.
+	f, err := os.Open(target)
+	if err != nil {
+		return "", err
+	}
+	data := make([]byte, 1024)
+	n, err := io.ReadFull(f, data)
+	f.Close()
+
+	if err != nil && n == 0 {
+		return "", err
+	}
+
+	bad := func() (string, error) {
+		return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDMalformed}
+	}
+
+	// Archive header.
+	for i := 0; ; i++ { // returns during i==3
+		j := bytes.IndexByte(data, '\n')
+		if j < 0 {
+			return bad()
+		}
+		line := data[:j]
+		data = data[j+1:]
+		switch i {
+		case 0:
+			if !bytes.Equal(line, bangArch) {
+				return bad()
+			}
+		case 1:
+			if !bytes.HasPrefix(line, pkgdef) {
+				return bad()
+			}
+		case 2:
+			if !bytes.HasPrefix(line, goobject) {
+				return bad()
+			}
+		case 3:
+			if !bytes.HasPrefix(line, buildid) {
+				// Found the object header, just doesn't have a build id line.
+				// Treat as successful, with empty build id.
+				return "", nil
+			}
+			id, err := strconv.Unquote(string(line[len(buildid):]))
+			if err != nil {
+				return bad()
+			}
+			return id, nil
+		}
+	}
+}
+
+var (
+	goBuildPrefix = []byte("\xff Go build ID: \"")
+	goBuildEnd    = []byte("\"\n \xff")
+
+	elfPrefix = []byte("\x7fELF")
+
+	machoPrefixes = [][]byte{
+		{0xfe, 0xed, 0xfa, 0xce},
+		{0xfe, 0xed, 0xfa, 0xcf},
+		{0xce, 0xfa, 0xed, 0xfe},
+		{0xcf, 0xfa, 0xed, 0xfe},
+	}
+)
+
+var BuildIDReadSize = 32 * 1024 // changed for testing
+
+// ReadBuildIDFromBinary reads the build ID from a binary.
+//
+// ELF binaries store the build ID in a proper PT_NOTE section.
+//
+// Other binary formats are not so flexible. For those, the linker
+// stores the build ID as non-instruction bytes at the very beginning
+// of the text segment, which should appear near the beginning
+// of the file. This is clumsy but fairly portable. Custom locations
+// can be added for other binary types as needed, like we did for ELF.
+func ReadBuildIDFromBinary(filename string) (id string, err error) {
+	if filename == "" {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
+	}
+
+	// Read the first 32 kB of the binary file.
+	// That should be enough to find the build ID.
+	// In ELF files, the build ID is in the leading headers,
+	// which are typically less than 4 kB, not to mention 32 kB.
+	// In Mach-O files, there's no limit, so we have to parse the file.
+	// On other systems, we're trying to read enough that
+	// we get the beginning of the text segment in the read.
+	// The offset where the text segment begins in a hello
+	// world compiled for each different object format today:
+	//
+	//	Plan 9: 0x20
+	//	Windows: 0x600
+	//
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	data := make([]byte, BuildIDReadSize)
+	_, err = io.ReadFull(f, data)
+	if err == io.ErrUnexpectedEOF {
+		err = nil
+	}
+	if err != nil {
+		return "", err
+	}
+
+	if bytes.HasPrefix(data, elfPrefix) {
+		return readELFGoBuildID(filename, f, data)
+	}
+	for _, m := range machoPrefixes {
+		if bytes.HasPrefix(data, m) {
+			return readMachoGoBuildID(filename, f, data)
+		}
+	}
+
+	return readRawGoBuildID(filename, data)
+}
+
+// readRawGoBuildID finds the raw build ID stored in text segment data.
+func readRawGoBuildID(filename string, data []byte) (id string, err error) {
+	i := bytes.Index(data, goBuildPrefix)
+	if i < 0 {
+		// Missing. Treat as successful but build ID empty.
+		return "", nil
+	}
+
+	j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
+	if j < 0 {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
+	}
+
+	quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
+	id, err = strconv.Unquote(string(quoted))
+	if err != nil {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
+	}
+
+	return id, nil
+}
diff --git a/src/cmd/go/internal/buildid/note.go b/src/cmd/go/internal/buildid/note.go
new file mode 100644
index 0000000..68c91e2
--- /dev/null
+++ b/src/cmd/go/internal/buildid/note.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 buildid
+
+import (
+	"bytes"
+	"debug/elf"
+	"debug/macho"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"os"
+)
+
+func readAligned4(r io.Reader, sz int32) ([]byte, error) {
+	full := (sz + 3) &^ 3
+	data := make([]byte, full)
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func ReadELFNote(filename, name string, typ int32) ([]byte, error) {
+	f, err := elf.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, noteType int32
+			err = binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed: %v", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed: %v", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &noteType)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed: %v", err)
+			}
+			noteName, err := readAligned4(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed: %v", err)
+			}
+			desc, err := readAligned4(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed: %v", err)
+			}
+			if name == string(noteName) && typ == noteType {
+				return desc, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+var elfGoNote = []byte("Go\x00\x00")
+
+// 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
+// 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.
+	// Rewrite the ELF header to set shnum to 0, so that we can pass
+	// the data to elf.NewFile and it will decode the Prog list but not
+	// try to read the section headers and the string table from disk.
+	// That's a waste of I/O when all we care about is the Prog list
+	// and the one ELF note.
+	switch elf.Class(data[elf.EI_CLASS]) {
+	case elf.ELFCLASS32:
+		data[48] = 0
+		data[49] = 0
+	case elf.ELFCLASS64:
+		data[60] = 0
+		data[61] = 0
+	}
+
+	const elfGoBuildIDTag = 4
+
+	ef, err := elf.NewFile(bytes.NewReader(data))
+	if err != nil {
+		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
+	}
+	for _, p := range ef.Progs {
+		if p.Type != elf.PT_NOTE || p.Filesz < 16 {
+			continue
+		}
+
+		var note []byte
+		if p.Off+p.Filesz < uint64(len(data)) {
+			note = data[p.Off : p.Off+p.Filesz]
+		} else {
+			// For some linkers, such as the Solaris linker,
+			// the buildid may not be found in data (which
+			// likely contains the first 16kB of the file)
+			// 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), io.SeekStart)
+			if err != nil {
+				return "", err
+			}
+
+			note = make([]byte, p.Filesz)
+			_, err = io.ReadFull(f, note)
+			if err != nil {
+				return "", err
+			}
+		}
+
+		filesz := p.Filesz
+		for filesz >= 16 {
+			nameSize := ef.ByteOrder.Uint32(note)
+			valSize := ef.ByteOrder.Uint32(note[4:])
+			tag := ef.ByteOrder.Uint32(note[8:])
+			name := note[12:16]
+			if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == elfGoBuildIDTag && bytes.Equal(name, elfGoNote) {
+				return string(note[16 : 16+valSize]), nil
+			}
+
+			nameSize = (nameSize + 3) &^ 3
+			valSize = (valSize + 3) &^ 3
+			notesz := uint64(12 + nameSize + valSize)
+			if filesz <= notesz {
+				break
+			}
+			filesz -= notesz
+			note = note[notesz:]
+		}
+	}
+
+	// No note. Treat as successful but build ID empty.
+	return "", nil
+}
+
+// The Go build ID is stored at the beginning of the Mach-O __text segment.
+// The caller has already opened filename, to get f, and read a few kB out, in data.
+// Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount
+// of other junk placed in the file ahead of the main text.
+func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
+	// If the data we want has already been read, don't worry about Mach-O parsing.
+	// This is both an optimization and a hedge against the Mach-O parsing failing
+	// in the future due to, for example, the name of the __text section changing.
+	if b, err := readRawGoBuildID(filename, data); b != "" && err == nil {
+		return b, err
+	}
+
+	mf, err := macho.NewFile(f)
+	if err != nil {
+		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
+	}
+
+	sect := mf.Section("__text")
+	if sect == nil {
+		// Every binary has a __text section. Something is wrong.
+		return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
+	}
+
+	// It should be in the first few bytes, but read a lot just in case,
+	// especially given our past problems on OS X with the build ID moving.
+	// There shouldn't be much difference between reading 4kB and 32kB:
+	// the hard part is getting to the data, not transferring it.
+	n := sect.Size
+	if n > uint64(BuildIDReadSize) {
+		n = uint64(BuildIDReadSize)
+	}
+	buf := make([]byte, n)
+	if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil {
+		return "", err
+	}
+
+	return readRawGoBuildID(filename, buf)
+}
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
new file mode 100644
index 0000000..65cc9a2
--- /dev/null
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -0,0 +1,114 @@
+// Copyright 2017 The Go Authors. 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 holds configuration shared by multiple parts
+// of the go command.
+package cfg
+
+import (
+	"fmt"
+	"go/build"
+	"os"
+	"path/filepath"
+	"runtime"
+
+	"cmd/internal/objabi"
+)
+
+// These are general "build flags" used by build and other commands.
+var (
+	BuildA                 bool   // -a flag
+	BuildBuildmode         string // -buildmode flag
+	BuildContext           = build.Default
+	BuildI                 bool               // -i flag
+	BuildLdflags           []string           // -ldflags flag
+	BuildLinkshared        bool               // -linkshared flag
+	BuildMSan              bool               // -msan flag
+	BuildN                 bool               // -n flag
+	BuildO                 string             // -o flag
+	BuildP                 = runtime.NumCPU() // -p flag
+	BuildPkgdir            string             // -pkgdir flag
+	BuildRace              bool               // -race flag
+	BuildToolexec          []string           // -toolexec flag
+	BuildToolchainName     string
+	BuildToolchainCompiler func() string
+	BuildToolchainLinker   func() string
+	BuildV                 bool // -v flag
+	BuildWork              bool // -work flag
+	BuildX                 bool // -x flag
+)
+
+func init() {
+	BuildToolchainCompiler = func() string { return "missing-compiler" }
+	BuildToolchainLinker = func() string { return "missing-linker" }
+}
+
+// An EnvVar is an environment variable Name=Value.
+type EnvVar struct {
+	Name  string
+	Value string
+}
+
+// OrigEnv is the original environment of the program at startup.
+var OrigEnv []string
+
+// CmdEnv is the new environment for running go tool commands.
+// User binaries (during go test or go run) are run with OrigEnv,
+// not CmdEnv.
+var CmdEnv []EnvVar
+
+// Global build parameters (used during package load)
+var (
+	Goarch    string
+	Goos      string
+	ExeSuffix string
+	Gopath    []string
+)
+
+var (
+	GOROOT    = findGOROOT()
+	GOBIN     = os.Getenv("GOBIN")
+	GOROOTbin = filepath.Join(GOROOT, "bin")
+	GOROOTpkg = filepath.Join(GOROOT, "pkg")
+	GOROOTsrc = filepath.Join(GOROOT, "src")
+
+	// Used in envcmd.MkEnv and build ID computations.
+	GOARM = fmt.Sprint(objabi.GOARM)
+	GO386 = objabi.GO386
+)
+
+func findGOROOT() string {
+	if env := os.Getenv("GOROOT"); env != "" {
+		return filepath.Clean(env)
+	}
+	exe, err := os.Executable()
+	if err == nil {
+		exe, err = filepath.Abs(exe)
+		if err == nil {
+			if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
+				return dir
+			}
+			exe, err = filepath.EvalSymlinks(exe)
+			if err == nil {
+				if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
+					return dir
+				}
+			}
+		}
+	}
+	return filepath.Clean(runtime.GOROOT())
+}
+
+// isGOROOT reports whether path looks like a GOROOT.
+//
+// It does this by looking for the path/pkg/tool directory,
+// which is necessary for useful operation of the cmd/go tool,
+// and is not typically present in a GOPATH.
+func isGOROOT(path string) bool {
+	stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
+	if err != nil {
+		return false
+	}
+	return stat.IsDir()
+}
diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go
new file mode 100644
index 0000000..454cac1
--- /dev/null
+++ b/src/cmd/go/internal/clean/clean.go
@@ -0,0 +1,254 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package clean implements the ``go clean'' command.
+package clean
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/work"
+)
+
+var CmdClean = &base.Command{
+	UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
+	Short:     "remove object files",
+	Long: `
+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'.
+	`,
+}
+
+var cleanI bool // clean -i flag
+var cleanR bool // clean -r flag
+
+func init() {
+	// break init cycle
+	CmdClean.Run = runClean
+
+	CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
+	CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
+	// -n and -x are important enough to be
+	// mentioned explicitly in the docs but they
+	// are part of the build flags.
+
+	work.AddBuildFlags(CmdClean)
+}
+
+func runClean(cmd *base.Command, args []string) {
+	for _, pkg := range load.PackagesAndErrors(args) {
+		clean(pkg)
+	}
+}
+
+var cleaned = map[*load.Package]bool{}
+
+// TODO: These are dregs left by Makefile-based builds.
+// Eventually, can stop deleting these.
+var cleanDir = map[string]bool{
+	"_test": true,
+	"_obj":  true,
+}
+
+var cleanFile = map[string]bool{
+	"_testmain.go": true,
+	"test.out":     true,
+	"build.out":    true,
+	"a.out":        true,
+}
+
+var cleanExt = map[string]bool{
+	".5":  true,
+	".6":  true,
+	".8":  true,
+	".a":  true,
+	".o":  true,
+	".so": true,
+}
+
+func clean(p *load.Package) {
+	if cleaned[p] {
+		return
+	}
+	cleaned[p] = true
+
+	if p.Dir == "" {
+		base.Errorf("can't load package: %v", p.Error)
+		return
+	}
+	dirs, err := ioutil.ReadDir(p.Dir)
+	if err != nil {
+		base.Errorf("go clean %s: %v", p.Dir, err)
+		return
+	}
+
+	var b work.Builder
+	b.Print = fmt.Print
+
+	packageFile := map[string]bool{}
+	if p.Name != "main" {
+		// Record which files are not in package main.
+		// The others are.
+		keep := func(list []string) {
+			for _, f := range list {
+				packageFile[f] = true
+			}
+		}
+		keep(p.GoFiles)
+		keep(p.CgoFiles)
+		keep(p.TestGoFiles)
+		keep(p.XTestGoFiles)
+	}
+
+	_, elem := filepath.Split(p.Dir)
+	var allRemove []string
+
+	// Remove dir-named executable only if this is package main.
+	if p.Name == "main" {
+		allRemove = append(allRemove,
+			elem,
+			elem+".exe",
+		)
+	}
+
+	// Remove package test executables.
+	allRemove = append(allRemove,
+		elem+".test",
+		elem+".test.exe",
+	)
+
+	// Remove a potential executable for each .go file in the directory that
+	// is not part of the directory's package.
+	for _, dir := range dirs {
+		name := dir.Name()
+		if packageFile[name] {
+			continue
+		}
+		if !dir.IsDir() && strings.HasSuffix(name, ".go") {
+			// TODO(adg,rsc): check that this .go file is actually
+			// in "package main", and therefore capable of building
+			// to an executable file.
+			base := name[:len(name)-len(".go")]
+			allRemove = append(allRemove, base, base+".exe")
+		}
+	}
+
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
+	}
+
+	toRemove := map[string]bool{}
+	for _, name := range allRemove {
+		toRemove[name] = true
+	}
+	for _, dir := range dirs {
+		name := dir.Name()
+		if dir.IsDir() {
+			// TODO: Remove once Makefiles are forgotten.
+			if cleanDir[name] {
+				if cfg.BuildN || cfg.BuildX {
+					b.Showcmd(p.Dir, "rm -r %s", name)
+					if cfg.BuildN {
+						continue
+					}
+				}
+				if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
+					base.Errorf("go clean: %v", err)
+				}
+			}
+			continue
+		}
+
+		if cfg.BuildN {
+			continue
+		}
+
+		if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
+			removeFile(filepath.Join(p.Dir, name))
+		}
+	}
+
+	if cleanI && p.Internal.Target != "" {
+		if cfg.BuildN || cfg.BuildX {
+			b.Showcmd("", "rm -f %s", p.Internal.Target)
+		}
+		if !cfg.BuildN {
+			removeFile(p.Internal.Target)
+		}
+	}
+
+	if cleanR {
+		for _, p1 := range p.Internal.Imports {
+			clean(p1)
+		}
+	}
+}
+
+// removeFile tries to remove file f, if error other than file doesn't exist
+// occurs, it will report the error.
+func removeFile(f string) {
+	err := os.Remove(f)
+	if err == nil || os.IsNotExist(err) {
+		return
+	}
+	// Windows does not allow deletion of a binary file while it is executing.
+	if base.ToolIsWindows {
+		// Remove lingering ~ file from last attempt.
+		if _, err2 := os.Stat(f + "~"); err2 == nil {
+			os.Remove(f + "~")
+		}
+		// 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 err2 := os.Rename(f, f+"~"); err2 == nil {
+			os.Remove(f + "~")
+			return
+		}
+	}
+	base.Errorf("go clean: %v", err)
+}
diff --git a/src/cmd/go/internal/cmdflag/flag.go b/src/cmd/go/internal/cmdflag/flag.go
new file mode 100644
index 0000000..7ab3022
--- /dev/null
+++ b/src/cmd/go/internal/cmdflag/flag.go
@@ -0,0 +1,123 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cmdflag handles flag processing common to several go tools.
+package cmdflag
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+
+	"cmd/go/internal/base"
+)
+
+// The flag handling part of go commands such as test is large and distracting.
+// We can't use the standard flag package because some of the flags from
+// our command line are for us, and some are for the binary we're running,
+// and some are for both.
+
+// Defn defines a flag we know about.
+type Defn struct {
+	Name       string     // Name on command line.
+	BoolVar    *bool      // If it's a boolean flag, this points to it.
+	Value      flag.Value // The flag.Value represented.
+	PassToTest bool       // Pass to the test binary? Used only by go test.
+	Present    bool       // Flag has been seen.
+}
+
+// IsBool reports whether v is a bool flag.
+func IsBool(v flag.Value) bool {
+	vv, ok := v.(interface {
+		IsBoolFlag() bool
+	})
+	if ok {
+		return vv.IsBoolFlag()
+	}
+	return false
+}
+
+// SetBool sets the addressed boolean to the value.
+func SetBool(cmd string, flag *bool, value string) {
+	x, err := strconv.ParseBool(value)
+	if err != nil {
+		SyntaxError(cmd, "illegal bool flag value "+value)
+	}
+	*flag = x
+}
+
+// SetInt sets the addressed integer to the value.
+func SetInt(cmd string, flag *int, value string) {
+	x, err := strconv.Atoi(value)
+	if err != nil {
+		SyntaxError(cmd, "illegal int flag value "+value)
+	}
+	*flag = x
+}
+
+// SyntaxError reports an argument syntax error and exits the program.
+func SyntaxError(cmd, msg string) {
+	fmt.Fprintf(os.Stderr, "go %s: %s\n", cmd, msg)
+	if cmd == "test" {
+		fmt.Fprintf(os.Stderr, `run "go help %s" or "go help testflag" for more information`+"\n", cmd)
+	} else {
+		fmt.Fprintf(os.Stderr, `run "go help %s" for more information`+"\n", cmd)
+	}
+	os.Exit(2)
+}
+
+// Parse sees if argument i is present in the definitions and if so,
+// returns its definition, value, and whether it consumed an extra word.
+// If the flag begins (cmd+".") it is ignored for the purpose of this function.
+func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
+	arg := args[i]
+	if strings.HasPrefix(arg, "--") { // reduce two minuses to one
+		arg = arg[1:]
+	}
+	switch arg {
+	case "-?", "-h", "-help":
+		base.Usage()
+	}
+	if arg == "" || arg[0] != '-' {
+		return
+	}
+	name := arg[1:]
+	// If there's already a prefix such as "test.", drop it for now.
+	name = strings.TrimPrefix(name, cmd+".")
+	equals := strings.Index(name, "=")
+	if equals >= 0 {
+		value = name[equals+1:]
+		name = name[:equals]
+	}
+	for _, f = range defns {
+		if name == f.Name {
+			// Booleans are special because they have modes -x, -x=true, -x=false.
+			if f.BoolVar != nil || IsBool(f.Value) {
+				if equals < 0 { // Otherwise, it's been set and will be verified in SetBool.
+					value = "true"
+				} else {
+					// verify it parses
+					SetBool(cmd, new(bool), value)
+				}
+			} else { // Non-booleans must have a value.
+				extra = equals < 0
+				if extra {
+					if i+1 >= len(args) {
+						SyntaxError(cmd, "missing argument for flag "+f.Name)
+					}
+					value = args[i+1]
+				}
+			}
+			if f.Present {
+				SyntaxError(cmd, f.Name+" flag may be set only once")
+			}
+			f.Present = true
+			return
+		}
+	}
+	f = nil
+	return
+}
diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go
new file mode 100644
index 0000000..d73dd9a
--- /dev/null
+++ b/src/cmd/go/internal/doc/doc.go
@@ -0,0 +1,123 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package doc implements the ``go doc'' command.
+package doc
+
+import (
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+)
+
+var CmdDoc = &base.Command{
+	Run:         runDoc,
+	UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
+	CustomFlags: true,
+	Short:       "show documentation for package or symbol",
+	Long: `
+Doc prints the documentation comments associated with the item identified by its
+arguments (a package, const, func, type, var, method, or struct field)
+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>[.<methodOrField>]
+	go doc [<pkg>.]<sym>[.<methodOrField>]
+	go doc [<pkg>.][<sym>.]<methodOrField>
+
+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 with method or struct field.
+This is similar to the syntax accepted by godoc:
+
+	go doc <pkg> <sym>[.<methodOrField>]
+
+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, methods, and fields.
+`,
+}
+
+func runDoc(cmd *base.Command, args []string) {
+	base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
+}
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
new file mode 100644
index 0000000..43d4334
--- /dev/null
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -0,0 +1,178 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package envcmd implements the ``go env'' command.
+package envcmd
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"runtime"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/work"
+)
+
+var CmdEnv = &base.Command{
+	UsageLine: "env [-json] [var ...]",
+	Short:     "print Go environment information",
+	Long: `
+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.
+
+The -json flag prints the environment in JSON format
+instead of as a shell script.
+	`,
+}
+
+func init() {
+	CmdEnv.Run = runEnv // break init cycle
+}
+
+var envJson = CmdEnv.Flag.Bool("json", false, "")
+
+func MkEnv() []cfg.EnvVar {
+	var b work.Builder
+	b.Init()
+
+	env := []cfg.EnvVar{
+		{Name: "GOARCH", Value: cfg.Goarch},
+		{Name: "GOBIN", Value: cfg.GOBIN},
+		{Name: "GOEXE", Value: cfg.ExeSuffix},
+		{Name: "GOHOSTARCH", Value: runtime.GOARCH},
+		{Name: "GOHOSTOS", Value: runtime.GOOS},
+		{Name: "GOOS", Value: cfg.Goos},
+		{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
+		{Name: "GORACE", Value: os.Getenv("GORACE")},
+		{Name: "GOROOT", Value: cfg.GOROOT},
+		{Name: "GOTOOLDIR", Value: base.ToolDir},
+
+		// disable escape codes in clang errors
+		{Name: "TERM", Value: "dumb"},
+	}
+
+	if work.GccgoBin != "" {
+		env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoBin})
+	} else {
+		env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName})
+	}
+
+	switch cfg.Goarch {
+	case "arm":
+		env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM})
+	case "386":
+		env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
+	}
+
+	cmd := b.GccCmd(".")
+	env = append(env, cfg.EnvVar{Name: "CC", Value: cmd[0]})
+	env = append(env, cfg.EnvVar{Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")})
+	cmd = b.GxxCmd(".")
+	env = append(env, cfg.EnvVar{Name: "CXX", Value: cmd[0]})
+
+	if cfg.BuildContext.CgoEnabled {
+		env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"})
+	} else {
+		env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "0"})
+	}
+
+	return env
+}
+
+func findEnv(env []cfg.EnvVar, name string) string {
+	for _, e := range env {
+		if e.Name == name {
+			return e.Value
+		}
+	}
+	return ""
+}
+
+// ExtraEnvVars returns environment variables that should not leak into child processes.
+func ExtraEnvVars() []cfg.EnvVar {
+	var b work.Builder
+	b.Init()
+	cppflags, cflags, cxxflags, fflags, ldflags := b.CFlags(&load.Package{})
+	return []cfg.EnvVar{
+		{Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")},
+		{Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")},
+		{Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")},
+		{Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")},
+		{Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")},
+		{Name: "PKG_CONFIG", Value: b.PkgconfigCmd()},
+	}
+}
+
+func runEnv(cmd *base.Command, args []string) {
+	env := cfg.CmdEnv
+	env = append(env, ExtraEnvVars()...)
+	if len(args) > 0 {
+		if *envJson {
+			var es []cfg.EnvVar
+			for _, name := range args {
+				e := cfg.EnvVar{Name: name, Value: findEnv(env, name)}
+				es = append(es, e)
+			}
+			printEnvAsJSON(es)
+		} else {
+			for _, name := range args {
+				fmt.Printf("%s\n", findEnv(env, name))
+			}
+		}
+		return
+	}
+
+	if *envJson {
+		printEnvAsJSON(env)
+		return
+	}
+
+	for _, e := range env {
+		if e.Name != "TERM" {
+			switch runtime.GOOS {
+			default:
+				fmt.Printf("%s=\"%s\"\n", e.Name, e.Value)
+			case "plan9":
+				if strings.IndexByte(e.Value, '\x00') < 0 {
+					fmt.Printf("%s='%s'\n", e.Name, strings.Replace(e.Value, "'", "''", -1))
+				} else {
+					v := strings.Split(e.Value, "\x00")
+					fmt.Printf("%s=(", e.Name)
+					for x, s := range v {
+						if x > 0 {
+							fmt.Printf(" ")
+						}
+						fmt.Printf("%s", s)
+					}
+					fmt.Printf(")\n")
+				}
+			case "windows":
+				fmt.Printf("set %s=%s\n", e.Name, e.Value)
+			}
+		}
+	}
+}
+
+func printEnvAsJSON(env []cfg.EnvVar) {
+	m := make(map[string]string)
+	for _, e := range env {
+		if e.Name == "TERM" {
+			continue
+		}
+		m[e.Name] = e.Value
+	}
+	enc := json.NewEncoder(os.Stdout)
+	enc.SetIndent("", "\t")
+	if err := enc.Encode(m); err != nil {
+		base.Fatalf("%s", err)
+	}
+}
diff --git a/src/cmd/go/internal/fix/fix.go b/src/cmd/go/internal/fix/fix.go
new file mode 100644
index 0000000..788d49b
--- /dev/null
+++ b/src/cmd/go/internal/fix/fix.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fix implements the ``go fix'' command.
+package fix
+
+import (
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+)
+
+var CmdFix = &base.Command{
+	Run:       runFix,
+	UsageLine: "fix [packages]",
+	Short:     "run go tool fix on packages",
+	Long: `
+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.
+	`,
+}
+
+func runFix(cmd *base.Command, args []string) {
+	for _, pkg := range load.Packages(args) {
+		// Use pkg.gofiles instead of pkg.Dir so that
+		// the command only applies to this package,
+		// not to packages in subdirectories.
+		files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles))
+		base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files))
+	}
+}
diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go
new file mode 100644
index 0000000..0563a04
--- /dev/null
+++ b/src/cmd/go/internal/fmtcmd/fmt.go
@@ -0,0 +1,71 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fmtcmd implements the ``go fmt'' command.
+package fmtcmd
+
+import (
+	"os"
+	"path/filepath"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+)
+
+func init() {
+	base.AddBuildFlagsNX(&CmdFmt.Flag)
+}
+
+var CmdFmt = &base.Command{
+	Run:       runFmt,
+	UsageLine: "fmt [-n] [-x] [packages]",
+	Short:     "run gofmt on package sources",
+	Long: `
+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.
+	`,
+}
+
+func runFmt(cmd *base.Command, args []string) {
+	gofmt := gofmtPath()
+	for _, pkg := range load.Packages(args) {
+		// Use pkg.gofiles instead of pkg.Dir so that
+		// the command only applies to this package,
+		// not to packages in subdirectories.
+		files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles))
+		base.Run(str.StringList(gofmt, "-l", "-w", files))
+	}
+}
+
+func gofmtPath() string {
+	gofmt := "gofmt"
+	if base.ToolIsWindows {
+		gofmt += base.ToolWindowsExtension
+	}
+
+	gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	// fallback to looking for gofmt in $PATH
+	return "gofmt"
+}
diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go
new file mode 100644
index 0000000..d47c9b7
--- /dev/null
+++ b/src/cmd/go/internal/generate/generate.go
@@ -0,0 +1,407 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package generate implements the ``go generate'' command.
+package generate
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/work"
+)
+
+var CmdGenerate = &base.Command{
+	Run:       runGenerate,
+	UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
+	Short:     "generate Go files by processing source",
+	Long: `
+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.
+
+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 foo go tool foo
+
+specifies that the command "foo" represents the generator
+"go tool foo".
+
+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'.
+	`,
+}
+
+var (
+	generateRunFlag string         // generate -run flag
+	generateRunRE   *regexp.Regexp // compiled expression for -run
+)
+
+func init() {
+	work.AddBuildFlags(CmdGenerate)
+	CmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
+}
+
+func runGenerate(cmd *base.Command, args []string) {
+	load.IgnoreImports = true
+
+	if generateRunFlag != "" {
+		var err error
+		generateRunRE, err = regexp.Compile(generateRunFlag)
+		if err != nil {
+			log.Fatalf("generate: %s", err)
+		}
+	}
+	// Even if the arguments are .go files, this loop suffices.
+	for _, pkg := range load.Packages(args) {
+		for _, file := range pkg.Internal.GoFiles {
+			if !generate(pkg.Name, file) {
+				break
+			}
+		}
+	}
+}
+
+// generate runs the generation directives for a single file.
+func generate(pkg, absFile string) bool {
+	fd, err := os.Open(absFile)
+	if err != nil {
+		log.Fatalf("generate: %s", err)
+	}
+	defer fd.Close()
+	g := &Generator{
+		r:        fd,
+		path:     absFile,
+		pkg:      pkg,
+		commands: make(map[string][]string),
+	}
+	return g.run()
+}
+
+// A Generator represents the state of a single Go source file
+// being scanned for generator commands.
+type Generator struct {
+	r        io.Reader
+	path     string // full rooted path name.
+	dir      string // full rooted directory of file.
+	file     string // base name of file.
+	pkg      string
+	commands map[string][]string
+	lineNum  int // current line number.
+	env      []string
+}
+
+// run runs the generators in the current file.
+func (g *Generator) run() (ok bool) {
+	// Processing below here calls g.errorf on failure, which does panic(stop).
+	// If we encounter an error, we abort the package.
+	defer func() {
+		e := recover()
+		if e != nil {
+			ok = false
+			if e != stop {
+				panic(e)
+			}
+			base.SetExitStatus(1)
+		}
+	}()
+	g.dir, g.file = filepath.Split(g.path)
+	g.dir = filepath.Clean(g.dir) // No final separator please.
+	if cfg.BuildV {
+		fmt.Fprintf(os.Stderr, "%s\n", base.ShortPath(g.path))
+	}
+
+	// Scan for lines that start "//go:generate".
+	// Can't use bufio.Scanner because it can't handle long lines,
+	// which are likely to appear when using generate.
+	input := bufio.NewReader(g.r)
+	var err error
+	// One line per loop.
+	for {
+		g.lineNum++ // 1-indexed.
+		var buf []byte
+		buf, err = input.ReadSlice('\n')
+		if err == bufio.ErrBufferFull {
+			// Line too long - consume and ignore.
+			if isGoGenerate(buf) {
+				g.errorf("directive too long")
+			}
+			for err == bufio.ErrBufferFull {
+				_, err = input.ReadSlice('\n')
+			}
+			if err != nil {
+				break
+			}
+			continue
+		}
+
+		if err != nil {
+			// Check for marker at EOF without final \n.
+			if err == io.EOF && isGoGenerate(buf) {
+				err = io.ErrUnexpectedEOF
+			}
+			break
+		}
+
+		if !isGoGenerate(buf) {
+			continue
+		}
+		if generateRunFlag != "" {
+			if !generateRunRE.Match(bytes.TrimSpace(buf)) {
+				continue
+			}
+		}
+
+		g.setEnv()
+		words := g.split(string(buf))
+		if len(words) == 0 {
+			g.errorf("no arguments to directive")
+		}
+		if words[0] == "-command" {
+			g.setShorthand(words)
+			continue
+		}
+		// Run the command line.
+		if cfg.BuildN || cfg.BuildX {
+			fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
+		}
+		if cfg.BuildN {
+			continue
+		}
+		g.exec(words)
+	}
+	if err != nil && err != io.EOF {
+		g.errorf("error reading %s: %s", base.ShortPath(g.path), err)
+	}
+	return true
+}
+
+func isGoGenerate(buf []byte) bool {
+	return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
+}
+
+// setEnv sets the extra environment variables used when executing a
+// single go:generate command.
+func (g *Generator) setEnv() {
+	g.env = []string{
+		"GOARCH=" + cfg.BuildContext.GOARCH,
+		"GOOS=" + cfg.BuildContext.GOOS,
+		"GOFILE=" + g.file,
+		"GOLINE=" + strconv.Itoa(g.lineNum),
+		"GOPACKAGE=" + g.pkg,
+		"DOLLAR=" + "$",
+	}
+}
+
+// split breaks the line into words, evaluating quoted
+// strings and evaluating environment variables.
+// The initial //go:generate element is present in line.
+func (g *Generator) split(line string) []string {
+	// Parse line, obeying quoted strings.
+	var words []string
+	line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
+	// There may still be a carriage return.
+	if len(line) > 0 && line[len(line)-1] == '\r' {
+		line = line[:len(line)-1]
+	}
+	// One (possibly quoted) word per iteration.
+Words:
+	for {
+		line = strings.TrimLeft(line, " \t")
+		if len(line) == 0 {
+			break
+		}
+		if line[0] == '"' {
+			for i := 1; i < len(line); i++ {
+				c := line[i] // Only looking for ASCII so this is OK.
+				switch c {
+				case '\\':
+					if i+1 == len(line) {
+						g.errorf("bad backslash")
+					}
+					i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
+				case '"':
+					word, err := strconv.Unquote(line[0 : i+1])
+					if err != nil {
+						g.errorf("bad quoted string")
+					}
+					words = append(words, word)
+					line = line[i+1:]
+					// Check the next character is space or end of line.
+					if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
+						g.errorf("expect space after quoted argument")
+					}
+					continue Words
+				}
+			}
+			g.errorf("mismatched quoted string")
+		}
+		i := strings.IndexAny(line, " \t")
+		if i < 0 {
+			i = len(line)
+		}
+		words = append(words, line[0:i])
+		line = line[i:]
+	}
+	// Substitute command if required.
+	if len(words) > 0 && g.commands[words[0]] != nil {
+		// Replace 0th word by command substitution.
+		words = append(g.commands[words[0]], words[1:]...)
+	}
+	// Substitute environment variables.
+	for i, word := range words {
+		words[i] = os.Expand(word, g.expandVar)
+	}
+	return words
+}
+
+var stop = fmt.Errorf("error in generation")
+
+// errorf logs an error message prefixed with the file and line number.
+// It then exits the program (with exit status 1) because generation stops
+// at the first error.
+func (g *Generator) errorf(format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum,
+		fmt.Sprintf(format, args...))
+	panic(stop)
+}
+
+// expandVar expands the $XXX invocation in word. It is called
+// by os.Expand.
+func (g *Generator) expandVar(word string) string {
+	w := word + "="
+	for _, e := range g.env {
+		if strings.HasPrefix(e, w) {
+			return e[len(w):]
+		}
+	}
+	return os.Getenv(word)
+}
+
+// setShorthand installs a new shorthand as defined by a -command directive.
+func (g *Generator) setShorthand(words []string) {
+	// Create command shorthand.
+	if len(words) == 1 {
+		g.errorf("no command specified for -command")
+	}
+	command := words[1]
+	if g.commands[command] != nil {
+		g.errorf("command %q defined multiply defined", command)
+	}
+	g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
+}
+
+// exec runs the command specified by the argument. The first word is
+// the command name itself.
+func (g *Generator) exec(words []string) {
+	cmd := exec.Command(words[0], words[1:]...)
+	// Standard in and out of generator should be the usual.
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	// Run the command in the package directory.
+	cmd.Dir = g.dir
+	cmd.Env = base.MergeEnvLists(g.env, cfg.OrigEnv)
+	err := cmd.Run()
+	if err != nil {
+		g.errorf("running %q: %s", words[0], err)
+	}
+}
diff --git a/src/cmd/go/internal/generate/generate_test.go b/src/cmd/go/internal/generate/generate_test.go
new file mode 100644
index 0000000..defc153
--- /dev/null
+++ b/src/cmd/go/internal/generate/generate_test.go
@@ -0,0 +1,56 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package generate
+
+import (
+	"reflect"
+	"runtime"
+	"testing"
+)
+
+type splitTest struct {
+	in  string
+	out []string
+}
+
+var splitTests = []splitTest{
+	{"", nil},
+	{"x", []string{"x"}},
+	{" a b\tc ", []string{"a", "b", "c"}},
+	{` " a " `, []string{" a "}},
+	{"$GOARCH", []string{runtime.GOARCH}},
+	{"$GOOS", []string{runtime.GOOS}},
+	{"$GOFILE", []string{"proc.go"}},
+	{"$GOPACKAGE", []string{"sys"}},
+	{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
+	{"/$XXNOTDEFINED/", []string{"//"}},
+	{"/$DOLLAR/", []string{"/$/"}},
+	{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
+}
+
+func TestGenerateCommandParse(t *testing.T) {
+	g := &Generator{
+		r:        nil, // Unused here.
+		path:     "/usr/ken/sys/proc.go",
+		dir:      "/usr/ken/sys",
+		file:     "proc.go",
+		pkg:      "sys",
+		commands: make(map[string][]string),
+	}
+	g.setEnv()
+	g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
+	for _, test := range splitTests {
+		// First with newlines.
+		got := g.split("//go:generate " + test.in + "\n")
+		if !reflect.DeepEqual(got, test.out) {
+			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
+		}
+		// Then with CRLFs, thank you Windows.
+		got = g.split("//go:generate " + test.in + "\r\n")
+		if !reflect.DeepEqual(got, test.out) {
+			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
+		}
+	}
+}
diff --git a/src/cmd/go/internal/get/discovery.go b/src/cmd/go/internal/get/discovery.go
new file mode 100644
index 0000000..b2918db
--- /dev/null
+++ b/src/cmd/go/internal/get/discovery.go
@@ -0,0 +1,76 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import (
+	"encoding/xml"
+	"fmt"
+	"io"
+	"strings"
+)
+
+// charsetReader returns a reader for the given charset. Currently
+// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
+// error which is printed by go get, so the user can find why the package
+// wasn't downloaded if the encoding is not supported. Note that, in
+// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
+// greater than 0x7f are not rejected).
+func charsetReader(charset string, input io.Reader) (io.Reader, error) {
+	switch strings.ToLower(charset) {
+	case "ascii":
+		return input, nil
+	default:
+		return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
+	}
+}
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+	d := xml.NewDecoder(r)
+	d.CharsetReader = charsetReader
+	d.Strict = false
+	var t xml.Token
+	for {
+		t, err = d.RawToken()
+		if err != nil {
+			if err == io.EOF || len(imports) > 0 {
+				err = nil
+			}
+			return
+		}
+		if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+			return
+		}
+		if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+			return
+		}
+		e, ok := t.(xml.StartElement)
+		if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+			continue
+		}
+		if attrValue(e.Attr, "name") != "go-import" {
+			continue
+		}
+		if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+			imports = append(imports, metaImport{
+				Prefix:   f[0],
+				VCS:      f[1],
+				RepoRoot: f[2],
+			})
+		}
+	}
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+	for _, a := range attrs {
+		if strings.EqualFold(a.Name.Local, name) {
+			return a.Value
+		}
+	}
+	return ""
+}
diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go
new file mode 100644
index 0000000..6291a72
--- /dev/null
+++ b/src/cmd/go/internal/get/get.go
@@ -0,0 +1,528 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package get implements the ``go get'' command.
+package get
+
+import (
+	"fmt"
+	"go/build"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+	"cmd/go/internal/web"
+	"cmd/go/internal/work"
+)
+
+var CmdGet = &base.Command{
+	UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
+	Short:     "download and install packages and dependencies",
+	Long: `
+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.
+
+The -v flag enables verbose progress and debug output.
+
+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. For more details 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.
+	`,
+}
+
+var getD = CmdGet.Flag.Bool("d", false, "")
+var getF = CmdGet.Flag.Bool("f", false, "")
+var getT = CmdGet.Flag.Bool("t", false, "")
+var getU = CmdGet.Flag.Bool("u", false, "")
+var getFix = CmdGet.Flag.Bool("fix", false, "")
+var getInsecure = CmdGet.Flag.Bool("insecure", false, "")
+
+func init() {
+	work.AddBuildFlags(CmdGet)
+	CmdGet.Run = runGet // break init loop
+}
+
+func runGet(cmd *base.Command, args []string) {
+	work.InstrumentInit()
+	work.BuildModeInit()
+
+	if *getF && !*getU {
+		base.Fatalf("go get: cannot use -f flag without -u")
+	}
+
+	// Disable any prompting for passwords by Git.
+	// Only has an effect for 2.3.0 or later, but avoiding
+	// the prompt in earlier versions is just too hard.
+	// If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
+	// prompting.
+	// See golang.org/issue/9341 and golang.org/issue/12706.
+	if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
+		os.Setenv("GIT_TERMINAL_PROMPT", "0")
+	}
+
+	// Disable any ssh connection pooling by Git.
+	// If a Git subprocess forks a child into the background to cache a new connection,
+	// that child keeps stdout/stderr open. After the Git subprocess exits,
+	// os /exec expects to be able to read from the stdout/stderr pipe
+	// until EOF to get all the data that the Git subprocess wrote before exiting.
+	// The EOF doesn't come until the child exits too, because the child
+	// is holding the write end of the pipe.
+	// This is unfortunate, but it has come up at least twice
+	// (see golang.org/issue/13453 and golang.org/issue/16104)
+	// and confuses users when it does.
+	// If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
+	// assume they know what they are doing and don't step on it.
+	// But default to turning off ControlMaster.
+	if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
+		os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
+	}
+
+	// Phase 1. Download/update.
+	var stk load.ImportStack
+	mode := 0
+	if *getT {
+		mode |= load.GetTestDeps
+	}
+	args = downloadPaths(args)
+	for _, arg := range args {
+		download(arg, nil, &stk, mode)
+	}
+	base.ExitIfErrors()
+
+	// Phase 2. Rescan packages and re-evaluate args list.
+
+	// 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
+	// track of the reverse dependency information, evict
+	// everything.
+	load.ClearPackageCache()
+
+	// In order to rebuild packages information completely,
+	// we need to clear commands cache. Command packages are
+	// referring to evicted packages from the package cache.
+	// This leads to duplicated loads of the standard packages.
+	load.ClearCmdCache()
+
+	args = load.ImportPaths(args)
+	load.PackagesForBuild(args)
+
+	// Phase 3. Install.
+	if *getD {
+		// Download only.
+		// Check delayed until now so that importPaths
+		// and packagesForBuild have a chance to print errors.
+		return
+	}
+
+	work.InstallPackages(args, true)
+}
+
+// downloadPaths prepares the list of paths to pass to download.
+// 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.
+func downloadPaths(args []string) []string {
+	args = load.ImportPathsNoDotExpansion(args)
+	var out []string
+	for _, a := range args {
+		if strings.Contains(a, "...") {
+			var expand []string
+			// Use matchPackagesInFS to avoid printing
+			// warnings. They will be printed by the
+			// eventual call to importPaths instead.
+			if build.IsLocalImport(a) {
+				expand = load.MatchPackagesInFS(a)
+			} else {
+				expand = load.MatchPackages(a)
+			}
+			if len(expand) > 0 {
+				out = append(out, expand...)
+				continue
+			}
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// downloadCache records the import paths we have already
+// considered during the download, to avoid duplicate work when
+// there is more than one dependency sequence leading to
+// a particular package.
+var downloadCache = map[string]bool{}
+
+// downloadRootCache records the version control repository
+// root directories we have already considered during the download.
+// For example, all the packages in the github.com/google/codesearch repo
+// share the same root (the directory for that path), and we only need
+// to run the hg commands to consider each repository once.
+var downloadRootCache = map[string]bool{}
+
+// download runs the download half of the get command
+// for the package named by the argument.
+func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
+	if mode&load.UseVendor != 0 {
+		// Caller is responsible for expanding vendor paths.
+		panic("internal error: download mode has useVendor set")
+	}
+	load1 := func(path string, mode int) *load.Package {
+		if parent == nil {
+			return load.LoadPackage(path, stk)
+		}
+		return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
+	}
+
+	p := load1(arg, mode)
+	if p.Error != nil && p.Error.Hard {
+		base.Errorf("%s", p.Error)
+		return
+	}
+
+	// loadPackage inferred the canonical ImportPath from arg.
+	// Use that in the following to prevent hysteresis effects
+	// in e.g. downloadCache and packageCache.
+	// This allows invocations such as:
+	//   mkdir -p $GOPATH/src/github.com/user
+	//   cd $GOPATH/src/github.com/user
+	//   go get ./foo
+	// see: golang.org/issue/9767
+	arg = p.ImportPath
+
+	// There's nothing to do if this is a package in the standard library.
+	if p.Standard {
+		return
+	}
+
+	// Only process each package once.
+	// (Unless we're fetching test dependencies for this package,
+	// in which case we want to process it again.)
+	if downloadCache[arg] && mode&load.GetTestDeps == 0 {
+		return
+	}
+	downloadCache[arg] = true
+
+	pkgs := []*load.Package{p}
+	wildcardOkay := len(*stk) == 0
+	isWildcard := false
+
+	// Download if the package is missing, or update if we're using -u.
+	if p.Dir == "" || *getU {
+		// The actual download.
+		stk.Push(arg)
+		err := downloadPackage(p)
+		if err != nil {
+			base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err.Error()})
+			stk.Pop()
+			return
+		}
+		stk.Pop()
+
+		args := []string{arg}
+		// If the argument has a wildcard in it, re-evaluate the wildcard.
+		// We delay this until after reloadPackage so that the old entry
+		// for p has been replaced in the package cache.
+		if wildcardOkay && strings.Contains(arg, "...") {
+			if build.IsLocalImport(arg) {
+				args = load.MatchPackagesInFS(arg)
+			} else {
+				args = load.MatchPackages(arg)
+			}
+			isWildcard = true
+		}
+
+		// Clear all relevant package cache entries before
+		// doing any new loads.
+		load.ClearPackageCachePartial(args)
+
+		pkgs = pkgs[:0]
+		for _, arg := range args {
+			// Note: load calls loadPackage or loadImport,
+			// which push arg onto stk already.
+			// Do not push here too, or else stk will say arg imports arg.
+			p := load1(arg, mode)
+			if p.Error != nil {
+				base.Errorf("%s", p.Error)
+				continue
+			}
+			pkgs = append(pkgs, p)
+		}
+	}
+
+	// Process package, which might now be multiple packages
+	// due to wildcard expansion.
+	for _, p := range pkgs {
+		if *getFix {
+			files := base.FilterDotUnderscoreFiles(base.RelPaths(p.Internal.AllGoFiles))
+			base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
+
+			// The imports might have changed, so reload again.
+			p = load.ReloadPackage(arg, stk)
+			if p.Error != nil {
+				base.Errorf("%s", p.Error)
+				return
+			}
+		}
+
+		if isWildcard {
+			// Report both the real package and the
+			// wildcard in any error message.
+			stk.Push(p.ImportPath)
+		}
+
+		// Process dependencies, now that we know what they are.
+		imports := p.Imports
+		if mode&load.GetTestDeps != 0 {
+			// Process test dependencies when -t is specified.
+			// (But don't get test dependencies for test dependencies:
+			// we always pass mode 0 to the recursive calls below.)
+			imports = str.StringList(imports, p.TestImports, p.XTestImports)
+		}
+		for i, path := range imports {
+			if path == "C" {
+				continue
+			}
+			// Fail fast on import naming full vendor path.
+			// Otherwise expand path as needed for test imports.
+			// Note that p.Imports can have additional entries beyond p.Internal.Build.Imports.
+			orig := path
+			if i < len(p.Internal.Build.Imports) {
+				orig = p.Internal.Build.Imports[i]
+			}
+			if j, ok := load.FindVendor(orig); ok {
+				stk.Push(path)
+				err := &load.PackageError{
+					ImportStack: stk.Copy(),
+					Err:         "must be imported as " + path[j+len("vendor/"):],
+				}
+				stk.Pop()
+				base.Errorf("%s", err)
+				continue
+			}
+			// If this is a test import, apply vendor lookup now.
+			// We cannot pass useVendor to download, because
+			// download does caching based on the value of path,
+			// so it must be the fully qualified path already.
+			if i >= len(p.Imports) {
+				path = load.VendoredImportPath(p, path)
+			}
+			download(path, p, stk, 0)
+		}
+
+		if isWildcard {
+			stk.Pop()
+		}
+	}
+}
+
+// downloadPackage runs the create or download command
+// to make the first copy of or update a copy of the given package.
+func downloadPackage(p *load.Package) error {
+	var (
+		vcs            *vcsCmd
+		repo, rootPath string
+		err            error
+	)
+
+	security := web.Secure
+	if *getInsecure {
+		security = web.Insecure
+	}
+
+	if p.Internal.Build.SrcRoot != "" {
+		// Directory exists. Look for checkout along path to src.
+		vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
+		if err != nil {
+			return err
+		}
+		repo = "<local>" // should be unused; make distinctive
+
+		// Double-check where it came from.
+		if *getU && vcs.remoteRepo != nil {
+			dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
+			remote, err := vcs.remoteRepo(vcs, dir)
+			if err != nil {
+				return err
+			}
+			repo = remote
+			if !*getF {
+				if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
+					repo := rr.repo
+					if rr.vcs.resolveRepo != nil {
+						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
+						if err == nil {
+							repo = resolved
+						}
+					}
+					if remote != repo && rr.isCustom {
+						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
+					}
+				}
+			}
+		}
+	} else {
+		// Analyze the import path to determine the version control system,
+		// repository, and the import path for the root of the repository.
+		rr, err := repoRootForImportPath(p.ImportPath, security)
+		if err != nil {
+			return err
+		}
+		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
+	}
+	if !vcs.isSecure(repo) && !*getInsecure {
+		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
+	}
+
+	if p.Internal.Build.SrcRoot == "" {
+		// Package not found. Put in first directory of $GOPATH.
+		list := filepath.SplitList(cfg.BuildContext.GOPATH)
+		if len(list) == 0 {
+			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
+		}
+		// Guard against people setting GOPATH=$GOROOT.
+		if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) {
+			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
+		}
+		if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
+			return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
+		}
+		p.Internal.Build.Root = list[0]
+		p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
+		p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
+	}
+	root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
+	// If we've considered this repository already, don't do it again.
+	if downloadRootCache[root] {
+		return nil
+	}
+	downloadRootCache[root] = true
+
+	if cfg.BuildV {
+		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
+	}
+
+	// Check that this is an appropriate place for the repo to be checked out.
+	// The target directory must either not exist or have a repo checked out already.
+	meta := filepath.Join(root, "."+vcs.cmd)
+	st, err := os.Stat(meta)
+	if err == nil && !st.IsDir() {
+		return fmt.Errorf("%s exists but is not a directory", meta)
+	}
+	if err != nil {
+		// 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 {
+			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
+		}
+
+		_, err := os.Stat(p.Internal.Build.Root)
+		gopathExisted := err == nil
+
+		// Some version control tools require the parent of the target to exist.
+		parent, _ := filepath.Split(root)
+		if err = os.MkdirAll(parent, 0777); err != nil {
+			return err
+		}
+		if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
+			fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
+		}
+
+		if err = vcs.create(root, repo); err != nil {
+			return err
+		}
+	} else {
+		// Metadata directory does exist; download incremental updates.
+		if err = vcs.download(root); err != nil {
+			return err
+		}
+	}
+
+	if cfg.BuildN {
+		// Do not show tag sync in -n; it's noise more than anything,
+		// and since we're not running commands, no tag will be found.
+		// But avoid printing nothing.
+		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
+		return nil
+	}
+
+	// Select and sync to appropriate version of the repository.
+	tags, err := vcs.tags(root)
+	if err != nil {
+		return err
+	}
+	vers := runtime.Version()
+	if i := strings.Index(vers, " "); i >= 0 {
+		vers = vers[:i]
+	}
+	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// selectTag returns the closest matching tag for a given version.
+// Closest means the latest one that is not after the current release.
+// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
+// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
+// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
+//
+// NOTE(rsc): Eventually we will need to decide on some logic here.
+// For now, there is only "go1". This matches the docs in go help get.
+func selectTag(goVersion string, tags []string) (match string) {
+	for _, t := range tags {
+		if t == "go1" {
+			return "go1"
+		}
+	}
+	return ""
+}
diff --git a/src/cmd/go/internal/get/pkg_test.go b/src/cmd/go/internal/get/pkg_test.go
new file mode 100644
index 0000000..b8937a5
--- /dev/null
+++ b/src/cmd/go/internal/get/pkg_test.go
@@ -0,0 +1,83 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import (
+	"cmd/go/internal/str"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+var foldDupTests = []struct {
+	list   []string
+	f1, f2 string
+}{
+	{str.StringList("math/rand", "math/big"), "", ""},
+	{str.StringList("math", "strings"), "", ""},
+	{str.StringList("strings"), "", ""},
+	{str.StringList("strings", "strings"), "strings", "strings"},
+	{str.StringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
+}
+
+func TestFoldDup(t *testing.T) {
+	for _, tt := range foldDupTests {
+		f1, f2 := str.FoldDup(tt.list)
+		if f1 != tt.f1 || f2 != tt.f2 {
+			t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
+		}
+	}
+}
+
+var parseMetaGoImportsTests = []struct {
+	in  string
+	out []metaImport
+}{
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+		[]metaImport{
+			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+			{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+		},
+	},
+	{
+		`<head>
+		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		</head>`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		<body>`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		// XML doesn't like <div style=position:relative>.
+		`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
+		[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
+	},
+}
+
+func TestParseMetaGoImports(t *testing.T) {
+	for i, tt := range parseMetaGoImportsTests {
+		out, err := parseMetaGoImports(strings.NewReader(tt.in))
+		if err != nil {
+			t.Errorf("test#%d: %v", i, err)
+			continue
+		}
+		if !reflect.DeepEqual(out, tt.out) {
+			t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
+		}
+	}
+}
diff --git a/src/cmd/go/internal/get/tag_test.go b/src/cmd/go/internal/get/tag_test.go
new file mode 100644
index 0000000..9a25dfa
--- /dev/null
+++ b/src/cmd/go/internal/get/tag_test.go
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import "testing"
+
+var selectTagTestTags = []string{
+	"go.r58",
+	"go.r58.1",
+	"go.r59",
+	"go.r59.1",
+	"go.r61",
+	"go.r61.1",
+	"go.weekly.2010-01-02",
+	"go.weekly.2011-10-12",
+	"go.weekly.2011-10-12.1",
+	"go.weekly.2011-10-14",
+	"go.weekly.2011-11-01",
+	"go1",
+	"go1.0.1",
+	"go1.999",
+	"go1.9.2",
+	"go5",
+
+	// these should be ignored:
+	"release.r59",
+	"release.r59.1",
+	"release",
+	"weekly.2011-10-12",
+	"weekly.2011-10-12.1",
+	"weekly",
+	"foo",
+	"bar",
+	"go.f00",
+	"go!r60",
+	"go.1999-01-01",
+	"go.2x",
+	"go.20000000000000",
+	"go.2.",
+	"go.2.0",
+	"go2x",
+	"go20000000000000",
+	"go2.",
+	"go2.0",
+}
+
+var selectTagTests = []struct {
+	version  string
+	selected string
+}{
+	/*
+		{"release.r57", ""},
+		{"release.r58.2", "go.r58.1"},
+		{"release.r59", "go.r59"},
+		{"release.r59.1", "go.r59.1"},
+		{"release.r60", "go.r59.1"},
+		{"release.r60.1", "go.r59.1"},
+		{"release.r61", "go.r61"},
+		{"release.r66", "go.r61.1"},
+		{"weekly.2010-01-01", ""},
+		{"weekly.2010-01-02", "go.weekly.2010-01-02"},
+		{"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
+		{"weekly.2010-01-03", "go.weekly.2010-01-02"},
+		{"weekly.2011-10-12", "go.weekly.2011-10-12"},
+		{"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
+		{"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
+		{"weekly.2011-10-14", "go.weekly.2011-10-14"},
+		{"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
+		{"weekly.2011-11-01", "go.weekly.2011-11-01"},
+		{"weekly.2014-01-01", "go.weekly.2011-11-01"},
+		{"weekly.3000-01-01", "go.weekly.2011-11-01"},
+		{"go1", "go1"},
+		{"go1.1", "go1.0.1"},
+		{"go1.998", "go1.9.2"},
+		{"go1.1000", "go1.999"},
+		{"go6", "go5"},
+
+		// faulty versions:
+		{"release.f00", ""},
+		{"weekly.1999-01-01", ""},
+		{"junk", ""},
+		{"", ""},
+		{"go2x", ""},
+		{"go200000000000", ""},
+		{"go2.", ""},
+		{"go2.0", ""},
+	*/
+	{"anything", "go1"},
+}
+
+func TestSelectTag(t *testing.T) {
+	for _, c := range selectTagTests {
+		selected := selectTag(c.version, selectTagTestTags)
+		if selected != c.selected {
+			t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
+		}
+	}
+}
diff --git a/src/cmd/go/internal/get/vcs.go b/src/cmd/go/internal/get/vcs.go
new file mode 100644
index 0000000..c656deb
--- /dev/null
+++ b/src/cmd/go/internal/get/vcs.go
@@ -0,0 +1,1000 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"internal/singleflight"
+	"log"
+	"net/url"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"sync"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/web"
+)
+
+// A vcsCmd describes how to use a version control system
+// like Mercurial, Git, or Subversion.
+type vcsCmd struct {
+	name string
+	cmd  string // name of binary to invoke command
+
+	createCmd   []string // commands to download a fresh copy of a repository
+	downloadCmd []string // commands to download updates into an existing repository
+
+	tagCmd         []tagCmd // commands to list tags
+	tagLookupCmd   []tagCmd // commands to lookup tags before running tagSyncCmd
+	tagSyncCmd     []string // commands to sync to specific tag
+	tagSyncDefault []string // commands to sync to default tag
+
+	scheme  []string
+	pingCmd string
+
+	remoteRepo  func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+	resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
+}
+
+var defaultSecureScheme = map[string]bool{
+	"https":   true,
+	"git+ssh": true,
+	"bzr+ssh": true,
+	"svn+ssh": true,
+	"ssh":     true,
+}
+
+func (v *vcsCmd) isSecure(repo string) bool {
+	u, err := url.Parse(repo)
+	if err != nil {
+		// If repo is not a URL, it's not secure.
+		return false
+	}
+	return v.isSecureScheme(u.Scheme)
+}
+
+func (v *vcsCmd) isSecureScheme(scheme string) bool {
+	switch v.cmd {
+	case "git":
+		// GIT_ALLOW_PROTOCOL is an environment variable defined by Git. It is a
+		// colon-separated list of schemes that are allowed to be used with git
+		// fetch/clone. Any scheme not mentioned will be considered insecure.
+		if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" {
+			for _, s := range strings.Split(allow, ":") {
+				if s == scheme {
+					return true
+				}
+			}
+			return false
+		}
+	}
+	return defaultSecureScheme[scheme]
+}
+
+// A tagCmd describes a command to list available tags
+// that can be passed to tagSyncCmd.
+type tagCmd struct {
+	cmd     string // command to list tags
+	pattern string // regexp to extract tags from list
+}
+
+// vcsList lists the known version control systems
+var vcsList = []*vcsCmd{
+	vcsHg,
+	vcsGit,
+	vcsSvn,
+	vcsBzr,
+}
+
+// vcsByCmd returns the version control system for the given
+// command name (hg, git, svn, bzr).
+func vcsByCmd(cmd string) *vcsCmd {
+	for _, vcs := range vcsList {
+		if vcs.cmd == cmd {
+			return vcs
+		}
+	}
+	return nil
+}
+
+// vcsHg describes how to use Mercurial.
+var vcsHg = &vcsCmd{
+	name: "Mercurial",
+	cmd:  "hg",
+
+	createCmd:   []string{"clone -U {repo} {dir}"},
+	downloadCmd: []string{"pull"},
+
+	// We allow both tag and branch names as 'tags'
+	// for selecting a version. This lets people have
+	// a go.release.r60 branch and a go1 branch
+	// and make changes in both, without constantly
+	// editing .hgtags.
+	tagCmd: []tagCmd{
+		{"tags", `^(\S+)`},
+		{"branches", `^(\S+)`},
+	},
+	tagSyncCmd:     []string{"update -r {tag}"},
+	tagSyncDefault: []string{"update default"},
+
+	scheme:     []string{"https", "http", "ssh"},
+	pingCmd:    "identify {scheme}://{repo}",
+	remoteRepo: hgRemoteRepo,
+}
+
+func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) {
+	out, err := vcsHg.runOutput(rootDir, "paths default")
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(string(out)), nil
+}
+
+// vcsGit describes how to use Git.
+var vcsGit = &vcsCmd{
+	name: "Git",
+	cmd:  "git",
+
+	createCmd:   []string{"clone {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"},
+	downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
+
+	tagCmd: []tagCmd{
+		// tags/xxx matches a git tag named xxx
+		// origin/xxx matches a git branch named xxx on the default remote repository
+		{"show-ref", `(?:tags|origin)/(\S+)$`},
+	},
+	tagLookupCmd: []tagCmd{
+		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
+	},
+	tagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"},
+	// both createCmd and downloadCmd update the working dir.
+	// No need to do more here. We used to 'checkout master'
+	// but that doesn't work if the default branch is not named master.
+	// DO NOT add 'checkout master' here.
+	// See golang.org/issue/9032.
+	tagSyncDefault: []string{"submodule update --init --recursive"},
+
+	scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
+	pingCmd:    "ls-remote {scheme}://{repo}",
+	remoteRepo: gitRemoteRepo,
+}
+
+// scpSyntaxRe matches the SCP-like addresses used by Git to access
+// repositories by SSH.
+var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
+
+func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
+	cmd := "config remote.origin.url"
+	errParse := errors.New("unable to parse output of git " + cmd)
+	errRemoteOriginNotFound := errors.New("remote origin not found")
+	outb, err := vcsGit.run1(rootDir, cmd, nil, false)
+	if err != nil {
+		// if it doesn't output any message, it means the config argument is correct,
+		// but the config value itself doesn't exist
+		if outb != nil && len(outb) == 0 {
+			return "", errRemoteOriginNotFound
+		}
+		return "", err
+	}
+	out := strings.TrimSpace(string(outb))
+
+	var repoURL *url.URL
+	if m := scpSyntaxRe.FindStringSubmatch(out); m != nil {
+		// Match SCP-like syntax and convert it to a URL.
+		// Eg, "git at github.com:user/repo" becomes
+		// "ssh://git@github.com/user/repo".
+		repoURL = &url.URL{
+			Scheme: "ssh",
+			User:   url.User(m[1]),
+			Host:   m[2],
+			Path:   m[3],
+		}
+	} else {
+		repoURL, err = url.Parse(out)
+		if err != nil {
+			return "", err
+		}
+	}
+
+	// Iterate over insecure schemes too, because this function simply
+	// reports the state of the repo. If we can't see insecure schemes then
+	// we can't report the actual repo URL.
+	for _, s := range vcsGit.scheme {
+		if repoURL.Scheme == s {
+			return repoURL.String(), nil
+		}
+	}
+	return "", errParse
+}
+
+// vcsBzr describes how to use Bazaar.
+var vcsBzr = &vcsCmd{
+	name: "Bazaar",
+	cmd:  "bzr",
+
+	createCmd: []string{"branch {repo} {dir}"},
+
+	// Without --overwrite bzr will not pull tags that changed.
+	// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
+	downloadCmd: []string{"pull --overwrite"},
+
+	tagCmd:         []tagCmd{{"tags", `^(\S+)`}},
+	tagSyncCmd:     []string{"update -r {tag}"},
+	tagSyncDefault: []string{"update -r revno:-1"},
+
+	scheme:      []string{"https", "http", "bzr", "bzr+ssh"},
+	pingCmd:     "info {scheme}://{repo}",
+	remoteRepo:  bzrRemoteRepo,
+	resolveRepo: bzrResolveRepo,
+}
+
+func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
+	outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(string(outb)), nil
+}
+
+func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
+	outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
+	if err != nil {
+		return "", err
+	}
+	out := string(outb)
+
+	// Expect:
+	// ...
+	//   (branch root|repository branch): <URL>
+	// ...
+
+	found := false
+	for _, prefix := range []string{"\n  branch root: ", "\n  repository branch: "} {
+		i := strings.Index(out, prefix)
+		if i >= 0 {
+			out = out[i+len(prefix):]
+			found = true
+			break
+		}
+	}
+	if !found {
+		return "", fmt.Errorf("unable to parse output of bzr info")
+	}
+
+	i := strings.Index(out, "\n")
+	if i < 0 {
+		return "", fmt.Errorf("unable to parse output of bzr info")
+	}
+	out = out[:i]
+	return strings.TrimSpace(out), nil
+}
+
+// vcsSvn describes how to use Subversion.
+var vcsSvn = &vcsCmd{
+	name: "Subversion",
+	cmd:  "svn",
+
+	createCmd:   []string{"checkout {repo} {dir}"},
+	downloadCmd: []string{"update"},
+
+	// There is no tag command in subversion.
+	// The branch information is all in the path names.
+
+	scheme:     []string{"https", "http", "svn", "svn+ssh"},
+	pingCmd:    "info {scheme}://{repo}",
+	remoteRepo: svnRemoteRepo,
+}
+
+func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {
+	outb, err := vcsSvn.runOutput(rootDir, "info")
+	if err != nil {
+		return "", err
+	}
+	out := string(outb)
+
+	// Expect:
+	// ...
+	// Repository Root: <URL>
+	// ...
+
+	i := strings.Index(out, "\nRepository Root: ")
+	if i < 0 {
+		return "", fmt.Errorf("unable to parse output of svn info")
+	}
+	out = out[i+len("\nRepository Root: "):]
+	i = strings.Index(out, "\n")
+	if i < 0 {
+		return "", fmt.Errorf("unable to parse output of svn info")
+	}
+	out = out[:i]
+	return strings.TrimSpace(out), nil
+}
+
+func (v *vcsCmd) String() string {
+	return v.name
+}
+
+// run runs the command line cmd in the given directory.
+// keyval is a list of key, value pairs. run expands
+// instances of {key} in cmd into value, but only after
+// splitting cmd into individual arguments.
+// If an error occurs, run prints the command line and the
+// command's combined stdout+stderr to standard error.
+// Otherwise run discards the command's output.
+func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
+	_, err := v.run1(dir, cmd, keyval, true)
+	return err
+}
+
+// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
+func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
+	_, err := v.run1(dir, cmd, keyval, false)
+	return err
+}
+
+// runOutput is like run but returns the output of the command.
+func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
+	return v.run1(dir, cmd, keyval, true)
+}
+
+// run1 is the generalized implementation of run and runOutput.
+func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
+	m := make(map[string]string)
+	for i := 0; i < len(keyval); i += 2 {
+		m[keyval[i]] = keyval[i+1]
+	}
+	args := strings.Fields(cmdline)
+	for i, arg := range args {
+		args[i] = expand(m, arg)
+	}
+
+	if len(args) >= 2 && args[0] == "-go-internal-cd" {
+		if filepath.IsAbs(args[1]) {
+			dir = args[1]
+		} else {
+			dir = filepath.Join(dir, args[1])
+		}
+		args = args[2:]
+	}
+
+	_, err := exec.LookPath(v.cmd)
+	if err != nil {
+		fmt.Fprintf(os.Stderr,
+			"go: missing %s command. See https://golang.org/s/gogetcmd\n",
+			v.name)
+		return nil, err
+	}
+
+	cmd := exec.Command(v.cmd, args...)
+	cmd.Dir = dir
+	cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
+	if cfg.BuildX {
+		fmt.Printf("cd %s\n", dir)
+		fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
+	}
+	var buf bytes.Buffer
+	cmd.Stdout = &buf
+	cmd.Stderr = &buf
+	err = cmd.Run()
+	out := buf.Bytes()
+	if err != nil {
+		if verbose || cfg.BuildV {
+			fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
+			os.Stderr.Write(out)
+		}
+		return out, err
+	}
+	return out, nil
+}
+
+// ping pings to determine scheme to use.
+func (v *vcsCmd) ping(scheme, repo string) error {
+	return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
+}
+
+// create creates a new copy of repo in dir.
+// The parent of dir must exist; dir must not.
+func (v *vcsCmd) create(dir, repo string) error {
+	for _, cmd := range v.createCmd {
+		if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// download downloads any new changes for the repo in dir.
+func (v *vcsCmd) download(dir string) error {
+	for _, cmd := range v.downloadCmd {
+		if err := v.run(dir, cmd); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// tags returns the list of available tags for the repo in dir.
+func (v *vcsCmd) tags(dir string) ([]string, error) {
+	var tags []string
+	for _, tc := range v.tagCmd {
+		out, err := v.runOutput(dir, tc.cmd)
+		if err != nil {
+			return nil, err
+		}
+		re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+		for _, m := range re.FindAllStringSubmatch(string(out), -1) {
+			tags = append(tags, m[1])
+		}
+	}
+	return tags, nil
+}
+
+// tagSync syncs the repo in dir to the named tag,
+// which either is a tag returned by tags or is v.tagDefault.
+func (v *vcsCmd) tagSync(dir, tag string) error {
+	if v.tagSyncCmd == nil {
+		return nil
+	}
+	if tag != "" {
+		for _, tc := range v.tagLookupCmd {
+			out, err := v.runOutput(dir, tc.cmd, "tag", tag)
+			if err != nil {
+				return err
+			}
+			re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+			m := re.FindStringSubmatch(string(out))
+			if len(m) > 1 {
+				tag = m[1]
+				break
+			}
+		}
+	}
+
+	if tag == "" && v.tagSyncDefault != nil {
+		for _, cmd := range v.tagSyncDefault {
+			if err := v.run(dir, cmd); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+
+	for _, cmd := range v.tagSyncCmd {
+		if err := v.run(dir, cmd, "tag", tag); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// A vcsPath describes how to convert an import path into a
+// version control system and repository name.
+type vcsPath struct {
+	prefix string                              // prefix this description applies to
+	re     string                              // pattern for import path
+	repo   string                              // repository to use (expand with match of re)
+	vcs    string                              // version control system to use (expand with match of re)
+	check  func(match map[string]string) error // additional checks
+	ping   bool                                // ping for scheme to use to download repo
+
+	regexp *regexp.Regexp // cached compiled form of re
+}
+
+// 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.
+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(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)
+	}
+
+	origDir := dir
+	for len(dir) > len(srcRoot) {
+		for _, vcs := range vcsList {
+			if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
+				return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
+			}
+		}
+
+		// Move to parent.
+		ndir := filepath.Dir(dir)
+		if len(ndir) >= len(dir) {
+			// Shouldn't happen, but just in case, stop.
+			break
+		}
+		dir = ndir
+	}
+
+	return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
+}
+
+// repoRoot represents a version control system, a repo, and a root of
+// where to put it on disk.
+type repoRoot struct {
+	vcs *vcsCmd
+
+	// repo is the repository URL, including scheme
+	repo string
+
+	// root is the import path corresponding to the root of the
+	// repository
+	root string
+
+	// isCustom is true for custom import paths (those defined by HTML meta tags)
+	isCustom bool
+}
+
+var httpPrefixRE = regexp.MustCompile(`^https?:`)
+
+// repoRootForImportPath analyzes importPath to determine the
+// version control system, and code repository to use.
+func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
+	rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
+	if err == errUnknownSite {
+		// If there are wildcards, look up the thing before the wildcard,
+		// hoping it applies to the wildcarded parts too.
+		// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
+		lookup := strings.TrimSuffix(importPath, "/...")
+		if i := strings.Index(lookup, "/.../"); i >= 0 {
+			lookup = lookup[:i]
+		}
+		rr, err = repoRootForImportDynamic(lookup, security)
+		if err != nil {
+			err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
+		}
+	}
+	if err != nil {
+		rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic)
+		if err1 == nil {
+			rr = rr1
+			err = nil
+		}
+	}
+
+	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+		// Do not allow wildcards in the repo root.
+		rr = nil
+		err = fmt.Errorf("cannot expand ... in %q", importPath)
+	}
+	return rr, err
+}
+
+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
+
+// repoRootFromVCSPaths attempts to map importPath to a repoRoot
+// using the mappings defined in vcsPaths.
+// If scheme is non-empty, that scheme is forced.
+func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
+	// A common error is to use https://packagepath because that's what
+	// hg and git require. Diagnose this helpfully.
+	if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
+		// The importPath has been cleaned, so has only one slash. The pattern
+		// ignores the slashes; the error message puts them back on the RHS at least.
+		return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
+	}
+	for _, srv := range vcsPaths {
+		if !strings.HasPrefix(importPath, srv.prefix) {
+			continue
+		}
+		m := srv.regexp.FindStringSubmatch(importPath)
+		if m == nil {
+			if srv.prefix != "" {
+				return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
+			}
+			continue
+		}
+
+		// Build map of named subexpression matches for expand.
+		match := map[string]string{
+			"prefix": srv.prefix,
+			"import": importPath,
+		}
+		for i, name := range srv.regexp.SubexpNames() {
+			if name != "" && match[name] == "" {
+				match[name] = m[i]
+			}
+		}
+		if srv.vcs != "" {
+			match["vcs"] = expand(match, srv.vcs)
+		}
+		if srv.repo != "" {
+			match["repo"] = expand(match, srv.repo)
+		}
+		if srv.check != nil {
+			if err := srv.check(match); err != nil {
+				return nil, err
+			}
+		}
+		vcs := vcsByCmd(match["vcs"])
+		if vcs == nil {
+			return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
+		}
+		if srv.ping {
+			if scheme != "" {
+				match["repo"] = scheme + "://" + match["repo"]
+			} else {
+				for _, scheme := range vcs.scheme {
+					if security == web.Secure && !vcs.isSecureScheme(scheme) {
+						continue
+					}
+					if vcs.ping(scheme, match["repo"]) == nil {
+						match["repo"] = scheme + "://" + match["repo"]
+						break
+					}
+				}
+			}
+		}
+		rr := &repoRoot{
+			vcs:  vcs,
+			repo: match["repo"],
+			root: match["root"],
+		}
+		return rr, nil
+	}
+	return nil, errUnknownSite
+}
+
+// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// statically known by repoRootForImportPathStatic.
+//
+// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
+func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) {
+	slash := strings.Index(importPath, "/")
+	if slash < 0 {
+		slash = len(importPath)
+	}
+	host := importPath[:slash]
+	if !strings.Contains(host, ".") {
+		return nil, errors.New("import path does not begin with hostname")
+	}
+	urlStr, body, err := web.GetMaybeInsecure(importPath, security)
+	if err != nil {
+		msg := "https fetch: %v"
+		if security == web.Insecure {
+			msg = "http/" + msg
+		}
+		return nil, fmt.Errorf(msg, err)
+	}
+	defer body.Close()
+	imports, err := parseMetaGoImports(body)
+	if err != nil {
+		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
+	}
+	// Find the matched meta import.
+	mmi, err := matchGoImport(imports, importPath)
+	if err != nil {
+		if _, ok := err.(ImportMismatchError); !ok {
+			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
+		}
+		return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)
+	}
+	if cfg.BuildV {
+		log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
+	}
+	// If the import was "uni.edu/bob/project", which said the
+	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
+	// make sure we don't trust Bob and check out evilroot.com to
+	// "uni.edu" yet (possibly overwriting/preempting another
+	// non-evil student). Instead, first verify the root and see
+	// if it matches Bob's claim.
+	if mmi.Prefix != importPath {
+		if cfg.BuildV {
+			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
+		}
+		urlStr0 := urlStr
+		var imports []metaImport
+		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
+		if err != nil {
+			return nil, err
+		}
+		metaImport2, err := matchGoImport(imports, importPath)
+		if err != nil || mmi != metaImport2 {
+			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)
+		}
+	}
+
+	if !strings.Contains(mmi.RepoRoot, "://") {
+		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
+	}
+	rr := &repoRoot{
+		vcs:      vcsByCmd(mmi.VCS),
+		repo:     mmi.RepoRoot,
+		root:     mmi.Prefix,
+		isCustom: true,
+	}
+	if rr.vcs == nil {
+		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
+	}
+	return rr, nil
+}
+
+var fetchGroup singleflight.Group
+var (
+	fetchCacheMu sync.Mutex
+	fetchCache   = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix
+)
+
+// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag
+// and returns its HTML discovery URL and the parsed metaImport lines
+// found on the page.
+//
+// The importPath is of the form "golang.org/x/tools".
+// It is an error if no imports are found.
+// urlStr will still be valid if err != nil.
+// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
+func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
+	setCache := func(res fetchResult) (fetchResult, error) {
+		fetchCacheMu.Lock()
+		defer fetchCacheMu.Unlock()
+		fetchCache[importPrefix] = res
+		return res, nil
+	}
+
+	resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {
+		fetchCacheMu.Lock()
+		if res, ok := fetchCache[importPrefix]; ok {
+			fetchCacheMu.Unlock()
+			return res, nil
+		}
+		fetchCacheMu.Unlock()
+
+		urlStr, body, err := web.GetMaybeInsecure(importPrefix, security)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
+		}
+		imports, err := parseMetaGoImports(body)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
+		}
+		if len(imports) == 0 {
+			err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+		}
+		return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})
+	})
+	res := resi.(fetchResult)
+	return res.urlStr, res.imports, res.err
+}
+
+type fetchResult struct {
+	urlStr  string // e.g. "https://foo.com/x/bar?go-get=1"
+	imports []metaImport
+	err     error
+}
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+	Prefix, VCS, RepoRoot string
+}
+
+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
+}
+
+// A ImportMismatchError is returned where metaImport/s are present
+// but none match our import path.
+type ImportMismatchError struct {
+	importPath string
+	mismatches []string // the meta imports that were discarded for not matching our importPath
+}
+
+func (m ImportMismatchError) Error() string {
+	formattedStrings := make([]string, len(m.mismatches))
+	for i, pre := range m.mismatches {
+		formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath)
+	}
+	return strings.Join(formattedStrings, ", ")
+}
+
+// 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, error) {
+	match := -1
+	imp := strings.Split(importPath, "/")
+
+	errImportMismatch := ImportMismatchError{importPath: importPath}
+	for i, im := range imports {
+		pre := strings.Split(im.Prefix, "/")
+
+		if !splitPathHasPrefix(imp, pre) {
+			errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
+			continue
+		}
+
+		if match != -1 {
+			return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
+		}
+		match = i
+	}
+
+	if match == -1 {
+		return metaImport{}, errImportMismatch
+	}
+	return imports[match], nil
+}
+
+// expand rewrites s to replace {k} with match[k] for each key k in match.
+func expand(match map[string]string, s string) string {
+	for k, v := range match {
+		s = strings.Replace(s, "{"+k+"}", v, -1)
+	}
+	return s
+}
+
+// vcsPaths defines the meaning of import paths referring to
+// commonly-used VCS hosting sites (github.com/user/dir)
+// and import paths referring to a fully-qualified importPath
+// containing a VCS type (foo.com/repo.git/dir)
+var vcsPaths = []*vcsPath{
+	// Github
+	{
+		prefix: "github.com/",
+		re:     `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`,
+		vcs:    "git",
+		repo:   "https://{root}",
+		check:  noVCSSuffix,
+	},
+
+	// Bitbucket
+	{
+		prefix: "bitbucket.org/",
+		re:     `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+		repo:   "https://{root}",
+		check:  bitbucketVCS,
+	},
+
+	// IBM DevOps Services (JazzHub)
+	{
+		prefix: "hub.jazz.net/git",
+		re:     `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "git",
+		repo:   "https://{root}",
+		check:  noVCSSuffix,
+	},
+
+	// Git at Apache
+	{
+		prefix: "git.apache.org",
+		re:     `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "git",
+		repo:   "https://{root}",
+	},
+
+	// 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.
+	{
+		re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?P<vcs>bzr|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`,
+		ping: true,
+	},
+}
+
+// vcsPathsAfterDynamic gives additional vcsPaths entries
+// to try after the dynamic HTML check.
+// This gives those sites a chance to introduce <meta> tags
+// as part of a graceful transition away from the hard-coded logic.
+var vcsPathsAfterDynamic = []*vcsPath{
+	// Launchpad. See golang.org/issue/11436.
+	{
+		prefix: "launchpad.net/",
+		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "bzr",
+		repo:   "https://{root}",
+		check:  launchpadVCS,
+	},
+}
+
+func init() {
+	// fill in cached regexps.
+	// Doing this eagerly discovers invalid regexp syntax
+	// without having to run a command that needs that regexp.
+	for _, srv := range vcsPaths {
+		srv.regexp = regexp.MustCompile(srv.re)
+	}
+	for _, srv := range vcsPathsAfterDynamic {
+		srv.regexp = regexp.MustCompile(srv.re)
+	}
+}
+
+// noVCSSuffix checks that the repository name does not
+// end in .foo for any version control system foo.
+// The usual culprit is ".git".
+func noVCSSuffix(match map[string]string) error {
+	repo := match["repo"]
+	for _, vcs := range vcsList {
+		if strings.HasSuffix(repo, "."+vcs.cmd) {
+			return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
+		}
+	}
+	return nil
+}
+
+// bitbucketVCS determines the version control system for a
+// Bitbucket repository, by using the Bitbucket API.
+func bitbucketVCS(match map[string]string) error {
+	if err := noVCSSuffix(match); err != nil {
+		return err
+	}
+
+	var resp struct {
+		SCM string `json:"scm"`
+	}
+	url := expand(match, "https://api.bitbucket.org/2.0/repositories/{bitname}?fields=scm")
+	data, err := web.Get(url)
+	if err != nil {
+		if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 {
+			// this may be a private repository. If so, attempt to determine which
+			// VCS it uses. See issue 5375.
+			root := match["root"]
+			for _, vcs := range []string{"git", "hg"} {
+				if vcsByCmd(vcs).ping("https", root) == nil {
+					resp.SCM = vcs
+					break
+				}
+			}
+		}
+
+		if resp.SCM == "" {
+			return err
+		}
+	} else {
+		if err := json.Unmarshal(data, &resp); err != nil {
+			return fmt.Errorf("decoding %s: %v", url, err)
+		}
+	}
+
+	if vcsByCmd(resp.SCM) != nil {
+		match["vcs"] = resp.SCM
+		if resp.SCM == "git" {
+			match["repo"] += ".git"
+		}
+		return nil
+	}
+
+	return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
+}
+
+// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
+// "foo" could be a series name registered in Launchpad with its own branch,
+// and it could also be the name of a directory within the main project
+// branch one level up.
+func launchpadVCS(match map[string]string) error {
+	if match["project"] == "" || match["series"] == "" {
+		return nil
+	}
+	_, err := web.Get(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
+	if err != nil {
+		match["root"] = expand(match, "launchpad.net/{project}")
+		match["repo"] = expand(match, "https://{root}")
+	}
+	return nil
+}
diff --git a/src/cmd/go/internal/get/vcs_test.go b/src/cmd/go/internal/get/vcs_test.go
new file mode 100644
index 0000000..62d352a
--- /dev/null
+++ b/src/cmd/go/internal/get/vcs_test.go
@@ -0,0 +1,392 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package get
+
+import (
+	"errors"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+	"testing"
+
+	"cmd/go/internal/web"
+)
+
+// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
+// TODO(cmang): Add tests for SVN and BZR.
+func TestRepoRootForImportPath(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tests := []struct {
+		path string
+		want *repoRoot
+	}{
+		{
+			"github.com/golang/groupcache",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://github.com/golang/groupcache",
+			},
+		},
+		// Unicode letters in directories (issue 18660).
+		{
+			"github.com/user/unicode/испытание",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://github.com/user/unicode",
+			},
+		},
+		// IBM DevOps Services tests
+		{
+			"hub.jazz.net/git/user1/pkgname",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://hub.jazz.net/git/user1/pkgname",
+			},
+		},
+		{
+			"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://hub.jazz.net/git/user1/pkgname",
+			},
+		},
+		{
+			"hub.jazz.net",
+			nil,
+		},
+		{
+			"hub2.jazz.net",
+			nil,
+		},
+		{
+			"hub.jazz.net/someotherprefix",
+			nil,
+		},
+		{
+			"hub.jazz.net/someotherprefix/user1/pkgname",
+			nil,
+		},
+		// Spaces are not valid in user names or package names
+		{
+			"hub.jazz.net/git/User 1/pkgname",
+			nil,
+		},
+		{
+			"hub.jazz.net/git/user1/pkg name",
+			nil,
+		},
+		// Dots are not valid in user names
+		{
+			"hub.jazz.net/git/user.1/pkgname",
+			nil,
+		},
+		{
+			"hub.jazz.net/git/user/pkg.name",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://hub.jazz.net/git/user/pkg.name",
+			},
+		},
+		// User names cannot have uppercase letters
+		{
+			"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",
+			},
+		},
+		{
+			"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",
+			nil,
+		},
+		// Should have ".git" suffix
+		{
+			"git.apache.org/package-name/path/to/lib",
+			nil,
+		},
+		{
+			"git.apache.org/package-name.git",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.apache.org/package-name.git",
+			},
+		},
+		{
+			"git.apache.org/package-name_2.x.git/path/to/lib",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.apache.org/package-name_2.x.git",
+			},
+		},
+	}
+
+	for _, test := range tests {
+		got, err := repoRootForImportPath(test.path, web.Secure)
+		want := test.want
+
+		if want == nil {
+			if err == nil {
+				t.Errorf("repoRootForImportPath(%q): Error expected but not received", test.path)
+			}
+			continue
+		}
+		if err != nil {
+			t.Errorf("repoRootForImportPath(%q): %v", test.path, err)
+			continue
+		}
+		if got.vcs.name != want.vcs.name || got.repo != want.repo {
+			t.Errorf("repoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
+		}
+	}
+}
+
+// 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 j, vcs := range vcsList {
+		dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
+		if j&1 == 0 {
+			err := os.MkdirAll(dir, 0755)
+			if err != nil {
+				t.Fatal(err)
+			}
+		} else {
+			err := os.MkdirAll(filepath.Dir(dir), 0755)
+			if err != nil {
+				t.Fatal(err)
+			}
+			f, err := os.Create(dir)
+			if err != nil {
+				t.Fatal(err)
+			}
+			f.Close()
+		}
+
+		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
+		url    string
+		secure bool
+	}{
+		{vcsGit, "http://example.com/foo.git", false},
+		{vcsGit, "https://example.com/foo.git", true},
+		{vcsBzr, "http://example.com/foo.bzr", false},
+		{vcsBzr, "https://example.com/foo.bzr", true},
+		{vcsSvn, "http://example.com/svn", false},
+		{vcsSvn, "https://example.com/svn", true},
+		{vcsHg, "http://example.com/foo.hg", false},
+		{vcsHg, "https://example.com/foo.hg", true},
+		{vcsGit, "ssh://user@example.com/foo.git", true},
+		{vcsGit, "user at server:path/to/repo.git", false},
+		{vcsGit, "user at server:", false},
+		{vcsGit, "server:repo.git", false},
+		{vcsGit, "server:path/to/repo.git", false},
+		{vcsGit, "example.com:path/to/repo.git", false},
+		{vcsGit, "path/that/contains/a:colon/repo.git", false},
+		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
+	}
+
+	for _, test := range tests {
+		secure := test.vcs.isSecure(test.url)
+		if secure != test.secure {
+			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
+		}
+	}
+}
+
+func TestIsSecureGitAllowProtocol(t *testing.T) {
+	tests := []struct {
+		vcs    *vcsCmd
+		url    string
+		secure bool
+	}{
+		// Same as TestIsSecure to verify same behavior.
+		{vcsGit, "http://example.com/foo.git", false},
+		{vcsGit, "https://example.com/foo.git", true},
+		{vcsBzr, "http://example.com/foo.bzr", false},
+		{vcsBzr, "https://example.com/foo.bzr", true},
+		{vcsSvn, "http://example.com/svn", false},
+		{vcsSvn, "https://example.com/svn", true},
+		{vcsHg, "http://example.com/foo.hg", false},
+		{vcsHg, "https://example.com/foo.hg", true},
+		{vcsGit, "user at server:path/to/repo.git", false},
+		{vcsGit, "user at server:", false},
+		{vcsGit, "server:repo.git", false},
+		{vcsGit, "server:path/to/repo.git", false},
+		{vcsGit, "example.com:path/to/repo.git", false},
+		{vcsGit, "path/that/contains/a:colon/repo.git", false},
+		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
+		// New behavior.
+		{vcsGit, "ssh://user@example.com/foo.git", false},
+		{vcsGit, "foo://example.com/bar.git", true},
+		{vcsHg, "foo://example.com/bar.hg", false},
+		{vcsSvn, "foo://example.com/svn", false},
+		{vcsBzr, "foo://example.com/bar.bzr", false},
+	}
+
+	defer os.Unsetenv("GIT_ALLOW_PROTOCOL")
+	os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo")
+	for _, test := range tests {
+		secure := test.vcs.isSecure(test.url)
+		if secure != test.secure {
+			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
+		}
+	}
+}
+
+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"),
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "different.example.com/user/foo",
+			err:  errors.New("meta tags do not match import 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/internal/help/help.go b/src/cmd/go/internal/help/help.go
new file mode 100644
index 0000000..b4c5217
--- /dev/null
+++ b/src/cmd/go/internal/help/help.go
@@ -0,0 +1,178 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package help implements the ``go help'' command.
+package help
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"text/template"
+	"unicode"
+	"unicode/utf8"
+
+	"cmd/go/internal/base"
+)
+
+// Help implements the 'help' command.
+func Help(args []string) {
+	if len(args) == 0 {
+		PrintUsage(os.Stdout)
+		// not exit 2: succeeded at 'go help'.
+		return
+	}
+	if len(args) != 1 {
+		fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
+		os.Exit(2) // failed at 'go help'
+	}
+
+	arg := args[0]
+
+	// '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 := &base.Command{Long: buf.String()}
+		tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...))
+		fmt.Println("package main")
+		return
+	}
+
+	for _, cmd := range base.Commands {
+		if cmd.Name() == arg {
+			tmpl(os.Stdout, helpTemplate, cmd)
+			// not exit 2: succeeded at 'go help cmd'.
+			return
+		}
+	}
+
+	fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
+	os.Exit(2) // failed at 'go help cmd'
+}
+
+var usageTemplate = `Go is a tool for managing Go source code.
+
+Usage:
+
+	go command [arguments]
+
+The commands are:
+{{range .}}{{if .Runnable}}
+	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+{{range .}}{{if not .Runnable}}
+	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "go help [topic]" for more information about that topic.
+
+`
+
+var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+`
+
+var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
+
+{{end}}{{if .Runnable}}Usage:
+
+	go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+
+
+{{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 {
+	w   io.Writer
+	err error
+}
+
+func (w *errWriter) Write(b []byte) (int, error) {
+	n, err := w.w.Write(b)
+	if err != nil {
+		w.err = err
+	}
+	return n, err
+}
+
+// tmpl executes the given template text on data, writing the result to w.
+func tmpl(w io.Writer, text string, data interface{}) {
+	t := template.New("top")
+	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
+	template.Must(t.Parse(text))
+	ew := &errWriter{w: w}
+	err := t.Execute(ew, data)
+	if ew.err != nil {
+		// I/O error writing. Ignore write on closed pipe.
+		if strings.Contains(ew.err.Error(), "pipe") {
+			os.Exit(1)
+		}
+		base.Fatalf("writing output: %v", ew.err)
+	}
+	if err != nil {
+		panic(err)
+	}
+}
+
+func capitalize(s string) string {
+	if s == "" {
+		return s
+	}
+	r, n := utf8.DecodeRuneInString(s)
+	return string(unicode.ToTitle(r)) + s[n:]
+}
+
+func PrintUsage(w io.Writer) {
+	bw := bufio.NewWriter(w)
+	tmpl(bw, usageTemplate, base.Commands)
+	bw.Flush()
+}
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
new file mode 100644
index 0000000..04731c2
--- /dev/null
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -0,0 +1,620 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package help
+
+import "cmd/go/internal/base"
+
+var HelpC = &base.Command{
+	UsageLine: "c",
+	Short:     "calling between Go and C",
+	Long: `
+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.
+	`,
+}
+
+var HelpPackages = &base.Command{
+	UsageLine: "packages",
+	Short:     "description of package lists",
+	Long: `
+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 (For more details 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.
+
+Import paths beginning with "cmd/" only match source code in
+the Go repository.
+
+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.
+
+To make common patterns more convenient, there are two special cases.
+First, /... at the end of the pattern can match an empty string,
+so that net/... matches both net and packages in its subdirectories, like net/http.
+Second, any slash-separated pattern element containing a wildcard never
+participates in a match of the "vendor" element in the path of a vendored
+package, so that ./... does not match packages in subdirectories of
+./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+Note, however, that a directory named vendor that itself contains code
+is not a vendored package: cmd/vendor would be a command named vendor,
+and the pattern cmd/... matches it.
+See golang.org/s/go15vendor for more about vendoring.
+
+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".
+	`,
+}
+
+var HelpImportPath = &base.Command{
+	UsageLine: "importpath",
+	Short:     "import path syntax",
+	Long: `
+
+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 (For more
+details 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://.
+
+By default, downloads are restricted to known secure protocols
+(e.g. https, ssh). To override this setting for Git downloads, the
+GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
+'go help environment').
+
+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 (For more details 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.
+	`,
+}
+
+var HelpGopath = &base.Command{
+	UsageLine: "gopath",
+	Short:     "GOPATH environment variable",
+	Long: `
+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.
+
+If the environment variable is unset, GOPATH defaults
+to a subdirectory named "go" in the user's home directory
+($HOME/go on Unix, %USERPROFILE%\go on Windows),
+unless that directory holds a Go distribution.
+Run "go env GOPATH" to see the current GOPATH.
+
+See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
+
+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/go
+
+    /home/user/go/
+        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/go/
+        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/go/
+        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.
+	`,
+}
+
+var HelpEnvironment = &base.Command{
+	UsageLine: "environment",
+	Short:     "environment variables",
+	Long: `
+
+The go command, and the tools it invokes, examine a few different
+environment variables. For many of these, you can see the default
+value of on your system by running 'go env NAME', where NAME is the
+name of the variable.
+
+General-purpose environment variables:
+
+	GCCGO
+		The gccgo command to run for 'go build -compiler=gccgo'.
+	GOARCH
+		The architecture, or processor, for which to compile code.
+		Examples are amd64, 386, arm, ppc64.
+	GOBIN
+		The directory where 'go install' will install a command.
+	GOOS
+		The operating system for which to compile code.
+		Examples are linux, darwin, windows, netbsd.
+	GOPATH
+		For more details 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_FFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		Fortran code.
+	CGO_LDFLAGS
+		Flags that cgo will pass to the compiler when linking.
+	CXX
+		The command to use to compile C++ code.
+	PKG_CONFIG
+		Path to pkg-config tool.
+
+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.
+	GIT_ALLOW_PROTOCOL
+		Defined by Git. A colon-separated list of schemes that are allowed to be used
+		with git fetch/clone. If set, any scheme not explicitly mentioned will be
+		considered insecure by 'go get'.
+	`,
+}
+
+var HelpFileType = &base.Command{
+	UsageLine: "filetype",
+	Short:     "file types",
+	Long: `
+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.
+	`,
+}
+
+var HelpBuildmode = &base.Command{
+	UsageLine: "buildmode",
+	Short:     "description of build modes",
+	Long: `
+The 'go build' and 'go install' commands take a -buildmode argument which
+indicates which kind of object file is to be built. Currently supported values
+are:
+
+	-buildmode=archive
+		Build the listed non-main packages into .a files. Packages named
+		main are ignored.
+
+	-buildmode=c-archive
+		Build the listed main package, plus all packages it imports,
+		into a C archive file. The only callable symbols will be those
+		functions exported using a cgo //export comment. Requires
+		exactly one main package to be listed.
+
+	-buildmode=c-shared
+		Build the listed main packages, plus all packages that they
+		import, into C shared libraries. The only callable symbols will
+		be those functions exported using a cgo //export comment.
+		Non-main packages are ignored.
+
+	-buildmode=default
+		Listed main packages are built into executables and listed
+		non-main packages are built into .a files (the default
+		behavior).
+
+	-buildmode=shared
+		Combine all the listed non-main packages into a single shared
+		library that will be used when building with the -linkshared
+		option. Packages named main are ignored.
+
+	-buildmode=exe
+		Build the listed main packages and everything they import into
+		executables. Packages not named main are ignored.
+
+	-buildmode=pie
+		Build the listed main packages and everything they import into
+		position independent executables (PIE). Packages not named
+		main are ignored.
+
+	-buildmode=plugin
+		Build the listed main packages, plus all packages that they
+		import, into a Go plugin. Packages not named main are ignored.
+`,
+}
diff --git a/src/cmd/go/internal/list/context.go b/src/cmd/go/internal/list/context.go
new file mode 100644
index 0000000..68d691e
--- /dev/null
+++ b/src/cmd/go/internal/list/context.go
@@ -0,0 +1,37 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package list
+
+import (
+	"go/build"
+)
+
+type Context struct {
+	GOARCH        string   `json:",omitempty"` // target architecture
+	GOOS          string   `json:",omitempty"` // target operating system
+	GOROOT        string   `json:",omitempty"` // Go root
+	GOPATH        string   `json:",omitempty"` // Go path
+	CgoEnabled    bool     `json:",omitempty"` // whether cgo can be used
+	UseAllFiles   bool     `json:",omitempty"` // use files regardless of +build lines, file names
+	Compiler      string   `json:",omitempty"` // compiler to assume when computing target paths
+	BuildTags     []string `json:",omitempty"` // build constraints to match in +build lines
+	ReleaseTags   []string `json:",omitempty"` // releases the current release is compatible with
+	InstallSuffix string   `json:",omitempty"` // suffix to use in the name of the install dir
+}
+
+func newContext(c *build.Context) *Context {
+	return &Context{
+		GOARCH:        c.GOARCH,
+		GOOS:          c.GOOS,
+		GOROOT:        c.GOROOT,
+		GOPATH:        c.GOPATH,
+		CgoEnabled:    c.CgoEnabled,
+		UseAllFiles:   c.UseAllFiles,
+		Compiler:      c.Compiler,
+		BuildTags:     c.BuildTags,
+		ReleaseTags:   c.ReleaseTags,
+		InstallSuffix: c.InstallSuffix,
+	}
+}
diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go
new file mode 100644
index 0000000..241d089
--- /dev/null
+++ b/src/cmd/go/internal/list/list.go
@@ -0,0 +1,240 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package list implements the ``go list'' command.
+package list
+
+import (
+	"bufio"
+	"encoding/json"
+	"io"
+	"os"
+	"strings"
+	"text/template"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/work"
+)
+
+var CmdList = &base.Command{
+	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
+	Short:     "list packages",
+	Long: `
+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
+        TestGoFiles    []string // _test.go files in package
+        XTestGoFiles   []string // _test.go files outside package
+
+        // 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
+        TestImports  []string // imports from TestGoFiles
+        XTestImports []string // imports from XTestGoFiles
+
+        // Error information
+        Incomplete bool            // this package or a dependency has an error
+        Error      *PackageError   // error loading package
+        DepsErrors []*PackageError // errors loading dependencies
+    }
+
+Packages stored in vendor directories report an ImportPath that includes the
+path to the vendor directory (for example, "d/vendor/p" instead of "p"),
+so that the ImportPath uniquely identifies a given copy of a package.
+The Imports, Deps, TestImports, and XTestImports lists also contain these
+expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+
+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'.
+	`,
+}
+
+func init() {
+	CmdList.Run = runList // break init cycle
+	work.AddBuildFlags(CmdList)
+}
+
+var listE = CmdList.Flag.Bool("e", false, "")
+var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
+var listJson = CmdList.Flag.Bool("json", false, "")
+var nl = []byte{'\n'}
+
+func runList(cmd *base.Command, args []string) {
+	work.BuildModeInit()
+	out := newTrackingWriter(os.Stdout)
+	defer out.w.Flush()
+
+	var do func(*load.PackagePublic)
+	if *listJson {
+		do = func(p *load.PackagePublic) {
+			b, err := json.MarshalIndent(p, "", "\t")
+			if err != nil {
+				out.Flush()
+				base.Fatalf("%s", err)
+			}
+			out.Write(b)
+			out.Write(nl)
+		}
+	} else {
+		var cachedCtxt *Context
+		context := func() *Context {
+			if cachedCtxt == nil {
+				cachedCtxt = newContext(&cfg.BuildContext)
+			}
+			return cachedCtxt
+		}
+		fm := template.FuncMap{
+			"join":    strings.Join,
+			"context": context,
+		}
+		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
+		if err != nil {
+			base.Fatalf("%s", err)
+		}
+		do = func(p *load.PackagePublic) {
+			if err := tmpl.Execute(out, p); err != nil {
+				out.Flush()
+				base.Fatalf("%s", err)
+			}
+			if out.NeedNL() {
+				out.Write(nl)
+			}
+		}
+	}
+
+	loadpkgs := load.Packages
+	if *listE {
+		loadpkgs = load.PackagesAndErrors
+	}
+
+	for _, pkg := range loadpkgs(args) {
+		// Show vendor-expanded paths in listing
+		pkg.TestImports = pkg.Vendored(pkg.TestImports)
+		pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
+
+		do(&pkg.PackagePublic)
+	}
+}
+
+// TrackingWriter tracks the last byte written on every write so
+// we can avoid printing a newline if one was already written or
+// if there is no output at all.
+type TrackingWriter struct {
+	w    *bufio.Writer
+	last byte
+}
+
+func newTrackingWriter(w io.Writer) *TrackingWriter {
+	return &TrackingWriter{
+		w:    bufio.NewWriter(w),
+		last: '\n',
+	}
+}
+
+func (t *TrackingWriter) Write(p []byte) (n int, err error) {
+	n, err = t.w.Write(p)
+	if n > 0 {
+		t.last = p[n-1]
+	}
+	return
+}
+
+func (t *TrackingWriter) Flush() {
+	t.w.Flush()
+}
+
+func (t *TrackingWriter) NeedNL() bool {
+	return t.last != '\n'
+}
diff --git a/src/cmd/go/internal/load/match_test.go b/src/cmd/go/internal/load/match_test.go
new file mode 100644
index 0000000..b8d67da
--- /dev/null
+++ b/src/cmd/go/internal/load/match_test.go
@@ -0,0 +1,165 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package load
+
+import (
+	"strings"
+	"testing"
+)
+
+var matchPatternTests = `
+	pattern ...
+	match foo
+	
+	pattern net
+	match net
+	not net/http
+	
+	pattern net/http
+	match net/http
+	not net
+	
+	pattern net...
+	match net net/http netchan
+	not not/http not/net/http
+	
+	# Special cases. Quoting docs:
+
+	# First, /... at the end of the pattern can match an empty string,
+	# so that net/... matches both net and packages in its subdirectories, like net/http.
+	pattern net/...
+	match net net/http
+	not not/http not/net/http netchan
+
+	# Second, any slash-separted pattern element containing a wildcard never
+	# participates in a match of the "vendor" element in the path of a vendored
+	# package, so that ./... does not match packages in subdirectories of
+	# ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+	# Note, however, that a directory named vendor that itself contains code
+	# is not a vendored package: cmd/vendor would be a command named vendor,
+	# and the pattern cmd/... matches it.
+	pattern ./...
+	match ./vendor ./mycode/vendor
+	not ./vendor/foo ./mycode/vendor/foo
+	
+	pattern ./vendor/...
+	match ./vendor/foo ./vendor/foo/vendor
+	not ./vendor/foo/vendor/bar
+	
+	pattern mycode/vendor/...
+	match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor
+	not mycode/vendor/foo/vendor/bar
+	
+	pattern x/vendor/y
+	match x/vendor/y
+	not x/vendor
+	
+	pattern x/vendor/y/...
+	match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor
+	not x/vendor/y/vendor/z
+	
+	pattern .../vendor/...
+	match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor
+`
+
+func TestMatchPattern(t *testing.T) {
+	testPatterns(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
+		return matchPattern(pattern)(name)
+	})
+}
+
+var treeCanMatchPatternTests = `
+	pattern ...
+	match foo
+	
+	pattern net
+	match net
+	not net/http
+	
+	pattern net/http
+	match net net/http
+	
+	pattern net...
+	match net netchan net/http
+	not not/http not/net/http
+
+	pattern net/...
+	match net net/http
+	not not/http netchan
+	
+	pattern abc.../def
+	match abcxyz
+	not xyzabc
+	
+	pattern x/y/z/...
+	match x x/y x/y/z x/y/z/w
+	
+	pattern x/y/z
+	match x x/y x/y/z
+	not x/y/z/w
+	
+	pattern x/.../y/z
+	match x/a/b/c
+	not y/x/a/b/c
+`
+
+func TestTreeCanMatchPattern(t *testing.T) {
+	testPatterns(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
+		return treeCanMatchPattern(pattern)(name)
+	})
+}
+
+var hasPathPrefixTests = []stringPairTest{
+	{"abc", "a", false},
+	{"a/bc", "a", true},
+	{"a", "a", true},
+	{"a/bc", "a/", true},
+}
+
+func TestHasPathPrefix(t *testing.T) {
+	testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
+}
+
+type stringPairTest struct {
+	in1 string
+	in2 string
+	out bool
+}
+
+func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
+	for _, tt := range tests {
+		if out := f(tt.in1, tt.in2); out != tt.out {
+			t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
+		}
+	}
+}
+
+func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) {
+	var patterns []string
+	for _, line := range strings.Split(tests, "\n") {
+		if i := strings.Index(line, "#"); i >= 0 {
+			line = line[:i]
+		}
+		f := strings.Fields(line)
+		if len(f) == 0 {
+			continue
+		}
+		switch f[0] {
+		default:
+			t.Fatalf("unknown directive %q", f[0])
+		case "pattern":
+			patterns = f[1:]
+		case "match", "not":
+			want := f[0] == "match"
+			for _, pattern := range patterns {
+				for _, in := range f[1:] {
+					if fn(pattern, in) != want {
+						t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want)
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/go/internal/load/path.go b/src/cmd/go/internal/load/path.go
new file mode 100644
index 0000000..9cc85dd
--- /dev/null
+++ b/src/cmd/go/internal/load/path.go
@@ -0,0 +1,80 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package load
+
+import (
+	"path/filepath"
+	"strings"
+)
+
+// hasSubdir reports whether dir is a subdirectory of
+// (possibly multiple levels below) root.
+// If so, it sets rel to the path fragment that must be
+// appended to root to reach dir.
+func hasSubdir(root, dir string) (rel string, ok bool) {
+	if p, err := filepath.EvalSymlinks(root); err == nil {
+		root = p
+	}
+	if p, err := filepath.EvalSymlinks(dir); err == nil {
+		dir = p
+	}
+	const sep = string(filepath.Separator)
+	root = filepath.Clean(root)
+	if !strings.HasSuffix(root, sep) {
+		root += sep
+	}
+	dir = filepath.Clean(dir)
+	if !strings.HasPrefix(dir, root) {
+		return "", false
+	}
+	return filepath.ToSlash(dir[len(root):]), true
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+	switch {
+	default:
+		return false
+	case len(s) == len(prefix):
+		return s == prefix
+	case len(s) > len(prefix):
+		if prefix != "" && prefix[len(prefix)-1] == '/' {
+			return strings.HasPrefix(s, prefix)
+		}
+		return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+	}
+}
+
+// expandPath returns the symlink-expanded form of path.
+func expandPath(p string) string {
+	x, err := filepath.EvalSymlinks(p)
+	if err == nil {
+		return x
+	}
+	return p
+}
+
+// hasFilePathPrefix reports whether the filesystem path s begins with the
+// elements in prefix.
+func hasFilePathPrefix(s, prefix string) bool {
+	sv := strings.ToUpper(filepath.VolumeName(s))
+	pv := strings.ToUpper(filepath.VolumeName(prefix))
+	s = s[len(sv):]
+	prefix = prefix[len(pv):]
+	switch {
+	default:
+		return false
+	case sv != pv:
+		return false
+	case len(s) == len(prefix):
+		return s == prefix
+	case len(s) > len(prefix):
+		if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
+			return strings.HasPrefix(s, prefix)
+		}
+		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
+	}
+}
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
new file mode 100644
index 0000000..9264681
--- /dev/null
+++ b/src/cmd/go/internal/load/pkg.go
@@ -0,0 +1,1924 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package load loads packages.
+package load
+
+import (
+	"crypto/sha1"
+	"fmt"
+	"go/build"
+	"go/token"
+	"io/ioutil"
+	"os"
+	pathpkg "path"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strings"
+	"unicode"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/buildid"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/str"
+)
+
+var IgnoreImports bool // control whether we ignore imports in packages
+
+// A Package describes a single package found in a directory.
+type Package struct {
+	PackagePublic                 // visible in 'go list'
+	Internal      PackageInternal // for use inside go command only
+}
+
+type PackagePublic 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
+	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
+	Name          string `json:",omitempty"` // package name
+	Doc           string `json:",omitempty"` // package documentation string
+	Target        string `json:",omitempty"` // install path
+	Shlib         string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
+	Goroot        bool   `json:",omitempty"` // is this package found in the Go root?
+	Standard      bool   `json:",omitempty"` // is this package part of the standard Go library?
+	Stale         bool   `json:",omitempty"` // would 'go install' do anything for this package?
+	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)
+	CgoFiles       []string `json:",omitempty"` // .go sources files that import "C"
+	IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
+	CFiles         []string `json:",omitempty"` // .c source files
+	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
+	SysoFiles      []string `json:",omitempty"` // .syso system object files added to package
+
+	// Cgo directives
+	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
+
+	// Dependency information
+	Imports []string `json:",omitempty"` // import paths used by this package
+	Deps    []string `json:",omitempty"` // all (recursively) imported dependencies
+
+	// Error information
+	Incomplete bool            `json:",omitempty"` // was there an error loading this package or dependencies?
+	Error      *PackageError   `json:",omitempty"` // error loading this package (not dependencies)
+	DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
+
+	// Test information
+	TestGoFiles  []string `json:",omitempty"` // _test.go files in package
+	TestImports  []string `json:",omitempty"` // imports from TestGoFiles
+	XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
+	XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+}
+
+type PackageInternal struct {
+	// Unexported fields are not part of the public API.
+	Build        *build.Package
+	Pkgdir       string // overrides build.PkgDir
+	Imports      []*Package
+	Deps         []*Package
+	GoFiles      []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+	SFiles       []string
+	AllGoFiles   []string             // gofiles + IgnoredGoFiles, absolute paths
+	Target       string               // installed file for this package (may be executable)
+	Fake         bool                 // synthesized package
+	External     bool                 // synthesized external test package
+	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 ../)
+	LocalPrefix  string               // interpret ./ and ../ imports relative to this prefix
+	ExeName      string               // desired name for temporary executable
+	CoverMode    string               // preprocess Go source files with the coverage tool in this mode
+	CoverVars    map[string]*CoverVar // variables created by coverage analysis
+	OmitDebug    bool                 // tell linker not to write debug information
+	BuildID      string               // expected build ID for generated package
+	GobinSubdir  bool                 // install target would be subdir of GOBIN
+}
+
+// Vendored returns the vendor-resolved version of imports,
+// which should be p.TestImports or p.XTestImports, NOT p.Imports.
+// The imports in p.TestImports and p.XTestImports are not recursively
+// loaded during the initial load of p, so they list the imports found in
+// the source file, but most processing should be over the vendor-resolved
+// import paths. We do this resolution lazily both to avoid file system work
+// and because the eventual real load of the test imports (during 'go test')
+// can produce better error messages if it starts with the original paths.
+// The initial load of p loads all the non-test imports and rewrites
+// the vendored paths, so nothing should ever call p.vendored(p.Imports).
+func (p *Package) Vendored(imports []string) []string {
+	if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
+		panic("internal error: p.vendored(p.Imports) called")
+	}
+	seen := make(map[string]bool)
+	var all []string
+	for _, path := range imports {
+		path = VendoredImportPath(p, path)
+		if !seen[path] {
+			seen[path] = true
+			all = append(all, path)
+		}
+	}
+	sort.Strings(all)
+	return all
+}
+
+// CoverVar holds the name of the generated coverage variables targeting the named file.
+type CoverVar struct {
+	File string // local file name
+	Var  string // name of count struct
+}
+
+func (p *Package) copyBuild(pp *build.Package) {
+	p.Internal.Build = pp
+
+	if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
+		old := pp.PkgTargetRoot
+		pp.PkgRoot = cfg.BuildPkgdir
+		pp.PkgTargetRoot = cfg.BuildPkgdir
+		pp.PkgObj = filepath.Join(cfg.BuildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
+	}
+
+	p.Dir = pp.Dir
+	p.ImportPath = pp.ImportPath
+	p.ImportComment = pp.ImportComment
+	p.Name = pp.Name
+	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)
+	p.GoFiles = pp.GoFiles
+	p.CgoFiles = pp.CgoFiles
+	p.IgnoredGoFiles = pp.IgnoredGoFiles
+	p.CFiles = pp.CFiles
+	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
+	p.SysoFiles = pp.SysoFiles
+	p.CgoCFLAGS = pp.CgoCFLAGS
+	p.CgoCPPFLAGS = pp.CgoCPPFLAGS
+	p.CgoCXXFLAGS = pp.CgoCXXFLAGS
+	p.CgoFFLAGS = pp.CgoFFLAGS
+	p.CgoLDFLAGS = pp.CgoLDFLAGS
+	p.CgoPkgConfig = pp.CgoPkgConfig
+	// We modify p.Imports in place, so make copy now.
+	p.Imports = make([]string, len(pp.Imports))
+	copy(p.Imports, pp.Imports)
+	p.TestGoFiles = pp.TestGoFiles
+	p.TestImports = pp.TestImports
+	p.XTestGoFiles = pp.XTestGoFiles
+	p.XTestImports = pp.XTestImports
+	if IgnoreImports {
+		p.Imports = nil
+		p.TestImports = nil
+		p.XTestImports = nil
+	}
+}
+
+// isStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+func isStandardImportPath(path string) bool {
+	i := strings.Index(path, "/")
+	if i < 0 {
+		i = len(path)
+	}
+	elem := path[:i]
+	return !strings.Contains(elem, ".")
+}
+
+// A PackageError describes an error loading information about a package.
+type PackageError struct {
+	ImportStack   []string // shortest path from package named on command line to this one
+	Pos           string   // position of error
+	Err           string   // the error itself
+	IsImportCycle bool     `json:"-"` // the error is an import cycle
+	Hard          bool     `json:"-"` // whether the error is soft or hard; soft errors are ignored in some places
+}
+
+func (p *PackageError) Error() string {
+	// Import cycles deserve special treatment.
+	if p.IsImportCycle {
+		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
+		// is the most important thing.
+		return p.Pos + ": " + p.Err
+	}
+	if len(p.ImportStack) == 0 {
+		return p.Err
+	}
+	return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
+}
+
+// An ImportStack is a stack of import paths.
+type ImportStack []string
+
+func (s *ImportStack) Push(p string) {
+	*s = append(*s, p)
+}
+
+func (s *ImportStack) Pop() {
+	*s = (*s)[0 : len(*s)-1]
+}
+
+func (s *ImportStack) Copy() []string {
+	return append([]string{}, *s...)
+}
+
+// shorterThan reports whether sp is shorter than t.
+// We use this to record the shortest import sequence
+// that leads to a particular package.
+func (sp *ImportStack) shorterThan(t []string) bool {
+	s := *sp
+	if len(s) != len(t) {
+		return len(s) < len(t)
+	}
+	// If they are the same length, settle ties using string ordering.
+	for i := range s {
+		if s[i] != t[i] {
+			return s[i] < t[i]
+		}
+	}
+	return false // they are equal
+}
+
+// packageCache is a lookup cache for loadPackage,
+// so that if we look up a package multiple times
+// we return the same pointer each time.
+var packageCache = map[string]*Package{}
+
+func ClearPackageCache() {
+	for name := range packageCache {
+		delete(packageCache, name)
+	}
+}
+
+func ClearPackageCachePartial(args []string) {
+	for _, arg := range args {
+		p := packageCache[arg]
+		if p != nil {
+			delete(packageCache, p.Dir)
+			delete(packageCache, p.ImportPath)
+		}
+	}
+}
+
+// reloadPackage is like loadPackage but makes sure
+// not to use the package cache.
+func ReloadPackage(arg string, stk *ImportStack) *Package {
+	p := packageCache[arg]
+	if p != nil {
+		delete(packageCache, p.Dir)
+		delete(packageCache, p.ImportPath)
+	}
+	return LoadPackage(arg, stk)
+}
+
+// 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
+// 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
+// automatically.
+func dirToImportPath(dir string) string {
+	return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
+}
+
+func makeImportValid(r rune) rune {
+	// Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport.
+	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+	if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+		return '_'
+	}
+	return r
+}
+
+// Mode flags for loadImport and download (in get.go).
+const (
+	// useVendor means that loadImport should do vendor expansion
+	// (provided the vendoring experiment is enabled).
+	// That is, useVendor means that the import path came from
+	// a source file and has not been vendor-expanded yet.
+	// Every import path should be loaded initially with useVendor,
+	// and then the expanded version (with the /vendor/ in it) gets
+	// recorded as the canonical import path. At that point, future loads
+	// of that package must not pass useVendor, because
+	// disallowVendor will reject direct use of paths containing /vendor/.
+	UseVendor = 1 << iota
+
+	// getTestDeps is for download (part of "go get") and indicates
+	// that test dependencies should be fetched too.
+	GetTestDeps
+)
+
+// loadImport scans the directory named by path, which must be an import path,
+// but possibly a local import path (an absolute file system path or one beginning
+// with ./ or ../). A local relative path is interpreted relative to srcDir.
+// It returns a *Package describing the package found in that directory.
+func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
+	stk.Push(path)
+	defer stk.Pop()
+
+	// Determine canonical identifier for this package.
+	// For a local import the identifier is the pseudo-import path
+	// we create from the full directory to the package.
+	// Otherwise it is the usual import path.
+	// For vendored imports, it is the expanded form.
+	importPath := path
+	origPath := path
+	isLocal := build.IsLocalImport(path)
+	if isLocal {
+		importPath = dirToImportPath(filepath.Join(srcDir, path))
+	} else if mode&UseVendor != 0 {
+		// We do our own vendor resolution, because we want to
+		// find out the key to use in packageCache without the
+		// overhead of repeated calls to buildContext.Import.
+		// The code is also needed in a few other places anyway.
+		path = VendoredImportPath(parent, path)
+		importPath = path
+	}
+
+	p := packageCache[importPath]
+	if p != nil {
+		p = reusePackage(p, stk)
+	} else {
+		p = new(Package)
+		p.Internal.Local = isLocal
+		p.ImportPath = importPath
+		packageCache[importPath] = p
+
+		// Load package.
+		// Import always returns bp != nil, even if an error occurs,
+		// in order to return partial information.
+		//
+		// TODO: After Go 1, decide when to pass build.AllowBinary here.
+		// See issue 3268 for mistakes to avoid.
+		buildMode := build.ImportComment
+		if mode&UseVendor == 0 || path != origPath {
+			// Not vendoring, or we already found the vendored path.
+			buildMode |= build.IgnoreVendor
+		}
+		bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
+		bp.ImportPath = importPath
+		if cfg.GOBIN != "" {
+			bp.BinDir = cfg.GOBIN
+		}
+		if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+			!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)
+		if p.Error != nil && p.Error.Pos == "" {
+			p = setErrorPos(p, importPos)
+		}
+
+		if origPath != cleanImport(origPath) {
+			p.Error = &PackageError{
+				ImportStack: stk.Copy(),
+				Err:         fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
+			}
+			p.Incomplete = true
+		}
+	}
+
+	// Checked on every import because the rules depend on the code doing the importing.
+	if perr := disallowInternal(srcDir, p, stk); perr != p {
+		return setErrorPos(perr, importPos)
+	}
+	if mode&UseVendor != 0 {
+		if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
+			return setErrorPos(perr, importPos)
+		}
+	}
+
+	if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
+		perr := *p
+		perr.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         fmt.Sprintf("import %q is a program, not an importable package", path),
+		}
+		return setErrorPos(&perr, importPos)
+	}
+
+	if p.Internal.Local && parent != nil && !parent.Internal.Local {
+		perr := *p
+		perr.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         fmt.Sprintf("local import %q in non-local package", path),
+		}
+		return setErrorPos(&perr, importPos)
+	}
+
+	return p
+}
+
+func setErrorPos(p *Package, importPos []token.Position) *Package {
+	if len(importPos) > 0 {
+		pos := importPos[0]
+		pos.Filename = base.ShortPath(pos.Filename)
+		p.Error.Pos = pos.String()
+	}
+	return p
+}
+
+func cleanImport(path string) string {
+	orig := path
+	path = pathpkg.Clean(path)
+	if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
+		path = "./" + path
+	}
+	return path
+}
+
+var isDirCache = map[string]bool{}
+
+func isDir(path string) bool {
+	result, ok := isDirCache[path]
+	if ok {
+		return result
+	}
+
+	fi, err := os.Stat(path)
+	result = err == nil && fi.IsDir()
+	isDirCache[path] = result
+	return result
+}
+
+// VendoredImportPath returns the expansion of path when it appears in parent.
+// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
+// x/vendor/path, vendor/path, or else stay 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 == "" {
+		return path
+	}
+
+	dir := filepath.Clean(parent.Dir)
+	root := filepath.Join(parent.Root, "src")
+	if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
+		// Look for symlinks before reporting error.
+		dir = expandPath(dir)
+		root = expandPath(root)
+	}
+
+	if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
+		base.Fatalf("unexpected directory layout:\n"+
+			"	import path: %s\n"+
+			"	root: %s\n"+
+			"	dir: %s\n"+
+			"	expand root: %s\n"+
+			"	expand dir: %s\n"+
+			"	separator: %s",
+			parent.ImportPath,
+			filepath.Join(parent.Root, "src"),
+			filepath.Clean(parent.Dir),
+			root,
+			dir,
+			string(filepath.Separator))
+	}
+
+	vpath := "vendor/" + path
+	for i := len(dir); i >= len(root); i-- {
+		if i < len(dir) && dir[i] != filepath.Separator {
+			continue
+		}
+		// Note: checking for the vendor directory before checking
+		// for the vendor/path directory helps us hit the
+		// isDir cache more often. It also helps us prepare a more useful
+		// list of places we looked, to report when an import is not found.
+		if !isDir(filepath.Join(dir[:i], "vendor")) {
+			continue
+		}
+		targ := filepath.Join(dir[:i], vpath)
+		if isDir(targ) && hasGoFiles(targ) {
+			importPath := parent.ImportPath
+			if importPath == "command-line-arguments" {
+				// If parent.ImportPath is 'command-line-arguments'.
+				// set to relative directory to root (also chopped root directory)
+				importPath = dir[len(root)+1:]
+			}
+			// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
+			// We know the import path for parent's dir.
+			// We chopped off some number of path elements and
+			// added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.
+			// Now we want to know the import path for that directory.
+			// Construct it by chopping the same number of path elements
+			// (actually the same number of bytes) from parent's import path
+			// and then append /vendor/path.
+			chopped := len(dir) - i
+			if chopped == len(importPath)+1 {
+				// We walked up from c:\gopath\src\foo\bar
+				// and found c:\gopath\src\vendor\path.
+				// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
+				// Use "vendor/path" without any prefix.
+				return vpath
+			}
+			return importPath[:len(importPath)-chopped] + "/" + vpath
+		}
+	}
+	return path
+}
+
+// hasGoFiles reports whether dir contains any files with names ending in .go.
+// For a vendor check we must exclude directories that contain no .go files.
+// Otherwise it is not possible to vendor just a/b/c and still import the
+// non-vendored a/b. See golang.org/issue/13832.
+func hasGoFiles(dir string) bool {
+	fis, _ := ioutil.ReadDir(dir)
+	for _, fi := range fis {
+		if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
+			return true
+		}
+	}
+	return false
+}
+
+// reusePackage reuses package p to satisfy the import at the top
+// of the import stack stk. If this use causes an import loop,
+// reusePackage updates p's error information to record the loop.
+func reusePackage(p *Package, stk *ImportStack) *Package {
+	// We use p.Internal.Imports==nil to detect a package that
+	// is in the midst of its own loadPackage call
+	// (all the recursion below happens before p.Internal.Imports gets set).
+	if p.Internal.Imports == nil {
+		if p.Error == nil {
+			p.Error = &PackageError{
+				ImportStack:   stk.Copy(),
+				Err:           "import cycle not allowed",
+				IsImportCycle: true,
+			}
+		}
+		p.Incomplete = true
+	}
+	// Don't rewrite the import stack in the error if we have an import cycle.
+	// If we do, we'll lose the path that describes the cycle.
+	if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
+		p.Error.ImportStack = stk.Copy()
+	}
+	return p
+}
+
+// disallowInternal checks that srcDir is allowed to import p.
+// If the import is allowed, disallowInternal returns the original package p.
+// If not, it returns a new package containing just an appropriate error.
+func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
+	// golang.org/s/go14internal:
+	// An import of a path containing the element “internal”
+	// is disallowed if the importing code is outside the tree
+	// rooted at the parent of the “internal” directory.
+
+	// There was an error loading the package; stop here.
+	if p.Error != nil {
+		return p
+	}
+
+	// The generated 'testmain' package is allowed to access testing/internal/...,
+	// as if it were generated into the testing directory tree
+	// (it's actually in a temporary directory outside any Go tree).
+	// This cleans up a former kludge in passing functionality to the testing package.
+	if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
+		return p
+	}
+
+	// We can't check standard packages with gccgo.
+	if cfg.BuildContext.Compiler == "gccgo" && p.Standard {
+		return p
+	}
+
+	// The stack includes p.ImportPath.
+	// If that's the only thing on the stack, we started
+	// with a name given on the command line, not an
+	// import. Anything listed on the command line is fine.
+	if len(*stk) == 1 {
+		return p
+	}
+
+	// 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
+	}
+
+	// Internal is present.
+	// Map import path back to directory corresponding to parent of internal.
+	if i > 0 {
+		i-- // rewind over slash in ".../internal"
+	}
+	parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
+	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+		return p
+	}
+
+	// Look for symlinks before reporting error.
+	srcDir = expandPath(srcDir)
+	parent = expandPath(parent)
+	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+		return p
+	}
+
+	// Internal is present, and srcDir is outside parent's tree. Not allowed.
+	perr := *p
+	perr.Error = &PackageError{
+		ImportStack: stk.Copy(),
+		Err:         "use of internal package not allowed",
+	}
+	perr.Incomplete = true
+	return &perr
+}
+
+// findInternal looks for the final "internal" path element in the given import path.
+// 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) {
+	// 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.
+	switch {
+	case strings.HasSuffix(path, "/internal"):
+		return len(path) - len("internal"), true
+	case strings.Contains(path, "/internal/"):
+		return strings.LastIndex(path, "/internal/") + 1, true
+	case path == "internal", strings.HasPrefix(path, "internal/"):
+		return 0, true
+	}
+	return 0, false
+}
+
+// disallowVendor checks that srcDir is allowed to import p as path.
+// If the import is allowed, disallowVendor returns the original package p.
+// If not, it returns a new package containing just an appropriate error.
+func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package {
+	// The stack includes p.ImportPath.
+	// If that's the only thing on the stack, we started
+	// with a name given on the command line, not an
+	// import. Anything listed on the command line is fine.
+	if len(*stk) == 1 {
+		return p
+	}
+
+	if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
+		return perr
+	}
+
+	// Paths like x/vendor/y must be imported as y, never as x/vendor/y.
+	if i, ok := FindVendor(path); ok {
+		perr := *p
+		perr.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         "must be imported as " + path[i+len("vendor/"):],
+		}
+		perr.Incomplete = true
+		return &perr
+	}
+
+	return p
+}
+
+// disallowVendorVisibility checks that srcDir is allowed to import p.
+// The rules are the same as for /internal/ except that a path ending in /vendor
+// is not subject to the rules, only subdirectories of vendor.
+// This allows people to have packages and commands named vendor,
+// for maximal compatibility with existing source trees.
+func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package {
+	// The stack includes p.ImportPath.
+	// If that's the only thing on the stack, we started
+	// with a name given on the command line, not an
+	// import. Anything listed on the command line is fine.
+	if len(*stk) == 1 {
+		return p
+	}
+
+	// Check for "vendor" element.
+	i, ok := FindVendor(p.ImportPath)
+	if !ok {
+		return p
+	}
+
+	// Vendor is present.
+	// Map import path back to directory corresponding to parent of vendor.
+	if i > 0 {
+		i-- // rewind over slash in ".../vendor"
+	}
+	truncateTo := i + len(p.Dir) - len(p.ImportPath)
+	if truncateTo < 0 || len(p.Dir) < truncateTo {
+		return p
+	}
+	parent := p.Dir[:truncateTo]
+	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+		return p
+	}
+
+	// Look for symlinks before reporting error.
+	srcDir = expandPath(srcDir)
+	parent = expandPath(parent)
+	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+		return p
+	}
+
+	// Vendor is present, and srcDir is outside parent's tree. Not allowed.
+	perr := *p
+	perr.Error = &PackageError{
+		ImportStack: stk.Copy(),
+		Err:         "use of vendored package not allowed",
+	}
+	perr.Incomplete = true
+	return &perr
+}
+
+// FindVendor looks for the last non-terminating "vendor" path element in the given import path.
+// If there isn't one, FindVendor returns ok=false.
+// Otherwise, 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).
+// This will allow people to have packages or commands named vendor.
+// This may help reduce breakage, or it may just be confusing. We'll see.
+func FindVendor(path string) (index int, ok bool) {
+	// Two cases, depending on internal at start of string or not.
+	// The order matters: we must return the index of the final element,
+	// because the final one is where the effective import path starts.
+	switch {
+	case strings.Contains(path, "/vendor/"):
+		return strings.LastIndex(path, "/vendor/") + 1, true
+	case strings.HasPrefix(path, "vendor/"):
+		return 0, true
+	}
+	return 0, false
+}
+
+type targetDir int
+
+const (
+	ToRoot    targetDir = iota // to bin dir inside package root (default)
+	ToTool                     // GOROOT/pkg/tool
+	StalePath                  // the old import path; fail to build
+)
+
+// goTools is a map of Go program import path to install target directory.
+var GoTools = map[string]targetDir{
+	"cmd/addr2line": ToTool,
+	"cmd/api":       ToTool,
+	"cmd/asm":       ToTool,
+	"cmd/compile":   ToTool,
+	"cmd/cgo":       ToTool,
+	"cmd/cover":     ToTool,
+	"cmd/dist":      ToTool,
+	"cmd/doc":       ToTool,
+	"cmd/fix":       ToTool,
+	"cmd/link":      ToTool,
+	"cmd/newlink":   ToTool,
+	"cmd/nm":        ToTool,
+	"cmd/objdump":   ToTool,
+	"cmd/pack":      ToTool,
+	"cmd/pprof":     ToTool,
+	"cmd/trace":     ToTool,
+	"cmd/vet":       ToTool,
+	"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,
+}
+
+var raceExclude = map[string]bool{
+	"runtime/race": true,
+	"runtime/msan": true,
+	"runtime/cgo":  true,
+	"cmd/cgo":      true,
+	"syscall":      true,
+	"errors":       true,
+}
+
+var cgoExclude = map[string]bool{
+	"runtime/cgo": true,
+}
+
+var cgoSyscallExclude = map[string]bool{
+	"runtime/cgo":  true,
+	"runtime/race": true,
+	"runtime/msan": true,
+}
+
+// load populates p using information from bp, err, which should
+// be the result of calling build.Context.Import.
+func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package {
+	p.copyBuild(bp)
+
+	// The localPrefix is the path we interpret ./ imports relative to.
+	// Synthesized main packages sometimes override this.
+	p.Internal.LocalPrefix = dirToImportPath(p.Dir)
+
+	if err != nil {
+		p.Incomplete = true
+		err = base.ExpandScanner(err)
+		p.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         err.Error(),
+		}
+		return p
+	}
+
+	useBindir := p.Name == "main"
+	if !p.Standard {
+		switch cfg.BuildBuildmode {
+		case "c-archive", "c-shared", "plugin":
+			useBindir = false
+		}
+	}
+
+	if useBindir {
+		// Report an error when the old code.google.com/p/go.tools paths are used.
+		if GoTools[p.ImportPath] == StalePath {
+			newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
+			e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
+			p.Error = &PackageError{Err: e}
+			return p
+		}
+		_, elem := filepath.Split(p.Dir)
+		full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
+		if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
+			// Install cross-compiled binaries to subdirectories of bin.
+			elem = full
+		}
+		if p.Internal.Build.BinDir != "" {
+			// Install to GOBIN or bin of GOPATH entry.
+			p.Internal.Target = filepath.Join(p.Internal.Build.BinDir, elem)
+			if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
+				// Do not create $GOBIN/goos_goarch/elem.
+				p.Internal.Target = ""
+				p.Internal.GobinSubdir = true
+			}
+		}
+		if GoTools[p.ImportPath] == ToTool {
+			// This is for 'go tool'.
+			// Override all the usual logic and force it into the tool directory.
+			p.Internal.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
+		}
+		if p.Internal.Target != "" && cfg.BuildContext.GOOS == "windows" {
+			p.Internal.Target += ".exe"
+		}
+	} else if p.Internal.Local {
+		// Local import turned into absolute path.
+		// No permanent install target.
+		p.Internal.Target = ""
+	} else {
+		p.Internal.Target = p.Internal.Build.PkgObj
+		if cfg.BuildLinkshared {
+			shlibnamefile := p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
+			shlib, err := ioutil.ReadFile(shlibnamefile)
+			if err == nil {
+				libname := strings.TrimSpace(string(shlib))
+				if cfg.BuildContext.Compiler == "gccgo" {
+					p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
+				} else {
+					p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
+
+				}
+			} else if !os.IsNotExist(err) {
+				base.Fatalf("unexpected error reading %s: %v", shlibnamefile, err)
+			}
+		}
+	}
+
+	ImportPaths := p.Imports
+	// Packages that use cgo import runtime/cgo implicitly.
+	// Packages that use cgo also import syscall implicitly,
+	// to wrap errno.
+	// Exclude certain packages to avoid circular dependencies.
+	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
+		ImportPaths = append(ImportPaths, "runtime/cgo")
+	}
+	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
+		ImportPaths = append(ImportPaths, "syscall")
+	}
+
+	if cfg.BuildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
+		// Currently build modes c-shared, pie (on systems that do not
+		// support PIE with internal linking mode), plugin, and
+		// -linkshared force external linking mode, as of course does
+		// -ldflags=-linkmode=external. External linking mode forces
+		// an import of runtime/cgo.
+		pieCgo := cfg.BuildBuildmode == "pie" && (cfg.BuildContext.GOOS != "linux" || cfg.BuildContext.GOARCH != "amd64")
+		linkmodeExternal := false
+		for i, a := range cfg.BuildLdflags {
+			if a == "-linkmode=external" {
+				linkmodeExternal = true
+			}
+			if a == "-linkmode" && i+1 < len(cfg.BuildLdflags) && cfg.BuildLdflags[i+1] == "external" {
+				linkmodeExternal = true
+			}
+		}
+		if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal {
+			ImportPaths = append(ImportPaths, "runtime/cgo")
+		}
+	}
+
+	// Everything depends on runtime, except runtime, its internal
+	// subpackages, and unsafe.
+	if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") {
+		ImportPaths = append(ImportPaths, "runtime")
+		// When race detection enabled everything depends on runtime/race.
+		// Exclude certain packages to avoid circular dependencies.
+		if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
+			ImportPaths = append(ImportPaths, "runtime/race")
+		}
+		// MSan uses runtime/msan.
+		if cfg.BuildMSan && (!p.Standard || !raceExclude[p.ImportPath]) {
+			ImportPaths = append(ImportPaths, "runtime/msan")
+		}
+		// On ARM with GOARM=5, everything depends on math for the link.
+		if p.Name == "main" && cfg.Goarch == "arm" {
+			ImportPaths = append(ImportPaths, "math")
+		}
+	}
+
+	// Runtime and its internal packages depend on runtime/internal/sys,
+	// so that they pick up the generated zversion.go file.
+	// This can be an issue particularly for runtime/internal/atomic;
+	// see issue 13655.
+	if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" {
+		ImportPaths = append(ImportPaths, "runtime/internal/sys")
+	}
+
+	// Build list of full paths to all Go files in the package,
+	// for use by commands like go fmt.
+	p.Internal.GoFiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+	for i := range p.Internal.GoFiles {
+		p.Internal.GoFiles[i] = filepath.Join(p.Dir, p.Internal.GoFiles[i])
+	}
+	sort.Strings(p.Internal.GoFiles)
+
+	p.Internal.SFiles = str.StringList(p.SFiles)
+	for i := range p.Internal.SFiles {
+		p.Internal.SFiles[i] = filepath.Join(p.Dir, p.Internal.SFiles[i])
+	}
+	sort.Strings(p.Internal.SFiles)
+
+	p.Internal.AllGoFiles = str.StringList(p.IgnoredGoFiles)
+	for i := range p.Internal.AllGoFiles {
+		p.Internal.AllGoFiles[i] = filepath.Join(p.Dir, p.Internal.AllGoFiles[i])
+	}
+	p.Internal.AllGoFiles = append(p.Internal.AllGoFiles, p.Internal.GoFiles...)
+	sort.Strings(p.Internal.AllGoFiles)
+
+	// Check for case-insensitive collision of input files.
+	// To avoid problems on case-insensitive files, we reject any package
+	// where two different input files have equal names under a case-insensitive
+	// comparison.
+	f1, f2 := str.FoldDup(str.StringList(
+		p.GoFiles,
+		p.CgoFiles,
+		p.IgnoredGoFiles,
+		p.CFiles,
+		p.CXXFiles,
+		p.MFiles,
+		p.HFiles,
+		p.FFiles,
+		p.SFiles,
+		p.SysoFiles,
+		p.SwigFiles,
+		p.SwigCXXFiles,
+		p.TestGoFiles,
+		p.XTestGoFiles,
+	))
+	if f1 != "" {
+		p.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
+		}
+		return p
+	}
+
+	// Build list of imported packages and full dependency list.
+	imports := make([]*Package, 0, len(p.Imports))
+	deps := make(map[string]*Package)
+	save := func(path string, p1 *Package) {
+		// The same import path could produce an error or not,
+		// depending on what tries to import it.
+		// Prefer to record entries with errors, so we can report them.
+		p0 := deps[path]
+		if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
+			deps[path] = p1
+		}
+	}
+
+	for i, path := range ImportPaths {
+		if path == "C" {
+			continue
+		}
+		p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
+		if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
+			p.Error = &PackageError{
+				ImportStack: stk.Copy(),
+				Err:         fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
+			}
+			pos := p.Internal.Build.ImportPos[path]
+			if len(pos) > 0 {
+				p.Error.Pos = pos[0].String()
+			}
+		}
+
+		path = p1.ImportPath
+		ImportPaths[i] = path
+		if i < len(p.Imports) {
+			p.Imports[i] = path
+		}
+
+		save(path, p1)
+		imports = append(imports, p1)
+		for _, dep := range p1.Internal.Deps {
+			save(dep.ImportPath, dep)
+		}
+		if p1.Incomplete {
+			p.Incomplete = true
+		}
+	}
+	p.Internal.Imports = imports
+
+	p.Deps = make([]string, 0, len(deps))
+	for dep := range deps {
+		p.Deps = append(p.Deps, dep)
+	}
+	sort.Strings(p.Deps)
+	for _, dep := range p.Deps {
+		p1 := deps[dep]
+		if p1 == nil {
+			panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
+		}
+		p.Internal.Deps = append(p.Internal.Deps, p1)
+		if p1.Error != nil {
+			p.DepsErrors = append(p.DepsErrors, p1.Error)
+		}
+	}
+
+	// unsafe is a fake package.
+	if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
+		p.Internal.Target = ""
+	}
+	p.Target = p.Internal.Target
+
+	// If cgo is not enabled, ignore cgo supporting sources
+	// just as we ignore go files containing import "C".
+	if !cfg.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() && cfg.BuildContext.Compiler == "gc" {
+		p.Error = &PackageError{
+			ImportStack: stk.Copy(),
+			Err:         fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
+		}
+		return p
+	}
+
+	// In the absence of errors lower in the dependency tree,
+	// check for case-insensitive collisions of import paths.
+	if len(p.DepsErrors) == 0 {
+		dep1, dep2 := str.FoldDup(p.Deps)
+		if dep1 != "" {
+			p.Error = &PackageError{
+				ImportStack: stk.Copy(),
+				Err:         fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
+			}
+			return p
+		}
+	}
+
+	if p.BinaryOnly {
+		// For binary-only package, use build ID from supplied package binary.
+		buildID, err := buildid.ReadBuildID(p.Name, p.Target)
+		if err == nil {
+			p.Internal.BuildID = buildID
+		}
+	} else {
+		computeBuildID(p)
+	}
+	return p
+}
+
+// usesSwig reports whether the package needs to run SWIG.
+func (p *Package) UsesSwig() bool {
+	return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
+}
+
+// usesCgo reports whether the package needs to run cgo
+func (p *Package) UsesCgo() bool {
+	return len(p.CgoFiles) > 0
+}
+
+// packageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal.
+func PackageList(roots []*Package) []*Package {
+	seen := map[*Package]bool{}
+	all := []*Package{}
+	var walk func(*Package)
+	walk = func(p *Package) {
+		if seen[p] {
+			return
+		}
+		seen[p] = true
+		for _, p1 := range p.Internal.Imports {
+			walk(p1)
+		}
+		all = append(all, p)
+	}
+	for _, root := range roots {
+		walk(root)
+	}
+	return all
+}
+
+// computeStale computes the Stale flag in the package dag that starts
+// at the named pkgs (command-line arguments).
+func ComputeStale(pkgs ...*Package) {
+	for _, p := range PackageList(pkgs) {
+		p.Stale, p.StaleReason = isStale(p)
+	}
+}
+
+// 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")
+
+// isStale and computeBuildID
+//
+// Theory of Operation
+//
+// There is an installed copy of the package (or binary).
+// Can we reuse the installed copy, or do we need to build a new one?
+//
+// We can use the installed copy if it matches what we'd get
+// by building a new one. The hard part is predicting that without
+// actually running a build.
+//
+// To start, we must know the set of inputs to the build process that can
+// affect the generated output. At a minimum, that includes the source
+// files for the package and also any compiled packages imported by those
+// source files. The *Package has these, and we use them. One might also
+// argue for including in the input set: the build tags, whether the race
+// detector is in use, the target operating system and architecture, the
+// compiler and linker binaries being used, the additional flags being
+// passed to those, the cgo binary being used, the additional flags cgo
+// passes to the host C compiler, the host C compiler being used, the set
+// of host C include files and installed C libraries, and so on.
+// We include some but not all of this information.
+//
+// Once we have decided on a set of inputs, we must next decide how to
+// tell whether the content of that set has changed since the last build
+// of p. If there have been no changes, then we assume a new build would
+// produce the same result and reuse the installed package or binary.
+// But if there have been changes, then we assume a new build might not
+// produce the same result, so we rebuild.
+//
+// There are two common ways to decide whether the content of the set has
+// changed: modification times and content hashes. We use a mixture of both.
+//
+// The use of modification times (mtimes) was pioneered by make:
+// assuming that a file's mtime is an accurate record of when that file was last written,
+// and assuming that the modification time of an installed package or
+// binary is the time that it was built, if the mtimes of the inputs
+// predate the mtime of the installed object, then the build of that
+// object saw those versions of the files, and therefore a rebuild using
+// those same versions would produce the same object. In contrast, if any
+// mtime of an input is newer than the mtime of the installed object, a
+// change has occurred since the build, and the build should be redone.
+//
+// Modification times are attractive because the logic is easy to
+// understand and the file system maintains the mtimes automatically
+// (less work for us). Unfortunately, there are a variety of ways in
+// which the mtime approach fails to detect a change and reuses a stale
+// object file incorrectly. (Making the opposite mistake, rebuilding
+// unnecessarily, is only a performance problem and not a correctness
+// problem, so we ignore that one.)
+//
+// As a warmup, one problem is that to be perfectly precise, we need to
+// compare the input mtimes against the time at the beginning of the
+// build, but the object file time is the time at the end of the build.
+// If an input file changes after being read but before the object is
+// written, the next build will see an object newer than the input and
+// will incorrectly decide that the object is up to date. We make no
+// attempt to detect or solve this problem.
+//
+// Another problem is that due to file system imprecision, an input and
+// output that are actually ordered in time have the same mtime.
+// This typically happens on file systems with 1-second (or, worse,
+// 2-second) mtime granularity and with automated scripts that write an
+// input and then immediately run a build, or vice versa. If an input and
+// an output have the same mtime, the conservative behavior is to treat
+// the output as out-of-date and rebuild. This can cause one or more
+// spurious rebuilds, but only for 1 second, until the object finally has
+// an mtime later than the input.
+//
+// Another problem is that binary distributions often set the mtime on
+// all files to the same time. If the distribution includes both inputs
+// and cached build outputs, the conservative solution to the previous
+// problem will cause unnecessary rebuilds. Worse, in such a binary
+// distribution, those rebuilds might not even have permission to update
+// the cached build output. To avoid these write errors, if an input and
+// output have the same mtime, we assume the output is up-to-date.
+// This is the opposite of what the previous problem would have us do,
+// but binary distributions are more common than instances of the
+// previous problem.
+//
+// A variant of the last problem is that some binary distributions do not
+// set the mtime on all files to the same time. Instead they let the file
+// system record mtimes as the distribution is unpacked. If the outputs
+// are unpacked before the inputs, they'll be older and a build will try
+// to rebuild them. That rebuild might hit the same write errors as in
+// the last scenario. We don't make any attempt to solve this, and we
+// haven't had many reports of it. Perhaps the only time this happens is
+// when people manually unpack the distribution, and most of the time
+// that's done as the same user who will be using it, so an initial
+// rebuild on first use succeeds quietly.
+//
+// More generally, people and programs change mtimes on files. The last
+// few problems were specific examples of this, but it's a general problem.
+// For example, instead of a binary distribution, copying a home
+// directory from one directory or machine to another might copy files
+// but not preserve mtimes. If the inputs are new than the outputs on the
+// first machine but copied first, they end up older than the outputs on
+// the second machine.
+//
+// Because many other build systems have the same sensitivity to mtimes,
+// most programs manipulating source code take pains not to break the
+// mtime assumptions. For example, Git does not set the mtime of files
+// during a checkout operation, even when checking out an old version of
+// the code. This decision was made specifically to work well with
+// mtime-based build systems.
+//
+// The killer problem, though, for mtime-based build systems is that the
+// build only has access to the mtimes of the inputs that still exist.
+// If it is possible to remove an input without changing any other inputs,
+// a later build will think the object is up-to-date when it is not.
+// This happens for Go because a package is made up of all source
+// files in a directory. If a source file is removed, there is no newer
+// mtime available recording that fact. The mtime on the directory could
+// be used, but it also changes when unrelated files are added to or
+// removed from the directory, so including the directory mtime would
+// cause unnecessary rebuilds, possibly many. It would also exacerbate
+// the problems mentioned earlier, since even programs that are careful
+// to maintain mtimes on files rarely maintain mtimes on directories.
+//
+// A variant of the last problem is when the inputs change for other
+// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg
+// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a.
+// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must
+// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date.
+// If Go 1.5 has just been installed, perhaps the compiler will have a
+// newer mtime; since the compiler is considered an input, that would
+// trigger a rebuild. But only once, and only the last Go 1.4 build of
+// mypkg.a happened before Go 1.5 was installed. If a user has the two
+// versions installed in different locations and flips back and forth,
+// mtimes alone cannot tell what to do. Changing the toolchain is
+// changing the set of inputs, without affecting any mtimes.
+//
+// To detect the set of inputs changing, we turn away from mtimes and to
+// an explicit data comparison. Specifically, we build a list of the
+// inputs to the build, compute its SHA1 hash, and record that as the
+// ``build ID'' in the generated object. At the next build, we can
+// recompute the 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.
+//
+// Because this build ID is computed before the build begins, the
+// comparison does not have the race that mtime comparison does.
+//
+// Making the build sensitive to changes in other state is
+// straightforward: include the state in the build ID hash, and if it
+// changes, so does the build ID, triggering a rebuild.
+//
+// To detect changes in toolchain, we include the toolchain version in
+// the build ID hash for package runtime, and then we include the build
+// IDs of all imported packages in the build ID for p.
+//
+// It is natural to think about including build tags in the build ID, but
+// the naive approach of just dumping the tags into the hash would cause
+// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag'
+// produce the same binaries (assuming neverusedtag is never used).
+// A more precise approach would be to include only tags that have an
+// effect on the build. But the effect of a tag on the build is to
+// include or exclude a file from the compilation, and that file list is
+// already in the build ID hash. So the build ID is already tag-sensitive
+// in a perfectly precise way. So we do NOT explicitly add build tags to
+// the build ID hash.
+//
+// We do not include as part of the build ID the operating system,
+// architecture, or whether the race detector is enabled, even though all
+// three have an effect on the output, because that information is used
+// to decide the install location. Binaries for linux and binaries for
+// darwin are written to different directory trees; including that
+// information in the build ID is unnecessary (although it would be
+// harmless).
+//
+// TODO(rsc): Investigate the cost of putting source file content into
+// the build ID hash as a replacement for the use of mtimes. Using the
+// file content would avoid all the mtime problems, but it does require
+// reading all the source files, something we avoid today (we read the
+// beginning to find the build tags and the imports, but we stop as soon
+// as we see the import block is over). If the package is stale, the compiler
+// is going to read the files anyway. But if the package is up-to-date, the
+// read is overhead.
+//
+// TODO(rsc): Investigate the complexity of making the build more
+// precise about when individual results are needed. To be fully precise,
+// there are two results of a compilation: the entire .a file used by the link
+// and the subpiece used by later compilations (__.PKGDEF only).
+// If a rebuild is needed but produces the previous __.PKGDEF, then
+// no more recompilation due to the rebuilt package is needed, only
+// relinking. To date, there is nothing in the Go command to express this.
+//
+// Special Cases
+//
+// When the go command makes the wrong build decision and does not
+// rebuild something it should, users fall back to adding the -a flag.
+// Any common use of the -a flag should be considered prima facie evidence
+// that isStale is returning an incorrect false result in some important case.
+// Bugs reported in the behavior of -a itself should prompt the question
+// ``Why is -a being used at all? What bug does that indicate?''
+//
+// There is a long history of changes to isStale to try to make -a into a
+// suitable workaround for bugs in the mtime-based decisions.
+// It is worth recording that history to inform (and, as much as possible, deter) future changes.
+//
+// (1) Before the build IDs were introduced, building with alternate tags
+// would happily reuse installed objects built without those tags.
+// For example, "go build -tags netgo myprog.go" would use the installed
+// copy of package net, even if that copy had been built without netgo.
+// (The netgo tag controls whether package net uses cgo or pure Go for
+// functionality such as name resolution.)
+// Using the installed non-netgo package defeats the purpose.
+//
+// Users worked around this with "go build -tags netgo -a myprog.go".
+//
+// Build IDs have made that workaround unnecessary:
+// "go build -tags netgo myprog.go"
+// cannot use a non-netgo copy of package net.
+//
+// (2) Before the build IDs were introduced, building with different toolchains,
+// especially changing between toolchains, tried to reuse objects stored in
+// $GOPATH/pkg, resulting in link-time errors about object file mismatches.
+//
+// Users worked around this with "go install -a ./...".
+//
+// Build IDs have made that workaround unnecessary:
+// "go install ./..." will rebuild any objects it finds that were built against
+// a different toolchain.
+//
+// (3) The common use of "go install -a ./..." led to reports of problems
+// when the -a forced the rebuild of the standard library, which for some
+// users was not writable. Because we didn't understand that the real
+// problem was the bug -a was working around, we changed -a not to
+// apply to the standard library.
+//
+// (4) The common use of "go build -tags netgo -a myprog.go" broke
+// when we changed -a not to apply to the standard library, because
+// if go build doesn't rebuild package net, it uses the non-netgo version.
+//
+// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go".
+// The -installsuffix here is making the go command look for packages
+// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH.
+// Since the former presumably doesn't exist, go build decides to rebuild
+// everything, including the standard library. Since go build doesn't
+// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf,
+// so repeated invocations continue to work.
+//
+// If the use of -a wasn't a red flag, the use of -installsuffix to point to
+// a non-existent directory in a command that installs nothing should
+// have been.
+//
+// (5) Now that (1) and (2) no longer need -a, we have removed the kludge
+// introduced in (3): once again, -a means ``rebuild everything,'' not
+// ``rebuild everything except the standard library.'' Only Go 1.4 had
+// the restricted meaning.
+//
+// In addition to these cases trying to trigger rebuilds, there are
+// special cases trying NOT to trigger rebuilds. The main one is that for
+// a variety of reasons (see above), the install process for a Go release
+// cannot be relied upon to set the mtimes such that the go command will
+// think the standard library is up to date. So the mtime evidence is
+// ignored for the standard library if we find ourselves in a release
+// version of Go. Build ID-based staleness checks still apply to the
+// standard library, even in release versions. This makes
+// 'go build -tags netgo' work, among other things.
+
+// isStale reports whether package p needs to be rebuilt,
+// along with the reason why.
+func isStale(p *Package) (bool, string) {
+	if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
+		// fake, builtin package
+		return false, "builtin package"
+	}
+	if p.Error != nil {
+		return true, "errors loading package"
+	}
+	if p.Stale {
+		return true, p.StaleReason
+	}
+
+	// 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.Internal.Target == "" {
+			// Fail if a build is attempted.
+			return true, "no source code for package, but no install target"
+		}
+		if _, err := os.Stat(p.Internal.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 cfg.BuildA {
+		return true, "build -a flag in use"
+	}
+
+	// If there's no install target, we have to rebuild.
+	if p.Internal.Target == "" {
+		return true, "no install target"
+	}
+
+	// Package is stale if completely unbuilt.
+	fi, err := os.Stat(p.Internal.Target)
+	if err != nil {
+		return true, "cannot stat install target"
+	}
+
+	// Package is stale if the expected build ID differs from the
+	// recorded build ID. This catches changes like a source file
+	// being removed from a package directory. See issue 3895.
+	// It also catches changes in build tags that affect the set of
+	// files being compiled. See issue 9369.
+	// It also catches changes in toolchain, like when flipping between
+	// two versions of Go compiling a single GOPATH.
+	// See issue 8290 and issue 10702.
+	targetBuildID, err := buildid.ReadBuildID(p.Name, p.Target)
+	if err == nil && targetBuildID != p.Internal.BuildID {
+		return true, "build ID mismatch"
+	}
+
+	// Package is stale if a dependency is.
+	for _, p1 := range p.Internal.Deps {
+		if p1.Stale {
+			return true, "stale dependency"
+		}
+	}
+
+	// The checks above are content-based staleness.
+	// We assume they are always accurate.
+	//
+	// The checks below are mtime-based staleness.
+	// We hope they are accurate, but we know that they fail in the case of
+	// prebuilt Go installations that don't preserve the build mtimes
+	// (for example, if the pkg/ mtimes are before the src/ mtimes).
+	// See the large comment above isStale for details.
+
+	// If we are running a release copy of Go and didn't find a content-based
+	// reason to rebuild the standard packages, do not rebuild them.
+	// They may not be writable anyway, but they are certainly not changing.
+	// This makes 'go build' skip the standard packages when
+	// using an official release, even when the mtimes have been changed.
+	// See issue 3036, issue 3149, issue 4106, issue 8290.
+	// (If a change to a release tree must be made by hand, the way to force the
+	// install is to run make.bash, which will remove the old package archives
+	// before rebuilding.)
+	if p.Standard && isGoRelease {
+		return false, "standard package in Go release distribution"
+	}
+
+	// Time-based staleness.
+
+	built := fi.ModTime()
+
+	olderThan := func(file string) bool {
+		fi, err := os.Stat(file)
+		return err != nil || fi.ModTime().After(built)
+	}
+
+	// Package is stale if a dependency is, or if a dependency is newer.
+	for _, p1 := range p.Internal.Deps {
+		if p1.Internal.Target != "" && olderThan(p1.Internal.Target) {
+			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
+	// back-dated, as some binary distributions may do, but it does handle
+	// a very common case.
+	// See issue 3036.
+	// Exclude $GOROOT, under the assumption that people working on
+	// the compiler may want to control when everything gets rebuilt,
+	// and people updating the Go repository will run make.bash or all.bash
+	// and get a full rebuild anyway.
+	// Excluding $GOROOT used to also fix issue 4106, but that's now
+	// taken care of above (at least when the installed Go is a released version).
+	if p.Root != cfg.GOROOT {
+		if olderThan(cfg.BuildToolchainCompiler()) {
+			return true, "newer compiler"
+		}
+		if p.Internal.Build.IsCommand() && olderThan(cfg.BuildToolchainLinker()) {
+			return true, "newer linker"
+		}
+	}
+
+	// Note: Until Go 1.5, we had an additional shortcut here.
+	// We built a list of the workspace roots ($GOROOT, each $GOPATH)
+	// containing targets directly named on the command line,
+	// and if p were not in any of those, it would be treated as up-to-date
+	// as long as it is built. The goal was to avoid rebuilding a system-installed
+	// $GOROOT, unless something from $GOROOT were explicitly named
+	// on the command line (like go install math).
+	// That's now handled by the isGoRelease clause above.
+	// The other effect of the shortcut was to isolate different entries in
+	// $GOPATH from each other. This had the unfortunate effect that
+	// if you had (say), GOPATH listing two entries, one for commands
+	// and one for libraries, and you did a 'git pull' in the library one
+	// and then tried 'go install commands/...', it would build the new libraries
+	// during the first build (because they wouldn't have been installed at all)
+	// but then subsequent builds would not rebuild the libraries, even if the
+	// mtimes indicate they are stale, because the different GOPATH entries
+	// were treated differently. This behavior was confusing when using
+	// non-trivial GOPATHs, which were particularly common with some
+	// code management conventions, like the original godep.
+	// Since the $GOROOT case (the original motivation) is handled separately,
+	// we no longer put a barrier between the different $GOPATH entries.
+	//
+	// One implication of this is that if there is a system directory for
+	// non-standard Go packages that is included in $GOPATH, the mtimes
+	// on those compiled packages must be no earlier than the mtimes
+	// on the source files. Since most distributions use the same mtime
+	// for all files in a tree, they will be unaffected. People using plain
+	// tar x to extract system-installed packages will need to adjust mtimes,
+	// but it's better to force them to get the mtimes right than to ignore
+	// the mtimes and thereby do the wrong thing in common use cases.
+	//
+	// So there is no GOPATH vs GOPATH shortcut here anymore.
+	//
+	// If something needs to come back here, we could try writing a dummy
+	// file with a random name to the $GOPATH/pkg directory (and removing it)
+	// to test for write access, and then skip GOPATH roots we don't have write
+	// access to. But hopefully we can just use the mtimes always.
+
+	srcs := str.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, "newer source file"
+		}
+	}
+
+	return false, ""
+}
+
+// computeBuildID computes the build ID for p, leaving it in p.Internal.BuildID.
+// Build ID is a hash of the information we want to detect changes in.
+// See the long comment in isStale for details.
+func computeBuildID(p *Package) {
+	h := sha1.New()
+
+	// Include the list of files compiled as part of the package.
+	// This lets us detect removed files. See issue 3895.
+	inputFiles := str.StringList(
+		p.GoFiles,
+		p.CgoFiles,
+		p.CFiles,
+		p.CXXFiles,
+		p.FFiles,
+		p.MFiles,
+		p.HFiles,
+		p.SFiles,
+		p.SysoFiles,
+		p.SwigFiles,
+		p.SwigCXXFiles,
+	)
+	for _, file := range inputFiles {
+		fmt.Fprintf(h, "file %s\n", file)
+	}
+
+	// Include the content of runtime/internal/sys/zversion.go in the hash
+	// for package runtime. This will give package runtime a
+	// different build ID in each Go release.
+	if p.Standard && p.ImportPath == "runtime/internal/sys" && cfg.BuildContext.Compiler != "gccgo" {
+		data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
+		if os.IsNotExist(err) {
+			p.Stale = true
+			p.StaleReason = fmt.Sprintf("missing zversion.go")
+		} else if err != nil {
+			base.Fatalf("go: %s", err)
+		}
+		fmt.Fprintf(h, "zversion %q\n", string(data))
+
+		// Add environment variables that affect code generation.
+		switch cfg.BuildContext.GOARCH {
+		case "arm":
+			fmt.Fprintf(h, "GOARM=%s\n", cfg.GOARM)
+		case "386":
+			fmt.Fprintf(h, "GO386=%s\n", cfg.GO386)
+		}
+	}
+
+	// Include the build IDs of any dependencies in the hash.
+	// This, combined with the runtime/zversion content,
+	// will cause packages to have different build IDs when
+	// compiled with different Go releases.
+	// This helps the go command know to recompile when
+	// people use the same GOPATH but switch between
+	// different Go releases. See issue 10702.
+	// This is also a better fix for issue 8290.
+	for _, p1 := range p.Internal.Deps {
+		fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.Internal.BuildID)
+	}
+
+	p.Internal.BuildID = fmt.Sprintf("%x", h.Sum(nil))
+}
+
+var cmdCache = map[string]*Package{}
+
+func ClearCmdCache() {
+	for name := range cmdCache {
+		delete(cmdCache, name)
+	}
+}
+
+// loadPackage is like loadImport but is used for command-line arguments,
+// 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 {
+	if build.IsLocalImport(arg) {
+		dir := arg
+		if !filepath.IsAbs(dir) {
+			if abs, err := filepath.Abs(dir); err == nil {
+				// interpret relative to current directory
+				dir = abs
+			}
+		}
+		if sub, ok := hasSubdir(cfg.GOROOTsrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
+			arg = sub
+		}
+	}
+	if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
+		if p := cmdCache[arg]; p != nil {
+			return p
+		}
+		stk.Push(arg)
+		defer stk.Pop()
+
+		bp, err := cfg.BuildContext.ImportDir(filepath.Join(cfg.GOROOTsrc, arg), 0)
+		bp.ImportPath = arg
+		bp.Goroot = true
+		bp.BinDir = cfg.GOROOTbin
+		if cfg.GOROOTbin != "" {
+			bp.BinDir = cfg.GOROOTbin
+		}
+		bp.Root = cfg.GOROOT
+		bp.SrcRoot = cfg.GOROOTsrc
+		p := new(Package)
+		cmdCache[arg] = p
+		p.load(stk, bp, err)
+		if p.Error == nil && p.Name != "main" {
+			p.Error = &PackageError{
+				ImportStack: stk.Copy(),
+				Err:         fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
+			}
+		}
+		return p
+	}
+
+	// Wasn't a command; must be a package.
+	// If it is a local import path but names a standard package,
+	// we treat it as if the user specified the standard package.
+	// This lets you run go test ./ioutil in package io and be
+	// referring to io/ioutil rather than a hypothetical import of
+	// "./ioutil".
+	if build.IsLocalImport(arg) {
+		bp, _ := cfg.BuildContext.ImportDir(filepath.Join(base.Cwd, arg), build.FindOnly)
+		if bp.ImportPath != "" && bp.ImportPath != "." {
+			arg = bp.ImportPath
+		}
+	}
+
+	return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
+}
+
+// packages returns the packages named by the
+// 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
+// to load dependencies of a named package, the named
+// package is still returned, with p.Incomplete = true
+// and details in p.DepsErrors.
+func Packages(args []string) []*Package {
+	var pkgs []*Package
+	for _, pkg := range PackagesAndErrors(args) {
+		if pkg.Error != nil {
+			base.Errorf("can't load package: %s", pkg.Error)
+			continue
+		}
+		pkgs = append(pkgs, pkg)
+	}
+	return pkgs
+}
+
+// packagesAndErrors is like 'packages' but returns a
+// *Package for every argument, even the ones that
+// cannot be loaded at all.
+// The packages that fail to load will have p.Error != nil.
+func PackagesAndErrors(args []string) []*Package {
+	if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
+		return []*Package{GoFilesPackage(args)}
+	}
+
+	args = ImportPaths(args)
+	var (
+		pkgs    []*Package
+		stk     ImportStack
+		seenArg = make(map[string]bool)
+		seenPkg = make(map[*Package]bool)
+	)
+
+	for _, arg := range args {
+		if seenArg[arg] {
+			continue
+		}
+		seenArg[arg] = true
+		pkg := LoadPackage(arg, &stk)
+		if seenPkg[pkg] {
+			continue
+		}
+		seenPkg[pkg] = true
+		pkgs = append(pkgs, pkg)
+	}
+	ComputeStale(pkgs...)
+
+	return pkgs
+}
+
+// packagesForBuild is like 'packages' but fails if any of
+// the packages or their dependencies have errors
+// (cannot be built).
+func PackagesForBuild(args []string) []*Package {
+	pkgs := PackagesAndErrors(args)
+	printed := map[*PackageError]bool{}
+	for _, pkg := range pkgs {
+		if pkg.Error != nil {
+			base.Errorf("can't load package: %s", pkg.Error)
+		}
+		for _, err := range pkg.DepsErrors {
+			// Since these are errors in dependencies,
+			// the same error might show up multiple times,
+			// once in each package that depends on it.
+			// Only print each once.
+			if !printed[err] {
+				printed[err] = true
+				base.Errorf("%s", err)
+			}
+		}
+	}
+	base.ExitIfErrors()
+
+	// Check for duplicate loads of the same package.
+	// That should be impossible, but if it does happen then
+	// we end up trying to build the same package twice,
+	// usually in parallel overwriting the same files,
+	// which doesn't work very well.
+	seen := map[string]bool{}
+	reported := map[string]bool{}
+	for _, pkg := range PackageList(pkgs) {
+		if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
+			reported[pkg.ImportPath] = true
+			base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
+		}
+		seen[pkg.ImportPath] = true
+	}
+	base.ExitIfErrors()
+
+	return pkgs
+}
+
+// GoFilesPackage creates a package for building a collection of Go files
+// (typically named on the command line). The target is named p.a for
+// package p or named after the first Go file for package main.
+func GoFilesPackage(gofiles []string) *Package {
+	// TODO: Remove this restriction.
+	for _, f := range gofiles {
+		if !strings.HasSuffix(f, ".go") {
+			base.Fatalf("named files must be .go files")
+		}
+	}
+
+	var stk ImportStack
+	ctxt := cfg.BuildContext
+	ctxt.UseAllFiles = true
+
+	// 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
+	// consistently, the files must all be in the same directory.
+	var dirent []os.FileInfo
+	var dir string
+	for _, file := range gofiles {
+		fi, err := os.Stat(file)
+		if err != nil {
+			base.Fatalf("%s", err)
+		}
+		if fi.IsDir() {
+			base.Fatalf("%s is a directory, should be a Go file", file)
+		}
+		dir1, _ := filepath.Split(file)
+		if dir1 == "" {
+			dir1 = "./"
+		}
+		if dir == "" {
+			dir = dir1
+		} else if dir != dir1 {
+			base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
+		}
+		dirent = append(dirent, fi)
+	}
+	ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+	var err error
+	if dir == "" {
+		dir = base.Cwd
+	}
+	dir, err = filepath.Abs(dir)
+	if err != nil {
+		base.Fatalf("%s", err)
+	}
+
+	bp, err := ctxt.ImportDir(dir, 0)
+	pkg := new(Package)
+	pkg.Internal.Local = true
+	pkg.Internal.Cmdline = true
+	stk.Push("main")
+	pkg.load(&stk, bp, err)
+	stk.Pop()
+	pkg.Internal.LocalPrefix = dirToImportPath(dir)
+	pkg.ImportPath = "command-line-arguments"
+	pkg.Internal.Target = ""
+
+	if pkg.Name == "main" {
+		_, elem := filepath.Split(gofiles[0])
+		exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
+		if cfg.BuildO == "" {
+			cfg.BuildO = exe
+		}
+		if cfg.GOBIN != "" {
+			pkg.Internal.Target = filepath.Join(cfg.GOBIN, exe)
+		}
+	}
+
+	pkg.Target = pkg.Internal.Target
+	pkg.Stale = true
+	pkg.StaleReason = "files named on command line"
+
+	ComputeStale(pkg)
+	return pkg
+}
diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go
new file mode 100644
index 0000000..4f6292c
--- /dev/null
+++ b/src/cmd/go/internal/load/search.go
@@ -0,0 +1,324 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package load
+
+import (
+	"cmd/go/internal/cfg"
+	"fmt"
+	"go/build"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+// allPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func allPackages(pattern string) []string {
+	pkgs := MatchPackages(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// 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.
+func allPackagesInFS(pattern string) []string {
+	pkgs := MatchPackagesInFS(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// MatchPackages returns a list of package paths matching pattern
+// (see go help packages for pattern syntax).
+func MatchPackages(pattern string) []string {
+	match := func(string) bool { return true }
+	treeCanMatch := func(string) bool { return true }
+	if !IsMetaPackage(pattern) {
+		match = matchPattern(pattern)
+		treeCanMatch = treeCanMatchPattern(pattern)
+	}
+
+	have := map[string]bool{
+		"builtin": true, // ignore pseudo-package that exists only for documentation
+	}
+	if !cfg.BuildContext.CgoEnabled {
+		have["runtime/cgo"] = true // ignore during walk
+	}
+	var pkgs []string
+
+	for _, src := range cfg.BuildContext.SrcDirs() {
+		if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
+			continue
+		}
+		src = filepath.Clean(src) + string(filepath.Separator)
+		root := src
+		if pattern == "cmd" {
+			root += "cmd" + string(filepath.Separator)
+		}
+		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+			if err != nil || !fi.IsDir() || path == src {
+				return nil
+			}
+
+			// Avoid .foo, _foo, and testdata directory trees.
+			_, elem := filepath.Split(path)
+			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+				return filepath.SkipDir
+			}
+
+			name := filepath.ToSlash(path[len(src):])
+			if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
+				// The name "std" is only the standard library.
+				// If the name is cmd, it's the root of the command tree.
+				return filepath.SkipDir
+			}
+			if !treeCanMatch(name) {
+				return filepath.SkipDir
+			}
+			if have[name] {
+				return nil
+			}
+			have[name] = true
+			if !match(name) {
+				return nil
+			}
+			pkg, err := cfg.BuildContext.ImportDir(path, 0)
+			if err != nil {
+				if _, noGo := err.(*build.NoGoError); noGo {
+					return nil
+				}
+			}
+
+			// If we are expanding "cmd", skip main
+			// packages under cmd/vendor. At least as of
+			// March, 2017, there is one there for the
+			// vendored pprof tool.
+			if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
+				return nil
+			}
+
+			pkgs = append(pkgs, name)
+			return nil
+		})
+	}
+	return pkgs
+}
+
+// MatchPackagesInFS returns a list of package paths matching pattern,
+// which must begin with ./ or ../
+// (see go help packages for pattern syntax).
+func MatchPackagesInFS(pattern string) []string {
+	// Find directory to begin the scan.
+	// Could be smarter but this one optimization
+	// is enough for now, since ... is usually at the
+	// end of a path.
+	i := strings.Index(pattern, "...")
+	dir, _ := path.Split(pattern[:i])
+
+	// pattern begins with ./ or ../.
+	// path.Clean will discard the ./ but not the ../.
+	// We need to preserve the ./ for pattern matching
+	// and in the returned import paths.
+	prefix := ""
+	if strings.HasPrefix(pattern, "./") {
+		prefix = "./"
+	}
+	match := matchPattern(pattern)
+
+	var pkgs []string
+	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() {
+			return nil
+		}
+		if path == dir {
+			// filepath.Walk starts at dir and recurses. For the recursive case,
+			// the path is the result of filepath.Join, which calls filepath.Clean.
+			// The initial case is not Cleaned, though, so we do this explicitly.
+			//
+			// This converts a path like "./io/" to "io". Without this step, running
+			// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+			// package, because prepending the prefix "./" to the unclean path would
+			// result in "././io", and match("././io") returns false.
+			path = filepath.Clean(path)
+		}
+
+		// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+		_, elem := filepath.Split(path)
+		dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+		if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+			return filepath.SkipDir
+		}
+
+		name := prefix + filepath.ToSlash(path)
+		if !match(name) {
+			return nil
+		}
+
+		// We keep the directory if we can import it, or if we can't import it
+		// due to invalid Go source files. This means that directories containing
+		// parse errors will be built (and fail) instead of being silently skipped
+		// as not matching the pattern. Go 1.5 and earlier skipped, but that
+		// behavior means people miss serious mistakes.
+		// See golang.org/issue/11407.
+		if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
+			if _, noGo := err.(*build.NoGoError); !noGo {
+				log.Print(err)
+			}
+			return nil
+		}
+		pkgs = append(pkgs, name)
+		return nil
+	})
+	return pkgs
+}
+
+// treeCanMatchPattern(pattern)(name) reports whether
+// name or children of name can possibly match pattern.
+// Pattern is the same limited glob accepted by matchPattern.
+func treeCanMatchPattern(pattern string) func(name string) bool {
+	wildCard := false
+	if i := strings.Index(pattern, "..."); i >= 0 {
+		wildCard = true
+		pattern = pattern[:i]
+	}
+	return func(name string) bool {
+		return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+			wildCard && strings.HasPrefix(name, pattern)
+	}
+}
+
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+// Unfortunately, there are two special cases. Quoting "go help packages":
+//
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separted pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+func matchPattern(pattern string) func(name string) bool {
+	// Convert pattern to regular expression.
+	// The strategy for the trailing /... is to nest it in an explicit ? expression.
+	// The strategy for the vendor exclusion is to change the unmatchable
+	// vendor strings to a disallowed code point (vendorChar) and to use
+	// "(anything but that codepoint)*" as the implementation of the ... wildcard.
+	// This is a bit complicated but the obvious alternative,
+	// namely a hand-written search like in most shell glob matchers,
+	// is too easy to make accidentally exponential.
+	// Using package regexp guarantees linear-time matching.
+
+	const vendorChar = "\x00"
+
+	if strings.Contains(pattern, vendorChar) {
+		return func(name string) bool { return false }
+	}
+
+	re := regexp.QuoteMeta(pattern)
+	re = replaceVendor(re, vendorChar)
+	switch {
+	case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
+		re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
+	case re == vendorChar+`/\.\.\.`:
+		re = `(/vendor|/` + vendorChar + `/\.\.\.)`
+	case strings.HasSuffix(re, `/\.\.\.`):
+		re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
+	}
+	re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
+
+	reg := regexp.MustCompile(`^` + re + `$`)
+
+	return func(name string) bool {
+		if strings.Contains(name, vendorChar) {
+			return false
+		}
+		return reg.MatchString(replaceVendor(name, vendorChar))
+	}
+}
+
+// replaceVendor returns the result of replacing
+// non-trailing vendor path elements in x with repl.
+func replaceVendor(x, repl string) string {
+	if !strings.Contains(x, "vendor") {
+		return x
+	}
+	elem := strings.Split(x, "/")
+	for i := 0; i < len(elem)-1; i++ {
+		if elem[i] == "vendor" {
+			elem[i] = repl
+		}
+	}
+	return strings.Join(elem, "/")
+}
+
+// ImportPaths returns the import paths to use for the given command line.
+func ImportPaths(args []string) []string {
+	args = ImportPathsNoDotExpansion(args)
+	var out []string
+	for _, a := range args {
+		if strings.Contains(a, "...") {
+			if build.IsLocalImport(a) {
+				out = append(out, allPackagesInFS(a)...)
+			} else {
+				out = append(out, allPackages(a)...)
+			}
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// ImportPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func ImportPathsNoDotExpansion(args []string) []string {
+	if len(args) == 0 {
+		return []string{"."}
+	}
+	var out []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.
+		if filepath.Separator == '\\' {
+			a = strings.Replace(a, `\`, `/`, -1)
+		}
+
+		// Put argument in canonical form, but preserve leading ./.
+		if strings.HasPrefix(a, "./") {
+			a = "./" + path.Clean(a)
+			if a == "./." {
+				a = "."
+			}
+		} else {
+			a = path.Clean(a)
+		}
+		if IsMetaPackage(a) {
+			out = append(out, allPackages(a)...)
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// isMetaPackage checks if name is a reserved package name that expands to multiple packages.
+func IsMetaPackage(name string) bool {
+	return name == "std" || name == "cmd" || name == "all"
+}
diff --git a/src/cmd/go/internal/load/testgo.go b/src/cmd/go/internal/load/testgo.go
new file mode 100644
index 0000000..7734048
--- /dev/null
+++ b/src/cmd/go/internal/load/testgo.go
@@ -0,0 +1,21 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains extra hooks for testing the go command.
+// It is compiled into the Go binary only when building the
+// test copy; it does not get compiled into the standard go
+// command, so these testing hooks are not present in the
+// go command that everyone uses.
+
+// +build testgo
+
+package load
+
+import "os"
+
+func init() {
+	if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
+		isGoRelease = v == "1"
+	}
+}
diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go
new file mode 100644
index 0000000..6e276c2
--- /dev/null
+++ b/src/cmd/go/internal/run/run.go
@@ -0,0 +1,131 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package run implements the ``go run'' command.
+package run
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+	"cmd/go/internal/work"
+)
+
+var CmdRun = &base.Command{
+	UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
+	Short:     "compile and run Go program",
+	Long: `
+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.
+	`,
+}
+
+func init() {
+	CmdRun.Run = runRun // break init loop
+
+	work.AddBuildFlags(CmdRun)
+	CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
+}
+
+func printStderr(args ...interface{}) (int, error) {
+	return fmt.Fprint(os.Stderr, args...)
+}
+
+func runRun(cmd *base.Command, args []string) {
+	work.InstrumentInit()
+	work.BuildModeInit()
+	var b work.Builder
+	b.Init()
+	b.Print = printStderr
+	i := 0
+	for i < len(args) && strings.HasSuffix(args[i], ".go") {
+		i++
+	}
+	files, cmdArgs := args[:i], args[i:]
+	if len(files) == 0 {
+		base.Fatalf("go run: no go files listed")
+	}
+	for _, file := range files {
+		if strings.HasSuffix(file, "_test.go") {
+			// GoFilesPackage is going to assign this to TestGoFiles.
+			// Reject since it won't be part of the build.
+			base.Fatalf("go run: cannot run *_test.go files (%s)", file)
+		}
+	}
+	p := load.GoFilesPackage(files)
+	if p.Error != nil {
+		base.Fatalf("%s", p.Error)
+	}
+	p.Internal.OmitDebug = true
+	if len(p.DepsErrors) > 0 {
+		// Since these are errors in dependencies,
+		// the same error might show up multiple times,
+		// once in each package that depends on it.
+		// Only print each once.
+		printed := map[*load.PackageError]bool{}
+		for _, err := range p.DepsErrors {
+			if !printed[err] {
+				printed[err] = true
+				base.Errorf("%s", err)
+			}
+		}
+	}
+	base.ExitIfErrors()
+	if p.Name != "main" {
+		base.Fatalf("go run: cannot run non-main package")
+	}
+	p.Internal.Target = "" // must build - not up to date
+	var src string
+	if len(p.GoFiles) > 0 {
+		src = p.GoFiles[0]
+	} else if len(p.CgoFiles) > 0 {
+		src = p.CgoFiles[0]
+	} else {
+		// this case could only happen if the provided source uses cgo
+		// while cgo is disabled.
+		hint := ""
+		if !cfg.BuildContext.CgoEnabled {
+			hint = " (cgo is disabled)"
+		}
+		base.Fatalf("go run: no suitable source files%s", hint)
+	}
+	p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
+	a1 := b.Action(work.ModeBuild, work.ModeBuild, p)
+	a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
+	b.Do(a)
+}
+
+// buildRunProgram is the action for running a binary that has already
+// been compiled. We ignore exit status.
+func buildRunProgram(b *work.Builder, a *work.Action) error {
+	cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd("", "%s", strings.Join(cmdline, " "))
+		if cfg.BuildN {
+			return nil
+		}
+	}
+
+	base.RunStdin(cmdline)
+	return nil
+}
diff --git a/src/cmd/go/internal/str/str.go b/src/cmd/go/internal/str/str.go
new file mode 100644
index 0000000..5d06bbe
--- /dev/null
+++ b/src/cmd/go/internal/str/str.go
@@ -0,0 +1,141 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package str provides string manipulation utilities.
+package str
+
+import (
+	"bytes"
+	"fmt"
+	"unicode"
+	"unicode/utf8"
+)
+
+// StringList flattens its arguments into a single []string.
+// Each argument in args must have type string or []string.
+func StringList(args ...interface{}) []string {
+	var x []string
+	for _, arg := range args {
+		switch arg := arg.(type) {
+		case []string:
+			x = append(x, arg...)
+		case string:
+			x = append(x, arg)
+		default:
+			panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
+		}
+	}
+	return x
+}
+
+// toFold returns a string with the property that
+//	strings.EqualFold(s, t) iff toFold(s) == toFold(t)
+// This lets us test a large set of strings for fold-equivalent
+// duplicates without making a quadratic number of calls
+// to EqualFold. Note that strings.ToUpper and strings.ToLower
+// do not have the desired property in some corner cases.
+func toFold(s string) string {
+	// Fast path: all ASCII, no upper case.
+	// Most paths look like this already.
+	for i := 0; i < len(s); i++ {
+		c := s[i]
+		if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
+			goto Slow
+		}
+	}
+	return s
+
+Slow:
+	var buf bytes.Buffer
+	for _, r := range s {
+		// SimpleFold(x) cycles to the next equivalent rune > x
+		// or wraps around to smaller values. Iterate until it wraps,
+		// and we've found the minimum value.
+		for {
+			r0 := r
+			r = unicode.SimpleFold(r0)
+			if r <= r0 {
+				break
+			}
+		}
+		// Exception to allow fast path above: A-Z => a-z
+		if 'A' <= r && r <= 'Z' {
+			r += 'a' - 'A'
+		}
+		buf.WriteRune(r)
+	}
+	return buf.String()
+}
+
+// FoldDup reports a pair of strings from the list that are
+// equal according to strings.EqualFold.
+// It returns "", "" if there are no such strings.
+func FoldDup(list []string) (string, string) {
+	clash := map[string]string{}
+	for _, s := range list {
+		fold := toFold(s)
+		if t := clash[fold]; t != "" {
+			if s > t {
+				s, t = t, s
+			}
+			return s, t
+		}
+		clash[fold] = s
+	}
+	return "", ""
+}
+
+// Contains reports whether x contains s.
+func Contains(x []string, s string) bool {
+	for _, t := range x {
+		if t == s {
+			return true
+		}
+	}
+	return false
+}
+
+func isSpaceByte(c byte) bool {
+	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+// SplitQuotedFields splits s into a list of fields,
+// allowing single or double quotes around elements.
+// There is no unescaping or other processing within
+// quoted fields.
+func SplitQuotedFields(s string) ([]string, error) {
+	// Split fields allowing '' or "" around elements.
+	// Quotes further inside the string do not count.
+	var f []string
+	for len(s) > 0 {
+		for len(s) > 0 && isSpaceByte(s[0]) {
+			s = s[1:]
+		}
+		if len(s) == 0 {
+			break
+		}
+		// Accepted quoted string. No unescaping inside.
+		if s[0] == '"' || s[0] == '\'' {
+			quote := s[0]
+			s = s[1:]
+			i := 0
+			for i < len(s) && s[i] != quote {
+				i++
+			}
+			if i >= len(s) {
+				return nil, fmt.Errorf("unterminated %c string", quote)
+			}
+			f = append(f, s[:i])
+			s = s[i+1:]
+			continue
+		}
+		i := 0
+		for i < len(s) && !isSpaceByte(s[i]) {
+			i++
+		}
+		f = append(f, s[:i])
+		s = s[i:]
+	}
+	return f, nil
+}
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
new file mode 100644
index 0000000..8cffa14
--- /dev/null
+++ b/src/cmd/go/internal/test/test.go
@@ -0,0 +1,1604 @@
+// Copyright 2011 The Go Authors. 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 (
+	"bytes"
+	"errors"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/doc"
+	"go/parser"
+	"go/token"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"sort"
+	"strings"
+	"text/template"
+	"time"
+	"unicode"
+	"unicode/utf8"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+	"cmd/go/internal/work"
+)
+
+// Break init loop.
+func init() {
+	CmdTest.Run = runTest
+}
+
+const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
+
+var CmdTest = &base.Command{
+	CustomFlags: true,
+	UsageLine:   testUsage,
+	Short:       "test packages",
+	Long: `
+'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.
+
+` + strings.TrimSpace(testFlag1) + ` 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.
+`,
+}
+
+const testFlag1 = `
+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'.
+`
+
+// Usage prints the usage message for 'go test -h' and exits.
+func Usage() {
+	os.Stderr.WriteString(testUsage + "\n\n" +
+		strings.TrimSpace(testFlag1) + "\n\n\t" +
+		strings.TrimSpace(testFlag2) + "\n")
+	os.Exit(2)
+}
+
+var HelpTestflag = &base.Command{
+	UsageLine: "testflag",
+	Short:     "description of testing flags",
+	Long: `
+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:
+
+	` + strings.TrimSpace(testFlag2) + `
+`,
+}
+
+const testFlag2 = `
+	-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=.'.
+
+	-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).
+
+	-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.
+	    Note that because coverage works by annotating the source
+	    code before compilation, compilation and test failures with
+	    coverage enabled may report line numbers that don't correspond
+	    to the original sources.
+
+	-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.
+
+	-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.
+
+	-list regexp
+	    List tests, benchmarks, or examples matching the regular expression.
+	    No tests, benchmarks or examples will be run. This will only
+	    list top-level tests. No subtest or subbenchmarks will be shown.
+
+	-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).
+
+	-v
+	    Verbose output: log all tests as they are run. Also print all
+	    text from Log and Logf calls even if the test succeeds.
+
+The following flags are also recognized by 'go test' and can be used to
+profile the tests during execution:
+
+	-benchmem
+	    Print memory allocation statistics for benchmarks.
+
+	-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.
+
+	-coverprofile cover.out
+	    Write a coverage profile to the file after all tests have passed.
+	    Sets -cover.
+
+	-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.
+
+	-mutexprofile mutex.out
+	    Write a mutex contention profile to the specified file
+	    when all tests are complete.
+	    Writes test binary as -c would.
+
+	-mutexprofilefraction n
+	    Sample 1 in n stack traces of goroutines holding a
+	    contended mutex.
+
+	-outputdir directory
+	    Place output files from profiling in the specified directory,
+	    by default the directory in which "go test" is running.
+
+	-trace trace.out
+	    Write an execution trace to the specified file before exiting.
+
+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.
+`
+
+var HelpTestfunc = &base.Command{
+	UsageLine: "testfunc",
+	Short:     "description of testing functions",
+	Long: `
+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 is compiled but not executed. An example with no text after
+"Output:" is compiled, executed, and expected to produce no output.
+
+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.
+`,
+}
+
+var (
+	testC            bool            // -c flag
+	testCover        bool            // -cover flag
+	testCoverMode    string          // -covermode flag
+	testCoverPaths   []string        // -coverpkg flag
+	testCoverPkgs    []*load.Package // -coverpkg flag
+	testO            string          // -o flag
+	testProfile      bool            // some profiling flag
+	testNeedBinary   bool            // profile needs to keep binary around
+	testV            bool            // -v flag
+	testTimeout      string          // -timeout flag
+	testArgs         []string
+	testBench        bool
+	testList         bool
+	testStreamOutput bool // show output as it is generated
+	testShowPass     bool // show passing output
+
+	testKillTimeout = 10 * time.Minute
+)
+
+var testMainDeps = map[string]bool{
+	// Dependencies for testmain.
+	"testing":                   true,
+	"testing/internal/testdeps": true,
+	"os": true,
+}
+
+func runTest(cmd *base.Command, args []string) {
+	var pkgArgs []string
+	pkgArgs, testArgs = testFlags(args)
+
+	work.FindExecCmd() // initialize cached result
+
+	work.InstrumentInit()
+	work.BuildModeInit()
+	pkgs := load.PackagesForBuild(pkgArgs)
+	if len(pkgs) == 0 {
+		base.Fatalf("no packages to test")
+	}
+
+	if testC && len(pkgs) != 1 {
+		base.Fatalf("cannot use -c flag with multiple packages")
+	}
+	if testO != "" && len(pkgs) != 1 {
+		base.Fatalf("cannot use -o flag with multiple packages")
+	}
+	if testProfile && len(pkgs) != 1 {
+		base.Fatalf("cannot use test profile flag with multiple packages")
+	}
+
+	// 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
+	// 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 {
+		testKillTimeout = dt + 1*time.Minute
+	}
+
+	// show passing test output (after buffering) with -v flag.
+	// must buffer because tests are running in parallel, and
+	// otherwise the output will get mixed.
+	testShowPass = testV || testList
+
+	// stream test output (no buffering) when no package has
+	// been given on the command line (implicit current directory)
+	// or when benchmarking.
+	// Also stream if we're showing output anyway with a
+	// single package under test or if parallelism is set to 1.
+	// In these cases, streaming the output produces the same result
+	// as not streaming, just more immediately.
+	testStreamOutput = len(pkgArgs) == 0 || testBench ||
+		(testShowPass && (len(pkgs) == 1 || cfg.BuildP == 1))
+
+	// For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier.
+	if cfg.BuildI && testO != "" {
+		testC = true
+	}
+
+	var b work.Builder
+	b.Init()
+
+	if cfg.BuildI {
+		cfg.BuildV = testV
+
+		deps := make(map[string]bool)
+		for dep := range testMainDeps {
+			deps[dep] = true
+		}
+
+		for _, p := range pkgs {
+			// Dependencies for each test.
+			for _, path := range p.Imports {
+				deps[path] = true
+			}
+			for _, path := range p.Vendored(p.TestImports) {
+				deps[path] = true
+			}
+			for _, path := range p.Vendored(p.XTestImports) {
+				deps[path] = true
+			}
+		}
+
+		// translate C to runtime/cgo
+		if deps["C"] {
+			delete(deps, "C")
+			deps["runtime/cgo"] = true
+			if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan {
+				deps["cmd/cgo"] = true
+			}
+		}
+		// Ignore pseudo-packages.
+		delete(deps, "unsafe")
+
+		all := []string{}
+		for path := range deps {
+			if !build.IsLocalImport(path) {
+				all = append(all, path)
+			}
+		}
+		sort.Strings(all)
+
+		a := &work.Action{}
+		for _, p := range load.PackagesForBuild(all) {
+			a.Deps = append(a.Deps, b.Action(work.ModeInstall, work.ModeInstall, p))
+		}
+		b.Do(a)
+		if !testC || a.Failed {
+			return
+		}
+		b.Init()
+	}
+
+	var builds, runs, prints []*work.Action
+
+	if testCoverPaths != nil {
+		// Load packages that were asked about for coverage.
+		// packagesForBuild exits if the packages cannot be loaded.
+		testCoverPkgs = load.PackagesForBuild(testCoverPaths)
+
+		// Warn about -coverpkg arguments that are not actually used.
+		used := make(map[string]bool)
+		for _, p := range pkgs {
+			used[p.ImportPath] = true
+			for _, dep := range p.Deps {
+				used[dep] = true
+			}
+		}
+		for _, p := range testCoverPkgs {
+			if !used[p.ImportPath] {
+				fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on %s\n", p.ImportPath)
+			}
+		}
+
+		// Mark all the coverage packages for rebuilding with coverage.
+		for _, p := range testCoverPkgs {
+			// There is nothing to cover in package unsafe; it comes from the compiler.
+			if p.ImportPath == "unsafe" {
+				continue
+			}
+			p.Stale = true // rebuild
+			p.StaleReason = "rebuild for coverage"
+			p.Internal.Fake = true // do not warn about rebuild
+			p.Internal.CoverMode = testCoverMode
+			var coverFiles []string
+			coverFiles = append(coverFiles, p.GoFiles...)
+			coverFiles = append(coverFiles, p.CgoFiles...)
+			coverFiles = append(coverFiles, p.TestGoFiles...)
+			p.Internal.CoverVars = declareCoverVars(p.ImportPath, coverFiles...)
+		}
+	}
+
+	// Prepare build + run + print actions for all packages being tested.
+	for _, p := range pkgs {
+		// sync/atomic import is inserted by the cover tool. See #18486
+		if testCover && testCoverMode == "atomic" {
+			ensureImport(p, "sync/atomic")
+		}
+
+		buildTest, runTest, printTest, err := builderTest(&b, p)
+		if err != nil {
+			str := err.Error()
+			if strings.HasPrefix(str, "\n") {
+				str = str[1:]
+			}
+			failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
+
+			if p.ImportPath != "" {
+				base.Errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
+			} else {
+				base.Errorf("%s\n%s", str, failed)
+			}
+			continue
+		}
+		builds = append(builds, buildTest)
+		runs = append(runs, runTest)
+		prints = append(prints, printTest)
+	}
+
+	// Ultimately the goal is to print the output.
+	root := &work.Action{Deps: prints}
+
+	// Force the printing of results to happen in order,
+	// one at a time.
+	for i, a := range prints {
+		if i > 0 {
+			a.Deps = append(a.Deps, prints[i-1])
+		}
+	}
+
+	// Force benchmarks to run in serial.
+	if !testC && testBench {
+		// The first run must wait for all builds.
+		// Later runs must wait for the previous run's print.
+		for i, run := range runs {
+			if i == 0 {
+				run.Deps = append(run.Deps, builds...)
+			} else {
+				run.Deps = append(run.Deps, prints[i-1])
+			}
+		}
+	}
+
+	// If we are building any out-of-date packages other
+	// than those under test, warn.
+	okBuild := map[*load.Package]bool{}
+	for _, p := range pkgs {
+		okBuild[p] = true
+	}
+	warned := false
+	for _, a := range work.ActionList(root) {
+		if a.Package == nil || okBuild[a.Package] {
+			continue
+		}
+		okBuild[a.Package] = true // warn at most once
+
+		// Don't warn about packages being rebuilt because of
+		// things like coverage analysis.
+		for _, p1 := range a.Package.Internal.Imports {
+			if p1.Internal.Fake {
+				a.Package.Internal.Fake = true
+			}
+		}
+
+		if a.Func != nil && !okBuild[a.Package] && !a.Package.Internal.Fake && !a.Package.Internal.Local {
+			if !warned {
+				fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
+				warned = true
+			}
+			fmt.Fprintf(os.Stderr, "\t%s\n", a.Package.ImportPath)
+		}
+	}
+	if warned {
+		args := strings.Join(pkgArgs, " ")
+		if args != "" {
+			args = " " + args
+		}
+		extraOpts := ""
+		if cfg.BuildRace {
+			extraOpts = "-race "
+		}
+		if cfg.BuildMSan {
+			extraOpts = "-msan "
+		}
+		fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args)
+	}
+
+	b.Do(root)
+}
+
+// ensures that package p imports the named package
+func ensureImport(p *load.Package, pkg string) {
+	for _, d := range p.Internal.Deps {
+		if d.Name == pkg {
+			return
+		}
+	}
+
+	a := load.LoadPackage(pkg, &load.ImportStack{})
+	if a.Error != nil {
+		base.Fatalf("load %s: %v", pkg, a.Error)
+	}
+	load.ComputeStale(a)
+
+	p.Internal.Imports = append(p.Internal.Imports, a)
+}
+
+var windowsBadWords = []string{
+	"install",
+	"patch",
+	"setup",
+	"update",
+}
+
+func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) {
+	if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
+		build := b.Action(work.ModeBuild, work.ModeBuild, p)
+		run := &work.Action{Package: p, Deps: []*work.Action{build}}
+		print := &work.Action{Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
+		return build, run, print, nil
+	}
+
+	// Build Package structs describing:
+	//	ptest - package + test files
+	//	pxtest - package of external test files
+	//	pmain - pkg.test binary
+	var ptest, pxtest, pmain *load.Package
+
+	var imports, ximports []*load.Package
+	var stk load.ImportStack
+	stk.Push(p.ImportPath + " (test)")
+	for i, path := range p.TestImports {
+		p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor)
+		if p1.Error != nil {
+			return nil, nil, nil, p1.Error
+		}
+		if len(p1.DepsErrors) > 0 {
+			err := p1.DepsErrors[0]
+			err.Pos = "" // show full import stack
+			return nil, nil, nil, err
+		}
+		if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
+			// Same error that loadPackage returns (via reusePackage) in pkg.go.
+			// Can't change that code, because that code is only for loading the
+			// non-test copy of a package.
+			err := &load.PackageError{
+				ImportStack:   testImportStack(stk[0], p1, p.ImportPath),
+				Err:           "import cycle not allowed in test",
+				IsImportCycle: true,
+			}
+			return nil, nil, nil, err
+		}
+		p.TestImports[i] = p1.ImportPath
+		imports = append(imports, p1)
+	}
+	stk.Pop()
+	stk.Push(p.ImportPath + "_test")
+	pxtestNeedsPtest := false
+	for i, path := range p.XTestImports {
+		p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor)
+		if p1.Error != nil {
+			return nil, nil, nil, p1.Error
+		}
+		if len(p1.DepsErrors) > 0 {
+			err := p1.DepsErrors[0]
+			err.Pos = "" // show full import stack
+			return nil, nil, nil, err
+		}
+		if p1.ImportPath == p.ImportPath {
+			pxtestNeedsPtest = true
+		} else {
+			ximports = append(ximports, p1)
+		}
+		p.XTestImports[i] = p1.ImportPath
+	}
+	stk.Pop()
+
+	// Use last element of import path, not package name.
+	// They differ when package name is "main".
+	// But if the import path is "command-line-arguments",
+	// like it is during 'go run', use the package name.
+	var elem string
+	if p.ImportPath == "command-line-arguments" {
+		elem = p.Name
+	} else {
+		_, elem = path.Split(p.ImportPath)
+	}
+	testBinary := elem + ".test"
+
+	// The ptest package needs to be importable under the
+	// same import path that p has, but we cannot put it in
+	// 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
+	// compiler and linker to look in that _test directory first.
+	//
+	// That is, if the package under test is unicode/utf8,
+	// then the normal place to write the package archive is
+	// $WORK/unicode/utf8.a, but we write the test package archive to
+	// $WORK/unicode/utf8/_test/unicode/utf8.a.
+	// We write the external test package archive to
+	// $WORK/unicode/utf8/_test/unicode/utf8_test.a.
+	testDir := filepath.Join(b.WorkDir, filepath.FromSlash(p.ImportPath+"/_test"))
+	ptestObj := work.BuildToolchain.Pkgpath(testDir, p)
+
+	// Create the directory for the .a files.
+	ptestDir, _ := filepath.Split(ptestObj)
+	if err := b.Mkdir(ptestDir); err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Should we apply coverage analysis locally,
+	// only for this package and only for this test?
+	// Yes, if -cover is on but -coverpkg has not specified
+	// a list of packages for global coverage.
+	localCover := testCover && testCoverPaths == nil
+
+	// Test package.
+	if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
+		ptest = new(load.Package)
+		*ptest = *p
+		ptest.GoFiles = nil
+		ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
+		ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
+		ptest.Internal.Target = ""
+		ptest.Imports = str.StringList(p.Imports, p.TestImports)
+		ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...)
+		ptest.Internal.Pkgdir = testDir
+		ptest.Internal.Fake = true
+		ptest.Internal.ForceLibrary = true
+		ptest.Stale = true
+		ptest.StaleReason = "rebuild for test"
+		ptest.Internal.Build = new(build.Package)
+		*ptest.Internal.Build = *p.Internal.Build
+		m := map[string][]token.Position{}
+		for k, v := range p.Internal.Build.ImportPos {
+			m[k] = append(m[k], v...)
+		}
+		for k, v := range p.Internal.Build.TestImportPos {
+			m[k] = append(m[k], v...)
+		}
+		ptest.Internal.Build.ImportPos = m
+
+		if localCover {
+			ptest.Internal.CoverMode = testCoverMode
+			var coverFiles []string
+			coverFiles = append(coverFiles, ptest.GoFiles...)
+			coverFiles = append(coverFiles, ptest.CgoFiles...)
+			ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
+		}
+	} else {
+		ptest = p
+	}
+
+	// External test package.
+	if len(p.XTestGoFiles) > 0 {
+		pxtest = &load.Package{
+			PackagePublic: load.PackagePublic{
+				Name:       p.Name + "_test",
+				ImportPath: p.ImportPath + "_test",
+				Root:       p.Root,
+				Dir:        p.Dir,
+				GoFiles:    p.XTestGoFiles,
+				Imports:    p.XTestImports,
+				Stale:      true,
+			},
+			Internal: load.PackageInternal{
+				LocalPrefix: p.Internal.LocalPrefix,
+				Build: &build.Package{
+					ImportPos: p.Internal.Build.XTestImportPos,
+				},
+				Imports:  ximports,
+				Pkgdir:   testDir,
+				Fake:     true,
+				External: true,
+			},
+		}
+		if pxtestNeedsPtest {
+			pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
+		}
+	}
+
+	// Action for building pkg.test.
+	pmain = &load.Package{
+		PackagePublic: load.PackagePublic{
+			Name:       "main",
+			Dir:        testDir,
+			GoFiles:    []string{"_testmain.go"},
+			ImportPath: "testmain",
+			Root:       p.Root,
+			Stale:      true,
+		},
+		Internal: load.PackageInternal{
+			Build:     &build.Package{Name: "main"},
+			Pkgdir:    testDir,
+			Fake:      true,
+			OmitDebug: !testC && !testNeedBinary,
+		},
+	}
+
+	// The generated main also imports testing, regexp, and os.
+	stk.Push("testmain")
+	for dep := range testMainDeps {
+		if dep == ptest.ImportPath {
+			pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
+		} else {
+			p1 := load.LoadImport(dep, "", nil, &stk, nil, 0)
+			if p1.Error != nil {
+				return nil, nil, nil, p1.Error
+			}
+			pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
+		}
+	}
+
+	if testCoverPkgs != nil {
+		// Add imports, but avoid duplicates.
+		seen := map[*load.Package]bool{p: true, ptest: true}
+		for _, p1 := range pmain.Internal.Imports {
+			seen[p1] = true
+		}
+		for _, p1 := range testCoverPkgs {
+			if !seen[p1] {
+				seen[p1] = true
+				pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
+			}
+		}
+	}
+
+	// Do initial scan for metadata needed for writing _testmain.go
+	// Use that metadata to update the list of imports for package main.
+	// The list of imports is used by recompileForTest and by the loop
+	// afterward that gathers t.Cover information.
+	t, err := loadTestFuncs(ptest)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
+		pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
+		t.ImportTest = true
+	}
+	if pxtest != nil {
+		pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
+		t.ImportXtest = true
+	}
+
+	if ptest != p && localCover {
+		// We have made modifications to the package p being tested
+		// and are rebuilding p (as ptest), writing it to the testDir tree.
+		// Arrange to rebuild, writing to that same tree, all packages q
+		// such that the test depends on q, and q depends on p.
+		// This makes sure that q sees the modifications to p.
+		// Strictly speaking, the rebuild is only necessary if the
+		// modifications to p change its export metadata, but
+		// determining that is a bit tricky, so we rebuild always.
+		//
+		// This will cause extra compilation, so for now we only do it
+		// when testCover is set. The conditions are more general, though,
+		// and we may find that we need to do it always in the future.
+		recompileForTest(pmain, p, ptest, testDir)
+	}
+
+	if cfg.BuildContext.GOOS == "darwin" {
+		if cfg.BuildContext.GOARCH == "arm" || cfg.BuildContext.GOARCH == "arm64" {
+			t.NeedCgo = true
+		}
+	}
+
+	for _, cp := range pmain.Internal.Imports {
+		if len(cp.Internal.CoverVars) > 0 {
+			t.Cover = append(t.Cover, coverInfo{cp, cp.Internal.CoverVars})
+		}
+	}
+
+	if !cfg.BuildN {
+		// writeTestmain writes _testmain.go. This must happen after recompileForTest,
+		// because recompileForTest modifies XXX.
+		if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
+			return nil, nil, nil, err
+		}
+	}
+
+	load.ComputeStale(pmain)
+
+	if ptest != p {
+		a := b.Action(work.ModeBuild, work.ModeBuild, ptest)
+		a.Objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
+		a.Objpkg = ptestObj
+		a.Target = ptestObj
+		a.Link = false
+	}
+
+	if pxtest != nil {
+		a := b.Action(work.ModeBuild, work.ModeBuild, pxtest)
+		a.Objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
+		a.Objpkg = work.BuildToolchain.Pkgpath(testDir, pxtest)
+		a.Target = a.Objpkg
+	}
+
+	a := b.Action(work.ModeBuild, work.ModeBuild, pmain)
+	a.Objdir = testDir + string(filepath.Separator)
+	a.Objpkg = filepath.Join(testDir, "main.a")
+	a.Target = filepath.Join(testDir, testBinary) + cfg.ExeSuffix
+	if cfg.Goos == "windows" {
+		// There are many reserved words on Windows that,
+		// if used in the name of an executable, cause Windows
+		// to try to ask for extra permissions.
+		// The word list includes setup, install, update, and patch,
+		// but it does not appear to be defined anywhere.
+		// We have run into this trying to run the
+		// go.codereview/patch tests.
+		// For package names containing those words, use test.test.exe
+		// instead of pkgname.test.exe.
+		// Note that this file name is only used in the Go command's
+		// temporary directory. If the -c or other flags are
+		// given, the code below will still use pkgname.test.exe.
+		// There are two user-visible effects of this change.
+		// First, you can actually run 'go test' in directories that
+		// have names that Windows thinks are installer-like,
+		// without getting a dialog box asking for more permissions.
+		// Second, in the Windows process listing during go test,
+		// the test shows up as test.test.exe, not pkgname.test.exe.
+		// That second one is a drawback, but it seems a small
+		// price to pay for the test running at all.
+		// If maintaining the list of bad words is too onerous,
+		// we could just do this always on Windows.
+		for _, bad := range windowsBadWords {
+			if strings.Contains(testBinary, bad) {
+				a.Target = filepath.Join(testDir, "test.test") + cfg.ExeSuffix
+				break
+			}
+		}
+	}
+	buildAction = a
+
+	if testC || testNeedBinary {
+		// -c or profiling flag: create action to copy binary to ./test.out.
+		target := filepath.Join(base.Cwd, testBinary+cfg.ExeSuffix)
+		if testO != "" {
+			target = testO
+			if !filepath.IsAbs(target) {
+				target = filepath.Join(base.Cwd, target)
+			}
+		}
+		buildAction = &work.Action{
+			Func:    work.BuildInstallFunc,
+			Deps:    []*work.Action{buildAction},
+			Package: pmain,
+			Target:  target,
+		}
+		runAction = buildAction // make sure runAction != nil even if not running test
+	}
+	if testC {
+		printAction = &work.Action{Package: p, Deps: []*work.Action{runAction}} // nop
+	} else {
+		// run test
+		runAction = &work.Action{
+			Func:       builderRunTest,
+			Deps:       []*work.Action{buildAction},
+			Package:    p,
+			IgnoreFail: true,
+		}
+		cleanAction := &work.Action{
+			Func:    builderCleanTest,
+			Deps:    []*work.Action{runAction},
+			Package: p,
+		}
+		printAction = &work.Action{
+			Func:    builderPrintTest,
+			Deps:    []*work.Action{cleanAction},
+			Package: p,
+		}
+	}
+
+	return buildAction, runAction, printAction, nil
+}
+
+func testImportStack(top string, p *load.Package, target string) []string {
+	stk := []string{top, p.ImportPath}
+Search:
+	for p.ImportPath != target {
+		for _, p1 := range p.Internal.Imports {
+			if p1.ImportPath == target || str.Contains(p1.Deps, target) {
+				stk = append(stk, p1.ImportPath)
+				p = p1
+				continue Search
+			}
+		}
+		// Can't happen, but in case it does...
+		stk = append(stk, "<lost path to cycle>")
+		break
+	}
+	return stk
+}
+
+func recompileForTest(pmain, preal, ptest *load.Package, testDir string) {
+	// The "test copy" of preal is ptest.
+	// For each package that depends on preal, make a "test copy"
+	// that depends on ptest. And so on, up the dependency tree.
+	testCopy := map[*load.Package]*load.Package{preal: ptest}
+	for _, p := range load.PackageList([]*load.Package{pmain}) {
+		// Copy on write.
+		didSplit := false
+		split := func() {
+			if didSplit {
+				return
+			}
+			didSplit = true
+			if p.Internal.Pkgdir != testDir {
+				p1 := new(load.Package)
+				testCopy[p] = p1
+				*p1 = *p
+				p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports))
+				copy(p1.Internal.Imports, p.Internal.Imports)
+				p = p1
+				p.Internal.Pkgdir = testDir
+				p.Internal.Target = ""
+				p.Internal.Fake = true
+				p.Stale = true
+				p.StaleReason = "depends on package being tested"
+			}
+		}
+
+		// Update p.Deps and p.Internal.Imports to use at test copies.
+		for i, dep := range p.Internal.Deps {
+			if p1 := testCopy[dep]; p1 != nil && p1 != dep {
+				split()
+				p.Internal.Deps[i] = p1
+			}
+		}
+		for i, imp := range p.Internal.Imports {
+			if p1 := testCopy[imp]; p1 != nil && p1 != imp {
+				split()
+				p.Internal.Imports[i] = p1
+			}
+		}
+	}
+}
+
+var coverIndex = 0
+
+// isTestFile reports whether the source file is a set of tests and should therefore
+// be excluded from coverage analysis.
+func isTestFile(file string) bool {
+	// We don't cover tests, only the code they test.
+	return strings.HasSuffix(file, "_test.go")
+}
+
+// declareCoverVars attaches the required cover variables names
+// to the files, to be used when annotating the files.
+func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
+	coverVars := make(map[string]*load.CoverVar)
+	for _, file := range files {
+		if isTestFile(file) {
+			continue
+		}
+		coverVars[file] = &load.CoverVar{
+			File: filepath.Join(importPath, file),
+			Var:  fmt.Sprintf("GoCover_%d", coverIndex),
+		}
+		coverIndex++
+	}
+	return coverVars
+}
+
+var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
+
+// builderRunTest is the action for running a test binary.
+func builderRunTest(b *work.Builder, a *work.Action) error {
+	args := str.StringList(work.FindExecCmd(), a.Deps[0].Target, testArgs)
+	a.TestOutput = new(bytes.Buffer)
+
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd("", "%s", strings.Join(args, " "))
+		if cfg.BuildN {
+			return nil
+		}
+	}
+
+	if a.Failed {
+		// We were unable to build the binary.
+		a.Failed = false
+		fmt.Fprintf(a.TestOutput, "FAIL\t%s [build failed]\n", a.Package.ImportPath)
+		base.SetExitStatus(1)
+		return nil
+	}
+
+	cmd := exec.Command(args[0], args[1:]...)
+	cmd.Dir = a.Package.Dir
+	cmd.Env = base.EnvForDir(cmd.Dir, cfg.OrigEnv)
+	var buf bytes.Buffer
+	if testStreamOutput {
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+	} else {
+		cmd.Stdout = &buf
+		cmd.Stderr = &buf
+	}
+
+	// If there are any local SWIG dependencies, we want to load
+	// the shared library from the build directory.
+	if a.Package.UsesSwig() {
+		env := cmd.Env
+		found := false
+		prefix := "LD_LIBRARY_PATH="
+		for i, v := range env {
+			if strings.HasPrefix(v, prefix) {
+				env[i] = v + ":."
+				found = true
+				break
+			}
+		}
+		if !found {
+			env = append(env, "LD_LIBRARY_PATH=.")
+		}
+		cmd.Env = env
+	}
+
+	t0 := time.Now()
+	err := cmd.Start()
+
+	// This is a last-ditch deadline to detect and
+	// stop wedged test binaries, to keep the builders
+	// running.
+	if err == nil {
+		tick := time.NewTimer(testKillTimeout)
+		base.StartSigHandlers()
+		done := make(chan error)
+		go func() {
+			done <- cmd.Wait()
+		}()
+	Outer:
+		select {
+		case err = <-done:
+			// ok
+		case <-tick.C:
+			if base.SignalTrace != nil {
+				// Send a quit signal in the hope that the program will print
+				// a stack trace and exit. Give it five seconds before resorting
+				// to Kill.
+				cmd.Process.Signal(base.SignalTrace)
+				select {
+				case err = <-done:
+					fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)
+					break Outer
+				case <-time.After(5 * time.Second):
+				}
+			}
+			cmd.Process.Kill()
+			err = <-done
+			fmt.Fprintf(&buf, "*** Test killed: ran too long (%v).\n", testKillTimeout)
+		}
+		tick.Stop()
+	}
+	out := buf.Bytes()
+	t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
+	if err == nil {
+		norun := ""
+		if testShowPass {
+			a.TestOutput.Write(out)
+		}
+		if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
+			norun = " [no tests to run]"
+		}
+		fmt.Fprintf(a.TestOutput, "ok  \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
+		return nil
+	}
+
+	base.SetExitStatus(1)
+	if len(out) > 0 {
+		a.TestOutput.Write(out)
+		// assume printing the test binary's exit status is superfluous
+	} else {
+		fmt.Fprintf(a.TestOutput, "%s\n", err)
+	}
+	fmt.Fprintf(a.TestOutput, "FAIL\t%s\t%s\n", a.Package.ImportPath, t)
+
+	return nil
+}
+
+// coveragePercentage returns the coverage results (if enabled) for the
+// test. It uncovers the data by scanning the output from the test run.
+func coveragePercentage(out []byte) string {
+	if !testCover {
+		return ""
+	}
+	// The string looks like
+	//	test coverage for encoding/binary: 79.9% of statements
+	// Extract the piece from the percentage to the end of the line.
+	re := regexp.MustCompile(`coverage: (.*)\n`)
+	matches := re.FindSubmatch(out)
+	if matches == nil {
+		// Probably running "go test -cover" not "go test -cover fmt".
+		// The coverage output will appear in the output directly.
+		return ""
+	}
+	return fmt.Sprintf("\tcoverage: %s", matches[1])
+}
+
+// builderCleanTest is the action for cleaning up after a test.
+func builderCleanTest(b *work.Builder, a *work.Action) error {
+	if cfg.BuildWork {
+		return nil
+	}
+	run := a.Deps[0]
+	testDir := filepath.Join(b.WorkDir, filepath.FromSlash(run.Package.ImportPath+"/_test"))
+	os.RemoveAll(testDir)
+	return nil
+}
+
+// builderPrintTest is the action for printing a test result.
+func builderPrintTest(b *work.Builder, a *work.Action) error {
+	clean := a.Deps[0]
+	run := clean.Deps[0]
+	os.Stdout.Write(run.TestOutput.Bytes())
+	run.TestOutput = nil
+	return nil
+}
+
+// builderNoTest is the action for testing a package with no test files.
+func builderNoTest(b *work.Builder, a *work.Action) error {
+	fmt.Printf("?   \t%s\t[no test files]\n", a.Package.ImportPath)
+	return 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
+	}
+	ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
+	if !ok {
+		return false
+	}
+	// 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.
+	// 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 == arg {
+		return true
+	}
+	return false
+}
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+	if !strings.HasPrefix(name, prefix) {
+		return false
+	}
+	if len(name) == len(prefix) { // "Test" is ok
+		return true
+	}
+	rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+	return !unicode.IsLower(rune)
+}
+
+type coverInfo struct {
+	Package *load.Package
+	Vars    map[string]*load.CoverVar
+}
+
+// loadTestFuncs returns the testFuncs describing the tests that will be run.
+func loadTestFuncs(ptest *load.Package) (*testFuncs, error) {
+	t := &testFuncs{
+		Package: ptest,
+	}
+	for _, file := range ptest.TestGoFiles {
+		if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
+			return nil, err
+		}
+	}
+	for _, file := range ptest.XTestGoFiles {
+		if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
+			return nil, err
+		}
+	}
+	return t, nil
+}
+
+// writeTestmain writes the _testmain.go file for t to the file named out.
+func writeTestmain(out string, t *testFuncs) error {
+	f, err := os.Create(out)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	if err := testmainTmpl.Execute(f, t); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+type testFuncs struct {
+	Tests       []testFunc
+	Benchmarks  []testFunc
+	Examples    []testFunc
+	TestMain    *testFunc
+	Package     *load.Package
+	ImportTest  bool
+	NeedTest    bool
+	ImportXtest bool
+	NeedXtest   bool
+	NeedCgo     bool
+	Cover       []coverInfo
+}
+
+func (t *testFuncs) CoverMode() string {
+	return testCoverMode
+}
+
+func (t *testFuncs) CoverEnabled() bool {
+	return testCover
+}
+
+// ImportPath returns the import path of the package being tested, if it is within GOPATH.
+// This is printed by the testing package when running benchmarks.
+func (t *testFuncs) ImportPath() string {
+	pkg := t.Package.ImportPath
+	if strings.HasPrefix(pkg, "_/") {
+		return ""
+	}
+	if pkg == "command-line-arguments" {
+		return ""
+	}
+	return pkg
+}
+
+// Covered returns a string describing which packages are being tested for coverage.
+// If the covered package is the same as the tested package, it returns the empty string.
+// Otherwise it is a comma-separated human-readable list of packages beginning with
+// " in", ready for use in the coverage message.
+func (t *testFuncs) Covered() string {
+	if testCoverPaths == nil {
+		return ""
+	}
+	return " in " + strings.Join(testCoverPaths, ", ")
+}
+
+// Tested returns the name of the package being tested.
+func (t *testFuncs) Tested() string {
+	return t.Package.Name
+}
+
+type testFunc struct {
+	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()
+
+func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
+	f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
+	if err != nil {
+		return base.ExpandScanner(err)
+	}
+	for _, d := range f.Decls {
+		n, ok := d.(*ast.FuncDecl)
+		if !ok {
+			continue
+		}
+		if n.Recv != nil {
+			continue
+		}
+		name := n.Name.String()
+		switch {
+		case name == "TestMain" && isTestFunc(n, "M"):
+			if t.TestMain != nil {
+				return errors.New("multiple definitions of TestMain")
+			}
+			t.TestMain = &testFunc{pkg, name, "", false}
+			*doImport, *seen = true, true
+		case isTest(name, "Test"):
+			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"):
+			err := checkTestFunc(n, "B")
+			if err != nil {
+				return err
+			}
+			t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
+			*doImport, *seen = true, true
+		}
+	}
+	ex := doc.Examples(f)
+	sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
+	for _, e := range ex {
+		*doImport = true // import test file whether executed or not
+		if e.Output == "" && !e.EmptyOutput {
+			// Don't run examples with no output.
+			continue
+		}
+		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
+}
+
+var testmainTmpl = template.Must(template.New("main").Parse(`
+package main
+
+import (
+{{if not .TestMain}}
+	"os"
+{{end}}
+	"testing"
+	"testing/internal/testdeps"
+
+{{if .ImportTest}}
+	{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
+{{end}}
+{{if .ImportXtest}}
+	{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
+{{end}}
+{{range $i, $p := .Cover}}
+	_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
+{{end}}
+
+{{if .NeedCgo}}
+	_ "runtime/cgo"
+{{end}}
+)
+
+var tests = []testing.InternalTest{
+{{range .Tests}}
+	{"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var benchmarks = []testing.InternalBenchmark{
+{{range .Benchmarks}}
+	{"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var examples = []testing.InternalExample{
+{{range .Examples}}
+	{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
+{{end}}
+}
+
+func init() {
+	testdeps.ImportPath = {{.ImportPath | printf "%q"}}
+}
+
+{{if .CoverEnabled}}
+
+// Only updated by init functions, so no need for atomicity.
+var (
+	coverCounters = make(map[string][]uint32)
+	coverBlocks = make(map[string][]testing.CoverBlock)
+)
+
+func init() {
+	{{range $i, $p := .Cover}}
+	{{range $file, $cover := $p.Vars}}
+	coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
+	{{end}}
+	{{end}}
+}
+
+func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
+	if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
+		panic("coverage: mismatched sizes")
+	}
+	if coverCounters[fileName] != nil {
+		// Already registered.
+		return
+	}
+	coverCounters[fileName] = counter
+	block := make([]testing.CoverBlock, len(counter))
+	for i := range counter {
+		block[i] = testing.CoverBlock{
+			Line0: pos[3*i+0],
+			Col0: uint16(pos[3*i+2]),
+			Line1: pos[3*i+1],
+			Col1: uint16(pos[3*i+2]>>16),
+			Stmts: numStmts[i],
+		}
+	}
+	coverBlocks[fileName] = block
+}
+{{end}}
+
+func main() {
+{{if .CoverEnabled}}
+	testing.RegisterCover(testing.Cover{
+		Mode: {{printf "%q" .CoverMode}},
+		Counters: coverCounters,
+		Blocks: coverBlocks,
+		CoveredPackages: {{printf "%q" .Covered}},
+	})
+{{end}}
+	m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
+{{with .TestMain}}
+	{{.Package}}.{{.Name}}(m)
+{{else}}
+	os.Exit(m.Run())
+{{end}}
+}
+
+`))
diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go
new file mode 100644
index 0000000..bff8656
--- /dev/null
+++ b/src/cmd/go/internal/test/testflag.go
@@ -0,0 +1,211 @@
+// Copyright 2011 The Go Authors. 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 (
+	"flag"
+	"os"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/cmdflag"
+	"cmd/go/internal/str"
+	"cmd/go/internal/work"
+)
+
+const cmd = "test"
+
+// The flag handling part of go test is large and distracting.
+// We can't use the flag package because some of the flags from
+// our command line are for us, and some are for 6.out, and
+// some are for both.
+
+// testFlagDefn is the set of flags we process.
+var testFlagDefn = []*cmdflag.Defn{
+	// local.
+	{Name: "c", BoolVar: &testC},
+	{Name: "i", BoolVar: &cfg.BuildI},
+	{Name: "o"},
+	{Name: "cover", BoolVar: &testCover},
+	{Name: "covermode"},
+	{Name: "coverpkg"},
+	{Name: "exec"},
+
+	// Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
+	{Name: "bench", PassToTest: true},
+	{Name: "benchmem", BoolVar: new(bool), PassToTest: true},
+	{Name: "benchtime", PassToTest: true},
+	{Name: "count", PassToTest: true},
+	{Name: "coverprofile", PassToTest: true},
+	{Name: "cpu", PassToTest: true},
+	{Name: "cpuprofile", PassToTest: true},
+	{Name: "list", PassToTest: true},
+	{Name: "memprofile", PassToTest: true},
+	{Name: "memprofilerate", PassToTest: true},
+	{Name: "blockprofile", PassToTest: true},
+	{Name: "blockprofilerate", PassToTest: true},
+	{Name: "mutexprofile", PassToTest: true},
+	{Name: "mutexprofilefraction", PassToTest: true},
+	{Name: "outputdir", PassToTest: true},
+	{Name: "parallel", PassToTest: true},
+	{Name: "run", PassToTest: true},
+	{Name: "short", BoolVar: new(bool), PassToTest: true},
+	{Name: "timeout", PassToTest: true},
+	{Name: "trace", PassToTest: true},
+	{Name: "v", BoolVar: &testV, PassToTest: true},
+}
+
+// add build flags to testFlagDefn
+func init() {
+	var cmd base.Command
+	work.AddBuildFlags(&cmd)
+	cmd.Flag.VisitAll(func(f *flag.Flag) {
+		if f.Name == "v" {
+			// test overrides the build -v flag
+			return
+		}
+		testFlagDefn = append(testFlagDefn, &cmdflag.Defn{
+			Name:  f.Name,
+			Value: f.Value,
+		})
+	})
+}
+
+// testFlags processes the command line, grabbing -x and -c, rewriting known flags
+// to have "test" before them, and reading the command line for the 6.out.
+// Unfortunately for us, we need to do our own flag processing because go test
+// grabs some flags but otherwise its command line is just a holding place for
+// pkg.test's arguments.
+// We allow known flags both before and after the package name list,
+// to allow both
+//	go test fmt -custom-flag-for-fmt-test
+//	go test -x math
+func testFlags(args []string) (packageNames, passToTest []string) {
+	inPkg := false
+	outputDir := ""
+	var explicitArgs []string
+	for i := 0; i < len(args); i++ {
+		if !strings.HasPrefix(args[i], "-") {
+			if !inPkg && packageNames == nil {
+				// First package name we've seen.
+				inPkg = true
+			}
+			if inPkg {
+				packageNames = append(packageNames, args[i])
+				continue
+			}
+		}
+
+		if inPkg {
+			// Found an argument beginning with "-"; end of package list.
+			inPkg = false
+		}
+
+		f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i)
+		if f == nil {
+			// This is a flag we do not know; we must assume
+			// that any args we see after this might be flag
+			// arguments, not package names.
+			inPkg = false
+			if packageNames == nil {
+				// make non-nil: we have seen the empty package list
+				packageNames = []string{}
+			}
+			if args[i] == "-args" || args[i] == "--args" {
+				// -args or --args signals that everything that follows
+				// should be passed to the test.
+				explicitArgs = args[i+1:]
+				break
+			}
+			passToTest = append(passToTest, args[i])
+			continue
+		}
+		if f.Value != nil {
+			if err := f.Value.Set(value); err != nil {
+				base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
+			}
+		} else {
+			// Test-only flags.
+			// Arguably should be handled by f.Value, but aren't.
+			switch f.Name {
+			// bool flags.
+			case "c", "i", "v", "cover":
+				cmdflag.SetBool(cmd, f.BoolVar, value)
+			case "o":
+				testO = value
+				testNeedBinary = true
+			case "exec":
+				xcmd, err := str.SplitQuotedFields(value)
+				if err != nil {
+					base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
+				}
+				work.ExecCmd = xcmd
+			case "bench":
+				// record that we saw the flag; don't care about the value
+				testBench = true
+			case "list":
+				testList = true
+			case "timeout":
+				testTimeout = value
+			case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
+				testProfile = true
+				testNeedBinary = true
+			case "trace":
+				testProfile = true
+			case "coverpkg":
+				testCover = true
+				if value == "" {
+					testCoverPaths = nil
+				} else {
+					testCoverPaths = strings.Split(value, ",")
+				}
+			case "coverprofile":
+				testCover = true
+				testProfile = true
+			case "covermode":
+				switch value {
+				case "set", "count", "atomic":
+					testCoverMode = value
+				default:
+					base.Fatalf("invalid flag argument for -covermode: %q", value)
+				}
+				testCover = true
+			case "outputdir":
+				outputDir = value
+			}
+		}
+		if extraWord {
+			i++
+		}
+		if f.PassToTest {
+			passToTest = append(passToTest, "-test."+f.Name+"="+value)
+		}
+	}
+
+	if testCoverMode == "" {
+		testCoverMode = "set"
+		if cfg.BuildRace {
+			// Default coverage mode is atomic when -race is set.
+			testCoverMode = "atomic"
+		}
+	}
+
+	if cfg.BuildRace && testCoverMode != "atomic" {
+		base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode)
+	}
+
+	// Tell the test what directory we're running in, so it can write the profiles there.
+	if testProfile && outputDir == "" {
+		dir, err := os.Getwd()
+		if err != nil {
+			base.Fatalf("error from os.Getwd: %s", err)
+		}
+		passToTest = append(passToTest, "-test.outputdir", dir)
+	}
+
+	passToTest = append(passToTest, explicitArgs...)
+	return
+}
diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go
new file mode 100644
index 0000000..5167526
--- /dev/null
+++ b/src/cmd/go/internal/tool/tool.go
@@ -0,0 +1,119 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tool implements the ``go tool'' command.
+package tool
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"sort"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+)
+
+var CmdTool = &base.Command{
+	Run:       runTool,
+	UsageLine: "tool [-n] command [args...]",
+	Short:     "run specified go tool",
+	Long: `
+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'.
+`,
+}
+
+var toolN bool
+
+func init() {
+	CmdTool.Flag.BoolVar(&toolN, "n", false, "")
+}
+
+func runTool(cmd *base.Command, args []string) {
+	if len(args) == 0 {
+		listTools()
+		return
+	}
+	toolName := args[0]
+	// The tool name must be lower-case letters, numbers or underscores.
+	for _, c := range toolName {
+		switch {
+		case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
+		default:
+			fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
+			base.SetExitStatus(2)
+			return
+		}
+	}
+	toolPath := base.Tool(toolName)
+	if toolPath == "" {
+		return
+	}
+	if toolN {
+		cmd := toolPath
+		if len(args) > 1 {
+			cmd += " " + strings.Join(args[1:], " ")
+		}
+		fmt.Printf("%s\n", cmd)
+		return
+	}
+	args[0] = toolPath // in case the tool wants to re-exec itself, e.g. cmd/dist
+	toolCmd := &exec.Cmd{
+		Path:   toolPath,
+		Args:   args,
+		Stdin:  os.Stdin,
+		Stdout: os.Stdout,
+		Stderr: os.Stderr,
+		// Set $GOROOT, mainly for go tool dist.
+		Env: base.MergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()),
+	}
+	err := toolCmd.Run()
+	if err != nil {
+		// Only print about the exit status if the command
+		// didn't even run (not an ExitError) or it didn't exit cleanly
+		// or we're printing command lines too (-x mode).
+		// Assume if command exited cleanly (even with non-zero status)
+		// it printed any messages it wanted to print.
+		if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX {
+			fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
+		}
+		base.SetExitStatus(1)
+		return
+	}
+}
+
+// listTools prints a list of the available tools in the tools directory.
+func listTools() {
+	f, err := os.Open(base.ToolDir)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
+		base.SetExitStatus(2)
+		return
+	}
+	defer f.Close()
+	names, err := f.Readdirnames(-1)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
+		base.SetExitStatus(2)
+		return
+	}
+
+	sort.Strings(names)
+	for _, name := range names {
+		// Unify presentation by going to lower case.
+		name = strings.ToLower(name)
+		// If it's windows, don't show the .exe suffix.
+		if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) {
+			name = name[:len(name)-len(base.ToolWindowsExtension)]
+		}
+		fmt.Println(name)
+	}
+}
diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go
new file mode 100644
index 0000000..c3f7d73
--- /dev/null
+++ b/src/cmd/go/internal/version/version.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.
+
+// Package version implements the ``go version'' command.
+package version
+
+import (
+	"fmt"
+	"runtime"
+
+	"cmd/go/internal/base"
+)
+
+var CmdVersion = &base.Command{
+	Run:       runVersion,
+	UsageLine: "version",
+	Short:     "print Go version",
+	Long:      `Version prints the Go version, as reported by runtime.Version.`,
+}
+
+func runVersion(cmd *base.Command, args []string) {
+	if len(args) != 0 {
+		cmd.Usage()
+	}
+
+	fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
+}
diff --git a/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go
new file mode 100644
index 0000000..ddacd08
--- /dev/null
+++ b/src/cmd/go/internal/vet/vet.go
@@ -0,0 +1,56 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package vet implements the ``go vet'' command.
+package vet
+
+import (
+	"path/filepath"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+)
+
+var CmdVet = &base.Command{
+	Run:         runVet,
+	CustomFlags: true,
+	UsageLine:   "vet [-n] [-x] [build flags] [vet flags] [packages]",
+	Short:       "run go tool vet on packages",
+	Long: `
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet and its flags, see 'go doc cmd/vet'.
+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.
+
+For more about build flags, see 'go help build'.
+
+See also: go fmt, go fix.
+	`,
+}
+
+func runVet(cmd *base.Command, args []string) {
+	vetFlags, packages := vetFlags(args)
+	for _, p := range load.Packages(packages) {
+		// Vet expects to be given a set of files all from the same package.
+		// Run once for package p and once for package p_test.
+		if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
+			runVetFiles(p, vetFlags, str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
+		}
+		if len(p.XTestGoFiles) > 0 {
+			runVetFiles(p, vetFlags, str.StringList(p.XTestGoFiles))
+		}
+	}
+}
+
+func runVetFiles(p *load.Package, flags, files []string) {
+	for i := range files {
+		files[i] = filepath.Join(p.Dir, files[i])
+	}
+	base.Run(cfg.BuildToolexec, base.Tool("vet"), flags, base.RelPaths(files))
+}
diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go
new file mode 100644
index 0000000..8cd21bb
--- /dev/null
+++ b/src/cmd/go/internal/vet/vetflag.go
@@ -0,0 +1,99 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vet
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cmdflag"
+	"cmd/go/internal/work"
+)
+
+const cmd = "vet"
+
+// vetFlagDefn is the set of flags we process.
+var vetFlagDefn = []*cmdflag.Defn{
+	// Note: Some flags, in particular -tags and -v, are known to
+	// vet but also defined as build flags. This works fine, so we
+	// don't define them here but use AddBuildFlags to init them.
+	// However some, like -x, are known to the build but not
+	// to vet. We handle them in vetFlags.
+
+	// local.
+	{Name: "all", BoolVar: new(bool)},
+	{Name: "asmdecl", BoolVar: new(bool)},
+	{Name: "assign", BoolVar: new(bool)},
+	{Name: "atomic", BoolVar: new(bool)},
+	{Name: "bool", BoolVar: new(bool)},
+	{Name: "buildtags", BoolVar: new(bool)},
+	{Name: "cgocall", BoolVar: new(bool)},
+	{Name: "composites", BoolVar: new(bool)},
+	{Name: "copylocks", BoolVar: new(bool)},
+	{Name: "httpresponse", BoolVar: new(bool)},
+	{Name: "lostcancel", BoolVar: new(bool)},
+	{Name: "methods", BoolVar: new(bool)},
+	{Name: "nilfunc", BoolVar: new(bool)},
+	{Name: "printf", BoolVar: new(bool)},
+	{Name: "printfuncs"},
+	{Name: "rangeloops", BoolVar: new(bool)},
+	{Name: "shadow", BoolVar: new(bool)},
+	{Name: "shadowstrict", BoolVar: new(bool)},
+	{Name: "source", BoolVar: new(bool)},
+	{Name: "structtags", BoolVar: new(bool)},
+	{Name: "tests", BoolVar: new(bool)},
+	{Name: "unreachable", BoolVar: new(bool)},
+	{Name: "unsafeptr", BoolVar: new(bool)},
+	{Name: "unusedfuncs"},
+	{Name: "unusedresult", BoolVar: new(bool)},
+	{Name: "unusedstringmethods"},
+}
+
+// add build flags to vetFlagDefn.
+func init() {
+	var cmd base.Command
+	work.AddBuildFlags(&cmd)
+	cmd.Flag.VisitAll(func(f *flag.Flag) {
+		vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
+			Name:  f.Name,
+			Value: f.Value,
+		})
+	})
+}
+
+// vetFlags processes the command line, splitting it at the first non-flag
+// into the list of flags and list of packages.
+func vetFlags(args []string) (passToVet, packageNames []string) {
+	for i := 0; i < len(args); i++ {
+		if !strings.HasPrefix(args[i], "-") {
+			return args[:i], args[i:]
+		}
+
+		f, value, extraWord := cmdflag.Parse(cmd, vetFlagDefn, args, i)
+		if f == nil {
+			fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
+			fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
+			os.Exit(2)
+		}
+		if f.Value != nil {
+			if err := f.Value.Set(value); err != nil {
+				base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
+			}
+			switch f.Name {
+			// Flags known to the build but not to vet, so must be dropped.
+			case "x", "n":
+				args = append(args[:i], args[i+1:]...)
+				i--
+			}
+		}
+		if extraWord {
+			i++
+		}
+	}
+	return args, nil
+}
diff --git a/src/cmd/go/internal/web/bootstrap.go b/src/cmd/go/internal/web/bootstrap.go
new file mode 100644
index 0000000..d1d4621
--- /dev/null
+++ b/src/cmd/go/internal/web/bootstrap.go
@@ -0,0 +1,37 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cmd_go_bootstrap
+
+// This code is compiled only into the bootstrap 'go' binary.
+// These stubs avoid importing packages with large dependency
+// trees, like the use of "net/http" in vcs.go.
+
+package web
+
+import (
+	"errors"
+	"io"
+)
+
+var errHTTP = errors.New("no http in bootstrap go command")
+
+type HTTPError struct {
+	StatusCode int
+}
+
+func (e *HTTPError) Error() string {
+	panic("unreachable")
+}
+
+func Get(url string) ([]byte, error) {
+	return nil, errHTTP
+}
+
+func GetMaybeInsecure(importPath string, security SecurityMode) (string, io.ReadCloser, error) {
+	return "", nil, errHTTP
+}
+
+func QueryEscape(s string) string { panic("unreachable") }
+func OpenBrowser(url string) bool { panic("unreachable") }
diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go
new file mode 100644
index 0000000..6e347fb
--- /dev/null
+++ b/src/cmd/go/internal/web/http.go
@@ -0,0 +1,122 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package web
+
+import (
+	"crypto/tls"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"time"
+
+	"cmd/go/internal/cfg"
+	"cmd/internal/browser"
+)
+
+// httpClient is the default HTTP client, but a variable so it can be
+// changed by tests, without modifying http.DefaultClient.
+var httpClient = http.DefaultClient
+
+// impatientInsecureHTTPClient is used in -insecure mode,
+// when we're connecting to https servers that might not be there
+// or might be using self-signed certificates.
+var impatientInsecureHTTPClient = &http.Client{
+	Timeout: 5 * time.Second,
+	Transport: &http.Transport{
+		Proxy: http.ProxyFromEnvironment,
+		TLSClientConfig: &tls.Config{
+			InsecureSkipVerify: true,
+		},
+	},
+}
+
+type HTTPError struct {
+	status     string
+	StatusCode int
+	url        string
+}
+
+func (e *HTTPError) Error() string {
+	return fmt.Sprintf("%s: %s", e.url, e.status)
+}
+
+// Get returns the data from an HTTP GET request for the given URL.
+func Get(url string) ([]byte, error) {
+	resp, err := httpClient.Get(url)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		err := &HTTPError{status: resp.Status, StatusCode: resp.StatusCode, url: url}
+
+		return nil, err
+	}
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, fmt.Errorf("%s: %v", url, err)
+	}
+	return b, nil
+}
+
+// GetMaybeInsecure returns the body of either the importPath's
+// https resource or, if unavailable and permitted by the security mode, the http resource.
+func GetMaybeInsecure(importPath string, security SecurityMode) (urlStr string, body io.ReadCloser, err error) {
+	fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
+		u, err := url.Parse(scheme + "://" + importPath)
+		if err != nil {
+			return "", nil, err
+		}
+		u.RawQuery = "go-get=1"
+		urlStr = u.String()
+		if cfg.BuildV {
+			log.Printf("Fetching %s", urlStr)
+		}
+		if security == Insecure && scheme == "https" { // fail earlier
+			res, err = impatientInsecureHTTPClient.Get(urlStr)
+		} else {
+			res, err = httpClient.Get(urlStr)
+		}
+		return
+	}
+	closeBody := func(res *http.Response) {
+		if res != nil {
+			res.Body.Close()
+		}
+	}
+	urlStr, res, err := fetch("https")
+	if err != nil {
+		if cfg.BuildV {
+			log.Printf("https fetch failed: %v", err)
+		}
+		if security == Insecure {
+			closeBody(res)
+			urlStr, res, err = fetch("http")
+		}
+	}
+	if err != nil {
+		closeBody(res)
+		return "", nil, err
+	}
+	// Note: accepting a non-200 OK here, so people can serve a
+	// meta import in their http 404 page.
+	if cfg.BuildV {
+		log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
+	}
+	return urlStr, res.Body, nil
+}
+
+func QueryEscape(s string) string { return url.QueryEscape(s) }
+func OpenBrowser(url string) bool { return browser.Open(url) }
diff --git a/src/cmd/go/internal/web/security.go b/src/cmd/go/internal/web/security.go
new file mode 100644
index 0000000..1dc6f1b
--- /dev/null
+++ b/src/cmd/go/internal/web/security.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package web defines helper routines for accessing HTTP/HTTPS resources.
+package web
+
+// SecurityMode specifies whether a function should make network
+// calls using insecure transports (eg, plain text HTTP).
+// The zero value is "secure".
+type SecurityMode int
+
+const (
+	Secure SecurityMode = iota
+	Insecure
+)
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
new file mode 100644
index 0000000..20f3952
--- /dev/null
+++ b/src/cmd/go/internal/work/build.go
@@ -0,0 +1,3865 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package work
+
+import (
+	"bufio"
+	"bytes"
+	"container/heap"
+	"debug/elf"
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/buildid"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+	"cmd/go/internal/str"
+)
+
+var CmdBuild = &base.Command{
+	UsageLine: "build [-o output] [-i] [build flags] [packages]",
+	Short:     "compile packages and dependencies",
+	Long: `
+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 space-separated 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>'.
+
+All the flags that take a list of arguments 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.
+	`,
+}
+
+const concurrentGCBackendCompilationEnabledByDefault = true
+
+func init() {
+	// break init cycle
+	CmdBuild.Run = runBuild
+	CmdInstall.Run = runInstall
+
+	CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "")
+	CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file")
+
+	AddBuildFlags(CmdBuild)
+	AddBuildFlags(CmdInstall)
+}
+
+// Note that flags consulted by other parts of the code
+// (for example, buildV) are in cmd/go/internal/cfg.
+
+var buildAsmflags []string   // -asmflags flag
+var buildGcflags []string    // -gcflags flag
+var buildGccgoflags []string // -gccgoflags flag
+
+var BuildToolchain toolchain = noToolchain{}
+var ldBuildmode string
+
+// buildCompiler implements flag.Var.
+// It implements Set by updating both
+// BuildToolchain and buildContext.Compiler.
+type buildCompiler struct{}
+
+func (c buildCompiler) Set(value string) error {
+	switch value {
+	case "gc":
+		BuildToolchain = gcToolchain{}
+	case "gccgo":
+		BuildToolchain = gccgoToolchain{}
+	default:
+		return fmt.Errorf("unknown compiler %q", value)
+	}
+	cfg.BuildToolchainName = value
+	cfg.BuildToolchainCompiler = BuildToolchain.compiler
+	cfg.BuildToolchainLinker = BuildToolchain.linker
+	cfg.BuildContext.Compiler = value
+	return nil
+}
+
+func (c buildCompiler) String() string {
+	return cfg.BuildContext.Compiler
+}
+
+func init() {
+	switch build.Default.Compiler {
+	case "gc", "gccgo":
+		buildCompiler{}.Set(build.Default.Compiler)
+	}
+}
+
+// addBuildFlags adds the flags common to the build, clean, get,
+// install, list, run, and test commands.
+func AddBuildFlags(cmd *base.Command) {
+	cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "")
+	cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "")
+	cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "")
+	cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+	cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "")
+
+	cmd.Flag.Var((*base.StringsFlag)(&buildAsmflags), "asmflags", "")
+	cmd.Flag.Var(buildCompiler{}, "compiler", "")
+	cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "")
+	cmd.Flag.Var((*base.StringsFlag)(&buildGcflags), "gcflags", "")
+	cmd.Flag.Var((*base.StringsFlag)(&buildGccgoflags), "gccgoflags", "")
+	cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
+	cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildLdflags), "ldflags", "")
+	cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "")
+	cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
+	cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
+	cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")
+	cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
+	cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
+	cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
+}
+
+// fileExtSplit expects a filename and returns the name
+// and ext (without the dot). If the file has no
+// extension, ext will be empty.
+func fileExtSplit(file string) (name, ext string) {
+	dotExt := filepath.Ext(file)
+	name = file[:len(file)-len(dotExt)]
+	if dotExt != "" {
+		ext = dotExt[1:]
+	}
+	return
+}
+
+func pkgsMain(pkgs []*load.Package) (res []*load.Package) {
+	for _, p := range pkgs {
+		if p.Name == "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) {
+	for _, p := range pkgs {
+		if p.Name != "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+func oneMainPkg(pkgs []*load.Package) []*load.Package {
+	if len(pkgs) != 1 || pkgs[0].Name != "main" {
+		base.Fatalf("-buildmode=%s requires exactly one main package", cfg.BuildBuildmode)
+	}
+	return pkgs
+}
+
+var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
+
+func BuildModeInit() {
+	gccgo := cfg.BuildToolchainName == "gccgo"
+	var codegenArg string
+	platform := cfg.Goos + "/" + cfg.Goarch
+	switch cfg.BuildBuildmode {
+	case "archive":
+		pkgsFilter = pkgsNotMain
+	case "c-archive":
+		pkgsFilter = oneMainPkg
+		switch platform {
+		case "darwin/arm", "darwin/arm64":
+			codegenArg = "-shared"
+		default:
+			switch cfg.Goos {
+			case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+				// Use -shared so that the result is
+				// suitable for inclusion in a PIE or
+				// shared library.
+				codegenArg = "-shared"
+			}
+		}
+		cfg.ExeSuffix = ".a"
+		ldBuildmode = "c-archive"
+	case "c-shared":
+		pkgsFilter = pkgsMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
+				"android/amd64", "android/arm", "android/arm64", "android/386":
+				codegenArg = "-shared"
+			case "darwin/amd64", "darwin/386":
+			default:
+				base.Fatalf("-buildmode=c-shared not supported on %s\n", platform)
+			}
+		}
+		ldBuildmode = "c-shared"
+	case "default":
+		switch platform {
+		case "android/arm", "android/arm64", "android/amd64", "android/386":
+			codegenArg = "-shared"
+			ldBuildmode = "pie"
+		case "darwin/arm", "darwin/arm64":
+			codegenArg = "-shared"
+			fallthrough
+		default:
+			ldBuildmode = "exe"
+		}
+	case "exe":
+		pkgsFilter = pkgsMain
+		ldBuildmode = "exe"
+	case "pie":
+		if cfg.BuildRace {
+			base.Fatalf("-buildmode=pie not supported when -race is enabled")
+		}
+		if gccgo {
+			base.Fatalf("-buildmode=pie not supported by gccgo")
+		} else {
+			switch platform {
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
+				"android/amd64", "android/arm", "android/arm64", "android/386":
+				codegenArg = "-shared"
+			default:
+				base.Fatalf("-buildmode=pie not supported on %s\n", platform)
+			}
+		}
+		ldBuildmode = "pie"
+	case "shared":
+		pkgsFilter = pkgsNotMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
+			default:
+				base.Fatalf("-buildmode=shared not supported on %s\n", platform)
+			}
+			codegenArg = "-dynlink"
+		}
+		if cfg.BuildO != "" {
+			base.Fatalf("-buildmode=shared and -o not supported together")
+		}
+		ldBuildmode = "shared"
+	case "plugin":
+		pkgsFilter = oneMainPkg
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x",
+				"android/amd64", "android/arm", "android/arm64", "android/386":
+			default:
+				base.Fatalf("-buildmode=plugin not supported on %s\n", platform)
+			}
+			codegenArg = "-dynlink"
+		}
+		cfg.ExeSuffix = ".so"
+		ldBuildmode = "plugin"
+	default:
+		base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
+	}
+	if cfg.BuildLinkshared {
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
+				buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1")
+			default:
+				base.Fatalf("-linkshared not supported on %s\n", platform)
+			}
+			codegenArg = "-dynlink"
+			// TODO(mwhudson): remove -w when that gets fixed in linker.
+			cfg.BuildLdflags = append(cfg.BuildLdflags, "-linkshared", "-w")
+		}
+	}
+	if codegenArg != "" {
+		if gccgo {
+			buildGccgoflags = append([]string{codegenArg}, buildGccgoflags...)
+		} else {
+			buildAsmflags = append([]string{codegenArg}, buildAsmflags...)
+			buildGcflags = append([]string{codegenArg}, buildGcflags...)
+		}
+		// Don't alter InstallSuffix when modifying default codegen args.
+		if cfg.BuildBuildmode != "default" || cfg.BuildLinkshared {
+			if cfg.BuildContext.InstallSuffix != "" {
+				cfg.BuildContext.InstallSuffix += "_"
+			}
+			cfg.BuildContext.InstallSuffix += codegenArg[1:]
+		}
+	}
+	if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
+		buildGcflags = append(buildGcflags, "-goversion", runtimeVersion)
+	}
+}
+
+var runtimeVersion = runtime.Version()
+
+func runBuild(cmd *base.Command, args []string) {
+	InstrumentInit()
+	BuildModeInit()
+	var b Builder
+	b.Init()
+
+	pkgs := load.PackagesForBuild(args)
+
+	if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
+		_, cfg.BuildO = path.Split(pkgs[0].ImportPath)
+		cfg.BuildO += cfg.ExeSuffix
+	}
+
+	// Special case -o /dev/null by not writing at all.
+	if cfg.BuildO == os.DevNull {
+		cfg.BuildO = ""
+	}
+
+	// sanity check some often mis-used options
+	switch cfg.BuildContext.Compiler {
+	case "gccgo":
+		if len(buildGcflags) != 0 {
+			fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags")
+		}
+		if len(cfg.BuildLdflags) != 0 {
+			fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags")
+		}
+	case "gc":
+		if len(buildGccgoflags) != 0 {
+			fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags")
+		}
+	}
+
+	depMode := ModeBuild
+	if cfg.BuildI {
+		depMode = ModeInstall
+	}
+
+	if cfg.BuildO != "" {
+		if len(pkgs) > 1 {
+			base.Fatalf("go build: cannot use -o with multiple packages")
+		} else if len(pkgs) == 0 {
+			base.Fatalf("no packages to build")
+		}
+		p := pkgs[0]
+		p.Internal.Target = cfg.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
+	}
+
+	pkgs = pkgsFilter(load.Packages(args))
+
+	var a *Action
+	if cfg.BuildBuildmode == "shared" {
+		if libName, err := libname(args, pkgs); err != nil {
+			base.Fatalf("%s", err.Error())
+		} else {
+			a = b.libaction(libName, pkgs, ModeBuild, depMode)
+		}
+	} else {
+		a = &Action{}
+		for _, p := range pkgs {
+			a.Deps = append(a.Deps, b.Action(ModeBuild, depMode, p))
+		}
+	}
+	b.Do(a)
+}
+
+var CmdInstall = &base.Command{
+	UsageLine: "install [build flags] [packages]",
+	Short:     "compile and install packages and dependencies",
+	Long: `
+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.
+	`,
+}
+
+// libname returns the filename to use for the shared library when using
+// -buildmode=shared. The rules we use are:
+// Use arguments for special 'meta' packages:
+//	std --> libstd.so
+//	std cmd --> libstd,cmd.so
+// A single non-meta argument with trailing "/..." is special cased:
+//	foo/... --> libfoo.so
+//	(A relative path like "./..."  expands the "." first)
+// Use import paths for other cases, changing '/' to '-':
+//	somelib --> libsubdir-somelib.so
+//	./ or ../ --> libsubdir-somelib.so
+//	gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
+//	a/... b/... ---> liba/c,b/d.so - all matching import paths
+// Name parts are joined with ','.
+func libname(args []string, pkgs []*load.Package) (string, error) {
+	var libname string
+	appendName := func(arg string) {
+		if libname == "" {
+			libname = arg
+		} else {
+			libname += "," + arg
+		}
+	}
+	var haveNonMeta bool
+	for _, arg := range args {
+		if load.IsMetaPackage(arg) {
+			appendName(arg)
+		} else {
+			haveNonMeta = true
+		}
+	}
+	if len(libname) == 0 { // non-meta packages only. use import paths
+		if len(args) == 1 && strings.HasSuffix(args[0], "/...") {
+			// Special case of "foo/..." as mentioned above.
+			arg := strings.TrimSuffix(args[0], "/...")
+			if build.IsLocalImport(arg) {
+				cwd, _ := os.Getwd()
+				bp, _ := cfg.BuildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+				if bp.ImportPath != "" && bp.ImportPath != "." {
+					arg = bp.ImportPath
+				}
+			}
+			appendName(strings.Replace(arg, "/", "-", -1))
+		} else {
+			for _, pkg := range pkgs {
+				appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
+			}
+		}
+	} else if haveNonMeta { // have both meta package and a non-meta one
+		return "", errors.New("mixing of meta and non-meta packages is not allowed")
+	}
+	// TODO(mwhudson): Needs to change for platforms that use different naming
+	// conventions...
+	return "lib" + libname + ".so", nil
+}
+
+func runInstall(cmd *base.Command, args []string) {
+	InstrumentInit()
+	BuildModeInit()
+	InstallPackages(args, false)
+}
+
+func InstallPackages(args []string, forGet bool) {
+	if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) {
+		base.Fatalf("cannot install, GOBIN must be an absolute path")
+	}
+
+	pkgs := pkgsFilter(load.PackagesForBuild(args))
+
+	for _, p := range pkgs {
+		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
+			switch {
+			case p.Internal.GobinSubdir:
+				base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
+			case p.Internal.Cmdline:
+				base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
+			case p.ConflictDir != "":
+				base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
+			default:
+				base.Errorf("go install: no install location for directory %s outside GOPATH\n"+
+					"\tFor more details see: 'go help gopath'", p.Dir)
+			}
+		}
+	}
+	base.ExitIfErrors()
+
+	var b Builder
+	b.Init()
+	// Set the behavior for `go get` to not error on packages with test files only.
+	b.testFilesOnlyOK = forGet
+	var a *Action
+	if cfg.BuildBuildmode == "shared" {
+		if libName, err := libname(args, pkgs); err != nil {
+			base.Fatalf("%s", err.Error())
+		} else {
+			a = b.libaction(libName, pkgs, ModeInstall, ModeInstall)
+		}
+	} else {
+		a = &Action{}
+		var tools []*Action
+		for _, p := range pkgs {
+			// If p is a tool, delay the installation until the end of the build.
+			// This avoids installing assemblers/compilers that are being executed
+			// by other steps in the build.
+			// cmd/cgo is handled specially in b.Action, so that we can
+			// both build and use it in the same 'go install'.
+			Action := b.Action(ModeInstall, ModeInstall, p)
+			if load.GoTools[p.ImportPath] == load.ToTool && p.ImportPath != "cmd/cgo" {
+				a.Deps = append(a.Deps, Action.Deps...)
+				Action.Deps = append(Action.Deps, a)
+				tools = append(tools, Action)
+				continue
+			}
+			a.Deps = append(a.Deps, Action)
+		}
+		if len(tools) > 0 {
+			a = &Action{
+				Deps: tools,
+			}
+		}
+	}
+	b.Do(a)
+	base.ExitIfErrors()
+
+	// Success. If this command is 'go install' with no arguments
+	// and the current directory (the implicit argument) is a command,
+	// remove any leftover command binary from a previous 'go build'.
+	// The binary is installed; it's not needed here anymore.
+	// And worse it might be a stale copy, which you don't want to find
+	// instead of the installed one if $PATH contains dot.
+	// One way to view this behavior is that it is as if 'go install' first
+	// runs 'go build' and the moves the generated file to the install dir.
+	// See issue 9645.
+	if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
+		// Compute file 'go build' would have created.
+		// If it exists and is an executable file, remove it.
+		_, targ := filepath.Split(pkgs[0].ImportPath)
+		targ += cfg.ExeSuffix
+		if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
+			fi, err := os.Stat(targ)
+			if err == nil {
+				m := fi.Mode()
+				if m.IsRegular() {
+					if m&0111 != 0 || cfg.Goos == "windows" { // windows never sets executable bit
+						os.Remove(targ)
+					}
+				}
+			}
+		}
+	}
+}
+
+func init() {
+	cfg.Goarch = cfg.BuildContext.GOARCH
+	cfg.Goos = cfg.BuildContext.GOOS
+
+	if cfg.Goos == "windows" {
+		cfg.ExeSuffix = ".exe"
+	}
+	cfg.Gopath = filepath.SplitList(cfg.BuildContext.GOPATH)
+}
+
+// A Builder holds global state about a build.
+// It does not hold per-package state, because we
+// build packages in parallel, and the builder is shared.
+type Builder struct {
+	WorkDir     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)
+
+	testFilesOnlyOK bool // do not error if the packages only have test files
+
+	output    sync.Mutex
+	scriptDir string // current directory in printed script
+
+	exec      sync.Mutex
+	readySema chan bool
+	ready     actionQueue
+}
+
+// NOTE: Much of Action would not need to be exported if not for test.
+// Maybe test functionality should move into this package too?
+
+// An Action represents a single action in the action graph.
+type Action struct {
+	Package    *load.Package                 // the package this action works on
+	Deps       []*Action                     // actions that must happen before this one
+	Func       func(*Builder, *Action) error // the action itself (nil = no-op)
+	IgnoreFail bool                          // whether to run f even if dependencies fail
+	TestOutput *bytes.Buffer                 // test output buffer
+	Args       []string                      // additional args for runProgram
+
+	triggers []*Action // inverse of deps
+	cgo      *Action   // action for cgo binary if needed
+
+	// Generated files, directories.
+	Link   bool   // target is executable, not just package
+	Pkgdir string // the -I or -L argument to use when importing this package
+	Objdir string // directory for intermediate objects
+	Objpkg string // the intermediate package .a file created during the action
+	Target string // goal of the action: the created package or executable
+
+	// Execution state.
+	pending  int  // number of deps yet to complete
+	priority int  // relative execution priority
+	Failed   bool // whether the action failed
+}
+
+// cacheKey is the key for the action cache.
+type cacheKey struct {
+	mode  BuildMode
+	p     *load.Package
+	shlib string
+}
+
+// BuildMode specifies the build mode:
+// are we just building things or also installing the results?
+type BuildMode int
+
+const (
+	ModeBuild BuildMode = iota
+	ModeInstall
+)
+
+func (b *Builder) Init() {
+	var err error
+	b.Print = func(a ...interface{}) (int, error) {
+		return fmt.Fprint(os.Stderr, a...)
+	}
+	b.actionCache = make(map[cacheKey]*Action)
+	b.mkdirCache = make(map[string]bool)
+
+	if cfg.BuildN {
+		b.WorkDir = "$WORK"
+	} else {
+		b.WorkDir, err = ioutil.TempDir("", "go-build")
+		if err != nil {
+			base.Fatalf("%s", err)
+		}
+		if cfg.BuildX || cfg.BuildWork {
+			fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir)
+		}
+		if !cfg.BuildWork {
+			workdir := b.WorkDir
+			base.AtExit(func() { os.RemoveAll(workdir) })
+		}
+	}
+}
+
+// readpkglist returns the list of packages that were built into the shared library
+// at shlibpath. For the native toolchain this list is stored, newline separated, in
+// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
+// .go_export section.
+func readpkglist(shlibpath string) (pkgs []*load.Package) {
+	var stk load.ImportStack
+	if cfg.BuildToolchainName == "gccgo" {
+		f, _ := elf.Open(shlibpath)
+		sect := f.Section(".go_export")
+		data, _ := sect.Data()
+		scanner := bufio.NewScanner(bytes.NewBuffer(data))
+		for scanner.Scan() {
+			t := scanner.Text()
+			if strings.HasPrefix(t, "pkgpath ") {
+				t = strings.TrimPrefix(t, "pkgpath ")
+				t = strings.TrimSuffix(t, ";")
+				pkgs = append(pkgs, load.LoadPackage(t, &stk))
+			}
+		}
+	} else {
+		pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1)
+		if err != nil {
+			base.Fatalf("readELFNote failed: %v", err)
+		}
+		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
+		for scanner.Scan() {
+			t := scanner.Text()
+			pkgs = append(pkgs, load.LoadPackage(t, &stk))
+		}
+	}
+	return
+}
+
+// Action returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+// action never looks for p in a shared library, but may find p's dependencies in a
+// shared library if buildLinkshared is true.
+func (b *Builder) Action(mode BuildMode, depMode BuildMode, p *load.Package) *Action {
+	return b.action1(mode, depMode, p, false, "")
+}
+
+// action1 returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+// action1 will look for p in a shared library if lookshared is true.
+// forShlib is the shared library that p will become part of, if any.
+func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lookshared bool, forShlib string) *Action {
+	shlib := ""
+	if lookshared {
+		shlib = p.Shlib
+	}
+	key := cacheKey{mode, p, shlib}
+
+	a := b.actionCache[key]
+	if a != nil {
+		return a
+	}
+	if shlib != "" {
+		key2 := cacheKey{ModeInstall, nil, shlib}
+		a = b.actionCache[key2]
+		if a != nil {
+			b.actionCache[key] = a
+			return a
+		}
+		pkgs := readpkglist(shlib)
+		a = b.libaction(filepath.Base(shlib), pkgs, ModeInstall, depMode)
+		b.actionCache[key2] = a
+		b.actionCache[key] = a
+		return a
+	}
+
+	a = &Action{Package: p, Pkgdir: p.Internal.Build.PkgRoot}
+	if p.Internal.Pkgdir != "" { // overrides p.t
+		a.Pkgdir = p.Internal.Pkgdir
+	}
+	b.actionCache[key] = a
+
+	for _, p1 := range p.Internal.Imports {
+		if forShlib != "" {
+			// p is part of a shared library.
+			if p1.Shlib != "" && p1.Shlib != forShlib {
+				// p1 is explicitly part of a different shared library.
+				// Put the action for that shared library into a.Deps.
+				a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, true, p1.Shlib))
+			} else {
+				// p1 is (implicitly or not) part of this shared library.
+				// Put the action for p1 into a.Deps.
+				a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, false, forShlib))
+			}
+		} else {
+			// p is not part of a shared library.
+			// If p1 is in a shared library, put the action for that into
+			// a.Deps, otherwise put the action for p1 into a.Deps.
+			a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, cfg.BuildLinkshared, p1.Shlib))
+		}
+	}
+
+	// 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
+	// are writing is not the cgo we need to use.
+	if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan {
+		if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !cfg.BuildLinkshared && cfg.BuildBuildmode != "shared" {
+			var stk load.ImportStack
+			p1 := load.LoadPackage("cmd/cgo", &stk)
+			if p1.Error != nil {
+				base.Fatalf("load cmd/cgo: %v", p1.Error)
+			}
+			a.cgo = b.Action(depMode, depMode, p1)
+			a.Deps = append(a.Deps, a.cgo)
+		}
+	}
+
+	if p.Standard {
+		switch p.ImportPath {
+		case "builtin", "unsafe":
+			// Fake packages - nothing to build.
+			return a
+		}
+		// gccgo standard library is "fake" too.
+		if cfg.BuildToolchainName == "gccgo" {
+			// the target name is needed for cgo.
+			a.Target = p.Internal.Target
+			return a
+		}
+	}
+
+	if !p.Stale && p.Internal.Target != "" {
+		// p.Stale==false implies that p.Internal.Target is up-to-date.
+		// Record target name for use by actions depending on this one.
+		a.Target = p.Internal.Target
+		return a
+	}
+
+	if p.Internal.Local && p.Internal.Target == "" {
+		// Imported via local path. No permanent target.
+		mode = ModeBuild
+	}
+	work := p.Internal.Pkgdir
+	if work == "" {
+		work = b.WorkDir
+	}
+	a.Objdir = filepath.Join(work, a.Package.ImportPath, "_obj") + string(filepath.Separator)
+	a.Objpkg = BuildToolchain.Pkgpath(work, a.Package)
+	a.Link = p.Name == "main"
+
+	switch mode {
+	case ModeInstall:
+		a.Func = BuildInstallFunc
+		a.Deps = []*Action{b.action1(ModeBuild, depMode, p, lookshared, forShlib)}
+		a.Target = a.Package.Internal.Target
+
+		// Install header for cgo in c-archive and c-shared modes.
+		if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
+			hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h"
+			if cfg.BuildContext.Compiler == "gccgo" {
+				// For the header file, remove the "lib"
+				// added by go/build, so we generate pkg.h
+				// rather than libpkg.h.
+				dir, file := filepath.Split(hdrTarget)
+				file = strings.TrimPrefix(file, "lib")
+				hdrTarget = filepath.Join(dir, file)
+			}
+			ah := &Action{
+				Package: a.Package,
+				Deps:    []*Action{a.Deps[0]},
+				Func:    (*Builder).installHeader,
+				Pkgdir:  a.Pkgdir,
+				Objdir:  a.Objdir,
+				Target:  hdrTarget,
+			}
+			a.Deps = append(a.Deps, ah)
+		}
+
+	case ModeBuild:
+		a.Func = (*Builder).build
+		a.Target = a.Objpkg
+		if a.Link {
+			// An executable file. (This is the name of a temporary file.)
+			// Because we run the temporary file in 'go run' and 'go test',
+			// 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
+			// to create a top-level package named exe.
+			name := "a.out"
+			if p.Internal.ExeName != "" {
+				name = p.Internal.ExeName
+			} else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.Internal.Target != "" {
+				// On OS X, the linker output name gets recorded in the
+				// shared library's LC_ID_DYLIB load command.
+				// The code invoking the linker knows to pass only the final
+				// path element. Arrange that the path element matches what
+				// we'll install it as; otherwise the library is only loadable as "a.out".
+				_, name = filepath.Split(p.Internal.Target)
+			}
+			a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
+		}
+	}
+
+	return a
+}
+
+func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode BuildMode) *Action {
+	a := &Action{}
+	switch mode {
+	default:
+		base.Fatalf("unrecognized mode %v", mode)
+
+	case ModeBuild:
+		a.Func = (*Builder).linkShared
+		a.Target = filepath.Join(b.WorkDir, libname)
+		for _, p := range pkgs {
+			if p.Internal.Target == "" {
+				continue
+			}
+			a.Deps = append(a.Deps, b.Action(depMode, depMode, p))
+		}
+
+	case ModeInstall:
+		// Currently build mode shared forces external linking mode, and
+		// external linking mode forces an import of runtime/cgo (and
+		// math on arm). So if it was not passed on the command line and
+		// it is not present in another shared library, add it here.
+		gccgo := cfg.BuildToolchainName == "gccgo"
+		if !gccgo {
+			seencgo := false
+			for _, p := range pkgs {
+				seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
+			}
+			if !seencgo {
+				var stk load.ImportStack
+				p := load.LoadPackage("runtime/cgo", &stk)
+				if p.Error != nil {
+					base.Fatalf("load runtime/cgo: %v", p.Error)
+				}
+				load.ComputeStale(p)
+				// If runtime/cgo is in another shared library, then that's
+				// also the shared library that contains runtime, so
+				// something will depend on it and so runtime/cgo's staleness
+				// will be checked when processing that library.
+				if p.Shlib == "" || p.Shlib == libname {
+					pkgs = append([]*load.Package{}, pkgs...)
+					pkgs = append(pkgs, p)
+				}
+			}
+			if cfg.Goarch == "arm" {
+				seenmath := false
+				for _, p := range pkgs {
+					seenmath = seenmath || (p.Standard && p.ImportPath == "math")
+				}
+				if !seenmath {
+					var stk load.ImportStack
+					p := load.LoadPackage("math", &stk)
+					if p.Error != nil {
+						base.Fatalf("load math: %v", p.Error)
+					}
+					load.ComputeStale(p)
+					// If math is in another shared library, then that's
+					// also the shared library that contains runtime, so
+					// something will depend on it and so math's staleness
+					// will be checked when processing that library.
+					if p.Shlib == "" || p.Shlib == libname {
+						pkgs = append([]*load.Package{}, pkgs...)
+						pkgs = append(pkgs, p)
+					}
+				}
+			}
+		}
+
+		// Figure out where the library will go.
+		var libdir string
+		for _, p := range pkgs {
+			plibdir := p.Internal.Build.PkgTargetRoot
+			if gccgo {
+				plibdir = filepath.Join(plibdir, "shlibs")
+			}
+			if libdir == "" {
+				libdir = plibdir
+			} else if libdir != plibdir {
+				base.Fatalf("multiple roots %s & %s", libdir, plibdir)
+			}
+		}
+		a.Target = filepath.Join(libdir, libname)
+
+		// Now we can check whether we need to rebuild it.
+		stale := false
+		var built time.Time
+		if fi, err := os.Stat(a.Target); err == nil {
+			built = fi.ModTime()
+		}
+		for _, p := range pkgs {
+			if p.Internal.Target == "" {
+				continue
+			}
+			stale = stale || p.Stale
+			lstat, err := os.Stat(p.Internal.Target)
+			if err != nil || lstat.ModTime().After(built) {
+				stale = true
+			}
+			a.Deps = append(a.Deps, b.action1(depMode, depMode, p, false, a.Target))
+		}
+
+		if stale {
+			a.Func = BuildInstallFunc
+			buildAction := b.libaction(libname, pkgs, ModeBuild, depMode)
+			a.Deps = []*Action{buildAction}
+			for _, p := range pkgs {
+				if p.Internal.Target == "" {
+					continue
+				}
+				shlibnameaction := &Action{}
+				shlibnameaction.Func = (*Builder).installShlibname
+				shlibnameaction.Target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
+				a.Deps = append(a.Deps, shlibnameaction)
+				shlibnameaction.Deps = append(shlibnameaction.Deps, buildAction)
+			}
+		}
+	}
+	return a
+}
+
+// ActionList returns the list of actions in the dag rooted at root
+// as visited in a depth-first post-order traversal.
+func ActionList(root *Action) []*Action {
+	seen := map[*Action]bool{}
+	all := []*Action{}
+	var walk func(*Action)
+	walk = func(a *Action) {
+		if seen[a] {
+			return
+		}
+		seen[a] = true
+		for _, a1 := range a.Deps {
+			walk(a1)
+		}
+		all = append(all, a)
+	}
+	walk(root)
+	return all
+}
+
+// allArchiveActions returns a list of the archive dependencies of root.
+// This is needed because if package p depends on package q that is in libr.so, the
+// action graph looks like p->libr.so->q and so just scanning through p's
+// dependencies does not find the import dir for q.
+func allArchiveActions(root *Action) []*Action {
+	seen := map[*Action]bool{}
+	r := []*Action{}
+	var walk func(*Action)
+	walk = func(a *Action) {
+		if seen[a] {
+			return
+		}
+		seen[a] = true
+		if strings.HasSuffix(a.Target, ".so") || a == root {
+			for _, a1 := range a.Deps {
+				walk(a1)
+			}
+		} else if strings.HasSuffix(a.Target, ".a") {
+			r = append(r, a)
+		}
+	}
+	walk(root)
+	return r
+}
+
+// do runs the action graph rooted at root.
+func (b *Builder) Do(root *Action) {
+	if _, ok := cfg.OSArchSupportsCgo[cfg.Goos+"/"+cfg.Goarch]; !ok && cfg.BuildContext.Compiler == "gc" {
+		fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", cfg.Goos, cfg.Goarch)
+		os.Exit(2)
+	}
+	for _, tag := range cfg.BuildContext.BuildTags {
+		if strings.Contains(tag, ",") {
+			fmt.Fprintf(os.Stderr, "cmd/go: -tags space-separated list contains comma\n")
+			os.Exit(2)
+		}
+	}
+
+	// Build list of all actions, assigning depth-first post-order priority.
+	// 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
+	// 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
+	// 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.
+	all := ActionList(root)
+	for i, a := range all {
+		a.priority = i
+	}
+
+	b.readySema = make(chan bool, len(all))
+
+	// Initialize per-action execution state.
+	for _, a := range all {
+		for _, a1 := range a.Deps {
+			a1.triggers = append(a1.triggers, a)
+		}
+		a.pending = len(a.Deps)
+		if a.pending == 0 {
+			b.ready.push(a)
+			b.readySema <- true
+		}
+	}
+
+	// Handle runs a single action and takes care of triggering
+	// any actions that are runnable as a result.
+	handle := func(a *Action) {
+		var err error
+		if a.Func != nil && (!a.Failed || a.IgnoreFail) {
+			err = a.Func(b, a)
+		}
+
+		// The actions run in parallel but all the updates to the
+		// shared work state are serialized through b.exec.
+		b.exec.Lock()
+		defer b.exec.Unlock()
+
+		if err != nil {
+			if err == errPrintedOutput {
+				base.SetExitStatus(2)
+			} else if _, ok := err.(*build.NoGoError); ok && len(a.Package.TestGoFiles) > 0 && b.testFilesOnlyOK {
+				// Ignore the "no buildable Go source files" error for a package with only test files.
+			} else {
+				base.Errorf("%s", err)
+			}
+			a.Failed = true
+		}
+
+		for _, a0 := range a.triggers {
+			if a.Failed {
+				a0.Failed = true
+			}
+			if a0.pending--; a0.pending == 0 {
+				b.ready.push(a0)
+				b.readySema <- true
+			}
+		}
+
+		if a == root {
+			close(b.readySema)
+		}
+	}
+
+	var wg sync.WaitGroup
+
+	// Kick off goroutines according to parallelism.
+	// If we are using the -n flag (just printing commands)
+	// drop the parallelism to 1, both to make the output
+	// deterministic and because there is no real work anyway.
+	par := cfg.BuildP
+	if cfg.BuildN {
+		par = 1
+	}
+	for i := 0; i < par; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for {
+				select {
+				case _, ok := <-b.readySema:
+					if !ok {
+						return
+					}
+					// Receiving a value from b.readySema entitles
+					// us to take from the ready queue.
+					b.exec.Lock()
+					a := b.ready.pop()
+					b.exec.Unlock()
+					handle(a)
+				case <-base.Interrupted:
+					base.SetExitStatus(1)
+					return
+				}
+			}
+		}()
+	}
+
+	wg.Wait()
+}
+
+// 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.Package.BinaryOnly {
+		return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.Package.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.
+	if len(a.Package.CXXFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() {
+		return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
+			a.Package.ImportPath, strings.Join(a.Package.CXXFiles, ","))
+	}
+	// Same as above for Objective-C files
+	if len(a.Package.MFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() {
+		return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
+			a.Package.ImportPath, strings.Join(a.Package.MFiles, ","))
+	}
+	// Same as above for Fortran files
+	if len(a.Package.FFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() {
+		return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
+			a.Package.ImportPath, strings.Join(a.Package.FFiles, ","))
+	}
+
+	defer func() {
+		if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.Package.TestGoFiles) > 0) {
+			err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
+		}
+	}()
+	if cfg.BuildN {
+		// In -n mode, print a banner between packages.
+		// The banner is five lines so that when changes to
+		// different sections of the bootstrap script have to
+		// be merged, the banners give patch something
+		// to use to find its context.
+		b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n")
+	}
+
+	if cfg.BuildV {
+		b.Print(a.Package.ImportPath + "\n")
+	}
+
+	// Make build directory.
+	obj := a.Objdir
+	if err := b.Mkdir(obj); err != nil {
+		return err
+	}
+
+	// make target directory
+	dir, _ := filepath.Split(a.Target)
+	if dir != "" {
+		if err := b.Mkdir(dir); err != nil {
+			return err
+		}
+	}
+
+	var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+
+	gofiles = append(gofiles, a.Package.GoFiles...)
+	cgofiles = append(cgofiles, a.Package.CgoFiles...)
+	cfiles = append(cfiles, a.Package.CFiles...)
+	sfiles = append(sfiles, a.Package.SFiles...)
+	cxxfiles = append(cxxfiles, a.Package.CXXFiles...)
+
+	if a.Package.UsesCgo() || a.Package.UsesSwig() {
+		if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil {
+			return
+		}
+	}
+
+	// Run SWIG on each .swig and .swigcxx file.
+	// Each run will generate two files, a .go file and a .c or .cxx file.
+	// The .go file will use import "C" and is to be processed by cgo.
+	if a.Package.UsesSwig() {
+		outGo, outC, outCXX, err := b.swig(a.Package, obj, pcCFLAGS)
+		if err != nil {
+			return err
+		}
+		objdirCgofiles = append(objdirCgofiles, outGo...)
+		cfiles = append(cfiles, outC...)
+		cxxfiles = append(cxxfiles, outCXX...)
+	}
+
+	// Run cgo.
+	if a.Package.UsesCgo() || a.Package.UsesSwig() {
+		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
+		// There is one exception: runtime/cgo's job is to bridge the
+		// cgo and non-cgo worlds, so it necessarily has files in both.
+		// In that case gcc only gets the gcc_* files.
+		var gccfiles []string
+		gccfiles = append(gccfiles, cfiles...)
+		cfiles = nil
+		if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" {
+			filter := func(files, nongcc, gcc []string) ([]string, []string) {
+				for _, f := range files {
+					if strings.HasPrefix(f, "gcc_") {
+						gcc = append(gcc, f)
+					} else {
+						nongcc = append(nongcc, f)
+					}
+				}
+				return nongcc, gcc
+			}
+			sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
+		} else {
+			gccfiles = append(gccfiles, sfiles...)
+			sfiles = nil
+		}
+
+		var cgoExe string
+		if a.cgo != nil && a.cgo.Target != "" {
+			cgoExe = a.cgo.Target
+		} else {
+			cgoExe = base.Tool("cgo")
+		}
+		outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles)
+		if err != nil {
+			return err
+		}
+		if cfg.BuildToolchainName == "gccgo" {
+			cgoObjects = append(cgoObjects, filepath.Join(a.Objdir, "_cgo_flags"))
+		}
+		cgoObjects = append(cgoObjects, outObj...)
+		gofiles = append(gofiles, outGo...)
+	}
+
+	if len(gofiles) == 0 {
+		return &build.NoGoError{Dir: a.Package.Dir}
+	}
+
+	// If we're doing coverage, preprocess the .go files and put them in the work directory
+	if a.Package.Internal.CoverMode != "" {
+		for i, file := range gofiles {
+			var sourceFile string
+			var coverFile string
+			var key string
+			if strings.HasSuffix(file, ".cgo1.go") {
+				// cgo files have absolute paths
+				base := filepath.Base(file)
+				sourceFile = file
+				coverFile = filepath.Join(obj, base)
+				key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
+			} else {
+				sourceFile = filepath.Join(a.Package.Dir, file)
+				coverFile = filepath.Join(obj, file)
+				key = file
+			}
+			cover := a.Package.Internal.CoverVars[key]
+			if cover == nil || base.IsTestFile(file) {
+				// Not covering this file.
+				continue
+			}
+			if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+				return err
+			}
+			gofiles[i] = coverFile
+		}
+	}
+
+	// Prepare Go import path list.
+	inc := b.includeArgs("-I", allArchiveActions(a))
+
+	// Compile Go.
+	ofile, out, err := BuildToolchain.gc(b, a.Package, a.Objpkg, obj, len(sfiles) > 0, inc, gofiles)
+	if len(out) > 0 {
+		b.showOutput(a.Package.Dir, a.Package.ImportPath, b.processOutput(out))
+		if err != nil {
+			return errPrintedOutput
+		}
+	}
+	if err != nil {
+		return err
+	}
+	if ofile != a.Objpkg {
+		objects = append(objects, ofile)
+	}
+
+	// Copy .h files named for goos or goarch or goos_goarch
+	// to names using GOOS and GOARCH.
+	// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
+	_goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch
+	_goos := "_" + cfg.Goos
+	_goarch := "_" + cfg.Goarch
+	for _, file := range a.Package.HFiles {
+		name, ext := fileExtSplit(file)
+		switch {
+		case strings.HasSuffix(name, _goos_goarch):
+			targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+				return err
+			}
+		case strings.HasSuffix(name, _goarch):
+			targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+				return err
+			}
+		case strings.HasSuffix(name, _goos):
+			targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+				return err
+			}
+		}
+	}
+
+	for _, file := range cfiles {
+		out := file[:len(file)-len(".c")] + ".o"
+		if err := BuildToolchain.cc(b, a.Package, obj, obj+out, file); err != nil {
+			return err
+		}
+		objects = append(objects, out)
+	}
+
+	// Assemble .s files.
+	if len(sfiles) > 0 {
+		ofiles, err := BuildToolchain.asm(b, a.Package, obj, sfiles)
+		if err != nil {
+			return err
+		}
+		objects = append(objects, ofiles...)
+	}
+
+	// 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.
+	// https://golang.org/issue/2601
+	objects = append(objects, cgoObjects...)
+
+	// Add system object files.
+	for _, syso := range a.Package.SysoFiles {
+		objects = append(objects, filepath.Join(a.Package.Dir, syso))
+	}
+
+	// Pack into archive in obj directory.
+	// If the Go compiler wrote an archive, we only need to add the
+	// object files for non-Go sources to the archive.
+	// If the Go compiler wrote an archive and the package is entirely
+	// Go sources, there is no pack to execute at all.
+	if len(objects) > 0 {
+		if err := BuildToolchain.pack(b, a.Package, obj, a.Objpkg, objects); err != nil {
+			return err
+		}
+	}
+
+	// Link if needed.
+	if a.Link {
+		// The compiler only cares about direct imports, but the
+		// linker needs the whole dependency tree.
+		all := ActionList(a)
+		all = all[:len(all)-1] // drop a
+		if err := BuildToolchain.ld(b, a, a.Target, all, a.Objpkg, objects); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// PkgconfigCmd returns a pkg-config binary name
+// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist.
+func (b *Builder) PkgconfigCmd() string {
+	return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0]
+}
+
+// splitPkgConfigOutput parses the pkg-config output into a slice of
+// flags. pkg-config always uses \ to escape special characters.
+func splitPkgConfigOutput(out []byte) []string {
+	if len(out) == 0 {
+		return nil
+	}
+	var flags []string
+	flag := make([]byte, len(out))
+	r, w := 0, 0
+	for r < len(out) {
+		switch out[r] {
+		case ' ', '\t', '\r', '\n':
+			if w > 0 {
+				flags = append(flags, string(flag[:w]))
+			}
+			w = 0
+		case '\\':
+			r++
+			fallthrough
+		default:
+			if r < len(out) {
+				flag[w] = out[r]
+				w++
+			}
+		}
+		r++
+	}
+	if w > 0 {
+		flags = append(flags, string(flag[:w]))
+	}
+	return flags
+}
+
+// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
+func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
+	if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
+		var out []byte
+		out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pkgs)
+		if err != nil {
+			b.showOutput(p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
+			b.Print(err.Error() + "\n")
+			err = errPrintedOutput
+			return
+		}
+		if len(out) > 0 {
+			cflags = splitPkgConfigOutput(out)
+		}
+		out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pkgs)
+		if err != nil {
+			b.showOutput(p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
+			b.Print(err.Error() + "\n")
+			err = errPrintedOutput
+			return
+		}
+		if len(out) > 0 {
+			ldflags = strings.Fields(string(out))
+		}
+	}
+	return
+}
+
+func (b *Builder) installShlibname(a *Action) error {
+	a1 := a.Deps[0]
+	err := ioutil.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666)
+	if err != nil {
+		return err
+	}
+	if cfg.BuildX {
+		b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target)
+	}
+	return nil
+}
+
+func (b *Builder) linkShared(a *Action) (err error) {
+	allactions := ActionList(a)
+	allactions = allactions[:len(allactions)-1]
+	return BuildToolchain.ldShared(b, a.Deps, a.Target, allactions)
+}
+
+// BuildInstallFunc is the action for installing a single package or executable.
+func BuildInstallFunc(b *Builder, a *Action) (err error) {
+	defer func() {
+		if err != nil && err != errPrintedOutput {
+			err = fmt.Errorf("go install %s: %v", a.Package.ImportPath, err)
+		}
+	}()
+	a1 := a.Deps[0]
+	perm := os.FileMode(0666)
+	if a1.Link {
+		switch cfg.BuildBuildmode {
+		case "c-archive", "c-shared", "plugin":
+		default:
+			perm = 0777
+		}
+	}
+
+	// make target directory
+	dir, _ := filepath.Split(a.Target)
+	if dir != "" {
+		if err := b.Mkdir(dir); err != nil {
+			return err
+		}
+	}
+
+	// remove object dir to keep the amount of
+	// 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 !cfg.BuildWork {
+		defer os.RemoveAll(a1.Objdir)
+		defer os.Remove(a1.Target)
+	}
+
+	return b.moveOrCopyFile(a, a.Target, a1.Target, perm, false)
+}
+
+// includeArgs returns the -I or -L directory list for access
+// to the results of the list of actions.
+func (b *Builder) includeArgs(flag string, all []*Action) []string {
+	inc := []string{}
+	incMap := map[string]bool{
+		b.WorkDir:     true, // handled later
+		cfg.GOROOTpkg: true,
+		"":            true, // ignore empty strings
+	}
+
+	// Look in the temporary space for results of test-specific actions.
+	// This is the $WORK/my/package/_test directory for the
+	// package being built, so there are few of these.
+	for _, a1 := range all {
+		if a1.Package == nil {
+			continue
+		}
+		if dir := a1.Pkgdir; dir != a1.Package.Internal.Build.PkgRoot && !incMap[dir] {
+			incMap[dir] = true
+			inc = append(inc, flag, dir)
+		}
+	}
+
+	// Also look in $WORK for any non-test packages that have
+	// been built but not installed.
+	inc = append(inc, flag, b.WorkDir)
+
+	// Finally, look in the installed package directories for each action.
+	// First add the package dirs corresponding to GOPATH entries
+	// in the original GOPATH order.
+	need := map[string]*build.Package{}
+	for _, a1 := range all {
+		if a1.Package != nil && a1.Pkgdir == a1.Package.Internal.Build.PkgRoot {
+			need[a1.Package.Internal.Build.Root] = a1.Package.Internal.Build
+		}
+	}
+	for _, root := range cfg.Gopath {
+		if p := need[root]; p != nil && !incMap[p.PkgRoot] {
+			incMap[p.PkgRoot] = true
+			inc = append(inc, flag, p.PkgTargetRoot)
+		}
+	}
+
+	// Then add anything that's left.
+	for _, a1 := range all {
+		if a1.Package == nil {
+			continue
+		}
+		if dir := a1.Pkgdir; dir == a1.Package.Internal.Build.PkgRoot && !incMap[dir] {
+			incMap[dir] = true
+			inc = append(inc, flag, a1.Package.Internal.Build.PkgTargetRoot)
+		}
+	}
+
+	return inc
+}
+
+// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
+func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, force bool) error {
+	if cfg.BuildN {
+		b.Showcmd("", "mv %s %s", src, dst)
+		return nil
+	}
+
+	// If we can update the mode and rename to the dst, do it.
+	// Otherwise fall back to standard copy.
+
+	// If the destination directory has the group sticky bit set,
+	// we have to copy the file to retain the correct permissions.
+	// https://golang.org/issue/18878
+	if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
+		if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 {
+			return b.copyFile(a, dst, src, perm, force)
+		}
+	}
+
+	// The perm argument is meant to be adjusted according to umask,
+	// but we don't know what the umask is.
+	// Create a dummy file to find out.
+	// This avoids build tags and works even on systems like Plan 9
+	// where the file mask computation incorporates other information.
+	mode := perm
+	f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
+	if err == nil {
+		fi, err := f.Stat()
+		if err == nil {
+			mode = fi.Mode() & 0777
+		}
+		name := f.Name()
+		f.Close()
+		os.Remove(name)
+	}
+
+	if err := os.Chmod(src, mode); err == nil {
+		if err := os.Rename(src, dst); err == nil {
+			if cfg.BuildX {
+				b.Showcmd("", "mv %s %s", src, dst)
+			}
+			return nil
+		}
+	}
+
+	return b.copyFile(a, dst, src, perm, force)
+}
+
+// copyFile is like 'cp src dst'.
+func (b *Builder) copyFile(a *Action, dst, src string, perm os.FileMode, force bool) error {
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd("", "cp %s %s", src, dst)
+		if cfg.BuildN {
+			return nil
+		}
+	}
+
+	sf, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sf.Close()
+
+	// Be careful about removing/overwriting dst.
+	// Do not remove/overwrite if dst exists and is a directory
+	// or a non-object file.
+	if fi, err := os.Stat(dst); err == nil {
+		if fi.IsDir() {
+			return fmt.Errorf("build output %q already exists and is a directory", dst)
+		}
+		if !force && fi.Mode().IsRegular() && !isObject(dst) {
+			return fmt.Errorf("build output %q already exists and is not an object file", dst)
+		}
+	}
+
+	// On Windows, remove lingering ~ file from last attempt.
+	if base.ToolIsWindows {
+		if _, err := os.Stat(dst + "~"); err == nil {
+			os.Remove(dst + "~")
+		}
+	}
+
+	mayberemovefile(dst)
+	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+	if err != nil && base.ToolIsWindows {
+		// Windows does not allow deletion of a binary file
+		// 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 {
+			os.Remove(dst + "~")
+		}
+		df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+	}
+	if err != nil {
+		return err
+	}
+
+	_, err = io.Copy(df, sf)
+	df.Close()
+	if err != nil {
+		mayberemovefile(dst)
+		return fmt.Errorf("copying %s to %s: %v", src, dst, err)
+	}
+	return nil
+}
+
+// Install the cgo export header file, if there is one.
+func (b *Builder) installHeader(a *Action) error {
+	src := a.Objdir + "_cgo_install.h"
+	if _, err := os.Stat(src); os.IsNotExist(err) {
+		// If the file does not exist, there are no exported
+		// functions, and we do not install anything.
+		return nil
+	}
+
+	dir, _ := filepath.Split(a.Target)
+	if dir != "" {
+		if err := b.Mkdir(dir); err != nil {
+			return err
+		}
+	}
+
+	return b.moveOrCopyFile(a, a.Target, src, 0666, true)
+}
+
+// cover runs, in effect,
+//	go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
+func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName string) error {
+	return b.run(a.Objdir, "cover "+a.Package.ImportPath, nil,
+		cfg.BuildToolexec,
+		base.Tool("cover"),
+		"-mode", a.Package.Internal.CoverMode,
+		"-var", varName,
+		"-o", dst,
+		src)
+}
+
+var objectMagic = [][]byte{
+	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
+	{'\x7F', 'E', 'L', 'F'},                   // ELF
+	{0xFE, 0xED, 0xFA, 0xCE},                  // Mach-O big-endian 32-bit
+	{0xFE, 0xED, 0xFA, 0xCF},                  // Mach-O big-endian 64-bit
+	{0xCE, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 32-bit
+	{0xCF, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 64-bit
+	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},      // PE (Windows) as generated by 6l/8l and gcc
+	{0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
+	{0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
+	{0x00, 0x00, 0x06, 0x47},                  // Plan 9 arm
+}
+
+func isObject(s string) bool {
+	f, err := os.Open(s)
+	if err != nil {
+		return false
+	}
+	defer f.Close()
+	buf := make([]byte, 64)
+	io.ReadFull(f, buf)
+	for _, magic := range objectMagic {
+		if bytes.HasPrefix(buf, magic) {
+			return true
+		}
+	}
+	return false
+}
+
+// mayberemovefile removes a file only if it is a regular file
+// When running as a user with sufficient privileges, we may delete
+// even device files, for example, which is not intended.
+func mayberemovefile(s string) {
+	if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
+		return
+	}
+	os.Remove(s)
+}
+
+// fmtcmd formats a command in the manner of fmt.Sprintf but also:
+//
+//	If dir is non-empty and the script is not in dir right now,
+//	fmtcmd inserts "cd dir\n" before the command.
+//
+//	fmtcmd replaces the value of b.WorkDir with $WORK.
+//	fmtcmd replaces the value of goroot with $GOROOT.
+//	fmtcmd replaces the value of b.gobin with $GOBIN.
+//
+//	fmtcmd replaces the name of the current directory with dot (.)
+//	but only when it is at the beginning of a space-separated token.
+//
+func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string {
+	cmd := fmt.Sprintf(format, args...)
+	if dir != "" && dir != "/" {
+		cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
+		if b.scriptDir != dir {
+			b.scriptDir = dir
+			cmd = "cd " + dir + "\n" + cmd
+		}
+	}
+	if b.WorkDir != "" {
+		cmd = strings.Replace(cmd, b.WorkDir, "$WORK", -1)
+	}
+	return cmd
+}
+
+// showcmd prints the given command to standard output
+// for the implementation of -n or -x.
+func (b *Builder) Showcmd(dir string, format string, args ...interface{}) {
+	b.output.Lock()
+	defer b.output.Unlock()
+	b.Print(b.fmtcmd(dir, format, args...) + "\n")
+}
+
+// showOutput prints "# desc" followed by the given output.
+// 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.
+// For example, if fmt doesn't compile and we are in src/html,
+// the output is
+//
+//	$ go build
+//	# fmt
+//	../fmt/print.go:1090: undefined: asdf
+//	$
+//
+// instead of
+//
+//	$ go build
+//	# fmt
+//	/usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
+//	$
+//
+// showOutput also replaces references to the work directory with $WORK.
+//
+func (b *Builder) showOutput(dir, desc, out string) {
+	prefix := "# " + desc
+	suffix := "\n" + out
+	if reldir := base.ShortPath(dir); reldir != dir {
+		suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
+		suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
+	}
+	suffix = strings.Replace(suffix, " "+b.WorkDir, " $WORK", -1)
+
+	b.output.Lock()
+	defer b.output.Unlock()
+	b.Print(prefix, suffix)
+}
+
+// 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
+// print this error.
+var errPrintedOutput = errors.New("already printed output - no need to show error")
+
+var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+(:[0-9]+)?\]`)
+var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
+
+// run runs the command given by cmdline in the directory dir.
+// If the command fails, run prints information about the failure
+// and returns a non-nil error.
+func (b *Builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
+	out, err := b.runOut(dir, desc, env, cmdargs...)
+	if len(out) > 0 {
+		if desc == "" {
+			desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " "))
+		}
+		b.showOutput(dir, desc, b.processOutput(out))
+		if err != nil {
+			err = errPrintedOutput
+		}
+	}
+	return err
+}
+
+// processOutput prepares the output of runOut to be output to the console.
+func (b *Builder) processOutput(out []byte) string {
+	if out[len(out)-1] != '\n' {
+		out = append(out, '\n')
+	}
+	messages := string(out)
+	// Fix up output referring to cgo-generated code to be more readable.
+	// Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
+	// Replace *[100]_Ctype_foo with *[100]C.foo.
+	// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
+	if !cfg.BuildX && cgoLine.MatchString(messages) {
+		messages = cgoLine.ReplaceAllString(messages, "")
+		messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
+	}
+	return messages
+}
+
+// runOut runs the command given by cmdline in the directory dir.
+// It returns the command output and any errors that occurred.
+func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
+	cmdline := str.StringList(cmdargs...)
+	if cfg.BuildN || cfg.BuildX {
+		var envcmdline string
+		for i := range env {
+			envcmdline += env[i]
+			envcmdline += " "
+		}
+		envcmdline += joinUnambiguously(cmdline)
+		b.Showcmd(dir, "%s", envcmdline)
+		if cfg.BuildN {
+			return nil, nil
+		}
+	}
+
+	nbusy := 0
+	for {
+		var buf bytes.Buffer
+		cmd := exec.Command(cmdline[0], cmdline[1:]...)
+		cmd.Stdout = &buf
+		cmd.Stderr = &buf
+		cmd.Dir = dir
+		cmd.Env = base.MergeEnvLists(env, base.EnvForDir(cmd.Dir, os.Environ()))
+		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 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
+		// a reference to the fd, keeping us from running exec.
+		//
+		// But, you might reasonably wonder, how can this happen?
+		// The cgo fd, like all our fds, is close-on-exec, so that we need
+		// not worry about other processes inheriting the fd accidentally.
+		// 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
+		// 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
+		// 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)
+		// only guarantees that when it returns, the exec is committed to
+		// 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
+		// guaranteed to be gone.
+		//
+		// Sleeping when we observe the race seems to be the most reliable
+		// option we have.
+		//
+		// https://golang.org/issue/3001
+		//
+		if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
+			time.Sleep(100 * time.Millisecond << uint(nbusy))
+			nbusy++
+			continue
+		}
+
+		// err can be something like 'exit status 1'.
+		// Add information about what program was running.
+		// Note that if buf.Bytes() is non-empty, the caller usually
+		// shows buf.Bytes() and does not print err at all, so the
+		// prefix here does not make most output any more verbose.
+		if err != nil {
+			err = errors.New(cmdline[0] + ": " + err.Error())
+		}
+		return buf.Bytes(), err
+	}
+}
+
+// joinUnambiguously prints the slice, quoting where necessary to make the
+// output unambiguous.
+// TODO: See issue 5279. The printing of commands needs a complete redo.
+func joinUnambiguously(a []string) string {
+	var buf bytes.Buffer
+	for i, s := range a {
+		if i > 0 {
+			buf.WriteByte(' ')
+		}
+		q := strconv.Quote(s)
+		if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 {
+			buf.WriteString(q)
+		} else {
+			buf.WriteString(s)
+		}
+	}
+	return buf.String()
+}
+
+// mkdir makes the named directory.
+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.
+	if b.mkdirCache[dir] {
+		return nil
+	}
+	b.mkdirCache[dir] = true
+
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd("", "mkdir -p %s", dir)
+		if cfg.BuildN {
+			return nil
+		}
+	}
+
+	if err := os.MkdirAll(dir, 0777); err != nil {
+		return err
+	}
+	return nil
+}
+
+// mkAbs returns an absolute path corresponding to
+// evaluating f in the directory dir.
+// We always pass absolute paths of source files so that
+// the error messages will include the full path to a file
+// in need of attention.
+func mkAbs(dir, f string) string {
+	// Leave absolute paths alone.
+	// Also, during -n mode we use the pseudo-directory $WORK
+	// instead of creating an actual work directory that won't be used.
+	// Leave paths beginning with $WORK alone too.
+	if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
+		return f
+	}
+	return filepath.Join(dir, f)
+}
+
+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.
+	gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+	// cc runs the toolchain's C compiler in a directory on a C file
+	// to produce an output file.
+	cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error
+	// asm runs the assembler in a specific directory on specific files
+	// and returns a list of named output files.
+	asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error)
+	// pkgpath builds an appropriate path for a temporary package file.
+	Pkgpath(basedir string, p *load.Package) string
+	// pack runs the archive packer in a specific directory to create
+	// an archive from a set of object files.
+	// typically it is run in the object directory.
+	pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error
+	// ld runs the linker to create an executable starting at mainpkg.
+	ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error
+	// ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
+	ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error
+
+	compiler() string
+	linker() string
+}
+
+type noToolchain struct{}
+
+func noCompiler() error {
+	log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler)
+	return nil
+}
+
+func (noToolchain) compiler() string {
+	noCompiler()
+	return ""
+}
+
+func (noToolchain) linker() string {
+	noCompiler()
+	return ""
+}
+
+func (noToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+	return "", nil, noCompiler()
+}
+
+func (noToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
+	return nil, noCompiler()
+}
+
+func (noToolchain) Pkgpath(basedir string, p *load.Package) string {
+	noCompiler()
+	return ""
+}
+
+func (noToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error {
+	return noCompiler()
+}
+
+func (noToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error {
+	return noCompiler()
+}
+
+func (noToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error {
+	return noCompiler()
+}
+
+func (noToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error {
+	return noCompiler()
+}
+
+// The Go toolchain.
+type gcToolchain struct{}
+
+func (gcToolchain) compiler() string {
+	return base.Tool("compile")
+}
+
+func (gcToolchain) linker() string {
+	return base.Tool("link")
+}
+
+func (gcToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+	if archive != "" {
+		ofile = archive
+	} else {
+		out := "_go_.o"
+		ofile = obj + out
+	}
+
+	gcargs := []string{"-p", p.ImportPath}
+	if p.Name == "main" {
+		gcargs[1] = "main"
+	}
+	if p.Standard {
+		gcargs = append(gcargs, "-std")
+	}
+	compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal"))
+	if compilingRuntime {
+		// runtime compiles with a special gc flag to emit
+		// additional reflect type data.
+		gcargs = append(gcargs, "-+")
+	}
+
+	// If we're giving the compiler the entire package (no C etc files), tell it that,
+	// 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.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+	if p.Standard {
+		switch p.ImportPath {
+		case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "syscall", "time":
+			extFiles++
+		}
+	}
+	if extFiles == 0 {
+		gcargs = append(gcargs, "-complete")
+	}
+	if cfg.BuildContext.InstallSuffix != "" {
+		gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
+	}
+	if p.Internal.BuildID != "" {
+		gcargs = append(gcargs, "-buildid", p.Internal.BuildID)
+	}
+	platform := cfg.Goos + "/" + cfg.Goarch
+	if p.Internal.OmitDebug || platform == "nacl/amd64p32" || platform == "darwin/arm" || platform == "darwin/arm64" || cfg.Goos == "plan9" {
+		gcargs = append(gcargs, "-dwarf=false")
+	}
+
+	for _, path := range p.Imports {
+		if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
+			gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
+		} else if strings.HasPrefix(path, "vendor/") {
+			gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
+		}
+	}
+
+	gcflags := buildGcflags
+	if compilingRuntime {
+		// Remove -N, if present.
+		// It is not possible to build the runtime with no optimizations,
+		// because the compiler cannot eliminate enough write barriers.
+		gcflags = make([]string, len(buildGcflags))
+		copy(gcflags, buildGcflags)
+		for i := 0; i < len(gcflags); i++ {
+			if gcflags[i] == "-N" {
+				copy(gcflags[i:], gcflags[i+1:])
+				gcflags = gcflags[:len(gcflags)-1]
+				i--
+			}
+		}
+	}
+	args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.WorkDir, gcflags, gcargs, "-D", p.Internal.LocalPrefix, importArgs}
+	if ofile == archive {
+		args = append(args, "-pack")
+	}
+	if asmhdr {
+		args = append(args, "-asmhdr", obj+"go_asm.h")
+	}
+
+	// Add -c=N to use concurrent backend compilation, if possible.
+	if c := gcBackendConcurrency(gcflags); c > 1 {
+		args = append(args, fmt.Sprintf("-c=%d", c))
+	}
+
+	for _, f := range gofiles {
+		args = append(args, mkAbs(p.Dir, f))
+	}
+
+	output, err = b.runOut(p.Dir, p.ImportPath, nil, args...)
+	return ofile, output, err
+}
+
+// gcBackendConcurrency returns the backend compiler concurrency level for a package compilation.
+func gcBackendConcurrency(gcflags []string) int {
+	// First, check whether we can use -c at all for this compilation.
+	canDashC := concurrentGCBackendCompilationEnabledByDefault
+
+	switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e {
+	case "0":
+		canDashC = false
+	case "1":
+		canDashC = true
+	case "":
+		// Not set. Use default.
+	default:
+		log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e)
+	}
+
+	if os.Getenv("GOEXPERIMENT") != "" {
+		// Concurrent compilation is presumed incompatible with GOEXPERIMENTs.
+		canDashC = false
+	}
+
+CheckFlags:
+	for _, flag := range gcflags {
+		// Concurrent compilation is presumed incompatible with any gcflags,
+		// except for a small whitelist of commonly used flags.
+		// If the user knows better, they can manually add their own -c to the gcflags.
+		switch flag {
+		case "-N", "-l", "-S", "-B", "-C", "-I":
+			// OK
+		default:
+			canDashC = false
+			break CheckFlags
+		}
+	}
+
+	if !canDashC {
+		return 1
+	}
+
+	// Decide how many concurrent backend compilations to allow.
+	//
+	// If we allow too many, in theory we might end up with p concurrent processes,
+	// each with c concurrent backend compiles, all fighting over the same resources.
+	// However, in practice, that seems not to happen too much.
+	// Most build graphs are surprisingly serial, so p==1 for much of the build.
+	// Furthermore, concurrent backend compilation is only enabled for a part
+	// of the overall compiler execution, so c==1 for much of the build.
+	// So don't worry too much about that interaction for now.
+	//
+	// However, in practice, setting c above 4 tends not to help very much.
+	// See the analysis in CL 41192.
+	//
+	// TODO(josharian): attempt to detect whether this particular compilation
+	// is likely to be a bottleneck, e.g. when:
+	//   - it has no successor packages to compile (usually package main)
+	//   - all paths through the build graph pass through it
+	//   - critical path scheduling says it is high priority
+	// and in such a case, set c to runtime.NumCPU.
+	// We do this now when p==1.
+	if cfg.BuildP == 1 {
+		// No process parallelism. Max out c.
+		return runtime.NumCPU()
+	}
+	// Some process parallelism. Set c to min(4, numcpu).
+	c := 4
+	if ncpu := runtime.NumCPU(); ncpu < c {
+		c = ncpu
+	}
+	return c
+}
+
+func (gcToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
+	// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
+	inc := filepath.Join(cfg.GOROOT, "pkg", "include")
+	args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.WorkDir, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags}
+	if p.ImportPath == "runtime" && cfg.Goarch == "386" {
+		for _, arg := range buildAsmflags {
+			if arg == "-dynlink" {
+				args = append(args, "-D=GOBUILDMODE_shared=1")
+			}
+		}
+	}
+	var ofiles []string
+	for _, sfile := range sfiles {
+		ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+		ofiles = append(ofiles, ofile)
+		a := append(args, "-o", ofile, mkAbs(p.Dir, sfile))
+		if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil {
+			return nil, err
+		}
+	}
+	return ofiles, nil
+}
+
+// toolVerify checks that the command line args writes the same output file
+// if run using newTool instead.
+// Unused now but kept around for future use.
+func toolVerify(b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error {
+	newArgs := make([]interface{}, len(args))
+	copy(newArgs, args)
+	newArgs[1] = base.Tool(newTool)
+	newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
+	if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
+		return err
+	}
+	data1, err := ioutil.ReadFile(ofile)
+	if err != nil {
+		return err
+	}
+	data2, err := ioutil.ReadFile(ofile + ".new")
+	if err != nil {
+		return err
+	}
+	if !bytes.Equal(data1, data2) {
+		return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " "))
+	}
+	os.Remove(ofile + ".new")
+	return nil
+}
+
+func (gcToolchain) Pkgpath(basedir string, p *load.Package) string {
+	end := filepath.FromSlash(p.ImportPath + ".a")
+	return filepath.Join(basedir, end)
+}
+
+func (gcToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error {
+	var absOfiles []string
+	for _, f := range ofiles {
+		absOfiles = append(absOfiles, mkAbs(objDir, f))
+	}
+	absAfile := mkAbs(objDir, afile)
+
+	// The archive file should have been created by the compiler.
+	// Since it used to not work that way, verify.
+	if !cfg.BuildN {
+		if _, err := os.Stat(absAfile); err != nil {
+			base.Fatalf("os.Stat of archive file failed: %v", err)
+		}
+	}
+
+	if cfg.BuildN || cfg.BuildX {
+		cmdline := str.StringList("pack", "r", absAfile, absOfiles)
+		b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+	}
+	if cfg.BuildN {
+		return nil
+	}
+	if err := packInternal(b, absAfile, absOfiles); err != nil {
+		b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+		return errPrintedOutput
+	}
+	return nil
+}
+
+func packInternal(b *Builder, afile string, ofiles []string) error {
+	dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
+	if err != nil {
+		return err
+	}
+	defer dst.Close() // only for error returns or panics
+	w := bufio.NewWriter(dst)
+
+	for _, ofile := range ofiles {
+		src, err := os.Open(ofile)
+		if err != nil {
+			return err
+		}
+		fi, err := src.Stat()
+		if err != nil {
+			src.Close()
+			return err
+		}
+		// Note: Not using %-16.16s format because we care
+		// about bytes, not runes.
+		name := fi.Name()
+		if len(name) > 16 {
+			name = name[:16]
+		} else {
+			name += strings.Repeat(" ", 16-len(name))
+		}
+		size := fi.Size()
+		fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
+			name, 0, 0, 0, 0644, size)
+		n, err := io.Copy(w, src)
+		src.Close()
+		if err == nil && n < size {
+			err = io.ErrUnexpectedEOF
+		} else if err == nil && n > size {
+			err = fmt.Errorf("file larger than size reported by stat")
+		}
+		if err != nil {
+			return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
+		}
+		if size&1 != 0 {
+			w.WriteByte(0)
+		}
+	}
+
+	if err := w.Flush(); err != nil {
+		return err
+	}
+	return dst.Close()
+}
+
+// setextld sets the appropriate linker flags for the specified compiler.
+func setextld(ldflags []string, compiler []string) []string {
+	for _, f := range ldflags {
+		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+			// don't override -extld if supplied
+			return ldflags
+		}
+	}
+	ldflags = append(ldflags, "-extld="+compiler[0])
+	if len(compiler) > 1 {
+		extldflags := false
+		add := strings.Join(compiler[1:], " ")
+		for i, f := range ldflags {
+			if f == "-extldflags" && i+1 < len(ldflags) {
+				ldflags[i+1] = add + " " + ldflags[i+1]
+				extldflags = true
+				break
+			} else if strings.HasPrefix(f, "-extldflags=") {
+				ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+				extldflags = true
+				break
+			}
+		}
+		if !extldflags {
+			ldflags = append(ldflags, "-extldflags="+add)
+		}
+	}
+	return ldflags
+}
+
+func (gcToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error {
+	importArgs := b.includeArgs("-L", allactions)
+	cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0
+	for _, a := range allactions {
+		if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
+			cxx = true
+		}
+	}
+	var ldflags []string
+	if cfg.BuildContext.InstallSuffix != "" {
+		ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
+	}
+	if root.Package.Internal.OmitDebug {
+		ldflags = append(ldflags, "-s", "-w")
+	}
+	if cfg.BuildBuildmode == "plugin" {
+		pluginpath := root.Package.ImportPath
+		if pluginpath == "command-line-arguments" {
+			pluginpath = "plugin/unnamed-" + root.Package.Internal.BuildID
+		}
+		ldflags = append(ldflags, "-pluginpath", pluginpath)
+	}
+
+	// If the user has not specified the -extld option, then specify the
+	// appropriate linker. In case of C++ code, use the compiler named
+	// by the CXX environment variable or defaultCXX if CXX is not set.
+	// Else, use the CC environment variable and defaultCC as fallback.
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", cfg.DefaultCXX)
+	} else {
+		compiler = envList("CC", cfg.DefaultCC)
+	}
+	ldflags = setextld(ldflags, compiler)
+	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
+	if root.Package.Internal.BuildID != "" {
+		ldflags = append(ldflags, "-buildid="+root.Package.Internal.BuildID)
+	}
+	ldflags = append(ldflags, cfg.BuildLdflags...)
+
+	// On OS X when using external linking to build a shared library,
+	// the argument passed here to -o ends up recorded in the final
+	// shared library in the LC_ID_DYLIB load command.
+	// To avoid putting the temporary output directory name there
+	// (and making the resulting shared library useless),
+	// run the link in the output directory so that -o can name
+	// just the final path element.
+	dir := "."
+	if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" {
+		dir, out = filepath.Split(out)
+	}
+
+	return b.run(dir, root.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+}
+
+func (gcToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error {
+	importArgs := b.includeArgs("-L", allactions)
+	ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix}
+	ldflags = append(ldflags, "-buildmode=shared")
+	ldflags = append(ldflags, cfg.BuildLdflags...)
+	cxx := false
+	for _, a := range allactions {
+		if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
+			cxx = true
+		}
+	}
+	// If the user has not specified the -extld option, then specify the
+	// appropriate linker. In case of C++ code, use the compiler named
+	// by the CXX environment variable or defaultCXX if CXX is not set.
+	// Else, use the CC environment variable and defaultCC as fallback.
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", cfg.DefaultCXX)
+	} else {
+		compiler = envList("CC", cfg.DefaultCC)
+	}
+	ldflags = setextld(ldflags, compiler)
+	for _, d := range toplevelactions {
+		if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries
+			continue
+		}
+		ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target)
+	}
+	return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags)
+}
+
+func (gcToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error {
+	return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
+}
+
+// The Gccgo toolchain.
+type gccgoToolchain struct{}
+
+var GccgoName, GccgoBin string
+var gccgoErr error
+
+func init() {
+	GccgoName = os.Getenv("GCCGO")
+	if GccgoName == "" {
+		GccgoName = "gccgo"
+	}
+	GccgoBin, gccgoErr = exec.LookPath(GccgoName)
+}
+
+func (gccgoToolchain) compiler() string {
+	checkGccgoBin()
+	return GccgoBin
+}
+
+func (gccgoToolchain) linker() string {
+	checkGccgoBin()
+	return GccgoBin
+}
+
+func checkGccgoBin() {
+	if gccgoErr == nil {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "cmd/go: gccgo: %s\n", gccgoErr)
+	os.Exit(2)
+}
+
+func (tools gccgoToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+	out := "_go_.o"
+	ofile = obj + out
+	gcargs := []string{"-g"}
+	gcargs = append(gcargs, b.gccArchArgs()...)
+	if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+		gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
+	}
+	if p.Internal.LocalPrefix != "" {
+		gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix)
+	}
+
+	// Handle vendor directories
+	savedirs := []string{}
+	for _, incdir := range importArgs {
+		if incdir != "-I" {
+			savedirs = append(savedirs, incdir)
+		}
+	}
+
+	for _, path := range p.Imports {
+		// If this is a new vendor path, add it to the list of importArgs
+		if i := strings.LastIndex(path, "/vendor"); i >= 0 {
+			for _, dir := range savedirs {
+				// Check if the vendor path is already included in dir
+				if strings.HasSuffix(dir, path[:i+len("/vendor")]) {
+					continue
+				}
+				// Make sure this vendor path is not already in the list for importArgs
+				vendorPath := dir + "/" + path[:i+len("/vendor")]
+				for _, imp := range importArgs {
+					if imp == "-I" {
+						continue
+					}
+					// This vendorPath is already in the list
+					if imp == vendorPath {
+						goto nextSuffixPath
+					}
+				}
+				// New vendorPath not yet in the importArgs list, so add it
+				importArgs = append(importArgs, "-I", vendorPath)
+			nextSuffixPath:
+			}
+		} else if strings.HasPrefix(path, "vendor/") {
+			for _, dir := range savedirs {
+				// Make sure this vendor path is not already in the list for importArgs
+				vendorPath := dir + "/" + path[len("/vendor"):]
+				for _, imp := range importArgs {
+					if imp == "-I" {
+						continue
+					}
+					if imp == vendorPath {
+						goto nextPrefixPath
+					}
+				}
+				// This vendor path is needed and not already in the list, so add it
+				importArgs = append(importArgs, "-I", vendorPath)
+			nextPrefixPath:
+			}
+		}
+	}
+
+	args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+	for _, f := range gofiles {
+		args = append(args, mkAbs(p.Dir, f))
+	}
+
+	output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
+	return ofile, output, err
+}
+
+func (tools gccgoToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
+	var ofiles []string
+	for _, sfile := range sfiles {
+		ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+		ofiles = append(ofiles, ofile)
+		sfile = mkAbs(p.Dir, sfile)
+		defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
+		if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+			defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+		}
+		defs = tools.maybePIC(defs)
+		defs = append(defs, b.gccArchArgs()...)
+		err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return ofiles, nil
+}
+
+func (gccgoToolchain) Pkgpath(basedir string, p *load.Package) string {
+	end := filepath.FromSlash(p.ImportPath + ".a")
+	afile := filepath.Join(basedir, end)
+	// add "lib" to the final element
+	return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
+}
+
+func (gccgoToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error {
+	var absOfiles []string
+	for _, f := range ofiles {
+		absOfiles = append(absOfiles, mkAbs(objDir, f))
+	}
+	return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
+}
+
+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.
+	apackagePathsSeen := make(map[string]bool)
+	afiles := []string{}
+	shlibs := []string{}
+	ldflags := b.gccArchArgs()
+	cgoldflags := []string{}
+	usesCgo := false
+	cxx := false
+	objc := false
+	fortran := false
+	if root.Package != nil {
+		cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0
+		objc = len(root.Package.MFiles) > 0
+		fortran = len(root.Package.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.WorkDir, 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.WorkDir, 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.WorkDir, "_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
+	// whether a shared library action has been seen on the way to an action (the
+	// construction of the graph means that if any path to a node passes through
+	// a shared library action, they all do).
+	var walk func(a *Action, seenShlib bool)
+	var err error
+	walk = func(a *Action, seenShlib bool) {
+		if actionsSeen[a] {
+			return
+		}
+		actionsSeen[a] = true
+		if a.Package != nil && !seenShlib {
+			if a.Package.Standard {
+				return
+			}
+			// We record the target of the first time we see a .a file
+			// for a package to make sure that we prefer the 'install'
+			// rather than the 'build' location (which may not exist any
+			// more). We still need to traverse the dependencies of the
+			// build action though so saying
+			// if apackagePathsSeen[a.Package.ImportPath] { return }
+			// doesn't work.
+			if !apackagePathsSeen[a.Package.ImportPath] {
+				apackagePathsSeen[a.Package.ImportPath] = true
+				target := a.Target
+				if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() {
+					target, err = readAndRemoveCgoFlags(target)
+					if err != nil {
+						return
+					}
+				}
+				afiles = append(afiles, target)
+			}
+		}
+		if strings.HasSuffix(a.Target, ".so") {
+			shlibs = append(shlibs, a.Target)
+			seenShlib = true
+		}
+		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
+		}
+	}
+
+	for _, a := range allactions {
+		// Gather CgoLDFLAGS, but not from standard packages.
+		// The go tool can dig up runtime/cgo from GOROOT and
+		// think that it should use its CgoLDFLAGS, but gccgo
+		// doesn't use runtime/cgo.
+		if a.Package == nil {
+			continue
+		}
+		if !a.Package.Standard {
+			cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...)
+		}
+		if len(a.Package.CgoFiles) > 0 {
+			usesCgo = true
+		}
+		if a.Package.UsesSwig() {
+			usesCgo = true
+		}
+		if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 {
+			cxx = true
+		}
+		if len(a.Package.MFiles) > 0 {
+			objc = true
+		}
+		if len(a.Package.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")
+	ldflags = append(ldflags, afiles...)
+	ldflags = append(ldflags, "-Wl,--no-whole-archive")
+
+	ldflags = append(ldflags, cgoldflags...)
+	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
+	if root.Package != nil {
+		ldflags = append(ldflags, root.Package.CgoLDFLAGS...)
+	}
+
+	ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
+
+	for _, shlib := range shlibs {
+		ldflags = append(
+			ldflags,
+			"-L"+filepath.Dir(shlib),
+			"-Wl,-rpath="+filepath.Dir(shlib),
+			"-l"+strings.TrimSuffix(
+				strings.TrimPrefix(filepath.Base(shlib), "lib"),
+				".so"))
+	}
+
+	var realOut string
+	switch buildmode {
+	case "exe":
+		if usesCgo && cfg.Goos == "linux" {
+			ldflags = append(ldflags, "-Wl,-E")
+		}
+
+	case "c-archive":
+		// Link the Go files into a single .o, and also link
+		// in -lgolibbegin.
+		//
+		// We need to use --whole-archive with -lgolibbegin
+		// because it doesn't define any symbols that will
+		// cause the contents to be pulled in; it's just
+		// initialization code.
+		//
+		// The user remains responsible for linking against
+		// -lgo -lpthread -lm in the final link. We can't use
+		// -r to pick them up because we can't combine
+		// split-stack and non-split-stack code in a single -r
+		// link, and libgo picks up non-split-stack code from
+		// libffi.
+		ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
+
+		if b.gccSupportsNoPie() {
+			ldflags = append(ldflags, "-no-pie")
+		}
+
+		// We are creating an object file, so we don't want a build ID.
+		ldflags = b.disableBuildID(ldflags)
+
+		realOut = out
+		out = out + ".o"
+
+	case "c-shared":
+		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
+	case "shared":
+		ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
+
+	default:
+		base.Fatalf("-buildmode=%s not supported for gccgo", buildmode)
+	}
+
+	switch buildmode {
+	case "exe", "c-shared":
+		if cxx {
+			ldflags = append(ldflags, "-lstdc++")
+		}
+		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(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+		return err
+	}
+
+	switch buildmode {
+	case "c-archive":
+		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.Package.ImportPath)
+}
+
+func (tools gccgoToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error {
+	fakeRoot := &Action{}
+	fakeRoot.Deps = toplevelactions
+	return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
+}
+
+func (tools gccgoToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error {
+	inc := filepath.Join(cfg.GOROOT, "pkg", "include")
+	cfile = mkAbs(p.Dir, cfile)
+	defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
+	defs = append(defs, b.gccArchArgs()...)
+	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
+	}
+	switch cfg.Goarch {
+	case "386", "amd64":
+		defs = append(defs, "-fsplit-stack")
+	}
+	defs = tools.maybePIC(defs)
+	return b.run(p.Dir, p.ImportPath, nil, envList("CC", cfg.DefaultCC), "-Wall", "-g",
+		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
+}
+
+// maybePIC adds -fPIC to the list of arguments if needed.
+func (tools gccgoToolchain) maybePIC(args []string) []string {
+	switch cfg.BuildBuildmode {
+	case "c-shared", "shared", "plugin":
+		args = append(args, "-fPIC")
+	}
+	return args
+}
+
+func gccgoPkgpath(p *load.Package) string {
+	if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary {
+		return ""
+	}
+	return p.ImportPath
+}
+
+func gccgoCleanPkgpath(p *load.Package) string {
+	clean := func(r rune) rune {
+		switch {
+		case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+			'0' <= r && r <= '9':
+			return r
+		}
+		return '_'
+	}
+	return strings.Map(clean, gccgoPkgpath(p))
+}
+
+// gcc runs the gcc C compiler to create an object from a single C file.
+func (b *Builder) gcc(p *load.Package, out string, flags []string, cfile string) error {
+	return b.ccompile(p, out, flags, cfile, b.GccCmd(p.Dir))
+}
+
+// gxx runs the g++ C++ compiler to create an object from a single C++ file.
+func (b *Builder) gxx(p *load.Package, out string, flags []string, cxxfile string) error {
+	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 *load.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 *load.Package, outfile string, flags []string, file string, compiler []string) error {
+	file = mkAbs(p.Dir, file)
+	desc := p.ImportPath
+	if !filepath.IsAbs(outfile) {
+		outfile = filepath.Join(p.Dir, outfile)
+	}
+	output, err := b.runOut(filepath.Dir(file), desc, nil, compiler, flags, "-o", outfile, "-c", filepath.Base(file))
+	if len(output) > 0 {
+		// On FreeBSD 11, when we pass -g to clang 3.8 it
+		// invokes its internal assembler with -dwarf-version=2.
+		// When it sees .section .note.GNU-stack, it warns
+		// "DWARF2 only supports one section per compilation unit".
+		// This warning makes no sense, since the section is empty,
+		// but it confuses people.
+		// We work around the problem by detecting the warning
+		// and dropping -g and trying again.
+		if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
+			newFlags := make([]string, 0, len(flags))
+			for _, f := range flags {
+				if !strings.HasPrefix(f, "-g") {
+					newFlags = append(newFlags, f)
+				}
+			}
+			if len(newFlags) < len(flags) {
+				return b.ccompile(p, outfile, newFlags, file, compiler)
+			}
+		}
+
+		b.showOutput(p.Dir, desc, b.processOutput(output))
+		if err != nil {
+			err = errPrintedOutput
+		} else if os.Getenv("GO_BUILDER_NAME") != "" {
+			return errors.New("C compiler warning promoted to error on Go builders")
+		}
+	}
+	return err
+}
+
+// gccld runs the gcc linker to create an executable from a set of object files.
+func (b *Builder) gccld(p *load.Package, out string, flags []string, obj []string) error {
+	var cmd []string
+	if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
+		cmd = b.GxxCmd(p.Dir)
+	} else {
+		cmd = b.GccCmd(p.Dir)
+	}
+	return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags)
+}
+
+// gccCmd returns a gcc command line prefix
+// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
+func (b *Builder) GccCmd(objdir string) []string {
+	return b.ccompilerCmd("CC", cfg.DefaultCC, objdir)
+}
+
+// gxxCmd returns a g++ command line prefix
+// defaultCXX is defined in zdefaultcc.go, written by cmd/dist.
+func (b *Builder) GxxCmd(objdir string) []string {
+	return b.ccompilerCmd("CXX", cfg.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 {
+	// NOTE: env.go's mkEnv knows that the first three
+	// strings returned are "gcc", "-I", objdir (and cuts them off).
+
+	compiler := envList(envvar, defcmd)
+	a := []string{compiler[0], "-I", objdir}
+	a = append(a, compiler[1:]...)
+
+	// Definitely want -fPIC but on Windows gcc complains
+	// "-fPIC ignored for target (all code is position independent)"
+	if cfg.Goos != "windows" {
+		a = append(a, "-fPIC")
+	}
+	a = append(a, b.gccArchArgs()...)
+	// gcc-4.5 and beyond require explicit "-pthread" flag
+	// for multithreading with pthread library.
+	if cfg.BuildContext.CgoEnabled {
+		switch cfg.Goos {
+		case "windows":
+			a = append(a, "-mthreads")
+		default:
+			a = append(a, "-pthread")
+		}
+	}
+
+	if strings.Contains(a[0], "clang") {
+		// disable ASCII art in clang errors, if possible
+		a = append(a, "-fno-caret-diagnostics")
+		// clang is too smart about command-line arguments
+		a = append(a, "-Qunused-arguments")
+	}
+
+	// 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.WorkDir+"=/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.
+	if cfg.Goos == "darwin" {
+		a = append(a, "-fno-common")
+	}
+
+	return a
+}
+
+// On systems with PIE (position independent executables) enabled by default,
+// -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 {
+	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
+	}
+	if b.flagCache == nil {
+		src := filepath.Join(b.WorkDir, "trivial.c")
+		if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+			return false
+		}
+		b.flagCache = make(map[string]bool)
+	}
+	cmdArgs := append(envList("CC", cfg.DefaultCC), flag, "-c", "trivial.c")
+	if cfg.BuildN || cfg.BuildX {
+		b.Showcmd(b.WorkDir, "%s", joinUnambiguously(cmdArgs))
+		if cfg.BuildN {
+			return false
+		}
+	}
+	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
+	cmd.Dir = b.WorkDir
+	cmd.Env = base.MergeEnvLists([]string{"LC_ALL=C"}, base.EnvForDir(cmd.Dir, os.Environ()))
+	out, err := cmd.CombinedOutput()
+	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.
+func (b *Builder) gccArchArgs() []string {
+	switch cfg.Goarch {
+	case "386":
+		return []string{"-m32"}
+	case "amd64", "amd64p32":
+		return []string{"-m64"}
+	case "arm":
+		return []string{"-marm"} // not thumb
+	case "s390x":
+		return []string{"-m64", "-march=z196"}
+	case "mips64", "mips64le":
+		return []string{"-mabi=64"}
+	case "mips", "mipsle":
+		return []string{"-mabi=32", "-march=mips32"}
+	}
+	return nil
+}
+
+// envList returns the value of the given environment variable broken
+// into fields, using the default value when the variable is empty.
+func envList(key, def string) []string {
+	v := os.Getenv(key)
+	if v == "" {
+		v = def
+	}
+	return strings.Fields(v)
+}
+
+// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
+func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
+	defaults := "-g -O2"
+
+	cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+	cflags = str.StringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+	cxxflags = str.StringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+	fflags = str.StringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
+	ldflags = str.StringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+	return
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+func (b *Builder) cgo(a *Action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+	p := a.Package
+	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.CFlags(p)
+	cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
+	cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
+	// If we are compiling Objective-C code, then we need to link against libobjc
+	if len(mfiles) > 0 {
+		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 cfg.BuildMSan {
+		cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
+		cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
+	}
+
+	// Allows including _cgo_export.h from .[ch] files in the package.
+	cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
+
+	// If we have cgo files in the object directory, then copy any
+	// other cgo files into the object directory, and pass a
+	// -srcdir option to cgo.
+	var srcdirarg []string
+	if len(objdirCgofiles) > 0 {
+		for _, fn := range cgofiles {
+			if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil {
+				return nil, nil, err
+			}
+		}
+		cgofiles = append(cgofiles, objdirCgofiles...)
+		srcdirarg = []string{"-srcdir", obj}
+	}
+
+	// cgo
+	// TODO: CGO_FLAGS?
+	gofiles := []string{obj + "_cgo_gotypes.go"}
+	cfiles := []string{"_cgo_export.c"}
+	for _, fn := range cgofiles {
+		f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+		gofiles = append(gofiles, obj+f+"cgo1.go")
+		cfiles = append(cfiles, f+"cgo2.c")
+	}
+
+	// TODO: make cgo not depend on $GOARCH?
+
+	cgoflags := []string{}
+	if p.Standard && p.ImportPath == "runtime/cgo" {
+		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
+	}
+	if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") {
+		cgoflags = append(cgoflags, "-import_syscall=false")
+	}
+
+	// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
+	var cgoenv []string
+	if len(cgoLDFLAGS) > 0 {
+		flags := make([]string, len(cgoLDFLAGS))
+		for i, f := range cgoLDFLAGS {
+			flags[i] = strconv.Quote(f)
+		}
+		cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
+	}
+
+	if cfg.BuildToolchainName == "gccgo" {
+		switch cfg.Goarch {
+		case "386", "amd64":
+			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
+		}
+		cgoflags = append(cgoflags, "-gccgo")
+		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
+		}
+	}
+
+	switch cfg.BuildBuildmode {
+	case "c-archive", "c-shared":
+		// Tell cgo that if there are any exported functions
+		// it should generate a header file that C code can
+		// #include.
+		cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
+	}
+
+	if err := b.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
+		return nil, nil, err
+	}
+	outGo = append(outGo, gofiles...)
+
+	// gcc
+	cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS)
+	for _, cfile := range cfiles {
+		ofile := obj + cfile[:len(cfile)-1] + "o"
+		if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, ofile)
+	}
+
+	for _, file := range gccfiles {
+		base := filepath.Base(file)
+		ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o"
+		if err := b.gcc(p, ofile, cflags, file); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, ofile)
+	}
+
+	cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS)
+	for _, file := range gxxfiles {
+		// Append .o to the file, just in case the pkg has file.c and file.cpp
+		ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
+		if err := b.gxx(p, ofile, cxxflags, file); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, ofile)
+	}
+
+	for _, file := range mfiles {
+		// Append .o to the file, just in case the pkg has file.c and file.m
+		ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
+		if err := b.gcc(p, ofile, cflags, file); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, ofile)
+	}
+
+	fflags := str.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(filepath.Base(file), "_") + ".o"
+		if err := b.gfortran(p, ofile, fflags, file); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, ofile)
+	}
+
+	switch cfg.BuildToolchainName {
+	case "gc":
+		importGo := obj + "_cgo_import.go"
+		if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
+			return nil, nil, err
+		}
+		outGo = append(outGo, importGo)
+
+		ofile := obj + "_all.o"
+		if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil {
+			return nil, nil, err
+		}
+		outObj = []string{ofile}
+
+	case "gccgo":
+		defunC := obj + "_cgo_defun.c"
+		defunObj := obj + "_cgo_defun.o"
+		if err := BuildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, defunObj)
+
+	default:
+		noCompiler()
+	}
+
+	return outGo, outObj, nil
+}
+
+// dynimport creates a Go source file named importGo containing
+// //go:cgo_import_dynamic directives for each symbol or library
+// dynamically imported by the object files outObj.
+func (b *Builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
+	cfile := obj + "_cgo_main.c"
+	ofile := obj + "_cgo_main.o"
+	if err := b.gcc(p, ofile, cflags, cfile); err != nil {
+		return err
+	}
+
+	linkobj := str.StringList(ofile, outObj, p.SysoFiles)
+	dynobj := obj + "_cgo_.o"
+
+	// we need to use -pie for Linux/ARM to get accurate imported sym
+	ldflags := cgoLDFLAGS
+	if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
+		ldflags = append(ldflags, "-pie")
+	}
+	if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil {
+		return err
+	}
+
+	// cgo -dynimport
+	var cgoflags []string
+	if p.Standard && p.ImportPath == "runtime/cgo" {
+		cgoflags = []string{"-dynlinker"} // record path to dynamic linker
+	}
+	return b.run(p.Dir, p.ImportPath, nil, cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+}
+
+// collect partially links the object files outObj into a single
+// relocatable object file named ofile.
+func (b *Builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj []string) error {
+	// When linking relocatable objects, various flags need to be
+	// filtered out as they are inapplicable and can cause some linkers
+	// to fail.
+	var ldflags []string
+	for i := 0; i < len(cgoLDFLAGS); i++ {
+		f := cgoLDFLAGS[i]
+		switch {
+		// skip "-lc" or "-l somelib"
+		case strings.HasPrefix(f, "-l"):
+			if f == "-l" {
+				i++
+			}
+		// skip "-framework X" on Darwin
+		case cfg.Goos == "darwin" && f == "-framework":
+			i++
+		// skip "*.{dylib,so,dll,o,a}"
+		case strings.HasSuffix(f, ".dylib"),
+			strings.HasSuffix(f, ".so"),
+			strings.HasSuffix(f, ".dll"),
+			strings.HasSuffix(f, ".o"),
+			strings.HasSuffix(f, ".a"):
+		// Remove any -fsanitize=foo flags.
+		// Otherwise the compiler driver thinks that we are doing final link
+		// and links sanitizer runtime into the object file. But we are not doing
+		// the final link, we will link the resulting object file again. And
+		// so the program ends up with two copies of sanitizer runtime.
+		// See issue 8788 for details.
+		case strings.HasPrefix(f, "-fsanitize="):
+			continue
+		// runpath flags not applicable unless building a shared
+		// 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.
+		case strings.HasPrefix(f, "-Wl,-rpath"):
+			if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
+				// Skip following argument to -rpath* too.
+				i++
+			}
+		default:
+			ldflags = append(ldflags, f)
+		}
+	}
+
+	ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
+
+	if b.gccSupportsNoPie() {
+		ldflags = append(ldflags, "-no-pie")
+	}
+
+	// We are creating an object file, so we don't want a build ID.
+	ldflags = b.disableBuildID(ldflags)
+
+	return b.gccld(p, ofile, ldflags, outObj)
+}
+
+// Run SWIG on all SWIG input files.
+// TODO: Don't build a shared library, once SWIG emits the necessary
+// pragmas for external linking.
+func (b *Builder) swig(p *load.Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
+	if err := b.swigVersionCheck(); err != nil {
+		return nil, nil, nil, err
+	}
+
+	intgosize, err := b.swigIntSize(obj)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	for _, f := range p.SwigFiles {
+		goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
+		if err != nil {
+			return nil, nil, nil, err
+		}
+		if goFile != "" {
+			outGo = append(outGo, goFile)
+		}
+		if cFile != "" {
+			outC = append(outC, cFile)
+		}
+	}
+	for _, f := range p.SwigCXXFiles {
+		goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
+		if err != nil {
+			return nil, nil, nil, err
+		}
+		if goFile != "" {
+			outGo = append(outGo, goFile)
+		}
+		if cxxFile != "" {
+			outCXX = append(outCXX, cxxFile)
+		}
+	}
+	return outGo, outC, outCXX, nil
+}
+
+// Make sure SWIG is new enough.
+var (
+	swigCheckOnce sync.Once
+	swigCheck     error
+)
+
+func (b *Builder) swigDoVersionCheck() error {
+	out, err := b.runOut("", "", nil, "swig", "-version")
+	if err != nil {
+		return err
+	}
+	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
+	matches := re.FindSubmatch(out)
+	if matches == nil {
+		// Can't find version number; hope for the best.
+		return nil
+	}
+
+	major, err := strconv.Atoi(string(matches[1]))
+	if err != nil {
+		// Can't find version number; hope for the best.
+		return nil
+	}
+	const errmsg = "must have SWIG version >= 3.0.6"
+	if major < 3 {
+		return errors.New(errmsg)
+	}
+	if major > 3 {
+		// 4.0 or later
+		return nil
+	}
+
+	// We have SWIG version 3.x.
+	if len(matches[2]) > 0 {
+		minor, err := strconv.Atoi(string(matches[2][1:]))
+		if err != nil {
+			return nil
+		}
+		if minor > 0 {
+			// 3.1 or later
+			return nil
+		}
+	}
+
+	// We have SWIG version 3.0.x.
+	if len(matches[3]) > 0 {
+		patch, err := strconv.Atoi(string(matches[3][1:]))
+		if err != nil {
+			return nil
+		}
+		if patch < 6 {
+			// Before 3.0.6.
+			return errors.New(errmsg)
+		}
+	}
+
+	return nil
+}
+
+func (b *Builder) swigVersionCheck() error {
+	swigCheckOnce.Do(func() {
+		swigCheck = b.swigDoVersionCheck()
+	})
+	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
+const i int = 1 << 32
+`
+
+// Determine the size of int on the target system for the -intgosize option
+// of swig >= 2.0.9. Run only once.
+func (b *Builder) swigDoIntSize(obj string) (intsize string, err error) {
+	if cfg.BuildN {
+		return "$INTBITS", nil
+	}
+	src := filepath.Join(b.WorkDir, "swig_intsize.go")
+	if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
+		return
+	}
+	srcs := []string{src}
+
+	p := load.GoFilesPackage(srcs)
+
+	if _, _, e := BuildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
+		return "32", nil
+	}
+	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 *load.Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
+	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.CFlags(p)
+	var cflags []string
+	if cxx {
+		cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
+	} else {
+		cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
+	}
+
+	n := 5 // length of ".swig"
+	if cxx {
+		n = 8 // length of ".swigcxx"
+	}
+	base := file[:len(file)-n]
+	goFile := base + ".go"
+	gccBase := base + "_wrap."
+	gccExt := "c"
+	if cxx {
+		gccExt = "cxx"
+	}
+
+	gccgo := cfg.BuildToolchainName == "gccgo"
+
+	// swig
+	args := []string{
+		"-go",
+		"-cgo",
+		"-intgosize", intgosize,
+		"-module", base,
+		"-o", obj + gccBase + gccExt,
+		"-outdir", obj,
+	}
+
+	for _, f := range cflags {
+		if len(f) > 3 && f[:2] == "-I" {
+			args = append(args, f)
+		}
+	}
+
+	if gccgo {
+		args = append(args, "-gccgo")
+		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+			args = append(args, "-go-pkgpath", pkgpath)
+		}
+	}
+	if cxx {
+		args = append(args, "-c++")
+	}
+
+	out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
+	if err != nil {
+		if len(out) > 0 {
+			if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
+				return "", "", errors.New("must have SWIG version >= 3.0.6")
+			}
+			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error
+			return "", "", errPrintedOutput
+		}
+		return "", "", err
+	}
+	if len(out) > 0 {
+		b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
+	}
+
+	return goFile, obj + gccBase + gccExt, nil
+}
+
+// disableBuildID adjusts a linker command line to avoid creating a
+// build ID when creating an object file rather than an executable or
+// shared library. Some systems, such as Ubuntu, always add
+// --build-id to every link, but we don't want a build ID when we are
+// producing an object file. On some of those system a plain -r (not
+// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
+// plain -r. I don't know how to turn off --build-id when using clang
+// other than passing a trailing --build-id=none. So that is what we
+// do, but only on systems likely to support it, which is to say,
+// systems that normally use gold or the GNU linker.
+func (b *Builder) disableBuildID(ldflags []string) []string {
+	switch cfg.Goos {
+	case "android", "dragonfly", "linux", "netbsd":
+		ldflags = append(ldflags, "-Wl,--build-id=none")
+	}
+	return ldflags
+}
+
+// An actionQueue is a priority queue of actions.
+type actionQueue []*Action
+
+// Implement heap.Interface
+func (q *actionQueue) Len() int           { return len(*q) }
+func (q *actionQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
+func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
+func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*Action)) }
+func (q *actionQueue) Pop() interface{} {
+	n := len(*q) - 1
+	x := (*q)[n]
+	*q = (*q)[:n]
+	return x
+}
+
+func (q *actionQueue) push(a *Action) {
+	heap.Push(q, a)
+}
+
+func (q *actionQueue) pop() *Action {
+	return heap.Pop(q).(*Action)
+}
+
+func InstrumentInit() {
+	if !cfg.BuildRace && !cfg.BuildMSan {
+		return
+	}
+	if cfg.BuildRace && cfg.BuildMSan {
+		fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
+		os.Exit(2)
+	}
+	if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64") {
+		fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
+		os.Exit(2)
+	}
+	if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" {
+		fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+		os.Exit(2)
+	}
+	if !cfg.BuildContext.CgoEnabled {
+		fmt.Fprintf(os.Stderr, "go %s: -race requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0])
+		os.Exit(2)
+	}
+	if cfg.BuildRace {
+		buildGcflags = append(buildGcflags, "-race")
+		cfg.BuildLdflags = append(cfg.BuildLdflags, "-race")
+	} else {
+		buildGcflags = append(buildGcflags, "-msan")
+		cfg.BuildLdflags = append(cfg.BuildLdflags, "-msan")
+	}
+	if cfg.BuildContext.InstallSuffix != "" {
+		cfg.BuildContext.InstallSuffix += "_"
+	}
+
+	if cfg.BuildRace {
+		cfg.BuildContext.InstallSuffix += "race"
+		cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "race")
+	} else {
+		cfg.BuildContext.InstallSuffix += "msan"
+		cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "msan")
+	}
+}
+
+// ExecCmd is the command to use to run user binaries.
+// Normally it is empty, meaning run the binaries directly.
+// If cross-compiling and running on a remote system or
+// simulator, it is typically go_GOOS_GOARCH_exec, with
+// the target GOOS and GOARCH substituted.
+// The -exec flag overrides these defaults.
+var ExecCmd []string
+
+// FindExecCmd derives the value of ExecCmd to use.
+// It returns that value and leaves ExecCmd set for direct use.
+func FindExecCmd() []string {
+	if ExecCmd != nil {
+		return ExecCmd
+	}
+	ExecCmd = []string{} // avoid work the second time
+	if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
+		return ExecCmd
+	}
+	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
+	if err == nil {
+		ExecCmd = []string{path}
+	}
+	return ExecCmd
+}
diff --git a/src/cmd/go/internal/work/build_test.go b/src/cmd/go/internal/work/build_test.go
new file mode 100644
index 0000000..294b83c
--- /dev/null
+++ b/src/cmd/go/internal/work/build_test.go
@@ -0,0 +1,227 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package work
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"strings"
+	"testing"
+
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
+)
+
+func TestRemoveDevNull(t *testing.T) {
+	fi, err := os.Lstat(os.DevNull)
+	if err != nil {
+		t.Skip(err)
+	}
+	if fi.Mode().IsRegular() {
+		t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
+	}
+	mayberemovefile(os.DevNull)
+	_, err = os.Lstat(os.DevNull)
+	if err != nil {
+		t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
+	}
+}
+
+func TestSplitPkgConfigOutput(t *testing.T) {
+	for _, test := range []struct {
+		in   []byte
+		want []string
+	}{
+		{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
+		{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
+		{[]byte(`broken flag\`), []string{"broken", "flag"}},
+		{[]byte("\textra     whitespace\r\n"), []string{"extra", "whitespace"}},
+		{[]byte("     \r\n      "), nil},
+	} {
+		got := splitPkgConfigOutput(test.in)
+		if !reflect.DeepEqual(got, test.want) {
+			t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
+		}
+	}
+}
+
+func TestSharedLibName(t *testing.T) {
+	// TODO(avdva) - make these values platform-specific
+	prefix := "lib"
+	suffix := ".so"
+	testData := []struct {
+		args      []string
+		pkgs      []*load.Package
+		expected  string
+		expectErr bool
+		rootedAt  string
+	}{
+		{
+			args:     []string{"std"},
+			pkgs:     []*load.Package{},
+			expected: "std",
+		},
+		{
+			args:     []string{"std", "cmd"},
+			pkgs:     []*load.Package{},
+			expected: "std,cmd",
+		},
+		{
+			args:     []string{},
+			pkgs:     []*load.Package{pkgImportPath("gopkg.in/somelib")},
+			expected: "gopkg.in-somelib",
+		},
+		{
+			args:     []string{"./..."},
+			pkgs:     []*load.Package{pkgImportPath("somelib")},
+			expected: "somelib",
+			rootedAt: "somelib",
+		},
+		{
+			args:     []string{"../somelib", "../somelib"},
+			pkgs:     []*load.Package{pkgImportPath("somelib")},
+			expected: "somelib",
+		},
+		{
+			args:     []string{"../lib1", "../lib2"},
+			pkgs:     []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
+			expected: "gopkg.in-lib1,gopkg.in-lib2",
+		},
+		{
+			args: []string{"./..."},
+			pkgs: []*load.Package{
+				pkgImportPath("gopkg.in/dir/lib1"),
+				pkgImportPath("gopkg.in/lib2"),
+				pkgImportPath("gopkg.in/lib3"),
+			},
+			expected: "gopkg.in",
+			rootedAt: "gopkg.in",
+		},
+		{
+			args:      []string{"std", "../lib2"},
+			pkgs:      []*load.Package{},
+			expectErr: true,
+		},
+		{
+			args:      []string{"all", "./"},
+			pkgs:      []*load.Package{},
+			expectErr: true,
+		},
+		{
+			args:      []string{"cmd", "fmt"},
+			pkgs:      []*load.Package{},
+			expectErr: true,
+		},
+	}
+	for _, data := range testData {
+		func() {
+			if data.rootedAt != "" {
+				tmpGopath, err := ioutil.TempDir("", "gopath")
+				if err != nil {
+					t.Fatal(err)
+				}
+				oldGopath := cfg.BuildContext.GOPATH
+				defer func() {
+					cfg.BuildContext.GOPATH = oldGopath
+					os.Chdir(base.Cwd)
+					err := os.RemoveAll(tmpGopath)
+					if err != nil {
+						t.Error(err)
+					}
+				}()
+				root := filepath.Join(tmpGopath, "src", data.rootedAt)
+				err = os.MkdirAll(root, 0755)
+				if err != nil {
+					t.Fatal(err)
+				}
+				cfg.BuildContext.GOPATH = tmpGopath
+				os.Chdir(root)
+			}
+			computed, err := libname(data.args, data.pkgs)
+			if err != nil {
+				if !data.expectErr {
+					t.Errorf("libname returned an error %q, expected a name", err.Error())
+				}
+			} else if data.expectErr {
+				t.Errorf("libname returned %q, expected an error", computed)
+			} else {
+				expected := prefix + data.expected + suffix
+				if expected != computed {
+					t.Errorf("libname returned %q, expected %q", computed, expected)
+				}
+			}
+		}()
+	}
+}
+
+func pkgImportPath(pkgpath string) *load.Package {
+	return &load.Package{
+		PackagePublic: load.PackagePublic{
+			ImportPath: pkgpath,
+		},
+	}
+}
+
+// When installing packages, the installed package directory should
+// respect the SetGID bit and group name of the destination
+// directory.
+// See https://golang.org/issue/18878.
+func TestRespectSetgidDir(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("can't set SetGID bit with chmod on nacl")
+	}
+
+	var b Builder
+
+	// Check that `cp` is called instead of `mv` by looking at the output
+	// of `(*Builder).ShowCmd` afterwards as a sanity check.
+	cfg.BuildX = true
+	var cmdBuf bytes.Buffer
+	b.Print = func(a ...interface{}) (int, error) {
+		return cmdBuf.WriteString(fmt.Sprint(a...))
+	}
+
+	setgiddir, err := ioutil.TempDir("", "SetGroupID")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(setgiddir)
+
+	if runtime.GOOS == "freebsd" {
+		err = os.Chown(setgiddir, os.Getuid(), os.Getgid())
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	// Change setgiddir's permissions to include the SetGID bit.
+	if err := os.Chmod(setgiddir, 0755|os.ModeSetgid); err != nil {
+		t.Fatal(err)
+	}
+
+	pkgfile, err := ioutil.TempFile("", "pkgfile")
+	if err != nil {
+		t.Fatalf("ioutil.TempFile(\"\", \"pkgfile\"): %v", err)
+	}
+	defer os.Remove(pkgfile.Name())
+	defer pkgfile.Close()
+
+	dirGIDFile := filepath.Join(setgiddir, "setgid")
+	if err := b.moveOrCopyFile(nil, dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
+		t.Fatalf("moveOrCopyFile: %v", err)
+	}
+
+	got := strings.TrimSpace(cmdBuf.String())
+	want := b.fmtcmd("", "cp %s %s", pkgfile.Name(), dirGIDFile)
+	if got != want {
+		t.Fatalf("moveOrCopyFile(%q, %q): want %q, got %q", dirGIDFile, pkgfile.Name(), want, got)
+	}
+}
diff --git a/src/cmd/go/internal/work/testgo.go b/src/cmd/go/internal/work/testgo.go
new file mode 100644
index 0000000..3e623c6
--- /dev/null
+++ b/src/cmd/go/internal/work/testgo.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go 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 extra hooks for testing the go command.
+
+// +build testgo
+
+package work
+
+import "os"
+
+func init() {
+	if v := os.Getenv("TESTGO_VERSION"); v != "" {
+		runtimeVersion = v
+	}
+}
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
deleted file mode 100644
index 2f24083..0000000
--- a/src/cmd/go/list.go
+++ /dev/null
@@ -1,234 +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 main
-
-import (
-	"bufio"
-	"encoding/json"
-	"io"
-	"os"
-	"strings"
-	"text/template"
-)
-
-var cmdList = &Command{
-	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
-	Short:     "list packages",
-	Long: `
-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
-        TestGoFiles    []string // _test.go files in package
-        XTestGoFiles   []string // _test.go files outside package
-
-        // 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
-        TestImports  []string // imports from TestGoFiles
-        XTestImports []string // imports from XTestGoFiles
-
-        // Error information
-        Incomplete bool            // this package or a dependency has an error
-        Error      *PackageError   // error loading package
-        DepsErrors []*PackageError // errors loading dependencies
-    }
-
-Packages stored in vendor directories report an ImportPath that includes the
-path to the vendor directory (for example, "d/vendor/p" instead of "p"),
-so that the ImportPath uniquely identifies a given copy of a package.
-The Imports, Deps, TestImports, and XTestImports lists also contain these
-expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
-
-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'.
-	`,
-}
-
-func init() {
-	cmdList.Run = runList // break init cycle
-	addBuildFlags(cmdList)
-}
-
-var listE = cmdList.Flag.Bool("e", false, "")
-var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
-var listJson = cmdList.Flag.Bool("json", false, "")
-var nl = []byte{'\n'}
-
-func runList(cmd *Command, args []string) {
-	buildModeInit()
-	out := newTrackingWriter(os.Stdout)
-	defer out.w.Flush()
-
-	var do func(*Package)
-	if *listJson {
-		do = func(p *Package) {
-			b, err := json.MarshalIndent(p, "", "\t")
-			if err != nil {
-				out.Flush()
-				fatalf("%s", err)
-			}
-			out.Write(b)
-			out.Write(nl)
-		}
-	} else {
-		var cachedCtxt *Context
-		context := func() *Context {
-			if cachedCtxt == nil {
-				cachedCtxt = newContext(&buildContext)
-			}
-			return cachedCtxt
-		}
-		fm := template.FuncMap{
-			"join":    strings.Join,
-			"context": context,
-		}
-		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
-		if err != nil {
-			fatalf("%s", err)
-		}
-		do = func(p *Package) {
-			if err := tmpl.Execute(out, p); err != nil {
-				out.Flush()
-				fatalf("%s", err)
-			}
-			if out.NeedNL() {
-				out.Write(nl)
-			}
-		}
-	}
-
-	load := packages
-	if *listE {
-		load = packagesAndErrors
-	}
-
-	for _, pkg := range load(args) {
-		// Show vendor-expanded paths in listing
-		pkg.TestImports = pkg.vendored(pkg.TestImports)
-		pkg.XTestImports = pkg.vendored(pkg.XTestImports)
-
-		do(pkg)
-	}
-}
-
-// TrackingWriter tracks the last byte written on every write so
-// we can avoid printing a newline if one was already written or
-// if there is no output at all.
-type TrackingWriter struct {
-	w    *bufio.Writer
-	last byte
-}
-
-func newTrackingWriter(w io.Writer) *TrackingWriter {
-	return &TrackingWriter{
-		w:    bufio.NewWriter(w),
-		last: '\n',
-	}
-}
-
-func (t *TrackingWriter) Write(p []byte) (n int, err error) {
-	n, err = t.w.Write(p)
-	if n > 0 {
-		t.last = p[n-1]
-	}
-	return
-}
-
-func (t *TrackingWriter) Flush() {
-	t.w.Flush()
-}
-
-func (t *TrackingWriter) NeedNL() bool {
-	return t.last != '\n'
-}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index d80ff2d..75a46db 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -2,141 +2,90 @@
 // 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
 
 import (
-	"bufio"
-	"bytes"
 	"flag"
 	"fmt"
-	"go/build"
-	"io"
 	"log"
 	"os"
-	"os/exec"
-	"path"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"strings"
-	"sync"
-	"text/template"
-	"unicode"
-	"unicode/utf8"
-)
-
-// A Command is an implementation of a go command
-// like go build or go fix.
-type Command struct {
-	// Run runs the command.
-	// The args are the arguments after the command name.
-	Run func(cmd *Command, args []string)
-
-	// UsageLine is the one-line usage message.
-	// The first word in the line is taken to be the command name.
-	UsageLine string
-
-	// Short is the short description shown in the 'go help' output.
-	Short string
-
-	// Long is the long message shown in the 'go help <this-command>' output.
-	Long string
-
-	// Flag is a set of flags specific to this command.
-	Flag flag.FlagSet
 
-	// CustomFlags indicates that the command will do its own
-	// flag parsing.
-	CustomFlags bool
-}
-
-// Name returns the command's name: the first word in the usage line.
-func (c *Command) Name() string {
-	name := c.UsageLine
-	i := strings.Index(name, " ")
-	if i >= 0 {
-		name = name[:i]
-	}
-	return name
-}
-
-func (c *Command) Usage() {
-	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
-	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
-	os.Exit(2)
-}
-
-// Runnable reports whether the command can be run; otherwise
-// it is a documentation pseudo-command such as importpath.
-func (c *Command) Runnable() bool {
-	return c.Run != nil
-}
-
-// Commands lists the available commands and help topics.
-// The order here is the order in which they are printed by 'go help'.
-var commands = []*Command{
-	cmdBuild,
-	cmdClean,
-	cmdDoc,
-	cmdEnv,
-	cmdBug,
-	cmdFix,
-	cmdFmt,
-	cmdGenerate,
-	cmdGet,
-	cmdInstall,
-	cmdList,
-	cmdRun,
-	cmdTest,
-	cmdTool,
-	cmdVersion,
-	cmdVet,
-
-	helpC,
-	helpBuildmode,
-	helpFileType,
-	helpGopath,
-	helpEnvironment,
-	helpImportPath,
-	helpPackages,
-	helpTestflag,
-	helpTestfunc,
-}
-
-var exitStatus = 0
-var exitMu sync.Mutex
+	"cmd/go/internal/base"
+	"cmd/go/internal/bug"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/clean"
+	"cmd/go/internal/doc"
+	"cmd/go/internal/envcmd"
+	"cmd/go/internal/fix"
+	"cmd/go/internal/fmtcmd"
+	"cmd/go/internal/generate"
+	"cmd/go/internal/get"
+	"cmd/go/internal/help"
+	"cmd/go/internal/list"
+	"cmd/go/internal/run"
+	"cmd/go/internal/test"
+	"cmd/go/internal/tool"
+	"cmd/go/internal/version"
+	"cmd/go/internal/vet"
+	"cmd/go/internal/work"
+)
 
-func setExitStatus(n int) {
-	exitMu.Lock()
-	if exitStatus < n {
-		exitStatus = n
+func init() {
+	base.Commands = []*base.Command{
+		work.CmdBuild,
+		clean.CmdClean,
+		doc.CmdDoc,
+		envcmd.CmdEnv,
+		bug.CmdBug,
+		fix.CmdFix,
+		fmtcmd.CmdFmt,
+		generate.CmdGenerate,
+		get.CmdGet,
+		work.CmdInstall,
+		list.CmdList,
+		run.CmdRun,
+		test.CmdTest,
+		tool.CmdTool,
+		version.CmdVersion,
+		vet.CmdVet,
+
+		help.HelpC,
+		help.HelpBuildmode,
+		help.HelpFileType,
+		help.HelpGopath,
+		help.HelpEnvironment,
+		help.HelpImportPath,
+		help.HelpPackages,
+		test.HelpTestflag,
+		test.HelpTestfunc,
 	}
-	exitMu.Unlock()
 }
 
-var origEnv []string
-var newEnv []envVar
-
 func main() {
 	_ = go11tag
-	flag.Usage = usage
+	flag.Usage = base.Usage
 	flag.Parse()
 	log.SetFlags(0)
 
 	args := flag.Args()
 	if len(args) < 1 {
-		usage()
+		base.Usage()
 	}
 
 	if args[0] == "help" {
-		help(args[1:])
+		help.Help(args[1:])
 		return
 	}
 
 	// Diagnose common mistake: GOPATH==GOROOT.
 	// This setting is equivalent to not setting GOPATH at all,
 	// which is not what most people want when they do it.
-	if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
+	if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
 		fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
 	} else {
 		for _, p := range filepath.SplitList(gopath) {
@@ -154,8 +103,8 @@ func main() {
 		}
 	}
 
-	if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
-		fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
+	if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
+		fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
 		os.Exit(2)
 	}
 
@@ -164,15 +113,15 @@ func main() {
 	// the same default computation of these as we do,
 	// but in practice there might be skew
 	// This makes sure we all agree.
-	origEnv = os.Environ()
-	newEnv = mkEnv()
-	for _, env := range newEnv {
-		if os.Getenv(env.name) != env.value {
-			os.Setenv(env.name, env.value)
+	cfg.OrigEnv = os.Environ()
+	cfg.CmdEnv = envcmd.MkEnv()
+	for _, env := range cfg.CmdEnv {
+		if os.Getenv(env.Name) != env.Value {
+			os.Setenv(env.Name, env.Value)
 		}
 	}
 
-	for _, cmd := range commands {
+	for _, cmd := range base.Commands {
 		if cmd.Name() == args[0] && cmd.Runnable() {
 			cmd.Flag.Usage = func() { cmd.Usage() }
 			if cmd.CustomFlags {
@@ -182,615 +131,25 @@ func main() {
 				args = cmd.Flag.Args()
 			}
 			cmd.Run(cmd, args)
-			exit()
+			base.Exit()
 			return
 		}
 	}
 
 	fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
-	setExitStatus(2)
-	exit()
+	base.SetExitStatus(2)
+	base.Exit()
 }
 
-var usageTemplate = `Go is a tool for managing Go source code.
-
-Usage:
-
-	go command [arguments]
-
-The commands are:
-{{range .}}{{if .Runnable}}
-	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-
-Use "go help [command]" for more information about a command.
-
-Additional help topics:
-{{range .}}{{if not .Runnable}}
-	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-
-Use "go help [topic]" for more information about that topic.
-
-`
-
-var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
-
-{{end}}{{.Long | trim}}
-`
-
-var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
-
-{{end}}{{if .Runnable}}Usage:
-
-	go {{.UsageLine}}
-
-{{end}}{{.Long | trim}}
-
-
-{{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
+func init() {
+	base.Usage = mainUsage
 }
 
-// An errWriter wraps a writer, recording whether a write error occurred.
-type errWriter struct {
-	w   io.Writer
-	err error
-}
-
-func (w *errWriter) Write(b []byte) (int, error) {
-	n, err := w.w.Write(b)
-	if err != nil {
-		w.err = err
-	}
-	return n, err
-}
-
-// tmpl executes the given template text on data, writing the result to w.
-func tmpl(w io.Writer, text string, data interface{}) {
-	t := template.New("top")
-	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
-	template.Must(t.Parse(text))
-	ew := &errWriter{w: w}
-	err := t.Execute(ew, data)
-	if ew.err != nil {
-		// I/O error writing. Ignore write on closed pipe.
-		if strings.Contains(ew.err.Error(), "pipe") {
-			os.Exit(1)
-		}
-		fatalf("writing output: %v", ew.err)
-	}
-	if err != nil {
-		panic(err)
-	}
-}
-
-func capitalize(s string) string {
-	if s == "" {
-		return s
-	}
-	r, n := utf8.DecodeRuneInString(s)
-	return string(unicode.ToTitle(r)) + s[n:]
-}
-
-func printUsage(w io.Writer) {
-	bw := bufio.NewWriter(w)
-	tmpl(bw, usageTemplate, commands)
-	bw.Flush()
-}
-
-func usage() {
+func mainUsage() {
 	// special case "go test -h"
 	if len(os.Args) > 1 && os.Args[1] == "test" {
-		os.Stderr.WriteString(testUsage + "\n\n" +
-			strings.TrimSpace(testFlag1) + "\n\n\t" +
-			strings.TrimSpace(testFlag2) + "\n")
-		os.Exit(2)
+		test.Usage()
 	}
-	printUsage(os.Stderr)
+	help.PrintUsage(os.Stderr)
 	os.Exit(2)
 }
-
-// help implements the 'help' command.
-func help(args []string) {
-	if len(args) == 0 {
-		printUsage(os.Stdout)
-		// not exit 2: succeeded at 'go help'.
-		return
-	}
-	if len(args) != 1 {
-		fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
-		os.Exit(2) // failed at 'go help'
-	}
-
-	arg := args[0]
-
-	// '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(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
-		fmt.Println("package main")
-		return
-	}
-
-	for _, cmd := range commands {
-		if cmd.Name() == arg {
-			tmpl(os.Stdout, helpTemplate, cmd)
-			// not exit 2: succeeded at 'go help cmd'.
-			return
-		}
-	}
-
-	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run 'go help'.\n", arg)
-	os.Exit(2) // failed at 'go help cmd'
-}
-
-// importPathsNoDotExpansion returns the import paths to use for the given
-// command line, but it does no ... expansion.
-func importPathsNoDotExpansion(args []string) []string {
-	if len(args) == 0 {
-		return []string{"."}
-	}
-	var out []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.
-		if filepath.Separator == '\\' {
-			a = strings.Replace(a, `\`, `/`, -1)
-		}
-
-		// Put argument in canonical form, but preserve leading ./.
-		if strings.HasPrefix(a, "./") {
-			a = "./" + path.Clean(a)
-			if a == "./." {
-				a = "."
-			}
-		} else {
-			a = path.Clean(a)
-		}
-		if isMetaPackage(a) {
-			out = append(out, allPackages(a)...)
-			continue
-		}
-		out = append(out, a)
-	}
-	return out
-}
-
-// importPaths returns the import paths to use for the given command line.
-func importPaths(args []string) []string {
-	args = importPathsNoDotExpansion(args)
-	var out []string
-	for _, a := range args {
-		if strings.Contains(a, "...") {
-			if build.IsLocalImport(a) {
-				out = append(out, allPackagesInFS(a)...)
-			} else {
-				out = append(out, allPackages(a)...)
-			}
-			continue
-		}
-		out = append(out, a)
-	}
-	return out
-}
-
-var atexitFuncs []func()
-
-func atexit(f func()) {
-	atexitFuncs = append(atexitFuncs, f)
-}
-
-func exit() {
-	for _, f := range atexitFuncs {
-		f()
-	}
-	os.Exit(exitStatus)
-}
-
-func fatalf(format string, args ...interface{}) {
-	errorf(format, args...)
-	exit()
-}
-
-func errorf(format string, args ...interface{}) {
-	log.Printf(format, args...)
-	setExitStatus(1)
-}
-
-func exitIfErrors() {
-	if exitStatus != 0 {
-		exit()
-	}
-}
-
-func run(cmdargs ...interface{}) {
-	cmdline := stringList(cmdargs...)
-	if buildN || buildX {
-		fmt.Printf("%s\n", strings.Join(cmdline, " "))
-		if buildN {
-			return
-		}
-	}
-
-	cmd := exec.Command(cmdline[0], cmdline[1:]...)
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if err := cmd.Run(); err != nil {
-		errorf("%v", err)
-	}
-}
-
-// envForDir returns a copy of the environment
-// suitable for running in the given directory.
-// The environment is the current process's environment
-// but with an updated $PWD, so that an os.Getwd in the
-// child will be faster.
-func envForDir(dir string, base []string) []string {
-	// Internally we only use rooted paths, so dir is rooted.
-	// Even if dir is not rooted, no harm done.
-	return mergeEnvLists([]string{"PWD=" + dir}, base)
-}
-
-// 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
-}
-
-// matchPattern(pattern)(name) reports whether
-// 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 {
-	re := regexp.QuoteMeta(pattern)
-	re = strings.Replace(re, `\.\.\.`, `.*`, -1)
-	// Special case: foo/... matches foo too.
-	if strings.HasSuffix(re, `/.*`) {
-		re = re[:len(re)-len(`/.*`)] + `(/.*)?`
-	}
-	reg := regexp.MustCompile(`^` + re + `$`)
-	return func(name string) bool {
-		return reg.MatchString(name)
-	}
-}
-
-// hasPathPrefix reports whether the path s begins with the
-// elements in prefix.
-func hasPathPrefix(s, prefix string) bool {
-	switch {
-	default:
-		return false
-	case len(s) == len(prefix):
-		return s == prefix
-	case len(s) > len(prefix):
-		if prefix != "" && prefix[len(prefix)-1] == '/' {
-			return strings.HasPrefix(s, prefix)
-		}
-		return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
-	}
-}
-
-// hasFilePathPrefix reports whether the filesystem path s begins with the
-// elements in prefix.
-func hasFilePathPrefix(s, prefix string) bool {
-	sv := strings.ToUpper(filepath.VolumeName(s))
-	pv := strings.ToUpper(filepath.VolumeName(prefix))
-	s = s[len(sv):]
-	prefix = prefix[len(pv):]
-	switch {
-	default:
-		return false
-	case sv != pv:
-		return false
-	case len(s) == len(prefix):
-		return s == prefix
-	case len(s) > len(prefix):
-		if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
-			return strings.HasPrefix(s, prefix)
-		}
-		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
-	}
-}
-
-// expandPath returns the symlink-expanded form of path.
-func expandPath(p string) string {
-	x, err := filepath.EvalSymlinks(p)
-	if err == nil {
-		return x
-	}
-	return p
-}
-
-// treeCanMatchPattern(pattern)(name) reports whether
-// name or children of name can possibly match pattern.
-// Pattern is the same limited glob accepted by matchPattern.
-func treeCanMatchPattern(pattern string) func(name string) bool {
-	wildCard := false
-	if i := strings.Index(pattern, "..."); i >= 0 {
-		wildCard = true
-		pattern = pattern[:i]
-	}
-	return func(name string) bool {
-		return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
-			wildCard && strings.HasPrefix(name, pattern)
-	}
-}
-
-// allPackages returns all the packages that can be found
-// under the $GOPATH directories and $GOROOT matching pattern.
-// The pattern is either "all" (all packages), "std" (standard packages),
-// "cmd" (standard commands), or a path including "...".
-func allPackages(pattern string) []string {
-	pkgs := matchPackages(pattern)
-	if len(pkgs) == 0 {
-		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
-	}
-	return pkgs
-}
-
-func matchPackages(pattern string) []string {
-	match := func(string) bool { return true }
-	treeCanMatch := func(string) bool { return true }
-	if !isMetaPackage(pattern) {
-		match = matchPattern(pattern)
-		treeCanMatch = treeCanMatchPattern(pattern)
-	}
-
-	have := map[string]bool{
-		"builtin": true, // ignore pseudo-package that exists only for documentation
-	}
-	if !buildContext.CgoEnabled {
-		have["runtime/cgo"] = true // ignore during walk
-	}
-	var pkgs []string
-
-	for _, src := range buildContext.SrcDirs() {
-		if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
-			continue
-		}
-		src = filepath.Clean(src) + string(filepath.Separator)
-		root := src
-		if pattern == "cmd" {
-			root += "cmd" + string(filepath.Separator)
-		}
-		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
-			if err != nil || !fi.IsDir() || path == src {
-				return nil
-			}
-
-			// Avoid .foo, _foo, and testdata directory trees.
-			_, elem := filepath.Split(path)
-			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
-				return filepath.SkipDir
-			}
-
-			name := filepath.ToSlash(path[len(src):])
-			if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
-				// The name "std" is only the standard library.
-				// If the name is cmd, it's the root of the command tree.
-				return filepath.SkipDir
-			}
-			if !treeCanMatch(name) {
-				return filepath.SkipDir
-			}
-			if have[name] {
-				return nil
-			}
-			have[name] = true
-			if !match(name) {
-				return nil
-			}
-			_, err = buildContext.ImportDir(path, 0)
-			if err != nil {
-				if _, noGo := err.(*build.NoGoError); noGo {
-					return nil
-				}
-			}
-			pkgs = append(pkgs, name)
-			return nil
-		})
-	}
-	return pkgs
-}
-
-// 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.
-func allPackagesInFS(pattern string) []string {
-	pkgs := matchPackagesInFS(pattern)
-	if len(pkgs) == 0 {
-		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
-	}
-	return pkgs
-}
-
-func matchPackagesInFS(pattern string) []string {
-	// Find directory to begin the scan.
-	// Could be smarter but this one optimization
-	// is enough for now, since ... is usually at the
-	// end of a path.
-	i := strings.Index(pattern, "...")
-	dir, _ := path.Split(pattern[:i])
-
-	// pattern begins with ./ or ../.
-	// path.Clean will discard the ./ but not the ../.
-	// We need to preserve the ./ for pattern matching
-	// and in the returned import paths.
-	prefix := ""
-	if strings.HasPrefix(pattern, "./") {
-		prefix = "./"
-	}
-	match := matchPattern(pattern)
-
-	var pkgs []string
-	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
-		if err != nil || !fi.IsDir() {
-			return nil
-		}
-		if path == dir {
-			// filepath.Walk starts at dir and recurses. For the recursive case,
-			// the path is the result of filepath.Join, which calls filepath.Clean.
-			// The initial case is not Cleaned, though, so we do this explicitly.
-			//
-			// This converts a path like "./io/" to "io". Without this step, running
-			// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
-			// package, because prepending the prefix "./" to the unclean path would
-			// result in "././io", and match("././io") returns false.
-			path = filepath.Clean(path)
-		}
-
-		// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
-		_, elem := filepath.Split(path)
-		dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
-		if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
-			return filepath.SkipDir
-		}
-
-		name := prefix + filepath.ToSlash(path)
-		if !match(name) {
-			return nil
-		}
-
-		// We keep the directory if we can import it, or if we can't import it
-		// due to invalid Go source files. This means that directories containing
-		// parse errors will be built (and fail) instead of being silently skipped
-		// as not matching the pattern. Go 1.5 and earlier skipped, but that
-		// behavior means people miss serious mistakes.
-		// See golang.org/issue/11407.
-		if p, err := buildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
-			if _, noGo := err.(*build.NoGoError); !noGo {
-				log.Print(err)
-			}
-			return nil
-		}
-		pkgs = append(pkgs, name)
-		return nil
-	})
-	return pkgs
-}
-
-// stringList's arguments should be a sequence of string or []string values.
-// stringList flattens them into a single []string.
-func stringList(args ...interface{}) []string {
-	var x []string
-	for _, arg := range args {
-		switch arg := arg.(type) {
-		case []string:
-			x = append(x, arg...)
-		case string:
-			x = append(x, arg)
-		default:
-			panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
-		}
-	}
-	return x
-}
-
-// toFold returns a string with the property that
-//	strings.EqualFold(s, t) iff toFold(s) == toFold(t)
-// This lets us test a large set of strings for fold-equivalent
-// duplicates without making a quadratic number of calls
-// to EqualFold. Note that strings.ToUpper and strings.ToLower
-// have the desired property in some corner cases.
-func toFold(s string) string {
-	// Fast path: all ASCII, no upper case.
-	// Most paths look like this already.
-	for i := 0; i < len(s); i++ {
-		c := s[i]
-		if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
-			goto Slow
-		}
-	}
-	return s
-
-Slow:
-	var buf bytes.Buffer
-	for _, r := range s {
-		// SimpleFold(x) cycles to the next equivalent rune > x
-		// or wraps around to smaller values. Iterate until it wraps,
-		// and we've found the minimum value.
-		for {
-			r0 := r
-			r = unicode.SimpleFold(r0)
-			if r <= r0 {
-				break
-			}
-		}
-		// Exception to allow fast path above: A-Z => a-z
-		if 'A' <= r && r <= 'Z' {
-			r += 'a' - 'A'
-		}
-		buf.WriteRune(r)
-	}
-	return buf.String()
-}
-
-// foldDup reports a pair of strings from the list that are
-// equal according to strings.EqualFold.
-// It returns "", "" if there are no such strings.
-func foldDup(list []string) (string, string) {
-	clash := map[string]string{}
-	for _, s := range list {
-		fold := toFold(s)
-		if t := clash[fold]; t != "" {
-			if s > t {
-				s, t = t, s
-			}
-			return s, t
-		}
-		clash[fold] = s
-	}
-	return "", ""
-}
diff --git a/src/cmd/go/match_test.go b/src/cmd/go/match_test.go
deleted file mode 100644
index e0ad562..0000000
--- a/src/cmd/go/match_test.go
+++ /dev/null
@@ -1,88 +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 main
-
-import "testing"
-
-var matchPatternTests = []stringPairTest{
-	{"...", "foo", true},
-	{"net", "net", true},
-	{"net", "net/http", false},
-	{"net/http", "net", false},
-	{"net/http", "net/http", true},
-	{"net...", "netchan", true},
-	{"net...", "net", true},
-	{"net...", "net/http", true},
-	{"net...", "not/http", false},
-	{"net/...", "netchan", false},
-	{"net/...", "net", true},
-	{"net/...", "net/http", true},
-	{"net/...", "not/http", false},
-}
-
-func TestMatchPattern(t *testing.T) {
-	testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
-		return matchPattern(pattern)(name)
-	})
-}
-
-var treeCanMatchPatternTests = []stringPairTest{
-	{"...", "foo", true},
-	{"net", "net", true},
-	{"net", "net/http", false},
-	{"net/http", "net", true},
-	{"net/http", "net/http", true},
-	{"net...", "netchan", true},
-	{"net...", "net", true},
-	{"net...", "net/http", true},
-	{"net...", "not/http", false},
-	{"net/...", "netchan", false},
-	{"net/...", "net", true},
-	{"net/...", "net/http", true},
-	{"net/...", "not/http", false},
-	{"abc.../def", "abcxyz", true},
-	{"abc.../def", "xyxabc", false},
-	{"x/y/z/...", "x", true},
-	{"x/y/z/...", "x/y", true},
-	{"x/y/z/...", "x/y/z", true},
-	{"x/y/z/...", "x/y/z/w", true},
-	{"x/y/z", "x", true},
-	{"x/y/z", "x/y", true},
-	{"x/y/z", "x/y/z", true},
-	{"x/y/z", "x/y/z/w", false},
-	{"x/.../y/z", "x/a/b/c", true},
-	{"x/.../y/z", "y/x/a/b/c", false},
-}
-
-func TestChildrenCanMatchPattern(t *testing.T) {
-	testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
-		return treeCanMatchPattern(pattern)(name)
-	})
-}
-
-var hasPathPrefixTests = []stringPairTest{
-	{"abc", "a", false},
-	{"a/bc", "a", true},
-	{"a", "a", true},
-	{"a/bc", "a/", true},
-}
-
-func TestHasPathPrefix(t *testing.T) {
-	testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
-}
-
-type stringPairTest struct {
-	in1 string
-	in2 string
-	out bool
-}
-
-func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
-	for _, tt := range tests {
-		if out := f(tt.in1, tt.in2); out != tt.out {
-			t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
-		}
-	}
-}
diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go
deleted file mode 100644
index fae9536..0000000
--- a/src/cmd/go/note.go
+++ /dev/null
@@ -1,187 +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 (
-	"bytes"
-	"debug/elf"
-	"debug/macho"
-	"encoding/binary"
-	"fmt"
-	"io"
-	"os"
-)
-
-func readAligned4(r io.Reader, sz int32) ([]byte, error) {
-	full := (sz + 3) &^ 3
-	data := make([]byte, full)
-	_, err := io.ReadFull(r, data)
-	if err != nil {
-		return nil, err
-	}
-	data = data[:sz]
-	return data, nil
-}
-
-func readELFNote(filename, name string, typ int32) ([]byte, error) {
-	f, err := elf.Open(filename)
-	if err != nil {
-		return nil, err
-	}
-	for _, sect := range f.Sections {
-		if sect.Type != elf.SHT_NOTE {
-			continue
-		}
-		r := sect.Open()
-		for {
-			var namesize, descsize, noteType int32
-			err = binary.Read(r, f.ByteOrder, &namesize)
-			if err != nil {
-				if err == io.EOF {
-					break
-				}
-				return nil, fmt.Errorf("read namesize failed: %v", err)
-			}
-			err = binary.Read(r, f.ByteOrder, &descsize)
-			if err != nil {
-				return nil, fmt.Errorf("read descsize failed: %v", err)
-			}
-			err = binary.Read(r, f.ByteOrder, &noteType)
-			if err != nil {
-				return nil, fmt.Errorf("read type failed: %v", err)
-			}
-			noteName, err := readAligned4(r, namesize)
-			if err != nil {
-				return nil, fmt.Errorf("read name failed: %v", err)
-			}
-			desc, err := readAligned4(r, descsize)
-			if err != nil {
-				return nil, fmt.Errorf("read desc failed: %v", err)
-			}
-			if name == string(noteName) && typ == noteType {
-				return desc, nil
-			}
-		}
-	}
-	return nil, nil
-}
-
-var elfGoNote = []byte("Go\x00\x00")
-
-// 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
-// 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.
-	// Rewrite the ELF header to set shnum to 0, so that we can pass
-	// the data to elf.NewFile and it will decode the Prog list but not
-	// try to read the section headers and the string table from disk.
-	// That's a waste of I/O when all we care about is the Prog list
-	// and the one ELF note.
-	switch elf.Class(data[elf.EI_CLASS]) {
-	case elf.ELFCLASS32:
-		data[48] = 0
-		data[49] = 0
-	case elf.ELFCLASS64:
-		data[60] = 0
-		data[61] = 0
-	}
-
-	const elfGoBuildIDTag = 4
-
-	ef, err := elf.NewFile(bytes.NewReader(data))
-	if err != nil {
-		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
-	}
-	for _, p := range ef.Progs {
-		if p.Type != elf.PT_NOTE || p.Filesz < 16 {
-			continue
-		}
-
-		var note []byte
-		if p.Off+p.Filesz < uint64(len(data)) {
-			note = data[p.Off : p.Off+p.Filesz]
-		} else {
-			// For some linkers, such as the Solaris linker,
-			// the buildid may not be found in data (which
-			// likely contains the first 16kB of the file)
-			// 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), io.SeekStart)
-			if err != nil {
-				return "", err
-			}
-
-			note = make([]byte, p.Filesz)
-			_, err = io.ReadFull(f, note)
-			if err != nil {
-				return "", err
-			}
-		}
-
-		filesz := p.Filesz
-		for filesz >= 16 {
-			nameSize := ef.ByteOrder.Uint32(note)
-			valSize := ef.ByteOrder.Uint32(note[4:])
-			tag := ef.ByteOrder.Uint32(note[8:])
-			name := note[12:16]
-			if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == elfGoBuildIDTag && bytes.Equal(name, elfGoNote) {
-				return string(note[16 : 16+valSize]), nil
-			}
-
-			nameSize = (nameSize + 3) &^ 3
-			valSize = (valSize + 3) &^ 3
-			notesz := uint64(12 + nameSize + valSize)
-			if filesz <= notesz {
-				break
-			}
-			filesz -= notesz
-			note = note[notesz:]
-		}
-	}
-
-	// No note. Treat as successful but build ID empty.
-	return "", nil
-}
-
-// The Go build ID is stored at the beginning of the Mach-O __text segment.
-// The caller has already opened filename, to get f, and read a few kB out, in data.
-// Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount
-// of other junk placed in the file ahead of the main text.
-func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
-	// If the data we want has already been read, don't worry about Mach-O parsing.
-	// This is both an optimization and a hedge against the Mach-O parsing failing
-	// in the future due to, for example, the name of the __text section changing.
-	if b, err := readRawGoBuildID(filename, data); b != "" && err == nil {
-		return b, err
-	}
-
-	mf, err := macho.NewFile(f)
-	if err != nil {
-		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
-	}
-
-	sect := mf.Section("__text")
-	if sect == nil {
-		// Every binary has a __text section. Something is wrong.
-		return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
-	}
-
-	// It should be in the first few bytes, but read a lot just in case,
-	// especially given our past problems on OS X with the build ID moving.
-	// There shouldn't be much difference between reading 4kB and 32kB:
-	// the hard part is getting to the data, not transferring it.
-	n := sect.Size
-	if n > uint64(BuildIDReadSize) {
-		n = uint64(BuildIDReadSize)
-	}
-	buf := make([]byte, n)
-	if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil {
-		return "", err
-	}
-
-	return readRawGoBuildID(filename, buf)
-}
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 2ee013f..289af99 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -5,10 +5,11 @@
 package main_test
 
 import (
-	main "cmd/go"
 	"go/build"
 	"runtime"
 	"testing"
+
+	"cmd/go/internal/buildid"
 )
 
 func TestNoteReading(t *testing.T) {
@@ -21,9 +22,9 @@ func TestNoteReading2K(t *testing.T) {
 	}
 	// Set BuildIDReadSize to 2kB to exercise Mach-O parsing more strictly.
 	defer func(old int) {
-		main.BuildIDReadSize = old
-	}(main.BuildIDReadSize)
-	main.BuildIDReadSize = 2 * 1024
+		buildid.BuildIDReadSize = old
+	}(buildid.BuildIDReadSize)
+	buildid.BuildIDReadSize = 2 * 1024
 
 	testNoteReading(t)
 }
@@ -34,7 +35,7 @@ func testNoteReading(t *testing.T) {
 	tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`)
 	const buildID = "TestNoteReading-Build-ID"
 	tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go"))
-	id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe"))
+	id, err := buildid.ReadBuildIDFromBinary(tg.path("hello.exe"))
 	if err != nil {
 		t.Fatalf("reading build ID from hello binary: %v", err)
 	}
@@ -54,7 +55,7 @@ func testNoteReading(t *testing.T) {
 	}
 
 	tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
-	id, err = main.ReadBuildIDFromBinary(tg.path("hello.exe"))
+	id, err = buildid.ReadBuildIDFromBinary(tg.path("hello.exe"))
 	if err != nil {
 		t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
 	}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
deleted file mode 100644
index 575f187..0000000
--- a/src/cmd/go/pkg.go
+++ /dev/null
@@ -1,2032 +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 main
-
-import (
-	"bytes"
-	"crypto/sha1"
-	"errors"
-	"fmt"
-	"go/build"
-	"go/scanner"
-	"go/token"
-	"io"
-	"io/ioutil"
-	"os"
-	pathpkg "path"
-	"path/filepath"
-	"runtime"
-	"sort"
-	"strconv"
-	"strings"
-	"unicode"
-)
-
-var ignoreImports bool // control whether we ignore imports in packages
-
-// 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
-	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
-	Name          string `json:",omitempty"` // package name
-	Doc           string `json:",omitempty"` // package documentation string
-	Target        string `json:",omitempty"` // install path
-	Shlib         string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
-	Goroot        bool   `json:",omitempty"` // is this package found in the Go root?
-	Standard      bool   `json:",omitempty"` // is this package part of the standard Go library?
-	Stale         bool   `json:",omitempty"` // would 'go install' do anything for this package?
-	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)
-	CgoFiles       []string `json:",omitempty"` // .go sources files that import "C"
-	IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
-	CFiles         []string `json:",omitempty"` // .c source files
-	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
-	SysoFiles      []string `json:",omitempty"` // .syso system object files added to package
-
-	// Cgo directives
-	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
-
-	// Dependency information
-	Imports []string `json:",omitempty"` // import paths used by this package
-	Deps    []string `json:",omitempty"` // all (recursively) imported dependencies
-
-	// Error information
-	Incomplete bool            `json:",omitempty"` // was there an error loading this package or dependencies?
-	Error      *PackageError   `json:",omitempty"` // error loading this package (not dependencies)
-	DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
-
-	// Test information
-	TestGoFiles  []string `json:",omitempty"` // _test.go files in package
-	TestImports  []string `json:",omitempty"` // imports from TestGoFiles
-	XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
-	XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
-
-	// Unexported fields are not part of the public API.
-	build        *build.Package
-	pkgdir       string // overrides build.PkgDir
-	imports      []*Package
-	deps         []*Package
-	gofiles      []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
-	sfiles       []string
-	allgofiles   []string             // gofiles + IgnoredGoFiles, absolute paths
-	target       string               // installed file for this package (may be executable)
-	fake         bool                 // synthesized package
-	external     bool                 // synthesized external test package
-	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 ../)
-	localPrefix  string               // interpret ./ and ../ imports relative to this prefix
-	exeName      string               // desired name for temporary executable
-	coverMode    string               // preprocess Go source files with the coverage tool in this mode
-	coverVars    map[string]*CoverVar // variables created by coverage analysis
-	omitDWARF    bool                 // tell linker not to write DWARF information
-	buildID      string               // expected build ID for generated package
-	gobinSubdir  bool                 // install target would be subdir of GOBIN
-}
-
-// vendored returns the vendor-resolved version of imports,
-// which should be p.TestImports or p.XTestImports, NOT p.Imports.
-// The imports in p.TestImports and p.XTestImports are not recursively
-// loaded during the initial load of p, so they list the imports found in
-// the source file, but most processing should be over the vendor-resolved
-// import paths. We do this resolution lazily both to avoid file system work
-// and because the eventual real load of the test imports (during 'go test')
-// can produce better error messages if it starts with the original paths.
-// The initial load of p loads all the non-test imports and rewrites
-// the vendored paths, so nothing should ever call p.vendored(p.Imports).
-func (p *Package) vendored(imports []string) []string {
-	if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
-		panic("internal error: p.vendored(p.Imports) called")
-	}
-	seen := make(map[string]bool)
-	var all []string
-	for _, path := range imports {
-		path = vendoredImportPath(p, path)
-		if !seen[path] {
-			seen[path] = true
-			all = append(all, path)
-		}
-	}
-	sort.Strings(all)
-	return all
-}
-
-// CoverVar holds the name of the generated coverage variables targeting the named file.
-type CoverVar struct {
-	File string // local file name
-	Var  string // name of count struct
-}
-
-func (p *Package) copyBuild(pp *build.Package) {
-	p.build = pp
-
-	if pp.PkgTargetRoot != "" && buildPkgdir != "" {
-		old := pp.PkgTargetRoot
-		pp.PkgRoot = buildPkgdir
-		pp.PkgTargetRoot = buildPkgdir
-		pp.PkgObj = filepath.Join(buildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
-	}
-
-	p.Dir = pp.Dir
-	p.ImportPath = pp.ImportPath
-	p.ImportComment = pp.ImportComment
-	p.Name = pp.Name
-	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)
-	p.GoFiles = pp.GoFiles
-	p.CgoFiles = pp.CgoFiles
-	p.IgnoredGoFiles = pp.IgnoredGoFiles
-	p.CFiles = pp.CFiles
-	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
-	p.SysoFiles = pp.SysoFiles
-	p.CgoCFLAGS = pp.CgoCFLAGS
-	p.CgoCPPFLAGS = pp.CgoCPPFLAGS
-	p.CgoCXXFLAGS = pp.CgoCXXFLAGS
-	p.CgoLDFLAGS = pp.CgoLDFLAGS
-	p.CgoPkgConfig = pp.CgoPkgConfig
-	// We modify p.Imports in place, so make copy now.
-	p.Imports = make([]string, len(pp.Imports))
-	copy(p.Imports, pp.Imports)
-	p.TestGoFiles = pp.TestGoFiles
-	p.TestImports = pp.TestImports
-	p.XTestGoFiles = pp.XTestGoFiles
-	p.XTestImports = pp.XTestImports
-	if ignoreImports {
-		p.Imports = nil
-		p.TestImports = nil
-		p.XTestImports = nil
-	}
-}
-
-// isStandardImportPath reports whether $GOROOT/src/path should be considered
-// part of the standard distribution. For historical reasons we allow people to add
-// their own code to $GOROOT instead of using $GOPATH, but we assume that
-// code will start with a domain name (dot in the first element).
-func isStandardImportPath(path string) bool {
-	i := strings.Index(path, "/")
-	if i < 0 {
-		i = len(path)
-	}
-	elem := path[:i]
-	return !strings.Contains(elem, ".")
-}
-
-// A PackageError describes an error loading information about a package.
-type PackageError struct {
-	ImportStack   []string // shortest path from package named on command line to this one
-	Pos           string   // position of error
-	Err           string   // the error itself
-	isImportCycle bool     // the error is an import cycle
-	hard          bool     // whether the error is soft or hard; soft errors are ignored in some places
-}
-
-func (p *PackageError) Error() string {
-	// Import cycles deserve special treatment.
-	if p.isImportCycle {
-		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
-		// is the most important thing.
-		return p.Pos + ": " + p.Err
-	}
-	if len(p.ImportStack) == 0 {
-		return p.Err
-	}
-	return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
-}
-
-// An importStack is a stack of import paths.
-type importStack []string
-
-func (s *importStack) push(p string) {
-	*s = append(*s, p)
-}
-
-func (s *importStack) pop() {
-	*s = (*s)[0 : len(*s)-1]
-}
-
-func (s *importStack) copy() []string {
-	return append([]string{}, *s...)
-}
-
-// shorterThan reports whether sp is shorter than t.
-// We use this to record the shortest import sequence
-// that leads to a particular package.
-func (sp *importStack) shorterThan(t []string) bool {
-	s := *sp
-	if len(s) != len(t) {
-		return len(s) < len(t)
-	}
-	// If they are the same length, settle ties using string ordering.
-	for i := range s {
-		if s[i] != t[i] {
-			return s[i] < t[i]
-		}
-	}
-	return false // they are equal
-}
-
-// packageCache is a lookup cache for loadPackage,
-// so that if we look up a package multiple times
-// we return the same pointer each time.
-var packageCache = map[string]*Package{}
-
-// reloadPackage is like loadPackage but makes sure
-// not to use the package cache.
-func reloadPackage(arg string, stk *importStack) *Package {
-	p := packageCache[arg]
-	if p != nil {
-		delete(packageCache, p.Dir)
-		delete(packageCache, p.ImportPath)
-	}
-	return loadPackage(arg, stk)
-}
-
-// 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
-// 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
-// automatically.
-func dirToImportPath(dir string) string {
-	return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
-}
-
-func makeImportValid(r rune) rune {
-	// Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport.
-	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
-	if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
-		return '_'
-	}
-	return r
-}
-
-// Mode flags for loadImport and download (in get.go).
-const (
-	// useVendor means that loadImport should do vendor expansion
-	// (provided the vendoring experiment is enabled).
-	// That is, useVendor means that the import path came from
-	// a source file and has not been vendor-expanded yet.
-	// Every import path should be loaded initially with useVendor,
-	// and then the expanded version (with the /vendor/ in it) gets
-	// recorded as the canonical import path. At that point, future loads
-	// of that package must not pass useVendor, because
-	// disallowVendor will reject direct use of paths containing /vendor/.
-	useVendor = 1 << iota
-
-	// getTestDeps is for download (part of "go get") and indicates
-	// that test dependencies should be fetched too.
-	getTestDeps
-)
-
-// loadImport scans the directory named by path, which must be an import path,
-// but possibly a local import path (an absolute file system path or one beginning
-// with ./ or ../).  A local relative path is interpreted relative to srcDir.
-// It returns a *Package describing the package found in that directory.
-func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package {
-	stk.push(path)
-	defer stk.pop()
-
-	// Determine canonical identifier for this package.
-	// For a local import the identifier is the pseudo-import path
-	// we create from the full directory to the package.
-	// Otherwise it is the usual import path.
-	// For vendored imports, it is the expanded form.
-	importPath := path
-	origPath := path
-	isLocal := build.IsLocalImport(path)
-	if isLocal {
-		importPath = dirToImportPath(filepath.Join(srcDir, path))
-	} else if mode&useVendor != 0 {
-		// We do our own vendor resolution, because we want to
-		// find out the key to use in packageCache without the
-		// overhead of repeated calls to buildContext.Import.
-		// The code is also needed in a few other places anyway.
-		path = vendoredImportPath(parent, path)
-		importPath = path
-	}
-
-	p := packageCache[importPath]
-	if p != nil {
-		p = reusePackage(p, stk)
-	} else {
-		p = new(Package)
-		p.local = isLocal
-		p.ImportPath = importPath
-		packageCache[importPath] = p
-
-		// Load package.
-		// Import always returns bp != nil, even if an error occurs,
-		// in order to return partial information.
-		//
-		// TODO: After Go 1, decide when to pass build.AllowBinary here.
-		// See issue 3268 for mistakes to avoid.
-		buildMode := build.ImportComment
-		if mode&useVendor == 0 || path != origPath {
-			// Not vendoring, or we already found the vendored path.
-			buildMode |= build.IgnoreVendor
-		}
-		bp, err := buildContext.Import(path, srcDir, buildMode)
-		bp.ImportPath = importPath
-		if gobin != "" {
-			bp.BinDir = gobin
-		}
-		if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
-			!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)
-		if p.Error != nil && p.Error.Pos == "" {
-			p = setErrorPos(p, importPos)
-		}
-
-		if origPath != cleanImport(origPath) {
-			p.Error = &PackageError{
-				ImportStack: stk.copy(),
-				Err:         fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
-			}
-			p.Incomplete = true
-		}
-	}
-
-	// Checked on every import because the rules depend on the code doing the importing.
-	if perr := disallowInternal(srcDir, p, stk); perr != p {
-		return setErrorPos(perr, importPos)
-	}
-	if mode&useVendor != 0 {
-		if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
-			return setErrorPos(perr, importPos)
-		}
-	}
-
-	if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
-		perr := *p
-		perr.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("import %q is a program, not an importable package", path),
-		}
-		return setErrorPos(&perr, importPos)
-	}
-
-	if p.local && parent != nil && !parent.local {
-		perr := *p
-		perr.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("local import %q in non-local package", path),
-		}
-		return setErrorPos(&perr, importPos)
-	}
-
-	return p
-}
-
-func setErrorPos(p *Package, importPos []token.Position) *Package {
-	if len(importPos) > 0 {
-		pos := importPos[0]
-		pos.Filename = shortPath(pos.Filename)
-		p.Error.Pos = pos.String()
-	}
-	return p
-}
-
-func cleanImport(path string) string {
-	orig := path
-	path = pathpkg.Clean(path)
-	if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
-		path = "./" + path
-	}
-	return path
-}
-
-var isDirCache = map[string]bool{}
-
-func isDir(path string) bool {
-	result, ok := isDirCache[path]
-	if ok {
-		return result
-	}
-
-	fi, err := os.Stat(path)
-	result = err == nil && fi.IsDir()
-	isDirCache[path] = result
-	return result
-}
-
-// vendoredImportPath returns the expansion of path when it appears in parent.
-// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
-// x/vendor/path, vendor/path, or else stay 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 == "" {
-		return path
-	}
-
-	dir := filepath.Clean(parent.Dir)
-	root := filepath.Join(parent.Root, "src")
-	if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
-		// Look for symlinks before reporting error.
-		dir = expandPath(dir)
-		root = expandPath(root)
-	}
-
-	if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.local && filepath.Join(root, parent.ImportPath) != dir {
-		fatalf("unexpected directory layout:\n"+
-			"	import path: %s\n"+
-			"	root: %s\n"+
-			"	dir: %s\n"+
-			"	expand root: %s\n"+
-			"	expand dir: %s\n"+
-			"	separator: %s",
-			parent.ImportPath,
-			filepath.Join(parent.Root, "src"),
-			filepath.Clean(parent.Dir),
-			root,
-			dir,
-			string(filepath.Separator))
-	}
-
-	vpath := "vendor/" + path
-	for i := len(dir); i >= len(root); i-- {
-		if i < len(dir) && dir[i] != filepath.Separator {
-			continue
-		}
-		// Note: checking for the vendor directory before checking
-		// for the vendor/path directory helps us hit the
-		// isDir cache more often. It also helps us prepare a more useful
-		// list of places we looked, to report when an import is not found.
-		if !isDir(filepath.Join(dir[:i], "vendor")) {
-			continue
-		}
-		targ := filepath.Join(dir[:i], vpath)
-		if isDir(targ) && hasGoFiles(targ) {
-			importPath := parent.ImportPath
-			if importPath == "command-line-arguments" {
-				// If parent.ImportPath is 'command-line-arguments'.
-				// set to relative directory to root (also chopped root directory)
-				importPath = dir[len(root)+1:]
-			}
-			// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
-			// We know the import path for parent's dir.
-			// We chopped off some number of path elements and
-			// added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.
-			// Now we want to know the import path for that directory.
-			// Construct it by chopping the same number of path elements
-			// (actually the same number of bytes) from parent's import path
-			// and then append /vendor/path.
-			chopped := len(dir) - i
-			if chopped == len(importPath)+1 {
-				// We walked up from c:\gopath\src\foo\bar
-				// and found c:\gopath\src\vendor\path.
-				// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
-				// Use "vendor/path" without any prefix.
-				return vpath
-			}
-			return importPath[:len(importPath)-chopped] + "/" + vpath
-		}
-	}
-	return path
-}
-
-// hasGoFiles reports whether dir contains any files with names ending in .go.
-// For a vendor check we must exclude directories that contain no .go files.
-// Otherwise it is not possible to vendor just a/b/c and still import the
-// non-vendored a/b. See golang.org/issue/13832.
-func hasGoFiles(dir string) bool {
-	fis, _ := ioutil.ReadDir(dir)
-	for _, fi := range fis {
-		if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
-			return true
-		}
-	}
-	return false
-}
-
-// reusePackage reuses package p to satisfy the import at the top
-// of the import stack stk. If this use causes an import loop,
-// reusePackage updates p's error information to record the loop.
-func reusePackage(p *Package, stk *importStack) *Package {
-	// We use p.imports==nil to detect a package that
-	// is in the midst of its own loadPackage call
-	// (all the recursion below happens before p.imports gets set).
-	if p.imports == nil {
-		if p.Error == nil {
-			p.Error = &PackageError{
-				ImportStack:   stk.copy(),
-				Err:           "import cycle not allowed",
-				isImportCycle: true,
-			}
-		}
-		p.Incomplete = true
-	}
-	// Don't rewrite the import stack in the error if we have an import cycle.
-	// If we do, we'll lose the path that describes the cycle.
-	if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
-		p.Error.ImportStack = stk.copy()
-	}
-	return p
-}
-
-// disallowInternal checks that srcDir is allowed to import p.
-// If the import is allowed, disallowInternal returns the original package p.
-// If not, it returns a new package containing just an appropriate error.
-func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
-	// golang.org/s/go14internal:
-	// An import of a path containing the element “internal”
-	// is disallowed if the importing code is outside the tree
-	// rooted at the parent of the “internal” directory.
-
-	// There was an error loading the package; stop here.
-	if p.Error != nil {
-		return p
-	}
-
-	// The generated 'testmain' package is allowed to access testing/internal/...,
-	// as if it were generated into the testing directory tree
-	// (it's actually in a temporary directory outside any Go tree).
-	// This cleans up a former kludge in passing functionality to the testing package.
-	if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
-		return p
-	}
-
-	// We can't check standard packages with gccgo.
-	if buildContext.Compiler == "gccgo" && p.Standard {
-		return p
-	}
-
-	// The stack includes p.ImportPath.
-	// If that's the only thing on the stack, we started
-	// with a name given on the command line, not an
-	// import. Anything listed on the command line is fine.
-	if len(*stk) == 1 {
-		return p
-	}
-
-	// 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
-	}
-
-	// Internal is present.
-	// Map import path back to directory corresponding to parent of internal.
-	if i > 0 {
-		i-- // rewind over slash in ".../internal"
-	}
-	parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
-	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
-		return p
-	}
-
-	// Look for symlinks before reporting error.
-	srcDir = expandPath(srcDir)
-	parent = expandPath(parent)
-	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
-		return p
-	}
-
-	// Internal is present, and srcDir is outside parent's tree. Not allowed.
-	perr := *p
-	perr.Error = &PackageError{
-		ImportStack: stk.copy(),
-		Err:         "use of internal package not allowed",
-	}
-	perr.Incomplete = true
-	return &perr
-}
-
-// findInternal looks for the final "internal" path element in the given import path.
-// 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) {
-	// 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.
-	switch {
-	case strings.HasSuffix(path, "/internal"):
-		return len(path) - len("internal"), true
-	case strings.Contains(path, "/internal/"):
-		return strings.LastIndex(path, "/internal/") + 1, true
-	case path == "internal", strings.HasPrefix(path, "internal/"):
-		return 0, true
-	}
-	return 0, false
-}
-
-// disallowVendor checks that srcDir is allowed to import p as path.
-// If the import is allowed, disallowVendor returns the original package p.
-// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
-	// The stack includes p.ImportPath.
-	// If that's the only thing on the stack, we started
-	// with a name given on the command line, not an
-	// import. Anything listed on the command line is fine.
-	if len(*stk) == 1 {
-		return p
-	}
-
-	if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
-		return perr
-	}
-
-	// Paths like x/vendor/y must be imported as y, never as x/vendor/y.
-	if i, ok := findVendor(path); ok {
-		perr := *p
-		perr.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         "must be imported as " + path[i+len("vendor/"):],
-		}
-		perr.Incomplete = true
-		return &perr
-	}
-
-	return p
-}
-
-// disallowVendorVisibility checks that srcDir is allowed to import p.
-// The rules are the same as for /internal/ except that a path ending in /vendor
-// is not subject to the rules, only subdirectories of vendor.
-// This allows people to have packages and commands named vendor,
-// for maximal compatibility with existing source trees.
-func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package {
-	// The stack includes p.ImportPath.
-	// If that's the only thing on the stack, we started
-	// with a name given on the command line, not an
-	// import. Anything listed on the command line is fine.
-	if len(*stk) == 1 {
-		return p
-	}
-
-	// Check for "vendor" element.
-	i, ok := findVendor(p.ImportPath)
-	if !ok {
-		return p
-	}
-
-	// Vendor is present.
-	// Map import path back to directory corresponding to parent of vendor.
-	if i > 0 {
-		i-- // rewind over slash in ".../vendor"
-	}
-	truncateTo := i + len(p.Dir) - len(p.ImportPath)
-	if truncateTo < 0 || len(p.Dir) < truncateTo {
-		return p
-	}
-	parent := p.Dir[:truncateTo]
-	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
-		return p
-	}
-
-	// Look for symlinks before reporting error.
-	srcDir = expandPath(srcDir)
-	parent = expandPath(parent)
-	if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
-		return p
-	}
-
-	// Vendor is present, and srcDir is outside parent's tree. Not allowed.
-	perr := *p
-	perr.Error = &PackageError{
-		ImportStack: stk.copy(),
-		Err:         "use of vendored package not allowed",
-	}
-	perr.Incomplete = true
-	return &perr
-}
-
-// findVendor looks for the last non-terminating "vendor" path element in the given import path.
-// If there isn't one, findVendor returns ok=false.
-// Otherwise, 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).
-// This will allow people to have packages or commands named vendor.
-// This may help reduce breakage, or it may just be confusing. We'll see.
-func findVendor(path string) (index int, ok bool) {
-	// Two cases, depending on internal at start of string or not.
-	// The order matters: we must return the index of the final element,
-	// because the final one is where the effective import path starts.
-	switch {
-	case strings.Contains(path, "/vendor/"):
-		return strings.LastIndex(path, "/vendor/") + 1, true
-	case strings.HasPrefix(path, "vendor/"):
-		return 0, true
-	}
-	return 0, false
-}
-
-type targetDir int
-
-const (
-	toRoot    targetDir = iota // to bin dir inside package root (default)
-	toTool                     // GOROOT/pkg/tool
-	stalePath                  // the old import path; fail to build
-)
-
-// goTools is a map of Go program import path to install target directory.
-var goTools = map[string]targetDir{
-	"cmd/addr2line": toTool,
-	"cmd/api":       toTool,
-	"cmd/asm":       toTool,
-	"cmd/compile":   toTool,
-	"cmd/cgo":       toTool,
-	"cmd/cover":     toTool,
-	"cmd/dist":      toTool,
-	"cmd/doc":       toTool,
-	"cmd/fix":       toTool,
-	"cmd/link":      toTool,
-	"cmd/newlink":   toTool,
-	"cmd/nm":        toTool,
-	"cmd/objdump":   toTool,
-	"cmd/pack":      toTool,
-	"cmd/pprof":     toTool,
-	"cmd/trace":     toTool,
-	"cmd/vet":       toTool,
-	"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,
-}
-
-// expandScanner expands a scanner.List error into all the errors in the list.
-// The default Error method only shows the first error.
-func expandScanner(err error) error {
-	// Look for parser errors.
-	if err, ok := err.(scanner.ErrorList); ok {
-		// 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
-		// instead of just the first, as err.Error does.
-		var buf bytes.Buffer
-		for _, e := range err {
-			e.Pos.Filename = shortPath(e.Pos.Filename)
-			buf.WriteString("\n")
-			buf.WriteString(e.Error())
-		}
-		return errors.New(buf.String())
-	}
-	return err
-}
-
-var raceExclude = map[string]bool{
-	"runtime/race": true,
-	"runtime/msan": true,
-	"runtime/cgo":  true,
-	"cmd/cgo":      true,
-	"syscall":      true,
-	"errors":       true,
-}
-
-var cgoExclude = map[string]bool{
-	"runtime/cgo": true,
-}
-
-var cgoSyscallExclude = map[string]bool{
-	"runtime/cgo":  true,
-	"runtime/race": true,
-	"runtime/msan": true,
-}
-
-// load populates p using information from bp, err, which should
-// be the result of calling build.Context.Import.
-func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
-	p.copyBuild(bp)
-
-	// The localPrefix is the path we interpret ./ imports relative to.
-	// Synthesized main packages sometimes override this.
-	p.localPrefix = dirToImportPath(p.Dir)
-
-	if err != nil {
-		p.Incomplete = true
-		err = expandScanner(err)
-		p.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         err.Error(),
-		}
-		return p
-	}
-
-	useBindir := p.Name == "main"
-	if !p.Standard {
-		switch buildBuildmode {
-		case "c-archive", "c-shared", "plugin":
-			useBindir = false
-		}
-	}
-
-	if useBindir {
-		// Report an error when the old code.google.com/p/go.tools paths are used.
-		if goTools[p.ImportPath] == stalePath {
-			newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
-			e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
-			p.Error = &PackageError{Err: e}
-			return p
-		}
-		_, elem := filepath.Split(p.Dir)
-		full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
-		if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
-			// Install cross-compiled binaries to subdirectories of bin.
-			elem = full
-		}
-		if p.build.BinDir != "" {
-			// Install to GOBIN or bin of GOPATH entry.
-			p.target = filepath.Join(p.build.BinDir, elem)
-			if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
-				// Do not create $GOBIN/goos_goarch/elem.
-				p.target = ""
-				p.gobinSubdir = true
-			}
-		}
-		if goTools[p.ImportPath] == toTool {
-			// This is for 'go tool'.
-			// Override all the usual logic and force it into the tool directory.
-			p.target = filepath.Join(gorootPkg, "tool", full)
-		}
-		if p.target != "" && buildContext.GOOS == "windows" {
-			p.target += ".exe"
-		}
-	} else if p.local {
-		// Local import turned into absolute path.
-		// No permanent install target.
-		p.target = ""
-	} else {
-		p.target = p.build.PkgObj
-		if buildLinkshared {
-			shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
-			shlib, err := ioutil.ReadFile(shlibnamefile)
-			if err == nil {
-				libname := strings.TrimSpace(string(shlib))
-				if buildContext.Compiler == "gccgo" {
-					p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname)
-				} else {
-					p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
-
-				}
-			} else if !os.IsNotExist(err) {
-				fatalf("unexpected error reading %s: %v", shlibnamefile, err)
-			}
-		}
-	}
-
-	importPaths := p.Imports
-	// Packages that use cgo import runtime/cgo implicitly.
-	// Packages that use cgo also import syscall implicitly,
-	// to wrap errno.
-	// Exclude certain packages to avoid circular dependencies.
-	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
-		importPaths = append(importPaths, "runtime/cgo")
-	}
-	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
-		importPaths = append(importPaths, "syscall")
-	}
-
-	if buildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
-		// Currently build modes c-shared, pie (on systems that do not
-		// support PIE with internal linking mode), plugin, and
-		// -linkshared force external linking mode, as of course does
-		// -ldflags=-linkmode=external. External linking mode forces
-		// an import of runtime/cgo.
-		pieCgo := buildBuildmode == "pie" && (buildContext.GOOS != "linux" || buildContext.GOARCH != "amd64")
-		linkmodeExternal := false
-		for i, a := range buildLdflags {
-			if a == "-linkmode=external" {
-				linkmodeExternal = true
-			}
-			if a == "-linkmode" && i+1 < len(buildLdflags) && buildLdflags[i+1] == "external" {
-				linkmodeExternal = true
-			}
-		}
-		if buildBuildmode == "c-shared" || buildBuildmode == "plugin" || pieCgo || buildLinkshared || linkmodeExternal {
-			importPaths = append(importPaths, "runtime/cgo")
-		}
-	}
-
-	// Everything depends on runtime, except runtime, its internal
-	// subpackages, and unsafe.
-	if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") {
-		importPaths = append(importPaths, "runtime")
-		// When race detection enabled everything depends on runtime/race.
-		// Exclude certain packages to avoid circular dependencies.
-		if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
-			importPaths = append(importPaths, "runtime/race")
-		}
-		// MSan uses runtime/msan.
-		if buildMSan && (!p.Standard || !raceExclude[p.ImportPath]) {
-			importPaths = append(importPaths, "runtime/msan")
-		}
-		// On ARM with GOARM=5, everything depends on math for the link.
-		if p.Name == "main" && goarch == "arm" {
-			importPaths = append(importPaths, "math")
-		}
-	}
-
-	// Runtime and its internal packages depend on runtime/internal/sys,
-	// so that they pick up the generated zversion.go file.
-	// This can be an issue particularly for runtime/internal/atomic;
-	// see issue 13655.
-	if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" {
-		importPaths = append(importPaths, "runtime/internal/sys")
-	}
-
-	// Build list of full paths to all Go files in the package,
-	// for use by commands like go fmt.
-	p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
-	for i := range p.gofiles {
-		p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
-	}
-	sort.Strings(p.gofiles)
-
-	p.sfiles = stringList(p.SFiles)
-	for i := range p.sfiles {
-		p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
-	}
-	sort.Strings(p.sfiles)
-
-	p.allgofiles = stringList(p.IgnoredGoFiles)
-	for i := range p.allgofiles {
-		p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
-	}
-	p.allgofiles = append(p.allgofiles, p.gofiles...)
-	sort.Strings(p.allgofiles)
-
-	// Check for case-insensitive collision of input files.
-	// To avoid problems on case-insensitive files, we reject any package
-	// where two different input files have equal names under a case-insensitive
-	// comparison.
-	f1, f2 := foldDup(stringList(
-		p.GoFiles,
-		p.CgoFiles,
-		p.IgnoredGoFiles,
-		p.CFiles,
-		p.CXXFiles,
-		p.MFiles,
-		p.HFiles,
-		p.FFiles,
-		p.SFiles,
-		p.SysoFiles,
-		p.SwigFiles,
-		p.SwigCXXFiles,
-		p.TestGoFiles,
-		p.XTestGoFiles,
-	))
-	if f1 != "" {
-		p.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
-		}
-		return p
-	}
-
-	// Build list of imported packages and full dependency list.
-	imports := make([]*Package, 0, len(p.Imports))
-	deps := make(map[string]*Package)
-	save := func(path string, p1 *Package) {
-		// The same import path could produce an error or not,
-		// depending on what tries to import it.
-		// Prefer to record entries with errors, so we can report them.
-		p0 := deps[path]
-		if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
-			deps[path] = p1
-		}
-	}
-
-	for i, path := range importPaths {
-		if path == "C" {
-			continue
-		}
-		p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor)
-		if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
-			p.Error = &PackageError{
-				ImportStack: stk.copy(),
-				Err:         fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
-			}
-			pos := p.build.ImportPos[path]
-			if len(pos) > 0 {
-				p.Error.Pos = pos[0].String()
-			}
-		}
-
-		path = p1.ImportPath
-		importPaths[i] = path
-		if i < len(p.Imports) {
-			p.Imports[i] = path
-		}
-
-		save(path, p1)
-		imports = append(imports, p1)
-		for _, dep := range p1.deps {
-			save(dep.ImportPath, dep)
-		}
-		if p1.Incomplete {
-			p.Incomplete = true
-		}
-	}
-	p.imports = imports
-
-	p.Deps = make([]string, 0, len(deps))
-	for dep := range deps {
-		p.Deps = append(p.Deps, dep)
-	}
-	sort.Strings(p.Deps)
-	for _, dep := range p.Deps {
-		p1 := deps[dep]
-		if p1 == nil {
-			panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
-		}
-		p.deps = append(p.deps, p1)
-		if p1.Error != nil {
-			p.DepsErrors = append(p.DepsErrors, p1.Error)
-		}
-	}
-
-	// unsafe is a fake package.
-	if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
-		p.target = ""
-	}
-	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{
-			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
-		}
-		return p
-	}
-
-	// In the absence of errors lower in the dependency tree,
-	// check for case-insensitive collisions of import paths.
-	if len(p.DepsErrors) == 0 {
-		dep1, dep2 := foldDup(p.Deps)
-		if dep1 != "" {
-			p.Error = &PackageError{
-				ImportStack: stk.copy(),
-				Err:         fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
-			}
-			return 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
-}
-
-// usesSwig reports whether the package needs to run SWIG.
-func (p *Package) usesSwig() bool {
-	return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
-}
-
-// usesCgo reports whether the package needs to run cgo
-func (p *Package) usesCgo() bool {
-	return len(p.CgoFiles) > 0
-}
-
-// packageList returns the list of packages in the dag rooted at roots
-// as visited in a depth-first post-order traversal.
-func packageList(roots []*Package) []*Package {
-	seen := map[*Package]bool{}
-	all := []*Package{}
-	var walk func(*Package)
-	walk = func(p *Package) {
-		if seen[p] {
-			return
-		}
-		seen[p] = true
-		for _, p1 := range p.imports {
-			walk(p1)
-		}
-		all = append(all, p)
-	}
-	for _, root := range roots {
-		walk(root)
-	}
-	return all
-}
-
-// computeStale computes the Stale flag in the package dag that starts
-// at the named pkgs (command-line arguments).
-func computeStale(pkgs ...*Package) {
-	for _, p := range packageList(pkgs) {
-		p.Stale, p.StaleReason = isStale(p)
-	}
-}
-
-// 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")
-
-// isStale and computeBuildID
-//
-// Theory of Operation
-//
-// There is an installed copy of the package (or binary).
-// Can we reuse the installed copy, or do we need to build a new one?
-//
-// We can use the installed copy if it matches what we'd get
-// by building a new one. The hard part is predicting that without
-// actually running a build.
-//
-// To start, we must know the set of inputs to the build process that can
-// affect the generated output. At a minimum, that includes the source
-// files for the package and also any compiled packages imported by those
-// source files. The *Package has these, and we use them. One might also
-// argue for including in the input set: the build tags, whether the race
-// detector is in use, the target operating system and architecture, the
-// compiler and linker binaries being used, the additional flags being
-// passed to those, the cgo binary being used, the additional flags cgo
-// passes to the host C compiler, the host C compiler being used, the set
-// of host C include files and installed C libraries, and so on.
-// We include some but not all of this information.
-//
-// Once we have decided on a set of inputs, we must next decide how to
-// tell whether the content of that set has changed since the last build
-// of p. If there have been no changes, then we assume a new build would
-// produce the same result and reuse the installed package or binary.
-// But if there have been changes, then we assume a new build might not
-// produce the same result, so we rebuild.
-//
-// There are two common ways to decide whether the content of the set has
-// changed: modification times and content hashes. We use a mixture of both.
-//
-// The use of modification times (mtimes) was pioneered by make:
-// assuming that a file's mtime is an accurate record of when that file was last written,
-// and assuming that the modification time of an installed package or
-// binary is the time that it was built, if the mtimes of the inputs
-// predate the mtime of the installed object, then the build of that
-// object saw those versions of the files, and therefore a rebuild using
-// those same versions would produce the same object. In contrast, if any
-// mtime of an input is newer than the mtime of the installed object, a
-// change has occurred since the build, and the build should be redone.
-//
-// Modification times are attractive because the logic is easy to
-// understand and the file system maintains the mtimes automatically
-// (less work for us). Unfortunately, there are a variety of ways in
-// which the mtime approach fails to detect a change and reuses a stale
-// object file incorrectly. (Making the opposite mistake, rebuilding
-// unnecessarily, is only a performance problem and not a correctness
-// problem, so we ignore that one.)
-//
-// As a warmup, one problem is that to be perfectly precise, we need to
-// compare the input mtimes against the time at the beginning of the
-// build, but the object file time is the time at the end of the build.
-// If an input file changes after being read but before the object is
-// written, the next build will see an object newer than the input and
-// will incorrectly decide that the object is up to date. We make no
-// attempt to detect or solve this problem.
-//
-// Another problem is that due to file system imprecision, an input and
-// output that are actually ordered in time have the same mtime.
-// This typically happens on file systems with 1-second (or, worse,
-// 2-second) mtime granularity and with automated scripts that write an
-// input and then immediately run a build, or vice versa. If an input and
-// an output have the same mtime, the conservative behavior is to treat
-// the output as out-of-date and rebuild. This can cause one or more
-// spurious rebuilds, but only for 1 second, until the object finally has
-// an mtime later than the input.
-//
-// Another problem is that binary distributions often set the mtime on
-// all files to the same time. If the distribution includes both inputs
-// and cached build outputs, the conservative solution to the previous
-// problem will cause unnecessary rebuilds. Worse, in such a binary
-// distribution, those rebuilds might not even have permission to update
-// the cached build output. To avoid these write errors, if an input and
-// output have the same mtime, we assume the output is up-to-date.
-// This is the opposite of what the previous problem would have us do,
-// but binary distributions are more common than instances of the
-// previous problem.
-//
-// A variant of the last problem is that some binary distributions do not
-// set the mtime on all files to the same time. Instead they let the file
-// system record mtimes as the distribution is unpacked. If the outputs
-// are unpacked before the inputs, they'll be older and a build will try
-// to rebuild them. That rebuild might hit the same write errors as in
-// the last scenario. We don't make any attempt to solve this, and we
-// haven't had many reports of it. Perhaps the only time this happens is
-// when people manually unpack the distribution, and most of the time
-// that's done as the same user who will be using it, so an initial
-// rebuild on first use succeeds quietly.
-//
-// More generally, people and programs change mtimes on files. The last
-// few problems were specific examples of this, but it's a general problem.
-// For example, instead of a binary distribution, copying a home
-// directory from one directory or machine to another might copy files
-// but not preserve mtimes. If the inputs are new than the outputs on the
-// first machine but copied first, they end up older than the outputs on
-// the second machine.
-//
-// Because many other build systems have the same sensitivity to mtimes,
-// most programs manipulating source code take pains not to break the
-// mtime assumptions. For example, Git does not set the mtime of files
-// during a checkout operation, even when checking out an old version of
-// the code. This decision was made specifically to work well with
-// mtime-based build systems.
-//
-// The killer problem, though, for mtime-based build systems is that the
-// build only has access to the mtimes of the inputs that still exist.
-// If it is possible to remove an input without changing any other inputs,
-// a later build will think the object is up-to-date when it is not.
-// This happens for Go because a package is made up of all source
-// files in a directory. If a source file is removed, there is no newer
-// mtime available recording that fact. The mtime on the directory could
-// be used, but it also changes when unrelated files are added to or
-// removed from the directory, so including the directory mtime would
-// cause unnecessary rebuilds, possibly many. It would also exacerbate
-// the problems mentioned earlier, since even programs that are careful
-// to maintain mtimes on files rarely maintain mtimes on directories.
-//
-// A variant of the last problem is when the inputs change for other
-// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg
-// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a.
-// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must
-// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date.
-// If Go 1.5 has just been installed, perhaps the compiler will have a
-// newer mtime; since the compiler is considered an input, that would
-// trigger a rebuild. But only once, and only the last Go 1.4 build of
-// mypkg.a happened before Go 1.5 was installed. If a user has the two
-// versions installed in different locations and flips back and forth,
-// mtimes alone cannot tell what to do. Changing the toolchain is
-// changing the set of inputs, without affecting any mtimes.
-//
-// To detect the set of inputs changing, we turn away from mtimes and to
-// an explicit data comparison. Specifically, we build a list of the
-// inputs to the build, compute its SHA1 hash, and record that as the
-// ``build ID'' in the generated object. At the next build, we can
-// recompute the 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.
-//
-// Because this build ID is computed before the build begins, the
-// comparison does not have the race that mtime comparison does.
-//
-// Making the build sensitive to changes in other state is
-// straightforward: include the state in the build ID hash, and if it
-// changes, so does the build ID, triggering a rebuild.
-//
-// To detect changes in toolchain, we include the toolchain version in
-// the build ID hash for package runtime, and then we include the build
-// IDs of all imported packages in the build ID for p.
-//
-// It is natural to think about including build tags in the build ID, but
-// the naive approach of just dumping the tags into the hash would cause
-// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag'
-// produce the same binaries (assuming neverusedtag is never used).
-// A more precise approach would be to include only tags that have an
-// effect on the build. But the effect of a tag on the build is to
-// include or exclude a file from the compilation, and that file list is
-// already in the build ID hash. So the build ID is already tag-sensitive
-// in a perfectly precise way. So we do NOT explicitly add build tags to
-// the build ID hash.
-//
-// We do not include as part of the build ID the operating system,
-// architecture, or whether the race detector is enabled, even though all
-// three have an effect on the output, because that information is used
-// to decide the install location. Binaries for linux and binaries for
-// darwin are written to different directory trees; including that
-// information in the build ID is unnecessary (although it would be
-// harmless).
-//
-// TODO(rsc): Investigate the cost of putting source file content into
-// the build ID hash as a replacement for the use of mtimes. Using the
-// file content would avoid all the mtime problems, but it does require
-// reading all the source files, something we avoid today (we read the
-// beginning to find the build tags and the imports, but we stop as soon
-// as we see the import block is over). If the package is stale, the compiler
-// is going to read the files anyway. But if the package is up-to-date, the
-// read is overhead.
-//
-// TODO(rsc): Investigate the complexity of making the build more
-// precise about when individual results are needed. To be fully precise,
-// there are two results of a compilation: the entire .a file used by the link
-// and the subpiece used by later compilations (__.PKGDEF only).
-// If a rebuild is needed but produces the previous __.PKGDEF, then
-// no more recompilation due to the rebuilt package is needed, only
-// relinking. To date, there is nothing in the Go command to express this.
-//
-// Special Cases
-//
-// When the go command makes the wrong build decision and does not
-// rebuild something it should, users fall back to adding the -a flag.
-// Any common use of the -a flag should be considered prima facie evidence
-// that isStale is returning an incorrect false result in some important case.
-// Bugs reported in the behavior of -a itself should prompt the question
-// ``Why is -a being used at all? What bug does that indicate?''
-//
-// There is a long history of changes to isStale to try to make -a into a
-// suitable workaround for bugs in the mtime-based decisions.
-// It is worth recording that history to inform (and, as much as possible, deter) future changes.
-//
-// (1) Before the build IDs were introduced, building with alternate tags
-// would happily reuse installed objects built without those tags.
-// For example, "go build -tags netgo myprog.go" would use the installed
-// copy of package net, even if that copy had been built without netgo.
-// (The netgo tag controls whether package net uses cgo or pure Go for
-// functionality such as name resolution.)
-// Using the installed non-netgo package defeats the purpose.
-//
-// Users worked around this with "go build -tags netgo -a myprog.go".
-//
-// Build IDs have made that workaround unnecessary:
-// "go build -tags netgo myprog.go"
-// cannot use a non-netgo copy of package net.
-//
-// (2) Before the build IDs were introduced, building with different toolchains,
-// especially changing between toolchains, tried to reuse objects stored in
-// $GOPATH/pkg, resulting in link-time errors about object file mismatches.
-//
-// Users worked around this with "go install -a ./...".
-//
-// Build IDs have made that workaround unnecessary:
-// "go install ./..." will rebuild any objects it finds that were built against
-// a different toolchain.
-//
-// (3) The common use of "go install -a ./..." led to reports of problems
-// when the -a forced the rebuild of the standard library, which for some
-// users was not writable. Because we didn't understand that the real
-// problem was the bug -a was working around, we changed -a not to
-// apply to the standard library.
-//
-// (4) The common use of "go build -tags netgo -a myprog.go" broke
-// when we changed -a not to apply to the standard library, because
-// if go build doesn't rebuild package net, it uses the non-netgo version.
-//
-// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go".
-// The -installsuffix here is making the go command look for packages
-// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH.
-// Since the former presumably doesn't exist, go build decides to rebuild
-// everything, including the standard library. Since go build doesn't
-// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf,
-// so repeated invocations continue to work.
-//
-// If the use of -a wasn't a red flag, the use of -installsuffix to point to
-// a non-existent directory in a command that installs nothing should
-// have been.
-//
-// (5) Now that (1) and (2) no longer need -a, we have removed the kludge
-// introduced in (3): once again, -a means ``rebuild everything,'' not
-// ``rebuild everything except the standard library.'' Only Go 1.4 had
-// the restricted meaning.
-//
-// In addition to these cases trying to trigger rebuilds, there are
-// special cases trying NOT to trigger rebuilds. The main one is that for
-// a variety of reasons (see above), the install process for a Go release
-// cannot be relied upon to set the mtimes such that the go command will
-// think the standard library is up to date. So the mtime evidence is
-// ignored for the standard library if we find ourselves in a release
-// version of Go. Build ID-based staleness checks still apply to the
-// standard library, even in release versions. This makes
-// 'go build -tags netgo' work, among other things.
-
-// isStale reports whether package p needs to be rebuilt,
-// 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, "builtin package"
-	}
-	if p.Error != nil {
-		return true, "errors loading package"
-	}
-	if p.Stale {
-		return true, p.StaleReason
-	}
-
-	// 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, "build -a flag in use"
-	}
-
-	// 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, "cannot stat install target"
-	}
-
-	// Package is stale if the expected build ID differs from the
-	// recorded build ID. This catches changes like a source file
-	// being removed from a package directory. See issue 3895.
-	// It also catches changes in build tags that affect the set of
-	// files being compiled. See issue 9369.
-	// It also catches changes in toolchain, like when flipping between
-	// two versions of Go compiling a single GOPATH.
-	// See issue 8290 and issue 10702.
-	targetBuildID, err := readBuildID(p)
-	if err == nil && targetBuildID != p.buildID {
-		return true, "build ID mismatch"
-	}
-
-	// Package is stale if a dependency is.
-	for _, p1 := range p.deps {
-		if p1.Stale {
-			return true, "stale dependency"
-		}
-	}
-
-	// The checks above are content-based staleness.
-	// We assume they are always accurate.
-	//
-	// The checks below are mtime-based staleness.
-	// We hope they are accurate, but we know that they fail in the case of
-	// prebuilt Go installations that don't preserve the build mtimes
-	// (for example, if the pkg/ mtimes are before the src/ mtimes).
-	// See the large comment above isStale for details.
-
-	// If we are running a release copy of Go and didn't find a content-based
-	// reason to rebuild the standard packages, do not rebuild them.
-	// They may not be writable anyway, but they are certainly not changing.
-	// This makes 'go build' skip the standard packages when
-	// using an official release, even when the mtimes have been changed.
-	// See issue 3036, issue 3149, issue 4106, issue 8290.
-	// (If a change to a release tree must be made by hand, the way to force the
-	// install is to run make.bash, which will remove the old package archives
-	// before rebuilding.)
-	if p.Standard && isGoRelease {
-		return false, "standard package in Go release distribution"
-	}
-
-	// Time-based staleness.
-
-	built := fi.ModTime()
-
-	olderThan := func(file string) bool {
-		fi, err := os.Stat(file)
-		return err != nil || fi.ModTime().After(built)
-	}
-
-	// 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, "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
-	// back-dated, as some binary distributions may do, but it does handle
-	// a very common case.
-	// See issue 3036.
-	// Exclude $GOROOT, under the assumption that people working on
-	// the compiler may want to control when everything gets rebuilt,
-	// and people updating the Go repository will run make.bash or all.bash
-	// and get a full rebuild anyway.
-	// Excluding $GOROOT used to also fix issue 4106, but that's now
-	// taken care of above (at least when the installed Go is a released version).
-	if p.Root != goroot {
-		if olderThan(buildToolchain.compiler()) {
-			return true, "newer compiler"
-		}
-		if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
-			return true, "newer linker"
-		}
-	}
-
-	// Note: Until Go 1.5, we had an additional shortcut here.
-	// We built a list of the workspace roots ($GOROOT, each $GOPATH)
-	// containing targets directly named on the command line,
-	// and if p were not in any of those, it would be treated as up-to-date
-	// as long as it is built. The goal was to avoid rebuilding a system-installed
-	// $GOROOT, unless something from $GOROOT were explicitly named
-	// on the command line (like go install math).
-	// That's now handled by the isGoRelease clause above.
-	// The other effect of the shortcut was to isolate different entries in
-	// $GOPATH from each other. This had the unfortunate effect that
-	// if you had (say), GOPATH listing two entries, one for commands
-	// and one for libraries, and you did a 'git pull' in the library one
-	// and then tried 'go install commands/...', it would build the new libraries
-	// during the first build (because they wouldn't have been installed at all)
-	// but then subsequent builds would not rebuild the libraries, even if the
-	// mtimes indicate they are stale, because the different GOPATH entries
-	// were treated differently. This behavior was confusing when using
-	// non-trivial GOPATHs, which were particularly common with some
-	// code management conventions, like the original godep.
-	// Since the $GOROOT case (the original motivation) is handled separately,
-	// we no longer put a barrier between the different $GOPATH entries.
-	//
-	// One implication of this is that if there is a system directory for
-	// non-standard Go packages that is included in $GOPATH, the mtimes
-	// on those compiled packages must be no earlier than the mtimes
-	// on the source files. Since most distributions use the same mtime
-	// for all files in a tree, they will be unaffected. People using plain
-	// tar x to extract system-installed packages will need to adjust mtimes,
-	// but it's better to force them to get the mtimes right than to ignore
-	// the mtimes and thereby do the wrong thing in common use cases.
-	//
-	// So there is no GOPATH vs GOPATH shortcut here anymore.
-	//
-	// If something needs to come back here, we could try writing a dummy
-	// file with a random name to the $GOPATH/pkg directory (and removing it)
-	// to test for write access, and then skip GOPATH roots we don't have write
-	// access to. But hopefully we can just use the mtimes always.
-
-	srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
-	for _, src := range srcs {
-		if olderThan(filepath.Join(p.Dir, src)) {
-			return true, "newer source file"
-		}
-	}
-
-	return false, ""
-}
-
-// computeBuildID computes the build ID for p, leaving it in p.buildID.
-// Build ID is a hash of the information we want to detect changes in.
-// See the long comment in isStale for details.
-func computeBuildID(p *Package) {
-	h := sha1.New()
-
-	// Include the list of files compiled as part of the package.
-	// This lets us detect removed files. See issue 3895.
-	inputFiles := stringList(
-		p.GoFiles,
-		p.CgoFiles,
-		p.CFiles,
-		p.CXXFiles,
-		p.MFiles,
-		p.HFiles,
-		p.SFiles,
-		p.SysoFiles,
-		p.SwigFiles,
-		p.SwigCXXFiles,
-	)
-	for _, file := range inputFiles {
-		fmt.Fprintf(h, "file %s\n", file)
-	}
-
-	// Include the content of runtime/internal/sys/zversion.go in the hash
-	// for package runtime. This will give package runtime a
-	// different build ID in each Go release.
-	if p.Standard && p.ImportPath == "runtime/internal/sys" && buildContext.Compiler != "gccgo" {
-		data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
-		if err != nil {
-			fatalf("go: %s", err)
-		}
-		fmt.Fprintf(h, "zversion %q\n", string(data))
-	}
-
-	// Include the build IDs of any dependencies in the hash.
-	// This, combined with the runtime/zversion content,
-	// will cause packages to have different build IDs when
-	// compiled with different Go releases.
-	// This helps the go command know to recompile when
-	// people use the same GOPATH but switch between
-	// different Go releases. See issue 10702.
-	// This is also a better fix for issue 8290.
-	for _, p1 := range p.deps {
-		fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID)
-	}
-
-	p.buildID = fmt.Sprintf("%x", h.Sum(nil))
-}
-
-var cwd, _ = os.Getwd()
-
-var cmdCache = map[string]*Package{}
-
-// loadPackage is like loadImport but is used for command-line arguments,
-// 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 {
-	if build.IsLocalImport(arg) {
-		dir := arg
-		if !filepath.IsAbs(dir) {
-			if abs, err := filepath.Abs(dir); err == nil {
-				// interpret relative to current directory
-				dir = abs
-			}
-		}
-		if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
-			arg = sub
-		}
-	}
-	if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
-		if p := cmdCache[arg]; p != nil {
-			return p
-		}
-		stk.push(arg)
-		defer stk.pop()
-
-		bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
-		bp.ImportPath = arg
-		bp.Goroot = true
-		bp.BinDir = gorootBin
-		if gobin != "" {
-			bp.BinDir = gobin
-		}
-		bp.Root = goroot
-		bp.SrcRoot = gorootSrc
-		p := new(Package)
-		cmdCache[arg] = p
-		p.load(stk, bp, err)
-		if p.Error == nil && p.Name != "main" {
-			p.Error = &PackageError{
-				ImportStack: stk.copy(),
-				Err:         fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
-			}
-		}
-		return p
-	}
-
-	// Wasn't a command; must be a package.
-	// If it is a local import path but names a standard package,
-	// we treat it as if the user specified the standard package.
-	// This lets you run go test ./ioutil in package io and be
-	// referring to io/ioutil rather than a hypothetical import of
-	// "./ioutil".
-	if build.IsLocalImport(arg) {
-		bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
-		if bp.ImportPath != "" && bp.ImportPath != "." {
-			arg = bp.ImportPath
-		}
-	}
-
-	return loadImport(arg, cwd, nil, stk, nil, 0)
-}
-
-// packages returns the packages named by the
-// 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
-// to load dependencies of a named package, the named
-// package is still returned, with p.Incomplete = true
-// and details in p.DepsErrors.
-func packages(args []string) []*Package {
-	var pkgs []*Package
-	for _, pkg := range packagesAndErrors(args) {
-		if pkg.Error != nil {
-			errorf("can't load package: %s", pkg.Error)
-			continue
-		}
-		pkgs = append(pkgs, pkg)
-	}
-	return pkgs
-}
-
-// packagesAndErrors is like 'packages' but returns a
-// *Package for every argument, even the ones that
-// cannot be loaded at all.
-// The packages that fail to load will have p.Error != nil.
-func packagesAndErrors(args []string) []*Package {
-	if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
-		return []*Package{goFilesPackage(args)}
-	}
-
-	args = importPaths(args)
-	var (
-		pkgs    []*Package
-		stk     importStack
-		seenArg = make(map[string]bool)
-		seenPkg = make(map[*Package]bool)
-	)
-
-	for _, arg := range args {
-		if seenArg[arg] {
-			continue
-		}
-		seenArg[arg] = true
-		pkg := loadPackage(arg, &stk)
-		if seenPkg[pkg] {
-			continue
-		}
-		seenPkg[pkg] = true
-		pkgs = append(pkgs, pkg)
-	}
-	computeStale(pkgs...)
-
-	return pkgs
-}
-
-// packagesForBuild is like 'packages' but fails if any of
-// the packages or their dependencies have errors
-// (cannot be built).
-func packagesForBuild(args []string) []*Package {
-	pkgs := packagesAndErrors(args)
-	printed := map[*PackageError]bool{}
-	for _, pkg := range pkgs {
-		if pkg.Error != nil {
-			errorf("can't load package: %s", pkg.Error)
-		}
-		for _, err := range pkg.DepsErrors {
-			// Since these are errors in dependencies,
-			// the same error might show up multiple times,
-			// once in each package that depends on it.
-			// Only print each once.
-			if !printed[err] {
-				printed[err] = true
-				errorf("%s", err)
-			}
-		}
-	}
-	exitIfErrors()
-
-	// Check for duplicate loads of the same package.
-	// That should be impossible, but if it does happen then
-	// we end up trying to build the same package twice,
-	// usually in parallel overwriting the same files,
-	// which doesn't work very well.
-	seen := map[string]bool{}
-	reported := map[string]bool{}
-	for _, pkg := range packageList(pkgs) {
-		if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
-			reported[pkg.ImportPath] = true
-			errorf("internal error: duplicate loads of %s", pkg.ImportPath)
-		}
-		seen[pkg.ImportPath] = true
-	}
-	exitIfErrors()
-
-	return pkgs
-}
-
-// hasSubdir reports whether dir is a subdirectory of
-// (possibly multiple levels below) root.
-// If so, it sets rel to the path fragment that must be
-// appended to root to reach dir.
-func hasSubdir(root, dir string) (rel string, ok bool) {
-	if p, err := filepath.EvalSymlinks(root); err == nil {
-		root = p
-	}
-	if p, err := filepath.EvalSymlinks(dir); err == nil {
-		dir = p
-	}
-	const sep = string(filepath.Separator)
-	root = filepath.Clean(root)
-	if !strings.HasSuffix(root, sep) {
-		root += sep
-	}
-	dir = filepath.Clean(dir)
-	if !strings.HasPrefix(dir, root) {
-		return "", false
-	}
-	return filepath.ToSlash(dir[len(root):]), true
-}
-
-var (
-	errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
-	errBuildIDMalformed = fmt.Errorf("malformed object file")
-	errBuildIDUnknown   = fmt.Errorf("lost build ID")
-)
-
-var (
-	bangArch = []byte("!<arch>")
-	pkgdef   = []byte("__.PKGDEF")
-	goobject = []byte("go object ")
-	buildid  = []byte("build id ")
-)
-
-// readBuildID reads the build ID from an archive or binary.
-// It only supports the gc toolchain.
-// Other toolchain maintainers should adjust this function.
-func readBuildID(p *Package) (id string, err error) {
-	if buildToolchain != (gcToolchain{}) {
-		return "", errBuildIDToolchain
-	}
-
-	// For commands, read build ID directly from binary.
-	if p.Name == "main" {
-		return ReadBuildIDFromBinary(p.Target)
-	}
-
-	// Otherwise, we expect to have an archive (.a) file,
-	// and we can read the build ID from the Go export data.
-	if !strings.HasSuffix(p.Target, ".a") {
-		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown}
-	}
-
-	// Read just enough of the target to fetch the build ID.
-	// The archive is expected to look like:
-	//
-	//	!<arch>
-	//	__.PKGDEF       0           0     0     644     7955      `
-	//	go object darwin amd64 devel X:none
-	//	build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224"
-	//
-	// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
-	// Reading the first 1024 bytes should be plenty.
-	f, err := os.Open(p.Target)
-	if err != nil {
-		return "", err
-	}
-	data := make([]byte, 1024)
-	n, err := io.ReadFull(f, data)
-	f.Close()
-
-	if err != nil && n == 0 {
-		return "", err
-	}
-
-	bad := func() (string, error) {
-		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed}
-	}
-
-	// Archive header.
-	for i := 0; ; i++ { // returns during i==3
-		j := bytes.IndexByte(data, '\n')
-		if j < 0 {
-			return bad()
-		}
-		line := data[:j]
-		data = data[j+1:]
-		switch i {
-		case 0:
-			if !bytes.Equal(line, bangArch) {
-				return bad()
-			}
-		case 1:
-			if !bytes.HasPrefix(line, pkgdef) {
-				return bad()
-			}
-		case 2:
-			if !bytes.HasPrefix(line, goobject) {
-				return bad()
-			}
-		case 3:
-			if !bytes.HasPrefix(line, buildid) {
-				// Found the object header, just doesn't have a build id line.
-				// Treat as successful, with empty build id.
-				return "", nil
-			}
-			id, err := strconv.Unquote(string(line[len(buildid):]))
-			if err != nil {
-				return bad()
-			}
-			return id, nil
-		}
-	}
-}
-
-var (
-	goBuildPrefix = []byte("\xff Go build ID: \"")
-	goBuildEnd    = []byte("\"\n \xff")
-
-	elfPrefix = []byte("\x7fELF")
-
-	machoPrefixes = [][]byte{
-		{0xfe, 0xed, 0xfa, 0xce},
-		{0xfe, 0xed, 0xfa, 0xcf},
-		{0xce, 0xfa, 0xed, 0xfe},
-		{0xcf, 0xfa, 0xed, 0xfe},
-	}
-)
-
-var BuildIDReadSize = 32 * 1024 // changed for testing
-
-// ReadBuildIDFromBinary reads the build ID from a binary.
-//
-// ELF binaries store the build ID in a proper PT_NOTE section.
-//
-// Other binary formats are not so flexible. For those, the linker
-// stores the build ID as non-instruction bytes at the very beginning
-// of the text segment, which should appear near the beginning
-// of the file. This is clumsy but fairly portable. Custom locations
-// can be added for other binary types as needed, like we did for ELF.
-func ReadBuildIDFromBinary(filename string) (id string, err error) {
-	if filename == "" {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
-	}
-
-	// Read the first 32 kB of the binary file.
-	// That should be enough to find the build ID.
-	// In ELF files, the build ID is in the leading headers,
-	// which are typically less than 4 kB, not to mention 32 kB.
-	// In Mach-O files, there's no limit, so we have to parse the file.
-	// On other systems, we're trying to read enough that
-	// we get the beginning of the text segment in the read.
-	// The offset where the text segment begins in a hello
-	// world compiled for each different object format today:
-	//
-	//	Plan 9: 0x20
-	//	Windows: 0x600
-	//
-	f, err := os.Open(filename)
-	if err != nil {
-		return "", err
-	}
-	defer f.Close()
-
-	data := make([]byte, BuildIDReadSize)
-	_, err = io.ReadFull(f, data)
-	if err == io.ErrUnexpectedEOF {
-		err = nil
-	}
-	if err != nil {
-		return "", err
-	}
-
-	if bytes.HasPrefix(data, elfPrefix) {
-		return readELFGoBuildID(filename, f, data)
-	}
-	for _, m := range machoPrefixes {
-		if bytes.HasPrefix(data, m) {
-			return readMachoGoBuildID(filename, f, data)
-		}
-	}
-
-	return readRawGoBuildID(filename, data)
-}
-
-// readRawGoBuildID finds the raw build ID stored in text segment data.
-func readRawGoBuildID(filename string, data []byte) (id string, err error) {
-	i := bytes.Index(data, goBuildPrefix)
-	if i < 0 {
-		// Missing. Treat as successful but build ID empty.
-		return "", nil
-	}
-
-	j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
-	if j < 0 {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
-	}
-
-	quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
-	id, err = strconv.Unquote(string(quoted))
-	if err != nil {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
-	}
-
-	return id, nil
-}
diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go
deleted file mode 100644
index fba1363..0000000
--- a/src/cmd/go/pkg_test.go
+++ /dev/null
@@ -1,194 +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 main
-
-import (
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-)
-
-var foldDupTests = []struct {
-	list   []string
-	f1, f2 string
-}{
-	{stringList("math/rand", "math/big"), "", ""},
-	{stringList("math", "strings"), "", ""},
-	{stringList("strings"), "", ""},
-	{stringList("strings", "strings"), "strings", "strings"},
-	{stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
-}
-
-func TestFoldDup(t *testing.T) {
-	for _, tt := range foldDupTests {
-		f1, f2 := foldDup(tt.list)
-		if f1 != tt.f1 || f2 != tt.f2 {
-			t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
-		}
-	}
-}
-
-var parseMetaGoImportsTests = []struct {
-	in  string
-	out []metaImport
-}{
-	{
-		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
-		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
-	},
-	{
-		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
-		<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
-		[]metaImport{
-			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
-			{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
-		},
-	},
-	{
-		`<head>
-		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
-		</head>`,
-		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
-	},
-	{
-		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
-		<body>`,
-		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
-	},
-	{
-		`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
-		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
-	},
-	{
-		// XML doesn't like <div style=position:relative>.
-		`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
-		[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
-	},
-}
-
-func TestParseMetaGoImports(t *testing.T) {
-	for i, tt := range parseMetaGoImportsTests {
-		out, err := parseMetaGoImports(strings.NewReader(tt.in))
-		if err != nil {
-			t.Errorf("test#%d: %v", i, err)
-			continue
-		}
-		if !reflect.DeepEqual(out, tt.out) {
-			t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
-		}
-	}
-}
-
-func TestSharedLibName(t *testing.T) {
-	// TODO(avdva) - make these values platform-specific
-	prefix := "lib"
-	suffix := ".so"
-	testData := []struct {
-		args      []string
-		pkgs      []*Package
-		expected  string
-		expectErr bool
-		rootedAt  string
-	}{
-		{
-			args:     []string{"std"},
-			pkgs:     []*Package{},
-			expected: "std",
-		},
-		{
-			args:     []string{"std", "cmd"},
-			pkgs:     []*Package{},
-			expected: "std,cmd",
-		},
-		{
-			args:     []string{},
-			pkgs:     []*Package{&Package{ImportPath: "gopkg.in/somelib"}},
-			expected: "gopkg.in-somelib",
-		},
-		{
-			args:     []string{"./..."},
-			pkgs:     []*Package{&Package{ImportPath: "somelib"}},
-			expected: "somelib",
-			rootedAt: "somelib",
-		},
-		{
-			args:     []string{"../somelib", "../somelib"},
-			pkgs:     []*Package{&Package{ImportPath: "somelib"}},
-			expected: "somelib",
-		},
-		{
-			args:     []string{"../lib1", "../lib2"},
-			pkgs:     []*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}},
-			expected: "gopkg.in-lib1,gopkg.in-lib2",
-		},
-		{
-			args: []string{"./..."},
-			pkgs: []*Package{
-				&Package{ImportPath: "gopkg.in/dir/lib1"},
-				&Package{ImportPath: "gopkg.in/lib2"},
-				&Package{ImportPath: "gopkg.in/lib3"},
-			},
-			expected: "gopkg.in",
-			rootedAt: "gopkg.in",
-		},
-		{
-			args:      []string{"std", "../lib2"},
-			pkgs:      []*Package{},
-			expectErr: true,
-		},
-		{
-			args:      []string{"all", "./"},
-			pkgs:      []*Package{},
-			expectErr: true,
-		},
-		{
-			args:      []string{"cmd", "fmt"},
-			pkgs:      []*Package{},
-			expectErr: true,
-		},
-	}
-	for _, data := range testData {
-		func() {
-			if data.rootedAt != "" {
-				tmpGopath, err := ioutil.TempDir("", "gopath")
-				if err != nil {
-					t.Fatal(err)
-				}
-				oldGopath := buildContext.GOPATH
-				defer func() {
-					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)
-				if err != nil {
-					t.Fatal(err)
-				}
-				buildContext.GOPATH = tmpGopath
-				os.Chdir(root)
-			}
-			computed, err := libname(data.args, data.pkgs)
-			if err != nil {
-				if !data.expectErr {
-					t.Errorf("libname returned an error %q, expected a name", err.Error())
-				}
-			} else if data.expectErr {
-				t.Errorf("libname returned %q, expected an error", computed)
-			} else {
-				expected := prefix + data.expected + suffix
-				if expected != computed {
-					t.Errorf("libname returned %q, expected %q", computed, expected)
-				}
-			}
-		}()
-	}
-}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
deleted file mode 100644
index 18387b5..0000000
--- a/src/cmd/go/run.go
+++ /dev/null
@@ -1,156 +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 main
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"runtime"
-	"strings"
-)
-
-var execCmd []string // -exec flag, for run and test
-
-func findExecCmd() []string {
-	if execCmd != nil {
-		return execCmd
-	}
-	execCmd = []string{} // avoid work the second time
-	if goos == runtime.GOOS && goarch == runtime.GOARCH {
-		return execCmd
-	}
-	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
-	if err == nil {
-		execCmd = []string{path}
-	}
-	return execCmd
-}
-
-var cmdRun = &Command{
-	UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
-	Short:     "compile and run Go program",
-	Long: `
-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.
-	`,
-}
-
-func init() {
-	cmdRun.Run = runRun // break init loop
-
-	addBuildFlags(cmdRun)
-	cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
-}
-
-func printStderr(args ...interface{}) (int, error) {
-	return fmt.Fprint(os.Stderr, args...)
-}
-
-func runRun(cmd *Command, args []string) {
-	instrumentInit()
-	buildModeInit()
-	var b builder
-	b.init()
-	b.print = printStderr
-	i := 0
-	for i < len(args) && strings.HasSuffix(args[i], ".go") {
-		i++
-	}
-	files, cmdArgs := args[:i], args[i:]
-	if len(files) == 0 {
-		fatalf("go run: no go files listed")
-	}
-	for _, file := range files {
-		if strings.HasSuffix(file, "_test.go") {
-			// goFilesPackage is going to assign this to TestGoFiles.
-			// Reject since it won't be part of the build.
-			fatalf("go run: cannot run *_test.go files (%s)", file)
-		}
-	}
-	p := goFilesPackage(files)
-	if p.Error != nil {
-		fatalf("%s", p.Error)
-	}
-	p.omitDWARF = true
-	if len(p.DepsErrors) > 0 {
-		// Since these are errors in dependencies,
-		// the same error might show up multiple times,
-		// once in each package that depends on it.
-		// Only print each once.
-		printed := map[*PackageError]bool{}
-		for _, err := range p.DepsErrors {
-			if !printed[err] {
-				printed[err] = true
-				errorf("%s", err)
-			}
-		}
-	}
-	exitIfErrors()
-	if p.Name != "main" {
-		fatalf("go run: cannot run non-main package")
-	}
-	p.target = "" // must build - not up to date
-	var src string
-	if len(p.GoFiles) > 0 {
-		src = p.GoFiles[0]
-	} else if len(p.CgoFiles) > 0 {
-		src = p.CgoFiles[0]
-	} else {
-		// this case could only happen if the provided source uses cgo
-		// while cgo is disabled.
-		hint := ""
-		if !buildContext.CgoEnabled {
-			hint = " (cgo is disabled)"
-		}
-		fatalf("go run: no suitable source files%s", hint)
-	}
-	p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
-	a1 := b.action(modeBuild, modeBuild, p)
-	a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
-	b.do(a)
-}
-
-// runProgram is the action for running a binary that has already
-// 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 {
-		b.showcmd("", "%s", strings.Join(cmdline, " "))
-		if buildN {
-			return nil
-		}
-	}
-
-	runStdin(cmdline)
-	return nil
-}
-
-// runStdin is like run, but connects Stdin.
-func runStdin(cmdline []string) {
-	cmd := exec.Command(cmdline[0], cmdline[1:]...)
-	cmd.Stdin = os.Stdin
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	cmd.Env = origEnv
-	startSigHandlers()
-	if err := cmd.Run(); err != nil {
-		errorf("%v", err)
-	}
-}
diff --git a/src/cmd/go/signal.go b/src/cmd/go/signal.go
deleted file mode 100644
index e8ba0d3..0000000
--- a/src/cmd/go/signal.go
+++ /dev/null
@@ -1,31 +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 main
-
-import (
-	"os"
-	"os/signal"
-	"sync"
-)
-
-// interrupted is closed, if go process is interrupted.
-var interrupted = make(chan struct{})
-
-// processSignals setups signal handler.
-func processSignals() {
-	sig := make(chan os.Signal)
-	signal.Notify(sig, signalsToIgnore...)
-	go func() {
-		<-sig
-		close(interrupted)
-	}()
-}
-
-var onceProcessSignals sync.Once
-
-// startSigHandlers start signal handlers.
-func startSigHandlers() {
-	onceProcessSignals.Do(processSignals)
-}
diff --git a/src/cmd/go/signal_notunix.go b/src/cmd/go/signal_notunix.go
deleted file mode 100644
index 29aa9d8..0000000
--- a/src/cmd/go/signal_notunix.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build plan9 windows
-
-package main
-
-import (
-	"os"
-)
-
-var signalsToIgnore = []os.Signal{os.Interrupt}
-
-// signalTrace is the signal to send to make a Go program
-// crash with a stack trace.
-var signalTrace os.Signal = nil
diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go
deleted file mode 100644
index e86cd46..0000000
--- a/src/cmd/go/signal_unix.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
-
-package main
-
-import (
-	"os"
-	"syscall"
-)
-
-var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
-
-// signalTrace is the signal to send to make a Go program
-// crash with a stack trace.
-var signalTrace os.Signal = syscall.SIGQUIT
diff --git a/src/cmd/go/tag_test.go b/src/cmd/go/tag_test.go
deleted file mode 100644
index 6649bd6..0000000
--- a/src/cmd/go/tag_test.go
+++ /dev/null
@@ -1,100 +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 main
-
-import "testing"
-
-var selectTagTestTags = []string{
-	"go.r58",
-	"go.r58.1",
-	"go.r59",
-	"go.r59.1",
-	"go.r61",
-	"go.r61.1",
-	"go.weekly.2010-01-02",
-	"go.weekly.2011-10-12",
-	"go.weekly.2011-10-12.1",
-	"go.weekly.2011-10-14",
-	"go.weekly.2011-11-01",
-	"go1",
-	"go1.0.1",
-	"go1.999",
-	"go1.9.2",
-	"go5",
-
-	// these should be ignored:
-	"release.r59",
-	"release.r59.1",
-	"release",
-	"weekly.2011-10-12",
-	"weekly.2011-10-12.1",
-	"weekly",
-	"foo",
-	"bar",
-	"go.f00",
-	"go!r60",
-	"go.1999-01-01",
-	"go.2x",
-	"go.20000000000000",
-	"go.2.",
-	"go.2.0",
-	"go2x",
-	"go20000000000000",
-	"go2.",
-	"go2.0",
-}
-
-var selectTagTests = []struct {
-	version  string
-	selected string
-}{
-	/*
-		{"release.r57", ""},
-		{"release.r58.2", "go.r58.1"},
-		{"release.r59", "go.r59"},
-		{"release.r59.1", "go.r59.1"},
-		{"release.r60", "go.r59.1"},
-		{"release.r60.1", "go.r59.1"},
-		{"release.r61", "go.r61"},
-		{"release.r66", "go.r61.1"},
-		{"weekly.2010-01-01", ""},
-		{"weekly.2010-01-02", "go.weekly.2010-01-02"},
-		{"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
-		{"weekly.2010-01-03", "go.weekly.2010-01-02"},
-		{"weekly.2011-10-12", "go.weekly.2011-10-12"},
-		{"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
-		{"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
-		{"weekly.2011-10-14", "go.weekly.2011-10-14"},
-		{"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
-		{"weekly.2011-11-01", "go.weekly.2011-11-01"},
-		{"weekly.2014-01-01", "go.weekly.2011-11-01"},
-		{"weekly.3000-01-01", "go.weekly.2011-11-01"},
-		{"go1", "go1"},
-		{"go1.1", "go1.0.1"},
-		{"go1.998", "go1.9.2"},
-		{"go1.1000", "go1.999"},
-		{"go6", "go5"},
-
-		// faulty versions:
-		{"release.f00", ""},
-		{"weekly.1999-01-01", ""},
-		{"junk", ""},
-		{"", ""},
-		{"go2x", ""},
-		{"go200000000000", ""},
-		{"go2.", ""},
-		{"go2.0", ""},
-	*/
-	{"anything", "go1"},
-}
-
-func TestSelectTag(t *testing.T) {
-	for _, c := range selectTagTests {
-		selected := selectTag(c.version, selectTagTestTags)
-		if selected != c.selected {
-			t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
-		}
-	}
-}
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
deleted file mode 100644
index 35250c9..0000000
--- a/src/cmd/go/test.go
+++ /dev/null
@@ -1,1596 +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 main
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"go/ast"
-	"go/build"
-	"go/doc"
-	"go/parser"
-	"go/token"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"sort"
-	"strings"
-	"text/template"
-	"time"
-	"unicode"
-	"unicode/utf8"
-)
-
-// Break init loop.
-func init() {
-	cmdTest.Run = runTest
-}
-
-const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
-
-var cmdTest = &Command{
-	CustomFlags: true,
-	UsageLine:   testUsage,
-	Short:       "test packages",
-	Long: `
-'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.
-
-` + strings.TrimSpace(testFlag1) + ` 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.
-`,
-}
-
-const testFlag1 = `
-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'.
-`
-
-var helpTestflag = &Command{
-	UsageLine: "testflag",
-	Short:     "description of testing flags",
-	Long: `
-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:
-
-	` + strings.TrimSpace(testFlag2) + `
-`,
-}
-
-const testFlag2 = `
-	-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=.'.
-
-	-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).
-
-	-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.
-
-	-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.
-
-	-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).
-
-	-v
-	    Verbose output: log all tests as they are run. Also print all
-	    text from Log and Logf calls even if the test succeeds.
-
-The following flags are also recognized by 'go test' and can be used to
-profile the tests during execution:
-
-	-benchmem
-	    Print memory allocation statistics for benchmarks.
-
-	-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.
-
-	-coverprofile cover.out
-	    Write a coverage profile to the file after all tests have passed.
-	    Sets -cover.
-
-	-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.
-
-	-mutexprofile mutex.out
-	    Write a mutex contention profile to the specified file
-	    when all tests are complete.
-	    Writes test binary as -c would.
-
-	-mutexprofilefraction n
-	    Sample 1 in n stack traces of goroutines holding a
-	    contended mutex.
-
-	-outputdir directory
-	    Place output files from profiling in the specified directory,
-	    by default the directory in which "go test" is running.
-
-	-trace trace.out
-	    Write an execution trace to the specified file before exiting.
-
-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.
-`
-
-var helpTestfunc = &Command{
-	UsageLine: "testfunc",
-	Short:     "description of testing functions",
-	Long: `
-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 is compiled but not executed. An example with no text after
-"Output:" is compiled, executed, and expected to produce no output.
-
-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.
-`,
-}
-
-var (
-	testC            bool       // -c flag
-	testCover        bool       // -cover flag
-	testCoverMode    string     // -covermode flag
-	testCoverPaths   []string   // -coverpkg flag
-	testCoverPkgs    []*Package // -coverpkg flag
-	testO            string     // -o flag
-	testProfile      bool       // some profiling flag
-	testNeedBinary   bool       // profile needs to keep binary around
-	testV            bool       // -v flag
-	testTimeout      string     // -timeout flag
-	testArgs         []string
-	testBench        bool
-	testStreamOutput bool // show output as it is generated
-	testShowPass     bool // show passing output
-
-	testKillTimeout = 10 * time.Minute
-)
-
-var testMainDeps = map[string]bool{
-	// Dependencies for testmain.
-	"testing":                   true,
-	"testing/internal/testdeps": true,
-	"os": true,
-}
-
-func runTest(cmd *Command, args []string) {
-	var pkgArgs []string
-	pkgArgs, testArgs = testFlags(args)
-
-	findExecCmd() // initialize cached result
-
-	instrumentInit()
-	buildModeInit()
-	pkgs := packagesForBuild(pkgArgs)
-	if len(pkgs) == 0 {
-		fatalf("no packages to test")
-	}
-
-	if testC && len(pkgs) != 1 {
-		fatalf("cannot use -c flag with multiple packages")
-	}
-	if testO != "" && len(pkgs) != 1 {
-		fatalf("cannot use -o flag with multiple packages")
-	}
-	if testProfile && len(pkgs) != 1 {
-		fatalf("cannot use test profile flag with multiple packages")
-	}
-
-	// 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
-	// 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 {
-		testKillTimeout = dt + 1*time.Minute
-	}
-
-	// show passing test output (after buffering) with -v flag.
-	// must buffer because tests are running in parallel, and
-	// otherwise the output will get mixed.
-	testShowPass = testV
-
-	// stream test output (no buffering) when no package has
-	// been given on the command line (implicit current directory)
-	// or when benchmarking.
-	// Also stream if we're showing output anyway with a
-	// single package under test or if parallelism is set to 1.
-	// In these cases, streaming the output produces the same result
-	// as not streaming, just more immediately.
-	testStreamOutput = len(pkgArgs) == 0 || testBench ||
-		(testShowPass && (len(pkgs) == 1 || buildP == 1))
-
-	// For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier.
-	if buildI && testO != "" {
-		testC = true
-	}
-
-	var b builder
-	b.init()
-
-	if buildI {
-		buildV = testV
-
-		deps := make(map[string]bool)
-		for dep := range testMainDeps {
-			deps[dep] = true
-		}
-
-		for _, p := range pkgs {
-			// Dependencies for each test.
-			for _, path := range p.Imports {
-				deps[path] = true
-			}
-			for _, path := range p.vendored(p.TestImports) {
-				deps[path] = true
-			}
-			for _, path := range p.vendored(p.XTestImports) {
-				deps[path] = true
-			}
-		}
-
-		// translate C to runtime/cgo
-		if deps["C"] {
-			delete(deps, "C")
-			deps["runtime/cgo"] = true
-			if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && !buildMSan {
-				deps["cmd/cgo"] = true
-			}
-		}
-		// Ignore pseudo-packages.
-		delete(deps, "unsafe")
-
-		all := []string{}
-		for path := range deps {
-			if !build.IsLocalImport(path) {
-				all = append(all, path)
-			}
-		}
-		sort.Strings(all)
-
-		a := &action{}
-		for _, p := range packagesForBuild(all) {
-			a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
-		}
-		b.do(a)
-		if !testC || a.failed {
-			return
-		}
-		b.init()
-	}
-
-	var builds, runs, prints []*action
-
-	if testCoverPaths != nil {
-		// Load packages that were asked about for coverage.
-		// packagesForBuild exits if the packages cannot be loaded.
-		testCoverPkgs = packagesForBuild(testCoverPaths)
-
-		// Warn about -coverpkg arguments that are not actually used.
-		used := make(map[string]bool)
-		for _, p := range pkgs {
-			used[p.ImportPath] = true
-			for _, dep := range p.Deps {
-				used[dep] = true
-			}
-		}
-		for _, p := range testCoverPkgs {
-			if !used[p.ImportPath] {
-				fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on %s\n", p.ImportPath)
-			}
-		}
-
-		// Mark all the coverage packages for rebuilding with coverage.
-		for _, p := range testCoverPkgs {
-			// There is nothing to cover in package unsafe; it comes from the compiler.
-			if p.ImportPath == "unsafe" {
-				continue
-			}
-			p.Stale = true // rebuild
-			p.StaleReason = "rebuild for coverage"
-			p.fake = true // do not warn about rebuild
-			p.coverMode = testCoverMode
-			var coverFiles []string
-			coverFiles = append(coverFiles, p.GoFiles...)
-			coverFiles = append(coverFiles, p.CgoFiles...)
-			coverFiles = append(coverFiles, p.TestGoFiles...)
-			p.coverVars = declareCoverVars(p.ImportPath, coverFiles...)
-		}
-	}
-
-	// Prepare build + run + print actions for all packages being tested.
-	for _, p := range pkgs {
-		// sync/atomic import is inserted by the cover tool. See #18486
-		if testCover && testCoverMode == "atomic" {
-			ensureImport(p, "sync/atomic")
-		}
-		buildTest, runTest, printTest, err := b.test(p)
-		if err != nil {
-			str := err.Error()
-			if strings.HasPrefix(str, "\n") {
-				str = str[1:]
-			}
-			failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
-
-			if p.ImportPath != "" {
-				errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
-			} else {
-				errorf("%s\n%s", str, failed)
-			}
-			continue
-		}
-		builds = append(builds, buildTest)
-		runs = append(runs, runTest)
-		prints = append(prints, printTest)
-	}
-
-	// Ultimately the goal is to print the output.
-	root := &action{deps: prints}
-
-	// Force the printing of results to happen in order,
-	// one at a time.
-	for i, a := range prints {
-		if i > 0 {
-			a.deps = append(a.deps, prints[i-1])
-		}
-	}
-
-	// Force benchmarks to run in serial.
-	if !testC && testBench {
-		// The first run must wait for all builds.
-		// Later runs must wait for the previous run's print.
-		for i, run := range runs {
-			if i == 0 {
-				run.deps = append(run.deps, builds...)
-			} else {
-				run.deps = append(run.deps, prints[i-1])
-			}
-		}
-	}
-
-	// If we are building any out-of-date packages other
-	// than those under test, warn.
-	okBuild := map[*Package]bool{}
-	for _, p := range pkgs {
-		okBuild[p] = true
-	}
-	warned := false
-	for _, a := range actionList(root) {
-		if a.p == nil || okBuild[a.p] {
-			continue
-		}
-		okBuild[a.p] = true // warn at most once
-
-		// Don't warn about packages being rebuilt because of
-		// things like coverage analysis.
-		for _, p1 := range a.p.imports {
-			if p1.fake {
-				a.p.fake = true
-			}
-		}
-
-		if a.f != nil && !okBuild[a.p] && !a.p.fake && !a.p.local {
-			if !warned {
-				fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
-				warned = true
-			}
-			fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath)
-		}
-	}
-	if warned {
-		args := strings.Join(pkgArgs, " ")
-		if args != "" {
-			args = " " + args
-		}
-		extraOpts := ""
-		if buildRace {
-			extraOpts = "-race "
-		}
-		if buildMSan {
-			extraOpts = "-msan "
-		}
-		fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args)
-	}
-
-	b.do(root)
-}
-
-// ensures that package p imports the named package.
-func ensureImport(p *Package, pkg string) {
-	for _, d := range p.deps {
-		if d.Name == pkg {
-			return
-		}
-	}
-
-	a := loadPackage(pkg, &importStack{})
-	if a.Error != nil {
-		fatalf("load %s: %v", pkg, a.Error)
-	}
-	computeStale(a)
-
-	p.imports = append(p.imports, a)
-}
-
-func contains(x []string, s string) bool {
-	for _, t := range x {
-		if t == s {
-			return true
-		}
-	}
-	return false
-}
-
-var windowsBadWords = []string{
-	"install",
-	"patch",
-	"setup",
-	"update",
-}
-
-func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
-	if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
-		build := b.action(modeBuild, modeBuild, p)
-		run := &action{p: p, deps: []*action{build}}
-		print := &action{f: (*builder).notest, p: p, deps: []*action{run}}
-		return build, run, print, nil
-	}
-
-	// Build Package structs describing:
-	//	ptest - package + test files
-	//	pxtest - package of external test files
-	//	pmain - pkg.test binary
-	var ptest, pxtest, pmain *Package
-
-	var imports, ximports []*Package
-	var stk importStack
-	stk.push(p.ImportPath + " (test)")
-	for i, path := range p.TestImports {
-		p1 := loadImport(path, p.Dir, p, &stk, p.build.TestImportPos[path], useVendor)
-		if p1.Error != nil {
-			return nil, nil, nil, p1.Error
-		}
-		if len(p1.DepsErrors) > 0 {
-			err := p1.DepsErrors[0]
-			err.Pos = "" // show full import stack
-			return nil, nil, nil, err
-		}
-		if contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
-			// Same error that loadPackage returns (via reusePackage) in pkg.go.
-			// Can't change that code, because that code is only for loading the
-			// non-test copy of a package.
-			err := &PackageError{
-				ImportStack:   testImportStack(stk[0], p1, p.ImportPath),
-				Err:           "import cycle not allowed in test",
-				isImportCycle: true,
-			}
-			return nil, nil, nil, err
-		}
-		p.TestImports[i] = p1.ImportPath
-		imports = append(imports, p1)
-	}
-	stk.pop()
-	stk.push(p.ImportPath + "_test")
-	pxtestNeedsPtest := false
-	for i, path := range p.XTestImports {
-		p1 := loadImport(path, p.Dir, p, &stk, p.build.XTestImportPos[path], useVendor)
-		if p1.Error != nil {
-			return nil, nil, nil, p1.Error
-		}
-		if len(p1.DepsErrors) > 0 {
-			err := p1.DepsErrors[0]
-			err.Pos = "" // show full import stack
-			return nil, nil, nil, err
-		}
-		if p1.ImportPath == p.ImportPath {
-			pxtestNeedsPtest = true
-		} else {
-			ximports = append(ximports, p1)
-		}
-		p.XTestImports[i] = p1.ImportPath
-	}
-	stk.pop()
-
-	// Use last element of import path, not package name.
-	// They differ when package name is "main".
-	// But if the import path is "command-line-arguments",
-	// like it is during 'go run', use the package name.
-	var elem string
-	if p.ImportPath == "command-line-arguments" {
-		elem = p.Name
-	} else {
-		_, elem = path.Split(p.ImportPath)
-	}
-	testBinary := elem + ".test"
-
-	// The ptest package needs to be importable under the
-	// same import path that p has, but we cannot put it in
-	// 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
-	// compiler and linker to look in that _test directory first.
-	//
-	// That is, if the package under test is unicode/utf8,
-	// then the normal place to write the package archive is
-	// $WORK/unicode/utf8.a, but we write the test package archive to
-	// $WORK/unicode/utf8/_test/unicode/utf8.a.
-	// We write the external test package archive to
-	// $WORK/unicode/utf8/_test/unicode/utf8_test.a.
-	testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
-	ptestObj := buildToolchain.pkgpath(testDir, p)
-
-	// Create the directory for the .a files.
-	ptestDir, _ := filepath.Split(ptestObj)
-	if err := b.mkdir(ptestDir); err != nil {
-		return nil, nil, nil, err
-	}
-
-	// Should we apply coverage analysis locally,
-	// only for this package and only for this test?
-	// Yes, if -cover is on but -coverpkg has not specified
-	// a list of packages for global coverage.
-	localCover := testCover && testCoverPaths == nil
-
-	// Test package.
-	if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
-		ptest = new(Package)
-		*ptest = *p
-		ptest.GoFiles = nil
-		ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
-		ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
-		ptest.target = ""
-		ptest.Imports = stringList(p.Imports, p.TestImports)
-		ptest.imports = append(append([]*Package{}, p.imports...), imports...)
-		ptest.pkgdir = testDir
-		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{}
-		for k, v := range p.build.ImportPos {
-			m[k] = append(m[k], v...)
-		}
-		for k, v := range p.build.TestImportPos {
-			m[k] = append(m[k], v...)
-		}
-		ptest.build.ImportPos = m
-
-		if localCover {
-			ptest.coverMode = testCoverMode
-			var coverFiles []string
-			coverFiles = append(coverFiles, ptest.GoFiles...)
-			coverFiles = append(coverFiles, ptest.CgoFiles...)
-			ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
-		}
-	} else {
-		ptest = p
-	}
-
-	// External test package.
-	if len(p.XTestGoFiles) > 0 {
-		pxtest = &Package{
-			Name:        p.Name + "_test",
-			ImportPath:  p.ImportPath + "_test",
-			localPrefix: p.localPrefix,
-			Root:        p.Root,
-			Dir:         p.Dir,
-			GoFiles:     p.XTestGoFiles,
-			Imports:     p.XTestImports,
-			build: &build.Package{
-				ImportPos: p.build.XTestImportPos,
-			},
-			imports:  ximports,
-			pkgdir:   testDir,
-			fake:     true,
-			external: true,
-			Stale:    true,
-		}
-		if pxtestNeedsPtest {
-			pxtest.imports = append(pxtest.imports, ptest)
-		}
-	}
-
-	// Action for building pkg.test.
-	pmain = &Package{
-		Name:       "main",
-		Dir:        testDir,
-		GoFiles:    []string{"_testmain.go"},
-		ImportPath: "testmain",
-		Root:       p.Root,
-		build:      &build.Package{Name: "main"},
-		pkgdir:     testDir,
-		fake:       true,
-		Stale:      true,
-		omitDWARF:  !testC && !testNeedBinary,
-	}
-
-	// The generated main also imports testing, regexp, and os.
-	stk.push("testmain")
-	for dep := range testMainDeps {
-		if dep == ptest.ImportPath {
-			pmain.imports = append(pmain.imports, ptest)
-		} else {
-			p1 := loadImport(dep, "", nil, &stk, nil, 0)
-			if p1.Error != nil {
-				return nil, nil, nil, p1.Error
-			}
-			pmain.imports = append(pmain.imports, p1)
-		}
-	}
-
-	if testCoverPkgs != nil {
-		// Add imports, but avoid duplicates.
-		seen := map[*Package]bool{p: true, ptest: true}
-		for _, p1 := range pmain.imports {
-			seen[p1] = true
-		}
-		for _, p1 := range testCoverPkgs {
-			if !seen[p1] {
-				seen[p1] = true
-				pmain.imports = append(pmain.imports, p1)
-			}
-		}
-	}
-
-	// Do initial scan for metadata needed for writing _testmain.go
-	// Use that metadata to update the list of imports for package main.
-	// The list of imports is used by recompileForTest and by the loop
-	// afterward that gathers t.Cover information.
-	t, err := loadTestFuncs(ptest)
-	if err != nil {
-		return nil, nil, nil, err
-	}
-	if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
-		pmain.imports = append(pmain.imports, ptest)
-		t.ImportTest = true
-	}
-	if pxtest != nil {
-		pmain.imports = append(pmain.imports, pxtest)
-		t.ImportXtest = true
-	}
-
-	if ptest != p && localCover {
-		// We have made modifications to the package p being tested
-		// and are rebuilding p (as ptest), writing it to the testDir tree.
-		// Arrange to rebuild, writing to that same tree, all packages q
-		// such that the test depends on q, and q depends on p.
-		// This makes sure that q sees the modifications to p.
-		// Strictly speaking, the rebuild is only necessary if the
-		// modifications to p change its export metadata, but
-		// determining that is a bit tricky, so we rebuild always.
-		//
-		// This will cause extra compilation, so for now we only do it
-		// when testCover is set. The conditions are more general, though,
-		// and we may find that we need to do it always in the future.
-		recompileForTest(pmain, p, ptest, testDir)
-	}
-
-	if buildContext.GOOS == "darwin" {
-		if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
-			t.IsIOS = true
-			t.NeedOS = true
-		}
-	}
-	if t.TestMain == nil {
-		t.NeedOS = true
-	}
-
-	for _, cp := range pmain.imports {
-		if len(cp.coverVars) > 0 {
-			t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
-		}
-	}
-
-	if !buildN {
-		// writeTestmain writes _testmain.go. This must happen after recompileForTest,
-		// because recompileForTest modifies XXX.
-		if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
-			return nil, nil, nil, err
-		}
-	}
-
-	computeStale(pmain)
-
-	if ptest != p {
-		a := b.action(modeBuild, modeBuild, ptest)
-		a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
-		a.objpkg = ptestObj
-		a.target = ptestObj
-		a.link = false
-	}
-
-	if pxtest != nil {
-		a := b.action(modeBuild, modeBuild, pxtest)
-		a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
-		a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
-		a.target = a.objpkg
-	}
-
-	a := b.action(modeBuild, modeBuild, pmain)
-	a.objdir = testDir + string(filepath.Separator)
-	a.objpkg = filepath.Join(testDir, "main.a")
-	a.target = filepath.Join(testDir, testBinary) + exeSuffix
-	if goos == "windows" {
-		// There are many reserved words on Windows that,
-		// if used in the name of an executable, cause Windows
-		// to try to ask for extra permissions.
-		// The word list includes setup, install, update, and patch,
-		// but it does not appear to be defined anywhere.
-		// We have run into this trying to run the
-		// go.codereview/patch tests.
-		// For package names containing those words, use test.test.exe
-		// instead of pkgname.test.exe.
-		// Note that this file name is only used in the Go command's
-		// temporary directory. If the -c or other flags are
-		// given, the code below will still use pkgname.test.exe.
-		// There are two user-visible effects of this change.
-		// First, you can actually run 'go test' in directories that
-		// have names that Windows thinks are installer-like,
-		// without getting a dialog box asking for more permissions.
-		// Second, in the Windows process listing during go test,
-		// the test shows up as test.test.exe, not pkgname.test.exe.
-		// That second one is a drawback, but it seems a small
-		// price to pay for the test running at all.
-		// If maintaining the list of bad words is too onerous,
-		// we could just do this always on Windows.
-		for _, bad := range windowsBadWords {
-			if strings.Contains(testBinary, bad) {
-				a.target = filepath.Join(testDir, "test.test") + exeSuffix
-				break
-			}
-		}
-	}
-	buildAction = a
-
-	if testC || testNeedBinary {
-		// -c or profiling flag: create action to copy binary to ./test.out.
-		target := filepath.Join(cwd, testBinary+exeSuffix)
-		if testO != "" {
-			target = testO
-			if !filepath.IsAbs(target) {
-				target = filepath.Join(cwd, target)
-			}
-		}
-		buildAction = &action{
-			f:      (*builder).install,
-			deps:   []*action{buildAction},
-			p:      pmain,
-			target: target,
-		}
-		runAction = buildAction // make sure runAction != nil even if not running test
-	}
-	if testC {
-		printAction = &action{p: p, deps: []*action{runAction}} // nop
-	} else {
-		// run test
-		runAction = &action{
-			f:          (*builder).runTest,
-			deps:       []*action{buildAction},
-			p:          p,
-			ignoreFail: true,
-		}
-		cleanAction := &action{
-			f:    (*builder).cleanTest,
-			deps: []*action{runAction},
-			p:    p,
-		}
-		printAction = &action{
-			f:    (*builder).printTest,
-			deps: []*action{cleanAction},
-			p:    p,
-		}
-	}
-
-	return buildAction, runAction, printAction, nil
-}
-
-func testImportStack(top string, p *Package, target string) []string {
-	stk := []string{top, p.ImportPath}
-Search:
-	for p.ImportPath != target {
-		for _, p1 := range p.imports {
-			if p1.ImportPath == target || contains(p1.Deps, target) {
-				stk = append(stk, p1.ImportPath)
-				p = p1
-				continue Search
-			}
-		}
-		// Can't happen, but in case it does...
-		stk = append(stk, "<lost path to cycle>")
-		break
-	}
-	return stk
-}
-
-func recompileForTest(pmain, preal, ptest *Package, testDir string) {
-	// The "test copy" of preal is ptest.
-	// For each package that depends on preal, make a "test copy"
-	// that depends on ptest. And so on, up the dependency tree.
-	testCopy := map[*Package]*Package{preal: ptest}
-	for _, p := range packageList([]*Package{pmain}) {
-		// Copy on write.
-		didSplit := false
-		split := func() {
-			if didSplit {
-				return
-			}
-			didSplit = true
-			if p.pkgdir != testDir {
-				p1 := new(Package)
-				testCopy[p] = p1
-				*p1 = *p
-				p1.imports = make([]*Package, len(p.imports))
-				copy(p1.imports, p.imports)
-				p = p1
-				p.pkgdir = testDir
-				p.target = ""
-				p.fake = true
-				p.Stale = true
-				p.StaleReason = "depends on package being tested"
-			}
-		}
-
-		// Update p.deps and p.imports to use at test copies.
-		for i, dep := range p.deps {
-			if p1 := testCopy[dep]; p1 != nil && p1 != dep {
-				split()
-				p.deps[i] = p1
-			}
-		}
-		for i, imp := range p.imports {
-			if p1 := testCopy[imp]; p1 != nil && p1 != imp {
-				split()
-				p.imports[i] = p1
-			}
-		}
-	}
-}
-
-var coverIndex = 0
-
-// isTestFile reports whether the source file is a set of tests and should therefore
-// be excluded from coverage analysis.
-func isTestFile(file string) bool {
-	// We don't cover tests, only the code they test.
-	return strings.HasSuffix(file, "_test.go")
-}
-
-// declareCoverVars attaches the required cover variables names
-// to the files, to be used when annotating the files.
-func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
-	coverVars := make(map[string]*CoverVar)
-	for _, file := range files {
-		if isTestFile(file) {
-			continue
-		}
-		coverVars[file] = &CoverVar{
-			File: filepath.Join(importPath, file),
-			Var:  fmt.Sprintf("GoCover_%d", coverIndex),
-		}
-		coverIndex++
-	}
-	return coverVars
-}
-
-var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
-
-// runTest is the action for running a test binary.
-func (b *builder) runTest(a *action) error {
-	args := stringList(findExecCmd(), a.deps[0].target, testArgs)
-	a.testOutput = new(bytes.Buffer)
-
-	if buildN || buildX {
-		b.showcmd("", "%s", strings.Join(args, " "))
-		if buildN {
-			return nil
-		}
-	}
-
-	if a.failed {
-		// We were unable to build the binary.
-		a.failed = false
-		fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
-		setExitStatus(1)
-		return nil
-	}
-
-	cmd := exec.Command(args[0], args[1:]...)
-	cmd.Dir = a.p.Dir
-	cmd.Env = envForDir(cmd.Dir, origEnv)
-	var buf bytes.Buffer
-	if testStreamOutput {
-		cmd.Stdout = os.Stdout
-		cmd.Stderr = os.Stderr
-	} else {
-		cmd.Stdout = &buf
-		cmd.Stderr = &buf
-	}
-
-	// If there are any local SWIG dependencies, we want to load
-	// the shared library from the build directory.
-	if a.p.usesSwig() {
-		env := cmd.Env
-		found := false
-		prefix := "LD_LIBRARY_PATH="
-		for i, v := range env {
-			if strings.HasPrefix(v, prefix) {
-				env[i] = v + ":."
-				found = true
-				break
-			}
-		}
-		if !found {
-			env = append(env, "LD_LIBRARY_PATH=.")
-		}
-		cmd.Env = env
-	}
-
-	t0 := time.Now()
-	err := cmd.Start()
-
-	// This is a last-ditch deadline to detect and
-	// stop wedged test binaries, to keep the builders
-	// running.
-	if err == nil {
-		tick := time.NewTimer(testKillTimeout)
-		startSigHandlers()
-		done := make(chan error)
-		go func() {
-			done <- cmd.Wait()
-		}()
-	Outer:
-		select {
-		case err = <-done:
-			// ok
-		case <-tick.C:
-			if signalTrace != nil {
-				// Send a quit signal in the hope that the program will print
-				// a stack trace and exit. Give it five seconds before resorting
-				// to Kill.
-				cmd.Process.Signal(signalTrace)
-				select {
-				case err = <-done:
-					fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", signalTrace, testKillTimeout)
-					break Outer
-				case <-time.After(5 * time.Second):
-				}
-			}
-			cmd.Process.Kill()
-			err = <-done
-			fmt.Fprintf(&buf, "*** Test killed: ran too long (%v).\n", testKillTimeout)
-		}
-		tick.Stop()
-	}
-	out := buf.Bytes()
-	t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
-	if err == nil {
-		norun := ""
-		if testShowPass {
-			a.testOutput.Write(out)
-		}
-		if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
-			norun = " [no tests to run]"
-		}
-		fmt.Fprintf(a.testOutput, "ok  \t%s\t%s%s%s\n", a.p.ImportPath, t, coveragePercentage(out), norun)
-		return nil
-	}
-
-	setExitStatus(1)
-	if len(out) > 0 {
-		a.testOutput.Write(out)
-		// assume printing the test binary's exit status is superfluous
-	} else {
-		fmt.Fprintf(a.testOutput, "%s\n", err)
-	}
-	fmt.Fprintf(a.testOutput, "FAIL\t%s\t%s\n", a.p.ImportPath, t)
-
-	return nil
-}
-
-// coveragePercentage returns the coverage results (if enabled) for the
-// test. It uncovers the data by scanning the output from the test run.
-func coveragePercentage(out []byte) string {
-	if !testCover {
-		return ""
-	}
-	// The string looks like
-	//	test coverage for encoding/binary: 79.9% of statements
-	// Extract the piece from the percentage to the end of the line.
-	re := regexp.MustCompile(`coverage: (.*)\n`)
-	matches := re.FindSubmatch(out)
-	if matches == nil {
-		// Probably running "go test -cover" not "go test -cover fmt".
-		// The coverage output will appear in the output directly.
-		return ""
-	}
-	return fmt.Sprintf("\tcoverage: %s", matches[1])
-}
-
-// cleanTest is the action for cleaning up after a test.
-func (b *builder) cleanTest(a *action) error {
-	if buildWork {
-		return nil
-	}
-	run := a.deps[0]
-	testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test"))
-	os.RemoveAll(testDir)
-	return nil
-}
-
-// printTest is the action for printing a test result.
-func (b *builder) printTest(a *action) error {
-	clean := a.deps[0]
-	run := clean.deps[0]
-	os.Stdout.Write(run.testOutput.Bytes())
-	run.testOutput = nil
-	return nil
-}
-
-// notest is the action for testing a package with no test files.
-func (b *builder) notest(a *action) error {
-	fmt.Printf("?   \t%s\t[no test files]\n", a.p.ImportPath)
-	return 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
-	}
-	ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
-	if !ok {
-		return false
-	}
-	// 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.
-	// 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 == arg {
-		return true
-	}
-	return false
-}
-
-// isTest tells whether name looks like a test (or benchmark, according to prefix).
-// It is a Test (say) if there is a character after Test that is not a lower-case letter.
-// We don't want TesticularCancer.
-func isTest(name, prefix string) bool {
-	if !strings.HasPrefix(name, prefix) {
-		return false
-	}
-	if len(name) == len(prefix) { // "Test" is ok
-		return true
-	}
-	rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
-	return !unicode.IsLower(rune)
-}
-
-type coverInfo struct {
-	Package *Package
-	Vars    map[string]*CoverVar
-}
-
-// loadTestFuncs returns the testFuncs describing the tests that will be run.
-func loadTestFuncs(ptest *Package) (*testFuncs, error) {
-	t := &testFuncs{
-		Package: ptest,
-	}
-	for _, file := range ptest.TestGoFiles {
-		if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
-			return nil, err
-		}
-	}
-	for _, file := range ptest.XTestGoFiles {
-		if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
-			return nil, err
-		}
-	}
-	return t, nil
-}
-
-// writeTestmain writes the _testmain.go file for t to the file named out.
-func writeTestmain(out string, t *testFuncs) error {
-	f, err := os.Create(out)
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-
-	if err := testmainTmpl.Execute(f, t); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-type testFuncs struct {
-	Tests       []testFunc
-	Benchmarks  []testFunc
-	Examples    []testFunc
-	TestMain    *testFunc
-	Package     *Package
-	ImportTest  bool
-	NeedTest    bool
-	ImportXtest bool
-	NeedXtest   bool
-	NeedOS      bool
-	IsIOS       bool
-	Cover       []coverInfo
-}
-
-func (t *testFuncs) CoverMode() string {
-	return testCoverMode
-}
-
-func (t *testFuncs) CoverEnabled() bool {
-	return testCover
-}
-
-// Covered returns a string describing which packages are being tested for coverage.
-// If the covered package is the same as the tested package, it returns the empty string.
-// Otherwise it is a comma-separated human-readable list of packages beginning with
-// " in", ready for use in the coverage message.
-func (t *testFuncs) Covered() string {
-	if testCoverPaths == nil {
-		return ""
-	}
-	return " in " + strings.Join(testCoverPaths, ", ")
-}
-
-// Tested returns the name of the package being tested.
-func (t *testFuncs) Tested() string {
-	return t.Package.Name
-}
-
-type testFunc struct {
-	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()
-
-func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
-	f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
-	if err != nil {
-		return expandScanner(err)
-	}
-	for _, d := range f.Decls {
-		n, ok := d.(*ast.FuncDecl)
-		if !ok {
-			continue
-		}
-		if n.Recv != nil {
-			continue
-		}
-		name := n.Name.String()
-		switch {
-		case name == "TestMain" && isTestFunc(n, "M"):
-			if t.TestMain != nil {
-				return errors.New("multiple definitions of TestMain")
-			}
-			t.TestMain = &testFunc{pkg, name, "", false}
-			*doImport, *seen = true, true
-		case isTest(name, "Test"):
-			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"):
-			err := checkTestFunc(n, "B")
-			if err != nil {
-				return err
-			}
-			t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
-			*doImport, *seen = true, true
-		}
-	}
-	ex := doc.Examples(f)
-	sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
-	for _, e := range ex {
-		*doImport = true // import test file whether executed or not
-		if e.Output == "" && !e.EmptyOutput {
-			// Don't run examples with no output.
-			continue
-		}
-		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
-}
-
-var testmainTmpl = template.Must(template.New("main").Parse(`
-package main
-
-import (
-{{if .NeedOS}}
-	"os"
-{{end}}
-	"testing"
-	"testing/internal/testdeps"
-
-{{if .ImportTest}}
-	{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
-{{end}}
-{{if .ImportXtest}}
-	{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
-{{end}}
-{{range $i, $p := .Cover}}
-	_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
-{{end}}
-
-{{if .IsIOS}}
-	"os/signal"
-	_ "runtime/cgo"
-	"syscall"
-{{end}}
-)
-
-var tests = []testing.InternalTest{
-{{range .Tests}}
-	{"{{.Name}}", {{.Package}}.{{.Name}}},
-{{end}}
-}
-
-var benchmarks = []testing.InternalBenchmark{
-{{range .Benchmarks}}
-	{"{{.Name}}", {{.Package}}.{{.Name}}},
-{{end}}
-}
-
-var examples = []testing.InternalExample{
-{{range .Examples}}
-	{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
-{{end}}
-}
-
-{{if .CoverEnabled}}
-
-// Only updated by init functions, so no need for atomicity.
-var (
-	coverCounters = make(map[string][]uint32)
-	coverBlocks = make(map[string][]testing.CoverBlock)
-)
-
-func init() {
-	{{range $i, $p := .Cover}}
-	{{range $file, $cover := $p.Vars}}
-	coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
-	{{end}}
-	{{end}}
-}
-
-func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
-	if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
-		panic("coverage: mismatched sizes")
-	}
-	if coverCounters[fileName] != nil {
-		// Already registered.
-		return
-	}
-	coverCounters[fileName] = counter
-	block := make([]testing.CoverBlock, len(counter))
-	for i := range counter {
-		block[i] = testing.CoverBlock{
-			Line0: pos[3*i+0],
-			Col0: uint16(pos[3*i+2]),
-			Line1: pos[3*i+1],
-			Col1: uint16(pos[3*i+2]>>16),
-			Stmts: numStmts[i],
-		}
-	}
-	coverBlocks[fileName] = block
-}
-{{end}}
-
-func main() {
-{{if .IsIOS}}
-	// Send a SIGUSR2, which will be intercepted by LLDB to
-	// tell the test harness that installation was successful.
-	// See misc/ios/go_darwin_arm_exec.go.
-	signal.Notify(make(chan os.Signal), syscall.SIGUSR2)
-	syscall.Kill(0, syscall.SIGUSR2)
-	signal.Reset(syscall.SIGUSR2)
-
-	// The first argument supplied to an iOS test is an offset
-	// suffix for the current working directory.
-	// Process it here, and remove it from os.Args.
-	const hdr = "cwdSuffix="
-	if len(os.Args) < 2 || len(os.Args[1]) <= len(hdr) || os.Args[1][:len(hdr)] != hdr {
-		panic("iOS test not passed a working directory suffix")
-	}
-	suffix := os.Args[1][len(hdr):]
-	dir, err := os.Getwd()
-	if err != nil {
-		panic(err)
-	}
-	if err := os.Chdir(dir + "/" + suffix); err != nil {
-		panic(err)
-	}
-	os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
-{{end}}
-
-{{if .CoverEnabled}}
-	testing.RegisterCover(testing.Cover{
-		Mode: {{printf "%q" .CoverMode}},
-		Counters: coverCounters,
-		Blocks: coverBlocks,
-		CoveredPackages: {{printf "%q" .Covered}},
-	})
-{{end}}
-	m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
-{{with .TestMain}}
-	{{.Package}}.{{.Name}}(m)
-{{else}}
-	os.Exit(m.Run())
-{{end}}
-}
-
-`))
diff --git a/src/cmd/go/testdata/inprogress_interrupt_test.go b/src/cmd/go/testdata/inprogress_interrupt_test.go
new file mode 100644
index 0000000..135cfa9
--- /dev/null
+++ b/src/cmd/go/testdata/inprogress_interrupt_test.go
@@ -0,0 +1,40 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package inprogress_interrupt_test
+
+import (
+	"os"
+	"os/signal"
+	"sync"
+	"syscall"
+	"testing"
+)
+
+func TestParallel(t *testing.T) {
+	t.Parallel()
+}
+
+func TestSerial(t *testing.T) {
+	sigCh := make(chan os.Signal, 1)
+	signal.Notify(sigCh, os.Interrupt)
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		<-sigCh // catch initial signal
+		<-sigCh // catch propagated signal
+		wg.Done()
+	}()
+
+	proc, err := os.FindProcess(syscall.Getpid())
+	if err != nil {
+		t.Fatalf("unable to find current process: %v", err)
+	}
+	err = proc.Signal(os.Interrupt)
+	if err != nil {
+		t.Fatalf("failed to interrupt current process: %v", err)
+	}
+
+	wg.Wait()
+}
diff --git a/src/cmd/go/testdata/src/bench/x_test.go b/src/cmd/go/testdata/src/bench/x_test.go
new file mode 100644
index 0000000..32cabf8
--- /dev/null
+++ b/src/cmd/go/testdata/src/bench/x_test.go
@@ -0,0 +1,6 @@
+package bench
+
+import "testing"
+
+func Benchmark(b *testing.B) {
+}
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
deleted file mode 100644
index fa53bfc..0000000
--- a/src/cmd/go/testflag.go
+++ /dev/null
@@ -1,294 +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 main
-
-import (
-	"flag"
-	"fmt"
-	"os"
-	"strconv"
-	"strings"
-)
-
-// The flag handling part of go test is large and distracting.
-// We can't use the flag package because some of the flags from
-// our command line are for us, and some are for 6.out, and
-// some are for both.
-
-// testFlagSpec defines a flag we know about.
-type testFlagSpec struct {
-	name       string
-	boolVar    *bool
-	flagValue  flag.Value
-	passToTest bool // pass to Test
-	multiOK    bool // OK to have multiple instances
-	present    bool // flag has been seen
-}
-
-// testFlagDefn is the set of flags we process.
-var testFlagDefn = []*testFlagSpec{
-	// local.
-	{name: "c", boolVar: &testC},
-	{name: "i", boolVar: &buildI},
-	{name: "o"},
-	{name: "cover", boolVar: &testCover},
-	{name: "covermode"},
-	{name: "coverpkg"},
-	{name: "exec"},
-
-	// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
-	{name: "bench", passToTest: true},
-	{name: "benchmem", boolVar: new(bool), passToTest: true},
-	{name: "benchtime", passToTest: true},
-	{name: "count", passToTest: true},
-	{name: "coverprofile", passToTest: true},
-	{name: "cpu", passToTest: true},
-	{name: "cpuprofile", passToTest: true},
-	{name: "memprofile", passToTest: true},
-	{name: "memprofilerate", passToTest: true},
-	{name: "blockprofile", passToTest: true},
-	{name: "blockprofilerate", passToTest: true},
-	{name: "mutexprofile", passToTest: true},
-	{name: "mutexprofilefraction", passToTest: true},
-	{name: "outputdir", passToTest: true},
-	{name: "parallel", passToTest: true},
-	{name: "run", passToTest: true},
-	{name: "short", boolVar: new(bool), passToTest: true},
-	{name: "timeout", passToTest: true},
-	{name: "trace", passToTest: true},
-	{name: "v", boolVar: &testV, passToTest: true},
-}
-
-// add build flags to testFlagDefn
-func init() {
-	var cmd Command
-	addBuildFlags(&cmd)
-	cmd.Flag.VisitAll(func(f *flag.Flag) {
-		if f.Name == "v" {
-			// test overrides the build -v flag
-			return
-		}
-		testFlagDefn = append(testFlagDefn, &testFlagSpec{
-			name:      f.Name,
-			flagValue: f.Value,
-		})
-	})
-}
-
-// testFlags processes the command line, grabbing -x and -c, rewriting known flags
-// to have "test" before them, and reading the command line for the 6.out.
-// Unfortunately for us, we need to do our own flag processing because go test
-// grabs some flags but otherwise its command line is just a holding place for
-// pkg.test's arguments.
-// We allow known flags both before and after the package name list,
-// to allow both
-//	go test fmt -custom-flag-for-fmt-test
-//	go test -x math
-func testFlags(args []string) (packageNames, passToTest []string) {
-	inPkg := false
-	outputDir := ""
-	var explicitArgs []string
-	for i := 0; i < len(args); i++ {
-		if !strings.HasPrefix(args[i], "-") {
-			if !inPkg && packageNames == nil {
-				// First package name we've seen.
-				inPkg = true
-			}
-			if inPkg {
-				packageNames = append(packageNames, args[i])
-				continue
-			}
-		}
-
-		if inPkg {
-			// Found an argument beginning with "-"; end of package list.
-			inPkg = false
-		}
-
-		f, value, extraWord := testFlag(args, i)
-		if f == nil {
-			// This is a flag we do not know; we must assume
-			// that any args we see after this might be flag
-			// arguments, not package names.
-			inPkg = false
-			if packageNames == nil {
-				// make non-nil: we have seen the empty package list
-				packageNames = []string{}
-			}
-			if args[i] == "-args" || args[i] == "--args" {
-				// -args or --args signals that everything that follows
-				// should be passed to the test.
-				explicitArgs = args[i+1:]
-				break
-			}
-			passToTest = append(passToTest, args[i])
-			continue
-		}
-		if f.flagValue != nil {
-			if err := f.flagValue.Set(value); err != nil {
-				fatalf("invalid flag argument for -%s: %v", f.name, err)
-			}
-		} else {
-			// Test-only flags.
-			// Arguably should be handled by f.flagValue, but aren't.
-			var err error
-			switch f.name {
-			// bool flags.
-			case "c", "i", "v", "cover":
-				setBoolFlag(f.boolVar, value)
-			case "o":
-				testO = value
-				testNeedBinary = true
-			case "exec":
-				execCmd, err = splitQuotedFields(value)
-				if err != nil {
-					fatalf("invalid flag argument for -%s: %v", f.name, err)
-				}
-			case "bench":
-				// record that we saw the flag; don't care about the value
-				testBench = true
-			case "timeout":
-				testTimeout = value
-			case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
-				testProfile = true
-				testNeedBinary = true
-			case "trace":
-				testProfile = true
-			case "coverpkg":
-				testCover = true
-				if value == "" {
-					testCoverPaths = nil
-				} else {
-					testCoverPaths = strings.Split(value, ",")
-				}
-			case "coverprofile":
-				testCover = true
-				testProfile = true
-			case "covermode":
-				switch value {
-				case "set", "count", "atomic":
-					testCoverMode = value
-				default:
-					fatalf("invalid flag argument for -covermode: %q", value)
-				}
-				testCover = true
-			case "outputdir":
-				outputDir = value
-			}
-		}
-		if extraWord {
-			i++
-		}
-		if f.passToTest {
-			passToTest = append(passToTest, "-test."+f.name+"="+value)
-		}
-	}
-
-	if testCoverMode == "" {
-		testCoverMode = "set"
-		if buildRace {
-			// Default coverage mode is atomic when -race is set.
-			testCoverMode = "atomic"
-		}
-	}
-
-	// Tell the test what directory we're running in, so it can write the profiles there.
-	if testProfile && outputDir == "" {
-		dir, err := os.Getwd()
-		if err != nil {
-			fatalf("error from os.Getwd: %s", err)
-		}
-		passToTest = append(passToTest, "-test.outputdir", dir)
-	}
-
-	passToTest = append(passToTest, explicitArgs...)
-	return
-}
-
-// testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
-func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) {
-	arg := args[i]
-	if strings.HasPrefix(arg, "--") { // reduce two minuses to one
-		arg = arg[1:]
-	}
-	switch arg {
-	case "-?", "-h", "-help":
-		usage()
-	}
-	if arg == "" || arg[0] != '-' {
-		return
-	}
-	name := arg[1:]
-	// If there's already "test.", drop it for now.
-	name = strings.TrimPrefix(name, "test.")
-	equals := strings.Index(name, "=")
-	if equals >= 0 {
-		value = name[equals+1:]
-		name = name[:equals]
-	}
-	for _, f = range testFlagDefn {
-		if name == f.name {
-			// Booleans are special because they have modes -x, -x=true, -x=false.
-			if f.boolVar != nil || isBoolFlag(f.flagValue) {
-				if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
-					value = "true"
-				} else {
-					// verify it parses
-					setBoolFlag(new(bool), value)
-				}
-			} else { // Non-booleans must have a value.
-				extra = equals < 0
-				if extra {
-					if i+1 >= len(args) {
-						testSyntaxError("missing argument for flag " + f.name)
-					}
-					value = args[i+1]
-				}
-			}
-			if f.present && !f.multiOK {
-				testSyntaxError(f.name + " flag may be set only once")
-			}
-			f.present = true
-			return
-		}
-	}
-	f = nil
-	return
-}
-
-// isBoolFlag reports whether v is a bool flag.
-func isBoolFlag(v flag.Value) bool {
-	vv, ok := v.(interface {
-		IsBoolFlag() bool
-	})
-	if ok {
-		return vv.IsBoolFlag()
-	}
-	return false
-}
-
-// setBoolFlag sets the addressed boolean to the value.
-func setBoolFlag(flag *bool, value string) {
-	x, err := strconv.ParseBool(value)
-	if err != nil {
-		testSyntaxError("illegal bool flag value " + value)
-	}
-	*flag = x
-}
-
-// setIntFlag sets the addressed integer to the value.
-func setIntFlag(flag *int, value string) {
-	x, err := strconv.Atoi(value)
-	if err != nil {
-		testSyntaxError("illegal int flag value " + value)
-	}
-	*flag = x
-}
-
-func testSyntaxError(msg string) {
-	fmt.Fprintf(os.Stderr, "go test: %s\n", msg)
-	fmt.Fprintf(os.Stderr, `run "go help test" or "go help testflag" for more information`+"\n")
-	os.Exit(2)
-}
diff --git a/src/cmd/go/testgo.go b/src/cmd/go/testgo.go
deleted file mode 100644
index e507f34..0000000
--- a/src/cmd/go/testgo.go
+++ /dev/null
@@ -1,21 +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 contains extra hooks for testing the go command.
-// It is compiled into the Go binary only when building the
-// test copy; it does not get compiled into the standard go
-// command, so these testing hooks are not present in the
-// go command that everyone uses.
-
-// +build testgo
-
-package main
-
-import "os"
-
-func init() {
-	if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
-		isGoRelease = v == "1"
-	}
-}
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
deleted file mode 100644
index 38110cf..0000000
--- a/src/cmd/go/tool.go
+++ /dev/null
@@ -1,152 +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 main
-
-import (
-	"fmt"
-	"go/build"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"runtime"
-	"sort"
-	"strings"
-)
-
-var cmdTool = &Command{
-	Run:       runTool,
-	UsageLine: "tool [-n] command [args...]",
-	Short:     "run specified go tool",
-	Long: `
-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'.
-`,
-}
-
-var (
-	toolGOOS      = runtime.GOOS
-	toolGOARCH    = runtime.GOARCH
-	toolIsWindows = toolGOOS == "windows"
-	toolDir       = build.ToolDir
-
-	toolN bool
-)
-
-func init() {
-	cmdTool.Flag.BoolVar(&toolN, "n", false, "")
-}
-
-const toolWindowsExtension = ".exe"
-
-func tool(toolName string) string {
-	toolPath := filepath.Join(toolDir, toolName)
-	if toolIsWindows {
-		toolPath += toolWindowsExtension
-	}
-	if len(buildToolExec) > 0 {
-		return toolPath
-	}
-	// Give a nice message if there is no tool with that name.
-	if _, err := os.Stat(toolPath); err != nil {
-		if isInGoToolsRepo(toolName) {
-			fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
-		} else {
-			fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
-		}
-		setExitStatus(2)
-		exit()
-	}
-	return toolPath
-}
-
-func isInGoToolsRepo(toolName string) bool {
-	return false
-}
-
-func runTool(cmd *Command, args []string) {
-	if len(args) == 0 {
-		listTools()
-		return
-	}
-	toolName := args[0]
-	// The tool name must be lower-case letters, numbers or underscores.
-	for _, c := range toolName {
-		switch {
-		case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
-		default:
-			fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
-			setExitStatus(2)
-			return
-		}
-	}
-	toolPath := tool(toolName)
-	if toolPath == "" {
-		return
-	}
-	if toolN {
-		cmd := toolPath
-		if len(args) > 1 {
-			cmd += " " + strings.Join(args[1:], " ")
-		}
-		fmt.Printf("%s\n", cmd)
-		return
-	}
-	args[0] = toolPath // in case the tool wants to re-exec itself, e.g. cmd/dist
-	toolCmd := &exec.Cmd{
-		Path:   toolPath,
-		Args:   args,
-		Stdin:  os.Stdin,
-		Stdout: os.Stdout,
-		Stderr: os.Stderr,
-		// Set $GOROOT, mainly for go tool dist.
-		Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()),
-	}
-	err := toolCmd.Run()
-	if err != nil {
-		// Only print about the exit status if the command
-		// didn't even run (not an ExitError) or it didn't exit cleanly
-		// or we're printing command lines too (-x mode).
-		// Assume if command exited cleanly (even with non-zero status)
-		// it printed any messages it wanted to print.
-		if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX {
-			fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
-		}
-		setExitStatus(1)
-		return
-	}
-}
-
-// listTools prints a list of the available tools in the tools directory.
-func listTools() {
-	f, err := os.Open(toolDir)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
-		setExitStatus(2)
-		return
-	}
-	defer f.Close()
-	names, err := f.Readdirnames(-1)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
-		setExitStatus(2)
-		return
-	}
-
-	sort.Strings(names)
-	for _, name := range names {
-		// Unify presentation by going to lower case.
-		name = strings.ToLower(name)
-		// If it's windows, don't show the .exe suffix.
-		if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
-			name = name[:len(name)-len(toolWindowsExtension)]
-		}
-		fmt.Println(name)
-	}
-}
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
deleted file mode 100644
index fcdce22..0000000
--- a/src/cmd/go/vcs.go
+++ /dev/null
@@ -1,1006 +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 main
-
-import (
-	"bytes"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"internal/singleflight"
-	"log"
-	"net/url"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"strings"
-	"sync"
-)
-
-// A vcsCmd describes how to use a version control system
-// like Mercurial, Git, or Subversion.
-type vcsCmd struct {
-	name string
-	cmd  string // name of binary to invoke command
-
-	createCmd   []string // commands to download a fresh copy of a repository
-	downloadCmd []string // commands to download updates into an existing repository
-
-	tagCmd         []tagCmd // commands to list tags
-	tagLookupCmd   []tagCmd // commands to lookup tags before running tagSyncCmd
-	tagSyncCmd     []string // commands to sync to specific tag
-	tagSyncDefault []string // commands to sync to default tag
-
-	scheme  []string
-	pingCmd string
-
-	remoteRepo  func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
-	resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
-}
-
-var defaultSecureScheme = map[string]bool{
-	"https":   true,
-	"git+ssh": true,
-	"bzr+ssh": true,
-	"svn+ssh": true,
-	"ssh":     true,
-}
-
-func (v *vcsCmd) isSecure(repo string) bool {
-	u, err := url.Parse(repo)
-	if err != nil {
-		// If repo is not a URL, it's not secure.
-		return false
-	}
-	return v.isSecureScheme(u.Scheme)
-}
-
-func (v *vcsCmd) isSecureScheme(scheme string) bool {
-	switch v.cmd {
-	case "git":
-		// GIT_ALLOW_PROTOCOL is an environment variable defined by Git. It is a
-		// colon-separated list of schemes that are allowed to be used with git
-		// fetch/clone. Any scheme not mentioned will be considered insecure.
-		if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" {
-			for _, s := range strings.Split(allow, ":") {
-				if s == scheme {
-					return true
-				}
-			}
-			return false
-		}
-	}
-	return defaultSecureScheme[scheme]
-}
-
-// A tagCmd describes a command to list available tags
-// that can be passed to tagSyncCmd.
-type tagCmd struct {
-	cmd     string // command to list tags
-	pattern string // regexp to extract tags from list
-}
-
-// vcsList lists the known version control systems
-var vcsList = []*vcsCmd{
-	vcsHg,
-	vcsGit,
-	vcsSvn,
-	vcsBzr,
-}
-
-// vcsByCmd returns the version control system for the given
-// command name (hg, git, svn, bzr).
-func vcsByCmd(cmd string) *vcsCmd {
-	for _, vcs := range vcsList {
-		if vcs.cmd == cmd {
-			return vcs
-		}
-	}
-	return nil
-}
-
-// vcsHg describes how to use Mercurial.
-var vcsHg = &vcsCmd{
-	name: "Mercurial",
-	cmd:  "hg",
-
-	createCmd:   []string{"clone -U {repo} {dir}"},
-	downloadCmd: []string{"pull"},
-
-	// We allow both tag and branch names as 'tags'
-	// for selecting a version. This lets people have
-	// a go.release.r60 branch and a go1 branch
-	// and make changes in both, without constantly
-	// editing .hgtags.
-	tagCmd: []tagCmd{
-		{"tags", `^(\S+)`},
-		{"branches", `^(\S+)`},
-	},
-	tagSyncCmd:     []string{"update -r {tag}"},
-	tagSyncDefault: []string{"update default"},
-
-	scheme:     []string{"https", "http", "ssh"},
-	pingCmd:    "identify {scheme}://{repo}",
-	remoteRepo: hgRemoteRepo,
-}
-
-func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	out, err := vcsHg.runOutput(rootDir, "paths default")
-	if err != nil {
-		return "", err
-	}
-	return strings.TrimSpace(string(out)), nil
-}
-
-// vcsGit describes how to use Git.
-var vcsGit = &vcsCmd{
-	name: "Git",
-	cmd:  "git",
-
-	createCmd:   []string{"clone {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"},
-	downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
-
-	tagCmd: []tagCmd{
-		// tags/xxx matches a git tag named xxx
-		// origin/xxx matches a git branch named xxx on the default remote repository
-		{"show-ref", `(?:tags|origin)/(\S+)$`},
-	},
-	tagLookupCmd: []tagCmd{
-		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
-	},
-	tagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"},
-	// both createCmd and downloadCmd update the working dir.
-	// No need to do more here. We used to 'checkout master'
-	// but that doesn't work if the default branch is not named master.
-	// DO NOT add 'checkout master' here.
-	// See golang.org/issue/9032.
-	tagSyncDefault: []string{"submodule update --init --recursive"},
-
-	scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
-	pingCmd:    "ls-remote {scheme}://{repo}",
-	remoteRepo: gitRemoteRepo,
-}
-
-// scpSyntaxRe matches the SCP-like addresses used by Git to access
-// repositories by SSH.
-var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
-
-func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	cmd := "config remote.origin.url"
-	errParse := errors.New("unable to parse output of git " + cmd)
-	errRemoteOriginNotFound := errors.New("remote origin not found")
-	outb, err := vcsGit.run1(rootDir, cmd, nil, false)
-	if err != nil {
-		// if it doesn't output any message, it means the config argument is correct,
-		// but the config value itself doesn't exist
-		if outb != nil && len(outb) == 0 {
-			return "", errRemoteOriginNotFound
-		}
-		return "", err
-	}
-	out := strings.TrimSpace(string(outb))
-
-	var repoURL *url.URL
-	if m := scpSyntaxRe.FindStringSubmatch(out); m != nil {
-		// Match SCP-like syntax and convert it to a URL.
-		// Eg, "git at github.com:user/repo" becomes
-		// "ssh://git@github.com/user/repo".
-		repoURL = &url.URL{
-			Scheme: "ssh",
-			User:   url.User(m[1]),
-			Host:   m[2],
-			Path:   m[3],
-		}
-	} else {
-		repoURL, err = url.Parse(out)
-		if err != nil {
-			return "", err
-		}
-	}
-
-	// Iterate over insecure schemes too, because this function simply
-	// reports the state of the repo. If we can't see insecure schemes then
-	// we can't report the actual repo URL.
-	for _, s := range vcsGit.scheme {
-		if repoURL.Scheme == s {
-			return repoURL.String(), nil
-		}
-	}
-	return "", errParse
-}
-
-// vcsBzr describes how to use Bazaar.
-var vcsBzr = &vcsCmd{
-	name: "Bazaar",
-	cmd:  "bzr",
-
-	createCmd: []string{"branch {repo} {dir}"},
-
-	// Without --overwrite bzr will not pull tags that changed.
-	// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
-	downloadCmd: []string{"pull --overwrite"},
-
-	tagCmd:         []tagCmd{{"tags", `^(\S+)`}},
-	tagSyncCmd:     []string{"update -r {tag}"},
-	tagSyncDefault: []string{"update -r revno:-1"},
-
-	scheme:      []string{"https", "http", "bzr", "bzr+ssh"},
-	pingCmd:     "info {scheme}://{repo}",
-	remoteRepo:  bzrRemoteRepo,
-	resolveRepo: bzrResolveRepo,
-}
-
-func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
-	if err != nil {
-		return "", err
-	}
-	return strings.TrimSpace(string(outb)), nil
-}
-
-func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
-	outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
-	if err != nil {
-		return "", err
-	}
-	out := string(outb)
-
-	// Expect:
-	// ...
-	//   (branch root|repository branch): <URL>
-	// ...
-
-	found := false
-	for _, prefix := range []string{"\n  branch root: ", "\n  repository branch: "} {
-		i := strings.Index(out, prefix)
-		if i >= 0 {
-			out = out[i+len(prefix):]
-			found = true
-			break
-		}
-	}
-	if !found {
-		return "", fmt.Errorf("unable to parse output of bzr info")
-	}
-
-	i := strings.Index(out, "\n")
-	if i < 0 {
-		return "", fmt.Errorf("unable to parse output of bzr info")
-	}
-	out = out[:i]
-	return strings.TrimSpace(out), nil
-}
-
-// vcsSvn describes how to use Subversion.
-var vcsSvn = &vcsCmd{
-	name: "Subversion",
-	cmd:  "svn",
-
-	createCmd:   []string{"checkout {repo} {dir}"},
-	downloadCmd: []string{"update"},
-
-	// There is no tag command in subversion.
-	// The branch information is all in the path names.
-
-	scheme:     []string{"https", "http", "svn", "svn+ssh"},
-	pingCmd:    "info {scheme}://{repo}",
-	remoteRepo: svnRemoteRepo,
-}
-
-func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	outb, err := vcsSvn.runOutput(rootDir, "info")
-	if err != nil {
-		return "", err
-	}
-	out := string(outb)
-
-	// Expect:
-	// ...
-	// Repository Root: <URL>
-	// ...
-
-	i := strings.Index(out, "\nRepository Root: ")
-	if i < 0 {
-		return "", fmt.Errorf("unable to parse output of svn info")
-	}
-	out = out[i+len("\nRepository Root: "):]
-	i = strings.Index(out, "\n")
-	if i < 0 {
-		return "", fmt.Errorf("unable to parse output of svn info")
-	}
-	out = out[:i]
-	return strings.TrimSpace(out), nil
-}
-
-func (v *vcsCmd) String() string {
-	return v.name
-}
-
-// run runs the command line cmd in the given directory.
-// keyval is a list of key, value pairs.  run expands
-// instances of {key} in cmd into value, but only after
-// splitting cmd into individual arguments.
-// If an error occurs, run prints the command line and the
-// command's combined stdout+stderr to standard error.
-// Otherwise run discards the command's output.
-func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
-	_, err := v.run1(dir, cmd, keyval, true)
-	return err
-}
-
-// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
-func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
-	_, err := v.run1(dir, cmd, keyval, false)
-	return err
-}
-
-// runOutput is like run but returns the output of the command.
-func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
-	return v.run1(dir, cmd, keyval, true)
-}
-
-// run1 is the generalized implementation of run and runOutput.
-func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
-	m := make(map[string]string)
-	for i := 0; i < len(keyval); i += 2 {
-		m[keyval[i]] = keyval[i+1]
-	}
-	args := strings.Fields(cmdline)
-	for i, arg := range args {
-		args[i] = expand(m, arg)
-	}
-
-	if len(args) >= 2 && args[0] == "-go-internal-cd" {
-		if filepath.IsAbs(args[1]) {
-			dir = args[1]
-		} else {
-			dir = filepath.Join(dir, args[1])
-		}
-		args = args[2:]
-	}
-
-	_, err := exec.LookPath(v.cmd)
-	if err != nil {
-		fmt.Fprintf(os.Stderr,
-			"go: missing %s command. See https://golang.org/s/gogetcmd\n",
-			v.name)
-		return nil, err
-	}
-
-	cmd := exec.Command(v.cmd, args...)
-	cmd.Dir = dir
-	cmd.Env = envForDir(cmd.Dir, os.Environ())
-	if buildX {
-		fmt.Printf("cd %s\n", dir)
-		fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
-	}
-	var buf bytes.Buffer
-	cmd.Stdout = &buf
-	cmd.Stderr = &buf
-	err = cmd.Run()
-	out := buf.Bytes()
-	if err != nil {
-		if verbose || buildV {
-			fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
-			os.Stderr.Write(out)
-		}
-		return out, err
-	}
-	return out, nil
-}
-
-// ping pings to determine scheme to use.
-func (v *vcsCmd) ping(scheme, repo string) error {
-	return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
-}
-
-// create creates a new copy of repo in dir.
-// The parent of dir must exist; dir must not.
-func (v *vcsCmd) create(dir, repo string) error {
-	for _, cmd := range v.createCmd {
-		if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// download downloads any new changes for the repo in dir.
-func (v *vcsCmd) download(dir string) error {
-	for _, cmd := range v.downloadCmd {
-		if err := v.run(dir, cmd); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// tags returns the list of available tags for the repo in dir.
-func (v *vcsCmd) tags(dir string) ([]string, error) {
-	var tags []string
-	for _, tc := range v.tagCmd {
-		out, err := v.runOutput(dir, tc.cmd)
-		if err != nil {
-			return nil, err
-		}
-		re := regexp.MustCompile(`(?m-s)` + tc.pattern)
-		for _, m := range re.FindAllStringSubmatch(string(out), -1) {
-			tags = append(tags, m[1])
-		}
-	}
-	return tags, nil
-}
-
-// tagSync syncs the repo in dir to the named tag,
-// which either is a tag returned by tags or is v.tagDefault.
-func (v *vcsCmd) tagSync(dir, tag string) error {
-	if v.tagSyncCmd == nil {
-		return nil
-	}
-	if tag != "" {
-		for _, tc := range v.tagLookupCmd {
-			out, err := v.runOutput(dir, tc.cmd, "tag", tag)
-			if err != nil {
-				return err
-			}
-			re := regexp.MustCompile(`(?m-s)` + tc.pattern)
-			m := re.FindStringSubmatch(string(out))
-			if len(m) > 1 {
-				tag = m[1]
-				break
-			}
-		}
-	}
-
-	if tag == "" && v.tagSyncDefault != nil {
-		for _, cmd := range v.tagSyncDefault {
-			if err := v.run(dir, cmd); err != nil {
-				return err
-			}
-		}
-		return nil
-	}
-
-	for _, cmd := range v.tagSyncCmd {
-		if err := v.run(dir, cmd, "tag", tag); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// A vcsPath describes how to convert an import path into a
-// version control system and repository name.
-type vcsPath struct {
-	prefix string                              // prefix this description applies to
-	re     string                              // pattern for import path
-	repo   string                              // repository to use (expand with match of re)
-	vcs    string                              // version control system to use (expand with match of re)
-	check  func(match map[string]string) error // additional checks
-	ping   bool                                // ping for scheme to use to download repo
-
-	regexp *regexp.Regexp // cached compiled form of re
-}
-
-// 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.
-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(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)
-	}
-
-	origDir := dir
-	for len(dir) > len(srcRoot) {
-		for _, vcs := range vcsList {
-			if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
-				return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
-			}
-		}
-
-		// Move to parent.
-		ndir := filepath.Dir(dir)
-		if len(ndir) >= len(dir) {
-			// Shouldn't happen, but just in case, stop.
-			break
-		}
-		dir = ndir
-	}
-
-	return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
-}
-
-// repoRoot represents a version control system, a repo, and a root of
-// where to put it on disk.
-type repoRoot struct {
-	vcs *vcsCmd
-
-	// repo is the repository URL, including scheme
-	repo string
-
-	// root is the import path corresponding to the root of the
-	// repository
-	root string
-
-	// isCustom is true for custom import paths (those defined by HTML meta tags)
-	isCustom bool
-}
-
-var httpPrefixRE = regexp.MustCompile(`^https?:`)
-
-// securityMode specifies whether a function should make network
-// calls using insecure transports (eg, plain text HTTP).
-// The zero value is "secure".
-type securityMode int
-
-const (
-	secure securityMode = iota
-	insecure
-)
-
-// repoRootForImportPath analyzes importPath to determine the
-// version control system, and code repository to use.
-func repoRootForImportPath(importPath string, security securityMode) (*repoRoot, error) {
-	rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
-	if err == errUnknownSite {
-		// If there are wildcards, look up the thing before the wildcard,
-		// hoping it applies to the wildcarded parts too.
-		// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
-		lookup := strings.TrimSuffix(importPath, "/...")
-		if i := strings.Index(lookup, "/.../"); i >= 0 {
-			lookup = lookup[:i]
-		}
-		rr, err = repoRootForImportDynamic(lookup, security)
-		if err != nil {
-			err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
-		}
-	}
-	if err != nil {
-		rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic)
-		if err1 == nil {
-			rr = rr1
-			err = nil
-		}
-	}
-
-	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
-		// Do not allow wildcards in the repo root.
-		rr = nil
-		err = fmt.Errorf("cannot expand ... in %q", importPath)
-	}
-	return rr, err
-}
-
-var errUnknownSite = errors.New("dynamic lookup required to find mapping")
-
-// repoRootFromVCSPaths attempts to map importPath to a repoRoot
-// using the mappings defined in vcsPaths.
-// If scheme is non-empty, that scheme is forced.
-func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
-	// A common error is to use https://packagepath because that's what
-	// hg and git require. Diagnose this helpfully.
-	if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
-		// The importPath has been cleaned, so has only one slash. The pattern
-		// ignores the slashes; the error message puts them back on the RHS at least.
-		return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
-	}
-	for _, srv := range vcsPaths {
-		if !strings.HasPrefix(importPath, srv.prefix) {
-			continue
-		}
-		m := srv.regexp.FindStringSubmatch(importPath)
-		if m == nil {
-			if srv.prefix != "" {
-				return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
-			}
-			continue
-		}
-
-		// Build map of named subexpression matches for expand.
-		match := map[string]string{
-			"prefix": srv.prefix,
-			"import": importPath,
-		}
-		for i, name := range srv.regexp.SubexpNames() {
-			if name != "" && match[name] == "" {
-				match[name] = m[i]
-			}
-		}
-		if srv.vcs != "" {
-			match["vcs"] = expand(match, srv.vcs)
-		}
-		if srv.repo != "" {
-			match["repo"] = expand(match, srv.repo)
-		}
-		if srv.check != nil {
-			if err := srv.check(match); err != nil {
-				return nil, err
-			}
-		}
-		vcs := vcsByCmd(match["vcs"])
-		if vcs == nil {
-			return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
-		}
-		if srv.ping {
-			if scheme != "" {
-				match["repo"] = scheme + "://" + match["repo"]
-			} else {
-				for _, scheme := range vcs.scheme {
-					if security == secure && !vcs.isSecureScheme(scheme) {
-						continue
-					}
-					if vcs.ping(scheme, match["repo"]) == nil {
-						match["repo"] = scheme + "://" + match["repo"]
-						break
-					}
-				}
-			}
-		}
-		rr := &repoRoot{
-			vcs:  vcs,
-			repo: match["repo"],
-			root: match["root"],
-		}
-		return rr, nil
-	}
-	return nil, errUnknownSite
-}
-
-// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
-// statically known by repoRootForImportPathStatic.
-//
-// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func repoRootForImportDynamic(importPath string, security securityMode) (*repoRoot, error) {
-	slash := strings.Index(importPath, "/")
-	if slash < 0 {
-		slash = len(importPath)
-	}
-	host := importPath[:slash]
-	if !strings.Contains(host, ".") {
-		return nil, errors.New("import path does not begin with hostname")
-	}
-	urlStr, body, err := httpsOrHTTP(importPath, security)
-	if err != nil {
-		msg := "https fetch: %v"
-		if security == insecure {
-			msg = "http/" + msg
-		}
-		return nil, fmt.Errorf(msg, err)
-	}
-	defer body.Close()
-	imports, err := parseMetaGoImports(body)
-	if err != nil {
-		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
-	}
-	// Find the matched meta import.
-	mmi, err := matchGoImport(imports, importPath)
-	if err != nil {
-		if _, ok := err.(ImportMismatchError); !ok {
-			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
-		}
-		return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)
-	}
-	if buildV {
-		log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
-	}
-	// If the import was "uni.edu/bob/project", which said the
-	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
-	// make sure we don't trust Bob and check out evilroot.com to
-	// "uni.edu" yet (possibly overwriting/preempting another
-	// non-evil student).  Instead, first verify the root and see
-	// if it matches Bob's claim.
-	if mmi.Prefix != importPath {
-		if buildV {
-			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
-		}
-		urlStr0 := urlStr
-		var imports []metaImport
-		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
-		if err != nil {
-			return nil, err
-		}
-		metaImport2, err := matchGoImport(imports, importPath)
-		if err != nil || mmi != metaImport2 {
-			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)
-		}
-	}
-
-	if !strings.Contains(mmi.RepoRoot, "://") {
-		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
-	}
-	rr := &repoRoot{
-		vcs:      vcsByCmd(mmi.VCS),
-		repo:     mmi.RepoRoot,
-		root:     mmi.Prefix,
-		isCustom: true,
-	}
-	if rr.vcs == nil {
-		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
-	}
-	return rr, nil
-}
-
-var fetchGroup singleflight.Group
-var (
-	fetchCacheMu sync.Mutex
-	fetchCache   = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix
-)
-
-// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag
-// and returns its HTML discovery URL and the parsed metaImport lines
-// found on the page.
-//
-// The importPath is of the form "golang.org/x/tools".
-// It is an error if no imports are found.
-// urlStr will still be valid if err != nil.
-// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
-func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr string, imports []metaImport, err error) {
-	setCache := func(res fetchResult) (fetchResult, error) {
-		fetchCacheMu.Lock()
-		defer fetchCacheMu.Unlock()
-		fetchCache[importPrefix] = res
-		return res, nil
-	}
-
-	resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {
-		fetchCacheMu.Lock()
-		if res, ok := fetchCache[importPrefix]; ok {
-			fetchCacheMu.Unlock()
-			return res, nil
-		}
-		fetchCacheMu.Unlock()
-
-		urlStr, body, err := httpsOrHTTP(importPrefix, security)
-		if err != nil {
-			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
-		}
-		imports, err := parseMetaGoImports(body)
-		if err != nil {
-			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
-		}
-		if len(imports) == 0 {
-			err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
-		}
-		return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})
-	})
-	res := resi.(fetchResult)
-	return res.urlStr, res.imports, res.err
-}
-
-type fetchResult struct {
-	urlStr  string // e.g. "https://foo.com/x/bar?go-get=1"
-	imports []metaImport
-	err     error
-}
-
-// metaImport represents the parsed <meta name="go-import"
-// content="prefix vcs reporoot" /> tags from HTML files.
-type metaImport struct {
-	Prefix, VCS, RepoRoot string
-}
-
-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
-}
-
-// A ImportMismatchError is returned where metaImport/s are present
-// but none match our import path.
-type ImportMismatchError struct {
-	importPath string
-	mismatches []string // the meta imports that were discarded for not matching our importPath
-}
-
-func (m ImportMismatchError) Error() string {
-	formattedStrings := make([]string, len(m.mismatches))
-	for i, pre := range m.mismatches {
-		formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath)
-	}
-	return strings.Join(formattedStrings, ", ")
-}
-
-// 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, error) {
-	match := -1
-	imp := strings.Split(importPath, "/")
-
-	errImportMismatch := ImportMismatchError{importPath: importPath}
-	for i, im := range imports {
-		pre := strings.Split(im.Prefix, "/")
-
-		if !splitPathHasPrefix(imp, pre) {
-			errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
-			continue
-		}
-
-		if match != -1 {
-			return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
-		}
-		match = i
-	}
-
-	if match == -1 {
-		return metaImport{}, errImportMismatch
-	}
-	return imports[match], nil
-}
-
-// expand rewrites s to replace {k} with match[k] for each key k in match.
-func expand(match map[string]string, s string) string {
-	for k, v := range match {
-		s = strings.Replace(s, "{"+k+"}", v, -1)
-	}
-	return s
-}
-
-// vcsPaths defines the meaning of import paths referring to
-// commonly-used VCS hosting sites (github.com/user/dir)
-// and import paths referring to a fully-qualified importPath
-// containing a VCS type (foo.com/repo.git/dir)
-var vcsPaths = []*vcsPath{
-	// Github
-	{
-		prefix: "github.com/",
-		re:     `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "git",
-		repo:   "https://{root}",
-		check:  noVCSSuffix,
-	},
-
-	// Bitbucket
-	{
-		prefix: "bitbucket.org/",
-		re:     `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		repo:   "https://{root}",
-		check:  bitbucketVCS,
-	},
-
-	// IBM DevOps Services (JazzHub)
-	{
-		prefix: "hub.jazz.net/git",
-		re:     `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "git",
-		repo:   "https://{root}",
-		check:  noVCSSuffix,
-	},
-
-	// Git at Apache
-	{
-		prefix: "git.apache.org",
-		re:     `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "git",
-		repo:   "https://{root}",
-	},
-
-	// 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.
-	{
-		re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?P<vcs>bzr|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`,
-		ping: true,
-	},
-}
-
-// vcsPathsAfterDynamic gives additional vcsPaths entries
-// to try after the dynamic HTML check.
-// This gives those sites a chance to introduce <meta> tags
-// as part of a graceful transition away from the hard-coded logic.
-var vcsPathsAfterDynamic = []*vcsPath{
-	// Launchpad. See golang.org/issue/11436.
-	{
-		prefix: "launchpad.net/",
-		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "bzr",
-		repo:   "https://{root}",
-		check:  launchpadVCS,
-	},
-}
-
-func init() {
-	// fill in cached regexps.
-	// Doing this eagerly discovers invalid regexp syntax
-	// without having to run a command that needs that regexp.
-	for _, srv := range vcsPaths {
-		srv.regexp = regexp.MustCompile(srv.re)
-	}
-	for _, srv := range vcsPathsAfterDynamic {
-		srv.regexp = regexp.MustCompile(srv.re)
-	}
-}
-
-// noVCSSuffix checks that the repository name does not
-// end in .foo for any version control system foo.
-// The usual culprit is ".git".
-func noVCSSuffix(match map[string]string) error {
-	repo := match["repo"]
-	for _, vcs := range vcsList {
-		if strings.HasSuffix(repo, "."+vcs.cmd) {
-			return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
-		}
-	}
-	return nil
-}
-
-// bitbucketVCS determines the version control system for a
-// Bitbucket repository, by using the Bitbucket API.
-func bitbucketVCS(match map[string]string) error {
-	if err := noVCSSuffix(match); err != nil {
-		return err
-	}
-
-	var resp struct {
-		SCM string `json:"scm"`
-	}
-	url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
-	data, err := httpGET(url)
-	if err != nil {
-		if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 {
-			// this may be a private repository. If so, attempt to determine which
-			// VCS it uses. See issue 5375.
-			root := match["root"]
-			for _, vcs := range []string{"git", "hg"} {
-				if vcsByCmd(vcs).ping("https", root) == nil {
-					resp.SCM = vcs
-					break
-				}
-			}
-		}
-
-		if resp.SCM == "" {
-			return err
-		}
-	} else {
-		if err := json.Unmarshal(data, &resp); err != nil {
-			return fmt.Errorf("decoding %s: %v", url, err)
-		}
-	}
-
-	if vcsByCmd(resp.SCM) != nil {
-		match["vcs"] = resp.SCM
-		if resp.SCM == "git" {
-			match["repo"] += ".git"
-		}
-		return nil
-	}
-
-	return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
-}
-
-// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
-// "foo" could be a series name registered in Launchpad with its own branch,
-// and it could also be the name of a directory within the main project
-// branch one level up.
-func launchpadVCS(match map[string]string) error {
-	if match["project"] == "" || match["series"] == "" {
-		return nil
-	}
-	_, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
-	if err != nil {
-		match["root"] = expand(match, "launchpad.net/{project}")
-		match["repo"] = expand(match, "https://{root}")
-	}
-	return nil
-}
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
deleted file mode 100644
index c73f5d0..0000000
--- a/src/cmd/go/vcs_test.go
+++ /dev/null
@@ -1,382 +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 main
-
-import (
-	"errors"
-	"internal/testenv"
-	"io/ioutil"
-	"os"
-	"path"
-	"path/filepath"
-	"testing"
-)
-
-// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
-// TODO(cmang): Add tests for SVN and BZR.
-func TestRepoRootForImportPath(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
-	tests := []struct {
-		path string
-		want *repoRoot
-	}{
-		{
-			"github.com/golang/groupcache",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://github.com/golang/groupcache",
-			},
-		},
-		// IBM DevOps Services tests
-		{
-			"hub.jazz.net/git/user1/pkgname",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user1/pkgname",
-			},
-		},
-		{
-			"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user1/pkgname",
-			},
-		},
-		{
-			"hub.jazz.net",
-			nil,
-		},
-		{
-			"hub2.jazz.net",
-			nil,
-		},
-		{
-			"hub.jazz.net/someotherprefix",
-			nil,
-		},
-		{
-			"hub.jazz.net/someotherprefix/user1/pkgname",
-			nil,
-		},
-		// Spaces are not valid in user names or package names
-		{
-			"hub.jazz.net/git/User 1/pkgname",
-			nil,
-		},
-		{
-			"hub.jazz.net/git/user1/pkg name",
-			nil,
-		},
-		// Dots are not valid in user names
-		{
-			"hub.jazz.net/git/user.1/pkgname",
-			nil,
-		},
-		{
-			"hub.jazz.net/git/user/pkg.name",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user/pkg.name",
-			},
-		},
-		// User names cannot have uppercase letters
-		{
-			"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",
-			},
-		},
-		{
-			"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",
-			nil,
-		},
-		// Should have ".git" suffix
-		{
-			"git.apache.org/package-name/path/to/lib",
-			nil,
-		},
-		{
-			"git.apache.org/package-name.git",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name.git",
-			},
-		},
-		{
-			"git.apache.org/package-name_2.x.git/path/to/lib",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name_2.x.git",
-			},
-		},
-	}
-
-	for _, test := range tests {
-		got, err := repoRootForImportPath(test.path, secure)
-		want := test.want
-
-		if want == nil {
-			if err == nil {
-				t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
-			}
-			continue
-		}
-		if err != nil {
-			t.Errorf("RepoRootForImport(%q): %v", test.path, err)
-			continue
-		}
-		if got.vcs.name != want.vcs.name || got.repo != want.repo {
-			t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
-		}
-	}
-}
-
-// 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 j, vcs := range vcsList {
-		dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
-		if j&1 == 0 {
-			err := os.MkdirAll(dir, 0755)
-			if err != nil {
-				t.Fatal(err)
-			}
-		} else {
-			err := os.MkdirAll(filepath.Dir(dir), 0755)
-			if err != nil {
-				t.Fatal(err)
-			}
-			f, err := os.Create(dir)
-			if err != nil {
-				t.Fatal(err)
-			}
-			f.Close()
-		}
-
-		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
-		url    string
-		secure bool
-	}{
-		{vcsGit, "http://example.com/foo.git", false},
-		{vcsGit, "https://example.com/foo.git", true},
-		{vcsBzr, "http://example.com/foo.bzr", false},
-		{vcsBzr, "https://example.com/foo.bzr", true},
-		{vcsSvn, "http://example.com/svn", false},
-		{vcsSvn, "https://example.com/svn", true},
-		{vcsHg, "http://example.com/foo.hg", false},
-		{vcsHg, "https://example.com/foo.hg", true},
-		{vcsGit, "ssh://user@example.com/foo.git", true},
-		{vcsGit, "user at server:path/to/repo.git", false},
-		{vcsGit, "user at server:", false},
-		{vcsGit, "server:repo.git", false},
-		{vcsGit, "server:path/to/repo.git", false},
-		{vcsGit, "example.com:path/to/repo.git", false},
-		{vcsGit, "path/that/contains/a:colon/repo.git", false},
-		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
-	}
-
-	for _, test := range tests {
-		secure := test.vcs.isSecure(test.url)
-		if secure != test.secure {
-			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
-		}
-	}
-}
-
-func TestIsSecureGitAllowProtocol(t *testing.T) {
-	tests := []struct {
-		vcs    *vcsCmd
-		url    string
-		secure bool
-	}{
-		// Same as TestIsSecure to verify same behavior.
-		{vcsGit, "http://example.com/foo.git", false},
-		{vcsGit, "https://example.com/foo.git", true},
-		{vcsBzr, "http://example.com/foo.bzr", false},
-		{vcsBzr, "https://example.com/foo.bzr", true},
-		{vcsSvn, "http://example.com/svn", false},
-		{vcsSvn, "https://example.com/svn", true},
-		{vcsHg, "http://example.com/foo.hg", false},
-		{vcsHg, "https://example.com/foo.hg", true},
-		{vcsGit, "user at server:path/to/repo.git", false},
-		{vcsGit, "user at server:", false},
-		{vcsGit, "server:repo.git", false},
-		{vcsGit, "server:path/to/repo.git", false},
-		{vcsGit, "example.com:path/to/repo.git", false},
-		{vcsGit, "path/that/contains/a:colon/repo.git", false},
-		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
-		// New behavior.
-		{vcsGit, "ssh://user@example.com/foo.git", false},
-		{vcsGit, "foo://example.com/bar.git", true},
-		{vcsHg, "foo://example.com/bar.hg", false},
-		{vcsSvn, "foo://example.com/svn", false},
-		{vcsBzr, "foo://example.com/bar.bzr", false},
-	}
-
-	defer os.Unsetenv("GIT_ALLOW_PROTOCOL")
-	os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo")
-	for _, test := range tests {
-		secure := test.vcs.isSecure(test.url)
-		if secure != test.secure {
-			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
-		}
-	}
-}
-
-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"),
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "different.example.com/user/foo",
-			err:  errors.New("meta tags do not match import 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 deec02e..739ce5a 100644
--- a/src/cmd/go/vendor_test.go
+++ b/src/cmd/go/vendor_test.go
@@ -20,18 +20,18 @@ func TestVendorImports(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
-	tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
+	tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...", "vend/vendor/...", "vend/x/vendor/...")
 	want := `
 		vend [vend/vendor/p r]
 		vend/dir1 []
 		vend/hello [fmt vend/vendor/strings]
 		vend/subdir [vend/vendor/p r]
+		vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2]
+		vend/x/invalid [vend/x/invalid/vendor/foo]
 		vend/vendor/p []
 		vend/vendor/q []
 		vend/vendor/strings []
 		vend/vendor/vend/dir1/dir2 []
-		vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2]
-		vend/x/invalid [vend/x/invalid/vendor/foo]
 		vend/x/vendor/p []
 		vend/x/vendor/p/p [notfound]
 		vend/x/vendor/r []
diff --git a/src/cmd/go/version.go b/src/cmd/go/version.go
deleted file mode 100644
index 3045f35..0000000
--- a/src/cmd/go/version.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-	"fmt"
-	"runtime"
-)
-
-var cmdVersion = &Command{
-	Run:       runVersion,
-	UsageLine: "version",
-	Short:     "print Go version",
-	Long:      `Version prints the Go version, as reported by runtime.Version.`,
-}
-
-func runVersion(cmd *Command, args []string) {
-	if len(args) != 0 {
-		cmd.Usage()
-	}
-
-	fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
-}
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
deleted file mode 100644
index 8e296c8..0000000
--- a/src/cmd/go/vet.go
+++ /dev/null
@@ -1,52 +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 main
-
-import "path/filepath"
-
-func init() {
-	addBuildFlags(cmdVet)
-}
-
-var cmdVet = &Command{
-	Run:       runVet,
-	UsageLine: "vet [-n] [-x] [build flags] [packages]",
-	Short:     "run go tool vet on packages",
-	Long: `
-Vet runs the Go vet command on the packages named by the import paths.
-
-For more about vet, see '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.
-	`,
-}
-
-func runVet(cmd *Command, args []string) {
-	for _, p := range packages(args) {
-		// Vet expects to be given a set of files all from the same package.
-		// Run once for package p and once for package p_test.
-		if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
-			runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
-		}
-		if len(p.XTestGoFiles) > 0 {
-			runVetFiles(p, stringList(p.XTestGoFiles))
-		}
-	}
-}
-
-func runVetFiles(p *Package, files []string) {
-	for i := range files {
-		files[i] = filepath.Join(p.Dir, files[i])
-	}
-	run(buildToolExec, tool("vet"), relPaths(files))
-}
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 8b22f03..e340665 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -4,7 +4,8 @@
 
 /*
 Gofmt formats Go programs.
-It uses tabs (width = 8) for indentation and blanks for alignment.
+It uses tabs for indentation and blanks for alignment.
+Alignment assumes that an editor is using a fixed-width font.
 
 Without an explicit path, it processes the standard input.  Given a file,
 it operates on that file; given a directory, it operates on all .go files in
@@ -100,4 +101,4 @@ package main
 
 // BUG(rsc): The implementation of -r is a bit slow.
 // BUG(gri): If -w fails, the restored original file may not have some of the
-//           original file attributes.
+// original file attributes.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index e1ef0dd..d5b7be3 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -139,11 +139,11 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 			}
 		}
 		if *doDiff {
-			data, err := diff(src, res)
+			data, err := diff(src, res, filename)
 			if err != nil {
 				return fmt.Errorf("computing diff: %s", err)
 			}
-			fmt.Printf("diff %s gofmt/%s\n", filename, filename)
+			fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
 			out.Write(data)
 		}
 	}
@@ -225,32 +225,76 @@ func gofmtMain() {
 	}
 }
 
-func diff(b1, b2 []byte) (data []byte, err error) {
-	f1, err := ioutil.TempFile("", "gofmt")
+func writeTempFile(dir, prefix string, data []byte) (string, error) {
+	file, err := ioutil.TempFile(dir, prefix)
+	if err != nil {
+		return "", err
+	}
+	_, err = file.Write(data)
+	if err1 := file.Close(); err == nil {
+		err = err1
+	}
+	if err != nil {
+		os.Remove(file.Name())
+		return "", err
+	}
+	return file.Name(), nil
+}
+
+func diff(b1, b2 []byte, filename string) (data []byte, err error) {
+	f1, err := writeTempFile("", "gofmt", b1)
 	if err != nil {
 		return
 	}
-	defer os.Remove(f1.Name())
-	defer f1.Close()
+	defer os.Remove(f1)
 
-	f2, err := ioutil.TempFile("", "gofmt")
+	f2, err := writeTempFile("", "gofmt", b2)
 	if err != nil {
 		return
 	}
-	defer os.Remove(f2.Name())
-	defer f2.Close()
+	defer os.Remove(f2)
 
-	f1.Write(b1)
-	f2.Write(b2)
+	cmd := "diff"
+	if runtime.GOOS == "plan9" {
+		cmd = "/bin/ape/diff"
+	}
 
-	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+	data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
 	if len(data) > 0 {
 		// diff exits with a non-zero status when the files don't match.
 		// Ignore that failure as long as we get output.
-		err = nil
+		return replaceTempFilename(data, filename)
 	}
 	return
+}
 
+// replaceTempFilename replaces temporary filenames in diff with actual one.
+//
+// --- /tmp/gofmt316145376	2017-02-03 19:13:00.280468375 -0500
+// +++ /tmp/gofmt617882815	2017-02-03 19:13:00.280468375 -0500
+// ...
+// ->
+// --- path/to/file.go.orig	2017-02-03 19:13:00.280468375 -0500
+// +++ path/to/file.go	2017-02-03 19:13:00.280468375 -0500
+// ...
+func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
+	bs := bytes.SplitN(diff, []byte{'\n'}, 3)
+	if len(bs) < 3 {
+		return nil, fmt.Errorf("got unexpected diff for %s", filename)
+	}
+	// Preserve timestamps.
+	var t0, t1 []byte
+	if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
+		t0 = bs[0][i:]
+	}
+	if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
+		t1 = bs[1][i:]
+	}
+	// Always print filepath with slash separator.
+	f := filepath.ToSlash(filename)
+	bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
+	bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
+	return bytes.Join(bs, []byte{'\n'}), nil
 }
 
 const chmodSupported = runtime.GOOS != "windows"
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index b7ca9e8..16b653b 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -9,7 +9,9 @@ import (
 	"flag"
 	"io/ioutil"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"testing"
 	"text/scanner"
@@ -110,7 +112,7 @@ func runTest(t *testing.T, in, out string) {
 		}
 
 		t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
-		d, err := diff(expected, got)
+		d, err := diff(expected, got, in)
 		if err == nil {
 			t.Errorf("%s", d)
 		}
@@ -184,3 +186,69 @@ func TestBackupFile(t *testing.T) {
 	}
 	t.Logf("Created: %s", name)
 }
+
+func TestDiff(t *testing.T) {
+	if _, err := exec.LookPath("diff"); err != nil {
+		t.Skipf("skip test on %s: diff command is required", runtime.GOOS)
+	}
+	in := []byte("first\nsecond\n")
+	out := []byte("first\nthird\n")
+	filename := "difftest.txt"
+	b, err := diff(in, out, filename)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if runtime.GOOS == "windows" {
+		b = bytes.Replace(b, []byte{'\r', '\n'}, []byte{'\n'}, -1)
+	}
+
+	bs := bytes.SplitN(b, []byte{'\n'}, 3)
+	line0, line1 := bs[0], bs[1]
+
+	if prefix := "--- difftest.txt.orig"; !bytes.HasPrefix(line0, []byte(prefix)) {
+		t.Errorf("diff: first line should start with `%s`\ngot: %s", prefix, line0)
+	}
+
+	if prefix := "+++ difftest.txt"; !bytes.HasPrefix(line1, []byte(prefix)) {
+		t.Errorf("diff: second line should start with `%s`\ngot: %s", prefix, line1)
+	}
+
+	want := `@@ -1,2 +1,2 @@
+ first
+-second
++third
+`
+
+	if got := string(bs[2]); got != want {
+		t.Errorf("diff: got:\n%s\nwant:\n%s", got, want)
+	}
+}
+
+func TestReplaceTempFilename(t *testing.T) {
+	diff := []byte(`--- /tmp/tmpfile1	2017-02-08 00:53:26.175105619 +0900
++++ /tmp/tmpfile2	2017-02-08 00:53:38.415151275 +0900
+@@ -1,2 +1,2 @@
+ first
+-second
++third
+`)
+	want := []byte(`--- path/to/file.go.orig	2017-02-08 00:53:26.175105619 +0900
++++ path/to/file.go	2017-02-08 00:53:38.415151275 +0900
+@@ -1,2 +1,2 @@
+ first
+-second
++third
+`)
+	// Check path in diff output is always slash regardless of the
+	// os.PathSeparator (`/` or `\`).
+	sep := string(os.PathSeparator)
+	filename := strings.Join([]string{"path", "to", "file.go"}, sep)
+	got, err := replaceTempFilename(diff, filename)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(got, want) {
+		t.Errorf("os.PathSeparator='%s': replacedDiff:\ngot:\n%s\nwant:\n%s", sep, got, want)
+	}
+}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 550492b..79b7858 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -66,10 +66,10 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
 		if !val.IsValid() {
 			return reflect.Value{}
 		}
+		val = apply(rewriteVal, val)
 		for k := range m {
 			delete(m, k)
 		}
-		val = apply(rewriteVal, val)
 		if match(m, pat, val) {
 			val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
 		}
diff --git a/src/cmd/gofmt/testdata/rewrite9.golden b/src/cmd/gofmt/testdata/rewrite9.golden
new file mode 100644
index 0000000..fffbd3d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite9.golden
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 The Go 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 18987.
+
+package p
+
+const _ = x != 1
diff --git a/src/cmd/gofmt/testdata/rewrite9.input b/src/cmd/gofmt/testdata/rewrite9.input
new file mode 100644
index 0000000..106ad94
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite9.input
@@ -0,0 +1,11 @@
+//gofmt -r=a&&b!=2->a
+
+// Copyright 2017 The Go 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 18987.
+
+package p
+
+const _ = x != 1 && x != 2
diff --git a/src/cmd/gofmt/testdata/typealias.golden b/src/cmd/gofmt/testdata/typealias.golden
new file mode 100644
index 0000000..bbbbf32
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.golden
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+	_  = chan<- int
+	aa = interface{}
+	bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+	_   chan<- int
+	_   = chan<- int
+	aa0 interface{}
+	aaa = interface{}
+	bb0 p.BB
+	bbb = p.BB
+)
diff --git a/src/cmd/gofmt/testdata/typealias.input b/src/cmd/gofmt/testdata/typealias.input
new file mode 100644
index 0000000..6e49328
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.input
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+	_ = chan<- int
+	aa = interface{}
+	bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+	_ chan<- int
+	_ = chan<- int
+	aa0 interface{}
+	aaa = interface{}
+	bb0 p.BB
+	bbb = p.BB
+)
diff --git a/src/cmd/internal/browser/browser.go b/src/cmd/internal/browser/browser.go
index 897086f..6867c85 100644
--- a/src/cmd/internal/browser/browser.go
+++ b/src/cmd/internal/browser/browser.go
@@ -9,6 +9,7 @@ import (
 	"os"
 	"os/exec"
 	"runtime"
+	"time"
 )
 
 // Commands returns a list of possible commands to use to open a url.
@@ -23,7 +24,10 @@ func Commands() [][]string {
 	case "windows":
 		cmds = append(cmds, []string{"cmd", "/c", "start"})
 	default:
-		cmds = append(cmds, []string{"xdg-open"})
+		if os.Getenv("DISPLAY") != "" {
+			// xdg-open is only for use in a desktop environment.
+			cmds = append(cmds, []string{"xdg-open"})
+		}
 	}
 	cmds = append(cmds,
 		[]string{"chrome"},
@@ -38,9 +42,26 @@ func Commands() [][]string {
 func Open(url string) bool {
 	for _, args := range Commands() {
 		cmd := exec.Command(args[0], append(args[1:], url)...)
-		if cmd.Start() == nil {
+		if cmd.Start() == nil && appearsSuccessful(cmd, 3*time.Second) {
 			return true
 		}
 	}
 	return false
 }
+
+// appearsSuccessful reports whether the command appears to have run successfully.
+// If the command runs longer than the timeout, it's deemed successful.
+// If the command runs within the timeout, it's deemed successful if it exited cleanly.
+func appearsSuccessful(cmd *exec.Cmd, timeout time.Duration) bool {
+	errc := make(chan error, 1)
+	go func() {
+		errc <- cmd.Wait()
+	}()
+
+	select {
+	case <-time.After(timeout):
+		return true
+	case err := <-errc:
+		return err == nil
+	}
+}
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
index 725f502..a617c38 100644
--- a/src/cmd/internal/dwarf/dwarf.go
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -8,15 +8,19 @@
 package dwarf
 
 import (
+	"errors"
 	"fmt"
-	"strings"
 )
 
 // InfoPrefix is the prefix for all the symbols containing DWARF info entries.
 const InfoPrefix = "go.info."
 
+// RangePrefix is the prefix for all the symbols containing DWARF range lists.
+const RangePrefix = "go.range."
+
 // Sym represents a symbol.
 type Sym interface {
+	Len() int64
 }
 
 // A Var represents a local variable or a function parameter.
@@ -24,8 +28,60 @@ type Var struct {
 	Name   string
 	Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
 	Offset int32
+	Scope  int32
 	Type   Sym
-	Link   *Var
+}
+
+// A Scope represents a lexical scope. All variables declared within a
+// scope will only be visible to instructions covered by the scope.
+// Lexical scopes are contiguous in source files but can end up being
+// compiled to discontiguous blocks of instructions in the executable.
+// The Ranges field lists all the blocks of instructions that belong
+// in this scope.
+type Scope struct {
+	Parent int32
+	Ranges []Range
+	Vars   []*Var
+}
+
+// A Range represents a half-open interval [Start, End).
+type Range struct {
+	Start, End int64
+}
+
+// UnifyRanges merges the list of ranges of c into the list of ranges of s
+func (s *Scope) UnifyRanges(c *Scope) {
+	out := make([]Range, 0, len(s.Ranges)+len(c.Ranges))
+
+	i, j := 0, 0
+	for {
+		var cur Range
+		if i < len(s.Ranges) && j < len(c.Ranges) {
+			if s.Ranges[i].Start < c.Ranges[j].Start {
+				cur = s.Ranges[i]
+				i++
+			} else {
+				cur = c.Ranges[j]
+				j++
+			}
+		} else if i < len(s.Ranges) {
+			cur = s.Ranges[i]
+			i++
+		} else if j < len(c.Ranges) {
+			cur = c.Ranges[j]
+			j++
+		} else {
+			break
+		}
+
+		if n := len(out); n > 0 && cur.Start <= out[n-1].End {
+			out[n-1].End = cur.End
+		} else {
+			out = append(out, cur)
+		}
+	}
+
+	s.Ranges = out
 }
 
 // A Context specifies how to add data to a Sym.
@@ -72,17 +128,56 @@ func AppendSleb128(b []byte, v int64) []byte {
 	return b
 }
 
-var encbuf [20]byte
+// sevenbits contains all unsigned seven bit numbers, indexed by their value.
+var sevenbits = [...]byte{
+	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,
+}
+
+// sevenBitU returns the unsigned LEB128 encoding of v if v is seven bits and nil otherwise.
+// The contents of the returned slice must not be modified.
+func sevenBitU(v int64) []byte {
+	if uint64(v) < uint64(len(sevenbits)) {
+		return sevenbits[v : v+1]
+	}
+	return nil
+}
+
+// sevenBitS returns the signed LEB128 encoding of v if v is seven bits and nil otherwise.
+// The contents of the returned slice must not be modified.
+func sevenBitS(v int64) []byte {
+	if uint64(v) <= 63 {
+		return sevenbits[v : v+1]
+	}
+	if uint64(-v) <= 64 {
+		return sevenbits[128+v : 128+v+1]
+	}
+	return nil
+}
 
-// AppendUleb128 appends v to s using DWARF's unsigned LEB128 encoding.
+// Uleb128put appends v to s using DWARF's unsigned LEB128 encoding.
 func Uleb128put(ctxt Context, s Sym, v int64) {
-	b := AppendUleb128(encbuf[:0], uint64(v))
+	b := sevenBitU(v)
+	if b == nil {
+		var encbuf [20]byte
+		b = AppendUleb128(encbuf[:0], uint64(v))
+	}
 	ctxt.AddBytes(s, b)
 }
 
-// AppendUleb128 appends v to s using DWARF's signed LEB128 encoding.
+// Sleb128put appends v to s using DWARF's signed LEB128 encoding.
 func Sleb128put(ctxt Context, s Sym, v int64) {
-	b := AppendSleb128(encbuf[:0], v)
+	b := sevenBitS(v)
+	if b == nil {
+		var encbuf [20]byte
+		b = AppendSleb128(encbuf[:0], v)
+	}
 	ctxt.AddBytes(s, b)
 }
 
@@ -102,6 +197,9 @@ const (
 	DW_AT_go_kind = 0x2900
 	DW_AT_go_key  = 0x2901
 	DW_AT_go_elem = 0x2902
+	// Attribute for DW_TAG_member of a struct type.
+	// Nonzero value indicates the struct field is an embedded field.
+	DW_AT_go_embedded_field = 0x2903
 
 	DW_AT_internal_location = 253 // params and locals; not emitted
 )
@@ -116,6 +214,8 @@ const (
 	DW_ABRV_VARIABLE
 	DW_ABRV_AUTO
 	DW_ABRV_PARAM
+	DW_ABRV_LEXICAL_BLOCK_RANGES
+	DW_ABRV_LEXICAL_BLOCK_SIMPLE
 	DW_ABRV_STRUCTFIELD
 	DW_ABRV_FUNCTYPEPARAM
 	DW_ABRV_DOTDOTDOT
@@ -155,8 +255,9 @@ var abbrevs = [DW_NABRV]dwAbbrev{
 			{DW_AT_language, DW_FORM_data1},
 			{DW_AT_low_pc, DW_FORM_addr},
 			{DW_AT_high_pc, DW_FORM_addr},
-			{DW_AT_stmt_list, DW_FORM_data4},
+			{DW_AT_stmt_list, DW_FORM_sec_offset},
 			{DW_AT_comp_dir, DW_FORM_string},
+			{DW_AT_producer, DW_FORM_string},
 		},
 	},
 
@@ -168,6 +269,7 @@ var abbrevs = [DW_NABRV]dwAbbrev{
 			{DW_AT_name, DW_FORM_string},
 			{DW_AT_low_pc, DW_FORM_addr},
 			{DW_AT_high_pc, DW_FORM_addr},
+			{DW_AT_frame_base, DW_FORM_block1},
 			{DW_AT_external, DW_FORM_flag},
 		},
 	},
@@ -205,6 +307,24 @@ var abbrevs = [DW_NABRV]dwAbbrev{
 			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
+	/* LEXICAL_BLOCK_RANGES */
+	{
+		DW_TAG_lexical_block,
+		DW_CHILDREN_yes,
+		[]dwAttrForm{
+			{DW_AT_ranges, DW_FORM_sec_offset},
+		},
+	},
+
+	/* LEXICAL_BLOCK_SIMPLE */
+	{
+		DW_TAG_lexical_block,
+		DW_CHILDREN_yes,
+		[]dwAttrForm{
+			{DW_AT_low_pc, DW_FORM_addr},
+			{DW_AT_high_pc, DW_FORM_addr},
+		},
+	},
 
 	/* STRUCTFIELD */
 	{
@@ -214,6 +334,7 @@ var abbrevs = [DW_NABRV]dwAbbrev{
 			{DW_AT_name, DW_FORM_string},
 			{DW_AT_data_member_location, DW_FORM_block1},
 			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_embedded_field, DW_FORM_flag},
 		},
 	},
 
@@ -400,7 +521,6 @@ func GetAbbrev() []byte {
 	for i := 1; i < DW_NABRV; i++ {
 		// See section 7.5.3
 		buf = AppendUleb128(buf, uint64(i))
-
 		buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
 		buf = append(buf, byte(abbrevs[i].children))
 		for _, f := range abbrevs[i].attr {
@@ -484,8 +604,8 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
 		ctxt.AddInt(s, 2, value)
 
 	case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
-		if cls == DW_CLS_PTR { // DW_AT_stmt_list
-			ctxt.AddSectionOffset(s, 4, data, 0)
+		if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges
+			ctxt.AddSectionOffset(s, 4, data, value)
 			break
 		}
 		ctxt.AddInt(s, 4, value)
@@ -514,16 +634,15 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
 			ctxt.AddInt(s, 1, 0)
 		}
 
-	// In DWARF 2 (which is what we claim to generate),
-	// the ref_addr is the same size as a normal address.
-	// In DWARF 3 it is always 32 bits, unless emitting a large
+	// As of DWARF 3 the ref_addr is always 32 bits, unless emitting a large
 	// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
 	case DW_FORM_ref_addr: // reference to a DIE in the .info section
+		fallthrough
+	case DW_FORM_sec_offset: // offset into a DWARF section other than .info
 		if data == nil {
 			return fmt.Errorf("dwarf: null reference in %d", abbrev)
-		} else {
-			ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, 0)
 		}
+		ctxt.AddSectionOffset(s, 4, data, value)
 
 	case DW_FORM_ref1, // reference within the compilation unit
 		DW_FORM_ref2,      // reference
@@ -565,40 +684,84 @@ func HasChildren(die *DWDie) bool {
 
 // PutFunc writes a DIE for a function to s.
 // It also writes child DIEs for each variable in vars.
-func PutFunc(ctxt Context, s Sym, name string, external bool, startPC Sym, size int64, vars *Var) {
+func PutFunc(ctxt Context, s, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
 	Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
 	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
 	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
-	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size+ctxt.SymValue(startPC), startPC)
+	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
+	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
 	var ev int64
 	if external {
 		ev = 1
 	}
 	putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
-	names := make(map[string]bool)
-	for v := vars; v != nil; v = v.Link {
-		if strings.Contains(v.Name, ".autotmp_") {
-			continue
+	if len(scopes) > 0 {
+		var encbuf [20]byte
+		if putscope(ctxt, s, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
+			return errors.New("multiple toplevel scopes")
 		}
-		var n string
-		if names[v.Name] {
-			n = fmt.Sprintf("%s#%d", v.Name, len(names))
-		} else {
-			n = v.Name
+	}
+
+	Uleb128put(ctxt, s, 0)
+	return nil
+}
+
+func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
+	for _, v := range scopes[curscope].Vars {
+		putvar(ctxt, s, v, encbuf)
+	}
+	this := curscope
+	curscope++
+	for curscope < int32(len(scopes)) {
+		scope := scopes[curscope]
+		if scope.Parent != this {
+			return curscope
 		}
-		names[n] = true
-
-		Uleb128put(ctxt, s, int64(v.Abbrev))
-		putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
-		loc := append(encbuf[:0], DW_OP_call_frame_cfa)
-		if v.Offset != 0 {
-			loc = append(loc, DW_OP_consts)
-			loc = AppendSleb128(loc, int64(v.Offset))
-			loc = append(loc, DW_OP_plus)
+
+		if len(scope.Ranges) == 1 {
+			Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
+			putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
+			putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
+		} else {
+			Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES)
+			putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
+
+			ctxt.AddAddress(ranges, nil, -1)
+			ctxt.AddAddress(ranges, startPC, 0)
+			for _, r := range scope.Ranges {
+				ctxt.AddAddress(ranges, nil, r.Start)
+				ctxt.AddAddress(ranges, nil, r.End)
+			}
+			ctxt.AddAddress(ranges, nil, 0)
+			ctxt.AddAddress(ranges, nil, 0)
 		}
-		putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
-		putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
 
+		curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
+
+		Uleb128put(ctxt, s, 0)
 	}
-	Uleb128put(ctxt, s, 0)
+	return curscope
+}
+
+func putvar(ctxt Context, s Sym, v *Var, encbuf []byte) {
+	n := v.Name
+
+	Uleb128put(ctxt, s, int64(v.Abbrev))
+	putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
+	loc := append(encbuf[:0], DW_OP_call_frame_cfa)
+	if v.Offset != 0 {
+		loc = append(loc, DW_OP_consts)
+		loc = AppendSleb128(loc, int64(v.Offset))
+		loc = append(loc, DW_OP_plus)
+	}
+	putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
+	putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
 }
+
+// VarsByOffset attaches the methods of sort.Interface to []*Var,
+// sorting in increasing Offset.
+type VarsByOffset []*Var
+
+func (s VarsByOffset) Len() int           { return len(s) }
+func (s VarsByOffset) Less(i, j int) bool { return s[i].Offset < s[j].Offset }
+func (s VarsByOffset) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
diff --git a/src/cmd/internal/dwarf/dwarf_defs.go b/src/cmd/internal/dwarf/dwarf_defs.go
index d1870b5..da238b7 100644
--- a/src/cmd/internal/dwarf/dwarf_defs.go
+++ b/src/cmd/internal/dwarf/dwarf_defs.go
@@ -212,6 +212,11 @@ const (
 	DW_FORM_ref8      = 0x14 // reference
 	DW_FORM_ref_udata = 0x15 // reference
 	DW_FORM_indirect  = 0x16 // (see Section 7.5.3)
+	// Dwarf4
+	DW_FORM_sec_offset   = 0x17 // lineptr, loclistptr, macptr, rangelistptr
+	DW_FORM_exprloc      = 0x18 // exprloc
+	DW_FORM_flag_present = 0x19 // flag
+	DW_FORM_ref_sig8     = 0x20 // reference
 )
 
 // Table 24 (#operands, notes)
diff --git a/src/cmd/internal/dwarf/dwarf_test.go b/src/cmd/internal/dwarf/dwarf_test.go
new file mode 100644
index 0000000..248a39b
--- /dev/null
+++ b/src/cmd/internal/dwarf/dwarf_test.go
@@ -0,0 +1,38 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestSevenBitEnc128(t *testing.T) {
+	t.Run("unsigned", func(t *testing.T) {
+		for v := int64(-255); v < 255; v++ {
+			s := sevenBitU(v)
+			if s == nil {
+				continue
+			}
+			b := AppendUleb128(nil, uint64(v))
+			if !reflect.DeepEqual(b, s) {
+				t.Errorf("sevenBitU(%d) = %v but AppendUleb128(%d) = %v", v, s, v, b)
+			}
+		}
+	})
+
+	t.Run("signed", func(t *testing.T) {
+		for v := int64(-255); v < 255; v++ {
+			s := sevenBitS(v)
+			if s == nil {
+				continue
+			}
+			b := AppendSleb128(nil, v)
+			if !reflect.DeepEqual(b, s) {
+				t.Errorf("sevenBitS(%d) = %v but AppendSleb128(%d) = %v", v, s, v, b)
+			}
+		}
+	})
+}
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index ff4aa59..b6c90d3 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -12,7 +12,7 @@ package goobj
 import (
 	"bufio"
 	"bytes"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"errors"
 	"fmt"
 	"io"
@@ -20,113 +20,16 @@ import (
 	"strings"
 )
 
-// A SymKind describes the kind of memory represented by a symbol.
-type SymKind int
-
-// This list is taken from include/link.h.
-
-// Defined SymKind values.
-// TODO(rsc): Give idiomatic Go names.
-// TODO(rsc): Reduce the number of symbol types in the object files.
-const (
-	// readonly, executable
-	STEXT      = SymKind(obj.STEXT)
-	SELFRXSECT = SymKind(obj.SELFRXSECT)
-
-	// readonly, non-executable
-	STYPE      = SymKind(obj.STYPE)
-	SSTRING    = SymKind(obj.SSTRING)
-	SGOSTRING  = SymKind(obj.SGOSTRING)
-	SGOFUNC    = SymKind(obj.SGOFUNC)
-	SRODATA    = SymKind(obj.SRODATA)
-	SFUNCTAB   = SymKind(obj.SFUNCTAB)
-	STYPELINK  = SymKind(obj.STYPELINK)
-	SITABLINK  = SymKind(obj.SITABLINK)
-	SSYMTAB    = SymKind(obj.SSYMTAB) // TODO: move to unmapped section
-	SPCLNTAB   = SymKind(obj.SPCLNTAB)
-	SELFROSECT = SymKind(obj.SELFROSECT)
-
-	// writable, non-executable
-	SMACHOPLT  = SymKind(obj.SMACHOPLT)
-	SELFSECT   = SymKind(obj.SELFSECT)
-	SMACHO     = SymKind(obj.SMACHO) // Mach-O __nl_symbol_ptr
-	SMACHOGOT  = SymKind(obj.SMACHOGOT)
-	SWINDOWS   = SymKind(obj.SWINDOWS)
-	SELFGOT    = SymKind(obj.SELFGOT)
-	SNOPTRDATA = SymKind(obj.SNOPTRDATA)
-	SINITARR   = SymKind(obj.SINITARR)
-	SDATA      = SymKind(obj.SDATA)
-	SBSS       = SymKind(obj.SBSS)
-	SNOPTRBSS  = SymKind(obj.SNOPTRBSS)
-	STLSBSS    = SymKind(obj.STLSBSS)
-
-	// not mapped
-	SXREF             = SymKind(obj.SXREF)
-	SMACHOSYMSTR      = SymKind(obj.SMACHOSYMSTR)
-	SMACHOSYMTAB      = SymKind(obj.SMACHOSYMTAB)
-	SMACHOINDIRECTPLT = SymKind(obj.SMACHOINDIRECTPLT)
-	SMACHOINDIRECTGOT = SymKind(obj.SMACHOINDIRECTGOT)
-	SFILE             = SymKind(obj.SFILE)
-	SFILEPATH         = SymKind(obj.SFILEPATH)
-	SCONST            = SymKind(obj.SCONST)
-	SDYNIMPORT        = SymKind(obj.SDYNIMPORT)
-	SHOSTOBJ          = SymKind(obj.SHOSTOBJ)
-)
-
-var symKindStrings = []string{
-	SBSS:              "SBSS",
-	SCONST:            "SCONST",
-	SDATA:             "SDATA",
-	SDYNIMPORT:        "SDYNIMPORT",
-	SELFROSECT:        "SELFROSECT",
-	SELFRXSECT:        "SELFRXSECT",
-	SELFSECT:          "SELFSECT",
-	SFILE:             "SFILE",
-	SFILEPATH:         "SFILEPATH",
-	SFUNCTAB:          "SFUNCTAB",
-	SGOFUNC:           "SGOFUNC",
-	SGOSTRING:         "SGOSTRING",
-	SHOSTOBJ:          "SHOSTOBJ",
-	SINITARR:          "SINITARR",
-	SMACHO:            "SMACHO",
-	SMACHOGOT:         "SMACHOGOT",
-	SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
-	SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
-	SMACHOPLT:         "SMACHOPLT",
-	SMACHOSYMSTR:      "SMACHOSYMSTR",
-	SMACHOSYMTAB:      "SMACHOSYMTAB",
-	SNOPTRBSS:         "SNOPTRBSS",
-	SNOPTRDATA:        "SNOPTRDATA",
-	SPCLNTAB:          "SPCLNTAB",
-	SRODATA:           "SRODATA",
-	SSTRING:           "SSTRING",
-	SSYMTAB:           "SSYMTAB",
-	STEXT:             "STEXT",
-	STLSBSS:           "STLSBSS",
-	STYPE:             "STYPE",
-	STYPELINK:         "STYPELINK",
-	SITABLINK:         "SITABLINK",
-	SWINDOWS:          "SWINDOWS",
-	SXREF:             "SXREF",
-}
-
-func (k SymKind) String() string {
-	if k < 0 || int(k) >= len(symKindStrings) {
-		return fmt.Sprintf("SymKind(%d)", k)
-	}
-	return symKindStrings[k]
-}
-
 // A Sym is a named symbol in an object file.
 type Sym struct {
-	SymID         // symbol identifier (name and version)
-	Kind  SymKind // kind of symbol
-	DupOK bool    // are duplicate definitions okay?
-	Size  int     // size of corresponding data
-	Type  SymID   // symbol for Go type information
-	Data  Data    // memory image of symbol
-	Reloc []Reloc // relocations to apply to Data
-	Func  *Func   // additional data for functions
+	SymID                // symbol identifier (name and version)
+	Kind  objabi.SymKind // kind of symbol
+	DupOK bool           // are duplicate definitions okay?
+	Size  int            // size of corresponding data
+	Type  SymID          // symbol for Go type information
+	Data  Data           // memory image of symbol
+	Reloc []Reloc        // relocations to apply to Data
+	Func  *Func          // additional data for functions
 }
 
 // A SymID - the combination of Name and Version - uniquely identifies
@@ -172,7 +75,7 @@ type Reloc struct {
 	// The Type records the form of address expected in the bytes
 	// described by the previous fields: absolute, PC-relative, and so on.
 	// TODO(rsc): The interpretation of Type is not exposed by this package.
-	Type obj.RelocType
+	Type objabi.RelocType
 }
 
 // A Var describes a variable in a function stack frame: a declared
@@ -198,9 +101,11 @@ type Func struct {
 	PCSP     Data       // PC → SP offset map
 	PCFile   Data       // PC → file number map (index into File)
 	PCLine   Data       // PC → line number map
+	PCInline Data       // PC → inline tree index map
 	PCData   []Data     // PC → runtime support data map
 	FuncData []FuncData // non-PC-specific runtime support data
 	File     []string   // paths indexed by PCFile
+	InlTree  []InlinedCall
 }
 
 // TODO: Add PCData []byte and PCDataIter (similar to liblink).
@@ -211,6 +116,15 @@ type FuncData struct {
 	Offset int64 // offset into symbol for funcdata pointer
 }
 
+// An InlinedCall is a node in an InlTree.
+// See cmd/internal/obj.InlTree for details.
+type InlinedCall struct {
+	Parent int
+	File   string
+	Line   int
+	Func   SymID
+}
+
 // A Package is a parsed Go object file or archive defining a Go package.
 type Package struct {
 	ImportPath string   // import path denoting this package
@@ -245,45 +159,6 @@ type objReader struct {
 	pkgprefix  string
 }
 
-// importPathToPrefix returns the prefix that will be used in the
-// final symbol table for the given import path.
-// We escape '%', '"', all control characters and non-ASCII bytes,
-// and any '.' after the final slash.
-//
-// See ../../../cmd/ld/lib.c:/^pathtoprefix and
-// ../../../cmd/gc/subr.c:/^pathtoprefix.
-func importPathToPrefix(s string) string {
-	// find index of last slash, if any, or else -1.
-	// used for determining whether an index is after the last slash.
-	slash := strings.LastIndex(s, "/")
-
-	// check for chars that need escaping
-	n := 0
-	for r := 0; r < len(s); r++ {
-		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
-			n++
-		}
-	}
-
-	// quick exit
-	if n == 0 {
-		return s
-	}
-
-	// escape
-	const hex = "0123456789abcdef"
-	p := make([]byte, 0, len(s)+2*n)
-	for r := 0; r < len(s); r++ {
-		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
-			p = append(p, '%', hex[c>>4], hex[c&0xF])
-		} else {
-			p = append(p, c)
-		}
-	}
-
-	return string(p)
-}
-
 // init initializes r to read package p from f.
 func (r *objReader) init(f io.ReadSeeker, p *Package) {
 	r.f = f
@@ -292,7 +167,7 @@ func (r *objReader) init(f io.ReadSeeker, p *Package) {
 	r.limit, _ = f.Seek(0, io.SeekEnd)
 	f.Seek(r.offset, io.SeekStart)
 	r.b = bufio.NewReader(f)
-	r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
+	r.pkgprefix = objabi.PathToPrefix(p.ImportPath) + "."
 }
 
 // error records that an error occurred.
@@ -583,7 +458,7 @@ func (r *objReader) parseObject(prefix []byte) error {
 	// TODO: extract OS + build ID if/when we need it
 
 	r.readFull(r.tmp[:8])
-	if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go17ld")) {
+	if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go19ld")) {
 		return r.error(errCorruptObject)
 	}
 
@@ -632,10 +507,10 @@ func (r *objReader) parseObject(prefix []byte) error {
 			break
 		}
 
-		typ := r.readInt()
+		typ := r.readByte()
 		s := &Sym{SymID: r.readSymID()}
 		r.p.Syms = append(r.p.Syms, s)
-		s.Kind = SymKind(typ)
+		s.Kind = objabi.SymKind(typ)
 		flags := r.readInt()
 		s.DupOK = flags&1 != 0
 		s.Size = r.readInt()
@@ -646,18 +521,18 @@ func (r *objReader) parseObject(prefix []byte) error {
 			rel := &s.Reloc[i]
 			rel.Offset = r.readInt()
 			rel.Size = r.readInt()
-			rel.Type = obj.RelocType(r.readInt())
+			rel.Type = objabi.RelocType(r.readInt())
 			rel.Add = r.readInt()
 			rel.Sym = r.readSymID()
 		}
 
-		if s.Kind == STEXT {
+		if s.Kind == objabi.STEXT {
 			f := new(Func)
 			s.Func = f
 			f.Args = r.readInt()
 			f.Frame = r.readInt()
 			flags := r.readInt()
-			f.Leaf = flags&1 != 0
+			f.Leaf = flags&(1<<0) != 0
 			f.NoSplit = r.readInt() != 0
 			f.Var = make([]Var, r.readInt())
 			for i := range f.Var {
@@ -671,6 +546,7 @@ func (r *objReader) parseObject(prefix []byte) error {
 			f.PCSP = r.readData()
 			f.PCFile = r.readData()
 			f.PCLine = r.readData()
+			f.PCInline = r.readData()
 			f.PCData = make([]Data, r.readInt())
 			for i := range f.PCData {
 				f.PCData[i] = r.readData()
@@ -686,11 +562,18 @@ func (r *objReader) parseObject(prefix []byte) error {
 			for i := range f.File {
 				f.File[i] = r.readSymID().Name
 			}
+			f.InlTree = make([]InlinedCall, r.readInt())
+			for i := range f.InlTree {
+				f.InlTree[i].Parent = r.readInt()
+				f.InlTree[i].File = r.readSymID().Name
+				f.InlTree[i].Line = r.readInt()
+				f.InlTree[i].Func = r.readSymID()
+			}
 		}
 	}
 
 	r.readFull(r.tmp[:7])
-	if !bytes.Equal(r.tmp[:7], []byte("\xffgo17ld")) {
+	if !bytes.Equal(r.tmp[:7], []byte("\xffgo19ld")) {
 		return r.error(errCorruptObject)
 	}
 
diff --git a/src/cmd/internal/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go
deleted file mode 100644
index ff165e8..0000000
--- a/src/cmd/internal/goobj/read_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package goobj
-
-import "testing"
-
-var importPathToPrefixTests = []struct {
-	in  string
-	out string
-}{
-	{"runtime", "runtime"},
-	{"sync/atomic", "sync/atomic"},
-	{"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"},
-	{"foo.bar/baz.quux", "foo.bar/baz%2equux"},
-	{"", ""},
-	{"%foo%bar", "%25foo%25bar"},
-	{"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"},
-}
-
-func TestImportPathToPrefix(t *testing.T) {
-	for _, tt := range importPathToPrefixTests {
-		if out := importPathToPrefix(tt.in); out != tt.out {
-			t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out)
-		}
-	}
-}
diff --git a/src/cmd/internal/obj/arm/a.out.go b/src/cmd/internal/obj/arm/a.out.go
index ad19f2d..6ea7d4b 100644
--- a/src/cmd/internal/obj/arm/a.out.go
+++ b/src/cmd/internal/obj/arm/a.out.go
@@ -121,9 +121,11 @@ const (
 	C_PSR
 	C_FCR
 
-	C_RCON /* 0xff rotated */
-	C_NCON /* ~RCON */
-	C_SCON /* 0xffff */
+	C_RCON   /* 0xff rotated */
+	C_NCON   /* ~RCON */
+	C_RCON2A /* OR of two disjoint C_RCON constants */
+	C_RCON2S /* subtraction of two disjoint C_RCON constants */
+	C_SCON   /* 0xffff */
 	C_LCON
 	C_LCONADDR
 	C_ZFCON
@@ -243,9 +245,12 @@ const (
 	AMULU
 	ADIVU
 	AMUL
+	AMMUL
 	ADIV
 	AMOD
 	AMODU
+	ADIVHW
+	ADIVUHW
 
 	AMOVB
 	AMOVBS
@@ -261,6 +266,9 @@ const (
 	ARFE
 	ASWI
 	AMULA
+	AMULS
+	AMMULA
+	AMMULS
 
 	AWORD
 
@@ -281,11 +289,17 @@ const (
 	APLD
 
 	ACLZ
+	AREV
+	AREV16
+	AREVSH
+	ARBIT
 
 	AMULWT
 	AMULWB
+	AMULBB
 	AMULAWT
 	AMULAWB
+	AMULABB
 
 	ADATABUNDLE
 	ADATABUNDLEEND
diff --git a/src/cmd/internal/obj/arm/anames.go b/src/cmd/internal/obj/arm/anames.go
index 6d7db2d..63cc5da 100644
--- a/src/cmd/internal/obj/arm/anames.go
+++ b/src/cmd/internal/obj/arm/anames.go
@@ -67,9 +67,12 @@ var Anames = []string{
 	"MULU",
 	"DIVU",
 	"MUL",
+	"MMUL",
 	"DIV",
 	"MOD",
 	"MODU",
+	"DIVHW",
+	"DIVUHW",
 	"MOVB",
 	"MOVBS",
 	"MOVBU",
@@ -83,6 +86,9 @@ var Anames = []string{
 	"RFE",
 	"SWI",
 	"MULA",
+	"MULS",
+	"MMULA",
+	"MMULS",
 	"WORD",
 	"MULL",
 	"MULAL",
@@ -97,10 +103,16 @@ var Anames = []string{
 	"STREXD",
 	"PLD",
 	"CLZ",
+	"REV",
+	"REV16",
+	"REVSH",
+	"RBIT",
 	"MULWT",
 	"MULWB",
+	"MULBB",
 	"MULAWT",
 	"MULAWB",
+	"MULABB",
 	"DATABUNDLE",
 	"DATABUNDLEEND",
 	"MRC",
diff --git a/src/cmd/internal/obj/arm/anames5.go b/src/cmd/internal/obj/arm/anames5.go
index 7fdd962..bb98d3b 100644
--- a/src/cmd/internal/obj/arm/anames5.go
+++ b/src/cmd/internal/obj/arm/anames5.go
@@ -16,6 +16,8 @@ var cnames5 = []string{
 	"FCR",
 	"RCON",
 	"NCON",
+	"RCON2A",
+	"RCON2S",
 	"SCON",
 	"LCON",
 	"LCONADDR",
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index a1213bc..04b1cb7 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -32,12 +32,33 @@ package arm
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"log"
 	"math"
 	"sort"
 )
 
+// ctxt5 holds state while assembling a single function.
+// Each function gets a fresh ctxt5.
+// This allows for multiple functions to be safely concurrently assembled.
+type ctxt5 struct {
+	ctxt       *obj.Link
+	newprog    obj.ProgAlloc
+	cursym     *obj.LSym
+	printp     *obj.Prog
+	blitrl     *obj.Prog
+	elitrl     *obj.Prog
+	autosize   int64
+	instoffset int64
+	pc         int64
+	pool       struct {
+		start uint32
+		size  uint32
+		extra uint32
+	}
+}
+
 type Optab struct {
 	as       obj.As
 	a1       uint8
@@ -65,16 +86,28 @@ var optab = []Optab{
 	{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
 	{AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
 	{AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
 	{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
 	{AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
 	{ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
 	{AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
 	{AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
+	{AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
+	{AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
+	{AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
+	{AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
 	{AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
 	{AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
 	{ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0},
 	{AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
 	{AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	{AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	{AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
 	{AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
 	{ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0},
 	{AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0},
@@ -94,7 +127,6 @@ var optab = []Optab{
 	{ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
 	{ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0},
 	{ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
-	{ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0},
 	{ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0},
 	{AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0},
 	{AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0},
@@ -102,14 +134,37 @@ var optab = []Optab{
 	{AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0},
 	{AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0},
 	{AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0},
+	{AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0},
 	{AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
 	{AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
 	{AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
 	{AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	{AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	{AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
 	{AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
 	{ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0},
+	{AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	{AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	{AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	{AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	{ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0},
+	{AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0},
+	{AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0},
+	{AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0},
+	{AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0},
+	{AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0},
+	{AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0},
 	{AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
 	{AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
+	{AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
+	{AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
+	{AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
+	{AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
 	{AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
 	{ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
 	{AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
@@ -122,8 +177,9 @@ var optab = []Optab{
 	{AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
 	{ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0},
 	{ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0},
+	{ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0},
+	{ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0},
 	{AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0},
-	{AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0},
 	{AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
 	{AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
 	{AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
@@ -175,8 +231,9 @@ var optab = []Optab{
 	{AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4},
 	{AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
 	{AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
-	{AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0},
-	{AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0},
+	{AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0},
+	{ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0},
 	{AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0},
 	{AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0},
 	{AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
@@ -231,7 +288,7 @@ var optab = []Optab{
 	{ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0},
 	{AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0},
 	{AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0},
-	{ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0},
+	{ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0},
 	{ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0},
 	{AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0},
 	{AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0},
@@ -239,7 +296,6 @@ var optab = []Optab{
 	{AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0},
 	{AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0},
 	{AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0},
-	{ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0},
 	{ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0},
 	{ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0},
 	{APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0},
@@ -247,7 +303,6 @@ var optab = []Optab{
 	{ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0},
 	{AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0},
 	{AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0},
-	{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
 	{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0},
 	{obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
 	{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
@@ -259,17 +314,17 @@ var optab = []Optab{
 	{obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
 }
 
-var pool struct {
-	start uint32
-	size  uint32
-	extra uint32
-}
-
 var oprange [ALAST & obj.AMask][]Optab
 
 var xcmp [C_GOK + 1][C_GOK + 1]bool
 
-var deferreturn *obj.LSym
+var (
+	deferreturn *obj.LSym
+	symdiv      *obj.LSym
+	symdivu     *obj.LSym
+	symmod      *obj.LSym
+	symmodu     *obj.LSym
+)
 
 // Note about encoding: Prog.scond holds the condition encoding,
 // but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
@@ -281,14 +336,14 @@ var deferreturn *obj.LSym
 // p->pc if extra padding is necessary.
 // In rare cases, asmoutnacl might split p into two instructions.
 // origPC is the PC for this Prog (no padding is taken into account).
-func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
+func (c *ctxt5) asmoutnacl(origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
 	size := int(o.size)
 
 	// instruction specific
 	switch p.As {
 	default:
 		if out != nil {
-			asmout(ctxt, p, o, out)
+			c.asmout(p, o, out)
 		}
 
 	case ADATABUNDLE, // align to 16-byte boundary
@@ -296,7 +351,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 		p.Pc = (p.Pc + 15) &^ 15
 
 		if out != nil {
-			asmout(ctxt, p, o, out)
+			c.asmout(p, o, out)
 		}
 
 	case obj.AUNDEF,
@@ -315,11 +370,11 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 	case AB, ABL:
 		if p.To.Type != obj.TYPE_MEM {
 			if out != nil {
-				asmout(ctxt, p, o, out)
+				c.asmout(p, o, out)
 			}
 		} else {
 			if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 {
-				ctxt.Diag("unsupported instruction: %v", p)
+				c.ctxt.Diag("unsupported instruction: %v", p)
 			}
 			if p.Pc&15 == 12 {
 				p.Pc += 4
@@ -338,9 +393,6 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 
 		// align the last instruction (the actual BL) to the last instruction in a bundle
 		if p.As == ABL {
-			if deferreturn == nil {
-				deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
-			}
 			if p.To.Sym == deferreturn {
 				p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size)
 			} else {
@@ -364,7 +416,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 		ASTREXD:
 		if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC
 			if out != nil {
-				asmout(ctxt, p, o, out)
+				c.asmout(p, o, out)
 			}
 			if size == 4 {
 				if out != nil {
@@ -400,7 +452,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 		}
 
 		if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 {
-			ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p)
+			c.ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p)
 		}
 
 		if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 {
@@ -408,7 +460,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 			// split it into two instructions:
 			// 	ADD $-100004, R13
 			// 	MOVW R14, 0(R13)
-			q := ctxt.NewProg()
+			q := c.newprog()
 
 			p.Scond &^= C_WBIT
 			*q = *p
@@ -446,7 +498,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 			a2.Reg = REG_R13
 			a2.Sym = nil
 			a2.Offset = 0
-			size = int(oplook(ctxt, p).size)
+			size = int(c.oplook(p).size)
 			break
 		}
 
@@ -463,7 +515,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 				// if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
 				if reg == 0 {
 					if out != nil {
-						asmout(ctxt, p, o, out)
+						c.asmout(p, o, out)
 					}
 				} else {
 					if out != nil {
@@ -474,7 +526,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 					}
 					size += 4
 					if out != nil {
-						asmout(ctxt, p, o, out[1:])
+						c.asmout(p, o, out[1:])
 					}
 				}
 
@@ -486,9 +538,9 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 				// 2. load/store from R11.
 				// This won't handle .W/.P, so we should reject such code.
 				if p.Scond&(C_PBIT|C_WBIT) != 0 {
-					ctxt.Diag("unsupported instruction (.P/.W): %v", p)
+					c.ctxt.Diag("unsupported instruction (.P/.W): %v", p)
 				}
-				q := ctxt.NewProg()
+				q := c.newprog()
 				*q = *p
 				var a2 *obj.Addr
 				if p.To.Type == obj.TYPE_MEM {
@@ -521,11 +573,11 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 				a2.Reg = REG_R11
 				a2.Sym = nil
 				a2.Offset = 0
-				size = int(oplook(ctxt, p).size)
+				size = int(c.oplook(p).size)
 				break
 			}
 		} else if out != nil {
-			asmout(ctxt, p, o, out)
+			c.asmout(p, o, out)
 		}
 	}
 
@@ -533,7 +585,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 	if p.To.Type == obj.TYPE_REG {
 		switch p.To.Reg {
 		case REG_R9:
-			ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
+			c.ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
 
 		case REG_R13:
 			if out != nil {
@@ -549,32 +601,88 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 	return size
 }
 
-func span5(ctxt *obj.Link, cursym *obj.LSym) {
+const (
+	T_SBIT = 1 << 0
+	T_PBIT = 1 << 1
+	T_WBIT = 1 << 2
+)
+
+var mayHaveSuffix = map[obj.As]uint8{
+	// bit logic
+	AAND: T_SBIT,
+	AEOR: T_SBIT,
+	AORR: T_SBIT,
+	ABIC: T_SBIT,
+	// arithmatic
+	ASUB: T_SBIT,
+	AADD: T_SBIT,
+	ASBC: T_SBIT,
+	AADC: T_SBIT,
+	ARSB: T_SBIT,
+	ARSC: T_SBIT,
+	// mov
+	AMVN:   T_SBIT,
+	AMOVW:  T_SBIT | T_PBIT | T_WBIT,
+	AMOVB:  T_SBIT | T_PBIT | T_WBIT,
+	AMOVBS: T_SBIT | T_PBIT | T_WBIT,
+	AMOVBU: T_SBIT | T_PBIT | T_WBIT,
+	AMOVH:  T_SBIT | T_PBIT | T_WBIT,
+	AMOVHS: T_SBIT | T_PBIT | T_WBIT,
+	AMOVHU: T_SBIT | T_PBIT | T_WBIT,
+	AMOVM:  T_PBIT | T_WBIT,
+	// shift
+	ASRL: T_SBIT,
+	ASRA: T_SBIT,
+	ASLL: T_SBIT,
+	// mul
+	AMUL:   T_SBIT,
+	AMULU:  T_SBIT,
+	AMULL:  T_SBIT,
+	AMULLU: T_SBIT,
+	// mula
+	AMULA:   T_SBIT,
+	AMULAL:  T_SBIT,
+	AMULALU: T_SBIT,
+	// MRC/MCR
+	AMRC: T_SBIT,
+}
+
+func checkBits(ctxt *obj.Link, p *obj.Prog) {
+	if p.Scond&C_SBIT != 0 && mayHaveSuffix[p.As]&T_SBIT == 0 {
+		ctxt.Diag("invalid .S suffix: %v", p)
+	}
+	if p.Scond&C_PBIT != 0 && mayHaveSuffix[p.As]&T_PBIT == 0 {
+		ctxt.Diag("invalid .P suffix: %v", p)
+	}
+	if p.Scond&C_WBIT != 0 && mayHaveSuffix[p.As]&T_WBIT == 0 {
+		ctxt.Diag("invalid .W suffix: %v", p)
+	}
+}
+
+func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 	var p *obj.Prog
 	var op *obj.Prog
 
-	p = cursym.Text
+	p = cursym.Func.Text
 	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
 		return
 	}
 
 	if oprange[AAND&obj.AMask] == nil {
-		buildop(ctxt)
+		ctxt.Diag("arm ops not initialized, call arm.buildop first")
 	}
 
-	ctxt.Cursym = cursym
-
-	ctxt.Autosize = int32(p.To.Offset + 4)
-	c := int32(0)
+	c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4}
+	pc := int32(0)
 
 	op = p
 	p = p.Link
 	var i int
 	var m int
 	var o *Optab
-	for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
+	for ; p != nil || c.blitrl != nil; op, p = p, p.Link {
 		if p == nil {
-			if checkpool(ctxt, op, 0) {
+			if c.checkpool(op, 0) {
 				p = op
 				continue
 			}
@@ -585,15 +693,14 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			break
 		}
 
-		ctxt.Curp = p
-		p.Pc = int64(c)
-		o = oplook(ctxt, p)
-		if ctxt.Headtype != obj.Hnacl {
+		p.Pc = int64(pc)
+		o = c.oplook(p)
+		if ctxt.Headtype != objabi.Hnacl {
 			m = int(o.size)
 		} else {
-			m = asmoutnacl(ctxt, c, p, o, nil)
-			c = int32(p.Pc)     // asmoutnacl might change pc for alignment
-			o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
+			m = c.asmoutnacl(pc, p, o, nil)
+			pc = int32(p.Pc) // asmoutnacl might change pc for alignment
+			o = c.oplook(p)  // asmoutnacl might change p in rare cases
 		}
 
 		if m%4 != 0 || p.Pc%4 != 0 {
@@ -601,39 +708,42 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 		}
 
 		// must check literal pool here in case p generates many instructions
-		if ctxt.Blitrl != nil {
+		if c.blitrl != nil {
 			i = m
-			if checkpool(ctxt, op, i) {
+			if c.checkpool(op, i) {
 				p = op
 				continue
 			}
 		}
 
-		if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
+		if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
 			ctxt.Diag("zero-width instruction\n%v", p)
 			continue
 		}
 
 		switch o.flag & (LFROM | LTO | LPOOL) {
 		case LFROM:
-			addpool(ctxt, p, &p.From)
+			c.addpool(p, &p.From)
 
 		case LTO:
-			addpool(ctxt, p, &p.To)
+			c.addpool(p, &p.To)
 
 		case LPOOL:
 			if p.Scond&C_SCOND == C_SCOND_NONE {
-				flushpool(ctxt, p, 0, 0)
+				c.flushpool(p, 0, 0)
 			}
 		}
 
 		if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
-			flushpool(ctxt, p, 0, 0)
+			c.flushpool(p, 0, 0)
 		}
-		c += int32(m)
+
+		checkBits(ctxt, p)
+
+		pc += int32(m)
 	}
 
-	cursym.Size = int64(c)
+	c.cursym.Size = int64(pc)
 
 	/*
 	 * if any procedure is large enough to
@@ -647,18 +757,14 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 	var opc int32
 	var out [6 + 3]uint32
 	for {
-		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f span1\n", obj.Cputime())
-		}
 		bflag = 0
-		c = 0
+		pc = 0
 		times++
-		cursym.Text.Pc = 0 // force re-layout the code.
-		for p = cursym.Text; p != nil; p = p.Link {
-			ctxt.Curp = p
-			o = oplook(ctxt, p)
-			if int64(c) > p.Pc {
-				p.Pc = int64(c)
+		c.cursym.Func.Text.Pc = 0 // force re-layout the code.
+		for p = c.cursym.Func.Text; p != nil; p = p.Link {
+			o = c.oplook(p)
+			if int64(pc) > p.Pc {
+				p.Pc = int64(pc)
 			}
 
 			/* very large branches
@@ -686,17 +792,17 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			*/
 			opc = int32(p.Pc)
 
-			if ctxt.Headtype != obj.Hnacl {
+			if ctxt.Headtype != objabi.Hnacl {
 				m = int(o.size)
 			} else {
-				m = asmoutnacl(ctxt, c, p, o, nil)
+				m = c.asmoutnacl(pc, p, o, nil)
 			}
 			if p.Pc != int64(opc) {
 				bflag = 1
 			}
 
 			//print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
-			c = int32(p.Pc + int64(m))
+			pc = int32(p.Pc + int64(m))
 
 			if m%4 != 0 || p.Pc%4 != 0 {
 				ctxt.Diag("pc invalid: %v size=%d", p, m)
@@ -705,9 +811,9 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			if m/4 > len(out) {
 				ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
 			}
-			if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
+			if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
 				if p.As == obj.ATEXT {
-					ctxt.Autosize = int32(p.To.Offset + 4)
+					c.autosize = p.To.Offset + 4
 					continue
 				}
 
@@ -716,14 +822,14 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 		}
 
-		cursym.Size = int64(c)
+		c.cursym.Size = int64(pc)
 		if bflag == 0 {
 			break
 		}
 	}
 
-	if c%4 != 0 {
-		ctxt.Diag("sym->size=%d, invalid", c)
+	if pc%4 != 0 {
+		ctxt.Diag("sym->size=%d, invalid", pc)
 	}
 
 	/*
@@ -735,23 +841,22 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 	 * perhaps we'd be able to parallelize the span loop above.
 	 */
 
-	p = cursym.Text
-	ctxt.Autosize = int32(p.To.Offset + 4)
-	cursym.Grow(cursym.Size)
+	p = c.cursym.Func.Text
+	c.autosize = p.To.Offset + 4
+	c.cursym.Grow(c.cursym.Size)
 
-	bp := cursym.P
-	c = int32(p.Pc) // even p->link might need extra padding
+	bp := c.cursym.P
+	pc = int32(p.Pc) // even p->link might need extra padding
 	var v int
 	for p = p.Link; p != nil; p = p.Link {
-		ctxt.Pc = p.Pc
-		ctxt.Curp = p
-		o = oplook(ctxt, p)
+		c.pc = p.Pc
+		o = c.oplook(p)
 		opc = int32(p.Pc)
-		if ctxt.Headtype != obj.Hnacl {
-			asmout(ctxt, p, o, out[:])
+		if ctxt.Headtype != objabi.Hnacl {
+			c.asmout(p, o, out[:])
 			m = int(o.size)
 		} else {
-			m = asmoutnacl(ctxt, c, p, o, out[:])
+			m = c.asmoutnacl(pc, p, o, out[:])
 			if int64(opc) != p.Pc {
 				ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
 			}
@@ -761,10 +866,10 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
 		}
 
-		if int64(c) > p.Pc {
-			ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p)
+		if int64(pc) > p.Pc {
+			ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p)
 		}
-		for int64(c) != p.Pc {
+		for int64(pc) != p.Pc {
 			// emit 0xe1a00000 (MOVW R0, R0)
 			bp[0] = 0x00
 			bp = bp[1:]
@@ -775,7 +880,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			bp = bp[1:]
 			bp[0] = 0xe1
 			bp = bp[1:]
-			c += 4
+			pc += 4
 		}
 
 		for i = 0; i < m/4; i++ {
@@ -790,7 +895,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 			bp = bp[1:]
 		}
 
-		c += int32(m)
+		pc += int32(m)
 	}
 }
 
@@ -800,77 +905,73 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
  * drop the pool now, and branch round it.
  * this happens only in extended basic blocks that exceed 4k.
  */
-func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool {
-	if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 {
-		return flushpool(ctxt, p, 1, 0)
+func (c *ctxt5) checkpool(p *obj.Prog, sz int) bool {
+	if c.pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+c.pool.size)-int64(c.pool.start+8))) == 0 {
+		return c.flushpool(p, 1, 0)
 	} else if p.Link == nil {
-		return flushpool(ctxt, p, 2, 0)
+		return c.flushpool(p, 2, 0)
 	}
 	return false
 }
 
-func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
-	if ctxt.Blitrl != nil {
+func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool {
+	if c.blitrl != nil {
 		if skip != 0 {
 			if false && skip == 1 {
-				fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
+				fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
 			}
-			q := ctxt.NewProg()
+			q := c.newprog()
 			q.As = AB
 			q.To.Type = obj.TYPE_BRANCH
 			q.Pcond = p.Link
-			q.Link = ctxt.Blitrl
-			q.Lineno = p.Lineno
-			ctxt.Blitrl = q
-		} else if force == 0 && (p.Pc+int64(12+pool.size)-int64(pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size
+			q.Link = c.blitrl
+			q.Pos = p.Pos
+			c.blitrl = q
+		} else if force == 0 && (p.Pc+int64(12+c.pool.size)-int64(c.pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size
 			return false
 		}
-		if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
+		if c.ctxt.Headtype == objabi.Hnacl && c.pool.size%16 != 0 {
 			// if pool is not multiple of 16 bytes, add an alignment marker
-			q := ctxt.NewProg()
+			q := c.newprog()
 
 			q.As = ADATABUNDLEEND
-			ctxt.Elitrl.Link = q
-			ctxt.Elitrl = q
+			c.elitrl.Link = q
+			c.elitrl = q
 		}
 
 		// The line number for constant pool entries doesn't really matter.
 		// We set it to the line number of the preceding instruction so that
 		// there are no deltas to encode in the pc-line tables.
-		for q := ctxt.Blitrl; q != nil; q = q.Link {
-			q.Lineno = p.Lineno
+		for q := c.blitrl; q != nil; q = q.Link {
+			q.Pos = p.Pos
 		}
 
-		ctxt.Elitrl.Link = p.Link
-		p.Link = ctxt.Blitrl
+		c.elitrl.Link = p.Link
+		p.Link = c.blitrl
 
-		ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
-		ctxt.Elitrl = nil
-		pool.size = 0
-		pool.start = 0
-		pool.extra = 0
+		c.blitrl = nil /* BUG: should refer back to values until out-of-range */
+		c.elitrl = nil
+		c.pool.size = 0
+		c.pool.start = 0
+		c.pool.extra = 0
 		return true
 	}
 
 	return false
 }
 
-func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	var t obj.Prog
-
-	c := aclass(ctxt, a)
-
-	t.Ctxt = ctxt
+func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) {
+	t := c.newprog()
 	t.As = AWORD
 
-	switch c {
+	switch c.aclass(a) {
 	default:
 		t.To.Offset = a.Offset
 		t.To.Sym = a.Sym
 		t.To.Type = a.Type
 		t.To.Name = a.Name
 
-		if ctxt.Flag_shared && t.To.Sym != nil {
+		if c.ctxt.Flag_shared && t.To.Sym != nil {
 			t.Rel = p
 		}
 
@@ -885,11 +986,11 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		C_LAUTO,
 		C_LACON:
 		t.To.Type = obj.TYPE_CONST
-		t.To.Offset = ctxt.Instoffset
+		t.To.Offset = c.instoffset
 	}
 
 	if t.Rel == nil {
-		for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
+		for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
 			if q.Rel == nil && q.To == t.To {
 				p.Pcond = q
 				return
@@ -897,42 +998,42 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
+	if c.ctxt.Headtype == objabi.Hnacl && c.pool.size%16 == 0 {
 		// start a new data bundle
-		q := ctxt.NewProg()
+		q := c.newprog()
 		q.As = ADATABUNDLE
-		q.Pc = int64(pool.size)
-		pool.size += 4
-		if ctxt.Blitrl == nil {
-			ctxt.Blitrl = q
-			pool.start = uint32(p.Pc)
+		q.Pc = int64(c.pool.size)
+		c.pool.size += 4
+		if c.blitrl == nil {
+			c.blitrl = q
+			c.pool.start = uint32(p.Pc)
 		} else {
-			ctxt.Elitrl.Link = q
+			c.elitrl.Link = q
 		}
 
-		ctxt.Elitrl = q
+		c.elitrl = q
 	}
 
-	q := ctxt.NewProg()
-	*q = t
-	q.Pc = int64(pool.size)
+	q := c.newprog()
+	*q = *t
+	q.Pc = int64(c.pool.size)
 
-	if ctxt.Blitrl == nil {
-		ctxt.Blitrl = q
-		pool.start = uint32(p.Pc)
+	if c.blitrl == nil {
+		c.blitrl = q
+		c.pool.start = uint32(p.Pc)
 	} else {
-		ctxt.Elitrl.Link = q
+		c.elitrl.Link = q
 	}
-	ctxt.Elitrl = q
-	pool.size += 4
+	c.elitrl = q
+	c.pool.size += 4
 
 	p.Pcond = q
 }
 
-func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
-	ctxt.Instoffset = 0
-	aclass(ctxt, a)
-	return int32(ctxt.Instoffset)
+func (c *ctxt5) regoff(a *obj.Addr) int32 {
+	c.instoffset = 0
+	c.aclass(a)
+	return int32(c.instoffset)
 }
 
 func immrot(v uint32) int32 {
@@ -946,6 +1047,47 @@ func immrot(v uint32) int32 {
 	return 0
 }
 
+// immrot2a returns bits encoding the immediate constant fields of two instructions,
+// such that the encoded constants x, y satisfy x|y==v, x&y==0.
+// Returns 0,0 if no such decomposition of v exists.
+func immrot2a(v uint32) (uint32, uint32) {
+	for i := uint(1); i < 32; i++ {
+		m := uint32(1<<i - 1)
+		if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 {
+			return uint32(x), uint32(y)
+		}
+	}
+	// TODO: handle some more cases, like where
+	// the wraparound from the rotate could help.
+	return 0, 0
+}
+
+// immrot2s returns bits encoding the immediate constant fields of two instructions,
+// such that the encoded constants y, x satisfy y-x==v, y&x==0.
+// Returns 0,0 if no such decomposition of v exists.
+func immrot2s(v uint32) (uint32, uint32) {
+	if immrot(v) != 0 {
+		return v, 0
+	}
+	// suppose v in the form of {leading 00, upper effective bits, lower 8 effective bits, trailing 00}
+	// omit trailing 00
+	var i uint32
+	for i = 2; i < 32; i += 2 {
+		if v&(1<<i-1) != 0 {
+			break
+		}
+	}
+	// i must be <= 24, then adjust i just above lower 8 effective bits of v
+	i += 6
+	// let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v
+	x := 1<<i - v&(1<<i-1)
+	y := v + x
+	if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 {
+		return y, x
+	}
+	return 0, 0
+}
+
 func immaddr(v int32) int32 {
 	if v >= 0 && v <= 0xfff {
 		return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
@@ -970,13 +1112,13 @@ func immhalf(v int32) bool {
 	return false
 }
 
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
+func (c *ctxt5) aclass(a *obj.Addr) int {
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
 
 	case obj.TYPE_REG:
-		ctxt.Instoffset = 0
+		c.instoffset = 0
 		if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
 			return C_REG
 		}
@@ -1013,9 +1155,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 				return C_GOK
 			}
 
-			ctxt.Instoffset = 0 // s.b. unused but just in case
-			if a.Sym.Type == obj.STLSBSS {
-				if ctxt.Flag_shared {
+			c.instoffset = 0 // s.b. unused but just in case
+			if a.Sym.Type == objabi.STLSBSS {
+				if c.ctxt.Flag_shared {
 					return C_TLS_IE
 				} else {
 					return C_TLS_LE
@@ -1025,9 +1167,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_ADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
-				if immhalf(int32(ctxt.Instoffset)) {
+			c.instoffset = c.autosize + a.Offset
+			if t := immaddr(int32(c.instoffset)); t != 0 {
+				if immhalf(int32(c.instoffset)) {
 					if immfloat(t) {
 						return C_HFAUTO
 					}
@@ -1043,9 +1185,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_LAUTO
 
 		case obj.NAME_PARAM:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
-			if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
-				if immhalf(int32(ctxt.Instoffset)) {
+			c.instoffset = c.autosize + a.Offset + 4
+			if t := immaddr(int32(c.instoffset)); t != 0 {
+				if immhalf(int32(c.instoffset)) {
 					if immfloat(t) {
 						return C_HFAUTO
 					}
@@ -1061,9 +1203,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_LAUTO
 
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
-			if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
-				if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
+			c.instoffset = a.Offset
+			if t := immaddr(int32(c.instoffset)); t != 0 {
+				if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */
 					if immfloat(t) {
 						return C_HFOREG
 					}
@@ -1073,16 +1215,16 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 				if immfloat(t) {
 					return C_FOREG /* n.b. that it will also satisfy immrot */
 				}
-				if immrot(uint32(ctxt.Instoffset)) != 0 {
+				if immrot(uint32(c.instoffset)) != 0 {
 					return C_SROREG
 				}
-				if immhalf(int32(ctxt.Instoffset)) {
+				if immhalf(int32(c.instoffset)) {
 					return C_HOREG
 				}
 				return C_SOREG
 			}
 
-			if immrot(uint32(ctxt.Instoffset)) != 0 {
+			if immrot(uint32(c.instoffset)) != 0 {
 				return C_ROREG
 			}
 			return C_LOREG
@@ -1091,10 +1233,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		return C_GOK
 
 	case obj.TYPE_FCONST:
-		if chipzero5(ctxt, a.Val.(float64)) >= 0 {
+		if c.chipzero5(a.Val.(float64)) >= 0 {
 			return C_ZFCON
 		}
-		if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
+		if c.chipfloat5(a.Val.(float64)) >= 0 {
 			return C_SFCON
 		}
 		return C_LFCON
@@ -1106,17 +1248,30 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		obj.TYPE_ADDR:
 		switch a.Name {
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Reg != 0 {
-				return aconsize(ctxt)
+				return c.aconsize()
 			}
 
-			if immrot(uint32(ctxt.Instoffset)) != 0 {
+			if immrot(uint32(c.instoffset)) != 0 {
 				return C_RCON
 			}
-			if immrot(^uint32(ctxt.Instoffset)) != 0 {
+			if immrot(^uint32(c.instoffset)) != 0 {
 				return C_NCON
 			}
+			if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 {
+				return C_SCON
+			}
+			if c.ctxt.Headtype != objabi.Hnacl {
+				// Don't split instructions on NaCl. The validator is not
+				// happy with it. See Issue 20595.
+				if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 {
+					return C_RCON2A
+				}
+				if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 {
+					return C_RCON2S
+				}
+			}
 			return C_LCON
 
 		case obj.NAME_EXTERN,
@@ -1126,16 +1281,16 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if s == nil {
 				break
 			}
-			ctxt.Instoffset = 0 // s.b. unused but just in case
+			c.instoffset = 0 // s.b. unused but just in case
 			return C_LCONADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			return aconsize(ctxt)
+			c.instoffset = c.autosize + a.Offset
+			return c.aconsize()
 
 		case obj.NAME_PARAM:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
-			return aconsize(ctxt)
+			c.instoffset = c.autosize + a.Offset + 4
+			return c.aconsize()
 		}
 
 		return C_GOK
@@ -1147,42 +1302,54 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	return C_GOK
 }
 
-func aconsize(ctxt *obj.Link) int {
-	if immrot(uint32(ctxt.Instoffset)) != 0 {
+func (c *ctxt5) aconsize() int {
+	if immrot(uint32(c.instoffset)) != 0 {
 		return C_RACON
 	}
-	if immrot(uint32(-ctxt.Instoffset)) != 0 {
+	if immrot(uint32(-c.instoffset)) != 0 {
 		return C_RACON
 	}
 	return C_LACON
 }
 
-func prasm(p *obj.Prog) {
-	fmt.Printf("%v\n", p)
-}
-
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+func (c *ctxt5) oplook(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
+		a1 = c.aclass(&p.From) + 1
 		p.From.Class = int8(a1)
 	}
 
 	a1--
 	a3 := int(p.To.Class)
 	if a3 == 0 {
-		a3 = aclass(ctxt, &p.To) + 1
+		a3 = c.aclass(&p.To) + 1
 		p.To.Class = int8(a3)
 	}
 
 	a3--
 	a2 := C_NONE
 	if p.Reg != 0 {
-		a2 = C_REG
+		switch {
+		case REG_F0 <= p.Reg && p.Reg <= REG_F15:
+			a2 = C_FREG
+		case REG_R0 <= p.Reg && p.Reg <= REG_R15:
+			a2 = C_REG
+		default:
+			c.ctxt.Diag("invalid register in %v", p)
+		}
+	}
+
+	// If current instruction has a .S suffix (flags update),
+	// we must use the constant pool instead of splitting it.
+	if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 {
+		a1 = C_LCON
+	}
+	if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 {
+		a3 = C_LCON
 	}
 
 	if false { /*debug['O']*/
@@ -1201,9 +1368,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 		}
 	}
 
-	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)
+	c.ctxt.Diag("illegal combination %v; %v %v %v; from %d %d; to %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.From.Name, p.To.Type, p.To.Name)
 	if ops == nil {
 		ops = optab
 	}
@@ -1216,7 +1381,7 @@ func cmp(a int, b int) bool {
 	}
 	switch a {
 	case C_LCON:
-		if b == C_RCON || b == C_NCON {
+		if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S {
 			return true
 		}
 
@@ -1306,6 +1471,20 @@ func opset(a, b0 obj.As) {
 }
 
 func buildop(ctxt *obj.Link) {
+	if oprange[AAND&obj.AMask] != nil {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
+	deferreturn = ctxt.Lookup("runtime.deferreturn")
+
+	symdiv = ctxt.Lookup("_div")
+	symdivu = ctxt.Lookup("_divu")
+	symmod = ctxt.Lookup("_mod")
+	symmodu = ctxt.Lookup("_modu")
+
 	var n int
 
 	for i := 0; i < C_GOK; i++ {
@@ -1342,19 +1521,20 @@ func buildop(ctxt *obj.Link) {
 			log.Fatalf("bad code")
 
 		case AADD:
-			opset(AAND, r0)
-			opset(AEOR, r0)
 			opset(ASUB, r0)
 			opset(ARSB, r0)
 			opset(AADC, r0)
 			opset(ASBC, r0)
 			opset(ARSC, r0)
-			opset(AORR, r0)
+
+		case AORR:
+			opset(AEOR, r0)
 			opset(ABIC, r0)
 
 		case ACMP:
 			opset(ATEQ, r0)
 			opset(ACMN, r0)
+			opset(ATST, r0)
 
 		case AMVN:
 			break
@@ -1388,6 +1568,9 @@ func buildop(ctxt *obj.Link) {
 			opset(AMODU, r0)
 			opset(ADIVU, r0)
 
+		case ADIVHW:
+			opset(ADIVUHW, r0)
+
 		case AMOVW,
 			AMOVB,
 			AMOVBS,
@@ -1410,9 +1593,7 @@ func buildop(ctxt *obj.Link) {
 			AWORD,
 			AMOVM,
 			ARFE,
-			obj.ATEXT,
-			obj.AUSEFIELD,
-			obj.ATYPE:
+			obj.ATEXT:
 			break
 
 		case AADDF:
@@ -1423,14 +1604,15 @@ func buildop(ctxt *obj.Link) {
 			opset(AMULD, r0)
 			opset(ADIVF, r0)
 			opset(ADIVD, r0)
+
+		case ANEGF:
+			opset(ANEGD, r0)
 			opset(ASQRTF, r0)
 			opset(ASQRTD, r0)
 			opset(AMOVFD, r0)
 			opset(AMOVDF, r0)
 			opset(AABSF, r0)
 			opset(AABSD, r0)
-			opset(ANEGF, r0)
-			opset(ANEGD, r0)
 
 		case ACMPF:
 			opset(ACMPD, r0)
@@ -1451,19 +1633,30 @@ func buildop(ctxt *obj.Link) {
 
 		case AMULWT:
 			opset(AMULWB, r0)
+			opset(AMULBB, r0)
+			opset(AMMUL, r0)
 
 		case AMULAWT:
 			opset(AMULAWB, r0)
-
-		case AMULA,
-			ALDREX,
+			opset(AMULABB, r0)
+			opset(AMULA, r0)
+			opset(AMULS, r0)
+			opset(AMMULA, r0)
+			opset(AMMULS, r0)
+
+		case ACLZ:
+			opset(AREV, r0)
+			opset(AREV16, r0)
+			opset(AREVSH, r0)
+			opset(ARBIT, r0)
+
+		case ALDREX,
 			ASTREX,
 			ALDREXD,
 			ASTREXD,
-			ATST,
 			APLD,
+			AAND,
 			obj.AUNDEF,
-			ACLZ,
 			obj.AFUNCDATA,
 			obj.APCDATA,
 			obj.ANOP,
@@ -1474,22 +1667,20 @@ func buildop(ctxt *obj.Link) {
 	}
 }
 
-func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
-	ctxt.Printp = p
+func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
+	c.printp = p
 	o1 := uint32(0)
 	o2 := uint32(0)
 	o3 := uint32(0)
 	o4 := uint32(0)
 	o5 := uint32(0)
 	o6 := uint32(0)
-	ctxt.Armsize += int32(o.size)
 	if false { /*debug['P']*/
 		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
 	}
 	switch o.type_ {
 	default:
-		ctxt.Diag("unknown asm %d", o.type_)
-		prasm(p)
+		c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
 
 	case 0: /* pseudo ops */
 		if false { /*debug['G']*/
@@ -1497,7 +1688,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 1: /* op R,[R],R */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1513,10 +1704,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
 
 	case 2: /* movbu $I,[R],R */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
-		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
+		o1 |= uint32(immrot(uint32(c.instoffset)))
 		rt := int(p.To.Reg)
 		r := int(p.Reg)
 		if p.To.Type == obj.TYPE_NONE {
@@ -1529,17 +1720,79 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
 
+	case 106: /* op $I,R,R where I can be decomposed into 2 immediates */
+		c.aclass(&p.From)
+		r := int(p.Reg)
+		rt := int(p.To.Reg)
+		if r == 0 {
+			r = rt
+		}
+		x, y := immrot2a(uint32(c.instoffset))
+		var as2 obj.As
+		switch p.As {
+		case AADD, ASUB, AORR, AEOR, ABIC:
+			as2 = p.As // ADD, SUB, ORR, EOR, BIC
+		case ARSB:
+			as2 = AADD // RSB -> RSB/ADD pair
+		case AADC:
+			as2 = AADD // ADC -> ADC/ADD pair
+		case ASBC:
+			as2 = ASUB // SBC -> SBC/SUB pair
+		case ARSC:
+			as2 = AADD // RSC -> RSC/ADD pair
+		default:
+			c.ctxt.Diag("unknown second op for %v", p)
+		}
+		o1 = c.oprrr(p, p.As, int(p.Scond))
+		o2 = c.oprrr(p, as2, int(p.Scond))
+		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+		o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
+		o1 |= x
+		o2 |= y
+
+	case 107: /* op $I,R,R where I can be decomposed into 2 immediates */
+		c.aclass(&p.From)
+		r := int(p.Reg)
+		rt := int(p.To.Reg)
+		if r == 0 {
+			r = rt
+		}
+		y, x := immrot2s(uint32(c.instoffset))
+		var as2 obj.As
+		switch p.As {
+		case AADD:
+			as2 = ASUB // ADD -> ADD/SUB pair
+		case ASUB:
+			as2 = AADD // SUB -> SUB/ADD pair
+		case ARSB:
+			as2 = ASUB // RSB -> RSB/SUB pair
+		case AADC:
+			as2 = ASUB // ADC -> ADC/SUB pair
+		case ASBC:
+			as2 = AADD // SBC -> SBC/ADD pair
+		case ARSC:
+			as2 = ASUB // RSC -> RSC/SUB pair
+		default:
+			c.ctxt.Diag("unknown second op for %v", p)
+		}
+		o1 = c.oprrr(p, p.As, int(p.Scond))
+		o2 = c.oprrr(p, as2, int(p.Scond))
+		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+		o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
+		o1 |= y
+		o2 |= x
+
 	case 3: /* add R<<[IR],[R],R */
-		o1 = mov(ctxt, p)
+		o1 = c.mov(p)
 
 	case 4: /* MOVW $off(R), R -> add $off,[R],R */
-		aclass(ctxt, &p.From)
-		if ctxt.Instoffset < 0 {
-			o1 = oprrr(ctxt, ASUB, int(p.Scond))
-			o1 |= uint32(immrot(uint32(-ctxt.Instoffset)))
+		c.aclass(&p.From)
+		if c.instoffset < 0 {
+			o1 = c.oprrr(p, ASUB, int(p.Scond))
+			o1 |= uint32(immrot(uint32(-c.instoffset)))
 		} else {
-			o1 = oprrr(ctxt, AADD, int(p.Scond))
-			o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+			o1 = c.oprrr(p, AADD, int(p.Scond))
+			o1 |= uint32(immrot(uint32(c.instoffset)))
 		}
 		r := int(p.From.Reg)
 		if r == 0 {
@@ -1549,60 +1802,60 @@ 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, p.As, int(p.Scond))
+		o1 = c.opbra(p, p.As, int(p.Scond))
 
 		v := int32(-8)
 		if p.To.Sym != nil {
-			rel := obj.Addrel(ctxt.Cursym)
-			rel.Off = int32(ctxt.Pc)
+			rel := obj.Addrel(c.cursym)
+			rel.Off = int32(c.pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
 			v += int32(p.To.Offset)
 			rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
-			rel.Type = obj.R_CALLARM
+			rel.Type = objabi.R_CALLARM
 			break
 		}
 
 		if p.Pcond != nil {
-			v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
+			v = int32((p.Pcond.Pc - c.pc) - 8)
 		}
 		o1 |= (uint32(v) >> 2) & 0xffffff
 
 	case 6: /* b ,O(R) -> add $O,R,PC */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
-		o1 = oprrr(ctxt, AADD, int(p.Scond))
-		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 = c.oprrr(p, AADD, int(p.Scond))
+		o1 |= uint32(immrot(uint32(c.instoffset)))
 		o1 |= (uint32(p.To.Reg) & 15) << 16
 		o1 |= (REGPC & 15) << 12
 
 	case 7: /* bl (R) -> blx R */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
+		if c.instoffset != 0 {
+			c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset)
 		}
-		o1 = oprrr(ctxt, ABL, int(p.Scond))
+		o1 = c.oprrr(p, ABL, int(p.Scond))
 		o1 |= (uint32(p.To.Reg) & 15) << 0
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 0
-		rel.Type = obj.R_CALLIND
+		rel.Type = objabi.R_CALLIND
 
 	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 		o1 |= (uint32(r) & 15) << 0
-		o1 |= uint32((ctxt.Instoffset & 31) << 7)
+		o1 |= uint32((c.instoffset & 31) << 7)
 		o1 |= (uint32(p.To.Reg) & 15) << 12
 
 	case 9: /* sll R,[R],R -> mov (R<<R),R */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		r := int(p.Reg)
 		if r == 0 {
@@ -1613,54 +1866,62 @@ 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		if p.To.Type != obj.TYPE_NONE {
-			aclass(ctxt, &p.To)
-			o1 |= uint32(ctxt.Instoffset & 0xffffff)
+			c.aclass(&p.To)
+			o1 |= uint32(c.instoffset & 0xffffff)
 		}
 
 	case 11: /* word */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
-		o1 = uint32(ctxt.Instoffset)
+		o1 = uint32(c.instoffset)
 		if p.To.Sym != nil {
 			// This case happens with words generated
-			// in the PC stream as part of the literal pool.
-			rel := obj.Addrel(ctxt.Cursym)
+			// in the PC stream as part of the literal pool (c.pool).
+			rel := obj.Addrel(c.cursym)
 
-			rel.Off = int32(ctxt.Pc)
+			rel.Off = int32(c.pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
 			rel.Add = p.To.Offset
 
-			if ctxt.Flag_shared {
+			if c.ctxt.Flag_shared {
 				if p.To.Name == obj.NAME_GOTREF {
-					rel.Type = obj.R_GOTPCREL
+					rel.Type = objabi.R_GOTPCREL
 				} else {
-					rel.Type = obj.R_PCREL
+					rel.Type = objabi.R_PCREL
 				}
-				rel.Add += ctxt.Pc - p.Rel.Pc - 8
+				rel.Add += c.pc - p.Rel.Pc - 8
 			} else {
-				rel.Type = obj.R_ADDR
+				rel.Type = objabi.R_ADDR
 			}
 			o1 = 0
 		}
 
 	case 12: /* movw $lcon, reg */
-		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
+		if o.a1 == C_SCON {
+			o1 = c.omvs(p, &p.From, int(p.To.Reg))
+		} else {
+			o1 = c.omvl(p, &p.From, int(p.To.Reg))
+		}
 
 		if o.flag&LPCREL != 0 {
-			o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
 		}
 
 	case 13: /* op $lcon, [R], R */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		if o.a1 == C_SCON {
+			o1 = c.omvs(p, &p.From, REGTMP)
+		} else {
+			o1 = c.omvl(p, &p.From, REGTMP)
+		}
 
 		if o1 == 0 {
 			break
 		}
-		o2 = oprrr(ctxt, p.As, int(p.Scond))
+		o2 = c.oprrr(p, p.As, int(p.Scond))
 		o2 |= REGTMP & 15
 		r := int(p.Reg)
 		if p.As == AMOVW || p.As == AMVN {
@@ -1674,12 +1935,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 14: /* movb/movbu/movh/movhu R,R */
-		o1 = oprrr(ctxt, ASLL, int(p.Scond))
+		o1 = c.oprrr(p, ASLL, int(p.Scond))
 
 		if p.As == AMOVBU || p.As == AMOVHU {
-			o2 = oprrr(ctxt, ASRL, int(p.Scond))
+			o2 = c.oprrr(p, ASRL, int(p.Scond))
 		} else {
-			o2 = oprrr(ctxt, ASRA, int(p.Scond))
+			o2 = c.oprrr(p, ASRA, int(p.Scond))
 		}
 
 		r := int(p.To.Reg)
@@ -1694,7 +1955,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 15: /* mul r,[r,]r */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1709,8 +1970,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 		if false {
 			if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
-				ctxt.Diag("bad registers in MUL")
-				prasm(p)
+				c.ctxt.Diag("%v: bad registers in MUL", p)
 			}
 		}
 
@@ -1722,7 +1982,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o2 = 0
 
 	case 17:
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
 		rt2 := int(p.To.Offset)
@@ -1730,28 +1990,28 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
 
 	case 20: /* mov/movb/movbu R,O(R) */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
+		o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
 
 	case 21: /* mov/movbu O(R),R -> lr */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
+		o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
 		if p.As != AMOVW {
 			o1 |= 1 << 22
 		}
 
 	case 30: /* mov/movb/movbu R,L(R) */
-		o1 = omvl(ctxt, p, &p.To, REGTMP)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -1760,13 +2020,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
+		o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
 		if p.As != AMOVW {
 			o2 |= 1 << 22
 		}
 
 	case 31: /* mov/movbu L(R),R -> lr[b] */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -1775,19 +2035,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
+		o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
 			o2 |= 1 << 22
 		}
 
 	case 34: /* mov $lacon,R */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
 
-		o2 = oprrr(ctxt, AADD, int(p.Scond))
+		o2 = c.oprrr(p, AADD, int(p.Scond))
 		o2 |= REGTMP & 15
 		r := int(p.From.Reg)
 		if r == 0 {
@@ -1806,7 +2066,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(p.To.Reg) & 15) << 12
 
 	case 36: /* mov R,PSR */
-		o1 = 2<<23 | 0x29f<<12 | 0<<4
+		o1 = 2<<23 | 0x2cf<<12 | 0<<4
 
 		if p.Scond&C_FBIT != 0 {
 			o1 ^= 0x010 << 12
@@ -1816,14 +2076,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(p.From.Reg) & 15) << 0
 
 	case 37: /* mov $con,PSR */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		o1 = 2<<23 | 0x29f<<12 | 0<<4
+		o1 = 2<<23 | 0x2cf<<12 | 0<<4
 		if p.Scond&C_FBIT != 0 {
 			o1 ^= 0x010 << 12
 		}
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 |= uint32(immrot(uint32(c.instoffset)))
 		o1 |= (uint32(p.To.Reg) & 1) << 22
 		o1 |= (uint32(p.From.Reg) & 15) << 0
 
@@ -1834,18 +2094,18 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 			o1 |= uint32(p.From.Offset & 0xffff)
 			o1 |= (uint32(p.To.Reg) & 15) << 16
-			aclass(ctxt, &p.To)
+			c.aclass(&p.To)
 
 		case 39: /* movm oreg,$con -> ldm */
 			o1 = 0x4<<25 | 1<<20
 
 			o1 |= uint32(p.To.Offset & 0xffff)
 			o1 |= (uint32(p.From.Reg) & 15) << 16
-			aclass(ctxt, &p.From)
+			c.aclass(&p.From)
 		}
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in MOVM; %v", p)
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in MOVM; %v", p)
 		}
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 		if p.Scond&C_PBIT != 0 {
@@ -1854,18 +2114,15 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if p.Scond&C_UBIT != 0 {
 			o1 |= 1 << 23
 		}
-		if p.Scond&C_SBIT != 0 {
-			o1 |= 1 << 22
-		}
 		if p.Scond&C_WBIT != 0 {
 			o1 |= 1 << 21
 		}
 
 	case 40: /* swp oreg,reg,reg */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in SWP")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in SWP")
 		}
 		o1 = 0x2<<23 | 0x9<<4
 		if p.As != ASWPW {
@@ -1880,25 +2137,25 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = 0xe8fd8000
 
 	case 50: /* floating point store */
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
+		o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p)
 
 	case 51: /* floating point load */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
+		o1 = c.ofsr(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)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -1907,11 +2164,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
-		o3 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
+		o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
+		o3 = c.ofsr(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)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -1920,36 +2177,41 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
-		o3 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
+		o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
+		o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
 
 	case 54: /* floating point arith */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
 		r := int(p.Reg)
 		if r == 0 {
 			r = rt
-			if p.As == AMOVF || p.As == AMOVD || p.As == AMOVFD || p.As == AMOVDF || p.As == ASQRTF || p.As == ASQRTD || p.As == AABSF || p.As == AABSD || p.As == ANEGF || p.As == ANEGD {
-				r = 0
-			}
 		}
 
 		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
 
+	case 55: /* negf freg, freg */
+		o1 = c.oprrr(p, p.As, int(p.Scond))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+
+		o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12
+
 	case 56: /* move to FP[CS]R */
-		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
+		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4
 
-		o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
+		o1 |= (uint32(p.From.Reg) & 15) << 12
 
 	case 57: /* move from FP[CS]R */
-		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
+		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4
 
-		o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
+		o1 |= (uint32(p.To.Reg) & 15) << 12
 
 	case 58: /* movbu R,R */
-		o1 = oprrr(ctxt, AAND, int(p.Scond))
+		o1 = c.oprrr(p, AAND, int(p.Scond))
 
 		o1 |= uint32(immrot(0xff))
 		rt := int(p.To.Reg)
@@ -1965,156 +2227,156 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 59: /* movw/bu R<<I(R),R -> ldr indexed */
 		if p.From.Reg == 0 {
 			if p.As != AMOVW {
-				ctxt.Diag("byte MOV from shifter operand")
+				c.ctxt.Diag("byte MOV from shifter operand")
 			}
-			o1 = mov(ctxt, p)
+			o1 = c.mov(p)
 			break
 		}
 
 		if p.From.Offset&(1<<4) != 0 {
-			ctxt.Diag("bad shift in LDR")
+			c.ctxt.Diag("bad shift in LDR")
 		}
-		o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
+		o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVBU {
 			o1 |= 1 << 22
 		}
 
 	case 60: /* movb R(R),R -> ldrsb indexed */
 		if p.From.Reg == 0 {
-			ctxt.Diag("byte MOV from shifter operand")
-			o1 = mov(ctxt, p)
+			c.ctxt.Diag("byte MOV from shifter operand")
+			o1 = c.mov(p)
 			break
 		}
 
 		if p.From.Offset&(^0xf) != 0 {
-			ctxt.Diag("bad shift in LDRSB")
+			c.ctxt.Diag("bad shift in LDRSB")
 		}
-		o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
+		o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
 		o1 ^= 1<<5 | 1<<6
 
 	case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
 		if p.To.Reg == 0 {
-			ctxt.Diag("MOV to shifter operand")
+			c.ctxt.Diag("MOV to shifter operand")
 		}
-		o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
+		o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
 			o1 |= 1 << 22
 		}
 
 		/* reloc ops */
 	case 64: /* mov/movb/movbu R,addr */
-		o1 = omvl(ctxt, p, &p.To, REGTMP)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
+		o2 = c.osr(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
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 	case 65: /* mov/movbu addr,R */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
+		o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
 			o2 |= 1 << 22
 		}
 		if o.flag&LPCREL != 0 {
 			o3 = o2
-			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 	case 101: /* movw tlsvar,R, local exec*/
 		if p.Scond&C_SCOND != C_SCOND_NONE {
-			ctxt.Diag("conditional tls")
+			c.ctxt.Diag("conditional tls")
 		}
-		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
+		o1 = c.omvl(p, &p.From, int(p.To.Reg))
 
 	case 102: /* movw tlsvar,R, initial exec*/
 		if p.Scond&C_SCOND != C_SCOND_NONE {
-			ctxt.Diag("conditional tls")
+			c.ctxt.Diag("conditional tls")
 		}
-		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
-		o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
+		o1 = c.omvl(p, &p.From, int(p.To.Reg))
+		o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
 
 	case 103: /* word tlsvar, local exec */
 		if p.To.Sym == nil {
-			ctxt.Diag("nil sym in tls %v", p)
+			c.ctxt.Diag("nil sym in tls %v", p)
 		}
 		if p.To.Offset != 0 {
-			ctxt.Diag("offset against tls var in %v", p)
+			c.ctxt.Diag("offset against tls var in %v", p)
 		}
 		// This case happens with words generated in the PC stream as part of
-		// the literal pool.
-		rel := obj.Addrel(ctxt.Cursym)
+		// the literal c.pool.
+		rel := obj.Addrel(c.cursym)
 
-		rel.Off = int32(ctxt.Pc)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
-		rel.Type = obj.R_TLS_LE
+		rel.Type = objabi.R_TLS_LE
 		o1 = 0
 
 	case 104: /* word tlsvar, initial exec */
 		if p.To.Sym == nil {
-			ctxt.Diag("nil sym in tls %v", p)
+			c.ctxt.Diag("nil sym in tls %v", p)
 		}
 		if p.To.Offset != 0 {
-			ctxt.Diag("offset against tls var in %v", p)
+			c.ctxt.Diag("offset against tls var in %v", p)
 		}
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
-		rel.Type = obj.R_TLS_IE
-		rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
+		rel.Type = objabi.R_TLS_IE
+		rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz)
 
 	case 68: /* floating point store -> ADDR */
-		o1 = omvl(ctxt, p, &p.To, REGTMP)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
+		o2 = c.ofsr(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
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 	case 69: /* floating point load <- ADDR */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
+		o2 = c.ofsr(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
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 		/* ArmV4 ops: */
 	case 70: /* movh/movhu R,O(R) -> strh */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
+		o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
 
 	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
+		o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVB || p.As == AMOVBS {
 			o1 ^= 1<<5 | 1<<6
 		} else if p.As == AMOVH || p.As == AMOVHS {
@@ -2122,7 +2384,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 72: /* movh/movhu R,L(R) -> strh */
-		o1 = omvl(ctxt, p, &p.To, REGTMP)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -2131,10 +2393,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
+		o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
 
 	case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
@@ -2143,7 +2405,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
+		o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVB || p.As == AMOVBS {
 			o2 ^= 1<<5 | 1<<6
 		} else if p.As == AMOVH || p.As == AMOVHS {
@@ -2151,36 +2413,36 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 74: /* bx $I */
-		ctxt.Diag("ABX $I")
+		c.ctxt.Diag("ABX $I")
 
 	case 75: /* bx O(R) */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("non-zero offset in ABX")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("non-zero offset in ABX")
 		}
 
 		/*
-			o1 = 	oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
+			o1 = 	c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
 			o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0);		// BX R
 		*/
 		// p->to.reg may be REGLINK
-		o1 = oprrr(ctxt, AADD, int(p.Scond))
+		o1 = c.oprrr(p, AADD, int(p.Scond))
 
-		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 |= uint32(immrot(uint32(c.instoffset)))
 		o1 |= (uint32(p.To.Reg) & 15) << 16
 		o1 |= (REGTMP & 15) << 12
-		o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
-		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15             // BX Rtmp
+		o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
+		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15            // BX Rtmp
 
 	case 76: /* bx O(R) when returning from fn*/
-		ctxt.Diag("ABXRET")
+		c.ctxt.Diag("ABXRET")
 
 	case 77: /* ldrex oreg,reg */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in LDREX")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in LDREX")
 		}
 		o1 = 0x19<<20 | 0xf9f
 		o1 |= (uint32(p.From.Reg) & 15) << 16
@@ -2188,10 +2450,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 
 	case 78: /* strex reg,oreg,reg */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in STREX")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in STREX")
 		}
 		o1 = 0x18<<20 | 0xf90
 		o1 |= (uint32(p.From.Reg) & 15) << 16
@@ -2202,10 +2464,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 80: /* fmov zfcon,freg */
 		if p.As == AMOVD {
 			o1 = 0xeeb00b00 // VMOV imm 64
-			o2 = oprrr(ctxt, ASUBD, int(p.Scond))
+			o2 = c.oprrr(p, ASUBD, int(p.Scond))
 		} else {
 			o1 = 0x0eb00a00 // VMOV imm 32
-			o2 = oprrr(ctxt, ASUBF, int(p.Scond))
+			o2 = c.oprrr(p, ASUBF, int(p.Scond))
 		}
 
 		v := int32(0x70) // 1.0
@@ -2228,78 +2490,73 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 		o1 |= (uint32(p.To.Reg) & 15) << 12
-		v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
+		v := int32(c.chipfloat5(p.From.Val.(float64)))
 		o1 |= (uint32(v) & 0xf) << 0
 		o1 |= (uint32(v) & 0xf0) << 12
 
 	case 82: /* fcmp freg,freg, */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
 		o1 |= (uint32(p.From.Reg) & 15) << 0
 		o1 |= (FREGTMP & 15) << 12
-		o2 = oprrr(ctxt, -AMOVFW, int(p.Scond))
+		o2 = c.oprrr(p, -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, int(p.Scond))
+		o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
 
 		o1 |= (uint32(p.From.Reg) & 15) << 12
 		o1 |= (FREGTMP & 15) << 16
-		o2 = oprrr(ctxt, p.As, int(p.Scond))
+		o2 = c.oprrr(p, 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, int(p.Scond))
+		o1 = c.oprrr(p, -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, int(p.Scond))
+		o1 = c.oprrr(p, -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, int(p.Scond))
-
-		o1 |= (uint32(p.From.Reg) & 15) << 16
-
 	case 91: /* ldrexd oreg,reg */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in LDREX")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in LDREX")
 		}
 		o1 = 0x1b<<20 | 0xf9f
 		o1 |= (uint32(p.From.Reg) & 15) << 16
@@ -2307,10 +2564,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 
 	case 92: /* strexd reg,oreg,reg */
-		aclass(ctxt, &p.From)
+		c.aclass(&p.From)
 
-		if ctxt.Instoffset != 0 {
-			ctxt.Diag("offset must be zero in STREX")
+		if c.instoffset != 0 {
+			c.ctxt.Diag("offset must be zero in STREX")
 		}
 		o1 = 0x1a<<20 | 0xf90
 		o1 |= (uint32(p.From.Reg) & 15) << 16
@@ -2319,12 +2576,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 
 	case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
-		o1 = omvl(ctxt, p, &p.From, REGTMP)
+		o1 = c.omvl(p, &p.From, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
+		o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond))
 		if p.As == AMOVB || p.As == AMOVBS {
 			o2 ^= 1<<5 | 1<<6
 		} else if p.As == AMOVH || p.As == AMOVHS {
@@ -2332,19 +2589,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		if o.flag&LPCREL != 0 {
 			o3 = o2
-			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 	case 94: /* movh/movhu R,addr -> strh */
-		o1 = omvl(ctxt, p, &p.To, REGTMP)
+		o1 = c.omvl(p, &p.To, REGTMP)
 
 		if o1 == 0 {
 			break
 		}
-		o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
+		o2 = c.oshr(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
+			o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
 		}
 
 	case 95: /* PLD off(reg) */
@@ -2367,25 +2624,25 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = 0xf7fabcfd
 
 	case 97: /* CLZ Rm, Rd */
-		o1 = oprrr(ctxt, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, 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, p.As, int(p.Scond))
+		o1 = c.oprrr(p, p.As, int(p.Scond))
 
-		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= (uint32(p.To.Reg) & 15) << 16
 		o1 |= (uint32(p.From.Reg) & 15) << 8
 		o1 |= (uint32(p.Reg) & 15) << 0
-		o1 |= uint32((p.To.Offset & 15) << 16)
+		o1 |= uint32((p.To.Offset & 15) << 12)
 
 	// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
 	// DATABUNDLEEND: zero width alignment marker
@@ -2393,6 +2650,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if p.As == ADATABUNDLE {
 			o1 = 0xe125be70
 		}
+
+	case 105: /* divhw r,[r,]r */
+		o1 = c.oprrr(p, p.As, int(p.Scond))
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
 	}
 
 	out[0] = o1
@@ -2404,9 +2671,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	return
 }
 
-func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
-	aclass(ctxt, &p.From)
-	o1 := oprrr(ctxt, p.As, int(p.Scond))
+func (c *ctxt5) mov(p *obj.Prog) uint32 {
+	c.aclass(&p.From)
+	o1 := c.oprrr(p, p.As, int(p.Scond))
 	o1 |= uint32(p.From.Offset)
 	rt := int(p.To.Reg)
 	if p.To.Type == obj.TYPE_NONE {
@@ -2422,15 +2689,24 @@ func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
 	return o1
 }
 
-func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
+func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 {
 	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_SBIT != 0 {
 		o |= 1 << 20
 	}
-	if sc&(C_PBIT|C_WBIT) != 0 {
-		ctxt.Diag(".nil/.W on dp instruction")
-	}
 	switch a {
+	case ADIVHW:
+		return o | 0x71<<20 | 0xf<<12 | 0x1<<4
+	case ADIVUHW:
+		return o | 0x73<<20 | 0xf<<12 | 0x1<<4
+	case AMMUL:
+		return o | 0x75<<20 | 0xf<<12 | 0x1<<4
+	case AMULS:
+		return o | 0x6<<20 | 0x9<<4
+	case AMMULA:
+		return o | 0x75<<20 | 0x1<<4
+	case AMMULS:
+		return o | 0x75<<20 | 0xd<<4
 	case AMULU, AMUL:
 		return o | 0x0<<21 | 0x9<<4
 	case AMULA:
@@ -2471,6 +2747,9 @@ func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
 		return o | 0xc<<21
 
 	case AMOVB, AMOVH, AMOVW:
+		if sc&(C_PBIT|C_WBIT) != 0 {
+			c.ctxt.Diag("invalid .P/.W suffix: %v", p)
+		}
 		return o | 0xd<<21
 	case ABIC:
 		return o | 0xe<<21
@@ -2565,38 +2844,52 @@ func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
 	case ACLZ:
 		return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
 
+	case AREV:
+		return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4
+
+	case AREV16:
+		return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4
+
+	case AREVSH:
+		return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4
+
+	case ARBIT:
+		return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4
+
 	case AMULWT:
 		return o&(0xf<<28) | 0x12<<20 | 0xe<<4
 
 	case AMULWB:
 		return o&(0xf<<28) | 0x12<<20 | 0xa<<4
 
+	case AMULBB:
+		return o&(0xf<<28) | 0x16<<20 | 0xf<<12 | 0x8<<4
+
 	case AMULAWT:
 		return o&(0xf<<28) | 0x12<<20 | 0xc<<4
 
 	case AMULAWB:
 		return o&(0xf<<28) | 0x12<<20 | 0x8<<4
 
+	case AMULABB:
+		return o&(0xf<<28) | 0x10<<20 | 0x8<<4
+
 	case ABL: // BLX REG
 		return o&(0xf<<28) | 0x12fff3<<4
 	}
 
-	ctxt.Diag("bad rrr %d", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad rrr %d", p, a)
 	return 0
 }
 
-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)
-	}
+func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 {
 	sc &= C_SCOND
 	sc ^= C_SCOND_XOR
 	if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
 		return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
 	}
 	if sc != 0xe {
-		ctxt.Diag("%v: .COND on bcond instruction", p)
+		c.ctxt.Diag("%v: .COND on bcond instruction", p)
 	}
 	switch a {
 	case ABEQ:
@@ -2635,14 +2928,13 @@ func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
 		return 0xe<<28 | 0x5<<25
 	}
 
-	ctxt.Diag("bad bra %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad bra %v", p, a)
 	return 0
 }
 
-func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
+func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 {
 	if sc&C_SBIT != 0 {
-		ctxt.Diag(".nil on LDR/STR instruction")
+		c.ctxt.Diag(".nil on LDR/STR instruction")
 	}
 	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
@@ -2657,14 +2949,14 @@ func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
 	o |= 1<<26 | 1<<20
 	if v < 0 {
 		if sc&C_UBIT != 0 {
-			ctxt.Diag(".U on neg offset")
+			c.ctxt.Diag(".U on neg offset")
 		}
 		v = -v
 		o ^= 1 << 23
 	}
 
 	if v >= 1<<12 || v < 0 {
-		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
+		c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
 	}
 	o |= uint32(v)
 	o |= (uint32(b) & 15) << 16
@@ -2672,9 +2964,9 @@ func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
 	return o
 }
 
-func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
+func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 {
 	if sc&C_SBIT != 0 {
-		ctxt.Diag(".nil on LDRH/STRH instruction")
+		c.ctxt.Diag(".nil on LDRH/STRH instruction")
 	}
 	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
@@ -2690,7 +2982,7 @@ func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
 	}
 
 	if v >= 1<<8 || v < 0 {
-		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
+		c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
 	}
 	o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
 	o |= (uint32(b) & 15) << 16
@@ -2698,39 +2990,36 @@ func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
 	return o
 }
 
-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)
+func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 {
+	o := c.olr(v, b, r, sc) ^ (1 << 20)
 	if a != AMOVW {
 		o |= 1 << 22
 	}
 	return o
 }
 
-func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
-	o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
+func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 {
+	o := c.olhr(v, b, r, sc) ^ (1 << 20)
 	return o
 }
 
-func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
-	return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
+func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 {
+	return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20)
 }
 
-func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
-	return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
+func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 {
+	return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20)
 }
 
-func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
-	return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
+func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 {
+	return c.olr(int32(i), b, r, sc) ^ (1 << 25)
 }
 
-func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
-	return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
+func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 {
+	return c.olhr(int32(i), b, r, sc) ^ (1 << 22)
 }
 
-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)
-	}
+func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
 	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
 		o |= 1 << 24
@@ -2745,9 +3034,9 @@ func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog)
 	}
 
 	if v&3 != 0 {
-		ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
+		c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
 	} else if v >= 1<<10 || v < 0 {
-		ctxt.Diag("literal span too large: %d\n%v", v, p)
+		c.ctxt.Diag("literal span too large: %d\n%v", v, p)
 	}
 	o |= (uint32(v) >> 2) & 0xFF
 	o |= (uint32(b) & 15) << 16
@@ -2755,7 +3044,7 @@ func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog)
 
 	switch a {
 	default:
-		ctxt.Diag("bad fst %v", a)
+		c.ctxt.Diag("bad fst %v", a)
 		fallthrough
 
 	case AMOVD:
@@ -2769,39 +3058,49 @@ func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog)
 	return o
 }
 
-func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
+// MOVW $"lower 16-bit", Reg
+func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 {
+	var o1 uint32
+	o1 = ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+	o1 |= 0x30 << 20
+	o1 |= (uint32(dr) & 15) << 12
+	o1 |= uint32(a.Offset) & 0x0fff
+	o1 |= (uint32(a.Offset) & 0xf000) << 4
+	return o1
+}
+
+func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 {
 	var o1 uint32
 	if p.Pcond == nil {
-		aclass(ctxt, a)
-		v := immrot(^uint32(ctxt.Instoffset))
+		c.aclass(a)
+		v := immrot(^uint32(c.instoffset))
 		if v == 0 {
-			ctxt.Diag("missing literal")
-			prasm(p)
+			c.ctxt.Diag("%v: missing literal", p)
 			return 0
 		}
 
-		o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
+		o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND)
 		o1 |= uint32(v)
 		o1 |= (uint32(dr) & 15) << 12
 	} else {
 		v := int32(p.Pcond.Pc - p.Pc - 8)
-		o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
+		o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND)
 	}
 
 	return o1
 }
 
-func chipzero5(ctxt *obj.Link, e float64) int {
+func (c *ctxt5) chipzero5(e float64) int {
 	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
-	if obj.GOARM < 7 || e != 0 {
+	if objabi.GOARM < 7 || e != 0 {
 		return -1
 	}
 	return 0
 }
 
-func chipfloat5(ctxt *obj.Link, e float64) int {
+func (c *ctxt5) chipfloat5(e float64) int {
 	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
-	if obj.GOARM < 7 {
+	if objabi.GOARM < 7 {
 		return -1
 	}
 
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
index c25a8b7..169a7f5 100644
--- a/src/cmd/internal/obj/arm/list5.go
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -36,11 +36,11 @@ import (
 )
 
 func init() {
-	obj.RegisterRegister(obj.RBaseARM, MAXREG, Rconv)
+	obj.RegisterRegister(obj.RBaseARM, MAXREG, rconv)
 	obj.RegisterOpcode(obj.ABaseARM, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 6e5390c..32c4643 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -32,24 +32,21 @@ package arm
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
-	"fmt"
-	"log"
-	"math"
 )
 
 var progedit_tlsfallback *obj.LSym
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 	p.From.Class = 0
 	p.To.Class = 0
 
+	c := ctxt5{ctxt: ctxt, newprog: newprog}
+
 	// Rewrite B/BL to symbol as TYPE_BRANCH.
 	switch p.As {
-	case AB,
-		ABL,
-		obj.ADUFFZERO,
-		obj.ADUFFCOPY:
+	case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY:
 		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
 			p.To.Type = obj.TYPE_BRANCH
 		}
@@ -66,10 +63,10 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 				ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
 			}
 
-			if obj.GOARM < 7 {
+			if objabi.GOARM < 7 {
 				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
 				if progedit_tlsfallback == nil {
-					progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0)
+					progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback")
 				}
 
 				// MOVW	LR, R11
@@ -81,7 +78,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 				p.To.Reg = REGTMP
 
 				// BL	runtime.read_tls_fallback(SB)
-				p = obj.Appendp(ctxt, p)
+				p = obj.Appendp(p, newprog)
 
 				p.As = ABL
 				p.To.Type = obj.TYPE_BRANCH
@@ -89,7 +86,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 				p.To.Offset = 0
 
 				// MOVW	R11, LR
-				p = obj.Appendp(ctxt, p)
+				p = obj.Appendp(p, newprog)
 
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_REG
@@ -107,36 +104,30 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	// Rewrite float constants to values stored in memory.
 	switch p.As {
 	case AMOVF:
-		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
+		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			literal := fmt.Sprintf("$f32.%08x", i32)
-			s := obj.Linklookup(ctxt, literal, 0)
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
+			p.From.Sym = ctxt.Float32Sym(f32)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
 
 	case AMOVD:
-		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
-			i64 := math.Float64bits(p.From.Val.(float64))
-			literal := fmt.Sprintf("$f64.%016x", i64)
-			s := obj.Linklookup(ctxt, literal, 0)
+		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
+			p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64))
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
 	}
 
 	if ctxt.Flag_dynlink {
-		rewriteToUseGot(ctxt, p)
+		c.rewriteToUseGot(p)
 	}
 }
 
 // Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
 	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
 		//     ADUFFxxx $offset
 		// becomes
@@ -145,9 +136,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		//     CALL (R9)
 		var sym *obj.LSym
 		if p.As == obj.ADUFFZERO {
-			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+			sym = c.ctxt.Lookup("runtime.duffzero")
 		} else {
-			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+			sym = c.ctxt.Lookup("runtime.duffcopy")
 		}
 		offset := p.To.Offset
 		p.As = AMOVW
@@ -159,13 +150,13 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		p.To.Name = obj.NAME_NONE
 		p.To.Offset = 0
 		p.To.Sym = nil
-		p1 := obj.Appendp(ctxt, p)
+		p1 := obj.Appendp(p, c.newprog)
 		p1.As = AADD
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = offset
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = REG_R9
-		p2 := obj.Appendp(ctxt, p1)
+		p2 := obj.Appendp(p1, c.newprog)
 		p2.As = obj.ACALL
 		p2.To.Type = obj.TYPE_MEM
 		p2.To.Reg = REG_R9
@@ -179,15 +170,15 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		// MOVW $sym, Rx becomes MOVW sym at GOT, Rx
 		// MOVW $sym+<off>, Rx becomes MOVW sym at GOT, Rx; ADD <off>, Rx
 		if p.As != AMOVW {
-			ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
 		}
 		if p.To.Type != obj.TYPE_REG {
-			ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
 		}
 		p.From.Type = obj.TYPE_MEM
 		p.From.Name = obj.NAME_GOTREF
 		if p.From.Offset != 0 {
-			q := obj.Appendp(ctxt, p)
+			q := obj.Appendp(p, c.newprog)
 			q.As = AADD
 			q.From.Type = obj.TYPE_CONST
 			q.From.Offset = p.From.Offset
@@ -196,7 +187,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 	if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
 	var source *obj.Addr
 	// MOVx sym, Ry becomes MOVW sym at GOT, R9; MOVx (R9), Ry
@@ -204,7 +195,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	// 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)
+			c.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() {
@@ -215,14 +206,14 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	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 {
+	if source.Sym.Type == objabi.STLSBSS {
 		return
 	}
 	if source.Type != obj.TYPE_MEM {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
-	p1 := obj.Appendp(ctxt, p)
-	p2 := obj.Appendp(ctxt, p1)
+	p1 := obj.Appendp(p, c.newprog)
+	p2 := obj.Appendp(p1, c.newprog)
 
 	p1.As = AMOVW
 	p1.From.Type = obj.TYPE_MEM
@@ -255,24 +246,24 @@ const (
 	LEAF  = 1 << 2
 )
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 	autosize := int32(0)
 
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
+	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
 		return
 	}
 
-	softfloat(ctxt, cursym)
+	c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
+
+	c.softfloat()
 
-	p := cursym.Text
+	p := c.cursym.Func.Text
 	autoffset := int32(p.To.Offset)
 	if autoffset < 0 {
 		autoffset = 0
 	}
-	cursym.Locals = autoffset
-	cursym.Args = p.To.Val.(int32)
+	cursym.Func.Locals = autoffset
+	cursym.Func.Args = p.To.Val.(int32)
 
 	/*
 	 * find leaf subroutines
@@ -282,7 +273,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	 */
 	var q1 *obj.Prog
 	var q *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
 		case obj.ATEXT:
 			p.Mark |= LEAF
@@ -292,10 +283,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 		case ADIV, ADIVU, AMOD, AMODU:
 			q = p
-			if ctxt.Sym_div == nil {
-				initdiv(ctxt)
-			}
-			cursym.Text.Mark &^= LEAF
+			cursym.Func.Text.Mark &^= LEAF
 			continue
 
 		case obj.ANOP:
@@ -310,7 +298,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			ABX,
 			obj.ADUFFZERO,
 			obj.ADUFFCOPY:
-			cursym.Text.Mark &^= LEAF
+			cursym.Func.Text.Mark &^= LEAF
 			fallthrough
 
 		case AB,
@@ -342,42 +330,40 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		q = p
 	}
 
-	var p1 *obj.Prog
-	var p2 *obj.Prog
 	var q2 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := cursym.Func.Text; p != nil; p = p.Link {
 		o := p.As
 		switch o {
 		case obj.ATEXT:
 			autosize = int32(p.To.Offset + 4)
 			if autosize <= 4 {
-				if cursym.Text.Mark&LEAF != 0 {
+				if cursym.Func.Text.Mark&LEAF != 0 {
 					p.To.Offset = -4
 					autosize = 0
 				}
 			}
 
-			if autosize == 0 && cursym.Text.Mark&LEAF == 0 {
-				if ctxt.Debugvlog != 0 {
+			if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
+				if ctxt.Debugvlog {
 					ctxt.Logf("save suppressed in: %s\n", cursym.Name)
 				}
 
-				cursym.Text.Mark |= LEAF
+				cursym.Func.Text.Mark |= LEAF
 			}
 
-			if cursym.Text.Mark&LEAF != 0 {
+			if cursym.Func.Text.Mark&LEAF != 0 {
 				cursym.Set(obj.AttrLeaf, true)
 				if autosize == 0 {
 					break
 				}
 			}
 
-			if p.From3.Offset&obj.NOSPLIT == 0 {
-				p = stacksplit(ctxt, p, autosize) // emit split check
+			if !p.From.Sym.NoSplit() {
+				p = c.stacksplit(p, autosize) // emit split check
 			}
 
 			// MOVW.W		R14,$-autosize(SP)
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, c.newprog)
 
 			p.As = AMOVW
 			p.Scond |= C_WBIT
@@ -388,26 +374,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Reg = REGSP
 			p.Spadj = autosize
 
-			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+			if cursym.Func.Text.From.Sym.Wrapper() {
 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
 				//
 				//	MOVW g_panic(g), R1
-				//	CMP $0, R1
-				//	B.EQ end
+				//	CMP  $0, R1
+				//	B.NE checkargp
+				// end:
+				//	NOP
+				// ... function ...
+				// checkargp:
 				//	MOVW panic_argp(R1), R2
-				//	ADD $(autosize+4), R13, R3
-				//	CMP R2, R3
+				//	ADD  $(autosize+4), R13, R3
+				//	CMP  R2, R3
 				//	B.NE end
-				//	ADD $4, R13, R4
+				//	ADD  $4, R13, R4
 				//	MOVW R4, panic_argp(R1)
-				// end:
-				//	NOP
+				//	B    end
 				//
 				// The NOP is needed to give the jumps somewhere to land.
 				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
 
-				p = obj.Appendp(ctxt, p)
-
+				p = obj.Appendp(p, newprog)
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_MEM
 				p.From.Reg = REGG
@@ -415,26 +403,40 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_R1
 
-				p = obj.Appendp(ctxt, p)
+				p = obj.Appendp(p, newprog)
 				p.As = ACMP
 				p.From.Type = obj.TYPE_CONST
 				p.From.Offset = 0
 				p.Reg = REG_R1
 
-				p = obj.Appendp(ctxt, p)
-				p.As = ABEQ
-				p.To.Type = obj.TYPE_BRANCH
-				p1 = p
+				// B.NE checkargp
+				bne := obj.Appendp(p, newprog)
+				bne.As = ABNE
+				bne.To.Type = obj.TYPE_BRANCH
 
-				p = obj.Appendp(ctxt, p)
-				p.As = AMOVW
-				p.From.Type = obj.TYPE_MEM
-				p.From.Reg = REG_R1
-				p.From.Offset = 0 // Panic.argp
-				p.To.Type = obj.TYPE_REG
-				p.To.Reg = REG_R2
+				// end: NOP
+				end := obj.Appendp(bne, newprog)
+				end.As = obj.ANOP
+
+				// find end of function
+				var last *obj.Prog
+				for last = end; last.Link != nil; last = last.Link {
+				}
 
-				p = obj.Appendp(ctxt, p)
+				// MOVW panic_argp(R1), R2
+				mov := obj.Appendp(last, newprog)
+				mov.As = AMOVW
+				mov.From.Type = obj.TYPE_MEM
+				mov.From.Reg = REG_R1
+				mov.From.Offset = 0 // Panic.argp
+				mov.To.Type = obj.TYPE_REG
+				mov.To.Reg = REG_R2
+
+				// B.NE branch target is MOVW above
+				bne.Pcond = mov
+
+				// ADD $(autosize+4), R13, R3
+				p = obj.Appendp(mov, newprog)
 				p.As = AADD
 				p.From.Type = obj.TYPE_CONST
 				p.From.Offset = int64(autosize) + 4
@@ -442,18 +444,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_R3
 
-				p = obj.Appendp(ctxt, p)
+				// CMP R2, R3
+				p = obj.Appendp(p, newprog)
 				p.As = ACMP
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REG_R2
 				p.Reg = REG_R3
 
-				p = obj.Appendp(ctxt, p)
+				// B.NE end
+				p = obj.Appendp(p, newprog)
 				p.As = ABNE
 				p.To.Type = obj.TYPE_BRANCH
-				p2 = p
+				p.Pcond = end
 
-				p = obj.Appendp(ctxt, p)
+				// ADD $4, R13, R4
+				p = obj.Appendp(p, newprog)
 				p.As = AADD
 				p.From.Type = obj.TYPE_CONST
 				p.From.Offset = 4
@@ -461,7 +466,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_R4
 
-				p = obj.Appendp(ctxt, p)
+				// MOVW R4, panic_argp(R1)
+				p = obj.Appendp(p, newprog)
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REG_R4
@@ -469,16 +475,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Reg = REG_R1
 				p.To.Offset = 0 // Panic.argp
 
-				p = obj.Appendp(ctxt, p)
+				// B end
+				p = obj.Appendp(p, newprog)
+				p.As = AB
+				p.To.Type = obj.TYPE_BRANCH
+				p.Pcond = end
 
-				p.As = obj.ANOP
-				p1.Pcond = p
-				p2.Pcond = p
+				// reset for subsequent passes
+				p = end
 			}
 
 		case obj.ARET:
 			nocache(p)
-			if cursym.Text.Mark&LEAF != 0 {
+			if cursym.Func.Text.Mark&LEAF != 0 {
 				if autosize == 0 {
 					p.As = AB
 					p.From = obj.Addr{}
@@ -507,7 +516,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			// with the same stackframe, so no spadj.
 			if p.To.Sym != nil { // retjmp
 				p.To.Reg = REGLINK
-				q2 = obj.Appendp(ctxt, p)
+				q2 = obj.Appendp(p, newprog)
 				q2.As = AB
 				q2.To.Type = obj.TYPE_BRANCH
 				q2.To.Sym = p.To.Sym
@@ -526,10 +535,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 		case ADIV, ADIVU, AMOD, AMODU:
-			if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
+			if cursym.Func.Text.From.Sym.NoSplit() {
 				ctxt.Diag("cannot divide in NOSPLIT function")
 			}
-			if ctxt.Debugdivmod != 0 {
+			const debugdivmod = false
+			if debugdivmod {
 				break
 			}
 			if p.From.Type != obj.TYPE_REG {
@@ -547,7 +557,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 			/* MOV m(g),REGTMP */
 			p.As = AMOVW
-			p.Lineno = q1.Lineno
+			p.Pos = q1.Pos
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = REGG
 			p.From.Offset = 6 * 4 // offset of g.m
@@ -556,9 +566,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Reg = REGTMP
 
 			/* MOV a,m_divmod(REGTMP) */
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, newprog)
 			p.As = AMOVW
-			p.Lineno = q1.Lineno
+			p.Pos = q1.Pos
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = q1.From.Reg
 			p.To.Type = obj.TYPE_MEM
@@ -566,9 +576,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Offset = 8 * 4 // offset of m.divmod
 
 			/* MOV b, R8 */
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, newprog)
 			p.As = AMOVW
-			p.Lineno = q1.Lineno
+			p.Pos = q1.Pos
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = q1.Reg
 			if q1.Reg == 0 {
@@ -579,28 +589,25 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Offset = 0
 
 			/* CALL appropriate */
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, newprog)
 			p.As = ABL
-			p.Lineno = q1.Lineno
+			p.Pos = q1.Pos
 			p.To.Type = obj.TYPE_BRANCH
 			switch o {
 			case ADIV:
-				p.To.Sym = ctxt.Sym_div
-
+				p.To.Sym = symdiv
 			case ADIVU:
-				p.To.Sym = ctxt.Sym_divu
-
+				p.To.Sym = symdivu
 			case AMOD:
-				p.To.Sym = ctxt.Sym_mod
-
+				p.To.Sym = symmod
 			case AMODU:
-				p.To.Sym = ctxt.Sym_modu
+				p.To.Sym = symmodu
 			}
 
 			/* MOV REGTMP, b */
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, newprog)
 			p.As = AMOVW
-			p.Lineno = q1.Lineno
+			p.Pos = q1.Pos
 			p.From.Type = obj.TYPE_REG
 			p.From.Reg = REGTMP
 			p.From.Offset = 0
@@ -625,21 +632,21 @@ func isfloatreg(a *obj.Addr) bool {
 	return a.Type == obj.TYPE_REG && REG_F0 <= a.Reg && a.Reg <= REG_F15
 }
 
-func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
-	if obj.GOARM > 5 {
+func (c *ctxt5) softfloat() {
+	if objabi.GOARM > 5 {
 		return
 	}
 
-	symsfloat := obj.Linklookup(ctxt, "_sfloat", 0)
+	symsfloat := c.ctxt.Lookup("runtime._sfloat")
 
 	wasfloat := 0
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		if p.Pcond != nil {
 			p.Pcond.Mark |= LABEL
 		}
 	}
 	var next *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
 		case AMOVW:
 			if isfloatreg(&p.To) || isfloatreg(&p.From) {
@@ -679,17 +686,17 @@ func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
 
 	soft:
 		if wasfloat == 0 || (p.Mark&LABEL != 0) {
-			next = ctxt.NewProg()
+			next = c.newprog()
 			*next = *p
 
-			// BL _sfloat(SB)
+			// BL runtime·_sfloat(SB)
 			*p = obj.Prog{}
-			p.Ctxt = ctxt
+			p.Ctxt = c.ctxt
 			p.Link = next
 			p.As = ABL
 			p.To.Type = obj.TYPE_BRANCH
 			p.To.Sym = symsfloat
-			p.Lineno = next.Lineno
+			p.Pos = next.Pos
 
 			p = next
 			wasfloat = 1
@@ -702,43 +709,43 @@ func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 }
 
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
-	// MOVW			g_stackguard(g), R1
-	p = obj.Appendp(ctxt, p)
+func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
+	// MOVW g_stackguard(g), R1
+	p = obj.Appendp(p, c.newprog)
 
 	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() {
-		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
+	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
+	if c.cursym.CFunc() {
+		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
 
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP < stackguard
 		//	CMP	stackguard, SP
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
 		p.Reg = REGSP
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize < stackguard-StackSmall
-		//	MOVW $-framesize(SP), R2
+		//	MOVW $-(framesize-StackSmall)(SP), R2
 		//	CMP stackguard, R2
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = AMOVW
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Reg = REGSP
-		p.From.Offset = int64(-framesize)
+		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
@@ -749,28 +756,28 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
 		// The +StackGuard on both sides is required to keep the left side positive:
 		// SP is allowed to be slightly below stackguard. See stack.h.
-		//	CMP $StackPreempt, R1
+		//	CMP     $StackPreempt, R1
 		//	MOVW.NE $StackGuard(SP), R2
-		//	SUB.NE R1, R2
+		//	SUB.NE  R1, R2
 		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
-		//	CMP.NE R3, R2
-		p = obj.Appendp(ctxt, p)
+		//	CMP.NE  R3, R2
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ACMP
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
+		p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
 		p.Reg = REG_R1
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVW
 		p.From.Type = obj.TYPE_ADDR
 		p.From.Reg = REGSP
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 		p.Scond = C_SCOND_NE
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ASUB
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
@@ -778,15 +785,15 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Reg = REG_R2
 		p.Scond = C_SCOND_NE
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVW
 		p.From.Type = obj.TYPE_ADDR
-		p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
+		p.From.Offset = int64(framesize) + (objabi.StackGuard - objabi.StackSmall)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R3
 		p.Scond = C_SCOND_NE
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
@@ -795,32 +802,31 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// BLS call-to-morestack
-	bls := obj.Appendp(ctxt, p)
+	bls := obj.Appendp(p, c.newprog)
 	bls.As = ABLS
 	bls.To.Type = obj.TYPE_BRANCH
 
 	var last *obj.Prog
-	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
 	}
 
 	// Now we are at the end of the function, but logically
 	// we are still in function prologue. We need to fix the
 	// SP data and PCDATA.
-	spfix := obj.Appendp(ctxt, last)
+	spfix := obj.Appendp(last, c.newprog)
 	spfix.As = obj.ANOP
 	spfix.Spadj = -framesize
 
-	pcdata := obj.Appendp(ctxt, spfix)
-	pcdata.Lineno = ctxt.Cursym.Text.Lineno
-	pcdata.Mode = ctxt.Cursym.Text.Mode
+	pcdata := obj.Appendp(spfix, c.newprog)
+	pcdata.Pos = c.cursym.Func.Text.Pos
 	pcdata.As = obj.APCDATA
 	pcdata.From.Type = obj.TYPE_CONST
-	pcdata.From.Offset = obj.PCDATA_StackMapIndex
+	pcdata.From.Offset = objabi.PCDATA_StackMapIndex
 	pcdata.To.Type = obj.TYPE_CONST
 	pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
 
 	// MOVW	LR, R3
-	movw := obj.Appendp(ctxt, pcdata)
+	movw := obj.Appendp(pcdata, c.newprog)
 	movw.As = AMOVW
 	movw.From.Type = obj.TYPE_REG
 	movw.From.Reg = REGLINK
@@ -830,215 +836,28 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	bls.Pcond = movw
 
 	// BL runtime.morestack
-	call := obj.Appendp(ctxt, movw)
+	call := obj.Appendp(movw, c.newprog)
 	call.As = obj.ACALL
 	call.To.Type = obj.TYPE_BRANCH
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.CFunc():
+	case c.cursym.CFunc():
 		morestack = "runtime.morestackc"
-	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
+	case !c.cursym.Func.Text.From.Sym.NeedCtxt():
 		morestack = "runtime.morestack_noctxt"
 	}
-	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+	call.To.Sym = c.ctxt.Lookup(morestack)
 
 	// B start
-	b := obj.Appendp(ctxt, call)
+	b := obj.Appendp(call, c.newprog)
 	b.As = obj.AJMP
 	b.To.Type = obj.TYPE_BRANCH
-	b.Pcond = ctxt.Cursym.Text.Link
+	b.Pcond = c.cursym.Func.Text.Link
 	b.Spadj = +framesize
 
 	return bls
 }
 
-func initdiv(ctxt *obj.Link) {
-	if ctxt.Sym_div != nil {
-		return
-	}
-	ctxt.Sym_div = obj.Linklookup(ctxt, "_div", 0)
-	ctxt.Sym_divu = obj.Linklookup(ctxt, "_divu", 0)
-	ctxt.Sym_mod = obj.Linklookup(ctxt, "_mod", 0)
-	ctxt.Sym_modu = obj.Linklookup(ctxt, "_modu", 0)
-}
-
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
-	firstp := ctxt.NewProg()
-	lastp := firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func relinv(a obj.As) obj.As {
-	switch a {
-	case ABEQ:
-		return ABNE
-	case ABNE:
-		return ABEQ
-	case ABCS:
-		return ABCC
-	case ABHS:
-		return ABLO
-	case ABCC:
-		return ABCS
-	case ABLO:
-		return ABHS
-	case ABMI:
-		return ABPL
-	case ABPL:
-		return ABMI
-	case ABVS:
-		return ABVC
-	case ABVC:
-		return ABVS
-	case ABHI:
-		return ABLS
-	case ABLS:
-		return ABHI
-	case ABGE:
-		return ABLT
-	case ABLT:
-		return ABGE
-	case ABGT:
-		return ABLE
-	case ABLE:
-		return ABGT
-	}
-
-	log.Fatalf("unknown relation: %s", Anames[a])
-	return 0
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
-	var q *obj.Prog
-	var r *obj.Prog
-	var i int
-
-loop:
-	if p == nil {
-		return
-	}
-	a := p.As
-	if a == AB {
-		q = p.Pcond
-		if q != nil && q.As != obj.ATEXT {
-			p.Mark |= FOLL
-			p = q
-			if p.Mark&FOLL == 0 {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark&FOLL != 0 {
-		i = 0
-		q = p
-		for ; i < 4; i, q = i+1, q.Link {
-			if q == *last || q == nil {
-				break
-			}
-			a = q.As
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
-				goto copy
-			}
-			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
-				continue
-			}
-			if a != ABEQ && a != ABNE {
-				continue
-			}
-
-		copy:
-			for {
-				r = ctxt.NewProg()
-				*r = *p
-				if r.Mark&FOLL == 0 {
-					fmt.Printf("can't happen 1\n")
-				}
-				r.Mark |= FOLL
-				if p != q {
-					p = p.Link
-					(*last).Link = r
-					*last = r
-					continue
-				}
-
-				(*last).Link = r
-				*last = r
-				if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
-					return
-				}
-				r.As = ABNE
-				if a == ABNE {
-					r.As = ABEQ
-				}
-				r.Pcond = p.Link
-				r.Link = p.Pcond
-				if r.Link.Mark&FOLL == 0 {
-					xfol(ctxt, r.Link, last)
-				}
-				if r.Pcond.Mark&FOLL == 0 {
-					fmt.Printf("can't happen 2\n")
-				}
-				return
-			}
-		}
-
-		a = AB
-		q = ctxt.NewProg()
-		q.As = a
-		q.Lineno = p.Lineno
-		q.To.Type = obj.TYPE_BRANCH
-		q.To.Offset = p.Pc
-		q.Pcond = p
-		p = q
-	}
-
-	p.Mark |= FOLL
-	(*last).Link = p
-	*last = p
-	if a == AB || (a == obj.ARET && p.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
-		return
-	}
-
-	if p.Pcond != nil {
-		if a != ABL && a != ABX && p.Link != nil {
-			q = obj.Brchain(ctxt, p.Link)
-			if a != obj.ATEXT {
-				if q != nil && (q.Mark&FOLL != 0) {
-					p.As = relinv(a)
-					p.Link = p.Pcond
-					p.Pcond = q
-				}
-			}
-
-			xfol(ctxt, p.Link, last)
-			q = obj.Brchain(ctxt, p.Pcond)
-			if q == nil {
-				q = p.Pcond
-			}
-			if q.Mark&FOLL != 0 {
-				p.Pcond = q
-				return
-			}
-
-			p = q
-			goto loop
-		}
-	}
-
-	p = p.Link
-	goto loop
-}
-
 var unaryDst = map[obj.As]bool{
 	ASWI:  true,
 	AWORD: true,
@@ -1046,9 +865,9 @@ var unaryDst = map[obj.As]bool{
 
 var Linkarm = obj.LinkArch{
 	Arch:       sys.ArchARM,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span5,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index bed129d89..3a3fed5 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -254,6 +254,9 @@ const (
 )
 
 const (
+	// optab is sorted based on the order of these constants
+	// and the first match is chosen.
+	// The more specific class needs to come earlier.
 	C_NONE   = iota
 	C_REG    // R0..R30
 	C_RSP    // R0..R30, RSP
@@ -266,13 +269,13 @@ const (
 	C_COND   // EQ, NE, etc
 
 	C_ZCON     // $0 or ZR
+	C_ABCON0   // could be C_ADDCON0 or C_BITCON
 	C_ADDCON0  // 12-bit unsigned, unshifted
+	C_ABCON    // could be C_ADDCON or C_BITCON
 	C_ADDCON   // 12-bit unsigned, shifted left by 0 or 12
+	C_MBCON    // could be C_MOVCON or C_BITCON
 	C_MOVCON   // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
 	C_BITCON   // bitfield and logical immediate masks
-	C_ABCON0   // could be C_ADDCON0 or C_BITCON
-	C_ABCON    // could be C_ADDCON or C_BITCON
-	C_MBCON    // could be C_MOVCON or C_BITCON
 	C_LCON     // 32-bit constant
 	C_VCON     // 64-bit constant
 	C_FCON     // floating-point constant
@@ -286,16 +289,21 @@ const (
 	C_SBRA // for TYPE_BRANCH
 	C_LBRA
 
-	C_NPAUTO   // -512 <= x < 0, 0 mod 8
-	C_NSAUTO   // -256 <= x < 0
-	C_PSAUTO   // 0 to 255
-	C_PPAUTO   // 0 to 504, 0 mod 8
-	C_UAUTO4K  // 0 to 4095
-	C_UAUTO8K  // 0 to 8190, 0 mod 2
-	C_UAUTO16K // 0 to 16380, 0 mod 4
-	C_UAUTO32K // 0 to 32760, 0 mod 8
-	C_UAUTO64K // 0 to 65520, 0 mod 16
-	C_LAUTO    // any other 32-bit constant
+	C_NPAUTO     // -512 <= x < 0, 0 mod 8
+	C_NSAUTO     // -256 <= x < 0
+	C_PSAUTO     // 0 to 255
+	C_PPAUTO     // 0 to 504, 0 mod 8
+	C_UAUTO4K_8  // 0 to 4095, 0 mod 8
+	C_UAUTO4K_4  // 0 to 4095, 0 mod 4
+	C_UAUTO4K_2  // 0 to 4095, 0 mod 2
+	C_UAUTO4K    // 0 to 4095
+	C_UAUTO8K_8  // 0 to 8190, 0 mod 8
+	C_UAUTO8K_4  // 0 to 8190, 0 mod 4
+	C_UAUTO8K    // 0 to 8190, 0 mod 2
+	C_UAUTO16K_8 // 0 to 16380, 0 mod 8
+	C_UAUTO16K   // 0 to 16380, 0 mod 4
+	C_UAUTO32K   // 0 to 32760, 0 mod 8
+	C_LAUTO      // any other 32-bit constant
 
 	C_SEXT1  // 0 to 4095, direct
 	C_SEXT2  // 0 to 8190
@@ -304,17 +312,21 @@ const (
 	C_SEXT16 // 0 to 65520
 	C_LEXT
 
-	// TODO(aram): s/AUTO/INDIR/
 	C_ZOREG  // 0(R)
-	C_NPOREG // mirror NPAUTO, etc
+	C_NPOREG // must mirror NPAUTO, etc
 	C_NSOREG
 	C_PSOREG
 	C_PPOREG
+	C_UOREG4K_8
+	C_UOREG4K_4
+	C_UOREG4K_2
 	C_UOREG4K
+	C_UOREG8K_8
+	C_UOREG8K_4
 	C_UOREG8K
+	C_UOREG16K_8
 	C_UOREG16K
 	C_UOREG32K
-	C_UOREG64K
 	C_LOREG
 
 	C_ADDR // TODO(aram): explain difference from C_VCONADDR
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index d55b34f..24911f6 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -4,6 +4,7 @@
 
 package arm64
 
+// This order should be strictly consistent to that in a.out.go
 var cnames7 = []string{
 	"NONE",
 	"REG",
@@ -16,13 +17,13 @@ var cnames7 = []string{
 	"SPR",
 	"COND",
 	"ZCON",
+	"ABCON0",
 	"ADDCON0",
+	"ABCON",
 	"ADDCON",
+	"MBCON",
 	"MOVCON",
 	"BITCON",
-	"ABCON0",
-	"ABCON",
-	"MBCON",
 	"LCON",
 	"VCON",
 	"FCON",
@@ -36,11 +37,16 @@ var cnames7 = []string{
 	"NSAUTO",
 	"PSAUTO",
 	"PPAUTO",
+	"UAUTO4K_8",
+	"UAUTO4K_4",
+	"UAUTO4K_2",
 	"UAUTO4K",
+	"UAUTO8K_8",
+	"UAUTO8K_4",
 	"UAUTO8K",
+	"UAUTO16K_8",
 	"UAUTO16K",
 	"UAUTO32K",
-	"UAUTO64K",
 	"LAUTO",
 	"SEXT1",
 	"SEXT2",
@@ -53,11 +59,16 @@ var cnames7 = []string{
 	"NSOREG",
 	"PSOREG",
 	"PPOREG",
+	"UOREG4K_8",
+	"UOREG4K_4",
+	"UOREG4K_2",
 	"UOREG4K",
+	"UOREG8K_8",
+	"UOREG8K_4",
 	"UOREG8K",
+	"UOREG16K_8",
 	"UOREG16K",
 	"UOREG32K",
-	"UOREG64K",
 	"LOREG",
 	"ADDR",
 	"GOTADDR",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 3409957..f4e2562 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -32,12 +32,31 @@ package arm64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"log"
 	"math"
 	"sort"
 )
 
+// ctxt7 holds state while assembling a single function.
+// Each function gets a fresh ctxt7.
+// This allows for multiple functions to be safely concurrently assembled.
+type ctxt7 struct {
+	ctxt       *obj.Link
+	newprog    obj.ProgAlloc
+	cursym     *obj.LSym
+	blitrl     *obj.Prog
+	elitrl     *obj.Prog
+	autosize   int32
+	instoffset int64
+	pc         int64
+	pool       struct {
+		start uint32
+		size  uint32
+	}
+}
+
 const (
 	funcAlign = 16
 )
@@ -190,6 +209,10 @@ var optab = []Optab{
 	{AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
 	{ABIC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
 	{ABIC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{AAND, C_MBCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+	{AAND, C_MBCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+	{ABIC, C_MBCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+	{ABIC, C_MBCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
 	{AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
 	{AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
 	{ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
@@ -346,33 +369,28 @@ var optab = []Optab{
 	{AMOVD, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
 
 	/* long displacement store */
-	{AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
-	{AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
-	{AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
-	{AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
-	{AMOVH, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
-	{AMOVH, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
-	{AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
-	{AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
-	{AMOVD, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
-	{AMOVD, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AMOVH, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AMOVH, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AMOVD, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AMOVD, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
 
 	/* long displacement load */
-	{AMOVB, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
-	{AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
-	{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVH, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
-	{AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
-	{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVD, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
-	{AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
-	{AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVB, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	{AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	{AMOVH, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	{AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	{AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	{AMOVD, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	{AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
 
 	/* load long effective stack address (load int32 offset and add) */
 	{AMOVD, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
@@ -472,7 +490,7 @@ var optab = []Optab{
 	{AFMOVD, C_FREG, C_NONE, C_REG, 29, 4, 0, 0, 0},
 	{AFCMPS, C_FREG, C_FREG, C_NONE, 56, 4, 0, 0, 0},
 	{AFCMPS, C_FCON, C_FREG, C_NONE, 56, 4, 0, 0, 0},
-	{AFCCMPS, C_COND, C_REG, C_VCON, 57, 4, 0, 0, 0},
+	{AFCCMPS, C_COND, C_FREG, C_VCON, 57, 4, 0, 0, 0},
 	{AFCSELD, C_COND, C_REG, C_FREG, 18, 4, 0, 0, 0},
 	{AFCVTSD, C_FREG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
 	{ACLREX, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0},
@@ -498,7 +516,6 @@ var optab = []Optab{
 	{ASHA1C, C_VREG, C_REG, C_VREG, 1, 4, 0, 0, 0},
 
 	{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
-	{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
 	{obj.APCDATA, C_VCON, C_NONE, C_VCON, 0, 0, 0, 0, 0},
 	{obj.AFUNCDATA, C_VCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
 	{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
@@ -520,66 +537,56 @@ var pstatefield = []struct {
 	{REG_DAIFClr, 3<<16 | 4<<12 | 7<<5},
 }
 
-var pool struct {
-	start uint32
-	size  uint32
-}
-
-func prasm(p *obj.Prog) {
-	fmt.Printf("%v\n", p)
-}
-
-func span7(ctxt *obj.Link, cursym *obj.LSym) {
-	p := cursym.Text
+func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	p := cursym.Func.Text
 	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
 		return
 	}
-	ctxt.Cursym = cursym
-	ctxt.Autosize = int32(p.To.Offset&0xffffffff) + 8
 
 	if oprange[AAND&obj.AMask] == nil {
-		buildop(ctxt)
+		ctxt.Diag("arm64 ops not initialized, call arm64.buildop first")
 	}
 
+	c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset&0xffffffff) + 8}
+
 	bflag := 1
-	c := int64(0)
-	p.Pc = c
+	pc := int64(0)
+	p.Pc = pc
 	var m int
 	var o *Optab
 	for p = p.Link; p != nil; p = p.Link {
-		ctxt.Curp = p
-		if p.As == ADWORD && (c&7) != 0 {
-			c += 4
+		if p.As == ADWORD && (pc&7) != 0 {
+			pc += 4
 		}
-		p.Pc = c
-		o = oplook(ctxt, p)
+		p.Pc = pc
+		o = c.oplook(p)
 		m = int(o.size)
 		if m == 0 {
-			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-				ctxt.Diag("zero-width instruction\n%v", p)
+			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+				c.ctxt.Diag("zero-width instruction\n%v", p)
 			}
 			continue
 		}
 
 		switch o.flag & (LFROM | LTO) {
 		case LFROM:
-			addpool(ctxt, p, &p.From)
+			c.addpool(p, &p.From)
 
 		case LTO:
-			addpool(ctxt, p, &p.To)
+			c.addpool(p, &p.To)
 			break
 		}
 
 		if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
-			checkpool(ctxt, p, 0)
+			c.checkpool(p, 0)
 		}
-		c += int64(m)
-		if ctxt.Blitrl != nil {
-			checkpool(ctxt, p, 1)
+		pc += int64(m)
+		if c.blitrl != nil {
+			c.checkpool(p, 1)
 		}
 	}
 
-	cursym.Size = c
+	c.cursym.Size = pc
 
 	/*
 	 * if any procedure is large enough to
@@ -588,30 +595,27 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
 	 * around jmps to fix. this is rare.
 	 */
 	for bflag != 0 {
-		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f span1\n", obj.Cputime())
-		}
 		bflag = 0
-		c = 0
-		for p = cursym.Text.Link; p != nil; p = p.Link {
-			if p.As == ADWORD && (c&7) != 0 {
-				c += 4
+		pc = 0
+		for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+			if p.As == ADWORD && (pc&7) != 0 {
+				pc += 4
 			}
-			p.Pc = c
-			o = oplook(ctxt, p)
+			p.Pc = pc
+			o = c.oplook(p)
 
 			/* very large branches */
 			if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
-				otxt := p.Pcond.Pc - c
+				otxt := p.Pcond.Pc - pc
 				if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
-					q := ctxt.NewProg()
+					q := c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = AB
 					q.To.Type = obj.TYPE_BRANCH
 					q.Pcond = p.Pcond
 					p.Pcond = q
-					q = ctxt.NewProg()
+					q = c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = AB
@@ -623,31 +627,30 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
 			m = int(o.size)
 
 			if m == 0 {
-				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-					ctxt.Diag("zero-width instruction\n%v", p)
+				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+					c.ctxt.Diag("zero-width instruction\n%v", p)
 				}
 				continue
 			}
 
-			c += int64(m)
+			pc += int64(m)
 		}
 	}
 
-	c += -c & (funcAlign - 1)
-	cursym.Size = c
+	pc += -pc & (funcAlign - 1)
+	c.cursym.Size = pc
 
 	/*
 	 * lay out the code, emitting code and data relocations.
 	 */
-	cursym.Grow(cursym.Size)
-	bp := cursym.P
+	c.cursym.Grow(c.cursym.Size)
+	bp := c.cursym.P
 	psz := int32(0)
 	var i int
 	var out [6]uint32
-	for p := cursym.Text.Link; p != nil; p = p.Link {
-		ctxt.Pc = p.Pc
-		ctxt.Curp = p
-		o = oplook(ctxt, p)
+	for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+		c.pc = p.Pc
+		o = c.oplook(p)
 
 		// need to align DWORDs on 8-byte boundary. The ISA doesn't
 		// require it, but the various 64-bit loads we generate assume it.
@@ -663,9 +666,9 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
 		if int(o.size) > 4*len(out) {
 			log.Fatalf("out array in span7 is too small, need at least %d for %v", o.size/4, p)
 		}
-		asmout(ctxt, p, o, out[:])
+		c.asmout(p, o, out[:])
 		for i = 0; i < int(o.size/4); i++ {
-			ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
+			c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
 			bp = bp[4:]
 			psz += 4
 		}
@@ -677,55 +680,55 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
  * to go out of range of a 1Mb PC-relative offset
  * drop the pool now, and branch round it.
  */
-func checkpool(ctxt *obj.Link, p *obj.Prog, skip int) {
-	if pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(pool.size)-int64(pool.start)+8)) {
-		flushpool(ctxt, p, skip)
+func (c *ctxt7) checkpool(p *obj.Prog, skip int) {
+	if c.pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(c.pool.size)-int64(c.pool.start)+8)) {
+		c.flushpool(p, skip)
 	} else if p.Link == nil {
-		flushpool(ctxt, p, 2)
+		c.flushpool(p, 2)
 	}
 }
 
-func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) {
-	if ctxt.Blitrl != nil {
+func (c *ctxt7) flushpool(p *obj.Prog, skip int) {
+	if c.blitrl != nil {
 		if skip != 0 {
-			if ctxt.Debugvlog != 0 && skip == 1 {
-				fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
+			if c.ctxt.Debugvlog && skip == 1 {
+				fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
 			}
-			q := ctxt.NewProg()
+			q := c.newprog()
 			q.As = AB
 			q.To.Type = obj.TYPE_BRANCH
 			q.Pcond = p.Link
-			q.Link = ctxt.Blitrl
-			q.Lineno = p.Lineno
-			ctxt.Blitrl = q
-		} else if p.Pc+int64(pool.size)-int64(pool.start) < maxPCDisp {
+			q.Link = c.blitrl
+			q.Pos = p.Pos
+			c.blitrl = q
+		} else if p.Pc+int64(c.pool.size)-int64(c.pool.start) < maxPCDisp {
 			return
 		}
 
 		// The line number for constant pool entries doesn't really matter.
 		// We set it to the line number of the preceding instruction so that
 		// there are no deltas to encode in the pc-line tables.
-		for q := ctxt.Blitrl; q != nil; q = q.Link {
-			q.Lineno = p.Lineno
+		for q := c.blitrl; q != nil; q = q.Link {
+			q.Pos = p.Pos
 		}
 
-		ctxt.Elitrl.Link = p.Link
-		p.Link = ctxt.Blitrl
+		c.elitrl.Link = p.Link
+		p.Link = c.blitrl
 
-		ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
-		ctxt.Elitrl = nil
-		pool.size = 0
-		pool.start = 0
+		c.blitrl = nil /* BUG: should refer back to values until out-of-range */
+		c.elitrl = nil
+		c.pool.size = 0
+		c.pool.start = 0
 	}
 }
 
 /*
  * TODO: hash
  */
-func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	c := aclass(ctxt, a)
-	lit := ctxt.Instoffset
-	t := *ctxt.NewProg()
+func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
+	cls := c.aclass(a)
+	lit := c.instoffset
+	t := c.newprog()
 	t.As = AWORD
 	sz := 4
 
@@ -733,18 +736,18 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 	//	MOVD addr, REGTMP
 	//	MOVD REGTMP, R
 	// where addr is the address of the DWORD containing the address of foo.
-	if p.As == AMOVD || c == C_ADDR || c == C_VCON || int64(lit) != int64(int32(lit)) || uint64(lit) != uint64(uint32(lit)) {
+	if p.As == AMOVD && a.Type != obj.TYPE_MEM || cls == C_ADDR || cls == C_VCON || int64(lit) != int64(int32(lit)) || uint64(lit) != uint64(uint32(lit)) {
 		// conservative: don't know if we want signed or unsigned extension.
 		// in case of ambiguity, store 64-bit
 		t.As = ADWORD
 		sz = 8
 	}
 
-	switch c {
+	switch cls {
 	// TODO(aram): remove.
 	default:
 		if a.Name != obj.NAME_EXTERN {
-			fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(c), p)
+			fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(cls), p)
 		}
 
 		t.To.Offset = a.Offset
@@ -759,21 +762,31 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 
 	case C_PSAUTO,
 		C_PPAUTO,
+		C_UAUTO4K_8,
+		C_UAUTO4K_4,
+		C_UAUTO4K_2,
 		C_UAUTO4K,
+		C_UAUTO8K_8,
+		C_UAUTO8K_4,
 		C_UAUTO8K,
+		C_UAUTO16K_8,
 		C_UAUTO16K,
 		C_UAUTO32K,
-		C_UAUTO64K,
 		C_NSAUTO,
 		C_NPAUTO,
 		C_LAUTO,
 		C_PPOREG,
 		C_PSOREG,
+		C_UOREG4K_8,
+		C_UOREG4K_4,
+		C_UOREG4K_2,
 		C_UOREG4K,
+		C_UOREG8K_8,
+		C_UOREG8K_4,
 		C_UOREG8K,
+		C_UOREG16K_8,
 		C_UOREG16K,
 		C_UOREG32K,
-		C_UOREG64K,
 		C_NSOREG,
 		C_NPOREG,
 		C_LOREG,
@@ -781,7 +794,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		C_LCON,
 		C_VCON:
 		if a.Name == obj.NAME_EXTERN {
-			fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(c), p)
+			fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p)
 		}
 
 		t.To.Type = obj.TYPE_CONST
@@ -789,32 +802,32 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		break
 	}
 
-	for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
+	for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
 		if q.To == t.To {
 			p.Pcond = q
 			return
 		}
 	}
 
-	q := ctxt.NewProg()
-	*q = t
-	q.Pc = int64(pool.size)
-	if ctxt.Blitrl == nil {
-		ctxt.Blitrl = q
-		pool.start = uint32(p.Pc)
+	q := c.newprog()
+	*q = *t
+	q.Pc = int64(c.pool.size)
+	if c.blitrl == nil {
+		c.blitrl = q
+		c.pool.start = uint32(p.Pc)
 	} else {
-		ctxt.Elitrl.Link = q
+		c.elitrl.Link = q
 	}
-	ctxt.Elitrl = q
-	pool.size = -pool.size & (funcAlign - 1)
-	pool.size += uint32(sz)
+	c.elitrl = q
+	c.pool.size = -c.pool.size & (funcAlign - 1)
+	c.pool.size += uint32(sz)
 	p.Pcond = q
 }
 
-func regoff(ctxt *obj.Link, a *obj.Addr) uint32 {
-	ctxt.Instoffset = 0
-	aclass(ctxt, a)
-	return uint32(ctxt.Instoffset)
+func (c *ctxt7) regoff(a *obj.Addr) uint32 {
+	c.instoffset = 0
+	c.aclass(a)
+	return uint32(c.instoffset)
 }
 
 // Maximum PC-relative displacement.
@@ -990,20 +1003,39 @@ func autoclass(l int64) int {
 		return C_PPAUTO
 	}
 	if l <= 4095 {
+		if l&7 == 0 {
+			return C_UAUTO4K_8
+		}
+		if l&3 == 0 {
+			return C_UAUTO4K_4
+		}
+		if l&1 == 0 {
+			return C_UAUTO4K_2
+		}
 		return C_UAUTO4K
 	}
-	if l <= 8190 && (l&1) == 0 {
-		return C_UAUTO8K
+	if l <= 8190 {
+		if l&7 == 0 {
+			return C_UAUTO8K_8
+		}
+		if l&3 == 0 {
+			return C_UAUTO8K_4
+		}
+		if l&1 == 0 {
+			return C_UAUTO8K
+		}
 	}
-	if l <= 16380 && (l&3) == 0 {
-		return C_UAUTO16K
+	if l <= 16380 {
+		if l&7 == 0 {
+			return C_UAUTO16K_8
+		}
+		if l&3 == 0 {
+			return C_UAUTO16K
+		}
 	}
 	if l <= 32760 && (l&7) == 0 {
 		return C_UAUTO32K
 	}
-	if l <= 65520 && (l&0xF) == 0 {
-		return C_UAUTO64K
-	}
 	return C_LAUTO
 }
 
@@ -1019,18 +1051,27 @@ func oregclass(l int64) int {
  * return the offset value to use in the instruction,
  * scaled if necessary
  */
-func offsetshift(ctxt *obj.Link, v int64, c int) int64 {
+func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 {
 	s := 0
-	if c >= C_SEXT1 && c <= C_SEXT16 {
-		s = c - C_SEXT1
-	} else if c >= C_UAUTO4K && c <= C_UAUTO64K {
-		s = c - C_UAUTO4K
-	} else if c >= C_UOREG4K && c <= C_UOREG64K {
-		s = c - C_UOREG4K
+	if cls >= C_SEXT1 && cls <= C_SEXT16 {
+		s = cls - C_SEXT1
+	} else {
+		switch cls {
+		case C_UAUTO4K, C_UOREG4K, C_ZOREG:
+			s = 0
+		case C_UAUTO8K, C_UOREG8K:
+			s = 1
+		case C_UAUTO16K, C_UOREG16K:
+			s = 2
+		case C_UAUTO32K, C_UOREG32K:
+			s = 3
+		default:
+			c.ctxt.Diag("bad class: %v\n%v", DRconv(cls), p)
+		}
 	}
 	vs := v >> uint(s)
 	if vs<<uint(s) != v {
-		ctxt.Diag("odd offset: %d\n%v", v, ctxt.Curp)
+		c.ctxt.Diag("odd offset: %d\n%v", v, p)
 	}
 	return vs
 }
@@ -1071,7 +1112,7 @@ func rclass(r int16) int {
 	return C_GOK
 }
 
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
+func (c *ctxt7) aclass(a *obj.Addr) int {
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -1091,10 +1132,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if a.Sym == nil {
 				break
 			}
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Sym != nil { // use relocation
-				if a.Sym.Type == obj.STLSBSS {
-					if ctxt.Flag_shared {
+				if a.Sym.Type == objabi.STLSBSS {
+					if c.ctxt.Flag_shared {
 						return C_TLS_IE
 					} else {
 						return C_TLS_LE
@@ -1108,16 +1149,16 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_GOTADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			return autoclass(ctxt.Instoffset)
+			c.instoffset = int64(c.autosize) + a.Offset
+			return autoclass(c.instoffset)
 
 		case obj.NAME_PARAM:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
-			return autoclass(ctxt.Instoffset)
+			c.instoffset = int64(c.autosize) + a.Offset + 8
+			return autoclass(c.instoffset)
 
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
-			return oregclass(ctxt.Instoffset)
+			c.instoffset = a.Offset
+			return oregclass(c.instoffset)
 		}
 		return C_GOK
 
@@ -1130,11 +1171,11 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	case obj.TYPE_CONST, obj.TYPE_ADDR:
 		switch a.Name {
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Reg != 0 && a.Reg != REGZERO {
 				goto aconsize
 			}
-			v := ctxt.Instoffset
+			v := c.instoffset
 			if v == 0 {
 				return C_ZCON
 			}
@@ -1180,24 +1221,24 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if a.Sym == nil {
 				break
 			}
-			if a.Sym.Type == obj.STLSBSS {
-				ctxt.Diag("taking address of TLS variable is not supported")
+			if a.Sym.Type == objabi.STLSBSS {
+				c.ctxt.Diag("taking address of TLS variable is not supported")
 			}
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			return C_VCONADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			c.instoffset = int64(c.autosize) + a.Offset
 			goto aconsize
 
 		case obj.NAME_PARAM:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+			c.instoffset = int64(c.autosize) + a.Offset + 8
 			goto aconsize
 		}
 		return C_GOK
 
 	aconsize:
-		if isaddcon(ctxt.Instoffset) {
+		if isaddcon(c.instoffset) {
 			return C_AACON
 		}
 		return C_LACON
@@ -1213,21 +1254,21 @@ func oclass(a *obj.Addr) int {
 	return int(a.Class) - 1
 }
 
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+func (c *ctxt7) oplook(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
+		a1 = c.aclass(&p.From) + 1
 		p.From.Class = int8(a1)
 	}
 
 	a1--
 	a3 := int(p.To.Class)
 	if a3 == 0 {
-		a3 = aclass(ctxt, &p.To) + 1
+		a3 = c.aclass(&p.To) + 1
 		p.To.Class = int8(a3)
 	}
 
@@ -1255,8 +1296,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 		}
 	}
 
-	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)
+	c.ctxt.Diag("illegal combination %v %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type)
 	if ops == nil {
 		ops = optab
 	}
@@ -1342,27 +1382,42 @@ func cmp(a int, b int) bool {
 		}
 
 	case C_UAUTO4K:
-		if b == C_PSAUTO || b == C_PPAUTO {
+		switch b {
+		case C_PSAUTO, C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
 			return true
 		}
 
 	case C_UAUTO8K:
-		return cmp(C_UAUTO4K, b)
+		switch b {
+		case C_PSAUTO, C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
+			return true
+		}
 
 	case C_UAUTO16K:
-		return cmp(C_UAUTO8K, b)
+		switch b {
+		case C_PSAUTO, C_PPAUTO, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
+			return true
+		}
 
 	case C_UAUTO32K:
-		return cmp(C_UAUTO16K, b)
-
-	case C_UAUTO64K:
-		return cmp(C_UAUTO32K, b)
+		switch b {
+		case C_PSAUTO, C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
+			return true
+		}
 
 	case C_NPAUTO:
 		return cmp(C_NSAUTO, b)
 
 	case C_LAUTO:
-		return cmp(C_NPAUTO, b) || cmp(C_UAUTO64K, b)
+		switch b {
+		case C_PSAUTO, C_PPAUTO,
+			C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8,
+			C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8,
+			C_UAUTO16K, C_UAUTO16K_8,
+			C_UAUTO32K:
+			return true
+		}
+		return cmp(C_NPAUTO, b)
 
 	case C_PSOREG:
 		if b == C_ZOREG {
@@ -1375,27 +1430,42 @@ func cmp(a int, b int) bool {
 		}
 
 	case C_UOREG4K:
-		if b == C_ZOREG || b == C_PSAUTO || b == C_PSOREG || b == C_PPAUTO || b == C_PPOREG {
+		switch b {
+		case C_ZOREG, C_PSOREG, C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
 			return true
 		}
 
 	case C_UOREG8K:
-		return cmp(C_UOREG4K, b)
+		switch b {
+		case C_ZOREG, C_PSOREG, C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4, C_UOREG8K_8:
+			return true
+		}
 
 	case C_UOREG16K:
-		return cmp(C_UOREG8K, b)
+		switch b {
+		case C_ZOREG, C_PSOREG, C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4, C_UOREG8K_8, C_UOREG16K_8:
+			return true
+		}
 
 	case C_UOREG32K:
-		return cmp(C_UOREG16K, b)
-
-	case C_UOREG64K:
-		return cmp(C_UOREG32K, b)
+		switch b {
+		case C_ZOREG, C_PSOREG, C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
+			return true
+		}
 
 	case C_NPOREG:
 		return cmp(C_NSOREG, b)
 
 	case C_LOREG:
-		return cmp(C_NPOREG, b) || cmp(C_UOREG64K, b)
+		switch b {
+		case C_ZOREG, C_PSOREG, C_PPOREG,
+			C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
+			C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8,
+			C_UOREG16K, C_UOREG16K_8,
+			C_UOREG32K:
+			return true
+		}
+		return cmp(C_NPOREG, b)
 
 	case C_LBRA:
 		if b == C_SBRA {
@@ -1442,6 +1512,13 @@ func oprangeset(a obj.As, t []Optab) {
 }
 
 func buildop(ctxt *obj.Link) {
+	if oprange[AAND&obj.AMask] != nil {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
 	var n int
 	for i := 0; i < C_GOK; i++ {
 		for n = 0; n < C_GOK; n++ {
@@ -1875,7 +1952,6 @@ func buildop(ctxt *obj.Link) {
 
 		case obj.ANOP,
 			obj.AUNDEF,
-			obj.AUSEFIELD,
 			obj.AFUNCDATA,
 			obj.APCDATA,
 			obj.ADUFFZERO,
@@ -1885,7 +1961,7 @@ func buildop(ctxt *obj.Link) {
 	}
 }
 
-func chipfloat7(ctxt *obj.Link, e float64) int {
+func (c *ctxt7) chipfloat7(e float64) int {
 	ei := math.Float64bits(e)
 	l := uint32(int32(ei))
 	h := uint32(int32(ei >> 32))
@@ -1925,7 +2001,7 @@ func SYSARG4(op1 int, Cn int, Cm int, op2 int) int {
 	return SYSARG5(0, op1, Cn, Cm, op2)
 }
 
-func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
 	o1 := uint32(0)
 	o2 := uint32(0)
 	o3 := uint32(0)
@@ -1936,14 +2012,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	}
 	switch o.type_ {
 	default:
-		ctxt.Diag("unknown asm %d", o.type_)
-		prasm(p)
+		c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
 
 	case 0: /* pseudo ops */
 		break
 
 	case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1957,12 +2032,12 @@ 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, p.As)
+		o1 = c.opirr(p, p.As)
 
 		rt := int(p.To.Reg)
 		if p.To.Type == obj.TYPE_NONE {
 			if (o1 & Sbit) == 0 {
-				ctxt.Diag("ineffective ZR destination\n%v", p)
+				c.ctxt.Diag("ineffective ZR destination\n%v", p)
 			}
 			rt = REGZERO
 		}
@@ -1971,11 +2046,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = rt
 		}
-		v := int32(regoff(ctxt, &p.From))
-		o1 = oaddi(ctxt, int32(o1), v, r, rt)
+		v := int32(c.regoff(&p.From))
+		o1 = c.oaddi(p, int32(o1), v, r, rt)
 
 	case 3: /* op R<<n[,R],R (shifted register) */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
 		rt := int(p.To.Reg)
@@ -1991,7 +2066,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, p.As)
+		o1 = c.opirr(p, p.As)
 
 		rt := int(p.To.Reg)
 		r := int(o.param)
@@ -2003,7 +2078,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = REGSP
 		}
-		v := int32(regoff(ctxt, &p.From))
+		v := int32(c.regoff(&p.From))
 		if (v & 0xFFF000) != 0 {
 			v >>= 12
 			o1 |= 1 << 22 /* shift, by 12 */
@@ -2012,33 +2087,33 @@ 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, p.As)
+		o1 = c.opbra(p, p.As)
 
 		if p.To.Sym == nil {
-			o1 |= uint32(brdist(ctxt, p, 0, 26, 2))
+			o1 |= uint32(c.brdist(p, 0, 26, 2))
 			break
 		}
 
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
-		rel.Type = obj.R_CALLARM64
+		rel.Type = objabi.R_CALLARM64
 
 	case 6: /* b ,O(R); bl ,O(R) */
-		o1 = opbrr(ctxt, p.As)
+		o1 = c.opbrr(p, p.As)
 
 		o1 |= uint32(p.To.Reg&31) << 5
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 0
-		rel.Type = obj.R_CALLIND
+		rel.Type = objabi.R_CALLIND
 
 	case 7: /* beq s */
-		o1 = opbra(ctxt, p.As)
+		o1 = c.opbra(p, p.As)
 
-		o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5)
+		o1 |= uint32(c.brdist(p, 0, 19, 2) << 5)
 
 	case 8: /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */
 		rt := int(p.To.Reg)
@@ -2050,36 +2125,36 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		v := int32(p.From.Offset)
 		switch p.As {
 		case AASR:
-			o1 = opbfm(ctxt, ASBFM, int(v), 63, rf, rt)
+			o1 = c.opbfm(p, ASBFM, int(v), 63, rf, rt)
 
 		case AASRW:
-			o1 = opbfm(ctxt, ASBFMW, int(v), 31, rf, rt)
+			o1 = c.opbfm(p, ASBFMW, int(v), 31, rf, rt)
 
 		case ALSL:
-			o1 = opbfm(ctxt, AUBFM, int((64-v)&63), int(63-v), rf, rt)
+			o1 = c.opbfm(p, AUBFM, int((64-v)&63), int(63-v), rf, rt)
 
 		case ALSLW:
-			o1 = opbfm(ctxt, AUBFMW, int((32-v)&31), int(31-v), rf, rt)
+			o1 = c.opbfm(p, AUBFMW, int((32-v)&31), int(31-v), rf, rt)
 
 		case ALSR:
-			o1 = opbfm(ctxt, AUBFM, int(v), 63, rf, rt)
+			o1 = c.opbfm(p, AUBFM, int(v), 63, rf, rt)
 
 		case ALSRW:
-			o1 = opbfm(ctxt, AUBFMW, int(v), 31, rf, rt)
+			o1 = c.opbfm(p, AUBFMW, int(v), 31, rf, rt)
 
 		case AROR:
-			o1 = opextr(ctxt, AEXTR, v, rf, rf, rt)
+			o1 = c.opextr(p, AEXTR, v, rf, rf, rt)
 
 		case ARORW:
-			o1 = opextr(ctxt, AEXTRW, v, rf, rf, rt)
+			o1 = c.opextr(p, AEXTRW, v, rf, rf, rt)
 
 		default:
-			ctxt.Diag("bad shift $con\n%v", ctxt.Curp)
+			c.ctxt.Diag("bad shift $con\n%v", p)
 			break
 		}
 
 	case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		r := int(p.Reg)
 		if r == 0 {
@@ -2088,33 +2163,33 @@ 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, p.As)
+		o1 = c.opimm(p, p.As)
 
 		if p.To.Type != obj.TYPE_NONE {
 			o1 |= uint32((p.To.Offset & 0xffff) << 5)
 		}
 
 	case 11: /* dword */
-		aclass(ctxt, &p.To)
+		c.aclass(&p.To)
 
-		o1 = uint32(ctxt.Instoffset)
-		o2 = uint32(ctxt.Instoffset >> 32)
+		o1 = uint32(c.instoffset)
+		o2 = uint32(c.instoffset >> 32)
 		if p.To.Sym != nil {
-			rel := obj.Addrel(ctxt.Cursym)
-			rel.Off = int32(ctxt.Pc)
+			rel := obj.Addrel(c.cursym)
+			rel.Off = int32(c.pc)
 			rel.Siz = 8
 			rel.Sym = p.To.Sym
 			rel.Add = p.To.Offset
-			rel.Type = obj.R_ADDR
+			rel.Type = objabi.R_ADDR
 			o2 = 0
 			o1 = o2
 		}
 
 	case 12: /* movT $vcon, reg */
-		o1 = omovlit(ctxt, p.As, p, &p.From, int(p.To.Reg))
+		o1 = c.omovlit(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)
+		o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
 
 		if !(o1 != 0) {
 			break
@@ -2128,11 +2203,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, p.As)
+			o2 = c.opxrrr(p, p.As)
 			o2 |= REGTMP & 31 << 16
 			o2 |= LSL0_64
 		} else {
-			o2 = oprrr(ctxt, p.As)
+			o2 = c.oprrr(p, p.As)
 			o2 |= REGTMP & 31 << 16 /* shift is 0 */
 		}
 
@@ -2140,25 +2215,25 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o2 |= uint32(rt & 31)
 
 	case 14: /* word */
-		if aclass(ctxt, &p.To) == C_ADDR {
-			ctxt.Diag("address constant needs DWORD\n%v", p)
+		if c.aclass(&p.To) == C_ADDR {
+			c.ctxt.Diag("address constant needs DWORD\n%v", p)
 		}
-		o1 = uint32(ctxt.Instoffset)
+		o1 = uint32(c.instoffset)
 		if p.To.Sym != nil {
 			// This case happens with words generated
 			// in the PC stream as part of the literal pool.
-			rel := obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(c.cursym)
 
-			rel.Off = int32(ctxt.Pc)
+			rel.Off = int32(c.pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
 			rel.Add = p.To.Offset
-			rel.Type = obj.R_ADDR
+			rel.Type = objabi.R_ADDR
 			o1 = 0
 		}
 
 	case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub Rm,Rn,Ra,Rd */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2181,7 +2256,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, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2190,12 +2265,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = rt
 		}
 		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | REGTMP&31
-		o2 = oprrr(ctxt, AMSUBW)
+		o2 = c.oprrr(p, AMSUBW)
 		o2 |= o1 & (1 << 31) /* same size */
 		o2 |= (uint32(rf&31) << 16) | (uint32(r&31) << 10) | (REGTMP & 31 << 5) | uint32(rt&31)
 
 	case 17: /* op Rm,[Rn],Rd; default Rn=ZR */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2209,9 +2284,15 @@ 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, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		cond := int(p.From.Reg)
+		if cond < COND_EQ || cond > COND_NV {
+			c.ctxt.Diag("invalid condition\n%v", p)
+		} else {
+			cond -= COND_EQ
+		}
+
 		r := int(p.Reg)
 		var rf int
 		if r != 0 {
@@ -2226,7 +2307,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else {
 			/* CSET */
 			if p.From3Type() != obj.TYPE_NONE {
-				ctxt.Diag("invalid combination\n%v", p)
+				c.ctxt.Diag("invalid combination\n%v", p)
 			}
 			rf = REGZERO
 			r = rf
@@ -2234,25 +2315,30 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 		rt := int(p.To.Reg)
-		o1 |= (uint32(rf&31) << 16) | (uint32(cond&31) << 12) | (uint32(r&31) << 5) | uint32(rt&31)
+		o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(r&31) << 5) | uint32(rt&31)
 
 	case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
 		nzcv := int(p.To.Offset)
 
 		cond := int(p.From.Reg)
+		if cond < COND_EQ || cond > COND_NV {
+			c.ctxt.Diag("invalid condition\n%v", p)
+		} else {
+			cond -= COND_EQ
+		}
 		var rf int
 		if p.From3.Type == obj.TYPE_REG {
-			o1 = oprrr(ctxt, p.As)
+			o1 = c.oprrr(p, p.As)
 			rf = int(p.From3.Reg) /* Rm */
 		} else {
-			o1 = opirr(ctxt, p.As)
+			o1 = c.opirr(p, p.As)
 			rf = int(p.From3.Offset & 0x1F)
 		}
 
-		o1 |= (uint32(rf&31) << 16) | (uint32(cond) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
+		o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
 
 	case 20: /* movT R,O(R) -> strT */
-		v := int32(regoff(ctxt, &p.To))
+		v := int32(c.regoff(&p.To))
 		sz := int32(1 << uint(movesize(p.As)))
 
 		r := int(p.To.Reg)
@@ -2260,14 +2346,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(o.param)
 		}
 		if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
-			o1 = olsr9s(ctxt, int32(opstr9(ctxt, p.As)), v, r, int(p.From.Reg))
+			o1 = c.olsr9s(p, int32(c.opstr9(p, p.As)), v, r, int(p.From.Reg))
 		} else {
-			v = int32(offsetshift(ctxt, int64(v), int(o.a3)))
-			o1 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), v, r, int(p.From.Reg))
+			v = int32(c.offsetshift(p, int64(v), int(o.a3)))
+			o1 = c.olsr12u(p, int32(c.opstr12(p, p.As)), v, r, int(p.From.Reg))
 		}
 
 	case 21: /* movT O(R),R -> ldrT */
-		v := int32(regoff(ctxt, &p.From))
+		v := int32(c.regoff(&p.From))
 		sz := int32(1 << uint(movesize(p.As)))
 
 		r := int(p.From.Reg)
@@ -2275,20 +2361,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(o.param)
 		}
 		if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
-			o1 = olsr9s(ctxt, int32(opldr9(ctxt, p.As)), v, r, int(p.To.Reg))
+			o1 = c.olsr9s(p, int32(c.opldr9(p, p.As)), v, r, int(p.To.Reg))
 		} else {
-			v = int32(offsetshift(ctxt, int64(v), int(o.a1)))
+			v = int32(c.offsetshift(p, int64(v), int(o.a1)))
 			//print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
-			o1 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), v, r, int(p.To.Reg))
+			o1 = c.olsr12u(p, int32(c.opldr12(p, p.As)), v, r, int(p.To.Reg))
 		}
 
 	case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
 		v := int32(p.From.Offset)
 
 		if v < -256 || v > 255 {
-			ctxt.Diag("offset out of range\n%v", p)
+			c.ctxt.Diag("offset out of range\n%v", p)
 		}
-		o1 = opldrpp(ctxt, p.As)
+		o1 = c.opldrpp(p, p.As)
 		if o.scond == C_XPOST {
 			o1 |= 1 << 10
 		} else {
@@ -2300,9 +2386,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		v := int32(p.To.Offset)
 
 		if v < -256 || v > 255 {
-			ctxt.Diag("offset out of range\n%v", p)
+			c.ctxt.Diag("offset out of range\n%v", p)
 		}
-		o1 = LD2STR(opldrpp(ctxt, p.As))
+		o1 = LD2STR(c.opldrpp(p, p.As))
 		if o.scond == C_XPOST {
 			o1 |= 1 << 10
 		} else {
@@ -2316,20 +2402,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		s := rf == REGSP || rt == REGSP
 		if p.As == AMVN || p.As == AMVNW {
 			if s {
-				ctxt.Diag("illegal SP reference\n%v", p)
+				c.ctxt.Diag("illegal SP reference\n%v", p)
 			}
-			o1 = oprrr(ctxt, p.As)
+			o1 = c.oprrr(p, p.As)
 			o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
 		} else if s {
-			o1 = opirr(ctxt, p.As)
+			o1 = c.opirr(p, p.As)
 			o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
 		} else {
-			o1 = oprrr(ctxt, p.As)
+			o1 = c.oprrr(p, 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, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		rf := int(p.From.Reg)
 		if rf == C_NONE {
@@ -2339,17 +2425,17 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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, p.As)
+		o1 = c.oprrr(p, 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, p.As)
+		o1 = c.opxrrr(p, p.As)
 
 		if (p.From.Reg-obj.RBaseARM64)&REG_EXT != 0 {
-			ctxt.Diag("extended register not implemented\n%v", p)
+			c.ctxt.Diag("extended register not implemented\n%v", p)
 			// o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
 		} else {
 			o1 |= uint32(p.From.Reg&31) << 16
@@ -2365,7 +2451,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(r&31) << 5) | uint32(rt&31)
 
 	case 28: /* logop $vcon, [R], R (64 bit literal) */
-		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+		o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
 
 		if !(o1 != 0) {
 			break
@@ -2374,14 +2460,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o2 = oprrr(ctxt, p.As)
+		o2 = c.oprrr(p, 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 */
-		fc := aclass(ctxt, &p.From)
-		tc := aclass(ctxt, &p.To)
+		fc := c.aclass(&p.From)
+		tc := c.aclass(&p.To)
 		if (p.As == AFMOVD || p.As == AFMOVS) && (fc == C_REG || fc == C_ZCON || tc == C_REG || tc == C_ZCON) {
 			// FMOV Rx, Fy or FMOV Fy, Rx
 			o1 = FPCVTI(0, 0, 0, 0, 6)
@@ -2392,82 +2478,116 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 				o1 |= 1 << 16 // FMOV Rx, Fy
 			}
 		} else {
-			o1 = oprrr(ctxt, p.As)
+			o1 = c.oprrr(p, p.As)
 		}
 		o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31)
 
 	case 30: /* movT R,L(R) -> strT */
+		// if offset L can be split into hi+lo, and both fit into instructions, do
+		//	add $hi, R, Rtmp
+		//	str R, lo(Rtmp)
+		// otherwise, use constant pool
+		//	mov $L, Rtmp (from constant pool)
+		//	str R, (R+Rtmp)
 		s := movesize(o.as)
-
 		if s < 0 {
-			ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
+			c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
 		}
-		v := int32(regoff(ctxt, &p.To))
-		if v < 0 {
-			ctxt.Diag("negative large offset\n%v", p)
+
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
 		}
-		if (v & ((1 << uint(s)) - 1)) != 0 {
-			ctxt.Diag("misaligned offset\n%v", p)
+
+		v := int32(c.regoff(&p.To))
+		var hi int32
+		if v < 0 || (v&((1<<uint(s))-1)) != 0 {
+			// negative or unaligned offset, use constant pool
+			goto storeusepool
 		}
-		hi := v - (v & (0xFFF << uint(s)))
-		if (hi & 0xFFF) != 0 {
-			ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+
+		hi = v - (v & (0xFFF << uint(s)))
+		if hi&0xFFF != 0 {
+			c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+		}
+		if hi&^0xFFF000 != 0 {
+			// hi doesn't fit into an ADD instruction
+			goto storeusepool
 		}
 
-		//fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
-		r := int(p.To.Reg)
+		o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
+		o2 = c.olsr12u(p, int32(c.opstr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
+		break
 
-		if r == 0 {
-			r = int(o.param)
+	storeusepool:
+		if r == REGTMP || p.From.Reg == REGTMP {
+			c.ctxt.Diag("REGTMP used in large offset store: %v", p)
 		}
-		o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP)
-		o2 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
+		o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
+		o2 = c.olsxrr(p, int32(c.opstrr(p, p.As)), int(p.From.Reg), r, REGTMP)
 
 	case 31: /* movT L(R), R -> ldrT */
+		// if offset L can be split into hi+lo, and both fit into instructions, do
+		//	add $hi, R, Rtmp
+		//	ldr lo(Rtmp), R
+		// otherwise, use constant pool
+		//	mov $L, Rtmp (from constant pool)
+		//	ldr (R+Rtmp), R
 		s := movesize(o.as)
-
 		if s < 0 {
-			ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
+			c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
 		}
-		v := int32(regoff(ctxt, &p.From))
-		if v < 0 {
-			ctxt.Diag("negative large offset\n%v", p)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
 		}
-		if (v & ((1 << uint(s)) - 1)) != 0 {
-			ctxt.Diag("misaligned offset\n%v", p)
+
+		v := int32(c.regoff(&p.From))
+		var hi int32
+		if v < 0 || (v&((1<<uint(s))-1)) != 0 {
+			// negative or unaligned offset, use constant pool
+			goto loadusepool
 		}
-		hi := v - (v & (0xFFF << uint(s)))
+
+		hi = v - (v & (0xFFF << uint(s)))
 		if (hi & 0xFFF) != 0 {
-			ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+			c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+		}
+		if hi&^0xFFF000 != 0 {
+			// hi doesn't fit into an ADD instruction
+			goto loadusepool
 		}
 
-		//fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
-		r := int(p.From.Reg)
+		o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
+		o2 = c.olsr12u(p, int32(c.opldr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
+		break
 
-		if r == 0 {
-			r = int(o.param)
+	loadusepool:
+		if r == REGTMP || p.From.Reg == REGTMP {
+			c.ctxt.Diag("REGTMP used in large offset load: %v", p)
 		}
-		o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP)
-		o2 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
+		o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
+		o2 = c.olsxrr(p, int32(c.opldrr(p, p.As)), int(p.To.Reg), r, REGTMP)
 
 	case 32: /* mov $con, R -> movz/movn */
-		o1 = omovconst(ctxt, p.As, p, &p.From, int(p.To.Reg))
+		o1 = c.omovconst(p.As, p, &p.From, int(p.To.Reg))
 
 	case 33: /* movk $uimm16 << pos */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		d := p.From.Offset
 		if (d >> 16) != 0 {
-			ctxt.Diag("requires uimm16\n%v", p)
+			c.ctxt.Diag("requires uimm16\n%v", p)
 		}
 		s := 0
 		if p.From3Type() != obj.TYPE_NONE {
 			if p.From3.Type != obj.TYPE_CONST {
-				ctxt.Diag("missing bit position\n%v", p)
+				c.ctxt.Diag("missing bit position\n%v", p)
 			}
 			s = int(p.From3.Offset / 16)
 			if (s*16&0xF) != 0 || s >= 4 || (o1&S64) == 0 && s >= 2 {
-				ctxt.Diag("illegal bit position\n%v", p)
+				c.ctxt.Diag("illegal bit position\n%v", p)
 			}
 		}
 
@@ -2475,12 +2595,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(((d & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
 
 	case 34: /* mov $lacon,R */
-		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+		o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
 
 		if !(o1 != 0) {
 			break
 		}
-		o2 = opxrrr(ctxt, AADD)
+		o2 = c.opxrrr(p, AADD)
 		o2 |= REGTMP & 31 << 16
 		o2 |= LSL0_64
 		r := int(p.From.Reg)
@@ -2491,30 +2611,30 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o2 |= uint32(p.To.Reg & 31)
 
 	case 35: /* mov SPR,R -> mrs */
-		o1 = oprrr(ctxt, AMRS)
+		o1 = c.oprrr(p, AMRS)
 
 		v := int32(p.From.Offset)
 		if (o1 & uint32(v&^(3<<19))) != 0 {
-			ctxt.Diag("MRS register value overlap\n%v", p)
+			c.ctxt.Diag("MRS register value overlap\n%v", p)
 		}
 		o1 |= uint32(v)
 		o1 |= uint32(p.To.Reg & 31)
 
 	case 36: /* mov R,SPR */
-		o1 = oprrr(ctxt, AMSR)
+		o1 = c.oprrr(p, AMSR)
 
 		v := int32(p.To.Offset)
 		if (o1 & uint32(v&^(3<<19))) != 0 {
-			ctxt.Diag("MSR register value overlap\n%v", p)
+			c.ctxt.Diag("MSR register value overlap\n%v", p)
 		}
 		o1 |= uint32(v)
 		o1 |= uint32(p.From.Reg & 31)
 
 	case 37: /* mov $con,PSTATEfield -> MSR [immediate] */
 		if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 {
-			ctxt.Diag("illegal immediate for PSTATE field\n%v", p)
+			c.ctxt.Diag("illegal immediate for PSTATE field\n%v", p)
 		}
-		o1 = opirr(ctxt, AMSR)
+		o1 = c.opirr(p, AMSR)
 		o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
 		v := int32(0)
 		for i := 0; i < len(pstatefield); i++ {
@@ -2525,12 +2645,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 		if v == 0 {
-			ctxt.Diag("illegal PSTATE field for immediate move\n%v", p)
+			c.ctxt.Diag("illegal PSTATE field for immediate move\n%v", p)
 		}
 		o1 |= uint32(v)
 
 	case 38: /* clrex [$imm] */
-		o1 = opimm(ctxt, p.As)
+		o1 = c.opimm(p, p.As)
 
 		if p.To.Type == obj.TYPE_NONE {
 			o1 |= 0xF << 8
@@ -2539,27 +2659,27 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 39: /* cbz R, rel */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		o1 |= uint32(p.From.Reg & 31)
-		o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5)
+		o1 |= uint32(c.brdist(p, 0, 19, 2) << 5)
 
 	case 40: /* tbz */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		v := int32(p.From.Offset)
 		if v < 0 || v > 63 {
-			ctxt.Diag("illegal bit number\n%v", p)
+			c.ctxt.Diag("illegal bit number\n%v", p)
 		}
 		o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19)
-		o1 |= uint32(brdist(ctxt, p, 0, 14, 2) << 5)
-		o1 |= uint32(p.Reg)
+		o1 |= uint32(c.brdist(p, 0, 14, 2) << 5)
+		o1 |= uint32(p.Reg & 31)
 
 	case 41: /* eret, nop, others with no operands */
-		o1 = op0(ctxt, p.As)
+		o1 = c.op0(p, p.As)
 
 	case 42: /* bfm R,r,s,R */
-		o1 = opbfm(ctxt, p.As, int(p.From.Offset), int(p.From3.Offset), int(p.Reg), int(p.To.Reg))
+		o1 = c.opbfm(p, 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)
@@ -2572,48 +2692,48 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		switch p.As {
 		case ABFI:
-			o1 = opbfm(ctxt, ABFM, 64-r, s-1, rf, rt)
+			o1 = c.opbfm(p, ABFM, 64-r, s-1, rf, rt)
 
 		case ABFIW:
-			o1 = opbfm(ctxt, ABFMW, 32-r, s-1, rf, rt)
+			o1 = c.opbfm(p, ABFMW, 32-r, s-1, rf, rt)
 
 		case ABFXIL:
-			o1 = opbfm(ctxt, ABFM, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, ABFM, r, r+s-1, rf, rt)
 
 		case ABFXILW:
-			o1 = opbfm(ctxt, ABFMW, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, ABFMW, r, r+s-1, rf, rt)
 
 		case ASBFIZ:
-			o1 = opbfm(ctxt, ASBFM, 64-r, s-1, rf, rt)
+			o1 = c.opbfm(p, ASBFM, 64-r, s-1, rf, rt)
 
 		case ASBFIZW:
-			o1 = opbfm(ctxt, ASBFMW, 32-r, s-1, rf, rt)
+			o1 = c.opbfm(p, ASBFMW, 32-r, s-1, rf, rt)
 
 		case ASBFX:
-			o1 = opbfm(ctxt, ASBFM, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, ASBFM, r, r+s-1, rf, rt)
 
 		case ASBFXW:
-			o1 = opbfm(ctxt, ASBFMW, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, ASBFMW, r, r+s-1, rf, rt)
 
 		case AUBFIZ:
-			o1 = opbfm(ctxt, AUBFM, 64-r, s-1, rf, rt)
+			o1 = c.opbfm(p, AUBFM, 64-r, s-1, rf, rt)
 
 		case AUBFIZW:
-			o1 = opbfm(ctxt, AUBFMW, 32-r, s-1, rf, rt)
+			o1 = c.opbfm(p, AUBFMW, 32-r, s-1, rf, rt)
 
 		case AUBFX:
-			o1 = opbfm(ctxt, AUBFM, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, AUBFM, r, r+s-1, rf, rt)
 
 		case AUBFXW:
-			o1 = opbfm(ctxt, AUBFMW, r, r+s-1, rf, rt)
+			o1 = c.opbfm(p, AUBFMW, r, r+s-1, rf, rt)
 
 		default:
-			ctxt.Diag("bad bfm alias\n%v", ctxt.Curp)
+			c.ctxt.Diag("bad bfm alias\n%v", p)
 			break
 		}
 
 	case 44: /* extr $b, Rn, Rm, Rd */
-		o1 = opextr(ctxt, p.As, int32(p.From.Offset), int(p.From3.Reg), int(p.Reg), int(p.To.Reg))
+		o1 = c.opextr(p, 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)
@@ -2625,78 +2745,54 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		switch as {
 		case AMOVB, ASXTB:
-			o1 = opbfm(ctxt, ASBFM, 0, 7, rf, rt)
+			o1 = c.opbfm(p, ASBFM, 0, 7, rf, rt)
 
 		case AMOVH, ASXTH:
-			o1 = opbfm(ctxt, ASBFM, 0, 15, rf, rt)
+			o1 = c.opbfm(p, ASBFM, 0, 15, rf, rt)
 
 		case AMOVW, ASXTW:
-			o1 = opbfm(ctxt, ASBFM, 0, 31, rf, rt)
+			o1 = c.opbfm(p, ASBFM, 0, 31, rf, rt)
 
 		case AMOVBU, AUXTB:
-			o1 = opbfm(ctxt, AUBFM, 0, 7, rf, rt)
+			o1 = c.opbfm(p, AUBFM, 0, 7, rf, rt)
 
 		case AMOVHU, AUXTH:
-			o1 = opbfm(ctxt, AUBFM, 0, 15, rf, rt)
+			o1 = c.opbfm(p, AUBFM, 0, 15, rf, rt)
 
 		case AMOVWU:
-			o1 = oprrr(ctxt, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
+			o1 = c.oprrr(p, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
 
 		case AUXTW:
-			o1 = opbfm(ctxt, AUBFM, 0, 31, rf, rt)
+			o1 = c.opbfm(p, AUBFM, 0, 31, rf, rt)
 
 		case ASXTBW:
-			o1 = opbfm(ctxt, ASBFMW, 0, 7, rf, rt)
+			o1 = c.opbfm(p, ASBFMW, 0, 7, rf, rt)
 
 		case ASXTHW:
-			o1 = opbfm(ctxt, ASBFMW, 0, 15, rf, rt)
+			o1 = c.opbfm(p, ASBFMW, 0, 15, rf, rt)
 
 		case AUXTBW:
-			o1 = opbfm(ctxt, AUBFMW, 0, 7, rf, rt)
+			o1 = c.opbfm(p, AUBFMW, 0, 7, rf, rt)
 
 		case AUXTHW:
-			o1 = opbfm(ctxt, AUBFMW, 0, 15, rf, rt)
+			o1 = c.opbfm(p, AUBFMW, 0, 15, rf, rt)
 
 		default:
-			ctxt.Diag("bad sxt %v", as)
+			c.ctxt.Diag("bad sxt %v", as)
 			break
 		}
 
 	case 46: /* cls */
-		o1 = opbit(ctxt, p.As)
+		o1 = c.opbit(p, p.As)
 
 		o1 |= uint32(p.From.Reg&31) << 5
 		o1 |= uint32(p.To.Reg & 31)
 
-	case 47: /* movT R,V(R) -> strT (huge offset) */
-		o1 = omovlit(ctxt, AMOVW, p, &p.To, REGTMP)
-
-		if !(o1 != 0) {
-			break
-		}
-		r := int(p.To.Reg)
-		if r == 0 {
-			r = int(o.param)
-		}
-		o2 = olsxrr(ctxt, p.As, REGTMP, r, int(p.From.Reg))
-
-	case 48: /* movT V(R), R -> ldrT (huge offset) */
-		o1 = omovlit(ctxt, AMOVW, p, &p.From, REGTMP)
-
-		if !(o1 != 0) {
-			break
-		}
-		r := int(p.From.Reg)
-		if r == 0 {
-			r = int(o.param)
-		}
-		o2 = olsxrr(ctxt, p.As, REGTMP, r, int(p.To.Reg))
-
 	case 50: /* sys/sysl */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 {
-			ctxt.Diag("illegal SYS argument\n%v", p)
+			c.ctxt.Diag("illegal SYS argument\n%v", p)
 		}
 		o1 |= uint32(p.From.Offset)
 		if p.To.Type == obj.TYPE_REG {
@@ -2708,14 +2804,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 51: /* dmb */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		if p.From.Type == obj.TYPE_CONST {
 			o1 |= uint32((p.From.Offset & 0xF) << 8)
 		}
 
 	case 52: /* hint */
-		o1 = opirr(ctxt, p.As)
+		o1 = c.opirr(p, p.As)
 
 		o1 |= uint32((p.From.Offset & 0x7F) << 5)
 
@@ -2737,17 +2833,17 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			v = ^v
 			mode = 32
 		}
-		o1 = opirr(ctxt, a)
+		o1 = c.opirr(p, a)
 		o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31)
 
 	case 54: /* floating point arith */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		var rf int
 		if p.From.Type == obj.TYPE_CONST {
-			rf = chipfloat7(ctxt, p.From.Val.(float64))
+			rf = c.chipfloat7(p.From.Val.(float64))
 			if rf < 0 || true {
-				ctxt.Diag("invalid floating-point immediate\n%v", p)
+				c.ctxt.Diag("invalid floating-point immediate\n%v", p)
 				rf = 0
 			}
 
@@ -2766,7 +2862,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, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		var rf int
 		if p.From.Type == obj.TYPE_CONST {
@@ -2779,23 +2875,29 @@ 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, p.As)
+		o1 = c.oprrr(p, p.As)
 
 		cond := int(p.From.Reg)
+		if cond < COND_EQ || cond > COND_NV {
+			c.ctxt.Diag("invalid condition\n%v", p)
+		} else {
+			cond -= COND_EQ
+		}
+
 		nzcv := int(p.To.Offset)
 		if nzcv&^0xF != 0 {
-			ctxt.Diag("implausible condition\n%v", p)
+			c.ctxt.Diag("implausible condition\n%v", p)
 		}
 		rf := int(p.Reg)
 		if p.From3 == nil || p.From3.Reg < REG_F0 || p.From3.Reg > REG_F31 {
-			ctxt.Diag("illegal FCCMP\n%v", p)
+			c.ctxt.Diag("illegal FCCMP\n%v", p)
 			break
 		}
 		rt := int(p.From3.Reg)
-		o1 |= uint32(rf&31)<<16 | uint32(cond)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
+		o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
 
 	case 58: /* ldar/ldxr/ldaxr */
-		o1 = opload(ctxt, p.As)
+		o1 = c.opload(p, p.As)
 
 		o1 |= 0x1F << 16
 		o1 |= uint32(p.From.Reg) << 5
@@ -2807,7 +2909,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, p.As)
+		o1 = c.opstore(p, p.As)
 
 		if p.RegTo2 != obj.REG_NONE {
 			o1 |= uint32(p.RegTo2&31) << 16
@@ -2821,20 +2923,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(p.From.Reg & 31)
 
 	case 60: /* adrp label,r */
-		d := brdist(ctxt, p, 12, 21, 0)
+		d := c.brdist(p, 12, 21, 0)
 
 		o1 = ADR(1, uint32(d), uint32(p.To.Reg))
 
 	case 61: /* adr label, r */
-		d := brdist(ctxt, p, 0, 21, 0)
+		d := c.brdist(p, 0, 21, 0)
 
 		o1 = ADR(0, uint32(d), uint32(p.To.Reg))
 
 	case 62: /* op $movcon, [R], R -> mov $movcon, REGTMP + op REGTMP, [R], R */
 		if p.Reg == REGTMP {
-			ctxt.Diag("cannot use REGTMP as source: %v\n", p)
+			c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
 		}
-		o1 = omovconst(ctxt, AMOVD, p, &p.From, REGTMP)
+		o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
 
 		rt := int(p.To.Reg)
 		if p.To.Type == obj.TYPE_NONE {
@@ -2845,11 +2947,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, p.As)
+			o2 = c.opxrrr(p, p.As)
 			o2 |= REGTMP & 31 << 16
 			o2 |= LSL0_64
 		} else {
-			o2 = oprrr(ctxt, p.As)
+			o2 = c.oprrr(p, p.As)
 			o2 |= REGTMP & 31 << 16 /* shift is 0 */
 		}
 		o2 |= uint32(r&31) << 5
@@ -2858,31 +2960,31 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		/* reloc ops */
 	case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
 		o1 = ADR(1, 0, REGTMP)
-		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
-		rel.Type = obj.R_ADDRARM64
-		o3 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), 0, REGTMP, int(p.From.Reg))
+		rel.Type = objabi.R_ADDRARM64
+		o3 = c.olsr12u(p, int32(c.opstr12(p, p.As)), 0, REGTMP, int(p.From.Reg))
 
 	case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
 		o1 = ADR(1, 0, REGTMP)
-		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRARM64
-		o3 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), 0, REGTMP, int(p.To.Reg))
+		rel.Type = objabi.R_ADDRARM64
+		o3 = c.olsr12u(p, int32(c.opldr12(p, p.As)), 0, REGTMP, int(p.To.Reg))
 
 	case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
 		v := int32(p.From.Offset)
 
 		if v < -512 || v > 504 {
-			ctxt.Diag("offset out of range\n%v", p)
+			c.ctxt.Diag("offset out of range\n%v", p)
 		}
 		if o.scond == C_XPOST {
 			o1 |= 1 << 23
@@ -2896,7 +2998,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		v := int32(p.To.Offset)
 
 		if v < -512 || v > 504 {
-			ctxt.Diag("offset out of range\n%v", p)
+			c.ctxt.Diag("offset out of range\n%v", p)
 		}
 		if o.scond == C_XPOST {
 			o1 |= 1 << 23
@@ -2907,51 +3009,51 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
 		if p.As == AMOVW {
-			ctxt.Diag("invalid load of 32-bit address: %v", p)
+			c.ctxt.Diag("invalid load of 32-bit address: %v", p)
 		}
 		o1 = ADR(1, 0, uint32(p.To.Reg))
-		o2 = opirr(ctxt, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		o2 = c.opirr(p, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRARM64
+		rel.Type = objabi.R_ADDRARM64
 
 	case 69: /* LE model movd $tlsvar, reg -> movz reg, 0 + reloc */
-		o1 = opirr(ctxt, AMOVZ)
+		o1 = c.opirr(p, AMOVZ)
 		o1 |= uint32(p.To.Reg & 31)
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_ARM64_TLS_LE
+		rel.Type = objabi.R_ARM64_TLS_LE
 		if p.From.Offset != 0 {
-			ctxt.Diag("invalid offset on MOVW $tlsvar")
+			c.ctxt.Diag("invalid offset on MOVW $tlsvar")
 		}
 
 	case 70: /* IE model movd $tlsvar, reg -> adrp REGTMP, 0; ldr reg, [REGTMP, #0] + relocs */
 		o1 = ADR(1, 0, REGTMP)
-		o2 = olsr12u(ctxt, int32(opldr12(ctxt, AMOVD)), 0, REGTMP, int(p.To.Reg))
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
 		rel.Add = 0
-		rel.Type = obj.R_ARM64_TLS_IE
+		rel.Type = objabi.R_ARM64_TLS_IE
 		if p.From.Offset != 0 {
-			ctxt.Diag("invalid offset on MOVW $tlsvar")
+			c.ctxt.Diag("invalid offset on MOVW $tlsvar")
 		}
 
 	case 71: /* movd sym at GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */
 		o1 = ADR(1, 0, REGTMP)
-		o2 = olsr12u(ctxt, int32(opldr12(ctxt, AMOVD)), 0, REGTMP, int(p.To.Reg))
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
 		rel.Add = 0
-		rel.Type = obj.R_ARM64_GOTPCREL
+		rel.Type = objabi.R_ARM64_GOTPCREL
 
 	// This is supposed to be something that stops execution.
 	// It's not supposed to be reached, ever, but if it is, we'd
@@ -2977,7 +3079,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 obj.As) uint32 {
+func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case AADC:
 		return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
@@ -3491,8 +3593,7 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 		return FPOP1S(0, 0, 3, 5)
 	}
 
-	ctxt.Diag("bad rrr %d %v", a, a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad rrr %d %v", p, a, a)
 	return 0
 }
 
@@ -3500,7 +3601,7 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
  * imm -> Rd
  * imm op Rn -> Rd
  */
-func opirr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opirr(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	/* op $addcon, Rn, Rd */
 	case AMOVD, AADD:
@@ -3678,12 +3779,11 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
 		return SYSOP(0, 0, 3, 2, 0, 0, 0x1F)
 	}
 
-	ctxt.Diag("bad irr %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad irr %v", p, a)
 	return 0
 }
 
-func opbit(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ACLS:
 		return S64 | OPBIT(5)
@@ -3719,7 +3819,7 @@ func opbit(ctxt *obj.Link, a obj.As) uint32 {
 		return S64 | OPBIT(2)
 
 	default:
-		ctxt.Diag("bad bit op\n%v", ctxt.Curp)
+		c.ctxt.Diag("bad bit op\n%v", p)
 		return 0
 	}
 }
@@ -3727,7 +3827,7 @@ func opbit(ctxt *obj.Link, a obj.As) uint32 {
 /*
  * add/subtract extended register
  */
-func opxrrr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
@@ -3754,11 +3854,11 @@ func opxrrr(ctxt *obj.Link, a obj.As) uint32 {
 		return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
 	}
 
-	ctxt.Diag("bad opxrrr %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opxrrr %v\n%v", a, p)
 	return 0
 }
 
-func opimm(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opimm(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ASVC:
 		return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */
@@ -3788,23 +3888,22 @@ func opimm(ctxt *obj.Link, a obj.As) uint32 {
 		return SYSOP(0, 0, 3, 3, 0, 2, 0x1F)
 	}
 
-	ctxt.Diag("bad imm %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad imm %v", p, a)
 	return 0
 }
 
-func brdist(ctxt *obj.Link, p *obj.Prog, preshift int, flen int, shift int) int64 {
+func (c *ctxt7) brdist(p *obj.Prog, preshift int, flen int, shift int) int64 {
 	v := int64(0)
 	t := int64(0)
 	if p.Pcond != nil {
-		v = (p.Pcond.Pc >> uint(preshift)) - (ctxt.Pc >> uint(preshift))
+		v = (p.Pcond.Pc >> uint(preshift)) - (c.pc >> uint(preshift))
 		if (v & ((1 << uint(shift)) - 1)) != 0 {
-			ctxt.Diag("misaligned label\n%v", p)
+			c.ctxt.Diag("misaligned label\n%v", p)
 		}
 		v >>= uint(shift)
 		t = int64(1) << uint(flen-1)
 		if v < -t || v >= t {
-			ctxt.Diag("branch too far %#x vs %#x [%p]\n%v\n%v", v, t, ctxt.Blitrl, p, p.Pcond)
+			c.ctxt.Diag("branch too far %#x vs %#x [%p]\n%v\n%v", v, t, c.blitrl, p, p.Pcond)
 			panic("branch too far")
 		}
 	}
@@ -3815,7 +3914,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 obj.As) uint32 {
+func (c *ctxt7) opbra(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ABEQ:
 		return OPBcc(0x0)
@@ -3872,12 +3971,11 @@ func opbra(ctxt *obj.Link, a obj.As) uint32 {
 		return 1<<31 | 5<<26
 	}
 
-	ctxt.Diag("bad bra %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad bra %v", p, a)
 	return 0
 }
 
-func opbrr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opbrr(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ABL:
 		return OPBLR(1) /* BLR */
@@ -3889,12 +3987,11 @@ func opbrr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPBLR(2) /* RET */
 	}
 
-	ctxt.Diag("bad brr %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad brr %v", p, a)
 	return 0
 }
 
-func op0(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) op0(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ADRPS:
 		return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5
@@ -3921,15 +4018,14 @@ func op0(ctxt *obj.Link, a obj.As) uint32 {
 		return SYSHINT(5)
 	}
 
-	ctxt.Diag("bad op0 %v", a)
-	prasm(ctxt.Curp)
+	c.ctxt.Diag("%v: bad op0 %v", p, a)
 	return 0
 }
 
 /*
  * register offset
  */
-func opload(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opload(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ALDAR:
 		return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10
@@ -3986,11 +4082,11 @@ func opload(ctxt *obj.Link, a obj.As) uint32 {
 		return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
 	}
 
-	ctxt.Diag("bad opload %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opload %v\n%v", a, p)
 	return 0
 }
 
-func opstore(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opstore(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case ASTLR:
 		return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10
@@ -4053,7 +4149,7 @@ func opstore(ctxt *obj.Link, a obj.As) uint32 {
 		return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
 	}
 
-	ctxt.Diag("bad opstore %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opstore %v\n%v", a, p)
 	return 0
 }
 
@@ -4061,9 +4157,9 @@ func opstore(ctxt *obj.Link, a obj.As) uint32 {
  * load/store register (unsigned immediate) C3.3.13
  *	these produce 64-bit values (when there's an option)
  */
-func olsr12u(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
+func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
 	if v < 0 || v >= (1<<12) {
-		ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp)
+		c.ctxt.Diag("offset out of range: %d\n%v", v, p)
 	}
 	o |= (v & 0xFFF) << 10
 	o |= int32(b&31) << 5
@@ -4071,7 +4167,7 @@ func olsr12u(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
 	return uint32(o)
 }
 
-func opldr12(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opldr12(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */
@@ -4101,20 +4197,20 @@ func opldr12(ctxt *obj.Link, a obj.As) uint32 {
 		return LDSTR12U(3, 1, 1)
 	}
 
-	ctxt.Diag("bad opldr12 %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opldr12 %v\n%v", a, p)
 	return 0
 }
 
-func opstr12(ctxt *obj.Link, a obj.As) uint32 {
-	return LD2STR(opldr12(ctxt, a))
+func (c *ctxt7) opstr12(p *obj.Prog, a obj.As) uint32 {
+	return LD2STR(c.opldr12(p, a))
 }
 
 /*
  * load/store register (unscaled immediate) C3.3.12
  */
-func olsr9s(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
+func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
 	if v < -256 || v > 255 {
-		ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp)
+		c.ctxt.Diag("offset out of range: %d\n%v", v, p)
 	}
 	o |= (v & 0x1FF) << 12
 	o |= int32(b&31) << 5
@@ -4122,7 +4218,7 @@ func olsr9s(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
 	return uint32(o)
 }
 
-func opldr9(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opldr9(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
@@ -4152,15 +4248,15 @@ func opldr9(ctxt *obj.Link, a obj.As) uint32 {
 		return LDSTR9S(3, 1, 1)
 	}
 
-	ctxt.Diag("bad opldr9 %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opldr9 %v\n%v", a, p)
 	return 0
 }
 
-func opstr9(ctxt *obj.Link, a obj.As) uint32 {
-	return LD2STR(opldr9(ctxt, a))
+func (c *ctxt7) opstr9(p *obj.Prog, a obj.As) uint32 {
+	return LD2STR(c.opldr9(p, a))
 }
 
-func opldrpp(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt7) opldrpp(p *obj.Prog, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */
@@ -4184,22 +4280,71 @@ func opldrpp(ctxt *obj.Link, a obj.As) uint32 {
 		return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
 	}
 
-	ctxt.Diag("bad opldr %v\n%v", a, ctxt.Curp)
+	c.ctxt.Diag("bad opldr %v\n%v", a, p)
 	return 0
 }
 
-/*
- * load/store register (extended register)
- */
-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
+// olsxrr attaches register operands to a load/store opcode supplied in o.
+// The result either encodes a load of r from (r1+r2) or a store of r to (r1+r2).
+func (c *ctxt7) olsxrr(p *obj.Prog, o int32, r int, r1 int, r2 int) uint32 {
+	o |= int32(r1&31) << 5
+	o |= int32(r2&31) << 16
+	o |= int32(r & 31)
+	return uint32(o)
+}
+
+// opldrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
+// for load instruction with register offset.
+func (c *ctxt7) opldrr(p *obj.Prog, a obj.As) uint32 {
+	switch a {
+	case AMOVD:
+		return 0x1a<<10 | 0x3<<21 | 0x1f<<27
+	case AMOVW:
+		return 0x1a<<10 | 0x5<<21 | 0x17<<27
+	case AMOVWU:
+		return 0x1a<<10 | 0x3<<21 | 0x17<<27
+	case AMOVH:
+		return 0x1a<<10 | 0x5<<21 | 0x0f<<27
+	case AMOVHU:
+		return 0x1a<<10 | 0x3<<21 | 0x0f<<27
+	case AMOVB:
+		return 0x1a<<10 | 0x5<<21 | 0x07<<27
+	case AMOVBU:
+		return 0x1a<<10 | 0x3<<21 | 0x07<<27
+	case AFMOVS:
+		return 0x1a<<10 | 0x3<<21 | 0x17<<27 | 1<<26
+	case AFMOVD:
+		return 0x1a<<10 | 0x3<<21 | 0x1f<<27 | 1<<26
+	}
+	c.ctxt.Diag("bad opldrr %v\n%v", a, p)
+	return 0
+}
+
+// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
+// for store instruction with register offset.
+func (c *ctxt7) opstrr(p *obj.Prog, a obj.As) uint32 {
+	switch a {
+	case AMOVD:
+		return 0x1a<<10 | 0x1<<21 | 0x1f<<27
+	case AMOVW, AMOVWU:
+		return 0x1a<<10 | 0x1<<21 | 0x17<<27
+	case AMOVH, AMOVHU:
+		return 0x1a<<10 | 0x1<<21 | 0x0f<<27
+	case AMOVB, AMOVBU:
+		return 0x1a<<10 | 0x1<<21 | 0x07<<27
+	case AFMOVS:
+		return 0x1a<<10 | 0x1<<21 | 0x17<<27 | 1<<26
+	case AFMOVD:
+		return 0x1a<<10 | 0x1<<21 | 0x1f<<27 | 1<<26
+	}
+	c.ctxt.Diag("bad opstrr %v\n%v", a, p)
+	return 0
 }
 
-func oaddi(ctxt *obj.Link, o1 int32, v int32, r int, rt int) uint32 {
+func (c *ctxt7) oaddi(p *obj.Prog, o1 int32, v int32, r int, rt int) uint32 {
 	if (v & 0xFFF000) != 0 {
 		if v&0xFFF != 0 {
-			ctxt.Diag("%v misuses oaddi", ctxt.Curp)
+			c.ctxt.Diag("%v misuses oaddi", p)
 		}
 		v >>= 12
 		o1 |= 1 << 22
@@ -4212,16 +4357,16 @@ 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 obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
+func (c *ctxt7) omovlit(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)
-		ctxt.Logf("omovlit add %d (%#x)\n", ctxt.Instoffset, uint64(ctxt.Instoffset))
+		c.aclass(a)
+		c.ctxt.Logf("omovlit add %d (%#x)\n", c.instoffset, uint64(c.instoffset))
 
 		/* TODO: could be clever, and use general constant builder */
-		o1 = int32(opirr(ctxt, AADD))
+		o1 = int32(c.opirr(p, AADD))
 
-		v := int32(ctxt.Instoffset)
+		v := int32(c.instoffset)
 		if v != 0 && (v&0xFFF) == 0 {
 			v >>= 12
 			o1 |= 1 << 22 /* shift, by 12 */
@@ -4251,7 +4396,7 @@ func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32
 			break
 		}
 
-		v := int32(brdist(ctxt, p, 0, 19, 2))
+		v := int32(c.brdist(p, 0, 19, 2))
 		o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27)
 		o1 |= (v & 0x7FFFF) << 5
 		o1 |= int32(dr & 31)
@@ -4261,8 +4406,8 @@ func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32
 }
 
 // load a constant (MOVCON or BITCON) in a into rt
-func omovconst(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
-	if c := oclass(a); c == C_BITCON || c == C_ABCON || c == C_ABCON0 {
+func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
+	if cls := oclass(a); cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0 {
 		// or $bitcon, REGZERO, rt
 		mode := 64
 		var as1 obj.As
@@ -4273,7 +4418,7 @@ func omovconst(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1
 		case AMOVD:
 			as1 = AORR
 		}
-		o1 = opirr(ctxt, as1)
+		o1 = c.opirr(p, as1)
 		o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31)
 		return o1
 	}
@@ -4288,54 +4433,54 @@ func omovconst(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1
 		d = ^d
 		s = movcon(d)
 		if s < 0 || s >= r {
-			ctxt.Diag("impossible move wide: %#x\n%v", uint64(a.Offset), p)
+			c.ctxt.Diag("impossible move wide: %#x\n%v", uint64(a.Offset), p)
 		}
 		if as == AMOVD {
-			o1 = opirr(ctxt, AMOVN)
+			o1 = c.opirr(p, AMOVN)
 		} else {
-			o1 = opirr(ctxt, AMOVNW)
+			o1 = c.opirr(p, AMOVNW)
 		}
 	} else {
 		if as == AMOVD {
-			o1 = opirr(ctxt, AMOVZ)
+			o1 = c.opirr(p, AMOVZ)
 		} else {
-			o1 = opirr(ctxt, AMOVZW)
+			o1 = c.opirr(p, AMOVZW)
 		}
 	}
 	o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
 	return o1
 }
 
-func opbfm(ctxt *obj.Link, a obj.As, r int, s int, rf int, rt int) uint32 {
-	var c uint32
-	o := opirr(ctxt, a)
+func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
+	var b uint32
+	o := c.opirr(p, a)
 	if (o & (1 << 31)) == 0 {
-		c = 32
+		b = 32
 	} else {
-		c = 64
+		b = 64
 	}
-	if r < 0 || uint32(r) >= c {
-		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	if r < 0 || uint32(r) >= b {
+		c.ctxt.Diag("illegal bit number\n%v", p)
 	}
 	o |= (uint32(r) & 0x3F) << 16
-	if s < 0 || uint32(s) >= c {
-		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	if s < 0 || uint32(s) >= b {
+		c.ctxt.Diag("illegal bit number\n%v", p)
 	}
 	o |= (uint32(s) & 0x3F) << 10
 	o |= (uint32(rf&31) << 5) | uint32(rt&31)
 	return o
 }
 
-func opextr(ctxt *obj.Link, a obj.As, v int32, rn int, rm int, rt int) uint32 {
-	var c uint32
-	o := opirr(ctxt, a)
+func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) uint32 {
+	var b uint32
+	o := c.opirr(p, a)
 	if (o & (1 << 31)) != 0 {
-		c = 63
+		b = 63
 	} else {
-		c = 31
+		b = 31
 	}
-	if v < 0 || uint32(v) > c {
-		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	if v < 0 || uint32(v) > b {
+		c.ctxt.Diag("illegal bit number\n%v", p)
 	}
 	o |= uint32(v) << 10
 	o |= uint32(rn&31) << 5
diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go
index ad9ff09..65be486 100644
--- a/src/cmd/internal/obj/arm64/list7.go
+++ b/src/cmd/internal/obj/arm64/list7.go
@@ -55,11 +55,11 @@ var strcond = [16]string{
 }
 
 func init() {
-	obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, Rconv)
+	obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, rconv)
 	obj.RegisterOpcode(obj.ABaseARM64, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if r == REGG {
 		return "g"
 	}
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 3ea78cd..7aa0c8d 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -32,9 +32,8 @@ package arm64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
-	"fmt"
-	"log"
 	"math"
 )
 
@@ -49,26 +48,26 @@ var complements = []obj.As{
 	ACMNW: ACMPW,
 }
 
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
 	// MOV	g_stackguard(g), R1
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	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.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
+	if c.cursym.CFunc() {
+		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
 
 	q := (*obj.Prog)(nil)
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP < stackguard
 		//	MOV	SP, R2
 		//	CMP	stackguard, R2
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_REG
@@ -76,25 +75,25 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
 		p.Reg = REG_R2
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize < stackguard-StackSmall
-		//	SUB	$framesize, SP, R2
+		//	SUB	$(framesize-StackSmall), SP, R2
 		//	CMP	stackguard, R2
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ASUB
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(framesize)
+		p.From.Offset = int64(framesize) - objabi.StackSmall
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
@@ -111,41 +110,41 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		//	SUB	R1, R2
 		//	MOV	$(framesize+(StackGuard-StackSmall)), R3
 		//	CMP	R3, R2
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ACMP
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackPreempt
+		p.From.Offset = objabi.StackPreempt
 		p.Reg = REG_R1
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		q = p
 		p.As = ABEQ
 		p.To.Type = obj.TYPE_BRANCH
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AADD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ASUB
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
+		p.From.Offset = int64(framesize) + (objabi.StackGuard - objabi.StackSmall)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R3
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMP
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
@@ -153,32 +152,31 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// BLS	do-morestack
-	bls := obj.Appendp(ctxt, p)
+	bls := obj.Appendp(p, c.newprog)
 	bls.As = ABLS
 	bls.To.Type = obj.TYPE_BRANCH
 
 	var last *obj.Prog
-	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
 	}
 
 	// Now we are at the end of the function, but logically
 	// we are still in function prologue. We need to fix the
 	// SP data and PCDATA.
-	spfix := obj.Appendp(ctxt, last)
+	spfix := obj.Appendp(last, c.newprog)
 	spfix.As = obj.ANOP
 	spfix.Spadj = -framesize
 
-	pcdata := obj.Appendp(ctxt, spfix)
-	pcdata.Lineno = ctxt.Cursym.Text.Lineno
-	pcdata.Mode = ctxt.Cursym.Text.Mode
+	pcdata := obj.Appendp(spfix, c.newprog)
+	pcdata.Pos = c.cursym.Func.Text.Pos
 	pcdata.As = obj.APCDATA
 	pcdata.From.Type = obj.TYPE_CONST
-	pcdata.From.Offset = obj.PCDATA_StackMapIndex
+	pcdata.From.Offset = objabi.PCDATA_StackMapIndex
 	pcdata.To.Type = obj.TYPE_CONST
 	pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
 
 	// MOV	LR, R3
-	movlr := obj.Appendp(ctxt, pcdata)
+	movlr := obj.Appendp(pcdata, c.newprog)
 	movlr.As = AMOVD
 	movlr.From.Type = obj.TYPE_REG
 	movlr.From.Reg = REGLINK
@@ -191,7 +189,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 
 	debug := movlr
 	if false {
-		debug = obj.Appendp(ctxt, debug)
+		debug = obj.Appendp(debug, c.newprog)
 		debug.As = AMOVD
 		debug.From.Type = obj.TYPE_CONST
 		debug.From.Offset = int64(framesize)
@@ -200,23 +198,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// BL	runtime.morestack(SB)
-	call := obj.Appendp(ctxt, debug)
+	call := obj.Appendp(debug, c.newprog)
 	call.As = ABL
 	call.To.Type = obj.TYPE_BRANCH
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.CFunc():
+	case c.cursym.CFunc():
 		morestack = "runtime.morestackc"
-	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
+	case !c.cursym.Func.Text.From.Sym.NeedCtxt():
 		morestack = "runtime.morestack_noctxt"
 	}
-	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+	call.To.Sym = c.ctxt.Lookup(morestack)
 
 	// B	start
-	jmp := obj.Appendp(ctxt, call)
+	jmp := obj.Appendp(call, c.newprog)
 	jmp.As = AB
 	jmp.To.Type = obj.TYPE_BRANCH
-	jmp.Pcond = ctxt.Cursym.Text.Link
+	jmp.Pcond = c.cursym.Func.Text.Link
 	jmp.Spadj = +framesize
 
 	// placeholder for bls's jump target
@@ -226,7 +224,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	return bls
 }
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
+	c := ctxt7{ctxt: ctxt, newprog: newprog}
+
 	p.From.Class = 0
 	p.To.Class = 0
 
@@ -261,36 +261,27 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AFMOVS:
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			if i32 == 0 {
+			if math.Float32bits(f32) == 0 {
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REGZERO
 				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.Set(obj.AttrLocal, true)
+			p.From.Sym = c.ctxt.Float32Sym(f32)
 			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 {
+			f64 := p.From.Val.(float64)
+			if math.Float64bits(f64) == 0 {
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REGZERO
 				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.Set(obj.AttrLocal, true)
+			p.From.Sym = c.ctxt.Float64Sym(f64)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -327,13 +318,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 
-	if ctxt.Flag_dynlink {
-		rewriteToUseGot(ctxt, p)
+	if c.ctxt.Flag_dynlink {
+		c.rewriteToUseGot(p)
 	}
 }
 
 // Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
 	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
 		//     ADUFFxxx $offset
 		// becomes
@@ -342,9 +333,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		//     CALL REGTMP
 		var sym *obj.LSym
 		if p.As == obj.ADUFFZERO {
-			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+			sym = c.ctxt.Lookup("runtime.duffzero")
 		} else {
-			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+			sym = c.ctxt.Lookup("runtime.duffcopy")
 		}
 		offset := p.To.Offset
 		p.As = AMOVD
@@ -356,13 +347,13 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		p.To.Name = obj.NAME_NONE
 		p.To.Offset = 0
 		p.To.Sym = nil
-		p1 := obj.Appendp(ctxt, p)
+		p1 := obj.Appendp(p, c.newprog)
 		p1.As = AADD
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = offset
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = REGTMP
-		p2 := obj.Appendp(ctxt, p1)
+		p2 := obj.Appendp(p1, c.newprog)
 		p2.As = obj.ACALL
 		p2.To.Type = obj.TYPE_REG
 		p2.To.Reg = REGTMP
@@ -375,15 +366,15 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
 		// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
 		if p.As != AMOVD {
-			ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
 		}
 		if p.To.Type != obj.TYPE_REG {
-			ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
 		}
 		p.From.Type = obj.TYPE_MEM
 		p.From.Name = obj.NAME_GOTREF
 		if p.From.Offset != 0 {
-			q := obj.Appendp(ctxt, p)
+			q := obj.Appendp(p, c.newprog)
 			q.As = AADD
 			q.From.Type = obj.TYPE_CONST
 			q.From.Offset = p.From.Offset
@@ -392,7 +383,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 	if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
 	var source *obj.Addr
 	// MOVx sym, Ry becomes MOVD sym at GOT, REGTMP; MOVx (REGTMP), Ry
@@ -400,7 +391,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	// 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)
+			c.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() {
@@ -411,14 +402,14 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	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 {
+	if source.Sym.Type == objabi.STLSBSS {
 		return
 	}
 	if source.Type != obj.TYPE_MEM {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
-	p1 := obj.Appendp(ctxt, p)
-	p2 := obj.Appendp(ctxt, p1)
+	p1 := obj.Appendp(p, c.newprog)
+	p2 := obj.Appendp(p1, c.newprog)
 	p1.As = AMOVD
 	p1.From.Type = obj.TYPE_MEM
 	p1.From.Sym = source.Sym
@@ -443,204 +434,19 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	obj.Nopout(p)
 }
 
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
-	firstp := ctxt.NewProg()
-	lastp := firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func relinv(a obj.As) obj.As {
-	switch a {
-	case ABEQ:
-		return ABNE
-	case ABNE:
-		return ABEQ
-	case ABCS:
-		return ABCC
-	case ABHS:
-		return ABLO
-	case ABCC:
-		return ABCS
-	case ABLO:
-		return ABHS
-	case ABMI:
-		return ABPL
-	case ABPL:
-		return ABMI
-	case ABVS:
-		return ABVC
-	case ABVC:
-		return ABVS
-	case ABHI:
-		return ABLS
-	case ABLS:
-		return ABHI
-	case ABGE:
-		return ABLT
-	case ABLT:
-		return ABGE
-	case ABGT:
-		return ABLE
-	case ABLE:
-		return ABGT
-	case ACBZ:
-		return ACBNZ
-	case ACBNZ:
-		return ACBZ
-	case ACBZW:
-		return ACBNZW
-	case ACBNZW:
-		return ACBZW
-	}
-
-	log.Fatalf("unknown relation: %s", Anames[a-obj.ABaseARM64])
-	return 0
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
-	var q *obj.Prog
-	var r *obj.Prog
-	var i int
-
-loop:
-	if p == nil {
-		return
-	}
-	a := p.As
-	if a == AB {
-		q = p.Pcond
-		if q != nil {
-			p.Mark |= FOLL
-			p = q
-			if !(p.Mark&FOLL != 0) {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark&FOLL != 0 {
-		i = 0
-		q = p
-		for ; i < 4; i, q = i+1, q.Link {
-			if q == *last || q == nil {
-				break
-			}
-			a = q.As
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if a == AB || a == obj.ARET || a == AERET {
-				goto copy
-			}
-			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
-				continue
-			}
-			if a != ABEQ && a != ABNE {
-				continue
-			}
-
-		copy:
-			for {
-				r = ctxt.NewProg()
-				*r = *p
-				if !(r.Mark&FOLL != 0) {
-					fmt.Printf("can't happen 1\n")
-				}
-				r.Mark |= FOLL
-				if p != q {
-					p = p.Link
-					(*last).Link = r
-					*last = r
-					continue
-				}
-
-				(*last).Link = r
-				*last = r
-				if a == AB || a == obj.ARET || a == AERET {
-					return
-				}
-				if a == ABNE {
-					r.As = ABEQ
-				} else {
-					r.As = ABNE
-				}
-				r.Pcond = p.Link
-				r.Link = p.Pcond
-				if !(r.Link.Mark&FOLL != 0) {
-					xfol(ctxt, r.Link, last)
-				}
-				if !(r.Pcond.Mark&FOLL != 0) {
-					fmt.Printf("can't happen 2\n")
-				}
-				return
-			}
-		}
-
-		a = AB
-		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
-	if a == AB || a == obj.ARET || a == AERET {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
 		return
 	}
-	if p.Pcond != nil {
-		if a != ABL && p.Link != nil {
-			q = obj.Brchain(ctxt, p.Link)
-			if a != obj.ATEXT {
-				if q != nil && (q.Mark&FOLL != 0) {
-					p.As = relinv(a)
-					p.Link = p.Pcond
-					p.Pcond = q
-				}
-			}
-
-			xfol(ctxt, p.Link, last)
-			q = obj.Brchain(ctxt, p.Pcond)
-			if q == nil {
-				q = p.Pcond
-			}
-			if q.Mark&FOLL != 0 {
-				p.Pcond = q
-				return
-			}
-
-			p = q
-			goto loop
-		}
-	}
-
-	p = p.Link
-	goto loop
-}
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
-		return
-	}
+	c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
 
-	p := cursym.Text
+	p := c.cursym.Func.Text
 	textstksiz := p.To.Offset
 	aoffset := int32(textstksiz)
 
-	cursym.Args = p.To.Val.(int32)
-	cursym.Locals = int32(textstksiz)
+	c.cursym.Func.Args = p.To.Val.(int32)
+	c.cursym.Func.Locals = int32(textstksiz)
 
 	/*
 	 * find leaf subroutines
@@ -649,7 +455,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	 */
 	q := (*obj.Prog)(nil)
 	var q1 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
 		case obj.ATEXT:
 			p.Mark |= LEAF
@@ -666,7 +472,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		case ABL,
 			obj.ADUFFZERO,
 			obj.ADUFFCOPY:
-			cursym.Text.Mark &^= LEAF
+			c.cursym.Func.Text.Mark &^= LEAF
 			fallthrough
 
 		case ACBNZ,
@@ -711,19 +517,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 	var q2 *obj.Prog
 	var retjmp *obj.LSym
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		o := p.As
 		switch o {
 		case obj.ATEXT:
-			cursym.Text = p
+			c.cursym.Func.Text = p
 			if textstksiz < 0 {
-				ctxt.Autosize = 0
+				c.autosize = 0
 			} else {
-				ctxt.Autosize = int32(textstksiz + 8)
+				c.autosize = int32(textstksiz + 8)
 			}
-			if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 {
-				ctxt.Autosize = 0
-			} else if ctxt.Autosize&(16-1) != 0 {
+			if (c.cursym.Func.Text.Mark&LEAF != 0) && c.autosize <= 8 {
+				c.autosize = 0
+			} else if c.autosize&(16-1) != 0 {
 				// The frame includes an LR.
 				// If the frame size is 8, it's only an LR,
 				// so there's no potential for breaking references to
@@ -732,32 +538,32 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// But otherwise, if there is a non-empty locals section,
 				// the author of the code is responsible for making sure
 				// that the frame size is 8 mod 16.
-				if ctxt.Autosize == 8 {
-					ctxt.Autosize += 8
-					cursym.Locals += 8
+				if c.autosize == 8 {
+					c.autosize += 8
+					c.cursym.Func.Locals += 8
 				} else {
-					ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8)
+					c.ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, c.autosize-8)
 				}
 			}
-			p.To.Offset = int64(ctxt.Autosize) - 8
-			if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) {
-				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("save suppressed in: %s\n", cursym.Text.From.Sym.Name)
+			p.To.Offset = int64(c.autosize) - 8
+			if c.autosize == 0 && !(c.cursym.Func.Text.Mark&LEAF != 0) {
+				if c.ctxt.Debugvlog {
+					c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
 				}
-				cursym.Text.Mark |= LEAF
+				c.cursym.Func.Text.Mark |= LEAF
 			}
 
-			if !(p.From3.Offset&obj.NOSPLIT != 0) {
-				p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check
+			if !p.From.Sym.NoSplit() {
+				p = c.stacksplit(p, c.autosize) // emit split check
 			}
 
-			aoffset = ctxt.Autosize
+			aoffset = c.autosize
 			if aoffset > 0xF0 {
 				aoffset = 0xF0
 			}
-			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Set(obj.AttrLeaf, true)
-				if ctxt.Autosize == 0 {
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
+				c.cursym.Set(obj.AttrLeaf, true)
+				if c.autosize == 0 {
 					break
 				}
 			}
@@ -765,41 +571,41 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			// Frame is non-empty. Make sure to save link register, even if
 			// it is a leaf function, so that traceback works.
 			q = p
-			if ctxt.Autosize > aoffset {
+			if c.autosize > aoffset {
 				// Frame size is too large for a MOVD.W instruction.
 				// Store link register before decrementing SP, so if a signal comes
 				// during the execution of the function prologue, the traceback
 				// code will not see a half-updated stack frame.
-				q = obj.Appendp(ctxt, q)
-				q.Lineno = p.Lineno
+				q = obj.Appendp(q, c.newprog)
+				q.Pos = p.Pos
 				q.As = ASUB
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = int64(ctxt.Autosize)
+				q.From.Offset = int64(c.autosize)
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REGTMP
 
-				q = obj.Appendp(ctxt, q)
-				q.Lineno = p.Lineno
+				q = obj.Appendp(q, c.newprog)
+				q.Pos = p.Pos
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REGLINK
 				q.To.Type = obj.TYPE_MEM
 				q.To.Reg = REGTMP
 
-				q1 = obj.Appendp(ctxt, q)
-				q1.Lineno = p.Lineno
+				q1 = obj.Appendp(q, c.newprog)
+				q1.Pos = p.Pos
 				q1.As = AMOVD
 				q1.From.Type = obj.TYPE_REG
 				q1.From.Reg = REGTMP
 				q1.To.Type = obj.TYPE_REG
 				q1.To.Reg = REGSP
-				q1.Spadj = ctxt.Autosize
+				q1.Spadj = c.autosize
 			} else {
 				// small frame, update SP and save LR in a single MOVD.W instruction
-				q1 = obj.Appendp(ctxt, q)
+				q1 = obj.Appendp(q, c.newprog)
 				q1.As = AMOVD
-				q1.Lineno = p.Lineno
+				q1.Pos = p.Pos
 				q1.From.Type = obj.TYPE_REG
 				q1.From.Reg = REGLINK
 				q1.To.Type = obj.TYPE_MEM
@@ -809,7 +615,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q1.Spadj = aoffset
 			}
 
-			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+			if c.cursym.Func.Text.From.Sym.Wrapper() {
 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
 				//
 				//	MOV g_panic(g), R1
@@ -828,26 +634,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes.
 				q = q1
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				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(c.ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ACMP
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REGZERO
 				q.Reg = REG_R1
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ABEQ
 				q.To.Type = obj.TYPE_BRANCH
 				q1 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REG_R1
@@ -855,26 +661,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R2
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = int64(ctxt.Autosize) + 8
+				q.From.Offset = int64(c.autosize) + 8
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ACMP
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R2
 				q.Reg = REG_R3
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ABNE
 				q.To.Type = obj.TYPE_BRANCH
 				q2 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = 8
@@ -882,7 +688,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R4
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R4
@@ -890,7 +696,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Reg = REG_R1
 				q.To.Offset = 0 // Panic.argp
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 
 				q.As = obj.ANOP
 				q1.Pcond = q
@@ -900,24 +706,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		case obj.ARET:
 			nocache(p)
 			if p.From.Type == obj.TYPE_CONST {
-				ctxt.Diag("using BECOME (%v) is not supported!", p)
+				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
 				break
 			}
 
 			retjmp = p.To.Sym
 			p.To = obj.Addr{}
-			if cursym.Text.Mark&LEAF != 0 {
-				if ctxt.Autosize != 0 {
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
+				if c.autosize != 0 {
 					p.As = AADD
 					p.From.Type = obj.TYPE_CONST
-					p.From.Offset = int64(ctxt.Autosize)
+					p.From.Offset = int64(c.autosize)
 					p.To.Type = obj.TYPE_REG
 					p.To.Reg = REGSP
-					p.Spadj = -ctxt.Autosize
+					p.Spadj = -c.autosize
 				}
 			} else {
 				/* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
-				aoffset = ctxt.Autosize
+				aoffset = c.autosize
 
 				if aoffset > 0xF0 {
 					aoffset = 0xF0
@@ -930,24 +736,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REGLINK
 				p.Spadj = -aoffset
-				if ctxt.Autosize > aoffset {
-					q = ctxt.NewProg()
+				if c.autosize > aoffset {
+					q = newprog()
 					q.As = AADD
 					q.From.Type = obj.TYPE_CONST
-					q.From.Offset = int64(ctxt.Autosize) - int64(aoffset)
+					q.From.Offset = int64(c.autosize) - int64(aoffset)
 					q.To.Type = obj.TYPE_REG
 					q.To.Reg = REGSP
 					q.Link = p.Link
 					q.Spadj = int32(-q.From.Offset)
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					p.Link = q
 					p = q
 				}
 			}
 
 			if p.As != obj.ARET {
-				q = ctxt.NewProg()
-				q.Lineno = p.Lineno
+				q = newprog()
+				q.Pos = p.Pos
 				q.Link = p.Link
 				p.Link = q
 				p = q
@@ -957,7 +763,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.As = AB
 				p.To.Type = obj.TYPE_BRANCH
 				p.To.Sym = retjmp
-				p.Spadj = +ctxt.Autosize
+				p.Spadj = +c.autosize
 				break
 			}
 
@@ -965,7 +771,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Type = obj.TYPE_MEM
 			p.To.Offset = 0
 			p.To.Reg = REGLINK
-			p.Spadj = +ctxt.Autosize
+			p.Spadj = +c.autosize
 
 		case AADD, ASUB:
 			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
@@ -996,9 +802,9 @@ var unaryDst = map[obj.As]bool{
 
 var Linkarm64 = obj.LinkArch{
 	Arch:       sys.ArchARM64,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span7,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
diff --git a/src/cmd/internal/obj/bootstrap.go b/src/cmd/internal/obj/bootstrap.go
new file mode 100644
index 0000000..42835e1
--- /dev/null
+++ b/src/cmd/internal/obj/bootstrap.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.8
+
+package obj
+
+import (
+	"reflect"
+	"sort"
+)
+
+func SortSlice(slice interface{}, less func(i, j int) bool) {
+	val := reflect.ValueOf(slice)
+	tmp := reflect.New(val.Type().Elem()).Elem()
+	x := sliceByFn{val: val, tmp: tmp, less: less}
+	sort.Sort(x)
+}
+
+type sliceByFn struct {
+	val  reflect.Value
+	tmp  reflect.Value
+	less func(i, j int) bool
+}
+
+func (x sliceByFn) Len() int           { return x.val.Len() }
+func (x sliceByFn) Less(i, j int) bool { return x.less(i, j) }
+func (x sliceByFn) Swap(i, j int) {
+	a, b := x.val.Index(i), x.val.Index(j)
+	x.tmp.Set(a)
+	a.Set(b)
+	b.Set(x.tmp)
+}
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index d5565f2..23d1809 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -32,6 +32,7 @@
 package obj
 
 import (
+	"cmd/internal/objabi"
 	"log"
 	"math"
 )
@@ -70,10 +71,15 @@ func (s *LSym) GrowCap(c int64) {
 // 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)
+		ctxt.Diag("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
 	}
-	if s.Type == SBSS || s.Type == STLSBSS {
-		ctxt.Diag("cannot supply data for BSS var")
+	switch s.Type {
+	case objabi.Sxxx, objabi.SBSS:
+		s.Type = objabi.SDATA
+	case objabi.SNOPTRBSS:
+		s.Type = objabi.SNOPTRDATA
+	case objabi.STLSBSS:
+		ctxt.Diag("cannot supply data for %v var %v", s.Type, s.Name)
 	}
 	l := off + int64(siz)
 	s.Grow(l)
@@ -114,7 +120,8 @@ func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
 // 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 {
+	// Allow 4-byte addresses for DWARF.
+	if siz != ctxt.Arch.PtrSize && siz != 4 {
 		ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
 	}
 	s.prepwrite(ctxt, off, siz)
@@ -125,7 +132,7 @@ func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64)
 	}
 	r.Siz = uint8(siz)
 	r.Sym = rsym
-	r.Type = R_ADDR
+	r.Type = objabi.R_ADDR
 	r.Add = roff
 }
 
@@ -141,7 +148,7 @@ func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
 	}
 	r.Siz = 4
 	r.Sym = rsym
-	r.Type = R_ADDROFF
+	r.Type = objabi.R_ADDROFF
 	r.Add = roff
 }
 
@@ -157,7 +164,7 @@ func (s *LSym) WriteWeakOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
 	}
 	r.Siz = 4
 	r.Sym = rsym
-	r.Type = R_WEAKADDROFF
+	r.Type = objabi.R_WEAKADDROFF
 	r.Add = roff
 }
 
@@ -181,26 +188,3 @@ func Addrel(s *LSym) *Reloc {
 	s.R = append(s.R, Reloc{})
 	return &s.R[len(s.R)-1]
 }
-
-func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
-	if s.Type == 0 {
-		s.Type = SDATA
-	}
-	if s.Size < off+wid {
-		s.Size = off + wid
-		s.Grow(s.Size)
-	}
-
-	switch wid {
-	case 1:
-		s.P[off] = uint8(v)
-	case 2:
-		ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
-	case 4:
-		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
-	case 8:
-		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
-	}
-
-	return off + wid
-}
diff --git a/src/cmd/internal/obj/flag.go b/src/cmd/internal/obj/flag.go
deleted file mode 100644
index ff69fd9..0000000
--- a/src/cmd/internal/obj/flag.go
+++ /dev/null
@@ -1,115 +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 obj
-
-import (
-	"flag"
-	"fmt"
-	"os"
-	"strconv"
-)
-
-func Flagfn2(string, string, func(string, string)) { panic("flag") }
-
-func Flagcount(name, usage string, val *int) {
-	flag.Var((*count)(val), name, usage)
-}
-
-func Flagint32(name, usage string, val *int32) {
-	flag.Var((*int32Value)(val), name, usage)
-}
-
-func Flagint64(name, usage string, val *int64) {
-	flag.Int64Var(val, name, *val, usage)
-}
-
-func Flagstr(name, usage string, val *string) {
-	flag.StringVar(val, name, *val, usage)
-}
-
-func Flagfn0(name, usage string, f func()) {
-	flag.Var(fn0(f), name, usage)
-}
-
-func Flagfn1(name, usage string, f func(string)) {
-	flag.Var(fn1(f), name, usage)
-}
-
-func Flagprint(fd int) {
-	if fd == 1 {
-		flag.CommandLine.SetOutput(os.Stdout)
-	}
-	flag.PrintDefaults()
-}
-
-func Flagparse(usage func()) {
-	flag.Usage = usage
-	flag.Parse()
-}
-
-// count is a flag.Value that is like a flag.Bool and a flag.Int.
-// If used as -name, it increments the count, but -name=x sets the count.
-// Used for verbose flag -v.
-type count int
-
-func (c *count) String() string {
-	return fmt.Sprint(int(*c))
-}
-
-func (c *count) Set(s string) error {
-	switch s {
-	case "true":
-		*c++
-	case "false":
-		*c = 0
-	default:
-		n, err := strconv.Atoi(s)
-		if err != nil {
-			return fmt.Errorf("invalid count %q", s)
-		}
-		*c = count(n)
-	}
-	return nil
-}
-
-func (c *count) IsBoolFlag() bool {
-	return true
-}
-
-type int32Value int32
-
-func (i *int32Value) Set(s string) error {
-	v, err := strconv.ParseInt(s, 0, 64)
-	*i = int32Value(v)
-	return err
-}
-
-func (i *int32Value) Get() interface{} { return int32(*i) }
-
-func (i *int32Value) String() string { return fmt.Sprint(*i) }
-
-type fn0 func()
-
-func (f fn0) Set(s string) error {
-	f()
-	return nil
-}
-
-func (f fn0) Get() interface{} { return nil }
-
-func (f fn0) String() string { return "" }
-
-func (f fn0) IsBoolFlag() bool {
-	return true
-}
-
-type fn1 func(string)
-
-func (f fn1) Set(s string) error {
-	f(s)
-	return nil
-}
-
-func (f fn1) String() string { return "" }
diff --git a/src/cmd/internal/obj/funcdata.go b/src/cmd/internal/obj/funcdata.go
deleted file mode 100644
index 62256a3..0000000
--- a/src/cmd/internal/obj/funcdata.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package obj
-
-// This file defines the IDs for PCDATA and FUNCDATA instructions
-// in Go binaries. It is included by assembly sources, so it must
-// be written using #defines.
-//
-// The Go compiler also #includes this file, for now.
-//
-// symtab.go also contains a copy of these constants.
-
-// Pseudo-assembly statements.
-
-// GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros
-// that communicate to the runtime information about the location and liveness
-// of pointers in an assembly function's arguments, results, and stack frame.
-// This communication is only required in assembly functions that make calls
-// to other functions that might be preempted or grow the stack.
-// NOSPLIT functions that make no calls do not need to use these macros.
-
-// GO_ARGS indicates that the Go prototype for this assembly function
-// defines the pointer map for the function's arguments.
-// GO_ARGS should be the first instruction in a function that uses it.
-// It can be omitted if there are no arguments at all.
-// GO_ARGS is inserted implicitly by the linker for any function
-// that also has a Go prototype and therefore is usually not necessary
-// to write explicitly.
-
-// GO_RESULTS_INITIALIZED indicates that the assembly function
-// has initialized the stack space for its results and that those results
-// should be considered live for the remainder of the function.
-
-// NO_LOCAL_POINTERS indicates that the assembly function stores
-// no pointers to heap objects in its local stack variables.
-
-// ArgsSizeUnknown is set in Func.argsize to mark all functions
-// whose argument size is unknown (C vararg functions, and
-// assembly code without an explicit specification).
-// This value is generated by the compiler, assembler, or linker.
-const (
-	PCDATA_StackMapIndex       = 0
-	FUNCDATA_ArgsPointerMaps   = 0
-	FUNCDATA_LocalsPointerMaps = 1
-	ArgsSizeUnknown            = -0x80000000
-)
diff --git a/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go
index 732ce19..f0b2c46 100644
--- a/src/cmd/internal/obj/go.go
+++ b/src/cmd/internal/obj/go.go
@@ -4,67 +4,8 @@
 
 package obj
 
-import (
-	"fmt"
-	"os"
-	"strings"
-)
-
 // go-specific code shared across loaders (5l, 6l, 8l).
 
-var (
-	framepointer_enabled     int
-	Fieldtrack_enabled       int
-	Preemptibleloops_enabled int
-)
-
-// Toolchain experiments.
-// These are controlled by the GOEXPERIMENT environment
-// variable recorded when the toolchain is built.
-// This list is also known to cmd/gc.
-var exper = []struct {
-	name string
-	val  *int
-}{
-	{"fieldtrack", &Fieldtrack_enabled},
-	{"framepointer", &framepointer_enabled},
-	{"preemptibleloops", &Preemptibleloops_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 == name {
-			if exper[i].val != nil {
-				*exper[i].val = v
-			}
-			return
-		}
-	}
-
-	fmt.Printf("unknown experiment %s\n", s)
-	os.Exit(2)
-}
-
-func init() {
-	framepointer_enabled = 1 // default
-	for _, f := range strings.Split(goexperiment, ",") {
-		if f != "" {
-			addexp(f)
-		}
-	}
-}
-
-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
@@ -73,16 +14,3 @@ func Nopout(p *Prog) {
 	p.Reg = 0
 	p.To = Addr{}
 }
-
-func Expstring() string {
-	buf := "X"
-	for i := range exper {
-		if *exper[i].val != 0 {
-			buf += "," + exper[i].name
-		}
-	}
-	if buf == "X" {
-		buf += ",none"
-	}
-	return "X:" + buf[2:]
-}
diff --git a/src/cmd/internal/obj/inl.go b/src/cmd/internal/obj/inl.go
new file mode 100644
index 0000000..1169219
--- /dev/null
+++ b/src/cmd/internal/obj/inl.go
@@ -0,0 +1,85 @@
+// Copyright 2017 The Go Authors. 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 "cmd/internal/src"
+
+// InlTree s a collection of inlined calls. The Parent field of an
+// InlinedCall is the index of another InlinedCall in InlTree.
+//
+// The compiler maintains a global inlining tree and adds a node to it
+// every time a function is inlined. For example, suppose f() calls g()
+// and g has two calls to h(), and that f, g, and h are inlineable:
+//
+//  1 func main() {
+//  2     f()
+//  3 }
+//  4 func f() {
+//  5     g()
+//  6 }
+//  7 func g() {
+//  8     h()
+//  9     h()
+// 10 }
+//
+// Assuming the global tree starts empty, inlining will produce the
+// following tree:
+//
+//   []InlinedCall{
+//     {Parent: -1, Func: "f", Pos: <line 2>},
+//     {Parent:  0, Func: "g", Pos: <line 5>},
+//     {Parent:  1, Func: "h", Pos: <line 8>},
+//     {Parent:  1, Func: "h", Pos: <line 9>},
+//   }
+//
+// The nodes of h inlined into main will have inlining indexes 2 and 3.
+//
+// Eventually, the compiler extracts a per-function inlining tree from
+// the global inlining tree (see pcln.go).
+type InlTree struct {
+	nodes []InlinedCall
+}
+
+// InlinedCall is a node in an InlTree.
+type InlinedCall struct {
+	Parent int      // index of the parent in the InlTree or < 0 if outermost call
+	Pos    src.XPos // position of the inlined call
+	Func   *LSym    // function that was inlined
+}
+
+// Add adds a new call to the tree, returning its index.
+func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym) int {
+	r := len(tree.nodes)
+	call := InlinedCall{
+		Parent: parent,
+		Pos:    pos,
+		Func:   func_,
+	}
+	tree.nodes = append(tree.nodes, call)
+	return r
+}
+
+// OutermostPos returns the outermost position corresponding to xpos,
+// which is where xpos was ultimately inlined to. In the example for
+// InlTree, main() contains inlined AST nodes from h(), but the
+// outermost position for those nodes is line 2.
+func (ctxt *Link) OutermostPos(xpos src.XPos) src.Pos {
+	pos := ctxt.PosTable.Pos(xpos)
+
+	outerxpos := xpos
+	for ix := pos.Base().InliningIndex(); ix >= 0; {
+		call := ctxt.InlTree.nodes[ix]
+		ix = call.Parent
+		outerxpos = call.Pos
+	}
+	return ctxt.PosTable.Pos(outerxpos)
+}
+
+func dumpInlTree(ctxt *Link, tree InlTree) {
+	for i, call := range tree.nodes {
+		pos := ctxt.PosTable.Pos(call.Pos)
+		ctxt.Logf("%0d | %0d | %s (%s)\n", i, call.Parent, call.Func, pos)
+	}
+}
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 54fde2f..275540d 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -59,7 +59,7 @@ func mkfwd(sym *LSym) {
 	}
 
 	i := 0
-	for p := sym.Text; p != nil && p.Link != nil; p = p.Link {
+	for p := sym.Func.Text; p != nil && p.Link != nil; p = p.Link {
 		i--
 		if i < 0 {
 			i = LOG - 1
@@ -76,17 +76,10 @@ func mkfwd(sym *LSym) {
 	}
 }
 
-func Copyp(ctxt *Link, q *Prog) *Prog {
-	p := ctxt.NewProg()
-	*p = *q
-	return p
-}
-
-func Appendp(ctxt *Link, q *Prog) *Prog {
-	p := ctxt.NewProg()
+func Appendp(q *Prog, newprog ProgAlloc) *Prog {
+	p := newprog()
 	p.Link = q.Link
 	q.Link = p
-	p.Lineno = q.Lineno
-	p.Mode = q.Mode
+	p.Pos = q.Pos
 	return p
 }
diff --git a/src/cmd/internal/obj/line.go b/src/cmd/internal/obj/line.go
index 566263d..fecf90c 100644
--- a/src/cmd/internal/obj/line.go
+++ b/src/cmd/internal/obj/line.go
@@ -5,302 +5,19 @@
 package obj
 
 import (
-	"fmt"
-	"path/filepath"
-	"sort"
-	"strings"
+	"cmd/internal/src"
 )
 
-// A LineHist records the history of the file input stack, which maps the virtual line number,
-// an incrementing count of lines processed in any input file and typically named lineno,
-// to a stack of file:line pairs showing the path of inclusions that led to that position.
-// The first line directive (//line in Go, #line in assembly) is treated as pushing
-// a new entry on the stack, so that errors can report both the actual and translated
-// line number.
-//
-// In typical use, the virtual lineno begins at 1, and file line numbers also begin at 1,
-// but the only requirements placed upon the numbers by this code are:
-//	- calls to Push, Update, and Pop must be monotonically increasing in lineno
-//	- except as specified by those methods, virtual and file line number increase
-//	  together, so that given (only) calls Push(10, "x.go", 1) and Pop(15),
-//	  virtual line 12 corresponds to x.go line 3.
-type LineHist struct {
-	Top               *LineStack  // current top of stack
-	Ranges            []LineRange // ranges for lookup
-	Dir               string      // directory to qualify relative paths
-	TrimPathPrefix    string      // remove leading TrimPath from recorded file names
-	PrintFilenameOnly bool        // ignore path when pretty-printing a line; internal use only
-	GOROOT            string      // current GOROOT
-}
-
-// A LineStack is an entry in the recorded line history.
-// Although the history at any given line number is a stack,
-// the record for all line processed forms a tree, with common
-// stack prefixes acting as parents.
-type LineStack struct {
-	Parent    *LineStack // parent in inclusion stack
-	Lineno    int        // virtual line number where this entry takes effect
-	File      string     // file name used to open source file, for error messages
-	AbsFile   string     // absolute file name, for pcln tables
-	FileLine  int        // line number in file at Lineno
-	Directive bool
-	Sym       *LSym // for linkgetline - TODO(rsc): remove
-}
-
-func (stk *LineStack) fileLineAt(lineno int) int {
-	return stk.FileLine + lineno - stk.Lineno
-}
-
-// The span of valid linenos in the recorded line history can be broken
-// into a set of ranges, each with a particular stack.
-// A LineRange records one such range.
-type LineRange struct {
-	Start int        // starting lineno
-	Stack *LineStack // top of stack for this range
-}
-
-// startRange starts a new range with the given top of stack.
-func (h *LineHist) startRange(lineno int, top *LineStack) {
-	h.Top = top
-	h.Ranges = append(h.Ranges, LineRange{top.Lineno, top})
-}
-
-// setFile sets stk.File = file and also derives stk.AbsFile.
-func (h *LineHist) setFile(stk *LineStack, file string) {
-	// Note: The exclusion of stk.Directive may be wrong but matches what we've done before.
-	// The check for < avoids putting a path prefix on "<autogenerated>".
-	abs := file
-	if h.Dir != "" && !filepath.IsAbs(file) && !strings.HasPrefix(file, "<") && !stk.Directive {
-		abs = filepath.Join(h.Dir, file)
-	}
-
-	// Remove leading TrimPathPrefix, or else rewrite $GOROOT to literal $GOROOT.
-	if h.TrimPathPrefix != "" && hasPathPrefix(abs, h.TrimPathPrefix) {
-		if abs == h.TrimPathPrefix {
-			abs = ""
-		} else {
-			abs = abs[len(h.TrimPathPrefix)+1:]
-		}
-	} else if hasPathPrefix(abs, h.GOROOT) {
-		abs = "$GOROOT" + abs[len(h.GOROOT):]
-	}
-	if abs == "" {
-		abs = "??"
-	}
-	abs = filepath.Clean(abs)
-	stk.AbsFile = abs
-
-	if file == "" {
-		file = "??"
-	}
-	stk.File = file
-}
-
-// Does s have t as a path prefix?
-// That is, does s == t or does s begin with t followed by a slash?
-// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
-// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
-// We do not allow full Unicode case folding, for fear of causing more confusion
-// or harm than good. (For an example of the kinds of things that can go wrong,
-// see http://article.gmane.org/gmane.linux.kernel/1853266.)
-func hasPathPrefix(s string, t string) bool {
-	if len(t) > len(s) {
-		return false
-	}
-	var i int
-	for i = 0; i < len(t); i++ {
-		cs := int(s[i])
-		ct := int(t[i])
-		if 'A' <= cs && cs <= 'Z' {
-			cs += 'a' - 'A'
-		}
-		if 'A' <= ct && ct <= 'Z' {
-			ct += 'a' - 'A'
-		}
-		if cs == '\\' {
-			cs = '/'
-		}
-		if ct == '\\' {
-			ct = '/'
-		}
-		if cs != ct {
-			return false
-		}
-	}
-	return i >= len(s) || s[i] == '/' || s[i] == '\\'
-}
-
-// Push records that at that lineno a new file with the given name was pushed onto the input stack.
-func (h *LineHist) Push(lineno int, file string) {
-	stk := &LineStack{
-		Parent:   h.Top,
-		Lineno:   lineno,
-		FileLine: 1,
-	}
-	h.setFile(stk, file)
-	h.startRange(lineno, stk)
-}
-
-// Pop records that at lineno the current file was popped from the input stack.
-func (h *LineHist) Pop(lineno int) {
-	top := h.Top
-	if top == nil {
-		return
-	}
-	if top.Directive && top.Parent != nil { // pop #line level too
-		top = top.Parent
-	}
-	next := top.Parent
-	if next == nil {
-		h.Top = nil
-		h.Ranges = append(h.Ranges, LineRange{lineno, nil})
-		return
-	}
-
-	// Popping included file. Update parent offset to account for
-	// the virtual line number range taken by the included file.
-	// Cannot modify the LineStack directly, or else lookups
-	// for the earlier line numbers will get the wrong answers,
-	// so make a new one.
-	stk := new(LineStack)
-	*stk = *next
-	stk.Lineno = lineno
-	stk.FileLine = next.fileLineAt(top.Lineno)
-	h.startRange(lineno, stk)
-}
-
-// Update records that at lineno the file name and line number were changed using
-// a line directive (//line in Go, #line in assembly).
-func (h *LineHist) Update(lineno int, file string, line int) {
-	top := h.Top
-	if top == nil {
-		return // shouldn't happen
-	}
-	var stk *LineStack
-	if top.Directive {
-		// Update existing entry, except make copy to avoid changing earlier history.
-		stk = new(LineStack)
-		*stk = *top
-	} else {
-		// Push new entry.
-		stk = &LineStack{
-			Parent:    top,
-			Directive: true,
-		}
-	}
-	stk.Lineno = lineno
-	if stk.File != file {
-		h.setFile(stk, file) // only retain string if needed
-	}
-	stk.FileLine = line
-	h.startRange(lineno, stk)
-}
-
 // AddImport adds a package to the list of imported packages.
 func (ctxt *Link) AddImport(pkg string) {
 	ctxt.Imports = append(ctxt.Imports, pkg)
 }
 
-// At returns the input stack in effect at lineno.
-func (h *LineHist) At(lineno int) *LineStack {
-	i := sort.Search(len(h.Ranges), func(i int) bool {
-		return h.Ranges[i].Start > lineno
-	})
-	// Found first entry beyond lineno.
-	if i == 0 {
-		return nil
-	}
-	return h.Ranges[i-1].Stack
-}
-
-// LineString returns a string giving the file and line number
-// corresponding to lineno, for use in error messages.
-func (h *LineHist) LineString(lineno int) string {
-	stk := h.At(lineno)
-	if stk == nil {
-		return "<unknown line number>"
-	}
-
-	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
-		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", filename, stk.fileLineAt(lineno))
-			if stk.Directive && stk.Parent != nil {
-				stk = stk.Parent
-				text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno))
-			}
-		}
-	}
-	return text
-}
-
-// FileLine returns the file name and line number
-// at the top of the stack for the given lineno.
-func (h *LineHist) FileLine(lineno int) (file string, line int) {
-	stk := h.At(lineno)
-	if stk == nil {
-		return "??", 0
-	}
-	return stk.File, stk.fileLineAt(lineno)
-}
-
-// AbsFileLine returns the absolute file name and line number
-// at the top of the stack for the given lineno.
-func (h *LineHist) AbsFileLine(lineno int) (file string, line int) {
-	stk := h.At(lineno)
-	if stk == nil {
-		return "??", 0
-	}
-	return stk.AbsFile, stk.fileLineAt(lineno)
-}
-
-// This is a simplified copy of linklinefmt above.
-// It doesn't allow printing the full stack, and it returns the file name and line number separately.
-// TODO: Unify with linklinefmt somehow.
-func linkgetline(ctxt *Link, lineno int32) (f *LSym, l int32) {
-	stk := ctxt.LineHist.At(int(lineno))
-	if stk == nil || stk.AbsFile == "" {
-		return Linklookup(ctxt, "??", HistVersion), 0
-	}
-	if stk.Sym == nil {
-		stk.Sym = Linklookup(ctxt, stk.AbsFile, HistVersion)
-	}
-	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
-		}
+func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) {
+	pos := ctxt.PosTable.Pos(xpos)
+	if !pos.IsKnown() {
+		pos = src.Pos{}
 	}
+	// TODO(gri) Should this use relative or absolute line number?
+	return pos.SymFilename(), int32(pos.RelLine())
 }
diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go
index 8f9bcd1..6b21abe 100644
--- a/src/cmd/internal/obj/line_test.go
+++ b/src/cmd/internal/obj/line_test.go
@@ -5,45 +5,36 @@
 package obj
 
 import (
+	"cmd/internal/src"
 	"fmt"
 	"testing"
 )
 
-func TestLineHist(t *testing.T) {
+func TestLinkgetlineFromPos(t *testing.T) {
 	ctxt := new(Link)
-	ctxt.Hash = make(map[SymVer]*LSym)
+	ctxt.hash = make(map[string]*LSym)
+	ctxt.statichash = make(map[string]*LSym)
 
-	ctxt.LineHist.Push(1, "a.c")
-	ctxt.LineHist.Push(3, "a.h")
-	ctxt.LineHist.Pop(5)
-	ctxt.LineHist.Update(7, "linedir", 2)
-	ctxt.LineHist.Pop(9)
-	ctxt.LineHist.Push(11, "b.c")
-	ctxt.LineHist.Pop(13)
+	afile := src.NewFileBase("a.go", "a.go")
+	bfile := src.NewFileBase("b.go", "/foo/bar/b.go")
+	lfile := src.NewLinePragmaBase(src.MakePos(afile, 7, 0), "linedir", 100)
 
-	var expect = []string{
-		0:  "??:0",
-		1:  "a.c:1",
-		2:  "a.c:2",
-		3:  "a.h:1",
-		4:  "a.h:2",
-		5:  "a.c:3",
-		6:  "a.c:4",
-		7:  "linedir:2",
-		8:  "linedir:3",
-		9:  "??:0",
-		10: "??:0",
-		11: "b.c:1",
-		12: "b.c:2",
-		13: "??:0",
-		14: "??:0",
+	var tests = []struct {
+		pos  src.Pos
+		want string
+	}{
+		{src.NoPos, "??:0"},
+		{src.MakePos(afile, 1, 0), "a.go:1"},
+		{src.MakePos(afile, 2, 0), "a.go:2"},
+		{src.MakePos(bfile, 10, 4), "/foo/bar/b.go:10"},
+		{src.MakePos(lfile, 10, 0), "linedir:102"}, // 102 == 100 + (10 - (7+1))
 	}
 
-	for i, want := range expect {
-		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)
+	for _, test := range tests {
+		f, l := linkgetlineFromPos(ctxt, ctxt.PosTable.XPos(test.pos))
+		got := fmt.Sprintf("%s:%d", f, l)
+		if got != src.FileSymPrefix+test.want {
+			t.Errorf("linkgetline(%v) = %q, want %q", test.pos, got, test.want)
 		}
 	}
 }
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 2ab2aec..d49bc8c 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -32,8 +32,12 @@ package obj
 
 import (
 	"bufio"
+	"cmd/internal/dwarf"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"cmd/internal/sys"
 	"fmt"
+	"sync"
 )
 
 // An Addr is an argument to an instruction.
@@ -156,7 +160,7 @@ type Addr struct {
 	Index  int16
 	Scale  int16 // Sometimes holds a register.
 	Type   AddrType
-	Name   int8
+	Name   AddrName
 	Class  int8
 	Offset int64
 	Sym    *LSym
@@ -167,14 +171,12 @@ type Addr struct {
 	//	for TYPE_BRANCH, a *Prog (optional)
 	//	for TYPE_TEXTSIZE, an int32 (optional)
 	Val interface{}
-
-	Node interface{} // for use by compiler
 }
 
-type AddrType uint8
+type AddrName int8
 
 const (
-	NAME_NONE = 0 + iota
+	NAME_NONE AddrName = iota
 	NAME_EXTERN
 	NAME_STATIC
 	NAME_AUTO
@@ -184,10 +186,11 @@ const (
 	NAME_GOTREF
 )
 
-const (
-	TYPE_NONE AddrType = 0
+type AddrType uint8
 
-	TYPE_BRANCH AddrType = 5 + iota
+const (
+	TYPE_NONE AddrType = iota
+	TYPE_BRANCH
 	TYPE_TEXTSIZE
 	TYPE_MEM
 	TYPE_CONST
@@ -221,36 +224,35 @@ const (
 // The Progs for a given function are arranged in a list linked through the Link field.
 //
 // Each Prog is charged to a specific source line in the debug information,
-// specified by Lineno, an index into the line history (see LineHist).
-// Every Prog has a Ctxt field that defines various context, including the current LineHist.
-// Progs should be allocated using ctxt.NewProg(), not new(Prog).
+// specified by Pos.Line().
+// Every Prog has a Ctxt field that defines its context.
+// For performance reasons, Progs usually are usually bulk allocated, cached, and reused;
+// those bulk allocators should always be used, rather than new(Prog).
 //
 // The other fields not yet mentioned are for use by the back ends and should
 // be left zeroed by creators of Prog lists.
 type Prog struct {
-	Ctxt   *Link       // linker context
-	Link   *Prog       // next Prog in linked list
-	From   Addr        // first source operand
-	From3  *Addr       // third source operand (second is Reg below)
-	To     Addr        // destination operand (second is RegTo2 below)
-	Pcond  *Prog       // target of conditional jump
-	Opt    interface{} // available to optimization passes to hold per-Prog state
-	Forwd  *Prog       // for x86 back end
-	Rel    *Prog       // for x86, arm back ends
-	Pc     int64       // for back ends or assembler: virtual or actual program counter, depending on phase
-	Lineno int32       // line number of this instruction
-	Spadj  int32       // effect of instruction on stack pointer (increment or decrement amount)
-	As     As          // assembler opcode
-	Reg    int16       // 2nd source operand
-	RegTo2 int16       // 2nd destination operand
-	Mark   uint16      // bitmask of arch-specific items
-	Optab  uint16      // arch-specific opcode index
-	Scond  uint8       // condition bits for conditional instruction (e.g., on ARM)
-	Back   uint8       // for x86 back end: backwards branch state
-	Ft     uint8       // for x86 back end: type index of Prog.From
-	Tt     uint8       // for x86 back end: type index of Prog.To
-	Isize  uint8       // for x86 back end: size of the instruction in bytes
-	Mode   int8        // for x86 back end: 32- or 64-bit mode
+	Ctxt   *Link    // linker context
+	Link   *Prog    // next Prog in linked list
+	From   Addr     // first source operand
+	From3  *Addr    // third source operand (second is Reg below)
+	To     Addr     // destination operand (second is RegTo2 below)
+	Pcond  *Prog    // target of conditional jump
+	Forwd  *Prog    // for x86 back end
+	Rel    *Prog    // for x86, arm back ends
+	Pc     int64    // for back ends or assembler: virtual or actual program counter, depending on phase
+	Pos    src.XPos // source position of this instruction
+	Spadj  int32    // effect of instruction on stack pointer (increment or decrement amount)
+	As     As       // assembler opcode
+	Reg    int16    // 2nd source operand
+	RegTo2 int16    // 2nd destination operand
+	Mark   uint16   // bitmask of arch-specific items
+	Optab  uint16   // arch-specific opcode index
+	Scond  uint8    // condition bits for conditional instruction (e.g., on ARM)
+	Back   uint8    // for x86 back end: backwards branch state
+	Ft     uint8    // for x86 back end: type index of Prog.From
+	Tt     uint8    // for x86 back end: type index of Prog.To
+	Isize  uint8    // for x86 back end: size of the instruction in bytes
 }
 
 // From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
@@ -261,14 +263,6 @@ func (p *Prog) From3Type() AddrType {
 	return p.From3.Type
 }
 
-// From3Offset returns From3.Offset, or 0 when From3 is nil.
-func (p *Prog) From3Offset() int64 {
-	if p.From3 == nil {
-		return 0
-	}
-	return p.From3.Offset
-}
-
 // An As denotes an assembler opcode.
 // There are some portable opcodes, declared here in package obj,
 // that are common to all architectures.
@@ -289,12 +283,7 @@ const (
 	APCDATA
 	ARET
 	ATEXT
-	ATYPE
 	AUNDEF
-	AUSEFIELD
-	AVARDEF
-	AVARKILL
-	AVARLIVE
 	A_ARCHSPECIFIC
 )
 
@@ -320,21 +309,32 @@ const (
 
 // An LSym is the sort of symbol that is written to an object file.
 type LSym struct {
-	Name    string
-	Type    SymKind
-	Version int16
+	Name string
+	Type objabi.SymKind
 	Attribute
 
 	RefIdx int // Index of this symbol in the symbol reference list.
-	Args   int32
-	Locals int32
 	Size   int64
 	Gotype *LSym
-	Autom  *Auto
-	Text   *Prog
-	Pcln   *Pcln
 	P      []byte
 	R      []Reloc
+
+	Func *FuncInfo
+}
+
+// A FuncInfo contains extra fields for STEXT symbols.
+type FuncInfo struct {
+	Args   int32
+	Locals int32
+	Text   *Prog
+	Autom  []*Auto
+	Pcln   Pcln
+
+	dwarfSym       *LSym
+	dwarfRangesSym *LSym
+
+	GCArgs   LSym
+	GCLocals LSym
 }
 
 // Attribute is a set of symbol attributes.
@@ -345,8 +345,12 @@ const (
 	AttrCFunc
 	AttrNoSplit
 	AttrLeaf
+	AttrWrapper
+	AttrNeedCtxt
+	AttrNoFrame
 	AttrSeenGlobl
 	AttrOnList
+	AttrStatic
 
 	// MakeTypelink means that the type should have an entry in the typelink table.
 	AttrMakeTypelink
@@ -377,6 +381,10 @@ func (a Attribute) SeenGlobl() bool     { return a&AttrSeenGlobl != 0 }
 func (a Attribute) OnList() bool        { return a&AttrOnList != 0 }
 func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
 func (a Attribute) Local() bool         { return a&AttrLocal != 0 }
+func (a Attribute) Wrapper() bool       { return a&AttrWrapper != 0 }
+func (a Attribute) NeedCtxt() bool      { return a&AttrNeedCtxt != 0 }
+func (a Attribute) NoFrame() bool       { return a&AttrNoFrame != 0 }
+func (a Attribute) Static() bool        { return a&AttrStatic != 0 }
 
 func (a *Attribute) Set(flag Attribute, value bool) {
 	if value {
@@ -386,6 +394,46 @@ func (a *Attribute) Set(flag Attribute, value bool) {
 	}
 }
 
+var textAttrStrings = [...]struct {
+	bit Attribute
+	s   string
+}{
+	{bit: AttrDuplicateOK, s: "DUPOK"},
+	{bit: AttrMakeTypelink, s: ""},
+	{bit: AttrCFunc, s: "CFUNC"},
+	{bit: AttrNoSplit, s: "NOSPLIT"},
+	{bit: AttrLeaf, s: "LEAF"},
+	{bit: AttrSeenGlobl, s: ""},
+	{bit: AttrOnList, s: ""},
+	{bit: AttrReflectMethod, s: "REFLECTMETHOD"},
+	{bit: AttrLocal, s: "LOCAL"},
+	{bit: AttrWrapper, s: "WRAPPER"},
+	{bit: AttrNeedCtxt, s: "NEEDCTXT"},
+	{bit: AttrNoFrame, s: "NOFRAME"},
+	{bit: AttrStatic, s: "STATIC"},
+}
+
+// TextAttrString formats a for printing in as part of a TEXT prog.
+func (a Attribute) TextAttrString() string {
+	var s string
+	for _, x := range textAttrStrings {
+		if a&x.bit != 0 {
+			if x.s != "" {
+				s += x.s + "|"
+			}
+			a &^= x.bit
+		}
+	}
+	if a != 0 {
+		s += fmt.Sprintf("UnknownAttribute(%d)|", a)
+	}
+	// Chop off trailing |, if present.
+	if len(s) > 0 {
+		s = s[:len(s)-1]
+	}
+	return s
+}
+
 // The compiler needs LSym to satisfy fmt.Stringer, because it stores
 // an LSym in ssa.ExternSymbol.
 func (s *LSym) String() string {
@@ -396,363 +444,56 @@ type Pcln struct {
 	Pcsp        Pcdata
 	Pcfile      Pcdata
 	Pcline      Pcdata
+	Pcinline    Pcdata
 	Pcdata      []Pcdata
 	Funcdata    []*LSym
 	Funcdataoff []int64
-	File        []*LSym
-	Lastfile    *LSym
+	File        []string
+	Lastfile    string
 	Lastindex   int
-}
-
-// A SymKind describes the kind of memory represented by a symbol.
-type SymKind int16
-
-// Defined SymKind values.
-//
-// TODO(rsc): Give idiomatic Go names.
-// TODO(rsc): Reduce the number of symbol types in the object files.
-//go:generate stringer -type=SymKind
-const (
-	Sxxx SymKind = iota
-	STEXT
-	SELFRXSECT
-
-	// Read-only sections.
-	STYPE
-	SSTRING
-	SGOSTRING
-	SGOFUNC
-	SGCBITS
-	SRODATA
-	SFUNCTAB
-
-	SELFROSECT
-	SMACHOPLT
-
-	// Read-only sections with relocations.
-	//
-	// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
-	// When linking a shared object, some conceptually "read only" types need to
-	// be written to by relocations and putting them in a section called
-	// ".rodata" interacts poorly with the system linkers. The GNU linkers
-	// support this situation by arranging for sections of the name
-	// ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
-	// relocations have applied, so when the Go linker is creating a shared
-	// object it checks all objects of the above types and bumps any object that
-	// has a relocation to it to the corresponding type below, which are then
-	// written to sections with appropriate magic names.
-	STYPERELRO
-	SSTRINGRELRO
-	SGOSTRINGRELRO
-	SGOFUNCRELRO
-	SGCBITSRELRO
-	SRODATARELRO
-	SFUNCTABRELRO
-
-	// Part of .data.rel.ro if it exists, otherwise part of .rodata.
-	STYPELINK
-	SITABLINK
-	SSYMTAB
-	SPCLNTAB
-
-	// Writable sections.
-	SELFSECT
-	SMACHO
-	SMACHOGOT
-	SWINDOWS
-	SELFGOT
-	SNOPTRDATA
-	SINITARR
-	SDATA
-	SBSS
-	SNOPTRBSS
-	STLSBSS
-	SXREF
-	SMACHOSYMSTR
-	SMACHOSYMTAB
-	SMACHOINDIRECTPLT
-	SMACHOINDIRECTGOT
-	SFILE
-	SFILEPATH
-	SCONST
-	SDYNIMPORT
-	SHOSTOBJ
-	SDWARFSECT
-	SDWARFINFO
-	SSUB       = SymKind(1 << 8)
-	SMASK      = SymKind(SSUB - 1)
-	SHIDDEN    = SymKind(1 << 9)
-	SCONTAINER = SymKind(1 << 10) // has a sub-symbol
-)
-
-// ReadOnly are the symbol kinds that form read-only sections. In some
-// cases, if they will require relocations, they are transformed into
-// rel-ro sections using RelROMap.
-var ReadOnly = []SymKind{
-	STYPE,
-	SSTRING,
-	SGOSTRING,
-	SGOFUNC,
-	SGCBITS,
-	SRODATA,
-	SFUNCTAB,
-}
-
-// RelROMap describes the transformation of read-only symbols to rel-ro
-// symbols.
-var RelROMap = map[SymKind]SymKind{
-	STYPE:     STYPERELRO,
-	SSTRING:   SSTRINGRELRO,
-	SGOSTRING: SGOSTRINGRELRO,
-	SGOFUNC:   SGOFUNCRELRO,
-	SGCBITS:   SGCBITSRELRO,
-	SRODATA:   SRODATARELRO,
-	SFUNCTAB:  SFUNCTABRELRO,
+	InlTree     InlTree // per-function inlining tree extracted from the global tree
 }
 
 type Reloc struct {
 	Off  int32
 	Siz  uint8
-	Type RelocType
+	Type objabi.RelocType
 	Add  int64
 	Sym  *LSym
 }
 
-type RelocType int32
-
-//go:generate stringer -type=RelocType
-const (
-	R_ADDR RelocType = 1 + iota
-	// R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit
-	// immediates in the low half of the instruction word), usually addis followed by
-	// another add or a load, inserting the "high adjusted" 16 bits of the address of
-	// the referenced symbol into the immediate field of the first instruction and the
-	// low 16 bits into that of the second instruction.
-	R_ADDRPOWER
-	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
-	// referenced symbol.
-	R_ADDRARM64
-	// R_ADDRMIPS (only used on mips/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_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
-	// A weak relocation does not make the symbol it refers to reachable,
-	// and is only honored by the linker if the symbol is in some other way
-	// reachable.
-	R_WEAKADDROFF
-	R_SIZE
-	R_CALL
-	R_CALLARM
-	R_CALLARM64
-	R_CALLIND
-	R_CALLPOWER
-	// R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
-	// of a CALL (JAL) instruction, by encoding the address into the instruction.
-	R_CALLMIPS
-	R_CONST
-	R_PCREL
-	// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
-	// thread-local symbol from the thread local base and is used to implement the
-	// "local exec" model for tls access (r.Sym is not set on intel platforms but is
-	// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
-	R_TLS_LE
-	// R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT
-	// slot containing the offset from the thread-local symbol from the thread local
-	// base and is used to implemented the "initial exec" model for tls access (r.Sym
-	// is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in
-	// the linker when externally linking).
-	R_TLS_IE
-	R_GOTOFF
-	R_PLT0
-	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
-	// inherently processor specific.
-
-	// Arm64.
-
-	// Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread
-	// local base to the thread local variable defined by the referenced (thread
-	// local) symbol. Error if the offset does not fit into 16 bits.
-	R_ARM64_TLS_LE
-
-	// Relocates an ADRP; LD64 instruction sequence to load the offset between
-	// the thread local base and the thread local variable defined by the
-	// referenced (thread local) symbol from the GOT.
-	R_ARM64_TLS_IE
-
-	// R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
-	// slot of the referenced symbol.
-	R_ARM64_GOTPCREL
-
-	// PPC64.
-
-	// R_POWER_TLS_LE is used to implement the "local exec" model for tls
-	// access. It resolves to the offset of the thread-local symbol from the
-	// thread pointer (R13) and inserts this value into the low 16 bits of an
-	// instruction word.
-	R_POWER_TLS_LE
-
-	// R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It
-	// relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It
-	// inserts to the offset of GOT slot for the thread-local symbol from the TOC (the
-	// GOT slot is filled by the dynamic linker with the offset of the thread-local
-	// symbol from the thread pointer (R13)).
-	R_POWER_TLS_IE
-
-	// R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as
-	// accessing a particular thread-local symbol. It does not affect code generation
-	// but is used by the system linker when relaxing "initial exec" model code to
-	// "local exec" model code.
-	R_POWER_TLS
-
-	// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
-	// instruction is a "DS-form" instruction, which has an immediate field occupying
-	// bits [15:2] of the instruction word. Bits [15:2] of the address of the
-	// relocated symbol are inserted into this field; it is an error if the last two
-	// bits of the address are not 0.
-	R_ADDRPOWER_DS
-
-	// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
-	// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
-	// from the TOC rather than the symbol's address.
-	R_ADDRPOWER_GOT
-
-	// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
-	// inserts the displacement from the place being relocated to the address of the
-	// the relocated symbol instead of just its address.
-	R_ADDRPOWER_PCREL
-
-	// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
-	// inserts the offset from the TOC to the address of the the relocated symbol
-	// rather than the symbol's address.
-	R_ADDRPOWER_TOCREL
-
-	// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
-	// 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 mips/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
-)
-
-// IsDirectJump returns whether r is a relocation for a direct jump.
-// A direct jump is a CALL or JMP instruction that takes the target address
-// as immediate. The address is embedded into the instruction, possibly
-// with limited width.
-// An indirect jump is a CALL or JMP instruction that takes the target address
-// in register or memory.
-func (r RelocType) IsDirectJump() bool {
-	switch r {
-	case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER, R_CALLMIPS, R_JMPMIPS:
-		return true
-	}
-	return false
-}
-
 type Auto struct {
 	Asym    *LSym
-	Link    *Auto
 	Aoffset int32
-	Name    int16
+	Name    AddrName
 	Gotype  *LSym
 }
 
-// Auto.name
-const (
-	A_AUTO = 1 + iota
-	A_PARAM
-)
-
 type Pcdata struct {
 	P []byte
 }
 
-// symbol version, incremented each time a file is loaded.
-// version==1 is reserved for savehist.
-const (
-	HistVersion = 1
-)
-
 // Link holds the context for writing object code from a compiler
 // to be linker input or for reading that input into the linker.
 type Link struct {
-	Headtype      HeadType
+	Headtype      objabi.HeadType
 	Arch          *LinkArch
-	Debugasm      int32
-	Debugvlog     int32
-	Debugdivmod   int32
-	Debugpcln     int32
+	Debugasm      bool
+	Debugvlog     bool
+	Debugpcln     string
 	Flag_shared   bool
 	Flag_dynlink  bool
 	Flag_optimize bool
 	Bso           *bufio.Writer
 	Pathname      string
-	Hash          map[SymVer]*LSym
-	LineHist      LineHist
+	hashmu        sync.Mutex       // protects hash
+	hash          map[string]*LSym // name -> sym mapping
+	statichash    map[string]*LSym // name -> sym mapping for static syms
+	PosTable      src.PosTable
+	InlTree       InlTree // global inlining tree used by gc/inl.go
 	Imports       []string
-	Plists        []*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
+	DebugInfo     func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
 	Errors        int
 
 	Framepointer_enabled bool
@@ -760,10 +501,6 @@ type Link struct {
 	// state for writing objects
 	Text []*LSym
 	Data []*LSym
-
-	// Cache of Progs
-	allocIdx int
-	progs    [10000]Prog
 }
 
 func (ctxt *Link) Diag(format string, args ...interface{}) {
@@ -793,186 +530,12 @@ func (ctxt *Link) FixedFrameSize() int64 {
 	}
 }
 
-type SymVer struct {
-	Name    string
-	Version int // TODO: make int16 to match LSym.Version?
-}
-
 // LinkArch is the definition of a single architecture.
 type LinkArch struct {
 	*sys.Arch
-	Preprocess func(*Link, *LSym)
-	Assemble   func(*Link, *LSym)
-	Follow     func(*Link, *LSym)
-	Progedit   func(*Link, *Prog)
+	Init       func(*Link)
+	Preprocess func(*Link, *LSym, ProgAlloc)
+	Assemble   func(*Link, *LSym, ProgAlloc)
+	Progedit   func(*Link, *Prog, ProgAlloc)
 	UnaryDst   map[As]bool // Instruction takes one operand, a destination.
 }
-
-// HeadType is the executable header type.
-type HeadType uint8
-
-const (
-	Hunknown HeadType = iota
-	Hdarwin
-	Hdragonfly
-	Hfreebsd
-	Hlinux
-	Hnacl
-	Hnetbsd
-	Hopenbsd
-	Hplan9
-	Hsolaris
-	Hwindows
-	Hwindowsgui
-)
-
-func (h *HeadType) Set(s string) error {
-	switch s {
-	case "darwin":
-		*h = Hdarwin
-	case "dragonfly":
-		*h = Hdragonfly
-	case "freebsd":
-		*h = Hfreebsd
-	case "linux", "android":
-		*h = Hlinux
-	case "nacl":
-		*h = Hnacl
-	case "netbsd":
-		*h = Hnetbsd
-	case "openbsd":
-		*h = Hopenbsd
-	case "plan9":
-		*h = Hplan9
-	case "solaris":
-		*h = Hsolaris
-	case "windows":
-		*h = Hwindows
-	case "windowsgui":
-		*h = Hwindowsgui
-	default:
-		return fmt.Errorf("invalid headtype: %q", s)
-	}
-	return nil
-}
-
-func (h *HeadType) String() string {
-	switch *h {
-	case Hdarwin:
-		return "darwin"
-	case Hdragonfly:
-		return "dragonfly"
-	case Hfreebsd:
-		return "freebsd"
-	case Hlinux:
-		return "linux"
-	case Hnacl:
-		return "nacl"
-	case Hnetbsd:
-		return "netbsd"
-	case Hopenbsd:
-		return "openbsd"
-	case Hplan9:
-		return "plan9"
-	case Hsolaris:
-		return "solaris"
-	case Hwindows:
-		return "windows"
-	case Hwindowsgui:
-		return "windowsgui"
-	}
-	return fmt.Sprintf("HeadType(%d)", *h)
-}
-
-// AsmBuf is a simple buffer to assemble variable-length x86 instructions into.
-type AsmBuf struct {
-	buf [100]byte
-	off int
-}
-
-// 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 f732ed5..46329a8 100644
--- a/src/cmd/internal/obj/mips/a.out.go
+++ b/src/cmd/internal/obj/mips/a.out.go
@@ -29,7 +29,9 @@
 
 package mips
 
-import "cmd/internal/obj"
+import (
+	"cmd/internal/obj"
+)
 
 //go:generate go run ../stringer.go -i $GOFILE -o anames.go -p mips
 
@@ -218,11 +220,6 @@ const (
 )
 
 const (
-	Mips32 = 32
-	Mips64 = 64
-)
-
-const (
 	C_NONE = iota
 	C_REG
 	C_FREG
@@ -302,6 +299,7 @@ const (
 	ADIVW
 	AGOK
 	ALL
+	ALLV
 	ALUI
 	AMOVB
 	AMOVBU
@@ -326,12 +324,14 @@ const (
 	ANEGD
 	ANEGF
 	ANEGW
+	ANOOP // hardware nop
 	ANOR
 	AOR
 	AREM
 	AREMU
 	ARFE
 	ASC
+	ASCV
 	ASGT
 	ASGTU
 	ASLL
diff --git a/src/cmd/internal/obj/mips/anames.go b/src/cmd/internal/obj/mips/anames.go
index 8482a9e..ed2143a 100644
--- a/src/cmd/internal/obj/mips/anames.go
+++ b/src/cmd/internal/obj/mips/anames.go
@@ -45,6 +45,7 @@ var Anames = []string{
 	"DIVW",
 	"GOK",
 	"LL",
+	"LLV",
 	"LUI",
 	"MOVB",
 	"MOVBU",
@@ -69,12 +70,14 @@ var Anames = []string{
 	"NEGD",
 	"NEGF",
 	"NEGW",
+	"NOOP",
 	"NOR",
 	"OR",
 	"REM",
 	"REMU",
 	"RFE",
 	"SC",
+	"SCV",
 	"SGT",
 	"SGTU",
 	"SLL",
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index c421dee..3cfb260 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -31,11 +31,25 @@ package mips
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"sort"
 )
 
+// ctxt0 holds state while assembling a single function.
+// Each function gets a fresh ctxt0.
+// This allows for multiple functions to be safely concurrently assembled.
+type ctxt0 struct {
+	ctxt       *obj.Link
+	newprog    obj.ProgAlloc
+	cursym     *obj.LSym
+	autosize   int32
+	instoffset int64
+	pc         int64
+}
+
 // Instruction layout.
 
 const (
@@ -47,201 +61,203 @@ const (
 )
 
 type Optab struct {
-	as    obj.As
-	a1    uint8
-	a2    uint8
-	a3    uint8
-	type_ int8
-	size  int8
-	param int16
-	mode  int
+	as     obj.As
+	a1     uint8
+	a2     uint8
+	a3     uint8
+	type_  int8
+	size   int8
+	param  int16
+	family sys.ArchFamily // 0 means both sys.MIPS and sys.MIPS64
 }
 
 var optab = []Optab{
-	{obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0, Mips64},
+	{obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0, sys.MIPS64},
 	{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0},
 
 	{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0, 0},
 	{AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0, 0},
-	{AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0, sys.MIPS64},
 
 	{ASUB, C_REG, C_REG, C_REG, 2, 4, 0, 0},
-	{ASUBV, C_REG, C_REG, C_REG, 2, 4, 0, Mips64},
+	{ASUBV, C_REG, C_REG, C_REG, 2, 4, 0, sys.MIPS64},
 	{AADD, C_REG, C_REG, C_REG, 2, 4, 0, 0},
-	{AADDV, C_REG, C_REG, C_REG, 2, 4, 0, Mips64},
+	{AADDV, C_REG, C_REG, C_REG, 2, 4, 0, sys.MIPS64},
 	{AAND, C_REG, C_REG, C_REG, 2, 4, 0, 0},
 	{ASUB, C_REG, C_NONE, C_REG, 2, 4, 0, 0},
-	{ASUBV, C_REG, C_NONE, C_REG, 2, 4, 0, Mips64},
+	{ASUBV, C_REG, C_NONE, C_REG, 2, 4, 0, sys.MIPS64},
 	{AADD, C_REG, C_NONE, C_REG, 2, 4, 0, 0},
-	{AADDV, C_REG, C_NONE, C_REG, 2, 4, 0, Mips64},
+	{AADDV, C_REG, C_NONE, C_REG, 2, 4, 0, sys.MIPS64},
 	{AAND, C_REG, C_NONE, C_REG, 2, 4, 0, 0},
 	{ACMOVN, C_REG, C_REG, C_REG, 2, 4, 0, 0},
 
 	{ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0},
 	{ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0},
-	{ASLLV, C_REG, C_NONE, C_REG, 9, 4, 0, Mips64},
-	{ASLLV, C_REG, C_REG, C_REG, 9, 4, 0, Mips64},
+	{ASLLV, C_REG, C_NONE, C_REG, 9, 4, 0, sys.MIPS64},
+	{ASLLV, C_REG, C_REG, C_REG, 9, 4, 0, sys.MIPS64},
 	{ACLO, C_REG, C_NONE, C_REG, 9, 4, 0, 0},
 
 	{AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0, 0},
 	{AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0, 0},
 	{ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0, 0},
 	{AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0},
-	{AMOVVF, C_FREG, C_NONE, C_FREG, 33, 4, 0, Mips64},
+	{AMOVVF, C_FREG, C_NONE, C_FREG, 33, 4, 0, sys.MIPS64},
 	{AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0},
 	{AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0},
 
-	{AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVWU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
-	{AMOVVL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64},
+	{AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVWU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
+	{AMOVVL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0},
-	{AMOVWU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, Mips64},
-	{AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0},
 	{AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0},
 	{AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0},
-	{AMOVVL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, Mips64},
+	{AMOVVL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0},
-	{AMOVWU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, Mips64},
-	{AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0},
 	{AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0},
 	{AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0},
-	{AMOVVL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, Mips64},
+	{AMOVVL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64},
 	{ASC, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0},
-
-	{AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVWU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
-	{AMOVVL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, Mips64},
+	{ASCV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64},
+
+	{AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVWU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
+	{AMOVVL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64},
 	{AMOVW, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0},
-	{AMOVWU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, Mips64},
-	{AMOVV, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, Mips64},
+	{AMOVWU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64},
+	{AMOVV, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64},
 	{AMOVB, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0},
 	{AMOVBU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0},
 	{AMOVWL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0},
-	{AMOVVL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, Mips64},
+	{AMOVVL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64},
 	{AMOVW, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
-	{AMOVWU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, Mips64},
-	{AMOVV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, Mips64},
+	{AMOVWU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64},
+	{AMOVV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64},
 	{AMOVB, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
 	{AMOVBU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
 	{AMOVWL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
-	{AMOVVL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, Mips64},
+	{AMOVVL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64},
 	{ALL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
+	{ALLV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64},
 
-	{AMOVW, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, Mips64},
-	{AMOVWU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, Mips64},
-	{AMOVV, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, Mips64},
-	{AMOVB, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, Mips64},
-	{AMOVBU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, Mips64},
+	{AMOVW, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64},
+	{AMOVWU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64},
+	{AMOVB, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64},
+	{AMOVBU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0},
-	{AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, Mips64},
-	{AMOVV, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0},
 	{AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0},
 	{AMOVW, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0},
-	{AMOVWU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, Mips64},
-	{AMOVV, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0},
 	{AMOVBU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0},
 	{ASC, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0},
-	{AMOVW, C_REG, C_NONE, C_ADDR, 50, 8, 0, Mips32},
-	{AMOVW, C_REG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
-	{AMOVWU, C_REG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
-	{AMOVV, C_REG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
-	{AMOVB, C_REG, C_NONE, C_ADDR, 50, 8, 0, Mips32},
-	{AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
-	{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 8, 0, Mips32},
-	{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
+	{AMOVW, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS},
+	{AMOVW, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
+	{AMOVWU, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
+	{AMOVB, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS},
+	{AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
+	{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS},
+	{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0, 0},
-	{AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0, Mips64},
-	{AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0, Mips64},
+	{AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64},
+	{AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64},
 	{AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0, 0},
 	{AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0, 0},
 
-	{AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, Mips64},
-	{AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, Mips64},
-	{AMOVV, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, Mips64},
-	{AMOVB, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, Mips64},
-	{AMOVBU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, Mips64},
+	{AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64},
+	{AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64},
+	{AMOVV, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64},
+	{AMOVB, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64},
+	{AMOVBU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64},
 	{AMOVW, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0},
-	{AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, Mips64},
-	{AMOVV, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, Mips64},
+	{AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, sys.MIPS64},
+	{AMOVV, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, sys.MIPS64},
 	{AMOVB, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0},
 	{AMOVBU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0},
 	{AMOVW, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0},
-	{AMOVWU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, Mips64},
-	{AMOVV, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, Mips64},
+	{AMOVWU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, sys.MIPS64},
+	{AMOVV, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, sys.MIPS64},
 	{AMOVB, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0},
 	{AMOVBU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0},
-	{AMOVW, C_ADDR, C_NONE, C_REG, 51, 8, 0, Mips32},
-	{AMOVW, C_ADDR, C_NONE, C_REG, 51, 12, 0, Mips64},
-	{AMOVWU, C_ADDR, C_NONE, C_REG, 51, 12, 0, Mips64},
-	{AMOVV, C_ADDR, C_NONE, C_REG, 51, 12, 0, Mips64},
-	{AMOVB, C_ADDR, C_NONE, C_REG, 51, 8, 0, Mips32},
-	{AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0, Mips64},
-	{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 8, 0, Mips32},
-	{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0, Mips64},
+	{AMOVW, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS},
+	{AMOVW, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64},
+	{AMOVWU, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64},
+	{AMOVV, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64},
+	{AMOVB, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS},
+	{AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64},
+	{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS},
+	{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64},
 	{AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0, 0},
-	{AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0, Mips64},
-	{AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0, Mips64},
+	{AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64},
+	{AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64},
 	{AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0, 0},
 	{AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0, 0},
 
-	{AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB, Mips64},
-	{AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB, Mips64},
+	{AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64},
+	{AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64},
 	{AMOVW, C_SACON, C_NONE, C_REG, 3, 4, REGSP, 0},
-	{AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP, Mips64},
-	{AMOVW, C_LECON, C_NONE, C_REG, 52, 8, REGSB, Mips32},
-	{AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB, Mips64},
-	{AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB, Mips64},
+	{AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP, sys.MIPS64},
+	{AMOVW, C_LECON, C_NONE, C_REG, 52, 8, REGSB, sys.MIPS},
+	{AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64},
+	{AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64},
 
 	{AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP, 0},
-	{AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP, Mips64},
+	{AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP, sys.MIPS64},
 	{AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, 0},
-	{AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, Mips64},
+	{AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64},
 	{AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, 0},
-	{AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, Mips64},
+	{AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64},
 	{AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0, 0},
-	{AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, Mips64},
+	{AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, sys.MIPS64},
 
 	{AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0, 0},
-	{AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0, Mips64},
+	{AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0, sys.MIPS64},
 	{AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0, 0},
-	{AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, Mips64},
+	{AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, sys.MIPS64},
 
 	{AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0, 0},
-	{AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0, Mips64},
+	{AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0, sys.MIPS64},
 	{AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0, 0},
-	{AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0, Mips64},
+	{AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0, sys.MIPS64},
 	{AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0, sys.MIPS64},
 
 	{AMUL, C_REG, C_REG, C_NONE, 22, 4, 0, 0},
 	{AMUL, C_REG, C_REG, C_REG, 22, 4, 0, 0},
-	{AMULV, C_REG, C_REG, C_NONE, 22, 4, 0, Mips64},
+	{AMULV, C_REG, C_REG, C_NONE, 22, 4, 0, sys.MIPS64},
 
 	{AADD, C_ADD0CON, C_REG, C_REG, 4, 4, 0, 0},
 	{AADD, C_ADD0CON, C_NONE, C_REG, 4, 4, 0, 0},
 	{AADD, C_ANDCON, C_REG, C_REG, 10, 8, 0, 0},
 	{AADD, C_ANDCON, C_NONE, C_REG, 10, 8, 0, 0},
 
-	{AADDV, C_ADD0CON, C_REG, C_REG, 4, 4, 0, Mips64},
-	{AADDV, C_ADD0CON, C_NONE, C_REG, 4, 4, 0, Mips64},
-	{AADDV, C_ANDCON, C_REG, C_REG, 10, 8, 0, Mips64},
-	{AADDV, C_ANDCON, C_NONE, C_REG, 10, 8, 0, Mips64},
+	{AADDV, C_ADD0CON, C_REG, C_REG, 4, 4, 0, sys.MIPS64},
+	{AADDV, C_ADD0CON, C_NONE, C_REG, 4, 4, 0, sys.MIPS64},
+	{AADDV, C_ANDCON, C_REG, C_REG, 10, 8, 0, sys.MIPS64},
+	{AADDV, C_ANDCON, C_NONE, C_REG, 10, 8, 0, sys.MIPS64},
 
 	{AAND, C_AND0CON, C_REG, C_REG, 4, 4, 0, 0},
 	{AAND, C_AND0CON, C_NONE, C_REG, 4, 4, 0, 0},
@@ -250,23 +266,23 @@ var optab = []Optab{
 
 	{AADD, C_UCON, C_REG, C_REG, 25, 8, 0, 0},
 	{AADD, C_UCON, C_NONE, C_REG, 25, 8, 0, 0},
-	{AADDV, C_UCON, C_REG, C_REG, 25, 8, 0, Mips64},
-	{AADDV, C_UCON, C_NONE, C_REG, 25, 8, 0, Mips64},
+	{AADDV, C_UCON, C_REG, C_REG, 25, 8, 0, sys.MIPS64},
+	{AADDV, C_UCON, C_NONE, C_REG, 25, 8, 0, sys.MIPS64},
 	{AAND, C_UCON, C_REG, C_REG, 25, 8, 0, 0},
 	{AAND, C_UCON, C_NONE, C_REG, 25, 8, 0, 0},
 
 	{AADD, C_LCON, C_NONE, C_REG, 23, 12, 0, 0},
-	{AADDV, C_LCON, C_NONE, C_REG, 23, 12, 0, Mips64},
+	{AADDV, C_LCON, C_NONE, C_REG, 23, 12, 0, sys.MIPS64},
 	{AAND, C_LCON, C_NONE, C_REG, 23, 12, 0, 0},
 	{AADD, C_LCON, C_REG, C_REG, 23, 12, 0, 0},
-	{AADDV, C_LCON, C_REG, C_REG, 23, 12, 0, Mips64},
+	{AADDV, C_LCON, C_REG, C_REG, 23, 12, 0, sys.MIPS64},
 	{AAND, C_LCON, C_REG, C_REG, 23, 12, 0, 0},
 
 	{ASLL, C_SCON, C_REG, C_REG, 16, 4, 0, 0},
 	{ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0, 0},
 
-	{ASLLV, C_SCON, C_REG, C_REG, 16, 4, 0, Mips64},
-	{ASLLV, C_SCON, C_NONE, C_REG, 16, 4, 0, Mips64},
+	{ASLLV, C_SCON, C_REG, C_REG, 16, 4, 0, sys.MIPS64},
+	{ASLLV, C_SCON, C_NONE, C_REG, 16, 4, 0, sys.MIPS64},
 
 	{ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0},
 
@@ -281,85 +297,84 @@ var optab = []Optab{
 	{AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO, 0},
 	{AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK, 0},
 
-	{AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, Mips64},
-	{AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, Mips64},
-	{AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, Mips64},
-	{AMOVW, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, Mips64},
+	{AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64},
+	{AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64},
+	{AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64},
+	{AMOVW, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, sys.MIPS64},
 	{AMOVF, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, 0},
 	{AMOVD, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, 0},
-	{AMOVW, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, Mips64},
+	{AMOVW, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, sys.MIPS64},
 	{AMOVF, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, 0},
 	{AMOVD, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, 0},
 
-	{AMOVW, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, Mips64},
-	{AMOVF, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, Mips64},
-	{AMOVD, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, Mips64},
-	{AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, Mips64},
+	{AMOVW, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64},
+	{AMOVF, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64},
+	{AMOVD, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64},
+	{AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, sys.MIPS64},
 	{AMOVF, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, 0},
 	{AMOVD, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, 0},
-	{AMOVW, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, Mips64},
+	{AMOVW, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, sys.MIPS64},
 	{AMOVF, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, 0},
 	{AMOVD, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, 0},
-	{AMOVF, C_ADDR, C_NONE, C_FREG, 51, 8, 0, Mips32},
-	{AMOVF, C_ADDR, C_NONE, C_FREG, 51, 12, 0, Mips64},
-	{AMOVD, C_ADDR, C_NONE, C_FREG, 51, 8, 0, Mips32},
-	{AMOVD, C_ADDR, C_NONE, C_FREG, 51, 12, 0, Mips64},
-
-	{AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, Mips64},
-	{AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, Mips64},
-	{AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, Mips64},
-	{AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, Mips64},
+	{AMOVF, C_ADDR, C_NONE, C_FREG, 51, 8, 0, sys.MIPS},
+	{AMOVF, C_ADDR, C_NONE, C_FREG, 51, 12, 0, sys.MIPS64},
+	{AMOVD, C_ADDR, C_NONE, C_FREG, 51, 8, 0, sys.MIPS},
+	{AMOVD, C_ADDR, C_NONE, C_FREG, 51, 12, 0, sys.MIPS64},
+
+	{AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64},
+	{AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64},
+	{AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64},
+	{AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, sys.MIPS64},
 	{AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, 0},
 	{AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, 0},
-	{AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, Mips64},
+	{AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, sys.MIPS64},
 	{AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, 0},
 	{AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, 0},
 
-	{AMOVW, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, Mips64},
-	{AMOVF, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, Mips64},
-	{AMOVD, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, Mips64},
-	{AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, Mips64},
+	{AMOVW, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64},
+	{AMOVF, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64},
+	{AMOVD, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64},
+	{AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, sys.MIPS64},
 	{AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, 0},
 	{AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, 0},
-	{AMOVW, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, Mips64},
+	{AMOVW, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, sys.MIPS64},
 	{AMOVF, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, 0},
 	{AMOVD, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, 0},
-	{AMOVF, C_FREG, C_NONE, C_ADDR, 50, 8, 0, Mips32},
-	{AMOVF, C_FREG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
-	{AMOVD, C_FREG, C_NONE, C_ADDR, 50, 8, 0, Mips32},
-	{AMOVD, C_FREG, C_NONE, C_ADDR, 50, 12, 0, Mips64},
+	{AMOVF, C_FREG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS},
+	{AMOVF, C_FREG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
+	{AMOVD, C_FREG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS},
+	{AMOVD, C_FREG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64},
 
 	{AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0, 0},
 	{AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0, Mips64},
-	{AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0, sys.MIPS64},
+	{AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0, sys.MIPS64},
 
-	{AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0, Mips64},
-	{AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0, Mips64},
+	{AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0, sys.MIPS64},
+	{AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0, sys.MIPS64},
 
 	{AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0, sys.MIPS64},
 	{AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0, 0},
-	{AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0, Mips64},
+	{AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0, sys.MIPS64},
 
 	{AWORD, C_LCON, C_NONE, C_NONE, 40, 4, 0, 0},
 
 	{AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0, 0},
-	{AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0, Mips64},
+	{AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0, sys.MIPS64},
 	{AMOVW, C_FCREG, C_NONE, C_REG, 42, 4, 0, 0},
-	{AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0, Mips64},
+	{AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0, sys.MIPS64},
 
 	{ATEQ, C_SCON, C_REG, C_REG, 15, 4, 0, 0},
 	{ATEQ, C_SCON, C_NONE, C_REG, 15, 4, 0, 0},
 	{ACMOVT, C_REG, C_NONE, C_REG, 17, 4, 0, 0},
 
-	{ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, Mips64}, /* really CACHE instruction */
-	{ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, Mips64},
-	{ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, Mips64},
+	{ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64}, /* really CACHE instruction */
+	{ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64},
+	{ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64},
 	{ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0},
 
 	{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0},
-	{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0},
 	{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0},
 	{obj.AFUNCDATA, C_SCON, C_NONE, C_ADDR, 0, 0, 0, 0},
 	{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0},
@@ -373,39 +388,38 @@ var oprange [ALAST & obj.AMask][]Optab
 
 var xcmp [C_NCLASS][C_NCLASS]bool
 
-func span0(ctxt *obj.Link, cursym *obj.LSym) {
-	p := cursym.Text
+func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	p := cursym.Func.Text
 	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
 		return
 	}
-	ctxt.Cursym = cursym
-	ctxt.Autosize = int32(p.To.Offset + ctxt.FixedFrameSize())
+
+	c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset + ctxt.FixedFrameSize())}
 
 	if oprange[AOR&obj.AMask] == nil {
-		buildop(ctxt)
+		c.ctxt.Diag("mips ops not initialized, call mips.buildop first")
 	}
 
-	c := int64(0)
-	p.Pc = c
+	pc := int64(0)
+	p.Pc = pc
 
 	var m int
 	var o *Optab
 	for p = p.Link; p != nil; p = p.Link {
-		ctxt.Curp = p
-		p.Pc = c
-		o = oplook(ctxt, p)
+		p.Pc = pc
+		o = c.oplook(p)
 		m = int(o.size)
 		if m == 0 {
-			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-				ctxt.Diag("zero-width instruction\n%v", p)
+			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+				c.ctxt.Diag("zero-width instruction\n%v", p)
 			}
 			continue
 		}
 
-		c += int64(m)
+		pc += int64(m)
 	}
 
-	cursym.Size = c
+	c.cursym.Size = pc
 
 	/*
 	 * if any procedure is large enough to
@@ -418,78 +432,74 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
 	var otxt int64
 	var q *obj.Prog
 	for bflag != 0 {
-		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f span1\n", obj.Cputime())
-		}
 		bflag = 0
-		c = 0
-		for p = cursym.Text.Link; p != nil; p = p.Link {
-			p.Pc = c
-			o = oplook(ctxt, p)
+		pc = 0
+		for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+			p.Pc = pc
+			o = c.oplook(p)
 
 			// very large conditional branches
 			if o.type_ == 6 && p.Pcond != nil {
-				otxt = p.Pcond.Pc - c
+				otxt = p.Pcond.Pc - pc
 				if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 {
-					q = ctxt.NewProg()
+					q = c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = AJMP
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.To.Type = obj.TYPE_BRANCH
 					q.Pcond = p.Pcond
 					p.Pcond = q
-					q = ctxt.NewProg()
+					q = c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = AJMP
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.To.Type = obj.TYPE_BRANCH
 					q.Pcond = q.Link.Link
 
-					addnop(ctxt, p.Link)
-					addnop(ctxt, p)
+					c.addnop(p.Link)
+					c.addnop(p)
 					bflag = 1
 				}
 			}
 
 			m = int(o.size)
 			if m == 0 {
-				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-					ctxt.Diag("zero-width instruction\n%v", p)
+				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+					c.ctxt.Diag("zero-width instruction\n%v", p)
 				}
 				continue
 			}
 
-			c += int64(m)
+			pc += int64(m)
 		}
 
-		cursym.Size = c
+		c.cursym.Size = pc
 	}
-	if ctxt.Mode&Mips64 != 0 {
-		c += -c & (mips64FuncAlign - 1)
+	if c.ctxt.Arch.Family == sys.MIPS64 {
+		pc += -pc & (mips64FuncAlign - 1)
 	}
-	cursym.Size = c
+	c.cursym.Size = pc
 
 	/*
 	 * lay out the code, emitting code and data relocations.
 	 */
 
-	cursym.Grow(cursym.Size)
+	c.cursym.Grow(c.cursym.Size)
 
-	bp := cursym.P
+	bp := c.cursym.P
 	var i int32
 	var out [4]uint32
-	for p := cursym.Text.Link; p != nil; p = p.Link {
-		ctxt.Pc = p.Pc
-		ctxt.Curp = p
-		o = oplook(ctxt, p)
+	for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+		c.pc = p.Pc
+		o = c.oplook(p)
 		if int(o.size) > 4*len(out) {
 			log.Fatalf("out array in span0 is too small, need at least %d for %v", o.size/4, p)
 		}
-		asmout(ctxt, p, o, out[:])
+		c.asmout(p, o, out[:])
 		for i = 0; i < int32(o.size/4); i++ {
-			ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
+			c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
 			bp = bp[4:]
 		}
 	}
@@ -503,7 +513,7 @@ func isuint32(v uint64) bool {
 	return uint64(uint32(v)) == v
 }
 
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
+func (c *ctxt0) aclass(a *obj.Addr) int {
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -536,9 +546,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if a.Sym == nil {
 				break
 			}
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Sym != nil { // use relocation
-				if a.Sym.Type == obj.STLSBSS {
+				if a.Sym.Type == objabi.STLSBSS {
 					return C_TLS
 				}
 				return C_ADDR
@@ -546,25 +556,25 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_LEXT
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SAUTO
 			}
 			return C_LAUTO
 
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
-			if ctxt.Instoffset == 0 {
+			c.instoffset = a.Offset
+			if c.instoffset == 0 {
 				return C_ZOREG
 			}
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SOREG
 			}
 			return C_LOREG
@@ -579,12 +589,12 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		obj.TYPE_ADDR:
 		switch a.Name {
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Reg != 0 {
-				if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
+				if -BIG <= c.instoffset && c.instoffset <= BIG {
 					return C_SACON
 				}
-				if isint32(ctxt.Instoffset) {
+				if isint32(c.instoffset) {
 					return C_LACON
 				}
 				return C_DACON
@@ -598,27 +608,23 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if s == nil {
 				break
 			}
-			if s.Type == obj.SCONST {
-				ctxt.Instoffset = a.Offset
-				goto consize
-			}
 
-			ctxt.Instoffset = a.Offset
-			if s.Type == obj.STLSBSS {
+			c.instoffset = a.Offset
+			if s.Type == objabi.STLSBSS {
 				return C_STCON // address of TLS variable
 			}
 			return C_LECON
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SACON
 			}
 			return C_LACON
@@ -627,32 +633,32 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		return C_GOK
 
 	consize:
-		if ctxt.Instoffset >= 0 {
-			if ctxt.Instoffset == 0 {
+		if c.instoffset >= 0 {
+			if c.instoffset == 0 {
 				return C_ZCON
 			}
-			if ctxt.Instoffset <= 0x7fff {
+			if c.instoffset <= 0x7fff {
 				return C_SCON
 			}
-			if ctxt.Instoffset <= 0xffff {
+			if c.instoffset <= 0xffff {
 				return C_ANDCON
 			}
-			if ctxt.Instoffset&0xffff == 0 && isuint32(uint64(ctxt.Instoffset)) { /* && (instoffset & (1<<31)) == 0) */
+			if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && (instoffset & (1<<31)) == 0) */
 				return C_UCON
 			}
-			if isint32(ctxt.Instoffset) || isuint32(uint64(ctxt.Instoffset)) {
+			if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) {
 				return C_LCON
 			}
 			return C_LCON // C_DCON
 		}
 
-		if ctxt.Instoffset >= -0x8000 {
+		if c.instoffset >= -0x8000 {
 			return C_ADDCON
 		}
-		if ctxt.Instoffset&0xffff == 0 && isint32(ctxt.Instoffset) {
+		if c.instoffset&0xffff == 0 && isint32(c.instoffset) {
 			return C_UCON
 		}
-		if isint32(ctxt.Instoffset) {
+		if isint32(c.instoffset) {
 			return C_LCON
 		}
 		return C_LCON // C_DCON
@@ -668,9 +674,9 @@ func prasm(p *obj.Prog) {
 	fmt.Printf("%v\n", p)
 }
 
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+func (c *ctxt0) oplook(p *obj.Prog) *Optab {
 	if oprange[AOR&obj.AMask] == nil {
-		buildop(ctxt)
+		c.ctxt.Diag("mips ops not initialized, call mips.buildop first")
 	}
 
 	a1 := int(p.Optab)
@@ -679,14 +685,14 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	}
 	a1 = int(p.From.Class)
 	if a1 == 0 {
-		a1 = aclass(ctxt, &p.From) + 1
+		a1 = c.aclass(&p.From) + 1
 		p.From.Class = int8(a1)
 	}
 
 	a1--
 	a3 := int(p.To.Class)
 	if a3 == 0 {
-		a3 = aclass(ctxt, &p.To) + 1
+		a3 = c.aclass(&p.To) + 1
 		p.To.Class = int8(a3)
 	}
 
@@ -703,13 +709,13 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	c3 := &xcmp[a3]
 	for i := range ops {
 		op := &ops[i]
-		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && (ctxt.Mode&op.mode == op.mode) {
+		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && (op.family == 0 || c.ctxt.Arch.Family == op.family) {
 			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
 			return op
 		}
 	}
 
-	ctxt.Diag("illegal combination %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
+	c.ctxt.Diag("illegal combination %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
 	prasm(p)
 	if ops == nil {
 		ops = optab
@@ -835,6 +841,13 @@ func opset(a, b0 obj.As) {
 }
 
 func buildop(ctxt *obj.Link) {
+	if oprange[AOR&obj.AMask] != nil {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
 	var n int
 
 	for i := 0; i < C_NCLASS; i++ {
@@ -952,6 +965,7 @@ func buildop(ctxt *obj.Link) {
 
 		case ASYSCALL:
 			opset(ASYNC, r0)
+			opset(ANOOP, r0)
 			opset(ATLBP, r0)
 			opset(ATLBR, r0)
 			opset(ATLBWI, r0)
@@ -983,12 +997,13 @@ func buildop(ctxt *obj.Link) {
 			AJMP,
 			AMOVWU,
 			ALL,
+			ALLV,
 			ASC,
+			ASCV,
 			AWORD,
 			obj.ANOP,
 			obj.ATEXT,
 			obj.AUNDEF,
-			obj.AUSEFIELD,
 			obj.AFUNCDATA,
 			obj.APCDATA,
 			obj.ADUFFZERO,
@@ -1062,7 +1077,7 @@ func OP_JMP(op uint32, i uint32) uint32 {
 	return op | i&0x3FFFFFF
 }
 
-func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
 	o1 := uint32(0)
 	o2 := uint32(0)
 	o3 := uint32(0)
@@ -1070,12 +1085,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	add := AADDU
 
-	if ctxt.Mode&Mips64 != 0 {
+	if c.ctxt.Arch.Family == sys.MIPS64 {
 		add = AADDVU
 	}
 	switch o.type_ {
 	default:
-		ctxt.Diag("unknown type %d %v", o.type_)
+		c.ctxt.Diag("unknown type %d %v", o.type_)
 		prasm(p)
 
 	case 0: /* pseudo ops */
@@ -1083,10 +1098,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 1: /* mov r1,r2 ==> OR r1,r0,r2 */
 		a := AOR
-		if p.As == AMOVW && ctxt.Mode&Mips64 != 0 {
+		if p.As == AMOVW && c.ctxt.Arch.Family == sys.MIPS64 {
 			a = AADDU // sign-extended to high 32 bits
 		}
-		o1 = OP_RRR(oprrr(ctxt, a), uint32(REGZERO), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_RRR(c.oprrr(a), uint32(REGZERO), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 2: /* add/sub r1,[r2],r3 */
 		r := int(p.Reg)
@@ -1094,10 +1109,10 @@ 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, p.As), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
+		o1 = OP_RRR(c.oprrr(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)
+		v := c.regoff(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
@@ -1108,20 +1123,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			a = AOR
 		}
 
-		o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(r), uint32(p.To.Reg))
+		o1 = OP_IRR(c.opirr(a), uint32(v), uint32(r), uint32(p.To.Reg))
 
 	case 4: /* add $scon,[r1],r2 */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 
-		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg))
+		o1 = OP_IRR(c.opirr(p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 
 	case 5: /* syscall */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p.As)
 
 	case 6: /* beq r1,[r2],sbra */
 		v := int32(0)
@@ -1131,9 +1146,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			v = int32(p.Pcond.Pc-p.Pc-4) >> 2
 		}
 		if (v<<16)>>16 != v {
-			ctxt.Diag("short branch too far\n%v", p)
+			c.ctxt.Diag("short branch too far\n%v", p)
 		}
-		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(p.From.Reg), uint32(p.Reg))
+		o1 = OP_IRR(c.opirr(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
@@ -1143,16 +1158,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		v := regoff(ctxt, &p.To)
-		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.From.Reg))
+		v := c.regoff(&p.To)
+		o1 = OP_IRR(c.opirr(p.As), uint32(v), uint32(r), uint32(p.From.Reg))
 
 	case 8: /* mov soreg, r ==> lw o(r) */
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, -p.As), uint32(v), uint32(r), uint32(p.To.Reg))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(-p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 
 	case 9: /* sll r1,[r2],r3 */
 		r := int(p.Reg)
@@ -1160,24 +1175,24 @@ 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, p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_RRR(c.oprrr(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)
+		v := c.regoff(&p.From)
 		a := AOR
 		if v < 0 {
 			a = AADDU
 		}
-		o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(0), uint32(REGTMP))
+		o1 = OP_IRR(c.opirr(a), uint32(v), uint32(0), uint32(REGTMP))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o2 = OP_RRR(oprrr(ctxt, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o2 = OP_RRR(c.oprrr(p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
 
 	case 11: /* jmp lbra */
 		v := int32(0)
-		if aclass(ctxt, &p.To) == C_SBRA && p.To.Sym == nil && p.As == AJMP {
+		if c.aclass(&p.To) == C_SBRA && p.To.Sym == nil && p.As == AJMP {
 			// use PC-relative branch for short branches
 			// BEQ	R0, R0, sbra
 			if p.Pcond == nil {
@@ -1186,7 +1201,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 				v = int32(p.Pcond.Pc-p.Pc-4) >> 2
 			}
 			if (v<<16)>>16 == v {
-				o1 = OP_IRR(opirr(ctxt, ABEQ), uint32(v), uint32(REGZERO), uint32(REGZERO))
+				o1 = OP_IRR(c.opirr(ABEQ), uint32(v), uint32(REGZERO), uint32(REGZERO))
 				break
 			}
 		}
@@ -1195,20 +1210,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else {
 			v = int32(p.Pcond.Pc) >> 2
 		}
-		o1 = OP_JMP(opirr(ctxt, p.As), uint32(v))
+		o1 = OP_JMP(c.opirr(p.As), uint32(v))
 		if p.To.Sym == nil {
-			p.To.Sym = ctxt.Cursym.Text.From.Sym
+			p.To.Sym = c.cursym.Func.Text.From.Sym
 			p.To.Offset = p.Pcond.Pc
 		}
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
 		if p.As == AJAL {
-			rel.Type = obj.R_CALLMIPS
+			rel.Type = objabi.R_CALLMIPS
 		} else {
-			rel.Type = obj.R_JMPMIPS
+			rel.Type = objabi.R_JMPMIPS
 		}
 
 	case 12: /* movbs r,r */
@@ -1216,31 +1231,31 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if p.As == AMOVB {
 			v = 24
 		}
-		o1 = OP_SRR(opirr(ctxt, ASLL), uint32(v), uint32(p.From.Reg), uint32(p.To.Reg))
-		o2 = OP_SRR(opirr(ctxt, ASRA), uint32(v), uint32(p.To.Reg), uint32(p.To.Reg))
+		o1 = OP_SRR(c.opirr(ASLL), uint32(v), uint32(p.From.Reg), uint32(p.To.Reg))
+		o2 = OP_SRR(c.opirr(ASRA), uint32(v), uint32(p.To.Reg), uint32(p.To.Reg))
 
 	case 13: /* movbu r,r */
 		if p.As == AMOVBU {
-			o1 = OP_IRR(opirr(ctxt, AAND), uint32(0xff), uint32(p.From.Reg), uint32(p.To.Reg))
+			o1 = OP_IRR(c.opirr(AAND), uint32(0xff), uint32(p.From.Reg), uint32(p.To.Reg))
 		} else {
-			o1 = OP_IRR(opirr(ctxt, AAND), uint32(0xffff), uint32(p.From.Reg), uint32(p.To.Reg))
+			o1 = OP_IRR(c.opirr(AAND), uint32(0xffff), uint32(p.From.Reg), uint32(p.To.Reg))
 		}
 
 	case 14: /* movwu r,r */
-		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))
+		o1 = OP_SRR(c.opirr(-ASLLV), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
+		o2 = OP_SRR(c.opirr(-ASRLV), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
 
 	case 15: /* teq $c r,r */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := int(p.Reg)
 		if r == 0 {
 			r = REGZERO
 		}
 		/* only use 10 bits of trap code */
-		o1 = OP_IRR(opirr(ctxt, p.As), (uint32(v)&0x3FF)<<6, uint32(p.Reg), uint32(p.To.Reg))
+		o1 = OP_IRR(c.opirr(p.As), (uint32(v)&0x3FF)<<6, uint32(p.Reg), uint32(p.To.Reg))
 
 	case 16: /* sll $c,[r1],r2 */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -1248,29 +1263,29 @@ 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, -p.As), uint32(v-32), uint32(r), uint32(p.To.Reg))
+			o1 = OP_SRR(c.opirr(-p.As), uint32(v-32), uint32(r), uint32(p.To.Reg))
 		} else {
-			o1 = OP_SRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg))
+			o1 = OP_SRR(c.opirr(p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 		}
 
 	case 17:
-		o1 = OP_RRR(oprrr(ctxt, p.As), uint32(REGZERO), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_RRR(c.oprrr(p.As), uint32(REGZERO), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 18: /* jmp [r1],0(r2) */
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		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)
+		o1 = OP_RRR(c.oprrr(p.As), uint32(0), uint32(p.To.Reg), uint32(r))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 0
-		rel.Type = obj.R_CALLIND
+		rel.Type = objabi.R_CALLIND
 
 	case 19: /* mov $lcon,r ==> lu+or */
-		v := regoff(ctxt, &p.From)
-		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))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
+		o2 = OP_IRR(c.opirr(AOR), uint32(v), uint32(p.To.Reg), uint32(p.To.Reg))
 
 	case 20: /* mov lo/hi,r */
 		a := OP(2, 0) /* mfhi */
@@ -1295,44 +1310,44 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			a := SP(3, 4) | 2 /* mul */
 			o1 = OP_RRR(a, uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
 		} else {
-			o1 = OP_RRR(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(p.Reg), uint32(REGZERO))
+			o1 = OP_RRR(c.oprrr(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, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_IRR(c.opirr(AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = OP_RRR(oprrr(ctxt, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o3 = OP_RRR(c.oprrr(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, ALUI), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(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, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(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, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o2 = OP_RRR(c.oprrr(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, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
+		v := c.regoff(&p.From)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_IRR(c.opirr(AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o3 = OP_RRR(oprrr(ctxt, add), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o3 = OP_RRR(c.oprrr(add), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
 
 	case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
@@ -1343,16 +1358,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		switch o.size {
 		case 12:
-			o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
-			o2 = OP_RRR(oprrr(ctxt, add), uint32(r), uint32(REGTMP), uint32(REGTMP))
-			o3 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(REGTMP), uint32(p.To.Reg))
+			o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+			o2 = OP_RRR(c.oprrr(add), uint32(r), uint32(REGTMP), uint32(REGTMP))
+			o3 = OP_IRR(c.opirr(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))
+			o1 = OP_IRR(c.opirr(a), uint32(v), uint32(r), uint32(p.To.Reg))
 		}
 
 	case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
@@ -1363,12 +1378,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 		switch o.size {
 		case 12:
-			o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
-			o2 = OP_RRR(oprrr(ctxt, add), uint32(r), uint32(REGTMP), uint32(REGTMP))
-			o3 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(REGTMP), uint32(p.From.Reg))
+			o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+			o2 = OP_RRR(c.oprrr(add), uint32(r), uint32(REGTMP), uint32(REGTMP))
+			o3 = OP_IRR(c.opirr(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))
+			o1 = OP_IRR(c.opirr(a), uint32(v), uint32(r), uint32(p.From.Reg))
 		}
 
 	case 30: /* movw r,fr */
@@ -1384,39 +1399,39 @@ 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, p.As), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
+		o1 = OP_FRRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
 
 	case 33: /* fabs fr1, fr3 */
-		o1 = OP_FRRR(oprrr(ctxt, p.As), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_FRRR(c.oprrr(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)
+		v := c.regoff(&p.From)
 		a := AADDU
 		if o.a1 == C_ANDCON {
 			a = AOR
 		}
-		o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(0), uint32(REGTMP))
+		o1 = OP_IRR(c.opirr(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(REGTMP) */
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_RRR(oprrr(ctxt, add), uint32(r), uint32(REGTMP), uint32(REGTMP))
-		o3 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(REGTMP), uint32(p.From.Reg))
+		o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_RRR(c.oprrr(add), uint32(r), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(c.opirr(p.As), uint32(v), uint32(REGTMP), uint32(p.From.Reg))
 
 	case 36: /* mov lext/auto/oreg,r ==> lw o(REGTMP) */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_RRR(oprrr(ctxt, add), uint32(r), uint32(REGTMP), uint32(REGTMP))
-		o3 = OP_IRR(opirr(ctxt, -p.As), uint32(v), uint32(REGTMP), uint32(p.To.Reg))
+		o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_RRR(c.oprrr(add), uint32(r), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(c.opirr(-p.As), uint32(v), uint32(REGTMP), uint32(p.To.Reg))
 
 	case 37: /* movw r,mr */
 		a := SP(2, 0) | (4 << 21) /* mtc0 */
@@ -1433,7 +1448,7 @@ 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 40: /* word */
-		o1 = uint32(regoff(ctxt, &p.From))
+		o1 = uint32(c.regoff(&p.From))
 
 	case 41: /* movw f,fcr */
 		o1 = OP_RRR(SP(2, 1)|(2<<21), uint32(REGZERO), uint32(0), uint32(p.To.Reg))    /* mfcc1 */
@@ -1455,68 +1470,68 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	/* relocation operations */
 	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)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(0), uint32(REGZERO), uint32(REGTMP))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
-		rel.Type = obj.R_ADDRMIPSU
-		o2 = OP_IRR(opirr(ctxt, p.As), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
-		rel2 := obj.Addrel(ctxt.Cursym)
-		rel2.Off = int32(ctxt.Pc + 4)
+		rel.Type = objabi.R_ADDRMIPSU
+		o2 = OP_IRR(c.opirr(p.As), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
+		rel2 := obj.Addrel(c.cursym)
+		rel2.Off = int32(c.pc + 4)
 		rel2.Siz = 4
 		rel2.Sym = p.To.Sym
 		rel2.Add = p.To.Offset
-		rel2.Type = obj.R_ADDRMIPS
+		rel2.Type = objabi.R_ADDRMIPS
 
 		if o.size == 12 {
 			o3 = o2
-			o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
+			o2 = OP_RRR(c.oprrr(AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
 			rel2.Off += 4
 		}
 
 	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)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(0), uint32(REGZERO), uint32(REGTMP))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRMIPSU
-		o2 = OP_IRR(opirr(ctxt, -p.As), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
-		rel2 := obj.Addrel(ctxt.Cursym)
-		rel2.Off = int32(ctxt.Pc + 4)
+		rel.Type = objabi.R_ADDRMIPSU
+		o2 = OP_IRR(c.opirr(-p.As), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
+		rel2 := obj.Addrel(c.cursym)
+		rel2.Off = int32(c.pc + 4)
 		rel2.Siz = 4
 		rel2.Sym = p.From.Sym
 		rel2.Add = p.From.Offset
-		rel2.Type = obj.R_ADDRMIPS
+		rel2.Type = objabi.R_ADDRMIPS
 
 		if o.size == 12 {
 			o3 = o2
-			o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
+			o2 = OP_RRR(c.oprrr(AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
 			rel2.Off += 4
 		}
 
 	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)
+		o1 = OP_IRR(c.opirr(ALUI), uint32(0), uint32(REGZERO), uint32(p.To.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRMIPSU
-		o2 = OP_IRR(opirr(ctxt, add), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
-		rel2 := obj.Addrel(ctxt.Cursym)
-		rel2.Off = int32(ctxt.Pc + 4)
+		rel.Type = objabi.R_ADDRMIPSU
+		o2 = OP_IRR(c.opirr(add), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
+		rel2 := obj.Addrel(c.cursym)
+		rel2.Off = int32(c.pc + 4)
 		rel2.Siz = 4
 		rel2.Sym = p.From.Sym
 		rel2.Add = p.From.Offset
-		rel2.Type = obj.R_ADDRMIPS
+		rel2.Type = objabi.R_ADDRMIPS
 
 		if o.size == 12 {
 			o3 = o2
-			o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(p.To.Reg), uint32(p.To.Reg))
+			o2 = OP_RRR(c.oprrr(AADDVU), uint32(REGSB), uint32(p.To.Reg), uint32(p.To.Reg))
 			rel2.Off += 4
 		}
 
@@ -1524,35 +1539,35 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		// 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)
+		o2 = OP_IRR(c.opirr(p.As), uint32(0), uint32(REG_R3), uint32(p.From.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc + 4)
 		rel.Siz = 4
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
-		rel.Type = obj.R_ADDRMIPSTLS
+		rel.Type = objabi.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)
+		o2 = OP_IRR(c.opirr(-p.As), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc + 4)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRMIPSTLS
+		rel.Type = objabi.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, add), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc + 4)
+		o2 = OP_IRR(c.opirr(add), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc + 4)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRMIPSTLS
+		rel.Type = objabi.R_ADDRMIPSTLS
 	}
 
 	out[0] = o1
@@ -1562,17 +1577,17 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	return
 }
 
-func vregoff(ctxt *obj.Link, a *obj.Addr) int64 {
-	ctxt.Instoffset = 0
-	aclass(ctxt, a)
-	return ctxt.Instoffset
+func (c *ctxt0) vregoff(a *obj.Addr) int64 {
+	c.instoffset = 0
+	c.aclass(a)
+	return c.instoffset
 }
 
-func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
-	return int32(vregoff(ctxt, a))
+func (c *ctxt0) regoff(a *obj.Addr) int32 {
+	return int32(c.vregoff(a))
 }
 
-func oprrr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt0) oprrr(a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return OP(4, 0)
@@ -1731,6 +1746,8 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 
 	case ASYNC:
 		return OP(1, 7)
+	case ANOOP:
+		return 0
 
 	case ACMOVN:
 		return OP(1, 3)
@@ -1747,14 +1764,14 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	}
 
 	if a < 0 {
-		ctxt.Diag("bad rrr opcode -%v", -a)
+		c.ctxt.Diag("bad rrr opcode -%v", -a)
 	} else {
-		ctxt.Diag("bad rrr opcode %v", a)
+		c.ctxt.Diag("bad rrr opcode %v", a)
 	}
 	return 0
 }
 
-func opirr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt0) opirr(a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return SP(1, 0)
@@ -1903,14 +1920,18 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
 		return OP(6, 6)
 	case -ALL:
 		return SP(6, 0)
+	case -ALLV:
+		return SP(6, 4)
 	case ASC:
 		return SP(7, 0)
+	case ASCV:
+		return SP(7, 4)
 	}
 
 	if a < 0 {
-		ctxt.Diag("bad irr opcode -%v", -a)
+		c.ctxt.Diag("bad irr opcode -%v", -a)
 	} else {
-		ctxt.Diag("bad irr opcode %v", a)
+		c.ctxt.Diag("bad irr opcode %v", a)
 	}
 	return 0
 }
diff --git a/src/cmd/internal/obj/mips/list0.go b/src/cmd/internal/obj/mips/list0.go
index 4dd5e80..bdd9df9 100644
--- a/src/cmd/internal/obj/mips/list0.go
+++ b/src/cmd/internal/obj/mips/list0.go
@@ -35,11 +35,11 @@ import (
 )
 
 func init() {
-	obj.RegisterRegister(obj.RBaseMIPS, REG_LAST+1, Rconv)
+	obj.RegisterRegister(obj.RBaseMIPS, REG_LAST+1, rconv)
 	obj.RegisterOpcode(obj.ABaseMIPS, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index 12cfb31..ae9d128 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -31,24 +31,15 @@ package mips
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"math"
 )
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
-	// Maintain information about code generation mode.
-	if ctxt.Mode == 0 {
-		switch ctxt.Arch.Family {
-		default:
-			ctxt.Diag("unsupported arch family")
-		case sys.MIPS:
-			ctxt.Mode = Mips32
-		case sys.MIPS64:
-			ctxt.Mode = Mips64
-		}
-	}
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
+	c := ctxt0{ctxt: ctxt, newprog: newprog}
 
 	p.From.Class = 0
 	p.To.Class = 0
@@ -70,36 +61,29 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AMOVF:
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			if i32 == 0 {
+			if math.Float32bits(f32) == 0 {
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REGZERO
 				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 = ctxt.Float32Sym(f32)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
 
 	case AMOVD:
 		if p.From.Type == obj.TYPE_FCONST {
-			i64 := math.Float64bits(p.From.Val.(float64))
-			if i64 == 0 && ctxt.Mode&Mips64 != 0 {
+			f64 := p.From.Val.(float64)
+			if math.Float64bits(f64) == 0 && c.ctxt.Arch.Family == sys.MIPS64 {
 				p.As = AMOVV
 				p.From.Type = obj.TYPE_REG
 				p.From.Reg = REGZERO
 				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 = ctxt.Float64Sym(f64)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -107,11 +91,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		// Put >32-bit constants in memory and load them
 	case AMOVV:
 		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
-			literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
-			s := obj.Linklookup(ctxt, literal, 0)
-			s.Size = 8
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
+			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -145,22 +126,22 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	}
 }
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 	// TODO(minux): add morestack short-cuts with small fixed frame-size.
-	ctxt.Cursym = cursym
+	c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
 
 	// a switch for enabling/disabling instruction scheduling
 	nosched := true
 
-	if cursym.Text == nil || cursym.Text.Link == nil {
+	if c.cursym.Func.Text == nil || c.cursym.Func.Text.Link == nil {
 		return
 	}
 
-	p := cursym.Text
+	p := c.cursym.Func.Text
 	textstksiz := p.To.Offset
 
-	cursym.Args = p.To.Val.(int32)
-	cursym.Locals = int32(textstksiz)
+	c.cursym.Func.Args = p.To.Val.(int32)
+	c.cursym.Func.Locals = int32(textstksiz)
 
 	/*
 	 * find leaf subroutines
@@ -168,13 +149,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	 * expand RET
 	 * expand BECOME pseudo
 	 */
-	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f noops\n", obj.Cputime())
-	}
 
 	var q *obj.Prog
 	var q1 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
 		/* too hard, just leave alone */
 		case obj.ATEXT:
@@ -220,7 +198,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			AJAL,
 			obj.ADUFFZERO,
 			obj.ADUFFCOPY:
-			cursym.Text.Mark &^= LEAF
+			c.cursym.Func.Text.Mark &^= LEAF
 			fallthrough
 
 		case AJMP,
@@ -285,7 +263,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	var mov, add obj.As
-	if ctxt.Mode&Mips64 != 0 {
+	if c.ctxt.Arch.Family == sys.MIPS64 {
 		add = AADDV
 		mov = AMOVV
 	} else {
@@ -296,21 +274,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	autosize := int32(0)
 	var p1 *obj.Prog
 	var p2 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		o := p.As
 		switch o {
 		case obj.ATEXT:
 			autosize = int32(textstksiz + ctxt.FixedFrameSize())
 			if (p.Mark&LEAF != 0) && autosize <= int32(ctxt.FixedFrameSize()) {
 				autosize = 0
-			} else if autosize&4 != 0 && ctxt.Mode&Mips64 != 0 {
+			} else if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
 				autosize += 4
 			}
 
 			p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
 
-			if p.From3.Offset&obj.NOSPLIT == 0 {
-				p = stacksplit(ctxt, p, autosize) // emit split check
+			if !p.From.Sym.NoSplit() {
+				p = c.stacksplit(p, autosize) // emit split check
 			}
 
 			q = p
@@ -321,39 +299,39 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// Store link register before decrement SP, so if a signal comes
 				// during the execution of the function prologue, the traceback
 				// code will not see a half-updated stack frame.
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = mov
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REGLINK
 				q.To.Type = obj.TYPE_MEM
 				q.To.Offset = int64(-autosize)
 				q.To.Reg = REGSP
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = add
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = int64(-autosize)
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REGSP
 				q.Spadj = +autosize
-			} else if cursym.Text.Mark&LEAF == 0 {
-				if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
-					if ctxt.Debugvlog != 0 {
-						ctxt.Logf("save suppressed in: %s\n", cursym.Name)
+			} else if c.cursym.Func.Text.Mark&LEAF == 0 {
+				if c.cursym.Func.Text.From.Sym.NoSplit() {
+					if ctxt.Debugvlog {
+						ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
 					}
 
-					cursym.Text.Mark |= LEAF
+					c.cursym.Func.Text.Mark |= LEAF
 				}
 			}
 
-			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Set(obj.AttrLeaf, true)
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
+				c.cursym.Set(obj.AttrLeaf, true)
 				break
 			}
 
-			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+			if c.cursym.Func.Text.From.Sym.Wrapper() {
 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
 				//
 				//	MOV	g_panic(g), R1
@@ -369,16 +347,16 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// The NOP is needed to give the jumps somewhere to land.
 				// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 
 				q.As = mov
 				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(c.ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = ABEQ
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R1
@@ -386,7 +364,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.Mark |= BRANCH
 				p1 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = mov
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REG_R1
@@ -394,7 +372,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R2
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = add
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
@@ -402,7 +380,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = ABNE
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R2
@@ -411,7 +389,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.Mark |= BRANCH
 				p2 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = add
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = ctxt.FixedFrameSize()
@@ -419,7 +397,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R2
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 				q.As = mov
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R2
@@ -427,7 +405,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Reg = REG_R1
 				q.To.Offset = 0 // Panic.argp
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, newprog)
 
 				q.As = obj.ANOP
 				p1.Pcond = q
@@ -444,7 +422,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
 			p.To.Sym = nil
 
-			if cursym.Text.Mark&LEAF != 0 {
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
 				if autosize == 0 {
 					p.As = AJMP
 					p.From = obj.Addr{}
@@ -468,9 +446,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Reg = REGSP
 				p.Spadj = -autosize
 
-				q = ctxt.NewProg()
+				q = c.newprog()
 				q.As = AJMP
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.To.Type = obj.TYPE_MEM
 				q.To.Offset = 0
 				q.To.Reg = REGLINK
@@ -493,9 +471,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			if autosize != 0 {
-				q = ctxt.NewProg()
+				q = c.newprog()
 				q.As = add
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = int64(autosize)
 				q.To.Type = obj.TYPE_REG
@@ -506,9 +484,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.Link = q
 			}
 
-			q1 = ctxt.NewProg()
+			q1 = c.newprog()
 			q1.As = AJMP
-			q1.Lineno = p.Lineno
+			q1.Pos = p.Pos
 			if retSym != nil { // retjmp
 				q1.To.Type = obj.TYPE_BRANCH
 				q1.To.Name = obj.NAME_EXTERN
@@ -534,9 +512,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		}
 	}
 
-	if ctxt.Mode&Mips32 != 0 {
+	if c.ctxt.Arch.Family == sys.MIPS {
 		// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
-		for p = cursym.Text; p != nil; p = p1 {
+		for p = c.cursym.Func.Text; p != nil; p = p1 {
 			p1 = p.Link
 
 			if p.As != AMOVD {
@@ -547,14 +525,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			p.As = AMOVF
-			q = ctxt.NewProg()
+			q = c.newprog()
 			*q = *p
 			q.Link = p.Link
 			p.Link = q
 			p1 = q.Link
 
 			var regOff int16
-			if ctxt.Arch.ByteOrder == binary.BigEndian {
+			if c.ctxt.Arch.ByteOrder == binary.BigEndian {
 				regOff = 1 // load odd register first
 			}
 			if p.From.Type == obj.TYPE_MEM {
@@ -574,24 +552,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	if nosched {
 		// if we don't do instruction scheduling, simply add
 		// NOP after each branch instruction.
-		for p = cursym.Text; p != nil; p = p.Link {
+		for p = c.cursym.Func.Text; p != nil; p = p.Link {
 			if p.Mark&BRANCH != 0 {
-				addnop(ctxt, p)
+				c.addnop(p)
 			}
 		}
 		return
 	}
 
 	// instruction scheduling
-	q = nil          // p - 1
-	q1 = cursym.Text // top of block
-	o := 0           // count of instructions
-	for p = cursym.Text; p != nil; p = p1 {
+	q = nil                 // p - 1
+	q1 = c.cursym.Func.Text // top of block
+	o := 0                  // count of instructions
+	for p = c.cursym.Func.Text; p != nil; p = p1 {
 		p1 = p.Link
 		o++
 		if p.Mark&NOSCHED != 0 {
 			if q1 != p {
-				sched(ctxt, q1, q)
+				c.sched(q1, q)
 			}
 			for ; p != nil; p = p.Link {
 				if p.Mark&NOSCHED == 0 {
@@ -606,18 +584,18 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		}
 		if p.Mark&(LABEL|SYNC) != 0 {
 			if q1 != p {
-				sched(ctxt, q1, q)
+				c.sched(q1, q)
 			}
 			q1 = p
 			o = 1
 		}
 		if p.Mark&(BRANCH|SYNC) != 0 {
-			sched(ctxt, q1, p)
+			c.sched(q1, p)
 			q1 = p1
 			o = 0
 		}
 		if o >= NSCHED {
-			sched(ctxt, q1, p)
+			c.sched(q1, p)
 			q1 = p1
 			o = 0
 		}
@@ -625,7 +603,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 }
 
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
 	// Leaf function with no frame is effectively NOSPLIT.
 	if framesize == 0 {
 		return p
@@ -633,7 +611,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 
 	var mov, add, sub obj.As
 
-	if ctxt.Mode&Mips64 != 0 {
+	if c.ctxt.Arch.Family == sys.MIPS64 {
 		add = AADDV
 		mov = AMOVV
 		sub = ASUBVU
@@ -644,23 +622,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// MOV	g_stackguard(g), R1
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = mov
 	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.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
+	if c.cursym.CFunc() {
+		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
 
 	var q *obj.Prog
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP < stackguard
 		//	AGTU	SP, stackguard, R1
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ASGTU
 		p.From.Type = obj.TYPE_REG
@@ -668,20 +646,20 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.Reg = REG_R1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R1
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize < stackguard-StackSmall
-		//	ADD	$-framesize, SP, R2
+		//	ADD	$-(framesize-StackSmall), SP, R2
 		//	SGTU	R2, stackguard, R1
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = add
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(-framesize)
+		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ASGTU
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R2
@@ -704,15 +682,15 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		//	SUB	R1, R2
 		//	MOV	$(framesize+(StackGuard-StackSmall)), R1
 		//	SGTU	R2, R1, R1
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = mov
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackPreempt
+		p.From.Offset = objabi.StackPreempt
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		q = p
 		p.As = ABEQ
 		p.From.Type = obj.TYPE_REG
@@ -721,29 +699,29 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Type = obj.TYPE_BRANCH
 		p.Mark |= BRANCH
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = add
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = sub
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R1
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R2
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = mov
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
+		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R1
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ASGTU
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R2
@@ -753,7 +731,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// q1: BNE	R1, done
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 	q1 := p
 
 	p.As = ABNE
@@ -763,7 +741,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	p.Mark |= BRANCH
 
 	// MOV	LINK, R3
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = mov
 	p.From.Type = obj.TYPE_REG
@@ -776,29 +754,29 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// JAL	runtime.morestack(SB)
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = AJAL
 	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)
+	if c.cursym.CFunc() {
+		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
+	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
 	} else {
-		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
+		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
 	}
 	p.Mark |= BRANCH
 
 	// JMP	start
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = AJMP
 	p.To.Type = obj.TYPE_BRANCH
-	p.Pcond = ctxt.Cursym.Text.Link
+	p.Pcond = c.cursym.Func.Text.Link
 	p.Mark |= BRANCH
 
 	// placeholder for q1's jump target
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = obj.ANOP // zero-width place holder
 	q1.Pcond = p
@@ -806,18 +784,10 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	return p
 }
 
-func addnop(ctxt *obj.Link, p *obj.Prog) {
-	q := ctxt.NewProg()
-	// we want to use the canonical NOP (SLL $0,R0,R0) here,
-	// however, as the assembler will always replace $0
-	// as R0, we have to resort to manually encode the SLL
-	// instruction as WORD $0.
-	q.As = AWORD
-	q.Lineno = p.Lineno
-	q.From.Type = obj.TYPE_CONST
-	q.From.Name = obj.NAME_NONE
-	q.From.Offset = 0
-
+func (c *ctxt0) addnop(p *obj.Prog) {
+	q := c.newprog()
+	q.As = ANOOP
+	q.Pos = p.Pos
 	q.Link = p.Link
 	p.Link = q
 }
@@ -850,7 +820,7 @@ type Sch struct {
 	comp    bool
 }
 
-func sched(ctxt *obj.Link, p0, pe *obj.Prog) {
+func (c *ctxt0) sched(p0, pe *obj.Prog) {
 	var sch [NSCHED]Sch
 
 	/*
@@ -859,7 +829,7 @@ func sched(ctxt *obj.Link, p0, pe *obj.Prog) {
 	s := sch[:]
 	for p := p0; ; p = p.Link {
 		s[0].p = *p
-		markregused(ctxt, &s[0])
+		c.markregused(&s[0])
 		if p == pe {
 			break
 		}
@@ -893,7 +863,7 @@ func sched(ctxt *obj.Link, p0, pe *obj.Prog) {
 				}
 			}
 			for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
-				if depend(ctxt, &u[0], &t[0]) {
+				if c.depend(&u[0], &t[0]) {
 					goto no2
 				}
 			}
@@ -935,14 +905,14 @@ func sched(ctxt *obj.Link, p0, pe *obj.Prog) {
 		}
 		for s[0].nop != 0 {
 			s[0].nop--
-			addnop(ctxt, p)
+			c.addnop(p)
 		}
 	}
 }
 
-func markregused(ctxt *obj.Link, s *Sch) {
+func (c *ctxt0) markregused(s *Sch) {
 	p := &s.p
-	s.comp = compound(ctxt, p)
+	s.comp = c.compound(p)
 	s.nop = 0
 	if s.comp {
 		s.set.ireg |= 1 << (REGTMP - REG_R0)
@@ -959,15 +929,15 @@ func markregused(ctxt *obj.Link, s *Sch) {
 	 */
 	switch p.As {
 	case obj.ATEXT:
-		ctxt.Autosize = int32(p.To.Offset + 8)
+		c.autosize = int32(p.To.Offset + 8)
 		ad = 1
 
 	case AJAL:
-		c := p.Reg
-		if c == 0 {
-			c = REGLINK
+		r := p.Reg
+		if r == 0 {
+			r = REGLINK
 		}
-		s.set.ireg |= 1 << uint(c-REG_R0)
+		s.set.ireg |= 1 << uint(r-REG_R0)
 		ar = 1
 		ad = 1
 
@@ -1086,15 +1056,15 @@ func markregused(ctxt *obj.Link, s *Sch) {
 	/*
 	 * flags based on 'to' field
 	 */
-	c := int(p.To.Class)
-	if c == 0 {
-		c = aclass(ctxt, &p.To) + 1
-		p.To.Class = int8(c)
+	cls := int(p.To.Class)
+	if cls == 0 {
+		cls = c.aclass(&p.To) + 1
+		p.To.Class = int8(cls)
 	}
-	c--
-	switch c {
+	cls--
+	switch cls {
 	default:
-		fmt.Printf("unknown class %d %v\n", c, p)
+		fmt.Printf("unknown class %d %v\n", cls, p)
 
 	case C_ZCON,
 		C_SCON,
@@ -1124,19 +1094,19 @@ func markregused(ctxt *obj.Link, s *Sch) {
 	case C_ZOREG,
 		C_SOREG,
 		C_LOREG:
-		c = int(p.To.Reg)
-		s.used.ireg |= 1 << uint(c-REG_R0)
+		cls = int(p.To.Reg)
+		s.used.ireg |= 1 << uint(cls-REG_R0)
 		if ad != 0 {
 			break
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.To)
+		s.soffset = c.regoff(&p.To)
 
 		m := uint32(ANYMEM)
-		if c == REGSB {
+		if cls == REGSB {
 			m = E_MEMSB
 		}
-		if c == REGSP {
+		if cls == REGSP {
 			m = E_MEMSP
 		}
 
@@ -1178,7 +1148,7 @@ func markregused(ctxt *obj.Link, s *Sch) {
 			break
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.To)
+		s.soffset = c.regoff(&p.To)
 
 		if ar != 0 {
 			s.used.cc |= E_MEMSP
@@ -1193,7 +1163,7 @@ func markregused(ctxt *obj.Link, s *Sch) {
 			break
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.To)
+		s.soffset = c.regoff(&p.To)
 
 		if ar != 0 {
 			s.used.cc |= E_MEMSB
@@ -1205,15 +1175,15 @@ func markregused(ctxt *obj.Link, s *Sch) {
 	/*
 	 * flags based on 'from' field
 	 */
-	c = int(p.From.Class)
-	if c == 0 {
-		c = aclass(ctxt, &p.From) + 1
-		p.From.Class = int8(c)
+	cls = int(p.From.Class)
+	if cls == 0 {
+		cls = c.aclass(&p.From) + 1
+		p.From.Class = int8(cls)
 	}
-	c--
-	switch c {
+	cls--
+	switch cls {
 	default:
-		fmt.Printf("unknown class %d %v\n", c, p)
+		fmt.Printf("unknown class %d %v\n", cls, p)
 
 	case C_ZCON,
 		C_SCON,
@@ -1243,19 +1213,19 @@ func markregused(ctxt *obj.Link, s *Sch) {
 	case C_ZOREG,
 		C_SOREG,
 		C_LOREG:
-		c = int(p.From.Reg)
-		s.used.ireg |= 1 << uint(c-REG_R0)
+		cls = int(p.From.Reg)
+		s.used.ireg |= 1 << uint(cls-REG_R0)
 		if ld != 0 {
 			p.Mark |= LOAD
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.From)
+		s.soffset = c.regoff(&p.From)
 
 		m := uint32(ANYMEM)
-		if c == REGSB {
+		if cls == REGSB {
 			m = E_MEMSB
 		}
-		if c == REGSP {
+		if cls == REGSP {
 			m = E_MEMSP
 		}
 
@@ -1263,11 +1233,11 @@ func markregused(ctxt *obj.Link, s *Sch) {
 
 	case C_SACON,
 		C_LACON:
-		c = int(p.From.Reg)
-		if c == 0 {
-			c = REGSP
+		cls = int(p.From.Reg)
+		if cls == 0 {
+			cls = REGSP
 		}
-		s.used.ireg |= 1 << uint(c-REG_R0)
+		s.used.ireg |= 1 << uint(cls-REG_R0)
 
 	case C_SECON,
 		C_LECON:
@@ -1292,7 +1262,7 @@ func markregused(ctxt *obj.Link, s *Sch) {
 			break
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.From)
+		s.soffset = c.regoff(&p.From)
 
 		s.used.cc |= E_MEMSP
 
@@ -1306,17 +1276,17 @@ func markregused(ctxt *obj.Link, s *Sch) {
 			break
 		}
 		s.size = uint8(sz)
-		s.soffset = regoff(ctxt, &p.From)
+		s.soffset = c.regoff(&p.From)
 
 		s.used.cc |= E_MEMSB
 	}
 
-	c = int(p.Reg)
-	if c != 0 {
-		if REG_F0 <= c && c <= REG_F31 {
-			s.used.freg |= 1 << uint(c-REG_F0)
+	cls = int(p.Reg)
+	if cls != 0 {
+		if REG_F0 <= cls && cls <= REG_F31 {
+			s.used.freg |= 1 << uint(cls-REG_F0)
 		} else {
-			s.used.ireg |= 1 << uint(c-REG_R0)
+			s.used.ireg |= 1 << uint(cls-REG_R0)
 		}
 	}
 	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
@@ -1326,7 +1296,7 @@ func markregused(ctxt *obj.Link, s *Sch) {
  * test to see if two instructions can be
  * interchanged without changing semantics
  */
-func depend(ctxt *obj.Link, sa, sb *Sch) bool {
+func (c *ctxt0) depend(sa, sb *Sch) bool {
 	if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
 		return true
 	}
@@ -1348,7 +1318,7 @@ func depend(ctxt *obj.Link, sa, sb *Sch) bool {
 	 */
 	if sa.used.cc&sb.used.cc&E_MEM != 0 {
 		if sa.p.Reg == sb.p.Reg {
-			if regoff(ctxt, &sa.p.From) == regoff(ctxt, &sb.p.From) {
+			if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
 				return true
 			}
 		}
@@ -1407,8 +1377,8 @@ func conflict(sa, sb *Sch) bool {
 	return false
 }
 
-func compound(ctxt *obj.Link, p *obj.Prog) bool {
-	o := oplook(ctxt, p)
+func (c *ctxt0) compound(p *obj.Prog) bool {
+	o := c.oplook(p)
 	if o.size != 4 {
 		return true
 	}
@@ -1418,174 +1388,34 @@ func compound(ctxt *obj.Link, p *obj.Prog) bool {
 	return false
 }
 
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
-	firstp := ctxt.NewProg()
-	lastp := firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
-	var q *obj.Prog
-	var r *obj.Prog
-	var i int
-
-loop:
-	if p == nil {
-		return
-	}
-	a := p.As
-	if a == AJMP {
-		q = p.Pcond
-		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
-			p.Mark |= FOLL
-			(*last).Link = p
-			*last = p
-			p = p.Link
-			xfol(ctxt, p, last)
-			p = q
-			if p != nil && p.Mark&FOLL == 0 {
-				goto loop
-			}
-			return
-		}
-
-		if q != nil {
-			p.Mark |= FOLL
-			p = q
-			if p.Mark&FOLL == 0 {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark&FOLL != 0 {
-		i = 0
-		q = p
-		for ; i < 4; i, q = i+1, q.Link {
-			if q == *last || (q.Mark&NOSCHED != 0) {
-				break
-			}
-			a = q.As
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if a == AJMP || a == ARET || a == ARFE {
-				goto copy
-			}
-			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
-				continue
-			}
-			if a != ABEQ && a != ABNE {
-				continue
-			}
-
-		copy:
-			for {
-				r = ctxt.NewProg()
-				*r = *p
-				if r.Mark&FOLL == 0 {
-					fmt.Printf("can't happen 1\n")
-				}
-				r.Mark |= FOLL
-				if p != q {
-					p = p.Link
-					(*last).Link = r
-					*last = r
-					continue
-				}
-
-				(*last).Link = r
-				*last = r
-				if a == AJMP || a == ARET || a == ARFE {
-					return
-				}
-				r.As = ABNE
-				if a == ABNE {
-					r.As = ABEQ
-				}
-				r.Pcond = p.Link
-				r.Link = p.Pcond
-				if r.Link.Mark&FOLL == 0 {
-					xfol(ctxt, r.Link, last)
-				}
-				if r.Pcond.Mark&FOLL == 0 {
-					fmt.Printf("can't happen 2\n")
-				}
-				return
-			}
-		}
-
-		a = AJMP
-		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
-	if a == AJMP || a == ARET || a == ARFE {
-		if p.Mark&NOSCHED != 0 {
-			p = p.Link
-			goto loop
-		}
-
-		return
-	}
-
-	if p.Pcond != nil {
-		if a != AJAL && p.Link != nil {
-			xfol(ctxt, p.Link, last)
-			p = p.Pcond
-			if p == nil || (p.Mark&FOLL != 0) {
-				return
-			}
-			goto loop
-		}
-	}
-
-	p = p.Link
-	goto loop
-}
-
 var Linkmips64 = obj.LinkArch{
 	Arch:       sys.ArchMIPS64,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span0,
-	Follow:     follow,
 	Progedit:   progedit,
 }
 
 var Linkmips64le = obj.LinkArch{
 	Arch:       sys.ArchMIPS64LE,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span0,
-	Follow:     follow,
 	Progedit:   progedit,
 }
 
 var Linkmips = obj.LinkArch{
 	Arch:       sys.ArchMIPS,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span0,
-	Follow:     follow,
 	Progedit:   progedit,
 }
 
 var Linkmipsle = obj.LinkArch{
 	Arch:       sys.ArchMIPSLE,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span0,
-	Follow:     follow,
 	Progedit:   progedit,
 }
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index eb56c6f..e309c5f 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -3,115 +3,13 @@
 // license that can be found in the LICENSE file.
 
 // Writing of Go object files.
-//
-// Originally, Go object files were Plan 9 object files, but no longer.
-// Now they are more like standard object files, in that each symbol is defined
-// by an associated memory image (bytes) and a list of relocations to apply
-// during linking. We do not (yet?) use a standard file format, however.
-// For now, the format is chosen to be as simple as possible to read and write.
-// It may change for reasons of efficiency, or we may even switch to a
-// standard file format if there are compelling benefits to doing so.
-// See golang.org/s/go13linker for more background.
-//
-// The file format is:
-//
-//	- magic header: "\x00\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\xffgo17ld"
-//
-// All integers are stored in a zigzag varint format.
-// See golang.org/s/go12symtab for a definition.
-//
-// Data blocks and strings are both stored as an integer
-// followed by that many bytes.
-//
-// A symbol reference is a string name followed by a version.
-//
-// 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 & version [symref index]
-//	- flags [int]
-//		1<<0 dupok
-//		1<<1 local
-//		1<<2 add to typelink table
-//	- size [int]
-//	- gotype [symref index]
-//	- p [data block]
-//	- nr [int]
-//	- r [nr relocations, sorted by off]
-//
-// If type == STEXT, there are a few more fields:
-//
-//	- args [int]
-//	- locals [int]
-//	- nosplit [int]
-//	- flags [int]
-//		1<<0 leaf
-//		1<<1 C function
-//		1<<2 function may call reflect.Type.Method
-//	- nlocal [int]
-//	- local [nlocal automatics]
-//	- pcln [pcln table]
-//
-// Each relocation has the encoding:
-//
-//	- off [int]
-//	- siz [int]
-//	- type [int]
-//	- add [int]
-//	- sym [symref index]
-//
-// Each local has the encoding:
-//
-//	- asym [symref index]
-//	- offset [int]
-//	- type [int]
-//	- gotype [symref index]
-//
-// The pcln table has the encoding:
-//
-//	- pcsp [data block]
-//	- pcfile [data block]
-//	- pcline [data block]
-//	- npcdata [int]
-//	- pcdata [npcdata data blocks]
-//	- nfuncdata [int]
-//	- funcdata [nfuncdata symref index]
-//	- funcdatasym [nfuncdata ints]
-//	- nfile [int]
-//	- 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.
 
 package obj
 
 import (
 	"bufio"
 	"cmd/internal/dwarf"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"log"
@@ -119,14 +17,6 @@ import (
 	"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
-// does not write out object files.
-func Writeobjdirect(ctxt *Link, b *bufio.Writer) {
-	Flushplist(ctxt)
-	WriteObjFile(ctxt, b)
-}
-
 // objWriter writes Go object files.
 type objWriter struct {
 	wr   *bufio.Writer
@@ -134,7 +24,7 @@ type objWriter struct {
 	// Temporary buffer for zigzag int writing.
 	varintbuf [10]uint8
 
-	// Provide the the index of a symbol reference by symbol name.
+	// Provide 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
@@ -154,16 +44,17 @@ func (w *objWriter) addLengths(s *LSym) {
 	w.nData += len(s.P)
 	w.nReloc += len(s.R)
 
-	if s.Type != STEXT {
+	if s.Type != objabi.STEXT {
 		return
 	}
 
-	pc := s.Pcln
+	pc := &s.Func.Pcln
 
 	data := 0
 	data += len(pc.Pcsp.P)
 	data += len(pc.Pcfile.P)
 	data += len(pc.Pcline.P)
+	data += len(pc.Pcinline.P)
 	for i := 0; i < len(pc.Pcdata); i++ {
 		data += len(pc.Pcdata[i].P)
 	}
@@ -171,11 +62,7 @@ func (w *objWriter) addLengths(s *LSym) {
 	w.nData += data
 	w.nPcdata += len(pc.Pcdata)
 
-	autom := 0
-	for a := s.Autom; a != nil; a = a.Link {
-		autom++
-	}
-	w.nAutom += autom
+	w.nAutom += len(s.Func.Autom)
 	w.nFuncdata += len(pc.Funcdataoff)
 	w.nFile += len(pc.File)
 }
@@ -202,7 +89,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
 	w := newObjWriter(ctxt, b)
 
 	// Magic header
-	w.wr.WriteString("\x00\x00go17ld")
+	w.wr.WriteString("\x00\x00go19ld")
 
 	// Version
 	w.wr.WriteByte(1)
@@ -231,15 +118,22 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
 	// Data block
 	for _, s := range ctxt.Text {
 		w.wr.Write(s.P)
-		pc := s.Pcln
+		pc := &s.Func.Pcln
 		w.wr.Write(pc.Pcsp.P)
 		w.wr.Write(pc.Pcfile.P)
 		w.wr.Write(pc.Pcline.P)
+		w.wr.Write(pc.Pcinline.P)
 		for i := 0; i < len(pc.Pcdata); i++ {
 			w.wr.Write(pc.Pcdata[i].P)
 		}
 	}
 	for _, s := range ctxt.Data {
+		if len(s.P) > 0 {
+			switch s.Type {
+			case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
+				ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
+			}
+		}
 		w.wr.Write(s.P)
 	}
 
@@ -252,7 +146,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
 	}
 
 	// Magic footer
-	w.wr.WriteString("\xff\xffgo17ld")
+	w.wr.WriteString("\xff\xffgo19ld")
 }
 
 // Symbols are prefixed so their content doesn't get confused with the magic footer.
@@ -263,17 +157,13 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
 		return
 	}
 	var m map[string]int
-	switch s.Version {
-	case 0:
+	if !s.Static() {
 		m = w.refIdx
-	case 1:
+	} else {
 		m = w.vrefIdx
-	default:
-		log.Fatalf("%s: invalid version number %d", s.Name, s.Version)
 	}
 
-	idx := m[s.Name]
-	if idx != 0 {
+	if idx := m[s.Name]; idx != 0 {
 		s.RefIdx = idx
 		return
 	}
@@ -283,7 +173,12 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
 	} else {
 		w.writeString(s.Name)
 	}
-	w.writeInt(int64(s.Version))
+	// Write "version".
+	if s.Static() {
+		w.writeInt(1)
+	} else {
+		w.writeInt(0)
+	}
 	w.nRefs++
 	s.RefIdx = w.nRefs
 	m[s.Name] = w.nRefs
@@ -296,17 +191,24 @@ func (w *objWriter) writeRefs(s *LSym) {
 		w.writeRef(s.R[i].Sym, false)
 	}
 
-	if s.Type == STEXT {
-		for a := s.Autom; a != nil; a = a.Link {
+	if s.Type == objabi.STEXT {
+		for _, a := range s.Func.Autom {
 			w.writeRef(a.Asym, false)
 			w.writeRef(a.Gotype, false)
 		}
-		pc := s.Pcln
+		pc := &s.Func.Pcln
 		for _, d := range pc.Funcdata {
 			w.writeRef(d, false)
 		}
 		for _, f := range pc.File {
-			w.writeRef(f, true)
+			fsym := w.ctxt.Lookup(f)
+			w.writeRef(fsym, true)
+		}
+		for _, call := range pc.InlTree.nodes {
+			w.writeRef(call.Func, false)
+			f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
+			fsym := w.ctxt.Lookup(f)
+			w.writeRef(fsym, true)
 		}
 	}
 }
@@ -314,11 +216,11 @@ func (w *objWriter) writeRefs(s *LSym) {
 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)
+		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
+	}
+	if s.Static() {
+		fmt.Fprint(ctxt.Bso, "static ")
 	}
 	if s.DuplicateOK() {
 		fmt.Fprintf(ctxt.Bso, "dupok ")
@@ -330,21 +232,21 @@ func (w *objWriter) writeSymDebug(s *LSym) {
 		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.Type == objabi.STEXT {
+		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals))
 		if s.Leaf() {
 			fmt.Fprintf(ctxt.Bso, " leaf")
 		}
 	}
-
 	fmt.Fprintf(ctxt.Bso, "\n")
-	for p := s.Text; p != nil; p = p.Link {
-		fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
+	if s.Type == objabi.STEXT {
+		for p := s.Func.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); {
+	for i := 0; i < len(s.P); i += 16 {
 		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
+		j := i
 		for j = i; j < i+16 && j < len(s.P); j++ {
 			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
 		}
@@ -353,7 +255,7 @@ func (w *objWriter) writeSymDebug(s *LSym) {
 		}
 		fmt.Fprintf(ctxt.Bso, "  ")
 		for j = i; j < i+16 && j < len(s.P); j++ {
-			c = int(s.P[j])
+			c := int(s.P[j])
 			if ' ' <= c && c <= 0x7e {
 				fmt.Fprintf(ctxt.Bso, "%c", c)
 			} else {
@@ -362,7 +264,6 @@ func (w *objWriter) writeSymDebug(s *LSym) {
 		}
 
 		fmt.Fprintf(ctxt.Bso, "\n")
-		i += 16
 	}
 
 	sort.Sort(relocByOff(s.R)) // generate stable output
@@ -370,7 +271,7 @@ func (w *objWriter) writeSymDebug(s *LSym) {
 		name := ""
 		if r.Sym != nil {
 			name = r.Sym.Name
-		} else if r.Type == R_TLS_LE {
+		} else if r.Type == objabi.R_TLS_LE {
 			name = "TLS"
 		}
 		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
@@ -383,12 +284,12 @@ func (w *objWriter) writeSymDebug(s *LSym) {
 
 func (w *objWriter) writeSym(s *LSym) {
 	ctxt := w.ctxt
-	if ctxt.Debugasm != 0 {
+	if ctxt.Debugasm {
 		w.writeSymDebug(s)
 	}
 
 	w.wr.WriteByte(symPrefix)
-	w.writeInt(int64(s.Type))
+	w.wr.WriteByte(byte(s.Type))
 	w.writeRefIndex(s)
 	flags := int64(0)
 	if s.DuplicateOK() {
@@ -416,12 +317,12 @@ func (w *objWriter) writeSym(s *LSym) {
 		w.writeRefIndex(r.Sym)
 	}
 
-	if s.Type != STEXT {
+	if s.Type != objabi.STEXT {
 		return
 	}
 
-	w.writeInt(int64(s.Args))
-	w.writeInt(int64(s.Locals))
+	w.writeInt(int64(s.Func.Args))
+	w.writeInt(int64(s.Func.Locals))
 	if s.NoSplit() {
 		w.writeInt(1)
 	} else {
@@ -437,29 +338,29 @@ func (w *objWriter) writeSym(s *LSym) {
 	if s.ReflectMethod() {
 		flags |= 1 << 2
 	}
-	w.writeInt(flags)
-	n := 0
-	for a := s.Autom; a != nil; a = a.Link {
-		n++
+	if ctxt.Flag_shared {
+		flags |= 1 << 3
 	}
-	w.writeInt(int64(n))
-	for a := s.Autom; a != nil; a = a.Link {
+	w.writeInt(flags)
+	w.writeInt(int64(len(s.Func.Autom)))
+	for _, a := range s.Func.Autom {
 		w.writeRefIndex(a.Asym)
 		w.writeInt(int64(a.Aoffset))
 		if a.Name == NAME_AUTO {
-			w.writeInt(A_AUTO)
+			w.writeInt(objabi.A_AUTO)
 		} else if a.Name == NAME_PARAM {
-			w.writeInt(A_PARAM)
+			w.writeInt(objabi.A_PARAM)
 		} else {
 			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
 		}
 		w.writeRefIndex(a.Gotype)
 	}
 
-	pc := s.Pcln
+	pc := &s.Func.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.Pcinline.P)))
 	w.writeInt(int64(len(pc.Pcdata)))
 	for i := 0; i < len(pc.Pcdata); i++ {
 		w.writeInt(int64(len(pc.Pcdata[i].P)))
@@ -473,7 +374,17 @@ func (w *objWriter) writeSym(s *LSym) {
 	}
 	w.writeInt(int64(len(pc.File)))
 	for _, f := range pc.File {
-		w.writeRefIndex(f)
+		fsym := ctxt.Lookup(f)
+		w.writeRefIndex(fsym)
+	}
+	w.writeInt(int64(len(pc.InlTree.nodes)))
+	for _, call := range pc.InlTree.nodes {
+		w.writeInt(int64(call.Parent))
+		f, l := linkgetlineFromPos(w.ctxt, call.Pos)
+		fsym := ctxt.Lookup(f)
+		w.writeRefIndex(fsym)
+		w.writeInt(int64(l))
+		w.writeRefIndex(call.Func)
 	}
 }
 
@@ -536,70 +447,52 @@ func (c dwCtxt) SymValue(s dwarf.Sym) int64 {
 	return 0
 }
 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
-	rsym := data.(*LSym)
 	ls := s.(*LSym)
 	size := c.PtrSize()
-	ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
+	if data != nil {
+		rsym := data.(*LSym)
+		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
+	} else {
+		ls.WriteInt(c.Link, ls.Size, size, value)
+	}
 }
 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
 	ls := s.(*LSym)
 	rsym := t.(*LSym)
 	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
 	r := &ls.R[len(ls.R)-1]
-	r.Type = R_DWARFREF
+	r.Type = objabi.R_DWARFREF
 }
 
-func gendwarf(ctxt *Link, text []*LSym) []*LSym {
-	dctxt := dwCtxt{ctxt}
-	var dw []*LSym
+// dwarfSym returns the DWARF symbols for TEXT symbol.
+func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfRangesSym *LSym) {
+	if s.Type != objabi.STEXT {
+		ctxt.Diag("dwarfSym of non-TEXT %v", s)
+	}
+	if s.Func.dwarfSym == nil {
+		s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
+		s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
+	}
+	return s.Func.dwarfSym, s.Func.dwarfRangesSym
+}
 
-	for _, s := range text {
-		dsym := Linklookup(ctxt, dwarf.InfoPrefix+s.Name, int(s.Version))
-		if dsym.Size != 0 {
-			continue
-		}
-		dw = append(dw, dsym)
-		dsym.Type = SDWARFINFO
-		dsym.Set(AttrDuplicateOK, s.DuplicateOK())
-		var vars dwarf.Var
-		var abbrev int
-		var offs int32
-		for a := s.Autom; a != nil; a = a.Link {
-			switch a.Name {
-			case NAME_AUTO:
-				abbrev = dwarf.DW_ABRV_AUTO
-				offs = a.Aoffset
-				if ctxt.FixedFrameSize() == 0 {
-					offs -= int32(ctxt.Arch.PtrSize)
-				}
-				if Framepointer_enabled(GOOS, GOARCH) {
-					offs -= int32(ctxt.Arch.PtrSize)
-				}
-
-			case NAME_PARAM:
-				abbrev = dwarf.DW_ABRV_PARAM
-				offs = a.Aoffset + int32(ctxt.FixedFrameSize())
-
-			default:
-				continue
-			}
-			typename := dwarf.InfoPrefix + a.Gotype.Name[len("type."):]
-			dwvar := &dwarf.Var{
-				Name:   a.Asym.Name,
-				Abbrev: abbrev,
-				Offset: int32(offs),
-				Type:   Linklookup(ctxt, typename, 0),
-			}
-			dws := &vars.Link
-			for ; *dws != nil; dws = &(*dws).Link {
-				if offs <= (*dws).Offset {
-					break
-				}
-			}
-			dwvar.Link = *dws
-			*dws = dwvar
-		}
-		dwarf.PutFunc(dctxt, dsym, s.Name, s.Version == 0, s, s.Size, vars.Link)
+func (s *LSym) Len() int64 {
+	return s.Size
+}
+
+// populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
+// The DWARFs symbol must already have been initialized in InitTextSym.
+func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
+	dsym, drsym := ctxt.dwarfSym(s)
+	if dsym.Size != 0 {
+		ctxt.Diag("makeFuncDebugEntry double process %v", s)
+	}
+	var scopes []dwarf.Scope
+	if ctxt.DebugInfo != nil {
+		scopes = ctxt.DebugInfo(s, curfn)
+	}
+	err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, !s.Static(), s, s.Size, scopes)
+	if err != nil {
+		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
 	}
-	return dw
 }
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index 1d2f74b..7cc187d 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -32,59 +32,40 @@ package obj
 
 // Code and data passes.
 
-func Brchain(ctxt *Link, p *Prog) *Prog {
-	for i := 0; i < 20; i++ {
-		if p == nil || p.As != AJMP || p.Pcond == nil {
-			return p
-		}
-		p = p.Pcond
-	}
-
-	return nil
-}
-
-func brloop(ctxt *Link, p *Prog) *Prog {
-	var q *Prog
-
+// brloop returns the ultimate destination of the series of unconditional jumps beginning at p.
+// In the case of an infinite loop, brloop returns nil.
+func brloop(p *Prog) *Prog {
 	c := 0
-	for q = p; q != nil; q = q.Pcond {
+	for q := p; q != nil; q = q.Pcond {
 		if q.As != AJMP || q.Pcond == nil {
-			break
+			return q
 		}
 		c++
 		if c >= 5000 {
+			// infinite loop
 			return nil
 		}
 	}
-
-	return q
+	panic("unreachable")
 }
 
+// checkaddr checks that a has an expected encoding, especially TYPE_CONST vs TYPE_ADDR.
 func checkaddr(ctxt *Link, p *Prog, a *Addr) {
-	// Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
 	switch a.Type {
-	case TYPE_NONE:
+	case TYPE_NONE, TYPE_REGREG2, TYPE_REGLIST:
 		return
 
-	case TYPE_BRANCH:
+	case TYPE_BRANCH, TYPE_TEXTSIZE:
 		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
 			break
 		}
 		return
 
-	case TYPE_TEXTSIZE:
-		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
-			break
-		}
-		return
-
-		//if(a->u.bits != 0)
-	//	break;
 	case TYPE_MEM:
 		return
 
-		// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
 	case TYPE_CONST:
+		// TODO(rsc): After fixing SHRQ, check a.Index != 0 too.
 		if a.Name != 0 || a.Sym != nil || a.Reg != 0 {
 			ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p)
 			return
@@ -101,9 +82,9 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
 		}
 		return
 
-	// TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
-	// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
 	case TYPE_REG:
+		// TODO(rsc): After fixing PINSRQ, check a.Offset != 0 too.
+		// TODO(rsc): After fixing SHRQ, check a.Index != 0 too.
 		if a.Scale != 0 || a.Name != 0 || a.Sym != nil {
 			break
 		}
@@ -118,27 +99,15 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
 		}
 		return
 
-	case TYPE_SHIFT:
-		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
-			break
-		}
-		return
-
-	case TYPE_REGREG:
+	case TYPE_SHIFT, TYPE_REGREG:
 		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
 			break
 		}
 		return
 
-	case TYPE_REGREG2:
-		return
-
-	case TYPE_REGLIST:
-		return
-
-	// Expect sym and name to be set, nothing else.
-	// Technically more is allowed, but this is only used for *name(SB).
 	case TYPE_INDIR:
+		// Expect sym and name to be set, nothing else.
+		// Technically more is allowed, but this is only used for *name(SB).
 		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil {
 			break
 		}
@@ -148,14 +117,12 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
 	ctxt.Diag("invalid encoding for argument %v", p)
 }
 
-func linkpatch(ctxt *Link, sym *LSym) {
+func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
 	var c int32
 	var name string
 	var q *Prog
 
-	ctxt.Cursym = sym
-
-	for p := sym.Text; p != nil; p = p.Link {
+	for p := sym.Func.Text; p != nil; p = p.Link {
 		checkaddr(ctxt, p, &p.From)
 		if p.From3 != nil {
 			checkaddr(ctxt, p, p.From3)
@@ -163,7 +130,7 @@ func linkpatch(ctxt *Link, sym *LSym) {
 		checkaddr(ctxt, p, &p.To)
 
 		if ctxt.Arch.Progedit != nil {
-			ctxt.Arch.Progedit(ctxt, p)
+			ctxt.Arch.Progedit(ctxt, p, newprog)
 		}
 		if p.To.Type != TYPE_BRANCH {
 			continue
@@ -178,7 +145,7 @@ func linkpatch(ctxt *Link, sym *LSym) {
 			continue
 		}
 		c = int32(p.To.Offset)
-		for q = sym.Text; q != nil; {
+		for q = sym.Func.Text; q != nil; {
 			if int64(c) == q.Pc {
 				break
 			}
@@ -202,16 +169,18 @@ func linkpatch(ctxt *Link, sym *LSym) {
 		p.Pcond = q
 	}
 
-	if ctxt.Flag_optimize {
-		for p := sym.Text; p != nil; p = p.Link {
-			if p.Pcond != nil {
-				p.Pcond = brloop(ctxt, p.Pcond)
-				if p.Pcond != nil {
-					if p.To.Type == TYPE_BRANCH {
-						p.To.Offset = p.Pcond.Pc
-					}
-				}
-			}
+	if !ctxt.Flag_optimize {
+		return
+	}
+
+	// Collapse series of jumps to jumps.
+	for p := sym.Func.Text; p != nil; p = p.Link {
+		if p.Pcond == nil {
+			continue
+		}
+		p.Pcond = brloop(p.Pcond)
+		if p.Pcond != nil && 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 e4a724a..b85bb8a 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -24,43 +24,35 @@ func addvarint(d *Pcdata, v uint32) {
 // where func is the function, val is the current value, p is the instruction being
 // considered, and arg can be used to further parameterize valfunc.
 func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
-	// To debug a specific function, uncomment lines and change name.
-	dbg := 0
-
-	//if func_.Name == "main.main" || desc == "pctospadj" {
-	//	dbg = 1
-	//}
-
-	ctxt.Debugpcln += int32(dbg)
+	dbg := desc == ctxt.Debugpcln
 
 	dst.P = dst.P[:0]
 
-	if ctxt.Debugpcln != 0 {
+	if dbg {
 		ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
 	}
 
 	val := int32(-1)
 	oldval := val
-	if func_.Text == nil {
-		ctxt.Debugpcln -= int32(dbg)
+	if func_.Func.Text == nil {
 		return
 	}
 
-	pc := func_.Text.Pc
+	pc := func_.Func.Text.Pc
 
-	if ctxt.Debugpcln != 0 {
-		ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Text)
+	if dbg {
+		ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
 	}
 
-	started := int32(0)
+	started := false
 	var delta uint32
-	for p := func_.Text; p != nil; p = p.Link {
+	for p := func_.Func.Text; p != nil; p = p.Link {
 		// Update val. If it's not changing, keep going.
 		val = valfunc(ctxt, func_, val, p, 0, arg)
 
-		if val == oldval && started != 0 {
+		if val == oldval && started {
 			val = valfunc(ctxt, func_, val, p, 1, arg)
-			if ctxt.Debugpcln != 0 {
+			if dbg {
 				ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
 			}
 			continue
@@ -72,7 +64,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		// for a true instruction boundary in the program.
 		if p.Link != nil && p.Link.Pc == p.Pc {
 			val = valfunc(ctxt, func_, val, p, 1, arg)
-			if ctxt.Debugpcln != 0 {
+			if dbg {
 				ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
 			}
 			continue
@@ -92,11 +84,11 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		// as variable-length little-endian base-128 integers,
 		// where the 0x80 bit indicates that the integer continues.
 
-		if ctxt.Debugpcln != 0 {
+		if dbg {
 			ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
 		}
 
-		if started != 0 {
+		if started {
 			addvarint(dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
 			pc = p.Pc
 		}
@@ -109,43 +101,36 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		}
 		addvarint(dst, delta)
 		oldval = val
-		started = 1
+		started = true
 		val = valfunc(ctxt, func_, val, p, 1, arg)
 	}
 
-	if started != 0 {
-		if ctxt.Debugpcln != 0 {
-			ctxt.Logf("%6x done\n", uint64(func_.Text.Pc+func_.Size))
+	if started {
+		if dbg {
+			ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
 		}
 		addvarint(dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
 		addvarint(dst, 0) // terminator
 	}
 
-	if ctxt.Debugpcln != 0 {
+	if dbg {
 		ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
 		for i := 0; i < len(dst.P); i++ {
 			ctxt.Logf(" %02x", dst.P[i])
 		}
 		ctxt.Logf("\n")
 	}
-
-	ctxt.Debugpcln -= int32(dbg)
 }
 
 // pctofileline computes either the file number (arg == 0)
 // or the line number (arg == 1) to use at p.
-// Because p->lineno applies to p, phase == 0 (before p)
+// Because p.Pos applies to p, phase == 0 (before p)
 // takes care of the update.
 func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
-	if p.As == ATEXT || p.As == ANOP || p.As == AUSEFIELD || p.Lineno == 0 || phase == 1 {
+	if p.As == ATEXT || p.As == ANOP || p.Pos.Line() == 0 || phase == 1 {
 		return oldval
 	}
-	f, l := linkgetline(ctxt, p.Lineno)
-	if f == nil {
-		//	print("getline failed for %s %v\n", ctxt->cursym->name, p);
-		return oldval
-	}
-
+	f, l := linkgetlineFromPos(ctxt, p.Pos)
 	if arg == nil {
 		return l
 	}
@@ -169,6 +154,62 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg
 	return int32(i)
 }
 
+// pcinlineState holds the state used to create a function's inlining
+// tree and the PC-value table that maps PCs to nodes in that tree.
+type pcinlineState struct {
+	globalToLocal map[int]int
+	localTree     InlTree
+}
+
+// addBranch adds a branch from the global inlining tree in ctxt to
+// the function's local inlining tree, returning the index in the local tree.
+func (s *pcinlineState) addBranch(ctxt *Link, globalIndex int) int {
+	if globalIndex < 0 {
+		return -1
+	}
+
+	localIndex, ok := s.globalToLocal[globalIndex]
+	if ok {
+		return localIndex
+	}
+
+	// Since tracebacks don't include column information, we could
+	// use one node for multiple calls of the same function on the
+	// same line (e.g., f(x) + f(y)). For now, we use one node for
+	// each inlined call.
+	call := ctxt.InlTree.nodes[globalIndex]
+	call.Parent = s.addBranch(ctxt, call.Parent)
+	localIndex = len(s.localTree.nodes)
+	s.localTree.nodes = append(s.localTree.nodes, call)
+	s.globalToLocal[globalIndex] = localIndex
+	return localIndex
+}
+
+// pctoinline computes the index into the local inlining tree to use at p.
+// If p is not the result of inlining, pctoinline returns -1. Because p.Pos
+// applies to p, phase == 0 (before p) takes care of the update.
+func (s *pcinlineState) pctoinline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
+	if phase == 1 {
+		return oldval
+	}
+
+	posBase := ctxt.PosTable.Pos(p.Pos).Base()
+	if posBase == nil {
+		return -1
+	}
+
+	globalIndex := posBase.InliningIndex()
+	if globalIndex < 0 {
+		return -1
+	}
+
+	if s.globalToLocal == nil {
+		s.globalToLocal = make(map[int]int)
+	}
+
+	return int32(s.addBranch(ctxt, globalIndex))
+}
+
 // pctospadj computes the sp adjustment in effect.
 // It is oldval plus any adjustment made by p itself.
 // The adjustment by p takes effect only after p, so we
@@ -206,14 +247,11 @@ func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg i
 }
 
 func linkpcln(ctxt *Link, cursym *LSym) {
-	ctxt.Cursym = cursym
-
-	pcln := new(Pcln)
-	cursym.Pcln = pcln
+	pcln := &cursym.Func.Pcln
 
 	npcdata := 0
 	nfuncdata := 0
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := cursym.Func.Text; p != nil; p = p.Link {
 		// Find the highest ID of any used PCDATA table. This ignores PCDATA table
 		// that consist entirely of "-1", since that's the assumed default value.
 		//   From.Offset is table ID
@@ -238,10 +276,19 @@ func linkpcln(ctxt *Link, cursym *LSym) {
 	funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
 	funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
 
+	pcinlineState := new(pcinlineState)
+	funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
+	pcln.InlTree = pcinlineState.localTree
+	if ctxt.Debugpcln == "pctoinline" && len(pcln.InlTree.nodes) > 0 {
+		ctxt.Logf("-- inlining tree for %s:\n", cursym)
+		dumpInlTree(ctxt, pcln.InlTree)
+		ctxt.Logf("--\n")
+	}
+
 	// tabulate which pc and func data we have.
 	havepc := make([]uint32, (npcdata+31)/32)
 	havefunc := make([]uint32, (nfuncdata+31)/32)
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := cursym.Func.Text; p != nil; p = p.Link {
 		if p.As == AFUNCDATA {
 			if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
 				ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
@@ -265,7 +312,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
 	// funcdata
 	if nfuncdata > 0 {
 		var i int
-		for p := cursym.Text; p != nil; p = p.Link {
+		for p := cursym.Func.Text; p != nil; p = p.Link {
 			if p.As == AFUNCDATA {
 				i = int(p.From.Offset)
 				pcln.Funcdataoff[i] = p.To.Offset
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index 804ea63..861da88 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -5,129 +5,74 @@
 package obj
 
 import (
+	"cmd/internal/objabi"
 	"fmt"
-	"log"
 	"strings"
 )
 
 type Plist struct {
 	Firstpc *Prog
+	Curfn   interface{} // holds a *gc.Node, if non-nil
 }
 
-/*
- * start a new Prog list.
- */
-func Linknewplist(ctxt *Link) *Plist {
-	pl := new(Plist)
-	ctxt.Plists = append(ctxt.Plists, pl)
-	return pl
-}
+// ProgAlloc is a function that allocates Progs.
+// It is used to provide access to cached/bulk-allocated Progs to the assemblers.
+type ProgAlloc func() *Prog
 
-func Flushplist(ctxt *Link) {
-	flushplist(ctxt, ctxt.Debugasm == 0)
-}
-func FlushplistNoFree(ctxt *Link) {
-	flushplist(ctxt, false)
-}
-func flushplist(ctxt *Link, freeProgs bool) {
+func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc) {
 	// 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 := range ctxt.Plists {
-		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
+	var plink *Prog
+	for p := plist.Firstpc; p != nil; p = plink {
+		if ctxt.Debugasm && ctxt.Debugvlog {
+			fmt.Printf("obj: %v\n", p)
+		}
+		plink = p.Link
+		p.Link = nil
 
-			switch p.As {
-			case AEND:
-				continue
+		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.To.Sym
-				a.Link = curtext.Autom
-				curtext.Autom = a
+		case ATEXT:
+			s := p.From.Sym
+			if s == nil {
+				// func _() { }
+				curtext = nil
 				continue
+			}
+			text = append(text, s)
+			etext = p
+			curtext = s
+			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.Set(AttrOnList, true)
-				text = append(text, s)
-				flag := int(p.From3Offset())
-				if flag&DUPOK != 0 {
-					s.Set(AttrDuplicateOK, true)
-				}
-				if flag&NOSPLIT != 0 {
-					s.Set(AttrNoSplit, true)
-				}
-				if flag&REFLECTMETHOD != 0 {
-					s.Set(AttrReflectMethod, true)
-				}
-				s.Type = STEXT
-				s.Text = p
-				etext = p
-				curtext = s
+		case AFUNCDATA:
+			// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
+			if curtext == nil { // func _() {}
 				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 p.To.Sym.Name == "go_args_stackmap" {
+				if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_ArgsPointerMaps {
+					ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
 				}
-
+				p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap")
 			}
 
-			if curtext == nil {
-				etext = nil
-				continue
-			}
-			etext.Link = p
-			etext = p
 		}
+
+		if curtext == nil {
+			etext = nil
+			continue
+		}
+		etext.Link = p
+		etext = p
+	}
+
+	if newprog == nil {
+		newprog = ctxt.NewProg
 	}
 
 	// Add reference to Go arguments for C or assembly functions without them.
@@ -136,49 +81,77 @@ func flushplist(ctxt *Link, freeProgs bool) {
 			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 {
+		for p := s.Func.Text; p != nil; p = p.Link {
+			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
 				found = true
 				break
 			}
 		}
 
 		if !found {
-			p = Appendp(ctxt, s.Text)
+			p := Appendp(s.Func.Text, newprog)
 			p.As = AFUNCDATA
 			p.From.Type = TYPE_CONST
-			p.From.Offset = FUNCDATA_ArgsPointerMaps
+			p.From.Offset = objabi.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))
+			p.To.Sym = ctxt.LookupDerived(s, s.Name+".args_stackmap")
 		}
 	}
 
 	// 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)
+		linkpatch(ctxt, s, newprog)
+		ctxt.Arch.Preprocess(ctxt, s, newprog)
+		ctxt.Arch.Assemble(ctxt, s, newprog)
 		linkpcln(ctxt, s)
-		if freeProgs {
-			s.Text = nil
-		}
+		ctxt.populateDWARF(plist.Curfn, s)
 	}
+}
 
-	// Add to running list in ctxt.
-	ctxt.Text = append(ctxt.Text, text...)
-	ctxt.Data = append(ctxt.Data, gendwarf(ctxt, text)...)
-	ctxt.Plists = nil
-	ctxt.Curp = nil
-	if freeProgs {
-		ctxt.freeProgs()
+func (ctxt *Link) InitTextSym(s *LSym, flag int) {
+	if s == nil {
+		// func _() { }
+		return
+	}
+	if s.Func != nil {
+		ctxt.Diag("InitTextSym double init for %s", s.Name)
 	}
+	s.Func = new(FuncInfo)
+	if s.Func.Text != nil {
+		ctxt.Diag("duplicate TEXT for %s", s.Name)
+	}
+	if s.OnList() {
+		ctxt.Diag("symbol %s listed multiple times", s.Name)
+	}
+	s.Set(AttrOnList, true)
+	s.Set(AttrDuplicateOK, flag&DUPOK != 0)
+	s.Set(AttrNoSplit, flag&NOSPLIT != 0)
+	s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0)
+	s.Set(AttrWrapper, flag&WRAPPER != 0)
+	s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0)
+	s.Set(AttrNoFrame, flag&NOFRAME != 0)
+	s.Type = objabi.STEXT
+	ctxt.Text = append(ctxt.Text, s)
+
+	// Set up DWARF entries for s.
+	dsym, drsym := ctxt.dwarfSym(s)
+	dsym.Type = objabi.SDWARFINFO
+	dsym.Set(AttrDuplicateOK, s.DuplicateOK())
+	drsym.Type = objabi.SDWARFRANGE
+	drsym.Set(AttrDuplicateOK, s.DuplicateOK())
+	ctxt.Data = append(ctxt.Data, dsym)
+	ctxt.Data = append(ctxt.Data, drsym)
+
+	// Set up the function's gcargs and gclocals.
+	// They will be filled in later if needed.
+	gcargs := &s.Func.GCArgs
+	gcargs.Set(AttrDuplicateOK, true)
+	gcargs.Type = objabi.SRODATA
+	gclocals := &s.Func.GCLocals
+	gclocals.Set(AttrDuplicateOK, true)
+	gclocals.Type = objabi.SRODATA
 }
 
 func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
@@ -187,22 +160,26 @@ func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
 	}
 	s.Set(AttrSeenGlobl, true)
 	if s.OnList() {
-		log.Fatalf("symbol %s listed multiple times", s.Name)
+		ctxt.Diag("symbol %s listed multiple times", s.Name)
 	}
 	s.Set(AttrOnList, true)
 	ctxt.Data = append(ctxt.Data, s)
 	s.Size = size
-	if s.Type == 0 || s.Type == SXREF {
-		s.Type = SBSS
+	if s.Type == 0 {
+		s.Type = objabi.SBSS
 	}
 	if flag&DUPOK != 0 {
 		s.Set(AttrDuplicateOK, true)
 	}
 	if flag&RODATA != 0 {
-		s.Type = SRODATA
+		s.Type = objabi.SRODATA
 	} else if flag&NOPTR != 0 {
-		s.Type = SNOPTRBSS
+		if s.Type == objabi.SDATA {
+			s.Type = objabi.SNOPTRDATA
+		} else {
+			s.Type = objabi.SNOPTRBSS
+		}
 	} else if flag&TLSBSS != 0 {
-		s.Type = STLSBSS
+		s.Type = objabi.STLSBSS
 	}
 }
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index 6078131..90a2047 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -626,6 +626,9 @@ const (
 	ACNTLZDCC
 	ACMPW /* CMP with L=0 */
 	ACMPWU
+	ACMPB
+	AFTDIV
+	AFTSQRT
 	ADIVD
 	ADIVDCC
 	ADIVDE
@@ -677,6 +680,8 @@ const (
 	ARLDCLCC
 	ARLDICL
 	ARLDICLCC
+	AROTL
+	AROTLW
 	ASLBIA
 	ASLBIE
 	ASLBMFEE
@@ -704,6 +709,9 @@ const (
 
 	/* more 64-bit operations */
 	AHRFID
+	APOPCNTD
+	APOPCNTW
+	APOPCNTB
 
 	/* Vector */
 	ALV
@@ -721,11 +729,9 @@ const (
 	ASTVX
 	ASTVXL
 	AVAND
-	AVANDL
 	AVANDC
 	AVNAND
 	AVOR
-	AVORL
 	AVORC
 	AVNOR
 	AVXOR
@@ -770,6 +776,11 @@ const (
 	AVSUBE
 	AVSUBEUQM
 	AVSUBECUQ
+	AVPMSUM
+	AVPMSUMB
+	AVPMSUMH
+	AVPMSUMW
+	AVPMSUMD
 	AVR
 	AVRLB
 	AVRLH
@@ -871,9 +882,13 @@ const (
 	ASTXSIWX
 	AMFVSR
 	AMFVSRD
+	AMFFPRD
+	AMFVRD
 	AMFVSRWZ
 	AMTVSR
 	AMTVSRD
+	AMTFPRD
+	AMTVRD
 	AMTVSRWA
 	AMTVSRWZ
 	AXXLAND
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
index 19ddd3c..5ca2945 100644
--- a/src/cmd/internal/obj/ppc64/anames.go
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -248,6 +248,9 @@ var Anames = []string{
 	"CNTLZDCC",
 	"CMPW",
 	"CMPWU",
+	"CMPB",
+	"FTDIV",
+	"FTSQRT",
 	"DIVD",
 	"DIVDCC",
 	"DIVDE",
@@ -298,6 +301,8 @@ var Anames = []string{
 	"RLDCLCC",
 	"RLDICL",
 	"RLDICLCC",
+	"ROTL",
+	"ROTLW",
 	"SLBIA",
 	"SLBIE",
 	"SLBMFEE",
@@ -321,6 +326,9 @@ var Anames = []string{
 	"REMDUV",
 	"REMDUVCC",
 	"HRFID",
+	"POPCNTD",
+	"POPCNTW",
+	"POPCNTB",
 	"LV",
 	"LVEBX",
 	"LVEHX",
@@ -336,11 +344,9 @@ var Anames = []string{
 	"STVX",
 	"STVXL",
 	"VAND",
-	"VANDL",
 	"VANDC",
 	"VNAND",
 	"VOR",
-	"VORL",
 	"VORC",
 	"VNOR",
 	"VXOR",
@@ -385,6 +391,11 @@ var Anames = []string{
 	"VSUBE",
 	"VSUBEUQM",
 	"VSUBECUQ",
+	"VPMSUM",
+	"VPMSUMB",
+	"VPMSUMH",
+	"VPMSUMW",
+	"VPMSUMD",
 	"VR",
 	"VRLB",
 	"VRLH",
@@ -484,9 +495,13 @@ var Anames = []string{
 	"STXSIWX",
 	"MFVSR",
 	"MFVSRD",
+	"MFFPRD",
+	"MFVRD",
 	"MFVSRWZ",
 	"MTVSR",
 	"MTVSRD",
+	"MTFPRD",
+	"MTVRD",
 	"MTVSRWA",
 	"MTVSRWZ",
 	"XXLAND",
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 4f86554..bdbac03 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -31,16 +31,29 @@ package ppc64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"encoding/binary"
 	"fmt"
 	"log"
 	"sort"
 )
 
+// ctxt9 holds state while assembling a single function.
+// Each function gets a fresh ctxt9.
+// This allows for multiple functions to be safely concurrently assembled.
+type ctxt9 struct {
+	ctxt       *obj.Link
+	newprog    obj.ProgAlloc
+	cursym     *obj.LSym
+	autosize   int32
+	instoffset int64
+	pc         int64
+}
+
 // Instruction layout.
 
 const (
-	funcAlign = 8
+	funcAlign = 16
 )
 
 const (
@@ -346,6 +359,12 @@ var optab = []Optab{
 	{AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0},  /* mtmsrd */
 	{AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0}, /* mtmsr */
 
+	/* Other ISA 2.05+ instructions */
+	{APOPCNTD, C_REG, C_NONE, C_NONE, C_REG, 93, 4, 0},  /* population count, x-form */
+	{ACMPB, C_REG, C_REG, C_NONE, C_REG, 92, 4, 0},      /* compare byte, x-form */
+	{AFTDIV, C_FREG, C_FREG, C_NONE, C_SCON, 92, 4, 0},  /* floating test for sw divide, x-form */
+	{AFTSQRT, C_FREG, C_NONE, C_NONE, C_SCON, 93, 4, 0}, /* floating test for sw square root, x-form */
+
 	/* Vector instructions */
 
 	/* Vector load */
@@ -372,6 +391,9 @@ var optab = []Optab{
 	{AVSUBSS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract signed saturate, vx-form */
 	{AVSUBE, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0},  /* vector subtract extended, va-form */
 
+	/* Vector multiply */
+	{AVPMSUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector polynomial multiply & sum, vx-form */
+
 	/* Vector rotate */
 	{AVR, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector rotate, vx-form */
 
@@ -428,9 +450,13 @@ var optab = []Optab{
 
 	/* VSX move from VSR */
 	{AMFVSR, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */
+	{AMFVSR, C_FREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
+	{AMFVSR, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
 
 	/* VSX move to VSR */
 	{AMTVSR, C_REG, C_NONE, C_NONE, C_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */
+	{AMTVSR, C_REG, C_NONE, C_NONE, C_FREG, 88, 4, 0},
+	{AMTVSR, C_REG, C_NONE, C_NONE, C_VREG, 88, 4, 0},
 
 	/* VSX logical */
 	{AXXLAND, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx and, xx3-form */
@@ -494,7 +520,7 @@ var optab = []Optab{
 	{AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0},
 	{AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
 	{AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
-	{AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0},
+	{AMOVFL, C_REG, C_NONE, C_NONE, C_LCON, 69, 4, 0},
 	{AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
 	{AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
 	{AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
@@ -526,7 +552,6 @@ var optab = []Optab{
 	{ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
 	{ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0},
 	{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0},
-	{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0},
 	{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0},
 	{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0},
 	{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0},
@@ -540,39 +565,38 @@ var oprange [ALAST & obj.AMask][]Optab
 
 var xcmp [C_NCLASS][C_NCLASS]bool
 
-func span9(ctxt *obj.Link, cursym *obj.LSym) {
-	p := cursym.Text
+func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	p := cursym.Func.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)
+		ctxt.Diag("ppc64 ops not initialized, call ppc64.buildop first")
 	}
 
-	c := int64(0)
-	p.Pc = c
+	c := ctxt9{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset)}
+
+	pc := int64(0)
+	p.Pc = pc
 
 	var m int
 	var o *Optab
 	for p = p.Link; p != nil; p = p.Link {
-		ctxt.Curp = p
-		p.Pc = c
-		o = oplook(ctxt, p)
+		p.Pc = pc
+		o = c.oplook(p)
 		m = int(o.size)
 		if m == 0 {
-			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-				ctxt.Diag("zero-width instruction\n%v", p)
+			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+				c.ctxt.Diag("zero-width instruction\n%v", p)
 			}
 			continue
 		}
 
-		c += int64(m)
+		pc += int64(m)
 	}
 
-	cursym.Size = c
+	c.cursym.Size = pc
 
 	/*
 	 * if any procedure is large enough to
@@ -585,27 +609,24 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
 	var otxt int64
 	var q *obj.Prog
 	for bflag != 0 {
-		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f span1\n", obj.Cputime())
-		}
 		bflag = 0
-		c = 0
-		for p = cursym.Text.Link; p != nil; p = p.Link {
-			p.Pc = c
-			o = oplook(ctxt, p)
+		pc = 0
+		for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+			p.Pc = pc
+			o = c.oplook(p)
 
 			// very large conditional branches
 			if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil {
-				otxt = p.Pcond.Pc - c
+				otxt = p.Pcond.Pc - pc
 				if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
-					q = ctxt.NewProg()
+					q = c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = ABR
 					q.To.Type = obj.TYPE_BRANCH
 					q.Pcond = p.Pcond
 					p.Pcond = q
-					q = ctxt.NewProg()
+					q = c.newprog()
 					q.Link = p.Link
 					p.Link = q
 					q.As = ABR
@@ -620,40 +641,39 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
 
 			m = int(o.size)
 			if m == 0 {
-				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
-					ctxt.Diag("zero-width instruction\n%v", p)
+				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+					c.ctxt.Diag("zero-width instruction\n%v", p)
 				}
 				continue
 			}
 
-			c += int64(m)
+			pc += int64(m)
 		}
 
-		cursym.Size = c
+		c.cursym.Size = pc
 	}
 
-	c += -c & (funcAlign - 1)
-	cursym.Size = c
+	pc += -pc & (funcAlign - 1)
+	c.cursym.Size = pc
 
 	/*
 	 * lay out the code, emitting code and data relocations.
 	 */
 
-	cursym.Grow(cursym.Size)
+	c.cursym.Grow(c.cursym.Size)
 
-	bp := cursym.P
+	bp := c.cursym.P
 	var i int32
 	var out [6]uint32
-	for p := cursym.Text.Link; p != nil; p = p.Link {
-		ctxt.Pc = p.Pc
-		ctxt.Curp = p
-		o = oplook(ctxt, p)
+	for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+		c.pc = p.Pc
+		o = c.oplook(p)
 		if int(o.size) > 4*len(out) {
 			log.Fatalf("out array in span9 is too small, need at least %d for %v", o.size/4, p)
 		}
-		asmout(ctxt, p, o, out[:])
+		c.asmout(p, o, out[:])
 		for i = 0; i < int32(o.size/4); i++ {
-			ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
+			c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
 			bp = bp[4:]
 		}
 	}
@@ -667,7 +687,7 @@ func isuint32(v uint64) bool {
 	return uint64(uint32(v)) == v
 }
 
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
+func (c *ctxt9) aclass(a *obj.Addr) int {
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -721,10 +741,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if a.Sym == nil {
 				break
 			}
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Sym != nil { // use relocation
-				if a.Sym.Type == obj.STLSBSS {
-					if ctxt.Flag_shared {
+				if a.Sym.Type == objabi.STLSBSS {
+					if c.ctxt.Flag_shared {
 						return C_TLS_IE
 					} else {
 						return C_TLS_LE
@@ -738,25 +758,25 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_GOTADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SAUTO
 			}
 			return C_LAUTO
 
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
-			if ctxt.Instoffset == 0 {
+			c.instoffset = a.Offset
+			if c.instoffset == 0 {
 				return C_ZOREG
 			}
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SOREG
 			}
 			return C_LOREG
@@ -771,12 +791,12 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		obj.TYPE_ADDR:
 		switch a.Name {
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 			if a.Reg != 0 {
-				if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
+				if -BIG <= c.instoffset && c.instoffset <= BIG {
 					return C_SACON
 				}
-				if isint32(ctxt.Instoffset) {
+				if isint32(c.instoffset) {
 					return C_LACON
 				}
 				return C_DACON
@@ -790,26 +810,22 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if s == nil {
 				break
 			}
-			if s.Type == obj.SCONST {
-				ctxt.Instoffset = a.Offset
-				goto consize
-			}
 
-			ctxt.Instoffset = a.Offset
+			c.instoffset = a.Offset
 
 			/* not sure why this barfs */
 			return C_LCON
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SACON
 			}
 			return C_LACON
@@ -818,38 +834,38 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		return C_GOK
 
 	consize:
-		if ctxt.Instoffset >= 0 {
-			if ctxt.Instoffset == 0 {
+		if c.instoffset >= 0 {
+			if c.instoffset == 0 {
 				return C_ZCON
 			}
-			if ctxt.Instoffset <= 0x7fff {
+			if c.instoffset <= 0x7fff {
 				return C_SCON
 			}
-			if ctxt.Instoffset <= 0xffff {
+			if c.instoffset <= 0xffff {
 				return C_ANDCON
 			}
-			if ctxt.Instoffset&0xffff == 0 && isuint32(uint64(ctxt.Instoffset)) { /* && (instoffset & (1<<31)) == 0) */
+			if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && (instoffset & (1<<31)) == 0) */
 				return C_UCON
 			}
-			if isint32(ctxt.Instoffset) || isuint32(uint64(ctxt.Instoffset)) {
+			if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) {
 				return C_LCON
 			}
 			return C_DCON
 		}
 
-		if ctxt.Instoffset >= -0x8000 {
+		if c.instoffset >= -0x8000 {
 			return C_ADDCON
 		}
-		if ctxt.Instoffset&0xffff == 0 && isint32(ctxt.Instoffset) {
+		if c.instoffset&0xffff == 0 && isint32(c.instoffset) {
 			return C_UCON
 		}
-		if isint32(ctxt.Instoffset) {
+		if isint32(c.instoffset) {
 			return C_LCON
 		}
 		return C_DCON
 
 	case obj.TYPE_BRANCH:
-		if a.Sym != nil && ctxt.Flag_dynlink {
+		if a.Sym != nil && c.ctxt.Flag_dynlink {
 			return C_LBRAPIC
 		}
 		return C_SBRA
@@ -862,14 +878,14 @@ func prasm(p *obj.Prog) {
 	fmt.Printf("%v\n", p)
 }
 
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+func (c *ctxt9) oplook(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
+		a1 = c.aclass(&p.From) + 1
 		p.From.Class = int8(a1)
 	}
 
@@ -878,7 +894,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	if p.From3 != nil {
 		a3 = int(p.From3.Class)
 		if a3 == 0 {
-			a3 = aclass(ctxt, p.From3) + 1
+			a3 = c.aclass(p.From3) + 1
 			p.From3.Class = int8(a3)
 		}
 	}
@@ -886,7 +902,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	a3--
 	a4 := int(p.To.Class)
 	if a4 == 0 {
-		a4 = aclass(ctxt, &p.To) + 1
+		a4 = c.aclass(&p.To) + 1
 		p.To.Class = int8(a4)
 	}
 
@@ -917,7 +933,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 		}
 	}
 
-	ctxt.Diag("illegal combination %v %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+	c.ctxt.Diag("illegal combination %v %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
 	prasm(p)
 	if ops == nil {
 		ops = optab
@@ -1042,6 +1058,13 @@ func opset(a, b0 obj.As) {
 }
 
 func buildop(ctxt *obj.Link) {
+	if oprange[AANDN&obj.AMask] != nil {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
 	var n int
 
 	for i := 0; i < C_NCLASS; i++ {
@@ -1161,6 +1184,10 @@ func buildop(ctxt *obj.Link) {
 			opset(ADIVDUVCC, r0)
 			opset(ADIVDUCC, r0)
 
+		case APOPCNTD:
+			opset(APOPCNTW, r0)
+			opset(APOPCNTB, r0)
+
 		case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
 			opset(AMOVH, r0)
 
@@ -1192,12 +1219,12 @@ func buildop(ctxt *obj.Link) {
 			opset(ASTVXL, r0)
 
 		case AVAND: /* vand, vandc, vnand */
-			opset(AVANDL, r0)
+			opset(AVAND, r0)
 			opset(AVANDC, r0)
 			opset(AVNAND, r0)
 
 		case AVOR: /* vor, vorc, vxor, vnor, veqv */
-			opset(AVORL, r0)
+			opset(AVOR, r0)
 			opset(AVORC, r0)
 			opset(AVXOR, r0)
 			opset(AVNOR, r0)
@@ -1253,6 +1280,12 @@ func buildop(ctxt *obj.Link) {
 			opset(AVSUBEUQM, r0)
 			opset(AVSUBECUQ, r0)
 
+		case AVPMSUM: /* vpmsumb, vpmsumh, vpmsumw, vpmsumd */
+			opset(AVPMSUMB, r0)
+			opset(AVPMSUMH, r0)
+			opset(AVPMSUMW, r0)
+			opset(AVPMSUMD, r0)
+
 		case AVR: /* vrlb, vrlh, vrlw, vrld */
 			opset(AVRLB, r0)
 			opset(AVRLH, r0)
@@ -1375,12 +1408,16 @@ func buildop(ctxt *obj.Link) {
 		case ASTXSI: /* stxsiwx */
 			opset(ASTXSIWX, r0)
 
-		case AMFVSR: /* mfvsrd, mfvsrwz */
+		case AMFVSR: /* mfvsrd, mfvsrwz (and extended mnemonics) */
 			opset(AMFVSRD, r0)
+			opset(AMFFPRD, r0)
+			opset(AMFVRD, r0)
 			opset(AMFVSRWZ, r0)
 
-		case AMTVSR: /* mtvsrd, mtvsrwa, mtvsrwz */
+		case AMTVSR: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics) */
 			opset(AMTVSRD, r0)
+			opset(AMTFPRD, r0)
+			opset(AMTVRD, r0)
 			opset(AMTVSRWA, r0)
 			opset(AMTVSRWZ, r0)
 
@@ -1614,11 +1651,13 @@ func buildop(ctxt *obj.Link) {
 			opset(ASLWCC, r0)
 			opset(ASRW, r0)
 			opset(ASRWCC, r0)
+			opset(AROTLW, r0)
 
 		case ASLD:
 			opset(ASLDCC, r0)
 			opset(ASRD, r0)
 			opset(ASRDCC, r0)
+			opset(AROTL, r0)
 
 		case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
 			opset(ASRAWCC, r0)
@@ -1710,6 +1749,15 @@ func buildop(ctxt *obj.Link) {
 		case ACMPU:
 			opset(ACMPWU, r0)
 
+		case ACMPB:
+			opset(ACMPB, r0)
+
+		case AFTDIV:
+			opset(AFTDIV, r0)
+
+		case AFTSQRT:
+			opset(AFTSQRT, r0)
+
 		case AADD,
 			AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
 			AFMOVSX,
@@ -1732,7 +1780,6 @@ func buildop(ctxt *obj.Link) {
 			obj.ANOP,
 			obj.ATEXT,
 			obj.AUNDEF,
-			obj.AUSEFIELD,
 			obj.AFUNCDATA,
 			obj.APCDATA,
 			obj.ADUFFZERO,
@@ -1783,7 +1830,7 @@ func AOP_RRR(op uint32, d uint32, a uint32, b uint32) uint32 {
 	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11
 }
 
-/* VX-form 2-register operands, r/r/none */
+/* VX-form 2-register operands, r/none/r */
 func AOP_RR(op uint32, d uint32, a uint32) uint32 {
 	return op | (d&31)<<21 | (a&31)<<11
 }
@@ -1881,6 +1928,10 @@ func OP_RLW(op uint32, a uint32, s uint32, sh uint32, mb uint32, me uint32) uint
 	return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1
 }
 
+func AOP_RLDIC(op uint32, a uint32, s uint32, sh uint32, m uint32) uint32 {
+	return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | ((sh&32)>>5)<<1 | (m&31)<<6 | ((m&32)>>5)<<5
+}
+
 func AOP_ISEL(op uint32, t uint32, a uint32, b uint32, bc uint32) uint32 {
 	return op | (t&31)<<21 | (a&31)<<16 | (b&31)<<11 | (bc&0x1F)<<6
 }
@@ -1918,10 +1969,12 @@ const (
 	OP_ORI    = 24<<26 | 0<<1 | 0<<10 | 0
 	OP_ORIS   = 25<<26 | 0<<1 | 0<<10 | 0
 	OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0
+	OP_RLWNM  = 23<<26 | 0<<1 | 0<<10 | 0
 	OP_SUBF   = 31<<26 | 40<<1 | 0<<10 | 0
 	OP_RLDIC  = 30<<26 | 4<<1 | 0<<10 | 0
 	OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0
 	OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0
+	OP_RLDCL  = 30<<26 | 8<<1 | 0<<10 | 0
 )
 
 func oclass(a *obj.Addr) int {
@@ -1933,29 +1986,48 @@ const (
 	DS_FORM
 )
 
-// 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 uint32) int {
+// This function determines when a non-indexed load or store is D or
+// DS form for use in finding the size of the offset field in the instruction.
+// The size is needed when setting the offset value in the instruction
+// and when generating relocation for that field.
+// DS form instructions include: ld, ldu, lwa, std, stdu.  All other
+// loads and stores with an offset field are D form.  This function should
+// only be called with the same opcodes as are handled by opstore and opload.
+func (c *ctxt9) opform(insn uint32) int {
 	switch insn {
 	default:
-		ctxt.Diag("bad insn in loadform: %x", insn)
+		c.ctxt.Diag("bad insn in loadform: %x", insn)
 	case OPVCC(58, 0, 0, 0), // ld
+		OPVCC(58, 0, 0, 1),        // ldu
 		OPVCC(58, 0, 0, 0) | 1<<1, // lwa
-		OPVCC(62, 0, 0, 0):        // std
+		OPVCC(62, 0, 0, 0),        // std
+		OPVCC(62, 0, 0, 1):        //stdu
 		return DS_FORM
 	case OP_ADDI, // add
 		OPVCC(32, 0, 0, 0), // lwz
-		OPVCC(42, 0, 0, 0), // lha
-		OPVCC(40, 0, 0, 0), // lhz
+		OPVCC(33, 0, 0, 0), // lwzu
 		OPVCC(34, 0, 0, 0), // lbz
-		OPVCC(50, 0, 0, 0), // lfd
+		OPVCC(35, 0, 0, 0), // lbzu
+		OPVCC(40, 0, 0, 0), // lhz
+		OPVCC(41, 0, 0, 0), // lhzu
+		OPVCC(42, 0, 0, 0), // lha
+		OPVCC(43, 0, 0, 0), // lhau
+		OPVCC(46, 0, 0, 0), // lmw
 		OPVCC(48, 0, 0, 0), // lfs
+		OPVCC(49, 0, 0, 0), // lfsu
+		OPVCC(50, 0, 0, 0), // lfd
+		OPVCC(51, 0, 0, 0), // lfdu
 		OPVCC(36, 0, 0, 0), // stw
-		OPVCC(44, 0, 0, 0), // sth
+		OPVCC(37, 0, 0, 0), // stwu
 		OPVCC(38, 0, 0, 0), // stb
+		OPVCC(39, 0, 0, 0), // stbu
+		OPVCC(44, 0, 0, 0), // sth
+		OPVCC(45, 0, 0, 0), // sthu
+		OPVCC(47, 0, 0, 0), // stmw
+		OPVCC(52, 0, 0, 0), // stfs
+		OPVCC(53, 0, 0, 0), // stfsu
 		OPVCC(54, 0, 0, 0), // stfd
-		OPVCC(52, 0, 0, 0): // stfs
+		OPVCC(55, 0, 0, 0): // stfdu
 		return D_FORM
 	}
 	return 0
@@ -1963,35 +2035,35 @@ func opform(ctxt *obj.Link, insn uint32) 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 uint32) (o1, o2 uint32) {
+func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
 	var base uint32
-	form := opform(ctxt, op)
-	if ctxt.Flag_shared {
+	form := c.opform(op)
+	if c.ctxt.Flag_shared {
 		base = REG_R2
 	} else {
 		base = REG_R0
 	}
 	o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
 	o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
-	rel := obj.Addrel(ctxt.Cursym)
-	rel.Off = int32(ctxt.Pc)
+	rel := obj.Addrel(c.cursym)
+	rel.Off = int32(c.pc)
 	rel.Siz = 8
 	rel.Sym = s
 	rel.Add = d
-	if ctxt.Flag_shared {
+	if c.ctxt.Flag_shared {
 		switch form {
 		case D_FORM:
-			rel.Type = obj.R_ADDRPOWER_TOCREL
+			rel.Type = objabi.R_ADDRPOWER_TOCREL
 		case DS_FORM:
-			rel.Type = obj.R_ADDRPOWER_TOCREL_DS
+			rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
 		}
 
 	} else {
 		switch form {
 		case D_FORM:
-			rel.Type = obj.R_ADDRPOWER
+			rel.Type = objabi.R_ADDRPOWER
 		case DS_FORM:
-			rel.Type = obj.R_ADDRPOWER_DS
+			rel.Type = objabi.R_ADDRPOWER_DS
 		}
 	}
 	return
@@ -2037,9 +2109,9 @@ func getmask(m []byte, v uint32) bool {
 	return false
 }
 
-func maskgen(ctxt *obj.Link, p *obj.Prog, m []byte, v uint32) {
+func (c *ctxt9) maskgen(p *obj.Prog, m []byte, v uint32) {
 	if !getmask(m, v) {
-		ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+		c.ctxt.Diag("cannot generate mask #%x\n%v", v, p)
 	}
 }
 
@@ -2072,9 +2144,9 @@ func getmask64(m []byte, v uint64) bool {
 	return false
 }
 
-func maskgen64(ctxt *obj.Link, p *obj.Prog, m []byte, v uint64) {
+func (c *ctxt9) maskgen64(p *obj.Prog, m []byte, v uint64) {
 	if !getmask64(m, v) {
-		ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+		c.ctxt.Diag("cannot generate mask #%x\n%v", v, p)
 	}
 }
 
@@ -2093,7 +2165,7 @@ func high16adjusted(d int32) uint16 {
 	return uint16(d >> 16)
 }
 
-func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
 	o1 := uint32(0)
 	o2 := uint32(0)
 	o3 := uint32(0)
@@ -2103,7 +2175,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	//print("%v => case %d\n", p, o->type);
 	switch o.type_ {
 	default:
-		ctxt.Diag("unknown type %d", o.type_)
+		c.ctxt.Diag("unknown type %d", o.type_)
 		prasm(p)
 
 	case 0: /* pseudo ops */
@@ -2111,10 +2183,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
 		if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
-			v := regoff(ctxt, &p.From)
+			v := c.regoff(&p.From)
 			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
 				//nerrors--;
-				ctxt.Diag("literal operation on R0\n%v", p)
+				c.ctxt.Diag("literal operation on R0\n%v", p)
 			}
 
 			o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
@@ -2129,10 +2201,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
 
 	case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&p.From)
 
 		v := int32(d)
 		r := int(p.From.Reg)
@@ -2140,7 +2212,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(o.param)
 		}
 		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) {
-			ctxt.Diag("literal operation on R0\n%v", p)
+			c.ctxt.Diag("literal operation on R0\n%v", p)
 		}
 		a := OP_ADDI
 		if o.a1 == C_UCON {
@@ -2163,22 +2235,22 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = AOP_IRR(uint32(a), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 4: /* add/mul $scon,[r1],r2 */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 {
-			ctxt.Diag("literal operation on R0\n%v", p)
+			c.ctxt.Diag("literal operation on R0\n%v", p)
 		}
 		if int32(int16(v)) != v {
 			log.Fatalf("mishandled instruction %v", p)
 		}
-		o1 = AOP_IRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+		o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 5: /* syscall */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p.As)
 
 	case 6: /* logical op Rb,[Rs,]Ra; no literal */
 		r := int(p.Reg)
@@ -2186,7 +2258,15 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = LOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+		// AROTL and AROTLW are extended mnemonics, which map to RLDCL and RLWNM.
+		switch p.As {
+		case AROTL:
+			o1 = AOP_RLDIC(OP_RLDCL, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), uint32(0))
+		case AROTLW:
+			o1 = OP_RLW(OP_RLWNM, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), 0, 31)
+		default:
+			o1 = LOP_RRR(c.oprrr(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)
@@ -2194,29 +2274,34 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 		if p.To.Type == obj.TYPE_MEM && p.To.Index != 0 {
 			if v != 0 {
-				ctxt.Diag("illegal indexed instruction\n%v", p)
+				c.ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			if ctxt.Flag_shared && r == REG_R13 {
-				rel := obj.Addrel(ctxt.Cursym)
-				rel.Off = int32(ctxt.Pc)
+			if c.ctxt.Flag_shared && r == REG_R13 {
+				rel := obj.Addrel(c.cursym)
+				rel.Off = int32(c.pc)
 				rel.Siz = 4
 				// This (and the matching part in the load case
 				// below) are the only places in the ppc64 toolchain
 				// that knows the name of the tls variable. Possibly
 				// we could add some assembly syntax so that the name
 				// of the variable does not have to be assumed.
-				rel.Sym = obj.Linklookup(ctxt, "runtime.tls_g", 0)
-				rel.Type = obj.R_POWER_TLS
+				rel.Sym = c.ctxt.Lookup("runtime.tls_g")
+				rel.Type = objabi.R_POWER_TLS
 			}
-			o1 = AOP_RRR(opstorex(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))
+			o1 = AOP_RRR(c.opstorex(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(opstore(ctxt, p.As), uint32(p.From.Reg), uint32(r), uint32(v))
+			// Offsets in DS form stores must be a multiple of 4
+			inst := c.opstore(p.As)
+			if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+				log.Fatalf("invalid offset for DS form load/store %v", p)
+			}
+			o1 = AOP_IRR(inst, uint32(p.From.Reg), uint32(r), uint32(v))
 		}
 
 	case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
@@ -2225,24 +2310,29 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
 			if v != 0 {
-				ctxt.Diag("illegal indexed instruction\n%v", p)
+				c.ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			if ctxt.Flag_shared && r == REG_R13 {
-				rel := obj.Addrel(ctxt.Cursym)
-				rel.Off = int32(ctxt.Pc)
+			if c.ctxt.Flag_shared && r == REG_R13 {
+				rel := obj.Addrel(c.cursym)
+				rel.Off = int32(c.pc)
 				rel.Siz = 4
-				rel.Sym = obj.Linklookup(ctxt, "runtime.tls_g", 0)
-				rel.Type = obj.R_POWER_TLS
+				rel.Sym = c.ctxt.Lookup("runtime.tls_g")
+				rel.Type = objabi.R_POWER_TLS
 			}
-			o1 = AOP_RRR(oploadx(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
+			o1 = AOP_RRR(c.oploadx(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(opload(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+			// Offsets in DS form loads must be a multiple of 4
+			inst := c.opload(p.As)
+			if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+				log.Fatalf("invalid offset for DS form load/store %v", p)
+			}
+			o1 = AOP_IRR(inst, uint32(p.To.Reg), uint32(r), uint32(v))
 		}
 
 	case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
@@ -2251,14 +2341,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
 			if v != 0 {
-				ctxt.Diag("illegal indexed instruction\n%v", p)
+				c.ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			o1 = AOP_RRR(oploadx(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
+			o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
 		} else {
-			o1 = AOP_IRR(opload(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+			o1 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 		}
 		o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
@@ -2268,7 +2358,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
 
 	case 11: /* br/bl lbra */
 		v := int32(0)
@@ -2276,37 +2366,37 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if p.Pcond != nil {
 			v = int32(p.Pcond.Pc - p.Pc)
 			if v&03 != 0 {
-				ctxt.Diag("odd branch target address\n%v", p)
+				c.ctxt.Diag("odd branch target address\n%v", p)
 				v &^= 03
 			}
 
 			if v < -(1<<25) || v >= 1<<24 {
-				ctxt.Diag("branch too far\n%v", p)
+				c.ctxt.Diag("branch too far\n%v", p)
 			}
 		}
 
-		o1 = OP_BR(opirr(ctxt, p.As), uint32(v), 0)
+		o1 = OP_BR(c.opirr(p.As), uint32(v), 0)
 		if p.To.Sym != nil {
-			rel := obj.Addrel(ctxt.Cursym)
-			rel.Off = int32(ctxt.Pc)
+			rel := obj.Addrel(c.cursym)
+			rel.Off = int32(c.pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
 			v += int32(p.To.Offset)
 			if v&03 != 0 {
-				ctxt.Diag("odd branch target address\n%v", p)
+				c.ctxt.Diag("odd branch target address\n%v", p)
 				v &^= 03
 			}
 
 			rel.Add = int64(v)
-			rel.Type = obj.R_CALLPOWER
+			rel.Type = objabi.R_CALLPOWER
 		}
 		o2 = 0x60000000 // nop, sometimes overwritten by ld r2, 24(r1) when dynamic linking
 
 	case 12: /* movb r,r (extsb); movw r,r (extsw) */
 		if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
-			v := regoff(ctxt, &p.From)
+			v := c.regoff(&p.From)
 			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
-				ctxt.Diag("literal operation on R0\n%v", p)
+				c.ctxt.Diag("literal operation on R0\n%v", p)
 			}
 
 			o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
@@ -2329,7 +2419,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else if p.As == AMOVWZ {
 			o1 = OP_RLW(OP_RLDIC, uint32(p.To.Reg), uint32(p.From.Reg), 0, 0, 0) | 1<<5 /* MB=32 */
 		} else {
-			ctxt.Diag("internal: bad mov[bhw]z\n%v", p)
+			c.ctxt.Diag("internal: bad mov[bhw]z\n%v", p)
 		}
 
 	case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
@@ -2338,7 +2428,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		d := vregoff(ctxt, p.From3)
+		d := c.vregoff(p.From3)
 		var a int
 		switch p.As {
 
@@ -2347,37 +2437,48 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		// Left here for compatibility in case they were used or generated.
 		case ARLDCL, ARLDCLCC:
 			var mask [2]uint8
-			maskgen64(ctxt, p, mask[:], uint64(d))
+			c.maskgen64(p, mask[:], uint64(d))
 
 			a = int(mask[0]) /* MB */
 			if mask[1] != 63 {
-				ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
+				c.ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
+			}
+			o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+			o1 |= (uint32(a) & 31) << 6
+			if a&0x20 != 0 {
+				o1 |= 1 << 5 /* mb[5] is top bit */
 			}
 
 		case ARLDCR, ARLDCRCC:
 			var mask [2]uint8
-			maskgen64(ctxt, p, mask[:], uint64(d))
+			c.maskgen64(p, mask[:], uint64(d))
 
 			a = int(mask[1]) /* ME */
 			if mask[0] != 0 {
-				ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
+				c.ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
+			}
+			o1 = LOP_RRR(c.oprrr(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 */
 			}
 
 		// These opcodes use a shift count like the ppc64 asm, no mask conversion done
-		case ARLDICR, ARLDICRCC, ARLDICL, ARLDICLCC:
-			a = int(d)
+		case ARLDICR, ARLDICRCC:
+			me := int(d)
+			sh := c.regoff(&p.From)
+			o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(me))
+
+		case ARLDICL, ARLDICLCC:
+			mb := int(d)
+			sh := c.regoff(&p.From)
+			o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(mb))
 
 		default:
-			ctxt.Diag("unexpected op in rldc case\n%v", p)
+			c.ctxt.Diag("unexpected op in rldc case\n%v", p)
 			a = 0
 		}
 
-		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 */
-		}
-
 	case 17, /* bc bo,bi,lbra (same for now) */
 		16: /* bc bo,bi,sbra */
 		a := 0
@@ -2385,10 +2486,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		r := int(p.Reg)
 
 		if p.From.Type == obj.TYPE_CONST {
-			a = int(regoff(ctxt, &p.From))
+			a = int(c.regoff(&p.From))
 		} else if p.From.Type == obj.TYPE_REG {
 			if r != 0 {
-				ctxt.Diag("unexpected register setting for branch with CR: %d\n", r)
+				c.ctxt.Diag("unexpected register setting for branch with CR: %d\n", r)
 			}
 			// BI values for the CR
 			switch p.From.Reg {
@@ -2409,7 +2510,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			case REG_CR7:
 				r = BI_CR7
 			default:
-				ctxt.Diag("unrecognized register: expecting CR\n")
+				c.ctxt.Diag("unrecognized register: expecting CR\n")
 			}
 		}
 		v := int32(0)
@@ -2417,19 +2518,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			v = int32(p.Pcond.Pc - p.Pc)
 		}
 		if v&03 != 0 {
-			ctxt.Diag("odd branch target address\n%v", p)
+			c.ctxt.Diag("odd branch target address\n%v", p)
 			v &^= 03
 		}
 
 		if v < -(1<<16) || v >= 1<<15 {
-			ctxt.Diag("branch too far\n%v", p)
+			c.ctxt.Diag("branch too far\n%v", p)
 		}
-		o1 = OP_BC(opirr(ctxt, p.As), uint32(a), uint32(r), uint32(v), 0)
+		o1 = OP_BC(c.opirr(p.As), uint32(a), uint32(r), uint32(v), 0)
 
 	case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
 		var v int32
 		if p.As == ABC || p.As == ABCL {
-			v = regoff(ctxt, &p.To) & 31
+			v = c.regoff(&p.To) & 31
 		} else {
 			v = 20 /* unconditional */
 		}
@@ -2443,7 +2544,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
 		var v int32
 		if p.As == ABC || p.As == ABCL {
-			v = regoff(ctxt, &p.From) & 31
+			v = c.regoff(&p.From) & 31
 		} else {
 			v = 20 /* unconditional */
 		}
@@ -2459,7 +2560,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			o1 = OPVCC(19, 16, 0, 0)
 
 		default:
-			ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
+			c.ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
 			v = 0
 		}
 
@@ -2469,61 +2570,61 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = OP_BCR(o1, uint32(v), uint32(r))
 
 	case 19: /* mov $lcon,r ==> cau+or */
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&p.From)
 
 		if p.From.Sym == nil {
 			o1 = loadu32(int(p.To.Reg), d)
 			o2 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(int32(d)))
 		} else {
-			o1, o2 = symbolAccess(ctxt, p.From.Sym, d, p.To.Reg, OP_ADDI)
+			o1, o2 = c.symbolAccess(p.From.Sym, d, p.To.Reg, OP_ADDI)
 		}
 
 	//if(dlm) reloc(&p->from, p->pc, 0);
 
 	case 20: /* add $ucon,,r */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 		if p.As == AADD && (r0iszero == 0 /*TypeKind(100016)*/ && p.Reg == 0 || r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0) {
-			ctxt.Diag("literal operation on R0\n%v", p)
+			c.ctxt.Diag("literal operation on R0\n%v", p)
 		}
-		o1 = AOP_IRR(opirr(ctxt, -p.As), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
+		o1 = AOP_IRR(c.opirr(-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("can't synthesize large constant\n%v", p)
+			c.ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&p.From)
 		o1 = loadu32(REGTMP, d)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(r))
+		o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
 		if p.From.Sym != nil {
-			ctxt.Diag("%v is not supported", p)
+			c.ctxt.Diag("%v is not supported", p)
 		}
 
 	//if(dlm) reloc(&p->from, p->pc, 0);
 
 	case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
 		if p.To.Reg == REGTMP || p.Reg == REGTMP {
-			ctxt.Diag("can't synthesize large constant\n%v", p)
+			c.ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&p.From)
 		o1 = loadu32(REGTMP, d)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = LOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(r))
+		o3 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
 		if p.From.Sym != nil {
-			ctxt.Diag("%v is not supported", p)
+			c.ctxt.Diag("%v is not supported", p)
 		}
 
 		//if(dlm) reloc(&p->from, p->pc, 0);
@@ -2531,7 +2632,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		/*24*/
 	case 25:
 		/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		if v < 0 {
 			v = 0
@@ -2543,39 +2644,35 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(p.To.Reg)
 		}
 		var a int
+		op := uint32(0)
 		switch p.As {
 		case ASLD, ASLDCC:
 			a = int(63 - v)
-			o1 = OP_RLDICR
+			op = OP_RLDICR
 
 		case ASRD, ASRDCC:
 			a = int(v)
 			v = 64 - v
-			o1 = OP_RLDICL
-
+			op = OP_RLDICL
+		case AROTL:
+			a = int(0)
+			op = OP_RLDICL
 		default:
-			ctxt.Diag("unexpected op in sldi case\n%v", p)
+			c.ctxt.Diag("unexpected op in sldi case\n%v", p)
 			a = 0
 			o1 = 0
 		}
 
-		o1 = AOP_RRR(o1, uint32(r), uint32(p.To.Reg), (uint32(v) & 0x1F))
-		o1 |= (uint32(a) & 31) << 6
-		if v&0x20 != 0 {
-			o1 |= 1 << 1
-		}
-		if a&0x20 != 0 {
-			o1 |= 1 << 5 /* mb[5] is top bit */
-		}
+		o1 = AOP_RLDIC(op, uint32(p.To.Reg), uint32(r), uint32(v), uint32(a))
 		if p.As == ASLDCC || p.As == ASRDCC {
-			o1 |= 1 /* Rc */
+			o1 |= 1 // Set the condition code bit
 		}
 
 	case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
 		if p.To.Reg == REGTMP {
-			ctxt.Diag("can't synthesize large constant\n%v", p)
+			c.ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
@@ -2584,57 +2681,57 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
 
 	case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
-		v := regoff(ctxt, p.From3)
+		v := c.regoff(p.From3)
 
 		r := int(p.From.Reg)
-		o1 = AOP_IRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+		o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
 		if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
-			ctxt.Diag("can't synthesize large constant\n%v", p)
+			c.ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		v := regoff(ctxt, p.From3)
+		v := c.regoff(p.From3)
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v))
-		o3 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
+		o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
 		if p.From.Sym != nil {
-			ctxt.Diag("%v is not supported", p)
+			c.ctxt.Diag("%v is not supported", p)
 		}
 
 	//if(dlm) reloc(&p->from3, p->pc, 0);
 
 	case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
-		d := vregoff(ctxt, p.From3)
+		d := c.vregoff(p.From3)
 		var mask [2]uint8
-		maskgen64(ctxt, p, mask[:], uint64(d))
+		c.maskgen64(p, mask[:], uint64(d))
 		var a int
 		switch p.As {
 		case ARLDC, ARLDCCC:
 			a = int(mask[0]) /* MB */
 			if int32(mask[1]) != (63 - v) {
-				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+				c.ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
 
 		case ARLDCL, ARLDCLCC:
 			a = int(mask[0]) /* MB */
 			if mask[1] != 63 {
-				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+				c.ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
 
 		case ARLDCR, ARLDCRCC:
 			a = int(mask[1]) /* ME */
 			if mask[0] != 0 {
-				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+				c.ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
 
 		default:
-			ctxt.Diag("unexpected op in rldic case\n%v", p)
+			c.ctxt.Diag("unexpected op in rldic case\n%v", p)
 			a = 0
 		}
 
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+		o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
 		o1 |= (uint32(a) & 31) << 6
 		if v&0x20 != 0 {
 			o1 |= 1 << 1
@@ -2644,20 +2741,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 30: /* rldimi $sh,s,$mask,a */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
-		d := vregoff(ctxt, p.From3)
+		d := c.vregoff(p.From3)
 
 		// Original opcodes had mask operands which had to be converted to a shift count as expected by
 		// the ppc64 asm.
 		switch p.As {
 		case ARLDMI, ARLDMICC:
 			var mask [2]uint8
-			maskgen64(ctxt, p, mask[:], uint64(d))
+			c.maskgen64(p, mask[:], uint64(d))
 			if int32(mask[1]) != (63 - v) {
-				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+				c.ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
-			o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+			o1 = AOP_RRR(c.opirr(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
@@ -2668,17 +2765,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 		// Opcodes with shift count operands.
 		case ARLDIMI, ARLDIMICC:
-			o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+			o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
 			o1 |= (uint32(d) & 31) << 6
+			if d&0x20 != 0 {
+				o1 |= 1 << 5
+			}
 			if v&0x20 != 0 {
 				o1 |= 1 << 1
 			}
 		}
 
 	case 31: /* dword */
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&p.From)
 
-		if ctxt.Arch.ByteOrder == binary.BigEndian {
+		if c.ctxt.Arch.ByteOrder == binary.BigEndian {
 			o1 = uint32(d >> 32)
 			o2 = uint32(d)
 		} else {
@@ -2687,12 +2787,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 		if p.From.Sym != nil {
-			rel := obj.Addrel(ctxt.Cursym)
-			rel.Off = int32(ctxt.Pc)
+			rel := obj.Addrel(c.cursym)
+			rel.Off = int32(c.pc)
 			rel.Siz = 8
 			rel.Sym = p.From.Sym
 			rel.Add = p.From.Offset
-			rel.Type = obj.R_ADDR
+			rel.Type = objabi.R_ADDR
 			o2 = 0
 			o1 = o2
 		}
@@ -2703,7 +2803,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), 0) | (uint32(p.From.Reg)&31)<<6
+		o1 = AOP_RRR(c.oprrr(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)
@@ -2711,62 +2811,67 @@ 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(oprrr(ctxt, p.As), uint32(p.To.Reg), 0, uint32(r))
+		o1 = AOP_RRR(c.oprrr(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(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.From3.Reg)&31)<<6
+	case 34: /* FMADDx fra,frb,frc,frt (t=a*c±b) */
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.From3.Reg)&31)<<6
 
 	case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
+		// Offsets in DS form stores must be a multiple of 4
+		inst := c.opstore(p.As)
+		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+			log.Fatalf("invalid offset for DS form load/store %v", p)
+		}
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-		o2 = AOP_IRR(opstore(ctxt, p.As), uint32(p.From.Reg), REGTMP, uint32(v))
+		o2 = AOP_IRR(inst, uint32(p.From.Reg), REGTMP, uint32(v))
 
 	case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-		o2 = AOP_IRR(opload(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(v))
+		o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v))
 
 	case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-		o2 = AOP_IRR(opload(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(v))
+		o2 = AOP_IRR(c.opload(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))
+		o1 = uint32(c.regoff(&p.From))
 
 	case 41: /* stswi */
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(regoff(ctxt, p.From3))&0x7F)<<11
+		o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(c.regoff(p.From3))&0x7F)<<11
 
 	case 42: /* lswi */
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(regoff(ctxt, p.From3))&0x7F)<<11
+		o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(c.regoff(p.From3))&0x7F)<<11
 
 	case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
-		o1 = AOP_RRR(oprrr(ctxt, p.As), 0, uint32(p.From.Index), uint32(p.From.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), 0, uint32(p.From.Index), uint32(p.From.Reg))
 
 	case 44: /* indexed store */
-		o1 = AOP_RRR(opstorex(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
+		o1 = AOP_RRR(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
 
 	case 45: /* indexed load */
-		o1 = AOP_RRR(oploadx(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
+		o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
 
 	case 46: /* plain op */
-		o1 = oprrr(ctxt, p.As)
+		o1 = c.oprrr(p.As)
 
 	case 47: /* op Ra, Rd; also op [Ra,] Rd */
 		r := int(p.From.Reg)
@@ -2774,7 +2879,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), 0)
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0)
 
 	case 48: /* op Rs, Ra */
 		r := int(p.From.Reg)
@@ -2782,14 +2887,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = LOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), 0)
+		o1 = LOP_RRR(c.oprrr(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(oprrr(ctxt, p.As), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
+			v := c.regoff(&p.From) & 1
+			o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
 		} else {
-			o1 = AOP_RRR(oprrr(ctxt, p.As), 0, 0, uint32(p.From.Reg))
+			o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.From.Reg))
 		}
 
 	case 50: /* rem[u] r1[,r2],r3 */
@@ -2798,7 +2903,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v := oprrr(ctxt, p.As)
+		v := c.oprrr(p.As)
 		t := v & (1<<10 | 1) /* OE|Rc */
 		o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
 		o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
@@ -2816,16 +2921,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v := oprrr(ctxt, p.As)
+		v := c.oprrr(p.As)
 		t := v & (1<<10 | 1) /* OE|Rc */
 		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|t, uint32(p.To.Reg), REGTMP, uint32(r))
 
 	case 52: /* mtfsbNx cr(n) */
-		v := regoff(ctxt, &p.From) & 31
+		v := c.regoff(&p.From) & 31
 
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(v), 0, 0)
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(v), 0, 0)
 
 	case 53: /* mffsX ,fr1 */
 		o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)
@@ -2842,22 +2947,22 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 55: /* op Rb, Rd */
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), 0, uint32(p.From.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(p.From.Reg))
 
 	case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(r), uint32(p.To.Reg), uint32(v)&31)
+		o1 = AOP_RRR(c.opirr(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] */
 		}
 
 	case 57: /* slw $sh,[s,]a -> rlwinm ... */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
@@ -2877,68 +2982,68 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			v = 32
 		}
 		var mask [2]uint8
-		if p.As == ASRW || p.As == ASRWCC { /* shift right */
-			mask[0] = uint8(v)
-			mask[1] = 31
+		switch p.As {
+		case AROTLW:
+			mask[0], mask[1] = 0, 31
+		case ASRW, ASRWCC:
+			mask[0], mask[1] = uint8(v), 31
 			v = 32 - v
-		} else {
-			mask[0] = 0
-			mask[1] = uint8(31 - v)
+		default:
+			mask[0], mask[1] = 0, uint8(31-v)
 		}
-
 		o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(r), uint32(v), uint32(mask[0]), uint32(mask[1]))
 		if p.As == ASLWCC || p.As == ASRWCC {
-			o1 |= 1 /* Rc */
+			o1 |= 1 // set the condition code
 		}
 
 	case 58: /* logical $andcon,[s],a */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = LOP_IRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+		o1 = LOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 59: /* or/and $ucon,,r */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = LOP_IRR(opirr(ctxt, -p.As), uint32(p.To.Reg), uint32(r), uint32(v)>>16) /* oris, xoris, andis */
+		o1 = LOP_IRR(c.opirr(-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)
+		r := int(c.regoff(&p.From) & 31)
 
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(r), uint32(p.Reg), uint32(p.To.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(r), uint32(p.Reg), uint32(p.To.Reg))
 
 	case 61: /* tw to,a,$simm */
-		r := int(regoff(ctxt, &p.From) & 31)
+		r := int(c.regoff(&p.From) & 31)
 
-		v := regoff(ctxt, &p.To)
-		o1 = AOP_IRR(opirr(ctxt, p.As), uint32(r), uint32(p.Reg), uint32(v))
+		v := c.regoff(&p.To)
+		o1 = AOP_IRR(c.opirr(p.As), uint32(r), uint32(p.Reg), uint32(v))
 
 	case 62: /* rlwmi $sh,s,$mask,a */
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 
 		var mask [2]uint8
-		maskgen(ctxt, p, mask[:], uint32(regoff(ctxt, p.From3)))
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
+		c.maskgen(p, mask[:], uint32(c.regoff(p.From3)))
+		o1 = AOP_RRR(c.opirr(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)))
+		c.maskgen(p, mask[:], uint32(c.regoff(p.From3)))
 
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
+		o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
 		o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
 
 	case 64: /* mtfsf fr[, $m] {,fpcsr} */
 		var v int32
 		if p.From3Type() != obj.TYPE_NONE {
-			v = regoff(ctxt, p.From3) & 255
+			v = c.regoff(p.From3) & 255
 		} else {
 			v = 255
 		}
@@ -2946,9 +3051,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
 		if p.To.Reg == 0 {
-			ctxt.Diag("must specify FPSCR(n)\n%v", p)
+			c.ctxt.Diag("must specify FPSCR(n)\n%v", p)
 		}
-		o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(regoff(ctxt, &p.From))&31)<<12
+		o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(c.regoff(&p.From))&31)<<12
 
 	case 66: /* mov spr,r1; mov r1,spr, also dcr */
 		var r int
@@ -2975,7 +3080,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 67: /* mcrf crfD,crfS */
 		if p.From.Type != obj.TYPE_REG || p.From.Reg < REG_CR0 || REG_CR7 < p.From.Reg || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
-			ctxt.Diag("illegal CR field number\n%v", p)
+			c.ctxt.Diag("illegal CR field number\n%v", p)
 		}
 		o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
 
@@ -2991,9 +3096,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		var v int32
 		if p.From3Type() != obj.TYPE_NONE {
 			if p.To.Reg != 0 {
-				ctxt.Diag("can't use both mask and CR(n)\n%v", p)
+				c.ctxt.Diag("can't use both mask and CR(n)\n%v", p)
 			}
-			v = regoff(ctxt, p.From3) & 0xff
+			v = c.regoff(p.From3) & 0xff
 		} else {
 			if p.To.Reg == 0 {
 				v = 0xff /* CR */
@@ -3011,7 +3116,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else {
 			r = (int(p.Reg) & 7) << 2
 		}
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 71: /* cmp[l] r,i,cr*/
 		var r int
@@ -3020,32 +3125,32 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else {
 			r = (int(p.Reg) & 7) << 2
 		}
-		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(r), uint32(p.From.Reg), 0) | uint32(regoff(ctxt, &p.To))&0xffff
+		o1 = AOP_RRR(c.opirr(p.As), uint32(r), uint32(p.From.Reg), 0) | uint32(c.regoff(&p.To))&0xffff
 
 	case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
-		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.From.Reg), 0, uint32(p.To.Reg))
+		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), 0, uint32(p.To.Reg))
 
 	case 73: /* mcrfs crfD,crfS */
 		if p.From.Type != obj.TYPE_REG || p.From.Reg != REG_FPSCR || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
-			ctxt.Diag("illegal FPSCR/CR field number\n%v", p)
+			c.ctxt.Diag("illegal FPSCR/CR field number\n%v", p)
 		}
 		o1 = AOP_RRR(OP_MCRFS, ((uint32(p.To.Reg) & 7) << 2), ((0 & 7) << 2), 0)
 
 	case 77: /* syscall $scon, syscall Rx */
 		if p.From.Type == obj.TYPE_CONST {
 			if p.From.Offset > BIG || p.From.Offset < -BIG {
-				ctxt.Diag("illegal syscall, sysnum too large: %v", p)
+				c.ctxt.Diag("illegal syscall, sysnum too large: %v", p)
 			}
 			o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(p.From.Offset))
 		} else if p.From.Type == obj.TYPE_REG {
 			o1 = LOP_RRR(OP_OR, REGZERO, uint32(p.From.Reg), uint32(p.From.Reg))
 		} else {
-			ctxt.Diag("illegal syscall: %v", p)
+			c.ctxt.Diag("illegal syscall: %v", p)
 			o1 = 0x7fe00008 // trap always
 		}
 
-		o2 = oprrr(ctxt, p.As)
-		o3 = AOP_RRR(oprrr(ctxt, AXOR), REGZERO, REGZERO, REGZERO) // XOR R0, R0
+		o2 = c.oprrr(p.As)
+		o3 = AOP_RRR(c.oprrr(AXOR), REGZERO, REGZERO, REGZERO) // XOR R0, R0
 
 	case 78: /* undef */
 		o1 = 0 /* "An instruction consisting entirely of binary 0s is guaranteed
@@ -3053,98 +3158,113 @@ 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, p.As))
+		v := c.vregoff(&p.To)
+		// Offsets in DS form stores must be a multiple of 4
+		inst := c.opstore(p.As)
+		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+			log.Fatalf("invalid offset for DS form load/store %v", p)
+		}
+		o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst)
 
 	//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, p.As))
+		v := c.vregoff(&p.From)
+		// Offsets in DS form loads must be a multiple of 4
+		inst := c.opload(p.As)
+		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+			log.Fatalf("invalid offset for DS form load/store %v", p)
+		}
+		o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
 
 	//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, p.As))
+		v := c.vregoff(&p.From)
+		// Offsets in DS form loads must be a multiple of 4
+		inst := c.opload(p.As)
+		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+			log.Fatalf("invalid offset for DS form load/store %v", p)
+		}
+		o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
 		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
 		//if(dlm) reloc(&p->from, p->pc, 1);
 
 	case 79:
 		if p.From.Offset != 0 {
-			ctxt.Diag("invalid offset against tls var %v", p)
+			c.ctxt.Diag("invalid offset against tls var %v", p)
 		}
 		o1 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGZERO, 0)
-		rel := obj.Addrel(ctxt.Cursym)
-		rel.Off = int32(ctxt.Pc)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_POWER_TLS_LE
+		rel.Type = objabi.R_POWER_TLS_LE
 
 	case 80:
 		if p.From.Offset != 0 {
-			ctxt.Diag("invalid offset against tls var %v", p)
+			c.ctxt.Diag("invalid offset against tls var %v", p)
 		}
 		o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 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)
+		o2 = AOP_IRR(c.opload(AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_POWER_TLS_IE
+		rel.Type = objabi.R_POWER_TLS_IE
 
 	case 81:
-		v := vregoff(ctxt, &p.To)
+		v := c.vregoff(&p.To)
 		if v != 0 {
-			ctxt.Diag("invalid offset against GOT slot %v", p)
+			c.ctxt.Diag("invalid offset against GOT slot %v", p)
 		}
 
 		o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 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)
+		o2 = AOP_IRR(c.opload(AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+		rel := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_ADDRPOWER_GOT
+		rel.Type = objabi.R_ADDRPOWER_GOT
 	case 82: /* vector instructions, VX-form and VC-form */
 		if p.From.Type == obj.TYPE_REG {
 			/* reg reg none OR reg reg reg */
 			/* 3-register operand order: VRA, VRB, VRT */
 			/* 2-register operand order: VRA, VRT */
-			o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+			o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
 		} else if p.From3Type() == obj.TYPE_CONST {
 			/* imm imm reg reg */
 			/* operand order: SIX, VRA, ST, VRT */
-			six := int(regoff(ctxt, &p.From))
-			st := int(regoff(ctxt, p.From3))
-			o1 = AOP_IIRR(opiirr(ctxt, p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six))
+			six := int(c.regoff(&p.From))
+			st := int(c.regoff(p.From3))
+			o1 = AOP_IIRR(c.opiirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six))
 		} else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 {
 			/* imm reg reg */
 			/* operand order: UIM, VRB, VRT */
-			uim := int(regoff(ctxt, &p.From))
-			o1 = AOP_VIRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(uim))
+			uim := int(c.regoff(&p.From))
+			o1 = AOP_VIRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(uim))
 		} else {
 			/* imm reg */
 			/* operand order: SIM, VRT */
-			sim := int(regoff(ctxt, &p.From))
-			o1 = AOP_IR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(sim))
+			sim := int(c.regoff(&p.From))
+			o1 = AOP_IR(c.opirr(p.As), uint32(p.To.Reg), uint32(sim))
 		}
 
 	case 83: /* vector instructions, VA-form */
 		if p.From.Type == obj.TYPE_REG {
 			/* reg reg reg reg */
 			/* 4-register operand order: VRA, VRB, VRC, VRT */
-			o1 = AOP_RRRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg))
+			o1 = AOP_RRRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg))
 		} else if p.From.Type == obj.TYPE_CONST {
 			/* imm reg reg reg */
 			/* operand order: SHB, VRA, VRB, VRT */
-			shb := int(regoff(ctxt, &p.From))
-			o1 = AOP_IRRR(opirrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), uint32(shb))
+			shb := int(c.regoff(&p.From))
+			o1 = AOP_IRRR(c.opirrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), uint32(shb))
 		}
 
 	case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc
-		bc := vregoff(ctxt, &p.From)
+		bc := c.vregoff(&p.From)
 
 		// rt = To.Reg, ra = p.Reg, rb = p.From3.Reg
 		o1 = AOP_ISEL(OP_ISEL, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), uint32(bc))
@@ -3152,17 +3272,17 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 85: /* vector instructions, VX-form */
 		/* reg none reg */
 		/* 2-register operand order: VRB, VRT */
-		o1 = AOP_RR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg))
+		o1 = AOP_RR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg))
 
 	case 86: /* VSX indexed store, XX1-form */
 		/* reg reg reg */
 		/* 3-register operand order: XT, (RB)(RA*1) */
-		o1 = AOP_XX1(opstorex(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
+		o1 = AOP_XX1(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
 
 	case 87: /* VSX indexed load, XX1-form */
 		/* reg reg reg */
 		/* 3-register operand order: (RB)(RA*1), XT */
-		o1 = AOP_XX1(oploadx(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
+		o1 = AOP_XX1(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
 
 	case 88: /* VSX instructions, XX1-form */
 		/* reg reg none OR reg reg reg */
@@ -3170,34 +3290,74 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		/* 2-register operand order: XS, RA or RA, XT */
 		xt := int32(p.To.Reg)
 		xs := int32(p.From.Reg)
-		if REG_VS0 <= xt && xt <= REG_VS63 {
-			o1 = AOP_XX1(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+		/* We need to treat the special case of extended mnemonics that may have a FREG/VREG as an argument */
+		if REG_V0 <= xt && xt <= REG_V31 {
+			/* Convert V0-V31 to VS32-VS63 */
+			xt = xt + 64
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+		} else if REG_F0 <= xt && xt <= REG_F31 {
+			/* Convert F0-F31 to VS0-VS31 */
+			xt = xt + 64
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+		} else if REG_VS0 <= xt && xt <= REG_VS63 {
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+		} else if REG_V0 <= xs && xs <= REG_V31 {
+			/* Likewise for XS */
+			xs = xs + 64
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
+		} else if REG_F0 <= xs && xs <= REG_F31 {
+			xs = xs + 64
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
 		} else if REG_VS0 <= xs && xs <= REG_VS63 {
-			o1 = AOP_XX1(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
+			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
 		}
 
 	case 89: /* VSX instructions, XX2-form */
 		/* reg none reg OR reg imm reg */
 		/* 2-register operand order: XB, XT or XB, UIM, XT*/
-		uim := int(regoff(ctxt, p.From3))
-		o1 = AOP_XX2(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg))
+		uim := int(c.regoff(p.From3))
+		o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg))
 
 	case 90: /* VSX instructions, XX3-form */
 		if p.From3Type() == obj.TYPE_NONE {
 			/* reg reg reg */
 			/* 3-register operand order: XA, XB, XT */
-			o1 = AOP_XX3(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+			o1 = AOP_XX3(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
 		} else if p.From3Type() == obj.TYPE_CONST {
 			/* reg reg reg imm */
 			/* operand order: XA, XB, DM, XT */
-			dm := int(regoff(ctxt, p.From3))
-			o1 = AOP_XX3I(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm))
+			dm := int(c.regoff(p.From3))
+			o1 = AOP_XX3I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm))
 		}
 
 	case 91: /* VSX instructions, XX4-form */
 		/* reg reg reg reg */
 		/* 3-register operand order: XA, XB, XC, XT */
-		o1 = AOP_XX4(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg))
+		o1 = AOP_XX4(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg))
+
+	case 92: /* X-form instructions, 3-operands */
+		if p.To.Type == obj.TYPE_CONST {
+			/* imm reg reg */
+			/* operand order: FRA, FRB, BF */
+			bf := int(c.regoff(&p.To)) << 2
+			o1 = AOP_RRR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg), uint32(p.Reg))
+		} else if p.To.Type == obj.TYPE_REG {
+			/* reg reg reg */
+			/* operand order: RS, RB, RA */
+			o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
+		}
+
+	case 93: /* X-form instructions, 2-operands */
+		if p.To.Type == obj.TYPE_CONST {
+			/* imm reg */
+			/* operand order: FRB, BF */
+			bf := int(c.regoff(&p.To)) << 2
+			o1 = AOP_RR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg))
+		} else if p.Reg == 0 {
+			/* popcnt* r,r, X-form */
+			/* operand order: RS, RA */
+			o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
+		}
 
 	}
 
@@ -3209,19 +3369,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	return
 }
 
-func vregoff(ctxt *obj.Link, a *obj.Addr) int64 {
-	ctxt.Instoffset = 0
+func (c *ctxt9) vregoff(a *obj.Addr) int64 {
+	c.instoffset = 0
 	if a != nil {
-		aclass(ctxt, a)
+		c.aclass(a)
 	}
-	return ctxt.Instoffset
+	return c.instoffset
 }
 
-func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
-	return int32(vregoff(ctxt, a))
+func (c *ctxt9) regoff(a *obj.Addr) int32 {
+	return int32(c.vregoff(a))
 }
 
-func oprrr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) oprrr(a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return OPVCC(31, 266, 0, 0)
@@ -3281,6 +3441,8 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVCC(31, 0, 0, 0) /* L=0 */
 	case ACMPWU:
 		return OPVCC(31, 32, 0, 0)
+	case ACMPB:
+		return OPVCC(31, 508, 0, 0) /* cmpb - v2.05 */
 
 	case ACNTLZW:
 		return OPVCC(31, 26, 0, 0)
@@ -3621,6 +3783,13 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	case AORNCC:
 		return OPVCC(31, 412, 0, 1)
 
+	case APOPCNTD:
+		return OPVCC(31, 506, 0, 0) /* popcntd - v2.06 */
+	case APOPCNTW:
+		return OPVCC(31, 378, 0, 0) /* popcntw - v2.06 */
+	case APOPCNTB:
+		return OPVCC(31, 122, 0, 0) /* popcntb - v2.02 */
+
 	case ARFI:
 		return OPVCC(19, 50, 0, 0)
 	case ARFCI:
@@ -3757,14 +3926,14 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	/* Vector (VMX/Altivec) instructions */
 	/* ISA 2.03 enables these for PPC970. For POWERx processors, these */
 	/* are enabled starting at POWER6 (ISA 2.05). */
-	case AVANDL:
+	case AVAND:
 		return OPVX(4, 1028, 0, 0) /* vand - v2.03 */
 	case AVANDC:
 		return OPVX(4, 1092, 0, 0) /* vandc - v2.03 */
 	case AVNAND:
 		return OPVX(4, 1412, 0, 0) /* vnand - v2.07 */
 
-	case AVORL:
+	case AVOR:
 		return OPVX(4, 1156, 0, 0) /* vor - v2.03 */
 	case AVORC:
 		return OPVX(4, 1348, 0, 0) /* vorc - v2.07 */
@@ -3810,6 +3979,15 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	case AVADDECUQ:
 		return OPVX(4, 61, 0, 0) /* vaddecuq - v2.07 */
 
+	case AVPMSUMB:
+		return OPVX(4, 1032, 0, 0) /* vpmsumb - v2.07 */
+	case AVPMSUMH:
+		return OPVX(4, 1096, 0, 0) /* vpmsumh - v2.07 */
+	case AVPMSUMW:
+		return OPVX(4, 1160, 0, 0) /* vpmsumw - v2.07 */
+	case AVPMSUMD:
+		return OPVX(4, 1224, 0, 0) /* vpmsumd - v2.07 */
+
 	case AVSUBUBM:
 		return OPVX(4, 1024, 0, 0) /* vsububm - v2.03 */
 	case AVSUBUHM:
@@ -3976,12 +4154,12 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 
 	/* Vector scalar (VSX) instructions */
 	/* ISA 2.06 enables these for POWER7. */
-	case AMFVSRD:
+	case AMFVSRD, AMFVRD, AMFFPRD:
 		return OPVXX1(31, 51, 0) /* mfvsrd - v2.07 */
 	case AMFVSRWZ:
 		return OPVXX1(31, 115, 0) /* mfvsrwz - v2.07 */
 
-	case AMTVSRD:
+	case AMTVSRD, AMTFPRD, AMTVRD:
 		return OPVXX1(31, 179, 0) /* mtvsrd - v2.07 */
 	case AMTVSRWA:
 		return OPVXX1(31, 211, 0) /* mtvsrwa - v2.07 */
@@ -4096,11 +4274,11 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVCC(31, 316, 0, 1)
 	}
 
-	ctxt.Diag("bad r/r, r/r/r or r/r/r/r opcode %v", a)
+	c.ctxt.Diag("bad r/r, r/r/r or r/r/r/r opcode %v", a)
 	return 0
 }
 
-func opirrr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opirrr(a obj.As) uint32 {
 	switch a {
 	/* Vector (VMX/Altivec) instructions */
 	/* ISA 2.03 enables these for PPC970. For POWERx processors, these */
@@ -4109,11 +4287,11 @@ func opirrr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVX(4, 44, 0, 0) /* vsldoi - v2.03 */
 	}
 
-	ctxt.Diag("bad i/r/r/r opcode %v", a)
+	c.ctxt.Diag("bad i/r/r/r opcode %v", a)
 	return 0
 }
 
-func opiirr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opiirr(a obj.As) uint32 {
 	switch a {
 	/* Vector (VMX/Altivec) instructions */
 	/* ISA 2.07 enables these for POWER8 and beyond. */
@@ -4123,11 +4301,11 @@ func opiirr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVX(4, 1730, 0, 0) /* vshasigmad - v2.07 */
 	}
 
-	ctxt.Diag("bad i/i/r/r opcode %v", a)
+	c.ctxt.Diag("bad i/i/r/r opcode %v", a)
 	return 0
 }
 
-func opirr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opirr(a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return OPVCC(14, 0, 0, 0)
@@ -4260,20 +4438,25 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVX(4, 908, 0, 0) /* vspltisw - v2.03 */
 	/* End of vector instructions */
 
+	case AFTDIV:
+		return OPVCC(63, 128, 0, 0) /* ftdiv - v2.06 */
+	case AFTSQRT:
+		return OPVCC(63, 160, 0, 0) /* ftsqrt - v2.06 */
+
 	case AXOR:
 		return OPVCC(26, 0, 0, 0) /* XORIL */
 	case -AXOR:
 		return OPVCC(27, 0, 0, 0) /* XORIU */
 	}
 
-	ctxt.Diag("bad opcode i/r or i/r/r %v", a)
+	c.ctxt.Diag("bad opcode i/r or i/r/r %v", a)
 	return 0
 }
 
 /*
  * load o(a),d
  */
-func opload(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opload(a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return OPVCC(58, 0, 0, 0) /* ld */
@@ -4313,14 +4496,14 @@ func opload(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVCC(46, 0, 0, 0) /* lmw */
 	}
 
-	ctxt.Diag("bad load opcode %v", a)
+	c.ctxt.Diag("bad load opcode %v", a)
 	return 0
 }
 
 /*
  * indexed load a(b),d
  */
-func oploadx(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) oploadx(a obj.As) uint32 {
 	switch a {
 	case AMOVWZ:
 		return OPVCC(31, 23, 0, 0) /* lwzx */
@@ -4416,14 +4599,14 @@ func oploadx(ctxt *obj.Link, a obj.As) uint32 {
 
 	}
 
-	ctxt.Diag("bad loadx opcode %v", a)
+	c.ctxt.Diag("bad loadx opcode %v", a)
 	return 0
 }
 
 /*
  * store s,o(d)
  */
-func opstore(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opstore(a obj.As) uint32 {
 	switch a {
 	case AMOVB, AMOVBZ:
 		return OPVCC(38, 0, 0, 0) /* stb */
@@ -4460,14 +4643,14 @@ func opstore(ctxt *obj.Link, a obj.As) uint32 {
 		return OPVCC(62, 0, 0, 1) /* stdu */
 	}
 
-	ctxt.Diag("unknown store opcode %v", a)
+	c.ctxt.Diag("unknown store opcode %v", a)
 	return 0
 }
 
 /*
  * indexed store s,a(b)
  */
-func opstorex(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxt9) opstorex(a obj.As) uint32 {
 	switch a {
 	case AMOVB, AMOVBZ:
 		return OPVCC(31, 215, 0, 0) /* stbx */
@@ -4546,6 +4729,6 @@ func opstorex(ctxt *obj.Link, a obj.As) uint32 {
 
 	}
 
-	ctxt.Diag("unknown storex opcode %v", a)
+	c.ctxt.Diag("unknown storex opcode %v", a)
 	return 0
 }
diff --git a/src/cmd/internal/obj/ppc64/list9.go b/src/cmd/internal/obj/ppc64/list9.go
index dfc4896..461950d 100644
--- a/src/cmd/internal/obj/ppc64/list9.go
+++ b/src/cmd/internal/obj/ppc64/list9.go
@@ -35,11 +35,11 @@ import (
 )
 
 func init() {
-	obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, Rconv)
+	obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, rconv)
 	obj.RegisterOpcode(obj.ABasePPC64, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 68211ee..b1509e3 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -31,15 +31,16 @@ package ppc64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
-	"fmt"
-	"math"
 )
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 	p.From.Class = 0
 	p.To.Class = 0
 
+	c := ctxt9{ctxt: ctxt, newprog: newprog}
+
 	// Rewrite BR/BL to symbol as TYPE_BRANCH.
 	switch p.As {
 	case ABR,
@@ -57,26 +58,17 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AFMOVS:
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			literal := fmt.Sprintf("$f32.%08x", i32)
-			s := obj.Linklookup(ctxt, literal, 0)
-			s.Size = 4
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
-			p.From.Sym.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float32Sym(f32)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
 
 	case AFMOVD:
 		if p.From.Type == obj.TYPE_FCONST {
-			i64 := math.Float64bits(p.From.Val.(float64))
-			literal := fmt.Sprintf("$f64.%016x", i64)
-			s := obj.Linklookup(ctxt, literal, 0)
-			s.Size = 8
+			f64 := p.From.Val.(float64)
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
-			p.From.Sym.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float64Sym(f64)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -84,12 +76,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		// Put >32-bit constants in memory and load them
 	case AMOVD:
 		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
-			literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
-			s := obj.Linklookup(ctxt, literal, 0)
-			s.Size = 8
 			p.From.Type = obj.TYPE_MEM
-			p.From.Sym = s
-			p.From.Sym.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -115,13 +103,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 			p.As = AADD
 		}
 	}
-	if ctxt.Flag_dynlink {
-		rewriteToUseGot(ctxt, p)
+	if c.ctxt.Flag_dynlink {
+		c.rewriteToUseGot(p)
 	}
 }
 
 // Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
 	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
 		//     ADUFFxxx $offset
 		// becomes
@@ -131,9 +119,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		//     BL (CTR)
 		var sym *obj.LSym
 		if p.As == obj.ADUFFZERO {
-			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+			sym = c.ctxt.Lookup("runtime.duffzero")
 		} else {
-			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+			sym = c.ctxt.Lookup("runtime.duffcopy")
 		}
 		offset := p.To.Offset
 		p.As = AMOVD
@@ -145,19 +133,19 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		p.To.Name = obj.NAME_NONE
 		p.To.Offset = 0
 		p.To.Sym = nil
-		p1 := obj.Appendp(ctxt, p)
+		p1 := obj.Appendp(p, c.newprog)
 		p1.As = AADD
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = offset
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = REG_R12
-		p2 := obj.Appendp(ctxt, p1)
+		p2 := obj.Appendp(p1, c.newprog)
 		p2.As = AMOVD
 		p2.From.Type = obj.TYPE_REG
 		p2.From.Reg = REG_R12
 		p2.To.Type = obj.TYPE_REG
 		p2.To.Reg = REG_CTR
-		p3 := obj.Appendp(ctxt, p2)
+		p3 := obj.Appendp(p2, c.newprog)
 		p3.As = obj.ACALL
 		p3.From.Type = obj.TYPE_REG
 		p3.From.Reg = REG_R12
@@ -172,15 +160,15 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
 		// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
 		if p.As != AMOVD {
-			ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
 		}
 		if p.To.Type != obj.TYPE_REG {
-			ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
 		}
 		p.From.Type = obj.TYPE_MEM
 		p.From.Name = obj.NAME_GOTREF
 		if p.From.Offset != 0 {
-			q := obj.Appendp(ctxt, p)
+			q := obj.Appendp(p, c.newprog)
 			q.As = AADD
 			q.From.Type = obj.TYPE_CONST
 			q.From.Offset = p.From.Offset
@@ -189,7 +177,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 	if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
 	var source *obj.Addr
 	// MOVx sym, Ry becomes MOVD sym at GOT, REGTMP; MOVx (REGTMP), Ry
@@ -197,7 +185,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	// 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)
+			c.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() {
@@ -208,14 +196,14 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	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 {
+	if source.Sym.Type == objabi.STLSBSS {
 		return
 	}
 	if source.Type != obj.TYPE_MEM {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
-	p1 := obj.Appendp(ctxt, p)
-	p2 := obj.Appendp(ctxt, p1)
+	p1 := obj.Appendp(p, c.newprog)
+	p2 := obj.Appendp(p1, c.newprog)
 
 	p1.As = AMOVD
 	p1.From.Type = obj.TYPE_MEM
@@ -241,32 +229,32 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	obj.Nopout(p)
 }
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 	// TODO(minux): add morestack short-cuts with small fixed frame-size.
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
+	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
 		return
 	}
 
-	p := cursym.Text
+	c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
+
+	p := c.cursym.Func.Text
 	textstksiz := p.To.Offset
 	if textstksiz == -8 {
 		// Compatibility hack.
-		p.From3.Offset |= obj.NOFRAME
+		p.From.Sym.Set(obj.AttrNoFrame, true)
 		textstksiz = 0
 	}
 	if textstksiz%8 != 0 {
-		ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
+		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
 	}
-	if p.From3.Offset&obj.NOFRAME != 0 {
+	if p.From.Sym.NoFrame() {
 		if textstksiz != 0 {
-			ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
+			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
 		}
 	}
 
-	cursym.Args = p.To.Val.(int32)
-	cursym.Locals = int32(textstksiz)
+	c.cursym.Func.Args = p.To.Val.(int32)
+	c.cursym.Func.Locals = int32(textstksiz)
 
 	/*
 	 * find leaf subroutines
@@ -274,13 +262,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	 * expand RET
 	 * expand BECOME pseudo
 	 */
-	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f noops\n", obj.Cputime())
-	}
 
 	var q *obj.Prog
 	var q1 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
 		/* too hard, just leave alone */
 		case obj.ATEXT:
@@ -386,7 +371,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			ABCL,
 			obj.ADUFFZERO,
 			obj.ADUFFCOPY:
-			cursym.Text.Mark &^= LEAF
+			c.cursym.Func.Text.Mark &^= LEAF
 			fallthrough
 
 		case ABC,
@@ -447,7 +432,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	autosize := int32(0)
 	var p1 *obj.Prog
 	var p2 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		o := p.As
 		switch o {
 		case obj.ATEXT:
@@ -455,26 +440,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 			if p.Mark&LEAF != 0 && autosize == 0 {
 				// A leaf function with no locals has no frame.
-				p.From3.Offset |= obj.NOFRAME
+				p.From.Sym.Set(obj.AttrNoFrame, true)
 			}
 
-			if p.From3.Offset&obj.NOFRAME == 0 {
+			if !p.From.Sym.NoFrame() {
 				// If there is a stack frame at all, it includes
 				// space to save the LR.
-				autosize += int32(ctxt.FixedFrameSize())
+				autosize += int32(c.ctxt.FixedFrameSize())
 			}
 
-			if p.Mark&LEAF != 0 && autosize < obj.StackSmall {
+			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
 				// A leaf function with a small stack can be marked
 				// NOSPLIT, avoiding a stack check.
-				p.From3.Offset |= obj.NOSPLIT
+				p.From.Sym.Set(obj.AttrNoSplit, true)
 			}
 
 			p.To.Offset = int64(autosize)
 
 			q = p
 
-			if ctxt.Flag_shared && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" {
+			if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
 				// When compiling Go into PIC, all functions must start
 				// with instructions to load the TOC pointer into r2:
 				//
@@ -485,52 +470,55 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// but it's a bit subtle. However, it is both safe and
 				// necessary to leave the prologue off duffzero and
 				// duffcopy as we rely on being able to jump to a specific
-				// instruction offset for them, and stackBarrier is only
-				// ever called from an overwritten LR-save slot on the
-				// stack (when r12 will not be remotely the right thing)
-				// but fortunately does not access global data.
+				// instruction offset for them.
 				//
 				// These are AWORDS because there is no (afaict) way to
 				// generate the addis instruction except as part of the
 				// load of a large constant, and in that case there is no
 				// way to use r12 as the source.
-				q = obj.Appendp(ctxt, q)
+				//
+				// Note that the same condition is tested in
+				// putelfsym in cmd/link/internal/ld/symtab.go
+				// where we set the st_other field to indicate
+				// the presence of these instructions.
+				q = obj.Appendp(q, c.newprog)
 				q.As = AWORD
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = 0x3c4c0000
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AWORD
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = 0x38420000
-				rel := obj.Addrel(ctxt.Cursym)
+				rel := obj.Addrel(c.cursym)
 				rel.Off = 0
 				rel.Siz = 8
-				rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0)
-				rel.Type = obj.R_ADDRPOWER_PCREL
+				rel.Sym = c.ctxt.Lookup(".TOC.")
+				rel.Type = objabi.R_ADDRPOWER_PCREL
 			}
 
-			if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
-				q = stacksplit(ctxt, q, autosize) // emit split check
+			if !c.cursym.Func.Text.From.Sym.NoSplit() {
+				q = c.stacksplit(q, autosize) // emit split check
 			}
 
 			if autosize != 0 {
-				// Make sure to save link register for non-empty frame, even if
-				// it is a leaf function, so that traceback works.
-				if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG {
+				// Save the link register and update the SP.  MOVDU is used unless
+				// the frame size is too large.  The link register must be saved
+				// even for non-empty leaf functions so that traceback works.
+				if autosize >= -BIG && autosize <= BIG {
 					// Use MOVDU to adjust R1 when saving R31, if autosize is small.
-					q = obj.Appendp(ctxt, q)
+					q = obj.Appendp(q, c.newprog)
 					q.As = AMOVD
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.From.Type = obj.TYPE_REG
 					q.From.Reg = REG_LR
 					q.To.Type = obj.TYPE_REG
 					q.To.Reg = REGTMP
 
-					q = obj.Appendp(ctxt, q)
+					q = obj.Appendp(q, c.newprog)
 					q.As = AMOVDU
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.From.Type = obj.TYPE_REG
 					q.From.Reg = REGTMP
 					q.To.Type = obj.TYPE_MEM
@@ -542,48 +530,48 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 					// Store link register before decrementing SP, so if a signal comes
 					// during the execution of the function prologue, the traceback
 					// code will not see a half-updated stack frame.
-					q = obj.Appendp(ctxt, q)
+					q = obj.Appendp(q, c.newprog)
 					q.As = AMOVD
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.From.Type = obj.TYPE_REG
 					q.From.Reg = REG_LR
 					q.To.Type = obj.TYPE_REG
 					q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
 
-					q = obj.Appendp(ctxt, q)
+					q = obj.Appendp(q, c.newprog)
 					q.As = AMOVD
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.From.Type = obj.TYPE_REG
 					q.From.Reg = REG_R29
 					q.To.Type = obj.TYPE_MEM
 					q.To.Offset = int64(-autosize)
 					q.To.Reg = REGSP
 
-					q = obj.Appendp(ctxt, q)
+					q = obj.Appendp(q, c.newprog)
 					q.As = AADD
-					q.Lineno = p.Lineno
+					q.Pos = p.Pos
 					q.From.Type = obj.TYPE_CONST
 					q.From.Offset = int64(-autosize)
 					q.To.Type = obj.TYPE_REG
 					q.To.Reg = REGSP
 					q.Spadj = +autosize
 				}
-			} else if cursym.Text.Mark&LEAF == 0 {
+			} else if c.cursym.Func.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
+				c.cursym.Func.Text.Mark |= LEAF
 			}
 
-			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Set(obj.AttrLeaf, true)
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
+				c.cursym.Set(obj.AttrLeaf, true)
 				break
 			}
 
-			if ctxt.Flag_shared {
-				q = obj.Appendp(ctxt, q)
+			if c.ctxt.Flag_shared {
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R2
 				q.To.Type = obj.TYPE_MEM
@@ -591,7 +579,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Offset = 24
 			}
 
-			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+			if c.cursym.Func.Text.From.Sym.Wrapper() {
 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
 				//
 				//	MOVD g_panic(g), R3
@@ -609,28 +597,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// The NOP is needed to give the jumps somewhere to land.
 				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 
 				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(c.ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				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 = obj.Appendp(q, c.newprog)
 				q.As = ABEQ
 				q.To.Type = obj.TYPE_BRANCH
 				p1 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REG_R3
@@ -638,35 +626,35 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R4
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
+				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R5
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				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 = obj.Appendp(q, c.newprog)
 				q.As = ABNE
 				q.To.Type = obj.TYPE_BRANCH
 				p2 = q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = ctxt.FixedFrameSize()
+				q.From.Offset = c.ctxt.FixedFrameSize()
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R6
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R6
@@ -674,7 +662,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Reg = REG_R3
 				q.To.Offset = 0 // Panic.argp
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 
 				q.As = obj.ANOP
 				p1.Pcond = q
@@ -683,13 +671,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 		case obj.ARET:
 			if p.From.Type == obj.TYPE_CONST {
-				ctxt.Diag("using BECOME (%v) is not supported!", p)
+				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
 				break
 			}
 
 			retTarget := p.To.Sym
 
-			if cursym.Text.Mark&LEAF != 0 {
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
 				if autosize == 0 {
 					p.As = ABR
 					p.From = obj.Addr{}
@@ -711,9 +699,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Reg = REGSP
 				p.Spadj = -autosize
 
-				q = ctxt.NewProg()
+				q = c.newprog()
 				q.As = ABR
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_LR
 				q.Mark |= BRANCH
@@ -731,9 +719,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = REGTMP
 
-			q = ctxt.NewProg()
+			q = c.newprog()
 			q.As = AMOVD
-			q.Lineno = p.Lineno
+			q.Pos = p.Pos
 			q.From.Type = obj.TYPE_REG
 			q.From.Reg = REGTMP
 			q.To.Type = obj.TYPE_REG
@@ -745,10 +733,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 			if false {
 				// Debug bad returns
-				q = ctxt.NewProg()
+				q = c.newprog()
 
 				q.As = AMOVD
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_MEM
 				q.From.Offset = 0
 				q.From.Reg = REGTMP
@@ -761,9 +749,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			if autosize != 0 {
-				q = ctxt.NewProg()
+				q = c.newprog()
 				q.As = AADD
-				q.Lineno = p.Lineno
+				q.Pos = p.Pos
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = int64(autosize)
 				q.To.Type = obj.TYPE_REG
@@ -774,9 +762,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.Link = q
 			}
 
-			q1 = ctxt.NewProg()
+			q1 = c.newprog()
 			q1.As = ABR
-			q1.Lineno = p.Lineno
+			q1.Pos = p.Pos
 			if retTarget == nil {
 				q1.To.Type = obj.TYPE_REG
 				q1.To.Reg = REG_LR
@@ -842,47 +830,47 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		q = p;
 	}
 */
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
 	p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
 
 	// MOVD	g_stackguard(g), R3
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	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.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
+	if c.cursym.CFunc() {
+		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
 
 	var q *obj.Prog
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP < stackguard
 		//	CMP	stackguard, SP
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ACMPU
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REGSP
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize < stackguard-StackSmall
-		//	ADD $-framesize, SP, R4
+		//	ADD $-(framesize-StackSmall), SP, R4
 		//	CMP stackguard, R4
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = AADD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(-framesize)
+		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R4
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMPU
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
@@ -904,42 +892,42 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		//	SUB	R3, R4
 		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
 		//	CMPU	R31, R4
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		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.To.Offset = objabi.StackPreempt
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		q = p
 		p.As = ABEQ
 		p.To.Type = obj.TYPE_BRANCH
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AADD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R4
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		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 = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
+		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REGTMP
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = ACMPU
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REGTMP
@@ -948,14 +936,14 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// q1: BLT	done
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 	q1 := p
 
 	p.As = ABLT
 	p.To.Type = obj.TYPE_BRANCH
 
 	// MOVD	LR, R5
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = AMOVD
 	p.From.Type = obj.TYPE_REG
@@ -967,15 +955,15 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	var morestacksym *obj.LSym
-	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)
+	if c.cursym.CFunc() {
+		morestacksym = c.ctxt.Lookup("runtime.morestackc")
+	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+		morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
 	} else {
-		morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0)
+		morestacksym = c.ctxt.Lookup("runtime.morestack")
 	}
 
-	if ctxt.Flag_shared {
+	if c.ctxt.Flag_shared {
 		// In PPC64 PIC code, R2 is used as TOC pointer derived from R12
 		// which is the address of function entry point when entering
 		// the function. We need to preserve R2 across call to morestack.
@@ -984,7 +972,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
 
 		// MOVD R12, 8(SP)
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R2
@@ -993,7 +981,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Offset = 8
 	}
 
-	if ctxt.Flag_dynlink {
+	if c.ctxt.Flag_dynlink {
 		// 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
@@ -1009,7 +997,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		// seems preferable.
 
 		// MOVD $runtime.morestack(SB), R12
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_MEM
 		p.From.Sym = morestacksym
@@ -1018,7 +1006,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Reg = REG_R12
 
 		// MOVD R12, CTR
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R12
@@ -1026,7 +1014,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Reg = REG_CTR
 
 		// BL CTR
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = obj.ACALL
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R12
@@ -1034,16 +1022,16 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 		p.To.Reg = REG_CTR
 	} else {
 		// BL	runtime.morestack(SB)
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = ABL
 		p.To.Type = obj.TYPE_BRANCH
 		p.To.Sym = morestacksym
 	}
 
-	if ctxt.Flag_shared {
+	if c.ctxt.Flag_shared {
 		// MOVD 8(SP), R2
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REGSP
@@ -1053,13 +1041,13 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	// BR	start
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 	p.As = ABR
 	p.To.Type = obj.TYPE_BRANCH
 	p.Pcond = p0.Link
 
 	// placeholder for q1's jump target
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = obj.ANOP // zero-width place holder
 	q1.Pcond = p
@@ -1067,184 +1055,18 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	return p
 }
 
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
-	firstp := ctxt.NewProg()
-	lastp := firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func relinv(a 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
-	var i int
-
-loop:
-	if p == nil {
-		return
-	}
-	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
-			p = p.Link
-			xfol(ctxt, p, last)
-			p = q
-			if p != nil && p.Mark&FOLL == 0 {
-				goto loop
-			}
-			return
-		}
-
-		if q != nil {
-			p.Mark |= FOLL
-			p = q
-			if p.Mark&FOLL == 0 {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark&FOLL != 0 {
-		i = 0
-		q = p
-		for ; i < 4; i, q = i+1, q.Link {
-			if q == *last || (q.Mark&NOSCHED != 0) {
-				break
-			}
-			b = 0 /* set */
-			a = q.As
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
-				goto copy
-			}
-			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
-				continue
-			}
-			b = relinv(a)
-			if b == 0 {
-				continue
-			}
-
-		copy:
-			for {
-				r = ctxt.NewProg()
-				*r = *p
-				if r.Mark&FOLL == 0 {
-					fmt.Printf("can't happen 1\n")
-				}
-				r.Mark |= FOLL
-				if p != q {
-					p = p.Link
-					(*last).Link = r
-					*last = r
-					continue
-				}
-
-				(*last).Link = r
-				*last = r
-				if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
-					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
-	if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
-		if p.Mark&NOSCHED != 0 {
-			p = p.Link
-			goto loop
-		}
-
-		return
-	}
-
-	if p.Pcond != nil {
-		if a != ABL && p.Link != nil {
-			xfol(ctxt, p.Link, last)
-			p = p.Pcond
-			if p == nil || (p.Mark&FOLL != 0) {
-				return
-			}
-			goto loop
-		}
-	}
-
-	p = p.Link
-	goto loop
-}
-
 var Linkppc64 = obj.LinkArch{
 	Arch:       sys.ArchPPC64,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span9,
-	Follow:     follow,
 	Progedit:   progedit,
 }
 
 var Linkppc64le = obj.LinkArch{
 	Arch:       sys.ArchPPC64LE,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   span9,
-	Follow:     follow,
 	Progedit:   progedit,
 }
diff --git a/src/cmd/internal/obj/reloctype_string.go b/src/cmd/internal/obj/reloctype_string.go
deleted file mode 100644
index 09c1312..0000000
--- a/src/cmd/internal/obj/reloctype_string.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Code generated by "stringer -type=RelocType"; DO NOT EDIT
-
-package obj
-
-import "fmt"
-
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
-
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 248, 262, 276, 292, 306, 320, 331, 345, 360, 377, 395, 416, 426, 437, 450}
-
-func (i RelocType) String() string {
-	i -= 1
-	if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
-		return fmt.Sprintf("RelocType(%d)", i+1)
-	}
-	return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
-}
diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go
index 87ee971..9d5b34a 100644
--- a/src/cmd/internal/obj/s390x/a.out.go
+++ b/src/cmd/internal/obj/s390x/a.out.go
@@ -138,7 +138,6 @@ const (
 
 	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
@@ -159,16 +158,8 @@ const (
 
 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
+	LEAF = 1 << iota
+	BRANCH
 )
 
 const ( // comments from func aclass in asmz.go
@@ -290,10 +281,6 @@ const (
 	AFNABS
 	AFNEG
 	AFNEGS
-	AFNMADD
-	AFNMADDS
-	AFNMSUB
-	AFNMSUBS
 	ALEDBR
 	ALDEBR
 	AFSUB
@@ -303,6 +290,10 @@ const (
 	AFIEBR
 	AFIDBR
 
+	// move from GPR to FPR and vice versa
+	ALDGR
+	ALGDR
+
 	// convert from int32/int64 to float/float64
 	ACEFBRA
 	ACDFBRA
diff --git a/src/cmd/internal/obj/s390x/anames.go b/src/cmd/internal/obj/s390x/anames.go
index 51b9ffc..42a0222 100644
--- a/src/cmd/internal/obj/s390x/anames.go
+++ b/src/cmd/internal/obj/s390x/anames.go
@@ -79,10 +79,6 @@ var Anames = []string{
 	"FNABS",
 	"FNEG",
 	"FNEGS",
-	"FNMADD",
-	"FNMADDS",
-	"FNMSUB",
-	"FNMSUBS",
 	"LEDBR",
 	"LDEBR",
 	"FSUB",
@@ -91,6 +87,8 @@ var Anames = []string{
 	"FSQRTS",
 	"FIEBR",
 	"FIDBR",
+	"LDGR",
+	"LGDR",
 	"CEFBRA",
 	"CDFBRA",
 	"CEGBRA",
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
index cc039bd..3bba7b2 100644
--- a/src/cmd/internal/obj/s390x/asmz.go
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -31,11 +31,24 @@ package s390x
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"log"
 	"math"
 	"sort"
 )
 
+// ctxtz holds state while assembling a single function.
+// Each function gets a fresh ctxtz.
+// This allows for multiple functions to be safely concurrently assembled.
+type ctxtz struct {
+	ctxt       *obj.Link
+	newprog    obj.ProgAlloc
+	cursym     *obj.LSym
+	autosize   int32
+	instoffset int64
+	pc         int64
+}
+
 // instruction layout.
 const (
 	funcAlign = 16
@@ -76,21 +89,26 @@ var optab = []Optab{
 	Optab{AMOVBZ, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
 
 	// store constant
-	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_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_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},
+	Optab{AMOVD, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVW, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVWZ, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVB, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVB, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVBZ, C_SCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVBZ, C_ADDCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVD, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVW, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVWZ, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVB, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVB, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVBZ, C_SCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVBZ, C_ADDCON, C_NONE, C_NONE, C_LOREG, 72, 0},
 
 	// store
 	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
@@ -177,13 +195,11 @@ var optab = []Optab{
 	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{AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 32, 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{AFMADD, C_FREG, C_FREG, C_NONE, 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},
@@ -191,6 +207,8 @@ var optab = []Optab{
 	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{ALDGR, C_REG, C_NONE, C_NONE, C_FREG, 81, 0},
+	Optab{ALGDR, C_FREG, C_NONE, C_NONE, C_REG, 81, 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},
 	Optab{AFIEBR, C_SCON, C_FREG, C_NONE, C_FREG, 48, 0},
@@ -256,16 +274,16 @@ var optab = []Optab{
 	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},
+	Optab{ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 80, 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},
+	Optab{AMVC, C_SCON, C_NONE, C_LOREG, C_LOREG, 84, 0},
+	Optab{AMVC, C_SCON, C_NONE, C_LOREG, C_LAUTO, 84, REGSP},
+	Optab{AMVC, C_SCON, C_NONE, C_LAUTO, C_LAUTO, 84, REGSP},
 
 	// address
 	Optab{ALARL, C_LCON, C_NONE, C_NONE, C_REG, 85, 0},
@@ -286,22 +304,22 @@ var optab = []Optab{
 	// 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},
+	Optab{AVSTEG, C_SCON, C_VREG, C_NONE, C_SOREG, 100, 0},
+	Optab{AVSTEG, C_SCON, C_VREG, C_NONE, 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},
+	Optab{AVLEG, C_SCON, C_NONE, C_SOREG, C_VREG, 101, 0},
+	Optab{AVLEG, C_SCON, C_NONE, C_SAUTO, 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},
+	Optab{AVSCEG, C_SCON, C_VREG, C_NONE, C_SOREG, 102, 0},
+	Optab{AVSCEG, C_SCON, C_VREG, C_NONE, 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},
+	Optab{AVGEG, C_SCON, C_NONE, C_SOREG, C_VREG, 103, 0},
+	Optab{AVGEG, C_SCON, C_NONE, C_SAUTO, 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},
@@ -322,19 +340,19 @@ var optab = []Optab{
 	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},
+	Optab{AVSTL, C_REG, C_VREG, C_NONE, C_SOREG, 107, 0},
+	Optab{AVSTL, C_REG, C_VREG, C_NONE, 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},
+	Optab{AVLL, C_REG, C_NONE, C_SOREG, C_VREG, 108, 0},
+	Optab{AVLL, C_REG, C_NONE, C_SAUTO, 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_ADDCON, C_VREG, 109, 0},
 	Optab{AVLEIG, C_SCON, C_NONE, C_SCON, C_VREG, 109, 0},
 
 	// VRI-b generate mask
@@ -345,8 +363,8 @@ var optab = []Optab{
 
 	// 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},
+	Optab{AVERIMG, C_SCON, C_VREG, C_VREG, C_VREG, 112, 0},
+	Optab{AVSLDB, C_SCON, C_VREG, C_VREG, C_VREG, 112, 0},
 
 	// VRI-d fp test data class immediate
 	Optab{AVFTCIDB, C_SCON, C_VREG, C_NONE, C_VREG, 113, 0},
@@ -366,7 +384,7 @@ var optab = []Optab{
 	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},
+	Optab{AVPDI, C_SCON, C_VREG, C_VREG, C_VREG, 123, 0},
 
 	// VRR-c shifts
 	Optab{AVERLLVG, C_VREG, C_VREG, C_NONE, C_VREG, 119, 0},
@@ -387,56 +405,55 @@ var oprange [ALAST & obj.AMask][]Optab
 
 var xcmp [C_NCLASS][C_NCLASS]bool
 
-func spanz(ctxt *obj.Link, cursym *obj.LSym) {
-	p := cursym.Text
+func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	p := cursym.Func.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[AORW&obj.AMask] == nil {
-		buildop(ctxt)
+		ctxt.Diag("s390x ops not initialized, call s390x.buildop first")
 	}
 
+	c := ctxtz{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset)}
+
 	buffer := make([]byte, 0)
 	changed := true
 	loop := 0
 	for changed {
 		if loop > 10 {
-			ctxt.Diag("stuck in spanz loop")
+			c.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 {
+		c.cursym.R = make([]obj.Reloc, 0)
+		for p := c.cursym.Func.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)
+			c.pc = p.Pc
+			c.asmout(p, &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)
+					c.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)
+	c.cursym.Size = int64(len(buffer))
+	if c.cursym.Size%funcAlign != 0 {
+		c.cursym.Size += funcAlign - (c.cursym.Size % funcAlign)
 	}
-	cursym.Grow(cursym.Size)
-	copy(cursym.P, buffer)
+	c.cursym.Grow(c.cursym.Size)
+	copy(c.cursym.P, buffer)
 }
 
 func isint32(v int64) bool {
@@ -447,7 +464,7 @@ func isuint32(v uint64) bool {
 	return uint64(uint32(v)) == v
 }
 
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
+func (c *ctxtz) aclass(a *obj.Addr) int {
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -475,9 +492,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 				// must have a symbol
 				break
 			}
-			ctxt.Instoffset = a.Offset
-			if a.Sym.Type == obj.STLSBSS {
-				if ctxt.Flag_shared {
+			c.instoffset = a.Offset
+			if a.Sym.Type == objabi.STLSBSS {
+				if c.ctxt.Flag_shared {
 					return C_TLS_IE // initial exec model
 				}
 				return C_TLS_LE // local exec model
@@ -488,25 +505,25 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			return C_GOTADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SAUTO
 			}
 			return C_LAUTO
 
 		case obj.NAME_NONE:
-			ctxt.Instoffset = a.Offset
-			if ctxt.Instoffset == 0 {
+			c.instoffset = a.Offset
+			if c.instoffset == 0 {
 				return C_ZOREG
 			}
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SOREG
 			}
 			return C_LOREG
@@ -521,18 +538,18 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		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)
+		c.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
+			c.instoffset = a.Offset
 			if a.Reg != 0 {
-				if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
+				if -BIG <= c.instoffset && c.instoffset <= BIG {
 					return C_SACON
 				}
-				if isint32(ctxt.Instoffset) {
+				if isint32(c.instoffset) {
 					return C_LACON
 				}
 				return C_DACON
@@ -545,23 +562,20 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			if s == nil {
 				break
 			}
-			ctxt.Instoffset = a.Offset
-			if s.Type == obj.SCONST {
-				goto consize
-			}
+			c.instoffset = a.Offset
 
 			return C_SYMADDR
 
 		case obj.NAME_AUTO:
-			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+			c.instoffset = int64(c.autosize) + a.Offset
+			if c.instoffset >= -BIG && c.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 {
+			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
+			if c.instoffset >= -BIG && c.instoffset < BIG {
 				return C_SACON
 			}
 			return C_LACON
@@ -570,32 +584,32 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 		return C_GOK
 
 	consize:
-		if ctxt.Instoffset == 0 {
+		if c.instoffset == 0 {
 			return C_ZCON
 		}
-		if ctxt.Instoffset >= 0 {
-			if ctxt.Instoffset <= 0x7fff {
+		if c.instoffset >= 0 {
+			if c.instoffset <= 0x7fff {
 				return C_SCON
 			}
-			if ctxt.Instoffset <= 0xffff {
+			if c.instoffset <= 0xffff {
 				return C_ANDCON
 			}
-			if ctxt.Instoffset&0xffff == 0 && isuint32(uint64(ctxt.Instoffset)) { /* && (instoffset & (1<<31)) == 0) */
+			if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && (instoffset & (1<<31)) == 0) */
 				return C_UCON
 			}
-			if isint32(ctxt.Instoffset) || isuint32(uint64(ctxt.Instoffset)) {
+			if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) {
 				return C_LCON
 			}
 			return C_DCON
 		}
 
-		if ctxt.Instoffset >= -0x8000 {
+		if c.instoffset >= -0x8000 {
 			return C_ADDCON
 		}
-		if ctxt.Instoffset&0xffff == 0 && isint32(ctxt.Instoffset) {
+		if c.instoffset&0xffff == 0 && isint32(c.instoffset) {
 			return C_UCON
 		}
-		if isint32(ctxt.Instoffset) {
+		if isint32(c.instoffset) {
 			return C_LCON
 		}
 		return C_DCON
@@ -607,14 +621,14 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	return C_GOK
 }
 
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+func (c *ctxtz) oplook(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
+		a1 = c.aclass(&p.From) + 1
 		p.From.Class = int8(a1)
 	}
 
@@ -623,7 +637,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	if p.From3 != nil {
 		a3 = int(p.From3.Class)
 		if a3 == 0 {
-			a3 = aclass(ctxt, p.From3) + 1
+			a3 = c.aclass(p.From3) + 1
 			p.From3.Class = int8(a3)
 		}
 	}
@@ -631,7 +645,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	a3--
 	a4 := int(p.To.Class)
 	if a4 == 0 {
-		a4 = aclass(ctxt, &p.To) + 1
+		a4 = c.aclass(&p.To) + 1
 		p.To.Class = int8(a4)
 	}
 
@@ -663,8 +677,8 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	}
 
 	// cannot find a case; abort
-	ctxt.Diag("illegal combination %v %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
-	ctxt.Diag("prog: %v\n", p)
+	c.ctxt.Diag("illegal combination %v %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+	c.ctxt.Diag("prog: %v\n", p)
 	return nil
 }
 
@@ -775,6 +789,13 @@ func opset(a, b obj.As) {
 }
 
 func buildop(ctxt *obj.Link) {
+	if oprange[AORW&obj.AMask] != nil {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
 	for i := 0; i < C_NCLASS; i++ {
 		for n := 0; n < C_NCLASS; n++ {
 			if cmp(n, i) {
@@ -872,10 +893,6 @@ func buildop(ctxt *obj.Link) {
 			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:
@@ -2484,51 +2501,51 @@ func oclass(a *obj.Addr) int {
 
 // 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 {
+func (c *ctxtz) addrilreloc(sym *obj.LSym, add int64) *obj.Reloc {
 	if sym == nil {
-		ctxt.Diag("require symbol to apply relocation")
+		c.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 := obj.Addrel(c.cursym)
+	rel.Off = int32(c.pc + offset)
 	rel.Siz = 4
 	rel.Sym = sym
 	rel.Add = add + offset + int64(rel.Siz)
-	rel.Type = obj.R_PCRELDBL
+	rel.Type = objabi.R_PCRELDBL
 	return rel
 }
 
-func addrilrelocoffset(ctxt *obj.Link, sym *obj.LSym, add, offset int64) *obj.Reloc {
+func (c *ctxtz) addrilrelocoffset(sym *obj.LSym, add, offset int64) *obj.Reloc {
 	if sym == nil {
-		ctxt.Diag("require symbol to apply relocation")
+		c.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 := obj.Addrel(c.cursym)
+	rel.Off = int32(c.pc + offset)
 	rel.Siz = 4
 	rel.Sym = sym
 	rel.Add = add + offset + int64(rel.Siz)
-	rel.Type = obj.R_PCRELDBL
+	rel.Type = objabi.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 {
+func (c *ctxtz) addcallreloc(sym *obj.LSym, add int64) *obj.Reloc {
 	if sym == nil {
-		ctxt.Diag("require symbol to apply relocation")
+		c.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 := obj.Addrel(c.cursym)
+	rel.Off = int32(c.pc + offset)
 	rel.Siz = 4
 	rel.Sym = sym
 	rel.Add = add + offset + int64(rel.Siz)
-	rel.Type = obj.R_CALL
+	rel.Type = objabi.R_CALL
 	return rel
 }
 
-func branchMask(ctxt *obj.Link, p *obj.Prog) uint32 {
+func (c *ctxtz) branchMask(p *obj.Prog) uint32 {
 	switch p.As {
 	case ABEQ, ACMPBEQ, ACMPUBEQ, AMOVDEQ:
 		return 0x8
@@ -2551,18 +2568,16 @@ func branchMask(ctxt *obj.Link, p *obj.Prog) uint32 {
 	case ABVS:
 		return 0x1 // unordered
 	}
-	ctxt.Diag("unknown conditional branch %v", p.As)
+	c.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
+func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
+	o := c.oplook(p)
 
 	switch o.type_ {
 	default:
-		ctxt.Diag("unknown type %d", o.type_)
+		c.ctxt.Diag("unknown type %d", o.type_)
 
 	case 0: // PSEUDO OPS
 		break
@@ -2570,7 +2585,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 	case 1: // mov reg reg
 		switch p.As {
 		default:
-			ctxt.Diag("unhandled operation: %v", p.As)
+			c.ctxt.Diag("unhandled operation: %v", p.As)
 		case AMOVD:
 			zRRE(op_LGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
 		// sign extend
@@ -2607,7 +2622,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 		switch p.As {
 		default:
-			ctxt.Diag("invalid opcode")
+			c.ctxt.Diag("invalid opcode")
 		case AADD:
 			opcode = op_AGRK
 		case AADDC:
@@ -2628,18 +2643,6 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			opcode = op_DSGR
 		case ADIVDU, AMODDU:
 			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 {
@@ -2678,33 +2681,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
 			zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
 
-		case AFADD, AFADDS:
-			if r == 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 == 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)
+		v := c.vregoff(&p.From)
 		switch p.As {
 		case AMOVBZ:
 			v = int64(uint8(v))
@@ -2796,7 +2776,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 7: // shift/rotate reg [reg] reg
-		d2 := vregoff(ctxt, &p.From)
+		d2 := c.vregoff(&p.From)
 		b2 := p.From.Reg
 		r3 := p.Reg
 		if r3 == 0 {
@@ -2827,7 +2807,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 8: // find leftmost one
 		if p.To.Reg&1 != 0 {
-			ctxt.Diag("target must be an even-numbered register")
+			c.ctxt.Diag("target must be an even-numbered register")
 		}
 		// FLOGR also writes a mask to p.To.Reg+1.
 		zRRE(op_FLOGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
@@ -2887,13 +2867,13 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 				zRIL(_c, op_BRCL, 0xF, uint32(v), asm)
 			}
 			if p.To.Sym != nil {
-				addcallreloc(ctxt, p.To.Sym, p.To.Offset)
+				c.addcallreloc(p.To.Sym, p.To.Offset)
 			}
 		}
 
 	case 12:
 		r1 := p.To.Reg
-		d2 := vregoff(ctxt, &p.From)
+		d2 := c.vregoff(&p.From)
 		b2 := p.From.Reg
 		if b2 == 0 {
 			b2 = o.param
@@ -2965,18 +2945,18 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		if p.Pcond != nil {
 			v = int32((p.Pcond.Pc - p.Pc) >> 1)
 		}
-		mask := branchMask(ctxt, p)
+		mask := c.branchMask(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)
+			c.addrilreloc(p.To.Sym, p.To.Offset)
 		}
 
 	case 17: // move on condition
-		m3 := branchMask(ctxt, p)
+		m3 := c.branchMask(p)
 		zRRF(op_LOCGR, m3, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
 
 	case 18: // br/bl reg
@@ -2987,16 +2967,16 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 19: // mov $sym+n(SB) reg
-		d := vregoff(ctxt, &p.From)
+		d := c.vregoff(&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)
+		c.addrilreloc(p.From.Sym, d)
 
 	case 21: // subtract $constant [reg] reg
-		v := vregoff(ctxt, &p.From)
+		v := c.vregoff(&p.From)
 		r := p.Reg
 		if r == 0 {
 			r = p.To.Reg
@@ -3018,7 +2998,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 22: // add/multiply $constant [reg] reg
-		v := vregoff(ctxt, &p.From)
+		v := c.vregoff(&p.From)
 		r := p.Reg
 		if r == 0 {
 			r = p.To.Reg
@@ -3064,10 +3044,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 23: // 64-bit logical op $constant reg
 		// TODO(mundaym): merge with case 24.
-		v := vregoff(ctxt, &p.From)
+		v := c.vregoff(&p.From)
 		switch p.As {
 		default:
-			ctxt.Diag("%v is not supported", p)
+			c.ctxt.Diag("%v is not supported", p)
 		case AAND:
 			if v >= 0 { // needs zero extend
 				zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
@@ -3096,7 +3076,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 24: // 32-bit logical op $constant reg
-		v := vregoff(ctxt, &p.From)
+		v := c.vregoff(&p.From)
 		switch p.As {
 		case AANDW:
 			if uint32(v&0xffff0000) == 0xffff0000 {
@@ -3119,7 +3099,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 26: // MOVD $offset(base)(index), reg
-		v := regoff(ctxt, &p.From)
+		v := c.regoff(&p.From)
 		r := p.From.Reg
 		if r == 0 {
 			r = o.param
@@ -3135,7 +3115,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 31: // dword
-		wd := uint64(vregoff(ctxt, &p.From))
+		wd := uint64(c.vregoff(&p.From))
 		*asm = append(*asm,
 			uint8(wd>>56),
 			uint8(wd>>48),
@@ -3146,31 +3126,29 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			uint8(wd>>8),
 			uint8(wd))
 
-	case 32: // fmul freg [freg] freg
-		r := int(p.Reg)
-		if r == 0 {
-			r = int(p.To.Reg)
-		}
-
+	case 32: // float op freg freg
 		var opcode uint32
-
 		switch p.As {
 		default:
-			ctxt.Diag("invalid opcode")
+			c.ctxt.Diag("invalid opcode")
+		case AFADD:
+			opcode = op_ADBR
+		case AFADDS:
+			opcode = op_AEBR
+		case AFDIV:
+			opcode = op_DDBR
+		case AFDIVS:
+			opcode = op_DEBR
 		case AFMUL:
 			opcode = op_MDBR
 		case AFMULS:
 			opcode = op_MEEBR
+		case AFSUB:
+			opcode = op_SDBR
+		case AFSUBS:
+			opcode = op_SEBR
 		}
-
-		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)
-		}
+		zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
 
 	case 33: // float op [freg] freg
 		r := p.From.Reg
@@ -3199,12 +3177,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 		zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
 
-	case 34: // float multiply-add freg freg freg freg
+	case 34: // float multiply-add freg freg freg
 		var opcode uint32
-
 		switch p.As {
 		default:
-			ctxt.Diag("invalid opcode")
+			c.ctxt.Diag("invalid opcode")
 		case AFMADD:
 			opcode = op_MADBR
 		case AFMADDS:
@@ -3213,25 +3190,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			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)
 		}
+		zRRD(opcode, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), asm)
 
 	case 35: // mov reg mem (no relocation)
-		d2 := regoff(ctxt, &p.To)
+		d2 := c.regoff(&p.To)
 		b2 := p.To.Reg
 		if b2 == 0 {
 			b2 = o.param
@@ -3245,10 +3208,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			x2 = REGTMP
 			d2 = 0
 		}
-		zRXY(zopstore(ctxt, p.As), uint32(p.From.Reg), uint32(x2), uint32(b2), uint32(d2), asm)
+		zRXY(c.zopstore(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)
+		d2 := c.regoff(&p.From)
 		b2 := p.From.Reg
 		if b2 == 0 {
 			b2 = o.param
@@ -3262,10 +3225,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			x2 = REGTMP
 			d2 = 0
 		}
-		zRXY(zopload(ctxt, p.As), uint32(p.To.Reg), uint32(x2), uint32(b2), uint32(d2), asm)
+		zRXY(c.zopload(p.As), uint32(p.To.Reg), uint32(x2), uint32(b2), uint32(d2), asm)
 
 	case 40: // word/byte
-		wd := uint32(regoff(ctxt, &p.From))
+		wd := uint32(c.regoff(&p.From))
 		if p.As == AWORD { //WORD
 			*asm = append(*asm, uint8(wd>>24), uint8(wd>>16), uint8(wd>>8), uint8(wd))
 		} else { //BYTE
@@ -3285,9 +3248,9 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 48: // floating-point round to integer
-		m3 := vregoff(ctxt, &p.From)
+		m3 := c.vregoff(&p.From)
 		if 0 > m3 || m3 > 7 {
-			ctxt.Diag("mask (%v) must be in the range [0, 7]", m3)
+			c.ctxt.Diag("mask (%v) must be in the range [0, 7]", m3)
 		}
 		var opcode uint32
 		switch p.As {
@@ -3316,21 +3279,21 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	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)
+			zRR(c.zoprr(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)
+			zRRE(c.zoprre(p.As), uint32(p.From.Reg), uint32(p.To.Reg), asm)
 		}
 
 	case 71: // cmp reg $constant
-		v := vregoff(ctxt, &p.To)
+		v := c.vregoff(&p.To)
 		switch p.As {
 		case ACMP, ACMPW:
 			if int64(int32(v)) != v {
-				ctxt.Diag("%v overflows an int32", v)
+				c.ctxt.Diag("%v overflows an int32", v)
 			}
 		case ACMPU, ACMPWU:
 			if int64(uint32(v)) != v {
-				ctxt.Diag("%v overflows a uint32", v)
+				c.ctxt.Diag("%v overflows a uint32", v)
 			}
 		}
 		if p.As == ACMP && int64(int16(v)) == v {
@@ -3338,95 +3301,60 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		} else if p.As == ACMPW && int64(int16(v)) == v {
 			zRI(op_CHI, uint32(p.From.Reg), uint32(v), asm)
 		} else {
-			zRIL(_a, zopril(ctxt, p.As), uint32(p.From.Reg), uint32(v), asm)
+			zRIL(_a, c.zopril(p.As), uint32(p.From.Reg), uint32(v), asm)
 		}
 
 	case 72: // mov $constant mem
-		v := regoff(ctxt, &p.From)
-		d := regoff(ctxt, &p.To)
+		v := c.regoff(&p.From)
+		d := c.regoff(&p.To)
 		r := p.To.Reg
-		x := p.To.Index
+		if p.To.Index != 0 {
+			c.ctxt.Diag("cannot use index register")
+		}
 		if r == 0 {
 			r = o.param
 		}
-		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)
+		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 d < 0 || d >= DISP12 {
+			if r == REGTMP {
+				c.ctxt.Diag("displacement must be in range [0, 4096) to use %v", r)
+			}
+			if d >= -DISP20/2 && d < DISP20/2 {
+				if opcode == op_MVI {
+					opcode = op_MVIY
 				} else {
-					zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
-					zRRE(op_AGR, REGTMP, uint32(r), asm)
+					zRXY(op_LAY, uint32(REGTMP), 0, uint32(r), uint32(d), asm)
 					r = REGTMP
+					d = 0
 				}
-				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
-				}
+				zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
+				zRX(op_LA, REGTMP, REGTMP, uint32(r), 0, asm)
+				r = 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 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)
+		switch opcode {
+		case op_MVI:
+			zSI(opcode, uint32(v), uint32(r), uint32(d), asm)
+		case op_MVIY:
+			zSIY(opcode, uint32(v), uint32(r), uint32(d), asm)
+		default:
+			zSIL(opcode, uint32(r), uint32(d), uint32(v), asm)
 		}
 
 	case 74: // mov reg addr (including relocation)
-		i2 := regoff(ctxt, &p.To)
+		i2 := c.regoff(&p.To)
 		switch p.As {
 		case AMOVD:
 			zRIL(_b, op_STGRL, uint32(p.From.Reg), 0, asm)
@@ -3449,10 +3377,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			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))
+		c.addrilreloc(p.To.Sym, int64(i2))
 
 	case 75: // mov addr reg (including relocation)
-		i2 := regoff(ctxt, &p.From)
+		i2 := c.regoff(&p.From)
 		switch p.As {
 		case AMOVD:
 			if i2&1 != 0 {
@@ -3490,11 +3418,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			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))
+		c.addrilreloc(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)
+			c.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)
@@ -3506,7 +3434,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		*asm = append(*asm, 0, 0, 0, 0)
 
 	case 79: // compare and swap reg reg reg
-		v := regoff(ctxt, &p.To)
+		v := c.regoff(&p.To)
 		if v < 0 {
 			v = 0
 		}
@@ -3516,9 +3444,17 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			zRSY(op_CSG, uint32(p.From.Reg), uint32(p.Reg), uint32(p.To.Reg), uint32(v), asm)
 		}
 
-	case 81: // sync
+	case 80: // sync
 		zRR(op_BCR, 0xE, 0, asm)
 
+	case 81: // float to fixed and fixed to float moves (no conversion)
+		switch p.As {
+		case ALDGR:
+			zRRE(op_LDGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case ALGDR:
+			zRRE(op_LGDR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		}
+
 	case 82: // fixed to float conversion
 		var opcode uint32
 		switch p.As {
@@ -3573,27 +3509,27 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		// 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)
+	case 84: // storage-and-storage operations $length mem mem
+		l := c.regoff(&p.From)
 		if l < 1 || l > 256 {
-			ctxt.Diag("number of bytes (%v) not in range [1,256]", l)
+			c.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")
+		if p.From3.Index != 0 || p.To.Index != 0 {
+			c.ctxt.Diag("cannot use index reg")
 		}
 		b1 := p.To.Reg
-		b2 := p.From.Reg
+		b2 := p.From3.Reg
 		if b1 == 0 {
 			b1 = o.param
 		}
 		if b2 == 0 {
 			b2 = o.param
 		}
-		d1 := regoff(ctxt, &p.To)
-		d2 := regoff(ctxt, &p.From)
+		d1 := c.regoff(&p.To)
+		d2 := c.regoff(p.From3)
 		if d1 < 0 || d1 >= DISP12 {
 			if b2 == REGTMP {
-				ctxt.Diag("REGTMP conflict")
+				c.ctxt.Diag("REGTMP conflict")
 			}
 			if b1 != REGTMP {
 				zRRE(op_LGR, REGTMP, uint32(b1), asm)
@@ -3608,7 +3544,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 		if d2 < 0 || d2 >= DISP12 {
 			if b1 == REGTMP2 {
-				ctxt.Diag("REGTMP2 conflict")
+				c.ctxt.Diag("REGTMP2 conflict")
 			}
 			if b2 != REGTMP2 {
 				zRRE(op_LGR, REGTMP2, uint32(b2), asm)
@@ -3620,7 +3556,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		var opcode uint32
 		switch p.As {
 		default:
-			ctxt.Diag("unexpected opcode %v", p.As)
+			c.ctxt.Diag("unexpected opcode %v", p.As)
 		case AMVC:
 			opcode = op_MVC
 		case ACLC:
@@ -3638,19 +3574,19 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		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)
+		v := c.regoff(&p.From)
 		if p.From.Sym == nil {
 			if (v & 1) != 0 {
-				ctxt.Diag("cannot use LARL with odd offset: %v", v)
+				c.ctxt.Diag("cannot use LARL with odd offset: %v", v)
 			}
 		} else {
-			addrilreloc(ctxt, p.From.Sym, int64(v))
+			c.addrilreloc(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)
+		d := c.vregoff(&p.From)
 		x := p.From.Index
 		b := p.From.Reg
 		if b == 0 {
@@ -3664,13 +3600,13 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		}
 
 	case 87: // execute relative long
-		v := vregoff(ctxt, &p.From)
+		v := c.vregoff(&p.From)
 		if p.From.Sym == nil {
 			if v&1 != 0 {
-				ctxt.Diag("cannot use EXRL with odd offset: %v", v)
+				c.ctxt.Diag("cannot use EXRL with odd offset: %v", v)
 			}
 		} else {
-			addrilreloc(ctxt, p.From.Sym, v)
+			c.addrilreloc(p.From.Sym, v)
 			v = 0
 		}
 		zRIL(_b, op_EXRL, uint32(p.To.Reg), uint32(v>>1), asm)
@@ -3687,7 +3623,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		case ASTCKF:
 			opcode = op_STCKF
 		}
-		v := vregoff(ctxt, &p.To)
+		v := c.vregoff(&p.To)
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
@@ -3708,7 +3644,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			opcode = op_CLGRJ
 			opcode2 = op_CLGR
 		}
-		mask := branchMask(ctxt, p)
+		mask := c.branchMask(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)
@@ -3730,25 +3666,25 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 			opcode = op_CLGIJ
 			opcode2 = op_CLGFI
 		}
-		mask := branchMask(ctxt, p)
+		mask := c.branchMask(p)
 		if int32(int16(v)) != v {
-			zRIL(_a, opcode2, uint32(p.From.Reg), uint32(regoff(ctxt, p.From3)), asm)
+			zRIL(_a, opcode2, uint32(p.From.Reg), uint32(c.regoff(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)
+			zRIE(_c, opcode, uint32(p.From.Reg), mask, uint32(v), 0, 0, 0, uint32(c.regoff(p.From3)), asm)
 		}
 
 	case 93: // GOT lookup
-		v := vregoff(ctxt, &p.To)
+		v := c.vregoff(&p.To)
 		if v != 0 {
-			ctxt.Diag("invalid offset against GOT slot %v", p)
+			c.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 := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc + 2)
 		rel.Siz = 4
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_GOTPCREL
+		rel.Type = objabi.R_GOTPCREL
 		rel.Add = 2 + int64(rel.Siz)
 
 	case 94: // TLS local exec model
@@ -3756,11 +3692,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		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 := obj.Addrel(c.cursym)
+		rel.Off = int32(c.pc + sizeRIL + sizeRXY + sizeRI)
 		rel.Siz = 8
 		rel.Sym = p.From.Sym
-		rel.Type = obj.R_TLS_LE
+		rel.Type = objabi.R_TLS_LE
 		rel.Add = 0
 
 	case 95: // TLS initial exec model
@@ -3776,11 +3712,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 		// R_390_TLS_IEENT
 		zRIL(_b, op_LARL, REGTMP, 0, asm)
-		ieent := obj.Addrel(ctxt.Cursym)
-		ieent.Off = int32(ctxt.Pc + 2)
+		ieent := obj.Addrel(c.cursym)
+		ieent.Off = int32(c.pc + 2)
 		ieent.Siz = 4
 		ieent.Sym = p.From.Sym
-		ieent.Type = obj.R_TLS_IE
+		ieent.Type = objabi.R_TLS_IE
 		ieent.Add = 2 + int64(ieent.Siz)
 
 		// R_390_TLS_LOAD
@@ -3789,14 +3725,14 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		// not strictly required but might allow the linker to optimize
 
 	case 96: // clear macro
-		length := vregoff(ctxt, &p.From)
-		offset := vregoff(ctxt, &p.To)
+		length := c.vregoff(&p.From)
+		offset := c.vregoff(&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)
+			c.ctxt.Diag("cannot CLEAR %d bytes, must be greater than 0", length)
 		}
 		for length > 0 {
 			if offset < 0 || offset >= DISP12 {
@@ -3836,7 +3772,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 	case 97: // store multiple
 		rstart := p.From.Reg
 		rend := p.Reg
-		offset := regoff(ctxt, &p.To)
+		offset := c.regoff(&p.To)
 		reg := p.To.Reg
 		if reg == 0 {
 			reg = o.param
@@ -3863,7 +3799,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 	case 98: // load multiple
 		rstart := p.Reg
 		rend := p.To.Reg
-		offset := regoff(ctxt, &p.From)
+		offset := c.regoff(&p.From)
 		reg := p.From.Reg
 		if reg == 0 {
 			reg = o.param
@@ -3889,11 +3825,11 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 99: // interlocked load and op
 		if p.To.Index != 0 {
-			ctxt.Diag("cannot use indexed address")
+			c.ctxt.Diag("cannot use indexed address")
 		}
-		offset := regoff(ctxt, &p.To)
+		offset := c.regoff(&p.To)
 		if offset < -DISP20/2 || offset >= DISP20/2 {
-			ctxt.Diag("%v does not fit into 20-bit signed integer", offset)
+			c.ctxt.Diag("%v does not fit into 20-bit signed integer", offset)
 		}
 		var opcode uint32
 		switch p.As {
@@ -3922,51 +3858,51 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 100: // VRX STORE
 		op, m3, _ := vop(p.As)
-		if p.From3 != nil {
-			m3 = uint32(vregoff(ctxt, p.From3))
+		v1 := p.From.Reg
+		if p.Reg != 0 {
+			m3 = uint32(c.vregoff(&p.From))
+			v1 = p.Reg
 		}
 		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)
+		d2 := uint32(c.vregoff(&p.To))
+		zVRX(op, uint32(v1), uint32(p.To.Index), uint32(b2), d2, m3, asm)
 
 	case 101: // VRX LOAD
 		op, m3, _ := vop(p.As)
+		src := &p.From
 		if p.From3 != nil {
-			m3 = uint32(vregoff(ctxt, p.From3))
+			m3 = uint32(c.vregoff(&p.From))
+			src = p.From3
 		}
-		b2 := p.From.Reg
+		b2 := src.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)
+		d2 := uint32(c.vregoff(src))
+		zVRX(op, uint32(p.To.Reg), uint32(src.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))
-		}
+		op, _, _ := vop(p.As)
+		m3 := uint32(c.vregoff(&p.From))
 		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)
+		d2 := uint32(c.vregoff(&p.To))
+		zVRV(op, uint32(p.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
+		op, _, _ := vop(p.As)
+		m3 := uint32(c.vregoff(&p.From))
+		b2 := p.From3.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)
+		d2 := uint32(c.vregoff(p.From3))
+		zVRV(op, uint32(p.To.Reg), uint32(p.From3.Index), uint32(b2), d2, m3, asm)
 
 	case 104: // VRS SHIFT/ROTATE and LOAD GR FROM VR ELEMENT
 		op, m4, _ := vop(p.As)
@@ -3974,12 +3910,12 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		if fr == 0 {
 			fr = p.To.Reg
 		}
-		bits := uint32(vregoff(ctxt, &p.From))
+		bits := uint32(c.vregoff(&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))
+		offset := uint32(c.vregoff(&p.To))
 		reg := p.To.Reg
 		if reg == 0 {
 			reg = o.param
@@ -3988,7 +3924,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 106: // VRS LOAD MULTIPLE
 		op, _, _ := vop(p.As)
-		offset := uint32(vregoff(ctxt, &p.From))
+		offset := uint32(c.vregoff(&p.From))
 		reg := p.From.Reg
 		if reg == 0 {
 			reg = o.param
@@ -3997,57 +3933,57 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	case 107: // VRS STORE WITH LENGTH
 		op, _, _ := vop(p.As)
-		offset := uint32(vregoff(ctxt, &p.To))
+		offset := uint32(c.vregoff(&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)
+		zVRS(op, uint32(p.Reg), uint32(p.From.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
+		offset := uint32(c.vregoff(p.From3))
+		reg := p.From3.Reg
 		if reg == 0 {
 			reg = o.param
 		}
-		zVRS(op, uint32(p.To.Reg), uint32(p.From3.Reg), uint32(reg), offset, 0, asm)
+		zVRS(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(reg), offset, 0, asm)
 
 	case 109: // VRI-a
-		op, _, _ := vop(p.As)
-		i2 := uint32(vregoff(ctxt, &p.From))
+		op, m3, _ := vop(p.As)
+		i2 := uint32(c.vregoff(&p.From))
+		if p.From3 != nil {
+			m3 = uint32(c.vregoff(&p.From))
+			i2 = uint32(c.vregoff(p.From3))
+		}
 		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))
+		i2 := uint32(c.vregoff(&p.From))
+		i3 := uint32(c.vregoff(p.From3))
 		zVRIb(op, uint32(p.To.Reg), i2, i3, m4, asm)
 
 	case 111:
 		op, m4, _ := vop(p.As)
-		i2 := uint32(vregoff(ctxt, &p.From))
+		i2 := uint32(c.vregoff(&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)
+		i4 := uint32(c.vregoff(&p.From))
+		zVRId(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), i4, m5, asm)
 
 	case 113:
 		op, m4, _ := vop(p.As)
 		m5 := singleElementMask(p.As)
-		i3 := uint32(vregoff(ctxt, &p.From))
+		i3 := uint32(c.vregoff(&p.From))
 		zVRIe(op, uint32(p.To.Reg), uint32(p.Reg), i3, m5, m4, asm)
 
 	case 114: // VRR-a
@@ -4060,8 +3996,6 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		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)
@@ -4088,18 +4022,18 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 		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)
+		v2 := uint32(p.From.Reg)
+		v3 := uint32(p.Reg)
+		v4 := uint32(p.From3.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)
+		v2 := uint32(p.From.Reg)
+		v3 := uint32(p.Reg)
+		v4 := uint32(p.From3.Reg)
 		zVRRe(op, v1, v2, v3, m6, m5, v4, asm)
 
 	case 122: // VRR-f LOAD VRS FROM GRS DISJOINT
@@ -4108,25 +4042,25 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
 
 	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)
+		m4 := c.regoff(&p.From)
+		zVRRc(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), 0, 0, uint32(m4), asm)
 	}
 }
 
-func vregoff(ctxt *obj.Link, a *obj.Addr) int64 {
-	ctxt.Instoffset = 0
+func (c *ctxtz) vregoff(a *obj.Addr) int64 {
+	c.instoffset = 0
 	if a != nil {
-		aclass(ctxt, a)
+		c.aclass(a)
 	}
-	return ctxt.Instoffset
+	return c.instoffset
 }
 
-func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
-	return int32(vregoff(ctxt, a))
+func (c *ctxtz) regoff(a *obj.Addr) int32 {
+	return int32(c.vregoff(a))
 }
 
 // zopload returns the RXY op for the given load
-func zopload(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxtz) zopload(a obj.As) uint32 {
 	switch a {
 	// fixed point load
 	case AMOVD:
@@ -4159,12 +4093,12 @@ func zopload(ctxt *obj.Link, a obj.As) uint32 {
 		return op_LRVH
 	}
 
-	ctxt.Diag("unknown store opcode %v", a)
+	c.ctxt.Diag("unknown store opcode %v", a)
 	return 0
 }
 
 // zopstore returns the RXY op for the given store
-func zopstore(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxtz) zopstore(a obj.As) uint32 {
 	switch a {
 	// fixed point store
 	case AMOVD:
@@ -4191,12 +4125,12 @@ func zopstore(ctxt *obj.Link, a obj.As) uint32 {
 		return op_STRVH
 	}
 
-	ctxt.Diag("unknown store opcode %v", a)
+	c.ctxt.Diag("unknown store opcode %v", a)
 	return 0
 }
 
 // zoprre returns the RRE op for the given a
-func zoprre(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxtz) zoprre(a obj.As) uint32 {
 	switch a {
 	case ACMP:
 		return op_CGR
@@ -4209,24 +4143,24 @@ func zoprre(ctxt *obj.Link, a obj.As) uint32 {
 	case ACEBR:
 		return op_CEBR
 	}
-	ctxt.Diag("unknown rre opcode %v", a)
+	c.ctxt.Diag("unknown rre opcode %v", a)
 	return 0
 }
 
 // zoprr returns the RR op for the given a
-func zoprr(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxtz) zoprr(a obj.As) uint32 {
 	switch a {
 	case ACMPW:
 		return op_CR
 	case ACMPWU:
 		return op_CLR
 	}
-	ctxt.Diag("unknown rr opcode %v", a)
+	c.ctxt.Diag("unknown rr opcode %v", a)
 	return 0
 }
 
 // zopril returns the RIL op for the given a
-func zopril(ctxt *obj.Link, a obj.As) uint32 {
+func (c *ctxtz) zopril(a obj.As) uint32 {
 	switch a {
 	case ACMP:
 		return op_CGFI
@@ -4237,7 +4171,7 @@ func zopril(ctxt *obj.Link, a obj.As) uint32 {
 	case ACMPWU:
 		return op_CLFI
 	}
-	ctxt.Diag("unknown ril opcode %v", a)
+	c.ctxt.Diag("unknown ril opcode %v", a)
 	return 0
 }
 
diff --git a/src/cmd/internal/obj/s390x/listz.go b/src/cmd/internal/obj/s390x/listz.go
index 152a45b..ee58026 100644
--- a/src/cmd/internal/obj/s390x/listz.go
+++ b/src/cmd/internal/obj/s390x/listz.go
@@ -35,11 +35,11 @@ import (
 )
 
 func init() {
-	obj.RegisterRegister(obj.RBaseS390X, REG_R0+1024, Rconv)
+	obj.RegisterRegister(obj.RBaseS390X, REG_R0+1024, rconv)
 	obj.RegisterOpcode(obj.ABaseS390X, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index fca8f85..3d3571a 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -31,22 +31,20 @@ package s390x
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
-	"fmt"
 	"math"
 )
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 	p.From.Class = 0
 	p.To.Class = 0
 
+	c := ctxtz{ctxt: ctxt, newprog: newprog}
+
 	// Rewrite BR/BL to symbol as TYPE_BRANCH.
 	switch p.As {
-	case ABR,
-		ABL,
-		obj.ARET,
-		obj.ADUFFZERO,
-		obj.ADUFFCOPY:
+	case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
 		if p.To.Sym != nil {
 			p.To.Type = obj.TYPE_BRANCH
 		}
@@ -57,32 +55,23 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AFMOVS:
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			if i32 == 0 { // +0
+			if math.Float32bits(f32) == 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.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float32Sym(f32)
 			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
+			f64 := p.From.Val.(float64)
+			if math.Float64bits(f64) == 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.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float64Sym(f64)
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Offset = 0
 		}
@@ -94,12 +83,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 			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.Set(obj.AttrLocal, true)
+				p.From.Sym = ctxt.Int64Sym(p.From.Offset)
 				p.From.Name = obj.NAME_EXTERN
 				p.From.Offset = 0
 			}
@@ -121,13 +106,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 
-	if ctxt.Flag_dynlink {
-		rewriteToUseGot(ctxt, p)
+	if c.ctxt.Flag_dynlink {
+		c.rewriteToUseGot(p)
 	}
 }
 
 // Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func (c *ctxtz) rewriteToUseGot(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 {
@@ -141,13 +126,13 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		// 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)
+			c.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 = obj.Appendp(p, c.newprog)
 			q.As = AADD
 			q.From.Type = obj.TYPE_CONST
 			q.From.Offset = p.From.Offset
@@ -156,7 +141,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 	if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.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
@@ -164,7 +149,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	// 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)
+			c.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() {
@@ -175,14 +160,14 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	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 {
+	if source.Sym.Type == objabi.STLSBSS {
 		return
 	}
 	if source.Type != obj.TYPE_MEM {
-		ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
 	}
-	p1 := obj.Appendp(ctxt, p)
-	p2 := obj.Appendp(ctxt, p1)
+	p1 := obj.Appendp(p, c.newprog)
+	p2 := obj.Appendp(p1, c.newprog)
 
 	p1.As = AMOVD
 	p1.From.Type = obj.TYPE_MEM
@@ -208,94 +193,49 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	obj.Nopout(p)
 }
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 	// TODO(minux): add morestack short-cuts with small fixed frame-size.
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
+	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
 		return
 	}
 
-	p := cursym.Text
+	c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
+
+	p := c.cursym.Func.Text
 	textstksiz := p.To.Offset
 	if textstksiz == -8 {
 		// Compatibility hack.
-		p.From3.Offset |= obj.NOFRAME
+		p.From.Sym.Set(obj.AttrNoFrame, true)
 		textstksiz = 0
 	}
 	if textstksiz%8 != 0 {
-		ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
+		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
 	}
-	if p.From3.Offset&obj.NOFRAME != 0 {
+	if p.From.Sym.NoFrame() {
 		if textstksiz != 0 {
-			ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
+			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
 		}
 	}
 
-	cursym.Args = p.To.Val.(int32)
-	cursym.Locals = int32(textstksiz)
+	c.cursym.Func.Args = p.To.Val.(int32)
+	c.cursym.Func.Locals = int32(textstksiz)
 
 	/*
 	 * find leaf subroutines
 	 * strip NOPs
 	 * expand RET
-	 * expand BECOME pseudo
 	 */
-	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f noops\n", obj.Cputime())
-	}
 
 	var q *obj.Prog
-	var q1 *obj.Prog
-	for p := cursym.Text; p != nil; p = p.Link {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		switch p.As {
-		/* too hard, just leave alone */
 		case obj.ATEXT:
 			q = p
+			p.Mark |= LEAF
 
-			p.Mark |= LABEL | LEAF | SYNC
-			if p.Link != nil {
-				p.Link.Mark |= LABEL
-			}
-
-		case ASYNC,
-			AWORD:
+		case ABL, ABCL:
 			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
+			c.cursym.Func.Text.Mark &^= LEAF
 			fallthrough
 
 		case ABC,
@@ -322,59 +262,31 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			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
+			p.Mark |= BRANCH
+			if p.Pcond != nil {
+				q := p.Pcond
+				for q.As == obj.ANOP {
+					q = q.Link
+					p.Pcond = q
 				}
-			} 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
+			q.Link = p.Link /* q is non-nop */
+			p.Link.Mark |= p.Mark
 
 		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 {
+	for p := c.cursym.Func.Text; p != nil; p = p.Link {
 		pLast = p
 		switch p.As {
 		case obj.ATEXT:
@@ -382,27 +294,27 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 			if p.Mark&LEAF != 0 && autosize == 0 {
 				// A leaf function with no locals has no frame.
-				p.From3.Offset |= obj.NOFRAME
+				p.From.Sym.Set(obj.AttrNoFrame, true)
 			}
 
-			if p.From3.Offset&obj.NOFRAME == 0 {
+			if !p.From.Sym.NoFrame() {
 				// If there is a stack frame at all, it includes
 				// space to save the LR.
-				autosize += int32(ctxt.FixedFrameSize())
+				autosize += int32(c.ctxt.FixedFrameSize())
 			}
 
-			if p.Mark&LEAF != 0 && autosize < obj.StackSmall {
+			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
 				// A leaf function with a small stack can be marked
 				// NOSPLIT, avoiding a stack check.
-				p.From3.Offset |= obj.NOSPLIT
+				p.From.Sym.Set(obj.AttrNoSplit, true)
 			}
 
 			p.To.Offset = int64(autosize)
 
-			q = p
+			q := p
 
-			if p.From3.Offset&obj.NOSPLIT == 0 {
-				p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check
+			if !p.From.Sym.NoSplit() {
+				p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
 				pPre = p
 				wasSplit = true //need post part of split
 			}
@@ -413,7 +325,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// Store link register before decrementing SP, so if a signal comes
 				// during the execution of the function prologue, the traceback
 				// code will not see a half-updated stack frame.
-				q = obj.Appendp(ctxt, p)
+				q = obj.Appendp(p, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_LR
@@ -421,7 +333,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Reg = REGSP
 				q.To.Offset = int64(-autosize)
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_ADDR
 				q.From.Offset = int64(-autosize)
@@ -429,19 +341,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REGSP
 				q.Spadj = autosize
-			} else if cursym.Text.Mark&LEAF == 0 {
+			} else if c.cursym.Func.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
+				c.cursym.Func.Text.Mark |= LEAF
 			}
 
-			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Set(obj.AttrLeaf, true)
+			if c.cursym.Func.Text.Mark&LEAF != 0 {
+				c.cursym.Set(obj.AttrLeaf, true)
 				break
 			}
 
-			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+			if c.cursym.Func.Text.From.Sym.Wrapper() {
 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
 				//
 				//	MOVD g_panic(g), R3
@@ -459,28 +371,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				// 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 = obj.Appendp(q, c.newprog)
 
 				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(c.ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ACMP
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R3
 				q.To.Type = obj.TYPE_CONST
 				q.To.Offset = 0
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = ABEQ
 				q.To.Type = obj.TYPE_BRANCH
-				p1 = q
+				p1 := q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REG_R3
@@ -488,35 +400,35 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R4
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
+				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R5
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				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 = obj.Appendp(q, c.newprog)
 				q.As = ABNE
 				q.To.Type = obj.TYPE_BRANCH
-				p2 = q
+				p2 := q
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = ctxt.FixedFrameSize()
+				q.From.Offset = c.ctxt.FixedFrameSize()
 				q.Reg = REGSP
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R6
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_REG
 				q.From.Reg = REG_R6
@@ -524,7 +436,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.To.Reg = REG_R3
 				q.To.Offset = 0 // Panic.argp
 
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 
 				q.As = obj.ANOP
 				p1.Pcond = q
@@ -532,14 +444,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 		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 c.cursym.Func.Text.Mark&LEAF != 0 {
 				if autosize == 0 {
 					p.As = ABR
 					p.From = obj.Addr{}
@@ -561,7 +468,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.To.Reg = REGSP
 				p.Spadj = -autosize
 
-				q = obj.Appendp(ctxt, p)
+				q = obj.Appendp(p, c.newprog)
 				q.As = ABR
 				q.From = obj.Addr{}
 				q.To.Type = obj.TYPE_REG
@@ -581,7 +488,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			q = p
 
 			if autosize != 0 {
-				q = obj.Appendp(ctxt, q)
+				q = obj.Appendp(q, c.newprog)
 				q.As = AADD
 				q.From.Type = obj.TYPE_CONST
 				q.From.Offset = int64(autosize)
@@ -590,7 +497,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.Spadj = -autosize
 			}
 
-			q = obj.Appendp(ctxt, q)
+			q = obj.Appendp(q, c.newprog)
 			q.As = ABR
 			q.From = obj.Addr{}
 			if retTarget == nil {
@@ -610,73 +517,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		}
 	}
 	if wasSplit {
-		pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check
+		c.stacksplitPost(pLast, pPre, pPreempt, autosize) // 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) {
+func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
 	var q *obj.Prog
 
 	// MOVD	g_stackguard(g), R3
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	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.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
+	if c.cursym.CFunc() {
+		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
 
 	q = nil
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP < stackguard
 		//	CMP	stackguard, SP
 
@@ -685,7 +547,7 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
 
 		// q1: BLT	done
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		//q1 = p
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
@@ -704,20 +566,20 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
 		//p.As = ABGE
 		//p.To.Type = obj.TYPE_BRANCH
 
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize < stackguard-StackSmall
-		//	ADD $-framesize, SP, R4
+		//	ADD $-(framesize-StackSmall), SP, R4
 		//	CMP stackguard, R4
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		p.As = AADD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(-framesize)
+		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R4
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_R3
 		p.Reg = REG_R4
@@ -740,42 +602,42 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
 		//	SUB	R3, R4
 		//	MOVD	$(framesize+(StackGuard-StackSmall)), TEMP
 		//	CMPUBGE	TEMP, R4
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 
 		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.To.Offset = objabi.StackPreempt
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		q = p
 		p.As = ABEQ
 		p.To.Type = obj.TYPE_BRANCH
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.As = AADD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.Reg = REGSP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_R4
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		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 = obj.Appendp(p, c.newprog)
 		p.As = AMOVD
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
+		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REGTMP
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, c.newprog)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REGTMP
 		p.Reg = REG_R4
@@ -786,25 +648,24 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
 	return p, q
 }
 
-func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
+func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
 	// Now we are at the end of the function, but logically
 	// we are still in function prologue. We need to fix the
 	// SP data and PCDATA.
-	spfix := obj.Appendp(ctxt, p)
+	spfix := obj.Appendp(p, c.newprog)
 	spfix.As = obj.ANOP
 	spfix.Spadj = -framesize
 
-	pcdata := obj.Appendp(ctxt, spfix)
-	pcdata.Lineno = ctxt.Cursym.Text.Lineno
-	pcdata.Mode = ctxt.Cursym.Text.Mode
+	pcdata := obj.Appendp(spfix, c.newprog)
+	pcdata.Pos = c.cursym.Func.Text.Pos
 	pcdata.As = obj.APCDATA
 	pcdata.From.Type = obj.TYPE_CONST
-	pcdata.From.Offset = obj.PCDATA_StackMapIndex
+	pcdata.From.Offset = objabi.PCDATA_StackMapIndex
 	pcdata.To.Type = obj.TYPE_CONST
 	pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
 
 	// MOVD	LR, R5
-	p = obj.Appendp(ctxt, pcdata)
+	p = obj.Appendp(pcdata, c.newprog)
 	pPre.Pcond = p
 	p.As = AMOVD
 	p.From.Type = obj.TYPE_REG
@@ -816,197 +677,27 @@ func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.P
 	}
 
 	// BL	runtime.morestack(SB)
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	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)
+	if c.cursym.CFunc() {
+		p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
+	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+		p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
 	} else {
-		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
+		p.To.Sym = c.ctxt.Lookup("runtime.morestack")
 	}
 
 	// BR	start
-	p = obj.Appendp(ctxt, p)
+	p = obj.Appendp(p, c.newprog)
 
 	p.As = ABR
 	p.To.Type = obj.TYPE_BRANCH
-	p.Pcond = ctxt.Cursym.Text.Link
+	p.Pcond = c.cursym.Func.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,
@@ -1020,9 +711,9 @@ var unaryDst = map[obj.As]bool{
 
 var Links390x = obj.LinkArch{
 	Arch:       sys.ArchS390X,
+	Init:       buildop,
 	Preprocess: preprocess,
 	Assemble:   spanz,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index b8a3c54..601e9e2 100644
--- a/src/cmd/internal/obj/sizeof_test.go
+++ b/src/cmd/internal/obj/sizeof_test.go
@@ -22,9 +22,9 @@ func TestSizeof(t *testing.T) {
 		_32bit uintptr     // size on 32bit platforms
 		_64bit uintptr     // size on 64bit platforms
 	}{
-		{Addr{}, 40, 64},
-		{LSym{}, 76, 128},
-		{Prog{}, 144, 224},
+		{Addr{}, 32, 48},
+		{LSym{}, 56, 104},
+		{Prog{}, 124, 184},
 	}
 
 	for _, tt := range tests {
diff --git a/src/cmd/internal/obj/sort.go b/src/cmd/internal/obj/sort.go
new file mode 100644
index 0000000..0cb801e
--- /dev/null
+++ b/src/cmd/internal/obj/sort.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package obj
+
+import "sort"
+
+func SortSlice(slice interface{}, less func(i, j int) bool) {
+	sort.Slice(slice, less)
+}
diff --git a/src/cmd/internal/obj/stack.go b/src/cmd/internal/obj/stack.go
deleted file mode 100644
index 687adf2..0000000
--- a/src/cmd/internal/obj/stack.go
+++ /dev/null
@@ -1,21 +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 obj
-
-// For the linkers. Must match Go definitions.
-// TODO(rsc): Share Go definitions with linkers directly.
-
-const (
-	STACKSYSTEM = 0
-	StackSystem = STACKSYSTEM
-	StackBig    = 4096
-	StackGuard  = 880*stackGuardMultiplier + StackSystem
-	StackSmall  = 128
-	StackLimit  = StackGuard - StackSystem - StackSmall
-)
-
-const (
-	StackPreempt = -1314 // 0xfff...fade
-)
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 84de5b6..3fb2df1 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -32,57 +32,94 @@
 package obj
 
 import (
+	"cmd/internal/objabi"
+	"fmt"
 	"log"
-	"os"
-	"path/filepath"
+	"math"
 )
 
 func Linknew(arch *LinkArch) *Link {
 	ctxt := new(Link)
-	ctxt.Hash = make(map[SymVer]*LSym)
+	ctxt.hash = make(map[string]*LSym)
+	ctxt.statichash = make(map[string]*LSym)
 	ctxt.Arch = arch
-	ctxt.Version = HistVersion
+	ctxt.Pathname = objabi.WorkingDir()
 
-	var buf string
-	buf, _ = os.Getwd()
-	if buf == "" {
-		buf = "/???"
-	}
-	buf = filepath.ToSlash(buf)
-	ctxt.Pathname = buf
-
-	ctxt.LineHist.GOROOT = GOROOT
-	ctxt.LineHist.Dir = ctxt.Pathname
-
-	ctxt.Headtype.Set(GOOS)
+	ctxt.Headtype.Set(objabi.GOOS)
 	if ctxt.Headtype < 0 {
-		log.Fatalf("unknown goos %s", GOOS)
+		log.Fatalf("unknown goos %s", objabi.GOOS)
 	}
 
 	ctxt.Flag_optimize = true
-	ctxt.Framepointer_enabled = Framepointer_enabled(GOOS, arch.Name)
+	ctxt.Framepointer_enabled = objabi.Framepointer_enabled(objabi.GOOS, arch.Name)
 	return ctxt
 }
 
-func Linklookup(ctxt *Link, name string, v int) *LSym {
-	s := ctxt.Hash[SymVer{name, v}]
-	if s != nil {
-		return s
+// LookupDerived looks up or creates the symbol with name name derived from symbol s.
+// The resulting symbol will be static iff s is.
+func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym {
+	if s.Static() {
+		return ctxt.LookupStatic(name)
 	}
+	return ctxt.Lookup(name)
+}
 
-	s = &LSym{
-		Name:    name,
-		Type:    0,
-		Version: int16(v),
-		Size:    0,
+// LookupStatic looks up the static symbol with name name.
+// If it does not exist, it creates it.
+func (ctxt *Link) LookupStatic(name string) *LSym {
+	s := ctxt.statichash[name]
+	if s == nil {
+		s = &LSym{Name: name, Attribute: AttrStatic}
+		ctxt.statichash[name] = s
 	}
-	ctxt.Hash[SymVer{name, v}] = s
 	return s
 }
 
-func Linksymfmt(s *LSym) string {
+// Lookup looks up the symbol with name name.
+// If it does not exist, it creates it.
+func (ctxt *Link) Lookup(name string) *LSym {
+	return ctxt.LookupInit(name, nil)
+}
+
+// LookupInit looks up the symbol with name name.
+// If it does not exist, it creates it and
+// passes it to init for one-time initialization.
+func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
+	ctxt.hashmu.Lock()
+	s := ctxt.hash[name]
 	if s == nil {
-		return "<nil>"
+		s = &LSym{Name: name}
+		ctxt.hash[name] = s
+		if init != nil {
+			init(s)
+		}
 	}
-	return s.Name
+	ctxt.hashmu.Unlock()
+	return s
+}
+
+func (ctxt *Link) Float32Sym(f float32) *LSym {
+	i := math.Float32bits(f)
+	name := fmt.Sprintf("$f32.%08x", i)
+	return ctxt.LookupInit(name, func(s *LSym) {
+		s.Size = 4
+		s.Set(AttrLocal, true)
+	})
+}
+
+func (ctxt *Link) Float64Sym(f float64) *LSym {
+	i := math.Float64bits(f)
+	name := fmt.Sprintf("$f64.%016x", i)
+	return ctxt.LookupInit(name, func(s *LSym) {
+		s.Size = 8
+		s.Set(AttrLocal, true)
+	})
+}
+
+func (ctxt *Link) Int64Sym(i int64) *LSym {
+	name := fmt.Sprintf("$i64.%016x", uint64(i))
+	return ctxt.LookupInit(name, func(s *LSym) {
+		s.Size = 8
+		s.Set(AttrLocal, true)
+	})
 }
diff --git a/src/cmd/internal/obj/symkind_string.go b/src/cmd/internal/obj/symkind_string.go
deleted file mode 100644
index fef8c35..0000000
--- a/src/cmd/internal/obj/symkind_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type=SymKind"; DO NOT EDIT
-
-package obj
-
-import "fmt"
-
-const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFO"
-
-var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408}
-
-func (i SymKind) String() string {
-	if i < 0 || i >= SymKind(len(_SymKind_index)-1) {
-		return fmt.Sprintf("SymKind(%d)", i)
-	}
-	return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
-}
diff --git a/src/cmd/internal/obj/typekind.go b/src/cmd/internal/obj/typekind.go
deleted file mode 100644
index 2193271..0000000
--- a/src/cmd/internal/obj/typekind.go
+++ /dev/null
@@ -1,41 +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 obj
-
-// Must match runtime and reflect.
-// Included by cmd/gc.
-
-const (
-	KindBool = 1 + iota
-	KindInt
-	KindInt8
-	KindInt16
-	KindInt32
-	KindInt64
-	KindUint
-	KindUint8
-	KindUint16
-	KindUint32
-	KindUint64
-	KindUintptr
-	KindFloat32
-	KindFloat64
-	KindComplex64
-	KindComplex128
-	KindArray
-	KindChan
-	KindFunc
-	KindInterface
-	KindMap
-	KindPtr
-	KindSlice
-	KindString
-	KindStruct
-	KindUnsafePointer
-	KindDirectIface = 1 << 5
-	KindGCProg      = 1 << 6
-	KindNoPointers  = 1 << 7
-	KindMask        = (1 << 5) - 1
-)
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index bc5d1c5..9bcdbbd 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -6,60 +6,15 @@ package obj
 
 import (
 	"bytes"
+	"cmd/internal/objabi"
 	"fmt"
-	"log"
-	"os"
 	"strings"
-	"time"
 )
 
 const REG_NONE = 0
 
-var start time.Time
-
-func Cputime() float64 {
-	if start.IsZero() {
-		start = time.Now()
-	}
-	return time.Since(start).Seconds()
-}
-
-func envOr(key, value string) string {
-	if x := os.Getenv(key); x != "" {
-		return x
-	}
-	return value
-}
-
-var (
-	GOROOT  = envOr("GOROOT", defaultGOROOT)
-	GOARCH  = envOr("GOARCH", defaultGOARCH)
-	GOOS    = envOr("GOOS", defaultGOOS)
-	GO386   = envOr("GO386", defaultGO386)
-	GOARM   = goarm()
-	Version = version
-)
-
-func goarm() int {
-	switch v := envOr("GOARM", defaultGOARM); v {
-	case "5":
-		return 5
-	case "6":
-		return 6
-	case "7":
-		return 7
-	}
-	// Fail here, rather than validate at multiple call sites.
-	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
-	panic("unreachable")
-}
-
-func Getgoextlinkenabled() string {
-	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
-}
-
 func (p *Prog) Line() string {
-	return p.Ctxt.LineHist.LineString(int(p.Lineno))
+	return p.Ctxt.OutermostPos(p.Pos).Format(false)
 }
 
 var armCondCode = []string{
@@ -143,16 +98,24 @@ func (p *Prog) String() string {
 		sep = ", "
 	}
 	if p.From3Type() != TYPE_NONE {
-		if p.From3.Type == TYPE_CONST && p.As == ATEXT {
-			// Special case - omit $.
-			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
-		} else if quadOpAmd64 {
+		if quadOpAmd64 {
 			fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
 		} else {
 			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
 		}
 		sep = ", "
 	}
+	if p.As == ATEXT {
+		// If there are attributes, print them. Otherwise, skip the comma.
+		// In short, print one of these two:
+		// TEXT	foo(SB), DUPOK|NOSPLIT, $0
+		// TEXT	foo(SB), $0
+		s := p.From.Sym.Attribute.TextAttrString()
+		if s != "" {
+			fmt.Fprintf(&buf, "%s%s", sep, s)
+			sep = ", "
+		}
+	}
 	if p.To.Type != TYPE_NONE {
 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
 	}
@@ -163,30 +126,13 @@ func (p *Prog) String() string {
 }
 
 func (ctxt *Link) NewProg() *Prog {
-	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 := new(Prog)
 	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)
-}
-
-func Getcallerpc(interface{}) uintptr {
-	return 1
+func (ctxt *Link) CanReuseProgs() bool {
+	return !ctxt.Debugasm
 }
 
 func (ctxt *Link) Dconv(a *Addr) string {
@@ -249,7 +195,7 @@ func Dconv(p *Prog, a *Addr) string {
 		}
 
 	case TYPE_TEXTSIZE:
-		if a.Val.(int32) == ArgsSizeUnknown {
+		if a.Val.(int32) == objabi.ArgsSizeUnknown {
 			str = fmt.Sprintf("$%d", a.Offset)
 		} else {
 			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
@@ -272,7 +218,7 @@ func Dconv(p *Prog, a *Addr) string {
 	case TYPE_SHIFT:
 		v := int(a.Offset)
 		ops := "<<>>->@>"
-		switch GOARCH {
+		switch objabi.GOARCH {
 		case "arm":
 			op := ops[((v>>5)&3)<<1:]
 			if v&(1<<4) != 0 {
@@ -287,14 +233,14 @@ func Dconv(p *Prog, a *Addr) string {
 			op := ops[((v>>22)&3)<<1:]
 			str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
 		default:
-			panic("TYPE_SHIFT is not supported on " + GOARCH)
+			panic("TYPE_SHIFT is not supported on " + objabi.GOARCH)
 		}
 
 	case TYPE_REGREG:
 		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
 
 	case TYPE_REGREG2:
-		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
+		str = fmt.Sprintf("%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
 
 	case TYPE_REGLIST:
 		str = regListConv(int(a.Offset))
@@ -320,39 +266,60 @@ func Mconv(a *Addr) string {
 			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
 		}
 
+		// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
 	case NAME_EXTERN:
+		reg := "SB"
+		if a.Reg != REG_NONE {
+			reg = Rconv(int(a.Reg))
+		}
 		if a.Sym != nil {
-			str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
+			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
 		} else {
-			str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
+			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
 		}
 
 	case NAME_GOTREF:
+		reg := "SB"
+		if a.Reg != REG_NONE {
+			reg = Rconv(int(a.Reg))
+		}
 		if a.Sym != nil {
-			str = fmt.Sprintf("%s%s at GOT(SB)", a.Sym.Name, offConv(a.Offset))
+			str = fmt.Sprintf("%s%s at GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
 		} else {
-			str = fmt.Sprintf("%s at GOT(SB)", offConv(a.Offset))
+			str = fmt.Sprintf("%s at GOT(%s)", offConv(a.Offset), reg)
 		}
 
 	case NAME_STATIC:
+		reg := "SB"
+		if a.Reg != REG_NONE {
+			reg = Rconv(int(a.Reg))
+		}
 		if a.Sym != nil {
-			str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
+			str = fmt.Sprintf("%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
 		} else {
-			str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
+			str = fmt.Sprintf("<>%s(%s)", offConv(a.Offset), reg)
 		}
 
 	case NAME_AUTO:
+		reg := "SP"
+		if a.Reg != REG_NONE {
+			reg = Rconv(int(a.Reg))
+		}
 		if a.Sym != nil {
-			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
+			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
 		} else {
-			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
+			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
 		}
 
 	case NAME_PARAM:
+		reg := "FP"
+		if a.Reg != REG_NONE {
+			reg = Rconv(int(a.Reg))
+		}
 		if a.Sym != nil {
-			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
+			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
 		} else {
-			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
+			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
 		}
 	}
 	return str
@@ -478,12 +445,7 @@ var Anames = []string{
 	"PCDATA",
 	"RET",
 	"TEXT",
-	"TYPE",
 	"UNDEF",
-	"USEFIELD",
-	"VARDEF",
-	"VARKILL",
-	"VARLIVE",
 }
 
 func Bool2int(b bool) int {
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index 02f92ed..04f9ef6 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -746,7 +746,6 @@ const (
 	ARETFQ
 	ASWAPGS
 
-	AMODE
 	ACRC32B
 	ACRC32Q
 	AIMUL3Q
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
index 8c5be80..38cc03d 100644
--- a/src/cmd/internal/obj/x86/anames.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -687,7 +687,6 @@ var Anames = []string{
 	"RETFL",
 	"RETFQ",
 	"SWAPGS",
-	"MODE",
 	"CRC32B",
 	"CRC32Q",
 	"IMUL3Q",
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index bf67822..bcf9318 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -32,12 +32,19 @@ package x86
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"log"
 	"strings"
 )
 
+var (
+	plan9privates *obj.LSym
+	deferreturn   *obj.LSym
+)
+
 // Instruction layout.
 
 const (
@@ -56,7 +63,6 @@ const (
 	//
 	LoopAlign  = 16
 	MaxLoopPad = 0
-	funcAlign  = 16
 )
 
 type Optab struct {
@@ -876,19 +882,19 @@ var ymmxmm0f38 = []ytab{
 }
 
 /*
- * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
- * and p->from and p->to as operands (Addr*).  The linker scans optab to find
- * the entry with the given p->as and then looks through the ytable for that
- * instruction (the second field in the optab struct) for a line whose first
- * two values match the Ytypes of the p->from and p->to operands.  The function
- * oclass in span.c computes the specific Ytype of an operand and then the set
+ * You are doasm, holding in your hand a *obj.Prog with p.As set to, say,
+ * ACRC32, and p.From and p.To as operands (obj.Addr).  The linker scans optab
+ * to find the entry with the given p.As and then looks through the ytable for
+ * that instruction (the second field in the optab struct) for a line whose
+ * first two values match the Ytypes of the p.From and p.To operands.  The
+ * function oclass computes the specific Ytype of an operand and then the set
  * of more general Ytypes that it satisfies is implied by the ycover table, set
  * up in instinit.  For example, oclass distinguishes the constants 0 and 1
  * from the more general 8-bit constants, but instinit says
  *
- *        ycover[Yi0*Ymax + Ys32] = 1;
- *        ycover[Yi1*Ymax + Ys32] = 1;
- *        ycover[Yi8*Ymax + Ys32] = 1;
+ *        ycover[Yi0*Ymax+Ys32] = 1
+ *        ycover[Yi1*Ymax+Ys32] = 1
+ *        ycover[Yi8*Ymax+Ys32] = 1
  *
  * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
  * if that's what an instruction can handle.
@@ -902,22 +908,20 @@ var ymmxmm0f38 = []ytab{
  * is, the Ztype) and the z bytes.
  *
  * For example, let's look at AADDL.  The optab line says:
- *        { AADDL,        yaddl,  Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *        {AADDL, yaddl, Px, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
  *
  * and yaddl says
- *        uchar   yaddl[] =
- *        {
- *                Yi8,    Yml,    Zibo_m, 2,
- *                Yi32,   Yax,    Zil_,   1,
- *                Yi32,   Yml,    Zilo_m, 2,
- *                Yrl,    Yml,    Zr_m,   1,
- *                Yml,    Yrl,    Zm_r,   1,
- *                0
- *        };
+ *        var yaddl = []ytab{
+ *                {Yi8, Ynone, Yml, Zibo_m, 2},
+ *                {Yi32, Ynone, Yax, Zil_, 1},
+ *                {Yi32, Ynone, Yml, Zilo_m, 2},
+ *                {Yrl, Ynone, Yml, Zr_m, 1},
+ *                {Yml, Ynone, Yrl, Zm_r, 1},
+ *        }
  *
  * so there are 5 possible types of ADDL instruction that can be laid down, and
  * possible states used to lay them down (Ztype and z pointer, assuming z
- * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ * points at [23]uint8{0x83, 00, 0x05,0x81, 00, 0x01, 0x03}) are:
  *
  *        Yi8, Yml -> Zibo_m, z (0x83, 00)
  *        Yi32, Yax -> Zil_, z+2 (0x05)
@@ -928,7 +932,7 @@ var ymmxmm0f38 = []ytab{
  * The Pconstant in the optab line controls the prefix bytes to emit.  That's
  * relatively straightforward as this program goes.
  *
- * The switch on t[2] in doasm implements the various Z cases.  Zibo_m, for
+ * The switch on yt.zcase in doasm implements the various Z cases.  Zibo_m, for
  * example, is an opcode byte (z[0]) then an asmando (which is some kind of
  * encoded addressing mode for the Yml arg), and then a single immediate byte.
  * Zilo_m is the same but a long (32-bit) immediate.
@@ -941,7 +945,7 @@ var optab =
 	{AAAD, ynone, P32, [23]uint8{0xd5, 0x0a}},
 	{AAAM, ynone, P32, [23]uint8{0xd4, 0x0a}},
 	{AAAS, ynone, P32, [23]uint8{0x3f}},
-	{AADCB, yxorb, Pb, [23]uint8{0x14, 0x80, 02, 0x10, 0x10}},
+	{AADCB, yxorb, Pb, [23]uint8{0x14, 0x80, 02, 0x10, 0x12}},
 	{AADCL, yaddl, Px, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
 	{AADCQ, yaddl, Pw, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
 	{AADCW, yaddl, Pe, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
@@ -959,7 +963,7 @@ var optab =
 	{AANDNPD, yxm, Pq, [23]uint8{0x55}},
 	{AANDNPS, yxm, Pm, [23]uint8{0x55}},
 	{AANDPD, yxm, Pq, [23]uint8{0x54}},
-	{AANDPS, yxm, Pq, [23]uint8{0x54}},
+	{AANDPS, yxm, Pm, [23]uint8{0x54}},
 	{AANDQ, yaddl, Pw, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
 	{AANDW, yaddl, Pe, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
 	{AARPL, yrl_ml, P32, [23]uint8{0x63}},
@@ -1698,12 +1702,8 @@ var optab =
 	{AXEND, ynone, Px, [23]uint8{0x0f, 01, 0xd5}},
 	{AXTEST, ynone, Px, [23]uint8{0x0f, 01, 0xd6}},
 	{AXGETBV, ynone, Pm, [23]uint8{01, 0xd0}},
-	{obj.AUSEFIELD, ynop, Px, [23]uint8{0, 0}},
-	{obj.ATYPE, nil, 0, [23]uint8{}},
 	{obj.AFUNCDATA, yfuncdata, Px, [23]uint8{0, 0}},
 	{obj.APCDATA, ypcdata, Px, [23]uint8{0, 0}},
-	{obj.AVARDEF, nil, 0, [23]uint8{}},
-	{obj.AVARKILL, nil, 0, [23]uint8{}},
 	{obj.ADUFFCOPY, yduff, Px, [23]uint8{0xe8}},
 	{obj.ADUFFZERO, yduff, Px, [23]uint8{0xe8}},
 	{obj.AEND, nil, 0, [23]uint8{}},
@@ -1760,24 +1760,24 @@ func naclpad(ctxt *obj.Link, s *obj.LSym, c int32, pad int32) int32 {
 }
 
 func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As {
-	if p.Mode != 64 || ctxt.Arch.PtrSize == 4 {
+	if ctxt.Arch.Family != sys.AMD64 || ctxt.Arch.PtrSize == 4 {
 		return l
 	}
 	return q
 }
 
-func span6(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
+func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
 	if s.P != nil {
 		return
 	}
 
 	if ycover[0] == 0 {
-		instinit()
+		ctxt.Diag("x86 tables not initialized, call x86.instinit first")
 	}
 
-	for p := ctxt.Cursym.Text; p != nil; p = p.Link {
+	var asmbuf AsmBuf
+
+	for p := s.Func.Text; p != nil; p = p.Link {
 		if p.To.Type == obj.TYPE_BRANCH {
 			if p.Pcond == nil {
 				p.Pcond = p
@@ -1803,7 +1803,7 @@ 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 {
+	for p := s.Func.Text; p != nil; p = p.Link {
 		count++
 		p.Back = 2 // use short branches first time through
 		q = p.Pcond
@@ -1834,10 +1834,6 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 	n := 0
 	var c int32
 	errors := ctxt.Errors
-	var deferreturn *obj.LSym
-	if ctxt.Headtype == obj.Hnacl {
-		deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
-	}
 	for {
 		loop := int32(0)
 		for i := range s.R {
@@ -1846,8 +1842,8 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		s.R = s.R[:0]
 		s.P = s.P[:0]
 		c = 0
-		for p := s.Text; p != nil; p = p.Link {
-			if ctxt.Headtype == obj.Hnacl && p.Isize > 0 {
+		for p := s.Func.Text; p != nil; p = p.Link {
+			if ctxt.Headtype == objabi.Hnacl && p.Isize > 0 {
 
 				// pad everything to avoid crossing 32-byte boundary
 				if c>>5 != (c+int32(p.Isize)-1)>>5 {
@@ -1917,15 +1913,15 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 			p.Rel = nil
 
 			p.Pc = int64(c)
-			asmins(ctxt, p)
-			m := ctxt.AsmBuf.Len()
+			asmbuf.asmins(ctxt, s, p)
+			m := asmbuf.Len()
 			if int(p.Isize) != m {
 				p.Isize = uint8(m)
 				loop++
 			}
 
 			s.Grow(p.Pc + int64(m))
-			copy(s.P[p.Pc:], ctxt.AsmBuf.Bytes())
+			copy(s.P[p.Pc:], asmbuf.Bytes())
 			c += int32(m)
 		}
 
@@ -1942,7 +1938,7 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl {
+	if ctxt.Headtype == objabi.Hnacl {
 		c = naclpad(ctxt, s, c, -c&31)
 	}
 
@@ -1969,11 +1965,25 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 	}
 }
 
-func instinit() {
+func instinit(ctxt *obj.Link) {
+	if ycover[0] != 0 {
+		// Already initialized; stop now.
+		// This happens in the cmd/asm tests,
+		// each of which re-initializes the arch.
+		return
+	}
+
+	switch ctxt.Headtype {
+	case objabi.Hplan9:
+		plan9privates = ctxt.Lookup("_privates")
+	case objabi.Hnacl:
+		deferreturn = ctxt.Lookup("runtime.deferreturn")
+	}
+
 	for i := 1; optab[i].as != 0; i++ {
 		c := optab[i].as
 		if opindex[c&obj.AMask] != nil {
-			log.Fatalf("phase error in optab: %d (%v)", i, c)
+			ctxt.Diag("phase error in optab: %d (%v)", i, c)
 		}
 		opindex[c&obj.AMask] = &optab[i]
 	}
@@ -2110,7 +2120,7 @@ func instinit() {
 	}
 }
 
-var isAndroid = (obj.GOOS == "android")
+var isAndroid = (objabi.GOOS == "android")
 
 func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 	if a.Reg < REG_CS && a.Index < REG_CS { // fast path
@@ -2140,7 +2150,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 			// the initial-exec model, where you load the TLS base into
 			// a register and then index from that register, do not reach
 			// this code and should not be listed.
-			if p.Mode == 32 {
+			if ctxt.Arch.Family == sys.I386 {
 				switch ctxt.Headtype {
 				default:
 					if isAndroid {
@@ -2148,11 +2158,11 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 					}
 					log.Fatalf("unknown TLS base register for %v", ctxt.Headtype)
 
-				case obj.Hdarwin,
-					obj.Hdragonfly,
-					obj.Hfreebsd,
-					obj.Hnetbsd,
-					obj.Hopenbsd:
+				case objabi.Hdarwin,
+					objabi.Hdragonfly,
+					objabi.Hfreebsd,
+					objabi.Hnetbsd,
+					objabi.Hopenbsd:
 					return 0x65 // GS
 				}
 			}
@@ -2161,7 +2171,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 			default:
 				log.Fatalf("unknown TLS base register for %v", ctxt.Headtype)
 
-			case obj.Hlinux:
+			case objabi.Hlinux:
 				if isAndroid {
 					return 0x64 // FS
 				}
@@ -2172,20 +2182,20 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 					return 0x64 // FS
 				}
 
-			case obj.Hdragonfly,
-				obj.Hfreebsd,
-				obj.Hnetbsd,
-				obj.Hopenbsd,
-				obj.Hsolaris:
+			case objabi.Hdragonfly,
+				objabi.Hfreebsd,
+				objabi.Hnetbsd,
+				objabi.Hopenbsd,
+				objabi.Hsolaris:
 				return 0x64 // FS
 
-			case obj.Hdarwin:
+			case objabi.Hdarwin:
 				return 0x65 // GS
 			}
 		}
 	}
 
-	if p.Mode == 32 {
+	if ctxt.Arch.Family == sys.I386 {
 		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
@@ -2258,7 +2268,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 			// Can't use SP as the index register
 			return Yxxx
 		}
-		if ctxt.Asmode == 64 {
+		if ctxt.Arch.Family == sys.AMD64 {
 			switch a.Name {
 			case obj.NAME_EXTERN, obj.NAME_STATIC, obj.NAME_GOTREF:
 				// Global variables can't use index registers and their
@@ -2289,7 +2299,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) {
+			if a.Sym != nil && isextern(a.Sym) || (ctxt.Arch.Family == sys.I386 && !ctxt.Flag_shared) {
 				return Yi32
 			}
 			return Yiauto // use pc-relative addressing
@@ -2319,7 +2329,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		}
 
 		v := a.Offset
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			v = int64(int32(v))
 		}
 		if v == 0 {
@@ -2341,7 +2351,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		if v >= -128 && v <= 127 {
 			return Yi8
 		}
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			return Yi32
 		}
 		l := int32(v)
@@ -2383,7 +2393,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		REG_R13B,
 		REG_R14B,
 		REG_R15B:
-		if ctxt.Asmode != 64 {
+		if ctxt.Arch.Family == sys.I386 {
 			return Yxxx
 		}
 		fallthrough
@@ -2413,13 +2423,13 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		REG_R13,
 		REG_R14,
 		REG_R15:
-		if ctxt.Asmode != 64 {
+		if ctxt.Arch.Family == sys.I386 {
 			return Yxxx
 		}
 		fallthrough
 
 	case REG_SP, REG_BP, REG_SI, REG_DI:
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			return Yrl32
 		}
 		return Yrl
@@ -2565,7 +2575,106 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 	return Yxxx
 }
 
-func asmidx(ctxt *obj.Link, scale int, index int, base int) {
+// AsmBuf is a simple buffer to assemble variable-length x86 instructions into
+// and hold assembly state.
+type AsmBuf struct {
+	buf     [100]byte
+	off     int
+	rexflag int
+	vexflag int
+	rep     int
+	repn    int
+	lock    bool
+}
+
+// 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 }
+
+// At returns the byte at offset i.
+func (a *AsmBuf) At(i int) byte { return a.buf[i] }
+
+func (asmbuf *AsmBuf) asmidx(ctxt *obj.Link, scale int, index int, base int) {
 	var i int
 
 	switch index {
@@ -2584,7 +2693,7 @@ func asmidx(ctxt *obj.Link, scale int, index int, base int) {
 		REG_R13,
 		REG_R14,
 		REG_R15:
-		if ctxt.Asmode != 64 {
+		if ctxt.Arch.Family == sys.I386 {
 			goto bad
 		}
 		fallthrough
@@ -2632,7 +2741,7 @@ bas:
 		REG_R13,
 		REG_R14,
 		REG_R15:
-		if ctxt.Asmode != 64 {
+		if ctxt.Arch.Family == sys.I386 {
 			goto bad
 		}
 		fallthrough
@@ -2648,16 +2757,16 @@ bas:
 		i |= reg[base]
 	}
 
-	ctxt.AsmBuf.Put1(byte(i))
+	asmbuf.Put1(byte(i))
 	return
 
 bad:
 	ctxt.Diag("asmidx: bad address %d/%d/%d", scale, index, base)
-	ctxt.AsmBuf.Put1(0)
+	asmbuf.Put1(0)
 	return
 }
 
-func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
+func (asmbuf *AsmBuf) relput4(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, a *obj.Addr) {
 	var rel obj.Reloc
 
 	v := vaddr(ctxt, p, a, &rel)
@@ -2665,31 +2774,14 @@ func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		if rel.Siz != 4 {
 			ctxt.Diag("bad reloc")
 		}
-		r := obj.Addrel(ctxt.Cursym)
+		r := obj.Addrel(cursym)
 		*r = rel
-		r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+		r.Off = int32(p.Pc + int64(asmbuf.Len()))
 	}
 
-	ctxt.AsmBuf.PutInt32(int32(v))
+	asmbuf.PutInt32(int32(v))
 }
 
-/*
-static void
-relput8(Prog *p, Addr *a)
-{
-	vlong v;
-	Reloc rel, *r;
-
-	v = vaddr(ctxt, p, a, &rel);
-	if(rel.siz != 0) {
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->siz = 8;
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-	}
-	put8(ctxt, v);
-}
-*/
 func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
 	if r != nil {
 		*r = obj.Reloc{}
@@ -2707,13 +2799,13 @@ 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) {
+			r.Type = objabi.R_GOTPCREL
+		} else if isextern(s) || (ctxt.Arch.Family != sys.AMD64 && !ctxt.Flag_shared) {
 			r.Siz = 4
-			r.Type = obj.R_ADDR
+			r.Type = objabi.R_ADDR
 		} else {
 			r.Siz = 4
-			r.Type = obj.R_PCREL
+			r.Type = objabi.R_PCREL
 		}
 
 		r.Off = -1 // caller must fill in
@@ -2729,8 +2821,8 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
 			log.Fatalf("reloc")
 		}
 
-		if !ctxt.Flag_shared || isAndroid || ctxt.Headtype == obj.Hdarwin {
-			r.Type = obj.R_TLS_LE
+		if !ctxt.Flag_shared || isAndroid || ctxt.Headtype == objabi.Hdarwin {
+			r.Type = objabi.R_TLS_LE
 			r.Siz = 4
 			r.Off = -1 // caller must fill in
 			r.Add = a.Offset
@@ -2741,7 +2833,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
 	return a.Offset
 }
 
-func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int) {
+func (asmbuf *AsmBuf) asmandsz(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int) {
 	var base int
 	var rel obj.Reloc
 
@@ -2749,7 +2841,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 	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:
+	case int64(uint32(a.Offset)) == a.Offset && asmbuf.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.
@@ -2776,8 +2868,8 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		if v != 0 {
 			goto bad
 		}
-		ctxt.AsmBuf.Put1(byte(3<<6 | reg[a.Reg]<<0 | r<<3))
-		ctxt.Rexflag |= regrex[a.Reg]&(0x40|Rxb) | rex
+		asmbuf.Put1(byte(3<<6 | reg[a.Reg]<<0 | r<<3))
+		asmbuf.rexflag |= regrex[a.Reg]&(0x40|Rxb) | rex
 		return
 	}
 
@@ -2791,10 +2883,10 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		case obj.NAME_EXTERN,
 			obj.NAME_GOTREF,
 			obj.NAME_STATIC:
-			if !isextern(a.Sym) && p.Mode == 64 {
+			if !isextern(a.Sym) && ctxt.Arch.Family == sys.AMD64 {
 				goto bad
 			}
-			if p.Mode == 32 && ctxt.Flag_shared {
+			if ctxt.Arch.Family == sys.I386 && ctxt.Flag_shared {
 				// The base register has already been set. It holds the PC
 				// of this instruction returned by a PC-reading thunk.
 				// See obj6.go:rewriteToPcrel.
@@ -2808,28 +2900,28 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 			base = REG_SP
 		}
 
-		ctxt.Rexflag |= regrex[int(a.Index)]&Rxx | regrex[base]&Rxb | rex
+		asmbuf.rexflag |= regrex[int(a.Index)]&Rxx | regrex[base]&Rxb | rex
 		if base == REG_NONE {
-			ctxt.AsmBuf.Put1(byte(0<<6 | 4<<0 | r<<3))
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
+			asmbuf.Put1(byte(0<<6 | 4<<0 | r<<3))
+			asmbuf.asmidx(ctxt, int(a.Scale), int(a.Index), base)
 			goto putrelv
 		}
 
 		if v == 0 && rel.Siz == 0 && base != REG_BP && base != REG_R13 {
-			ctxt.AsmBuf.Put1(byte(0<<6 | 4<<0 | r<<3))
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
+			asmbuf.Put1(byte(0<<6 | 4<<0 | r<<3))
+			asmbuf.asmidx(ctxt, int(a.Scale), int(a.Index), base)
 			return
 		}
 
 		if v >= -128 && v < 128 && rel.Siz == 0 {
-			ctxt.AsmBuf.Put1(byte(1<<6 | 4<<0 | r<<3))
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
-			ctxt.AsmBuf.Put1(byte(v))
+			asmbuf.Put1(byte(1<<6 | 4<<0 | r<<3))
+			asmbuf.asmidx(ctxt, int(a.Scale), int(a.Index), base)
+			asmbuf.Put1(byte(v))
 			return
 		}
 
-		ctxt.AsmBuf.Put1(byte(2<<6 | 4<<0 | r<<3))
-		asmidx(ctxt, int(a.Scale), int(a.Index), base)
+		asmbuf.Put1(byte(2<<6 | 4<<0 | r<<3))
+		asmbuf.asmidx(ctxt, int(a.Scale), int(a.Index), base)
 		goto putrelv
 	}
 
@@ -2841,7 +2933,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 {
+		if ctxt.Arch.Family == sys.I386 && ctxt.Flag_shared {
 			// The base register has already been set. It holds the PC
 			// of this instruction returned by a PC-reading thunk.
 			// See obj6.go:rewriteToPcrel.
@@ -2859,18 +2951,18 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		v = int32(vaddr(ctxt, p, a, &rel))
 	}
 
-	ctxt.Rexflag |= regrex[base]&Rxb | rex
+	asmbuf.rexflag |= regrex[base]&Rxb | rex
 	if base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS {
-		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_GOTREF) || p.Mode != 64 {
+		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_GOTREF) || ctxt.Arch.Family != sys.AMD64 {
 			if a.Name == obj.NAME_GOTREF && (a.Offset != 0 || a.Index != 0 || a.Scale != 0) {
 				ctxt.Diag("%v has offset against gotref", p)
 			}
-			ctxt.AsmBuf.Put1(byte(0<<6 | 5<<0 | r<<3))
+			asmbuf.Put1(byte(0<<6 | 5<<0 | r<<3))
 			goto putrelv
 		}
 
 		// temporary
-		ctxt.AsmBuf.Put2(
+		asmbuf.Put2(
 			byte(0<<6|4<<0|r<<3), // sib present
 			0<<6|4<<3|5<<0,       // DS:d32
 		)
@@ -2879,27 +2971,27 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 
 	if base == REG_SP || base == REG_R12 {
 		if v == 0 {
-			ctxt.AsmBuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
-			asmidx(ctxt, int(a.Scale), REG_NONE, base)
+			asmbuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
+			asmbuf.asmidx(ctxt, int(a.Scale), REG_NONE, base)
 			return
 		}
 
 		if v >= -128 && v < 128 {
-			ctxt.AsmBuf.Put1(byte(1<<6 | reg[base]<<0 | r<<3))
-			asmidx(ctxt, int(a.Scale), REG_NONE, base)
-			ctxt.AsmBuf.Put1(byte(v))
+			asmbuf.Put1(byte(1<<6 | reg[base]<<0 | r<<3))
+			asmbuf.asmidx(ctxt, int(a.Scale), REG_NONE, base)
+			asmbuf.Put1(byte(v))
 			return
 		}
 
-		ctxt.AsmBuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
-		asmidx(ctxt, int(a.Scale), REG_NONE, base)
+		asmbuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
+		asmbuf.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 {
 			rel = obj.Reloc{}
-			rel.Type = obj.R_TLS_LE
+			rel.Type = objabi.R_TLS_LE
 			rel.Siz = 4
 			rel.Sym = nil
 			rel.Add = int64(v)
@@ -2907,16 +2999,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.AsmBuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
+			asmbuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
 			return
 		}
 
 		if v >= -128 && v < 128 && rel.Siz == 0 {
-			ctxt.AsmBuf.Put2(byte(1<<6|reg[base]<<0|r<<3), byte(v))
+			asmbuf.Put2(byte(1<<6|reg[base]<<0|r<<3), byte(v))
 			return
 		}
 
-		ctxt.AsmBuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
+		asmbuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
 		goto putrelv
 	}
 
@@ -2929,12 +3021,12 @@ putrelv:
 			goto bad
 		}
 
-		r := obj.Addrel(ctxt.Cursym)
+		r := obj.Addrel(cursym)
 		*r = rel
-		r.Off = int32(ctxt.Curp.Pc + int64(ctxt.AsmBuf.Len()))
+		r.Off = int32(p.Pc + int64(asmbuf.Len()))
 	}
 
-	ctxt.AsmBuf.PutInt32(v)
+	asmbuf.PutInt32(v)
 	return
 
 bad:
@@ -2942,12 +3034,12 @@ bad:
 	return
 }
 
-func asmand(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, ra *obj.Addr) {
-	asmandsz(ctxt, p, a, reg[ra.Reg], regrex[ra.Reg], 0)
+func (asmbuf *AsmBuf) asmand(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, a *obj.Addr, ra *obj.Addr) {
+	asmbuf.asmandsz(ctxt, cursym, p, a, reg[ra.Reg], regrex[ra.Reg], 0)
 }
 
-func asmando(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, o int) {
-	asmandsz(ctxt, p, a, o, 0, 0)
+func (asmbuf *AsmBuf) asmando(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, a *obj.Addr, o int) {
+	asmbuf.asmandsz(ctxt, cursym, p, a, o, 0, 0)
 }
 
 func bytereg(a *obj.Addr, t *uint8) {
@@ -3122,7 +3214,7 @@ func isax(a *obj.Addr) bool {
 
 func subreg(p *obj.Prog, from int, to int) {
 	if false { /* debug['Q'] */
-		fmt.Printf("\n%v\ts/%v/%v/\n", p, Rconv(from), Rconv(to))
+		fmt.Printf("\n%v\ts/%v/%v/\n", p, rconv(from), rconv(to))
 	}
 
 	if int(p.From.Reg) == from {
@@ -3150,14 +3242,14 @@ func subreg(p *obj.Prog, from int, to int) {
 	}
 }
 
-func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
+func (asmbuf *AsmBuf) mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
 	switch op {
 	case Pm, Pe, Pf2, Pf3:
 		if osize != 1 {
 			if op != Pm {
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 			}
-			ctxt.AsmBuf.Put1(Pm)
+			asmbuf.Put1(Pm)
 			z++
 			op = int(o.op[z])
 			break
@@ -3165,12 +3257,12 @@ func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
 		fallthrough
 
 	default:
-		if ctxt.AsmBuf.Len() == 0 || ctxt.AsmBuf.Last() != Pm {
-			ctxt.AsmBuf.Put1(Pm)
+		if asmbuf.Len() == 0 || asmbuf.Last() != Pm {
+			asmbuf.Put1(Pm)
 		}
 	}
 
-	ctxt.AsmBuf.Put1(byte(op))
+	asmbuf.Put1(byte(op))
 	return z
 }
 
@@ -3191,8 +3283,8 @@ var bpduff2 = []byte{
 // and the opcode byte.
 // For details about vex prefix see:
 // 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
+func (asmbuf *AsmBuf) asmvex(ctxt *obj.Link, rm, v, r *obj.Addr, vex, opcode uint8) {
+	asmbuf.vexflag = 1
 	rexR := 0
 	if r != nil {
 		rexR = regrex[r.Reg] & Rxr
@@ -3212,20 +3304,18 @@ 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.AsmBuf.Put2(0xc5, byte(rexR<<5)^0x80|vexV<<3|vexWLP)
+		asmbuf.Put2(0xc5, byte(rexR<<5)^0x80|vexV<<3|vexWLP)
 	} else {
 		// Must use 3-byte encoding.
-		ctxt.AsmBuf.Put3(0xc4,
+		asmbuf.Put3(0xc4,
 			(byte(rexR|rexX|rexB)<<5)^0xE0|vexM,
 			vexV<<3|vexWLP,
 		)
 	}
-	ctxt.AsmBuf.Put1(opcode)
+	asmbuf.Put1(opcode)
 }
 
-func doasm(ctxt *obj.Link, p *obj.Prog) {
-	ctxt.Curp = p // TODO
-
+func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
 	o := opindex[p.As&obj.AMask]
 
 	if o == nil {
@@ -3235,11 +3325,11 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 	pre := prefixof(ctxt, p, &p.From)
 	if pre != 0 {
-		ctxt.AsmBuf.Put1(byte(pre))
+		asmbuf.Put1(byte(pre))
 	}
 	pre = prefixof(ctxt, p, &p.To)
 	if pre != 0 {
-		ctxt.AsmBuf.Put1(byte(pre))
+		asmbuf.Put1(byte(pre))
 	}
 
 	// TODO(rsc): This special case is for SHRQ $3, AX:DX,
@@ -3304,53 +3394,53 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 		if ycover[ft+int(yt.from)] != 0 && ycover[f3t+int(yt.from3)] != 0 && ycover[tt+int(yt.to)] != 0 {
 			switch o.prefix {
 			case Px1: /* first option valid only in 32-bit mode */
-				if ctxt.Mode == 64 && z == 0 {
+				if ctxt.Arch.Family == sys.AMD64 && z == 0 {
 					z += int(yt.zoffset) + xo
 					continue
 				}
 			case Pq: /* 16 bit escape and opcode escape */
-				ctxt.AsmBuf.Put2(Pe, Pm)
+				asmbuf.Put2(Pe, Pm)
 
 			case Pq3: /* 16 bit escape and opcode escape + REX.W */
-				ctxt.Rexflag |= Pw
-				ctxt.AsmBuf.Put2(Pe, Pm)
+				asmbuf.rexflag |= Pw
+				asmbuf.Put2(Pe, Pm)
 
 			case Pq4: /*  66 0F 38 */
-				ctxt.AsmBuf.Put3(0x66, 0x0F, 0x38)
+				asmbuf.Put3(0x66, 0x0F, 0x38)
 
 			case Pf2, /* xmm opcode escape */
 				Pf3:
-				ctxt.AsmBuf.Put2(o.prefix, Pm)
+				asmbuf.Put2(o.prefix, Pm)
 
 			case Pef3:
-				ctxt.AsmBuf.Put3(Pe, Pf3, Pm)
+				asmbuf.Put3(Pe, Pf3, Pm)
 
 			case Pfw: /* xmm opcode escape + REX.W */
-				ctxt.Rexflag |= Pw
-				ctxt.AsmBuf.Put2(Pf3, Pm)
+				asmbuf.rexflag |= Pw
+				asmbuf.Put2(Pf3, Pm)
 
 			case Pm: /* opcode escape */
-				ctxt.AsmBuf.Put1(Pm)
+				asmbuf.Put1(Pm)
 
 			case Pe: /* 16 bit escape */
-				ctxt.AsmBuf.Put1(Pe)
+				asmbuf.Put1(Pe)
 
 			case Pw: /* 64-bit escape */
-				if p.Mode != 64 {
+				if ctxt.Arch.Family != sys.AMD64 {
 					ctxt.Diag("asmins: illegal 64: %v", p)
 				}
-				ctxt.Rexflag |= Pw
+				asmbuf.rexflag |= Pw
 
 			case Pw8: /* 64-bit escape if z >= 8 */
 				if z >= 8 {
-					if p.Mode != 64 {
+					if ctxt.Arch.Family != sys.AMD64 {
 						ctxt.Diag("asmins: illegal 64: %v", p)
 					}
-					ctxt.Rexflag |= Pw
+					asmbuf.rexflag |= Pw
 				}
 
 			case Pb: /* botch */
-				if p.Mode != 64 && (isbadbyte(&p.From) || isbadbyte(&p.To)) {
+				if ctxt.Arch.Family != sys.AMD64 && (isbadbyte(&p.From) || isbadbyte(&p.To)) {
 					goto bad
 				}
 				// NOTE(rsc): This is probably safe to do always,
@@ -3361,29 +3451,29 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				// in the original obj/i386, and it would encode
 				// (using a valid, shorter form) as 3c 00 if we enabled
 				// the call to bytereg here.
-				if p.Mode == 64 {
+				if ctxt.Arch.Family == sys.AMD64 {
 					bytereg(&p.From, &p.Ft)
 					bytereg(&p.To, &p.Tt)
 				}
 
 			case P32: /* 32 bit but illegal if 64-bit mode */
-				if p.Mode == 64 {
+				if ctxt.Arch.Family == sys.AMD64 {
 					ctxt.Diag("asmins: illegal in 64-bit mode: %v", p)
 				}
 
 			case Py: /* 64-bit only, no prefix */
-				if p.Mode != 64 {
-					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				if ctxt.Arch.Family != sys.AMD64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", ctxt.Arch.RegSize*8, p)
 				}
 
 			case Py1: /* 64-bit only if z < 1, no prefix */
-				if z < 1 && p.Mode != 64 {
-					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				if z < 1 && ctxt.Arch.Family != sys.AMD64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", ctxt.Arch.RegSize*8, p)
 				}
 
 			case Py3: /* 64-bit only if z < 3, no prefix */
-				if z < 3 && p.Mode != 64 {
-					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				if z < 3 && ctxt.Arch.Family != sys.AMD64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", ctxt.Arch.RegSize*8, p)
 				}
 			}
 
@@ -3393,7 +3483,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 			op = int(o.op[z])
 			// In vex case 0x0f is actually VEX_256_F2_0F_WIG
 			if op == 0x0f && o.prefix != Pvex {
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 				z++
 				op = int(o.op[z])
 			}
@@ -3412,7 +3502,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.AsmBuf.Put1(byte(op))
+					asmbuf.Put1(byte(op))
 				}
 
 			case Zlitm_r:
@@ -3421,35 +3511,35 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.AsmBuf.Put1(byte(op))
+					asmbuf.Put1(byte(op))
 				}
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zmb_r:
 				bytereg(&p.From, &p.Ft)
 				fallthrough
 
 			case Zm_r:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.Put1(byte(op))
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zm2_r:
-				ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.Put2(byte(op), o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zm_r_xm:
-				mediaop(ctxt, o, op, int(yt.zoffset), z)
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zm_r_xm_nr:
-				ctxt.Rexflag = 0
-				mediaop(ctxt, o, op, int(yt.zoffset), z)
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.rexflag = 0
+				asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zm_r_i_xm:
-				mediaop(ctxt, o, op, int(yt.zoffset), z)
-				asmand(ctxt, p, &p.From, p.From3)
-				ctxt.AsmBuf.Put1(byte(p.To.Offset))
+				asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmand(ctxt, cursym, p, &p.From, p.From3)
+				asmbuf.Put1(byte(p.To.Offset))
 
 			case Zibm_r, Zibr_m:
 				for {
@@ -3459,103 +3549,103 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.AsmBuf.Put1(byte(op))
+					asmbuf.Put1(byte(op))
 				}
 				if yt.zcase == Zibr_m {
-					asmand(ctxt, p, &p.To, p.From3)
+					asmbuf.asmand(ctxt, cursym, p, &p.To, p.From3)
 				} else {
-					asmand(ctxt, p, p.From3, &p.To)
+					asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To)
 				}
-				ctxt.AsmBuf.Put1(byte(p.From.Offset))
+				asmbuf.Put1(byte(p.From.Offset))
 
 			case Zaut_r:
-				ctxt.AsmBuf.Put1(0x8d) // leal
+				asmbuf.Put1(0x8d) // leal
 				if p.From.Type != obj.TYPE_ADDR {
 					ctxt.Diag("asmins: Zaut sb type ADDR")
 				}
 				p.From.Type = obj.TYPE_MEM
-				asmand(ctxt, p, &p.From, &p.To)
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 				p.From.Type = obj.TYPE_ADDR
 
 			case Zm_o:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmando(ctxt, p, &p.From, int(o.op[z+1]))
+				asmbuf.Put1(byte(op))
+				asmbuf.asmando(ctxt, cursym, p, &p.From, int(o.op[z+1]))
 
 			case Zr_m:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmand(ctxt, p, &p.To, &p.From)
+				asmbuf.Put1(byte(op))
+				asmbuf.asmand(ctxt, cursym, 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)
+				asmbuf.asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 			case Zvex_i_r_v:
-				asmvex(ctxt, p.From3, &p.To, nil, o.op[z], o.op[z+1])
+				asmbuf.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))
+				asmbuf.Put1(byte(o.op[z+2]) | regnum)
+				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))
+				asmbuf.asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
+				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))
+				asmbuf.asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To)
+				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)
+				asmbuf.asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To)
 
 			case Zvex_r_v_rm:
-				asmvex(ctxt, &p.To, p.From3, &p.From, o.op[z], o.op[z+1])
-				asmand(ctxt, p, &p.To, &p.From)
+				asmbuf.asmvex(ctxt, &p.To, p.From3, &p.From, o.op[z], o.op[z+1])
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From)
 
 			case Zr_m_xm:
-				mediaop(ctxt, o, op, int(yt.zoffset), z)
-				asmand(ctxt, p, &p.To, &p.From)
+				asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From)
 
 			case Zr_m_xm_nr:
-				ctxt.Rexflag = 0
-				mediaop(ctxt, o, op, int(yt.zoffset), z)
-				asmand(ctxt, p, &p.To, &p.From)
+				asmbuf.rexflag = 0
+				asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From)
 
 			case Zo_m:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmando(ctxt, p, &p.To, int(o.op[z+1]))
+				asmbuf.Put1(byte(op))
+				asmbuf.asmando(ctxt, cursym, p, &p.To, int(o.op[z+1]))
 
 			case Zcallindreg:
-				r = obj.Addrel(ctxt.Cursym)
+				r = obj.Addrel(cursym)
 				r.Off = int32(p.Pc)
-				r.Type = obj.R_CALLIND
+				r.Type = objabi.R_CALLIND
 				r.Siz = 0
 				fallthrough
 
 			case Zo_m64:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmandsz(ctxt, p, &p.To, int(o.op[z+1]), 0, 1)
+				asmbuf.Put1(byte(op))
+				asmbuf.asmandsz(ctxt, cursym, p, &p.To, int(o.op[z+1]), 0, 1)
 
 			case Zm_ibo:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmando(ctxt, p, &p.From, int(o.op[z+1]))
-				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.To, nil)))
+				asmbuf.Put1(byte(op))
+				asmbuf.asmando(ctxt, cursym, p, &p.From, int(o.op[z+1]))
+				asmbuf.Put1(byte(vaddr(ctxt, p, &p.To, nil)))
 
 			case Zibo_m:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmando(ctxt, p, &p.To, int(o.op[z+1]))
-				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
+				asmbuf.Put1(byte(op))
+				asmbuf.asmando(ctxt, cursym, p, &p.To, int(o.op[z+1]))
+				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.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
+				z = asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmbuf.asmando(ctxt, cursym, p, &p.To, int(o.op[z+1]))
+				asmbuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
 
 			case Z_ib, Zib_:
 				if yt.zcase == Zib_ {
@@ -3563,31 +3653,31 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				} else {
 					a = &p.To
 				}
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 				if p.As == AXABORT {
-					ctxt.AsmBuf.Put1(o.op[z+1])
+					asmbuf.Put1(o.op[z+1])
 				}
-				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, a, nil)))
+				asmbuf.Put1(byte(vaddr(ctxt, p, a, nil)))
 
 			case Zib_rp:
-				ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
-				ctxt.AsmBuf.Put2(byte(op+reg[p.To.Reg]), byte(vaddr(ctxt, p, &p.From, nil)))
+				asmbuf.rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
+				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.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
+				asmbuf.rexflag |= regrex[p.To.Reg] & Rxb
+				asmbuf.Put1(byte(op + reg[p.To.Reg]))
 				if o.prefix == Pe {
 					v = vaddr(ctxt, p, &p.From, nil)
-					ctxt.AsmBuf.PutInt16(int16(v))
+					asmbuf.PutInt16(int16(v))
 				} else {
-					relput4(ctxt, p, &p.From)
+					asmbuf.relput4(ctxt, cursym, p, &p.From)
 				}
 
 			case Zo_iw:
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 				if p.From.Type != obj.TYPE_NONE {
 					v = vaddr(ctxt, p, &p.From, nil)
-					ctxt.AsmBuf.PutInt16(int16(v))
+					asmbuf.PutInt16(int16(v))
 				}
 
 			case Ziq_rp:
@@ -3596,42 +3686,42 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				if l == 0 && rel.Siz != 8 {
 					//p->mark |= 0100;
 					//print("zero: %llux %v\n", v, p);
-					ctxt.Rexflag &^= (0x40 | Rxw)
+					asmbuf.rexflag &^= (0x40 | Rxw)
 
-					ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-					ctxt.AsmBuf.Put1(byte(0xb8 + reg[p.To.Reg]))
+					asmbuf.rexflag |= regrex[p.To.Reg] & Rxb
+					asmbuf.Put1(byte(0xb8 + reg[p.To.Reg]))
 					if rel.Type != 0 {
-						r = obj.Addrel(ctxt.Cursym)
+						r = obj.Addrel(cursym)
 						*r = rel
-						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+						r.Off = int32(p.Pc + int64(asmbuf.Len()))
 					}
 
-					ctxt.AsmBuf.PutInt32(int32(v))
+					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.AsmBuf.Put1(0xc7)
-					asmando(ctxt, p, &p.To, 0)
+					asmbuf.Put1(0xc7)
+					asmbuf.asmando(ctxt, cursym, p, &p.To, 0)
 
-					ctxt.AsmBuf.PutInt32(int32(v)) // need all 8
+					asmbuf.PutInt32(int32(v)) // need all 8
 				} else {
 					//print("all: %llux %v\n", v, p);
-					ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-					ctxt.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
+					asmbuf.rexflag |= regrex[p.To.Reg] & Rxb
+					asmbuf.Put1(byte(op + reg[p.To.Reg]))
 					if rel.Type != 0 {
-						r = obj.Addrel(ctxt.Cursym)
+						r = obj.Addrel(cursym)
 						*r = rel
-						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+						r.Off = int32(p.Pc + int64(asmbuf.Len()))
 					}
 
-					ctxt.AsmBuf.PutInt64(v)
+					asmbuf.PutInt64(v)
 				}
 
 			case Zib_rr:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmand(ctxt, p, &p.To, &p.To)
-				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
+				asmbuf.Put1(byte(op))
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.To)
+				asmbuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
 
 			case Z_il, Zil_:
 				if yt.zcase == Zil_ {
@@ -3639,80 +3729,80 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				} else {
 					a = &p.To
 				}
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 				if o.prefix == Pe {
 					v = vaddr(ctxt, p, a, nil)
-					ctxt.AsmBuf.PutInt16(int16(v))
+					asmbuf.PutInt16(int16(v))
 				} else {
-					relput4(ctxt, p, a)
+					asmbuf.relput4(ctxt, cursym, p, a)
 				}
 
 			case Zm_ilo, Zilo_m:
-				ctxt.AsmBuf.Put1(byte(op))
+				asmbuf.Put1(byte(op))
 				if yt.zcase == Zilo_m {
 					a = &p.From
-					asmando(ctxt, p, &p.To, int(o.op[z+1]))
+					asmbuf.asmando(ctxt, cursym, p, &p.To, int(o.op[z+1]))
 				} else {
 					a = &p.To
-					asmando(ctxt, p, &p.From, int(o.op[z+1]))
+					asmbuf.asmando(ctxt, cursym, p, &p.From, int(o.op[z+1]))
 				}
 
 				if o.prefix == Pe {
 					v = vaddr(ctxt, p, a, nil)
-					ctxt.AsmBuf.PutInt16(int16(v))
+					asmbuf.PutInt16(int16(v))
 				} else {
-					relput4(ctxt, p, a)
+					asmbuf.relput4(ctxt, cursym, p, a)
 				}
 
 			case Zil_rr:
-				ctxt.AsmBuf.Put1(byte(op))
-				asmand(ctxt, p, &p.To, &p.To)
+				asmbuf.Put1(byte(op))
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.To)
 				if o.prefix == Pe {
 					v = vaddr(ctxt, p, &p.From, nil)
-					ctxt.AsmBuf.PutInt16(int16(v))
+					asmbuf.PutInt16(int16(v))
 				} else {
-					relput4(ctxt, p, &p.From)
+					asmbuf.relput4(ctxt, cursym, p, &p.From)
 				}
 
 			case Z_rp:
-				ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
-				ctxt.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
+				asmbuf.rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
+				asmbuf.Put1(byte(op + reg[p.To.Reg]))
 
 			case Zrp_:
-				ctxt.Rexflag |= regrex[p.From.Reg] & (Rxb | 0x40)
-				ctxt.AsmBuf.Put1(byte(op + reg[p.From.Reg]))
+				asmbuf.rexflag |= regrex[p.From.Reg] & (Rxb | 0x40)
+				asmbuf.Put1(byte(op + reg[p.From.Reg]))
 
 			case Zclr:
-				ctxt.Rexflag &^= Pw
-				ctxt.AsmBuf.Put1(byte(op))
-				asmand(ctxt, p, &p.To, &p.To)
+				asmbuf.rexflag &^= Pw
+				asmbuf.Put1(byte(op))
+				asmbuf.asmand(ctxt, cursym, p, &p.To, &p.To)
 
 			case Zcallcon, Zjmpcon:
 				if yt.zcase == Zcallcon {
-					ctxt.AsmBuf.Put1(byte(op))
+					asmbuf.Put1(byte(op))
 				} else {
-					ctxt.AsmBuf.Put1(o.op[z+1])
+					asmbuf.Put1(o.op[z+1])
 				}
-				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
-				r.Type = obj.R_PCREL
+				r = obj.Addrel(cursym)
+				r.Off = int32(p.Pc + int64(asmbuf.Len()))
+				r.Type = objabi.R_PCREL
 				r.Siz = 4
 				r.Add = p.To.Offset
-				ctxt.AsmBuf.PutInt32(0)
+				asmbuf.PutInt32(0)
 
 			case Zcallind:
-				ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
-				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
-				if p.Mode == 64 {
-					r.Type = obj.R_PCREL
+				asmbuf.Put2(byte(op), o.op[z+1])
+				r = obj.Addrel(cursym)
+				r.Off = int32(p.Pc + int64(asmbuf.Len()))
+				if ctxt.Arch.Family == sys.AMD64 {
+					r.Type = objabi.R_PCREL
 				} else {
-					r.Type = obj.R_ADDR
+					r.Type = objabi.R_ADDR
 				}
 				r.Siz = 4
 				r.Add = p.To.Offset
 				r.Sym = p.To.Sym
-				ctxt.AsmBuf.PutInt32(0)
+				asmbuf.PutInt32(0)
 
 			case Zcall, Zcallduff:
 				if p.To.Sym == nil {
@@ -3724,7 +3814,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					ctxt.Diag("directly calling duff when dynamically linking Go")
 				}
 
-				if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 {
+				if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && ctxt.Arch.Family == sys.AMD64 {
 					// 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
@@ -3732,27 +3822,27 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					// whole point of obj.Framepointer_enabled).
 					// MOVQ BP, -16(SP)
 					// LEAQ -16(SP), BP
-					ctxt.AsmBuf.Put(bpduff1)
+					asmbuf.Put(bpduff1)
 				}
-				ctxt.AsmBuf.Put1(byte(op))
-				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+				asmbuf.Put1(byte(op))
+				r = obj.Addrel(cursym)
+				r.Off = int32(p.Pc + int64(asmbuf.Len()))
 				r.Sym = p.To.Sym
 				r.Add = p.To.Offset
-				r.Type = obj.R_CALL
+				r.Type = objabi.R_CALL
 				r.Siz = 4
-				ctxt.AsmBuf.PutInt32(0)
+				asmbuf.PutInt32(0)
 
-				if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 {
+				if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && ctxt.Arch.Family == sys.AMD64 {
 					// Pop BP pushed above.
 					// MOVQ 0(BP), BP
-					ctxt.AsmBuf.Put(bpduff2)
+					asmbuf.Put(bpduff2)
 				}
 
 			// TODO: jump across functions needs reloc
 			case Zbr, Zjmp, Zloop:
 				if p.As == AXBEGIN {
-					ctxt.AsmBuf.Put1(byte(op))
+					asmbuf.Put1(byte(op))
 				}
 				if p.To.Sym != nil {
 					if yt.zcase != Zjmp {
@@ -3760,13 +3850,13 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						log.Fatalf("bad code")
 					}
 
-					ctxt.AsmBuf.Put1(o.op[z+1])
-					r = obj.Addrel(ctxt.Cursym)
-					r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+					asmbuf.Put1(o.op[z+1])
+					r = obj.Addrel(cursym)
+					r.Off = int32(p.Pc + int64(asmbuf.Len()))
 					r.Sym = p.To.Sym
-					r.Type = obj.R_PCREL
+					r.Type = objabi.R_PCREL
 					r.Siz = 4
-					ctxt.AsmBuf.PutInt32(0)
+					asmbuf.PutInt32(0)
 					break
 				}
 
@@ -3785,9 +3875,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.AsmBuf.Put1(0x67)
+							asmbuf.Put1(0x67)
 						}
-						ctxt.AsmBuf.Put2(byte(op), byte(v))
+						asmbuf.Put2(byte(op), byte(v))
 					} else if yt.zcase == Zloop {
 						ctxt.Diag("loop too far: %v", p)
 					} else {
@@ -3796,12 +3886,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							v--
 						}
 						if yt.zcase == Zbr {
-							ctxt.AsmBuf.Put1(0x0f)
+							asmbuf.Put1(0x0f)
 							v--
 						}
 
-						ctxt.AsmBuf.Put1(o.op[z+1])
-						ctxt.AsmBuf.PutInt32(int32(v))
+						asmbuf.Put1(o.op[z+1])
+						asmbuf.PutInt32(int32(v))
 					}
 
 					break
@@ -3813,17 +3903,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.AsmBuf.Put1(0x67)
+						asmbuf.Put1(0x67)
 					}
-					ctxt.AsmBuf.Put2(byte(op), 0)
+					asmbuf.Put2(byte(op), 0)
 				} else if yt.zcase == Zloop {
 					ctxt.Diag("loop too far: %v", p)
 				} else {
 					if yt.zcase == Zbr {
-						ctxt.AsmBuf.Put1(0x0f)
+						asmbuf.Put1(0x0f)
 					}
-					ctxt.AsmBuf.Put1(o.op[z+1])
-					ctxt.AsmBuf.PutInt32(0)
+					asmbuf.Put1(o.op[z+1])
+					asmbuf.PutInt32(0)
 				}
 
 				break
@@ -3851,18 +3941,18 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				v = vaddr(ctxt, p, &p.From, &rel)
 				if rel.Siz != 0 {
 					rel.Siz = uint8(op)
-					r = obj.Addrel(ctxt.Cursym)
+					r = obj.Addrel(cursym)
 					*r = rel
-					r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
+					r.Off = int32(p.Pc + int64(asmbuf.Len()))
 				}
 
-				ctxt.AsmBuf.Put1(byte(v))
+				asmbuf.Put1(byte(v))
 				if op > 1 {
-					ctxt.AsmBuf.Put1(byte(v >> 8))
+					asmbuf.Put1(byte(v >> 8))
 					if op > 2 {
-						ctxt.AsmBuf.PutInt16(int16(v >> 16))
+						asmbuf.PutInt16(int16(v >> 16))
 						if op > 4 {
-							ctxt.AsmBuf.PutInt32(int32(v >> 32))
+							asmbuf.PutInt32(int32(v >> 32))
 						}
 					}
 				}
@@ -3884,62 +3974,62 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 				case 0: /* lit */
 					for z = 0; t[z] != E; z++ {
-						ctxt.AsmBuf.Put1(t[z])
+						asmbuf.Put1(t[z])
 					}
 
 				case 1: /* r,m */
-					ctxt.AsmBuf.Put1(t[0])
-					asmando(ctxt, p, &p.To, int(t[1]))
+					asmbuf.Put1(t[0])
+					asmbuf.asmando(ctxt, cursym, p, &p.To, int(t[1]))
 
 				case 2: /* m,r */
-					ctxt.AsmBuf.Put1(t[0])
-					asmando(ctxt, p, &p.From, int(t[1]))
+					asmbuf.Put1(t[0])
+					asmbuf.asmando(ctxt, cursym, p, &p.From, int(t[1]))
 
 				case 3: /* r,m - 2op */
-					ctxt.AsmBuf.Put2(t[0], t[1])
-					asmando(ctxt, p, &p.To, int(t[2]))
-					ctxt.Rexflag |= regrex[p.From.Reg] & (Rxr | 0x40)
+					asmbuf.Put2(t[0], t[1])
+					asmbuf.asmando(ctxt, cursym, p, &p.To, int(t[2]))
+					asmbuf.rexflag |= regrex[p.From.Reg] & (Rxr | 0x40)
 
 				case 4: /* m,r - 2op */
-					ctxt.AsmBuf.Put2(t[0], t[1])
-					asmando(ctxt, p, &p.From, int(t[2]))
-					ctxt.Rexflag |= regrex[p.To.Reg] & (Rxr | 0x40)
+					asmbuf.Put2(t[0], t[1])
+					asmbuf.asmando(ctxt, cursym, p, &p.From, int(t[2]))
+					asmbuf.rexflag |= regrex[p.To.Reg] & (Rxr | 0x40)
 
 				case 5: /* load full pointer, trash heap */
 					if t[0] != 0 {
-						ctxt.AsmBuf.Put1(t[0])
+						asmbuf.Put1(t[0])
 					}
 					switch p.To.Index {
 					default:
 						goto bad
 
 					case REG_DS:
-						ctxt.AsmBuf.Put1(0xc5)
+						asmbuf.Put1(0xc5)
 
 					case REG_SS:
-						ctxt.AsmBuf.Put2(0x0f, 0xb2)
+						asmbuf.Put2(0x0f, 0xb2)
 
 					case REG_ES:
-						ctxt.AsmBuf.Put1(0xc4)
+						asmbuf.Put1(0xc4)
 
 					case REG_FS:
-						ctxt.AsmBuf.Put2(0x0f, 0xb4)
+						asmbuf.Put2(0x0f, 0xb4)
 
 					case REG_GS:
-						ctxt.AsmBuf.Put2(0x0f, 0xb5)
+						asmbuf.Put2(0x0f, 0xb5)
 					}
 
-					asmand(ctxt, p, &p.From, &p.To)
+					asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
 
 				case 6: /* double shift */
 					if t[0] == Pw {
-						if p.Mode != 64 {
+						if ctxt.Arch.Family != sys.AMD64 {
 							ctxt.Diag("asmins: illegal 64: %v", p)
 						}
-						ctxt.Rexflag |= Pw
+						asmbuf.rexflag |= Pw
 						t = t[1:]
 					} else if t[0] == Pe {
-						ctxt.AsmBuf.Put1(Pe)
+						asmbuf.Put1(Pe)
 						t = t[1:]
 					}
 
@@ -3948,9 +4038,9 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						goto bad
 
 					case obj.TYPE_CONST:
-						ctxt.AsmBuf.Put2(0x0f, t[0])
-						asmandsz(ctxt, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
-						ctxt.AsmBuf.Put1(byte(p.From.Offset))
+						asmbuf.Put2(0x0f, t[0])
+						asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
+						asmbuf.Put1(byte(p.From.Offset))
 
 					case obj.TYPE_REG:
 						switch p.From.Reg {
@@ -3958,8 +4048,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							goto bad
 
 						case REG_CL, REG_CX:
-							ctxt.AsmBuf.Put2(0x0f, t[1])
-							asmandsz(ctxt, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
+							asmbuf.Put2(0x0f, t[1])
+							asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
 						}
 					}
 
@@ -3968,11 +4058,11 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				// register to access the actual TLS variables. Systems that allow direct TLS access
 				// are handled in prefixof above and should not be listed here.
 				case 7: /* mov tls, r */
-					if p.Mode == 64 && p.As != AMOVQ || p.Mode == 32 && p.As != AMOVL {
+					if ctxt.Arch.Family == sys.AMD64 && p.As != AMOVQ || ctxt.Arch.Family == sys.I386 && p.As != AMOVL {
 						ctxt.Diag("invalid load of TLS: %v", p)
 					}
 
-					if p.Mode == 32 {
+					if ctxt.Arch.Family == sys.I386 {
 						// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
 						// where you load the TLS base register into a register and then index off that
 						// register to access the actual TLS variables. Systems that allow direct TLS access
@@ -3981,8 +4071,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						default:
 							log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
 
-						case obj.Hlinux,
-							obj.Hnacl:
+						case objabi.Hlinux,
+							objabi.Hnacl:
 							if ctxt.Flag_shared {
 								// Note that this is not generating the same insns as the other cases.
 								//     MOV TLS, dst
@@ -3996,21 +4086,21 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 								// is g, which we can't check here, but will when we assemble the second
 								// instruction.
 								dst := p.To.Reg
-								ctxt.AsmBuf.Put1(0xe8)
-								r = obj.Addrel(ctxt.Cursym)
-								r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
-								r.Type = obj.R_CALL
+								asmbuf.Put1(0xe8)
+								r = obj.Addrel(cursym)
+								r.Off = int32(p.Pc + int64(asmbuf.Len()))
+								r.Type = objabi.R_CALL
 								r.Siz = 4
-								r.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk."+strings.ToLower(Rconv(int(dst))), 0)
-								ctxt.AsmBuf.PutInt32(0)
+								r.Sym = ctxt.Lookup("__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst))))
+								asmbuf.PutInt32(0)
 
-								ctxt.AsmBuf.Put2(0x8B, byte(2<<6|reg[dst]|(reg[dst]<<3)))
-								r = obj.Addrel(ctxt.Cursym)
-								r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
-								r.Type = obj.R_TLS_IE
+								asmbuf.Put2(0x8B, byte(2<<6|reg[dst]|(reg[dst]<<3)))
+								r = obj.Addrel(cursym)
+								r.Off = int32(p.Pc + int64(asmbuf.Len()))
+								r.Type = objabi.R_TLS_IE
 								r.Siz = 4
 								r.Add = 2
-								ctxt.AsmBuf.PutInt32(0)
+								asmbuf.PutInt32(0)
 							} else {
 								// ELF TLS base is 0(GS).
 								pp.From = p.From
@@ -4020,24 +4110,21 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 								pp.From.Offset = 0
 								pp.From.Index = REG_NONE
 								pp.From.Scale = 0
-								ctxt.AsmBuf.Put2(0x65, // GS
+								asmbuf.Put2(0x65, // GS
 									0x8B)
-								asmand(ctxt, p, &pp.From, &p.To)
-							}
-						case obj.Hplan9:
-							if ctxt.Plan9privates == nil {
-								ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
+								asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 							}
+						case objabi.Hplan9:
 							pp.From = obj.Addr{}
 							pp.From.Type = obj.TYPE_MEM
 							pp.From.Name = obj.NAME_EXTERN
-							pp.From.Sym = ctxt.Plan9privates
+							pp.From.Sym = plan9privates
 							pp.From.Offset = 0
 							pp.From.Index = REG_NONE
-							ctxt.AsmBuf.Put1(0x8B)
-							asmand(ctxt, p, &pp.From, &p.To)
+							asmbuf.Put1(0x8B)
+							asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 
-						case obj.Hwindows, obj.Hwindowsgui:
+						case objabi.Hwindows:
 							// Windows TLS base is always 0x14(FS).
 							pp.From = p.From
 
@@ -4046,9 +4133,9 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							pp.From.Offset = 0x14
 							pp.From.Index = REG_NONE
 							pp.From.Scale = 0
-							ctxt.AsmBuf.Put2(0x64, // FS
+							asmbuf.Put2(0x64, // FS
 								0x8B)
-							asmand(ctxt, p, &pp.From, &p.To)
+							asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 						}
 						break
 					}
@@ -4057,7 +4144,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					default:
 						log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
 
-					case obj.Hlinux:
+					case objabi.Hlinux:
 						if !ctxt.Flag_shared {
 							log.Fatalf("unknown TLS base location for linux without -shared")
 						}
@@ -4070,31 +4157,28 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						// and a R_TLS_IE reloc. This all assumes the only tls variable we access
 						// is g, which we can't check here, but will when we assemble the second
 						// instruction.
-						ctxt.Rexflag = Pw | (regrex[p.To.Reg] & Rxr)
+						asmbuf.rexflag = Pw | (regrex[p.To.Reg] & Rxr)
 
-						ctxt.AsmBuf.Put2(0x8B, byte(0x05|(reg[p.To.Reg]<<3)))
-						r = obj.Addrel(ctxt.Cursym)
-						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
-						r.Type = obj.R_TLS_IE
+						asmbuf.Put2(0x8B, byte(0x05|(reg[p.To.Reg]<<3)))
+						r = obj.Addrel(cursym)
+						r.Off = int32(p.Pc + int64(asmbuf.Len()))
+						r.Type = objabi.R_TLS_IE
 						r.Siz = 4
 						r.Add = -4
-						ctxt.AsmBuf.PutInt32(0)
+						asmbuf.PutInt32(0)
 
-					case obj.Hplan9:
-						if ctxt.Plan9privates == nil {
-							ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
-						}
+					case objabi.Hplan9:
 						pp.From = obj.Addr{}
 						pp.From.Type = obj.TYPE_MEM
 						pp.From.Name = obj.NAME_EXTERN
-						pp.From.Sym = ctxt.Plan9privates
+						pp.From.Sym = plan9privates
 						pp.From.Offset = 0
 						pp.From.Index = REG_NONE
-						ctxt.Rexflag |= Pw
-						ctxt.AsmBuf.Put1(0x8B)
-						asmand(ctxt, p, &pp.From, &p.To)
+						asmbuf.rexflag |= Pw
+						asmbuf.Put1(0x8B)
+						asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 
-					case obj.Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
+					case objabi.Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
 						// TLS base is 0(FS).
 						pp.From = p.From
 
@@ -4104,12 +4188,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						pp.From.Offset = 0
 						pp.From.Index = REG_NONE
 						pp.From.Scale = 0
-						ctxt.Rexflag |= Pw
-						ctxt.AsmBuf.Put2(0x64, // FS
+						asmbuf.rexflag |= Pw
+						asmbuf.Put2(0x64, // FS
 							0x8B)
-						asmand(ctxt, p, &pp.From, &p.To)
+						asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 
-					case obj.Hwindows, obj.Hwindowsgui:
+					case objabi.Hwindows:
 						// Windows TLS base is always 0x28(GS).
 						pp.From = p.From
 
@@ -4119,10 +4203,10 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						pp.From.Offset = 0x28
 						pp.From.Index = REG_NONE
 						pp.From.Scale = 0
-						ctxt.Rexflag |= Pw
-						ctxt.AsmBuf.Put2(0x65, // GS
+						asmbuf.rexflag |= Pw
+						asmbuf.Put2(0x65, // GS
 							0x8B)
-						asmand(ctxt, p, &pp.From, &p.To)
+						asmbuf.asmand(ctxt, cursym, p, &pp.From, &p.To)
 					}
 				}
 				return
@@ -4132,7 +4216,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 	goto bad
 
 bad:
-	if p.Mode != 64 {
+	if ctxt.Arch.Family != sys.AMD64 {
 		/*
 		 * here, the assembly has failed.
 		 * if its a byte instruction that has
@@ -4149,20 +4233,20 @@ bad:
 		if p.From.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
 			// TODO(rsc): Use this code for x86-64 too. It has bug fixes not present in the amd64 code base.
 			// For now, different to keep bit-for-bit compatibility.
-			if p.Mode == 32 {
+			if ctxt.Arch.Family == sys.I386 {
 				breg := byteswapreg(ctxt, &p.To)
 				if breg != REG_AX {
-					ctxt.AsmBuf.Put1(0x87) // xchg lhs,bx
-					asmando(ctxt, p, &p.From, reg[breg])
+					asmbuf.Put1(0x87) // xchg lhs,bx
+					asmbuf.asmando(ctxt, cursym, p, &p.From, reg[breg])
 					subreg(&pp, z, breg)
-					doasm(ctxt, &pp)
-					ctxt.AsmBuf.Put1(0x87) // xchg lhs,bx
-					asmando(ctxt, p, &p.From, reg[breg])
+					asmbuf.doasm(ctxt, cursym, &pp)
+					asmbuf.Put1(0x87) // xchg lhs,bx
+					asmbuf.asmando(ctxt, cursym, p, &p.From, reg[breg])
 				} else {
-					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
+					asmbuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 					subreg(&pp, z, REG_AX)
-					doasm(ctxt, &pp)
-					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
+					asmbuf.doasm(ctxt, cursym, &pp)
+					asmbuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 				}
 				return
 			}
@@ -4170,17 +4254,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.AsmBuf.Put1(0x87) // xchg lhs,bx
-				asmando(ctxt, p, &p.From, reg[REG_BX])
+				asmbuf.Put1(0x87) // xchg lhs,bx
+				asmbuf.asmando(ctxt, cursym, p, &p.From, reg[REG_BX])
 				subreg(&pp, z, REG_BX)
-				doasm(ctxt, &pp)
-				ctxt.AsmBuf.Put1(0x87) // xchg lhs,bx
-				asmando(ctxt, p, &p.From, reg[REG_BX])
+				asmbuf.doasm(ctxt, cursym, &pp)
+				asmbuf.Put1(0x87) // xchg lhs,bx
+				asmbuf.asmando(ctxt, cursym, p, &p.From, reg[REG_BX])
 			} else {
-				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
+				asmbuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 				subreg(&pp, z, REG_AX)
-				doasm(ctxt, &pp)
-				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
+				asmbuf.doasm(ctxt, cursym, &pp)
+				asmbuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 			}
 			return
 		}
@@ -4189,36 +4273,36 @@ bad:
 		if p.To.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
 			// TODO(rsc): Use this code for x86-64 too. It has bug fixes not present in the amd64 code base.
 			// For now, different to keep bit-for-bit compatibility.
-			if p.Mode == 32 {
+			if ctxt.Arch.Family == sys.I386 {
 				breg := byteswapreg(ctxt, &p.From)
 				if breg != REG_AX {
-					ctxt.AsmBuf.Put1(0x87) //xchg rhs,bx
-					asmando(ctxt, p, &p.To, reg[breg])
+					asmbuf.Put1(0x87) //xchg rhs,bx
+					asmbuf.asmando(ctxt, cursym, p, &p.To, reg[breg])
 					subreg(&pp, z, breg)
-					doasm(ctxt, &pp)
-					ctxt.AsmBuf.Put1(0x87) // xchg rhs,bx
-					asmando(ctxt, p, &p.To, reg[breg])
+					asmbuf.doasm(ctxt, cursym, &pp)
+					asmbuf.Put1(0x87) // xchg rhs,bx
+					asmbuf.asmando(ctxt, cursym, p, &p.To, reg[breg])
 				} else {
-					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
+					asmbuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 					subreg(&pp, z, REG_AX)
-					doasm(ctxt, &pp)
-					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
+					asmbuf.doasm(ctxt, cursym, &pp)
+					asmbuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 				}
 				return
 			}
 
 			if isax(&p.From) {
-				ctxt.AsmBuf.Put1(0x87) // xchg rhs,bx
-				asmando(ctxt, p, &p.To, reg[REG_BX])
+				asmbuf.Put1(0x87) // xchg rhs,bx
+				asmbuf.asmando(ctxt, cursym, p, &p.To, reg[REG_BX])
 				subreg(&pp, z, REG_BX)
-				doasm(ctxt, &pp)
-				ctxt.AsmBuf.Put1(0x87) // xchg rhs,bx
-				asmando(ctxt, p, &p.To, reg[REG_BX])
+				asmbuf.doasm(ctxt, cursym, &pp)
+				asmbuf.Put1(0x87) // xchg rhs,bx
+				asmbuf.asmando(ctxt, cursym, p, &p.To, reg[REG_BX])
 			} else {
-				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
+				asmbuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 				subreg(&pp, z, REG_AX)
-				doasm(ctxt, &pp)
-				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
+				asmbuf.doasm(ctxt, cursym, &pp)
+				asmbuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 			}
 			return
 		}
@@ -4234,68 +4318,53 @@ bad:
 // If a is empty, it returns BX to account for MULB-like instructions
 // that might use DX and AX.
 func byteswapreg(ctxt *obj.Link, a *obj.Addr) int {
-	cand := 1
-	canc := cand
-	canb := canc
-	cana := canb
-
+	cana, canb, canc, cand := true, true, true, true
 	if a.Type == obj.TYPE_NONE {
-		cand = 0
-		cana = cand
+		cana, cand = false, false
 	}
 
 	if a.Type == obj.TYPE_REG || ((a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Name == obj.NAME_NONE) {
 		switch a.Reg {
 		case REG_NONE:
-			cand = 0
-			cana = cand
-
+			cana, cand = false, false
 		case REG_AX, REG_AL, REG_AH:
-			cana = 0
-
+			cana = false
 		case REG_BX, REG_BL, REG_BH:
-			canb = 0
-
+			canb = false
 		case REG_CX, REG_CL, REG_CH:
-			canc = 0
-
+			canc = false
 		case REG_DX, REG_DL, REG_DH:
-			cand = 0
+			cand = false
 		}
 	}
 
 	if a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR {
 		switch a.Index {
 		case REG_AX:
-			cana = 0
-
+			cana = false
 		case REG_BX:
-			canb = 0
-
+			canb = false
 		case REG_CX:
-			canc = 0
-
+			canc = false
 		case REG_DX:
-			cand = 0
+			cand = false
 		}
 	}
 
-	if cana != 0 {
+	switch {
+	case cana:
 		return REG_AX
-	}
-	if canb != 0 {
+	case canb:
 		return REG_BX
-	}
-	if canc != 0 {
+	case canc:
 		return REG_CX
-	}
-	if cand != 0 {
+	case cand:
 		return REG_DX
+	default:
+		ctxt.Diag("impossible byte register")
+		log.Fatalf("bad code")
+		return 0
 	}
-
-	ctxt.Diag("impossible byte register")
-	log.Fatalf("bad code")
-	return 0
 }
 
 func isbadbyte(a *obj.Addr) bool {
@@ -4353,84 +4422,83 @@ var naclstos = []uint8{
 	0x3f, // LEAQ (R15)(DI*1), DI
 }
 
-func nacltrunc(ctxt *obj.Link, reg int) {
+func (asmbuf *AsmBuf) nacltrunc(ctxt *obj.Link, reg int) {
 	if reg >= REG_R8 {
-		ctxt.AsmBuf.Put1(0x45)
+		asmbuf.Put1(0x45)
 	}
 	reg = (reg - REG_AX) & 7
-	ctxt.AsmBuf.Put2(0x89, byte(3<<6|reg<<3|reg))
+	asmbuf.Put2(0x89, byte(3<<6|reg<<3|reg))
 }
 
-func asmins(ctxt *obj.Link, p *obj.Prog) {
-	ctxt.AsmBuf.Reset()
-	ctxt.Asmode = int(p.Mode)
+func (asmbuf *AsmBuf) asmins(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
+	asmbuf.Reset()
 
-	if ctxt.Headtype == obj.Hnacl && p.Mode == 32 {
+	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.I386 {
 		switch p.As {
 		case obj.ARET:
-			ctxt.AsmBuf.Put(naclret8)
+			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.AsmBuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
+				asmbuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
 			}
 
 		case AINT:
-			ctxt.AsmBuf.Put1(0xf4)
+			asmbuf.Put1(0xf4)
 			return
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
+	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 		if p.As == AREP {
-			ctxt.Rep++
+			asmbuf.rep++
 			return
 		}
 
 		if p.As == AREPN {
-			ctxt.Repn++
+			asmbuf.repn++
 			return
 		}
 
 		if p.As == ALOCK {
-			ctxt.Lock++
+			asmbuf.lock = true
 			return
 		}
 
 		if p.As != ALEAQ && p.As != ALEAL {
 			if p.From.Index != REG_NONE && p.From.Scale > 0 {
-				nacltrunc(ctxt, int(p.From.Index))
+				asmbuf.nacltrunc(ctxt, int(p.From.Index))
 			}
 			if p.To.Index != REG_NONE && p.To.Scale > 0 {
-				nacltrunc(ctxt, int(p.To.Index))
+				asmbuf.nacltrunc(ctxt, int(p.To.Index))
 			}
 		}
 
 		switch p.As {
 		case obj.ARET:
-			ctxt.AsmBuf.Put(naclret)
+			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.AsmBuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
+				asmbuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
 				// ADDQ R15, reg
-				ctxt.AsmBuf.Put3(0x4c, 0x01, byte(0xf8|(p.To.Reg-REG_AX)))
+				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.AsmBuf.Put4(0x41, 0x83, byte(0xe0|(p.To.Reg-REG_R8)), 0xe0)
+				asmbuf.Put4(0x41, 0x83, byte(0xe0|(p.To.Reg-REG_R8)), 0xe0)
 				// ADDQ R15, reg
-				ctxt.AsmBuf.Put3(0x4d, 0x01, byte(0xf8|(p.To.Reg-REG_R8)))
+				asmbuf.Put3(0x4d, 0x01, byte(0xf8|(p.To.Reg-REG_R8)))
 			}
 
 		case AINT:
-			ctxt.AsmBuf.Put1(0xf4)
+			asmbuf.Put1(0xf4)
 			return
 
 		case ASCASB,
@@ -4441,34 +4509,33 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 			ASTOSW,
 			ASTOSL,
 			ASTOSQ:
-			ctxt.AsmBuf.Put(naclstos)
+			asmbuf.Put(naclstos)
 
 		case AMOVSB, AMOVSW, AMOVSL, AMOVSQ:
-			ctxt.AsmBuf.Put(naclmovs)
+			asmbuf.Put(naclmovs)
 		}
 
-		if ctxt.Rep != 0 {
-			ctxt.AsmBuf.Put1(0xf3)
-			ctxt.Rep = 0
+		if asmbuf.rep != 0 {
+			asmbuf.Put1(0xf3)
+			asmbuf.rep = 0
 		}
 
-		if ctxt.Repn != 0 {
-			ctxt.AsmBuf.Put1(0xf2)
-			ctxt.Repn = 0
+		if asmbuf.repn != 0 {
+			asmbuf.Put1(0xf2)
+			asmbuf.repn = 0
 		}
 
-		if ctxt.Lock != 0 {
-			ctxt.AsmBuf.Put1(0xf0)
-			ctxt.Lock = 0
+		if asmbuf.lock {
+			asmbuf.Put1(0xf0)
+			asmbuf.lock = false
 		}
 	}
 
-	ctxt.Rexflag = 0
-	ctxt.Vexflag = 0
-	mark := ctxt.AsmBuf.Len()
-	ctxt.Asmode = int(p.Mode)
-	doasm(ctxt, p)
-	if ctxt.Rexflag != 0 && ctxt.Vexflag == 0 {
+	asmbuf.rexflag = 0
+	asmbuf.vexflag = 0
+	mark := asmbuf.Len()
+	asmbuf.doasm(ctxt, cursym, p)
+	if asmbuf.rexflag != 0 && asmbuf.vexflag == 0 {
 		/*
 		 * as befits the whole approach of the architecture,
 		 * the rex prefix must appear before the first opcode byte
@@ -4476,31 +4543,31 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 		 * before the 0f opcode escape!), or it might be ignored.
 		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
 		 */
-		if p.Mode != 64 {
-			ctxt.Diag("asmins: illegal in mode %d: %v (%d %d)", p.Mode, p, p.Ft, p.Tt)
+		if ctxt.Arch.Family != sys.AMD64 {
+			ctxt.Diag("asmins: illegal in mode %d: %v (%d %d)", ctxt.Arch.RegSize*8, p, p.Ft, p.Tt)
 		}
-		n := ctxt.AsmBuf.Len()
+		n := asmbuf.Len()
 		var np int
 		for np = mark; np < n; np++ {
-			c := ctxt.AsmBuf.Peek(np)
+			c := asmbuf.At(np)
 			if c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26 {
 				break
 			}
 		}
-		ctxt.AsmBuf.Insert(np, byte(0x40|ctxt.Rexflag))
+		asmbuf.Insert(np, byte(0x40|asmbuf.rexflag))
 	}
 
-	n := ctxt.AsmBuf.Len()
-	for i := len(ctxt.Cursym.R) - 1; i >= 0; i-- {
-		r := &ctxt.Cursym.R[i]
+	n := asmbuf.Len()
+	for i := len(cursym.R) - 1; i >= 0; i-- {
+		r := &cursym.R[i]
 		if int64(r.Off) < p.Pc {
 			break
 		}
-		if ctxt.Rexflag != 0 {
+		if asmbuf.rexflag != 0 && asmbuf.vexflag == 0 {
 			r.Off++
 		}
-		if r.Type == obj.R_PCREL {
-			if p.Mode == 64 || p.As == obj.AJMP || p.As == obj.ACALL {
+		if r.Type == objabi.R_PCREL {
+			if ctxt.Arch.Family == sys.AMD64 || p.As == obj.AJMP || p.As == obj.ACALL {
 				// PC-relative addressing is relative to the end of the instruction,
 				// but the relocations applied by the linker are relative to the end
 				// of the relocation. Because immediate instruction
@@ -4509,7 +4576,7 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 				// adjust addend so that linker can keep relocating relative to the
 				// end of the relocation.
 				r.Add -= p.Pc + int64(n) - (int64(r.Off) + int64(r.Siz))
-			} else if p.Mode == 32 {
+			} else if ctxt.Arch.Family == sys.I386 {
 				// On 386 PC-relative addressing (for non-call/jmp instructions)
 				// assumes that the previous instruction loaded the PC of the end
 				// of that instruction into CX, so the adjustment is relative to
@@ -4517,19 +4584,19 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 				r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
 			}
 		}
-		if r.Type == obj.R_GOTPCREL && p.Mode == 32 {
+		if r.Type == objabi.R_GOTPCREL && ctxt.Arch.Family == sys.I386 {
 			// On 386, R_GOTPCREL makes the same assumptions as R_PCREL.
 			r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
 		}
 
 	}
 
-	if p.Mode == 64 && ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
+	if ctxt.Arch.Family == sys.AMD64 && ctxt.Headtype == objabi.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
 		switch p.To.Reg {
 		case REG_SP:
-			ctxt.AsmBuf.Put(naclspfix)
+			asmbuf.Put(naclspfix)
 		case REG_BP:
-			ctxt.AsmBuf.Put(naclbpfix)
+			asmbuf.Put(naclbpfix)
 		}
 	}
 }
diff --git a/src/cmd/internal/obj/x86/issue19518_test.go b/src/cmd/internal/obj/x86/issue19518_test.go
new file mode 100644
index 0000000..2fe227e
--- /dev/null
+++ b/src/cmd/internal/obj/x86/issue19518_test.go
@@ -0,0 +1,110 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x86_test
+
+import (
+	"bytes"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+const asmData = `
+GLOBL zeros<>(SB),8,$64
+TEXT ·testASM(SB),4,$0
+VMOVDQU zeros<>(SB), Y8 // PC relative relocation is off by 1, for Y8-15
+RET
+`
+
+const goData = `
+package main
+
+func testASM()
+
+func main() {
+	testASM()
+}
+`
+
+func objdumpOutput(t *testing.T) []byte {
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpdir, err := ioutil.TempDir("", "19518")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+	tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer tmpfile.Close()
+	_, err = tmpfile.WriteString(asmData)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpfile2, err := os.Create(filepath.Join(tmpdir, "input.go"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer tmpfile2.Close()
+	_, err = tmpfile2.WriteString(goData)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.Chdir(tmpdir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cmd := exec.Command(
+		testenv.GoToolPath(t), "build", "-o",
+		filepath.Join(tmpdir, "output"))
+
+	var env []string
+	for _, v := range os.Environ() {
+		if !strings.HasPrefix(v, "GOARCH=") {
+			env = append(env, v)
+		}
+	}
+	cmd.Env = append(env, "GOARCH=amd64")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("error %s output %s", err, out)
+	}
+	cmd2 := exec.Command(
+		testenv.GoToolPath(t), "tool", "objdump", "-s", "testASM",
+		filepath.Join(tmpdir, "output"))
+	cmd2.Env = cmd.Env
+	objout, err := cmd2.CombinedOutput()
+	if err != nil {
+		t.Fatalf("error %s output %s", err, objout)
+	}
+	err = os.Chdir(cwd)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return objout
+}
+
+func TestVexPCrelative(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	objout := objdumpOutput(t)
+	data := bytes.Split(objout, []byte("\n"))
+	for idx := len(data) - 1; idx >= 0; idx-- {
+		// OBJDUMP doesn't know about VMOVDQU,
+		// so instead of checking that it was assembled correctly,
+		// check that RET wasn't overwritten.
+		if bytes.Index(data[idx], []byte("RET")) != -1 {
+			return
+		}
+	}
+	t.Fatal("RET was overwritten")
+}
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
index a1a49ed..add8788 100644
--- a/src/cmd/internal/obj/x86/list6.go
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -168,11 +168,11 @@ var Register = []string{
 }
 
 func init() {
-	obj.RegisterRegister(REG_AL, REG_AL+len(Register), Rconv)
+	obj.RegisterRegister(REG_AL, REG_AL+len(Register), rconv)
 	obj.RegisterOpcode(obj.ABaseAMD64, Anames)
 }
 
-func Rconv(r int) string {
+func rconv(r int) string {
 	if REG_AL <= r && r-REG_AL < len(Register) {
 		return Register[r-REG_AL]
 	}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index eb6f867..d34f0ae 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -32,9 +32,8 @@ package x86
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
-	"fmt"
-	"log"
 	"math"
 	"strings"
 )
@@ -50,13 +49,12 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
 		return true
 	}
 
-	if ctxt.Arch.RegSize == 4 {
+	if ctxt.Arch.Family == sys.I386 {
 		switch ctxt.Headtype {
-		case obj.Hlinux,
-			obj.Hnacl,
-			obj.Hplan9,
-			obj.Hwindows,
-			obj.Hwindowsgui:
+		case objabi.Hlinux,
+			objabi.Hnacl,
+			objabi.Hplan9,
+			objabi.Hwindows:
 			return false
 		}
 
@@ -64,33 +62,16 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
 	}
 
 	switch ctxt.Headtype {
-	case obj.Hplan9, obj.Hwindows, obj.Hwindowsgui:
+	case objabi.Hplan9, objabi.Hwindows:
 		return false
-	case obj.Hlinux:
+	case objabi.Hlinux:
 		return !ctxt.Flag_shared
 	}
 
 	return true
 }
 
-func progedit(ctxt *obj.Link, p *obj.Prog) {
-	// Maintain information about code generation mode.
-	if ctxt.Mode == 0 {
-		ctxt.Mode = ctxt.Arch.RegSize * 8
-	}
-	p.Mode = int8(ctxt.Mode)
-
-	switch p.As {
-	case AMODE:
-		if p.From.Type == obj.TYPE_CONST || (p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_NONE) {
-			switch int(p.From.Offset) {
-			case 16, 32, 64:
-				ctxt.Mode = int(p.From.Offset)
-			}
-		}
-		obj.Nopout(p)
-	}
-
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 	// Thread-local storage references use the TLS pseudo-register.
 	// As a register, TLS refers to the thread-local storage base, and it
 	// can only be loaded into another register:
@@ -143,7 +124,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		// TODO(rsc): Remove the Hsolaris special case. It exists only to
 		// guarantee we are producing byte-identical binaries as before this code.
 		// But it should be unnecessary.
-		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != obj.Hsolaris {
+		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != objabi.Hsolaris {
 			obj.Nopout(p)
 		}
 		if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
@@ -165,7 +146,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		//	MOVQ TLS, BX
 		//	MOVQ 0(BX)(TLS*1), BX
 		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
-			q := obj.Appendp(ctxt, p)
+			q := obj.Appendp(p, newprog)
 			q.As = p.As
 			q.From = p.From
 			q.From.Type = obj.TYPE_MEM
@@ -181,7 +162,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	}
 
 	// TODO: Remove.
-	if (ctxt.Headtype == obj.Hwindows || ctxt.Headtype == obj.Hwindowsgui) && p.Mode == 64 || ctxt.Headtype == obj.Hplan9 {
+	if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
 		if p.From.Scale == 1 && p.From.Index == REG_TLS {
 			p.From.Scale = 2
 		}
@@ -219,7 +200,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
+	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 		if p.From3 != nil {
 			nacladdr(ctxt, p, p.From3)
 		}
@@ -260,13 +241,9 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		AUCOMISS:
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
-			i32 := math.Float32bits(f32)
-			literal := fmt.Sprintf("$f32.%08x", i32)
-			s := obj.Linklookup(ctxt, literal, 0)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Name = obj.NAME_EXTERN
-			p.From.Sym = s
-			p.From.Sym.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float32Sym(f32)
 			p.From.Offset = 0
 		}
 
@@ -300,37 +277,32 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		ACOMISD,
 		AUCOMISD:
 		if p.From.Type == obj.TYPE_FCONST {
-			i64 := math.Float64bits(p.From.Val.(float64))
-			literal := fmt.Sprintf("$f64.%016x", i64)
-			s := obj.Linklookup(ctxt, literal, 0)
+			f64 := p.From.Val.(float64)
 			p.From.Type = obj.TYPE_MEM
 			p.From.Name = obj.NAME_EXTERN
-			p.From.Sym = s
-			p.From.Sym.Set(obj.AttrLocal, true)
+			p.From.Sym = ctxt.Float64Sym(f64)
 			p.From.Offset = 0
 		}
 	}
 
 	if ctxt.Flag_dynlink {
-		rewriteToUseGot(ctxt, p)
+		rewriteToUseGot(ctxt, p, newprog)
 	}
 
-	if ctxt.Flag_shared && p.Mode == 32 {
-		rewriteToPcrel(ctxt, p)
+	if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
+		rewriteToPcrel(ctxt, p, newprog)
 	}
 }
 
 // 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 obj.As
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
+	var lea, mov obj.As
 	var reg int16
-	if p.Mode == 64 {
-		add = AADDQ
+	if ctxt.Arch.Family == sys.AMD64 {
 		lea = ALEAQ
 		mov = AMOVQ
 		reg = REG_R15
 	} else {
-		add = AADDL
 		lea = ALEAL
 		mov = AMOVL
 		reg = REG_CX
@@ -347,13 +319,15 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		//     ADUFFxxx $offset
 		// becomes
 		//     $MOV runtime.duffxxx at GOT, $reg
-		//     $ADD $offset, $reg
+		//     $LEA $offset($reg), $reg
 		//     CALL $reg
+		// (we use LEAx rather than ADDx because ADDx clobbers
+		// flags and duffzero on 386 does not otherwise do so)
 		var sym *obj.LSym
 		if p.As == obj.ADUFFZERO {
-			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+			sym = ctxt.Lookup("runtime.duffzero")
 		} else {
-			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+			sym = ctxt.Lookup("runtime.duffcopy")
 		}
 		offset := p.To.Offset
 		p.As = mov
@@ -364,13 +338,14 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		p.To.Reg = reg
 		p.To.Offset = 0
 		p.To.Sym = nil
-		p1 := obj.Appendp(ctxt, p)
-		p1.As = add
-		p1.From.Type = obj.TYPE_CONST
+		p1 := obj.Appendp(p, newprog)
+		p1.As = lea
+		p1.From.Type = obj.TYPE_MEM
 		p1.From.Offset = offset
+		p1.From.Reg = reg
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = reg
-		p2 := obj.Appendp(ctxt, p1)
+		p2 := obj.Appendp(p1, newprog)
 		p2.As = obj.ACALL
 		p2.To.Type = obj.TYPE_REG
 		p2.To.Reg = reg
@@ -392,7 +367,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		pAs := p.As
 		var dest obj.Addr
 		if p.To.Type != obj.TYPE_REG || pAs != mov {
-			if p.Mode == 64 {
+			if ctxt.Arch.Family == sys.AMD64 {
 				ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
 			}
 			cmplxdest = true
@@ -407,7 +382,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		p.From.Name = obj.NAME_GOTREF
 		q := p
 		if p.From.Offset != 0 {
-			q = obj.Appendp(ctxt, p)
+			q = obj.Appendp(p, newprog)
 			q.As = lea
 			q.From.Type = obj.TYPE_MEM
 			q.From.Reg = p.To.Reg
@@ -416,7 +391,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 			p.From.Offset = 0
 		}
 		if cmplxdest {
-			q = obj.Appendp(ctxt, q)
+			q = obj.Appendp(q, newprog)
 			q.As = pAs
 			q.To = dest
 			q.From.Type = obj.TYPE_REG
@@ -445,16 +420,16 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		// to a PLT, so make sure the GOT pointer is loaded into BX.
 		// RegTo2 is set on the replacement call insn to stop it being
 		// processed when it is in turn passed to progedit.
-		if p.Mode == 64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
+		if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
 			return
 		}
-		p1 := obj.Appendp(ctxt, p)
-		p2 := obj.Appendp(ctxt, p1)
+		p1 := obj.Appendp(p, newprog)
+		p2 := obj.Appendp(p1, newprog)
 
 		p1.As = ALEAL
 		p1.From.Type = obj.TYPE_MEM
 		p1.From.Name = obj.NAME_STATIC
-		p1.From.Sym = obj.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
+		p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
 		p1.To.Type = obj.TYPE_REG
 		p1.To.Reg = REG_BX
 
@@ -480,8 +455,8 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	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 := obj.Appendp(p, newprog)
+	p2 := obj.Appendp(p1, newprog)
 
 	p1.As = mov
 	p1.From.Type = obj.TYPE_MEM
@@ -507,7 +482,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	obj.Nopout(p)
 }
 
-func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 	// RegTo2 is set on the instructions we insert here so they don't get
 	// processed twice.
 	if p.RegTo2 != 0 {
@@ -523,7 +498,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
 		if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
 			return false
 		}
-		if a.Sym.Type == obj.STLSBSS {
+		if a.Sym.Type == objabi.STLSBSS {
 			return false
 		}
 		return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
@@ -534,7 +509,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
 		// to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
 		// respectively.
 		if p.To.Type != obj.TYPE_REG {
-			q := obj.Appendp(ctxt, p)
+			q := obj.Appendp(p, newprog)
 			q.As = p.As
 			q.From.Type = obj.TYPE_REG
 			q.From.Reg = REG_CX
@@ -556,15 +531,15 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
 		// Why?  See the comment near the top of rewriteToUseGot above.
 		// AMOVLs might be introduced by the GOT rewrites.
 	}
-	q := obj.Appendp(ctxt, p)
+	q := obj.Appendp(p, newprog)
 	q.RegTo2 = 1
-	r := obj.Appendp(ctxt, q)
+	r := obj.Appendp(q, newprog)
 	r.RegTo2 = 1
 	q.As = obj.ACALL
-	q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk."+strings.ToLower(Rconv(int(dst))), 0)
+	thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
+	q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
 	q.To.Type = obj.TYPE_MEM
 	q.To.Name = obj.NAME_EXTERN
-	q.To.Sym.Set(obj.AttrLocal, true)
 	r.As = p.As
 	r.Scond = p.Scond
 	r.From = p.From
@@ -615,18 +590,12 @@ func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 	}
 }
 
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	if ctxt.Headtype == obj.Hplan9 && ctxt.Plan9privates == nil {
-		ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
-	}
-
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
+	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
 		return
 	}
 
-	p := cursym.Text
+	p := cursym.Func.Text
 	autoffset := int32(p.To.Offset)
 	if autoffset < 0 {
 		autoffset = 0
@@ -641,9 +610,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	var bpsize int
-	if p.Mode == 64 && ctxt.Framepointer_enabled &&
-		p.From3.Offset&obj.NOFRAME == 0 && // (1) below
-		!(autoffset == 0 && p.From3.Offset&obj.NOSPLIT != 0) && // (2) below
+	if ctxt.Arch.Family == sys.AMD64 && ctxt.Framepointer_enabled &&
+		!p.From.Sym.NoFrame() && // (1) below
+		!(autoffset == 0 && p.From.Sym.NoSplit()) && // (2) below
 		!(autoffset == 0 && !hasCall) { // (3) below
 		// Make room to save a base pointer.
 		// There are 2 cases we must avoid:
@@ -661,16 +630,16 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	textarg := int64(p.To.Val.(int32))
-	cursym.Args = int32(textarg)
-	cursym.Locals = int32(p.To.Offset)
+	cursym.Func.Args = int32(textarg)
+	cursym.Func.Locals = int32(p.To.Offset)
 
 	// TODO(rsc): Remove.
-	if p.Mode == 32 && cursym.Locals < 0 {
-		cursym.Locals = 0
+	if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
+		cursym.Func.Locals = 0
 	}
 
-	// TODO(rsc): Remove 'p.Mode == 64 &&'.
-	if p.Mode == 64 && autoffset < obj.StackSmall && p.From3Offset()&obj.NOSPLIT == 0 {
+	// TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
+	if ctxt.Arch.Family == sys.AMD64 && autoffset < objabi.StackSmall && !p.From.Sym.NoSplit() {
 		leaf := true
 	LeafSearch:
 		for q := p; q != nil; q = q.Link {
@@ -684,7 +653,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				}
 				fallthrough
 			case obj.ADUFFCOPY, obj.ADUFFZERO:
-				if autoffset >= obj.StackSmall-8 {
+				if autoffset >= objabi.StackSmall-8 {
 					leaf = false
 					break LeafSearch
 				}
@@ -692,24 +661,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		}
 
 		if leaf {
-			p.From3.Offset |= obj.NOSPLIT
+			p.From.Sym.Set(obj.AttrNoSplit, true)
 		}
 	}
 
-	if p.From3Offset()&obj.NOSPLIT == 0 || p.From3Offset()&obj.WRAPPER != 0 {
-		p = obj.Appendp(ctxt, p)
-		p = load_g_cx(ctxt, p) // load g into CX
+	if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
+		p = obj.Appendp(p, newprog)
+		p = load_g_cx(ctxt, p, newprog) // load g into CX
 	}
 
-	if cursym.Text.From3Offset()&obj.NOSPLIT == 0 {
-		p = stacksplit(ctxt, p, autoffset, int32(textarg)) // emit split check
+	if !cursym.Func.Text.From.Sym.NoSplit() {
+		p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
 	}
 
 	if autoffset != 0 {
 		if autoffset%int32(ctxt.Arch.RegSize) != 0 {
 			ctxt.Diag("unaligned stack size %d", autoffset)
 		}
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 		p.As = AADJSP
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = int64(autoffset)
@@ -720,7 +689,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 	if bpsize > 0 {
 		// Save caller's BP
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 
 		p.As = AMOVQ
 		p.From.Type = obj.TYPE_REG
@@ -731,7 +700,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		p.To.Offset = int64(autoffset) - int64(bpsize)
 
 		// Move current frame to BP
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 
 		p.As = ALEAQ
 		p.From.Type = obj.TYPE_MEM
@@ -742,116 +711,146 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		p.To.Reg = REG_BP
 	}
 
-	if cursym.Text.From3Offset()&obj.WRAPPER != 0 {
-		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+	if cursym.Func.Text.From.Sym.Wrapper() {
+		// if g._panic != nil && g._panic.argp == FP {
+		//   g._panic.argp = bottom-of-frame
+		// }
 		//
 		//	MOVQ g_panic(CX), BX
 		//	TESTQ BX, BX
-		//	JEQ end
+		//	JNE checkargp
+		// end:
+		//	NOP
+		//  ... rest of function ...
+		// checkargp:
 		//	LEAQ (autoffset+8)(SP), DI
 		//	CMPQ panic_argp(BX), DI
 		//	JNE end
-		//	MOVQ SP, panic_argp(BX)
-		// end:
-		//	NOP
+		//  MOVQ SP, panic_argp(BX)
+		//  JMP end
 		//
 		// The NOP is needed to give the jumps somewhere to land.
 		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
+		//
+		// The layout is chosen to help static branch prediction:
+		// Both conditional jumps are unlikely, so they are arranged to be forward jumps.
 
-		p = obj.Appendp(ctxt, p)
-
+		// MOVQ g_panic(CX), BX
+		p = obj.Appendp(p, newprog)
 		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 {
+		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 			p.As = AMOVL
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = REG_R15
 			p.From.Scale = 1
 			p.From.Index = REG_CX
 		}
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			p.As = AMOVL
 		}
 
-		p = obj.Appendp(ctxt, p)
+		// TESTQ BX, BX
+		p = obj.Appendp(p, newprog)
 		p.As = ATESTQ
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_BX
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_BX
-		if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
+		if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
 			p.As = ATESTL
 		}
 
-		p = obj.Appendp(ctxt, p)
-		p.As = AJEQ
-		p.To.Type = obj.TYPE_BRANCH
-		p1 := p
+		// JNE checkargp (checkargp to be resolved later)
+		jne := obj.Appendp(p, newprog)
+		jne.As = AJNE
+		jne.To.Type = obj.TYPE_BRANCH
+
+		// end:
+		//  NOP
+		end := obj.Appendp(jne, newprog)
+		end.As = obj.ANOP
 
-		p = obj.Appendp(ctxt, p)
+		// Fast forward to end of function.
+		var last *obj.Prog
+		for last = end; last.Link != nil; last = last.Link {
+		}
+
+		// LEAQ (autoffset+8)(SP), DI
+		p = obj.Appendp(last, newprog)
 		p.As = ALEAQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
 		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
-		if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
+		if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
 			p.As = ALEAL
 		}
 
-		p = obj.Appendp(ctxt, p)
+		// Set jne branch target.
+		jne.Pcond = p
+
+		// CMPQ panic_argp(BX), DI
+		p = obj.Appendp(p, newprog)
 		p.As = ACMPQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_BX
 		p.From.Offset = 0 // Panic.argp
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
-		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
+		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 			p.As = ACMPL
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = REG_R15
 			p.From.Scale = 1
 			p.From.Index = REG_BX
 		}
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			p.As = ACMPL
 		}
 
-		p = obj.Appendp(ctxt, p)
+		// JNE end
+		p = obj.Appendp(p, newprog)
 		p.As = AJNE
 		p.To.Type = obj.TYPE_BRANCH
-		p2 := p
+		p.Pcond = end
 
-		p = obj.Appendp(ctxt, p)
+		// MOVQ SP, panic_argp(BX)
+		p = obj.Appendp(p, newprog)
 		p.As = AMOVQ
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_SP
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = REG_BX
 		p.To.Offset = 0 // Panic.argp
-		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
+		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 			p.As = AMOVL
 			p.To.Type = obj.TYPE_MEM
 			p.To.Reg = REG_R15
 			p.To.Scale = 1
 			p.To.Index = REG_BX
 		}
-		if p.Mode == 32 {
+		if ctxt.Arch.Family == sys.I386 {
 			p.As = AMOVL
 		}
 
-		p = obj.Appendp(ctxt, p)
-		p.As = obj.ANOP
-		p1.Pcond = p
-		p2.Pcond = p
+		// JMP end
+		p = obj.Appendp(p, newprog)
+		p.As = obj.AJMP
+		p.To.Type = obj.TYPE_BRANCH
+		p.Pcond = end
+
+		// Reset p for following code.
+		p = end
 	}
 
 	for ; p != nil; p = p.Link {
-		pcsize := int(p.Mode) / 8
+		pcsize := ctxt.Arch.RegSize
 		switch p.From.Name {
 		case obj.NAME_AUTO:
 			p.From.Offset += int64(deltasp) - int64(bpsize)
@@ -926,14 +925,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.From.Offset = int64(autoffset) - int64(bpsize)
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_BP
-				p = obj.Appendp(ctxt, p)
+				p = obj.Appendp(p, newprog)
 			}
 
 			p.As = AADJSP
 			p.From.Type = obj.TYPE_CONST
 			p.From.Offset = int64(-autoffset)
 			p.Spadj = -autoffset
-			p = obj.Appendp(ctxt, p)
+			p = obj.Appendp(p, newprog)
 			p.As = obj.ARET
 
 			// If there are instructions following
@@ -954,14 +953,14 @@ func isZeroArgRuntimeCall(s *obj.LSym) bool {
 		return false
 	}
 	switch s.Name {
-	case "runtime.panicindex", "runtime.panicslice", "runtime.panicdivide":
+	case "runtime.panicindex", "runtime.panicslice", "runtime.panicdivide", "runtime.panicwrap":
 		return true
 	}
 	return false
 }
 
 func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
+	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
 		a.Type = obj.TYPE_MEM
 		a.Reg = REG_R15
 		a.Index = REG_CX
@@ -978,7 +977,7 @@ func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 // Overwriting p is unusual but it lets use this in both the
 // prologue (caller must call appendp first) and in the epilogue.
 // Returns last new instruction.
-func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
+func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
 	p.As = AMOVQ
 	if ctxt.Arch.PtrSize == 4 {
 		p.As = AMOVL
@@ -990,7 +989,7 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
 	p.To.Reg = REG_CX
 
 	next := p.Link
-	progedit(ctxt, p)
+	progedit(ctxt, p, newprog)
 	for p.Link != next {
 		p = p.Link
 	}
@@ -1006,13 +1005,13 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
 // Appends to (does not overwrite) p.
 // Assumes g is in CX.
 // Returns last new instruction.
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
 	cmp := ACMPQ
 	lea := ALEAQ
 	mov := AMOVQ
 	sub := ASUBQ
 
-	if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
+	if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
 		cmp = ACMPL
 		lea = ALEAL
 		mov = AMOVL
@@ -1020,39 +1019,39 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 	}
 
 	var q1 *obj.Prog
-	if framesize <= obj.StackSmall {
+	if framesize <= objabi.StackSmall {
 		// small stack: SP <= stackguard
 		//	CMPQ SP, stackguard
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 
 		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() {
+		if cursym.CFunc() {
 			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
-	} else if framesize <= obj.StackBig {
+	} else if framesize <= objabi.StackBig {
 		// large stack: SP-framesize <= stackguard-StackSmall
 		//	LEAQ -xxx(SP), AX
 		//	CMPQ AX, stackguard
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 
 		p.As = lea
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
-		p.From.Offset = -(int64(framesize) - obj.StackSmall)
+		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_AX
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 		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() {
+		if cursym.CFunc() {
 			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 	} else {
@@ -1071,108 +1070,106 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		//	SUBQ	CX, AX
 		//	CMPQ	AX, $(framesize+(StackGuard-StackSmall))
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 
 		p.As = mov
 		indir_cx(ctxt, p, &p.From)
 		p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
-		if ctxt.Cursym.CFunc() {
+		if 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 = obj.Appendp(p, newprog)
 		p.As = cmp
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_SI
 		p.To.Type = obj.TYPE_CONST
-		p.To.Offset = obj.StackPreempt
-		if p.Mode == 32 {
-			p.To.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
+		p.To.Offset = objabi.StackPreempt
+		if ctxt.Arch.Family == sys.I386 {
+			p.To.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
 		}
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 		p.As = AJEQ
 		p.To.Type = obj.TYPE_BRANCH
 		q1 = p
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 		p.As = lea
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
-		p.From.Offset = obj.StackGuard
+		p.From.Offset = objabi.StackGuard
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_AX
 
-		p = obj.Appendp(ctxt, p)
+		p = obj.Appendp(p, newprog)
 		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 = obj.Appendp(p, newprog)
 		p.As = cmp
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_AX
 		p.To.Type = obj.TYPE_CONST
-		p.To.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
+		p.To.Offset = int64(framesize) + (objabi.StackGuard - objabi.StackSmall)
 	}
 
 	// common
-	jls := obj.Appendp(ctxt, p)
+	jls := obj.Appendp(p, newprog)
 	jls.As = AJLS
 	jls.To.Type = obj.TYPE_BRANCH
 
 	var last *obj.Prog
-	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	for last = cursym.Func.Text; last.Link != nil; last = last.Link {
 	}
 
 	// Now we are at the end of the function, but logically
 	// we are still in function prologue. We need to fix the
 	// SP data and PCDATA.
-	spfix := obj.Appendp(ctxt, last)
+	spfix := obj.Appendp(last, newprog)
 	spfix.As = obj.ANOP
 	spfix.Spadj = -framesize
 
-	pcdata := obj.Appendp(ctxt, spfix)
-	pcdata.Lineno = ctxt.Cursym.Text.Lineno
-	pcdata.Mode = ctxt.Cursym.Text.Mode
+	pcdata := obj.Appendp(spfix, newprog)
+	pcdata.Pos = cursym.Func.Text.Pos
 	pcdata.As = obj.APCDATA
 	pcdata.From.Type = obj.TYPE_CONST
-	pcdata.From.Offset = obj.PCDATA_StackMapIndex
+	pcdata.From.Offset = objabi.PCDATA_StackMapIndex
 	pcdata.To.Type = obj.TYPE_CONST
 	pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
 
-	call := obj.Appendp(ctxt, pcdata)
-	call.Lineno = ctxt.Cursym.Text.Lineno
-	call.Mode = ctxt.Cursym.Text.Mode
+	call := obj.Appendp(pcdata, newprog)
+	call.Pos = cursym.Func.Text.Pos
 	call.As = obj.ACALL
 	call.To.Type = obj.TYPE_BRANCH
 	call.To.Name = obj.NAME_EXTERN
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.CFunc():
+	case cursym.CFunc():
 		morestack = "runtime.morestackc"
-	case ctxt.Cursym.Text.From3Offset()&obj.NEEDCTXT == 0:
+	case !cursym.Func.Text.From.Sym.NeedCtxt():
 		morestack = "runtime.morestack_noctxt"
 	}
-	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+	call.To.Sym = ctxt.Lookup(morestack)
 	// 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)
+	progedit(ctxt, callend, newprog)
 	for ; callend.Link != nil; callend = callend.Link {
-		progedit(ctxt, callend.Link)
+		progedit(ctxt, callend.Link, newprog)
 	}
 
-	jmp := obj.Appendp(ctxt, callend)
+	jmp := obj.Appendp(callend, newprog)
 	jmp.As = obj.AJMP
 	jmp.To.Type = obj.TYPE_BRANCH
-	jmp.Pcond = ctxt.Cursym.Text.Link
+	jmp.Pcond = cursym.Func.Text.Link
 	jmp.Spadj = +framesize
 
 	jls.Pcond = call
@@ -1183,241 +1180,6 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 	return jls
 }
 
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	ctxt.Cursym = s
-
-	firstp := ctxt.NewProg()
-	lastp := firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func nofollow(a obj.As) bool {
-	switch a {
-	case obj.AJMP,
-		obj.ARET,
-		AIRETL,
-		AIRETQ,
-		AIRETW,
-		ARETFL,
-		ARETFQ,
-		ARETFW,
-		obj.AUNDEF:
-		return true
-	}
-
-	return false
-}
-
-func pushpop(a obj.As) bool {
-	switch a {
-	case APUSHL,
-		APUSHFL,
-		APUSHQ,
-		APUSHFQ,
-		APUSHW,
-		APUSHFW,
-		APOPL,
-		APOPFL,
-		APOPQ,
-		APOPFQ,
-		APOPW,
-		APOPFW:
-		return true
-	}
-
-	return false
-}
-
-func relinv(a obj.As) obj.As {
-	switch a {
-	case AJEQ:
-		return AJNE
-	case AJNE:
-		return AJEQ
-	case AJLE:
-		return AJGT
-	case AJLS:
-		return AJHI
-	case AJLT:
-		return AJGE
-	case AJMI:
-		return AJPL
-	case AJGE:
-		return AJLT
-	case AJPL:
-		return AJMI
-	case AJGT:
-		return AJLE
-	case AJHI:
-		return AJLS
-	case AJCS:
-		return AJCC
-	case AJCC:
-		return AJCS
-	case AJPS:
-		return AJPC
-	case AJPC:
-		return AJPS
-	case AJOS:
-		return AJOC
-	case AJOC:
-		return AJOS
-	}
-
-	log.Fatalf("unknown relation: %s", a)
-	return 0
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
-	var q *obj.Prog
-	var i int
-	var a obj.As
-
-loop:
-	if p == nil {
-		return
-	}
-	if p.As == obj.AJMP {
-		q = p.Pcond
-		if q != nil && q.As != obj.ATEXT {
-			/* mark instruction as done and continue layout at target of jump */
-			p.Mark |= DONE
-
-			p = q
-			if p.Mark&DONE == 0 {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark&DONE != 0 {
-		/*
-		 * p goes here, but already used it elsewhere.
-		 * copy up to 4 instructions or else branch to other copy.
-		 */
-		i = 0
-		q = p
-		for ; i < 4; i, q = i+1, q.Link {
-			if q == nil {
-				break
-			}
-			if q == *last {
-				break
-			}
-			a = q.As
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if nofollow(a) || pushpop(a) {
-				break // NOTE(rsc): arm does goto copy
-			}
-			if q.Pcond == nil || q.Pcond.Mark&DONE != 0 {
-				continue
-			}
-			if a == obj.ACALL || a == ALOOP {
-				continue
-			}
-			for {
-				if p.As == obj.ANOP {
-					p = p.Link
-					continue
-				}
-
-				q = obj.Copyp(ctxt, p)
-				p = p.Link
-				q.Mark |= DONE
-				(*last).Link = q
-				*last = q
-				if q.As != a || q.Pcond == nil || q.Pcond.Mark&DONE != 0 {
-					continue
-				}
-
-				q.As = relinv(q.As)
-				p = q.Pcond
-				q.Pcond = q.Link
-				q.Link = p
-				xfol(ctxt, q.Link, last)
-				p = q.Link
-				if p.Mark&DONE != 0 {
-					return
-				}
-				goto loop
-				/* */
-			}
-		}
-		q = ctxt.NewProg()
-		q.As = obj.AJMP
-		q.Lineno = p.Lineno
-		q.To.Type = obj.TYPE_BRANCH
-		q.To.Offset = p.Pc
-		q.Pcond = p
-		p = q
-	}
-
-	/* emit p */
-	p.Mark |= DONE
-
-	(*last).Link = p
-	*last = p
-	a = p.As
-
-	/* continue loop with what comes after p */
-	if nofollow(a) {
-		return
-	}
-	if p.Pcond != nil && a != obj.ACALL {
-		/*
-		 * some kind of conditional branch.
-		 * recurse to follow one path.
-		 * continue loop on the other.
-		 */
-		q = obj.Brchain(ctxt, p.Pcond)
-		if q != nil {
-			p.Pcond = q
-		}
-		q = obj.Brchain(ctxt, p.Link)
-		if q != nil {
-			p.Link = q
-		}
-		if p.From.Type == obj.TYPE_CONST {
-			if p.From.Offset == 1 {
-				/*
-				 * expect conditional jump to be taken.
-				 * rewrite so that's the fall-through case.
-				 */
-				p.As = relinv(a)
-
-				q = p.Link
-				p.Link = p.Pcond
-				p.Pcond = q
-			}
-		} else {
-			q = p.Link
-			if q.Mark&DONE != 0 {
-				if a != ALOOP {
-					p.As = relinv(a)
-					p.Link = p.Pcond
-					p.Pcond = q
-				}
-			}
-		}
-
-		xfol(ctxt, p.Link, last)
-		if p.Pcond.Mark&DONE != 0 {
-			return
-		}
-		p = p.Pcond
-		goto loop
-	}
-
-	p = p.Link
-	goto loop
-}
-
 var unaryDst = map[obj.As]bool{
 	ABSWAPL:    true,
 	ABSWAPQ:    true,
@@ -1470,27 +1232,27 @@ var unaryDst = map[obj.As]bool{
 
 var Linkamd64 = obj.LinkArch{
 	Arch:       sys.ArchAMD64,
+	Init:       instinit,
 	Preprocess: preprocess,
 	Assemble:   span6,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
 
 var Linkamd64p32 = obj.LinkArch{
 	Arch:       sys.ArchAMD64P32,
+	Init:       instinit,
 	Preprocess: preprocess,
 	Assemble:   span6,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
 
 var Link386 = obj.LinkArch{
 	Arch:       sys.Arch386,
+	Init:       instinit,
 	Preprocess: preprocess,
 	Assemble:   span6,
-	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
 }
diff --git a/src/cmd/internal/objabi/autotype.go b/src/cmd/internal/objabi/autotype.go
new file mode 100644
index 0000000..17c4293
--- /dev/null
+++ b/src/cmd/internal/objabi/autotype.go
@@ -0,0 +1,37 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package objabi
+
+// Auto.name
+const (
+	A_AUTO = 1 + iota
+	A_PARAM
+)
diff --git a/src/cmd/internal/objabi/doc.go b/src/cmd/internal/objabi/doc.go
new file mode 100644
index 0000000..7bd5ff6
--- /dev/null
+++ b/src/cmd/internal/objabi/doc.go
@@ -0,0 +1,120 @@
+// Copyright 2013 The Go 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: There are *three* independent implementations of this object
+// file format in the Go source tree:
+//
+//	- cmd/internal/goobj/read.go (used by cmd/addr2line, cmd/nm, cmd/objdump, cmd/pprof)
+//	- cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
+//	- cmd/link/internal/objfile.go (used by cmd/link)
+//
+// When changing the object file format, remember to change all three.
+
+// Originally, Go object files were Plan 9 object files, but no longer.
+// Now they are more like standard object files, in that each symbol is defined
+// by an associated memory image (bytes) and a list of relocations to apply
+// during linking. We do not (yet?) use a standard file format, however.
+// For now, the format is chosen to be as simple as possible to read and write.
+// It may change for reasons of efficiency, or we may even switch to a
+// standard file format if there are compelling benefits to doing so.
+// See golang.org/s/go13linker for more background.
+//
+// The file format is:
+//
+//	- magic header: "\x00\x00go19ld"
+//	- 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\xffgo19ld"
+//
+// All integers are stored in a zigzag varint format.
+// See golang.org/s/go12symtab for a definition.
+//
+// Data blocks and strings are both stored as an integer
+// followed by that many bytes.
+//
+// A symbol reference is a string name followed by a version.
+//
+// A symbol points to other symbols using an index into the symbol
+// reference sequence. Index 0 corresponds to a nil symbol pointer.
+// In the symbol layout described below "symref index" stands for this
+// index.
+//
+// Each symbol is laid out as the following fields:
+//
+//	- byte 0xfe (sanity check for synchronization)
+//	- type [byte]
+//	- name & version [symref index]
+//	- flags [int]
+//		1<<0 dupok
+//		1<<1 local
+//		1<<2 add to typelink table
+//	- size [int]
+//	- gotype [symref index]
+//	- p [data block]
+//	- nr [int]
+//	- r [nr relocations, sorted by off]
+//
+// If type == STEXT, there are a few more fields:
+//
+//	- args [int]
+//	- locals [int]
+//	- nosplit [int]
+//	- flags [int]
+//		1<<0 leaf
+//		1<<1 C function
+//		1<<2 function may call reflect.Type.Method
+//		1<<3 function compiled with -shared
+//	- nlocal [int]
+//	- local [nlocal automatics]
+//	- pcln [pcln table]
+//
+// Each relocation has the encoding:
+//
+//	- off [int]
+//	- siz [int]
+//	- type [int]
+//	- add [int]
+//	- sym [symref index]
+//
+// Each local has the encoding:
+//
+//	- asym [symref index]
+//	- offset [int]
+//	- type [int]
+//	- gotype [symref index]
+//
+// The pcln table has the encoding:
+//
+//	- pcsp [data block]
+//	- pcfile [data block]
+//	- pcline [data block]
+//	- pcinline [data block]
+//	- npcdata [int]
+//	- pcdata [npcdata data blocks]
+//	- nfuncdata [int]
+//	- funcdata [nfuncdata symref index]
+//	- funcdatasym [nfuncdata ints]
+//	- nfile [int]
+//	- file [nfile symref index]
+//	- ninlinedcall [int]
+//	- inlinedcall [ninlinedcall int symref int symref]
+//
+// 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.
+package objabi
diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go
new file mode 100644
index 0000000..e349b41
--- /dev/null
+++ b/src/cmd/internal/objabi/flag.go
@@ -0,0 +1,115 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"strconv"
+)
+
+func Flagfn2(string, string, func(string, string)) { panic("flag") }
+
+func Flagcount(name, usage string, val *int) {
+	flag.Var((*count)(val), name, usage)
+}
+
+func Flagint32(name, usage string, val *int32) {
+	flag.Var((*int32Value)(val), name, usage)
+}
+
+func Flagint64(name, usage string, val *int64) {
+	flag.Int64Var(val, name, *val, usage)
+}
+
+func Flagstr(name, usage string, val *string) {
+	flag.StringVar(val, name, *val, usage)
+}
+
+func Flagfn0(name, usage string, f func()) {
+	flag.Var(fn0(f), name, usage)
+}
+
+func Flagfn1(name, usage string, f func(string)) {
+	flag.Var(fn1(f), name, usage)
+}
+
+func Flagprint(fd int) {
+	if fd == 1 {
+		flag.CommandLine.SetOutput(os.Stdout)
+	}
+	flag.PrintDefaults()
+}
+
+func Flagparse(usage func()) {
+	flag.Usage = usage
+	flag.Parse()
+}
+
+// count is a flag.Value that is like a flag.Bool and a flag.Int.
+// If used as -name, it increments the count, but -name=x sets the count.
+// Used for verbose flag -v.
+type count int
+
+func (c *count) String() string {
+	return fmt.Sprint(int(*c))
+}
+
+func (c *count) Set(s string) error {
+	switch s {
+	case "true":
+		*c++
+	case "false":
+		*c = 0
+	default:
+		n, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("invalid count %q", s)
+		}
+		*c = count(n)
+	}
+	return nil
+}
+
+func (c *count) IsBoolFlag() bool {
+	return true
+}
+
+type int32Value int32
+
+func (i *int32Value) Set(s string) error {
+	v, err := strconv.ParseInt(s, 0, 64)
+	*i = int32Value(v)
+	return err
+}
+
+func (i *int32Value) Get() interface{} { return int32(*i) }
+
+func (i *int32Value) String() string { return fmt.Sprint(*i) }
+
+type fn0 func()
+
+func (f fn0) Set(s string) error {
+	f()
+	return nil
+}
+
+func (f fn0) Get() interface{} { return nil }
+
+func (f fn0) String() string { return "" }
+
+func (f fn0) IsBoolFlag() bool {
+	return true
+}
+
+type fn1 func(string)
+
+func (f fn1) Set(s string) error {
+	f(s)
+	return nil
+}
+
+func (f fn1) String() string { return "" }
diff --git a/src/cmd/internal/objabi/funcdata.go b/src/cmd/internal/objabi/funcdata.go
new file mode 100644
index 0000000..80874ed
--- /dev/null
+++ b/src/cmd/internal/objabi/funcdata.go
@@ -0,0 +1,25 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+// This file defines the IDs for PCDATA and FUNCDATA instructions
+// in Go binaries.
+//
+// These must agree with ../../../runtime/funcdata.h and
+// ../../../runtime/symtab.go.
+
+const (
+	PCDATA_StackMapIndex       = 0
+	PCDATA_InlTreeIndex        = 1
+	FUNCDATA_ArgsPointerMaps   = 0
+	FUNCDATA_LocalsPointerMaps = 1
+	FUNCDATA_InlTree           = 2
+
+	// ArgsSizeUnknown is set in Func.argsize to mark all functions
+	// whose argument size is unknown (C vararg functions, and
+	// assembly code without an explicit specification).
+	// This value is generated by the compiler, assembler, or linker.
+	ArgsSizeUnknown = -0x80000000
+)
diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go
new file mode 100644
index 0000000..ff19606
--- /dev/null
+++ b/src/cmd/internal/objabi/head.go
@@ -0,0 +1,104 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package objabi
+
+import "fmt"
+
+// HeadType is the executable header type.
+type HeadType uint8
+
+const (
+	Hunknown HeadType = iota
+	Hdarwin
+	Hdragonfly
+	Hfreebsd
+	Hlinux
+	Hnacl
+	Hnetbsd
+	Hopenbsd
+	Hplan9
+	Hsolaris
+	Hwindows
+)
+
+func (h *HeadType) Set(s string) error {
+	switch s {
+	case "darwin":
+		*h = Hdarwin
+	case "dragonfly":
+		*h = Hdragonfly
+	case "freebsd":
+		*h = Hfreebsd
+	case "linux", "android":
+		*h = Hlinux
+	case "nacl":
+		*h = Hnacl
+	case "netbsd":
+		*h = Hnetbsd
+	case "openbsd":
+		*h = Hopenbsd
+	case "plan9":
+		*h = Hplan9
+	case "solaris":
+		*h = Hsolaris
+	case "windows":
+		*h = Hwindows
+	default:
+		return fmt.Errorf("invalid headtype: %q", s)
+	}
+	return nil
+}
+
+func (h *HeadType) String() string {
+	switch *h {
+	case Hdarwin:
+		return "darwin"
+	case Hdragonfly:
+		return "dragonfly"
+	case Hfreebsd:
+		return "freebsd"
+	case Hlinux:
+		return "linux"
+	case Hnacl:
+		return "nacl"
+	case Hnetbsd:
+		return "netbsd"
+	case Hopenbsd:
+		return "openbsd"
+	case Hplan9:
+		return "plan9"
+	case Hsolaris:
+		return "solaris"
+	case Hwindows:
+		return "windows"
+	}
+	return fmt.Sprintf("HeadType(%d)", *h)
+}
diff --git a/src/cmd/internal/objabi/line.go b/src/cmd/internal/objabi/line.go
new file mode 100644
index 0000000..ed509b7
--- /dev/null
+++ b/src/cmd/internal/objabi/line.go
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import (
+	"os"
+	"path/filepath"
+)
+
+// WorkingDir returns the current working directory
+// (or "/???" if the directory cannot be identified),
+// with "/" as separator.
+func WorkingDir() string {
+	var path string
+	path, _ = os.Getwd()
+	if path == "" {
+		path = "/???"
+	}
+	return filepath.ToSlash(path)
+}
+
+// AbsFile returns the absolute filename for file in the given directory.
+// It also removes a leading pathPrefix, or else rewrites a leading $GOROOT
+// prefix to the literal "$GOROOT".
+// If the resulting path is the empty string, the result is "??".
+func AbsFile(dir, file, pathPrefix string) string {
+	abs := file
+	if dir != "" && !filepath.IsAbs(file) {
+		abs = filepath.Join(dir, file)
+	}
+
+	if pathPrefix != "" && hasPathPrefix(abs, pathPrefix) {
+		if abs == pathPrefix {
+			abs = ""
+		} else {
+			abs = abs[len(pathPrefix)+1:]
+		}
+	} else if hasPathPrefix(abs, GOROOT) {
+		abs = "$GOROOT" + abs[len(GOROOT):]
+	}
+	if abs == "" {
+		abs = "??"
+	}
+
+	return filepath.Clean(abs)
+}
+
+// Does s have t as a path prefix?
+// That is, does s == t or does s begin with t followed by a slash?
+// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
+// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
+// We do not allow full Unicode case folding, for fear of causing more confusion
+// or harm than good. (For an example of the kinds of things that can go wrong,
+// see http://article.gmane.org/gmane.linux.kernel/1853266.)
+func hasPathPrefix(s string, t string) bool {
+	if len(t) > len(s) {
+		return false
+	}
+	var i int
+	for i = 0; i < len(t); i++ {
+		cs := int(s[i])
+		ct := int(t[i])
+		if 'A' <= cs && cs <= 'Z' {
+			cs += 'a' - 'A'
+		}
+		if 'A' <= ct && ct <= 'Z' {
+			ct += 'a' - 'A'
+		}
+		if cs == '\\' {
+			cs = '/'
+		}
+		if ct == '\\' {
+			ct = '/'
+		}
+		if cs != ct {
+			return false
+		}
+	}
+	return i >= len(s) || s[i] == '/' || s[i] == '\\'
+}
diff --git a/src/cmd/internal/objabi/path.go b/src/cmd/internal/objabi/path.go
new file mode 100644
index 0000000..2a42179
--- /dev/null
+++ b/src/cmd/internal/objabi/path.go
@@ -0,0 +1,41 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import "strings"
+
+// PathToPrefix converts raw string to the prefix that will be used in the
+// symbol table. All control characters, space, '%' and '"', as well as
+// non-7-bit clean bytes turn into %xx. The period needs escaping only in the
+// last segment of the path, and it makes for happier users if we escape that as
+// little as possible.
+func PathToPrefix(s string) string {
+	slash := strings.LastIndex(s, "/")
+	// check for chars that need escaping
+	n := 0
+	for r := 0; r < len(s); r++ {
+		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+			n++
+		}
+	}
+
+	// quick exit
+	if n == 0 {
+		return s
+	}
+
+	// escape
+	const hex = "0123456789abcdef"
+	p := make([]byte, 0, len(s)+2*n)
+	for r := 0; r < len(s); r++ {
+		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+			p = append(p, '%', hex[c>>4], hex[c&0xF])
+		} else {
+			p = append(p, c)
+		}
+	}
+
+	return string(p)
+}
diff --git a/src/cmd/internal/objabi/path_test.go b/src/cmd/internal/objabi/path_test.go
new file mode 100644
index 0000000..05d7fb4
--- /dev/null
+++ b/src/cmd/internal/objabi/path_test.go
@@ -0,0 +1,33 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import "testing"
+
+func TestPathToPrefix(t *testing.T) {
+	tests := []struct {
+		Path     string
+		Expected string
+	}{{"foo/bar/v1", "foo/bar/v1"},
+		{"foo/bar/v.1", "foo/bar/v%2e1"},
+		{"f.o.o/b.a.r/v1", "f.o.o/b.a.r/v1"},
+		{"f.o.o/b.a.r/v.1", "f.o.o/b.a.r/v%2e1"},
+		{"f.o.o/b.a.r/v..1", "f.o.o/b.a.r/v%2e%2e1"},
+		{"f.o.o/b.a.r/v..1.", "f.o.o/b.a.r/v%2e%2e1%2e"},
+		{"f.o.o/b.a.r/v%1", "f.o.o/b.a.r/v%251"},
+		{"runtime", "runtime"},
+		{"sync/atomic", "sync/atomic"},
+		{"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"},
+		{"foo.bar/baz.quux", "foo.bar/baz%2equux"},
+		{"", ""},
+		{"%foo%bar", "%25foo%25bar"},
+		{"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"},
+	}
+	for _, tc := range tests {
+		if got := PathToPrefix(tc.Path); got != tc.Expected {
+			t.Errorf("expected PathToPrefix(%s) = %s, got %s", tc.Path, tc.Expected, got)
+		}
+	}
+}
diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
new file mode 100644
index 0000000..179f049
--- /dev/null
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -0,0 +1,200 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package objabi
+
+type RelocType int32
+
+//go:generate stringer -type=RelocType
+const (
+	R_ADDR RelocType = 1 + iota
+	// R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit
+	// immediates in the low half of the instruction word), usually addis followed by
+	// another add or a load, inserting the "high adjusted" 16 bits of the address of
+	// the referenced symbol into the immediate field of the first instruction and the
+	// low 16 bits into that of the second instruction.
+	R_ADDRPOWER
+	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
+	// referenced symbol.
+	R_ADDRARM64
+	// R_ADDRMIPS (only used on mips/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_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
+	// A weak relocation does not make the symbol it refers to reachable,
+	// and is only honored by the linker if the symbol is in some other way
+	// reachable.
+	R_WEAKADDROFF
+	R_SIZE
+	R_CALL
+	R_CALLARM
+	R_CALLARM64
+	R_CALLIND
+	R_CALLPOWER
+	// R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
+	// of a CALL (JAL) instruction, by encoding the address into the instruction.
+	R_CALLMIPS
+	R_CONST
+	R_PCREL
+	// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
+	// thread-local symbol from the thread local base and is used to implement the
+	// "local exec" model for tls access (r.Sym is not set on intel platforms but is
+	// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
+	R_TLS_LE
+	// R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT
+	// slot containing the offset from the thread-local symbol from the thread local
+	// base and is used to implemented the "initial exec" model for tls access (r.Sym
+	// is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in
+	// the linker when externally linking).
+	R_TLS_IE
+	R_GOTOFF
+	R_PLT0
+	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
+	// inherently processor specific.
+
+	// Arm64.
+
+	// Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread
+	// local base to the thread local variable defined by the referenced (thread
+	// local) symbol. Error if the offset does not fit into 16 bits.
+	R_ARM64_TLS_LE
+
+	// Relocates an ADRP; LD64 instruction sequence to load the offset between
+	// the thread local base and the thread local variable defined by the
+	// referenced (thread local) symbol from the GOT.
+	R_ARM64_TLS_IE
+
+	// R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
+	// slot of the referenced symbol.
+	R_ARM64_GOTPCREL
+
+	// PPC64.
+
+	// R_POWER_TLS_LE is used to implement the "local exec" model for tls
+	// access. It resolves to the offset of the thread-local symbol from the
+	// thread pointer (R13) and inserts this value into the low 16 bits of an
+	// instruction word.
+	R_POWER_TLS_LE
+
+	// R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It
+	// relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It
+	// inserts to the offset of GOT slot for the thread-local symbol from the TOC (the
+	// GOT slot is filled by the dynamic linker with the offset of the thread-local
+	// symbol from the thread pointer (R13)).
+	R_POWER_TLS_IE
+
+	// R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as
+	// accessing a particular thread-local symbol. It does not affect code generation
+	// but is used by the system linker when relaxing "initial exec" model code to
+	// "local exec" model code.
+	R_POWER_TLS
+
+	// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
+	// instruction is a "DS-form" instruction, which has an immediate field occupying
+	// bits [15:2] of the instruction word. Bits [15:2] of the address of the
+	// relocated symbol are inserted into this field; it is an error if the last two
+	// bits of the address are not 0.
+	R_ADDRPOWER_DS
+
+	// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
+	// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
+	// from the TOC rather than the symbol's address.
+	R_ADDRPOWER_GOT
+
+	// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
+	// inserts the displacement from the place being relocated to the address of the
+	// the relocated symbol instead of just its address.
+	R_ADDRPOWER_PCREL
+
+	// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
+	// inserts the offset from the TOC to the address of the relocated symbol
+	// rather than the symbol's address.
+	R_ADDRPOWER_TOCREL
+
+	// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
+	// 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 mips/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
+)
+
+// IsDirectJump returns whether r is a relocation for a direct jump.
+// A direct jump is a CALL or JMP instruction that takes the target address
+// as immediate. The address is embedded into the instruction, possibly
+// with limited width.
+// An indirect jump is a CALL or JMP instruction that takes the target address
+// in register or memory.
+func (r RelocType) IsDirectJump() bool {
+	switch r {
+	case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER, R_CALLMIPS, R_JMPMIPS:
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go
new file mode 100644
index 0000000..182d03f
--- /dev/null
+++ b/src/cmd/internal/objabi/reloctype_string.go
@@ -0,0 +1,17 @@
+// Code generated by "stringer -type=RelocType"; DO NOT EDIT.
+
+package objabi
+
+import "fmt"
+
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
+
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 248, 262, 276, 292, 306, 320, 331, 345, 360, 377, 395, 416, 426, 437, 450}
+
+func (i RelocType) String() string {
+	i -= 1
+	if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
+		return fmt.Sprintf("RelocType(%d)", i+1)
+	}
+	return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
+}
diff --git a/src/cmd/internal/objabi/stack.go b/src/cmd/internal/objabi/stack.go
new file mode 100644
index 0000000..1143393
--- /dev/null
+++ b/src/cmd/internal/objabi/stack.go
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+// For the linkers. Must match Go definitions.
+
+const (
+	STACKSYSTEM = 0
+	StackSystem = STACKSYSTEM
+	StackBig    = 4096
+	StackGuard  = 880*stackGuardMultiplier + StackSystem
+	StackSmall  = 128
+	StackLimit  = StackGuard - StackSystem - StackSmall
+)
+
+const (
+	StackPreempt = -1314 // 0xfff...fade
+)
diff --git a/src/cmd/internal/objabi/symkind.go b/src/cmd/internal/objabi/symkind.go
new file mode 100644
index 0000000..b037e9e
--- /dev/null
+++ b/src/cmd/internal/objabi/symkind.go
@@ -0,0 +1,60 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package objabi
+
+// A SymKind describes the kind of memory represented by a symbol.
+type SymKind uint8
+
+// Defined SymKind values.
+//
+// TODO(rsc): Give idiomatic Go names.
+//go:generate stringer -type=SymKind
+const (
+	// An otherwise invalid zero value for the type
+	Sxxx SymKind = iota
+	// Executable instructions
+	STEXT
+	// Read only static data
+	SRODATA
+	// Static data that does not contain any pointers
+	SNOPTRDATA
+	// Static data
+	SDATA
+	// Statically data that is initially all 0s
+	SBSS
+	// Statically data that is initially all 0s and does not contain pointers
+	SNOPTRBSS
+	// Thread-local data that is initally all 0s
+	STLSBSS
+	// Debugging data
+	SDWARFINFO
+	SDWARFRANGE
+)
diff --git a/src/cmd/internal/objabi/symkind_string.go b/src/cmd/internal/objabi/symkind_string.go
new file mode 100644
index 0000000..5123dc7
--- /dev/null
+++ b/src/cmd/internal/objabi/symkind_string.go
@@ -0,0 +1,16 @@
+// Code generated by "stringer -type=SymKind"; DO NOT EDIT.
+
+package objabi
+
+import "fmt"
+
+const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE"
+
+var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72}
+
+func (i SymKind) String() string {
+	if i >= SymKind(len(_SymKind_index)-1) {
+		return fmt.Sprintf("SymKind(%d)", i)
+	}
+	return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
+}
diff --git a/src/cmd/internal/objabi/typekind.go b/src/cmd/internal/objabi/typekind.go
new file mode 100644
index 0000000..f0e6f47
--- /dev/null
+++ b/src/cmd/internal/objabi/typekind.go
@@ -0,0 +1,41 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+// Must match runtime and reflect.
+// Included by cmd/gc.
+
+const (
+	KindBool = 1 + iota
+	KindInt
+	KindInt8
+	KindInt16
+	KindInt32
+	KindInt64
+	KindUint
+	KindUint8
+	KindUint16
+	KindUint32
+	KindUint64
+	KindUintptr
+	KindFloat32
+	KindFloat64
+	KindComplex64
+	KindComplex128
+	KindArray
+	KindChan
+	KindFunc
+	KindInterface
+	KindMap
+	KindPtr
+	KindSlice
+	KindString
+	KindStruct
+	KindUnsafePointer
+	KindDirectIface = 1 << 5
+	KindGCProg      = 1 << 6
+	KindNoPointers  = 1 << 7
+	KindMask        = (1 << 5) - 1
+)
diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go
new file mode 100644
index 0000000..811fdd3
--- /dev/null
+++ b/src/cmd/internal/objabi/util.go
@@ -0,0 +1,114 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strings"
+)
+
+func envOr(key, value string) string {
+	if x := os.Getenv(key); x != "" {
+		return x
+	}
+	return value
+}
+
+var (
+	GOROOT  = envOr("GOROOT", defaultGOROOT)
+	GOARCH  = envOr("GOARCH", defaultGOARCH)
+	GOOS    = envOr("GOOS", defaultGOOS)
+	GO386   = envOr("GO386", defaultGO386)
+	GOARM   = goarm()
+	Version = version
+)
+
+func goarm() int {
+	switch v := envOr("GOARM", defaultGOARM); v {
+	case "5":
+		return 5
+	case "6":
+		return 6
+	case "7":
+		return 7
+	}
+	// Fail here, rather than validate at multiple call sites.
+	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
+	panic("unreachable")
+}
+
+func Getgoextlinkenabled() string {
+	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
+}
+
+func init() {
+	framepointer_enabled = 1 // default
+	for _, f := range strings.Split(goexperiment, ",") {
+		if f != "" {
+			addexp(f)
+		}
+	}
+}
+
+func Framepointer_enabled(goos, goarch string) bool {
+	return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
+}
+
+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 == name {
+			if exper[i].val != nil {
+				*exper[i].val = v
+			}
+			return
+		}
+	}
+
+	fmt.Printf("unknown experiment %s\n", s)
+	os.Exit(2)
+}
+
+var (
+	framepointer_enabled     int
+	Fieldtrack_enabled       int
+	Preemptibleloops_enabled int
+	Clobberdead_enabled      int
+)
+
+// Toolchain experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the toolchain is built.
+// This list is also known to cmd/gc.
+var exper = []struct {
+	name string
+	val  *int
+}{
+	{"fieldtrack", &Fieldtrack_enabled},
+	{"framepointer", &framepointer_enabled},
+	{"preemptibleloops", &Preemptibleloops_enabled},
+	{"clobberdead", &Clobberdead_enabled},
+}
+
+func Expstring() string {
+	buf := "X"
+	for i := range exper {
+		if *exper[i].val != 0 {
+			buf += "," + exper[i].name
+		}
+	}
+	if buf == "X" {
+		buf += ",none"
+	}
+	return "X:" + buf[2:]
+}
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index 8af0c8f..d61cb27 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -6,10 +6,16 @@ package objfile
 
 import (
 	"bufio"
+	"bytes"
+	"cmd/internal/src"
+	"container/list"
 	"debug/gosym"
 	"encoding/binary"
 	"fmt"
 	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
 	"regexp"
 	"sort"
 	"strings"
@@ -102,10 +108,82 @@ func base(path string) string {
 	return path
 }
 
+// CachedFile contains the content of a file split into lines.
+type CachedFile struct {
+	FileName string
+	Lines    [][]byte
+}
+
+// FileCache is a simple LRU cache of file contents.
+type FileCache struct {
+	files  *list.List
+	maxLen int
+}
+
+// NewFileCache returns a FileCache which can contain up to maxLen cached file contents.
+func NewFileCache(maxLen int) *FileCache {
+	return &FileCache{
+		files:  list.New(),
+		maxLen: maxLen,
+	}
+}
+
+// Line returns the source code line for the given file and line number.
+// If the file is not already cached, reads it , inserts it into the cache,
+// and removes the least recently used file if necessary.
+// If the file is in cache, moves it up to the front of the list.
+func (fc *FileCache) Line(filename string, line int) ([]byte, error) {
+	if filepath.Ext(filename) != ".go" {
+		return nil, nil
+	}
+
+	// Clean filenames returned by src.Pos.SymFilename()
+	// or src.PosBase.SymFilename() removing
+	// the leading src.FileSymPrefix.
+	if strings.HasPrefix(filename, src.FileSymPrefix) {
+		filename = filename[len(src.FileSymPrefix):]
+	}
+
+	// Expand literal "$GOROOT" rewrited by obj.AbsFile()
+	filename = filepath.Clean(os.ExpandEnv(filename))
+
+	var cf *CachedFile
+	var e *list.Element
+
+	for e = fc.files.Front(); e != nil; e = e.Next() {
+		cf = e.Value.(*CachedFile)
+		if cf.FileName == filename {
+			break
+		}
+	}
+
+	if e == nil {
+		content, err := ioutil.ReadFile(filename)
+		if err != nil {
+			return nil, err
+		}
+
+		cf = &CachedFile{
+			FileName: filename,
+			Lines:    bytes.Split(content, []byte{'\n'}),
+		}
+		fc.files.PushFront(cf)
+
+		if fc.files.Len() >= fc.maxLen {
+			fc.files.Remove(fc.files.Back())
+		}
+	} else {
+		fc.files.MoveToFront(e)
+	}
+
+	return cf.Lines[line-1], nil
+}
+
 // Print prints a disassembly of the file to w.
 // If filter is non-nil, the disassembly only includes functions with names matching filter.
+// If printCode is true, the disassembly includs corresponding source lines.
 // The disassembly only includes functions that overlap the range [start, end).
-func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
+func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool) {
 	if start < d.textStart {
 		start = d.textStart
 	}
@@ -114,6 +192,12 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
 	}
 	printed := false
 	bw := bufio.NewWriter(w)
+
+	var fc *FileCache
+	if printCode {
+		fc = NewFileCache(8)
+	}
+
 	for _, sym := range d.syms {
 		symStart := sym.Addr
 		symEnd := sym.Addr + uint64(sym.Size)
@@ -132,14 +216,32 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
 		file, _, _ := d.pcln.PCToLine(sym.Addr)
 		fmt.Fprintf(bw, "TEXT %s(SB) %s\n", sym.Name, file)
 
-		tw := tabwriter.NewWriter(bw, 1, 8, 1, '\t', 0)
+		tw := tabwriter.NewWriter(bw, 18, 8, 1, '\t', tabwriter.StripEscape)
 		if symEnd > end {
 			symEnd = end
 		}
 		code := d.text[:end-d.textStart]
+
+		var lastFile string
+		var lastLine int
+
 		d.Decode(symStart, symEnd, relocs, func(pc, size uint64, file string, line int, text string) {
 			i := pc - d.textStart
-			fmt.Fprintf(tw, "\t%s:%d\t%#x\t", base(file), line, pc)
+
+			if printCode {
+				if file != lastFile || line != lastLine {
+					if srcLine, err := fc.Line(file, line); err == nil {
+						fmt.Fprintf(tw, "%s%s%s\n", []byte{tabwriter.Escape}, srcLine, []byte{tabwriter.Escape})
+					}
+
+					lastFile, lastLine = file, line
+				}
+
+				fmt.Fprintf(tw, "  %#x\t", pc)
+			} else {
+				fmt.Fprintf(tw, "  %s:%d\t%#x\t", base(file), line, pc)
+			}
+
 			if size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" {
 				// Print instruction as bytes.
 				fmt.Fprintf(tw, "%x", code[i:i+size])
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index c04987c..e075604 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -8,6 +8,7 @@ package objfile
 
 import (
 	"cmd/internal/goobj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"debug/dwarf"
 	"debug/gosym"
@@ -44,16 +45,14 @@ func (f *goobjFile) symbols() ([]Sym, error) {
 		seen[s.SymID] = true
 		sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'}
 		switch s.Kind {
-		case goobj.STEXT, goobj.SELFRXSECT:
+		case objabi.STEXT:
 			sym.Code = 'T'
-		case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SITABLINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT:
+		case objabi.SRODATA:
 			sym.Code = 'R'
-		case goobj.SMACHOPLT, goobj.SELFSECT, goobj.SMACHO, goobj.SMACHOGOT, goobj.SNOPTRDATA, goobj.SINITARR, goobj.SDATA, goobj.SWINDOWS:
+		case objabi.SDATA:
 			sym.Code = 'D'
-		case goobj.SBSS, goobj.SNOPTRBSS, goobj.STLSBSS:
+		case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
 			sym.Code = 'B'
-		case goobj.SXREF, goobj.SMACHOSYMSTR, goobj.SMACHOSYMTAB, goobj.SMACHOINDIRECTPLT, goobj.SMACHOINDIRECTGOT, goobj.SFILE, goobj.SFILEPATH, goobj.SCONST, goobj.SDYNIMPORT, goobj.SHOSTOBJ:
-			sym.Code = 'X' // should not see
 		}
 		if s.Version != 0 {
 			sym.Code += 'a' - 'A'
diff --git a/src/cmd/internal/src/pos.go b/src/cmd/internal/src/pos.go
new file mode 100644
index 0000000..a1ea3fc
--- /dev/null
+++ b/src/cmd/internal/src/pos.go
@@ -0,0 +1,268 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the encoding of source positions.
+
+package src
+
+import "strconv"
+
+// A Pos encodes a source position consisting of a (line, column) number pair
+// and a position base. A zero Pos is a ready to use "unknown" position (nil
+// position base and zero line number).
+//
+// The (line, column) values refer to a position in a file independent of any
+// position base ("absolute" file position).
+//
+// The position base is used to determine the "relative" position, that is the
+// filename and line number relative to the position base. If the base refers
+// to the current file, there is no difference between absolute and relative
+// positions. If it refers to a //line pragma, a relative position is relative
+// to that pragma. A position base in turn contains the position at which it
+// was introduced in the current file.
+type Pos struct {
+	base *PosBase
+	lico
+}
+
+// NoPos is a valid unknown position.
+var NoPos Pos
+
+// MakePos creates a new Pos value with the given base, and (file-absolute)
+// line and column.
+func MakePos(base *PosBase, line, col uint) Pos {
+	return Pos{base, makeLico(line, col)}
+}
+
+// IsKnown reports whether the position p is known.
+// A position is known if it either has a non-nil
+// position base, or a non-zero line number.
+func (p Pos) IsKnown() bool {
+	return p.base != nil || p.Line() != 0
+}
+
+// Before reports whether the position p comes before q in the source.
+// For positions in different files, ordering is by filename.
+func (p Pos) Before(q Pos) bool {
+	n, m := p.Filename(), q.Filename()
+	return n < m || n == m && p.lico < q.lico
+}
+
+// After reports whether the position p comes after q in the source.
+// For positions in different files, ordering is by filename.
+func (p Pos) After(q Pos) bool {
+	n, m := p.Filename(), q.Filename()
+	return n > m || n == m && p.lico > q.lico
+}
+
+// Filename returns the name of the actual file containing this position.
+func (p Pos) Filename() string { return p.base.Pos().RelFilename() }
+
+// Base returns the position base.
+func (p Pos) Base() *PosBase { return p.base }
+
+// SetBase sets the position base.
+func (p *Pos) SetBase(base *PosBase) { p.base = base }
+
+// RelFilename returns the filename recorded with the position's base.
+func (p Pos) RelFilename() string { return p.base.Filename() }
+
+// RelLine returns the line number relative to the positions's base.
+func (p Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() }
+
+// AbsFilename() returns the absolute filename recorded with the position's base.
+func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
+
+// SymFilename() returns the absolute filename recorded with the position's base,
+// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
+func (p Pos) SymFilename() string { return p.base.SymFilename() }
+
+func (p Pos) String() string {
+	return p.Format(true)
+}
+
+// Format formats a position as "filename:line" or "filename:line:column",
+// controlled by the showCol flag.
+// If the position is relative to a line directive, the original position
+// is appended in square brackets without column (since the column doesn't
+// change).
+func (p Pos) Format(showCol bool) string {
+	if !p.IsKnown() {
+		return "<unknown line number>"
+	}
+
+	if b := p.base; b == b.Pos().base {
+		// base is file base (incl. nil)
+		return format(p.Filename(), p.Line(), p.Col(), showCol)
+	}
+
+	// base is relative
+	// Print the column only for the original position since the
+	// relative position's column information may be bogus (it's
+	// typically generated code and we can't say much about the
+	// original source at that point but for the file:line info
+	// that's provided via a line directive).
+	// TODO(gri) This may not be true if we have an inlining base.
+	// We may want to differentiate at some point.
+	return format(p.RelFilename(), p.RelLine(), 0, false) +
+		"[" + format(p.Filename(), p.Line(), p.Col(), showCol) + "]"
+}
+
+// format formats a (filename, line, col) tuple as "filename:line" (showCol
+// is false) or "filename:line:column" (showCol is true).
+func format(filename string, line, col uint, showCol bool) string {
+	s := filename + ":" + strconv.FormatUint(uint64(line), 10)
+	// col == colMax is interpreted as unknown column value
+	if showCol && col < colMax {
+		s += ":" + strconv.FormatUint(uint64(col), 10)
+	}
+	return s
+}
+
+// ----------------------------------------------------------------------------
+// PosBase
+
+// A PosBase encodes a filename and base line number.
+// Typically, each file and line pragma introduce a PosBase.
+// A nil *PosBase is a ready to use file PosBase for an unnamed
+// file with line numbers starting at 1.
+type PosBase struct {
+	pos         Pos
+	filename    string // file name used to open source file, for error messages
+	absFilename string // absolute file name, for PC-Line tables
+	symFilename string // cached symbol file name, to avoid repeated string concatenation
+	line        uint   // relative line number at pos
+	inl         int    // inlining index (see cmd/internal/obj/inl.go)
+}
+
+// NewFileBase returns a new *PosBase for a file with the given (relative and
+// absolute) filenames.
+func NewFileBase(filename, absFilename string) *PosBase {
+	if filename != "" {
+		base := &PosBase{
+			filename:    filename,
+			absFilename: absFilename,
+			symFilename: FileSymPrefix + absFilename,
+			inl:         -1,
+		}
+		base.pos = MakePos(base, 0, 0)
+		return base
+	}
+	return nil
+}
+
+// NewLinePragmaBase returns a new *PosBase for a line pragma of the form
+//      //line filename:line
+// at position pos.
+func NewLinePragmaBase(pos Pos, filename string, line uint) *PosBase {
+	return &PosBase{pos, filename, filename, FileSymPrefix + filename, line - 1, -1}
+}
+
+// NewInliningBase returns a copy of the old PosBase with the given inlining
+// index. If old == nil, the resulting PosBase has no filename.
+func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase {
+	if old == nil {
+		base := &PosBase{inl: inlTreeIndex}
+		base.pos = MakePos(base, 0, 0)
+		return base
+	}
+	copy := *old
+	base := &copy
+	base.inl = inlTreeIndex
+	if old == old.pos.base {
+		base.pos.base = base
+	}
+	return base
+}
+
+var noPos Pos
+
+// Pos returns the position at which base is located.
+// If b == nil, the result is the zero position.
+func (b *PosBase) Pos() *Pos {
+	if b != nil {
+		return &b.pos
+	}
+	return &noPos
+}
+
+// Filename returns the filename recorded with the base.
+// If b == nil, the result is the empty string.
+func (b *PosBase) Filename() string {
+	if b != nil {
+		return b.filename
+	}
+	return ""
+}
+
+// AbsFilename returns the absolute filename recorded with the base.
+// If b == nil, the result is the empty string.
+func (b *PosBase) AbsFilename() string {
+	if b != nil {
+		return b.absFilename
+	}
+	return ""
+}
+
+const FileSymPrefix = "gofile.."
+
+// SymFilename returns the absolute filename recorded with the base,
+// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
+// If b is nil, SymFilename returns FileSymPrefix + "??".
+func (b *PosBase) SymFilename() string {
+	if b != nil {
+		return b.symFilename
+	}
+	return FileSymPrefix + "??"
+}
+
+// Line returns the line number recorded with the base.
+// If b == nil, the result is 0.
+func (b *PosBase) Line() uint {
+	if b != nil {
+		return b.line
+	}
+	return 0
+}
+
+// InliningIndex returns the index into the global inlining
+// tree recorded with the base. If b == nil or the base has
+// not been inlined, the result is < 0.
+func (b *PosBase) InliningIndex() int {
+	if b != nil {
+		return b.inl
+	}
+	return -1
+}
+
+// ----------------------------------------------------------------------------
+// lico
+
+// A lico is a compact encoding of a LIne and COlumn number.
+type lico uint32
+
+// Layout constants: 24 bits for line, 8 bits for column.
+// (If this is too tight, we can either make lico 64b wide,
+// or we can introduce a tiered encoding where we remove column
+// information as line numbers grow bigger; similar to what gcc
+// does.)
+const (
+	lineBits, lineMax = 24, 1<<lineBits - 1
+	colBits, colMax   = 32 - lineBits, 1<<colBits - 1
+)
+
+func makeLico(line, col uint) lico {
+	if line > lineMax {
+		// cannot represent line, use max. line so we have some information
+		line = lineMax
+	}
+	if col > colMax {
+		// cannot represent column, use max. column so we have some information
+		col = colMax
+	}
+	return lico(line<<colBits | col)
+}
+
+func (x lico) Line() uint { return uint(x) >> colBits }
+func (x lico) Col() uint  { return uint(x) & colMax }
diff --git a/src/cmd/internal/src/pos_test.go b/src/cmd/internal/src/pos_test.go
new file mode 100644
index 0000000..a101bc1
--- /dev/null
+++ b/src/cmd/internal/src/pos_test.go
@@ -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.
+
+package src
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestPos(t *testing.T) {
+	f0 := NewFileBase("", "")
+	f1 := NewFileBase("f1", "f1")
+	f2 := NewLinePragmaBase(Pos{}, "f2", 10)
+	f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", 100)
+	f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", 100)
+
+	// line directives from issue #19392
+	fp := NewFileBase("p.go", "p.go")
+	fc := NewLinePragmaBase(MakePos(fp, 3, 0), "c.go", 10)
+	ft := NewLinePragmaBase(MakePos(fp, 6, 0), "t.go", 20)
+	fv := NewLinePragmaBase(MakePos(fp, 9, 0), "v.go", 30)
+	ff := NewLinePragmaBase(MakePos(fp, 12, 0), "f.go", 40)
+
+	for _, test := range []struct {
+		pos    Pos
+		string string
+
+		// absolute info
+		filename  string
+		line, col uint
+
+		// relative info
+		relFilename string
+		relLine     uint
+	}{
+		{Pos{}, "<unknown line number>", "", 0, 0, "", 0},
+		{MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2},
+		{MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2},
+		{MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1},
+		{MakePos(f2, 7, 10), "f2:16[:7:10]", "", 7, 10, "f2", 16},
+		{MakePos(f3, 12, 7), "f3:101[f1:12:7]", "f1", 12, 7, "f3", 101},
+		{MakePos(f4, 25, 1), "f4:114[f3:25:1]", "f3", 25, 1, "f4", 114},
+
+		// positions from issue #19392
+		{MakePos(fc, 4, 0), "c.go:10[p.go:4:0]", "p.go", 4, 0, "c.go", 10},
+		{MakePos(ft, 7, 0), "t.go:20[p.go:7:0]", "p.go", 7, 0, "t.go", 20},
+		{MakePos(fv, 10, 0), "v.go:30[p.go:10:0]", "p.go", 10, 0, "v.go", 30},
+		{MakePos(ff, 13, 0), "f.go:40[p.go:13:0]", "p.go", 13, 0, "f.go", 40},
+	} {
+		pos := test.pos
+		if got := pos.String(); got != test.string {
+			t.Errorf("%s: got %q", test.string, got)
+		}
+
+		// absolute info
+		if got := pos.Filename(); got != test.filename {
+			t.Errorf("%s: got filename %q; want %q", test.string, got, test.filename)
+		}
+		if got := pos.Line(); got != test.line {
+			t.Errorf("%s: got line %d; want %d", test.string, got, test.line)
+		}
+		if got := pos.Col(); got != test.col {
+			t.Errorf("%s: got col %d; want %d", test.string, got, test.col)
+		}
+
+		// relative info
+		if got := pos.RelFilename(); got != test.relFilename {
+			t.Errorf("%s: got relFilename %q; want %q", test.string, got, test.relFilename)
+		}
+		if got := pos.RelLine(); got != test.relLine {
+			t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
+		}
+	}
+}
+
+func TestPredicates(t *testing.T) {
+	b1 := NewFileBase("b1", "b1")
+	b2 := NewFileBase("b2", "b2")
+	for _, test := range []struct {
+		p, q                 Pos
+		known, before, after bool
+	}{
+		{NoPos, NoPos, false, false, false},
+		{NoPos, MakePos(nil, 1, 0), false, true, false},
+		{MakePos(b1, 0, 0), NoPos, true, false, true},
+		{MakePos(nil, 1, 0), NoPos, true, false, true},
+
+		{MakePos(nil, 1, 1), MakePos(nil, 1, 1), true, false, false},
+		{MakePos(nil, 1, 1), MakePos(nil, 1, 2), true, true, false},
+		{MakePos(nil, 1, 2), MakePos(nil, 1, 1), true, false, true},
+		{MakePos(nil, 123, 1), MakePos(nil, 1, 123), true, false, true},
+
+		{MakePos(b1, 1, 1), MakePos(b1, 1, 1), true, false, false},
+		{MakePos(b1, 1, 1), MakePos(b1, 1, 2), true, true, false},
+		{MakePos(b1, 1, 2), MakePos(b1, 1, 1), true, false, true},
+		{MakePos(b1, 123, 1), MakePos(b1, 1, 123), true, false, true},
+
+		{MakePos(b1, 1, 1), MakePos(b2, 1, 1), true, true, false},
+		{MakePos(b1, 1, 1), MakePos(b2, 1, 2), true, true, false},
+		{MakePos(b1, 1, 2), MakePos(b2, 1, 1), true, true, false},
+		{MakePos(b1, 123, 1), MakePos(b2, 1, 123), true, true, false},
+
+		// special case: unknown column (column too large to represent)
+		{MakePos(nil, 1, colMax+10), MakePos(nil, 1, colMax+20), true, false, false},
+	} {
+		if got := test.p.IsKnown(); got != test.known {
+			t.Errorf("%s known: got %v; want %v", test.p, got, test.known)
+		}
+		if got := test.p.Before(test.q); got != test.before {
+			t.Errorf("%s < %s: got %v; want %v", test.p, test.q, got, test.before)
+		}
+		if got := test.p.After(test.q); got != test.after {
+			t.Errorf("%s > %s: got %v; want %v", test.p, test.q, got, test.after)
+		}
+	}
+}
+
+func TestLico(t *testing.T) {
+	for _, test := range []struct {
+		x         lico
+		string    string
+		line, col uint
+	}{
+		{0, ":0:0", 0, 0},
+		{makeLico(0, 0), ":0:0", 0, 0},
+		{makeLico(0, 1), ":0:1", 0, 1},
+		{makeLico(1, 0), ":1:0", 1, 0},
+		{makeLico(1, 1), ":1:1", 1, 1},
+		{makeLico(2, 3), ":2:3", 2, 3},
+		{makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1},
+		{makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, // line too large, stick with max. line
+		{makeLico(1, colMax), ":1", 1, colMax},
+		{makeLico(1, colMax+1), ":1", 1, 0}, // column too large
+		{makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0},
+	} {
+		x := test.x
+		if got := format("", x.Line(), x.Col(), true); got != test.string {
+			t.Errorf("%s: got %q", test.string, got)
+		}
+	}
+}
diff --git a/src/cmd/internal/src/xpos.go b/src/cmd/internal/src/xpos.go
new file mode 100644
index 0000000..db06707
--- /dev/null
+++ b/src/cmd/internal/src/xpos.go
@@ -0,0 +1,75 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the compressed encoding of source
+// positions using a lookup table.
+
+package src
+
+// XPos is a more compact representation of Pos.
+type XPos struct {
+	index int32
+	lico
+}
+
+// NoXPos is a valid unknown position.
+var NoXPos XPos
+
+// IsKnown reports whether the position p is known.
+// XPos.IsKnown() matches Pos.IsKnown() for corresponding
+// positions.
+func (p XPos) IsKnown() bool {
+	return p.index != 0 || p.Line() != 0
+}
+
+// Before reports whether the position p comes before q in the source.
+// For positions with different bases, ordering is by base index.
+func (p XPos) Before(q XPos) bool {
+	n, m := p.index, q.index
+	return n < m || n == m && p.lico < q.lico
+}
+
+// After reports whether the position p comes after q in the source.
+// For positions with different bases, ordering is by base index.
+func (p XPos) After(q XPos) bool {
+	n, m := p.index, q.index
+	return n > m || n == m && p.lico > q.lico
+}
+
+// A PosTable tracks Pos -> XPos conversions and vice versa.
+// Its zero value is a ready-to-use PosTable.
+type PosTable struct {
+	baseList []*PosBase
+	indexMap map[*PosBase]int
+}
+
+// XPos returns the corresponding XPos for the given pos,
+// adding pos to t if necessary.
+func (t *PosTable) XPos(pos Pos) XPos {
+	m := t.indexMap
+	if m == nil {
+		// Create new list and map and populate with nil
+		// base so that NoPos always gets index 0.
+		t.baseList = append(t.baseList, nil)
+		m = map[*PosBase]int{nil: 0}
+		t.indexMap = m
+	}
+	i, ok := m[pos.base]
+	if !ok {
+		i = len(t.baseList)
+		t.baseList = append(t.baseList, pos.base)
+		t.indexMap[pos.base] = i
+	}
+	return XPos{int32(i), pos.lico}
+}
+
+// Pos returns the corresponding Pos for the given p.
+// If p cannot be translated via t, the function panics.
+func (t *PosTable) Pos(p XPos) Pos {
+	var base *PosBase
+	if p.index != 0 {
+		base = t.baseList[p.index]
+	}
+	return Pos{base, p.lico}
+}
diff --git a/src/cmd/internal/src/xpos_test.go b/src/cmd/internal/src/xpos_test.go
new file mode 100644
index 0000000..4cfeedc
--- /dev/null
+++ b/src/cmd/internal/src/xpos_test.go
@@ -0,0 +1,84 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package src
+
+import (
+	"testing"
+	"unsafe"
+)
+
+func TestNoXPos(t *testing.T) {
+	var tab PosTable
+	if tab.Pos(NoXPos) != NoPos {
+		t.Errorf("failed to translate NoXPos to Pos using zero PosTable")
+	}
+}
+
+func TestConversion(t *testing.T) {
+	b1 := NewFileBase("b1", "b1")
+	b2 := NewFileBase("b2", "b2")
+	b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", 123)
+
+	var tab PosTable
+	for _, want := range []Pos{
+		NoPos,
+		MakePos(nil, 0, 0), // same table entry as NoPos
+		MakePos(b1, 0, 0),
+		MakePos(nil, 10, 20), // same table entry as NoPos
+		MakePos(b2, 10, 20),
+		MakePos(b3, 10, 20),
+		MakePos(b3, 123, 0), // same table entry as MakePos(b3, 10, 20)
+	} {
+		xpos := tab.XPos(want)
+		got := tab.Pos(xpos)
+		if got != want {
+			t.Errorf("got %v; want %v", got, want)
+		}
+	}
+
+	if len(tab.baseList) != len(tab.indexMap) {
+		t.Errorf("table length discrepancy: %d != %d", len(tab.baseList), len(tab.indexMap))
+	}
+
+	const wantLen = 4
+	if len(tab.baseList) != wantLen {
+		t.Errorf("got table length %d; want %d", len(tab.baseList), wantLen)
+	}
+
+	if got := tab.XPos(NoPos); got != NoXPos {
+		t.Errorf("XPos(NoPos): got %v; want %v", got, NoXPos)
+	}
+
+	if tab.baseList[0] != nil || tab.indexMap[nil] != 0 {
+		t.Errorf("nil base not at index 0")
+	}
+}
+
+func TestSize(t *testing.T) {
+	var p XPos
+	if unsafe.Alignof(p) != 4 {
+		t.Errorf("alignment = %v; want 4", unsafe.Alignof(p))
+	}
+	if unsafe.Sizeof(p) != 8 {
+		t.Errorf("size = %v; want 8", unsafe.Sizeof(p))
+	}
+}
+
+func TestSetBase(t *testing.T) {
+	var tab PosTable
+	b1 := NewFileBase("b1", "b1")
+	orig := MakePos(b1, 42, 7)
+	xpos := tab.XPos(orig)
+
+	pos := tab.Pos(xpos)
+	new := NewInliningBase(b1, 2)
+	pos.SetBase(new)
+	xpos = tab.XPos(pos)
+
+	pos = tab.Pos(xpos)
+	if inl := pos.Base().InliningIndex(); inl != 2 {
+		t.Fatalf("wrong inlining index: %d", inl)
+	}
+}
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
index 22c8c32..c761a83 100644
--- a/src/cmd/internal/sys/arch.go
+++ b/src/cmd/internal/sys/arch.go
@@ -12,7 +12,8 @@ import "encoding/binary"
 type ArchFamily byte
 
 const (
-	AMD64 ArchFamily = iota
+	NoArch ArchFamily = iota
+	AMD64
 	ARM
 	ARM64
 	I386
@@ -29,8 +30,11 @@ type Arch struct {
 
 	ByteOrder binary.ByteOrder
 
-	IntSize int
+	// PtrSize is the size in bytes of pointers and the
+	// predeclared "int", "uint", and "uintptr" types.
 	PtrSize int
+
+	// RegSize is the size in bytes of general purpose registers.
 	RegSize int
 
 	// MinLC is the minimum length of an instruction code.
@@ -52,7 +56,6 @@ var Arch386 = &Arch{
 	Name:      "386",
 	Family:    I386,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   4,
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     1,
@@ -62,7 +65,6 @@ var ArchAMD64 = &Arch{
 	Name:      "amd64",
 	Family:    AMD64,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     1,
@@ -72,7 +74,6 @@ var ArchAMD64P32 = &Arch{
 	Name:      "amd64p32",
 	Family:    AMD64,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   4,
 	PtrSize:   4,
 	RegSize:   8,
 	MinLC:     1,
@@ -82,7 +83,6 @@ var ArchARM = &Arch{
 	Name:      "arm",
 	Family:    ARM,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   4,
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
@@ -92,7 +92,6 @@ var ArchARM64 = &Arch{
 	Name:      "arm64",
 	Family:    ARM64,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
@@ -102,7 +101,6 @@ var ArchMIPS = &Arch{
 	Name:      "mips",
 	Family:    MIPS,
 	ByteOrder: binary.BigEndian,
-	IntSize:   4,
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
@@ -112,7 +110,6 @@ var ArchMIPSLE = &Arch{
 	Name:      "mipsle",
 	Family:    MIPS,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   4,
 	PtrSize:   4,
 	RegSize:   4,
 	MinLC:     4,
@@ -122,7 +119,6 @@ var ArchMIPS64 = &Arch{
 	Name:      "mips64",
 	Family:    MIPS64,
 	ByteOrder: binary.BigEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
@@ -132,7 +128,6 @@ var ArchMIPS64LE = &Arch{
 	Name:      "mips64le",
 	Family:    MIPS64,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
@@ -142,7 +137,6 @@ var ArchPPC64 = &Arch{
 	Name:      "ppc64",
 	Family:    PPC64,
 	ByteOrder: binary.BigEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
@@ -152,7 +146,6 @@ var ArchPPC64LE = &Arch{
 	Name:      "ppc64le",
 	Family:    PPC64,
 	ByteOrder: binary.LittleEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     4,
@@ -162,7 +155,6 @@ var ArchS390X = &Arch{
 	Name:      "s390x",
 	Family:    S390X,
 	ByteOrder: binary.BigEndian,
-	IntSize:   8,
 	PtrSize:   8,
 	RegSize:   8,
 	MinLC:     2,
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 32fa3a3..f88aecc 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -20,10 +20,6 @@ import (
 )
 
 func TestDWARF(t *testing.T) {
-	if runtime.GOOS == "windows" {
-		t.Skip("DWARF is not supported on Windows")
-	}
-
 	testenv.MustHaveCGO(t)
 	testenv.MustHaveGoBuild(t)
 
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index 60bd45c..03bd594 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -31,7 +31,7 @@
 package amd64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"debug/elf"
 	"log"
@@ -49,7 +49,7 @@ func Addcall(ctxt *ld.Link, s *ld.Symbol, t *ld.Symbol) int64 {
 	r := ld.Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
-	r.Type = obj.R_CALL
+	r.Type = objabi.R_CALL
 	r.Siz = 4
 	return i + int64(r.Siz)
 }
@@ -59,14 +59,14 @@ func gentext(ctxt *ld.Link) {
 		return
 	}
 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT && ld.Buildmode != ld.BuildmodePlugin {
+	if addmoduledata.Type == ld.STEXT && ld.Buildmode != ld.BuildmodePlugin {
 		// we're linking a module containing the runtime -> no need for
 		// an init function
 		return
 	}
 	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 	o := func(op ...uint8) {
@@ -92,7 +92,7 @@ func gentext(ctxt *ld.Link) {
 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
 	initarray_entry.Attr |= ld.AttrReachable
 	initarray_entry.Attr |= ld.AttrLocal
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -108,20 +108,20 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_X86_64_PC32:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
 		}
-		if targ.Type == 0 || targ.Type == obj.SXREF {
+		if targ.Type == 0 || targ.Type == ld.SXREF {
 			ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
 		}
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += 4
 		return true
 
 	case 256 + ld.R_X86_64_PLT32:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += 4
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -130,13 +130,13 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 
 	case 256 + ld.R_X86_64_GOTPCREL, 256 + ld.R_X86_64_GOTPCRELX, 256 + ld.R_X86_64_REX_GOTPCRELX:
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			// have symbol
 			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
 				// turn MOVQ of GOT entry into LEAQ of symbol itself
 				s.P[r.Off-2] = 0x8d
 
-				r.Type = obj.R_PCREL
+				r.Type = objabi.R_PCREL
 				r.Add += 4
 				return true
 			}
@@ -146,17 +146,17 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		// TODO: just needs relocation, no need to put in .dynsym
 		addgotsym(ctxt, targ)
 
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += 4
 		r.Add += int64(targ.Got)
 		return true
 
 	case 256 + ld.R_X86_64_64:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 		return true
 
 	// Handle relocations found in Mach-O object files.
@@ -164,19 +164,19 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
 		512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
 		// TODO: What is the difference between all these?
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
 		}
 		return true
 
 	case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add = int64(targ.Plt)
-			r.Type = obj.R_PCREL
+			r.Type = objabi.R_PCREL
 			return true
 		}
 		fallthrough
@@ -187,15 +187,15 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
 		}
 		return true
 
 	case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			// have symbol
 			// turn MOVQ of GOT entry into LEAQ of symbol itself
 			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
@@ -204,31 +204,31 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			}
 
 			s.P[r.Off-2] = 0x8d
-			r.Type = obj.R_PCREL
+			r.Type = objabi.R_PCREL
 			return true
 		}
 		fallthrough
 
 		// fall through
 	case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
 		}
 		addgotsym(ctxt, targ)
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(targ.Got)
 		return true
 	}
 
 	switch r.Type {
-	case obj.R_CALL,
-		obj.R_PCREL:
-		if targ.Type != obj.SDYNIMPORT {
+	case objabi.R_CALL,
+		objabi.R_PCREL:
+		if targ.Type != ld.SDYNIMPORT {
 			// nothing to do, the relocation will be laid out in reloc
 			return true
 		}
-		if ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui {
+		if ld.Headtype == objabi.Hwindows {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return true
 		} else {
@@ -239,9 +239,9 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			return true
 		}
 
-	case obj.R_ADDR:
-		if s.Type == obj.STEXT && ld.Iself {
-			if ld.Headtype == obj.Hsolaris {
+	case objabi.R_ADDR:
+		if s.Type == ld.STEXT && ld.Iself {
+			if ld.Headtype == objabi.Hsolaris {
 				addpltsym(ctxt, targ)
 				r.Sym = ctxt.Syms.Lookup(".plt", 0)
 				r.Add += int64(targ.Plt)
@@ -294,7 +294,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			// linking, in which case the relocation will be
 			// prepared in the 'reloc' phase and passed to the
 			// external linker in the 'asmb' phase.
-			if s.Type != obj.SDATA && s.Type != obj.SRODATA {
+			if s.Type != ld.SDATA && s.Type != ld.SRODATA {
 				break
 			}
 		}
@@ -317,7 +317,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			return true
 		}
 
-		if ld.Headtype == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
+		if ld.Headtype == objabi.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.
@@ -331,7 +331,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			ld.Adddynsym(ctxt, targ)
 
 			got := ctxt.Syms.Lookup(".got", 0)
-			s.Type = got.Type | obj.SSUB
+			s.Type = got.Type | ld.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
 			got.Sub = s
@@ -342,7 +342,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			return true
 		}
 
-		if ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui {
+		if ld.Headtype == objabi.Hwindows {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return true
 		}
@@ -359,7 +359,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
 		} else if r.Siz == 8 {
@@ -368,23 +368,23 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_TLS_LE:
+	case objabi.R_TLS_LE:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
 		} else {
 			return -1
 		}
 
-	case obj.R_TLS_IE:
+	case objabi.R_TLS_IE:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
 		} else {
 			return -1
 		}
 
-	case obj.R_CALL:
+	case objabi.R_CALL:
 		if r.Siz == 4 {
-			if r.Xsym.Type == obj.SDYNIMPORT {
+			if r.Xsym.Type == ld.SDYNIMPORT {
 				if ctxt.DynlinkingGo() {
 					ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
 				} else {
@@ -397,9 +397,9 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_PCREL:
+	case objabi.R_PCREL:
 		if r.Siz == 4 {
-			if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
+			if r.Xsym.Type == ld.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
 				ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
 			} else {
 				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
@@ -408,7 +408,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_GOTPCREL:
+	case objabi.R_GOTPCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
 		} else {
@@ -425,7 +425,7 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 
 	rs := r.Xsym
 
-	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL || r.Type == obj.R_GOTPCREL {
+	if rs.Type == ld.SHOSTOBJ || r.Type == objabi.R_PCREL || r.Type == objabi.R_GOTPCREL {
 		if rs.Dynid < 0 {
 			ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -445,18 +445,18 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
 
-	case obj.R_CALL:
+	case objabi.R_CALL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
 
 		// NOTE: Only works with 'external' relocation. Forced above.
-	case obj.R_PCREL:
+	case objabi.R_PCREL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
-	case obj.R_GOTPCREL:
+	case objabi.R_GOTPCREL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
 	}
@@ -500,15 +500,18 @@ func pereloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) bool {
 	default:
 		return false
 
-	case obj.R_ADDR:
+	case objabi.R_DWARFREF:
+		v = ld.IMAGE_REL_AMD64_SECREL
+
+	case objabi.R_ADDR:
 		if r.Siz == 8 {
 			v = ld.IMAGE_REL_AMD64_ADDR64
 		} else {
 			v = ld.IMAGE_REL_AMD64_ADDR32
 		}
 
-	case obj.R_CALL,
-		obj.R_PCREL:
+	case objabi.R_CALL,
+		objabi.R_PCREL:
 		v = ld.IMAGE_REL_AMD64_REL32
 	}
 
@@ -594,7 +597,7 @@ func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
 		ld.Adduint64(ctxt, rela, 0)
 
 		s.Plt = int32(plt.Size - 16)
-	} else if ld.Headtype == obj.Hdarwin {
+	} else if ld.Headtype == objabi.Hdarwin {
 		// To do lazy symbol lookup right, we're supposed
 		// to tell the dynamic loader which library each
 		// symbol comes from and format the link info
@@ -636,7 +639,7 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 		ld.Addaddrplus(ctxt, rela, got, int64(s.Got))
 		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
 		ld.Adduint64(ctxt, rela, 0)
-	} else if ld.Headtype == obj.Hdarwin {
+	} else if ld.Headtype == objabi.Hdarwin {
 		ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(s.Dynid))
 	} else {
 		ld.Errorf(s, "addgotsym: unsupported binary format")
@@ -645,43 +648,43 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f codeblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f codeblk\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	// 0xCC is INT $3 - breakpoint instruction
 	ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -691,7 +694,7 @@ func asmb(ctxt *ld.Link) {
 	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
 
 	machlink := int64(0)
-	if ld.Headtype == obj.Hdarwin {
+	if ld.Headtype == objabi.Hdarwin {
 		machlink = ld.Domacholink(ctxt)
 	}
 
@@ -700,23 +703,22 @@ func asmb(ctxt *ld.Link) {
 		ld.Errorf(nil, "unknown header type %v", ld.Headtype)
 		fallthrough
 
-	case obj.Hplan9:
+	case objabi.Hplan9:
 		break
 
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		ld.Flag8 = true /* 64-bit addresses */
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hdragonfly,
-		obj.Hsolaris:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hdragonfly,
+		objabi.Hsolaris:
 		ld.Flag8 = true /* 64-bit addresses */
 
-	case obj.Hnacl,
-		obj.Hwindows,
-		obj.Hwindowsgui:
+	case objabi.Hnacl,
+		objabi.Hwindows:
 		break
 	}
 
@@ -726,29 +728,28 @@ func asmb(ctxt *ld.Link) {
 	symo := int64(0)
 	if !*ld.FlagS {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			*ld.FlagS = true
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
 
-		case obj.Hlinux,
-			obj.Hfreebsd,
-			obj.Hnetbsd,
-			obj.Hopenbsd,
-			obj.Hdragonfly,
-			obj.Hsolaris,
-			obj.Hnacl:
+		case objabi.Hlinux,
+			objabi.Hfreebsd,
+			objabi.Hnetbsd,
+			objabi.Hopenbsd,
+			objabi.Hdragonfly,
+			objabi.Hsolaris,
+			objabi.Hnacl:
 			symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = ld.Rnd(symo, int64(*ld.FlagRound))
 
-		case obj.Hwindows,
-			obj.Hwindowsgui:
+		case objabi.Hwindows:
 			symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = ld.Rnd(symo, ld.PEFILEALIGN)
 		}
@@ -763,7 +764,7 @@ func asmb(ctxt *ld.Link) {
 				ld.Cwrite(ld.Elfstrdat)
 
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+					ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
 				}
 
 				if ld.Linkmode == ld.LinkExternal {
@@ -771,7 +772,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -785,12 +786,12 @@ func asmb(ctxt *ld.Link) {
 				ld.Cflush()
 			}
 
-		case obj.Hwindows, obj.Hwindowsgui:
+		case objabi.Hwindows:
 			if ctxt.Debugvlog != 0 {
-				ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+				ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
 			}
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc(ctxt)
 			}
@@ -798,12 +799,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f headr\n", obj.Cputime())
+		ctxt.Logf("%5.2f headr\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan9 */
+	case objabi.Hplan9: /* plan9 */
 		magic := int32(4*26*26 + 7)
 
 		magic |= 0x00008000                  /* fat header */
@@ -818,20 +819,19 @@ func asmb(ctxt *ld.Link) {
 		ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
 		ld.Vputb(uint64(vl))        /* va of entry */
 
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		ld.Asmbmacho(ctxt)
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hdragonfly,
-		obj.Hsolaris,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hdragonfly,
+		objabi.Hsolaris,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, symo)
 
-	case obj.Hwindows,
-		obj.Hwindowsgui:
+	case objabi.Hwindows:
 		ld.Asmbpe(ctxt)
 	}
 
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index 9646b60..ef69c26 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -31,7 +31,7 @@
 package amd64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -39,7 +39,7 @@ import (
 
 func Init() {
 	ld.SysArch = sys.ArchAMD64
-	if obj.GOARCH == "amd64p32" {
+	if objabi.GOARCH == "amd64p32" {
 		ld.SysArch = sys.ArchAMD64P32
 	}
 
@@ -80,7 +80,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32 + 8
 
 		if *ld.FlagTextAddr == -1 {
@@ -93,7 +93,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x200000
 		}
 
-	case obj.Hdarwin: /* apple MACH */
+	case objabi.Hdarwin: /* apple MACH */
 		ld.Machoinit()
 
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -107,12 +107,12 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagDataAddr = 0
 		}
 
-	case obj.Hlinux, /* elf64 executable */
-		obj.Hfreebsd,   /* freebsd */
-		obj.Hnetbsd,    /* netbsd */
-		obj.Hopenbsd,   /* openbsd */
-		obj.Hdragonfly, /* dragonfly */
-		obj.Hsolaris:   /* solaris */
+	case objabi.Hlinux, /* elf64 executable */
+		objabi.Hfreebsd,   /* freebsd */
+		objabi.Hnetbsd,    /* netbsd */
+		objabi.Hopenbsd,   /* openbsd */
+		objabi.Hdragonfly, /* dragonfly */
+		objabi.Hsolaris:   /* solaris */
 		ld.Elfinit(ctxt)
 
 		ld.HEADR = ld.ELFRESERVE
@@ -126,7 +126,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		*ld.FlagW = true // disable dwarf, which gets confused and is useless anyway
 		ld.HEADR = 0x10000
@@ -141,19 +141,9 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hwindows, obj.Hwindowsgui: /* PE executable */
-		ld.Peinit(ctxt)
-
-		ld.HEADR = ld.PEFILEHEADR
-		if *ld.FlagTextAddr == -1 {
-			*ld.FlagTextAddr = ld.PEBASE + int64(ld.PESECTHEADR)
-		}
-		if *ld.FlagDataAddr == -1 {
-			*ld.FlagDataAddr = 0
-		}
-		if *ld.FlagRound == -1 {
-			*ld.FlagRound = ld.PESECTALIGN
-		}
+	case objabi.Hwindows: /* PE executable */
+		// ld.HEADR, ld.FlagTextAddr, ld.FlagDataAddr and ld.FlagRound are set in ld.Peinit
+		return
 	}
 
 	if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index ee57df1..0f281c1 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -31,7 +31,7 @@
 package arm
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -63,14 +63,14 @@ func gentext(ctxt *ld.Link) {
 		return
 	}
 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT && ld.Buildmode != ld.BuildmodePlugin {
+	if addmoduledata.Type == ld.STEXT && ld.Buildmode != ld.BuildmodePlugin {
 		// we're linking a module containing the runtime -> no need for
 		// an init function
 		return
 	}
 	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
@@ -84,7 +84,7 @@ func gentext(ctxt *ld.Link) {
 	rel.Off = 8
 	rel.Siz = 4
 	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	rel.Type = obj.R_CALLARM
+	rel.Type = objabi.R_CALLARM
 	rel.Add = 0xeafffffe // vomit
 
 	o(0x00000000)
@@ -92,7 +92,7 @@ func gentext(ctxt *ld.Link) {
 	rel.Off = 12
 	rel.Siz = 4
 	rel.Sym = ctxt.Moduledata
-	rel.Type = obj.R_PCREL
+	rel.Type = objabi.R_PCREL
 	rel.Add = 4
 
 	if ld.Buildmode == ld.BuildmodePlugin {
@@ -102,7 +102,7 @@ func gentext(ctxt *ld.Link) {
 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
 	initarray_entry.Attr |= ld.AttrReachable
 	initarray_entry.Attr |= ld.AttrLocal
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -124,9 +124,9 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_ARM_PLT32:
-		r.Type = obj.R_CALLARM
+		r.Type = objabi.R_CALLARM
 
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -139,44 +139,44 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return false
 
 	case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			addgotsyminternal(ctxt, targ)
 		} else {
 			addgotsym(ctxt, targ)
 		}
 
-		r.Type = obj.R_CONST // write r->add during relocsym
+		r.Type = objabi.R_CONST // write r->add during relocsym
 		r.Sym = nil
 		r.Add += int64(targ.Got)
 		return true
 
 	case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			addgotsyminternal(ctxt, targ)
 		} else {
 			addgotsym(ctxt, targ)
 		}
 
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(targ.Got) + 4
 		return true
 
 	case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
-		r.Type = obj.R_GOTOFF
+		r.Type = objabi.R_GOTOFF
 
 		return true
 
 	case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += 4
 		return true
 
 	case 256 + ld.R_ARM_CALL:
-		r.Type = obj.R_CALLARM
-		if targ.Type == obj.SDYNIMPORT {
+		r.Type = objabi.R_CALLARM
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -185,16 +185,16 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 
 	case 256 + ld.R_ARM_REL32: // R_ARM_REL32
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 
 		r.Add += 4
 		return true
 
 	case 256 + ld.R_ARM_ABS32:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 		return true
 
 		// we can just ignore this, because we are targeting ARM V5+ anyway
@@ -209,8 +209,8 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 	case 256 + ld.R_ARM_PC24,
 		256 + ld.R_ARM_JUMP24:
-		r.Type = obj.R_CALLARM
-		if targ.Type == obj.SDYNIMPORT {
+		r.Type = objabi.R_CALLARM
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -220,19 +220,19 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != obj.SDYNIMPORT {
+	if targ.Type != ld.SDYNIMPORT {
 		return true
 	}
 
 	switch r.Type {
-	case obj.R_CALLARM:
+	case objabi.R_CALLARM:
 		addpltsym(ctxt, targ)
 		r.Sym = ctxt.Syms.Lookup(".plt", 0)
 		r.Add = int64(targ.Plt)
 		return true
 
-	case obj.R_ADDR:
-		if s.Type != obj.SDATA {
+	case objabi.R_ADDR:
+		if s.Type != ld.SDATA {
 			break
 		}
 		if ld.Iself {
@@ -240,7 +240,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			rel := ctxt.Syms.Lookup(".rel", 0)
 			ld.Addaddrplus(ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynamic reloc
-			r.Type = obj.R_CONST                                                            // write r->add during relocsym
+			r.Type = objabi.R_CONST                                                         // write r->add during relocsym
 			r.Sym = nil
 			return true
 		}
@@ -257,21 +257,21 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case obj.R_PCREL:
+	case objabi.R_PCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case obj.R_CALLARM:
+	case objabi.R_CALLARM:
 		if r.Siz == 4 {
 			if r.Add&0xff000000 == 0xeb000000 { // BL
 				ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
@@ -282,13 +282,13 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_TLS_LE:
+	case objabi.R_TLS_LE:
 		ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
 
-	case obj.R_TLS_IE:
+	case objabi.R_TLS_IE:
 		ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
 
-	case obj.R_GOTPCREL:
+	case objabi.R_GOTPCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_ARM_GOT_PREL | uint32(elfsym)<<8)
 		} else {
@@ -331,8 +331,8 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 
 	rs := r.Xsym
 
-	if r.Type == obj.R_PCREL {
-		if rs.Type == obj.SHOSTOBJ {
+	if r.Type == objabi.R_PCREL {
+		if rs.Type == ld.SHOSTOBJ {
 			ld.Errorf(s, "pc-relative relocation of external symbol is not supported")
 			return -1
 		}
@@ -361,7 +361,7 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 		return 0
 	}
 
-	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
+	if rs.Type == ld.SHOSTOBJ || r.Type == objabi.R_CALLARM {
 		if rs.Dynid < 0 {
 			ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -381,10 +381,10 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 
-	case obj.R_CALLARM:
+	case objabi.R_CALLARM:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_ARM_RELOC_BR24 << 28
 	}
@@ -430,7 +430,7 @@ func immrot(v uint32) uint32 {
 // Convert the direct jump relocation r to refer to a trampoline if the target is too far
 func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
 	switch r.Type {
-	case obj.R_CALLARM:
+	case objabi.R_CALLARM:
 		// r.Add is the instruction
 		// low 24-bit encodes the target address
 		t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
@@ -443,7 +443,7 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
 			for i := 0; ; i++ {
 				name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
 				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
-				if tramp.Type == obj.SDYNIMPORT {
+				if tramp.Type == ld.SDYNIMPORT {
 					// don't reuse trampoline defined in other module
 					continue
 				}
@@ -500,7 +500,7 @@ func gentramp(tramp, target *ld.Symbol, offset int64) {
 	if ld.Linkmode == ld.LinkExternal {
 		r := ld.Addrel(tramp)
 		r.Off = 8
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 		r.Siz = 4
 		r.Sym = target
 		r.Add = offset
@@ -522,7 +522,7 @@ func gentramppic(tramp, target *ld.Symbol, offset int64) {
 
 	r := ld.Addrel(tramp)
 	r.Off = 12
-	r.Type = obj.R_PCREL
+	r.Type = objabi.R_PCREL
 	r.Siz = 4
 	r.Sym = target
 	r.Add = offset + 4
@@ -557,7 +557,7 @@ func gentrampdyn(tramp, target *ld.Symbol, offset int64) {
 
 	r := ld.Addrel(tramp)
 	r.Off = 16
-	r.Type = obj.R_GOTPCREL
+	r.Type = objabi.R_GOTPCREL
 	r.Siz = 4
 	r.Sym = target
 	r.Add = 8
@@ -571,7 +571,7 @@ func gentrampdyn(tramp, target *ld.Symbol, offset int64) {
 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
 		switch r.Type {
-		case obj.R_CALLARM:
+		case objabi.R_CALLARM:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
@@ -584,7 +584,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 				rs = rs.Outer
 			}
 
-			if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
 				ld.Errorf(s, "missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
@@ -594,7 +594,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 			// the section load address.
 			// we need to compensate that by removing the instruction's address
 			// from addend.
-			if ld.Headtype == obj.Hdarwin {
+			if ld.Headtype == objabi.Hdarwin {
 				r.Xadd -= ld.Symaddr(s) + int64(r.Off)
 			}
 
@@ -610,34 +610,34 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 
 	// The following three arch specific relocations are only for generation of
 	// Linux/ARM ELF's PLT entry (3 assembler instruction)
-	case obj.R_PLT0: // add ip, pc, #0xXX00000
+	case objabi.R_PLT0: // add ip, pc, #0xXX00000
 		if ld.Symaddr(ctxt.Syms.Lookup(".got.plt", 0)) < ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) {
 			ld.Errorf(s, ".got.plt should be placed after .plt section.")
 		}
 		*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20))
 		return 0
 
-	case obj.R_PLT1: // add ip, ip, #0xYY000
+	case objabi.R_PLT1: // add ip, ip, #0xYY000
 		*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
 
 		return 0
 
-	case obj.R_PLT2: // ldr pc, [ip, #0xZZZ]!
+	case objabi.R_PLT2: // ldr pc, [ip, #0xZZZ]!
 		*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8)))
 
 		return 0
 
-	case obj.R_CALLARM: // bl XXXXXX or b YYYYYY
+	case objabi.R_CALLARM: // bl XXXXXX or b YYYYYY
 		// r.Add is the instruction
 		// low 24-bit encodes the target address
 		t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
@@ -657,7 +657,7 @@ func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
 	return t
 }
 
-func addpltreloc(ctxt *ld.Link, plt *ld.Symbol, got *ld.Symbol, sym *ld.Symbol, typ obj.RelocType) *ld.Reloc {
+func addpltreloc(ctxt *ld.Link, plt *ld.Symbol, got *ld.Symbol, sym *ld.Symbol, typ objabi.RelocType) *ld.Reloc {
 	r := ld.Addrel(plt)
 	r.Sym = got
 	r.Off = int32(plt.Size)
@@ -698,9 +698,9 @@ func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
 		// .plt entry, this depends on the .got entry
 		s.Plt = int32(plt.Size)
 
-		addpltreloc(ctxt, plt, got, s, obj.R_PLT0) // add lr, pc, #0xXX00000
-		addpltreloc(ctxt, plt, got, s, obj.R_PLT1) // add lr, lr, #0xYY000
-		addpltreloc(ctxt, plt, got, s, obj.R_PLT2) // ldr pc, [lr, #0xZZZ]!
+		addpltreloc(ctxt, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
+		addpltreloc(ctxt, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
+		addpltreloc(ctxt, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
 
 		// rel
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
@@ -748,38 +748,38 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -789,7 +789,7 @@ func asmb(ctxt *ld.Link) {
 	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
 
 	machlink := uint32(0)
-	if ld.Headtype == obj.Hdarwin {
+	if ld.Headtype == objabi.Hdarwin {
 		machlink = uint32(ld.Domacholink(ctxt))
 	}
 
@@ -801,7 +801,7 @@ func asmb(ctxt *ld.Link) {
 	if !*ld.FlagS {
 		// TODO: rationalize
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
@@ -810,10 +810,10 @@ func asmb(ctxt *ld.Link) {
 				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
 		}
 
@@ -822,7 +822,7 @@ func asmb(ctxt *ld.Link) {
 		default:
 			if ld.Iself {
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 				}
 				ld.Asmelfsym(ctxt)
 				ld.Cflush()
@@ -833,7 +833,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -847,7 +847,7 @@ func asmb(ctxt *ld.Link) {
 				ld.Cflush()
 			}
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc(ctxt)
 			}
@@ -855,12 +855,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.Lputb(0x647)                      /* magic */
 		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Lputb(uint32(ld.Segdata.Filelen))
@@ -870,14 +870,14 @@ func asmb(ctxt *ld.Link) {
 		ld.Lputb(0)
 		ld.Lputb(uint32(ld.Lcsize))
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, int64(symo))
 
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		ld.Asmbmacho(ctxt)
 	}
 
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index 05b90d2..2975e5d 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -31,7 +31,7 @@
 package arm
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -76,7 +76,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if *ld.FlagTextAddr == -1 {
@@ -89,10 +89,10 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hlinux, /* arm elf */
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd:
+	case objabi.Hlinux, /* arm elf */
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd:
 		*ld.FlagD = false
 		// with dynamic linking
 		ld.Elfinit(ctxt)
@@ -107,7 +107,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
@@ -121,7 +121,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hdarwin: /* apple MACH */
+	case objabi.Hdarwin: /* apple MACH */
 		*ld.FlagW = true // disable DWARF generation
 		ld.Machoinit()
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 118a575..92a87f9 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -31,7 +31,7 @@
 package arm64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"encoding/binary"
 	"fmt"
@@ -43,14 +43,14 @@ func gentext(ctxt *ld.Link) {
 		return
 	}
 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT {
+	if addmoduledata.Type == ld.STEXT {
 		// we're linking a module containing the runtime -> no need for
 		// an init function
 		return
 	}
 	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
@@ -67,7 +67,7 @@ func gentext(ctxt *ld.Link) {
 	rel.Off = 0
 	rel.Siz = 8
 	rel.Sym = ctxt.Moduledata
-	rel.Type = obj.R_ADDRARM64
+	rel.Type = objabi.R_ADDRARM64
 
 	// 8:	14000000 	bl	0 <runtime.addmoduledata>
 	// 	8: R_AARCH64_CALL26	runtime.addmoduledata
@@ -76,13 +76,13 @@ func gentext(ctxt *ld.Link) {
 	rel.Off = 8
 	rel.Siz = 4
 	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
+	rel.Type = objabi.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
 
 	ctxt.Textp = append(ctxt.Textp, initfunc)
 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
 	initarray_entry.Attr |= ld.AttrReachable
 	initarray_entry.Attr |= ld.AttrLocal
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -99,7 +99,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		switch r.Siz {
 		case 4:
 			ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32)
@@ -109,29 +109,29 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_ADDRARM64:
+	case objabi.R_ADDRARM64:
 		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
 		ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32)
 
-	case obj.R_ARM64_TLS_LE:
+	case objabi.R_ARM64_TLS_LE:
 		ld.Thearch.Vput(ld.R_AARCH64_TLSLE_MOVW_TPREL_G0 | uint64(elfsym)<<32)
 
-	case obj.R_ARM64_TLS_IE:
+	case objabi.R_ARM64_TLS_IE:
 		ld.Thearch.Vput(ld.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC | uint64(elfsym)<<32)
 
-	case obj.R_ARM64_GOTPCREL:
+	case objabi.R_ARM64_GOTPCREL:
 		ld.Thearch.Vput(ld.R_AARCH64_ADR_GOT_PAGE | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_AARCH64_LD64_GOT_LO12_NC | uint64(elfsym)<<32)
 
-	case obj.R_CALLARM64:
+	case objabi.R_CALLARM64:
 		if r.Siz != 4 {
 			return -1
 		}
@@ -156,7 +156,7 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 	// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
 	// 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.Type == ld.SHOSTOBJ || r.Type == objabi.R_CALLARM64 || r.Type == objabi.R_ADDRARM64 || r.Type == objabi.R_ADDR {
 		if rs.Dynid < 0 {
 			ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -176,10 +176,10 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
 
-	case obj.R_CALLARM64:
+	case objabi.R_CALLARM64:
 		if r.Xadd != 0 {
 			ld.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
 		}
@@ -187,7 +187,7 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
 
-	case obj.R_ADDRARM64:
+	case objabi.R_ADDRARM64:
 		r.Siz = 4
 		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
 		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
@@ -233,7 +233,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		default:
 			return -1
 
-		case obj.R_ARM64_GOTPCREL:
+		case objabi.R_ARM64_GOTPCREL:
 			var o1, o2 uint32
 			if ctxt.Arch.ByteOrder == binary.BigEndian {
 				o1 = uint32(*val >> 32)
@@ -250,12 +250,12 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, 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.Attr.Local()) && r.Sym.Type == obj.STEXT && ctxt.DynlinkingGo() {
+			if !(r.Sym.Version != 0 || (r.Sym.Type&ld.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == ld.STEXT && ctxt.DynlinkingGo() {
 				if o2&0xffc00000 != 0xf9400000 {
 					ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
 				}
 				o2 = 0x91000000 | (o2 & 0x000003ff)
-				r.Type = obj.R_ADDRARM64
+				r.Type = objabi.R_ADDRARM64
 			}
 			if ctxt.Arch.ByteOrder == binary.BigEndian {
 				*val = int64(o1)<<32 | int64(o2)
@@ -264,7 +264,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 			}
 			fallthrough
 
-		case obj.R_ADDRARM64:
+		case objabi.R_ADDRARM64:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
@@ -275,7 +275,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 				rs = rs.Outer
 			}
 
-			if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
 				ld.Errorf(s, "missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
@@ -285,7 +285,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 			// the BR26 relocation should be fully resolved at link time.
 			// That is the reason why the next if block is disabled. When the bug in ld64
 			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
-			if false && ld.Headtype == obj.Hdarwin {
+			if false && ld.Headtype == objabi.Hdarwin {
 				var o0, o1 uint32
 
 				if ctxt.Arch.ByteOrder == binary.BigEndian {
@@ -314,9 +314,9 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 
 			return 0
 
-		case obj.R_CALLARM64,
-			obj.R_ARM64_TLS_LE,
-			obj.R_ARM64_TLS_IE:
+		case objabi.R_CALLARM64,
+			objabi.R_ARM64_TLS_LE,
+			objabi.R_ARM64_TLS_IE:
 			r.Done = 0
 			r.Xsym = r.Sym
 			r.Xadd = r.Add
@@ -325,15 +325,15 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 
-	case obj.R_ADDRARM64:
+	case objabi.R_ADDRARM64:
 		t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
 		if t >= 1<<32 || t < -1<<32 {
 			ld.Errorf(s, "program too large, address relocation distance = %d", t)
@@ -360,9 +360,9 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		}
 		return 0
 
-	case obj.R_ARM64_TLS_LE:
+	case objabi.R_ARM64_TLS_LE:
 		r.Done = 0
-		if ld.Headtype != obj.Hlinux {
+		if ld.Headtype != objabi.Hlinux {
 			ld.Errorf(s, "TLS reloc on unsupported OS %v", ld.Headtype)
 		}
 		// The TCB is two pointers. This is not documented anywhere, but is
@@ -374,7 +374,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		*val |= v << 5
 		return 0
 
-	case obj.R_CALLARM64:
+	case objabi.R_CALLARM64:
 		t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
 		if t >= 1<<27 || t < -1<<27 {
 			ld.Errorf(s, "program too large, call relocation distance = %d", t)
@@ -393,38 +393,38 @@ func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -434,7 +434,7 @@ func asmb(ctxt *ld.Link) {
 	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
 
 	machlink := uint32(0)
-	if ld.Headtype == obj.Hdarwin {
+	if ld.Headtype == objabi.Hdarwin {
 		machlink = uint32(ld.Domacholink(ctxt))
 	}
 
@@ -446,7 +446,7 @@ func asmb(ctxt *ld.Link) {
 	if !*ld.FlagS {
 		// TODO: rationalize
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
@@ -455,10 +455,10 @@ func asmb(ctxt *ld.Link) {
 				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
 		}
 
@@ -467,7 +467,7 @@ func asmb(ctxt *ld.Link) {
 		default:
 			if ld.Iself {
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 				}
 				ld.Asmelfsym(ctxt)
 				ld.Cflush()
@@ -478,7 +478,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -492,7 +492,7 @@ func asmb(ctxt *ld.Link) {
 				ld.Cflush()
 			}
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc(ctxt)
 			}
@@ -500,12 +500,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.Thearch.Lput(0x647)                      /* magic */
 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
@@ -515,14 +515,14 @@ func asmb(ctxt *ld.Link) {
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, int64(symo))
 
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		ld.Asmbmacho(ctxt)
 	}
 
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 7d49163..dce9beb 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -31,7 +31,7 @@
 package arm64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -76,7 +76,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if *ld.FlagTextAddr == -1 {
@@ -89,7 +89,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hlinux: /* arm64 elf */
+	case objabi.Hlinux: /* arm64 elf */
 		ld.Elfinit(ctxt)
 		ld.HEADR = ld.ELFRESERVE
 		if *ld.FlagTextAddr == -1 {
@@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hdarwin: /* apple MACH */
+	case objabi.Hdarwin: /* apple MACH */
 		*ld.FlagW = true // disable DWARF generation
 		ld.Machoinit()
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -116,7 +116,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index 6db672f..8827b76 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -32,7 +32,7 @@ package ld
 
 import (
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"encoding/binary"
 	"fmt"
 	"io"
@@ -101,7 +101,7 @@ func hostArchive(ctxt *Link, name string) {
 		var load []uint64
 		for _, s := range ctxt.Syms.Allsym {
 			for _, r := range s.R {
-				if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF {
+				if r.Sym != nil && r.Sym.Type&SMASK == SXREF {
 					if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
 						load = append(load, off)
 						loaded[off] = true
@@ -166,7 +166,7 @@ func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
 
 		// For Mach-O and PE/386 files we strip a leading
 		// underscore from the symbol name.
-		if obj.GOOS == "darwin" || (obj.GOOS == "windows" && obj.GOARCH == "386") {
+		if objabi.GOOS == "darwin" || (objabi.GOOS == "windows" && objabi.GOARCH == "386") {
 			if name[0] == '_' && len(name) > 1 {
 				name = name[1:]
 			}
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 2656c24..342351b 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -5,7 +5,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"log"
@@ -34,7 +34,7 @@ const (
 
 func (mode *BuildMode) Set(s string) error {
 	badmode := func() error {
-		return fmt.Errorf("buildmode %s not supported on %s/%s", s, obj.GOOS, obj.GOARCH)
+		return fmt.Errorf("buildmode %s not supported on %s/%s", s, objabi.GOOS, objabi.GOARCH)
 	}
 	switch s {
 	default:
@@ -42,17 +42,17 @@ func (mode *BuildMode) Set(s string) error {
 	case "exe":
 		*mode = BuildmodeExe
 	case "pie":
-		switch obj.GOOS {
+		switch objabi.GOOS {
 		case "android", "linux":
 		default:
 			return badmode()
 		}
 		*mode = BuildmodePIE
 	case "c-archive":
-		switch obj.GOOS {
+		switch objabi.GOOS {
 		case "darwin", "linux":
 		case "windows":
-			switch obj.GOARCH {
+			switch objabi.GOARCH {
 			case "amd64", "386":
 			default:
 				return badmode()
@@ -62,16 +62,16 @@ func (mode *BuildMode) Set(s string) error {
 		}
 		*mode = BuildmodeCArchive
 	case "c-shared":
-		switch obj.GOARCH {
+		switch objabi.GOARCH {
 		case "386", "amd64", "arm", "arm64":
 		default:
 			return badmode()
 		}
 		*mode = BuildmodeCShared
 	case "shared":
-		switch obj.GOOS {
+		switch objabi.GOOS {
 		case "linux":
-			switch obj.GOARCH {
+			switch objabi.GOARCH {
 			case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
 			default:
 				return badmode()
@@ -81,15 +81,15 @@ func (mode *BuildMode) Set(s string) error {
 		}
 		*mode = BuildmodeShared
 	case "plugin":
-		switch obj.GOOS {
+		switch objabi.GOOS {
 		case "linux":
-			switch obj.GOARCH {
-			case "386", "amd64", "arm", "arm64":
+			switch objabi.GOARCH {
+			case "386", "amd64", "arm", "arm64", "s390x":
 			default:
 				return badmode()
 			}
 		case "darwin":
-			switch obj.GOARCH {
+			switch objabi.GOARCH {
 			case "amd64":
 			default:
 				return badmode()
@@ -168,7 +168,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
 		}()
 	}
 
-	switch obj.GOOS {
+	switch objabi.GOOS {
 	case "android":
 		return true, "android"
 	case "darwin":
@@ -185,7 +185,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
 	// https://golang.org/issue/10373
 	// https://golang.org/issue/14449
 	if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS) {
-		return true, obj.GOARCH + " does not support internal cgo"
+		return true, objabi.GOARCH + " does not support internal cgo"
 	}
 
 	// Some build modes require work the internal linker cannot do (yet).
@@ -195,7 +195,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
 	case BuildmodeCShared:
 		return true, "buildmode=c-shared"
 	case BuildmodePIE:
-		switch obj.GOOS + "/" + obj.GOARCH {
+		switch objabi.GOOS + "/" + objabi.GOARCH {
 		case "linux/amd64":
 		default:
 			// Internal linking does not support TLS_IE.
@@ -225,7 +225,7 @@ func determineLinkMode(ctxt *Link) {
 		// default value of -linkmode. If it is not set when the
 		// linker is called we take the value it was set to when
 		// cmd/link was compiled. (See make.bash.)
-		switch obj.Getgoextlinkenabled() {
+		switch objabi.Getgoextlinkenabled() {
 		case "0":
 			if needed, reason := mustLinkExternal(ctxt); needed {
 				Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index aca8973..4523323 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -33,7 +33,7 @@ package ld
 
 import (
 	"cmd/internal/gcprog"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"log"
@@ -65,7 +65,7 @@ func Addrel(s *Symbol) *Reloc {
 
 func setuintxx(ctxt *Link, s *Symbol, off int64, v uint64, wid int64) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	if s.Size < off+wid {
@@ -89,7 +89,7 @@ func setuintxx(ctxt *Link, s *Symbol, off int64, v uint64, wid int64) int64 {
 
 func Addbytes(s *Symbol, bytes []byte) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	s.P = append(s.P, bytes...)
@@ -107,7 +107,7 @@ func adduintxx(ctxt *Link, s *Symbol, v uint64, wid int) int64 {
 func Adduint8(ctxt *Link, s *Symbol, v uint8) int64 {
 	off := s.Size
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	s.Size++
@@ -129,7 +129,7 @@ func Adduint64(ctxt *Link, s *Symbol, v uint64) int64 {
 }
 
 func adduint(ctxt *Link, s *Symbol, v uint64) int64 {
-	return adduintxx(ctxt, s, v, SysArch.IntSize)
+	return adduintxx(ctxt, s, v, SysArch.PtrSize)
 }
 
 func setuint8(ctxt *Link, s *Symbol, r int64, v uint8) int64 {
@@ -140,9 +140,13 @@ func setuint32(ctxt *Link, s *Symbol, r int64, v uint32) int64 {
 	return setuintxx(ctxt, s, r, uint64(v), 4)
 }
 
+func setuint(ctxt *Link, s *Symbol, r int64, v uint64) int64 {
+	return setuintxx(ctxt, s, r, v, int64(SysArch.PtrSize))
+}
+
 func Addaddrplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
@@ -152,14 +156,14 @@ func Addaddrplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.PtrSize)
-	r.Type = obj.R_ADDR
+	r.Type = objabi.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
 }
 
 func Addpcrelplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
@@ -169,7 +173,7 @@ func Addpcrelplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	r.Sym = t
 	r.Off = int32(i)
 	r.Add = add
-	r.Type = obj.R_PCREL
+	r.Type = objabi.R_PCREL
 	r.Siz = 4
 	if SysArch.Family == sys.S390X {
 		r.Variant = RV_390_DBL
@@ -183,7 +187,7 @@ func Addaddr(ctxt *Link, s *Symbol, t *Symbol) int64 {
 
 func setaddrplus(ctxt *Link, s *Symbol, off int64, t *Symbol, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	if off+int64(ctxt.Arch.PtrSize) > s.Size {
@@ -195,7 +199,7 @@ func setaddrplus(ctxt *Link, s *Symbol, off int64, t *Symbol, add int64) int64 {
 	r.Sym = t
 	r.Off = int32(off)
 	r.Siz = uint8(ctxt.Arch.PtrSize)
-	r.Type = obj.R_ADDR
+	r.Type = objabi.R_ADDR
 	r.Add = add
 	return off + int64(r.Siz)
 }
@@ -206,7 +210,7 @@ func setaddr(ctxt *Link, s *Symbol, off int64, t *Symbol) int64 {
 
 func addsize(ctxt *Link, s *Symbol, t *Symbol) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
@@ -216,13 +220,13 @@ func addsize(ctxt *Link, s *Symbol, t *Symbol) int64 {
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.PtrSize)
-	r.Type = obj.R_SIZE
+	r.Type = objabi.R_SIZE
 	return i + int64(r.Siz)
 }
 
 func addaddrplus4(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SDATA
+		s.Type = SDATA
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
@@ -232,7 +236,7 @@ func addaddrplus4(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = 4
-	r.Type = obj.R_ADDR
+	r.Type = objabi.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
 }
@@ -324,24 +328,42 @@ func isRuntimeDepPkg(pkg string) bool {
 	return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
 }
 
+// Estimate the max size needed to hold any new trampolines created for this function. This
+// is used to determine when the section can be split if it becomes too large, to ensure that
+// the trampolines are in the same section as the function that uses them.
+func maxSizeTrampolinesPPC64(s *Symbol, isTramp bool) uint64 {
+	// If Thearch.Trampoline is nil, then trampoline support is not available on this arch.
+	// A trampoline does not need any dependent trampolines.
+	if Thearch.Trampoline == nil || isTramp {
+		return 0
+	}
+
+	n := uint64(0)
+	for ri := range s.R {
+		r := &s.R[ri]
+		if r.Type.IsDirectJump() {
+			n++
+		}
+	}
+	// Trampolines in ppc64 are 4 instructions.
+	return n * 16
+}
+
 // detect too-far jumps in function s, and add trampolines if necessary
-// ARM supports trampoline insertion for internal and external linking
-// PPC64 & PPC64LE support trampoline insertion for internal linking only
+// ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
+// On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
+// where necessary.
 func trampoline(ctxt *Link, s *Symbol) {
 	if Thearch.Trampoline == nil {
 		return // no need or no support of trampolines on this arch
 	}
 
-	if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
-		return
-	}
-
 	for ri := range s.R {
 		r := &s.R[ri]
 		if !r.Type.IsDirectJump() {
 			continue
 		}
-		if Symaddr(r.Sym) == 0 && r.Sym.Type != obj.SDYNIMPORT {
+		if Symaddr(r.Sym) == 0 && r.Sym.Type != SDYNIMPORT {
 			if r.Sym.File != s.File {
 				if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
 					Errorf(s, "unresolved inter-package jump to %s(%s)", r.Sym, r.Sym.File)
@@ -382,12 +404,12 @@ func relocsym(ctxt *Link, s *Symbol) {
 			continue
 		}
 
-		if r.Sym != nil && (r.Sym.Type&(obj.SMASK|obj.SHIDDEN) == 0 || r.Sym.Type&obj.SMASK == obj.SXREF) {
+		if r.Sym != nil && (r.Sym.Type&(SMASK|SHIDDEN) == 0 || r.Sym.Type&SMASK == SXREF) {
 			// When putting the runtime but not main into a shared library
 			// these symbols are undefined and that's OK.
 			if Buildmode == BuildmodeShared {
 				if r.Sym.Name == "main.main" || r.Sym.Name == "main.init" {
-					r.Sym.Type = obj.SDYNIMPORT
+					r.Sym.Type = SDYNIMPORT
 				} else if strings.HasPrefix(r.Sym.Name, "go.info.") {
 					// Skip go.info symbols. They are only needed to communicate
 					// DWARF info between the compiler and linker.
@@ -408,22 +430,22 @@ func relocsym(ctxt *Link, s *Symbol) {
 
 		// 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 && !ctxt.DynlinkingGo() {
+		if Headtype != objabi.Hsolaris && r.Sym != nil && r.Sym.Type == SDYNIMPORT && !ctxt.DynlinkingGo() {
 			if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
 				Errorf(s, "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.Type != obj.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
+		if r.Sym != nil && r.Sym.Type != STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
 			Errorf(s, "unreachable sym in relocation: %s", 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
+			case objabi.R_PCRELDBL:
+				r.Type = objabi.R_PCREL
 				r.Variant = RV_390_DBL
-			case obj.R_CALL:
+			case objabi.R_CALL:
 				r.Variant = RV_390_DBL
 			}
 		}
@@ -446,10 +468,10 @@ func relocsym(ctxt *Link, s *Symbol) {
 				Errorf(s, "unknown reloc to %v: %v", r.Sym.Name, r.Type)
 			}
 
-		case obj.R_TLS_LE:
-			isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
+		case objabi.R_TLS_LE:
+			isAndroidX86 := objabi.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
-			if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
+			if Linkmode == LinkExternal && Iself && !isAndroidX86 {
 				r.Done = 0
 				if r.Sym == nil {
 					r.Sym = ctxt.Tlsg
@@ -472,18 +494,18 @@ func relocsym(ctxt *Link, s *Symbol) {
 				// related to the fact that our own TLS storage happens
 				// to take up 8 bytes.
 				o = 8 + r.Sym.Value
-			} else if Iself || Headtype == obj.Hplan9 || Headtype == obj.Hdarwin || isAndroidX86 {
+			} else if Iself || Headtype == objabi.Hplan9 || Headtype == objabi.Hdarwin || isAndroidX86 {
 				o = int64(ctxt.Tlsoffset) + r.Add
-			} else if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+			} else if Headtype == objabi.Hwindows {
 				o = r.Add
 			} else {
 				log.Fatalf("unexpected R_TLS_LE relocation for %v", Headtype)
 			}
 
-		case obj.R_TLS_IE:
-			isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
+		case objabi.R_TLS_IE:
+			isAndroidX86 := objabi.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
-			if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
+			if Linkmode == LinkExternal && Iself && !isAndroidX86 {
 				r.Done = 0
 				if r.Sym == nil {
 					r.Sym = ctxt.Tlsg
@@ -511,8 +533,8 @@ func relocsym(ctxt *Link, s *Symbol) {
 				log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name)
 			}
 
-		case obj.R_ADDR:
-			if Linkmode == LinkExternal && r.Sym.Type != obj.SCONST {
+		case objabi.R_ADDR:
+			if Linkmode == LinkExternal && r.Sym.Type != SCONST {
 				r.Done = 0
 
 				// set up addend for eventual relocation via outer symbol.
@@ -524,7 +546,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 					rs = rs.Outer
 				}
 
-				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+				if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
 					Errorf(s, "missing section for relocation target %s", rs.Name)
 				}
 				r.Xsym = rs
@@ -534,13 +556,13 @@ func relocsym(ctxt *Link, s *Symbol) {
 					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
-				} else if Headtype == obj.Hdarwin {
+				} else if Headtype == objabi.Hdarwin {
 					// ld64 for arm64 has a bug where if the address pointed to by o exists in the
 					// symbol table (dynid >= 0), or is inside a symbol that exists in the symbol
 					// table, then it will add o twice into the relocated value.
 					// The workaround is that on arm64 don't ever add symaddr to o and always use
 					// extern relocation by requiring rs->dynid >= 0.
-					if rs.Type != obj.SHOSTOBJ {
+					if rs.Type != SHOSTOBJ {
 						if SysArch.Family == sys.ARM64 && rs.Dynid < 0 {
 							Errorf(s, "R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
 						}
@@ -548,7 +570,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 							o += Symaddr(rs)
 						}
 					}
-				} else if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+				} else if Headtype == objabi.Hwindows {
 					// nothing to do
 				} else {
 					Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, Headtype)
@@ -569,16 +591,33 @@ func relocsym(ctxt *Link, s *Symbol) {
 				errorexit()
 			}
 
-		case obj.R_DWARFREF:
-			if r.Sym.Sect == nil {
+		case objabi.R_DWARFREF:
+			var sectName string
+			var vaddr int64
+			switch {
+			case r.Sym.Sect != nil:
+				sectName = r.Sym.Sect.Name
+				vaddr = int64(r.Sym.Sect.Vaddr)
+			case r.Sym.Type == SDWARFRANGE:
+				sectName = ".debug_ranges"
+			default:
 				Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
 			}
+
 			if Linkmode == LinkExternal {
 				r.Done = 0
-				r.Type = obj.R_ADDR
+				// PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
+				// for R_DWARFREF relocations, while R_ADDR is replaced with
+				// IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
+				// Do not replace R_DWARFREF with R_ADDR for windows -
+				// let PE code emit correct relocations.
+				if Headtype != objabi.Hwindows {
+					r.Type = objabi.R_ADDR
+				}
+
+				r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
+				r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
 
-				r.Xsym = ctxt.Syms.ROLookup(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 {
@@ -586,26 +625,26 @@ func relocsym(ctxt *Link, s *Symbol) {
 				}
 				break
 			}
-			o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
+			o = Symaddr(r.Sym) + r.Add - vaddr
 
-		case obj.R_WEAKADDROFF:
+		case objabi.R_WEAKADDROFF:
 			if !r.Sym.Attr.Reachable() {
 				continue
 			}
 			fallthrough
-		case obj.R_ADDROFF:
+		case objabi.R_ADDROFF:
 			// The method offset tables using this relocation expect the offset to be relative
 			// to the start of the first text section, even if there are multiple.
 
 			if r.Sym.Sect.Name == ".text" {
-				o = Symaddr(r.Sym) - int64(Segtext.Sect.Vaddr) + r.Add
+				o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add
 			} else {
 				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_GOTPCREL:
-			if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin && r.Sym != nil && r.Sym.Type != obj.SCONST {
+		case objabi.R_GOTPCREL:
+			if ctxt.DynlinkingGo() && Headtype == objabi.Hdarwin && r.Sym != nil && r.Sym.Type != SCONST {
 				r.Done = 0
 				r.Xadd = r.Add
 				r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
@@ -616,8 +655,8 @@ func relocsym(ctxt *Link, s *Symbol) {
 				break
 			}
 			fallthrough
-		case obj.R_CALL, obj.R_PCREL:
-			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != s.Sect || r.Type == obj.R_GOTPCREL) {
+		case objabi.R_CALL, objabi.R_PCREL:
+			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
 				r.Done = 0
 
 				// set up addend for eventual relocation via outer symbol.
@@ -630,7 +669,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 				}
 
 				r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
-				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+				if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
 					Errorf(s, "missing section for relocation target %s", rs.Name)
 				}
 				r.Xsym = rs
@@ -640,9 +679,9 @@ func relocsym(ctxt *Link, s *Symbol) {
 					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
-				} else if Headtype == obj.Hdarwin {
-					if r.Type == obj.R_CALL {
-						if rs.Type != obj.SHOSTOBJ {
+				} else if Headtype == objabi.Hdarwin {
+					if r.Type == objabi.R_CALL {
+						if rs.Type != SHOSTOBJ {
 							o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
 						}
 						o -= int64(r.Off) // relative to section offset, not symbol
@@ -652,13 +691,10 @@ func relocsym(ctxt *Link, s *Symbol) {
 					} else {
 						o += int64(r.Siz)
 					}
-				} else if (Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui) && SysArch.Family == sys.AMD64 { // only amd64 needs PCREL
+				} else if Headtype == objabi.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)
-					// GNU ld always add VirtualAddress of the .text section to the
-					// relocated address, compensate that.
-					o -= int64(s.Sect.Vaddr - PEBASE)
 				} else {
 					Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, Headtype)
 				}
@@ -673,7 +709,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 
 			o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
 
-		case obj.R_SIZE:
+		case objabi.R_SIZE:
 			o = r.Sym.Size + r.Add
 		}
 
@@ -705,7 +741,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 			ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
 
 		case 4:
-			if r.Type == obj.R_PCREL || r.Type == obj.R_CALL {
+			if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
 				if o != int64(int32(o)) {
 					Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
 				}
@@ -726,7 +762,7 @@ func relocsym(ctxt *Link, s *Symbol) {
 
 func (ctxt *Link) reloc() {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f reloc\n", obj.Cputime())
+		ctxt.Logf("%5.2f reloc\n", Cputime())
 	}
 
 	for _, s := range ctxt.Textp {
@@ -741,7 +777,7 @@ func (ctxt *Link) reloc() {
 }
 
 func dynrelocsym(ctxt *Link, s *Symbol) {
-	if (Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui) && Linkmode != LinkExternal {
+	if Headtype == objabi.Hwindows && Linkmode != LinkExternal {
 		rel := ctxt.Syms.Lookup(".rel", 0)
 		if s == rel {
 			return
@@ -753,7 +789,7 @@ func dynrelocsym(ctxt *Link, s *Symbol) {
 				continue
 			}
 			if !targ.Attr.Reachable() {
-				if r.Type == obj.R_WEAKADDROFF {
+				if r.Type == objabi.R_WEAKADDROFF {
 					continue
 				}
 				Errorf(s, "dynamic relocation to unreachable symbol %s", targ.Name)
@@ -795,7 +831,7 @@ func dynrelocsym(ctxt *Link, s *Symbol) {
 			Thearch.Adddynrel(ctxt, s, r)
 			continue
 		}
-		if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 {
+		if r.Sym != nil && r.Sym.Type == SDYNIMPORT || r.Type >= 256 {
 			if r.Sym != nil && !r.Sym.Attr.Reachable() {
 				Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
 			}
@@ -806,14 +842,14 @@ func dynrelocsym(ctxt *Link, s *Symbol) {
 	}
 }
 
-func dynreloc(ctxt *Link, data *[obj.SXREF][]*Symbol) {
+func dynreloc(ctxt *Link, data *[SXREF][]*Symbol) {
 	// -d suppresses dynamic loader format, so we may as well not
 	// compute these sections or mark their symbols as reachable.
-	if *FlagD && Headtype != obj.Hwindows && Headtype != obj.Hwindowsgui {
+	if *FlagD && Headtype != objabi.Hwindows {
 		return
 	}
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f reloc\n", obj.Cputime())
+		ctxt.Logf("%5.2f reloc\n", Cputime())
 	}
 
 	for _, s := range ctxt.Textp {
@@ -898,7 +934,7 @@ func CodeblkPad(ctxt *Link, addr int64, size int64, pad []byte) {
 
 func blk(ctxt *Link, syms []*Symbol, addr, size int64, pad []byte) {
 	for i, s := range syms {
-		if s.Type&obj.SSUB == 0 && s.Value >= addr {
+		if s.Type&SSUB == 0 && s.Value >= addr {
 			syms = syms[i:]
 			break
 		}
@@ -906,7 +942,7 @@ func blk(ctxt *Link, syms []*Symbol, addr, size int64, pad []byte) {
 
 	eaddr := addr + size
 	for _, s := range syms {
-		if s.Type&obj.SSUB != 0 {
+		if s.Type&SSUB != 0 {
 			continue
 		}
 		if s.Value >= eaddr {
@@ -995,11 +1031,11 @@ func Datblk(ctxt *Link, addr int64, size int64) {
 			}
 			typ := "?"
 			switch r.Type {
-			case obj.R_ADDR:
+			case objabi.R_ADDR:
 				typ = "addr"
-			case obj.R_PCREL:
+			case objabi.R_PCREL:
 				typ = "pcrel"
-			case obj.R_CALL:
+			case objabi.R_CALL:
 				typ = "call"
 			}
 			ctxt.Logf("\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)
@@ -1055,7 +1091,7 @@ func addstrdata1(ctxt *Link, arg string) {
 	if eq < 0 || dot < 0 {
 		Exitf("-X flag requires argument of the form importpath.name=value")
 	}
-	addstrdata(ctxt, pathtoprefix(arg[:dot])+arg[dot:eq], arg[eq+1:])
+	addstrdata(ctxt, objabi.PathToPrefix(arg[:dot])+arg[dot:eq], arg[eq+1:])
 }
 
 func addstrdata(ctxt *Link, name string, value string) {
@@ -1063,7 +1099,7 @@ func addstrdata(ctxt *Link, name string, value string) {
 	sp := ctxt.Syms.Lookup(p, 0)
 
 	Addstring(sp, value)
-	sp.Type = obj.SRODATA
+	sp.Type = SRODATA
 
 	s := ctxt.Syms.Lookup(name, 0)
 	s.Size = 0
@@ -1084,7 +1120,7 @@ func addstrdata(ctxt *Link, name string, value string) {
 
 func (ctxt *Link) checkstrdata() {
 	for _, s := range strdata {
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			Errorf(s, "cannot use -X with text symbol")
 		} else if s.Gotype != nil && s.Gotype.Name != "type.string" {
 			Errorf(s, "cannot use -X with non-string symbol")
@@ -1094,7 +1130,7 @@ func (ctxt *Link) checkstrdata() {
 
 func Addstring(s *Symbol, str string) int64 {
 	if s.Type == 0 {
-		s.Type = obj.SNOPTRDATA
+		s.Type = SNOPTRDATA
 	}
 	s.Attr |= AttrReachable
 	r := s.Size
@@ -1111,12 +1147,12 @@ func Addstring(s *Symbol, str string) int64 {
 // symbol used to define the string data and must be unique per linked object.
 func addgostring(ctxt *Link, s *Symbol, symname, str string) {
 	sym := ctxt.Syms.Lookup(symname, 0)
-	if sym.Type != obj.Sxxx {
+	if sym.Type != Sxxx {
 		Errorf(s, "duplicate symname in addgostring: %s", symname)
 	}
 	sym.Attr |= AttrReachable
 	sym.Attr |= AttrLocal
-	sym.Type = obj.SRODATA
+	sym.Type = SRODATA
 	sym.Size = int64(len(str))
 	sym.P = []byte(str)
 	Addaddr(ctxt, s, sym)
@@ -1126,28 +1162,23 @@ func addgostring(ctxt *Link, s *Symbol, symname, str string) {
 func addinitarrdata(ctxt *Link, s *Symbol) {
 	p := s.Name + ".ptr"
 	sp := ctxt.Syms.Lookup(p, 0)
-	sp.Type = obj.SINITARR
+	sp.Type = SINITARR
 	sp.Size = 0
 	sp.Attr |= AttrDuplicateOK
 	Addaddr(ctxt, sp, s)
 }
 
 func dosymtype(ctxt *Link) {
-	for _, s := range ctxt.Syms.Allsym {
-		if len(s.P) > 0 {
-			if s.Type == obj.SBSS {
-				s.Type = obj.SDATA
-			}
-			if s.Type == obj.SNOPTRBSS {
-				s.Type = obj.SNOPTRDATA
-			}
-		}
-		// Create a new entry in the .init_array section that points to the
-		// library initializer function.
-		switch Buildmode {
-		case BuildmodeCArchive, BuildmodeCShared:
-			if s.Name == *flagEntrySymbol {
-				addinitarrdata(ctxt, s)
+	switch Buildmode {
+	case BuildmodeCArchive, BuildmodeCShared:
+		for _, s := range ctxt.Syms.Allsym {
+			// Create a new entry in the .init_array section that points to the
+			// library initializer function.
+			switch Buildmode {
+			case BuildmodeCArchive, BuildmodeCShared:
+				if s.Name == *flagEntrySymbol {
+					addinitarrdata(ctxt, s)
+				}
 			}
 		}
 	}
@@ -1271,7 +1302,7 @@ func (d bySizeAndName) Less(i, j int) bool {
 
 const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
 
-func checkdatsize(ctxt *Link, datsize int64, symn obj.SymKind) {
+func checkdatsize(ctxt *Link, datsize int64, symn SymKind) {
 	if datsize > cutoff {
 		Errorf(nil, "too much data in section %v (over %d bytes)", symn, cutoff)
 	}
@@ -1283,10 +1314,10 @@ var datap []*Symbol
 
 func (ctxt *Link) dodata() {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f dodata\n", obj.Cputime())
+		ctxt.Logf("%5.2f dodata\n", Cputime())
 	}
 
-	if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+	if ctxt.DynlinkingGo() && Headtype == objabi.Hdarwin {
 		// The values in moduledata are filled out by relocations
 		// pointing to the addresses of these special symbols.
 		// Typically these symbols have no size and are not laid
@@ -1317,22 +1348,22 @@ func (ctxt *Link) dodata() {
 		ctxt.Syms.Lookup("runtime.edata", 0).Attr.Set(AttrSpecial, false)
 
 		types := ctxt.Syms.Lookup("runtime.types", 0)
-		types.Type = obj.STYPE
+		types.Type = STYPE
 		types.Size = 8
 		types.Attr.Set(AttrSpecial, false)
 
 		etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
-		etypes.Type = obj.SFUNCTAB
+		etypes.Type = SFUNCTAB
 		etypes.Attr.Set(AttrSpecial, false)
 	}
 
 	// Collect data symbols by type into data.
-	var data [obj.SXREF][]*Symbol
+	var data [SXREF][]*Symbol
 	for _, s := range ctxt.Syms.Allsym {
 		if !s.Attr.Reachable() || s.Attr.Special() {
 			continue
 		}
-		if s.Type <= obj.STEXT || s.Type >= obj.SXREF {
+		if s.Type <= STEXT || s.Type >= SXREF {
 			continue
 		}
 		data[s.Type] = append(data[s.Type], s)
@@ -1344,7 +1375,7 @@ func (ctxt *Link) dodata() {
 	// symbol, which is itself data.
 	//
 	// On darwin, we need the symbol table numbers for dynreloc.
-	if Headtype == obj.Hdarwin {
+	if Headtype == objabi.Hdarwin {
 		machosymorder(ctxt)
 	}
 	dynreloc(ctxt, &data)
@@ -1353,8 +1384,8 @@ func (ctxt *Link) dodata() {
 		// "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 _, symnro := range obj.ReadOnly {
-			symnrelro := obj.RelROMap[symnro]
+		for _, symnro := range readOnly {
+			symnrelro := relROMap[symnro]
 
 			ro := []*Symbol{}
 			relro := data[symnrelro]
@@ -1362,7 +1393,7 @@ func (ctxt *Link) dodata() {
 			for _, s := range data[symnro] {
 				isRelro := len(s.R) > 0
 				switch s.Type {
-				case obj.STYPE, obj.STYPERELRO, obj.SGOFUNCRELRO:
+				case STYPE, STYPERELRO, SGOFUNCRELRO:
 					// Symbols are not sorted yet, so it is possible
 					// that an Outer symbol has been changed to a
 					// relro Type before it reaches here.
@@ -1396,10 +1427,10 @@ func (ctxt *Link) dodata() {
 	}
 
 	// Sort symbols.
-	var dataMaxAlign [obj.SXREF]int32
+	var dataMaxAlign [SXREF]int32
 	var wg sync.WaitGroup
 	for symn := range data {
-		symn := obj.SymKind(symn)
+		symn := SymKind(symn)
 		wg.Add(1)
 		go func() {
 			data[symn], dataMaxAlign[symn] = dodataSect(ctxt, symn, data[symn])
@@ -1415,11 +1446,11 @@ func (ctxt *Link) dodata() {
 	datsize := int64(0)
 
 	// Writable data sections that do not need any specialized handling.
-	writable := []obj.SymKind{
-		obj.SELFSECT,
-		obj.SMACHO,
-		obj.SMACHOGOT,
-		obj.SWINDOWS,
+	writable := []SymKind{
+		SELFSECT,
+		SMACHO,
+		SMACHOGOT,
+		SWINDOWS,
 	}
 	for _, symn := range writable {
 		for _, s := range data[symn] {
@@ -1428,7 +1459,7 @@ func (ctxt *Link) dodata() {
 			datsize = Rnd(datsize, int64(sect.Align))
 			sect.Vaddr = uint64(datsize)
 			s.Sect = sect
-			s.Type = obj.SDATA
+			s.Type = SDATA
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 			datsize += s.Size
 			sect.Length = uint64(datsize) - sect.Vaddr
@@ -1437,16 +1468,16 @@ func (ctxt *Link) dodata() {
 	}
 
 	// .got (and .toc on ppc64)
-	if len(data[obj.SELFGOT]) > 0 {
+	if len(data[SELFGOT]) > 0 {
 		sect := addsection(&Segdata, ".got", 06)
-		sect.Align = dataMaxAlign[obj.SELFGOT]
+		sect.Align = dataMaxAlign[SELFGOT]
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		var toc *Symbol
-		for _, s := range data[obj.SELFGOT] {
+		for _, s := range data[SELFGOT] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
-			s.Type = obj.SDATA
+			s.Type = SDATA
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 
 			// Resolve .TOC. symbol for this object file (ppc64)
@@ -1462,25 +1493,25 @@ func (ctxt *Link) dodata() {
 
 			datsize += s.Size
 		}
-		checkdatsize(ctxt, datsize, obj.SELFGOT)
+		checkdatsize(ctxt, datsize, SELFGOT)
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
 
 	/* pointer-free data */
 	sect := addsection(&Segdata, ".noptrdata", 06)
-	sect.Align = dataMaxAlign[obj.SNOPTRDATA]
+	sect.Align = dataMaxAlign[SNOPTRDATA]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
-	for _, s := range data[obj.SNOPTRDATA] {
+	for _, s := range data[SNOPTRDATA] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = obj.SDATA
+		s.Type = SDATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SNOPTRDATA)
+	checkdatsize(ctxt, datsize, SNOPTRDATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	hasinitarr := *FlagLinkshared
@@ -1492,68 +1523,68 @@ func (ctxt *Link) dodata() {
 	}
 	if hasinitarr {
 		sect := addsection(&Segdata, ".init_array", 06)
-		sect.Align = dataMaxAlign[obj.SINITARR]
+		sect.Align = dataMaxAlign[SINITARR]
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
-		for _, s := range data[obj.SINITARR] {
+		for _, s := range data[SINITARR] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 			datsize += s.Size
 		}
 		sect.Length = uint64(datsize) - sect.Vaddr
-		checkdatsize(ctxt, datsize, obj.SINITARR)
+		checkdatsize(ctxt, datsize, SINITARR)
 	}
 
 	/* data */
 	sect = addsection(&Segdata, ".data", 06)
-	sect.Align = dataMaxAlign[obj.SDATA]
+	sect.Align = dataMaxAlign[SDATA]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
 	var gc GCProg
 	gc.Init(ctxt, "runtime.gcdata")
-	for _, s := range data[obj.SDATA] {
+	for _, s := range data[SDATA] {
 		s.Sect = sect
-		s.Type = obj.SDATA
+		s.Type = SDATA
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		gc.AddSym(s)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SDATA)
+	checkdatsize(ctxt, datsize, SDATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 	gc.End(int64(sect.Length))
 
 	/* bss */
 	sect = addsection(&Segdata, ".bss", 06)
-	sect.Align = dataMaxAlign[obj.SBSS]
+	sect.Align = dataMaxAlign[SBSS]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
 	gc = GCProg{}
 	gc.Init(ctxt, "runtime.gcbss")
-	for _, s := range data[obj.SBSS] {
+	for _, s := range data[SBSS] {
 		s.Sect = sect
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		gc.AddSym(s)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SBSS)
+	checkdatsize(ctxt, datsize, SBSS)
 	sect.Length = uint64(datsize) - sect.Vaddr
 	gc.End(int64(sect.Length))
 
 	/* pointer-free bss */
 	sect = addsection(&Segdata, ".noptrbss", 06)
-	sect.Align = dataMaxAlign[obj.SNOPTRBSS]
+	sect.Align = dataMaxAlign[SNOPTRBSS]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
-	for _, s := range data[obj.SNOPTRBSS] {
+	for _, s := range data[SNOPTRBSS] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1562,24 +1593,24 @@ func (ctxt *Link) dodata() {
 
 	sect.Length = uint64(datsize) - sect.Vaddr
 	ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
-	checkdatsize(ctxt, datsize, obj.SNOPTRBSS)
+	checkdatsize(ctxt, datsize, SNOPTRBSS)
 
-	if len(data[obj.STLSBSS]) > 0 {
+	if len(data[STLSBSS]) > 0 {
 		var sect *Section
-		if Iself && (Linkmode == LinkExternal || !*FlagD) && Headtype != obj.Hopenbsd {
+		if Iself && (Linkmode == LinkExternal || !*FlagD) {
 			sect = addsection(&Segdata, ".tbss", 06)
 			sect.Align = int32(SysArch.PtrSize)
 			sect.Vaddr = 0
 		}
 		datsize = 0
 
-		for _, s := range data[obj.STLSBSS] {
+		for _, s := range data[STLSBSS] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = datsize
 			datsize += s.Size
 		}
-		checkdatsize(ctxt, datsize, obj.STLSBSS)
+		checkdatsize(ctxt, datsize, STLSBSS)
 
 		if sect != nil {
 			sect.Length = uint64(datsize)
@@ -1606,20 +1637,20 @@ func (ctxt *Link) dodata() {
 	datsize = 0
 
 	/* read-only executable ELF, Mach-O sections */
-	if len(data[obj.STEXT]) != 0 {
-		Errorf(nil, "dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
+	if len(data[STEXT]) != 0 {
+		Errorf(nil, "dodata found an STEXT symbol: %s", data[STEXT][0].Name)
 	}
-	for _, s := range data[obj.SELFRXSECT] {
+	for _, s := range data[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.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
-		checkdatsize(ctxt, datsize, obj.SELFRXSECT)
+		checkdatsize(ctxt, datsize, SELFRXSECT)
 	}
 
 	/* read-only data */
@@ -1632,18 +1663,18 @@ func (ctxt *Link) dodata() {
 		ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
 		ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
 	}
-	for _, symn := range obj.ReadOnly {
+	for _, symn := range readOnly {
 		align := dataMaxAlign[symn]
 		if sect.Align < align {
 			sect.Align = align
 		}
 	}
 	datsize = Rnd(datsize, int64(sect.Align))
-	for _, symn := range obj.ReadOnly {
+	for _, symn := range readOnly {
 		for _, s := range data[symn] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 			datsize += s.Size
 		}
@@ -1652,31 +1683,31 @@ func (ctxt *Link) dodata() {
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* read-only ELF, Mach-O sections */
-	for _, s := range data[obj.SELFROSECT] {
+	for _, s := range data[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.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
-	checkdatsize(ctxt, datsize, obj.SELFROSECT)
+	checkdatsize(ctxt, datsize, SELFROSECT)
 
-	for _, s := range data[obj.SMACHOPLT] {
+	for _, s := range data[SMACHOPLT] {
 		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.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
-	checkdatsize(ctxt, datsize, obj.SMACHOPLT)
+	checkdatsize(ctxt, datsize, SMACHOPLT)
 
 	// There is some data that are conceptually read-only but are written to by
 	// relocations. On GNU systems, we can arrange for the dynamic linker to
@@ -1712,23 +1743,23 @@ func (ctxt *Link) dodata() {
 		sect.Vaddr = 0
 		ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
 		ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
-		for _, symnro := range obj.ReadOnly {
-			symn := obj.RelROMap[symnro]
+		for _, symnro := range readOnly {
+			symn := relROMap[symnro]
 			align := dataMaxAlign[symn]
 			if sect.Align < align {
 				sect.Align = align
 			}
 		}
 		datsize = Rnd(datsize, int64(sect.Align))
-		for _, symnro := range obj.ReadOnly {
-			symn := obj.RelROMap[symnro]
+		for _, symnro := range readOnly {
+			symn := relROMap[symnro]
 			for _, s := range data[symn] {
 				datsize = aligndatsize(datsize, s)
 				if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
 					Errorf(s, "s.Outer (%s) in different section from s, %s != %s", s.Outer.Name, s.Outer.Sect.Name, sect.Name)
 				}
 				s.Sect = sect
-				s.Type = obj.SRODATA
+				s.Type = SRODATA
 				s.Value = int64(uint64(datsize) - sect.Vaddr)
 				datsize += s.Size
 			}
@@ -1740,65 +1771,65 @@ func (ctxt *Link) dodata() {
 
 	/* typelink */
 	sect = addrelrosection(".typelink")
-	sect.Align = dataMaxAlign[obj.STYPELINK]
+	sect.Align = dataMaxAlign[STYPELINK]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
 	typelink.Sect = sect
-	typelink.Type = obj.RODATA
+	typelink.Type = SRODATA
 	datsize += typelink.Size
-	checkdatsize(ctxt, datsize, obj.STYPELINK)
+	checkdatsize(ctxt, datsize, STYPELINK)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* itablink */
 	sect = addrelrosection(".itablink")
-	sect.Align = dataMaxAlign[obj.SITABLINK]
+	sect.Align = dataMaxAlign[SITABLINK]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
-	for _, s := range data[obj.SITABLINK] {
+	for _, s := range data[SITABLINK] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = obj.SRODATA
+		s.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SITABLINK)
+	checkdatsize(ctxt, datsize, SITABLINK)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* gosymtab */
 	sect = addrelrosection(".gosymtab")
-	sect.Align = dataMaxAlign[obj.SSYMTAB]
+	sect.Align = dataMaxAlign[SSYMTAB]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
-	for _, s := range data[obj.SSYMTAB] {
+	for _, s := range data[SSYMTAB] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = obj.SRODATA
+		s.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SSYMTAB)
+	checkdatsize(ctxt, datsize, SSYMTAB)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* gopclntab */
 	sect = addrelrosection(".gopclntab")
-	sect.Align = dataMaxAlign[obj.SPCLNTAB]
+	sect.Align = dataMaxAlign[SPCLNTAB]
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
 	ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
-	for _, s := range data[obj.SPCLNTAB] {
+	for _, s := range data[SPCLNTAB] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = obj.SRODATA
+		s.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 	}
-	checkdatsize(ctxt, datsize, obj.SRODATA)
+	checkdatsize(ctxt, datsize, SRODATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
@@ -1806,7 +1837,7 @@ func (ctxt *Link) dodata() {
 		Errorf(nil, "read-only data segment too large: %d", datsize)
 	}
 
-	for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ {
+	for symn := SELFRXSECT; symn < SXREF; symn++ {
 		datap = append(datap, data[symn]...)
 	}
 
@@ -1815,20 +1846,21 @@ func (ctxt *Link) dodata() {
 	var s *Symbol
 	var i int
 	for i, s = range dwarfp {
-		if s.Type != obj.SDWARFSECT {
+		if s.Type != SDWARFSECT {
 			break
 		}
+
 		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.Type = SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
-	checkdatsize(ctxt, datsize, obj.SDWARFSECT)
+	checkdatsize(ctxt, datsize, SDWARFSECT)
 
 	if i < len(dwarfp) {
 		sect = addsection(&Segdwarf, ".debug_info", 04)
@@ -1836,46 +1868,46 @@ func (ctxt *Link) dodata() {
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		for _, s := range dwarfp[i:] {
-			if s.Type != obj.SDWARFINFO {
+			if s.Type != SDWARFINFO {
 				break
 			}
 			s.Sect = sect
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 			s.Attr |= AttrLocal
 			datsize += s.Size
 		}
 		sect.Length = uint64(datsize) - sect.Vaddr
-		checkdatsize(ctxt, datsize, obj.SDWARFINFO)
+		checkdatsize(ctxt, datsize, SDWARFINFO)
 	}
 
 	/* number the sections */
 	n := int32(1)
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrodata.Sections {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrelrodata.Sections {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		sect.Extnum = int16(n)
 		n++
 	}
 }
 
-func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol, maxAlign int32) {
-	if Headtype == obj.Hdarwin {
+func dodataSect(ctxt *Link, symn SymKind, syms []*Symbol) (result []*Symbol, maxAlign int32) {
+	if Headtype == objabi.Hdarwin {
 		// Some symbols may no longer belong in syms
 		// due to movement in machosymorder.
 		newSyms := make([]*Symbol, 0, len(syms))
@@ -1906,7 +1938,7 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
 		// If the usually-special section-marker symbols are being laid
 		// out as regular symbols, put them either at the beginning or
 		// end of their section.
-		if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+		if ctxt.DynlinkingGo() && Headtype == objabi.Hdarwin {
 			switch s.Name {
 			case "runtime.text", "runtime.bss", "runtime.data", "runtime.types":
 				head = s
@@ -1924,7 +1956,7 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
 		}
 
 		switch s.Type {
-		case obj.SELFGOT:
+		case 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
@@ -1953,7 +1985,7 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
 		syms[len(syms)-1] = tail
 	}
 
-	if Iself && symn == obj.SELFROSECT {
+	if Iself && symn == SELFROSECT {
 		// Make .rela and .rela.plt contiguous, the ELF ABI requires this
 		// and Solaris actually cares.
 		reli, plti := -1, -1
@@ -2004,7 +2036,7 @@ func (ctxt *Link) textbuildid() {
 	// 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(*flagBuildid) + "\n \xff"
-	sym.Type = obj.STEXT
+	sym.Type = STEXT
 	sym.P = []byte(data)
 	sym.Size = int64(len(sym.P))
 
@@ -2020,14 +2052,14 @@ func (ctxt *Link) textaddress() {
 	// Assign PCs in text segment.
 	// Could parallelize, by assigning to text
 	// and then letting threads copy down, but probably not worth it.
-	sect := Segtext.Sect
+	sect := Segtext.Sections[0]
 
 	sect.Align = int32(Funcalign)
 
 	text := ctxt.Syms.Lookup("runtime.text", 0)
 	text.Sect = sect
 
-	if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+	if ctxt.DynlinkingGo() && Headtype == objabi.Hdarwin {
 		etext := ctxt.Syms.Lookup("runtime.etext", 0)
 		etext.Sect = sect
 
@@ -2036,22 +2068,19 @@ func (ctxt *Link) textaddress() {
 		ctxt.Textp[0] = text
 	}
 
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
-		ctxt.Syms.Lookup(".text", 0).Sect = sect
-	}
 	va := uint64(*FlagTextAddr)
 	n := 1
 	sect.Vaddr = va
 	ntramps := 0
 	for _, sym := range ctxt.Textp {
-		sect, n, va = assignAddress(ctxt, sect, n, sym, va)
+		sect, n, va = assignAddress(ctxt, sect, n, sym, va, false)
 
 		trampoline(ctxt, sym) // resolve jumps, may add trampolines if jump too far
 
 		// lay down trampolines after each function
 		for ; ntramps < len(ctxt.tramps); ntramps++ {
 			tramp := ctxt.tramps[ntramps]
-			sect, n, va = assignAddress(ctxt, sect, n, tramp, va)
+			sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
 		}
 	}
 
@@ -2077,9 +2106,9 @@ func (ctxt *Link) textaddress() {
 // assigns address for a text symbol, returns (possibly new) section, its number, and the address
 // Note: once we have trampoline insertion support for external linking, this function
 // will not need to create new text sections, and so no need to return sect and n.
-func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*Section, int, uint64) {
+func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64, isTramp bool) (*Section, int, uint64) {
 	sym.Sect = sect
-	if sym.Type&obj.SSUB != 0 {
+	if sym.Type&SSUB != 0 {
 		return sect, n, va
 	}
 	if sym.Align != 0 {
@@ -2106,7 +2135,7 @@ func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*S
 
 	// Only break at outermost syms.
 
-	if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
+	if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(sym, isTramp) > 0x1c00000 {
 
 		// Set the length for the previous text section
 		sect.Length = va - sect.Vaddr
@@ -2131,7 +2160,7 @@ func (ctxt *Link) address() {
 	Segtext.Rwx = 05
 	Segtext.Vaddr = va
 	Segtext.Fileoff = uint64(HEADR)
-	for s := Segtext.Sect; s != nil; s = s.Next {
+	for _, s := range Segtext.Sections {
 		va = uint64(Rnd(int64(va), int64(s.Align)))
 		s.Vaddr = va
 		va += s.Length
@@ -2139,11 +2168,11 @@ func (ctxt *Link) address() {
 
 	Segtext.Length = va - uint64(*FlagTextAddr)
 	Segtext.Filelen = Segtext.Length
-	if Headtype == obj.Hnacl {
+	if Headtype == objabi.Hnacl {
 		va += 32 // room for the "halt sled"
 	}
 
-	if Segrodata.Sect != nil {
+	if len(Segrodata.Sections) > 0 {
 		// align to page boundary so as not to mix
 		// rodata and executable text.
 		//
@@ -2163,7 +2192,7 @@ func (ctxt *Link) address() {
 		Segrodata.Vaddr = va
 		Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
 		Segrodata.Filelen = 0
-		for s := Segrodata.Sect; s != nil; s = s.Next {
+		for _, s := range Segrodata.Sections {
 			va = uint64(Rnd(int64(va), int64(s.Align)))
 			s.Vaddr = va
 			va += s.Length
@@ -2172,7 +2201,7 @@ func (ctxt *Link) address() {
 		Segrodata.Length = va - Segrodata.Vaddr
 		Segrodata.Filelen = Segrodata.Length
 	}
-	if Segrelrodata.Sect != nil {
+	if len(Segrelrodata.Sections) > 0 {
 		// align to page boundary so as not to mix
 		// rodata, rel-ro data, and executable text.
 		va = uint64(Rnd(int64(va), int64(*FlagRound)))
@@ -2181,7 +2210,7 @@ func (ctxt *Link) address() {
 		Segrelrodata.Vaddr = va
 		Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
 		Segrelrodata.Filelen = 0
-		for s := Segrelrodata.Sect; s != nil; s = s.Next {
+		for _, s := range Segrelrodata.Sections {
 			va = uint64(Rnd(int64(va), int64(s.Align)))
 			s.Vaddr = va
 			va += s.Length
@@ -2196,10 +2225,10 @@ func (ctxt *Link) address() {
 	Segdata.Vaddr = va
 	Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
 	Segdata.Filelen = 0
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+	if Headtype == objabi.Hwindows {
 		Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
 	}
-	if Headtype == obj.Hplan9 {
+	if Headtype == objabi.Hplan9 {
 		Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
 	}
 	var data *Section
@@ -2207,13 +2236,13 @@ func (ctxt *Link) address() {
 	var bss *Section
 	var noptrbss *Section
 	var vlen int64
-	for s := Segdata.Sect; s != nil; s = s.Next {
+	for i, s := range Segdata.Sections {
 		if Iself && s.Name == ".tbss" {
 			continue
 		}
 		vlen = int64(s.Length)
-		if s.Next != nil && !(Iself && s.Next.Name == ".tbss") {
-			vlen = int64(s.Next.Vaddr - s.Vaddr)
+		if i+1 < len(Segdata.Sections) && !(Iself && Segdata.Sections[i+1].Name == ".tbss") {
+			vlen = int64(Segdata.Sections[i+1].Vaddr - s.Vaddr)
 		}
 		s.Vaddr = va
 		va += uint64(vlen)
@@ -2239,17 +2268,17 @@ func (ctxt *Link) address() {
 	Segdwarf.Vaddr = va
 	Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound)))
 	Segdwarf.Filelen = 0
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+	if Headtype == objabi.Hwindows {
 		Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(PEFILEALIGN)))
 	}
-	for s := Segdwarf.Sect; s != nil; s = s.Next {
+	for i, s := range Segdwarf.Sections {
 		vlen = int64(s.Length)
-		if s.Next != nil {
-			vlen = int64(s.Next.Vaddr - s.Vaddr)
+		if i+1 < len(Segdwarf.Sections) {
+			vlen = int64(Segdwarf.Sections[i+1].Vaddr - s.Vaddr)
 		}
 		s.Vaddr = va
 		va += uint64(vlen)
-		if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+		if Headtype == objabi.Hwindows {
 			va = uint64(Rnd(int64(va), PEFILEALIGN))
 		}
 		Segdwarf.Length = va - Segdwarf.Vaddr
@@ -2258,7 +2287,7 @@ func (ctxt *Link) address() {
 	Segdwarf.Filelen = va - Segdwarf.Vaddr
 
 	var (
-		text     = Segtext.Sect
+		text     = Segtext.Sections[0]
 		rodata   = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
 		itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
 		symtab   = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
@@ -2267,8 +2296,10 @@ func (ctxt *Link) address() {
 	)
 	lasttext := text
 	// Could be multiple .text sections
-	for sect := text.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
-		lasttext = sect
+	for _, sect := range Segtext.Sections {
+		if sect.Name == ".text" {
+			lasttext = sect
+		}
 	}
 
 	for _, s := range datap {
@@ -2296,56 +2327,57 @@ func (ctxt *Link) address() {
 		s.Value = int64(sectSym.Sect.Vaddr + 16)
 	}
 
-	ctxt.xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
-	ctxt.xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length))
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
-		ctxt.xdefine(".text", obj.STEXT, int64(text.Vaddr))
-	}
+	ctxt.xdefine("runtime.text", STEXT, int64(text.Vaddr))
+	ctxt.xdefine("runtime.etext", STEXT, int64(lasttext.Vaddr+lasttext.Length))
 
 	// If there are multiple text sections, create runtime.text.n for
 	// their section Vaddr, using n for index
 	n := 1
-	for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
-		symname := fmt.Sprintf("runtime.text.%d", n)
-		ctxt.xdefine(symname, obj.STEXT, int64(sect.Vaddr))
-		n++
+	for _, sect := range Segtext.Sections[1:] {
+		if sect.Name == ".text" {
+			symname := fmt.Sprintf("runtime.text.%d", n)
+			ctxt.xdefine(symname, STEXT, int64(sect.Vaddr))
+			n++
+		} else {
+			break
+		}
 	}
 
-	ctxt.xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
-	ctxt.xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
-	ctxt.xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
-	ctxt.xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
-	ctxt.xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
-	ctxt.xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
+	ctxt.xdefine("runtime.rodata", SRODATA, int64(rodata.Vaddr))
+	ctxt.xdefine("runtime.erodata", SRODATA, int64(rodata.Vaddr+rodata.Length))
+	ctxt.xdefine("runtime.types", SRODATA, int64(types.Vaddr))
+	ctxt.xdefine("runtime.etypes", SRODATA, int64(types.Vaddr+types.Length))
+	ctxt.xdefine("runtime.itablink", SRODATA, int64(itablink.Vaddr))
+	ctxt.xdefine("runtime.eitablink", SRODATA, int64(itablink.Vaddr+itablink.Length))
 
 	sym := ctxt.Syms.Lookup("runtime.gcdata", 0)
 	sym.Attr |= AttrLocal
-	ctxt.xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
+	ctxt.xdefine("runtime.egcdata", SRODATA, Symaddr(sym)+sym.Size)
 	ctxt.Syms.Lookup("runtime.egcdata", 0).Sect = sym.Sect
 
 	sym = ctxt.Syms.Lookup("runtime.gcbss", 0)
 	sym.Attr |= AttrLocal
-	ctxt.xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size)
+	ctxt.xdefine("runtime.egcbss", SRODATA, Symaddr(sym)+sym.Size)
 	ctxt.Syms.Lookup("runtime.egcbss", 0).Sect = sym.Sect
 
-	ctxt.xdefine("runtime.symtab", obj.SRODATA, int64(symtab.Vaddr))
-	ctxt.xdefine("runtime.esymtab", obj.SRODATA, int64(symtab.Vaddr+symtab.Length))
-	ctxt.xdefine("runtime.pclntab", obj.SRODATA, int64(pclntab.Vaddr))
-	ctxt.xdefine("runtime.epclntab", obj.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
-	ctxt.xdefine("runtime.noptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr))
-	ctxt.xdefine("runtime.enoptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
-	ctxt.xdefine("runtime.bss", obj.SBSS, int64(bss.Vaddr))
-	ctxt.xdefine("runtime.ebss", obj.SBSS, int64(bss.Vaddr+bss.Length))
-	ctxt.xdefine("runtime.data", obj.SDATA, int64(data.Vaddr))
-	ctxt.xdefine("runtime.edata", obj.SDATA, int64(data.Vaddr+data.Length))
-	ctxt.xdefine("runtime.noptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr))
-	ctxt.xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
-	ctxt.xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+	ctxt.xdefine("runtime.symtab", SRODATA, int64(symtab.Vaddr))
+	ctxt.xdefine("runtime.esymtab", SRODATA, int64(symtab.Vaddr+symtab.Length))
+	ctxt.xdefine("runtime.pclntab", SRODATA, int64(pclntab.Vaddr))
+	ctxt.xdefine("runtime.epclntab", SRODATA, int64(pclntab.Vaddr+pclntab.Length))
+	ctxt.xdefine("runtime.noptrdata", SNOPTRDATA, int64(noptr.Vaddr))
+	ctxt.xdefine("runtime.enoptrdata", SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
+	ctxt.xdefine("runtime.bss", SBSS, int64(bss.Vaddr))
+	ctxt.xdefine("runtime.ebss", SBSS, int64(bss.Vaddr+bss.Length))
+	ctxt.xdefine("runtime.data", SDATA, int64(data.Vaddr))
+	ctxt.xdefine("runtime.edata", SDATA, int64(data.Vaddr+data.Length))
+	ctxt.xdefine("runtime.noptrbss", SNOPTRBSS, int64(noptrbss.Vaddr))
+	ctxt.xdefine("runtime.enoptrbss", SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
+	ctxt.xdefine("runtime.end", SBSS, int64(Segdata.Vaddr+Segdata.Length))
 }
 
 // add a trampoline with symbol s (to be laid down after the current function)
 func (ctxt *Link) AddTramp(s *Symbol) {
-	s.Type = obj.STEXT
+	s.Type = STEXT
 	s.Attr |= AttrReachable
 	s.Attr |= AttrOnList
 	ctxt.tramps = append(ctxt.tramps, s)
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index ae51681..dbb96fb 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -5,7 +5,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"strings"
@@ -46,7 +46,7 @@ import (
 // Any unreached text symbols are removed from ctxt.Textp.
 func deadcode(ctxt *Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f deadcode\n", obj.Cputime())
+		ctxt.Logf("%5.2f deadcode\n", Cputime())
 	}
 
 	d := &deadcodepass{
@@ -127,27 +127,6 @@ func deadcode(ctxt *Link) {
 	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.
@@ -177,7 +156,7 @@ type deadcodepass struct {
 
 func (d *deadcodepass) cleanupReloc(r *Reloc) {
 	if r.Sym.Attr.Reachable() {
-		r.Type = obj.R_ADDROFF
+		r.Type = objabi.R_ADDROFF
 	} else {
 		if d.ctxt.Debugvlog > 1 {
 			d.ctxt.Logf("removing method %s\n", r.Sym.Name)
@@ -211,7 +190,7 @@ func (d *deadcodepass) mark(s, parent *Symbol) {
 func (d *deadcodepass) markMethod(m methodref) {
 	for _, r := range m.r {
 		d.mark(r.Sym, m.src)
-		r.Type = obj.R_ADDROFF
+		r.Type = objabi.R_ADDROFF
 	}
 }
 
@@ -222,9 +201,6 @@ func (d *deadcodepass) init() {
 
 	if SysArch.Family == sys.ARM {
 		// mark some functions that are only referenced after linker code editing
-		if obj.GOARM == 5 {
-			names = append(names, "_sfloat")
-		}
 		names = append(names, "runtime.read_tls_fallback")
 	}
 
@@ -232,7 +208,7 @@ func (d *deadcodepass) init() {
 		// Mark all symbols defined in this library as reachable when
 		// building a shared library.
 		for _, s := range d.ctxt.Syms.Allsym {
-			if s.Type != 0 && s.Type != obj.SDYNIMPORT {
+			if s.Type != 0 && s.Type != SDYNIMPORT {
 				d.mark(s, nil)
 			}
 		}
@@ -254,9 +230,6 @@ func (d *deadcodepass) init() {
 				}
 			}
 		}
-		for _, name := range markextra {
-			names = append(names, name)
-		}
 		for _, s := range dynexp {
 			d.mark(s, nil)
 		}
@@ -273,7 +246,7 @@ func (d *deadcodepass) flood() {
 	for len(d.markQueue) > 0 {
 		s := d.markQueue[0]
 		d.markQueue = d.markQueue[1:]
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			if d.ctxt.Debugvlog > 1 {
 				d.ctxt.Logf("marktext %s\n", s.Name)
 			}
@@ -308,13 +281,13 @@ func (d *deadcodepass) flood() {
 			if r.Sym == nil {
 				continue
 			}
-			if r.Type == obj.R_WEAKADDROFF {
+			if r.Type == objabi.R_WEAKADDROFF {
 				// An R_WEAKADDROFF relocation is not reason
 				// enough to mark the pointed-to symbol as
 				// reachable.
 				continue
 			}
-			if r.Type != obj.R_METHODOFF {
+			if r.Type != objabi.R_METHODOFF {
 				d.mark(r.Sym, s)
 				continue
 			}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index d111b00..eba8ee3 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -6,7 +6,7 @@ package ld
 
 import (
 	"bytes"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"debug/elf"
 	"fmt"
@@ -14,7 +14,7 @@ import (
 
 // 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.
+// cmd/compile/internal/gc/reflect.go stuffs in these.
 
 // tflag is documented in reflect/type.go.
 //
@@ -65,12 +65,12 @@ func uncommonSize() int    { return 4 + 2 + 2 + 4 + 4 }         // runtime.uncom
 
 // Type.commonType.kind
 func decodetypeKind(s *Symbol) uint8 {
-	return s.P[2*SysArch.PtrSize+7] & obj.KindMask //  0x13 / 0x1f
+	return s.P[2*SysArch.PtrSize+7] & objabi.KindMask //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetypeUsegcprog(s *Symbol) uint8 {
-	return s.P[2*SysArch.PtrSize+7] & obj.KindGCProg //  0x13 / 0x1f
+	return s.P[2*SysArch.PtrSize+7] & objabi.KindGCProg //  0x13 / 0x1f
 }
 
 // Type.commonType.size
@@ -104,7 +104,7 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
 
 // Type.commonType.gc
 func decodetypeGcprog(ctxt *Link, s *Symbol) []byte {
-	if s.Type == obj.SDYNIMPORT {
+	if s.Type == SDYNIMPORT {
 		addr := decodetypeGcprogShlib(ctxt, s)
 		sect := findShlibSection(ctxt, s.File, addr)
 		if sect != nil {
@@ -135,7 +135,7 @@ func decodetypeGcprogShlib(ctxt *Link, s *Symbol) uint64 {
 }
 
 func decodetypeGcmask(ctxt *Link, s *Symbol) []byte {
-	if s.Type == obj.SDYNIMPORT {
+	if s.Type == SDYNIMPORT {
 		addr := decodetypeGcprogShlib(ctxt, s)
 		ptrdata := decodetypePtrdata(ctxt.Arch, s)
 		sect := findShlibSection(ctxt, s.File, addr)
@@ -210,11 +210,11 @@ func decodetypeFuncOutType(arch *sys.Arch, s *Symbol, i int) *Symbol {
 
 // Type.StructType.fields.Slice::length
 func decodetypeStructFieldCount(arch *sys.Arch, s *Symbol) int {
-	return int(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
+	return int(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
 }
 
 func decodetypeStructFieldArrayOff(s *Symbol, i int) int {
-	off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize
+	off := commonsize() + 4*SysArch.PtrSize
 	if decodetypeHasUncommon(s) {
 		off += uncommonSize()
 	}
@@ -254,13 +254,17 @@ func decodetypeStructFieldType(s *Symbol, i int) *Symbol {
 }
 
 func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
+	return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
+}
+
+func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *Symbol, i int) int64 {
 	off := decodetypeStructFieldArrayOff(s, i)
-	return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
+	return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.PtrSize))
 }
 
 // InterfaceType.methods.length
 func decodetypeIfaceMethodCount(arch *sys.Arch, s *Symbol) int64 {
-	return int64(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
+	return int64(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
 }
 
 // methodsig is a fully qualified typed method signature, like
@@ -342,7 +346,7 @@ func decodetypeMethods(arch *sys.Arch, s *Symbol) []methodsig {
 	off := commonsize() // reflect.rtype
 	switch decodetypeKind(s) & kindMask {
 	case kindStruct: // reflect.structType
-		off += 2*SysArch.PtrSize + 2*SysArch.IntSize
+		off += 4 * SysArch.PtrSize
 	case kindPtr: // reflect.ptrType
 		off += SysArch.PtrSize
 	case kindFunc: // reflect.funcType
@@ -356,7 +360,7 @@ func decodetypeMethods(arch *sys.Arch, s *Symbol) []methodsig {
 	case kindMap: // reflect.mapType
 		off += 4*SysArch.PtrSize + 8
 	case kindInterface: // reflect.interfaceType
-		off += SysArch.PtrSize + 2*SysArch.IntSize
+		off += 3 * SysArch.PtrSize
 	default:
 		// just Sizeof(rtype)
 	}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 22d2c54..ba8ace5 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -8,7 +8,6 @@
 //   - assign global variables and types to their packages
 //   - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
 //     ptype struct '[]uint8' and qualifiers need to be quoted away
-//   - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
 //   - file:line info for variables
 //   - make strings a typedef so prettyprinters can see the underlying string type
 
@@ -16,7 +15,7 @@ package ld
 
 import (
 	"cmd/internal/dwarf"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"log"
 	"os"
@@ -64,7 +63,7 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
 		addaddrplus4(c.linkctxt, ls, t.(*Symbol), 0)
 	}
 	r := &ls.R[len(ls.R)-1]
-	r.Type = obj.R_DWARFREF
+	r.Type = objabi.R_DWARFREF
 	r.Add = ofs
 }
 
@@ -76,6 +75,7 @@ var arangessec *Symbol
 var framesec *Symbol
 var infosec *Symbol
 var linesec *Symbol
+var rangesec *Symbol
 
 var gdbscript string
 
@@ -83,7 +83,7 @@ var dwarfp []*Symbol
 
 func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
 	s := ctxt.Syms.Lookup(".debug_abbrev", 0)
-	s.Type = obj.SDWARFSECT
+	s.Type = SDWARFSECT
 	abbrevsym = s
 	Addbytes(s, dwarf.GetAbbrev())
 	return append(syms, s)
@@ -147,8 +147,8 @@ func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version in
 	if name != "" && (abbrev <= dwarf.DW_ABRV_VARIABLE || abbrev >= dwarf.DW_ABRV_NULLTYPE) {
 		if abbrev != dwarf.DW_ABRV_VARIABLE || version == 0 {
 			sym := ctxt.Syms.Lookup(dwarf.InfoPrefix+name, version)
-			sym.Attr |= AttrHidden
-			sym.Type = obj.SDWARFINFO
+			sym.Attr |= AttrNotInSymbolTable
+			sym.Type = SDWARFINFO
 			die.Sym = sym
 		}
 	}
@@ -202,7 +202,7 @@ func find(ctxt *Link, name string) *Symbol {
 	// The string allocation below is optimized away because it is only used in a map lookup.
 	s := ctxt.Syms.ROLookup(string(n), 0)
 	prefixBuf = n[:len(dwarf.InfoPrefix)]
-	if s != nil && s.Type == obj.SDWARFINFO {
+	if s != nil && s.Type == SDWARFINFO {
 		return s
 	}
 	return nil
@@ -228,7 +228,7 @@ func adddwarfref(ctxt *Link, s *Symbol, t *Symbol, size int) int64 {
 		result = addaddrplus4(ctxt, s, t, 0)
 	}
 	r := &s.R[len(s.R)-1]
-	r.Type = obj.R_DWARFREF
+	r.Type = objabi.R_DWARFREF
 	return result
 }
 
@@ -339,8 +339,8 @@ func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) {
 	}
 
 	sym := ctxt.Syms.Lookup(dtolsym(def.Sym).Name+"..def", 0)
-	sym.Attr |= AttrHidden
-	sym.Type = obj.SDWARFINFO
+	sym.Attr |= AttrNotInSymbolTable
+	sym.Type = SDWARFINFO
 	def.Sym = sym
 
 	// The typedef entry must be created after the def,
@@ -381,43 +381,43 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 
 	var die *dwarf.DWDie
 	switch kind {
-	case obj.KindBool:
+	case objabi.KindBool:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
 		newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_boolean, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindInt,
-		obj.KindInt8,
-		obj.KindInt16,
-		obj.KindInt32,
-		obj.KindInt64:
+	case objabi.KindInt,
+		objabi.KindInt8,
+		objabi.KindInt16,
+		objabi.KindInt32,
+		objabi.KindInt64:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
 		newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_signed, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindUint,
-		obj.KindUint8,
-		obj.KindUint16,
-		obj.KindUint32,
-		obj.KindUint64,
-		obj.KindUintptr:
+	case objabi.KindUint,
+		objabi.KindUint8,
+		objabi.KindUint16,
+		objabi.KindUint32,
+		objabi.KindUint64,
+		objabi.KindUintptr:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
 		newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindFloat32,
-		obj.KindFloat64:
+	case objabi.KindFloat32,
+		objabi.KindFloat64:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
 		newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_float, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindComplex64,
-		obj.KindComplex128:
+	case objabi.KindComplex64,
+		objabi.KindComplex128:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
 		newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_complex_float, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindArray:
+	case objabi.KindArray:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
@@ -430,7 +430,7 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 
 		newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
 
-	case obj.KindChan:
+	case objabi.KindChan:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 		s := decodetypeChanElem(gotype)
@@ -439,7 +439,7 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 		// but that would change the order of DIEs we output.
 		newrefattr(die, dwarf.DW_AT_type, s)
 
-	case obj.KindFunc:
+	case objabi.KindFunc:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "void"))
@@ -462,7 +462,7 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 			newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, defgotype(ctxt, s)))
 		}
 
-	case obj.KindInterface:
+	case objabi.KindInterface:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
@@ -475,7 +475,7 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 		}
 		newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
 
-	case obj.KindMap:
+	case objabi.KindMap:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
 		s := decodetypeMapKey(gotype)
 		newrefattr(die, dwarf.DW_AT_go_key, defgotype(ctxt, s))
@@ -485,13 +485,13 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 		// but that would change the order of the DIEs.
 		newrefattr(die, dwarf.DW_AT_type, gotype)
 
-	case obj.KindPtr:
+	case objabi.KindPtr:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		s := decodetypePtrElem(gotype)
 		newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
 
-	case obj.KindSlice:
+	case objabi.KindSlice:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
@@ -499,30 +499,31 @@ func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
 		elem := defgotype(ctxt, s)
 		newrefattr(die, dwarf.DW_AT_go_elem, elem)
 
-	case obj.KindString:
+	case objabi.KindString:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
-	case obj.KindStruct:
+	case objabi.KindStruct:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
 		dotypedef(ctxt, &dwtypes, name, die)
 		newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 		nfields := decodetypeStructFieldCount(ctxt.Arch, gotype)
-		var f string
-		var fld *dwarf.DWDie
-		var s *Symbol
 		for i := 0; i < nfields; i++ {
-			f = decodetypeStructFieldName(gotype, i)
-			s = decodetypeStructFieldType(gotype, i)
+			f := decodetypeStructFieldName(gotype, i)
+			s := decodetypeStructFieldType(gotype, i)
 			if f == "" {
 				f = s.Name[5:] // skip "type."
 			}
-			fld = newdie(ctxt, die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
+			fld := newdie(ctxt, die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
 			newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
-			newmemberoffsetattr(fld, int32(decodetypeStructFieldOffs(ctxt.Arch, gotype, i)))
+			offsetAnon := decodetypeStructFieldOffsAnon(ctxt.Arch, gotype, i)
+			newmemberoffsetattr(fld, int32(offsetAnon>>1))
+			if offsetAnon&1 != 0 { // is embedded field
+				newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
+			}
 		}
 
-	case obj.KindUnsafePointer:
+	case objabi.KindUnsafePointer:
 		die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
 
 	default:
@@ -659,7 +660,7 @@ func mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f
 	name := mkinternaltypename(typename, keyname, valname)
 	symname := dwarf.InfoPrefix + name
 	s := ctxt.Syms.ROLookup(symname, 0)
-	if s != nil && s.Type == obj.SDWARFINFO {
+	if s != nil && s.Type == SDWARFINFO {
 		return s
 	}
 	die := newdie(ctxt, &dwtypes, abbrev, name, 0)
@@ -871,7 +872,7 @@ func finddebugruntimepath(s *Symbol) {
 
 	for i := range s.FuncInfo.File {
 		f := s.FuncInfo.File[i]
-		if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 {
+		if i := strings.Index(f.Name, "runtime/debug.go"); i >= 0 {
 			gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
 			break
 		}
@@ -995,7 +996,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
 	if linesec == nil {
 		linesec = ctxt.Syms.Lookup(".debug_line", 0)
 	}
-	linesec.Type = obj.SDWARFSECT
+	linesec.Type = SDWARFSECT
 	linesec.R = linesec.R[:0]
 
 	ls := linesec
@@ -1012,7 +1013,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
 	lang := dwarf.DW_LANG_Go
 
 	s := ctxt.Textp[0]
-	if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+	if ctxt.DynlinkingGo() && Headtype == objabi.Hdarwin {
 		s = ctxt.Textp[1] // skip runtime.text
 	}
 
@@ -1023,6 +1024,8 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
 	// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
 	compDir := getCompilationDir()
 	newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
+	producer := "Go cmd/compile " + objabi.Version
+	newattr(dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
 
 	// Write .debug_line Line Number Program Header (sec 6.2.4)
 	// Fields marked with (*) must be changed for 64-bit dwarf
@@ -1080,10 +1083,10 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
 		epcs = s
 
 		dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
-		dsym.Attr |= AttrHidden | AttrReachable
-		dsym.Type = obj.SDWARFINFO
+		dsym.Attr |= AttrNotInSymbolTable | AttrReachable
+		dsym.Type = SDWARFINFO
 		for _, r := range dsym.R {
-			if r.Type == obj.R_DWARFREF && r.Sym.Size == 0 {
+			if r.Type == objabi.R_DWARFREF && r.Sym.Size == 0 {
 				if Buildmode == BuildmodeShared {
 					// These type symbols may not be present in BuildmodeShared. Skip.
 					continue
@@ -1178,7 +1181,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
 	if framesec == nil {
 		framesec = ctxt.Syms.Lookup(".debug_frame", 0)
 	}
-	framesec.Type = obj.SDWARFSECT
+	framesec.Type = SDWARFSECT
 	framesec.R = framesec.R[:0]
 	fs := framesec
 	syms = append(syms, fs)
@@ -1288,6 +1291,33 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
 	return syms
 }
 
+func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
+	if rangesec == nil {
+		rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
+	}
+	rangesec.Type = SDWARFSECT
+	rangesec.Attr |= AttrReachable
+	rangesec.R = rangesec.R[:0]
+
+	for _, s := range ctxt.Textp {
+		rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
+		rangeSym.Attr |= AttrReachable
+		rangeSym.Type = SDWARFRANGE
+		rangeSym.Value = rangesec.Size
+		rangesec.P = append(rangesec.P, rangeSym.P...)
+		for _, r := range rangeSym.R {
+			r.Off += int32(rangesec.Size)
+			rangesec.R = append(rangesec.R, r)
+		}
+		rangesec.Size += rangeSym.Size
+	}
+	if rangesec.Size > 0 {
+		// PE does not like empty sections
+		syms = append(syms, rangesec)
+	}
+	return syms
+}
+
 /*
  *  Walk DWarfDebugInfoEntries, and emit .debug_info
  */
@@ -1300,7 +1330,7 @@ func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
 		infosec = ctxt.Syms.Lookup(".debug_info", 0)
 	}
 	infosec.R = infosec.R[:0]
-	infosec.Type = obj.SDWARFINFO
+	infosec.Type = SDWARFINFO
 	infosec.Attr |= AttrReachable
 	syms = append(syms, infosec)
 
@@ -1318,7 +1348,7 @@ func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
 		// Fields marked with (*) must be changed for 64-bit dwarf
 		// This must match COMPUNITHEADERSIZE above.
 		Adduint32(ctxt, s, 0) // unit_length (*), will be filled in later.
-		Adduint16(ctxt, s, 2) // dwarf version (appendix F)
+		Adduint16(ctxt, s, 4) // dwarf version (appendix F)
 
 		// debug_abbrev_offset (*)
 		adddwarfref(ctxt, s, abbrevsym, 4)
@@ -1366,7 +1396,7 @@ func ispubtype(die *dwarf.DWDie) bool {
 
 func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*Symbol) []*Symbol {
 	s := ctxt.Syms.Lookup(sname, 0)
-	s.Type = obj.SDWARFSECT
+	s.Type = SDWARFSECT
 	syms = append(syms, s)
 
 	for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link {
@@ -1406,7 +1436,7 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*S
  */
 func writearanges(ctxt *Link, syms []*Symbol) []*Symbol {
 	s := ctxt.Syms.Lookup(".debug_aranges", 0)
-	s.Type = obj.SDWARFSECT
+	s.Type = 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(SysArch.PtrSize*2))) // don't count unit_length field itself
@@ -1447,10 +1477,19 @@ func writearanges(ctxt *Link, syms []*Symbol) []*Symbol {
 }
 
 func writegdbscript(ctxt *Link, syms []*Symbol) []*Symbol {
+	if Linkmode == LinkExternal && Headtype == objabi.Hwindows && Buildmode == BuildmodeCArchive {
+		// gcc on Windows places .debug_gdb_scripts in the wrong location, which
+		// causes the program not to run. See https://golang.org/issue/20183
+		// Non c-archives can avoid this issue via a linker script
+		// (see fix near writeGDBLinkerScript).
+		// c-archive users would need to specify the linker script manually.
+		// For UX it's better not to deal with this.
+		return syms
+	}
 
 	if gdbscript != "" {
 		s := ctxt.Syms.Lookup(".debug_gdb_scripts", 0)
-		s.Type = obj.SDWARFSECT
+		s.Type = SDWARFSECT
 		syms = append(syms, s)
 		Adduint8(ctxt, s, 1) // magic 1 byte?
 		Addstring(s, gdbscript)
@@ -1474,21 +1513,25 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
 	if *FlagW { // disable dwarf
 		return
 	}
-	if *FlagS && Headtype != obj.Hdarwin {
+	if *FlagS && Headtype != objabi.Hdarwin {
 		return
 	}
-	if Headtype == obj.Hplan9 {
+	if Headtype == objabi.Hplan9 {
 		return
 	}
 
 	if Linkmode == LinkExternal {
-		if !Iself && Headtype != obj.Hdarwin {
+		switch {
+		case Iself:
+		case Headtype == objabi.Hdarwin:
+		case Headtype == objabi.Hwindows:
+		default:
 			return
 		}
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+		ctxt.Logf("%5.2f dwarf\n", Cputime())
 	}
 
 	// Forctxt.Diagnostic messages.
@@ -1503,7 +1546,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
 	die := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
 	newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
 	newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0)
-	newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, obj.KindUintptr, 0)
+	newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, objabi.KindUintptr, 0)
 
 	// Prototypes needed for type synthesis.
 	prototypedies = map[string]*dwarf.DWDie{
@@ -1517,16 +1560,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
 	}
 
 	// Needed by the prettyprinter code for interface inspection.
-	defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime._type"))
-
-	defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime.interfacetype"))
-	defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime.itab"))
+	for _, typ := range []string{
+		"type.runtime._type",
+		"type.runtime.arraytype",
+		"type.runtime.chantype",
+		"type.runtime.functype",
+		"type.runtime.maptype",
+		"type.runtime.ptrtype",
+		"type.runtime.slicetype",
+		"type.runtime.structtype",
+		"type.runtime.interfacetype",
+		"type.runtime.itab",
+		"type.runtime.imethod"} {
+		defgotype(ctxt, lookupOrDiag(ctxt, typ))
+	}
 
 	genasmsym(ctxt, defdwsymb)
 
 	syms := writeabbrev(ctxt, nil)
 	syms, funcs := writelines(ctxt, syms)
 	syms = writeframes(ctxt, syms)
+	syms = writeranges(ctxt, syms)
 
 	synthesizestringtypes(ctxt, dwtypes.Child)
 	synthesizeslicetypes(ctxt, dwtypes.Child)
@@ -1568,6 +1622,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
 	Addstring(shstrtab, ".debug_pubnames")
 	Addstring(shstrtab, ".debug_pubtypes")
 	Addstring(shstrtab, ".debug_gdb_scripts")
+	Addstring(shstrtab, ".debug_ranges")
 	if Linkmode == LinkExternal {
 		Addstring(shstrtab, elfRelType+".debug_info")
 		Addstring(shstrtab, elfRelType+".debug_aranges")
@@ -1575,6 +1630,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
 		Addstring(shstrtab, elfRelType+".debug_frame")
 		Addstring(shstrtab, elfRelType+".debug_pubnames")
 		Addstring(shstrtab, elfRelType+".debug_pubtypes")
+		Addstring(shstrtab, elfRelType+".debug_ranges")
 	}
 }
 
@@ -1595,6 +1651,10 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
 	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
 	sym = ctxt.Syms.Lookup(".debug_frame", 0)
 	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+	sym = ctxt.Syms.Lookup(".debug_ranges", 0)
+	if sym.Sect != nil {
+		putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+	}
 }
 
 /*
@@ -1604,7 +1664,7 @@ func dwarfaddpeheaders(ctxt *Link) {
 	if *FlagW { // disable dwarf
 		return
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		h := newPEDWARFSection(ctxt, sect.Name, int64(sect.Length))
 		fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
 		if uint64(h.PointerToRawData) != fileoff {
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
new file mode 100644
index 0000000..4e7413f
--- /dev/null
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -0,0 +1,194 @@
+// Copyright 2017 The Go Authors. 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 (
+	objfilepkg "cmd/internal/objfile" // renamed to avoid conflict with objfile function
+	"debug/dwarf"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"testing"
+)
+
+func TestRuntimeTypeDIEs(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9; no DWARF symbol table in executables")
+	}
+
+	dir, err := ioutil.TempDir("", "TestRuntimeTypeDIEs")
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	f := gobuild(t, dir, `package main; func main() { }`)
+	defer f.Close()
+
+	dwarf, err := f.DWARF()
+	if err != nil {
+		t.Fatalf("error reading DWARF: %v", err)
+	}
+
+	want := map[string]bool{
+		"runtime._type":         true,
+		"runtime.arraytype":     true,
+		"runtime.chantype":      true,
+		"runtime.functype":      true,
+		"runtime.maptype":       true,
+		"runtime.ptrtype":       true,
+		"runtime.slicetype":     true,
+		"runtime.structtype":    true,
+		"runtime.interfacetype": true,
+		"runtime.itab":          true,
+		"runtime.imethod":       true,
+	}
+
+	found := findTypes(t, dwarf, want)
+	if len(found) != len(want) {
+		t.Errorf("found %v, want %v", found, want)
+	}
+}
+
+func findTypes(t *testing.T, dw *dwarf.Data, want map[string]bool) (found map[string]bool) {
+	found = make(map[string]bool)
+	rdr := dw.Reader()
+	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
+		if err != nil {
+			t.Fatalf("error reading DWARF: %v", err)
+		}
+		switch entry.Tag {
+		case dwarf.TagTypedef:
+			if name, ok := entry.Val(dwarf.AttrName).(string); ok && want[name] {
+				found[name] = true
+			}
+		}
+	}
+	return
+}
+
+func gobuild(t *testing.T, dir string, testfile string) *objfilepkg.File {
+	src := filepath.Join(dir, "test.go")
+	dst := filepath.Join(dir, "out")
+
+	if err := ioutil.WriteFile(src, []byte(testfile), 0666); err != nil {
+		t.Fatal(err)
+	}
+
+	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dst, src)
+	if b, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("build: %s\n", b)
+		t.Fatalf("build error: %v", err)
+	}
+
+	f, err := objfilepkg.Open(dst)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return f
+}
+
+func TestEmbeddedStructMarker(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9; no DWARF symbol table in executables")
+	}
+
+	const prog = `
+package main
+
+import "fmt"
+
+type Foo struct { v int }
+type Bar struct {
+	Foo
+	name string
+}
+type Baz struct {
+	*Foo
+	name string
+}
+
+func main() {
+	bar := Bar{ Foo: Foo{v: 123}, name: "onetwothree"}
+	baz := Baz{ Foo: &bar.Foo, name: "123" }
+	fmt.Println(bar, baz)
+}`
+
+	want := map[string]map[string]bool{
+		"main.Foo": map[string]bool{"v": false},
+		"main.Bar": map[string]bool{"Foo": true, "name": false},
+		"main.Baz": map[string]bool{"Foo": true, "name": false},
+	}
+
+	dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker")
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	f := gobuild(t, dir, prog)
+
+	defer f.Close()
+
+	d, err := f.DWARF()
+	if err != nil {
+		t.Fatalf("error reading DWARF: %v", err)
+	}
+
+	rdr := d.Reader()
+	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
+		if err != nil {
+			t.Fatalf("error reading DWARF: %v", err)
+		}
+		switch entry.Tag {
+		case dwarf.TagStructType:
+			name := entry.Val(dwarf.AttrName).(string)
+			wantMembers := want[name]
+			if wantMembers == nil {
+				continue
+			}
+			gotMembers, err := findMembers(rdr)
+			if err != nil {
+				t.Fatalf("error reading DWARF: %v", err)
+			}
+
+			if !reflect.DeepEqual(gotMembers, wantMembers) {
+				t.Errorf("type %v: got map[member]embedded = %+v, want %+v", name, wantMembers, gotMembers)
+			}
+			delete(want, name)
+		}
+	}
+	if len(want) != 0 {
+		t.Errorf("failed to check all expected types: missing types = %+v", want)
+	}
+}
+
+func findMembers(rdr *dwarf.Reader) (map[string]bool, error) {
+	memberEmbedded := map[string]bool{}
+	// TODO(hyangah): define in debug/dwarf package
+	const goEmbeddedStruct = dwarf.Attr(0x2903)
+	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
+		if err != nil {
+			return nil, err
+		}
+		switch entry.Tag {
+		case dwarf.TagMember:
+			name := entry.Val(dwarf.AttrName).(string)
+			embedded := entry.Val(goEmbeddedStruct).(bool)
+			memberEmbedded[name] = embedded
+		case 0:
+			return memberEmbedded, nil
+		}
+	}
+	return memberEmbedded, nil
+}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 1d8a5dd..0fc947f 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -5,7 +5,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"crypto/sha1"
 	"encoding/binary"
@@ -936,7 +936,7 @@ func Elfinit(ctxt *Link) {
 		fallthrough
 	case sys.AMD64, sys.ARM64, sys.MIPS64:
 		if SysArch.Family == sys.MIPS64 {
-			ehdr.flags = 0x20000000 /* MIPS 3 */
+			ehdr.flags = 0x20000004 /* MIPS 3 CPIC */
 		}
 		elf64 = true
 
@@ -950,7 +950,7 @@ func Elfinit(ctxt *Link) {
 	case sys.ARM, sys.MIPS:
 		if SysArch.Family == sys.ARM {
 			// we use EABI on linux/arm, freebsd/arm, netbsd/arm.
-			if Headtype == obj.Hlinux || Headtype == obj.Hfreebsd || Headtype == obj.Hnetbsd {
+			if Headtype == objabi.Hlinux || Headtype == objabi.Hfreebsd || Headtype == objabi.Hnetbsd {
 				// We set a value here that makes no indication of which
 				// float ABI the object uses, because this is information
 				// used by the dynamic linker to compare executables and
@@ -1451,7 +1451,7 @@ func elfdynhash(ctxt *Link) {
 
 	nsym := Nelfsym
 	s := ctxt.Syms.Lookup(".hash", 0)
-	s.Type = obj.SELFROSECT
+	s.Type = SELFROSECT
 	s.Attr |= AttrReachable
 
 	i := nsym
@@ -1831,7 +1831,7 @@ func Elfemitreloc(ctxt *Link) {
 		Cput(0)
 	}
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		if sect.Name == ".text" {
 			elfrelocsect(ctxt, sect, ctxt.Textp)
 		} else {
@@ -1839,16 +1839,16 @@ func Elfemitreloc(ctxt *Link) {
 		}
 	}
 
-	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrodata.Sections {
 		elfrelocsect(ctxt, sect, datap)
 	}
-	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrelrodata.Sections {
 		elfrelocsect(ctxt, sect, datap)
 	}
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		elfrelocsect(ctxt, sect, datap)
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		elfrelocsect(ctxt, sect, dwarfp)
 	}
 }
@@ -1856,7 +1856,7 @@ func Elfemitreloc(ctxt *Link) {
 func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
 	s := ctxt.Syms.Lookup(sectionName, 0)
 	s.Attr |= AttrReachable
-	s.Type = obj.SELFROSECT
+	s.Type = SELFROSECT
 	// namesz
 	Adduint32(ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
 	// descsz
@@ -1884,7 +1884,7 @@ func (ctxt *Link) doelf() {
 	/* predefine strings we need for section headers */
 	shstrtab := ctxt.Syms.Lookup(".shstrtab", 0)
 
-	shstrtab.Type = obj.SELFROSECT
+	shstrtab.Type = SELFROSECT
 	shstrtab.Attr |= AttrReachable
 
 	Addstring(shstrtab, "")
@@ -1894,19 +1894,16 @@ func (ctxt *Link) doelf() {
 	Addstring(shstrtab, ".bss")
 	Addstring(shstrtab, ".noptrbss")
 
-	// generate .tbss section (except for OpenBSD where it's not supported)
-	// for dynamic internal linker or external linking, so that various
-	// binutils could correctly calculate PT_TLS size.
-	// see https://golang.org/issue/5200.
-	if Headtype != obj.Hopenbsd {
-		if !*FlagD || Linkmode == LinkExternal {
-			Addstring(shstrtab, ".tbss")
-		}
+	// generate .tbss section for dynamic internal linker or external
+	// linking, so that various binutils could correctly calculate
+	// PT_TLS size. See https://golang.org/issue/5200.
+	if !*FlagD || Linkmode == LinkExternal {
+		Addstring(shstrtab, ".tbss")
 	}
-	if Headtype == obj.Hnetbsd {
+	if Headtype == objabi.Hnetbsd {
 		Addstring(shstrtab, ".note.netbsd.ident")
 	}
-	if Headtype == obj.Hopenbsd {
+	if Headtype == objabi.Hopenbsd {
 		Addstring(shstrtab, ".note.openbsd.ident")
 	}
 	if len(buildinfo) > 0 {
@@ -1995,7 +1992,7 @@ func (ctxt *Link) doelf() {
 		/* dynamic symbol table - first entry all zeros */
 		s := ctxt.Syms.Lookup(".dynsym", 0)
 
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 		s.Attr |= AttrReachable
 		if elf64 {
 			s.Size += ELF64SYMSIZE
@@ -2006,7 +2003,7 @@ func (ctxt *Link) doelf() {
 		/* dynamic string table */
 		s = ctxt.Syms.Lookup(".dynstr", 0)
 
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 		s.Attr |= AttrReachable
 		if s.Size == 0 {
 			Addstring(s, "")
@@ -2016,30 +2013,30 @@ func (ctxt *Link) doelf() {
 		/* relocation table */
 		s = ctxt.Syms.Lookup(elfRelType, 0)
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 
 		/* global offset table */
 		s = ctxt.Syms.Lookup(".got", 0)
 
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFGOT // writable
+		s.Type = SELFGOT // writable
 
 		/* ppc64 glink resolver */
 		if SysArch.Family == sys.PPC64 {
 			s := ctxt.Syms.Lookup(".glink", 0)
 			s.Attr |= AttrReachable
-			s.Type = obj.SELFRXSECT
+			s.Type = SELFRXSECT
 		}
 
 		/* hash */
 		s = ctxt.Syms.Lookup(".hash", 0)
 
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 
 		s = ctxt.Syms.Lookup(".got.plt", 0)
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFSECT // writable
+		s.Type = SELFSECT // writable
 
 		s = ctxt.Syms.Lookup(".plt", 0)
 
@@ -2047,30 +2044,30 @@ func (ctxt *Link) doelf() {
 		if SysArch.Family == sys.PPC64 {
 			// In the ppc64 ABI, .plt is a data section
 			// written by the dynamic linker.
-			s.Type = obj.SELFSECT
+			s.Type = SELFSECT
 		} else {
-			s.Type = obj.SELFRXSECT
+			s.Type = SELFRXSECT
 		}
 
 		Thearch.Elfsetupplt(ctxt)
 
 		s = ctxt.Syms.Lookup(elfRelType+".plt", 0)
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 
 		s = ctxt.Syms.Lookup(".gnu.version", 0)
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 
 		s = ctxt.Syms.Lookup(".gnu.version_r", 0)
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFROSECT
+		s.Type = SELFROSECT
 
 		/* define dynamic elf table */
 		s = ctxt.Syms.Lookup(".dynamic", 0)
 
 		s.Attr |= AttrReachable
-		s.Type = obj.SELFSECT // writable
+		s.Type = SELFSECT // writable
 
 		/*
 		 * .dynamic table
@@ -2123,7 +2120,7 @@ func (ctxt *Link) doelf() {
 		// part of the .note.go.abihash section in data.go:func address().
 		s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
 		s.Attr |= AttrLocal
-		s.Type = obj.SRODATA
+		s.Type = SRODATA
 		s.Attr |= AttrSpecial
 		s.Attr |= AttrReachable
 		s.Size = int64(sha1.Size)
@@ -2170,7 +2167,7 @@ func Asmbelfsetup() {
 	/* This null SHdr must appear before all others */
 	elfshname("")
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		// There could be multiple .text sections. Instead check the Elfsect
 		// field to determine if already has an ElfShdr and if not, create one.
 		if sect.Name == ".text" {
@@ -2181,16 +2178,16 @@ func Asmbelfsetup() {
 			elfshalloc(sect)
 		}
 	}
-	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrodata.Sections {
 		elfshalloc(sect)
 	}
-	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrelrodata.Sections {
 		elfshalloc(sect)
 	}
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		elfshalloc(sect)
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		elfshalloc(sect)
 	}
 }
@@ -2219,7 +2216,7 @@ func Asmbelf(ctxt *Link, symo int64) {
 	elfreserve := int64(ELFRESERVE)
 
 	numtext := int64(0)
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		if sect.Name == ".text" {
 			numtext++
 		}
@@ -2279,7 +2276,7 @@ func Asmbelf(ctxt *Link, symo int64) {
 	 * segment boundaries downwards to include it.
 	 * Except on NaCl where it must not be loaded.
 	 */
-	if Headtype != obj.Hnacl {
+	if Headtype != objabi.Hnacl {
 		o := int64(Segtext.Vaddr - pph.vaddr)
 		Segtext.Vaddr -= uint64(o)
 		Segtext.Length += uint64(o)
@@ -2297,22 +2294,22 @@ func Asmbelf(ctxt *Link, symo int64) {
 		sh.addralign = 1
 		if interpreter == "" {
 			switch Headtype {
-			case obj.Hlinux:
+			case objabi.Hlinux:
 				interpreter = Thearch.Linuxdynld
 
-			case obj.Hfreebsd:
+			case objabi.Hfreebsd:
 				interpreter = Thearch.Freebsddynld
 
-			case obj.Hnetbsd:
+			case objabi.Hnetbsd:
 				interpreter = Thearch.Netbsddynld
 
-			case obj.Hopenbsd:
+			case objabi.Hopenbsd:
 				interpreter = Thearch.Openbsddynld
 
-			case obj.Hdragonfly:
+			case objabi.Hdragonfly:
 				interpreter = Thearch.Dragonflydynld
 
-			case obj.Hsolaris:
+			case objabi.Hsolaris:
 				interpreter = Thearch.Solarisdynld
 			}
 		}
@@ -2326,14 +2323,14 @@ func Asmbelf(ctxt *Link, symo int64) {
 	}
 
 	pnote = nil
-	if Headtype == obj.Hnetbsd || Headtype == obj.Hopenbsd {
+	if Headtype == objabi.Hnetbsd || Headtype == objabi.Hopenbsd {
 		var sh *ElfShdr
 		switch Headtype {
-		case obj.Hnetbsd:
+		case objabi.Hnetbsd:
 			sh = elfshname(".note.netbsd.ident")
 			resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
 
-		case obj.Hopenbsd:
+		case objabi.Hopenbsd:
 			sh = elfshname(".note.openbsd.ident")
 			resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
 		}
@@ -2370,10 +2367,10 @@ func Asmbelf(ctxt *Link, symo int64) {
 	// Additions to the reserved area must be above this line.
 
 	elfphload(&Segtext)
-	if Segrodata.Sect != nil {
+	if len(Segrodata.Sections) > 0 {
 		elfphload(&Segrodata)
 	}
-	if Segrelrodata.Sect != nil {
+	if len(Segrelrodata.Sections) > 0 {
 		elfphload(&Segrelrodata)
 		elfphrelro(&Segrelrodata)
 	}
@@ -2525,27 +2522,22 @@ func Asmbelf(ctxt *Link, symo int64) {
 		/*
 		 * Thread-local storage segment (really just size).
 		 */
-		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
-		// not currently support it. This is handled
-		// appropriately in runtime/cgo.
-		if Headtype != obj.Hopenbsd {
-			tlssize := uint64(0)
-			for sect := Segdata.Sect; sect != nil; sect = sect.Next {
-				if sect.Name == ".tbss" {
-					tlssize = sect.Length
-				}
-			}
-			if tlssize != 0 {
-				ph := newElfPhdr()
-				ph.type_ = PT_TLS
-				ph.flags = PF_R
-				ph.memsz = tlssize
-				ph.align = uint64(SysArch.RegSize)
+		tlssize := uint64(0)
+		for _, sect := range Segdata.Sections {
+			if sect.Name == ".tbss" {
+				tlssize = sect.Length
 			}
 		}
+		if tlssize != 0 {
+			ph := newElfPhdr()
+			ph.type_ = PT_TLS
+			ph.flags = PF_R
+			ph.memsz = tlssize
+			ph.align = uint64(SysArch.RegSize)
+		}
 	}
 
-	if Headtype == obj.Hlinux {
+	if Headtype == objabi.Hlinux {
 		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
@@ -2555,7 +2547,7 @@ func Asmbelf(ctxt *Link, symo int64) {
 		ph.type_ = PT_PAX_FLAGS
 		ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
 		ph.align = uint64(SysArch.RegSize)
-	} else if Headtype == obj.Hsolaris {
+	} else if Headtype == objabi.Hsolaris {
 		ph := newElfPhdr()
 		ph.type_ = PT_SUNWSTACK
 		ph.flags = PF_W + PF_R
@@ -2574,40 +2566,40 @@ elfobj:
 		elfshname(".strtab")
 	}
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		elfshbits(sect)
 	}
-	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrodata.Sections {
 		elfshbits(sect)
 	}
-	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segrelrodata.Sections {
 		elfshbits(sect)
 	}
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		elfshbits(sect)
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		elfshbits(sect)
 	}
 
 	if Linkmode == LinkExternal {
-		for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+		for _, sect := range Segtext.Sections {
 			elfshreloc(sect)
 		}
-		for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+		for _, sect := range Segrodata.Sections {
 			elfshreloc(sect)
 		}
-		for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+		for _, sect := range Segrelrodata.Sections {
 			elfshreloc(sect)
 		}
-		for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		for _, sect := range Segdata.Sections {
 			elfshreloc(sect)
 		}
 		for _, s := range dwarfp {
-			if len(s.R) > 0 || s.Type == obj.SDWARFINFO {
+			if len(s.R) > 0 || s.Type == SDWARFINFO {
 				elfshreloc(s.Sect)
 			}
-			if s.Type == obj.SDWARFINFO {
+			if s.Type == SDWARFINFO {
 				break
 			}
 		}
@@ -2642,13 +2634,13 @@ elfobj:
 	eh.ident[EI_MAG1] = 'E'
 	eh.ident[EI_MAG2] = 'L'
 	eh.ident[EI_MAG3] = 'F'
-	if Headtype == obj.Hfreebsd {
+	if Headtype == objabi.Hfreebsd {
 		eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
-	} else if Headtype == obj.Hnetbsd {
+	} else if Headtype == objabi.Hnetbsd {
 		eh.ident[EI_OSABI] = ELFOSABI_NETBSD
-	} else if Headtype == obj.Hopenbsd {
+	} else if Headtype == objabi.Hopenbsd {
 		eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
-	} else if Headtype == obj.Hdragonfly {
+	} else if Headtype == objabi.Hdragonfly {
 		eh.ident[EI_OSABI] = ELFOSABI_NONE
 	}
 	if elf64 {
@@ -2691,10 +2683,10 @@ elfobj:
 		a += int64(elfwriteinterp())
 	}
 	if Linkmode != LinkExternal {
-		if Headtype == obj.Hnetbsd {
+		if Headtype == objabi.Hnetbsd {
 			a += int64(elfwritenetbsdsig())
 		}
-		if Headtype == obj.Hopenbsd {
+		if Headtype == objabi.Hopenbsd {
 			a += int64(elfwriteopenbsdsig())
 		}
 		if len(buildinfo) > 0 {
@@ -2723,7 +2715,7 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
 		/* type */
 		t := STB_GLOBAL << 4
 
-		if s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
+		if s.Attr.CgoExport() && s.Type&SMASK == STEXT {
 			t |= STT_FUNC
 		} else {
 			t |= STT_OBJECT
@@ -2734,14 +2726,14 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
 		Adduint8(ctxt, d, 0)
 
 		/* section where symbol is defined */
-		if s.Type == obj.SDYNIMPORT {
+		if s.Type == SDYNIMPORT {
 			Adduint16(ctxt, d, SHN_UNDEF)
 		} else {
 			Adduint16(ctxt, d, 1)
 		}
 
 		/* value */
-		if s.Type == obj.SDYNIMPORT {
+		if s.Type == SDYNIMPORT {
 			Adduint64(ctxt, d, 0)
 		} else {
 			Addaddr(ctxt, d, s)
@@ -2765,7 +2757,7 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
 		Adduint32(ctxt, d, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
 
 		/* value */
-		if s.Type == obj.SDYNIMPORT {
+		if s.Type == SDYNIMPORT {
 			Adduint32(ctxt, d, 0)
 		} else {
 			Addaddr(ctxt, d, s)
@@ -2778,9 +2770,9 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
 		t := STB_GLOBAL << 4
 
 		// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
-		if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
+		if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&SMASK == STEXT {
 			t |= STT_FUNC
-		} else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
+		} else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&SMASK == STEXT {
 			t |= STT_FUNC
 		} else {
 			t |= STT_OBJECT
@@ -2789,7 +2781,7 @@ func Elfadddynsym(ctxt *Link, s *Symbol) {
 		Adduint8(ctxt, d, 0)
 
 		/* shndx */
-		if s.Type == obj.SDYNIMPORT {
+		if s.Type == SDYNIMPORT {
 			Adduint16(ctxt, d, SHN_UNDEF)
 		} else {
 			Adduint16(ctxt, d, 1)
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 5b84c3d..2930a6b 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -9,7 +9,7 @@ package ld
 import (
 	"bytes"
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"io"
 	"os"
@@ -174,7 +174,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
 				// to force a link of foo.so.
 				havedynamic = 1
 
-				if Headtype == obj.Hdarwin {
+				if Headtype == objabi.Hdarwin {
 					Machoadddynlib(lib)
 				} else {
 					dynlib = append(dynlib, lib)
@@ -190,12 +190,12 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
 			s = ctxt.Syms.Lookup(local, 0)
 			if local != f[1] {
 			}
-			if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ {
+			if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
 				s.Dynimplib = lib
 				s.Extname = remote
 				s.Dynimpvers = q
-				if s.Type != obj.SHOSTOBJ {
-					s.Type = obj.SDYNIMPORT
+				if s.Type != SHOSTOBJ {
+					s.Type = SDYNIMPORT
 				}
 				havedynamic = 1
 			}
@@ -209,7 +209,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
 			}
 			local = f[1]
 			s = ctxt.Syms.Lookup(local, 0)
-			s.Type = obj.SHOSTOBJ
+			s.Type = SHOSTOBJ
 			s.Size = 0
 			continue
 		}
@@ -322,9 +322,9 @@ func Adddynsym(ctxt *Link, s *Symbol) {
 
 	if Iself {
 		Elfadddynsym(ctxt, s)
-	} else if Headtype == obj.Hdarwin {
+	} else if Headtype == objabi.Hdarwin {
 		Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname)
-	} else if Headtype == obj.Hwindows {
+	} else if Headtype == objabi.Hwindows {
 		// already taken care of
 	} else {
 		Errorf(s, "adddynsym: unsupported binary format")
@@ -337,7 +337,7 @@ func fieldtrack(ctxt *Link) {
 	for _, s := range ctxt.Syms.Allsym {
 		if strings.HasPrefix(s.Name, "go.track.") {
 			s.Attr |= AttrSpecial // do not lay out in data segment
-			s.Attr |= AttrHidden
+			s.Attr |= AttrNotInSymbolTable
 			if s.Attr.Reachable() {
 				buf.WriteString(s.Name[9:])
 				for p := s.Reachparent; p != nil; p = p.Reachparent {
@@ -347,7 +347,7 @@ func fieldtrack(ctxt *Link) {
 				buf.WriteString("\n")
 			}
 
-			s.Type = obj.SCONST
+			s.Type = SCONST
 			s.Value = 0
 		}
 	}
@@ -360,10 +360,11 @@ func fieldtrack(ctxt *Link) {
 		return
 	}
 	addstrdata(ctxt, *flagFieldTrack, buf.String())
+	s.Type = SDATA
 }
 
 func (ctxt *Link) addexport() {
-	if Headtype == obj.Hdarwin {
+	if Headtype == objabi.Hdarwin {
 		return
 	}
 
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index 4750e82..fc41372 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -32,8 +32,8 @@
 package ld
 
 import (
-	"cmd/internal/obj"
 	"io/ioutil"
+	"log"
 	"os"
 	"path"
 	"path/filepath"
@@ -41,6 +41,51 @@ import (
 	"strings"
 )
 
+func (ctxt *Link) readImportCfg(file string) {
+	ctxt.PackageFile = make(map[string]string)
+	ctxt.PackageShlib = make(map[string]string)
+	data, err := ioutil.ReadFile(file)
+	if err != nil {
+		log.Fatalf("-importcfg: %v", err)
+	}
+
+	for lineNum, line := range strings.Split(string(data), "\n") {
+		lineNum++ // 1-based
+		line = strings.TrimSpace(line)
+		if line == "" {
+			continue
+		}
+		if line == "" || strings.HasPrefix(line, "#") {
+			continue
+		}
+
+		var verb, args string
+		if i := strings.Index(line, " "); i < 0 {
+			verb = line
+		} else {
+			verb, args = line[:i], strings.TrimSpace(line[i+1:])
+		}
+		var before, after string
+		if i := strings.Index(args, "="); i >= 0 {
+			before, after = args[:i], args[i+1:]
+		}
+		switch verb {
+		default:
+			log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
+		case "packagefile":
+			if before == "" || after == "" {
+				log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
+			}
+			ctxt.PackageFile[before] = after
+		case "packageshlib":
+			if before == "" || after == "" {
+				log.Fatalf(`%s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, file, lineNum)
+			}
+			ctxt.PackageShlib[before] = after
+		}
+	}
+}
+
 func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
 	name := path.Clean(pathname)
 
@@ -51,35 +96,44 @@ func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
 	}
 
 	// already loaded?
-	for i := 0; i < len(ctxt.Library); i++ {
-		if ctxt.Library[i].Pkg == pkg {
-			return ctxt.Library[i]
-		}
+	if l := ctxt.LibraryByPkg[pkg]; l != nil {
+		return l
 	}
 
 	var pname string
 	isshlib := false
-	if filepath.IsAbs(name) {
-		pname = name
+
+	if *FlagLinkshared && ctxt.PackageShlib[name] != "" {
+		pname = ctxt.PackageShlib[name]
+		isshlib = true
+	} else if ctxt.PackageFile != nil {
+		pname = ctxt.PackageFile[name]
+		if pname == "" {
+			ctxt.Logf("cannot find package %s (using -importcfg)\n", name)
+			return nil
+		}
 	} else {
-		// try dot, -L "libdir", and then goroot.
-		for _, dir := range ctxt.Libdir {
-			if *FlagLinkshared {
-				pname = dir + "/" + pkg + ".shlibname"
+		if filepath.IsAbs(name) {
+			pname = name
+		} else {
+			// try dot, -L "libdir", and then goroot.
+			for _, dir := range ctxt.Libdir {
+				if *FlagLinkshared {
+					pname = dir + "/" + pkg + ".shlibname"
+					if _, err := os.Stat(pname); err == nil {
+						isshlib = true
+						break
+					}
+				}
+				pname = dir + "/" + name
 				if _, err := os.Stat(pname); err == nil {
-					isshlib = true
 					break
 				}
 			}
-			pname = dir + "/" + name
-			if _, err := os.Stat(pname); err == nil {
-				break
-			}
 		}
+		pname = path.Clean(pname)
 	}
 
-	pname = path.Clean(pname)
-
 	if ctxt.Debugvlog > 1 {
 		ctxt.Logf("%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
 	}
@@ -98,18 +152,17 @@ func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
  *	pkg: package import path, e.g. container/vector
  */
 func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) *Library {
-	for i := 0; i < len(ctxt.Library); i++ {
-		if pkg == ctxt.Library[i].Pkg {
-			return ctxt.Library[i]
-		}
+	if l := ctxt.LibraryByPkg[pkg]; l != nil {
+		return l
 	}
 
 	if ctxt.Debugvlog > 1 {
-		ctxt.Logf("%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
+		ctxt.Logf("%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", Cputime(), srcref, objref, file, pkg, shlibnamefile)
 	}
 
-	ctxt.Library = append(ctxt.Library, &Library{})
-	l := ctxt.Library[len(ctxt.Library)-1]
+	l := &Library{}
+	ctxt.LibraryByPkg[pkg] = l
+	ctxt.Library = append(ctxt.Library, l)
 	l.Objref = objref
 	l.Srcref = srcref
 	l.File = file
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
index 00e8f37..d4f9fc4 100644
--- a/src/cmd/link/internal/ld/ldelf.go
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -3,7 +3,7 @@ package ld
 import (
 	"bytes"
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
@@ -444,7 +444,7 @@ func parseArmAttributes(ctxt *Link, e binary.ByteOrder, data []byte) {
 
 func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f ldelf %s\n", obj.Cputime(), pn)
+		ctxt.Logf("%5.2f ldelf %s\n", Cputime(), pn)
 	}
 
 	localSymVersion := ctxt.Syms.IncVersion()
@@ -453,7 +453,6 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	var add uint64
 	var e binary.ByteOrder
 	var elfobj *ElfObj
-	var err error
 	var flag int
 	var hdr *ElfHdrBytes
 	var hdrbuf [64]uint8
@@ -472,12 +471,14 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	var sym ElfSym
 	var symbols []*Symbol
 	if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
-		goto bad
+		Errorf(nil, "%s: malformed elf file: %v", pn, err)
+		return
 	}
 	hdr = new(ElfHdrBytes)
 	binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
 	if string(hdr.Ident[:4]) != "\x7FELF" {
-		goto bad
+		Errorf(nil, "%s: malformed elf file", pn)
+		return
 	}
 	switch hdr.Ident[5] {
 	case ElfDataLsb:
@@ -487,7 +488,8 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		e = binary.BigEndian
 
 	default:
-		goto bad
+		Errorf(nil, "%s: malformed elf file", pn)
+		return
 	}
 
 	// read header
@@ -534,8 +536,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 
 	elfobj.is64 = is64
 
-	if uint32(hdr.Ident[6]) != elfobj.version {
-		goto bad
+	if v := uint32(hdr.Ident[6]); v != elfobj.version {
+		Errorf(nil, "%s: malformed elf version: got %d, want %d", pn, v, elfobj.version)
+		return
 	}
 
 	if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
@@ -603,14 +606,16 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	elfobj.nsect = uint(elfobj.shnum)
 	for i := 0; uint(i) < elfobj.nsect; i++ {
 		if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
-			goto bad
+			Errorf(nil, "%s: malformed elf file", pn)
+			return
 		}
 		sect = &elfobj.sect[i]
 		if is64 != 0 {
 			var b ElfSectBytes64
 
-			if err = binary.Read(f, e, &b); err != nil {
-				goto bad
+			if err := binary.Read(f, e, &b); err != nil {
+				Errorf(nil, "%s: malformed elf file: %v", pn, err)
+				return
 			}
 
 			sect.nameoff = e.Uint32(b.Name[:])
@@ -626,8 +631,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		} else {
 			var b ElfSectBytes
 
-			if err = binary.Read(f, e, &b); err != nil {
-				goto bad
+			if err := binary.Read(f, e, &b); err != nil {
+				Errorf(nil, "%s: malformed elf file: %v", pn, err)
+				return
 			}
 
 			sect.nameoff = e.Uint32(b.Name[:])
@@ -645,13 +651,14 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 
 	// read section string table and translate names
 	if elfobj.shstrndx >= uint32(elfobj.nsect) {
-		err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
-		goto bad
+		Errorf(nil, "%s: malformed elf file: shstrndx out of range %d >= %d", pn, elfobj.shstrndx, elfobj.nsect)
+		return
 	}
 
 	sect = &elfobj.sect[elfobj.shstrndx]
-	if err = elfmap(elfobj, sect); err != nil {
-		goto bad
+	if err := elfmap(elfobj, sect); err != nil {
+		Errorf(nil, "%s: malformed elf file: %v", pn, err)
+		return
 	}
 	for i := 0; uint(i) < elfobj.nsect; i++ {
 		if elfobj.sect[i].nameoff != 0 {
@@ -679,11 +686,13 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
 	}
 
-	if err = elfmap(elfobj, elfobj.symtab); err != nil {
-		goto bad
+	if err := elfmap(elfobj, elfobj.symtab); err != nil {
+		Errorf(nil, "%s: malformed elf file: %v", pn, err)
+		return
 	}
-	if err = elfmap(elfobj, elfobj.symstr); err != nil {
-		goto bad
+	if err := elfmap(elfobj, elfobj.symstr); err != nil {
+		Errorf(nil, "%s: malformed elf file: %v", pn, err)
+		return
 	}
 
 	// load text and data segments into memory.
@@ -695,8 +704,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	for i := 0; uint(i) < elfobj.nsect; i++ {
 		sect = &elfobj.sect[i]
 		if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
-			if err = elfmap(elfobj, sect); err != nil {
-				goto bad
+			if err := elfmap(elfobj, sect); err != nil {
+				Errorf(nil, "%s: malformed elf file: %v", pn, err)
+				return
 			}
 			parseArmAttributes(ctxt, e, sect.base[:sect.size])
 		}
@@ -704,8 +714,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			continue
 		}
 		if sect.type_ != ElfSectNobits {
-			if err = elfmap(elfobj, sect); err != nil {
-				goto bad
+			if err := elfmap(elfobj, sect); err != nil {
+				Errorf(nil, "%s: malformed elf file: %v", pn, err)
+				return
 			}
 		}
 
@@ -714,25 +725,25 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 
 		switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
 		default:
-			err = fmt.Errorf("unexpected flags for ELF section %s", sect.name)
-			goto bad
+			Errorf(nil, "%s: unexpected flags for ELF section %s", pn, sect.name)
+			return
 
 		case ElfSectFlagAlloc:
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 
 		case ElfSectFlagAlloc + ElfSectFlagWrite:
 			if sect.type_ == ElfSectNobits {
-				s.Type = obj.SNOPTRBSS
+				s.Type = SNOPTRBSS
 			} else {
-				s.Type = obj.SNOPTRDATA
+				s.Type = SNOPTRDATA
 			}
 
 		case ElfSectFlagAlloc + ElfSectFlagExec:
-			s.Type = obj.STEXT
+			s.Type = STEXT
 		}
 
 		if sect.name == ".got" || sect.name == ".toc" {
-			s.Type = obj.SELFGOT
+			s.Type = SELFGOT
 		}
 		if sect.type_ == ElfSectProgbits {
 			s.P = sect.base
@@ -749,8 +760,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 	symbols = make([]*Symbol, elfobj.nsymtab)
 
 	for i := 1; i < elfobj.nsymtab; i++ {
-		if err = readelfsym(ctxt, elfobj, i, &sym, 1, localSymVersion); err != nil {
-			goto bad
+		if err := readelfsym(ctxt, elfobj, i, &sym, 1, localSymVersion); err != nil {
+			Errorf(nil, "%s: malformed elf file: %v", pn, err)
+			return
 		}
 		symbols[i] = sym.sym
 		if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone && sym.type_ != ElfSymTypeCommon {
@@ -761,8 +773,8 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			if uint64(s.Size) < sym.size {
 				s.Size = int64(sym.size)
 			}
-			if s.Type == 0 || s.Type == obj.SXREF {
-				s.Type = obj.SNOPTRBSS
+			if s.Type == 0 || s.Type == SXREF {
+				s.Type = SNOPTRBSS
 			}
 			continue
 		}
@@ -804,14 +816,14 @@ func ldelf(ctxt *Link, f *bio.Reader, 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
+		s.Type = sect.sym.Type | s.Type&^SMASK | SSUB
 		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 sect.sym.Type == STEXT {
 			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Errorf(s, "%s: duplicate symbol definition", pn)
 			}
@@ -838,7 +850,7 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		if s.Sub != nil {
 			s.Sub = listsort(s.Sub)
 		}
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			if s.Attr.OnList() {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -864,8 +876,9 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			continue
 		}
 		sect = &elfobj.sect[rsect.info]
-		if err = elfmap(elfobj, rsect); err != nil {
-			goto bad
+		if err := elfmap(elfobj, rsect); err != nil {
+			Errorf(nil, "%s: malformed elf file: %v", pn, err)
+			return
 		}
 		rela = 0
 		if rsect.type_ == ElfSectRela {
@@ -911,19 +924,20 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
 				rp.Sym = nil
 			} else {
-				if err = readelfsym(ctxt, elfobj, int(info>>32), &sym, 0, 0); err != nil {
-					goto bad
+				if err := readelfsym(ctxt, elfobj, int(info>>32), &sym, 0, 0); err != nil {
+					Errorf(nil, "%s: malformed elf file: %v", pn, err)
+					return
 				}
 				sym.sym = symbols[info>>32]
 				if sym.sym == nil {
-					err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
-					goto bad
+					Errorf(nil, "%s: malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", pn, sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
+					return
 				}
 
 				rp.Sym = sym.sym
 			}
 
-			rp.Type = 256 + obj.RelocType(info)
+			rp.Type = 256 + objabi.RelocType(info)
 			rp.Siz = relSize(ctxt, pn, uint32(info))
 			if rela != 0 {
 				rp.Add = int64(add)
@@ -954,11 +968,6 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		s.R = r
 		s.R = s.R[:n]
 	}
-
-	return
-
-bad:
-	Errorf(nil, "%s: malformed elf file: %v", pn, err)
 }
 
 func section(elfobj *ElfObj, name string) *ElfSect {
@@ -1051,7 +1060,7 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, sym *ElfSym, needSym int, loc
 				// set dupok generally. See http://codereview.appspot.com/5823055/
 				// comment #5 for details.
 				if s != nil && sym.other == 2 {
-					s.Type |= obj.SHIDDEN
+					s.Type |= SHIDDEN
 					s.Attr |= AttrDuplicateOK
 				}
 			}
@@ -1068,7 +1077,7 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, sym *ElfSym, needSym int, loc
 				// so put it in the hash table.
 				if needSym != 0 {
 					s = ctxt.Syms.Lookup(sym.name, localSymVersion)
-					s.Type |= obj.SHIDDEN
+					s.Type |= SHIDDEN
 				}
 
 				break
@@ -1080,14 +1089,14 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, sym *ElfSym, needSym int, loc
 				// don't bother to add them into the hash table
 				s = ctxt.Syms.newsym(sym.name, localSymVersion)
 
-				s.Type |= obj.SHIDDEN
+				s.Type |= SHIDDEN
 			}
 
 		case ElfSymBindWeak:
 			if needSym != 0 {
 				s = ctxt.Syms.Lookup(sym.name, 0)
 				if sym.other == 2 {
-					s.Type |= obj.SHIDDEN
+					s.Type |= SHIDDEN
 				}
 			}
 
@@ -1098,7 +1107,7 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, sym *ElfSym, needSym int, loc
 	}
 
 	if s != nil && s.Type == 0 && sym.type_ != ElfSymTypeSection {
-		s.Type = obj.SXREF
+		s.Type = SXREF
 	}
 	sym.sym = s
 
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
index 54812b1..7bfa67d 100644
--- a/src/cmd/link/internal/ld/ldmacho.go
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -2,7 +2,7 @@ package ld
 
 import (
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
@@ -602,16 +602,16 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 
 		if sect.segname == "__TEXT" {
 			if sect.name == "__text" {
-				s.Type = obj.STEXT
+				s.Type = STEXT
 			} else {
-				s.Type = obj.SRODATA
+				s.Type = SRODATA
 			}
 		} else {
 			if sect.name == "__bss" {
-				s.Type = obj.SNOPTRBSS
+				s.Type = SNOPTRBSS
 				s.P = s.P[:0]
 			} else {
-				s.Type = obj.SNOPTRDATA
+				s.Type = SNOPTRDATA
 			}
 		}
 
@@ -663,7 +663,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
 		}
 
-		s.Type = outer.Type | obj.SSUB
+		s.Type = outer.Type | SSUB
 		s.Sub = outer.Sub
 		outer.Sub = s
 		s.Outer = outer
@@ -671,7 +671,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 		if !s.Attr.CgoExportDynamic() {
 			s.Dynimplib = "" // satisfy dynimport
 		}
-		if outer.Type == obj.STEXT {
+		if outer.Type == STEXT {
 			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Errorf(s, "%s: duplicate symbol definition", pn)
 			}
@@ -702,7 +702,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			}
 		}
 
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			if s.Attr.OnList() {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -772,7 +772,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 				// want to make it pc-relative aka relative to rp->off+4
 				// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
 				// adjust rp->add accordingly.
-				rp.Type = obj.R_PCREL
+				rp.Type = objabi.R_PCREL
 
 				rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
 
@@ -828,7 +828,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
 			}
 
 			rp.Siz = rel.length
-			rp.Type = 512 + (obj.RelocType(rel.type_) << 1) + obj.RelocType(rel.pcrel)
+			rp.Type = 512 + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel)
 			rp.Off = int32(rel.addr)
 
 			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
index f9c49d0..14f56d4 100644
--- a/src/cmd/link/internal/ld/ldpe.go
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -6,7 +6,7 @@ package ld
 
 import (
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"debug/pe"
 	"errors"
@@ -18,6 +18,7 @@ import (
 )
 
 const (
+	// TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 (same with IMAGE_SYM_DTYPE_POINTER and IMAGE_SYM_DTYPE_FUNCTION)
 	IMAGE_SYM_UNDEFINED              = 0
 	IMAGE_SYM_ABSOLUTE               = -1
 	IMAGE_SYM_DEBUG                  = -2
@@ -126,7 +127,7 @@ func ldpe(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) {
 
 func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) error {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f ldpe %s\n", obj.Cputime(), pn)
+		ctxt.Logf("%5.2f ldpe %s\n", Cputime(), pn)
 	}
 
 	localSymVersion := ctxt.Syms.IncVersion()
@@ -161,34 +162,35 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 			continue
 		}
 
-		data, err := sect.Data()
-		if err != nil {
-			return err
-		}
-		sectdata[sect] = data
-
 		name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
 		s := ctxt.Syms.Lookup(name, localSymVersion)
 
 		switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 
 		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
-			s.Type = obj.SNOPTRBSS
+			s.Type = SNOPTRBSS
 
 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
-			s.Type = obj.SNOPTRDATA
+			s.Type = SNOPTRDATA
 
 		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
-			s.Type = obj.STEXT
+			s.Type = STEXT
 
 		default:
 			return fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
 		}
 
-		s.P = data
-		s.Size = int64(len(data))
+		if s.Type != SNOPTRBSS {
+			data, err := sect.Data()
+			if err != nil {
+				return err
+			}
+			sectdata[sect] = data
+			s.P = data
+		}
+		s.Size = int64(sect.Size)
 		sectsyms[sect] = s
 		if sect.Name == ".rsrc" {
 			setpersrc(ctxt, s)
@@ -242,12 +244,12 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
 				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
 				IMAGE_REL_AMD64_ADDR32NB:
-				rp.Type = obj.R_PCREL
+				rp.Type = objabi.R_PCREL
 
 				rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
 
 			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
-				rp.Type = obj.R_ADDR
+				rp.Type = objabi.R_ADDR
 
 				// load addend from image
 				rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
@@ -255,7 +257,7 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
 				rp.Siz = 8
 
-				rp.Type = obj.R_ADDR
+				rp.Type = objabi.R_ADDR
 
 				// load addend from image
 				rp.Add = int64(Le64(sectdata[rsect][rp.Off:]))
@@ -312,11 +314,11 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 		}
 
 		if pesym.SectionNumber == 0 { // extern
-			if s.Type == obj.SDYNIMPORT {
+			if s.Type == SDYNIMPORT {
 				s.Plt = -2 // flag for dynimport in PE object files.
 			}
-			if s.Type == obj.SXREF && pesym.Value > 0 { // global data
-				s.Type = obj.SNOPTRDATA
+			if s.Type == SXREF && pesym.Value > 0 { // global data
+				s.Type = SNOPTRDATA
 				s.Size = int64(pesym.Value)
 			}
 
@@ -344,11 +346,11 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 		sectsym := sectsyms[sect]
 		s.Sub = sectsym.Sub
 		sectsym.Sub = s
-		s.Type = sectsym.Type | obj.SSUB
+		s.Type = sectsym.Type | SSUB
 		s.Value = int64(pesym.Value)
 		s.Size = 4
 		s.Outer = sectsym
-		if sectsym.Type == obj.STEXT {
+		if sectsym.Type == STEXT {
 			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Errorf(s, "%s: duplicate symbol definition", pn)
 			}
@@ -366,7 +368,7 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
 		if s.Sub != nil {
 			s.Sub = listsort(s.Sub)
 		}
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			if s.Attr.OnList() {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -432,7 +434,7 @@ func readpesym(ctxt *Link, f *pe.File, sym *pe.COFFSymbol, sectsyms map[*pe.Sect
 	}
 
 	if s != nil && s.Type == 0 && (sym.StorageClass != IMAGE_SYM_CLASS_STATIC || sym.Value != 0) {
-		s.Type = obj.SXREF
+		s.Type = SXREF
 	}
 	if strings.HasPrefix(symname, "__imp_") {
 		s.Got = -2 // flag for __imp_
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index b624aa0..6252871 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -34,7 +34,7 @@ import (
 	"bufio"
 	"bytes"
 	"cmd/internal/bio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"crypto/sha1"
 	"debug/elf"
@@ -141,12 +141,12 @@ const (
 )
 
 type Segment struct {
-	Rwx     uint8  // permission as usual unix bits (5 = r-x etc)
-	Vaddr   uint64 // virtual address
-	Length  uint64 // length in memory
-	Fileoff uint64 // file offset
-	Filelen uint64 // length on disk
-	Sect    *Section
+	Rwx      uint8  // permission as usual unix bits (5 = r-x etc)
+	Vaddr    uint64 // virtual address
+	Length   uint64 // length in memory
+	Fileoff  uint64 // file offset
+	Filelen  uint64 // length on disk
+	Sections []*Section
 }
 
 type Section struct {
@@ -156,7 +156,6 @@ type Section struct {
 	Name    string
 	Vaddr   uint64
 	Length  uint64
-	Next    *Section
 	Seg     *Segment
 	Elfsect *ElfShdr
 	Reloff  uint64
@@ -197,7 +196,7 @@ var (
 
 	debug_s  bool // backup old value of debug['s']
 	HEADR    int32
-	Headtype obj.HeadType
+	Headtype objabi.HeadType
 
 	nerrors  int
 	liveness int64
@@ -287,7 +286,7 @@ func libinit(ctxt *Link) {
 		suffix = "msan"
 	}
 
-	Lflag(ctxt, filepath.Join(obj.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", obj.GOOS, obj.GOARCH, suffixsep, suffix)))
+	Lflag(ctxt, filepath.Join(objabi.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", objabi.GOOS, objabi.GOARCH, suffixsep, suffix)))
 
 	mayberemoveoutfile()
 	f, err := os.OpenFile(*flagOutfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
@@ -301,9 +300,9 @@ func libinit(ctxt *Link) {
 	if *flagEntrySymbol == "" {
 		switch Buildmode {
 		case BuildmodeCShared, BuildmodeCArchive:
-			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", obj.GOARCH, obj.GOOS)
+			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", objabi.GOARCH, objabi.GOOS)
 		case BuildmodeExe, BuildmodePIE:
-			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", obj.GOARCH, obj.GOOS)
+			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", objabi.GOARCH, objabi.GOOS)
 		case BuildmodeShared, BuildmodePlugin:
 			// No *flagEntrySymbol for -buildmode=shared and plugin
 		default:
@@ -334,6 +333,19 @@ func errorexit() {
 }
 
 func loadinternal(ctxt *Link, name string) *Library {
+	if *FlagLinkshared && ctxt.PackageShlib != nil {
+		if shlibname := ctxt.PackageShlib[name]; shlibname != "" {
+			return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
+		}
+	}
+	if ctxt.PackageFile != nil {
+		if pname := ctxt.PackageFile[name]; pname != "" {
+			return addlibpath(ctxt, "internal", "internal", pname, name, "")
+		}
+		ctxt.Logf("loadinternal: cannot find %s\n", name)
+		return nil
+	}
+
 	for i := 0; i < len(ctxt.Libdir); i++ {
 		if *FlagLinkshared {
 			shlibname := filepath.Join(ctxt.Libdir[i], name+".shlibname")
@@ -412,7 +424,7 @@ func (ctxt *Link) loadlib() {
 		iscgo = iscgo || ctxt.Library[i].Pkg == "runtime/cgo"
 		if ctxt.Library[i].Shlib == "" {
 			if ctxt.Debugvlog > 1 {
-				ctxt.Logf("%5.2f autolib: %s (from %s)\n", obj.Cputime(), ctxt.Library[i].File, ctxt.Library[i].Objref)
+				ctxt.Logf("%5.2f autolib: %s (from %s)\n", Cputime(), ctxt.Library[i].File, ctxt.Library[i].Objref)
 			}
 			objfile(ctxt, ctxt.Library[i])
 		}
@@ -421,7 +433,7 @@ func (ctxt *Link) loadlib() {
 	for i = 0; i < len(ctxt.Library); i++ {
 		if ctxt.Library[i].Shlib != "" {
 			if ctxt.Debugvlog > 1 {
-				ctxt.Logf("%5.2f autolib: %s (from %s)\n", obj.Cputime(), ctxt.Library[i].Shlib, ctxt.Library[i].Objref)
+				ctxt.Logf("%5.2f autolib: %s (from %s)\n", Cputime(), ctxt.Library[i].Shlib, ctxt.Library[i].Objref)
 			}
 			ldshlibsyms(ctxt, ctxt.Library[i].Shlib)
 		}
@@ -430,13 +442,18 @@ func (ctxt *Link) loadlib() {
 	// We now have enough information to determine the link mode.
 	determineLinkMode(ctxt)
 
-	if Headtype == obj.Hdarwin && Linkmode == LinkExternal {
+	// Recalculate pe parameters now that we have Linkmode set.
+	if Headtype == objabi.Hwindows {
+		Peinit(ctxt)
+	}
+
+	if Headtype == objabi.Hdarwin && Linkmode == LinkExternal {
 		*FlagTextAddr = 0
 	}
 
 	if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
 		toc := ctxt.Syms.Lookup(".TOC.", 0)
-		toc.Type = obj.SDYNIMPORT
+		toc.Type = SDYNIMPORT
 	}
 
 	if Linkmode == LinkExternal && !iscgo {
@@ -462,13 +479,13 @@ func (ctxt *Link) loadlib() {
 		// Drop all the cgo_import_static declarations.
 		// Turns out we won't be needing them.
 		for _, s := range ctxt.Syms.Allsym {
-			if s.Type == obj.SHOSTOBJ {
+			if s.Type == SHOSTOBJ {
 				// If a symbol was marked both
 				// cgo_import_static and cgo_import_dynamic,
 				// then we want to make it cgo_import_dynamic
 				// now.
 				if s.Extname != "" && s.Dynimplib != "" && !s.Attr.CgoExport() {
-					s.Type = obj.SDYNIMPORT
+					s.Type = SDYNIMPORT
 				} else {
 					s.Type = 0
 				}
@@ -481,9 +498,9 @@ func (ctxt *Link) loadlib() {
 	// runtime.tlsg is used for external linking on platforms that do not define
 	// a variable to hold g in assembly (currently only intel).
 	if tlsg.Type == 0 {
-		tlsg.Type = obj.STLSBSS
+		tlsg.Type = STLSBSS
 		tlsg.Size = int64(SysArch.PtrSize)
-	} else if tlsg.Type != obj.SDYNIMPORT {
+	} else if tlsg.Type != SDYNIMPORT {
 		Errorf(nil, "runtime declared tlsg variable %v", tlsg.Type)
 	}
 	tlsg.Attr |= AttrReachable
@@ -496,7 +513,7 @@ func (ctxt *Link) loadlib() {
 	} else {
 		moduledata = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
 	}
-	if moduledata.Type != 0 && moduledata.Type != obj.SDYNIMPORT {
+	if moduledata.Type != 0 && moduledata.Type != SDYNIMPORT {
 		// If the module (toolchain-speak for "executable or shared
 		// library") we are linking contains the runtime package, it
 		// will define the runtime.firstmoduledata symbol and we
@@ -508,14 +525,14 @@ func (ctxt *Link) loadlib() {
 		// recording the value of GOARM.
 		if SysArch.Family == sys.ARM {
 			s := ctxt.Syms.Lookup("runtime.goarm", 0)
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 			s.Size = 0
-			Adduint8(ctxt, s, uint8(obj.GOARM))
+			Adduint8(ctxt, s, uint8(objabi.GOARM))
 		}
 
-		if obj.Framepointer_enabled(obj.GOOS, obj.GOARCH) {
+		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
 			s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 			s.Size = 0
 			Adduint8(ctxt, s, 1)
 		}
@@ -527,7 +544,7 @@ func (ctxt *Link) loadlib() {
 	}
 	// In all cases way we mark the moduledata as noptrdata to hide it from
 	// the GC.
-	moduledata.Type = obj.SNOPTRDATA
+	moduledata.Type = SNOPTRDATA
 	moduledata.Attr |= AttrReachable
 	ctxt.Moduledata = moduledata
 
@@ -555,7 +572,7 @@ func (ctxt *Link) loadlib() {
 		any := false
 		for _, s := range ctxt.Syms.Allsym {
 			for _, r := range s.R {
-				if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF && r.Sym.Name != ".got" {
+				if r.Sym != nil && r.Sym.Type&SMASK == SXREF && r.Sym.Name != ".got" {
 					any = true
 					break
 				}
@@ -568,7 +585,7 @@ func (ctxt *Link) loadlib() {
 			if *flagLibGCC != "none" {
 				hostArchive(ctxt, *flagLibGCC)
 			}
-			if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+			if Headtype == objabi.Hwindows {
 				if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
 					hostArchive(ctxt, p)
 				}
@@ -603,7 +620,7 @@ func (ctxt *Link) loadlib() {
 	// Also leave it enabled on Solaris which doesn't support
 	// statically linked binaries.
 	if Buildmode == BuildmodeExe {
-		if havedynamic == 0 && Headtype != obj.Hdarwin && Headtype != obj.Hsolaris {
+		if havedynamic == 0 && Headtype != objabi.Hdarwin && Headtype != objabi.Hsolaris {
 			*FlagD = true
 		}
 	}
@@ -621,7 +638,7 @@ func (ctxt *Link) loadlib() {
 	if SysArch == sys.Arch386 {
 		if (Buildmode == BuildmodeCArchive && Iself) || Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE || ctxt.DynlinkingGo() {
 			got := ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
-			got.Type = obj.SDYNIMPORT
+			got.Type = SDYNIMPORT
 			got.Attr |= AttrReachable
 		}
 	}
@@ -642,6 +659,12 @@ func (ctxt *Link) loadlib() {
 				if !s.Attr.OnList() {
 					ctxt.Textp = append(ctxt.Textp, s)
 					s.Attr |= AttrOnList
+					// dupok symbols may be defined in multiple packages. its
+					// associated package is chosen sort of arbitrarily (the
+					// first containing package that the linker loads). canonicalize
+					// it here to the package with which it will be laid down
+					// in text.
+					s.File = objabi.PathToPrefix(lib.Pkg)
 				}
 			}
 		}
@@ -653,7 +676,7 @@ func (ctxt *Link) loadlib() {
 		// pcln table entries for these any more so remove them from Textp.
 		textp := make([]*Symbol, 0, len(ctxt.Textp))
 		for _, s := range ctxt.Textp {
-			if s.Type != obj.SDYNIMPORT {
+			if s.Type != SDYNIMPORT {
 				textp = append(textp, s)
 			}
 		}
@@ -709,18 +732,43 @@ func genhash(ctxt *Link, lib *Library) {
 	}
 
 	h := sha1.New()
-	if _, err := io.CopyN(h, f, atolwhex(arhdr.size)); err != nil {
-		Errorf(nil, "bad read of %s for hash generation: %v", lib.File, err)
+
+	// To compute the hash of a package, we hash the first line of
+	// __.PKGDEF (which contains the toolchain version and any
+	// GOEXPERIMENT flags) and the export data (which is between
+	// the first two occurences of "\n$$").
+
+	pkgDefBytes := make([]byte, atolwhex(arhdr.size))
+	_, err = io.ReadFull(f, pkgDefBytes)
+	if err != nil {
+		Errorf(nil, "%s: error reading package data: %v", lib.File, err)
 		return
 	}
+	firstEOL := bytes.Index(pkgDefBytes, []byte("\n"))
+	if firstEOL < 0 {
+		Errorf(nil, "cannot parse package data of %s for hash generation, no newline found", lib.File)
+		return
+	}
+	firstDoubleDollar := bytes.Index(pkgDefBytes, []byte("\n$$"))
+	if firstDoubleDollar < 0 {
+		Errorf(nil, "cannot parse package data of %s for hash generation, no \\n$$ found", lib.File)
+		return
+	}
+	secondDoubleDollar := bytes.Index(pkgDefBytes[firstDoubleDollar+1:], []byte("\n$$"))
+	if secondDoubleDollar < 0 {
+		Errorf(nil, "cannot parse package data of %s for hash generation, only one \\n$$ found", lib.File)
+		return
+	}
+	h.Write(pkgDefBytes[0:firstEOL])
+	h.Write(pkgDefBytes[firstDoubleDollar : firstDoubleDollar+secondDoubleDollar])
 	lib.hash = hex.EncodeToString(h.Sum(nil))
 }
 
 func objfile(ctxt *Link, lib *Library) {
-	pkg := pathtoprefix(lib.Pkg)
+	pkg := objabi.PathToPrefix(lib.Pkg)
 
 	if ctxt.Debugvlog > 1 {
-		ctxt.Logf("%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
+		ctxt.Logf("%5.2f ldobj: %s (%s)\n", Cputime(), lib.File, pkg)
 	}
 	f, err := bio.Open(lib.File)
 	if err != nil {
@@ -831,7 +879,7 @@ func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), f *bio.Reader
 	// force external linking for any libraries that link in code that
 	// uses errno. This can be removed if the Go linker ever supports
 	// these relocation types.
-	if Headtype == obj.Hdragonfly {
+	if Headtype == objabi.Hdragonfly {
 		if pkg == "net" || pkg == "os/user" {
 			isinternal = false
 		}
@@ -951,6 +999,29 @@ func hostobjCopy() (paths []string) {
 	return paths
 }
 
+// writeGDBLinkerScript creates gcc linker script file in temp
+// directory. writeGDBLinkerScript returns created file path.
+// The script is used to work around gcc bug
+// (see https://golang.org/issue/20183 for details).
+func writeGDBLinkerScript() string {
+	name := "fix_debug_gdb_scripts.ld"
+	path := filepath.Join(*flagTmpdir, name)
+	src := `SECTIONS
+{
+  .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
+  {
+    *(.debug_gdb_scripts)
+  }
+}
+INSERT AFTER .debug_types;
+`
+	err := ioutil.WriteFile(path, []byte(src), 0666)
+	if err != nil {
+		Errorf(nil, "WriteFile %s failed: %v", name, err)
+	}
+	return path
+}
+
 // archive builds a .a archive from the hostobj object files.
 func (ctxt *Link) archive() {
 	if Buildmode != BuildmodeCArchive {
@@ -1002,7 +1073,7 @@ func (l *Link) hostlink() {
 
 	if !*FlagS && !debug_s {
 		argv = append(argv, "-gdwarf-2")
-	} else if Headtype == obj.Hdarwin {
+	} else if Headtype == objabi.Hdarwin {
 		// Recent versions of macOS print
 		//	ld: warning: option -s is obsolete and being ignored
 		// so do not pass any arguments.
@@ -1011,24 +1082,26 @@ func (l *Link) hostlink() {
 	}
 
 	switch Headtype {
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		argv = append(argv, "-Wl,-headerpad,1144")
 		if l.DynlinkingGo() {
 			argv = append(argv, "-Wl,-flat_namespace")
-		} else {
+		} else if !SysArch.InFamily(sys.ARM64) {
 			argv = append(argv, "-Wl,-no_pie")
 		}
-	case obj.Hopenbsd:
+	case objabi.Hopenbsd:
 		argv = append(argv, "-Wl,-nopie")
-	case obj.Hwindows:
-		argv = append(argv, "-mconsole")
-	case obj.Hwindowsgui:
-		argv = append(argv, "-mwindows")
+	case objabi.Hwindows:
+		if windowsgui {
+			argv = append(argv, "-mwindows")
+		} else {
+			argv = append(argv, "-mconsole")
+		}
 	}
 
 	switch Buildmode {
 	case BuildmodeExe:
-		if Headtype == obj.Hdarwin {
+		if Headtype == objabi.Hdarwin {
 			argv = append(argv, "-Wl,-pagezero_size,4000000")
 		}
 	case BuildmodePIE:
@@ -1037,8 +1110,11 @@ func (l *Link) hostlink() {
 		}
 		argv = append(argv, "-pie")
 	case BuildmodeCShared:
-		if Headtype == obj.Hdarwin {
-			argv = append(argv, "-dynamiclib", "-Wl,-read_only_relocs,suppress")
+		if Headtype == objabi.Hdarwin {
+			argv = append(argv, "-dynamiclib")
+			if SysArch.Family != sys.AMD64 {
+				argv = append(argv, "-Wl,-read_only_relocs,suppress")
+			}
 		} else {
 			// ELF.
 			argv = append(argv, "-Wl,-Bsymbolic")
@@ -1055,7 +1131,7 @@ func (l *Link) hostlink() {
 		}
 		argv = append(argv, "-shared")
 	case BuildmodePlugin:
-		if Headtype == obj.Hdarwin {
+		if Headtype == objabi.Hdarwin {
 			argv = append(argv, "-dynamiclib")
 		} else {
 			if UseRelro() {
@@ -1110,7 +1186,7 @@ func (l *Link) hostlink() {
 	// only want to do this when producing a Windows output file
 	// on a Windows host.
 	outopt := *flagOutfile
-	if obj.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
+	if objabi.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
 		outopt += "."
 	}
 	argv = append(argv, "-o")
@@ -1206,7 +1282,11 @@ func (l *Link) hostlink() {
 			}
 		}
 	}
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+	if Headtype == objabi.Hwindows {
+		// use gcc linker script to work around gcc bug
+		// (see https://golang.org/issue/20183 for details).
+		p := writeGDBLinkerScript()
+		argv = append(argv, "-Wl,-T,"+p)
 		// libmingw32 and libmingwex have some inter-dependencies,
 		// so must use linker groups.
 		argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
@@ -1214,7 +1294,7 @@ func (l *Link) hostlink() {
 	}
 
 	if l.Debugvlog != 0 {
-		l.Logf("%5.2f host link:", obj.Cputime())
+		l.Logf("%5.2f host link:", Cputime())
 		for _, v := range argv {
 			l.Logf(" %q", v)
 		}
@@ -1223,11 +1303,13 @@ func (l *Link) hostlink() {
 
 	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 l.Debugvlog != 0 && len(out) > 0 {
+	} else if len(out) > 0 {
+		// always print external output even if the command is successful, so that we don't
+		// swallow linker warnings (see https://golang.org/issue/17935).
 		l.Logf("%s", out)
 	}
 
-	if !*FlagS && !*FlagW && !debug_s && Headtype == obj.Hdarwin {
+	if !*FlagS && !*FlagW && !debug_s && Headtype == objabi.Hdarwin {
 		// Skip combining dwarf on arm.
 		if !SysArch.InFamily(sys.ARM, sys.ARM64) {
 			dsym := filepath.Join(*flagTmpdir, "go.dwarf")
@@ -1275,7 +1357,7 @@ func hostlinkArchArgs() []string {
 // compiled by a non-Go compiler) it returns the Hostobj pointer. If
 // it is a Go object, it returns nil.
 func ldobj(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string, file string, whence int) *Hostobj {
-	pkg := pathtoprefix(lib.Pkg)
+	pkg := objabi.PathToPrefix(lib.Pkg)
 
 	eof := f.Offset() + length
 	start := f.Offset()
@@ -1322,7 +1404,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string, fil
 	}
 
 	// First, check that the basic GOOS, GOARCH, and Version match.
-	t := fmt.Sprintf("%s %s %s ", obj.GOOS, obj.GOARCH, obj.Version)
+	t := fmt.Sprintf("%s %s %s ", objabi.GOOS, objabi.GOARCH, objabi.Version)
 
 	line = strings.TrimRight(line, "\n")
 	if !strings.HasPrefix(line[10:]+" ", t) && !*flagF {
@@ -1452,7 +1534,7 @@ func ldshlibsyms(ctxt *Link, shlib string) {
 		}
 	}
 	if ctxt.Debugvlog > 1 {
-		ctxt.Logf("%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
+		ctxt.Logf("%5.2f ldshlibsyms: found library with name %s at %s\n", Cputime(), shlib, libpath)
 	}
 
 	f, err := elf.Open(libpath)
@@ -1489,10 +1571,10 @@ func ldshlibsyms(ctxt *Link, shlib string) {
 		// 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 {
+		if lsym.Type != 0 && lsym.Type != SDYNIMPORT {
 			continue
 		}
-		lsym.Type = obj.SDYNIMPORT
+		lsym.Type = SDYNIMPORT
 		lsym.ElfType = elf.ST_TYPE(elfsym.Info)
 		lsym.Size = int64(elfsym.Size)
 		if elfsym.Section != elf.SHN_UNDEF {
@@ -1535,46 +1617,13 @@ func ldshlibsyms(ctxt *Link, shlib string) {
 	ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses})
 }
 
-// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
-/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx.	 Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
- *
- * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
- * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
- */
-func pathtoprefix(s string) string {
-	slash := strings.LastIndex(s, "/")
-	for i := 0; i < len(s); i++ {
-		c := s[i]
-		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			var buf bytes.Buffer
-			for i := 0; i < len(s); i++ {
-				c := s[i]
-				if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-					fmt.Fprintf(&buf, "%%%02x", c)
-					continue
-				}
-				buf.WriteByte(c)
-			}
-			return buf.String()
-		}
-	}
-	return s
-}
-
 func addsection(seg *Segment, name string, rwx int) *Section {
-	var l **Section
-
-	for l = &seg.Sect; *l != nil; l = &(*l).Next {
-	}
 	sect := new(Section)
 	sect.Rwx = uint8(rwx)
 	sect.Name = name
 	sect.Seg = seg
 	sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned
-	*l = sect
+	seg.Sections = append(seg.Sections, sect)
 	return sect
 }
 
@@ -1634,7 +1683,7 @@ func (ctxt *Link) dostkcheck() {
 	// of non-splitting functions.
 	ch.up = nil
 
-	ch.limit = obj.StackLimit - callsize(ctxt)
+	ch.limit = objabi.StackLimit - callsize(ctxt)
 
 	// Check every function, but do the nosplit functions in a first pass,
 	// to make the printed failure chains as short as possible.
@@ -1666,7 +1715,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
 
 	// Don't duplicate work: only need to consider each
 	// function at top of safe zone once.
-	top := limit == obj.StackLimit-callsize(ctxt)
+	top := limit == objabi.StackLimit-callsize(ctxt)
 	if top {
 		if s.Attr.StackCheck() {
 			return 0
@@ -1685,7 +1734,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
 		// should never be called directly.
 		// onlyctxt.Diagnose the direct caller.
 		// TODO(mwhudson): actually think about this.
-		if depth == 1 && s.Type != obj.SXREF && !ctxt.DynlinkingGo() &&
+		if depth == 1 && s.Type != SXREF && !ctxt.DynlinkingGo() &&
 			Buildmode != BuildmodeCArchive && Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared && Buildmode != BuildmodePlugin {
 
 			Errorf(s, "call to external function")
@@ -1722,7 +1771,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
 		if s.FuncInfo != nil {
 			locals = s.FuncInfo.Locals
 		}
-		limit = int(obj.StackLimit+locals) + int(ctxt.FixedFrameSize())
+		limit = int(objabi.StackLimit+locals) + int(ctxt.FixedFrameSize())
 	}
 
 	// Walk through sp adjustments in function, consuming relocs.
@@ -1746,7 +1795,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
 			r = &s.R[ri]
 			switch r.Type {
 			// Direct call.
-			case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER, obj.R_CALLMIPS:
+			case objabi.R_CALL, objabi.R_CALLARM, objabi.R_CALLARM64, objabi.R_CALLPOWER, objabi.R_CALLMIPS:
 				ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
 				ch.sym = r.Sym
 				if stkcheck(ctxt, &ch, depth+1) < 0 {
@@ -1757,7 +1806,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
 			// so we have to make sure it can call morestack.
 			// Arrange the data structures to report both calls, so that
 			// if there is an error, stkprint shows all the steps involved.
-			case obj.R_CALLIND:
+			case objabi.R_CALLIND:
 				ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
 
 				ch.sym = nil
@@ -1842,12 +1891,12 @@ func Cput(c uint8) {
 
 func usage() {
 	fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
-	obj.Flagprint(2)
+	objabi.Flagprint(2)
 	Exit(2)
 }
 
 func doversion() {
-	Exitf("version %s", obj.Version)
+	Exitf("version %s", objabi.Version)
 }
 
 type SymbolType int8
@@ -1868,14 +1917,14 @@ func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *
 	// 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 := ctxt.Syms.Lookup("runtime.text", 0)
-	if s.Type == obj.STEXT {
+	if s.Type == STEXT {
 		put(ctxt, s, s.Name, TextSym, s.Value, nil)
 	}
 
 	n := 0
 
 	// Generate base addresses for all text sections if there are multiple
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		if n == 0 {
 			n++
 			continue
@@ -1887,78 +1936,78 @@ func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *
 		if s == nil {
 			break
 		}
-		if s.Type == obj.STEXT {
+		if s.Type == STEXT {
 			put(ctxt, s, s.Name, TextSym, s.Value, nil)
 		}
 		n++
 	}
 
 	s = ctxt.Syms.Lookup("runtime.etext", 0)
-	if s.Type == obj.STEXT {
+	if s.Type == STEXT {
 		put(ctxt, s, s.Name, TextSym, s.Value, nil)
 	}
 
 	for _, s := range ctxt.Syms.Allsym {
-		if s.Attr.Hidden() {
+		if s.Attr.NotInSymbolTable() {
 			continue
 		}
 		if (s.Name == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC." {
 			continue
 		}
-		switch s.Type & obj.SMASK {
-		case obj.SCONST,
-			obj.SRODATA,
-			obj.SSYMTAB,
-			obj.SPCLNTAB,
-			obj.SINITARR,
-			obj.SDATA,
-			obj.SNOPTRDATA,
-			obj.SELFROSECT,
-			obj.SMACHOGOT,
-			obj.STYPE,
-			obj.SSTRING,
-			obj.SGOSTRING,
-			obj.SGOFUNC,
-			obj.SGCBITS,
-			obj.STYPERELRO,
-			obj.SSTRINGRELRO,
-			obj.SGOSTRINGRELRO,
-			obj.SGOFUNCRELRO,
-			obj.SGCBITSRELRO,
-			obj.SRODATARELRO,
-			obj.STYPELINK,
-			obj.SITABLINK,
-			obj.SWINDOWS:
+		switch s.Type & SMASK {
+		case SCONST,
+			SRODATA,
+			SSYMTAB,
+			SPCLNTAB,
+			SINITARR,
+			SDATA,
+			SNOPTRDATA,
+			SELFROSECT,
+			SMACHOGOT,
+			STYPE,
+			SSTRING,
+			SGOSTRING,
+			SGOFUNC,
+			SGCBITS,
+			STYPERELRO,
+			SSTRINGRELRO,
+			SGOSTRINGRELRO,
+			SGOFUNCRELRO,
+			SGCBITSRELRO,
+			SRODATARELRO,
+			STYPELINK,
+			SITABLINK,
+			SWINDOWS:
 			if !s.Attr.Reachable() {
 				continue
 			}
 			put(ctxt, s, s.Name, DataSym, Symaddr(s), s.Gotype)
 
-		case obj.SBSS, obj.SNOPTRBSS:
+		case SBSS, SNOPTRBSS:
 			if !s.Attr.Reachable() {
 				continue
 			}
 			if len(s.P) > 0 {
-				Errorf(s, "should not be bss (size=%d type=%d special=%v)", len(s.P), s.Type, s.Attr.Special())
+				Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(s.P), s.Type, s.Attr.Special())
 			}
 			put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
 
-		case obj.SFILE:
+		case SFILE:
 			put(ctxt, nil, s.Name, FileSym, s.Value, nil)
 
-		case obj.SHOSTOBJ:
-			if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui || Iself {
+		case SHOSTOBJ:
+			if Headtype == objabi.Hwindows || Iself {
 				put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
 			}
 
-		case obj.SDYNIMPORT:
+		case SDYNIMPORT:
 			if !s.Attr.Reachable() {
 				continue
 			}
 			put(ctxt, s, s.Extname, UndefinedSym, 0, nil)
 
-		case obj.STLSBSS:
-			if Linkmode == LinkExternal && Headtype != obj.Hopenbsd {
+		case STLSBSS:
+			if Linkmode == LinkExternal {
 				put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
 			}
 		}
@@ -1981,12 +2030,12 @@ func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *
 		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 {
+			if a.Name != objabi.A_AUTO && a.Name != objabi.A_PARAM {
 				continue
 			}
 
 			// compute offset relative to FP
-			if a.Name == obj.A_PARAM {
+			if a.Name == objabi.A_PARAM {
 				off = a.Aoffset
 			} else {
 				off = a.Aoffset - int32(SysArch.PtrSize)
@@ -2009,7 +2058,7 @@ func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *
 	}
 
 	if ctxt.Debugvlog != 0 || *flagN {
-		ctxt.Logf("%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
+		ctxt.Logf("%5.2f symsize = %d\n", Cputime(), uint32(Symsize))
 	}
 }
 
@@ -2020,7 +2069,7 @@ func Symaddr(s *Symbol) int64 {
 	return s.Value
 }
 
-func (ctxt *Link) xdefine(p string, t obj.SymKind, v int64) {
+func (ctxt *Link) xdefine(p string, t SymKind, v int64) {
 	s := ctxt.Syms.Lookup(p, 0)
 	s.Type = t
 	s.Value = v
@@ -2049,7 +2098,7 @@ func Entryvalue(ctxt *Link) int64 {
 	if s.Type == 0 {
 		return *FlagTextAddr
 	}
-	if s.Type != obj.STEXT {
+	if s.Type != STEXT {
 		Errorf(s, "entry not text")
 	}
 	return s.Value
@@ -2063,10 +2112,10 @@ func undefsym(ctxt *Link, s *Symbol) {
 		if r.Sym == nil { // happens for some external ARM relocs
 			continue
 		}
-		if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
+		if r.Sym.Type == Sxxx || r.Sym.Type == SXREF {
 			Errorf(s, "undefined: %q", r.Sym.Name)
 		}
-		if !r.Sym.Attr.Reachable() && r.Type != obj.R_WEAKADDROFF {
+		if !r.Sym.Attr.Reachable() && r.Type != objabi.R_WEAKADDROFF {
 			Errorf(s, "relocation target %q", r.Sym.Name)
 		}
 	}
@@ -2097,7 +2146,7 @@ func (ctxt *Link) callgraph() {
 			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 {
+			if (r.Type == objabi.R_CALL || r.Type == objabi.R_CALLARM || r.Type == objabi.R_CALLPOWER || r.Type == objabi.R_CALLMIPS) && r.Sym.Type == STEXT {
 				ctxt.Logf("%s calls %s\n", s.Name, r.Sym.Name)
 			}
 		}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index ffe0873..302364c 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -32,7 +32,7 @@ package ld
 
 import (
 	"bufio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"debug/elf"
 	"fmt"
@@ -42,7 +42,7 @@ import (
 type Symbol struct {
 	Name        string
 	Extname     string
-	Type        obj.SymKind
+	Type        SymKind
 	Version     int16
 	Attr        Attribute
 	Localentry  uint8
@@ -89,23 +89,59 @@ func (s *Symbol) ElfsymForReloc() int32 {
 	}
 }
 
+func (s *Symbol) Len() int64 {
+	return s.Size
+}
+
 // Attribute is a set of common symbol attributes.
 type Attribute int16
 
 const (
+	// AttrDuplicateOK marks a symbol that can be present in multiple object
+	// files.
 	AttrDuplicateOK Attribute = 1 << iota
+	// AttrExternal marks function symbols loaded from host object files.
 	AttrExternal
+	// AttrNoSplit marks functions that cannot split the stack; the linker
+	// cares because it checks that there are no call chains of nosplit
+	// functions that require more than StackLimit bytes (see
+	// lib.go:dostkcheck)
 	AttrNoSplit
+	// AttrReachable marks symbols that are transitively referenced from the
+	// entry points. Unreachable symbols are not written to the output.
 	AttrReachable
+	// AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced
+	// by directives written by cgo (in response to //export directives in
+	// the source).
 	AttrCgoExportDynamic
 	AttrCgoExportStatic
+	// AttrSpecial marks symbols that do not have their address (i.e. Value)
+	// computed by the usual mechanism of data.go:dodata() &
+	// data.go:address().
 	AttrSpecial
+	// AttrStackCheck is used by dostkcheck to only check each NoSplit
+	// function's stack usage once.
 	AttrStackCheck
-	AttrHidden
+	// AttrNotInSymbolTable marks symbols that are not written to the symbol table.
+	AttrNotInSymbolTable
+	// AttrOnList marks symbols that are on some list (such as the list of
+	// all text symbols, or one of the lists of data symbols) and is
+	// consulted to avoid bugs where a symbol is put on a list twice.
 	AttrOnList
+	// AttrLocal marks symbols that are only visible within the module
+	// (exectuable or shared library) being linked. Only relevant when
+	// dynamically linking Go code.
 	AttrLocal
+	// AttrReflectMethod marks certain methods from the reflect package that
+	// can be used to call arbitrary methods. If no symbol with this bit set
+	// is marked as reachable, more dead code elimination can be done.
 	AttrReflectMethod
+	// AttrMakeTypelink Amarks types that should be added to the typelink
+	// table. See typelinks.go:typelinks().
 	AttrMakeTypelink
+	// AttrShared marks symbols compiled with the -shared option.
+	AttrShared
+	// 14 attributes defined so far.
 )
 
 func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
@@ -116,11 +152,12 @@ 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) NotInSymbolTable() bool { return a&AttrNotInSymbolTable != 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) MakeTypelink() bool     { return a&AttrMakeTypelink != 0 }
+func (a Attribute) Shared() bool           { return a&AttrShared != 0 }
 
 func (a Attribute) CgoExport() bool {
 	return a.CgoExportDynamic() || a.CgoExportStatic()
@@ -146,15 +183,15 @@ func (a *Attribute) Set(flag Attribute, value bool) {
 //
 // Some relocations are created by cmd/link.
 type Reloc struct {
-	Off     int32         // offset to rewrite
-	Siz     uint8         // number of bytes to rewrite, 1, 2, or 4
-	Done    uint8         // set to 1 when relocation is complete
-	Variant RelocVariant  // variation on Type
-	Type    obj.RelocType // the relocation type
-	Add     int64         // addend
-	Xadd    int64         // addend passed to external linker
-	Sym     *Symbol       // symbol the relocation addresses
-	Xsym    *Symbol       // symbol passed to external linker
+	Off     int32            // offset to rewrite
+	Siz     uint8            // number of bytes to rewrite, 1, 2, or 4
+	Done    uint8            // set to 1 when relocation is complete
+	Variant RelocVariant     // variation on Type
+	Type    objabi.RelocType // the relocation type
+	Add     int64            // addend
+	Xadd    int64            // addend passed to external linker
+	Sym     *Symbol          // symbol the relocation addresses
+	Xsym    *Symbol          // symbol passed to external linker
 }
 
 type Auto struct {
@@ -183,14 +220,18 @@ type Link struct {
 
 	Loaded bool // set after all inputs have been loaded as symbols
 
-	Tlsg       *Symbol
-	Libdir     []string
-	Library    []*Library
-	Shlibs     []Shlib
-	Tlsoffset  int
-	Textp      []*Symbol
-	Filesyms   []*Symbol
-	Moduledata *Symbol
+	Tlsg         *Symbol
+	Libdir       []string
+	Library      []*Library
+	LibraryByPkg map[string]*Library
+	Shlibs       []Shlib
+	Tlsoffset    int
+	Textp        []*Symbol
+	Filesyms     []*Symbol
+	Moduledata   *Symbol
+
+	PackageFile  map[string]string
+	PackageShlib map[string]string
 
 	tramps []*Symbol // trampolines
 }
@@ -240,10 +281,20 @@ type FuncInfo struct {
 	Pcsp        Pcdata
 	Pcfile      Pcdata
 	Pcline      Pcdata
+	Pcinline    Pcdata
 	Pcdata      []Pcdata
 	Funcdata    []*Symbol
 	Funcdataoff []int64
 	File        []*Symbol
+	InlTree     []InlinedCall
+}
+
+// InlinedCall is a node in a local inlining tree (FuncInfo.InlTree).
+type InlinedCall struct {
+	Parent int32   // index of parent in InlTree
+	File   *Symbol // file of the inlined call
+	Line   int32   // line number of the inlined call
+	Func   *Symbol // function that was inlined
 }
 
 type Pcdata struct {
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 1ab61b7..59c81a6 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -5,7 +5,6 @@
 package ld
 
 import (
-	"cmd/internal/obj"
 	"cmd/internal/sys"
 	"sort"
 	"strings"
@@ -302,31 +301,31 @@ func (ctxt *Link) domacho() {
 	// empirically, string table must begin with " \x00".
 	s := ctxt.Syms.Lookup(".machosymstr", 0)
 
-	s.Type = obj.SMACHOSYMSTR
+	s.Type = SMACHOSYMSTR
 	s.Attr |= AttrReachable
 	Adduint8(ctxt, s, ' ')
 	Adduint8(ctxt, s, '\x00')
 
 	s = ctxt.Syms.Lookup(".machosymtab", 0)
-	s.Type = obj.SMACHOSYMTAB
+	s.Type = SMACHOSYMTAB
 	s.Attr |= AttrReachable
 
 	if Linkmode != LinkExternal {
 		s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
-		s.Type = obj.SMACHOPLT
+		s.Type = SMACHOPLT
 		s.Attr |= AttrReachable
 
 		s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
-		s.Type = obj.SMACHOGOT
+		s.Type = SMACHOGOT
 		s.Attr |= AttrReachable
 		s.Align = 4
 
 		s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
-		s.Type = obj.SMACHOINDIRECTPLT
+		s.Type = SMACHOINDIRECTPLT
 		s.Attr |= AttrReachable
 
 		s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
-		s.Type = obj.SMACHOINDIRECTGOT
+		s.Type = SMACHOINDIRECTGOT
 		s.Attr |= AttrReachable
 	}
 }
@@ -472,7 +471,7 @@ func Asmbmacho(ctxt *Link) {
 		ms.prot2 = 5
 	}
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		machoshbits(ctxt, ms, sect, "__TEXT")
 	}
 
@@ -488,7 +487,7 @@ func Asmbmacho(ctxt *Link) {
 		ms.prot2 = 3
 	}
 
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		machoshbits(ctxt, ms, sect, "__DATA")
 	}
 
@@ -501,7 +500,7 @@ func Asmbmacho(ctxt *Link) {
 			ms.fileoffset = Segdwarf.Fileoff
 			ms.filesize = Segdwarf.Filelen
 		}
-		for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		for _, sect := range Segdwarf.Sections {
 			machoshbits(ctxt, ms, sect, "__DWARF")
 		}
 	}
@@ -603,7 +602,7 @@ func Asmbmacho(ctxt *Link) {
 }
 
 func symkind(s *Symbol) int {
-	if s.Type == obj.SDYNIMPORT {
+	if s.Type == SDYNIMPORT {
 		return SymKindUndef
 	}
 	if s.Attr.CgoExport() {
@@ -659,7 +658,7 @@ func (x machoscmp) Less(i, j int) bool {
 func machogenasmsym(ctxt *Link) {
 	genasmsym(ctxt, addsym)
 	for _, s := range ctxt.Syms.Allsym {
-		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
+		if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
 			if s.Attr.Reachable() {
 				addsym(ctxt, s, "", DataSym, 0, nil)
 			}
@@ -704,7 +703,7 @@ func machoShouldExport(ctxt *Link, s *Symbol) bool {
 	if strings.HasPrefix(s.Name, "go.link.pkghash") {
 		return true
 	}
-	return s.Type >= obj.SELFSECT // only writable sections
+	return s.Type >= SELFSECT // only writable sections
 }
 
 func machosymtab(ctxt *Link) {
@@ -732,7 +731,7 @@ func machosymtab(ctxt *Link) {
 		// replace "·" as ".", because DTrace cannot handle it.
 		Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1))
 
-		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
+		if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
 			Adduint8(ctxt, symtab, 0x01)                // type N_EXT, external symbol
 			Adduint8(ctxt, symtab, 0)                   // no section
 			Adduint16(ctxt, symtab, 0)                  // desc
@@ -892,14 +891,14 @@ func Machoemitreloc(ctxt *Link) {
 		Cput(0)
 	}
 
-	machorelocsect(ctxt, Segtext.Sect, ctxt.Textp)
-	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
+	machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp)
+	for _, sect := range Segtext.Sections[1:] {
 		machorelocsect(ctxt, sect, datap)
 	}
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdata.Sections {
 		machorelocsect(ctxt, sect, datap)
 	}
-	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segdwarf.Sections {
 		machorelocsect(ctxt, sect, dwarfp)
 	}
 }
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 2fd92f6..f03460d 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -32,7 +32,7 @@ package ld
 
 import (
 	"bufio"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"flag"
 	"log"
@@ -44,12 +44,12 @@ import (
 
 var (
 	pkglistfornote []byte
+	windowsgui     bool // writes a "GUI binary" instead of a "console binary"
 )
 
 func init() {
 	flag.Var(&Linkmode, "linkmode", "set link `mode`")
 	flag.Var(&Buildmode, "buildmode", "set build `mode`")
-	flag.Var(&Headtype, "H", "set header `type`")
 	flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
 }
 
@@ -88,6 +88,7 @@ var (
 	flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
 	FlagDebugTramp  = flag.Int("debugtramp", 0, "debug trampolines")
 
+	flagHeadtype    = flag.String("H", "", "set header `type`")
 	FlagRound       = flag.Int("R", -1, "set address rounding `quantum`")
 	FlagTextAddr    = flag.Int64("T", -1, "set text segment `address`")
 	FlagDataAddr    = flag.Int64("D", -1, "set data segment `address`")
@@ -113,16 +114,29 @@ func Main() {
 	}
 
 	// TODO(matloob): define these above and then check flag values here
-	if SysArch.Family == sys.AMD64 && obj.GOOS == "plan9" {
+	if SysArch.Family == sys.AMD64 && objabi.GOOS == "plan9" {
 		flag.BoolVar(&Flag8, "8", false, "use 64-bit addresses in symbol table")
 	}
-	obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
-	obj.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
-	obj.Flagfn0("V", "print version and exit", doversion)
-	obj.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
-	obj.Flagcount("v", "print link trace", &ctxt.Debugvlog)
-
-	obj.Flagparse(usage)
+	objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
+	objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
+	objabi.Flagfn0("V", "print version and exit", doversion)
+	objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
+	objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
+	objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)
+
+	objabi.Flagparse(usage)
+
+	switch *flagHeadtype {
+	case "":
+	case "windowsgui":
+		Headtype = objabi.Hwindows
+		windowsgui = true
+	default:
+		if err := Headtype.Set(*flagHeadtype); err != nil {
+			Errorf(nil, "%v", err)
+			usage()
+		}
+	}
 
 	startProfile()
 	if Buildmode == BuildmodeUnset {
@@ -135,7 +149,7 @@ func Main() {
 
 	if *flagOutfile == "" {
 		*flagOutfile = "a.out"
-		if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+		if Headtype == objabi.Hwindows {
 			*flagOutfile += ".exe"
 		}
 	}
@@ -144,8 +158,8 @@ func Main() {
 
 	libinit(ctxt) // creates outfile
 
-	if Headtype == obj.Hunknown {
-		Headtype.Set(obj.GOOS)
+	if Headtype == objabi.Hunknown {
+		Headtype.Set(objabi.GOOS)
 	}
 
 	ctxt.computeTLSOffset()
@@ -187,11 +201,11 @@ func Main() {
 	ctxt.callgraph()
 
 	ctxt.doelf()
-	if Headtype == obj.Hdarwin {
+	if Headtype == objabi.Hdarwin {
 		ctxt.domacho()
 	}
 	ctxt.dostkcheck()
-	if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+	if Headtype == objabi.Hwindows {
 		ctxt.dope()
 	}
 	ctxt.addexport()
@@ -210,7 +224,7 @@ func Main() {
 	ctxt.hostlink()
 	ctxt.archive()
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f cpu time\n", obj.Cputime())
+		ctxt.Logf("%5.2f cpu time\n", Cputime())
 		ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
 		ctxt.Logf("%d liveness data\n", liveness)
 	}
diff --git a/src/cmd/link/internal/ld/nooptcgolink_test.go b/src/cmd/link/internal/ld/nooptcgolink_test.go
new file mode 100644
index 0000000..1df2965
--- /dev/null
+++ b/src/cmd/link/internal/ld/nooptcgolink_test.go
@@ -0,0 +1,32 @@
+// Copyright 2017 The Go Authors. 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 (
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"testing"
+)
+
+func TestNooptCgoBuild(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	testenv.MustHaveCGO(t)
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	cmd := exec.Command("go", "build", "-gcflags=-N -l", "-o", filepath.Join(dir, "a.out"))
+	cmd.Dir = filepath.Join(runtime.GOROOT(), "src", "runtime", "testdata", "testprogcgo")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Logf("go build output: %s", out)
+		t.Fatal(err)
+	}
+}
diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
index 7626a4f..13dde21 100644
--- a/src/cmd/link/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -5,116 +5,13 @@
 package ld
 
 // Reading of Go object files.
-//
-// Originally, Go object files were Plan 9 object files, but no longer.
-// Now they are more like standard object files, in that each symbol is defined
-// by an associated memory image (bytes) and a list of relocations to apply
-// during linking. We do not (yet?) use a standard file format, however.
-// For now, the format is chosen to be as simple as possible to read and write.
-// It may change for reasons of efficiency, or we may even switch to a
-// standard file format if there are compelling benefits to doing so.
-// See golang.org/s/go13linker for more background.
-//
-// The file format is:
-//
-//	- magic header: "\x00\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\xffgo17ld"
-//
-// All integers are stored in a zigzag varint format.
-// See golang.org/s/go12symtab for a definition.
-//
-// Data blocks and strings are both stored as an integer
-// followed by that many bytes.
-//
-// A symbol reference is a string name followed by a version.
-//
-// A symbol points to other symbols using an index into the symbol
-// reference sequence. Index 0 corresponds to a nil Object* pointer.
-// In the symbol layout described below "symref index" stands for this
-// index.
-//
-// Each symbol is laid out as the following fields (taken from Object*):
-//
-//	- byte 0xfe (sanity check for synchronization)
-//	- type [int]
-//	- name & version [symref index]
-//	- flags [int]
-//		1<<0 dupok
-//		1<<1 local
-//		1<<2 add to typelink table
-//	- size [int]
-//	- gotype [symref index]
-//	- p [data block]
-//	- nr [int]
-//	- r [nr relocations, sorted by off]
-//
-// If type == STEXT, there are a few more fields:
-//
-//	- args [int]
-//	- locals [int]
-//	- nosplit [int]
-//	- flags [int]
-//		1<<0 leaf
-//		1<<1 C function
-//		1<<2 function may call reflect.Type.Method
-//	- nlocal [int]
-//	- local [nlocal automatics]
-//	- pcln [pcln table]
-//
-// Each relocation has the encoding:
-//
-//	- off [int]
-//	- siz [int]
-//	- type [int]
-//	- add [int]
-//	- sym [symref index]
-//
-// Each local has the encoding:
-//
-//	- asym [symref index]
-//	- offset [int]
-//	- type [int]
-//	- gotype [symref index]
-//
-// The pcln table has the encoding:
-//
-//	- pcsp [data block]
-//	- pcfile [data block]
-//	- pcline [data block]
-//	- npcdata [int]
-//	- pcdata [npcdata data blocks]
-//	- nfuncdata [int]
-//	- funcdata [nfuncdata symref index]
-//	- funcdatasym [nfuncdata ints]
-//	- nfile [int]
-//	- 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.
 
 import (
 	"bufio"
 	"bytes"
 	"cmd/internal/bio"
 	"cmd/internal/dwarf"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"crypto/sha1"
 	"encoding/base64"
 	"io"
@@ -124,8 +21,8 @@ import (
 )
 
 const (
-	startmagic = "\x00\x00go17ld"
-	endmagic   = "\xff\xffgo17ld"
+	startmagic = "\x00\x00go19ld"
+	endmagic   = "\xff\xffgo19ld"
 )
 
 var emptyPkg = []byte(`"".`)
@@ -171,7 +68,7 @@ func LoadObjFile(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn strin
 }
 
 func (r *objReader) loadObjFile() {
-	pkg := pathtoprefix(r.lib.Pkg)
+	pkg := objabi.PathToPrefix(r.lib.Pkg)
 
 	// Magic header
 	var buf [8]uint8
@@ -258,10 +155,15 @@ func (r *objReader) readSlices() {
 const symPrefix = 0xfe
 
 func (r *objReader) readSym() {
-	if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
+	var c byte
+	var err error
+	if c, err = r.rd.ReadByte(); c != symPrefix || err != nil {
 		log.Fatalln("readSym out of sync")
 	}
-	t := obj.SymKind(r.readInt())
+	if c, err = r.rd.ReadByte(); err != nil {
+		log.Fatalln("error reading input: ", err)
+	}
+	t := abiSymKindToSymKind[c]
 	s := r.readSymIndex()
 	flags := r.readInt()
 	dupok := flags&1 != 0
@@ -271,12 +173,12 @@ func (r *objReader) readSym() {
 	typ := r.readSymIndex()
 	data := r.readData()
 	nreloc := r.readInt()
-	pkg := pathtoprefix(r.lib.Pkg)
+	pkg := objabi.PathToPrefix(r.lib.Pkg)
 	isdup := false
 
 	var dup *Symbol
-	if s.Type != 0 && s.Type != obj.SXREF {
-		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
+	if s.Type != 0 && s.Type != SXREF {
+		if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
 			if s.Size < int64(size) {
 				s.Size = int64(size)
 			}
@@ -286,10 +188,10 @@ func (r *objReader) readSym() {
 			return
 		}
 
-		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
+		if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
 			goto overwrite
 		}
-		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
+		if s.Type != SBSS && s.Type != 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 {
@@ -304,13 +206,13 @@ overwrite:
 	if dupok {
 		s.Attr |= AttrDuplicateOK
 	}
-	if t == obj.SXREF {
+	if t == SXREF {
 		log.Fatalf("bad sxref")
 	}
 	if t == 0 {
 		log.Fatalf("missing type for %s in %s", s.Name, r.pn)
 	}
-	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
+	if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
 		t = s.Type
 	}
 	s.Type = t
@@ -336,14 +238,14 @@ overwrite:
 			s.R[i] = Reloc{
 				Off:  r.readInt32(),
 				Siz:  r.readUint8(),
-				Type: obj.RelocType(r.readInt32()),
+				Type: objabi.RelocType(r.readInt32()),
 				Add:  r.readInt64(),
 				Sym:  r.readSymIndex(),
 			}
 		}
 	}
 
-	if s.Type == obj.STEXT {
+	if s.Type == STEXT {
 		s.FuncInfo = new(FuncInfo)
 		pc := s.FuncInfo
 
@@ -356,6 +258,9 @@ overwrite:
 		if flags&(1<<2) != 0 {
 			s.Attr |= AttrReflectMethod
 		}
+		if flags&(1<<3) != 0 {
+			s.Attr |= AttrShared
+		}
 		n := r.readInt()
 		pc.Autom = r.autom[:n:n]
 		if !isdup {
@@ -374,6 +279,7 @@ overwrite:
 		pc.Pcsp.P = r.readData()
 		pc.Pcfile.P = r.readData()
 		pc.Pcline.P = r.readData()
+		pc.Pcinline.P = r.readData()
 		n = r.readInt()
 		pc.Pcdata = r.pcdata[:n:n]
 		if !isdup {
@@ -403,6 +309,14 @@ overwrite:
 		for i := 0; i < n; i++ {
 			pc.File[i] = r.readSymIndex()
 		}
+		n = r.readInt()
+		pc.InlTree = make([]InlinedCall, n)
+		for i := 0; i < n; i++ {
+			pc.InlTree[i].Parent = r.readInt32()
+			pc.InlTree[i].File = r.readSymIndex()
+			pc.InlTree[i].Line = r.readInt32()
+			pc.InlTree[i].Func = r.readSymIndex()
+		}
 
 		if !dupok {
 			if s.Attr.OnList() {
@@ -420,7 +334,7 @@ overwrite:
 			}
 		}
 	}
-	if s.Type == obj.SDWARFINFO {
+	if s.Type == SDWARFINFO {
 		r.patchDWARFName(s)
 	}
 }
@@ -439,7 +353,7 @@ func (r *objReader) patchDWARFName(s *Symbol) {
 	if p == -1 {
 		return
 	}
-	pkgprefix := []byte(pathtoprefix(r.lib.Pkg) + ".")
+	pkgprefix := []byte(objabi.PathToPrefix(r.lib.Pkg) + ".")
 	patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
 
 	s.P = append(patched, s.P[e:]...)
@@ -467,7 +381,7 @@ func (r *objReader) readRef() {
 	name := r.readSymName()
 	v := r.readInt()
 	if v != 0 && v != 1 {
-		log.Fatalf("invalid symbol version %d", v)
+		log.Fatalf("invalid symbol version for %q: %d", name, v)
 	}
 	if v == 1 {
 		v = r.localSymVersion
@@ -483,7 +397,7 @@ func (r *objReader) readRef() {
 		if err != nil {
 			log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
 		}
-		s.Type = obj.SRODATA
+		s.Type = SRODATA
 		s.Attr |= AttrLocal
 		switch s.Name[:5] {
 		case "$f32.":
@@ -572,7 +486,7 @@ func (r *objReader) readData() []byte {
 
 // readSymName reads a symbol name, replacing all "". with pkg.
 func (r *objReader) readSymName() string {
-	pkg := pathtoprefix(r.lib.Pkg)
+	pkg := objabi.PathToPrefix(r.lib.Pkg)
 	n := r.readInt()
 	if n == 0 {
 		r.readInt64()
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 479425f..1f6aed3 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -5,7 +5,8 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
+	"cmd/internal/src"
 	"log"
 	"os"
 	"path/filepath"
@@ -108,18 +109,24 @@ func ftabaddstring(ctxt *Link, ftab *Symbol, s string) int32 {
 	return start
 }
 
+// numberfile assigns a file number to the file if it hasn't been assigned already.
+func numberfile(ctxt *Link, file *Symbol) {
+	if file.Type != SFILEPATH {
+		ctxt.Filesyms = append(ctxt.Filesyms, file)
+		file.Value = int64(len(ctxt.Filesyms))
+		file.Type = SFILEPATH
+		path := file.Name[len(src.FileSymPrefix):]
+		file.Name = expandGoroot(path)
+	}
+}
+
 func renumberfiles(ctxt *Link, files []*Symbol, d *Pcdata) {
 	var f *Symbol
 
 	// Give files numbers.
 	for i := 0; i < len(files); i++ {
 		f = files[i]
-		if f.Type != obj.SFILEPATH {
-			ctxt.Filesyms = append(ctxt.Filesyms, f)
-			f.Value = int64(len(ctxt.Filesyms))
-			f.Type = obj.SFILEPATH
-			f.Name = expandGoroot(f.Name)
-		}
+		numberfile(ctxt, f)
 	}
 
 	newval := int32(-1)
@@ -168,12 +175,12 @@ func container(s *Symbol) int {
 	if s == nil {
 		return 0
 	}
-	if Buildmode == BuildmodePlugin && Headtype == obj.Hdarwin && onlycsymbol(s) {
+	if Buildmode == BuildmodePlugin && Headtype == objabi.Hdarwin && onlycsymbol(s) {
 		return 1
 	}
 	// We want to generate func table entries only for the "lowest level" symbols,
 	// not containers of subsymbols.
-	if s.Type&obj.SCONTAINER != 0 {
+	if s.Type&SCONTAINER != 0 {
 		return 1
 	}
 	return 0
@@ -194,7 +201,7 @@ var pclntabLastFunc *Symbol
 func (ctxt *Link) pclntab() {
 	funcdataBytes := int64(0)
 	ftab := ctxt.Syms.Lookup("runtime.pclntab", 0)
-	ftab.Type = obj.SPCLNTAB
+	ftab.Type = SPCLNTAB
 	ftab.Attr |= AttrReachable
 
 	// See golang.org/s/go12symtab for the format. Briefly:
@@ -208,7 +215,7 @@ func (ctxt *Link) pclntab() {
 	// Find container symbols, mark them with SCONTAINER
 	for _, s := range ctxt.Textp {
 		if s.Outer != nil {
-			s.Outer.Type |= obj.SCONTAINER
+			s.Outer.Type |= SCONTAINER
 		}
 	}
 
@@ -223,9 +230,19 @@ func (ctxt *Link) pclntab() {
 	setuint32(ctxt, ftab, 0, 0xfffffffb)
 	setuint8(ctxt, ftab, 6, uint8(SysArch.MinLC))
 	setuint8(ctxt, ftab, 7, uint8(SysArch.PtrSize))
-	setuintxx(ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
+	setuint(ctxt, ftab, 8, uint64(nfunc))
 	pclntabPclntabOffset = int32(8 + SysArch.PtrSize)
 
+	funcnameoff := make(map[string]int32)
+	nameToOffset := func(name string) int32 {
+		nameoff, ok := funcnameoff[name]
+		if !ok {
+			nameoff = ftabaddstring(ctxt, ftab, name)
+			funcnameoff[name] = nameoff
+		}
+		return nameoff
+	}
+
 	nfunc = 0
 	var last *Symbol
 	for _, s := range ctxt.Textp {
@@ -242,11 +259,30 @@ func (ctxt *Link) pclntab() {
 			pclntabFirstFunc = s
 		}
 
+		if len(pcln.InlTree) > 0 {
+			if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex {
+				// Create inlining pcdata table.
+				pcdata := make([]Pcdata, objabi.PCDATA_InlTreeIndex+1)
+				copy(pcdata, pcln.Pcdata)
+				pcln.Pcdata = pcdata
+			}
+
+			if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree {
+				// Create inline tree funcdata.
+				funcdata := make([]*Symbol, objabi.FUNCDATA_InlTree+1)
+				funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1)
+				copy(funcdata, pcln.Funcdata)
+				copy(funcdataoff, pcln.Funcdataoff)
+				pcln.Funcdata = funcdata
+				pcln.Funcdataoff = funcdataoff
+			}
+		}
+
 		funcstart := int32(len(ftab.P))
 		funcstart += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
 
 		setaddr(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), s)
-		setuintxx(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
+		setuint(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart))
 
 		// Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
 		// and package debug/gosym.
@@ -264,7 +300,8 @@ func (ctxt *Link) pclntab() {
 		off = int32(setaddr(ctxt, ftab, int64(off), s))
 
 		// name int32
-		off = int32(setuint32(ctxt, ftab, int64(off), uint32(ftabaddstring(ctxt, ftab, s.Name))))
+		nameoff := nameToOffset(s.Name)
+		off = int32(setuint32(ctxt, ftab, int64(off), uint32(nameoff)))
 
 		// args int32
 		// TODO: Move into funcinfo.
@@ -295,6 +332,30 @@ func (ctxt *Link) pclntab() {
 			}
 		}
 
+		if len(pcln.InlTree) > 0 {
+			inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0)
+			inlTreeSym.Type = SRODATA
+			inlTreeSym.Attr |= AttrReachable | AttrDuplicateOK
+
+			for i, call := range pcln.InlTree {
+				// Usually, call.File is already numbered since the file
+				// shows up in the Pcfile table. However, two inlined calls
+				// might overlap exactly so that only the innermost file
+				// appears in the Pcfile table. In that case, this assigns
+				// the outer file a number.
+				numberfile(ctxt, call.File)
+				nameoff := nameToOffset(call.Func.Name)
+
+				setuint32(ctxt, inlTreeSym, int64(i*16+0), uint32(call.Parent))
+				setuint32(ctxt, inlTreeSym, int64(i*16+4), uint32(call.File.Value))
+				setuint32(ctxt, inlTreeSym, int64(i*16+8), uint32(call.Line))
+				setuint32(ctxt, inlTreeSym, int64(i*16+12), uint32(nameoff))
+			}
+
+			pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym
+			pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline
+		}
+
 		// pcdata
 		off = addpctab(ctxt, ftab, off, &pcln.Pcsp)
 
@@ -314,7 +375,7 @@ func (ctxt *Link) pclntab() {
 			}
 			for i := 0; i < len(pcln.Funcdata); i++ {
 				if pcln.Funcdata[i] == nil {
-					setuintxx(ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize))
+					setuint(ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]))
 				} else {
 					// TODO: Dedup.
 					funcdataBytes += pcln.Funcdata[i].Size
@@ -355,14 +416,14 @@ func (ctxt *Link) pclntab() {
 	ftab.Size = int64(len(ftab.P))
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), ftab.Size, funcdataBytes)
+		ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", Cputime(), ftab.Size, funcdataBytes)
 	}
 }
 
 func expandGoroot(s string) string {
 	const n = len("$GOROOT")
 	if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
-		root := obj.GOROOT
+		root := objabi.GOROOT
 		if final := os.Getenv("GOROOT_FINAL"); final != "" {
 			root = final
 		}
@@ -382,7 +443,7 @@ const (
 // function for a pc. See src/runtime/symtab.go:findfunc for details.
 func (ctxt *Link) findfunctab() {
 	t := ctxt.Syms.Lookup("runtime.findfunctab", 0)
-	t.Type = obj.SRODATA
+	t.Type = SRODATA
 	t.Attr |= AttrReachable
 	t.Attr |= AttrLocal
 
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 517ed6c..a64975c 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -5,7 +5,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
@@ -101,15 +101,17 @@ type IMAGE_EXPORT_DIRECTORY struct {
 
 const (
 	PEBASE = 0x00400000
+)
 
+var (
 	// SectionAlignment must be greater than or equal to FileAlignment.
 	// The default is the page size for the architecture.
-	PESECTALIGN = 0x1000
+	PESECTALIGN int64 = 0x1000
 
 	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
 	// The default is 512. If the SectionAlignment is less than
 	// the architecture's page size, then FileAlignment must match SectionAlignment.
-	PEFILEALIGN = 2 << 8
+	PEFILEALIGN int64 = 2 << 8
 )
 
 const (
@@ -354,6 +356,9 @@ var oh64 PE64_IMAGE_OPTIONAL_HEADER
 
 var sh [16]IMAGE_SECTION_HEADER
 
+// shNames stores full names of PE sections stored in sh.
+var shNames []string
+
 var dd []IMAGE_DATA_DIRECTORY
 
 type Imp struct {
@@ -377,7 +382,7 @@ var dexport [1024]*Symbol
 
 var nexport int
 
-func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
+func addpesectionWithLongName(ctxt *Link, shortname, longname string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
 	if pensect == 16 {
 		Errorf(nil, "too many sections")
 		errorexit()
@@ -385,7 +390,8 @@ func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SE
 
 	h := &sh[pensect]
 	pensect++
-	copy(h.Name[:], name)
+	copy(h.Name[:], shortname)
+	shNames = append(shNames, longname)
 	h.VirtualSize = uint32(sectsize)
 	h.VirtualAddress = uint32(nextsectoff)
 	nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN))
@@ -398,6 +404,9 @@ func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SE
 	return h
 }
 
+func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
+	return addpesectionWithLongName(ctxt, name, name, sectsize, filesize)
+}
 func chksectoff(ctxt *Link, h *IMAGE_SECTION_HEADER, off int64) {
 	if off != int64(h.PointerToRawData) {
 		Errorf(nil, "%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
@@ -435,15 +444,39 @@ func Peinit(ctxt *Link) {
 		dd = oh.DataDirectory[:]
 	}
 
+	if Linkmode == LinkExternal {
+		PESECTALIGN = 0
+		PEFILEALIGN = 0
+	}
+
 	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
-	PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
+	if Linkmode != LinkExternal {
+		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
+	} else {
+		PESECTHEADR = 0
+	}
 	nextsectoff = int(PESECTHEADR)
 	nextfileoff = int(PEFILEHEADR)
 
-	// some mingw libs depend on this symbol, for example, FindPESectionByName
-	ctxt.xdefine("__image_base__", obj.SDATA, PEBASE)
+	if Linkmode == LinkInternal {
+		// some mingw libs depend on this symbol, for example, FindPESectionByName
+		ctxt.xdefine("__image_base__", SDATA, PEBASE)
+		ctxt.xdefine("_image_base__", SDATA, PEBASE)
+	}
 
-	ctxt.xdefine("_image_base__", obj.SDATA, PEBASE)
+	HEADR = PEFILEHEADR
+	if *FlagTextAddr == -1 {
+		*FlagTextAddr = PEBASE + int64(PESECTHEADR)
+	}
+	if *FlagDataAddr == -1 {
+		*FlagDataAddr = 0
+	}
+	if *FlagRound == -1 {
+		*FlagRound = int(PESECTALIGN)
+	}
+	if *FlagDataAddr != 0 && *FlagRound != 0 {
+		fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*FlagDataAddr), uint32(*FlagRound))
+	}
 }
 
 func pewrite() {
@@ -460,6 +493,11 @@ func pewrite() {
 	} else {
 		binary.Write(&coutbuf, binary.LittleEndian, &oh)
 	}
+	if Linkmode == LinkExternal {
+		for i := range sh[:pensect] {
+			sh[i].VirtualAddress = 0
+		}
+	}
 	binary.Write(&coutbuf, binary.LittleEndian, sh[:pensect])
 }
 
@@ -478,7 +516,7 @@ func initdynimport(ctxt *Link) *Dll {
 	dr = nil
 	var m *Imp
 	for _, s := range ctxt.Syms.Allsym {
-		if !s.Attr.Reachable() || s.Type != obj.SDYNIMPORT {
+		if !s.Attr.Reachable() || s.Type != SDYNIMPORT {
 			continue
 		}
 		for d = dr; d != nil; d = d.next {
@@ -520,7 +558,7 @@ func initdynimport(ctxt *Link) *Dll {
 		// Add real symbol name
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
-				m.s.Type = obj.SDATA
+				m.s.Type = SDATA
 				Symgrow(m.s, int64(SysArch.PtrSize))
 				dynName := m.s.Extname
 				// only windows/386 requires stdcall decoration
@@ -529,21 +567,21 @@ func initdynimport(ctxt *Link) *Dll {
 				}
 				dynSym := ctxt.Syms.Lookup(dynName, 0)
 				dynSym.Attr |= AttrReachable
-				dynSym.Type = obj.SHOSTOBJ
+				dynSym.Type = SHOSTOBJ
 				r := Addrel(m.s)
 				r.Sym = dynSym
 				r.Off = 0
 				r.Siz = uint8(SysArch.PtrSize)
-				r.Type = obj.R_ADDR
+				r.Type = objabi.R_ADDR
 			}
 		}
 	} else {
 		dynamic := ctxt.Syms.Lookup(".windynamic", 0)
 		dynamic.Attr |= AttrReachable
-		dynamic.Type = obj.SWINDOWS
+		dynamic.Type = SWINDOWS
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
-				m.s.Type = obj.SWINDOWS | obj.SSUB
+				m.s.Type = SWINDOWS | SSUB
 				m.s.Sub = dynamic.Sub
 				dynamic.Sub = m.s
 				m.s.Value = dynamic.Size
@@ -763,7 +801,7 @@ func addexports(ctxt *Link) {
 
 // perelocsect relocates symbols from first in section sect, and returns
 // the total number of relocations emitted.
-func perelocsect(ctxt *Link, sect *Section, syms []*Symbol) int {
+func perelocsect(ctxt *Link, sect *Section, syms []*Symbol, base uint64) int {
 	// If main section has no bits, nothing to relocate.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
 		return 0
@@ -803,7 +841,7 @@ func perelocsect(ctxt *Link, sect *Section, syms []*Symbol) int {
 			if r.Xsym.Dynid < 0 {
 				Errorf(sym, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
 			}
-			if !Thearch.PEreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
+			if !Thearch.PEreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-base)) {
 				Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
 			}
 
@@ -816,73 +854,81 @@ func perelocsect(ctxt *Link, sect *Section, syms []*Symbol) int {
 	return relocs
 }
 
-// peemitreloc emits relocation entries for go.o in external linking.
-func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) {
-	for coutbuf.Offset()&7 != 0 {
-		Cput(0)
-	}
-
-	text.PointerToRelocations = uint32(coutbuf.Offset())
+// peemitsectreloc emits the relocation entries for sect.
+// The actual relocations are emitted by relocfn.
+// This updates the corresponding PE section table entry
+// with the relocation offset and count.
+func peemitsectreloc(sect *IMAGE_SECTION_HEADER, relocfn func() int) {
+	sect.PointerToRelocations = uint32(coutbuf.Offset())
 	// first entry: extended relocs
 	Lputl(0) // placeholder for number of relocation + 1
 	Lputl(0)
 	Wputl(0)
 
-	n := perelocsect(ctxt, Segtext.Sect, ctxt.Textp) + 1
-	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
-		n += perelocsect(ctxt, sect, datap)
-	}
+	n := relocfn() + 1
 
 	cpos := coutbuf.Offset()
-	Cseek(int64(text.PointerToRelocations))
+	Cseek(int64(sect.PointerToRelocations))
 	Lputl(uint32(n))
 	Cseek(cpos)
 	if n > 0x10000 {
 		n = 0x10000
-		text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
+		sect.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
 	} else {
-		text.PointerToRelocations += 10 // skip the extend reloc entry
+		sect.PointerToRelocations += 10 // skip the extend reloc entry
 	}
-	text.NumberOfRelocations = uint16(n - 1)
-
-	data.PointerToRelocations = uint32(cpos)
-	// first entry: extended relocs
-	Lputl(0) // placeholder for number of relocation + 1
-	Lputl(0)
-	Wputl(0)
+	sect.NumberOfRelocations = uint16(n - 1)
+}
 
-	n = 1
-	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
-		n += perelocsect(ctxt, sect, datap)
+// peemitreloc emits relocation entries for go.o in external linking.
+func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) {
+	for coutbuf.Offset()&7 != 0 {
+		Cput(0)
 	}
 
-	cpos = coutbuf.Offset()
-	Cseek(int64(data.PointerToRelocations))
-	Lputl(uint32(n))
-	Cseek(cpos)
-	if n > 0x10000 {
-		n = 0x10000
-		data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
-	} else {
-		data.PointerToRelocations += 10 // skip the extend reloc entry
-	}
-	data.NumberOfRelocations = uint16(n - 1)
+	peemitsectreloc(text, func() int {
+		n := perelocsect(ctxt, Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr)
+		for _, sect := range Segtext.Sections[1:] {
+			n += perelocsect(ctxt, sect, datap, Segtext.Vaddr)
+		}
+		return n
+	})
 
-	dottext := ctxt.Syms.Lookup(".text", 0)
-	ctors.NumberOfRelocations = 1
-	ctors.PointerToRelocations = uint32(coutbuf.Offset())
-	sectoff := ctors.VirtualAddress
-	Lputl(sectoff)
-	Lputl(uint32(dottext.Dynid))
-	switch obj.GOARCH {
-	default:
-		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH)
-		os.Exit(2)
-	case "386":
-		Wputl(IMAGE_REL_I386_DIR32)
-	case "amd64":
-		Wputl(IMAGE_REL_AMD64_ADDR64)
+	peemitsectreloc(data, func() int {
+		var n int
+		for _, sect := range Segdata.Sections {
+			n += perelocsect(ctxt, sect, datap, Segdata.Vaddr)
+		}
+		return n
+	})
+
+dwarfLoop:
+	for _, sect := range Segdwarf.Sections {
+		for i, name := range shNames {
+			if sect.Name == name {
+				peemitsectreloc(&sh[i], func() int {
+					return perelocsect(ctxt, sect, dwarfp, sect.Vaddr)
+				})
+				continue dwarfLoop
+			}
+		}
+		Errorf(nil, "peemitsectreloc: could not find %q section", sect.Name)
 	}
+
+	peemitsectreloc(ctors, func() int {
+		dottext := ctxt.Syms.Lookup(".text", 0)
+		Lputl(0)
+		Lputl(uint32(dottext.Dynid))
+		switch objabi.GOARCH {
+		default:
+			Errorf(dottext, "unknown architecture for PE: %q\n", objabi.GOARCH)
+		case "386":
+			Wputl(IMAGE_REL_I386_DIR32)
+		case "amd64":
+			Wputl(IMAGE_REL_AMD64_ADDR64)
+		}
+		return 1
+	})
 }
 
 func (ctxt *Link) dope() {
@@ -890,7 +936,7 @@ func (ctxt *Link) dope() {
 	rel := ctxt.Syms.Lookup(".rel", 0)
 
 	rel.Attr |= AttrReachable
-	rel.Type = obj.SELFROSECT
+	rel.Type = SELFROSECT
 
 	initdynimport(ctxt)
 	initdynexport(ctxt)
@@ -917,7 +963,7 @@ func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADE
 
 	off := strtbladd(name)
 	s := fmt.Sprintf("/%d", off)
-	h := addpesection(ctxt, s, int(size), int(size))
+	h := addpesectionWithLongName(ctxt, s, name, int(size), int(size))
 	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
 
 	return h
@@ -928,6 +974,25 @@ func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADE
 func writePESymTableRecords(ctxt *Link) int {
 	var symcnt int
 
+	writeOneSymbol := func(s *Symbol, addr int64, sectidx int, typ uint16, class uint8) {
+		// write COFF symbol table record
+		if len(s.Name) > 8 {
+			Lputl(0)
+			Lputl(uint32(strtbladd(s.Name)))
+		} else {
+			strnput(s.Name, 8)
+		}
+		Lputl(uint32(addr))
+		Wputl(uint16(sectidx))
+		Wputl(typ)
+		Cput(class)
+		Cput(0) // no aux entries
+
+		s.Dynid = int32(symcnt)
+
+		symcnt++
+	}
+
 	put := func(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) {
 		if s == nil {
 			return
@@ -941,27 +1006,27 @@ func writePESymTableRecords(ctxt *Link) int {
 		case DataSym, BSSSym, TextSym, UndefinedSym:
 		}
 
-		// only windows/386 requires underscore prefix on external symbols
+		// Only windows/386 requires underscore prefix on external symbols.
 		if SysArch.Family == sys.I386 &&
 			Linkmode == LinkExternal &&
-			(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
-			s.Name == s.Extname &&
-			s.Name != "_main" {
+			(s.Type == SHOSTOBJ || s.Attr.CgoExport()) {
 			s.Name = "_" + s.Name
 		}
 
-		var typ uint16
+		typ := uint16(IMAGE_SYM_TYPE_NULL)
 		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 {
-			value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
-			sect = bsssect
-		} else if uint64(s.Value) >= Segdata.Vaddr {
-			value = int64(uint64(s.Value) - Segdata.Vaddr)
-			sect = datasect
-		} else if uint64(s.Value) >= Segtext.Vaddr {
+		if s.Sect != nil && s.Sect.Seg == &Segdata {
+			// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
+			// it still belongs to the .data section, not the .bss section.
+			if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != SDATA && Linkmode == LinkExternal {
+				value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
+				sect = bsssect
+			} else {
+				value = int64(uint64(s.Value) - Segdata.Vaddr)
+				sect = datasect
+			}
+		} else if s.Sect != nil && s.Sect.Seg == &Segtext {
 			value = int64(uint64(s.Value) - Segtext.Vaddr)
 			sect = textsect
 		} else if type_ == UndefinedSym {
@@ -969,42 +1034,25 @@ func writePESymTableRecords(ctxt *Link) int {
 		} else {
 			Errorf(s, "addpesym %#x", addr)
 		}
-
-		// write COFF symbol table record
-		if len(s.Name) > 8 {
-			Lputl(0)
-			Lputl(uint32(strtbladd(s.Name)))
-		} else {
-			strnput(s.Name, 8)
+		if typ != IMAGE_SYM_TYPE_NULL {
+		} else if Linkmode != LinkExternal {
+			// TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308
+			typ = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT
+			typ = 0x0308 // "array of structs"
 		}
-		Lputl(uint32(value))
-		Wputl(uint16(sect))
-		if typ != 0 {
-			Wputl(typ)
-		} else if Linkmode == LinkExternal {
-			Wputl(0)
-		} else {
-			Wputl(0x0308) // "array of structs"
+		class := IMAGE_SYM_CLASS_EXTERNAL
+		if s.Version != 0 || (s.Type&SHIDDEN != 0) || s.Attr.Local() {
+			class = IMAGE_SYM_CLASS_STATIC
 		}
-		Cput(2) // storage class: external
-		Cput(0) // no aux entries
-
-		s.Dynid = int32(symcnt)
-
-		symcnt++
+		writeOneSymbol(s, value, sect, typ, uint8(class))
 	}
 
 	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(ctxt, s, s.Name, UndefinedSym, 0, nil)
-			}
-		}
-
-		s := ctxt.Syms.Lookup(".text", 0)
-		if s.Type == obj.STEXT {
-			put(ctxt, s, s.Name, TextSym, s.Value, nil)
+		// Include section symbols as external, because
+		// .ctors and .debug_* section relocations refer to it.
+		for idx, name := range shNames {
+			sym := ctxt.Syms.Lookup(name, 0)
+			writeOneSymbol(sym, 0, idx+1, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
 		}
 	}
 
@@ -1095,9 +1143,9 @@ func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) {
 	// 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.GOARCH {
+	switch objabi.GOARCH {
 	default:
-		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH)
+		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", objabi.GOARCH)
 		os.Exit(2)
 	case "386":
 		size = 4
@@ -1114,7 +1162,7 @@ func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) {
 	init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0)
 	addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
 
-	switch obj.GOARCH {
+	switch objabi.GOARCH {
 	case "386":
 		Lputl(uint32(addr))
 	case "amd64":
@@ -1161,14 +1209,16 @@ func Asmbpe(ctxt *Link) {
 		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(ctxt)
 	}
 
 	if !*FlagS {
 		dwarfaddpeheaders(ctxt)
 	}
 
+	if Linkmode == LinkExternal {
+		c = addinitarray(ctxt)
+	}
+
 	Cseek(int64(nextfileoff))
 	if Linkmode != LinkExternal {
 		addimports(ctxt, d)
@@ -1222,10 +1272,10 @@ func Asmbpe(ctxt *Link) {
 	oh.BaseOfCode = t.VirtualAddress
 	oh64.ImageBase = PEBASE
 	oh.ImageBase = PEBASE
-	oh64.SectionAlignment = PESECTALIGN
-	oh.SectionAlignment = PESECTALIGN
-	oh64.FileAlignment = PEFILEALIGN
-	oh.FileAlignment = PEFILEALIGN
+	oh64.SectionAlignment = uint32(PESECTALIGN)
+	oh.SectionAlignment = uint32(PESECTALIGN)
+	oh64.FileAlignment = uint32(PEFILEALIGN)
+	oh.FileAlignment = uint32(PEFILEALIGN)
 	oh64.MajorOperatingSystemVersion = 4
 	oh.MajorOperatingSystemVersion = 4
 	oh64.MinorOperatingSystemVersion = 0
@@ -1242,7 +1292,7 @@ func Asmbpe(ctxt *Link) {
 	oh.SizeOfImage = uint32(nextsectoff)
 	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
 	oh.SizeOfHeaders = uint32(PEFILEHEADR)
-	if Headtype == obj.Hwindowsgui {
+	if windowsgui {
 		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
 		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
 	} else {
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 4908e34..6e239d7 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -32,7 +32,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"log"
 )
@@ -47,11 +47,12 @@ func linknew(arch *sys.Arch) *Link {
 			},
 			Allsym: make([]*Symbol, 0, 100000),
 		},
-		Arch: arch,
+		Arch:         arch,
+		LibraryByPkg: make(map[string]*Library),
 	}
 
-	if obj.GOARCH != arch.Name {
-		log.Fatalf("invalid obj.GOARCH %s (want %s)", obj.GOARCH, arch.Name)
+	if objabi.GOARCH != arch.Name {
+		log.Fatalf("invalid objabi.GOARCH %s (want %s)", objabi.GOARCH, arch.Name)
 	}
 
 	return ctxt
@@ -63,7 +64,7 @@ func (ctxt *Link) computeTLSOffset() {
 	default:
 		log.Fatalf("unknown thread-local storage offset for %v", Headtype)
 
-	case obj.Hplan9, obj.Hwindows, obj.Hwindowsgui:
+	case objabi.Hplan9, objabi.Hwindows:
 		break
 
 		/*
@@ -71,13 +72,13 @@ func (ctxt *Link) computeTLSOffset() {
 		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
 		 * Known to low-level assembly in package runtime and runtime/cgo.
 		 */
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hdragonfly,
-		obj.Hsolaris:
-		if obj.GOOS == "android" {
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hdragonfly,
+		objabi.Hsolaris:
+		if objabi.GOOS == "android" {
 			switch ctxt.Arch.Family {
 			case sys.AMD64:
 				// Android/amd64 constant - offset from 0(FS) to our TLS slot.
@@ -93,7 +94,7 @@ func (ctxt *Link) computeTLSOffset() {
 			ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
@@ -112,7 +113,7 @@ func (ctxt *Link) computeTLSOffset() {
 		 * OS X system constants - offset from 0(GS) to our TLS.
 		 * Explained in src/runtime/cgo/gcc_darwin_*.c.
 		 */
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
diff --git a/src/cmd/link/internal/ld/symkind.go b/src/cmd/link/internal/ld/symkind.go
new file mode 100644
index 0000000..c057f6c
--- /dev/null
+++ b/src/cmd/link/internal/ld/symkind.go
@@ -0,0 +1,152 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+// A SymKind describes the kind of memory represented by a symbol.
+type SymKind int16
+
+// Defined SymKind values.
+//
+// TODO(rsc): Give idiomatic Go names.
+//go:generate stringer -type=SymKind
+const (
+	Sxxx SymKind = iota
+	STEXT
+	SELFRXSECT
+
+	// Read-only sections.
+	STYPE
+	SSTRING
+	SGOSTRING
+	SGOFUNC
+	SGCBITS
+	SRODATA
+	SFUNCTAB
+
+	SELFROSECT
+	SMACHOPLT
+
+	// Read-only sections with relocations.
+	//
+	// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
+	// When linking a shared object, some conceptually "read only" types need to
+	// be written to by relocations and putting them in a section called
+	// ".rodata" interacts poorly with the system linkers. The GNU linkers
+	// support this situation by arranging for sections of the name
+	// ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
+	// relocations have applied, so when the Go linker is creating a shared
+	// object it checks all objects of the above types and bumps any object that
+	// has a relocation to it to the corresponding type below, which are then
+	// written to sections with appropriate magic names.
+	STYPERELRO
+	SSTRINGRELRO
+	SGOSTRINGRELRO
+	SGOFUNCRELRO
+	SGCBITSRELRO
+	SRODATARELRO
+	SFUNCTABRELRO
+
+	// Part of .data.rel.ro if it exists, otherwise part of .rodata.
+	STYPELINK
+	SITABLINK
+	SSYMTAB
+	SPCLNTAB
+
+	// Writable sections.
+	SELFSECT
+	SMACHO
+	SMACHOGOT
+	SWINDOWS
+	SELFGOT
+	SNOPTRDATA
+	SINITARR
+	SDATA
+	SBSS
+	SNOPTRBSS
+	STLSBSS
+	SXREF
+	SMACHOSYMSTR
+	SMACHOSYMTAB
+	SMACHOINDIRECTPLT
+	SMACHOINDIRECTGOT
+	SFILE
+	SFILEPATH
+	SCONST
+	SDYNIMPORT
+	SHOSTOBJ
+	SDWARFSECT
+	SDWARFINFO
+	SDWARFRANGE
+	SSUB       = SymKind(1 << 8)
+	SMASK      = SymKind(SSUB - 1)
+	SHIDDEN    = SymKind(1 << 9)
+	SCONTAINER = SymKind(1 << 10) // has a sub-symbol
+)
+
+// abiSymKindToSymKind maps values read from object files (which are
+// of type cmd/internal/objabi.SymKind) to values of type SymKind.
+var abiSymKindToSymKind = [...]SymKind{
+	Sxxx,
+	STEXT,
+	SRODATA,
+	SNOPTRDATA,
+	SDATA,
+	SBSS,
+	SNOPTRBSS,
+	STLSBSS,
+	SDWARFINFO,
+	SDWARFRANGE,
+}
+
+// readOnly are the symbol kinds that form read-only sections. In some
+// cases, if they will require relocations, they are transformed into
+// rel-ro sections using relROMap.
+var readOnly = []SymKind{
+	STYPE,
+	SSTRING,
+	SGOSTRING,
+	SGOFUNC,
+	SGCBITS,
+	SRODATA,
+	SFUNCTAB,
+}
+
+// relROMap describes the transformation of read-only symbols to rel-ro
+// symbols.
+var relROMap = map[SymKind]SymKind{
+	STYPE:     STYPERELRO,
+	SSTRING:   SSTRINGRELRO,
+	SGOSTRING: SGOSTRINGRELRO,
+	SGOFUNC:   SGOFUNCRELRO,
+	SGCBITS:   SGCBITSRELRO,
+	SRODATA:   SRODATARELRO,
+	SFUNCTAB:  SFUNCTABRELRO,
+}
diff --git a/src/cmd/link/internal/ld/symkind_string.go b/src/cmd/link/internal/ld/symkind_string.go
new file mode 100644
index 0000000..2178b50
--- /dev/null
+++ b/src/cmd/link/internal/ld/symkind_string.go
@@ -0,0 +1,16 @@
+// Code generated by "stringer -type=SymKind"; DO NOT EDIT.
+
+package ld
+
+import "fmt"
+
+const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGE"
+
+var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419}
+
+func (i SymKind) String() string {
+	if i < 0 || i >= SymKind(len(_SymKind_index)-1) {
+		return fmt.Sprintf("SymKind(%d)", i)
+	}
+	return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
+}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index dd0e540..78e9dc2 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -31,7 +31,7 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"fmt"
 	"path/filepath"
@@ -109,7 +109,7 @@ func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *S
 	}
 
 	var elfshnum int
-	if xo.Type == obj.SDYNIMPORT || xo.Type == obj.SHOSTOBJ {
+	if xo.Type == SDYNIMPORT || xo.Type == SHOSTOBJ {
 		elfshnum = SHN_UNDEF
 	} else {
 		if xo.Sect == nil {
@@ -127,7 +127,7 @@ func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *S
 	// maybe one day STB_WEAK.
 	bind := STB_GLOBAL
 
-	if x.Version != 0 || (x.Type&obj.SHIDDEN != 0) || x.Attr.Local() {
+	if x.Version != 0 || (x.Type&SHIDDEN != 0) || x.Attr.Local() {
 		bind = STB_LOCAL
 	}
 
@@ -144,13 +144,16 @@ func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *S
 		addr -= int64(xo.Sect.Vaddr)
 	}
 	other := STV_DEFAULT
-	if x.Type&obj.SHIDDEN != 0 {
+	if x.Type&SHIDDEN != 0 {
 		other = STV_HIDDEN
 	}
-	if (Buildmode == BuildmodeCArchive || Buildmode == BuildmodePIE || ctxt.DynlinkingGo()) && SysArch.Family == sys.PPC64 && typ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+	if SysArch.Family == sys.PPC64 && typ == STT_FUNC && x.Attr.Shared() && 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.
+		// The conditions here match those in preprocess in
+		// cmd/internal/obj/ppc64/obj9.go, which is where the
+		// instructions are inserted.
 		other |= 3 << 5
 	}
 
@@ -162,7 +165,7 @@ func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *S
 		s = strings.Replace(s, "·", ".", -1)
 	}
 
-	if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == obj.STEXT {
+	if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == STEXT {
 		// When dynamically linking, we want references to functions defined
 		// in this module to always be to the function object, not to the
 		// PLT. We force this by writing an additional local symbol for every
@@ -222,7 +225,7 @@ func putplan9sym(ctxt *Link, x *Symbol, s string, typ SymbolType, addr int64, go
 
 	case AutoSym, ParamSym, FileSym, FrameSym:
 		l := 4
-		if Headtype == obj.Hplan9 && SysArch.Family == sys.AMD64 && !Flag8 {
+		if Headtype == objabi.Hplan9 && SysArch.Family == sys.AMD64 && !Flag8 {
 			Lputb(uint32(addr >> 32))
 			l = 8
 		}
@@ -307,18 +310,18 @@ func (libs byPkg) Swap(a, b int) {
 func textsectionmap(ctxt *Link) uint32 {
 
 	t := ctxt.Syms.Lookup("runtime.textsectionmap", 0)
-	t.Type = obj.SRODATA
+	t.Type = SRODATA
 	t.Attr |= AttrReachable
 	nsections := int64(0)
 
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range Segtext.Sections {
 		if sect.Name == ".text" {
 			nsections++
 		} else {
 			break
 		}
 	}
-	Symgrow(t, nsections*(2*int64(SysArch.IntSize)+int64(SysArch.PtrSize)))
+	Symgrow(t, 3*nsections*int64(SysArch.PtrSize))
 
 	off := int64(0)
 	n := 0
@@ -332,13 +335,13 @@ func textsectionmap(ctxt *Link) uint32 {
 	// order of creation starting with 1. These symbols provide the section's
 	// address after relocation by the linker.
 
-	textbase := Segtext.Sect.Vaddr
-	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+	textbase := Segtext.Sections[0].Vaddr
+	for _, sect := range Segtext.Sections {
 		if sect.Name != ".text" {
 			break
 		}
-		off = setuintxx(ctxt, t, off, sect.Vaddr-textbase, int64(SysArch.IntSize))
-		off = setuintxx(ctxt, t, off, sect.Length, int64(SysArch.IntSize))
+		off = setuint(ctxt, t, off, sect.Vaddr-textbase)
+		off = setuint(ctxt, t, off, sect.Length)
 		if n == 0 {
 			s := ctxt.Syms.ROLookup("runtime.text", 0)
 			if s == nil {
@@ -363,40 +366,40 @@ func (ctxt *Link) symtab() {
 
 	// Define these so that they'll get put into the symbol table.
 	// data.c:/^address will provide the actual values.
-	ctxt.xdefine("runtime.text", obj.STEXT, 0)
-
-	ctxt.xdefine("runtime.etext", obj.STEXT, 0)
-	ctxt.xdefine("runtime.itablink", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.eitablink", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.rodata", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.erodata", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.types", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.etypes", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
-	ctxt.xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
-	ctxt.xdefine("runtime.data", obj.SDATA, 0)
-	ctxt.xdefine("runtime.edata", obj.SDATA, 0)
-	ctxt.xdefine("runtime.bss", obj.SBSS, 0)
-	ctxt.xdefine("runtime.ebss", obj.SBSS, 0)
-	ctxt.xdefine("runtime.noptrbss", obj.SNOPTRBSS, 0)
-	ctxt.xdefine("runtime.enoptrbss", obj.SNOPTRBSS, 0)
-	ctxt.xdefine("runtime.end", obj.SBSS, 0)
-	ctxt.xdefine("runtime.epclntab", obj.SRODATA, 0)
-	ctxt.xdefine("runtime.esymtab", obj.SRODATA, 0)
+	ctxt.xdefine("runtime.text", STEXT, 0)
+
+	ctxt.xdefine("runtime.etext", STEXT, 0)
+	ctxt.xdefine("runtime.itablink", SRODATA, 0)
+	ctxt.xdefine("runtime.eitablink", SRODATA, 0)
+	ctxt.xdefine("runtime.rodata", SRODATA, 0)
+	ctxt.xdefine("runtime.erodata", SRODATA, 0)
+	ctxt.xdefine("runtime.types", SRODATA, 0)
+	ctxt.xdefine("runtime.etypes", SRODATA, 0)
+	ctxt.xdefine("runtime.noptrdata", SNOPTRDATA, 0)
+	ctxt.xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
+	ctxt.xdefine("runtime.data", SDATA, 0)
+	ctxt.xdefine("runtime.edata", SDATA, 0)
+	ctxt.xdefine("runtime.bss", SBSS, 0)
+	ctxt.xdefine("runtime.ebss", SBSS, 0)
+	ctxt.xdefine("runtime.noptrbss", SNOPTRBSS, 0)
+	ctxt.xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
+	ctxt.xdefine("runtime.end", SBSS, 0)
+	ctxt.xdefine("runtime.epclntab", SRODATA, 0)
+	ctxt.xdefine("runtime.esymtab", SRODATA, 0)
 
 	// garbage collection symbols
 	s := ctxt.Syms.Lookup("runtime.gcdata", 0)
 
-	s.Type = obj.SRODATA
+	s.Type = SRODATA
 	s.Size = 0
 	s.Attr |= AttrReachable
-	ctxt.xdefine("runtime.egcdata", obj.SRODATA, 0)
+	ctxt.xdefine("runtime.egcdata", SRODATA, 0)
 
 	s = ctxt.Syms.Lookup("runtime.gcbss", 0)
-	s.Type = obj.SRODATA
+	s.Type = SRODATA
 	s.Size = 0
 	s.Attr |= AttrReachable
-	ctxt.xdefine("runtime.egcbss", obj.SRODATA, 0)
+	ctxt.xdefine("runtime.egcbss", SRODATA, 0)
 
 	// pseudo-symbols to mark locations of type, string, and go string data.
 	var symtype *Symbol
@@ -404,28 +407,28 @@ func (ctxt *Link) symtab() {
 	if UseRelro() && (Buildmode == BuildmodeCArchive || Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
 		s = ctxt.Syms.Lookup("type.*", 0)
 
-		s.Type = obj.STYPE
+		s.Type = STYPE
 		s.Size = 0
 		s.Attr |= AttrReachable
 		symtype = s
 
 		s = ctxt.Syms.Lookup("typerel.*", 0)
 
-		s.Type = obj.STYPERELRO
+		s.Type = STYPERELRO
 		s.Size = 0
 		s.Attr |= AttrReachable
 		symtyperel = s
 	} else if !ctxt.DynlinkingGo() {
 		s = ctxt.Syms.Lookup("type.*", 0)
 
-		s.Type = obj.STYPE
+		s.Type = STYPE
 		s.Size = 0
 		s.Attr |= AttrReachable
 		symtype = s
 		symtyperel = s
 	}
 
-	groupSym := func(name string, t obj.SymKind) *Symbol {
+	groupSym := func(name string, t SymKind) *Symbol {
 		s := ctxt.Syms.Lookup(name, 0)
 		s.Type = t
 		s.Size = 0
@@ -433,26 +436,26 @@ func (ctxt *Link) symtab() {
 		return s
 	}
 	var (
-		symgostring = groupSym("go.string.*", obj.SGOSTRING)
-		symgofunc   = groupSym("go.func.*", obj.SGOFUNC)
-		symgcbits   = groupSym("runtime.gcbits.*", obj.SGCBITS)
+		symgostring = groupSym("go.string.*", SGOSTRING)
+		symgofunc   = groupSym("go.func.*", SGOFUNC)
+		symgcbits   = groupSym("runtime.gcbits.*", SGCBITS)
 	)
 
 	var symgofuncrel *Symbol
 	if !ctxt.DynlinkingGo() {
 		if UseRelro() {
-			symgofuncrel = groupSym("go.funcrel.*", obj.SGOFUNCRELRO)
+			symgofuncrel = groupSym("go.funcrel.*", SGOFUNCRELRO)
 		} else {
 			symgofuncrel = symgofunc
 		}
 	}
 
 	symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
-	symitablink.Type = obj.SITABLINK
+	symitablink.Type = SITABLINK
 
 	symt = ctxt.Syms.Lookup("runtime.symtab", 0)
 	symt.Attr |= AttrLocal
-	symt.Type = obj.SSYMTAB
+	symt.Type = SSYMTAB
 	symt.Size = 0
 	symt.Attr |= AttrReachable
 
@@ -463,59 +466,62 @@ func (ctxt *Link) symtab() {
 	// just defined above will be first.
 	// hide the specific symbols.
 	for _, s := range ctxt.Syms.Allsym {
-		if !s.Attr.Reachable() || s.Attr.Special() || s.Type != obj.SRODATA {
+		if !s.Attr.Reachable() || s.Attr.Special() || s.Type != SRODATA {
 			continue
 		}
 
 		switch {
 		case strings.HasPrefix(s.Name, "type."):
 			if !ctxt.DynlinkingGo() {
-				s.Attr |= AttrHidden
+				s.Attr |= AttrNotInSymbolTable
 			}
 			if UseRelro() {
-				s.Type = obj.STYPERELRO
+				s.Type = STYPERELRO
 				s.Outer = symtyperel
 			} else {
-				s.Type = obj.STYPE
+				s.Type = STYPE
 				s.Outer = symtype
 			}
 
 		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
+			s.Type = STYPERELRO
 
 		case strings.HasPrefix(s.Name, "go.itablink."):
 			nitablinks++
-			s.Type = obj.SITABLINK
-			s.Attr |= AttrHidden
+			s.Type = SITABLINK
+			s.Attr |= AttrNotInSymbolTable
 			s.Outer = symitablink
 
 		case strings.HasPrefix(s.Name, "go.string."):
-			s.Type = obj.SGOSTRING
-			s.Attr |= AttrHidden
+			s.Type = SGOSTRING
+			s.Attr |= AttrNotInSymbolTable
 			s.Outer = symgostring
 
 		case strings.HasPrefix(s.Name, "runtime.gcbits."):
-			s.Type = obj.SGCBITS
-			s.Attr |= AttrHidden
+			s.Type = SGCBITS
+			s.Attr |= AttrNotInSymbolTable
 			s.Outer = symgcbits
 
 		case strings.HasSuffix(s.Name, "·f"):
 			if !ctxt.DynlinkingGo() {
-				s.Attr |= AttrHidden
+				s.Attr |= AttrNotInSymbolTable
 			}
 			if UseRelro() {
-				s.Type = obj.SGOFUNCRELRO
+				s.Type = SGOFUNCRELRO
 				s.Outer = symgofuncrel
 			} else {
-				s.Type = obj.SGOFUNC
+				s.Type = SGOFUNC
 				s.Outer = symgofunc
 			}
 
-		case strings.HasPrefix(s.Name, "gcargs."), strings.HasPrefix(s.Name, "gclocals."), strings.HasPrefix(s.Name, "gclocals·"):
-			s.Type = obj.SGOFUNC
-			s.Attr |= AttrHidden
+		case strings.HasPrefix(s.Name, "gcargs."),
+			strings.HasPrefix(s.Name, "gclocals."),
+			strings.HasPrefix(s.Name, "gclocals·"),
+			strings.HasPrefix(s.Name, "inltree."):
+			s.Type = SGOFUNC
+			s.Attr |= AttrNotInSymbolTable
 			s.Outer = symgofunc
 			s.Align = 4
 			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
@@ -525,7 +531,7 @@ func (ctxt *Link) symtab() {
 	if Buildmode == BuildmodeShared {
 		abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0)
 		abihashgostr.Attr |= AttrReachable
-		abihashgostr.Type = obj.SRODATA
+		abihashgostr.Type = SRODATA
 		hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
 		Addaddr(ctxt, abihashgostr, hashsym)
 		adduint(ctxt, abihashgostr, uint64(hashsym.Size))
@@ -534,12 +540,12 @@ func (ctxt *Link) symtab() {
 		for _, l := range ctxt.Library {
 			s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0)
 			s.Attr |= AttrReachable
-			s.Type = obj.SRODATA
+			s.Type = SRODATA
 			s.Size = int64(len(l.hash))
 			s.P = []byte(l.hash)
 			str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0)
 			str.Attr |= AttrReachable
-			str.Type = obj.SRODATA
+			str.Type = SRODATA
 			Addaddr(ctxt, str, s)
 			adduint(ctxt, str, uint64(len(l.hash)))
 		}
@@ -604,7 +610,7 @@ func (ctxt *Link) symtab() {
 	// The ptab slice
 	if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() {
 		ptab.Attr |= AttrLocal
-		ptab.Type = obj.SRODATA
+		ptab.Type = SRODATA
 
 		nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff)
 		Addaddr(ctxt, moduledata, ptab)
@@ -621,7 +627,7 @@ func (ctxt *Link) symtab() {
 		pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0)
 		pkghashes.Attr |= AttrReachable
 		pkghashes.Attr |= AttrLocal
-		pkghashes.Type = obj.SRODATA
+		pkghashes.Type = SRODATA
 
 		for i, l := range ctxt.Library {
 			// pkghashes[i].name
@@ -655,7 +661,7 @@ func (ctxt *Link) symtab() {
 		modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0)
 		modulehashes.Attr |= AttrReachable
 		modulehashes.Attr |= AttrLocal
-		modulehashes.Type = obj.SRODATA
+		modulehashes.Type = SRODATA
 
 		for i, shlib := range ctxt.Shlibs {
 			// modulehashes[i].modulename
@@ -685,8 +691,8 @@ func (ctxt *Link) symtab() {
 	Symgrow(moduledata, moduledata.Size)
 
 	lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
-	if lastmoduledatap.Type != obj.SDYNIMPORT {
-		lastmoduledatap.Type = obj.SNOPTRDATA
+	if lastmoduledatap.Type != SDYNIMPORT {
+		lastmoduledatap.Type = SNOPTRDATA
 		lastmoduledatap.Size = 0 // overwrite existing value
 		Addaddr(ctxt, lastmoduledatap, moduledata)
 	}
diff --git a/src/cmd/link/internal/ld/typelink.go b/src/cmd/link/internal/ld/typelink.go
index 48a1104..a3badb3 100644
--- a/src/cmd/link/internal/ld/typelink.go
+++ b/src/cmd/link/internal/ld/typelink.go
@@ -5,9 +5,8 @@
 package ld
 
 import (
+	"cmd/internal/objabi"
 	"sort"
-
-	"cmd/internal/obj"
 )
 
 type byTypeStr []typelinkSortKey
@@ -34,7 +33,7 @@ func (ctxt *Link) typelink() {
 	sort.Sort(typelinks)
 
 	tl := ctxt.Syms.Lookup("runtime.typelink", 0)
-	tl.Type = obj.STYPELINK
+	tl.Type = STYPELINK
 	tl.Attr |= AttrReachable | AttrLocal
 	tl.Size = int64(4 * len(typelinks))
 	tl.P = make([]byte, tl.Size)
@@ -44,6 +43,6 @@ func (ctxt *Link) typelink() {
 		r.Sym = s.Type
 		r.Off = int32(i * 4)
 		r.Siz = 4
-		r.Type = obj.R_ADDROFF
+		r.Type = objabi.R_ADDROFF
 	}
 }
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index 925aab6..4b72636 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -13,6 +13,16 @@ import (
 	"time"
 )
 
+var startTime time.Time
+
+// TODO(josharian): delete. See issue 19865.
+func Cputime() float64 {
+	if startTime.IsZero() {
+		startTime = time.Now()
+	}
+	return time.Since(startTime).Seconds()
+}
+
 func cstring(x []byte) string {
 	i := bytes.IndexByte(x, '\x00')
 	if i >= 0 {
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
index a591b06..353f2c7 100644
--- a/src/cmd/link/internal/mips/asm.go
+++ b/src/cmd/link/internal/mips/asm.go
@@ -31,7 +31,7 @@
 package mips
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -54,22 +54,22 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		if r.Siz != 4 {
 			return -1
 		}
 		ld.Thearch.Lput(ld.R_MIPS_32 | uint32(elfsym)<<8)
 
-	case obj.R_ADDRMIPS:
+	case objabi.R_ADDRMIPS:
 		ld.Thearch.Lput(ld.R_MIPS_LO16 | uint32(elfsym)<<8)
 
-	case obj.R_ADDRMIPSU:
+	case objabi.R_ADDRMIPSU:
 		ld.Thearch.Lput(ld.R_MIPS_HI16 | uint32(elfsym)<<8)
 
-	case obj.R_ADDRMIPSTLS:
+	case objabi.R_ADDRMIPSTLS:
 		ld.Thearch.Lput(ld.R_MIPS_TLS_TPREL_LO16 | uint32(elfsym)<<8)
 
-	case obj.R_CALLMIPS, obj.R_JMPMIPS:
+	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
 		ld.Thearch.Lput(ld.R_MIPS_26 | uint32(elfsym)<<8)
 	}
 
@@ -87,11 +87,11 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 func applyrel(r *ld.Reloc, s *ld.Symbol, val *int64, t int64) {
 	o := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
 	switch r.Type {
-	case obj.R_ADDRMIPS, obj.R_ADDRMIPSTLS:
+	case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS:
 		*val = int64(o&0xffff0000 | uint32(t)&0xffff)
-	case obj.R_ADDRMIPSU:
+	case objabi.R_ADDRMIPSU:
 		*val = int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff)
-	case obj.R_CALLMIPS, obj.R_JMPMIPS:
+	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
 		*val = int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000)
 	}
 }
@@ -102,7 +102,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		default:
 			return -1
 
-		case obj.R_ADDRMIPS, obj.R_ADDRMIPSU:
+		case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
 
 			r.Done = 0
 
@@ -114,14 +114,14 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 				rs = rs.Outer
 			}
 
-			if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
 				ld.Errorf(s, "missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
 			applyrel(r, s, val, r.Xadd)
 			return 0
 
-		case obj.R_ADDRMIPSTLS, obj.R_CALLMIPS, obj.R_JMPMIPS:
+		case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS:
 			r.Done = 0
 			r.Xsym = r.Sym
 			r.Xadd = r.Add
@@ -131,20 +131,20 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 
-	case obj.R_ADDRMIPS, obj.R_ADDRMIPSU:
+	case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
 		t := ld.Symaddr(r.Sym) + r.Add
 		applyrel(r, s, val, t)
 		return 0
 
-	case obj.R_CALLMIPS, obj.R_JMPMIPS:
+	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
 		t := ld.Symaddr(r.Sym) + r.Add
 
 		if t&3 != 0 {
@@ -159,7 +159,7 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		applyrel(r, s, val, t)
 		return 0
 
-	case obj.R_ADDRMIPSTLS:
+	case objabi.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 {
@@ -178,24 +178,24 @@ func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
@@ -203,7 +203,7 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -222,21 +222,21 @@ func asmb(ctxt *ld.Link) {
 			ld.Errorf(nil, "unsupported executable format")
 		}
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 		symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 
 		ld.Cseek(int64(symo))
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+			ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 		}
 		ld.Asmelfsym(ctxt)
 		ld.Cflush()
 		ld.Cwrite(ld.Elfstrdat)
 
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+			ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
 		}
 
 		if ld.Linkmode == ld.LinkExternal {
@@ -245,14 +245,14 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
 		ld.Errorf(nil, "unsupported operating system")
-	case obj.Hlinux:
+	case objabi.Hlinux:
 		ld.Asmbelf(ctxt, int64(symo))
 	}
 
diff --git a/src/cmd/link/internal/mips/obj.go b/src/cmd/link/internal/mips/obj.go
index a333876..3ba02b7 100644
--- a/src/cmd/link/internal/mips/obj.go
+++ b/src/cmd/link/internal/mips/obj.go
@@ -31,7 +31,7 @@
 package mips
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -40,7 +40,7 @@ import (
 // Reading object files.
 
 func Init() {
-	if obj.GOARCH == "mipsle" {
+	if objabi.GOARCH == "mipsle" {
 		ld.SysArch = sys.ArchMIPSLE
 	} else {
 		ld.SysArch = sys.ArchMIPS
@@ -90,7 +90,7 @@ func archinit(ctxt *ld.Link) {
 	switch ld.Headtype {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
-	case obj.Hlinux: /* mips elf */
+	case objabi.Hlinux: /* mips elf */
 		ld.Elfinit(ctxt)
 		ld.HEADR = ld.ELFRESERVE
 		if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 1c3216f..3425681 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -31,7 +31,7 @@
 package mips64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -66,7 +66,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		switch r.Siz {
 		case 4:
 			ld.Cput(ld.R_MIPS_32)
@@ -76,17 +76,17 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_ADDRMIPS:
+	case objabi.R_ADDRMIPS:
 		ld.Cput(ld.R_MIPS_LO16)
 
-	case obj.R_ADDRMIPSU:
+	case objabi.R_ADDRMIPSU:
 		ld.Cput(ld.R_MIPS_HI16)
 
-	case obj.R_ADDRMIPSTLS:
+	case objabi.R_ADDRMIPSTLS:
 		ld.Cput(ld.R_MIPS_TLS_TPREL_LO16)
 
-	case obj.R_CALLMIPS,
-		obj.R_JMPMIPS:
+	case objabi.R_CALLMIPS,
+		objabi.R_JMPMIPS:
 		ld.Cput(ld.R_MIPS_26)
 	}
 	ld.Thearch.Vput(uint64(r.Xadd))
@@ -108,8 +108,8 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		default:
 			return -1
 
-		case obj.R_ADDRMIPS,
-			obj.R_ADDRMIPSU:
+		case objabi.R_ADDRMIPS,
+			objabi.R_ADDRMIPSU:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
@@ -120,16 +120,16 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 				rs = rs.Outer
 			}
 
-			if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
 				ld.Errorf(s, "missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
 
 			return 0
 
-		case obj.R_ADDRMIPSTLS,
-			obj.R_CALLMIPS,
-			obj.R_JMPMIPS:
+		case objabi.R_ADDRMIPSTLS,
+			objabi.R_CALLMIPS,
+			objabi.R_JMPMIPS:
 			r.Done = 0
 			r.Xsym = r.Sym
 			r.Xadd = r.Add
@@ -138,26 +138,26 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 
-	case obj.R_ADDRMIPS,
-		obj.R_ADDRMIPSU:
+	case objabi.R_ADDRMIPS,
+		objabi.R_ADDRMIPSU:
 		t := ld.Symaddr(r.Sym) + r.Add
 		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
-		if r.Type == obj.R_ADDRMIPS {
+		if r.Type == objabi.R_ADDRMIPS {
 			*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
 		} else {
 			*val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
 		}
 		return 0
 
-	case obj.R_ADDRMIPSTLS:
+	case objabi.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 {
@@ -167,8 +167,8 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
 		return 0
 
-	case obj.R_CALLMIPS,
-		obj.R_JMPMIPS:
+	case objabi.R_CALLMIPS,
+		objabi.R_JMPMIPS:
 		// Low 26 bits = (S + A) >> 2
 		t := ld.Symaddr(r.Sym) + r.Add
 		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
@@ -185,38 +185,38 @@ func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -233,7 +233,7 @@ func asmb(ctxt *ld.Link) {
 	if !*ld.FlagS {
 		// TODO: rationalize
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
@@ -242,7 +242,7 @@ func asmb(ctxt *ld.Link) {
 				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 		}
 
@@ -251,7 +251,7 @@ func asmb(ctxt *ld.Link) {
 		default:
 			if ld.Iself {
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 				}
 				ld.Asmelfsym(ctxt)
 				ld.Cflush()
@@ -262,7 +262,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -279,12 +279,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		magic := uint32(4*18*18 + 7)
 		if ld.SysArch == sys.ArchMIPS64LE {
 			magic = uint32(4*26*26 + 7)
@@ -298,11 +298,11 @@ func asmb(ctxt *ld.Link) {
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, int64(symo))
 	}
 
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index b79cd9d..1a24a7e 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -31,14 +31,14 @@
 package mips64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 )
 
 func Init() {
-	if obj.GOARCH == "mips64le" {
+	if objabi.GOARCH == "mips64le" {
 		ld.SysArch = sys.ArchMIPS64LE
 	} else {
 		ld.SysArch = sys.ArchMIPS64
@@ -89,7 +89,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if *ld.FlagTextAddr == -1 {
@@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 16 * 1024
 		}
 
-	case obj.Hlinux: /* mips64 elf */
+	case objabi.Hlinux: /* mips64 elf */
 		ld.Elfinit(ctxt)
 		ld.HEADR = ld.ELFRESERVE
 		if *ld.FlagTextAddr == -1 {
@@ -115,7 +115,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index cf2c532..ee4e218 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -31,7 +31,7 @@
 package ppc64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"encoding/binary"
 	"fmt"
@@ -91,7 +91,7 @@ func genplt(ctxt *ld.Link) {
 	for _, s := range ctxt.Textp {
 		for i := range s.R {
 			r := &s.R[i]
-			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT {
+			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
 				continue
 			}
 
@@ -131,12 +131,12 @@ func genplt(ctxt *ld.Link) {
 
 func genaddmoduledata(ctxt *ld.Link) {
 	addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT {
+	if addmoduledata.Type == ld.STEXT {
 		return
 	}
 	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
@@ -147,7 +147,7 @@ func genaddmoduledata(ctxt *ld.Link) {
 	rel.Off = int32(initfunc.Size)
 	rel.Siz = 8
 	rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
-	rel.Type = obj.R_ADDRPOWER_PCREL
+	rel.Type = objabi.R_ADDRPOWER_PCREL
 	o(0x3c4c0000)
 	// addi r2, r2, .TOC.-func at l
 	o(0x38420000)
@@ -160,7 +160,7 @@ func genaddmoduledata(ctxt *ld.Link) {
 	rel.Off = int32(initfunc.Size)
 	rel.Siz = 8
 	rel.Sym = ctxt.Syms.Lookup("local.moduledata", 0)
-	rel.Type = obj.R_ADDRPOWER_GOT
+	rel.Type = objabi.R_ADDRPOWER_GOT
 	o(0x3c620000)
 	// ld r3, local.moduledata at got@l(r3)
 	o(0xe8630000)
@@ -169,7 +169,7 @@ func genaddmoduledata(ctxt *ld.Link) {
 	rel.Off = int32(initfunc.Size)
 	rel.Siz = 4
 	rel.Sym = addmoduledata
-	rel.Type = obj.R_CALLPOWER
+	rel.Type = objabi.R_CALLPOWER
 	o(0x48000001)
 	// nop
 	o(0x60000000)
@@ -186,7 +186,7 @@ func genaddmoduledata(ctxt *ld.Link) {
 	ctxt.Textp = append(ctxt.Textp, initfunc)
 	initarray_entry.Attr |= ld.AttrReachable
 	initarray_entry.Attr |= ld.AttrLocal
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -211,7 +211,7 @@ func gencallstub(ctxt *ld.Link, abicase int, stub *ld.Symbol, targ *ld.Symbol) {
 
 	plt := ctxt.Syms.Lookup(".plt", 0)
 
-	stub.Type = obj.STEXT
+	stub.Type = ld.STEXT
 
 	// Save TOC pointer in TOC save slot
 	ld.Adduint32(ctxt, stub, 0xf8410018) // std r2,24(r1)
@@ -226,7 +226,7 @@ func gencallstub(ctxt *ld.Link, abicase int, stub *ld.Symbol, targ *ld.Symbol) {
 	if ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
-	r.Type = obj.R_POWER_TOC
+	r.Type = objabi.R_POWER_TOC
 	r.Variant = ld.RV_POWER_HA
 	ld.Adduint32(ctxt, stub, 0x3d820000) // addis r12,r2,targ at plt@toc at ha
 	r = ld.Addrel(stub)
@@ -237,7 +237,7 @@ func gencallstub(ctxt *ld.Link, abicase int, stub *ld.Symbol, targ *ld.Symbol) {
 	if ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
-	r.Type = obj.R_POWER_TOC
+	r.Type = objabi.R_POWER_TOC
 	r.Variant = ld.RV_POWER_LO
 	ld.Adduint32(ctxt, stub, 0xe98c0000) // ld r12,targ at plt@toc at l(r12)
 
@@ -258,7 +258,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_PPC64_REL24:
-		r.Type = obj.R_CALLPOWER
+		r.Type = objabi.R_CALLPOWER
 
 		// This is a local call, so the caller isn't setting
 		// up r12 and r2 is the same for the caller and
@@ -267,7 +267,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		// to use r12 to compute r2.)
 		r.Add += int64(r.Sym.Localentry) * 4
 
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			// Should have been handled in elfsetupplt
 			ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
 		}
@@ -275,18 +275,18 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 
 	case 256 + ld.R_PPC_REL32:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += 4
 
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
 		}
 
 		return true
 
 	case 256 + ld.R_PPC64_ADDR64:
-		r.Type = obj.R_ADDR
-		if targ.Type == obj.SDYNIMPORT {
+		r.Type = objabi.R_ADDR
+		if targ.Type == ld.SDYNIMPORT {
 			// These happen in .toc sections
 			ld.Adddynsym(ctxt, targ)
 
@@ -300,56 +300,56 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 
 	case 256 + ld.R_PPC64_TOC16:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
 		return true
 
 	case 256 + ld.R_PPC64_TOC16_LO:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_LO
 		return true
 
 	case 256 + ld.R_PPC64_TOC16_HA:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
 		return true
 
 	case 256 + ld.R_PPC64_TOC16_HI:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
 		return true
 
 	case 256 + ld.R_PPC64_TOC16_DS:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
 		return true
 
 	case 256 + ld.R_PPC64_TOC16_LO_DS:
-		r.Type = obj.R_POWER_TOC
+		r.Type = objabi.R_POWER_TOC
 		r.Variant = ld.RV_POWER_DS
 		return true
 
 	case 256 + ld.R_PPC64_REL16_LO:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_POWER_LO
 		r.Add += 2 // Compensate for relocation size of 2
 		return true
 
 	case 256 + ld.R_PPC64_REL16_HI:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
 		r.Add += 2
 		return true
 
 	case 256 + ld.R_PPC64_REL16_HA:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
 		r.Add += 2
 		return true
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != obj.SDYNIMPORT {
+	if targ.Type != ld.SDYNIMPORT {
 		return true
 	}
 
@@ -366,7 +366,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		switch r.Siz {
 		case 4:
 			ld.Thearch.Vput(ld.R_PPC64_ADDR32 | uint64(elfsym)<<32)
@@ -376,56 +376,56 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_POWER_TLS:
+	case objabi.R_POWER_TLS:
 		ld.Thearch.Vput(ld.R_PPC64_TLS | uint64(elfsym)<<32)
 
-	case obj.R_POWER_TLS_LE:
+	case objabi.R_POWER_TLS_LE:
 		ld.Thearch.Vput(ld.R_PPC64_TPREL16 | uint64(elfsym)<<32)
 
-	case obj.R_POWER_TLS_IE:
+	case objabi.R_POWER_TLS_IE:
 		ld.Thearch.Vput(ld.R_PPC64_GOT_TPREL16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_GOT_TPREL16_LO_DS | uint64(elfsym)<<32)
 
-	case obj.R_ADDRPOWER:
+	case objabi.R_ADDRPOWER:
 		ld.Thearch.Vput(ld.R_PPC64_ADDR16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO | uint64(elfsym)<<32)
 
-	case obj.R_ADDRPOWER_DS:
+	case objabi.R_ADDRPOWER_DS:
 		ld.Thearch.Vput(ld.R_PPC64_ADDR16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO_DS | uint64(elfsym)<<32)
 
-	case obj.R_ADDRPOWER_GOT:
+	case objabi.R_ADDRPOWER_GOT:
 		ld.Thearch.Vput(ld.R_PPC64_GOT16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_GOT16_LO_DS | uint64(elfsym)<<32)
 
-	case obj.R_ADDRPOWER_PCREL:
+	case objabi.R_ADDRPOWER_PCREL:
 		ld.Thearch.Vput(ld.R_PPC64_REL16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_REL16_LO | uint64(elfsym)<<32)
 		r.Xadd += 4
 
-	case obj.R_ADDRPOWER_TOCREL:
+	case objabi.R_ADDRPOWER_TOCREL:
 		ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_TOC16_LO | uint64(elfsym)<<32)
 
-	case obj.R_ADDRPOWER_TOCREL_DS:
+	case objabi.R_ADDRPOWER_TOCREL_DS:
 		ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
 		ld.Thearch.Vput(uint64(r.Xadd))
 		ld.Thearch.Vput(uint64(sectoff + 4))
 		ld.Thearch.Vput(ld.R_PPC64_TOC16_LO_DS | uint64(elfsym)<<32)
 
-	case obj.R_CALLPOWER:
+	case objabi.R_CALLPOWER:
 		if r.Siz != 4 {
 			return -1
 		}
@@ -496,11 +496,11 @@ func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_ADDRPOWER:
+	case objabi.R_ADDRPOWER:
 		o1 |= (uint32(t) >> 16) & 0xffff
 		o2 |= uint32(t) & 0xffff
 
-	case obj.R_ADDRPOWER_DS:
+	case objabi.R_ADDRPOWER_DS:
 		o1 |= (uint32(t) >> 16) & 0xffff
 		if t&3 != 0 {
 			ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
@@ -522,13 +522,22 @@ func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 // resolve direct jump relocation r in s, and add trampoline if necessary
 func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
 
+	// Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
+	// For internal linking, trampolines are always created for long calls.
+	// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
+	// r2.  For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
+	if ld.Linkmode == ld.LinkExternal && (ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE) {
+		// No trampolines needed since r2 contains the TOC
+		return
+	}
+
 	t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
 	switch r.Type {
-	case obj.R_CALLPOWER:
+	case objabi.R_CALLPOWER:
 
 		// If branch offset is too far then create a trampoline.
 
-		if int64(int32(t<<6)>>6) != t || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
+		if (ld.Linkmode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
 			var tramp *ld.Symbol
 			for i := 0; ; i++ {
 
@@ -552,26 +561,20 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
 
 				t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
 
-				// If the offset of the trampoline that has been found is within range, use it.
-				if int64(int32(t<<6)>>6) == t {
+				// With internal linking, the trampoline can be used if it is not too far.
+				// With external linking, the trampoline must be in this section for it to be reused.
+				if (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ld.Linkmode == ld.LinkExternal && s.Sect == tramp.Sect) {
 					break
 				}
 			}
 			if tramp.Type == 0 {
-				ctxt.AddTramp(tramp)
-				tramp.Size = 16 // 4 instructions
-				tramp.P = make([]byte, tramp.Size)
-				t = ld.Symaddr(r.Sym) + r.Add
-				f := t & 0xffff0000
-				o1 := uint32(0x3fe00000 | (f >> 16)) // lis r31,trampaddr hi (r31 is temp reg)
-				f = t & 0xffff
-				o2 := uint32(0x63ff0000 | f) // ori r31,trampaddr lo
-				o3 := uint32(0x7fe903a6)     // mtctr
-				o4 := uint32(0x4e800420)     // bctr
-				ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
-				ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
-				ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
-				ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
+				if ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
+					// Should have returned for above cases
+					ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
+				} else {
+					ctxt.AddTramp(tramp)
+					gentramp(tramp, r.Sym, int64(r.Add))
+				}
 			}
 			r.Sym = tramp
 			r.Add = 0 // This was folded into the trampoline target address
@@ -582,25 +585,61 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
 	}
 }
 
+func gentramp(tramp, target *ld.Symbol, offset int64) {
+	// Used for default build mode for an executable
+	// Address of the call target is generated using
+	// relocation and doesn't depend on r2 (TOC).
+	tramp.Size = 16 // 4 instructions
+	tramp.P = make([]byte, tramp.Size)
+	t := ld.Symaddr(target) + offset
+	o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
+	o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
+	// With external linking, the target address must be
+	// relocated using LO and HA
+	if ld.Linkmode == ld.LinkExternal {
+		tr := ld.Addrel(tramp)
+		tr.Off = 0
+		tr.Type = objabi.R_ADDRPOWER
+		tr.Siz = 8 // generates 2 relocations:  HA + LO
+		tr.Sym = target
+		tr.Add = offset
+	} else {
+		// adjustment needed if lo has sign bit set
+		// when using addi to compute address
+		val := uint32((t & 0xffff0000) >> 16)
+		if t&0x8000 != 0 {
+			val += 1
+		}
+		o1 |= val                // hi part of addr
+		o2 |= uint32(t & 0xffff) // lo part of addr
+	}
+	o3 := uint32(0x7fe903a6) // mtctr r31
+	o4 := uint32(0x4e800420) // bctr
+	ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
+	ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
+	ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
+	ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
+}
+
 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
 		switch r.Type {
 		default:
 			return -1
 
-		case obj.R_POWER_TLS, obj.R_POWER_TLS_LE, obj.R_POWER_TLS_IE:
+		case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
 			r.Done = 0
 			// check Outer is nil, Type is TLSBSS?
 			r.Xadd = r.Add
 			r.Xsym = r.Sym
 			return 0
 
-		case obj.R_ADDRPOWER,
-			obj.R_ADDRPOWER_DS,
-			obj.R_ADDRPOWER_TOCREL,
-			obj.R_ADDRPOWER_TOCREL_DS,
-			obj.R_ADDRPOWER_GOT,
-			obj.R_ADDRPOWER_PCREL:
+		case objabi.R_ADDRPOWER,
+			objabi.R_ADDRPOWER_DS,
+			objabi.R_ADDRPOWER_TOCREL,
+			objabi.R_ADDRPOWER_TOCREL_DS,
+			objabi.R_ADDRPOWER_GOT,
+			objabi.R_ADDRPOWER_PCREL:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
@@ -611,14 +650,14 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 				rs = rs.Outer
 			}
 
-			if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
 				ld.Errorf(s, "missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
 
 			return 0
 
-		case obj.R_CALLPOWER:
+		case objabi.R_CALLPOWER:
 			r.Done = 0
 			r.Xsym = r.Sym
 			r.Xadd = r.Add
@@ -627,18 +666,18 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 
-	case obj.R_ADDRPOWER, obj.R_ADDRPOWER_DS:
+	case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
 		return archrelocaddr(ctxt, r, s, val)
 
-	case obj.R_CALLPOWER:
+	case objabi.R_CALLPOWER:
 		// Bits 6 through 29 = (S + A - P) >> 2
 
 		t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
@@ -654,12 +693,12 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		*val |= int64(uint32(t) &^ 0xfc000003)
 		return 0
 
-	case obj.R_POWER_TOC: // S + A - .TOC.
+	case objabi.R_POWER_TOC: // S + A - .TOC.
 		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s)
 
 		return 0
 
-	case obj.R_POWER_TLS_LE:
+	case objabi.R_POWER_TLS_LE:
 		// The thread pointer points 0x7000 bytes after the start of the the
 		// thread local storage area as documented in section "3.7.2 TLS
 		// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
@@ -790,7 +829,7 @@ func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
 		r.Sym = glink
 		r.Off = int32(glink.Size)
 		r.Siz = 4
-		r.Type = obj.R_CALLPOWER
+		r.Type = objabi.R_CALLPOWER
 		ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
 
 		// In the ppc64 ABI, the dynamic linker is responsible
@@ -845,7 +884,7 @@ func ensureglinkresolver(ctxt *ld.Link) *ld.Symbol {
 	r.Off = int32(glink.Size)
 	r.Sym = ctxt.Syms.Lookup(".plt", 0)
 	r.Siz = 8
-	r.Type = obj.R_ADDRPOWER
+	r.Type = objabi.R_ADDRPOWER
 
 	ld.Adduint32(ctxt, glink, 0x3d600000) // addis r11,0,.plt at ha
 	ld.Adduint32(ctxt, glink, 0x396b0000) // addi r11,r11,.plt at l
@@ -873,14 +912,14 @@ func ensureglinkresolver(ctxt *ld.Link) *ld.Symbol {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	for sect := ld.Segtext.Sect; sect != nil; sect = sect.Next {
+	for _, sect := range ld.Segtext.Sections {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		// Handle additional text sections with Codeblk
 		if sect.Name == ".text" {
@@ -892,21 +931,21 @@ func asmb(ctxt *ld.Link) {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -923,7 +962,7 @@ func asmb(ctxt *ld.Link) {
 	if !*ld.FlagS {
 		// TODO: rationalize
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
@@ -932,7 +971,7 @@ func asmb(ctxt *ld.Link) {
 				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 		}
 
@@ -941,7 +980,7 @@ func asmb(ctxt *ld.Link) {
 		default:
 			if ld.Iself {
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 				}
 				ld.Asmelfsym(ctxt)
 				ld.Cflush()
@@ -952,7 +991,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -969,12 +1008,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.Thearch.Lput(0x647)                      /* magic */
 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
@@ -984,11 +1023,11 @@ func asmb(ctxt *ld.Link) {
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, int64(symo))
 	}
 
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index f7ae33d..c78535b 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -64,7 +64,7 @@ package ppc64
 const (
 	maxAlign  = 32 // max data alignment
 	minAlign  = 1  // min data alignment
-	funcAlign = 8
+	funcAlign = 16
 )
 
 /* 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 6eff2f4..2d11eb5 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -31,14 +31,14 @@
 package ppc64
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 )
 
 func Init() {
-	if obj.GOARCH == "ppc64le" {
+	if objabi.GOARCH == "ppc64le" {
 		ld.SysArch = sys.ArchPPC64LE
 	} else {
 		ld.SysArch = sys.ArchPPC64
@@ -91,7 +91,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if *ld.FlagTextAddr == -1 {
@@ -104,7 +104,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hlinux: /* ppc64 elf */
+	case objabi.Hlinux: /* ppc64 elf */
 		if ld.SysArch == sys.ArchPPC64 {
 			*ld.FlagD = true // TODO(austin): ELF ABI v1 not supported yet
 		}
@@ -120,7 +120,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 4a5f48c..7f120c7 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -31,7 +31,7 @@
 package s390x
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"debug/elf"
 	"fmt"
@@ -52,14 +52,14 @@ func gentext(ctxt *ld.Link) {
 		return
 	}
 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT {
+	if addmoduledata.Type == ld.STEXT && ld.Buildmode != ld.BuildmodePlugin {
 		// we're linking a module containing the runtime -> no need for
 		// an init function
 		return
 	}
 	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 
@@ -70,7 +70,7 @@ func gentext(ctxt *ld.Link) {
 	lmd.Off = int32(initfunc.Size)
 	lmd.Siz = 4
 	lmd.Sym = ctxt.Moduledata
-	lmd.Type = obj.R_PCREL
+	lmd.Type = objabi.R_PCREL
 	lmd.Variant = ld.RV_390_DBL
 	lmd.Add = 2 + int64(lmd.Siz)
 	ld.Adduint32(ctxt, initfunc, 0)
@@ -82,19 +82,21 @@ func gentext(ctxt *ld.Link) {
 	rel.Off = int32(initfunc.Size)
 	rel.Siz = 4
 	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	rel.Type = obj.R_CALL
+	rel.Type = objabi.R_CALL
 	rel.Variant = ld.RV_390_DBL
 	rel.Add = 2 + int64(rel.Siz)
 	ld.Adduint32(ctxt, initfunc, 0)
 
 	// undef (for debugging)
 	ld.Adduint32(ctxt, initfunc, 0)
-
+	if ld.Buildmode == ld.BuildmodePlugin {
+		ctxt.Textp = append(ctxt.Textp, addmoduledata)
+	}
 	ctxt.Textp = append(ctxt.Textp, initfunc)
 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
 	initarray_entry.Attr |= ld.AttrLocal
 	initarray_entry.Attr |= ld.AttrReachable
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -118,22 +120,22 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		256 + ld.R_390_16,
 		256 + ld.R_390_32,
 		256 + ld.R_390_64:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 		return true
 
 	case 256 + ld.R_390_PC16,
 		256 + ld.R_390_PC32,
 		256 + ld.R_390_PC64:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
 		}
-		if targ.Type == 0 || targ.Type == obj.SXREF {
+		if targ.Type == 0 || targ.Type == ld.SXREF {
 			ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
 		}
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += int64(r.Siz)
 		return true
 
@@ -145,10 +147,10 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 	case 256 + ld.R_390_PLT16DBL,
 		256 + ld.R_390_PLT32DBL:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_390_DBL
 		r.Add += int64(r.Siz)
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -157,9 +159,9 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 	case 256 + ld.R_390_PLT32,
 		256 + ld.R_390_PLT64:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += int64(r.Siz)
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -183,30 +185,30 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return false
 
 	case 256 + ld.R_390_GOTOFF:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = obj.R_GOTOFF
+		r.Type = objabi.R_GOTOFF
 		return true
 
 	case 256 + ld.R_390_GOTPC:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(r.Siz)
 		return true
 
 	case 256 + ld.R_390_PC16DBL,
 		256 + ld.R_390_PC32DBL:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_390_DBL
 		r.Add += int64(r.Siz)
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
 		}
 		return true
 
 	case 256 + ld.R_390_GOTPCDBL:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_390_DBL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(r.Siz)
@@ -215,7 +217,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 	case 256 + ld.R_390_GOTENT:
 		addgotsym(ctxt, targ)
 
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Variant = ld.RV_390_DBL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(targ.Got)
@@ -223,7 +225,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 	}
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != obj.SDYNIMPORT {
+	if targ.Type != ld.SDYNIMPORT {
 		return true
 	}
 
@@ -238,7 +240,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_TLS_LE:
+	case objabi.R_TLS_LE:
 		switch r.Siz {
 		default:
 			return -1
@@ -250,7 +252,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			ld.Thearch.Vput(ld.R_390_TLS_LE64 | uint64(elfsym)<<32)
 		}
 
-	case obj.R_TLS_IE:
+	case objabi.R_TLS_IE:
 		switch r.Siz {
 		default:
 			return -1
@@ -258,7 +260,7 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			ld.Thearch.Vput(ld.R_390_TLS_IEENT | uint64(elfsym)<<32)
 		}
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		switch r.Siz {
 		default:
 			return -1
@@ -268,23 +270,23 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			ld.Thearch.Vput(ld.R_390_64 | uint64(elfsym)<<32)
 		}
 
-	case obj.R_GOTPCREL:
+	case objabi.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:
+	case objabi.R_PCREL, objabi.R_PCRELDBL, objabi.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:
+		case objabi.R_PCRELDBL, objabi.R_CALL:
 			isdbl = true
 		}
-		if r.Xsym.Type == obj.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == obj.R_CALL) {
+		if r.Xsym.Type == ld.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == objabi.R_CALL) {
 			if isdbl {
 				switch r.Siz {
 				case 2:
@@ -389,11 +391,11 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 	}
 
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 	}
@@ -503,38 +505,38 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -553,21 +555,21 @@ func asmb(ctxt *ld.Link) {
 			ld.Errorf(nil, "unsupported executable format")
 		}
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 		symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 
 		ld.Cseek(int64(symo))
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+			ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 		}
 		ld.Asmelfsym(ctxt)
 		ld.Cflush()
 		ld.Cwrite(ld.Elfstrdat)
 
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+			ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
 		}
 
 		if ld.Linkmode == ld.LinkExternal {
@@ -576,13 +578,13 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f header\n", obj.Cputime())
+		ctxt.Logf("%5.2f header\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
 		ld.Errorf(nil, "unsupported operating system")
-	case obj.Hlinux:
+	case objabi.Hlinux:
 		ld.Asmbelf(ctxt, int64(symo))
 	}
 
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index eea8978..cd5da6a 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -31,7 +31,7 @@
 package s390x
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -77,7 +77,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hlinux: // s390x ELF
+	case objabi.Hlinux: // s390x ELF
 		ld.Elfinit(ctxt)
 		ld.HEADR = ld.ELFRESERVE
 		if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index af702c2..3649e6a 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -31,7 +31,7 @@
 package x86
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/ld"
 	"log"
 )
@@ -45,7 +45,7 @@ func addcall(ctxt *ld.Link, s *ld.Symbol, t *ld.Symbol) {
 	r := ld.Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
-	r.Type = obj.R_CALL
+	r.Type = objabi.R_CALL
 	r.Siz = 4
 }
 
@@ -81,7 +81,7 @@ func gentext(ctxt *ld.Link) {
 		{"di", 7},
 	} {
 		thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0)
-		thunkfunc.Type = obj.STEXT
+		thunkfunc.Type = ld.STEXT
 		thunkfunc.Attr |= ld.AttrLocal
 		thunkfunc.Attr |= ld.AttrReachable //TODO: remove?
 		o := func(op ...uint8) {
@@ -100,7 +100,7 @@ func gentext(ctxt *ld.Link) {
 	ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
 
 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
-	if addmoduledata.Type == obj.STEXT && ld.Buildmode != ld.BuildmodePlugin {
+	if addmoduledata.Type == ld.STEXT && ld.Buildmode != ld.BuildmodePlugin {
 		// we're linking a module containing the runtime -> no need for
 		// an init function
 		return
@@ -109,7 +109,7 @@ func gentext(ctxt *ld.Link) {
 	addmoduledata.Attr |= ld.AttrReachable
 
 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
-	initfunc.Type = obj.STEXT
+	initfunc.Type = ld.STEXT
 	initfunc.Attr |= ld.AttrLocal
 	initfunc.Attr |= ld.AttrReachable
 	o := func(op ...uint8) {
@@ -142,7 +142,7 @@ func gentext(ctxt *ld.Link) {
 	r := ld.Addrel(initfunc)
 	r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
 	r.Off = int32(i)
-	r.Type = obj.R_PCREL
+	r.Type = objabi.R_PCREL
 	r.Add = 12
 	r.Siz = 4
 
@@ -160,7 +160,7 @@ func gentext(ctxt *ld.Link) {
 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
 	initarray_entry.Attr |= ld.AttrReachable
 	initarray_entry.Attr |= ld.AttrLocal
-	initarray_entry.Type = obj.SINITARR
+	initarray_entry.Type = ld.SINITARR
 	ld.Addaddr(ctxt, initarray_entry, initfunc)
 }
 
@@ -176,20 +176,20 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_386_PC32:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
 		}
-		if targ.Type == 0 || targ.Type == obj.SXREF {
+		if targ.Type == 0 || targ.Type == ld.SXREF {
 			ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
 		}
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += 4
 		return true
 
 	case 256 + ld.R_386_PLT32:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Add += 4
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -198,13 +198,13 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		return true
 
 	case 256 + ld.R_386_GOT32, 256 + ld.R_386_GOT32X:
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			// have symbol
 			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
 				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
 				s.P[r.Off-2] = 0x8d
 
-				r.Type = obj.R_GOTOFF
+				r.Type = objabi.R_GOTOFF
 				return true
 			}
 
@@ -214,7 +214,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 				s.P[r.Off-2] = 0x36
 
 				s.P[r.Off-1] = 0x68
-				r.Type = obj.R_ADDR
+				r.Type = objabi.R_ADDR
 				return true
 			}
 
@@ -223,49 +223,49 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 		}
 
 		addgotsym(ctxt, targ)
-		r.Type = obj.R_CONST // write r->add during relocsym
+		r.Type = objabi.R_CONST // write r->add during relocsym
 		r.Sym = nil
 		r.Add += int64(targ.Got)
 		return true
 
 	case 256 + ld.R_386_GOTOFF:
-		r.Type = obj.R_GOTOFF
+		r.Type = objabi.R_GOTOFF
 		return true
 
 	case 256 + ld.R_386_GOTPC:
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += 4
 		return true
 
 	case 256 + ld.R_386_32:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = obj.R_ADDR
+		r.Type = objabi.R_ADDR
 		return true
 
 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
-		r.Type = obj.R_ADDR
-		if targ.Type == obj.SDYNIMPORT {
+		r.Type = objabi.R_ADDR
+		if targ.Type == ld.SDYNIMPORT {
 			ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
 		}
 		return true
 
 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
-		if targ.Type == obj.SDYNIMPORT {
+		if targ.Type == ld.SDYNIMPORT {
 			addpltsym(ctxt, targ)
 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
 			r.Add = int64(targ.Plt)
-			r.Type = obj.R_PCREL
+			r.Type = objabi.R_PCREL
 			return true
 		}
 
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		return true
 
 	case 512 + ld.MACHO_FAKE_GOTPCREL:
-		if targ.Type != obj.SDYNIMPORT {
+		if targ.Type != ld.SDYNIMPORT {
 			// have symbol
 			// turn MOVL of GOT entry into LEAL of symbol itself
 			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
@@ -274,31 +274,31 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			}
 
 			s.P[r.Off-2] = 0x8d
-			r.Type = obj.R_PCREL
+			r.Type = objabi.R_PCREL
 			return true
 		}
 
 		addgotsym(ctxt, targ)
 		r.Sym = ctxt.Syms.Lookup(".got", 0)
 		r.Add += int64(targ.Got)
-		r.Type = obj.R_PCREL
+		r.Type = objabi.R_PCREL
 		return true
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != obj.SDYNIMPORT {
+	if targ.Type != ld.SDYNIMPORT {
 		return true
 	}
 	switch r.Type {
-	case obj.R_CALL,
-		obj.R_PCREL:
+	case objabi.R_CALL,
+		objabi.R_PCREL:
 		addpltsym(ctxt, targ)
 		r.Sym = ctxt.Syms.Lookup(".plt", 0)
 		r.Add = int64(targ.Plt)
 		return true
 
-	case obj.R_ADDR:
-		if s.Type != obj.SDATA {
+	case objabi.R_ADDR:
+		if s.Type != ld.SDATA {
 			break
 		}
 		if ld.Iself {
@@ -306,12 +306,12 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			rel := ctxt.Syms.Lookup(".rel", 0)
 			ld.Addaddrplus(ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
-			r.Type = obj.R_CONST // write r->add during relocsym
+			r.Type = objabi.R_CONST // write r->add during relocsym
 			r.Sym = nil
 			return true
 		}
 
-		if ld.Headtype == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
+		if ld.Headtype == objabi.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.
@@ -325,7 +325,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			ld.Adddynsym(ctxt, targ)
 
 			got := ctxt.Syms.Lookup(".got", 0)
-			s.Type = got.Type | obj.SSUB
+			s.Type = got.Type | ld.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
 			got.Sub = s
@@ -336,7 +336,7 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
 			return true
 		}
 
-		if (ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui) && s.Size == int64(ld.SysArch.PtrSize) {
+		if ld.Headtype == objabi.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return true
 		}
@@ -353,14 +353,14 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case obj.R_GOTPCREL:
+	case objabi.R_GOTPCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_GOTPC)
 			if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
@@ -371,9 +371,9 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_CALL:
+	case objabi.R_CALL:
 		if r.Siz == 4 {
-			if r.Xsym.Type == obj.SDYNIMPORT {
+			if r.Xsym.Type == ld.SDYNIMPORT {
 				ld.Thearch.Lput(ld.R_386_PLT32 | uint32(elfsym)<<8)
 			} else {
 				ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
@@ -382,21 +382,21 @@ func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
 			return -1
 		}
 
-	case obj.R_PCREL:
+	case objabi.R_PCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case obj.R_TLS_LE:
+	case objabi.R_TLS_LE:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case obj.R_TLS_IE:
+	case objabi.R_TLS_IE:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_GOTPC)
 			ld.Thearch.Lput(uint32(sectoff))
@@ -414,7 +414,7 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 
 	rs := r.Xsym
 
-	if rs.Type == obj.SHOSTOBJ {
+	if rs.Type == ld.SHOSTOBJ {
 		if rs.Dynid < 0 {
 			ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -434,11 +434,11 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
 	default:
 		return -1
 
-	case obj.R_ADDR:
+	case objabi.R_ADDR:
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 
-	case obj.R_CALL,
-		obj.R_PCREL:
+	case objabi.R_CALL,
+		objabi.R_PCREL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 	}
@@ -482,11 +482,14 @@ func pereloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) bool {
 	default:
 		return false
 
-	case obj.R_ADDR:
+	case objabi.R_DWARFREF:
+		v = ld.IMAGE_REL_I386_SECREL
+
+	case objabi.R_ADDR:
 		v = ld.IMAGE_REL_I386_DIR32
 
-	case obj.R_CALL,
-		obj.R_PCREL:
+	case objabi.R_CALL,
+		objabi.R_PCREL:
 		v = ld.IMAGE_REL_I386_REL32
 	}
 
@@ -500,11 +503,11 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
 		return -1
 	}
 	switch r.Type {
-	case obj.R_CONST:
+	case objabi.R_CONST:
 		*val = r.Add
 		return 0
 
-	case obj.R_GOTOFF:
+	case objabi.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
 		return 0
 	}
@@ -584,7 +587,7 @@ func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
 
 		s.Plt = int32(plt.Size - 16)
-	} else if ld.Headtype == obj.Hdarwin {
+	} else if ld.Headtype == objabi.Hdarwin {
 		// Same laziness as in 6l.
 
 		plt := ctxt.Syms.Lookup(".plt", 0)
@@ -618,7 +621,7 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 		rel := ctxt.Syms.Lookup(".rel", 0)
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
-	} else if ld.Headtype == obj.Hdarwin {
+	} else if ld.Headtype == objabi.Hdarwin {
 		ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(s.Dynid))
 	} else {
 		ld.Errorf(s, "addgotsym: unsupported binary format")
@@ -627,25 +630,25 @@ func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
 
 func asmb(ctxt *ld.Link) {
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
 	}
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
 	}
 
-	sect := ld.Segtext.Sect
+	sect := ld.Segtext.Sections[0]
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	// 0xCC is INT $3 - breakpoint instruction
 	ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
-	for sect = sect.Next; sect != nil; sect = sect.Next {
+	for _, sect = range ld.Segtext.Sections[1:] {
 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
 	}
 
 	if ld.Segrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
 		}
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
@@ -653,14 +656,14 @@ func asmb(ctxt *ld.Link) {
 	}
 	if ld.Segrelrodata.Filelen > 0 {
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
+			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
 		}
 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
 	}
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
@@ -670,7 +673,7 @@ func asmb(ctxt *ld.Link) {
 	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
 
 	machlink := uint32(0)
-	if ld.Headtype == obj.Hdarwin {
+	if ld.Headtype == objabi.Hdarwin {
 		machlink = uint32(ld.Domacholink(ctxt))
 	}
 
@@ -681,7 +684,7 @@ func asmb(ctxt *ld.Link) {
 	if !*ld.FlagS {
 		// TODO: rationalize
 		if ctxt.Debugvlog != 0 {
-			ctxt.Logf("%5.2f sym\n", obj.Cputime())
+			ctxt.Logf("%5.2f sym\n", ld.Cputime())
 		}
 		switch ld.Headtype {
 		default:
@@ -690,13 +693,13 @@ func asmb(ctxt *ld.Link) {
 				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
 
-		case obj.Hwindows, obj.Hwindowsgui:
+		case objabi.Hwindows:
 			symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
 		}
@@ -706,7 +709,7 @@ func asmb(ctxt *ld.Link) {
 		default:
 			if ld.Iself {
 				if ctxt.Debugvlog != 0 {
-					ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
+					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
 				}
 				ld.Asmelfsym(ctxt)
 				ld.Cflush()
@@ -717,7 +720,7 @@ func asmb(ctxt *ld.Link) {
 				}
 			}
 
-		case obj.Hplan9:
+		case objabi.Hplan9:
 			ld.Asmplan9sym(ctxt)
 			ld.Cflush()
 
@@ -731,12 +734,12 @@ func asmb(ctxt *ld.Link) {
 				ld.Cflush()
 			}
 
-		case obj.Hwindows, obj.Hwindowsgui:
+		case objabi.Hwindows:
 			if ctxt.Debugvlog != 0 {
-				ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+				ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
 			}
 
-		case obj.Hdarwin:
+		case objabi.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc(ctxt)
 			}
@@ -744,12 +747,12 @@ func asmb(ctxt *ld.Link) {
 	}
 
 	if ctxt.Debugvlog != 0 {
-		ctxt.Logf("%5.2f headr\n", obj.Cputime())
+		ctxt.Logf("%5.2f headr\n", ld.Cputime())
 	}
 	ld.Cseek(0)
 	switch ld.Headtype {
 	default:
-	case obj.Hplan9: /* plan9 */
+	case objabi.Hplan9: /* plan9 */
 		magic := int32(4*11*11 + 7)
 
 		ld.Lputb(uint32(magic))              /* magic */
@@ -761,17 +764,17 @@ func asmb(ctxt *ld.Link) {
 		ld.Lputb(uint32(ld.Spsize))           /* sp offsets */
 		ld.Lputb(uint32(ld.Lcsize))           /* line offsets */
 
-	case obj.Hdarwin:
+	case objabi.Hdarwin:
 		ld.Asmbmacho(ctxt)
 
-	case obj.Hlinux,
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd,
-		obj.Hnacl:
+	case objabi.Hlinux,
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd,
+		objabi.Hnacl:
 		ld.Asmbelf(ctxt, int64(symo))
 
-	case obj.Hwindows, obj.Hwindowsgui:
+	case objabi.Hwindows:
 		ld.Asmbpe(ctxt)
 	}
 
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index ea213be..fa925d1 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -31,7 +31,7 @@
 package x86
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
@@ -75,7 +75,7 @@ func archinit(ctxt *ld.Link) {
 	default:
 		ld.Exitf("unknown -H option: %v", ld.Headtype)
 
-	case obj.Hplan9: /* plan 9 */
+	case objabi.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if *ld.FlagTextAddr == -1 {
@@ -88,7 +88,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hdarwin: /* apple MACH */
+	case objabi.Hdarwin: /* apple MACH */
 		ld.Machoinit()
 
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -102,10 +102,10 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hlinux, /* elf32 executable */
-		obj.Hfreebsd,
-		obj.Hnetbsd,
-		obj.Hopenbsd:
+	case objabi.Hlinux, /* elf32 executable */
+		objabi.Hfreebsd,
+		objabi.Hnetbsd,
+		objabi.Hopenbsd:
 		ld.Elfinit(ctxt)
 
 		ld.HEADR = ld.ELFRESERVE
@@ -119,7 +119,7 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 4096
 		}
 
-	case obj.Hnacl:
+	case objabi.Hnacl:
 		ld.Elfinit(ctxt)
 		ld.HEADR = 0x10000
 		ld.Funcalign = 32
@@ -133,19 +133,9 @@ func archinit(ctxt *ld.Link) {
 			*ld.FlagRound = 0x10000
 		}
 
-	case obj.Hwindows, obj.Hwindowsgui: /* PE executable */
-		ld.Peinit(ctxt)
-
-		ld.HEADR = ld.PEFILEHEADR
-		if *ld.FlagTextAddr == -1 {
-			*ld.FlagTextAddr = ld.PEBASE + int64(ld.PESECTHEADR)
-		}
-		if *ld.FlagDataAddr == -1 {
-			*ld.FlagDataAddr = 0
-		}
-		if *ld.FlagRound == -1 {
-			*ld.FlagRound = ld.PESECTALIGN
-		}
+	case objabi.Hwindows: /* PE executable */
+		// ld.HEADR, ld.FlagTextAddr, ld.FlagDataAddr and ld.FlagRound are set in ld.Peinit
+		return
 	}
 
 	if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
diff --git a/src/cmd/link/linkbig_test.go b/src/cmd/link/linkbig_test.go
index 960d89f..21208e8 100644
--- a/src/cmd/link/linkbig_test.go
+++ b/src/cmd/link/linkbig_test.go
@@ -10,7 +10,7 @@ package main
 
 import (
 	"bytes"
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"fmt"
 	"internal/testenv"
 	"io/ioutil"
@@ -20,8 +20,8 @@ import (
 )
 
 func TestLargeText(t *testing.T) {
-	if testing.Short() || (obj.GOARCH != "ppc64le" && obj.GOARCH != "ppc64" && obj.GOARCH != "arm") {
-		t.Skipf("Skipping large text section test in short mode or on %s", obj.GOARCH)
+	if testing.Short() || (objabi.GOARCH != "ppc64le" && objabi.GOARCH != "ppc64" && objabi.GOARCH != "arm") {
+		t.Skipf("Skipping large text section test in short mode or on %s", objabi.GOARCH)
 	}
 	testenv.MustHaveGoBuild(t)
 
@@ -41,7 +41,7 @@ func TestLargeText(t *testing.T) {
 		"ppc64le": "\tMOVD\tR0,R3\n",
 		"arm":     "\tMOVW\tR0,R1\n",
 	}
-	inst := instOnArch[obj.GOARCH]
+	inst := instOnArch[objabi.GOARCH]
 	for j := 0; j < FN; j++ {
 		testname := fmt.Sprintf("bigfn%d", j)
 		fmt.Fprintf(&w, "TEXT ·%s(SB),$0\n", testname)
diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go
index a9aeb1e..eab190d 100644
--- a/src/cmd/link/main.go
+++ b/src/cmd/link/main.go
@@ -5,7 +5,7 @@
 package main
 
 import (
-	"cmd/internal/obj"
+	"cmd/internal/objabi"
 	"cmd/link/internal/amd64"
 	"cmd/link/internal/arm"
 	"cmd/link/internal/arm64"
@@ -34,9 +34,9 @@ import (
 // via the ld.Thearch.Archinit function.
 
 func main() {
-	switch obj.GOARCH {
+	switch objabi.GOARCH {
 	default:
-		fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.GOARCH)
+		fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", objabi.GOARCH)
 		os.Exit(2)
 	case "386":
 		x86.Init()
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
index 4384af8..2e2dd75 100644
--- a/src/cmd/nm/nm.go
+++ b/src/cmd/nm/nm.go
@@ -15,8 +15,21 @@ import (
 	"cmd/internal/objfile"
 )
 
+const helpText = `usage: go tool nm [options] file...
+  -n
+      an alias for -sort address (numeric),
+      for compatibility with other nm commands
+  -size
+      print symbol size in decimal between address and type
+  -sort {address,name,none,size}
+      sort output in the given order (default name)
+      size orders from largest to smallest
+  -type
+      print symbol type after name
+`
+
 func usage() {
-	fmt.Fprintf(os.Stderr, "usage: go tool nm [-n] [-size] [-sort order] [-type] file...\n")
+	fmt.Fprintf(os.Stderr, helpText)
 	os.Exit(2)
 }
 
diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go
new file mode 100644
index 0000000..de16f77
--- /dev/null
+++ b/src/cmd/nm/nm_cgo_test.go
@@ -0,0 +1,36 @@
+// Copyright 2017 The Go Authors. 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
+
+package main
+
+import (
+	"runtime"
+	"testing"
+)
+
+func TestInternalLinkerCgoFile(t *testing.T) {
+	if !canInternalLink() {
+		t.Skip("skipping; internal linking is not supported")
+	}
+	testGoFile(t, true, false)
+}
+
+func canInternalLink() bool {
+	switch runtime.GOOS {
+	case "dragonfly":
+		return false
+	case "linux":
+		switch runtime.GOARCH {
+		case "arm64", "mips64", "mips64le", "mips", "mipsle":
+			return false
+		}
+	}
+	return true
+}
+
+func TestExternalLinkerCgoFile(t *testing.T) {
+	testGoFile(t, true, true)
+}
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index ed1ad0d..170d87a 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -16,60 +16,45 @@ import (
 	"runtime"
 	"strings"
 	"testing"
+	"text/template"
 )
 
-var testData uint32
+var testnmpath string // path to nm command created for testing purposes
 
-func checkSymbols(t *testing.T, nmoutput []byte) {
-	var checkSymbolsFound, testDataFound bool
-	scanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))
-	for scanner.Scan() {
-		f := strings.Fields(scanner.Text())
-		if len(f) < 3 {
-			continue
-		}
-		switch f[2] {
-		case "cmd/nm.checkSymbols":
-			checkSymbolsFound = true
-			addr := "0x" + f[0]
-			if addr != fmt.Sprintf("%p", checkSymbols) {
-				t.Errorf("nm shows wrong address %v for checkSymbols (%p)", addr, checkSymbols)
-			}
-		case "cmd/nm.testData":
-			testDataFound = true
-			addr := "0x" + f[0]
-			if addr != fmt.Sprintf("%p", &testData) {
-				t.Errorf("nm shows wrong address %v for testData (%p)", addr, &testData)
-			}
-		}
-	}
-	if err := scanner.Err(); err != nil {
-		t.Errorf("error while reading symbols: %v", err)
-		return
-	}
-	if !checkSymbolsFound {
-		t.Error("nm shows no checkSymbols symbol")
-	}
-	if !testDataFound {
-		t.Error("nm shows no testData symbol")
-	}
+// The TestMain function creates a nm command for testing purposes and
+// deletes it after the tests have been run.
+func TestMain(m *testing.M) {
+	os.Exit(testMain(m))
 }
 
-func TestNM(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+func testMain(m *testing.M) int {
+	if !testenv.HasGoBuild() {
+		return 0
+	}
 
 	tmpDir, err := ioutil.TempDir("", "TestNM")
 	if err != nil {
-		t.Fatal("TempDir failed: ", err)
+		fmt.Println("TempDir failed:", err)
+		return 2
 	}
 	defer os.RemoveAll(tmpDir)
 
-	testnmpath := filepath.Join(tmpDir, "testnm.exe")
-	out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
+	testnmpath = filepath.Join(tmpDir, "testnm.exe")
+	gotool, err := testenv.GoTool()
+	if err != nil {
+		fmt.Println("GoTool failed:", err)
+		return 2
+	}
+	out, err := exec.Command(gotool, "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
 	if err != nil {
-		t.Fatalf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
+		fmt.Printf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
+		return 2
 	}
 
+	return m.Run()
+}
+
+func TestNonGoFiles(t *testing.T) {
 	testfiles := []string{
 		"elf/testdata/gcc-386-freebsd-exec",
 		"elf/testdata/gcc-amd64-linux-exec",
@@ -88,11 +73,109 @@ func TestNM(t *testing.T) {
 			t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out))
 		}
 	}
+}
+
+func testGoFile(t *testing.T, iscgo, isexternallinker bool) {
+	tmpdir, err := ioutil.TempDir("", "TestGoFile")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	src := filepath.Join(tmpdir, "a.go")
+	file, err := os.Create(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = template.Must(template.New("main").Parse(testprog)).Execute(file, iscgo)
+	if err != nil {
+		file.Close()
+		t.Fatal(err)
+	}
+	file.Close()
+
+	exe := filepath.Join(tmpdir, "a.exe")
+	args := []string{"build", "-o", exe}
+	if iscgo {
+		linkmode := "internal"
+		if isexternallinker {
+			linkmode = "external"
+		}
+		args = append(args, "-ldflags", "-linkmode="+linkmode)
+	}
+	args = append(args, src)
+	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
+	if err != nil {
+		t.Fatalf("building test executable failed: %s %s", err, out)
+	}
+
+	out, err = exec.Command(exe).CombinedOutput()
+	if err != nil {
+		t.Fatalf("running test executable failed: %s %s", err, out)
+	}
+	names := make(map[string]string)
+	for _, line := range strings.Split(string(out), "\n") {
+		if line == "" {
+			continue
+		}
+		f := strings.Split(line, "=")
+		if len(f) != 2 {
+			t.Fatalf("unexpected output line: %q", line)
+		}
+		names["main."+f[0]] = f[1]
+	}
 
-	cmd := exec.Command(testnmpath, os.Args[0])
-	out, err = cmd.CombinedOutput()
+	out, err = exec.Command(testnmpath, exe).CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool nm: %v\n%s", err, string(out))
+	}
+	scanner := bufio.NewScanner(bytes.NewBuffer(out))
+	dups := make(map[string]bool)
+	for scanner.Scan() {
+		f := strings.Fields(scanner.Text())
+		if len(f) < 3 {
+			continue
+		}
+		name := f[2]
+		if addr, found := names[name]; found {
+			if want, have := addr, "0x"+f[0]; have != want {
+				t.Errorf("want %s address for %s symbol, but have %s", want, name, have)
+			}
+			delete(names, name)
+		}
+		if _, found := dups[name]; found {
+			t.Errorf("duplicate name of %q is found", name)
+		}
+	}
+	err = scanner.Err()
 	if err != nil {
-		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
+		t.Fatalf("error reading nm output: %v", err)
 	}
-	checkSymbols(t, out)
+	if len(names) > 0 {
+		t.Errorf("executable is missing %v symbols", names)
+	}
+}
+
+func TestGoFile(t *testing.T) {
+	testGoFile(t, false, false)
+}
+
+const testprog = `
+package main
+
+import "fmt"
+{{if .}}import "C"
+{{end}}
+
+func main() {
+	testfunc()
+}
+
+var testdata uint32
+
+func testfunc() {
+	fmt.Printf("main=%p\n", main)
+	fmt.Printf("testfunc=%p\n", testfunc)
+	fmt.Printf("testdata=%p\n", &testdata)
 }
+`
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
index 8bf9e4e..7163699 100644
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -43,18 +43,16 @@ import (
 	"cmd/internal/objfile"
 )
 
+var printCode = flag.Bool("S", false, "print go code alongside assembly")
 var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
 var symRE *regexp.Regexp
 
 func usage() {
-	fmt.Fprintf(os.Stderr, "usage: go tool objdump [-s symregexp] binary [start end]\n\n")
+	fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-s symregexp] binary [start end]\n\n")
 	flag.PrintDefaults()
 	os.Exit(2)
 }
 
-type lookupFunc func(addr uint64) (sym string, base uint64)
-type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int)
-
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("objdump: ")
@@ -88,7 +86,7 @@ func main() {
 		usage()
 	case 1:
 		// disassembly of entire object
-		dis.Print(os.Stdout, symRE, 0, ^uint64(0))
+		dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode)
 		os.Exit(0)
 
 	case 3:
@@ -101,7 +99,7 @@ func main() {
 		if err != nil {
 			log.Fatalf("invalid end PC: %v", err)
 		}
-		dis.Print(os.Stdout, symRE, start, end)
+		dis.Print(os.Stdout, symRE, start, end, *printCode)
 		os.Exit(0)
 	}
 }
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 10fc716..47e51df 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -57,26 +57,20 @@ func buildObjdump() error {
 }
 
 var x86Need = []string{
-	"fmthello.go:6",
-	"TEXT main.main(SB)",
 	"JMP main.main(SB)",
-	"CALL fmt.Println(SB)",
+	"CALL main.Println(SB)",
 	"RET",
 }
 
 var armNeed = []string{
-	"fmthello.go:6",
-	"TEXT main.main(SB)",
 	//"B.LS main.main(SB)", // TODO(rsc): restore; golang.org/issue/9021
-	"BL fmt.Println(SB)",
+	"BL main.Println(SB)",
 	"RET",
 }
 
 var ppcNeed = []string{
-	"fmthello.go:6",
-	"TEXT main.main(SB)",
 	"BR main.main(SB)",
-	"CALL fmt.Println(SB)",
+	"CALL main.Println(SB)",
 	"RET",
 }
 
@@ -91,7 +85,7 @@ var target = flag.String("target", "", "test disassembly of `goos/goarch` binary
 // binary for the current system (only) and test that objdump
 // can handle that one.
 
-func testDisasm(t *testing.T, flags ...string) {
+func testDisasm(t *testing.T, printCode bool, flags ...string) {
 	goarch := runtime.GOARCH
 	if *target != "" {
 		f := strings.Split(*target, "/")
@@ -114,9 +108,15 @@ func testDisasm(t *testing.T, flags ...string) {
 		t.Fatalf("go build fmthello.go: %v\n%s", err, out)
 	}
 	need := []string{
-		"fmthello.go:6",
 		"TEXT main.main(SB)",
 	}
+
+	if printCode {
+		need = append(need, `	Println("hello, world")`)
+	} else {
+		need = append(need, "fmthello.go:6")
+	}
+
 	switch goarch {
 	case "amd64", "386":
 		need = append(need, x86Need...)
@@ -126,7 +126,16 @@ func testDisasm(t *testing.T, flags ...string) {
 		need = append(need, ppcNeed...)
 	}
 
-	out, err = exec.Command(exe, "-s", "main.main", hello).CombinedOutput()
+	args = []string{
+		"-s", "main.main",
+		hello,
+	}
+
+	if printCode {
+		args = append([]string{"-S"}, args...)
+	}
+
+	out, err = exec.Command(exe, args...).CombinedOutput()
 	if err != nil {
 		t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
 	}
@@ -153,7 +162,19 @@ func TestDisasm(t *testing.T) {
 	case "s390x":
 		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
 	}
-	testDisasm(t)
+	testDisasm(t, false)
+}
+
+func TestDisasmCode(t *testing.T) {
+	switch runtime.GOARCH {
+	case "arm64":
+		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
+	case "mips", "mipsle", "mips64", "mips64le":
+		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+	case "s390x":
+		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
+	}
+	testDisasm(t, true)
 }
 
 func TestDisasmExtld(t *testing.T) {
@@ -178,5 +199,52 @@ func TestDisasmExtld(t *testing.T) {
 	if !build.Default.CgoEnabled {
 		t.Skip("skipping because cgo is not enabled")
 	}
-	testDisasm(t, "-ldflags=-linkmode=external")
+	testDisasm(t, false, "-ldflags=-linkmode=external")
+}
+
+func TestDisasmGoobj(t *testing.T) {
+	switch runtime.GOARCH {
+	case "arm":
+		t.Skipf("skipping on %s, issue 19811", runtime.GOARCH)
+	case "arm64":
+		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
+	case "mips", "mipsle", "mips64", "mips64le":
+		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+	case "s390x":
+		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
+	}
+
+	hello := filepath.Join(tmp, "hello.o")
+	args := []string{"tool", "compile", "-o", hello}
+	args = append(args, "testdata/fmthello.go")
+	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
+	}
+	need := []string{
+		"main(SB)",
+		"fmthello.go:6",
+	}
+
+	args = []string{
+		"-s", "main",
+		hello,
+	}
+
+	out, err = exec.Command(exe, args...).CombinedOutput()
+	if err != nil {
+		t.Fatalf("objdump fmthello.o: %v\n%s", err, out)
+	}
+
+	text := string(out)
+	ok := true
+	for _, s := range need {
+		if !strings.Contains(text, s) {
+			t.Errorf("disassembly missing '%s'", s)
+			ok = false
+		}
+	}
+	if !ok {
+		t.Logf("full disassembly:\n%s", text)
+	}
 }
diff --git a/src/cmd/objdump/testdata/fmthello.go b/src/cmd/objdump/testdata/fmthello.go
index 635db7a..e982681 100644
--- a/src/cmd/objdump/testdata/fmthello.go
+++ b/src/cmd/objdump/testdata/fmthello.go
@@ -3,5 +3,10 @@ package main
 import "fmt"
 
 func main() {
-	fmt.Println("hello, world")
+	Println("hello, world")
+}
+
+//go:noinline
+func Println(s string) {
+	fmt.Println(s)
 }
diff --git a/src/cmd/pprof/README b/src/cmd/pprof/README
index a728ef2..612dc64 100644
--- a/src/cmd/pprof/README
+++ b/src/cmd/pprof/README
@@ -1,8 +1,18 @@
-The pprof in this directory is adapted from the pprof used inside Google
-for C++, Java, and Go programs. Because it was developed for that broader
-context, it is overgeneralized when used here for the specific use case
-of profiling standard Go programs. However, we've left the abstractions
-intact in order to share updates between this copy and Google's internal one.
+This directory is the copy of Google's pprof shipped as part of the Go distribution.
+The bulk of the code is vendored from github.com/google/pprof and is in
+../vendor/github.com/google/pprof.
 
+Two important notes:
+
+1. Using github.com/google/pprof directly (for example, after installing
+with "go get") should work with Go programs, but we cannot guarantee that.
+What we test is that the "go tool pprof" shipped with each Go release works
+with programs from that release.
+
+2. Pprof is used inside Google for C++, Java, and Go programs.
+Because it was developed for that broader context, it is overgeneralized
+when used here for the specific use case of profiling standard Go programs.
+However, we've left the abstractions intact in order to share updates
+between our vendored copy and Google's internal one.
 Please do not take the level of abstraction in this program as an example
 to follow in your own.
diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go
deleted file mode 100644
index 9669cb9..0000000
--- a/src/cmd/pprof/internal/commands/commands.go
+++ /dev/null
@@ -1,235 +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"
-	"strings"
-	"time"
-
-	"cmd/internal/browser"
-	"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(interactive, "callgraph.out"), false, "Outputs a graph in callgrind format"},
-		"proto":     {c, report.Proto, awayFromTTY(interactive, "pb.gz"), false, "Outputs the profile in compressed protobuf format"},
-
-		// Generate report in DOT format and postprocess with dot
-		"gif": {c, report.Dot, invokeDot(interactive, "gif"), false, "Outputs a graph image in GIF format"},
-		"pdf": {c, report.Dot, invokeDot(interactive, "pdf"), false, "Outputs a graph in PDF format"},
-		"png": {c, report.Dot, invokeDot(interactive, "png"), false, "Outputs a graph image in PNG format"},
-		"ps":  {c, report.Dot, invokeDot(interactive, "ps"), false, "Outputs a graph in PS format"},
-
-		// Save SVG output into a file after including svgpan library
-		"svg": {c, report.Dot, saveSVGToFile(interactive), false, "Outputs a graph in SVG format"},
-
-		// Visualize postprocessed dot output
-		"eog":    {c, report.Dot, invokeVisualizer(interactive, invokeDot(nil, "svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
-		"evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot(nil, "pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
-		"gv":     {c, report.Dot, invokeVisualizer(interactive, invokeDot(nil, "ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
-		"web":    {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(nil), "svg", browsers()), false, "Visualize graph through web browser"},
-
-		// Visualize HTML directly generated by report.
-		"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY(nil, "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
-	for _, cmd := range browser.Commands() {
-		cmds = append(cmds, strings.Join(cmd, " "))
-	}
-	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(interactive **bool, format string) PostProcessor {
-	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
-		if output == os.Stdout && (ui.IsTerminal() || interactive != nil && **interactive) {
-			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(interactive **bool, format string) PostProcessor {
-	divert := awayFromTTY(interactive, 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(interactive **bool) PostProcessor {
-	generateSVG := invokeDot(nil, "svg")
-	divert := awayFromTTY(interactive, "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/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go
deleted file mode 100644
index 0f1ed6e..0000000
--- a/src/cmd/pprof/internal/driver/driver.go
+++ /dev/null
@@ -1,1042 +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/report"
-	"cmd/pprof/internal/tempfile"
-	"internal/pprof/profile"
-)
-
-// cpuProfileHandler is the Go pprof CPU profile handler URL.
-const cpuProfileHandler = "/debug/pprof/profile"
-
-// 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 = cpuProfileHandler
-	case "/protoz":
-		// Rewrite to /profilez?type=proto
-		url.Path = cpuProfileHandler
-		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")
-	flagCallgrind := f.isFormat("callgrind")
-
-	if flagDis || flagWebList || flagCallgrind {
-		// 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, "delay", "-total_delay", err)
-	si, err = sampleIndex(p, &f.flagMeanDelay, si, "delay", "-mean_delay", err)
-	si, err = sampleIndex(p, &f.flagContentions, si, "contentions", "-contentions", err)
-
-	si, err = sampleIndex(p, &f.flagInUseSpace, si, "inuse_space", "-inuse_space", err)
-	si, err = sampleIndex(p, &f.flagInUseObjects, si, "inuse_objects", "-inuse_objects", err)
-	si, err = sampleIndex(p, &f.flagAllocSpace, si, "alloc_space", "-alloc_space", err)
-	si, err = sampleIndex(p, &f.flagAllocObjects, si, "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,
-	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")
-	}
-	for index, s := range p.SampleType {
-		if sampleType == s.Type {
-			return index, nil
-		}
-	}
-	return 0, fmt.Errorf("option %s not valid for this profile", option)
-}
-
-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.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"), f.isFormat("callgrind"):
-		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 1fa07a2..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"
-	"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/pprof/internal/fetch/fetch.go b/src/cmd/pprof/internal/fetch/fetch.go
deleted file mode 100644
index d3ccb65..0000000
--- a/src/cmd/pprof/internal/fetch/fetch.go
+++ /dev/null
@@ -1,98 +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 (
-	"crypto/tls"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"net/url"
-	"os"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/plugin"
-	"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(source string, timeout time.Duration) (*http.Response, error) {
-	url, err := url.Parse(source)
-	if err != nil {
-		return nil, err
-	}
-
-	var tlsConfig *tls.Config
-	if url.Scheme == "https+insecure" {
-		tlsConfig = &tls.Config{
-			InsecureSkipVerify: true,
-		}
-		url.Scheme = "https"
-		source = url.String()
-	}
-
-	client := &http.Client{
-		Transport: &http.Transport{
-			ResponseHeaderTimeout: timeout + 5*time.Second,
-			TLSClientConfig:       tlsConfig,
-		},
-	}
-	return client.Get(source)
-}
diff --git a/src/cmd/pprof/internal/plugin/plugin.go b/src/cmd/pprof/internal/plugin/plugin.go
deleted file mode 100644
index ff1e8ad..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"
-
-	"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/pprof/internal/report/report.go b/src/cmd/pprof/internal/report/report.go
deleted file mode 100644
index f897c90..0000000
--- a/src/cmd/pprof/internal/report/report.go
+++ /dev/null
@@ -1,1726 +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"
-	"path/filepath"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/plugin"
-	"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[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, "positions: instr line")
-	fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
-
-	objfiles := make(map[string]int)
-	files := make(map[string]int)
-	names := make(map[string]int)
-
-	// prevInfo points to the previous nodeInfo.
-	// It is used to group cost lines together as much as possible.
-	var prevInfo *nodeInfo
-	for _, n := range g.ns {
-		if prevInfo == nil || n.info.objfile != prevInfo.objfile || n.info.file != prevInfo.file || n.info.name != prevInfo.name {
-			fmt.Fprintln(w)
-			fmt.Fprintln(w, "ob="+callgrindName(objfiles, n.info.objfile))
-			fmt.Fprintln(w, "fl="+callgrindName(files, n.info.file))
-			fmt.Fprintln(w, "fn="+callgrindName(names, n.info.name))
-		}
-
-		addr := callgrindAddress(prevInfo, n.info.address)
-		sv, _ := ScaleValue(n.flat, o.SampleUnit, o.OutputUnit)
-		fmt.Fprintf(w, "%s %d %d\n", addr, n.info.lineno, int(sv))
-
-		// Print outgoing edges.
-		for _, out := range sortedEdges(n.out) {
-			c, _ := ScaleValue(out.weight, o.SampleUnit, o.OutputUnit)
-			callee := out.dest
-			fmt.Fprintln(w, "cfl="+callgrindName(files, callee.info.file))
-			fmt.Fprintln(w, "cfn="+callgrindName(names, callee.info.name))
-			fmt.Fprintf(w, "calls=%d %s %d\n", int(c), callgrindAddress(prevInfo, callee.info.address), callee.info.lineno)
-			// TODO: This address may be in the middle of a call
-			// instruction. It would be best to find the beginning
-			// of the instruction, but the tools seem to handle
-			// this OK.
-			fmt.Fprintf(w, "* * %d\n", int(c))
-		}
-
-		prevInfo = &n.info
-	}
-
-	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)
-}
-
-// callgrindAddress implements the callgrind subposition compression scheme if
-// possible. If prevInfo != nil, it contains the previous address. The current
-// address can be given relative to the previous address, with an explicit +/-
-// to indicate it is relative, or * for the same address.
-func callgrindAddress(prevInfo *nodeInfo, curr uint64) string {
-	abs := fmt.Sprintf("%#x", curr)
-	if prevInfo == nil {
-		return abs
-	}
-
-	prev := prevInfo.address
-	if prev == curr {
-		return "*"
-	}
-
-	diff := int64(curr - prev)
-	relative := fmt.Sprintf("%+d", diff)
-
-	// Only bother to use the relative address if it is actually shorter.
-	if len(relative) < len(abs) {
-		return relative
-	}
-
-	return abs
-}
-
-// 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 = 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 = "[" + filepath.Base(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/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go
deleted file mode 100644
index 458985d..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 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/pprof/internal/report/source_html.go
deleted file mode 100644
index 267fabd..0000000
--- a/src/cmd/pprof/internal/report/source_html.go
+++ /dev/null
@@ -1,77 +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
-
-const weblistPageHeader = `
-<!DOCTYPE html>
-<html>
-<head>
-<title>Pprof listing</title>
-<style type="text/css">
-body {
-font-family: sans-serif;
-}
-h1 {
-  font-size: 1.5em;
-  margin-bottom: 4px;
-}
-.legend {
-  font-size: 1.25em;
-}
-.line {
-color: #aaaaaa;
-}
-.nop {
-color: #aaaaaa;
-}
-.unimportant {
-color: #cccccc;
-}
-.disasmloc {
-color: #000000;
-}
-.deadsrc {
-cursor: pointer;
-}
-.deadsrc:hover {
-background-color: #eeeeee;
-}
-.livesrc {
-color: #0000ff;
-cursor: pointer;
-}
-.livesrc:hover {
-background-color: #eeeeee;
-}
-.asm {
-color: #008800;
-display: none;
-}
-</style>
-<script type="text/javascript">
-function pprof_toggle_asm(e) {
-  var target;
-  if (!e) e = window.event;
-  if (e.target) target = e.target;
-  else if (e.srcElement) target = e.srcElement;
-
-  if (target) {
-    var asm = target.nextSibling;
-    if (asm && asm.className == "asm") {
-      asm.style.display = (asm.style.display == "block" ? "" : "block");
-      e.preventDefault();
-      return false;
-    }
-  }
-}
-</script>
-</head>
-<body>
-`
-
-const weblistPageClosing = `
-</body>
-</html>
-`
diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/pprof/internal/svg/svg.go
deleted file mode 100644
index 04f6ff1..0000000
--- a/src/cmd/pprof/internal/svg/svg.go
+++ /dev/null
@@ -1,71 +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 svg provides tools related to handling of SVG files
-package svg
-
-import (
-	"bytes"
-	"regexp"
-	"strings"
-)
-
-var (
-	viewBox  = regexp.MustCompile(`<svg\s*width="[^"]+"\s*height="[^"]+"\s*viewBox="[^"]+"`)
-	graphId  = regexp.MustCompile(`<g id="graph\d"`)
-	svgClose = regexp.MustCompile(`</svg>`)
-)
-
-// Massage enhances the SVG output from DOT to provide better
-// panning inside a web browser. It uses the SVGPan library, which is
-// included directly.
-func Massage(in bytes.Buffer) string {
-	svg := string(in.Bytes())
-
-	// Work around for dot bug which misses quoting some ampersands,
-	// resulting on unparsable SVG.
-	svg = strings.Replace(svg, "&;", "&;", -1)
-
-	//Dot's SVG output is
-	//
-	//    <svg width="___" height="___"
-	//     viewBox="___" xmlns=...>
-	//    <g id="graph0" transform="...">
-	//    ...
-	//    </g>
-	//    </svg>
-	//
-	// Change it to
-	//
-	//    <svg width="100%" height="100%"
-	//     xmlns=...>
-	//    <script>...</script>
-	//    <g id="viewport" transform="translate(0,0)">
-	//    <g id="graph0" transform="...">
-	//    ...
-	//    </g>
-	//    </g>
-	//    </svg>
-
-	if loc := viewBox.FindStringIndex(svg); loc != nil {
-		svg = svg[:loc[0]] +
-			`<svg width="100%" height="100%"` +
-			svg[loc[1]:]
-	}
-
-	if loc := graphId.FindStringIndex(svg); loc != nil {
-		svg = svg[:loc[0]] +
-			`<script type="text/ecmascript"><![CDATA[` + svgPanJS + `]]></script>` +
-			`<g id="viewport" transform="scale(0.5,0.5) translate(0,0)">` +
-			svg[loc[0]:]
-	}
-
-	if loc := svgClose.FindStringIndex(svg); loc != nil {
-		svg = svg[:loc[0]] +
-			`</g>` +
-			svg[loc[0]:]
-	}
-
-	return svg
-}
diff --git a/src/cmd/pprof/internal/svg/svgpan.go b/src/cmd/pprof/internal/svg/svgpan.go
deleted file mode 100644
index d8f12af..0000000
--- a/src/cmd/pprof/internal/svg/svgpan.go
+++ /dev/null
@@ -1,291 +0,0 @@
-// SVG pan and zoom library.
-// See copyright notice in string constant below.
-
-package svg
-
-// https://www.cyberz.org/projects/SVGPan/SVGPan.js
-
-const svgPanJS = `
-/** 
- *  SVGPan library 1.2.1
- * ======================
- *
- * Given an unique existing element with id "viewport" (or when missing, the first g 
- * element), including the the library into any SVG adds the following capabilities:
- *
- *  - Mouse panning
- *  - Mouse zooming (using the wheel)
- *  - Object dragging
- *
- * You can configure the behavior of the pan/zoom/drag with the variables
- * listed in the CONFIGURATION section of this file.
- *
- * Known issues:
- *
- *  - Zooming (while panning) on Safari has still some issues
- *
- * Releases:
- *
- * 1.2.1, Mon Jul  4 00:33:18 CEST 2011, Andrea Leofreddi
- *	- Fixed a regression with mouse wheel (now working on Firefox 5)
- *	- Working with viewBox attribute (#4)
- *	- Added "use strict;" and fixed resulting warnings (#5)
- *	- Added configuration variables, dragging is disabled by default (#3)
- *
- * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
- *	Fixed a bug with browser mouse handler interaction
- *
- * 1.1, Wed Feb  3 17:39:33 GMT 2010, Zeng Xiaohui
- *	Updated the zoom code to support the mouse wheel on Safari/Chrome
- *
- * 1.0, Andrea Leofreddi
- *	First release
- *
- * This code is licensed under the following BSD license:
- *
- * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi at itcharm.com>. All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- * 
- *    1. Redistributions of source code must retain the above copyright notice, this list of
- *       conditions and the following disclaimer.
- * 
- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
- *       of conditions and the following disclaimer in the documentation and/or other materials
- *       provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ` + "``AS IS''" + ` AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of Andrea Leofreddi.
- */
-
-"use strict";
-
-/// CONFIGURATION 
-/// ====>
-
-var enablePan = 1; // 1 or 0: enable or disable panning (default enabled)
-var enableZoom = 1; // 1 or 0: enable or disable zooming (default enabled)
-var enableDrag = 0; // 1 or 0: enable or disable dragging (default disabled)
-
-/// <====
-/// END OF CONFIGURATION 
-
-var root = document.documentElement;
-
-var state = 'none', svgRoot, stateTarget, stateOrigin, stateTf;
-
-setupHandlers(root);
-
-/**
- * Register handlers
- */
-function setupHandlers(root){
-	setAttributes(root, {
-		"onmouseup" : "handleMouseUp(evt)",
-		"onmousedown" : "handleMouseDown(evt)",
-		"onmousemove" : "handleMouseMove(evt)",
-		//"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
-	});
-
-	if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
-		window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
-	else
-		window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
-}
-
-/**
- * Retrieves the root element for SVG manipulation. The element is then cached into the svgRoot global variable.
- */
-function getRoot(root) {
-	if(typeof(svgRoot) == "undefined") {
-		var g = null;
-
-		g = root.getElementById("viewport");
-
-		if(g == null)
-			g = root.getElementsByTagName('g')[0];
-
-		if(g == null)
-			alert('Unable to obtain SVG root element');
-
-		setCTM(g, g.getCTM());
-
-		g.removeAttribute("viewBox");
-
-		svgRoot = g;
-	}
-
-	return svgRoot;
-}
-
-/**
- * Instance an SVGPoint object with given event coordinates.
- */
-function getEventPoint(evt) {
-	var p = root.createSVGPoint();
-
-	p.x = evt.clientX;
-	p.y = evt.clientY;
-
-	return p;
-}
-
-/**
- * Sets the current transform matrix of an element.
- */
-function setCTM(element, matrix) {
-	var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
-
-	element.setAttribute("transform", s);
-}
-
-/**
- * Dumps a matrix to a string (useful for debug).
- */
-function dumpMatrix(matrix) {
-	var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n  " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n  0, 0, 1 ]";
-
-	return s;
-}
-
-/**
- * Sets attributes of an element.
- */
-function setAttributes(element, attributes){
-	for (var i in attributes)
-		element.setAttributeNS(null, i, attributes[i]);
-}
-
-/**
- * Handle mouse wheel event.
- */
-function handleMouseWheel(evt) {
-	if(!enableZoom)
-		return;
-
-	if(evt.preventDefault)
-		evt.preventDefault();
-
-	evt.returnValue = false;
-
-	var svgDoc = evt.target.ownerDocument;
-
-	var delta;
-
-	if(evt.wheelDelta)
-		delta = evt.wheelDelta / 3600; // Chrome/Safari
-	else
-		delta = evt.detail / -90; // Mozilla
-
-	var z = 1 + delta; // Zoom factor: 0.9/1.1
-
-	var g = getRoot(svgDoc);
-	
-	var p = getEventPoint(evt);
-
-	p = p.matrixTransform(g.getCTM().inverse());
-
-	// Compute new scale matrix in current mouse position
-	var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
-
-        setCTM(g, g.getCTM().multiply(k));
-
-	if(typeof(stateTf) == "undefined")
-		stateTf = g.getCTM().inverse();
-
-	stateTf = stateTf.multiply(k.inverse());
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseMove(evt) {
-	if(evt.preventDefault)
-		evt.preventDefault();
-
-	evt.returnValue = false;
-
-	var svgDoc = evt.target.ownerDocument;
-
-	var g = getRoot(svgDoc);
-
-	if(state == 'pan' && enablePan) {
-		// Pan mode
-		var p = getEventPoint(evt).matrixTransform(stateTf);
-
-		setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
-	} else if(state == 'drag' && enableDrag) {
-		// Drag mode
-		var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
-
-		setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
-
-		stateOrigin = p;
-	}
-}
-
-/**
- * Handle click event.
- */
-function handleMouseDown(evt) {
-	if(evt.preventDefault)
-		evt.preventDefault();
-
-	evt.returnValue = false;
-
-	var svgDoc = evt.target.ownerDocument;
-
-	var g = getRoot(svgDoc);
-
-	if(
-		evt.target.tagName == "svg" 
-		|| !enableDrag // Pan anyway when drag is disabled and the user clicked on an element 
-	) {
-		// Pan mode
-		state = 'pan';
-
-		stateTf = g.getCTM().inverse();
-
-		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
-	} else {
-		// Drag mode
-		state = 'drag';
-
-		stateTarget = evt.target;
-
-		stateTf = g.getCTM().inverse();
-
-		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
-	}
-}
-
-/**
- * Handle mouse button release event.
- */
-function handleMouseUp(evt) {
-	if(evt.preventDefault)
-		evt.preventDefault();
-
-	evt.returnValue = false;
-
-	var svgDoc = evt.target.ownerDocument;
-
-	if(state == 'pan' || state == 'drag') {
-		// Quit pan mode
-		state = '';
-	}
-}
-
-`
diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go
deleted file mode 100644
index 06a3976..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"
-	"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/pprof/internal/symbolz/symbolz.go b/src/cmd/pprof/internal/symbolz/symbolz.go
deleted file mode 100644
index 6e58001..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"
-
-	"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/pprof/internal/tempfile/tempfile.go b/src/cmd/pprof/internal/tempfile/tempfile.go
deleted file mode 100644
index a570634..0000000
--- a/src/cmd/pprof/internal/tempfile/tempfile.go
+++ /dev/null
@@ -1,46 +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 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/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 18479b4..24bec07 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -2,137 +2,140 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// pprof is a tool for visualization of profile.data. It is based on
+// the upstream version at github.com/google/pprof, with minor
+// modifications specific to the Go distribution. Please consider
+// upstreaming any modifications to these packages.
+
 package main
 
 import (
+	"crypto/tls"
 	"debug/dwarf"
-	"flag"
 	"fmt"
+	"net/http"
 	"net/url"
 	"os"
 	"regexp"
-	"strings"
+	"strconv"
 	"sync"
+	"time"
 
 	"cmd/internal/objfile"
-	"cmd/pprof/internal/commands"
-	"cmd/pprof/internal/driver"
-	"cmd/pprof/internal/fetch"
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/symbolizer"
-	"cmd/pprof/internal/symbolz"
-	"internal/pprof/profile"
+
+	"github.com/google/pprof/driver"
+	"github.com/google/pprof/profile"
 )
 
 func main() {
-	var extraCommands map[string]*commands.Command // no added Go-specific commands
-	if err := driver.PProf(flags{}, fetch.Fetcher, symbolize, new(objTool), plugin.StandardUI(), extraCommands); err != nil {
+	options := &driver.Options{
+		Fetch: new(fetcher),
+		Obj:   new(objTool),
+	}
+	if err := driver.PProf(options); err != nil {
 		fmt.Fprintf(os.Stderr, "%v\n", err)
 		os.Exit(2)
 	}
 }
 
-// symbolize attempts to symbolize profile p.
-// If the source is a local binary, it tries using symbolizer and obj.
-// If the source is a URL, it fetches symbol information using symbolz.
-func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
-	remote, local := true, true
-	for _, o := range strings.Split(strings.ToLower(mode), ":") {
-		switch o {
-		case "none", "no":
-			return nil
-		case "local":
-			remote, local = false, true
-		case "remote":
-			remote, local = true, false
-		default:
-			ui.PrintErr("ignoring unrecognized symbolization option: " + mode)
-			ui.PrintErr("expecting -symbolize=[local|remote|none][:force]")
-			fallthrough
-		case "", "force":
-			// -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
-				}
-			}
-		}
-	}
+type fetcher struct {
+}
 
-	var err error
-	if local {
-		// Symbolize using binutils.
-		if err = symbolizer.Symbolize(mode, p, obj, ui); err == nil {
-			return nil
-		}
+func (f *fetcher) Fetch(src string, duration, timeout time.Duration) (*profile.Profile, string, error) {
+	sourceURL, timeout := adjustURL(src, duration, timeout)
+	if sourceURL == "" {
+		// Could not recognize URL, let regular pprof attempt to fetch the profile (eg. from a file)
+		return nil, "", nil
 	}
-	if remote {
-		err = symbolz.Symbolize(source, fetch.PostURL, p)
+	fmt.Fprintln(os.Stderr, "Fetching profile over HTTP from", sourceURL)
+	if duration > 0 {
+		fmt.Fprintf(os.Stderr, "Please wait... (%v)\n", duration)
 	}
-	return err
+	p, err := getProfile(sourceURL, timeout)
+	return p, sourceURL, err
 }
 
-// isRemote returns whether source is a URL for a remote source.
-func isRemote(source string) bool {
+func getProfile(source string, timeout time.Duration) (*profile.Profile, error) {
 	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 nil, err
 	}
-	return true
-}
 
-// flags implements the driver.FlagPackage interface using the builtin flag package.
-type flags struct {
-}
-
-func (flags) Bool(o string, d bool, c string) *bool {
-	return flag.Bool(o, d, c)
-}
+	var tlsConfig *tls.Config
+	if url.Scheme == "https+insecure" {
+		tlsConfig = &tls.Config{
+			InsecureSkipVerify: true,
+		}
+		url.Scheme = "https"
+		source = url.String()
+	}
 
-func (flags) Int(o string, d int, c string) *int {
-	return flag.Int(o, d, c)
+	client := &http.Client{
+		Transport: &http.Transport{
+			ResponseHeaderTimeout: timeout + 5*time.Second,
+			Proxy:           http.ProxyFromEnvironment,
+			TLSClientConfig: tlsConfig,
+		},
+	}
+	resp, err := client.Get(source)
+	if err != nil {
+		return nil, err
+	}
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("server response: %s", resp.Status)
+	}
+	return profile.Parse(resp.Body)
 }
 
-func (flags) Float64(o string, d float64, c string) *float64 {
-	return flag.Float64(o, d, c)
-}
+// cpuProfileHandler is the Go pprof CPU profile handler URL.
+const cpuProfileHandler = "/debug/pprof/profile"
 
-func (flags) String(o, d, c string) *string {
-	return flag.String(o, d, c)
-}
+// adjustURL applies the duration/timeout values and Go specific defaults
+func adjustURL(source string, duration, timeout time.Duration) (string, time.Duration) {
+	u, err := url.Parse(source)
+	if err != nil || (u.Host == "" && u.Scheme != "" && u.Scheme != "file") {
+		// Try adding http:// to catch sources of the form hostname:port/path.
+		// url.Parse treats "hostname" as the scheme.
+		u, err = url.Parse("http://" + source)
+	}
+	if err != nil || u.Host == "" {
+		return "", 0
+	}
 
-func (flags) Parse(usage func()) []string {
-	flag.Usage = usage
-	flag.Parse()
-	args := flag.Args()
-	if len(args) == 0 {
-		usage()
+	if u.Path == "" || u.Path == "/" {
+		u.Path = cpuProfileHandler
 	}
-	return args
-}
 
-func (flags) ExtraUsage() string {
-	return ""
+	// Apply duration/timeout overrides to URL.
+	values := u.Query()
+	if duration > 0 {
+		values.Set("seconds", fmt.Sprint(int(duration.Seconds())))
+	} else {
+		if urlSeconds := values.Get("seconds"); urlSeconds != "" {
+			if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
+				duration = time.Duration(us) * time.Second
+			}
+		}
+	}
+	if timeout <= 0 {
+		if duration > 0 {
+			timeout = duration + duration/2
+		} else {
+			timeout = 60 * time.Second
+		}
+	}
+	u.RawQuery = values.Encode()
+	return u.String(), timeout
 }
 
-// objTool implements plugin.ObjTool using Go libraries
+// objTool implements driver.ObjTool using Go libraries
 // (instead of invoking GNU binutils).
 type objTool struct {
 	mu          sync.Mutex
 	disasmCache map[string]*objfile.Disasm
 }
 
-func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
+func (*objTool) Open(name string, start, limit, offset uint64) (driver.ObjFile, error) {
 	of, err := objfile.Open(name)
 	if err != nil {
 		return nil, err
@@ -154,14 +157,14 @@ func (*objTool) Demangle(names []string) (map[string]string, error) {
 	return make(map[string]string), nil
 }
 
-func (t *objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error) {
 	d, err := t.cachedDisasm(file)
 	if err != nil {
 		return nil, err
 	}
-	var asm []plugin.Inst
+	var asm []driver.Inst
 	d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) {
-		asm = append(asm, plugin.Inst{Addr: pc, File: file, Line: line, Text: text})
+		asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text})
 	})
 	return asm, nil
 }
@@ -194,7 +197,7 @@ func (*objTool) SetConfig(config string) {
 	// Ignore entirely.
 }
 
-// file implements plugin.ObjFile using Go libraries
+// file implements driver.ObjFile using Go libraries
 // (instead of invoking GNU binutils).
 // A file represents a single executable being analyzed.
 type file struct {
@@ -222,7 +225,7 @@ func (f *file) BuildID() string {
 	return ""
 }
 
-func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
+func (f *file) SourceLine(addr uint64) ([]driver.Frame, error) {
 	if f.pcln == nil {
 		pcln, err := f.file.PCLineTable()
 		if err != nil {
@@ -233,7 +236,7 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
 	addr -= f.offset
 	file, line, fn := f.pcln.PCToLine(addr)
 	if fn != nil {
-		frame := []plugin.Frame{
+		frame := []driver.Frame{
 			{
 				Func: fn.Name,
 				File: file,
@@ -254,7 +257,7 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
 // 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 {
+func (f *file) dwarfSourceLine(addr uint64) []driver.Frame {
 	if f.dwarf == nil && !f.triedDwarf {
 		// Ignore any error--we don't care exactly why there
 		// is no DWARF info.
@@ -277,7 +280,7 @@ func (f *file) dwarfSourceLine(addr uint64) []plugin.Frame {
 
 // 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 {
+func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []driver.Frame {
 	lines, err := f.dwarf.LineReader(entry)
 	if err != nil {
 		return nil
@@ -311,7 +314,7 @@ FindName:
 
 	// TODO: Report inlined functions.
 
-	frames := []plugin.Frame{
+	frames := []driver.Frame{
 		{
 			Func: name,
 			File: lentry.File.Name,
@@ -322,7 +325,7 @@ FindName:
 	return frames
 }
 
-func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*driver.Sym, error) {
 	if f.sym == nil {
 		sym, err := f.file.Symbols()
 		if err != nil {
@@ -330,7 +333,7 @@ func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
 		}
 		f.sym = sym
 	}
-	var out []*plugin.Sym
+	var out []*driver.Sym
 	for _, s := range f.sym {
 		// Ignore a symbol with address 0 and size 0.
 		// An ELF STT_FILE symbol will look like that.
@@ -338,7 +341,7 @@ func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
 			continue
 		}
 		if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
-			out = append(out, &plugin.Sym{
+			out = append(out, &driver.Sym{
 				Name:  []string{s.Name},
 				File:  f.name,
 				Start: s.Addr,
diff --git a/src/cmd/trace/doc.go b/src/cmd/trace/doc.go
new file mode 100644
index 0000000..ed1f930
--- /dev/null
+++ b/src/cmd/trace/doc.go
@@ -0,0 +1,35 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Trace is a tool for viewing trace files.
+
+Trace files can be generated with:
+	- runtime/trace.Start
+	- net/http/pprof package
+	- go test -trace
+
+Example usage:
+Generate a trace file with 'go test':
+	go test -trace trace.out pkg
+View the trace in a web browser:
+	go tool trace trace.out
+Generate a pprof-like profile from the trace:
+	go tool trace -pprof=TYPE trace.out > TYPE.pprof
+
+Supported profile types are:
+	- net: network blocking profile
+	- sync: synchronization blocking profile
+	- syscall: syscall blocking profile
+	- sched: scheduler latency profile
+
+Then, you can use the pprof tool to analyze the profile:
+	go tool pprof TYPE.pprof
+
+Note that while the various profiles available when launching
+'go tool trace' work on every browser, the trace viewer itself
+(the 'view trace' page) comes from the Chrome/Chromium project
+and is only actively tested on that browser.
+*/
+package main
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index c7bf75e..8ea0ba0 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -2,28 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-/*
-Trace is a tool for viewing trace files.
-
-Trace files can be generated with:
-	- runtime/trace.Start
-	- net/http/pprof package
-	- go test -trace
-
-Example usage:
-Generate a trace file with 'go test':
-	go test -trace trace.out pkg
-View the trace in a web browser:
-	go tool trace trace.out
-Generate a pprof-like profile from the trace:
-	go tool trace -pprof=TYPE trace.out > TYPE.pprof
-
-Supported profile types are:
-	- net: network blocking profile
-	- sync: synchronization blocking profile
-	- syscall: syscall blocking profile
-	- sched: scheduler latency profile
-*/
 package main
 
 import (
@@ -64,6 +42,11 @@ Supported profile types are:
 Flags:
 	-http=addr: HTTP service address (e.g., ':6060')
 	-pprof=type: print a pprof-like profile instead
+
+Note that while the various profiles available when launching
+'go tool trace' work on every browser, the trace viewer itself
+(the 'view trace' page) comes from the Chrome/Chromium project
+and is only actively tested on that browser.
 `
 
 var (
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
index dea3a74..40803ac 100644
--- a/src/cmd/trace/pprof.go
+++ b/src/cmd/trace/pprof.go
@@ -9,13 +9,14 @@ package main
 import (
 	"bufio"
 	"fmt"
-	"internal/pprof/profile"
 	"internal/trace"
 	"io"
 	"io/ioutil"
 	"net/http"
 	"os"
 	"os/exec"
+
+	"github.com/google/pprof/profile"
 )
 
 func init() {
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index f5a2df4..7db2188 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -288,6 +288,13 @@ const (
 	gStateCount
 )
 
+type gInfo struct {
+	state      gState       // current state
+	name       string       // name chosen for this goroutine at first EvGoStart
+	start      *trace.Event // most recent EvGoStart
+	markAssist *trace.Event // if non-nil, the mark assist currently running.
+}
+
 type ViewerData struct {
 	Events   []*ViewerEvent         `json:"traceEvents"`
 	Frames   map[string]ViewerFrame `json:"stackFrames"`
@@ -337,35 +344,47 @@ func generateTrace(params *traceParams) (ViewerData, error) {
 	ctx.data.Frames = make(map[string]ViewerFrame)
 	ctx.data.TimeUnit = "ns"
 	maxProc := 0
-	gnames := make(map[uint64]string)
-	gstates := make(map[uint64]gState)
+	ginfos := make(map[uint64]*gInfo)
+
+	getGInfo := func(g uint64) *gInfo {
+		info, ok := ginfos[g]
+		if !ok {
+			info = &gInfo{}
+			ginfos[g] = info
+		}
+		return info
+	}
+
 	// Since we make many calls to setGState, we record a sticky
 	// error in setGStateErr and check it after every event.
 	var setGStateErr error
 	setGState := func(ev *trace.Event, g uint64, oldState, newState gState) {
-		if oldState == gWaiting && gstates[g] == gWaitingGC {
+		info := getGInfo(g)
+		if oldState == gWaiting && info.state == gWaitingGC {
 			// For checking, gWaiting counts as any gWaiting*.
-			oldState = gstates[g]
+			oldState = info.state
 		}
-		if gstates[g] != oldState && setGStateErr == nil {
+		if info.state != oldState && setGStateErr == nil {
 			setGStateErr = fmt.Errorf("expected G %d to be in state %d, but got state %d", g, oldState, newState)
 		}
-		ctx.gstates[gstates[g]]--
+		ctx.gstates[info.state]--
 		ctx.gstates[newState]++
-		gstates[g] = newState
+		info.state = newState
 	}
 	for _, ev := range ctx.events {
 		// Handle state transitions before we filter out events.
 		switch ev.Type {
 		case trace.EvGoStart, trace.EvGoStartLabel:
 			setGState(ev, ev.G, gRunnable, gRunning)
-			if _, ok := gnames[ev.G]; !ok {
+			info := getGInfo(ev.G)
+			if info.name == "" {
 				if len(ev.Stk) > 0 {
-					gnames[ev.G] = fmt.Sprintf("G%v %s", ev.G, ev.Stk[0].Fn)
+					info.name = fmt.Sprintf("G%v %s", ev.G, ev.Stk[0].Fn)
 				} else {
-					gnames[ev.G] = fmt.Sprintf("G%v", ev.G)
+					info.name = fmt.Sprintf("G%v", ev.G)
 				}
 			}
+			info.start = ev
 		case trace.EvProcStart:
 			ctx.threadStats.prunning++
 		case trace.EvProcStop:
@@ -392,6 +411,10 @@ func generateTrace(params *traceParams) (ViewerData, error) {
 			setGState(ev, ev.G, gRunning, gWaiting)
 		case trace.EvGoBlockGC:
 			setGState(ev, ev.G, gRunning, gWaitingGC)
+		case trace.EvGCMarkAssistStart:
+			getGInfo(ev.G).markAssist = ev
+		case trace.EvGCMarkAssistDone:
+			getGInfo(ev.G).markAssist = nil
 		case trace.EvGoWaiting:
 			setGState(ev, ev.G, gRunnable, gWaiting)
 		case trace.EvGoInSyscall:
@@ -444,13 +467,47 @@ func generateTrace(params *traceParams) (ViewerData, error) {
 			}
 			ctx.emitSlice(ev, "MARK TERMINATION")
 		case trace.EvGCScanDone:
+		case trace.EvGCMarkAssistStart:
+			// Mark assists can continue past preemptions, so truncate to the
+			// whichever comes first. We'll synthesize another slice if
+			// necessary in EvGoStart.
+			markFinish := ev.Link
+			goFinish := getGInfo(ev.G).start.Link
+			fakeMarkStart := *ev
+			text := "MARK ASSIST"
+			if markFinish == nil || markFinish.Ts > goFinish.Ts {
+				fakeMarkStart.Link = goFinish
+				text = "MARK ASSIST (unfinished)"
+			}
+			ctx.emitSlice(&fakeMarkStart, text)
 		case trace.EvGCSweepStart:
-			ctx.emitSlice(ev, "SWEEP")
-		case trace.EvGCSweepDone:
-		case trace.EvGoStart:
-			ctx.emitSlice(ev, gnames[ev.G])
-		case trace.EvGoStartLabel:
-			ctx.emitSlice(ev, ev.SArgs[0])
+			slice := ctx.emitSlice(ev, "SWEEP")
+			if done := ev.Link; done != nil && done.Args[0] != 0 {
+				slice.Arg = struct {
+					Swept     uint64 `json:"Swept bytes"`
+					Reclaimed uint64 `json:"Reclaimed bytes"`
+				}{done.Args[0], done.Args[1]}
+			}
+		case trace.EvGoStart, trace.EvGoStartLabel:
+			info := getGInfo(ev.G)
+			if ev.Type == trace.EvGoStartLabel {
+				ctx.emitSlice(ev, ev.SArgs[0])
+			} else {
+				ctx.emitSlice(ev, info.name)
+			}
+			if info.markAssist != nil {
+				// If we're in a mark assist, synthesize a new slice, ending
+				// either when the mark assist ends or when we're descheduled.
+				markFinish := info.markAssist.Link
+				goFinish := ev.Link
+				fakeMarkStart := *ev
+				text := "MARK ASSIST (resumed, unfinished)"
+				if markFinish != nil && markFinish.Ts < goFinish.Ts {
+					fakeMarkStart.Link = markFinish
+					text = "MARK ASSIST (resumed)"
+				}
+				ctx.emitSlice(&fakeMarkStart, text)
+			}
 		case trace.EvGoCreate:
 			ctx.emitArrow(ev, "go")
 		case trace.EvGoUnblock:
@@ -493,11 +550,11 @@ func generateTrace(params *traceParams) (ViewerData, error) {
 	}
 
 	if ctx.gtrace && ctx.gs != nil {
-		for k, v := range gnames {
+		for k, v := range ginfos {
 			if !ctx.gs[k] {
 				continue
 			}
-			ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: k, Arg: &NameArg{v}})
+			ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: k, Arg: &NameArg{v.name}})
 		}
 		ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: ctx.maing, Arg: &SortIndexArg{-2}})
 		ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: 0, Arg: &SortIndexArg{-1}})
@@ -523,8 +580,8 @@ func (ctx *traceContext) proc(ev *trace.Event) uint64 {
 	}
 }
 
-func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
-	ctx.emit(&ViewerEvent{
+func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
+	sl := &ViewerEvent{
 		Name:     name,
 		Phase:    "X",
 		Time:     ctx.time(ev),
@@ -532,7 +589,9 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
 		Tid:      ctx.proc(ev),
 		Stack:    ctx.stack(ev.Stk),
 		EndStack: ctx.stack(ev.Link.Stk),
-	})
+	}
+	ctx.emit(sl)
+	return sl
 }
 
 type heapCountersArg struct {
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go
index d14239c..d96c297 100644
--- a/src/cmd/trace/trace_test.go
+++ b/src/cmd/trace/trace_test.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"internal/trace"
+	"strings"
 	"testing"
 )
 
@@ -99,3 +100,43 @@ func TestGoroutineFilter(t *testing.T) {
 		t.Fatalf("generateTrace failed: %v", err)
 	}
 }
+
+func TestPreemptedMarkAssist(t *testing.T) {
+	w := trace.NewWriter()
+	w.Emit(trace.EvBatch, 0, 0)  // start of per-P batch event [pid, timestamp]
+	w.Emit(trace.EvFrequency, 1) // [ticks per second]
+
+	// goroutine 9999: running -> mark assisting -> preempted -> assisting -> running -> block
+	w.Emit(trace.EvGoCreate, 1, 9999, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
+	w.Emit(trace.EvGoStartLocal, 1, 9999)   // [timestamp, goroutine id]
+	w.Emit(trace.EvGCMarkAssistStart, 1, 2) // [timestamp, stack]
+	w.Emit(trace.EvGoPreempt, 1, 3)         // [timestamp, stack]
+	w.Emit(trace.EvGoStartLocal, 1, 9999)   // [timestamp, goroutine id]
+	w.Emit(trace.EvGCMarkAssistDone, 1)     // [timestamp]
+	w.Emit(trace.EvGoBlock, 1, 4)           // [timestamp, stack]
+
+	events, err := trace.Parse(w, "")
+	if err != nil {
+		t.Fatalf("failed to parse test trace: %v", err)
+	}
+
+	params := &traceParams{
+		events:  events,
+		endTime: int64(1<<63 - 1),
+	}
+
+	viewerData, err := generateTrace(params)
+	if err != nil {
+		t.Fatalf("generateTrace failed: %v", err)
+	}
+
+	marks := 0
+	for _, ev := range viewerData.Events {
+		if strings.Contains(ev.Name, "MARK ASSIST") {
+			marks++
+		}
+	}
+	if marks != 2 {
+		t.Errorf("Got %v MARK ASSIST events, want %v", marks, 2)
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/AUTHORS b/src/cmd/vendor/github.com/google/pprof/AUTHORS
new file mode 100644
index 0000000..fd736cb
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/AUTHORS
@@ -0,0 +1,7 @@
+# This is the official list of pprof authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+# Names should be added to this file as:
+# Name or Organization <email address>
+# The email address is not required for organizations.
+Google Inc.
\ No newline at end of file
diff --git a/src/cmd/vendor/github.com/google/pprof/CONTRIBUTING b/src/cmd/vendor/github.com/google/pprof/CONTRIBUTING
new file mode 100644
index 0000000..2827b7d
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/CONTRIBUTING
@@ -0,0 +1,27 @@
+Want to contribute? Great! First, read this page (including the small print at the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement]
+(https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the
+[Software Grant and Corporate Contributor License Agreement]
+(https://cla.developers.google.com/about/google-corporate).
diff --git a/src/cmd/vendor/github.com/google/pprof/CONTRIBUTORS b/src/cmd/vendor/github.com/google/pprof/CONTRIBUTORS
new file mode 100644
index 0000000..2f73c29
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/CONTRIBUTORS
@@ -0,0 +1,14 @@
+# People who have agreed to one of the CLAs and can contribute patches.
+# The AUTHORS file lists the copyright holders; this file
+# lists people.  For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# https://developers.google.com/open-source/cla/individual
+# https://developers.google.com/open-source/cla/corporate
+#
+# Names should be added to this file as:
+#     Name <email address>
+Raul Silvera <rsilvera at google.com>
+Tipp Moseley <tipp at google.com>
+Hyoun Kyu Cho <netforce at google.com>
+
diff --git a/src/cmd/vendor/github.com/google/pprof/LICENSE b/src/cmd/vendor/github.com/google/pprof/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/src/cmd/vendor/github.com/google/pprof/README.md b/src/cmd/vendor/github.com/google/pprof/README.md
new file mode 100644
index 0000000..a134872
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/README.md
@@ -0,0 +1,86 @@
+# Introduction
+
+pprof is a tool for visualization and analysis of profiling data.
+
+pprof reads a collection of profiling samples in profile.proto format and
+generates reports to visualize and help analyze the data. It can generate both
+text and graphical reports (through the use of the dot visualization package).
+
+profile.proto is a protocol buffer that describes a set of callstacks
+and symbolization information. A common usage is to represent a set of
+sampled callstacks from statistical profiling. The format is
+described on the [proto/profile.proto](./proto/profile.proto) file. For details on protocol
+buffers, see https://developers.google.com/protocol-buffers
+
+Profiles can be read from a local file, or over http. Multiple
+profiles of the same type can be aggregated or compared.
+
+If the profile samples contain machine addresses, pprof can symbolize
+them through the use of the native binutils tools (addr2line and nm).
+
+**This is not an official Google product.**
+
+# Building pprof
+
+Prerequisites:
+
+- Go development kit. Known to work with Go 1.5.
+  Follow [these instructions](http://golang.org/doc/code.html) to install the 
+  go tool and set up GOPATH.
+
+- Graphviz: http://www.graphviz.org/
+  Optional, used to generate graphic visualizations of profiles
+
+To build and install it, use the `go get` tool.
+
+    go get github.com/google/pprof
+
+# Basic usage
+
+pprof can read a profile from a file or directly from a server via http.
+Specify the profile input(s) in the command line, and use options to
+indicate how to format the report.
+
+## Generate a text report of the profile, sorted by hotness:
+
+```
+% pprof -top [main_binary] profile.pb.gz
+Where
+    main_binary:  Local path to the main program binary, to enable symbolization
+    profile.pb.gz: Local path to the profile in a compressed protobuf, or
+                   URL to the http service that serves a profile.
+```
+
+## Generate a graph in an SVG file, and open it with a web browser:
+
+```
+pprof -web [main_binary] profile.pb.gz
+```
+
+## Run pprof on interactive mode:
+
+If no output formatting option is specified, pprof runs on interactive mode,
+where reads the profile and accepts interactive commands for visualization and
+refinement of the profile.
+
+```
+pprof [main_binary] profile.pb.gz
+
+This will open a simple shell that takes pprof commands to generate reports.
+Type 'help' for available commands/options.
+```
+
+## Using pprof with Linux Perf
+
+pprof can read `perf.data` files generated by the
+[Linux perf](https://perf.wiki.kernel.org/index.php) tool by using the
+`perf_to_profile` program from the
+[perf_data_converter](http://github.com/google/perf_data_converter) package.
+
+## Further documentation
+
+See [doc/pprof.md](doc/pprof.md) for more detailed end-user documentation.
+
+See [doc/developer/pprof.dev.md](doc/developer/pprof.dev.md) for developer documentation.
+
+See [doc/developer/profile.proto.md](doc/developer/profile.proto.md) for a description of the profile.proto format.
diff --git a/src/cmd/vendor/github.com/google/pprof/doc/developer/pprof.dev.md b/src/cmd/vendor/github.com/google/pprof/doc/developer/pprof.dev.md
new file mode 100644
index 0000000..b2a197f
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/doc/developer/pprof.dev.md
@@ -0,0 +1,14 @@
+This is pprof's developer documentation. It discusses how to maintain and extend
+pprof. It has yet to be written.
+
+# How is pprof code structured?
+
+Internal vs external packages.
+
+# External interface
+
+## Plugins
+
+## Legacy formats
+
+#  Overview of internal packages
diff --git a/src/cmd/vendor/github.com/google/pprof/doc/developer/profile.proto.md b/src/cmd/vendor/github.com/google/pprof/doc/developer/profile.proto.md
new file mode 100644
index 0000000..9932e7e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/doc/developer/profile.proto.md
@@ -0,0 +1,147 @@
+This is a description of the profile.proto format.
+
+# Overview
+
+Profile.proto is a data representation for profile data. It is independent of
+the type of data being collected and the sampling process used to collect that
+data. On disk, it is represented as a gzip-compressed protocol buffer, described
+at src/proto/profile.proto
+
+A profile in this context refers to a collection of samples, each one
+representing measurements performed at a certain point in the life of a job. A
+sample associates a set of measurement values with a list of locations, commonly
+representing the program call stack when the sample was taken.
+
+Tools such as pprof analyze these samples and display this information in
+multiple forms, such as identifying hottest locations, building graphical call
+graphs or trees, etc.
+
+# General structure of a profile
+
+A profile is represented on a Profile message, which contain the following
+fields:
+
+* *sample*: A profile sample, with the values measured and the associated call
+  stack as a list of location ids. Samples with identical call stacks can be
+  merged by adding their respective values, element by element.
+* *location*: A unique place in the program, commonly mapped to a single
+  instruction address. It has a unique nonzero id, to be referenced from the
+  samples. It contains source information in the form of lines, and a mapping id
+  that points to a binary.
+* *function*: A program function as defined in the program source. It has a
+  unique nonzero id, referenced from the location lines. It contains a
+  human-readable name for the function (eg a C++ demangled name), a system name
+  (eg a C++ mangled name), the name of the corresponding source file, and other
+  function attributes.
+* *mapping*: A binary that is part of the program during the profile
+  collection. It has a unique nonzero id, referenced from the locations. It
+  includes details on how the binary was mapped during program execution. By
+  convention the main program binary is the first mapping, followed by any
+  shared libraries.
+* *string_table*: All strings in the profile are represented as indices into
+  this repeating field. The first string is empty, so index == 0 always
+  represents the empty string.
+
+# Measurement values
+
+Measurement values are represented as 64-bit integers. The profile contains an
+explicit description of each value represented, using a ValueType message, with
+two fields:
+
+* *Type*: A human-readable description of the type semantics. For example “cpu”
+  to represent CPU time, “wall” or “time” for wallclock time, or “memory” for
+  bytes allocated.
+* *Unit*: A human-readable name of the unit represented by the 64-bit integer
+  values. For example, it could be “nanoseconds” or “milliseconds” for a time
+  value, or “bytes” or “megabytes” for a memory size. If this is just
+  representing a number of events, the recommended unit name is “count”.
+
+A profile can represent multiple measurements per sample, but all samples must
+have the same number and type of measurements. The actual values are stored in
+the Sample.value fields, each one described by the corresponding
+Profile.sample_type field.
+
+Some profiles have a uniform period that describe the granularity of the data
+collection. For example, a CPU profile may have a period of 100ms, or a memory
+allocation profile may have a period of 512kb. Profiles can optionally describe
+such a value on the Profile.period and Profile.period_type fields. The profile
+period is meant for human consumption and does not affect the interpretation of
+the profiling data.
+
+By convention, the first value on all profiles is the number of samples
+collected at this call stack, with unit “count”. Because the profile does not
+describe the sampling process beyond the optional period, it must include
+unsampled values for all measurements. For example, a CPU profile could have
+value[0] == samples, and value[1] == time in milliseconds.
+
+## Locations, functions and mappings
+
+Each sample lists the id of each location where the sample was collected, in
+bottom-up order. Each location has an explicit unique nonzero integer id,
+independent of its position in the profile, and holds additional information to
+identify the corresponding source.
+
+The profile source is expected to perform any adjustment required to the
+locations in order to point to the calls in the stack. For example, if the
+profile source extracts the call stack by walking back over the program stack,
+it must adjust the instruction addresses to point to the actual call
+instruction, instead of the instruction that each call will return to.
+
+Sources usually generate profiles that fall into these two categories:
+
+* *Unsymbolized profiles*: These only contain instruction addresses, and are to
+  be symbolized by a separate tool. It is critical for each location to point to
+  a valid mapping, which will provide the information required for
+  symbolization. These are used for profiles of compiled languages, such as C++
+  and Go.
+
+* *Symbolized profiles*: These contain all the symbol information available for
+  the profile. Mappings and instruction addresses are optional for symbolized
+  locations. These are used for profiles of interpreted or jitted languages,
+  such as Java or Python.  Also, the profile format allows the generation of
+  mixed profiles, with symbolized and unsymbolized locations.
+
+The symbol information is represented in the repeating lines field of the
+Location message. A location has multiple lines if it reflects multiple program
+sources, for example if representing inlined call stacks. Lines reference
+functions by their unique nonzero id, and the source line number within the
+source file listed by the function. A function contains the source attributes
+for a function, including its name, source file, etc. Functions include both a
+user and a system form of the name, for example to include C++ demangled and
+mangled names. For profiles where only a single name exists, both should be set
+to the same string.
+
+Mappings are also referenced from locations by their unique nonzero id, and
+include all information needed to symbolize addresses within the mapping. It
+includes similar information to the Linux /proc/self/maps file. Locations
+associated to a mapping should have addresses that land between the mapping
+start and limit. Also, if available, mappings should include a build id to
+uniquely identify the version of the binary being used.
+
+## Labels
+
+Samples optionally contain labels, which are annotations to discriminate samples
+with identical locations. For example, a label can be used on a malloc profile
+to indicate allocation size, so two samples on the same call stack with sizes
+2MB and 4MB do not get merged into a single sample with two allocations and a
+size of 6MB.
+
+Labels can be string-based or numeric. They are represented by the Label
+message, with a key identifying the label and either a string or numeric
+value. For numeric labels, by convention the key represents the measurement unit
+of the numeric value. So for the previous example, the samples would have labels
+{“bytes”, 2097152} and {“bytes”, 4194304}.
+
+## Keep and drop expressions
+
+Some profile sources may have knowledge of locations that are uninteresting or
+irrelevant. However, if symbolization is needed in order to identify these
+locations, the profile source may not be able to remove them when the profile is
+generated. The profile format provides a mechanism to identify these frames by
+name, through regular expressions.
+
+These expressions must match the function name in its entirety. Frames that
+match Profile.drop\_frames will be dropped from the profile, along with any
+frames below it. Frames that match Profile.keep\_frames will be kept, even if
+they match drop\_frames.
+
diff --git a/src/cmd/vendor/github.com/google/pprof/doc/pprof.md b/src/cmd/vendor/github.com/google/pprof/doc/pprof.md
new file mode 100644
index 0000000..d2c7e26
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/doc/pprof.md
@@ -0,0 +1,210 @@
+# pprof
+
+pprof is a tool for visualization and analysis of profiling data.
+
+pprof reads a collection of profiling samples in profile.proto format and
+generates reports to visualize and help analyze the data. It can generate both
+text and graphical reports (through the use of the dot visualization package).
+
+profile.proto is a protocol buffer that describes a set of callstacks
+and symbolization information. A common usage is to represent a set of
+sampled callstacks from statistical profiling. The format is
+described on the src/proto/profile.proto file. For details on protocol
+buffers, see https://developers.google.com/protocol-buffers
+
+Profiles can be read from a local file, or over http. Multiple
+profiles of the same type can be aggregated or compared.
+
+If the profile samples contain machine addresses, pprof can symbolize
+them through the use of the native binutils tools (addr2line and nm).
+
+# pprof profiles
+
+pprof operates on data in the profile.proto format. Each profile is a collection
+of samples, where each sample is associated to a point in a location hierarchy,
+one or more numeric values, and a set of labels. Often these profiles represents
+data collected through statistical sampling of a program, so each sample
+describes a program call stack and a number or weight of samples collected at a
+location. pprof is agnostic to the profile semantics, so other uses are
+possible. The interpretation of the reports generated by pprof depends on the
+semantics defined by the source of the profile.
+
+# General usage
+
+The objective of pprof is to generate a report for a profile. The report is
+generated from a location hierarchy, which is reconstructed from the profile
+samples. Each location contains two values: *flat* is the value of the location
+itself, while *cum* is the value of the location plus all its
+descendants. Samples that include a location multiple times (eg for recursive
+functions) are counted only once per location.
+
+The basic usage of pprof is
+
+    pprof <format> [options] source
+
+Where *format* selects the nature of the report, and *options* configure the
+contents of the report. Each option has a value, which can be boolean, numeric,
+or strings. While only one format can be specified, most options can be selected
+independently of each other.
+
+Some common pprof options are:
+
+* **-flat [default]:** Sort entries based on their flat weight, on text reports.
+* **-cum:** Sort entries based on cumulative weight, on text reports.
+* **-functions [default]:** Accumulate samples at the function level; profile
+  locations that describe the same function will be merged into a report entry.
+* **-lines:** Accumulate samples at the source line level; profile locations that
+  describe the same function will be merged into a report entry.
+* **-addresses:** Accumulate samples at the instruction address; profile locations
+  that describe the same function address will be merged into a report entry.
+* **-nodecount= _int_:** Maximum number of entries in the report. pprof will only print
+  this many entries and will use heuristics to select which entries to trim.
+* **-focus= _regex_:** Only include samples that include a report entry matching
+  *regex*.
+* **-ignore= _regex_:** Do not include samples that include a report entry matching
+  *regex*.
+* **-show= _regex_:** Only show entries that match *regex*.
+* **-hide= _regex_:** Do not show entries that match *regex*.
+
+Each sample in a profile may include multiple values, representing different
+entities associated to the sample. pprof reports include a single sample value,
+which by convention is the last one specified in the report. The `sample_index=`
+option selects which value to use, and can be set to a number (from 0 to the
+number of values - 1) or the name of the sample value.
+
+Sample values are numeric values associated to a unit. If pprof can recognize
+these units, it will attempt to scale the values to a suitable unit for
+visualization. The `unite=` option will force the use of a specific unit. For
+example, `sample_index=sec` will force any time values to be reported in
+seconds. pprof recognizes most common time and memory size units.
+
+## Text reports
+
+pprof text reports show the location hierarchy in text format.
+
+* **-text:** Prints the location entries, one per line, including the flat and cum
+  values.
+* **-tree:** Prints each location entry with its predecessors and successors.
+* **-peek= _regex_:** Print the location entry with all its predecessors and
+  successors, without trimming any entries.
+* **-traces:** Prints each sample with a location per line.
+
+## Graphical reports
+
+pprof can generate graphical reports on the DOT format, and convert them to
+multiple formats using the graphviz package.
+
+These reports represent the location hierarchy as a graph, with a report entry
+represented as a node. Solid edges represent a direct connection between
+entries, while dotted edges represent a connection where some intermediate nodes
+have been removed. Nodes are removed using heuristics to limit the size of
+the graph, controlled by the *nodecount* option.
+
+The size of each node represents the flat weight of the node, and the width of
+each edge represents the cumulative weight of all samples going through
+it. Nodes are colored according to their cumulative weight, highlighting the
+paths with the highest cum weight.
+
+* **-dot:** Generates a report in .dot format. All other formats are generated from
+  this one.
+* **-svg:** Generates a report in SVG format.
+* **-web:** Generates a report in SVG format on a temp file, and starts a web
+  browser to view it.
+* **-png, -jpg, -gif, -pdf:** Generates a report in these formats,
+
+## Annotated code
+
+pprof can also generate reports of annotated source with samples associated to
+them. For these, the source or binaries must be locally available, and the
+profile must contain data with the appropriate level of detail.
+
+pprof will look for source files on its current working directory and all its
+ancestors. pprof will look for binaries on the directories specified in the
+`$PPROF_BINARY_PATH` environment variable, by default `$HOME/pprof/binaries`
+(`%USERPROFILE%\pprof\binaries` on Windows). It will look binaries up by name,
+and if the profile includes linker build ids, it will also search for them in
+a directory named as the build id.
+
+pprof uses the binutils tools to examine and disassemble the binaries. By
+default it will search for those tools in the current path, but it can also
+search for them in a directory pointed to by the environment variable
+`$PPROF_TOOLS`.
+
+* **-disasm= _regex_:** Generates an annotated source listing for functions matching
+  regex, with flat/cum weights for each source line.
+* **-list= _regex_:** Generates an annotated disassembly listing for functions
+  matching *regex*.
+* **-weblist= _regex_:** Generates a source/assembly combined annotated listing for
+  functions matching *regex*, and starts a web browser to display it.
+
+# Fetching profiles
+
+pprof can read profiles from a file or directly from a URL over http. Its native
+format is a gzipped profile.proto file, but it can also accept some legacy
+formats generated by [gperftools](https://github.com/gperftools/gperftools).
+
+When fetching from a URL handler, pprof accepts options to indicate how much to
+wait for the profile.
+
+* **-seconds= _int_:** Makes pprof request for a profile with the specified duration
+  in seconds. Only makes sense for profiles based on elapsed time, such as CPU
+  profiles.
+* **-timeout= _int_:** Makes pprof wait for the specified timeout when retrieving a
+  profile over http. If not specified, pprof will use heuristics to determine a
+  reasonable timeout.
+
+If multiple profiles are specified, pprof will fetch them all and merge
+them. This is useful to combine profiles from multiple processes of a
+distributed job. The profiles may be from different programs but must be
+compatible (for example, CPU profiles cannot be combined with heap profiles).
+
+pprof can subtract a profile from another in order to compare them. For that,
+use the **-base= _profile_** option, where *profile* is the filename or URL for the
+profile to be subtracted. This may result on some report entries having negative
+values.
+
+## Symbolization
+
+pprof can add symbol information to a profile that was collected only with
+address information. This is useful for profiles for compiled languages, where
+it may not be easy or even possible for the profile source to include function
+names or source coordinates.
+
+pprof can extract the symbol information locally by examining the binaries using
+the binutils tools, or it can ask running jobs that provide a symbolization
+interface.
+
+pprof will attempt symbolizing profiles by default, and its `-symbolize` option
+provides some control over symbolization:
+
+* **-symbolize=none:** Disables any symbolization from pprof.
+
+* **-symbolize=local:** Only attempts symbolizing the profile from local
+  binaries using the binutils tools.
+
+* **-symbolize=remote:** Only attempts to symbolize running jobs by contacting
+  their symbolization handler.
+
+For local symbolization, pprof will look for the binaries on the paths specified
+by the profile, and then it will search for them on the path specified by the
+environment variable `$PPROF_BINARY_PATH`. Also, the name of the main binary can
+be passed directly to pprof as its first parameter, to override the name or
+location of the main binary of the profile, like this:
+
+    pprof /path/to/binary profile.pb.gz
+
+By default pprof will attempt to demangle and simplify C++ names, to provide
+readable names for C++ symbols. It will aggressively discard template and
+function parameters. This can be controlled with the `-symbolize=demangle`
+option. Note that for remote symbolization mangled names may not be provided by
+the symbolization handler.
+
+* **--symbolize=demangle=none:** Do not perform any demangling. Show mangled
+  names if available.
+
+* **-symbolize=demangle=full:** Demangle, but do not perform any
+  simplification. Show full demangled names if available.
+
+* **-symbolize=demangle=templates:** Demangle, and trim function parameters, but
+  not template parameters.
+
diff --git a/src/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
new file mode 100644
index 0000000..d01d0fa
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
@@ -0,0 +1,281 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package driver provides an external entry point to the pprof driver.
+package driver
+
+import (
+	"io"
+	"regexp"
+	"time"
+
+	internaldriver "github.com/google/pprof/internal/driver"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/profile"
+)
+
+// 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(o *Options) error {
+	return internaldriver.PProf(o.InternalOptions())
+}
+
+func (o *Options) InternalOptions() *plugin.Options {
+	var obj plugin.ObjTool
+	if o.Obj != nil {
+		obj = &internalObjTool{o.Obj}
+	}
+	var sym plugin.Symbolizer
+	if o.Sym != nil {
+		sym = &internalSymbolizer{o.Sym}
+	}
+	return &plugin.Options{
+		Writer:  o.Writer,
+		Flagset: o.Flagset,
+		Fetch:   o.Fetch,
+		Sym:     sym,
+		Obj:     obj,
+		UI:      o.UI,
+	}
+}
+
+// Options groups all the optional plugins into pprof.
+type Options struct {
+	Writer  Writer
+	Flagset FlagSet
+	Fetch   Fetcher
+	Sym     Symbolizer
+	Obj     ObjTool
+	UI      UI
+}
+
+// Writer provides a mechanism to write data under a certain name,
+// typically a filename.
+type Writer interface {
+	Open(name string) (io.WriteCloser, error)
+}
+
+// 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
+
+	// BoolVar, IntVar, Float64Var, and StringVar define new flags referencing
+	// a given pointer, like the functions of the same name in package flag.
+	BoolVar(pointer *bool, name string, def bool, usage string)
+	IntVar(pointer *int, name string, def int, usage string)
+	Float64Var(pointer *float64, name string, def float64, usage string)
+	StringVar(pointer *string, name string, def string, usage string)
+
+	// StringList is similar to String but allows multiple values for a
+	// single flag
+	StringList(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
+}
+
+// A Fetcher reads and returns the profile named by src, using
+// the specified duration and timeout. It returns the fetched
+// profile and a string indicating a URL from where the profile
+// was fetched, which may be different than src.
+type Fetcher interface {
+	Fetch(src string, duration, timeout time.Duration) (*profile.Profile, string, error)
+}
+
+// A Symbolizer introduces symbol information into a profile.
+type Symbolizer interface {
+	Symbolize(mode string, srcs MappingSources, prof *profile.Profile) error
+}
+
+// MappingSources map each profile.Mapping to the source of the profile.
+// The key is either Mapping.File or Mapping.BuildId.
+type MappingSources map[string][]struct {
+	Source string // URL of the source the mapping was collected from
+	Start  uint64 // delta applied to addresses from this source (to represent Merge adjustments)
+}
+
+// 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/limit/offset are the addresses where it is mapped
+	// into memory in the address space being inspected.
+	Open(file string, start, limit, offset uint64) (ObjFile, 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)
+}
+
+// An Inst is a single instruction in an assembly listing.
+type Inst struct {
+	Addr     uint64 // virtual address of instruction
+	Text     string // instruction text
+	Function string // function name
+	File     string // source file
+	Line     int    // source line
+}
+
+// An ObjFile is a single object file: a shared library or executable.
+type ObjFile interface {
+	// Name returns the underlying 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)
+}
+
+// A UI manages user interactions.
+type UI interface {
+	// Read returns a line of text (a command) read from the user.
+	// prompt is printed before reading the command.
+	ReadLine(prompt string) (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)
+}
+
+// internalObjTool is a wrapper to map from the pprof external
+// interface to the internal interface.
+type internalObjTool struct {
+	ObjTool
+}
+
+func (o *internalObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	f, err := o.ObjTool.Open(file, start, limit, offset)
+	if err != nil {
+		return nil, err
+	}
+	return &internalObjFile{f}, err
+}
+
+type internalObjFile struct {
+	ObjFile
+}
+
+func (f *internalObjFile) SourceLine(frame uint64) ([]plugin.Frame, error) {
+	frames, err := f.ObjFile.SourceLine(frame)
+	if err != nil {
+		return nil, err
+	}
+	var pluginFrames []plugin.Frame
+	for _, f := range frames {
+		pluginFrames = append(pluginFrames, plugin.Frame(f))
+	}
+	return pluginFrames, nil
+}
+
+func (f *internalObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+	syms, err := f.ObjFile.Symbols(r, addr)
+	if err != nil {
+		return nil, err
+	}
+	var pluginSyms []*plugin.Sym
+	for _, s := range syms {
+		ps := plugin.Sym(*s)
+		pluginSyms = append(pluginSyms, &ps)
+	}
+	return pluginSyms, nil
+}
+
+func (o *internalObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+	insts, err := o.ObjTool.Disasm(file, start, end)
+	if err != nil {
+		return nil, err
+	}
+	var pluginInst []plugin.Inst
+	for _, inst := range insts {
+		pluginInst = append(pluginInst, plugin.Inst(inst))
+	}
+	return pluginInst, nil
+}
+
+// internalSymbolizer is a wrapper to map from the pprof external
+// interface to the internal interface.
+type internalSymbolizer struct {
+	Symbolizer
+}
+
+func (s *internalSymbolizer) Symbolize(mode string, srcs plugin.MappingSources, prof *profile.Profile) error {
+	isrcs := plugin.MappingSources{}
+	for m, s := range srcs {
+		isrcs[m] = s
+	}
+	return s.Symbolize(mode, isrcs, prof)
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go
new file mode 100644
index 0000000..e3a7777
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go
@@ -0,0 +1,222 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"os/exec"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/plugin"
+)
+
+const (
+	defaultAddr2line = "addr2line"
+
+	// addr2line may produce multiple lines of output. We
+	// use this sentinel to identify the end of the output.
+	sentinel = ^uint64(0)
+)
+
+// addr2Liner is a connection to an addr2line command for obtaining
+// address and line number information from a binary.
+type addr2Liner struct {
+	rw   lineReaderWriter
+	base uint64
+
+	// nm holds an NM based addr2Liner which can provide
+	// better full names compared to addr2line, which often drops
+	// namespaces etc. from the names it returns.
+	nm *addr2LinerNM
+}
+
+// lineReaderWriter is an interface to abstract the I/O to an addr2line
+// process. It writes a line of input to the job, and reads its output
+// one line at a time.
+type lineReaderWriter interface {
+	write(string) error
+	readLine() (string, error)
+	close()
+}
+
+type addr2LinerJob struct {
+	cmd *exec.Cmd
+	in  io.WriteCloser
+	out *bufio.Reader
+}
+
+func (a *addr2LinerJob) write(s string) error {
+	_, err := fmt.Fprint(a.in, s+"\n")
+	return err
+}
+
+func (a *addr2LinerJob) readLine() (string, error) {
+	return a.out.ReadString('\n')
+}
+
+// close releases any resources used by the addr2liner object.
+func (a *addr2LinerJob) close() {
+	a.in.Close()
+	a.cmd.Wait()
+}
+
+// newAddr2liner starts the given addr2liner command reporting
+// information about the given executable file. If file is a shared
+// library, base should be the address at which it was mapped in the
+// program under consideration.
+func newAddr2Liner(cmd, file string, base uint64) (*addr2Liner, error) {
+	if cmd == "" {
+		cmd = defaultAddr2line
+	}
+
+	j := &addr2LinerJob{
+		cmd: exec.Command(cmd, "-aif", "-e", file),
+	}
+
+	var err error
+	if j.in, err = j.cmd.StdinPipe(); err != nil {
+		return nil, err
+	}
+
+	outPipe, err := j.cmd.StdoutPipe()
+	if err != nil {
+		return nil, err
+	}
+
+	j.out = bufio.NewReader(outPipe)
+	if err := j.cmd.Start(); err != nil {
+		return nil, err
+	}
+
+	a := &addr2Liner{
+		rw:   j,
+		base: base,
+	}
+
+	return a, nil
+}
+
+func (d *addr2Liner) readString() (string, error) {
+	s, err := d.rw.readLine()
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(s), nil
+}
+
+// readFrame parses the addr2line output for a single address. It
+// returns a populated plugin.Frame and whether it has reached the end of the
+// data.
+func (d *addr2Liner) readFrame() (plugin.Frame, bool) {
+	funcname, err := d.readString()
+	if err != nil {
+		return plugin.Frame{}, true
+	}
+	if strings.HasPrefix(funcname, "0x") {
+		// If addr2line returns a hex address we can assume it is the
+		// sentinel. Read and ignore next two lines of output from
+		// addr2line
+		d.readString()
+		d.readString()
+		return plugin.Frame{}, true
+	}
+
+	fileline, err := d.readString()
+	if err != nil {
+		return plugin.Frame{}, true
+	}
+
+	linenumber := 0
+
+	if funcname == "??" {
+		funcname = ""
+	}
+
+	if fileline == "??:0" {
+		fileline = ""
+	} else {
+		if i := strings.LastIndex(fileline, ":"); i >= 0 {
+			// Remove discriminator, if present
+			if disc := strings.Index(fileline, " (discriminator"); disc > 0 {
+				fileline = fileline[:disc]
+			}
+			// If we cannot parse a number after the last ":", keep it as
+			// part of the filename.
+			if line, err := strconv.Atoi(fileline[i+1:]); err == nil {
+				linenumber = line
+				fileline = fileline[:i]
+			}
+		}
+	}
+
+	return plugin.Frame{
+		Func: funcname,
+		File: fileline,
+		Line: linenumber}, false
+}
+
+// addrInfo returns the stack frame information for a specific program
+// address. It returns nil if the address could not be identified.
+func (d *addr2Liner) addrInfo(addr uint64) ([]plugin.Frame, error) {
+	if err := d.rw.write(fmt.Sprintf("%x", addr-d.base)); err != nil {
+		return nil, err
+	}
+
+	if err := d.rw.write(fmt.Sprintf("%x", sentinel)); err != nil {
+		return nil, err
+	}
+
+	resp, err := d.readString()
+	if err != nil {
+		return nil, err
+	}
+
+	if !strings.HasPrefix(resp, "0x") {
+		return nil, fmt.Errorf("unexpected addr2line output: %s", resp)
+	}
+
+	var stack []plugin.Frame
+	for {
+		frame, end := d.readFrame()
+		if end {
+			break
+		}
+
+		if frame != (plugin.Frame{}) {
+			stack = append(stack, frame)
+		}
+	}
+
+	// Get better name from nm if possible.
+	if len(stack) > 0 && d.nm != nil {
+		nm, err := d.nm.addrInfo(addr)
+		if err == nil && len(nm) > 0 {
+			// Last entry in frame list should match since
+			// it is non-inlined. As a simple heuristic,
+			// we only switch to the nm-based name if it
+			// is longer.
+			nmName := nm[len(nm)-1].Func
+			a2lName := stack[len(stack)-1].Func
+			if len(nmName) > len(a2lName) {
+				stack[len(stack)-1].Func = nmName
+			}
+		}
+	}
+
+	return stack, nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
new file mode 100644
index 0000000..7692b0a
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
@@ -0,0 +1,170 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"os/exec"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/plugin"
+)
+
+const (
+	defaultLLVMSymbolizer = "llvm-symbolizer"
+)
+
+// llvmSymbolizer is a connection to an llvm-symbolizer command for
+// obtaining address and line number information from a binary.
+type llvmSymbolizer struct {
+	filename string
+	rw       lineReaderWriter
+	base     uint64
+}
+
+type llvmSymbolizerJob struct {
+	cmd *exec.Cmd
+	in  io.WriteCloser
+	out *bufio.Reader
+}
+
+func (a *llvmSymbolizerJob) write(s string) error {
+	_, err := fmt.Fprint(a.in, s+"\n")
+	return err
+}
+
+func (a *llvmSymbolizerJob) readLine() (string, error) {
+	return a.out.ReadString('\n')
+}
+
+// close releases any resources used by the llvmSymbolizer object.
+func (a *llvmSymbolizerJob) close() {
+	a.in.Close()
+	a.cmd.Wait()
+}
+
+// newLlvmSymbolizer starts the given llvmSymbolizer command reporting
+// information about the given executable file. If file is a shared
+// library, base should be the address at which it was mapped in the
+// program under consideration.
+func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) {
+	if cmd == "" {
+		cmd = defaultLLVMSymbolizer
+	}
+
+	j := &llvmSymbolizerJob{
+		cmd: exec.Command(cmd, "-inlining", "-demangle=false"),
+	}
+
+	var err error
+	if j.in, err = j.cmd.StdinPipe(); err != nil {
+		return nil, err
+	}
+
+	outPipe, err := j.cmd.StdoutPipe()
+	if err != nil {
+		return nil, err
+	}
+
+	j.out = bufio.NewReader(outPipe)
+	if err := j.cmd.Start(); err != nil {
+		return nil, err
+	}
+
+	a := &llvmSymbolizer{
+		filename: file,
+		rw:       j,
+		base:     base,
+	}
+
+	return a, nil
+}
+
+func (d *llvmSymbolizer) readString() (string, error) {
+	s, err := d.rw.readLine()
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(s), nil
+}
+
+// readFrame parses the llvm-symbolizer output for a single address. It
+// returns a populated plugin.Frame and whether it has reached the end of the
+// data.
+func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) {
+	funcname, err := d.readString()
+	if err != nil {
+		return plugin.Frame{}, true
+	}
+
+	switch funcname {
+	case "":
+		return plugin.Frame{}, true
+	case "??":
+		funcname = ""
+	}
+
+	fileline, err := d.readString()
+	if err != nil {
+		return plugin.Frame{Func: funcname}, true
+	}
+
+	linenumber := 0
+	if fileline == "??:0" {
+		fileline = ""
+	} else {
+		switch split := strings.Split(fileline, ":"); len(split) {
+		case 1:
+			// filename
+			fileline = split[0]
+		case 2, 3:
+			// filename:line , or
+			// filename:line:disc , or
+			fileline = split[0]
+			if line, err := strconv.Atoi(split[1]); err == nil {
+				linenumber = line
+			}
+		default:
+			// Unrecognized, ignore
+		}
+	}
+
+	return plugin.Frame{Func: funcname, File: fileline, Line: linenumber}, false
+}
+
+// addrInfo returns the stack frame information for a specific program
+// address. It returns nil if the address could not be identified.
+func (d *llvmSymbolizer) addrInfo(addr uint64) ([]plugin.Frame, error) {
+	if err := d.rw.write(fmt.Sprintf("%s 0x%x", d.filename, addr-d.base)); err != nil {
+		return nil, err
+	}
+
+	var stack []plugin.Frame
+	for {
+		frame, end := d.readFrame()
+		if end {
+			break
+		}
+
+		if frame != (plugin.Frame{}) {
+			stack = append(stack, frame)
+		}
+	}
+
+	return stack, nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
new file mode 100644
index 0000000..e7a8e10
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
@@ -0,0 +1,123 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"bufio"
+	"bytes"
+	"io"
+	"os/exec"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/plugin"
+)
+
+const (
+	defaultNM = "nm"
+)
+
+// addr2LinerNM is a connection to an nm command for obtaining address
+// information from a binary.
+type addr2LinerNM struct {
+	m []symbolInfo // Sorted list of addresses from binary.
+}
+
+type symbolInfo struct {
+	address uint64
+	name    string
+}
+
+//  newAddr2LinerNM starts the given nm command reporting information about the
+// given executable file. If file is a shared library, base should be
+// the address at which it was mapped in the program under
+// consideration.
+func newAddr2LinerNM(cmd, file string, base uint64) (*addr2LinerNM, error) {
+	if cmd == "" {
+		cmd = defaultNM
+	}
+
+	a := &addr2LinerNM{
+		m: []symbolInfo{},
+	}
+
+	var b bytes.Buffer
+	c := exec.Command(cmd, "-n", file)
+	c.Stdout = &b
+
+	if err := c.Run(); err != nil {
+		return nil, err
+	}
+
+	// Parse nm output and populate symbol map.
+	// Skip lines we fail to parse.
+	buf := bufio.NewReader(&b)
+	for {
+		line, err := buf.ReadString('\n')
+		if line == "" && err != nil {
+			if err == io.EOF {
+				break
+			}
+			return nil, err
+		}
+		line = strings.TrimSpace(line)
+		fields := strings.SplitN(line, " ", 3)
+		if len(fields) != 3 {
+			continue
+		}
+		address, err := strconv.ParseUint(fields[0], 16, 64)
+		if err != nil {
+			continue
+		}
+		a.m = append(a.m, symbolInfo{
+			address: address + base,
+			name:    fields[2],
+		})
+	}
+
+	return a, nil
+}
+
+// addrInfo returns the stack frame information for a specific program
+// address. It returns nil if the address could not be identified.
+func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) {
+	if len(a.m) == 0 || addr < a.m[0].address || addr > a.m[len(a.m)-1].address {
+		return nil, nil
+	}
+
+	// Binary search. Search until low, high are separated by 1.
+	low, high := 0, len(a.m)
+	for low+1 < high {
+		mid := (low + high) / 2
+		v := a.m[mid].address
+		if addr == v {
+			low = mid
+			break
+		} else if addr > v {
+			low = mid
+		} else {
+			high = mid
+		}
+	}
+
+	// Address is between a.m[low] and a.m[high].
+	// Pick low, as it represents [low, high).
+	f := []plugin.Frame{
+		{
+			Func: a.m[low].name,
+		},
+	}
+	return f, nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
new file mode 100644
index 0000000..9854c9a
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
@@ -0,0 +1,305 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package binutils provides access to the GNU binutils.
+package binutils
+
+import (
+	"debug/elf"
+	"debug/macho"
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+
+	"github.com/google/pprof/internal/elfexec"
+	"github.com/google/pprof/internal/plugin"
+)
+
+// A Binutils implements plugin.ObjTool by invoking the GNU binutils.
+// SetConfig must be called before any of the other methods.
+type Binutils struct {
+	// Commands to invoke.
+	llvmSymbolizer      string
+	llvmSymbolizerFound bool
+	addr2line           string
+	addr2lineFound      bool
+	nm                  string
+	nmFound             bool
+	objdump             string
+	objdumpFound        bool
+
+	// if fast, perform symbolization using nm (symbol names only),
+	// instead of file-line detail from the slower addr2line.
+	fast bool
+}
+
+// SetFastSymbolization sets a toggle that makes binutils use fast
+// symbolization (using nm), which is much faster than addr2line but
+// provides only symbol name information (no file/line).
+func (b *Binutils) SetFastSymbolization(fast bool) {
+	b.fast = fast
+}
+
+// SetTools processes the contents of the tools option. It
+// expects a set of entries separated by commas; each entry is a pair
+// of the form t:path, where cmd will be used to look only for the
+// tool named t. If t is not specified, the path is searched for all
+// tools.
+func (b *Binutils) SetTools(config string) {
+	// paths collect paths per tool; Key "" contains the default.
+	paths := make(map[string][]string)
+	for _, t := range strings.Split(config, ",") {
+		name, path := "", t
+		if ct := strings.SplitN(t, ":", 2); len(ct) == 2 {
+			name, path = ct[0], ct[1]
+		}
+		paths[name] = append(paths[name], path)
+	}
+
+	defaultPath := paths[""]
+	b.llvmSymbolizer, b.llvmSymbolizerFound = findExe("llvm-symbolizer", append(paths["llvm-symbolizer"], defaultPath...))
+	b.addr2line, b.addr2lineFound = findExe("addr2line", append(paths["addr2line"], defaultPath...))
+	b.nm, b.nmFound = findExe("nm", append(paths["nm"], defaultPath...))
+	b.objdump, b.objdumpFound = findExe("objdump", append(paths["objdump"], defaultPath...))
+}
+
+// findExe looks for an executable command on a set of paths.
+// If it cannot find it, returns cmd.
+func findExe(cmd string, paths []string) (string, bool) {
+	for _, p := range paths {
+		cp := filepath.Join(p, cmd)
+		if c, err := exec.LookPath(cp); err == nil {
+			return c, true
+		}
+	}
+	return cmd, false
+}
+
+// Disasm returns the assembly instructions for the specified address range
+// of a binary.
+func (b *Binutils) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+	if b.addr2line == "" {
+		// Update the command invocations if not initialized.
+		b.SetTools("")
+	}
+	cmd := exec.Command(b.objdump, "-d", "-C", "--no-show-raw-insn", "-l",
+		fmt.Sprintf("--start-address=%#x", start),
+		fmt.Sprintf("--stop-address=%#x", end),
+		file)
+	out, err := cmd.Output()
+	if err != nil {
+		return nil, fmt.Errorf("%v: %v", cmd.Args, err)
+	}
+
+	return disassemble(out)
+}
+
+// Open satisfies the plugin.ObjTool interface.
+func (b *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	if b.addr2line == "" {
+		// Update the command invocations if not initialized.
+		b.SetTools("")
+	}
+
+	// Make sure file is a supported executable.
+	// The pprof driver uses Open to sniff the difference
+	// between an executable and a profile.
+	// For now, only ELF is supported.
+	// Could read the first few bytes of the file and
+	// use a table of prefixes if we need to support other
+	// systems at some point.
+
+	if _, err := os.Stat(name); err != nil {
+		// For testing, do not require file name to exist.
+		if strings.Contains(b.addr2line, "testdata/") {
+			return &fileAddr2Line{file: file{b: b, name: name}}, nil
+		}
+		return nil, err
+	}
+
+	if f, err := b.openELF(name, start, limit, offset); err == nil {
+		return f, nil
+	}
+	if f, err := b.openMachO(name, start, limit, offset); err == nil {
+		return f, nil
+	}
+	return nil, fmt.Errorf("unrecognized binary: %s", name)
+}
+
+func (b *Binutils) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	of, err := macho.Open(name)
+	if err != nil {
+		return nil, fmt.Errorf("Parsing %s: %v", name, err)
+	}
+	defer of.Close()
+
+	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
+		return &fileNM{file: file{b: b, name: name}}, nil
+	}
+	return &fileAddr2Line{file: file{b: b, name: name}}, nil
+}
+
+func (b *Binutils) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	ef, err := elf.Open(name)
+	if err != nil {
+		return nil, fmt.Errorf("Parsing %s: %v", name, err)
+	}
+	defer ef.Close()
+
+	var stextOffset *uint64
+	var pageAligned = func(addr uint64) bool { return addr%4096 == 0 }
+	if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) {
+		// Reading all Symbols is expensive, and we only rarely need it so
+		// we don't want to do it every time. But if _stext happens to be
+		// page-aligned but isn't the same as Vaddr, we would symbolize
+		// wrong. So if the name the addresses aren't page aligned, or if
+		// the name is "vmlinux" we read _stext. We can be wrong if: (1)
+		// someone passes a kernel path that doesn't contain "vmlinux" AND
+		// (2) _stext is page-aligned AND (3) _stext is not at Vaddr
+		symbols, err := ef.Symbols()
+		if err != nil {
+			return nil, err
+		}
+		for _, s := range symbols {
+			if s.Name == "_stext" {
+				// The kernel may use _stext as the mapping start address.
+				stextOffset = &s.Value
+				break
+			}
+		}
+	}
+
+	base, err := elfexec.GetBase(&ef.FileHeader, nil, stextOffset, start, limit, offset)
+	if err != nil {
+		return nil, fmt.Errorf("Could not identify base for %s: %v", name, err)
+	}
+
+	buildID := ""
+	if f, err := os.Open(name); err == nil {
+		if id, err := elfexec.GetBuildID(f); err == nil {
+			buildID = fmt.Sprintf("%x", id)
+		}
+	}
+	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
+		return &fileNM{file: file{b, name, base, buildID}}, nil
+	}
+	return &fileAddr2Line{file: file{b, name, base, buildID}}, nil
+}
+
+// file implements the binutils.ObjFile interface.
+type file struct {
+	b       *Binutils
+	name    string
+	base    uint64
+	buildID string
+}
+
+func (f *file) Name() string {
+	return f.name
+}
+
+func (f *file) Base() uint64 {
+	return f.base
+}
+
+func (f *file) BuildID() string {
+	return f.buildID
+}
+
+func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	return []plugin.Frame{}, nil
+}
+
+func (f *file) Close() error {
+	return nil
+}
+
+func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+	// Get from nm a list of symbols sorted by address.
+	cmd := exec.Command(f.b.nm, "-n", f.name)
+	out, err := cmd.Output()
+	if err != nil {
+		return nil, fmt.Errorf("%v: %v", cmd.Args, err)
+	}
+
+	return findSymbols(out, f.name, r, addr)
+}
+
+// fileNM implements the binutils.ObjFile interface, using 'nm' to map
+// addresses to symbols (without file/line number information). It is
+// faster than fileAddr2Line.
+type fileNM struct {
+	file
+	addr2linernm *addr2LinerNM
+}
+
+func (f *fileNM) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	if f.addr2linernm == nil {
+		addr2liner, err := newAddr2LinerNM(f.b.nm, f.name, f.base)
+		if err != nil {
+			return nil, err
+		}
+		f.addr2linernm = addr2liner
+	}
+	return f.addr2linernm.addrInfo(addr)
+}
+
+// fileAddr2Line implements the binutils.ObjFile interface, using
+// 'addr2line' to map addresses to symbols (with file/line number
+// information). It can be slow for large binaries with debug
+// information.
+type fileAddr2Line struct {
+	file
+	addr2liner     *addr2Liner
+	llvmSymbolizer *llvmSymbolizer
+}
+
+func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	if f.llvmSymbolizer != nil {
+		return f.llvmSymbolizer.addrInfo(addr)
+	}
+	if f.addr2liner != nil {
+		return f.addr2liner.addrInfo(addr)
+	}
+
+	if llvmSymbolizer, err := newLLVMSymbolizer(f.b.llvmSymbolizer, f.name, f.base); err == nil {
+		f.llvmSymbolizer = llvmSymbolizer
+		return f.llvmSymbolizer.addrInfo(addr)
+	}
+
+	if addr2liner, err := newAddr2Liner(f.b.addr2line, f.name, f.base); err == nil {
+		f.addr2liner = addr2liner
+
+		// When addr2line encounters some gcc compiled binaries, it
+		// drops interesting parts of names in anonymous namespaces.
+		// Fallback to NM for better function names.
+		if nm, err := newAddr2LinerNM(f.b.nm, f.name, f.base); err == nil {
+			f.addr2liner.nm = nm
+		}
+		return f.addr2liner.addrInfo(addr)
+	}
+
+	return nil, fmt.Errorf("could not find local addr2liner")
+}
+
+func (f *fileAddr2Line) Close() error {
+	if f.addr2liner != nil {
+		f.addr2liner.rw.close()
+		f.addr2liner = nil
+	}
+	return nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go
new file mode 100644
index 0000000..b0ba5f6
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go
@@ -0,0 +1,152 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/pprof/internal/plugin"
+)
+
+var testAddrMap = map[int]string{
+	1000: "_Z3fooid.clone2",
+	2000: "_ZNSaIiEC1Ev.clone18",
+	3000: "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm",
+}
+
+func functionName(level int) (name string) {
+	if name = testAddrMap[level]; name != "" {
+		return name
+	}
+	return fmt.Sprintf("fun%d", level)
+}
+
+func TestAddr2Liner(t *testing.T) {
+	const offset = 0x500
+
+	a := addr2Liner{&mockAddr2liner{}, offset, nil}
+	for i := 1; i < 8; i++ {
+		addr := i*0x1000 + offset
+		s, err := a.addrInfo(uint64(addr))
+		if err != nil {
+			t.Fatalf("addrInfo(%#x): %v", addr, err)
+		}
+		if len(s) != i {
+			t.Fatalf("addrInfo(%#x): got len==%d, want %d", addr, len(s), i)
+		}
+		for l, f := range s {
+			level := (len(s) - l) * 1000
+			want := plugin.Frame{Func: functionName(level), File: fmt.Sprintf("file%d", level), Line: level}
+
+			if f != want {
+				t.Errorf("AddrInfo(%#x)[%d]: = %+v, want %+v", addr, l, f, want)
+			}
+		}
+	}
+	s, err := a.addrInfo(0xFFFF)
+	if err != nil {
+		t.Fatalf("addrInfo(0xFFFF): %v", err)
+	}
+	if len(s) != 0 {
+		t.Fatalf("AddrInfo(0xFFFF): got len==%d, want 0", len(s))
+	}
+	a.rw.close()
+}
+
+type mockAddr2liner struct {
+	output []string
+}
+
+func (a *mockAddr2liner) write(s string) error {
+	var lines []string
+	switch s {
+	case "1000":
+		lines = []string{"_Z3fooid.clone2", "file1000:1000"}
+	case "2000":
+		lines = []string{"_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "3000":
+		lines = []string{"_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "4000":
+		lines = []string{"fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "5000":
+		lines = []string{"fun5000", "file5000:5000", "fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "6000":
+		lines = []string{"fun6000", "file6000:6000", "fun5000", "file5000:5000", "fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "7000":
+		lines = []string{"fun7000", "file7000:7000", "fun6000", "file6000:6000", "fun5000", "file5000:5000", "fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "8000":
+		lines = []string{"fun8000", "file8000:8000", "fun7000", "file7000:7000", "fun6000", "file6000:6000", "fun5000", "file5000:5000", "fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	case "9000":
+		lines = []string{"fun9000", "file9000:9000", "fun8000", "file8000:8000", "fun7000", "file7000:7000", "fun6000", "file6000:6000", "fun5000", "file5000:5000", "fun4000", "file4000:4000", "_ZNSt6vectorIS_IS_IiSaIiEESaIS1_EESaIS3_EEixEm", "file3000:3000", "_ZNSaIiEC1Ev.clone18", "file2000:2000", "_Z3fooid.clone2", "file1000:1000"}
+	default:
+		lines = []string{"??", "??:0"}
+	}
+	a.output = append(a.output, "0x"+s)
+	a.output = append(a.output, lines...)
+	return nil
+}
+
+func (a *mockAddr2liner) readLine() (string, error) {
+	if len(a.output) == 0 {
+		return "", fmt.Errorf("end of file")
+	}
+	next := a.output[0]
+	a.output = a.output[1:]
+	return next, nil
+}
+
+func (a *mockAddr2liner) close() {
+}
+
+func TestAddr2LinerLookup(t *testing.T) {
+	oddSizedMap := addr2LinerNM{
+		m: []symbolInfo{
+			{0x1000, "0x1000"},
+			{0x2000, "0x2000"},
+			{0x3000, "0x3000"},
+		},
+	}
+	evenSizedMap := addr2LinerNM{
+		m: []symbolInfo{
+			{0x1000, "0x1000"},
+			{0x2000, "0x2000"},
+			{0x3000, "0x3000"},
+			{0x4000, "0x4000"},
+		},
+	}
+	for _, a := range []*addr2LinerNM{
+		&oddSizedMap, &evenSizedMap,
+	} {
+		for address, want := range map[uint64]string{
+			0x1000: "0x1000",
+			0x1001: "0x1000",
+			0x1FFF: "0x1000",
+			0x2000: "0x2000",
+			0x2001: "0x2000",
+		} {
+			if got, _ := a.addrInfo(address); !checkAddress(got, address, want) {
+				t.Errorf("%x: got %v, want %s", address, got, want)
+			}
+		}
+	}
+}
+
+func checkAddress(got []plugin.Frame, address uint64, want string) bool {
+	if len(got) != 1 {
+		return false
+	}
+	return got[0].Func == want
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
new file mode 100644
index 0000000..1a3b6f8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
@@ -0,0 +1,147 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"bytes"
+	"io"
+	"regexp"
+	"strconv"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/ianlancetaylor/demangle"
+)
+
+var (
+	nmOutputRE            = regexp.MustCompile(`^\s*([[:xdigit:]]+)\s+(.)\s+(.*)`)
+	objdumpAsmOutputRE    = regexp.MustCompile(`^\s*([[:xdigit:]]+):\s+(.*)`)
+	objdumpOutputFileLine = regexp.MustCompile(`^(.*):([0-9]+)`)
+	objdumpOutputFunction = regexp.MustCompile(`^(\S.*)\(\):`)
+)
+
+func findSymbols(syms []byte, file string, r *regexp.Regexp, address uint64) ([]*plugin.Sym, error) {
+	// Collect all symbols from the nm output, grouping names mapped to
+	// the same address into a single symbol.
+	var symbols []*plugin.Sym
+	names, start := []string{}, uint64(0)
+	buf := bytes.NewBuffer(syms)
+	for symAddr, name, err := nextSymbol(buf); err == nil; symAddr, name, err = nextSymbol(buf) {
+		if err != nil {
+			return nil, err
+		}
+		if start == symAddr {
+			names = append(names, name)
+			continue
+		}
+		if match := matchSymbol(names, start, symAddr-1, r, address); match != nil {
+			symbols = append(symbols, &plugin.Sym{Name: match, File: file, Start: start, End: symAddr - 1})
+		}
+		names, start = []string{name}, symAddr
+	}
+
+	return symbols, nil
+}
+
+// matchSymbol checks if a symbol is to be selected by checking its
+// name to the regexp and optionally its address. It returns the name(s)
+// to be used for the matched symbol, or nil if no match
+func matchSymbol(names []string, start, end uint64, r *regexp.Regexp, address uint64) []string {
+	if address != 0 && address >= start && address <= end {
+		return names
+	}
+	for _, name := range names {
+		if r.MatchString(name) {
+			return []string{name}
+		}
+
+		// Match all possible demangled versions of the name.
+		for _, o := range [][]demangle.Option{
+			{demangle.NoClones},
+			{demangle.NoParams},
+			{demangle.NoParams, demangle.NoTemplateParams},
+		} {
+			if demangled, err := demangle.ToString(name, o...); err == nil && r.MatchString(demangled) {
+				return []string{demangled}
+			}
+		}
+	}
+	return nil
+}
+
+// disassemble parses the output of the objdump command and returns
+// the assembly instructions in a slice.
+func disassemble(asm []byte) ([]plugin.Inst, error) {
+	buf := bytes.NewBuffer(asm)
+	function, file, line := "", "", 0
+	var assembly []plugin.Inst
+	for {
+		input, err := buf.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return nil, err
+			}
+			if input == "" {
+				break
+			}
+		}
+
+		if fields := objdumpAsmOutputRE.FindStringSubmatch(input); len(fields) == 3 {
+			if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil {
+				assembly = append(assembly,
+					plugin.Inst{
+						Addr:     address,
+						Text:     fields[2],
+						Function: function,
+						File:     file,
+						Line:     line,
+					})
+				continue
+			}
+		}
+		if fields := objdumpOutputFileLine.FindStringSubmatch(input); len(fields) == 3 {
+			if l, err := strconv.ParseUint(fields[2], 10, 32); err == nil {
+				file, line = fields[1], int(l)
+			}
+			continue
+		}
+		if fields := objdumpOutputFunction.FindStringSubmatch(input); len(fields) == 2 {
+			function = fields[1]
+			continue
+		}
+		// Reset on unrecognized lines.
+		function, file, line = "", "", 0
+	}
+
+	return assembly, nil
+}
+
+// nextSymbol parses the nm output to find the next symbol listed.
+// Skips over any output it cannot recognize.
+func nextSymbol(buf *bytes.Buffer) (uint64, string, error) {
+	for {
+		line, err := buf.ReadString('\n')
+		if err != nil {
+			if err != io.EOF || line == "" {
+				return 0, "", err
+			}
+		}
+
+		if fields := nmOutputRE.FindStringSubmatch(line); len(fields) == 4 {
+			if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil {
+				return address, fields[3], nil
+			}
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm_test.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm_test.go
new file mode 100644
index 0000000..7fc2574
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm_test.go
@@ -0,0 +1,154 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package binutils
+
+import (
+	"fmt"
+	"regexp"
+	"testing"
+
+	"github.com/google/pprof/internal/plugin"
+)
+
+// TestFindSymbols tests the FindSymbols routine using a hardcoded nm output.
+func TestFindSymbols(t *testing.T) {
+	type testcase struct {
+		query, syms string
+		want        []plugin.Sym
+	}
+
+	testsyms := `0000000000001000 t lineA001
+0000000000001000 t lineA002
+0000000000001000 t line1000
+0000000000002000 t line200A
+0000000000002000 t line2000
+0000000000002000 t line200B
+0000000000003000 t line3000
+0000000000003000 t _ZNK4DumbclEPKc
+0000000000003000 t lineB00C
+0000000000003000 t line300D
+0000000000004000 t _the_end
+	`
+	testcases := []testcase{
+		{
+			"line.*[AC]",
+			testsyms,
+			[]plugin.Sym{
+				{Name: []string{"lineA001"}, File: "object.o", Start: 0x1000, End: 0x1FFF},
+				{Name: []string{"line200A"}, File: "object.o", Start: 0x2000, End: 0x2FFF},
+				{Name: []string{"lineB00C"}, File: "object.o", Start: 0x3000, End: 0x3FFF},
+			},
+		},
+		{
+			"Dumb::operator",
+			testsyms,
+			[]plugin.Sym{
+				{Name: []string{"Dumb::operator()(char const*) const"}, File: "object.o", Start: 0x3000, End: 0x3FFF},
+			},
+		},
+	}
+
+	for _, tc := range testcases {
+		syms, err := findSymbols([]byte(tc.syms), "object.o", regexp.MustCompile(tc.query), 0)
+		if err != nil {
+			t.Fatalf("%q: findSymbols: %v", tc.query, err)
+		}
+		if err := checkSymbol(syms, tc.want); err != nil {
+			t.Errorf("%q: %v", tc.query, err)
+		}
+	}
+}
+
+func checkSymbol(got []*plugin.Sym, want []plugin.Sym) error {
+	if len(got) != len(want) {
+		return fmt.Errorf("unexpected number of symbols %d (want %d)\n", len(got), len(want))
+	}
+
+	for i, g := range got {
+		w := want[i]
+		if len(g.Name) != len(w.Name) {
+			return fmt.Errorf("names, got %d, want %d", len(g.Name), len(w.Name))
+		}
+		for n := range g.Name {
+			if g.Name[n] != w.Name[n] {
+				return fmt.Errorf("name %d, got %q, want %q", n, g.Name[n], w.Name[n])
+			}
+		}
+		if g.File != w.File {
+			return fmt.Errorf("filename, got %q, want %q", g.File, w.File)
+		}
+		if g.Start != w.Start {
+			return fmt.Errorf("start address, got %#x, want %#x", g.Start, w.Start)
+		}
+		if g.End != w.End {
+			return fmt.Errorf("end address, got %#x, want %#x", g.End, w.End)
+		}
+	}
+	return nil
+}
+
+// TestFunctionAssembly tests the FunctionAssembly routine by using a
+// fake objdump script.
+func TestFunctionAssembly(t *testing.T) {
+	type testcase struct {
+		s    plugin.Sym
+		asm  string
+		want []plugin.Inst
+	}
+	testcases := []testcase{
+		{
+			plugin.Sym{Name: []string{"symbol1"}, Start: 0x1000, End: 0x1FFF},
+			`  1000: instruction one
+  1001: instruction two
+  1002: instruction three
+  1003: instruction four
+`,
+			[]plugin.Inst{
+				{Addr: 0x1000, Text: "instruction one"},
+				{Addr: 0x1001, Text: "instruction two"},
+				{Addr: 0x1002, Text: "instruction three"},
+				{Addr: 0x1003, Text: "instruction four"},
+			},
+		},
+		{
+			plugin.Sym{Name: []string{"symbol2"}, Start: 0x2000, End: 0x2FFF},
+			`  2000: instruction one
+  2001: instruction two
+`,
+			[]plugin.Inst{
+				{Addr: 0x2000, Text: "instruction one"},
+				{Addr: 0x2001, Text: "instruction two"},
+			},
+		},
+	}
+
+	const objdump = "testdata/wrapper/objdump"
+
+	for _, tc := range testcases {
+		insts, err := disassemble([]byte(tc.asm))
+		if err != nil {
+			t.Fatalf("FunctionAssembly: %v", err)
+		}
+
+		if len(insts) != len(tc.want) {
+			t.Errorf("Unexpected number of assembly instructions %d (want %d)\n", len(insts), len(tc.want))
+		}
+		for i := range insts {
+			if insts[i] != tc.want[i] {
+				t.Errorf("Expected symbol %v, got %v\n", tc.want[i], insts[i])
+			}
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
new file mode 100644
index 0000000..0005ead
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
@@ -0,0 +1,272 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/google/pprof/internal/binutils"
+	"github.com/google/pprof/internal/plugin"
+)
+
+type source struct {
+	Sources  []string
+	ExecName string
+	BuildID  string
+	Base     []string
+
+	Seconds   int
+	Timeout   int
+	Symbolize string
+}
+
+// Parse parses the command lines through the specified flags package
+// and returns the source of the profile and optionally the command
+// for the kind of report to generate (nil for interactive use).
+func parseFlags(o *plugin.Options) (*source, []string, error) {
+	flag := o.Flagset
+	// Comparisons.
+	flagBase := flag.StringList("base", "", "Source for base profile for comparison")
+	// Internal options.
+	flagSymbolize := flag.String("symbolize", "", "Options for profile symbolization")
+	flagBuildID := flag.String("buildid", "", "Override build id for first mapping")
+	// 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")
+	// 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")
+
+	flagTimeout := flag.Int("timeout", -1, "Timeout in seconds for fetching a profile")
+
+	// Flags used during command processing
+	installedFlags := installFlags(flag)
+
+	flagCommands := make(map[string]*bool)
+	flagParamCommands := make(map[string]*string)
+	for name, cmd := range pprofCommands {
+		if cmd.hasParam {
+			flagParamCommands[name] = flag.String(name, "", "Generate a report in "+name+" format, matching regexp")
+		} else {
+			flagCommands[name] = flag.Bool(name, false, "Generate a report in "+name+" format")
+		}
+	}
+
+	args := flag.Parse(func() {
+		o.UI.Print(usageMsgHdr +
+			usage(true) +
+			usageMsgSrc +
+			flag.ExtraUsage() +
+			usageMsgVars)
+	})
+	if len(args) == 0 {
+		return nil, nil, fmt.Errorf("no profile source specified")
+	}
+
+	var execName string
+	// Recognize first argument as an executable or buildid override.
+	if len(args) > 1 {
+		arg0 := args[0]
+		if file, err := o.Obj.Open(arg0, 0, ^uint64(0), 0); err == nil {
+			file.Close()
+			execName = arg0
+			args = args[1:]
+		} else if *flagBuildID == "" && isBuildID(arg0) {
+			*flagBuildID = arg0
+			args = args[1:]
+		}
+	}
+
+	// Report conflicting options
+	if err := updateFlags(installedFlags); err != nil {
+		return nil, nil, err
+	}
+
+	cmd, err := outputFormat(flagCommands, flagParamCommands)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	si := pprofVariables["sample_index"].value
+	si = sampleIndex(flagTotalDelay, si, "delay", "-total_delay", o.UI)
+	si = sampleIndex(flagMeanDelay, si, "delay", "-mean_delay", o.UI)
+	si = sampleIndex(flagContentions, si, "contentions", "-contentions", o.UI)
+	si = sampleIndex(flagInUseSpace, si, "inuse_space", "-inuse_space", o.UI)
+	si = sampleIndex(flagInUseObjects, si, "inuse_objects", "-inuse_objects", o.UI)
+	si = sampleIndex(flagAllocSpace, si, "alloc_space", "-alloc_space", o.UI)
+	si = sampleIndex(flagAllocObjects, si, "alloc_objects", "-alloc_objects", o.UI)
+	pprofVariables.set("sample_index", si)
+
+	if *flagMeanDelay {
+		pprofVariables.set("mean", "true")
+	}
+
+	source := &source{
+		Sources:   args,
+		ExecName:  execName,
+		BuildID:   *flagBuildID,
+		Seconds:   *flagSeconds,
+		Timeout:   *flagTimeout,
+		Symbolize: *flagSymbolize,
+	}
+
+	for _, s := range *flagBase {
+		if *s != "" {
+			source.Base = append(source.Base, *s)
+		}
+	}
+
+	if bu, ok := o.Obj.(*binutils.Binutils); ok {
+		bu.SetTools(*flagTools)
+	}
+	return source, cmd, nil
+}
+
+// installFlags creates command line flags for pprof variables.
+func installFlags(flag plugin.FlagSet) flagsInstalled {
+	f := flagsInstalled{
+		ints:    make(map[string]*int),
+		bools:   make(map[string]*bool),
+		floats:  make(map[string]*float64),
+		strings: make(map[string]*string),
+	}
+	for n, v := range pprofVariables {
+		switch v.kind {
+		case boolKind:
+			if v.group != "" {
+				// Set all radio variables to false to identify conflicts.
+				f.bools[n] = flag.Bool(n, false, v.help)
+			} else {
+				f.bools[n] = flag.Bool(n, v.boolValue(), v.help)
+			}
+		case intKind:
+			f.ints[n] = flag.Int(n, v.intValue(), v.help)
+		case floatKind:
+			f.floats[n] = flag.Float64(n, v.floatValue(), v.help)
+		case stringKind:
+			f.strings[n] = flag.String(n, v.value, v.help)
+		}
+	}
+	return f
+}
+
+// updateFlags updates the pprof variables according to the flags
+// parsed in the command line.
+func updateFlags(f flagsInstalled) error {
+	vars := pprofVariables
+	groups := map[string]string{}
+	for n, v := range f.bools {
+		vars.set(n, fmt.Sprint(*v))
+		if *v {
+			g := vars[n].group
+			if g != "" && groups[g] != "" {
+				return fmt.Errorf("conflicting options %q and %q set", n, groups[g])
+			}
+			groups[g] = n
+		}
+	}
+	for n, v := range f.ints {
+		vars.set(n, fmt.Sprint(*v))
+	}
+	for n, v := range f.floats {
+		vars.set(n, fmt.Sprint(*v))
+	}
+	for n, v := range f.strings {
+		vars.set(n, *v)
+	}
+	return nil
+}
+
+type flagsInstalled struct {
+	ints    map[string]*int
+	bools   map[string]*bool
+	floats  map[string]*float64
+	strings map[string]*string
+}
+
+// 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") == ""
+}
+
+func sampleIndex(flag *bool, si string, sampleType, option string, ui plugin.UI) string {
+	if *flag {
+		if si == "" {
+			return sampleType
+		}
+		ui.PrintErr("Multiple value selections, ignoring ", option)
+	}
+	return si
+}
+
+func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, err error) {
+	for n, b := range bcmd {
+		if *b {
+			if cmd != nil {
+				return nil, fmt.Errorf("must set at most one output format")
+			}
+			cmd = []string{n}
+		}
+	}
+	for n, s := range acmd {
+		if *s != "" {
+			if cmd != nil {
+				return nil, fmt.Errorf("must set at most one output format")
+			}
+			cmd = []string{n, *s}
+		}
+	}
+	return cmd, nil
+}
+
+var usageMsgHdr = "usage: pprof [options] [-base source] [binary] <source> ...\n"
+
+var usageMsgSrc = "\n\n" +
+	"  Source options:\n" +
+	"    -seconds              Duration for time-based profile collection\n" +
+	"    -timeout              Timeout in seconds for profile collection\n" +
+	"    -buildid              Override build id for main binary\n" +
+	"    -base source          Source of profile to use as baseline\n" +
+	"    profile.pb.gz         Profile in compressed protobuf format\n" +
+	"    legacy_profile        Profile in legacy pprof format\n" +
+	"    http://host/profile   URL for profile handler to retrieve\n" +
+	"    -symbolize=           Controls source of symbol information\n" +
+	"      none                  Do not attempt symbolization\n" +
+	"      local                 Examine only local binaries\n" +
+	"      fastlocal             Only get function names from local binaries\n" +
+	"      remote                Do not examine local binaries\n" +
+	"      force                 Force re-symbolization\n" +
+	"    Binary                  Local path or build id of binary for symbolization\n"
+
+var usageMsgVars = "\n\n" +
+	"  Misc options:\n" +
+	"   -tools                 Search path for object tools\n" +
+	"\n" +
+	"  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\n" +
+	"   * On Windows, %USERPROFILE% is used instead of $HOME"
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
new file mode 100644
index 0000000..5e54062
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
@@ -0,0 +1,561 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/report"
+	"github.com/google/pprof/third_party/svg"
+)
+
+// 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 {
+	format      int           // report format to generate
+	postProcess PostProcessor // postprocessing to run on report
+	visualizer  PostProcessor // display output using some callback
+	hasParam    bool          // collect a parameter from the CLI
+	description string        // single-line description text saying what the command does
+	usage       string        // multi-line help text saying how the command is used
+}
+
+// help returns a help string for a command.
+func (c *command) help(name string) string {
+	message := c.description + "\n"
+	if c.usage != "" {
+		message += "  Usage:\n"
+		lines := strings.Split(c.usage, "\n")
+		for _, line := range lines {
+			message += fmt.Sprintf("    %s\n", line)
+		}
+	}
+	return message + "\n"
+}
+
+// AddCommand adds an additional command to the set of commands
+// accepted by pprof. This enables extensions to add new commands for
+// specialized visualization formats. If the command specified already
+// exists, it is overwritten.
+func AddCommand(cmd string, format int, post PostProcessor, desc, usage string) {
+	pprofCommands[cmd] = &command{format, post, nil, false, desc, usage}
+}
+
+// SetVariableDefault sets the default value for a pprof
+// variable. This enables extensions to set their own defaults.
+func SetVariableDefault(variable, value string) {
+	if v := pprofVariables[variable]; v != nil {
+		v.value = value
+	}
+}
+
+// PostProcessor is a function that applies post-processing to the report output
+type PostProcessor func(input io.Reader, output io.Writer, ui plugin.UI) error
+
+// interactiveMode is true if pprof is running on interactive mode, reading
+// commands from its shell.
+var interactiveMode = false
+
+// pprofCommands are the report generation commands recognized by pprof.
+var pprofCommands = commands{
+	// Commands that require no post-processing.
+	"comments": {report.Comments, nil, nil, false, "Output all profile comments", ""},
+	"disasm":   {report.Dis, nil, nil, true, "Output assembly listings annotated with samples", listHelp("disasm", true)},
+	"dot":      {report.Dot, nil, nil, false, "Outputs a graph in DOT format", reportHelp("dot", false, true)},
+	"list":     {report.List, nil, nil, true, "Output annotated source for functions matching regexp", listHelp("list", false)},
+	"peek":     {report.Tree, nil, nil, true, "Output callers/callees of functions matching regexp", "peek func_regex\nDisplay callers and callees of functions matching func_regex."},
+	"raw":      {report.Raw, nil, nil, false, "Outputs a text representation of the raw profile", ""},
+	"tags":     {report.Tags, nil, nil, false, "Outputs all tags in the profile", "tags [tag_regex]* [-ignore_regex]* [>file]\nList tags with key:value matching tag_regex and exclude ignore_regex."},
+	"text":     {report.Text, nil, nil, false, "Outputs top entries in text form", reportHelp("text", true, true)},
+	"top":      {report.Text, nil, nil, false, "Outputs top entries in text form", reportHelp("top", true, true)},
+	"traces":   {report.Traces, nil, nil, false, "Outputs all profile samples in text form", ""},
+	"tree":     {report.Tree, nil, nil, false, "Outputs a text rendering of call graph", reportHelp("tree", true, true)},
+
+	// Save binary formats to a file
+	"callgrind": {report.Callgrind, nil, awayFromTTY("callgraph.out"), false, "Outputs a graph in callgrind format", reportHelp("callgrind", false, true)},
+	"proto":     {report.Proto, nil, awayFromTTY("pb.gz"), false, "Outputs the profile in compressed protobuf format", ""},
+	"topproto":  {report.TopProto, nil, awayFromTTY("pb.gz"), false, "Outputs top entries in compressed protobuf format", ""},
+
+	// Generate report in DOT format and postprocess with dot
+	"gif": {report.Dot, invokeDot("gif"), awayFromTTY("gif"), false, "Outputs a graph image in GIF format", reportHelp("gif", false, true)},
+	"pdf": {report.Dot, invokeDot("pdf"), awayFromTTY("pdf"), false, "Outputs a graph in PDF format", reportHelp("pdf", false, true)},
+	"png": {report.Dot, invokeDot("png"), awayFromTTY("png"), false, "Outputs a graph image in PNG format", reportHelp("png", false, true)},
+	"ps":  {report.Dot, invokeDot("ps"), awayFromTTY("ps"), false, "Outputs a graph in PS format", reportHelp("ps", false, true)},
+
+	// Save SVG output into a file
+	"svg": {report.Dot, massageDotSVG(), awayFromTTY("svg"), false, "Outputs a graph in SVG format", reportHelp("svg", false, true)},
+
+	// Visualize postprocessed dot output
+	"eog":    {report.Dot, invokeDot("svg"), invokeVisualizer("svg", []string{"eog"}), false, "Visualize graph through eog", reportHelp("eog", false, false)},
+	"evince": {report.Dot, invokeDot("pdf"), invokeVisualizer("pdf", []string{"evince"}), false, "Visualize graph through evince", reportHelp("evince", false, false)},
+	"gv":     {report.Dot, invokeDot("ps"), invokeVisualizer("ps", []string{"gv --noantialias"}), false, "Visualize graph through gv", reportHelp("gv", false, false)},
+	"web":    {report.Dot, massageDotSVG(), invokeVisualizer("svg", browsers()), false, "Visualize graph through web browser", reportHelp("web", false, false)},
+
+	// Visualize callgrind output
+	"kcachegrind": {report.Callgrind, nil, invokeVisualizer("grind", kcachegrind), false, "Visualize report in KCachegrind", reportHelp("kcachegrind", false, false)},
+
+	// Visualize HTML directly generated by report.
+	"weblist": {report.WebList, nil, invokeVisualizer("html", browsers()), true, "Display annotated source in a web browser", listHelp("weblist", false)},
+}
+
+// pprofVariables are the configuration parameters that affect the
+// reported generated by pprof.
+var pprofVariables = variables{
+	// Filename for file-based output formats, stdout by default.
+	"output": &variable{stringKind, "", "", helpText("Output filename for file-based outputs")},
+
+	// Comparisons.
+	"drop_negative": &variable{boolKind, "f", "", helpText(
+		"Ignore negative differences",
+		"Do not show any locations with values <0.")},
+
+	// Comparisons.
+	"positive_percentages": &variable{boolKind, "f", "", helpText(
+		"Ignore negative samples when computing percentages",
+		" Do not count negative samples when computing the total value",
+		" of the profile, used to compute percentages. If set, and the -base",
+		" option is used, percentages reported will be computed against the",
+		" main profile, ignoring the base profile.")},
+
+	// Graph handling options.
+	"call_tree": &variable{boolKind, "f", "", helpText(
+		"Create a context-sensitive call tree",
+		"Treat locations reached through different paths as separate.")},
+
+	// Display options.
+	"relative_percentages": &variable{boolKind, "f", "", helpText(
+		"Show percentages relative to focused subgraph",
+		"If unset, percentages are relative to full graph before focusing",
+		"to facilitate comparison with original graph.")},
+	"unit": &variable{stringKind, "minimum", "", helpText(
+		"Measurement units to display",
+		"Scale the sample values to this unit.",
+		" For time-based profiles, use seconds, milliseconds, nanoseconds, etc.",
+		" For memory profiles, use megabytes, kilobytes, bytes, etc.",
+		" auto will scale each value independently to the most natural unit.")},
+	"compact_labels": &variable{boolKind, "f", "", "Show minimal headers"},
+	"source_path":    &variable{stringKind, "", "", "Search path for source files"},
+
+	// Filtering options
+	"nodecount": &variable{intKind, "-1", "", helpText(
+		"Max number of nodes to show",
+		"Uses heuristics to limit the number of locations to be displayed.",
+		"On graphs, dotted edges represent paths through nodes that have been removed.")},
+	"nodefraction": &variable{floatKind, "0.005", "", "Hide nodes below <f>*total"},
+	"edgefraction": &variable{floatKind, "0.001", "", "Hide edges below <f>*total"},
+	"trim": &variable{boolKind, "t", "", helpText(
+		"Honor nodefraction/edgefraction/nodecount defaults",
+		"Set to false to get the full profile, without any trimming.")},
+	"focus": &variable{stringKind, "", "", helpText(
+		"Restricts to samples going through a node matching regexp",
+		"Discard samples that do not include a node matching this regexp.",
+		"Matching includes the function name, filename or object name.")},
+	"ignore": &variable{stringKind, "", "", helpText(
+		"Skips paths going through any nodes matching regexp",
+		"If set, discard samples that include a node matching this regexp.",
+		"Matching includes the function name, filename or object name.")},
+	"prune_from": &variable{stringKind, "", "", helpText(
+		"Drops any functions below the matched frame.",
+		"If set, any frames matching the specified regexp and any frames",
+		"below it will be dropped from each sample.")},
+	"hide": &variable{stringKind, "", "", helpText(
+		"Skips nodes matching regexp",
+		"Discard nodes that match this location.",
+		"Other nodes from samples that include this location will be shown.",
+		"Matching includes the function name, filename or object name.")},
+	"show": &variable{stringKind, "", "", helpText(
+		"Only show nodes matching regexp",
+		"If set, only show nodes that match this location.",
+		"Matching includes the function name, filename or object name.")},
+	"tagfocus": &variable{stringKind, "", "", helpText(
+		"Restrict to samples with tags in range or matched by regexp",
+		"Discard samples that do not include a node with a tag matching this regexp.")},
+	"tagignore": &variable{stringKind, "", "", helpText(
+		"Discard samples with tags in range or matched by regexp",
+		"Discard samples that do include a node with a tag matching this regexp.")},
+	"tagshow": &variable{stringKind, "", "", helpText(
+		"Only consider tags matching this regexp",
+		"Discard tags that do not match this regexp")},
+	"taghide": &variable{stringKind, "", "", helpText(
+		"Skip tags matching this regexp",
+		"Discard tags that match this regexp")},
+	// Heap profile options
+	"divide_by": &variable{floatKind, "1", "", helpText(
+		"Ratio to divide all samples before visualization",
+		"Divide all samples values by a constant, eg the number of processors or jobs.")},
+	"mean": &variable{boolKind, "f", "", helpText(
+		"Average sample value over first value (count)",
+		"For memory profiles, report average memory per allocation.",
+		"For time-based profiles, report average time per event.")},
+	"sample_index": &variable{stringKind, "", "", helpText(
+		"Sample value to report (0-based index or name)",
+		"Profiles contain multiple values per sample.",
+		"Use sample_index=i to select the ith value (starting at 0).")},
+
+	// Data sorting criteria
+	"flat": &variable{boolKind, "t", "cumulative", helpText("Sort entries based on own weight")},
+	"cum":  &variable{boolKind, "f", "cumulative", helpText("Sort entries based on cumulative weight")},
+
+	// Output granularity
+	"functions": &variable{boolKind, "t", "granularity", helpText(
+		"Aggregate at the function level.",
+		"Takes into account the filename/lineno where the function was defined.")},
+	"functionnameonly": &variable{boolKind, "f", "granularity", helpText(
+		"Aggregate at the function level.",
+		"Ignores the filename/lineno where the function was defined.")},
+	"files": &variable{boolKind, "f", "granularity", "Aggregate at the file level."},
+	"lines": &variable{boolKind, "f", "granularity", "Aggregate at the source code line level."},
+	"addresses": &variable{boolKind, "f", "granularity", helpText(
+		"Aggregate at the function level.",
+		"Includes functions' addresses in the output.")},
+	"noinlines": &variable{boolKind, "f", "granularity", helpText(
+		"Aggregate at the function level.",
+		"Attributes inlined functions to their first out-of-line caller.")},
+	"addressnoinlines": &variable{boolKind, "f", "granularity", helpText(
+		"Aggregate at the function level, including functions' addresses in the output.",
+		"Attributes inlined functions to their first out-of-line caller.")},
+}
+
+func helpText(s ...string) string {
+	return strings.Join(s, "\n") + "\n"
+}
+
+// usage returns a string describing the pprof commands and variables.
+// if commandLine is set, the output reflect cli usage.
+func usage(commandLine bool) string {
+	var prefix string
+	if commandLine {
+		prefix = "-"
+	}
+	fmtHelp := func(c, d string) string {
+		return fmt.Sprintf("    %-16s %s", c, strings.SplitN(d, "\n", 2)[0])
+	}
+
+	var commands []string
+	for name, cmd := range pprofCommands {
+		commands = append(commands, fmtHelp(prefix+name, cmd.description))
+	}
+	sort.Strings(commands)
+
+	var help string
+	if commandLine {
+		help = "  Output formats (select only one):\n"
+	} else {
+		help = "  Commands:\n"
+		commands = append(commands, fmtHelp("o/options", "List options and their current values"))
+		commands = append(commands, fmtHelp("quit/exit/^D", "Exit pprof"))
+	}
+
+	help = help + strings.Join(commands, "\n") + "\n\n" +
+		"  Options:\n"
+
+	// Print help for variables after sorting them.
+	// Collect radio variables by their group name to print them together.
+	radioOptions := make(map[string][]string)
+	var variables []string
+	for name, vr := range pprofVariables {
+		if vr.group != "" {
+			radioOptions[vr.group] = append(radioOptions[vr.group], name)
+			continue
+		}
+		variables = append(variables, fmtHelp(prefix+name, vr.help))
+	}
+	sort.Strings(variables)
+
+	help = help + strings.Join(variables, "\n") + "\n\n" +
+		"  Option groups (only set one per group):\n"
+
+	var radioStrings []string
+	for radio, ops := range radioOptions {
+		sort.Strings(ops)
+		s := []string{fmtHelp(radio, "")}
+		for _, op := range ops {
+			s = append(s, "  "+fmtHelp(prefix+op, pprofVariables[op].help))
+		}
+
+		radioStrings = append(radioStrings, strings.Join(s, "\n"))
+	}
+	sort.Strings(radioStrings)
+	return help + strings.Join(radioStrings, "\n")
+}
+
+func reportHelp(c string, cum, redirect bool) string {
+	h := []string{
+		c + " [n] [focus_regex]* [-ignore_regex]*",
+		"Include up to n samples",
+		"Include samples matching focus_regex, and exclude ignore_regex.",
+	}
+	if cum {
+		h[0] += " [-cum]"
+		h = append(h, "-cum sorts the output by cumulative weight")
+	}
+	if redirect {
+		h[0] += " >f"
+		h = append(h, "Optionally save the report on the file f")
+	}
+	return strings.Join(h, "\n")
+}
+
+func listHelp(c string, redirect bool) string {
+	h := []string{
+		c + "<func_regex|address> [-focus_regex]* [-ignore_regex]*",
+		"Include functions matching func_regex, or including the address specified.",
+		"Include samples matching focus_regex, and exclude ignore_regex.",
+	}
+	if redirect {
+		h[0] += " >f"
+		h = append(h, "Optionally save the report on the file f")
+	}
+	return strings.Join(h, "\n")
+}
+
+// browsers returns a list of commands to attempt for web visualization.
+func browsers() []string {
+	cmds := []string{"chrome", "google-chrome", "firefox"}
+	switch runtime.GOOS {
+	case "darwin":
+		return append(cmds, "/usr/bin/open")
+	case "windows":
+		return append(cmds, "cmd /c start")
+	default:
+		userBrowser := os.Getenv("BROWSER")
+		if userBrowser != "" {
+			cmds = append([]string{userBrowser, "sensible-browser"}, cmds...)
+		} else {
+			cmds = append([]string{"sensible-browser"}, cmds...)
+		}
+		return append(cmds, "xdg-open")
+	}
+}
+
+var kcachegrind = []string{"kcachegrind"}
+
+// 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 io.Reader, output io.Writer, ui plugin.UI) error {
+		if output == os.Stdout && (ui.IsTerminal() || interactiveMode) {
+			tempFile, err := newTempFile("", "profile", "."+format)
+			if err != nil {
+				return err
+			}
+			ui.PrintErr("Generating report in ", tempFile.Name())
+			output = tempFile
+		}
+		_, err := io.Copy(output, input)
+		return err
+	}
+}
+
+func invokeDot(format string) PostProcessor {
+	return func(input io.Reader, output io.Writer, ui plugin.UI) error {
+		cmd := exec.Command("dot", "-T"+format)
+		cmd.Stdin, cmd.Stdout, cmd.Stderr = input, output, os.Stderr
+		if err := cmd.Run(); err != nil {
+			return fmt.Errorf("Failed to execute dot. Is Graphviz installed? Error: %v", err)
+		}
+		return nil
+	}
+}
+
+// massageDotSVG invokes the dot tool to generate an SVG image and alters
+// the image to have panning capabilities when viewed in a browser.
+func massageDotSVG() PostProcessor {
+	generateSVG := invokeDot("svg")
+	return func(input io.Reader, output io.Writer, ui plugin.UI) error {
+		baseSVG := new(bytes.Buffer)
+		if err := generateSVG(input, baseSVG, ui); err != nil {
+			return err
+		}
+		_, err := output.Write([]byte(svg.Massage(baseSVG.String())))
+		return err
+	}
+}
+
+func invokeVisualizer(suffix string, visualizers []string) PostProcessor {
+	return func(input io.Reader, output io.Writer, ui plugin.UI) error {
+		tempFile, err := newTempFile(os.TempDir(), "pprof", "."+suffix)
+		if err != nil {
+			return err
+		}
+		deferDeleteTempFile(tempFile.Name())
+		if _, err := io.Copy(tempFile, input); err != nil {
+			return err
+		}
+		tempFile.Close()
+		// 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 {
+				// Wait for a second so that the visualizer has a chance to
+				// open the input file. This needs to be done even if we're
+				// waiting for the visualizer as it can be just a wrapper that
+				// spawns a browser tab and returns right away.
+				defer func(t <-chan time.Time) {
+					<-t
+				}(time.After(time.Second))
+				// On interactive mode, let the visualizer run in the background
+				// so other commands can be issued.
+				if !interactiveMode {
+					return viewer.Wait()
+				}
+				return nil
+			}
+		}
+		return err
+	}
+}
+
+// variables describe the configuration parameters recognized by pprof.
+type variables map[string]*variable
+
+// variable is a single configuration parameter.
+type variable struct {
+	kind  int    // How to interpret the value, must be one of the enums below.
+	value string // Effective value. Only values appropriate for the Kind should be set.
+	group string // boolKind variables with the same Group != "" cannot be set simultaneously.
+	help  string // Text describing the variable, in multiple lines separated by newline.
+}
+
+const (
+	// variable.kind must be one of these variables.
+	boolKind = iota
+	intKind
+	floatKind
+	stringKind
+)
+
+// set updates the value of a variable, checking that the value is
+// suitable for the variable Kind.
+func (vars variables) set(name, value string) error {
+	v := vars[name]
+	if v == nil {
+		return fmt.Errorf("no variable %s", name)
+	}
+	var err error
+	switch v.kind {
+	case boolKind:
+		var b bool
+		if b, err = stringToBool(value); err == nil {
+			if v.group != "" && b == false {
+				err = fmt.Errorf("%q can only be set to true", name)
+			}
+		}
+	case intKind:
+		_, err = strconv.Atoi(value)
+	case floatKind:
+		_, err = strconv.ParseFloat(value, 64)
+	case stringKind:
+		// Remove quotes, particularly useful for empty values.
+		if len(value) > 1 && strings.HasPrefix(value, `"`) && strings.HasSuffix(value, `"`) {
+			value = value[1 : len(value)-1]
+		}
+	}
+	if err != nil {
+		return err
+	}
+	vars[name].value = value
+	if group := vars[name].group; group != "" {
+		for vname, vvar := range vars {
+			if vvar.group == group && vname != name {
+				vvar.value = "f"
+			}
+		}
+	}
+	return err
+}
+
+// boolValue returns the value of a boolean variable.
+func (v *variable) boolValue() bool {
+	b, err := stringToBool(v.value)
+	if err != nil {
+		panic("unexpected value " + v.value + " for bool ")
+	}
+	return b
+}
+
+// intValue returns the value of an intKind variable.
+func (v *variable) intValue() int {
+	i, err := strconv.Atoi(v.value)
+	if err != nil {
+		panic("unexpected value " + v.value + " for int ")
+	}
+	return i
+}
+
+// floatValue returns the value of a Float variable.
+func (v *variable) floatValue() float64 {
+	f, err := strconv.ParseFloat(v.value, 64)
+	if err != nil {
+		panic("unexpected value " + v.value + " for float ")
+	}
+	return f
+}
+
+// stringValue returns a canonical representation for a variable.
+func (v *variable) stringValue() string {
+	switch v.kind {
+	case boolKind:
+		return fmt.Sprint(v.boolValue())
+	case intKind:
+		return fmt.Sprint(v.intValue())
+	case floatKind:
+		return fmt.Sprint(v.floatValue())
+	}
+	return v.value
+}
+
+func stringToBool(s string) (bool, error) {
+	switch strings.ToLower(s) {
+	case "true", "t", "yes", "y", "1", "":
+		return true, nil
+	case "false", "f", "no", "n", "0":
+		return false, nil
+	default:
+		return false, fmt.Errorf(`illegal value "%s" for bool variable`, s)
+	}
+}
+
+// makeCopy returns a duplicate of a set of shell variables.
+func (vars variables) makeCopy() variables {
+	varscopy := make(variables, len(vars))
+	for n, v := range vars {
+		vcopy := *v
+		varscopy[n] = &vcopy
+	}
+	return varscopy
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
new file mode 100644
index 0000000..2ca09df
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
@@ -0,0 +1,287 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package driver implements the core pprof functionality. It can be
+// parameterized with a flag implementation, fetch and symbolize
+// mechanisms.
+package driver
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"path/filepath"
+	"regexp"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/report"
+	"github.com/google/pprof/profile"
+)
+
+// 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(eo *plugin.Options) error {
+	// Remove any temporary files created during pprof processing.
+	defer cleanupTempFiles()
+
+	o := setDefaults(eo)
+
+	src, cmd, err := parseFlags(o)
+	if err != nil {
+		return err
+	}
+
+	p, err := fetchProfiles(src, o)
+	if err != nil {
+		return err
+	}
+
+	if cmd != nil {
+		return generateReport(p, cmd, pprofVariables, o)
+	}
+
+	return interactive(p, o)
+}
+
+func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
+	p = p.Copy() // Prevent modification to the incoming profile.
+
+	vars = applyCommandOverrides(cmd, vars)
+
+	// Delay focus after configuring report to get percentages on all samples.
+	relative := vars["relative_percentages"].boolValue()
+	if relative {
+		if err := applyFocus(p, vars, o.UI); err != nil {
+			return err
+		}
+	}
+	ropt, err := reportOptions(p, vars)
+	if err != nil {
+		return err
+	}
+	c := pprofCommands[cmd[0]]
+	if c == nil {
+		panic("unexpected nil command")
+	}
+	ropt.OutputFormat = c.format
+	if len(cmd) == 2 {
+		s, err := regexp.Compile(cmd[1])
+		if err != nil {
+			return fmt.Errorf("parsing argument regexp %s: %v", cmd[1], err)
+		}
+		ropt.Symbol = s
+	}
+
+	rpt := report.New(p, ropt)
+	if !relative {
+		if err := applyFocus(p, vars, o.UI); err != nil {
+			return err
+		}
+	}
+	if err := aggregate(p, vars); err != nil {
+		return err
+	}
+
+	// Generate the report.
+	dst := new(bytes.Buffer)
+	if err := report.Generate(dst, rpt, o.Obj); err != nil {
+		return err
+	}
+	src := dst
+
+	// If necessary, perform any data post-processing.
+	if c.postProcess != nil {
+		dst = new(bytes.Buffer)
+		if err := c.postProcess(src, dst, o.UI); err != nil {
+			return err
+		}
+		src = dst
+	}
+
+	// If no output is specified, use default visualizer.
+	output := vars["output"].value
+	if output == "" {
+		if c.visualizer != nil {
+			return c.visualizer(src, os.Stdout, o.UI)
+		}
+		_, err := src.WriteTo(os.Stdout)
+		return err
+	}
+
+	// Output to specified file.
+	o.UI.PrintErr("Generating report in ", output)
+	out, err := os.Create(output)
+	if err != nil {
+		return err
+	}
+	if _, err := src.WriteTo(out); err != nil {
+		out.Close()
+		return err
+	}
+	return out.Close()
+}
+
+func applyCommandOverrides(cmd []string, v variables) variables {
+	trim, focus, tagfocus, hide := v["trim"].boolValue(), true, true, true
+
+	switch cmd[0] {
+	case "proto", "raw":
+		trim, focus, tagfocus, hide = false, false, false, false
+		v.set("addresses", "t")
+	case "callgrind", "kcachegrind":
+		trim = false
+		v.set("addresses", "t")
+	case "disasm", "weblist":
+		trim = false
+		v.set("addressnoinlines", "t")
+	case "peek":
+		trim, focus, hide = false, false, false
+	case "list":
+		v.set("nodecount", "0")
+		v.set("lines", "t")
+	case "text", "top", "topproto":
+		if v["nodecount"].intValue() == -1 {
+			v.set("nodecount", "0")
+		}
+	default:
+		if v["nodecount"].intValue() == -1 {
+			v.set("nodecount", "80")
+		}
+	}
+	if trim == false {
+		v.set("nodecount", "0")
+		v.set("nodefraction", "0")
+		v.set("edgefraction", "0")
+	}
+	if focus == false {
+		v.set("focus", "")
+		v.set("ignore", "")
+	}
+	if tagfocus == false {
+		v.set("tagfocus", "")
+		v.set("tagignore", "")
+	}
+	if hide == false {
+		v.set("hide", "")
+		v.set("show", "")
+	}
+	return v
+}
+
+func aggregate(prof *profile.Profile, v variables) error {
+	var inlines, function, filename, linenumber, address bool
+	switch {
+	case v["addresses"].boolValue():
+		return nil
+	case v["lines"].boolValue():
+		inlines = true
+		function = true
+		filename = true
+		linenumber = true
+	case v["files"].boolValue():
+		inlines = true
+		filename = true
+	case v["functions"].boolValue():
+		inlines = true
+		function = true
+		filename = true
+	case v["noinlines"].boolValue():
+		function = true
+		filename = true
+	case v["addressnoinlines"].boolValue():
+		function = true
+		filename = true
+		linenumber = true
+		address = true
+	case v["functionnameonly"].boolValue():
+		inlines = true
+		function = true
+	default:
+		return fmt.Errorf("unexpected granularity")
+	}
+	return prof.Aggregate(inlines, function, filename, linenumber, address)
+}
+
+func reportOptions(p *profile.Profile, vars variables) (*report.Options, error) {
+	si, mean := vars["sample_index"].value, vars["mean"].boolValue()
+	value, meanDiv, sample, err := sampleFormat(p, si, mean)
+	if err != nil {
+		return nil, err
+	}
+
+	stype := sample.Type
+	if mean {
+		stype = "mean_" + stype
+	}
+
+	if vars["divide_by"].floatValue() == 0 {
+		return nil, fmt.Errorf("zero divisor specified")
+	}
+
+	ropt := &report.Options{
+		CumSort:             vars["cum"].boolValue(),
+		CallTree:            vars["call_tree"].boolValue(),
+		DropNegative:        vars["drop_negative"].boolValue(),
+		PositivePercentages: vars["positive_percentages"].boolValue(),
+
+		CompactLabels: vars["compact_labels"].boolValue(),
+		Ratio:         1 / vars["divide_by"].floatValue(),
+
+		NodeCount:    vars["nodecount"].intValue(),
+		NodeFraction: vars["nodefraction"].floatValue(),
+		EdgeFraction: vars["edgefraction"].floatValue(),
+
+		SampleValue:       value,
+		SampleMeanDivisor: meanDiv,
+		SampleType:        stype,
+		SampleUnit:        sample.Unit,
+
+		OutputUnit: vars["unit"].value,
+
+		SourcePath: vars["source_path"].stringValue(),
+	}
+
+	if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
+		ropt.Title = filepath.Base(p.Mapping[0].File)
+	}
+
+	return ropt, nil
+}
+
+type sampleValueFunc func([]int64) 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, sampleIndex string, mean bool) (value, meanDiv sampleValueFunc, v *profile.ValueType, err error) {
+	if len(p.SampleType) == 0 {
+		return nil, nil, nil, fmt.Errorf("profile has no samples")
+	}
+	index, err := p.SampleIndexByName(sampleIndex)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	value = valueExtractor(index)
+	if mean {
+		meanDiv = valueExtractor(0)
+	}
+	v = p.SampleType[index]
+	return
+}
+
+func valueExtractor(ix int) sampleValueFunc {
+	return func(v []int64) int64 {
+		return v[ix]
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go
new file mode 100644
index 0000000..c60ad81
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go
@@ -0,0 +1,174 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/measurement"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/profile"
+)
+
+var tagFilterRangeRx = regexp.MustCompile("([[:digit:]]+)([[:alpha:]]+)")
+
+// applyFocus filters samples based on the focus/ignore options
+func applyFocus(prof *profile.Profile, v variables, ui plugin.UI) error {
+	focus, err := compileRegexOption("focus", v["focus"].value, nil)
+	ignore, err := compileRegexOption("ignore", v["ignore"].value, err)
+	hide, err := compileRegexOption("hide", v["hide"].value, err)
+	show, err := compileRegexOption("show", v["show"].value, err)
+	tagfocus, err := compileTagFilter("tagfocus", v["tagfocus"].value, ui, err)
+	tagignore, err := compileTagFilter("tagignore", v["tagignore"].value, ui, err)
+	prunefrom, err := compileRegexOption("prune_from", v["prune_from"].value, err)
+	if err != nil {
+		return err
+	}
+
+	fm, im, hm, hnm := prof.FilterSamplesByName(focus, ignore, hide, show)
+	warnNoMatches(focus == nil || fm, "Focus", ui)
+	warnNoMatches(ignore == nil || im, "Ignore", ui)
+	warnNoMatches(hide == nil || hm, "Hide", ui)
+	warnNoMatches(show == nil || hnm, "Show", ui)
+
+	tfm, tim := prof.FilterSamplesByTag(tagfocus, tagignore)
+	warnNoMatches(tagfocus == nil || tfm, "TagFocus", ui)
+	warnNoMatches(tagignore == nil || tim, "TagIgnore", ui)
+
+	tagshow, err := compileRegexOption("tagshow", v["tagshow"].value, err)
+	taghide, err := compileRegexOption("taghide", v["taghide"].value, err)
+	tns, tnh := prof.FilterTagsByName(tagshow, taghide)
+	warnNoMatches(tagshow == nil || tns, "TagShow", ui)
+	warnNoMatches(tagignore == nil || tnh, "TagHide", ui)
+
+	if prunefrom != nil {
+		prof.PruneFrom(prunefrom)
+	}
+	return nil
+}
+
+func compileRegexOption(name, value string, err error) (*regexp.Regexp, error) {
+	if value == "" || err != nil {
+		return nil, err
+	}
+	rx, err := regexp.Compile(value)
+	if err != nil {
+		return nil, fmt.Errorf("parsing %s regexp: %v", name, err)
+	}
+	return rx, nil
+}
+
+func compileTagFilter(name, value string, ui plugin.UI, err error) (func(*profile.Sample) bool, error) {
+	if value == "" || err != nil {
+		return nil, err
+	}
+	if numFilter := parseTagFilterRange(value); numFilter != nil {
+		ui.PrintErr(name, ":Interpreted '", value, "' as range, not regexp")
+		return func(s *profile.Sample) bool {
+			for key, vals := range s.NumLabel {
+				for _, val := range vals {
+					if numFilter(val, key) {
+						return true
+					}
+				}
+			}
+			return false
+		}, nil
+	}
+	var rfx []*regexp.Regexp
+	for _, tagf := range strings.Split(value, ",") {
+		fx, err := regexp.Compile(tagf)
+		if err != nil {
+			return nil, fmt.Errorf("parsing %s regexp: %v", name, err)
+		}
+		rfx = append(rfx, fx)
+	}
+	return func(s *profile.Sample) bool {
+	matchedrx:
+		for _, rx := range rfx {
+			for key, vals := range s.Label {
+				for _, val := range vals {
+					if rx.MatchString(key + ":" + val) {
+						continue matchedrx
+					}
+				}
+			}
+			return false
+		}
+		return true
+	}, nil
+}
+
+// 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))
+	}
+	scaledValue, unit := measurement.Scale(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 := measurement.Scale(v, u, unit)
+				return su == unit && sv == scaledValue
+			}
+		case match + ":":
+			return func(v int64, u string) bool {
+				sv, su := measurement.Scale(v, u, unit)
+				return su == unit && sv >= scaledValue
+			}
+		case ":" + match:
+			return func(v int64, u string) bool {
+				sv, su := measurement.Scale(v, u, unit)
+				return su == unit && sv <= scaledValue
+			}
+		}
+		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))
+	}
+	scaledValue2, unit2 := measurement.Scale(v, ranges[1][2], unit)
+	if unit != unit2 {
+		return nil
+	}
+	return func(v int64, u string) bool {
+		sv, su := measurement.Scale(v, u, unit)
+		return su == unit && sv >= scaledValue && sv <= scaledValue2
+	}
+}
+
+func warnNoMatches(match bool, option string, ui plugin.UI) {
+	if !match {
+		ui.PrintErr(option + " expression matched no samples")
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
new file mode 100644
index 0000000..75eaebe
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
@@ -0,0 +1,1095 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/proftest"
+	"github.com/google/pprof/internal/symbolz"
+	"github.com/google/pprof/profile"
+)
+
+func TestParse(t *testing.T) {
+	// Override weblist command to collect output in buffer
+	pprofCommands["weblist"].postProcess = nil
+
+	// Our mockObjTool.Open will always return success, causing
+	// driver.locateBinaries to "find" the binaries below in a non-existant
+	// directory. As a workaround, point the search path to the fake
+	// directory containing out fake binaries.
+	savePath := os.Getenv("PPROF_BINARY_PATH")
+	os.Setenv("PPROF_BINARY_PATH", "/path/to")
+	defer os.Setenv("PPROF_BINARY_PATH", savePath)
+
+	testcase := []struct {
+		flags, source string
+	}{
+		{"text,functions,flat", "cpu"},
+		{"tree,addresses,flat,nodecount=4", "cpusmall"},
+		{"text,functions,flat", "unknown"},
+		{"text,alloc_objects,flat", "heap_alloc"},
+		{"text,files,flat", "heap"},
+		{"text,inuse_objects,flat", "heap"},
+		{"text,lines,cum,hide=line[X3]0", "cpu"},
+		{"text,lines,cum,show=[12]00", "cpu"},
+		{"topproto,lines,cum,hide=mangled[X3]0", "cpu"},
+		{"tree,lines,cum,focus=[24]00", "heap"},
+		{"tree,relative_percentages,cum,focus=[24]00", "heap"},
+		{"callgrind", "cpu"},
+		{"callgrind", "heap"},
+		{"dot,functions,flat", "cpu"},
+		{"dot,lines,flat,focus=[12]00", "heap"},
+		{"dot,addresses,flat,ignore=[X3]002,focus=[X1]000", "contention"},
+		{"dot,files,cum", "contention"},
+		{"comments", "cpu"},
+		{"comments", "heap"},
+		{"tags", "cpu"},
+		{"tags,tagignore=tag[13],tagfocus=key[12]", "cpu"},
+		{"tags", "heap"},
+		{"tags,unit=bytes", "heap"},
+		{"traces", "cpu"},
+		{"dot,alloc_space,flat,focus=[234]00", "heap_alloc"},
+		{"dot,alloc_space,flat,hide=line.*1?23?", "heap_alloc"},
+		{"dot,inuse_space,flat,tagfocus=1mb:2gb", "heap"},
+		{"dot,inuse_space,flat,tagfocus=30kb:,tagignore=1mb:2mb", "heap"},
+		{"disasm=line[13],addresses,flat", "cpu"},
+		{"peek=line.*01", "cpu"},
+		{"weblist=line[13],addresses,flat", "cpu"},
+	}
+
+	baseVars := pprofVariables
+	defer func() { pprofVariables = baseVars }()
+	for _, tc := range testcase {
+		// Reset the pprof variables before processing
+		pprofVariables = baseVars.makeCopy()
+
+		f := baseFlags()
+		f.args = []string{tc.source}
+
+		flags := strings.Split(tc.flags, ",")
+
+		// Skip the output format in the first flag, to output to a proto
+		addFlags(&f, flags[1:])
+
+		// Encode profile into a protobuf and decode it again.
+		protoTempFile, err := ioutil.TempFile("", "profile_proto")
+		if err != nil {
+			t.Errorf("cannot create tempfile: %v", err)
+		}
+		defer protoTempFile.Close()
+		f.strings["output"] = protoTempFile.Name()
+
+		if flags[0] == "topproto" {
+			f.bools["proto"] = false
+			f.bools["topproto"] = true
+		}
+
+		// First pprof invocation to save the profile into a profile.proto.
+		o1 := setDefaults(nil)
+		o1.Flagset = f
+		o1.Fetch = testFetcher{}
+		o1.Sym = testSymbolizer{}
+		if err := PProf(o1); err != nil {
+			t.Errorf("%s %q:  %v", tc.source, tc.flags, err)
+			continue
+		}
+		// Reset the pprof variables after the proto invocation
+		pprofVariables = baseVars.makeCopy()
+
+		// Read the profile from the encoded protobuf
+		outputTempFile, err := ioutil.TempFile("", "profile_output")
+		if err != nil {
+			t.Errorf("cannot create tempfile: %v", err)
+		}
+		defer outputTempFile.Close()
+		f.strings["output"] = outputTempFile.Name()
+		f.args = []string{protoTempFile.Name()}
+
+		var solution string
+		// Apply the flags for the second pprof run, and identify name of
+		// the file containing expected results
+		if flags[0] == "topproto" {
+			solution = solutionFilename(tc.source, &f)
+			delete(f.bools, "topproto")
+			f.bools["text"] = true
+		} else {
+			delete(f.bools, "proto")
+			addFlags(&f, flags[:1])
+			solution = solutionFilename(tc.source, &f)
+		}
+
+		// Second pprof invocation to read the profile from profile.proto
+		// and generate a report.
+		o2 := setDefaults(nil)
+		o2.Flagset = f
+		o2.Sym = testSymbolizeDemangler{}
+		o2.Obj = new(mockObjTool)
+
+		if err := PProf(o2); err != nil {
+			t.Errorf("%s: %v", tc.source, err)
+		}
+		b, err := ioutil.ReadFile(outputTempFile.Name())
+		if err != nil {
+			t.Errorf("Failed to read profile %s: %v", outputTempFile.Name(), err)
+		}
+
+		// Read data file with expected solution
+		solution = "testdata/" + solution
+		sbuf, err := ioutil.ReadFile(solution)
+		if err != nil {
+			t.Errorf("reading solution file %s: %v", solution, err)
+			continue
+		}
+		if runtime.GOOS == "windows" {
+			sbuf = bytes.Replace(sbuf, []byte("testdata/"), []byte("testdata\\"), -1)
+			sbuf = bytes.Replace(sbuf, []byte("/path/to/"), []byte("\\path\\to\\"), -1)
+		}
+
+		if flags[0] == "svg" {
+			b = removeScripts(b)
+			sbuf = removeScripts(sbuf)
+		}
+
+		if string(b) != string(sbuf) {
+			t.Errorf("diff %s %s", solution, tc.source)
+			d, err := proftest.Diff(sbuf, b)
+			if err != nil {
+				t.Fatalf("diff %s %v", solution, err)
+			}
+			t.Errorf("%s\n%s\n", solution, d)
+		}
+	}
+}
+
+// removeScripts removes <script > .. </script> pairs from its input
+func removeScripts(in []byte) []byte {
+	beginMarker := []byte("<script")
+	endMarker := []byte("</script>")
+
+	if begin := bytes.Index(in, beginMarker); begin > 0 {
+		if end := bytes.Index(in[begin:], endMarker); end > 0 {
+			in = append(in[:begin], removeScripts(in[begin+end+len(endMarker):])...)
+		}
+	}
+	return in
+}
+
+// addFlags parses flag descriptions and adds them to the testFlags
+func addFlags(f *testFlags, flags []string) {
+	for _, flag := range flags {
+		fields := strings.SplitN(flag, "=", 2)
+		switch len(fields) {
+		case 1:
+			f.bools[fields[0]] = true
+		case 2:
+			if i, err := strconv.Atoi(fields[1]); err == nil {
+				f.ints[fields[0]] = i
+			} else {
+				f.strings[fields[0]] = fields[1]
+			}
+		}
+	}
+}
+
+// solutionFilename returns the name of the solution file for the test
+func solutionFilename(source string, f *testFlags) string {
+	name := []string{"pprof", strings.TrimPrefix(source, "http://host:8000/")}
+	name = addString(name, f, []string{"flat", "cum"})
+	name = addString(name, f, []string{"functions", "files", "lines", "addresses"})
+	name = addString(name, f, []string{"inuse_space", "inuse_objects", "alloc_space", "alloc_objects"})
+	name = addString(name, f, []string{"relative_percentages"})
+	name = addString(name, f, []string{"seconds"})
+	name = addString(name, f, []string{"text", "tree", "callgrind", "dot", "svg", "tags", "dot", "traces", "disasm", "peek", "weblist", "topproto", "comments"})
+	if f.strings["focus"] != "" || f.strings["tagfocus"] != "" {
+		name = append(name, "focus")
+	}
+	if f.strings["ignore"] != "" || f.strings["tagignore"] != "" {
+		name = append(name, "ignore")
+	}
+	name = addString(name, f, []string{"hide", "show"})
+	if f.strings["unit"] != "minimum" {
+		name = addString(name, f, []string{"unit"})
+	}
+	return strings.Join(name, ".")
+}
+
+func addString(name []string, f *testFlags, components []string) []string {
+	for _, c := range components {
+		if f.bools[c] || f.strings[c] != "" || f.ints[c] != 0 {
+			return append(name, c)
+		}
+	}
+	return name
+}
+
+// testFlags implements the plugin.FlagSet interface.
+type testFlags struct {
+	bools   map[string]bool
+	ints    map[string]int
+	floats  map[string]float64
+	strings map[string]string
+	args    []string
+}
+
+func (testFlags) ExtraUsage() string { return "" }
+
+func (f testFlags) Bool(s string, d bool, c string) *bool {
+	if b, ok := f.bools[s]; ok {
+		return &b
+	}
+	return &d
+}
+
+func (f testFlags) Int(s string, d int, c string) *int {
+	if i, ok := f.ints[s]; ok {
+		return &i
+	}
+	return &d
+}
+
+func (f testFlags) Float64(s string, d float64, c string) *float64 {
+	if g, ok := f.floats[s]; ok {
+		return &g
+	}
+	return &d
+}
+
+func (f testFlags) String(s, d, c string) *string {
+	if t, ok := f.strings[s]; ok {
+		return &t
+	}
+	return &d
+}
+
+func (f testFlags) BoolVar(p *bool, s string, d bool, c string) {
+	if b, ok := f.bools[s]; ok {
+		*p = b
+	} else {
+		*p = d
+	}
+}
+
+func (f testFlags) IntVar(p *int, s string, d int, c string) {
+	if i, ok := f.ints[s]; ok {
+		*p = i
+	} else {
+		*p = d
+	}
+}
+
+func (f testFlags) Float64Var(p *float64, s string, d float64, c string) {
+	if g, ok := f.floats[s]; ok {
+		*p = g
+	} else {
+		*p = d
+	}
+}
+
+func (f testFlags) StringVar(p *string, s, d, c string) {
+	if t, ok := f.strings[s]; ok {
+		*p = t
+	} else {
+		*p = d
+	}
+}
+
+func (f testFlags) StringList(s, d, c string) *[]*string {
+	return &[]*string{}
+}
+
+func (f testFlags) Parse(func()) []string {
+	return f.args
+}
+
+func baseFlags() testFlags {
+	return testFlags{
+		bools: map[string]bool{
+			"proto":          true,
+			"trim":           true,
+			"compact_labels": true,
+		},
+		ints: map[string]int{
+			"nodecount": 20,
+		},
+		floats: map[string]float64{
+			"nodefraction": 0.05,
+			"edgefraction": 0.01,
+			"divide_by":    1.0,
+		},
+		strings: map[string]string{
+			"unit": "minimum",
+		},
+	}
+}
+
+type testProfile struct {
+}
+
+const testStart = 0x1000
+const testOffset = 0x5000
+
+type testFetcher struct{}
+
+func (testFetcher) Fetch(s string, d, t time.Duration) (*profile.Profile, string, error) {
+	var p *profile.Profile
+	s = strings.TrimPrefix(s, "http://host:8000/")
+	switch s {
+	case "cpu", "unknown":
+		p = cpuProfile()
+	case "cpusmall":
+		p = cpuProfileSmall()
+	case "heap":
+		p = heapProfile()
+	case "heap_alloc":
+		p = heapProfile()
+		p.SampleType = []*profile.ValueType{
+			{Type: "alloc_objects", Unit: "count"},
+			{Type: "alloc_space", Unit: "bytes"},
+		}
+	case "contention":
+		p = contentionProfile()
+	case "symbolz":
+		p = symzProfile()
+	case "http://host2/symbolz":
+		p = symzProfile()
+		p.Mapping[0].Start += testOffset
+		p.Mapping[0].Limit += testOffset
+		for i := range p.Location {
+			p.Location[i].Address += testOffset
+		}
+	default:
+		return nil, "", fmt.Errorf("unexpected source: %s", s)
+	}
+	return p, s, nil
+}
+
+type testSymbolizer struct{}
+
+func (testSymbolizer) Symbolize(_ string, _ plugin.MappingSources, _ *profile.Profile) error {
+	return nil
+}
+
+type testSymbolizeDemangler struct{}
+
+func (testSymbolizeDemangler) Symbolize(_ string, _ plugin.MappingSources, p *profile.Profile) error {
+	for _, fn := range p.Function {
+		if fn.Name == "" || fn.SystemName == fn.Name {
+			fn.Name = fakeDemangler(fn.SystemName)
+		}
+	}
+	return nil
+}
+
+func testFetchSymbols(source, post string) ([]byte, error) {
+	var buf bytes.Buffer
+
+	if source == "http://host2/symbolz" {
+		for _, address := range strings.Split(post, "+") {
+			a, _ := strconv.ParseInt(address, 0, 64)
+			fmt.Fprintf(&buf, "%v\t", address)
+			if a-testStart < testOffset {
+				fmt.Fprintf(&buf, "wrong_source_%v_", address)
+				continue
+			}
+			fmt.Fprintf(&buf, "%#x\n", a-testStart-testOffset)
+		}
+		return buf.Bytes(), nil
+	}
+	for _, address := range strings.Split(post, "+") {
+		a, _ := strconv.ParseInt(address, 0, 64)
+		fmt.Fprintf(&buf, "%v\t", address)
+		if a-testStart > testOffset {
+			fmt.Fprintf(&buf, "wrong_source_%v_", address)
+			continue
+		}
+		fmt.Fprintf(&buf, "%#x\n", a-testStart)
+	}
+	return buf.Bytes(), nil
+}
+
+type testSymbolzSymbolizer struct{}
+
+func (testSymbolzSymbolizer) Symbolize(variables string, sources plugin.MappingSources, p *profile.Profile) error {
+	return symbolz.Symbolize(sources, testFetchSymbols, p, nil)
+}
+
+func fakeDemangler(name string) string {
+	switch name {
+	case "mangled1000":
+		return "line1000"
+	case "mangled2000":
+		return "line2000"
+	case "mangled2001":
+		return "line2001"
+	case "mangled3000":
+		return "line3000"
+	case "mangled3001":
+		return "line3001"
+	case "mangled3002":
+		return "line3002"
+	case "mangledNEW":
+		return "operator new"
+	case "mangledMALLOC":
+		return "malloc"
+	default:
+		return name
+	}
+}
+
+func cpuProfile() *profile.Profile {
+	var cpuM = []*profile.Mapping{
+		{
+			ID:              1,
+			Start:           0x1000,
+			Limit:           0x4000,
+			File:            "/path/to/testbinary",
+			HasFunctions:    true,
+			HasFilenames:    true,
+			HasLineNumbers:  true,
+			HasInlineFrames: true,
+		},
+	}
+
+	var cpuF = []*profile.Function{
+		{ID: 1, Name: "mangled1000", SystemName: "mangled1000", Filename: "testdata/file1000.src"},
+		{ID: 2, Name: "mangled2000", SystemName: "mangled2000", Filename: "testdata/file2000.src"},
+		{ID: 3, Name: "mangled2001", SystemName: "mangled2001", Filename: "testdata/file2000.src"},
+		{ID: 4, Name: "mangled3000", SystemName: "mangled3000", Filename: "testdata/file3000.src"},
+		{ID: 5, Name: "mangled3001", SystemName: "mangled3001", Filename: "testdata/file3000.src"},
+		{ID: 6, Name: "mangled3002", SystemName: "mangled3002", Filename: "testdata/file3000.src"},
+	}
+
+	var cpuL = []*profile.Location{
+		{
+			ID:      1000,
+			Mapping: cpuM[0],
+			Address: 0x1000,
+			Line: []profile.Line{
+				{Function: cpuF[0], Line: 1},
+			},
+		},
+		{
+			ID:      2000,
+			Mapping: cpuM[0],
+			Address: 0x2000,
+			Line: []profile.Line{
+				{Function: cpuF[2], Line: 9},
+				{Function: cpuF[1], Line: 4},
+			},
+		},
+		{
+			ID:      3000,
+			Mapping: cpuM[0],
+			Address: 0x3000,
+			Line: []profile.Line{
+				{Function: cpuF[5], Line: 2},
+				{Function: cpuF[4], Line: 5},
+				{Function: cpuF[3], Line: 6},
+			},
+		},
+		{
+			ID:      3001,
+			Mapping: cpuM[0],
+			Address: 0x3001,
+			Line: []profile.Line{
+				{Function: cpuF[4], Line: 8},
+				{Function: cpuF[3], Line: 9},
+			},
+		},
+		{
+			ID:      3002,
+			Mapping: cpuM[0],
+			Address: 0x3002,
+			Line: []profile.Line{
+				{Function: cpuF[5], Line: 5},
+				{Function: cpuF[3], Line: 9},
+			},
+		},
+	}
+
+	return &profile.Profile{
+		PeriodType:    &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
+		Period:        1,
+		DurationNanos: 10e9,
+		SampleType: []*profile.ValueType{
+			{Type: "samples", Unit: "count"},
+			{Type: "cpu", Unit: "milliseconds"},
+		},
+		Sample: []*profile.Sample{
+			{
+				Location: []*profile.Location{cpuL[0], cpuL[1], cpuL[2]},
+				Value:    []int64{1000, 1000},
+				Label: map[string][]string{
+					"key1": []string{"tag1"},
+					"key2": []string{"tag1"},
+				},
+			},
+			{
+				Location: []*profile.Location{cpuL[0], cpuL[3]},
+				Value:    []int64{100, 100},
+				Label: map[string][]string{
+					"key1": []string{"tag2"},
+					"key3": []string{"tag2"},
+				},
+			},
+			{
+				Location: []*profile.Location{cpuL[1], cpuL[4]},
+				Value:    []int64{10, 10},
+				Label: map[string][]string{
+					"key1": []string{"tag3"},
+					"key2": []string{"tag2"},
+				},
+			},
+			{
+				Location: []*profile.Location{cpuL[2]},
+				Value:    []int64{10, 10},
+				Label: map[string][]string{
+					"key1": []string{"tag4"},
+					"key2": []string{"tag1"},
+				},
+			},
+		},
+		Location: cpuL,
+		Function: cpuF,
+		Mapping:  cpuM,
+	}
+}
+
+func cpuProfileSmall() *profile.Profile {
+	var cpuM = []*profile.Mapping{
+		{
+			ID:              1,
+			Start:           0x1000,
+			Limit:           0x4000,
+			File:            "/path/to/testbinary",
+			HasFunctions:    true,
+			HasFilenames:    true,
+			HasLineNumbers:  true,
+			HasInlineFrames: true,
+		},
+	}
+
+	var cpuL = []*profile.Location{
+		{
+			ID:      1000,
+			Mapping: cpuM[0],
+			Address: 0x1000,
+		},
+		{
+			ID:      2000,
+			Mapping: cpuM[0],
+			Address: 0x2000,
+		},
+		{
+			ID:      3000,
+			Mapping: cpuM[0],
+			Address: 0x3000,
+		},
+		{
+			ID:      4000,
+			Mapping: cpuM[0],
+			Address: 0x4000,
+		},
+		{
+			ID:      5000,
+			Mapping: cpuM[0],
+			Address: 0x5000,
+		},
+	}
+
+	return &profile.Profile{
+		PeriodType:    &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
+		Period:        1,
+		DurationNanos: 10e9,
+		SampleType: []*profile.ValueType{
+			{Type: "samples", Unit: "count"},
+			{Type: "cpu", Unit: "milliseconds"},
+		},
+		Sample: []*profile.Sample{
+			{
+				Location: []*profile.Location{cpuL[0], cpuL[1], cpuL[2]},
+				Value:    []int64{1000, 1000},
+			},
+			{
+				Location: []*profile.Location{cpuL[3], cpuL[1], cpuL[4]},
+				Value:    []int64{1000, 1000},
+			},
+			{
+				Location: []*profile.Location{cpuL[2]},
+				Value:    []int64{1000, 1000},
+			},
+			{
+				Location: []*profile.Location{cpuL[4]},
+				Value:    []int64{1000, 1000},
+			},
+		},
+		Location: cpuL,
+		Function: nil,
+		Mapping:  cpuM,
+	}
+}
+
+func heapProfile() *profile.Profile {
+	var heapM = []*profile.Mapping{
+		{
+			ID:              1,
+			BuildID:         "buildid",
+			Start:           0x1000,
+			Limit:           0x4000,
+			HasFunctions:    true,
+			HasFilenames:    true,
+			HasLineNumbers:  true,
+			HasInlineFrames: true,
+		},
+	}
+
+	var heapF = []*profile.Function{
+		{ID: 1, Name: "pruneme", SystemName: "pruneme", Filename: "prune.h"},
+		{ID: 2, Name: "mangled1000", SystemName: "mangled1000", Filename: "testdata/file1000.src"},
+		{ID: 3, Name: "mangled2000", SystemName: "mangled2000", Filename: "testdata/file2000.src"},
+		{ID: 4, Name: "mangled2001", SystemName: "mangled2001", Filename: "testdata/file2000.src"},
+		{ID: 5, Name: "mangled3000", SystemName: "mangled3000", Filename: "testdata/file3000.src"},
+		{ID: 6, Name: "mangled3001", SystemName: "mangled3001", Filename: "testdata/file3000.src"},
+		{ID: 7, Name: "mangled3002", SystemName: "mangled3002", Filename: "testdata/file3000.src"},
+		{ID: 8, Name: "mangledMALLOC", SystemName: "mangledMALLOC", Filename: "malloc.h"},
+		{ID: 9, Name: "mangledNEW", SystemName: "mangledNEW", Filename: "new.h"},
+	}
+
+	var heapL = []*profile.Location{
+		{
+			ID:      1000,
+			Mapping: heapM[0],
+			Address: 0x1000,
+			Line: []profile.Line{
+				{Function: heapF[0], Line: 100},
+				{Function: heapF[7], Line: 100},
+				{Function: heapF[1], Line: 1},
+			},
+		},
+		{
+			ID:      2000,
+			Mapping: heapM[0],
+			Address: 0x2000,
+			Line: []profile.Line{
+				{Function: heapF[8], Line: 100},
+				{Function: heapF[3], Line: 2},
+				{Function: heapF[2], Line: 3},
+			},
+		},
+		{
+			ID:      3000,
+			Mapping: heapM[0],
+			Address: 0x3000,
+			Line: []profile.Line{
+				{Function: heapF[8], Line: 100},
+				{Function: heapF[6], Line: 3},
+				{Function: heapF[5], Line: 2},
+				{Function: heapF[4], Line: 4},
+			},
+		},
+		{
+			ID:      3001,
+			Mapping: heapM[0],
+			Address: 0x3001,
+			Line: []profile.Line{
+				{Function: heapF[0], Line: 100},
+				{Function: heapF[8], Line: 100},
+				{Function: heapF[5], Line: 2},
+				{Function: heapF[4], Line: 4},
+			},
+		},
+		{
+			ID:      3002,
+			Mapping: heapM[0],
+			Address: 0x3002,
+			Line: []profile.Line{
+				{Function: heapF[6], Line: 3},
+				{Function: heapF[4], Line: 4},
+			},
+		},
+	}
+
+	return &profile.Profile{
+		Comments:   []string{"comment", "#hidden comment"},
+		PeriodType: &profile.ValueType{Type: "allocations", Unit: "bytes"},
+		Period:     524288,
+		SampleType: []*profile.ValueType{
+			{Type: "inuse_objects", Unit: "count"},
+			{Type: "inuse_space", Unit: "bytes"},
+		},
+		Sample: []*profile.Sample{
+			{
+				Location: []*profile.Location{heapL[0], heapL[1], heapL[2]},
+				Value:    []int64{10, 1024000},
+				NumLabel: map[string][]int64{
+					"bytes": []int64{102400},
+				},
+			},
+			{
+				Location: []*profile.Location{heapL[0], heapL[3]},
+				Value:    []int64{20, 4096000},
+				NumLabel: map[string][]int64{
+					"bytes": []int64{204800},
+				},
+			},
+			{
+				Location: []*profile.Location{heapL[1], heapL[4]},
+				Value:    []int64{40, 65536000},
+				NumLabel: map[string][]int64{
+					"bytes": []int64{1638400},
+				},
+			},
+			{
+				Location: []*profile.Location{heapL[2]},
+				Value:    []int64{80, 32768000},
+				NumLabel: map[string][]int64{
+					"bytes": []int64{409600},
+				},
+			},
+		},
+		DropFrames: ".*operator new.*|malloc",
+		Location:   heapL,
+		Function:   heapF,
+		Mapping:    heapM,
+	}
+}
+
+func contentionProfile() *profile.Profile {
+	var contentionM = []*profile.Mapping{
+		{
+			ID:              1,
+			BuildID:         "buildid-contention",
+			Start:           0x1000,
+			Limit:           0x4000,
+			HasFunctions:    true,
+			HasFilenames:    true,
+			HasLineNumbers:  true,
+			HasInlineFrames: true,
+		},
+	}
+
+	var contentionF = []*profile.Function{
+		{ID: 1, Name: "mangled1000", SystemName: "mangled1000", Filename: "testdata/file1000.src"},
+		{ID: 2, Name: "mangled2000", SystemName: "mangled2000", Filename: "testdata/file2000.src"},
+		{ID: 3, Name: "mangled2001", SystemName: "mangled2001", Filename: "testdata/file2000.src"},
+		{ID: 4, Name: "mangled3000", SystemName: "mangled3000", Filename: "testdata/file3000.src"},
+		{ID: 5, Name: "mangled3001", SystemName: "mangled3001", Filename: "testdata/file3000.src"},
+		{ID: 6, Name: "mangled3002", SystemName: "mangled3002", Filename: "testdata/file3000.src"},
+	}
+
+	var contentionL = []*profile.Location{
+		{
+			ID:      1000,
+			Mapping: contentionM[0],
+			Address: 0x1000,
+			Line: []profile.Line{
+				{Function: contentionF[0], Line: 1},
+			},
+		},
+		{
+			ID:      2000,
+			Mapping: contentionM[0],
+			Address: 0x2000,
+			Line: []profile.Line{
+				{Function: contentionF[2], Line: 2},
+				{Function: contentionF[1], Line: 3},
+			},
+		},
+		{
+			ID:      3000,
+			Mapping: contentionM[0],
+			Address: 0x3000,
+			Line: []profile.Line{
+				{Function: contentionF[5], Line: 2},
+				{Function: contentionF[4], Line: 3},
+				{Function: contentionF[3], Line: 5},
+			},
+		},
+		{
+			ID:      3001,
+			Mapping: contentionM[0],
+			Address: 0x3001,
+			Line: []profile.Line{
+				{Function: contentionF[4], Line: 3},
+				{Function: contentionF[3], Line: 5},
+			},
+		},
+		{
+			ID:      3002,
+			Mapping: contentionM[0],
+			Address: 0x3002,
+			Line: []profile.Line{
+				{Function: contentionF[5], Line: 4},
+				{Function: contentionF[3], Line: 3},
+			},
+		},
+	}
+
+	return &profile.Profile{
+		PeriodType: &profile.ValueType{Type: "contentions", Unit: "count"},
+		Period:     524288,
+		SampleType: []*profile.ValueType{
+			{Type: "contentions", Unit: "count"},
+			{Type: "delay", Unit: "nanoseconds"},
+		},
+		Sample: []*profile.Sample{
+			{
+				Location: []*profile.Location{contentionL[0], contentionL[1], contentionL[2]},
+				Value:    []int64{10, 10240000},
+			},
+			{
+				Location: []*profile.Location{contentionL[0], contentionL[3]},
+				Value:    []int64{20, 40960000},
+			},
+			{
+				Location: []*profile.Location{contentionL[1], contentionL[4]},
+				Value:    []int64{40, 65536000},
+			},
+			{
+				Location: []*profile.Location{contentionL[2]},
+				Value:    []int64{80, 32768000},
+			},
+		},
+		Location: contentionL,
+		Function: contentionF,
+		Mapping:  contentionM,
+		Comments: []string{"Comment #1", "Comment #2"},
+	}
+}
+
+func symzProfile() *profile.Profile {
+	var symzM = []*profile.Mapping{
+		{
+			ID:    1,
+			Start: testStart,
+			Limit: 0x4000,
+			File:  "/path/to/testbinary",
+		},
+	}
+
+	var symzL = []*profile.Location{
+		{ID: 1, Mapping: symzM[0], Address: testStart},
+		{ID: 2, Mapping: symzM[0], Address: testStart + 0x1000},
+		{ID: 3, Mapping: symzM[0], Address: testStart + 0x2000},
+	}
+
+	return &profile.Profile{
+		PeriodType:    &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
+		Period:        1,
+		DurationNanos: 10e9,
+		SampleType: []*profile.ValueType{
+			{Type: "samples", Unit: "count"},
+			{Type: "cpu", Unit: "milliseconds"},
+		},
+		Sample: []*profile.Sample{
+			{
+				Location: []*profile.Location{symzL[0], symzL[1], symzL[2]},
+				Value:    []int64{1, 1},
+			},
+		},
+		Location: symzL,
+		Mapping:  symzM,
+	}
+}
+
+var autoCompleteTests = []struct {
+	in  string
+	out string
+}{
+	{"", ""},
+	{"xyz", "xyz"},                        // no match
+	{"dis", "disasm"},                     // single match
+	{"t", "t"},                            // many matches
+	{"top abc", "top abc"},                // no function name match
+	{"top mangledM", "top mangledMALLOC"}, // single function name match
+	{"top cmd cmd mangledM", "top cmd cmd mangledMALLOC"},
+	{"top mangled", "top mangled"},                      // many function name matches
+	{"cmd mangledM", "cmd mangledM"},                    // invalid command
+	{"top mangledM cmd", "top mangledM cmd"},            // cursor misplaced
+	{"top edMA", "top mangledMALLOC"},                   // single infix function name match
+	{"top -mangledM", "top -mangledMALLOC"},             // ignore sign handled
+	{"lin", "lines"},                                    // single variable match
+	{"EdGeF", "edgefraction"},                           // single capitalized match
+	{"help dis", "help disasm"},                         // help command match
+	{"help relative_perc", "help relative_percentages"}, // help variable match
+	{"help coMpa", "help compact_labels"},               // help variable capitalized match
+}
+
+func TestAutoComplete(t *testing.T) {
+	complete := newCompleter(functionNames(heapProfile()))
+
+	for _, test := range autoCompleteTests {
+		if out := complete(test.in); out != test.out {
+			t.Errorf("autoComplete(%s) = %s; want %s", test.in, out, test.out)
+		}
+	}
+}
+
+func TestTagFilter(t *testing.T) {
+	var tagFilterTests = []struct {
+		name, value string
+		tags        map[string][]string
+		want        bool
+	}{
+		{"test1", "tag2", map[string][]string{"value1": {"tag1", "tag2"}}, true},
+		{"test2", "tag3", map[string][]string{"value1": {"tag1", "tag2"}}, false},
+		{"test3", "tag1,tag3", map[string][]string{"value1": {"tag1", "tag2"}, "value2": {"tag3"}}, true},
+		{"test4", "t..[12],t..3", map[string][]string{"value1": {"tag1", "tag2"}, "value2": {"tag3"}}, true},
+		{"test5", "tag2,tag3", map[string][]string{"value1": {"tag1", "tag2"}}, false},
+	}
+
+	for _, test := range tagFilterTests {
+		filter, err := compileTagFilter(test.name, test.value, &proftest.TestUI{T: t}, nil)
+		if err != nil {
+			t.Errorf("tagFilter %s:%v", test.name, err)
+			continue
+		}
+		s := profile.Sample{
+			Label: test.tags,
+		}
+
+		if got := filter(&s); got != test.want {
+			t.Errorf("tagFilter %s: got %v, want %v", test.name, got, test.want)
+		}
+	}
+}
+
+func TestSymbolzAfterMerge(t *testing.T) {
+	baseVars := pprofVariables
+	pprofVariables = baseVars.makeCopy()
+	defer func() { pprofVariables = baseVars }()
+
+	f := baseFlags()
+	f.args = []string{"symbolz", "http://host2/symbolz"}
+
+	o := setDefaults(nil)
+	o.Flagset = f
+	o.Obj = new(mockObjTool)
+	src, cmd, err := parseFlags(o)
+	if err != nil {
+		t.Fatalf("parseFlags: %v", err)
+	}
+
+	if len(cmd) != 1 || cmd[0] != "proto" {
+		t.Fatalf("parseFlags returned command %v, want [proto]", cmd)
+	}
+
+	o.Fetch = testFetcher{}
+	o.Sym = testSymbolzSymbolizer{}
+	p, err := fetchProfiles(src, o)
+	if err != nil {
+		t.Fatalf("fetchProfiles: %v", err)
+	}
+	if len(p.Location) != 3 {
+		t.Errorf("Got %d locations after merge, want %d", len(p.Location), 3)
+	}
+	for i, l := range p.Location {
+		if len(l.Line) != 1 {
+			t.Errorf("Number of lines for symbolz %#x in iteration %d, got %d, want %d", l.Address, i, len(l.Line), 1)
+			continue
+		}
+		address := l.Address - l.Mapping.Start
+		if got, want := l.Line[0].Function.Name, fmt.Sprintf("%#x", address); got != want {
+			t.Errorf("symbolz %#x, got %s, want %s", address, got, want)
+		}
+	}
+}
+
+type mockObjTool struct{}
+
+func (*mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	return &mockFile{file, "abcdef", 0}, nil
+}
+
+func (m *mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+	switch start {
+	case 0x1000:
+		return []plugin.Inst{
+			{Addr: 0x1000, Text: "instruction one"},
+			{Addr: 0x1001, Text: "instruction two"},
+			{Addr: 0x1002, Text: "instruction three"},
+			{Addr: 0x1003, Text: "instruction four"},
+		}, nil
+	case 0x3000:
+		return []plugin.Inst{
+			{Addr: 0x3000, Text: "instruction one"},
+			{Addr: 0x3001, Text: "instruction two"},
+			{Addr: 0x3002, Text: "instruction three"},
+			{Addr: 0x3003, Text: "instruction four"},
+			{Addr: 0x3004, Text: "instruction five"},
+		}, nil
+	}
+	return nil, fmt.Errorf("unimplemented")
+}
+
+type mockFile struct {
+	name, buildId string
+	base          uint64
+}
+
+// Name returns the underlyinf file name, if available
+func (m *mockFile) Name() string {
+	return m.name
+}
+
+// Base returns the base address to use when looking up symbols in the file.
+func (m *mockFile) Base() uint64 {
+	return m.base
+}
+
+// BuildID returns the GNU build ID of the file, or an empty string.
+func (m *mockFile) BuildID() string {
+	return m.buildId
+}
+
+// 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.
+func (*mockFile) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	return nil, fmt.Errorf("unimplemented")
+}
+
+// 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.
+func (m *mockFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+	switch r.String() {
+	case "line[13]":
+		return []*plugin.Sym{
+			{[]string{"line1000"}, m.name, 0x1000, 0x1003},
+			{[]string{"line3000"}, m.name, 0x3000, 0x3004},
+		}, nil
+	}
+	return nil, fmt.Errorf("unimplemented")
+}
+
+// Close closes the file, releasing associated resources.
+func (*mockFile) Close() error {
+	return nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
new file mode 100644
index 0000000..f9e8231
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
@@ -0,0 +1,542 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"bytes"
+	"crypto/tls"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/google/pprof/internal/measurement"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/profile"
+)
+
+// fetchProfiles fetches and symbolizes the profiles specified by s.
+// It will merge all the profiles it is able to retrieve, even if
+// there are some failures. It will return an error if it is unable to
+// fetch any profiles.
+func fetchProfiles(s *source, o *plugin.Options) (*profile.Profile, error) {
+	sources := make([]profileSource, 0, len(s.Sources)+len(s.Base))
+	for _, src := range s.Sources {
+		sources = append(sources, profileSource{
+			addr:   src,
+			source: s,
+			scale:  1,
+		})
+	}
+	for _, src := range s.Base {
+		sources = append(sources, profileSource{
+			addr:   src,
+			source: s,
+			scale:  -1,
+		})
+	}
+	p, msrcs, save, cnt, err := chunkedGrab(sources, o.Fetch, o.Obj, o.UI)
+	if err != nil {
+		return nil, err
+	}
+	if cnt == 0 {
+		return nil, fmt.Errorf("failed to fetch any profiles")
+	}
+	if want, got := len(sources), cnt; want != got {
+		o.UI.PrintErr(fmt.Sprintf("fetched %d profiles out of %d", got, want))
+	}
+
+	// Symbolize the merged profile.
+	if err := o.Sym.Symbolize(s.Symbolize, msrcs, p); err != nil {
+		return nil, err
+	}
+	p.RemoveUninteresting()
+	unsourceMappings(p)
+
+	// Save a copy of the merged profile if there is at least one remote source.
+	if save {
+		dir, err := setTmpDir(o.UI)
+		if err != nil {
+			return nil, err
+		}
+
+		prefix := "pprof."
+		if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
+			prefix += filepath.Base(p.Mapping[0].File) + "."
+		}
+		for _, s := range p.SampleType {
+			prefix += s.Type + "."
+		}
+
+		tempFile, err := newTempFile(dir, prefix, ".pb.gz")
+		if err == nil {
+			if err = p.Write(tempFile); err == nil {
+				o.UI.PrintErr("Saved profile in ", tempFile.Name())
+			}
+		}
+		if err != nil {
+			o.UI.PrintErr("Could not save profile: ", err)
+		}
+	}
+
+	if err := p.CheckValid(); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// chunkedGrab fetches the profiles described in source and merges them into
+// a single profile. It fetches a chunk of profiles concurrently, with a maximum
+// chunk size to limit its memory usage.
+func chunkedGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (*profile.Profile, plugin.MappingSources, bool, int, error) {
+	const chunkSize = 64
+
+	var p *profile.Profile
+	var msrc plugin.MappingSources
+	var save bool
+	var count int
+
+	for start := 0; start < len(sources); start += chunkSize {
+		end := start + chunkSize
+		if end > len(sources) {
+			end = len(sources)
+		}
+		chunkP, chunkMsrc, chunkSave, chunkCount, chunkErr := concurrentGrab(sources[start:end], fetch, obj, ui)
+		switch {
+		case chunkErr != nil:
+			return nil, nil, false, 0, chunkErr
+		case chunkP == nil:
+			continue
+		case p == nil:
+			p, msrc, save, count = chunkP, chunkMsrc, chunkSave, chunkCount
+		default:
+			p, msrc, chunkErr = combineProfiles([]*profile.Profile{p, chunkP}, []plugin.MappingSources{msrc, chunkMsrc})
+			if chunkErr != nil {
+				return nil, nil, false, 0, chunkErr
+			}
+			if chunkSave {
+				save = true
+			}
+			count += chunkCount
+		}
+	}
+	return p, msrc, save, count, nil
+}
+
+// concurrentGrab fetches multiple profiles concurrently
+func concurrentGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (*profile.Profile, plugin.MappingSources, bool, int, error) {
+	wg := sync.WaitGroup{}
+	wg.Add(len(sources))
+	for i := range sources {
+		go func(s *profileSource) {
+			defer wg.Done()
+			s.p, s.msrc, s.remote, s.err = grabProfile(s.source, s.addr, s.scale, fetch, obj, ui)
+		}(&sources[i])
+	}
+	wg.Wait()
+
+	var save bool
+	profiles := make([]*profile.Profile, 0, len(sources))
+	msrcs := make([]plugin.MappingSources, 0, len(sources))
+	for i := range sources {
+		s := &sources[i]
+		if err := s.err; err != nil {
+			ui.PrintErr(s.addr + ": " + err.Error())
+			continue
+		}
+		save = save || s.remote
+		profiles = append(profiles, s.p)
+		msrcs = append(msrcs, s.msrc)
+		*s = profileSource{}
+	}
+
+	if len(profiles) == 0 {
+		return nil, nil, false, 0, nil
+	}
+
+	p, msrc, err := combineProfiles(profiles, msrcs)
+	if err != nil {
+		return nil, nil, false, 0, err
+	}
+	return p, msrc, save, len(profiles), nil
+}
+
+func combineProfiles(profiles []*profile.Profile, msrcs []plugin.MappingSources) (*profile.Profile, plugin.MappingSources, error) {
+	// Merge profiles.
+	if err := measurement.ScaleProfiles(profiles); err != nil {
+		return nil, nil, err
+	}
+
+	p, err := profile.Merge(profiles)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// Combine mapping sources.
+	msrc := make(plugin.MappingSources)
+	for _, ms := range msrcs {
+		for m, s := range ms {
+			msrc[m] = append(msrc[m], s...)
+		}
+	}
+	return p, msrc, nil
+}
+
+type profileSource struct {
+	addr   string
+	source *source
+	scale  float64
+
+	p      *profile.Profile
+	msrc   plugin.MappingSources
+	remote bool
+	err    error
+}
+
+func homeEnv() string {
+	switch runtime.GOOS {
+	case "windows":
+		return "USERPROFILE"
+	case "plan9":
+		return "home"
+	default:
+		return "HOME"
+	}
+}
+
+// setTmpDir prepares the directory to use to save profiles retrieved
+// remotely. It is selected from PPROF_TMPDIR, defaults to $HOME/pprof.
+func setTmpDir(ui plugin.UI) (string, error) {
+	if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir != "" {
+		return profileDir, nil
+	}
+	for _, tmpDir := range []string{os.Getenv(homeEnv()) + "/pprof", os.TempDir()} {
+		if err := os.MkdirAll(tmpDir, 0755); err != nil {
+			ui.PrintErr("Could not use temp dir ", tmpDir, ": ", err.Error())
+			continue
+		}
+		return tmpDir, nil
+	}
+	return "", fmt.Errorf("failed to identify temp dir")
+}
+
+// grabProfile fetches a profile. Returns the profile, sources for the
+// profile mappings, a bool indicating if the profile was fetched
+// remotely, and an error.
+func grabProfile(s *source, source string, scale float64, fetcher plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (p *profile.Profile, msrc plugin.MappingSources, remote bool, err error) {
+	var src string
+	duration, timeout := time.Duration(s.Seconds)*time.Second, time.Duration(s.Timeout)*time.Second
+	if fetcher != nil {
+		p, src, err = fetcher.Fetch(source, duration, timeout)
+		if err != nil {
+			return
+		}
+	}
+	if err != nil || p == nil {
+		// Fetch the profile over HTTP or from a file.
+		p, src, err = fetch(source, duration, timeout, ui)
+		if err != nil {
+			return
+		}
+	}
+
+	if err = p.CheckValid(); err != nil {
+		return
+	}
+
+	// Apply local changes to the profile.
+	p.Scale(scale)
+
+	// Update the binary locations from command line and paths.
+	locateBinaries(p, s, obj, ui)
+
+	// Collect the source URL for all mappings.
+	if src != "" {
+		msrc = collectMappingSources(p, src)
+		remote = true
+	}
+	return
+}
+
+// collectMappingSources saves the mapping sources of a profile.
+func collectMappingSources(p *profile.Profile, source string) plugin.MappingSources {
+	ms := plugin.MappingSources{}
+	for _, m := range p.Mapping {
+		src := struct {
+			Source string
+			Start  uint64
+		}{
+			source, m.Start,
+		}
+		key := m.BuildID
+		if key == "" {
+			key = m.File
+		}
+		if key == "" {
+			// If there is no build id or source file, use the source as the
+			// mapping file. This will enable remote symbolization for this
+			// mapping, in particular for Go profiles on the legacy format.
+			// The source is reset back to empty string by unsourceMapping
+			// which is called after symbolization is finished.
+			m.File = source
+			key = source
+		}
+		ms[key] = append(ms[key], src)
+	}
+	return ms
+}
+
+// unsourceMappings iterates over the mappings in a profile and replaces file
+// set to the remote source URL by collectMappingSources back to empty string.
+func unsourceMappings(p *profile.Profile) {
+	for _, m := range p.Mapping {
+		if m.BuildID == "" {
+			if u, err := url.Parse(m.File); err == nil && u.IsAbs() {
+				m.File = ""
+			}
+		}
+	}
+}
+
+// locateBinaries searches for binary files listed in the profile and, if found,
+// updates the profile accordingly.
+func locateBinaries(p *profile.Profile, s *source, obj plugin.ObjTool, ui plugin.UI) {
+	// 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(homeEnv()), "pprof", "binaries")
+	}
+mapping:
+	for _, m := range p.Mapping {
+		var baseName string
+		if m.File != "" {
+			baseName = filepath.Base(m.File)
+		}
+
+		for _, path := range filepath.SplitList(searchPath) {
+			var fileNames []string
+			if m.BuildID != "" {
+				fileNames = []string{filepath.Join(path, m.BuildID, baseName)}
+				if matches, err := filepath.Glob(filepath.Join(path, m.BuildID, "*")); err == nil {
+					fileNames = append(fileNames, matches...)
+				}
+			}
+			if m.File != "" {
+				// Try both the basename and the full path, to support the same directory
+				// structure as the perf symfs option.
+				if baseName != "" {
+					fileNames = append(fileNames, filepath.Join(path, baseName))
+				}
+				fileNames = append(fileNames, filepath.Join(path, m.File))
+			}
+			for _, name := range fileNames {
+				if f, err := obj.Open(name, m.Start, m.Limit, m.Offset); err == nil {
+					defer f.Close()
+					fileBuildID := f.BuildID()
+					if m.BuildID != "" && m.BuildID != fileBuildID {
+						ui.PrintErr("Ignoring local file " + name + ": build-id mismatch (" + m.BuildID + " != " + fileBuildID + ")")
+					} else {
+						m.File = name
+						continue mapping
+					}
+				}
+			}
+		}
+	}
+	// Replace executable filename/buildID with the overrides from source.
+	// Assumes the executable is the first Mapping entry.
+	if execName, buildID := s.ExecName, s.BuildID; execName != "" || buildID != "" {
+		if len(p.Mapping) == 0 {
+			// If there are no mappings, add a fake mapping to attempt symbolization.
+			// This is useful for some profiles generated by the golang runtime, which
+			// do not include any mappings. Symbolization with a fake mapping will only
+			// be successful against a non-PIE binary.
+			m := &profile.Mapping{ID: 1}
+			p.Mapping = []*profile.Mapping{m}
+			for _, l := range p.Location {
+				l.Mapping = m
+			}
+		}
+		m := p.Mapping[0]
+		if execName != "" {
+			m.File = execName
+		}
+		if buildID != "" {
+			m.BuildID = buildID
+		}
+	}
+}
+
+// fetch fetches a profile from source, within the timeout specified,
+// producing messages through the ui. It returns the profile and the
+// url of the actual source of the profile for remote profiles.
+func fetch(source string, duration, timeout time.Duration, ui plugin.UI) (p *profile.Profile, src string, err error) {
+	var f io.ReadCloser
+
+	if sourceURL, timeout := adjustURL(source, duration, timeout); sourceURL != "" {
+		ui.Print("Fetching profile over HTTP from " + sourceURL)
+		if duration > 0 {
+			ui.Print(fmt.Sprintf("Please wait... (%v)", duration))
+		}
+		f, err = fetchURL(sourceURL, timeout)
+		src = sourceURL
+	} else if isPerfFile(source) {
+		f, err = convertPerfData(source, ui)
+	} else {
+		f, err = os.Open(source)
+	}
+	if err == nil {
+		defer f.Close()
+		p, err = profile.Parse(f)
+	}
+	return
+}
+
+// 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: %v", err)
+	}
+	if resp.StatusCode != http.StatusOK {
+		defer resp.Body.Close()
+		return nil, statusCodeError(resp)
+	}
+
+	return resp.Body, nil
+}
+
+func statusCodeError(resp *http.Response) error {
+	if resp.Header.Get("X-Go-Pprof") != "" && strings.Contains(resp.Header.Get("Content-Type"), "text/plain") {
+		// error is from pprof endpoint
+		if body, err := ioutil.ReadAll(resp.Body); err == nil {
+			return fmt.Errorf("server response: %s - %s", resp.Status, body)
+		}
+	}
+	return fmt.Errorf("server response: %s", resp.Status)
+}
+
+// isPerfFile checks if a file is in perf.data format. It also returns false
+// if it encounters an error during the check.
+func isPerfFile(path string) bool {
+	sourceFile, openErr := os.Open(path)
+	if openErr != nil {
+		return false
+	}
+	defer sourceFile.Close()
+
+	// If the file is the output of a perf record command, it should begin
+	// with the string PERFILE2.
+	perfHeader := []byte("PERFILE2")
+	actualHeader := make([]byte, len(perfHeader))
+	if _, readErr := sourceFile.Read(actualHeader); readErr != nil {
+		return false
+	}
+	return bytes.Equal(actualHeader, perfHeader)
+}
+
+// convertPerfData converts the file at path which should be in perf.data format
+// using the perf_to_profile tool and returns the file containing the
+// profile.proto formatted data.
+func convertPerfData(perfPath string, ui plugin.UI) (*os.File, error) {
+	ui.Print(fmt.Sprintf(
+		"Converting %s to a profile.proto... (May take a few minutes)",
+		perfPath))
+	profile, err := newTempFile(os.TempDir(), "pprof_", ".pb.gz")
+	if err != nil {
+		return nil, err
+	}
+	deferDeleteTempFile(profile.Name())
+	cmd := exec.Command("perf_to_profile", perfPath, profile.Name())
+	if err := cmd.Run(); err != nil {
+		profile.Close()
+		return nil, fmt.Errorf("failed to convert perf.data file. Try github.com/google/perf_data_converter: %v", err)
+	}
+	return profile, nil
+}
+
+// adjustURL validates if a profile source is a URL and returns an
+// cleaned up URL and the timeout to use for retrieval over HTTP.
+// If the source cannot be recognized as a URL it returns an empty string.
+func adjustURL(source string, duration, timeout time.Duration) (string, time.Duration) {
+	u, err := url.Parse(source)
+	if err != nil || (u.Host == "" && u.Scheme != "" && u.Scheme != "file") {
+		// Try adding http:// to catch sources of the form hostname:port/path.
+		// url.Parse treats "hostname" as the scheme.
+		u, err = url.Parse("http://" + source)
+	}
+	if err != nil || u.Host == "" {
+		return "", 0
+	}
+
+	// Apply duration/timeout overrides to URL.
+	values := u.Query()
+	if duration > 0 {
+		values.Set("seconds", fmt.Sprint(int(duration.Seconds())))
+	} else {
+		if urlSeconds := values.Get("seconds"); urlSeconds != "" {
+			if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
+				duration = time.Duration(us) * time.Second
+			}
+		}
+	}
+	if timeout <= 0 {
+		if duration > 0 {
+			timeout = duration + duration/2
+		} else {
+			timeout = 60 * time.Second
+		}
+	}
+	u.RawQuery = values.Encode()
+	return u.String(), timeout
+}
+
+// httpGet is a wrapper around http.Get; it is defined as a variable
+// so it can be redefined during for testing.
+var httpGet = func(source string, timeout time.Duration) (*http.Response, error) {
+	url, err := url.Parse(source)
+	if err != nil {
+		return nil, err
+	}
+
+	var tlsConfig *tls.Config
+	if url.Scheme == "https+insecure" {
+		tlsConfig = &tls.Config{
+			InsecureSkipVerify: true,
+		}
+		url.Scheme = "https"
+		source = url.String()
+	}
+
+	client := &http.Client{
+		Transport: &http.Transport{
+			ResponseHeaderTimeout: timeout + 5*time.Second,
+			Proxy:           http.ProxyFromEnvironment,
+			TLSClientConfig: tlsConfig,
+		},
+	}
+	return client.Get(source)
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
new file mode 100644
index 0000000..90b84b2
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
@@ -0,0 +1,229 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"reflect"
+	"regexp"
+	"runtime"
+	"testing"
+	"time"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/proftest"
+	"github.com/google/pprof/profile"
+)
+
+func TestSymbolizationPath(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("test assumes Unix paths")
+	}
+
+	// Save environment variables to restore after test
+	saveHome := os.Getenv(homeEnv())
+	savePath := os.Getenv("PPROF_BINARY_PATH")
+
+	tempdir, err := ioutil.TempDir("", "home")
+	if err != nil {
+		t.Fatal("creating temp dir: ", err)
+	}
+	defer os.RemoveAll(tempdir)
+	os.MkdirAll(filepath.Join(tempdir, "pprof", "binaries", "abcde10001"), 0700)
+	os.Create(filepath.Join(tempdir, "pprof", "binaries", "abcde10001", "binary"))
+
+	obj := testObj{tempdir}
+	os.Setenv(homeEnv(), tempdir)
+	for _, tc := range []struct {
+		env, file, buildID, want string
+		msgCount                 int
+	}{
+		{"", "/usr/bin/binary", "", "/usr/bin/binary", 0},
+		{"", "/usr/bin/binary", "fedcb10000", "/usr/bin/binary", 0},
+		{"/usr", "/bin/binary", "", "/usr/bin/binary", 0},
+		{"", "/prod/path/binary", "abcde10001", filepath.Join(tempdir, "pprof/binaries/abcde10001/binary"), 0},
+		{"/alternate/architecture", "/usr/bin/binary", "", "/alternate/architecture/binary", 0},
+		{"/alternate/architecture", "/usr/bin/binary", "abcde10001", "/alternate/architecture/binary", 0},
+		{"/nowhere:/alternate/architecture", "/usr/bin/binary", "fedcb10000", "/usr/bin/binary", 1},
+		{"/nowhere:/alternate/architecture", "/usr/bin/binary", "abcde10002", "/usr/bin/binary", 1},
+	} {
+		os.Setenv("PPROF_BINARY_PATH", tc.env)
+		p := &profile.Profile{
+			Mapping: []*profile.Mapping{
+				{
+					File:    tc.file,
+					BuildID: tc.buildID,
+				},
+			},
+		}
+		s := &source{}
+		locateBinaries(p, s, obj, &proftest.TestUI{T: t, Ignore: tc.msgCount})
+		if file := p.Mapping[0].File; file != tc.want {
+			t.Errorf("%s:%s:%s, want %s, got %s", tc.env, tc.file, tc.buildID, tc.want, file)
+		}
+	}
+	os.Setenv(homeEnv(), saveHome)
+	os.Setenv("PPROF_BINARY_PATH", savePath)
+}
+
+func TestCollectMappingSources(t *testing.T) {
+	const startAddress uint64 = 0x40000
+	const url = "http://example.com"
+	for _, tc := range []struct {
+		file, buildID string
+		want          plugin.MappingSources
+	}{
+		{"/usr/bin/binary", "buildId", mappingSources("buildId", url, startAddress)},
+		{"/usr/bin/binary", "", mappingSources("/usr/bin/binary", url, startAddress)},
+		{"", "", mappingSources(url, url, startAddress)},
+	} {
+		p := &profile.Profile{
+			Mapping: []*profile.Mapping{
+				{
+					File:    tc.file,
+					BuildID: tc.buildID,
+					Start:   startAddress,
+				},
+			},
+		}
+		got := collectMappingSources(p, url)
+		if !reflect.DeepEqual(got, tc.want) {
+			t.Errorf("%s:%s, want %v, got %v", tc.file, tc.buildID, tc.want, got)
+		}
+	}
+}
+
+func TestUnsourceMappings(t *testing.T) {
+	for _, tc := range []struct {
+		file, buildID, want string
+	}{
+		{"/usr/bin/binary", "buildId", "/usr/bin/binary"},
+		{"http://example.com", "", ""},
+	} {
+		p := &profile.Profile{
+			Mapping: []*profile.Mapping{
+				{
+					File:    tc.file,
+					BuildID: tc.buildID,
+				},
+			},
+		}
+		unsourceMappings(p)
+		if got := p.Mapping[0].File; got != tc.want {
+			t.Errorf("%s:%s, want %s, got %s", tc.file, tc.buildID, tc.want, got)
+		}
+	}
+}
+
+type testObj struct {
+	home string
+}
+
+func (o testObj) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	switch file {
+	case "/alternate/architecture/binary":
+		return testFile{file, "abcde10001"}, nil
+	case "/usr/bin/binary":
+		return testFile{file, "fedcb10000"}, nil
+	case filepath.Join(o.home, "pprof/binaries/abcde10001/binary"):
+		return testFile{file, "abcde10001"}, nil
+	}
+	return nil, fmt.Errorf("not found: %s", file)
+}
+func (testObj) Demangler(_ string) func(names []string) (map[string]string, error) {
+	return func(names []string) (map[string]string, error) { return nil, nil }
+}
+func (testObj) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { return nil, nil }
+
+type testFile struct{ name, buildID string }
+
+func (f testFile) Name() string                                               { return f.name }
+func (testFile) Base() uint64                                                 { return 0 }
+func (f testFile) BuildID() string                                            { return f.buildID }
+func (testFile) SourceLine(addr uint64) ([]plugin.Frame, error)               { return nil, nil }
+func (testFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) { return nil, nil }
+func (testFile) Close() error                                                 { return nil }
+
+func TestFetch(t *testing.T) {
+	const path = "testdata/"
+
+	// Intercept http.Get calls from HTTPFetcher.
+	httpGet = stubHTTPGet
+
+	type testcase struct {
+		source, execName string
+	}
+
+	for _, tc := range []testcase{
+		{path + "go.crc32.cpu", ""},
+		{path + "go.nomappings.crash", "/bin/gotest.exe"},
+		{"http://localhost/profile?file=cppbench.cpu", ""},
+	} {
+		p, _, _, err := grabProfile(&source{ExecName: tc.execName}, tc.source, 0, nil, testObj{}, &proftest.TestUI{T: t})
+		if err != nil {
+			t.Fatalf("%s: %s", tc.source, err)
+		}
+		if len(p.Sample) == 0 {
+			t.Errorf("%s: want non-zero samples", tc.source)
+		}
+		if e := tc.execName; e != "" {
+			switch {
+			case len(p.Mapping) == 0 || p.Mapping[0] == nil:
+				t.Errorf("%s: want mapping[0].execName == %s, got no mappings", tc.source, e)
+			case p.Mapping[0].File != e:
+				t.Errorf("%s: want mapping[0].execName == %s, got %s", tc.source, e, p.Mapping[0].File)
+			}
+		}
+	}
+}
+
+// mappingSources creates MappingSources map with a single item.
+func mappingSources(key, source string, start uint64) plugin.MappingSources {
+	return plugin.MappingSources{
+		key: []struct {
+			Source string
+			Start  uint64
+		}{
+			{Source: source, Start: start},
+		},
+	}
+}
+
+// stubHTTPGet intercepts a call to http.Get and rewrites it to use
+// "file://" to get the profile directly from a file.
+func stubHTTPGet(source string, _ time.Duration) (*http.Response, error) {
+	url, err := url.Parse(source)
+	if err != nil {
+		return nil, err
+	}
+
+	values := url.Query()
+	file := values.Get("file")
+
+	if file == "" {
+		return nil, fmt.Errorf("want .../file?profile, got %s", source)
+	}
+
+	t := &http.Transport{}
+	t.RegisterProtocol("file", http.NewFileTransport(http.Dir("testdata/")))
+
+	c := &http.Client{Transport: t}
+	return c.Get("file:///" + file)
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
new file mode 100644
index 0000000..aa9c5b8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
@@ -0,0 +1,430 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"io"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/report"
+	"github.com/google/pprof/profile"
+)
+
+var commentStart = "//:" // Sentinel for comments on options
+var tailDigitsRE = regexp.MustCompile("[0-9]+$")
+
+// interactive starts a shell to read pprof commands.
+func interactive(p *profile.Profile, o *plugin.Options) error {
+	// Enter command processing loop.
+	o.UI.SetAutoComplete(newCompleter(functionNames(p)))
+	pprofVariables.set("compact_labels", "true")
+	pprofVariables["sample_index"].help += fmt.Sprintf("Or use sample_index=name, with name in %v.\n", sampleTypes(p))
+
+	// Do not wait for the visualizer to complete, to allow multiple
+	// graphs to be visualized simultaneously.
+	interactiveMode = true
+	shortcuts := profileShortcuts(p)
+
+	greetings(p, o.UI)
+	for {
+		input, err := o.UI.ReadLine("(pprof) ")
+		if err != nil {
+			if err != io.EOF {
+				return err
+			}
+			if input == "" {
+				return nil
+			}
+		}
+
+		for _, input := range shortcuts.expand(input) {
+			// Process assignments of the form variable=value
+			if s := strings.SplitN(input, "=", 2); len(s) > 0 {
+				name := strings.TrimSpace(s[0])
+				var value string
+				if len(s) == 2 {
+					value = s[1]
+					if comment := strings.LastIndex(value, commentStart); comment != -1 {
+						value = value[:comment]
+					}
+					value = strings.TrimSpace(value)
+				}
+				if v := pprofVariables[name]; v != nil {
+					if name == "sample_index" {
+						// Error check sample_index=xxx to ensure xxx is a valid sample type.
+						index, err := p.SampleIndexByName(value)
+						if err != nil {
+							o.UI.PrintErr(err)
+							continue
+						}
+						value = p.SampleType[index].Type
+					}
+					if err := pprofVariables.set(name, value); err != nil {
+						o.UI.PrintErr(err)
+					}
+					continue
+				}
+				// Allow group=variable syntax by converting into variable="".
+				if v := pprofVariables[value]; v != nil && v.group == name {
+					if err := pprofVariables.set(value, ""); err != nil {
+						o.UI.PrintErr(err)
+					}
+					continue
+				}
+			}
+
+			tokens := strings.Fields(input)
+			if len(tokens) == 0 {
+				continue
+			}
+
+			switch tokens[0] {
+			case "o", "options":
+				printCurrentOptions(p, o.UI)
+				continue
+			case "exit", "quit":
+				return nil
+			case "help":
+				commandHelp(strings.Join(tokens[1:], " "), o.UI)
+				continue
+			}
+
+			args, vars, err := parseCommandLine(tokens)
+			if err == nil {
+				err = generateReportWrapper(p, args, vars, o)
+			}
+
+			if err != nil {
+				o.UI.PrintErr(err)
+			}
+		}
+	}
+}
+
+var generateReportWrapper = generateReport // For testing purposes.
+
+// greetings prints a brief welcome and some overall profile
+// information before accepting interactive commands.
+func greetings(p *profile.Profile, ui plugin.UI) {
+	ropt, err := reportOptions(p, pprofVariables)
+	if err == nil {
+		ui.Print(strings.Join(report.ProfileLabels(report.New(p, ropt)), "\n"))
+	}
+	ui.Print("Entering interactive mode (type \"help\" for commands, \"o\" for options)")
+}
+
+// shortcuts represents composite commands that expand into a sequence
+// of other commands.
+type shortcuts map[string][]string
+
+func (a shortcuts) expand(input string) []string {
+	input = strings.TrimSpace(input)
+	if a != nil {
+		if r, ok := a[input]; ok {
+			return r
+		}
+	}
+	return []string{input}
+}
+
+var pprofShortcuts = shortcuts{
+	":": []string{"focus=", "ignore=", "hide=", "tagfocus=", "tagignore="},
+}
+
+// profileShortcuts creates macros for convenience and backward compatibility.
+func profileShortcuts(p *profile.Profile) shortcuts {
+	s := pprofShortcuts
+	// Add shortcuts for sample types
+	for _, st := range p.SampleType {
+		command := fmt.Sprintf("sample_index=%s", st.Type)
+		s[st.Type] = []string{command}
+		s["total_"+st.Type] = []string{"mean=0", command}
+		s["mean_"+st.Type] = []string{"mean=1", command}
+	}
+	return s
+}
+
+func sampleTypes(p *profile.Profile) []string {
+	types := make([]string, len(p.SampleType))
+	for i, t := range p.SampleType {
+		types[i] = t.Type
+	}
+	return types
+}
+
+func printCurrentOptions(p *profile.Profile, ui plugin.UI) {
+	var args []string
+	type groupInfo struct {
+		set    string
+		values []string
+	}
+	groups := make(map[string]*groupInfo)
+	for n, o := range pprofVariables {
+		v := o.stringValue()
+		comment := ""
+		if g := o.group; g != "" {
+			gi, ok := groups[g]
+			if !ok {
+				gi = &groupInfo{}
+				groups[g] = gi
+			}
+			if o.boolValue() {
+				gi.set = n
+			}
+			gi.values = append(gi.values, n)
+			continue
+		}
+		switch {
+		case n == "sample_index":
+			st := sampleTypes(p)
+			if v == "" {
+				// Apply default (last sample index).
+				v = st[len(st)-1]
+			}
+			// Add comments for all sample types in profile.
+			comment = "[" + strings.Join(st, " | ") + "]"
+		case n == "source_path":
+			continue
+		case n == "nodecount" && v == "-1":
+			comment = "default"
+		case v == "":
+			// Add quotes for empty values.
+			v = `""`
+		}
+		if comment != "" {
+			comment = commentStart + " " + comment
+		}
+		args = append(args, fmt.Sprintf("  %-25s = %-20s %s", n, v, comment))
+	}
+	for g, vars := range groups {
+		sort.Strings(vars.values)
+		comment := commentStart + " [" + strings.Join(vars.values, " | ") + "]"
+		args = append(args, fmt.Sprintf("  %-25s = %-20s %s", g, vars.set, comment))
+	}
+	sort.Strings(args)
+	ui.Print(strings.Join(args, "\n"))
+}
+
+// parseCommandLine parses a command and returns the pprof command to
+// execute and a set of variables for the report.
+func parseCommandLine(input []string) ([]string, variables, error) {
+	cmd, args := input[:1], input[1:]
+	name := cmd[0]
+
+	c := pprofCommands[name]
+	if c == nil {
+		// Attempt splitting digits on abbreviated commands (eg top10)
+		if d := tailDigitsRE.FindString(name); d != "" && d != name {
+			name = name[:len(name)-len(d)]
+			cmd[0], args = name, append([]string{d}, args...)
+			c = pprofCommands[name]
+		}
+	}
+	if c == nil {
+		return nil, nil, fmt.Errorf("Unrecognized command: %q", name)
+	}
+
+	if c.hasParam {
+		if len(args) == 0 {
+			return nil, nil, fmt.Errorf("command %s requires an argument", name)
+		}
+		cmd = append(cmd, args[0])
+		args = args[1:]
+	}
+
+	// Copy the variables as options set in the command line are not persistent.
+	vcopy := pprofVariables.makeCopy()
+
+	var focus, ignore string
+	for i := 0; i < len(args); i++ {
+		t := args[i]
+		if _, err := strconv.ParseInt(t, 10, 32); err == nil {
+			vcopy.set("nodecount", t)
+			continue
+		}
+		switch t[0] {
+		case '>':
+			outputFile := t[1:]
+			if outputFile == "" {
+				i++
+				if i >= len(args) {
+					return nil, nil, fmt.Errorf("Unexpected end of line after >")
+				}
+				outputFile = args[i]
+			}
+			vcopy.set("output", outputFile)
+		case '-':
+			if t == "--cum" || t == "-cum" {
+				vcopy.set("cum", "t")
+				continue
+			}
+			ignore = catRegex(ignore, t[1:])
+		default:
+			focus = catRegex(focus, t)
+		}
+	}
+
+	if name == "tags" {
+		updateFocusIgnore(vcopy, "tag", focus, ignore)
+	} else {
+		updateFocusIgnore(vcopy, "", focus, ignore)
+	}
+
+	if vcopy["nodecount"].intValue() == -1 && (name == "text" || name == "top") {
+		vcopy.set("nodecount", "10")
+	}
+
+	return cmd, vcopy, nil
+}
+
+func updateFocusIgnore(v variables, prefix, f, i string) {
+	if f != "" {
+		focus := prefix + "focus"
+		v.set(focus, catRegex(v[focus].value, f))
+	}
+
+	if i != "" {
+		ignore := prefix + "ignore"
+		v.set(ignore, catRegex(v[ignore].value, i))
+	}
+}
+
+func catRegex(a, b string) string {
+	if a != "" && b != "" {
+		return a + "|" + b
+	}
+	return a + b
+}
+
+// commandHelp displays help and usage information for all Commands
+// and Variables or a specific Command or Variable.
+func commandHelp(args string, ui plugin.UI) {
+	if args == "" {
+		help := usage(false)
+		help = help + `
+  :   Clear focus/ignore/hide/tagfocus/tagignore
+
+  type "help <cmd|option>" for more information
+`
+
+		ui.Print(help)
+		return
+	}
+
+	if c := pprofCommands[args]; c != nil {
+		ui.Print(c.help(args))
+		return
+	}
+
+	if v := pprofVariables[args]; v != nil {
+		ui.Print(v.help + "\n")
+		return
+	}
+
+	ui.PrintErr("Unknown command: " + args)
+}
+
+// newCompleter creates an autocompletion function for a set of commands.
+func newCompleter(fns []string) func(string) string {
+	return func(line string) string {
+		v := pprofVariables
+		switch tokens := strings.Fields(line); len(tokens) {
+		case 0:
+			// Nothing to complete
+		case 1:
+			// Single token -- complete command name
+			if match := matchVariableOrCommand(v, tokens[0]); match != "" {
+				return match
+			}
+		case 2:
+			if tokens[0] == "help" {
+				if match := matchVariableOrCommand(v, tokens[1]); match != "" {
+					return tokens[0] + " " + match
+				}
+				return line
+			}
+			fallthrough
+		default:
+			// Multiple tokens -- complete using functions, except for tags
+			if cmd := pprofCommands[tokens[0]]; cmd != nil && tokens[0] != "tags" {
+				lastTokenIdx := len(tokens) - 1
+				lastToken := tokens[lastTokenIdx]
+				if strings.HasPrefix(lastToken, "-") {
+					lastToken = "-" + functionCompleter(lastToken[1:], fns)
+				} else {
+					lastToken = functionCompleter(lastToken, fns)
+				}
+				return strings.Join(append(tokens[:lastTokenIdx], lastToken), " ")
+			}
+		}
+		return line
+	}
+}
+
+// matchCommand attempts to match a string token to the prefix of a Command.
+func matchVariableOrCommand(v variables, token string) string {
+	token = strings.ToLower(token)
+	found := ""
+	for cmd := range pprofCommands {
+		if strings.HasPrefix(cmd, token) {
+			if found != "" {
+				return ""
+			}
+			found = cmd
+		}
+	}
+	for variable := range v {
+		if strings.HasPrefix(variable, token) {
+			if found != "" {
+				return ""
+			}
+			found = variable
+		}
+	}
+	return found
+}
+
+// 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, fns []string) string {
+	found := ""
+	for _, fName := range fns {
+		if strings.Contains(fName, substring) {
+			if found != "" {
+				return substring
+			}
+			found = fName
+		}
+	}
+	if found != "" {
+		return found
+	}
+	return substring
+}
+
+func functionNames(p *profile.Profile) []string {
+	var fns []string
+	for _, fn := range p.Function {
+		fns = append(fns, fn.Name)
+	}
+	return fns
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go
new file mode 100644
index 0000000..ba80741
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go
@@ -0,0 +1,325 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"io"
+	"math/rand"
+	"strings"
+	"testing"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/report"
+	"github.com/google/pprof/profile"
+)
+
+func TestShell(t *testing.T) {
+	p := &profile.Profile{}
+	generateReportWrapper = checkValue
+	defer func() { generateReportWrapper = generateReport }()
+
+	// Use test commands and variables to exercise interactive processing
+	var savedCommands commands
+	savedCommands, pprofCommands = pprofCommands, testCommands
+	defer func() { pprofCommands = savedCommands }()
+
+	savedVariables := pprofVariables
+	defer func() { pprofVariables = savedVariables }()
+
+	// Random interleave of independent scripts
+	pprofVariables = testVariables(savedVariables)
+	o := setDefaults(nil)
+	o.UI = newUI(t, interleave(script, 0))
+	if err := interactive(p, o); err != nil {
+		t.Error("first attempt:", err)
+	}
+	// Random interleave of independent scripts
+	pprofVariables = testVariables(savedVariables)
+	o.UI = newUI(t, interleave(script, 1))
+	if err := interactive(p, o); err != nil {
+		t.Error("second attempt:", err)
+	}
+
+	// Random interleave of independent scripts with shortcuts
+	pprofVariables = testVariables(savedVariables)
+	var scScript []string
+	pprofShortcuts, scScript = makeShortcuts(interleave(script, 2), 1)
+	o.UI = newUI(t, scScript)
+	if err := interactive(p, o); err != nil {
+		t.Error("first shortcut attempt:", err)
+	}
+
+	// Random interleave of independent scripts with shortcuts
+	pprofVariables = testVariables(savedVariables)
+	pprofShortcuts, scScript = makeShortcuts(interleave(script, 1), 2)
+	o.UI = newUI(t, scScript)
+	if err := interactive(p, o); err != nil {
+		t.Error("second shortcut attempt:", err)
+	}
+
+	// Verify propagation of IO errors
+	pprofVariables = testVariables(savedVariables)
+	o.UI = newUI(t, []string{"**error**"})
+	if err := interactive(p, o); err == nil {
+		t.Error("expected IO error, got nil")
+	}
+
+}
+
+var testCommands = commands{
+	"check": &command{report.Raw, nil, nil, true, "", ""},
+}
+
+func testVariables(base variables) variables {
+	v := base.makeCopy()
+
+	v["b"] = &variable{boolKind, "f", "", ""}
+	v["bb"] = &variable{boolKind, "f", "", ""}
+	v["i"] = &variable{intKind, "0", "", ""}
+	v["ii"] = &variable{intKind, "0", "", ""}
+	v["f"] = &variable{floatKind, "0", "", ""}
+	v["ff"] = &variable{floatKind, "0", "", ""}
+	v["s"] = &variable{stringKind, "", "", ""}
+	v["ss"] = &variable{stringKind, "", "", ""}
+
+	v["ta"] = &variable{boolKind, "f", "radio", ""}
+	v["tb"] = &variable{boolKind, "f", "radio", ""}
+	v["tc"] = &variable{boolKind, "t", "radio", ""}
+
+	return v
+}
+
+// script contains sequences of commands to be executed for testing. Commands
+// are split by semicolon and interleaved randomly, so they must be
+// independent from each other.
+var script = []string{
+	"bb=true;bb=false;check bb=false;bb=yes;check bb=true",
+	"b=1;check b=true;b=n;check b=false",
+	"i=-1;i=-2;check i=-2;i=999999;check i=999999",
+	"check ii=0;ii=-1;check ii=-1;ii=100;check ii=100",
+	"f=-1;f=-2.5;check f=-2.5;f=0.0001;check f=0.0001",
+	"check ff=0;ff=-1.01;check ff=-1.01;ff=100;check ff=100",
+	"s=one;s=two;check s=two",
+	"ss=tree;check ss=tree;ss=;check ss;ss=forest;check ss=forest",
+	"ta=true;check ta=true;check tb=false;check tc=false;tb=1;check tb=true;check ta=false;check tc=false;tc=yes;check tb=false;check ta=false;check tc=true",
+}
+
+func makeShortcuts(input []string, seed int) (shortcuts, []string) {
+	rand.Seed(int64(seed))
+
+	s := shortcuts{}
+	var output, chunk []string
+	for _, l := range input {
+		chunk = append(chunk, l)
+		switch rand.Intn(3) {
+		case 0:
+			// Create a macro for commands in 'chunk'.
+			macro := fmt.Sprintf("alias%d", len(s))
+			s[macro] = chunk
+			output = append(output, macro)
+			chunk = nil
+		case 1:
+			// Append commands in 'chunk' by themselves.
+			output = append(output, chunk...)
+			chunk = nil
+		case 2:
+			// Accumulate commands into 'chunk'
+		}
+	}
+	output = append(output, chunk...)
+	return s, output
+}
+
+func newUI(t *testing.T, input []string) plugin.UI {
+	return &testUI{
+		t:     t,
+		input: input,
+	}
+}
+
+type testUI struct {
+	t     *testing.T
+	input []string
+	index int
+}
+
+func (ui *testUI) ReadLine(_ string) (string, error) {
+	if ui.index >= len(ui.input) {
+		return "", io.EOF
+	}
+	input := ui.input[ui.index]
+	if input == "**error**" {
+		return "", fmt.Errorf("Error: %s", input)
+	}
+	ui.index++
+	return input, nil
+}
+
+func (ui *testUI) Print(args ...interface{}) {
+}
+
+func (ui *testUI) PrintErr(args ...interface{}) {
+	output := fmt.Sprint(args)
+	if output != "" {
+		ui.t.Error(output)
+	}
+}
+
+func (ui *testUI) IsTerminal() bool {
+	return false
+}
+
+func (ui *testUI) SetAutoComplete(func(string) string) {
+}
+
+func checkValue(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
+	if len(cmd) != 2 {
+		return fmt.Errorf("expected len(cmd)==2, got %v", cmd)
+	}
+
+	input := cmd[1]
+	args := strings.SplitN(input, "=", 2)
+	if len(args) == 0 {
+		return fmt.Errorf("unexpected empty input")
+	}
+	name, value := args[0], ""
+	if len(args) == 2 {
+		value = args[1]
+	}
+
+	gotv := vars[name]
+	if gotv == nil {
+		return fmt.Errorf("Could not find variable named %s", name)
+	}
+
+	if got := gotv.stringValue(); got != value {
+		return fmt.Errorf("Variable %s, want %s, got %s", name, value, got)
+	}
+	return nil
+}
+
+func interleave(input []string, seed int) []string {
+	var inputs [][]string
+	for _, s := range input {
+		inputs = append(inputs, strings.Split(s, ";"))
+	}
+	rand.Seed(int64(seed))
+	var output []string
+	for len(inputs) > 0 {
+		next := rand.Intn(len(inputs))
+		output = append(output, inputs[next][0])
+		if tail := inputs[next][1:]; len(tail) > 0 {
+			inputs[next] = tail
+		} else {
+			inputs = append(inputs[:next], inputs[next+1:]...)
+		}
+	}
+	return output
+}
+
+func TestInteractiveCommands(t *testing.T) {
+	type interactiveTestcase struct {
+		input string
+		want  map[string]string
+	}
+
+	testcases := []interactiveTestcase{
+		{
+			"top 10 --cum focus1 -ignore focus2",
+			map[string]string{
+				"functions": "true",
+				"nodecount": "10",
+				"cum":       "true",
+				"focus":     "focus1|focus2",
+				"ignore":    "ignore",
+			},
+		},
+		{
+			"top10 --cum focus1 -ignore focus2",
+			map[string]string{
+				"functions": "true",
+				"nodecount": "10",
+				"cum":       "true",
+				"focus":     "focus1|focus2",
+				"ignore":    "ignore",
+			},
+		},
+		{
+			"dot",
+			map[string]string{
+				"functions": "true",
+				"nodecount": "80",
+				"cum":       "false",
+			},
+		},
+		{
+			"tags   -ignore1 -ignore2 focus1 >out",
+			map[string]string{
+				"functions": "true",
+				"nodecount": "80",
+				"cum":       "false",
+				"output":    "out",
+				"tagfocus":  "focus1",
+				"tagignore": "ignore1|ignore2",
+			},
+		},
+		{
+			"weblist  find -test",
+			map[string]string{
+				"functions":        "false",
+				"addressnoinlines": "true",
+				"nodecount":        "0",
+				"cum":              "false",
+				"flat":             "true",
+				"ignore":           "test",
+			},
+		},
+		{
+			"callgrind   fun -ignore  >out",
+			map[string]string{
+				"functions": "false",
+				"addresses": "true",
+				"nodecount": "0",
+				"cum":       "false",
+				"flat":      "true",
+				"output":    "out",
+			},
+		},
+		{
+			"999",
+			nil, // Error
+		},
+	}
+
+	for _, tc := range testcases {
+		cmd, vars, err := parseCommandLine(strings.Fields(tc.input))
+		if tc.want == nil && err != nil {
+			// Error expected
+			continue
+		}
+		if err != nil {
+			t.Errorf("failed on %q: %v", tc.input, err)
+			continue
+		}
+		vars = applyCommandOverrides(cmd, vars)
+
+		for n, want := range tc.want {
+			if got := vars[n].stringValue(); got != want {
+				t.Errorf("failed on %q, cmd=%q, %s got %s, want %s", tc.input, cmd, n, got, want)
+			}
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go
new file mode 100644
index 0000000..cb20e94
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go
@@ -0,0 +1,148 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/google/pprof/internal/binutils"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/symbolizer"
+)
+
+// setDefaults returns a new plugin.Options with zero fields sets to
+// sensible defaults.
+func setDefaults(o *plugin.Options) *plugin.Options {
+	d := &plugin.Options{}
+	if o != nil {
+		*d = *o
+	}
+	if d.Writer == nil {
+		d.Writer = oswriter{}
+	}
+	if d.Flagset == nil {
+		d.Flagset = goFlags{}
+	}
+	if d.Obj == nil {
+		d.Obj = &binutils.Binutils{}
+	}
+	if d.UI == nil {
+		d.UI = &stdUI{r: bufio.NewReader(os.Stdin)}
+	}
+	if d.Sym == nil {
+		d.Sym = &symbolizer.Symbolizer{Obj: d.Obj, UI: d.UI}
+	}
+	return d
+}
+
+// goFlags returns a flagset implementation based on the standard flag
+// package from the Go distribution. It implements the plugin.FlagSet
+// interface.
+type goFlags struct{}
+
+func (goFlags) Bool(o string, d bool, c string) *bool {
+	return flag.Bool(o, d, c)
+}
+
+func (goFlags) Int(o string, d int, c string) *int {
+	return flag.Int(o, d, c)
+}
+
+func (goFlags) Float64(o string, d float64, c string) *float64 {
+	return flag.Float64(o, d, c)
+}
+
+func (goFlags) String(o, d, c string) *string {
+	return flag.String(o, d, c)
+}
+
+func (goFlags) BoolVar(b *bool, o string, d bool, c string) {
+	flag.BoolVar(b, o, d, c)
+}
+
+func (goFlags) IntVar(i *int, o string, d int, c string) {
+	flag.IntVar(i, o, d, c)
+}
+
+func (goFlags) Float64Var(f *float64, o string, d float64, c string) {
+	flag.Float64Var(f, o, d, c)
+}
+
+func (goFlags) StringVar(s *string, o, d, c string) {
+	flag.StringVar(s, o, d, c)
+}
+
+func (goFlags) StringList(o, d, c string) *[]*string {
+	return &[]*string{flag.String(o, d, c)}
+}
+
+func (goFlags) ExtraUsage() string {
+	return ""
+}
+
+func (goFlags) Parse(usage func()) []string {
+	flag.Usage = usage
+	flag.Parse()
+	args := flag.Args()
+	if len(args) == 0 {
+		usage()
+	}
+	return args
+}
+
+type stdUI struct {
+	r *bufio.Reader
+}
+
+func (ui *stdUI) ReadLine(prompt string) (string, error) {
+	os.Stdout.WriteString(prompt)
+	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)
+}
+
+// oswriter implements the Writer interface using a regular file.
+type oswriter struct{}
+
+func (oswriter) Open(name string) (io.WriteCloser, error) {
+	f, err := os.Create(name)
+	return f, err
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go
new file mode 100644
index 0000000..28679f1
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go
@@ -0,0 +1,54 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package driver
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+)
+
+// newTempFile returns a new output file in dir with the provided prefix and suffix.
+func newTempFile(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{}
+
+// deferDeleteTempFile marks a file to be deleted by next call to Cleanup()
+func deferDeleteTempFile(path string) {
+	tempFilesMu.Lock()
+	tempFiles = append(tempFiles, path)
+	tempFilesMu.Unlock()
+}
+
+// cleanupTempFiles removes any temporary files selected for deferred cleaning.
+func cleanupTempFiles() {
+	tempFilesMu.Lock()
+	for _, f := range tempFiles {
+		os.Remove(f)
+	}
+	tempFiles = nil
+	tempFilesMu.Unlock()
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/cppbench.cpu b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/cppbench.cpu
new file mode 100644
index 0000000..95c22e1
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/cppbench.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file1000.src b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file1000.src
new file mode 100644
index 0000000..b53eeca
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file1000.src
@@ -0,0 +1,17 @@
+line1
+line2
+line3
+line4
+line5
+line6
+line7
+line8
+line9
+line0
+line1
+line2
+line3
+line4
+line5
+		
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file2000.src b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file2000.src
new file mode 100644
index 0000000..b53eeca
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file2000.src
@@ -0,0 +1,17 @@
+line1
+line2
+line3
+line4
+line5
+line6
+line7
+line8
+line9
+line0
+line1
+line2
+line3
+line4
+line5
+		
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file3000.src b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file3000.src
new file mode 100644
index 0000000..b53eeca
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/file3000.src
@@ -0,0 +1,17 @@
+line1
+line2
+line3
+line4
+line5
+line6
+line7
+line8
+line9
+line0
+line1
+line2
+line3
+line4
+line5
+		
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.crc32.cpu b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.crc32.cpu
new file mode 100644
index 0000000..ce08313
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.crc32.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.nomappings.crash b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.nomappings.crash
new file mode 100644
index 0000000..4915d5a
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/go.nomappings.crash differ
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.cum.files.dot b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.cum.files.dot
new file mode 100644
index 0000000..2e130c8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.cum.files.dot
@@ -0,0 +1,10 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid-contention" [shape=box fontsize=16 label="Build ID: buildid-contention\lComment #1\lComment #2\lType: delay\lShowing nodes accounting for 149.50ms, 100% of 149.50ms total\l"] }
+N1 [label="file3000.src\n32.77ms (21.92%)\nof 149.50ms (100%)" fontsize=20 shape=box tooltip="testdata/file3000.src (149.50ms)" color="#b20000" fillcolor="#edd5d5"]
+N2 [label="file1000.src\n51.20ms (34.25%)" fontsize=23 shape=box tooltip="testdata/file1000.src (51.20ms)" color="#b23100" fillcolor="#eddbd5"]
+N3 [label="file2000.src\n65.54ms (43.84%)\nof 75.78ms (50.68%)" fontsize=24 shape=box tooltip="testdata/file2000.src (75.78ms)" color="#b22000" fillcolor="#edd9d5"]
+N1 -> N3 [label=" 75.78ms" weight=51 penwidth=3 color="#b22000" tooltip="testdata/file3000.src -> testdata/file2000.src (75.78ms)" labeltooltip="testdata/file3000.src -> testdata/file2000.src (75.78ms)"]
+N1 -> N2 [label=" 40.96ms" weight=28 penwidth=2 color="#b23900" tooltip="testdata/file3000.src -> testdata/file1000.src (40.96ms)" labeltooltip="testdata/file3000.src -> testdata/file1000.src (40.96ms)"]
+N3 -> N2 [label=" 10.24ms" weight=7 color="#b29775" tooltip="testdata/file2000.src -> testdata/file1000.src (10.24ms)" labeltooltip="testdata/file2000.src -> testdata/file1000.src (10.24ms)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.flat.addresses.dot.focus.ignore b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.flat.addresses.dot.focus.ignore
new file mode 100644
index 0000000..aa08a41
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.contention.flat.addresses.dot.focus.ignore
@@ -0,0 +1,9 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid-contention" [shape=box fontsize=16 label="Build ID: buildid-contention\lComment #1\lComment #2\lType: delay\lShowing nodes accounting for 40.96ms, 27.40% of 149.50ms total\l"] }
+N1 [label="0000000000001000\nline1000\nfile1000.src:1\n40.96ms (27.40%)" fontsize=24 shape=box tooltip="0000000000001000 line1000 testdata/file1000.src:1 (40.96ms)" color="#b23900" fillcolor="#edddd5"]
+N2 [label="0000000000003001\nline3000\nfile3000.src:5\n0 of 40.96ms (27.40%)" fontsize=8 shape=box tooltip="0000000000003001 line3000 testdata/file3000.src:5 (40.96ms)" color="#b23900" fillcolor="#edddd5"]
+N3 [label="0000000000003001\nline3001\nfile3000.src:3\n0 of 40.96ms (27.40%)" fontsize=8 shape=box tooltip="0000000000003001 line3001 testdata/file3000.src:3 (40.96ms)" color="#b23900" fillcolor="#edddd5"]
+N2 -> N3 [label=" 40.96ms\n (inline)" weight=28 penwidth=2 color="#b23900" tooltip="0000000000003001 line3000 testdata/file3000.src:5 -> 0000000000003001 line3001 testdata/file3000.src:3 (40.96ms)" labeltooltip="0000000000003001 line3000 testdata/file3000.src:5 -> 0000000000003001 line3001 testdata/file3000.src:3 (40.96ms)"]
+N3 -> N1 [label=" 40.96ms" weight=28 penwidth=2 color="#b23900" tooltip="0000000000003001 line3001 testdata/file3000.src:3 -> 0000000000001000 line1000 testdata/file1000.src:1 (40.96ms)" labeltooltip="0000000000003001 line3001 testdata/file3000.src:3 -> 0000000000001000 line1000 testdata/file1000.src:1 (40.96ms)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.callgrind b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.callgrind
new file mode 100644
index 0000000..0b04996
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.callgrind
@@ -0,0 +1,88 @@
+positions: instr line
+events: cpu(ms)
+
+ob=(1) /path/to/testbinary
+fl=(1) testdata/file1000.src
+fn=(1) line1000
+0x1000 1 1100
+
+ob=(1)
+fl=(2) testdata/file2000.src
+fn=(2) line2001
++4096 9 10
+cfl=(1)
+cfn=(1)
+calls=0 * 1
+* * 1000
+
+ob=(1)
+fl=(3) testdata/file3000.src
+fn=(3) line3002
++4096 2 10
+cfl=(2)
+cfn=(4) line2000
+calls=0 * 4
+* * 1000
+
+ob=(1)
+fl=(2)
+fn=(4)
+-4096 4 0
+cfl=(2)
+cfn=(2)
+calls=0 -4096 9
+* * 1010
+
+ob=(1)
+fl=(3)
+fn=(5) line3000
++4096 6 0
+cfl=(3)
+cfn=(6) line3001
+calls=0 +4096 5
+* * 1010
+
+ob=(1)
+fl=(3)
+fn=(6)
+* 5 0
+cfl=(3)
+cfn=(3)
+calls=0 * 2
+* * 1010
+
+ob=(1)
+fl=(3)
+fn=(5)
++1 9 0
+cfl=(3)
+cfn=(6)
+calls=0 +1 8
+* * 100
+
+ob=(1)
+fl=(3)
+fn=(6)
+* 8 0
+cfl=(1)
+cfn=(1)
+calls=0 -8193 1
+* * 100
+
+ob=(1)
+fl=(3)
+fn=(5)
++1 9 0
+cfl=(3)
+cfn=(3)
+calls=0 +1 5
+* * 10
+
+ob=(1)
+fl=(3)
+fn=(3)
+* 5 0
+cfl=(2)
+cfn=(4)
+calls=0 -4098 4
+* * 10
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.comments b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.comments
new file mode 100644
index 0000000..e69de29
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.hide b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.hide
new file mode 100644
index 0000000..9d17271
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.hide
@@ -0,0 +1,5 @@
+Showing nodes accounting for 1.11s, 99.11% of 1.12s total
+      flat  flat%   sum%        cum   cum%
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000 testdata/file1000.src:1
+         0     0% 98.21%      1.01s 90.18%  line2000 testdata/file2000.src:4
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2001 testdata/file2000.src:9 (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.show b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.show
new file mode 100644
index 0000000..9d17271
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.text.show
@@ -0,0 +1,5 @@
+Showing nodes accounting for 1.11s, 99.11% of 1.12s total
+      flat  flat%   sum%        cum   cum%
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000 testdata/file1000.src:1
+         0     0% 98.21%      1.01s 90.18%  line2000 testdata/file2000.src:4
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2001 testdata/file2000.src:9 (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.topproto.hide b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.topproto.hide
new file mode 100644
index 0000000..33bf681
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.cum.lines.topproto.hide
@@ -0,0 +1,3 @@
+Showing nodes accounting for 1s, 100% of 1s total
+      flat  flat%   sum%        cum   cum%
+        1s   100%   100%         1s   100%  mangled1000 testdata/file1000.src:1
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.disasm b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.disasm
new file mode 100644
index 0000000..9c8e603
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.disasm
@@ -0,0 +1,14 @@
+Total: 1.12s
+ROUTINE ======================== line1000
+     1.10s      1.10s (flat, cum) 98.21% of Total
+     1.10s      1.10s       1000: instruction one                         ;line1000 file1000.src:1
+         .          .       1001: instruction two
+         .          .       1002: instruction three
+         .          .       1003: instruction four
+ROUTINE ======================== line3000
+      10ms      1.12s (flat, cum)   100% of Total
+      10ms      1.01s       3000: instruction one                         ;line3000 file3000.src:6
+         .      100ms       3001: instruction two                         ;line3000 file3000.src:9
+         .       10ms       3002: instruction three
+         .          .       3003: instruction four
+         .          .       3004: instruction five
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.weblist b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.weblist
new file mode 100644
index 0000000..ccf4ee8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.addresses.weblist
@@ -0,0 +1,109 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+font-family: sans-serif;
+}
+h1 {
+  font-size: 1.5em;
+  margin-bottom: 4px;
+}
+.legend {
+  font-size: 1.25em;
+}
+.line {
+color: #aaaaaa;
+}
+.nop {
+color: #aaaaaa;
+}
+.unimportant {
+color: #cccccc;
+}
+.disasmloc {
+color: #000000;
+}
+.deadsrc {
+cursor: pointer;
+}
+.deadsrc:hover {
+background-color: #eeeeee;
+}
+.livesrc {
+color: #0000ff;
+cursor: pointer;
+}
+.livesrc:hover {
+background-color: #eeeeee;
+}
+.asm {
+color: #008800;
+display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+  var target;
+  if (!e) e = window.event;
+  if (e.target) target = e.target;
+  else if (e.srcElement) target = e.srcElement;
+
+  if (target) {
+    var asm = target.nextSibling;
+    if (asm && asm.className == "asm") {
+      asm.style.display = (asm.style.display == "block" ? "" : "block");
+      e.preventDefault();
+      return false;
+    }
+  }
+}
+</script>
+</head>
+<body>
+
+<div class="legend">File: testbinary<br>
+Type: cpu<br>
+Duration: 10s, Total samples = 1.12s (11.20%)<br>Total: 1.12s</div><h1>line1000</h1>testdata/file1000.src
+<pre onClick="pprof_toggle_asm(event)">
+  Total:       1.10s      1.10s (flat, cum) 98.21%
+<span class=line>      1</span> <span class=deadsrc>       1.10s      1.10s line1 </span><span class=asm>               1.10s      1.10s     1000: instruction one                                  <span class=disasmloc>file1000.src:1</span>
+                   .          .     1001: instruction two                                  <span class=disasmloc></span>
+                   .          .     1002: instruction three                                <span class=disasmloc></span>
+                   .          .     1003: instruction four                                 <span class=disasmloc></span>
+</span>
+<span class=line>      2</span> <span class=nop>           .          . line2 </span>
+<span class=line>      3</span> <span class=nop>           .          . line3 </span>
+<span class=line>      4</span> <span class=nop>           .          . line4 </span>
+<span class=line>      5</span> <span class=nop>           .          . line5 </span>
+<span class=line>      6</span> <span class=nop>           .          . line6 </span>
+</pre>
+<h1>line3000</h1>testdata/file3000.src
+<pre onClick="pprof_toggle_asm(event)">
+  Total:        10ms      1.12s (flat, cum)   100%
+<span class=line>      1</span> <span class=nop>           .          . line1 </span>
+<span class=line>      2</span> <span class=nop>           .          . line2 </span>
+<span class=line>      3</span> <span class=nop>           .          . line3 </span>
+<span class=line>      4</span> <span class=nop>           .          . line4 </span>
+<span class=line>      5</span> <span class=nop>           .          . line5 </span>
+<span class=line>      6</span> <span class=deadsrc>        10ms      1.01s line6 </span><span class=asm>                10ms      1.01s     3000: instruction one                                  <span class=disasmloc>file3000.src:6</span>
+</span>
+<span class=line>      7</span> <span class=nop>           .          . line7 </span>
+<span class=line>      8</span> <span class=nop>           .          . line8 </span>
+<span class=line>      9</span> <span class=deadsrc>           .      110ms line9 </span><span class=asm>                   .      100ms     3001: instruction two                                  <span class=disasmloc>file3000.src:9</span>
+                   .       10ms     3002: instruction three                                <span class=disasmloc>file3000.src:9</span>
+                   .          .     3003: instruction four                                 <span class=disasmloc></span>
+                   .          .     3004: instruction five                                 <span class=disasmloc></span>
+</span>
+<span class=line>     10</span> <span class=nop>           .          . line0 </span>
+<span class=line>     11</span> <span class=nop>           .          . line1 </span>
+<span class=line>     12</span> <span class=nop>           .          . line2 </span>
+<span class=line>     13</span> <span class=nop>           .          . line3 </span>
+<span class=line>     14</span> <span class=nop>           .          . line4 </span>
+</pre>
+
+</body>
+</html>
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.dot b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.dot
new file mode 100644
index 0000000..18b1abf
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.dot
@@ -0,0 +1,20 @@
+digraph "testbinary" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "File: testbinary" [shape=box fontsize=16 label="File: testbinary\lType: cpu\lDuration: 10s, Total samples = 1.12s (11.20%)\lShowing nodes accounting for 1.12s, 100% of 1.12s total\l"] }
+N1 [label="line1000\nfile1000.src\n1.10s (98.21%)" fontsize=24 shape=box tooltip="line1000 testdata/file1000.src (1.10s)" color="#b20000" fillcolor="#edd5d5"]
+N1_0 [label = "key1:tag1\nkey2:tag1" fontsize=8 shape=box3d tooltip="1s"]
+N1 -> N1_0 [label=" 1s" weight=100 tooltip="1s" labeltooltip="1s"]
+N1_1 [label = "key1:tag2\nkey3:tag2" fontsize=8 shape=box3d tooltip="0.10s"]
+N1 -> N1_1 [label=" 0.10s" weight=100 tooltip="0.10s" labeltooltip="0.10s"]
+N2 [label="line3000\nfile3000.src\n0 of 1.12s (100%)" fontsize=8 shape=box tooltip="line3000 testdata/file3000.src (1.12s)" color="#b20000" fillcolor="#edd5d5"]
+N3 [label="line3001\nfile3000.src\n0 of 1.11s (99.11%)" fontsize=8 shape=box tooltip="line3001 testdata/file3000.src (1.11s)" color="#b20000" fillcolor="#edd5d5"]
+N4 [label="line3002\nfile3000.src\n0.01s (0.89%)\nof 1.02s (91.07%)" fontsize=10 shape=box tooltip="line3002 testdata/file3000.src (1.02s)" color="#b20400" fillcolor="#edd6d5"]
+N5 [label="line2001\nfile2000.src\n0.01s (0.89%)\nof 1.01s (90.18%)" fontsize=10 shape=box tooltip="line2001 testdata/file2000.src (1.01s)" color="#b20500" fillcolor="#edd6d5"]
+N6 [label="line2000\nfile2000.src\n0 of 1.01s (90.18%)" fontsize=8 shape=box tooltip="line2000 testdata/file2000.src (1.01s)" color="#b20500" fillcolor="#edd6d5"]
+N2 -> N3 [label=" 1.11s\n (inline)" weight=100 penwidth=5 color="#b20000" tooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (1.11s)" labeltooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (1.11s)"]
+N6 -> N5 [label=" 1.01s\n (inline)" weight=91 penwidth=5 color="#b20500" tooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (1.01s)" labeltooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (1.01s)"]
+N3 -> N4 [label=" 1.01s\n (inline)" weight=91 penwidth=5 color="#b20500" tooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (1.01s)" labeltooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (1.01s)"]
+N4 -> N6 [label=" 1.01s" weight=91 penwidth=5 color="#b20500" tooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (1.01s)" labeltooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (1.01s)"]
+N5 -> N1 [label=" 1s" weight=90 penwidth=5 color="#b20500" tooltip="line2001 testdata/file2000.src -> line1000 testdata/file1000.src (1s)" labeltooltip="line2001 testdata/file2000.src -> line1000 testdata/file1000.src (1s)"]
+N3 -> N1 [label=" 0.10s" weight=9 color="#b28b62" tooltip="line3001 testdata/file3000.src -> line1000 testdata/file1000.src (0.10s)" labeltooltip="line3001 testdata/file3000.src -> line1000 testdata/file1000.src (0.10s)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.text
new file mode 100644
index 0000000..0807ed2
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.flat.functions.text
@@ -0,0 +1,8 @@
+Showing nodes accounting for 1.12s, 100% of 1.12s total
+      flat  flat%   sum%        cum   cum%
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000 testdata/file1000.src
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2001 testdata/file2000.src (inline)
+     0.01s  0.89%   100%      1.02s 91.07%  line3002 testdata/file3000.src (inline)
+         0     0%   100%      1.01s 90.18%  line2000 testdata/file2000.src
+         0     0%   100%      1.12s   100%  line3000 testdata/file3000.src
+         0     0%   100%      1.11s 99.11%  line3001 testdata/file3000.src (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.peek b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.peek
new file mode 100644
index 0000000..1a4a70c
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.peek
@@ -0,0 +1,13 @@
+Showing nodes accounting for 1.12s, 100% of 1.12s total
+----------------------------------------------------------+-------------
+      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 
+----------------------------------------------------------+-------------
+                                             1.01s   100% |   line2000 testdata/file2000.src (inline)
+     0.01s  0.89%  0.89%      1.01s 90.18%                | line2001 testdata/file2000.src
+                                                1s 99.01% |   line1000 testdata/file1000.src
+----------------------------------------------------------+-------------
+                                             1.11s   100% |   line3000 testdata/file3000.src (inline)
+         0     0%  0.89%      1.11s 99.11%                | line3001 testdata/file3000.src
+                                             1.01s 90.99% |   line3002 testdata/file3000.src (inline)
+                                             0.10s  9.01% |   line1000 testdata/file1000.src
+----------------------------------------------------------+-------------
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags
new file mode 100644
index 0000000..fc784f0
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags
@@ -0,0 +1,13 @@
+key1: Total 1120
+      1000 (89.29%): tag1
+       100 ( 8.93%): tag2
+        10 ( 0.89%): tag3
+        10 ( 0.89%): tag4
+
+key2: Total 1020
+      1010 (99.02%): tag1
+        10 ( 0.98%): tag2
+
+key3: Total 100
+       100 (  100%): tag2
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags.focus.ignore b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags.focus.ignore
new file mode 100644
index 0000000..650ebb1
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.tags.focus.ignore
@@ -0,0 +1,6 @@
+key1: Total 100
+       100 (  100%): tag2
+
+key3: Total 100
+       100 (  100%): tag2
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.traces b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.traces
new file mode 100644
index 0000000..d59fe30
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpu.traces
@@ -0,0 +1,32 @@
+File: testbinary
+Type: cpu
+Duration: 10s, Total samples = 1.12s (11.20%)
+-----------+-------------------------------------------------------
+      key1:  tag1
+      key2:  tag1
+        1s   line1000 testdata/file1000.src
+             line2001 testdata/file2000.src
+             line2000 testdata/file2000.src
+             line3002 testdata/file3000.src
+             line3001 testdata/file3000.src
+             line3000 testdata/file3000.src
+-----------+-------------------------------------------------------
+      key1:  tag2
+      key3:  tag2
+     100ms   line1000 testdata/file1000.src
+             line3001 testdata/file3000.src
+             line3000 testdata/file3000.src
+-----------+-------------------------------------------------------
+      key1:  tag3
+      key2:  tag2
+      10ms   line2001 testdata/file2000.src
+             line2000 testdata/file2000.src
+             line3002 testdata/file3000.src
+             line3000 testdata/file3000.src
+-----------+-------------------------------------------------------
+      key1:  tag4
+      key2:  tag1
+      10ms   line3002 testdata/file3000.src
+             line3001 testdata/file3000.src
+             line3000 testdata/file3000.src
+-----------+-------------------------------------------------------
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpusmall.flat.addresses.tree b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpusmall.flat.addresses.tree
new file mode 100644
index 0000000..606db2b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.cpusmall.flat.addresses.tree
@@ -0,0 +1,17 @@
+Showing nodes accounting for 4s, 100% of 4s total
+Showing top 4 nodes out of 5
+----------------------------------------------------------+-------------
+      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 
+----------------------------------------------------------+-------------
+                                                1s   100% |   0000000000003000 [testbinary]
+        1s 25.00% 25.00%         1s 25.00%                | 0000000000001000 [testbinary]
+----------------------------------------------------------+-------------
+        1s 25.00% 50.00%         2s 50.00%                | 0000000000003000 [testbinary]
+                                                1s 50.00% |   0000000000001000 [testbinary]
+----------------------------------------------------------+-------------
+                                                1s   100% |   0000000000005000 [testbinary]
+        1s 25.00% 75.00%         1s 25.00%                | 0000000000004000 [testbinary]
+----------------------------------------------------------+-------------
+        1s 25.00%   100%         2s 50.00%                | 0000000000005000 [testbinary]
+                                                1s 50.00% |   0000000000004000 [testbinary]
+----------------------------------------------------------+-------------
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.callgrind b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.callgrind
new file mode 100644
index 0000000..bfd96cb
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.callgrind
@@ -0,0 +1,88 @@
+positions: instr line
+events: inuse_space(MB)
+
+ob=
+fl=(1) testdata/file2000.src
+fn=(1) line2001
+0x2000 2 62
+cfl=(2) testdata/file1000.src
+cfn=(2) line1000
+calls=0 0x1000 1
+* * 0
+
+ob=
+fl=(3) testdata/file3000.src
+fn=(3) line3002
++4096 3 31
+cfl=(1)
+cfn=(4) line2000
+calls=0 * 3
+* * 0
+
+ob=
+fl=(2)
+fn=(2)
+-8192 1 4
+
+ob=
+fl=(1)
+fn=(4)
++4096 3 0
+cfl=(1)
+cfn=(1)
+calls=0 +4096 2
+* * 63
+
+ob=
+fl=(3)
+fn=(5) line3000
++4096 4 0
+cfl=(3)
+cfn=(6) line3001
+calls=0 +4096 2
+* * 32
+
+ob=
+fl=(3)
+fn=(6)
+* 2 0
+cfl=(3)
+cfn=(3)
+calls=0 * 3
+* * 32
+
+ob=
+fl=(3)
+fn=(5)
++1 4 0
+cfl=(3)
+cfn=(6)
+calls=0 +1 2
+* * 3
+
+ob=
+fl=(3)
+fn=(6)
+* 2 0
+cfl=(2)
+cfn=(2)
+calls=0 -8193 1
+* * 3
+
+ob=
+fl=(3)
+fn=(5)
++1 4 0
+cfl=(3)
+cfn=(3)
+calls=0 +1 3
+* * 62
+
+ob=
+fl=(3)
+fn=(3)
+* 3 0
+cfl=(1)
+cfn=(4)
+calls=0 -4098 3
+* * 62
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.comments b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.comments
new file mode 100644
index 0000000..6eca2fb
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.comments
@@ -0,0 +1,2 @@
+comment
+#hidden comment
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.lines.tree.focus b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.lines.tree.focus
new file mode 100644
index 0000000..cda6d65
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.lines.tree.focus
@@ -0,0 +1,19 @@
+Showing nodes accounting for 62.50MB, 63.37% of 98.63MB total
+Dropped 2 nodes (cum <= 4.93MB)
+----------------------------------------------------------+-------------
+      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line3002 testdata/file3000.src:3
+         0     0%     0%    63.48MB 64.36%                | line2000 testdata/file2000.src:3
+                                           63.48MB   100% |   line2001 testdata/file2000.src:2 (inline)
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line2000 testdata/file2000.src:3 (inline)
+   62.50MB 63.37% 63.37%    63.48MB 64.36%                | line2001 testdata/file2000.src:2
+----------------------------------------------------------+-------------
+         0     0% 63.37%    63.48MB 64.36%                | line3000 testdata/file3000.src:4
+                                           63.48MB   100% |   line3002 testdata/file3000.src:3 (inline)
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line3000 testdata/file3000.src:4 (inline)
+         0     0% 63.37%    63.48MB 64.36%                | line3002 testdata/file3000.src:3
+                                           63.48MB   100% |   line2000 testdata/file2000.src:3
+----------------------------------------------------------+-------------
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.relative_percentages.tree.focus b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.relative_percentages.tree.focus
new file mode 100644
index 0000000..35f0bf5
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.cum.relative_percentages.tree.focus
@@ -0,0 +1,19 @@
+Showing nodes accounting for 62.50MB, 98.46% of 63.48MB total
+Dropped 2 nodes (cum <= 3.17MB)
+----------------------------------------------------------+-------------
+      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line3002 testdata/file3000.src
+         0     0%     0%    63.48MB   100%                | line2000 testdata/file2000.src
+                                           63.48MB   100% |   line2001 testdata/file2000.src (inline)
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line2000 testdata/file2000.src (inline)
+   62.50MB 98.46% 98.46%    63.48MB   100%                | line2001 testdata/file2000.src
+----------------------------------------------------------+-------------
+         0     0% 98.46%    63.48MB   100%                | line3000 testdata/file3000.src
+                                           63.48MB   100% |   line3002 testdata/file3000.src (inline)
+----------------------------------------------------------+-------------
+                                           63.48MB   100% |   line3000 testdata/file3000.src (inline)
+         0     0% 98.46%    63.48MB   100%                | line3002 testdata/file3000.src
+                                           63.48MB   100% |   line2000 testdata/file2000.src
+----------------------------------------------------------+-------------
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.seconds.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.seconds.text
new file mode 100644
index 0000000..b9571ef
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.seconds.text
@@ -0,0 +1,2 @@
+Showing nodes accounting for 0, 0% of 0 total
+      flat  flat%   sum%        cum   cum%
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.text
new file mode 100644
index 0000000..fd536df
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.files.text
@@ -0,0 +1,5 @@
+Showing nodes accounting for 93.75MB, 95.05% of 98.63MB total
+Dropped 1 node (cum <= 4.93MB)
+      flat  flat%   sum%        cum   cum%
+   62.50MB 63.37% 63.37%    63.48MB 64.36%  testdata/file2000.src
+   31.25MB 31.68% 95.05%    98.63MB   100%  testdata/file3000.src
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_objects.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_objects.text
new file mode 100644
index 0000000..bc061ad
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_objects.text
@@ -0,0 +1,8 @@
+Showing nodes accounting for 150, 100% of 150 total
+      flat  flat%   sum%        cum   cum%
+        80 53.33% 53.33%        130 86.67%  line3002 testdata/file3000.src (inline)
+        40 26.67% 80.00%         50 33.33%  line2001 testdata/file2000.src (inline)
+        30 20.00%   100%         30 20.00%  line1000 testdata/file1000.src
+         0     0%   100%         50 33.33%  line2000 testdata/file2000.src
+         0     0%   100%        150   100%  line3000 testdata/file3000.src
+         0     0%   100%        110 73.33%  line3001 testdata/file3000.src (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus
new file mode 100644
index 0000000..c8533f3
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus
@@ -0,0 +1,13 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid" [shape=box fontsize=16 label="Build ID: buildid\lcomment\lType: inuse_space\lShowing nodes accounting for 62.50MB, 63.37% of 98.63MB total\l"] }
+N1 [label="line2001\nfile2000.src\n62.50MB (63.37%)" fontsize=24 shape=box tooltip="line2001 testdata/file2000.src (62.50MB)" color="#b21600" fillcolor="#edd8d5"]
+NN1_0 [label = "1.56MB" fontsize=8 shape=box3d tooltip="62.50MB"]
+N1 -> NN1_0 [label=" 62.50MB" weight=100 tooltip="62.50MB" labeltooltip="62.50MB"]
+N2 [label="line3000\nfile3000.src\n0 of 62.50MB (63.37%)" fontsize=8 shape=box tooltip="line3000 testdata/file3000.src (62.50MB)" color="#b21600" fillcolor="#edd8d5"]
+N3 [label="line2000\nfile2000.src\n0 of 62.50MB (63.37%)" fontsize=8 shape=box tooltip="line2000 testdata/file2000.src (62.50MB)" color="#b21600" fillcolor="#edd8d5"]
+N4 [label="line3002\nfile3000.src\n0 of 62.50MB (63.37%)" fontsize=8 shape=box tooltip="line3002 testdata/file3000.src (62.50MB)" color="#b21600" fillcolor="#edd8d5"]
+N3 -> N1 [label=" 62.50MB\n (inline)" weight=64 penwidth=4 color="#b21600" tooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (62.50MB)" labeltooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (62.50MB)"]
+N2 -> N4 [label=" 62.50MB\n (inline)" weight=64 penwidth=4 color="#b21600" tooltip="line3000 testdata/file3000.src -> line3002 testdata/file3000.src (62.50MB)" labeltooltip="line3000 testdata/file3000.src -> line3002 testdata/file3000.src (62.50MB)"]
+N4 -> N3 [label=" 62.50MB" weight=64 penwidth=4 color="#b21600" tooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (62.50MB)" labeltooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (62.50MB)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus.ignore b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus.ignore
new file mode 100644
index 0000000..40354dd
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.inuse_space.dot.focus.ignore
@@ -0,0 +1,16 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid" [shape=box fontsize=16 label="Build ID: buildid\lcomment\lType: inuse_space\lShowing nodes accounting for 36.13MB, 36.63% of 98.63MB total\lDropped 2 nodes (cum <= 4.93MB)\l"] }
+N1 [label="line3002\nfile3000.src\n31.25MB (31.68%)\nof 32.23MB (32.67%)" fontsize=24 shape=box tooltip="line3002 testdata/file3000.src (32.23MB)" color="#b23200" fillcolor="#eddcd5"]
+NN1_0 [label = "400kB" fontsize=8 shape=box3d tooltip="31.25MB"]
+N1 -> NN1_0 [label=" 31.25MB" weight=100 tooltip="31.25MB" labeltooltip="31.25MB"]
+N2 [label="line3000\nfile3000.src\n0 of 36.13MB (36.63%)" fontsize=8 shape=box tooltip="line3000 testdata/file3000.src (36.13MB)" color="#b22e00" fillcolor="#eddbd5"]
+N3 [label="line3001\nfile3000.src\n0 of 36.13MB (36.63%)" fontsize=8 shape=box tooltip="line3001 testdata/file3000.src (36.13MB)" color="#b22e00" fillcolor="#eddbd5"]
+N4 [label="line1000\nfile1000.src\n4.88MB (4.95%)" fontsize=15 shape=box tooltip="line1000 testdata/file1000.src (4.88MB)" color="#b2a086" fillcolor="#edeae7"]
+NN4_0 [label = "200kB" fontsize=8 shape=box3d tooltip="3.91MB"]
+N4 -> NN4_0 [label=" 3.91MB" weight=100 tooltip="3.91MB" labeltooltip="3.91MB"]
+N2 -> N3 [label=" 36.13MB\n (inline)" weight=37 penwidth=2 color="#b22e00" tooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)" labeltooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)"]
+N3 -> N1 [label=" 32.23MB\n (inline)" weight=33 penwidth=2 color="#b23200" tooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (32.23MB)" labeltooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (32.23MB)"]
+N3 -> N4 [label=" 3.91MB" weight=4 color="#b2a58f" tooltip="line3001 testdata/file3000.src -> line1000 testdata/file1000.src (3.91MB)" labeltooltip="line3001 testdata/file3000.src -> line1000 testdata/file1000.src (3.91MB)"]
+N1 -> N4 [label=" 0.98MB" color="#b2b0a9" tooltip="line3002 testdata/file3000.src ... line1000 testdata/file1000.src (0.98MB)" labeltooltip="line3002 testdata/file3000.src ... line1000 testdata/file1000.src (0.98MB)" style="dotted" minlen=2]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.lines.dot.focus b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.lines.dot.focus
new file mode 100644
index 0000000..f05969c
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.flat.lines.dot.focus
@@ -0,0 +1,21 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid" [shape=box fontsize=16 label="Build ID: buildid\lcomment\lType: inuse_space\lShowing nodes accounting for 67.38MB, 68.32% of 98.63MB total\l"] }
+N1 [label="line3000\nfile3000.src:4\n0 of 67.38MB (68.32%)" fontsize=8 shape=box tooltip="line3000 testdata/file3000.src:4 (67.38MB)" color="#b21300" fillcolor="#edd7d5"]
+N2 [label="line2001\nfile2000.src:2\n62.50MB (63.37%)\nof 63.48MB (64.36%)" fontsize=24 shape=box tooltip="line2001 testdata/file2000.src:2 (63.48MB)" color="#b21600" fillcolor="#edd8d5"]
+NN2_0 [label = "1.56MB" fontsize=8 shape=box3d tooltip="62.50MB"]
+N2 -> NN2_0 [label=" 62.50MB" weight=100 tooltip="62.50MB" labeltooltip="62.50MB"]
+N3 [label="line1000\nfile1000.src:1\n4.88MB (4.95%)" fontsize=13 shape=box tooltip="line1000 testdata/file1000.src:1 (4.88MB)" color="#b2a086" fillcolor="#edeae7"]
+NN3_0 [label = "200kB" fontsize=8 shape=box3d tooltip="3.91MB"]
+N3 -> NN3_0 [label=" 3.91MB" weight=100 tooltip="3.91MB" labeltooltip="3.91MB"]
+N4 [label="line3002\nfile3000.src:3\n0 of 63.48MB (64.36%)" fontsize=8 shape=box tooltip="line3002 testdata/file3000.src:3 (63.48MB)" color="#b21600" fillcolor="#edd8d5"]
+N5 [label="line3001\nfile3000.src:2\n0 of 4.88MB (4.95%)" fontsize=8 shape=box tooltip="line3001 testdata/file3000.src:2 (4.88MB)" color="#b2a086" fillcolor="#edeae7"]
+N6 [label="line2000\nfile2000.src:3\n0 of 63.48MB (64.36%)" fontsize=8 shape=box tooltip="line2000 testdata/file2000.src:3 (63.48MB)" color="#b21600" fillcolor="#edd8d5"]
+N6 -> N2 [label=" 63.48MB\n (inline)" weight=65 penwidth=4 color="#b21600" tooltip="line2000 testdata/file2000.src:3 -> line2001 testdata/file2000.src:2 (63.48MB)" labeltooltip="line2000 testdata/file2000.src:3 -> line2001 testdata/file2000.src:2 (63.48MB)"]
+N4 -> N6 [label=" 63.48MB" weight=65 penwidth=4 color="#b21600" tooltip="line3002 testdata/file3000.src:3 -> line2000 testdata/file2000.src:3 (63.48MB)" labeltooltip="line3002 testdata/file3000.src:3 -> line2000 testdata/file2000.src:3 (63.48MB)"]
+N1 -> N4 [label=" 62.50MB\n (inline)" weight=64 penwidth=4 color="#b21600" tooltip="line3000 testdata/file3000.src:4 -> line3002 testdata/file3000.src:3 (62.50MB)" labeltooltip="line3000 testdata/file3000.src:4 -> line3002 testdata/file3000.src:3 (62.50MB)"]
+N1 -> N5 [label=" 4.88MB\n (inline)" weight=5 color="#b2a086" tooltip="line3000 testdata/file3000.src:4 -> line3001 testdata/file3000.src:2 (4.88MB)" labeltooltip="line3000 testdata/file3000.src:4 -> line3001 testdata/file3000.src:2 (4.88MB)"]
+N5 -> N3 [label=" 3.91MB" weight=4 color="#b2a58f" tooltip="line3001 testdata/file3000.src:2 -> line1000 testdata/file1000.src:1 (3.91MB)" labeltooltip="line3001 testdata/file3000.src:2 -> line1000 testdata/file1000.src:1 (3.91MB)"]
+N2 -> N3 [label=" 0.98MB" color="#b2b0a9" tooltip="line2001 testdata/file2000.src:2 -> line1000 testdata/file1000.src:1 (0.98MB)" labeltooltip="line2001 testdata/file2000.src:2 -> line1000 testdata/file1000.src:1 (0.98MB)" minlen=2]
+N5 -> N4 [label=" 0.98MB\n (inline)" color="#b2b0a9" tooltip="line3001 testdata/file3000.src:2 -> line3002 testdata/file3000.src:3 (0.98MB)" labeltooltip="line3001 testdata/file3000.src:2 -> line3002 testdata/file3000.src:3 (0.98MB)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags
new file mode 100644
index 0000000..7a6f0a7
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags
@@ -0,0 +1,6 @@
+bytes: Total 150
+        80 (53.33%): 400kB
+        40 (26.67%): 1.56MB
+        20 (13.33%): 200kB
+        10 ( 6.67%): 100kB
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags.unit b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags.unit
new file mode 100644
index 0000000..7238b36
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap.tags.unit
@@ -0,0 +1,6 @@
+bytes: Total 150
+        80 (53.33%): 409600B
+        40 (26.67%): 1638400B
+        20 (13.33%): 204800B
+        10 ( 6.67%): 102400B
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_objects.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_objects.text
new file mode 100644
index 0000000..bc061ad
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_objects.text
@@ -0,0 +1,8 @@
+Showing nodes accounting for 150, 100% of 150 total
+      flat  flat%   sum%        cum   cum%
+        80 53.33% 53.33%        130 86.67%  line3002 testdata/file3000.src (inline)
+        40 26.67% 80.00%         50 33.33%  line2001 testdata/file2000.src (inline)
+        30 20.00%   100%         30 20.00%  line1000 testdata/file1000.src
+         0     0%   100%         50 33.33%  line2000 testdata/file2000.src
+         0     0%   100%        150   100%  line3000 testdata/file3000.src
+         0     0%   100%        110 73.33%  line3001 testdata/file3000.src (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.focus b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.focus
new file mode 100644
index 0000000..c693ef3
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.focus
@@ -0,0 +1,18 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid" [shape=box fontsize=16 label="Build ID: buildid\lcomment\lType: alloc_space\lShowing nodes accounting for 93.75MB, 95.05% of 98.63MB total\lDropped 1 node (cum <= 4.93MB)\l"] }
+N1 [label="line3002\nfile3000.src\n31.25MB (31.68%)\nof 94.73MB (96.04%)" fontsize=20 shape=box tooltip="line3002 testdata/file3000.src (94.73MB)" color="#b20200" fillcolor="#edd5d5"]
+NN1_0 [label = "400kB" fontsize=8 shape=box3d tooltip="31.25MB"]
+N1 -> NN1_0 [label=" 31.25MB" weight=100 tooltip="31.25MB" labeltooltip="31.25MB"]
+N2 [label="line3000\nfile3000.src\n0 of 98.63MB (100%)" fontsize=8 shape=box tooltip="line3000 testdata/file3000.src (98.63MB)" color="#b20000" fillcolor="#edd5d5"]
+N3 [label="line2001\nfile2000.src\n62.50MB (63.37%)\nof 63.48MB (64.36%)" fontsize=24 shape=box tooltip="line2001 testdata/file2000.src (63.48MB)" color="#b21600" fillcolor="#edd8d5"]
+NN3_0 [label = "1.56MB" fontsize=8 shape=box3d tooltip="62.50MB"]
+N3 -> NN3_0 [label=" 62.50MB" weight=100 tooltip="62.50MB" labeltooltip="62.50MB"]
+N4 [label="line2000\nfile2000.src\n0 of 63.48MB (64.36%)" fontsize=8 shape=box tooltip="line2000 testdata/file2000.src (63.48MB)" color="#b21600" fillcolor="#edd8d5"]
+N5 [label="line3001\nfile3000.src\n0 of 36.13MB (36.63%)" fontsize=8 shape=box tooltip="line3001 testdata/file3000.src (36.13MB)" color="#b22e00" fillcolor="#eddbd5"]
+N4 -> N3 [label=" 63.48MB\n (inline)" weight=65 penwidth=4 color="#b21600" tooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (63.48MB)" labeltooltip="line2000 testdata/file2000.src -> line2001 testdata/file2000.src (63.48MB)"]
+N1 -> N4 [label=" 63.48MB" weight=65 penwidth=4 color="#b21600" tooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (63.48MB)" labeltooltip="line3002 testdata/file3000.src -> line2000 testdata/file2000.src (63.48MB)" minlen=2]
+N2 -> N1 [label=" 62.50MB\n (inline)" weight=64 penwidth=4 color="#b21600" tooltip="line3000 testdata/file3000.src -> line3002 testdata/file3000.src (62.50MB)" labeltooltip="line3000 testdata/file3000.src -> line3002 testdata/file3000.src (62.50MB)"]
+N2 -> N5 [label=" 36.13MB\n (inline)" weight=37 penwidth=2 color="#b22e00" tooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)" labeltooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)"]
+N5 -> N1 [label=" 32.23MB\n (inline)" weight=33 penwidth=2 color="#b23200" tooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (32.23MB)" labeltooltip="line3001 testdata/file3000.src -> line3002 testdata/file3000.src (32.23MB)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.hide b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.hide
new file mode 100644
index 0000000..26a51c5
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.heap_alloc.flat.alloc_space.dot.hide
@@ -0,0 +1,11 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Build ID: buildid" [shape=box fontsize=16 label="Build ID: buildid\lcomment\lType: alloc_space\lShowing nodes accounting for 93.75MB, 95.05% of 98.63MB total\lDropped 1 node (cum <= 4.93MB)\l"] }
+N1 [label="line3000\nfile3000.src\n62.50MB (63.37%)\nof 98.63MB (100%)" fontsize=24 shape=box tooltip="line3000 testdata/file3000.src (98.63MB)" color="#b20000" fillcolor="#edd5d5"]
+NN1_0 [label = "1.56MB" fontsize=8 shape=box3d tooltip="62.50MB"]
+N1 -> NN1_0 [label=" 62.50MB" weight=100 tooltip="62.50MB" labeltooltip="62.50MB"]
+N2 [label="line3001\nfile3000.src\n31.25MB (31.68%)\nof 36.13MB (36.63%)" fontsize=20 shape=box tooltip="line3001 testdata/file3000.src (36.13MB)" color="#b22e00" fillcolor="#eddbd5"]
+NN2_0 [label = "400kB" fontsize=8 shape=box3d tooltip="31.25MB"]
+N2 -> NN2_0 [label=" 31.25MB" weight=100 tooltip="31.25MB" labeltooltip="31.25MB"]
+N1 -> N2 [label=" 36.13MB\n (inline)" weight=37 penwidth=2 color="#b22e00" tooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)" labeltooltip="line3000 testdata/file3000.src -> line3001 testdata/file3000.src (36.13MB)" minlen=2]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.unknown.flat.functions.text b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.unknown.flat.functions.text
new file mode 100644
index 0000000..0807ed2
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/testdata/pprof.unknown.flat.functions.text
@@ -0,0 +1,8 @@
+Showing nodes accounting for 1.12s, 100% of 1.12s total
+      flat  flat%   sum%        cum   cum%
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000 testdata/file1000.src
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2001 testdata/file2000.src (inline)
+     0.01s  0.89%   100%      1.02s 91.07%  line3002 testdata/file3000.src (inline)
+         0     0%   100%      1.01s 90.18%  line2000 testdata/file2000.src
+         0     0%   100%      1.12s   100%  line3000 testdata/file3000.src
+         0     0%   100%      1.11s 99.11%  line3001 testdata/file3000.src (inline)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
new file mode 100644
index 0000000..c46272e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
@@ -0,0 +1,256 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package elfexec provides utility routines to examine ELF binaries.
+package elfexec
+
+import (
+	"bufio"
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+const (
+	maxNoteSize        = 1 << 20 // in bytes
+	noteTypeGNUBuildID = 3
+)
+
+// elfNote is the payload of a Note Section in an ELF file.
+type elfNote struct {
+	Name string // Contents of the "name" field, omitting the trailing zero byte.
+	Desc []byte // Contents of the "desc" field.
+	Type uint32 // Contents of the "type" field.
+}
+
+// parseNotes returns the notes from a SHT_NOTE section or PT_NOTE segment.
+func parseNotes(reader io.Reader, alignment int, order binary.ByteOrder) ([]elfNote, error) {
+	r := bufio.NewReader(reader)
+
+	// padding returns the number of bytes required to pad the given size to an
+	// alignment boundary.
+	padding := func(size int) int {
+		return ((size + (alignment - 1)) &^ (alignment - 1)) - size
+	}
+
+	var notes []elfNote
+	for {
+		noteHeader := make([]byte, 12) // 3 4-byte words
+		if _, err := io.ReadFull(r, noteHeader); err == io.EOF {
+			break
+		} else if err != nil {
+			return nil, err
+		}
+		namesz := order.Uint32(noteHeader[0:4])
+		descsz := order.Uint32(noteHeader[4:8])
+		typ := order.Uint32(noteHeader[8:12])
+
+		if uint64(namesz) > uint64(maxNoteSize) {
+			return nil, fmt.Errorf("note name too long (%d bytes)", namesz)
+		}
+		var name string
+		if namesz > 0 {
+			// Documentation differs as to whether namesz is meant to include the
+			// trailing zero, but everyone agrees that name is null-terminated.
+			// So we'll just determine the actual length after the fact.
+			var err error
+			name, err = r.ReadString('\x00')
+			if err == io.EOF {
+				return nil, fmt.Errorf("missing note name (want %d bytes)", namesz)
+			} else if err != nil {
+				return nil, err
+			}
+			namesz = uint32(len(name))
+			name = name[:len(name)-1]
+		}
+
+		// Drop padding bytes until the desc field.
+		for n := padding(len(noteHeader) + int(namesz)); n > 0; n-- {
+			if _, err := r.ReadByte(); err == io.EOF {
+				return nil, fmt.Errorf(
+					"missing %d bytes of padding after note name", n)
+			} else if err != nil {
+				return nil, err
+			}
+		}
+
+		if uint64(descsz) > uint64(maxNoteSize) {
+			return nil, fmt.Errorf("note desc too long (%d bytes)", descsz)
+		}
+		desc := make([]byte, int(descsz))
+		if _, err := io.ReadFull(r, desc); err == io.EOF {
+			return nil, fmt.Errorf("missing desc (want %d bytes)", len(desc))
+		} else if err != nil {
+			return nil, err
+		}
+
+		notes = append(notes, elfNote{Name: name, Desc: desc, Type: typ})
+
+		// Drop padding bytes until the next note or the end of the section,
+		// whichever comes first.
+		for n := padding(len(desc)); n > 0; n-- {
+			if _, err := r.ReadByte(); err == io.EOF {
+				// We hit the end of the section before an alignment boundary.
+				// This can happen if this section is at the end of the file or the next
+				// section has a smaller alignment requirement.
+				break
+			} else if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return notes, nil
+}
+
+// GetBuildID returns the GNU build-ID for an ELF binary.
+//
+// If no build-ID was found but the binary was read without error, it returns
+// (nil, nil).
+func GetBuildID(binary io.ReaderAt) ([]byte, error) {
+	f, err := elf.NewFile(binary)
+	if err != nil {
+		return nil, err
+	}
+
+	findBuildID := func(notes []elfNote) ([]byte, error) {
+		var buildID []byte
+		for _, note := range notes {
+			if note.Name == "GNU" && note.Type == noteTypeGNUBuildID {
+				if buildID == nil {
+					buildID = note.Desc
+				} else {
+					return nil, fmt.Errorf("multiple build ids found, don't know which to use!")
+				}
+			}
+		}
+		return buildID, nil
+	}
+
+	for _, p := range f.Progs {
+		if p.Type != elf.PT_NOTE {
+			continue
+		}
+		notes, err := parseNotes(p.Open(), int(p.Align), f.ByteOrder)
+		if err != nil {
+			return nil, err
+		}
+		if b, err := findBuildID(notes); b != nil || err != nil {
+			return b, err
+		}
+	}
+	for _, s := range f.Sections {
+		if s.Type != elf.SHT_NOTE {
+			continue
+		}
+		notes, err := parseNotes(s.Open(), int(s.Addralign), f.ByteOrder)
+		if err != nil {
+			return nil, err
+		}
+		if b, err := findBuildID(notes); b != nil || err != nil {
+			return b, err
+		}
+	}
+	return nil, nil
+}
+
+// GetBase determines the base address to subtract from virtual
+// address to get symbol table address. For an executable, the base
+// is 0. Otherwise, it's a shared library, and the base is the
+// address where the mapping starts. The kernel is special, and may
+// use the address of the _stext symbol as the mmap start. _stext
+// offset can be obtained with `nm vmlinux | grep _stext`
+func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64) (uint64, error) {
+	const (
+		pageSize = 4096
+		// PAGE_OFFSET for PowerPC64, see arch/powerpc/Kconfig in the kernel sources.
+		pageOffsetPpc64 = 0xc000000000000000
+	)
+
+	if start == 0 && offset == 0 &&
+		(limit == ^uint64(0) || limit == 0) {
+		// Some tools may introduce a fake mapping that spans the entire
+		// address space. Assume that the address has already been
+		// adjusted, so no additional base adjustment is necessary.
+		return 0, nil
+	}
+
+	switch fh.Type {
+	case elf.ET_EXEC:
+		if loadSegment == nil {
+			// Fixed-address executable, no adjustment.
+			return 0, nil
+		}
+		if start == 0 && limit != 0 {
+			// ChromeOS remaps its kernel to 0. Nothing else should come
+			// down this path. Empirical values:
+			//       VADDR=0xffffffff80200000
+			// stextOffset=0xffffffff80200198
+			if stextOffset != nil {
+				return -*stextOffset, nil
+			}
+			return -loadSegment.Vaddr, nil
+		}
+		if loadSegment.Vaddr-loadSegment.Off == start-offset {
+			return offset, nil
+		}
+		if loadSegment.Vaddr == start-offset {
+			return offset, nil
+		}
+		if start >= loadSegment.Vaddr && limit > start && (offset == 0 || offset == pageOffsetPpc64) {
+			// Some kernels look like:
+			//       VADDR=0xffffffff80200000
+			// stextOffset=0xffffffff80200198
+			//       Start=0xffffffff83200000
+			//       Limit=0xffffffff84200000
+			//      Offset=0 (0xc000000000000000 for PowerPC64)
+			// So the base should be:
+			if stextOffset != nil && (start%pageSize) == (*stextOffset%pageSize) {
+				// perf uses the address of _stext as start. Some tools may
+				// adjust for this before calling GetBase, in which case the the page
+				// alignment should be different from that of stextOffset.
+				return start - *stextOffset, nil
+			}
+
+			return start - loadSegment.Vaddr, nil
+		} else if start%pageSize != 0 && stextOffset != nil && *stextOffset%pageSize == start%pageSize {
+			// ChromeOS remaps its kernel to 0 + start%pageSize. Nothing
+			// else should come down this path. Empirical values:
+			//       start=0x198 limit=0x2f9fffff offset=0
+			//       VADDR=0xffffffff81000000
+			// stextOffset=0xffffffff81000198
+			return -(*stextOffset - start), nil
+		}
+
+		return 0, fmt.Errorf("Don't know how to handle EXEC segment: %v start=0x%x limit=0x%x offset=0x%x", *loadSegment, start, limit, offset)
+	case elf.ET_REL:
+		if offset != 0 {
+			return 0, fmt.Errorf("Don't know how to handle mapping.Offset")
+		}
+		return start, nil
+	case elf.ET_DYN:
+		if offset != 0 {
+			if loadSegment == nil || loadSegment.Vaddr == 0 {
+				return start - offset, nil
+			}
+			return 0, fmt.Errorf("Don't know how to handle mapping. Offset=%x, vaddr=%x",
+				offset, loadSegment.Vaddr)
+		}
+		if loadSegment == nil {
+			return start, nil
+		}
+		return start - loadSegment.Vaddr, nil
+	}
+	return 0, fmt.Errorf("Don't know how to handle FileHeader.Type %v", fh.Type)
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec_test.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec_test.go
new file mode 100644
index 0000000..b9f2a84
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec_test.go
@@ -0,0 +1,92 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package elfexec
+
+import (
+	"debug/elf"
+	"testing"
+)
+
+func TestGetBase(t *testing.T) {
+
+	fhExec := &elf.FileHeader{
+		Type: elf.ET_EXEC,
+	}
+	fhRel := &elf.FileHeader{
+		Type: elf.ET_REL,
+	}
+	fhDyn := &elf.FileHeader{
+		Type: elf.ET_DYN,
+	}
+	lsOffset := &elf.ProgHeader{
+		Vaddr: 0x400000,
+		Off:   0x200000,
+	}
+	kernelHeader := &elf.ProgHeader{
+		Vaddr: 0xffffffff81000000,
+	}
+	ppc64KernelHeader := &elf.ProgHeader{
+		Vaddr: 0xc000000000000000,
+	}
+
+	testcases := []struct {
+		label                string
+		fh                   *elf.FileHeader
+		loadSegment          *elf.ProgHeader
+		stextOffset          *uint64
+		start, limit, offset uint64
+		want                 uint64
+		wanterr              bool
+	}{
+		{"exec", fhExec, nil, nil, 0x400000, 0, 0, 0, false},
+		{"exec offset", fhExec, lsOffset, nil, 0x400000, 0x800000, 0, 0, false},
+		{"exec offset 2", fhExec, lsOffset, nil, 0x200000, 0x600000, 0, 0, false},
+		{"exec nomap", fhExec, nil, nil, 0, 0, 0, 0, false},
+		{"exec kernel", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0xffffffff82000198, 0xffffffff83000198, 0, 0x1000000, false},
+		{"exec PPC64 kernel", fhExec, ppc64KernelHeader, uint64p(0xc000000000000000), 0xc000000000000000, 0xd00000001a730000, 0xc000000000000000, 0x0, false},
+		{"exec chromeos kernel", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0, 0x10197, 0, 0x7efffe68, false},
+		{"exec chromeos kernel 2", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0, 0x10198, 0, 0x7efffe68, false},
+		{"exec chromeos kernel 3", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0x198, 0x100000, 0, 0x7f000000, false},
+		{"exec chromeos kernel 4", fhExec, kernelHeader, uint64p(0xffffffff81200198), 0x198, 0x100000, 0, 0x7ee00000, false},
+		{"exec chromeos kernel unremapped", fhExec, kernelHeader, uint64p(0xffffffff810001c8), 0xffffffff834001c8, 0xffffffffc0000000, 0xffffffff834001c8, 0x2400000, false},
+		{"dyn", fhDyn, nil, nil, 0x200000, 0x300000, 0, 0x200000, false},
+		{"dyn offset", fhDyn, lsOffset, nil, 0x0, 0x300000, 0, 0xFFFFFFFFFFC00000, false},
+		{"dyn nomap", fhDyn, nil, nil, 0x0, 0x0, 0, 0, false},
+		{"rel", fhRel, nil, nil, 0x2000000, 0x3000000, 0, 0x2000000, false},
+		{"rel nomap", fhRel, nil, nil, 0x0, ^uint64(0), 0, 0, false},
+		{"rel offset", fhRel, nil, nil, 0x100000, 0x200000, 0x1, 0, true},
+	}
+
+	for _, tc := range testcases {
+		base, err := GetBase(tc.fh, tc.loadSegment, tc.stextOffset, tc.start, tc.limit, tc.offset)
+		if err != nil {
+			if !tc.wanterr {
+				t.Errorf("%s: want no error, got %v", tc.label, err)
+			}
+			continue
+		}
+		if tc.wanterr {
+			t.Errorf("%s: want error, got nil", tc.label)
+			continue
+		}
+		if base != tc.want {
+			t.Errorf("%s: want %x, got %x", tc.label, tc.want, base)
+		}
+	}
+}
+
+func uint64p(n uint64) *uint64 {
+	return &n
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go
new file mode 100644
index 0000000..c99e899
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go
@@ -0,0 +1,483 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package graph
+
+import (
+	"fmt"
+	"io"
+	"math"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/pprof/internal/measurement"
+)
+
+// DotAttributes contains details about the graph itself, giving
+// insight into how its elements should be rendered.
+type DotAttributes struct {
+	Nodes map[*Node]*DotNodeAttributes // A map allowing each Node to have its own visualization option
+}
+
+// DotNodeAttributes contains Node specific visualization options.
+type DotNodeAttributes struct {
+	Shape       string                 // The optional shape of the node when rendered visually
+	Bold        bool                   // If the node should be bold or not
+	Peripheries int                    // An optional number of borders to place around a node
+	URL         string                 // An optional url link to add to a node
+	Formatter   func(*NodeInfo) string // An optional formatter for the node's label
+}
+
+// DotConfig contains attributes about how a graph should be
+// constructed and how it should look.
+type DotConfig struct {
+	Title  string   // The title of the DOT graph
+	Labels []string // The labels for the DOT's legend
+
+	FormatValue func(int64) string         // A formatting function for values
+	FormatTag   func(int64, string) string // A formatting function for numeric tags
+	Total       int64                      // The total weight of the graph, used to compute percentages
+}
+
+// Compose creates and writes a in the DOT format to the writer, using
+// the configurations given.
+func ComposeDot(w io.Writer, g *Graph, a *DotAttributes, c *DotConfig) {
+	builder := &builder{w, a, c}
+
+	// Begin constructing DOT by adding a title and legend.
+	builder.start()
+	defer builder.finish()
+	builder.addLegend()
+
+	if len(g.Nodes) == 0 {
+		return
+	}
+
+	// Preprocess graph to get id map and find max flat.
+	nodeIDMap := make(map[*Node]int)
+	hasNodelets := make(map[*Node]bool)
+
+	maxFlat := float64(abs64(g.Nodes[0].FlatValue()))
+	for i, n := range g.Nodes {
+		nodeIDMap[n] = i + 1
+		if float64(abs64(n.FlatValue())) > maxFlat {
+			maxFlat = float64(abs64(n.FlatValue()))
+		}
+	}
+
+	edges := EdgeMap{}
+
+	// Add nodes and nodelets to DOT builder.
+	for _, n := range g.Nodes {
+		builder.addNode(n, nodeIDMap[n], maxFlat)
+		hasNodelets[n] = builder.addNodelets(n, nodeIDMap[n])
+
+		// Collect all edges. Use a fake node to support multiple incoming edges.
+		for _, e := range n.Out {
+			edges[&Node{}] = e
+		}
+	}
+
+	// Add edges to DOT builder. Sort edges by frequency as a hint to the graph layout engine.
+	for _, e := range edges.Sort() {
+		builder.addEdge(e, nodeIDMap[e.Src], nodeIDMap[e.Dest], hasNodelets[e.Src])
+	}
+}
+
+// builder wraps an io.Writer and understands how to compose DOT formatted elements.
+type builder struct {
+	io.Writer
+	attributes *DotAttributes
+	config     *DotConfig
+}
+
+// start generates a title and initial node in DOT format.
+func (b *builder) start() {
+	graphname := "unnamed"
+	if b.config.Title != "" {
+		graphname = b.config.Title
+	}
+	fmt.Fprintln(b, `digraph "`+graphname+`" {`)
+	fmt.Fprintln(b, `node [style=filled fillcolor="#f8f8f8"]`)
+}
+
+// finish closes the opening curly bracket in the constructed DOT buffer.
+func (b *builder) finish() {
+	fmt.Fprintln(b, "}")
+}
+
+// addLegend generates a legend in DOT format.
+func (b *builder) addLegend() {
+	labels := b.config.Labels
+	var title string
+	if len(labels) > 0 {
+		title = labels[0]
+	}
+	fmt.Fprintf(b, `subgraph cluster_L { "%s" [shape=box fontsize=16 label="%s\l"] }`+"\n", title, strings.Join(labels, `\l`))
+}
+
+// addNode generates a graph node in DOT format.
+func (b *builder) addNode(node *Node, nodeID int, maxFlat float64) {
+	flat, cum := node.FlatValue(), node.CumValue()
+	attrs := b.attributes.Nodes[node]
+
+	// Populate label for node.
+	var label string
+	if attrs != nil && attrs.Formatter != nil {
+		label = attrs.Formatter(&node.Info)
+	} else {
+		label = multilinePrintableName(&node.Info)
+	}
+
+	flatValue := b.config.FormatValue(flat)
+	if flat != 0 {
+		label = label + fmt.Sprintf(`%s (%s)`,
+			flatValue,
+			strings.TrimSpace(percentage(flat, b.config.Total)))
+	} else {
+		label = label + "0"
+	}
+	cumValue := flatValue
+	if cum != flat {
+		if flat != 0 {
+			label = label + `\n`
+		} else {
+			label = label + " "
+		}
+		cumValue = b.config.FormatValue(cum)
+		label = label + fmt.Sprintf(`of %s (%s)`,
+			cumValue,
+			strings.TrimSpace(percentage(cum, b.config.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(abs64(flat)) <= maxFlat {
+		fontSize += int(math.Ceil(maxFontGrowth * math.Sqrt(float64(abs64(flat))/maxFlat)))
+	}
+
+	// Determine node shape.
+	shape := "box"
+	if attrs != nil && attrs.Shape != "" {
+		shape = attrs.Shape
+	}
+
+	// Create DOT attribute for node.
+	attr := fmt.Sprintf(`label="%s" fontsize=%d shape=%s tooltip="%s (%s)" color="%s" fillcolor="%s"`,
+		label, fontSize, shape, node.Info.PrintableName(), cumValue,
+		dotColor(float64(node.CumValue())/float64(abs64(b.config.Total)), false),
+		dotColor(float64(node.CumValue())/float64(abs64(b.config.Total)), true))
+
+	// Add on extra attributes if provided.
+	if attrs != nil {
+		// Make bold if specified.
+		if attrs.Bold {
+			attr += ` style="bold,filled"`
+		}
+
+		// Add peripheries if specified.
+		if attrs.Peripheries != 0 {
+			attr += fmt.Sprintf(` peripheries=%d`, attrs.Peripheries)
+		}
+
+		// Add URL if specified. target="_blank" forces the link to open in a new tab.
+		if attrs.URL != "" {
+			attr += fmt.Sprintf(` URL="%s" target="_blank"`, attrs.URL)
+		}
+	}
+
+	fmt.Fprintf(b, "N%d [%s]\n", nodeID, attr)
+}
+
+// addNodelets generates the DOT boxes for the node tags if they exist.
+func (b *builder) addNodelets(node *Node, nodeID int) bool {
+	const maxNodelets = 4    // Number of nodelets for alphanumeric labels
+	const maxNumNodelets = 4 // Number of nodelets for numeric labels
+	var nodelets string
+
+	// Populate two Tag slices, one for LabelTags and one for NumericTags.
+	var ts []*Tag
+	lnts := make(map[string][]*Tag, 0)
+	for _, t := range node.LabelTags {
+		ts = append(ts, t)
+	}
+	for l, tm := range node.NumericTags {
+		for _, t := range tm {
+			lnts[l] = append(lnts[l], t)
+		}
+	}
+
+	// For leaf nodes, print cumulative tags (includes weight from
+	// children that have been deleted).
+	// For internal nodes, print only flat tags.
+	flatTags := len(node.Out) > 0
+
+	// Select the top maxNodelets alphanumeric labels by weight.
+	SortTags(ts, flatTags)
+	if len(ts) > maxNodelets {
+		ts = ts[:maxNodelets]
+	}
+	for i, t := range ts {
+		w := t.CumValue()
+		if flatTags {
+			w = t.FlatValue()
+		}
+		if w == 0 {
+			continue
+		}
+		weight := b.config.FormatValue(w)
+		nodelets += fmt.Sprintf(`N%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", nodeID, i, t.Name, weight)
+		nodelets += fmt.Sprintf(`N%d -> N%d_%d [label=" %s" weight=100 tooltip="%s" labeltooltip="%s"]`+"\n", nodeID, nodeID, i, weight, weight, weight)
+		if nts := lnts[t.Name]; nts != nil {
+			nodelets += b.numericNodelets(nts, maxNumNodelets, flatTags, fmt.Sprintf(`N%d_%d`, nodeID, i))
+		}
+	}
+
+	if nts := lnts[""]; nts != nil {
+		nodelets += b.numericNodelets(nts, maxNumNodelets, flatTags, fmt.Sprintf(`N%d`, nodeID))
+	}
+
+	fmt.Fprint(b, nodelets)
+	return nodelets != ""
+}
+
+func (b *builder) numericNodelets(nts []*Tag, maxNumNodelets int, flatTags bool, source string) string {
+	nodelets := ""
+
+	// Collapse numeric labels into maxNumNodelets buckets, of the form:
+	// 1MB..2MB, 3MB..5MB, ...
+	for j, t := range b.collapsedTags(nts, maxNumNodelets, flatTags) {
+		w, attr := t.CumValue(), ` style="dotted"`
+		if flatTags || t.FlatValue() == t.CumValue() {
+			w, attr = t.FlatValue(), ""
+		}
+		if w != 0 {
+			weight := b.config.FormatValue(w)
+			nodelets += fmt.Sprintf(`N%s_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", source, j, t.Name, weight)
+			nodelets += fmt.Sprintf(`%s -> N%s_%d [label=" %s" weight=100 tooltip="%s" labeltooltip="%s"%s]`+"\n", source, source, j, weight, weight, weight, attr)
+		}
+	}
+	return nodelets
+}
+
+// addEdge generates a graph edge in DOT format.
+func (b *builder) addEdge(edge *Edge, from, to int, hasNodelets bool) {
+	var inline string
+	if edge.Inline {
+		inline = `\n (inline)`
+	}
+	w := b.config.FormatValue(edge.WeightValue())
+	attr := fmt.Sprintf(`label=" %s%s"`, w, inline)
+	if b.config.Total != 0 {
+		// Note: edge.weight > b.config.Total is possible for profile diffs.
+		if weight := 1 + int(min64(abs64(edge.WeightValue()*100/b.config.Total), 100)); weight > 1 {
+			attr = fmt.Sprintf(`%s weight=%d`, attr, weight)
+		}
+		if width := 1 + int(min64(abs64(edge.WeightValue()*5/b.config.Total), 5)); width > 1 {
+			attr = fmt.Sprintf(`%s penwidth=%d`, attr, width)
+		}
+		attr = fmt.Sprintf(`%s color="%s"`, attr,
+			dotColor(float64(edge.WeightValue())/float64(abs64(b.config.Total)), false))
+	}
+	arrow := "->"
+	if edge.Residual {
+		arrow = "..."
+	}
+	tooltip := fmt.Sprintf(`"%s %s %s (%s)"`,
+		edge.Src.Info.PrintableName(), arrow, edge.Dest.Info.PrintableName(), w)
+	attr = fmt.Sprintf(`%s tooltip=%s labeltooltip=%s`, attr, tooltip, tooltip)
+
+	if edge.Residual {
+		attr = attr + ` style="dotted"`
+	}
+
+	if hasNodelets {
+		// Separate children further if source has tags.
+		attr = attr + " minlen=2"
+	}
+
+	fmt.Fprintf(b, "N%d -> N%d [%s]\n", from, to, attr)
+}
+
+// dotColor returns a color for the given score (between -1.0 and
+// 1.0), with -1.0 colored red, 0.0 colored grey, and 1.0 colored
+// green. If isBackground is true, then a light (low-saturation)
+// color is returned (suitable for use as a background color);
+// otherwise, a darker color is returned (suitable for use as a
+// foreground color).
+func dotColor(score float64, isBackground bool) string {
+	// A float between 0.0 and 1.0, indicating the extent to which
+	// colors should be shifted away from grey (to make positive and
+	// negative values easier to distinguish, and to make more use of
+	// the color range.)
+	const shift = 0.7
+
+	// Saturation and value (in hsv colorspace) for background colors.
+	const bgSaturation = 0.1
+	const bgValue = 0.93
+
+	// Saturation and value (in hsv colorspace) for foreground colors.
+	const fgSaturation = 1.0
+	const fgValue = 0.7
+
+	// Choose saturation and value based on isBackground.
+	var saturation float64
+	var value float64
+	if isBackground {
+		saturation = bgSaturation
+		value = bgValue
+	} else {
+		saturation = fgSaturation
+		value = fgValue
+	}
+
+	// Limit the score values to the range [-1.0, 1.0].
+	score = math.Max(-1.0, math.Min(1.0, score))
+
+	// Reduce saturation near score=0 (so it is colored grey, rather than yellow).
+	if math.Abs(score) < 0.2 {
+		saturation *= math.Abs(score) / 0.2
+	}
+
+	// Apply 'shift' to move scores away from 0.0 (grey).
+	if score > 0.0 {
+		score = math.Pow(score, (1.0 - shift))
+	}
+	if score < 0.0 {
+		score = -math.Pow(-score, (1.0 - shift))
+	}
+
+	var r, g, b float64 // red, green, blue
+	if score < 0.0 {
+		g = value
+		r = value * (1 + saturation*score)
+	} else {
+		r = value
+		g = value * (1 - saturation*score)
+	}
+	b = value * (1 - saturation)
+	return fmt.Sprintf("#%02x%02x%02x", uint8(r*255.0), uint8(g*255.0), uint8(b*255.0))
+}
+
+// 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 = math.Abs(float64(value)/float64(total)) * 100
+	}
+	switch {
+	case math.Abs(ratio) >= 99.95 && math.Abs(ratio) <= 100.05:
+		return "  100%"
+	case math.Abs(ratio) >= 1.0:
+		return fmt.Sprintf("%5.2f%%", ratio)
+	default:
+		return fmt.Sprintf("%5.2g%%", ratio)
+	}
+}
+
+func multilinePrintableName(info *NodeInfo) string {
+	infoCopy := *info
+	infoCopy.Name = strings.Replace(infoCopy.Name, "::", `\n`, -1)
+	infoCopy.Name = strings.Replace(infoCopy.Name, ".", `\n`, -1)
+	if infoCopy.File != "" {
+		infoCopy.File = filepath.Base(infoCopy.File)
+	}
+	return strings.Join(infoCopy.NameComponents(), `\n`) + `\n`
+}
+
+// collapsedTags trims and sorts a slice of tags.
+func (b *builder) collapsedTags(ts []*Tag, count int, flatTags bool) []*Tag {
+	ts = SortTags(ts, flatTags)
+	if len(ts) <= count {
+		return ts
+	}
+
+	tagGroups := make([][]*Tag, count)
+	for i, t := range (ts)[:count] {
+		tagGroups[i] = []*Tag{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 []*Tag
+	for _, g := range tagGroups {
+		l, w, c := b.tagGroupLabel(g)
+		nts = append(nts, &Tag{
+			Name: l,
+			Flat: w,
+			Cum:  c,
+		})
+	}
+	return SortTags(nts, flatTags)
+}
+
+func tagDistance(t, u *Tag) float64 {
+	v, _ := measurement.Scale(u.Value, u.Unit, t.Unit)
+	if v < float64(t.Value) {
+		return float64(t.Value) - v
+	}
+	return v - float64(t.Value)
+}
+
+func (b *builder) tagGroupLabel(g []*Tag) (label string, flat, cum int64) {
+	formatTag := b.config.FormatTag
+	if formatTag == nil {
+		formatTag = measurement.Label
+	}
+
+	if len(g) == 1 {
+		t := g[0]
+		return formatTag(t.Value, t.Unit), t.FlatValue(), t.CumValue()
+	}
+	min := g[0]
+	max := g[0]
+	df, f := min.FlatDiv, min.Flat
+	dc, c := min.CumDiv, min.Cum
+	for _, t := range g[1:] {
+		if v, _ := measurement.Scale(t.Value, t.Unit, min.Unit); int64(v) < min.Value {
+			min = t
+		}
+		if v, _ := measurement.Scale(t.Value, t.Unit, max.Unit); int64(v) > max.Value {
+			max = t
+		}
+		f += t.Flat
+		df += t.FlatDiv
+		c += t.Cum
+		dc += t.CumDiv
+	}
+	if df != 0 {
+		f = f / df
+	}
+	if dc != 0 {
+		c = c / dc
+	}
+	return formatTag(min.Value, min.Unit) + ".." + formatTag(max.Value, max.Unit), f, c
+}
+
+func min64(a, b int64) int64 {
+	if a < b {
+		return a
+	}
+	return b
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph_test.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph_test.go
new file mode 100644
index 0000000..7f51269
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph_test.go
@@ -0,0 +1,282 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package graph
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/google/pprof/internal/proftest"
+)
+
+const path = "testdata/"
+
+func TestComposeWithStandardGraph(t *testing.T) {
+	g := baseGraph()
+	a, c := baseAttrsAndConfig()
+
+	var buf bytes.Buffer
+	ComposeDot(&buf, g, a, c)
+
+	want, err := ioutil.ReadFile(path + "compose1.dot")
+	if err != nil {
+		t.Fatalf("error reading test file: %v", err)
+	}
+
+	compareGraphs(t, buf.Bytes(), want)
+}
+
+func TestComposeWithNodeAttributesAndZeroFlat(t *testing.T) {
+	g := baseGraph()
+	a, c := baseAttrsAndConfig()
+
+	// Set NodeAttributes for Node 1.
+	a.Nodes[g.Nodes[0]] = &DotNodeAttributes{
+		Shape:       "folder",
+		Bold:        true,
+		Peripheries: 2,
+		URL:         "www.google.com",
+		Formatter: func(ni *NodeInfo) string {
+			return strings.ToUpper(ni.Name)
+		},
+	}
+
+	// Set Flat value to zero on Node 2.
+	g.Nodes[1].Flat = 0
+
+	var buf bytes.Buffer
+	ComposeDot(&buf, g, a, c)
+
+	want, err := ioutil.ReadFile(path + "compose2.dot")
+	if err != nil {
+		t.Fatalf("error reading test file: %v", err)
+	}
+
+	compareGraphs(t, buf.Bytes(), want)
+}
+
+func TestComposeWithTagsAndResidualEdge(t *testing.T) {
+	g := baseGraph()
+	a, c := baseAttrsAndConfig()
+
+	// Add tags to Node 1.
+	g.Nodes[0].LabelTags["a"] = &Tag{
+		Name: "tag1",
+		Cum:  10,
+		Flat: 10,
+	}
+	g.Nodes[0].NumericTags[""] = TagMap{
+		"b": &Tag{
+			Name: "tag2",
+			Cum:  20,
+			Flat: 20,
+			Unit: "ms",
+		},
+	}
+
+	// Set edge to be Residual.
+	g.Nodes[0].Out[g.Nodes[1]].Residual = true
+
+	var buf bytes.Buffer
+	ComposeDot(&buf, g, a, c)
+
+	want, err := ioutil.ReadFile(path + "compose3.dot")
+	if err != nil {
+		t.Fatalf("error reading test file: %v", err)
+	}
+
+	compareGraphs(t, buf.Bytes(), want)
+}
+
+func TestComposeWithNestedTags(t *testing.T) {
+	g := baseGraph()
+	a, c := baseAttrsAndConfig()
+
+	// Add tags to Node 1.
+	g.Nodes[0].LabelTags["tag1"] = &Tag{
+		Name: "tag1",
+		Cum:  10,
+		Flat: 10,
+	}
+	g.Nodes[0].NumericTags["tag1"] = TagMap{
+		"tag2": &Tag{
+			Name: "tag2",
+			Cum:  20,
+			Flat: 20,
+			Unit: "ms",
+		},
+	}
+
+	var buf bytes.Buffer
+	ComposeDot(&buf, g, a, c)
+
+	want, err := ioutil.ReadFile(path + "compose5.dot")
+	if err != nil {
+		t.Fatalf("error reading test file: %v", err)
+	}
+
+	compareGraphs(t, buf.Bytes(), want)
+}
+
+func TestComposeWithEmptyGraph(t *testing.T) {
+	g := &Graph{}
+	a, c := baseAttrsAndConfig()
+
+	var buf bytes.Buffer
+	ComposeDot(&buf, g, a, c)
+
+	want, err := ioutil.ReadFile(path + "compose4.dot")
+	if err != nil {
+		t.Fatalf("error reading test file: %v", err)
+	}
+
+	compareGraphs(t, buf.Bytes(), want)
+}
+
+func baseGraph() *Graph {
+	src := &Node{
+		Info:        NodeInfo{Name: "src"},
+		Flat:        10,
+		Cum:         25,
+		In:          make(EdgeMap),
+		Out:         make(EdgeMap),
+		LabelTags:   make(TagMap),
+		NumericTags: make(map[string]TagMap),
+	}
+	dest := &Node{
+		Info:        NodeInfo{Name: "dest"},
+		Flat:        15,
+		Cum:         25,
+		In:          make(EdgeMap),
+		Out:         make(EdgeMap),
+		LabelTags:   make(TagMap),
+		NumericTags: make(map[string]TagMap),
+	}
+	edge := &Edge{
+		Src:    src,
+		Dest:   dest,
+		Weight: 10,
+	}
+	src.Out[dest] = edge
+	src.In[src] = edge
+	return &Graph{
+		Nodes: Nodes{
+			src,
+			dest,
+		},
+	}
+}
+
+func baseAttrsAndConfig() (*DotAttributes, *DotConfig) {
+	a := &DotAttributes{
+		Nodes: make(map[*Node]*DotNodeAttributes),
+	}
+	c := &DotConfig{
+		Title:  "testtitle",
+		Labels: []string{"label1", "label2"},
+		Total:  100,
+		FormatValue: func(v int64) string {
+			return strconv.FormatInt(v, 10)
+		},
+	}
+	return a, c
+}
+
+func compareGraphs(t *testing.T, got, want []byte) {
+	if string(got) != string(want) {
+		d, err := proftest.Diff(got, want)
+		if err != nil {
+			t.Fatalf("error finding diff: %v", err)
+		}
+		t.Errorf("Compose incorrectly wrote %s", string(d))
+	}
+}
+
+func TestMultilinePrintableName(t *testing.T) {
+	ni := &NodeInfo{
+		Name:    "test1.test2::test3",
+		File:    "src/file.cc",
+		Address: 123,
+		Lineno:  999,
+	}
+
+	want := fmt.Sprintf(`%016x\ntest1\ntest2\ntest3\nfile.cc:999\n`, 123)
+	if got := multilinePrintableName(ni); got != want {
+		t.Errorf("multilinePrintableName(%#v) == %q, want %q", ni, got, want)
+	}
+}
+
+func TestTagCollapse(t *testing.T) {
+
+	makeTag := func(name, unit string, value, flat, cum int64) *Tag {
+		return &Tag{name, unit, value, flat, 0, cum, 0}
+	}
+
+	tagSource := []*Tag{
+		makeTag("12mb", "mb", 12, 100, 100),
+		makeTag("1kb", "kb", 1, 1, 1),
+		makeTag("1mb", "mb", 1, 1000, 1000),
+		makeTag("2048mb", "mb", 2048, 1000, 1000),
+		makeTag("1b", "b", 1, 100, 100),
+		makeTag("2b", "b", 2, 100, 100),
+		makeTag("7b", "b", 7, 100, 100),
+	}
+
+	tagWant := [][]*Tag{
+		[]*Tag{
+			makeTag("1B..2GB", "", 0, 2401, 2401),
+		},
+		[]*Tag{
+			makeTag("2GB", "", 0, 1000, 1000),
+			makeTag("1B..12MB", "", 0, 1401, 1401),
+		},
+		[]*Tag{
+			makeTag("2GB", "", 0, 1000, 1000),
+			makeTag("12MB", "", 0, 100, 100),
+			makeTag("1B..1MB", "", 0, 1301, 1301),
+		},
+		[]*Tag{
+			makeTag("2GB", "", 0, 1000, 1000),
+			makeTag("1MB", "", 0, 1000, 1000),
+			makeTag("2B..1kB", "", 0, 201, 201),
+			makeTag("1B", "", 0, 100, 100),
+			makeTag("12MB", "", 0, 100, 100),
+		},
+	}
+
+	for _, tc := range tagWant {
+		var got, want []*Tag
+		b := builder{nil, &DotAttributes{}, &DotConfig{}}
+		got = b.collapsedTags(tagSource, len(tc), true)
+		want = SortTags(tc, true)
+
+		if !reflect.DeepEqual(got, want) {
+			t.Errorf("collapse to %d, got:\n%v\nwant:\n%v", len(tc), tagString(got), tagString(want))
+		}
+	}
+}
+
+func tagString(t []*Tag) string {
+	var ret []string
+	for _, s := range t {
+		ret = append(ret, fmt.Sprintln(s))
+	}
+	return strings.Join(ret, ":")
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go
new file mode 100644
index 0000000..428e625
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go
@@ -0,0 +1,1134 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package graph collects a set of samples into a directed graph.
+package graph
+
+import (
+	"fmt"
+	"math"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/profile"
+)
+
+// Graph summarizes a performance profile into a format that is
+// suitable for visualization.
+type Graph struct {
+	Nodes Nodes
+}
+
+// Options encodes the options for constructing a graph
+type Options struct {
+	SampleValue       func(s []int64) int64      // Function to compute the value of a sample
+	SampleMeanDivisor func(s []int64) int64      // Function to compute the divisor for mean graphs, or nil
+	FormatTag         func(int64, string) string // Function to format a sample tag value into a string
+	ObjNames          bool                       // Always preserve obj filename
+	OrigFnNames       bool                       // Preserve original (eg mangled) function names
+
+	CallTree     bool // Build a tree instead of a graph
+	DropNegative bool // Drop nodes with overall negative values
+
+	KeptNodes NodeSet // If non-nil, only use nodes in this set
+}
+
+// Nodes is an ordered collection of graph nodes.
+type Nodes []*Node
+
+// Node is an entry on a profiling report. It represents a unique
+// program location.
+type Node struct {
+	// Info describes the source location associated to this node.
+	Info NodeInfo
+
+	// Function represents the function that this node belongs to. On
+	// graphs with sub-function resolution (eg line number or
+	// addresses), two nodes in a NodeMap that are part of the same
+	// function have the same value of Node.Function. If the Node
+	// represents the whole function, it points back to itself.
+	Function *Node
+
+	// Values associated to this node. Flat is exclusive to this node,
+	// Cum includes all descendents.
+	Flat, FlatDiv, Cum, CumDiv int64
+
+	// In and out Contains the nodes immediately reaching or reached by
+	// this node.
+	In, Out EdgeMap
+
+	// LabelTags provide additional information about subsets of a sample.
+	LabelTags TagMap
+
+	// NumericTags provide additional values for subsets of a sample.
+	// Numeric tags are optionally associated to a label tag. The key
+	// for NumericTags is the name of the LabelTag they are associated
+	// to, or "" for numeric tags not associated to a label tag.
+	NumericTags map[string]TagMap
+}
+
+// FlatValue returns the exclusive value for this node, computing the
+// mean if a divisor is available.
+func (n *Node) FlatValue() int64 {
+	if n.FlatDiv == 0 {
+		return n.Flat
+	}
+	return n.Flat / n.FlatDiv
+}
+
+// CumValue returns the inclusive value for this node, computing the
+// mean if a divisor is available.
+func (n *Node) CumValue() int64 {
+	if n.CumDiv == 0 {
+		return n.Cum
+	}
+	return n.Cum / n.CumDiv
+}
+
+// AddToEdge increases the weight of an edge between two nodes. If
+// there isn't such an edge one is created.
+func (n *Node) AddToEdge(to *Node, v int64, residual, inline bool) {
+	n.AddToEdgeDiv(to, 0, v, residual, inline)
+}
+
+// AddToEdgeDiv increases the weight of an edge between two nodes. If
+// there isn't such an edge one is created.
+func (n *Node) AddToEdgeDiv(to *Node, dv, v int64, residual, inline bool) {
+	if n.Out[to] != to.In[n] {
+		panic(fmt.Errorf("asymmetric edges %v %v", *n, *to))
+	}
+
+	if e := n.Out[to]; e != nil {
+		e.WeightDiv += dv
+		e.Weight += v
+		if residual {
+			e.Residual = true
+		}
+		if !inline {
+			e.Inline = false
+		}
+		return
+	}
+
+	info := &Edge{Src: n, Dest: to, WeightDiv: dv, Weight: v, Residual: residual, Inline: inline}
+	n.Out[to] = info
+	to.In[n] = info
+}
+
+// NodeInfo contains the attributes for a node.
+type NodeInfo struct {
+	Name              string
+	OrigName          string
+	Address           uint64
+	File              string
+	StartLine, Lineno int
+	Objfile           string
+}
+
+// PrintableName calls the Node's Formatter function with a single space separator.
+func (i *NodeInfo) PrintableName() string {
+	return strings.Join(i.NameComponents(), " ")
+}
+
+// NameComponents returns the components of the printable name to be used for a node.
+func (i *NodeInfo) NameComponents() []string {
+	var name []string
+	if i.Address != 0 {
+		name = append(name, fmt.Sprintf("%016x", i.Address))
+	}
+	if fun := i.Name; fun != "" {
+		name = append(name, fun)
+	}
+
+	switch {
+	case i.Lineno != 0:
+		// User requested line numbers, provide what we have.
+		name = append(name, fmt.Sprintf("%s:%d", i.File, i.Lineno))
+	case i.File != "":
+		// User requested file name, provide it.
+		name = append(name, i.File)
+	case i.Name != "":
+		// User requested function name. It was already included.
+	case i.Objfile != "":
+		// Only binary name is available
+		name = append(name, "["+filepath.Base(i.Objfile)+"]")
+	default:
+		// Do not leave it empty if there is no information at all.
+		name = append(name, "<unknown>")
+	}
+	return name
+}
+
+// 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
+
+// NodeSet is a collection of node info structs.
+type NodeSet map[NodeInfo]bool
+
+// NodePtrSet is a collection of nodes. Trimming a graph or tree requires a set
+// of objects which uniquely identify the nodes to keep. In a graph, NodeInfo
+// works as a unique identifier; however, in a tree multiple nodes may share
+// identical NodeInfos. A *Node does uniquely identify a node so we can use that
+// instead. Though a *Node also uniquely identifies a node in a graph,
+// currently, during trimming, graphs are rebult from scratch using only the
+// NodeSet, so there would not be the required context of the initial graph to
+// allow for the use of *Node.
+type NodePtrSet map[*Node]bool
+
+// FindOrInsertNode takes the info for a node and either returns a matching node
+// from the node map if one exists, or adds one to the map if one does not.
+// If kept is non-nil, nodes are only added if they can be located on it.
+func (nm NodeMap) FindOrInsertNode(info NodeInfo, kept NodeSet) *Node {
+	if kept != nil {
+		if _, ok := kept[info]; !ok {
+			return nil
+		}
+	}
+
+	if n, ok := nm[info]; ok {
+		return n
+	}
+
+	n := &Node{
+		Info:        info,
+		In:          make(EdgeMap),
+		Out:         make(EdgeMap),
+		LabelTags:   make(TagMap),
+		NumericTags: make(map[string]TagMap),
+	}
+	nm[info] = n
+	if info.Address == 0 && info.Lineno == 0 {
+		// This node represents the whole function, so point Function
+		// back to itself.
+		n.Function = n
+		return n
+	}
+	// Find a node that represents the whole function.
+	info.Address = 0
+	info.Lineno = 0
+	n.Function = nm.FindOrInsertNode(info, nil)
+	return n
+}
+
+// EdgeMap is used to represent the incoming/outgoing edges from a node.
+type EdgeMap map[*Node]*Edge
+
+// Edge contains any attributes to be represented about edges in a graph.
+type Edge struct {
+	Src, Dest *Node
+	// The summary weight of the edge
+	Weight, WeightDiv int64
+
+	// residual edges connect nodes that were connected through a
+	// separate node, which has been removed from the report.
+	Residual bool
+	// An inline edge represents a call that was inlined into the caller.
+	Inline bool
+}
+
+func (e *Edge) WeightValue() int64 {
+	if e.WeightDiv == 0 {
+		return e.Weight
+	}
+	return e.Weight / e.WeightDiv
+}
+
+// Tag represent sample annotations
+type Tag struct {
+	Name          string
+	Unit          string // Describe the value, "" for non-numeric tags
+	Value         int64
+	Flat, FlatDiv int64
+	Cum, CumDiv   int64
+}
+
+// FlatValue returns the exclusive value for this tag, computing the
+// mean if a divisor is available.
+func (t *Tag) FlatValue() int64 {
+	if t.FlatDiv == 0 {
+		return t.Flat
+	}
+	return t.Flat / t.FlatDiv
+}
+
+// CumValue returns the inclusive value for this tag, computing the
+// mean if a divisor is available.
+func (t *Tag) CumValue() int64 {
+	if t.CumDiv == 0 {
+		return t.Cum
+	}
+	return t.Cum / t.CumDiv
+}
+
+// TagMap is a collection of tags, classified by their name.
+type TagMap map[string]*Tag
+
+// SortTags sorts a slice of tags based on their weight.
+func SortTags(t []*Tag, flat bool) []*Tag {
+	ts := tags{t, flat}
+	sort.Sort(ts)
+	return ts.t
+}
+
+// New summarizes performance data from a profile into a graph.
+func New(prof *profile.Profile, o *Options) *Graph {
+	if o.CallTree {
+		return newTree(prof, o)
+	}
+	g, _ := newGraph(prof, o)
+	return g
+}
+
+// newGraph computes a graph from a profile. It returns the graph, and
+// a map from the profile location indices to the corresponding graph
+// nodes.
+func newGraph(prof *profile.Profile, o *Options) (*Graph, map[uint64]Nodes) {
+	nodes, locationMap := CreateNodes(prof, o)
+	for _, sample := range prof.Sample {
+		var w, dw int64
+		w = o.SampleValue(sample.Value)
+		if o.SampleMeanDivisor != nil {
+			dw = o.SampleMeanDivisor(sample.Value)
+		}
+		if dw == 0 && w == 0 {
+			continue
+		}
+		seenNode := make(map[*Node]bool, len(sample.Location))
+		seenEdge := make(map[nodePair]bool, len(sample.Location))
+		var parent *Node
+		// A residual edge goes over one or more nodes that were not kept.
+		residual := false
+
+		labels := joinLabels(sample)
+		// Group the sample frames, based on a global map.
+		for i := len(sample.Location) - 1; i >= 0; i-- {
+			l := sample.Location[i]
+			locNodes := locationMap[l.ID]
+			for ni := len(locNodes) - 1; ni >= 0; ni-- {
+				n := locNodes[ni]
+				if n == nil {
+					residual = true
+					continue
+				}
+				// Add cum weight to all nodes in stack, avoiding double counting.
+				if _, ok := seenNode[n]; !ok {
+					seenNode[n] = true
+					n.addSample(dw, w, labels, sample.NumLabel, o.FormatTag, false)
+				}
+				// Update edge weights for all edges in stack, avoiding double counting.
+				if _, ok := seenEdge[nodePair{n, parent}]; !ok && parent != nil && n != parent {
+					seenEdge[nodePair{n, parent}] = true
+					parent.AddToEdgeDiv(n, dw, w, residual, ni != len(locNodes)-1)
+				}
+				parent = n
+				residual = false
+			}
+		}
+		if parent != nil && !residual {
+			// Add flat weight to leaf node.
+			parent.addSample(dw, w, labels, sample.NumLabel, o.FormatTag, true)
+		}
+	}
+
+	return selectNodesForGraph(nodes, o.DropNegative), locationMap
+}
+
+func selectNodesForGraph(nodes Nodes, dropNegative bool) *Graph {
+	// Collect nodes into a graph.
+	gNodes := make(Nodes, 0, len(nodes))
+	for _, n := range nodes {
+		if n == nil {
+			continue
+		}
+		if n.Cum == 0 && n.Flat == 0 {
+			continue
+		}
+		if dropNegative && isNegative(n) {
+			continue
+		}
+		gNodes = append(gNodes, n)
+	}
+	return &Graph{gNodes}
+}
+
+type nodePair struct {
+	src, dest *Node
+}
+
+func newTree(prof *profile.Profile, o *Options) (g *Graph) {
+	parentNodeMap := make(map[*Node]NodeMap, len(prof.Sample))
+	for _, sample := range prof.Sample {
+		var w, dw int64
+		w = o.SampleValue(sample.Value)
+		if o.SampleMeanDivisor != nil {
+			dw = o.SampleMeanDivisor(sample.Value)
+		}
+		if dw == 0 && w == 0 {
+			continue
+		}
+		var parent *Node
+		labels := joinLabels(sample)
+		// Group the sample frames, based on a per-node map.
+		for i := len(sample.Location) - 1; i >= 0; i-- {
+			l := sample.Location[i]
+			lines := l.Line
+			if len(lines) == 0 {
+				lines = []profile.Line{{}} // Create empty line to include location info.
+			}
+			for lidx := len(lines) - 1; lidx >= 0; lidx-- {
+				nodeMap := parentNodeMap[parent]
+				if nodeMap == nil {
+					nodeMap = make(NodeMap)
+					parentNodeMap[parent] = nodeMap
+				}
+				n := nodeMap.findOrInsertLine(l, lines[lidx], o)
+				if n == nil {
+					continue
+				}
+				n.addSample(dw, w, labels, sample.NumLabel, o.FormatTag, false)
+				if parent != nil {
+					parent.AddToEdgeDiv(n, dw, w, false, lidx != len(lines)-1)
+				}
+				parent = n
+			}
+		}
+		if parent != nil {
+			parent.addSample(dw, w, labels, sample.NumLabel, o.FormatTag, true)
+		}
+	}
+
+	nodes := make(Nodes, len(prof.Location))
+	for _, nm := range parentNodeMap {
+		nodes = append(nodes, nm.nodes()...)
+	}
+	return selectNodesForGraph(nodes, o.DropNegative)
+}
+
+// TrimTree trims a Graph in forest form, keeping only the nodes in kept. This
+// will not work correctly if even a single node has multiple parents.
+func (g *Graph) TrimTree(kept NodePtrSet) {
+	// Creates a new list of nodes
+	oldNodes := g.Nodes
+	g.Nodes = make(Nodes, 0, len(kept))
+
+	for _, cur := range oldNodes {
+		// A node may not have multiple parents
+		if len(cur.In) > 1 {
+			panic("TrimTree only works on trees")
+		}
+
+		// If a node should be kept, add it to the new list of nodes
+		if _, ok := kept[cur]; ok {
+			g.Nodes = append(g.Nodes, cur)
+			continue
+		}
+
+		// If a node has no parents, then delete all of the in edges of its
+		// children to make them each roots of their own trees.
+		if len(cur.In) == 0 {
+			for _, outEdge := range cur.Out {
+				delete(outEdge.Dest.In, cur)
+			}
+			continue
+		}
+
+		// Get the parent. This works since at this point cur.In must contain only
+		// one element.
+		if len(cur.In) != 1 {
+			panic("Get parent assertion failed. cur.In expected to be of length 1.")
+		}
+		var parent *Node
+		for _, edge := range cur.In {
+			parent = edge.Src
+		}
+
+		parentEdgeInline := parent.Out[cur].Inline
+
+		// Remove the edge from the parent to this node
+		delete(parent.Out, cur)
+
+		// Reconfigure every edge from the current node to now begin at the parent.
+		for _, outEdge := range cur.Out {
+			child := outEdge.Dest
+
+			delete(child.In, cur)
+			child.In[parent] = outEdge
+			parent.Out[child] = outEdge
+
+			outEdge.Src = parent
+			outEdge.Residual = true
+			// If the edge from the parent to the current node and the edge from the
+			// current node to the child are both inline, then this resulting residual
+			// edge should also be inline
+			outEdge.Inline = parentEdgeInline && outEdge.Inline
+		}
+	}
+	g.RemoveRedundantEdges()
+}
+
+func joinLabels(s *profile.Sample) string {
+	if len(s.Label) == 0 {
+		return ""
+	}
+
+	var labels []string
+	for key, vals := range s.Label {
+		for _, v := range vals {
+			labels = append(labels, key+":"+v)
+		}
+	}
+	sort.Strings(labels)
+	return strings.Join(labels, `\n`)
+}
+
+// isNegative returns true if the node is considered as "negative" for the
+// purposes of drop_negative.
+func isNegative(n *Node) bool {
+	switch {
+	case n.Flat < 0:
+		return true
+	case n.Flat == 0 && n.Cum < 0:
+		return true
+	default:
+		return false
+	}
+}
+
+// CreateNodes creates graph nodes for all locations in a profile. It
+// returns set of all nodes, plus a mapping of each location to the
+// set of corresponding nodes (one per location.Line). If kept is
+// non-nil, only nodes in that set are included; nodes that do not
+// match are represented as a nil.
+func CreateNodes(prof *profile.Profile, o *Options) (Nodes, map[uint64]Nodes) {
+	locations := make(map[uint64]Nodes, len(prof.Location))
+	nm := make(NodeMap, len(prof.Location))
+	for _, l := range prof.Location {
+		lines := l.Line
+		if len(lines) == 0 {
+			lines = []profile.Line{{}} // Create empty line to include location info.
+		}
+		nodes := make(Nodes, len(lines))
+		for ln := range lines {
+			nodes[ln] = nm.findOrInsertLine(l, lines[ln], o)
+		}
+		locations[l.ID] = nodes
+	}
+	return nm.nodes(), locations
+}
+
+func (nm NodeMap) nodes() Nodes {
+	nodes := make(Nodes, 0, len(nm))
+	for _, n := range nm {
+		nodes = append(nodes, n)
+	}
+	return nodes
+}
+
+func (nm NodeMap) findOrInsertLine(l *profile.Location, li profile.Line, o *Options) *Node {
+	var objfile string
+	if m := l.Mapping; m != nil && m.File != "" {
+		objfile = m.File
+	}
+
+	if ni := nodeInfo(l, li, objfile, o); ni != nil {
+		return nm.FindOrInsertNode(*ni, o.KeptNodes)
+	}
+	return nil
+}
+
+func nodeInfo(l *profile.Location, line profile.Line, objfile string, o *Options) *NodeInfo {
+	if line.Function == nil {
+		return &NodeInfo{Address: l.Address, Objfile: objfile}
+	}
+	ni := &NodeInfo{
+		Address: l.Address,
+		Lineno:  int(line.Line),
+		Name:    line.Function.Name,
+	}
+	if fname := line.Function.Filename; fname != "" {
+		ni.File = filepath.Clean(fname)
+	}
+	if o.ObjNames {
+		ni.Objfile = objfile
+		ni.StartLine = int(line.Function.StartLine)
+	}
+	if o.OrigFnNames {
+		ni.OrigName = line.Function.SystemName
+	}
+	return ni
+}
+
+type tags struct {
+	t    []*Tag
+	flat bool
+}
+
+func (t tags) Len() int      { return len(t.t) }
+func (t tags) Swap(i, j int) { t.t[i], t.t[j] = t.t[j], t.t[i] }
+func (t tags) Less(i, j int) bool {
+	if !t.flat {
+		if t.t[i].Cum != t.t[j].Cum {
+			return abs64(t.t[i].Cum) > abs64(t.t[j].Cum)
+		}
+	}
+	if t.t[i].Flat != t.t[j].Flat {
+		return abs64(t.t[i].Flat) > abs64(t.t[j].Flat)
+	}
+	return t.t[i].Name < t.t[j].Name
+}
+
+// Sum adds the flat and cum values of a set of nodes.
+func (ns Nodes) Sum() (flat int64, cum int64) {
+	for _, n := range ns {
+		flat += n.Flat
+		cum += n.Cum
+	}
+	return
+}
+
+func (n *Node) addSample(dw, w int64, labels string, numLabel map[string][]int64, format func(int64, string) string, flat bool) {
+	// Update sample value
+	if flat {
+		n.FlatDiv += dw
+		n.Flat += w
+	} else {
+		n.CumDiv += dw
+		n.Cum += w
+	}
+
+	// Add string tags
+	if labels != "" {
+		t := n.LabelTags.findOrAddTag(labels, "", 0)
+		if flat {
+			t.FlatDiv += dw
+			t.Flat += w
+		} else {
+			t.CumDiv += dw
+			t.Cum += w
+		}
+	}
+
+	numericTags := n.NumericTags[labels]
+	if numericTags == nil {
+		numericTags = TagMap{}
+		n.NumericTags[labels] = numericTags
+	}
+	// Add numeric tags
+	if format == nil {
+		format = defaultLabelFormat
+	}
+	for key, nvals := range numLabel {
+		for _, v := range nvals {
+			t := numericTags.findOrAddTag(format(v, key), key, v)
+			if flat {
+				t.FlatDiv += dw
+				t.Flat += w
+			} else {
+				t.CumDiv += dw
+				t.Cum += w
+			}
+		}
+	}
+}
+
+func defaultLabelFormat(v int64, key string) string {
+	return strconv.FormatInt(v, 10)
+}
+
+func (m TagMap) findOrAddTag(label, unit string, value int64) *Tag {
+	l := m[label]
+	if l == nil {
+		l = &Tag{
+			Name:  label,
+			Unit:  unit,
+			Value: value,
+		}
+		m[label] = l
+	}
+	return l
+}
+
+// String returns a text representation of a graph, for debugging purposes.
+func (g *Graph) String() string {
+	var s []string
+
+	nodeIndex := make(map[*Node]int, len(g.Nodes))
+
+	for i, n := range g.Nodes {
+		nodeIndex[n] = i + 1
+	}
+
+	for i, n := range g.Nodes {
+		name := n.Info.PrintableName()
+		var in, out []int
+
+		for _, from := range n.In {
+			in = append(in, nodeIndex[from.Src])
+		}
+		for _, to := range n.Out {
+			out = append(out, nodeIndex[to.Dest])
+		}
+		s = append(s, fmt.Sprintf("%d: %s[flat=%d cum=%d] %x -> %v ", i+1, name, n.Flat, n.Cum, in, out))
+	}
+	return strings.Join(s, "\n")
+}
+
+// DiscardLowFrequencyNodes returns a set of the nodes at or over a
+// specific cum value cutoff.
+func (g *Graph) DiscardLowFrequencyNodes(nodeCutoff int64) NodeSet {
+	return makeNodeSet(g.Nodes, nodeCutoff)
+}
+
+// DiscardLowFrequencyNodePtrs returns a NodePtrSet of nodes at or over a
+// specific cum value cutoff.
+func (g *Graph) DiscardLowFrequencyNodePtrs(nodeCutoff int64) NodePtrSet {
+	cutNodes := getNodesAboveCumCutoff(g.Nodes, nodeCutoff)
+	kept := make(NodePtrSet, len(cutNodes))
+	for _, n := range cutNodes {
+		kept[n] = true
+	}
+	return kept
+}
+
+func makeNodeSet(nodes Nodes, nodeCutoff int64) NodeSet {
+	cutNodes := getNodesAboveCumCutoff(nodes, nodeCutoff)
+	kept := make(NodeSet, len(cutNodes))
+	for _, n := range cutNodes {
+		kept[n.Info] = true
+	}
+	return kept
+}
+
+// getNodesAboveCumCutoff returns all the nodes which have a Cum value greater
+// than or equal to cutoff.
+func getNodesAboveCumCutoff(nodes Nodes, nodeCutoff int64) Nodes {
+	cutoffNodes := make(Nodes, 0, len(nodes))
+	for _, n := range nodes {
+		if abs64(n.Cum) < nodeCutoff {
+			continue
+		}
+		cutoffNodes = append(cutoffNodes, n)
+	}
+	return cutoffNodes
+}
+
+// TrimLowFrequencyTags removes tags that have less than
+// the specified weight.
+func (g *Graph) TrimLowFrequencyTags(tagCutoff int64) {
+	// Remove nodes with value <= total*nodeFraction
+	for _, n := range g.Nodes {
+		n.LabelTags = trimLowFreqTags(n.LabelTags, tagCutoff)
+		for s, nt := range n.NumericTags {
+			n.NumericTags[s] = trimLowFreqTags(nt, tagCutoff)
+		}
+	}
+}
+
+func trimLowFreqTags(tags TagMap, minValue int64) TagMap {
+	kept := TagMap{}
+	for s, t := range tags {
+		if abs64(t.Flat) >= minValue || abs64(t.Cum) >= minValue {
+			kept[s] = t
+		}
+	}
+	return kept
+}
+
+// TrimLowFrequencyEdges removes edges that have less than
+// the specified weight. Returns the number of edges removed
+func (g *Graph) TrimLowFrequencyEdges(edgeCutoff int64) int {
+	var droppedEdges int
+	for _, n := range g.Nodes {
+		for src, e := range n.In {
+			if abs64(e.Weight) < edgeCutoff {
+				delete(n.In, src)
+				delete(src.Out, n)
+				droppedEdges++
+			}
+		}
+	}
+	return droppedEdges
+}
+
+// SortNodes sorts the nodes in a graph based on a specific heuristic.
+func (g *Graph) SortNodes(cum bool, visualMode bool) {
+	// Sort nodes based on requested mode
+	switch {
+	case visualMode:
+		// Specialized sort to produce a more visually-interesting graph
+		g.Nodes.Sort(EntropyOrder)
+	case cum:
+		g.Nodes.Sort(CumNameOrder)
+	default:
+		g.Nodes.Sort(FlatNameOrder)
+	}
+}
+
+// SelectTopNodePtrs returns a set of the top maxNodes *Node in a graph.
+func (g *Graph) SelectTopNodePtrs(maxNodes int, visualMode bool) NodePtrSet {
+	set := make(NodePtrSet)
+	for _, node := range g.selectTopNodes(maxNodes, visualMode) {
+		set[node] = true
+	}
+	return set
+}
+
+// SelectTopNodes returns a set of the top maxNodes nodes in a graph.
+func (g *Graph) SelectTopNodes(maxNodes int, visualMode bool) NodeSet {
+	return makeNodeSet(g.selectTopNodes(maxNodes, visualMode), 0)
+}
+
+// selectTopNodes returns a slice of the top maxNodes nodes in a graph.
+func (g *Graph) selectTopNodes(maxNodes int, visualMode bool) Nodes {
+	if maxNodes > 0 {
+		if visualMode {
+			var count int
+			// If generating a visual graph, count tags as nodes. Update
+			// maxNodes to account for them.
+			for i, n := range g.Nodes {
+				if count += countTags(n) + 1; count >= maxNodes {
+					maxNodes = i + 1
+					break
+				}
+			}
+		}
+	}
+	if maxNodes > len(g.Nodes) {
+		maxNodes = len(g.Nodes)
+	}
+	return g.Nodes[:maxNodes]
+}
+
+// countTags counts the tags with flat count. This underestimates the
+// number of tags being displayed, but in practice is close enough.
+func countTags(n *Node) int {
+	count := 0
+	for _, e := range n.LabelTags {
+		if e.Flat != 0 {
+			count++
+		}
+	}
+	for _, t := range n.NumericTags {
+		for _, e := range t {
+			if e.Flat != 0 {
+				count++
+			}
+		}
+	}
+	return count
+}
+
+// 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
+}
+
+// RemoveRedundantEdges removes residual edges if the destination can
+// be reached through another path. This is done to simplify the graph
+// while preserving connectivity.
+func (g *Graph) RemoveRedundantEdges() {
+	// Walk the nodes and outgoing edges in reverse order to prefer
+	// removing edges with the lowest weight.
+	for i := len(g.Nodes); i > 0; i-- {
+		n := g.Nodes[i-1]
+		in := n.In.Sort()
+		for j := len(in); j > 0; j-- {
+			e := in[j-1]
+			if !e.Residual {
+				// Do not remove edges heavier than a non-residual edge, to
+				// avoid potential confusion.
+				break
+			}
+			if isRedundantEdge(e) {
+				delete(e.Src.Out, e.Dest)
+				delete(e.Dest.In, e.Src)
+			}
+		}
+	}
+}
+
+// isRedundantEdge determines if there is a path that allows e.Src
+// to reach e.Dest after removing e.
+func isRedundantEdge(e *Edge) bool {
+	src, n := e.Src, e.Dest
+	seen := map[*Node]bool{n: true}
+	queue := Nodes{n}
+	for len(queue) > 0 {
+		n := queue[0]
+		queue = queue[1:]
+		for _, ie := range n.In {
+			if e == ie || seen[ie.Src] {
+				continue
+			}
+			if ie.Src == src {
+				return true
+			}
+			seen[ie.Src] = true
+			queue = append(queue, ie.Src)
+		}
+	}
+	return false
+}
+
+// nodeSorter is a mechanism used to allow a report to be sorted
+// in different ways.
+type nodeSorter struct {
+	rs   Nodes
+	less func(l, r *Node) 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(s.rs[i], s.rs[j]) }
+
+// Sort reorders a slice of nodes based on the specified ordering
+// criteria. The result is sorted in decreasing order for (absolute)
+// numeric quantities, alphabetically for text, and increasing for
+// addresses.
+func (ns Nodes) Sort(o NodeOrder) error {
+	var s nodeSorter
+
+	switch o {
+	case FlatNameOrder:
+		s = nodeSorter{ns,
+			func(l, r *Node) bool {
+				if iv, jv := abs64(l.Flat), abs64(r.Flat); iv != jv {
+					return iv > jv
+				}
+				if iv, jv := l.Info.PrintableName(), r.Info.PrintableName(); iv != jv {
+					return iv < jv
+				}
+				if iv, jv := abs64(l.Cum), abs64(r.Cum); iv != jv {
+					return iv > jv
+				}
+				return compareNodes(l, r)
+			},
+		}
+	case FlatCumNameOrder:
+		s = nodeSorter{ns,
+			func(l, r *Node) bool {
+				if iv, jv := abs64(l.Flat), abs64(r.Flat); iv != jv {
+					return iv > jv
+				}
+				if iv, jv := abs64(l.Cum), abs64(r.Cum); iv != jv {
+					return iv > jv
+				}
+				if iv, jv := l.Info.PrintableName(), r.Info.PrintableName(); iv != jv {
+					return iv < jv
+				}
+				return compareNodes(l, r)
+			},
+		}
+	case NameOrder:
+		s = nodeSorter{ns,
+			func(l, r *Node) bool {
+				if iv, jv := l.Info.Name, r.Info.Name; iv != jv {
+					return iv < jv
+				}
+				return compareNodes(l, r)
+			},
+		}
+	case FileOrder:
+		s = nodeSorter{ns,
+			func(l, r *Node) bool {
+				if iv, jv := l.Info.File, r.Info.File; iv != jv {
+					return iv < jv
+				}
+				if iv, jv := l.Info.StartLine, r.Info.StartLine; iv != jv {
+					return iv < jv
+				}
+				return compareNodes(l, r)
+			},
+		}
+	case AddressOrder:
+		s = nodeSorter{ns,
+			func(l, r *Node) bool {
+				if iv, jv := l.Info.Address, r.Info.Address; iv != jv {
+					return iv < jv
+				}
+				return compareNodes(l, r)
+			},
+		}
+	case CumNameOrder, EntropyOrder:
+		// Hold scoring for score-based ordering
+		var score map[*Node]int64
+		scoreOrder := func(l, r *Node) bool {
+			if iv, jv := abs64(score[l]), abs64(score[r]); iv != jv {
+				return iv > jv
+			}
+			if iv, jv := l.Info.PrintableName(), r.Info.PrintableName(); iv != jv {
+				return iv < jv
+			}
+			if iv, jv := abs64(l.Flat), abs64(r.Flat); iv != jv {
+				return iv > jv
+			}
+			return compareNodes(l, r)
+		}
+
+		switch o {
+		case CumNameOrder:
+			score = make(map[*Node]int64, len(ns))
+			for _, n := range ns {
+				score[n] = n.Cum
+			}
+			s = nodeSorter{ns, scoreOrder}
+		case EntropyOrder:
+			score = make(map[*Node]int64, len(ns))
+			for _, n := range ns {
+				score[n] = entropyScore(n)
+			}
+			s = nodeSorter{ns, scoreOrder}
+		}
+	default:
+		return fmt.Errorf("report: unrecognized sort ordering: %d", o)
+	}
+	sort.Sort(s)
+	return nil
+}
+
+// compareNodes compares two nodes to provide a deterministic ordering
+// between them. Two nodes cannot have the same Node.Info value.
+func compareNodes(l, r *Node) bool {
+	return fmt.Sprint(l.Info) < fmt.Sprint(r.Info)
+}
+
+// entropyScore computes a score for a node representing how important
+// it is to include this node on a graph visualization. It is used to
+// sort the nodes and select which ones to display if we have more
+// nodes than desired in the graph. This number is computed by looking
+// at the flat and cum weights of the node and the incoming/outgoing
+// edges. The fundamental idea is to penalize nodes that have a simple
+// fallthrough from their incoming to the outgoing edge.
+func entropyScore(n *Node) int64 {
+	score := float64(0)
+
+	if len(n.In) == 0 {
+		score++ // Favor entry nodes
+	} else {
+		score += edgeEntropyScore(n, n.In, 0)
+	}
+
+	if len(n.Out) == 0 {
+		score++ // Favor leaf nodes
+	} else {
+		score += edgeEntropyScore(n, n.Out, n.Flat)
+	}
+
+	return int64(score*float64(n.Cum)) + n.Flat
+}
+
+// edgeEntropyScore computes the entropy value for a set of edges
+// coming in or out of a node. Entropy (as defined in information
+// theory) refers to the amount of information encoded by the set of
+// edges. A set of edges that have a more interesting distribution of
+// samples gets a higher score.
+func edgeEntropyScore(n *Node, edges EdgeMap, self int64) float64 {
+	score := float64(0)
+	total := self
+	for _, e := range edges {
+		if e.Weight > 0 {
+			total += abs64(e.Weight)
+		}
+	}
+	if total != 0 {
+		for _, e := range edges {
+			frac := float64(abs64(e.Weight)) / float64(total)
+			score += -frac * math.Log2(frac)
+		}
+		if self > 0 {
+			frac := float64(abs64(self)) / float64(total)
+			score += -frac * math.Log2(frac)
+		}
+	}
+	return score
+}
+
+// NodeOrder sets the ordering for a Sort operation
+type NodeOrder int
+
+// Sorting options for node sort.
+const (
+	FlatNameOrder NodeOrder = iota
+	FlatCumNameOrder
+	CumNameOrder
+	NameOrder
+	FileOrder
+	AddressOrder
+	EntropyOrder
+)
+
+// Sort returns a slice of the edges in the map, in a consistent
+// order. The sort order is first based on the edge weight
+// (higher-to-lower) and then by the node names to avoid flakiness.
+func (e EdgeMap) Sort() []*Edge {
+	el := make(edgeList, 0, len(e))
+	for _, w := range e {
+		el = append(el, w)
+	}
+
+	sort.Sort(el)
+	return el
+}
+
+// Sum returns the total weight for a set of nodes.
+func (e EdgeMap) Sum() int64 {
+	var ret int64
+	for _, edge := range e {
+		ret += edge.Weight
+	}
+	return ret
+}
+
+type edgeList []*Edge
+
+func (el edgeList) Len() int {
+	return len(el)
+}
+
+func (el edgeList) Less(i, j int) bool {
+	if el[i].Weight != el[j].Weight {
+		return abs64(el[i].Weight) > abs64(el[j].Weight)
+	}
+
+	from1 := el[i].Src.Info.PrintableName()
+	from2 := el[j].Src.Info.PrintableName()
+	if from1 != from2 {
+		return from1 < from2
+	}
+
+	to1 := el[i].Dest.Info.PrintableName()
+	to2 := el[j].Dest.Info.PrintableName()
+
+	return to1 < to2
+}
+
+func (el edgeList) Swap(i, j int) {
+	el[i], el[j] = el[j], el[i]
+}
+
+func abs64(i int64) int64 {
+	if i < 0 {
+		return -i
+	}
+	return i
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/graph_test.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph_test.go
new file mode 100644
index 0000000..c2848f8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph_test.go
@@ -0,0 +1,314 @@
+package graph
+
+import (
+	"fmt"
+	"testing"
+)
+
+func edgeDebugString(edge *Edge) string {
+	debug := ""
+	debug += fmt.Sprintf("\t\tSrc: %p\n", edge.Src)
+	debug += fmt.Sprintf("\t\tDest: %p\n", edge.Dest)
+	debug += fmt.Sprintf("\t\tWeight: %d\n", edge.Weight)
+	debug += fmt.Sprintf("\t\tResidual: %t\n", edge.Residual)
+	debug += fmt.Sprintf("\t\tInline: %t\n", edge.Inline)
+	return debug
+}
+
+func edgeMapsDebugString(in, out EdgeMap) string {
+	debug := ""
+	debug += "In Edges:\n"
+	for parent, edge := range in {
+		debug += fmt.Sprintf("\tParent: %p\n", parent)
+		debug += edgeDebugString(edge)
+	}
+	debug += "Out Edges:\n"
+	for child, edge := range out {
+		debug += fmt.Sprintf("\tChild: %p\n", child)
+		debug += edgeDebugString(edge)
+	}
+	return debug
+}
+
+func graphDebugString(graph *Graph) string {
+	debug := ""
+	for i, node := range graph.Nodes {
+		debug += fmt.Sprintf("Node %d: %p\n", i, node)
+	}
+
+	for i, node := range graph.Nodes {
+		debug += "\n"
+		debug += fmt.Sprintf("===  Node %d: %p  ===\n", i, node)
+		debug += edgeMapsDebugString(node.In, node.Out)
+	}
+	return debug
+}
+
+func expectedNodesDebugString(expected []expectedNode) string {
+	debug := ""
+	for i, node := range expected {
+		debug += fmt.Sprintf("Node %d: %p\n", i, node.node)
+	}
+
+	for i, node := range expected {
+		debug += "\n"
+		debug += fmt.Sprintf("===  Node %d: %p  ===\n", i, node.node)
+		debug += edgeMapsDebugString(node.in, node.out)
+	}
+	return debug
+}
+
+// edgeMapsEqual checks if all the edges in this equal all the edges in that.
+func edgeMapsEqual(this, that EdgeMap) bool {
+	if len(this) != len(that) {
+		return false
+	}
+	for node, thisEdge := range this {
+		if *thisEdge != *that[node] {
+			return false
+		}
+	}
+	return true
+}
+
+// nodesEqual checks if node is equal to expected.
+func nodesEqual(node *Node, expected expectedNode) bool {
+	return node == expected.node && edgeMapsEqual(node.In, expected.in) &&
+		edgeMapsEqual(node.Out, expected.out)
+}
+
+// graphsEqual checks if graph is equivalent to the graph templated by expected.
+func graphsEqual(graph *Graph, expected []expectedNode) bool {
+	if len(graph.Nodes) != len(expected) {
+		return false
+	}
+	expectedSet := make(map[*Node]expectedNode)
+	for i := range expected {
+		expectedSet[expected[i].node] = expected[i]
+	}
+
+	for _, node := range graph.Nodes {
+		expectedNode, found := expectedSet[node]
+		if !found || !nodesEqual(node, expectedNode) {
+			return false
+		}
+	}
+	return true
+}
+
+type expectedNode struct {
+	node    *Node
+	in, out EdgeMap
+}
+
+type trimTreeTestcase struct {
+	initial  *Graph
+	expected []expectedNode
+	keep     NodePtrSet
+}
+
+// makeExpectedEdgeResidual makes the edge from parent to child residual.
+func makeExpectedEdgeResidual(parent, child expectedNode) {
+	parent.out[child.node].Residual = true
+	child.in[parent.node].Residual = true
+}
+
+func makeEdgeInline(edgeMap EdgeMap, node *Node) {
+	edgeMap[node].Inline = true
+}
+
+func setEdgeWeight(edgeMap EdgeMap, node *Node, weight int64) {
+	edgeMap[node].Weight = weight
+}
+
+// createEdges creates directed edges from the parent to each of the children.
+func createEdges(parent *Node, children ...*Node) {
+	for _, child := range children {
+		edge := &Edge{
+			Src:  parent,
+			Dest: child,
+		}
+		parent.Out[child] = edge
+		child.In[parent] = edge
+	}
+}
+
+// createEmptyNode creates a node without any edges.
+func createEmptyNode() *Node {
+	return &Node{
+		In:  make(EdgeMap),
+		Out: make(EdgeMap),
+	}
+}
+
+// createExpectedNodes creates a slice of expectedNodes from nodes.
+func createExpectedNodes(nodes ...*Node) ([]expectedNode, NodePtrSet) {
+	expected := make([]expectedNode, len(nodes))
+	keep := make(NodePtrSet, len(nodes))
+
+	for i, node := range nodes {
+		expected[i] = expectedNode{
+			node: node,
+			in:   make(EdgeMap),
+			out:  make(EdgeMap),
+		}
+		keep[node] = true
+	}
+
+	return expected, keep
+}
+
+// createExpectedEdges creates directed edges from the parent to each of the
+// children.
+func createExpectedEdges(parent expectedNode, children ...expectedNode) {
+	for _, child := range children {
+		edge := &Edge{
+			Src:  parent.node,
+			Dest: child.node,
+		}
+		parent.out[child.node] = edge
+		child.in[parent.node] = edge
+	}
+}
+
+// createTestCase1 creates a test case that initally looks like:
+//     0
+//     |(5)
+//     1
+// (3)/ \(4)
+//   2   3.
+//
+// After keeping 0, 2, and 3, it expects the graph:
+//     0
+// (3)/ \(4)
+//   2   3.
+func createTestCase1() trimTreeTestcase {
+	// Create initial graph
+	graph := &Graph{make(Nodes, 4)}
+	nodes := graph.Nodes
+	for i := range nodes {
+		nodes[i] = createEmptyNode()
+	}
+	createEdges(nodes[0], nodes[1])
+	createEdges(nodes[1], nodes[2], nodes[3])
+	makeEdgeInline(nodes[0].Out, nodes[1])
+	makeEdgeInline(nodes[1].Out, nodes[2])
+	setEdgeWeight(nodes[0].Out, nodes[1], 5)
+	setEdgeWeight(nodes[1].Out, nodes[2], 3)
+	setEdgeWeight(nodes[1].Out, nodes[3], 4)
+
+	// Create expected graph
+	expected, keep := createExpectedNodes(nodes[0], nodes[2], nodes[3])
+	createExpectedEdges(expected[0], expected[1], expected[2])
+	makeEdgeInline(expected[0].out, expected[1].node)
+	makeExpectedEdgeResidual(expected[0], expected[1])
+	makeExpectedEdgeResidual(expected[0], expected[2])
+	setEdgeWeight(expected[0].out, expected[1].node, 3)
+	setEdgeWeight(expected[0].out, expected[2].node, 4)
+	return trimTreeTestcase{
+		initial:  graph,
+		expected: expected,
+		keep:     keep,
+	}
+}
+
+// createTestCase2 creates a test case that initially looks like:
+//   3
+//   | (12)
+//   1
+//   | (8)
+//   2
+//   | (15)
+//   0
+//   | (10)
+//   4.
+//
+// After keeping 3 and 4, it expects the graph:
+//   3
+//   | (10)
+//   4.
+func createTestCase2() trimTreeTestcase {
+	// Create initial graph
+	graph := &Graph{make(Nodes, 5)}
+	nodes := graph.Nodes
+	for i := range nodes {
+		nodes[i] = createEmptyNode()
+	}
+	createEdges(nodes[3], nodes[1])
+	createEdges(nodes[1], nodes[2])
+	createEdges(nodes[2], nodes[0])
+	createEdges(nodes[0], nodes[4])
+	setEdgeWeight(nodes[3].Out, nodes[1], 12)
+	setEdgeWeight(nodes[1].Out, nodes[2], 8)
+	setEdgeWeight(nodes[2].Out, nodes[0], 15)
+	setEdgeWeight(nodes[0].Out, nodes[4], 10)
+
+	// Create expected graph
+	expected, keep := createExpectedNodes(nodes[3], nodes[4])
+	createExpectedEdges(expected[0], expected[1])
+	makeExpectedEdgeResidual(expected[0], expected[1])
+	setEdgeWeight(expected[0].out, expected[1].node, 10)
+	return trimTreeTestcase{
+		initial:  graph,
+		expected: expected,
+		keep:     keep,
+	}
+}
+
+// createTestCase3 creates an initally empty graph and expects an empty graph
+// after trimming.
+func createTestCase3() trimTreeTestcase {
+	graph := &Graph{make(Nodes, 0)}
+	expected, keep := createExpectedNodes()
+	return trimTreeTestcase{
+		initial:  graph,
+		expected: expected,
+		keep:     keep,
+	}
+}
+
+// createTestCase4 creates a test case that initially looks like:
+//   0.
+//
+// After keeping 0, it expects the graph:
+//   0.
+func createTestCase4() trimTreeTestcase {
+	graph := &Graph{make(Nodes, 1)}
+	nodes := graph.Nodes
+	for i := range nodes {
+		nodes[i] = createEmptyNode()
+	}
+	expected, keep := createExpectedNodes(nodes[0])
+	return trimTreeTestcase{
+		initial:  graph,
+		expected: expected,
+		keep:     keep,
+	}
+}
+
+func createTrimTreeTestCases() []trimTreeTestcase {
+	caseGenerators := []func() trimTreeTestcase{
+		createTestCase1,
+		createTestCase2,
+		createTestCase3,
+		createTestCase4,
+	}
+	cases := make([]trimTreeTestcase, len(caseGenerators))
+	for i, gen := range caseGenerators {
+		cases[i] = gen()
+	}
+	return cases
+}
+
+func TestTrimTree(t *testing.T) {
+	tests := createTrimTreeTestCases()
+	for _, test := range tests {
+		graph := test.initial
+		graph.TrimTree(test.keep)
+		if !graphsEqual(graph, test.expected) {
+			t.Fatalf("Graphs do not match.\nExpected: %s\nFound: %s\n",
+				expectedNodesDebugString(test.expected),
+				graphDebugString(graph))
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose1.dot b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose1.dot
new file mode 100644
index 0000000..ceed025
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose1.dot
@@ -0,0 +1,7 @@
+digraph "testtitle" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "label1" [shape=box fontsize=16 label="label1\llabel2\l"] }
+N1 [label="src\n10 (10.00%)\nof 25 (25.00%)" fontsize=22 shape=box tooltip="src (25)" color="#b23c00" fillcolor="#edddd5"]
+N2 [label="dest\n15 (15.00%)\nof 25 (25.00%)" fontsize=24 shape=box tooltip="dest (25)" color="#b23c00" fillcolor="#edddd5"]
+N1 -> N2 [label=" 10" weight=11 color="#b28559" tooltip="src -> dest (10)" labeltooltip="src -> dest (10)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose2.dot b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose2.dot
new file mode 100644
index 0000000..ee951fe
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose2.dot
@@ -0,0 +1,7 @@
+digraph "testtitle" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "label1" [shape=box fontsize=16 label="label1\llabel2\l"] }
+N1 [label="SRC10 (10.00%)\nof 25 (25.00%)" fontsize=24 shape=folder tooltip="src (25)" color="#b23c00" fillcolor="#edddd5" style="bold,filled" peripheries=2 URL="www.google.com" target="_blank"]
+N2 [label="dest\n0 of 25 (25.00%)" fontsize=8 shape=box tooltip="dest (25)" color="#b23c00" fillcolor="#edddd5"]
+N1 -> N2 [label=" 10" weight=11 color="#b28559" tooltip="src -> dest (10)" labeltooltip="src -> dest (10)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose3.dot b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose3.dot
new file mode 100644
index 0000000..99a3119
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose3.dot
@@ -0,0 +1,11 @@
+digraph "testtitle" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "label1" [shape=box fontsize=16 label="label1\llabel2\l"] }
+N1 [label="src\n10 (10.00%)\nof 25 (25.00%)" fontsize=22 shape=box tooltip="src (25)" color="#b23c00" fillcolor="#edddd5"]
+N1_0 [label = "tag1" fontsize=8 shape=box3d tooltip="10"]
+N1 -> N1_0 [label=" 10" weight=100 tooltip="10" labeltooltip="10"]
+NN1_0 [label = "tag2" fontsize=8 shape=box3d tooltip="20"]
+N1 -> NN1_0 [label=" 20" weight=100 tooltip="20" labeltooltip="20"]
+N2 [label="dest\n15 (15.00%)\nof 25 (25.00%)" fontsize=24 shape=box tooltip="dest (25)" color="#b23c00" fillcolor="#edddd5"]
+N1 -> N2 [label=" 10" weight=11 color="#b28559" tooltip="src ... dest (10)" labeltooltip="src ... dest (10)" style="dotted" minlen=2]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose4.dot b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose4.dot
new file mode 100644
index 0000000..adc9cc6
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose4.dot
@@ -0,0 +1,4 @@
+digraph "testtitle" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "label1" [shape=box fontsize=16 label="label1\llabel2\l"] }
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose5.dot b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose5.dot
new file mode 100644
index 0000000..352975f
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/testdata/compose5.dot
@@ -0,0 +1,11 @@
+digraph "testtitle" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "label1" [shape=box fontsize=16 label="label1\llabel2\l"] }
+N1 [label="src\n10 (10.00%)\nof 25 (25.00%)" fontsize=22 shape=box tooltip="src (25)" color="#b23c00" fillcolor="#edddd5"]
+N1_0 [label = "tag1" fontsize=8 shape=box3d tooltip="10"]
+N1 -> N1_0 [label=" 10" weight=100 tooltip="10" labeltooltip="10"]
+NN1_0_0 [label = "tag2" fontsize=8 shape=box3d tooltip="20"]
+N1_0 -> NN1_0_0 [label=" 20" weight=100 tooltip="20" labeltooltip="20"]
+N2 [label="dest\n15 (15.00%)\nof 25 (25.00%)" fontsize=24 shape=box tooltip="dest (25)" color="#b23c00" fillcolor="#edddd5"]
+N1 -> N2 [label=" 10" weight=11 color="#b28559" tooltip="src -> dest (10)" labeltooltip="src -> dest (10)" minlen=2]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go
new file mode 100644
index 0000000..0f7a21d
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go
@@ -0,0 +1,299 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package measurement export utility functions to manipulate/format performance profile sample values.
+package measurement
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/google/pprof/profile"
+)
+
+// ScaleProfiles updates the units in a set of profiles to make them
+// compatible. It scales the profiles to the smallest unit to preserve
+// data.
+func ScaleProfiles(profiles []*profile.Profile) error {
+	if len(profiles) == 0 {
+		return nil
+	}
+	periodTypes := make([]*profile.ValueType, 0, len(profiles))
+	for _, p := range profiles {
+		if p.PeriodType != nil {
+			periodTypes = append(periodTypes, p.PeriodType)
+		}
+	}
+	periodType, err := CommonValueType(periodTypes)
+	if err != nil {
+		return fmt.Errorf("period type: %v", err)
+	}
+
+	// Identify common sample types
+	numSampleTypes := len(profiles[0].SampleType)
+	for _, p := range profiles[1:] {
+		if numSampleTypes != len(p.SampleType) {
+			return fmt.Errorf("inconsistent samples type count: %d != %d", numSampleTypes, len(p.SampleType))
+		}
+	}
+	sampleType := make([]*profile.ValueType, numSampleTypes)
+	for i := 0; i < numSampleTypes; i++ {
+		sampleTypes := make([]*profile.ValueType, len(profiles))
+		for j, p := range profiles {
+			sampleTypes[j] = p.SampleType[i]
+		}
+		sampleType[i], err = CommonValueType(sampleTypes)
+		if err != nil {
+			return fmt.Errorf("sample types: %v", err)
+		}
+	}
+
+	for _, p := range profiles {
+		if p.PeriodType != nil && periodType != nil {
+			period, _ := Scale(p.Period, p.PeriodType.Unit, periodType.Unit)
+			p.Period, p.PeriodType.Unit = int64(period), periodType.Unit
+		}
+		ratios := make([]float64, len(p.SampleType))
+		for i, st := range p.SampleType {
+			if sampleType[i] == nil {
+				ratios[i] = 1
+				continue
+			}
+			ratios[i], _ = Scale(1, st.Unit, sampleType[i].Unit)
+			p.SampleType[i].Unit = sampleType[i].Unit
+		}
+		if err := p.ScaleN(ratios); err != nil {
+			return fmt.Errorf("scale: %v", err)
+		}
+	}
+	return nil
+}
+
+// CommonValueType returns the finest type from a set of compatible
+// types.
+func CommonValueType(ts []*profile.ValueType) (*profile.ValueType, error) {
+	if len(ts) <= 1 {
+		return nil, nil
+	}
+	minType := ts[0]
+	for _, t := range ts[1:] {
+		if !compatibleValueTypes(minType, t) {
+			return nil, fmt.Errorf("incompatible types: %v %v", *minType, *t)
+		}
+		if ratio, _ := Scale(1, t.Unit, minType.Unit); ratio < 1 {
+			minType = t
+		}
+	}
+	rcopy := *minType
+	return &rcopy, nil
+}
+
+func compatibleValueTypes(v1, v2 *profile.ValueType) bool {
+	if v1 == nil || v2 == nil {
+		return true // No grounds to disqualify.
+	}
+	// Remove trailing 's' to permit minor mismatches.
+	if t1, t2 := strings.TrimSuffix(v1.Type, "s"), strings.TrimSuffix(v2.Type, "s"); t1 != t2 {
+		return false
+	}
+
+	return v1.Unit == v2.Unit ||
+		(isTimeUnit(v1.Unit) && isTimeUnit(v2.Unit)) ||
+		(isMemoryUnit(v1.Unit) && isMemoryUnit(v2.Unit))
+}
+
+// Scale a measurement from an unit to a different unit and returns
+// the scaled value and the target unit. The returned target unit
+// will be empty if uninteresting (could be skipped).
+func Scale(value int64, fromUnit, toUnit string) (float64, string) {
+	// Avoid infinite recursion on overflow.
+	if value < 0 && -value > 0 {
+		v, u := Scale(-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", "auto":
+		return float64(value), ""
+	default:
+		return float64(value), toUnit
+	}
+}
+
+// Label returns the label used to describe a certain measurement.
+func Label(value int64, unit string) string {
+	return ScaledLabel(value, unit, "auto")
+}
+
+// ScaledLabel scales the passed-in measurement (if necessary) and
+// returns the label used to describe a float measurement.
+func ScaledLabel(value int64, fromUnit, toUnit string) string {
+	v, u := Scale(value, fromUnit, toUnit)
+	sv := strings.TrimSuffix(fmt.Sprintf("%.2f", v), ".00")
+	if sv == "0" || sv == "-0" {
+		return "0"
+	}
+	return sv + u
+}
+
+// isMemoryUnit returns whether a name is recognized as a memory size
+// unit.
+func isMemoryUnit(unit string) bool {
+	switch strings.TrimSuffix(strings.ToLower(unit), "s") {
+	case "byte", "b", "kilobyte", "kb", "megabyte", "mb", "gigabyte", "gb":
+		return true
+	}
+	return false
+}
+
+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
+}
+
+// isTimeUnit returns whether a name is recognized as a time unit.
+func isTimeUnit(unit string) bool {
+	unit = strings.ToLower(unit)
+	if len(unit) > 2 {
+		unit = strings.TrimSuffix(unit, "s")
+	}
+
+	switch unit {
+	case "nanosecond", "ns", "microsecond", "millisecond", "ms", "s", "second", "sec", "hr", "day", "week", "year":
+		return true
+	}
+	return false
+}
+
+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", "s":
+		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
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
new file mode 100644
index 0000000..d14ac2c
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
@@ -0,0 +1,187 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package plugin defines the plugin implementations that the main pprof driver requires.
+package plugin
+
+import (
+	"io"
+	"regexp"
+	"time"
+
+	"github.com/google/pprof/profile"
+)
+
+// Options groups all the optional plugins into pprof.
+type Options struct {
+	Writer  Writer
+	Flagset FlagSet
+	Fetch   Fetcher
+	Sym     Symbolizer
+	Obj     ObjTool
+	UI      UI
+}
+
+// Writer provides a mechanism to write data under a certain name,
+// typically a filename.
+type Writer interface {
+	Open(name string) (io.WriteCloser, error)
+}
+
+// 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
+
+	// BoolVar, IntVar, Float64Var, and StringVar define new flags referencing
+	// a given pointer, like the functions of the same name in package flag.
+	BoolVar(pointer *bool, name string, def bool, usage string)
+	IntVar(pointer *int, name string, def int, usage string)
+	Float64Var(pointer *float64, name string, def float64, usage string)
+	StringVar(pointer *string, name string, def string, usage string)
+
+	// StringList is similar to String but allows multiple values for a
+	// single flag
+	StringList(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
+}
+
+// A Fetcher reads and returns the profile named by src. src can be a
+// local file path or a URL. duration and timeout are units specified
+// by the end user, or 0 by default. duration refers to the length of
+// the profile collection, if applicable, and timeout is the amount of
+// time to wait for a profile before returning an error. Returns the
+// fetched profile, the URL of the actual source of the profile, or an
+// error.
+type Fetcher interface {
+	Fetch(src string, duration, timeout time.Duration) (*profile.Profile, string, error)
+}
+
+// A Symbolizer introduces symbol information into a profile.
+type Symbolizer interface {
+	Symbolize(mode string, srcs MappingSources, prof *profile.Profile) error
+}
+
+// MappingSources map each profile.Mapping to the source of the profile.
+// The key is either Mapping.File or Mapping.BuildId.
+type MappingSources map[string][]struct {
+	Source string // URL of the source the mapping was collected from
+	Start  uint64 // delta applied to addresses from this source (to represent Merge adjustments)
+}
+
+// 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/limit/offset are the addresses where it is mapped
+	// into memory in the address space being inspected.
+	Open(file string, start, limit, offset uint64) (ObjFile, 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)
+}
+
+// An Inst is a single instruction in an assembly listing.
+type Inst struct {
+	Addr     uint64 // virtual address of instruction
+	Text     string // instruction text
+	Function string // function name
+	File     string // source file
+	Line     int    // source line
+}
+
+// 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)
+}
+
+// A UI manages user interactions.
+type UI interface {
+	// Read returns a line of text (a command) read from the user.
+	// prompt is printed before reading the command.
+	ReadLine(prompt string) (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)
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/proftest/proftest.go b/src/cmd/vendor/github.com/google/pprof/internal/proftest/proftest.go
new file mode 100644
index 0000000..9767b2e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/proftest/proftest.go
@@ -0,0 +1,106 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package proftest provides some utility routines to test other
+// packages related to profiles.
+package proftest
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"testing"
+)
+
+// Diff compares two byte arrays using the diff tool to highlight the
+// differences. It is meant for testing purposes to display the
+// differences between expected and actual output.
+func Diff(b1, b2 []byte) (data []byte, err error) {
+	f1, err := ioutil.TempFile("", "proto_test")
+	if err != nil {
+		return nil, err
+	}
+	defer os.Remove(f1.Name())
+	defer f1.Close()
+
+	f2, err := ioutil.TempFile("", "proto_test")
+	if err != nil {
+		return nil, err
+	}
+	defer os.Remove(f2.Name())
+	defer f2.Close()
+
+	f1.Write(b1)
+	f2.Write(b2)
+
+	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+	if len(data) > 0 {
+		// diff exits with a non-zero status when the files don't match.
+		// Ignore that failure as long as we get output.
+		err = nil
+	}
+	if err != nil {
+		data = []byte(fmt.Sprintf("diff failed: %v\nb1: %q\nb2: %q\n", err, b1, b2))
+		err = nil
+	}
+	return
+}
+
+// EncodeJSON encodes a value into a byte array. This is intended for
+// testing purposes.
+func EncodeJSON(x interface{}) []byte {
+	data, err := json.MarshalIndent(x, "", "    ")
+	if err != nil {
+		panic(err)
+	}
+	data = append(data, '\n')
+	return data
+}
+
+// TestUI implements the plugin.UI interface, triggering test failures
+// if more than Ignore errors are printed.
+type TestUI struct {
+	T      *testing.T
+	Ignore int
+}
+
+// ReadLine returns no input, as no input is expected during testing.
+func (ui *TestUI) ReadLine(_ string) (string, error) {
+	return "", fmt.Errorf("no input")
+}
+
+// Print messages are discarded by the test UI.
+func (ui *TestUI) Print(args ...interface{}) {
+}
+
+// PrintErr messages may trigger an error failure. A fixed number of
+// error messages are permitted when appropriate.
+func (ui *TestUI) PrintErr(args ...interface{}) {
+	if ui.Ignore > 0 {
+		ui.Ignore--
+		return
+	}
+	ui.T.Error(args)
+}
+
+// IsTerminal indicates if the UI is an interactive terminal.
+func (ui *TestUI) IsTerminal() bool {
+	return false
+}
+
+// SetAutoComplete is not supported by the test UI.
+func (ui *TestUI) SetAutoComplete(_ func(string) string) {
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
new file mode 100644
index 0000000..ecfd698
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
@@ -0,0 +1,1167 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package report summarizes a performance profile into a
+// human-readable report.
+package report
+
+import (
+	"fmt"
+	"io"
+	"math"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/google/pprof/internal/graph"
+	"github.com/google/pprof/internal/measurement"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/profile"
+)
+
+// Output formats.
+const (
+	Callgrind = iota
+	Comments
+	Dis
+	Dot
+	List
+	Proto
+	Raw
+	Tags
+	Text
+	TopProto
+	Traces
+	Tree
+	WebList
+)
+
+// Options are the formatting and filtering options used to generate a
+// profile.
+type Options struct {
+	OutputFormat int
+
+	CumSort             bool
+	CallTree            bool
+	DropNegative        bool
+	PositivePercentages bool
+	CompactLabels       bool
+	Ratio               float64
+	Title               string
+	ProfileLabels       []string
+
+	NodeCount    int
+	NodeFraction float64
+	EdgeFraction float64
+
+	SampleValue       func(s []int64) int64
+	SampleMeanDivisor func(s []int64) int64
+	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.
+	SourcePath string         // Search path for source files.
+}
+
+// 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 Comments:
+		return printComments(w, rpt)
+	case Dot:
+		return printDOT(w, rpt)
+	case Tree:
+		return printTree(w, rpt)
+	case Text:
+		return printText(w, rpt)
+	case Traces:
+		return printTraces(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 TopProto:
+		return printTopProto(w, rpt)
+	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")
+}
+
+// newTrimmedGraph creates a graph for this report, trimmed according
+// to the report options.
+func (rpt *Report) newTrimmedGraph() (g *graph.Graph, origCount, droppedNodes, droppedEdges int) {
+	o := rpt.options
+
+	// Build a graph and refine it. On each refinement step we must rebuild the graph from the samples,
+	// as the graph itself doesn't contain enough information to preserve full precision.
+	visualMode := o.OutputFormat == Dot
+	cumSort := o.CumSort
+
+	// First step: Build complete graph to identify low frequency nodes, based on their cum weight.
+	g = rpt.newGraph(nil)
+	totalValue, _ := g.Nodes.Sum()
+	nodeCutoff := abs64(int64(float64(totalValue) * o.NodeFraction))
+	edgeCutoff := abs64(int64(float64(totalValue) * o.EdgeFraction))
+
+	// Filter out nodes with cum value below nodeCutoff.
+	if nodeCutoff > 0 {
+		if o.CallTree {
+			if nodesKept := g.DiscardLowFrequencyNodePtrs(nodeCutoff); len(g.Nodes) != len(nodesKept) {
+				droppedNodes = len(g.Nodes) - len(nodesKept)
+				g.TrimTree(nodesKept)
+			}
+		} else {
+			if nodesKept := g.DiscardLowFrequencyNodes(nodeCutoff); len(g.Nodes) != len(nodesKept) {
+				droppedNodes = len(g.Nodes) - len(nodesKept)
+				g = rpt.newGraph(nodesKept)
+			}
+		}
+	}
+	origCount = len(g.Nodes)
+
+	// Second step: Limit the total number of nodes. Apply specialized heuristics to improve
+	// visualization when generating dot output.
+	g.SortNodes(cumSort, visualMode)
+	if nodeCount := o.NodeCount; nodeCount > 0 {
+		// Remove low frequency tags and edges as they affect selection.
+		g.TrimLowFrequencyTags(nodeCutoff)
+		g.TrimLowFrequencyEdges(edgeCutoff)
+		if o.CallTree {
+			if nodesKept := g.SelectTopNodePtrs(nodeCount, visualMode); len(g.Nodes) != len(nodesKept) {
+				g.TrimTree(nodesKept)
+				g.SortNodes(cumSort, visualMode)
+			}
+		} else {
+			if nodesKept := g.SelectTopNodes(nodeCount, visualMode); len(g.Nodes) != len(nodesKept) {
+				g = rpt.newGraph(nodesKept)
+				g.SortNodes(cumSort, visualMode)
+			}
+		}
+	}
+
+	// Final step: Filter out low frequency tags and edges, and remove redundant edges that clutter
+	// the graph.
+	g.TrimLowFrequencyTags(nodeCutoff)
+	droppedEdges = g.TrimLowFrequencyEdges(edgeCutoff)
+	if visualMode {
+		g.RemoveRedundantEdges()
+	}
+	return
+}
+
+func (rpt *Report) selectOutputUnit(g *graph.Graph) {
+	o := rpt.options
+
+	// Select best unit for profile output.
+	// Find the appropriate units for the smallest non-zero sample
+	if o.OutputUnit != "minimum" || len(g.Nodes) == 0 {
+		return
+	}
+	var minValue int64
+
+	for _, n := range g.Nodes {
+		nodeMin := abs64(n.FlatValue())
+		if nodeMin == 0 {
+			nodeMin = abs64(n.CumValue())
+		}
+		if nodeMin > 0 && (minValue == 0 || nodeMin < minValue) {
+			minValue = nodeMin
+		}
+	}
+	maxValue := rpt.total
+	if minValue == 0 {
+		minValue = maxValue
+	}
+
+	if r := o.Ratio; r > 0 && r != 1 {
+		minValue = int64(float64(minValue) * r)
+		maxValue = int64(float64(maxValue) * r)
+	}
+
+	_, minUnit := measurement.Scale(minValue, o.SampleUnit, "minimum")
+	_, maxUnit := measurement.Scale(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 = measurement.Scale(100*minValue, o.SampleUnit, "minimum")
+	}
+
+	if unit != "" {
+		o.OutputUnit = unit
+	} else {
+		o.OutputUnit = o.SampleUnit
+	}
+}
+
+// newGraph creates a new graph for this report. If nodes is non-nil,
+// only nodes whose info matches are included. Otherwise, all nodes
+// are included, without trimming.
+func (rpt *Report) newGraph(nodes graph.NodeSet) *graph.Graph {
+	o := rpt.options
+
+	// Clean up file paths using heuristics.
+	prof := rpt.prof
+	for _, f := range prof.Function {
+		f.Filename = trimPath(f.Filename)
+	}
+	// Remove numeric tags not recognized by pprof.
+	for _, s := range prof.Sample {
+		numLabels := make(map[string][]int64, len(s.NumLabel))
+		for k, v := range s.NumLabel {
+			if k == "bytes" {
+				numLabels[k] = append(numLabels[k], v...)
+			}
+		}
+		s.NumLabel = numLabels
+	}
+
+	formatTag := func(v int64, key string) string {
+		return measurement.ScaledLabel(v, key, o.OutputUnit)
+	}
+
+	gopt := &graph.Options{
+		SampleValue:       o.SampleValue,
+		SampleMeanDivisor: o.SampleMeanDivisor,
+		FormatTag:         formatTag,
+		CallTree:          o.CallTree && (o.OutputFormat == Dot || o.OutputFormat == Callgrind),
+		DropNegative:      o.DropNegative,
+		KeptNodes:         nodes,
+	}
+
+	// Only keep binary names for disassembly-based reports, otherwise
+	// remove it to allow merging of functions across binaries.
+	switch o.OutputFormat {
+	case Raw, List, WebList, Dis, Callgrind:
+		gopt.ObjNames = true
+	}
+
+	return graph.New(rpt.prof, gopt)
+}
+
+func printTopProto(w io.Writer, rpt *Report) error {
+	p := rpt.prof
+	o := rpt.options
+	g, _, _, _ := rpt.newTrimmedGraph()
+	rpt.selectOutputUnit(g)
+
+	out := profile.Profile{
+		SampleType: []*profile.ValueType{
+			{Type: "cum", Unit: o.OutputUnit},
+			{Type: "flat", Unit: o.OutputUnit},
+		},
+		TimeNanos:     p.TimeNanos,
+		DurationNanos: p.DurationNanos,
+		PeriodType:    p.PeriodType,
+		Period:        p.Period,
+	}
+	functionMap := make(functionMap)
+	for i, n := range g.Nodes {
+		f := functionMap.FindOrAdd(n.Info)
+		flat, cum := n.FlatValue(), n.CumValue()
+		l := &profile.Location{
+			ID:      uint64(i + 1),
+			Address: n.Info.Address,
+			Line: []profile.Line{
+				{
+					Line:     int64(n.Info.Lineno),
+					Function: f,
+				},
+			},
+		}
+
+		fv, _ := measurement.Scale(flat, o.SampleUnit, o.OutputUnit)
+		cv, _ := measurement.Scale(cum, o.SampleUnit, o.OutputUnit)
+		s := &profile.Sample{
+			Location: []*profile.Location{l},
+			Value:    []int64{int64(cv), int64(fv)},
+		}
+		out.Function = append(out.Function, f)
+		out.Location = append(out.Location, l)
+		out.Sample = append(out.Sample, s)
+	}
+
+	return out.Write(w)
+}
+
+type functionMap map[string]*profile.Function
+
+func (fm functionMap) FindOrAdd(ni graph.NodeInfo) *profile.Function {
+	fName := fmt.Sprintf("%q%q%q%d", ni.Name, ni.OrigName, ni.File, ni.StartLine)
+
+	if f := fm[fName]; f != nil {
+		return f
+	}
+
+	f := &profile.Function{
+		ID:         uint64(len(fm) + 1),
+		Name:       ni.Name,
+		SystemName: ni.OrigName,
+		Filename:   ni.File,
+		StartLine:  int64(ni.StartLine),
+	}
+	fm[fName] = f
+	return f
+}
+
+// printAssembly prints an annotated assembly listing.
+func printAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
+	o := rpt.options
+	prof := rpt.prof
+
+	g := rpt.newGraph(nil)
+
+	// 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.Nodes, 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 := sns.Sum()
+
+		// Get the function assembly.
+		insts, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End)
+		if err != nil {
+			return err
+		}
+
+		ns := annotateAssembly(insts, 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))
+
+		function, file, line := "", "", 0
+		for _, n := range ns {
+			locStr := ""
+			// Skip loc information if it hasn't changed from previous instruction.
+			if n.function != function || n.file != file || n.line != line {
+				function, file, line = n.function, n.file, n.line
+				if n.function != "" {
+					locStr = n.function + " "
+				}
+				if n.file != "" {
+					locStr += n.file
+					if n.line != 0 {
+						locStr += fmt.Sprintf(":%d", n.line)
+					}
+				}
+			}
+			switch {
+			case locStr == "":
+				// No location info, just print the instruction.
+				fmt.Fprintf(w, "%10s %10s %10x: %s\n",
+					valueOrDot(n.flatValue(), rpt),
+					valueOrDot(n.cumValue(), rpt),
+					n.address, n.instruction,
+				)
+			case len(n.instruction) < 40:
+				// Short instruction, print loc on the same line.
+				fmt.Fprintf(w, "%10s %10s %10x: %-40s;%s\n",
+					valueOrDot(n.flatValue(), rpt),
+					valueOrDot(n.cumValue(), rpt),
+					n.address, n.instruction,
+					locStr,
+				)
+			default:
+				// Long instruction, print loc on a separate line.
+				fmt.Fprintf(w, "%74s;%s\n", "", locStr)
+				fmt.Fprintf(w, "%10s %10s %10x: %s\n",
+					valueOrDot(n.flatValue(), rpt),
+					valueOrDot(n.cumValue(), rpt),
+					n.address, n.instruction,
+				)
+			}
+		}
+	}
+	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.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.Nodes {
+		if name := n.Info.PrintableName(); 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[m.File] {
+			if address == nil || !(m.Start <= *address && *address <= m.Limit) {
+				continue
+			}
+		}
+
+		f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset)
+		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 graph.Nodes, symbols []*objSymbol) map[*objSymbol]graph.Nodes {
+	symNodes := make(map[*objSymbol]graph.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
+}
+
+type assemblyInstruction struct {
+	address         uint64
+	instruction     string
+	function        string
+	file            string
+	line            int
+	flat, cum       int64
+	flatDiv, cumDiv int64
+}
+
+func (a *assemblyInstruction) flatValue() int64 {
+	if a.flatDiv != 0 {
+		return a.flat / a.flatDiv
+	}
+	return a.flat
+}
+
+func (a *assemblyInstruction) cumValue() int64 {
+	if a.cumDiv != 0 {
+		return a.cum / a.cumDiv
+	}
+	return a.cum
+}
+
+// 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(insts []plugin.Inst, samples graph.Nodes, base uint64) []assemblyInstruction {
+	// Add end marker to simplify printing loop.
+	insts = append(insts, plugin.Inst{
+		Addr: ^uint64(0),
+	})
+
+	// Ensure samples are sorted by address.
+	samples.Sort(graph.AddressOrder)
+
+	s := 0
+	asm := make([]assemblyInstruction, 0, len(insts))
+	for ix, in := range insts[:len(insts)-1] {
+		n := assemblyInstruction{
+			address:     in.Addr,
+			instruction: in.Text,
+			function:    in.Function,
+			line:        in.Line,
+		}
+		if in.File != "" {
+			n.file = filepath.Base(in.File)
+		}
+
+		// Sum all the samples until the next instruction (to account
+		// for samples attributed to the middle of an instruction).
+		for next := insts[ix+1].Addr; s < len(samples) && samples[s].Info.Address-base < next; s++ {
+			sample := samples[s]
+			n.flatDiv += sample.FlatDiv
+			n.flat += sample.Flat
+			n.cumDiv += sample.CumDiv
+			n.cum += sample.Cum
+			if f := sample.Info.File; f != "" && n.file == "" {
+				n.file = filepath.Base(f)
+			}
+			if ln := sample.Info.Lineno; ln != 0 && n.line == 0 {
+				n.line = ln
+			}
+			if f := sample.Info.Name; f != "" && n.function == "" {
+				n.function = f
+			}
+		}
+		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
+
+	o := rpt.options
+	formatTag := func(v int64, key string) string {
+		return measurement.ScaledLabel(v, key, o.OutputUnit)
+	}
+
+	// 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 := formatTag(nval, key)
+				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([]*graph.Tag, 0, len(tagMap))
+	for key := range tagMap {
+		tagKeys = append(tagKeys, &graph.Tag{Name: key})
+	}
+	for _, tagKey := range graph.SortTags(tagKeys, true) {
+		var total int64
+		key := tagKey.Name
+		tags := make([]*graph.Tag, 0, len(tagMap[key]))
+		for t, c := range tagMap[key] {
+			total += c
+			tags = append(tags, &graph.Tag{Name: t, Flat: c})
+		}
+
+		fmt.Fprintf(w, "%s: Total %d\n", key, total)
+		for _, t := range graph.SortTags(tags, true) {
+			if total > 0 {
+				fmt.Fprintf(w, "  %8d (%s): %s\n", t.FlatValue(),
+					percentage(t.FlatValue(), total), t.Name)
+			} else {
+				fmt.Fprintf(w, "  %8d: %s\n", t.FlatValue(), t.Name)
+			}
+		}
+		fmt.Fprintln(w)
+	}
+	return nil
+}
+
+// printComments prints all freeform comments in the profile.
+func printComments(w io.Writer, rpt *Report) error {
+	p := rpt.prof
+
+	for _, c := range p.Comments {
+		fmt.Fprintln(w, c)
+	}
+	return nil
+}
+
+// printText prints a flat text report for a profile.
+func printText(w io.Writer, rpt *Report) error {
+	g, origCount, droppedNodes, _ := rpt.newTrimmedGraph()
+	rpt.selectOutputUnit(g)
+
+	fmt.Fprintln(w, strings.Join(reportLabels(rpt, g, origCount, droppedNodes, 0, false), "\n"))
+
+	fmt.Fprintf(w, "%10s %5s%% %5s%% %10s %5s%%\n",
+		"flat", "flat", "sum", "cum", "cum")
+
+	var flatSum int64
+	for _, n := range g.Nodes {
+		name, flat, cum := n.Info.PrintableName(), n.FlatValue(), n.CumValue()
+
+		var inline, noinline bool
+		for _, e := range n.In {
+			if e.Inline {
+				inline = true
+			} else {
+				noinline = true
+			}
+		}
+
+		if inline {
+			if noinline {
+				name = name + " (partial-inline)"
+			} else {
+				name = name + " (inline)"
+			}
+		}
+
+		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
+}
+
+// printTraces prints all traces from a profile.
+func printTraces(w io.Writer, rpt *Report) error {
+	fmt.Fprintln(w, strings.Join(ProfileLabels(rpt), "\n"))
+
+	prof := rpt.prof
+	o := rpt.options
+
+	const separator = "-----------+-------------------------------------------------------"
+
+	_, locations := graph.CreateNodes(prof, &graph.Options{})
+	for _, sample := range prof.Sample {
+		var stack graph.Nodes
+		for _, loc := range sample.Location {
+			id := loc.ID
+			stack = append(stack, locations[id]...)
+		}
+
+		if len(stack) == 0 {
+			continue
+		}
+
+		fmt.Fprintln(w, separator)
+		// Print any text labels for the sample.
+		var labels []string
+		for s, vs := range sample.Label {
+			labels = append(labels, fmt.Sprintf("%10s:  %s\n", s, strings.Join(vs, " ")))
+		}
+		sort.Strings(labels)
+		fmt.Fprint(w, strings.Join(labels, ""))
+		var d, v int64
+		v = o.SampleValue(sample.Value)
+		if o.SampleMeanDivisor != nil {
+			d = o.SampleMeanDivisor(sample.Value)
+		}
+		// Print call stack.
+		if d != 0 {
+			v = v / d
+		}
+		fmt.Fprintf(w, "%10s   %s\n",
+			rpt.formatValue(v), stack[0].Info.PrintableName())
+		for _, s := range stack[1:] {
+			fmt.Fprintf(w, "%10s   %s\n", "", s.Info.PrintableName())
+		}
+	}
+	fmt.Fprintln(w, separator)
+	return nil
+}
+
+// printCallgrind prints a graph for a profile on callgrind format.
+func printCallgrind(w io.Writer, rpt *Report) error {
+	o := rpt.options
+	rpt.options.NodeFraction = 0
+	rpt.options.EdgeFraction = 0
+	rpt.options.NodeCount = 0
+
+	g, _, _, _ := rpt.newTrimmedGraph()
+	rpt.selectOutputUnit(g)
+
+	nodeNames := getDisambiguatedNames(g)
+
+	fmt.Fprintln(w, "positions: instr line")
+	fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
+
+	objfiles := make(map[string]int)
+	files := make(map[string]int)
+	names := make(map[string]int)
+
+	// prevInfo points to the previous NodeInfo.
+	// It is used to group cost lines together as much as possible.
+	var prevInfo *graph.NodeInfo
+	for _, n := range g.Nodes {
+		if prevInfo == nil || n.Info.Objfile != prevInfo.Objfile || n.Info.File != prevInfo.File || n.Info.Name != prevInfo.Name {
+			fmt.Fprintln(w)
+			fmt.Fprintln(w, "ob="+callgrindName(objfiles, n.Info.Objfile))
+			fmt.Fprintln(w, "fl="+callgrindName(files, n.Info.File))
+			fmt.Fprintln(w, "fn="+callgrindName(names, n.Info.Name))
+		}
+
+		addr := callgrindAddress(prevInfo, n.Info.Address)
+		sv, _ := measurement.Scale(n.FlatValue(), o.SampleUnit, o.OutputUnit)
+		fmt.Fprintf(w, "%s %d %d\n", addr, n.Info.Lineno, int64(sv))
+
+		// Print outgoing edges.
+		for _, out := range n.Out.Sort() {
+			c, _ := measurement.Scale(out.Weight, o.SampleUnit, o.OutputUnit)
+			callee := out.Dest
+			fmt.Fprintln(w, "cfl="+callgrindName(files, callee.Info.File))
+			fmt.Fprintln(w, "cfn="+callgrindName(names, nodeNames[callee]))
+			// pprof doesn't have a flat weight for a call, leave as 0.
+			fmt.Fprintf(w, "calls=0 %s %d\n", callgrindAddress(prevInfo, callee.Info.Address), callee.Info.Lineno)
+			// TODO: This address may be in the middle of a call
+			// instruction. It would be best to find the beginning
+			// of the instruction, but the tools seem to handle
+			// this OK.
+			fmt.Fprintf(w, "* * %d\n", int64(c))
+		}
+
+		prevInfo = &n.Info
+	}
+
+	return nil
+}
+
+// getDisambiguatedNames returns a map from each node in the graph to
+// the name to use in the callgrind output. Callgrind merges all
+// functions with the same [file name, function name]. Add a [%d/n]
+// suffix to disambiguate nodes with different values of
+// node.Function, which we want to keep separate. In particular, this
+// affects graphs created with --call_tree, where nodes from different
+// contexts are associated to different Functions.
+func getDisambiguatedNames(g *graph.Graph) map[*graph.Node]string {
+	nodeName := make(map[*graph.Node]string, len(g.Nodes))
+
+	type names struct {
+		file, function string
+	}
+
+	// nameFunctionIndex maps the callgrind names (filename, function)
+	// to the node.Function values found for that name, and each
+	// node.Function value to a sequential index to be used on the
+	// disambiguated name.
+	nameFunctionIndex := make(map[names]map[*graph.Node]int)
+	for _, n := range g.Nodes {
+		nm := names{n.Info.File, n.Info.Name}
+		p, ok := nameFunctionIndex[nm]
+		if !ok {
+			p = make(map[*graph.Node]int)
+			nameFunctionIndex[nm] = p
+		}
+		if _, ok := p[n.Function]; !ok {
+			p[n.Function] = len(p)
+		}
+	}
+
+	for _, n := range g.Nodes {
+		nm := names{n.Info.File, n.Info.Name}
+		nodeName[n] = n.Info.Name
+		if p := nameFunctionIndex[nm]; len(p) > 1 {
+			// If there is more than one function, add suffix to disambiguate.
+			nodeName[n] += fmt.Sprintf(" [%d/%d]", p[n.Function]+1, len(p))
+		}
+	}
+	return nodeName
+}
+
+// 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)
+}
+
+// callgrindAddress implements the callgrind subposition compression scheme if
+// possible. If prevInfo != nil, it contains the previous address. The current
+// address can be given relative to the previous address, with an explicit +/-
+// to indicate it is relative, or * for the same address.
+func callgrindAddress(prevInfo *graph.NodeInfo, curr uint64) string {
+	abs := fmt.Sprintf("%#x", curr)
+	if prevInfo == nil {
+		return abs
+	}
+
+	prev := prevInfo.Address
+	if prev == curr {
+		return "*"
+	}
+
+	diff := int64(curr - prev)
+	relative := fmt.Sprintf("%+d", diff)
+
+	// Only bother to use the relative address if it is actually shorter.
+	if len(relative) < len(abs) {
+		return relative
+	}
+
+	return abs
+}
+
+// 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, origCount, droppedNodes, _ := rpt.newTrimmedGraph()
+	rpt.selectOutputUnit(g)
+
+	fmt.Fprintln(w, strings.Join(reportLabels(rpt, g, origCount, droppedNodes, 0, false), "\n"))
+
+	fmt.Fprintln(w, separator)
+	fmt.Fprintln(w, legend)
+	var flatSum int64
+
+	rx := rpt.options.Symbol
+	for _, n := range g.Nodes {
+		name, flat, cum := n.Info.PrintableName(), n.FlatValue(), n.CumValue()
+
+		// 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 := n.In.Sort()
+		for _, in := range inEdges {
+			var inline string
+			if in.Inline {
+				inline = " (inline)"
+			}
+			fmt.Fprintf(w, "%50s %s |   %s%s\n", rpt.formatValue(in.Weight),
+				percentage(in.Weight, cum), in.Src.Info.PrintableName(), inline)
+		}
+
+		// 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 := n.Out.Sort()
+		for _, out := range outEdges {
+			var inline string
+			if out.Inline {
+				inline = " (inline)"
+			}
+			fmt.Fprintf(w, "%50s %s |   %s%s\n", rpt.formatValue(out.Weight),
+				percentage(out.Weight, cum), out.Dest.Info.PrintableName(), inline)
+		}
+	}
+	if len(g.Nodes) > 0 {
+		fmt.Fprintln(w, separator)
+	}
+	return nil
+}
+
+// printDOT prints an annotated callgraph in DOT format.
+func printDOT(w io.Writer, rpt *Report) error {
+	g, origCount, droppedNodes, droppedEdges := rpt.newTrimmedGraph()
+	rpt.selectOutputUnit(g)
+	labels := reportLabels(rpt, g, origCount, droppedNodes, droppedEdges, true)
+
+	o := rpt.options
+	formatTag := func(v int64, key string) string {
+		return measurement.ScaledLabel(v, key, o.OutputUnit)
+	}
+
+	c := &graph.DotConfig{
+		Title:       rpt.options.Title,
+		Labels:      labels,
+		FormatValue: rpt.formatValue,
+		FormatTag:   formatTag,
+		Total:       rpt.total,
+	}
+	graph.ComposeDot(w, g, &graph.DotAttributes{}, c)
+	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 = math.Abs(float64(value)/float64(total)) * 100
+	}
+	switch {
+	case math.Abs(ratio) >= 99.95 && math.Abs(ratio) <= 100.05:
+		return "  100%"
+	case math.Abs(ratio) >= 1.0:
+		return fmt.Sprintf("%5.2f%%", ratio)
+	default:
+		return fmt.Sprintf("%5.2g%%", ratio)
+	}
+}
+
+// ProfileLabels returns printable labels for a profile.
+func ProfileLabels(rpt *Report) []string {
+	label := []string{}
+	prof := rpt.prof
+	o := rpt.options
+	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)
+		}
+	}
+	// Only include comments that do not start with '#'.
+	for _, c := range prof.Comments {
+		if !strings.HasPrefix(c, "#") {
+			label = append(label, c)
+		}
+	}
+	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 {
+		duration := measurement.Label(prof.DurationNanos, "nanoseconds")
+		totalNanos, totalUnit := measurement.Scale(rpt.total, o.SampleUnit, "nanoseconds")
+		var ratio string
+		if totalUnit == "ns" && totalNanos != 0 {
+			ratio = "(" + percentage(int64(totalNanos), prof.DurationNanos) + ")"
+		}
+		label = append(label, fmt.Sprintf("Duration: %s, Total samples = %s %s", duration, rpt.formatValue(rpt.total), ratio))
+	}
+	return label
+}
+
+// reportLabels returns printable labels for a report. Includes
+// profileLabels.
+func reportLabels(rpt *Report, g *graph.Graph, origCount, droppedNodes, droppedEdges int, fullHeaders bool) []string {
+	nodeFraction := rpt.options.NodeFraction
+	edgeFraction := rpt.options.EdgeFraction
+	nodeCount := len(g.Nodes)
+
+	var label []string
+	if len(rpt.options.ProfileLabels) > 0 {
+		for _, l := range rpt.options.ProfileLabels {
+			label = append(label, l)
+		}
+	} else if fullHeaders || !rpt.options.CompactLabels {
+		label = ProfileLabels(rpt)
+	}
+
+	var flatSum int64
+	for _, n := range g.Nodes {
+		flatSum = flatSum + n.FlatValue()
+	}
+
+	label = append(label, fmt.Sprintf("Showing nodes accounting for %s, %s of %s total", rpt.formatValue(flatSum), strings.TrimSpace(percentage(flatSum, rpt.total)), rpt.formatValue(rpt.total)))
+
+	if rpt.total != 0 {
+		if droppedNodes > 0 {
+			label = append(label, genLabel(droppedNodes, "node", "cum",
+				rpt.formatValue(abs64(int64(float64(rpt.total)*nodeFraction)))))
+		}
+		if droppedEdges > 0 {
+			label = append(label, genLabel(droppedEdges, "edge", "freq",
+				rpt.formatValue(abs64(int64(float64(rpt.total)*edgeFraction)))))
+		}
+		if nodeCount > 0 && nodeCount < origCount {
+			label = append(label, fmt.Sprintf("Showing top %d nodes out of %d",
+				nodeCount, origCount))
+		}
+	}
+	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)
+}
+
+// New builds a new report indexing the sample values interpreting the
+// samples with the provided function.
+func New(prof *profile.Profile, o *Options) *Report {
+	format := func(v int64) string {
+		if r := o.Ratio; r > 0 && r != 1 {
+			fv := float64(v) * r
+			v = int64(fv)
+		}
+		return measurement.ScaledLabel(v, o.SampleUnit, o.OutputUnit)
+	}
+	return &Report{prof, computeTotal(prof, o.SampleValue, o.SampleMeanDivisor, !o.PositivePercentages),
+		o, format}
+}
+
+// NewDefault builds a new report indexing the last sample value
+// available.
+func NewDefault(prof *profile.Profile, options Options) *Report {
+	index := len(prof.SampleType) - 1
+	o := &options
+	if o.Title == "" && len(prof.Mapping) > 0 && prof.Mapping[0].File != "" {
+		o.Title = filepath.Base(prof.Mapping[0].File)
+	}
+	o.SampleType = prof.SampleType[index].Type
+	o.SampleUnit = strings.ToLower(prof.SampleType[index].Unit)
+	o.SampleValue = func(v []int64) int64 {
+		return v[index]
+	}
+	return New(prof, o)
+}
+
+// computeTotal computes the sum of all sample values. This will be
+// used to compute percentages. If includeNegative is set, use use
+// absolute values to provide a meaningful percentage for both
+// negative and positive values. Otherwise only use positive values,
+// which is useful when comparing profiles from different jobs.
+func computeTotal(prof *profile.Profile, value, meanDiv func(v []int64) int64, includeNegative bool) int64 {
+	var div, ret int64
+	for _, sample := range prof.Sample {
+		var d, v int64
+		v = value(sample.Value)
+		if meanDiv != nil {
+			d = meanDiv(sample.Value)
+		}
+		if v >= 0 {
+			ret += v
+			div += d
+		} else if includeNegative {
+			ret -= v
+			div += d
+		}
+	}
+	if div != 0 {
+		return ret / div
+	}
+	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
+	formatValue func(int64) string
+}
+
+func abs64(i int64) int64 {
+	if i < 0 {
+		return -i
+	}
+	return i
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go
new file mode 100644
index 0000000..28cf6b4
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go
@@ -0,0 +1,266 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package report
+
+import (
+	"bytes"
+	"io/ioutil"
+	"regexp"
+	"runtime"
+	"testing"
+
+	"github.com/google/pprof/internal/binutils"
+	"github.com/google/pprof/internal/graph"
+	"github.com/google/pprof/internal/proftest"
+	"github.com/google/pprof/profile"
+)
+
+type testcase struct {
+	rpt  *Report
+	want string
+}
+
+func TestSource(t *testing.T) {
+	const path = "testdata/"
+
+	sampleValue1 := func(v []int64) int64 {
+		return v[1]
+	}
+
+	for _, tc := range []testcase{
+		{
+			rpt: New(
+				testProfile.Copy(),
+				&Options{
+					OutputFormat: List,
+					Symbol:       regexp.MustCompile(`.`),
+
+					SampleValue: sampleValue1,
+					SampleUnit:  testProfile.SampleType[1].Unit,
+				},
+			),
+			want: path + "source.rpt",
+		},
+		{
+			rpt: New(
+				testProfile.Copy(),
+				&Options{
+					OutputFormat: Dot,
+					CallTree:     true,
+					Symbol:       regexp.MustCompile(`.`),
+
+					SampleValue: sampleValue1,
+					SampleUnit:  testProfile.SampleType[1].Unit,
+				},
+			),
+			want: path + "source.dot",
+		},
+	} {
+		b := bytes.NewBuffer(nil)
+		if err := Generate(b, tc.rpt, &binutils.Binutils{}); err != nil {
+			t.Fatalf("%s: %v", tc.want, err)
+		}
+
+		gold, err := ioutil.ReadFile(tc.want)
+		if err != nil {
+			t.Fatalf("%s: %v", tc.want, err)
+		}
+		if runtime.GOOS == "windows" {
+			gold = bytes.Replace(gold, []byte("testdata/"), []byte("testdata\\"), -1)
+		}
+		if string(b.String()) != string(gold) {
+			d, err := proftest.Diff(gold, b.Bytes())
+			if err != nil {
+				t.Fatalf("%s: %v", "source", err)
+			}
+			t.Error("source" + "\n" + string(d) + "\n" + "gold:\n" + tc.want)
+		}
+	}
+}
+
+var testM = []*profile.Mapping{
+	{
+		ID:              1,
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+}
+
+var testF = []*profile.Function{
+	{
+		ID:       1,
+		Name:     "main",
+		Filename: "testdata/source1",
+	},
+	{
+		ID:       2,
+		Name:     "foo",
+		Filename: "testdata/source1",
+	},
+	{
+		ID:       3,
+		Name:     "bar",
+		Filename: "testdata/source1",
+	},
+	{
+		ID:       4,
+		Name:     "tee",
+		Filename: "testdata/source2",
+	},
+}
+
+var testL = []*profile.Location{
+	{
+		ID:      1,
+		Mapping: testM[0],
+		Line: []profile.Line{
+			{
+				Function: testF[0],
+				Line:     2,
+			},
+		},
+	},
+	{
+		ID:      2,
+		Mapping: testM[0],
+		Line: []profile.Line{
+			{
+				Function: testF[1],
+				Line:     4,
+			},
+		},
+	},
+	{
+		ID:      3,
+		Mapping: testM[0],
+		Line: []profile.Line{
+			{
+				Function: testF[2],
+				Line:     10,
+			},
+		},
+	},
+	{
+		ID:      4,
+		Mapping: testM[0],
+		Line: []profile.Line{
+			{
+				Function: testF[3],
+				Line:     2,
+			},
+		},
+	},
+	{
+		ID:      5,
+		Mapping: testM[0],
+		Line: []profile.Line{
+			{
+				Function: testF[3],
+				Line:     8,
+			},
+		},
+	},
+}
+
+var testProfile = &profile.Profile{
+	PeriodType:    &profile.ValueType{Type: "cpu", Unit: "millisecond"},
+	Period:        10,
+	DurationNanos: 10e9,
+	SampleType: []*profile.ValueType{
+		{Type: "samples", Unit: "count"},
+		{Type: "cpu", Unit: "cycles"},
+	},
+	Sample: []*profile.Sample{
+		{
+			Location: []*profile.Location{testL[0]},
+			Value:    []int64{1, 1},
+		},
+		{
+			Location: []*profile.Location{testL[2], testL[1], testL[0]},
+			Value:    []int64{1, 10},
+		},
+		{
+			Location: []*profile.Location{testL[4], testL[2], testL[0]},
+			Value:    []int64{1, 100},
+		},
+		{
+			Location: []*profile.Location{testL[3], testL[0]},
+			Value:    []int64{1, 1000},
+		},
+		{
+			Location: []*profile.Location{testL[4], testL[3], testL[0]},
+			Value:    []int64{1, 10000},
+		},
+	},
+	Location: testL,
+	Function: testF,
+	Mapping:  testM,
+}
+
+func TestDisambiguation(t *testing.T) {
+	parent1 := &graph.Node{Info: graph.NodeInfo{Name: "parent1"}}
+	parent2 := &graph.Node{Info: graph.NodeInfo{Name: "parent2"}}
+	child1 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent1}
+	child2 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent2}
+	child3 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent1}
+	sibling := &graph.Node{Info: graph.NodeInfo{Name: "sibling"}, Function: parent1}
+
+	n := []*graph.Node{parent1, parent2, child1, child2, child3, sibling}
+
+	wanted := map[*graph.Node]string{
+		parent1: "parent1",
+		parent2: "parent2",
+		child1:  "child [1/2]",
+		child2:  "child [2/2]",
+		child3:  "child [1/2]",
+		sibling: "sibling",
+	}
+
+	g := &graph.Graph{Nodes: n}
+
+	names := getDisambiguatedNames(g)
+
+	for node, want := range wanted {
+		if got := names[node]; got != want {
+			t.Errorf("name %s, got %s, want %s", node.Info.Name, got, want)
+		}
+	}
+}
+
+func TestFunctionMap(t *testing.T) {
+
+	fm := make(functionMap)
+	nodes := []graph.NodeInfo{
+		{Name: "fun1"},
+		{Name: "fun2", File: "filename"},
+		{Name: "fun1"},
+		{Name: "fun2", File: "filename2"},
+	}
+
+	want := []profile.Function{
+		{ID: 1, Name: "fun1"},
+		{ID: 2, Name: "fun2", Filename: "filename"},
+		{ID: 1, Name: "fun1"},
+		{ID: 3, Name: "fun2", Filename: "filename2"},
+	}
+
+	for i, tc := range nodes {
+		if got, want := fm.FindOrAdd(tc), want[i]; *got != want {
+			t.Errorf("%d: want %v, got %v", i, want, got)
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
new file mode 100644
index 0000000..f5e3b6b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
@@ -0,0 +1,494 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package report
+
+// This file contains routines related to the generation of annotated
+// source listings.
+
+import (
+	"bufio"
+	"fmt"
+	"html/template"
+	"io"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/graph"
+	"github.com/google/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 := rpt.newGraph(nil)
+
+	// Identify all the functions that match the regexp provided.
+	// Group nodes for each matching function.
+	var functions graph.Nodes
+	functionNodes := make(map[string]graph.Nodes)
+	for _, n := range g.Nodes {
+		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(graph.NameOrder)
+
+	sourcePath := o.SourcePath
+	if sourcePath == "" {
+		wd, err := os.Getwd()
+		if err != nil {
+			return fmt.Errorf("Could not stat current dir: %v", err)
+		}
+		sourcePath = wd
+	}
+
+	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 graph.Nodes
+		fileNodes := make(map[string]graph.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.Fprintf(w, "No source information for %s\n", name)
+			continue
+		}
+
+		sourceFiles.Sort(graph.FileOrder)
+
+		// Print each file associated with this function.
+		for _, fl := range sourceFiles {
+			filename := fl.Info.File
+			fns := fileNodes[filename]
+			flatSum, cumSum := fns.Sum()
+
+			fnodes, _, err := getSourceFromFile(filename, sourcePath, fns, 0, 0)
+			fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, filename)
+			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 := rpt.newGraph(nil)
+
+	// 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
+	}
+
+	sourcePath := o.SourcePath
+	if sourcePath == "" {
+		wd, err := os.Getwd()
+		if err != nil {
+			return fmt.Errorf("Could not stat current dir: %v", err)
+		}
+		sourcePath = wd
+	}
+
+	type fileFunction struct {
+		fileName, functionName string
+	}
+
+	// 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.Nodes, symbols)
+
+	// Identify sources associated to a symbol by examining
+	// symbol samples. Classify samples per source file.
+	fileNodes := make(map[fileFunction]graph.Nodes)
+	if len(symNodes) == 0 {
+		for _, n := range g.Nodes {
+			if n.Info.File == "" || !o.Symbol.MatchString(n.Info.Name) {
+				continue
+			}
+			ff := fileFunction{n.Info.File, n.Info.Name}
+			fileNodes[ff] = append(fileNodes[ff], n)
+		}
+	} else {
+		for _, nodes := range symNodes {
+			for _, n := range nodes {
+				if n.Info.File != "" {
+					ff := fileFunction{n.Info.File, n.Info.Name}
+					fileNodes[ff] = append(fileNodes[ff], n)
+				}
+			}
+		}
+	}
+
+	if len(fileNodes) == 0 {
+		return fmt.Errorf("No source information for %s\n", o.Symbol.String())
+	}
+
+	sourceFiles := make(graph.Nodes, 0, len(fileNodes))
+	for _, nodes := range fileNodes {
+		sNode := *nodes[0]
+		sNode.Flat, sNode.Cum = nodes.Sum()
+		sourceFiles = append(sourceFiles, &sNode)
+	}
+	sourceFiles.Sort(graph.FileOrder)
+
+	// Print each file associated with this function.
+	printHeader(w, rpt)
+	for _, n := range sourceFiles {
+		ff := fileFunction{n.Info.File, n.Info.Name}
+		fns := fileNodes[ff]
+
+		asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj)
+		start, end := sourceCoordinates(asm)
+
+		fnodes, path, err := getSourceFromFile(ff.fileName, sourcePath, fns, start, end)
+		if err != nil {
+			fnodes, path = getMissingFunctionSource(ff.fileName, asm, start, end)
+		}
+
+		printFunctionHeader(w, ff.functionName, path, n.Flat, n.Cum, 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][]assemblyInstruction) (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 graph.Nodes, src string, obj plugin.ObjTool) map[int][]assemblyInstruction {
+	assembly := make(map[int][]assemblyInstruction)
+	// Identify symbol to use for this collection of samples.
+	o := findMatchingSymbol(objSyms, rs)
+	if o == nil {
+		return assembly
+	}
+
+	// Extract assembly for matched symbol
+	insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
+	if err != nil {
+		return assembly
+	}
+
+	srcBase := filepath.Base(src)
+	anodes := annotateAssembly(insts, rs, o.base)
+	var lineno = 0
+	for _, an := range anodes {
+		if filepath.Base(an.file) == srcBase {
+			lineno = an.line
+		}
+		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 graph.Nodes) *objSymbol {
+	for _, n := range ns {
+		for _, o := range objSyms {
+			if filepath.Base(o.sym.File) == filepath.Base(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 ProfileLabels(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 *graph.Node, assembly []assemblyInstruction, 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.file != "" {
+			fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.file), an.line)
+			if an.line != fn.Info.Lineno {
+				class = "unimportant"
+			}
+		}
+		flat, cum := an.flat, an.cum
+		if an.flatDiv != 0 {
+			flat = flat / an.flatDiv
+		}
+		if an.cumDiv != 0 {
+			cum = cum / an.cumDiv
+		}
+		fmt.Fprintf(w, " %8s %10s %10s %8x: %-48s <span class=%s>%s</span>\n", "",
+			valueOrDot(flat, rpt), valueOrDot(cum, rpt),
+			an.address,
+			template.HTMLEscapeString(an.instruction),
+			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)
+}
+
+// getSourceFromFile 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 getSourceFromFile(file, sourcePath string, fns graph.Nodes, start, end int) (graph.Nodes, string, error) {
+	file = trimPath(file)
+	f, err := openSourceFile(file, sourcePath)
+	if err != nil {
+		return nil, file, err
+	}
+
+	lineNodes := make(map[int]graph.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 graph.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 == "" {
+				break
+			}
+		}
+		if lineno >= start {
+			flat, cum := lineNodes[lineno].Sum()
+
+			src = append(src, &graph.Node{
+				Info: graph.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][]assemblyInstruction, start, end int) (graph.Nodes, string) {
+	var fnodes graph.Nodes
+	for i := start; i <= end; i++ {
+		insts := asm[i]
+		if len(insts) == 0 {
+			continue
+		}
+		var group assemblyInstruction
+		for _, insn := range insts {
+			group.flat += insn.flat
+			group.cum += insn.cum
+			group.flatDiv += insn.flatDiv
+			group.cumDiv += insn.cumDiv
+		}
+		flat := group.flatValue()
+		cum := group.cumValue()
+		fnodes = append(fnodes, &graph.Node{
+			Info: graph.NodeInfo{
+				Name:   "???",
+				Lineno: i,
+			},
+			Flat: flat,
+			Cum:  cum,
+		})
+	}
+	return fnodes, filename
+}
+
+// openSourceFile opens a source file from a name encoded in a
+// profile. File names in a profile after often relative paths, so
+// search them in each of the paths in searchPath (or CWD by default),
+// and their parents.
+func openSourceFile(path, searchPath string) (*os.File, error) {
+	if filepath.IsAbs(path) {
+		f, err := os.Open(path)
+		return f, err
+	}
+
+	// Scan each component of the path
+	for _, dir := range strings.Split(searchPath, ":") {
+		// Search up for every parent of each possible path.
+		for {
+			filename := filepath.Join(dir, path)
+			if f, err := os.Open(filename); err == nil {
+				return f, nil
+			}
+			parent := filepath.Dir(dir)
+			if parent == dir {
+				break
+			}
+			dir = parent
+		}
+	}
+
+	return nil, fmt.Errorf("Could not find file %s on path %s", path, searchPath)
+}
+
+// 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/vendor/github.com/google/pprof/internal/report/source_html.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
new file mode 100644
index 0000000..2bb81f2
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
@@ -0,0 +1,87 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package report
+
+const weblistPageHeader = `
+<!DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+font-family: sans-serif;
+}
+h1 {
+  font-size: 1.5em;
+  margin-bottom: 4px;
+}
+.legend {
+  font-size: 1.25em;
+}
+.line {
+color: #aaaaaa;
+}
+.nop {
+color: #aaaaaa;
+}
+.unimportant {
+color: #cccccc;
+}
+.disasmloc {
+color: #000000;
+}
+.deadsrc {
+cursor: pointer;
+}
+.deadsrc:hover {
+background-color: #eeeeee;
+}
+.livesrc {
+color: #0000ff;
+cursor: pointer;
+}
+.livesrc:hover {
+background-color: #eeeeee;
+}
+.asm {
+color: #008800;
+display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+  var target;
+  if (!e) e = window.event;
+  if (e.target) target = e.target;
+  else if (e.srcElement) target = e.srcElement;
+
+  if (target) {
+    var asm = target.nextSibling;
+    if (asm && asm.className == "asm") {
+      asm.style.display = (asm.style.display == "block" ? "" : "block");
+      e.preventDefault();
+      return false;
+    }
+  }
+}
+</script>
+</head>
+<body>
+`
+
+const weblistPageClosing = `
+</body>
+</html>
+`
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.dot b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.dot
new file mode 100644
index 0000000..19746a4
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.dot
@@ -0,0 +1,17 @@
+digraph "unnamed" {
+node [style=filled fillcolor="#f8f8f8"]
+subgraph cluster_L { "Duration: 10s, Total samples = 11111 " [shape=box fontsize=16 label="Duration: 10s, Total samples = 11111 \lShowing nodes accounting for 11111, 100% of 11111 total\l"] }
+N1 [label="tee\nsource2:8\n10000 (90.00%)" fontsize=24 shape=box tooltip="tee testdata/source2:8 (10000)" color="#b20500" fillcolor="#edd6d5"]
+N2 [label="main\nsource1:2\n1 (0.009%)\nof 11111 (100%)" fontsize=9 shape=box tooltip="main testdata/source1:2 (11111)" color="#b20000" fillcolor="#edd5d5"]
+N3 [label="tee\nsource2:2\n1000 (9.00%)\nof 11000 (99.00%)" fontsize=14 shape=box tooltip="tee testdata/source2:2 (11000)" color="#b20000" fillcolor="#edd5d5"]
+N4 [label="tee\nsource2:8\n100 (0.9%)" fontsize=10 shape=box tooltip="tee testdata/source2:8 (100)" color="#b2b0aa" fillcolor="#edecec"]
+N5 [label="bar\nsource1:10\n10 (0.09%)" fontsize=9 shape=box tooltip="bar testdata/source1:10 (10)" color="#b2b2b1" fillcolor="#ededed"]
+N6 [label="bar\nsource1:10\n0 of 100 (0.9%)" fontsize=8 shape=box tooltip="bar testdata/source1:10 (100)" color="#b2b0aa" fillcolor="#edecec"]
+N7 [label="foo\nsource1:4\n0 of 10 (0.09%)" fontsize=8 shape=box tooltip="foo testdata/source1:4 (10)" color="#b2b2b1" fillcolor="#ededed"]
+N2 -> N3 [label=" 11000" weight=100 penwidth=5 color="#b20000" tooltip="main testdata/source1:2 -> tee testdata/source2:2 (11000)" labeltooltip="main testdata/source1:2 -> tee testdata/source2:2 (11000)"]
+N3 -> N1 [label=" 10000" weight=91 penwidth=5 color="#b20500" tooltip="tee testdata/source2:2 -> tee testdata/source2:8 (10000)" labeltooltip="tee testdata/source2:2 -> tee testdata/source2:8 (10000)"]
+N6 -> N4 [label=" 100" color="#b2b0aa" tooltip="bar testdata/source1:10 -> tee testdata/source2:8 (100)" labeltooltip="bar testdata/source1:10 -> tee testdata/source2:8 (100)"]
+N2 -> N6 [label=" 100" color="#b2b0aa" tooltip="main testdata/source1:2 -> bar testdata/source1:10 (100)" labeltooltip="main testdata/source1:2 -> bar testdata/source1:10 (100)"]
+N7 -> N5 [label=" 10" color="#b2b2b1" tooltip="foo testdata/source1:4 -> bar testdata/source1:10 (10)" labeltooltip="foo testdata/source1:4 -> bar testdata/source1:10 (10)"]
+N2 -> N7 [label=" 10" color="#b2b2b1" tooltip="main testdata/source1:2 -> foo testdata/source1:4 (10)" labeltooltip="main testdata/source1:2 -> foo testdata/source1:4 (10)"]
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.rpt b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.rpt
new file mode 100644
index 0000000..9ec7b3b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source.rpt
@@ -0,0 +1,49 @@
+Total: 11111
+ROUTINE ======================== bar in testdata/source1
+        10        110 (flat, cum)  0.99% of Total
+         .          .      5:source1 line 5;
+         .          .      6:source1 line 6;
+         .          .      7:source1 line 7;
+         .          .      8:source1 line 8;
+         .          .      9:source1 line 9;
+        10        110     10:source1 line 10;
+         .          .     11:source1 line 11;
+         .          .     12:source1 line 12;
+         .          .     13:source1 line 13;
+         .          .     14:source1 line 14;
+         .          .     15:source1 line 15;
+ROUTINE ======================== foo in testdata/source1
+         0         10 (flat, cum)  0.09% of Total
+         .          .      1:source1 line 1;
+         .          .      2:source1 line 2;
+         .          .      3:source1 line 3;
+         .         10      4:source1 line 4;
+         .          .      5:source1 line 5;
+         .          .      6:source1 line 6;
+         .          .      7:source1 line 7;
+         .          .      8:source1 line 8;
+         .          .      9:source1 line 9;
+ROUTINE ======================== main in testdata/source1
+         1      11111 (flat, cum)   100% of Total
+         .          .      1:source1 line 1;
+         1      11111      2:source1 line 2;
+         .          .      3:source1 line 3;
+         .          .      4:source1 line 4;
+         .          .      5:source1 line 5;
+         .          .      6:source1 line 6;
+         .          .      7:source1 line 7;
+ROUTINE ======================== tee in testdata/source2
+     11100      21100 (flat, cum) 189.90% of Total
+         .          .      1:source2 line 1;
+      1000      11000      2:source2 line 2;
+         .          .      3:source2 line 3;
+         .          .      4:source2 line 4;
+         .          .      5:source2 line 5;
+         .          .      6:source2 line 6;
+         .          .      7:source2 line 7;
+     10100      10100      8:source2 line 8;
+         .          .      9:source2 line 9;
+         .          .     10:source2 line 10;
+         .          .     11:source2 line 11;
+         .          .     12:source2 line 12;
+         .          .     13:source2 line 13;
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source1 b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source1
new file mode 100644
index 0000000..70e3fc3
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source1
@@ -0,0 +1,19 @@
+source1 line 1;
+source1 line 2;
+source1 line 3;
+source1 line 4;
+source1 line 5;
+source1 line 6;
+source1 line 7;
+source1 line 8;
+source1 line 9;
+source1 line 10;
+source1 line 11;
+source1 line 12;
+source1 line 13;
+source1 line 14;
+source1 line 15;
+source1 line 16;
+source1 line 17;
+source1 line 18;
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source2 b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source2
new file mode 100644
index 0000000..54f99cc
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/testdata/source2
@@ -0,0 +1,19 @@
+source2 line 1;
+source2 line 2;
+source2 line 3;
+source2 line 4;
+source2 line 5;
+source2 line 6;
+source2 line 7;
+source2 line 8;
+source2 line 9;
+source2 line 10;
+source2 line 11;
+source2 line 12;
+source2 line 13;
+source2 line 14;
+source2 line 15;
+source2 line 16;
+source2 line 17;
+source2 line 18;
+
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go
new file mode 100644
index 0000000..2c1c729
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go
@@ -0,0 +1,356 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package symbolizer provides a routine to populate a profile with
+// symbol, file and line number information. It relies on the
+// addr2liner and demangle packages to do the actual work.
+package symbolizer
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/pprof/internal/binutils"
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/symbolz"
+	"github.com/google/pprof/profile"
+	"github.com/ianlancetaylor/demangle"
+)
+
+// Symbolizer implements the plugin.Symbolize interface.
+type Symbolizer struct {
+	Obj plugin.ObjTool
+	UI  plugin.UI
+}
+
+// test taps for dependency injection
+var symbolzSymbolize = symbolz.Symbolize
+var localSymbolize = doLocalSymbolize
+
+// Symbolize attempts to symbolize profile p. First uses binutils on
+// local binaries; if the source is a URL it attempts to get any
+// missed entries using symbolz.
+func (s *Symbolizer) Symbolize(mode string, sources plugin.MappingSources, p *profile.Profile) error {
+	remote, local, force, demanglerMode := true, true, false, ""
+	for _, o := range strings.Split(strings.ToLower(mode), ":") {
+		switch o {
+		case "none", "no":
+			return nil
+		case "local", "fastlocal":
+			remote, local = false, true
+		case "remote":
+			remote, local = true, false
+		case "", "force":
+			force = true
+		default:
+			switch d := strings.TrimPrefix(o, "demangle="); d {
+			case "full", "none", "templates":
+				demanglerMode = d
+				force = true
+				continue
+			case "default":
+				continue
+			}
+			s.UI.PrintErr("ignoring unrecognized symbolization option: " + mode)
+			s.UI.PrintErr("expecting -symbolize=[local|fastlocal|remote|none][:force][:demangle=[none|full|templates|default]")
+		}
+	}
+
+	var err error
+	if local {
+		// Symbolize locally using binutils.
+		if err = localSymbolize(mode, p, s.Obj, s.UI); err != nil {
+			s.UI.PrintErr("local symbolization: " + err.Error())
+		}
+	}
+	if remote {
+		if err = symbolzSymbolize(sources, postURL, p, s.UI); err != nil {
+			return err // Ran out of options.
+		}
+	}
+
+	Demangle(p, force, demanglerMode)
+	return 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)
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != http.StatusOK {
+		return nil, statusCodeError(resp)
+	}
+	return ioutil.ReadAll(resp.Body)
+}
+
+func statusCodeError(resp *http.Response) error {
+	if resp.Header.Get("X-Go-Pprof") != "" && strings.Contains(resp.Header.Get("Content-Type"), "text/plain") {
+		// error is from pprof endpoint
+		if body, err := ioutil.ReadAll(resp.Body); err == nil {
+			return fmt.Errorf("server response: %s - %s", resp.Status, body)
+		}
+	}
+	return fmt.Errorf("server response: %s", resp.Status)
+}
+
+// doLocalSymbolize adds symbol and line number information to all locations
+// in a profile. mode enables some options to control
+// symbolization.
+func doLocalSymbolize(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 {
+		case o == "force":
+			force = true
+		case o == "fastlocal":
+			if bu, ok := obj.(*binutils.Binutils); ok {
+				bu.SetFastSymbolization(true)
+			}
+		default:
+		}
+	}
+
+	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
+}
+
+// Demangle updates the function names in a profile with demangled C++
+// names, simplified according to demanglerMode. If force is set,
+// overwrite any names that appear already demangled.
+func Demangle(prof *profile.Profile, force bool, demanglerMode string) {
+	if force {
+		// Remove the current demangled names to force demangling
+		for _, f := range prof.Function {
+			if f.Name != "" && f.SystemName != "" {
+				f.Name = f.SystemName
+			}
+		}
+	}
+
+	var options []demangle.Option
+	switch demanglerMode {
+	case "": // demangled, simplified: no parameters, no templates, no return type
+		options = []demangle.Option{demangle.NoParams, demangle.NoTemplateParams}
+	case "templates": // demangled, simplified: no parameters, no return type
+		options = []demangle.Option{demangle.NoParams}
+	case "full":
+		options = []demangle.Option{demangle.NoClones}
+	case "none": // no demangling
+		return
+	}
+
+	// Copy the options because they may be updated by the call.
+	o := make([]demangle.Option, len(options))
+	for _, fn := range prof.Function {
+		if fn.Name != "" && fn.SystemName != fn.Name {
+			continue // Already demangled.
+		}
+		copy(o, options)
+		if demangled := demangle.Filter(fn.SystemName, o...); demangled != fn.SystemName {
+			fn.Name = demangled
+			continue
+		}
+		// Could not demangle. Apply heuristics in case the name is
+		// already demangled.
+		name := fn.SystemName
+		if looksLikeDemangledCPlusPlus(name) {
+			if demanglerMode == "" || demanglerMode == "templates" {
+				name = removeMatching(name, '(', ')')
+			}
+			if demanglerMode == "" {
+				name = removeMatching(name, '<', '>')
+			}
+		}
+		fn.Name = name
+	}
+}
+
+// looksLikeDemangledCPlusPlus is a heuristic to decide if a name is
+// the result of demangling C++. If so, further heuristics will be
+// applied to simplify the name.
+func looksLikeDemangledCPlusPlus(demangled string) bool {
+	if strings.Contains(demangled, ".<") { // Skip java names of the form "class.<init>"
+		return false
+	}
+	return strings.ContainsAny(demangled, "<>[]") || strings.Contains(demangled, "::")
+}
+
+// removeMatching removes nested instances of start..end from name.
+func removeMatching(name string, start, end byte) string {
+	s := string(start) + string(end)
+	var nesting, first, current int
+	for index := strings.IndexAny(name[current:], s); index != -1; index = strings.IndexAny(name[current:], s) {
+		switch current += index; name[current] {
+		case start:
+			nesting++
+			if nesting == 1 {
+				first = current
+			}
+		case end:
+			nesting--
+			switch {
+			case nesting < 0:
+				return name // Mismatch, abort
+			case nesting == 0:
+				name = name[:first] + name[current+1:]
+				current = first - 1
+			}
+		}
+		current++
+	}
+	return name
+}
+
+// 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
+	}
+
+	missingBinaries := false
+	for midx, 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
+		}
+
+		if m.File == "" {
+			if midx == 0 {
+				ui.PrintErr("Main binary filename not available.")
+				continue
+			}
+			missingBinaries = true
+			continue
+		}
+
+		// Skip well-known system mappings
+		if m.Unsymbolizable() {
+			continue
+		}
+
+		// Skip mappings pointing to a source URL
+		if m.BuildID == "" {
+			if u, err := url.Parse(m.File); err == nil && u.IsAbs() && strings.Contains(strings.ToLower(u.Scheme), "http") {
+				continue
+			}
+		}
+
+		name := filepath.Base(m.File)
+		f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset)
+		if err != nil {
+			ui.PrintErr("Local symbolization failed for ", name, ": ", err)
+			missingBinaries = true
+			continue
+		}
+		if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
+			ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
+			f.Close()
+			continue
+		}
+
+		mt.segments[m] = f
+	}
+	if missingBinaries {
+		ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.\n" +
+			"Try setting PPROF_BINARY_PATH to the search path for local binaries.")
+	}
+	return mt, nil
+}
+
+// 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/vendor/github.com/google/pprof/internal/symbolizer/symbolizer_test.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer_test.go
new file mode 100644
index 0000000..66cad3e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer_test.go
@@ -0,0 +1,260 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package symbolizer
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/proftest"
+	"github.com/google/pprof/profile"
+)
+
+var testM = []*profile.Mapping{
+	{
+		ID:    1,
+		Start: 0x1000,
+		Limit: 0x5000,
+		File:  "mapping",
+	},
+}
+
+var testL = []*profile.Location{
+	{
+		ID:      1,
+		Mapping: testM[0],
+		Address: 1000,
+	},
+	{
+		ID:      2,
+		Mapping: testM[0],
+		Address: 2000,
+	},
+	{
+		ID:      3,
+		Mapping: testM[0],
+		Address: 3000,
+	},
+	{
+		ID:      4,
+		Mapping: testM[0],
+		Address: 4000,
+	},
+	{
+		ID:      5,
+		Mapping: testM[0],
+		Address: 5000,
+	},
+}
+
+var testProfile = profile.Profile{
+	DurationNanos: 10e9,
+	SampleType: []*profile.ValueType{
+		{Type: "cpu", Unit: "cycles"},
+	},
+	Sample: []*profile.Sample{
+		{
+			Location: []*profile.Location{testL[0]},
+			Value:    []int64{1},
+		},
+		{
+			Location: []*profile.Location{testL[1], testL[0]},
+			Value:    []int64{10},
+		},
+		{
+			Location: []*profile.Location{testL[2], testL[0]},
+			Value:    []int64{100},
+		},
+		{
+			Location: []*profile.Location{testL[3], testL[0]},
+			Value:    []int64{1},
+		},
+		{
+			Location: []*profile.Location{testL[4], testL[3], testL[0]},
+			Value:    []int64{10000},
+		},
+	},
+	Location:   testL,
+	Mapping:    testM,
+	PeriodType: &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
+	Period:     10,
+}
+
+func TestSymbolization(t *testing.T) {
+	sSym := symbolzSymbolize
+	lSym := localSymbolize
+	defer func() {
+		symbolzSymbolize = sSym
+		localSymbolize = lSym
+	}()
+	symbolzSymbolize = symbolzMock
+	localSymbolize = localMock
+
+	type testcase struct {
+		mode        string
+		wantComment string
+	}
+
+	s := Symbolizer{
+		mockObjTool{},
+		&proftest.TestUI{T: t},
+	}
+	for i, tc := range []testcase{
+		{
+			"local",
+			"local=local",
+		},
+		{
+			"fastlocal",
+			"local=fastlocal",
+		},
+		{
+			"remote",
+			"symbolz",
+		},
+		{
+			"",
+			"local=:symbolz",
+		},
+	} {
+		prof := testProfile.Copy()
+		if err := s.Symbolize(tc.mode, nil, prof); err != nil {
+			t.Errorf("symbolize #%d: %v", i, err)
+			continue
+		}
+		if got, want := strings.Join(prof.Comments, ":"), tc.wantComment; got != want {
+			t.Errorf("got %s, want %s", got, want)
+			continue
+		}
+	}
+}
+
+func symbolzMock(sources plugin.MappingSources, syms func(string, string) ([]byte, error), p *profile.Profile, ui plugin.UI) error {
+	p.Comments = append(p.Comments, "symbolz")
+	return nil
+}
+
+func localMock(mode string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
+	p.Comments = append(p.Comments, "local="+mode)
+	return nil
+}
+
+func TestLocalSymbolization(t *testing.T) {
+	prof := testProfile.Copy()
+
+	if prof.HasFunctions() {
+		t.Error("unexpected function names")
+	}
+	if prof.HasFileLines() {
+		t.Error("unexpected filenames or line numbers")
+	}
+
+	b := mockObjTool{}
+	if err := localSymbolize("", prof, b, &proftest.TestUI{T: t}); err != nil {
+		t.Fatalf("localSymbolize(): %v", err)
+	}
+
+	for _, loc := range prof.Location {
+		if err := checkSymbolizedLocation(loc.Address, loc.Line); err != nil {
+			t.Errorf("location %d: %v", loc.Address, err)
+		}
+	}
+	if !prof.HasFunctions() {
+		t.Error("missing function names")
+	}
+	if !prof.HasFileLines() {
+		t.Error("missing filenames or line numbers")
+	}
+}
+
+func checkSymbolizedLocation(a uint64, got []profile.Line) error {
+	want, ok := mockAddresses[a]
+	if !ok {
+		return fmt.Errorf("unexpected address")
+	}
+	if len(want) != len(got) {
+		return fmt.Errorf("want len %d, got %d", len(want), len(got))
+	}
+
+	for i, w := range want {
+		g := got[i]
+		if g.Function.Name != w.Func {
+			return fmt.Errorf("want function: %q, got %q", w.Func, g.Function.Name)
+		}
+		if g.Function.Filename != w.File {
+			return fmt.Errorf("want filename: %q, got %q", w.File, g.Function.Filename)
+		}
+		if g.Line != int64(w.Line) {
+			return fmt.Errorf("want lineno: %d, got %d", w.Line, g.Line)
+		}
+	}
+	return nil
+}
+
+var mockAddresses = map[uint64][]plugin.Frame{
+	1000: []plugin.Frame{frame("fun11", "file11.src", 10)},
+	2000: []plugin.Frame{frame("fun21", "file21.src", 20), frame("fun22", "file22.src", 20)},
+	3000: []plugin.Frame{frame("fun31", "file31.src", 30), frame("fun32", "file32.src", 30), frame("fun33", "file33.src", 30)},
+	4000: []plugin.Frame{frame("fun41", "file41.src", 40), frame("fun42", "file42.src", 40), frame("fun43", "file43.src", 40), frame("fun44", "file44.src", 40)},
+	5000: []plugin.Frame{frame("fun51", "file51.src", 50), frame("fun52", "file52.src", 50), frame("fun53", "file53.src", 50), frame("fun54", "file54.src", 50), frame("fun55", "file55.src", 50)},
+}
+
+func frame(fname, file string, line int) plugin.Frame {
+	return plugin.Frame{
+		Func: fname,
+		File: file,
+		Line: line}
+}
+
+type mockObjTool struct{}
+
+func (mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
+	return mockObjFile{frames: mockAddresses}, nil
+}
+
+func (mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+	return nil, fmt.Errorf("disassembly not supported")
+}
+
+type mockObjFile struct {
+	frames map[uint64][]plugin.Frame
+}
+
+func (mockObjFile) Name() string {
+	return ""
+}
+
+func (mockObjFile) Base() uint64 {
+	return 0
+}
+
+func (mockObjFile) BuildID() string {
+	return ""
+}
+
+func (mf mockObjFile) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	return mf.frames[addr], nil
+}
+
+func (mockObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+	return []*plugin.Sym{}, nil
+}
+
+func (mockObjFile) Close() error {
+	return nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz.go
new file mode 100644
index 0000000..e84765b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz.go
@@ -0,0 +1,161 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package symbolz symbolizes a profile using the output from the symbolz
+// service.
+package symbolz
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/url"
+	"path"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/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(sources plugin.MappingSources, syms func(string, string) ([]byte, error), p *profile.Profile, ui plugin.UI) error {
+	for _, m := range p.Mapping {
+		if m.HasFunctions {
+			continue
+		}
+		mappingSources := sources[m.File]
+		if m.BuildID != "" {
+			mappingSources = append(mappingSources, sources[m.BuildID]...)
+		}
+		for _, source := range mappingSources {
+			if symz := symbolz(source.Source); symz != "" {
+				if err := symbolizeMapping(symz, int64(source.Start)-int64(m.Start), syms, m, p); err != nil {
+					return err
+				}
+				m.HasFunctions = true
+				break
+			}
+		}
+	}
+
+	return nil
+}
+
+// symbolz returns the corresponding symbolz source for a profile URL.
+func symbolz(source string) string {
+	if url, err := url.Parse(source); err == nil && url.Host != "" {
+		if strings.Contains(url.Path, "/") {
+			if dir := path.Dir(url.Path); dir == "/debug/pprof" {
+				// For Go language profile handlers in net/http/pprof package.
+				url.Path = "/debug/pprof/symbol"
+			} else {
+				url.Path = "/symbolz"
+			}
+			url.RawQuery = ""
+			return url.String()
+		}
+	}
+
+	return ""
+}
+
+// symbolizeMapping symbolizes locations belonging to a Mapping by querying
+// a symbolz handler. An offset is applied to all addresses to take care of
+// normalization occured for merged Mappings.
+func symbolizeMapping(source string, offset int64, syms func(string, string) ([]byte, error), m *profile.Mapping, p *profile.Profile) error {
+	// Construct query of addresses to symbolize.
+	var a []string
+	for _, l := range p.Location {
+		if l.Mapping == m && l.Address != 0 && len(l.Line) == 0 {
+			// Compensate for normalization.
+			addr := int64(l.Address) + offset
+			if addr < 0 {
+				return fmt.Errorf("unexpected negative adjusted address, mapping %v source %d, offset %d", l.Mapping, l.Address, offset)
+			}
+			a = append(a, fmt.Sprintf("%#x", addr))
+		}
+	}
+
+	if len(a) == 0 {
+		// No addresses to symbolize.
+		return nil
+	}
+
+	lines := make(map[uint64]profile.Line)
+	functions := make(map[string]*profile.Function)
+
+	b, err := syms(source, strings.Join(a, "+"))
+	if err != nil {
+		return err
+	}
+
+	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.ParseInt(symbol[1], 0, 64)
+			if err != nil {
+				return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
+			}
+			if addr < 0 {
+				return fmt.Errorf("unexpected negative adjusted address, source %s, offset %d", symbol[1], offset)
+			}
+			// Reapply offset expected by the profile.
+			addr -= offset
+
+			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[uint64(addr)] = profile.Line{Function: fn}
+		}
+	}
+
+	for _, l := range p.Location {
+		if l.Mapping != m {
+			continue
+		}
+		if line, ok := lines[l.Address]; ok {
+			l.Line = []profile.Line{line}
+		}
+	}
+
+	return nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz_test.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz_test.go
new file mode 100644
index 0000000..641b5ca
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolz/symbolz_test.go
@@ -0,0 +1,100 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package symbolz
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/pprof/internal/plugin"
+	"github.com/google/pprof/internal/proftest"
+	"github.com/google/pprof/profile"
+)
+
+func TestSymbolzURL(t *testing.T) {
+	for try, want := range map[string]string{
+		"http://host:8000/profilez":                        "http://host:8000/symbolz",
+		"http://host:8000/profilez?seconds=5":              "http://host:8000/symbolz",
+		"http://host:8000/profilez?seconds=5&format=proto": "http://host:8000/symbolz",
+		"http://host:8000/heapz?format=legacy":             "http://host:8000/symbolz",
+		"http://host:8000/debug/pprof/profile":             "http://host:8000/debug/pprof/symbol",
+		"http://host:8000/debug/pprof/profile?seconds=10":  "http://host:8000/debug/pprof/symbol",
+		"http://host:8000/debug/pprof/heap":                "http://host:8000/debug/pprof/symbol",
+	} {
+		if got := symbolz(try); got != want {
+			t.Errorf(`symbolz(%s)=%s, want "%s"`, try, got, want)
+		}
+	}
+}
+
+func TestSymbolize(t *testing.T) {
+	m := []*profile.Mapping{
+		{
+			ID:      1,
+			Start:   0x1000,
+			Limit:   0x5000,
+			BuildID: "buildid",
+		},
+	}
+	p := &profile.Profile{
+		Location: []*profile.Location{
+			{ID: 1, Mapping: m[0], Address: 0x1000},
+			{ID: 2, Mapping: m[0], Address: 0x2000},
+			{ID: 3, Mapping: m[0], Address: 0x3000},
+			{ID: 4, Mapping: m[0], Address: 0x4000},
+		},
+		Mapping: m,
+	}
+
+	s := plugin.MappingSources{
+		"buildid": []struct {
+			Source string
+			Start  uint64
+		}{
+			{Source: "http://localhost:80/profilez"},
+		},
+	}
+
+	if err := Symbolize(s, fetchSymbols, p, &proftest.TestUI{T: t}); err != nil {
+		t.Errorf("symbolz: %v", err)
+	}
+
+	if l := p.Location[0]; len(l.Line) != 0 {
+		t.Errorf("unexpected symbolization for %#x: %v", l.Address, l.Line)
+	}
+
+	for _, l := range p.Location[1:] {
+		if len(l.Line) != 1 {
+			t.Errorf("failed to symbolize %#x", l.Address)
+			continue
+		}
+		address := l.Address - l.Mapping.Start
+		if got, want := l.Line[0].Function.Name, fmt.Sprintf("%#x", address); got != want {
+			t.Errorf("symbolz %#x, got %s, want %s", address, got, want)
+		}
+	}
+}
+
+func fetchSymbols(source, post string) ([]byte, error) {
+	var symbolz string
+
+	addresses := strings.Split(post, "+")
+	// Do not symbolize the first symbol.
+	for _, address := range addresses[1:] {
+		symbolz += fmt.Sprintf("%s\t%s\n", address, address)
+	}
+	return []byte(symbolz), nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/pprof.go b/src/cmd/vendor/github.com/google/pprof/pprof.go
new file mode 100644
index 0000000..57ec28a
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/pprof.go
@@ -0,0 +1,31 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// pprof is a tool for collection, manipulation and visualization
+// of performance profiles.
+package main
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/google/pprof/driver"
+)
+
+func main() {
+	if err := driver.PProf(&driver.Options{}); err != nil {
+		fmt.Fprintf(os.Stderr, "pprof: %v\n", err)
+		os.Exit(2)
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/encode.go b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
new file mode 100644
index 0000000..c64083a
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
@@ -0,0 +1,526 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"errors"
+	"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 = make([]uint64, len(s.Location))
+		for i, loc := range s.Location {
+			s.locationIDX[i] = loc.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.commentX = nil
+	for _, c := range p.Comments {
+		p.commentX = append(p.commentX, addString(strings, c))
+	}
+
+	p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
+
+	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)
+	encodeInt64s(b, 13, p.commentX)
+	encodeInt64(b, 14, p.defaultSampleTypeX)
+}
+
+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)
+		x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer
+		pp := m.(*Profile)
+		pp.Location = append(pp.Location, x)
+		err := decodeMessage(b, x)
+		var tmp []Line
+		x.Line = append(tmp, x.Line...) // Shrink to allocated size
+		return err
+	},
+	// 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
+	},
+	// int64 drop_frames = 7
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
+	// int64 keep_frames = 8
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
+	// int64 time_nanos = 9
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
+	// int64 duration_nanos = 10
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
+	// ValueType period_type = 11
+	func(b *buffer, m message) error {
+		x := new(ValueType)
+		pp := m.(*Profile)
+		pp.PeriodType = x
+		return decodeMessage(b, x)
+	},
+	// int64 period = 12
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
+	// repeated int64 comment = 13
+	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
+	// int64 defaultSampleType = 14
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
+}
+
+// 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, len(p.Mapping))
+	mappingIds := make([]*Mapping, len(p.Mapping)+1)
+	for _, m := range p.Mapping {
+		m.File, err = getString(p.stringTable, &m.fileX, err)
+		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
+		if m.ID < uint64(len(mappingIds)) {
+			mappingIds[m.ID] = m
+		} else {
+			mappings[m.ID] = m
+		}
+	}
+
+	functions := make(map[uint64]*Function, len(p.Function))
+	functionIds := make([]*Function, len(p.Function)+1)
+	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)
+		if f.ID < uint64(len(functionIds)) {
+			functionIds[f.ID] = f
+		} else {
+			functions[f.ID] = f
+		}
+	}
+
+	locations := make(map[uint64]*Location, len(p.Location))
+	locationIds := make([]*Location, len(p.Location)+1)
+	for _, l := range p.Location {
+		if id := l.mappingIDX; id < uint64(len(mappingIds)) {
+			l.Mapping = mappingIds[id]
+		} else {
+			l.Mapping = mappings[id]
+		}
+		l.mappingIDX = 0
+		for i, ln := range l.Line {
+			if id := ln.functionIDX; id != 0 {
+				l.Line[i].functionIDX = 0
+				if id < uint64(len(functionIds)) {
+					l.Line[i].Function = functionIds[id]
+				} else {
+					l.Line[i].Function = functions[id]
+				}
+			}
+		}
+		if l.ID < uint64(len(locationIds)) {
+			locationIds[l.ID] = l
+		} else {
+			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, len(s.labelX))
+		numLabels := make(map[string][]int64, len(s.labelX))
+		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 if l.numX != 0 {
+				numLabels[key] = append(numLabels[key], l.numX)
+			}
+		}
+		if len(labels) > 0 {
+			s.Label = labels
+		}
+		if len(numLabels) > 0 {
+			s.NumLabel = numLabels
+		}
+		s.Location = make([]*Location, len(s.locationIDX))
+		for i, lid := range s.locationIDX {
+			if lid < uint64(len(locationIds)) {
+				s.Location[i] = locationIds[lid]
+			} else {
+				s.Location[i] = 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)
+	}
+
+	for _, i := range p.commentX {
+		var c string
+		c, err = getString(p.stringTable, &i, err)
+		p.Comments = append(p.Comments, c)
+	}
+
+	p.commentX = nil
+	p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
+	p.stringTable = nil
+	return err
+}
+
+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)
+	encodeInt64s(b, 2, p.Value)
+	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/vendor/github.com/google/pprof/profile/filter.go b/src/cmd/vendor/github.com/google/pprof/profile/filter.go
new file mode 100644
index 0000000..85361e8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/filter.go
@@ -0,0 +1,201 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+// Implements methods to filter samples from profiles.
+
+import "regexp"
+
+// FilterSamplesByName filters the samples in a profile and only keeps
+// samples where at least one frame matches focus but none match ignore.
+// Returns true is the corresponding regexp matched at least one sample.
+func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
+	focusOrIgnore := make(map[uint64]bool)
+	hidden := make(map[uint64]bool)
+	for _, l := range p.Location {
+		if ignore != nil && l.matchesName(ignore) {
+			im = true
+			focusOrIgnore[l.ID] = false
+		} else if focus == nil || l.matchesName(focus) {
+			fm = true
+			focusOrIgnore[l.ID] = true
+		}
+
+		if hide != nil && l.matchesName(hide) {
+			hm = true
+			l.Line = l.unmatchedLines(hide)
+			if len(l.Line) == 0 {
+				hidden[l.ID] = true
+			}
+		}
+		if show != nil {
+			hnm = true
+			l.Line = l.matchedLines(show)
+			if len(l.Line) == 0 {
+				hidden[l.ID] = true
+			}
+		}
+	}
+
+	s := make([]*Sample, 0, len(p.Sample))
+	for _, sample := range p.Sample {
+		if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
+			if len(hidden) > 0 {
+				var locs []*Location
+				for _, loc := range sample.Location {
+					if !hidden[loc.ID] {
+						locs = append(locs, loc)
+					}
+				}
+				if len(locs) == 0 {
+					// Remove sample with no locations (by not adding it to s).
+					continue
+				}
+				sample.Location = locs
+			}
+			s = append(s, sample)
+		}
+	}
+	p.Sample = s
+
+	return
+}
+
+// FilterTagsByName filters the tags in a profile and only keeps
+// tags that match show and not hide.
+func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) {
+	matchRemove := func(name string) bool {
+		matchShow := show == nil || show.MatchString(name)
+		matchHide := hide != nil && hide.MatchString(name)
+
+		if matchShow {
+			sm = true
+		}
+		if matchHide {
+			hm = true
+		}
+		return !matchShow || matchHide
+	}
+	for _, s := range p.Sample {
+		for lab := range s.Label {
+			if matchRemove(lab) {
+				delete(s.Label, lab)
+			}
+		}
+		for lab := range s.NumLabel {
+			if matchRemove(lab) {
+				delete(s.NumLabel, lab)
+			}
+		}
+	}
+	return
+}
+
+// matchesName returns whether the location matches the regular
+// expression. It checks any available function names, file names, and
+// mapping object filename.
+func (loc *Location) matchesName(re *regexp.Regexp) bool {
+	for _, ln := range loc.Line {
+		if fn := ln.Function; fn != nil {
+			if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
+				return true
+			}
+		}
+	}
+	if m := loc.Mapping; m != nil && re.MatchString(m.File) {
+		return true
+	}
+	return false
+}
+
+// unmatchedLines returns the lines in the location that do not match
+// the regular expression.
+func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
+	if m := loc.Mapping; m != nil && re.MatchString(m.File) {
+		return nil
+	}
+	var lines []Line
+	for _, ln := range loc.Line {
+		if fn := ln.Function; fn != nil {
+			if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
+				continue
+			}
+		}
+		lines = append(lines, ln)
+	}
+	return lines
+}
+
+// matchedLines returns the lines in the location that match
+// the regular expression.
+func (loc *Location) matchedLines(re *regexp.Regexp) []Line {
+	var lines []Line
+	for _, ln := range loc.Line {
+		if fn := ln.Function; fn != nil {
+			if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) {
+				continue
+			}
+		}
+		lines = append(lines, ln)
+	}
+	return lines
+}
+
+// focusedAndNotIgnored looks up a slice of ids against a map of
+// focused/ignored locations. The map only contains locations that are
+// explicitly focused or ignored. Returns whether there is at least
+// one focused location but no ignored locations.
+func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
+	var f bool
+	for _, loc := range locs {
+		if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
+			if focus {
+				// Found focused location. Must keep searching in case there
+				// is an ignored one as well.
+				f = true
+			} else {
+				// Found ignored location. Can return false right away.
+				return false
+			}
+		}
+	}
+	return f
+}
+
+// TagMatch selects tags for filtering
+type TagMatch func(s *Sample) bool
+
+// FilterSamplesByTag removes all samples from the profile, except
+// those that match focus and do not match the ignore regular
+// expression.
+func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
+	samples := make([]*Sample, 0, len(p.Sample))
+	for _, s := range p.Sample {
+		focused, ignored := true, false
+		if focus != nil {
+			focused = focus(s)
+		}
+		if ignore != nil {
+			ignored = ignore(s)
+		}
+		fm = fm || focused
+		im = im || ignored
+		if focused && !ignored {
+			samples = append(samples, s)
+		}
+	}
+	p.Sample = samples
+	return
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/index.go b/src/cmd/vendor/github.com/google/pprof/profile/index.go
new file mode 100644
index 0000000..bef1d60
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/index.go
@@ -0,0 +1,64 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// SampleIndexByName returns the appropriate index for a value of sample index.
+// If numeric, it returns the number, otherwise it looks up the text in the
+// profile sample types.
+func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) {
+	if sampleIndex == "" {
+		if dst := p.DefaultSampleType; dst != "" {
+			for i, t := range sampleTypes(p) {
+				if t == dst {
+					return i, nil
+				}
+			}
+		}
+		// By default select the last sample value
+		return len(p.SampleType) - 1, nil
+	}
+	if i, err := strconv.Atoi(sampleIndex); err == nil {
+		if i < 0 || i >= len(p.SampleType) {
+			return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1)
+		}
+		return i, nil
+	}
+
+	// Remove the inuse_ prefix to support legacy pprof options
+	// "inuse_space" and "inuse_objects" for profiles containing types
+	// "space" and "objects".
+	noInuse := strings.TrimPrefix(sampleIndex, "inuse_")
+	for i, t := range p.SampleType {
+		if t.Type == sampleIndex || t.Type == noInuse {
+			return i, nil
+		}
+	}
+
+	return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p))
+}
+
+func sampleTypes(p *Profile) []string {
+	types := make([]string, len(p.SampleType))
+	for i, t := range p.SampleType {
+		types[i] = t.Type
+	}
+	return types
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/index_test.go b/src/cmd/vendor/github.com/google/pprof/profile/index_test.go
new file mode 100644
index 0000000..f846b59
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/index_test.go
@@ -0,0 +1,114 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"testing"
+)
+
+func TestSampleIndexByName(t *testing.T) {
+	for _, c := range []struct {
+		desc              string
+		sampleTypes       []string
+		defaultSampleType string
+		index             string
+		want              int
+		wantError         bool
+	}{
+		{
+			desc:        "use last by default",
+			index:       "",
+			want:        1,
+			sampleTypes: []string{"zero", "default"},
+		},
+		{
+			desc:              "honour specified default",
+			index:             "",
+			want:              1,
+			defaultSampleType: "default",
+			sampleTypes:       []string{"zero", "default", "two"},
+		},
+		{
+			desc:              "invalid default is ignored",
+			index:             "",
+			want:              2,
+			defaultSampleType: "non-existent",
+			sampleTypes:       []string{"zero", "one", "default"},
+		},
+		{
+			desc:        "index by int",
+			index:       "0",
+			want:        0,
+			sampleTypes: []string{"zero", "one", "two"},
+		},
+		{
+			desc:              "index by int ignores default",
+			index:             "0",
+			want:              0,
+			defaultSampleType: "default",
+			sampleTypes:       []string{"zero", "default", "two"},
+		},
+		{
+			desc:        "index by name",
+			index:       "two",
+			want:        2,
+			sampleTypes: []string{"zero", "one", "two", "three"},
+		},
+		{
+			desc:              "index by name ignores default",
+			index:             "zero",
+			want:              0,
+			defaultSampleType: "default",
+			sampleTypes:       []string{"zero", "default", "two"},
+		},
+		{
+			desc:        "out of bound int causes error",
+			index:       "100",
+			wantError:   true,
+			sampleTypes: []string{"zero", "default"},
+		},
+		{
+			desc:        "unknown name causes error",
+			index:       "does not exist",
+			wantError:   true,
+			sampleTypes: []string{"zero", "default"},
+		},
+		{
+			desc:        "'inused_{x}' recognized for legacy '{x}'",
+			index:       "inuse_zero",
+			want:        0,
+			sampleTypes: []string{"zero", "default"},
+		},
+	} {
+		p := &Profile{
+			DefaultSampleType: c.defaultSampleType,
+			SampleType:        []*ValueType{},
+		}
+		for _, st := range c.sampleTypes {
+			p.SampleType = append(p.SampleType, &ValueType{Type: st, Unit: "milliseconds"})
+		}
+
+		got, err := p.SampleIndexByName(c.index)
+
+		switch {
+		case c.wantError && err == nil:
+			t.Errorf("%s: error should have been returned not index=%d, err=%v", c.desc, got, err)
+		case !c.wantError && err != nil:
+			t.Errorf("%s: unexpected got index=%d, err=%v; wanted index=%d, err=nil", c.desc, got, err, c.want)
+		case !c.wantError && got != c.want:
+			t.Errorf("%s: got index=%d, want index=%d", c.desc, got, c.want)
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_java_profile.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_java_profile.go
new file mode 100644
index 0000000..7b40f5d
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_java_profile.go
@@ -0,0 +1,312 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file implements parsers to convert java legacy profiles into
+// the profile.proto format.
+
+package profile
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+var (
+	attributeRx            = regexp.MustCompile(`([\w ]+)=([\w ]+)`)
+	javaSampleRx           = regexp.MustCompile(` *(\d+) +(\d+) +@ +([ x0-9a-f]*)`)
+	javaLocationRx         = regexp.MustCompile(`^\s*0x([[:xdigit:]]+)\s+(.*)\s*$`)
+	javaLocationFileLineRx = regexp.MustCompile(`^(.*)\s+\((.+):(-?[[:digit:]]+)\)$`)
+	javaLocationPathRx     = regexp.MustCompile(`^(.*)\s+\((.*)\)$`)
+)
+
+// javaCPUProfile returns a new Profile from 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 javaCPUProfile(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
+	var locs map[uint64]*Location
+	if b, locs, err = parseCPUSamples(b, parse, false, p); err != nil {
+		return nil, err
+	}
+
+	if err = parseJavaLocations(b, locs, p); err != nil {
+		return nil, err
+	}
+
+	// Strip out addresses for better merge.
+	if err = p.Aggregate(true, true, true, true, false); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// parseJavaProfile returns a new profile from heapz or contentionz
+// data. b is the profile bytes after the header.
+func parseJavaProfile(b []byte) (*Profile, error) {
+	h := bytes.SplitAfterN(b, []byte("\n"), 2)
+	if len(h) < 2 {
+		return nil, errUnrecognized
+	}
+
+	p := &Profile{
+		PeriodType: &ValueType{},
+	}
+	header := string(bytes.TrimSpace(h[0]))
+
+	var err error
+	var pType string
+	switch header {
+	case "--- heapz 1 ---":
+		pType = "heap"
+	case "--- contentionz 1 ---":
+		pType = "contention"
+	default:
+		return nil, errUnrecognized
+	}
+
+	if b, err = parseJavaHeader(pType, h[1], p); err != nil {
+		return nil, err
+	}
+	var locs map[uint64]*Location
+	if b, locs, err = parseJavaSamples(pType, b, p); err != nil {
+		return nil, err
+	}
+	if err = parseJavaLocations(b, locs, p); err != nil {
+		return nil, err
+	}
+
+	// Strip out addresses for better merge.
+	if err = p.Aggregate(true, true, true, true, false); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// parseJavaHeader parses the attribute section on a java profile and
+// populates a profile. Returns the remainder of the buffer after all
+// attributes.
+func parseJavaHeader(pType string, b []byte, p *Profile) ([]byte, error) {
+	nextNewLine := bytes.IndexByte(b, byte('\n'))
+	for nextNewLine != -1 {
+		line := string(bytes.TrimSpace(b[0:nextNewLine]))
+		if line != "" {
+			h := attributeRx.FindStringSubmatch(line)
+			if h == nil {
+				// Not a valid attribute, exit.
+				return b, nil
+			}
+
+			attribute, value := strings.TrimSpace(h[1]), strings.TrimSpace(h[2])
+			var err error
+			switch pType + "/" + attribute {
+			case "heap/format", "cpu/format", "contention/format":
+				if value != "java" {
+					return nil, errUnrecognized
+				}
+			case "heap/resolution":
+				p.SampleType = []*ValueType{
+					{Type: "inuse_objects", Unit: "count"},
+					{Type: "inuse_space", Unit: value},
+				}
+			case "contention/resolution":
+				p.SampleType = []*ValueType{
+					{Type: "contentions", Unit: value},
+					{Type: "delay", Unit: value},
+				}
+			case "contention/sampling period":
+				p.PeriodType = &ValueType{
+					Type: "contentions", Unit: "count",
+				}
+				if p.Period, err = strconv.ParseInt(value, 0, 64); err != nil {
+					return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
+				}
+			case "contention/ms since reset":
+				millis, err := strconv.ParseInt(value, 0, 64)
+				if err != nil {
+					return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
+				}
+				p.DurationNanos = millis * 1000 * 1000
+			default:
+				return nil, errUnrecognized
+			}
+		}
+		// Grab next line.
+		b = b[nextNewLine+1:]
+		nextNewLine = bytes.IndexByte(b, byte('\n'))
+	}
+	return b, nil
+}
+
+// parseJavaSamples parses the samples from a java profile and
+// populates the Samples in a profile. Returns the remainder of the
+// buffer after the samples.
+func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*Location, error) {
+	nextNewLine := bytes.IndexByte(b, byte('\n'))
+	locs := make(map[uint64]*Location)
+	for nextNewLine != -1 {
+		line := string(bytes.TrimSpace(b[0:nextNewLine]))
+		if line != "" {
+			sample := javaSampleRx.FindStringSubmatch(line)
+			if sample == nil {
+				// Not a valid sample, exit.
+				return b, locs, nil
+			}
+
+			// Java profiles have data/fields inverted compared to other
+			// profile types.
+			var err error
+			value1, value2, value3 := sample[2], sample[1], sample[3]
+			addrs, err := parseHexAddresses(value3)
+			if err != nil {
+				return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
+			}
+
+			var sloc []*Location
+			for _, addr := range addrs {
+				loc := locs[addr]
+				if locs[addr] == nil {
+					loc = &Location{
+						Address: addr,
+					}
+					p.Location = append(p.Location, loc)
+					locs[addr] = loc
+				}
+				sloc = append(sloc, loc)
+			}
+			s := &Sample{
+				Value:    make([]int64, 2),
+				Location: sloc,
+			}
+
+			if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil {
+				return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
+			}
+			if s.Value[1], err = strconv.ParseInt(value2, 0, 64); err != nil {
+				return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
+			}
+
+			switch pType {
+			case "heap":
+				const javaHeapzSamplingRate = 524288 // 512K
+				s.NumLabel = map[string][]int64{"bytes": []int64{s.Value[1] / s.Value[0]}}
+				s.Value[0], s.Value[1] = scaleHeapSample(s.Value[0], s.Value[1], javaHeapzSamplingRate)
+			case "contention":
+				if period := p.Period; period != 0 {
+					s.Value[0] = s.Value[0] * p.Period
+					s.Value[1] = s.Value[1] * p.Period
+				}
+			}
+			p.Sample = append(p.Sample, s)
+		}
+		// Grab next line.
+		b = b[nextNewLine+1:]
+		nextNewLine = bytes.IndexByte(b, byte('\n'))
+	}
+	return b, locs, nil
+}
+
+// parseJavaLocations parses the location information in a java
+// profile and populates the Locations in a profile. It uses the
+// location addresses from the profile as both the ID of each
+// location.
+func parseJavaLocations(b []byte, locs map[uint64]*Location, p *Profile) error {
+	r := bytes.NewBuffer(b)
+	fns := make(map[string]*Function)
+	for {
+		line, err := r.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return err
+			}
+			if line == "" {
+				break
+			}
+		}
+
+		if line = strings.TrimSpace(line); line == "" {
+			continue
+		}
+
+		jloc := javaLocationRx.FindStringSubmatch(line)
+		if len(jloc) != 3 {
+			continue
+		}
+		addr, err := strconv.ParseUint(jloc[1], 16, 64)
+		if err != nil {
+			return fmt.Errorf("parsing sample %s: %v", line, err)
+		}
+		loc := locs[addr]
+		if loc == nil {
+			// Unused/unseen
+			continue
+		}
+		var lineFunc, lineFile string
+		var lineNo int64
+
+		if fileLine := javaLocationFileLineRx.FindStringSubmatch(jloc[2]); len(fileLine) == 4 {
+			// Found a line of the form: "function (file:line)"
+			lineFunc, lineFile = fileLine[1], fileLine[2]
+			if n, err := strconv.ParseInt(fileLine[3], 10, 64); err == nil && n > 0 {
+				lineNo = n
+			}
+		} else if filePath := javaLocationPathRx.FindStringSubmatch(jloc[2]); len(filePath) == 3 {
+			// If there's not a file:line, it's a shared library path.
+			// The path isn't interesting, so just give the .so.
+			lineFunc, lineFile = filePath[1], filepath.Base(filePath[2])
+		} else if strings.Contains(jloc[2], "generated stub/JIT") {
+			lineFunc = "STUB"
+		} else {
+			// Treat whole line as the function name. This is used by the
+			// java agent for internal states such as "GC" or "VM".
+			lineFunc = jloc[2]
+		}
+		fn := fns[lineFunc]
+
+		if fn == nil {
+			fn = &Function{
+				Name:       lineFunc,
+				SystemName: lineFunc,
+				Filename:   lineFile,
+			}
+			fns[lineFunc] = fn
+			p.Function = append(p.Function, fn)
+		}
+		loc.Line = []Line{
+			{
+				Function: fn,
+				Line:     lineNo,
+			},
+		}
+		loc.Address = 0
+	}
+
+	p.remapLocationIDs()
+	p.remapFunctionIDs()
+	p.remapMappingIDs()
+
+	return nil
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go
new file mode 100644
index 0000000..096890d
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go
@@ -0,0 +1,1224 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// 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(\S+) profile: total \d+\z`)
+	countRE      = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\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: ---`)
+
+	// Regular expressions to parse process mappings. Support the format used by Linux /proc/.../maps and other tools.
+	// Recommended format:
+	// Start   End     object file name     offset(optional)   linker build id
+	// 0x40000-0x80000 /path/to/binary      (@FF00)            abc123456
+	spaceDigits = `\s+[[:digit:]]+`
+	hexPair     = `\s+[[:xdigit:]]+:[[:xdigit:]]+`
+	oSpace      = `\s*`
+	// Capturing expressions.
+	cHex           = `(?:0x)?([[:xdigit:]]+)`
+	cHexRange      = `\s*` + cHex + `[\s-]?` + oSpace + cHex + `:?`
+	cSpaceString   = `(?:\s+(\S+))?`
+	cSpaceHex      = `(?:\s+([[:xdigit:]]+))?`
+	cSpaceAtOffset = `(?:\s+\(@([[:xdigit:]]+)\))?`
+	cPerm          = `(?:\s+([-rwxp]+))?`
+
+	procMapsRE  = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceHex + hexPair + spaceDigits + cSpaceString)
+	briefMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceString + cSpaceAtOffset + cSpaceHex)
+
+	// Regular expression to parse log data, of the form:
+	// ... file:line] msg...
+	logInfoRE = regexp.MustCompile(`^[^\[\]]+:[0-9]+]\s`)
+)
+
+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) {
+	s := bufio.NewScanner(bytes.NewBuffer(b))
+	// Skip comments at the beginning of the file.
+	for s.Scan() && isSpaceOrComment(s.Text()) {
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+	m := countStartRE.FindStringSubmatch(s.Text())
+	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 s.Scan() {
+		line := s.Text()
+		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 top of 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 := s.Err(); err != nil {
+		return nil, err
+	}
+
+	if err := parseAdditionalSections(s, 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() {
+	// Some profile handlers will incorrectly set regions for the main
+	// executable if its section is remapped. Fix them through heuristics.
+
+	if len(p.Mapping) > 0 {
+		// 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.
+	if len(p.Mapping) > 0 {
+		const expectedStart = 0x400000
+		if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
+			m.Start = expectedStart
+			m.Offset = 0
+		}
+	}
+
+	// Associate each location with an address to the corresponding
+	// mapping. Create fake mapping if a suitable one isn't found.
+	var fake *Mapping
+nextLocation:
+	for _, l := range p.Location {
+		a := l.Address
+		if l.Mapping != nil || a == 0 {
+			continue
+		}
+		for _, m := range p.Mapping {
+			if m.Start <= a && a < m.Limit {
+				l.Mapping = m
+				continue nextLocation
+			}
+		}
+		// Work around legacy handlers failing to encode the first
+		// part of mappings split into adjacent ranges.
+		for _, m := range p.Mapping {
+			if m.Offset != 0 && m.Start-m.Offset <= a && a < m.Start {
+				m.Start -= m.Offset
+				m.Offset = 0
+				l.Mapping = m
+				continue nextLocation
+			}
+		}
+		// If there is still no mapping, create a fake one.
+		// This is important for the Go legacy handler, which produced
+		// no mappings.
+		if fake == nil {
+			fake = &Mapping{
+				ID:    1,
+				Limit: ^uint64(0),
+			}
+			p.Mapping = append(p.Mapping, fake)
+		}
+		l.Mapping = fake
+	}
+
+	// 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:]
+}
+
+// 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)
+		}
+		if tmp != nil && n1 == 0 && n2 == 3 && n3 == 1 && n4 > 0 && n5 == 0 {
+			b = tmp
+			return javaCPUProfile(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 *most* 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.
+
+	// Remove up to two frames.
+	maxiter := 2
+	// Allow one different sample for this many samples with the same
+	// second-to-last frame.
+	similarSamples := 32
+	margin := len(p.Sample) / similarSamples
+
+	for iter := 0; iter < maxiter; iter++ {
+		addr1 := make(map[uint64]int)
+		for _, s := range p.Sample {
+			if len(s.Location) > 1 {
+				a := s.Location[1].Address
+				addr1[a] = addr1[a] + 1
+			}
+		}
+
+		for id1, count := range addr1 {
+			if count >= len(p.Sample)-margin {
+				// Found uninteresting frame, strip it out from all samples
+				for _, s := range p.Sample {
+					if len(s.Location) > 1 && s.Location[1].Address == id1 {
+						s.Location = append(s.Location[:1], s.Location[2:]...)
+					}
+				}
+				break
+			}
+		}
+	}
+
+	if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
+		return nil, err
+	}
+
+	cleanupDuplicateLocations(p)
+	return p, nil
+}
+
+func cleanupDuplicateLocations(p *Profile) {
+	// The profile handler may duplicate the leaf frame, because it gets
+	// its address both from stack unwinding and from the signal
+	// context. Detect this and delete the duplicate, which has been
+	// adjusted by -1. The leaf address should not be adjusted as it is
+	// not a call.
+	for _, s := range p.Sample {
+		if len(s.Location) > 1 && s.Location[0].Address == s.Location[1].Address+1 {
+			s.Location = append(s.Location[:1], s.Location[2:]...)
+		}
+	}
+}
+
+// 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) {
+	s := bufio.NewScanner(bytes.NewBuffer(b))
+	if !s.Scan() {
+		if err := s.Err(); err != nil {
+			return nil, err
+		}
+		return nil, errUnrecognized
+	}
+	p = &Profile{}
+
+	sampling := ""
+	hasAlloc := false
+
+	line := s.Text()
+	p.PeriodType = &ValueType{Type: "space", Unit: "bytes"}
+	if header := heapHeaderRE.FindStringSubmatch(line); header != nil {
+		sampling, p.Period, hasAlloc, err = parseHeapHeader(line)
+		if err != nil {
+			return nil, err
+		}
+	} else if header = growthHeaderRE.FindStringSubmatch(line); header != nil {
+		p.Period = 1
+	} else if header = fragmentationHeaderRE.FindStringSubmatch(line); header != nil {
+		p.Period = 1
+	} else {
+		return nil, errUnrecognized
+	}
+
+	if hasAlloc {
+		// Put alloc before inuse so that default pprof selection
+		// will prefer inuse_space.
+		p.SampleType = []*ValueType{
+			{Type: "alloc_objects", Unit: "count"},
+			{Type: "alloc_space", Unit: "bytes"},
+			{Type: "inuse_objects", Unit: "count"},
+			{Type: "inuse_space", Unit: "bytes"},
+		}
+	} else {
+		p.SampleType = []*ValueType{
+			{Type: "objects", Unit: "count"},
+			{Type: "space", Unit: "bytes"},
+		}
+	}
+
+	locs := make(map[uint64]*Location)
+	for s.Scan() {
+		line := strings.TrimSpace(s.Text())
+
+		if isSpaceOrComment(line) {
+			continue
+		}
+
+		if isMemoryMapSentinel(line) {
+			break
+		}
+
+		value, blocksize, addrs, err := parseHeapSample(line, p.Period, sampling, hasAlloc)
+		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 := s.Err(); err != nil {
+		return nil, err
+	}
+	if err := parseAdditionalSections(s, p); err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+func parseHeapHeader(line string) (sampling string, period int64, hasAlloc bool, err error) {
+	header := heapHeaderRE.FindStringSubmatch(line)
+	if header == nil {
+		return "", 0, false, errUnrecognized
+	}
+
+	if len(header[6]) > 0 {
+		if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
+			return "", 0, false, errUnrecognized
+		}
+	}
+
+	if (header[3] != header[1] && header[3] != "0") || (header[4] != header[2] && header[4] != "0") {
+		hasAlloc = true
+	}
+
+	switch header[5] {
+	case "heapz_v2", "heap_v2":
+		return "v2", period, hasAlloc, nil
+	case "heapprofile":
+		return "", 1, hasAlloc, nil
+	case "heap":
+		return "v2", period / 2, hasAlloc, nil
+	default:
+		return "", 0, false, errUnrecognized
+	}
+}
+
+// parseHeapSample parses a single row from a heap profile into a new Sample.
+func parseHeapSample(line string, rate int64, sampling string, includeAlloc bool) (value []int64, blocksize int64, addrs []uint64, err error) {
+	sampleData := heapSampleRE.FindStringSubmatch(line)
+	if len(sampleData) != 6 {
+		return nil, 0, nil, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
+	}
+
+	// This is a local-scoped helper function to avoid needing to pass
+	// around rate, sampling and many return parameters.
+	addValues := func(countString, sizeString string, label string) error {
+		count, err := strconv.ParseInt(countString, 10, 64)
+		if err != nil {
+			return fmt.Errorf("malformed sample: %s: %v", line, err)
+		}
+		size, err := strconv.ParseInt(sizeString, 10, 64)
+		if err != nil {
+			return fmt.Errorf("malformed sample: %s: %v", line, err)
+		}
+		if count == 0 && size != 0 {
+			return fmt.Errorf("%s count was 0 but %s bytes was %d", label, label, size)
+		}
+		if count != 0 {
+			blocksize = size / count
+			if sampling == "v2" {
+				count, size = scaleHeapSample(count, size, rate)
+			}
+		}
+		value = append(value, count, size)
+		return nil
+	}
+
+	if includeAlloc {
+		if err := addValues(sampleData[3], sampleData[4], "allocation"); err != nil {
+			return nil, 0, nil, err
+		}
+	}
+
+	if err := addValues(sampleData[1], sampleData[2], "inuse"); err != nil {
+		return nil, 0, nil, err
+	}
+
+	addrs, err = parseHexAddresses(sampleData[5])
+	if err != nil {
+		return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+
+	return value, blocksize, addrs, nil
+}
+
+// parseHexAddresses extracts hex numbers from a string, attempts to convert
+// each to an unsigned 64-bit number and returns the resulting numbers as a
+// slice, or an error if the string contains hex numbers which are too large to
+// handle (which means a malformed profile).
+func parseHexAddresses(s string) ([]uint64, error) {
+	hexStrings := hexNumberRE.FindAllString(s, -1)
+	var addrs []uint64
+	for _, s := range hexStrings {
+		if addr, err := strconv.ParseUint(s, 0, 64); err == nil {
+			addrs = append(addrs, addr)
+		} else {
+			return nil, fmt.Errorf("failed to parse as hex 64-bit number: %s", s)
+		}
+	}
+	return addrs, nil
+}
+
+// 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 mutex or contention profile. There are 2 cases:
+// "--- contentionz " for legacy C++ profiles (and backwards compatibility)
+// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime.
+func parseContention(b []byte) (*Profile, error) {
+	s := bufio.NewScanner(bytes.NewBuffer(b))
+	if !s.Scan() {
+		if err := s.Err(); err != nil {
+			return nil, err
+		}
+		return nil, errUnrecognized
+	}
+
+	switch l := s.Text(); {
+	case strings.HasPrefix(l, "--- contentionz "):
+	case strings.HasPrefix(l, "--- mutex:"):
+	case strings.HasPrefix(l, "--- contention:"):
+	default:
+		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 s.Scan() {
+		line := s.Text()
+		if line = strings.TrimSpace(line); isSpaceOrComment(line) {
+			continue
+		}
+		if strings.HasPrefix(line, "---") {
+			break
+		}
+		attr := strings.SplitN(line, 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
+		}
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	locs := make(map[uint64]*Location)
+	for {
+		line := strings.TrimSpace(s.Text())
+		if strings.HasPrefix(line, "---") {
+			break
+		}
+		if !isSpaceOrComment(line) {
+			value, addrs, err := parseContentionSample(line, 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 !s.Scan() {
+			break
+		}
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	if err := parseAdditionalSections(s, 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 nil, nil, errUnrecognized
+	}
+
+	v1, err := strconv.ParseInt(sampleData[1], 10, 64)
+	if err != nil {
+		return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+	v2, err := strconv.ParseInt(sampleData[2], 10, 64)
+	if err != nil {
+		return nil, nil, 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, err = parseHexAddresses(sampleData[3])
+	if err != nil {
+		return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+
+	return value, addrs, nil
+}
+
+// parseThread parses a Threadz profile and returns a new Profile.
+func parseThread(b []byte) (*Profile, error) {
+	s := bufio.NewScanner(bytes.NewBuffer(b))
+	// Skip past comments and empty lines seeking a real header.
+	for s.Scan() && isSpaceOrComment(s.Text()) {
+	}
+
+	line := s.Text()
+	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
+		// Advance over initial comments until first stack trace.
+		for s.Scan() {
+			if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") {
+				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 !isMemoryMapSentinel(line) {
+		if strings.HasPrefix(line, "---- no stack trace for") {
+			line = ""
+			break
+		}
+		if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+			return nil, errUnrecognized
+		}
+
+		var addrs []uint64
+		var err error
+		line, addrs, err = parseThreadSample(s)
+		if err != nil {
+			return nil, err
+		}
+		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(s, p); err != nil {
+		return nil, err
+	}
+
+	cleanupDuplicateLocations(p)
+	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(s *bufio.Scanner) (nextl string, addrs []uint64, err error) {
+	var line string
+	sameAsPrevious := false
+	for s.Scan() {
+		line = strings.TrimSpace(s.Text())
+		if line == "" {
+			continue
+		}
+
+		if strings.HasPrefix(line, "---") {
+			break
+		}
+		if strings.Contains(line, "same as previous thread") {
+			sameAsPrevious = true
+			continue
+		}
+
+		curAddrs, err := parseHexAddresses(line)
+		if err != nil {
+			return "", nil, fmt.Errorf("malformed sample: %s: %v", line, err)
+		}
+		addrs = append(addrs, curAddrs...)
+	}
+	if err := s.Err(); err != nil {
+		return "", nil, err
+	}
+	if sameAsPrevious {
+		return line, nil, nil
+	}
+	return line, addrs, nil
+}
+
+// parseAdditionalSections parses any additional sections in the
+// profile, ignoring any unrecognized sections.
+func parseAdditionalSections(s *bufio.Scanner, p *Profile) error {
+	for !isMemoryMapSentinel(s.Text()) && s.Scan() {
+	}
+	if err := s.Err(); err != nil {
+		return err
+	}
+	return p.ParseMemoryMapFromScanner(s)
+}
+
+// ParseProcMaps parses a memory map in the format of /proc/self/maps.
+// ParseMemoryMap should be called after setting on a profile to
+// associate locations to the corresponding mapping based on their
+// address.
+func ParseProcMaps(rd io.Reader) ([]*Mapping, error) {
+	s := bufio.NewScanner(rd)
+	return parseProcMapsFromScanner(s)
+}
+
+func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) {
+	var mapping []*Mapping
+
+	var attrs []string
+	const delimiter = "="
+	r := strings.NewReplacer()
+	for s.Scan() {
+		line := r.Replace(removeLoggingInfo(s.Text()))
+		m, err := parseMappingEntry(line)
+		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(line, 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 nil, err
+		}
+		if m == nil {
+			continue
+		}
+		mapping = append(mapping, m)
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+	return mapping, nil
+}
+
+// removeLoggingInfo detects and removes log prefix entries generated
+// by the glog package. If no logging prefix is detected, the string
+// is returned unmodified.
+func removeLoggingInfo(line string) string {
+	if match := logInfoRE.FindStringIndex(line); match != nil {
+		return line[match[1]:]
+	}
+	return line
+}
+
+// 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 {
+	return p.ParseMemoryMapFromScanner(bufio.NewScanner(rd))
+}
+
+// ParseMemoryMapFromScanner parses a memory map in the format of
+// /proc/self/maps or a variety of legacy format, and overrides the
+// mappings in the current profile.  It renumbers the samples and
+// locations in the profile correspondingly.
+func (p *Profile) ParseMemoryMapFromScanner(s *bufio.Scanner) error {
+	mapping, err := parseProcMapsFromScanner(s)
+	if err != nil {
+		return err
+	}
+	p.Mapping = append(p.Mapping, mapping...)
+	p.massageMappings()
+	p.remapLocationIDs()
+	p.remapFunctionIDs()
+	p.remapMappingIDs()
+	return nil
+}
+
+func parseMappingEntry(l string) (*Mapping, error) {
+	var start, end, perm, file, offset, buildID string
+	if me := procMapsRE.FindStringSubmatch(l); len(me) == 6 {
+		start, end, perm, offset, file = me[1], me[2], me[3], me[4], me[5]
+	} else if me := briefMapsRE.FindStringSubmatch(l); len(me) == 7 {
+		start, end, perm, file, offset, buildID = me[1], me[2], me[3], me[4], me[5], me[6]
+	} else {
+		return nil, errUnrecognized
+	}
+
+	var err error
+	mapping := &Mapping{
+		File:    file,
+		BuildID: buildID,
+	}
+	if perm != "" && !strings.Contains(perm, "x") {
+		// Skip non-executable entries.
+		return nil, nil
+	}
+	if mapping.Start, err = strconv.ParseUint(start, 16, 64); err != nil {
+		return nil, errUnrecognized
+	}
+	if mapping.Limit, err = strconv.ParseUint(end, 16, 64); err != nil {
+		return nil, errUnrecognized
+	}
+	if offset != "" {
+		if mapping.Offset, err = strconv.ParseUint(offset, 16, 64); err != nil {
+			return nil, errUnrecognized
+		}
+	}
+	return mapping, nil
+}
+
+var memoryMapSentinels = []string{
+	"--- Memory map: ---",
+	"MAPPED_LIBRARIES:",
+}
+
+// isMemoryMapSentinel returns true if the string contains one of the
+// known sentinels for memory map information.
+func isMemoryMapSentinel(line string) bool {
+	for _, s := range memoryMapSentinels {
+		if strings.Contains(line, s) {
+			return true
+		}
+	}
+	return false
+}
+
+func (p *Profile) addLegacyFrameInfo() {
+	switch {
+	case isProfileType(p, heapzSampleTypes):
+		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
+	{"objects", "space"},
+	{"inuse_objects", "inuse_space"},
+	{"alloc_objects", "alloc_space"},
+}
+var contentionzSampleTypes = [][]string{
+	{"contentions", "delay"},
+}
+
+func isProfileType(p *Profile, types [][]string) bool {
+	st := p.SampleType
+nextType:
+	for _, t := range types {
+		if len(st) != len(t) {
+			continue
+		}
+
+		for i := range st {
+			if st[i].Type != t[i] {
+				continue nextType
+			}
+		}
+		return true
+	}
+	return false
+}
+
+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`,
+	`runtime\.reflectcall`,
+	`runtime\.call[0-9]*`,
+}, `|`)
+
+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.*`,
+	`(base::Mutex::)?AwaitCommon.*`,
+	`(base::Mutex::)?Unlock.*`,
+	`(base::Mutex::)?UnlockSlow.*`,
+	`(base::Mutex::)?ReaderUnlock.*`,
+	`(base::MutexLock::)?~MutexLock.*`,
+	`(Mutex::)?AwaitCommon.*`,
+	`(Mutex::)?Unlock.*`,
+	`(Mutex::)?UnlockSlow.*`,
+	`(Mutex::)?ReaderUnlock.*`,
+	`(MutexLock::)?~MutexLock.*`,
+	`(SpinLock::)?Unlock.*`,
+	`(SpinLock::)?SlowUnlock.*`,
+	`(SpinLockHolder::)?~SpinLockHolder.*`,
+}, `|`)
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go
new file mode 100644
index 0000000..5f63453
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go
@@ -0,0 +1,319 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func TestLegacyProfileType(t *testing.T) {
+	type testcase struct {
+		sampleTypes []string
+		typeSet     [][]string
+		want        bool
+		setName     string
+	}
+
+	heap := heapzSampleTypes
+	cont := contentionzSampleTypes
+	testcases := []testcase{
+		// True cases
+		{[]string{"allocations", "size"}, heap, true, "heapzSampleTypes"},
+		{[]string{"objects", "space"}, heap, true, "heapzSampleTypes"},
+		{[]string{"inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"},
+		{[]string{"alloc_objects", "alloc_space"}, heap, true, "heapzSampleTypes"},
+		{[]string{"contentions", "delay"}, cont, true, "contentionzSampleTypes"},
+		// False cases
+		{[]string{"objects"}, heap, false, "heapzSampleTypes"},
+		{[]string{"objects", "unknown"}, heap, false, "heapzSampleTypes"},
+		{[]string{"contentions", "delay"}, heap, false, "heapzSampleTypes"},
+		{[]string{"samples", "cpu"}, heap, false, "heapzSampleTypes"},
+		{[]string{"samples", "cpu"}, cont, false, "contentionzSampleTypes"},
+	}
+
+	for _, tc := range testcases {
+		p := profileOfType(tc.sampleTypes)
+		if got := isProfileType(p, tc.typeSet); got != tc.want {
+			t.Error("isProfileType({"+strings.Join(tc.sampleTypes, ",")+"},", tc.setName, "), got", got, "want", tc.want)
+		}
+	}
+}
+
+func TestCpuParse(t *testing.T) {
+	// profileString is a legacy encoded profile, represnted by words separated by ":"
+	// Each sample has the form value : N : stack1..stackN
+	// EOF is represented as "0:1:0"
+	profileString := "1:3:100:999:100:"                                      // sample with bogus 999 and duplicate leaf
+	profileString += "1:5:200:999:200:501:502:"                              // sample with bogus 999 and duplicate leaf
+	profileString += "1:12:300:999:300:601:602:603:604:605:606:607:608:609:" // sample with bogus 999 and duplicate leaf
+	profileString += "0:1:0000"                                              // EOF -- must use 4 bytes for the final zero
+
+	p, err := cpuProfile([]byte(profileString), 1, parseString)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := checkTestSample(p, []uint64{100}); err != nil {
+		t.Error(err)
+	}
+	if err := checkTestSample(p, []uint64{200, 500, 501}); err != nil {
+		t.Error(err)
+	}
+	if err := checkTestSample(p, []uint64{300, 600, 601, 602, 603, 604, 605, 606, 607, 608}); err != nil {
+		t.Error(err)
+	}
+}
+
+func parseString(b []byte) (uint64, []byte) {
+	slices := bytes.SplitN(b, []byte(":"), 2)
+	var value, remainder []byte
+	if len(slices) > 0 {
+		value = slices[0]
+	}
+	if len(slices) > 1 {
+		remainder = slices[1]
+	}
+	v, _ := strconv.ParseUint(string(value), 10, 64)
+	return v, remainder
+}
+
+func checkTestSample(p *Profile, want []uint64) error {
+	for _, s := range p.Sample {
+		got := []uint64{}
+		for _, l := range s.Location {
+			got = append(got, l.Address)
+		}
+		if reflect.DeepEqual(got, want) {
+			return nil
+		}
+	}
+	return fmt.Errorf("Could not find sample : %v", want)
+}
+
+// profileOfType creates an empty profile with only sample types set,
+// for testing purposes only.
+func profileOfType(sampleTypes []string) *Profile {
+	p := new(Profile)
+	p.SampleType = make([]*ValueType, len(sampleTypes))
+	for i, t := range sampleTypes {
+		p.SampleType[i] = new(ValueType)
+		p.SampleType[i].Type = t
+	}
+	return p
+}
+
+func TestParseMappingEntry(t *testing.T) {
+	for _, test := range []*struct {
+		entry string
+		want  *Mapping
+	}{
+		{
+			entry: "00400000-02e00000 r-xp 00000000 00:00 0",
+			want: &Mapping{
+				Start: 0x400000,
+				Limit: 0x2e00000,
+			},
+		},
+		{
+			entry: "02e00000-02e8a000 r-xp 02a00000 00:00 15953927    /foo/bin",
+			want: &Mapping{
+				Start:  0x2e00000,
+				Limit:  0x2e8a000,
+				Offset: 0x2a00000,
+				File:   "/foo/bin",
+			},
+		},
+		{
+			entry: "02e00000-02e8a000 r-xp 000000 00:00 15953927    [vdso]",
+			want: &Mapping{
+				Start: 0x2e00000,
+				Limit: 0x2e8a000,
+				File:  "[vdso]",
+			},
+		},
+		{
+			entry: "  02e00000-02e8a000: /foo/bin (@2a00000)",
+			want: &Mapping{
+				Start:  0x2e00000,
+				Limit:  0x2e8a000,
+				Offset: 0x2a00000,
+				File:   "/foo/bin",
+			},
+		},
+		{
+			entry: "  02e00000-02e8a000: /foo/bin (deleted)",
+			want: &Mapping{
+				Start: 0x2e00000,
+				Limit: 0x2e8a000,
+				File:  "/foo/bin",
+			},
+		},
+		{
+			entry: "  02e00000-02e8a000: /foo/bin",
+			want: &Mapping{
+				Start: 0x2e00000,
+				Limit: 0x2e8a000,
+				File:  "/foo/bin",
+			},
+		},
+		{
+			entry: "  02e00000-02e8a000: [vdso]",
+			want: &Mapping{
+				Start: 0x2e00000,
+				Limit: 0x2e8a000,
+				File:  "[vdso]",
+			},
+		},
+		{entry: "0xff6810563000 0xff6810565000 r-xp abc_exe 87c4d547f895cfd6a370e08dc5c5ee7bd4199d5b",
+			want: &Mapping{
+				Start:   0xff6810563000,
+				Limit:   0xff6810565000,
+				File:    "abc_exe",
+				BuildID: "87c4d547f895cfd6a370e08dc5c5ee7bd4199d5b",
+			},
+		},
+		{entry: "7f5e5435e000-7f5e5455e000 --xp 00002000 00:00 1531        myprogram",
+			want: &Mapping{
+				Start:  0x7f5e5435e000,
+				Limit:  0x7f5e5455e000,
+				Offset: 0x2000,
+				File:   "myprogram",
+			},
+		},
+		{entry: "7f7472710000-7f7472722000 r-xp 00000000 fc:00 790190      /usr/lib/libfantastic-1.2.so",
+			want: &Mapping{
+				Start: 0x7f7472710000,
+				Limit: 0x7f7472722000,
+				File:  "/usr/lib/libfantastic-1.2.so",
+			},
+		},
+		{entry: "7f47a542f000-7f47a5447000: /lib/libpthread-2.15.so",
+			want: &Mapping{
+				Start: 0x7f47a542f000,
+				Limit: 0x7f47a5447000,
+				File:  "/lib/libpthread-2.15.so",
+			},
+		},
+		{entry: "0x40000-0x80000 /path/to/binary      (@FF00)            abc123456",
+			want: &Mapping{
+				Start:   0x40000,
+				Limit:   0x80000,
+				File:    "/path/to/binary",
+				Offset:  0xFF00,
+				BuildID: "abc123456",
+			},
+		},
+		{entry: "W1220 15:07:15.201776    8272 logger.cc:12033] --- Memory map: ---\n" +
+			"0x40000-0x80000 /path/to/binary      (@FF00)            abc123456",
+			want: &Mapping{
+				Start:   0x40000,
+				Limit:   0x80000,
+				File:    "/path/to/binary",
+				Offset:  0xFF00,
+				BuildID: "abc123456",
+			},
+		},
+		{entry: "W1220 15:07:15.201776    8272 logger.cc:12033] --- Memory map: ---\n" +
+			"W1220 15:07:15.202776    8272 logger.cc:12036]   0x40000-0x80000 /path/to/binary      (@FF00)            abc123456",
+			want: &Mapping{
+				Start:   0x40000,
+				Limit:   0x80000,
+				File:    "/path/to/binary",
+				Offset:  0xFF00,
+				BuildID: "abc123456",
+			},
+		},
+		{entry: "7f5e5435e000-7f5e5455e000 ---p 00002000 00:00 1531        myprogram",
+			want: nil,
+		},
+	} {
+		got, err := ParseProcMaps(strings.NewReader(test.entry))
+		if err != nil {
+			t.Errorf("%s: %v", test.entry, err)
+			continue
+		}
+		if test.want == nil {
+			if got, want := len(got), 0; got != want {
+				t.Errorf("%s: got %d mappings, want %d", test.entry, got, want)
+			}
+			continue
+		}
+		if got, want := len(got), 1; got != want {
+			t.Errorf("%s: got %d mappings, want %d", test.entry, got, want)
+			continue
+		}
+		if !reflect.DeepEqual(test.want, got[0]) {
+			t.Errorf("%s want=%v got=%v", test.entry, test.want, got[0])
+		}
+	}
+}
+
+func TestParseThreadProfileWithInvalidAddress(t *testing.T) {
+	profile := `
+--- threadz 1 ---
+
+--- Thread 7eff063d9940 (name: main/25376) stack: ---
+  PC: 0x40b688 0x4d5f51 0x40be31 0x473add693e639c6f0
+--- Memory map: ---
+  00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main.unstripped
+	`
+	wantErr := "failed to parse as hex 64-bit number: 0x473add693e639c6f0"
+	if _, gotErr := parseThread([]byte(profile)); !strings.Contains(gotErr.Error(), wantErr) {
+		t.Errorf("parseThread(): got error %q, want error containing %q", gotErr, wantErr)
+	}
+}
+
+func TestParseGoCount(t *testing.T) {
+	for _, test := range []struct {
+		in  string
+		typ string
+	}{
+		{
+			in: `# ignored comment
+
+threadcreate profile: total 123
+`,
+			typ: "threadcreate",
+		},
+		{
+			in: `
+# ignored comment
+goroutine profile: total 123456
+`,
+			typ: "goroutine",
+		},
+		{
+			in: `
+sub/dir-ect_o.ry profile: total 999
+`,
+			typ: "sub/dir-ect_o.ry",
+		},
+	} {
+		t.Run(test.typ, func(t *testing.T) {
+			p, err := parseGoCount([]byte(test.in))
+			if err != nil {
+				t.Fatalf("parseGoCount(%q) = %v", test.in, err)
+			}
+			if typ := p.PeriodType.Type; typ != test.typ {
+				t.Fatalf("parseGoCount(%q).PeriodType.Type = %q want %q", test.in, typ, test.typ)
+			}
+		})
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/merge.go b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
new file mode 100644
index 0000000..2e9c2cd
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
@@ -0,0 +1,443 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"fmt"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// Compact performs garbage collection on a profile to remove any
+// unreferenced fields. This is useful to reduce the size of a profile
+// after samples or locations have been removed.
+func (p *Profile) Compact() *Profile {
+	p, _ = Merge([]*Profile{p})
+	return p
+}
+
+// Merge merges all the profiles in profs into a single Profile.
+// Returns a new profile independent of the input profiles. The merged
+// profile is compacted to eliminate unused samples, locations,
+// functions and mappings. Profiles must have identical profile sample
+// and period types or the merge will fail. profile.Period of the
+// resulting profile will be the maximum of all profiles, and
+// profile.TimeNanos will be the earliest nonzero one.
+func Merge(srcs []*Profile) (*Profile, error) {
+	if len(srcs) == 0 {
+		return nil, fmt.Errorf("no profiles to merge")
+	}
+	p, err := combineHeaders(srcs)
+	if err != nil {
+		return nil, err
+	}
+
+	pm := &profileMerger{
+		p:         p,
+		samples:   make(map[sampleKey]*Sample, len(srcs[0].Sample)),
+		locations: make(map[locationKey]*Location, len(srcs[0].Location)),
+		functions: make(map[functionKey]*Function, len(srcs[0].Function)),
+		mappings:  make(map[mappingKey]*Mapping, len(srcs[0].Mapping)),
+	}
+
+	for _, src := range srcs {
+		// Clear the profile-specific hash tables
+		pm.locationsByID = make(map[uint64]*Location, len(src.Location))
+		pm.functionsByID = make(map[uint64]*Function, len(src.Function))
+		pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping))
+
+		if len(pm.mappings) == 0 && len(src.Mapping) > 0 {
+			// The Mapping list has the property that the first mapping
+			// represents the main binary. Take the first Mapping we see,
+			// otherwise the operations below will add mappings in an
+			// arbitrary order.
+			pm.mapMapping(srcs[0].Mapping[0])
+		}
+
+		for _, s := range src.Sample {
+			if !isZeroSample(s) {
+				pm.mapSample(s)
+			}
+		}
+	}
+
+	for _, s := range p.Sample {
+		if isZeroSample(s) {
+			// If there are any zero samples, re-merge the profile to GC
+			// them.
+			return Merge([]*Profile{p})
+		}
+	}
+
+	return p, nil
+}
+
+func isZeroSample(s *Sample) bool {
+	for _, v := range s.Value {
+		if v != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+type profileMerger struct {
+	p *Profile
+
+	// Memoization tables within a profile.
+	locationsByID map[uint64]*Location
+	functionsByID map[uint64]*Function
+	mappingsByID  map[uint64]mapInfo
+
+	// Memoization tables for profile entities.
+	samples   map[sampleKey]*Sample
+	locations map[locationKey]*Location
+	functions map[functionKey]*Function
+	mappings  map[mappingKey]*Mapping
+}
+
+type mapInfo struct {
+	m      *Mapping
+	offset int64
+}
+
+func (pm *profileMerger) mapSample(src *Sample) *Sample {
+	s := &Sample{
+		Location: make([]*Location, len(src.Location)),
+		Value:    make([]int64, len(src.Value)),
+		Label:    make(map[string][]string, len(src.Label)),
+		NumLabel: make(map[string][]int64, len(src.NumLabel)),
+	}
+	for i, l := range src.Location {
+		s.Location[i] = pm.mapLocation(l)
+	}
+	for k, v := range src.Label {
+		vv := make([]string, len(v))
+		copy(vv, v)
+		s.Label[k] = vv
+	}
+	for k, v := range src.NumLabel {
+		vv := make([]int64, len(v))
+		copy(vv, v)
+		s.NumLabel[k] = vv
+	}
+	// Check memoization table. Must be done on the remapped location to
+	// account for the remapped mapping. Add current values to the
+	// existing sample.
+	k := s.key()
+	if ss, ok := pm.samples[k]; ok {
+		for i, v := range src.Value {
+			ss.Value[i] += v
+		}
+		return ss
+	}
+	copy(s.Value, src.Value)
+	pm.samples[k] = s
+	pm.p.Sample = append(pm.p.Sample, s)
+	return s
+}
+
+// key generates sampleKey to be used as a key for maps.
+func (sample *Sample) key() sampleKey {
+	ids := make([]string, len(sample.Location))
+	for i, l := range sample.Location {
+		ids[i] = strconv.FormatUint(l.ID, 16)
+	}
+
+	labels := make([]string, 0, len(sample.Label))
+	for k, v := range sample.Label {
+		labels = append(labels, fmt.Sprintf("%q%q", k, v))
+	}
+	sort.Strings(labels)
+
+	numlabels := make([]string, 0, len(sample.NumLabel))
+	for k, v := range sample.NumLabel {
+		numlabels = append(numlabels, fmt.Sprintf("%q%x", k, v))
+	}
+	sort.Strings(numlabels)
+
+	return sampleKey{
+		strings.Join(ids, "|"),
+		strings.Join(labels, ""),
+		strings.Join(numlabels, ""),
+	}
+}
+
+type sampleKey struct {
+	locations string
+	labels    string
+	numlabels string
+}
+
+func (pm *profileMerger) mapLocation(src *Location) *Location {
+	if src == nil {
+		return nil
+	}
+
+	if l, ok := pm.locationsByID[src.ID]; ok {
+		pm.locationsByID[src.ID] = l
+		return l
+	}
+
+	mi := pm.mapMapping(src.Mapping)
+	l := &Location{
+		ID:      uint64(len(pm.p.Location) + 1),
+		Mapping: mi.m,
+		Address: uint64(int64(src.Address) + mi.offset),
+		Line:    make([]Line, len(src.Line)),
+	}
+	for i, ln := range src.Line {
+		l.Line[i] = pm.mapLine(ln)
+	}
+	// Check memoization table. Must be done on the remapped location to
+	// account for the remapped mapping ID.
+	k := l.key()
+	if ll, ok := pm.locations[k]; ok {
+		pm.locationsByID[src.ID] = ll
+		return ll
+	}
+	pm.locationsByID[src.ID] = l
+	pm.locations[k] = l
+	pm.p.Location = append(pm.p.Location, l)
+	return l
+}
+
+// key generates locationKey to be used as a key for maps.
+func (l *Location) key() locationKey {
+	key := locationKey{
+		addr: l.Address,
+	}
+	if l.Mapping != nil {
+		// Normalizes address to handle address space randomization.
+		key.addr -= l.Mapping.Start
+		key.mappingID = l.Mapping.ID
+	}
+	lines := make([]string, len(l.Line)*2)
+	for i, line := range l.Line {
+		if line.Function != nil {
+			lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
+		}
+		lines[i*2+1] = strconv.FormatInt(line.Line, 16)
+	}
+	key.lines = strings.Join(lines, "|")
+	return key
+}
+
+type locationKey struct {
+	addr, mappingID uint64
+	lines           string
+}
+
+func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
+	if src == nil {
+		return mapInfo{}
+	}
+
+	if mi, ok := pm.mappingsByID[src.ID]; ok {
+		return mi
+	}
+
+	// Check memoization tables.
+	bk, pk := src.key()
+	if src.BuildID != "" {
+		if m, ok := pm.mappings[bk]; ok {
+			mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
+			pm.mappingsByID[src.ID] = mi
+			return mi
+		}
+	}
+	if src.File != "" {
+		if m, ok := pm.mappings[pk]; ok {
+			mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
+			pm.mappingsByID[src.ID] = mi
+			return mi
+		}
+	}
+	m := &Mapping{
+		ID:              uint64(len(pm.p.Mapping) + 1),
+		Start:           src.Start,
+		Limit:           src.Limit,
+		Offset:          src.Offset,
+		File:            src.File,
+		BuildID:         src.BuildID,
+		HasFunctions:    src.HasFunctions,
+		HasFilenames:    src.HasFilenames,
+		HasLineNumbers:  src.HasLineNumbers,
+		HasInlineFrames: src.HasInlineFrames,
+	}
+	pm.p.Mapping = append(pm.p.Mapping, m)
+
+	// Update memoization tables.
+	if m.BuildID != "" {
+		pm.mappings[bk] = m
+	}
+	if m.File != "" {
+		pm.mappings[pk] = m
+	}
+	mi := mapInfo{m, 0}
+	pm.mappingsByID[src.ID] = mi
+	return mi
+}
+
+// key generates encoded strings of Mapping to be used as a key for
+// maps. The first key represents only the build id, while the second
+// represents only the file path.
+func (m *Mapping) key() (buildIDKey, pathKey mappingKey) {
+	// Normalize addresses to handle address space randomization.
+	// Round up to next 4K boundary to avoid minor discrepancies.
+	const mapsizeRounding = 0x1000
+
+	size := m.Limit - m.Start
+	size = size + mapsizeRounding - 1
+	size = size - (size % mapsizeRounding)
+
+	buildIDKey = mappingKey{
+		size,
+		m.Offset,
+		m.BuildID,
+	}
+
+	pathKey = mappingKey{
+		size,
+		m.Offset,
+		m.File,
+	}
+	return
+}
+
+type mappingKey struct {
+	size, offset    uint64
+	buildidIDOrFile string
+}
+
+func (pm *profileMerger) mapLine(src Line) Line {
+	ln := Line{
+		Function: pm.mapFunction(src.Function),
+		Line:     src.Line,
+	}
+	return ln
+}
+
+func (pm *profileMerger) mapFunction(src *Function) *Function {
+	if src == nil {
+		return nil
+	}
+	if f, ok := pm.functionsByID[src.ID]; ok {
+		return f
+	}
+	k := src.key()
+	if f, ok := pm.functions[k]; ok {
+		pm.functionsByID[src.ID] = f
+		return f
+	}
+	f := &Function{
+		ID:         uint64(len(pm.p.Function) + 1),
+		Name:       src.Name,
+		SystemName: src.SystemName,
+		Filename:   src.Filename,
+		StartLine:  src.StartLine,
+	}
+	pm.functions[k] = f
+	pm.functionsByID[src.ID] = f
+	pm.p.Function = append(pm.p.Function, f)
+	return f
+}
+
+// key generates a struct to be used as a key for maps.
+func (f *Function) key() functionKey {
+	return functionKey{
+		f.StartLine,
+		f.Name,
+		f.SystemName,
+		f.Filename,
+	}
+}
+
+type functionKey struct {
+	startLine                  int64
+	name, systemName, fileName string
+}
+
+// combineHeaders checks that all profiles can be merged and returns
+// their combined profile.
+func combineHeaders(srcs []*Profile) (*Profile, error) {
+	for _, s := range srcs[1:] {
+		if err := srcs[0].compatible(s); err != nil {
+			return nil, err
+		}
+	}
+
+	var timeNanos, durationNanos, period int64
+	var comments []string
+	var defaultSampleType string
+	for _, s := range srcs {
+		if timeNanos == 0 || s.TimeNanos < timeNanos {
+			timeNanos = s.TimeNanos
+		}
+		durationNanos += s.DurationNanos
+		if period == 0 || period < s.Period {
+			period = s.Period
+		}
+		comments = append(comments, s.Comments...)
+		if defaultSampleType == "" {
+			defaultSampleType = s.DefaultSampleType
+		}
+	}
+
+	p := &Profile{
+		SampleType: make([]*ValueType, len(srcs[0].SampleType)),
+
+		DropFrames: srcs[0].DropFrames,
+		KeepFrames: srcs[0].KeepFrames,
+
+		TimeNanos:     timeNanos,
+		DurationNanos: durationNanos,
+		PeriodType:    srcs[0].PeriodType,
+		Period:        period,
+
+		Comments:          comments,
+		DefaultSampleType: defaultSampleType,
+	}
+	copy(p.SampleType, srcs[0].SampleType)
+	return p, nil
+}
+
+// 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 !equalValueType(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 !equalValueType(p.SampleType[i], pb.SampleType[i]) {
+			return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
+		}
+	}
+
+	return nil
+}
+
+// equalValueType returns true if the two value types are semantically
+// equal. It ignores the internal fields used during encode/decode.
+func equalValueType(st1, st2 *ValueType) bool {
+	return st1.Type == st2.Type && st1.Unit == st2.Unit
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
new file mode 100644
index 0000000..fb3d4fd
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
@@ -0,0 +1,619 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// 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"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strings"
+	"time"
+)
+
+// Profile is an in-memory representation of profile.proto.
+type Profile struct {
+	SampleType        []*ValueType
+	DefaultSampleType string
+	Sample            []*Sample
+	Mapping           []*Mapping
+	Location          []*Location
+	Function          []*Function
+	Comments          []string
+
+	DropFrames string
+	KeepFrames string
+
+	TimeNanos     int64
+	DurationNanos int64
+	PeriodType    *ValueType
+	Period        int64
+
+	commentX           []int64
+	dropFramesX        int64
+	keepFramesX        int64
+	stringTable        []string
+	defaultSampleTypeX int64
+}
+
+// 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) {
+	data, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+	return ParseData(data)
+}
+
+// ParseData parses a profile from a buffer and checks for its
+// validity.
+func ParseData(data []byte) (*Profile, error) {
+	var p *Profile
+	var err error
+	if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b {
+		gz, err := gzip.NewReader(bytes.NewBuffer(data))
+		if err == nil {
+			data, err = ioutil.ReadAll(gz)
+		}
+		if err != nil {
+			return nil, fmt.Errorf("decompressing profile: %v", err)
+		}
+	}
+	if p, err = ParseUncompressed(data); err != nil && err != errNoData {
+		p, err = parseLegacy(data)
+	}
+
+	if 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")
+var errNoData = fmt.Errorf("empty input file")
+
+func parseLegacy(data []byte) (*Profile, error) {
+	parsers := []func([]byte) (*Profile, error){
+		parseCPU,
+		parseHeap,
+		parseGoCount, // goroutine, threadcreate
+		parseThread,
+		parseContention,
+		parseJavaProfile,
+	}
+
+	for _, parser := range parsers {
+		p, err := parser(data)
+		if err == nil {
+			p.addLegacyFrameInfo()
+			return p, nil
+		}
+		if err != errUnrecognized {
+			return nil, err
+		}
+	}
+	return nil, errUnrecognized
+}
+
+// ParseUncompressed parses an uncompressed protobuf into a profile.
+func ParseUncompressed(data []byte) (*Profile, error) {
+	if len(data) == 0 {
+		return nil, errNoData
+	}
+	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]+)`)
+
+// massageMappings applies heuristic-based changes to the profile
+// mappings to account for quirks of some environments.
+func (p *Profile) massageMappings() {
+	// Merge adjacent regions with matching names, checking that the offsets match
+	if len(p.Mapping) > 1 {
+		mappings := []*Mapping{p.Mapping[0]}
+		for _, m := range p.Mapping[1:] {
+			lm := mappings[len(mappings)-1]
+			if adjacent(lm, m) {
+				lm.Limit = m.Limit
+				if m.File != "" {
+					lm.File = m.File
+				}
+				if m.BuildID != "" {
+					lm.BuildID = m.BuildID
+				}
+				p.updateLocationMapping(m, lm)
+				continue
+			}
+			mappings = append(mappings, m)
+		}
+		p.Mapping = mappings
+	}
+
+	// Use heuristics to identify main binary and move it to the top of the list of mappings
+	for i, m := range p.Mapping {
+		file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1))
+		if len(file) == 0 {
+			continue
+		}
+		if len(libRx.FindStringSubmatch(file)) > 0 {
+			continue
+		}
+		if file[0] == '[' {
+			continue
+		}
+		// Swap what we guess is main to position 0.
+		p.Mapping[0], p.Mapping[i] = p.Mapping[i], p.Mapping[0]
+		break
+	}
+
+	// Keep the mapping IDs neatly sorted
+	for i, m := range p.Mapping {
+		m.ID = uint64(i + 1)
+	}
+}
+
+// adjacent returns whether two mapping entries represent the same
+// mapping that has been split into two. Check that their addresses are adjacent,
+// and if the offsets match, if they are available.
+func adjacent(m1, m2 *Mapping) bool {
+	if m1.File != "" && m2.File != "" {
+		if m1.File != m2.File {
+			return false
+		}
+	}
+	if m1.BuildID != "" && m2.BuildID != "" {
+		if m1.BuildID != m2.BuildID {
+			return false
+		}
+	}
+	if m1.Limit != m2.Start {
+		return false
+	}
+	if m1.Offset != 0 && m2.Offset != 0 {
+		offset := m1.Offset + (m1.Limit - m1.Start)
+		if offset != m2.Offset {
+			return false
+		}
+	}
+	return true
+}
+
+func (p *Profile) updateLocationMapping(from, to *Mapping) {
+	for _, l := range p.Location {
+		if l.Mapping == from {
+			l.Mapping = to
+		}
+	}
+}
+
+// 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
+}
+
+// WriteUncompressed writes the profile as a marshaled protobuf.
+func (p *Profile) WriteUncompressed(w io.Writer) error {
+	p.preEncode()
+	b := marshal(p)
+	_, err := w.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))
+		}
+		for _, l := range s.Location {
+			if l == nil {
+				return fmt.Errorf("sample has nil location")
+			}
+		}
+	}
+
+	// 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()
+}
+
+// String dumps a text representation of a profile. Intended mainly
+// for debugging purposes.
+func (p *Profile) String() string {
+	ss := make([]string, 0, len(p.Comments)+len(p.Sample)+len(p.Mapping)+len(p.Location))
+	for _, c := range p.Comments {
+		ss = append(ss, "Comment: "+c)
+	}
+	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: %.4v", time.Duration(p.DurationNanos)))
+	}
+
+	ss = append(ss, "Samples:")
+	var sh1 string
+	for _, s := range p.SampleType {
+		dflt := ""
+		if s.Type == p.DefaultSampleType {
+			dflt = "[dflt]"
+		}
+		sh1 = sh1 + fmt.Sprintf("%s/%s%s ", s.Type, s.Unit, dflt)
+	}
+	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 := []string{}
+			for k, v := range s.Label {
+				ls = append(ls, fmt.Sprintf("%s:%v", k, v))
+			}
+			sort.Strings(ls)
+			ss = append(ss, labelHeader+strings.Join(ls, " "))
+		}
+		if len(s.NumLabel) > 0 {
+			ls := []string{}
+			for k, v := range s.NumLabel {
+				ls = append(ls, fmt.Sprintf("%s:%v", k, v))
+			}
+			sort.Strings(ls)
+			ss = append(ss, labelHeader+strings.Join(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"
+}
+
+// Scale multiplies all sample values in a profile by a constant.
+func (p *Profile) Scale(ratio float64) {
+	if ratio == 1 {
+		return
+	}
+	ratios := make([]float64, len(p.SampleType))
+	for i := range p.SampleType {
+		ratios[i] = ratio
+	}
+	p.ScaleN(ratios)
+}
+
+// ScaleN multiplies each sample values in a sample by a different amount.
+func (p *Profile) ScaleN(ratios []float64) error {
+	if len(p.SampleType) != len(ratios) {
+		return fmt.Errorf("mismatched scale ratios, got %d, want %d", len(ratios), len(p.SampleType))
+	}
+	allOnes := true
+	for _, r := range ratios {
+		if r != 1 {
+			allOnes = false
+			break
+		}
+	}
+	if allOnes {
+		return nil
+	}
+	for _, s := range p.Sample {
+		for i, v := range s.Value {
+			if ratios[i] != 1 {
+				s.Value[i] = int64(float64(v) * ratios[i])
+			}
+		}
+	}
+	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
+}
+
+// Unsymbolizable returns true if a mapping points to a binary for which
+// locations can't be symbolized in principle, at least now.
+func (m *Mapping) Unsymbolizable() bool {
+	name := filepath.Base(m.File)
+	return name == "[vdso]" || strings.HasPrefix(name, "linux-vdso") || name == "[heap]" || strings.HasPrefix(m.File, "/dev/dri/")
+}
+
+// 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
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go
new file mode 100644
index 0000000..c2319a6
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go
@@ -0,0 +1,521 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/google/pprof/internal/proftest"
+)
+
+func TestParse(t *testing.T) {
+	const path = "testdata/"
+
+	for _, source := range []string{
+		"go.crc32.cpu",
+		"go.godoc.thread",
+		"gobench.cpu",
+		"gobench.heap",
+		"cppbench.cpu",
+		"cppbench.heap",
+		"cppbench.contention",
+		"cppbench.growth",
+		"cppbench.thread",
+		"cppbench.thread.all",
+		"cppbench.thread.none",
+		"java.cpu",
+		"java.heap",
+		"java.contention",
+	} {
+		inbytes, err := ioutil.ReadFile(filepath.Join(path, source))
+		if err != nil {
+			t.Fatal(err)
+		}
+		p, err := Parse(bytes.NewBuffer(inbytes))
+		if err != nil {
+			t.Fatalf("%s: %s", source, err)
+		}
+
+		js := p.String()
+		goldFilename := path + source + ".string"
+		gold, err := ioutil.ReadFile(goldFilename)
+		if err != nil {
+			t.Fatalf("%s: %v", source, err)
+		}
+
+		if js != string(gold) {
+			t.Errorf("diff %s %s", source, goldFilename)
+			d, err := proftest.Diff(gold, []byte(js))
+			if err != nil {
+				t.Fatalf("%s: %v", source, err)
+			}
+			t.Error(source + "\n" + string(d) + "\n" + "new profile at:\n" + leaveTempfile([]byte(js)))
+		}
+
+		// Reencode and decode.
+		bw := bytes.NewBuffer(nil)
+		if err := p.Write(bw); err != nil {
+			t.Fatalf("%s: %v", source, err)
+		}
+		if p, err = Parse(bw); err != nil {
+			t.Fatalf("%s: %v", source, err)
+		}
+		js2 := p.String()
+		if js2 != string(gold) {
+			d, err := proftest.Diff(gold, []byte(js2))
+			if err != nil {
+				t.Fatalf("%s: %v", source, err)
+			}
+			t.Error(source + "\n" + string(d) + "\n" + "gold:\n" + goldFilename +
+				"\nnew profile at:\n" + leaveTempfile([]byte(js)))
+		}
+	}
+}
+
+func TestParseError(t *testing.T) {
+
+	testcases := []string{
+		"",
+		"garbage text",
+		"\x1f\x8b", // truncated gzip header
+		"\x1f\x8b\x08\x08\xbe\xe9\x20\x58\x00\x03\x65\x6d\x70\x74\x79\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // empty gzipped file
+	}
+
+	for i, input := range testcases {
+		_, err := Parse(strings.NewReader(input))
+		if err == nil {
+			t.Errorf("got nil, want error for input #%d", i)
+		}
+	}
+}
+
+// leaveTempfile leaves |b| in a temporary file on disk and returns the
+// temp filename. This is useful to recover a profile when the test
+// fails.
+func leaveTempfile(b []byte) string {
+	f1, err := ioutil.TempFile("", "profile_test")
+	if err != nil {
+		panic(err)
+	}
+	if _, err := f1.Write(b); err != nil {
+		panic(err)
+	}
+	return f1.Name()
+}
+
+const mainBinary = "/bin/main"
+
+var cpuM = []*Mapping{
+	{
+		ID:              1,
+		Start:           0x10000,
+		Limit:           0x40000,
+		File:            mainBinary,
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+	{
+		ID:              2,
+		Start:           0x1000,
+		Limit:           0x4000,
+		File:            "/lib/lib.so",
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+	{
+		ID:              3,
+		Start:           0x4000,
+		Limit:           0x5000,
+		File:            "/lib/lib2_c.so.6",
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+	{
+		ID:              4,
+		Start:           0x5000,
+		Limit:           0x9000,
+		File:            "/lib/lib.so_6 (deleted)",
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+}
+
+var cpuF = []*Function{
+	{ID: 1, Name: "main", SystemName: "main", Filename: "main.c"},
+	{ID: 2, Name: "foo", SystemName: "foo", Filename: "foo.c"},
+	{ID: 3, Name: "foo_caller", SystemName: "foo_caller", Filename: "foo.c"},
+}
+
+var cpuL = []*Location{
+	{
+		ID:      1000,
+		Mapping: cpuM[1],
+		Address: 0x1000,
+		Line: []Line{
+			{Function: cpuF[0], Line: 1},
+		},
+	},
+	{
+		ID:      2000,
+		Mapping: cpuM[0],
+		Address: 0x2000,
+		Line: []Line{
+			{Function: cpuF[1], Line: 2},
+			{Function: cpuF[2], Line: 1},
+		},
+	},
+	{
+		ID:      3000,
+		Mapping: cpuM[0],
+		Address: 0x3000,
+		Line: []Line{
+			{Function: cpuF[1], Line: 2},
+			{Function: cpuF[2], Line: 1},
+		},
+	},
+	{
+		ID:      3001,
+		Mapping: cpuM[0],
+		Address: 0x3001,
+		Line: []Line{
+			{Function: cpuF[2], Line: 2},
+		},
+	},
+	{
+		ID:      3002,
+		Mapping: cpuM[0],
+		Address: 0x3002,
+		Line: []Line{
+			{Function: cpuF[2], Line: 3},
+		},
+	},
+}
+
+var testProfile = &Profile{
+	PeriodType:    &ValueType{Type: "cpu", Unit: "milliseconds"},
+	Period:        1,
+	DurationNanos: 10e9,
+	SampleType: []*ValueType{
+		{Type: "samples", Unit: "count"},
+		{Type: "cpu", Unit: "milliseconds"},
+	},
+	Sample: []*Sample{
+		{
+			Location: []*Location{cpuL[0]},
+			Value:    []int64{1000, 1000},
+			Label: map[string][]string{
+				"key1": []string{"tag1"},
+				"key2": []string{"tag1"},
+			},
+		},
+		{
+			Location: []*Location{cpuL[1], cpuL[0]},
+			Value:    []int64{100, 100},
+			Label: map[string][]string{
+				"key1": []string{"tag2"},
+				"key3": []string{"tag2"},
+			},
+		},
+		{
+			Location: []*Location{cpuL[2], cpuL[0]},
+			Value:    []int64{10, 10},
+			Label: map[string][]string{
+				"key1": []string{"tag3"},
+				"key2": []string{"tag2"},
+			},
+		},
+		{
+			Location: []*Location{cpuL[3], cpuL[0]},
+			Value:    []int64{10000, 10000},
+			Label: map[string][]string{
+				"key1": []string{"tag4"},
+				"key2": []string{"tag1"},
+			},
+		},
+		{
+			Location: []*Location{cpuL[4], cpuL[0]},
+			Value:    []int64{1, 1},
+			Label: map[string][]string{
+				"key1": []string{"tag4"},
+				"key2": []string{"tag1"},
+			},
+		},
+	},
+	Location: cpuL,
+	Function: cpuF,
+	Mapping:  cpuM,
+}
+
+var aggTests = map[string]aggTest{
+	"precise":         aggTest{true, true, true, true, 5},
+	"fileline":        aggTest{false, true, true, true, 4},
+	"inline_function": aggTest{false, true, false, true, 3},
+	"function":        aggTest{false, true, false, false, 2},
+}
+
+type aggTest struct {
+	precise, function, fileline, inlineFrame bool
+	rows                                     int
+}
+
+const totalSamples = int64(11111)
+
+func TestAggregation(t *testing.T) {
+	prof := testProfile.Copy()
+	for _, resolution := range []string{"precise", "fileline", "inline_function", "function"} {
+		a := aggTests[resolution]
+		if !a.precise {
+			if err := prof.Aggregate(a.inlineFrame, a.function, a.fileline, a.fileline, false); err != nil {
+				t.Error("aggregating to " + resolution + ":" + err.Error())
+			}
+		}
+		if err := checkAggregation(prof, &a); err != nil {
+			t.Error("failed aggregation to " + resolution + ": " + err.Error())
+		}
+	}
+}
+
+// checkAggregation verifies that the profile remained consistent
+// with its aggregation.
+func checkAggregation(prof *Profile, a *aggTest) error {
+	// Check that the total number of samples for the rows was preserved.
+	total := int64(0)
+
+	samples := make(map[string]bool)
+	for _, sample := range prof.Sample {
+		tb := locationHash(sample)
+		samples[tb] = true
+		total += sample.Value[0]
+	}
+
+	if total != totalSamples {
+		return fmt.Errorf("sample total %d, want %d", total, totalSamples)
+	}
+
+	// Check the number of unique sample locations
+	if a.rows != len(samples) {
+		return fmt.Errorf("number of samples %d, want %d", len(samples), a.rows)
+	}
+
+	// Check that all mappings have the right detail flags.
+	for _, m := range prof.Mapping {
+		if m.HasFunctions != a.function {
+			return fmt.Errorf("unexpected mapping.HasFunctions %v, want %v", m.HasFunctions, a.function)
+		}
+		if m.HasFilenames != a.fileline {
+			return fmt.Errorf("unexpected mapping.HasFilenames %v, want %v", m.HasFilenames, a.fileline)
+		}
+		if m.HasLineNumbers != a.fileline {
+			return fmt.Errorf("unexpected mapping.HasLineNumbers %v, want %v", m.HasLineNumbers, a.fileline)
+		}
+		if m.HasInlineFrames != a.inlineFrame {
+			return fmt.Errorf("unexpected mapping.HasInlineFrames %v, want %v", m.HasInlineFrames, a.inlineFrame)
+		}
+	}
+
+	// Check that aggregation has removed finer resolution data.
+	for _, l := range prof.Location {
+		if !a.inlineFrame && len(l.Line) > 1 {
+			return fmt.Errorf("found %d lines on location %d, want 1", len(l.Line), l.ID)
+		}
+
+		for _, ln := range l.Line {
+			if !a.fileline && (ln.Function.Filename != "" || ln.Line != 0) {
+				return fmt.Errorf("found line %s:%d on location %d, want :0",
+					ln.Function.Filename, ln.Line, l.ID)
+			}
+			if !a.function && (ln.Function.Name != "") {
+				return fmt.Errorf(`found file %s location %d, want ""`,
+					ln.Function.Name, l.ID)
+			}
+		}
+	}
+
+	return nil
+}
+
+// Test merge leaves the main binary in place.
+func TestMergeMain(t *testing.T) {
+	prof := testProfile.Copy()
+	p1, err := Merge([]*Profile{prof})
+	if err != nil {
+		t.Fatalf("merge error: %v", err)
+	}
+	if cpuM[0].File != p1.Mapping[0].File {
+		t.Errorf("want Mapping[0]=%s got %s", cpuM[0].File, p1.Mapping[0].File)
+	}
+}
+
+func TestMerge(t *testing.T) {
+	// Aggregate a profile with itself and once again with a factor of
+	// -2. Should end up with an empty profile (all samples for a
+	// location should add up to 0).
+
+	prof := testProfile.Copy()
+	p1, err := Merge([]*Profile{prof, prof})
+	if err != nil {
+		t.Errorf("merge error: %v", err)
+	}
+	prof.Scale(-2)
+	prof, err = Merge([]*Profile{p1, prof})
+	if err != nil {
+		t.Errorf("merge error: %v", err)
+	}
+
+	// Use aggregation to merge locations at function granularity.
+	if err := prof.Aggregate(false, true, false, false, false); err != nil {
+		t.Errorf("aggregating after merge: %v", err)
+	}
+
+	samples := make(map[string]int64)
+	for _, s := range prof.Sample {
+		tb := locationHash(s)
+		samples[tb] = samples[tb] + s.Value[0]
+	}
+	for s, v := range samples {
+		if v != 0 {
+			t.Errorf("nonzero value for sample %s: %d", s, v)
+		}
+	}
+}
+
+func TestMergeAll(t *testing.T) {
+	// Aggregate 10 copies of the profile.
+	profs := make([]*Profile, 10)
+	for i := 0; i < 10; i++ {
+		profs[i] = testProfile.Copy()
+	}
+	prof, err := Merge(profs)
+	if err != nil {
+		t.Errorf("merge error: %v", err)
+	}
+	samples := make(map[string]int64)
+	for _, s := range prof.Sample {
+		tb := locationHash(s)
+		samples[tb] = samples[tb] + s.Value[0]
+	}
+	for _, s := range testProfile.Sample {
+		tb := locationHash(s)
+		if samples[tb] != s.Value[0]*10 {
+			t.Errorf("merge got wrong value at %s : %d instead of %d", tb, samples[tb], s.Value[0]*10)
+		}
+	}
+}
+
+func TestFilter(t *testing.T) {
+	// Perform several forms of filtering on the test profile.
+
+	type filterTestcase struct {
+		focus, ignore, hide, show *regexp.Regexp
+		fm, im, hm, hnm           bool
+	}
+
+	for tx, tc := range []filterTestcase{
+		{nil, nil, nil, nil, true, false, false, false},
+		{regexp.MustCompile("notfound"), nil, nil, nil, false, false, false, false},
+		{nil, regexp.MustCompile("foo.c"), nil, nil, true, true, false, false},
+		{nil, nil, regexp.MustCompile("lib.so"), nil, true, false, true, false},
+	} {
+		prof := *testProfile.Copy()
+		gf, gi, gh, gnh := prof.FilterSamplesByName(tc.focus, tc.ignore, tc.hide, tc.show)
+		if gf != tc.fm {
+			t.Errorf("Filter #%d, got fm=%v, want %v", tx, gf, tc.fm)
+		}
+		if gi != tc.im {
+			t.Errorf("Filter #%d, got im=%v, want %v", tx, gi, tc.im)
+		}
+		if gh != tc.hm {
+			t.Errorf("Filter #%d, got hm=%v, want %v", tx, gh, tc.hm)
+		}
+		if gnh != tc.hnm {
+			t.Errorf("Filter #%d, got hnm=%v, want %v", tx, gnh, tc.hnm)
+		}
+	}
+}
+
+func TestTagFilter(t *testing.T) {
+	// Perform several forms of tag filtering on the test profile.
+
+	type filterTestcase struct {
+		include, exclude *regexp.Regexp
+		im, em           bool
+		count            int
+	}
+
+	countTags := func(p *Profile) map[string]bool {
+		tags := make(map[string]bool)
+
+		for _, s := range p.Sample {
+			for l := range s.Label {
+				tags[l] = true
+			}
+			for l := range s.NumLabel {
+				tags[l] = true
+			}
+		}
+		return tags
+	}
+
+	for tx, tc := range []filterTestcase{
+		{nil, nil, true, false, 3},
+		{regexp.MustCompile("notfound"), nil, false, false, 0},
+		{regexp.MustCompile("key1"), nil, true, false, 1},
+		{nil, regexp.MustCompile("key[12]"), true, true, 1},
+	} {
+		prof := testProfile.Copy()
+		gim, gem := prof.FilterTagsByName(tc.include, tc.exclude)
+		if gim != tc.im {
+			t.Errorf("Filter #%d, got include match=%v, want %v", tx, gim, tc.im)
+		}
+		if gem != tc.em {
+			t.Errorf("Filter #%d, got exclude match=%v, want %v", tx, gem, tc.em)
+		}
+		if tags := countTags(prof); len(tags) != tc.count {
+			t.Errorf("Filter #%d, got %d tags[%v], want %d", tx, len(tags), tags, tc.count)
+		}
+	}
+}
+
+// locationHash constructs a string to use as a hashkey for a sample, based on its locations
+func locationHash(s *Sample) string {
+	var tb string
+	for _, l := range s.Location {
+		for _, ln := range l.Line {
+			tb = tb + fmt.Sprintf("%s:%d@%d ", ln.Function.Name, ln.Line, l.Address)
+		}
+	}
+	return tb
+}
+
+func TestSetMain(t *testing.T) {
+	testProfile.massageMappings()
+	if testProfile.Mapping[0].File != mainBinary {
+		t.Errorf("got %s for main", testProfile.Mapping[0].File)
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/proto.go b/src/cmd/vendor/github.com/google/pprof/profile/proto.go
new file mode 100644
index 0000000..01b7f7a
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/proto.go
@@ -0,0 +1,375 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file is a simple protocol buffer encoder and decoder.
+// The format is described at
+// https://developers.google.com/protocol-buffers/docs/encoding
+//
+// 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 // field tag
+	typ   int // proto wire type code for field
+	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 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 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 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 wire 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
+		tmp := make([]int64, 0, len(data)) // Maximally sized
+		for len(data) > 0 {
+			var u uint64
+			var err error
+
+			if u, data, err = decodeVarint(data); err != nil {
+				return err
+			}
+			tmp = append(tmp, int64(u))
+		}
+		*x = append(*x, tmp...)
+		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
+		tmp := make([]uint64, 0, len(data)) // Maximally sized
+		for len(data) > 0 {
+			var u uint64
+			var err error
+
+			if u, data, err = decodeVarint(data); err != nil {
+				return err
+			}
+			tmp = append(tmp, u)
+		}
+		*x = append(*x, tmp...)
+		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/vendor/github.com/google/pprof/profile/proto_test.go b/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go
new file mode 100644
index 0000000..d2a3513
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go
@@ -0,0 +1,146 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/google/pprof/internal/proftest"
+)
+
+var testM = []*Mapping{
+	{
+		ID:              1,
+		Start:           1,
+		Limit:           10,
+		Offset:          0,
+		File:            "file1",
+		BuildID:         "buildid1",
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+	{
+		ID:              2,
+		Start:           10,
+		Limit:           30,
+		Offset:          9,
+		File:            "file1",
+		BuildID:         "buildid2",
+		HasFunctions:    true,
+		HasFilenames:    true,
+		HasLineNumbers:  true,
+		HasInlineFrames: true,
+	},
+}
+
+var testF = []*Function{
+	{ID: 1, Name: "func1", SystemName: "func1", Filename: "file1"},
+	{ID: 2, Name: "func2", SystemName: "func2", Filename: "file1"},
+	{ID: 3, Name: "func3", SystemName: "func3", Filename: "file2"},
+}
+
+var testL = []*Location{
+	{
+		ID:      1,
+		Address: 1,
+		Mapping: testM[0],
+		Line: []Line{
+			{
+				Function: testF[0],
+				Line:     2,
+			},
+			{
+				Function: testF[1],
+				Line:     2222222,
+			},
+		},
+	},
+	{
+		ID:      2,
+		Mapping: testM[1],
+		Address: 11,
+		Line: []Line{
+			{
+				Function: testF[2],
+				Line:     2,
+			},
+		},
+	},
+	{
+		ID:      3,
+		Mapping: testM[1],
+		Address: 12,
+	},
+}
+
+var all = &Profile{
+	PeriodType:    &ValueType{Type: "cpu", Unit: "milliseconds"},
+	Period:        10,
+	DurationNanos: 10e9,
+	SampleType: []*ValueType{
+		{Type: "cpu", Unit: "cycles"},
+		{Type: "object", Unit: "count"},
+	},
+	Sample: []*Sample{
+		{
+			Location: []*Location{testL[0], testL[1], testL[2], testL[1], testL[1]},
+			Label: map[string][]string{
+				"key1": []string{"value1"},
+				"key2": []string{"value2"},
+			},
+			Value: []int64{10, 20},
+		},
+		{
+			Location: []*Location{testL[1], testL[2], testL[0], testL[1]},
+			Value:    []int64{30, 40},
+			Label: map[string][]string{
+				"key1": []string{"value1"},
+				"key2": []string{"value2"},
+			},
+			NumLabel: map[string][]int64{
+				"key1": []int64{1, 2},
+				"key2": []int64{3, 4},
+			},
+		},
+	},
+	Function: testF,
+	Mapping:  testM,
+	Location: testL,
+	Comments: []string{"Comment 1", "Comment 2"},
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+	// Write the profile, parse it, and ensure they're equal.
+	buf := bytes.NewBuffer(nil)
+	all.Write(buf)
+	all2, err := Parse(buf)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	js1 := proftest.EncodeJSON(&all)
+	js2 := proftest.EncodeJSON(&all2)
+	if string(js1) != string(js2) {
+		t.Errorf("profiles differ")
+		d, err := proftest.Diff(js1, js2)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Error("\n" + string(d))
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/prune.go b/src/cmd/vendor/github.com/google/pprof/profile/prune.go
new file mode 100644
index 0000000..cf9cbb3
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/prune.go
@@ -0,0 +1,155 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Implements methods to remove frames from profiles.
+
+package profile
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+)
+
+// 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 != "" {
+				// Account for leading '.' on the PPC ELF v1 ABI.
+				funcName := strings.TrimPrefix(fn.Name, ".")
+				// Account for unsimplified names -- trim starting from the first '('.
+				if index := strings.Index(funcName, "("); index > 0 {
+					funcName = funcName[:index]
+				}
+				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
+}
+
+// PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself.
+//
+// Please see the example below to understand this method as well as
+// the difference from Prune method.
+//
+// A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline.
+//
+// PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A.
+// Prune(A, nil) returns [B,C,B,D] by removing A itself.
+//
+// PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom.
+// Prune(B, nil) returns [D] because a matching node is found by scanning from the root.
+func (p *Profile) PruneFrom(dropRx *regexp.Regexp) {
+	pruneBeneath := make(map[uint64]bool)
+
+	for _, loc := range p.Location {
+		for i := 0; i < len(loc.Line); i++ {
+			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
+				// Account for leading '.' on the PPC ELF v1 ABI.
+				funcName := strings.TrimPrefix(fn.Name, ".")
+				// Account for unsimplified names -- trim starting from the first '('.
+				if index := strings.Index(funcName, "("); index > 0 {
+					funcName = funcName[:index]
+				}
+				if dropRx.MatchString(funcName) {
+					// Found matching entry to prune.
+					pruneBeneath[loc.ID] = true
+					loc.Line = loc.Line[i:]
+					break
+				}
+			}
+		}
+	}
+
+	// Prune locs from each Sample
+	for _, sample := range p.Sample {
+		// Scan from the bottom leaf to the root to find the prune location.
+		for i, loc := range sample.Location {
+			if pruneBeneath[loc.ID] {
+				sample.Location = sample.Location[i:]
+				break
+			}
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/prune_test.go b/src/cmd/vendor/github.com/google/pprof/profile/prune_test.go
new file mode 100644
index 0000000..58fa25e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/prune_test.go
@@ -0,0 +1,139 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package profile
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestPrune(t *testing.T) {
+	for _, test := range []struct {
+		in   *Profile
+		want string
+	}{
+		{in1, out1},
+	} {
+		in := test.in.Copy()
+		in.RemoveUninteresting()
+		if err := in.CheckValid(); err != nil {
+			t.Error(err)
+		}
+		w := strings.Split(test.want, "\n")
+		for i, g := range strings.Split(in.String(), "\n") {
+			if i >= len(w) {
+				t.Fatalf("got trailing %s", g)
+			}
+			if strings.TrimSpace(g) != strings.TrimSpace(w[i]) {
+				t.Fatalf(`%d: got: "%s"  want:"%s"`, i, g, w[i])
+			}
+		}
+	}
+}
+
+var funs = []*Function{
+	{ID: 1, Name: "main", SystemName: "main", Filename: "main.c"},
+	{ID: 2, Name: "fun1", SystemName: "fun1", Filename: "fun.c"},
+	{ID: 3, Name: "fun2", SystemName: "fun2", Filename: "fun.c"},
+	{ID: 4, Name: "fun3", SystemName: "fun3", Filename: "fun.c"},
+	{ID: 5, Name: "fun4", SystemName: "fun4", Filename: "fun.c"},
+	{ID: 6, Name: "fun5", SystemName: "fun5", Filename: "fun.c"},
+}
+
+var locs1 = []*Location{
+	{
+		ID: 1,
+		Line: []Line{
+			{Function: funs[0], Line: 1},
+		},
+	},
+	{
+		ID: 2,
+		Line: []Line{
+			{Function: funs[1], Line: 2},
+			{Function: funs[2], Line: 1},
+		},
+	},
+	{
+		ID: 3,
+		Line: []Line{
+			{Function: funs[3], Line: 2},
+			{Function: funs[1], Line: 1},
+		},
+	},
+	{
+		ID: 4,
+		Line: []Line{
+			{Function: funs[3], Line: 2},
+			{Function: funs[1], Line: 2},
+			{Function: funs[5], Line: 2},
+		},
+	},
+}
+
+var in1 = &Profile{
+	PeriodType:    &ValueType{Type: "cpu", Unit: "milliseconds"},
+	Period:        1,
+	DurationNanos: 10e9,
+	SampleType: []*ValueType{
+		{Type: "samples", Unit: "count"},
+		{Type: "cpu", Unit: "milliseconds"},
+	},
+	Sample: []*Sample{
+		{
+			Location: []*Location{locs1[0]},
+			Value:    []int64{1, 1},
+		},
+		{
+			Location: []*Location{locs1[1], locs1[0]},
+			Value:    []int64{1, 1},
+		},
+		{
+			Location: []*Location{locs1[2], locs1[0]},
+			Value:    []int64{1, 1},
+		},
+		{
+			Location: []*Location{locs1[3], locs1[0]},
+			Value:    []int64{1, 1},
+		},
+		{
+			Location: []*Location{locs1[3], locs1[2], locs1[1], locs1[0]},
+			Value:    []int64{1, 1},
+		},
+	},
+	Location:   locs1,
+	Function:   funs,
+	DropFrames: "fu.*[12]|banana",
+	KeepFrames: ".*[n2][n2]",
+}
+
+const out1 = `PeriodType: cpu milliseconds
+Period: 1
+Duration: 10s
+Samples:
+samples/count cpu/milliseconds
+          1          1: 1
+          1          1: 2 1
+          1          1: 1
+          1          1: 4 1
+          1          1: 2 1
+Locations
+     1: 0x0 main main.c:1 s=0
+     2: 0x0 fun2 fun.c:1 s=0
+     3: 0x0 fun3 fun.c:2 s=0
+             fun1 fun.c:1 s=0
+     4: 0x0 fun5 fun.c:2 s=0
+Mappings
+`
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention
new file mode 100644
index 0000000..66a64c9
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention
@@ -0,0 +1,24 @@
+--- contentionz 1 ---
+cycles/second = 3201000000
+sampling period = 100
+ms since reset = 16502830
+discarded samples = 0
+  19490304       27 @ 0xbccc97 0xc61202 0x42ed5f 0x42edc1 0x42e15a 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+       768        1 @ 0xbccc97 0xa42dc7 0xa456e4 0x7fcdc2ff214e
+      5760        2 @ 0xbccc97 0xb82b73 0xb82bcb 0xb87eab 0xb8814c 0x4e969d 0x4faa17 0x4fc5f6 0x4fd028 0x4fd230 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+    569088        1 @ 0xbccc97 0xb82b73 0xb82bcb 0xb87f08 0xb8814c 0x42ed5f 0x42edc1 0x42e15a 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+      2432        1 @ 0xbccc97 0xb82b73 0xb82bcb 0xb87eab 0xb8814c 0x7aa74c 0x7ab844 0x7ab914 0x79e9e9 0x79e326 0x4d299e 0x4d4b7b 0x4b7be8 0x4b7ff1 0x4d2dae 0x79e80a
+   2034816        3 @ 0xbccc97 0xb82f0f 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+--- Memory map: ---
+  00400000-00fcb000: cppbench_server_main
+  7fcdc231e000-7fcdc2321000: /libnss_cache-2.15.so
+  7fcdc2522000-7fcdc252e000: /libnss_files-2.15.so
+  7fcdc272f000-7fcdc28dd000: /libc-2.15.so
+  7fcdc2ae7000-7fcdc2be2000: /libm-2.15.so
+  7fcdc2de3000-7fcdc2dea000: /librt-2.15.so
+  7fcdc2feb000-7fcdc3003000: /libpthread-2.15.so
+  7fcdc3208000-7fcdc320a000: /libdl-2.15.so
+  7fcdc340c000-7fcdc3415000: /libcrypt-2.15.so
+  7fcdc3645000-7fcdc3669000: /ld-2.15.so
+  7fff86bff000-7fff86c00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention.string
new file mode 100644
index 0000000..441f1ce
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.contention.string
@@ -0,0 +1,65 @@
+PeriodType: contentions count
+Period: 100
+Duration: 4h35
+Samples:
+contentions/count delay/nanoseconds
+       2700  608881724: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+        100      23992: 1 14 12 13 
+        200     179943: 1 15 16 17 18 19 20 21 22 23 9 10 11 12 13 
+        100   17778444: 1 15 16 24 18 3 4 5 6 7 8 9 10 11 12 13 
+        100      75976: 1 15 16 17 18 25 26 27 28 29 30 31 32 33 34 9 
+        300   63568134: 1 35 36 37 38 39 40 6 7 8 9 10 11 12 13 
+Locations
+     1: 0xbccc96 M=1 
+     2: 0xc61201 M=1 
+     3: 0x42ed5e M=1 
+     4: 0x42edc0 M=1 
+     5: 0x42e159 M=1 
+     6: 0x5261ae M=1 
+     7: 0x526ede M=1 
+     8: 0x5280aa M=1 
+     9: 0x79e809 M=1 
+    10: 0x7a251a M=1 
+    11: 0x7a296c M=1 
+    12: 0xa456e3 M=1 
+    13: 0x7fcdc2ff214d M=7 
+    14: 0xa42dc6 M=1 
+    15: 0xb82b72 M=1 
+    16: 0xb82bca M=1 
+    17: 0xb87eaa M=1 
+    18: 0xb8814b M=1 
+    19: 0x4e969c M=1 
+    20: 0x4faa16 M=1 
+    21: 0x4fc5f5 M=1 
+    22: 0x4fd027 M=1 
+    23: 0x4fd22f M=1 
+    24: 0xb87f07 M=1 
+    25: 0x7aa74b M=1 
+    26: 0x7ab843 M=1 
+    27: 0x7ab913 M=1 
+    28: 0x79e9e8 M=1 
+    29: 0x79e325 M=1 
+    30: 0x4d299d M=1 
+    31: 0x4d4b7a M=1 
+    32: 0x4b7be7 M=1 
+    33: 0x4b7ff0 M=1 
+    34: 0x4d2dad M=1 
+    35: 0xb82f0e M=1 
+    36: 0xb83002 M=1 
+    37: 0xb87d4f M=1 
+    38: 0xc635ef M=1 
+    39: 0x42ecc2 M=1 
+    40: 0x42e14b M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 cppbench_server_main  
+2: 0x7fcdc231e000/0x7fcdc2321000/0x0 /libnss_cache-2.15.so  
+3: 0x7fcdc2522000/0x7fcdc252e000/0x0 /libnss_files-2.15.so  
+4: 0x7fcdc272f000/0x7fcdc28dd000/0x0 /libc-2.15.so  
+5: 0x7fcdc2ae7000/0x7fcdc2be2000/0x0 /libm-2.15.so  
+6: 0x7fcdc2de3000/0x7fcdc2dea000/0x0 /librt-2.15.so  
+7: 0x7fcdc2feb000/0x7fcdc3003000/0x0 /libpthread-2.15.so  
+8: 0x7fcdc3208000/0x7fcdc320a000/0x0 /libdl-2.15.so  
+9: 0x7fcdc340c000/0x7fcdc3415000/0x0 /libcrypt-2.15.so  
+10: 0x7fcdc3645000/0x7fcdc3669000/0x0 /ld-2.15.so  
+11: 0x7fff86bff000/0x7fff86c00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu
new file mode 100644
index 0000000..607015e
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu.string
new file mode 100644
index 0000000..251f913
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.cpu.string
@@ -0,0 +1,179 @@
+PeriodType: cpu nanoseconds
+Period: 10000000
+Samples:
+samples/count cpu/nanoseconds
+          1   10000000: 1 2 3 4 5 6 7 8 9 10 
+          1   10000000: 11 2 3 4 5 6 7 8 9 10 
+          1   10000000: 1 2 3 4 5 6 7 8 9 10 
+          1   10000000: 12 13 14 15 16 17 18 3 4 5 6 7 8 9 10 
+        542 5420000000: 19 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 20 17 18 3 4 5 6 7 8 9 10 
+         10  100000000: 21 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 22 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 23 24 25 2 3 4 5 6 7 8 9 10 
+          3   30000000: 26 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 27 16 17 18 3 4 5 6 7 8 9 10 
+          2   20000000: 28 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 29 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 30 31 32 33 34 35 36 37 38 9 10 
+          3   30000000: 39 40 41 24 25 2 3 4 5 6 7 8 9 10 
+          2   20000000: 42 40 41 24 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 43 40 41 24 25 2 3 4 5 6 7 8 9 10 
+          2   20000000: 44 45 41 24 25 2 3 4 5 6 7 8 9 10 
+         67  670000000: 46 2 3 4 5 6 7 8 9 10 
+         20  200000000: 47 2 3 4 5 6 7 8 9 10 
+         12  120000000: 48 2 3 4 5 6 7 8 9 10 
+          5   50000000: 11 2 3 4 5 6 7 8 9 10 
+          1   10000000: 49 10 
+          1   10000000: 50 51 52 13 14 15 16 17 18 3 4 5 6 7 8 9 10 
+          2   20000000: 53 51 52 13 14 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 54 14 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 55 56 57 58 4 5 6 7 8 9 10 
+          1   10000000: 59 41 24 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 60 41 24 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 61 62 63 64 40 41 24 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 65 66 67 68 69 70 71 72 73 74 75 37 38 9 10 
+          1   10000000: 76 13 77 15 16 17 18 3 4 5 6 7 8 9 10 
+          2   20000000: 78 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 79 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 80 13 77 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 81 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 82 13 14 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 83 13 77 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 83 13 14 15 16 17 18 3 4 5 6 7 8 9 10 
+          1   10000000: 30 84 85 86 9 10 
+          1   10000000: 87 88 40 41 24 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 89 90 91 92 8 9 10 
+          1   10000000: 30 93 8 9 10 
+          1   10000000: 30 84 94 9 10 
+          1   10000000: 95 3 4 5 6 7 8 9 10 
+          1   10000000: 96 97 3 4 5 6 7 8 9 10 
+          1   10000000: 98 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 99 25 2 3 4 5 6 7 8 9 10 
+          1   10000000: 100 101 102 41 24 25 2 3 4 5 6 7 8 9 10 
+          2   20000000: 103 104 91 92 8 9 10 
+          1   10000000: 105 104 91 92 8 9 10 
+          1   10000000: 106 107 108 109 97 3 4 5 6 7 8 9 10 
+Locations
+     1: 0x42ef04 M=1 
+     2: 0x42e14b M=1 
+     3: 0x5261ae M=1 
+     4: 0x526ede M=1 
+     5: 0x5280aa M=1 
+     6: 0x79e809 M=1 
+     7: 0x7a251a M=1 
+     8: 0x7a296c M=1 
+     9: 0xa456e3 M=1 
+    10: 0x7f5e541460fd M=7 
+    11: 0x42ef17 M=1 
+    12: 0xb867c0 M=1 
+    13: 0xb82bca M=1 
+    14: 0xb87eaa M=1 
+    15: 0xb8814b M=1 
+    16: 0x42ed5e M=1 
+    17: 0x42edc0 M=1 
+    18: 0x42e159 M=1 
+    19: 0x42ed43 M=1 
+    20: 0xc60ea0 M=1 
+    21: 0x42ed40 M=1 
+    22: 0xbf42fe M=1 
+    23: 0xb87d6f M=1 
+    24: 0xc635ef M=1 
+    25: 0x42ecc2 M=1 
+    26: 0xc60f0f M=1 
+    27: 0xc610d7 M=1 
+    28: 0xc61108 M=1 
+    29: 0xb8816e M=1 
+    30: 0xbc8f1c M=1 
+    31: 0xbcae54 M=1 
+    32: 0xbcb5f4 M=1 
+    33: 0x40b687 M=1 
+    34: 0x535244 M=1 
+    35: 0x536bf4 M=1 
+    36: 0x42eb0f M=1 
+    37: 0x42de64 M=1 
+    38: 0xa41281 M=1 
+    39: 0xb82dea M=1 
+    40: 0xb83002 M=1 
+    41: 0xb87d4f M=1 
+    42: 0xb82df1 M=1 
+    43: 0xb82dd3 M=1 
+    44: 0xb82c23 M=1 
+    45: 0xb82fd1 M=1 
+    46: 0x42ef13 M=1 
+    47: 0x42ef0b M=1 
+    48: 0x42ef0f M=1 
+    49: 0x7f5e53999f13 M=4 
+    50: 0xb8591b M=1 
+    51: 0xb85e48 M=1 
+    52: 0xb82ae3 M=1 
+    53: 0xb85893 M=1 
+    54: 0xb88cdc M=1 
+    55: 0x698000 M=1 
+    56: 0x653f4b M=1 
+    57: 0x54dc65 M=1 
+    58: 0x525120 M=1 
+    59: 0xb88d84 M=1 
+    60: 0xb88d98 M=1 
+    61: 0xb86591 M=1 
+    62: 0xb859de M=1 
+    63: 0xb862de M=1 
+    64: 0xb82d5e M=1 
+    65: 0x967171 M=1 
+    66: 0x964990 M=1 
+    67: 0x448584 M=1 
+    68: 0x5476d7 M=1 
+    69: 0x4f1be0 M=1 
+    70: 0x4f34db M=1 
+    71: 0x4f8a9a M=1 
+    72: 0x5388df M=1 
+    73: 0x573c5a M=1 
+    74: 0x4a4168 M=1 
+    75: 0x42eb03 M=1 
+    76: 0xb82a31 M=1 
+    77: 0xb87f07 M=1 
+    78: 0xb87e76 M=1 
+    79: 0xb87e7e M=1 
+    80: 0xb82a36 M=1 
+    81: 0xb87ede M=1 
+    82: 0xb82a55 M=1 
+    83: 0xb82b08 M=1 
+    84: 0xbcbcff M=1 
+    85: 0xbcbea4 M=1 
+    86: 0xa40112 M=1 
+    87: 0xb85e87 M=1 
+    88: 0xb82d77 M=1 
+    89: 0x79eb32 M=1 
+    90: 0x7a18e8 M=1 
+    91: 0x7a1c44 M=1 
+    92: 0x7a2726 M=1 
+    93: 0x7a2690 M=1 
+    94: 0x89f186 M=1 
+    95: 0xc60eb7 M=1 
+    96: 0x521c7f M=1 
+    97: 0x5194c8 M=1 
+    98: 0xc634f0 M=1 
+    99: 0xc63245 M=1 
+   100: 0xb867d8 M=1 
+   101: 0xb82cf2 M=1 
+   102: 0xb82f82 M=1 
+   103: 0x7f5e538b9a93 M=4 
+   104: 0x7a1955 M=1 
+   105: 0x7f5e538b9a97 M=4 
+   106: 0x7e0f10 M=1 
+   107: 0x7e0b5d M=1 
+   108: 0x6ab44f M=1 
+   109: 0x521d51 M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 cppbench_server_main  
+2: 0x7f5e53061000/0x7f5e53062000/0x0 /lib/libnss_borg-2.15.so  
+3: 0x7f5e53264000/0x7f5e53270000/0x0 /lib/libnss_files-2.15.so  
+4: 0x7f5e53883000/0x7f5e53a31000/0x0 /lib/libc-2.15.so  
+5: 0x7f5e53c3b000/0x7f5e53d36000/0x0 /lib/libm-2.15.so  
+6: 0x7f5e53f37000/0x7f5e53f3e000/0x0 /lib/librt-2.15.so  
+7: 0x7f5e5413f000/0x7f5e54157000/0x0 /lib/libpthread-2.15.so  
+8: 0x7f5e5435c000/0x7f5e5435e000/0x0 /lib/libdl-2.15.so  
+9: 0x7f5e54560000/0x7f5e54569000/0x0 /lib/libcrypt-2.15.so  
+10: 0x7f5e54799000/0x7f5e547bd000/0x0 /lib/ld-2.15.so  
+11: 0x7ffffb56b000/0x7ffffb56d000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth
new file mode 100644
index 0000000..d06f78b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth
@@ -0,0 +1,99 @@
+heap profile:     85: 178257920 [    85: 178257920] @ growthz
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0xafc0eb 0xb087b1 0xb0aa7d 0xb0b374 0xb12f10 0xb13a92 0xb0c443 0xb145f3 0xb147ca 0xa5dddd 0xbbffe6 0xa5e837 0xa65f94 0x5aac9e 0x535526 0x535144 0x5aa468 0x7e3ce7 0x7d13a2 0x7e0d28 0x6ab450 0x538d27 0x5390e8 0x5391e3 0x4e9603 0x4faa17 0x4fc5f6
+     1:  2097152 [     1:  2097152] @ 0xc635c8 0x816900 0x8149fd 0x813aa0 0xbbff77 0x81421c 0x4ed414 0x4fd707 0x4de2a2 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7fcdc2ff214e
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0xbb5783 0x40acd8 0x61192e 0x4b9522 0x4b9f62 0x4ba025 0x40bd86 0x7fcdc276711d
+     1:  2097152 [     1:  2097152] @ 0xb83003 0xb87d50 0xc635f0 0x42d576 0xc25cc6 0x40651b
+--- Memory map: ---
+  00400000-00fcb000: cppbench_server_main
+  7fcdc231e000-7fcdc2321000: /libnss_cache-2.15.so
+  7fcdc2522000-7fcdc252e000: /libnss_files-2.15.so
+  7fcdc272f000-7fcdc28dd000: /libc-2.15.so
+  7fcdc2ae7000-7fcdc2be2000: /libm-2.15.so
+  7fcdc2de3000-7fcdc2dea000: /librt-2.15.so
+  7fcdc2feb000-7fcdc3003000: /libpthread-2.15.so
+  7fcdc3208000-7fcdc320a000: /libdl-2.15.so
+  7fcdc340c000-7fcdc3415000: /libcrypt-2.15.so
+  7fcdc3645000-7fcdc3669000: /ld-2.15.so
+  7fff86bff000-7fff86c00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth.string
new file mode 100644
index 0000000..842ff9f
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.growth.string
@@ -0,0 +1,248 @@
+PeriodType: space bytes
+Period: 1
+Samples:
+objects/count space/bytes
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 14 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 4 5 6 7 8 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 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 
+                bytes:[2097152]
+          1    2097152: 14 42 43 44 45 46 47 48 49 9 10 11 12 13 
+                bytes:[2097152]
+          1    2097152: 1 2 3 50 51 52 53 54 55 56 57 
+                bytes:[2097152]
+          1    2097152: 1 2 3 58 59 60 
+                bytes:[2097152]
+Locations
+     1: 0xb83002 M=1 
+     2: 0xb87d4f M=1 
+     3: 0xc635ef M=1 
+     4: 0x42ecc2 M=1 
+     5: 0x42e14b M=1 
+     6: 0x5261ae M=1 
+     7: 0x526ede M=1 
+     8: 0x5280aa M=1 
+     9: 0x79e809 M=1 
+    10: 0x7a251a M=1 
+    11: 0x7a296c M=1 
+    12: 0xa456e3 M=1 
+    13: 0x7fcdc2ff214d M=7 
+    14: 0xc635c7 M=1 
+    15: 0xafc0ea M=1 
+    16: 0xb087b0 M=1 
+    17: 0xb0aa7c M=1 
+    18: 0xb0b373 M=1 
+    19: 0xb12f0f M=1 
+    20: 0xb13a91 M=1 
+    21: 0xb0c442 M=1 
+    22: 0xb145f2 M=1 
+    23: 0xb147c9 M=1 
+    24: 0xa5dddc M=1 
+    25: 0xbbffe5 M=1 
+    26: 0xa5e836 M=1 
+    27: 0xa65f93 M=1 
+    28: 0x5aac9d M=1 
+    29: 0x535525 M=1 
+    30: 0x535143 M=1 
+    31: 0x5aa467 M=1 
+    32: 0x7e3ce6 M=1 
+    33: 0x7d13a1 M=1 
+    34: 0x7e0d27 M=1 
+    35: 0x6ab44f M=1 
+    36: 0x538d26 M=1 
+    37: 0x5390e7 M=1 
+    38: 0x5391e2 M=1 
+    39: 0x4e9602 M=1 
+    40: 0x4faa16 M=1 
+    41: 0x4fc5f5 M=1 
+    42: 0x8168ff M=1 
+    43: 0x8149fc M=1 
+    44: 0x813a9f M=1 
+    45: 0xbbff76 M=1 
+    46: 0x81421b M=1 
+    47: 0x4ed413 M=1 
+    48: 0x4fd706 M=1 
+    49: 0x4de2a1 M=1 
+    50: 0xbb5782 M=1 
+    51: 0x40acd7 M=1 
+    52: 0x61192d M=1 
+    53: 0x4b9521 M=1 
+    54: 0x4b9f61 M=1 
+    55: 0x4ba024 M=1 
+    56: 0x40bd85 M=1 
+    57: 0x7fcdc276711c M=4 
+    58: 0x42d575 M=1 
+    59: 0xc25cc5 M=1 
+    60: 0x40651a M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 cppbench_server_main  
+2: 0x7fcdc231e000/0x7fcdc2321000/0x0 /libnss_cache-2.15.so  
+3: 0x7fcdc2522000/0x7fcdc252e000/0x0 /libnss_files-2.15.so  
+4: 0x7fcdc272f000/0x7fcdc28dd000/0x0 /libc-2.15.so  
+5: 0x7fcdc2ae7000/0x7fcdc2be2000/0x0 /libm-2.15.so  
+6: 0x7fcdc2de3000/0x7fcdc2dea000/0x0 /librt-2.15.so  
+7: 0x7fcdc2feb000/0x7fcdc3003000/0x0 /libpthread-2.15.so  
+8: 0x7fcdc3208000/0x7fcdc320a000/0x0 /libdl-2.15.so  
+9: 0x7fcdc340c000/0x7fcdc3415000/0x0 /libcrypt-2.15.so  
+10: 0x7fcdc3645000/0x7fcdc3669000/0x0 /ld-2.15.so  
+11: 0x7fff86bff000/0x7fff86c00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap
new file mode 100644
index 0000000..5622250
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap
@@ -0,0 +1,47 @@
+heap profile:    144:  8498176 [   144:  8498176] @ heapz_v2/524288
+     1:     9216 [     1:     9216] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:      144 [     1:      144] @ 0xc635c8 0xa7479b 0xb65e6b 0xb65f80 0xa6d069 0xa6dc80 0xbbffe6 0xa5dd84 0xa7b7c6 0xaa88da 0xaa9db2 0xb59bae 0xb0c39c 0xb145f3 0xb147ca 0xa5dddd 0xbbffe6 0xa5e837 0xa65f94 0x5aac9e 0x535526 0x535144 0x5aa468 0x7e3ce7 0x7d13a2 0x7e0d28 0x6ab450 0x538d27 0x5390e8 0x5391e3 0x4e9603
+     7:   114688 [     7:   114688] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     1792 [     1:     1792] @ 0xc635c8 0x51a272 0x524997 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+    13:   319488 [    13:   319488] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     1792 [     1:     1792] @ 0xc635c8 0xac95a0 0xacdc7c 0xace07b 0xace1ac 0xabd100 0xabe2a9 0x72f52e 0x655376 0x6558d3 0x41c711 0xc25cc6 0x40651b
+     1:  2162688 [     1:  2162688] @ 0xc63568 0xbc462e 0xbc4bb5 0xbc4eda 0x4a57b8 0x4b152c 0x4ae04c 0x4ad225 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:       48 [     1:       48] @ 0xc635c8 0x7be14a 0x7be675 0x6b312d 0xbaa17f 0xbaa142 0xbaabc6 0xbb092c 0x40bce4 0x7f47a4bab11d
+     1:   262144 [     1:   262144] @ 0xc635c8 0x816900 0x8149fd 0x8139f4 0xbbff77 0x81421c 0x4ed414 0x4fd707 0x4de2a2 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:      320 [     1:      320] @ 0xc635c8 0x721a59 0x43005e 0x7382a4 0x430590 0x435425 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     1792 [     1:     1792] @ 0xc635c8 0x5413b0 0x541ab2 0xbaa17f 0xbaabc6 0x53507c 0xbaa17f 0xbaa9f9 0xbb0d21 0x40bce4 0x7f47a4bab11d
+     1:    10240 [     1:    10240] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+    16:   327680 [    16:   327680] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:      160 [     1:      160] @ 0xc635c8 0x578705 0x586247 0x592615 0x592745 0x592cb9 0xa456e4 0x7f47a54360fe
+     1:     8192 [     1:     8192] @ 0xc635c8 0xaaf469 0x52cad7 0x52e89b 0x527f32 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     2:    24576 [     2:    24576] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:  2097152 [     1:  2097152] @ 0xc63568 0xbc463b 0xbc4bb5 0xbc4eda 0x4a57b8 0x4b152c 0x4ae04c 0x4ad225 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:      448 [     1:      448] @ 0xc635c8 0xafca3b 0xb09ba0 0xb09ec0 0xb12fec 0xb13a92 0xb13c93 0xb13d9d 0xa02777 0xbbff77 0xa026ec 0x5701e2 0x53541a 0x535144 0x5aa468 0x7e3ce7 0x7d13a2 0x7e0d28 0x6ab450 0x538d27 0x5390e8 0x5391e3 0x4e9603 0x4faa17 0x4fc5f6 0x4fd028 0x4fd230 0x79e80a 0x7a251b 0x7a296d 0xa456e4
+    47:  1925120 [    47:  1925120] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     6656 [     1:     6656] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+    11:   292864 [    11:   292864] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     4096 [     1:     4096] @ 0xc635c8 0x75373b 0x7eb2d3 0x7ecc87 0x7ece56 0x7ed1ce 0x7ed360 0x7edb1a 0x7edbb5 0x7d50b0 0x4b9ba6 0x4b9f62 0x4ba025 0x40bd86 0x7f47a4bab11d
+     1:      112 [     1:      112] @ 0xc635c8 0x430498 0x435425 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:    20480 [     1:    20480] @ 0xc635c8 0x5a8b92 0x526bff 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:       48 [     1:       48] @ 0xc635c8 0x720c2e 0x5d35f0 0xbaa17f 0xbaabc6 0x42f03d 0xbaa17f 0xbaa9f9 0xbb0d21 0x40bce4 0x7f47a4bab11d
+     1:     8192 [     1:     8192] @ 0xc635c8 0xaaf3e6 0xab0ba0 0xab11be 0xab1639 0x52ebdc 0x527f32 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     2:   131072 [     2:   131072] @ 0xc635c8 0xaaf469 0xaad4ce 0xb66bcd 0xb670f2 0xb659b5 0x63689b 0x548172 0x520cdc 0x521b82 0x5194c9 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:     8192 [     1:     8192] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+     1:      512 [     1:      512] @ 0xc635c8 0xaff12a 0xb0b331 0xb12f10 0xb13a92 0xb0c443 0xb145f3 0xb147ca 0xa5dddd 0xbbffe6 0xa5e837 0xa65f94 0x5aac9e 0x535526 0x535144 0x5aa468 0x7e3ce7 0x7d13a2 0x7e0d28 0x6ab450 0x538d27 0x5390e8 0x5391e3 0x4e9603 0x4faa17 0x4fc5f6 0x4fd028 0x4fd230 0x79e80a 0x7a251b 0x7a296d
+     1:     4608 [     1:     4608] @ 0xc635c8 0x464379 0xa6318d 0x7feee9 0x5ab69c 0x7b0b26 0x79e81a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+    23:   753664 [    23:   753664] @ 0xc635c8 0x42ecc3 0x42e14c 0x5261af 0x526edf 0x5280ab 0x79e80a 0x7a251b 0x7a296d 0xa456e4 0x7f47a54360fe
+--- Memory map: ---
+	source=/home
+  00400000-00fcb000: $source/cppbench_server_main
+  7f47a4351000-7f47a4352000: /lib/libnss_borg-2.15.so
+  7f47a4554000-7f47a4560000: /lib/libnss_files-2.15.so
+  7f47a4b73000-7f47a4d21000: /lib/libc-2.15.so
+  7f47a4f2b000-7f47a5026000: /lib/libm-2.15.so
+  7f47a5227000-7f47a522e000: /lib/librt-2.15.so
+  7f47a542f000-7f47a5447000: /lib/libpthread-2.15.so
+  7f47a564c000-7f47a564e000: /lib/libdl-2.15.so
+  7f47a5850000-7f47a5859000: /lib/libcrypt-2.15.so
+  7f47a5a89000-7f47a5aad000: /lib/ld-2.15.so
+  7fff63dfe000-7fff63e00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
+
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap.string
new file mode 100644
index 0000000..d099e59
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.heap.string
@@ -0,0 +1,237 @@
+PeriodType: space bytes
+Period: 524288
+Samples:
+objects/count space/bytes
+         57     528909: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[9216]
+       3641     524360: 1 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 17 27 28 29 30 31 32 33 34 35 36 37 38 39 40 
+                bytes:[144]
+        227    3727658: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[16384]
+        293     525184: 1 41 42 5 6 7 8 9 10 11 
+                bytes:[1792]
+        283    6976735: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[24576]
+        293     525184: 1 43 44 45 46 47 48 49 50 51 52 53 54 
+                bytes:[1792]
+          1    2198218: 55 56 57 58 59 60 61 62 7 8 9 10 11 
+                bytes:[2162688]
+      10923     524312: 1 63 64 65 66 67 68 69 70 71 
+                bytes:[48]
+          2     666237: 1 72 73 74 75 76 77 78 79 7 8 9 10 11 
+                bytes:[262144]
+       1638     524448: 1 80 81 82 83 84 4 5 6 7 8 9 10 11 
+                bytes:[320]
+        293     525184: 1 85 86 66 68 87 66 88 89 70 71 
+                bytes:[1792]
+         51     529424: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[10240]
+        417    8553514: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[20480]
+       3277     524368: 1 90 91 92 93 94 10 11 
+                bytes:[160]
+         64     528394: 1 95 96 97 98 7 8 9 10 11 
+                bytes:[8192]
+         86    1060911: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[12288]
+          1    2136279: 55 99 57 58 59 60 61 62 7 8 9 10 11 
+                bytes:[2097152]
+       1170     524512: 1 100 101 102 103 104 105 106 107 75 108 109 110 31 32 33 34 35 36 37 38 39 40 111 112 113 114 7 8 9 10 
+                bytes:[448]
+        625   25616628: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[40960]
+         79     527623: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[6656]
+        222    5914839: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[26624]
+        128     526338: 1 115 116 117 118 119 120 121 122 123 124 125 126 127 71 
+                bytes:[4096]
+       4681     524344: 1 128 84 4 5 6 7 8 9 10 11 
+                bytes:[112]
+         26     534594: 1 129 130 6 7 8 9 10 11 
+                bytes:[20480]
+      10923     524312: 1 131 132 66 68 133 66 88 89 70 71 
+                bytes:[48]
+         64     528394: 1 134 135 136 137 138 98 7 8 9 10 11 
+                bytes:[8192]
+         17    1115476: 1 95 139 140 141 142 143 144 145 146 147 4 5 6 7 8 9 10 11 
+                bytes:[65536]
+         64     528394: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[8192]
+       1024     524544: 1 148 149 150 104 151 24 25 26 17 27 28 29 30 31 32 33 34 35 36 37 38 39 40 111 112 113 114 7 8 9 
+                bytes:[512]
+        114     526595: 1 152 153 154 155 156 157 8 9 10 11 
+                bytes:[4608]
+        379   12439381: 1 2 3 4 5 6 7 8 9 10 11 
+                bytes:[32768]
+Locations
+     1: 0xc635c7 M=1 
+     2: 0x42ecc2 M=1 
+     3: 0x42e14b M=1 
+     4: 0x5261ae M=1 
+     5: 0x526ede M=1 
+     6: 0x5280aa M=1 
+     7: 0x79e809 M=1 
+     8: 0x7a251a M=1 
+     9: 0x7a296c M=1 
+    10: 0xa456e3 M=1 
+    11: 0x7f47a54360fd M=7 
+    12: 0xa7479a M=1 
+    13: 0xb65e6a M=1 
+    14: 0xb65f7f M=1 
+    15: 0xa6d068 M=1 
+    16: 0xa6dc7f M=1 
+    17: 0xbbffe5 M=1 
+    18: 0xa5dd83 M=1 
+    19: 0xa7b7c5 M=1 
+    20: 0xaa88d9 M=1 
+    21: 0xaa9db1 M=1 
+    22: 0xb59bad M=1 
+    23: 0xb0c39b M=1 
+    24: 0xb145f2 M=1 
+    25: 0xb147c9 M=1 
+    26: 0xa5dddc M=1 
+    27: 0xa5e836 M=1 
+    28: 0xa65f93 M=1 
+    29: 0x5aac9d M=1 
+    30: 0x535525 M=1 
+    31: 0x535143 M=1 
+    32: 0x5aa467 M=1 
+    33: 0x7e3ce6 M=1 
+    34: 0x7d13a1 M=1 
+    35: 0x7e0d27 M=1 
+    36: 0x6ab44f M=1 
+    37: 0x538d26 M=1 
+    38: 0x5390e7 M=1 
+    39: 0x5391e2 M=1 
+    40: 0x4e9602 M=1 
+    41: 0x51a271 M=1 
+    42: 0x524996 M=1 
+    43: 0xac959f M=1 
+    44: 0xacdc7b M=1 
+    45: 0xace07a M=1 
+    46: 0xace1ab M=1 
+    47: 0xabd0ff M=1 
+    48: 0xabe2a8 M=1 
+    49: 0x72f52d M=1 
+    50: 0x655375 M=1 
+    51: 0x6558d2 M=1 
+    52: 0x41c710 M=1 
+    53: 0xc25cc5 M=1 
+    54: 0x40651a M=1 
+    55: 0xc63567 M=1 
+    56: 0xbc462d M=1 
+    57: 0xbc4bb4 M=1 
+    58: 0xbc4ed9 M=1 
+    59: 0x4a57b7 M=1 
+    60: 0x4b152b M=1 
+    61: 0x4ae04b M=1 
+    62: 0x4ad224 M=1 
+    63: 0x7be149 M=1 
+    64: 0x7be674 M=1 
+    65: 0x6b312c M=1 
+    66: 0xbaa17e M=1 
+    67: 0xbaa141 M=1 
+    68: 0xbaabc5 M=1 
+    69: 0xbb092b M=1 
+    70: 0x40bce3 M=1 
+    71: 0x7f47a4bab11c M=4 
+    72: 0x8168ff M=1 
+    73: 0x8149fc M=1 
+    74: 0x8139f3 M=1 
+    75: 0xbbff76 M=1 
+    76: 0x81421b M=1 
+    77: 0x4ed413 M=1 
+    78: 0x4fd706 M=1 
+    79: 0x4de2a1 M=1 
+    80: 0x721a58 M=1 
+    81: 0x43005d M=1 
+    82: 0x7382a3 M=1 
+    83: 0x43058f M=1 
+    84: 0x435424 M=1 
+    85: 0x5413af M=1 
+    86: 0x541ab1 M=1 
+    87: 0x53507b M=1 
+    88: 0xbaa9f8 M=1 
+    89: 0xbb0d20 M=1 
+    90: 0x578704 M=1 
+    91: 0x586246 M=1 
+    92: 0x592614 M=1 
+    93: 0x592744 M=1 
+    94: 0x592cb8 M=1 
+    95: 0xaaf468 M=1 
+    96: 0x52cad6 M=1 
+    97: 0x52e89a M=1 
+    98: 0x527f31 M=1 
+    99: 0xbc463a M=1 
+   100: 0xafca3a M=1 
+   101: 0xb09b9f M=1 
+   102: 0xb09ebf M=1 
+   103: 0xb12feb M=1 
+   104: 0xb13a91 M=1 
+   105: 0xb13c92 M=1 
+   106: 0xb13d9c M=1 
+   107: 0xa02776 M=1 
+   108: 0xa026eb M=1 
+   109: 0x5701e1 M=1 
+   110: 0x535419 M=1 
+   111: 0x4faa16 M=1 
+   112: 0x4fc5f5 M=1 
+   113: 0x4fd027 M=1 
+   114: 0x4fd22f M=1 
+   115: 0x75373a M=1 
+   116: 0x7eb2d2 M=1 
+   117: 0x7ecc86 M=1 
+   118: 0x7ece55 M=1 
+   119: 0x7ed1cd M=1 
+   120: 0x7ed35f M=1 
+   121: 0x7edb19 M=1 
+   122: 0x7edbb4 M=1 
+   123: 0x7d50af M=1 
+   124: 0x4b9ba5 M=1 
+   125: 0x4b9f61 M=1 
+   126: 0x4ba024 M=1 
+   127: 0x40bd85 M=1 
+   128: 0x430497 M=1 
+   129: 0x5a8b91 M=1 
+   130: 0x526bfe M=1 
+   131: 0x720c2d M=1 
+   132: 0x5d35ef M=1 
+   133: 0x42f03c M=1 
+   134: 0xaaf3e5 M=1 
+   135: 0xab0b9f M=1 
+   136: 0xab11bd M=1 
+   137: 0xab1638 M=1 
+   138: 0x52ebdb M=1 
+   139: 0xaad4cd M=1 
+   140: 0xb66bcc M=1 
+   141: 0xb670f1 M=1 
+   142: 0xb659b4 M=1 
+   143: 0x63689a M=1 
+   144: 0x548171 M=1 
+   145: 0x520cdb M=1 
+   146: 0x521b81 M=1 
+   147: 0x5194c8 M=1 
+   148: 0xaff129 M=1 
+   149: 0xb0b330 M=1 
+   150: 0xb12f0f M=1 
+   151: 0xb0c442 M=1 
+   152: 0x464378 M=1 
+   153: 0xa6318c M=1 
+   154: 0x7feee8 M=1 
+   155: 0x5ab69b M=1 
+   156: 0x7b0b25 M=1 
+   157: 0x79e819 M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 /home/cppbench_server_main  
+2: 0x7f47a4351000/0x7f47a4352000/0x0 /lib/libnss_borg-2.15.so  
+3: 0x7f47a4554000/0x7f47a4560000/0x0 /lib/libnss_files-2.15.so  
+4: 0x7f47a4b73000/0x7f47a4d21000/0x0 /lib/libc-2.15.so  
+5: 0x7f47a4f2b000/0x7f47a5026000/0x0 /lib/libm-2.15.so  
+6: 0x7f47a5227000/0x7f47a522e000/0x0 /lib/librt-2.15.so  
+7: 0x7f47a542f000/0x7f47a5447000/0x0 /lib/libpthread-2.15.so  
+8: 0x7f47a564c000/0x7f47a564e000/0x0 /lib/libdl-2.15.so  
+9: 0x7f47a5850000/0x7f47a5859000/0x0 /lib/libcrypt-2.15.so  
+10: 0x7f47a5a89000/0x7f47a5aad000/0x0 /lib/ld-2.15.so  
+11: 0x7fff63dfe000/0x7fff63e00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread
new file mode 100644
index 0000000..0192dd6
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread
@@ -0,0 +1,29 @@
+--- threadz 1 ---
+
+--- Thread 7f794ab90940 (name: main/14748) stack: ---
+  PC:  0x00bc8f1c: helper(arg *)
+  0x0040be31: main
+  0x7f7949a9811d: __libc_start_main
+--- Thread 7f794964e700 (name: thread1/14751) stack: ---
+  PC:  0x7f794a32bf7d: nanosleep
+  0x7f794a32414e: start_thread
+      creator: 0xa45b96 0xa460b4 0xbaa17f 0xbaa9f9 0xbb0d21 0x40bce4 0x7f7949a9811d
+--- Thread 7f794934c700 (name: thread2/14752) stack: ---
+  PC:  0x00bc8f1c: Wait(int)
+  0x7f794a32414e: start_thread
+      creator: 0xa45b96 0xa48928 0xbaa17f 0xbaa9f9 0xbb0d21 0x40bce4 0x7f7949a9811d
+--- Thread 7f7948978700 (name: thread3/14759) stack: ---
+  [same as previous thread]
+--- Memory map: ---
+  00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main
+  7f794964f000-7f7949652000: /lib/libnss_cache-2.15.so
+  7f7949853000-7f794985f000: /lib/libnss_files-2.15.so
+  7f7949a60000-7f7949c0e000: /lib/libc-2.15.so
+  7f7949e19000-7f7949f14000: /lib/libm-2.15.so
+  7f794a115000-7f794a11c000: /lib/librt-2.15.so
+  7f794a31d000-7f794a335000: /lib/libpthread-2.15.so
+  7f794a53a000-7f794a53d000: /lib/libdl-2.15.so
+  7f794a73e000-7f794a747000: /lib/libcrypt-2.15.so
+  7f794a977000-7f794a99b000: /lib/ld-2.15.so
+  7fffb8dff000-7fffb8e00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all
new file mode 100644
index 0000000..a3f8893
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all
@@ -0,0 +1,33 @@
+--- threadz 1 ---
+
+--- Thread 7eff063d9940 (name: main/25376) stack: ---
+  PC:  0x00bc8f1c: helper(arg*)
+  0x0040be31: main
+  0x7eff052e111d: __libc_start_main
+--- Thread 7eff04e97700 (name: thread1/25379) stack: ---
+  PC:  0x7eff05b74f7d: nanosleep
+  0x7eff05b6d14e: start_thread
+      creator:
+  0x0040bce4: main
+  0x7eff052e111d: __libc_start_main
+--- Thread 7eff04770700 (name: thread2/25382) stack: ---
+  PC:  0x00bc8f1c: Wait(int)
+  0x7eff05b6d14e: start_thread
+      creator:
+  0x0040bd6e: main
+  0x7eff052e111d: __libc_start_main
+--- Thread 7eff0464d700 (name: thread3/25383) stack: ---
+  [same as previous thread]
+--- Memory map: ---
+  00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main
+  7eff04e98000-7eff04e9b000: /lib/libnss_cache-2.15.so
+  7eff0509c000-7eff050a8000: /lib/libnss_files-2.15.so
+  7eff052a9000-7eff05457000: /lib/libc-2.15.so
+  7eff05662000-7eff0575d000: /lib/libm-2.15.so
+  7eff0595e000-7eff05965000: /lib/librt-2.15.so
+  7eff05b66000-7eff05b7e000: /lib/libpthread-2.15.so
+  7eff05d83000-7eff05d86000: /lib/libdl-2.15.so
+  7eff05f87000-7eff05f90000: /lib/libcrypt-2.15.so
+  7eff061c0000-7eff061e4000: /lib/ld-2.15.so
+  7fff2edff000-7fff2ee00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all.string
new file mode 100644
index 0000000..c7c0f02
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.all.string
@@ -0,0 +1,28 @@
+PeriodType: thread count
+Period: 1
+Samples:
+thread/count
+          1: 1 2 3 
+          1: 4 5 6 3 
+          2: 1 5 7 3 
+Locations
+     1: 0xbc8f1c M=1 
+     2: 0x40be30 M=1 
+     3: 0x7eff052e111c M=4 
+     4: 0x7eff05b74f7d M=7 
+     5: 0x7eff05b6d14d M=7 
+     6: 0x40bce3 M=1 
+     7: 0x40bd6d M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 /home/rsilvera/cppbench/cppbench_server_main  
+2: 0x7eff04e98000/0x7eff04e9b000/0x0 /lib/libnss_cache-2.15.so  
+3: 0x7eff0509c000/0x7eff050a8000/0x0 /lib/libnss_files-2.15.so  
+4: 0x7eff052a9000/0x7eff05457000/0x0 /lib/libc-2.15.so  
+5: 0x7eff05662000/0x7eff0575d000/0x0 /lib/libm-2.15.so  
+6: 0x7eff0595e000/0x7eff05965000/0x0 /lib/librt-2.15.so  
+7: 0x7eff05b66000/0x7eff05b7e000/0x0 /lib/libpthread-2.15.so  
+8: 0x7eff05d83000/0x7eff05d86000/0x0 /lib/libdl-2.15.so  
+9: 0x7eff05f87000/0x7eff05f90000/0x0 /lib/libcrypt-2.15.so  
+10: 0x7eff061c0000/0x7eff061e4000/0x0 /lib/ld-2.15.so  
+11: 0x7fff2edff000/0x7fff2ee00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none
new file mode 100644
index 0000000..6ab2421
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none
@@ -0,0 +1,27 @@
+--- threadz 1 ---
+
+--- Thread 7eff063d9940 (name: main/25376) stack: ---
+  PC: 0xbc8f1c 0xbcae55 0xbcb5f5 0x40b688 0x4d5f51 0x40be31 0x7eff052e111d
+--- Thread 7eff04b95700 (name: thread1/25380) stack: ---
+  PC: 0xbc8f1c 0xbcbd00 0xa47f60 0xa456e4 0x7eff05b6d14e
+      creator: 0xa45b96 0xa48928 0xbaa17f 0xbaa9f9 0xbb0d21 0x40bce4 0x7eff052e111d
+--- Thread 7eff04893700 (name: thread2/25381) stack: ---
+  PC: 0x7eff052dfa93 0x7a1956 0x7a1c45 0x7a2727 0x7a296d 0xa456e4
+      0x7eff05b6d14e
+      creator: 0xa45b96 0x7a37d2 0x7a3e8d 0xbbff77 0x79ec1c 0x40bd6e 0x7eff052e111d
+--- Thread 7eff04770700 (name: thread3/25382) stack: ---
+  PC: 0xbc8f1c 0x7a2691 0x7a296d 0xa456e4 0x7eff05b6d14e
+      creator: 0xa45b96 0x7a37d2 0x7a3e8d 0xbbff77 0x79ec1c 0x40bd6e 0x7eff052e111d
+--- Memory map: ---
+  00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main.unstripped
+  7eff04e98000-7eff04e9b000: /lib/libnss_cache-2.15.so
+  7eff0509c000-7eff050a8000: /lib/libnss_files-2.15.so
+  7eff052a9000-7eff05457000: /lib/libc-2.15.so
+  7eff05662000-7eff0575d000: /lib/libm-2.15.so
+  7eff0595e000-7eff05965000: /lib/librt-2.15.so
+  7eff05b66000-7eff05b7e000: /lib/libpthread-2.15.so
+  7eff05d83000-7eff05d86000: /lib/libdl-2.15.so
+  7eff05f87000-7eff05f90000: /lib/libcrypt-2.15.so
+  7eff061c0000-7eff061e4000: /lib/ld-2.15.so
+  7fff2edff000-7fff2ee00000: [vdso]
+  ffffffffff600000-ffffffffff601000: [vsyscall]
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none.string
new file mode 100644
index 0000000..af0ad3c
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.none.string
@@ -0,0 +1,50 @@
+PeriodType: thread count
+Period: 1
+Samples:
+thread/count
+          1: 1 2 3 4 5 6 7 
+          1: 1 8 9 10 11 12 13 14 15 16 17 7 
+          1: 18 19 20 21 22 10 11 12 23 24 25 26 27 7 
+          1: 1 28 22 10 11 12 23 24 25 26 27 7 
+Locations
+     1: 0xbc8f1c M=1 
+     2: 0xbcae54 M=1 
+     3: 0xbcb5f4 M=1 
+     4: 0x40b687 M=1 
+     5: 0x4d5f50 M=1 
+     6: 0x40be30 M=1 
+     7: 0x7eff052e111c M=4 
+     8: 0xbcbcff M=1 
+     9: 0xa47f5f M=1 
+    10: 0xa456e3 M=1 
+    11: 0x7eff05b6d14d M=7 
+    12: 0xa45b95 M=1 
+    13: 0xa48927 M=1 
+    14: 0xbaa17e M=1 
+    15: 0xbaa9f8 M=1 
+    16: 0xbb0d20 M=1 
+    17: 0x40bce3 M=1 
+    18: 0x7eff052dfa93 M=4 
+    19: 0x7a1955 M=1 
+    20: 0x7a1c44 M=1 
+    21: 0x7a2726 M=1 
+    22: 0x7a296c M=1 
+    23: 0x7a37d1 M=1 
+    24: 0x7a3e8c M=1 
+    25: 0xbbff76 M=1 
+    26: 0x79ec1b M=1 
+    27: 0x40bd6d M=1 
+    28: 0x7a2690 M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 /home/rsilvera/cppbench/cppbench_server_main.unstripped  
+2: 0x7eff04e98000/0x7eff04e9b000/0x0 /lib/libnss_cache-2.15.so  
+3: 0x7eff0509c000/0x7eff050a8000/0x0 /lib/libnss_files-2.15.so  
+4: 0x7eff052a9000/0x7eff05457000/0x0 /lib/libc-2.15.so  
+5: 0x7eff05662000/0x7eff0575d000/0x0 /lib/libm-2.15.so  
+6: 0x7eff0595e000/0x7eff05965000/0x0 /lib/librt-2.15.so  
+7: 0x7eff05b66000/0x7eff05b7e000/0x0 /lib/libpthread-2.15.so  
+8: 0x7eff05d83000/0x7eff05d86000/0x0 /lib/libdl-2.15.so  
+9: 0x7eff05f87000/0x7eff05f90000/0x0 /lib/libcrypt-2.15.so  
+10: 0x7eff061c0000/0x7eff061e4000/0x0 /lib/ld-2.15.so  
+11: 0x7fff2edff000/0x7fff2ee00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.string
new file mode 100644
index 0000000..bf3f0f3
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/cppbench.thread.string
@@ -0,0 +1,33 @@
+PeriodType: thread count
+Period: 1
+Samples:
+thread/count
+          1: 1 2 3 
+          1: 4 5 6 7 8 9 10 11 3 
+          2: 1 5 6 12 8 9 10 11 3 
+Locations
+     1: 0xbc8f1c M=1 
+     2: 0x40be30 M=1 
+     3: 0x7f7949a9811c M=4 
+     4: 0x7f794a32bf7d M=7 
+     5: 0x7f794a32414d M=7 
+     6: 0xa45b95 M=1 
+     7: 0xa460b3 M=1 
+     8: 0xbaa17e M=1 
+     9: 0xbaa9f8 M=1 
+    10: 0xbb0d20 M=1 
+    11: 0x40bce3 M=1 
+    12: 0xa48927 M=1 
+Mappings
+1: 0x400000/0xfcb000/0x0 /home/rsilvera/cppbench/cppbench_server_main  
+2: 0x7f794964f000/0x7f7949652000/0x0 /lib/libnss_cache-2.15.so  
+3: 0x7f7949853000/0x7f794985f000/0x0 /lib/libnss_files-2.15.so  
+4: 0x7f7949a60000/0x7f7949c0e000/0x0 /lib/libc-2.15.so  
+5: 0x7f7949e19000/0x7f7949f14000/0x0 /lib/libm-2.15.so  
+6: 0x7f794a115000/0x7f794a11c000/0x0 /lib/librt-2.15.so  
+7: 0x7f794a31d000/0x7f794a335000/0x0 /lib/libpthread-2.15.so  
+8: 0x7f794a53a000/0x7f794a53d000/0x0 /lib/libdl-2.15.so  
+9: 0x7f794a73e000/0x7f794a747000/0x0 /lib/libcrypt-2.15.so  
+10: 0x7f794a977000/0x7f794a99b000/0x0 /lib/ld-2.15.so  
+11: 0x7fffb8dff000/0x7fffb8e00000/0x0 [vdso]  
+12: 0xffffffffff600000/0xffffffffff601000/0x0 [vsyscall]  
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu
new file mode 100644
index 0000000..ce08313
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu.string
new file mode 100644
index 0000000..c2838b8
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.crc32.cpu.string
@@ -0,0 +1,87 @@
+PeriodType: cpu nanoseconds
+Period: 10000000
+Samples:
+samples/count cpu/nanoseconds
+          1   10000000: 1 2 3 4 5 
+          2   20000000: 6 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          2   20000000: 8 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          4   40000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          2   20000000: 6 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          2   20000000: 6 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          2   20000000: 8 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          2   20000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          3   30000000: 7 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          2   20000000: 1 2 3 4 5 
+          2   20000000: 7 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          2   20000000: 7 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+          2   20000000: 6 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 6 2 3 4 5 
+          1   10000000: 8 2 3 4 5 
+          1   10000000: 1 2 3 4 5 
+         85  850000000: 9 2 3 4 5 
+         21  210000000: 10 2 3 4 5 
+          1   10000000: 7 2 3 4 5 
+         24  240000000: 11 2 3 4 5 
+Locations
+     1: 0x430b93 M=1 
+     2: 0x4317eb M=1 
+     3: 0x42a065 M=1 
+     4: 0x42a31b M=1 
+     5: 0x415d0f M=1 
+     6: 0x430baa M=1 
+     7: 0x430bb5 M=1 
+     8: 0x430ba6 M=1 
+     9: 0x430bac M=1 
+    10: 0x430b9f M=1 
+    11: 0x430bb3 M=1 
+Mappings
+1: 0x0/0xffffffffffffffff/0x0   
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread
new file mode 100644
index 0000000..1c8582b
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread
@@ -0,0 +1,8 @@
+threadcreate profile: total 7
+1 @ 0x44cb3 0x45045 0x45323 0x45534 0x47e9c 0x47c98 0x44ba2 0x2720fe 0x271fb5
+1 @ 0x44cb3 0x45045 0x45323 0x45534 0x46716 0x51584 0x461e0
+1 @ 0x44cb3 0x45045 0x45323 0x45547 0x46716 0x40963 0x461e0
+1 @ 0x44cb3 0x45045 0x45323 0x45547 0x4562e 0x460ed 0x51a59
+1 @ 0x44cb3 0x45045 0x441ae 0x461e0
+1 @ 0x44cb3 0x44e04 0x44b80 0x5192d
+1 @ 0x440e2 0x5191a
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread.string
new file mode 100644
index 0000000..095f7ce
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/go.godoc.thread.string
@@ -0,0 +1,37 @@
+PeriodType: threadcreate count
+Period: 1
+Samples:
+threadcreate/count
+          1: 1 2 3 4 5 6 7 8 9 
+          1: 1 2 3 4 10 11 12 
+          1: 1 2 3 13 10 14 12 
+          1: 1 2 3 13 15 16 17 
+          1: 1 2 18 12 
+          1: 1 19 20 21 
+          1: 22 23 
+Locations
+     1: 0x44cb2 M=1 
+     2: 0x45044 M=1 
+     3: 0x45322 M=1 
+     4: 0x45533 M=1 
+     5: 0x47e9b M=1 
+     6: 0x47c97 M=1 
+     7: 0x44ba1 M=1 
+     8: 0x2720fd M=1 
+     9: 0x271fb4 M=1 
+    10: 0x46715 M=1 
+    11: 0x51583 M=1 
+    12: 0x461df M=1 
+    13: 0x45546 M=1 
+    14: 0x40962 M=1 
+    15: 0x4562d M=1 
+    16: 0x460ec M=1 
+    17: 0x51a58 M=1 
+    18: 0x441ad M=1 
+    19: 0x44e03 M=1 
+    20: 0x44b7f M=1 
+    21: 0x5192c M=1 
+    22: 0x440e1 M=1 
+    23: 0x51919 M=1 
+Mappings
+1: 0x0/0xffffffffffffffff/0x0   
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu
new file mode 100644
index 0000000..e921d21
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu.string
new file mode 100644
index 0000000..7df1533
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.cpu.string
@@ -0,0 +1,415 @@
+PeriodType: cpu nanoseconds
+Period: 10000000
+Samples:
+samples/count cpu/nanoseconds
+          1   10000000: 1 2 
+          1   10000000: 3 2 
+          1   10000000: 4 2 
+          1   10000000: 5 2 
+          1   10000000: 6 2 
+          1   10000000: 7 2 
+          1   10000000: 8 2 
+          1   10000000: 9 2 
+          1   10000000: 10 2 
+          1   10000000: 11 2 
+          1   10000000: 12 2 
+          1   10000000: 13 2 
+          1   10000000: 14 2 
+          1   10000000: 15 2 
+          1   10000000: 16 2 
+          1   10000000: 17 2 
+          1   10000000: 18 2 
+          1   10000000: 16 2 
+          1   10000000: 19 2 
+          1   10000000: 20 2 
+          1   10000000: 21 2 
+          1   10000000: 22 2 
+          1   10000000: 23 2 
+          1   10000000: 24 2 
+          1   10000000: 25 2 
+          1   10000000: 15 2 
+          1   10000000: 26 2 
+          1   10000000: 9 2 
+          1   10000000: 27 2 
+          1   10000000: 28 2 
+          1   10000000: 29 2 
+          1   10000000: 30 2 
+          1   10000000: 31 2 
+          1   10000000: 32 2 
+          1   10000000: 24 2 
+          1   10000000: 30 2 
+          1   10000000: 33 2 
+          1   10000000: 34 2 
+          1   10000000: 35 2 
+          1   10000000: 36 2 
+          1   10000000: 27 2 
+          1   10000000: 37 2 
+          1   10000000: 38 2 
+          1   10000000: 19 2 
+          1   10000000: 39 2 
+          1   10000000: 40 2 
+          1   10000000: 41 2 
+          1   10000000: 16 2 
+          1   10000000: 42 2 
+          1   10000000: 43 2 
+          1   10000000: 44 2 
+          1   10000000: 45 2 
+          1   10000000: 46 2 
+          1   10000000: 47 2 
+          1   10000000: 48 2 
+          1   10000000: 40 2 
+          1   10000000: 10 2 
+          1   10000000: 49 2 
+          1   10000000: 50 2 
+          1   10000000: 51 2 
+          1   10000000: 52 2 
+          1   10000000: 53 2 
+          1   10000000: 30 2 
+          1   10000000: 54 2 
+          1   10000000: 55 2 
+          1   10000000: 36 2 
+          1   10000000: 56 2 
+          1   10000000: 57 2 
+          1   10000000: 58 2 
+          1   10000000: 59 2 
+          1   10000000: 60 2 
+          1   10000000: 61 2 
+          1   10000000: 57 2 
+          1   10000000: 62 2 
+          1   10000000: 63 2 
+          1   10000000: 30 2 
+          1   10000000: 64 2 
+          1   10000000: 16 2 
+          1   10000000: 65 2 
+          1   10000000: 26 2 
+          1   10000000: 40 2 
+          1   10000000: 66 2 
+          1   10000000: 58 2 
+          1   10000000: 67 2 
+          1   10000000: 68 2 
+          1   10000000: 69 2 
+          1   10000000: 70 2 
+          1   10000000: 71 2 
+          1   10000000: 72 2 
+          1   10000000: 51 2 
+          1   10000000: 73 2 
+          1   10000000: 74 2 
+          1   10000000: 75 2 
+          1   10000000: 76 2 
+          1   10000000: 77 2 
+          1   10000000: 78 2 
+          1   10000000: 79 2 
+          1   10000000: 80 2 
+          1   10000000: 81 2 
+          1   10000000: 82 2 
+          1   10000000: 83 2 
+          1   10000000: 84 2 
+          1   10000000: 85 2 
+          1   10000000: 86 2 
+          1   10000000: 10 2 
+          1   10000000: 87 2 
+          1   10000000: 88 2 
+          1   10000000: 89 2 
+          1   10000000: 90 2 
+          1   10000000: 63 2 
+          1   10000000: 91 2 
+          1   10000000: 5 2 
+          1   10000000: 92 2 
+          1   10000000: 93 2 
+          1   10000000: 94 2 
+          1   10000000: 19 2 
+          1   10000000: 95 2 
+          1   10000000: 30 2 
+          1   10000000: 96 2 
+          1   10000000: 10 2 
+          1   10000000: 97 2 
+          1   10000000: 98 2 
+          1   10000000: 99 2 
+          1   10000000: 62 2 
+          1   10000000: 92 2 
+          1   10000000: 100 2 
+          1   10000000: 101 2 
+          1   10000000: 39 2 
+          1   10000000: 102 2 
+          1   10000000: 86 2 
+          1   10000000: 33 2 
+          1   10000000: 103 2 
+          1   10000000: 104 2 
+          1   10000000: 13 2 
+          2   20000000: 105 2 
+          1   10000000: 106 2 
+          1   10000000: 52 2 
+          1   10000000: 24 2 
+          1   10000000: 107 2 
+          1   10000000: 108 2 
+          1   10000000: 52 2 
+          1   10000000: 109 2 
+          1   10000000: 5 2 
+          1   10000000: 82 2 
+          1   10000000: 8 2 
+          1   10000000: 110 2 
+          1   10000000: 111 2 
+          1   10000000: 112 2 
+          1   10000000: 113 2 
+          1   10000000: 114 2 
+          1   10000000: 115 2 
+          1   10000000: 116 2 
+          1   10000000: 19 2 
+          1   10000000: 64 2 
+          1   10000000: 106 2 
+          1   10000000: 117 2 
+          1   10000000: 30 2 
+          1   10000000: 118 2 
+          1   10000000: 86 2 
+          1   10000000: 119 2 
+          1   10000000: 120 2 
+          1   10000000: 121 2 
+          1   10000000: 81 2 
+          2   20000000: 10 2 
+          1   10000000: 19 2 
+          1   10000000: 122 2 
+          1   10000000: 123 2 
+          1   10000000: 105 2 
+          1   10000000: 124 2 
+          1   10000000: 125 2 
+          1   10000000: 46 2 
+          1   10000000: 8 2 
+         10  100000000: 21 2 
+          7   70000000: 126 2 
+          3   30000000: 9 2 
+          1   10000000: 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 
+          1   10000000: 144 2 
+          5   50000000: 145 2 
+         25  250000000: 146 2 
+          1   10000000: 147 2 
+          1   10000000: 148 149 150 134 135 136 137 138 139 140 141 142 143 
+          1   10000000: 151 152 153 154 155 135 136 137 138 139 140 141 142 143 
+          1   10000000: 156 157 153 154 155 135 136 137 138 139 140 141 142 143 
+          1   10000000: 158 159 132 133 134 135 136 137 138 139 140 141 142 143 
+          4   40000000: 27 2 
+          4   40000000: 160 2 
+          1   10000000: 116 2 
+          5   50000000: 161 2 
+         20  200000000: 162 163 164 135 136 137 138 139 140 141 142 143 
+          1   10000000: 165 166 167 164 135 136 137 138 139 140 141 142 143 
+          1   10000000: 168 169 167 164 135 136 137 138 139 140 141 142 143 
+          2   20000000: 170 171 172 142 143 
+          2   20000000: 173 171 172 142 143 
+          1   10000000: 105 174 175 154 155 176 177 140 141 142 143 
+          1   10000000: 178 179 176 177 140 141 142 143 
+          1   10000000: 180 181 182 181 183 184 185 186 187 188 189 190 191 192 193 194 143 
+          7   70000000: 195 2 
+          2   20000000: 196 2 
+          8   80000000: 16 2 
+          1   10000000: 197 2 
+          1   10000000: 146 198 199 135 136 137 138 139 140 141 142 143 
+          1   10000000: 200 199 135 136 137 138 139 140 141 142 143 
+          3   30000000: 162 179 135 136 137 138 139 140 141 142 143 
+          1   10000000: 201 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 
+          1   10000000: 202 167 152 153 154 155 135 136 137 138 139 140 141 142 143 
+          6   60000000: 162 163 152 153 154 155 135 136 137 138 139 140 141 142 143 
+Locations
+     1: 0x410bc0 M=1 
+     2: 0x41a770 M=1 
+     3: 0x410b4b M=1 
+     4: 0x40f534 M=1 
+     5: 0x40f018 M=1 
+     6: 0x421f4f M=1 
+     7: 0x40e46f M=1 
+     8: 0x40f0e3 M=1 
+     9: 0x4286c7 M=1 
+    10: 0x40f15b M=1 
+    11: 0x40efb1 M=1 
+    12: 0x41250d M=1 
+    13: 0x427854 M=1 
+    14: 0x40e688 M=1 
+    15: 0x410b61 M=1 
+    16: 0x40fa72 M=1 
+    17: 0x40e92a M=1 
+    18: 0x421ff1 M=1 
+    19: 0x42830d M=1 
+    20: 0x41cf23 M=1 
+    21: 0x40e7cb M=1 
+    22: 0x40ea46 M=1 
+    23: 0x40f792 M=1 
+    24: 0x40f023 M=1 
+    25: 0x40ee50 M=1 
+    26: 0x40c6ab M=1 
+    27: 0x40fa51 M=1 
+    28: 0x40f14b M=1 
+    29: 0x421fca M=1 
+    30: 0x4285d3 M=1 
+    31: 0x410ba9 M=1 
+    32: 0x40e75f M=1 
+    33: 0x4277a1 M=1 
+    34: 0x40e89f M=1 
+    35: 0x40ea54 M=1 
+    36: 0x40f0ab M=1 
+    37: 0x40ef9b M=1 
+    38: 0x410d6a M=1 
+    39: 0x40e455 M=1 
+    40: 0x427856 M=1 
+    41: 0x40e80b M=1 
+    42: 0x40f5ef M=1 
+    43: 0x40fb2a M=1 
+    44: 0x422786 M=1 
+    45: 0x40f031 M=1 
+    46: 0x40f49d M=1 
+    47: 0x40f331 M=1 
+    48: 0x40e927 M=1 
+    49: 0x40f558 M=1 
+    50: 0x410b56 M=1 
+    51: 0x40eac1 M=1 
+    52: 0x40e813 M=1 
+    53: 0x40e7df M=1 
+    54: 0x40f53d M=1 
+    55: 0x40f180 M=1 
+    56: 0x410b94 M=1 
+    57: 0x40fbf6 M=1 
+    58: 0x40f026 M=1 
+    59: 0x40f0dc M=1 
+    60: 0x40e9d3 M=1 
+    61: 0x40fa7b M=1 
+    62: 0x40e877 M=1 
+    63: 0x4048a8 M=1 
+    64: 0x40f02e M=1 
+    65: 0x4048b8 M=1 
+    66: 0x4277d0 M=1 
+    67: 0x40f5cb M=1 
+    68: 0x40fbae M=1 
+    69: 0x40e8c2 M=1 
+    70: 0x40f64b M=1 
+    71: 0x40e82e M=1 
+    72: 0x421f22 M=1 
+    73: 0x40fa67 M=1 
+    74: 0x40fbb1 M=1 
+    75: 0x40f568 M=1 
+    76: 0x40e461 M=1 
+    77: 0x40ef85 M=1 
+    78: 0x40f58b M=1 
+    79: 0x40f08d M=1 
+    80: 0x40e75c M=1 
+    81: 0x410c22 M=1 
+    82: 0x40fa59 M=1 
+    83: 0x40f091 M=1 
+    84: 0x40eb69 M=1 
+    85: 0x41075a M=1 
+    86: 0x40e7e9 M=1 
+    87: 0x40fa97 M=1 
+    88: 0x4131eb M=1 
+    89: 0x40f769 M=1 
+    90: 0x40f54e M=1 
+    91: 0x4277d5 M=1 
+    92: 0x40f0ca M=1 
+    93: 0x40f051 M=1 
+    94: 0x40e94f M=1 
+    95: 0x40fc11 M=1 
+    96: 0x41815b M=1 
+    97: 0x40f4b3 M=1 
+    98: 0x421fe8 M=1 
+    99: 0x40e79e M=1 
+   100: 0x413f29 M=1 
+   101: 0x427822 M=1 
+   102: 0x40ef3d M=1 
+   103: 0x40e440 M=1 
+   104: 0x40e767 M=1 
+   105: 0x42783b M=1 
+   106: 0x40fa85 M=1 
+   107: 0x40fb36 M=1 
+   108: 0x410bae M=1 
+   109: 0x40f0d7 M=1 
+   110: 0x410ba4 M=1 
+   111: 0x40e87b M=1 
+   112: 0x40e7c0 M=1 
+   113: 0x40eae0 M=1 
+   114: 0x410a99 M=1 
+   115: 0x40e7bd M=1 
+   116: 0x40f09d M=1 
+   117: 0x410b70 M=1 
+   118: 0x40f32d M=1 
+   119: 0x4283ec M=1 
+   120: 0x40f010 M=1 
+   121: 0x40e97a M=1 
+   122: 0x40f19a M=1 
+   123: 0x40e779 M=1 
+   124: 0x40f61d M=1 
+   125: 0x40f4e1 M=1 
+   126: 0x40f58f M=1 
+   127: 0x41ef43 M=1 
+   128: 0x41ef96 M=1 
+   129: 0x41f089 M=1 
+   130: 0x41f360 M=1 
+   131: 0x41fc8e M=1 
+   132: 0x4204c7 M=1 
+   133: 0x422b03 M=1 
+   134: 0x420cee M=1 
+   135: 0x422150 M=1 
+   136: 0x4221d9 M=1 
+   137: 0x41dc0c M=1 
+   138: 0x41db47 M=1 
+   139: 0x672125 M=1 
+   140: 0x4ac6fd M=1 
+   141: 0x4abf98 M=1 
+   142: 0x491fbd M=1 
+   143: 0x41931f M=1 
+   144: 0x40e844 M=1 
+   145: 0x421ff8 M=1 
+   146: 0x4277e4 M=1 
+   147: 0x40e990 M=1 
+   148: 0x41c53f M=1 
+   149: 0x422746 M=1 
+   150: 0x422b42 M=1 
+   151: 0x412b5f M=1 
+   152: 0x40d47b M=1 
+   153: 0x40cf5e M=1 
+   154: 0x40cceb M=1 
+   155: 0x420b5e M=1 
+   156: 0x413ab9 M=1 
+   157: 0x40d56e M=1 
+   158: 0x41f5a6 M=1 
+   159: 0x420149 M=1 
+   160: 0x40f531 M=1 
+   161: 0x410b8d M=1 
+   162: 0x427ac9 M=1 
+   163: 0x412b91 M=1 
+   164: 0x420ee3 M=1 
+   165: 0x4134a8 M=1 
+   166: 0x412dc7 M=1 
+   167: 0x412afa M=1 
+   168: 0x413a9d M=1 
+   169: 0x412bf6 M=1 
+   170: 0x671ed3 M=1 
+   171: 0x4ac6ad M=1 
+   172: 0x4abdd8 M=1 
+   173: 0x671ebe M=1 
+   174: 0x40c8ae M=1 
+   175: 0x40d00a M=1 
+   176: 0x422081 M=1 
+   177: 0x672148 M=1 
+   178: 0x427ad1 M=1 
+   179: 0x420e54 M=1 
+   180: 0x5718ff M=1 
+   181: 0x575ab6 M=1 
+   182: 0x572114 M=1 
+   183: 0x571257 M=1 
+   184: 0x462494 M=1 
+   185: 0x475ea6 M=1 
+   186: 0x473682 M=1 
+   187: 0x471fd7 M=1 
+   188: 0x471ac0 M=1 
+   189: 0x46f1b2 M=1 
+   190: 0x46ef32 M=1 
+   191: 0x4ab9e0 M=1 
+   192: 0x4acce1 M=1 
+   193: 0x4ac7b6 M=1 
+   194: 0x4ace6a M=1 
+   195: 0x410b8a M=1 
+   196: 0x40f56e M=1 
+   197: 0x428176 M=1 
+   198: 0x4120f3 M=1 
+   199: 0x420be8 M=1 
+   200: 0x412100 M=1 
+   201: 0x41ef39 M=1 
+   202: 0x412e38 M=1 
+Mappings
+1: 0x0/0xffffffffffffffff/0x0   
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap
new file mode 100644
index 0000000..ed44903
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap
@@ -0,0 +1,16 @@
+heap profile: 13: 1595680 [47130736: 2584596557304] @ heap/1048576
+1: 524288 [3: 1572864] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x74920f 0x6295ac 0x629855 0x462769 0x419320
+1: 524288 [1: 524288] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x74920f 0x63963f 0x419320
+1: 262144 [1: 262144] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x451a39 0x451ba5 0x450683 0x450077 0x4525a4 0x58e034 0x419320
+1: 262144 [1: 262144] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x451a39 0x451ba5 0x450683 0x450077 0x4524d4 0x401090 0x4011a1 0x416dff 0x419320
+1: 10240 [642: 6574080] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x477637 0x47718b 0x477056 0x4799b2 0x46bfd7 0x419320
+1: 4096 [1: 4096] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x526126 0x5261ea 0x4683d4 0x467e09 0x419320
+1: 4096 [1: 4096] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41db48 0x53fbf3 0x53f85f 0x545f52 0x545a70 0x419320
+1: 2048 [1: 2048] @ 0x420cef 0x420fa9 0x414b22 0x414d20 0x4901be 0x419320
+1: 1280 [1: 1280] @ 0x420cef 0x422082 0x48dbe3 0x48d15c 0x48cdd0 0x4a9dc0 0x545bfe 0x543ac7 0x419320
+1: 384 [1: 384] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41dd68 0x41dcbd 0x429150 0x429add 0x42e013 0x4307e2 0x4366ff 0x42c1c2 0x653e4d 0x64bdc5 0x64c359 0x65a73d 0x64cdb1 0x64be73 0x64c359 0x64c59a 0x64c205 0x64c359 0x64b778 0x5cd55c 0x45dbc3 0x543e70 0x559166 0x55ba54 0x559691 0x559985 0x5a19ff 0x543e70
+1: 288 [1: 288] @ 0x420cef 0x420fa9 0x419e19 0x41a1a8 0x419f63 0x48f09f 0x48d991 0x48cdd0 0x4a9dc0 0x545bfe 0x543ac7 0x419320
+1: 288 [2: 296] @
+1: 96 [1: 96] @ 0x420cef 0x424f35 0x4255d1 0x6fc293 0x6f9c88 0x6f9944 0x6f96be 0x6f966b 0x59f39a 0x468318 0x467e09 0x419320
+0: 0 [1: 1024] @ 0x420cef 0x422151 0x4221da 0x41dc0d 0x41dd68 0x41dcbd 0x6d71a3 0x6da87d 0x7b2c3b 0x419320
+0: 0 [1: 16] @ 0x420cef 0x422048 0x40b517 0x40b746 0x6d9ca2 0x4761c5 0x475ea7 0x46fc4f 0x46f180 0x46ef33 0x4ab821 0x4acc32 0x4ac7b7 0x4ace36 0x419320
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap.string
new file mode 100644
index 0000000..01306ce
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/gobench.heap.string
@@ -0,0 +1,137 @@
+PeriodType: space bytes
+Period: 524288
+Samples:
+alloc_objects/count alloc_space/bytes inuse_objects/count inuse_space/bytes
+          4    2488234          1     829411: 1 2 3 4 5 6 7 8 9 10 
+                bytes:[524288]
+          1     829411          1     829411: 1 2 3 4 5 6 11 10 
+                bytes:[524288]
+          2     666237          2     666237: 1 2 3 4 5 12 13 14 15 16 17 10 
+                bytes:[262144]
+          2     666237          2     666237: 1 2 3 4 5 12 13 14 15 18 19 20 21 10 
+                bytes:[262144]
+      33192  339890635         51     529424: 1 2 3 4 5 22 23 24 25 26 10 
+                bytes:[10240]
+        128     526338        128     526338: 1 2 3 4 5 27 28 29 30 10 
+                bytes:[4096]
+        128     526338        128     526338: 1 2 3 4 5 31 32 33 34 10 
+                bytes:[4096]
+        256     525312        256     525312: 1 35 36 37 38 10 
+                bytes:[2048]
+        410     524928        410     524928: 1 39 40 41 42 43 44 45 10 
+                bytes:[1280]
+       1365     524480       1365     524480: 1 2 3 4 46 47 48 49 50 51 52 53 54 55 56 57 58 59 56 60 61 56 62 63 64 65 66 67 68 69 70 65 
+                bytes:[384]
+       1820     524432       1820     524432: 1 35 71 72 73 74 75 42 43 44 45 10 
+                bytes:[288]
+       7085    1048724       1820     524432: 
+                bytes:[288]
+       5461     524336       5461     524336: 1 76 77 78 79 80 81 82 83 84 30 10 
+                bytes:[96]
+        512     524800          0          0: 1 2 3 4 46 47 85 86 87 10 
+                bytes:[1024]
+      32768     524296          0          0: 1 88 89 90 91 92 93 94 95 96 97 98 99 100 10 
+                bytes:[16]
+Locations
+     1: 0x420cee M=1 
+     2: 0x422150 M=1 
+     3: 0x4221d9 M=1 
+     4: 0x41dc0c M=1 
+     5: 0x41db47 M=1 
+     6: 0x74920e M=1 
+     7: 0x6295ab M=1 
+     8: 0x629854 M=1 
+     9: 0x462768 M=1 
+    10: 0x41931f M=1 
+    11: 0x63963e M=1 
+    12: 0x451a38 M=1 
+    13: 0x451ba4 M=1 
+    14: 0x450682 M=1 
+    15: 0x450076 M=1 
+    16: 0x4525a3 M=1 
+    17: 0x58e033 M=1 
+    18: 0x4524d3 M=1 
+    19: 0x40108f M=1 
+    20: 0x4011a0 M=1 
+    21: 0x416dfe M=1 
+    22: 0x477636 M=1 
+    23: 0x47718a M=1 
+    24: 0x477055 M=1 
+    25: 0x4799b1 M=1 
+    26: 0x46bfd6 M=1 
+    27: 0x526125 M=1 
+    28: 0x5261e9 M=1 
+    29: 0x4683d3 M=1 
+    30: 0x467e08 M=1 
+    31: 0x53fbf2 M=1 
+    32: 0x53f85e M=1 
+    33: 0x545f51 M=1 
+    34: 0x545a6f M=1 
+    35: 0x420fa8 M=1 
+    36: 0x414b21 M=1 
+    37: 0x414d1f M=1 
+    38: 0x4901bd M=1 
+    39: 0x422081 M=1 
+    40: 0x48dbe2 M=1 
+    41: 0x48d15b M=1 
+    42: 0x48cdcf M=1 
+    43: 0x4a9dbf M=1 
+    44: 0x545bfd M=1 
+    45: 0x543ac6 M=1 
+    46: 0x41dd67 M=1 
+    47: 0x41dcbc M=1 
+    48: 0x42914f M=1 
+    49: 0x429adc M=1 
+    50: 0x42e012 M=1 
+    51: 0x4307e1 M=1 
+    52: 0x4366fe M=1 
+    53: 0x42c1c1 M=1 
+    54: 0x653e4c M=1 
+    55: 0x64bdc4 M=1 
+    56: 0x64c358 M=1 
+    57: 0x65a73c M=1 
+    58: 0x64cdb0 M=1 
+    59: 0x64be72 M=1 
+    60: 0x64c599 M=1 
+    61: 0x64c204 M=1 
+    62: 0x64b777 M=1 
+    63: 0x5cd55b M=1 
+    64: 0x45dbc2 M=1 
+    65: 0x543e6f M=1 
+    66: 0x559165 M=1 
+    67: 0x55ba53 M=1 
+    68: 0x559690 M=1 
+    69: 0x559984 M=1 
+    70: 0x5a19fe M=1 
+    71: 0x419e18 M=1 
+    72: 0x41a1a7 M=1 
+    73: 0x419f62 M=1 
+    74: 0x48f09e M=1 
+    75: 0x48d990 M=1 
+    76: 0x424f34 M=1 
+    77: 0x4255d0 M=1 
+    78: 0x6fc292 M=1 
+    79: 0x6f9c87 M=1 
+    80: 0x6f9943 M=1 
+    81: 0x6f96bd M=1 
+    82: 0x6f966a M=1 
+    83: 0x59f399 M=1 
+    84: 0x468317 M=1 
+    85: 0x6d71a2 M=1 
+    86: 0x6da87c M=1 
+    87: 0x7b2c3a M=1 
+    88: 0x422047 M=1 
+    89: 0x40b516 M=1 
+    90: 0x40b745 M=1 
+    91: 0x6d9ca1 M=1 
+    92: 0x4761c4 M=1 
+    93: 0x475ea6 M=1 
+    94: 0x46fc4e M=1 
+    95: 0x46f17f M=1 
+    96: 0x46ef32 M=1 
+    97: 0x4ab820 M=1 
+    98: 0x4acc31 M=1 
+    99: 0x4ac7b6 M=1 
+   100: 0x4ace35 M=1 
+Mappings
+1: 0x0/0xffffffffffffffff/0x0   
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention
new file mode 100644
index 0000000..fb484b7
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention
@@ -0,0 +1,43 @@
+--- contentionz 1 ---
+format = java
+resolution = microseconds
+sampling period = 100
+ms since reset = 6019923
+            1     1 @ 0x00000003 0x00000004
+           14     1 @ 0x0000000d 0x0000000e 0x0000000f 0x00000010 0x00000011 0x00000012 0x00000013 0x00000014 0x00000017 0x00000018 0x00000019 0x0000001a 0x0000001b 0x0000001c 0x00000014 0x00000029 0x0000002a 0x0000002b 0x0000002c 0x0000002d 0x0000002e 0x0000002f 0x00000030 0x00000031 0x00000032 0x00000033 0x00000034 0x00000035
+            2     2 @ 0x00000003 0x00000004
+            2     3 @ 0x00000036 0x00000037 0x00000038
+
+
+ 0x0000003 com.example.function03 (source.java:03)
+ 0x0000004 com.example.function04 (source.java:04)
+ 0x000000d com.example.function0d (source.java:0)
+ 0x000000e com.example.function0e (source.java:0)
+ 0x000000f com.example.function0f (source.java:0)
+ 0x0000010 com.example.function10 (source.java:10)
+ 0x0000011 com.example.function11 (source.java:11)
+ 0x0000012 com.example.function12 (source.java:12)
+ 0x0000013 com.example.function13 (source.java:13)
+ 0x0000014 com.example.function14 (source.java:14)
+ 0x0000017 com.example.function17 (source.java:17)
+ 0x0000018 com.example.function18 (source.java:18)
+ 0x0000019 com.example.function19 (source.java:19)
+ 0x000001a com.example.function1a (source.java:1)
+ 0x000001b com.example.function1b (source.java:1)
+ 0x000001c com.example.function1c (source.java:1)
+ 0x0000029 com.example.function29 (source.java:29)
+ 0x000002a com.example.function2a (source.java:2)
+ 0x000002b com.example.function2b (source.java:2)
+ 0x000002c com.example.function2c (source.java:2)
+ 0x000002d com.example.function2d (source.java:2)
+ 0x000002e com.example.function2e (source.java:2)
+ 0x000002f com.example.function2f (source.java:2)
+ 0x0000030 com.example.function30 (source.java:30)
+ 0x0000031 com.example.function31 (source.java:31)
+ 0x0000032 com.example.function32 (source.java:32)
+ 0x0000033 com.example.function33 (source.java:33)
+ 0x0000034 com.example.function34 (source.java:34)
+ 0x0000035 com.example.function35 (source.java:35)
+ 0x0000036 com.example.function36 (source.java:36)
+ 0x0000037 com.example.function37 (source.java:37)
+ 0x0000038 com.example.function38 (source.java:38)
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention.string
new file mode 100644
index 0000000..1587014
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.contention.string
@@ -0,0 +1,43 @@
+PeriodType: contentions count
+Period: 100
+Duration: 1h40
+Samples:
+contentions/microseconds delay/microseconds
+        100        100: 1 2 
+        100       1400: 3 4 5 6 7 8 9 10 11 12 13 14 15 16 10 17 18 19 20 21 22 23 24 25 26 27 28 29 
+        200        200: 1 2 
+        300        200: 30 31 32 
+Locations
+     1: 0x0 com.example.function03 source.java:3 s=0
+     2: 0x0 com.example.function04 source.java:4 s=0
+     3: 0x0 com.example.function0d source.java:0 s=0
+     4: 0x0 com.example.function0e source.java:0 s=0
+     5: 0x0 com.example.function0f source.java:0 s=0
+     6: 0x0 com.example.function10 source.java:10 s=0
+     7: 0x0 com.example.function11 source.java:11 s=0
+     8: 0x0 com.example.function12 source.java:12 s=0
+     9: 0x0 com.example.function13 source.java:13 s=0
+    10: 0x0 com.example.function14 source.java:14 s=0
+    11: 0x0 com.example.function17 source.java:17 s=0
+    12: 0x0 com.example.function18 source.java:18 s=0
+    13: 0x0 com.example.function19 source.java:19 s=0
+    14: 0x0 com.example.function1a source.java:1 s=0
+    15: 0x0 com.example.function1b source.java:1 s=0
+    16: 0x0 com.example.function1c source.java:1 s=0
+    17: 0x0 com.example.function29 source.java:29 s=0
+    18: 0x0 com.example.function2a source.java:2 s=0
+    19: 0x0 com.example.function2b source.java:2 s=0
+    20: 0x0 com.example.function2c source.java:2 s=0
+    21: 0x0 com.example.function2d source.java:2 s=0
+    22: 0x0 com.example.function2e source.java:2 s=0
+    23: 0x0 com.example.function2f source.java:2 s=0
+    24: 0x0 com.example.function30 source.java:30 s=0
+    25: 0x0 com.example.function31 source.java:31 s=0
+    26: 0x0 com.example.function32 source.java:32 s=0
+    27: 0x0 com.example.function33 source.java:33 s=0
+    28: 0x0 com.example.function34 source.java:34 s=0
+    29: 0x0 com.example.function35 source.java:35 s=0
+    30: 0x0 com.example.function36 source.java:36 s=0
+    31: 0x0 com.example.function37 source.java:37 s=0
+    32: 0x0 com.example.function38 source.java:38 s=0
+Mappings
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu
new file mode 100644
index 0000000..593588b
Binary files /dev/null and b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu differ
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu.string
new file mode 100644
index 0000000..f728cf2
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.cpu.string
@@ -0,0 +1,78 @@
+PeriodType: cpu nanoseconds
+Period: 10000000
+Samples:
+samples/count cpu/nanoseconds
+          0          0: 1 
+          0          0: 2 
+          2   20000000: 3 
+          1   10000000: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
+          1   10000000: 19 20 21 22 23 16 17 18 
+          1   10000000: 24 25 26 27 28 29 30 31 32 
+          1   10000000: 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 29 30 31 32 
+          1   10000000: 54 55 56 57 58 59 60 61 62 11 63 64 16 17 18 
+Locations
+     1: 0x0 GC :0 s=0
+     2: 0x0 Compile :0 s=0
+     3: 0x0 VM :0 s=0
+     4: 0x0 com.example.function06 source.java:6 s=0
+     5: 0x0 com.example.function07 source.java:7 s=0
+     6: 0x0 com.example.function08 source.java:8 s=0
+     7: 0x0 com.example.function09 source.java:9 s=0
+     8: 0x0 com.example.function0a source.java:0 s=0
+     9: 0x0 com.example.function0b source.java:0 s=0
+    10: 0x0 com.example.function0c source.java:0 s=0
+    11: 0x0 com.example.function0d source.java:0 s=0
+    12: 0x0 com.example.function0e source.java:0 s=0
+    13: 0x0 com.example.function0f source.java:0 s=0
+    14: 0x0 com.example.function10 source.java:10 s=0
+    15: 0x0 com.example.function11 source.java:11 s=0
+    16: 0x0 com.example.function12 source.java:12 s=0
+    17: 0x0 com.example.function13 source.java:13 s=0
+    18: 0x0 com.example.function14 source.java:14 s=0
+    19: 0x0 com.example.function1d source.java:1 s=0
+    20: 0x0 com.example.function1e source.java:1 s=0
+    21: 0x0 com.example.function1f source.java:1 s=0
+    22: 0x0 com.example.function20 source.java:20 s=0
+    23: 0x0 com.example.function21 source.java:21 s=0
+    24: 0x0 com.example.function22 source.java:22 s=0
+    25: 0x0 com.example.function23 source.java:23 s=0
+    26: 0x0 com.example.function24 source.java:24 s=0
+    27: 0x0 com.example.function25 source.java:25 s=0
+    28: 0x0 com.example.function26 source.java:26 s=0
+    29: 0x0 com.example.function27 source.java:27 s=0
+    30: 0x0 com.example.function28 source.java:28 s=0
+    31: 0x0 com.example.function29 source.java:29 s=0
+    32: 0x0 com.example.function2a source.java:2 s=0
+    33: 0x0 com.example.function2b source.java:2 s=0
+    34: 0x0 com.example.function2c source.java:2 s=0
+    35: 0x0 com.example.function2d source.java:2 s=0
+    36: 0x0 com.example.function2e source.java:2 s=0
+    37: 0x0 com.example.function2f source.java:2 s=0
+    38: 0x0 com.example.function30 source.java:30 s=0
+    39: 0x0 com.example.function31 source.java:31 s=0
+    40: 0x0 com.example.function32 source.java:32 s=0
+    41: 0x0 com.example.function33 source.java:33 s=0
+    42: 0x0 com.example.function34 source.java:34 s=0
+    43: 0x0 com.example.function35 source.java:35 s=0
+    44: 0x0 com.example.function36 source.java:36 s=0
+    45: 0x0 com.example.function37 source.java:37 s=0
+    46: 0x0 com.example.function38 source.java:38 s=0
+    47: 0x0 com.example.function39 source.java:39 s=0
+    48: 0x0 com.example.function3a source.java:3 s=0
+    49: 0x0 com.example.function3b source.java:3 s=0
+    50: 0x0 com.example.function3c source.java:3 s=0
+    51: 0x0 com.example.function3d source.java:3 s=0
+    52: 0x0 com.example.function3e source.java:3 s=0
+    53: 0x0 com.example.function3f source.java:3 s=0
+    54: 0x0 com.example.function40 source.java:40 s=0
+    55: 0x0 com.example.function41 source.java:41 s=0
+    56: 0x0 com.example.function42 source.java:42 s=0
+    57: 0x0 com.example.function43 source.java:43 s=0
+    58: 0x0 com.example.function44 source.java:44 s=0
+    59: 0x0 com.example.function45 source.java:45 s=0
+    60: 0x0 com.example.function46 source.java:46 s=0
+    61: 0x0 com.example.function47 source.java:47 s=0
+    62: 0x0 com.example.function48 source.java:48 s=0
+    63: 0x0 com.example.function49 source.java:49 s=0
+    64: 0x0 com.example.function4a source.java:4 s=0
+Mappings
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap
new file mode 100644
index 0000000..95e4f6e
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap
@@ -0,0 +1,133 @@
+--- heapz 1 ---
+format = java
+resolution = bytes
+          7048     1 @ 0x00000003 0x00000004 0x00000005 0x00000006 0x00000007 0x00000008 0x00000009 0x0000000a 0x0000000b 0x0000000c 0x0000000d 0x0000000e 0x0000000f 0x00000010 0x00000011 0x00000018 0x00000019 0x0000001a 0x0000001b 0x0000001c 0x0000001d 0x0000001e 0x0000001f 0x00000020 0x00000021 0x00000022 0x00000023 0x00000024 0x00000025 0x00000026 0x00000027 0x00000023 0x00000028 0x00000029 0x0000001d 0x0000001e 0x0000001f 0x00000020 0x00000021 0x00000027 0x00000023 0x00000028 0x00000 [...]
+          4752     9 @ 0x0000002b 0x0000002c 0x0000002d 0x0000002e
+           880     1 @ 0x00000035 0x00000036 0x00000037 0x00000038 0x00000039 0x0000003a 0x0000003b 0x00000011 0x0000003d 0x0000003e 0x0000003f 0x00000040 0x00000041 0x00000042 0x00000011 0x00000049 0x0000004a 0x0000004b 0x0000004c 0x0000004d 0x0000004e 0x0000004b 0x0000004f 0x0000004b 0x00000050 0x00000051 0x00000052 0x00000053 0x00000054 0x00000055 0x00000056 0x00000057
+           560     1 @ 0x00000035 0x00000036 0x00000037 0x00000038 0x00000039 0x0000003a 0x0000003b 0x00000011 0x0000003d 0x0000003e 0x0000003f 0x00000040 0x00000041 0x00000042 0x00000011 0x0000005e 0x0000005f 0x00000060 0x00000061 0x00000062 0x00000063 0x00000064 0x00000065 0x00000066 0x00000067 0x00000068 0x00000069 0x0000006a 0x0000006b 0x0000006c 0x0000006d 0x0000006e 0x0000006f 0x00000070 0x00000071 0x00000072 0x00000073 0x00000074 0x00000075 0x00000067 0x00000068
+           528     1 @ 0x00000076 0x00000077 0x00000078 0x00000079 0x0000007a 0x0000007b 0x00000011 0x00000081 0x00000011 0x00000082 0x0000004e 0x0000004b 0x0000004f 0x0000004b 0x00000050 0x00000051 0x00000052 0x00000053 0x00000054 0x00000055 0x00000056 0x00000057
+           440     1 @ 0x00000083 0x00000084 0x00000085 0x00000086 0x00000087 0x00000088 0x00000089 0x0000008a 0x0000008b 0x0000008c 0x0000008d 0x0000008e 0x0000008f 0x00000090 0x00000091 0x00000092 0x00000093 0x00000094 0x00000095 0x00000096
+           240     5 @ 0x00000097
+
+
+ 0x00000003 com.example.function003 (Source003.java:103)
+ 0x00000004 com.example.function004 (Source004.java:104)
+ 0x00000005 com.example.function005 (Source005.java:105)
+ 0x00000006 com.example.function006 (Source006.java:106)
+ 0x00000007 com.example.function007 (Source007.java:107)
+ 0x00000008 com.example.function008 (Source008.java:108)
+ 0x00000009 com.example.function009 (Source009.java:109)
+ 0x0000000a com.example.function00a (Source00a.java:10)
+ 0x0000000b com.example.function00b (Source00b.java:10)
+ 0x0000000c com.example.function00c (Source00c.java:10)
+ 0x0000000d com.example.function00d (Source00d.java:10)
+ 0x0000000e com.example.function00e (Source00e.java:10)
+ 0x0000000f com.example.function00f (Source00f.java:10)
+ 0x00000010 com.example.function010 (Source010.java:110)
+ 0x00000011 com.example.function011 (Source011.java:111)
+ 0x00000018 com.example.function018 (Source018.java:118)
+ 0x00000019 com.example.function019 (Source019.java:119)
+ 0x0000001a com.example.function01a (Source01a.java:11)
+ 0x0000001b com.example.function01b (Source01b.java:11)
+ 0x0000001c com.example.function01c (Source01c.java:11)
+ 0x0000001d com.example.function01d (Source01d.java:11)
+ 0x0000001e com.example.function01e (Source01e.java:11)
+ 0x0000001f com.example.function01f (Source01f.java:11)
+ 0x00000020 com.example.function020 (Source020.java:120)
+ 0x00000021 com.example.function021 (Source021.java:121)
+ 0x00000022 com.example.function022 (Source022.java:122)
+ 0x00000023 com.example.function023 (Source023.java:123)
+ 0x00000024 com.example.function024 (Source024.java:124)
+ 0x00000025 com.example.function025 (Source025.java:125)
+ 0x00000026 com.example.function026 (Source026.java:126)
+ 0x00000027 com.example.function027 (Source027.java:127)
+ 0x00000028 com.example.function028 (Source028.java:128)
+ 0x00000029 com.example.function029 (Source029.java:129)
+ 0x0000002a com.example.function02a (Source02a.java:12)
+ 0x0000002b com.example.function02b (Source02b.java:12)
+ 0x0000002c com.example.function02c (Source02c.java:12)
+ 0x0000002d com.example.function02d (Source02d.java:12)
+ 0x0000002e com.example.function02e (Source02e.java:12)
+ 0x00000035 com.example.function035 (Source035.java:135)
+ 0x00000036 com.example.function036 (Source036.java:136)
+ 0x00000037 com.example.function037 (Source037.java:137)
+ 0x00000038 com.example.function038 (Source038.java:138)
+ 0x00000039 com.example.function039 (Source039.java:139)
+ 0x0000003a com.example.function03a (Source03a.java:13)
+ 0x0000003b com.example.function03b (Source03b.java:13)
+ 0x0000003d com.example.function03d (Source03d.java:13)
+ 0x0000003e com.example.function03e (Source03e.java:13)
+ 0x0000003f com.example.function03f (Source03f.java:13)
+ 0x00000040 com.example.function040 (Source040.java:140)
+ 0x00000041 com.example.function041 (Source041.java:141)
+ 0x00000042 com.example.function042 (Source042.java:142)
+ 0x00000049 com.example.function049 (Source049.java:149)
+ 0x0000004a com.example.function04a (Source04a.java:14)
+ 0x0000004b com.example.function04b (Source04b.java:14)
+ 0x0000004c com.example.function04c (Source04c.java:14)
+ 0x0000004d com.example.function04d (Source04d.java:14)
+ 0x0000004e com.example.function04e (Source04e.java:14)
+ 0x0000004f com.example.function04f (Source04f.java:14)
+ 0x00000050 com.example.function050 (Source050.java:150)
+ 0x00000051 com.example.function051 (Source051.java:151)
+ 0x00000052 com.example.function052 (Source052.java:152)
+ 0x00000053 com.example.function053 (Source053.java:153)
+ 0x00000054 com.example.function054 (Source054.java:154)
+ 0x00000055 com.example.function055 (Source055.java:155)
+ 0x00000056 com.example.function056 (Source056.java:156)
+ 0x00000057 com.example.function057 (Source057.java:157)
+ 0x0000005a com.example.function05a (Source05a.java:15)
+ 0x0000005e com.example.function05e (Source05e.java:15)
+ 0x0000005f com.example.function05f (Source05f.java:15)
+ 0x00000060 com.example.function060 (Source060.java:160)
+ 0x00000061 com.example.function061 (Source061.java:161)
+ 0x00000062 com.example.function062 (Source062.java:162)
+ 0x00000063 com.example.function063 (Source063.java:163)
+ 0x00000064 com.example.function064 (Source064.java:164)
+ 0x00000065 com.example.function065 (Source065.java:165)
+ 0x00000066 com.example.function066 (Source066.java:166)
+ 0x00000067 com.example.function067 (Source067.java:167)
+ 0x00000068 com.example.function068 (Source068.java:168)
+ 0x00000069 com.example.function069 (Source069.java:169)
+ 0x0000006a com.example.function06a (Source06a.java:16)
+ 0x0000006b com.example.function06b (Source06b.java:16)
+ 0x0000006c com.example.function06c (Source06c.java:16)
+ 0x0000006d com.example.function06d (Source06d.java:16)
+ 0x0000006e com.example.function06e (Source06e.java:16)
+ 0x0000006f com.example.function06f (Source06f.java:16)
+ 0x00000070 com.example.function070 (Source070.java:170)
+ 0x00000071 com.example.function071 (Source071.java:171)
+ 0x00000072 com.example.function072 (Source072.java:172)
+ 0x00000073 com.example.function073 (Source073.java:173)
+ 0x00000074 com.example.function074 (Source074.java:174)
+ 0x00000075 com.example.function075 (Source075.java:175)
+ 0x00000076 com.example.function076 (Source076.java:176)
+ 0x00000077 com.example.function077 (Source077.java:177)
+ 0x00000078 com.example.function078 (Source078.java:178)
+ 0x00000079 com.example.function079 (Source079.java:179)
+ 0x0000007a com.example.function07a (Source07a.java:17)
+ 0x0000007b com.example.function07b (Source07b.java:17)
+ 0x0000007d com.example.function07d (Source07d.java:17)
+ 0x00000081 com.example.function081 (Source081.java:181)
+ 0x00000082 com.example.function082 (Source082.java:182)
+ 0x00000083 com.example.function083 (Source083.java:183)
+ 0x00000084 com.example.function084 (Source084.java:184)
+ 0x00000085 com.example.function085 (Source085.java:185)
+ 0x00000086 com.example.function086 (Source086.java:186)
+ 0x00000087 com.example.function087 (Source087.java:187)
+ 0x00000088 com.example.function088 (Source088.java:188)
+ 0x00000089 com.example.function089 (Source089.java:189)
+ 0x0000008a com.example.function08a (Source08a.java:18)
+ 0x0000008b com.example.function08b (Source08b.java:18)
+ 0x0000008c com.example.function08c (Source08c.java:18)
+ 0x0000008d com.example.function08d (Source08d.java:18)
+ 0x0000008e com.example.function08e (Source08e.java:18)
+ 0x0000008f com.example.function08f (Source08f.java:18)
+ 0x00000090 com.example.function090 (Source090.java:190)
+ 0x00000091 com.example.function091 (Source091.java:191)
+ 0x00000092 com.example.function092 (Source092.java:192)
+ 0x00000093 com.example.function093 (Source093.java:193)
+ 0x00000094 com.example.function094 (Source094.java:194)
+ 0x00000095 com.example.function095 (Source095.java:195)
+ 0x00000096 com.example.function096 (Source096.java:196)
+ 0x00000097 com.example.function097 (Source097.java:197)
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap.string b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap.string
new file mode 100644
index 0000000..261bee1
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/profile/testdata/java.heap.string
@@ -0,0 +1,139 @@
+PeriodType:  
+Period: 0
+Samples:
+inuse_objects/count inuse_space/bytes
+         74     527819: 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 27 32 33 21 22 23 24 25 31 27 32 33 21 22 23 24 25 34 31 27 32 33 21 22 23 24 
+                bytes:[7048]
+       8941    4720968: 35 36 37 38 
+                bytes:[528]
+        596     524728: 39 40 41 42 43 44 45 15 46 47 48 49 50 51 15 52 53 54 55 56 57 54 58 54 59 60 61 62 63 64 65 66 
+                bytes:[880]
+        936     524568: 39 40 41 42 43 44 45 15 46 47 48 49 50 51 15 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 76 77 
+                bytes:[560]
+        993     524552: 91 92 93 94 95 96 15 97 15 98 57 54 58 54 59 60 61 62 63 64 65 66 
+                bytes:[528]
+       1192     524508: 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 
+                bytes:[440]
+      54615    2621560: 119 
+                bytes:[48]
+Locations
+     1: 0x0 com.example.function003 Source003.java:103 s=0
+     2: 0x0 com.example.function004 Source004.java:104 s=0
+     3: 0x0 com.example.function005 Source005.java:105 s=0
+     4: 0x0 com.example.function006 Source006.java:106 s=0
+     5: 0x0 com.example.function007 Source007.java:107 s=0
+     6: 0x0 com.example.function008 Source008.java:108 s=0
+     7: 0x0 com.example.function009 Source009.java:109 s=0
+     8: 0x0 com.example.function00a Source00a.java:10 s=0
+     9: 0x0 com.example.function00b Source00b.java:10 s=0
+    10: 0x0 com.example.function00c Source00c.java:10 s=0
+    11: 0x0 com.example.function00d Source00d.java:10 s=0
+    12: 0x0 com.example.function00e Source00e.java:10 s=0
+    13: 0x0 com.example.function00f Source00f.java:10 s=0
+    14: 0x0 com.example.function010 Source010.java:110 s=0
+    15: 0x0 com.example.function011 Source011.java:111 s=0
+    16: 0x0 com.example.function018 Source018.java:118 s=0
+    17: 0x0 com.example.function019 Source019.java:119 s=0
+    18: 0x0 com.example.function01a Source01a.java:11 s=0
+    19: 0x0 com.example.function01b Source01b.java:11 s=0
+    20: 0x0 com.example.function01c Source01c.java:11 s=0
+    21: 0x0 com.example.function01d Source01d.java:11 s=0
+    22: 0x0 com.example.function01e Source01e.java:11 s=0
+    23: 0x0 com.example.function01f Source01f.java:11 s=0
+    24: 0x0 com.example.function020 Source020.java:120 s=0
+    25: 0x0 com.example.function021 Source021.java:121 s=0
+    26: 0x0 com.example.function022 Source022.java:122 s=0
+    27: 0x0 com.example.function023 Source023.java:123 s=0
+    28: 0x0 com.example.function024 Source024.java:124 s=0
+    29: 0x0 com.example.function025 Source025.java:125 s=0
+    30: 0x0 com.example.function026 Source026.java:126 s=0
+    31: 0x0 com.example.function027 Source027.java:127 s=0
+    32: 0x0 com.example.function028 Source028.java:128 s=0
+    33: 0x0 com.example.function029 Source029.java:129 s=0
+    34: 0x0 com.example.function02a Source02a.java:12 s=0
+    35: 0x0 com.example.function02b Source02b.java:12 s=0
+    36: 0x0 com.example.function02c Source02c.java:12 s=0
+    37: 0x0 com.example.function02d Source02d.java:12 s=0
+    38: 0x0 com.example.function02e Source02e.java:12 s=0
+    39: 0x0 com.example.function035 Source035.java:135 s=0
+    40: 0x0 com.example.function036 Source036.java:136 s=0
+    41: 0x0 com.example.function037 Source037.java:137 s=0
+    42: 0x0 com.example.function038 Source038.java:138 s=0
+    43: 0x0 com.example.function039 Source039.java:139 s=0
+    44: 0x0 com.example.function03a Source03a.java:13 s=0
+    45: 0x0 com.example.function03b Source03b.java:13 s=0
+    46: 0x0 com.example.function03d Source03d.java:13 s=0
+    47: 0x0 com.example.function03e Source03e.java:13 s=0
+    48: 0x0 com.example.function03f Source03f.java:13 s=0
+    49: 0x0 com.example.function040 Source040.java:140 s=0
+    50: 0x0 com.example.function041 Source041.java:141 s=0
+    51: 0x0 com.example.function042 Source042.java:142 s=0
+    52: 0x0 com.example.function049 Source049.java:149 s=0
+    53: 0x0 com.example.function04a Source04a.java:14 s=0
+    54: 0x0 com.example.function04b Source04b.java:14 s=0
+    55: 0x0 com.example.function04c Source04c.java:14 s=0
+    56: 0x0 com.example.function04d Source04d.java:14 s=0
+    57: 0x0 com.example.function04e Source04e.java:14 s=0
+    58: 0x0 com.example.function04f Source04f.java:14 s=0
+    59: 0x0 com.example.function050 Source050.java:150 s=0
+    60: 0x0 com.example.function051 Source051.java:151 s=0
+    61: 0x0 com.example.function052 Source052.java:152 s=0
+    62: 0x0 com.example.function053 Source053.java:153 s=0
+    63: 0x0 com.example.function054 Source054.java:154 s=0
+    64: 0x0 com.example.function055 Source055.java:155 s=0
+    65: 0x0 com.example.function056 Source056.java:156 s=0
+    66: 0x0 com.example.function057 Source057.java:157 s=0
+    67: 0x0 com.example.function05e Source05e.java:15 s=0
+    68: 0x0 com.example.function05f Source05f.java:15 s=0
+    69: 0x0 com.example.function060 Source060.java:160 s=0
+    70: 0x0 com.example.function061 Source061.java:161 s=0
+    71: 0x0 com.example.function062 Source062.java:162 s=0
+    72: 0x0 com.example.function063 Source063.java:163 s=0
+    73: 0x0 com.example.function064 Source064.java:164 s=0
+    74: 0x0 com.example.function065 Source065.java:165 s=0
+    75: 0x0 com.example.function066 Source066.java:166 s=0
+    76: 0x0 com.example.function067 Source067.java:167 s=0
+    77: 0x0 com.example.function068 Source068.java:168 s=0
+    78: 0x0 com.example.function069 Source069.java:169 s=0
+    79: 0x0 com.example.function06a Source06a.java:16 s=0
+    80: 0x0 com.example.function06b Source06b.java:16 s=0
+    81: 0x0 com.example.function06c Source06c.java:16 s=0
+    82: 0x0 com.example.function06d Source06d.java:16 s=0
+    83: 0x0 com.example.function06e Source06e.java:16 s=0
+    84: 0x0 com.example.function06f Source06f.java:16 s=0
+    85: 0x0 com.example.function070 Source070.java:170 s=0
+    86: 0x0 com.example.function071 Source071.java:171 s=0
+    87: 0x0 com.example.function072 Source072.java:172 s=0
+    88: 0x0 com.example.function073 Source073.java:173 s=0
+    89: 0x0 com.example.function074 Source074.java:174 s=0
+    90: 0x0 com.example.function075 Source075.java:175 s=0
+    91: 0x0 com.example.function076 Source076.java:176 s=0
+    92: 0x0 com.example.function077 Source077.java:177 s=0
+    93: 0x0 com.example.function078 Source078.java:178 s=0
+    94: 0x0 com.example.function079 Source079.java:179 s=0
+    95: 0x0 com.example.function07a Source07a.java:17 s=0
+    96: 0x0 com.example.function07b Source07b.java:17 s=0
+    97: 0x0 com.example.function081 Source081.java:181 s=0
+    98: 0x0 com.example.function082 Source082.java:182 s=0
+    99: 0x0 com.example.function083 Source083.java:183 s=0
+   100: 0x0 com.example.function084 Source084.java:184 s=0
+   101: 0x0 com.example.function085 Source085.java:185 s=0
+   102: 0x0 com.example.function086 Source086.java:186 s=0
+   103: 0x0 com.example.function087 Source087.java:187 s=0
+   104: 0x0 com.example.function088 Source088.java:188 s=0
+   105: 0x0 com.example.function089 Source089.java:189 s=0
+   106: 0x0 com.example.function08a Source08a.java:18 s=0
+   107: 0x0 com.example.function08b Source08b.java:18 s=0
+   108: 0x0 com.example.function08c Source08c.java:18 s=0
+   109: 0x0 com.example.function08d Source08d.java:18 s=0
+   110: 0x0 com.example.function08e Source08e.java:18 s=0
+   111: 0x0 com.example.function08f Source08f.java:18 s=0
+   112: 0x0 com.example.function090 Source090.java:190 s=0
+   113: 0x0 com.example.function091 Source091.java:191 s=0
+   114: 0x0 com.example.function092 Source092.java:192 s=0
+   115: 0x0 com.example.function093 Source093.java:193 s=0
+   116: 0x0 com.example.function094 Source094.java:194 s=0
+   117: 0x0 com.example.function095 Source095.java:195 s=0
+   118: 0x0 com.example.function096 Source096.java:196 s=0
+   119: 0x0 com.example.function097 Source097.java:197 s=0
+Mappings
diff --git a/src/cmd/vendor/github.com/google/pprof/proto/profile.proto b/src/cmd/vendor/github.com/google/pprof/proto/profile.proto
new file mode 100644
index 0000000..aa790e0
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/proto/profile.proto
@@ -0,0 +1,183 @@
+// Profile is a common stacktrace profile format.
+//
+// Measurements represented with this format should follow the
+// following conventions:
+//
+// - Consumers should treat unset optional fields as if they had been
+//   set with their default value.
+//
+// - When possible, measurements should be stored in "unsampled" form
+//   that is most useful to humans.  There should be enough
+//   information present to determine the original sampled values.
+//
+// - On-disk, the serialized proto must be gzip-compressed.
+//
+// - The profile is represented as a set of samples, where each sample
+//   references a sequence of locations, and where each location belongs
+//   to a mapping.
+// - There is a N->1 relationship from sample.location_id entries to
+//   locations. For every sample.location_id entry there must be a
+//   unique Location with that id.
+// - There is an optional N->1 relationship from locations to
+//   mappings. For every nonzero Location.mapping_id there must be a
+//   unique Mapping with that id.
+
+syntax = "proto3";
+
+package perftools.profiles;
+
+option java_package = "com.google.perftools.profiles";
+option java_outer_classname = "ProfileProto";
+
+message Profile {
+  // A description of the samples associated with each Sample.value.
+  // For a cpu profile this might be:
+  //   [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]]
+  // For a heap profile, this might be:
+  //   [["allocations","count"], ["space","bytes"]],
+  // If one of the values represents the number of events represented
+  // by the sample, by convention it should be at index 0 and use
+  // sample_type.unit == "count".
+  repeated ValueType sample_type = 1;
+  // The set of samples recorded in this profile.
+  repeated Sample sample = 2;
+  // Mapping from address ranges to the image/binary/library mapped
+  // into that address range.  mapping[0] will be the main binary.
+  repeated Mapping mapping = 3;
+  // Useful program location
+  repeated Location location = 4;
+  // Functions referenced by locations
+  repeated Function function = 5;
+  // A common table for strings referenced by various messages.
+  // string_table[0] must always be "".
+  repeated string string_table = 6;
+  // frames with Function.function_name fully matching the following
+  // regexp will be dropped from the samples, along with their successors.
+  int64 drop_frames = 7;   // Index into string table.
+  // frames with Function.function_name fully matching the following
+  // regexp will be kept, even if it matches drop_functions.
+  int64 keep_frames = 8;  // Index into string table.
+
+  // The following fields are informational, do not affect
+  // interpretation of results.
+
+  // Time of collection (UTC) represented as nanoseconds past the epoch.
+  int64 time_nanos = 9;
+  // Duration of the profile, if a duration makes sense.
+  int64 duration_nanos = 10;
+  // The kind of events between sampled ocurrences.
+  // e.g [ "cpu","cycles" ] or [ "heap","bytes" ]
+  ValueType period_type = 11;
+  // The number of events between sampled occurrences.
+  int64 period = 12;
+  // Freeform text associated to the profile.
+  repeated int64 comment = 13; // Indices into string table.
+  // Index into the string table of the type of the preferred sample
+  // value. If unset, clients should default to the last sample value.
+  int64 default_sample_type = 14;
+}
+
+// ValueType describes the semantics and measurement units of a value.
+message ValueType {
+  int64 type = 1; // Index into string table.
+  int64 unit = 2; // Index into string table.
+}
+
+// Each Sample records values encountered in some program
+// context. The program context is typically a stack trace, perhaps
+// augmented with auxiliary information like the thread-id, some
+// indicator of a higher level request being handled etc.
+message Sample {
+  // The ids recorded here correspond to a Profile.location.id.
+  // The leaf is at location_id[0].
+  repeated uint64 location_id = 1;
+  // The type and unit of each value is defined by the corresponding
+  // entry in Profile.sample_type. All samples must have the same
+  // number of values, the same as the length of Profile.sample_type.
+  // When aggregating multiple samples into a single sample, the
+  // result has a list of values that is the elemntwise sum of the
+  // lists of the originals.
+  repeated int64 value = 2;
+  // label includes additional context for this sample. It can include
+  // things like a thread id, allocation size, etc
+  repeated Label label = 3;
+}
+
+message Label {
+  int64 key = 1;   // Index into string table
+
+  // At most one of the following must be present
+  int64 str = 2;   // Index into string table
+  int64 num = 3;
+}
+
+message Mapping {
+  // Unique nonzero id for the mapping.
+  uint64 id = 1;
+  // Address at which the binary (or DLL) is loaded into memory.
+  uint64 memory_start = 2;
+  // The limit of the address range occupied by this mapping.
+  uint64 memory_limit = 3;
+  // Offset in the binary that corresponds to the first mapped address.
+  uint64 file_offset = 4;
+  // The object this entry is loaded from.  This can be a filename on
+  // disk for the main binary and shared libraries, or virtual
+  // abstractions like "[vdso]".
+  int64 filename = 5;  // Index into string table
+  // A string that uniquely identifies a particular program version
+  // with high probability. E.g., for binaries generated by GNU tools,
+  // it could be the contents of the .note.gnu.build-id field.
+  int64 build_id = 6;  // Index into string table
+
+  // The following fields indicate the resolution of symbolic info.
+  bool has_functions = 7;
+  bool has_filenames = 8;
+  bool has_line_numbers = 9;
+  bool has_inline_frames = 10;
+}
+
+// Describes function and line table debug information.
+message Location {
+  // Unique nonzero id for the location.  A profile could use
+  // instruction addresses or any integer sequence as ids.
+  uint64 id = 1;
+  // The id of the corresponding profile.Mapping for this location.
+  // If can be unset if the mapping is unknown or not applicable for
+  // this profile type.
+  uint64 mapping_id = 2;
+  // The instruction address for this location, if available.  It
+  // should be within [Mapping.memory_start...Mapping.memory_limit]
+  // for the corresponding mapping. A non-leaf address may be in the
+  // middle of a call instruction. It is up to display tools to find
+  // the beginning of the instruction if necessary.
+  uint64 address = 3;
+  // Multiple line indicates this location has inlined functions,
+  // where the last entry represents the caller into which the
+  // preceding entries were inlined.
+  //
+  // E.g., if memcpy() is inlined into printf:
+  //    line[0].function_name == "memcpy"
+  //    line[1].function_name == "printf"
+  repeated Line line = 4;
+}
+
+message Line {
+  // The id of the corresponding profile.Function for this line.
+  uint64 function_id = 1;
+  // Line number in source code.
+  int64 line = 2;
+}
+
+message Function {
+  // Unique nonzero id for the function.
+  uint64 id = 1;
+  // Name of the function, in human-readable form if available.
+  int64 name = 2; // Index into string table
+  // Name of the function, as identified by the system.
+  // For instance, it can be a C++ mangled name.
+  int64 system_name = 3; // Index into string table
+  // Source file containing the function.
+  int64 filename = 4; // Index into string table
+  // Line number in source file.
+  int64 start_line = 5;
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/third_party/svg/svg.go b/src/cmd/vendor/github.com/google/pprof/third_party/svg/svg.go
new file mode 100644
index 0000000..e08f8be
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/third_party/svg/svg.go
@@ -0,0 +1,79 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package svg provides tools related to handling of SVG files
+package svg
+
+import (
+	"regexp"
+	"strings"
+)
+
+var (
+	viewBox  = regexp.MustCompile(`<svg\s*width="[^"]+"\s*height="[^"]+"\s*viewBox="[^"]+"`)
+	graphID  = regexp.MustCompile(`<g id="graph\d"`)
+	svgClose = regexp.MustCompile(`</svg>`)
+)
+
+// Massage enhances the SVG output from DOT to provide better
+// panning inside a web browser. It uses the SVGPan library, which is
+// embedded into the svgPanJS variable.
+func Massage(svg string) string {
+	// Work around for dot bug which misses quoting some ampersands,
+	// resulting on unparsable SVG.
+	svg = strings.Replace(svg, "&;", "&;", -1)
+
+	//Dot's SVG output is
+	//
+	//    <svg width="___" height="___"
+	//     viewBox="___" xmlns=...>
+	//    <g id="graph0" transform="...">
+	//    ...
+	//    </g>
+	//    </svg>
+	//
+	// Change it to
+	//
+	//    <svg width="100%" height="100%"
+	//     xmlns=...>
+
+	//    <script type="text/ecmascript"><![CDATA[` ..$(svgPanJS)... `]]></script>`
+	//    <g id="viewport" transform="translate(0,0)">
+	//    <g id="graph0" transform="...">
+	//    ...
+	//    </g>
+	//    </g>
+	//    </svg>
+
+	if loc := viewBox.FindStringIndex(svg); loc != nil {
+		svg = svg[:loc[0]] +
+			`<svg width="100%" height="100%"` +
+			svg[loc[1]:]
+	}
+
+	if loc := graphID.FindStringIndex(svg); loc != nil {
+		svg = svg[:loc[0]] +
+			`<script type="text/ecmascript"><![CDATA[` + string(svgPanJS) + `]]></script>` +
+			`<g id="viewport" transform="scale(0.5,0.5) translate(0,0)">` +
+			svg[loc[0]:]
+	}
+
+	if loc := svgClose.FindStringIndex(svg); loc != nil {
+		svg = svg[:loc[0]] +
+			`</g>` +
+			svg[loc[0]:]
+	}
+
+	return svg
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/third_party/svg/svgpan.go b/src/cmd/vendor/github.com/google/pprof/third_party/svg/svgpan.go
new file mode 100644
index 0000000..4975b10
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/third_party/svg/svgpan.go
@@ -0,0 +1,291 @@
+// SVG pan and zoom library.
+// See copyright notice in string constant below.
+
+package svg
+
+// https://www.cyberz.org/projects/SVGPan/SVGPan.js
+
+const svgPanJS = `
+/** 
+ *  SVGPan library 1.2.1
+ * ======================
+ *
+ * Given an unique existing element with id "viewport" (or when missing, the first g 
+ * element), including the the library into any SVG adds the following capabilities:
+ *
+ *  - Mouse panning
+ *  - Mouse zooming (using the wheel)
+ *  - Object dragging
+ *
+ * You can configure the behaviour of the pan/zoom/drag with the variables
+ * listed in the CONFIGURATION section of this file.
+ *
+ * Known issues:
+ *
+ *  - Zooming (while panning) on Safari has still some issues
+ *
+ * Releases:
+ *
+ * 1.2.1, Mon Jul  4 00:33:18 CEST 2011, Andrea Leofreddi
+ *	- Fixed a regression with mouse wheel (now working on Firefox 5)
+ *	- Working with viewBox attribute (#4)
+ *	- Added "use strict;" and fixed resulting warnings (#5)
+ *	- Added configuration variables, dragging is disabled by default (#3)
+ *
+ * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
+ *	Fixed a bug with browser mouse handler interaction
+ *
+ * 1.1, Wed Feb  3 17:39:33 GMT 2010, Zeng Xiaohui
+ *	Updated the zoom code to support the mouse wheel on Safari/Chrome
+ *
+ * 1.0, Andrea Leofreddi
+ *	First release
+ *
+ * This code is licensed under the following BSD license:
+ *
+ * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi at itcharm.com>. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ` + "``AS IS''" + ` AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of Andrea Leofreddi.
+ */
+
+"use strict";
+
+/// CONFIGURATION 
+/// ====>
+
+var enablePan = 1; // 1 or 0: enable or disable panning (default enabled)
+var enableZoom = 1; // 1 or 0: enable or disable zooming (default enabled)
+var enableDrag = 0; // 1 or 0: enable or disable dragging (default disabled)
+
+/// <====
+/// END OF CONFIGURATION 
+
+var root = document.documentElement;
+
+var state = 'none', svgRoot, stateTarget, stateOrigin, stateTf;
+
+setupHandlers(root);
+
+/**
+ * Register handlers
+ */
+function setupHandlers(root){
+	setAttributes(root, {
+		"onmouseup" : "handleMouseUp(evt)",
+		"onmousedown" : "handleMouseDown(evt)",
+		"onmousemove" : "handleMouseMove(evt)",
+		//"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
+	});
+
+	if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
+		window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
+	else
+		window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
+}
+
+/**
+ * Retrieves the root element for SVG manipulation. The element is then cached into the svgRoot global variable.
+ */
+function getRoot(root) {
+	if(typeof(svgRoot) == "undefined") {
+		var g = null;
+
+		g = root.getElementById("viewport");
+
+		if(g == null)
+			g = root.getElementsByTagName('g')[0];
+
+		if(g == null)
+			alert('Unable to obtain SVG root element');
+
+		setCTM(g, g.getCTM());
+
+		g.removeAttribute("viewBox");
+
+		svgRoot = g;
+	}
+
+	return svgRoot;
+}
+
+/**
+ * Instance an SVGPoint object with given event coordinates.
+ */
+function getEventPoint(evt) {
+	var p = root.createSVGPoint();
+
+	p.x = evt.clientX;
+	p.y = evt.clientY;
+
+	return p;
+}
+
+/**
+ * Sets the current transform matrix of an element.
+ */
+function setCTM(element, matrix) {
+	var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
+
+	element.setAttribute("transform", s);
+}
+
+/**
+ * Dumps a matrix to a string (useful for debug).
+ */
+function dumpMatrix(matrix) {
+	var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n  " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n  0, 0, 1 ]";
+
+	return s;
+}
+
+/**
+ * Sets attributes of an element.
+ */
+function setAttributes(element, attributes){
+	for (var i in attributes)
+		element.setAttributeNS(null, i, attributes[i]);
+}
+
+/**
+ * Handle mouse wheel event.
+ */
+function handleMouseWheel(evt) {
+	if(!enableZoom)
+		return;
+
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var delta;
+
+	if(evt.wheelDelta)
+		delta = evt.wheelDelta / 3600; // Chrome/Safari
+	else
+		delta = evt.detail / -90; // Mozilla
+
+	var z = 1 + delta; // Zoom factor: 0.9/1.1
+
+	var g = getRoot(svgDoc);
+	
+	var p = getEventPoint(evt);
+
+	p = p.matrixTransform(g.getCTM().inverse());
+
+	// Compute new scale matrix in current mouse position
+	var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
+
+        setCTM(g, g.getCTM().multiply(k));
+
+	if(typeof(stateTf) == "undefined")
+		stateTf = g.getCTM().inverse();
+
+	stateTf = stateTf.multiply(k.inverse());
+}
+
+/**
+ * Handle mouse move event.
+ */
+function handleMouseMove(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var g = getRoot(svgDoc);
+
+	if(state == 'pan' && enablePan) {
+		// Pan mode
+		var p = getEventPoint(evt).matrixTransform(stateTf);
+
+		setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
+	} else if(state == 'drag' && enableDrag) {
+		// Drag mode
+		var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
+
+		setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
+
+		stateOrigin = p;
+	}
+}
+
+/**
+ * Handle click event.
+ */
+function handleMouseDown(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var g = getRoot(svgDoc);
+
+	if(
+		evt.target.tagName == "svg" 
+		|| !enableDrag // Pan anyway when drag is disabled and the user clicked on an element 
+	) {
+		// Pan mode
+		state = 'pan';
+
+		stateTf = g.getCTM().inverse();
+
+		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+	} else {
+		// Drag mode
+		state = 'drag';
+
+		stateTarget = evt.target;
+
+		stateTf = g.getCTM().inverse();
+
+		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+	}
+}
+
+/**
+ * Handle mouse button release event.
+ */
+function handleMouseUp(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	if(state == 'pan' || state == 'drag') {
+		// Quit pan mode
+		state = '';
+	}
+}
+
+`
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/.gitignore b/src/cmd/vendor/github.com/ianlancetaylor/demangle/.gitignore
new file mode 100644
index 0000000..4a8b38f
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/.gitignore
@@ -0,0 +1,13 @@
+*.o
+*.a
+*.so
+._*
+.nfs.*
+a.out
+*~
+*.orig
+*.rej
+*.exe
+.*.swp
+core
+demangle.test
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/LICENSE b/src/cmd/vendor/github.com/ianlancetaylor/demangle/LICENSE
new file mode 100644
index 0000000..d29b372
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2015 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/README.md b/src/cmd/vendor/github.com/ianlancetaylor/demangle/README.md
new file mode 100644
index 0000000..ef3f94a
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/README.md
@@ -0,0 +1,3 @@
+# github.com/ianlancetaylor/demangle
+
+A Go package that can be used to demangle C++ symbol names.
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast.go
new file mode 100644
index 0000000..0ad5354
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast.go
@@ -0,0 +1,2879 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package demangle
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+)
+
+// AST is an abstract syntax tree representing a C++ declaration.
+// This is sufficient for the demangler but is by no means a general C++ AST.
+type AST interface {
+	// Internal method to convert to demangled string.
+	print(*printState)
+
+	// Traverse each element of an AST.  If the function returns
+	// false, traversal of children of that element is skipped.
+	Traverse(func(AST) bool)
+
+	// Copy an AST with possible transformations.
+	// If the skip function returns true, no copy is required.
+	// If the copy function returns nil, no copy is required.
+	// Otherwise the AST returned by copy is used in a copy of the full AST.
+	// Copy itself returns either a copy or nil.
+	Copy(copy func(AST) AST, skip func(AST) bool) AST
+
+	// Implement the fmt.GoStringer interface.
+	GoString() string
+	goString(indent int, field string) string
+}
+
+// ASTToString returns the demangled name of the AST.
+func ASTToString(a AST, options ...Option) string {
+	tparams := true
+	for _, o := range options {
+		switch o {
+		case NoTemplateParams:
+			tparams = false
+		}
+	}
+
+	ps := printState{tparams: tparams}
+	a.print(&ps)
+	return ps.buf.String()
+}
+
+// The printState type holds information needed to print an AST.
+type printState struct {
+	tparams bool // whether to print template parameters
+
+	buf  bytes.Buffer
+	last byte // Last byte written to buffer.
+
+	// The inner field is a list of items to print for a type
+	// name.  This is used by types to implement the inside-out
+	// C++ declaration syntax.
+	inner []AST
+
+	// The printing field is a list of items we are currently
+	// printing.  This avoids endless recursion if a substitution
+	// reference creates a cycle in the graph.
+	printing []AST
+}
+
+// writeByte adds a byte to the string being printed.
+func (ps *printState) writeByte(b byte) {
+	ps.last = b
+	ps.buf.WriteByte(b)
+}
+
+// writeString adds a string to the string being printed.
+func (ps *printState) writeString(s string) {
+	if len(s) > 0 {
+		ps.last = s[len(s)-1]
+	}
+	ps.buf.WriteString(s)
+}
+
+// Print an AST.
+func (ps *printState) print(a AST) {
+	c := 0
+	for _, v := range ps.printing {
+		if v == a {
+			// We permit the type to appear once, and
+			// return without printing anything if we see
+			// it twice.  This is for a case like
+			// _Z6outer2IsEPFilES1_, where the
+			// substitution is printed differently the
+			// second time because the set of inner types
+			// is different.
+			c++
+			if c > 1 {
+				return
+			}
+		}
+	}
+	ps.printing = append(ps.printing, a)
+
+	a.print(ps)
+
+	ps.printing = ps.printing[:len(ps.printing)-1]
+}
+
+// Name is an unqualified name.
+type Name struct {
+	Name string
+}
+
+func (n *Name) print(ps *printState) {
+	ps.writeString(n.Name)
+}
+
+func (n *Name) Traverse(fn func(AST) bool) {
+	fn(n)
+}
+
+func (n *Name) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(n) {
+		return nil
+	}
+	return fn(n)
+}
+
+func (n *Name) GoString() string {
+	return n.goString(0, "Name: ")
+}
+
+func (n *Name) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%s%s", indent, "", field, n.Name)
+}
+
+// Typed is a typed name.
+type Typed struct {
+	Name AST
+	Type AST
+}
+
+func (t *Typed) print(ps *printState) {
+	// We are printing a typed name, so ignore the current set of
+	// inner names to print.  Pass down our name as the one to use.
+	holdInner := ps.inner
+	defer func() { ps.inner = holdInner }()
+
+	ps.inner = []AST{t}
+	ps.print(t.Type)
+	if len(ps.inner) > 0 {
+		// The type did not print the name; print it now in
+		// the default location.
+		ps.writeByte(' ')
+		ps.print(t.Name)
+	}
+}
+
+func (t *Typed) printInner(ps *printState) {
+	ps.print(t.Name)
+}
+
+func (t *Typed) Traverse(fn func(AST) bool) {
+	if fn(t) {
+		t.Name.Traverse(fn)
+		t.Type.Traverse(fn)
+	}
+}
+
+func (t *Typed) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(t) {
+		return nil
+	}
+	name := t.Name.Copy(fn, skip)
+	typ := t.Type.Copy(fn, skip)
+	if name == nil && typ == nil {
+		return fn(t)
+	}
+	if name == nil {
+		name = t.Name
+	}
+	if typ == nil {
+		typ = t.Type
+	}
+	t = &Typed{Name: name, Type: typ}
+	if r := fn(t); r != nil {
+		return r
+	}
+	return t
+}
+
+func (t *Typed) GoString() string {
+	return t.goString(0, "")
+}
+
+func (t *Typed) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sTyped:\n%s\n%s", indent, "", field,
+		t.Name.goString(indent+2, "Name: "),
+		t.Type.goString(indent+2, "Type: "))
+}
+
+// Qualified is a name in a scope.
+type Qualified struct {
+	Scope AST
+	Name  AST
+
+	// The LocalName field is true if this is parsed as a
+	// <local-name>.  We shouldn't really need this, but in some
+	// cases (for the unary sizeof operator) the standard
+	// demangler prints a local name slightly differently.  We
+	// keep track of this for compatibility.
+	LocalName bool // A full local name encoding
+}
+
+func (q *Qualified) print(ps *printState) {
+	ps.print(q.Scope)
+	ps.writeString("::")
+	ps.print(q.Name)
+}
+
+func (q *Qualified) Traverse(fn func(AST) bool) {
+	if fn(q) {
+		q.Scope.Traverse(fn)
+		q.Name.Traverse(fn)
+	}
+}
+
+func (q *Qualified) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(q) {
+		return nil
+	}
+	scope := q.Scope.Copy(fn, skip)
+	name := q.Name.Copy(fn, skip)
+	if scope == nil && name == nil {
+		return fn(q)
+	}
+	if scope == nil {
+		scope = q.Scope
+	}
+	if name == nil {
+		name = q.Name
+	}
+	q = &Qualified{Scope: scope, Name: name, LocalName: q.LocalName}
+	if r := fn(q); r != nil {
+		return r
+	}
+	return q
+}
+
+func (q *Qualified) GoString() string {
+	return q.goString(0, "")
+}
+
+func (q *Qualified) goString(indent int, field string) string {
+	s := ""
+	if q.LocalName {
+		s = " LocalName: true"
+	}
+	return fmt.Sprintf("%*s%sQualified:%s\n%s\n%s", indent, "", field,
+		s, q.Scope.goString(indent+2, "Scope: "),
+		q.Name.goString(indent+2, "Name: "))
+}
+
+// Template is a template with arguments.
+type Template struct {
+	Name AST
+	Args []AST
+}
+
+func (t *Template) print(ps *printState) {
+	// Inner types apply to the template as a whole, they don't
+	// cross over into the template.
+	holdInner := ps.inner
+	defer func() { ps.inner = holdInner }()
+
+	ps.inner = nil
+	ps.print(t.Name)
+
+	if !ps.tparams {
+		// Do not print template parameters.
+		return
+	}
+	// We need an extra space after operator<.
+	if ps.last == '<' {
+		ps.writeByte(' ')
+	}
+
+	ps.writeByte('<')
+	first := true
+	for _, a := range t.Args {
+		if ps.isEmpty(a) {
+			continue
+		}
+		if !first {
+			ps.writeString(", ")
+		}
+		ps.print(a)
+		first = false
+	}
+	if ps.last == '>' {
+		// Avoid syntactic ambiguity in old versions of C++.
+		ps.writeByte(' ')
+	}
+	ps.writeByte('>')
+}
+
+func (t *Template) Traverse(fn func(AST) bool) {
+	if fn(t) {
+		t.Name.Traverse(fn)
+		for _, a := range t.Args {
+			a.Traverse(fn)
+		}
+	}
+}
+
+func (t *Template) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(t) {
+		return nil
+	}
+	name := t.Name.Copy(fn, skip)
+	changed := name != nil
+	args := make([]AST, len(t.Args))
+	for i, a := range t.Args {
+		ac := a.Copy(fn, skip)
+		if ac == nil {
+			args[i] = a
+		} else {
+			args[i] = ac
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(t)
+	}
+	if name == nil {
+		name = t.Name
+	}
+	t = &Template{Name: name, Args: args}
+	if r := fn(t); r != nil {
+		return r
+	}
+	return t
+}
+
+func (t *Template) GoString() string {
+	return t.goString(0, "")
+}
+
+func (t *Template) goString(indent int, field string) string {
+	var args string
+	if len(t.Args) == 0 {
+		args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+	} else {
+		args = fmt.Sprintf("%*sArgs:", indent+2, "")
+		for i, a := range t.Args {
+			args += "\n"
+			args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+		}
+	}
+	return fmt.Sprintf("%*s%sTemplate (%p):\n%s\n%s", indent, "", field, t,
+		t.Name.goString(indent+2, "Name: "), args)
+}
+
+// TemplateParam is a template parameter.  The Template field is
+// filled in while parsing the demangled string.  We don't normally
+// see these while printing--they are replaced by the simplify
+// function.
+type TemplateParam struct {
+	Index    int
+	Template *Template
+}
+
+func (tp *TemplateParam) print(ps *printState) {
+	if tp.Template == nil {
+		panic("TemplateParam Template field is nil")
+	}
+	if tp.Index >= len(tp.Template.Args) {
+		panic("TemplateParam Index out of bounds")
+	}
+	ps.print(tp.Template.Args[tp.Index])
+}
+
+func (tp *TemplateParam) Traverse(fn func(AST) bool) {
+	fn(tp)
+	// Don't traverse Template--it points elsewhere in the AST.
+}
+
+func (tp *TemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(tp) {
+		return nil
+	}
+	return fn(tp)
+}
+
+func (tp *TemplateParam) GoString() string {
+	return tp.goString(0, "")
+}
+
+func (tp *TemplateParam) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sTemplateParam: Template: %p; Index %d", indent, "", field, tp.Template, tp.Index)
+}
+
+// Qualifiers is an ordered list of type qualifiers.
+type Qualifiers []string
+
+// TypeWithQualifiers is a type with standard qualifiers.
+type TypeWithQualifiers struct {
+	Base       AST
+	Qualifiers Qualifiers
+}
+
+func (twq *TypeWithQualifiers) print(ps *printState) {
+	// Give the base type a chance to print the inner types.
+	ps.inner = append(ps.inner, twq)
+	ps.print(twq.Base)
+	if len(ps.inner) > 0 {
+		// The qualifier wasn't printed by Base.
+		ps.writeByte(' ')
+		ps.writeString(strings.Join(twq.Qualifiers, " "))
+		ps.inner = ps.inner[:len(ps.inner)-1]
+	}
+}
+
+// Print qualifiers as an inner type by just printing the qualifiers.
+func (twq *TypeWithQualifiers) printInner(ps *printState) {
+	ps.writeByte(' ')
+	ps.writeString(strings.Join(twq.Qualifiers, " "))
+}
+
+func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) {
+	if fn(twq) {
+		twq.Base.Traverse(fn)
+	}
+}
+
+func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(twq) {
+		return nil
+	}
+	base := twq.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(twq)
+	}
+	twq = &TypeWithQualifiers{Base: base, Qualifiers: twq.Qualifiers}
+	if r := fn(twq); r != nil {
+		return r
+	}
+	return twq
+}
+
+func (twq *TypeWithQualifiers) GoString() string {
+	return twq.goString(0, "")
+}
+
+func (twq *TypeWithQualifiers) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sTypeWithQualifiers: Qualifiers: %s\n%s", indent, "", field,
+		twq.Qualifiers, twq.Base.goString(indent+2, "Base: "))
+}
+
+// MethodWithQualifiers is a method with qualifiers.
+type MethodWithQualifiers struct {
+	Method       AST
+	Qualifiers   Qualifiers
+	RefQualifier string // "" or "&" or "&&"
+}
+
+func (mwq *MethodWithQualifiers) print(ps *printState) {
+	// Give the base type a chance to print the inner types.
+	ps.inner = append(ps.inner, mwq)
+	ps.print(mwq.Method)
+	if len(ps.inner) > 0 {
+		if len(mwq.Qualifiers) > 0 {
+			ps.writeByte(' ')
+			ps.writeString(strings.Join(mwq.Qualifiers, " "))
+		}
+		if mwq.RefQualifier != "" {
+			ps.writeByte(' ')
+			ps.writeString(mwq.RefQualifier)
+		}
+		ps.inner = ps.inner[:len(ps.inner)-1]
+	}
+}
+
+func (mwq *MethodWithQualifiers) printInner(ps *printState) {
+	if len(mwq.Qualifiers) > 0 {
+		ps.writeByte(' ')
+		ps.writeString(strings.Join(mwq.Qualifiers, " "))
+	}
+	if mwq.RefQualifier != "" {
+		ps.writeByte(' ')
+		ps.writeString(mwq.RefQualifier)
+	}
+}
+
+func (mwq *MethodWithQualifiers) Traverse(fn func(AST) bool) {
+	if fn(mwq) {
+		mwq.Method.Traverse(fn)
+	}
+}
+
+func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(mwq) {
+		return nil
+	}
+	method := mwq.Method.Copy(fn, skip)
+	if method == nil {
+		return fn(mwq)
+	}
+	mwq = &MethodWithQualifiers{Method: method, Qualifiers: mwq.Qualifiers, RefQualifier: mwq.RefQualifier}
+	if r := fn(mwq); r != nil {
+		return r
+	}
+	return mwq
+}
+
+func (mwq *MethodWithQualifiers) GoString() string {
+	return mwq.goString(0, "")
+}
+
+func (mwq *MethodWithQualifiers) goString(indent int, field string) string {
+	var q string
+	if len(mwq.Qualifiers) > 0 {
+		q += fmt.Sprintf(" Qualifiers: %v", mwq.Qualifiers)
+	}
+	if mwq.RefQualifier != "" {
+		if q != "" {
+			q += ";"
+		}
+		q += " RefQualifier: " + mwq.RefQualifier
+	}
+	return fmt.Sprintf("%*s%sMethodWithQualifiers:%s\n%s", indent, "", field,
+		q, mwq.Method.goString(indent+2, "Method: "))
+}
+
+// BuiltinType is a builtin type, like "int".
+type BuiltinType struct {
+	Name string
+}
+
+func (bt *BuiltinType) print(ps *printState) {
+	ps.writeString(bt.Name)
+}
+
+func (bt *BuiltinType) Traverse(fn func(AST) bool) {
+	fn(bt)
+}
+
+func (bt *BuiltinType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(bt) {
+		return nil
+	}
+	return fn(bt)
+}
+
+func (bt *BuiltinType) GoString() string {
+	return bt.goString(0, "")
+}
+
+func (bt *BuiltinType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sBuiltinType: %s", indent, "", field, bt.Name)
+}
+
+// printBase is common print code for types that are printed with a
+// simple suffix.
+func printBase(ps *printState, qual, base AST) {
+	ps.inner = append(ps.inner, qual)
+	ps.print(base)
+	if len(ps.inner) > 0 {
+		qual.(innerPrinter).printInner(ps)
+		ps.inner = ps.inner[:len(ps.inner)-1]
+	}
+}
+
+// PointerType is a pointer type.
+type PointerType struct {
+	Base AST
+}
+
+func (pt *PointerType) print(ps *printState) {
+	printBase(ps, pt, pt.Base)
+}
+
+func (pt *PointerType) printInner(ps *printState) {
+	ps.writeString("*")
+}
+
+func (pt *PointerType) Traverse(fn func(AST) bool) {
+	if fn(pt) {
+		pt.Base.Traverse(fn)
+	}
+}
+
+func (pt *PointerType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(pt) {
+		return nil
+	}
+	base := pt.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(pt)
+	}
+	pt = &PointerType{Base: base}
+	if r := fn(pt); r != nil {
+		return r
+	}
+	return pt
+}
+
+func (pt *PointerType) GoString() string {
+	return pt.goString(0, "")
+}
+
+func (pt *PointerType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sPointerType:\n%s", indent, "", field,
+		pt.Base.goString(indent+2, ""))
+}
+
+// ReferenceType is a reference type.
+type ReferenceType struct {
+	Base AST
+}
+
+func (rt *ReferenceType) print(ps *printState) {
+	printBase(ps, rt, rt.Base)
+}
+
+func (rt *ReferenceType) printInner(ps *printState) {
+	ps.writeString("&")
+}
+
+func (rt *ReferenceType) Traverse(fn func(AST) bool) {
+	if fn(rt) {
+		rt.Base.Traverse(fn)
+	}
+}
+
+func (rt *ReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(rt) {
+		return nil
+	}
+	base := rt.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(rt)
+	}
+	rt = &ReferenceType{Base: base}
+	if r := fn(rt); r != nil {
+		return r
+	}
+	return rt
+}
+
+func (rt *ReferenceType) GoString() string {
+	return rt.goString(0, "")
+}
+
+func (rt *ReferenceType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sReferenceType:\n%s", indent, "", field,
+		rt.Base.goString(indent+2, ""))
+}
+
+// RvalueReferenceType is an rvalue reference type.
+type RvalueReferenceType struct {
+	Base AST
+}
+
+func (rt *RvalueReferenceType) print(ps *printState) {
+	printBase(ps, rt, rt.Base)
+}
+
+func (rt *RvalueReferenceType) printInner(ps *printState) {
+	ps.writeString("&&")
+}
+
+func (rt *RvalueReferenceType) Traverse(fn func(AST) bool) {
+	if fn(rt) {
+		rt.Base.Traverse(fn)
+	}
+}
+
+func (rt *RvalueReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(rt) {
+		return nil
+	}
+	base := rt.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(rt)
+	}
+	rt = &RvalueReferenceType{Base: base}
+	if r := fn(rt); r != nil {
+		return r
+	}
+	return rt
+}
+
+func (rt *RvalueReferenceType) GoString() string {
+	return rt.goString(0, "")
+}
+
+func (rt *RvalueReferenceType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sRvalueReferenceType:\n%s", indent, "", field,
+		rt.Base.goString(indent+2, ""))
+}
+
+// ComplexType is a complex type.
+type ComplexType struct {
+	Base AST
+}
+
+func (ct *ComplexType) print(ps *printState) {
+	printBase(ps, ct, ct.Base)
+}
+
+func (ct *ComplexType) printInner(ps *printState) {
+	ps.writeString(" _Complex")
+}
+
+func (ct *ComplexType) Traverse(fn func(AST) bool) {
+	if fn(ct) {
+		ct.Base.Traverse(fn)
+	}
+}
+
+func (ct *ComplexType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(ct) {
+		return nil
+	}
+	base := ct.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(ct)
+	}
+	ct = &ComplexType{Base: base}
+	if r := fn(ct); r != nil {
+		return r
+	}
+	return ct
+}
+
+func (ct *ComplexType) GoString() string {
+	return ct.goString(0, "")
+}
+
+func (ct *ComplexType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sComplexType:\n%s", indent, "", field,
+		ct.Base.goString(indent+2, ""))
+}
+
+// ImaginaryType is an imaginary type.
+type ImaginaryType struct {
+	Base AST
+}
+
+func (it *ImaginaryType) print(ps *printState) {
+	printBase(ps, it, it.Base)
+}
+
+func (it *ImaginaryType) printInner(ps *printState) {
+	ps.writeString(" _Imaginary")
+}
+
+func (it *ImaginaryType) Traverse(fn func(AST) bool) {
+	if fn(it) {
+		it.Base.Traverse(fn)
+	}
+}
+
+func (it *ImaginaryType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(it) {
+		return nil
+	}
+	base := it.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(it)
+	}
+	it = &ImaginaryType{Base: base}
+	if r := fn(it); r != nil {
+		return r
+	}
+	return it
+}
+
+func (it *ImaginaryType) GoString() string {
+	return it.goString(0, "")
+}
+
+func (it *ImaginaryType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sImaginaryType:\n%s", indent, "", field,
+		it.Base.goString(indent+2, ""))
+}
+
+// VendorQualifier is a type qualified by a vendor-specific qualifier.
+type VendorQualifier struct {
+	Qualifier AST
+	Type      AST
+}
+
+func (vq *VendorQualifier) print(ps *printState) {
+	ps.inner = append(ps.inner, vq)
+	ps.print(vq.Type)
+	if len(ps.inner) > 0 {
+		ps.printOneInner(nil)
+	}
+}
+
+func (vq *VendorQualifier) printInner(ps *printState) {
+	ps.writeByte(' ')
+	ps.print(vq.Qualifier)
+}
+
+func (vq *VendorQualifier) Traverse(fn func(AST) bool) {
+	if fn(vq) {
+		vq.Qualifier.Traverse(fn)
+		vq.Type.Traverse(fn)
+	}
+}
+
+func (vq *VendorQualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(vq) {
+		return nil
+	}
+	qualifier := vq.Qualifier.Copy(fn, skip)
+	typ := vq.Type.Copy(fn, skip)
+	if qualifier == nil && typ == nil {
+		return fn(vq)
+	}
+	if qualifier == nil {
+		qualifier = vq.Qualifier
+	}
+	if typ == nil {
+		typ = vq.Type
+	}
+	vq = &VendorQualifier{Qualifier: qualifier, Type: vq.Type}
+	if r := fn(vq); r != nil {
+		return r
+	}
+	return vq
+}
+
+func (vq *VendorQualifier) GoString() string {
+	return vq.goString(0, "")
+}
+
+func (vq *VendorQualifier) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sVendorQualifier:\n%s\n%s", indent, "", field,
+		vq.Qualifier.goString(indent+2, "Qualifier: "),
+		vq.Type.goString(indent+2, "Type: "))
+}
+
+// ArrayType is an array type.
+type ArrayType struct {
+	Dimension AST
+	Element   AST
+}
+
+func (at *ArrayType) print(ps *printState) {
+	// Pass the array type down as an inner type so that we print
+	// multi-dimensional arrays correctly.
+	ps.inner = append(ps.inner, at)
+	ps.print(at.Element)
+	if ln := len(ps.inner); ln > 0 {
+		ps.inner = ps.inner[:ln-1]
+		at.printDimension(ps)
+	}
+}
+
+func (at *ArrayType) printInner(ps *printState) {
+	at.printDimension(ps)
+}
+
+// Print the array dimension.
+func (at *ArrayType) printDimension(ps *printState) {
+	space := " "
+	for len(ps.inner) > 0 {
+		// We haven't gotten to the real type yet.  Use
+		// parentheses around that type, except that if it is
+		// an array type we print it as a multi-dimensional
+		// array
+		in := ps.inner[len(ps.inner)-1]
+		if twq, ok := in.(*TypeWithQualifiers); ok {
+			in = twq.Base
+		}
+		if _, ok := in.(*ArrayType); ok {
+			if in == ps.inner[len(ps.inner)-1] {
+				space = ""
+			}
+			ps.printOneInner(nil)
+		} else {
+			ps.writeString(" (")
+			ps.printInner(false)
+			ps.writeByte(')')
+		}
+	}
+	ps.writeString(space)
+	ps.writeByte('[')
+	ps.print(at.Dimension)
+	ps.writeByte(']')
+}
+
+func (at *ArrayType) Traverse(fn func(AST) bool) {
+	if fn(at) {
+		at.Dimension.Traverse(fn)
+		at.Element.Traverse(fn)
+	}
+}
+
+func (at *ArrayType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(at) {
+		return nil
+	}
+	dimension := at.Dimension.Copy(fn, skip)
+	element := at.Element.Copy(fn, skip)
+	if dimension == nil && element == nil {
+		return fn(at)
+	}
+	if dimension == nil {
+		dimension = at.Dimension
+	}
+	if element == nil {
+		element = at.Element
+	}
+	at = &ArrayType{Dimension: dimension, Element: element}
+	if r := fn(at); r != nil {
+		return r
+	}
+	return at
+}
+
+func (at *ArrayType) GoString() string {
+	return at.goString(0, "")
+}
+
+func (at *ArrayType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sArrayType:\n%s\n%s", indent, "", field,
+		at.Dimension.goString(indent+2, "Dimension: "),
+		at.Element.goString(indent+2, "Element: "))
+}
+
+// FunctionType is a function type.  The Return field may be nil for
+// cases where the return type is not part of the mangled name.
+type FunctionType struct {
+	Return AST
+	Args   []AST
+}
+
+func (ft *FunctionType) print(ps *printState) {
+	if ft.Return != nil {
+		// Pass the return type as an inner type in order to
+		// print the arguments in the right location.
+		ps.inner = append(ps.inner, ft)
+		ps.print(ft.Return)
+		if len(ps.inner) == 0 {
+			// Everything was printed.
+			return
+		}
+		ps.inner = ps.inner[:len(ps.inner)-1]
+		ps.writeByte(' ')
+	}
+	ft.printArgs(ps)
+}
+
+func (ft *FunctionType) printInner(ps *printState) {
+	ft.printArgs(ps)
+}
+
+// printArgs prints the arguments of a function type.  It looks at the
+// inner types for spacing.
+func (ft *FunctionType) printArgs(ps *printState) {
+	paren := false
+	space := false
+	for i := len(ps.inner) - 1; i >= 0; i-- {
+		switch ps.inner[i].(type) {
+		case *PointerType, *ReferenceType, *RvalueReferenceType:
+			paren = true
+		case *TypeWithQualifiers, *ComplexType, *ImaginaryType, *PtrMem:
+			space = true
+			paren = true
+		}
+		if paren {
+			break
+		}
+	}
+
+	if paren {
+		if !space && (ps.last != '(' && ps.last != '*') {
+			space = true
+		}
+		if space && ps.last != ' ' {
+			ps.writeByte(' ')
+		}
+		ps.writeByte('(')
+	}
+
+	save := ps.printInner(true)
+
+	if paren {
+		ps.writeByte(')')
+	}
+
+	ps.writeByte('(')
+	first := true
+	for _, a := range ft.Args {
+		if ps.isEmpty(a) {
+			continue
+		}
+		if !first {
+			ps.writeString(", ")
+		}
+		ps.print(a)
+		first = false
+	}
+	ps.writeByte(')')
+
+	ps.inner = save
+	ps.printInner(false)
+}
+
+func (ft *FunctionType) Traverse(fn func(AST) bool) {
+	if fn(ft) {
+		if ft.Return != nil {
+			ft.Return.Traverse(fn)
+		}
+		for _, a := range ft.Args {
+			a.Traverse(fn)
+		}
+	}
+}
+
+func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(ft) {
+		return nil
+	}
+	changed := false
+	var ret AST
+	if ft.Return != nil {
+		ret = ft.Return.Copy(fn, skip)
+		if ret == nil {
+			ret = ft.Return
+		} else {
+			changed = true
+		}
+	}
+	args := make([]AST, len(ft.Args))
+	for i, a := range ft.Args {
+		ac := a.Copy(fn, skip)
+		if ac == nil {
+			args[i] = a
+		} else {
+			args[i] = ac
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(ft)
+	}
+	ft = &FunctionType{Return: ret, Args: args}
+	if r := fn(ft); r != nil {
+		return r
+	}
+	return ft
+}
+
+func (ft *FunctionType) GoString() string {
+	return ft.goString(0, "")
+}
+
+func (ft *FunctionType) goString(indent int, field string) string {
+	var r string
+	if ft.Return == nil {
+		r = fmt.Sprintf("%*sReturn: nil", indent+2, "")
+	} else {
+		r = ft.Return.goString(indent+2, "Return: ")
+	}
+	var args string
+	if len(ft.Args) == 0 {
+		args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+	} else {
+		args = fmt.Sprintf("%*sArgs:", indent+2, "")
+		for i, a := range ft.Args {
+			args += "\n"
+			args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+		}
+	}
+	return fmt.Sprintf("%*s%sFunctionType:\n%s\n%s", indent, "", field, r, args)
+}
+
+// FunctionParam is a parameter of a function, used for last-specified
+// return type in a closure.
+type FunctionParam struct {
+	Index int
+}
+
+func (fp *FunctionParam) print(ps *printState) {
+	if fp.Index == 0 {
+		ps.writeString("this")
+	} else {
+		fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
+	}
+}
+
+func (fp *FunctionParam) Traverse(fn func(AST) bool) {
+	fn(fp)
+}
+
+func (fp *FunctionParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(fp) {
+		return nil
+	}
+	return fn(fp)
+}
+
+func (fp *FunctionParam) GoString() string {
+	return fp.goString(0, "")
+}
+
+func (fp *FunctionParam) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sFunctionParam: %d", indent, "", field, fp.Index)
+}
+
+// PtrMem is a pointer-to-member expression.
+type PtrMem struct {
+	Class  AST
+	Member AST
+}
+
+func (pm *PtrMem) print(ps *printState) {
+	ps.inner = append(ps.inner, pm)
+	ps.print(pm.Member)
+	if len(ps.inner) > 0 {
+		ps.printOneInner(nil)
+	}
+}
+
+func (pm *PtrMem) printInner(ps *printState) {
+	if ps.last != '(' {
+		ps.writeByte(' ')
+	}
+	ps.print(pm.Class)
+	ps.writeString("::*")
+}
+
+func (pm *PtrMem) Traverse(fn func(AST) bool) {
+	if fn(pm) {
+		pm.Class.Traverse(fn)
+		pm.Member.Traverse(fn)
+	}
+}
+
+func (pm *PtrMem) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(pm) {
+		return nil
+	}
+	class := pm.Class.Copy(fn, skip)
+	member := pm.Member.Copy(fn, skip)
+	if class == nil && member == nil {
+		return fn(pm)
+	}
+	if class == nil {
+		class = pm.Class
+	}
+	if member == nil {
+		member = pm.Member
+	}
+	pm = &PtrMem{Class: class, Member: member}
+	if r := fn(pm); r != nil {
+		return r
+	}
+	return pm
+}
+
+func (pm *PtrMem) GoString() string {
+	return pm.goString(0, "")
+}
+
+func (pm *PtrMem) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sPtrMem:\n%s\n%s", indent, "", field,
+		pm.Class.goString(indent+2, "Class: "),
+		pm.Member.goString(indent+2, "Member: "))
+}
+
+// FixedType is a fixed numeric type of unknown size.
+type FixedType struct {
+	Base  AST
+	Accum bool
+	Sat   bool
+}
+
+func (ft *FixedType) print(ps *printState) {
+	if ft.Sat {
+		ps.writeString("_Sat ")
+	}
+	if bt, ok := ft.Base.(*BuiltinType); ok && bt.Name == "int" {
+		// The standard demangler skips printing "int".
+	} else {
+		ps.print(ft.Base)
+		ps.writeByte(' ')
+	}
+	if ft.Accum {
+		ps.writeString("_Accum")
+	} else {
+		ps.writeString("_Fract")
+	}
+}
+
+func (ft *FixedType) Traverse(fn func(AST) bool) {
+	if fn(ft) {
+		ft.Base.Traverse(fn)
+	}
+}
+
+func (ft *FixedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(ft) {
+		return nil
+	}
+	base := ft.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(ft)
+	}
+	ft = &FixedType{Base: base, Accum: ft.Accum, Sat: ft.Sat}
+	if r := fn(ft); r != nil {
+		return r
+	}
+	return ft
+}
+
+func (ft *FixedType) GoString() string {
+	return ft.goString(0, "")
+}
+
+func (ft *FixedType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sFixedType: Accum: %t; Sat: %t\n%s", indent, "", field,
+		ft.Accum, ft.Sat,
+		ft.Base.goString(indent+2, "Base: "))
+}
+
+// VectorType is a vector type.
+type VectorType struct {
+	Dimension AST
+	Base      AST
+}
+
+func (vt *VectorType) print(ps *printState) {
+	ps.inner = append(ps.inner, vt)
+	ps.print(vt.Base)
+	if len(ps.inner) > 0 {
+		ps.printOneInner(nil)
+	}
+}
+
+func (vt *VectorType) printInner(ps *printState) {
+	ps.writeString(" __vector(")
+	ps.print(vt.Dimension)
+	ps.writeByte(')')
+}
+
+func (vt *VectorType) Traverse(fn func(AST) bool) {
+	if fn(vt) {
+		vt.Dimension.Traverse(fn)
+		vt.Base.Traverse(fn)
+	}
+}
+
+func (vt *VectorType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(vt) {
+		return nil
+	}
+	dimension := vt.Dimension.Copy(fn, skip)
+	base := vt.Base.Copy(fn, skip)
+	if dimension == nil && base == nil {
+		return fn(vt)
+	}
+	if dimension == nil {
+		dimension = vt.Dimension
+	}
+	if base == nil {
+		base = vt.Base
+	}
+	vt = &VectorType{Dimension: dimension, Base: base}
+	if r := fn(vt); r != nil {
+		return r
+	}
+	return vt
+}
+
+func (vt *VectorType) GoString() string {
+	return vt.goString(0, "")
+}
+
+func (vt *VectorType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sVectorType:\n%s\n%s", indent, "", field,
+		vt.Dimension.goString(indent+2, "Dimension: "),
+		vt.Base.goString(indent+2, "Base: "))
+}
+
+// Decltype is the decltype operator.
+type Decltype struct {
+	Expr AST
+}
+
+func (dt *Decltype) print(ps *printState) {
+	ps.writeString("decltype (")
+	ps.print(dt.Expr)
+	ps.writeByte(')')
+}
+
+func (dt *Decltype) Traverse(fn func(AST) bool) {
+	if fn(dt) {
+		dt.Expr.Traverse(fn)
+	}
+}
+
+func (dt *Decltype) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(dt) {
+		return nil
+	}
+	expr := dt.Expr.Copy(fn, skip)
+	if expr == nil {
+		return fn(dt)
+	}
+	dt = &Decltype{Expr: expr}
+	if r := fn(dt); r != nil {
+		return r
+	}
+	return dt
+}
+
+func (dt *Decltype) GoString() string {
+	return dt.goString(0, "")
+}
+
+func (dt *Decltype) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sDecltype:\n%s", indent, "", field,
+		dt.Expr.goString(indent+2, "Expr: "))
+}
+
+// Operator is an operator.
+type Operator struct {
+	Name string
+}
+
+func (op *Operator) print(ps *printState) {
+	ps.writeString("operator")
+	if isLower(op.Name[0]) {
+		ps.writeByte(' ')
+	}
+	n := op.Name
+	n = strings.TrimSuffix(n, " ")
+	ps.writeString(n)
+}
+
+func (op *Operator) Traverse(fn func(AST) bool) {
+	fn(op)
+}
+
+func (op *Operator) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(op) {
+		return nil
+	}
+	return fn(op)
+}
+
+func (op *Operator) GoString() string {
+	return op.goString(0, "")
+}
+
+func (op *Operator) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sOperator: %s", indent, "", field, op.Name)
+}
+
+// Constructor is a constructor.
+type Constructor struct {
+	Name AST
+}
+
+func (c *Constructor) print(ps *printState) {
+	ps.print(c.Name)
+}
+
+func (c *Constructor) Traverse(fn func(AST) bool) {
+	if fn(c) {
+		c.Name.Traverse(fn)
+	}
+}
+
+func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(c) {
+		return nil
+	}
+	name := c.Name.Copy(fn, skip)
+	if name == nil {
+		return fn(c)
+	}
+	c = &Constructor{Name: name}
+	if r := fn(c); r != nil {
+		return r
+	}
+	return c
+}
+
+func (c *Constructor) GoString() string {
+	return c.goString(0, "")
+}
+
+func (c *Constructor) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sConstructor:\n%s", indent, "", field, c.Name.goString(indent+2, "Name: "))
+}
+
+// Destructor is a destructor.
+type Destructor struct {
+	Name AST
+}
+
+func (d *Destructor) print(ps *printState) {
+	ps.writeByte('~')
+	ps.print(d.Name)
+}
+
+func (d *Destructor) Traverse(fn func(AST) bool) {
+	if fn(d) {
+		d.Name.Traverse(fn)
+	}
+}
+
+func (d *Destructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(d) {
+		return nil
+	}
+	name := d.Name.Copy(fn, skip)
+	if name == nil {
+		return fn(d)
+	}
+	d = &Destructor{Name: name}
+	if r := fn(d); r != nil {
+		return r
+	}
+	return d
+}
+
+func (d *Destructor) GoString() string {
+	return d.goString(0, "")
+}
+
+func (d *Destructor) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sDestructor:\n%s", indent, "", field, d.Name.goString(indent+2, "Name: "))
+}
+
+// GlobalCDtor is a global constructor or destructor.
+type GlobalCDtor struct {
+	Ctor bool
+	Key  AST
+}
+
+func (gcd *GlobalCDtor) print(ps *printState) {
+	ps.writeString("global ")
+	if gcd.Ctor {
+		ps.writeString("constructors")
+	} else {
+		ps.writeString("destructors")
+	}
+	ps.writeString(" keyed to ")
+	ps.print(gcd.Key)
+}
+
+func (gcd *GlobalCDtor) Traverse(fn func(AST) bool) {
+	if fn(gcd) {
+		gcd.Key.Traverse(fn)
+	}
+}
+
+func (gcd *GlobalCDtor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(gcd) {
+		return nil
+	}
+	key := gcd.Key.Copy(fn, skip)
+	if key == nil {
+		return fn(gcd)
+	}
+	gcd = &GlobalCDtor{Ctor: gcd.Ctor, Key: key}
+	if r := fn(gcd); r != nil {
+		return r
+	}
+	return gcd
+}
+
+func (gcd *GlobalCDtor) GoString() string {
+	return gcd.goString(0, "")
+}
+
+func (gcd *GlobalCDtor) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sGlobalCDtor: Ctor: %t\n%s", indent, "", field,
+		gcd.Ctor, gcd.Key.goString(indent+2, "Key: "))
+}
+
+// TaggedName is a name with an ABI tag.
+type TaggedName struct {
+	Name AST
+	Tag  AST
+}
+
+func (t *TaggedName) print(ps *printState) {
+	ps.print(t.Name)
+	ps.writeString("[abi:")
+	ps.print(t.Tag)
+	ps.writeByte(']')
+}
+
+func (t *TaggedName) Traverse(fn func(AST) bool) {
+	if fn(t) {
+		t.Name.Traverse(fn)
+		t.Tag.Traverse(fn)
+	}
+}
+
+func (t *TaggedName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(t) {
+		return nil
+	}
+	name := t.Name.Copy(fn, skip)
+	tag := t.Tag.Copy(fn, skip)
+	if name == nil && tag == nil {
+		return fn(t)
+	}
+	if name == nil {
+		name = t.Name
+	}
+	if tag == nil {
+		tag = t.Tag
+	}
+	t = &TaggedName{Name: name, Tag: tag}
+	if r := fn(t); r != nil {
+		return r
+	}
+	return t
+}
+
+func (t *TaggedName) GoString() string {
+	return t.goString(0, "")
+}
+
+func (t *TaggedName) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sTaggedName:\n%s\n%s", indent, "", field,
+		t.Name.goString(indent+2, "Name: "),
+		t.Tag.goString(indent+2, "Tag: "))
+}
+
+// PackExpansion is a pack expansion.  The Pack field may be nil.
+type PackExpansion struct {
+	Base AST
+	Pack *ArgumentPack
+}
+
+func (pe *PackExpansion) print(ps *printState) {
+	// We normally only get here if the simplify function was
+	// unable to locate and expand the pack.
+	if pe.Pack == nil {
+		parenthesize(ps, pe.Base)
+		ps.writeString("...")
+	} else {
+		ps.print(pe.Base)
+	}
+}
+
+func (pe *PackExpansion) Traverse(fn func(AST) bool) {
+	if fn(pe) {
+		pe.Base.Traverse(fn)
+		// Don't traverse Template--it points elsewhere in the AST.
+	}
+}
+
+func (pe *PackExpansion) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(pe) {
+		return nil
+	}
+	base := pe.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(pe)
+	}
+	pe = &PackExpansion{Base: base, Pack: pe.Pack}
+	if r := fn(pe); r != nil {
+		return r
+	}
+	return pe
+}
+
+func (pe *PackExpansion) GoString() string {
+	return pe.goString(0, "")
+}
+
+func (pe *PackExpansion) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sPackExpansion: Pack: %p\n%s", indent, "", field,
+		pe.Pack, pe.Base.goString(indent+2, "Base: "))
+}
+
+// ArgumentPack is an argument pack.
+type ArgumentPack struct {
+	Args []AST
+}
+
+func (ap *ArgumentPack) print(ps *printState) {
+	for i, a := range ap.Args {
+		if i > 0 {
+			ps.writeString(", ")
+		}
+		ps.print(a)
+	}
+}
+
+func (ap *ArgumentPack) Traverse(fn func(AST) bool) {
+	if fn(ap) {
+		for _, a := range ap.Args {
+			a.Traverse(fn)
+		}
+	}
+}
+
+func (ap *ArgumentPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(ap) {
+		return nil
+	}
+	args := make([]AST, len(ap.Args))
+	changed := false
+	for i, a := range ap.Args {
+		ac := a.Copy(fn, skip)
+		if ac == nil {
+			args[i] = a
+		} else {
+			args[i] = ac
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(ap)
+	}
+	ap = &ArgumentPack{Args: args}
+	if r := fn(ap); r != nil {
+		return r
+	}
+	return ap
+}
+
+func (ap *ArgumentPack) GoString() string {
+	return ap.goString(0, "")
+}
+
+func (ap *ArgumentPack) goString(indent int, field string) string {
+	if len(ap.Args) == 0 {
+		return fmt.Sprintf("%*s%sArgumentPack: nil", indent, "", field)
+	}
+	s := fmt.Sprintf("%*s%sArgumentPack:", indent, "", field)
+	for i, a := range ap.Args {
+		s += "\n"
+		s += a.goString(indent+2, fmt.Sprintf("%d: ", i))
+	}
+	return s
+}
+
+// SizeofPack is the sizeof operator applied to an argument pack.
+type SizeofPack struct {
+	Pack *ArgumentPack
+}
+
+func (sp *SizeofPack) print(ps *printState) {
+	ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+}
+
+func (sp *SizeofPack) Traverse(fn func(AST) bool) {
+	fn(sp)
+	// Don't traverse the pack--it points elsewhere in the AST.
+}
+
+func (sp *SizeofPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(sp) {
+		return nil
+	}
+	sp = &SizeofPack{Pack: sp.Pack}
+	if r := fn(sp); r != nil {
+		return r
+	}
+	return sp
+}
+
+func (sp *SizeofPack) GoString() string {
+	return sp.goString(0, "")
+}
+
+func (sp *SizeofPack) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sSizeofPack: Pack: %p", indent, "", field, sp.Pack)
+}
+
+// SizeofArgs is the size of a captured template parameter pack from
+// an alias template.
+type SizeofArgs struct {
+	Args []AST
+}
+
+func (sa *SizeofArgs) print(ps *printState) {
+	c := 0
+	for _, a := range sa.Args {
+		if ap, ok := a.(*ArgumentPack); ok {
+			c += len(ap.Args)
+		} else if el, ok := a.(*ExprList); ok {
+			c += len(el.Exprs)
+		} else {
+			c++
+		}
+	}
+	ps.writeString(fmt.Sprintf("%d", c))
+}
+
+func (sa *SizeofArgs) Traverse(fn func(AST) bool) {
+	if fn(sa) {
+		for _, a := range sa.Args {
+			a.Traverse(fn)
+		}
+	}
+}
+
+func (sa *SizeofArgs) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(sa) {
+		return nil
+	}
+	changed := false
+	args := make([]AST, len(sa.Args))
+	for i, a := range sa.Args {
+		ac := a.Copy(fn, skip)
+		if ac == nil {
+			args[i] = a
+		} else {
+			args[i] = ac
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(sa)
+	}
+	sa = &SizeofArgs{Args: args}
+	if r := fn(sa); r != nil {
+		return r
+	}
+	return sa
+}
+
+func (sa *SizeofArgs) GoString() string {
+	return sa.goString(0, "")
+}
+
+func (sa *SizeofArgs) goString(indent int, field string) string {
+	var args string
+	if len(sa.Args) == 0 {
+		args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+	} else {
+		args = fmt.Sprintf("%*sArgs:", indent+2, "")
+		for i, a := range sa.Args {
+			args += "\n"
+			args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+		}
+	}
+	return fmt.Sprintf("%*s%sSizeofArgs:\n%s", indent, "", field, args)
+}
+
+// Cast is a type cast.
+type Cast struct {
+	To AST
+}
+
+func (c *Cast) print(ps *printState) {
+	ps.writeString("operator ")
+	ps.print(c.To)
+}
+
+func (c *Cast) Traverse(fn func(AST) bool) {
+	if fn(c) {
+		c.To.Traverse(fn)
+	}
+}
+
+func (c *Cast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(c) {
+		return nil
+	}
+	to := c.To.Copy(fn, skip)
+	if to == nil {
+		return fn(c)
+	}
+	c = &Cast{To: to}
+	if r := fn(c); r != nil {
+		return r
+	}
+	return c
+}
+
+func (c *Cast) GoString() string {
+	return c.goString(0, "")
+}
+
+func (c *Cast) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sCast\n%s", indent, "", field,
+		c.To.goString(indent+2, "To: "))
+}
+
+// The parenthesize function prints the string for val, wrapped in
+// parentheses if necessary.
+func parenthesize(ps *printState, val AST) {
+	paren := false
+	switch v := val.(type) {
+	case *Name, *InitializerList, *FunctionParam:
+	case *Qualified:
+		if v.LocalName {
+			paren = true
+		}
+	default:
+		paren = true
+	}
+	if paren {
+		ps.writeByte('(')
+	}
+	ps.print(val)
+	if paren {
+		ps.writeByte(')')
+	}
+}
+
+// Nullary is an operator in an expression with no arguments, such as
+// throw.
+type Nullary struct {
+	Op AST
+}
+
+func (n *Nullary) print(ps *printState) {
+	if op, ok := n.Op.(*Operator); ok {
+		ps.writeString(op.Name)
+	} else {
+		ps.print(n.Op)
+	}
+}
+
+func (n *Nullary) Traverse(fn func(AST) bool) {
+	if fn(n) {
+		n.Op.Traverse(fn)
+	}
+}
+
+func (n *Nullary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(n) {
+		return nil
+	}
+	op := n.Op.Copy(fn, skip)
+	if op == nil {
+		return fn(n)
+	}
+	n = &Nullary{Op: op}
+	if r := fn(n); r != nil {
+		return r
+	}
+	return n
+}
+
+func (n *Nullary) GoString() string {
+	return n.goString(0, "")
+}
+
+func (n *Nullary) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sNullary:\n%s", indent, "", field,
+		n.Op.goString(indent+2, "Op: "))
+}
+
+// Unary is a unary operation in an expression.
+type Unary struct {
+	Op         AST
+	Expr       AST
+	Suffix     bool // true for ++ -- when used as postfix
+	SizeofType bool // true for sizeof (type)
+}
+
+func (u *Unary) print(ps *printState) {
+	expr := u.Expr
+
+	// Don't print the argument list when taking the address of a
+	// function.
+	if op, ok := u.Op.(*Operator); ok && op.Name == "&" {
+		if t, ok := expr.(*Typed); ok {
+			if _, ok := t.Type.(*FunctionType); ok {
+				expr = t.Name
+			}
+		}
+	}
+
+	if u.Suffix {
+		parenthesize(ps, expr)
+	}
+
+	if op, ok := u.Op.(*Operator); ok {
+		ps.writeString(op.Name)
+	} else if c, ok := u.Op.(*Cast); ok {
+		ps.writeByte('(')
+		ps.print(c.To)
+		ps.writeByte(')')
+	} else {
+		ps.print(u.Op)
+	}
+
+	if !u.Suffix {
+		if op, ok := u.Op.(*Operator); ok && op.Name == "::" {
+			// Don't use parentheses after ::.
+			ps.print(expr)
+		} else if u.SizeofType {
+			// Always use parentheses for sizeof argument.
+			ps.writeByte('(')
+			ps.print(expr)
+			ps.writeByte(')')
+		} else {
+			parenthesize(ps, expr)
+		}
+	}
+}
+
+func (u *Unary) Traverse(fn func(AST) bool) {
+	if fn(u) {
+		u.Op.Traverse(fn)
+		u.Expr.Traverse(fn)
+	}
+}
+
+func (u *Unary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(u) {
+		return nil
+	}
+	op := u.Op.Copy(fn, skip)
+	expr := u.Expr.Copy(fn, skip)
+	if op == nil && expr == nil {
+		return fn(u)
+	}
+	if op == nil {
+		op = u.Op
+	}
+	if expr == nil {
+		expr = u.Expr
+	}
+	u = &Unary{Op: op, Expr: expr, Suffix: u.Suffix, SizeofType: u.SizeofType}
+	if r := fn(u); r != nil {
+		return r
+	}
+	return u
+}
+
+func (u *Unary) GoString() string {
+	return u.goString(0, "")
+}
+
+func (u *Unary) goString(indent int, field string) string {
+	var s string
+	if u.Suffix {
+		s = " Suffix: true"
+	}
+	if u.SizeofType {
+		s += " SizeofType: true"
+	}
+	return fmt.Sprintf("%*s%sUnary:%s\n%s\n%s", indent, "", field,
+		s, u.Op.goString(indent+2, "Op: "),
+		u.Expr.goString(indent+2, "Expr: "))
+}
+
+// Binary is a binary operation in an expression.
+type Binary struct {
+	Op    AST
+	Left  AST
+	Right AST
+}
+
+func (b *Binary) print(ps *printState) {
+	op, _ := b.Op.(*Operator)
+
+	if op != nil && strings.Contains(op.Name, "cast") {
+		ps.writeString(op.Name)
+		ps.writeByte('<')
+		ps.print(b.Left)
+		ps.writeString(">(")
+		ps.print(b.Right)
+		ps.writeByte(')')
+		return
+	}
+
+	// Use an extra set of parentheses around an expression that
+	// uses the greater-than operator, so that it does not get
+	// confused with the '>' that ends template parameters.
+	if op != nil && op.Name == ">" {
+		ps.writeByte('(')
+	}
+
+	left := b.Left
+
+	// A function call in an expression should not print the types
+	// of the arguments.
+	if op != nil && op.Name == "()" {
+		if ty, ok := b.Left.(*Typed); ok {
+			left = ty.Name
+		}
+	}
+
+	parenthesize(ps, left)
+
+	if op != nil && op.Name == "[]" {
+		ps.writeByte('[')
+		ps.print(b.Right)
+		ps.writeByte(']')
+		return
+	}
+
+	if op != nil {
+		if op.Name != "()" {
+			ps.writeString(op.Name)
+		}
+	} else {
+		ps.print(b.Op)
+	}
+
+	parenthesize(ps, b.Right)
+
+	if op != nil && op.Name == ">" {
+		ps.writeByte(')')
+	}
+}
+
+func (b *Binary) Traverse(fn func(AST) bool) {
+	if fn(b) {
+		b.Op.Traverse(fn)
+		b.Left.Traverse(fn)
+		b.Right.Traverse(fn)
+	}
+}
+
+func (b *Binary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(b) {
+		return nil
+	}
+	op := b.Op.Copy(fn, skip)
+	left := b.Left.Copy(fn, skip)
+	right := b.Right.Copy(fn, skip)
+	if op == nil && left == nil && right == nil {
+		return fn(b)
+	}
+	if op == nil {
+		op = b.Op
+	}
+	if left == nil {
+		left = b.Left
+	}
+	if right == nil {
+		right = b.Right
+	}
+	b = &Binary{Op: op, Left: left, Right: right}
+	if r := fn(b); r != nil {
+		return r
+	}
+	return b
+}
+
+func (b *Binary) GoString() string {
+	return b.goString(0, "")
+}
+
+func (b *Binary) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sBinary:\n%s\n%s\n%s", indent, "", field,
+		b.Op.goString(indent+2, "Op: "),
+		b.Left.goString(indent+2, "Left: "),
+		b.Right.goString(indent+2, "Right: "))
+}
+
+// Trinary is the ?: trinary operation in an expression.
+type Trinary struct {
+	Op     AST
+	First  AST
+	Second AST
+	Third  AST
+}
+
+func (t *Trinary) print(ps *printState) {
+	parenthesize(ps, t.First)
+	ps.writeByte('?')
+	parenthesize(ps, t.Second)
+	ps.writeString(" : ")
+	parenthesize(ps, t.Third)
+}
+
+func (t *Trinary) Traverse(fn func(AST) bool) {
+	if fn(t) {
+		t.Op.Traverse(fn)
+		t.First.Traverse(fn)
+		t.Second.Traverse(fn)
+		t.Third.Traverse(fn)
+	}
+}
+
+func (t *Trinary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(t) {
+		return nil
+	}
+	op := t.Op.Copy(fn, skip)
+	first := t.First.Copy(fn, skip)
+	second := t.Second.Copy(fn, skip)
+	third := t.Third.Copy(fn, skip)
+	if op == nil && first == nil && second == nil && third == nil {
+		return fn(t)
+	}
+	if op == nil {
+		op = t.Op
+	}
+	if first == nil {
+		first = t.First
+	}
+	if second == nil {
+		second = t.Second
+	}
+	if third == nil {
+		third = t.Third
+	}
+	t = &Trinary{Op: op, First: first, Second: second, Third: third}
+	if r := fn(t); r != nil {
+		return r
+	}
+	return t
+}
+
+func (t *Trinary) GoString() string {
+	return t.goString(0, "")
+}
+
+func (t *Trinary) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sTrinary:\n%s\n%s\n%s\n%s", indent, "", field,
+		t.Op.goString(indent+2, "Op: "),
+		t.First.goString(indent+2, "First: "),
+		t.Second.goString(indent+2, "Second: "),
+		t.Third.goString(indent+2, "Third: "))
+}
+
+// Fold is a C++17 fold-expression.  Arg2 is nil for a unary operator.
+type Fold struct {
+	Left bool
+	Op   AST
+	Arg1 AST
+	Arg2 AST
+}
+
+func (f *Fold) print(ps *printState) {
+	op, _ := f.Op.(*Operator)
+	printOp := func() {
+		if op != nil {
+			ps.writeString(op.Name)
+		} else {
+			ps.print(f.Op)
+		}
+	}
+
+	if f.Arg2 == nil {
+		if f.Left {
+			ps.writeString("(...")
+			printOp()
+			parenthesize(ps, f.Arg1)
+			ps.writeString(")")
+		} else {
+			ps.writeString("(")
+			parenthesize(ps, f.Arg1)
+			printOp()
+			ps.writeString("...)")
+		}
+	} else {
+		ps.writeString("(")
+		parenthesize(ps, f.Arg1)
+		printOp()
+		ps.writeString("...")
+		printOp()
+		parenthesize(ps, f.Arg2)
+		ps.writeString(")")
+	}
+}
+
+func (f *Fold) Traverse(fn func(AST) bool) {
+	if fn(f) {
+		f.Op.Traverse(fn)
+		f.Arg1.Traverse(fn)
+		if f.Arg2 != nil {
+			f.Arg2.Traverse(fn)
+		}
+	}
+}
+
+func (f *Fold) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(f) {
+		return nil
+	}
+	op := f.Op.Copy(fn, skip)
+	arg1 := f.Arg1.Copy(fn, skip)
+	var arg2 AST
+	if f.Arg2 != nil {
+		arg2 = f.Arg2.Copy(fn, skip)
+	}
+	if op == nil && arg1 == nil && arg2 == nil {
+		return fn(f)
+	}
+	if op == nil {
+		op = f.Op
+	}
+	if arg1 == nil {
+		arg1 = f.Arg1
+	}
+	if arg2 == nil {
+		arg2 = f.Arg2
+	}
+	f = &Fold{Left: f.Left, Op: op, Arg1: arg1, Arg2: arg2}
+	if r := fn(f); r != nil {
+		return r
+	}
+	return f
+}
+
+func (f *Fold) GoString() string {
+	return f.goString(0, "")
+}
+
+func (f *Fold) goString(indent int, field string) string {
+	if f.Arg2 == nil {
+		return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s", indent, "", field,
+			f.Left, f.Op.goString(indent+2, "Op: "),
+			f.Arg1.goString(indent+2, "Arg1: "))
+	} else {
+		return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s\n%s", indent, "", field,
+			f.Left, f.Op.goString(indent+2, "Op: "),
+			f.Arg1.goString(indent+2, "Arg1: "),
+			f.Arg2.goString(indent+2, "Arg2: "))
+	}
+}
+
+// New is a use of operator new in an expression.
+type New struct {
+	Op    AST
+	Place AST
+	Type  AST
+	Init  AST
+}
+
+func (n *New) print(ps *printState) {
+	// Op doesn't really matter for printing--we always print "new".
+	ps.writeString("new ")
+	if n.Place != nil {
+		parenthesize(ps, n.Place)
+		ps.writeByte(' ')
+	}
+	ps.print(n.Type)
+	if n.Init != nil {
+		parenthesize(ps, n.Init)
+	}
+}
+
+func (n *New) Traverse(fn func(AST) bool) {
+	if fn(n) {
+		n.Op.Traverse(fn)
+		if n.Place != nil {
+			n.Place.Traverse(fn)
+		}
+		n.Type.Traverse(fn)
+		if n.Init != nil {
+			n.Init.Traverse(fn)
+		}
+	}
+}
+
+func (n *New) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(n) {
+		return nil
+	}
+	op := n.Op.Copy(fn, skip)
+	var place AST
+	if n.Place != nil {
+		place = n.Place.Copy(fn, skip)
+	}
+	typ := n.Type.Copy(fn, skip)
+	var ini AST
+	if n.Init != nil {
+		ini = n.Init.Copy(fn, skip)
+	}
+	if op == nil && place == nil && typ == nil && ini == nil {
+		return fn(n)
+	}
+	if op == nil {
+		op = n.Op
+	}
+	if place == nil {
+		place = n.Place
+	}
+	if typ == nil {
+		typ = n.Type
+	}
+	if ini == nil {
+		ini = n.Init
+	}
+	n = &New{Op: op, Place: place, Type: typ, Init: ini}
+	if r := fn(n); r != nil {
+		return r
+	}
+	return n
+}
+
+func (n *New) GoString() string {
+	return n.goString(0, "")
+}
+
+func (n *New) goString(indent int, field string) string {
+	var place string
+	if n.Place == nil {
+		place = fmt.Sprintf("%*sPlace: nil", indent, "")
+	} else {
+		place = n.Place.goString(indent+2, "Place: ")
+	}
+	var ini string
+	if n.Init == nil {
+		ini = fmt.Sprintf("%*sInit: nil", indent, "")
+	} else {
+		ini = n.Init.goString(indent+2, "Init: ")
+	}
+	return fmt.Sprintf("%*s%sNew:\n%s\n%s\n%s\n%s", indent, "", field,
+		n.Op.goString(indent+2, "Op: "), place,
+		n.Type.goString(indent+2, "Type: "), ini)
+}
+
+// Literal is a literal in an expression.
+type Literal struct {
+	Type AST
+	Val  string
+	Neg  bool
+}
+
+// Suffixes to use for constants of the given integer type.
+var builtinTypeSuffix = map[string]string{
+	"int":                "",
+	"unsigned int":       "u",
+	"long":               "l",
+	"unsigned long":      "ul",
+	"long long":          "ll",
+	"unsigned long long": "ull",
+}
+
+// Builtin float types.
+var builtinTypeFloat = map[string]bool{
+	"double":      true,
+	"long double": true,
+	"float":       true,
+	"__float128":  true,
+	"half":        true,
+}
+
+func (l *Literal) print(ps *printState) {
+	isFloat := false
+	if b, ok := l.Type.(*BuiltinType); ok {
+		if suffix, ok := builtinTypeSuffix[b.Name]; ok {
+			if l.Neg {
+				ps.writeByte('-')
+			}
+			ps.writeString(l.Val)
+			ps.writeString(suffix)
+			return
+		} else if b.Name == "bool" && !l.Neg {
+			switch l.Val {
+			case "0":
+				ps.writeString("false")
+				return
+			case "1":
+				ps.writeString("true")
+				return
+			}
+		} else {
+			isFloat = builtinTypeFloat[b.Name]
+		}
+	}
+
+	ps.writeByte('(')
+	ps.print(l.Type)
+	ps.writeByte(')')
+
+	if isFloat {
+		ps.writeByte('[')
+	}
+	if l.Neg {
+		ps.writeByte('-')
+	}
+	ps.writeString(l.Val)
+	if isFloat {
+		ps.writeByte(']')
+	}
+}
+
+func (l *Literal) Traverse(fn func(AST) bool) {
+	if fn(l) {
+		l.Type.Traverse(fn)
+	}
+}
+
+func (l *Literal) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(l) {
+		return nil
+	}
+	typ := l.Type.Copy(fn, skip)
+	if typ == nil {
+		return fn(l)
+	}
+	l = &Literal{Type: typ, Val: l.Val, Neg: l.Neg}
+	if r := fn(l); r != nil {
+		return r
+	}
+	return l
+}
+
+func (l *Literal) GoString() string {
+	return l.goString(0, "")
+}
+
+func (l *Literal) goString(indent int, field string) string {
+	var neg string
+	if l.Neg {
+		neg = " Neg: true"
+	}
+	return fmt.Sprintf("%*s%sLiteral:%s\n%s\n%*sVal: %s", indent, "", field,
+		neg, l.Type.goString(indent+2, "Type: "),
+		indent+2, "", l.Val)
+}
+
+// ExprList is a list of expressions, typically arguments to a
+// function call in an expression.
+type ExprList struct {
+	Exprs []AST
+}
+
+func (el *ExprList) print(ps *printState) {
+	for i, e := range el.Exprs {
+		if i > 0 {
+			ps.writeString(", ")
+		}
+		ps.print(e)
+	}
+}
+
+func (el *ExprList) Traverse(fn func(AST) bool) {
+	if fn(el) {
+		for _, e := range el.Exprs {
+			e.Traverse(fn)
+		}
+	}
+}
+
+func (el *ExprList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(el) {
+		return nil
+	}
+	exprs := make([]AST, len(el.Exprs))
+	changed := false
+	for i, e := range el.Exprs {
+		ec := e.Copy(fn, skip)
+		if ec == nil {
+			exprs[i] = e
+		} else {
+			exprs[i] = ec
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(el)
+	}
+	el = &ExprList{Exprs: exprs}
+	if r := fn(el); r != nil {
+		return r
+	}
+	return el
+}
+
+func (el *ExprList) GoString() string {
+	return el.goString(0, "")
+}
+
+func (el *ExprList) goString(indent int, field string) string {
+	if len(el.Exprs) == 0 {
+		return fmt.Sprintf("%*s%sExprList: nil", indent, "", field)
+	}
+	s := fmt.Sprintf("%*s%sExprList:", indent, "", field)
+	for i, e := range el.Exprs {
+		s += "\n"
+		s += e.goString(indent+2, fmt.Sprintf("%d: ", i))
+	}
+	return s
+}
+
+// InitializerList is an initializer list: an optional type with a
+// list of expressions.
+type InitializerList struct {
+	Type  AST
+	Exprs AST
+}
+
+func (il *InitializerList) print(ps *printState) {
+	if il.Type != nil {
+		ps.print(il.Type)
+	}
+	ps.writeByte('{')
+	ps.print(il.Exprs)
+	ps.writeByte('}')
+}
+
+func (il *InitializerList) Traverse(fn func(AST) bool) {
+	if fn(il) {
+		if il.Type != nil {
+			il.Type.Traverse(fn)
+		}
+		il.Exprs.Traverse(fn)
+	}
+}
+
+func (il *InitializerList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(il) {
+		return nil
+	}
+	var typ AST
+	if il.Type != nil {
+		typ = il.Type.Copy(fn, skip)
+	}
+	exprs := il.Exprs.Copy(fn, skip)
+	if typ == nil && exprs == nil {
+		return fn(il)
+	}
+	if typ == nil {
+		typ = il.Type
+	}
+	if exprs == nil {
+		exprs = il.Exprs
+	}
+	il = &InitializerList{Type: typ, Exprs: exprs}
+	if r := fn(il); r != nil {
+		return r
+	}
+	return il
+}
+
+func (il *InitializerList) GoString() string {
+	return il.goString(0, "")
+}
+
+func (il *InitializerList) goString(indent int, field string) string {
+	var t string
+	if il.Type == nil {
+		t = fmt.Sprintf("%*sType: nil", indent+2, "")
+	} else {
+		t = il.Type.goString(indent+2, "Type: ")
+	}
+	return fmt.Sprintf("%*s%sInitializerList:\n%s\n%s", indent, "", field,
+		t, il.Exprs.goString(indent+2, "Exprs: "))
+}
+
+// DefaultArg holds a default argument for a local name.
+type DefaultArg struct {
+	Num int
+	Arg AST
+}
+
+func (da *DefaultArg) print(ps *printState) {
+	fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+	ps.print(da.Arg)
+}
+
+func (da *DefaultArg) Traverse(fn func(AST) bool) {
+	if fn(da) {
+		da.Arg.Traverse(fn)
+	}
+}
+
+func (da *DefaultArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(da) {
+		return nil
+	}
+	arg := da.Arg.Copy(fn, skip)
+	if arg == nil {
+		return fn(da)
+	}
+	da = &DefaultArg{Num: da.Num, Arg: arg}
+	if r := fn(da); r != nil {
+		return r
+	}
+	return da
+}
+
+func (da *DefaultArg) GoString() string {
+	return da.goString(0, "")
+}
+
+func (da *DefaultArg) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sDefaultArg: Num: %d\n%s", indent, "", field, da.Num,
+		da.Arg.goString(indent+2, "Arg: "))
+}
+
+// Closure is a closure, or lambda expression.
+type Closure struct {
+	Types []AST
+	Num   int
+}
+
+func (cl *Closure) print(ps *printState) {
+	ps.writeString("{lambda(")
+	for i, t := range cl.Types {
+		if i > 0 {
+			ps.writeString(", ")
+		}
+		ps.print(t)
+	}
+	ps.writeString(fmt.Sprintf(")#%d}", cl.Num+1))
+}
+
+func (cl *Closure) Traverse(fn func(AST) bool) {
+	if fn(cl) {
+		for _, t := range cl.Types {
+			t.Traverse(fn)
+		}
+	}
+}
+
+func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(cl) {
+		return nil
+	}
+	types := make([]AST, len(cl.Types))
+	changed := false
+	for i, t := range cl.Types {
+		tc := t.Copy(fn, skip)
+		if tc == nil {
+			types[i] = t
+		} else {
+			types[i] = tc
+			changed = true
+		}
+	}
+	if !changed {
+		return fn(cl)
+	}
+	cl = &Closure{Types: types, Num: cl.Num}
+	if r := fn(cl); r != nil {
+		return r
+	}
+	return cl
+}
+
+func (cl *Closure) GoString() string {
+	return cl.goString(0, "")
+}
+
+func (cl *Closure) goString(indent int, field string) string {
+	var types string
+	if len(cl.Types) == 0 {
+		types = fmt.Sprintf("%*sTypes: nil", indent+2, "")
+	} else {
+		types = fmt.Sprintf("%*sTypes:", indent+2, "")
+		for i, t := range cl.Types {
+			types += "\n"
+			types += t.goString(indent+4, fmt.Sprintf("%d: ", i))
+		}
+	}
+	return fmt.Sprintf("%*s%sClosure: Num: %d\n%s", indent, "", field, cl.Num, types)
+}
+
+// UnnamedType is an unnamed type, that just has an index.
+type UnnamedType struct {
+	Num int
+}
+
+func (ut *UnnamedType) print(ps *printState) {
+	ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+}
+
+func (ut *UnnamedType) Traverse(fn func(AST) bool) {
+	fn(ut)
+}
+
+func (ut *UnnamedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(ut) {
+		return nil
+	}
+	return fn(ut)
+}
+
+func (ut *UnnamedType) GoString() string {
+	return ut.goString(0, "")
+}
+
+func (ut *UnnamedType) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sUnnamedType: Num: %d", indent, "", field, ut.Num)
+}
+
+// Clone is a clone of a function, with a distinguishing suffix.
+type Clone struct {
+	Base   AST
+	Suffix string
+}
+
+func (c *Clone) print(ps *printState) {
+	ps.print(c.Base)
+	ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+}
+
+func (c *Clone) Traverse(fn func(AST) bool) {
+	if fn(c) {
+		c.Base.Traverse(fn)
+	}
+}
+
+func (c *Clone) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(c) {
+		return nil
+	}
+	base := c.Base.Copy(fn, skip)
+	if base == nil {
+		return fn(c)
+	}
+	c = &Clone{Base: base, Suffix: c.Suffix}
+	if r := fn(c); r != nil {
+		return r
+	}
+	return c
+}
+
+func (c *Clone) GoString() string {
+	return c.goString(0, "")
+}
+
+func (c *Clone) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sClone: Suffix: %s\n%s", indent, "", field,
+		c.Suffix, c.Base.goString(indent+2, "Base: "))
+}
+
+// Special is a special symbol, printed as a prefix plus another
+// value.
+type Special struct {
+	Prefix string
+	Val    AST
+}
+
+func (s *Special) print(ps *printState) {
+	ps.writeString(s.Prefix)
+	ps.print(s.Val)
+}
+
+func (s *Special) Traverse(fn func(AST) bool) {
+	if fn(s) {
+		s.Val.Traverse(fn)
+	}
+}
+
+func (s *Special) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(s) {
+		return nil
+	}
+	val := s.Val.Copy(fn, skip)
+	if val == nil {
+		return fn(s)
+	}
+	s = &Special{Prefix: s.Prefix, Val: val}
+	if r := fn(s); r != nil {
+		return r
+	}
+	return s
+}
+
+func (s *Special) GoString() string {
+	return s.goString(0, "")
+}
+
+func (s *Special) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sSpecial: Prefix: %s\n%s", indent, "", field,
+		s.Prefix, s.Val.goString(indent+2, "Val: "))
+}
+
+// Special2 is like special, but uses two values.
+type Special2 struct {
+	Prefix string
+	Val1   AST
+	Middle string
+	Val2   AST
+}
+
+func (s *Special2) print(ps *printState) {
+	ps.writeString(s.Prefix)
+	ps.print(s.Val1)
+	ps.writeString(s.Middle)
+	ps.print(s.Val2)
+}
+
+func (s *Special2) Traverse(fn func(AST) bool) {
+	if fn(s) {
+		s.Val1.Traverse(fn)
+		s.Val2.Traverse(fn)
+	}
+}
+
+func (s *Special2) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+	if skip(s) {
+		return nil
+	}
+	val1 := s.Val1.Copy(fn, skip)
+	val2 := s.Val2.Copy(fn, skip)
+	if val1 == nil && val2 == nil {
+		return fn(s)
+	}
+	if val1 == nil {
+		val1 = s.Val1
+	}
+	if val2 == nil {
+		val2 = s.Val2
+	}
+	s = &Special2{Prefix: s.Prefix, Val1: val1, Middle: s.Middle, Val2: val2}
+	if r := fn(s); r != nil {
+		return r
+	}
+	return s
+}
+
+func (s *Special2) GoString() string {
+	return s.goString(0, "")
+}
+
+func (s *Special2) goString(indent int, field string) string {
+	return fmt.Sprintf("%*s%sSpecial2: Prefix: %s\n%s\n%*sMiddle: %s\n%s", indent, "", field,
+		s.Prefix, s.Val1.goString(indent+2, "Val1: "),
+		indent+2, "", s.Middle, s.Val2.goString(indent+2, "Val2: "))
+}
+
+// Print the inner types.
+func (ps *printState) printInner(prefixOnly bool) []AST {
+	var save []AST
+	var psave *[]AST
+	if prefixOnly {
+		psave = &save
+	}
+	for len(ps.inner) > 0 {
+		ps.printOneInner(psave)
+	}
+	return save
+}
+
+// innerPrinter is an interface for types that can print themselves as
+// inner types.
+type innerPrinter interface {
+	printInner(*printState)
+}
+
+// Print the most recent inner type.  If save is not nil, only print
+// prefixes.
+func (ps *printState) printOneInner(save *[]AST) {
+	if len(ps.inner) == 0 {
+		panic("printOneInner called with no inner types")
+	}
+	ln := len(ps.inner)
+	a := ps.inner[ln-1]
+	ps.inner = ps.inner[:ln-1]
+
+	if save != nil {
+		if _, ok := a.(*MethodWithQualifiers); ok {
+			*save = append(*save, a)
+			return
+		}
+	}
+
+	if ip, ok := a.(innerPrinter); ok {
+		ip.printInner(ps)
+	} else {
+		ps.print(a)
+	}
+}
+
+// isEmpty returns whether printing a will not print anything.
+func (ps *printState) isEmpty(a AST) bool {
+	switch a := a.(type) {
+	case *ArgumentPack:
+		return len(a.Args) == 0
+	case *ExprList:
+		return len(a.Exprs) == 0
+	case *PackExpansion:
+		return a.Pack != nil && ps.isEmpty(a.Base)
+	default:
+		return false
+	}
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast_test.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast_test.go
new file mode 100644
index 0000000..b554061
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/ast_test.go
@@ -0,0 +1,42 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package demangle
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestASTToString(t *testing.T) {
+	var tests = []struct {
+		input     AST
+		want      string
+		formatted string
+	}{
+		{
+			&Qualified{Scope: &Name{Name: "s"}, Name: &Name{Name: "C"}},
+			"s::C",
+			`Qualified:
+  Scope: s
+  Name: C`,
+		},
+		{
+			&Typed{Name: &Name{Name: "v"}, Type: &BuiltinType{"int"}},
+			"int v",
+			`Typed:
+  Name: v
+  Type: BuiltinType: int`,
+		},
+	}
+
+	for i, test := range tests {
+		if got := ASTToString(test.input); got != test.want {
+			t.Errorf("ASTToString of test %d == %s, want %s", i, test.input, test.want)
+		}
+		if got := fmt.Sprintf("%#v", test.input); got != test.formatted {
+			t.Errorf("Formatted test %d == %s, want %s", i, got, test.formatted)
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/c++filt.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/c++filt.go
new file mode 100644
index 0000000..7ba817c
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/c++filt.go
@@ -0,0 +1,144 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This is a program that works like the GNU c++filt program.
+// It's here for testing purposes and as an example.
+
+package main
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"unicode"
+
+	"github.com/ianlancetaylor/demangle"
+)
+
+func flagUsage() {
+	usage(os.Stderr, 2)
+}
+
+func usage(w io.Writer, status int) {
+	fmt.Fprintf(w, "Usage: %s [options] [mangled names]\n", os.Args[0])
+	flag.CommandLine.SetOutput(w)
+	flag.PrintDefaults()
+	fmt.Fprintln(w, `Demangled names are displayed to stdout
+If a name cannot be demangled it is just echoed to stdout.
+If no names are provided on the command line, stdin is read.`)
+	os.Exit(status)
+}
+
+var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore")
+var noParams = flag.Bool("p", false, "Do not display function argument types")
+var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)")
+var help = flag.Bool("h", false, "Display help information")
+var debug = flag.Bool("d", false, "Display debugging information for strings on command line")
+
+// Unimplemented c++filt flags:
+// -n (opposite of -_)
+// -t (demangle types)
+// -s (set demangling style)
+// -V (print version information)
+
+// Characters considered to be part of a symbol.
+const symbolChars = "_$."
+
+func main() {
+	flag.Usage = func() { usage(os.Stderr, 1) }
+	flag.Parse()
+
+	if *help {
+		usage(os.Stdout, 0)
+	}
+
+	out := bufio.NewWriter(os.Stdout)
+
+	if flag.NArg() > 0 {
+		for _, f := range flag.Args() {
+			if *debug {
+				a, err := demangle.ToAST(f, options()...)
+				if err != nil {
+					fmt.Fprintf(os.Stderr, "%s: %v\n", f, err)
+				} else {
+					fmt.Fprintf(out, "%#v\n", a)
+				}
+			} else {
+				doDemangle(out, f)
+			}
+			out.WriteByte('\n')
+		}
+		if err := out.Flush(); err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			os.Exit(2)
+		}
+		return
+	}
+
+	scanner := bufio.NewScanner(bufio.NewReader(os.Stdin))
+	for scanner.Scan() {
+		line := scanner.Text()
+		start := -1
+		for i, c := range line {
+			if unicode.IsLetter(c) || unicode.IsNumber(c) || strings.ContainsRune(symbolChars, c) {
+				if start < 0 {
+					start = i
+				}
+			} else {
+				if start >= 0 {
+					doDemangle(out, line[start:i])
+				}
+				out.WriteRune(c)
+				start = -1
+			}
+		}
+		if start >= 0 {
+			doDemangle(out, line[start:])
+			start = -1
+		}
+		out.WriteByte('\n')
+		if err := out.Flush(); err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			os.Exit(2)
+		}
+	}
+}
+
+// Demangle a string just as the GNU c++filt program does.
+func doDemangle(out *bufio.Writer, name string) {
+	skip := 0
+	if name[0] == '.' || name[0] == '$' {
+		skip++
+	}
+	if *stripUnderscore && name[skip] == '_' {
+		skip++
+	}
+	result := demangle.Filter(name[skip:], options()...)
+	if result == name[skip:] {
+		out.WriteString(name)
+	} else {
+		if name[0] == '.' {
+			out.WriteByte('.')
+		}
+		out.WriteString(result)
+	}
+}
+
+// options returns the demangling options to use based on the command
+// line flags.
+func options() []demangle.Option {
+	var options []demangle.Option
+	if *noParams {
+		options = append(options, demangle.NoParams)
+	}
+	if !*noVerbose {
+		options = append(options, demangle.Verbose)
+	}
+	return options
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle.go
new file mode 100644
index 0000000..c467440
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle.go
@@ -0,0 +1,2501 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package demangle defines functions that demangle GCC/LLVM C++ symbol names.
+// This package recognizes names that were mangled according to the C++ ABI
+// defined at http://codesourcery.com/cxx-abi/.
+package demangle
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+)
+
+// ErrNotMangledName is returned by CheckedDemangle if the string does
+// not appear to be a C++ symbol name.
+var ErrNotMangledName = errors.New("not a C++ mangled name")
+
+// Option is the type of demangler options.
+type Option int
+
+const (
+	// The NoParams option disables demangling of function parameters.
+	NoParams Option = iota
+
+	// The NoTemplateParams option disables demangling of template parameters.
+	NoTemplateParams
+
+	// The NoClones option disables inclusion of clone suffixes.
+	// NoParams implies NoClones.
+	NoClones
+
+	// The Verbose option turns on more verbose demangling.
+	Verbose
+)
+
+// Filter demangles a C++ symbol name, returning the human-readable C++ name.
+// If any error occurs during demangling, the input string is returned.
+func Filter(name string, options ...Option) string {
+	ret, err := ToString(name, options...)
+	if err != nil {
+		return name
+	}
+	return ret
+}
+
+// ToString demangles a C++ symbol name, returning human-readable C++
+// name or an error.
+// If the name does not appear to be a C++ symbol name at all, the
+// error will be ErrNotMangledName.
+func ToString(name string, options ...Option) (string, error) {
+	a, err := ToAST(name, options...)
+	if err != nil {
+		return "", err
+	}
+	return ASTToString(a, options...), nil
+}
+
+// ToAST demangles a C++ symbol name into an abstract syntax tree
+// representing the symbol.
+// If the NoParams option is passed, and the name has a function type,
+// the parameter types are not demangled.
+// If the name does not appear to be a C++ symbol name at all, the
+// error will be ErrNotMangledName.
+func ToAST(name string, options ...Option) (AST, error) {
+	if strings.HasPrefix(name, "_Z") {
+		a, err := doDemangle(name[2:], options...)
+		return a, adjustErr(err, 2)
+	}
+
+	const prefix = "_GLOBAL_"
+	if strings.HasPrefix(name, prefix) {
+		// The standard demangler ignores NoParams for global
+		// constructors.  We are compatible.
+		i := 0
+		for i < len(options) {
+			if options[i] == NoParams {
+				options = append(options[:i], options[i+1:]...)
+			} else {
+				i++
+			}
+		}
+		a, err := globalCDtorName(name[len(prefix):], options...)
+		return a, adjustErr(err, len(prefix))
+	}
+
+	return nil, ErrNotMangledName
+}
+
+// globalCDtorName demangles a global constructor/destructor symbol name.
+// The parameter is the string following the "_GLOBAL_" prefix.
+func globalCDtorName(name string, options ...Option) (AST, error) {
+	if len(name) < 4 {
+		return nil, ErrNotMangledName
+	}
+	switch name[0] {
+	case '.', '_', '$':
+	default:
+		return nil, ErrNotMangledName
+	}
+
+	var ctor bool
+	switch name[1] {
+	case 'I':
+		ctor = true
+	case 'D':
+		ctor = false
+	default:
+		return nil, ErrNotMangledName
+	}
+
+	if name[2] != '_' {
+		return nil, ErrNotMangledName
+	}
+
+	if !strings.HasPrefix(name[3:], "_Z") {
+		return &GlobalCDtor{Ctor: ctor, Key: &Name{Name: name}}, nil
+	} else {
+		a, err := doDemangle(name[5:], options...)
+		if err != nil {
+			return nil, adjustErr(err, 5)
+		}
+		return &GlobalCDtor{Ctor: ctor, Key: a}, nil
+	}
+}
+
+// The doDemangle function is the entry point into the demangler proper.
+func doDemangle(name string, options ...Option) (ret AST, err error) {
+	// When the demangling routines encounter an error, they panic
+	// with a value of type demangleErr.
+	defer func() {
+		if r := recover(); r != nil {
+			if de, ok := r.(demangleErr); ok {
+				ret = nil
+				err = de
+				return
+			}
+			panic(r)
+		}
+	}()
+
+	params := true
+	clones := true
+	verbose := false
+	for _, o := range options {
+		switch o {
+		case NoParams:
+			params = false
+			clones = false
+		case NoTemplateParams:
+		// This is a valid option but only affect printing of the AST.
+		case NoClones:
+			clones = false
+		case Verbose:
+			verbose = true
+		default:
+			return nil, fmt.Errorf("unrecognized demangler option %v", o)
+		}
+	}
+
+	st := &state{str: name, verbose: verbose}
+	a := st.encoding(params)
+
+	// Accept a clone suffix.
+	if clones {
+		for len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_' || isDigit(st.str[1])) {
+			a = st.cloneSuffix(a)
+		}
+	}
+
+	if clones && len(st.str) > 0 {
+		st.fail("unparsed characters at end of mangled name")
+	}
+
+	return a, nil
+}
+
+// A state holds the current state of demangling a string.
+type state struct {
+	str       string        // remainder of string to demangle
+	verbose   bool          // whether to use verbose demangling
+	off       int           // offset of str within original string
+	subs      substitutions // substitutions
+	templates []*Template   // templates being processed
+}
+
+// copy returns a copy of the current state.
+func (st *state) copy() *state {
+	n := new(state)
+	*n = *st
+	return n
+}
+
+// fail panics with demangleErr, to be caught in doDemangle.
+func (st *state) fail(err string) {
+	panic(demangleErr{err: err, off: st.off})
+}
+
+// failEarlier is like fail, but decrements the offset to indicate
+// that the point of failure occurred earlier in the string.
+func (st *state) failEarlier(err string, dec int) {
+	if st.off < dec {
+		panic("internal error")
+	}
+	panic(demangleErr{err: err, off: st.off - dec})
+}
+
+// advance advances the current string offset.
+func (st *state) advance(add int) {
+	if len(st.str) < add {
+		panic("internal error")
+	}
+	st.str = st.str[add:]
+	st.off += add
+}
+
+// checkChar requires that the next character in the string be c, and
+// advances past it.
+func (st *state) checkChar(c byte) {
+	if len(st.str) == 0 || st.str[0] != c {
+		panic("internal error")
+	}
+	st.advance(1)
+}
+
+// A demangleErr is an error at a specific offset in the mangled
+// string.
+type demangleErr struct {
+	err string
+	off int
+}
+
+// Error implements the builtin error interface for demangleErr.
+func (de demangleErr) Error() string {
+	return fmt.Sprintf("%s at %d", de.err, de.off)
+}
+
+// adjustErr adjusts the position of err, if it is a demangleErr,
+// and returns err.
+func adjustErr(err error, adj int) error {
+	if err == nil {
+		return nil
+	}
+	if de, ok := err.(demangleErr); ok {
+		de.off += adj
+		return de
+	}
+	return err
+}
+
+// encoding ::= <(function) name> <bare-function-type>
+//              <(data) name>
+//              <special-name>
+func (st *state) encoding(params bool) AST {
+	if len(st.str) < 1 {
+		st.fail("expected encoding")
+	}
+
+	if st.str[0] == 'G' || st.str[0] == 'T' {
+		return st.specialName()
+	}
+
+	a := st.name()
+	a = simplify(a)
+
+	if !params {
+		// Don't demangle the parameters.
+
+		// Strip CV-qualifiers, as they apply to the 'this'
+		// parameter, and are not output by the standard
+		// demangler without parameters.
+		if mwq, ok := a.(*MethodWithQualifiers); ok {
+			a = mwq.Method
+		}
+
+		// If this is a local name, there may be CV-qualifiers
+		// on the name that really apply to the top level, and
+		// therefore must be discarded when discarding
+		// parameters.  This can happen when parsing a class
+		// that is local to a function.
+		if q, ok := a.(*Qualified); ok && q.LocalName {
+			p := &q.Name
+			if da, ok := (*p).(*DefaultArg); ok {
+				p = &da.Arg
+			}
+			if mwq, ok := (*p).(*MethodWithQualifiers); ok {
+				*p = mwq.Method
+			}
+		}
+
+		return a
+	}
+
+	if len(st.str) == 0 || st.str[0] == 'E' {
+		// There are no parameters--this is a data symbol, not
+		// a function symbol.
+		return a
+	}
+
+	check := a
+	mwq, _ := check.(*MethodWithQualifiers)
+	if mwq != nil {
+		check = mwq.Method
+	}
+	template, _ := check.(*Template)
+	if template != nil {
+		st.templates = append(st.templates, template)
+	}
+
+	ft := st.bareFunctionType(hasReturnType(a))
+
+	if template != nil {
+		st.templates = st.templates[:len(st.templates)-1]
+	}
+
+	ft = simplify(ft)
+
+	// Any top-level qualifiers belong to the function type.
+	if mwq != nil {
+		a = mwq.Method
+		mwq.Method = ft
+		ft = mwq
+	}
+	if q, ok := a.(*Qualified); ok && q.LocalName {
+		p := &q.Name
+		if da, ok := (*p).(*DefaultArg); ok {
+			p = &da.Arg
+		}
+		if mwq, ok := (*p).(*MethodWithQualifiers); ok {
+			*p = mwq.Method
+			mwq.Method = ft
+			ft = mwq
+		}
+	}
+
+	return &Typed{Name: a, Type: ft}
+}
+
+// hasReturnType returns whether the mangled form of a will have a
+// return type.
+func hasReturnType(a AST) bool {
+	switch a := a.(type) {
+	case *Template:
+		return !isCDtorConversion(a.Name)
+	case *TypeWithQualifiers:
+		return hasReturnType(a.Base)
+	case *MethodWithQualifiers:
+		return hasReturnType(a.Method)
+	default:
+		return false
+	}
+}
+
+// isCDtorConversion returns when an AST is a constructor, a
+// destructor, or a conversion operator.
+func isCDtorConversion(a AST) bool {
+	switch a := a.(type) {
+	case *Qualified:
+		return isCDtorConversion(a.Name)
+	case *Constructor, *Destructor, *Cast:
+		return true
+	default:
+		return false
+	}
+}
+
+// <tagged-name> ::= <name> B <source-name>
+func (st *state) taggedName(a AST) AST {
+	for len(st.str) > 0 && st.str[0] == 'B' {
+		st.advance(1)
+		tag := st.sourceName()
+		a = &TaggedName{Name: a, Tag: tag}
+	}
+	return a
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <local-name>
+//
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+func (st *state) name() AST {
+	if len(st.str) < 1 {
+		st.fail("expected name")
+	}
+	switch st.str[0] {
+	case 'N':
+		return st.nestedName()
+	case 'Z':
+		return st.localName()
+	case 'U':
+		a, isCast := st.unqualifiedName()
+		if isCast {
+			st.setTemplate(a, nil)
+		}
+		return a
+	case 'S':
+		if len(st.str) < 2 {
+			st.advance(1)
+			st.fail("expected substitution index")
+		}
+		var a AST
+		isCast := false
+		subst := false
+		if st.str[1] == 't' {
+			st.advance(2)
+			a, isCast = st.unqualifiedName()
+			a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
+		} else {
+			a = st.substitution(false)
+			subst = true
+		}
+		if len(st.str) > 0 && st.str[0] == 'I' {
+			// This can only happen if we saw
+			// <unscoped-template-name> and are about to see
+			// <template-args>.  <unscoped-template-name> is a
+			// substitution candidate if it did not come from a
+			// substitution.
+			if !subst {
+				st.subs.add(a)
+			}
+			args := st.templateArgs()
+			tmpl := &Template{Name: a, Args: args}
+			if isCast {
+				st.setTemplate(a, tmpl)
+				st.clearTemplateArgs(args)
+				isCast = false
+			}
+			a = tmpl
+		}
+		if isCast {
+			st.setTemplate(a, nil)
+		}
+		return a
+
+	default:
+		a, isCast := st.unqualifiedName()
+		if len(st.str) > 0 && st.str[0] == 'I' {
+			st.subs.add(a)
+			args := st.templateArgs()
+			tmpl := &Template{Name: a, Args: args}
+			if isCast {
+				st.setTemplate(a, tmpl)
+				st.clearTemplateArgs(args)
+				isCast = false
+			}
+			a = tmpl
+		}
+		if isCast {
+			st.setTemplate(a, nil)
+		}
+		return a
+	}
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+func (st *state) nestedName() AST {
+	st.checkChar('N')
+	q := st.cvQualifiers()
+	r := st.refQualifier()
+	a := st.prefix()
+	if len(q) > 0 || r != "" {
+		a = &MethodWithQualifiers{Method: a, Qualifiers: q, RefQualifier: r}
+	}
+	if len(st.str) == 0 || st.str[0] != 'E' {
+		st.fail("expected E after nested name")
+	}
+	st.advance(1)
+	return a
+}
+
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <decltype>
+//          ::=
+//          ::= <substitution>
+//
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+//
+// <decltype> ::= Dt <expression> E
+//            ::= DT <expression> E
+func (st *state) prefix() AST {
+	var a AST
+
+	// The last name seen, for a constructor/destructor.
+	var last AST
+
+	getLast := func(a AST) AST {
+		for {
+			if t, ok := a.(*Template); ok {
+				a = t.Name
+			} else if q, ok := a.(*Qualified); ok {
+				a = q.Name
+			} else if t, ok := a.(*TaggedName); ok {
+				a = t.Name
+			} else {
+				return a
+			}
+		}
+	}
+
+	isCast := false
+	for {
+		if len(st.str) == 0 {
+			st.fail("expected prefix")
+		}
+		var next AST
+
+		c := st.str[0]
+		if isDigit(c) || isLower(c) || c == 'U' || c == 'L' {
+			un, isUnCast := st.unqualifiedName()
+			next = un
+			if isUnCast {
+				isCast = true
+			}
+		} else {
+			switch st.str[0] {
+			case 'C':
+				if len(st.str) < 2 {
+					st.fail("expected constructor type")
+				}
+				if last == nil {
+					st.fail("constructor before name is seen")
+				}
+				st.advance(2)
+				next = &Constructor{Name: getLast(last)}
+			case 'D':
+				if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
+					next = st.demangleType(false)
+				} else {
+					if len(st.str) < 2 {
+						st.fail("expected destructor type")
+					}
+					if last == nil {
+						st.fail("destructor before name is seen")
+					}
+					st.advance(2)
+					next = &Destructor{Name: getLast(last)}
+				}
+			case 'S':
+				next = st.substitution(true)
+			case 'I':
+				if a == nil {
+					st.fail("unexpected template arguments")
+				}
+				var args []AST
+				args = st.templateArgs()
+				tmpl := &Template{Name: a, Args: args}
+				if isCast {
+					st.setTemplate(a, tmpl)
+					st.clearTemplateArgs(args)
+					isCast = false
+				}
+				a = nil
+				next = tmpl
+			case 'T':
+				next = st.templateParam()
+			case 'E':
+				if a == nil {
+					st.fail("expected prefix")
+				}
+				if isCast {
+					st.setTemplate(a, nil)
+				}
+				return a
+			case 'M':
+				if a == nil {
+					st.fail("unexpected lambda initializer")
+				}
+				// This is the initializer scope for a
+				// lambda.  We don't need to record
+				// it.  The normal code will treat the
+				// variable has a type scope, which
+				// gives appropriate output.
+				st.advance(1)
+				continue
+			default:
+				st.fail("unrecognized letter in prefix")
+			}
+		}
+		last = next
+		if a == nil {
+			a = next
+		} else {
+			a = &Qualified{Scope: a, Name: next, LocalName: false}
+		}
+
+		if c != 'S' && (len(st.str) == 0 || st.str[0] != 'E') {
+			st.subs.add(a)
+		}
+	}
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name>
+//
+//  <local-source-name>	::= L <source-name> <discriminator>
+func (st *state) unqualifiedName() (r AST, isCast bool) {
+	if len(st.str) < 1 {
+		st.fail("expected unqualified name")
+	}
+	var a AST
+	isCast = false
+	c := st.str[0]
+	if isDigit(c) {
+		a = st.sourceName()
+	} else if isLower(c) {
+		a, _ = st.operatorName(false)
+		if _, ok := a.(*Cast); ok {
+			isCast = true
+		}
+		if op, ok := a.(*Operator); ok && op.Name == `operator"" ` {
+			n := st.sourceName()
+			a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
+		}
+	} else {
+		switch c {
+		case 'C', 'D':
+			st.fail("constructor/destructor not in nested name")
+		case 'L':
+			st.advance(1)
+			a = st.sourceName()
+			a = st.discriminator(a)
+		case 'U':
+			if len(st.str) < 2 {
+				st.advance(1)
+				st.fail("expected closure or unnamed type")
+			}
+			c := st.str[1]
+			switch c {
+			case 'l':
+				a = st.closureTypeName()
+			case 't':
+				a = st.unnamedTypeName()
+			default:
+				st.advance(1)
+				st.fail("expected closure or unnamed type")
+			}
+		default:
+			st.fail("expected unqualified name")
+		}
+	}
+
+	if len(st.str) > 0 && st.str[0] == 'B' {
+		a = st.taggedName(a)
+	}
+
+	return a, isCast
+}
+
+// <source-name> ::= <(positive length) number> <identifier>
+// identifier ::= <(unqualified source code identifier)>
+func (st *state) sourceName() AST {
+	val := st.number()
+	if val <= 0 {
+		st.fail("expected positive number")
+	}
+	if len(st.str) < val {
+		st.fail("not enough characters for identifier")
+	}
+	id := st.str[:val]
+	st.advance(val)
+
+	// Look for GCC encoding of anonymous namespace, and make it
+	// more friendly.
+	const anonPrefix = "_GLOBAL_"
+	if strings.HasPrefix(id, anonPrefix) && len(id) > len(anonPrefix)+2 {
+		c1 := id[len(anonPrefix)]
+		c2 := id[len(anonPrefix)+1]
+		if (c1 == '.' || c1 == '_' || c1 == '$') && c2 == 'N' {
+			id = "(anonymous namespace)"
+		}
+	}
+
+	n := &Name{Name: id}
+	return n
+}
+
+// number ::= [n] <(non-negative decimal integer)>
+func (st *state) number() int {
+	neg := false
+	if len(st.str) > 0 && st.str[0] == 'n' {
+		neg = true
+		st.advance(1)
+	}
+	if len(st.str) == 0 || !isDigit(st.str[0]) {
+		st.fail("missing number")
+	}
+	val := 0
+	for len(st.str) > 0 && isDigit(st.str[0]) {
+		// Number picked to ensure we can't overflow with 32-bit int.
+		// Any very large number here is bogus.
+		if val >= 0x80000000/10-10 {
+			st.fail("numeric overflow")
+		}
+		val = val*10 + int(st.str[0]-'0')
+		st.advance(1)
+	}
+	if neg {
+		val = -val
+	}
+	return val
+}
+
+// An operator is the demangled name, and the number of arguments it
+// takes in an expression.
+type operator struct {
+	name string
+	args int
+}
+
+// The operators map maps the mangled operator names to information
+// about them.
+var operators = map[string]operator{
+	"aN": {"&=", 2},
+	"aS": {"=", 2},
+	"aa": {"&&", 2},
+	"ad": {"&", 1},
+	"an": {"&", 2},
+	"at": {"alignof ", 1},
+	"az": {"alignof ", 1},
+	"cc": {"const_cast", 2},
+	"cl": {"()", 2},
+	"cm": {",", 2},
+	"co": {"~", 1},
+	"dV": {"/=", 2},
+	"da": {"delete[] ", 1},
+	"dc": {"dynamic_cast", 2},
+	"de": {"*", 1},
+	"dl": {"delete ", 1},
+	"ds": {".*", 2},
+	"dt": {".", 2},
+	"dv": {"/", 2},
+	"eO": {"^=", 2},
+	"eo": {"^", 2},
+	"eq": {"==", 2},
+	"fl": {"...", 2},
+	"fr": {"...", 2},
+	"fL": {"...", 3},
+	"fR": {"...", 3},
+	"ge": {">=", 2},
+	"gs": {"::", 1},
+	"gt": {">", 2},
+	"ix": {"[]", 2},
+	"lS": {"<<=", 2},
+	"le": {"<=", 2},
+	"li": {`operator"" `, 1},
+	"ls": {"<<", 2},
+	"lt": {"<", 2},
+	"mI": {"-=", 2},
+	"mL": {"*=", 2},
+	"mi": {"-", 2},
+	"ml": {"*", 2},
+	"mm": {"--", 1},
+	"na": {"new[]", 3},
+	"ne": {"!=", 2},
+	"ng": {"-", 1},
+	"nt": {"!", 1},
+	"nw": {"new", 3},
+	"oR": {"|=", 2},
+	"oo": {"||", 2},
+	"or": {"|", 2},
+	"pL": {"+=", 2},
+	"pl": {"+", 2},
+	"pm": {"->*", 2},
+	"pp": {"++", 1},
+	"ps": {"+", 1},
+	"pt": {"->", 2},
+	"qu": {"?", 3},
+	"rM": {"%=", 2},
+	"rS": {">>=", 2},
+	"rc": {"reinterpret_cast", 2},
+	"rm": {"%", 2},
+	"rs": {">>", 2},
+	"sc": {"static_cast", 2},
+	"st": {"sizeof ", 1},
+	"sz": {"sizeof ", 1},
+	"tr": {"throw", 0},
+	"tw": {"throw ", 1},
+}
+
+// operator_name ::= many different two character encodings.
+//               ::= cv <type>
+//               ::= v <digit> <source-name>
+//
+// We need to know whether we are in an expression because it affects
+// how we handle template parameters in the type of a cast operator.
+func (st *state) operatorName(inExpression bool) (AST, int) {
+	if len(st.str) < 2 {
+		st.fail("missing operator code")
+	}
+	code := st.str[:2]
+	st.advance(2)
+	if code[0] == 'v' && isDigit(code[1]) {
+		name := st.sourceName()
+		return &Operator{Name: name.(*Name).Name}, int(code[1] - '0')
+	} else if code == "cv" {
+		// Push a nil on templates to indicate that template
+		// parameters will have their template filled in
+		// later.
+		if !inExpression {
+			st.templates = append(st.templates, nil)
+		}
+
+		t := st.demangleType(!inExpression)
+
+		if !inExpression {
+			st.templates = st.templates[:len(st.templates)-1]
+		}
+
+		return &Cast{To: t}, 1
+	} else if op, ok := operators[code]; ok {
+		return &Operator{Name: op.name}, op.args
+	} else {
+		st.failEarlier("unrecognized operator code", 2)
+		panic("not reached")
+	}
+}
+
+// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+//              ::= Z <(function) encoding> E s [<discriminator>]
+//              ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
+func (st *state) localName() AST {
+	st.checkChar('Z')
+	fn := st.encoding(true)
+	if len(st.str) == 0 || st.str[0] != 'E' {
+		st.fail("expected E after local name")
+	}
+	st.advance(1)
+	if len(st.str) > 0 && st.str[0] == 's' {
+		st.advance(1)
+		var n AST = &Name{Name: "string literal"}
+		n = st.discriminator(n)
+		return &Qualified{Scope: fn, Name: n, LocalName: true}
+	} else {
+		num := -1
+		if len(st.str) > 0 && st.str[0] == 'd' {
+			// Default argument scope.
+			st.advance(1)
+			num = st.compactNumber()
+		}
+		var n AST = st.name()
+		n = st.discriminator(n)
+		if num >= 0 {
+			n = &DefaultArg{Num: num, Arg: n}
+		}
+		return &Qualified{Scope: fn, Name: n, LocalName: true}
+	}
+}
+
+// Parse a Java resource special-name.
+func (st *state) javaResource() AST {
+	off := st.off
+	ln := st.number()
+	if ln <= 1 {
+		st.failEarlier("java resource length less than 1", st.off-off)
+	}
+	if len(st.str) == 0 || st.str[0] != '_' {
+		st.fail("expected _ after number")
+	}
+	st.advance(1)
+	ln--
+	if len(st.str) < ln {
+		st.fail("not enough characters for java resource length")
+	}
+	str := st.str[:ln]
+	final := ""
+	st.advance(ln)
+	for i := 0; i < len(str); i++ {
+		if str[i] != '$' {
+			final += string(str[i])
+		} else {
+			if len(str) <= i+1 {
+				st.failEarlier("java resource escape at end of string", 1)
+			}
+			i++
+			r, ok := map[byte]string{
+				'S': "/",
+				'_': ".",
+				'$': "$",
+			}[str[i]]
+			if !ok {
+				st.failEarlier("unrecognized java resource escape", ln-i-1)
+			}
+			final += r
+		}
+	}
+	return &Special{Prefix: "java resource ", Val: &Name{Name: final}}
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+// Also g++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Gr <resource name>
+//                ::= GTt <encoding>
+//                ::= GTn <encoding>
+func (st *state) specialName() AST {
+	if st.str[0] == 'T' {
+		st.advance(1)
+		if len(st.str) == 0 {
+			st.fail("expected special name code")
+		}
+		c := st.str[0]
+		st.advance(1)
+		switch c {
+		case 'V':
+			t := st.demangleType(false)
+			return &Special{Prefix: "vtable for ", Val: t}
+		case 'T':
+			t := st.demangleType(false)
+			return &Special{Prefix: "VTT for ", Val: t}
+		case 'I':
+			t := st.demangleType(false)
+			return &Special{Prefix: "typeinfo for ", Val: t}
+		case 'S':
+			t := st.demangleType(false)
+			return &Special{Prefix: "typeinfo name for ", Val: t}
+		case 'h':
+			st.callOffset('h')
+			v := st.encoding(true)
+			return &Special{Prefix: "non-virtual thunk to ", Val: v}
+		case 'v':
+			st.callOffset('v')
+			v := st.encoding(true)
+			return &Special{Prefix: "virtual thunk to ", Val: v}
+		case 'c':
+			st.callOffset(0)
+			st.callOffset(0)
+			v := st.encoding(true)
+			return &Special{Prefix: "covariant return thunk to ", Val: v}
+		case 'C':
+			derived := st.demangleType(false)
+			off := st.off
+			offset := st.number()
+			if offset < 0 {
+				st.failEarlier("expected positive offset", st.off-off)
+			}
+			if len(st.str) == 0 || st.str[0] != '_' {
+				st.fail("expected _ after number")
+			}
+			st.advance(1)
+			base := st.demangleType(false)
+			return &Special2{Prefix: "construction vtable for ", Val1: base, Middle: "-in-", Val2: derived}
+		case 'F':
+			t := st.demangleType(false)
+			return &Special{Prefix: "typeinfo fn for ", Val: t}
+		case 'J':
+			t := st.demangleType(false)
+			return &Special{Prefix: "java Class for ", Val: t}
+		case 'H':
+			n := st.name()
+			return &Special{Prefix: "TLS init function for ", Val: n}
+		case 'W':
+			n := st.name()
+			return &Special{Prefix: "TLS wrapper function for ", Val: n}
+		default:
+			st.fail("unrecognized special T name code")
+			panic("not reached")
+		}
+	} else {
+		st.checkChar('G')
+		if len(st.str) == 0 {
+			st.fail("expected special name code")
+		}
+		c := st.str[0]
+		st.advance(1)
+		switch c {
+		case 'V':
+			n := st.name()
+			return &Special{Prefix: "guard variable for ", Val: n}
+		case 'R':
+			n := st.name()
+			i := st.number()
+			return &Special{Prefix: fmt.Sprintf("reference temporary #%d for ", i), Val: n}
+		case 'A':
+			v := st.encoding(true)
+			return &Special{Prefix: "hidden alias for ", Val: v}
+		case 'T':
+			if len(st.str) == 0 {
+				st.fail("expected special GT name code")
+			}
+			c := st.str[0]
+			st.advance(1)
+			v := st.encoding(true)
+			switch c {
+			case 'n':
+				return &Special{Prefix: "non-transaction clone for ", Val: v}
+			default:
+				// The proposal is that different
+				// letters stand for different types
+				// of transactional cloning.  Treat
+				// them all the same for now.
+				fallthrough
+			case 't':
+				return &Special{Prefix: "transaction clone for ", Val: v}
+			}
+		case 'r':
+			return st.javaResource()
+		default:
+			st.fail("unrecognized special G name code")
+			panic("not reached")
+		}
+	}
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+//
+// <nv-offset> ::= <(offset) number>
+//
+// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+//
+// The c parameter, if not 0, is a character we just read which is the
+// start of the <call-offset>.
+//
+// We don't display the offset information anywhere.
+func (st *state) callOffset(c byte) {
+	if c == 0 {
+		if len(st.str) == 0 {
+			st.fail("missing call offset")
+		}
+		c = st.str[0]
+		st.advance(1)
+	}
+	switch c {
+	case 'h':
+		st.number()
+	case 'v':
+		st.number()
+		if len(st.str) == 0 || st.str[0] != '_' {
+			st.fail("expected _ after number")
+		}
+		st.advance(1)
+		st.number()
+	default:
+		st.failEarlier("unrecognized call offset code", 1)
+	}
+	if len(st.str) == 0 || st.str[0] != '_' {
+		st.fail("expected _ after call offset")
+	}
+	st.advance(1)
+}
+
+// builtinTypes maps the type letter to the type name.
+var builtinTypes = map[byte]string{
+	'a': "signed char",
+	'b': "bool",
+	'c': "char",
+	'd': "double",
+	'e': "long double",
+	'f': "float",
+	'g': "__float128",
+	'h': "unsigned char",
+	'i': "int",
+	'j': "unsigned int",
+	'l': "long",
+	'm': "unsigned long",
+	'n': "__int128",
+	'o': "unsigned __int128",
+	's': "short",
+	't': "unsigned short",
+	'v': "void",
+	'w': "wchar_t",
+	'x': "long long",
+	'y': "unsigned long long",
+	'z': "...",
+}
+
+// <type> ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-param>
+//        ::= <template-template-param> <template-args>
+//        ::= <substitution>
+//        ::= <CV-qualifiers> <type>
+//        ::= P <type>
+//        ::= R <type>
+//        ::= O <type> (C++0x)
+//        ::= C <type>
+//        ::= G <type>
+//        ::= U <source-name> <type>
+//
+// <builtin-type> ::= various one letter codes
+//                ::= u <source-name>
+func (st *state) demangleType(isCast bool) AST {
+	if len(st.str) == 0 {
+		st.fail("expected type")
+	}
+
+	addSubst := true
+
+	q := st.cvQualifiers()
+	if len(q) > 0 {
+		if len(st.str) == 0 {
+			st.fail("expected type")
+		}
+
+		// CV-qualifiers before a function type apply to
+		// 'this', so avoid adding the unqualified function
+		// type to the substitution list.
+		if st.str[0] == 'F' {
+			addSubst = false
+		}
+	}
+
+	var ret AST
+
+	// Use correct substitution for a template parameter.
+	var sub AST
+
+	if btype, ok := builtinTypes[st.str[0]]; ok {
+		ret = &BuiltinType{Name: btype}
+		st.advance(1)
+		if len(q) > 0 {
+			ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
+			st.subs.add(ret)
+		}
+		return ret
+	}
+	c := st.str[0]
+	switch c {
+	case 'u':
+		st.advance(1)
+		ret = st.sourceName()
+	case 'F':
+		ret = st.functionType()
+	case 'N', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+		ret = st.name()
+	case 'A':
+		ret = st.arrayType(isCast)
+	case 'M':
+		ret = st.pointerToMemberType(isCast)
+	case 'T':
+		ret = st.templateParam()
+		if len(st.str) > 0 && st.str[0] == 'I' {
+			// See the function comment to explain this.
+			if !isCast {
+				st.subs.add(ret)
+				args := st.templateArgs()
+				ret = &Template{Name: ret, Args: args}
+			} else {
+				ret = st.demangleCastTemplateArgs(ret, true)
+			}
+		}
+	case 'S':
+		// If this is a special substitution, then it
+		// is the start of <class-enum-type>.
+		var c2 byte
+		if len(st.str) > 1 {
+			c2 = st.str[1]
+		}
+		if isDigit(c2) || c2 == '_' || isUpper(c2) {
+			ret = st.substitution(false)
+			if len(st.str) == 0 || st.str[0] != 'I' {
+				addSubst = false
+			} else {
+				// See the function comment to explain this.
+				if _, ok := ret.(*TemplateParam); !ok || !isCast {
+					args := st.templateArgs()
+					ret = &Template{Name: ret, Args: args}
+				} else {
+					next := st.demangleCastTemplateArgs(ret, false)
+					if next == ret {
+						addSubst = false
+					}
+					ret = next
+				}
+			}
+		} else {
+			ret = st.name()
+			// This substitution is not itself a
+			// substitution candidate, unless template
+			// arguments were added.
+			if ret == subAST[c2] || ret == verboseAST[c2] {
+				addSubst = false
+			}
+		}
+	case 'O', 'P', 'R', 'C', 'G':
+		st.advance(1)
+		t := st.demangleType(isCast)
+		switch c {
+		case 'O':
+			ret = &RvalueReferenceType{Base: t}
+		case 'P':
+			ret = &PointerType{Base: t}
+		case 'R':
+			ret = &ReferenceType{Base: t}
+		case 'C':
+			ret = &ComplexType{Base: t}
+		case 'G':
+			ret = &ImaginaryType{Base: t}
+		}
+	case 'U':
+		if len(st.str) < 2 {
+			st.fail("expected source name or unnamed type")
+		}
+		switch st.str[1] {
+		case 'l':
+			ret = st.closureTypeName()
+			addSubst = false
+		case 't':
+			ret = st.unnamedTypeName()
+			addSubst = false
+		default:
+			st.advance(1)
+			n := st.sourceName()
+			if len(st.str) > 0 && st.str[0] == 'I' {
+				args := st.templateArgs()
+				n = &Template{Name: n, Args: args}
+			}
+			t := st.demangleType(isCast)
+			ret = &VendorQualifier{Qualifier: n, Type: t}
+		}
+	case 'D':
+		st.advance(1)
+		if len(st.str) == 0 {
+			st.fail("expected D code for type")
+		}
+		addSubst = false
+		c2 := st.str[0]
+		st.advance(1)
+		switch c2 {
+		case 'T', 't':
+			// decltype(expression)
+			ret = st.expression()
+			if len(st.str) == 0 || st.str[0] != 'E' {
+				st.fail("expected E after expression in type")
+			}
+			st.advance(1)
+			ret = &Decltype{Expr: ret}
+			addSubst = true
+
+		case 'p':
+			t := st.demangleType(isCast)
+			pack := st.findArgumentPack(t)
+			ret = &PackExpansion{Base: t, Pack: pack}
+			addSubst = true
+
+		case 'a':
+			ret = &Name{Name: "auto"}
+
+		case 'f':
+			ret = &BuiltinType{Name: "decimal32"}
+		case 'd':
+			ret = &BuiltinType{Name: "decimal64"}
+		case 'e':
+			ret = &BuiltinType{Name: "decimal128"}
+		case 'h':
+			ret = &BuiltinType{Name: "half"}
+		case 's':
+			ret = &BuiltinType{Name: "char16_t"}
+		case 'i':
+			ret = &BuiltinType{Name: "char32_t"}
+		case 'n':
+			ret = &BuiltinType{Name: "decltype(nullptr)"}
+
+		case 'F':
+			accum := false
+			if len(st.str) > 0 && isDigit(st.str[0]) {
+				accum = true
+				// We don't care about the bits.
+				_ = st.number()
+			}
+			base := st.demangleType(isCast)
+			if len(st.str) > 0 && isDigit(st.str[0]) {
+				// We don't care about the bits.
+				st.number()
+			}
+			sat := false
+			if len(st.str) > 0 {
+				if st.str[0] == 's' {
+					sat = true
+				}
+				st.advance(1)
+			}
+			ret = &FixedType{Base: base, Accum: accum, Sat: sat}
+
+		case 'v':
+			ret = st.vectorType(isCast)
+			addSubst = true
+
+		default:
+			st.fail("unrecognized D code in type")
+		}
+
+	default:
+		st.fail("unrecognized type code")
+	}
+
+	if addSubst {
+		if sub != nil {
+			st.subs.add(sub)
+		} else {
+			st.subs.add(ret)
+		}
+	}
+
+	if len(q) > 0 {
+		if _, ok := ret.(*FunctionType); ok {
+			ret = &MethodWithQualifiers{Method: ret, Qualifiers: q, RefQualifier: ""}
+		} else if mwq, ok := ret.(*MethodWithQualifiers); ok {
+			// Merge adjacent qualifiers.  This case
+			// happens with a function with a trailing
+			// ref-qualifier.
+			mwq.Qualifiers = mergeQualifiers(q, mwq.Qualifiers)
+		} else {
+			// Merge adjacent qualifiers.  This case
+			// happens with multi-dimensional array types.
+			if qsub, ok := ret.(*TypeWithQualifiers); ok {
+				q = mergeQualifiers(q, qsub.Qualifiers)
+				ret = qsub.Base
+			}
+			ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
+		}
+		st.subs.add(ret)
+	}
+
+	return ret
+}
+
+// demangleCastTemplateArgs is for a rather hideous parse.  When we
+// see a template-param followed by a template-args, we need to decide
+// whether we have a template-param or a template-template-param.
+// Normally it is template-template-param, meaning that we pick up the
+// template arguments here.  But, if we are parsing the type for a
+// cast operator, then the only way this can be template-template-param
+// is if there is another set of template-args immediately after this
+// set.  That would look like this:
+//
+// <nested-name>
+// -> <template-prefix> <template-args>
+// -> <prefix> <template-unqualified-name> <template-args>
+// -> <unqualified-name> <template-unqualified-name> <template-args>
+// -> <source-name> <template-unqualified-name> <template-args>
+// -> <source-name> <operator-name> <template-args>
+// -> <source-name> cv <type> <template-args>
+// -> <source-name> cv <template-template-param> <template-args> <template-args>
+//
+// Otherwise, we have this derivation:
+//
+// <nested-name>
+// -> <template-prefix> <template-args>
+// -> <prefix> <template-unqualified-name> <template-args>
+// -> <unqualified-name> <template-unqualified-name> <template-args>
+// -> <source-name> <template-unqualified-name> <template-args>
+// -> <source-name> <operator-name> <template-args>
+// -> <source-name> cv <type> <template-args>
+// -> <source-name> cv <template-param> <template-args>
+//
+// in which the template-args are actually part of the prefix.  For
+// the special case where this arises, demangleType is called with
+// isCast as true.  This function is then responsible for checking
+// whether we see <template-param> <template-args> but there is not
+// another following <template-args>.  In that case, we reset the
+// parse and just return the <template-param>.
+func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST {
+	save := st.copy()
+
+	var args []AST
+	failed := false
+	func() {
+		defer func() {
+			if r := recover(); r != nil {
+				if _, ok := r.(demangleErr); ok {
+					failed = true
+				} else {
+					panic(r)
+				}
+			}
+		}()
+
+		args = st.templateArgs()
+	}()
+
+	if !failed && len(st.str) > 0 && st.str[0] == 'I' {
+		if addSubst {
+			st.subs.add(tp)
+		}
+		return &Template{Name: tp, Args: args}
+	}
+	// Reset back to before we started reading the template arguments.
+	// They will be read again by st.prefix.
+	*st = *save
+	return tp
+}
+
+// mergeQualifiers merges two qualifer lists into one.
+func mergeQualifiers(q1, q2 Qualifiers) Qualifiers {
+	m := make(map[string]bool)
+	for _, qual := range q1 {
+		m[qual] = true
+	}
+	for _, qual := range q2 {
+		if !m[qual] {
+			q1 = append(q1, qual)
+			m[qual] = true
+		}
+	}
+	return q1
+}
+
+// qualifiers maps from the character used in the mangled name to the
+// string to print.
+var qualifiers = map[byte]string{
+	'r': "restrict",
+	'V': "volatile",
+	'K': "const",
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+func (st *state) cvQualifiers() Qualifiers {
+	var q Qualifiers
+	for len(st.str) > 0 {
+		if qv, ok := qualifiers[st.str[0]]; ok {
+			q = append([]string{qv}, q...)
+			st.advance(1)
+		} else if len(st.str) > 1 && st.str[:2] == "Dx" {
+			q = append([]string{"transaction_safe"}, q...)
+			st.advance(2)
+		} else {
+			break
+		}
+	}
+	return q
+}
+
+// <ref-qualifier> ::= R
+//                 ::= O
+func (st *state) refQualifier() string {
+	if len(st.str) > 0 {
+		switch st.str[0] {
+		case 'R':
+			st.advance(1)
+			return "&"
+		case 'O':
+			st.advance(1)
+			return "&&"
+		}
+	}
+	return ""
+}
+
+// <type>+
+func (st *state) parmlist() []AST {
+	var ret []AST
+	for {
+		if len(st.str) < 1 {
+			break
+		}
+		if st.str[0] == 'E' || st.str[0] == '.' {
+			break
+		}
+		if (st.str[0] == 'R' || st.str[0] == 'O') && len(st.str) > 1 && st.str[1] == 'E' {
+			// This is a function ref-qualifier.
+			break
+		}
+		ptype := st.demangleType(false)
+		ret = append(ret, ptype)
+	}
+
+	// There should always be at least one type.  A function that
+	// takes no arguments will have a single parameter type
+	// "void".
+	if len(ret) == 0 {
+		st.fail("expected at least one type in type list")
+	}
+
+	// Omit a single parameter type void.
+	if len(ret) == 1 {
+		if bt, ok := ret[0].(*BuiltinType); ok && bt.Name == "void" {
+			ret = nil
+		}
+	}
+
+	return ret
+}
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+func (st *state) functionType() AST {
+	st.checkChar('F')
+	if len(st.str) > 0 && st.str[0] == 'Y' {
+		// Function has C linkage.  We don't print this.
+		st.advance(1)
+	}
+	ret := st.bareFunctionType(true)
+	r := st.refQualifier()
+	if r != "" {
+		ret = &MethodWithQualifiers{Method: ret, Qualifiers: nil, RefQualifier: r}
+	}
+	if len(st.str) == 0 || st.str[0] != 'E' {
+		st.fail("expected E after function type")
+	}
+	st.advance(1)
+	return ret
+}
+
+// <bare-function-type> ::= [J]<type>+
+func (st *state) bareFunctionType(hasReturnType bool) AST {
+	if len(st.str) > 0 && st.str[0] == 'J' {
+		hasReturnType = true
+		st.advance(1)
+	}
+	var returnType AST
+	if hasReturnType {
+		returnType = st.demangleType(false)
+	}
+	types := st.parmlist()
+	return &FunctionType{Return: returnType, Args: types}
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+func (st *state) arrayType(isCast bool) AST {
+	st.checkChar('A')
+
+	if len(st.str) == 0 {
+		st.fail("missing array dimension")
+	}
+
+	var dim AST
+	if st.str[0] == '_' {
+		dim = &Name{Name: ""}
+	} else if isDigit(st.str[0]) {
+		i := 1
+		for len(st.str) > i && isDigit(st.str[i]) {
+			i++
+		}
+		dim = &Name{Name: st.str[:i]}
+		st.advance(i)
+	} else {
+		dim = st.expression()
+	}
+
+	if len(st.str) == 0 || st.str[0] != '_' {
+		st.fail("expected _ after dimension")
+	}
+	st.advance(1)
+
+	t := st.demangleType(isCast)
+
+	arr := &ArrayType{Dimension: dim, Element: t}
+
+	// Qualifiers on the element of an array type go on the whole
+	// array type.
+	if q, ok := arr.Element.(*TypeWithQualifiers); ok {
+		return &TypeWithQualifiers{Base: &ArrayType{Dimension: dim, Element: q.Base}, Qualifiers: q.Qualifiers}
+	}
+
+	return arr
+}
+
+// <vector-type> ::= Dv <number> _ <type>
+//               ::= Dv _ <expression> _ <type>
+func (st *state) vectorType(isCast bool) AST {
+	if len(st.str) == 0 {
+		st.fail("expected vector dimension")
+	}
+
+	var dim AST
+	if st.str[0] == '_' {
+		st.advance(1)
+		dim = st.expression()
+	} else {
+		num := st.number()
+		dim = &Name{Name: fmt.Sprintf("%d", num)}
+	}
+
+	if len(st.str) == 0 || st.str[0] != '_' {
+		st.fail("expected _ after vector dimension")
+	}
+	st.advance(1)
+
+	t := st.demangleType(isCast)
+
+	return &VectorType{Dimension: dim, Base: t}
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+func (st *state) pointerToMemberType(isCast bool) AST {
+	st.checkChar('M')
+	cl := st.demangleType(false)
+
+	// The ABI says, "The type of a non-static member function is
+	// considered to be different, for the purposes of
+	// substitution, from the type of a namespace-scope or static
+	// member function whose type appears similar. The types of
+	// two non-static member functions are considered to be
+	// different, for the purposes of substitution, if the
+	// functions are members of different classes. In other words,
+	// for the purposes of substitution, the class of which the
+	// function is a member is considered part of the type of
+	// function."
+	//
+	// For a pointer to member function, this call to demangleType
+	// will end up adding a (possibly qualified) non-member
+	// function type to the substitution table, which is not
+	// correct; however, the member function type will never be
+	// used in a substitution, so putting the wrong type in the
+	// substitution table is harmless.
+	mem := st.demangleType(isCast)
+	return &PtrMem{Class: cl, Member: mem}
+}
+
+// <non-negative number> _ */
+func (st *state) compactNumber() int {
+	if len(st.str) == 0 {
+		st.fail("missing index")
+	}
+	if st.str[0] == '_' {
+		st.advance(1)
+		return 0
+	} else if st.str[0] == 'n' {
+		st.fail("unexpected negative number")
+	}
+	n := st.number()
+	if len(st.str) == 0 || st.str[0] != '_' {
+		st.fail("missing underscore after number")
+	}
+	st.advance(1)
+	return n + 1
+}
+
+// <template-param> ::= T_
+//                  ::= T <(parameter-2 non-negative) number> _
+//
+// When a template parameter is a substitution candidate, any
+// reference to that substitution refers to the template parameter
+// with the same index in the currently active template, not to
+// whatever the template parameter would be expanded to here.  We sort
+// this out in substitution and simplify.
+func (st *state) templateParam() AST {
+	if len(st.templates) == 0 {
+		st.fail("template parameter not in scope of template")
+	}
+	off := st.off
+
+	st.checkChar('T')
+	n := st.compactNumber()
+
+	template := st.templates[len(st.templates)-1]
+
+	if template == nil {
+		// We are parsing a cast operator.  If the cast is
+		// itself a template, then this is a forward
+		// reference.  Fill it in later.
+		return &TemplateParam{Index: n, Template: nil}
+	}
+
+	if n >= len(template.Args) {
+		st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
+	}
+
+	return &TemplateParam{Index: n, Template: template}
+}
+
+// setTemplate sets the Template field of any TemplateParam's in a.
+// This handles the forward referencing template parameters found in
+// cast operators.
+func (st *state) setTemplate(a AST, tmpl *Template) {
+	var seen []AST
+	a.Traverse(func(a AST) bool {
+		switch a := a.(type) {
+		case *TemplateParam:
+			if a.Template != nil {
+				if tmpl != nil {
+					st.fail("duplicate template parameters")
+				}
+				return false
+			}
+			if tmpl == nil {
+				st.fail("cast template parameter not in scope of template")
+			}
+			if a.Index >= len(tmpl.Args) {
+				st.fail(fmt.Sprintf("cast template index out of range (%d >= %d)", a.Index, len(tmpl.Args)))
+			}
+			a.Template = tmpl
+			return false
+		default:
+			for _, v := range seen {
+				if v == a {
+					return false
+				}
+			}
+			seen = append(seen, a)
+			return true
+		}
+	})
+}
+
+// clearTemplateArgs gives an error for any unset Template field in
+// args.  This handles erroneous cases where a cast operator with a
+// forward referenced template is in the scope of another cast
+// operator.
+func (st *state) clearTemplateArgs(args []AST) {
+	for _, a := range args {
+		st.setTemplate(a, nil)
+	}
+}
+
+// <template-args> ::= I <template-arg>+ E
+func (st *state) templateArgs() []AST {
+	if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') {
+		panic("internal error")
+	}
+	st.advance(1)
+
+	var ret []AST
+	for len(st.str) == 0 || st.str[0] != 'E' {
+		arg := st.templateArg()
+		ret = append(ret, arg)
+	}
+	st.advance(1)
+	return ret
+}
+
+// <template-arg> ::= <type>
+//                ::= X <expression> E
+//                ::= <expr-primary>
+func (st *state) templateArg() AST {
+	if len(st.str) == 0 {
+		st.fail("missing template argument")
+	}
+	switch st.str[0] {
+	case 'X':
+		st.advance(1)
+		expr := st.expression()
+		if len(st.str) == 0 || st.str[0] != 'E' {
+			st.fail("missing end of expression")
+		}
+		st.advance(1)
+		return expr
+
+	case 'L':
+		return st.exprPrimary()
+
+	case 'I', 'J':
+		args := st.templateArgs()
+		return &ArgumentPack{Args: args}
+
+	default:
+		return st.demangleType(false)
+	}
+}
+
+// exprList parses a sequence of expressions up to a terminating character.
+func (st *state) exprList(stop byte) AST {
+	if len(st.str) > 0 && st.str[0] == stop {
+		st.advance(1)
+		return &ExprList{Exprs: nil}
+	}
+
+	var exprs []AST
+	for {
+		e := st.expression()
+		exprs = append(exprs, e)
+		if len(st.str) > 0 && st.str[0] == stop {
+			st.advance(1)
+			break
+		}
+	}
+	return &ExprList{Exprs: exprs}
+}
+
+// <expression> ::= <(unary) operator-name> <expression>
+//              ::= <(binary) operator-name> <expression> <expression>
+//              ::= <(trinary) operator-name> <expression> <expression> <expression>
+//              ::= cl <expression>+ E
+//              ::= st <type>
+//              ::= <template-param>
+//              ::= sr <type> <unqualified-name>
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= <expr-primary>
+func (st *state) expression() AST {
+	if len(st.str) == 0 {
+		st.fail("expected expression")
+	}
+	if st.str[0] == 'L' {
+		return st.exprPrimary()
+	} else if st.str[0] == 'T' {
+		return st.templateParam()
+	} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' {
+		st.advance(2)
+		if len(st.str) == 0 {
+			st.fail("expected unresolved type")
+		}
+		switch st.str[0] {
+		case 'T', 'D', 'S':
+			t := st.demangleType(false)
+			n := st.baseUnresolvedName()
+			n = &Qualified{Scope: t, Name: n, LocalName: false}
+			if len(st.str) > 0 && st.str[0] == 'I' {
+				args := st.templateArgs()
+				n = &Template{Name: n, Args: args}
+			}
+			return n
+		default:
+			var s AST
+			if st.str[0] == 'N' {
+				st.advance(1)
+				s = st.demangleType(false)
+			}
+			for len(st.str) == 0 || st.str[0] != 'E' {
+				// GCC does not seem to follow the ABI here.
+				// It can emit type/name without an 'E'.
+				if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) {
+					if q, ok := s.(*Qualified); ok {
+						a := q.Scope
+						if t, ok := a.(*Template); ok {
+							st.subs.add(t.Name)
+							st.subs.add(t)
+						} else {
+							st.subs.add(a)
+						}
+						return s
+					}
+				}
+				n := st.sourceName()
+				if len(st.str) > 0 && st.str[0] == 'I' {
+					st.subs.add(n)
+					args := st.templateArgs()
+					n = &Template{Name: n, Args: args}
+				}
+				if s == nil {
+					s = n
+				} else {
+					s = &Qualified{Scope: s, Name: n, LocalName: false}
+				}
+				st.subs.add(s)
+			}
+			if s == nil {
+				st.fail("missing scope in unresolved name")
+			}
+			st.advance(1)
+			n := st.baseUnresolvedName()
+			return &Qualified{Scope: s, Name: n, LocalName: false}
+		}
+	} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
+		st.advance(2)
+		e := st.expression()
+		pack := st.findArgumentPack(e)
+		return &PackExpansion{Base: e, Pack: pack}
+	} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'Z' {
+		st.advance(2)
+		off := st.off
+		e := st.expression()
+		ap := st.findArgumentPack(e)
+		if ap == nil {
+			st.failEarlier("missing argument pack", st.off-off)
+		}
+		return &SizeofPack{Pack: ap}
+	} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'P' {
+		st.advance(2)
+		var args []AST
+		for len(st.str) == 0 || st.str[0] != 'E' {
+			arg := st.templateArg()
+			args = append(args, arg)
+		}
+		st.advance(1)
+		return &SizeofArgs{Args: args}
+	} else if st.str[0] == 'f' && len(st.str) > 1 && st.str[1] == 'p' {
+		st.advance(2)
+		if len(st.str) > 0 && st.str[0] == 'T' {
+			st.advance(1)
+			return &FunctionParam{Index: 0}
+		} else {
+			index := st.compactNumber()
+			return &FunctionParam{Index: index + 1}
+		}
+	} else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') {
+		if st.str[0] == 'o' {
+			// Skip operator function ID.
+			st.advance(2)
+		}
+		n, _ := st.unqualifiedName()
+		if len(st.str) > 0 && st.str[0] == 'I' {
+			args := st.templateArgs()
+			n = &Template{Name: n, Args: args}
+		}
+		return n
+	} else if (st.str[0] == 'i' || st.str[0] == 't') && len(st.str) > 1 && st.str[1] == 'l' {
+		// Brace-enclosed initializer list.
+		c := st.str[0]
+		st.advance(2)
+		var t AST
+		if c == 't' {
+			t = st.demangleType(false)
+		}
+		exprs := st.exprList('E')
+		return &InitializerList{Type: t, Exprs: exprs}
+	} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 't' {
+		o, _ := st.operatorName(true)
+		t := st.demangleType(false)
+		return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true}
+	} else {
+		if len(st.str) < 2 {
+			st.fail("missing operator code")
+		}
+		code := st.str[:2]
+		o, args := st.operatorName(true)
+		switch args {
+		case 0:
+			return &Nullary{Op: o}
+
+		case 1:
+			suffix := false
+			if code == "pp" || code == "mm" {
+				if len(st.str) > 0 && st.str[0] == '_' {
+					st.advance(1)
+				} else {
+					suffix = true
+				}
+			}
+			var operand AST
+			if _, ok := o.(*Cast); ok && len(st.str) > 0 && st.str[0] == '_' {
+				st.advance(1)
+				operand = st.exprList('E')
+			} else {
+				operand = st.expression()
+			}
+			return &Unary{Op: o, Expr: operand, Suffix: suffix, SizeofType: false}
+
+		case 2:
+			var left, right AST
+			if code == "sc" || code == "dc" || code == "cc" || code == "rc" {
+				left = st.demangleType(false)
+			} else if code[0] == 'f' {
+				left, _ = st.operatorName(true)
+				right = st.expression()
+				return &Fold{Left: code[1] == 'l', Op: left, Arg1: right, Arg2: nil}
+			} else {
+				left = st.expression()
+			}
+			if code == "cl" {
+				right = st.exprList('E')
+			} else if code == "dt" || code == "pt" {
+				right, _ = st.unqualifiedName()
+				if len(st.str) > 0 && st.str[0] == 'I' {
+					args := st.templateArgs()
+					right = &Template{Name: right, Args: args}
+				}
+			} else {
+				right = st.expression()
+			}
+			return &Binary{Op: o, Left: left, Right: right}
+
+		case 3:
+			if code[0] == 'n' {
+				if code[1] != 'w' && code[1] != 'a' {
+					panic("internal error")
+				}
+				place := st.exprList('_')
+				if place.(*ExprList).Exprs == nil {
+					place = nil
+				}
+				t := st.demangleType(false)
+				var ini AST
+				if len(st.str) > 0 && st.str[0] == 'E' {
+					st.advance(1)
+				} else if len(st.str) > 1 && st.str[0] == 'p' && st.str[1] == 'i' {
+					// Parenthesized initializer.
+					st.advance(2)
+					ini = st.exprList('E')
+				} else if len(st.str) > 1 && st.str[0] == 'i' && st.str[1] == 'l' {
+					// Initializer list.
+					ini = st.expression()
+				} else {
+					st.fail("unrecognized new initializer")
+				}
+				return &New{Op: o, Place: place, Type: t, Init: ini}
+			} else if code[0] == 'f' {
+				first, _ := st.operatorName(true)
+				second := st.expression()
+				third := st.expression()
+				return &Fold{Left: code[1] == 'L', Op: first, Arg1: second, Arg2: third}
+			} else {
+				first := st.expression()
+				second := st.expression()
+				third := st.expression()
+				return &Trinary{Op: o, First: first, Second: second, Third: third}
+			}
+
+		default:
+			st.fail(fmt.Sprintf("unsupported number of operator arguments: %d", args))
+			panic("not reached")
+		}
+	}
+}
+
+// <base-unresolved-name> ::= <simple-id>
+//                        ::= on <operator-name>
+//                        ::= on <operator-name> <template-args>
+//                        ::= dn <destructor-name>
+//
+//<simple-id> ::= <source-name> [ <template-args> ]
+func (st *state) baseUnresolvedName() AST {
+	var n AST
+	if len(st.str) >= 2 && st.str[:2] == "on" {
+		st.advance(2)
+		n, _ = st.operatorName(true)
+	} else if len(st.str) >= 2 && st.str[:2] == "dn" {
+		st.advance(2)
+		if len(st.str) > 0 && isDigit(st.str[0]) {
+			n = st.sourceName()
+		} else {
+			n = st.demangleType(false)
+		}
+		n = &Destructor{Name: n}
+	} else if len(st.str) > 0 && isDigit(st.str[0]) {
+		n = st.sourceName()
+	} else {
+		// GCC seems to not follow the ABI here: it can have
+		// an operator name without on.
+		// See https://gcc.gnu.org/PR70182.
+		n, _ = st.operatorName(true)
+	}
+	if len(st.str) > 0 && st.str[0] == 'I' {
+		args := st.templateArgs()
+		n = &Template{Name: n, Args: args}
+	}
+	return n
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+func (st *state) exprPrimary() AST {
+	st.checkChar('L')
+	if len(st.str) == 0 {
+		st.fail("expected primary expression")
+
+	}
+
+	// Check for 'Z' here because g++ incorrectly omitted the
+	// underscore until -fabi-version=3.
+	var ret AST
+	if st.str[0] == '_' || st.str[0] == 'Z' {
+		if st.str[0] == '_' {
+			st.advance(1)
+		}
+		if len(st.str) == 0 || st.str[0] != 'Z' {
+			st.fail("expected mangled name")
+		}
+		st.advance(1)
+		ret = st.encoding(true)
+	} else {
+		t := st.demangleType(false)
+
+		neg := false
+		if len(st.str) > 0 && st.str[0] == 'n' {
+			neg = true
+			st.advance(1)
+		}
+		i := 0
+		for len(st.str) > i && st.str[i] != 'E' {
+			i++
+		}
+		val := st.str[:i]
+		st.advance(i)
+		ret = &Literal{Type: t, Val: val, Neg: neg}
+	}
+	if len(st.str) == 0 || st.str[0] != 'E' {
+		st.fail("expected E after literal")
+	}
+	st.advance(1)
+	return ret
+}
+
+// <discriminator> ::= _ <(non-negative) number>
+func (st *state) discriminator(a AST) AST {
+	if len(st.str) == 0 || st.str[0] != '_' {
+		return a
+	}
+	off := st.off
+	st.advance(1)
+	d := st.number()
+	if d < 0 {
+		st.failEarlier("invalid negative discriminator", st.off-off)
+	}
+	// We don't currently print out the discriminator, so we don't
+	// save it.
+	return a
+}
+
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+func (st *state) closureTypeName() AST {
+	st.checkChar('U')
+	st.checkChar('l')
+	types := st.parmlist()
+	if len(st.str) == 0 || st.str[0] != 'E' {
+		st.fail("expected E after closure type name")
+	}
+	st.advance(1)
+	num := st.compactNumber()
+	ret := &Closure{Types: types, Num: num}
+	st.subs.add(ret)
+	return ret
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+func (st *state) unnamedTypeName() AST {
+	st.checkChar('U')
+	st.checkChar('t')
+	num := st.compactNumber()
+	ret := &UnnamedType{Num: num}
+	st.subs.add(ret)
+	return ret
+}
+
+// Recognize a clone suffix.  These are not part of the mangling API,
+// but are added by GCC when cloning functions.
+func (st *state) cloneSuffix(a AST) AST {
+	i := 0
+	if len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_') {
+		i += 2
+		for len(st.str) > i && (isLower(st.str[i]) || st.str[i] == '_') {
+			i++
+		}
+	}
+	for len(st.str) > i+1 && st.str[i] == '.' && isDigit(st.str[i+1]) {
+		i += 2
+		for len(st.str) > i && isDigit(st.str[i]) {
+			i++
+		}
+	}
+	suffix := st.str[:i]
+	st.advance(i)
+	return &Clone{Base: a, Suffix: suffix}
+}
+
+// substitutions is the list of substitution candidates that may
+// appear later in the string.
+type substitutions []AST
+
+// add adds a new substitution candidate.
+func (subs *substitutions) add(a AST) {
+	*subs = append(*subs, a)
+}
+
+// subAST maps standard substitution codes to the corresponding AST.
+var subAST = map[byte]AST{
+	't': &Name{Name: "std"},
+	'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+	'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+	's': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "string"}},
+	'i': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "istream"}},
+	'o': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "ostream"}},
+	'd': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "iostream"}},
+}
+
+// verboseAST maps standard substitution codes to the long form of the
+// corresponding AST.  We use this when the Verbose option is used, to
+// match the standard demangler.
+var verboseAST = map[byte]AST{
+	't': &Name{Name: "std"},
+	'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+	'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+
+	// std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+	's': &Template{
+		Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+		Args: []AST{
+			&BuiltinType{Name: "char"},
+			&Template{
+				Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+				Args: []AST{&BuiltinType{Name: "char"}}},
+			&Template{
+				Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+				Args: []AST{&BuiltinType{Name: "char"}}}}},
+	// std::basic_istream<char, std::char_traits<char> >
+	'i': &Template{
+		Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_istream"}},
+		Args: []AST{
+			&BuiltinType{Name: "char"},
+			&Template{
+				Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+				Args: []AST{&BuiltinType{Name: "char"}}}}},
+	// std::basic_ostream<char, std::char_traits<char> >
+	'o': &Template{
+		Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_ostream"}},
+		Args: []AST{
+			&BuiltinType{Name: "char"},
+			&Template{
+				Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+				Args: []AST{&BuiltinType{Name: "char"}}}}},
+	// std::basic_iostream<char, std::char_traits<char> >
+	'd': &Template{
+		Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_iostream"}},
+		Args: []AST{
+			&BuiltinType{Name: "char"},
+			&Template{
+				Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+				Args: []AST{&BuiltinType{Name: "char"}}}}},
+}
+
+// <substitution> ::= S <seq-id> _
+//                ::= S_
+//                ::= St
+//                ::= Sa
+//                ::= Sb
+//                ::= Ss
+//                ::= Si
+//                ::= So
+//                ::= Sd
+func (st *state) substitution(forPrefix bool) AST {
+	st.checkChar('S')
+	if len(st.str) == 0 {
+		st.fail("missing substitution index")
+	}
+	c := st.str[0]
+	st.advance(1)
+	dec := 1
+	if c == '_' || isDigit(c) || isUpper(c) {
+		id := 0
+		if c != '_' {
+			for c != '_' {
+				// Don't overflow a 32-bit int.
+				if id >= 0x80000000/36-36 {
+					st.fail("substitution index overflow")
+				}
+				if isDigit(c) {
+					id = id*36 + int(c-'0')
+				} else if isUpper(c) {
+					id = id*36 + int(c-'A') + 10
+				} else {
+					st.fail("invalid character in substitution index")
+				}
+
+				if len(st.str) == 0 {
+					st.fail("missing end to substitution index")
+				}
+				c = st.str[0]
+				st.advance(1)
+				dec++
+			}
+			id++
+		}
+
+		if id >= len(st.subs) {
+			st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
+		}
+
+		ret := st.subs[id]
+
+		// We need to update any references to template
+		// parameters to refer to the currently active
+		// template.
+		copy := func(a AST) AST {
+			tp, ok := a.(*TemplateParam)
+			if !ok {
+				return nil
+			}
+			if len(st.templates) == 0 {
+				st.failEarlier("substituted template parameter not in scope of template", dec)
+			}
+			template := st.templates[len(st.templates)-1]
+			if template == nil {
+				// This template parameter is within
+				// the scope of a cast operator.
+				return &TemplateParam{Index: tp.Index, Template: nil}
+			}
+
+			if tp.Index >= len(template.Args) {
+				st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec)
+			}
+
+			return &TemplateParam{Index: tp.Index, Template: template}
+		}
+		var seen []AST
+		skip := func(a AST) bool {
+			if _, ok := a.(*Typed); ok {
+				return true
+			}
+			for _, v := range seen {
+				if v == a {
+					return true
+				}
+			}
+			seen = append(seen, a)
+			return false
+		}
+		if c := ret.Copy(copy, skip); c != nil {
+			return c
+		}
+
+		return ret
+	} else {
+		m := subAST
+		if st.verbose {
+			m = verboseAST
+		}
+		// For compatibility with the standard demangler, use
+		// a longer name for a constructor or destructor.
+		if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') {
+			m = verboseAST
+		}
+		a, ok := m[c]
+		if !ok {
+			st.failEarlier("unrecognized substitution code", 1)
+		}
+
+		if len(st.str) > 0 && st.str[0] == 'B' {
+			a = st.taggedName(a)
+		}
+
+		return a
+	}
+}
+
+// isDigit returns whetner c is a digit for demangling purposes.
+func isDigit(c byte) bool {
+	return c >= '0' && c <= '9'
+}
+
+// isUpper returns whether c is an upper case letter for demangling purposes.
+func isUpper(c byte) bool {
+	return c >= 'A' && c <= 'Z'
+}
+
+// isLower returns whether c is a lower case letter for demangling purposes.
+func isLower(c byte) bool {
+	return c >= 'a' && c <= 'z'
+}
+
+// simplify replaces template parameters with their expansions, and
+// merges qualifiers.
+func simplify(a AST) AST {
+	var seen []AST
+	skip := func(a AST) bool {
+		for _, v := range seen {
+			if v == a {
+				return true
+			}
+		}
+		seen = append(seen, a)
+		return false
+	}
+	if r := a.Copy(simplifyOne, skip); r != nil {
+		return r
+	}
+	return a
+}
+
+// simplifyOne simplifies a single AST.  It returns nil if there is
+// nothing to do.
+func simplifyOne(a AST) AST {
+	switch a := a.(type) {
+	case *TemplateParam:
+		if a.Template != nil && a.Index < len(a.Template.Args) {
+			return a.Template.Args[a.Index]
+		}
+	case *MethodWithQualifiers:
+		if m, ok := a.Method.(*MethodWithQualifiers); ok {
+			ref := a.RefQualifier
+			if ref == "" {
+				ref = m.RefQualifier
+			} else if m.RefQualifier != "" {
+				if ref == "&" || m.RefQualifier == "&" {
+					ref = "&"
+				}
+			}
+			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref}
+		}
+		if t, ok := a.Method.(*TypeWithQualifiers); ok {
+			return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier}
+		}
+	case *TypeWithQualifiers:
+		if ft, ok := a.Base.(*FunctionType); ok {
+			return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""}
+		}
+		if t, ok := a.Base.(*TypeWithQualifiers); ok {
+			return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)}
+		}
+		if m, ok := a.Base.(*MethodWithQualifiers); ok {
+			return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier}
+		}
+	case *ReferenceType:
+		if rt, ok := a.Base.(*ReferenceType); ok {
+			return rt
+		}
+		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
+			return &ReferenceType{Base: rrt.Base}
+		}
+	case *RvalueReferenceType:
+		if rrt, ok := a.Base.(*RvalueReferenceType); ok {
+			return rrt
+		}
+		if rt, ok := a.Base.(*ReferenceType); ok {
+			return rt
+		}
+	case *ArrayType:
+		// Qualifiers on the element of an array type
+		// go on the whole array type.
+		if q, ok := a.Element.(*TypeWithQualifiers); ok {
+			return &TypeWithQualifiers{
+				Base:       &ArrayType{Dimension: a.Dimension, Element: q.Base},
+				Qualifiers: q.Qualifiers,
+			}
+		}
+	case *PackExpansion:
+		// Expand the pack and replace it with a list of
+		// expressions.
+		if a.Pack != nil {
+			exprs := make([]AST, len(a.Pack.Args))
+			for i, arg := range a.Pack.Args {
+				copy := func(sub AST) AST {
+					// Replace the ArgumentPack
+					// with a specific argument.
+					if sub == a.Pack {
+						return arg
+					}
+					// Copy everything else.
+					return nil
+				}
+
+				var seen []AST
+				skip := func(sub AST) bool {
+					// Don't traverse into another
+					// pack expansion.
+					if _, ok := sub.(*PackExpansion); ok {
+						return true
+					}
+					for _, v := range seen {
+						if v == sub {
+							return true
+						}
+					}
+					seen = append(seen, sub)
+					return false
+				}
+
+				b := a.Base.Copy(copy, skip)
+				if b == nil {
+					b = a.Base
+				}
+				exprs[i] = simplify(b)
+			}
+			return &ExprList{Exprs: exprs}
+		}
+	}
+	return nil
+}
+
+// findArgumentPack walks the AST looking for the argument pack for a
+// pack expansion.  We find it via a template parameter.
+func (st *state) findArgumentPack(a AST) *ArgumentPack {
+	var seen []AST
+	var ret *ArgumentPack
+	a.Traverse(func(a AST) bool {
+		if ret != nil {
+			return false
+		}
+		switch a := a.(type) {
+		case *TemplateParam:
+			if a.Template == nil || a.Index >= len(a.Template.Args) {
+				return true
+			}
+			if pack, ok := a.Template.Args[a.Index].(*ArgumentPack); ok {
+				ret = pack
+				return false
+			}
+		case *PackExpansion, *Closure, *Name:
+			return false
+		case *TaggedName, *Operator, *BuiltinType, *FunctionParam:
+			return false
+		case *UnnamedType, *FixedType, *DefaultArg:
+			return false
+		}
+		for _, v := range seen {
+			if v == a {
+				return false
+			}
+		}
+		seen = append(seen, a)
+		return true
+	})
+	return ret
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle_test.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle_test.go
new file mode 100644
index 0000000..30a3269
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle_test.go
@@ -0,0 +1,420 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package demangle
+
+import (
+	"strconv"
+	"strings"
+	"testing"
+)
+
+// Check test cases discovered after the code passed the tests in
+// demangle-expected (which are tested by TestExpected).  Some of this
+// are cases where we differ from the standard demangler, some we are
+// the same but we weren't initially.
+func TestDemangler(t *testing.T) {
+	var tests = []struct {
+		input                string
+		want                 string
+		wantNoParams         string
+		wantNoTemplateParams string
+		wantMinimal          string
+	}{
+		{
+			"_ZNSaIcEC1ERKS_",
+			"std::allocator<char>::allocator(std::allocator<char> const&)",
+			"std::allocator<char>::allocator",
+			"std::allocator::allocator(std::allocator const&)",
+			"std::allocator::allocator",
+		},
+		{
+			"_ZN9__gnu_cxx13stdio_filebufIcSt11char_traitsIcEEC1EP8_IO_FILESt13_Ios_Openmodem",
+			"__gnu_cxx::stdio_filebuf<char, std::char_traits<char> >::stdio_filebuf(_IO_FILE*, std::_Ios_Openmode, unsigned long)",
+			"__gnu_cxx::stdio_filebuf<char, std::char_traits<char> >::stdio_filebuf",
+			"__gnu_cxx::stdio_filebuf::stdio_filebuf(_IO_FILE*, std::_Ios_Openmode, unsigned long)",
+			"__gnu_cxx::stdio_filebuf::stdio_filebuf",
+		},
+		{
+			"_ZN1n1CcvNS_1DIT_EEI1EEEv",
+			"n::C::operator n::D<E><E>()",
+			"n::C::operator n::D<E><E>",
+			"n::C::operator n::D()",
+			"n::C::operator n::D",
+		},
+		{
+			"_Z1CIvPN1D1E1FIdJEEEdEPN1GILb0ET_T0_T1_E1HEPFS6_S7_S8_EN1H1I1JIS7_E1KENSG_IS8_E1KE",
+			"G<false, void, D::E::F<double>*, double>::H* C<void, D::E::F<double>*, double>(void (*)(D::E::F<double>*, double), H::I::J<D::E::F<double>*>::K, H::I::J<double>::K)",
+			"C<void, D::E::F<double>*, double>",
+			"G::H* C(void (*)(D::E::F*, double), H::I::J::K, H::I::J::K)",
+			"C",
+		},
+		{
+			"_ZZNK1CI1DIcSt1EIcESaIcEEJEE1FEvE1F",
+			"C<D<char, std::E<char>, std::allocator<char> > >::F() const::F",
+			"C<D<char, std::E<char>, std::allocator<char> > >::F() const::F",
+			"C::F() const::F",
+			"C::F() const::F",
+		},
+		{
+			"_ZN1CI1DSt1EIK1FN1G1HEEE1I1JIJRKS6_EEEvDpOT_",
+			"void C<D, std::E<F const, G::H> >::I::J<std::E<F const, G::H> const&>(std::E<F const, G::H> const&)",
+			"C<D, std::E<F const, G::H> >::I::J<std::E<F const, G::H> const&>",
+			"void C::I::J(std::E const&)",
+			"C::I::J",
+		},
+		{
+			"_ZN1C1D1E1FIJEEEvi1GDpT_",
+			"void C::D::E::F<>(int, G)",
+			"C::D::E::F<>",
+			"void C::D::E::F(int, G)",
+			"C::D::E::F",
+		},
+		{
+			"_ZN1CILj50ELb1EE1DEv",
+			"C<50u, true>::D()",
+			"C<50u, true>::D",
+			"C::D()",
+			"C::D",
+		},
+		{
+			"_ZN1CUt_C2Ev",
+			"C::{unnamed type#1}::{unnamed type#1}()",
+			"C::{unnamed type#1}::{unnamed type#1}",
+			"C::{unnamed type#1}::{unnamed type#1}()",
+			"C::{unnamed type#1}::{unnamed type#1}",
+		},
+		{
+			"_ZN1C12_GLOBAL__N_11DINS_1EEEEN1F1GIDTadcldtcvT__E1HEEEERKS5_NS_1I1JE",
+			"F::G<decltype (&((((C::E)()).H)()))> C::(anonymous namespace)::D<C::E>(C::E const&, C::I::J)",
+			"C::(anonymous namespace)::D<C::E>",
+			"F::G C::(anonymous namespace)::D(C::E const&, C::I::J)",
+			"C::(anonymous namespace)::D",
+		},
+		{
+			"_ZN1CI1DE1EIJiRiRPKcRA1_S4_S8_bS6_S3_RjRPKN1F1GERPKN1H1IEEEEvDpOT_",
+			"void C<D>::E<int, int&, char const*&, char const (&) [1], char const (&) [1], bool, char const*&, int&, unsigned int&, F::G const*&, H::I const*&>(int&&, int&, char const*&, char const (&) [1], char const (&) [1], bool&&, char const*&, int&, unsigned int&, F::G const*&, H::I const*&)",
+			"C<D>::E<int, int&, char const*&, char const (&) [1], char const (&) [1], bool, char const*&, int&, unsigned int&, F::G const*&, H::I const*&>",
+			"void C::E(int&&, int&, char const*&, char const (&) [1], char const (&) [1], bool&&, char const*&, int&, unsigned int&, F::G const*&, H::I const*&)",
+			"C::E",
+		},
+		{
+			"_ZN1C12_GLOBAL__N_11DIFbPKNS_1EEEEEvPNS_1FERKT_",
+			"void C::(anonymous namespace)::D<bool (C::E const*)>(C::F*, bool (&)(C::E const*) const)",
+			"C::(anonymous namespace)::D<bool (C::E const*)>",
+			"void C::(anonymous namespace)::D(C::F*, bool (&)(C::E const*) const)",
+			"C::(anonymous namespace)::D",
+		},
+		{
+			"_ZN1C1D1EIJRFviSt1FIFvRKN1G1H1IEEERKSt6vectorINS_1JESaISB_EEERiS9_EvEENS0_1K1LIJDpNSt1MIT_E1NEEEEDpOSM_",
+			"C::D::K::L<std::M<void (&)(int, std::F<void (G::H::I const&)>, std::vector<C::J, std::allocator<C::J> > const&)>::N, std::M<int&>::N, std::M<std::F<void (G::H::I const&)> >::N> C::D::E<void (&)(int, std::F<void (G::H::I const&)>, std::vector<C::J, std::allocator<C::J> > const&), int&, std::F<void (G::H::I const&)>, void>(void (&)(int, std::F<void (G::H::I const&)>, std::vector<C::J, std::allocator<C::J> > const&), int&, std::F<void (G::H::I const&)>&&)",
+			"C::D::E<void (&)(int, std::F<void (G::H::I const&)>, std::vector<C::J, std::allocator<C::J> > const&), int&, std::F<void (G::H::I const&)>, void>",
+			"C::D::K::L C::D::E(void (&)(int, std::F, std::vector const&), int&, std::F&&)",
+			"C::D::E",
+		},
+		{
+			"_ZN1C1D1E1FcvNS_1GIT_EEI1HEEv",
+			"C::D::E::F::operator C::G<H><H>()",
+			"C::D::E::F::operator C::G<H><H>",
+			"C::D::E::F::operator C::G()",
+			"C::D::E::F::operator C::G",
+		},
+		{
+			"_ZN9__gnu_cxx17__normal_iteratorIPK1EIN1F1G1HEESt6vectorIS5_SaIS5_EEEC2IPS5_EERKNS0_IT_NS_11__enable_ifIXsr3std10__are_sameISE_SD_EE7__valueESA_E1IEEE",
+			"__gnu_cxx::__normal_iterator<E<F::G::H> const*, std::vector<E<F::G::H>, std::allocator<E<F::G::H> > > >::__normal_iterator<E<F::G::H>*>(__gnu_cxx::__normal_iterator<E<F::G::H>*, __gnu_cxx::__enable_if<std::__are_same<E<F::G::H>*, E<F::G::H>*>::__value, std::vector<E<F::G::H>, std::allocator<E<F::G::H> > > >::I> const&)",
+			"__gnu_cxx::__normal_iterator<E<F::G::H> const*, std::vector<E<F::G::H>, std::allocator<E<F::G::H> > > >::__normal_iterator<E<F::G::H>*>",
+			"__gnu_cxx::__normal_iterator::__normal_iterator(__gnu_cxx::__normal_iterator const&)",
+			"__gnu_cxx::__normal_iterator::__normal_iterator",
+		},
+		{
+			"_ZNKSt1CIM1DKFjvEEclIJEvEEjPKS0_DpOT_",
+			"unsigned int std::C<unsigned int (D::*)() const>::operator()<void>(D const*) const",
+			"std::C<unsigned int (D::*)() const>::operator()<void>",
+			"unsigned int std::C::operator()(D const*) const",
+			"std::C::operator()",
+		},
+		{
+			"_ZNSt10_HashtableI12basic_stringIcSt11char_traitsIcESaIcEESt4pairIKS4_N1C1D1EEESaISA_ENSt8__detail10_Select1stESt8equal_toIS4_ESt4hashIS4_ENSC_18_Mod_range_hashingENSC_20_Default_ranged_hashENSC_20_Prime_rehash_policyENSC_17_Hashtable_traitsILb1ELb0ELb1EEEE9_M_assignIZNSN_C1ERKSN_EUlPKNSC_10_Hash_nodeISA_Lb1EEEE_EEvSQ_RKT_",
+			"void std::_Hashtable<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<basic_string<char, std::char_traits<char>, std::allocator<char> > const, C::D::E>, std::allocator<std::pair<basic_string<char, std::char_traits<char>, std::allocator<char> > const, C::D::E> >, std::__detail::_Select1st, std::equal_to<basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__d [...]
+			"std::_Hashtable<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<basic_string<char, std::char_traits<char>, std::allocator<char> > const, C::D::E>, std::allocator<std::pair<basic_string<char, std::char_traits<char>, std::allocator<char> > const, C::D::E> >, std::__detail::_Select1st, std::equal_to<basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail [...]
+			"void std::_Hashtable::_M_assign(std::_Hashtable const&, std::_Hashtable::_Hashtable(std::_Hashtable const&)::{lambda(std::__detail::_Hash_node const*)#1} const&)",
+			"std::_Hashtable::_M_assign",
+		},
+		{
+			"_ZSt3maxIVdERKT_S3_S3_",
+			"double const volatile& std::max<double volatile>(double const volatile&, double const volatile&)",
+			"std::max<double volatile>",
+			"double const volatile& std::max(double const volatile&, double const volatile&)",
+			"std::max",
+		},
+		{
+			"_ZZN1C1D1E1F1G1HEvENUlvE_C2EOS4_",
+			"C::D::E::F::G::H()::{lambda()#1}::{lambda()#1}({lambda()#1}&&)",
+			"C::D::E::F::G::H()::{lambda()#1}::{lambda()#1}",
+			"C::D::E::F::G::H()::{lambda()#1}::{lambda()#1}({lambda()#1}&&)",
+			"C::D::E::F::G::H()::{lambda()#1}::{lambda()#1}",
+		},
+		{
+			"_ZThn8_NK1C1D1EEv",
+			"non-virtual thunk to C::D::E() const",
+			"non-virtual thunk to C::D::E() const",
+			"non-virtual thunk to C::D::E() const",
+			"non-virtual thunk to C::D::E() const",
+		},
+		{
+			"_ZTv0_n96_NK1C1D1E1FEv",
+			"virtual thunk to C::D::E::F() const",
+			"virtual thunk to C::D::E::F() const",
+			"virtual thunk to C::D::E::F() const",
+			"virtual thunk to C::D::E::F() const",
+		},
+		{
+			"_ZTCSt9strstream16_So",
+			"construction vtable for std::ostream-in-std::strstream",
+			"construction vtable for std::ostream-in-std::strstream",
+			"construction vtable for std::ostream-in-std::strstream",
+			"construction vtable for std::ostream-in-std::strstream",
+		},
+		{
+			"_ZGVZZN1C1D1EEvENK3$_0clEvE1F",
+			"guard variable for C::D::E()::$_0::operator()() const::F",
+			"guard variable for C::D::E()::$_0::operator()() const::F",
+			"guard variable for C::D::E()::$_0::operator()() const::F",
+			"guard variable for C::D::E()::$_0::operator()() const::F",
+		},
+		{
+			"_Z1fICiEvT_",
+			"void f<int _Complex>(int _Complex)",
+			"f<int _Complex>",
+			"void f(int _Complex)",
+			"f",
+		},
+		{
+			"_GLOBAL__D__Z2fnv",
+			"global destructors keyed to fn()",
+			"global destructors keyed to fn()",
+			"global destructors keyed to fn()",
+			"global destructors keyed to fn()",
+		},
+		{
+			"_Z1fIXadL_Z1hvEEEvv",
+			"void f<&h>()",
+			"f<&h>",
+			"void f()",
+			"f",
+		},
+		{
+			"_Z1CIP1DEiRK1EPT_N1F1GIS5_Xaasr1HIS5_E1IntsrSA_1JEE1KE",
+			"int C<D*>(E const&, D**, F::G<D*, H<D*>::I&&(!H<D*>::J)>::K)",
+			"C<D*>",
+			"int C(E const&, D**, F::G::K)",
+			"C",
+		},
+		{
+			"_ZNO1A1B1C1DIZN1E1F1GINS3_1HE1IEEvMNS3_1JEFvP1LPKT_PT0_P1KESD_SA_SF_SH_EUlvE_Lb0EEcvPSB_ISG_vvEEv",
+			"A::B::C::D<void E::F::G<E::H, I>(void (E::J::*)(L*, E::H const*, I*, K*), E::H const*, L*, I*, K*)::{lambda()#1}, false>::operator K*<K, void, void>() &&",
+			"A::B::C::D<void E::F::G<E::H, I>(void (E::J::*)(L*, E::H const*, I*, K*), E::H const*, L*, I*, K*)::{lambda()#1}, false>::operator K*<K, void, void>",
+			"A::B::C::D::operator K*() &&",
+			"A::B::C::D::operator K*",
+		},
+		{
+			"_ZNSt1AIFSt1BImjEjEZN1C1DI1EEENSt1FIXeqsr1G1H1IIDTadsrT_onclEEE1JLi2EEvE1KEPKcSC_OS7_EUljE_E1KERKSt1Lj",
+			"std::A<std::B<unsigned long, unsigned int> (unsigned int), std::F<G::H::I<decltype (&E::operator())>::J==(2), void>::K C::D<E>(char const*, G::H::I<decltype (&E::operator())>, G&&)::{lambda(unsigned int)#1}>::K(std::L const&, unsigned int)",
+			"std::A<std::B<unsigned long, unsigned int> (unsigned int), std::F<G::H::I<decltype (&E::operator())>::J==(2), void>::K C::D<E>(char const*, G::H::I<decltype (&E::operator())>, G&&)::{lambda(unsigned int)#1}>::K",
+			"std::A::K(std::L const&, unsigned int)",
+			"std::A::K",
+		},
+		{
+			"_ZNSt1AIFSt1BImjEjEZN1L1CIUljE_EENSt1DIXeqsrN1E1F1GIDTadsrT_clEEE1HLi2EEvE1IEPKcSG_OSA_EUljE_E1JERKSt1Kj",
+			"std::A<std::B<unsigned long, unsigned int> (unsigned int), std::D<E::F::G<decltype (&{lambda(unsigned int)#1}::operator())>::H==(2), void>::I L::C<{lambda(unsigned int)#1}>(char const*, char const*, {lambda(unsigned int)#1}&&)::{lambda(unsigned int)#1}>::J(std::K const&, unsigned int)",
+			"std::A<std::B<unsigned long, unsigned int> (unsigned int), std::D<E::F::G<decltype (&{lambda(unsigned int)#1}::operator())>::H==(2), void>::I L::C<{lambda(unsigned int)#1}>(char const*, char const*, {lambda(unsigned int)#1}&&)::{lambda(unsigned int)#1}>::J",
+			"std::A::J(std::K const&, unsigned int)",
+			"std::A::J",
+		},
+		{
+			"_ZNSt1A1BIiNS_1CIiEEE1DIPiEENS_1EIXaasr1FIT_EE1Gsr1HIiNS_1IIS7_E1JEEE1KEvE1LES7_S7_",
+			"std::A::E<F<int*>::G&&H<int, std::A::I<F>::J>::K, void>::L std::A::B<int, std::A::C<int> >::D<int*>(F, F)",
+			"std::A::B<int, std::A::C<int> >::D<int*>",
+			"std::A::E::L std::A::B::D(F, F)",
+			"std::A::B::D",
+		},
+		{
+			"_ZNO1A1B1C1DIJOZZN1E1F1GINS4_1HINS4_1IINS4_1JEEEEEJNS4_1KEEEEN1L1MINS4_1OINT_1PEEEEERKSt6vectorIN1Q1RESaISL_EERKN3gtl1S1TIN1U1VEEERKNS4_1W1XERKNS4_1YERKNSQ_1ZINS4_1aEEEPSt13unordered_mapISL_NSK_9UniquePtrINS4_1bINS0_1cIJS9_NS7_INST_1dEEEEEENS4_1fEEEEENSC_1g1hIvEESt8equal_toISL_ESaISt4pairIKSL_S1J_EEEDpRKT0_ENKUlSL_mmS1G_E_clESL_mmS1G_EUlS9_E_OZZNS5_ISA_JSB_EEESI_SP_SX_S11_S14_S19_S1U_S1Y_ENKS1Z_clESL_mmS1G_EUlS1F_E0_EEclIJRS9_EEEDTclcl1iIXsrNS1_1jISt5tupleIJNS1_1kIS21_EENS29_IS23_EEE [...]
+			"decltype (((i<A::B::C::j<std::tuple<A::B::C::k<{lambda(E::F::I<E::F::J>)#1}>, E::F::I<E::F::J>&<L::M<E::F::O<E::F::H<E::F::I<E::F::J> >::P> > E::F::G<E::F::H<E::F::I<E::F::J> >, E::F::K>(std::vector<Q::R, std::allocator<Q::R> > const&, gtl::S::T<U::V> const&, E::F::W::X const&, E::F::Y const&, gtl::Z<E::F::a> const&, std::unordered_map<Q::R, Q::UniquePtr<E::F::b<A::B::c<E::F::I<E::F::J>, E::F::I<U::d> >, E::F::f> >, L::g::h<void>, std::equal_to<Q::R>, std::allocator<std::pair<Q::R co [...]
+			"A::B::C::D<L::M<E::F::O<E::F::H<E::F::I<E::F::J> >::P> > E::F::G<E::F::H<E::F::I<E::F::J> >, E::F::K>(std::vector<Q::R, std::allocator<Q::R> > const&, gtl::S::T<U::V> const&, E::F::W::X const&, E::F::Y const&, gtl::Z<E::F::a> const&, std::unordered_map<Q::R, Q::UniquePtr<E::F::b<A::B::c<E::F::I<E::F::J>, E::F::I<U::d> >, E::F::f> >, L::g::h<void>, std::equal_to<Q::R>, std::allocator<std::pair<Q::R const, Q::UniquePtr<E::F::b<A::B::c<E::F::I<E::F::J>, E::F::I<U::d> >, E::F::f> > > > > [...]
+			"decltype (((i)((m)()))(((m)())...)) A::B::C::D::operator()((A::B::C::k&&)...) &&",
+			"A::B::C::D::operator()",
+		},
+		{
+			"_ZcvAna_eE_e",
+			"operator long double [new long double]",
+			"operator long double [new long double]",
+			"operator long double [new long double]",
+			"operator long double [new long double]",
+		},
+		{
+			"_ZZ1irFeeEES_S_",
+			"i(() restrict)::long double (long double)(() restrict) restrict",
+			"i(long double (long double) restrict)::long double (long double)",
+			"i(() restrict)::long double (long double)(() restrict) restrict",
+			"i(long double (long double) restrict)::long double (long double)",
+		},
+		{
+			"_Z1_VFaeEZS_S_ES_",
+			"_((() volatile) volatile, signed char (long double)(() volatile) volatile::(() volatile) volatile)",
+			"_",
+			"_((() volatile) volatile, signed char (long double)(() volatile) volatile::(() volatile) volatile)",
+			"_",
+		},
+		{
+			"_ZdsrFliEZS_GS_EcvS_",
+			"operator.*(( ( _Imaginary)( _Imaginary) restrict) restrict, long (int)( ( _Imaginary)( _Imaginary) restrict) restrict::operator ( ( _Imaginary)( _Imaginary) restrict) restrict)",
+			"operator.*",
+			"operator.*(( ( _Imaginary)( _Imaginary) restrict) restrict, long (int)( ( _Imaginary)( _Imaginary) restrict) restrict::operator ( ( _Imaginary)( _Imaginary) restrict) restrict)",
+			"operator.*",
+		},
+	}
+
+	for _, test := range tests {
+		if got, err := ToString(test.input); err != nil {
+			t.Errorf("demangling %s: unexpected error %v", test.input, err)
+		} else if got != test.want {
+			t.Errorf("demangling %s: got %s, want %s", test.input, got, test.want)
+		}
+
+		if got, err := ToString(test.input, NoParams); err != nil {
+			t.Errorf("demangling NoParams  %s: unexpected error %v", test.input, err)
+		} else if got != test.wantNoParams {
+			t.Errorf("demangling NoParams %s: got %s, want %s", test.input, got, test.wantNoParams)
+		}
+
+		if got, err := ToString(test.input, NoTemplateParams); err != nil {
+			t.Errorf("demangling NoTemplateParams %s: unexpected error %v", test.input, err)
+		} else if got != test.wantNoTemplateParams {
+			t.Errorf("demangling NoTemplateParams %s: got %s, want %s", test.input, got, test.wantNoTemplateParams)
+		}
+
+		if got, err := ToString(test.input, NoParams, NoTemplateParams); err != nil {
+			t.Errorf("demangling NoTemplateParams %s: unexpected error %v", test.input, err)
+		} else if got != test.wantMinimal {
+			t.Errorf("demangling Minimal %s: got %s, want %s", test.input, got, test.wantMinimal)
+		}
+
+		// Test Filter also.
+		if got := Filter(test.input); got != test.want {
+			t.Errorf("Filter(%s) == %s, want %s", test.input, got, test.want)
+		}
+	}
+}
+
+// Test for some failure cases.
+func TestFailure(t *testing.T) {
+	var tests = []struct {
+		input string
+		error string
+		off   int
+	}{
+		{
+			"_Z1FE",
+			"unparsed characters at end of mangled name",
+			4,
+		},
+		{
+			"_Z1FQ",
+			"unrecognized type code",
+			4,
+		},
+		{
+			"_ZZSaIL0D",
+			"expected positive number",
+			8,
+		},
+		{
+			"_ZNKE",
+			"expected prefix",
+			4,
+		},
+		{
+			"_ZcvT_",
+			"not in scope of template",
+			6,
+		},
+		{
+			"_Z1AIXsZ1_EE",
+			"missing argument pack",
+			8,
+		},
+		{
+			"_Z1gIEDTclspilE",
+			"expected expression",
+			15,
+		},
+		{
+			"_ZNcvZN1ET_IEE",
+			"after local name",
+			14,
+		},
+		{
+			"_Zv00",
+			"expected positive number",
+			5,
+		},
+		{
+			"_ZcvT_B2T0",
+			"template parameter not in scope",
+			10,
+		},
+		{
+			"_ZStcvT_",
+			"template parameter not in scope",
+			8,
+		},
+		{
+			"_Z1aIeEU1RT_ZcvS1_",
+			"expected E after local name",
+			18,
+		},
+		{
+			"_ZNcvT_oRIEE",
+			"template index out of range",
+			11,
+		},
+		{
+			"_ZNcvT_D0IIEE",
+			"expected prefix",
+			13,
+		},
+		{
+			"_ZcvT_IAoncvT__eE",
+			"template parameter not in scope",
+			17,
+		},
+	}
+
+	for _, test := range tests {
+		got, err := ToString(test.input)
+		if err == nil {
+			t.Errorf("unexpected success for %s: %s", test.input, got)
+		} else if !strings.Contains(err.Error(), test.error) {
+			t.Errorf("unexpected error for %s: %v", test.input, err)
+		} else {
+			s := err.Error()
+			i := strings.LastIndex(s, " at ")
+			if i < 0 {
+				t.Errorf("missing offset in error for %s: %v", test.input, err)
+			} else {
+				off, oerr := strconv.Atoi(s[i+4:])
+				if oerr != nil {
+					t.Errorf("can't parse offset (%s) for %s: %v", s[i+4:], test.input, err)
+				} else if off != test.off {
+					t.Errorf("unexpected offset for %s: got %d, want %d", test.input, off, test.off)
+				}
+			}
+		}
+
+		if got := Filter(test.input); got != test.input {
+			t.Errorf("Filter(%s) == %s, want %s", test.input, got, test.input)
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/expected_test.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/expected_test.go
new file mode 100644
index 0000000..1dff860
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/expected_test.go
@@ -0,0 +1,183 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package demangle
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+	"testing"
+)
+
+var verbose = flag.Bool("verbose", false, "print each demangle-expected symbol")
+
+const filename = "testdata/demangle-expected"
+
+// A list of exceptions from demangle-expected that we do not handle
+// the same as the standard demangler.  We keep a list of exceptions
+// so that we can use an exact copy of the file.  These exceptions are
+// all based on different handling of a substitution that refers to a
+// template parameter.  The standard demangler seems to have a bug in
+// which template it uses when a reference or rvalue-reference refers
+// to a substitution that resolves to a template parameter.
+var exceptions = map[string]bool{
+	"_ZSt7forwardIRN1x14refobjiteratorINS0_3refINS0_4mime30multipart_section_processorObjIZ15get_body_parserIZZN14mime_processor21make_section_iteratorERKNS2_INS3_10sectionObjENS0_10ptrrefBaseEEEbENKUlvE_clEvEUlSB_bE_ZZNS6_21make_section_iteratorESB_bENKSC_clEvEUlSB_E0_ENS1_INS2_INS0_20outputrefiteratorObjIiEES8_EEEERKSsSB_OT_OT0_EUlmE_NS3_32make_multipart_default_discarderISP_EEEES8_EEEEEOT_RNSt16remove_referenceISW_E4typeE": true,
+	"_ZN3mdr16in_cached_threadIRZNK4cudr6GPUSet17parallel_for_eachIZN5tns3d20shape_representation7compute7GPUImpl7executeERKNS_1AINS_7ptr_refIKjEELl3ELl3ENS_8c_strideILl1ELl0EEEEERKNS8_INS9_IjEELl4ELl1ESD_EEEUliRKNS1_7ContextERNS7_5StateEE_JSt6vectorISO_SaISO_EEEEEvOT_DpRT0_EUlSP_E_JSt17reference_wrapperISO_EEEENS_12ScopedFutureIDTclfp_spcl7forwardISW_Efp0_EEEEESV_DpOSW_":                                                        true,
+	"_ZNSt9_Any_data9_M_accessIPZN3sel8Selector6SetObjI3FooJPKcMS4_FviEEEEvRT_DpT0_EUlvE_EESA_v":                                                                                                                   true,
+	"_ZNSt9_Any_data9_M_accessIPZN13ThreadManager7newTaskIRSt5_BindIFSt7_Mem_fnIM5DiaryFivEEPS5_EEIEEESt6futureINSt9result_ofIFT_DpT0_EE4typeEEOSF_DpOSG_EUlvE_EERSF_v":                                            true,
+	"_ZNSt9_Any_data9_M_accessIPZN6cereal18polymorphic_detail15getInputBindingINS1_16JSONInputArchiveEEENS1_6detail15InputBindingMapIT_E11SerializersERS7_jEUlPvRSt10unique_ptrIvNS5_12EmptyDeleterIvEEEE0_EESA_v": true,
+	"_ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v":                                                                                                                                        true,
+	"_ZNSt9_Any_data9_M_accessIPZN13ThreadManager10futureTaskISt5_BindIFSt7_Mem_fnIM6RunnerFvvEEPS5_EEEEvOT_EUlvE_EERSC_v":                                                                                         true,
+}
+
+// For simplicity, this test reads an exact copy of
+// libiberty/testsuite/demangle-expected from GCC.  See that file for
+// the syntax.  We ignore all tests that are not --format=gnu-v3 or
+// --format=auto with a string starting with _Z.
+func TestExpected(t *testing.T) {
+	f, err := os.Open(filename)
+	if err != nil {
+		t.Fatal(err)
+	}
+	scanner := bufio.NewScanner(f)
+	lineno := 1
+	for {
+		format, got := getOptLine(t, scanner, &lineno)
+		if !got {
+			break
+		}
+		report := lineno
+		input := getLine(t, scanner, &lineno)
+		expect := getLine(t, scanner, &lineno)
+
+		testNoParams := false
+		skip := false
+		if len(format) > 0 && format[0] == '-' {
+			for _, arg := range strings.Fields(format) {
+				switch arg {
+				case "--format=gnu-v3":
+				case "--format=auto":
+					if !strings.HasPrefix(input, "_Z") {
+						skip = true
+					}
+				case "--no-params":
+					testNoParams = true
+				case "--ret-postfix", "--ret-drop":
+					skip = true
+				case "--is-v3-ctor", "--is-v3-dtor":
+					skip = true
+				default:
+					if !strings.HasPrefix(arg, "--format=") {
+						t.Errorf("%s:%d: unrecognized argument %s", filename, report, arg)
+					}
+					skip = true
+				}
+			}
+		}
+
+		// The libiberty testsuite passes DMGL_TYPES to
+		// demangle type names, but that doesn't seem useful
+		// and we don't support it.
+		if !strings.HasPrefix(input, "_Z") && !strings.HasPrefix(input, "_GLOBAL_") {
+			skip = true
+		}
+
+		var expectNoParams string
+		if testNoParams {
+			expectNoParams = getLine(t, scanner, &lineno)
+		}
+
+		if skip {
+			continue
+		}
+
+		oneTest(t, report, input, expect, true)
+		if testNoParams {
+			oneTest(t, report, input, expectNoParams, false)
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		t.Error(err)
+	}
+}
+
+// oneTest tests one entry from demangle-expected.
+func oneTest(t *testing.T, report int, input, expect string, params bool) {
+	if *verbose {
+		fmt.Println(input)
+	}
+
+	exception := exceptions[input]
+
+	var s string
+	var err error
+	if params {
+		s, err = ToString(input)
+	} else {
+		s, err = ToString(input, NoParams)
+	}
+	if err != nil {
+		if exception {
+			t.Logf("%s:%d: ignore expected difference: got %q, expected %q", filename, report, err, expect)
+			return
+		}
+
+		if err != ErrNotMangledName {
+			if input == expect {
+				return
+			}
+			t.Errorf("%s:%d: %v", filename, report, err)
+			return
+		}
+		s = input
+	}
+
+	if s != expect {
+		if exception {
+			t.Logf("%s:%d: ignore expected difference: got %q, expected %q", filename, report, s, expect)
+		} else {
+			var a AST
+			if params {
+				a, err = ToAST(input)
+			} else {
+				a, err = ToAST(input, NoParams)
+			}
+			if err != nil {
+				t.Logf("ToAST error: %v", err)
+			} else {
+				t.Logf("\n%#v", a)
+			}
+			t.Errorf("%s:%d: params: %t: got %q, expected %q", filename, report, params, s, expect)
+		}
+	} else if exception && params {
+		t.Errorf("%s:%d: unexpected success (input listed in exceptions)", filename, report)
+	}
+}
+
+// getLine reads a line from demangle-expected.
+func getLine(t *testing.T, scanner *bufio.Scanner, lineno *int) string {
+	s, got := getOptLine(t, scanner, lineno)
+	if !got {
+		t.Fatalf("%s:%d: unexpected EOF", filename, *lineno)
+	}
+	return s
+}
+
+// getOptLine reads an optional line from demangle-expected, returning
+// false at EOF.  It skips comment lines and updates *lineno.
+func getOptLine(t *testing.T, scanner *bufio.Scanner, lineno *int) (string, bool) {
+	for {
+		if !scanner.Scan() {
+			return "", false
+		}
+		*lineno++
+		line := scanner.Text()
+		if !strings.HasPrefix(line, "#") {
+			return line, true
+		}
+	}
+}
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/testdata/demangle-expected b/src/cmd/vendor/github.com/ianlancetaylor/demangle/testdata/demangle-expected
new file mode 100644
index 0000000..015454b
--- /dev/null
+++ b/src/cmd/vendor/github.com/ianlancetaylor/demangle/testdata/demangle-expected
@@ -0,0 +1,4594 @@
+# This file holds test cases for the demangler.
+# Each test case looks like this:
+#  options
+#  input to be demangled
+#  expected output
+#
+#  Supported options:
+#    --format=<name>     Sets the demangling style.
+#    --no-params         There are two lines of expected output; the first
+#                        is with DMGL_PARAMS, the second is without it.
+#    --is-v3-ctor        Calls is_gnu_v3_mangled_ctor on input; expected
+#                        output is an integer representing ctor_kind.
+#    --is-v3-dtor        Likewise, but for dtors.
+#    --ret-postfix       Passes the DMGL_RET_POSTFIX option
+#
+#  For compatibility, just in case it matters, the options line may be
+#  empty, to mean --format=auto.  If it doesn't start with --, then it
+#  may contain only a format name.
+#
+# A line starting with `#' is ignored.
+# However, blank lines in this file are NOT ignored.
+#
+--format=gnu --no-params
+AddAlignment__9ivTSolverUiP12ivInteractorP7ivTGlue
+ivTSolver::AddAlignment(unsigned int, ivInteractor *, ivTGlue *)
+ivTSolver::AddAlignment
+#
+--format=gnu --no-params
+ArrowheadIntersects__9ArrowLineP9ArrowheadR6BoxObjP7Graphic
+ArrowLine::ArrowheadIntersects(Arrowhead *, BoxObj &, Graphic *)
+ArrowLine::ArrowheadIntersects
+#
+--format=gnu --no-params
+ArrowheadIntersects__9ArrowLineP9ArrowheadO6BoxObjP7Graphic
+ArrowLine::ArrowheadIntersects(Arrowhead *, BoxObj &&, Graphic *)
+ArrowLine::ArrowheadIntersects
+#
+--format=gnu --no-params
+AtEnd__13ivRubberGroup
+ivRubberGroup::AtEnd(void)
+ivRubberGroup::AtEnd
+#
+--format=gnu --no-params
+BgFilter__9ivTSolverP12ivInteractor
+ivTSolver::BgFilter(ivInteractor *)
+ivTSolver::BgFilter
+#
+--format=gnu --no-params
+Check__6UArrayi
+UArray::Check(int)
+UArray::Check
+#
+--format=gnu --no-params
+CoreConstDecls__8TextCodeR7ostream
+TextCode::CoreConstDecls(ostream &)
+TextCode::CoreConstDecls
+#
+--format=gnu --no-params
+CoreConstDecls__8TextCodeO7ostream
+TextCode::CoreConstDecls(ostream &&)
+TextCode::CoreConstDecls
+#
+--format=gnu --no-params
+Detach__8StateVarP12StateVarView
+StateVar::Detach(StateVarView *)
+StateVar::Detach
+#
+--format=gnu --no-params
+Done__9ComponentG8Iterator
+Component::Done(Iterator)
+Component::Done
+#
+--format=gnu --no-params
+Effect__11RelateManipR7ivEvent
+RelateManip::Effect(ivEvent &)
+RelateManip::Effect
+#
+--format=gnu --no-params
+Effect__11RelateManipO7ivEvent
+RelateManip::Effect(ivEvent &&)
+RelateManip::Effect
+#
+--format=gnu --no-params
+FindFixed__FRP4CNetP4CNet
+FindFixed(CNet *&, CNet *)
+FindFixed
+#
+--format=gnu --no-params
+FindFixed__FOP4CNetP4CNet
+FindFixed(CNet *&&, CNet *)
+FindFixed
+#
+--format=gnu --no-params
+Fix48_abort__FR8twolongs
+Fix48_abort(twolongs &)
+Fix48_abort
+#
+--format=gnu --no-params
+Fix48_abort__FO8twolongs
+Fix48_abort(twolongs &&)
+Fix48_abort
+#
+--format=gnu --no-params
+GetBarInfo__15iv2_6_VScrollerP13ivPerspectiveRiT2
+iv2_6_VScroller::GetBarInfo(ivPerspective *, int &, int &)
+iv2_6_VScroller::GetBarInfo
+#
+--format=gnu --no-params
+GetBarInfo__15iv2_6_VScrollerP13ivPerspectiveOiT2
+iv2_6_VScroller::GetBarInfo(ivPerspective *, int &&, int &&)
+iv2_6_VScroller::GetBarInfo
+#
+--format=gnu --no-params
+GetBgColor__C9ivPainter
+ivPainter::GetBgColor(void) const
+ivPainter::GetBgColor
+#
+--format=gnu --no-params
+InsertBody__15H_PullrightMenuii
+H_PullrightMenu::InsertBody(int, int)
+H_PullrightMenu::InsertBody
+#
+--format=gnu --no-params
+InsertCharacter__9TextManipc
+TextManip::InsertCharacter(char)
+TextManip::InsertCharacter
+#
+--format=gnu --no-params
+InsertToplevel__7ivWorldP12ivInteractorT1
+ivWorld::InsertToplevel(ivInteractor *, ivInteractor *)
+ivWorld::InsertToplevel
+#
+--format=gnu --no-params
+InsertToplevel__7ivWorldP12ivInteractorT1iiUi
+ivWorld::InsertToplevel(ivInteractor *, ivInteractor *, int, int, unsigned int)
+ivWorld::InsertToplevel
+#
+--format=gnu --no-params
+IsAGroup__FP11GraphicViewP11GraphicComp
+IsAGroup(GraphicView *, GraphicComp *)
+IsAGroup
+#
+--format=gnu --no-params
+IsA__10ButtonCodeUl
+ButtonCode::IsA(unsigned long)
+ButtonCode::IsA
+#
+--format=gnu --no-params
+ReadName__FR7istreamPc
+ReadName(istream &, char *)
+ReadName
+#
+--format=gnu --no-params
+Redraw__13StringBrowseriiii
+StringBrowser::Redraw(int, int, int, int)
+StringBrowser::Redraw
+#
+--format=gnu --no-params
+Rotate__13ivTransformerf
+ivTransformer::Rotate(float)
+ivTransformer::Rotate
+#
+--format=gnu --no-params
+Rotated__C13ivTransformerf
+ivTransformer::Rotated(float) const
+ivTransformer::Rotated
+#
+--format=gnu --no-params
+Round__Ff
+Round(float)
+Round
+#
+--format=gnu --no-params
+SetExport__16MemberSharedNameUi
+MemberSharedName::SetExport(unsigned int)
+MemberSharedName::SetExport
+#
+--format=gnu --no-params
+Set__14ivControlState13ControlStatusUi
+ivControlState::Set(ControlStatus, unsigned int)
+ivControlState::Set
+#
+--format=gnu --no-params
+Set__5DFacePcii
+DFace::Set(char *, int, int)
+DFace::Set
+#
+--format=gnu --no-params
+VConvert__9ivTSolverP12ivInteractorRP8TElementT2
+ivTSolver::VConvert(ivInteractor *, TElement *&, TElement *&)
+ivTSolver::VConvert
+#
+--format=gnu --no-params
+VConvert__9ivTSolverP7ivTGlueRP8TElement
+ivTSolver::VConvert(ivTGlue *, TElement *&)
+ivTSolver::VConvert
+#
+--format=gnu --no-params
+VOrder__9ivTSolverUiRP12ivInteractorT2
+ivTSolver::VOrder(unsigned int, ivInteractor *&, ivInteractor *&)
+ivTSolver::VOrder
+#
+--format=gnu --no-params
+_10PageButton$__both
+PageButton::__both
+PageButton::__both
+#
+--format=gnu --no-params
+_3RNG$singleMantissa
+RNG::singleMantissa
+RNG::singleMantissa
+#
+--format=gnu --no-params
+_5IComp$_release
+IComp::_release
+IComp::_release
+#
+--format=gnu --no-params
+_$_10BitmapComp
+BitmapComp::~BitmapComp(void)
+BitmapComp::~BitmapComp
+#
+--format=gnu --no-params
+_$_9__io_defs
+__io_defs::~__io_defs(void)
+__io_defs::~__io_defs
+#
+--format=gnu --no-params
+_$_Q23foo3bar
+foo::bar::~bar(void)
+foo::bar::~bar
+#
+--format=gnu --no-params
+_$_Q33foo3bar4bell
+foo::bar::bell::~bell(void)
+foo::bar::bell::~bell
+#
+--format=gnu --no-params
+__10ivTelltaleiP7ivGlyph
+ivTelltale::ivTelltale(int, ivGlyph *)
+ivTelltale::ivTelltale
+#
+--format=gnu --no-params
+__10ivViewportiP12ivInteractorUi
+ivViewport::ivViewport(int, ivInteractor *, unsigned int)
+ivViewport::ivViewport
+#
+--format=gnu --no-params
+__10ostrstream
+ostrstream::ostrstream(void)
+ostrstream::ostrstream
+#
+--format=gnu --no-params
+__10ostrstreamPcii
+ostrstream::ostrstream(char *, int, int)
+ostrstream::ostrstream
+#
+--format=gnu --no-params
+__11BitmapTablei
+BitmapTable::BitmapTable(int)
+BitmapTable::BitmapTable
+#
+--format=gnu --no-params
+__12ViewportCodeP12ViewportComp
+ViewportCode::ViewportCode(ViewportComp *)
+ViewportCode::ViewportCode
+#
+--format=gnu --no-params
+__12iv2_6_Borderii
+iv2_6_Border::iv2_6_Border(int, int)
+iv2_6_Border::iv2_6_Border
+#
+--format=gnu --no-params
+__12ivBreak_Listl
+ivBreak_List::ivBreak_List(long)
+ivBreak_List::ivBreak_List
+#
+--format=gnu --no-params
+__14iv2_6_MenuItemiP12ivInteractor
+iv2_6_MenuItem::iv2_6_MenuItem(int, ivInteractor *)
+iv2_6_MenuItem::iv2_6_MenuItem
+#
+--format=gnu --no-params
+__20DisplayList_IteratorR11DisplayList
+DisplayList_Iterator::DisplayList_Iterator(DisplayList &)
+DisplayList_Iterator::DisplayList_Iterator
+#
+--format=gnu --no-params
+__3fooRT0
+foo::foo(foo &)
+foo::foo
+#
+--format=gnu --no-params
+__3fooiN31
+foo::foo(int, int, int, int)
+foo::foo
+#
+--format=gnu --no-params
+__3fooiRT0iT2iT2
+foo::foo(int, foo &, int, foo &, int, foo &)
+foo::foo
+#
+--format=gnu --no-params
+__6KeyMapPT0
+KeyMap::KeyMap(KeyMap *)
+KeyMap::KeyMap
+#
+--format=gnu --no-params
+__8ArrowCmdP6EditorUiUi
+ArrowCmd::ArrowCmd(Editor *, unsigned int, unsigned int)
+ArrowCmd::ArrowCmd
+#
+--format=gnu --no-params
+__9F_EllipseiiiiP7Graphic
+F_Ellipse::F_Ellipse(int, int, int, int, Graphic *)
+F_Ellipse::F_Ellipse
+#
+--format=gnu --no-params
+__9FrameDataP9FrameCompi
+FrameData::FrameData(FrameComp *, int)
+FrameData::FrameData
+#
+--format=gnu --no-params
+__9HVGraphicP9CanvasVarP7Graphic
+HVGraphic::HVGraphic(CanvasVar *, Graphic *)
+HVGraphic::HVGraphic
+#
+--format=gnu --no-params
+__Q23foo3bar
+foo::bar::bar(void)
+foo::bar::bar
+#
+--format=gnu --no-params
+__Q33foo3bar4bell
+foo::bar::bell::bell(void)
+foo::bar::bell::bell
+#
+--format=gnu --no-params
+__aa__3fooRT0
+foo::operator&&(foo &)
+foo::operator&&
+#
+--format=gnu --no-params
+__aad__3fooRT0
+foo::operator&=(foo &)
+foo::operator&=
+#
+--format=gnu --no-params
+__ad__3fooRT0
+foo::operator&(foo &)
+foo::operator&
+#
+--format=gnu --no-params
+__adv__3fooRT0
+foo::operator/=(foo &)
+foo::operator/=
+#
+--format=gnu --no-params
+__aer__3fooRT0
+foo::operator^=(foo &)
+foo::operator^=
+#
+--format=gnu --no-params
+__als__3fooRT0
+foo::operator<<=(foo &)
+foo::operator<<=
+#
+--format=gnu --no-params
+__amd__3fooRT0
+foo::operator%=(foo &)
+foo::operator%=
+#
+--format=gnu --no-params
+__ami__3fooRT0
+foo::operator-=(foo &)
+foo::operator-=
+#
+--format=gnu --no-params
+__aml__3FixRT0
+Fix::operator*=(Fix &)
+Fix::operator*=
+#
+--format=gnu --no-params
+__aml__5Fix16i
+Fix16::operator*=(int)
+Fix16::operator*=
+#
+--format=gnu --no-params
+__aml__5Fix32RT0
+Fix32::operator*=(Fix32 &)
+Fix32::operator*=
+#
+--format=gnu --no-params
+__aor__3fooRT0
+foo::operator|=(foo &)
+foo::operator|=
+#
+--format=gnu --no-params
+__apl__3fooRT0
+foo::operator+=(foo &)
+foo::operator+=
+#
+--format=gnu --no-params
+__ars__3fooRT0
+foo::operator>>=(foo &)
+foo::operator>>=
+#
+--format=gnu --no-params
+__as__3fooRT0
+foo::operator=(foo &)
+foo::operator=
+#
+--format=gnu --no-params
+__cl__3fooRT0
+foo::operator()(foo &)
+foo::operator()
+#
+--format=gnu --no-params
+__cl__6Normal
+Normal::operator()(void)
+Normal::operator()
+#
+--format=gnu --no-params
+__cl__6Stringii
+String::operator()(int, int)
+String::operator()
+#
+--format=gnu --no-params
+__cm__3fooRT0
+foo::operator, (foo &)
+foo::operator, 
+#
+--format=gnu --no-params
+__co__3foo
+foo::operator~(void)
+foo::operator~
+#
+--format=gnu --no-params
+__dl__3fooPv
+foo::operator delete(void *)
+foo::operator delete
+#
+--format=gnu --no-params
+__dv__3fooRT0
+foo::operator/(foo &)
+foo::operator/
+#
+--format=gnu --no-params
+__eq__3fooRT0
+foo::operator==(foo &)
+foo::operator==
+#
+--format=gnu --no-params
+__er__3fooRT0
+foo::operator^(foo &)
+foo::operator^
+#
+--format=gnu --no-params
+__ge__3fooRT0
+foo::operator>=(foo &)
+foo::operator>=
+#
+--format=gnu --no-params
+__gt__3fooRT0
+foo::operator>(foo &)
+foo::operator>
+#
+--format=gnu --no-params
+__le__3fooRT0
+foo::operator<=(foo &)
+foo::operator<=
+#
+--format=gnu --no-params
+__ls__3fooRT0
+foo::operator<<(foo &)
+foo::operator<<
+#
+--format=gnu --no-params
+__ls__FR7ostreamPFR3ios_R3ios
+operator<<(ostream &, ios &(*)(ios &))
+operator<<
+#
+--format=gnu --no-params
+__ls__FR7ostreamR3Fix
+operator<<(ostream &, Fix &)
+operator<<
+#
+--format=gnu --no-params
+__lt__3fooRT0
+foo::operator<(foo &)
+foo::operator<
+#
+--format=gnu --no-params
+__md__3fooRT0
+foo::operator%(foo &)
+foo::operator%
+#
+--format=gnu --no-params
+__mi__3fooRT0
+foo::operator-(foo &)
+foo::operator-
+#
+--format=gnu --no-params
+__ml__3fooRT0
+foo::operator*(foo &)
+foo::operator*
+#
+--format=gnu --no-params
+__mm__3fooi
+foo::operator--(int)
+foo::operator--
+#
+--format=gnu --no-params
+__ne__3fooRT0
+foo::operator!=(foo &)
+foo::operator!=
+#
+--format=gnu --no-params
+__nt__3foo
+foo::operator!(void)
+foo::operator!
+#
+--format=gnu --no-params
+__nw__3fooi
+foo::operator new(int)
+foo::operator new
+#
+--format=gnu --no-params
+__oo__3fooRT0
+foo::operator||(foo &)
+foo::operator||
+#
+--format=gnu --no-params
+__opPc__3foo
+foo::operator char *(void)
+foo::operator char *
+#
+--format=gnu --no-params
+__opi__3foo
+foo::operator int(void)
+foo::operator int
+#
+--format=gnu --no-params
+__or__3fooRT0
+foo::operator|(foo &)
+foo::operator|
+#
+--format=gnu --no-params
+__pl__3fooRT0
+foo::operator+(foo &)
+foo::operator+
+#
+--format=gnu --no-params
+__pp__3fooi
+foo::operator++(int)
+foo::operator++
+#
+--format=gnu --no-params
+__rf__3foo
+foo::operator->(void)
+foo::operator->
+#
+--format=gnu --no-params
+__rm__3fooRT0
+foo::operator->*(foo &)
+foo::operator->*
+#
+--format=gnu --no-params
+__rs__3fooRT0
+foo::operator>>(foo &)
+foo::operator>>
+#
+--format=gnu --no-params
+_new_Fix__FUs
+_new_Fix(unsigned short)
+_new_Fix
+#
+--format=gnu --no-params
+_vt.foo
+foo virtual table
+foo virtual table
+#
+--format=gnu --no-params
+_vt.foo.bar
+foo::bar virtual table
+foo::bar virtual table
+#
+--format=gnu --no-params
+_vt$foo
+foo virtual table
+foo virtual table
+#
+--format=gnu --no-params
+_vt$foo$bar
+foo::bar virtual table
+foo::bar virtual table
+#
+--format=gnu --no-params
+append__7ivGlyphPT0
+ivGlyph::append(ivGlyph *)
+ivGlyph::append
+#
+--format=gnu --no-params
+clearok__FP7_win_sti
+clearok(_win_st *, int)
+clearok
+#
+--format=gnu --no-params
+complexfunc2__FPFPc_i
+complexfunc2(int (*)(char *))
+complexfunc2
+#
+--format=gnu --no-params
+complexfunc3__FPFPFPl_s_i
+complexfunc3(int (*)(short (*)(long *)))
+complexfunc3
+#
+--format=gnu --no-params
+complexfunc4__FPFPFPc_s_i
+complexfunc4(int (*)(short (*)(char *)))
+complexfunc4
+#
+--format=gnu --no-params
+complexfunc5__FPFPc_PFl_i
+complexfunc5(int (*(*)(char *))(long))
+complexfunc5
+#
+--format=gnu --no-params
+complexfunc6__FPFPi_PFl_i
+complexfunc6(int (*(*)(int *))(long))
+complexfunc6
+#
+--format=gnu --no-params
+complexfunc7__FPFPFPc_i_PFl_i
+complexfunc7(int (*(*)(int (*)(char *)))(long))
+complexfunc7
+#
+--format=gnu --no-params
+foo__FiN30
+foo(int, int, int, int)
+foo
+#
+--format=gnu --no-params
+foo__FiR3fooiT1iT1
+foo(int, foo &, int, foo &, int, foo &)
+foo
+#
+--format=gnu --no-params
+foo___3barl
+bar::foo_(long)
+bar::foo_
+#
+--format=gnu --no-params
+insert__15ivClippingStacklRP8_XRegion
+ivClippingStack::insert(long, _XRegion *&)
+ivClippingStack::insert
+#
+--format=gnu --no-params
+insert__16ChooserInfo_ListlR11ChooserInfo
+ChooserInfo_List::insert(long, ChooserInfo &)
+ChooserInfo_List::insert
+#
+--format=gnu --no-params
+insert__17FontFamilyRepListlRP15ivFontFamilyRep
+FontFamilyRepList::insert(long, ivFontFamilyRep *&)
+FontFamilyRepList::insert
+#
+--format=gnu --no-params
+leaveok__FP7_win_stc
+leaveok(_win_st *, char)
+leaveok
+#
+--format=gnu --no-params
+left_mover__C7ivMFKitP12ivAdjustableP7ivStyle
+ivMFKit::left_mover(ivAdjustable *, ivStyle *) const
+ivMFKit::left_mover
+#
+--format=gnu --no-params
+overload1arg__FSc
+overload1arg(signed char)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__FUc
+overload1arg(unsigned char)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__FUi
+overload1arg(unsigned int)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__FUl
+overload1arg(unsigned long)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__FUs
+overload1arg(unsigned short)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fc
+overload1arg(char)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fd
+overload1arg(double)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Ff
+overload1arg(float)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fi
+overload1arg(int)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fl
+overload1arg(long)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fs
+overload1arg(short)
+overload1arg
+#
+--format=gnu --no-params
+overload1arg__Fv
+overload1arg(void)
+overload1arg
+#
+--format=gnu --no-params
+overloadargs__Fi
+overloadargs(int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fii
+overloadargs(int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiii
+overloadargs(int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiii
+overloadargs(int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiii
+overloadargs(int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiii
+overloadargs(int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiiii
+overloadargs(int, int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiiiii
+overloadargs(int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiiiiii
+overloadargs(int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiiiiiii
+overloadargs(int, int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+overloadargs__Fiiiiiiiiiii
+overloadargs(int, int, int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=gnu --no-params
+poke__8ivRasterUlUlffff
+ivRaster::poke(unsigned long, unsigned long, float, float, float, float)
+ivRaster::poke
+#
+--format=gnu --no-params
+polar__Fdd
+polar(double, double)
+polar
+#
+--format=gnu --no-params
+scale__13ivTransformerff
+ivTransformer::scale(float, float)
+ivTransformer::scale
+#
+--format=gnu --no-params
+sgetn__7filebufPci
+filebuf::sgetn(char *, int)
+filebuf::sgetn
+#
+--format=gnu --no-params
+shift__FP5_FrepiT0
+shift(_Frep *, int, _Frep *)
+shift
+#
+--format=gnu --no-params
+test__C6BitSeti
+BitSet::test(int) const
+BitSet::test
+#
+--format=gnu --no-params
+test__C6BitSetii
+BitSet::test(int, int) const
+BitSet::test
+#
+--format=gnu --no-params
+text_source__8Documentl
+Document::text_source(long)
+Document::text_source
+#
+--format=gnu --no-params
+variance__6Erlangd
+Erlang::variance(double)
+Erlang::variance
+#
+--format=gnu --no-params
+view__14DocumentViewerP8ItemViewP11TabularItem
+DocumentViewer::view(ItemView *, TabularItem *)
+DocumentViewer::view
+#
+--format=gnu --no-params
+xy_extents__11ivExtensionffff
+ivExtension::xy_extents(float, float, float, float)
+ivExtension::xy_extents
+#
+--format=gnu --no-params
+zero__8osMemoryPvUi
+osMemory::zero(void *, unsigned int)
+osMemory::zero
+#
+--format=gnu --no-params
+_2T4$N
+T4::N
+T4::N
+#
+--format=gnu --no-params
+_Q22T42t1$N
+T4::t1::N
+T4::t1::N
+#
+--format=gnu --no-params
+get__2T1
+T1::get(void)
+T1::get
+#
+--format=gnu --no-params
+get__Q22T11a
+T1::a::get(void)
+T1::a::get
+#
+--format=gnu --no-params
+get__Q32T11a1b
+T1::a::b::get(void)
+T1::a::b::get
+#
+--format=gnu --no-params
+get__Q42T11a1b1c
+T1::a::b::c::get(void)
+T1::a::b::c::get
+#
+--format=gnu --no-params
+get__Q52T11a1b1c1d
+T1::a::b::c::d::get(void)
+T1::a::b::c::d::get
+#
+--format=gnu --no-params
+put__2T1i
+T1::put(int)
+T1::put
+#
+--format=gnu --no-params
+put__Q22T11ai
+T1::a::put(int)
+T1::a::put
+#
+--format=gnu --no-params
+put__Q32T11a1bi
+T1::a::b::put(int)
+T1::a::b::put
+#
+--format=gnu --no-params
+put__Q42T11a1b1ci
+T1::a::b::c::put(int)
+T1::a::b::c::put
+#
+--format=gnu --no-params
+put__Q52T11a1b1c1di
+T1::a::b::c::d::put(int)
+T1::a::b::c::d::put
+#
+--format=gnu --no-params
+bar__3fooPv
+foo::bar(void *)
+foo::bar
+#
+--format=gnu --no-params
+bar__C3fooPv
+foo::bar(void *) const
+foo::bar
+#
+--format=gnu --no-params
+__eq__3fooRT0
+foo::operator==(foo &)
+foo::operator==
+#
+--format=gnu --no-params
+__eq__C3fooR3foo
+foo::operator==(foo &) const
+foo::operator==
+#
+--format=gnu --no-params
+elem__t6vector1Zdi
+vector<double>::elem(int)
+vector<double>::elem
+#
+--format=gnu --no-params
+elem__t6vector1Zii
+vector<int>::elem(int)
+vector<int>::elem
+#
+--format=gnu --no-params
+__t6vector1Zdi
+vector<double>::vector(int)
+vector<double>::vector
+#
+--format=gnu --no-params
+__t6vector1Zii
+vector<int>::vector(int)
+vector<int>::vector
+#
+--format=gnu --no-params
+_$_t6vector1Zdi
+vector<double>::~vector(int)
+vector<double>::~vector
+#
+--format=gnu --no-params
+_$_t6vector1Zii
+vector<int>::~vector(int)
+vector<int>::~vector
+#
+--format=gnu --no-params
+__nw__t2T11ZcUi
+T1<char>::operator new(unsigned int)
+T1<char>::operator new
+#
+--format=gnu --no-params
+__nw__t2T11Z1tUi
+T1<t>::operator new(unsigned int)
+T1<t>::operator new
+#
+--format=gnu --no-params
+__dl__t2T11ZcPv
+T1<char>::operator delete(void *)
+T1<char>::operator delete
+#
+--format=gnu --no-params
+__dl__t2T11Z1tPv
+T1<t>::operator delete(void *)
+T1<t>::operator delete
+#
+--format=gnu --no-params
+__t2T11Zci
+T1<char>::T1(int)
+T1<char>::T1
+#
+--format=gnu --no-params
+__t2T11Zc
+T1<char>::T1(void)
+T1<char>::T1
+#
+--format=gnu --no-params
+__t2T11Z1ti
+T1<t>::T1(int)
+T1<t>::T1
+#
+--format=gnu --no-params
+__t2T11Z1t
+T1<t>::T1(void)
+T1<t>::T1
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity3Pix
+List<VHDLEntity>::Pix::Pix(void)
+List<VHDLEntity>::Pix::Pix
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity3PixPQ2t4List1Z10VHDLEntity7element
+List<VHDLEntity>::Pix::Pix(List<VHDLEntity>::element *)
+List<VHDLEntity>::Pix::Pix
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity3PixRCQ2t4List1Z10VHDLEntity3Pix
+List<VHDLEntity>::Pix::Pix(List<VHDLEntity>::Pix const &)
+List<VHDLEntity>::Pix::Pix
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity3PixOCQ2t4List1Z10VHDLEntity3Pix
+List<VHDLEntity>::Pix::Pix(List<VHDLEntity>::Pix const &&)
+List<VHDLEntity>::Pix::Pix
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity7elementRC10VHDLEntityPT0
+List<VHDLEntity>::element::element(VHDLEntity const &, List<VHDLEntity>::element *)
+List<VHDLEntity>::element::element
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity7elementOC10VHDLEntityPT0
+List<VHDLEntity>::element::element(VHDLEntity const &&, List<VHDLEntity>::element *)
+List<VHDLEntity>::element::element
+#
+--format=gnu --no-params
+__Q2t4List1Z10VHDLEntity7elementRCQ2t4List1Z10VHDLEntity7element
+List<VHDLEntity>::element::element(List<VHDLEntity>::element const &)
+List<VHDLEntity>::element::element
+#
+--format=gnu --no-params
+__cl__C11VHDLLibraryGt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+VHDLLibrary::operator()(PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >) const
+VHDLLibrary::operator()
+#
+--format=gnu --no-params
+__cl__Ct4List1Z10VHDLEntityRCQ2t4List1Z10VHDLEntity3Pix
+List<VHDLEntity>::operator()(List<VHDLEntity>::Pix const &) const
+List<VHDLEntity>::operator()
+#
+--format=gnu --no-params
+__ne__FPvRCQ2t4List1Z10VHDLEntity3Pix
+operator!=(void *, List<VHDLEntity>::Pix const &)
+operator!=
+#
+--format=gnu --no-params
+__ne__FPvRCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+operator!=(void *, PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> > const &)
+operator!=
+#
+--format=gnu --no-params
+__t4List1Z10VHDLEntityRCt4List1Z10VHDLEntity
+List<VHDLEntity>::List(List<VHDLEntity> const &)
+List<VHDLEntity>::List
+#
+--format=gnu --no-params
+__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX(void)
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX
+#
+--format=gnu --no-params
+__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityP14VHDLLibraryRepGQ2t4List1Z10VHDLEntity3Pix
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX(VHDLLibraryRep *, List<VHDLEntity>::Pix)
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX
+#
+--format=gnu --no-params
+__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityRCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX(PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> > const &)
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX
+#
+--format=gnu --no-params
+__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityOCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX(PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> > const &&)
+PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> >::PixX
+#
+--format=gnu --no-params
+nextE__C11VHDLLibraryRt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity
+VHDLLibrary::nextE(PixX<VHDLLibrary, VHDLLibraryRep, List<VHDLEntity> > &) const
+VHDLLibrary::nextE
+#
+--format=gnu --no-params
+next__Ct4List1Z10VHDLEntityRQ2t4List1Z10VHDLEntity3Pix
+List<VHDLEntity>::next(List<VHDLEntity>::Pix &) const
+List<VHDLEntity>::next
+#
+--format=gnu --no-params
+_GLOBAL_$D$set
+global destructors keyed to set
+global destructors keyed to set
+#
+--format=gnu --no-params
+_GLOBAL_$I$set
+global constructors keyed to set
+global constructors keyed to set
+#
+--format=gnu --no-params
+__as__t5ListS1ZUiRCt5ListS1ZUi
+ListS<unsigned int>::operator=(ListS<unsigned int> const &)
+ListS<unsigned int>::operator=
+#
+--format=gnu --no-params
+__cl__Ct5ListS1ZUiRCQ2t5ListS1ZUi3Vix
+ListS<unsigned int>::operator()(ListS<unsigned int>::Vix const &) const
+ListS<unsigned int>::operator()
+#
+--format=gnu --no-params
+__cl__Ct5SetLS1ZUiRCQ2t5SetLS1ZUi3Vix
+SetLS<unsigned int>::operator()(SetLS<unsigned int>::Vix const &) const
+SetLS<unsigned int>::operator()
+#
+--format=gnu --no-params
+__t10ListS_link1ZUiRCUiPT0
+ListS_link<unsigned int>::ListS_link(unsigned int const &, ListS_link<unsigned int> *)
+ListS_link<unsigned int>::ListS_link
+#
+--format=gnu --no-params
+__t10ListS_link1ZUiRCt10ListS_link1ZUi
+ListS_link<unsigned int>::ListS_link(ListS_link<unsigned int> const &)
+ListS_link<unsigned int>::ListS_link
+#
+--format=gnu --no-params
+__t5ListS1ZUiRCt5ListS1ZUi
+ListS<unsigned int>::ListS(ListS<unsigned int> const &)
+ListS<unsigned int>::ListS
+#
+--format=gnu --no-params
+next__Ct5ListS1ZUiRQ2t5ListS1ZUi3Vix
+ListS<unsigned int>::next(ListS<unsigned int>::Vix &) const
+ListS<unsigned int>::next
+#
+--format=gnu --no-params
+__ne__FPvRCQ2t5SetLS1ZUi3Vix
+operator!=(void *, SetLS<unsigned int>::Vix const &)
+operator!=
+#
+--format=gnu --no-params
+__t8ListElem1Z5LabelRt4List1Z5Label
+ListElem<Label>::ListElem(List<Label> &)
+ListElem<Label>::ListElem
+#
+--format=gnu --no-params
+__t8BDDHookV1ZPcRCPc
+BDDHookV<char *>::BDDHookV(char *const &)
+BDDHookV<char *>::BDDHookV
+#
+--format=gnu --no-params
+_vt$t8BDDHookV1ZPc
+BDDHookV<char *> virtual table
+BDDHookV<char *> virtual table
+#
+--format=gnu --no-params
+__ne__FPvRCQ211BDDFunction4VixB
+operator!=(void *, BDDFunction::VixB const &)
+operator!=
+#
+--format=gnu --no-params
+__eq__FPvRCQ211BDDFunction4VixB
+operator==(void *, BDDFunction::VixB const &)
+operator==
+#
+--format=gnu --no-params
+relativeId__CQ36T_phi210T_preserve8FPC_nextRCQ26T_phi210T_preserveRC10Parameters
+T_phi2::T_preserve::FPC_next::relativeId(T_phi2::T_preserve const &, Parameters const &) const
+T_phi2::T_preserve::FPC_next::relativeId
+#
+--format=lucid --no-params
+WS__FR7istream
+WS(istream &)
+WS
+#
+--format=lucid --no-params
+__aa__3fooFR3foo
+foo::operator&&(foo &)
+foo::operator&&
+#
+--format=lucid --no-params
+__aad__3fooFR3foo
+foo::operator&=(foo &)
+foo::operator&=
+#
+--format=lucid --no-params
+__ad__3fooFR3foo
+foo::operator&(foo &)
+foo::operator&
+#
+--format=lucid --no-params
+__adv__3fooFR3foo
+foo::operator/=(foo &)
+foo::operator/=
+#
+--format=lucid --no-params
+__adv__7complexF7complex
+complex::operator/=(complex)
+complex::operator/=
+#
+--format=lucid --no-params
+__aer__3fooFR3foo
+foo::operator^=(foo &)
+foo::operator^=
+#
+--format=lucid --no-params
+__als__3fooFR3foo
+foo::operator<<=(foo &)
+foo::operator<<=
+#
+--format=lucid --no-params
+__amd__3fooFR3foo
+foo::operator%=(foo &)
+foo::operator%=
+#
+--format=lucid --no-params
+__ami__3fooFR3foo
+foo::operator-=(foo &)
+foo::operator-=
+#
+--format=lucid --no-params
+__amu__3fooFR3foo
+foo::operator*=(foo &)
+foo::operator*=
+#
+--format=lucid --no-params
+__amu__7complexF7complex
+complex::operator*=(complex)
+complex::operator*=
+#
+--format=lucid --no-params
+__aor__3fooFR3foo
+foo::operator|=(foo &)
+foo::operator|=
+#
+--format=lucid --no-params
+__apl__3fooFR3foo
+foo::operator+=(foo &)
+foo::operator+=
+#
+--format=lucid --no-params
+__ars__3fooFR3foo
+foo::operator>>=(foo &)
+foo::operator>>=
+#
+--format=lucid --no-params
+__as__18istream_withassignFP9streambuf
+istream_withassign::operator=(streambuf *)
+istream_withassign::operator=
+#
+--format=lucid --no-params
+__as__18istream_withassignFR7istream
+istream_withassign::operator=(istream &)
+istream_withassign::operator=
+#
+--format=lucid --no-params
+__as__3fooFR3foo
+foo::operator=(foo &)
+foo::operator=
+#
+--format=lucid --no-params
+__as__3iosFR3ios
+ios::operator=(ios &)
+ios::operator=
+#
+--format=lucid --no-params
+__cl__3fooFR3foo
+foo::operator()(foo &)
+foo::operator()
+#
+--format=lucid --no-params
+__cm__3fooFR3foo
+foo::operator, (foo &)
+foo::operator, 
+#
+--format=lucid --no-params
+__co__3fooFv
+foo::operator~(void)
+foo::operator~
+#
+--format=lucid --no-params
+__ct__10istrstreamFPc
+istrstream::istrstream(char *)
+istrstream::istrstream
+#
+--format=lucid --no-params
+__ct__10istrstreamFPci
+istrstream::istrstream(char *, int)
+istrstream::istrstream
+#
+--format=lucid --no-params
+__ct__10ostrstreamFPciT2
+ostrstream::ostrstream(char *, int, int)
+ostrstream::ostrstream
+#
+--format=lucid --no-params
+__ct__10ostrstreamFv
+ostrstream::ostrstream(void)
+ostrstream::ostrstream
+#
+--format=lucid --no-params
+__ct__10smanip_intFPFR3iosi_R3iosi
+smanip_int::smanip_int(ios &(*)(ios &, int), int)
+smanip_int::smanip_int
+#
+--format=lucid --no-params
+__ct__10smanip_intFPFO3iosi_O3iosi
+smanip_int::smanip_int(ios &&(*)(ios &&, int), int)
+smanip_int::smanip_int
+#
+--format=lucid --no-params
+__ct__11fstreambaseFi
+fstreambase::fstreambase(int)
+fstreambase::fstreambase
+#
+--format=lucid --no-params
+__ct__11fstreambaseFiPcT1
+fstreambase::fstreambase(int, char *, int)
+fstreambase::fstreambase
+#
+--format=lucid --no-params
+__ct__11fstreambaseFv
+fstreambase::fstreambase(void)
+fstreambase::fstreambase
+#
+--format=lucid --no-params
+__ct__11smanip_longFPFR3iosl_R3iosl
+smanip_long::smanip_long(ios &(*)(ios &, long), long)
+smanip_long::smanip_long
+#
+--format=lucid --no-params
+__ct__11smanip_longFPFO3iosl_O3iosl
+smanip_long::smanip_long(ios &&(*)(ios &&, long), long)
+smanip_long::smanip_long
+#
+--format=lucid --no-params
+__ct__11stdiostreamFP4FILE
+stdiostream::stdiostream(FILE *)
+stdiostream::stdiostream
+#
+--format=lucid --no-params
+__ct__12strstreambufFPFl_PvPFPv_v
+strstreambuf::strstreambuf(void *(*)(long), void (*)(void *))
+strstreambuf::strstreambuf
+#
+--format=lucid --no-params
+__ct__12strstreambufFPUciT1
+strstreambuf::strstreambuf(unsigned char *, int, unsigned char *)
+strstreambuf::strstreambuf
+#
+--format=lucid --no-params
+__ct__12strstreambufFPciT1
+strstreambuf::strstreambuf(char *, int, char *)
+strstreambuf::strstreambuf
+#
+--format=lucid --no-params
+__ct__12strstreambufFi
+strstreambuf::strstreambuf(int)
+strstreambuf::strstreambuf
+#
+--format=lucid --no-params
+__ct__12strstreambufFv
+strstreambuf::strstreambuf(void)
+strstreambuf::strstreambuf
+#
+--format=lucid --no-params
+__ct__13strstreambaseFPciT1
+strstreambase::strstreambase(char *, int, char *)
+strstreambase::strstreambase
+#
+--format=lucid --no-params
+__ct__3fooFR3foo
+foo::foo(foo &)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3fooFO3foo
+foo::foo(foo &&)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3fooFi
+foo::foo(int)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3fooFiN31
+foo::foo(int, int, int, int)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3fooFiR3fooT1T2T1T2
+foo::foo(int, foo &, int, foo &, int, foo &)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3fooFiO3fooT1T2T1T2
+foo::foo(int, foo &&, int, foo &&, int, foo &&)
+foo::foo
+#
+--format=lucid --no-params
+__ct__3iosFP9streambuf
+ios::ios(streambuf *)
+ios::ios
+#
+--format=lucid --no-params
+__ct__7filebufFiPcT1
+filebuf::filebuf(int, char *, int)
+filebuf::filebuf
+#
+--format=lucid --no-params
+__ct__7fstreamFiPcT1
+fstream::fstream(int, char *, int)
+fstream::fstream
+#
+--format=lucid --no-params
+__ct__7istreamFP9streambuf
+istream::istream(streambuf *)
+istream::istream
+#
+--format=lucid --no-params
+__ct__7istreamFP9streambufiP7ostream
+istream::istream(streambuf *, int, ostream *)
+istream::istream
+#
+--format=lucid --no-params
+__ct__7istreamFiPcT1
+istream::istream(int, char *, int)
+istream::istream
+#
+--format=lucid --no-params
+__ct__7istreamFiT1P7ostream
+istream::istream(int, int, ostream *)
+istream::istream
+#
+--format=lucid --no-params
+__ct__7ostreamFP9streambuf
+ostream::ostream(streambuf *)
+ostream::ostream
+#
+--format=lucid --no-params
+__ct__7ostreamFiPc
+ostream::ostream(int, char *)
+ostream::ostream
+#
+--format=lucid --no-params
+__ct__8ifstreamFiPcT1
+ifstream::ifstream(int, char *, int)
+ifstream::ifstream
+#
+--format=lucid --no-params
+__ct__Q23foo3barFv
+foo::bar::bar(void)
+foo::bar::bar
+#
+--format=lucid --no-params
+__ct__Q33foo3bar4bellFv
+foo::bar::bell::bell(void)
+foo::bar::bell::bell
+#
+--format=lucid --no-params
+__dl__3fooSFPv
+foo::operator delete(void *) static
+foo::operator delete
+#
+--format=lucid --no-params
+__dl__FPv
+operator delete(void *)
+operator delete
+#
+--format=lucid --no-params
+__dt__10istrstreamFv
+istrstream::~istrstream(void)
+istrstream::~istrstream
+#
+--format=lucid --no-params
+__dt__Q23foo3barFv
+foo::bar::~bar(void)
+foo::bar::~bar
+#
+--format=lucid --no-params
+__dt__Q33foo3bar4bellFv
+foo::bar::bell::~bell(void)
+foo::bar::bell::~bell
+#
+--format=lucid --no-params
+__dv__3fooFR3foo
+foo::operator/(foo &)
+foo::operator/
+#
+--format=lucid --no-params
+__dv__F7complexT1
+operator/(complex, complex)
+operator/
+#
+--format=lucid --no-params
+__eq__3fooFR3foo
+foo::operator==(foo &)
+foo::operator==
+#
+--format=lucid --no-params
+__er__3fooFR3foo
+foo::operator^(foo &)
+foo::operator^
+#
+--format=lucid --no-params
+__ge__3fooFR3foo
+foo::operator>=(foo &)
+foo::operator>=
+#
+--format=lucid --no-params
+__gt__3fooFR3foo
+foo::operator>(foo &)
+foo::operator>
+#
+--format=lucid --no-params
+__le__3fooFR3foo
+foo::operator<=(foo &)
+foo::operator<=
+#
+--format=lucid --no-params
+__ls__3fooFR3foo
+foo::operator<<(foo &)
+foo::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFP9streambuf
+ostream::operator<<(streambuf *)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFPFR3ios_R3ios
+ostream::operator<<(ios &(*)(ios &))
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFPv
+ostream::operator<<(void *)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFUi
+ostream::operator<<(unsigned int)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFUl
+ostream::operator<<(unsigned long)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFd
+ostream::operator<<(double)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFf
+ostream::operator<<(float)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFi
+ostream::operator<<(int)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__7ostreamFl
+ostream::operator<<(long)
+ostream::operator<<
+#
+--format=lucid --no-params
+__ls__FR7ostream7complex
+operator<<(ostream &, complex)
+operator<<
+#
+--format=lucid --no-params
+__lt__3fooFR3foo
+foo::operator<(foo &)
+foo::operator<
+#
+--format=lucid --no-params
+__md__3fooFR3foo
+foo::operator%(foo &)
+foo::operator%
+#
+--format=lucid --no-params
+__mi__3fooFR3foo
+foo::operator-(foo &)
+foo::operator-
+#
+--format=lucid --no-params
+__ml__3fooFR3foo
+foo::operator*(foo &)
+foo::operator*
+#
+--format=lucid --no-params
+__ml__F7complexT1
+operator*(complex, complex)
+operator*
+#
+--format=lucid --no-params
+__mm__3fooFi
+foo::operator--(int)
+foo::operator--
+#
+--format=lucid --no-params
+__ne__3fooFR3foo
+foo::operator!=(foo &)
+foo::operator!=
+#
+--format=lucid --no-params
+__nt__3fooFv
+foo::operator!(void)
+foo::operator!
+#
+--format=lucid --no-params
+__nw__3fooSFi
+foo::operator new(int) static
+foo::operator new
+#
+--format=lucid --no-params
+__nw__FUi
+operator new(unsigned int)
+operator new
+#
+--format=lucid --no-params
+__nw__FUiPv
+operator new(unsigned int, void *)
+operator new
+#
+--format=lucid --no-params
+__oo__3fooFR3foo
+foo::operator||(foo &)
+foo::operator||
+#
+--format=lucid --no-params
+__opPc__3fooFv
+foo::operator char *(void)
+foo::operator char *
+#
+--format=lucid --no-params
+__opi__3fooFv
+foo::operator int(void)
+foo::operator int
+#
+--format=lucid --no-params
+__or__3fooFR3foo
+foo::operator|(foo &)
+foo::operator|
+#
+--format=lucid --no-params
+__pl__3fooFR3foo
+foo::operator+(foo &)
+foo::operator+
+#
+--format=lucid --no-params
+__pp__3fooFi
+foo::operator++(int)
+foo::operator++
+#
+--format=lucid --no-params
+__pt__3fooFv
+foo::operator->(void)
+foo::operator->
+#
+--format=lucid --no-params
+__rm__3fooFR3foo
+foo::operator->*(foo &)
+foo::operator->*
+#
+--format=lucid --no-params
+__rs__3fooFR3foo
+foo::operator>>(foo &)
+foo::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFP9streambuf
+istream::operator>>(streambuf *)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFPFR3ios_R3ios
+istream::operator>>(ios &(*)(ios &))
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFPFR7istream_R7istream
+istream::operator>>(istream &(*)(istream &))
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFPUc
+istream::operator>>(unsigned char *)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFPc
+istream::operator>>(char *)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRUi
+istream::operator>>(unsigned int &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRUl
+istream::operator>>(unsigned long &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRUs
+istream::operator>>(unsigned short &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRd
+istream::operator>>(double &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRf
+istream::operator>>(float &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRi
+istream::operator>>(int &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRl
+istream::operator>>(long &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__7istreamFRs
+istream::operator>>(short &)
+istream::operator>>
+#
+--format=lucid --no-params
+__rs__FR7istreamR7complex
+operator>>(istream &, complex &)
+operator>>
+#
+--format=lucid --no-params
+__vtbl__10istrstream
+istrstream virtual table
+istrstream virtual table
+#
+--format=lucid --no-params
+__vtbl__17ostream__iostream__19iostream_withassign
+iostream_withassign::ostream__iostream virtual table
+iostream_withassign::ostream__iostream virtual table
+#
+--format=lucid --no-params
+__vtbl__3ios
+ios virtual table
+ios virtual table
+#
+--format=lucid --no-params
+__vtbl__3ios__13strstreambase
+strstreambase::ios virtual table
+strstreambase::ios virtual table
+#
+--format=lucid --no-params
+abs__F7complex
+abs(complex)
+abs
+#
+--format=lucid --no-params
+allocate__9streambufFv
+streambuf::allocate(void)
+streambuf::allocate
+#
+--format=lucid --no-params
+attach__11fstreambaseFi
+fstreambase::attach(int)
+fstreambase::attach
+#
+--format=lucid --no-params
+bitalloc__3iosSFv
+ios::bitalloc(void) static
+ios::bitalloc
+#
+--format=lucid --no-params
+chr__FiT1
+chr(int, int)
+chr
+#
+--format=lucid --no-params
+complex_error__FR11c_exception
+complex_error(c_exception &)
+complex_error
+#
+--format=lucid --no-params
+complexfunc2__FPFPc_i
+complexfunc2(int (*)(char *))
+complexfunc2
+#
+--format=lucid --no-params
+complexfunc3__FPFPFPl_s_i
+complexfunc3(int (*)(short (*)(long *)))
+complexfunc3
+#
+--format=lucid --no-params
+complexfunc4__FPFPFPc_s_i
+complexfunc4(int (*)(short (*)(char *)))
+complexfunc4
+#
+--format=lucid --no-params
+complexfunc5__FPFPc_PFl_i
+complexfunc5(int (*(*)(char *))(long))
+complexfunc5
+#
+--format=lucid --no-params
+complexfunc6__FPFPi_PFl_i
+complexfunc6(int (*(*)(int *))(long))
+complexfunc6
+#
+--format=lucid --no-params
+complexfunc7__FPFPFPc_i_PFl_i
+complexfunc7(int (*(*)(int (*)(char *)))(long))
+complexfunc7
+#
+--format=lucid --no-params
+complicated_put__7ostreamFc
+ostream::complicated_put(char)
+ostream::complicated_put
+#
+--format=lucid --no-params
+conv10__FlPc
+conv10(long, char *)
+conv10
+#
+--format=lucid --no-params
+conv16__FUlPc
+conv16(unsigned long, char *)
+conv16
+#
+--format=lucid --no-params
+dec__FR3ios
+dec(ios &)
+dec
+#
+--format=lucid --no-params
+dec__Fli
+dec(long, int)
+dec
+#
+--format=lucid --no-params
+dofield__FP7ostreamPciT2T3
+dofield(ostream *, char *, int, char *, int)
+dofield
+#
+--format=lucid --no-params
+flags__3iosFl
+ios::flags(long)
+ios::flags
+#
+--format=lucid --no-params
+flags__3iosFv
+ios::flags(void)
+ios::flags
+#
+--format=lucid --no-params
+foo__FiN31
+foo(int, int, int, int)
+foo
+#
+--format=lucid --no-params
+foo__FiR3fooT1T2T1T2
+foo(int, foo &, int, foo &, int, foo &)
+foo
+#
+--format=lucid --no-params
+foo__FiO3fooT1T2T1T2
+foo(int, foo &&, int, foo &&, int, foo &&)
+foo
+#
+--format=lucid --no-params
+foo___3barFl
+bar::foo_(long)
+bar::foo_
+#
+--format=lucid --no-params
+get__7istreamFPcic
+istream::get(char *, int, char)
+istream::get
+#
+--format=lucid --no-params
+get__7istreamFR9streambufc
+istream::get(streambuf &, char)
+istream::get
+#
+--format=lucid --no-params
+get_complicated__7istreamFRUc
+istream::get_complicated(unsigned char &)
+istream::get_complicated
+#
+--format=lucid --no-params
+get_complicated__7istreamFRc
+istream::get_complicated(char &)
+istream::get_complicated
+#
+--format=lucid --no-params
+getline__7istreamFPUcic
+istream::getline(unsigned char *, int, char)
+istream::getline
+#
+--format=lucid --no-params
+getline__7istreamFPcic
+istream::getline(char *, int, char)
+istream::getline
+#
+--format=lucid --no-params
+ignore__7istreamFiT1
+istream::ignore(int, int)
+istream::ignore
+#
+--format=lucid --no-params
+init__12strstreambufFPciT1
+strstreambuf::init(char *, int, char *)
+strstreambuf::init
+#
+--format=lucid --no-params
+init__3iosFP9streambuf
+ios::init(streambuf *)
+ios::init
+#
+--format=lucid --no-params
+initcount__13Iostream_init
+Iostream_init::initcount
+Iostream_init::initcount
+#
+--format=lucid --no-params
+ipfx__7istreamFi
+istream::ipfx(int)
+istream::ipfx
+#
+--format=lucid --no-params
+ls_complicated__7ostreamFUc
+ostream::ls_complicated(unsigned char)
+ostream::ls_complicated
+#
+--format=lucid --no-params
+ls_complicated__7ostreamFc
+ostream::ls_complicated(char)
+ostream::ls_complicated
+#
+--format=lucid --no-params
+overload1arg__FSc
+overload1arg(signed char)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__FUc
+overload1arg(unsigned char)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__FUi
+overload1arg(unsigned int)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__FUl
+overload1arg(unsigned long)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__FUs
+overload1arg(unsigned short)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fc
+overload1arg(char)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fd
+overload1arg(double)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Ff
+overload1arg(float)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fi
+overload1arg(int)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fl
+overload1arg(long)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fs
+overload1arg(short)
+overload1arg
+#
+--format=lucid --no-params
+overload1arg__Fv
+overload1arg(void)
+overload1arg
+#
+--format=lucid --no-params
+overloadargs__FiN21
+overloadargs(int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN31
+overloadargs(int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN41
+overloadargs(int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN51
+overloadargs(int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN61
+overloadargs(int, int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN71
+overloadargs(int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN81
+overloadargs(int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN91
+overloadargs(int, int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiN91N11
+overloadargs(int, int, int, int, int, int, int, int, int, int, int)
+overloadargs
+#
+--format=lucid --no-params
+overloadargs__FiT1
+overloadargs(int, int)
+overloadargs
+#
+--format=lucid --no-params
+polar__FdT1
+polar(double, double)
+polar
+#
+--format=lucid --no-params
+pow__F7complexT1
+pow(complex, complex)
+pow
+#
+--format=lucid --no-params
+pow__F7complexd
+pow(complex, double)
+pow
+#
+--format=lucid --no-params
+pow__F7complexi
+pow(complex, int)
+pow
+#
+--format=lucid --no-params
+pow__Fd7complex
+pow(double, complex)
+pow
+#
+--format=lucid --no-params
+pstart__FPciT2
+pstart(char *, int, int)
+pstart
+#
+--format=lucid --no-params
+put__7ostreamFc
+ostream::put(char)
+ostream::put
+#
+--format=lucid --no-params
+read__7istreamFPci
+istream::read(char *, int)
+istream::read
+#
+--format=lucid --no-params
+resetiosflags__FR3iosl
+resetiosflags(ios &, long)
+resetiosflags
+#
+--format=lucid --no-params
+restore_errno__FRi
+restore_errno(int &)
+restore_errno
+#
+--format=lucid --no-params
+rs_complicated__7istreamFRUc
+istream::rs_complicated(unsigned char &)
+istream::rs_complicated
+#
+--format=lucid --no-params
+rs_complicated__7istreamFRc
+istream::rs_complicated(char &)
+istream::rs_complicated
+#
+--format=lucid --no-params
+seekg__7istreamFl8seek_dir
+istream::seekg(long, seek_dir)
+istream::seekg
+#
+--format=lucid --no-params
+seekoff__12strstreambufFl8seek_diri
+strstreambuf::seekoff(long, seek_dir, int)
+strstreambuf::seekoff
+#
+--format=lucid --no-params
+seekoff__9streambufFlQ2_3ios12ios_seek_diri
+streambuf::seekoff(long, ios::ios_seek_dir, int)
+streambuf::seekoff
+#
+--format=lucid --no-params
+seekpos__9streambufFli
+streambuf::seekpos(long, int)
+streambuf::seekpos
+#
+--format=lucid --no-params
+set_new_handler__FPFv_v
+set_new_handler(void (*)(void))
+set_new_handler
+#
+--format=lucid --no-params
+setb__9streambufFPcT1i
+streambuf::setb(char *, char *, int)
+streambuf::setb
+#
+--format=lucid --no-params
+setb__FR3iosi
+setb(ios &, int)
+setb
+#
+--format=lucid --no-params
+setbuf__11fstreambaseFPci
+fstreambase::setbuf(char *, int)
+fstreambase::setbuf
+#
+--format=lucid --no-params
+setbuf__9streambufFPUci
+streambuf::setbuf(unsigned char *, int)
+streambuf::setbuf
+#
+--format=lucid --no-params
+setbuf__9streambufFPciT2
+streambuf::setbuf(char *, int, int)
+streambuf::setbuf
+#
+--format=lucid --no-params
+setf__3iosFlT1
+ios::setf(long, long)
+ios::setf
+#
+--format=lucid --no-params
+setfill__FR3iosi
+setfill(ios &, int)
+setfill
+#
+--format=lucid --no-params
+setg__9streambufFPcN21
+streambuf::setg(char *, char *, char *)
+streambuf::setg
+#
+--format=lucid --no-params
+setp__9streambufFPcT1
+streambuf::setp(char *, char *)
+streambuf::setp
+#
+--format=lucid --no-params
+tie__3iosFP7ostream
+ios::tie(ostream *)
+ios::tie
+#
+--format=lucid --no-params
+uconv10__FUlPc
+uconv10(unsigned long, char *)
+uconv10
+#
+--format=lucid --no-params
+xget__7istreamFPc
+istream::xget(char *)
+istream::xget
+#
+--format=lucid --no-params
+xsgetn__9streambufFPci
+streambuf::xsgetn(char *, int)
+streambuf::xsgetn
+#
+--format=arm --no-params
+__dt__21T5__pt__11_PFiPPdPv_iFv
+T5<int (*)(int, double **, void *)>::~T5(void)
+T5<int (*)(int, double **, void *)>::~T5
+#
+--format=arm --no-params
+__ct__1cFi
+c::c(int)
+c::c
+#
+--format=arm --no-params
+__dt__11T5__pt__2_iFv
+T5<int>::~T5(void)
+T5<int>::~T5
+#
+--format=arm --no-params
+__dt__11T5__pt__2_cFv
+T5<char>::~T5(void)
+T5<char>::~T5
+#
+--format=arm --no-params
+__ct__2T2Fi
+T2::T2(int)
+T2::T2
+#
+--format=arm --no-params
+__dt__2T1Fv
+T1::~T1(void)
+T1::~T1
+#
+--format=arm --no-params
+__dt__12T5__pt__3_1xFv
+T5<x>::~T5(void)
+T5<x>::~T5
+#
+--format=arm --no-params
+__dt__17T5__pt__8_PFcPv_iFv
+T5<int (*)(char, void *)>::~T5(void)
+T5<int (*)(char, void *)>::~T5
+#
+--format=arm --no-params
+__ct__21T5__pt__11_PFiPPdPv_iFi
+T5<int (*)(int, double **, void *)>::T5(int)
+T5<int (*)(int, double **, void *)>::T5
+#
+--format=arm --no-params
+__amd__FR2T2i
+operator%=(T2 &, int)
+operator%=
+#
+--format=arm --no-params
+__adv__FR2T2i
+operator/=(T2 &, int)
+operator/=
+#
+--format=arm --no-params
+__amu__FR2T2i
+operator*=(T2 &, int)
+operator*=
+#
+--format=arm --no-params
+__ami__FR2T2i
+operator-=(T2 &, int)
+operator-=
+#
+--format=arm --no-params
+__apl__FR2T2i
+operator+=(T2 &, int)
+operator+=
+#
+--format=arm --no-params
+__nw__2T1SFUi
+T1::operator new(unsigned int) static
+T1::operator new
+#
+--format=arm --no-params
+__dl__2T1SFPv
+T1::operator delete(void *) static
+T1::operator delete
+#
+--format=arm --no-params
+put__2T7SFi
+T7::put(int) static
+T7::put
+#
+--format=arm --no-params
+__dl__12T5__pt__3_1xSFPv
+T5<x>::operator delete(void *) static
+T5<x>::operator delete
+#
+--format=arm --no-params
+h__FUc
+h(unsigned char)
+h
+#
+--format=arm --no-params
+f__Fic
+f(int, char)
+f
+#
+--format=arm --no-params
+h__FUi
+h(unsigned int)
+h
+#
+--format=arm --no-params
+h__Fci
+h(char, int)
+h
+#
+--format=arm --no-params
+h__FUl
+h(unsigned long)
+h
+#
+--format=arm --no-params
+h__Fcl
+h(char, long)
+h
+#
+--format=arm --no-params
+h__FUs
+h(unsigned short)
+h
+#
+--format=arm --no-params
+h__Fcs
+h(char, short)
+h
+#
+--format=arm --no-params
+X__12T5__pt__3_1x
+T5<x>::X
+T5<x>::X
+#
+--format=arm --no-params
+__ct__11T5__pt__2_iFi
+T5<int>::T5(int)
+T5<int>::T5
+#
+--format=arm --no-params
+__ct__11T5__pt__2_cFi
+T5<char>::T5(int)
+T5<char>::T5
+#
+--format=arm --no-params
+h__FcT1
+h(char, char)
+h
+#
+--format=arm --no-params
+f__Ficd
+f(int, char, double)
+f
+#
+--format=arm --no-params
+__dl__17T5__pt__8_PFcPv_iSFPv
+T5<int (*)(char, void *)>::operator delete(void *) static
+T5<int (*)(char, void *)>::operator delete
+#
+--format=arm --no-params
+X__17T5__pt__8_PFcPv_i
+T5<int (*)(char, void *)>::X
+T5<int (*)(char, void *)>::X
+#
+--format=arm --no-params
+__ct__12T5__pt__3_1xFi
+T5<x>::T5(int)
+T5<x>::T5
+#
+--format=arm --no-params
+__dl__21T5__pt__11_PFiPPdPv_iSFPv
+T5<int (*)(int, double **, void *)>::operator delete(void *) static
+T5<int (*)(int, double **, void *)>::operator delete
+#
+--format=arm --no-params
+__std__foo
+global destructors keyed to foo
+global destructors keyed to foo
+#
+--format=arm --no-params
+__sti__bar
+global constructors keyed to bar
+global constructors keyed to bar
+#
+--format=arm --no-params
+f__FicdPcPFci_v
+f(int, char, double, char *, void (*)(char, int))
+f
+#
+--format=arm --no-params
+f__FicdPcPFic_v
+f(int, char, double, char *, void (*)(int, char))
+f
+#
+--format=arm --no-params
+get__2T7SFv
+T7::get(void) static
+T7::get
+#
+--format=arm --no-params
+X__21T5__pt__11_PFiPPdPv_i
+T5<int (*)(int, double **, void *)>::X
+T5<int (*)(int, double **, void *)>::X
+#
+--format=arm --no-params
+__dl__11T5__pt__2_iSFPv
+T5<int>::operator delete(void *) static
+T5<int>::operator delete
+#
+--format=arm --no-params
+__dl__11T5__pt__2_cSFPv
+T5<char>::operator delete(void *) static
+T5<char>::operator delete
+#
+--format=arm --no-params
+h__Fc
+h(char)
+h
+#
+--format=arm --no-params
+h__Fd
+h(double)
+h
+#
+--format=arm --no-params
+h__Ff
+h(float)
+h
+#
+--format=arm --no-params
+h__Fi
+h(int)
+h
+#
+--format=arm --no-params
+f__Fi
+f(int)
+f
+#
+--format=arm --no-params
+h__Fl
+h(long)
+h
+#
+--format=arm --no-params
+h__Fs
+h(short)
+h
+#
+--format=arm --no-params
+X__11T5__pt__2_c
+T5<char>::X
+T5<char>::X
+#
+--format=arm --no-params
+X__11T5__pt__2_i
+T5<int>::X
+T5<int>::X
+#
+--format=arm --no-params
+__ct__17T5__pt__8_PFcPv_iFi
+T5<int (*)(char, void *)>::T5(int)
+T5<int (*)(char, void *)>::T5
+#
+--format=arm --no-params
+f__FicdPc
+f(int, char, double, char *)
+f
+#
+--format=arm --no-params
+__nw__FUi
+operator new(unsigned int)
+operator new
+#
+--format=arm --no-params
+__ct__Q3_2T11a1bSFi
+T1::a::b::b(int) static
+T1::a::b::b
+#
+--format=arm --no-params
+__dt__Q3_2T11a1bSFi
+T1::a::b::~b(int) static
+T1::a::b::~b
+#
+--format=arm --no-params
+put__Q3_2T11a1bSFi
+T1::a::b::put(int) static
+T1::a::b::put
+#
+--format=arm --no-params
+get__Q2_2T11aSFv
+T1::a::get(void) static
+T1::a::get
+#
+--format=arm --no-params
+put__2T1SFi
+T1::put(int) static
+T1::put
+#
+--format=arm --no-params
+put__Q5_2T11a1b1c1dSFi
+T1::a::b::c::d::put(int) static
+T1::a::b::c::d::put
+#
+--format=arm --no-params
+get__Q4_2T11a1b1cSFv
+T1::a::b::c::get(void) static
+T1::a::b::c::get
+#
+--format=arm --no-params
+put__Q2_2T11aSFi
+T1::a::put(int) static
+T1::a::put
+#
+--format=arm --no-params
+put__Q4_2T11a1b1cSFi
+T1::a::b::c::put(int) static
+T1::a::b::c::put
+#
+--format=arm --no-params
+get__Q3_2T11a1bSFv
+T1::a::b::get(void) static
+T1::a::b::get
+#
+--format=arm --no-params
+get__2T1SFv
+T1::get(void) static
+T1::get
+#
+--format=arm --no-params
+get__Q5_2T11a1b1c1dSFv
+T1::a::b::c::d::get(void) static
+T1::a::b::c::d::get
+#
+--format=arm --no-params
+__dt__11T1__pt__2_cFv
+T1<char>::~T1(void)
+T1<char>::~T1
+#
+--format=arm --no-params
+__dt__12T1__pt__3_1tFv
+T1<t>::~T1(void)
+T1<t>::~T1
+#
+--format=arm --no-params
+__dl__12T1__pt__3_1tSFPv
+T1<t>::operator delete(void *) static
+T1<t>::operator delete
+#
+--format=arm --no-params
+__ct__11T1__pt__2_cFi
+T1<char>::T1(int)
+T1<char>::T1
+#
+--format=arm --no-params
+__ct__11T1__pt__2_cFv
+T1<char>::T1(void)
+T1<char>::T1
+#
+--format=arm --no-params
+__ct__12T1__pt__3_1tFi
+T1<t>::T1(int)
+T1<t>::T1
+#
+--format=arm --no-params
+__ct__12T1__pt__3_1tFv
+T1<t>::T1(void)
+T1<t>::T1
+#
+--format=arm --no-params
+__dl__11T1__pt__2_cSFPv
+T1<char>::operator delete(void *) static
+T1<char>::operator delete
+#
+--format=arm --no-params
+bar__3fooFPv
+foo::bar(void *)
+foo::bar
+#
+--format=arm --no-params
+bar__3fooCFPv
+foo::bar(void *) const
+foo::bar
+#
+--format=arm --no-params
+__eq__3fooFR3foo
+foo::operator==(foo &)
+foo::operator==
+#
+--format=arm --no-params
+__eq__3fooCFR3foo
+foo::operator==(foo &) const
+foo::operator==
+#
+--format=arm --no-params
+elem__15vector__pt__2_dFi
+vector<double>::elem(int)
+vector<double>::elem
+#
+--format=arm --no-params
+elem__15vector__pt__2_iFi
+vector<int>::elem(int)
+vector<int>::elem
+#
+--format=arm --no-params
+__ct__15vector__pt__2_dFi
+vector<double>::vector(int)
+vector<double>::vector
+#
+--format=arm --no-params
+__ct__15vector__pt__2_iFi
+vector<int>::vector(int)
+vector<int>::vector
+#
+--format=arm --no-params
+__ct__25DListNode__pt__9_R6RLabelFR6RLabelP25DListNode__pt__9_R6RLabelT2
+DListNode<RLabel &>::DListNode(RLabel &, DListNode<RLabel &> *, DListNode<RLabel &> *)
+DListNode<RLabel &>::DListNode
+#
+--format=arm --no-params
+__ct__25DListNode__pt__9_O6RLabelFO6RLabelP25DListNode__pt__9_O6RLabelT2
+DListNode<RLabel &&>::DListNode(RLabel &&, DListNode<RLabel &&> *, DListNode<RLabel &&> *)
+DListNode<RLabel &&>::DListNode
+#
+--format=arm --no-params
+bar__3fooFiT16FooBar
+foo::bar(int, int, FooBar)
+foo::bar
+#
+--format=arm --no-params
+bar__3fooFPiN51PdN37PcN211T1iN215
+foo::bar(int *, int *, int *, int *, int *, int *, double *, double *, double *, double *, char *, char *, char *, int *, int, int, int)
+foo::bar
+#
+--format=hp --no-params
+__amd__FR2T2i
+operator%=(T2 &, int)
+operator%=
+#
+--format=hp --no-params
+__adv__FR2T2i
+operator/=(T2 &, int)
+operator/=
+#
+--format=hp --no-params
+__amu__FR2T2i
+operator*=(T2 &, int)
+operator*=
+#
+--format=hp --no-params
+__ami__FR2T2i
+operator-=(T2 &, int)
+operator-=
+#
+--format=hp --no-params
+__apl__FR2T2i
+operator+=(T2 &, int)
+operator+=
+#
+--format=hp --no-params
+__nw__2T1SFUi
+T1::operator new(unsigned int) static
+T1::operator new
+#
+--format=hp --no-params
+__dl__2T1SFPv
+T1::operator delete(void *) static
+T1::operator delete
+#
+--format=hp --no-params
+put__2T7SFi
+T7::put(int) static
+T7::put
+#
+--format=hp --no-params
+h__FUc
+h(unsigned char)
+h
+#
+--format=hp --no-params
+f__Fic
+f(int, char)
+f
+#
+--format=hp --no-params
+h__FUi
+h(unsigned int)
+h
+#
+--format=hp --no-params
+h__Fci
+h(char, int)
+h
+#
+--format=hp --no-params
+h__FUl
+h(unsigned long)
+h
+#
+--format=hp --no-params
+h__Fcl
+h(char, long)
+h
+#
+--format=hp --no-params
+h__FUs
+h(unsigned short)
+h
+#
+--format=hp --no-params
+h__Fcs
+h(char, short)
+h
+#
+--format=hp --no-params
+h__FcT1
+h(char, char)
+h
+#
+--format=hp --no-params
+f__Ficd
+f(int, char, double)
+f
+#
+--format=hp --no-params
+f__FicdPcPFci_v
+f(int, char, double, char *, void (*)(char, int))
+f
+#
+--format=hp --no-params
+f__FicdPcPFic_v
+f(int, char, double, char *, void (*)(int, char))
+f
+#
+--format=hp --no-params
+get__2T7SFv
+T7::get(void) static
+T7::get
+#
+--format=hp --no-params
+h__Fc
+h(char)
+h
+#
+--format=hp --no-params
+h__Fd
+h(double)
+h
+#
+--format=hp --no-params
+h__Ff
+h(float)
+h
+#
+--format=hp --no-params
+h__Fi
+h(int)
+h
+#
+--format=hp --no-params
+f__Fi
+f(int)
+f
+#
+--format=hp --no-params
+h__Fl
+h(long)
+h
+#
+--format=hp --no-params
+h__Fs
+h(short)
+h
+#
+--format=hp --no-params
+f__FicdPc
+f(int, char, double, char *)
+f
+#
+--format=hp --no-params
+__nw__FUi
+operator new(unsigned int)
+operator new
+#
+--format=hp --no-params
+__ct__Q3_2T11a1bSFi
+T1::a::b::b(int) static
+T1::a::b::b
+#
+--format=hp --no-params
+__dt__Q3_2T11a1bSFi
+T1::a::b::~b(int) static
+T1::a::b::~b
+#
+--format=hp --no-params
+put__Q3_2T11a1bSFi
+T1::a::b::put(int) static
+T1::a::b::put
+#
+--format=hp --no-params
+get__Q2_2T11aSFv
+T1::a::get(void) static
+T1::a::get
+#
+--format=hp --no-params
+put__2T1SFi
+T1::put(int) static
+T1::put
+#
+--format=hp --no-params
+put__Q5_2T11a1b1c1dSFi
+T1::a::b::c::d::put(int) static
+T1::a::b::c::d::put
+#
+--format=hp --no-params
+get__Q4_2T11a1b1cSFv
+T1::a::b::c::get(void) static
+T1::a::b::c::get
+#
+--format=hp --no-params
+put__Q2_2T11aSFi
+T1::a::put(int) static
+T1::a::put
+#
+--format=hp --no-params
+put__Q4_2T11a1b1cSFi
+T1::a::b::c::put(int) static
+T1::a::b::c::put
+#
+--format=hp --no-params
+get__Q3_2T11a1bSFv
+T1::a::b::get(void) static
+T1::a::b::get
+#
+--format=hp --no-params
+get__2T1SFv
+T1::get(void) static
+T1::get
+#
+--format=hp --no-params
+get__Q5_2T11a1b1c1dSFv
+T1::a::b::c::d::get(void) static
+T1::a::b::c::d::get
+#
+--format=hp --no-params
+bar__3fooFPv
+foo::bar(void *)
+foo::bar
+#
+--format=hp --no-params
+bar__3fooCFPv
+foo::bar(void *) const
+foo::bar
+#
+--format=hp --no-params
+__eq__3fooFR3foo
+foo::operator==(foo &)
+foo::operator==
+#
+--format=hp --no-params
+__eq__3fooCFR3foo
+foo::operator==(foo &) const
+foo::operator==
+#
+--format=hp --no-params
+bar__3fooFiT16FooBar
+foo::bar(int, int, FooBar)
+foo::bar
+#
+--format=hp --no-params
+bar__3fooFPiN51PdN37PcN211T1iN215
+foo::bar(int *, int *, int *, int *, int *, int *, double *, double *, double *, double *, char *, char *, char *, int *, int, int, int)
+foo::bar
+#
+--format=hp --no-params
+__dt__2T5XTPFiPPdPv_i__Fv
+T5<int (*)(int, double **, void *)>::~T5(void)
+T5<int (*)(int, double **, void *)>::~T5
+#
+--format=hp --no-params
+__ct__1cFi
+c::c(int)
+c::c
+#
+--format=hp --no-params
+__dt__2T5XTi__Fv
+T5<int>::~T5(void)
+T5<int>::~T5
+#
+--format=hp --no-params
+__dt__2T5XTc__Fv
+T5<char>::~T5(void)
+T5<char>::~T5
+#
+--format=hp --no-params
+__ct__2T2Fi
+T2::T2(int)
+T2::T2
+#
+--format=hp --no-params
+__dt__2T1Fv
+T1::~T1(void)
+T1::~T1
+#
+--format=hp --no-params
+__dt__2T5XT1x__Fv
+T5<x>::~T5(void)
+T5<x>::~T5
+#
+--format=hp --no-params
+__dt__2T5XTPFcPv_i__Fv
+T5<int (*)(char, void *)>::~T5(void)
+T5<int (*)(char, void *)>::~T5
+#
+--format=hp --no-params
+__ct__2T5XTPFiPPdPv_i__Fi
+T5<int (*)(int, double **, void *)>::T5(int)
+T5<int (*)(int, double **, void *)>::T5
+#
+--format=hp --no-params
+__dl__2T5XT1x__SFPv
+T5<x>::operator delete(void *) static
+T5<x>::operator delete
+#
+--format=hp --no-params
+X__2T5XT1x
+T5<x>::X
+T5<x>::X
+#
+--format=hp --no-params
+__ct__2T5XTi__Fi
+T5<int>::T5(int)
+T5<int>::T5
+#
+--format=hp --no-params
+__ct__2T5XTc__Fi
+T5<char>::T5(int)
+T5<char>::T5
+#
+--format=hp --no-params
+__dl__2T5XTPFcPv_i__SFPv
+T5<int (*)(char, void *)>::operator delete(void *) static
+T5<int (*)(char, void *)>::operator delete
+#
+--format=hp --no-params
+X__2T5XTPFcPv_i
+T5<int (*)(char, void *)>::X
+T5<int (*)(char, void *)>::X
+#
+--format=hp --no-params
+__ct__2T5XT1x__Fi
+T5<x>::T5(int)
+T5<x>::T5
+#
+--format=hp --no-params
+__dl__2T5XTPFiPPdPv_i__SFPv
+T5<int (*)(int, double **, void *)>::operator delete(void *) static
+T5<int (*)(int, double **, void *)>::operator delete
+#
+--format=hp --no-params
+X__2T5XTPFiPPdPv_i
+T5<int (*)(int, double **, void *)>::X
+T5<int (*)(int, double **, void *)>::X
+#
+--format=hp --no-params
+__dl__2T5XTi__SFPv
+T5<int>::operator delete(void *) static
+T5<int>::operator delete
+#
+--format=hp --no-params
+__dl__2T5XTc__SFPv
+T5<char>::operator delete(void *) static
+T5<char>::operator delete
+#
+--format=hp --no-params
+X__2T5XTc
+T5<char>::X
+T5<char>::X
+#
+--format=hp --no-params
+X__2T5XTi
+T5<int>::X
+T5<int>::X
+#
+--format=hp --no-params
+__ct__2T5XTPFcPv_i__Fi
+T5<int (*)(char, void *)>::T5(int)
+T5<int (*)(char, void *)>::T5
+#
+--format=hp --no-params
+__dt__2T1XTc__Fv
+T1<char>::~T1(void)
+T1<char>::~T1
+#
+--format=hp --no-params
+__dt__2T1XT1t__Fv
+T1<t>::~T1(void)
+T1<t>::~T1
+#
+--format=hp --no-params
+__dl__2T1XT1t__SFPv
+T1<t>::operator delete(void *) static
+T1<t>::operator delete
+#
+--format=hp --no-params
+__ct__2T1XTc__Fi
+T1<char>::T1(int)
+T1<char>::T1
+#
+--format=hp --no-params
+__ct__2T1XTc__Fv
+T1<char>::T1(void)
+T1<char>::T1
+#
+--format=hp --no-params
+__ct__2T1XT1t__Fi
+T1<t>::T1(int)
+T1<t>::T1
+#
+--format=hp --no-params
+__ct__2T1XT1t__Fv
+T1<t>::T1(void)
+T1<t>::T1
+#
+--format=hp --no-params
+__dl__2T1XTc__SFPv
+T1<char>::operator delete(void *) static
+T1<char>::operator delete
+#
+--format=hp --no-params
+elem__6vectorXTd__Fi
+vector<double>::elem(int)
+vector<double>::elem
+#
+--format=hp --no-params
+elem__6vectorXTi__Fi
+vector<int>::elem(int)
+vector<int>::elem
+#
+--format=hp --no-params
+__ct__6vectorXTd__Fi
+vector<double>::vector(int)
+vector<double>::vector
+#
+--format=hp --no-params
+__ct__6vectorXTi__Fi
+vector<int>::vector(int)
+vector<int>::vector
+#
+--format=hp --no-params
+__ct__9DListNodeXTR6RLabel__FR6RLabelP9DListNodeXTR6RLabel_T2
+DListNode<RLabel &>::DListNode(RLabel &, DListNode<RLabel &> *, DListNode<RLabel &> *)
+DListNode<RLabel &>::DListNode
+#
+--format=hp --no-params
+__ct__9DListNodeXTO6RLabel__FO6RLabelP9DListNodeXTO6RLabel_T2
+DListNode<RLabel &&>::DListNode(RLabel &&, DListNode<RLabel &&> *, DListNode<RLabel &&> *)
+DListNode<RLabel &&>::DListNode
+#
+--format=hp --no-params
+elem__6vectorXTiUP34__Fi
+vector<int,34U>::elem(int)
+vector<int,34U>::elem
+#
+--format=hp --no-params
+elem__6vectorXUP2701Td__Fi
+vector<2701U,double>::elem(int)
+vector<2701U,double>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSP334__Fi
+vector<int,334>::elem(int)
+vector<int,334>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN67__Fi
+vector<int,-67>::elem(int)
+vector<int,-67>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSM__SCFPPd
+vector<int,-2147483648>::elem(double **) static const
+vector<int,-2147483648>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN67UP4000TRs__Fi
+vector<int,-67,4000U,short &>::elem(int)
+vector<int,-67,4000U,short &>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN67UP4000TOs__Fi
+vector<int,-67,4000U,short &&>::elem(int)
+vector<int,-67,4000U,short &&>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN67TRdTFPv_i__Fi
+vector<int,-67,double &,int (void *)>::elem(int)
+vector<int,-67,double &,int (void *)>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN67TOdTFPv_i__Fi
+vector<int,-67,double &&,int (void *)>::elem(int)
+vector<int,-67,double &&,int (void *)>::elem
+#
+--format=hp --no-params
+X__6vectorXTiSN67TdTPvUP5TRs
+vector<int,-67,double,void *,5U,short &>::X
+vector<int,-67,double,void *,5U,short &>::X
+#
+--format=hp --no-params
+X__6vectorXTiSN67TdTPvUP5TOs
+vector<int,-67,double,void *,5U,short &&>::X
+vector<int,-67,double,void *,5U,short &&>::X
+#
+--format=hp --no-params
+elem__6vectorXTiA3foo__Fi
+vector<int,&foo>::elem(int)
+vector<int,&foo>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiA3fooTPvA5Label__FiPPvT2
+vector<int,&foo,void *,&Label>::elem(int, void **, void **)
+vector<int,&foo,void *,&Label>::elem
+#
+--format=hp --no-params
+elem__6vectorXTiSN42A3foo__Fi
+vector<int,-42,&foo>::elem(int)
+vector<int,-42,&foo>::elem
+#
+--format=hp --no-params
+__ct__2T5XTPFcPv_i__Fi_2
+T5<int (*)(char, void *)>::T5(int)
+T5<int (*)(char, void *)>::T5
+#
+--format=hp --no-params
+__ct__2T5XTPFcPv_i__Fi_19
+T5<int (*)(char, void *)>::T5(int)
+T5<int (*)(char, void *)>::T5
+#
+--format=hp --no-params
+f__FicdPcPFci_v_34
+f(int, char, double, char *, void (*)(char, int))
+f
+#
+--format=hp --no-params
+spec__13Spec<#1,#1.*>XTiTPi_FPi
+Spec<int,int *>::spec(int *)
+Spec<int,int *>::spec
+#
+--format=hp --no-params
+spec__16Spec<#1,#1.&,#1>XTiTRiTi_FPi
+Spec<int,int &,int>::spec(int *)
+Spec<int,int &,int>::spec
+#
+--format=hp --no-params
+spec__17Spec<#1,#1.&&,#1>XTiTOiTi_FPi
+Spec<int,int &&,int>::spec(int *)
+Spec<int,int &&,int>::spec
+#
+--format=hp --no-params
+add__XTc_FcT1
+add<char>(char, char)
+add<char>
+#
+--format=hp --no-params
+add__XTcSP9A5label_FcPPlT1
+add<char,9,&label>(char, long **, char)
+add<char,9,&label>
+#
+--format=hp --no-params
+add__XTPfTFPd_f_FcT1
+add<float *,float (double *)>(char, char)
+add<float *,float (double *)>
+#
+--format=hp --no-params
+unLink__12basic_stringXTcT18string_char_traitsXTc_T9allocator_Fv
+basic_string<char,string_char_traits<char>,allocator>::unLink(void)
+basic_string<char,string_char_traits<char>,allocator>::unLink
+#
+# A regression test with no args.  This used to cause a segv.
+
+_Utf390_1__1_9223372036854775807__9223372036854775
+_Utf390_1__1_9223372036854775807__9223372036854775
+#
+--format=gnu --no-params
+call__H1Z4Test_RX01_t1C2ZX01PMX01FPX01i_vQ2X016output
+C<Test, Test::output> call<Test>(Test &)
+C<Test, Test::output> call<Test>
+#
+--format=gnu --no-params
+call__H1Z4Test_OX01_t1C2ZX01PMX01FPX01i_vQ2X016output
+C<Test, Test::output> call<Test>(Test &&)
+C<Test, Test::output> call<Test>
+#
+--format=gnu --no-params
+fn__FPQ21n1cPMQ21n1cFPQ21n1c_i
+fn(n::c *, int (n::c::*)(n::c *))
+fn
+#
+--format=gnu --no-params
+f__FGt3Bar1i2G1i
+f(Bar<2>, i)
+f
+#
+--format=gnu --no-params
+f__FGt3Bar1i21i
+f(Bar<21>, int)
+f
+#
+--format=gnu --no-params
+f__FGt3Bar1i2G4XY_t
+f(Bar<2>, XY_t)
+f
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZRCiZt2NA1Ui9_X01_i
+int foo<TA<int const &, NA<9> > >(TA<int const &, NA<9> >)
+int foo<TA<int const &, NA<9> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZOCiZt2NA1Ui9_X01_i
+int foo<TA<int const &&, NA<9> > >(TA<int const &&, NA<9> >)
+int foo<TA<int const &&, NA<9> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZcZt2NA1Ui20_X01_i
+int foo<TA<char, NA<20> > >(TA<char, NA<20> >)
+int foo<TA<char, NA<20> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZiZt8N___A___1Ui99_X01_i
+int foo<TA<int, N___A___<99> > >(TA<int, N___A___<99> >)
+int foo<TA<int, N___A___<99> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZRCiZt2NA1im1_X01_i
+int foo<TA<int const &, NA<-1> > >(TA<int const &, NA<-1> >)
+int foo<TA<int const &, NA<-1> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZRCiZt2NA1im9_X01_i
+int foo<TA<int const &, NA<-9> > >(TA<int const &, NA<-9> >)
+int foo<TA<int const &, NA<-9> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZcZt2NA1i_m20__X01_i
+int foo<TA<char, NA<-20> > >(TA<char, NA<-20> >)
+int foo<TA<char, NA<-20> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZcZt2NA1im1_X01_i
+int foo<TA<char, NA<-1> > >(TA<char, NA<-1> >)
+int foo<TA<char, NA<-1> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZiZt4N__A1im9_X01_i
+int foo<TA<int, N__A<-9> > >(TA<int, N__A<-9> >)
+int foo<TA<int, N__A<-9> > >
+#
+--format=gnu --no-params
+foo__H1Zt2TA2ZiZt4N__A1i_m99__X01_i
+int foo<TA<int, N__A<-99> > >(TA<int, N__A<-99> >)
+int foo<TA<int, N__A<-99> > >
+#
+--format=gnu --no-params
+__opi__t2TA2ZiZt4N__A1i9
+TA<int, N__A<9> >::operator int(void)
+TA<int, N__A<9> >::operator int
+#
+--format=gnu --no-params
+__opi__t2TA2ZiZt8N___A___1i_m99_
+TA<int, N___A___<-99> >::operator int(void)
+TA<int, N___A___<-99> >::operator int
+#
+--format=gnu --no-params
+foo___bar__baz_____H1Zt2TA2ZiZt8N___A___1i99_X01_i
+int foo___bar__baz___<TA<int, N___A___<99> > >(TA<int, N___A___<99> >)
+int foo___bar__baz___<TA<int, N___A___<99> > >
+#
+--format=gnu --no-params
+foo__bar___foobar_____t2TA2ZiZt8N___A___1i_m99_
+TA<int, N___A___<-99> >::foo__bar___foobar___(void)
+TA<int, N___A___<-99> >::foo__bar___foobar___
+#
+--format=gnu --no-params
+foo__bar___foobar_____t2TA2ZiZt4N__A1i9
+TA<int, N__A<9> >::foo__bar___foobar___(void)
+TA<int, N__A<9> >::foo__bar___foobar___
+#
+--format=gnu --no-params
+__tfP8sockaddr
+sockaddr * type_info function
+sockaddr * type_info function
+#
+--format=gnu --no-params
+__tfPQ25libcwt16option_event_tct1Z12burst_app_ct
+libcw::option_event_tct<burst_app_ct> * type_info function
+libcw::option_event_tct<burst_app_ct> * type_info function
+#
+--format=gnu --no-params
+__tiP8sockaddr
+sockaddr * type_info node
+sockaddr * type_info node
+#
+--format=gnu --no-params
+__tiPQ25libcwt16option_event_tct1Z12burst_app_ct
+libcw::option_event_tct<burst_app_ct> * type_info node
+libcw::option_event_tct<burst_app_ct> * type_info node
+#
+--format=gnu --no-params
+_27_GLOBAL_.N.__12burst_app_ct.app_instance
+{anonymous}::app_instance
+{anonymous}::app_instance
+#
+--format=gnu --no-params
+_26_GLOBAL_$N$_tmp_n.iilg4Gya$app_instance
+{anonymous}::app_instance
+{anonymous}::app_instance
+#
+--format=gnu-v3 --no-params
+_Z3fo5n
+fo5(__int128)
+fo5
+#
+--format=gnu-v3 --no-params
+_Z3fo5o
+fo5(unsigned __int128)
+fo5
+#
+--format=java
+_ZN4java3awt10ScrollPane7addImplEPNS0_9ComponentEPNS_4lang6ObjectEi
+java.awt.ScrollPane.addImpl(java.awt.Component, java.lang.Object, int)
+#
+--format=java
+_ZN4java3awt4geom15AffineTransform9getMatrixEP6JArrayIdE
+java.awt.geom.AffineTransform.getMatrix(double[])
+#
+--format=java
+_ZN23Mangle$Inner$InnerInner3fooEP6JArrayIPS0_IiEEdPS0_IPS0_IPS0_IPS0_IPN4java4lang6StringEEEEEPS0_IPS0_IPN6MangleEEE
+Mangle$Inner$InnerInner.foo(int[][], double, java.lang.String[][][][], Mangle[][])
+#
+--format=java
+_ZN6JArray1tEP6JArrayIPS_E
+JArray.t(JArray[])
+#
+--format=java
+_ZN4Prim1iEibcdfwPN4java4lang6StringEsx
+Prim.i(int, boolean, byte, double, float, char, java.lang.String, short, long)
+#
+--format=java
+_ZN4java4util14Map__U24_Entry11class__U24_E
+java.util.Map$Entry.class$
+#
+--format=java
+_ZN3org7eclipse3cdt5debug8internal4core5model9CVariable6sizeof$Ev
+org.eclipse.cdt.debug.internal.core.model.CVariable.sizeof()
+#
+--format=hp --no-params
+_Utf58_0_1__1_2147483647__2147483648
+_Utf58_0_1__1_2147483647__2147483648
+_Utf58_0_1__1_2147483647__2147483648
+#
+--format=gnu-v3 --no-params
+St9bad_alloc
+std::bad_alloc
+std::bad_alloc
+#
+--format=gnu-v3 --no-params
+_ZN1f1fE
+f::f
+f::f
+#
+--format=gnu-v3 --no-params
+_Z1fv
+f()
+f
+#
+--format=gnu-v3 --no-params
+_Z1fi
+f(int)
+f
+#
+--format=gnu-v3 --no-params
+_Z3foo3bar
+foo(bar)
+foo
+#
+--format=gnu-v3 --no-params
+_Zrm1XS_
+operator%(X, X)
+operator%
+#
+--format=gnu-v3 --no-params
+_ZplR1XS0_
+operator+(X&, X&)
+operator+
+#
+--format=gnu-v3 --no-params
+_ZlsRK1XS1_
+operator<<(X const&, X const&)
+operator<<
+#
+--format=gnu-v3 --no-params
+_ZN3FooIA4_iE3barE
+Foo<int [4]>::bar
+Foo<int [4]>::bar
+#
+--format=gnu-v3 --no-params
+_Z1fIiEvi
+void f<int>(int)
+f<int>
+#
+--format=gnu-v3 --no-params
+_Z5firstI3DuoEvS0_
+void first<Duo>(Duo)
+first<Duo>
+#
+--format=gnu-v3 --no-params
+_Z5firstI3DuoEvT_
+void first<Duo>(Duo)
+first<Duo>
+#
+--format=gnu-v3 --no-params
+_Z3fooIiFvdEiEvv
+void foo<int, void (double), int>()
+foo<int, void (double), int>
+#
+--format=gnu-v3 --no-params
+_Z1fIFvvEEvv
+void f<void ()>()
+f<void ()>
+#
+--format=gnu-v3 --no-params
+_ZN1N1fE
+N::f
+N::f
+#
+--format=gnu-v3 --no-params
+_ZN6System5Sound4beepEv
+System::Sound::beep()
+System::Sound::beep
+#
+--format=gnu-v3 --no-params
+_ZN5Arena5levelE
+Arena::level
+Arena::level
+#
+--format=gnu-v3 --no-params
+_ZN5StackIiiE5levelE
+Stack<int, int>::level
+Stack<int, int>::level
+#
+--format=gnu-v3 --no-params
+_Z1fI1XEvPVN1AIT_E1TE
+void f<X>(A<X>::T volatile*)
+f<X>
+#
+--format=gnu-v3 --no-params
+_ZngILi42EEvN1AIXplT_Li2EEE1TE
+void operator-<42>(A<(42)+(2)>::T)
+operator-<42>
+#
+--format=gnu-v3 --no-params
+_Z4makeI7FactoryiET_IT0_Ev
+Factory<int> make<Factory, int>()
+make<Factory, int>
+#
+--format=gnu-v3 --no-params
+_Z4makeI7FactoryiET_IT0_Ev
+Factory<int> make<Factory, int>()
+make<Factory, int>
+#
+--format=gnu-v3 --no-params
+_Z3foo5Hello5WorldS0_S_
+foo(Hello, World, World, Hello)
+foo
+#
+--format=gnu-v3 --no-params
+_Z3fooPM2ABi
+foo(int AB::**)
+foo
+#
+--format=gnu-v3 --no-params
+_ZlsRSoRKSs
+operator<<(std::ostream&, std::string const&)
+operator<<
+#
+--format=gnu-v3 --no-params
+_ZTI7a_class
+typeinfo for a_class
+typeinfo for a_class
+#
+--format=gnu-v3 --no-params
+U4_farrVKPi
+int* const volatile restrict _far
+int* const volatile restrict _far
+# 
+--format=gnu-v3 --no-params
+_Z3fooILi2EEvRAplT_Li1E_i
+void foo<2>(int (&) [(2)+(1)])
+foo<2>
+#
+--format=gnu-v3 --no-params
+_Z3fooILi2EEvOAplT_Li1E_i
+void foo<2>(int (&&) [(2)+(1)])
+foo<2>
+# 
+--format=gnu-v3 --no-params
+_Z1fM1AKFvvE
+f(void (A::*)() const)
+f
+#
+--format=gnu-v3 --no-params
+_Z3fooc
+foo(char)
+foo
+#
+--format=gnu-v3 --no-params
+_Z2f0u8char16_t
+f0(char16_t)
+f0
+#
+--format=gnu-v3 --no-params
+_Z2f0Pu8char16_t
+f0(char16_t*)
+f0
+#
+--format=gnu-v3 --no-params
+_Z2f0u8char32_t
+f0(char32_t)
+f0
+#
+--format=gnu-v3 --no-params
+_Z2f0Pu8char32_t
+f0(char32_t*)
+f0
+#
+--format=gnu-v3 --no-params
+2CBIL_Z3foocEE
+CB<foo(char)>
+CB<foo(char)>
+#
+--format=gnu-v3 --no-params
+2CBIL_Z7IsEmptyEE
+CB<IsEmpty>
+CB<IsEmpty>
+#
+--format=gnu-v3 --no-params
+_ZZN1N1fEiE1p
+N::f(int)::p
+N::f(int)::p
+#
+--format=gnu-v3 --no-params
+_ZZN1N1fEiEs
+N::f(int)::string literal
+N::f(int)::string literal
+# 
+--format=gnu-v3 --no-params
+_Z1fPFvvEM1SFvvE
+f(void (*)(), void (S::*)())
+f
+#
+--format=gnu-v3 --no-params
+_ZN1N1TIiiE2mfES0_IddE
+N::T<int, int>::mf(N::T<double, double>)
+N::T<int, int>::mf
+# 
+--format=gnu-v3 --no-params
+_ZSt5state
+std::state
+std::state
+# 
+--format=gnu-v3 --no-params
+_ZNSt3_In4wardE
+std::_In::ward
+std::_In::ward
+#
+--format=gnu-v3 --no-params
+_Z1fKPFiiE
+f(int (* const)(int))
+f
+#
+--format=gnu-v3 --no-params
+_Z1fAszL_ZZNK1N1A1fEvE3foo_0E_i
+f(int [sizeof (N::A::f() const::foo)])
+f
+#
+--format=gnu-v3 --no-params
+_Z1fA37_iPS_
+f(int [37], int (*) [37])
+f
+#
+--format=gnu-v3 --no-params
+_Z1fM1AFivEPS0_
+f(int (A::*)(), int (*)())
+f
+#
+--format=gnu-v3 --no-params
+_Z1fPFPA1_ivE
+f(int (*(*)()) [1])
+f
+#
+--format=gnu-v3 --no-params
+_Z1fPKM1AFivE
+f(int (A::* const*)())
+f
+#
+--format=gnu-v3 --no-params
+_Z1jM1AFivEPS1_
+j(int (A::*)(), int (A::**)())
+j
+#
+--format=gnu-v3 --no-params
+_Z1sPA37_iPS0_
+s(int (*) [37], int (**) [37])
+s
+#
+--format=gnu-v3 --no-params
+_Z3fooA30_A_i
+foo(int [30][])
+foo
+#
+--format=gnu-v3 --no-params
+_Z3kooPA28_A30_i
+koo(int (*) [28][30])
+koo
+#
+--format=gnu-v3 --no-params
+_ZlsRKU3fooU4bart1XS0_
+operator<<(X bart foo const&, X bart)
+operator<<
+#
+--format=gnu-v3 --no-params
+_ZlsRKU3fooU4bart1XS2_
+operator<<(X bart foo const&, X bart foo const)
+operator<<
+#
+--format=gnu-v3 --no-params
+_Z1fM1AKFivE
+f(int (A::*)() const)
+f
+#
+--format=gnu-v3 --no-params
+_Z3absILi11EEvv
+void abs<11>()
+abs<11>
+#
+--format=gnu-v3 --no-params
+_ZN1AIfEcvT_IiEEv
+A<float>::operator int<int>()
+A<float>::operator int<int>
+#
+--format=gnu-v3 --no-params
+_ZN12libcw_app_ct10add_optionIS_EEvMT_FvPKcES3_cS3_S3_
+void libcw_app_ct::add_option<libcw_app_ct>(void (libcw_app_ct::*)(char const*), char const*, char, char const*, char const*)
+libcw_app_ct::add_option<libcw_app_ct>
+#
+--format=gnu-v3 --no-params
+_ZGVN5libcw24_GLOBAL__N_cbll.cc0ZhUKa23compiler_bug_workaroundISt6vectorINS_13omanip_id_tctINS_5debug32memblk_types_manipulator_data_ctEEESaIS6_EEE3idsE
+guard variable for libcw::(anonymous namespace)::compiler_bug_workaround<std::vector<libcw::omanip_id_tct<libcw::debug::memblk_types_manipulator_data_ct>, std::allocator<libcw::omanip_id_tct<libcw::debug::memblk_types_manipulator_data_ct> > > >::ids
+guard variable for libcw::(anonymous namespace)::compiler_bug_workaround<std::vector<libcw::omanip_id_tct<libcw::debug::memblk_types_manipulator_data_ct>, std::allocator<libcw::omanip_id_tct<libcw::debug::memblk_types_manipulator_data_ct> > > >::ids
+#
+--format=gnu-v3 --no-params
+_ZN5libcw5debug13cwprint_usingINS_9_private_12GlobalObjectEEENS0_17cwprint_using_tctIT_EERKS5_MS5_KFvRSt7ostreamE
+libcw::debug::cwprint_using_tct<libcw::_private_::GlobalObject> libcw::debug::cwprint_using<libcw::_private_::GlobalObject>(libcw::_private_::GlobalObject const&, void (libcw::_private_::GlobalObject::*)(std::ostream&) const)
+libcw::debug::cwprint_using<libcw::_private_::GlobalObject>
+#
+--format=gnu-v3 --no-params
+_ZNKSt14priority_queueIP27timer_event_request_base_ctSt5dequeIS1_SaIS1_EE13timer_greaterE3topEv
+std::priority_queue<timer_event_request_base_ct*, std::deque<timer_event_request_base_ct*, std::allocator<timer_event_request_base_ct*> >, timer_greater>::top() const
+std::priority_queue<timer_event_request_base_ct*, std::deque<timer_event_request_base_ct*, std::allocator<timer_event_request_base_ct*> >, timer_greater>::top
+#
+--format=gnu-v3 --no-params
+_ZNKSt15_Deque_iteratorIP15memory_block_stRKS1_PS2_EeqERKS5_
+std::_Deque_iterator<memory_block_st*, memory_block_st* const&, memory_block_st* const*>::operator==(std::_Deque_iterator<memory_block_st*, memory_block_st* const&, memory_block_st* const*> const&) const
+std::_Deque_iterator<memory_block_st*, memory_block_st* const&, memory_block_st* const*>::operator==
+#
+--format=gnu-v3 --no-params
+_ZNKSt17__normal_iteratorIPK6optionSt6vectorIS0_SaIS0_EEEmiERKS6_
+std::__normal_iterator<option const*, std::vector<option, std::allocator<option> > >::operator-(std::__normal_iterator<option const*, std::vector<option, std::allocator<option> > > const&) const
+std::__normal_iterator<option const*, std::vector<option, std::allocator<option> > >::operator-
+#
+--format=gnu-v3 --no-params
+_ZNSbIcSt11char_traitsIcEN5libcw5debug27no_alloc_checking_allocatorEE12_S_constructIPcEES6_T_S7_RKS3_
+char* std::basic_string<char, std::char_traits<char>, libcw::debug::no_alloc_checking_allocator>::_S_construct<char*>(char*, char*, libcw::debug::no_alloc_checking_allocator const&)
+std::basic_string<char, std::char_traits<char>, libcw::debug::no_alloc_checking_allocator>::_S_construct<char*>
+#
+--format=gnu-v3 --no-params
+_Z1fI1APS0_PKS0_EvT_T0_T1_PA4_S3_M1CS8_
+void f<A, A*, A const*>(A, A*, A const*, A const* (*) [4], A const* (* C::*) [4])
+f<A, A*, A const*>
+#
+--format=gnu-v3 --no-params
+_Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_
+foo(int, int*, int**, int***, int****, int*****, int******, int*******, int********, int*********, int**********, int***********, int************, int*************, int**************, int***************)
+foo
+#
+--format=gnu-v3 --no-params
+_ZSt1BISt1DIP1ARKS2_PS3_ES0_IS2_RS2_PS2_ES2_ET0_T_SB_SA_PT1_
+std::D<A*, A*&, A**> std::B<std::D<A*, A* const&, A* const*>, std::D<A*, A*&, A**>, A*>(std::D<A*, A* const&, A* const*>, std::D<A*, A* const&, A* const*>, std::D<A*, A*&, A**>, A**)
+std::B<std::D<A*, A* const&, A* const*>, std::D<A*, A*&, A**>, A*>
+#
+--format=gnu-v3 --no-params
+_X11TransParseAddress
+_X11TransParseAddress
+_X11TransParseAddress
+#
+--format=gnu-v3 --no-params
+_ZNSt13_Alloc_traitsISbIcSt18string_char_traitsIcEN5libcw5debug9_private_17allocator_adaptorIcSt24__default_alloc_templateILb0ELi327664EELb1EEEENS5_IS9_S7_Lb1EEEE15_S_instancelessE
+std::_Alloc_traits<std::basic_string<char, std::string_char_traits<char>, libcw::debug::_private_::allocator_adaptor<char, std::__default_alloc_template<false, 327664>, true> >, libcw::debug::_private_::allocator_adaptor<std::basic_string<char, std::string_char_traits<char>, libcw::debug::_private_::allocator_adaptor<char, std::__default_alloc_template<false, 327664>, true> >, std::__default_alloc_template<false, 327664>, true> >::_S_instanceless
+std::_Alloc_traits<std::basic_string<char, std::string_char_traits<char>, libcw::debug::_private_::allocator_adaptor<char, std::__default_alloc_template<false, 327664>, true> >, libcw::debug::_private_::allocator_adaptor<std::basic_string<char, std::string_char_traits<char>, libcw::debug::_private_::allocator_adaptor<char, std::__default_alloc_template<false, 327664>, true> >, std::__default_alloc_template<false, 327664>, true> >::_S_instanceless
+#
+--format=gnu-v3 --no-params
+_GLOBAL__I__Z2fnv
+global constructors keyed to fn()
+global constructors keyed to fn()
+#
+--format=gnu-v3 --no-params
+_Z1rM1GFivEMS_KFivES_M1HFivES1_4whatIKS_E5what2IS8_ES3_
+r(int (G::*)(), int (G::*)() const, G, int (H::*)(), int (G::*)(), what<G const>, what2<G const>, int (G::*)() const)
+r
+#
+# This is from the gdb testsuite gdb.cp/cplusfuncs.exp.
+--format=gnu-v3 --no-params
+_Z10hairyfunc5PFPFilEPcE
+hairyfunc5(int (*(*)(char*))(long))
+hairyfunc5
+#
+# This is from gcc PR 8861
+--format=gnu-v3 --no-params
+_Z1fILi1ELc120EEv1AIXplT_cviLd810000000000000000703DAD7A370C5EEE
+void f<1, (char)120>(A<(1)+((int)((double)[810000000000000000703DAD7A370C5]))>)
+f<1, (char)120>
+#
+# This is also from gcc PR 8861
+--format=gnu-v3 --no-params
+_Z1fILi1EEv1AIXplT_cvingLf3f800000EEE
+void f<1>(A<(1)+((int)(-((float)[3f800000])))>)
+f<1>
+#
+# This is from a libstdc++ debug mode patch.
+--format=gnu-v3 --no-params
+_ZNK11__gnu_debug16_Error_formatter14_M_format_wordImEEvPciPKcT_
+void __gnu_debug::_Error_formatter::_M_format_word<unsigned long>(char*, int, char const*, unsigned long) const
+__gnu_debug::_Error_formatter::_M_format_word<unsigned long>
+#
+# The new demangler used to core dump on this.
+--format=gnu-v3 --no-params
+_ZSt18uninitialized_copyIN9__gnu_cxx17__normal_iteratorIPSt4pairISsPFbP6sqlitePPcEESt6vectorIS9_SaIS9_EEEESE_ET0_T_SG_SF_
+__gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > > std::uninitialized_copy<__gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >, __gnu_cxx::__normal_iterator<std::pai [...]
+std::uninitialized_copy<__gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > >, __gnu_cxx::__normal_iterator<std::pair<std::string, bool (*)(sqlite*, char**)>*, std::vector<std::pair<std::string, bool (*)(sqlite*, char**)>, std::allocator<std::pair<std::string, bool (*)(sqlite*, char**)> > > > >
+#
+# The new demangler used to fail on this.
+--format=gnu-v3 --no-params
+_Z1fP1cIPFiiEE
+f(c<int (*)(int)>*)
+f
+#
+# Wrap expressions using '>' in an extra layer of parens to avoid
+# confusion with the '>' which ends the template parameters.
+--format=gnu-v3 --no-params
+_Z4dep9ILi3EEvP3fooIXgtT_Li2EEE
+void dep9<3>(foo<((3)>(2))>*)
+dep9<3>
+#
+# Watch out for templated version of `operator<'--it needs an extra
+# space.
+--format=gnu-v3 --no-params
+_ZStltI9file_pathSsEbRKSt4pairIT_T0_ES6_
+bool std::operator< <file_path, std::string>(std::pair<file_path, std::string> const&, std::pair<file_path, std::string> const&)
+std::operator< <file_path, std::string>
+#
+# More hairy qualifier handling.
+--format=gnu-v3 --no-params
+_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE
+hairyfunc(int (* const (X::** (* restrict (* volatile* (Y::*)(int) const)(char*)) [2])(long) const) [3])
+hairyfunc
+#
+# Check that negative numbers are handled correctly.
+--format=gnu-v3 --no-params
+_Z1fILin1EEvv
+void f<-1>()
+f<-1>
+#
+# Check a destructor of a standard substitution.
+--format=gnu-v3 --no-params
+_ZNSdD0Ev
+std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()
+std::basic_iostream<char, std::char_traits<char> >::~basic_iostream
+#
+# Another case where we got member function qualifiers wrong.
+--format=gnu-v3 --no-params
+_ZNK15nsBaseHashtableI15nsUint32HashKey8nsCOMPtrI4IFooEPS2_E13EnumerateReadEPF15PLDHashOperatorRKjS4_PvES9_
+nsBaseHashtable<nsUint32HashKey, nsCOMPtr<IFoo>, IFoo*>::EnumerateRead(PLDHashOperator (*)(unsigned int const&, IFoo*, void*), void*) const
+nsBaseHashtable<nsUint32HashKey, nsCOMPtr<IFoo>, IFoo*>::EnumerateRead
+#
+# Another member function qualifier test case, when the member function
+# returns a pointer to function.
+--format=gnu-v3 --no-params
+_ZNK1C1fIiEEPFivEv
+int (*C::f<int>() const)()
+C::f<int>
+#
+# Another case where we got member function qualifiers wrong.
+--format=gnu-v3 --no-params
+_ZZ3BBdI3FooEvvENK3Fob3FabEv
+void BBd<Foo>()::Fob::Fab() const
+void BBd<Foo>()::Fob::Fab
+#
+# The same idea one level deeper.
+--format=gnu-v3 --no-params
+_ZZZ3BBdI3FooEvvENK3Fob3FabEvENK3Gob3GabEv
+void BBd<Foo>()::Fob::Fab() const::Gob::Gab() const
+void BBd<Foo>()::Fob::Fab() const::Gob::Gab
+#
+# Yet another member function qualifier problem.
+--format=gnu-v3 --no-params
+_ZNK5boost6spirit5matchI13rcs_deltatextEcvMNS0_4impl5dummyEFvvEEv
+boost::spirit::match<rcs_deltatext>::operator void (boost::spirit::impl::dummy::*)()() const
+boost::spirit::match<rcs_deltatext>::operator void (boost::spirit::impl::dummy::*)()
+#
+# Multi-dimensional arrays with qualifiers on the inner dimensions.
+--format=gnu-v3 --no-params
+_Z3fooIA6_KiEvA9_KT_rVPrS4_
+void foo<int const [6]>(int const [9][6], int restrict const (* volatile restrict) [9][6])
+foo<int const [6]>
+#
+# From PR libstdc++/12736
+--format=gnu-v3 --no-params
+_Z3fooIA3_iEvRKT_
+void foo<int [3]>(int const (&) [3])
+foo<int [3]>
+#
+# Related to PR libstdc++/12736
+--format=gnu-v3 --no-params
+_Z3fooIPA3_iEvRKT_
+void foo<int (*) [3]>(int (* const&) [3])
+foo<int (*) [3]>
+#
+# This used to crash the demangler--PR 16240
+--format=gnu-v3 --no-params
+_ZN13PatternDriver23StringScalarDeleteValueC1ERKNS_25ConflateStringScalarValueERKNS_25AbstractStringScalarValueERKNS_12TemplateEnumINS_12pdcomplementELZNS_16complement_namesEELZNS_14COMPLEMENTENUMEEEE
+PatternDriver::StringScalarDeleteValue::StringScalarDeleteValue(PatternDriver::ConflateStringScalarValue const&, PatternDriver::AbstractStringScalarValue const&, PatternDriver::TemplateEnum<PatternDriver::pdcomplement, PatternDriver::complement_names, PatternDriver::COMPLEMENTENUM> const&)
+PatternDriver::StringScalarDeleteValue::StringScalarDeleteValue
+#
+# This used to cause the demangler to walk into undefined memory--PR 22268
+--format=gnu-v3 --no-params
+ALsetchannels
+ALsetchannels
+ALsetchannels
+# Test GNU V3 constructor and destructor identification.
+# 0 means it is not a constructor/destructor.
+# Other integers correspond to enum gnu_v3_{c,d}tor_kinds in demangle.h.
+--is-v3-ctor
+_GLOBAL__I__Z2fnv
+0
+#
+--is-v3-dtor
+_GLOBAL__I__Z2fnv
+0
+#
+--is-v3-ctor
+_ZNSdC1Ev
+1
+#
+--is-v3-dtor
+_ZNSdC1Ev
+0
+#
+--is-v3-ctor
+_ZNSdD0Ev
+0
+#
+--is-v3-dtor
+_ZNSdD0Ev
+1
+#
+--is-v3-ctor
+_ZNSdC2Ev
+2
+#
+--is-v3-dtor
+_ZNSdC2Ev
+0
+#
+--is-v3-ctor
+_ZNSdD1Ev
+0
+#
+--is-v3-dtor
+_ZNSdD1Ev
+2
+#
+# This caused an infinite loop.
+#
+# This is generated by an EDG compiler (kcc 4.0).  To demangle it
+# correctly, I believe that we have to understand that the J37J deep
+# in the string somehow refers back to the type starting 37 characters
+# in from some starting point, so that it winds up being the type
+# starting with 41THandle....  However, lacking a spec for EDG
+# demangling, it's hard to implement this.
+#
+# In the meantime, this symbol can be successfully demangled in GNU
+# mode.  Of course the result is more or less nonsense, but an older
+# version of g++ would indeed generate this mangled name given the
+# appropriate input, so the demangling is correct.
+--format=auto --no-params
+__CPR212____ct__Q3_3std141list__tm__128_Q2_3edm41THandle__tm__26_Q2_4emid15EMparticleChunkQ2_3std68allocator__tm__51_Q2_3edmJ37J14const_iteratorFRCQ3_3std18list__tm__7_Z1ZZ2Z8iterator
+_Z1ZZ2Z::__CPR212____ct__Q3_3std141list__tm__128_Q2_3edm41THandle__tm__26_Q2_4emid15EMparticleChunkQ2_3std68allocator__tm__51_Q2_3edmJ37J14const_iteratorFRCQ3_3std18list__tm(iterator)
+_Z1ZZ2Z::__CPR212____ct__Q3_3std141list__tm__128_Q2_3edm41THandle__tm__26_Q2_4emid15EMparticleChunkQ2_3std68allocator__tm__51_Q2_3edmJ37J14const_iteratorFRCQ3_3std18list__tm
+#
+# This used to cause a crash. It doesn't follow the C++ encoding so
+# the demangled name should be identical to the original symbol name.
+--format=auto --no-params
+_test_array__L_1__B23b___clean.6
+_test_array__L_1__B23b___clean.6
+_test_array__L_1__B23b___clean.6
+#
+--format=java
+_ZGAN4java4lang5Class7forNameEPNS0_6StringE
+hidden alias for java.lang.Class.forName(java.lang.String)
+#
+# Test cases to verify encoding that determines if a return type is present
+# Related to PR9861
+--format=java
+_ZN4java4lang4Math4acosEJdd
+java.lang.Math.acos(double)double
+#
+--format=auto
+_ZN4java4lang4Math4acosEJdd
+double java::lang::Math::acos(double)
+#
+--format=auto
+_ZN4java4lang4Math4acosEJvd
+void java::lang::Math::acos(double)
+#
+--format=auto --ret-postfix
+_ZN4java4lang4Math4acosEJdd
+java::lang::Math::acos(double)double
+#
+--format=gnu-v3 --no-params --ret-postfix
+_Z4makeI7FactoryiET_IT0_Ev
+make<Factory, int>()Factory<int>
+make<Factory, int>
+#
+# From PR 28797
+--format=auto --no-params
+_Z1fM1AKiPKS1_
+f(int const A::*, int const A::* const*)
+f
+# This used to cause a core dump in the demangler -- PR 29176
+--format=auto --no-params
+SASDASDFASDF_sdfsdf
+SASDASDFASDF_sdfsdf
+SASDASDFASDF_sdfsdf
+# These are all cases of invalid manglings where the demangler would read
+# past the end of the string.
+# d_name wasn't honouring a NULL from d_substitution
+--format=gnu-v3
+_ZSA
+_ZSA
+# d_expr_primary wasn't honouring NULL from cplus_demangle_mangled_name
+--format=gnu-v3
+_ZN1fIL_
+_ZN1fIL_
+# d_operator_name was taking two characters in a row
+--format=gnu-v3
+_Za
+_Za
+# d_prefix wasn't honouring NULL from d_substitution
+--format=gnu-v3
+_ZNSA
+_ZNSA
+# d_prefix wasn't honouring NULL from d_template_param
+--format=gnu-v3
+_ZNT
+_ZNT
+# Dereferencing NULL in d_pointer_to_member_type
+--format=gnu-v3
+_Z1aMark
+_Z1aMark
+# <local-source-name> test 1
+--format=gnu-v3
+_ZL3foo_2
+foo
+# <local-source-name> test 2
+--format=gnu-v3
+_ZZL3foo_2vE4var1
+foo()::var1
+# <local-source-name> test 3
+--format=gnu-v3
+_ZZL3foo_2vE4var1_0
+foo()::var1
+# <local-source-name> test 4
+--format=gnu-v3
+_ZZN7myspaceL3foo_1EvEN11localstruct1fEZNS_3fooEvE16otherlocalstruct
+myspace::foo()::localstruct::f(myspace::foo()::otherlocalstruct)
+# Java resource name
+--format=gnu-v3
+_ZGr32_java$Sutil$Siso4217$_properties
+java resource java/util/iso4217.properties
+# decltype/param placeholder test
+--format=gnu-v3
+_Z3addIidEDTplfp_fp0_ET_T0_
+decltype ({parm#1}+{parm#2}) add<int, double>(int, double)
+# decltype scope test
+--format=gnu-v3
+_Z1fI1SENDtfp_E4typeET_
+decltype ({parm#1})::type f<S>(S)
+# decltype/fn call test
+--format=gnu-v3
+_Z4add3IidEDTclL_Z1gEfp_fp0_EET_T0_
+decltype (g({parm#1}, {parm#2})) add3<int, double>(int, double)
+# 'this' test
+--format=gnu-v3
+_ZN1A1fIiEEDTcldtdtdefpT1b1fIT_EEEv
+decltype ((((*this).b).(f<int>))()) A::f<int>()
+# new (2008) built in types test
+--format=gnu-v3
+_Z1fDfDdDeDhDsDi
+f(decimal32, decimal64, decimal128, half, char16_t, char32_t)
+# pack expansion test
+--format=gnu-v3
+_Z1fIIPiPfPdEEvDpT_
+void f<int*, float*, double*>(int*, float*, double*)
+# '.' test
+--format=gnu-v3
+_Z1hI1AIiEdEDTcldtfp_1gIT0_EEET_S2_
+decltype (({parm#1}.(g<double>))()) h<A<int>, double>(A<int>, double)
+# test for typed function in decltype
+--format=gnu-v3
+_ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_
+decltype ({parm#1}+(x())) A<int>::j<int>(int)
+# typed function in decltype with an argument list
+--format=gnu-v3
+_Z1tIlEDTplcvT_Li5EclL_Z1qsELi6EEEv
+decltype (((long)(5))+(q(6))) t<long>()
+# test for expansion of function parameter pack
+--format=gnu-v3
+_Z1gIJidEEDTclL_Z1fEspplfp_Li1EEEDpT_
+decltype (f(({parm#1}+(1))...)) g<int, double>(int, double)
+# lambda tests
+--format=gnu-v3
+_ZZ1giENKUlvE_clEv
+g(int)::{lambda()#1}::operator()() const
+--format=gnu-v3
+_Z4algoIZ1giEUlvE0_EiT_
+int algo<g(int)::{lambda()#2}>(g(int)::{lambda()#2})
+--format=gnu-v3
+_ZZN1S1fEiiEd0_NKUlvE0_clEv
+S::f(int, int)::{default arg#2}::{lambda()#2}::operator()() const
+--format=gnu-v3
+_ZNK1SIiE1xMUlvE1_clEv
+S<int>::x::{lambda()#3}::operator()() const
+--format=gnu-v3
+_ZN8functionC1IZN1CIiE4testES_Ed_UliE_EET_
+function::function<C<int>::test(function)::{default arg#1}::{lambda(int)#1}>(C<int>::test(function)::{default arg#1}::{lambda(int)#1})
+--format=gnu-v3
+_Z1fN1SUt_E
+f(S::{unnamed type#1})
+--format=gnu-v3
+_Z1fDv32_f
+f(float __vector(32))
+--format=gnu-v3
+_Z1fIfLi4EEvDv_T0__T_
+void f<float, 4>(float __vector(4))
+--format=gnu-v3
+_Z1fI1AEDTclonplfp_fp_EET_
+decltype ((operator+)({parm#1}, {parm#1})) f<A>(A)
+--format=gnu-v3
+_Z1hI1AEDTcldtfp_miEET_
+decltype (({parm#1}.(operator-))()) h<A>(A)
+--format=gnu-v3
+_Z1fDn
+f(decltype(nullptr))
+--format=gnu-v3
+_Z1fIRiEvOT_b
+void f<int&>(int&, bool)
+--format=gnu-v3
+_ZN5aaaaa6bbbbbb5cccccIN23ddddddddddddddddddddddd3eeeENS2_4ffff16ggggggggggggggggENS0_9hhhhhhhhhES6_S6_S6_S6_S6_S6_S6_EE
+aaaaa::bbbbbb::ccccc<ddddddddddddddddddddddd::eee, ddddddddddddddddddddddd::ffff::gggggggggggggggg, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh, aaaaa::bbbbbb::hhhhhhhhh>
+--format=gnu-v3
+_Z5outerIsEcPFilE
+char outer<short>(int (*)(long))
+--format=gnu-v3
+_Z5outerPFsiEl
+outer(short (*)(int), long)
+--format=gnu-v3
+_Z6outer2IsEPFilES1_
+int (*outer2<short>(int (*)(long)))(long)
+--format=gnu-v3 --ret-postfix
+_Z5outerIsEcPFilE
+outer<short>(int (*)(long))char
+--format=gnu-v3 --ret-postfix
+_Z5outerPFsiEl
+outer(short (*)(int), long)
+--format=gnu-v3 --ret-postfix
+_Z6outer2IsEPFilES1_
+outer2<short>(int (*)(long))int (*)(long)
+--format=gnu-v3 --ret-drop
+_Z5outerIsEcPFilE
+outer<short>(int (*)(long))
+--format=gnu-v3 --ret-drop
+_Z5outerPFsiEl
+outer(short (*)(int), long)
+--format=gnu-v3 --ret-drop
+_Z6outer2IsEPFilES1_
+outer2<short>(int (*)(long))
+#
+--format=gnu-v3 --no-params
+_ZN1KIXadL_ZN1S1mEiEEE1fEv
+K<&S::m>::f()
+K<&S::m>::f
+--format=gnu-v3
+_ZN1KILi1EXadL_ZN1S1mEiEEE1fEv
+K<1, &S::m>::f()
+# Here the `(int)' argument list of `S::m' is already removed.
+--format=gnu-v3
+_ZN1KILi1EXadL_ZN1S1mEEEE1fEv
+K<1, &S::m>::f()
+#
+# Used to crash -- binutils PR 13030.
+--format=gnu-v3
+_ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_
+_ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_
+# A pack expansion is substitutable.
+--format=gnu-v3
+_Z1fIJiEiEv1AIJDpT_EET0_S4_
+void f<int, int>(A<int>, int, int)
+# So is decltype.
+--format=gnu-v3
+_Z1fIiiEDTcvT__EET0_S2_
+decltype ((int)()) f<int, int>(int, int)
+# And vector.
+--format=gnu-v3
+_Z1fDv4_iS_
+f(int __vector(4), int __vector(4))
+--format=gnu-v3
+_Z2f1Ii1AEDTdsfp_fp0_ET0_MS2_T_
+decltype ({parm#1}.*{parm#2}) f1<int, A>(A, int A::*)
+--format=gnu-v3
+_Z2f2IiEDTquL_Z1bEfp_trET_
+decltype (b?{parm#1} : (throw)) f2<int>(int)
+--format=gnu-v3
+_Z6check1IiEvP6helperIXsznw_T_EEE
+void check1<int>(helper<sizeof (new int)>*)
+--format=gnu-v3
+_Z6check2IiEvP6helperIXszgsnw_T_piEEE
+void check2<int>(helper<sizeof (::new int())>*)
+--format=gnu-v3
+_Z6check3IiEvP6helperIXsznwadL_Z1iE_T_piLi1EEEE
+void check3<int>(helper<sizeof (new (&i) int(1))>*)
+--format=gnu-v3
+_Z6check4IiEvP6helperIXszna_A1_T_EEE
+void check4<int>(helper<sizeof (new int [1])>*)
+--format=gnu-v3
+_Z6check5IiEvP6helperIXszna_A1_T_piEEE
+void check5<int>(helper<sizeof (new int [1]())>*)
+--format=gnu-v3
+_Z1fIiEDTcmgsdlfp_psfp_EPT_
+decltype ((::delete {parm#1}),(+{parm#1})) f<int>(int*)
+--format=gnu-v3
+_Z1fIiEDTcmdafp_psfp_EPT_
+decltype ((delete[] {parm#1}),(+{parm#1})) f<int>(int*)
+--format=gnu-v3
+_ZN1AdlEPv
+A::operator delete(void*)
+--format=gnu-v3
+_Z2f1IiEDTppfp_ET_
+decltype ({parm#1}++) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTpp_fp_ET_
+decltype (++{parm#1}) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTcl1gfp_ilEEET_
+decltype (g({parm#1}, {})) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTnw_T_ilEES0_
+decltype (new int{}) f1<int>(int)
+--format=gnu-v3
+_Zli2_wPKc
+operator"" _w(char const*)
+--format=gnu-v3
+_Z1fIiEDTnw_Dapifp_EET_
+decltype (new auto({parm#1})) f<int>(int)
+--format=gnu-v3
+_Z1fIiERDaRKT_S1_
+auto& f<int>(int const&, int)
+--format=gnu-v3
+_Z1gILi1EEvR1AIXT_EER1BIXscbT_EE
+void g<1>(A<1>&, B<static_cast<bool>(1)>&)
+--format=gnu-v3
+_ZNKSt7complexIiE4realB5cxx11Ev
+std::complex<int>::real[abi:cxx11]() const
+#
+# Some more crashes revealed by fuzz-testing:
+# Check for NULL pointer when demangling trinary operators
+--format=gnu-v3
+_Z1fAv32_f
+_Z1fAv32_f
+# Do not overflow when decoding identifier length
+--format=gnu-v3
+_Z11111111111
+_Z11111111111
+# Check out-of-bounds access when decoding braced initializer list
+--format=gnu-v3
+_ZDTtl
+_ZDTtl
+# Check for NULL pointer when demangling DEMANGLE_COMPONENT_LOCAL_NAME
+--format=gnu-v3
+_ZZN1fEEd_lEv
+_ZZN1fEEd_lEv
+# Handle DEMANGLE_COMPONENT_FIXED_TYPE in d_find_pack
+--format=gnu-v3
+_Z1fDpDFT_
+_Z1fDpDFT_
+# Likewise, DEMANGLE_COMPONENT_DEFAULT_ARG
+--format=gnu-v3
+_Z1fIDpZ1fEd_E
+_Z1fIDpZ1fEd_E
+# Likewise, DEMANGLE_COMPONENT_NUMBER
+--format=gnu-v3
+_Z1fDpDv1_c
+f((char __vector(1))...)
+#
+# Ada (GNAT) tests.
+#
+# Simple test.
+--format=gnat
+yz__qrs
+yz.qrs
+# Operator
+--format=gnat
+oper__Oadd
+oper."+"
+# Overloaded subprogram.
+--format=gnat
+yz__qrs__2
+yz.qrs
+# Nested subprogram.
+--format=gnat
+yz__qrs__tuv.1661
+yz.qrs.tuv
+# Nested and overloaded subprograms.
+--format=gnat
+yz__qrs__tuv__2_1.1667
+yz.qrs.tuv
+--format=gnat
+yz__qrs__tuv__2_2.1670
+yz.qrs.tuv
+--format=gnat
+yz__qrs__tuv__2_3.1674
+yz.qrs.tuv
+# Elaborated flag (not demangled)
+--format=gnat
+x_E
+<x_E>
+# Nested package
+--format=gnat
+x__m1
+x.m1
+--format=gnat
+x__m3
+x.m3
+--format=gnat
+x__y__m2X
+x.y.m2
+--format=gnat
+x__y__z__rXb
+x.y.z.r
+# Child package
+--format=gnat
+x__y__j
+x.y.j
+# Library level
+--format=gnat
+_ada_x__m3
+x.m3
+# Package body elaborator
+--format=gnat
+p___elabb
+p'Elab_Body
+# Package spec elaborator
+--format=gnat
+p___elabs
+p'Elab_Spec
+# Task body
+--format=gnat
+p__taskobjTKB
+p.taskobj
+# Task subprogram
+--format=gnat
+p__taskobjTK__f1.2330
+p.taskobj.f1
+# Protected types subprograms
+--format=gnat
+prot__lock__getN
+prot.lock.get
+--format=gnat
+prot__lock__getP
+prot.lock.get
+--format=gnat
+prot__lock__get__sub.2590
+prot.lock.get.sub
+--format=gnat
+prot__lock__setN
+prot.lock.set
+--format=gnat
+prot__lock__setP
+prot.lock.set
+# Protected type entries
+--format=gnat
+prot__lock__update_B7s
+prot.lock.update
+--format=gnat
+prot__lock__update_E6s
+prot.lock.update
+# Controlled types
+--format=gnat
+gnat__sockets__sockets_library_controllerDF__2
+gnat.sockets.sockets_library_controller.Finalize
+--format=gnat
+system__partition_interface__racw_stub_typeDA
+system.partition_interface.racw_stub_type.Adjust
+# Stream operations
+--format=gnat
+gnat__wide_wide_string_split__slice_setSR__2
+gnat.wide_wide_string_split.slice_set'Read
+--format=gnat
+ada__real_time__timing_events__events__listSW__2Xnn
+ada.real_time.timing_events.events.list'Write
+--format=gnat
+system__finalization_root__root_controlledSI
+system.finalization_root.root_controlled'Input
+--format=gnat
+ada__finalization__limited_controlledSO__2
+ada.finalization.limited_controlled'Output
+# Tagged types
+--format=gnat
+ada__synchronous_task_control___size__2
+ada.synchronous_task_control'Size
+--format=gnat
+ada__real_time__timing_events__events___alignment__2Xnn
+ada.real_time.timing_events.events'Alignment
+--format=gnat
+system__finalization_root___assign__2
+system.finalization_root.":="
+#
+# Used to crash the demangler.
+--format=gnu-v3
+DFA
+DFA
+#
+# http://sourceware.org/bugzilla/show_bug.cgi?id=11572
+--format=auto
+_ZN3Psi7VariantIIcPKcEE5visitIIRZN11VariantTest9TestVisit11test_methodEvEUlS2_E0_RZNS6_11test_methodEvEUlcE1_RZNS6_11test_methodEvEUlNS_4NoneEE_EEENS_13VariantDetail19SelectVisitorResultIIDpT_EE4typeEDpOSG_
+Psi::VariantDetail::SelectVisitorResult<VariantTest::TestVisit::test_method()::{lambda(char const*)#2}&, VariantTest::TestVisit::test_method()::{lambda(char)#3}&, VariantTest::TestVisit::test_method()::{lambda(Psi::None)#1}&>::type Psi::Variant<char, char const*>::visit<VariantTest::TestVisit::test_method()::{lambda(char const*)#2}&, VariantTest::TestVisit::test_method()::{lambda(char)#3}&, VariantTest::TestVisit::test_method()::{lambda(Psi::None)#1}&>((VariantTest::TestVisit::test_metho [...]
+#
+# Clone suffix tests
+#
+--format=gnu-v3 --no-params
+_Z3fo5n.clone.1
+fo5(__int128) [clone .clone.1]
+fo5
+#
+--format=gnu-v3 --no-params
+_Z3fo5n.constprop.2
+fo5(__int128) [clone .constprop.2]
+fo5
+#
+--format=gnu-v3 --no-params
+_Z3fo5n.isra.3
+fo5(__int128) [clone .isra.3]
+fo5
+#
+--format=gnu-v3 --no-params
+_Z3fo5n.part.4
+fo5(__int128) [clone .part.4]
+fo5
+#
+--format=gnu-v3 --no-params
+_Z12to_be_clonediPv.clone.0
+to_be_cloned(int, void*) [clone .clone.0]
+to_be_cloned
+#
+--format=gnu-v3 --no-params
+_Z3fooi.1988
+foo(int) [clone .1988]
+foo
+#
+--format=gnu-v3 --no-params
+_Z3fooi.part.9.165493.constprop.775.31805
+foo(int) [clone .part.9.165493] [clone .constprop.775.31805]
+foo
+#
+--format=gnu-v3 --no-params
+_Z2f1IiEvT_S0_S0_._omp_fn.2
+void f1<int>(int, int, int) [clone ._omp_fn.2]
+f1<int>
+#
+--format=gnu-v3 --no-params
+_Z3fooi._omp_cpyfn.6
+foo(int) [clone ._omp_cpyfn.6]
+foo
+#
+--format=gnu-v3 --no-params
+_Z1fIKFvvES0_Evv
+void f<void () const, void () const>()
+f<void () const, void () const>
+#
+--format=gnu-v3
+_ZN4modc6parser8sequenceINS_9astParser13LocatedParserINS0_9ParserRefINS2_UlRNS2_16TokenParserInputEE_EEEEEINS0_14OptionalParserINS2_18ListParserTemplateILNS_6tokens5Token4TypeE4EXadL_ZNSD_Ut_13parenthesizedEEEE6ParserINS4_INS0_6ParserIS5_NS_3ast10ExpressionEEEEEEEEENSA_INS4_INS2_22OneOfKeywordsToTParserINSJ_5StyleEEEEEEENS0_14SequenceParserIS5_INS0_18ExactElementParserIS5_EENSA_ISM_EEEEENS0_14RepeatedParserINS4_INS0_15TransformParserINSU_IS5_INS4_INSP_INSJ_10Annotation12RelationshipEEEEE [...]
+modc::parser::ParserRef<modc::astParser::OneOfKeywordsToTParser<modc::astParser::ListParserTemplate<(modc::tokens::Token::Type)4, &modc::tokens::{unnamed type#1}::parenthesized>::Parser::Style> ><modc::parser::ExtractParserType<modc::astParser::LocatedParser<modc::parser::ParserRef<modc::astParser::{lambda(modc::astParser::TokenParserInput&)#1}> > >::InputType, modc::parser::MaybeRef<modc::astParser::{lambda(modc::astParser::Loc, modc::parser::RepeatedParser, modc::Maybe<modc::parser::Pa [...]
+--format=gnu-v3
+_ZNKR1A1hEv
+A::h() const &
+--format=gnu-v3
+_Z1lM1AKFvvRE
+l(void (A::*)() const &)
+--format=gnu-v3
+_Z1mIFvvOEEvM1AT_
+void m<void () &&>(void (A::*)() &&)
+--format=gnu-v3
+_Z1nIM1AKFvvREEvT_
+void n<void (A::*)() const &>(void (A::*)() const &)
+--format=gnu-v3
+_ZL1fIiEvv
+void f<int>()
+# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c3
+--format=gnu-v3
+_ZSt7forwardIRN1x14refobjiteratorINS0_3refINS0_4mime30multipart_section_processorObjIZ15get_body_parserIZZN14mime_processor21make_section_iteratorERKNS2_INS3_10sectionObjENS0_10ptrrefBaseEEEbENKUlvE_clEvEUlSB_bE_ZZNS6_21make_section_iteratorESB_bENKSC_clEvEUlSB_E0_ENS1_INS2_INS0_20outputrefiteratorObjIiEES8_EEEERKSsSB_OT_OT0_EUlmE_NS3_32make_multipart_default_discarderISP_EEEES8_EEEEEOT_RNSt16remove_referenceISW_E4typeE
+x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x: [...]
+#
+--format=gnu-v3 --no-params
+_ZNK7strings8internal8SplitterINS_9delimiter5AnyOfENS_9SkipEmptyEEcvT_ISt6vectorI12basic_stringIcSt11char_traitsIcESaIcEESaISD_EEvEEv
+strings::internal::Splitter<strings::delimiter::AnyOf, strings::SkipEmpty>::operator std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > ><std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > >, void>() const
+strings::internal::Splitter<strings::delimiter::AnyOf, strings::SkipEmpty>::operator std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > ><std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > >, void>
+#
+--format=gnu-v3 --no-params
+_ZN1AcvT_I1CEEv
+A::operator C<C>()
+A::operator C<C>
+#
+--format=gnu-v3 --no-params
+_ZN1AcvPT_I1CEEv
+A::operator C*<C>()
+A::operator C*<C>
+#
+--format=gnu-v3 --no-params
+_ZN1AcvT_IiEI1CEEv
+A::operator C<int><C>()
+A::operator C<int><C>
+# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c16
+--format=gnu-v3
+_ZN3mdr16in_cached_threadIRZNK4cudr6GPUSet17parallel_for_eachIZN5tns3d20shape_representation7compute7GPUImpl7executeERKNS_1AINS_7ptr_refIKjEELl3ELl3ENS_8c_strideILl1ELl0EEEEERKNS8_INS9_IjEELl4ELl1ESD_EEEUliRKNS1_7ContextERNS7_5StateEE_JSt6vectorISO_SaISO_EEEEEvOT_DpRT0_EUlSP_E_JSt17reference_wrapperISO_EEEENS_12ScopedFutureIDTclfp_spcl7forwardISW_Efp0_EEEEESV_DpOSW_
+mdr::ScopedFuture<decltype ({parm#1}(((forward<void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_represen [...]
+# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c18
+--format=gnu-v3
+_ZNSt9_Any_data9_M_accessIPZN13ThreadManager10futureTaskISt5_BindIFSt7_Mem_fnIM6RunnerFvvEEPS5_EEEEvOT_EUlvE_EERSC_v
+void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*& std::_Any_data::_M_access<void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
+# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c24
+# aka https://sourceware.org/bugzilla/show_bug.cgi?id=16593
+--format=gnu-v3
+_ZNSt9_Any_data9_M_accessIPZN3sel8Selector6SetObjI3FooJPKcMS4_FviEEEEvRT_DpT0_EUlvE_EESA_v
+void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*& std::_Any_data::_M_access<void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*&, char const*, void (Foo::*)(int))::{lambda()#1}*>()
+# https://sourceware.org/bugzilla/show_bug.cgi?id=16752#c1
+--format=gnu-v3
+_ZNSt9_Any_data9_M_accessIPZN13ThreadManager7newTaskIRSt5_BindIFSt7_Mem_fnIM5DiaryFivEEPS5_EEIEEESt6futureINSt9result_ofIFT_DpT0_EE4typeEEOSF_DpOSG_EUlvE_EERSF_v
+std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>& ()>::type> ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&)::{lambda()#1}*& std::_Any_data::_M_access<std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>& ()>::type> ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diar [...]
+# https://sourceware.org/bugzilla/show_bug.cgi?id=16752#c6
+--format=gnu-v3
+_ZNSt9_Any_data9_M_accessIPZN6cereal18polymorphic_detail15getInputBindingINS1_16JSONInputArchiveEEENS1_6detail15InputBindingMapIT_E11SerializersERS7_jEUlPvRSt10unique_ptrIvNS5_12EmptyDeleterIvEEEE0_EESA_v
+cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::JSONInputArchive&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*& std::_Any_data::_M_access<cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Se [...]
+# https://sourceware.org/bugzilla/show_bug.cgi?id=16845#c2
+--format=gnu-v3
+_ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v
+void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<void post<std::function<void ()> >(void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
+#
+--format=auto --no-params
+_Z3xxxDFyuVb
+xxx(unsigned long long _Fract, bool volatile)
+xxx
+# https://sourceware.org/bugzilla/show_bug.cgi?id=16817
+--format=auto --no-params
+_QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
+_QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
+_QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
+--format=gnu-v3
+_Z1fSsB3fooS_
+f(std::string[abi:foo], std::string[abi:foo])
+--format=gnu-v3
+_Z18IndirectExternCallIPU7stdcallU7regparmILi3EEFviiEiEvT_T0_S3_
+void IndirectExternCall<void ( regparm<3> stdcall*)(int, int), int>(void ( regparm<3> stdcall*)(int, int), int, void ( regparm<3> stdcall*)(int, int))
+# 
+# ABI tags used to confuse the constructor name calculation.
+--format=gnu-v3 --no-params
+_ZNSt8ios_base7failureB5cxx11C1EPKcRKSt10error_code
+std::ios_base::failure[abi:cxx11]::failure(char const*, std::error_code const&)
+std::ios_base::failure[abi:cxx11]::failure
+--format=gnu-v3
+_Z1fPDxFvvES0_
+f(void (*)() transaction_safe, void (*)() transaction_safe)
+#
+# These two are from gcc PR61321, and gcc PR61233 / gdb PR16957
+#
+--format=gnu-v3
+_Z13function_tempIiEv1AIXszcvT_Li999EEE
+void function_temp<int>(A<sizeof ((int)(999))>)
+#
+--format=gnu-v3
+_Z7ZipWithI7QStringS0_5QListZN4oral6detail16AdaptCreateTableI7AccountEES0_RKNS3_16CachedFieldsDataEEUlRKS0_SA_E_ET1_IDTclfp1_cvT__EcvT0__EEEERKT1_ISC_ERKT1_ISD_ET2_
+QList<decltype ({parm#3}((QString)(), (QString)()))> ZipWith<QString, QString, QList, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}>(QList<QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}> const&, QList<QList> const&, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString con [...]
+#
+# These three are symbols generated by g++'s testsuite, which triggered the same bug as above.
+--format=gnu-v3
+_Z14int_if_addableI1YERiP1AIXszpldecvPT_Li0EdecvS4_Li0EEE
+int& int_if_addable<Y>(A<sizeof ((*((Y*)(0)))+(*((Y*)(0))))>*)
+#
+--format=gnu-v3
+_Z3bazIiEvP1AIXszcl3foocvT__ELCf00000000_00000000EEEE
+void baz<int>(A<sizeof (foo((int)(), (float _Complex)00000000_00000000))>*)
+#
+--format=gnu-v3
+_Z3fooI1FEN1XIXszdtcl1PclcvT__EEE5arrayEE4TypeEv
+X<sizeof ((P(((F)())())).array)>::Type foo<F>()
+
+_Z1fIJidEEv1AIXsZT_EE
+void f<int, double>(A<2>)
+
+_ZN1A1fIJiiEiJiiiEEEvRAsPDpT_T0_DpT1_E_iS3_S5_
+void A::f<int, int, int, int, int, int>(int (&) [6], int, int, int, int)
+
+_Z10unary_leftIJLi1ELi2ELi3EEEv1AIXflplT_EE
+void unary_left<1, 2, 3>(A<(...+(1, 2, 3))>)
+
+_Z11unary_rightIJLi1ELi2ELi3EEEv1AIXfrplT_EE
+void unary_right<1, 2, 3>(A<((1, 2, 3)+...)>)
+
+_Z11binary_leftIJLi1ELi2ELi3EEEv1AIXfLplLi42ET_EE
+void binary_left<1, 2, 3>(A<((42)+...+(1, 2, 3))>)
+
+_Z12binary_rightIJLi1ELi2ELi3EEEv1AIXfRplT_Li42EEE
+void binary_right<1, 2, 3>(A<((1, 2, 3)+...+(42))>)
+#
+# Tests a use-after-free problem PR70481
+
+_Q.__0
+::Q.(void)
+#
+# Tests a use-after-free problem PR70481
+
+_Q10-__9cafebabe.
+cafebabe.::-(void)
+#
+# Tests integer overflow problem PR70492
+
+__vt_90000000000cafebabe
+__vt_90000000000cafebabe
+#
+# Tests write access violation PR70498
+
+_Z80800000000000000000000
+_Z80800000000000000000000
+#
+# Tests write access violation PR70926
+
+0__Ot2m02R5T0000500000
+0__Ot2m02R5T0000500000
+#
+
+0__GT50000000000_
+0__GT50000000000_
+#
+
+__t2m05B500000000000000000_
+__t2m05B500000000000000000_
+#
+# Tests stack overflow PR71696
+
+__10%0__S4_0T0T0
+%0<>::%0(%0<>)
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
index 9b35973..148870b 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go
@@ -84,6 +84,7 @@ const (
 	xArgImm16u       // arg imm8 but record as unsigned
 	xArgM            // arg m
 	xArgM128         // arg m128
+	xArgM256         // arg m256
 	xArgM1428byte    // arg m14/28byte
 	xArgM16          // arg m16
 	xArgM16and16     // arg m16&16
@@ -155,12 +156,14 @@ const (
 	xArgXmm1         // arg xmm1
 	xArgXmm2         // arg xmm2
 	xArgXmm2M128     // arg xmm2/m128
+	xArgYmm2M256     // arg ymm2/m256
 	xArgXmm2M16      // arg xmm2/m16
 	xArgXmm2M32      // arg xmm2/m32
 	xArgXmm2M64      // arg xmm2/m64
 	xArgXmmM128      // arg xmm/m128
 	xArgXmmM32       // arg xmm/m32
 	xArgXmmM64       // arg xmm/m64
+	xArgYmm1         // arg ymm1
 	xArgRmf16        // arg r/m16 but force mod=3
 	xArgRmf32        // arg r/m32 but force mod=3
 	xArgRmf64        // arg r/m64 but force mod=3
@@ -258,6 +261,8 @@ func decode1(src []byte, mode int, gnuCompat bool) (Inst, error) {
 		rex           Prefix // rex byte if present (or 0)
 		rexUsed       Prefix // bits used in rex byte
 		rexIndex      = -1   // index of rex byte
+		vex           Prefix // use vex encoding
+		vexIndex      = -1   // index of vex prefix
 
 		addrMode = mode // address mode (width in bits)
 		dataMode = mode // operand mode (width in bits)
@@ -398,6 +403,33 @@ ReadPrefixes:
 				inst.Prefix[addrSizeIndex] |= PrefixIgnored
 			}
 			addrSizeIndex = pos
+
+		//Group 5 - Vex encoding
+		case 0xC5:
+			if pos == 0 && (mode == 64 || (mode == 32 && pos+1 < len(src) && src[pos+1]&0xc0 == 0xc0)) {
+				vex = p
+				vexIndex = pos
+				inst.Prefix[pos] = p
+				inst.Prefix[pos+1] = Prefix(src[pos+1])
+				pos += 1
+				continue
+			} else {
+				nprefix = pos
+				break ReadPrefixes
+			}
+		case 0xC4:
+			if pos == 0 && (mode == 64 || (mode == 32 && pos+2 < len(src) && src[pos+1]&0xc0 == 0xc0)) {
+				vex = p
+				vexIndex = pos
+				inst.Prefix[pos] = p
+				inst.Prefix[pos+1] = Prefix(src[pos+1])
+				inst.Prefix[pos+2] = Prefix(src[pos+2])
+				pos += 2
+				continue
+			} else {
+				nprefix = pos
+				break ReadPrefixes
+			}
 		}
 
 		if pos >= len(inst.Prefix) {
@@ -408,7 +440,7 @@ ReadPrefixes:
 	}
 
 	// Read REX prefix.
-	if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() {
+	if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() && vex == 0 {
 		rex = Prefix(src[pos])
 		rexIndex = pos
 		if pos >= len(inst.Prefix) {
@@ -514,11 +546,11 @@ Decode:
 					scale = sib >> 6
 					index = (sib >> 3) & 07
 					base = sib & 07
-					if rex&PrefixREXB != 0 {
+					if rex&PrefixREXB != 0 || vex == 0xC4 && inst.Prefix[vexIndex+1]&0x20 == 0 {
 						rexUsed |= PrefixREXB
 						base |= 8
 					}
-					if rex&PrefixREXX != 0 {
+					if rex&PrefixREXX != 0 || vex == 0xC4 && inst.Prefix[vexIndex+1]&0x40 == 0 {
 						rexUsed |= PrefixREXX
 						index |= 8
 					}
@@ -779,6 +811,34 @@ Decode:
 					if rex&prefix == prefix {
 						ok = true
 					}
+				} else if prefix == 0xC5 || prefix == 0xC4 {
+					if vex == prefix {
+						ok = true
+					}
+				} else if vex != 0 && (prefix == 0x0F || prefix == 0x0F38 || prefix == 0x0F3A ||
+					prefix == 0x66 || prefix == 0xF2 || prefix == 0xF3) {
+					var vexM, vexP Prefix
+					if vex == 0xC5 {
+						vexM = 1 // 2 byte vex always implies 0F
+						vexP = inst.Prefix[vexIndex+1]
+					} else {
+						vexM = inst.Prefix[vexIndex+1]
+						vexP = inst.Prefix[vexIndex+2]
+					}
+					switch prefix {
+					case 0x66:
+						ok = vexP&3 == 1
+					case 0xF3:
+						ok = vexP&3 == 2
+					case 0xF2:
+						ok = vexP&3 == 3
+					case 0x0F:
+						ok = vexM&3 == 1
+					case 0x0F38:
+						ok = vexM&3 == 2
+					case 0x0F3A:
+						ok = vexM&3 == 3
+					}
 				} else {
 					if prefix == 0xF3 {
 						sawF3 = true
@@ -993,6 +1053,7 @@ Decode:
 
 		case xArgM,
 			xArgM128,
+			xArgM256,
 			xArgM1428byte,
 			xArgM16,
 			xArgM16and16,
@@ -1041,7 +1102,7 @@ Decode:
 
 		case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64:
 			// TODO(rsc): Can address be 64 bits?
-			mem = Mem{Disp: immc}
+			mem = Mem{Disp: int64(immc)}
 			if segIndex >= 0 {
 				mem.Segment = prefixToSegment(inst.Prefix[segIndex])
 				inst.Prefix[segIndex] |= PrefixImplicit
@@ -1054,6 +1115,15 @@ Decode:
 			}
 			narg++
 
+		case xArgYmm1:
+			base := baseReg[x]
+			index := Reg(regop)
+			if inst.Prefix[vexIndex+1]&0x80 == 0 {
+				index += 8
+			}
+			inst.Args[narg] = base + index
+			narg++
+
 		case xArgR8, xArgR16, xArgR32, xArgR64, xArgXmm, xArgXmm1, xArgDR0dashDR7:
 			base := baseReg[x]
 			index := Reg(regop)
@@ -1115,10 +1185,10 @@ Decode:
 			}
 			inst.Args[narg] = base + index
 			narg++
-
 		case xArgRM8, xArgRM16, xArgRM32, xArgRM64, xArgR32M16, xArgR32M8, xArgR64M16,
 			xArgMmM32, xArgMmM64, xArgMm2M64,
-			xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128:
+			xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128,
+			xArgYmm2M256:
 			if haveMem {
 				inst.Args[narg] = mem
 				inst.MemBytes = int(memBytes[decodeOp(x)])
@@ -1139,6 +1209,10 @@ Decode:
 						index -= 4
 						base = SPB
 					}
+				case xArgYmm2M256:
+					if vex == 0xC4 && inst.Prefix[vexIndex+1]&0x40 == 0x40 {
+						index += 8
+					}
 				}
 				inst.Args[narg] = base + index
 			}
@@ -1522,8 +1596,10 @@ var baseReg = [...]Reg{
 	xArgSTi:        F0,
 	xArgTR0dashTR7: TR0,
 	xArgXmm1:       X0,
+	xArgYmm1:       X0,
 	xArgXmm2:       X0,
 	xArgXmm2M128:   X0,
+	xArgYmm2M256:   X0,
 	xArgXmm2M16:    X0,
 	xArgXmm2M32:    X0,
 	xArgXmm2M64:    X0,
@@ -1579,6 +1655,7 @@ var fixedArg = [...]Arg{
 // by a memory argument of the given form.
 var memBytes = [...]int8{
 	xArgM128:       128 / 8,
+	xArgM256:       256 / 8,
 	xArgM16:        16 / 8,
 	xArgM16and16:   (16 + 16) / 8,
 	xArgM16colon16: (16 + 16) / 8,
@@ -1607,6 +1684,7 @@ var memBytes = [...]int8{
 	xArgRM64:       64 / 8,
 	xArgRM8:        8 / 8,
 	xArgXmm2M128:   128 / 8,
+	xArgYmm2M256:   256 / 8,
 	xArgXmm2M16:    16 / 8,
 	xArgXmm2M32:    32 / 8,
 	xArgXmm2M64:    64 / 8,
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
index e2ff801..728e5d1 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
@@ -432,7 +432,7 @@ SuffixLoop:
 		}
 	}
 	for _, p := range inst.Prefix {
-		if p == 0 {
+		if p == 0 || p.IsVEX() {
 			break
 		}
 		if p&PrefixImplicit != 0 {
@@ -530,6 +530,8 @@ func gnuArg(inst *Inst, x Arg, usedPrefixes *bool) string {
 			if x == DX {
 				return "(%dx)"
 			}
+		case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
+			return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
 		}
 		return gccRegName[x]
 	case Mem:
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
index ef74025..4632b50 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
@@ -72,11 +72,13 @@ const (
 
 	// The REX prefixes must be in the range [PrefixREX, PrefixREX+0x10).
 	// the other bits are set or not according to the intended use.
-	PrefixREX  Prefix = 0x40 // REX 64-bit extension prefix
-	PrefixREXW Prefix = 0x08 // extension bit W (64-bit instruction width)
-	PrefixREXR Prefix = 0x04 // extension bit R (r field in modrm)
-	PrefixREXX Prefix = 0x02 // extension bit X (index field in sib)
-	PrefixREXB Prefix = 0x01 // extension bit B (r/m field in modrm or base field in sib)
+	PrefixREX       Prefix = 0x40 // REX 64-bit extension prefix
+	PrefixREXW      Prefix = 0x08 // extension bit W (64-bit instruction width)
+	PrefixREXR      Prefix = 0x04 // extension bit R (r field in modrm)
+	PrefixREXX      Prefix = 0x02 // extension bit X (index field in sib)
+	PrefixREXB      Prefix = 0x01 // extension bit B (r/m field in modrm or base field in sib)
+	PrefixVEX2Bytes Prefix = 0xC5 // Short form of vex prefix
+	PrefixVEX3Bytes Prefix = 0xC4 // Long form of vex prefix
 )
 
 // IsREX reports whether p is a REX prefix byte.
@@ -84,6 +86,10 @@ func (p Prefix) IsREX() bool {
 	return p&0xF0 == PrefixREX
 }
 
+func (p Prefix) IsVEX() bool {
+	return p&0xFF == PrefixVEX2Bytes || p&0xFF == PrefixVEX3Bytes
+}
+
 func (p Prefix) String() string {
 	p &^= PrefixImplicit | PrefixIgnored | PrefixInvalid
 	if s := prefixNames[p]; s != "" {
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
index 90af9dd..63fa2cf 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
@@ -88,6 +88,13 @@ func IntelSyntax(inst Inst) string {
 			if p.IsREX() {
 				inst.Prefix[i] |= PrefixImplicit
 			}
+			if p.IsVEX() {
+				if p == PrefixVEX3Bytes {
+					inst.Prefix[i+2] |= PrefixImplicit
+				}
+				inst.Prefix[i] |= PrefixImplicit
+				inst.Prefix[i+1] |= PrefixImplicit
+			}
 		}
 	}
 
@@ -353,6 +360,8 @@ func intelArg(inst *Inst, arg Arg) string {
 			prefix = "qword "
 		case 16:
 			prefix = "xmmword "
+		case 32:
+			prefix = "ymmword "
 		}
 		switch inst.Op {
 		case INVLPG:
@@ -434,7 +443,12 @@ func intelArg(inst *Inst, arg Arg) string {
 		return fmt.Sprintf(".%+#x", int64(a))
 	case Reg:
 		if int(a) < len(intelReg) && intelReg[a] != "" {
-			return intelReg[a]
+			switch inst.Op {
+			case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
+				return strings.Replace(intelReg[a], "xmm", "ymm", -1)
+			default:
+				return intelReg[a]
+			}
 		}
 	}
 	return strings.ToLower(arg.String())
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
index 44427d1..41cfc08 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
@@ -29,20 +29,32 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
 		args = append(args, plan9Arg(&inst, pc, symname, a))
 	}
 
+	var rep string
 	var last Prefix
 	for _, p := range inst.Prefix {
-		if p == 0 || p.IsREX() {
+		if p == 0 || p.IsREX() || p.IsVEX() {
 			break
 		}
-		last = p
+
+		switch {
+		// Don't show prefixes implied by the instruction text.
+		case p&0xFF00 == PrefixImplicit:
+			continue
+		// Only REP and REPN are recognized repeaters. Plan 9 syntax
+		// treats them as separate opcodes.
+		case p&0xFF == PrefixREP:
+			rep = "REP; "
+		case p&0xFF == PrefixREPN:
+			rep = "REPNE; "
+		default:
+			last = p
+		}
 	}
 
 	prefix := ""
 	switch last & 0xFF {
 	case 0, 0x66, 0x67:
 		// ignore
-	case PrefixREPN:
-		prefix += "REPNE "
 	default:
 		prefix += last.String() + " "
 	}
@@ -69,7 +81,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
 		op += " " + strings.Join(args, ", ")
 	}
 
-	return prefix + op
+	return rep + prefix + op
 }
 
 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
index 3d08d5e..5b39b74 100644
--- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
@@ -48,207 +48,207 @@ var decoder = [...]uint16{
 	0x28, 8375,
 	0x29, 8381,
 	0x2A, 8410,
-	0x2B, 8416,
-	0x2C, 8445,
-	0x2D, 8451,
-	0x2F, 8480,
-	0x30, 8486,
-	0x31, 8492,
-	0x32, 8521,
-	0x33, 8527,
-	0x34, 8556,
-	0x35, 8562,
-	0x37, 8591,
-	0x38, 8597,
-	0x39, 8603,
-	0x3A, 8632,
-	0x3B, 8638,
-	0x3C, 8667,
-	0x3D, 8673,
-	0x3F, 8702,
-	0x40, 8708,
-	0x41, 8708,
-	0x42, 8708,
-	0x43, 8708,
-	0x44, 8708,
-	0x45, 8708,
-	0x46, 8708,
-	0x47, 8708,
-	0x48, 8723,
-	0x49, 8723,
-	0x4a, 8723,
-	0x4b, 8723,
-	0x4c, 8723,
-	0x4d, 8723,
-	0x4e, 8723,
-	0x4f, 8723,
-	0x50, 8738,
-	0x51, 8738,
-	0x52, 8738,
-	0x53, 8738,
-	0x54, 8738,
-	0x55, 8738,
-	0x56, 8738,
-	0x57, 8738,
-	0x58, 8765,
-	0x59, 8765,
-	0x5a, 8765,
-	0x5b, 8765,
-	0x5c, 8765,
-	0x5d, 8765,
-	0x5e, 8765,
-	0x5f, 8765,
-	0x60, 8792,
-	0x61, 8805,
-	0x62, 8818,
-	0x63, 8837,
-	0x68, 8868,
-	0x69, 8887,
-	0x6A, 8922,
-	0x6B, 8927,
-	0x6C, 8962,
-	0x6D, 8965,
-	0x6E, 8978,
-	0x6F, 8981,
-	0x70, 8994,
-	0x71, 8999,
-	0x72, 9004,
-	0x73, 9009,
-	0x74, 9014,
-	0x75, 9019,
-	0x76, 9024,
-	0x77, 9029,
-	0x78, 9034,
-	0x79, 9039,
-	0x7A, 9044,
-	0x7B, 9049,
-	0x7C, 9054,
-	0x7D, 9059,
-	0x7E, 9064,
-	0x7F, 9069,
-	0x80, 9074,
-	0x81, 9131,
-	0x83, 9372,
-	0x84, 9613,
-	0x85, 9619,
-	0x86, 9648,
-	0x87, 9654,
-	0x88, 9683,
-	0x89, 9689,
-	0x8A, 9711,
-	0x8B, 9717,
-	0x8C, 9739,
-	0x8D, 9768,
-	0x8E, 9797,
-	0x8F, 9826,
-	0x90, 9862,
-	0x91, 9862,
-	0x92, 9862,
-	0x93, 9862,
-	0x94, 9862,
-	0x95, 9862,
-	0x96, 9862,
-	0x97, 9862,
-	0x98, 9888,
-	0x99, 9908,
-	0x9A, 9928,
-	0x9B, 9945,
-	0x9C, 9948,
-	0x9D, 9971,
-	0x9E, 9994,
-	0x9F, 9997,
-	0xA0, 10000,
-	0xA1, 10019,
-	0xA2, 10041,
-	0xA3, 10060,
-	0xA4, 10082,
-	0xA5, 10085,
-	0xA6, 10105,
-	0xA7, 10108,
-	0xA8, 10128,
-	0xA9, 10134,
-	0xAA, 10163,
-	0xAB, 10166,
-	0xAC, 10186,
-	0xAD, 10189,
-	0xAE, 10209,
-	0xAF, 10212,
-	0xb0, 10232,
-	0xb1, 10232,
-	0xb2, 10232,
-	0xb3, 10232,
-	0xb4, 10232,
-	0xb5, 10232,
-	0xb6, 10232,
-	0xb7, 10232,
-	0xb8, 10238,
-	0xb9, 10238,
-	0xba, 10238,
-	0xbb, 10238,
-	0xbc, 10238,
-	0xbd, 10238,
-	0xbe, 10238,
-	0xbf, 10238,
-	0xC0, 10267,
-	0xC1, 10318,
-	0xC2, 10516,
-	0xC3, 10521,
-	0xC4, 10524,
-	0xC5, 10543,
-	0xC6, 10562,
-	0xC7, 10586,
-	0xC8, 10647,
-	0xC9, 10654,
-	0xCA, 10677,
-	0xCB, 10682,
-	0xCC, 10685,
-	0xCD, 10689,
-	0xCE, 10694,
-	0xCF, 10700,
-	0xD0, 10720,
-	0xD1, 10764,
-	0xD2, 10955,
-	0xD3, 10999,
-	0xD4, 11190,
-	0xD5, 11198,
-	0xD7, 11206,
-	0xD8, 11219,
-	0xD9, 11428,
-	0xDA, 11637,
-	0xDB, 11769,
-	0xDC, 11940,
-	0xDD, 12109,
-	0xDE, 12248,
-	0xDF, 12422,
-	0xE0, 12533,
-	0xE1, 12538,
-	0xE2, 12543,
-	0xE3, 12548,
-	0xE4, 12574,
-	0xE5, 12580,
-	0xE6, 12602,
-	0xE7, 12608,
-	0xE8, 12630,
-	0xE9, 12661,
-	0xEA, 12692,
-	0xEB, 12709,
-	0xEC, 12714,
-	0xED, 12719,
-	0xEE, 12738,
-	0xEF, 12743,
-	0xF1, 12762,
-	0xF4, 12765,
-	0xF5, 12768,
-	0xF6, 12771,
-	0xF7, 12810,
-	0xF8, 12986,
-	0xF9, 12989,
-	0xFA, 12992,
-	0xFB, 12995,
-	0xFC, 12998,
-	0xFD, 13001,
-	0xFE, 13004,
-	0xFF, 13021,
+	0x2B, 8452,
+	0x2C, 8481,
+	0x2D, 8487,
+	0x2F, 8516,
+	0x30, 8522,
+	0x31, 8528,
+	0x32, 8557,
+	0x33, 8563,
+	0x34, 8592,
+	0x35, 8598,
+	0x37, 8627,
+	0x38, 8633,
+	0x39, 8639,
+	0x3A, 8668,
+	0x3B, 8674,
+	0x3C, 8703,
+	0x3D, 8709,
+	0x3F, 8738,
+	0x40, 8744,
+	0x41, 8744,
+	0x42, 8744,
+	0x43, 8744,
+	0x44, 8744,
+	0x45, 8744,
+	0x46, 8744,
+	0x47, 8744,
+	0x48, 8759,
+	0x49, 8759,
+	0x4a, 8759,
+	0x4b, 8759,
+	0x4c, 8759,
+	0x4d, 8759,
+	0x4e, 8759,
+	0x4f, 8759,
+	0x50, 8774,
+	0x51, 8774,
+	0x52, 8774,
+	0x53, 8774,
+	0x54, 8774,
+	0x55, 8774,
+	0x56, 8774,
+	0x57, 8774,
+	0x58, 8801,
+	0x59, 8801,
+	0x5a, 8801,
+	0x5b, 8801,
+	0x5c, 8801,
+	0x5d, 8801,
+	0x5e, 8801,
+	0x5f, 8801,
+	0x60, 8828,
+	0x61, 8841,
+	0x62, 8854,
+	0x63, 8873,
+	0x68, 8904,
+	0x69, 8923,
+	0x6A, 8958,
+	0x6B, 8963,
+	0x6C, 8998,
+	0x6D, 9001,
+	0x6E, 9014,
+	0x6F, 9017,
+	0x70, 9090,
+	0x71, 9095,
+	0x72, 9100,
+	0x73, 9105,
+	0x74, 9110,
+	0x75, 9115,
+	0x76, 9120,
+	0x77, 9125,
+	0x78, 9152,
+	0x79, 9157,
+	0x7A, 9162,
+	0x7B, 9167,
+	0x7C, 9172,
+	0x7D, 9177,
+	0x7E, 9182,
+	0x7F, 9187,
+	0x80, 9252,
+	0x81, 9309,
+	0x83, 9550,
+	0x84, 9791,
+	0x85, 9797,
+	0x86, 9826,
+	0x87, 9832,
+	0x88, 9861,
+	0x89, 9867,
+	0x8A, 9889,
+	0x8B, 9895,
+	0x8C, 9917,
+	0x8D, 9946,
+	0x8E, 9975,
+	0x8F, 10004,
+	0x90, 10040,
+	0x91, 10040,
+	0x92, 10040,
+	0x93, 10040,
+	0x94, 10040,
+	0x95, 10040,
+	0x96, 10040,
+	0x97, 10040,
+	0x98, 10066,
+	0x99, 10086,
+	0x9A, 10106,
+	0x9B, 10123,
+	0x9C, 10126,
+	0x9D, 10149,
+	0x9E, 10172,
+	0x9F, 10175,
+	0xA0, 10178,
+	0xA1, 10197,
+	0xA2, 10219,
+	0xA3, 10238,
+	0xA4, 10260,
+	0xA5, 10263,
+	0xA6, 10283,
+	0xA7, 10286,
+	0xA8, 10306,
+	0xA9, 10312,
+	0xAA, 10341,
+	0xAB, 10344,
+	0xAC, 10364,
+	0xAD, 10367,
+	0xAE, 10387,
+	0xAF, 10390,
+	0xb0, 10410,
+	0xb1, 10410,
+	0xb2, 10410,
+	0xb3, 10410,
+	0xb4, 10410,
+	0xb5, 10410,
+	0xb6, 10410,
+	0xb7, 10410,
+	0xb8, 10416,
+	0xb9, 10416,
+	0xba, 10416,
+	0xbb, 10416,
+	0xbc, 10416,
+	0xbd, 10416,
+	0xbe, 10416,
+	0xbf, 10416,
+	0xC0, 10445,
+	0xC1, 10496,
+	0xC2, 10694,
+	0xC3, 10699,
+	0xC4, 10702,
+	0xC5, 10721,
+	0xC6, 10740,
+	0xC7, 10764,
+	0xC8, 10825,
+	0xC9, 10832,
+	0xCA, 10855,
+	0xCB, 10860,
+	0xCC, 10863,
+	0xCD, 10867,
+	0xCE, 10872,
+	0xCF, 10878,
+	0xD0, 10898,
+	0xD1, 10942,
+	0xD2, 11133,
+	0xD3, 11177,
+	0xD4, 11368,
+	0xD5, 11376,
+	0xD7, 11384,
+	0xD8, 11397,
+	0xD9, 11606,
+	0xDA, 11815,
+	0xDB, 11947,
+	0xDC, 12118,
+	0xDD, 12287,
+	0xDE, 12426,
+	0xDF, 12600,
+	0xE0, 12711,
+	0xE1, 12716,
+	0xE2, 12721,
+	0xE3, 12726,
+	0xE4, 12752,
+	0xE5, 12758,
+	0xE6, 12780,
+	0xE7, 12786,
+	0xE8, 12844,
+	0xE9, 12875,
+	0xEA, 12906,
+	0xEB, 12923,
+	0xEC, 12928,
+	0xED, 12933,
+	0xEE, 12952,
+	0xEF, 12957,
+	0xF1, 12976,
+	0xF4, 12979,
+	0xF5, 12982,
+	0xF6, 12985,
+	0xF7, 13024,
+	0xF8, 13200,
+	0xF9, 13203,
+	0xFA, 13206,
+	0xFB, 13209,
+	0xFC, 13212,
+	0xFD, 13215,
+	0xFE, 13218,
+	0xFF, 13235,
 	uint16(xFail),
 	/*490*/ uint16(xSetOp), uint16(ADD),
 	/*492*/ uint16(xReadSlashR),
@@ -5492,1396 +5492,1506 @@ var decoder = [...]uint16{
 	/*8407*/ uint16(xArgRM64),
 	/*8408*/ uint16(xArgR64),
 	/*8409*/ uint16(xMatch),
-	/*8410*/ uint16(xSetOp), uint16(SUB),
-	/*8412*/ uint16(xReadSlashR),
-	/*8413*/ uint16(xArgR8),
-	/*8414*/ uint16(xArgRM8),
-	/*8415*/ uint16(xMatch),
-	/*8416*/ uint16(xCondIs64), 8419, 8435,
-	/*8419*/ uint16(xCondDataSize), 8423, 8429, 0,
-	/*8423*/ uint16(xSetOp), uint16(SUB),
-	/*8425*/ uint16(xReadSlashR),
-	/*8426*/ uint16(xArgR16),
-	/*8427*/ uint16(xArgRM16),
-	/*8428*/ uint16(xMatch),
-	/*8429*/ uint16(xSetOp), uint16(SUB),
-	/*8431*/ uint16(xReadSlashR),
-	/*8432*/ uint16(xArgR32),
-	/*8433*/ uint16(xArgRM32),
-	/*8434*/ uint16(xMatch),
-	/*8435*/ uint16(xCondDataSize), 8423, 8429, 8439,
-	/*8439*/ uint16(xSetOp), uint16(SUB),
-	/*8441*/ uint16(xReadSlashR),
-	/*8442*/ uint16(xArgR64),
-	/*8443*/ uint16(xArgRM64),
-	/*8444*/ uint16(xMatch),
-	/*8445*/ uint16(xSetOp), uint16(SUB),
-	/*8447*/ uint16(xReadIb),
-	/*8448*/ uint16(xArgAL),
-	/*8449*/ uint16(xArgImm8u),
-	/*8450*/ uint16(xMatch),
-	/*8451*/ uint16(xCondIs64), 8454, 8470,
-	/*8454*/ uint16(xCondDataSize), 8458, 8464, 0,
-	/*8458*/ uint16(xSetOp), uint16(SUB),
-	/*8460*/ uint16(xReadIw),
-	/*8461*/ uint16(xArgAX),
-	/*8462*/ uint16(xArgImm16),
-	/*8463*/ uint16(xMatch),
-	/*8464*/ uint16(xSetOp), uint16(SUB),
-	/*8466*/ uint16(xReadId),
-	/*8467*/ uint16(xArgEAX),
-	/*8468*/ uint16(xArgImm32),
-	/*8469*/ uint16(xMatch),
-	/*8470*/ uint16(xCondDataSize), 8458, 8464, 8474,
-	/*8474*/ uint16(xSetOp), uint16(SUB),
-	/*8476*/ uint16(xReadId),
-	/*8477*/ uint16(xArgRAX),
-	/*8478*/ uint16(xArgImm32),
-	/*8479*/ uint16(xMatch),
-	/*8480*/ uint16(xCondIs64), 8483, 0,
-	/*8483*/ uint16(xSetOp), uint16(DAS),
-	/*8485*/ uint16(xMatch),
-	/*8486*/ uint16(xSetOp), uint16(XOR),
-	/*8488*/ uint16(xReadSlashR),
-	/*8489*/ uint16(xArgRM8),
-	/*8490*/ uint16(xArgR8),
-	/*8491*/ uint16(xMatch),
-	/*8492*/ uint16(xCondIs64), 8495, 8511,
-	/*8495*/ uint16(xCondDataSize), 8499, 8505, 0,
-	/*8499*/ uint16(xSetOp), uint16(XOR),
-	/*8501*/ uint16(xReadSlashR),
-	/*8502*/ uint16(xArgRM16),
-	/*8503*/ uint16(xArgR16),
-	/*8504*/ uint16(xMatch),
-	/*8505*/ uint16(xSetOp), uint16(XOR),
-	/*8507*/ uint16(xReadSlashR),
-	/*8508*/ uint16(xArgRM32),
-	/*8509*/ uint16(xArgR32),
-	/*8510*/ uint16(xMatch),
-	/*8511*/ uint16(xCondDataSize), 8499, 8505, 8515,
-	/*8515*/ uint16(xSetOp), uint16(XOR),
-	/*8517*/ uint16(xReadSlashR),
-	/*8518*/ uint16(xArgRM64),
-	/*8519*/ uint16(xArgR64),
-	/*8520*/ uint16(xMatch),
-	/*8521*/ uint16(xSetOp), uint16(XOR),
-	/*8523*/ uint16(xReadSlashR),
-	/*8524*/ uint16(xArgR8),
+	/*8410*/ uint16(xCondPrefix), 3,
+	0xC5, 8438,
+	0xC4, 8424,
+	0x0, 8418,
+	/*8418*/ uint16(xSetOp), uint16(SUB),
+	/*8420*/ uint16(xReadSlashR),
+	/*8421*/ uint16(xArgR8),
+	/*8422*/ uint16(xArgRM8),
+	/*8423*/ uint16(xMatch),
+	/*8424*/ uint16(xCondPrefix), 1,
+	0x66, 8428,
+	/*8428*/ uint16(xCondPrefix), 1,
+	0x0F38, 8432,
+	/*8432*/ uint16(xSetOp), uint16(VMOVNTDQA),
+	/*8434*/ uint16(xReadSlashR),
+	/*8435*/ uint16(xArgYmm1),
+	/*8436*/ uint16(xArgM256),
+	/*8437*/ uint16(xMatch),
+	/*8438*/ uint16(xCondPrefix), 1,
+	0x66, 8442,
+	/*8442*/ uint16(xCondPrefix), 1,
+	0x0F38, 8446,
+	/*8446*/ uint16(xSetOp), uint16(VMOVNTDQA),
+	/*8448*/ uint16(xReadSlashR),
+	/*8449*/ uint16(xArgYmm1),
+	/*8450*/ uint16(xArgM256),
+	/*8451*/ uint16(xMatch),
+	/*8452*/ uint16(xCondIs64), 8455, 8471,
+	/*8455*/ uint16(xCondDataSize), 8459, 8465, 0,
+	/*8459*/ uint16(xSetOp), uint16(SUB),
+	/*8461*/ uint16(xReadSlashR),
+	/*8462*/ uint16(xArgR16),
+	/*8463*/ uint16(xArgRM16),
+	/*8464*/ uint16(xMatch),
+	/*8465*/ uint16(xSetOp), uint16(SUB),
+	/*8467*/ uint16(xReadSlashR),
+	/*8468*/ uint16(xArgR32),
+	/*8469*/ uint16(xArgRM32),
+	/*8470*/ uint16(xMatch),
+	/*8471*/ uint16(xCondDataSize), 8459, 8465, 8475,
+	/*8475*/ uint16(xSetOp), uint16(SUB),
+	/*8477*/ uint16(xReadSlashR),
+	/*8478*/ uint16(xArgR64),
+	/*8479*/ uint16(xArgRM64),
+	/*8480*/ uint16(xMatch),
+	/*8481*/ uint16(xSetOp), uint16(SUB),
+	/*8483*/ uint16(xReadIb),
+	/*8484*/ uint16(xArgAL),
+	/*8485*/ uint16(xArgImm8u),
+	/*8486*/ uint16(xMatch),
+	/*8487*/ uint16(xCondIs64), 8490, 8506,
+	/*8490*/ uint16(xCondDataSize), 8494, 8500, 0,
+	/*8494*/ uint16(xSetOp), uint16(SUB),
+	/*8496*/ uint16(xReadIw),
+	/*8497*/ uint16(xArgAX),
+	/*8498*/ uint16(xArgImm16),
+	/*8499*/ uint16(xMatch),
+	/*8500*/ uint16(xSetOp), uint16(SUB),
+	/*8502*/ uint16(xReadId),
+	/*8503*/ uint16(xArgEAX),
+	/*8504*/ uint16(xArgImm32),
+	/*8505*/ uint16(xMatch),
+	/*8506*/ uint16(xCondDataSize), 8494, 8500, 8510,
+	/*8510*/ uint16(xSetOp), uint16(SUB),
+	/*8512*/ uint16(xReadId),
+	/*8513*/ uint16(xArgRAX),
+	/*8514*/ uint16(xArgImm32),
+	/*8515*/ uint16(xMatch),
+	/*8516*/ uint16(xCondIs64), 8519, 0,
+	/*8519*/ uint16(xSetOp), uint16(DAS),
+	/*8521*/ uint16(xMatch),
+	/*8522*/ uint16(xSetOp), uint16(XOR),
+	/*8524*/ uint16(xReadSlashR),
 	/*8525*/ uint16(xArgRM8),
-	/*8526*/ uint16(xMatch),
-	/*8527*/ uint16(xCondIs64), 8530, 8546,
-	/*8530*/ uint16(xCondDataSize), 8534, 8540, 0,
-	/*8534*/ uint16(xSetOp), uint16(XOR),
-	/*8536*/ uint16(xReadSlashR),
-	/*8537*/ uint16(xArgR16),
+	/*8526*/ uint16(xArgR8),
+	/*8527*/ uint16(xMatch),
+	/*8528*/ uint16(xCondIs64), 8531, 8547,
+	/*8531*/ uint16(xCondDataSize), 8535, 8541, 0,
+	/*8535*/ uint16(xSetOp), uint16(XOR),
+	/*8537*/ uint16(xReadSlashR),
 	/*8538*/ uint16(xArgRM16),
-	/*8539*/ uint16(xMatch),
-	/*8540*/ uint16(xSetOp), uint16(XOR),
-	/*8542*/ uint16(xReadSlashR),
-	/*8543*/ uint16(xArgR32),
+	/*8539*/ uint16(xArgR16),
+	/*8540*/ uint16(xMatch),
+	/*8541*/ uint16(xSetOp), uint16(XOR),
+	/*8543*/ uint16(xReadSlashR),
 	/*8544*/ uint16(xArgRM32),
-	/*8545*/ uint16(xMatch),
-	/*8546*/ uint16(xCondDataSize), 8534, 8540, 8550,
-	/*8550*/ uint16(xSetOp), uint16(XOR),
-	/*8552*/ uint16(xReadSlashR),
-	/*8553*/ uint16(xArgR64),
+	/*8545*/ uint16(xArgR32),
+	/*8546*/ uint16(xMatch),
+	/*8547*/ uint16(xCondDataSize), 8535, 8541, 8551,
+	/*8551*/ uint16(xSetOp), uint16(XOR),
+	/*8553*/ uint16(xReadSlashR),
 	/*8554*/ uint16(xArgRM64),
-	/*8555*/ uint16(xMatch),
-	/*8556*/ uint16(xSetOp), uint16(XOR),
-	/*8558*/ uint16(xReadIb),
-	/*8559*/ uint16(xArgAL),
-	/*8560*/ uint16(xArgImm8u),
-	/*8561*/ uint16(xMatch),
-	/*8562*/ uint16(xCondIs64), 8565, 8581,
-	/*8565*/ uint16(xCondDataSize), 8569, 8575, 0,
-	/*8569*/ uint16(xSetOp), uint16(XOR),
-	/*8571*/ uint16(xReadIw),
-	/*8572*/ uint16(xArgAX),
-	/*8573*/ uint16(xArgImm16),
-	/*8574*/ uint16(xMatch),
-	/*8575*/ uint16(xSetOp), uint16(XOR),
-	/*8577*/ uint16(xReadId),
-	/*8578*/ uint16(xArgEAX),
-	/*8579*/ uint16(xArgImm32),
-	/*8580*/ uint16(xMatch),
-	/*8581*/ uint16(xCondDataSize), 8569, 8575, 8585,
-	/*8585*/ uint16(xSetOp), uint16(XOR),
-	/*8587*/ uint16(xReadId),
-	/*8588*/ uint16(xArgRAX),
-	/*8589*/ uint16(xArgImm32),
-	/*8590*/ uint16(xMatch),
-	/*8591*/ uint16(xCondIs64), 8594, 0,
-	/*8594*/ uint16(xSetOp), uint16(AAA),
-	/*8596*/ uint16(xMatch),
-	/*8597*/ uint16(xSetOp), uint16(CMP),
-	/*8599*/ uint16(xReadSlashR),
-	/*8600*/ uint16(xArgRM8),
-	/*8601*/ uint16(xArgR8),
-	/*8602*/ uint16(xMatch),
-	/*8603*/ uint16(xCondIs64), 8606, 8622,
-	/*8606*/ uint16(xCondDataSize), 8610, 8616, 0,
-	/*8610*/ uint16(xSetOp), uint16(CMP),
-	/*8612*/ uint16(xReadSlashR),
-	/*8613*/ uint16(xArgRM16),
-	/*8614*/ uint16(xArgR16),
-	/*8615*/ uint16(xMatch),
-	/*8616*/ uint16(xSetOp), uint16(CMP),
-	/*8618*/ uint16(xReadSlashR),
-	/*8619*/ uint16(xArgRM32),
-	/*8620*/ uint16(xArgR32),
-	/*8621*/ uint16(xMatch),
-	/*8622*/ uint16(xCondDataSize), 8610, 8616, 8626,
-	/*8626*/ uint16(xSetOp), uint16(CMP),
-	/*8628*/ uint16(xReadSlashR),
-	/*8629*/ uint16(xArgRM64),
-	/*8630*/ uint16(xArgR64),
-	/*8631*/ uint16(xMatch),
-	/*8632*/ uint16(xSetOp), uint16(CMP),
-	/*8634*/ uint16(xReadSlashR),
-	/*8635*/ uint16(xArgR8),
+	/*8555*/ uint16(xArgR64),
+	/*8556*/ uint16(xMatch),
+	/*8557*/ uint16(xSetOp), uint16(XOR),
+	/*8559*/ uint16(xReadSlashR),
+	/*8560*/ uint16(xArgR8),
+	/*8561*/ uint16(xArgRM8),
+	/*8562*/ uint16(xMatch),
+	/*8563*/ uint16(xCondIs64), 8566, 8582,
+	/*8566*/ uint16(xCondDataSize), 8570, 8576, 0,
+	/*8570*/ uint16(xSetOp), uint16(XOR),
+	/*8572*/ uint16(xReadSlashR),
+	/*8573*/ uint16(xArgR16),
+	/*8574*/ uint16(xArgRM16),
+	/*8575*/ uint16(xMatch),
+	/*8576*/ uint16(xSetOp), uint16(XOR),
+	/*8578*/ uint16(xReadSlashR),
+	/*8579*/ uint16(xArgR32),
+	/*8580*/ uint16(xArgRM32),
+	/*8581*/ uint16(xMatch),
+	/*8582*/ uint16(xCondDataSize), 8570, 8576, 8586,
+	/*8586*/ uint16(xSetOp), uint16(XOR),
+	/*8588*/ uint16(xReadSlashR),
+	/*8589*/ uint16(xArgR64),
+	/*8590*/ uint16(xArgRM64),
+	/*8591*/ uint16(xMatch),
+	/*8592*/ uint16(xSetOp), uint16(XOR),
+	/*8594*/ uint16(xReadIb),
+	/*8595*/ uint16(xArgAL),
+	/*8596*/ uint16(xArgImm8u),
+	/*8597*/ uint16(xMatch),
+	/*8598*/ uint16(xCondIs64), 8601, 8617,
+	/*8601*/ uint16(xCondDataSize), 8605, 8611, 0,
+	/*8605*/ uint16(xSetOp), uint16(XOR),
+	/*8607*/ uint16(xReadIw),
+	/*8608*/ uint16(xArgAX),
+	/*8609*/ uint16(xArgImm16),
+	/*8610*/ uint16(xMatch),
+	/*8611*/ uint16(xSetOp), uint16(XOR),
+	/*8613*/ uint16(xReadId),
+	/*8614*/ uint16(xArgEAX),
+	/*8615*/ uint16(xArgImm32),
+	/*8616*/ uint16(xMatch),
+	/*8617*/ uint16(xCondDataSize), 8605, 8611, 8621,
+	/*8621*/ uint16(xSetOp), uint16(XOR),
+	/*8623*/ uint16(xReadId),
+	/*8624*/ uint16(xArgRAX),
+	/*8625*/ uint16(xArgImm32),
+	/*8626*/ uint16(xMatch),
+	/*8627*/ uint16(xCondIs64), 8630, 0,
+	/*8630*/ uint16(xSetOp), uint16(AAA),
+	/*8632*/ uint16(xMatch),
+	/*8633*/ uint16(xSetOp), uint16(CMP),
+	/*8635*/ uint16(xReadSlashR),
 	/*8636*/ uint16(xArgRM8),
-	/*8637*/ uint16(xMatch),
-	/*8638*/ uint16(xCondIs64), 8641, 8657,
-	/*8641*/ uint16(xCondDataSize), 8645, 8651, 0,
-	/*8645*/ uint16(xSetOp), uint16(CMP),
-	/*8647*/ uint16(xReadSlashR),
-	/*8648*/ uint16(xArgR16),
+	/*8637*/ uint16(xArgR8),
+	/*8638*/ uint16(xMatch),
+	/*8639*/ uint16(xCondIs64), 8642, 8658,
+	/*8642*/ uint16(xCondDataSize), 8646, 8652, 0,
+	/*8646*/ uint16(xSetOp), uint16(CMP),
+	/*8648*/ uint16(xReadSlashR),
 	/*8649*/ uint16(xArgRM16),
-	/*8650*/ uint16(xMatch),
-	/*8651*/ uint16(xSetOp), uint16(CMP),
-	/*8653*/ uint16(xReadSlashR),
-	/*8654*/ uint16(xArgR32),
+	/*8650*/ uint16(xArgR16),
+	/*8651*/ uint16(xMatch),
+	/*8652*/ uint16(xSetOp), uint16(CMP),
+	/*8654*/ uint16(xReadSlashR),
 	/*8655*/ uint16(xArgRM32),
-	/*8656*/ uint16(xMatch),
-	/*8657*/ uint16(xCondDataSize), 8645, 8651, 8661,
-	/*8661*/ uint16(xSetOp), uint16(CMP),
-	/*8663*/ uint16(xReadSlashR),
-	/*8664*/ uint16(xArgR64),
+	/*8656*/ uint16(xArgR32),
+	/*8657*/ uint16(xMatch),
+	/*8658*/ uint16(xCondDataSize), 8646, 8652, 8662,
+	/*8662*/ uint16(xSetOp), uint16(CMP),
+	/*8664*/ uint16(xReadSlashR),
 	/*8665*/ uint16(xArgRM64),
-	/*8666*/ uint16(xMatch),
-	/*8667*/ uint16(xSetOp), uint16(CMP),
-	/*8669*/ uint16(xReadIb),
-	/*8670*/ uint16(xArgAL),
-	/*8671*/ uint16(xArgImm8u),
-	/*8672*/ uint16(xMatch),
-	/*8673*/ uint16(xCondIs64), 8676, 8692,
-	/*8676*/ uint16(xCondDataSize), 8680, 8686, 0,
-	/*8680*/ uint16(xSetOp), uint16(CMP),
-	/*8682*/ uint16(xReadIw),
-	/*8683*/ uint16(xArgAX),
-	/*8684*/ uint16(xArgImm16),
-	/*8685*/ uint16(xMatch),
-	/*8686*/ uint16(xSetOp), uint16(CMP),
-	/*8688*/ uint16(xReadId),
-	/*8689*/ uint16(xArgEAX),
-	/*8690*/ uint16(xArgImm32),
-	/*8691*/ uint16(xMatch),
-	/*8692*/ uint16(xCondDataSize), 8680, 8686, 8696,
-	/*8696*/ uint16(xSetOp), uint16(CMP),
-	/*8698*/ uint16(xReadId),
-	/*8699*/ uint16(xArgRAX),
-	/*8700*/ uint16(xArgImm32),
-	/*8701*/ uint16(xMatch),
-	/*8702*/ uint16(xCondIs64), 8705, 0,
-	/*8705*/ uint16(xSetOp), uint16(AAS),
-	/*8707*/ uint16(xMatch),
-	/*8708*/ uint16(xCondIs64), 8711, 0,
-	/*8711*/ uint16(xCondDataSize), 8715, 8719, 0,
-	/*8715*/ uint16(xSetOp), uint16(INC),
-	/*8717*/ uint16(xArgR16op),
-	/*8718*/ uint16(xMatch),
-	/*8719*/ uint16(xSetOp), uint16(INC),
-	/*8721*/ uint16(xArgR32op),
-	/*8722*/ uint16(xMatch),
-	/*8723*/ uint16(xCondIs64), 8726, 0,
-	/*8726*/ uint16(xCondDataSize), 8730, 8734, 0,
-	/*8730*/ uint16(xSetOp), uint16(DEC),
-	/*8732*/ uint16(xArgR16op),
-	/*8733*/ uint16(xMatch),
-	/*8734*/ uint16(xSetOp), uint16(DEC),
-	/*8736*/ uint16(xArgR32op),
+	/*8666*/ uint16(xArgR64),
+	/*8667*/ uint16(xMatch),
+	/*8668*/ uint16(xSetOp), uint16(CMP),
+	/*8670*/ uint16(xReadSlashR),
+	/*8671*/ uint16(xArgR8),
+	/*8672*/ uint16(xArgRM8),
+	/*8673*/ uint16(xMatch),
+	/*8674*/ uint16(xCondIs64), 8677, 8693,
+	/*8677*/ uint16(xCondDataSize), 8681, 8687, 0,
+	/*8681*/ uint16(xSetOp), uint16(CMP),
+	/*8683*/ uint16(xReadSlashR),
+	/*8684*/ uint16(xArgR16),
+	/*8685*/ uint16(xArgRM16),
+	/*8686*/ uint16(xMatch),
+	/*8687*/ uint16(xSetOp), uint16(CMP),
+	/*8689*/ uint16(xReadSlashR),
+	/*8690*/ uint16(xArgR32),
+	/*8691*/ uint16(xArgRM32),
+	/*8692*/ uint16(xMatch),
+	/*8693*/ uint16(xCondDataSize), 8681, 8687, 8697,
+	/*8697*/ uint16(xSetOp), uint16(CMP),
+	/*8699*/ uint16(xReadSlashR),
+	/*8700*/ uint16(xArgR64),
+	/*8701*/ uint16(xArgRM64),
+	/*8702*/ uint16(xMatch),
+	/*8703*/ uint16(xSetOp), uint16(CMP),
+	/*8705*/ uint16(xReadIb),
+	/*8706*/ uint16(xArgAL),
+	/*8707*/ uint16(xArgImm8u),
+	/*8708*/ uint16(xMatch),
+	/*8709*/ uint16(xCondIs64), 8712, 8728,
+	/*8712*/ uint16(xCondDataSize), 8716, 8722, 0,
+	/*8716*/ uint16(xSetOp), uint16(CMP),
+	/*8718*/ uint16(xReadIw),
+	/*8719*/ uint16(xArgAX),
+	/*8720*/ uint16(xArgImm16),
+	/*8721*/ uint16(xMatch),
+	/*8722*/ uint16(xSetOp), uint16(CMP),
+	/*8724*/ uint16(xReadId),
+	/*8725*/ uint16(xArgEAX),
+	/*8726*/ uint16(xArgImm32),
+	/*8727*/ uint16(xMatch),
+	/*8728*/ uint16(xCondDataSize), 8716, 8722, 8732,
+	/*8732*/ uint16(xSetOp), uint16(CMP),
+	/*8734*/ uint16(xReadId),
+	/*8735*/ uint16(xArgRAX),
+	/*8736*/ uint16(xArgImm32),
 	/*8737*/ uint16(xMatch),
-	/*8738*/ uint16(xCondIs64), 8741, 8753,
-	/*8741*/ uint16(xCondDataSize), 8745, 8749, 0,
-	/*8745*/ uint16(xSetOp), uint16(PUSH),
-	/*8747*/ uint16(xArgR16op),
-	/*8748*/ uint16(xMatch),
-	/*8749*/ uint16(xSetOp), uint16(PUSH),
-	/*8751*/ uint16(xArgR32op),
-	/*8752*/ uint16(xMatch),
-	/*8753*/ uint16(xCondDataSize), 8745, 8757, 8761,
-	/*8757*/ uint16(xSetOp), uint16(PUSH),
-	/*8759*/ uint16(xArgR64op),
-	/*8760*/ uint16(xMatch),
-	/*8761*/ uint16(xSetOp), uint16(PUSH),
-	/*8763*/ uint16(xArgR64op),
-	/*8764*/ uint16(xMatch),
-	/*8765*/ uint16(xCondIs64), 8768, 8780,
-	/*8768*/ uint16(xCondDataSize), 8772, 8776, 0,
-	/*8772*/ uint16(xSetOp), uint16(POP),
-	/*8774*/ uint16(xArgR16op),
-	/*8775*/ uint16(xMatch),
-	/*8776*/ uint16(xSetOp), uint16(POP),
-	/*8778*/ uint16(xArgR32op),
-	/*8779*/ uint16(xMatch),
-	/*8780*/ uint16(xCondDataSize), 8772, 8784, 8788,
-	/*8784*/ uint16(xSetOp), uint16(POP),
-	/*8786*/ uint16(xArgR64op),
-	/*8787*/ uint16(xMatch),
-	/*8788*/ uint16(xSetOp), uint16(POP),
-	/*8790*/ uint16(xArgR64op),
-	/*8791*/ uint16(xMatch),
-	/*8792*/ uint16(xCondIs64), 8795, 0,
-	/*8795*/ uint16(xCondDataSize), 8799, 8802, 0,
-	/*8799*/ uint16(xSetOp), uint16(PUSHA),
-	/*8801*/ uint16(xMatch),
-	/*8802*/ uint16(xSetOp), uint16(PUSHAD),
-	/*8804*/ uint16(xMatch),
-	/*8805*/ uint16(xCondIs64), 8808, 0,
-	/*8808*/ uint16(xCondDataSize), 8812, 8815, 0,
-	/*8812*/ uint16(xSetOp), uint16(POPA),
-	/*8814*/ uint16(xMatch),
-	/*8815*/ uint16(xSetOp), uint16(POPAD),
-	/*8817*/ uint16(xMatch),
-	/*8818*/ uint16(xCondIs64), 8821, 0,
-	/*8821*/ uint16(xCondDataSize), 8825, 8831, 0,
-	/*8825*/ uint16(xSetOp), uint16(BOUND),
-	/*8827*/ uint16(xReadSlashR),
-	/*8828*/ uint16(xArgR16),
-	/*8829*/ uint16(xArgM16and16),
-	/*8830*/ uint16(xMatch),
-	/*8831*/ uint16(xSetOp), uint16(BOUND),
-	/*8833*/ uint16(xReadSlashR),
-	/*8834*/ uint16(xArgR32),
-	/*8835*/ uint16(xArgM32and32),
-	/*8836*/ uint16(xMatch),
-	/*8837*/ uint16(xCondIs64), 8840, 8846,
-	/*8840*/ uint16(xSetOp), uint16(ARPL),
-	/*8842*/ uint16(xReadSlashR),
-	/*8843*/ uint16(xArgRM16),
-	/*8844*/ uint16(xArgR16),
-	/*8845*/ uint16(xMatch),
-	/*8846*/ uint16(xCondDataSize), 8850, 8856, 8862,
-	/*8850*/ uint16(xSetOp), uint16(MOVSXD),
-	/*8852*/ uint16(xReadSlashR),
-	/*8853*/ uint16(xArgR16),
-	/*8854*/ uint16(xArgRM32),
-	/*8855*/ uint16(xMatch),
-	/*8856*/ uint16(xSetOp), uint16(MOVSXD),
-	/*8858*/ uint16(xReadSlashR),
-	/*8859*/ uint16(xArgR32),
-	/*8860*/ uint16(xArgRM32),
-	/*8861*/ uint16(xMatch),
-	/*8862*/ uint16(xSetOp), uint16(MOVSXD),
-	/*8864*/ uint16(xReadSlashR),
-	/*8865*/ uint16(xArgR64),
-	/*8866*/ uint16(xArgRM32),
-	/*8867*/ uint16(xMatch),
-	/*8868*/ uint16(xCondDataSize), 8872, 8877, 8882,
-	/*8872*/ uint16(xSetOp), uint16(PUSH),
-	/*8874*/ uint16(xReadIw),
-	/*8875*/ uint16(xArgImm16),
-	/*8876*/ uint16(xMatch),
-	/*8877*/ uint16(xSetOp), uint16(PUSH),
-	/*8879*/ uint16(xReadId),
-	/*8880*/ uint16(xArgImm32),
+	/*8738*/ uint16(xCondIs64), 8741, 0,
+	/*8741*/ uint16(xSetOp), uint16(AAS),
+	/*8743*/ uint16(xMatch),
+	/*8744*/ uint16(xCondIs64), 8747, 0,
+	/*8747*/ uint16(xCondDataSize), 8751, 8755, 0,
+	/*8751*/ uint16(xSetOp), uint16(INC),
+	/*8753*/ uint16(xArgR16op),
+	/*8754*/ uint16(xMatch),
+	/*8755*/ uint16(xSetOp), uint16(INC),
+	/*8757*/ uint16(xArgR32op),
+	/*8758*/ uint16(xMatch),
+	/*8759*/ uint16(xCondIs64), 8762, 0,
+	/*8762*/ uint16(xCondDataSize), 8766, 8770, 0,
+	/*8766*/ uint16(xSetOp), uint16(DEC),
+	/*8768*/ uint16(xArgR16op),
+	/*8769*/ uint16(xMatch),
+	/*8770*/ uint16(xSetOp), uint16(DEC),
+	/*8772*/ uint16(xArgR32op),
+	/*8773*/ uint16(xMatch),
+	/*8774*/ uint16(xCondIs64), 8777, 8789,
+	/*8777*/ uint16(xCondDataSize), 8781, 8785, 0,
+	/*8781*/ uint16(xSetOp), uint16(PUSH),
+	/*8783*/ uint16(xArgR16op),
+	/*8784*/ uint16(xMatch),
+	/*8785*/ uint16(xSetOp), uint16(PUSH),
+	/*8787*/ uint16(xArgR32op),
+	/*8788*/ uint16(xMatch),
+	/*8789*/ uint16(xCondDataSize), 8781, 8793, 8797,
+	/*8793*/ uint16(xSetOp), uint16(PUSH),
+	/*8795*/ uint16(xArgR64op),
+	/*8796*/ uint16(xMatch),
+	/*8797*/ uint16(xSetOp), uint16(PUSH),
+	/*8799*/ uint16(xArgR64op),
+	/*8800*/ uint16(xMatch),
+	/*8801*/ uint16(xCondIs64), 8804, 8816,
+	/*8804*/ uint16(xCondDataSize), 8808, 8812, 0,
+	/*8808*/ uint16(xSetOp), uint16(POP),
+	/*8810*/ uint16(xArgR16op),
+	/*8811*/ uint16(xMatch),
+	/*8812*/ uint16(xSetOp), uint16(POP),
+	/*8814*/ uint16(xArgR32op),
+	/*8815*/ uint16(xMatch),
+	/*8816*/ uint16(xCondDataSize), 8808, 8820, 8824,
+	/*8820*/ uint16(xSetOp), uint16(POP),
+	/*8822*/ uint16(xArgR64op),
+	/*8823*/ uint16(xMatch),
+	/*8824*/ uint16(xSetOp), uint16(POP),
+	/*8826*/ uint16(xArgR64op),
+	/*8827*/ uint16(xMatch),
+	/*8828*/ uint16(xCondIs64), 8831, 0,
+	/*8831*/ uint16(xCondDataSize), 8835, 8838, 0,
+	/*8835*/ uint16(xSetOp), uint16(PUSHA),
+	/*8837*/ uint16(xMatch),
+	/*8838*/ uint16(xSetOp), uint16(PUSHAD),
+	/*8840*/ uint16(xMatch),
+	/*8841*/ uint16(xCondIs64), 8844, 0,
+	/*8844*/ uint16(xCondDataSize), 8848, 8851, 0,
+	/*8848*/ uint16(xSetOp), uint16(POPA),
+	/*8850*/ uint16(xMatch),
+	/*8851*/ uint16(xSetOp), uint16(POPAD),
+	/*8853*/ uint16(xMatch),
+	/*8854*/ uint16(xCondIs64), 8857, 0,
+	/*8857*/ uint16(xCondDataSize), 8861, 8867, 0,
+	/*8861*/ uint16(xSetOp), uint16(BOUND),
+	/*8863*/ uint16(xReadSlashR),
+	/*8864*/ uint16(xArgR16),
+	/*8865*/ uint16(xArgM16and16),
+	/*8866*/ uint16(xMatch),
+	/*8867*/ uint16(xSetOp), uint16(BOUND),
+	/*8869*/ uint16(xReadSlashR),
+	/*8870*/ uint16(xArgR32),
+	/*8871*/ uint16(xArgM32and32),
+	/*8872*/ uint16(xMatch),
+	/*8873*/ uint16(xCondIs64), 8876, 8882,
+	/*8876*/ uint16(xSetOp), uint16(ARPL),
+	/*8878*/ uint16(xReadSlashR),
+	/*8879*/ uint16(xArgRM16),
+	/*8880*/ uint16(xArgR16),
 	/*8881*/ uint16(xMatch),
-	/*8882*/ uint16(xSetOp), uint16(PUSH),
-	/*8884*/ uint16(xReadId),
-	/*8885*/ uint16(xArgImm32),
-	/*8886*/ uint16(xMatch),
-	/*8887*/ uint16(xCondIs64), 8890, 8910,
-	/*8890*/ uint16(xCondDataSize), 8894, 8902, 0,
-	/*8894*/ uint16(xSetOp), uint16(IMUL),
-	/*8896*/ uint16(xReadSlashR),
-	/*8897*/ uint16(xReadIw),
-	/*8898*/ uint16(xArgR16),
-	/*8899*/ uint16(xArgRM16),
-	/*8900*/ uint16(xArgImm16),
-	/*8901*/ uint16(xMatch),
-	/*8902*/ uint16(xSetOp), uint16(IMUL),
-	/*8904*/ uint16(xReadSlashR),
-	/*8905*/ uint16(xReadId),
-	/*8906*/ uint16(xArgR32),
-	/*8907*/ uint16(xArgRM32),
-	/*8908*/ uint16(xArgImm32),
-	/*8909*/ uint16(xMatch),
-	/*8910*/ uint16(xCondDataSize), 8894, 8902, 8914,
-	/*8914*/ uint16(xSetOp), uint16(IMUL),
-	/*8916*/ uint16(xReadSlashR),
-	/*8917*/ uint16(xReadId),
-	/*8918*/ uint16(xArgR64),
-	/*8919*/ uint16(xArgRM64),
-	/*8920*/ uint16(xArgImm32),
-	/*8921*/ uint16(xMatch),
-	/*8922*/ uint16(xSetOp), uint16(PUSH),
-	/*8924*/ uint16(xReadIb),
-	/*8925*/ uint16(xArgImm8),
-	/*8926*/ uint16(xMatch),
-	/*8927*/ uint16(xCondIs64), 8930, 8950,
-	/*8930*/ uint16(xCondDataSize), 8934, 8942, 0,
-	/*8934*/ uint16(xSetOp), uint16(IMUL),
-	/*8936*/ uint16(xReadSlashR),
-	/*8937*/ uint16(xReadIb),
-	/*8938*/ uint16(xArgR16),
-	/*8939*/ uint16(xArgRM16),
-	/*8940*/ uint16(xArgImm8),
-	/*8941*/ uint16(xMatch),
-	/*8942*/ uint16(xSetOp), uint16(IMUL),
-	/*8944*/ uint16(xReadSlashR),
-	/*8945*/ uint16(xReadIb),
-	/*8946*/ uint16(xArgR32),
-	/*8947*/ uint16(xArgRM32),
-	/*8948*/ uint16(xArgImm8),
-	/*8949*/ uint16(xMatch),
-	/*8950*/ uint16(xCondDataSize), 8934, 8942, 8954,
-	/*8954*/ uint16(xSetOp), uint16(IMUL),
-	/*8956*/ uint16(xReadSlashR),
-	/*8957*/ uint16(xReadIb),
-	/*8958*/ uint16(xArgR64),
-	/*8959*/ uint16(xArgRM64),
-	/*8960*/ uint16(xArgImm8),
-	/*8961*/ uint16(xMatch),
-	/*8962*/ uint16(xSetOp), uint16(INSB),
-	/*8964*/ uint16(xMatch),
-	/*8965*/ uint16(xCondDataSize), 8969, 8972, 8975,
-	/*8969*/ uint16(xSetOp), uint16(INSW),
-	/*8971*/ uint16(xMatch),
-	/*8972*/ uint16(xSetOp), uint16(INSD),
-	/*8974*/ uint16(xMatch),
-	/*8975*/ uint16(xSetOp), uint16(INSD),
+	/*8882*/ uint16(xCondDataSize), 8886, 8892, 8898,
+	/*8886*/ uint16(xSetOp), uint16(MOVSXD),
+	/*8888*/ uint16(xReadSlashR),
+	/*8889*/ uint16(xArgR16),
+	/*8890*/ uint16(xArgRM32),
+	/*8891*/ uint16(xMatch),
+	/*8892*/ uint16(xSetOp), uint16(MOVSXD),
+	/*8894*/ uint16(xReadSlashR),
+	/*8895*/ uint16(xArgR32),
+	/*8896*/ uint16(xArgRM32),
+	/*8897*/ uint16(xMatch),
+	/*8898*/ uint16(xSetOp), uint16(MOVSXD),
+	/*8900*/ uint16(xReadSlashR),
+	/*8901*/ uint16(xArgR64),
+	/*8902*/ uint16(xArgRM32),
+	/*8903*/ uint16(xMatch),
+	/*8904*/ uint16(xCondDataSize), 8908, 8913, 8918,
+	/*8908*/ uint16(xSetOp), uint16(PUSH),
+	/*8910*/ uint16(xReadIw),
+	/*8911*/ uint16(xArgImm16),
+	/*8912*/ uint16(xMatch),
+	/*8913*/ uint16(xSetOp), uint16(PUSH),
+	/*8915*/ uint16(xReadId),
+	/*8916*/ uint16(xArgImm32),
+	/*8917*/ uint16(xMatch),
+	/*8918*/ uint16(xSetOp), uint16(PUSH),
+	/*8920*/ uint16(xReadId),
+	/*8921*/ uint16(xArgImm32),
+	/*8922*/ uint16(xMatch),
+	/*8923*/ uint16(xCondIs64), 8926, 8946,
+	/*8926*/ uint16(xCondDataSize), 8930, 8938, 0,
+	/*8930*/ uint16(xSetOp), uint16(IMUL),
+	/*8932*/ uint16(xReadSlashR),
+	/*8933*/ uint16(xReadIw),
+	/*8934*/ uint16(xArgR16),
+	/*8935*/ uint16(xArgRM16),
+	/*8936*/ uint16(xArgImm16),
+	/*8937*/ uint16(xMatch),
+	/*8938*/ uint16(xSetOp), uint16(IMUL),
+	/*8940*/ uint16(xReadSlashR),
+	/*8941*/ uint16(xReadId),
+	/*8942*/ uint16(xArgR32),
+	/*8943*/ uint16(xArgRM32),
+	/*8944*/ uint16(xArgImm32),
+	/*8945*/ uint16(xMatch),
+	/*8946*/ uint16(xCondDataSize), 8930, 8938, 8950,
+	/*8950*/ uint16(xSetOp), uint16(IMUL),
+	/*8952*/ uint16(xReadSlashR),
+	/*8953*/ uint16(xReadId),
+	/*8954*/ uint16(xArgR64),
+	/*8955*/ uint16(xArgRM64),
+	/*8956*/ uint16(xArgImm32),
+	/*8957*/ uint16(xMatch),
+	/*8958*/ uint16(xSetOp), uint16(PUSH),
+	/*8960*/ uint16(xReadIb),
+	/*8961*/ uint16(xArgImm8),
+	/*8962*/ uint16(xMatch),
+	/*8963*/ uint16(xCondIs64), 8966, 8986,
+	/*8966*/ uint16(xCondDataSize), 8970, 8978, 0,
+	/*8970*/ uint16(xSetOp), uint16(IMUL),
+	/*8972*/ uint16(xReadSlashR),
+	/*8973*/ uint16(xReadIb),
+	/*8974*/ uint16(xArgR16),
+	/*8975*/ uint16(xArgRM16),
+	/*8976*/ uint16(xArgImm8),
 	/*8977*/ uint16(xMatch),
-	/*8978*/ uint16(xSetOp), uint16(OUTSB),
-	/*8980*/ uint16(xMatch),
-	/*8981*/ uint16(xCondDataSize), 8985, 8988, 8991,
-	/*8985*/ uint16(xSetOp), uint16(OUTSW),
-	/*8987*/ uint16(xMatch),
-	/*8988*/ uint16(xSetOp), uint16(OUTSD),
-	/*8990*/ uint16(xMatch),
-	/*8991*/ uint16(xSetOp), uint16(OUTSD),
-	/*8993*/ uint16(xMatch),
-	/*8994*/ uint16(xSetOp), uint16(JO),
-	/*8996*/ uint16(xReadCb),
-	/*8997*/ uint16(xArgRel8),
-	/*8998*/ uint16(xMatch),
-	/*8999*/ uint16(xSetOp), uint16(JNO),
-	/*9001*/ uint16(xReadCb),
-	/*9002*/ uint16(xArgRel8),
-	/*9003*/ uint16(xMatch),
-	/*9004*/ uint16(xSetOp), uint16(JB),
-	/*9006*/ uint16(xReadCb),
-	/*9007*/ uint16(xArgRel8),
-	/*9008*/ uint16(xMatch),
-	/*9009*/ uint16(xSetOp), uint16(JAE),
-	/*9011*/ uint16(xReadCb),
-	/*9012*/ uint16(xArgRel8),
+	/*8978*/ uint16(xSetOp), uint16(IMUL),
+	/*8980*/ uint16(xReadSlashR),
+	/*8981*/ uint16(xReadIb),
+	/*8982*/ uint16(xArgR32),
+	/*8983*/ uint16(xArgRM32),
+	/*8984*/ uint16(xArgImm8),
+	/*8985*/ uint16(xMatch),
+	/*8986*/ uint16(xCondDataSize), 8970, 8978, 8990,
+	/*8990*/ uint16(xSetOp), uint16(IMUL),
+	/*8992*/ uint16(xReadSlashR),
+	/*8993*/ uint16(xReadIb),
+	/*8994*/ uint16(xArgR64),
+	/*8995*/ uint16(xArgRM64),
+	/*8996*/ uint16(xArgImm8),
+	/*8997*/ uint16(xMatch),
+	/*8998*/ uint16(xSetOp), uint16(INSB),
+	/*9000*/ uint16(xMatch),
+	/*9001*/ uint16(xCondDataSize), 9005, 9008, 9011,
+	/*9005*/ uint16(xSetOp), uint16(INSW),
+	/*9007*/ uint16(xMatch),
+	/*9008*/ uint16(xSetOp), uint16(INSD),
+	/*9010*/ uint16(xMatch),
+	/*9011*/ uint16(xSetOp), uint16(INSD),
 	/*9013*/ uint16(xMatch),
-	/*9014*/ uint16(xSetOp), uint16(JE),
-	/*9016*/ uint16(xReadCb),
-	/*9017*/ uint16(xArgRel8),
-	/*9018*/ uint16(xMatch),
-	/*9019*/ uint16(xSetOp), uint16(JNE),
-	/*9021*/ uint16(xReadCb),
-	/*9022*/ uint16(xArgRel8),
-	/*9023*/ uint16(xMatch),
-	/*9024*/ uint16(xSetOp), uint16(JBE),
-	/*9026*/ uint16(xReadCb),
-	/*9027*/ uint16(xArgRel8),
-	/*9028*/ uint16(xMatch),
-	/*9029*/ uint16(xSetOp), uint16(JA),
-	/*9031*/ uint16(xReadCb),
-	/*9032*/ uint16(xArgRel8),
-	/*9033*/ uint16(xMatch),
-	/*9034*/ uint16(xSetOp), uint16(JS),
-	/*9036*/ uint16(xReadCb),
-	/*9037*/ uint16(xArgRel8),
-	/*9038*/ uint16(xMatch),
-	/*9039*/ uint16(xSetOp), uint16(JNS),
-	/*9041*/ uint16(xReadCb),
-	/*9042*/ uint16(xArgRel8),
-	/*9043*/ uint16(xMatch),
-	/*9044*/ uint16(xSetOp), uint16(JP),
-	/*9046*/ uint16(xReadCb),
-	/*9047*/ uint16(xArgRel8),
-	/*9048*/ uint16(xMatch),
-	/*9049*/ uint16(xSetOp), uint16(JNP),
-	/*9051*/ uint16(xReadCb),
-	/*9052*/ uint16(xArgRel8),
+	/*9014*/ uint16(xSetOp), uint16(OUTSB),
+	/*9016*/ uint16(xMatch),
+	/*9017*/ uint16(xCondPrefix), 3,
+	0xC5, 9064,
+	0xC4, 9038,
+	0x0, 9025,
+	/*9025*/ uint16(xCondDataSize), 9029, 9032, 9035,
+	/*9029*/ uint16(xSetOp), uint16(OUTSW),
+	/*9031*/ uint16(xMatch),
+	/*9032*/ uint16(xSetOp), uint16(OUTSD),
+	/*9034*/ uint16(xMatch),
+	/*9035*/ uint16(xSetOp), uint16(OUTSD),
+	/*9037*/ uint16(xMatch),
+	/*9038*/ uint16(xCondPrefix), 2,
+	0xF3, 9054,
+	0x66, 9044,
+	/*9044*/ uint16(xCondPrefix), 1,
+	0x0F, 9048,
+	/*9048*/ uint16(xSetOp), uint16(VMOVDQA),
+	/*9050*/ uint16(xReadSlashR),
+	/*9051*/ uint16(xArgYmm1),
+	/*9052*/ uint16(xArgYmm2M256),
 	/*9053*/ uint16(xMatch),
-	/*9054*/ uint16(xSetOp), uint16(JL),
-	/*9056*/ uint16(xReadCb),
-	/*9057*/ uint16(xArgRel8),
-	/*9058*/ uint16(xMatch),
-	/*9059*/ uint16(xSetOp), uint16(JGE),
-	/*9061*/ uint16(xReadCb),
-	/*9062*/ uint16(xArgRel8),
+	/*9054*/ uint16(xCondPrefix), 1,
+	0x0F, 9058,
+	/*9058*/ uint16(xSetOp), uint16(VMOVDQU),
+	/*9060*/ uint16(xReadSlashR),
+	/*9061*/ uint16(xArgYmm1),
+	/*9062*/ uint16(xArgYmm2M256),
 	/*9063*/ uint16(xMatch),
-	/*9064*/ uint16(xSetOp), uint16(JLE),
-	/*9066*/ uint16(xReadCb),
-	/*9067*/ uint16(xArgRel8),
-	/*9068*/ uint16(xMatch),
-	/*9069*/ uint16(xSetOp), uint16(JG),
-	/*9071*/ uint16(xReadCb),
-	/*9072*/ uint16(xArgRel8),
-	/*9073*/ uint16(xMatch),
-	/*9074*/ uint16(xCondSlashR),
-	9083, // 0
-	9089, // 1
-	9095, // 2
-	9101, // 3
-	9107, // 4
-	9113, // 5
-	9119, // 6
-	9125, // 7
-	/*9083*/ uint16(xSetOp), uint16(ADD),
-	/*9085*/ uint16(xReadIb),
-	/*9086*/ uint16(xArgRM8),
-	/*9087*/ uint16(xArgImm8u),
-	/*9088*/ uint16(xMatch),
-	/*9089*/ uint16(xSetOp), uint16(OR),
-	/*9091*/ uint16(xReadIb),
-	/*9092*/ uint16(xArgRM8),
-	/*9093*/ uint16(xArgImm8u),
+	/*9064*/ uint16(xCondPrefix), 2,
+	0xF3, 9080,
+	0x66, 9070,
+	/*9070*/ uint16(xCondPrefix), 1,
+	0x0F, 9074,
+	/*9074*/ uint16(xSetOp), uint16(VMOVDQA),
+	/*9076*/ uint16(xReadSlashR),
+	/*9077*/ uint16(xArgYmm1),
+	/*9078*/ uint16(xArgYmm2M256),
+	/*9079*/ uint16(xMatch),
+	/*9080*/ uint16(xCondPrefix), 1,
+	0x0F, 9084,
+	/*9084*/ uint16(xSetOp), uint16(VMOVDQU),
+	/*9086*/ uint16(xReadSlashR),
+	/*9087*/ uint16(xArgYmm1),
+	/*9088*/ uint16(xArgYmm2M256),
+	/*9089*/ uint16(xMatch),
+	/*9090*/ uint16(xSetOp), uint16(JO),
+	/*9092*/ uint16(xReadCb),
+	/*9093*/ uint16(xArgRel8),
 	/*9094*/ uint16(xMatch),
-	/*9095*/ uint16(xSetOp), uint16(ADC),
-	/*9097*/ uint16(xReadIb),
-	/*9098*/ uint16(xArgRM8),
-	/*9099*/ uint16(xArgImm8u),
-	/*9100*/ uint16(xMatch),
-	/*9101*/ uint16(xSetOp), uint16(SBB),
-	/*9103*/ uint16(xReadIb),
-	/*9104*/ uint16(xArgRM8),
-	/*9105*/ uint16(xArgImm8u),
-	/*9106*/ uint16(xMatch),
-	/*9107*/ uint16(xSetOp), uint16(AND),
-	/*9109*/ uint16(xReadIb),
-	/*9110*/ uint16(xArgRM8),
-	/*9111*/ uint16(xArgImm8u),
-	/*9112*/ uint16(xMatch),
-	/*9113*/ uint16(xSetOp), uint16(SUB),
-	/*9115*/ uint16(xReadIb),
-	/*9116*/ uint16(xArgRM8),
-	/*9117*/ uint16(xArgImm8u),
-	/*9118*/ uint16(xMatch),
-	/*9119*/ uint16(xSetOp), uint16(XOR),
-	/*9121*/ uint16(xReadIb),
-	/*9122*/ uint16(xArgRM8),
-	/*9123*/ uint16(xArgImm8u),
+	/*9095*/ uint16(xSetOp), uint16(JNO),
+	/*9097*/ uint16(xReadCb),
+	/*9098*/ uint16(xArgRel8),
+	/*9099*/ uint16(xMatch),
+	/*9100*/ uint16(xSetOp), uint16(JB),
+	/*9102*/ uint16(xReadCb),
+	/*9103*/ uint16(xArgRel8),
+	/*9104*/ uint16(xMatch),
+	/*9105*/ uint16(xSetOp), uint16(JAE),
+	/*9107*/ uint16(xReadCb),
+	/*9108*/ uint16(xArgRel8),
+	/*9109*/ uint16(xMatch),
+	/*9110*/ uint16(xSetOp), uint16(JE),
+	/*9112*/ uint16(xReadCb),
+	/*9113*/ uint16(xArgRel8),
+	/*9114*/ uint16(xMatch),
+	/*9115*/ uint16(xSetOp), uint16(JNE),
+	/*9117*/ uint16(xReadCb),
+	/*9118*/ uint16(xArgRel8),
+	/*9119*/ uint16(xMatch),
+	/*9120*/ uint16(xSetOp), uint16(JBE),
+	/*9122*/ uint16(xReadCb),
+	/*9123*/ uint16(xArgRel8),
 	/*9124*/ uint16(xMatch),
-	/*9125*/ uint16(xSetOp), uint16(CMP),
-	/*9127*/ uint16(xReadIb),
-	/*9128*/ uint16(xArgRM8),
-	/*9129*/ uint16(xArgImm8u),
-	/*9130*/ uint16(xMatch),
-	/*9131*/ uint16(xCondSlashR),
-	9140, // 0
-	9169, // 1
-	9198, // 2
-	9227, // 3
-	9256, // 4
-	9285, // 5
-	9314, // 6
-	9343, // 7
-	/*9140*/ uint16(xCondIs64), 9143, 9159,
-	/*9143*/ uint16(xCondDataSize), 9147, 9153, 0,
-	/*9147*/ uint16(xSetOp), uint16(ADD),
-	/*9149*/ uint16(xReadIw),
-	/*9150*/ uint16(xArgRM16),
-	/*9151*/ uint16(xArgImm16),
-	/*9152*/ uint16(xMatch),
-	/*9153*/ uint16(xSetOp), uint16(ADD),
-	/*9155*/ uint16(xReadId),
-	/*9156*/ uint16(xArgRM32),
-	/*9157*/ uint16(xArgImm32),
-	/*9158*/ uint16(xMatch),
-	/*9159*/ uint16(xCondDataSize), 9147, 9153, 9163,
-	/*9163*/ uint16(xSetOp), uint16(ADD),
-	/*9165*/ uint16(xReadId),
-	/*9166*/ uint16(xArgRM64),
-	/*9167*/ uint16(xArgImm32),
-	/*9168*/ uint16(xMatch),
-	/*9169*/ uint16(xCondIs64), 9172, 9188,
-	/*9172*/ uint16(xCondDataSize), 9176, 9182, 0,
-	/*9176*/ uint16(xSetOp), uint16(OR),
-	/*9178*/ uint16(xReadIw),
-	/*9179*/ uint16(xArgRM16),
-	/*9180*/ uint16(xArgImm16),
+	/*9125*/ uint16(xCondPrefix), 3,
+	0xC5, 9145,
+	0xC4, 9138,
+	0x0, 9133,
+	/*9133*/ uint16(xSetOp), uint16(JA),
+	/*9135*/ uint16(xReadCb),
+	/*9136*/ uint16(xArgRel8),
+	/*9137*/ uint16(xMatch),
+	/*9138*/ uint16(xCondPrefix), 1,
+	0x0F, 9142,
+	/*9142*/ uint16(xSetOp), uint16(VZEROUPPER),
+	/*9144*/ uint16(xMatch),
+	/*9145*/ uint16(xCondPrefix), 1,
+	0x0F, 9149,
+	/*9149*/ uint16(xSetOp), uint16(VZEROUPPER),
+	/*9151*/ uint16(xMatch),
+	/*9152*/ uint16(xSetOp), uint16(JS),
+	/*9154*/ uint16(xReadCb),
+	/*9155*/ uint16(xArgRel8),
+	/*9156*/ uint16(xMatch),
+	/*9157*/ uint16(xSetOp), uint16(JNS),
+	/*9159*/ uint16(xReadCb),
+	/*9160*/ uint16(xArgRel8),
+	/*9161*/ uint16(xMatch),
+	/*9162*/ uint16(xSetOp), uint16(JP),
+	/*9164*/ uint16(xReadCb),
+	/*9165*/ uint16(xArgRel8),
+	/*9166*/ uint16(xMatch),
+	/*9167*/ uint16(xSetOp), uint16(JNP),
+	/*9169*/ uint16(xReadCb),
+	/*9170*/ uint16(xArgRel8),
+	/*9171*/ uint16(xMatch),
+	/*9172*/ uint16(xSetOp), uint16(JL),
+	/*9174*/ uint16(xReadCb),
+	/*9175*/ uint16(xArgRel8),
+	/*9176*/ uint16(xMatch),
+	/*9177*/ uint16(xSetOp), uint16(JGE),
+	/*9179*/ uint16(xReadCb),
+	/*9180*/ uint16(xArgRel8),
 	/*9181*/ uint16(xMatch),
-	/*9182*/ uint16(xSetOp), uint16(OR),
-	/*9184*/ uint16(xReadId),
-	/*9185*/ uint16(xArgRM32),
-	/*9186*/ uint16(xArgImm32),
-	/*9187*/ uint16(xMatch),
-	/*9188*/ uint16(xCondDataSize), 9176, 9182, 9192,
-	/*9192*/ uint16(xSetOp), uint16(OR),
-	/*9194*/ uint16(xReadId),
-	/*9195*/ uint16(xArgRM64),
-	/*9196*/ uint16(xArgImm32),
-	/*9197*/ uint16(xMatch),
-	/*9198*/ uint16(xCondIs64), 9201, 9217,
-	/*9201*/ uint16(xCondDataSize), 9205, 9211, 0,
-	/*9205*/ uint16(xSetOp), uint16(ADC),
-	/*9207*/ uint16(xReadIw),
-	/*9208*/ uint16(xArgRM16),
-	/*9209*/ uint16(xArgImm16),
-	/*9210*/ uint16(xMatch),
-	/*9211*/ uint16(xSetOp), uint16(ADC),
-	/*9213*/ uint16(xReadId),
-	/*9214*/ uint16(xArgRM32),
-	/*9215*/ uint16(xArgImm32),
-	/*9216*/ uint16(xMatch),
-	/*9217*/ uint16(xCondDataSize), 9205, 9211, 9221,
-	/*9221*/ uint16(xSetOp), uint16(ADC),
-	/*9223*/ uint16(xReadId),
-	/*9224*/ uint16(xArgRM64),
-	/*9225*/ uint16(xArgImm32),
-	/*9226*/ uint16(xMatch),
-	/*9227*/ uint16(xCondIs64), 9230, 9246,
-	/*9230*/ uint16(xCondDataSize), 9234, 9240, 0,
-	/*9234*/ uint16(xSetOp), uint16(SBB),
-	/*9236*/ uint16(xReadIw),
-	/*9237*/ uint16(xArgRM16),
-	/*9238*/ uint16(xArgImm16),
-	/*9239*/ uint16(xMatch),
-	/*9240*/ uint16(xSetOp), uint16(SBB),
-	/*9242*/ uint16(xReadId),
-	/*9243*/ uint16(xArgRM32),
-	/*9244*/ uint16(xArgImm32),
-	/*9245*/ uint16(xMatch),
-	/*9246*/ uint16(xCondDataSize), 9234, 9240, 9250,
-	/*9250*/ uint16(xSetOp), uint16(SBB),
-	/*9252*/ uint16(xReadId),
-	/*9253*/ uint16(xArgRM64),
-	/*9254*/ uint16(xArgImm32),
-	/*9255*/ uint16(xMatch),
-	/*9256*/ uint16(xCondIs64), 9259, 9275,
-	/*9259*/ uint16(xCondDataSize), 9263, 9269, 0,
-	/*9263*/ uint16(xSetOp), uint16(AND),
-	/*9265*/ uint16(xReadIw),
-	/*9266*/ uint16(xArgRM16),
-	/*9267*/ uint16(xArgImm16),
-	/*9268*/ uint16(xMatch),
-	/*9269*/ uint16(xSetOp), uint16(AND),
-	/*9271*/ uint16(xReadId),
-	/*9272*/ uint16(xArgRM32),
-	/*9273*/ uint16(xArgImm32),
-	/*9274*/ uint16(xMatch),
-	/*9275*/ uint16(xCondDataSize), 9263, 9269, 9279,
-	/*9279*/ uint16(xSetOp), uint16(AND),
-	/*9281*/ uint16(xReadId),
-	/*9282*/ uint16(xArgRM64),
-	/*9283*/ uint16(xArgImm32),
+	/*9182*/ uint16(xSetOp), uint16(JLE),
+	/*9184*/ uint16(xReadCb),
+	/*9185*/ uint16(xArgRel8),
+	/*9186*/ uint16(xMatch),
+	/*9187*/ uint16(xCondPrefix), 3,
+	0xC5, 9226,
+	0xC4, 9200,
+	0x0, 9195,
+	/*9195*/ uint16(xSetOp), uint16(JG),
+	/*9197*/ uint16(xReadCb),
+	/*9198*/ uint16(xArgRel8),
+	/*9199*/ uint16(xMatch),
+	/*9200*/ uint16(xCondPrefix), 2,
+	0xF3, 9216,
+	0x66, 9206,
+	/*9206*/ uint16(xCondPrefix), 1,
+	0x0F, 9210,
+	/*9210*/ uint16(xSetOp), uint16(VMOVDQA),
+	/*9212*/ uint16(xReadSlashR),
+	/*9213*/ uint16(xArgYmm2M256),
+	/*9214*/ uint16(xArgYmm1),
+	/*9215*/ uint16(xMatch),
+	/*9216*/ uint16(xCondPrefix), 1,
+	0x0F, 9220,
+	/*9220*/ uint16(xSetOp), uint16(VMOVDQU),
+	/*9222*/ uint16(xReadSlashR),
+	/*9223*/ uint16(xArgYmm2M256),
+	/*9224*/ uint16(xArgYmm1),
+	/*9225*/ uint16(xMatch),
+	/*9226*/ uint16(xCondPrefix), 2,
+	0xF3, 9242,
+	0x66, 9232,
+	/*9232*/ uint16(xCondPrefix), 1,
+	0x0F, 9236,
+	/*9236*/ uint16(xSetOp), uint16(VMOVDQA),
+	/*9238*/ uint16(xReadSlashR),
+	/*9239*/ uint16(xArgYmm2M256),
+	/*9240*/ uint16(xArgYmm1),
+	/*9241*/ uint16(xMatch),
+	/*9242*/ uint16(xCondPrefix), 1,
+	0x0F, 9246,
+	/*9246*/ uint16(xSetOp), uint16(VMOVDQU),
+	/*9248*/ uint16(xReadSlashR),
+	/*9249*/ uint16(xArgYmm2M256),
+	/*9250*/ uint16(xArgYmm1),
+	/*9251*/ uint16(xMatch),
+	/*9252*/ uint16(xCondSlashR),
+	9261, // 0
+	9267, // 1
+	9273, // 2
+	9279, // 3
+	9285, // 4
+	9291, // 5
+	9297, // 6
+	9303, // 7
+	/*9261*/ uint16(xSetOp), uint16(ADD),
+	/*9263*/ uint16(xReadIb),
+	/*9264*/ uint16(xArgRM8),
+	/*9265*/ uint16(xArgImm8u),
+	/*9266*/ uint16(xMatch),
+	/*9267*/ uint16(xSetOp), uint16(OR),
+	/*9269*/ uint16(xReadIb),
+	/*9270*/ uint16(xArgRM8),
+	/*9271*/ uint16(xArgImm8u),
+	/*9272*/ uint16(xMatch),
+	/*9273*/ uint16(xSetOp), uint16(ADC),
+	/*9275*/ uint16(xReadIb),
+	/*9276*/ uint16(xArgRM8),
+	/*9277*/ uint16(xArgImm8u),
+	/*9278*/ uint16(xMatch),
+	/*9279*/ uint16(xSetOp), uint16(SBB),
+	/*9281*/ uint16(xReadIb),
+	/*9282*/ uint16(xArgRM8),
+	/*9283*/ uint16(xArgImm8u),
 	/*9284*/ uint16(xMatch),
-	/*9285*/ uint16(xCondIs64), 9288, 9304,
-	/*9288*/ uint16(xCondDataSize), 9292, 9298, 0,
-	/*9292*/ uint16(xSetOp), uint16(SUB),
-	/*9294*/ uint16(xReadIw),
-	/*9295*/ uint16(xArgRM16),
-	/*9296*/ uint16(xArgImm16),
-	/*9297*/ uint16(xMatch),
-	/*9298*/ uint16(xSetOp), uint16(SUB),
-	/*9300*/ uint16(xReadId),
-	/*9301*/ uint16(xArgRM32),
-	/*9302*/ uint16(xArgImm32),
-	/*9303*/ uint16(xMatch),
-	/*9304*/ uint16(xCondDataSize), 9292, 9298, 9308,
-	/*9308*/ uint16(xSetOp), uint16(SUB),
-	/*9310*/ uint16(xReadId),
-	/*9311*/ uint16(xArgRM64),
-	/*9312*/ uint16(xArgImm32),
-	/*9313*/ uint16(xMatch),
-	/*9314*/ uint16(xCondIs64), 9317, 9333,
-	/*9317*/ uint16(xCondDataSize), 9321, 9327, 0,
-	/*9321*/ uint16(xSetOp), uint16(XOR),
-	/*9323*/ uint16(xReadIw),
-	/*9324*/ uint16(xArgRM16),
-	/*9325*/ uint16(xArgImm16),
-	/*9326*/ uint16(xMatch),
-	/*9327*/ uint16(xSetOp), uint16(XOR),
-	/*9329*/ uint16(xReadId),
-	/*9330*/ uint16(xArgRM32),
-	/*9331*/ uint16(xArgImm32),
-	/*9332*/ uint16(xMatch),
-	/*9333*/ uint16(xCondDataSize), 9321, 9327, 9337,
-	/*9337*/ uint16(xSetOp), uint16(XOR),
-	/*9339*/ uint16(xReadId),
-	/*9340*/ uint16(xArgRM64),
-	/*9341*/ uint16(xArgImm32),
-	/*9342*/ uint16(xMatch),
-	/*9343*/ uint16(xCondIs64), 9346, 9362,
-	/*9346*/ uint16(xCondDataSize), 9350, 9356, 0,
-	/*9350*/ uint16(xSetOp), uint16(CMP),
-	/*9352*/ uint16(xReadIw),
-	/*9353*/ uint16(xArgRM16),
-	/*9354*/ uint16(xArgImm16),
-	/*9355*/ uint16(xMatch),
-	/*9356*/ uint16(xSetOp), uint16(CMP),
-	/*9358*/ uint16(xReadId),
-	/*9359*/ uint16(xArgRM32),
-	/*9360*/ uint16(xArgImm32),
-	/*9361*/ uint16(xMatch),
-	/*9362*/ uint16(xCondDataSize), 9350, 9356, 9366,
-	/*9366*/ uint16(xSetOp), uint16(CMP),
-	/*9368*/ uint16(xReadId),
-	/*9369*/ uint16(xArgRM64),
-	/*9370*/ uint16(xArgImm32),
-	/*9371*/ uint16(xMatch),
-	/*9372*/ uint16(xCondSlashR),
-	9381, // 0
-	9410, // 1
-	9439, // 2
-	9468, // 3
-	9497, // 4
-	9526, // 5
-	9555, // 6
-	9584, // 7
-	/*9381*/ uint16(xCondIs64), 9384, 9400,
-	/*9384*/ uint16(xCondDataSize), 9388, 9394, 0,
-	/*9388*/ uint16(xSetOp), uint16(ADD),
-	/*9390*/ uint16(xReadIb),
-	/*9391*/ uint16(xArgRM16),
-	/*9392*/ uint16(xArgImm8),
-	/*9393*/ uint16(xMatch),
-	/*9394*/ uint16(xSetOp), uint16(ADD),
-	/*9396*/ uint16(xReadIb),
-	/*9397*/ uint16(xArgRM32),
-	/*9398*/ uint16(xArgImm8),
-	/*9399*/ uint16(xMatch),
-	/*9400*/ uint16(xCondDataSize), 9388, 9394, 9404,
-	/*9404*/ uint16(xSetOp), uint16(ADD),
-	/*9406*/ uint16(xReadIb),
-	/*9407*/ uint16(xArgRM64),
-	/*9408*/ uint16(xArgImm8),
-	/*9409*/ uint16(xMatch),
-	/*9410*/ uint16(xCondIs64), 9413, 9429,
-	/*9413*/ uint16(xCondDataSize), 9417, 9423, 0,
-	/*9417*/ uint16(xSetOp), uint16(OR),
-	/*9419*/ uint16(xReadIb),
-	/*9420*/ uint16(xArgRM16),
-	/*9421*/ uint16(xArgImm8),
-	/*9422*/ uint16(xMatch),
-	/*9423*/ uint16(xSetOp), uint16(OR),
-	/*9425*/ uint16(xReadIb),
-	/*9426*/ uint16(xArgRM32),
-	/*9427*/ uint16(xArgImm8),
-	/*9428*/ uint16(xMatch),
-	/*9429*/ uint16(xCondDataSize), 9417, 9423, 9433,
-	/*9433*/ uint16(xSetOp), uint16(OR),
-	/*9435*/ uint16(xReadIb),
-	/*9436*/ uint16(xArgRM64),
-	/*9437*/ uint16(xArgImm8),
-	/*9438*/ uint16(xMatch),
-	/*9439*/ uint16(xCondIs64), 9442, 9458,
-	/*9442*/ uint16(xCondDataSize), 9446, 9452, 0,
-	/*9446*/ uint16(xSetOp), uint16(ADC),
-	/*9448*/ uint16(xReadIb),
-	/*9449*/ uint16(xArgRM16),
-	/*9450*/ uint16(xArgImm8),
-	/*9451*/ uint16(xMatch),
-	/*9452*/ uint16(xSetOp), uint16(ADC),
-	/*9454*/ uint16(xReadIb),
-	/*9455*/ uint16(xArgRM32),
-	/*9456*/ uint16(xArgImm8),
-	/*9457*/ uint16(xMatch),
-	/*9458*/ uint16(xCondDataSize), 9446, 9452, 9462,
-	/*9462*/ uint16(xSetOp), uint16(ADC),
-	/*9464*/ uint16(xReadIb),
-	/*9465*/ uint16(xArgRM64),
-	/*9466*/ uint16(xArgImm8),
-	/*9467*/ uint16(xMatch),
-	/*9468*/ uint16(xCondIs64), 9471, 9487,
-	/*9471*/ uint16(xCondDataSize), 9475, 9481, 0,
-	/*9475*/ uint16(xSetOp), uint16(SBB),
-	/*9477*/ uint16(xReadIb),
-	/*9478*/ uint16(xArgRM16),
-	/*9479*/ uint16(xArgImm8),
-	/*9480*/ uint16(xMatch),
-	/*9481*/ uint16(xSetOp), uint16(SBB),
-	/*9483*/ uint16(xReadIb),
-	/*9484*/ uint16(xArgRM32),
-	/*9485*/ uint16(xArgImm8),
-	/*9486*/ uint16(xMatch),
-	/*9487*/ uint16(xCondDataSize), 9475, 9481, 9491,
-	/*9491*/ uint16(xSetOp), uint16(SBB),
-	/*9493*/ uint16(xReadIb),
-	/*9494*/ uint16(xArgRM64),
-	/*9495*/ uint16(xArgImm8),
-	/*9496*/ uint16(xMatch),
-	/*9497*/ uint16(xCondIs64), 9500, 9516,
-	/*9500*/ uint16(xCondDataSize), 9504, 9510, 0,
-	/*9504*/ uint16(xSetOp), uint16(AND),
-	/*9506*/ uint16(xReadIb),
-	/*9507*/ uint16(xArgRM16),
-	/*9508*/ uint16(xArgImm8),
-	/*9509*/ uint16(xMatch),
-	/*9510*/ uint16(xSetOp), uint16(AND),
-	/*9512*/ uint16(xReadIb),
-	/*9513*/ uint16(xArgRM32),
-	/*9514*/ uint16(xArgImm8),
-	/*9515*/ uint16(xMatch),
-	/*9516*/ uint16(xCondDataSize), 9504, 9510, 9520,
-	/*9520*/ uint16(xSetOp), uint16(AND),
-	/*9522*/ uint16(xReadIb),
-	/*9523*/ uint16(xArgRM64),
-	/*9524*/ uint16(xArgImm8),
-	/*9525*/ uint16(xMatch),
-	/*9526*/ uint16(xCondIs64), 9529, 9545,
-	/*9529*/ uint16(xCondDataSize), 9533, 9539, 0,
-	/*9533*/ uint16(xSetOp), uint16(SUB),
-	/*9535*/ uint16(xReadIb),
-	/*9536*/ uint16(xArgRM16),
-	/*9537*/ uint16(xArgImm8),
-	/*9538*/ uint16(xMatch),
-	/*9539*/ uint16(xSetOp), uint16(SUB),
-	/*9541*/ uint16(xReadIb),
-	/*9542*/ uint16(xArgRM32),
-	/*9543*/ uint16(xArgImm8),
-	/*9544*/ uint16(xMatch),
-	/*9545*/ uint16(xCondDataSize), 9533, 9539, 9549,
-	/*9549*/ uint16(xSetOp), uint16(SUB),
-	/*9551*/ uint16(xReadIb),
-	/*9552*/ uint16(xArgRM64),
-	/*9553*/ uint16(xArgImm8),
-	/*9554*/ uint16(xMatch),
-	/*9555*/ uint16(xCondIs64), 9558, 9574,
-	/*9558*/ uint16(xCondDataSize), 9562, 9568, 0,
-	/*9562*/ uint16(xSetOp), uint16(XOR),
-	/*9564*/ uint16(xReadIb),
-	/*9565*/ uint16(xArgRM16),
-	/*9566*/ uint16(xArgImm8),
-	/*9567*/ uint16(xMatch),
-	/*9568*/ uint16(xSetOp), uint16(XOR),
-	/*9570*/ uint16(xReadIb),
-	/*9571*/ uint16(xArgRM32),
-	/*9572*/ uint16(xArgImm8),
-	/*9573*/ uint16(xMatch),
-	/*9574*/ uint16(xCondDataSize), 9562, 9568, 9578,
-	/*9578*/ uint16(xSetOp), uint16(XOR),
-	/*9580*/ uint16(xReadIb),
-	/*9581*/ uint16(xArgRM64),
-	/*9582*/ uint16(xArgImm8),
-	/*9583*/ uint16(xMatch),
-	/*9584*/ uint16(xCondIs64), 9587, 9603,
-	/*9587*/ uint16(xCondDataSize), 9591, 9597, 0,
-	/*9591*/ uint16(xSetOp), uint16(CMP),
-	/*9593*/ uint16(xReadIb),
-	/*9594*/ uint16(xArgRM16),
-	/*9595*/ uint16(xArgImm8),
-	/*9596*/ uint16(xMatch),
-	/*9597*/ uint16(xSetOp), uint16(CMP),
-	/*9599*/ uint16(xReadIb),
-	/*9600*/ uint16(xArgRM32),
-	/*9601*/ uint16(xArgImm8),
-	/*9602*/ uint16(xMatch),
-	/*9603*/ uint16(xCondDataSize), 9591, 9597, 9607,
-	/*9607*/ uint16(xSetOp), uint16(CMP),
-	/*9609*/ uint16(xReadIb),
-	/*9610*/ uint16(xArgRM64),
-	/*9611*/ uint16(xArgImm8),
-	/*9612*/ uint16(xMatch),
-	/*9613*/ uint16(xSetOp), uint16(TEST),
-	/*9615*/ uint16(xReadSlashR),
-	/*9616*/ uint16(xArgRM8),
-	/*9617*/ uint16(xArgR8),
-	/*9618*/ uint16(xMatch),
-	/*9619*/ uint16(xCondIs64), 9622, 9638,
-	/*9622*/ uint16(xCondDataSize), 9626, 9632, 0,
-	/*9626*/ uint16(xSetOp), uint16(TEST),
-	/*9628*/ uint16(xReadSlashR),
-	/*9629*/ uint16(xArgRM16),
-	/*9630*/ uint16(xArgR16),
-	/*9631*/ uint16(xMatch),
-	/*9632*/ uint16(xSetOp), uint16(TEST),
-	/*9634*/ uint16(xReadSlashR),
-	/*9635*/ uint16(xArgRM32),
-	/*9636*/ uint16(xArgR32),
-	/*9637*/ uint16(xMatch),
-	/*9638*/ uint16(xCondDataSize), 9626, 9632, 9642,
-	/*9642*/ uint16(xSetOp), uint16(TEST),
-	/*9644*/ uint16(xReadSlashR),
-	/*9645*/ uint16(xArgRM64),
-	/*9646*/ uint16(xArgR64),
-	/*9647*/ uint16(xMatch),
-	/*9648*/ uint16(xSetOp), uint16(XCHG),
-	/*9650*/ uint16(xReadSlashR),
-	/*9651*/ uint16(xArgRM8),
-	/*9652*/ uint16(xArgR8),
-	/*9653*/ uint16(xMatch),
-	/*9654*/ uint16(xCondIs64), 9657, 9673,
-	/*9657*/ uint16(xCondDataSize), 9661, 9667, 0,
-	/*9661*/ uint16(xSetOp), uint16(XCHG),
-	/*9663*/ uint16(xReadSlashR),
-	/*9664*/ uint16(xArgRM16),
-	/*9665*/ uint16(xArgR16),
-	/*9666*/ uint16(xMatch),
-	/*9667*/ uint16(xSetOp), uint16(XCHG),
-	/*9669*/ uint16(xReadSlashR),
-	/*9670*/ uint16(xArgRM32),
-	/*9671*/ uint16(xArgR32),
-	/*9672*/ uint16(xMatch),
-	/*9673*/ uint16(xCondDataSize), 9661, 9667, 9677,
-	/*9677*/ uint16(xSetOp), uint16(XCHG),
-	/*9679*/ uint16(xReadSlashR),
-	/*9680*/ uint16(xArgRM64),
-	/*9681*/ uint16(xArgR64),
-	/*9682*/ uint16(xMatch),
-	/*9683*/ uint16(xSetOp), uint16(MOV),
-	/*9685*/ uint16(xReadSlashR),
-	/*9686*/ uint16(xArgRM8),
-	/*9687*/ uint16(xArgR8),
-	/*9688*/ uint16(xMatch),
-	/*9689*/ uint16(xCondDataSize), 9693, 9699, 9705,
-	/*9693*/ uint16(xSetOp), uint16(MOV),
-	/*9695*/ uint16(xReadSlashR),
-	/*9696*/ uint16(xArgRM16),
-	/*9697*/ uint16(xArgR16),
-	/*9698*/ uint16(xMatch),
-	/*9699*/ uint16(xSetOp), uint16(MOV),
-	/*9701*/ uint16(xReadSlashR),
-	/*9702*/ uint16(xArgRM32),
-	/*9703*/ uint16(xArgR32),
-	/*9704*/ uint16(xMatch),
-	/*9705*/ uint16(xSetOp), uint16(MOV),
-	/*9707*/ uint16(xReadSlashR),
-	/*9708*/ uint16(xArgRM64),
-	/*9709*/ uint16(xArgR64),
-	/*9710*/ uint16(xMatch),
-	/*9711*/ uint16(xSetOp), uint16(MOV),
-	/*9713*/ uint16(xReadSlashR),
-	/*9714*/ uint16(xArgR8),
-	/*9715*/ uint16(xArgRM8),
+	/*9285*/ uint16(xSetOp), uint16(AND),
+	/*9287*/ uint16(xReadIb),
+	/*9288*/ uint16(xArgRM8),
+	/*9289*/ uint16(xArgImm8u),
+	/*9290*/ uint16(xMatch),
+	/*9291*/ uint16(xSetOp), uint16(SUB),
+	/*9293*/ uint16(xReadIb),
+	/*9294*/ uint16(xArgRM8),
+	/*9295*/ uint16(xArgImm8u),
+	/*9296*/ uint16(xMatch),
+	/*9297*/ uint16(xSetOp), uint16(XOR),
+	/*9299*/ uint16(xReadIb),
+	/*9300*/ uint16(xArgRM8),
+	/*9301*/ uint16(xArgImm8u),
+	/*9302*/ uint16(xMatch),
+	/*9303*/ uint16(xSetOp), uint16(CMP),
+	/*9305*/ uint16(xReadIb),
+	/*9306*/ uint16(xArgRM8),
+	/*9307*/ uint16(xArgImm8u),
+	/*9308*/ uint16(xMatch),
+	/*9309*/ uint16(xCondSlashR),
+	9318, // 0
+	9347, // 1
+	9376, // 2
+	9405, // 3
+	9434, // 4
+	9463, // 5
+	9492, // 6
+	9521, // 7
+	/*9318*/ uint16(xCondIs64), 9321, 9337,
+	/*9321*/ uint16(xCondDataSize), 9325, 9331, 0,
+	/*9325*/ uint16(xSetOp), uint16(ADD),
+	/*9327*/ uint16(xReadIw),
+	/*9328*/ uint16(xArgRM16),
+	/*9329*/ uint16(xArgImm16),
+	/*9330*/ uint16(xMatch),
+	/*9331*/ uint16(xSetOp), uint16(ADD),
+	/*9333*/ uint16(xReadId),
+	/*9334*/ uint16(xArgRM32),
+	/*9335*/ uint16(xArgImm32),
+	/*9336*/ uint16(xMatch),
+	/*9337*/ uint16(xCondDataSize), 9325, 9331, 9341,
+	/*9341*/ uint16(xSetOp), uint16(ADD),
+	/*9343*/ uint16(xReadId),
+	/*9344*/ uint16(xArgRM64),
+	/*9345*/ uint16(xArgImm32),
+	/*9346*/ uint16(xMatch),
+	/*9347*/ uint16(xCondIs64), 9350, 9366,
+	/*9350*/ uint16(xCondDataSize), 9354, 9360, 0,
+	/*9354*/ uint16(xSetOp), uint16(OR),
+	/*9356*/ uint16(xReadIw),
+	/*9357*/ uint16(xArgRM16),
+	/*9358*/ uint16(xArgImm16),
+	/*9359*/ uint16(xMatch),
+	/*9360*/ uint16(xSetOp), uint16(OR),
+	/*9362*/ uint16(xReadId),
+	/*9363*/ uint16(xArgRM32),
+	/*9364*/ uint16(xArgImm32),
+	/*9365*/ uint16(xMatch),
+	/*9366*/ uint16(xCondDataSize), 9354, 9360, 9370,
+	/*9370*/ uint16(xSetOp), uint16(OR),
+	/*9372*/ uint16(xReadId),
+	/*9373*/ uint16(xArgRM64),
+	/*9374*/ uint16(xArgImm32),
+	/*9375*/ uint16(xMatch),
+	/*9376*/ uint16(xCondIs64), 9379, 9395,
+	/*9379*/ uint16(xCondDataSize), 9383, 9389, 0,
+	/*9383*/ uint16(xSetOp), uint16(ADC),
+	/*9385*/ uint16(xReadIw),
+	/*9386*/ uint16(xArgRM16),
+	/*9387*/ uint16(xArgImm16),
+	/*9388*/ uint16(xMatch),
+	/*9389*/ uint16(xSetOp), uint16(ADC),
+	/*9391*/ uint16(xReadId),
+	/*9392*/ uint16(xArgRM32),
+	/*9393*/ uint16(xArgImm32),
+	/*9394*/ uint16(xMatch),
+	/*9395*/ uint16(xCondDataSize), 9383, 9389, 9399,
+	/*9399*/ uint16(xSetOp), uint16(ADC),
+	/*9401*/ uint16(xReadId),
+	/*9402*/ uint16(xArgRM64),
+	/*9403*/ uint16(xArgImm32),
+	/*9404*/ uint16(xMatch),
+	/*9405*/ uint16(xCondIs64), 9408, 9424,
+	/*9408*/ uint16(xCondDataSize), 9412, 9418, 0,
+	/*9412*/ uint16(xSetOp), uint16(SBB),
+	/*9414*/ uint16(xReadIw),
+	/*9415*/ uint16(xArgRM16),
+	/*9416*/ uint16(xArgImm16),
+	/*9417*/ uint16(xMatch),
+	/*9418*/ uint16(xSetOp), uint16(SBB),
+	/*9420*/ uint16(xReadId),
+	/*9421*/ uint16(xArgRM32),
+	/*9422*/ uint16(xArgImm32),
+	/*9423*/ uint16(xMatch),
+	/*9424*/ uint16(xCondDataSize), 9412, 9418, 9428,
+	/*9428*/ uint16(xSetOp), uint16(SBB),
+	/*9430*/ uint16(xReadId),
+	/*9431*/ uint16(xArgRM64),
+	/*9432*/ uint16(xArgImm32),
+	/*9433*/ uint16(xMatch),
+	/*9434*/ uint16(xCondIs64), 9437, 9453,
+	/*9437*/ uint16(xCondDataSize), 9441, 9447, 0,
+	/*9441*/ uint16(xSetOp), uint16(AND),
+	/*9443*/ uint16(xReadIw),
+	/*9444*/ uint16(xArgRM16),
+	/*9445*/ uint16(xArgImm16),
+	/*9446*/ uint16(xMatch),
+	/*9447*/ uint16(xSetOp), uint16(AND),
+	/*9449*/ uint16(xReadId),
+	/*9450*/ uint16(xArgRM32),
+	/*9451*/ uint16(xArgImm32),
+	/*9452*/ uint16(xMatch),
+	/*9453*/ uint16(xCondDataSize), 9441, 9447, 9457,
+	/*9457*/ uint16(xSetOp), uint16(AND),
+	/*9459*/ uint16(xReadId),
+	/*9460*/ uint16(xArgRM64),
+	/*9461*/ uint16(xArgImm32),
+	/*9462*/ uint16(xMatch),
+	/*9463*/ uint16(xCondIs64), 9466, 9482,
+	/*9466*/ uint16(xCondDataSize), 9470, 9476, 0,
+	/*9470*/ uint16(xSetOp), uint16(SUB),
+	/*9472*/ uint16(xReadIw),
+	/*9473*/ uint16(xArgRM16),
+	/*9474*/ uint16(xArgImm16),
+	/*9475*/ uint16(xMatch),
+	/*9476*/ uint16(xSetOp), uint16(SUB),
+	/*9478*/ uint16(xReadId),
+	/*9479*/ uint16(xArgRM32),
+	/*9480*/ uint16(xArgImm32),
+	/*9481*/ uint16(xMatch),
+	/*9482*/ uint16(xCondDataSize), 9470, 9476, 9486,
+	/*9486*/ uint16(xSetOp), uint16(SUB),
+	/*9488*/ uint16(xReadId),
+	/*9489*/ uint16(xArgRM64),
+	/*9490*/ uint16(xArgImm32),
+	/*9491*/ uint16(xMatch),
+	/*9492*/ uint16(xCondIs64), 9495, 9511,
+	/*9495*/ uint16(xCondDataSize), 9499, 9505, 0,
+	/*9499*/ uint16(xSetOp), uint16(XOR),
+	/*9501*/ uint16(xReadIw),
+	/*9502*/ uint16(xArgRM16),
+	/*9503*/ uint16(xArgImm16),
+	/*9504*/ uint16(xMatch),
+	/*9505*/ uint16(xSetOp), uint16(XOR),
+	/*9507*/ uint16(xReadId),
+	/*9508*/ uint16(xArgRM32),
+	/*9509*/ uint16(xArgImm32),
+	/*9510*/ uint16(xMatch),
+	/*9511*/ uint16(xCondDataSize), 9499, 9505, 9515,
+	/*9515*/ uint16(xSetOp), uint16(XOR),
+	/*9517*/ uint16(xReadId),
+	/*9518*/ uint16(xArgRM64),
+	/*9519*/ uint16(xArgImm32),
+	/*9520*/ uint16(xMatch),
+	/*9521*/ uint16(xCondIs64), 9524, 9540,
+	/*9524*/ uint16(xCondDataSize), 9528, 9534, 0,
+	/*9528*/ uint16(xSetOp), uint16(CMP),
+	/*9530*/ uint16(xReadIw),
+	/*9531*/ uint16(xArgRM16),
+	/*9532*/ uint16(xArgImm16),
+	/*9533*/ uint16(xMatch),
+	/*9534*/ uint16(xSetOp), uint16(CMP),
+	/*9536*/ uint16(xReadId),
+	/*9537*/ uint16(xArgRM32),
+	/*9538*/ uint16(xArgImm32),
+	/*9539*/ uint16(xMatch),
+	/*9540*/ uint16(xCondDataSize), 9528, 9534, 9544,
+	/*9544*/ uint16(xSetOp), uint16(CMP),
+	/*9546*/ uint16(xReadId),
+	/*9547*/ uint16(xArgRM64),
+	/*9548*/ uint16(xArgImm32),
+	/*9549*/ uint16(xMatch),
+	/*9550*/ uint16(xCondSlashR),
+	9559, // 0
+	9588, // 1
+	9617, // 2
+	9646, // 3
+	9675, // 4
+	9704, // 5
+	9733, // 6
+	9762, // 7
+	/*9559*/ uint16(xCondIs64), 9562, 9578,
+	/*9562*/ uint16(xCondDataSize), 9566, 9572, 0,
+	/*9566*/ uint16(xSetOp), uint16(ADD),
+	/*9568*/ uint16(xReadIb),
+	/*9569*/ uint16(xArgRM16),
+	/*9570*/ uint16(xArgImm8),
+	/*9571*/ uint16(xMatch),
+	/*9572*/ uint16(xSetOp), uint16(ADD),
+	/*9574*/ uint16(xReadIb),
+	/*9575*/ uint16(xArgRM32),
+	/*9576*/ uint16(xArgImm8),
+	/*9577*/ uint16(xMatch),
+	/*9578*/ uint16(xCondDataSize), 9566, 9572, 9582,
+	/*9582*/ uint16(xSetOp), uint16(ADD),
+	/*9584*/ uint16(xReadIb),
+	/*9585*/ uint16(xArgRM64),
+	/*9586*/ uint16(xArgImm8),
+	/*9587*/ uint16(xMatch),
+	/*9588*/ uint16(xCondIs64), 9591, 9607,
+	/*9591*/ uint16(xCondDataSize), 9595, 9601, 0,
+	/*9595*/ uint16(xSetOp), uint16(OR),
+	/*9597*/ uint16(xReadIb),
+	/*9598*/ uint16(xArgRM16),
+	/*9599*/ uint16(xArgImm8),
+	/*9600*/ uint16(xMatch),
+	/*9601*/ uint16(xSetOp), uint16(OR),
+	/*9603*/ uint16(xReadIb),
+	/*9604*/ uint16(xArgRM32),
+	/*9605*/ uint16(xArgImm8),
+	/*9606*/ uint16(xMatch),
+	/*9607*/ uint16(xCondDataSize), 9595, 9601, 9611,
+	/*9611*/ uint16(xSetOp), uint16(OR),
+	/*9613*/ uint16(xReadIb),
+	/*9614*/ uint16(xArgRM64),
+	/*9615*/ uint16(xArgImm8),
+	/*9616*/ uint16(xMatch),
+	/*9617*/ uint16(xCondIs64), 9620, 9636,
+	/*9620*/ uint16(xCondDataSize), 9624, 9630, 0,
+	/*9624*/ uint16(xSetOp), uint16(ADC),
+	/*9626*/ uint16(xReadIb),
+	/*9627*/ uint16(xArgRM16),
+	/*9628*/ uint16(xArgImm8),
+	/*9629*/ uint16(xMatch),
+	/*9630*/ uint16(xSetOp), uint16(ADC),
+	/*9632*/ uint16(xReadIb),
+	/*9633*/ uint16(xArgRM32),
+	/*9634*/ uint16(xArgImm8),
+	/*9635*/ uint16(xMatch),
+	/*9636*/ uint16(xCondDataSize), 9624, 9630, 9640,
+	/*9640*/ uint16(xSetOp), uint16(ADC),
+	/*9642*/ uint16(xReadIb),
+	/*9643*/ uint16(xArgRM64),
+	/*9644*/ uint16(xArgImm8),
+	/*9645*/ uint16(xMatch),
+	/*9646*/ uint16(xCondIs64), 9649, 9665,
+	/*9649*/ uint16(xCondDataSize), 9653, 9659, 0,
+	/*9653*/ uint16(xSetOp), uint16(SBB),
+	/*9655*/ uint16(xReadIb),
+	/*9656*/ uint16(xArgRM16),
+	/*9657*/ uint16(xArgImm8),
+	/*9658*/ uint16(xMatch),
+	/*9659*/ uint16(xSetOp), uint16(SBB),
+	/*9661*/ uint16(xReadIb),
+	/*9662*/ uint16(xArgRM32),
+	/*9663*/ uint16(xArgImm8),
+	/*9664*/ uint16(xMatch),
+	/*9665*/ uint16(xCondDataSize), 9653, 9659, 9669,
+	/*9669*/ uint16(xSetOp), uint16(SBB),
+	/*9671*/ uint16(xReadIb),
+	/*9672*/ uint16(xArgRM64),
+	/*9673*/ uint16(xArgImm8),
+	/*9674*/ uint16(xMatch),
+	/*9675*/ uint16(xCondIs64), 9678, 9694,
+	/*9678*/ uint16(xCondDataSize), 9682, 9688, 0,
+	/*9682*/ uint16(xSetOp), uint16(AND),
+	/*9684*/ uint16(xReadIb),
+	/*9685*/ uint16(xArgRM16),
+	/*9686*/ uint16(xArgImm8),
+	/*9687*/ uint16(xMatch),
+	/*9688*/ uint16(xSetOp), uint16(AND),
+	/*9690*/ uint16(xReadIb),
+	/*9691*/ uint16(xArgRM32),
+	/*9692*/ uint16(xArgImm8),
+	/*9693*/ uint16(xMatch),
+	/*9694*/ uint16(xCondDataSize), 9682, 9688, 9698,
+	/*9698*/ uint16(xSetOp), uint16(AND),
+	/*9700*/ uint16(xReadIb),
+	/*9701*/ uint16(xArgRM64),
+	/*9702*/ uint16(xArgImm8),
+	/*9703*/ uint16(xMatch),
+	/*9704*/ uint16(xCondIs64), 9707, 9723,
+	/*9707*/ uint16(xCondDataSize), 9711, 9717, 0,
+	/*9711*/ uint16(xSetOp), uint16(SUB),
+	/*9713*/ uint16(xReadIb),
+	/*9714*/ uint16(xArgRM16),
+	/*9715*/ uint16(xArgImm8),
 	/*9716*/ uint16(xMatch),
-	/*9717*/ uint16(xCondDataSize), 9721, 9727, 9733,
-	/*9721*/ uint16(xSetOp), uint16(MOV),
-	/*9723*/ uint16(xReadSlashR),
-	/*9724*/ uint16(xArgR16),
-	/*9725*/ uint16(xArgRM16),
-	/*9726*/ uint16(xMatch),
-	/*9727*/ uint16(xSetOp), uint16(MOV),
-	/*9729*/ uint16(xReadSlashR),
-	/*9730*/ uint16(xArgR32),
-	/*9731*/ uint16(xArgRM32),
+	/*9717*/ uint16(xSetOp), uint16(SUB),
+	/*9719*/ uint16(xReadIb),
+	/*9720*/ uint16(xArgRM32),
+	/*9721*/ uint16(xArgImm8),
+	/*9722*/ uint16(xMatch),
+	/*9723*/ uint16(xCondDataSize), 9711, 9717, 9727,
+	/*9727*/ uint16(xSetOp), uint16(SUB),
+	/*9729*/ uint16(xReadIb),
+	/*9730*/ uint16(xArgRM64),
+	/*9731*/ uint16(xArgImm8),
 	/*9732*/ uint16(xMatch),
-	/*9733*/ uint16(xSetOp), uint16(MOV),
-	/*9735*/ uint16(xReadSlashR),
-	/*9736*/ uint16(xArgR64),
-	/*9737*/ uint16(xArgRM64),
-	/*9738*/ uint16(xMatch),
-	/*9739*/ uint16(xCondIs64), 9742, 9758,
-	/*9742*/ uint16(xCondDataSize), 9746, 9752, 0,
-	/*9746*/ uint16(xSetOp), uint16(MOV),
-	/*9748*/ uint16(xReadSlashR),
-	/*9749*/ uint16(xArgRM16),
-	/*9750*/ uint16(xArgSreg),
+	/*9733*/ uint16(xCondIs64), 9736, 9752,
+	/*9736*/ uint16(xCondDataSize), 9740, 9746, 0,
+	/*9740*/ uint16(xSetOp), uint16(XOR),
+	/*9742*/ uint16(xReadIb),
+	/*9743*/ uint16(xArgRM16),
+	/*9744*/ uint16(xArgImm8),
+	/*9745*/ uint16(xMatch),
+	/*9746*/ uint16(xSetOp), uint16(XOR),
+	/*9748*/ uint16(xReadIb),
+	/*9749*/ uint16(xArgRM32),
+	/*9750*/ uint16(xArgImm8),
 	/*9751*/ uint16(xMatch),
-	/*9752*/ uint16(xSetOp), uint16(MOV),
-	/*9754*/ uint16(xReadSlashR),
-	/*9755*/ uint16(xArgR32M16),
-	/*9756*/ uint16(xArgSreg),
-	/*9757*/ uint16(xMatch),
-	/*9758*/ uint16(xCondDataSize), 9746, 9752, 9762,
-	/*9762*/ uint16(xSetOp), uint16(MOV),
-	/*9764*/ uint16(xReadSlashR),
-	/*9765*/ uint16(xArgR64M16),
-	/*9766*/ uint16(xArgSreg),
-	/*9767*/ uint16(xMatch),
-	/*9768*/ uint16(xCondIs64), 9771, 9787,
-	/*9771*/ uint16(xCondDataSize), 9775, 9781, 0,
-	/*9775*/ uint16(xSetOp), uint16(LEA),
-	/*9777*/ uint16(xReadSlashR),
-	/*9778*/ uint16(xArgR16),
-	/*9779*/ uint16(xArgM),
+	/*9752*/ uint16(xCondDataSize), 9740, 9746, 9756,
+	/*9756*/ uint16(xSetOp), uint16(XOR),
+	/*9758*/ uint16(xReadIb),
+	/*9759*/ uint16(xArgRM64),
+	/*9760*/ uint16(xArgImm8),
+	/*9761*/ uint16(xMatch),
+	/*9762*/ uint16(xCondIs64), 9765, 9781,
+	/*9765*/ uint16(xCondDataSize), 9769, 9775, 0,
+	/*9769*/ uint16(xSetOp), uint16(CMP),
+	/*9771*/ uint16(xReadIb),
+	/*9772*/ uint16(xArgRM16),
+	/*9773*/ uint16(xArgImm8),
+	/*9774*/ uint16(xMatch),
+	/*9775*/ uint16(xSetOp), uint16(CMP),
+	/*9777*/ uint16(xReadIb),
+	/*9778*/ uint16(xArgRM32),
+	/*9779*/ uint16(xArgImm8),
 	/*9780*/ uint16(xMatch),
-	/*9781*/ uint16(xSetOp), uint16(LEA),
-	/*9783*/ uint16(xReadSlashR),
-	/*9784*/ uint16(xArgR32),
-	/*9785*/ uint16(xArgM),
-	/*9786*/ uint16(xMatch),
-	/*9787*/ uint16(xCondDataSize), 9775, 9781, 9791,
-	/*9791*/ uint16(xSetOp), uint16(LEA),
+	/*9781*/ uint16(xCondDataSize), 9769, 9775, 9785,
+	/*9785*/ uint16(xSetOp), uint16(CMP),
+	/*9787*/ uint16(xReadIb),
+	/*9788*/ uint16(xArgRM64),
+	/*9789*/ uint16(xArgImm8),
+	/*9790*/ uint16(xMatch),
+	/*9791*/ uint16(xSetOp), uint16(TEST),
 	/*9793*/ uint16(xReadSlashR),
-	/*9794*/ uint16(xArgR64),
-	/*9795*/ uint16(xArgM),
+	/*9794*/ uint16(xArgRM8),
+	/*9795*/ uint16(xArgR8),
 	/*9796*/ uint16(xMatch),
 	/*9797*/ uint16(xCondIs64), 9800, 9816,
 	/*9800*/ uint16(xCondDataSize), 9804, 9810, 0,
-	/*9804*/ uint16(xSetOp), uint16(MOV),
+	/*9804*/ uint16(xSetOp), uint16(TEST),
 	/*9806*/ uint16(xReadSlashR),
-	/*9807*/ uint16(xArgSreg),
-	/*9808*/ uint16(xArgRM16),
+	/*9807*/ uint16(xArgRM16),
+	/*9808*/ uint16(xArgR16),
 	/*9809*/ uint16(xMatch),
-	/*9810*/ uint16(xSetOp), uint16(MOV),
+	/*9810*/ uint16(xSetOp), uint16(TEST),
 	/*9812*/ uint16(xReadSlashR),
-	/*9813*/ uint16(xArgSreg),
-	/*9814*/ uint16(xArgR32M16),
+	/*9813*/ uint16(xArgRM32),
+	/*9814*/ uint16(xArgR32),
 	/*9815*/ uint16(xMatch),
 	/*9816*/ uint16(xCondDataSize), 9804, 9810, 9820,
-	/*9820*/ uint16(xSetOp), uint16(MOV),
+	/*9820*/ uint16(xSetOp), uint16(TEST),
 	/*9822*/ uint16(xReadSlashR),
-	/*9823*/ uint16(xArgSreg),
-	/*9824*/ uint16(xArgR64M16),
+	/*9823*/ uint16(xArgRM64),
+	/*9824*/ uint16(xArgR64),
 	/*9825*/ uint16(xMatch),
-	/*9826*/ uint16(xCondSlashR),
-	9835, // 0
-	0,    // 1
-	0,    // 2
-	0,    // 3
-	0,    // 4
-	0,    // 5
-	0,    // 6
-	0,    // 7
-	/*9835*/ uint16(xCondIs64), 9838, 9850,
-	/*9838*/ uint16(xCondDataSize), 9842, 9846, 0,
-	/*9842*/ uint16(xSetOp), uint16(POP),
-	/*9844*/ uint16(xArgRM16),
-	/*9845*/ uint16(xMatch),
-	/*9846*/ uint16(xSetOp), uint16(POP),
+	/*9826*/ uint16(xSetOp), uint16(XCHG),
+	/*9828*/ uint16(xReadSlashR),
+	/*9829*/ uint16(xArgRM8),
+	/*9830*/ uint16(xArgR8),
+	/*9831*/ uint16(xMatch),
+	/*9832*/ uint16(xCondIs64), 9835, 9851,
+	/*9835*/ uint16(xCondDataSize), 9839, 9845, 0,
+	/*9839*/ uint16(xSetOp), uint16(XCHG),
+	/*9841*/ uint16(xReadSlashR),
+	/*9842*/ uint16(xArgRM16),
+	/*9843*/ uint16(xArgR16),
+	/*9844*/ uint16(xMatch),
+	/*9845*/ uint16(xSetOp), uint16(XCHG),
+	/*9847*/ uint16(xReadSlashR),
 	/*9848*/ uint16(xArgRM32),
-	/*9849*/ uint16(xMatch),
-	/*9850*/ uint16(xCondDataSize), 9842, 9854, 9858,
-	/*9854*/ uint16(xSetOp), uint16(POP),
-	/*9856*/ uint16(xArgRM64),
-	/*9857*/ uint16(xMatch),
-	/*9858*/ uint16(xSetOp), uint16(POP),
-	/*9860*/ uint16(xArgRM64),
-	/*9861*/ uint16(xMatch),
-	/*9862*/ uint16(xCondIs64), 9865, 9879,
-	/*9865*/ uint16(xCondDataSize), 9869, 9874, 0,
-	/*9869*/ uint16(xSetOp), uint16(XCHG),
-	/*9871*/ uint16(xArgR16op),
-	/*9872*/ uint16(xArgAX),
-	/*9873*/ uint16(xMatch),
-	/*9874*/ uint16(xSetOp), uint16(XCHG),
-	/*9876*/ uint16(xArgR32op),
-	/*9877*/ uint16(xArgEAX),
-	/*9878*/ uint16(xMatch),
-	/*9879*/ uint16(xCondDataSize), 9869, 9874, 9883,
-	/*9883*/ uint16(xSetOp), uint16(XCHG),
-	/*9885*/ uint16(xArgR64op),
-	/*9886*/ uint16(xArgRAX),
-	/*9887*/ uint16(xMatch),
-	/*9888*/ uint16(xCondIs64), 9891, 9901,
-	/*9891*/ uint16(xCondDataSize), 9895, 9898, 0,
-	/*9895*/ uint16(xSetOp), uint16(CBW),
-	/*9897*/ uint16(xMatch),
-	/*9898*/ uint16(xSetOp), uint16(CWDE),
-	/*9900*/ uint16(xMatch),
-	/*9901*/ uint16(xCondDataSize), 9895, 9898, 9905,
-	/*9905*/ uint16(xSetOp), uint16(CDQE),
-	/*9907*/ uint16(xMatch),
-	/*9908*/ uint16(xCondIs64), 9911, 9921,
-	/*9911*/ uint16(xCondDataSize), 9915, 9918, 0,
-	/*9915*/ uint16(xSetOp), uint16(CWD),
-	/*9917*/ uint16(xMatch),
-	/*9918*/ uint16(xSetOp), uint16(CDQ),
-	/*9920*/ uint16(xMatch),
-	/*9921*/ uint16(xCondDataSize), 9915, 9918, 9925,
-	/*9925*/ uint16(xSetOp), uint16(CQO),
-	/*9927*/ uint16(xMatch),
-	/*9928*/ uint16(xCondIs64), 9931, 0,
-	/*9931*/ uint16(xCondDataSize), 9935, 9940, 0,
-	/*9935*/ uint16(xSetOp), uint16(LCALL),
-	/*9937*/ uint16(xReadCd),
-	/*9938*/ uint16(xArgPtr16colon16),
-	/*9939*/ uint16(xMatch),
-	/*9940*/ uint16(xSetOp), uint16(LCALL),
-	/*9942*/ uint16(xReadCp),
-	/*9943*/ uint16(xArgPtr16colon32),
-	/*9944*/ uint16(xMatch),
-	/*9945*/ uint16(xSetOp), uint16(FWAIT),
-	/*9947*/ uint16(xMatch),
-	/*9948*/ uint16(xCondIs64), 9951, 9961,
-	/*9951*/ uint16(xCondDataSize), 9955, 9958, 0,
-	/*9955*/ uint16(xSetOp), uint16(PUSHF),
-	/*9957*/ uint16(xMatch),
-	/*9958*/ uint16(xSetOp), uint16(PUSHFD),
-	/*9960*/ uint16(xMatch),
-	/*9961*/ uint16(xCondDataSize), 9955, 9965, 9968,
-	/*9965*/ uint16(xSetOp), uint16(PUSHFQ),
-	/*9967*/ uint16(xMatch),
-	/*9968*/ uint16(xSetOp), uint16(PUSHFQ),
-	/*9970*/ uint16(xMatch),
-	/*9971*/ uint16(xCondIs64), 9974, 9984,
-	/*9974*/ uint16(xCondDataSize), 9978, 9981, 0,
-	/*9978*/ uint16(xSetOp), uint16(POPF),
-	/*9980*/ uint16(xMatch),
-	/*9981*/ uint16(xSetOp), uint16(POPFD),
-	/*9983*/ uint16(xMatch),
-	/*9984*/ uint16(xCondDataSize), 9978, 9988, 9991,
-	/*9988*/ uint16(xSetOp), uint16(POPFQ),
-	/*9990*/ uint16(xMatch),
-	/*9991*/ uint16(xSetOp), uint16(POPFQ),
+	/*9849*/ uint16(xArgR32),
+	/*9850*/ uint16(xMatch),
+	/*9851*/ uint16(xCondDataSize), 9839, 9845, 9855,
+	/*9855*/ uint16(xSetOp), uint16(XCHG),
+	/*9857*/ uint16(xReadSlashR),
+	/*9858*/ uint16(xArgRM64),
+	/*9859*/ uint16(xArgR64),
+	/*9860*/ uint16(xMatch),
+	/*9861*/ uint16(xSetOp), uint16(MOV),
+	/*9863*/ uint16(xReadSlashR),
+	/*9864*/ uint16(xArgRM8),
+	/*9865*/ uint16(xArgR8),
+	/*9866*/ uint16(xMatch),
+	/*9867*/ uint16(xCondDataSize), 9871, 9877, 9883,
+	/*9871*/ uint16(xSetOp), uint16(MOV),
+	/*9873*/ uint16(xReadSlashR),
+	/*9874*/ uint16(xArgRM16),
+	/*9875*/ uint16(xArgR16),
+	/*9876*/ uint16(xMatch),
+	/*9877*/ uint16(xSetOp), uint16(MOV),
+	/*9879*/ uint16(xReadSlashR),
+	/*9880*/ uint16(xArgRM32),
+	/*9881*/ uint16(xArgR32),
+	/*9882*/ uint16(xMatch),
+	/*9883*/ uint16(xSetOp), uint16(MOV),
+	/*9885*/ uint16(xReadSlashR),
+	/*9886*/ uint16(xArgRM64),
+	/*9887*/ uint16(xArgR64),
+	/*9888*/ uint16(xMatch),
+	/*9889*/ uint16(xSetOp), uint16(MOV),
+	/*9891*/ uint16(xReadSlashR),
+	/*9892*/ uint16(xArgR8),
+	/*9893*/ uint16(xArgRM8),
+	/*9894*/ uint16(xMatch),
+	/*9895*/ uint16(xCondDataSize), 9899, 9905, 9911,
+	/*9899*/ uint16(xSetOp), uint16(MOV),
+	/*9901*/ uint16(xReadSlashR),
+	/*9902*/ uint16(xArgR16),
+	/*9903*/ uint16(xArgRM16),
+	/*9904*/ uint16(xMatch),
+	/*9905*/ uint16(xSetOp), uint16(MOV),
+	/*9907*/ uint16(xReadSlashR),
+	/*9908*/ uint16(xArgR32),
+	/*9909*/ uint16(xArgRM32),
+	/*9910*/ uint16(xMatch),
+	/*9911*/ uint16(xSetOp), uint16(MOV),
+	/*9913*/ uint16(xReadSlashR),
+	/*9914*/ uint16(xArgR64),
+	/*9915*/ uint16(xArgRM64),
+	/*9916*/ uint16(xMatch),
+	/*9917*/ uint16(xCondIs64), 9920, 9936,
+	/*9920*/ uint16(xCondDataSize), 9924, 9930, 0,
+	/*9924*/ uint16(xSetOp), uint16(MOV),
+	/*9926*/ uint16(xReadSlashR),
+	/*9927*/ uint16(xArgRM16),
+	/*9928*/ uint16(xArgSreg),
+	/*9929*/ uint16(xMatch),
+	/*9930*/ uint16(xSetOp), uint16(MOV),
+	/*9932*/ uint16(xReadSlashR),
+	/*9933*/ uint16(xArgR32M16),
+	/*9934*/ uint16(xArgSreg),
+	/*9935*/ uint16(xMatch),
+	/*9936*/ uint16(xCondDataSize), 9924, 9930, 9940,
+	/*9940*/ uint16(xSetOp), uint16(MOV),
+	/*9942*/ uint16(xReadSlashR),
+	/*9943*/ uint16(xArgR64M16),
+	/*9944*/ uint16(xArgSreg),
+	/*9945*/ uint16(xMatch),
+	/*9946*/ uint16(xCondIs64), 9949, 9965,
+	/*9949*/ uint16(xCondDataSize), 9953, 9959, 0,
+	/*9953*/ uint16(xSetOp), uint16(LEA),
+	/*9955*/ uint16(xReadSlashR),
+	/*9956*/ uint16(xArgR16),
+	/*9957*/ uint16(xArgM),
+	/*9958*/ uint16(xMatch),
+	/*9959*/ uint16(xSetOp), uint16(LEA),
+	/*9961*/ uint16(xReadSlashR),
+	/*9962*/ uint16(xArgR32),
+	/*9963*/ uint16(xArgM),
+	/*9964*/ uint16(xMatch),
+	/*9965*/ uint16(xCondDataSize), 9953, 9959, 9969,
+	/*9969*/ uint16(xSetOp), uint16(LEA),
+	/*9971*/ uint16(xReadSlashR),
+	/*9972*/ uint16(xArgR64),
+	/*9973*/ uint16(xArgM),
+	/*9974*/ uint16(xMatch),
+	/*9975*/ uint16(xCondIs64), 9978, 9994,
+	/*9978*/ uint16(xCondDataSize), 9982, 9988, 0,
+	/*9982*/ uint16(xSetOp), uint16(MOV),
+	/*9984*/ uint16(xReadSlashR),
+	/*9985*/ uint16(xArgSreg),
+	/*9986*/ uint16(xArgRM16),
+	/*9987*/ uint16(xMatch),
+	/*9988*/ uint16(xSetOp), uint16(MOV),
+	/*9990*/ uint16(xReadSlashR),
+	/*9991*/ uint16(xArgSreg),
+	/*9992*/ uint16(xArgR32M16),
 	/*9993*/ uint16(xMatch),
-	/*9994*/ uint16(xSetOp), uint16(SAHF),
-	/*9996*/ uint16(xMatch),
-	/*9997*/ uint16(xSetOp), uint16(LAHF),
-	/*9999*/ uint16(xMatch),
-	/*10000*/ uint16(xCondIs64), 10003, 10009,
-	/*10003*/ uint16(xSetOp), uint16(MOV),
-	/*10005*/ uint16(xReadCm),
-	/*10006*/ uint16(xArgAL),
-	/*10007*/ uint16(xArgMoffs8),
-	/*10008*/ uint16(xMatch),
-	/*10009*/ uint16(xCondDataSize), 10003, 10003, 10013,
-	/*10013*/ uint16(xSetOp), uint16(MOV),
-	/*10015*/ uint16(xReadCm),
-	/*10016*/ uint16(xArgAL),
-	/*10017*/ uint16(xArgMoffs8),
-	/*10018*/ uint16(xMatch),
-	/*10019*/ uint16(xCondDataSize), 10023, 10029, 10035,
-	/*10023*/ uint16(xSetOp), uint16(MOV),
-	/*10025*/ uint16(xReadCm),
-	/*10026*/ uint16(xArgAX),
-	/*10027*/ uint16(xArgMoffs16),
-	/*10028*/ uint16(xMatch),
-	/*10029*/ uint16(xSetOp), uint16(MOV),
-	/*10031*/ uint16(xReadCm),
-	/*10032*/ uint16(xArgEAX),
-	/*10033*/ uint16(xArgMoffs32),
-	/*10034*/ uint16(xMatch),
-	/*10035*/ uint16(xSetOp), uint16(MOV),
-	/*10037*/ uint16(xReadCm),
-	/*10038*/ uint16(xArgRAX),
-	/*10039*/ uint16(xArgMoffs64),
-	/*10040*/ uint16(xMatch),
-	/*10041*/ uint16(xCondIs64), 10044, 10050,
-	/*10044*/ uint16(xSetOp), uint16(MOV),
-	/*10046*/ uint16(xReadCm),
-	/*10047*/ uint16(xArgMoffs8),
-	/*10048*/ uint16(xArgAL),
-	/*10049*/ uint16(xMatch),
-	/*10050*/ uint16(xCondDataSize), 10044, 10044, 10054,
-	/*10054*/ uint16(xSetOp), uint16(MOV),
-	/*10056*/ uint16(xReadCm),
-	/*10057*/ uint16(xArgMoffs8),
-	/*10058*/ uint16(xArgAL),
-	/*10059*/ uint16(xMatch),
-	/*10060*/ uint16(xCondDataSize), 10064, 10070, 10076,
-	/*10064*/ uint16(xSetOp), uint16(MOV),
-	/*10066*/ uint16(xReadCm),
-	/*10067*/ uint16(xArgMoffs16),
-	/*10068*/ uint16(xArgAX),
-	/*10069*/ uint16(xMatch),
-	/*10070*/ uint16(xSetOp), uint16(MOV),
-	/*10072*/ uint16(xReadCm),
-	/*10073*/ uint16(xArgMoffs32),
-	/*10074*/ uint16(xArgEAX),
+	/*9994*/ uint16(xCondDataSize), 9982, 9988, 9998,
+	/*9998*/ uint16(xSetOp), uint16(MOV),
+	/*10000*/ uint16(xReadSlashR),
+	/*10001*/ uint16(xArgSreg),
+	/*10002*/ uint16(xArgR64M16),
+	/*10003*/ uint16(xMatch),
+	/*10004*/ uint16(xCondSlashR),
+	10013, // 0
+	0,     // 1
+	0,     // 2
+	0,     // 3
+	0,     // 4
+	0,     // 5
+	0,     // 6
+	0,     // 7
+	/*10013*/ uint16(xCondIs64), 10016, 10028,
+	/*10016*/ uint16(xCondDataSize), 10020, 10024, 0,
+	/*10020*/ uint16(xSetOp), uint16(POP),
+	/*10022*/ uint16(xArgRM16),
+	/*10023*/ uint16(xMatch),
+	/*10024*/ uint16(xSetOp), uint16(POP),
+	/*10026*/ uint16(xArgRM32),
+	/*10027*/ uint16(xMatch),
+	/*10028*/ uint16(xCondDataSize), 10020, 10032, 10036,
+	/*10032*/ uint16(xSetOp), uint16(POP),
+	/*10034*/ uint16(xArgRM64),
+	/*10035*/ uint16(xMatch),
+	/*10036*/ uint16(xSetOp), uint16(POP),
+	/*10038*/ uint16(xArgRM64),
+	/*10039*/ uint16(xMatch),
+	/*10040*/ uint16(xCondIs64), 10043, 10057,
+	/*10043*/ uint16(xCondDataSize), 10047, 10052, 0,
+	/*10047*/ uint16(xSetOp), uint16(XCHG),
+	/*10049*/ uint16(xArgR16op),
+	/*10050*/ uint16(xArgAX),
+	/*10051*/ uint16(xMatch),
+	/*10052*/ uint16(xSetOp), uint16(XCHG),
+	/*10054*/ uint16(xArgR32op),
+	/*10055*/ uint16(xArgEAX),
+	/*10056*/ uint16(xMatch),
+	/*10057*/ uint16(xCondDataSize), 10047, 10052, 10061,
+	/*10061*/ uint16(xSetOp), uint16(XCHG),
+	/*10063*/ uint16(xArgR64op),
+	/*10064*/ uint16(xArgRAX),
+	/*10065*/ uint16(xMatch),
+	/*10066*/ uint16(xCondIs64), 10069, 10079,
+	/*10069*/ uint16(xCondDataSize), 10073, 10076, 0,
+	/*10073*/ uint16(xSetOp), uint16(CBW),
 	/*10075*/ uint16(xMatch),
-	/*10076*/ uint16(xSetOp), uint16(MOV),
-	/*10078*/ uint16(xReadCm),
-	/*10079*/ uint16(xArgMoffs64),
-	/*10080*/ uint16(xArgRAX),
-	/*10081*/ uint16(xMatch),
-	/*10082*/ uint16(xSetOp), uint16(MOVSB),
-	/*10084*/ uint16(xMatch),
-	/*10085*/ uint16(xCondIs64), 10088, 10098,
-	/*10088*/ uint16(xCondDataSize), 10092, 10095, 0,
-	/*10092*/ uint16(xSetOp), uint16(MOVSW),
-	/*10094*/ uint16(xMatch),
-	/*10095*/ uint16(xSetOp), uint16(MOVSD),
-	/*10097*/ uint16(xMatch),
-	/*10098*/ uint16(xCondDataSize), 10092, 10095, 10102,
-	/*10102*/ uint16(xSetOp), uint16(MOVSQ),
-	/*10104*/ uint16(xMatch),
-	/*10105*/ uint16(xSetOp), uint16(CMPSB),
-	/*10107*/ uint16(xMatch),
-	/*10108*/ uint16(xCondIs64), 10111, 10121,
-	/*10111*/ uint16(xCondDataSize), 10115, 10118, 0,
-	/*10115*/ uint16(xSetOp), uint16(CMPSW),
+	/*10076*/ uint16(xSetOp), uint16(CWDE),
+	/*10078*/ uint16(xMatch),
+	/*10079*/ uint16(xCondDataSize), 10073, 10076, 10083,
+	/*10083*/ uint16(xSetOp), uint16(CDQE),
+	/*10085*/ uint16(xMatch),
+	/*10086*/ uint16(xCondIs64), 10089, 10099,
+	/*10089*/ uint16(xCondDataSize), 10093, 10096, 0,
+	/*10093*/ uint16(xSetOp), uint16(CWD),
+	/*10095*/ uint16(xMatch),
+	/*10096*/ uint16(xSetOp), uint16(CDQ),
+	/*10098*/ uint16(xMatch),
+	/*10099*/ uint16(xCondDataSize), 10093, 10096, 10103,
+	/*10103*/ uint16(xSetOp), uint16(CQO),
+	/*10105*/ uint16(xMatch),
+	/*10106*/ uint16(xCondIs64), 10109, 0,
+	/*10109*/ uint16(xCondDataSize), 10113, 10118, 0,
+	/*10113*/ uint16(xSetOp), uint16(LCALL),
+	/*10115*/ uint16(xReadCd),
+	/*10116*/ uint16(xArgPtr16colon16),
 	/*10117*/ uint16(xMatch),
-	/*10118*/ uint16(xSetOp), uint16(CMPSD),
-	/*10120*/ uint16(xMatch),
-	/*10121*/ uint16(xCondDataSize), 10115, 10118, 10125,
-	/*10125*/ uint16(xSetOp), uint16(CMPSQ),
-	/*10127*/ uint16(xMatch),
-	/*10128*/ uint16(xSetOp), uint16(TEST),
-	/*10130*/ uint16(xReadIb),
-	/*10131*/ uint16(xArgAL),
-	/*10132*/ uint16(xArgImm8u),
-	/*10133*/ uint16(xMatch),
-	/*10134*/ uint16(xCondIs64), 10137, 10153,
-	/*10137*/ uint16(xCondDataSize), 10141, 10147, 0,
-	/*10141*/ uint16(xSetOp), uint16(TEST),
-	/*10143*/ uint16(xReadIw),
-	/*10144*/ uint16(xArgAX),
-	/*10145*/ uint16(xArgImm16),
-	/*10146*/ uint16(xMatch),
-	/*10147*/ uint16(xSetOp), uint16(TEST),
-	/*10149*/ uint16(xReadId),
-	/*10150*/ uint16(xArgEAX),
-	/*10151*/ uint16(xArgImm32),
-	/*10152*/ uint16(xMatch),
-	/*10153*/ uint16(xCondDataSize), 10141, 10147, 10157,
-	/*10157*/ uint16(xSetOp), uint16(TEST),
-	/*10159*/ uint16(xReadId),
-	/*10160*/ uint16(xArgRAX),
-	/*10161*/ uint16(xArgImm32),
-	/*10162*/ uint16(xMatch),
-	/*10163*/ uint16(xSetOp), uint16(STOSB),
-	/*10165*/ uint16(xMatch),
-	/*10166*/ uint16(xCondIs64), 10169, 10179,
-	/*10169*/ uint16(xCondDataSize), 10173, 10176, 0,
-	/*10173*/ uint16(xSetOp), uint16(STOSW),
-	/*10175*/ uint16(xMatch),
-	/*10176*/ uint16(xSetOp), uint16(STOSD),
-	/*10178*/ uint16(xMatch),
-	/*10179*/ uint16(xCondDataSize), 10173, 10176, 10183,
-	/*10183*/ uint16(xSetOp), uint16(STOSQ),
-	/*10185*/ uint16(xMatch),
-	/*10186*/ uint16(xSetOp), uint16(LODSB),
-	/*10188*/ uint16(xMatch),
-	/*10189*/ uint16(xCondIs64), 10192, 10202,
-	/*10192*/ uint16(xCondDataSize), 10196, 10199, 0,
-	/*10196*/ uint16(xSetOp), uint16(LODSW),
-	/*10198*/ uint16(xMatch),
-	/*10199*/ uint16(xSetOp), uint16(LODSD),
-	/*10201*/ uint16(xMatch),
-	/*10202*/ uint16(xCondDataSize), 10196, 10199, 10206,
-	/*10206*/ uint16(xSetOp), uint16(LODSQ),
-	/*10208*/ uint16(xMatch),
-	/*10209*/ uint16(xSetOp), uint16(SCASB),
-	/*10211*/ uint16(xMatch),
-	/*10212*/ uint16(xCondIs64), 10215, 10225,
-	/*10215*/ uint16(xCondDataSize), 10219, 10222, 0,
-	/*10219*/ uint16(xSetOp), uint16(SCASW),
-	/*10221*/ uint16(xMatch),
-	/*10222*/ uint16(xSetOp), uint16(SCASD),
-	/*10224*/ uint16(xMatch),
-	/*10225*/ uint16(xCondDataSize), 10219, 10222, 10229,
-	/*10229*/ uint16(xSetOp), uint16(SCASQ),
-	/*10231*/ uint16(xMatch),
+	/*10118*/ uint16(xSetOp), uint16(LCALL),
+	/*10120*/ uint16(xReadCp),
+	/*10121*/ uint16(xArgPtr16colon32),
+	/*10122*/ uint16(xMatch),
+	/*10123*/ uint16(xSetOp), uint16(FWAIT),
+	/*10125*/ uint16(xMatch),
+	/*10126*/ uint16(xCondIs64), 10129, 10139,
+	/*10129*/ uint16(xCondDataSize), 10133, 10136, 0,
+	/*10133*/ uint16(xSetOp), uint16(PUSHF),
+	/*10135*/ uint16(xMatch),
+	/*10136*/ uint16(xSetOp), uint16(PUSHFD),
+	/*10138*/ uint16(xMatch),
+	/*10139*/ uint16(xCondDataSize), 10133, 10143, 10146,
+	/*10143*/ uint16(xSetOp), uint16(PUSHFQ),
+	/*10145*/ uint16(xMatch),
+	/*10146*/ uint16(xSetOp), uint16(PUSHFQ),
+	/*10148*/ uint16(xMatch),
+	/*10149*/ uint16(xCondIs64), 10152, 10162,
+	/*10152*/ uint16(xCondDataSize), 10156, 10159, 0,
+	/*10156*/ uint16(xSetOp), uint16(POPF),
+	/*10158*/ uint16(xMatch),
+	/*10159*/ uint16(xSetOp), uint16(POPFD),
+	/*10161*/ uint16(xMatch),
+	/*10162*/ uint16(xCondDataSize), 10156, 10166, 10169,
+	/*10166*/ uint16(xSetOp), uint16(POPFQ),
+	/*10168*/ uint16(xMatch),
+	/*10169*/ uint16(xSetOp), uint16(POPFQ),
+	/*10171*/ uint16(xMatch),
+	/*10172*/ uint16(xSetOp), uint16(SAHF),
+	/*10174*/ uint16(xMatch),
+	/*10175*/ uint16(xSetOp), uint16(LAHF),
+	/*10177*/ uint16(xMatch),
+	/*10178*/ uint16(xCondIs64), 10181, 10187,
+	/*10181*/ uint16(xSetOp), uint16(MOV),
+	/*10183*/ uint16(xReadCm),
+	/*10184*/ uint16(xArgAL),
+	/*10185*/ uint16(xArgMoffs8),
+	/*10186*/ uint16(xMatch),
+	/*10187*/ uint16(xCondDataSize), 10181, 10181, 10191,
+	/*10191*/ uint16(xSetOp), uint16(MOV),
+	/*10193*/ uint16(xReadCm),
+	/*10194*/ uint16(xArgAL),
+	/*10195*/ uint16(xArgMoffs8),
+	/*10196*/ uint16(xMatch),
+	/*10197*/ uint16(xCondDataSize), 10201, 10207, 10213,
+	/*10201*/ uint16(xSetOp), uint16(MOV),
+	/*10203*/ uint16(xReadCm),
+	/*10204*/ uint16(xArgAX),
+	/*10205*/ uint16(xArgMoffs16),
+	/*10206*/ uint16(xMatch),
+	/*10207*/ uint16(xSetOp), uint16(MOV),
+	/*10209*/ uint16(xReadCm),
+	/*10210*/ uint16(xArgEAX),
+	/*10211*/ uint16(xArgMoffs32),
+	/*10212*/ uint16(xMatch),
+	/*10213*/ uint16(xSetOp), uint16(MOV),
+	/*10215*/ uint16(xReadCm),
+	/*10216*/ uint16(xArgRAX),
+	/*10217*/ uint16(xArgMoffs64),
+	/*10218*/ uint16(xMatch),
+	/*10219*/ uint16(xCondIs64), 10222, 10228,
+	/*10222*/ uint16(xSetOp), uint16(MOV),
+	/*10224*/ uint16(xReadCm),
+	/*10225*/ uint16(xArgMoffs8),
+	/*10226*/ uint16(xArgAL),
+	/*10227*/ uint16(xMatch),
+	/*10228*/ uint16(xCondDataSize), 10222, 10222, 10232,
 	/*10232*/ uint16(xSetOp), uint16(MOV),
-	/*10234*/ uint16(xReadIb),
-	/*10235*/ uint16(xArgR8op),
-	/*10236*/ uint16(xArgImm8u),
+	/*10234*/ uint16(xReadCm),
+	/*10235*/ uint16(xArgMoffs8),
+	/*10236*/ uint16(xArgAL),
 	/*10237*/ uint16(xMatch),
-	/*10238*/ uint16(xCondIs64), 10241, 10257,
-	/*10241*/ uint16(xCondDataSize), 10245, 10251, 0,
-	/*10245*/ uint16(xSetOp), uint16(MOV),
-	/*10247*/ uint16(xReadIw),
-	/*10248*/ uint16(xArgR16op),
-	/*10249*/ uint16(xArgImm16),
-	/*10250*/ uint16(xMatch),
-	/*10251*/ uint16(xSetOp), uint16(MOV),
-	/*10253*/ uint16(xReadId),
-	/*10254*/ uint16(xArgR32op),
-	/*10255*/ uint16(xArgImm32),
-	/*10256*/ uint16(xMatch),
-	/*10257*/ uint16(xCondDataSize), 10245, 10251, 10261,
-	/*10261*/ uint16(xSetOp), uint16(MOV),
-	/*10263*/ uint16(xReadIo),
-	/*10264*/ uint16(xArgR64op),
-	/*10265*/ uint16(xArgImm64),
-	/*10266*/ uint16(xMatch),
-	/*10267*/ uint16(xCondSlashR),
-	10276, // 0
-	10282, // 1
-	10288, // 2
-	10294, // 3
-	10300, // 4
-	10306, // 5
-	0,     // 6
-	10312, // 7
-	/*10276*/ uint16(xSetOp), uint16(ROL),
-	/*10278*/ uint16(xReadIb),
-	/*10279*/ uint16(xArgRM8),
-	/*10280*/ uint16(xArgImm8u),
-	/*10281*/ uint16(xMatch),
-	/*10282*/ uint16(xSetOp), uint16(ROR),
-	/*10284*/ uint16(xReadIb),
-	/*10285*/ uint16(xArgRM8),
-	/*10286*/ uint16(xArgImm8u),
-	/*10287*/ uint16(xMatch),
-	/*10288*/ uint16(xSetOp), uint16(RCL),
-	/*10290*/ uint16(xReadIb),
-	/*10291*/ uint16(xArgRM8),
-	/*10292*/ uint16(xArgImm8u),
-	/*10293*/ uint16(xMatch),
-	/*10294*/ uint16(xSetOp), uint16(RCR),
-	/*10296*/ uint16(xReadIb),
-	/*10297*/ uint16(xArgRM8),
-	/*10298*/ uint16(xArgImm8u),
-	/*10299*/ uint16(xMatch),
-	/*10300*/ uint16(xSetOp), uint16(SHL),
-	/*10302*/ uint16(xReadIb),
-	/*10303*/ uint16(xArgRM8),
-	/*10304*/ uint16(xArgImm8u),
+	/*10238*/ uint16(xCondDataSize), 10242, 10248, 10254,
+	/*10242*/ uint16(xSetOp), uint16(MOV),
+	/*10244*/ uint16(xReadCm),
+	/*10245*/ uint16(xArgMoffs16),
+	/*10246*/ uint16(xArgAX),
+	/*10247*/ uint16(xMatch),
+	/*10248*/ uint16(xSetOp), uint16(MOV),
+	/*10250*/ uint16(xReadCm),
+	/*10251*/ uint16(xArgMoffs32),
+	/*10252*/ uint16(xArgEAX),
+	/*10253*/ uint16(xMatch),
+	/*10254*/ uint16(xSetOp), uint16(MOV),
+	/*10256*/ uint16(xReadCm),
+	/*10257*/ uint16(xArgMoffs64),
+	/*10258*/ uint16(xArgRAX),
+	/*10259*/ uint16(xMatch),
+	/*10260*/ uint16(xSetOp), uint16(MOVSB),
+	/*10262*/ uint16(xMatch),
+	/*10263*/ uint16(xCondIs64), 10266, 10276,
+	/*10266*/ uint16(xCondDataSize), 10270, 10273, 0,
+	/*10270*/ uint16(xSetOp), uint16(MOVSW),
+	/*10272*/ uint16(xMatch),
+	/*10273*/ uint16(xSetOp), uint16(MOVSD),
+	/*10275*/ uint16(xMatch),
+	/*10276*/ uint16(xCondDataSize), 10270, 10273, 10280,
+	/*10280*/ uint16(xSetOp), uint16(MOVSQ),
+	/*10282*/ uint16(xMatch),
+	/*10283*/ uint16(xSetOp), uint16(CMPSB),
+	/*10285*/ uint16(xMatch),
+	/*10286*/ uint16(xCondIs64), 10289, 10299,
+	/*10289*/ uint16(xCondDataSize), 10293, 10296, 0,
+	/*10293*/ uint16(xSetOp), uint16(CMPSW),
+	/*10295*/ uint16(xMatch),
+	/*10296*/ uint16(xSetOp), uint16(CMPSD),
+	/*10298*/ uint16(xMatch),
+	/*10299*/ uint16(xCondDataSize), 10293, 10296, 10303,
+	/*10303*/ uint16(xSetOp), uint16(CMPSQ),
 	/*10305*/ uint16(xMatch),
-	/*10306*/ uint16(xSetOp), uint16(SHR),
+	/*10306*/ uint16(xSetOp), uint16(TEST),
 	/*10308*/ uint16(xReadIb),
-	/*10309*/ uint16(xArgRM8),
+	/*10309*/ uint16(xArgAL),
 	/*10310*/ uint16(xArgImm8u),
 	/*10311*/ uint16(xMatch),
-	/*10312*/ uint16(xSetOp), uint16(SAR),
-	/*10314*/ uint16(xReadIb),
-	/*10315*/ uint16(xArgRM8),
-	/*10316*/ uint16(xArgImm8u),
-	/*10317*/ uint16(xMatch),
-	/*10318*/ uint16(xCondSlashR),
-	10327, // 0
-	10349, // 1
-	10371, // 2
-	10400, // 3
-	10429, // 4
-	10458, // 5
-	0,     // 6
-	10487, // 7
-	/*10327*/ uint16(xCondDataSize), 10331, 10337, 10343,
-	/*10331*/ uint16(xSetOp), uint16(ROL),
-	/*10333*/ uint16(xReadIb),
-	/*10334*/ uint16(xArgRM16),
-	/*10335*/ uint16(xArgImm8u),
-	/*10336*/ uint16(xMatch),
-	/*10337*/ uint16(xSetOp), uint16(ROL),
-	/*10339*/ uint16(xReadIb),
-	/*10340*/ uint16(xArgRM32),
-	/*10341*/ uint16(xArgImm8u),
-	/*10342*/ uint16(xMatch),
-	/*10343*/ uint16(xSetOp), uint16(ROL),
-	/*10345*/ uint16(xReadIb),
-	/*10346*/ uint16(xArgRM64),
-	/*10347*/ uint16(xArgImm8u),
-	/*10348*/ uint16(xMatch),
-	/*10349*/ uint16(xCondDataSize), 10353, 10359, 10365,
-	/*10353*/ uint16(xSetOp), uint16(ROR),
-	/*10355*/ uint16(xReadIb),
-	/*10356*/ uint16(xArgRM16),
-	/*10357*/ uint16(xArgImm8u),
-	/*10358*/ uint16(xMatch),
-	/*10359*/ uint16(xSetOp), uint16(ROR),
-	/*10361*/ uint16(xReadIb),
-	/*10362*/ uint16(xArgRM32),
-	/*10363*/ uint16(xArgImm8u),
-	/*10364*/ uint16(xMatch),
-	/*10365*/ uint16(xSetOp), uint16(ROR),
-	/*10367*/ uint16(xReadIb),
-	/*10368*/ uint16(xArgRM64),
-	/*10369*/ uint16(xArgImm8u),
-	/*10370*/ uint16(xMatch),
-	/*10371*/ uint16(xCondIs64), 10374, 10390,
-	/*10374*/ uint16(xCondDataSize), 10378, 10384, 0,
-	/*10378*/ uint16(xSetOp), uint16(RCL),
-	/*10380*/ uint16(xReadIb),
-	/*10381*/ uint16(xArgRM16),
-	/*10382*/ uint16(xArgImm8u),
-	/*10383*/ uint16(xMatch),
-	/*10384*/ uint16(xSetOp), uint16(RCL),
-	/*10386*/ uint16(xReadIb),
-	/*10387*/ uint16(xArgRM32),
-	/*10388*/ uint16(xArgImm8u),
+	/*10312*/ uint16(xCondIs64), 10315, 10331,
+	/*10315*/ uint16(xCondDataSize), 10319, 10325, 0,
+	/*10319*/ uint16(xSetOp), uint16(TEST),
+	/*10321*/ uint16(xReadIw),
+	/*10322*/ uint16(xArgAX),
+	/*10323*/ uint16(xArgImm16),
+	/*10324*/ uint16(xMatch),
+	/*10325*/ uint16(xSetOp), uint16(TEST),
+	/*10327*/ uint16(xReadId),
+	/*10328*/ uint16(xArgEAX),
+	/*10329*/ uint16(xArgImm32),
+	/*10330*/ uint16(xMatch),
+	/*10331*/ uint16(xCondDataSize), 10319, 10325, 10335,
+	/*10335*/ uint16(xSetOp), uint16(TEST),
+	/*10337*/ uint16(xReadId),
+	/*10338*/ uint16(xArgRAX),
+	/*10339*/ uint16(xArgImm32),
+	/*10340*/ uint16(xMatch),
+	/*10341*/ uint16(xSetOp), uint16(STOSB),
+	/*10343*/ uint16(xMatch),
+	/*10344*/ uint16(xCondIs64), 10347, 10357,
+	/*10347*/ uint16(xCondDataSize), 10351, 10354, 0,
+	/*10351*/ uint16(xSetOp), uint16(STOSW),
+	/*10353*/ uint16(xMatch),
+	/*10354*/ uint16(xSetOp), uint16(STOSD),
+	/*10356*/ uint16(xMatch),
+	/*10357*/ uint16(xCondDataSize), 10351, 10354, 10361,
+	/*10361*/ uint16(xSetOp), uint16(STOSQ),
+	/*10363*/ uint16(xMatch),
+	/*10364*/ uint16(xSetOp), uint16(LODSB),
+	/*10366*/ uint16(xMatch),
+	/*10367*/ uint16(xCondIs64), 10370, 10380,
+	/*10370*/ uint16(xCondDataSize), 10374, 10377, 0,
+	/*10374*/ uint16(xSetOp), uint16(LODSW),
+	/*10376*/ uint16(xMatch),
+	/*10377*/ uint16(xSetOp), uint16(LODSD),
+	/*10379*/ uint16(xMatch),
+	/*10380*/ uint16(xCondDataSize), 10374, 10377, 10384,
+	/*10384*/ uint16(xSetOp), uint16(LODSQ),
+	/*10386*/ uint16(xMatch),
+	/*10387*/ uint16(xSetOp), uint16(SCASB),
 	/*10389*/ uint16(xMatch),
-	/*10390*/ uint16(xCondDataSize), 10378, 10384, 10394,
-	/*10394*/ uint16(xSetOp), uint16(RCL),
-	/*10396*/ uint16(xReadIb),
-	/*10397*/ uint16(xArgRM64),
-	/*10398*/ uint16(xArgImm8u),
+	/*10390*/ uint16(xCondIs64), 10393, 10403,
+	/*10393*/ uint16(xCondDataSize), 10397, 10400, 0,
+	/*10397*/ uint16(xSetOp), uint16(SCASW),
 	/*10399*/ uint16(xMatch),
-	/*10400*/ uint16(xCondIs64), 10403, 10419,
-	/*10403*/ uint16(xCondDataSize), 10407, 10413, 0,
-	/*10407*/ uint16(xSetOp), uint16(RCR),
-	/*10409*/ uint16(xReadIb),
-	/*10410*/ uint16(xArgRM16),
-	/*10411*/ uint16(xArgImm8u),
-	/*10412*/ uint16(xMatch),
-	/*10413*/ uint16(xSetOp), uint16(RCR),
-	/*10415*/ uint16(xReadIb),
-	/*10416*/ uint16(xArgRM32),
-	/*10417*/ uint16(xArgImm8u),
-	/*10418*/ uint16(xMatch),
-	/*10419*/ uint16(xCondDataSize), 10407, 10413, 10423,
-	/*10423*/ uint16(xSetOp), uint16(RCR),
-	/*10425*/ uint16(xReadIb),
-	/*10426*/ uint16(xArgRM64),
-	/*10427*/ uint16(xArgImm8u),
+	/*10400*/ uint16(xSetOp), uint16(SCASD),
+	/*10402*/ uint16(xMatch),
+	/*10403*/ uint16(xCondDataSize), 10397, 10400, 10407,
+	/*10407*/ uint16(xSetOp), uint16(SCASQ),
+	/*10409*/ uint16(xMatch),
+	/*10410*/ uint16(xSetOp), uint16(MOV),
+	/*10412*/ uint16(xReadIb),
+	/*10413*/ uint16(xArgR8op),
+	/*10414*/ uint16(xArgImm8u),
+	/*10415*/ uint16(xMatch),
+	/*10416*/ uint16(xCondIs64), 10419, 10435,
+	/*10419*/ uint16(xCondDataSize), 10423, 10429, 0,
+	/*10423*/ uint16(xSetOp), uint16(MOV),
+	/*10425*/ uint16(xReadIw),
+	/*10426*/ uint16(xArgR16op),
+	/*10427*/ uint16(xArgImm16),
 	/*10428*/ uint16(xMatch),
-	/*10429*/ uint16(xCondIs64), 10432, 10448,
-	/*10432*/ uint16(xCondDataSize), 10436, 10442, 0,
-	/*10436*/ uint16(xSetOp), uint16(SHL),
-	/*10438*/ uint16(xReadIb),
-	/*10439*/ uint16(xArgRM16),
-	/*10440*/ uint16(xArgImm8u),
-	/*10441*/ uint16(xMatch),
-	/*10442*/ uint16(xSetOp), uint16(SHL),
-	/*10444*/ uint16(xReadIb),
-	/*10445*/ uint16(xArgRM32),
-	/*10446*/ uint16(xArgImm8u),
-	/*10447*/ uint16(xMatch),
-	/*10448*/ uint16(xCondDataSize), 10436, 10442, 10452,
-	/*10452*/ uint16(xSetOp), uint16(SHL),
-	/*10454*/ uint16(xReadIb),
-	/*10455*/ uint16(xArgRM64),
-	/*10456*/ uint16(xArgImm8u),
-	/*10457*/ uint16(xMatch),
-	/*10458*/ uint16(xCondIs64), 10461, 10477,
-	/*10461*/ uint16(xCondDataSize), 10465, 10471, 0,
-	/*10465*/ uint16(xSetOp), uint16(SHR),
-	/*10467*/ uint16(xReadIb),
-	/*10468*/ uint16(xArgRM16),
-	/*10469*/ uint16(xArgImm8u),
-	/*10470*/ uint16(xMatch),
-	/*10471*/ uint16(xSetOp), uint16(SHR),
-	/*10473*/ uint16(xReadIb),
-	/*10474*/ uint16(xArgRM32),
-	/*10475*/ uint16(xArgImm8u),
-	/*10476*/ uint16(xMatch),
-	/*10477*/ uint16(xCondDataSize), 10465, 10471, 10481,
-	/*10481*/ uint16(xSetOp), uint16(SHR),
-	/*10483*/ uint16(xReadIb),
-	/*10484*/ uint16(xArgRM64),
-	/*10485*/ uint16(xArgImm8u),
-	/*10486*/ uint16(xMatch),
-	/*10487*/ uint16(xCondIs64), 10490, 10506,
-	/*10490*/ uint16(xCondDataSize), 10494, 10500, 0,
-	/*10494*/ uint16(xSetOp), uint16(SAR),
-	/*10496*/ uint16(xReadIb),
-	/*10497*/ uint16(xArgRM16),
-	/*10498*/ uint16(xArgImm8u),
-	/*10499*/ uint16(xMatch),
-	/*10500*/ uint16(xSetOp), uint16(SAR),
-	/*10502*/ uint16(xReadIb),
-	/*10503*/ uint16(xArgRM32),
-	/*10504*/ uint16(xArgImm8u),
-	/*10505*/ uint16(xMatch),
-	/*10506*/ uint16(xCondDataSize), 10494, 10500, 10510,
-	/*10510*/ uint16(xSetOp), uint16(SAR),
-	/*10512*/ uint16(xReadIb),
-	/*10513*/ uint16(xArgRM64),
-	/*10514*/ uint16(xArgImm8u),
-	/*10515*/ uint16(xMatch),
-	/*10516*/ uint16(xSetOp), uint16(RET),
-	/*10518*/ uint16(xReadIw),
-	/*10519*/ uint16(xArgImm16u),
+	/*10429*/ uint16(xSetOp), uint16(MOV),
+	/*10431*/ uint16(xReadId),
+	/*10432*/ uint16(xArgR32op),
+	/*10433*/ uint16(xArgImm32),
+	/*10434*/ uint16(xMatch),
+	/*10435*/ uint16(xCondDataSize), 10423, 10429, 10439,
+	/*10439*/ uint16(xSetOp), uint16(MOV),
+	/*10441*/ uint16(xReadIo),
+	/*10442*/ uint16(xArgR64op),
+	/*10443*/ uint16(xArgImm64),
+	/*10444*/ uint16(xMatch),
+	/*10445*/ uint16(xCondSlashR),
+	10454, // 0
+	10460, // 1
+	10466, // 2
+	10472, // 3
+	10478, // 4
+	10484, // 5
+	0,     // 6
+	10490, // 7
+	/*10454*/ uint16(xSetOp), uint16(ROL),
+	/*10456*/ uint16(xReadIb),
+	/*10457*/ uint16(xArgRM8),
+	/*10458*/ uint16(xArgImm8u),
+	/*10459*/ uint16(xMatch),
+	/*10460*/ uint16(xSetOp), uint16(ROR),
+	/*10462*/ uint16(xReadIb),
+	/*10463*/ uint16(xArgRM8),
+	/*10464*/ uint16(xArgImm8u),
+	/*10465*/ uint16(xMatch),
+	/*10466*/ uint16(xSetOp), uint16(RCL),
+	/*10468*/ uint16(xReadIb),
+	/*10469*/ uint16(xArgRM8),
+	/*10470*/ uint16(xArgImm8u),
+	/*10471*/ uint16(xMatch),
+	/*10472*/ uint16(xSetOp), uint16(RCR),
+	/*10474*/ uint16(xReadIb),
+	/*10475*/ uint16(xArgRM8),
+	/*10476*/ uint16(xArgImm8u),
+	/*10477*/ uint16(xMatch),
+	/*10478*/ uint16(xSetOp), uint16(SHL),
+	/*10480*/ uint16(xReadIb),
+	/*10481*/ uint16(xArgRM8),
+	/*10482*/ uint16(xArgImm8u),
+	/*10483*/ uint16(xMatch),
+	/*10484*/ uint16(xSetOp), uint16(SHR),
+	/*10486*/ uint16(xReadIb),
+	/*10487*/ uint16(xArgRM8),
+	/*10488*/ uint16(xArgImm8u),
+	/*10489*/ uint16(xMatch),
+	/*10490*/ uint16(xSetOp), uint16(SAR),
+	/*10492*/ uint16(xReadIb),
+	/*10493*/ uint16(xArgRM8),
+	/*10494*/ uint16(xArgImm8u),
+	/*10495*/ uint16(xMatch),
+	/*10496*/ uint16(xCondSlashR),
+	10505, // 0
+	10527, // 1
+	10549, // 2
+	10578, // 3
+	10607, // 4
+	10636, // 5
+	0,     // 6
+	10665, // 7
+	/*10505*/ uint16(xCondDataSize), 10509, 10515, 10521,
+	/*10509*/ uint16(xSetOp), uint16(ROL),
+	/*10511*/ uint16(xReadIb),
+	/*10512*/ uint16(xArgRM16),
+	/*10513*/ uint16(xArgImm8u),
+	/*10514*/ uint16(xMatch),
+	/*10515*/ uint16(xSetOp), uint16(ROL),
+	/*10517*/ uint16(xReadIb),
+	/*10518*/ uint16(xArgRM32),
+	/*10519*/ uint16(xArgImm8u),
 	/*10520*/ uint16(xMatch),
-	/*10521*/ uint16(xSetOp), uint16(RET),
-	/*10523*/ uint16(xMatch),
-	/*10524*/ uint16(xCondIs64), 10527, 0,
-	/*10527*/ uint16(xCondDataSize), 10531, 10537, 0,
-	/*10531*/ uint16(xSetOp), uint16(LES),
-	/*10533*/ uint16(xReadSlashR),
-	/*10534*/ uint16(xArgR16),
-	/*10535*/ uint16(xArgM16colon16),
+	/*10521*/ uint16(xSetOp), uint16(ROL),
+	/*10523*/ uint16(xReadIb),
+	/*10524*/ uint16(xArgRM64),
+	/*10525*/ uint16(xArgImm8u),
+	/*10526*/ uint16(xMatch),
+	/*10527*/ uint16(xCondDataSize), 10531, 10537, 10543,
+	/*10531*/ uint16(xSetOp), uint16(ROR),
+	/*10533*/ uint16(xReadIb),
+	/*10534*/ uint16(xArgRM16),
+	/*10535*/ uint16(xArgImm8u),
 	/*10536*/ uint16(xMatch),
-	/*10537*/ uint16(xSetOp), uint16(LES),
-	/*10539*/ uint16(xReadSlashR),
-	/*10540*/ uint16(xArgR32),
-	/*10541*/ uint16(xArgM16colon32),
+	/*10537*/ uint16(xSetOp), uint16(ROR),
+	/*10539*/ uint16(xReadIb),
+	/*10540*/ uint16(xArgRM32),
+	/*10541*/ uint16(xArgImm8u),
 	/*10542*/ uint16(xMatch),
-	/*10543*/ uint16(xCondIs64), 10546, 0,
-	/*10546*/ uint16(xCondDataSize), 10550, 10556, 0,
-	/*10550*/ uint16(xSetOp), uint16(LDS),
-	/*10552*/ uint16(xReadSlashR),
-	/*10553*/ uint16(xArgR16),
-	/*10554*/ uint16(xArgM16colon16),
-	/*10555*/ uint16(xMatch),
-	/*10556*/ uint16(xSetOp), uint16(LDS),
-	/*10558*/ uint16(xReadSlashR),
-	/*10559*/ uint16(xArgR32),
-	/*10560*/ uint16(xArgM16colon32),
+	/*10543*/ uint16(xSetOp), uint16(ROR),
+	/*10545*/ uint16(xReadIb),
+	/*10546*/ uint16(xArgRM64),
+	/*10547*/ uint16(xArgImm8u),
+	/*10548*/ uint16(xMatch),
+	/*10549*/ uint16(xCondIs64), 10552, 10568,
+	/*10552*/ uint16(xCondDataSize), 10556, 10562, 0,
+	/*10556*/ uint16(xSetOp), uint16(RCL),
+	/*10558*/ uint16(xReadIb),
+	/*10559*/ uint16(xArgRM16),
+	/*10560*/ uint16(xArgImm8u),
 	/*10561*/ uint16(xMatch),
-	/*10562*/ uint16(xCondByte), 1,
-	0xF8, 10581,
-	/*10566*/ uint16(xCondSlashR),
-	10575, // 0
+	/*10562*/ uint16(xSetOp), uint16(RCL),
+	/*10564*/ uint16(xReadIb),
+	/*10565*/ uint16(xArgRM32),
+	/*10566*/ uint16(xArgImm8u),
+	/*10567*/ uint16(xMatch),
+	/*10568*/ uint16(xCondDataSize), 10556, 10562, 10572,
+	/*10572*/ uint16(xSetOp), uint16(RCL),
+	/*10574*/ uint16(xReadIb),
+	/*10575*/ uint16(xArgRM64),
+	/*10576*/ uint16(xArgImm8u),
+	/*10577*/ uint16(xMatch),
+	/*10578*/ uint16(xCondIs64), 10581, 10597,
+	/*10581*/ uint16(xCondDataSize), 10585, 10591, 0,
+	/*10585*/ uint16(xSetOp), uint16(RCR),
+	/*10587*/ uint16(xReadIb),
+	/*10588*/ uint16(xArgRM16),
+	/*10589*/ uint16(xArgImm8u),
+	/*10590*/ uint16(xMatch),
+	/*10591*/ uint16(xSetOp), uint16(RCR),
+	/*10593*/ uint16(xReadIb),
+	/*10594*/ uint16(xArgRM32),
+	/*10595*/ uint16(xArgImm8u),
+	/*10596*/ uint16(xMatch),
+	/*10597*/ uint16(xCondDataSize), 10585, 10591, 10601,
+	/*10601*/ uint16(xSetOp), uint16(RCR),
+	/*10603*/ uint16(xReadIb),
+	/*10604*/ uint16(xArgRM64),
+	/*10605*/ uint16(xArgImm8u),
+	/*10606*/ uint16(xMatch),
+	/*10607*/ uint16(xCondIs64), 10610, 10626,
+	/*10610*/ uint16(xCondDataSize), 10614, 10620, 0,
+	/*10614*/ uint16(xSetOp), uint16(SHL),
+	/*10616*/ uint16(xReadIb),
+	/*10617*/ uint16(xArgRM16),
+	/*10618*/ uint16(xArgImm8u),
+	/*10619*/ uint16(xMatch),
+	/*10620*/ uint16(xSetOp), uint16(SHL),
+	/*10622*/ uint16(xReadIb),
+	/*10623*/ uint16(xArgRM32),
+	/*10624*/ uint16(xArgImm8u),
+	/*10625*/ uint16(xMatch),
+	/*10626*/ uint16(xCondDataSize), 10614, 10620, 10630,
+	/*10630*/ uint16(xSetOp), uint16(SHL),
+	/*10632*/ uint16(xReadIb),
+	/*10633*/ uint16(xArgRM64),
+	/*10634*/ uint16(xArgImm8u),
+	/*10635*/ uint16(xMatch),
+	/*10636*/ uint16(xCondIs64), 10639, 10655,
+	/*10639*/ uint16(xCondDataSize), 10643, 10649, 0,
+	/*10643*/ uint16(xSetOp), uint16(SHR),
+	/*10645*/ uint16(xReadIb),
+	/*10646*/ uint16(xArgRM16),
+	/*10647*/ uint16(xArgImm8u),
+	/*10648*/ uint16(xMatch),
+	/*10649*/ uint16(xSetOp), uint16(SHR),
+	/*10651*/ uint16(xReadIb),
+	/*10652*/ uint16(xArgRM32),
+	/*10653*/ uint16(xArgImm8u),
+	/*10654*/ uint16(xMatch),
+	/*10655*/ uint16(xCondDataSize), 10643, 10649, 10659,
+	/*10659*/ uint16(xSetOp), uint16(SHR),
+	/*10661*/ uint16(xReadIb),
+	/*10662*/ uint16(xArgRM64),
+	/*10663*/ uint16(xArgImm8u),
+	/*10664*/ uint16(xMatch),
+	/*10665*/ uint16(xCondIs64), 10668, 10684,
+	/*10668*/ uint16(xCondDataSize), 10672, 10678, 0,
+	/*10672*/ uint16(xSetOp), uint16(SAR),
+	/*10674*/ uint16(xReadIb),
+	/*10675*/ uint16(xArgRM16),
+	/*10676*/ uint16(xArgImm8u),
+	/*10677*/ uint16(xMatch),
+	/*10678*/ uint16(xSetOp), uint16(SAR),
+	/*10680*/ uint16(xReadIb),
+	/*10681*/ uint16(xArgRM32),
+	/*10682*/ uint16(xArgImm8u),
+	/*10683*/ uint16(xMatch),
+	/*10684*/ uint16(xCondDataSize), 10672, 10678, 10688,
+	/*10688*/ uint16(xSetOp), uint16(SAR),
+	/*10690*/ uint16(xReadIb),
+	/*10691*/ uint16(xArgRM64),
+	/*10692*/ uint16(xArgImm8u),
+	/*10693*/ uint16(xMatch),
+	/*10694*/ uint16(xSetOp), uint16(RET),
+	/*10696*/ uint16(xReadIw),
+	/*10697*/ uint16(xArgImm16u),
+	/*10698*/ uint16(xMatch),
+	/*10699*/ uint16(xSetOp), uint16(RET),
+	/*10701*/ uint16(xMatch),
+	/*10702*/ uint16(xCondIs64), 10705, 0,
+	/*10705*/ uint16(xCondDataSize), 10709, 10715, 0,
+	/*10709*/ uint16(xSetOp), uint16(LES),
+	/*10711*/ uint16(xReadSlashR),
+	/*10712*/ uint16(xArgR16),
+	/*10713*/ uint16(xArgM16colon16),
+	/*10714*/ uint16(xMatch),
+	/*10715*/ uint16(xSetOp), uint16(LES),
+	/*10717*/ uint16(xReadSlashR),
+	/*10718*/ uint16(xArgR32),
+	/*10719*/ uint16(xArgM16colon32),
+	/*10720*/ uint16(xMatch),
+	/*10721*/ uint16(xCondIs64), 10724, 0,
+	/*10724*/ uint16(xCondDataSize), 10728, 10734, 0,
+	/*10728*/ uint16(xSetOp), uint16(LDS),
+	/*10730*/ uint16(xReadSlashR),
+	/*10731*/ uint16(xArgR16),
+	/*10732*/ uint16(xArgM16colon16),
+	/*10733*/ uint16(xMatch),
+	/*10734*/ uint16(xSetOp), uint16(LDS),
+	/*10736*/ uint16(xReadSlashR),
+	/*10737*/ uint16(xArgR32),
+	/*10738*/ uint16(xArgM16colon32),
+	/*10739*/ uint16(xMatch),
+	/*10740*/ uint16(xCondByte), 1,
+	0xF8, 10759,
+	/*10744*/ uint16(xCondSlashR),
+	10753, // 0
 	0,     // 1
 	0,     // 2
 	0,     // 3
@@ -6889,19 +6999,19 @@ var decoder = [...]uint16{
 	0,     // 5
 	0,     // 6
 	0,     // 7
-	/*10575*/ uint16(xSetOp), uint16(MOV),
-	/*10577*/ uint16(xReadIb),
-	/*10578*/ uint16(xArgRM8),
-	/*10579*/ uint16(xArgImm8u),
-	/*10580*/ uint16(xMatch),
-	/*10581*/ uint16(xSetOp), uint16(XABORT),
-	/*10583*/ uint16(xReadIb),
-	/*10584*/ uint16(xArgImm8u),
-	/*10585*/ uint16(xMatch),
-	/*10586*/ uint16(xCondByte), 1,
-	0xF8, 10628,
-	/*10590*/ uint16(xCondSlashR),
-	10599, // 0
+	/*10753*/ uint16(xSetOp), uint16(MOV),
+	/*10755*/ uint16(xReadIb),
+	/*10756*/ uint16(xArgRM8),
+	/*10757*/ uint16(xArgImm8u),
+	/*10758*/ uint16(xMatch),
+	/*10759*/ uint16(xSetOp), uint16(XABORT),
+	/*10761*/ uint16(xReadIb),
+	/*10762*/ uint16(xArgImm8u),
+	/*10763*/ uint16(xMatch),
+	/*10764*/ uint16(xCondByte), 1,
+	0xF8, 10806,
+	/*10768*/ uint16(xCondSlashR),
+	10777, // 0
 	0,     // 1
 	0,     // 2
 	0,     // 3
@@ -6909,1634 +7019,1656 @@ var decoder = [...]uint16{
 	0,     // 5
 	0,     // 6
 	0,     // 7
-	/*10599*/ uint16(xCondIs64), 10602, 10618,
-	/*10602*/ uint16(xCondDataSize), 10606, 10612, 0,
-	/*10606*/ uint16(xSetOp), uint16(MOV),
-	/*10608*/ uint16(xReadIw),
-	/*10609*/ uint16(xArgRM16),
-	/*10610*/ uint16(xArgImm16),
-	/*10611*/ uint16(xMatch),
-	/*10612*/ uint16(xSetOp), uint16(MOV),
-	/*10614*/ uint16(xReadId),
-	/*10615*/ uint16(xArgRM32),
-	/*10616*/ uint16(xArgImm32),
-	/*10617*/ uint16(xMatch),
-	/*10618*/ uint16(xCondDataSize), 10606, 10612, 10622,
-	/*10622*/ uint16(xSetOp), uint16(MOV),
-	/*10624*/ uint16(xReadId),
-	/*10625*/ uint16(xArgRM64),
-	/*10626*/ uint16(xArgImm32),
-	/*10627*/ uint16(xMatch),
-	/*10628*/ uint16(xCondDataSize), 10632, 10637, 10642,
-	/*10632*/ uint16(xSetOp), uint16(XBEGIN),
-	/*10634*/ uint16(xReadCw),
-	/*10635*/ uint16(xArgRel16),
-	/*10636*/ uint16(xMatch),
-	/*10637*/ uint16(xSetOp), uint16(XBEGIN),
-	/*10639*/ uint16(xReadCd),
-	/*10640*/ uint16(xArgRel32),
-	/*10641*/ uint16(xMatch),
-	/*10642*/ uint16(xSetOp), uint16(XBEGIN),
-	/*10644*/ uint16(xReadCd),
-	/*10645*/ uint16(xArgRel32),
-	/*10646*/ uint16(xMatch),
-	/*10647*/ uint16(xSetOp), uint16(ENTER),
-	/*10649*/ uint16(xReadIw),
-	/*10650*/ uint16(xReadIb),
-	/*10651*/ uint16(xArgImm16u),
-	/*10652*/ uint16(xArgImm8u),
-	/*10653*/ uint16(xMatch),
-	/*10654*/ uint16(xCondIs64), 10657, 10667,
-	/*10657*/ uint16(xCondDataSize), 10661, 10664, 0,
-	/*10661*/ uint16(xSetOp), uint16(LEAVE),
-	/*10663*/ uint16(xMatch),
-	/*10664*/ uint16(xSetOp), uint16(LEAVE),
-	/*10666*/ uint16(xMatch),
-	/*10667*/ uint16(xCondDataSize), 10661, 10671, 10674,
-	/*10671*/ uint16(xSetOp), uint16(LEAVE),
-	/*10673*/ uint16(xMatch),
-	/*10674*/ uint16(xSetOp), uint16(LEAVE),
-	/*10676*/ uint16(xMatch),
-	/*10677*/ uint16(xSetOp), uint16(LRET),
-	/*10679*/ uint16(xReadIw),
-	/*10680*/ uint16(xArgImm16u),
-	/*10681*/ uint16(xMatch),
-	/*10682*/ uint16(xSetOp), uint16(LRET),
-	/*10684*/ uint16(xMatch),
-	/*10685*/ uint16(xSetOp), uint16(INT),
-	/*10687*/ uint16(xArg3),
-	/*10688*/ uint16(xMatch),
-	/*10689*/ uint16(xSetOp), uint16(INT),
-	/*10691*/ uint16(xReadIb),
-	/*10692*/ uint16(xArgImm8u),
-	/*10693*/ uint16(xMatch),
-	/*10694*/ uint16(xCondIs64), 10697, 0,
-	/*10697*/ uint16(xSetOp), uint16(INTO),
-	/*10699*/ uint16(xMatch),
-	/*10700*/ uint16(xCondIs64), 10703, 10713,
-	/*10703*/ uint16(xCondDataSize), 10707, 10710, 0,
-	/*10707*/ uint16(xSetOp), uint16(IRET),
-	/*10709*/ uint16(xMatch),
-	/*10710*/ uint16(xSetOp), uint16(IRETD),
-	/*10712*/ uint16(xMatch),
-	/*10713*/ uint16(xCondDataSize), 10707, 10710, 10717,
-	/*10717*/ uint16(xSetOp), uint16(IRETQ),
-	/*10719*/ uint16(xMatch),
-	/*10720*/ uint16(xCondSlashR),
-	10729, // 0
-	10734, // 1
-	10739, // 2
-	10744, // 3
-	10749, // 4
-	10754, // 5
-	0,     // 6
-	10759, // 7
-	/*10729*/ uint16(xSetOp), uint16(ROL),
-	/*10731*/ uint16(xArgRM8),
-	/*10732*/ uint16(xArg1),
-	/*10733*/ uint16(xMatch),
-	/*10734*/ uint16(xSetOp), uint16(ROR),
-	/*10736*/ uint16(xArgRM8),
-	/*10737*/ uint16(xArg1),
-	/*10738*/ uint16(xMatch),
-	/*10739*/ uint16(xSetOp), uint16(RCL),
-	/*10741*/ uint16(xArgRM8),
-	/*10742*/ uint16(xArg1),
-	/*10743*/ uint16(xMatch),
-	/*10744*/ uint16(xSetOp), uint16(RCR),
-	/*10746*/ uint16(xArgRM8),
-	/*10747*/ uint16(xArg1),
-	/*10748*/ uint16(xMatch),
-	/*10749*/ uint16(xSetOp), uint16(SHL),
-	/*10751*/ uint16(xArgRM8),
-	/*10752*/ uint16(xArg1),
-	/*10753*/ uint16(xMatch),
-	/*10754*/ uint16(xSetOp), uint16(SHR),
-	/*10756*/ uint16(xArgRM8),
-	/*10757*/ uint16(xArg1),
-	/*10758*/ uint16(xMatch),
-	/*10759*/ uint16(xSetOp), uint16(SAR),
-	/*10761*/ uint16(xArgRM8),
-	/*10762*/ uint16(xArg1),
-	/*10763*/ uint16(xMatch),
-	/*10764*/ uint16(xCondSlashR),
-	10773, // 0
-	10799, // 1
-	10825, // 2
-	10851, // 3
-	10877, // 4
-	10903, // 5
-	0,     // 6
-	10929, // 7
-	/*10773*/ uint16(xCondIs64), 10776, 10790,
-	/*10776*/ uint16(xCondDataSize), 10780, 10785, 0,
-	/*10780*/ uint16(xSetOp), uint16(ROL),
-	/*10782*/ uint16(xArgRM16),
-	/*10783*/ uint16(xArg1),
-	/*10784*/ uint16(xMatch),
-	/*10785*/ uint16(xSetOp), uint16(ROL),
-	/*10787*/ uint16(xArgRM32),
-	/*10788*/ uint16(xArg1),
+	/*10777*/ uint16(xCondIs64), 10780, 10796,
+	/*10780*/ uint16(xCondDataSize), 10784, 10790, 0,
+	/*10784*/ uint16(xSetOp), uint16(MOV),
+	/*10786*/ uint16(xReadIw),
+	/*10787*/ uint16(xArgRM16),
+	/*10788*/ uint16(xArgImm16),
 	/*10789*/ uint16(xMatch),
-	/*10790*/ uint16(xCondDataSize), 10780, 10785, 10794,
-	/*10794*/ uint16(xSetOp), uint16(ROL),
-	/*10796*/ uint16(xArgRM64),
-	/*10797*/ uint16(xArg1),
-	/*10798*/ uint16(xMatch),
-	/*10799*/ uint16(xCondIs64), 10802, 10816,
-	/*10802*/ uint16(xCondDataSize), 10806, 10811, 0,
-	/*10806*/ uint16(xSetOp), uint16(ROR),
-	/*10808*/ uint16(xArgRM16),
-	/*10809*/ uint16(xArg1),
-	/*10810*/ uint16(xMatch),
-	/*10811*/ uint16(xSetOp), uint16(ROR),
-	/*10813*/ uint16(xArgRM32),
-	/*10814*/ uint16(xArg1),
-	/*10815*/ uint16(xMatch),
-	/*10816*/ uint16(xCondDataSize), 10806, 10811, 10820,
-	/*10820*/ uint16(xSetOp), uint16(ROR),
-	/*10822*/ uint16(xArgRM64),
-	/*10823*/ uint16(xArg1),
+	/*10790*/ uint16(xSetOp), uint16(MOV),
+	/*10792*/ uint16(xReadId),
+	/*10793*/ uint16(xArgRM32),
+	/*10794*/ uint16(xArgImm32),
+	/*10795*/ uint16(xMatch),
+	/*10796*/ uint16(xCondDataSize), 10784, 10790, 10800,
+	/*10800*/ uint16(xSetOp), uint16(MOV),
+	/*10802*/ uint16(xReadId),
+	/*10803*/ uint16(xArgRM64),
+	/*10804*/ uint16(xArgImm32),
+	/*10805*/ uint16(xMatch),
+	/*10806*/ uint16(xCondDataSize), 10810, 10815, 10820,
+	/*10810*/ uint16(xSetOp), uint16(XBEGIN),
+	/*10812*/ uint16(xReadCw),
+	/*10813*/ uint16(xArgRel16),
+	/*10814*/ uint16(xMatch),
+	/*10815*/ uint16(xSetOp), uint16(XBEGIN),
+	/*10817*/ uint16(xReadCd),
+	/*10818*/ uint16(xArgRel32),
+	/*10819*/ uint16(xMatch),
+	/*10820*/ uint16(xSetOp), uint16(XBEGIN),
+	/*10822*/ uint16(xReadCd),
+	/*10823*/ uint16(xArgRel32),
 	/*10824*/ uint16(xMatch),
-	/*10825*/ uint16(xCondIs64), 10828, 10842,
-	/*10828*/ uint16(xCondDataSize), 10832, 10837, 0,
-	/*10832*/ uint16(xSetOp), uint16(RCL),
-	/*10834*/ uint16(xArgRM16),
-	/*10835*/ uint16(xArg1),
-	/*10836*/ uint16(xMatch),
-	/*10837*/ uint16(xSetOp), uint16(RCL),
-	/*10839*/ uint16(xArgRM32),
-	/*10840*/ uint16(xArg1),
+	/*10825*/ uint16(xSetOp), uint16(ENTER),
+	/*10827*/ uint16(xReadIw),
+	/*10828*/ uint16(xReadIb),
+	/*10829*/ uint16(xArgImm16u),
+	/*10830*/ uint16(xArgImm8u),
+	/*10831*/ uint16(xMatch),
+	/*10832*/ uint16(xCondIs64), 10835, 10845,
+	/*10835*/ uint16(xCondDataSize), 10839, 10842, 0,
+	/*10839*/ uint16(xSetOp), uint16(LEAVE),
 	/*10841*/ uint16(xMatch),
-	/*10842*/ uint16(xCondDataSize), 10832, 10837, 10846,
-	/*10846*/ uint16(xSetOp), uint16(RCL),
-	/*10848*/ uint16(xArgRM64),
-	/*10849*/ uint16(xArg1),
-	/*10850*/ uint16(xMatch),
-	/*10851*/ uint16(xCondIs64), 10854, 10868,
-	/*10854*/ uint16(xCondDataSize), 10858, 10863, 0,
-	/*10858*/ uint16(xSetOp), uint16(RCR),
-	/*10860*/ uint16(xArgRM16),
-	/*10861*/ uint16(xArg1),
+	/*10842*/ uint16(xSetOp), uint16(LEAVE),
+	/*10844*/ uint16(xMatch),
+	/*10845*/ uint16(xCondDataSize), 10839, 10849, 10852,
+	/*10849*/ uint16(xSetOp), uint16(LEAVE),
+	/*10851*/ uint16(xMatch),
+	/*10852*/ uint16(xSetOp), uint16(LEAVE),
+	/*10854*/ uint16(xMatch),
+	/*10855*/ uint16(xSetOp), uint16(LRET),
+	/*10857*/ uint16(xReadIw),
+	/*10858*/ uint16(xArgImm16u),
+	/*10859*/ uint16(xMatch),
+	/*10860*/ uint16(xSetOp), uint16(LRET),
 	/*10862*/ uint16(xMatch),
-	/*10863*/ uint16(xSetOp), uint16(RCR),
-	/*10865*/ uint16(xArgRM32),
-	/*10866*/ uint16(xArg1),
-	/*10867*/ uint16(xMatch),
-	/*10868*/ uint16(xCondDataSize), 10858, 10863, 10872,
-	/*10872*/ uint16(xSetOp), uint16(RCR),
-	/*10874*/ uint16(xArgRM64),
-	/*10875*/ uint16(xArg1),
-	/*10876*/ uint16(xMatch),
-	/*10877*/ uint16(xCondIs64), 10880, 10894,
-	/*10880*/ uint16(xCondDataSize), 10884, 10889, 0,
-	/*10884*/ uint16(xSetOp), uint16(SHL),
-	/*10886*/ uint16(xArgRM16),
-	/*10887*/ uint16(xArg1),
-	/*10888*/ uint16(xMatch),
-	/*10889*/ uint16(xSetOp), uint16(SHL),
-	/*10891*/ uint16(xArgRM32),
-	/*10892*/ uint16(xArg1),
-	/*10893*/ uint16(xMatch),
-	/*10894*/ uint16(xCondDataSize), 10884, 10889, 10898,
-	/*10898*/ uint16(xSetOp), uint16(SHL),
-	/*10900*/ uint16(xArgRM64),
-	/*10901*/ uint16(xArg1),
-	/*10902*/ uint16(xMatch),
-	/*10903*/ uint16(xCondIs64), 10906, 10920,
-	/*10906*/ uint16(xCondDataSize), 10910, 10915, 0,
-	/*10910*/ uint16(xSetOp), uint16(SHR),
-	/*10912*/ uint16(xArgRM16),
-	/*10913*/ uint16(xArg1),
-	/*10914*/ uint16(xMatch),
-	/*10915*/ uint16(xSetOp), uint16(SHR),
-	/*10917*/ uint16(xArgRM32),
-	/*10918*/ uint16(xArg1),
-	/*10919*/ uint16(xMatch),
-	/*10920*/ uint16(xCondDataSize), 10910, 10915, 10924,
-	/*10924*/ uint16(xSetOp), uint16(SHR),
-	/*10926*/ uint16(xArgRM64),
-	/*10927*/ uint16(xArg1),
-	/*10928*/ uint16(xMatch),
-	/*10929*/ uint16(xCondIs64), 10932, 10946,
-	/*10932*/ uint16(xCondDataSize), 10936, 10941, 0,
-	/*10936*/ uint16(xSetOp), uint16(SAR),
-	/*10938*/ uint16(xArgRM16),
-	/*10939*/ uint16(xArg1),
-	/*10940*/ uint16(xMatch),
-	/*10941*/ uint16(xSetOp), uint16(SAR),
-	/*10943*/ uint16(xArgRM32),
-	/*10944*/ uint16(xArg1),
-	/*10945*/ uint16(xMatch),
-	/*10946*/ uint16(xCondDataSize), 10936, 10941, 10950,
-	/*10950*/ uint16(xSetOp), uint16(SAR),
-	/*10952*/ uint16(xArgRM64),
-	/*10953*/ uint16(xArg1),
-	/*10954*/ uint16(xMatch),
-	/*10955*/ uint16(xCondSlashR),
-	10964, // 0
-	10969, // 1
-	10974, // 2
-	10979, // 3
-	10984, // 4
-	10989, // 5
+	/*10863*/ uint16(xSetOp), uint16(INT),
+	/*10865*/ uint16(xArg3),
+	/*10866*/ uint16(xMatch),
+	/*10867*/ uint16(xSetOp), uint16(INT),
+	/*10869*/ uint16(xReadIb),
+	/*10870*/ uint16(xArgImm8u),
+	/*10871*/ uint16(xMatch),
+	/*10872*/ uint16(xCondIs64), 10875, 0,
+	/*10875*/ uint16(xSetOp), uint16(INTO),
+	/*10877*/ uint16(xMatch),
+	/*10878*/ uint16(xCondIs64), 10881, 10891,
+	/*10881*/ uint16(xCondDataSize), 10885, 10888, 0,
+	/*10885*/ uint16(xSetOp), uint16(IRET),
+	/*10887*/ uint16(xMatch),
+	/*10888*/ uint16(xSetOp), uint16(IRETD),
+	/*10890*/ uint16(xMatch),
+	/*10891*/ uint16(xCondDataSize), 10885, 10888, 10895,
+	/*10895*/ uint16(xSetOp), uint16(IRETQ),
+	/*10897*/ uint16(xMatch),
+	/*10898*/ uint16(xCondSlashR),
+	10907, // 0
+	10912, // 1
+	10917, // 2
+	10922, // 3
+	10927, // 4
+	10932, // 5
 	0,     // 6
-	10994, // 7
-	/*10964*/ uint16(xSetOp), uint16(ROL),
-	/*10966*/ uint16(xArgRM8),
-	/*10967*/ uint16(xArgCL),
-	/*10968*/ uint16(xMatch),
-	/*10969*/ uint16(xSetOp), uint16(ROR),
-	/*10971*/ uint16(xArgRM8),
-	/*10972*/ uint16(xArgCL),
-	/*10973*/ uint16(xMatch),
-	/*10974*/ uint16(xSetOp), uint16(RCL),
-	/*10976*/ uint16(xArgRM8),
-	/*10977*/ uint16(xArgCL),
-	/*10978*/ uint16(xMatch),
-	/*10979*/ uint16(xSetOp), uint16(RCR),
-	/*10981*/ uint16(xArgRM8),
-	/*10982*/ uint16(xArgCL),
-	/*10983*/ uint16(xMatch),
-	/*10984*/ uint16(xSetOp), uint16(SHL),
-	/*10986*/ uint16(xArgRM8),
-	/*10987*/ uint16(xArgCL),
+	10937, // 7
+	/*10907*/ uint16(xSetOp), uint16(ROL),
+	/*10909*/ uint16(xArgRM8),
+	/*10910*/ uint16(xArg1),
+	/*10911*/ uint16(xMatch),
+	/*10912*/ uint16(xSetOp), uint16(ROR),
+	/*10914*/ uint16(xArgRM8),
+	/*10915*/ uint16(xArg1),
+	/*10916*/ uint16(xMatch),
+	/*10917*/ uint16(xSetOp), uint16(RCL),
+	/*10919*/ uint16(xArgRM8),
+	/*10920*/ uint16(xArg1),
+	/*10921*/ uint16(xMatch),
+	/*10922*/ uint16(xSetOp), uint16(RCR),
+	/*10924*/ uint16(xArgRM8),
+	/*10925*/ uint16(xArg1),
+	/*10926*/ uint16(xMatch),
+	/*10927*/ uint16(xSetOp), uint16(SHL),
+	/*10929*/ uint16(xArgRM8),
+	/*10930*/ uint16(xArg1),
+	/*10931*/ uint16(xMatch),
+	/*10932*/ uint16(xSetOp), uint16(SHR),
+	/*10934*/ uint16(xArgRM8),
+	/*10935*/ uint16(xArg1),
+	/*10936*/ uint16(xMatch),
+	/*10937*/ uint16(xSetOp), uint16(SAR),
+	/*10939*/ uint16(xArgRM8),
+	/*10940*/ uint16(xArg1),
+	/*10941*/ uint16(xMatch),
+	/*10942*/ uint16(xCondSlashR),
+	10951, // 0
+	10977, // 1
+	11003, // 2
+	11029, // 3
+	11055, // 4
+	11081, // 5
+	0,     // 6
+	11107, // 7
+	/*10951*/ uint16(xCondIs64), 10954, 10968,
+	/*10954*/ uint16(xCondDataSize), 10958, 10963, 0,
+	/*10958*/ uint16(xSetOp), uint16(ROL),
+	/*10960*/ uint16(xArgRM16),
+	/*10961*/ uint16(xArg1),
+	/*10962*/ uint16(xMatch),
+	/*10963*/ uint16(xSetOp), uint16(ROL),
+	/*10965*/ uint16(xArgRM32),
+	/*10966*/ uint16(xArg1),
+	/*10967*/ uint16(xMatch),
+	/*10968*/ uint16(xCondDataSize), 10958, 10963, 10972,
+	/*10972*/ uint16(xSetOp), uint16(ROL),
+	/*10974*/ uint16(xArgRM64),
+	/*10975*/ uint16(xArg1),
+	/*10976*/ uint16(xMatch),
+	/*10977*/ uint16(xCondIs64), 10980, 10994,
+	/*10980*/ uint16(xCondDataSize), 10984, 10989, 0,
+	/*10984*/ uint16(xSetOp), uint16(ROR),
+	/*10986*/ uint16(xArgRM16),
+	/*10987*/ uint16(xArg1),
 	/*10988*/ uint16(xMatch),
-	/*10989*/ uint16(xSetOp), uint16(SHR),
-	/*10991*/ uint16(xArgRM8),
-	/*10992*/ uint16(xArgCL),
+	/*10989*/ uint16(xSetOp), uint16(ROR),
+	/*10991*/ uint16(xArgRM32),
+	/*10992*/ uint16(xArg1),
 	/*10993*/ uint16(xMatch),
-	/*10994*/ uint16(xSetOp), uint16(SAR),
-	/*10996*/ uint16(xArgRM8),
-	/*10997*/ uint16(xArgCL),
-	/*10998*/ uint16(xMatch),
-	/*10999*/ uint16(xCondSlashR),
-	11008, // 0
-	11034, // 1
-	11060, // 2
-	11086, // 3
-	11112, // 4
-	11138, // 5
-	0,     // 6
-	11164, // 7
-	/*11008*/ uint16(xCondIs64), 11011, 11025,
-	/*11011*/ uint16(xCondDataSize), 11015, 11020, 0,
-	/*11015*/ uint16(xSetOp), uint16(ROL),
-	/*11017*/ uint16(xArgRM16),
-	/*11018*/ uint16(xArgCL),
+	/*10994*/ uint16(xCondDataSize), 10984, 10989, 10998,
+	/*10998*/ uint16(xSetOp), uint16(ROR),
+	/*11000*/ uint16(xArgRM64),
+	/*11001*/ uint16(xArg1),
+	/*11002*/ uint16(xMatch),
+	/*11003*/ uint16(xCondIs64), 11006, 11020,
+	/*11006*/ uint16(xCondDataSize), 11010, 11015, 0,
+	/*11010*/ uint16(xSetOp), uint16(RCL),
+	/*11012*/ uint16(xArgRM16),
+	/*11013*/ uint16(xArg1),
+	/*11014*/ uint16(xMatch),
+	/*11015*/ uint16(xSetOp), uint16(RCL),
+	/*11017*/ uint16(xArgRM32),
+	/*11018*/ uint16(xArg1),
 	/*11019*/ uint16(xMatch),
-	/*11020*/ uint16(xSetOp), uint16(ROL),
-	/*11022*/ uint16(xArgRM32),
-	/*11023*/ uint16(xArgCL),
-	/*11024*/ uint16(xMatch),
-	/*11025*/ uint16(xCondDataSize), 11015, 11020, 11029,
-	/*11029*/ uint16(xSetOp), uint16(ROL),
-	/*11031*/ uint16(xArgRM64),
-	/*11032*/ uint16(xArgCL),
-	/*11033*/ uint16(xMatch),
-	/*11034*/ uint16(xCondIs64), 11037, 11051,
-	/*11037*/ uint16(xCondDataSize), 11041, 11046, 0,
-	/*11041*/ uint16(xSetOp), uint16(ROR),
-	/*11043*/ uint16(xArgRM16),
-	/*11044*/ uint16(xArgCL),
+	/*11020*/ uint16(xCondDataSize), 11010, 11015, 11024,
+	/*11024*/ uint16(xSetOp), uint16(RCL),
+	/*11026*/ uint16(xArgRM64),
+	/*11027*/ uint16(xArg1),
+	/*11028*/ uint16(xMatch),
+	/*11029*/ uint16(xCondIs64), 11032, 11046,
+	/*11032*/ uint16(xCondDataSize), 11036, 11041, 0,
+	/*11036*/ uint16(xSetOp), uint16(RCR),
+	/*11038*/ uint16(xArgRM16),
+	/*11039*/ uint16(xArg1),
+	/*11040*/ uint16(xMatch),
+	/*11041*/ uint16(xSetOp), uint16(RCR),
+	/*11043*/ uint16(xArgRM32),
+	/*11044*/ uint16(xArg1),
 	/*11045*/ uint16(xMatch),
-	/*11046*/ uint16(xSetOp), uint16(ROR),
-	/*11048*/ uint16(xArgRM32),
-	/*11049*/ uint16(xArgCL),
-	/*11050*/ uint16(xMatch),
-	/*11051*/ uint16(xCondDataSize), 11041, 11046, 11055,
-	/*11055*/ uint16(xSetOp), uint16(ROR),
-	/*11057*/ uint16(xArgRM64),
-	/*11058*/ uint16(xArgCL),
-	/*11059*/ uint16(xMatch),
-	/*11060*/ uint16(xCondIs64), 11063, 11077,
-	/*11063*/ uint16(xCondDataSize), 11067, 11072, 0,
-	/*11067*/ uint16(xSetOp), uint16(RCL),
-	/*11069*/ uint16(xArgRM16),
-	/*11070*/ uint16(xArgCL),
+	/*11046*/ uint16(xCondDataSize), 11036, 11041, 11050,
+	/*11050*/ uint16(xSetOp), uint16(RCR),
+	/*11052*/ uint16(xArgRM64),
+	/*11053*/ uint16(xArg1),
+	/*11054*/ uint16(xMatch),
+	/*11055*/ uint16(xCondIs64), 11058, 11072,
+	/*11058*/ uint16(xCondDataSize), 11062, 11067, 0,
+	/*11062*/ uint16(xSetOp), uint16(SHL),
+	/*11064*/ uint16(xArgRM16),
+	/*11065*/ uint16(xArg1),
+	/*11066*/ uint16(xMatch),
+	/*11067*/ uint16(xSetOp), uint16(SHL),
+	/*11069*/ uint16(xArgRM32),
+	/*11070*/ uint16(xArg1),
 	/*11071*/ uint16(xMatch),
-	/*11072*/ uint16(xSetOp), uint16(RCL),
-	/*11074*/ uint16(xArgRM32),
-	/*11075*/ uint16(xArgCL),
-	/*11076*/ uint16(xMatch),
-	/*11077*/ uint16(xCondDataSize), 11067, 11072, 11081,
-	/*11081*/ uint16(xSetOp), uint16(RCL),
-	/*11083*/ uint16(xArgRM64),
-	/*11084*/ uint16(xArgCL),
-	/*11085*/ uint16(xMatch),
-	/*11086*/ uint16(xCondIs64), 11089, 11103,
-	/*11089*/ uint16(xCondDataSize), 11093, 11098, 0,
-	/*11093*/ uint16(xSetOp), uint16(RCR),
-	/*11095*/ uint16(xArgRM16),
-	/*11096*/ uint16(xArgCL),
+	/*11072*/ uint16(xCondDataSize), 11062, 11067, 11076,
+	/*11076*/ uint16(xSetOp), uint16(SHL),
+	/*11078*/ uint16(xArgRM64),
+	/*11079*/ uint16(xArg1),
+	/*11080*/ uint16(xMatch),
+	/*11081*/ uint16(xCondIs64), 11084, 11098,
+	/*11084*/ uint16(xCondDataSize), 11088, 11093, 0,
+	/*11088*/ uint16(xSetOp), uint16(SHR),
+	/*11090*/ uint16(xArgRM16),
+	/*11091*/ uint16(xArg1),
+	/*11092*/ uint16(xMatch),
+	/*11093*/ uint16(xSetOp), uint16(SHR),
+	/*11095*/ uint16(xArgRM32),
+	/*11096*/ uint16(xArg1),
 	/*11097*/ uint16(xMatch),
-	/*11098*/ uint16(xSetOp), uint16(RCR),
-	/*11100*/ uint16(xArgRM32),
-	/*11101*/ uint16(xArgCL),
-	/*11102*/ uint16(xMatch),
-	/*11103*/ uint16(xCondDataSize), 11093, 11098, 11107,
-	/*11107*/ uint16(xSetOp), uint16(RCR),
-	/*11109*/ uint16(xArgRM64),
-	/*11110*/ uint16(xArgCL),
-	/*11111*/ uint16(xMatch),
-	/*11112*/ uint16(xCondIs64), 11115, 11129,
-	/*11115*/ uint16(xCondDataSize), 11119, 11124, 0,
-	/*11119*/ uint16(xSetOp), uint16(SHL),
-	/*11121*/ uint16(xArgRM16),
-	/*11122*/ uint16(xArgCL),
+	/*11098*/ uint16(xCondDataSize), 11088, 11093, 11102,
+	/*11102*/ uint16(xSetOp), uint16(SHR),
+	/*11104*/ uint16(xArgRM64),
+	/*11105*/ uint16(xArg1),
+	/*11106*/ uint16(xMatch),
+	/*11107*/ uint16(xCondIs64), 11110, 11124,
+	/*11110*/ uint16(xCondDataSize), 11114, 11119, 0,
+	/*11114*/ uint16(xSetOp), uint16(SAR),
+	/*11116*/ uint16(xArgRM16),
+	/*11117*/ uint16(xArg1),
+	/*11118*/ uint16(xMatch),
+	/*11119*/ uint16(xSetOp), uint16(SAR),
+	/*11121*/ uint16(xArgRM32),
+	/*11122*/ uint16(xArg1),
 	/*11123*/ uint16(xMatch),
-	/*11124*/ uint16(xSetOp), uint16(SHL),
-	/*11126*/ uint16(xArgRM32),
-	/*11127*/ uint16(xArgCL),
-	/*11128*/ uint16(xMatch),
-	/*11129*/ uint16(xCondDataSize), 11119, 11124, 11133,
-	/*11133*/ uint16(xSetOp), uint16(SHL),
-	/*11135*/ uint16(xArgRM64),
-	/*11136*/ uint16(xArgCL),
-	/*11137*/ uint16(xMatch),
-	/*11138*/ uint16(xCondIs64), 11141, 11155,
-	/*11141*/ uint16(xCondDataSize), 11145, 11150, 0,
-	/*11145*/ uint16(xSetOp), uint16(SHR),
-	/*11147*/ uint16(xArgRM16),
-	/*11148*/ uint16(xArgCL),
-	/*11149*/ uint16(xMatch),
-	/*11150*/ uint16(xSetOp), uint16(SHR),
-	/*11152*/ uint16(xArgRM32),
-	/*11153*/ uint16(xArgCL),
-	/*11154*/ uint16(xMatch),
-	/*11155*/ uint16(xCondDataSize), 11145, 11150, 11159,
-	/*11159*/ uint16(xSetOp), uint16(SHR),
-	/*11161*/ uint16(xArgRM64),
-	/*11162*/ uint16(xArgCL),
-	/*11163*/ uint16(xMatch),
-	/*11164*/ uint16(xCondIs64), 11167, 11181,
-	/*11167*/ uint16(xCondDataSize), 11171, 11176, 0,
-	/*11171*/ uint16(xSetOp), uint16(SAR),
-	/*11173*/ uint16(xArgRM16),
-	/*11174*/ uint16(xArgCL),
-	/*11175*/ uint16(xMatch),
-	/*11176*/ uint16(xSetOp), uint16(SAR),
-	/*11178*/ uint16(xArgRM32),
-	/*11179*/ uint16(xArgCL),
-	/*11180*/ uint16(xMatch),
-	/*11181*/ uint16(xCondDataSize), 11171, 11176, 11185,
-	/*11185*/ uint16(xSetOp), uint16(SAR),
-	/*11187*/ uint16(xArgRM64),
-	/*11188*/ uint16(xArgCL),
-	/*11189*/ uint16(xMatch),
-	/*11190*/ uint16(xCondIs64), 11193, 0,
-	/*11193*/ uint16(xSetOp), uint16(AAM),
-	/*11195*/ uint16(xReadIb),
-	/*11196*/ uint16(xArgImm8u),
+	/*11124*/ uint16(xCondDataSize), 11114, 11119, 11128,
+	/*11128*/ uint16(xSetOp), uint16(SAR),
+	/*11130*/ uint16(xArgRM64),
+	/*11131*/ uint16(xArg1),
+	/*11132*/ uint16(xMatch),
+	/*11133*/ uint16(xCondSlashR),
+	11142, // 0
+	11147, // 1
+	11152, // 2
+	11157, // 3
+	11162, // 4
+	11167, // 5
+	0,     // 6
+	11172, // 7
+	/*11142*/ uint16(xSetOp), uint16(ROL),
+	/*11144*/ uint16(xArgRM8),
+	/*11145*/ uint16(xArgCL),
+	/*11146*/ uint16(xMatch),
+	/*11147*/ uint16(xSetOp), uint16(ROR),
+	/*11149*/ uint16(xArgRM8),
+	/*11150*/ uint16(xArgCL),
+	/*11151*/ uint16(xMatch),
+	/*11152*/ uint16(xSetOp), uint16(RCL),
+	/*11154*/ uint16(xArgRM8),
+	/*11155*/ uint16(xArgCL),
+	/*11156*/ uint16(xMatch),
+	/*11157*/ uint16(xSetOp), uint16(RCR),
+	/*11159*/ uint16(xArgRM8),
+	/*11160*/ uint16(xArgCL),
+	/*11161*/ uint16(xMatch),
+	/*11162*/ uint16(xSetOp), uint16(SHL),
+	/*11164*/ uint16(xArgRM8),
+	/*11165*/ uint16(xArgCL),
+	/*11166*/ uint16(xMatch),
+	/*11167*/ uint16(xSetOp), uint16(SHR),
+	/*11169*/ uint16(xArgRM8),
+	/*11170*/ uint16(xArgCL),
+	/*11171*/ uint16(xMatch),
+	/*11172*/ uint16(xSetOp), uint16(SAR),
+	/*11174*/ uint16(xArgRM8),
+	/*11175*/ uint16(xArgCL),
+	/*11176*/ uint16(xMatch),
+	/*11177*/ uint16(xCondSlashR),
+	11186, // 0
+	11212, // 1
+	11238, // 2
+	11264, // 3
+	11290, // 4
+	11316, // 5
+	0,     // 6
+	11342, // 7
+	/*11186*/ uint16(xCondIs64), 11189, 11203,
+	/*11189*/ uint16(xCondDataSize), 11193, 11198, 0,
+	/*11193*/ uint16(xSetOp), uint16(ROL),
+	/*11195*/ uint16(xArgRM16),
+	/*11196*/ uint16(xArgCL),
 	/*11197*/ uint16(xMatch),
-	/*11198*/ uint16(xCondIs64), 11201, 0,
-	/*11201*/ uint16(xSetOp), uint16(AAD),
-	/*11203*/ uint16(xReadIb),
-	/*11204*/ uint16(xArgImm8u),
-	/*11205*/ uint16(xMatch),
-	/*11206*/ uint16(xCondIs64), 11209, 11212,
-	/*11209*/ uint16(xSetOp), uint16(XLATB),
+	/*11198*/ uint16(xSetOp), uint16(ROL),
+	/*11200*/ uint16(xArgRM32),
+	/*11201*/ uint16(xArgCL),
+	/*11202*/ uint16(xMatch),
+	/*11203*/ uint16(xCondDataSize), 11193, 11198, 11207,
+	/*11207*/ uint16(xSetOp), uint16(ROL),
+	/*11209*/ uint16(xArgRM64),
+	/*11210*/ uint16(xArgCL),
 	/*11211*/ uint16(xMatch),
-	/*11212*/ uint16(xCondDataSize), 11209, 11209, 11216,
-	/*11216*/ uint16(xSetOp), uint16(XLATB),
-	/*11218*/ uint16(xMatch),
-	/*11219*/ uint16(xCondByte), 64,
-	0xc0, 11390,
-	0xc1, 11390,
-	0xc2, 11390,
-	0xc3, 11390,
-	0xc4, 11390,
-	0xc5, 11390,
-	0xc6, 11390,
-	0xc7, 11390,
-	0xc8, 11395,
-	0xc9, 11395,
-	0xca, 11395,
-	0xcb, 11395,
-	0xcc, 11395,
-	0xcd, 11395,
-	0xce, 11395,
-	0xcf, 11395,
-	0xd0, 11400,
-	0xd1, 11400,
-	0xd2, 11400,
-	0xd3, 11400,
-	0xd4, 11400,
-	0xd5, 11400,
-	0xd6, 11400,
-	0xd7, 11400,
-	0xd8, 11404,
-	0xd9, 11404,
-	0xda, 11404,
-	0xdb, 11404,
-	0xdc, 11404,
-	0xdd, 11404,
-	0xde, 11404,
-	0xdf, 11404,
-	0xe0, 11408,
-	0xe1, 11408,
-	0xe2, 11408,
-	0xe3, 11408,
-	0xe4, 11408,
-	0xe5, 11408,
-	0xe6, 11408,
-	0xe7, 11408,
-	0xe8, 11413,
-	0xe9, 11413,
-	0xea, 11413,
-	0xeb, 11413,
-	0xec, 11413,
-	0xed, 11413,
-	0xee, 11413,
-	0xef, 11413,
-	0xf0, 11418,
-	0xf1, 11418,
-	0xf2, 11418,
-	0xf3, 11418,
-	0xf4, 11418,
-	0xf5, 11418,
-	0xf6, 11418,
-	0xf7, 11418,
-	0xf8, 11423,
-	0xf9, 11423,
-	0xfa, 11423,
-	0xfb, 11423,
-	0xfc, 11423,
-	0xfd, 11423,
-	0xfe, 11423,
-	0xff, 11423,
-	/*11349*/ uint16(xCondSlashR),
-	11358, // 0
-	11362, // 1
-	11366, // 2
-	11370, // 3
-	11374, // 4
-	11378, // 5
-	11382, // 6
-	11386, // 7
-	/*11358*/ uint16(xSetOp), uint16(FADD),
-	/*11360*/ uint16(xArgM32fp),
-	/*11361*/ uint16(xMatch),
-	/*11362*/ uint16(xSetOp), uint16(FMUL),
-	/*11364*/ uint16(xArgM32fp),
-	/*11365*/ uint16(xMatch),
-	/*11366*/ uint16(xSetOp), uint16(FCOM),
-	/*11368*/ uint16(xArgM32fp),
-	/*11369*/ uint16(xMatch),
-	/*11370*/ uint16(xSetOp), uint16(FCOMP),
-	/*11372*/ uint16(xArgM32fp),
-	/*11373*/ uint16(xMatch),
-	/*11374*/ uint16(xSetOp), uint16(FSUB),
-	/*11376*/ uint16(xArgM32fp),
-	/*11377*/ uint16(xMatch),
-	/*11378*/ uint16(xSetOp), uint16(FSUBR),
-	/*11380*/ uint16(xArgM32fp),
-	/*11381*/ uint16(xMatch),
-	/*11382*/ uint16(xSetOp), uint16(FDIV),
-	/*11384*/ uint16(xArgM32fp),
-	/*11385*/ uint16(xMatch),
-	/*11386*/ uint16(xSetOp), uint16(FDIVR),
-	/*11388*/ uint16(xArgM32fp),
+	/*11212*/ uint16(xCondIs64), 11215, 11229,
+	/*11215*/ uint16(xCondDataSize), 11219, 11224, 0,
+	/*11219*/ uint16(xSetOp), uint16(ROR),
+	/*11221*/ uint16(xArgRM16),
+	/*11222*/ uint16(xArgCL),
+	/*11223*/ uint16(xMatch),
+	/*11224*/ uint16(xSetOp), uint16(ROR),
+	/*11226*/ uint16(xArgRM32),
+	/*11227*/ uint16(xArgCL),
+	/*11228*/ uint16(xMatch),
+	/*11229*/ uint16(xCondDataSize), 11219, 11224, 11233,
+	/*11233*/ uint16(xSetOp), uint16(ROR),
+	/*11235*/ uint16(xArgRM64),
+	/*11236*/ uint16(xArgCL),
+	/*11237*/ uint16(xMatch),
+	/*11238*/ uint16(xCondIs64), 11241, 11255,
+	/*11241*/ uint16(xCondDataSize), 11245, 11250, 0,
+	/*11245*/ uint16(xSetOp), uint16(RCL),
+	/*11247*/ uint16(xArgRM16),
+	/*11248*/ uint16(xArgCL),
+	/*11249*/ uint16(xMatch),
+	/*11250*/ uint16(xSetOp), uint16(RCL),
+	/*11252*/ uint16(xArgRM32),
+	/*11253*/ uint16(xArgCL),
+	/*11254*/ uint16(xMatch),
+	/*11255*/ uint16(xCondDataSize), 11245, 11250, 11259,
+	/*11259*/ uint16(xSetOp), uint16(RCL),
+	/*11261*/ uint16(xArgRM64),
+	/*11262*/ uint16(xArgCL),
+	/*11263*/ uint16(xMatch),
+	/*11264*/ uint16(xCondIs64), 11267, 11281,
+	/*11267*/ uint16(xCondDataSize), 11271, 11276, 0,
+	/*11271*/ uint16(xSetOp), uint16(RCR),
+	/*11273*/ uint16(xArgRM16),
+	/*11274*/ uint16(xArgCL),
+	/*11275*/ uint16(xMatch),
+	/*11276*/ uint16(xSetOp), uint16(RCR),
+	/*11278*/ uint16(xArgRM32),
+	/*11279*/ uint16(xArgCL),
+	/*11280*/ uint16(xMatch),
+	/*11281*/ uint16(xCondDataSize), 11271, 11276, 11285,
+	/*11285*/ uint16(xSetOp), uint16(RCR),
+	/*11287*/ uint16(xArgRM64),
+	/*11288*/ uint16(xArgCL),
+	/*11289*/ uint16(xMatch),
+	/*11290*/ uint16(xCondIs64), 11293, 11307,
+	/*11293*/ uint16(xCondDataSize), 11297, 11302, 0,
+	/*11297*/ uint16(xSetOp), uint16(SHL),
+	/*11299*/ uint16(xArgRM16),
+	/*11300*/ uint16(xArgCL),
+	/*11301*/ uint16(xMatch),
+	/*11302*/ uint16(xSetOp), uint16(SHL),
+	/*11304*/ uint16(xArgRM32),
+	/*11305*/ uint16(xArgCL),
+	/*11306*/ uint16(xMatch),
+	/*11307*/ uint16(xCondDataSize), 11297, 11302, 11311,
+	/*11311*/ uint16(xSetOp), uint16(SHL),
+	/*11313*/ uint16(xArgRM64),
+	/*11314*/ uint16(xArgCL),
+	/*11315*/ uint16(xMatch),
+	/*11316*/ uint16(xCondIs64), 11319, 11333,
+	/*11319*/ uint16(xCondDataSize), 11323, 11328, 0,
+	/*11323*/ uint16(xSetOp), uint16(SHR),
+	/*11325*/ uint16(xArgRM16),
+	/*11326*/ uint16(xArgCL),
+	/*11327*/ uint16(xMatch),
+	/*11328*/ uint16(xSetOp), uint16(SHR),
+	/*11330*/ uint16(xArgRM32),
+	/*11331*/ uint16(xArgCL),
+	/*11332*/ uint16(xMatch),
+	/*11333*/ uint16(xCondDataSize), 11323, 11328, 11337,
+	/*11337*/ uint16(xSetOp), uint16(SHR),
+	/*11339*/ uint16(xArgRM64),
+	/*11340*/ uint16(xArgCL),
+	/*11341*/ uint16(xMatch),
+	/*11342*/ uint16(xCondIs64), 11345, 11359,
+	/*11345*/ uint16(xCondDataSize), 11349, 11354, 0,
+	/*11349*/ uint16(xSetOp), uint16(SAR),
+	/*11351*/ uint16(xArgRM16),
+	/*11352*/ uint16(xArgCL),
+	/*11353*/ uint16(xMatch),
+	/*11354*/ uint16(xSetOp), uint16(SAR),
+	/*11356*/ uint16(xArgRM32),
+	/*11357*/ uint16(xArgCL),
+	/*11358*/ uint16(xMatch),
+	/*11359*/ uint16(xCondDataSize), 11349, 11354, 11363,
+	/*11363*/ uint16(xSetOp), uint16(SAR),
+	/*11365*/ uint16(xArgRM64),
+	/*11366*/ uint16(xArgCL),
+	/*11367*/ uint16(xMatch),
+	/*11368*/ uint16(xCondIs64), 11371, 0,
+	/*11371*/ uint16(xSetOp), uint16(AAM),
+	/*11373*/ uint16(xReadIb),
+	/*11374*/ uint16(xArgImm8u),
+	/*11375*/ uint16(xMatch),
+	/*11376*/ uint16(xCondIs64), 11379, 0,
+	/*11379*/ uint16(xSetOp), uint16(AAD),
+	/*11381*/ uint16(xReadIb),
+	/*11382*/ uint16(xArgImm8u),
+	/*11383*/ uint16(xMatch),
+	/*11384*/ uint16(xCondIs64), 11387, 11390,
+	/*11387*/ uint16(xSetOp), uint16(XLATB),
 	/*11389*/ uint16(xMatch),
-	/*11390*/ uint16(xSetOp), uint16(FADD),
-	/*11392*/ uint16(xArgST),
-	/*11393*/ uint16(xArgSTi),
-	/*11394*/ uint16(xMatch),
-	/*11395*/ uint16(xSetOp), uint16(FMUL),
-	/*11397*/ uint16(xArgST),
-	/*11398*/ uint16(xArgSTi),
-	/*11399*/ uint16(xMatch),
-	/*11400*/ uint16(xSetOp), uint16(FCOM),
-	/*11402*/ uint16(xArgSTi),
-	/*11403*/ uint16(xMatch),
-	/*11404*/ uint16(xSetOp), uint16(FCOMP),
-	/*11406*/ uint16(xArgSTi),
-	/*11407*/ uint16(xMatch),
-	/*11408*/ uint16(xSetOp), uint16(FSUB),
-	/*11410*/ uint16(xArgST),
-	/*11411*/ uint16(xArgSTi),
-	/*11412*/ uint16(xMatch),
-	/*11413*/ uint16(xSetOp), uint16(FSUBR),
-	/*11415*/ uint16(xArgST),
-	/*11416*/ uint16(xArgSTi),
-	/*11417*/ uint16(xMatch),
-	/*11418*/ uint16(xSetOp), uint16(FDIV),
-	/*11420*/ uint16(xArgST),
-	/*11421*/ uint16(xArgSTi),
-	/*11422*/ uint16(xMatch),
-	/*11423*/ uint16(xSetOp), uint16(FDIVR),
-	/*11425*/ uint16(xArgST),
-	/*11426*/ uint16(xArgSTi),
-	/*11427*/ uint16(xMatch),
-	/*11428*/ uint16(xCondByte), 42,
-	0xc0, 11551,
-	0xc1, 11551,
-	0xc2, 11551,
-	0xc3, 11551,
-	0xc4, 11551,
-	0xc5, 11551,
-	0xc6, 11551,
-	0xc7, 11551,
-	0xc8, 11555,
-	0xc9, 11555,
-	0xca, 11555,
-	0xcb, 11555,
-	0xcc, 11555,
-	0xcd, 11555,
-	0xce, 11555,
-	0xcf, 11555,
-	0xD0, 11559,
-	0xE0, 11562,
-	0xE1, 11565,
-	0xE4, 11568,
-	0xE5, 11571,
-	0xE8, 11574,
-	0xE9, 11577,
-	0xEA, 11580,
-	0xEB, 11583,
-	0xEC, 11586,
-	0xF0, 11589,
-	0xF1, 11592,
-	0xF2, 11595,
-	0xF3, 11598,
-	0xF4, 11601,
-	0xF5, 11604,
-	0xF6, 11607,
-	0xF7, 11610,
-	0xF8, 11613,
-	0xF9, 11616,
-	0xFA, 11619,
-	0xFB, 11622,
-	0xFC, 11625,
-	0xFD, 11628,
-	0xFE, 11631,
-	0xFF, 11634,
-	/*11514*/ uint16(xCondSlashR),
-	11523, // 0
-	0,     // 1
-	11527, // 2
-	11531, // 3
-	11535, // 4
-	11539, // 5
-	11543, // 6
-	11547, // 7
-	/*11523*/ uint16(xSetOp), uint16(FLD),
-	/*11525*/ uint16(xArgM32fp),
-	/*11526*/ uint16(xMatch),
-	/*11527*/ uint16(xSetOp), uint16(FST),
-	/*11529*/ uint16(xArgM32fp),
-	/*11530*/ uint16(xMatch),
-	/*11531*/ uint16(xSetOp), uint16(FSTP),
-	/*11533*/ uint16(xArgM32fp),
-	/*11534*/ uint16(xMatch),
-	/*11535*/ uint16(xSetOp), uint16(FLDENV),
-	/*11537*/ uint16(xArgM1428byte),
-	/*11538*/ uint16(xMatch),
-	/*11539*/ uint16(xSetOp), uint16(FLDCW),
-	/*11541*/ uint16(xArgM2byte),
-	/*11542*/ uint16(xMatch),
-	/*11543*/ uint16(xSetOp), uint16(FNSTENV),
-	/*11545*/ uint16(xArgM1428byte),
-	/*11546*/ uint16(xMatch),
-	/*11547*/ uint16(xSetOp), uint16(FNSTCW),
-	/*11549*/ uint16(xArgM2byte),
-	/*11550*/ uint16(xMatch),
-	/*11551*/ uint16(xSetOp), uint16(FLD),
-	/*11553*/ uint16(xArgSTi),
-	/*11554*/ uint16(xMatch),
-	/*11555*/ uint16(xSetOp), uint16(FXCH),
-	/*11557*/ uint16(xArgSTi),
-	/*11558*/ uint16(xMatch),
-	/*11559*/ uint16(xSetOp), uint16(FNOP),
-	/*11561*/ uint16(xMatch),
-	/*11562*/ uint16(xSetOp), uint16(FCHS),
-	/*11564*/ uint16(xMatch),
-	/*11565*/ uint16(xSetOp), uint16(FABS),
+	/*11390*/ uint16(xCondDataSize), 11387, 11387, 11394,
+	/*11394*/ uint16(xSetOp), uint16(XLATB),
+	/*11396*/ uint16(xMatch),
+	/*11397*/ uint16(xCondByte), 64,
+	0xc0, 11568,
+	0xc1, 11568,
+	0xc2, 11568,
+	0xc3, 11568,
+	0xc4, 11568,
+	0xc5, 11568,
+	0xc6, 11568,
+	0xc7, 11568,
+	0xc8, 11573,
+	0xc9, 11573,
+	0xca, 11573,
+	0xcb, 11573,
+	0xcc, 11573,
+	0xcd, 11573,
+	0xce, 11573,
+	0xcf, 11573,
+	0xd0, 11578,
+	0xd1, 11578,
+	0xd2, 11578,
+	0xd3, 11578,
+	0xd4, 11578,
+	0xd5, 11578,
+	0xd6, 11578,
+	0xd7, 11578,
+	0xd8, 11582,
+	0xd9, 11582,
+	0xda, 11582,
+	0xdb, 11582,
+	0xdc, 11582,
+	0xdd, 11582,
+	0xde, 11582,
+	0xdf, 11582,
+	0xe0, 11586,
+	0xe1, 11586,
+	0xe2, 11586,
+	0xe3, 11586,
+	0xe4, 11586,
+	0xe5, 11586,
+	0xe6, 11586,
+	0xe7, 11586,
+	0xe8, 11591,
+	0xe9, 11591,
+	0xea, 11591,
+	0xeb, 11591,
+	0xec, 11591,
+	0xed, 11591,
+	0xee, 11591,
+	0xef, 11591,
+	0xf0, 11596,
+	0xf1, 11596,
+	0xf2, 11596,
+	0xf3, 11596,
+	0xf4, 11596,
+	0xf5, 11596,
+	0xf6, 11596,
+	0xf7, 11596,
+	0xf8, 11601,
+	0xf9, 11601,
+	0xfa, 11601,
+	0xfb, 11601,
+	0xfc, 11601,
+	0xfd, 11601,
+	0xfe, 11601,
+	0xff, 11601,
+	/*11527*/ uint16(xCondSlashR),
+	11536, // 0
+	11540, // 1
+	11544, // 2
+	11548, // 3
+	11552, // 4
+	11556, // 5
+	11560, // 6
+	11564, // 7
+	/*11536*/ uint16(xSetOp), uint16(FADD),
+	/*11538*/ uint16(xArgM32fp),
+	/*11539*/ uint16(xMatch),
+	/*11540*/ uint16(xSetOp), uint16(FMUL),
+	/*11542*/ uint16(xArgM32fp),
+	/*11543*/ uint16(xMatch),
+	/*11544*/ uint16(xSetOp), uint16(FCOM),
+	/*11546*/ uint16(xArgM32fp),
+	/*11547*/ uint16(xMatch),
+	/*11548*/ uint16(xSetOp), uint16(FCOMP),
+	/*11550*/ uint16(xArgM32fp),
+	/*11551*/ uint16(xMatch),
+	/*11552*/ uint16(xSetOp), uint16(FSUB),
+	/*11554*/ uint16(xArgM32fp),
+	/*11555*/ uint16(xMatch),
+	/*11556*/ uint16(xSetOp), uint16(FSUBR),
+	/*11558*/ uint16(xArgM32fp),
+	/*11559*/ uint16(xMatch),
+	/*11560*/ uint16(xSetOp), uint16(FDIV),
+	/*11562*/ uint16(xArgM32fp),
+	/*11563*/ uint16(xMatch),
+	/*11564*/ uint16(xSetOp), uint16(FDIVR),
+	/*11566*/ uint16(xArgM32fp),
 	/*11567*/ uint16(xMatch),
-	/*11568*/ uint16(xSetOp), uint16(FTST),
-	/*11570*/ uint16(xMatch),
-	/*11571*/ uint16(xSetOp), uint16(FXAM),
-	/*11573*/ uint16(xMatch),
-	/*11574*/ uint16(xSetOp), uint16(FLD1),
-	/*11576*/ uint16(xMatch),
-	/*11577*/ uint16(xSetOp), uint16(FLDL2T),
-	/*11579*/ uint16(xMatch),
-	/*11580*/ uint16(xSetOp), uint16(FLDL2E),
-	/*11582*/ uint16(xMatch),
-	/*11583*/ uint16(xSetOp), uint16(FLDPI),
+	/*11568*/ uint16(xSetOp), uint16(FADD),
+	/*11570*/ uint16(xArgST),
+	/*11571*/ uint16(xArgSTi),
+	/*11572*/ uint16(xMatch),
+	/*11573*/ uint16(xSetOp), uint16(FMUL),
+	/*11575*/ uint16(xArgST),
+	/*11576*/ uint16(xArgSTi),
+	/*11577*/ uint16(xMatch),
+	/*11578*/ uint16(xSetOp), uint16(FCOM),
+	/*11580*/ uint16(xArgSTi),
+	/*11581*/ uint16(xMatch),
+	/*11582*/ uint16(xSetOp), uint16(FCOMP),
+	/*11584*/ uint16(xArgSTi),
 	/*11585*/ uint16(xMatch),
-	/*11586*/ uint16(xSetOp), uint16(FLDLG2),
-	/*11588*/ uint16(xMatch),
-	/*11589*/ uint16(xSetOp), uint16(F2XM1),
-	/*11591*/ uint16(xMatch),
-	/*11592*/ uint16(xSetOp), uint16(FYL2X),
-	/*11594*/ uint16(xMatch),
-	/*11595*/ uint16(xSetOp), uint16(FPTAN),
-	/*11597*/ uint16(xMatch),
-	/*11598*/ uint16(xSetOp), uint16(FPATAN),
+	/*11586*/ uint16(xSetOp), uint16(FSUB),
+	/*11588*/ uint16(xArgST),
+	/*11589*/ uint16(xArgSTi),
+	/*11590*/ uint16(xMatch),
+	/*11591*/ uint16(xSetOp), uint16(FSUBR),
+	/*11593*/ uint16(xArgST),
+	/*11594*/ uint16(xArgSTi),
+	/*11595*/ uint16(xMatch),
+	/*11596*/ uint16(xSetOp), uint16(FDIV),
+	/*11598*/ uint16(xArgST),
+	/*11599*/ uint16(xArgSTi),
 	/*11600*/ uint16(xMatch),
-	/*11601*/ uint16(xSetOp), uint16(FXTRACT),
-	/*11603*/ uint16(xMatch),
-	/*11604*/ uint16(xSetOp), uint16(FPREM1),
-	/*11606*/ uint16(xMatch),
-	/*11607*/ uint16(xSetOp), uint16(FDECSTP),
-	/*11609*/ uint16(xMatch),
-	/*11610*/ uint16(xSetOp), uint16(FINCSTP),
-	/*11612*/ uint16(xMatch),
-	/*11613*/ uint16(xSetOp), uint16(FPREM),
-	/*11615*/ uint16(xMatch),
-	/*11616*/ uint16(xSetOp), uint16(FYL2XP1),
-	/*11618*/ uint16(xMatch),
-	/*11619*/ uint16(xSetOp), uint16(FSQRT),
-	/*11621*/ uint16(xMatch),
-	/*11622*/ uint16(xSetOp), uint16(FSINCOS),
-	/*11624*/ uint16(xMatch),
-	/*11625*/ uint16(xSetOp), uint16(FRNDINT),
-	/*11627*/ uint16(xMatch),
-	/*11628*/ uint16(xSetOp), uint16(FSCALE),
-	/*11630*/ uint16(xMatch),
-	/*11631*/ uint16(xSetOp), uint16(FSIN),
-	/*11633*/ uint16(xMatch),
-	/*11634*/ uint16(xSetOp), uint16(FCOS),
-	/*11636*/ uint16(xMatch),
-	/*11637*/ uint16(xCondByte), 33,
-	0xc0, 11746,
-	0xc1, 11746,
-	0xc2, 11746,
-	0xc3, 11746,
-	0xc4, 11746,
-	0xc5, 11746,
-	0xc6, 11746,
-	0xc7, 11746,
-	0xc8, 11751,
-	0xc9, 11751,
-	0xca, 11751,
-	0xcb, 11751,
-	0xcc, 11751,
-	0xcd, 11751,
-	0xce, 11751,
-	0xcf, 11751,
-	0xd0, 11756,
-	0xd1, 11756,
-	0xd2, 11756,
-	0xd3, 11756,
-	0xd4, 11756,
-	0xd5, 11756,
-	0xd6, 11756,
-	0xd7, 11756,
-	0xd8, 11761,
-	0xd9, 11761,
-	0xda, 11761,
-	0xdb, 11761,
-	0xdc, 11761,
-	0xdd, 11761,
-	0xde, 11761,
-	0xdf, 11761,
-	0xE9, 11766,
-	/*11705*/ uint16(xCondSlashR),
-	11714, // 0
-	11718, // 1
-	11722, // 2
-	11726, // 3
-	11730, // 4
-	11734, // 5
-	11738, // 6
-	11742, // 7
-	/*11714*/ uint16(xSetOp), uint16(FIADD),
-	/*11716*/ uint16(xArgM32int),
-	/*11717*/ uint16(xMatch),
-	/*11718*/ uint16(xSetOp), uint16(FIMUL),
-	/*11720*/ uint16(xArgM32int),
-	/*11721*/ uint16(xMatch),
-	/*11722*/ uint16(xSetOp), uint16(FICOM),
-	/*11724*/ uint16(xArgM32int),
-	/*11725*/ uint16(xMatch),
-	/*11726*/ uint16(xSetOp), uint16(FICOMP),
-	/*11728*/ uint16(xArgM32int),
-	/*11729*/ uint16(xMatch),
-	/*11730*/ uint16(xSetOp), uint16(FISUB),
-	/*11732*/ uint16(xArgM32int),
-	/*11733*/ uint16(xMatch),
-	/*11734*/ uint16(xSetOp), uint16(FISUBR),
-	/*11736*/ uint16(xArgM32int),
-	/*11737*/ uint16(xMatch),
-	/*11738*/ uint16(xSetOp), uint16(FIDIV),
-	/*11740*/ uint16(xArgM32int),
-	/*11741*/ uint16(xMatch),
-	/*11742*/ uint16(xSetOp), uint16(FIDIVR),
-	/*11744*/ uint16(xArgM32int),
+	/*11601*/ uint16(xSetOp), uint16(FDIVR),
+	/*11603*/ uint16(xArgST),
+	/*11604*/ uint16(xArgSTi),
+	/*11605*/ uint16(xMatch),
+	/*11606*/ uint16(xCondByte), 42,
+	0xc0, 11729,
+	0xc1, 11729,
+	0xc2, 11729,
+	0xc3, 11729,
+	0xc4, 11729,
+	0xc5, 11729,
+	0xc6, 11729,
+	0xc7, 11729,
+	0xc8, 11733,
+	0xc9, 11733,
+	0xca, 11733,
+	0xcb, 11733,
+	0xcc, 11733,
+	0xcd, 11733,
+	0xce, 11733,
+	0xcf, 11733,
+	0xD0, 11737,
+	0xE0, 11740,
+	0xE1, 11743,
+	0xE4, 11746,
+	0xE5, 11749,
+	0xE8, 11752,
+	0xE9, 11755,
+	0xEA, 11758,
+	0xEB, 11761,
+	0xEC, 11764,
+	0xF0, 11767,
+	0xF1, 11770,
+	0xF2, 11773,
+	0xF3, 11776,
+	0xF4, 11779,
+	0xF5, 11782,
+	0xF6, 11785,
+	0xF7, 11788,
+	0xF8, 11791,
+	0xF9, 11794,
+	0xFA, 11797,
+	0xFB, 11800,
+	0xFC, 11803,
+	0xFD, 11806,
+	0xFE, 11809,
+	0xFF, 11812,
+	/*11692*/ uint16(xCondSlashR),
+	11701, // 0
+	0,     // 1
+	11705, // 2
+	11709, // 3
+	11713, // 4
+	11717, // 5
+	11721, // 6
+	11725, // 7
+	/*11701*/ uint16(xSetOp), uint16(FLD),
+	/*11703*/ uint16(xArgM32fp),
+	/*11704*/ uint16(xMatch),
+	/*11705*/ uint16(xSetOp), uint16(FST),
+	/*11707*/ uint16(xArgM32fp),
+	/*11708*/ uint16(xMatch),
+	/*11709*/ uint16(xSetOp), uint16(FSTP),
+	/*11711*/ uint16(xArgM32fp),
+	/*11712*/ uint16(xMatch),
+	/*11713*/ uint16(xSetOp), uint16(FLDENV),
+	/*11715*/ uint16(xArgM1428byte),
+	/*11716*/ uint16(xMatch),
+	/*11717*/ uint16(xSetOp), uint16(FLDCW),
+	/*11719*/ uint16(xArgM2byte),
+	/*11720*/ uint16(xMatch),
+	/*11721*/ uint16(xSetOp), uint16(FNSTENV),
+	/*11723*/ uint16(xArgM1428byte),
+	/*11724*/ uint16(xMatch),
+	/*11725*/ uint16(xSetOp), uint16(FNSTCW),
+	/*11727*/ uint16(xArgM2byte),
+	/*11728*/ uint16(xMatch),
+	/*11729*/ uint16(xSetOp), uint16(FLD),
+	/*11731*/ uint16(xArgSTi),
+	/*11732*/ uint16(xMatch),
+	/*11733*/ uint16(xSetOp), uint16(FXCH),
+	/*11735*/ uint16(xArgSTi),
+	/*11736*/ uint16(xMatch),
+	/*11737*/ uint16(xSetOp), uint16(FNOP),
+	/*11739*/ uint16(xMatch),
+	/*11740*/ uint16(xSetOp), uint16(FCHS),
+	/*11742*/ uint16(xMatch),
+	/*11743*/ uint16(xSetOp), uint16(FABS),
 	/*11745*/ uint16(xMatch),
-	/*11746*/ uint16(xSetOp), uint16(FCMOVB),
-	/*11748*/ uint16(xArgST),
-	/*11749*/ uint16(xArgSTi),
-	/*11750*/ uint16(xMatch),
-	/*11751*/ uint16(xSetOp), uint16(FCMOVE),
-	/*11753*/ uint16(xArgST),
-	/*11754*/ uint16(xArgSTi),
-	/*11755*/ uint16(xMatch),
-	/*11756*/ uint16(xSetOp), uint16(FCMOVBE),
-	/*11758*/ uint16(xArgST),
-	/*11759*/ uint16(xArgSTi),
+	/*11746*/ uint16(xSetOp), uint16(FTST),
+	/*11748*/ uint16(xMatch),
+	/*11749*/ uint16(xSetOp), uint16(FXAM),
+	/*11751*/ uint16(xMatch),
+	/*11752*/ uint16(xSetOp), uint16(FLD1),
+	/*11754*/ uint16(xMatch),
+	/*11755*/ uint16(xSetOp), uint16(FLDL2T),
+	/*11757*/ uint16(xMatch),
+	/*11758*/ uint16(xSetOp), uint16(FLDL2E),
 	/*11760*/ uint16(xMatch),
-	/*11761*/ uint16(xSetOp), uint16(FCMOVU),
-	/*11763*/ uint16(xArgST),
-	/*11764*/ uint16(xArgSTi),
-	/*11765*/ uint16(xMatch),
-	/*11766*/ uint16(xSetOp), uint16(FUCOMPP),
-	/*11768*/ uint16(xMatch),
-	/*11769*/ uint16(xCondByte), 50,
-	0xc0, 11904,
-	0xc1, 11904,
-	0xc2, 11904,
-	0xc3, 11904,
-	0xc4, 11904,
-	0xc5, 11904,
-	0xc6, 11904,
-	0xc7, 11904,
-	0xc8, 11909,
-	0xc9, 11909,
-	0xca, 11909,
-	0xcb, 11909,
-	0xcc, 11909,
-	0xcd, 11909,
-	0xce, 11909,
-	0xcf, 11909,
-	0xd0, 11914,
-	0xd1, 11914,
-	0xd2, 11914,
-	0xd3, 11914,
-	0xd4, 11914,
-	0xd5, 11914,
-	0xd6, 11914,
-	0xd7, 11914,
-	0xd8, 11919,
-	0xd9, 11919,
-	0xda, 11919,
-	0xdb, 11919,
-	0xdc, 11919,
-	0xdd, 11919,
-	0xde, 11919,
-	0xdf, 11919,
-	0xE2, 11924,
-	0xE3, 11927,
-	0xe8, 11930,
-	0xe9, 11930,
-	0xea, 11930,
-	0xeb, 11930,
-	0xec, 11930,
-	0xed, 11930,
-	0xee, 11930,
-	0xef, 11930,
-	0xf0, 11935,
-	0xf1, 11935,
-	0xf2, 11935,
-	0xf3, 11935,
-	0xf4, 11935,
-	0xf5, 11935,
-	0xf6, 11935,
-	0xf7, 11935,
-	/*11871*/ uint16(xCondSlashR),
-	11880, // 0
-	11884, // 1
-	11888, // 2
-	11892, // 3
-	0,     // 4
-	11896, // 5
-	0,     // 6
-	11900, // 7
-	/*11880*/ uint16(xSetOp), uint16(FILD),
-	/*11882*/ uint16(xArgM32int),
-	/*11883*/ uint16(xMatch),
-	/*11884*/ uint16(xSetOp), uint16(FISTTP),
-	/*11886*/ uint16(xArgM32int),
-	/*11887*/ uint16(xMatch),
-	/*11888*/ uint16(xSetOp), uint16(FIST),
-	/*11890*/ uint16(xArgM32int),
-	/*11891*/ uint16(xMatch),
-	/*11892*/ uint16(xSetOp), uint16(FISTP),
+	/*11761*/ uint16(xSetOp), uint16(FLDPI),
+	/*11763*/ uint16(xMatch),
+	/*11764*/ uint16(xSetOp), uint16(FLDLG2),
+	/*11766*/ uint16(xMatch),
+	/*11767*/ uint16(xSetOp), uint16(F2XM1),
+	/*11769*/ uint16(xMatch),
+	/*11770*/ uint16(xSetOp), uint16(FYL2X),
+	/*11772*/ uint16(xMatch),
+	/*11773*/ uint16(xSetOp), uint16(FPTAN),
+	/*11775*/ uint16(xMatch),
+	/*11776*/ uint16(xSetOp), uint16(FPATAN),
+	/*11778*/ uint16(xMatch),
+	/*11779*/ uint16(xSetOp), uint16(FXTRACT),
+	/*11781*/ uint16(xMatch),
+	/*11782*/ uint16(xSetOp), uint16(FPREM1),
+	/*11784*/ uint16(xMatch),
+	/*11785*/ uint16(xSetOp), uint16(FDECSTP),
+	/*11787*/ uint16(xMatch),
+	/*11788*/ uint16(xSetOp), uint16(FINCSTP),
+	/*11790*/ uint16(xMatch),
+	/*11791*/ uint16(xSetOp), uint16(FPREM),
+	/*11793*/ uint16(xMatch),
+	/*11794*/ uint16(xSetOp), uint16(FYL2XP1),
+	/*11796*/ uint16(xMatch),
+	/*11797*/ uint16(xSetOp), uint16(FSQRT),
+	/*11799*/ uint16(xMatch),
+	/*11800*/ uint16(xSetOp), uint16(FSINCOS),
+	/*11802*/ uint16(xMatch),
+	/*11803*/ uint16(xSetOp), uint16(FRNDINT),
+	/*11805*/ uint16(xMatch),
+	/*11806*/ uint16(xSetOp), uint16(FSCALE),
+	/*11808*/ uint16(xMatch),
+	/*11809*/ uint16(xSetOp), uint16(FSIN),
+	/*11811*/ uint16(xMatch),
+	/*11812*/ uint16(xSetOp), uint16(FCOS),
+	/*11814*/ uint16(xMatch),
+	/*11815*/ uint16(xCondByte), 33,
+	0xc0, 11924,
+	0xc1, 11924,
+	0xc2, 11924,
+	0xc3, 11924,
+	0xc4, 11924,
+	0xc5, 11924,
+	0xc6, 11924,
+	0xc7, 11924,
+	0xc8, 11929,
+	0xc9, 11929,
+	0xca, 11929,
+	0xcb, 11929,
+	0xcc, 11929,
+	0xcd, 11929,
+	0xce, 11929,
+	0xcf, 11929,
+	0xd0, 11934,
+	0xd1, 11934,
+	0xd2, 11934,
+	0xd3, 11934,
+	0xd4, 11934,
+	0xd5, 11934,
+	0xd6, 11934,
+	0xd7, 11934,
+	0xd8, 11939,
+	0xd9, 11939,
+	0xda, 11939,
+	0xdb, 11939,
+	0xdc, 11939,
+	0xdd, 11939,
+	0xde, 11939,
+	0xdf, 11939,
+	0xE9, 11944,
+	/*11883*/ uint16(xCondSlashR),
+	11892, // 0
+	11896, // 1
+	11900, // 2
+	11904, // 3
+	11908, // 4
+	11912, // 5
+	11916, // 6
+	11920, // 7
+	/*11892*/ uint16(xSetOp), uint16(FIADD),
 	/*11894*/ uint16(xArgM32int),
 	/*11895*/ uint16(xMatch),
-	/*11896*/ uint16(xSetOp), uint16(FLD),
-	/*11898*/ uint16(xArgM80fp),
+	/*11896*/ uint16(xSetOp), uint16(FIMUL),
+	/*11898*/ uint16(xArgM32int),
 	/*11899*/ uint16(xMatch),
-	/*11900*/ uint16(xSetOp), uint16(FSTP),
-	/*11902*/ uint16(xArgM80fp),
+	/*11900*/ uint16(xSetOp), uint16(FICOM),
+	/*11902*/ uint16(xArgM32int),
 	/*11903*/ uint16(xMatch),
-	/*11904*/ uint16(xSetOp), uint16(FCMOVNB),
-	/*11906*/ uint16(xArgST),
-	/*11907*/ uint16(xArgSTi),
-	/*11908*/ uint16(xMatch),
-	/*11909*/ uint16(xSetOp), uint16(FCMOVNE),
-	/*11911*/ uint16(xArgST),
-	/*11912*/ uint16(xArgSTi),
-	/*11913*/ uint16(xMatch),
-	/*11914*/ uint16(xSetOp), uint16(FCMOVNBE),
-	/*11916*/ uint16(xArgST),
-	/*11917*/ uint16(xArgSTi),
-	/*11918*/ uint16(xMatch),
-	/*11919*/ uint16(xSetOp), uint16(FCMOVNU),
-	/*11921*/ uint16(xArgST),
-	/*11922*/ uint16(xArgSTi),
+	/*11904*/ uint16(xSetOp), uint16(FICOMP),
+	/*11906*/ uint16(xArgM32int),
+	/*11907*/ uint16(xMatch),
+	/*11908*/ uint16(xSetOp), uint16(FISUB),
+	/*11910*/ uint16(xArgM32int),
+	/*11911*/ uint16(xMatch),
+	/*11912*/ uint16(xSetOp), uint16(FISUBR),
+	/*11914*/ uint16(xArgM32int),
+	/*11915*/ uint16(xMatch),
+	/*11916*/ uint16(xSetOp), uint16(FIDIV),
+	/*11918*/ uint16(xArgM32int),
+	/*11919*/ uint16(xMatch),
+	/*11920*/ uint16(xSetOp), uint16(FIDIVR),
+	/*11922*/ uint16(xArgM32int),
 	/*11923*/ uint16(xMatch),
-	/*11924*/ uint16(xSetOp), uint16(FNCLEX),
-	/*11926*/ uint16(xMatch),
-	/*11927*/ uint16(xSetOp), uint16(FNINIT),
-	/*11929*/ uint16(xMatch),
-	/*11930*/ uint16(xSetOp), uint16(FUCOMI),
-	/*11932*/ uint16(xArgST),
-	/*11933*/ uint16(xArgSTi),
-	/*11934*/ uint16(xMatch),
-	/*11935*/ uint16(xSetOp), uint16(FCOMI),
-	/*11937*/ uint16(xArgST),
-	/*11938*/ uint16(xArgSTi),
-	/*11939*/ uint16(xMatch),
-	/*11940*/ uint16(xCondByte), 48,
-	0xc0, 12079,
-	0xc1, 12079,
-	0xc2, 12079,
-	0xc3, 12079,
-	0xc4, 12079,
-	0xc5, 12079,
-	0xc6, 12079,
-	0xc7, 12079,
-	0xc8, 12084,
-	0xc9, 12084,
-	0xca, 12084,
-	0xcb, 12084,
-	0xcc, 12084,
-	0xcd, 12084,
-	0xce, 12084,
-	0xcf, 12084,
-	0xe0, 12089,
-	0xe1, 12089,
-	0xe2, 12089,
-	0xe3, 12089,
-	0xe4, 12089,
-	0xe5, 12089,
-	0xe6, 12089,
-	0xe7, 12089,
-	0xe8, 12094,
-	0xe9, 12094,
-	0xea, 12094,
-	0xeb, 12094,
-	0xec, 12094,
-	0xed, 12094,
-	0xee, 12094,
-	0xef, 12094,
-	0xf0, 12099,
-	0xf1, 12099,
-	0xf2, 12099,
-	0xf3, 12099,
-	0xf4, 12099,
-	0xf5, 12099,
-	0xf6, 12099,
-	0xf7, 12099,
-	0xf8, 12104,
-	0xf9, 12104,
-	0xfa, 12104,
-	0xfb, 12104,
-	0xfc, 12104,
-	0xfd, 12104,
-	0xfe, 12104,
-	0xff, 12104,
-	/*12038*/ uint16(xCondSlashR),
-	12047, // 0
-	12051, // 1
-	12055, // 2
-	12059, // 3
-	12063, // 4
-	12067, // 5
-	12071, // 6
-	12075, // 7
-	/*12047*/ uint16(xSetOp), uint16(FADD),
-	/*12049*/ uint16(xArgM64fp),
-	/*12050*/ uint16(xMatch),
-	/*12051*/ uint16(xSetOp), uint16(FMUL),
-	/*12053*/ uint16(xArgM64fp),
-	/*12054*/ uint16(xMatch),
-	/*12055*/ uint16(xSetOp), uint16(FCOM),
-	/*12057*/ uint16(xArgM64fp),
-	/*12058*/ uint16(xMatch),
-	/*12059*/ uint16(xSetOp), uint16(FCOMP),
-	/*12061*/ uint16(xArgM64fp),
-	/*12062*/ uint16(xMatch),
-	/*12063*/ uint16(xSetOp), uint16(FSUB),
-	/*12065*/ uint16(xArgM64fp),
-	/*12066*/ uint16(xMatch),
-	/*12067*/ uint16(xSetOp), uint16(FSUBR),
-	/*12069*/ uint16(xArgM64fp),
-	/*12070*/ uint16(xMatch),
-	/*12071*/ uint16(xSetOp), uint16(FDIV),
-	/*12073*/ uint16(xArgM64fp),
-	/*12074*/ uint16(xMatch),
-	/*12075*/ uint16(xSetOp), uint16(FDIVR),
-	/*12077*/ uint16(xArgM64fp),
-	/*12078*/ uint16(xMatch),
-	/*12079*/ uint16(xSetOp), uint16(FADD),
-	/*12081*/ uint16(xArgSTi),
-	/*12082*/ uint16(xArgST),
-	/*12083*/ uint16(xMatch),
-	/*12084*/ uint16(xSetOp), uint16(FMUL),
-	/*12086*/ uint16(xArgSTi),
-	/*12087*/ uint16(xArgST),
-	/*12088*/ uint16(xMatch),
-	/*12089*/ uint16(xSetOp), uint16(FSUBR),
-	/*12091*/ uint16(xArgSTi),
-	/*12092*/ uint16(xArgST),
-	/*12093*/ uint16(xMatch),
-	/*12094*/ uint16(xSetOp), uint16(FSUB),
-	/*12096*/ uint16(xArgSTi),
-	/*12097*/ uint16(xArgST),
-	/*12098*/ uint16(xMatch),
-	/*12099*/ uint16(xSetOp), uint16(FDIVR),
-	/*12101*/ uint16(xArgSTi),
-	/*12102*/ uint16(xArgST),
-	/*12103*/ uint16(xMatch),
-	/*12104*/ uint16(xSetOp), uint16(FDIV),
-	/*12106*/ uint16(xArgSTi),
-	/*12107*/ uint16(xArgST),
-	/*12108*/ uint16(xMatch),
-	/*12109*/ uint16(xCondByte), 40,
-	0xc0, 12228,
-	0xc1, 12228,
-	0xc2, 12228,
-	0xc3, 12228,
-	0xc4, 12228,
-	0xc5, 12228,
-	0xc6, 12228,
-	0xc7, 12228,
-	0xd0, 12232,
-	0xd1, 12232,
-	0xd2, 12232,
-	0xd3, 12232,
-	0xd4, 12232,
-	0xd5, 12232,
-	0xd6, 12232,
-	0xd7, 12232,
-	0xd8, 12236,
-	0xd9, 12236,
-	0xda, 12236,
-	0xdb, 12236,
-	0xdc, 12236,
-	0xdd, 12236,
-	0xde, 12236,
-	0xdf, 12236,
-	0xe0, 12240,
-	0xe1, 12240,
-	0xe2, 12240,
-	0xe3, 12240,
-	0xe4, 12240,
-	0xe5, 12240,
-	0xe6, 12240,
-	0xe7, 12240,
-	0xe8, 12244,
-	0xe9, 12244,
-	0xea, 12244,
-	0xeb, 12244,
-	0xec, 12244,
-	0xed, 12244,
-	0xee, 12244,
-	0xef, 12244,
-	/*12191*/ uint16(xCondSlashR),
-	12200, // 0
-	12204, // 1
-	12208, // 2
-	12212, // 3
-	12216, // 4
+	/*11924*/ uint16(xSetOp), uint16(FCMOVB),
+	/*11926*/ uint16(xArgST),
+	/*11927*/ uint16(xArgSTi),
+	/*11928*/ uint16(xMatch),
+	/*11929*/ uint16(xSetOp), uint16(FCMOVE),
+	/*11931*/ uint16(xArgST),
+	/*11932*/ uint16(xArgSTi),
+	/*11933*/ uint16(xMatch),
+	/*11934*/ uint16(xSetOp), uint16(FCMOVBE),
+	/*11936*/ uint16(xArgST),
+	/*11937*/ uint16(xArgSTi),
+	/*11938*/ uint16(xMatch),
+	/*11939*/ uint16(xSetOp), uint16(FCMOVU),
+	/*11941*/ uint16(xArgST),
+	/*11942*/ uint16(xArgSTi),
+	/*11943*/ uint16(xMatch),
+	/*11944*/ uint16(xSetOp), uint16(FUCOMPP),
+	/*11946*/ uint16(xMatch),
+	/*11947*/ uint16(xCondByte), 50,
+	0xc0, 12082,
+	0xc1, 12082,
+	0xc2, 12082,
+	0xc3, 12082,
+	0xc4, 12082,
+	0xc5, 12082,
+	0xc6, 12082,
+	0xc7, 12082,
+	0xc8, 12087,
+	0xc9, 12087,
+	0xca, 12087,
+	0xcb, 12087,
+	0xcc, 12087,
+	0xcd, 12087,
+	0xce, 12087,
+	0xcf, 12087,
+	0xd0, 12092,
+	0xd1, 12092,
+	0xd2, 12092,
+	0xd3, 12092,
+	0xd4, 12092,
+	0xd5, 12092,
+	0xd6, 12092,
+	0xd7, 12092,
+	0xd8, 12097,
+	0xd9, 12097,
+	0xda, 12097,
+	0xdb, 12097,
+	0xdc, 12097,
+	0xdd, 12097,
+	0xde, 12097,
+	0xdf, 12097,
+	0xE2, 12102,
+	0xE3, 12105,
+	0xe8, 12108,
+	0xe9, 12108,
+	0xea, 12108,
+	0xeb, 12108,
+	0xec, 12108,
+	0xed, 12108,
+	0xee, 12108,
+	0xef, 12108,
+	0xf0, 12113,
+	0xf1, 12113,
+	0xf2, 12113,
+	0xf3, 12113,
+	0xf4, 12113,
+	0xf5, 12113,
+	0xf6, 12113,
+	0xf7, 12113,
+	/*12049*/ uint16(xCondSlashR),
+	12058, // 0
+	12062, // 1
+	12066, // 2
+	12070, // 3
+	0,     // 4
+	12074, // 5
+	0,     // 6
+	12078, // 7
+	/*12058*/ uint16(xSetOp), uint16(FILD),
+	/*12060*/ uint16(xArgM32int),
+	/*12061*/ uint16(xMatch),
+	/*12062*/ uint16(xSetOp), uint16(FISTTP),
+	/*12064*/ uint16(xArgM32int),
+	/*12065*/ uint16(xMatch),
+	/*12066*/ uint16(xSetOp), uint16(FIST),
+	/*12068*/ uint16(xArgM32int),
+	/*12069*/ uint16(xMatch),
+	/*12070*/ uint16(xSetOp), uint16(FISTP),
+	/*12072*/ uint16(xArgM32int),
+	/*12073*/ uint16(xMatch),
+	/*12074*/ uint16(xSetOp), uint16(FLD),
+	/*12076*/ uint16(xArgM80fp),
+	/*12077*/ uint16(xMatch),
+	/*12078*/ uint16(xSetOp), uint16(FSTP),
+	/*12080*/ uint16(xArgM80fp),
+	/*12081*/ uint16(xMatch),
+	/*12082*/ uint16(xSetOp), uint16(FCMOVNB),
+	/*12084*/ uint16(xArgST),
+	/*12085*/ uint16(xArgSTi),
+	/*12086*/ uint16(xMatch),
+	/*12087*/ uint16(xSetOp), uint16(FCMOVNE),
+	/*12089*/ uint16(xArgST),
+	/*12090*/ uint16(xArgSTi),
+	/*12091*/ uint16(xMatch),
+	/*12092*/ uint16(xSetOp), uint16(FCMOVNBE),
+	/*12094*/ uint16(xArgST),
+	/*12095*/ uint16(xArgSTi),
+	/*12096*/ uint16(xMatch),
+	/*12097*/ uint16(xSetOp), uint16(FCMOVNU),
+	/*12099*/ uint16(xArgST),
+	/*12100*/ uint16(xArgSTi),
+	/*12101*/ uint16(xMatch),
+	/*12102*/ uint16(xSetOp), uint16(FNCLEX),
+	/*12104*/ uint16(xMatch),
+	/*12105*/ uint16(xSetOp), uint16(FNINIT),
+	/*12107*/ uint16(xMatch),
+	/*12108*/ uint16(xSetOp), uint16(FUCOMI),
+	/*12110*/ uint16(xArgST),
+	/*12111*/ uint16(xArgSTi),
+	/*12112*/ uint16(xMatch),
+	/*12113*/ uint16(xSetOp), uint16(FCOMI),
+	/*12115*/ uint16(xArgST),
+	/*12116*/ uint16(xArgSTi),
+	/*12117*/ uint16(xMatch),
+	/*12118*/ uint16(xCondByte), 48,
+	0xc0, 12257,
+	0xc1, 12257,
+	0xc2, 12257,
+	0xc3, 12257,
+	0xc4, 12257,
+	0xc5, 12257,
+	0xc6, 12257,
+	0xc7, 12257,
+	0xc8, 12262,
+	0xc9, 12262,
+	0xca, 12262,
+	0xcb, 12262,
+	0xcc, 12262,
+	0xcd, 12262,
+	0xce, 12262,
+	0xcf, 12262,
+	0xe0, 12267,
+	0xe1, 12267,
+	0xe2, 12267,
+	0xe3, 12267,
+	0xe4, 12267,
+	0xe5, 12267,
+	0xe6, 12267,
+	0xe7, 12267,
+	0xe8, 12272,
+	0xe9, 12272,
+	0xea, 12272,
+	0xeb, 12272,
+	0xec, 12272,
+	0xed, 12272,
+	0xee, 12272,
+	0xef, 12272,
+	0xf0, 12277,
+	0xf1, 12277,
+	0xf2, 12277,
+	0xf3, 12277,
+	0xf4, 12277,
+	0xf5, 12277,
+	0xf6, 12277,
+	0xf7, 12277,
+	0xf8, 12282,
+	0xf9, 12282,
+	0xfa, 12282,
+	0xfb, 12282,
+	0xfc, 12282,
+	0xfd, 12282,
+	0xfe, 12282,
+	0xff, 12282,
+	/*12216*/ uint16(xCondSlashR),
+	12225, // 0
+	12229, // 1
+	12233, // 2
+	12237, // 3
+	12241, // 4
+	12245, // 5
+	12249, // 6
+	12253, // 7
+	/*12225*/ uint16(xSetOp), uint16(FADD),
+	/*12227*/ uint16(xArgM64fp),
+	/*12228*/ uint16(xMatch),
+	/*12229*/ uint16(xSetOp), uint16(FMUL),
+	/*12231*/ uint16(xArgM64fp),
+	/*12232*/ uint16(xMatch),
+	/*12233*/ uint16(xSetOp), uint16(FCOM),
+	/*12235*/ uint16(xArgM64fp),
+	/*12236*/ uint16(xMatch),
+	/*12237*/ uint16(xSetOp), uint16(FCOMP),
+	/*12239*/ uint16(xArgM64fp),
+	/*12240*/ uint16(xMatch),
+	/*12241*/ uint16(xSetOp), uint16(FSUB),
+	/*12243*/ uint16(xArgM64fp),
+	/*12244*/ uint16(xMatch),
+	/*12245*/ uint16(xSetOp), uint16(FSUBR),
+	/*12247*/ uint16(xArgM64fp),
+	/*12248*/ uint16(xMatch),
+	/*12249*/ uint16(xSetOp), uint16(FDIV),
+	/*12251*/ uint16(xArgM64fp),
+	/*12252*/ uint16(xMatch),
+	/*12253*/ uint16(xSetOp), uint16(FDIVR),
+	/*12255*/ uint16(xArgM64fp),
+	/*12256*/ uint16(xMatch),
+	/*12257*/ uint16(xSetOp), uint16(FADD),
+	/*12259*/ uint16(xArgSTi),
+	/*12260*/ uint16(xArgST),
+	/*12261*/ uint16(xMatch),
+	/*12262*/ uint16(xSetOp), uint16(FMUL),
+	/*12264*/ uint16(xArgSTi),
+	/*12265*/ uint16(xArgST),
+	/*12266*/ uint16(xMatch),
+	/*12267*/ uint16(xSetOp), uint16(FSUBR),
+	/*12269*/ uint16(xArgSTi),
+	/*12270*/ uint16(xArgST),
+	/*12271*/ uint16(xMatch),
+	/*12272*/ uint16(xSetOp), uint16(FSUB),
+	/*12274*/ uint16(xArgSTi),
+	/*12275*/ uint16(xArgST),
+	/*12276*/ uint16(xMatch),
+	/*12277*/ uint16(xSetOp), uint16(FDIVR),
+	/*12279*/ uint16(xArgSTi),
+	/*12280*/ uint16(xArgST),
+	/*12281*/ uint16(xMatch),
+	/*12282*/ uint16(xSetOp), uint16(FDIV),
+	/*12284*/ uint16(xArgSTi),
+	/*12285*/ uint16(xArgST),
+	/*12286*/ uint16(xMatch),
+	/*12287*/ uint16(xCondByte), 40,
+	0xc0, 12406,
+	0xc1, 12406,
+	0xc2, 12406,
+	0xc3, 12406,
+	0xc4, 12406,
+	0xc5, 12406,
+	0xc6, 12406,
+	0xc7, 12406,
+	0xd0, 12410,
+	0xd1, 12410,
+	0xd2, 12410,
+	0xd3, 12410,
+	0xd4, 12410,
+	0xd5, 12410,
+	0xd6, 12410,
+	0xd7, 12410,
+	0xd8, 12414,
+	0xd9, 12414,
+	0xda, 12414,
+	0xdb, 12414,
+	0xdc, 12414,
+	0xdd, 12414,
+	0xde, 12414,
+	0xdf, 12414,
+	0xe0, 12418,
+	0xe1, 12418,
+	0xe2, 12418,
+	0xe3, 12418,
+	0xe4, 12418,
+	0xe5, 12418,
+	0xe6, 12418,
+	0xe7, 12418,
+	0xe8, 12422,
+	0xe9, 12422,
+	0xea, 12422,
+	0xeb, 12422,
+	0xec, 12422,
+	0xed, 12422,
+	0xee, 12422,
+	0xef, 12422,
+	/*12369*/ uint16(xCondSlashR),
+	12378, // 0
+	12382, // 1
+	12386, // 2
+	12390, // 3
+	12394, // 4
 	0,     // 5
-	12220, // 6
-	12224, // 7
-	/*12200*/ uint16(xSetOp), uint16(FLD),
-	/*12202*/ uint16(xArgM64fp),
-	/*12203*/ uint16(xMatch),
-	/*12204*/ uint16(xSetOp), uint16(FISTTP),
-	/*12206*/ uint16(xArgM64int),
-	/*12207*/ uint16(xMatch),
-	/*12208*/ uint16(xSetOp), uint16(FST),
-	/*12210*/ uint16(xArgM64fp),
-	/*12211*/ uint16(xMatch),
-	/*12212*/ uint16(xSetOp), uint16(FSTP),
-	/*12214*/ uint16(xArgM64fp),
-	/*12215*/ uint16(xMatch),
-	/*12216*/ uint16(xSetOp), uint16(FRSTOR),
-	/*12218*/ uint16(xArgM94108byte),
-	/*12219*/ uint16(xMatch),
-	/*12220*/ uint16(xSetOp), uint16(FNSAVE),
-	/*12222*/ uint16(xArgM94108byte),
-	/*12223*/ uint16(xMatch),
-	/*12224*/ uint16(xSetOp), uint16(FNSTSW),
-	/*12226*/ uint16(xArgM2byte),
-	/*12227*/ uint16(xMatch),
-	/*12228*/ uint16(xSetOp), uint16(FFREE),
-	/*12230*/ uint16(xArgSTi),
-	/*12231*/ uint16(xMatch),
-	/*12232*/ uint16(xSetOp), uint16(FST),
-	/*12234*/ uint16(xArgSTi),
-	/*12235*/ uint16(xMatch),
-	/*12236*/ uint16(xSetOp), uint16(FSTP),
-	/*12238*/ uint16(xArgSTi),
-	/*12239*/ uint16(xMatch),
-	/*12240*/ uint16(xSetOp), uint16(FUCOM),
-	/*12242*/ uint16(xArgSTi),
-	/*12243*/ uint16(xMatch),
-	/*12244*/ uint16(xSetOp), uint16(FUCOMP),
-	/*12246*/ uint16(xArgSTi),
-	/*12247*/ uint16(xMatch),
-	/*12248*/ uint16(xCondByte), 49,
-	0xc0, 12389,
-	0xc1, 12389,
-	0xc2, 12389,
-	0xc3, 12389,
-	0xc4, 12389,
-	0xc5, 12389,
-	0xc6, 12389,
-	0xc7, 12389,
-	0xc8, 12394,
-	0xc9, 12394,
-	0xca, 12394,
-	0xcb, 12394,
-	0xcc, 12394,
-	0xcd, 12394,
-	0xce, 12394,
-	0xcf, 12394,
-	0xD9, 12399,
-	0xe0, 12402,
-	0xe1, 12402,
-	0xe2, 12402,
-	0xe3, 12402,
-	0xe4, 12402,
-	0xe5, 12402,
-	0xe6, 12402,
-	0xe7, 12402,
-	0xe8, 12407,
-	0xe9, 12407,
-	0xea, 12407,
-	0xeb, 12407,
-	0xec, 12407,
-	0xed, 12407,
-	0xee, 12407,
-	0xef, 12407,
-	0xf0, 12412,
-	0xf1, 12412,
-	0xf2, 12412,
-	0xf3, 12412,
-	0xf4, 12412,
-	0xf5, 12412,
-	0xf6, 12412,
-	0xf7, 12412,
-	0xf8, 12417,
-	0xf9, 12417,
-	0xfa, 12417,
-	0xfb, 12417,
-	0xfc, 12417,
-	0xfd, 12417,
-	0xfe, 12417,
-	0xff, 12417,
-	/*12348*/ uint16(xCondSlashR),
-	12357, // 0
-	12361, // 1
-	12365, // 2
-	12369, // 3
-	12373, // 4
-	12377, // 5
-	12381, // 6
-	12385, // 7
-	/*12357*/ uint16(xSetOp), uint16(FIADD),
-	/*12359*/ uint16(xArgM16int),
-	/*12360*/ uint16(xMatch),
-	/*12361*/ uint16(xSetOp), uint16(FIMUL),
-	/*12363*/ uint16(xArgM16int),
-	/*12364*/ uint16(xMatch),
-	/*12365*/ uint16(xSetOp), uint16(FICOM),
-	/*12367*/ uint16(xArgM16int),
-	/*12368*/ uint16(xMatch),
-	/*12369*/ uint16(xSetOp), uint16(FICOMP),
-	/*12371*/ uint16(xArgM16int),
-	/*12372*/ uint16(xMatch),
-	/*12373*/ uint16(xSetOp), uint16(FISUB),
-	/*12375*/ uint16(xArgM16int),
-	/*12376*/ uint16(xMatch),
-	/*12377*/ uint16(xSetOp), uint16(FISUBR),
-	/*12379*/ uint16(xArgM16int),
-	/*12380*/ uint16(xMatch),
-	/*12381*/ uint16(xSetOp), uint16(FIDIV),
-	/*12383*/ uint16(xArgM16int),
-	/*12384*/ uint16(xMatch),
-	/*12385*/ uint16(xSetOp), uint16(FIDIVR),
-	/*12387*/ uint16(xArgM16int),
-	/*12388*/ uint16(xMatch),
-	/*12389*/ uint16(xSetOp), uint16(FADDP),
-	/*12391*/ uint16(xArgSTi),
-	/*12392*/ uint16(xArgST),
+	12398, // 6
+	12402, // 7
+	/*12378*/ uint16(xSetOp), uint16(FLD),
+	/*12380*/ uint16(xArgM64fp),
+	/*12381*/ uint16(xMatch),
+	/*12382*/ uint16(xSetOp), uint16(FISTTP),
+	/*12384*/ uint16(xArgM64int),
+	/*12385*/ uint16(xMatch),
+	/*12386*/ uint16(xSetOp), uint16(FST),
+	/*12388*/ uint16(xArgM64fp),
+	/*12389*/ uint16(xMatch),
+	/*12390*/ uint16(xSetOp), uint16(FSTP),
+	/*12392*/ uint16(xArgM64fp),
 	/*12393*/ uint16(xMatch),
-	/*12394*/ uint16(xSetOp), uint16(FMULP),
-	/*12396*/ uint16(xArgSTi),
-	/*12397*/ uint16(xArgST),
-	/*12398*/ uint16(xMatch),
-	/*12399*/ uint16(xSetOp), uint16(FCOMPP),
+	/*12394*/ uint16(xSetOp), uint16(FRSTOR),
+	/*12396*/ uint16(xArgM94108byte),
+	/*12397*/ uint16(xMatch),
+	/*12398*/ uint16(xSetOp), uint16(FNSAVE),
+	/*12400*/ uint16(xArgM94108byte),
 	/*12401*/ uint16(xMatch),
-	/*12402*/ uint16(xSetOp), uint16(FSUBRP),
-	/*12404*/ uint16(xArgSTi),
-	/*12405*/ uint16(xArgST),
-	/*12406*/ uint16(xMatch),
-	/*12407*/ uint16(xSetOp), uint16(FSUBP),
-	/*12409*/ uint16(xArgSTi),
-	/*12410*/ uint16(xArgST),
-	/*12411*/ uint16(xMatch),
-	/*12412*/ uint16(xSetOp), uint16(FDIVRP),
-	/*12414*/ uint16(xArgSTi),
-	/*12415*/ uint16(xArgST),
-	/*12416*/ uint16(xMatch),
-	/*12417*/ uint16(xSetOp), uint16(FDIVP),
-	/*12419*/ uint16(xArgSTi),
-	/*12420*/ uint16(xArgST),
+	/*12402*/ uint16(xSetOp), uint16(FNSTSW),
+	/*12404*/ uint16(xArgM2byte),
+	/*12405*/ uint16(xMatch),
+	/*12406*/ uint16(xSetOp), uint16(FFREE),
+	/*12408*/ uint16(xArgSTi),
+	/*12409*/ uint16(xMatch),
+	/*12410*/ uint16(xSetOp), uint16(FST),
+	/*12412*/ uint16(xArgSTi),
+	/*12413*/ uint16(xMatch),
+	/*12414*/ uint16(xSetOp), uint16(FSTP),
+	/*12416*/ uint16(xArgSTi),
+	/*12417*/ uint16(xMatch),
+	/*12418*/ uint16(xSetOp), uint16(FUCOM),
+	/*12420*/ uint16(xArgSTi),
 	/*12421*/ uint16(xMatch),
-	/*12422*/ uint16(xCondByte), 25,
-	0xc0, 12515,
-	0xc1, 12515,
-	0xc2, 12515,
-	0xc3, 12515,
-	0xc4, 12515,
-	0xc5, 12515,
-	0xc6, 12515,
-	0xc7, 12515,
-	0xE0, 12519,
-	0xe8, 12523,
-	0xe9, 12523,
-	0xea, 12523,
-	0xeb, 12523,
-	0xec, 12523,
-	0xed, 12523,
-	0xee, 12523,
-	0xef, 12523,
-	0xf0, 12528,
-	0xf1, 12528,
-	0xf2, 12528,
-	0xf3, 12528,
-	0xf4, 12528,
-	0xf5, 12528,
-	0xf6, 12528,
-	0xf7, 12528,
-	/*12474*/ uint16(xCondSlashR),
-	12483, // 0
-	12487, // 1
-	12491, // 2
-	12495, // 3
-	12499, // 4
-	12503, // 5
-	12507, // 6
-	12511, // 7
-	/*12483*/ uint16(xSetOp), uint16(FILD),
-	/*12485*/ uint16(xArgM16int),
-	/*12486*/ uint16(xMatch),
-	/*12487*/ uint16(xSetOp), uint16(FISTTP),
-	/*12489*/ uint16(xArgM16int),
-	/*12490*/ uint16(xMatch),
-	/*12491*/ uint16(xSetOp), uint16(FIST),
-	/*12493*/ uint16(xArgM16int),
-	/*12494*/ uint16(xMatch),
-	/*12495*/ uint16(xSetOp), uint16(FISTP),
-	/*12497*/ uint16(xArgM16int),
-	/*12498*/ uint16(xMatch),
-	/*12499*/ uint16(xSetOp), uint16(FBLD),
-	/*12501*/ uint16(xArgM80dec),
-	/*12502*/ uint16(xMatch),
-	/*12503*/ uint16(xSetOp), uint16(FILD),
-	/*12505*/ uint16(xArgM64int),
-	/*12506*/ uint16(xMatch),
-	/*12507*/ uint16(xSetOp), uint16(FBSTP),
-	/*12509*/ uint16(xArgM80bcd),
-	/*12510*/ uint16(xMatch),
-	/*12511*/ uint16(xSetOp), uint16(FISTP),
-	/*12513*/ uint16(xArgM64int),
-	/*12514*/ uint16(xMatch),
-	/*12515*/ uint16(xSetOp), uint16(FFREEP),
-	/*12517*/ uint16(xArgSTi),
-	/*12518*/ uint16(xMatch),
-	/*12519*/ uint16(xSetOp), uint16(FNSTSW),
-	/*12521*/ uint16(xArgAX),
-	/*12522*/ uint16(xMatch),
-	/*12523*/ uint16(xSetOp), uint16(FUCOMIP),
-	/*12525*/ uint16(xArgST),
-	/*12526*/ uint16(xArgSTi),
-	/*12527*/ uint16(xMatch),
-	/*12528*/ uint16(xSetOp), uint16(FCOMIP),
-	/*12530*/ uint16(xArgST),
-	/*12531*/ uint16(xArgSTi),
-	/*12532*/ uint16(xMatch),
-	/*12533*/ uint16(xSetOp), uint16(LOOPNE),
-	/*12535*/ uint16(xReadCb),
-	/*12536*/ uint16(xArgRel8),
-	/*12537*/ uint16(xMatch),
-	/*12538*/ uint16(xSetOp), uint16(LOOPE),
-	/*12540*/ uint16(xReadCb),
-	/*12541*/ uint16(xArgRel8),
+	/*12422*/ uint16(xSetOp), uint16(FUCOMP),
+	/*12424*/ uint16(xArgSTi),
+	/*12425*/ uint16(xMatch),
+	/*12426*/ uint16(xCondByte), 49,
+	0xc0, 12567,
+	0xc1, 12567,
+	0xc2, 12567,
+	0xc3, 12567,
+	0xc4, 12567,
+	0xc5, 12567,
+	0xc6, 12567,
+	0xc7, 12567,
+	0xc8, 12572,
+	0xc9, 12572,
+	0xca, 12572,
+	0xcb, 12572,
+	0xcc, 12572,
+	0xcd, 12572,
+	0xce, 12572,
+	0xcf, 12572,
+	0xD9, 12577,
+	0xe0, 12580,
+	0xe1, 12580,
+	0xe2, 12580,
+	0xe3, 12580,
+	0xe4, 12580,
+	0xe5, 12580,
+	0xe6, 12580,
+	0xe7, 12580,
+	0xe8, 12585,
+	0xe9, 12585,
+	0xea, 12585,
+	0xeb, 12585,
+	0xec, 12585,
+	0xed, 12585,
+	0xee, 12585,
+	0xef, 12585,
+	0xf0, 12590,
+	0xf1, 12590,
+	0xf2, 12590,
+	0xf3, 12590,
+	0xf4, 12590,
+	0xf5, 12590,
+	0xf6, 12590,
+	0xf7, 12590,
+	0xf8, 12595,
+	0xf9, 12595,
+	0xfa, 12595,
+	0xfb, 12595,
+	0xfc, 12595,
+	0xfd, 12595,
+	0xfe, 12595,
+	0xff, 12595,
+	/*12526*/ uint16(xCondSlashR),
+	12535, // 0
+	12539, // 1
+	12543, // 2
+	12547, // 3
+	12551, // 4
+	12555, // 5
+	12559, // 6
+	12563, // 7
+	/*12535*/ uint16(xSetOp), uint16(FIADD),
+	/*12537*/ uint16(xArgM16int),
+	/*12538*/ uint16(xMatch),
+	/*12539*/ uint16(xSetOp), uint16(FIMUL),
+	/*12541*/ uint16(xArgM16int),
 	/*12542*/ uint16(xMatch),
-	/*12543*/ uint16(xSetOp), uint16(LOOP),
-	/*12545*/ uint16(xReadCb),
-	/*12546*/ uint16(xArgRel8),
-	/*12547*/ uint16(xMatch),
-	/*12548*/ uint16(xCondIs64), 12551, 12565,
-	/*12551*/ uint16(xCondAddrSize), 12555, 12560, 0,
-	/*12555*/ uint16(xSetOp), uint16(JCXZ),
-	/*12557*/ uint16(xReadCb),
-	/*12558*/ uint16(xArgRel8),
-	/*12559*/ uint16(xMatch),
-	/*12560*/ uint16(xSetOp), uint16(JECXZ),
-	/*12562*/ uint16(xReadCb),
-	/*12563*/ uint16(xArgRel8),
-	/*12564*/ uint16(xMatch),
-	/*12565*/ uint16(xCondAddrSize), 0, 12560, 12569,
-	/*12569*/ uint16(xSetOp), uint16(JRCXZ),
-	/*12571*/ uint16(xReadCb),
-	/*12572*/ uint16(xArgRel8),
-	/*12573*/ uint16(xMatch),
-	/*12574*/ uint16(xSetOp), uint16(IN),
-	/*12576*/ uint16(xReadIb),
-	/*12577*/ uint16(xArgAL),
-	/*12578*/ uint16(xArgImm8u),
+	/*12543*/ uint16(xSetOp), uint16(FICOM),
+	/*12545*/ uint16(xArgM16int),
+	/*12546*/ uint16(xMatch),
+	/*12547*/ uint16(xSetOp), uint16(FICOMP),
+	/*12549*/ uint16(xArgM16int),
+	/*12550*/ uint16(xMatch),
+	/*12551*/ uint16(xSetOp), uint16(FISUB),
+	/*12553*/ uint16(xArgM16int),
+	/*12554*/ uint16(xMatch),
+	/*12555*/ uint16(xSetOp), uint16(FISUBR),
+	/*12557*/ uint16(xArgM16int),
+	/*12558*/ uint16(xMatch),
+	/*12559*/ uint16(xSetOp), uint16(FIDIV),
+	/*12561*/ uint16(xArgM16int),
+	/*12562*/ uint16(xMatch),
+	/*12563*/ uint16(xSetOp), uint16(FIDIVR),
+	/*12565*/ uint16(xArgM16int),
+	/*12566*/ uint16(xMatch),
+	/*12567*/ uint16(xSetOp), uint16(FADDP),
+	/*12569*/ uint16(xArgSTi),
+	/*12570*/ uint16(xArgST),
+	/*12571*/ uint16(xMatch),
+	/*12572*/ uint16(xSetOp), uint16(FMULP),
+	/*12574*/ uint16(xArgSTi),
+	/*12575*/ uint16(xArgST),
+	/*12576*/ uint16(xMatch),
+	/*12577*/ uint16(xSetOp), uint16(FCOMPP),
 	/*12579*/ uint16(xMatch),
-	/*12580*/ uint16(xCondDataSize), 12584, 12590, 12596,
-	/*12584*/ uint16(xSetOp), uint16(IN),
-	/*12586*/ uint16(xReadIb),
-	/*12587*/ uint16(xArgAX),
-	/*12588*/ uint16(xArgImm8u),
+	/*12580*/ uint16(xSetOp), uint16(FSUBRP),
+	/*12582*/ uint16(xArgSTi),
+	/*12583*/ uint16(xArgST),
+	/*12584*/ uint16(xMatch),
+	/*12585*/ uint16(xSetOp), uint16(FSUBP),
+	/*12587*/ uint16(xArgSTi),
+	/*12588*/ uint16(xArgST),
 	/*12589*/ uint16(xMatch),
-	/*12590*/ uint16(xSetOp), uint16(IN),
-	/*12592*/ uint16(xReadIb),
-	/*12593*/ uint16(xArgEAX),
-	/*12594*/ uint16(xArgImm8u),
-	/*12595*/ uint16(xMatch),
-	/*12596*/ uint16(xSetOp), uint16(IN),
-	/*12598*/ uint16(xReadIb),
-	/*12599*/ uint16(xArgEAX),
-	/*12600*/ uint16(xArgImm8u),
-	/*12601*/ uint16(xMatch),
-	/*12602*/ uint16(xSetOp), uint16(OUT),
-	/*12604*/ uint16(xReadIb),
-	/*12605*/ uint16(xArgImm8u),
-	/*12606*/ uint16(xArgAL),
-	/*12607*/ uint16(xMatch),
-	/*12608*/ uint16(xCondDataSize), 12612, 12618, 12624,
-	/*12612*/ uint16(xSetOp), uint16(OUT),
-	/*12614*/ uint16(xReadIb),
-	/*12615*/ uint16(xArgImm8u),
-	/*12616*/ uint16(xArgAX),
-	/*12617*/ uint16(xMatch),
-	/*12618*/ uint16(xSetOp), uint16(OUT),
-	/*12620*/ uint16(xReadIb),
-	/*12621*/ uint16(xArgImm8u),
-	/*12622*/ uint16(xArgEAX),
-	/*12623*/ uint16(xMatch),
-	/*12624*/ uint16(xSetOp), uint16(OUT),
-	/*12626*/ uint16(xReadIb),
-	/*12627*/ uint16(xArgImm8u),
-	/*12628*/ uint16(xArgEAX),
-	/*12629*/ uint16(xMatch),
-	/*12630*/ uint16(xCondIs64), 12633, 12647,
-	/*12633*/ uint16(xCondDataSize), 12637, 12642, 0,
-	/*12637*/ uint16(xSetOp), uint16(CALL),
-	/*12639*/ uint16(xReadCw),
-	/*12640*/ uint16(xArgRel16),
-	/*12641*/ uint16(xMatch),
-	/*12642*/ uint16(xSetOp), uint16(CALL),
-	/*12644*/ uint16(xReadCd),
-	/*12645*/ uint16(xArgRel32),
-	/*12646*/ uint16(xMatch),
-	/*12647*/ uint16(xCondDataSize), 12651, 12642, 12656,
-	/*12651*/ uint16(xSetOp), uint16(CALL),
-	/*12653*/ uint16(xReadCd),
-	/*12654*/ uint16(xArgRel32),
-	/*12655*/ uint16(xMatch),
-	/*12656*/ uint16(xSetOp), uint16(CALL),
-	/*12658*/ uint16(xReadCd),
-	/*12659*/ uint16(xArgRel32),
-	/*12660*/ uint16(xMatch),
-	/*12661*/ uint16(xCondIs64), 12664, 12678,
-	/*12664*/ uint16(xCondDataSize), 12668, 12673, 0,
-	/*12668*/ uint16(xSetOp), uint16(JMP),
-	/*12670*/ uint16(xReadCw),
-	/*12671*/ uint16(xArgRel16),
+	/*12590*/ uint16(xSetOp), uint16(FDIVRP),
+	/*12592*/ uint16(xArgSTi),
+	/*12593*/ uint16(xArgST),
+	/*12594*/ uint16(xMatch),
+	/*12595*/ uint16(xSetOp), uint16(FDIVP),
+	/*12597*/ uint16(xArgSTi),
+	/*12598*/ uint16(xArgST),
+	/*12599*/ uint16(xMatch),
+	/*12600*/ uint16(xCondByte), 25,
+	0xc0, 12693,
+	0xc1, 12693,
+	0xc2, 12693,
+	0xc3, 12693,
+	0xc4, 12693,
+	0xc5, 12693,
+	0xc6, 12693,
+	0xc7, 12693,
+	0xE0, 12697,
+	0xe8, 12701,
+	0xe9, 12701,
+	0xea, 12701,
+	0xeb, 12701,
+	0xec, 12701,
+	0xed, 12701,
+	0xee, 12701,
+	0xef, 12701,
+	0xf0, 12706,
+	0xf1, 12706,
+	0xf2, 12706,
+	0xf3, 12706,
+	0xf4, 12706,
+	0xf5, 12706,
+	0xf6, 12706,
+	0xf7, 12706,
+	/*12652*/ uint16(xCondSlashR),
+	12661, // 0
+	12665, // 1
+	12669, // 2
+	12673, // 3
+	12677, // 4
+	12681, // 5
+	12685, // 6
+	12689, // 7
+	/*12661*/ uint16(xSetOp), uint16(FILD),
+	/*12663*/ uint16(xArgM16int),
+	/*12664*/ uint16(xMatch),
+	/*12665*/ uint16(xSetOp), uint16(FISTTP),
+	/*12667*/ uint16(xArgM16int),
+	/*12668*/ uint16(xMatch),
+	/*12669*/ uint16(xSetOp), uint16(FIST),
+	/*12671*/ uint16(xArgM16int),
 	/*12672*/ uint16(xMatch),
-	/*12673*/ uint16(xSetOp), uint16(JMP),
-	/*12675*/ uint16(xReadCd),
-	/*12676*/ uint16(xArgRel32),
-	/*12677*/ uint16(xMatch),
-	/*12678*/ uint16(xCondDataSize), 12682, 12673, 12687,
-	/*12682*/ uint16(xSetOp), uint16(JMP),
-	/*12684*/ uint16(xReadCd),
-	/*12685*/ uint16(xArgRel32),
-	/*12686*/ uint16(xMatch),
-	/*12687*/ uint16(xSetOp), uint16(JMP),
-	/*12689*/ uint16(xReadCd),
-	/*12690*/ uint16(xArgRel32),
-	/*12691*/ uint16(xMatch),
-	/*12692*/ uint16(xCondIs64), 12695, 0,
-	/*12695*/ uint16(xCondDataSize), 12699, 12704, 0,
-	/*12699*/ uint16(xSetOp), uint16(LJMP),
-	/*12701*/ uint16(xReadCd),
-	/*12702*/ uint16(xArgPtr16colon16),
-	/*12703*/ uint16(xMatch),
-	/*12704*/ uint16(xSetOp), uint16(LJMP),
-	/*12706*/ uint16(xReadCp),
-	/*12707*/ uint16(xArgPtr16colon32),
-	/*12708*/ uint16(xMatch),
-	/*12709*/ uint16(xSetOp), uint16(JMP),
-	/*12711*/ uint16(xReadCb),
-	/*12712*/ uint16(xArgRel8),
-	/*12713*/ uint16(xMatch),
-	/*12714*/ uint16(xSetOp), uint16(IN),
-	/*12716*/ uint16(xArgAL),
-	/*12717*/ uint16(xArgDX),
-	/*12718*/ uint16(xMatch),
-	/*12719*/ uint16(xCondDataSize), 12723, 12728, 12733,
-	/*12723*/ uint16(xSetOp), uint16(IN),
-	/*12725*/ uint16(xArgAX),
-	/*12726*/ uint16(xArgDX),
-	/*12727*/ uint16(xMatch),
-	/*12728*/ uint16(xSetOp), uint16(IN),
-	/*12730*/ uint16(xArgEAX),
-	/*12731*/ uint16(xArgDX),
-	/*12732*/ uint16(xMatch),
-	/*12733*/ uint16(xSetOp), uint16(IN),
-	/*12735*/ uint16(xArgEAX),
-	/*12736*/ uint16(xArgDX),
+	/*12673*/ uint16(xSetOp), uint16(FISTP),
+	/*12675*/ uint16(xArgM16int),
+	/*12676*/ uint16(xMatch),
+	/*12677*/ uint16(xSetOp), uint16(FBLD),
+	/*12679*/ uint16(xArgM80dec),
+	/*12680*/ uint16(xMatch),
+	/*12681*/ uint16(xSetOp), uint16(FILD),
+	/*12683*/ uint16(xArgM64int),
+	/*12684*/ uint16(xMatch),
+	/*12685*/ uint16(xSetOp), uint16(FBSTP),
+	/*12687*/ uint16(xArgM80bcd),
+	/*12688*/ uint16(xMatch),
+	/*12689*/ uint16(xSetOp), uint16(FISTP),
+	/*12691*/ uint16(xArgM64int),
+	/*12692*/ uint16(xMatch),
+	/*12693*/ uint16(xSetOp), uint16(FFREEP),
+	/*12695*/ uint16(xArgSTi),
+	/*12696*/ uint16(xMatch),
+	/*12697*/ uint16(xSetOp), uint16(FNSTSW),
+	/*12699*/ uint16(xArgAX),
+	/*12700*/ uint16(xMatch),
+	/*12701*/ uint16(xSetOp), uint16(FUCOMIP),
+	/*12703*/ uint16(xArgST),
+	/*12704*/ uint16(xArgSTi),
+	/*12705*/ uint16(xMatch),
+	/*12706*/ uint16(xSetOp), uint16(FCOMIP),
+	/*12708*/ uint16(xArgST),
+	/*12709*/ uint16(xArgSTi),
+	/*12710*/ uint16(xMatch),
+	/*12711*/ uint16(xSetOp), uint16(LOOPNE),
+	/*12713*/ uint16(xReadCb),
+	/*12714*/ uint16(xArgRel8),
+	/*12715*/ uint16(xMatch),
+	/*12716*/ uint16(xSetOp), uint16(LOOPE),
+	/*12718*/ uint16(xReadCb),
+	/*12719*/ uint16(xArgRel8),
+	/*12720*/ uint16(xMatch),
+	/*12721*/ uint16(xSetOp), uint16(LOOP),
+	/*12723*/ uint16(xReadCb),
+	/*12724*/ uint16(xArgRel8),
+	/*12725*/ uint16(xMatch),
+	/*12726*/ uint16(xCondIs64), 12729, 12743,
+	/*12729*/ uint16(xCondAddrSize), 12733, 12738, 0,
+	/*12733*/ uint16(xSetOp), uint16(JCXZ),
+	/*12735*/ uint16(xReadCb),
+	/*12736*/ uint16(xArgRel8),
 	/*12737*/ uint16(xMatch),
-	/*12738*/ uint16(xSetOp), uint16(OUT),
-	/*12740*/ uint16(xArgDX),
-	/*12741*/ uint16(xArgAL),
+	/*12738*/ uint16(xSetOp), uint16(JECXZ),
+	/*12740*/ uint16(xReadCb),
+	/*12741*/ uint16(xArgRel8),
 	/*12742*/ uint16(xMatch),
-	/*12743*/ uint16(xCondDataSize), 12747, 12752, 12757,
-	/*12747*/ uint16(xSetOp), uint16(OUT),
-	/*12749*/ uint16(xArgDX),
-	/*12750*/ uint16(xArgAX),
+	/*12743*/ uint16(xCondAddrSize), 0, 12738, 12747,
+	/*12747*/ uint16(xSetOp), uint16(JRCXZ),
+	/*12749*/ uint16(xReadCb),
+	/*12750*/ uint16(xArgRel8),
 	/*12751*/ uint16(xMatch),
-	/*12752*/ uint16(xSetOp), uint16(OUT),
-	/*12754*/ uint16(xArgDX),
-	/*12755*/ uint16(xArgEAX),
-	/*12756*/ uint16(xMatch),
-	/*12757*/ uint16(xSetOp), uint16(OUT),
-	/*12759*/ uint16(xArgDX),
-	/*12760*/ uint16(xArgEAX),
-	/*12761*/ uint16(xMatch),
-	/*12762*/ uint16(xSetOp), uint16(ICEBP),
-	/*12764*/ uint16(xMatch),
-	/*12765*/ uint16(xSetOp), uint16(HLT),
+	/*12752*/ uint16(xSetOp), uint16(IN),
+	/*12754*/ uint16(xReadIb),
+	/*12755*/ uint16(xArgAL),
+	/*12756*/ uint16(xArgImm8u),
+	/*12757*/ uint16(xMatch),
+	/*12758*/ uint16(xCondDataSize), 12762, 12768, 12774,
+	/*12762*/ uint16(xSetOp), uint16(IN),
+	/*12764*/ uint16(xReadIb),
+	/*12765*/ uint16(xArgAX),
+	/*12766*/ uint16(xArgImm8u),
 	/*12767*/ uint16(xMatch),
-	/*12768*/ uint16(xSetOp), uint16(CMC),
-	/*12770*/ uint16(xMatch),
-	/*12771*/ uint16(xCondSlashR),
-	12780, // 0
-	0,     // 1
-	12786, // 2
-	12790, // 3
-	12794, // 4
-	12798, // 5
-	12802, // 6
-	12806, // 7
-	/*12780*/ uint16(xSetOp), uint16(TEST),
+	/*12768*/ uint16(xSetOp), uint16(IN),
+	/*12770*/ uint16(xReadIb),
+	/*12771*/ uint16(xArgEAX),
+	/*12772*/ uint16(xArgImm8u),
+	/*12773*/ uint16(xMatch),
+	/*12774*/ uint16(xSetOp), uint16(IN),
+	/*12776*/ uint16(xReadIb),
+	/*12777*/ uint16(xArgEAX),
+	/*12778*/ uint16(xArgImm8u),
+	/*12779*/ uint16(xMatch),
+	/*12780*/ uint16(xSetOp), uint16(OUT),
 	/*12782*/ uint16(xReadIb),
-	/*12783*/ uint16(xArgRM8),
-	/*12784*/ uint16(xArgImm8u),
+	/*12783*/ uint16(xArgImm8u),
+	/*12784*/ uint16(xArgAL),
 	/*12785*/ uint16(xMatch),
-	/*12786*/ uint16(xSetOp), uint16(NOT),
-	/*12788*/ uint16(xArgRM8),
-	/*12789*/ uint16(xMatch),
-	/*12790*/ uint16(xSetOp), uint16(NEG),
-	/*12792*/ uint16(xArgRM8),
-	/*12793*/ uint16(xMatch),
-	/*12794*/ uint16(xSetOp), uint16(MUL),
-	/*12796*/ uint16(xArgRM8),
-	/*12797*/ uint16(xMatch),
-	/*12798*/ uint16(xSetOp), uint16(IMUL),
-	/*12800*/ uint16(xArgRM8),
-	/*12801*/ uint16(xMatch),
-	/*12802*/ uint16(xSetOp), uint16(DIV),
-	/*12804*/ uint16(xArgRM8),
-	/*12805*/ uint16(xMatch),
-	/*12806*/ uint16(xSetOp), uint16(IDIV),
-	/*12808*/ uint16(xArgRM8),
+	/*12786*/ uint16(xCondPrefix), 3,
+	0xC5, 12830,
+	0xC4, 12816,
+	0x0, 12794,
+	/*12794*/ uint16(xCondDataSize), 12798, 12804, 12810,
+	/*12798*/ uint16(xSetOp), uint16(OUT),
+	/*12800*/ uint16(xReadIb),
+	/*12801*/ uint16(xArgImm8u),
+	/*12802*/ uint16(xArgAX),
+	/*12803*/ uint16(xMatch),
+	/*12804*/ uint16(xSetOp), uint16(OUT),
+	/*12806*/ uint16(xReadIb),
+	/*12807*/ uint16(xArgImm8u),
+	/*12808*/ uint16(xArgEAX),
 	/*12809*/ uint16(xMatch),
-	/*12810*/ uint16(xCondSlashR),
-	12819, // 0
-	0,     // 1
-	12848, // 2
-	12871, // 3
-	12894, // 4
-	12917, // 5
-	12940, // 6
-	12963, // 7
-	/*12819*/ uint16(xCondIs64), 12822, 12838,
-	/*12822*/ uint16(xCondDataSize), 12826, 12832, 0,
-	/*12826*/ uint16(xSetOp), uint16(TEST),
-	/*12828*/ uint16(xReadIw),
-	/*12829*/ uint16(xArgRM16),
-	/*12830*/ uint16(xArgImm16),
-	/*12831*/ uint16(xMatch),
-	/*12832*/ uint16(xSetOp), uint16(TEST),
-	/*12834*/ uint16(xReadId),
-	/*12835*/ uint16(xArgRM32),
-	/*12836*/ uint16(xArgImm32),
-	/*12837*/ uint16(xMatch),
-	/*12838*/ uint16(xCondDataSize), 12826, 12832, 12842,
-	/*12842*/ uint16(xSetOp), uint16(TEST),
-	/*12844*/ uint16(xReadId),
-	/*12845*/ uint16(xArgRM64),
-	/*12846*/ uint16(xArgImm32),
-	/*12847*/ uint16(xMatch),
-	/*12848*/ uint16(xCondIs64), 12851, 12863,
-	/*12851*/ uint16(xCondDataSize), 12855, 12859, 0,
-	/*12855*/ uint16(xSetOp), uint16(NOT),
-	/*12857*/ uint16(xArgRM16),
-	/*12858*/ uint16(xMatch),
-	/*12859*/ uint16(xSetOp), uint16(NOT),
-	/*12861*/ uint16(xArgRM32),
-	/*12862*/ uint16(xMatch),
-	/*12863*/ uint16(xCondDataSize), 12855, 12859, 12867,
-	/*12867*/ uint16(xSetOp), uint16(NOT),
-	/*12869*/ uint16(xArgRM64),
-	/*12870*/ uint16(xMatch),
-	/*12871*/ uint16(xCondIs64), 12874, 12886,
-	/*12874*/ uint16(xCondDataSize), 12878, 12882, 0,
-	/*12878*/ uint16(xSetOp), uint16(NEG),
-	/*12880*/ uint16(xArgRM16),
-	/*12881*/ uint16(xMatch),
-	/*12882*/ uint16(xSetOp), uint16(NEG),
-	/*12884*/ uint16(xArgRM32),
-	/*12885*/ uint16(xMatch),
-	/*12886*/ uint16(xCondDataSize), 12878, 12882, 12890,
-	/*12890*/ uint16(xSetOp), uint16(NEG),
-	/*12892*/ uint16(xArgRM64),
-	/*12893*/ uint16(xMatch),
-	/*12894*/ uint16(xCondIs64), 12897, 12909,
-	/*12897*/ uint16(xCondDataSize), 12901, 12905, 0,
-	/*12901*/ uint16(xSetOp), uint16(MUL),
-	/*12903*/ uint16(xArgRM16),
-	/*12904*/ uint16(xMatch),
-	/*12905*/ uint16(xSetOp), uint16(MUL),
-	/*12907*/ uint16(xArgRM32),
-	/*12908*/ uint16(xMatch),
-	/*12909*/ uint16(xCondDataSize), 12901, 12905, 12913,
-	/*12913*/ uint16(xSetOp), uint16(MUL),
-	/*12915*/ uint16(xArgRM64),
-	/*12916*/ uint16(xMatch),
-	/*12917*/ uint16(xCondIs64), 12920, 12932,
-	/*12920*/ uint16(xCondDataSize), 12924, 12928, 0,
-	/*12924*/ uint16(xSetOp), uint16(IMUL),
-	/*12926*/ uint16(xArgRM16),
+	/*12810*/ uint16(xSetOp), uint16(OUT),
+	/*12812*/ uint16(xReadIb),
+	/*12813*/ uint16(xArgImm8u),
+	/*12814*/ uint16(xArgEAX),
+	/*12815*/ uint16(xMatch),
+	/*12816*/ uint16(xCondPrefix), 1,
+	0x66, 12820,
+	/*12820*/ uint16(xCondPrefix), 1,
+	0x0F, 12824,
+	/*12824*/ uint16(xSetOp), uint16(VMOVNTDQ),
+	/*12826*/ uint16(xReadSlashR),
+	/*12827*/ uint16(xArgM256),
+	/*12828*/ uint16(xArgYmm1),
+	/*12829*/ uint16(xMatch),
+	/*12830*/ uint16(xCondPrefix), 1,
+	0x66, 12834,
+	/*12834*/ uint16(xCondPrefix), 1,
+	0x0F, 12838,
+	/*12838*/ uint16(xSetOp), uint16(VMOVNTDQ),
+	/*12840*/ uint16(xReadSlashR),
+	/*12841*/ uint16(xArgM256),
+	/*12842*/ uint16(xArgYmm1),
+	/*12843*/ uint16(xMatch),
+	/*12844*/ uint16(xCondIs64), 12847, 12861,
+	/*12847*/ uint16(xCondDataSize), 12851, 12856, 0,
+	/*12851*/ uint16(xSetOp), uint16(CALL),
+	/*12853*/ uint16(xReadCw),
+	/*12854*/ uint16(xArgRel16),
+	/*12855*/ uint16(xMatch),
+	/*12856*/ uint16(xSetOp), uint16(CALL),
+	/*12858*/ uint16(xReadCd),
+	/*12859*/ uint16(xArgRel32),
+	/*12860*/ uint16(xMatch),
+	/*12861*/ uint16(xCondDataSize), 12865, 12856, 12870,
+	/*12865*/ uint16(xSetOp), uint16(CALL),
+	/*12867*/ uint16(xReadCd),
+	/*12868*/ uint16(xArgRel32),
+	/*12869*/ uint16(xMatch),
+	/*12870*/ uint16(xSetOp), uint16(CALL),
+	/*12872*/ uint16(xReadCd),
+	/*12873*/ uint16(xArgRel32),
+	/*12874*/ uint16(xMatch),
+	/*12875*/ uint16(xCondIs64), 12878, 12892,
+	/*12878*/ uint16(xCondDataSize), 12882, 12887, 0,
+	/*12882*/ uint16(xSetOp), uint16(JMP),
+	/*12884*/ uint16(xReadCw),
+	/*12885*/ uint16(xArgRel16),
+	/*12886*/ uint16(xMatch),
+	/*12887*/ uint16(xSetOp), uint16(JMP),
+	/*12889*/ uint16(xReadCd),
+	/*12890*/ uint16(xArgRel32),
+	/*12891*/ uint16(xMatch),
+	/*12892*/ uint16(xCondDataSize), 12896, 12887, 12901,
+	/*12896*/ uint16(xSetOp), uint16(JMP),
+	/*12898*/ uint16(xReadCd),
+	/*12899*/ uint16(xArgRel32),
+	/*12900*/ uint16(xMatch),
+	/*12901*/ uint16(xSetOp), uint16(JMP),
+	/*12903*/ uint16(xReadCd),
+	/*12904*/ uint16(xArgRel32),
+	/*12905*/ uint16(xMatch),
+	/*12906*/ uint16(xCondIs64), 12909, 0,
+	/*12909*/ uint16(xCondDataSize), 12913, 12918, 0,
+	/*12913*/ uint16(xSetOp), uint16(LJMP),
+	/*12915*/ uint16(xReadCd),
+	/*12916*/ uint16(xArgPtr16colon16),
+	/*12917*/ uint16(xMatch),
+	/*12918*/ uint16(xSetOp), uint16(LJMP),
+	/*12920*/ uint16(xReadCp),
+	/*12921*/ uint16(xArgPtr16colon32),
+	/*12922*/ uint16(xMatch),
+	/*12923*/ uint16(xSetOp), uint16(JMP),
+	/*12925*/ uint16(xReadCb),
+	/*12926*/ uint16(xArgRel8),
 	/*12927*/ uint16(xMatch),
-	/*12928*/ uint16(xSetOp), uint16(IMUL),
-	/*12930*/ uint16(xArgRM32),
-	/*12931*/ uint16(xMatch),
-	/*12932*/ uint16(xCondDataSize), 12924, 12928, 12936,
-	/*12936*/ uint16(xSetOp), uint16(IMUL),
-	/*12938*/ uint16(xArgRM64),
-	/*12939*/ uint16(xMatch),
-	/*12940*/ uint16(xCondIs64), 12943, 12955,
-	/*12943*/ uint16(xCondDataSize), 12947, 12951, 0,
-	/*12947*/ uint16(xSetOp), uint16(DIV),
-	/*12949*/ uint16(xArgRM16),
-	/*12950*/ uint16(xMatch),
-	/*12951*/ uint16(xSetOp), uint16(DIV),
-	/*12953*/ uint16(xArgRM32),
-	/*12954*/ uint16(xMatch),
-	/*12955*/ uint16(xCondDataSize), 12947, 12951, 12959,
-	/*12959*/ uint16(xSetOp), uint16(DIV),
-	/*12961*/ uint16(xArgRM64),
-	/*12962*/ uint16(xMatch),
-	/*12963*/ uint16(xCondIs64), 12966, 12978,
-	/*12966*/ uint16(xCondDataSize), 12970, 12974, 0,
-	/*12970*/ uint16(xSetOp), uint16(IDIV),
-	/*12972*/ uint16(xArgRM16),
-	/*12973*/ uint16(xMatch),
-	/*12974*/ uint16(xSetOp), uint16(IDIV),
-	/*12976*/ uint16(xArgRM32),
-	/*12977*/ uint16(xMatch),
-	/*12978*/ uint16(xCondDataSize), 12970, 12974, 12982,
-	/*12982*/ uint16(xSetOp), uint16(IDIV),
-	/*12984*/ uint16(xArgRM64),
-	/*12985*/ uint16(xMatch),
-	/*12986*/ uint16(xSetOp), uint16(CLC),
-	/*12988*/ uint16(xMatch),
-	/*12989*/ uint16(xSetOp), uint16(STC),
-	/*12991*/ uint16(xMatch),
-	/*12992*/ uint16(xSetOp), uint16(CLI),
-	/*12994*/ uint16(xMatch),
-	/*12995*/ uint16(xSetOp), uint16(STI),
-	/*12997*/ uint16(xMatch),
-	/*12998*/ uint16(xSetOp), uint16(CLD),
-	/*13000*/ uint16(xMatch),
-	/*13001*/ uint16(xSetOp), uint16(STD),
+	/*12928*/ uint16(xSetOp), uint16(IN),
+	/*12930*/ uint16(xArgAL),
+	/*12931*/ uint16(xArgDX),
+	/*12932*/ uint16(xMatch),
+	/*12933*/ uint16(xCondDataSize), 12937, 12942, 12947,
+	/*12937*/ uint16(xSetOp), uint16(IN),
+	/*12939*/ uint16(xArgAX),
+	/*12940*/ uint16(xArgDX),
+	/*12941*/ uint16(xMatch),
+	/*12942*/ uint16(xSetOp), uint16(IN),
+	/*12944*/ uint16(xArgEAX),
+	/*12945*/ uint16(xArgDX),
+	/*12946*/ uint16(xMatch),
+	/*12947*/ uint16(xSetOp), uint16(IN),
+	/*12949*/ uint16(xArgEAX),
+	/*12950*/ uint16(xArgDX),
+	/*12951*/ uint16(xMatch),
+	/*12952*/ uint16(xSetOp), uint16(OUT),
+	/*12954*/ uint16(xArgDX),
+	/*12955*/ uint16(xArgAL),
+	/*12956*/ uint16(xMatch),
+	/*12957*/ uint16(xCondDataSize), 12961, 12966, 12971,
+	/*12961*/ uint16(xSetOp), uint16(OUT),
+	/*12963*/ uint16(xArgDX),
+	/*12964*/ uint16(xArgAX),
+	/*12965*/ uint16(xMatch),
+	/*12966*/ uint16(xSetOp), uint16(OUT),
+	/*12968*/ uint16(xArgDX),
+	/*12969*/ uint16(xArgEAX),
+	/*12970*/ uint16(xMatch),
+	/*12971*/ uint16(xSetOp), uint16(OUT),
+	/*12973*/ uint16(xArgDX),
+	/*12974*/ uint16(xArgEAX),
+	/*12975*/ uint16(xMatch),
+	/*12976*/ uint16(xSetOp), uint16(ICEBP),
+	/*12978*/ uint16(xMatch),
+	/*12979*/ uint16(xSetOp), uint16(HLT),
+	/*12981*/ uint16(xMatch),
+	/*12982*/ uint16(xSetOp), uint16(CMC),
+	/*12984*/ uint16(xMatch),
+	/*12985*/ uint16(xCondSlashR),
+	12994, // 0
+	0,     // 1
+	13000, // 2
+	13004, // 3
+	13008, // 4
+	13012, // 5
+	13016, // 6
+	13020, // 7
+	/*12994*/ uint16(xSetOp), uint16(TEST),
+	/*12996*/ uint16(xReadIb),
+	/*12997*/ uint16(xArgRM8),
+	/*12998*/ uint16(xArgImm8u),
+	/*12999*/ uint16(xMatch),
+	/*13000*/ uint16(xSetOp), uint16(NOT),
+	/*13002*/ uint16(xArgRM8),
 	/*13003*/ uint16(xMatch),
-	/*13004*/ uint16(xCondSlashR),
-	13013, // 0
-	13017, // 1
+	/*13004*/ uint16(xSetOp), uint16(NEG),
+	/*13006*/ uint16(xArgRM8),
+	/*13007*/ uint16(xMatch),
+	/*13008*/ uint16(xSetOp), uint16(MUL),
+	/*13010*/ uint16(xArgRM8),
+	/*13011*/ uint16(xMatch),
+	/*13012*/ uint16(xSetOp), uint16(IMUL),
+	/*13014*/ uint16(xArgRM8),
+	/*13015*/ uint16(xMatch),
+	/*13016*/ uint16(xSetOp), uint16(DIV),
+	/*13018*/ uint16(xArgRM8),
+	/*13019*/ uint16(xMatch),
+	/*13020*/ uint16(xSetOp), uint16(IDIV),
+	/*13022*/ uint16(xArgRM8),
+	/*13023*/ uint16(xMatch),
+	/*13024*/ uint16(xCondSlashR),
+	13033, // 0
+	0,     // 1
+	13062, // 2
+	13085, // 3
+	13108, // 4
+	13131, // 5
+	13154, // 6
+	13177, // 7
+	/*13033*/ uint16(xCondIs64), 13036, 13052,
+	/*13036*/ uint16(xCondDataSize), 13040, 13046, 0,
+	/*13040*/ uint16(xSetOp), uint16(TEST),
+	/*13042*/ uint16(xReadIw),
+	/*13043*/ uint16(xArgRM16),
+	/*13044*/ uint16(xArgImm16),
+	/*13045*/ uint16(xMatch),
+	/*13046*/ uint16(xSetOp), uint16(TEST),
+	/*13048*/ uint16(xReadId),
+	/*13049*/ uint16(xArgRM32),
+	/*13050*/ uint16(xArgImm32),
+	/*13051*/ uint16(xMatch),
+	/*13052*/ uint16(xCondDataSize), 13040, 13046, 13056,
+	/*13056*/ uint16(xSetOp), uint16(TEST),
+	/*13058*/ uint16(xReadId),
+	/*13059*/ uint16(xArgRM64),
+	/*13060*/ uint16(xArgImm32),
+	/*13061*/ uint16(xMatch),
+	/*13062*/ uint16(xCondIs64), 13065, 13077,
+	/*13065*/ uint16(xCondDataSize), 13069, 13073, 0,
+	/*13069*/ uint16(xSetOp), uint16(NOT),
+	/*13071*/ uint16(xArgRM16),
+	/*13072*/ uint16(xMatch),
+	/*13073*/ uint16(xSetOp), uint16(NOT),
+	/*13075*/ uint16(xArgRM32),
+	/*13076*/ uint16(xMatch),
+	/*13077*/ uint16(xCondDataSize), 13069, 13073, 13081,
+	/*13081*/ uint16(xSetOp), uint16(NOT),
+	/*13083*/ uint16(xArgRM64),
+	/*13084*/ uint16(xMatch),
+	/*13085*/ uint16(xCondIs64), 13088, 13100,
+	/*13088*/ uint16(xCondDataSize), 13092, 13096, 0,
+	/*13092*/ uint16(xSetOp), uint16(NEG),
+	/*13094*/ uint16(xArgRM16),
+	/*13095*/ uint16(xMatch),
+	/*13096*/ uint16(xSetOp), uint16(NEG),
+	/*13098*/ uint16(xArgRM32),
+	/*13099*/ uint16(xMatch),
+	/*13100*/ uint16(xCondDataSize), 13092, 13096, 13104,
+	/*13104*/ uint16(xSetOp), uint16(NEG),
+	/*13106*/ uint16(xArgRM64),
+	/*13107*/ uint16(xMatch),
+	/*13108*/ uint16(xCondIs64), 13111, 13123,
+	/*13111*/ uint16(xCondDataSize), 13115, 13119, 0,
+	/*13115*/ uint16(xSetOp), uint16(MUL),
+	/*13117*/ uint16(xArgRM16),
+	/*13118*/ uint16(xMatch),
+	/*13119*/ uint16(xSetOp), uint16(MUL),
+	/*13121*/ uint16(xArgRM32),
+	/*13122*/ uint16(xMatch),
+	/*13123*/ uint16(xCondDataSize), 13115, 13119, 13127,
+	/*13127*/ uint16(xSetOp), uint16(MUL),
+	/*13129*/ uint16(xArgRM64),
+	/*13130*/ uint16(xMatch),
+	/*13131*/ uint16(xCondIs64), 13134, 13146,
+	/*13134*/ uint16(xCondDataSize), 13138, 13142, 0,
+	/*13138*/ uint16(xSetOp), uint16(IMUL),
+	/*13140*/ uint16(xArgRM16),
+	/*13141*/ uint16(xMatch),
+	/*13142*/ uint16(xSetOp), uint16(IMUL),
+	/*13144*/ uint16(xArgRM32),
+	/*13145*/ uint16(xMatch),
+	/*13146*/ uint16(xCondDataSize), 13138, 13142, 13150,
+	/*13150*/ uint16(xSetOp), uint16(IMUL),
+	/*13152*/ uint16(xArgRM64),
+	/*13153*/ uint16(xMatch),
+	/*13154*/ uint16(xCondIs64), 13157, 13169,
+	/*13157*/ uint16(xCondDataSize), 13161, 13165, 0,
+	/*13161*/ uint16(xSetOp), uint16(DIV),
+	/*13163*/ uint16(xArgRM16),
+	/*13164*/ uint16(xMatch),
+	/*13165*/ uint16(xSetOp), uint16(DIV),
+	/*13167*/ uint16(xArgRM32),
+	/*13168*/ uint16(xMatch),
+	/*13169*/ uint16(xCondDataSize), 13161, 13165, 13173,
+	/*13173*/ uint16(xSetOp), uint16(DIV),
+	/*13175*/ uint16(xArgRM64),
+	/*13176*/ uint16(xMatch),
+	/*13177*/ uint16(xCondIs64), 13180, 13192,
+	/*13180*/ uint16(xCondDataSize), 13184, 13188, 0,
+	/*13184*/ uint16(xSetOp), uint16(IDIV),
+	/*13186*/ uint16(xArgRM16),
+	/*13187*/ uint16(xMatch),
+	/*13188*/ uint16(xSetOp), uint16(IDIV),
+	/*13190*/ uint16(xArgRM32),
+	/*13191*/ uint16(xMatch),
+	/*13192*/ uint16(xCondDataSize), 13184, 13188, 13196,
+	/*13196*/ uint16(xSetOp), uint16(IDIV),
+	/*13198*/ uint16(xArgRM64),
+	/*13199*/ uint16(xMatch),
+	/*13200*/ uint16(xSetOp), uint16(CLC),
+	/*13202*/ uint16(xMatch),
+	/*13203*/ uint16(xSetOp), uint16(STC),
+	/*13205*/ uint16(xMatch),
+	/*13206*/ uint16(xSetOp), uint16(CLI),
+	/*13208*/ uint16(xMatch),
+	/*13209*/ uint16(xSetOp), uint16(STI),
+	/*13211*/ uint16(xMatch),
+	/*13212*/ uint16(xSetOp), uint16(CLD),
+	/*13214*/ uint16(xMatch),
+	/*13215*/ uint16(xSetOp), uint16(STD),
+	/*13217*/ uint16(xMatch),
+	/*13218*/ uint16(xCondSlashR),
+	13227, // 0
+	13231, // 1
 	0,     // 2
 	0,     // 3
 	0,     // 4
 	0,     // 5
 	0,     // 6
 	0,     // 7
-	/*13013*/ uint16(xSetOp), uint16(INC),
-	/*13015*/ uint16(xArgRM8),
-	/*13016*/ uint16(xMatch),
-	/*13017*/ uint16(xSetOp), uint16(DEC),
-	/*13019*/ uint16(xArgRM8),
-	/*13020*/ uint16(xMatch),
-	/*13021*/ uint16(xCondSlashR),
-	13030, // 0
-	13053, // 1
-	13076, // 2
-	13095, // 3
-	13118, // 4
-	13137, // 5
-	13160, // 6
+	/*13227*/ uint16(xSetOp), uint16(INC),
+	/*13229*/ uint16(xArgRM8),
+	/*13230*/ uint16(xMatch),
+	/*13231*/ uint16(xSetOp), uint16(DEC),
+	/*13233*/ uint16(xArgRM8),
+	/*13234*/ uint16(xMatch),
+	/*13235*/ uint16(xCondSlashR),
+	13244, // 0
+	13267, // 1
+	13290, // 2
+	13309, // 3
+	13332, // 4
+	13351, // 5
+	13374, // 6
 	0,     // 7
-	/*13030*/ uint16(xCondIs64), 13033, 13045,
-	/*13033*/ uint16(xCondDataSize), 13037, 13041, 0,
-	/*13037*/ uint16(xSetOp), uint16(INC),
-	/*13039*/ uint16(xArgRM16),
-	/*13040*/ uint16(xMatch),
-	/*13041*/ uint16(xSetOp), uint16(INC),
-	/*13043*/ uint16(xArgRM32),
-	/*13044*/ uint16(xMatch),
-	/*13045*/ uint16(xCondDataSize), 13037, 13041, 13049,
-	/*13049*/ uint16(xSetOp), uint16(INC),
-	/*13051*/ uint16(xArgRM64),
-	/*13052*/ uint16(xMatch),
-	/*13053*/ uint16(xCondIs64), 13056, 13068,
-	/*13056*/ uint16(xCondDataSize), 13060, 13064, 0,
-	/*13060*/ uint16(xSetOp), uint16(DEC),
-	/*13062*/ uint16(xArgRM16),
-	/*13063*/ uint16(xMatch),
-	/*13064*/ uint16(xSetOp), uint16(DEC),
-	/*13066*/ uint16(xArgRM32),
-	/*13067*/ uint16(xMatch),
-	/*13068*/ uint16(xCondDataSize), 13060, 13064, 13072,
-	/*13072*/ uint16(xSetOp), uint16(DEC),
-	/*13074*/ uint16(xArgRM64),
-	/*13075*/ uint16(xMatch),
-	/*13076*/ uint16(xCondIs64), 13079, 13091,
-	/*13079*/ uint16(xCondDataSize), 13083, 13087, 0,
-	/*13083*/ uint16(xSetOp), uint16(CALL),
-	/*13085*/ uint16(xArgRM16),
-	/*13086*/ uint16(xMatch),
-	/*13087*/ uint16(xSetOp), uint16(CALL),
-	/*13089*/ uint16(xArgRM32),
-	/*13090*/ uint16(xMatch),
-	/*13091*/ uint16(xSetOp), uint16(CALL),
-	/*13093*/ uint16(xArgRM64),
-	/*13094*/ uint16(xMatch),
-	/*13095*/ uint16(xCondIs64), 13098, 13110,
-	/*13098*/ uint16(xCondDataSize), 13102, 13106, 0,
-	/*13102*/ uint16(xSetOp), uint16(LCALL),
-	/*13104*/ uint16(xArgM16colon16),
-	/*13105*/ uint16(xMatch),
-	/*13106*/ uint16(xSetOp), uint16(LCALL),
-	/*13108*/ uint16(xArgM16colon32),
-	/*13109*/ uint16(xMatch),
-	/*13110*/ uint16(xCondDataSize), 13102, 13106, 13114,
-	/*13114*/ uint16(xSetOp), uint16(LCALL),
-	/*13116*/ uint16(xArgM16colon64),
-	/*13117*/ uint16(xMatch),
-	/*13118*/ uint16(xCondIs64), 13121, 13133,
-	/*13121*/ uint16(xCondDataSize), 13125, 13129, 0,
-	/*13125*/ uint16(xSetOp), uint16(JMP),
-	/*13127*/ uint16(xArgRM16),
-	/*13128*/ uint16(xMatch),
-	/*13129*/ uint16(xSetOp), uint16(JMP),
-	/*13131*/ uint16(xArgRM32),
-	/*13132*/ uint16(xMatch),
-	/*13133*/ uint16(xSetOp), uint16(JMP),
-	/*13135*/ uint16(xArgRM64),
-	/*13136*/ uint16(xMatch),
-	/*13137*/ uint16(xCondIs64), 13140, 13152,
-	/*13140*/ uint16(xCondDataSize), 13144, 13148, 0,
-	/*13144*/ uint16(xSetOp), uint16(LJMP),
-	/*13146*/ uint16(xArgM16colon16),
-	/*13147*/ uint16(xMatch),
-	/*13148*/ uint16(xSetOp), uint16(LJMP),
-	/*13150*/ uint16(xArgM16colon32),
-	/*13151*/ uint16(xMatch),
-	/*13152*/ uint16(xCondDataSize), 13144, 13148, 13156,
-	/*13156*/ uint16(xSetOp), uint16(LJMP),
-	/*13158*/ uint16(xArgM16colon64),
-	/*13159*/ uint16(xMatch),
-	/*13160*/ uint16(xCondIs64), 13163, 13175,
-	/*13163*/ uint16(xCondDataSize), 13167, 13171, 0,
-	/*13167*/ uint16(xSetOp), uint16(PUSH),
-	/*13169*/ uint16(xArgRM16),
-	/*13170*/ uint16(xMatch),
-	/*13171*/ uint16(xSetOp), uint16(PUSH),
-	/*13173*/ uint16(xArgRM32),
-	/*13174*/ uint16(xMatch),
-	/*13175*/ uint16(xCondDataSize), 13167, 13179, 13183,
-	/*13179*/ uint16(xSetOp), uint16(PUSH),
-	/*13181*/ uint16(xArgRM64),
-	/*13182*/ uint16(xMatch),
-	/*13183*/ uint16(xSetOp), uint16(PUSH),
-	/*13185*/ uint16(xArgRM64),
-	/*13186*/ uint16(xMatch),
+	/*13244*/ uint16(xCondIs64), 13247, 13259,
+	/*13247*/ uint16(xCondDataSize), 13251, 13255, 0,
+	/*13251*/ uint16(xSetOp), uint16(INC),
+	/*13253*/ uint16(xArgRM16),
+	/*13254*/ uint16(xMatch),
+	/*13255*/ uint16(xSetOp), uint16(INC),
+	/*13257*/ uint16(xArgRM32),
+	/*13258*/ uint16(xMatch),
+	/*13259*/ uint16(xCondDataSize), 13251, 13255, 13263,
+	/*13263*/ uint16(xSetOp), uint16(INC),
+	/*13265*/ uint16(xArgRM64),
+	/*13266*/ uint16(xMatch),
+	/*13267*/ uint16(xCondIs64), 13270, 13282,
+	/*13270*/ uint16(xCondDataSize), 13274, 13278, 0,
+	/*13274*/ uint16(xSetOp), uint16(DEC),
+	/*13276*/ uint16(xArgRM16),
+	/*13277*/ uint16(xMatch),
+	/*13278*/ uint16(xSetOp), uint16(DEC),
+	/*13280*/ uint16(xArgRM32),
+	/*13281*/ uint16(xMatch),
+	/*13282*/ uint16(xCondDataSize), 13274, 13278, 13286,
+	/*13286*/ uint16(xSetOp), uint16(DEC),
+	/*13288*/ uint16(xArgRM64),
+	/*13289*/ uint16(xMatch),
+	/*13290*/ uint16(xCondIs64), 13293, 13305,
+	/*13293*/ uint16(xCondDataSize), 13297, 13301, 0,
+	/*13297*/ uint16(xSetOp), uint16(CALL),
+	/*13299*/ uint16(xArgRM16),
+	/*13300*/ uint16(xMatch),
+	/*13301*/ uint16(xSetOp), uint16(CALL),
+	/*13303*/ uint16(xArgRM32),
+	/*13304*/ uint16(xMatch),
+	/*13305*/ uint16(xSetOp), uint16(CALL),
+	/*13307*/ uint16(xArgRM64),
+	/*13308*/ uint16(xMatch),
+	/*13309*/ uint16(xCondIs64), 13312, 13324,
+	/*13312*/ uint16(xCondDataSize), 13316, 13320, 0,
+	/*13316*/ uint16(xSetOp), uint16(LCALL),
+	/*13318*/ uint16(xArgM16colon16),
+	/*13319*/ uint16(xMatch),
+	/*13320*/ uint16(xSetOp), uint16(LCALL),
+	/*13322*/ uint16(xArgM16colon32),
+	/*13323*/ uint16(xMatch),
+	/*13324*/ uint16(xCondDataSize), 13316, 13320, 13328,
+	/*13328*/ uint16(xSetOp), uint16(LCALL),
+	/*13330*/ uint16(xArgM16colon64),
+	/*13331*/ uint16(xMatch),
+	/*13332*/ uint16(xCondIs64), 13335, 13347,
+	/*13335*/ uint16(xCondDataSize), 13339, 13343, 0,
+	/*13339*/ uint16(xSetOp), uint16(JMP),
+	/*13341*/ uint16(xArgRM16),
+	/*13342*/ uint16(xMatch),
+	/*13343*/ uint16(xSetOp), uint16(JMP),
+	/*13345*/ uint16(xArgRM32),
+	/*13346*/ uint16(xMatch),
+	/*13347*/ uint16(xSetOp), uint16(JMP),
+	/*13349*/ uint16(xArgRM64),
+	/*13350*/ uint16(xMatch),
+	/*13351*/ uint16(xCondIs64), 13354, 13366,
+	/*13354*/ uint16(xCondDataSize), 13358, 13362, 0,
+	/*13358*/ uint16(xSetOp), uint16(LJMP),
+	/*13360*/ uint16(xArgM16colon16),
+	/*13361*/ uint16(xMatch),
+	/*13362*/ uint16(xSetOp), uint16(LJMP),
+	/*13364*/ uint16(xArgM16colon32),
+	/*13365*/ uint16(xMatch),
+	/*13366*/ uint16(xCondDataSize), 13358, 13362, 13370,
+	/*13370*/ uint16(xSetOp), uint16(LJMP),
+	/*13372*/ uint16(xArgM16colon64),
+	/*13373*/ uint16(xMatch),
+	/*13374*/ uint16(xCondIs64), 13377, 13389,
+	/*13377*/ uint16(xCondDataSize), 13381, 13385, 0,
+	/*13381*/ uint16(xSetOp), uint16(PUSH),
+	/*13383*/ uint16(xArgRM16),
+	/*13384*/ uint16(xMatch),
+	/*13385*/ uint16(xSetOp), uint16(PUSH),
+	/*13387*/ uint16(xArgRM32),
+	/*13388*/ uint16(xMatch),
+	/*13389*/ uint16(xCondDataSize), 13381, 13393, 13397,
+	/*13393*/ uint16(xSetOp), uint16(PUSH),
+	/*13395*/ uint16(xArgRM64),
+	/*13396*/ uint16(xMatch),
+	/*13397*/ uint16(xSetOp), uint16(PUSH),
+	/*13399*/ uint16(xArgRM64),
+	/*13400*/ uint16(xMatch),
 }
 
 const (
@@ -9119,6 +9251,11 @@ const (
 	UNPCKLPS
 	VERR
 	VERW
+	VMOVDQA
+	VMOVDQU
+	VMOVNTDQ
+	VMOVNTDQA
+	VZEROUPPER
 	WBINVD
 	WRFSBASE
 	WRGSBASE
@@ -9729,6 +9866,11 @@ var opNames = [...]string{
 	UNPCKLPS:        "UNPCKLPS",
 	VERR:            "VERR",
 	VERW:            "VERW",
+	VMOVDQA:         "VMOVDQA",
+	VMOVDQU:         "VMOVDQU",
+	VMOVNTDQ:        "VMOVNTDQ",
+	VMOVNTDQA:       "VMOVNTDQA",
+	VZEROUPPER:      "VZEROUPPER",
 	WBINVD:          "WBINVD",
 	WRFSBASE:        "WRFSBASE",
 	WRGSBASE:        "WRGSBASE",
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
index 745e81f..5203789 100644
--- 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
@@ -2009,7 +2009,7 @@
 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	32	plan9	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
@@ -2022,7 +2022,7 @@
 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
+26a011223344|556677885f5f5f5f5f5f	32	plan9	MOVB ES:0x44332211, AL
 26|8211223344556677885f5f5f5f5f5f	32	intel	es
 26|8211223344556677885f5f5f5f5f5f	32	plan9	ES Op(0)
 26|8211223344556677885f5f5f5f5f5f	64	gnu	es
@@ -2155,10 +2155,10 @@
 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	32	plan9	REP; 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
+3ef367660f38f011|223344556677885f	64	plan9	REP; MOVBE 0(CX), DX
 3f|11223344556677885f5f5f5f5f5f5f	32	intel	aas
 3f|11223344556677885f5f5f5f5f5f5f	32	plan9	AAS
 3f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
@@ -4666,53 +4666,53 @@
 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	32	plan9	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
+66f20f2a11|223344556677885f5f5f5f	64	plan9	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	32	plan9	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
+66f20f2c11|223344556677885f5f5f5f	64	plan9	CVTTSD2SIQ 0(CX), DX
 66f20f2d11|223344556677885f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
-66f20f2d11|223344556677885f5f5f5f	32	plan9	REPNE CVTSD2SIQ 0(CX), DX
+66f20f2d11|223344556677885f5f5f5f	32	plan9	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
+66f20f2d11|223344556677885f5f5f5f	64	plan9	CVTSD2SIQ 0(CX), DX
 66f20f38f011|223344556677885f5f5f	32	intel	crc32 edx, byte ptr [ecx]
-66f20f38f011|223344556677885f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+66f20f38f011|223344556677885f5f5f	32	plan9	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
+66f20f38f011|223344556677885f5f5f	64	plan9	CRC32 0(CX), DX
 66f30f2c11|223344556677885f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
-66f30f2c11|223344556677885f5f5f5f	32	plan9	REP CVTTSS2SIL 0(CX), DX
+66f30f2c11|223344556677885f5f5f5f	32	plan9	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
+66f30f2c11|223344556677885f5f5f5f	64	plan9	CVTTSS2SIL 0(CX), DX
 66f30f2d11|223344556677885f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
-66f30f2d11|223344556677885f5f5f5f	32	plan9	REP CVTSS2SIL 0(CX), DX
+66f30f2d11|223344556677885f5f5f5f	32	plan9	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
+66f30f2d11|223344556677885f5f5f5f	64	plan9	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)
+66f30fae11|223344556677885f5f5f5f	64	plan9	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)
+66f30fae18|11223344556677885f5f5f	64	plan9	WRGSBASE 0(AX)
 66f30faec0|11223344556677885f5f5f	64	gnu	rdfsbase %eax
 66f30faec0|11223344556677885f5f5f	64	intel	rdfsbase eax
-66f30faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
+66f30faec0|11223344556677885f5f5f	64	plan9	RDFSBASE AX
 66f30faec8|11223344556677885f5f5f	64	gnu	rdgsbase %eax
 66f30faec8|11223344556677885f5f5f	64	intel	rdgsbase eax
-66f30faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
+66f30faec8|11223344556677885f5f5f	64	plan9	RDGSBASE AX
 66f30fd6c5|11223344556677885f5f5f	32	intel	movq2dq xmm0, mmx5
-66f30fd6c5|11223344556677885f5f5f	32	plan9	REP MOVQ2DQ M5, X0
+66f30fd6c5|11223344556677885f5f5f	32	plan9	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
+66f30fd6c5|11223344556677885f5f5f	64	plan9	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)
@@ -6236,327 +6236,327 @@ 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	32	plan9	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
+f20f1011|223344556677885f5f5f5f5f	64	plan9	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	32	plan9	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)
+f20f1122|3344556677885f5f5f5f5f5f	64	plan9	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	32	plan9	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
+f20f1211|223344556677885f5f5f5f5f	64	plan9	MOVDDUP 0(CX), X2
 f20f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2sd xmm2, dword ptr [ecx]
-f20f2a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSI2SDL 0(CX), X2
+f20f2a11|223344556677885f5f5f5f5f	32	plan9	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
+f20f2a11|223344556677885f5f5f5f5f	64	plan9	CVTSI2SDL 0(CX), X2
 f20f2c11|223344556677885f5f5f5f5f	32	intel	cvttsd2si edx, qword ptr [ecx]
-f20f2c11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+f20f2c11|223344556677885f5f5f5f5f	32	plan9	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
+f20f2c11|223344556677885f5f5f5f5f	64	plan9	CVTTSD2SIQ 0(CX), DX
 f20f2d11|223344556677885f5f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
-f20f2d11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SIQ 0(CX), DX
+f20f2d11|223344556677885f5f5f5f5f	32	plan9	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
+f20f2d11|223344556677885f5f5f5f5f	64	plan9	CVTSD2SIQ 0(CX), DX
 f20f38f011|223344556677885f5f5f5f	32	intel	crc32 edx, byte ptr [ecx]
-f20f38f011|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+f20f38f011|223344556677885f5f5f5f	32	plan9	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
+f20f38f011|223344556677885f5f5f5f	64	plan9	CRC32 0(CX), DX
 f20f38f111|223344556677885f5f5f5f	32	intel	crc32 edx, dword ptr [ecx]
-f20f38f111|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+f20f38f111|223344556677885f5f5f5f	32	plan9	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
+f20f38f111|223344556677885f5f5f5f	64	plan9	CRC32 0(CX), DX
 f20f5111|223344556677885f5f5f5f5f	32	intel	sqrtsd xmm2, qword ptr [ecx]
-f20f5111|223344556677885f5f5f5f5f	32	plan9	REPNE SQRTSD 0(CX), X2
+f20f5111|223344556677885f5f5f5f5f	32	plan9	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
+f20f5111|223344556677885f5f5f5f5f	64	plan9	SQRTSD 0(CX), X2
 f20f5811|223344556677885f5f5f5f5f	32	intel	addsd xmm2, qword ptr [ecx]
-f20f5811|223344556677885f5f5f5f5f	32	plan9	REPNE ADDSD 0(CX), X2
+f20f5811|223344556677885f5f5f5f5f	32	plan9	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
+f20f5811|223344556677885f5f5f5f5f	64	plan9	ADDSD 0(CX), X2
 f20f5911|223344556677885f5f5f5f5f	32	intel	mulsd xmm2, qword ptr [ecx]
-f20f5911|223344556677885f5f5f5f5f	32	plan9	REPNE MULSD 0(CX), X2
+f20f5911|223344556677885f5f5f5f5f	32	plan9	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
+f20f5911|223344556677885f5f5f5f5f	64	plan9	MULSD 0(CX), X2
 f20f5a11|223344556677885f5f5f5f5f	32	intel	cvtsd2ss xmm2, qword ptr [ecx]
-f20f5a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SS 0(CX), X2
+f20f5a11|223344556677885f5f5f5f5f	32	plan9	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
+f20f5a11|223344556677885f5f5f5f5f	64	plan9	CVTSD2SS 0(CX), X2
 f20f5c11|223344556677885f5f5f5f5f	32	intel	subsd xmm2, qword ptr [ecx]
-f20f5c11|223344556677885f5f5f5f5f	32	plan9	REPNE SUBSD 0(CX), X2
+f20f5c11|223344556677885f5f5f5f5f	32	plan9	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
+f20f5c11|223344556677885f5f5f5f5f	64	plan9	SUBSD 0(CX), X2
 f20f5d11|223344556677885f5f5f5f5f	32	intel	minsd xmm2, qword ptr [ecx]
-f20f5d11|223344556677885f5f5f5f5f	32	plan9	REPNE MINSD 0(CX), X2
+f20f5d11|223344556677885f5f5f5f5f	32	plan9	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
+f20f5d11|223344556677885f5f5f5f5f	64	plan9	MINSD 0(CX), X2
 f20f5e11|223344556677885f5f5f5f5f	32	intel	divsd xmm2, qword ptr [ecx]
-f20f5e11|223344556677885f5f5f5f5f	32	plan9	REPNE DIVSD 0(CX), X2
+f20f5e11|223344556677885f5f5f5f5f	32	plan9	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
+f20f5e11|223344556677885f5f5f5f5f	64	plan9	DIVSD 0(CX), X2
 f20f5f11|223344556677885f5f5f5f5f	32	intel	maxsd xmm2, qword ptr [ecx]
-f20f5f11|223344556677885f5f5f5f5f	32	plan9	REPNE MAXSD 0(CX), X2
+f20f5f11|223344556677885f5f5f5f5f	32	plan9	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
+f20f5f11|223344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f20f701122|3344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f20f7c11|223344556677885f5f5f5f5f	64	plan9	HADDPS 0(CX), X2
 f20f7d11|223344556677885f5f5f5f5f	32	intel	hsubps xmm2, xmmword ptr [ecx]
-f20f7d11|223344556677885f5f5f5f5f	32	plan9	REPNE HSUBPS 0(CX), X2
+f20f7d11|223344556677885f5f5f5f5f	32	plan9	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
+f20f7d11|223344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f20fc21122|3344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f20fd011|223344556677885f5f5f5f5f	64	plan9	ADDSUBPS 0(CX), X2
 f20fd6c0|11223344556677885f5f5f5f	32	intel	movdq2q mmx0, xmm0
-f20fd6c0|11223344556677885f5f5f5f	32	plan9	REPNE MOVDQ2Q X0, M0
+f20fd6c0|11223344556677885f5f5f5f	32	plan9	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
+f20fd6c0|11223344556677885f5f5f5f	64	plan9	MOVDQ2Q X0, M0
 f20fe611|223344556677885f5f5f5f5f	32	intel	cvtpd2dq xmm2, xmmword ptr [ecx]
-f20fe611|223344556677885f5f5f5f5f	32	plan9	REPNE CVTPD2DQ 0(CX), X2
+f20fe611|223344556677885f5f5f5f5f	32	plan9	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
+f20fe611|223344556677885f5f5f5f5f	64	plan9	CVTPD2DQ 0(CX), X2
 f20ff011|223344556677885f5f5f5f5f	32	intel	lddqu xmm2, xmmword ptr [ecx]
-f20ff011|223344556677885f5f5f5f5f	32	plan9	REPNE LDDQU 0(CX), X2
+f20ff011|223344556677885f5f5f5f5f	32	plan9	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
+f20ff011|223344556677885f5f5f5f5f	64	plan9	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
+f2480f2a11|223344556677885f5f5f5f	64	plan9	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
+f2480f2c11|223344556677885f5f5f5f	64	plan9	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
+f2480f2d11|223344556677885f5f5f5f	64	plan9	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
+f2480f38f011|223344556677885f5f5f	64	plan9	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
+f2480f38f111|223344556677885f5f5f	64	plan9	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	32	plan9	DS 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	32	plan9	REPNE; 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)
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REPNE; MOVNTSS X2, 0(CX)
 f30f1011|223344556677885f5f5f5f5f	32	intel	movss xmm2, dword ptr [ecx]
-f30f1011|223344556677885f5f5f5f5f	32	plan9	REP MOVSS 0(CX), X2
+f30f1011|223344556677885f5f5f5f5f	32	plan9	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
+f30f1011|223344556677885f5f5f5f5f	64	plan9	MOVSS 0(CX), X2
 f30f1122|3344556677885f5f5f5f5f5f	32	intel	movss dword ptr [edx], xmm4
-f30f1122|3344556677885f5f5f5f5f5f	32	plan9	REP MOVSS X4, 0(DX)
+f30f1122|3344556677885f5f5f5f5f5f	32	plan9	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)
+f30f1122|3344556677885f5f5f5f5f5f	64	plan9	MOVSS X4, 0(DX)
 f30f1211|223344556677885f5f5f5f5f	32	intel	movsldup xmm2, xmmword ptr [ecx]
-f30f1211|223344556677885f5f5f5f5f	32	plan9	REP MOVSLDUP 0(CX), X2
+f30f1211|223344556677885f5f5f5f5f	32	plan9	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
+f30f1211|223344556677885f5f5f5f5f	64	plan9	MOVSLDUP 0(CX), X2
 f30f1611|223344556677885f5f5f5f5f	32	intel	movshdup xmm2, xmmword ptr [ecx]
-f30f1611|223344556677885f5f5f5f5f	32	plan9	REP MOVSHDUP 0(CX), X2
+f30f1611|223344556677885f5f5f5f5f	32	plan9	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
+f30f1611|223344556677885f5f5f5f5f	64	plan9	MOVSHDUP 0(CX), X2
 f30f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2ss xmm2, dword ptr [ecx]
-f30f2a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSI2SSL 0(CX), X2
+f30f2a11|223344556677885f5f5f5f5f	32	plan9	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
+f30f2a11|223344556677885f5f5f5f5f	64	plan9	CVTSI2SSL 0(CX), X2
 f30f2c11|223344556677885f5f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
-f30f2c11|223344556677885f5f5f5f5f	32	plan9	REP CVTTSS2SIL 0(CX), DX
+f30f2c11|223344556677885f5f5f5f5f	32	plan9	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
+f30f2c11|223344556677885f5f5f5f5f	64	plan9	CVTTSS2SIL 0(CX), DX
 f30f2d11|223344556677885f5f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
-f30f2d11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SIL 0(CX), DX
+f30f2d11|223344556677885f5f5f5f5f	32	plan9	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
+f30f2d11|223344556677885f5f5f5f5f	64	plan9	CVTSS2SIL 0(CX), DX
 f30f5111|223344556677885f5f5f5f5f	32	intel	sqrtss xmm2, dword ptr [ecx]
-f30f5111|223344556677885f5f5f5f5f	32	plan9	REP SQRTSS 0(CX), X2
+f30f5111|223344556677885f5f5f5f5f	32	plan9	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
+f30f5111|223344556677885f5f5f5f5f	64	plan9	SQRTSS 0(CX), X2
 f30f5211|223344556677885f5f5f5f5f	32	intel	rsqrtss xmm2, dword ptr [ecx]
-f30f5211|223344556677885f5f5f5f5f	32	plan9	REP RSQRTSS 0(CX), X2
+f30f5211|223344556677885f5f5f5f5f	32	plan9	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
+f30f5211|223344556677885f5f5f5f5f	64	plan9	RSQRTSS 0(CX), X2
 f30f5311|223344556677885f5f5f5f5f	32	intel	rcpss xmm2, dword ptr [ecx]
-f30f5311|223344556677885f5f5f5f5f	32	plan9	REP RCPSS 0(CX), X2
+f30f5311|223344556677885f5f5f5f5f	32	plan9	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
+f30f5311|223344556677885f5f5f5f5f	64	plan9	RCPSS 0(CX), X2
 f30f5811|223344556677885f5f5f5f5f	32	intel	addss xmm2, dword ptr [ecx]
-f30f5811|223344556677885f5f5f5f5f	32	plan9	REP ADDSS 0(CX), X2
+f30f5811|223344556677885f5f5f5f5f	32	plan9	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
+f30f5811|223344556677885f5f5f5f5f	64	plan9	ADDSS 0(CX), X2
 f30f5911|223344556677885f5f5f5f5f	32	intel	mulss xmm2, dword ptr [ecx]
-f30f5911|223344556677885f5f5f5f5f	32	plan9	REP MULSS 0(CX), X2
+f30f5911|223344556677885f5f5f5f5f	32	plan9	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
+f30f5911|223344556677885f5f5f5f5f	64	plan9	MULSS 0(CX), X2
 f30f5a11|223344556677885f5f5f5f5f	32	intel	cvtss2sd xmm2, dword ptr [ecx]
-f30f5a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SD 0(CX), X2
+f30f5a11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5a11|223344556677885f5f5f5f5f	64	plan9	CVTSS2SD 0(CX), X2
 f30f5b11|223344556677885f5f5f5f5f	32	intel	cvttps2dq xmm2, xmmword ptr [ecx]
-f30f5b11|223344556677885f5f5f5f5f	32	plan9	REP CVTTPS2DQ 0(CX), X2
+f30f5b11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5b11|223344556677885f5f5f5f5f	64	plan9	CVTTPS2DQ 0(CX), X2
 f30f5c11|223344556677885f5f5f5f5f	32	intel	subss xmm2, dword ptr [ecx]
-f30f5c11|223344556677885f5f5f5f5f	32	plan9	REP SUBSS 0(CX), X2
+f30f5c11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5c11|223344556677885f5f5f5f5f	64	plan9	SUBSS 0(CX), X2
 f30f5d11|223344556677885f5f5f5f5f	32	intel	minss xmm2, dword ptr [ecx]
-f30f5d11|223344556677885f5f5f5f5f	32	plan9	REP MINSS 0(CX), X2
+f30f5d11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5d11|223344556677885f5f5f5f5f	64	plan9	MINSS 0(CX), X2
 f30f5e11|223344556677885f5f5f5f5f	32	intel	divss xmm2, dword ptr [ecx]
-f30f5e11|223344556677885f5f5f5f5f	32	plan9	REP DIVSS 0(CX), X2
+f30f5e11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5e11|223344556677885f5f5f5f5f	64	plan9	DIVSS 0(CX), X2
 f30f5f11|223344556677885f5f5f5f5f	32	intel	maxss xmm2, dword ptr [ecx]
-f30f5f11|223344556677885f5f5f5f5f	32	plan9	REP MAXSS 0(CX), X2
+f30f5f11|223344556677885f5f5f5f5f	32	plan9	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
+f30f5f11|223344556677885f5f5f5f5f	64	plan9	MAXSS 0(CX), X2
 f30f6f11|223344556677885f5f5f5f5f	32	intel	movdqu xmm2, xmmword ptr [ecx]
-f30f6f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU 0(CX), X2
+f30f6f11|223344556677885f5f5f5f5f	32	plan9	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
+f30f6f11|223344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f30f701122|3344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f30f7e11|223344556677885f5f5f5f5f	64	plan9	MOVQ 0(CX), X2
 f30f7f11|223344556677885f5f5f5f5f	32	intel	movdqu xmmword ptr [ecx], xmm2
-f30f7f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU X2, 0(CX)
+f30f7f11|223344556677885f5f5f5f5f	32	plan9	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)
+f30f7f11|223344556677885f5f5f5f5f	64	plan9	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)
+f30fae11|223344556677885f5f5f5f5f	64	plan9	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)
+f30fae18|11223344556677885f5f5f5f	64	plan9	WRGSBASE 0(AX)
 f30faec0|11223344556677885f5f5f5f	64	gnu	rdfsbase %eax
 f30faec0|11223344556677885f5f5f5f	64	intel	rdfsbase eax
-f30faec0|11223344556677885f5f5f5f	64	plan9	REP RDFSBASE AX
+f30faec0|11223344556677885f5f5f5f	64	plan9	RDFSBASE AX
 f30faec8|11223344556677885f5f5f5f	64	gnu	rdgsbase %eax
 f30faec8|11223344556677885f5f5f5f	64	intel	rdgsbase eax
-f30faec8|11223344556677885f5f5f5f	64	plan9	REP RDGSBASE AX
+f30faec8|11223344556677885f5f5f5f	64	plan9	RDGSBASE AX
 f30fb811|223344556677885f5f5f5f5f	32	intel	popcnt edx, dword ptr [ecx]
-f30fb811|223344556677885f5f5f5f5f	32	plan9	REP POPCNT 0(CX), DX
+f30fb811|223344556677885f5f5f5f5f	32	plan9	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
+f30fb811|223344556677885f5f5f5f5f	64	plan9	POPCNT 0(CX), DX
 f30fbc11|223344556677885f5f5f5f5f	32	intel	tzcnt edx, dword ptr [ecx]
-f30fbc11|223344556677885f5f5f5f5f	32	plan9	REP TZCNT 0(CX), DX
+f30fbc11|223344556677885f5f5f5f5f	32	plan9	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
+f30fbc11|223344556677885f5f5f5f5f	64	plan9	TZCNT 0(CX), DX
 f30fbd11|223344556677885f5f5f5f5f	32	intel	lzcnt edx, dword ptr [ecx]
-f30fbd11|223344556677885f5f5f5f5f	32	plan9	REP LZCNT 0(CX), DX
+f30fbd11|223344556677885f5f5f5f5f	32	plan9	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
+f30fbd11|223344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f30fc21122|3344556677885f5f5f5f5f	64	plan9	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	32	plan9	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
+f30fe611|223344556677885f5f5f5f5f	64	plan9	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
+f3480f2a11|223344556677885f5f5f5f	64	plan9	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
+f3480f2c11|223344556677885f5f5f5f	64	plan9	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
+f3480f2d11|223344556677885f5f5f5f	64	plan9	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)
+f3480fae11|223344556677885f5f5f5f	64	plan9	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)
+f3480fae18|11223344556677885f5f5f	64	plan9	WRGSBASE 0(AX)
 f3480faec0|11223344556677885f5f5f	64	gnu	rdfsbase %rax
 f3480faec0|11223344556677885f5f5f	64	intel	rdfsbase rax
-f3480faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
+f3480faec0|11223344556677885f5f5f	64	plan9	RDFSBASE AX
 f3480faec8|11223344556677885f5f5f	64	gnu	rdgsbase %rax
 f3480faec8|11223344556677885f5f5f	64	intel	rdgsbase rax
-f3480faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
+f3480faec8|11223344556677885f5f5f	64	plan9	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
+f3480fb811|223344556677885f5f5f5f	64	plan9	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
+f3480fbc11|223344556677885f5f5f5f	64	plan9	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
+f3480fbd11|223344556677885f5f5f5f	64	plan9	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
@@ -6573,15 +6573,15 @@ 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	32	plan9	REP; 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)
+f3f0673e660f38f111|22334455667788	64	plan9	REP; MOVBE DX, 0(CX)
 f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	intel	movntsd qword ptr [ecx], xmm2
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REPNE MOVNTSD X2, 0(CX)
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REP; 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)
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REP; MOVNTSD X2, 0(CX)
 f4|11223344556677885f5f5f5f5f5f5f	32	intel	hlt
 f4|11223344556677885f5f5f5f5f5f5f	32	plan9	HLT
 f4|11223344556677885f5f5f5f5f5f5f	64	gnu	hlt
@@ -6731,3 +6731,41 @@ 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)
+c5fe6f06|44556677885f5f5f5f5f5f5f	32	intel	vmovdqu ymm0, ymmword ptr [esi]
+c5fe6f06|44556677885f5f5f5f5f5f5f	32	plan9	VMOVDQU 0(SI), X0
+c5fe6f06|44556677885f5f5f5f5f5f5f	32	gnu	vmovdqu (%esi),%ymm0
+c4227d2a0c36|6677885f5f5f5f5f5f5f	64	intel	vmovntdqa ymm9, ymmword ptr [rsi+r14*1]
+c4227d2a0c36|6677885f5f5f5f5f5f5f	64	plan9	VMOVNTDQA 0(SI)(R14*1), X9
+c4227d2a0c36|6677885f5f5f5f5f5f5f	64	gnu	vmovntdqa (%rsi,%r14,1),%ymm9
+c57d7ff7|44556677885f5f5f5f5f5f5f	64	intel	vmovdqa ymm7, ymm14
+c57d7ff7|44556677885f5f5f5f5f5f5f	64	plan9	VMOVDQA X14, X7
+c57d7ff7|44556677885f5f5f5f5f5f5f	64	gnu	vmovdqa %ymm14,%ymm7
+66f3ab|223344556677885f5f5f5f5f5f	64	gnu	rep stos %ax,%es:(%rdi)
+66f3ab|223344556677885f5f5f5f5f5f	64	intel	rep stosw word ptr [rdi]
+66f3ab|223344556677885f5f5f5f5f5f	64	plan9	REP; STOSW AX, ES:0(DI)
+f348a5|223344556677885f5f5f5f5f5f	64	gnu	rep movsq %ds:(%rsi),%es:(%rdi)
+f348a5|223344556677885f5f5f5f5f5f	64	intel	rep movsq qword ptr [rdi], qword ptr [rsi]
+f348a5|223344556677885f5f5f5f5f5f	64	plan9	REP; MOVSQ DS:0(SI), ES:0(DI)
+f348ab|223344556677885f5f5f5f5f5f	64	gnu	rep stos %rax,%es:(%rdi)
+f348ab|223344556677885f5f5f5f5f5f	64	intel	rep stosq qword ptr [rdi]
+f348ab|223344556677885f5f5f5f5f5f	64	plan9	REP; STOSQ AX, ES:0(DI)
+f3a4|11223344556677885f5f5f5f5f5f	32	gnu	rep movsb %ds:(%esi),%es:(%edi)
+f3a4|11223344556677885f5f5f5f5f5f	32	gnu	rep movsb %ds:(%esi),%es:(%edi)
+f3a4|11223344556677885f5f5f5f5f5f	32	intel	rep movsb byte ptr [edi], byte ptr [esi]
+f3a4|11223344556677885f5f5f5f5f5f	32	plan9	REP; MOVSB DS:0(SI), ES:0(DI)
+f3a4|11223344556677885f5f5f5f5f5f	64	gnu	rep movsb %ds:(%rsi),%es:(%rdi)
+f3a4|11223344556677885f5f5f5f5f5f	64	intel	rep movsb byte ptr [rdi], byte ptr [rsi]
+f3a4|11223344556677885f5f5f5f5f5f	64	plan9	REP; MOVSB DS:0(SI), ES:0(DI)
+f3a5|11223344556677885f5f5f5f5f5f	32	gnu	rep movsl %ds:(%esi),%es:(%edi)
+f3a5|11223344556677885f5f5f5f5f5f	32	intel	rep movsd dword ptr [edi], dword ptr [esi]
+f3a5|11223344556677885f5f5f5f5f5f	32	plan9	REP; MOVSD DS:0(SI), ES:0(DI)
+f3a5|11223344556677885f5f5f5f5f5f	64	gnu	rep movsl %ds:(%rsi),%es:(%rdi)
+f3a5|11223344556677885f5f5f5f5f5f	64	intel	rep movsd dword ptr [rdi], dword ptr [rsi]
+f3a5|11223344556677885f5f5f5f5f5f	64	plan9	REP; MOVSD DS:0(SI), ES:0(DI)
+f3a6|11223344556677885f5f5f5f5f5f	64	gnu	rep cmpsb %es:(%rdi),%ds:(%rsi)
+f3a6|11223344556677885f5f5f5f5f5f	64	intel	rep cmpsb byte ptr [rsi], byte ptr [rdi]
+f3a6|11223344556677885f5f5f5f5f5f	64	plan9	REP; CMPSB ES:0(DI), DS:0(SI)
+f3ab|11223344556677885f5f5f5f5f5f	32	gnu	rep stos %eax,%es:(%edi)
+f3ab|11223344556677885f5f5f5f5f5f	32	intel	rep stosd dword ptr [edi]
+f3ab|11223344556677885f5f5f5f5f5f	32	plan9	REP; STOSD AX, ES:0(DI)
+f201c1|223344556677885f5f5f5f5f5f	64	plan9	REPNE; ADDL AX, CX
diff --git a/src/cmd/vendor/vendor.json b/src/cmd/vendor/vendor.json
index 8fc8897..6e8171d 100644
--- a/src/cmd/vendor/vendor.json
+++ b/src/cmd/vendor/vendor.json
@@ -1,10 +1,22 @@
 {
 	"package": [
 		{
+			"canonical": "github.com/ianlancetaylor/demangle",
+			"local": "github.com/ianlancetaylor/demangle",
+			"revision": "4883227f66371e02c4948937d3e2be1664d9be38",
+			"revisionTime": "2016-09-27T19:13:59Z"
+		},
+		{
+			"canonical": "github.com/google/pprof",
+			"local": "github.com/google/pprof",
+			"revision": "dec22b42d9eee442222c36c8da24ddc9905e7ee6",
+			"revisionTime": "2017-03-01T19:58:13Z",
+		},
+		{
 			"canonical": "golang.org/x/arch/x86/x86asm",
 			"local": "golang.org/x/arch/x86/x86asm",
-			"revision": "ad6a463afcf9bd5b38c81fa9ba612dae11859d40",
-			"revisionTime": "2015-08-28T15:42:14Z"
+			"revision": "58ea1a195b1a354bcd572b7ef6bbbd264dc63732",
+			"revisionTime": "2017-02-16T08:17:04Z"
 		},
 		{
 			"canonical": "golang.org/x/arch/arm/armasm",
diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go
index f4ee8fe..64b3a01 100644
--- a/src/cmd/vet/all/main.go
+++ b/src/cmd/vet/all/main.go
@@ -15,15 +15,15 @@ import (
 	"flag"
 	"fmt"
 	"go/build"
+	"go/types"
 	"internal/testenv"
 	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
-	"sync"
+	"sync/atomic"
 )
 
 var (
@@ -33,6 +33,7 @@ var (
 )
 
 var cmdGoPath string
+var failed uint32 // updated atomically
 
 func main() {
 	log.SetPrefix("vet/all: ")
@@ -59,11 +60,15 @@ func main() {
 	case *flagAll:
 		vetPlatforms(allPlatforms())
 	default:
-		host := platform{os: build.Default.GOOS, arch: build.Default.GOARCH}
-		host.vet(runtime.GOMAXPROCS(-1))
+		hostPlatform.vet()
+	}
+	if atomic.LoadUint32(&failed) != 0 {
+		os.Exit(1)
 	}
 }
 
+var hostPlatform = platform{os: build.Default.GOOS, arch: build.Default.GOARCH}
+
 func allPlatforms() []platform {
 	var pp []platform
 	cmd := exec.Command(cmdGoPath, "tool", "dist", "list")
@@ -102,11 +107,11 @@ type whitelist map[string]int
 
 // load adds entries from the whitelist file, if present, for os/arch to w.
 func (w whitelist) load(goos string, goarch string) {
-	// Look up whether goarch is a 32-bit or 64-bit architecture.
-	archbits, ok := nbits[goarch]
-	if !ok {
-		log.Fatalf("unknown bitwidth for arch %q", goarch)
+	sz := types.SizesFor("gc", goarch)
+	if sz == nil {
+		log.Fatalf("unknown type sizes for arch %q", goarch)
 	}
+	archbits := 8 * sz.Sizeof(types.Typ[types.UnsafePointer])
 
 	// Look up whether goarch has a shared arch suffix,
 	// such as mips64x for mips64 and mips64le.
@@ -180,23 +185,12 @@ var ignorePathPrefixes = [...]string{
 }
 
 func vetPlatforms(pp []platform) {
-	ncpus := runtime.GOMAXPROCS(-1) / len(pp)
-	if ncpus < 1 {
-		ncpus = 1
-	}
-	var wg sync.WaitGroup
-	wg.Add(len(pp))
 	for _, p := range pp {
-		p := p
-		go func() {
-			p.vet(ncpus)
-			wg.Done()
-		}()
+		p.vet()
 	}
-	wg.Wait()
 }
 
-func (p platform) vet(ncpus int) {
+func (p platform) vet() {
 	var buf bytes.Buffer
 	fmt.Fprintf(&buf, "go run main.go -p %s\n", p)
 
@@ -204,29 +198,15 @@ func (p platform) vet(ncpus int) {
 	w := make(whitelist)
 	w.load(p.os, p.arch)
 
-	env := append(os.Environ(), "GOOS="+p.os, "GOARCH="+p.arch)
-
-	// Do 'go install std' before running vet.
-	// It is cheap when already installed.
-	// Not installing leads to non-obvious failures due to inability to typecheck.
-	// TODO: If go/loader ever makes it to the standard library, have vet use it,
-	// at which point vet can work off source rather than compiled packages.
-	cmd := exec.Command(cmdGoPath, "install", "-p", strconv.Itoa(ncpus), "std")
-	cmd.Env = env
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		log.Fatalf("failed to run GOOS=%s GOARCH=%s 'go install std': %v\n%s", p.os, p.arch, err, out)
-	}
-
 	// 'go tool vet .' is considerably faster than 'go vet ./...'
 	// TODO: The unsafeptr checks are disabled for now,
 	// because there are so many false positives,
 	// and no clear way to improve vet to eliminate large chunks of them.
 	// And having them in the whitelists will just cause annoyance
 	// and churn when working on the runtime.
-	cmd = exec.Command(cmdGoPath, "tool", "vet", "-unsafeptr=false", ".")
+	cmd := exec.Command(cmdGoPath, "tool", "vet", "-unsafeptr=false", "-source", ".")
 	cmd.Dir = filepath.Join(runtime.GOROOT(), "src")
-	cmd.Env = env
+	cmd.Env = append(os.Environ(), "GOOS="+p.os, "GOARCH="+p.arch, "CGO_ENABLED=0")
 	stderr, err := cmd.StderrPipe()
 	if err != nil {
 		log.Fatal(err)
@@ -237,6 +217,7 @@ func (p platform) vet(ncpus int) {
 
 	// Process vet output.
 	scan := bufio.NewScanner(stderr)
+	var parseFailed bool
 NextLine:
 	for scan.Scan() {
 		line := scan.Text()
@@ -255,7 +236,11 @@ NextLine:
 		case 3:
 			file, lineno, msg = fields[0], fields[1], fields[2]
 		default:
-			log.Fatalf("could not parse vet output line:\n%s", line)
+			if !parseFailed {
+				parseFailed = true
+				fmt.Fprintln(os.Stderr, "failed to parse vet output:")
+			}
+			fmt.Println(os.Stderr, line)
 		}
 		msg = strings.TrimSpace(msg)
 
@@ -273,10 +258,15 @@ NextLine:
 			} else {
 				fmt.Fprintf(&buf, "%s:%s: %s\n", file, lineno, msg)
 			}
+			atomic.StoreUint32(&failed, 1)
 			continue
 		}
 		w[key]--
 	}
+	if parseFailed {
+		atomic.StoreUint32(&failed, 1)
+		return
+	}
 	if scan.Err() != nil {
 		log.Fatalf("failed to scan vet output: %v", scan.Err())
 	}
@@ -297,6 +287,7 @@ NextLine:
 				for i := 0; i < v; i++ {
 					fmt.Fprintln(&buf, k)
 				}
+				atomic.StoreUint32(&failed, 1)
 			}
 		}
 	}
@@ -304,29 +295,14 @@ NextLine:
 	os.Stdout.Write(buf.Bytes())
 }
 
-// nbits maps from architecture names to the number of bits in a pointer.
-// TODO: figure out a clean way to avoid get this info rather than listing it here yet again.
-var nbits = map[string]int{
-	"386":      32,
-	"amd64":    64,
-	"amd64p32": 32,
-	"arm":      32,
-	"arm64":    64,
-	"mips":     32,
-	"mipsle":   32,
-	"mips64":   64,
-	"mips64le": 64,
-	"ppc64":    64,
-	"ppc64le":  64,
-	"s390x":    64,
-}
-
 // archAsmX maps architectures to the suffix usually used for their assembly files,
 // if different than the arch name itself.
 var archAsmX = map[string]string{
 	"android":  "linux",
 	"mips64":   "mips64x",
 	"mips64le": "mips64x",
+	"mips":     "mipsx",
+	"mipsle":   "mipsx",
 	"ppc64":    "ppc64x",
 	"ppc64le":  "ppc64x",
 }
diff --git a/src/cmd/vet/all/whitelist/64bit.txt b/src/cmd/vet/all/whitelist/64bit.txt
deleted file mode 100644
index 35b9eb3..0000000
--- a/src/cmd/vet/all/whitelist/64bit.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 64-bit-specific vet whitelist. See readme.txt for details.
-
-// False positives.
-
-// Clever const tricks outwit the "large shift" check.
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap.go: hash might be too small for shift of 56
-runtime/hashmap_fast.go: hash might be too small for shift of 56
-runtime/hashmap_fast.go: hash might be too small for shift of 56
diff --git a/src/cmd/vet/all/whitelist/all.txt b/src/cmd/vet/all/whitelist/all.txt
index 7250de1..c28035f 100644
--- a/src/cmd/vet/all/whitelist/all.txt
+++ b/src/cmd/vet/all/whitelist/all.txt
@@ -13,17 +13,17 @@ go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have
 
 // False positives.
 
+// Test of how fmt handles nil.
+fmt/fmt_test.go: arg nil for printf verb %s of wrong type: untyped nil
+
 // Nothing much to do about cross-package assembly. Unfortunate.
 runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: call is in package reflect
 runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Equal is in package bytes
 runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package bytes
 runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package strings
-runtime/sys_GOOS_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: now is in package time
 
 // Legitimate vet complaints in which we are testing for correct runtime behavior
 // in bad situations that vet can also detect statically.
-cmd/cover/testdata/test.go: unreachable code
-fmt/fmt_test.go: arg nil for printf verb %s of wrong type: untyped nil
 encoding/json/decode_test.go: struct field m has json tag but is not exported
 encoding/json/decode_test.go: struct field m2 has json tag but is not exported
 encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key
@@ -37,7 +37,6 @@ sync/cond_test.go: assignment copies lock value to c2: sync.Cond contains sync.n
 // Except for the runtime/pprof case, the API is not exported.
 cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error)
 cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error)
-cmd/internal/obj/link.go: method Peek(i int) byte should have signature Peek(int) ([]byte, error)
 fmt/print.go: method WriteByte(c byte) should have signature WriteByte(byte) error
 runtime/pprof/pprof.go: method WriteTo(w io.Writer, debug int) error should have signature WriteTo(io.Writer) (int64, error)
 
@@ -50,41 +49,6 @@ encoding/xml/marshal_test.go: method MarshalXML(e *Encoder, start StartElement)
 encoding/xml/read.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error
 encoding/xml/read_test.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error
 
-// Lots of false positives from the "large shift" check.
-// Mostly code that uses clever const tricks to determine
-// or use the size of an int or pointer (and related values).
-image/png/paeth.go: x might be too small for shift of 63
-math/big/arith.go: x might be too small for shift of 32
-math/big/arith.go: y might be too small for shift of 32
-math/big/arith.go: w0 might be too small for shift of 32
-math/big/arith.go: t might be too small for shift of 32
-math/big/arith.go: w1 might be too small for shift of 32
-math/big/arith.go: v might be too small for shift of 32
-math/big/arith.go: un10 might be too small for shift of 32
-math/big/arith.go: (xi&yi | (xi|yi)&^zi) might be too small for shift of 63
-math/big/arith.go: (yi&^xi | (yi|^xi)&zi) might be too small for shift of 63
-math/big/arith.go: xi &^ zi might be too small for shift of 63
-math/big/arith.go: (zi &^ xi) might be too small for shift of 63
-math/big/float.go: x[i] might be too small for shift of 32
-math/big/nat.go: t too small for shift of 64
-math/big/nat.go: x too small for shift of 64
-math/big/nat.go: ((x & -x) * (deBruijn64 & _M)) might be too small for shift of 58
-math/big/nat.go: Word(rand.Uint32()) might be too small for shift of 32
-math/big/nat.go: yi might be too small for shift of 60
-math/big/nat.go: yi might be too small for shift of 60
-runtime/cpuprof.go: h might be too small for shift of 56
-runtime/malloc.go: uintptr(i) might be too small for shift of 40
-runtime/malloc.go: uintptr(i) might be too small for shift of 40
-runtime/malloc.go: uintptr(i) might be too small for shift of 40
-sync/atomic/atomic_test.go: uintptr(seed + i) might be too small for shift of 32
-sync/atomic/atomic_test.go: uintptr(seed+i) << 32 might be too small for shift of 32
-sync/atomic/atomic_test.go: uintptr(seed + i) might be too small for shift of 32
-sync/atomic/atomic_test.go: old might be too small for shift of 32
-sync/atomic/atomic_test.go: old << 32 might be too small for shift of 32
-sync/atomic/atomic_test.go: old might be too small for shift of 32
-sync/atomic/atomic_test.go: v might be too small for shift of 32
-sync/atomic/atomic_test.go: v might be too small for shift of 32
-
 // Long struct tags used to test reflect internals
 cmd/link/link_test.go: struct field tag "\n\tLondon. 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 a [...]
 cmd/link/link_test.go: struct field tag "\n\tIt 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 aga [...]
diff --git a/src/cmd/vet/all/whitelist/amd64.txt b/src/cmd/vet/all/whitelist/amd64.txt
index df4ec84..fb617d5 100644
--- a/src/cmd/vet/all/whitelist/amd64.txt
+++ b/src/cmd/vet/all/whitelist/amd64.txt
@@ -15,8 +15,8 @@ runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument fram
 runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package strings
 runtime/asm_amd64.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
 runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package bytes
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: supportAVX2 is in package strings
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: supportAVX2 is in package bytes
+runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package strings
+runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package bytes
 
 // Intentionally missing declarations. These are special assembly routines.
 // Some are jumped into from other routines, with values in specific registers.
@@ -32,4 +32,4 @@ runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration
 runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration
 runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration
 runtime/asm_amd64.s: [amd64] indexShortStr: function indexShortStr missing Go declaration
-
+runtime/asm_amd64.s: [amd64] countByte: function countByte missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/darwin_386.txt b/src/cmd/vet/all/whitelist/darwin_386.txt
index c5c51d0..d19d7d7 100644
--- a/src/cmd/vet/all/whitelist/darwin_386.txt
+++ b/src/cmd/vet/all/whitelist/darwin_386.txt
@@ -6,3 +6,4 @@ runtime/sys_darwin_386.s: [386] now: function now missing Go declaration
 runtime/sys_darwin_386.s: [386] bsdthread_start: function bsdthread_start missing Go declaration
 runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration
 runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration
+runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time
diff --git a/src/cmd/vet/all/whitelist/darwin_amd64.txt b/src/cmd/vet/all/whitelist/darwin_amd64.txt
index 277abd7..94a4e8f 100644
--- a/src/cmd/vet/all/whitelist/darwin_amd64.txt
+++ b/src/cmd/vet/all/whitelist/darwin_amd64.txt
@@ -2,3 +2,4 @@
 
 runtime/sys_darwin_amd64.s: [amd64] bsdthread_start: function bsdthread_start missing Go declaration
 runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration
+runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time
diff --git a/src/cmd/vet/all/whitelist/mips.txt b/src/cmd/vet/all/whitelist/mips.txt
new file mode 100644
index 0000000..ad29336
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/mips.txt
@@ -0,0 +1,7 @@
+// mips64-specific vet whitelist. See readme.txt for details.
+
+// Work around if-def'd code. Will be fixed by golang.org/issue/17544.
+runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_lo+0(FP); expected sec_lo+4(FP)
+runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_hi+4(FP); expected sec_hi+0(FP)
+runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_lo+0(FP); expected ret_lo+4(FP)
+runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_hi+4(FP); expected ret_hi+0(FP)
diff --git a/src/cmd/vet/all/whitelist/mipsle.txt b/src/cmd/vet/all/whitelist/mipsle.txt
new file mode 100644
index 0000000..9292169
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/mipsle.txt
@@ -0,0 +1,7 @@
+// mips64-specific vet whitelist. See readme.txt for details.
+
+// Work around if-def'd code. Will be fixed by golang.org/issue/17544.
+runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_lo+4(FP); expected sec_lo+0(FP)
+runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_hi+0(FP); expected sec_hi+4(FP)
+runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_lo+4(FP); expected ret_lo+0(FP)
+runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_hi+0(FP); expected ret_hi+4(FP)
diff --git a/src/cmd/vet/all/whitelist/mipsx.txt b/src/cmd/vet/all/whitelist/mipsx.txt
new file mode 100644
index 0000000..949a1b3
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/mipsx.txt
@@ -0,0 +1,11 @@
+// mips64-specific vet whitelist. See readme.txt for details.
+
+reflect/asm_mipsx.s: [GOARCH] makeFuncStub: use of 8(R29) points beyond argument frame
+reflect/asm_mipsx.s: [GOARCH] methodValueCall: use of 8(R29) points beyond argument frame
+runtime/asm_mipsx.s: [GOARCH] abort: function abort missing Go declaration
+runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration
+runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration
+runtime/asm_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP)
+runtime/sys_linux_mipsx.s: [GOARCH] clone: 4(R29) should be flags+0(FP)
+runtime/sys_linux_mipsx.s: [GOARCH] clone: 8(R29) should be stk+4(FP)
diff --git a/src/cmd/vet/all/whitelist/windows.txt b/src/cmd/vet/all/whitelist/windows.txt
index e80a92f..1a208ad 100644
--- a/src/cmd/vet/all/whitelist/windows.txt
+++ b/src/cmd/vet/all/whitelist/windows.txt
@@ -1,5 +1,9 @@
 // windows-specific vet whitelist. See readme.txt for details.
 
+// Issue 18609
+crypto/x509/root_windows.go: unreachable code
+
 path/filepath/path_windows_test.go: possible formatting directive in Fatal call
+
 runtime/sys_windows_ARCHSUFF.s: [GOARCH] sigtramp: function sigtramp missing Go declaration
 runtime/sys_windows_ARCHSUFF.s: [GOARCH] onosstack: unknown variable usec; offset 0 is fn+0(FP)
diff --git a/src/cmd/vet/all/whitelist/windows_386.txt b/src/cmd/vet/all/whitelist/windows_386.txt
index 7a6d23f..788684a 100644
--- a/src/cmd/vet/all/whitelist/windows_386.txt
+++ b/src/cmd/vet/all/whitelist/windows_386.txt
@@ -7,3 +7,4 @@ runtime/zcallback_windows.s: [386] callbackasm: function callbackasm missing Go
 runtime/sys_windows_386.s: [386] callbackasm1+0: function callbackasm1+0 missing Go declaration
 runtime/sys_windows_386.s: [386] tstart: function tstart missing Go declaration
 runtime/sys_windows_386.s: [386] tstart_stdcall: RET without writing to 4-byte ret+4(FP)
+runtime/sys_windows_386.s: [386] cannot check cross-package assembly function: now is in package time
diff --git a/src/cmd/vet/all/whitelist/windows_amd64.txt b/src/cmd/vet/all/whitelist/windows_amd64.txt
index a2e1844..3be4602 100644
--- a/src/cmd/vet/all/whitelist/windows_amd64.txt
+++ b/src/cmd/vet/all/whitelist/windows_amd64.txt
@@ -5,4 +5,5 @@ runtime/sys_windows_amd64.s: [amd64] ctrlhandler: RET without writing to 4-byte
 runtime/sys_windows_amd64.s: [amd64] callbackasm1: function callbackasm1 missing Go declaration
 runtime/sys_windows_amd64.s: [amd64] tstart_stdcall: RET without writing to 4-byte ret+8(FP)
 runtime/sys_windows_amd64.s: [amd64] settls: function settls missing Go declaration
+runtime/sys_windows_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time
 runtime/zcallback_windows.s: [amd64] callbackasm: function callbackasm missing Go declaration
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
index a516cc4..7882112 100644
--- a/src/cmd/vet/asmdecl.go
+++ b/src/cmd/vet/asmdecl.go
@@ -36,10 +36,14 @@ const (
 // An asmArch describes assembly parameters for an architecture
 type asmArch struct {
 	name      string
-	sizes     *types.StdSizes
 	bigEndian bool
 	stack     string
 	lr        bool
+	// calculated during initialization
+	sizes    types.Sizes
+	intSize  int
+	ptrSize  int
+	maxAlign int
 }
 
 // An asmFunc describes the expected variables for a function on a given architecture.
@@ -60,26 +64,19 @@ type asmVar struct {
 	inner []*asmVar
 }
 
-// Common architecture word sizes and alignments.
 var (
-	size44 = &types.StdSizes{WordSize: 4, MaxAlign: 4}
-	size48 = &types.StdSizes{WordSize: 4, MaxAlign: 8}
-	size88 = &types.StdSizes{WordSize: 8, MaxAlign: 8}
-)
-
-var (
-	asmArch386      = asmArch{"386", size44, false, "SP", false}
-	asmArchArm      = asmArch{"arm", size44, false, "R13", true}
-	asmArchArm64    = asmArch{"arm64", size88, false, "RSP", true}
-	asmArchAmd64    = asmArch{"amd64", size88, false, "SP", false}
-	asmArchAmd64p32 = asmArch{"amd64p32", size48, false, "SP", false}
-	asmArchMips     = asmArch{"mips", size44, true, "R29", true}
-	asmArchMipsLE   = asmArch{"mipsle", size44, false, "R29", true}
-	asmArchMips64   = asmArch{"mips64", size88, true, "R29", true}
-	asmArchMips64LE = asmArch{"mips64le", size88, false, "R29", true}
-	asmArchPpc64    = asmArch{"ppc64", size88, true, "R1", true}
-	asmArchPpc64LE  = asmArch{"ppc64le", size88, false, "R1", true}
-	asmArchS390X    = asmArch{"s390x", size88, true, "R15", true}
+	asmArch386      = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
+	asmArchArm      = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
+	asmArchArm64    = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true}
+	asmArchAmd64    = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false}
+	asmArchAmd64p32 = asmArch{name: "amd64p32", bigEndian: false, stack: "SP", lr: false}
+	asmArchMips     = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
+	asmArchMipsLE   = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true}
+	asmArchMips64   = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true}
+	asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true}
+	asmArchPpc64    = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
+	asmArchPpc64LE  = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
+	asmArchS390X    = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
 
 	arches = []*asmArch{
 		&asmArch386,
@@ -97,9 +94,17 @@ var (
 	}
 )
 
-func (a *asmArch) intSize() int  { return int(a.sizes.WordSize) }
-func (a *asmArch) ptrSize() int  { return int(a.sizes.WordSize) }
-func (a *asmArch) maxAlign() int { return int(a.sizes.MaxAlign) }
+func init() {
+	for _, arch := range arches {
+		arch.sizes = types.SizesFor("gc", arch.name)
+		if arch.sizes == nil {
+			panic("missing SizesFor for gc/" + arch.name)
+		}
+		arch.intSize = int(arch.sizes.Sizeof(types.Typ[types.Int]))
+		arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
+		arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
+	}
+}
 
 var (
 	re           = regexp.MustCompile
@@ -244,10 +249,10 @@ Files:
 					}
 				}
 				localSize, _ = strconv.Atoi(m[4])
-				localSize += archDef.intSize()
+				localSize += archDef.intSize
 				if archDef.lr {
 					// Account for caller's saved LR
-					localSize += archDef.intSize()
+					localSize += archDef.intSize
 				}
 				argSize, _ = strconv.Atoi(m[5])
 				if fn == nil && !strings.Contains(fnName, "<>") {
@@ -412,7 +417,7 @@ func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suff
 
 	switch kind {
 	case 8:
-		if arch.ptrSize() == 4 {
+		if arch.ptrSize == 4 {
 			w1, w2 := "lo", "hi"
 			if arch.bigEndian {
 				w1, w2 = w2, w1
@@ -422,21 +427,21 @@ func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suff
 		}
 
 	case asmEmptyInterface:
-		cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize()), "interface type", off, arch.ptrSize(), suffix))
-		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix))
+		cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize), "interface type", off, arch.ptrSize, suffix))
+		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
 
 	case asmInterface:
-		cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize()), "interface itable", off, arch.ptrSize(), suffix))
-		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix))
+		cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize), "interface itable", off, arch.ptrSize, suffix))
+		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
 
 	case asmSlice:
-		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "slice base", off, arch.ptrSize(), suffix))
-		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "slice len", off+arch.ptrSize(), arch.intSize(), suffix))
-		cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize()), "slice cap", off+arch.ptrSize()+arch.intSize(), arch.intSize(), suffix))
+		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "slice base", off, arch.ptrSize, suffix))
+		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "slice len", off+arch.ptrSize, arch.intSize, suffix))
+		cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize), "slice cap", off+arch.ptrSize+arch.intSize, arch.intSize, suffix))
 
 	case asmString:
-		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "string base", off, arch.ptrSize(), suffix))
-		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "string len", off+arch.ptrSize(), arch.intSize(), suffix))
+		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "string base", off, arch.ptrSize, suffix))
+		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "string len", off+arch.ptrSize, arch.intSize, suffix))
 
 	case asmComplex:
 		fsize := size / 2
@@ -542,7 +547,7 @@ func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
 		offset = 0
 		addParams(decl.Type.Params.List, false)
 		if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
-			offset += -offset & (arch.maxAlign() - 1)
+			offset += -offset & (arch.maxAlign - 1)
 			addParams(decl.Type.Results.List, true)
 		}
 		fn.size = offset
diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go
index ccf764e..5fa08b6 100644
--- a/src/cmd/vet/buildtag.go
+++ b/src/cmd/vet/buildtag.go
@@ -52,6 +52,7 @@ func checkBuildTag(name string, data []byte) {
 			if !bytes.Equal(fields[0], plusBuild) {
 				// Comment is something like +buildasdf not +build.
 				fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+				setExit(1)
 				continue
 			}
 			if i >= cutoff {
@@ -85,6 +86,7 @@ func checkBuildTag(name string, data []byte) {
 		// Comment with +build but not at beginning.
 		if bytes.Contains(line, plusBuild) && i < cutoff {
 			fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+			setExit(1)
 			continue
 		}
 	}
diff --git a/src/cmd/vet/dead.go b/src/cmd/vet/dead.go
new file mode 100644
index 0000000..b3a157b
--- /dev/null
+++ b/src/cmd/vet/dead.go
@@ -0,0 +1,108 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Simplified dead code detector. Used for skipping certain checks
+// on unreachable code (for instance, shift checks on arch-specific code).
+//
+package main
+
+import (
+	"go/ast"
+	"go/constant"
+)
+
+// updateDead puts unreachable "if" and "case" nodes into f.dead.
+func (f *File) updateDead(node ast.Node) {
+	if f.dead[node] {
+		// The node is already marked as dead.
+		return
+	}
+
+	switch stmt := node.(type) {
+	case *ast.IfStmt:
+		// "if" branch is dead if its condition evaluates
+		// to constant false.
+		v := f.pkg.types[stmt.Cond].Value
+		if v == nil {
+			return
+		}
+		if !constant.BoolVal(v) {
+			f.setDead(stmt.Body)
+			return
+		}
+		f.setDead(stmt.Else)
+	case *ast.SwitchStmt:
+		// Case clause with empty switch tag is dead if it evaluates
+		// to constant false.
+		if stmt.Tag == nil {
+		BodyLoopBool:
+			for _, stmt := range stmt.Body.List {
+				cc := stmt.(*ast.CaseClause)
+				if cc.List == nil {
+					// Skip default case.
+					continue
+				}
+				for _, expr := range cc.List {
+					v := f.pkg.types[expr].Value
+					if v == nil || constant.BoolVal(v) {
+						continue BodyLoopBool
+					}
+				}
+				f.setDead(cc)
+			}
+			return
+		}
+
+		// Case clause is dead if its constant value doesn't match
+		// the constant value from the switch tag.
+		// TODO: This handles integer comparisons only.
+		v := f.pkg.types[stmt.Tag].Value
+		if v == nil || v.Kind() != constant.Int {
+			return
+		}
+		tagN, ok := constant.Uint64Val(v)
+		if !ok {
+			return
+		}
+	BodyLoopInt:
+		for _, x := range stmt.Body.List {
+			cc := x.(*ast.CaseClause)
+			if cc.List == nil {
+				// Skip default case.
+				continue
+			}
+			for _, expr := range cc.List {
+				v := f.pkg.types[expr].Value
+				if v == nil {
+					continue BodyLoopInt
+				}
+				n, ok := constant.Uint64Val(v)
+				if !ok || tagN == n {
+					continue BodyLoopInt
+				}
+			}
+			f.setDead(cc)
+		}
+	}
+}
+
+// setDead marks the node and all the children as dead.
+func (f *File) setDead(node ast.Node) {
+	dv := deadVisitor{
+		f: f,
+	}
+	ast.Walk(dv, node)
+}
+
+type deadVisitor struct {
+	f *File
+}
+
+func (dv deadVisitor) Visit(node ast.Node) ast.Visitor {
+	if node == nil {
+		return nil
+	}
+	dv.f.dead[node] = true
+	return dv
+}
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index 5cbe116..1ee44a4 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -34,6 +34,9 @@ If any flags are explicitly set to true, only those tests are run. Conversely, i
 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 vet uses the object files generated by 'go install some/pkg' to typecheck the code.
+If the -source flag is provided, vet uses only source code.
+
 Available checks:
 
 Assembly declarations
diff --git a/src/cmd/vet/httpresponse.go b/src/cmd/vet/httpresponse.go
index f667edb..ce5ae46 100644
--- a/src/cmd/vet/httpresponse.go
+++ b/src/cmd/vet/httpresponse.go
@@ -12,29 +12,17 @@ import (
 	"go/types"
 )
 
-var (
-	httpResponseType types.Type
-	httpClientType   types.Type
-)
-
 func init() {
-	if typ := importType("net/http", "Response"); typ != nil {
-		httpResponseType = typ
-	}
-	if typ := importType("net/http", "Client"); typ != nil {
-		httpClientType = typ
-	}
-	// if http.Response or http.Client are not defined don't register this check.
-	if httpResponseType == nil || httpClientType == nil {
-		return
-	}
-
 	register("httpresponse",
 		"check errors are checked before using an http Response",
 		checkHTTPResponse, callExpr)
 }
 
 func checkHTTPResponse(f *File, node ast.Node) {
+	// If http.Response or http.Client are not defined, skip this check.
+	if httpResponseType == nil || httpClientType == nil {
+		return
+	}
 	call := node.(*ast.CallExpr)
 	if !isHTTPFuncOrMethodOnClient(f, call) {
 		return // the function call is not related to this check.
diff --git a/src/cmd/vet/lostcancel.go b/src/cmd/vet/lostcancel.go
index d049a3e..ee03420 100644
--- a/src/cmd/vet/lostcancel.go
+++ b/src/cmd/vet/lostcancel.go
@@ -104,7 +104,11 @@ func checkLostCancel(f *File, node ast.Node) {
 	var sig *types.Signature
 	switch node := node.(type) {
 	case *ast.FuncDecl:
-		sig, _ = f.pkg.defs[node.Name].Type().(*types.Signature)
+		obj := f.pkg.defs[node.Name]
+		if obj == nil {
+			return // type error (e.g. duplicate function declaration)
+		}
+		sig, _ = obj.Type().(*types.Signature)
 		g = cfg.New(node.Body, mayReturn)
 	case *ast.FuncLit:
 		sig, _ = f.pkg.types[node.Type].Type.(*types.Signature)
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 3da0b3c..77376c9 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -23,8 +23,11 @@ import (
 	"strings"
 )
 
+// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
+
 var (
 	verbose = flag.Bool("v", false, "verbose")
+	source  = flag.Bool("source", false, "import from source instead of compiled object files")
 	tags    = flag.String("tags", "", "space-separated list of build tags to apply when parsing")
 	tagList = []string{} // exploded version of tags flag; set in main
 )
@@ -191,6 +194,9 @@ type File struct {
 
 	// Registered checkers to run.
 	checkers map[ast.Node][]func(*File, ast.Node)
+
+	// Unreachable nodes; can be ignored in shift check.
+	dead map[ast.Node]bool
 }
 
 func main() {
@@ -327,7 +333,13 @@ func doPackage(directory string, names []string, basePkg *Package) *Package {
 			}
 			astFiles = append(astFiles, parsedFile)
 		}
-		files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
+		files = append(files, &File{
+			fset:    fs,
+			content: data,
+			name:    name,
+			file:    parsedFile,
+			dead:    make(map[ast.Node]bool),
+		})
 	}
 	if len(astFiles) == 0 {
 		return nil
@@ -469,6 +481,7 @@ func (f *File) walkFile(name string, file *ast.File) {
 
 // Visit implements the ast.Visitor interface.
 func (f *File) Visit(node ast.Node) ast.Visitor {
+	f.updateDead(node)
 	var key ast.Node
 	switch node.(type) {
 	case *ast.AssignStmt:
diff --git a/src/cmd/vet/method.go b/src/cmd/vet/method.go
index 8a554e1..baefa55 100644
--- a/src/cmd/vet/method.go
+++ b/src/cmd/vet/method.go
@@ -48,7 +48,6 @@ var canonicalMethods = map[string]MethodSig{
 	"GobEncode":     {[]string{}, []string{"[]byte", "error"}},                         // gob.GobEncoder
 	"MarshalJSON":   {[]string{}, []string{"[]byte", "error"}},                         // json.Marshaler
 	"MarshalXML":    {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler
-	"Peek":          {[]string{"=int"}, []string{"[]byte", "error"}},                   // image.reader (matching bufio.Reader)
 	"ReadByte":      {[]string{}, []string{"byte", "error"}},                           // io.ByteReader
 	"ReadFrom":      {[]string{"=io.Reader"}, []string{"int64", "error"}},              // io.ReaderFrom
 	"ReadRune":      {[]string{}, []string{"rune", "int", "error"}},                    // io.RuneReader
diff --git a/src/cmd/vet/shift.go b/src/cmd/vet/shift.go
index 55f3ea3..1e48d32 100644
--- a/src/cmd/vet/shift.go
+++ b/src/cmd/vet/shift.go
@@ -23,6 +23,11 @@ func init() {
 }
 
 func checkShift(f *File, node ast.Node) {
+	if f.dead[node] {
+		// Skip shift checks on unreachable nodes.
+		return
+	}
+
 	switch node := node.(type) {
 	case *ast.BinaryExpr:
 		if node.Op == token.SHL || node.Op == token.SHR {
@@ -47,6 +52,7 @@ func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
 		// like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
 		return
 	}
+
 	v := f.pkg.types[y].Value
 	if v == nil {
 		return
@@ -64,7 +70,6 @@ func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
 		return
 	}
 	var size int64
-	var msg string
 	switch b.Kind() {
 	case types.Uint8, types.Int8:
 		size = 8
@@ -74,15 +79,20 @@ func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
 		size = 32
 	case types.Uint64, types.Int64:
 		size = 64
-	case types.Int, types.Uint, types.Uintptr:
-		// These types may be as small as 32 bits, but no smaller.
-		size = 32
-		msg = "might be "
+	case types.Int, types.Uint:
+		size = uintBitSize
+	case types.Uintptr:
+		size = uintptrBitSize
 	default:
 		return
 	}
 	if amt >= size {
 		ident := f.gofmt(x)
-		f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
+		f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
 	}
 }
+
+var (
+	uintBitSize    = 8 * archSizes.Sizeof(types.Typ[types.Uint])
+	uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
+)
diff --git a/src/cmd/vet/testdata/copylock_func.go b/src/cmd/vet/testdata/copylock_func.go
index d51ff27..0f7ffcb 100644
--- a/src/cmd/vet/testdata/copylock_func.go
+++ b/src/cmd/vet/testdata/copylock_func.go
@@ -87,9 +87,9 @@ func FuncCallInterfaceArg(f func(a int, b interface{})) {
 	f(2, &t)
 	f(3, &sync.Mutex{})
 	f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
-	f(5, t) // ERROR "call of f copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+	f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
 	var fntab []func(t)
-	fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+	fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
 }
 
 // Returning lock via interface value
@@ -105,7 +105,7 @@ func ReturnViaInterface(x int) (int, interface{}) {
 	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"
+		return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
 	}
 }
 
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
index b5c59eb..76e7bd7 100644
--- a/src/cmd/vet/testdata/print.go
+++ b/src/cmd/vet/testdata/print.go
@@ -87,6 +87,9 @@ func PrintfTests() {
 	fmt.Printf("%s", &stringerv)
 	fmt.Printf("%v", &stringerv)
 	fmt.Printf("%T", &stringerv)
+	fmt.Printf("%s", &embeddedStringerv)
+	fmt.Printf("%v", &embeddedStringerv)
+	fmt.Printf("%T", &embeddedStringerv)
 	fmt.Printf("%v", notstringerv)
 	fmt.Printf("%T", notstringerv)
 	fmt.Printf("%q", stringerarrayv)
@@ -123,6 +126,8 @@ func PrintfTests() {
 	fmt.Printf("%X", 2.3)                      // ERROR "arg 2.3 for printf verb %X of wrong type"
 	fmt.Printf("%s", stringerv)                // ERROR "arg stringerv for printf verb %s of wrong type"
 	fmt.Printf("%t", stringerv)                // ERROR "arg stringerv for printf verb %t of wrong type"
+	fmt.Printf("%s", embeddedStringerv)        // ERROR "arg embeddedStringerv for printf verb %s of wrong type"
+	fmt.Printf("%t", embeddedStringerv)        // ERROR "arg embeddedStringerv for printf verb %t of wrong type"
 	fmt.Printf("%q", notstringerv)             // ERROR "arg notstringerv for printf verb %q of wrong type"
 	fmt.Printf("%t", notstringerv)             // ERROR "arg notstringerv for printf verb %t of wrong type"
 	fmt.Printf("%t", stringerarrayv)           // ERROR "arg stringerarrayv for printf verb %t of wrong type"
@@ -346,6 +351,14 @@ func (*stringer) Warnf(int, string, ...interface{}) string {
 	return "warnf"
 }
 
+type embeddedStringer struct {
+	foo string
+	stringer
+	bar int
+}
+
+var embeddedStringerv embeddedStringer
+
 type notstringer struct {
 	f float64
 }
diff --git a/src/cmd/vet/testdata/shift.go b/src/cmd/vet/testdata/shift.go
index 99acaad..50a042e 100644
--- a/src/cmd/vet/testdata/shift.go
+++ b/src/cmd/vet/testdata/shift.go
@@ -6,75 +6,154 @@
 
 package testdata
 
+import "unsafe"
+
 func ShiftTest() {
 	var i8 int8
 	_ = i8 << 7
-	_ = (i8 + 1) << 8 // ERROR "\(i8 \+ 1\) too small for shift of 8"
-	_ = i8 << (7 + 1) // ERROR "i8 too small for shift of 8"
-	_ = i8 >> 8       // ERROR "i8 too small for shift of 8"
-	i8 <<= 8          // ERROR "i8 too small for shift of 8"
-	i8 >>= 8          // ERROR "i8 too small for shift of 8"
+	_ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8"
+	_ = i8 << (7 + 1) // ERROR "i8 .8 bits. too small for shift of 8"
+	_ = i8 >> 8       // ERROR "i8 .8 bits. too small for shift of 8"
+	i8 <<= 8          // ERROR "i8 .8 bits. too small for shift of 8"
+	i8 >>= 8          // ERROR "i8 .8 bits. too small for shift of 8"
 	var i16 int16
 	_ = i16 << 15
-	_ = i16 << 16 // ERROR "i16 too small for shift of 16"
-	_ = i16 >> 16 // ERROR "i16 too small for shift of 16"
-	i16 <<= 16    // ERROR "i16 too small for shift of 16"
-	i16 >>= 16    // ERROR "i16 too small for shift of 16"
+	_ = i16 << 16 // ERROR "i16 .16 bits. too small for shift of 16"
+	_ = i16 >> 16 // ERROR "i16 .16 bits. too small for shift of 16"
+	i16 <<= 16    // ERROR "i16 .16 bits. too small for shift of 16"
+	i16 >>= 16    // ERROR "i16 .16 bits. too small for shift of 16"
 	var i32 int32
 	_ = i32 << 31
-	_ = i32 << 32 // ERROR "i32 too small for shift of 32"
-	_ = i32 >> 32 // ERROR "i32 too small for shift of 32"
-	i32 <<= 32    // ERROR "i32 too small for shift of 32"
-	i32 >>= 32    // ERROR "i32 too small for shift of 32"
+	_ = i32 << 32 // ERROR "i32 .32 bits. too small for shift of 32"
+	_ = i32 >> 32 // ERROR "i32 .32 bits. too small for shift of 32"
+	i32 <<= 32    // ERROR "i32 .32 bits. too small for shift of 32"
+	i32 >>= 32    // ERROR "i32 .32 bits. too small for shift of 32"
 	var i64 int64
 	_ = i64 << 63
-	_ = i64 << 64 // ERROR "i64 too small for shift of 64"
-	_ = i64 >> 64 // ERROR "i64 too small for shift of 64"
-	i64 <<= 64    // ERROR "i64 too small for shift of 64"
-	i64 >>= 64    // ERROR "i64 too small for shift of 64"
+	_ = i64 << 64 // ERROR "i64 .64 bits. too small for shift of 64"
+	_ = i64 >> 64 // ERROR "i64 .64 bits. too small for shift of 64"
+	i64 <<= 64    // ERROR "i64 .64 bits. too small for shift of 64"
+	i64 >>= 64    // ERROR "i64 .64 bits. too small for shift of 64"
 	var u8 uint8
 	_ = u8 << 7
-	_ = u8 << 8 // ERROR "u8 too small for shift of 8"
-	_ = u8 >> 8 // ERROR "u8 too small for shift of 8"
-	u8 <<= 8    // ERROR "u8 too small for shift of 8"
-	u8 >>= 8    // ERROR "u8 too small for shift of 8"
+	_ = u8 << 8 // ERROR "u8 .8 bits. too small for shift of 8"
+	_ = u8 >> 8 // ERROR "u8 .8 bits. too small for shift of 8"
+	u8 <<= 8    // ERROR "u8 .8 bits. too small for shift of 8"
+	u8 >>= 8    // ERROR "u8 .8 bits. too small for shift of 8"
 	var u16 uint16
 	_ = u16 << 15
-	_ = u16 << 16 // ERROR "u16 too small for shift of 16"
-	_ = u16 >> 16 // ERROR "u16 too small for shift of 16"
-	u16 <<= 16    // ERROR "u16 too small for shift of 16"
-	u16 >>= 16    // ERROR "u16 too small for shift of 16"
+	_ = u16 << 16 // ERROR "u16 .16 bits. too small for shift of 16"
+	_ = u16 >> 16 // ERROR "u16 .16 bits. too small for shift of 16"
+	u16 <<= 16    // ERROR "u16 .16 bits. too small for shift of 16"
+	u16 >>= 16    // ERROR "u16 .16 bits. too small for shift of 16"
 	var u32 uint32
 	_ = u32 << 31
-	_ = u32 << 32 // ERROR "u32 too small for shift of 32"
-	_ = u32 >> 32 // ERROR "u32 too small for shift of 32"
-	u32 <<= 32    // ERROR "u32 too small for shift of 32"
-	u32 >>= 32    // ERROR "u32 too small for shift of 32"
+	_ = u32 << 32 // ERROR "u32 .32 bits. too small for shift of 32"
+	_ = u32 >> 32 // ERROR "u32 .32 bits. too small for shift of 32"
+	u32 <<= 32    // ERROR "u32 .32 bits. too small for shift of 32"
+	u32 >>= 32    // ERROR "u32 .32 bits. too small for shift of 32"
 	var u64 uint64
 	_ = u64 << 63
-	_ = u64 << 64  // ERROR "u64 too small for shift of 64"
-	_ = u64 >> 64  // ERROR "u64 too small for shift of 64"
-	u64 <<= 64     // ERROR "u64 too small for shift of 64"
-	u64 >>= 64     // ERROR "u64 too small for shift of 64"
+	_ = u64 << 64  // ERROR "u64 .64 bits. too small for shift of 64"
+	_ = u64 >> 64  // ERROR "u64 .64 bits. too small for shift of 64"
+	u64 <<= 64     // ERROR "u64 .64 bits. too small for shift of 64"
+	u64 >>= 64     // ERROR "u64 .64 bits. too small for shift of 64"
 	_ = u64 << u64 // Non-constant shifts should succeed.
+
 	var i int
 	_ = i << 31
-	_ = i << 32 // ERROR "i might be too small for shift of 32"
-	_ = i >> 32 // ERROR "i might be too small for shift of 32"
-	i <<= 32    // ERROR "i might be too small for shift of 32"
-	i >>= 32    // ERROR "i might be too small for shift of 32"
+	const in = 8 * unsafe.Sizeof(i)
+	_ = i << in // ERROR "too small for shift"
+	_ = i >> in // ERROR "too small for shift"
+	i <<= in    // ERROR "too small for shift"
+	i >>= in    // ERROR "too small for shift"
+	const ix = 8*unsafe.Sizeof(i) - 1
+	_ = i << ix
+	_ = i >> ix
+	i <<= ix
+	i >>= ix
+
 	var u uint
 	_ = u << 31
-	_ = u << 32 // ERROR "u might be too small for shift of 32"
-	_ = u >> 32 // ERROR "u might be too small for shift of 32"
-	u <<= 32    // ERROR "u might be too small for shift of 32"
-	u >>= 32    // ERROR "u might be too small for shift of 32"
+	const un = 8 * unsafe.Sizeof(u)
+	_ = u << un // ERROR "too small for shift"
+	_ = u >> un // ERROR "too small for shift"
+	u <<= un    // ERROR "too small for shift"
+	u >>= un    // ERROR "too small for shift"
+	const ux = 8*unsafe.Sizeof(u) - 1
+	_ = u << ux
+	_ = u >> ux
+	u <<= ux
+	u >>= ux
+
 	var p uintptr
 	_ = p << 31
-	_ = p << 32 // ERROR "p might be too small for shift of 32"
-	_ = p >> 32 // ERROR "p might be too small for shift of 32"
-	p <<= 32    // ERROR "p might be too small for shift of 32"
-	p >>= 32    // ERROR "p might be too small for shift of 32"
+	const pn = 8 * unsafe.Sizeof(p)
+	_ = p << pn // ERROR "too small for shift"
+	_ = p >> pn // ERROR "too small for shift"
+	p <<= pn    // ERROR "too small for shift"
+	p >>= pn    // ERROR "too small for shift"
+	const px = 8*unsafe.Sizeof(p) - 1
+	_ = p << px
+	_ = p >> px
+	p <<= px
+	p >>= px
 
 	const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks
+
+	var h uintptr
+	h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
+	h <<= 8 * unsafe.Sizeof(h) // ERROR "too small for shift"
+	h >>= 7 * unsafe.Alignof(h)
+	h >>= 8 * unsafe.Alignof(h) // ERROR "too small for shift"
+}
+
+func ShiftDeadCode() {
+	var i int
+	const iBits = 8 * unsafe.Sizeof(i)
+
+	if iBits <= 32 {
+		if iBits == 16 {
+			_ = i >> 8
+		} else {
+			_ = i >> 16
+		}
+	} else {
+		_ = i >> 32
+	}
+
+	if iBits >= 64 {
+		_ = i << 32
+		if iBits == 128 {
+			_ = i << 64
+		}
+	} else {
+		_ = i << 16
+	}
+
+	if iBits == 64 {
+		_ = i << 32
+	}
+
+	switch iBits {
+	case 128, 64:
+		_ = i << 32
+	default:
+		_ = i << 16
+	}
+
+	switch {
+	case iBits < 32:
+		_ = i << 16
+	case iBits > 64:
+		_ = i << 64
+	default:
+		_ = i << 64 // ERROR "too small for shift"
+	}
+
+	// Make sure other vet checks work in dead code.
+	if iBits == 1024 {
+		_ = i << 512                  // OK
+		fmt.Printf("foo %s bar", 123) // ERROR "arg 123 for printf verb %s of wrong type: untyped int"
+	}
 }
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 8357d3c..77bd1c1 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -8,32 +8,39 @@ package main
 
 import (
 	"go/ast"
+	"go/build"
 	"go/importer"
 	"go/token"
 	"go/types"
 )
 
 // stdImporter is the importer we use to import packages.
-// It is created during initialization so that all packages
-// are imported by the same importer.
-var stdImporter = importer.Default()
+// It is shared so that all packages are imported by the same importer.
+var stdImporter types.Importer
 
 var (
-	errorType     *types.Interface
-	stringerType  *types.Interface // possibly nil
-	formatterType *types.Interface // possibly nil
+	errorType        *types.Interface
+	stringerType     *types.Interface // possibly nil
+	formatterType    *types.Interface // possibly nil
+	httpResponseType types.Type       // possibly nil
+	httpClientType   types.Type       // possibly nil
 )
 
-func init() {
+func inittypes() {
 	errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
 
 	if typ := importType("fmt", "Stringer"); typ != nil {
 		stringerType = typ.Underlying().(*types.Interface)
 	}
-
 	if typ := importType("fmt", "Formatter"); typ != nil {
 		formatterType = typ.Underlying().(*types.Interface)
 	}
+	if typ := importType("net/http", "Response"); typ != nil {
+		httpResponseType = typ
+	}
+	if typ := importType("net/http", "Client"); typ != nil {
+		httpClientType = typ
+	}
 }
 
 // importType returns the type denoted by the qualified identifier
@@ -54,6 +61,14 @@ func importType(path, name string) types.Type {
 }
 
 func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+	if stdImporter == nil {
+		if *source {
+			stdImporter = importer.For("source", nil)
+		} else {
+			stdImporter = importer.Default()
+		}
+		inittypes()
+	}
 	pkg.defs = make(map[*ast.Ident]types.Object)
 	pkg.uses = make(map[*ast.Ident]types.Object)
 	pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
@@ -66,6 +81,8 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
 		// By providing a Config with our own error function, it will continue
 		// past the first error. There is no need for that function to do anything.
 		Error: func(error) {},
+
+		Sizes: archSizes,
 	}
 	info := &types.Info{
 		Selections: pkg.selectors,
@@ -275,3 +292,5 @@ func (f *File) hasMethod(typ types.Type, name string) bool {
 	_, ok := obj.(*types.Func)
 	return ok
 }
+
+var archSizes = types.SizesFor("gc", build.Default.GOARCH)
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index 95fb189..a6c3080 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -204,6 +204,12 @@ func TestMTF(t *testing.T) {
 	}
 }
 
+var (
+	digits = mustLoadFile("testdata/e.txt.bz2")
+	twain  = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
+	random = mustLoadFile("testdata/random.data.bz2")
+)
+
 func benchmarkDecode(b *testing.B, compressed []byte) {
 	// Determine the uncompressed size of testfile.
 	uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
@@ -221,18 +227,6 @@ func benchmarkDecode(b *testing.B, compressed []byte) {
 	}
 }
 
-func BenchmarkDecodeDigits(b *testing.B) {
-	digits := mustLoadFile("testdata/e.txt.bz2")
-	b.ResetTimer()
-	benchmarkDecode(b, digits)
-}
-func BenchmarkDecodeTwain(b *testing.B) {
-	twain := mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
-	b.ResetTimer()
-	benchmarkDecode(b, twain)
-}
-func BenchmarkDecodeRand(b *testing.B) {
-	random := mustLoadFile("testdata/random.data.bz2")
-	b.ResetTimer()
-	benchmarkDecode(b, random)
-}
+func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
+func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
+func BenchmarkDecodeRand(b *testing.B)   { benchmarkDecode(b, random) }
diff --git a/src/compress/bzip2/huffman.go b/src/compress/bzip2/huffman.go
index 9d574b9..dbba9a5 100644
--- a/src/compress/bzip2/huffman.go
+++ b/src/compress/bzip2/huffman.go
@@ -108,10 +108,6 @@ func newHuffmanTree(lengths []uint8) (huffmanTree, error) {
 	codes := huffmanCodes(make([]huffmanCode, len(lengths)))
 	for i := len(pairs) - 1; i >= 0; i-- {
 		if length > pairs[i].length {
-			// If the code length decreases we shift in order to
-			// zero any bits beyond the end of the code.
-			length >>= 32 - pairs[i].length
-			length <<= 32 - pairs[i].length
 			length = pairs[i].length
 		}
 		codes[i].code = code
diff --git a/src/compress/flate/huffman_code.go b/src/compress/flate/huffman_code.go
index bdcbd82..891537e 100644
--- a/src/compress/flate/huffman_code.go
+++ b/src/compress/flate/huffman_code.go
@@ -6,6 +6,7 @@ package flate
 
 import (
 	"math"
+	"math/bits"
 	"sort"
 )
 
@@ -342,3 +343,7 @@ func (s byFreq) Less(i, j int) bool {
 }
 
 func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+	return bits.Reverse16(number << (16 - bitLength))
+}
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 9a8c4fc..faa33cc 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -10,6 +10,7 @@ package flate
 import (
 	"bufio"
 	"io"
+	mathbits "math/bits"
 	"strconv"
 	"sync"
 )
@@ -176,7 +177,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		link := nextcode[huffmanChunkBits+1] >> 1
 		h.links = make([][]uint32, huffmanNumChunks-link)
 		for j := uint(link); j < huffmanNumChunks; j++ {
-			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+			reverse := int(mathbits.Reverse16(uint16(j)))
 			reverse >>= uint(16 - huffmanChunkBits)
 			off := j - uint(link)
 			if sanity && h.chunks[reverse] != 0 {
@@ -194,7 +195,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		code := nextcode[n]
 		nextcode[n]++
 		chunk := uint32(i<<huffmanValueShift | n)
-		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
+		reverse := int(mathbits.Reverse16(uint16(code)))
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
 			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
@@ -556,7 +557,7 @@ readLiteral:
 					return
 				}
 			}
-			dist = int(reverseByte[(f.b&0x1F)<<3])
+			dist = int(mathbits.Reverse8(uint8(f.b & 0x1F << 3)))
 			f.b >>= 5
 			f.nb -= 5
 		} else {
diff --git a/src/compress/flate/reverse_bits.go b/src/compress/flate/reverse_bits.go
deleted file mode 100644
index 6b22290..0000000
--- a/src/compress/flate/reverse_bits.go
+++ /dev/null
@@ -1,48 +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 flate
-
-var reverseByte = [256]byte{
-	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
-	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
-	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
-	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
-	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
-	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
-	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
-	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
-	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
-	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
-	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
-	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
-	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
-	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
-	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
-	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
-	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
-	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
-	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
-	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-}
-
-func reverseUint16(v uint16) uint16 {
-	return uint16(reverseByte[v>>8]) | uint16(reverseByte[v&0xFF])<<8
-}
-
-func reverseBits(number uint16, bitLength byte) uint16 {
-	return reverseUint16(number << (16 - bitLength))
-}
diff --git a/src/compress/gzip/gzip.go b/src/compress/gzip/gzip.go
index aafb442..0cc44c5 100644
--- a/src/compress/gzip/gzip.go
+++ b/src/compress/gzip/gzip.go
@@ -222,8 +222,9 @@ func (z *Writer) Flush() error {
 	return z.err
 }
 
-// Close closes the Writer, flushing any unwritten data to the underlying
-// io.Writer, but does not close the underlying io.Writer.
+// Close closes the Writer by flushing any unwritten data to the underlying
+// io.Writer and writing the GZIP footer.
+// It does not close the underlying io.Writer.
 func (z *Writer) Close() error {
 	if z.err != nil {
 		return z.err
diff --git a/src/compress/lzw/reader.go b/src/compress/lzw/reader.go
index 9eef2b2..1be52d5 100644
--- a/src/compress/lzw/reader.go
+++ b/src/compress/lzw/reader.go
@@ -57,8 +57,14 @@ type decoder struct {
 	// The next two codes mean clear and EOF.
 	// Other valid codes are in the range [lo, hi] where lo := clear + 2,
 	// with the upper bound incrementing on each code seen.
-	// overflow is the code at which hi overflows the code width.
+	//
+	// overflow is the code at which hi overflows the code width. It always
+	// equals 1 << width.
+	//
 	// last is the most recently seen code, or decoderInvalidCode.
+	//
+	// An invariant is that
+	// (hi < overflow) || (hi == overflow && last == decoderInvalidCode)
 	clear, eof, hi, overflow, last uint16
 
 	// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
@@ -163,7 +169,7 @@ loop:
 			break loop
 		case code <= d.hi:
 			c, i := code, len(d.output)-1
-			if code == d.hi {
+			if code == d.hi && d.last != decoderInvalidCode {
 				// code == hi is a special case which expands to the last expansion
 				// followed by the head of the last expansion. To find the head, we walk
 				// the prefix chain until we find a literal code.
@@ -196,6 +202,10 @@ loop:
 		if d.hi >= d.overflow {
 			if d.width == maxWidth {
 				d.last = decoderInvalidCode
+				// Undo the d.hi++ a few lines above, so that (1) we maintain
+				// the invariant that d.hi <= d.overflow, and (2) d.hi does not
+				// eventually overflow a uint16.
+				d.hi--
 			} else {
 				d.width++
 				d.overflow <<= 1
diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go
index 6b9f9a3..f8974de 100644
--- a/src/compress/lzw/reader_test.go
+++ b/src/compress/lzw/reader_test.go
@@ -120,6 +120,103 @@ func TestReader(t *testing.T) {
 	}
 }
 
+type devZero struct{}
+
+func (devZero) Read(p []byte) (int, error) {
+	for i := range p {
+		p[i] = 0
+	}
+	return len(p), nil
+}
+
+func TestHiCodeDoesNotOverflow(t *testing.T) {
+	r := NewReader(devZero{}, LSB, 8)
+	d := r.(*decoder)
+	buf := make([]byte, 1024)
+	oldHi := uint16(0)
+	for i := 0; i < 100; i++ {
+		if _, err := io.ReadFull(r, buf); err != nil {
+			t.Fatalf("i=%d: %v", i, err)
+		}
+		// The hi code should never decrease.
+		if d.hi < oldHi {
+			t.Fatalf("i=%d: hi=%d decreased from previous value %d", i, d.hi, oldHi)
+		}
+		oldHi = d.hi
+	}
+}
+
+// TestNoLongerSavingPriorExpansions tests the decoder state when codes other
+// than clear codes continue to be seen after decoder.hi and decoder.width
+// reach their maximum values (4095 and 12), i.e. after we no longer save prior
+// expansions. In particular, it tests seeing the highest possible code, 4095.
+func TestNoLongerSavingPriorExpansions(t *testing.T) {
+	// Iterations is used to calculate how many input bits are needed to get
+	// the decoder.hi and decoder.width values up to their maximum.
+	iterations := []struct {
+		width, n int
+	}{
+		// The final term is 257, not 256, as NewReader initializes d.hi to
+		// d.clear+1 and the clear code is 256.
+		{9, 512 - 257},
+		{10, 1024 - 512},
+		{11, 2048 - 1024},
+		{12, 4096 - 2048},
+	}
+	nCodes, nBits := 0, 0
+	for _, e := range iterations {
+		nCodes += e.n
+		nBits += e.n * e.width
+	}
+	if nCodes != 3839 {
+		t.Fatalf("nCodes: got %v, want %v", nCodes, 3839)
+	}
+	if nBits != 43255 {
+		t.Fatalf("nBits: got %v, want %v", nBits, 43255)
+	}
+
+	// Construct our input of 43255 zero bits (which gets d.hi and d.width up
+	// to 4095 and 12), followed by 0xfff (4095) as 12 bits, followed by 0x101
+	// (EOF) as 12 bits.
+	//
+	// 43255 = 5406*8 + 7, and codes are read in LSB order. The final bytes are
+	// therefore:
+	//
+	// xwwwwwww xxxxxxxx yyyyyxxx zyyyyyyy
+	// 10000000 11111111 00001111 00001000
+	//
+	// or split out:
+	//
+	// .0000000 ........ ........ ........   w = 0x000
+	// 1....... 11111111 .....111 ........   x = 0xfff
+	// ........ ........ 00001... .0001000   y = 0x101
+	//
+	// The 12 'w' bits (not all are shown) form the 3839'th code, with value
+	// 0x000. Just after decoder.read returns that code, d.hi == 4095 and
+	// d.last == 0.
+	//
+	// The 12 'x' bits form the 3840'th code, with value 0xfff or 4095. Just
+	// after decoder.read returns that code, d.hi == 4095 and d.last ==
+	// decoderInvalidCode.
+	//
+	// The 12 'y' bits form the 3841'st code, with value 0x101, the EOF code.
+	//
+	// The 'z' bit is unused.
+	in := make([]byte, 5406)
+	in = append(in, 0x80, 0xff, 0x0f, 0x08)
+
+	r := NewReader(bytes.NewReader(in), LSB, 8)
+	nDecoded, err := io.Copy(ioutil.Discard, r)
+	if err != nil {
+		t.Fatalf("Copy: %v", err)
+	}
+	// nDecoded should be 3841: 3839 literal codes and then 2 decoded bytes
+	// from 1 non-literal code. The EOF code contributes 0 decoded bytes.
+	if nDecoded != int64(nCodes+2) {
+		t.Fatalf("nDecoded: got %v, want %v", nDecoded, nCodes+2)
+	}
+}
+
 func BenchmarkDecoder(b *testing.B) {
 	buf, err := ioutil.ReadFile("../testdata/e.txt")
 	if err != nil {
diff --git a/src/container/heap/heap.go b/src/container/heap/heap.go
index 7110c51..b2c6427 100644
--- a/src/container/heap/heap.go
+++ b/src/container/heap/heap.go
@@ -72,8 +72,9 @@ func Remove(h Interface, i int) interface{} {
 	n := h.Len() - 1
 	if n != i {
 		h.Swap(i, n)
-		down(h, i, n)
-		up(h, i)
+		if !down(h, i, n) {
+			up(h, i)
+		}
 	}
 	return h.Pop()
 }
@@ -107,7 +108,7 @@ func down(h Interface, i0, n int) bool {
 			break
 		}
 		j := j1 // left child
-		if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
+		if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
 			j = j2 // = 2*i + 2  // right child
 		}
 		if !h.Less(j, i) {
diff --git a/src/context/context.go b/src/context/context.go
index 0aa7c24..892ff27 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -96,10 +96,11 @@ type Context interface {
 	// 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.
+	// If Done is not yet closed, Err returns nil.
+	// If Done is closed, Err returns a non-nil error explaining why:
+	// Canceled if the context was canceled
+	// or DeadlineExceeded if the context's deadline passed.
+	// After Err returns a non-nil error, successive calls to Err return the same error.
 	Err() error
 
 	// Value returns the value associated with this context for key, or nil
@@ -234,10 +235,7 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
 
 // newCancelCtx returns an initialized cancelCtx.
 func newCancelCtx(parent Context) cancelCtx {
-	return cancelCtx{
-		Context: parent,
-		done:    make(chan struct{}),
-	}
+	return cancelCtx{Context: parent}
 }
 
 // propagateCancel arranges for child to be canceled when parent is.
@@ -306,20 +304,32 @@ type canceler interface {
 	Done() <-chan struct{}
 }
 
+// closedchan is a reusable closed channel.
+var closedchan = make(chan struct{})
+
+func init() {
+	close(closedchan)
+}
+
 // 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
+	mu       sync.Mutex            // protects following fields
+	done     chan struct{}         // created lazily, closed by first cancel call
 	children map[canceler]struct{} // 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
+	c.mu.Lock()
+	if c.done == nil {
+		c.done = make(chan struct{})
+	}
+	d := c.done
+	c.mu.Unlock()
+	return d
 }
 
 func (c *cancelCtx) Err() error {
@@ -344,7 +354,11 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
 		return // already canceled
 	}
 	c.err = err
-	close(c.done)
+	if c.done == nil {
+		c.done = closedchan
+	} else {
+		close(c.done)
+	}
 	for child := range c.children {
 		// NOTE: acquiring the child's lock while holding parent's lock.
 		child.cancel(false, err)
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 6efc06c..f73f283 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -428,7 +428,7 @@ func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(
 		limit := test.limit
 		if runtime.Compiler == "gccgo" {
 			// gccgo does not yet do escape analysis.
-			// TOOD(iant): Remove this when gccgo does do escape analysis.
+			// TODO(iant): Remove this when gccgo does do escape analysis.
 			limit = test.gccgoLimit
 		}
 		numRuns := 100
diff --git a/src/crypto/aes/asm_ppc64le.s b/src/crypto/aes/asm_ppc64le.s
new file mode 100644
index 0000000..05e0018
--- /dev/null
+++ b/src/crypto/aes/asm_ppc64le.s
@@ -0,0 +1,499 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a derived work from OpenSSL of AES using assembly optimizations. The
+// original code was written by Andy Polyakov <appro at openssl.org> and it's dual
+// licensed under OpenSSL and CRYPTOGAMS licenses depending on where you obtain
+// it. For further details see http://www.openssl.org/~appro/cryptogams/.
+
+// Original code can be found at the link below:
+// https://git.openssl.org/?p=openssl.git;a=blob;f=crypto/aes/asm/aesp8-ppc.pl
+
+// The code is based on 627c953376 from 4 Jun 2016. I changed some function
+// names in order to be more likely to go standards. For instance, function
+// aes_p8_set_{en,de}crypt_key become set{En,De}cryptKeyAsm. I also split
+// setEncryptKeyAsm in two parts and a new session was created
+// (doEncryptKeyAsm). This was necessary to avoid arguments overwriting when
+// setDecryptKeyAsm calls setEncryptKeyAsm. There were other modifications as
+// well but kept the same functionality.
+
+#include "textflag.h"
+
+// For set{En,De}cryptKeyAsm
+#define INP     R3
+#define BITS    R4
+#define OUT     R5
+#define PTR     R6
+#define CNT     R7
+#define ROUNDS  R8
+#define TEMP    R19
+#define ZERO    V0
+#define IN0     V1
+#define IN1     V2
+#define KEY     V3
+#define RCON    V4
+#define MASK    V5
+#define TMP     V6
+#define STAGE   V7
+#define OUTPERM V8
+#define OUTMASK V9
+#define OUTHEAD V10
+#define OUTTAIL V11
+
+// For {en,de}cryptBlockAsm
+#define BLK_INP    R3
+#define BLK_OUT    R4
+#define BLK_KEY    R5
+#define BLK_ROUNDS R6
+#define BLK_IDX    R7
+
+DATA  ·rcon+0x00(SB)/8, $0x0100000001000000 // RCON
+DATA  ·rcon+0x08(SB)/8, $0x0100000001000000 // RCON
+DATA  ·rcon+0x10(SB)/8, $0x1b0000001b000000
+DATA  ·rcon+0x18(SB)/8, $0x1b0000001b000000
+DATA  ·rcon+0x20(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK
+DATA  ·rcon+0x28(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK
+DATA  ·rcon+0x30(SB)/8, $0x0000000000000000
+DATA  ·rcon+0x38(SB)/8, $0x0000000000000000
+GLOBL ·rcon(SB), RODATA, $64
+
+// func setEncryptKeyAsm(key *byte, keylen int, enc *uint32) int
+TEXT ·setEncryptKeyAsm(SB),NOSPLIT|NOFRAME,$0
+	// Load the arguments inside the registers
+	MOVD key+0(FP), INP
+	MOVD keylen+8(FP), BITS
+	MOVD enc+16(FP), OUT
+	JMP ·doEncryptKeyAsm(SB)
+
+// This text is used both setEncryptKeyAsm and setDecryptKeyAsm
+TEXT ·doEncryptKeyAsm(SB),NOSPLIT|NOFRAME,$0
+	// Do not change R10 since it's storing the LR value in setDecryptKeyAsm
+
+	// Check arguments
+	MOVD $-1, PTR                  // li    6,-1       exit code to -1 (255)
+	CMPU INP, $0                   // cmpldi r3,0      input key pointer set?
+	BC 0x0E, 2, enc_key_abort      // beq-  .Lenc_key_abort
+	CMPU OUT, $0                   // cmpldi r5,0      output key pointer set?
+	BC 0x0E, 2, enc_key_abort      // beq-  .Lenc_key_abort
+	MOVD $-2, PTR                  // li    6,-2       exit code to -2 (254)
+	CMPW BITS, $128                // cmpwi 4,128      greater or equal to 128
+	BC 0x0E, 0, enc_key_abort      // blt-  .Lenc_key_abort
+	CMPW BITS, $256                // cmpwi 4,256      lesser or equal to 256
+	BC 0x0E, 1, enc_key_abort      // bgt-  .Lenc_key_abort
+	ANDCC $0x3f, BITS, TEMP        // andi. 0,4,0x3f   multiple of 64
+	BC 0x06, 2, enc_key_abort      // bne-  .Lenc_key_abort
+
+	MOVD $·rcon(SB), PTR           // PTR point to rcon addr
+
+	// Get key from memory and write aligned into VR
+	NEG INP, R9                    // neg   9,3        R9 is ~INP + 1
+	LVX (INP)(R0), IN0             // lvx   1,0,3      Load key inside IN0
+	ADD $15, INP, INP              // addi  3,3,15     Add 15B to INP addr
+	LVSR (R9)(R0), KEY             // lvsr  3,0,9
+	MOVD $0x20, R8                 // li    8,0x20     R8 = 32
+	CMPW BITS, $192                // cmpwi 4,192      Key size == 192?
+	LVX (INP)(R0), IN1             // lvx   2,0,3
+	VSPLTISB $0x0f, MASK           // vspltisb 5,0x0f  0x0f0f0f0f... mask
+	LVX (PTR)(R0), RCON            // lvx   4,0,6      Load first 16 bytes into RCON
+	VXOR KEY, MASK, KEY            // vxor  3,3,5      Adjust for byte swap
+	LVX (PTR)(R8), MASK            // lvx   5,8,6
+	ADD $0x10, PTR, PTR            // addi  6,6,0x10   PTR to next 16 bytes of RCON
+	VPERM IN0, IN1, KEY, IN0       // vperm 1,1,2,3    Align
+	MOVD $8, CNT                   // li    7,8        CNT = 8
+	VXOR ZERO, ZERO, ZERO          // vxor  0,0,0      Zero to be zero :)
+	MOVD CNT, CTR                  // mtctr 7          Set the counter to 8 (rounds)
+
+	LVSL (OUT)(R0), OUTPERM        // lvsl  8,0,5
+	VSPLTISB $-1, OUTMASK          // vspltisb      9,-1
+	LVX (OUT)(R0), OUTHEAD         // lvx   10,0,5
+	VPERM OUTMASK, ZERO, OUTPERM, OUTMASK  // vperm 9,9,0,8
+
+	BLT loop128                    // blt   .Loop128
+	ADD $8, INP, INP               // addi  3,3,8
+	BEQ l192                       // beq   .L192
+	ADD $8, INP, INP               // addi  3,3,8
+	JMP l256                       // b     .L256
+
+loop128:
+	// Key schedule (Round 1 to 8)
+	VPERM IN0, IN0, MASK, KEY      // vperm 3,1,1,5         Rotate-n-splat
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8    Rotate
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5        Write to output
+	ADD $16, OUT, OUT              // addi 5,5,16       Point to the next round
+
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VADDUWM RCON, RCON, RCON       // vadduwm 4,4,4
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+	BC 0x10, 0, loop128            // bdnz .Loop128
+
+	LVX (PTR)(R0), RCON            // lvx 4,0,6     Last two round keys
+
+	// Key schedule (Round 9)
+	VPERM IN0, IN0, MASK, KEY      // vperm 3,1,1,5   Rotate-n-spat
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8  Rotate
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5   Round 9
+	ADD $16, OUT, OUT              // addi 5,5,16
+
+	// Key schedule (Round 10)
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VADDUWM RCON, RCON, RCON       // vadduwm 4,4,4
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+
+	VPERM IN0, IN0, MASK, KEY      // vperm 3,1,1,5   Rotate-n-splat
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8  Rotate
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5    Round 10
+	ADD $16, OUT, OUT              // addi 5,5,16
+
+	// Key schedule (Round 11)
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5  Round 11
+
+	ADD $15, OUT, INP              // addi  3,5,15
+	ADD $0x50, OUT, OUT            // addi  5,5,0x50
+
+	MOVD $10, ROUNDS               // li    8,10
+	JMP done                       // b     .Ldone
+
+l192:
+	LVX (INP)(R0), TMP             // lvx 6,0,3
+	MOVD $4, CNT                   // li 7,4
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $16, OUT, OUT              // addi 5,5,16
+	VPERM IN1, TMP, KEY, IN1       // vperm 2,2,6,3
+	VSPLTISB $8, KEY               // vspltisb 3,8
+	MOVD CNT, CTR                  // mtctr 7
+	VSUBUBM MASK, KEY, MASK        // vsububm 5,5,3
+
+loop192:
+	VPERM IN1, IN1, MASK, KEY      // vperm 3,2,2,5
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+
+	VSLDOI $8, ZERO, IN1, STAGE    // vsldoi 7,0,2,8
+	VSPLTW $3, IN0, TMP            // vspltw 6,1,3
+	VXOR TMP, IN1, TMP             // vxor 6,6,2
+	VSLDOI $12, ZERO, IN1, IN1     // vsldoi 2,0,2,12
+	VADDUWM RCON, RCON, RCON       // vadduwm 4,4,4
+	VXOR IN1, TMP, IN1             // vxor 2,2,6
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+	VXOR IN1, KEY, IN1             // vxor 2,2,3
+	VSLDOI $8, STAGE, IN0, STAGE   // vsldoi 7,7,1,8
+
+	VPERM IN1, IN1, MASK, KEY      // vperm 3,2,2,5
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VPERM STAGE, STAGE, OUTPERM, OUTTAIL // vperm 11,7,7,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $16, OUT, OUT              // addi 5,5,16
+
+	VSLDOI $8, IN0, IN1, STAGE     // vsldoi 7,1,2,8
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VPERM STAGE, STAGE, OUTPERM, OUTTAIL // vperm 11,7,7,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $16, OUT, OUT              // addi 5,5,16
+
+	VSPLTW $3, IN0, TMP            // vspltw 6,1,3
+	VXOR TMP, IN1, TMP             // vxor 6,6,2
+	VSLDOI $12, ZERO, IN1, IN1     // vsldoi 2,0,2,12
+	VADDUWM RCON, RCON, RCON       // vadduwm 4,4,4
+	VXOR IN1, TMP, IN1             // vxor 2,2,6
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+	VXOR IN1, KEY, IN1             // vxor 2,2,3
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $15, OUT, INP              // addi 3,5,15
+	ADD $16, OUT, OUT              // addi 5,5,16
+	BC 0x10, 0, loop192           // bdnz .Loop192
+
+	MOVD $12, ROUNDS               // li 8,12
+	ADD $0x20, OUT, OUT            // addi 5,5,0x20
+	JMP done                       // b .Ldone
+
+l256:
+	LVX (INP)(R0), TMP             // lvx 6,0,3
+	MOVD $7, CNT                   // li 7,7
+	MOVD $14, ROUNDS               // li 8,14
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $16, OUT, OUT              // addi 5,5,16
+	VPERM IN1, TMP, KEY, IN1       // vperm 2,2,6,3
+	MOVD CNT, CTR                  // mtctr 7
+
+loop256:
+	VPERM IN1, IN1, MASK, KEY      // vperm 3,2,2,5
+	VSLDOI $12, ZERO, IN0, TMP     // vsldoi 6,0,1,12
+	VPERM IN1, IN1, OUTPERM, OUTTAIL // vperm 11,2,2,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	VCIPHERLAST KEY, RCON, KEY     // vcipherlast 3,3,4
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $16, OUT, OUT              // addi 5,5,16
+
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN0, TMP, IN0             // vxor 1,1,6
+	VADDUWM RCON, RCON, RCON       // vadduwm 4,4,4
+	VXOR IN0, KEY, IN0             // vxor 1,1,3
+	VPERM IN0, IN0, OUTPERM, OUTTAIL // vperm 11,1,1,8
+	VSEL OUTHEAD, OUTTAIL, OUTMASK, STAGE // vsel 7,10,11,9
+	VOR OUTTAIL, OUTTAIL, OUTHEAD  // vor 10,11,11
+	STVX STAGE, (OUT+R0)           // stvx 7,0,5
+	ADD $15, OUT, INP              // addi 3,5,15
+	ADD $16, OUT, OUT              // addi 5,5,16
+	BC 0x12, 0, done               // bdz .Ldone
+
+	VSPLTW $3, IN0, KEY            // vspltw 3,1,3
+	VSLDOI $12, ZERO, IN1, TMP     // vsldoi 6,0,2,12
+	VSBOX KEY, KEY                 // vsbox 3,3
+
+	VXOR IN1, TMP, IN1             // vxor 2,2,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN1, TMP, IN1             // vxor 2,2,6
+	VSLDOI $12, ZERO, TMP, TMP     // vsldoi 6,0,6,12
+	VXOR IN1, TMP, IN1             // vxor 2,2,6
+
+	VXOR IN1, KEY, IN1             // vxor 2,2,3
+	JMP loop256                    // b .Loop256
+
+done:
+	LVX (INP)(R0), IN1             // lvx   2,0,3
+	VSEL OUTHEAD, IN1, OUTMASK, IN1 // vsel 2,10,2,9
+	STVX IN1, (INP+R0)             // stvx  2,0,3
+	MOVD $0, PTR                   // li    6,0    set PTR to 0 (exit code 0)
+	MOVW ROUNDS, 0(OUT)            // stw   8,0(5)
+
+enc_key_abort:
+	MOVD PTR, INP                  // mr    3,6    set exit code with PTR value
+	MOVD INP, ret+24(FP)           // Put return value into the FP
+	RET                            // blr
+
+// func setDecryptKeyAsm(key *byte, keylen int, dec *uint32) int
+TEXT ·setDecryptKeyAsm(SB),NOSPLIT|NOFRAME,$0
+	// Load the arguments inside the registers
+	MOVD key+0(FP), INP
+	MOVD keylen+8(FP), BITS
+	MOVD dec+16(FP), OUT
+
+	MOVD LR, R10                   // mflr 10
+	CALL ·doEncryptKeyAsm(SB)
+	MOVD R10, LR                   // mtlr 10
+
+	CMPW INP, $0                   // cmpwi 3,0  exit 0 = ok
+	BC 0x06, 2, dec_key_abort      // bne- .Ldec_key_abort
+
+	// doEncryptKeyAsm set ROUNDS (R8) with the proper value for each mode
+	SLW $4, ROUNDS, CNT            // slwi 7,8,4
+	SUB $240, OUT, INP             // subi 3,5,240
+	SRW $1, ROUNDS, ROUNDS         // srwi 8,8,1
+	ADD R7, INP, OUT               // add 5,3,7
+	MOVD ROUNDS, CTR               // mtctr 8
+
+// dec_key will invert the key sequence in order to be used for decrypt
+dec_key:
+	MOVWZ 0(INP), TEMP             // lwz 0, 0(3)
+	MOVWZ 4(INP), R6               // lwz 6, 4(3)
+	MOVWZ 8(INP), R7               // lwz 7, 8(3)
+	MOVWZ 12(INP), R8              // lwz 8, 12(3)
+	ADD $16, INP, INP              // addi 3,3,16
+	MOVWZ 0(OUT), R9               // lwz 9, 0(5)
+	MOVWZ 4(OUT), R10              // lwz 10,4(5)
+	MOVWZ 8(OUT), R11              // lwz 11,8(5)
+	MOVWZ 12(OUT), R12             // lwz 12,12(5)
+	MOVW TEMP, 0(OUT)              // stw 0, 0(5)
+	MOVW R6, 4(OUT)                // stw 6, 4(5)
+	MOVW R7, 8(OUT)                // stw 7, 8(5)
+	MOVW R8, 12(OUT)               // stw 8, 12(5)
+	SUB $16, OUT, OUT              // subi 5,5,16
+	MOVW R9, -16(INP)              // stw 9, -16(3)
+	MOVW R10, -12(INP)             // stw 10,-12(3)
+	MOVW R11, -8(INP)              // stw 11,-8(3)
+	MOVW R12, -4(INP)              // stw 12,-4(3)
+	BC 0x10, 0, dec_key            // bdnz .Ldeckey
+
+	XOR R3, R3, R3                 // xor 3,3,3      Clean R3
+
+dec_key_abort:
+	MOVD R3, ret+24(FP)            // Put return value into the FP
+	RET                            // blr
+
+
+// func encryptBlockAsm(dst, src *byte, enc *uint32)
+TEXT ·encryptBlockAsm(SB),NOSPLIT|NOFRAME,$0
+	// Load the arguments inside the registers
+	MOVD dst+0(FP), BLK_OUT
+	MOVD src+8(FP), BLK_INP
+	MOVD enc+16(FP), BLK_KEY
+
+	MOVWZ 240(BLK_KEY), BLK_ROUNDS // lwz 6,240(5)
+	MOVD $15, BLK_IDX              // li 7,15
+
+	LVX (BLK_INP)(R0), ZERO        // lvx 0,0,3
+	NEG BLK_OUT, R11               // neg 11,4
+	LVX (BLK_INP)(BLK_IDX), IN0    // lvx 1,7,3
+	LVSL (BLK_INP)(R0), IN1        // lvsl 2,0,3
+	VSPLTISB $0x0f, RCON           // vspltisb 4,0x0f
+	LVSR (R11)(R0), KEY            // lvsr 3,0,11
+	VXOR IN1, RCON, IN1            // vxor 2,2,4
+	MOVD $16, BLK_IDX              // li 7,16
+	VPERM ZERO, IN0, IN1, ZERO     // vperm 0,0,1,2
+	LVX (BLK_KEY)(R0), IN0         // lvx 1,0,5
+	LVSR (BLK_KEY)(R0), MASK       // lvsr 5,0,5
+	SRW $1, BLK_ROUNDS, BLK_ROUNDS // srwi 6,6,1
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	SUB $1, BLK_ROUNDS, BLK_ROUNDS // subi 6,6,1
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+
+	VXOR ZERO, IN0, ZERO           // vxor 0,0,1
+	LVX (BLK_KEY)(BLK_IDX), IN0    // lvx 1,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	MOVD BLK_ROUNDS, CTR           // mtctr 6
+
+loop_enc:
+	VPERM IN0, IN1, MASK, IN1      // vperm 2,1,2,5
+	VCIPHER ZERO, IN1, ZERO        // vcipher 0,0,2
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+	VCIPHER ZERO, IN0, ZERO        // vcipher 0,0,1
+	LVX (BLK_KEY)(BLK_IDX), IN0    // lvx 1,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	BC 0x10, 0, loop_enc           // bdnz .Loop_enc
+
+	VPERM IN0, IN1, MASK, IN1      // vperm 2,1,2,5
+	VCIPHER ZERO, IN1, ZERO        // vcipher 0,0,2
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+	VCIPHERLAST ZERO, IN0, ZERO    // vcipherlast 0,0,1
+
+	VSPLTISB $-1, IN1              // vspltisb 2,-1
+	VXOR IN0, IN0, IN0             // vxor 1,1,1
+	MOVD $15, BLK_IDX              // li 7,15
+	VPERM IN1, IN0, KEY, IN1       // vperm 2,2,1,3
+	VXOR KEY, RCON, KEY            // vxor 3,3,4
+	LVX (BLK_OUT)(R0), IN0         // lvx 1,0,4
+	VPERM ZERO, ZERO, KEY, ZERO    // vperm 0,0,0,3
+	VSEL IN0, ZERO, IN1, IN0       // vsel 1,1,0,2
+	LVX (BLK_OUT)(BLK_IDX), RCON   // lvx 4,7,4
+	STVX IN0, (BLK_OUT+R0)         // stvx 1,0,4
+	VSEL ZERO, RCON, IN1, ZERO     // vsel 0,0,4,2
+	STVX ZERO, (BLK_OUT+BLK_IDX)   // stvx 0,7,4
+
+	RET                            // blr
+
+
+// func decryptBlockAsm(dst, src *byte, dec *uint32)
+TEXT ·decryptBlockAsm(SB),NOSPLIT|NOFRAME,$0
+	// Load the arguments inside the registers
+	MOVD dst+0(FP), BLK_OUT
+	MOVD src+8(FP), BLK_INP
+	MOVD dec+16(FP), BLK_KEY
+
+	MOVWZ 240(BLK_KEY), BLK_ROUNDS // lwz 6,240(5)
+	MOVD $15, BLK_IDX              // li 7,15
+
+	LVX (BLK_INP)(R0), ZERO        // lvx 0,0,3
+	NEG BLK_OUT, R11               // neg 11,4
+	LVX (BLK_INP)(BLK_IDX), IN0    // lvx 1,7,3
+	LVSL (BLK_INP)(R0), IN1        // lvsl 2,0,3
+	VSPLTISB $0x0f, RCON           // vspltisb 4,0x0f
+	LVSR (R11)(R0), KEY            // lvsr 3,0,11
+	VXOR IN1, RCON, IN1            // vxor 2,2,4
+	MOVD $16, BLK_IDX              // li 7,16
+	VPERM ZERO, IN0, IN1, ZERO     // vperm 0,0,1,2
+	LVX (BLK_KEY)(R0), IN0         // lvx 1,0,5
+	LVSR (BLK_KEY)(R0), MASK       // lvsr 5,0,5
+	SRW $1, BLK_ROUNDS, BLK_ROUNDS // srwi 6,6,1
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	SUB $1, BLK_ROUNDS, BLK_ROUNDS // subi 6,6,1
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+
+	VXOR ZERO, IN0, ZERO           // vxor 0,0,1
+	LVX (BLK_KEY)(BLK_IDX), IN0    // lvx 1,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	MOVD BLK_ROUNDS, CTR           // mtctr 6
+
+loop_dec:
+	VPERM IN0, IN1, MASK, IN1      // vperm 2,1,2,5
+	VNCIPHER ZERO, IN1, ZERO       // vncipher 0,0,2
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+	VNCIPHER ZERO, IN0, ZERO       // vncipher 0,0,1
+	LVX (BLK_KEY)(BLK_IDX), IN0    // lvx 1,7,5
+	ADD $16, BLK_IDX, BLK_IDX      // addi 7,7,16
+	BC 0x10, 0, loop_dec           // bdnz .Loop_dec
+
+	VPERM IN0, IN1, MASK, IN1      // vperm 2,1,2,5
+	VNCIPHER ZERO, IN1, ZERO       // vncipher 0,0,2
+	LVX (BLK_KEY)(BLK_IDX), IN1    // lvx 2,7,5
+	VPERM IN1, IN0, MASK, IN0      // vperm 1,2,1,5
+	VNCIPHERLAST ZERO, IN0, ZERO   // vncipherlast 0,0,1
+
+	VSPLTISB $-1, IN1              // vspltisb 2,-1
+	VXOR IN0, IN0, IN0             // vxor 1,1,1
+	MOVD $15, BLK_IDX              // li 7,15
+	VPERM IN1, IN0, KEY, IN1       // vperm 2,2,1,3
+	VXOR KEY, RCON, KEY            // vxor 3,3,4
+	LVX (BLK_OUT)(R0), IN0         // lvx 1,0,4
+	VPERM ZERO, ZERO, KEY, ZERO    // vperm 0,0,0,3
+	VSEL IN0, ZERO, IN1, IN0       // vsel 1,1,0,2
+	LVX (BLK_OUT)(BLK_IDX), RCON   // lvx 4,7,4
+	STVX IN0, (BLK_OUT+R0)         // stvx 1,0,4
+	VSEL ZERO, RCON, IN1, ZERO     // vsel 0,0,4,2
+	STVX ZERO, (BLK_OUT+BLK_IDX)   // stvx 0,7,4
+
+	RET                            // blr
diff --git a/src/crypto/aes/cipher_generic.go b/src/crypto/aes/cipher_generic.go
index f807034..ca74aa8 100644
--- a/src/crypto/aes/cipher_generic.go
+++ b/src/crypto/aes/cipher_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,!s390x
+// +build !amd64,!s390x,!ppc64le
 
 package aes
 
diff --git a/src/crypto/aes/cipher_ppc64le.go b/src/crypto/aes/cipher_ppc64le.go
new file mode 100644
index 0000000..4a564e9
--- /dev/null
+++ b/src/crypto/aes/cipher_ppc64le.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 aes
+
+import (
+	"crypto/cipher"
+)
+
+// defined in asm_ppc64le.s
+
+//go:noescape
+
+func setEncryptKeyAsm(key *byte, keylen int, enc *uint32) int
+
+//go:noescape
+
+func setDecryptKeyAsm(key *byte, keylen int, dec *uint32) int
+
+//go:noescape
+
+func doEncryptKeyAsm(key *byte, keylen int, dec *uint32) int
+
+//go:noescape
+
+func encryptBlockAsm(dst, src *byte, enc *uint32)
+
+//go:noescape
+
+func decryptBlockAsm(dst, src *byte, dec *uint32)
+
+type aesCipherAsm struct {
+	aesCipher
+}
+
+func newCipher(key []byte) (cipher.Block, error) {
+	n := 64 // size is fixed for all and round value is stored inside it too
+	c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
+	k := len(key)
+
+	ret := 0
+	ret += setEncryptKeyAsm(&key[0], k*8, &c.enc[0])
+	ret += setDecryptKeyAsm(&key[0], k*8, &c.dec[0])
+
+	if ret > 0 {
+		return nil, KeySizeError(k)
+	}
+
+	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(&dst[0], &src[0], &c.enc[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(&dst[0], &src[0], &c.dec[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) {
+	setEncryptKeyAsm(&key[0], len(key)*8, &enc[0])
+	setDecryptKeyAsm(&key[0], len(key)*8, &dec[0])
+}
diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go
index a80ebd3..b4d6cdc 100644
--- a/src/crypto/crypto.go
+++ b/src/crypto/crypto.go
@@ -21,40 +21,48 @@ func (h Hash) HashFunc() Hash {
 }
 
 const (
-	MD4        Hash = 1 + iota // import golang.org/x/crypto/md4
-	MD5                        // import crypto/md5
-	SHA1                       // import crypto/sha1
-	SHA224                     // import crypto/sha256
-	SHA256                     // import crypto/sha256
-	SHA384                     // import crypto/sha512
-	SHA512                     // import crypto/sha512
-	MD5SHA1                    // no implementation; MD5+SHA1 used for TLS RSA
-	RIPEMD160                  // import golang.org/x/crypto/ripemd160
-	SHA3_224                   // import golang.org/x/crypto/sha3
-	SHA3_256                   // import golang.org/x/crypto/sha3
-	SHA3_384                   // import golang.org/x/crypto/sha3
-	SHA3_512                   // import golang.org/x/crypto/sha3
-	SHA512_224                 // import crypto/sha512
-	SHA512_256                 // import crypto/sha512
+	MD4         Hash = 1 + iota // import golang.org/x/crypto/md4
+	MD5                         // import crypto/md5
+	SHA1                        // import crypto/sha1
+	SHA224                      // import crypto/sha256
+	SHA256                      // import crypto/sha256
+	SHA384                      // import crypto/sha512
+	SHA512                      // import crypto/sha512
+	MD5SHA1                     // no implementation; MD5+SHA1 used for TLS RSA
+	RIPEMD160                   // import golang.org/x/crypto/ripemd160
+	SHA3_224                    // import golang.org/x/crypto/sha3
+	SHA3_256                    // import golang.org/x/crypto/sha3
+	SHA3_384                    // import golang.org/x/crypto/sha3
+	SHA3_512                    // import golang.org/x/crypto/sha3
+	SHA512_224                  // import crypto/sha512
+	SHA512_256                  // import crypto/sha512
+	BLAKE2s_256                 // import golang.org/x/crypto/blake2s
+	BLAKE2b_256                 // import golang.org/x/crypto/blake2b
+	BLAKE2b_384                 // import golang.org/x/crypto/blake2b
+	BLAKE2b_512                 // import golang.org/x/crypto/blake2b
 	maxHash
 )
 
 var digestSizes = []uint8{
-	MD4:        16,
-	MD5:        16,
-	SHA1:       20,
-	SHA224:     28,
-	SHA256:     32,
-	SHA384:     48,
-	SHA512:     64,
-	SHA512_224: 28,
-	SHA512_256: 32,
-	SHA3_224:   28,
-	SHA3_256:   32,
-	SHA3_384:   48,
-	SHA3_512:   64,
-	MD5SHA1:    36,
-	RIPEMD160:  20,
+	MD4:         16,
+	MD5:         16,
+	SHA1:        20,
+	SHA224:      28,
+	SHA256:      32,
+	SHA384:      48,
+	SHA512:      64,
+	SHA512_224:  28,
+	SHA512_256:  32,
+	SHA3_224:    28,
+	SHA3_256:    32,
+	SHA3_384:    48,
+	SHA3_512:    64,
+	MD5SHA1:     36,
+	RIPEMD160:   20,
+	BLAKE2s_256: 32,
+	BLAKE2b_256: 32,
+	BLAKE2b_384: 48,
+	BLAKE2b_512: 64,
 }
 
 // Size returns the length, in bytes, of a digest resulting from the given hash
diff --git a/src/crypto/des/block.go b/src/crypto/des/block.go
index 99338d6..21e6d4e 100644
--- a/src/crypto/des/block.go
+++ b/src/crypto/des/block.go
@@ -4,25 +4,29 @@
 
 package des
 
-import (
-	"encoding/binary"
-)
+import "encoding/binary"
 
 func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
 	b := binary.BigEndian.Uint64(src)
 	b = permuteInitialBlock(b)
 	left, right := uint32(b>>32), uint32(b)
 
-	var subkey uint64
-	for i := 0; i < 16; i++ {
-		if decrypt {
-			subkey = subkeys[15-i]
-		} else {
-			subkey = subkeys[i]
-		}
+	left = (left << 1) | (left >> 31)
+	right = (right << 1) | (right >> 31)
 
-		left, right = right, left^feistel(right, subkey)
+	if decrypt {
+		for i := 0; i < 8; i++ {
+			left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)])
+		}
+	} else {
+		for i := 0; i < 8; i++ {
+			left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1])
+		}
 	}
+
+	left = (left << 31) | (left >> 1)
+	right = (right << 31) | (right >> 1)
+
 	// switch left & right and perform final permutation
 	preOutput := (uint64(right) << 32) | uint64(left)
 	binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
@@ -39,19 +43,34 @@ func decryptBlock(subkeys []uint64, dst, src []byte) {
 }
 
 // DES Feistel function
-func feistel(right uint32, key uint64) (result uint32) {
-	sBoxLocations := key ^ expandBlock(right)
-	var sBoxResult uint32
-	for i := uint8(0); i < 8; i++ {
-		sBoxLocation := uint8(sBoxLocations>>42) & 0x3f
-		sBoxLocations <<= 6
-		// row determined by 1st and 6th bit
-		// column is middle four bits
-		row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4)
-		column := (sBoxLocation >> 1) & 0xf
-		sBoxResult ^= feistelBox[i][16*row+column]
-	}
-	return sBoxResult
+func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) {
+	var t uint32
+
+	t = r ^ uint32(k0>>32)
+	l ^= feistelBox[7][t&0x3f] ^
+		feistelBox[5][(t>>8)&0x3f] ^
+		feistelBox[3][(t>>16)&0x3f] ^
+		feistelBox[1][(t>>24)&0x3f]
+
+	t = ((r << 28) | (r >> 4)) ^ uint32(k0)
+	l ^= feistelBox[6][(t)&0x3f] ^
+		feistelBox[4][(t>>8)&0x3f] ^
+		feistelBox[2][(t>>16)&0x3f] ^
+		feistelBox[0][(t>>24)&0x3f]
+
+	t = l ^ uint32(k1>>32)
+	r ^= feistelBox[7][t&0x3f] ^
+		feistelBox[5][(t>>8)&0x3f] ^
+		feistelBox[3][(t>>16)&0x3f] ^
+		feistelBox[1][(t>>24)&0x3f]
+
+	t = ((l << 28) | (l >> 4)) ^ uint32(k1)
+	r ^= feistelBox[6][(t)&0x3f] ^
+		feistelBox[4][(t>>8)&0x3f] ^
+		feistelBox[2][(t>>16)&0x3f] ^
+		feistelBox[0][(t>>24)&0x3f]
+
+	return l, r
 }
 
 // feistelBox[s][16*i+j] contains the output of permutationFunction
@@ -73,27 +92,22 @@ func init() {
 			for j := 0; j < 16; j++ {
 				f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
 				f = permuteBlock(f, permutationFunction[:])
-				feistelBox[s][16*i+j] = uint32(f)
+
+				// Row is determined by the 1st and 6th bit.
+				// Column is the middle four bits.
+				row := uint8(((i & 2) << 4) | i&1)
+				col := uint8(j << 1)
+				t := row | col
+
+				// The rotation was performed in the feistel rounds, being factored out and now mixed into the feistelBox.
+				f = (f << 1) | (f >> 31)
+
+				feistelBox[s][t] = uint32(f)
 			}
 		}
 	}
 }
 
-// expandBlock expands an input block of 32 bits,
-// producing an output block of 48 bits.
-func expandBlock(src uint32) (block uint64) {
-	// rotate the 5 highest bits to the right.
-	src = (src << 5) | (src >> 27)
-	for i := 0; i < 8; i++ {
-		block <<= 6
-		// take the 6 bits on the right
-		block |= uint64(src) & (1<<6 - 1)
-		// advance by 4 bits.
-		src = (src << 4) | (src >> 28)
-	}
-	return
-}
-
 // permuteInitialBlock is equivalent to the permutation defined
 // by initialPermutation.
 func permuteInitialBlock(block uint64) uint64 {
@@ -218,6 +232,24 @@ func (c *desCipher) generateSubkeys(keyBytes []byte) {
 		// combine halves to form 56-bit input to PC2
 		pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
 		// apply PC2 permutation to 7 byte input
-		c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:])
+		c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:]))
 	}
 }
+
+// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top.
+// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without
+// extra shifts/rotations for alignments.
+func unpack(x uint64) uint64 {
+	var result uint64
+
+	result = ((x>>(6*1))&0xff)<<(8*0) |
+		((x>>(6*3))&0xff)<<(8*1) |
+		((x>>(6*5))&0xff)<<(8*2) |
+		((x>>(6*7))&0xff)<<(8*3) |
+		((x>>(6*0))&0xff)<<(8*4) |
+		((x>>(6*2))&0xff)<<(8*5) |
+		((x>>(6*4))&0xff)<<(8*6) |
+		((x>>(6*6))&0xff)<<(8*7)
+
+	return result
+}
diff --git a/src/crypto/des/cipher.go b/src/crypto/des/cipher.go
index 2f929ca..46af5b0 100644
--- a/src/crypto/des/cipher.go
+++ b/src/crypto/des/cipher.go
@@ -6,6 +6,7 @@ package des
 
 import (
 	"crypto/cipher"
+	"encoding/binary"
 	"strconv"
 )
 
@@ -61,13 +62,51 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) {
 func (c *tripleDESCipher) BlockSize() int { return BlockSize }
 
 func (c *tripleDESCipher) Encrypt(dst, src []byte) {
-	c.cipher1.Encrypt(dst, src)
-	c.cipher2.Decrypt(dst, dst)
-	c.cipher3.Encrypt(dst, dst)
+	b := binary.BigEndian.Uint64(src)
+	b = permuteInitialBlock(b)
+	left, right := uint32(b>>32), uint32(b)
+
+	left = (left << 1) | (left >> 31)
+	right = (right << 1) | (right >> 31)
+
+	for i := 0; i < 8; i++ {
+		left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1])
+	}
+	for i := 0; i < 8; i++ {
+		right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)])
+	}
+	for i := 0; i < 8; i++ {
+		left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1])
+	}
+
+	left = (left << 31) | (left >> 1)
+	right = (right << 31) | (right >> 1)
+
+	preOutput := (uint64(right) << 32) | uint64(left)
+	binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
 }
 
 func (c *tripleDESCipher) Decrypt(dst, src []byte) {
-	c.cipher3.Decrypt(dst, src)
-	c.cipher2.Encrypt(dst, dst)
-	c.cipher1.Decrypt(dst, dst)
+	b := binary.BigEndian.Uint64(src)
+	b = permuteInitialBlock(b)
+	left, right := uint32(b>>32), uint32(b)
+
+	left = (left << 1) | (left >> 31)
+	right = (right << 1) | (right >> 31)
+
+	for i := 0; i < 8; i++ {
+		left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)])
+	}
+	for i := 0; i < 8; i++ {
+		right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1])
+	}
+	for i := 0; i < 8; i++ {
+		left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)])
+	}
+
+	left = (left << 31) | (left >> 1)
+	right = (right << 31) | (right >> 1)
+
+	preOutput := (uint64(right) << 32) | uint64(left)
+	binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
 }
diff --git a/src/crypto/des/const.go b/src/crypto/des/const.go
index 2bd485e..a20879d 100644
--- a/src/crypto/des/const.go
+++ b/src/crypto/des/const.go
@@ -5,6 +5,9 @@
 // Package des implements the Data Encryption Standard (DES) and the
 // Triple Data Encryption Algorithm (TDEA) as defined
 // in U.S. Federal Information Processing Standards Publication 46-3.
+//
+// DES is cryptographically broken and should not be used for secure
+// applications.
 package des
 
 // Used to perform an initial permutation of a 64-bit input block.
diff --git a/src/crypto/des/des_test.go b/src/crypto/des/des_test.go
index 2bd525a..690a49f 100644
--- a/src/crypto/des/des_test.go
+++ b/src/crypto/des/des_test.go
@@ -1526,17 +1526,6 @@ func TestFinalPermute(t *testing.T) {
 	}
 }
 
-func TestExpandBlock(t *testing.T) {
-	for i := uint(0); i < 32; i++ {
-		bit := uint32(1) << i
-		got := expandBlock(bit)
-		want := permuteBlock(uint64(bit), expansionFunction[:])
-		if got != want {
-			t.Errorf("expand(%x) = %x, want %x", bit, got, want)
-		}
-	}
-}
-
 func BenchmarkEncrypt(b *testing.B) {
 	tt := encryptDESTests[0]
 	c, err := NewCipher(tt.key)
@@ -1564,3 +1553,31 @@ func BenchmarkDecrypt(b *testing.B) {
 		c.Decrypt(out, tt.out)
 	}
 }
+
+func BenchmarkTDESEncrypt(b *testing.B) {
+	tt := encryptTripleDESTests[0]
+	c, err := NewTripleDESCipher(tt.key)
+	if err != nil {
+		b.Fatal("NewCipher:", err)
+	}
+	out := make([]byte, len(tt.in))
+	b.SetBytes(int64(len(out)))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		c.Encrypt(out, tt.in)
+	}
+}
+
+func BenchmarkTDESDecrypt(b *testing.B) {
+	tt := encryptTripleDESTests[0]
+	c, err := NewTripleDESCipher(tt.key)
+	if err != nil {
+		b.Fatal("NewCipher:", err)
+	}
+	out := make([]byte, len(tt.out))
+	b.SetBytes(int64(len(out)))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		c.Decrypt(out, tt.out)
+	}
+}
diff --git a/src/crypto/dsa/dsa_test.go b/src/crypto/dsa/dsa_test.go
index 8600059..a78c3f1 100644
--- a/src/crypto/dsa/dsa_test.go
+++ b/src/crypto/dsa/dsa_test.go
@@ -82,12 +82,17 @@ func fromHex(s string) *big.Int {
 }
 
 func TestSignAndVerify(t *testing.T) {
-	var priv PrivateKey
-	priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
-	priv.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
-	priv.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
-	priv.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
-	priv.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
+	priv := PrivateKey{
+		PublicKey: PublicKey {
+			Parameters: Parameters{
+				P: fromHex("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF"),
+				Q: fromHex("E1D3391245933D68A0714ED34BBCB7A1F422B9C1"),
+				G: fromHex("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA"),
+			},
+			Y: fromHex("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2"),
+		},
+		X: fromHex("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A"),
+	}
 
 	testSignAndVerify(t, 0, &priv)
 }
diff --git a/src/crypto/md5/md5.go b/src/crypto/md5/md5.go
index ce58d5e..b682f00 100644
--- a/src/crypto/md5/md5.go
+++ b/src/crypto/md5/md5.go
@@ -5,6 +5,9 @@
 //go:generate go run gen.go -full -output md5block.go
 
 // Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
+//
+// MD5 is cryptographically broken and should not be used for secure
+// applications.
 package md5
 
 import (
diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go
index 472daa7..8a4c757 100644
--- a/src/crypto/rand/rand_linux.go
+++ b/src/crypto/rand/rand_linux.go
@@ -6,34 +6,20 @@ package rand
 
 import (
 	"internal/syscall/unix"
-	"sync"
 )
 
 func init() {
 	altGetRandom = getRandomLinux
 }
 
-var (
-	once       sync.Once
-	useSyscall bool
-)
-
-func pickStrategy() {
-	// Test whether we should use the system call or /dev/urandom.
-	// We'll fall back to urandom if:
-	// - the kernel is too old (before 3.17)
-	// - the machine has no entropy available (early boot + no hardware
-	//   entropy source?) and we want to avoid blocking later.
-	var buf [1]byte
-	n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
-	useSyscall = n == 1 && err == nil
-}
-
+// If the kernel is too old (before 3.17) to support the getrandom syscall(),
+// unix.GetRandom will immediately return ENOSYS and we will then fall back to
+// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
+// result so we only suffer the syscall overhead once in this case.
+// If the kernel supports the getrandom() syscall, unix.GetRandom will block
+// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
+// In this case, unix.GetRandom will not return an error.
 func getRandomLinux(p []byte) (ok bool) {
-	once.Do(pickStrategy)
-	if !useSyscall {
-		return false
-	}
 	n, err := unix.GetRandom(p, 0)
 	return n == len(p) && err == nil
 }
diff --git a/src/crypto/rand/util.go b/src/crypto/rand/util.go
index 592c57e..4dd1711 100644
--- a/src/crypto/rand/util.go
+++ b/src/crypto/rand/util.go
@@ -107,16 +107,23 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
 	if max.Sign() <= 0 {
 		panic("crypto/rand: argument to Int is <= 0")
 	}
-	k := (max.BitLen() + 7) / 8
-
-	// b is the number of bits in the most significant byte of max.
-	b := uint(max.BitLen() % 8)
+	n = new(big.Int)
+	n.Sub(max, n.SetUint64(1))
+	// bitLen is the maximum bit length needed to encode a value < max.
+	bitLen := n.BitLen()
+	if bitLen == 0 {
+		// the only valid result is 0
+		return
+	}
+	// k is the maximum byte length needed to encode a value < max.
+	k := (bitLen + 7) / 8
+	// b is the number of bits in the most significant byte of max-1.
+	b := uint(bitLen % 8)
 	if b == 0 {
 		b = 8
 	}
 
 	bytes := make([]byte, k)
-	n = new(big.Int)
 
 	for {
 		_, err = io.ReadFull(rand, bytes)
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
index 48a2c3f..685624e 100644
--- a/src/crypto/rand/util_test.go
+++ b/src/crypto/rand/util_test.go
@@ -5,7 +5,10 @@
 package rand_test
 
 import (
+	"bytes"
 	"crypto/rand"
+	"fmt"
+	"io"
 	"math/big"
 	mathrand "math/rand"
 	"testing"
@@ -45,6 +48,56 @@ func TestInt(t *testing.T) {
 	}
 }
 
+type countingReader struct {
+	r io.Reader
+	n int
+}
+
+func (r *countingReader) Read(p []byte) (n int, err error) {
+	n, err = r.r.Read(p)
+	r.n += n
+	return n, err
+}
+
+// Test that Int reads only the necessary number of bytes from the reader for
+// max at each bit length
+func TestIntReads(t *testing.T) {
+	for i := 0; i < 32; i++ {
+		max := int64(1 << uint64(i))
+		t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) {
+			reader := &countingReader{r: rand.Reader}
+
+			_, err := rand.Int(reader, big.NewInt(max))
+			if err != nil {
+				t.Fatalf("Can't generate random value: %d, %v", max, err)
+			}
+			expected := (i + 7) / 8
+			if reader.n != expected {
+				t.Errorf("Int(reader, %d) should read %d bytes, but it read: %d", max, expected, reader.n)
+			}
+		})
+	}
+}
+
+// Test that Int does not mask out valid return values
+func TestIntMask(t *testing.T) {
+	for max := 1; max <= 256; max++ {
+		t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) {
+			for i := 0; i < max; i++ {
+				var b bytes.Buffer
+				b.WriteByte(byte(i))
+				n, err := rand.Int(&b, big.NewInt(int64(max)))
+				if err != nil {
+					t.Fatalf("Can't generate random value: %d, %v", max, err)
+				}
+				if n.Int64() != int64(i) {
+					t.Errorf("Int(reader, %d) should have returned value of %d, but it returned: %v", max, i, n)
+				}
+			}
+		})
+	}
+}
+
 func testIntPanics(t *testing.T, b *big.Int) {
 	defer func() {
 		if err := recover(); err == nil {
diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
index bd04aee..772af0e 100644
--- a/src/crypto/rc4/rc4.go
+++ b/src/crypto/rc4/rc4.go
@@ -4,11 +4,11 @@
 
 // Package rc4 implements RC4 encryption, as defined in Bruce Schneier's
 // Applied Cryptography.
+//
+// RC4 is cryptographically broken and should not be used for secure
+// applications.
 package rc4
 
-// BUG(agl): RC4 is in common use but has design weaknesses that make
-// it a poor choice for new protocols.
-
 import "strconv"
 
 // A Cipher is an instance of RC4 using a particular key.
diff --git a/src/crypto/sha1/sha1.go b/src/crypto/sha1/sha1.go
index fbb2f94..6b17214 100644
--- a/src/crypto/sha1/sha1.go
+++ b/src/crypto/sha1/sha1.go
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174.
+// Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174.
+//
+// SHA-1 is cryptographically broken and should not be used for secure
+// applications.
 package sha1
 
 import (
@@ -14,10 +17,10 @@ func init() {
 	crypto.RegisterHash(crypto.SHA1, New)
 }
 
-// The size of a SHA1 checksum in bytes.
+// The size of a SHA-1 checksum in bytes.
 const Size = 20
 
-// The blocksize of SHA1 in bytes.
+// The blocksize of SHA-1 in bytes.
 const BlockSize = 64
 
 const (
@@ -189,7 +192,7 @@ func (d *digest) constSum() [Size]byte {
 	return digest
 }
 
-// Sum returns the SHA1 checksum of the data.
+// Sum returns the SHA-1 checksum of the data.
 func Sum(data []byte) [Size]byte {
 	var d digest
 	d.Reset()
diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go
index 3e59a5d..faa9916 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.
+// SHA-1 hash algorithm. See RFC 3174.
 
 package sha1
 
diff --git a/src/crypto/sha1/sha1block.go b/src/crypto/sha1/sha1block.go
index fde3c98..1d37544 100644
--- a/src/crypto/sha1/sha1block.go
+++ b/src/crypto/sha1/sha1block.go
@@ -11,7 +11,7 @@ const (
 	_K3 = 0xCA62C1D6
 )
 
-// blockGeneric is a portable, pure Go version of the SHA1 block step.
+// blockGeneric is a portable, pure Go version of the SHA-1 block step.
 // It's used by sha1block_generic.go and tests.
 func blockGeneric(dig *digest, p []byte) {
 	var w [16]uint32
diff --git a/src/crypto/sha1/sha1block_386.s b/src/crypto/sha1/sha1block_386.s
index 46f5d79..0a7e45a 100644
--- a/src/crypto/sha1/sha1block_386.s
+++ b/src/crypto/sha1/sha1block_386.s
@@ -4,7 +4,7 @@
 
 #include "textflag.h"
 
-// SHA1 block routine. See sha1block.go for Go equivalent.
+// SHA-1 block routine. See sha1block.go for Go equivalent.
 //
 // There are 80 rounds of 4 types:
 //   - rounds 0-15 are type 1 and load data (ROUND1 macro).
diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go
index 0320e41..039813d 100644
--- a/src/crypto/sha1/sha1block_amd64.go
+++ b/src/crypto/sha1/sha1block_amd64.go
@@ -4,18 +4,18 @@
 
 package sha1
 
-//go:noescape
+import "internal/cpu"
 
+//go:noescape
 func blockAVX2(dig *digest, p []byte)
 
 //go:noescape
 func blockAMD64(dig *digest, p []byte)
-func checkAVX2() bool
 
-var hasAVX2 = checkAVX2()
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2
 
 func block(dig *digest, p []byte) {
-	if hasAVX2 && len(p) >= 256 {
+	if useAVX2 && 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
diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s
index 77c8ec3..3adb6d2 100644
--- a/src/crypto/sha1/sha1block_amd64.s
+++ b/src/crypto/sha1/sha1block_amd64.s
@@ -13,7 +13,7 @@
 
 #include "textflag.h"
 
-// SHA1 block routine. See sha1block.go for Go equivalent.
+// SHA-1 block routine. See sha1block.go for Go equivalent.
 //
 // There are 80 rounds of 4 types:
 //   - rounds 0-15 are type 1 and load data (ROUND1 macro).
@@ -1457,23 +1457,6 @@ TEXT ·blockAVX2(SB),$1408-32
 
 	CALC // RET is inside macros
 
-
-// func checkAVX2() bool
-// returns whether AVX2, BMI1 and BMI2 are supported
-TEXT ·checkAVX2(SB),NOSPLIT,$0
-	CMPB runtime·support_avx2(SB), $0
-	JE   noavx2
-	CMPB runtime·support_bmi1(SB), $0  // check for ANDNL instruction
-	JE   noavx2
-	CMPB runtime·support_bmi2(SB), $0  // check for RORXL instruction
-	JE   noavx2
-        MOVB    $1, ret+0(FP)
-	RET
-noavx2:
-        MOVB    $0, 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
diff --git a/src/crypto/sha1/sha1block_amd64p32.s b/src/crypto/sha1/sha1block_amd64p32.s
index 0159d23..e5404e8 100644
--- a/src/crypto/sha1/sha1block_amd64p32.s
+++ b/src/crypto/sha1/sha1block_amd64p32.s
@@ -4,7 +4,7 @@
 
 #include "textflag.h"
 
-// SHA1 block routine. See sha1block.go for Go equivalent.
+// SHA-1 block routine. See sha1block.go for Go equivalent.
 //
 // There are 80 rounds of 4 types:
 //   - rounds 0-15 are type 1 and load data (ROUND1 macro).
diff --git a/src/crypto/sha1/sha1block_arm.s b/src/crypto/sha1/sha1block_arm.s
index 9c76801..055edc9 100644
--- a/src/crypto/sha1/sha1block_arm.s
+++ b/src/crypto/sha1/sha1block_arm.s
@@ -6,7 +6,7 @@
 
 #include "textflag.h"
 
-// SHA1 block routine. See sha1block.go for Go equivalent.
+// SHA-1 block routine. See sha1block.go for Go equivalent.
 //
 // There are 80 rounds of 4 types:
 //   - rounds 0-15 are type 1 and load data (ROUND1 macro).
@@ -25,11 +25,11 @@
 // Register definitions
 #define Rdata	R0	// Pointer to incoming data
 #define Rconst	R1	// Current constant for SHA round
-#define Ra	R2		// SHA1 accumulator
-#define Rb	R3		// SHA1 accumulator
-#define Rc	R4		// SHA1 accumulator
-#define Rd	R5		// SHA1 accumulator
-#define Re	R6		// SHA1 accumulator
+#define Ra	R2		// SHA-1 accumulator
+#define Rb	R3		// SHA-1 accumulator
+#define Rc	R4		// SHA-1 accumulator
+#define Rd	R5		// SHA-1 accumulator
+#define Re	R6		// SHA-1 accumulator
 #define Rt0	R7		// Temporary
 #define Rt1	R8		// Temporary
 // r9, r10 are forbidden
@@ -143,7 +143,7 @@ TEXT	·block(SB), 0, $352-16
 	ADD	Rdata, Rt0
 	MOVW	Rt0, p_end	// pointer to end of data
 
-	// Load up initial SHA1 accumulator
+	// Load up initial SHA-1 accumulator
 	MOVW	dig+0(FP), Rt0
 	MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re]
 
@@ -210,7 +210,7 @@ loop4:	ROUND4(Ra, Rb, Rc, Rd, Re)
 	CMP	Rt0, Rdata
 	BLO	loop
 
-	// Save final SHA1 accumulator
+	// Save final SHA-1 accumulator
 	MOVW	dig+0(FP), Rt0
 	MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0)
 
diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go
index aac7c11..340704a 100644
--- a/src/crypto/sha1/sha1block_s390x.go
+++ b/src/crypto/sha1/sha1block_s390x.go
@@ -5,7 +5,7 @@
 package sha1
 
 // featureCheck reports whether the CPU supports the
-// SHA1 compute intermediate message digest (KIMD)
+// SHA-1 compute intermediate message digest (KIMD)
 // function code.
 func featureCheck() bool
 
diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s
index a9c4b08..3c71998 100644
--- a/src/crypto/sha1/sha1block_s390x.s
+++ b/src/crypto/sha1/sha1block_s390x.s
@@ -10,7 +10,7 @@ TEXT ·featureCheck(SB),NOSPLIT,$16-1
 	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
+	AND	$0x40, R4      // bit 1 (big endian) for SHA-1
 	CMPBEQ	R4, $0, nosha1
 	MOVB	$1, ret+0(FP)
 	RET
@@ -23,7 +23,7 @@ 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
+	MOVBZ	$1, R0        // SHA-1 function code
 loop:
 	WORD	$0xB93E0002   // KIMD R2
 	BVS	loop          // continue if interrupted
diff --git a/src/crypto/sha256/sha256block_amd64.go b/src/crypto/sha256/sha256block_amd64.go
new file mode 100644
index 0000000..27464e2
--- /dev/null
+++ b/src/crypto/sha256/sha256block_amd64.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. 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
+
+import "internal/cpu"
+
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s
index e9705b9..d7ac1e5 100644
--- a/src/crypto/sha256/sha256block_amd64.s
+++ b/src/crypto/sha256/sha256block_amd64.s
@@ -559,11 +559,8 @@
 	ADDL  y3, h                        // h = t1 + S0 + MAJ					// --
 
 TEXT ·block(SB), 0, $536-32
-	CMPB runtime·support_avx2(SB), $0
-	JE   noavx2bmi2
-	CMPB runtime·support_bmi2(SB), $1  // check for RORXL instruction
+	CMPB ·useAVX2(SB), $1
 	JE   avx2
-noavx2bmi2:
 
 	MOVQ p_base+8(FP), SI
 	MOVQ p_len+16(FP), DX
diff --git a/src/crypto/sha256/sha256block_ppc64le.s b/src/crypto/sha256/sha256block_ppc64le.s
index 7ac5000..9ffa5f8 100644
--- a/src/crypto/sha256/sha256block_ppc64le.s
+++ b/src/crypto/sha256/sha256block_ppc64le.s
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This is a derived work from OpenSSL of SHA-2 using assembly optimizations. The
+// original code was written by Andy Polyakov <appro at openssl.org> and it's dual
+// licensed under OpenSSL and CRYPTOGAMS licenses depending on where you obtain
+// it. For further details see http://www.openssl.org/~appro/cryptogams/.
+
 #include "textflag.h"
 
 // SHA256 block routine. See sha256block.go for Go equivalent.
@@ -44,226 +49,368 @@
 // H6 = g + H6
 // H7 = h + H7
 
-// Wt = Mt; for 0 <= t <= 15
-#define MSGSCHEDULE0(index) \
-	MOVWZ	(index*4)(R26), R7; \
-	RLWNM	$24, R7, $-1, R11; \
-	RLWMI	$8, R7, $0x00FF0000, R11; \
-	RLWMI	$8, R7, $0x000000FF, R11; \
-	MOVWZ	R11, R7; \
-	MOVWZ	R7, (index*4)(R27)
-
-// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
-//   SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
-//   SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
-#define MSGSCHEDULE1(index) \
-	MOVWZ	((index-2)*4)(R27), R7; \
-	MOVWZ	R7, R9; \
-	RLWNM	$32-17, R7, $-1, R7; \
-	MOVWZ	R9, R10; \
-	RLWNM	$32-19, R9, $-1, R9; \
-	SRW	$10, R10; \
-	MOVWZ	((index-15)*4)(R27), R8; \
-	XOR	R9, R7; \
-	MOVWZ	R8, R9; \
-	XOR	R10, R7; \
-	RLWNM	$32-7, R8, $-1, R8; \
-	MOVWZ	R9, R10; \
-	SRW	$3, R10; \
-	RLWNM	$32-18, R9, $-1, R9; \
-	MOVWZ	((index-7)*4)(R27), R11; \
-	ADD	R11, R7; \
-	XOR	R9, R8; \
-	XOR	R10, R8; \
-	MOVWZ	((index-16)*4)(R27), R11; \
-	ADD	R11, R8; \
-	ADD	R8, R7; \
-	MOVWZ	R7, ((index)*4)(R27)
-
-// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
-//   BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
-//   Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
-#define SHA256T1(const, e, f, g, h) \
-	ADD	R7, h; \
-	MOVWZ	e, R7; \
-	ADD	$const, h; \
-	MOVWZ	e, R9; \
-	RLWNM	$32-6, R7, $-1, R7; \
-	MOVWZ	e, R10; \
-	RLWNM	$32-11, R9, $-1, R9; \
-	XOR	R9, R7; \
-	MOVWZ	e, R9; \
-	RLWNM	$32-25, R10, $-1, R10; \
-	AND	f, R9; \
-	XOR	R7, R10; \
-	MOVWZ	e, R7; \
-	NOR	R7, R7, R7; \
-	ADD	R10, h; \
-	AND	g, R7; \
-	XOR	R9, R7; \
-	ADD	h, R7
-
-// T2 = BIGSIGMA0(a) + Maj(a, b, c)
-//   BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
-//   Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
-#define SHA256T2(a, b, c) \
-	MOVWZ	a, R28; \
-	MOVWZ	c, R8; \
-	RLWNM	$32-2, R28, $-1, R28; \
-	MOVWZ	a, R10; \
-	AND	b, R8; \
-	RLWNM	$32-13, R10, $-1, R10; \
-	MOVWZ	a, R9; \
-	AND	c, R9; \
-	XOR	R10, R28; \
-	XOR	R9, R8; \
-	MOVWZ	a, R10; \
-	MOVWZ	b, R9; \
-	RLWNM	$32-22, R10, $-1, R10; \
-	AND	a, R9; \
-	XOR	R9, R8; \
-	XOR	R10, R28; \
-	ADD	R28, R8
-
-// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
-// The values for e and a are stored in d and h, ready for rotation.
-#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
-	SHA256T1(const, e, f, g, h); \
-	SHA256T2(a, b, c); \
-	MOVWZ	R8, h; \
-	ADD	R7, d; \
-	ADD	R7, h
-
-#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
-	MSGSCHEDULE0(index); \
-	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
-
-#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
-	MSGSCHEDULE1(index); \
-	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+#define CTX	R3
+#define INP	R4
+#define END	R5
+#define TBL	R6
+#define IDX	R7
+#define CNT	R8
+#define LEN	R9
+#define OFFLOAD	R11
+#define TEMP	R12
+
+#define HEX00	R0
+#define HEX10	R10
+#define HEX20	R25
+#define HEX30	R26
+#define HEX40	R27
+#define HEX50	R28
+#define HEX60	R29
+#define HEX70	R31
+
+// V0-V7 are A-H
+// V8-V23 are used for the message schedule
+#define KI	V24
+#define FUNC	V25
+#define S0	V26
+#define S1	V27
+#define s0	V28
+#define s1	V29
+#define LEMASK	V31	// Permutation control register for little endian
+
+// 4 copies of each Kt, to fill all 4 words of a vector register
+DATA  ·kcon+0x000(SB)/8, $0x428a2f98428a2f98
+DATA  ·kcon+0x008(SB)/8, $0x428a2f98428a2f98
+DATA  ·kcon+0x010(SB)/8, $0x7137449171374491
+DATA  ·kcon+0x018(SB)/8, $0x7137449171374491
+DATA  ·kcon+0x020(SB)/8, $0xb5c0fbcfb5c0fbcf
+DATA  ·kcon+0x028(SB)/8, $0xb5c0fbcfb5c0fbcf
+DATA  ·kcon+0x030(SB)/8, $0xe9b5dba5e9b5dba5
+DATA  ·kcon+0x038(SB)/8, $0xe9b5dba5e9b5dba5
+DATA  ·kcon+0x040(SB)/8, $0x3956c25b3956c25b
+DATA  ·kcon+0x048(SB)/8, $0x3956c25b3956c25b
+DATA  ·kcon+0x050(SB)/8, $0x59f111f159f111f1
+DATA  ·kcon+0x058(SB)/8, $0x59f111f159f111f1
+DATA  ·kcon+0x060(SB)/8, $0x923f82a4923f82a4
+DATA  ·kcon+0x068(SB)/8, $0x923f82a4923f82a4
+DATA  ·kcon+0x070(SB)/8, $0xab1c5ed5ab1c5ed5
+DATA  ·kcon+0x078(SB)/8, $0xab1c5ed5ab1c5ed5
+DATA  ·kcon+0x080(SB)/8, $0xd807aa98d807aa98
+DATA  ·kcon+0x088(SB)/8, $0xd807aa98d807aa98
+DATA  ·kcon+0x090(SB)/8, $0x12835b0112835b01
+DATA  ·kcon+0x098(SB)/8, $0x12835b0112835b01
+DATA  ·kcon+0x0A0(SB)/8, $0x243185be243185be
+DATA  ·kcon+0x0A8(SB)/8, $0x243185be243185be
+DATA  ·kcon+0x0B0(SB)/8, $0x550c7dc3550c7dc3
+DATA  ·kcon+0x0B8(SB)/8, $0x550c7dc3550c7dc3
+DATA  ·kcon+0x0C0(SB)/8, $0x72be5d7472be5d74
+DATA  ·kcon+0x0C8(SB)/8, $0x72be5d7472be5d74
+DATA  ·kcon+0x0D0(SB)/8, $0x80deb1fe80deb1fe
+DATA  ·kcon+0x0D8(SB)/8, $0x80deb1fe80deb1fe
+DATA  ·kcon+0x0E0(SB)/8, $0x9bdc06a79bdc06a7
+DATA  ·kcon+0x0E8(SB)/8, $0x9bdc06a79bdc06a7
+DATA  ·kcon+0x0F0(SB)/8, $0xc19bf174c19bf174
+DATA  ·kcon+0x0F8(SB)/8, $0xc19bf174c19bf174
+DATA  ·kcon+0x100(SB)/8, $0xe49b69c1e49b69c1
+DATA  ·kcon+0x108(SB)/8, $0xe49b69c1e49b69c1
+DATA  ·kcon+0x110(SB)/8, $0xefbe4786efbe4786
+DATA  ·kcon+0x118(SB)/8, $0xefbe4786efbe4786
+DATA  ·kcon+0x120(SB)/8, $0x0fc19dc60fc19dc6
+DATA  ·kcon+0x128(SB)/8, $0x0fc19dc60fc19dc6
+DATA  ·kcon+0x130(SB)/8, $0x240ca1cc240ca1cc
+DATA  ·kcon+0x138(SB)/8, $0x240ca1cc240ca1cc
+DATA  ·kcon+0x140(SB)/8, $0x2de92c6f2de92c6f
+DATA  ·kcon+0x148(SB)/8, $0x2de92c6f2de92c6f
+DATA  ·kcon+0x150(SB)/8, $0x4a7484aa4a7484aa
+DATA  ·kcon+0x158(SB)/8, $0x4a7484aa4a7484aa
+DATA  ·kcon+0x160(SB)/8, $0x5cb0a9dc5cb0a9dc
+DATA  ·kcon+0x168(SB)/8, $0x5cb0a9dc5cb0a9dc
+DATA  ·kcon+0x170(SB)/8, $0x76f988da76f988da
+DATA  ·kcon+0x178(SB)/8, $0x76f988da76f988da
+DATA  ·kcon+0x180(SB)/8, $0x983e5152983e5152
+DATA  ·kcon+0x188(SB)/8, $0x983e5152983e5152
+DATA  ·kcon+0x190(SB)/8, $0xa831c66da831c66d
+DATA  ·kcon+0x198(SB)/8, $0xa831c66da831c66d
+DATA  ·kcon+0x1A0(SB)/8, $0xb00327c8b00327c8
+DATA  ·kcon+0x1A8(SB)/8, $0xb00327c8b00327c8
+DATA  ·kcon+0x1B0(SB)/8, $0xbf597fc7bf597fc7
+DATA  ·kcon+0x1B8(SB)/8, $0xbf597fc7bf597fc7
+DATA  ·kcon+0x1C0(SB)/8, $0xc6e00bf3c6e00bf3
+DATA  ·kcon+0x1C8(SB)/8, $0xc6e00bf3c6e00bf3
+DATA  ·kcon+0x1D0(SB)/8, $0xd5a79147d5a79147
+DATA  ·kcon+0x1D8(SB)/8, $0xd5a79147d5a79147
+DATA  ·kcon+0x1E0(SB)/8, $0x06ca635106ca6351
+DATA  ·kcon+0x1E8(SB)/8, $0x06ca635106ca6351
+DATA  ·kcon+0x1F0(SB)/8, $0x1429296714292967
+DATA  ·kcon+0x1F8(SB)/8, $0x1429296714292967
+DATA  ·kcon+0x200(SB)/8, $0x27b70a8527b70a85
+DATA  ·kcon+0x208(SB)/8, $0x27b70a8527b70a85
+DATA  ·kcon+0x210(SB)/8, $0x2e1b21382e1b2138
+DATA  ·kcon+0x218(SB)/8, $0x2e1b21382e1b2138
+DATA  ·kcon+0x220(SB)/8, $0x4d2c6dfc4d2c6dfc
+DATA  ·kcon+0x228(SB)/8, $0x4d2c6dfc4d2c6dfc
+DATA  ·kcon+0x230(SB)/8, $0x53380d1353380d13
+DATA  ·kcon+0x238(SB)/8, $0x53380d1353380d13
+DATA  ·kcon+0x240(SB)/8, $0x650a7354650a7354
+DATA  ·kcon+0x248(SB)/8, $0x650a7354650a7354
+DATA  ·kcon+0x250(SB)/8, $0x766a0abb766a0abb
+DATA  ·kcon+0x258(SB)/8, $0x766a0abb766a0abb
+DATA  ·kcon+0x260(SB)/8, $0x81c2c92e81c2c92e
+DATA  ·kcon+0x268(SB)/8, $0x81c2c92e81c2c92e
+DATA  ·kcon+0x270(SB)/8, $0x92722c8592722c85
+DATA  ·kcon+0x278(SB)/8, $0x92722c8592722c85
+DATA  ·kcon+0x280(SB)/8, $0xa2bfe8a1a2bfe8a1
+DATA  ·kcon+0x288(SB)/8, $0xa2bfe8a1a2bfe8a1
+DATA  ·kcon+0x290(SB)/8, $0xa81a664ba81a664b
+DATA  ·kcon+0x298(SB)/8, $0xa81a664ba81a664b
+DATA  ·kcon+0x2A0(SB)/8, $0xc24b8b70c24b8b70
+DATA  ·kcon+0x2A8(SB)/8, $0xc24b8b70c24b8b70
+DATA  ·kcon+0x2B0(SB)/8, $0xc76c51a3c76c51a3
+DATA  ·kcon+0x2B8(SB)/8, $0xc76c51a3c76c51a3
+DATA  ·kcon+0x2C0(SB)/8, $0xd192e819d192e819
+DATA  ·kcon+0x2C8(SB)/8, $0xd192e819d192e819
+DATA  ·kcon+0x2D0(SB)/8, $0xd6990624d6990624
+DATA  ·kcon+0x2D8(SB)/8, $0xd6990624d6990624
+DATA  ·kcon+0x2E0(SB)/8, $0xf40e3585f40e3585
+DATA  ·kcon+0x2E8(SB)/8, $0xf40e3585f40e3585
+DATA  ·kcon+0x2F0(SB)/8, $0x106aa070106aa070
+DATA  ·kcon+0x2F8(SB)/8, $0x106aa070106aa070
+DATA  ·kcon+0x300(SB)/8, $0x19a4c11619a4c116
+DATA  ·kcon+0x308(SB)/8, $0x19a4c11619a4c116
+DATA  ·kcon+0x310(SB)/8, $0x1e376c081e376c08
+DATA  ·kcon+0x318(SB)/8, $0x1e376c081e376c08
+DATA  ·kcon+0x320(SB)/8, $0x2748774c2748774c
+DATA  ·kcon+0x328(SB)/8, $0x2748774c2748774c
+DATA  ·kcon+0x330(SB)/8, $0x34b0bcb534b0bcb5
+DATA  ·kcon+0x338(SB)/8, $0x34b0bcb534b0bcb5
+DATA  ·kcon+0x340(SB)/8, $0x391c0cb3391c0cb3
+DATA  ·kcon+0x348(SB)/8, $0x391c0cb3391c0cb3
+DATA  ·kcon+0x350(SB)/8, $0x4ed8aa4a4ed8aa4a
+DATA  ·kcon+0x358(SB)/8, $0x4ed8aa4a4ed8aa4a
+DATA  ·kcon+0x360(SB)/8, $0x5b9cca4f5b9cca4f
+DATA  ·kcon+0x368(SB)/8, $0x5b9cca4f5b9cca4f
+DATA  ·kcon+0x370(SB)/8, $0x682e6ff3682e6ff3
+DATA  ·kcon+0x378(SB)/8, $0x682e6ff3682e6ff3
+DATA  ·kcon+0x380(SB)/8, $0x748f82ee748f82ee
+DATA  ·kcon+0x388(SB)/8, $0x748f82ee748f82ee
+DATA  ·kcon+0x390(SB)/8, $0x78a5636f78a5636f
+DATA  ·kcon+0x398(SB)/8, $0x78a5636f78a5636f
+DATA  ·kcon+0x3A0(SB)/8, $0x84c8781484c87814
+DATA  ·kcon+0x3A8(SB)/8, $0x84c8781484c87814
+DATA  ·kcon+0x3B0(SB)/8, $0x8cc702088cc70208
+DATA  ·kcon+0x3B8(SB)/8, $0x8cc702088cc70208
+DATA  ·kcon+0x3C0(SB)/8, $0x90befffa90befffa
+DATA  ·kcon+0x3C8(SB)/8, $0x90befffa90befffa
+DATA  ·kcon+0x3D0(SB)/8, $0xa4506ceba4506ceb
+DATA  ·kcon+0x3D8(SB)/8, $0xa4506ceba4506ceb
+DATA  ·kcon+0x3E0(SB)/8, $0xbef9a3f7bef9a3f7
+DATA  ·kcon+0x3E8(SB)/8, $0xbef9a3f7bef9a3f7
+DATA  ·kcon+0x3F0(SB)/8, $0xc67178f2c67178f2
+DATA  ·kcon+0x3F8(SB)/8, $0xc67178f2c67178f2
+DATA  ·kcon+0x400(SB)/8, $0x0000000000000000
+DATA  ·kcon+0x408(SB)/8, $0x0000000000000000
+DATA  ·kcon+0x410(SB)/8, $0x1011121310111213	// permutation control vectors
+DATA  ·kcon+0x418(SB)/8, $0x1011121300010203
+DATA  ·kcon+0x420(SB)/8, $0x1011121310111213
+DATA  ·kcon+0x428(SB)/8, $0x0405060700010203
+DATA  ·kcon+0x430(SB)/8, $0x1011121308090a0b
+DATA  ·kcon+0x438(SB)/8, $0x0405060700010203
+GLOBL ·kcon(SB), RODATA, $1088
+
+#define SHA256ROUND0(a, b, c, d, e, f, g, h, xi) \
+	VSEL		g, f, e, FUNC; \
+	VSHASIGMAW	$15, e, $1, S1; \
+	VADDUWM		xi, h, h; \
+	VSHASIGMAW	$0, a, $1, S0; \
+	VADDUWM		FUNC, h, h; \
+	VXOR		b, a, FUNC; \
+	VADDUWM		S1, h, h; \
+	VSEL		b, c, FUNC, FUNC; \
+	VADDUWM		KI, g, g; \
+	VADDUWM		h, d, d; \
+	VADDUWM		FUNC, S0, S0; \
+	LVX		(TBL)(IDX), KI; \
+	ADD		$16, IDX; \
+	VADDUWM		S0, h, h
+
+#define SHA256ROUND1(a, b, c, d, e, f, g, h, xi, xj, xj_1, xj_9, xj_14) \
+	VSHASIGMAW	$0, xj_1, $0, s0; \
+	VSEL		g, f, e, FUNC; \
+	VSHASIGMAW	$15, e, $1, S1; \
+	VADDUWM		xi, h, h; \
+	VSHASIGMAW	$0, a, $1, S0; \
+	VSHASIGMAW	$15, xj_14, $0, s1; \
+	VADDUWM		FUNC, h, h; \
+	VXOR		b, a, FUNC; \
+	VADDUWM		xj_9, xj, xj; \
+	VADDUWM		S1, h, h; \
+	VSEL		b, c, FUNC, FUNC; \
+	VADDUWM		KI, g, g; \
+	VADDUWM		h, d, d; \
+	VADDUWM		FUNC, S0, S0; \
+	VADDUWM		s0, xj, xj; \
+	LVX		(TBL)(IDX), KI; \
+	ADD		$16, IDX; \
+	VADDUWM		S0, h, h; \
+	VADDUWM		s1, xj, xj
 
 // func block(dig *digest, p []byte)
-TEXT ·block(SB),0,$296-32
-	MOVD	p_base+8(FP), R26
-	MOVD	p_len+16(FP), R29
-	SRD	$6, R29
-	SLD	$6, R29
+TEXT ·block(SB),0,$128-32
+	MOVD	dig+0(FP), CTX
+	MOVD	p_base+8(FP), INP
+	MOVD	p_len+16(FP), LEN
+
+	SRD	$6, LEN
+	SLD	$6, LEN
 
-	ADD	R26, R29, R28
+	ADD	INP, LEN, END
 
-	MOVD	R28, 256(R1)
-	CMP	R26, R28
+	CMP	INP, END
 	BEQ	end
 
-	MOVD	dig+0(FP), R27
-	MOVWZ	(0*4)(R27), R14		// a = H0
-	MOVWZ	(1*4)(R27), R15		// b = H1
-	MOVWZ	(2*4)(R27), R16		// c = H2
-	MOVWZ	(3*4)(R27), R17		// d = H3
-	MOVWZ	(4*4)(R27), R18		// e = H4
-	MOVWZ	(5*4)(R27), R19		// f = H5
-	MOVWZ	(6*4)(R27), R20		// g = H6
-	MOVWZ	(7*4)(R27), R21		// h = H7
+	MOVD	$·kcon(SB), TBL
+	MOVD	R1, OFFLOAD
+
+	MOVD	R0, CNT
+	MOVWZ	$0x10, HEX10
+	MOVWZ	$0x20, HEX20
+	MOVWZ	$0x30, HEX30
+	MOVWZ	$0x40, HEX40
+	MOVWZ	$0x50, HEX50
+	MOVWZ	$0x60, HEX60
+	MOVWZ	$0x70, HEX70
+
+	MOVWZ	$8, IDX
+	LVSL	(IDX)(R0), LEMASK
+	VSPLTISB	$0x0F, KI
+	VXOR	KI, LEMASK, LEMASK
+
+	LXVW4X	(CTX)(HEX00), VS32	// v0 = vs32
+	LXVW4X	(CTX)(HEX10), VS36	// v4 = vs36
+
+	// unpack the input values into vector registers
+	VSLDOI	$4, V0, V0, V1
+	VSLDOI	$8, V0, V0, V2
+	VSLDOI	$12, V0, V0, V3
+	VSLDOI	$4, V4, V4, V5
+	VSLDOI	$8, V4, V4, V6
+	VSLDOI	$12, V4, V4, V7
 
 loop:
-	MOVD	R1, R27		// R27: message schedule
-
-	SHA256ROUND0(0, 0x428a2f98, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND0(1, 0x71374491, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND0(2, 0xb5c0fbcf, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND0(3, 0xe9b5dba5, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND0(4, 0x3956c25b, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND0(5, 0x59f111f1, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND0(6, 0x923f82a4, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND0(7, 0xab1c5ed5, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND0(8, 0xd807aa98, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND0(9, 0x12835b01, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND0(10, 0x243185be, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND0(11, 0x550c7dc3, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND0(12, 0x72be5d74, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND0(13, 0x80deb1fe, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND0(14, 0x9bdc06a7, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND0(15, 0xc19bf174, R15, R16, R17, R18, R19, R20, R21, R14)
-
-	SHA256ROUND1(16, 0xe49b69c1, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(17, 0xefbe4786, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(18, 0x0fc19dc6, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(19, 0x240ca1cc, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(20, 0x2de92c6f, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(21, 0x4a7484aa, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(22, 0x5cb0a9dc, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(23, 0x76f988da, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND1(24, 0x983e5152, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(25, 0xa831c66d, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(26, 0xb00327c8, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(27, 0xbf597fc7, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(28, 0xc6e00bf3, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(29, 0xd5a79147, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(30, 0x06ca6351, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(31, 0x14292967, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND1(32, 0x27b70a85, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(33, 0x2e1b2138, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(34, 0x4d2c6dfc, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(35, 0x53380d13, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(36, 0x650a7354, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(37, 0x766a0abb, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(38, 0x81c2c92e, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(39, 0x92722c85, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND1(40, 0xa2bfe8a1, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(41, 0xa81a664b, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(42, 0xc24b8b70, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(43, 0xc76c51a3, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(44, 0xd192e819, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(45, 0xd6990624, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(46, 0xf40e3585, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(47, 0x106aa070, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND1(48, 0x19a4c116, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(49, 0x1e376c08, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(50, 0x2748774c, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(51, 0x34b0bcb5, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(52, 0x391c0cb3, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(53, 0x4ed8aa4a, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(54, 0x5b9cca4f, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(55, 0x682e6ff3, R15, R16, R17, R18, R19, R20, R21, R14)
-	SHA256ROUND1(56, 0x748f82ee, R14, R15, R16, R17, R18, R19, R20, R21)
-	SHA256ROUND1(57, 0x78a5636f, R21, R14, R15, R16, R17, R18, R19, R20)
-	SHA256ROUND1(58, 0x84c87814, R20, R21, R14, R15, R16, R17, R18, R19)
-	SHA256ROUND1(59, 0x8cc70208, R19, R20, R21, R14, R15, R16, R17, R18)
-	SHA256ROUND1(60, 0x90befffa, R18, R19, R20, R21, R14, R15, R16, R17)
-	SHA256ROUND1(61, 0xa4506ceb, R17, R18, R19, R20, R21, R14, R15, R16)
-	SHA256ROUND1(62, 0xbef9a3f7, R16, R17, R18, R19, R20, R21, R14, R15)
-	SHA256ROUND1(63, 0xc67178f2, R15, R16, R17, R18, R19, R20, R21, R14)
-
-	MOVD	dig+0(FP), R27
-	MOVWZ	(0*4)(R27), R11
-	ADD	R11, R14	// H0 = a + H0
-	MOVWZ	R14, (0*4)(R27)
-	MOVWZ	(1*4)(R27), R11
-	ADD	R11, R15	// H1 = b + H1
-	MOVWZ	R15, (1*4)(R27)
-	MOVWZ	(2*4)(R27), R11
-	ADD	R11, R16	// H2 = c + H2
-	MOVWZ	R16, (2*4)(R27)
-	MOVWZ	(3*4)(R27), R11
-	ADD	R11, R17	// H3 = d + H3
-	MOVWZ	R17, (3*4)(R27)
-	MOVWZ	(4*4)(R27), R11
-	ADD	R11, R18	// H4 = e + H4
-	MOVWZ	R18, (4*4)(R27)
-	MOVWZ	(5*4)(R27), R11
-	ADD	R11, R19	// H5 = f + H5
-	MOVWZ	R19, (5*4)(R27)
-	MOVWZ	(6*4)(R27), R11
-	ADD	R11, R20	// H6 = g + H6
-	MOVWZ	R20, (6*4)(R27)
-	MOVWZ	(7*4)(R27), R11
-	ADD	R11, R21	// H7 = h + H7
-	MOVWZ	R21, (7*4)(R27)
-
-	ADD	$64, R26
-	MOVD	256(R1), R11
-	CMPU	R26, R11
+	LVX	(TBL)(HEX00), KI
+	MOVWZ	$16, IDX
+
+	LXVD2X	(INP)(R0), VS40	// load v8 (=vs40) in advance
+	ADD	$16, INP
+
+	STVX	V0, (OFFLOAD+HEX00)
+	STVX	V1, (OFFLOAD+HEX10)
+	STVX	V2, (OFFLOAD+HEX20)
+	STVX	V3, (OFFLOAD+HEX30)
+	STVX	V4, (OFFLOAD+HEX40)
+	STVX	V5, (OFFLOAD+HEX50)
+	STVX	V6, (OFFLOAD+HEX60)
+	STVX	V7, (OFFLOAD+HEX70)
+
+	VADDUWM	KI, V7, V7	// h+K[i]
+	LVX	(TBL)(IDX), KI
+	ADD	$16, IDX
+
+	VPERM	V8, V8, LEMASK, V8
+	SHA256ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V8)
+	VSLDOI	$4, V8, V8, V9
+	SHA256ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V9)
+	VSLDOI	$4, V9, V9, V10
+	SHA256ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V10)
+	LXVD2X	(INP)(R0), VS44	// load v12 (=vs44) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$4, V10, V10, V11
+	SHA256ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V11)
+	VPERM	V12, V12, LEMASK, V12
+	SHA256ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V12)
+	VSLDOI	$4, V12, V12, V13
+	SHA256ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V13)
+	VSLDOI	$4, V13, V13, V14
+	SHA256ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V14)
+	LXVD2X	(INP)(R0), VS48	// load v16 (=vs48) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$4, V14, V14, V15
+	SHA256ROUND0(V1, V2, V3, V4, V5, V6, V7, V0, V15)
+	VPERM	V16, V16, LEMASK, V16
+	SHA256ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V16)
+	VSLDOI	$4, V16, V16, V17
+	SHA256ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V17)
+	VSLDOI	$4, V17, V17, V18
+	SHA256ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V18)
+	VSLDOI	$4, V18, V18, V19
+	LXVD2X	(INP)(R0), VS52	// load v20 (=vs52) in advance
+	ADD	$16, INP, INP
+	SHA256ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V19)
+	VPERM	V20, V20, LEMASK, V20
+	SHA256ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V20)
+	VSLDOI	$4, V20, V20, V21
+	SHA256ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V21)
+	VSLDOI	$4, V21, V21, V22
+	SHA256ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V22)
+	VSLDOI	$4, V22, V22, V23
+	SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+	MOVWZ	$3, TEMP
+	MOVWZ	TEMP, CTR
+
+L16_xx:
+	SHA256ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V18, V23)
+	SHA256ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V9, V10, V11, V19, V8)
+	SHA256ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V10, V11, V12, V20, V9)
+	SHA256ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V11, V12, V13, V21, V10)
+	SHA256ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V12, V13, V14, V22, V11)
+	SHA256ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V13, V14, V15, V23, V12)
+	SHA256ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V14, V15, V16, V8, V13)
+	SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V15, V16, V17, V9, V14)
+	SHA256ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V16, V17, V18, V10, V15)
+	SHA256ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V17, V18, V19, V11, V16)
+	SHA256ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V18, V19, V20, V12, V17)
+	SHA256ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V19, V20, V21, V13, V18)
+	SHA256ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V20, V21, V22, V14, V19)
+	SHA256ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V21, V22, V23, V15, V20)
+	SHA256ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V22, V23, V8, V16, V21)
+	SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+	BC	0x10, 0, L16_xx		// bdnz
+
+	LVX	(OFFLOAD)(HEX00), V10
+
+	LVX	(OFFLOAD)(HEX10), V11
+	VADDUWM	V10, V0, V0
+	LVX	(OFFLOAD)(HEX20), V12
+	VADDUWM	V11, V1, V1
+	LVX	(OFFLOAD)(HEX30), V13
+	VADDUWM	V12, V2, V2
+	LVX	(OFFLOAD)(HEX40), V14
+	VADDUWM	V13, V3, V3
+	LVX	(OFFLOAD)(HEX50), V15
+	VADDUWM	V14, V4, V4
+	LVX	(OFFLOAD)(HEX60), V16
+	VADDUWM	V15, V5, V5
+	LVX	(OFFLOAD)(HEX70), V17
+	VADDUWM	V16, V6, V6
+	VADDUWM	V17, V7, V7
+
+	CMPU	INP, END
 	BLT	loop
 
+	LVX	(TBL)(IDX), V8
+	ADD	$16, IDX
+	VPERM	V0, V1, KI, V0
+	LVX	(TBL)(IDX), V9
+	VPERM	V4, V5, KI, V4
+	VPERM	V0, V2, V8, V0
+	VPERM	V4, V6, V8, V4
+	VPERM	V0, V3, V9, V0
+	VPERM	V4, V7, V9, V4
+	STXVD2X	VS32, (CTX+HEX00)	// v0 = vs32
+	STXVD2X	VS36, (CTX+HEX10)	// v4 = vs36
+
 end:
 	RET
+
diff --git a/src/crypto/sha512/sha512block_amd64.go b/src/crypto/sha512/sha512block_amd64.go
new file mode 100644
index 0000000..18151ce
--- /dev/null
+++ b/src/crypto/sha512/sha512block_amd64.go
@@ -0,0 +1,25 @@
+// Copyright 2013 The Go Authors. 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 sha512
+
+import "internal/cpu"
+
+//go:noescape
+func blockAVX2(dig *digest, p []byte)
+
+//go:noescape
+func blockAMD64(dig *digest, p []byte)
+
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2
+
+func block(dig *digest, p []byte) {
+	if useAVX2 {
+		blockAVX2(dig, p)
+	} else {
+		blockAMD64(dig, p)
+	}
+}
diff --git a/src/crypto/sha512/sha512block_amd64.s b/src/crypto/sha512/sha512block_amd64.s
index 87502cd..5b42420 100644
--- a/src/crypto/sha512/sha512block_amd64.s
+++ b/src/crypto/sha512/sha512block_amd64.s
@@ -141,7 +141,7 @@
 	MSGSCHEDULE1(index); \
 	SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
 
-TEXT ·block(SB),0,$648-32
+TEXT ·blockAMD64(SB),0,$648-32
 	MOVQ	p_base+8(FP), SI
 	MOVQ	p_len+16(FP), DX
 	SHRQ	$7, DX
@@ -271,3 +271,1204 @@ loop:
 
 end:
 	RET
+
+// Version below is based on "Fast SHA512 Implementations on Intel
+// Architecture Processors" White-paper
+// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf
+// AVX2 version by Intel, same algorithm in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha512-avx2-asm.S
+
+// James Guilford <james.guilford at intel.com>
+// Kirk Yap <kirk.s.yap at intel.com>
+// Tim Chen <tim.c.chen at linux.intel.com>
+// David Cote <david.m.cote at intel.com>
+// Aleksey Sidorov <aleksey.sidorov at intel.com>
+
+#define YFER_SIZE (4*8)
+#define SRND_SIZE (1*8)
+#define INP_SIZE (1*8)
+
+#define frame_YFER (0)
+#define frame_SRND (frame_YFER + YFER_SIZE)
+#define frame_INP (frame_SRND + SRND_SIZE)
+#define frame_INPEND (frame_INP + INP_SIZE)
+
+#define addm(p1, p2) \
+	ADDQ p1, p2; \
+	MOVQ p2, p1
+
+#define COPY_YMM_AND_BSWAP(p1, p2, p3) \
+	VMOVDQU p2, p1;    \
+	VPSHUFB p3, p1, p1
+
+#define MY_VPALIGNR(YDST, YSRC1, YSRC2, RVAL) \
+	VPERM2F128 $0x3, YSRC2, YSRC1, YDST; \
+	VPALIGNR   $RVAL, YSRC2, YDST, YDST
+
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x00(SB)/8, $0x0001020304050607
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x08(SB)/8, $0x08090a0b0c0d0e0f
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x10(SB)/8, $0x1011121314151617
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x18(SB)/8, $0x18191a1b1c1d1e1f
+
+GLOBL PSHUFFLE_BYTE_FLIP_MASK<>(SB), (NOPTR+RODATA), $32
+
+DATA MASK_YMM_LO<>+0x00(SB)/8, $0x0000000000000000
+DATA MASK_YMM_LO<>+0x08(SB)/8, $0x0000000000000000
+DATA MASK_YMM_LO<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA MASK_YMM_LO<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+
+GLOBL MASK_YMM_LO<>(SB), (NOPTR+RODATA), $32
+
+TEXT ·blockAVX2(SB), NOSPLIT, $56-32
+	MOVQ dig+0(FP), SI
+	MOVQ p_base+8(FP), DI
+	MOVQ p_len+16(FP), DX
+
+	SHRQ $7, DX
+	SHLQ $7, DX
+
+	JZ   done_hash
+	ADDQ DI, DX
+	MOVQ DX, frame_INPEND(SP)
+
+	MOVQ (0*8)(SI), AX
+	MOVQ (1*8)(SI), BX
+	MOVQ (2*8)(SI), CX
+	MOVQ (3*8)(SI), R8
+	MOVQ (4*8)(SI), DX
+	MOVQ (5*8)(SI), R9
+	MOVQ (6*8)(SI), R10
+	MOVQ (7*8)(SI), R11
+
+	MOVQ    $PSHUFFLE_BYTE_FLIP_MASK<>(SB), R12
+	VMOVDQU (R12), Y9
+
+loop0:
+	MOVQ ·_K+0(SB), BP
+
+	// byte swap first 16 dwords
+	COPY_YMM_AND_BSWAP(Y4, (0*32)(DI), Y9)
+	COPY_YMM_AND_BSWAP(Y5, (1*32)(DI), Y9)
+	COPY_YMM_AND_BSWAP(Y6, (2*32)(DI), Y9)
+	COPY_YMM_AND_BSWAP(Y7, (3*32)(DI), Y9)
+
+	MOVQ DI, frame_INP(SP)
+
+	// schedule 64 input dwords, by doing 12 rounds of 4 each
+	MOVQ $4, frame_SRND(SP)
+
+loop1:
+	VPADDQ  (BP), Y4, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+
+	MY_VPALIGNR(Y0, Y7, Y6, 8)
+
+	VPADDQ Y4, Y0, Y0
+
+	MY_VPALIGNR(Y1, Y5, Y4, 8)
+
+	VPSRLQ $1, Y1, Y2
+	VPSLLQ $(64-1), Y1, Y3
+	VPOR   Y2, Y3, Y3
+
+	VPSRLQ $7, Y1, Y8
+
+	MOVQ  AX, DI
+	RORXQ $41, DX, R13
+	RORXQ $18, DX, R14
+	ADDQ  frame_YFER(SP), R11
+	ORQ   CX, DI
+	MOVQ  R9, R15
+	RORXQ $34, AX, R12
+
+	XORQ  R14, R13
+	XORQ  R10, R15
+	RORXQ $14, DX, R14
+
+	ANDQ  DX, R15
+	XORQ  R14, R13
+	RORXQ $39, AX, R14
+	ADDQ  R11, R8
+
+	ANDQ  BX, DI
+	XORQ  R12, R14
+	RORXQ $28, AX, R12
+
+	XORQ R10, R15
+	XORQ R12, R14
+	MOVQ AX, R12
+	ANDQ CX, R12
+
+	ADDQ R13, R15
+	ORQ  R12, DI
+	ADDQ R14, R11
+
+	ADDQ R15, R8
+
+	ADDQ R15, R11
+	ADDQ DI, R11
+
+	VPSRLQ $8, Y1, Y2
+	VPSLLQ $(64-8), Y1, Y1
+	VPOR   Y2, Y1, Y1
+
+	VPXOR Y8, Y3, Y3
+	VPXOR Y1, Y3, Y1
+
+	VPADDQ Y1, Y0, Y0
+
+	VPERM2F128 $0x0, Y0, Y0, Y4
+
+	MOVQ $MASK_YMM_LO<>(SB), R13
+
+	VPAND (R13), Y0, Y0
+
+	VPERM2F128 $0x11, Y7, Y7, Y2
+	VPSRLQ     $6, Y2, Y8
+
+	MOVQ  R11, DI
+	RORXQ $41, R8, R13
+	RORXQ $18, R8, R14
+	ADDQ  1*8+frame_YFER(SP), R10
+	ORQ   BX, DI
+
+	MOVQ  DX, R15
+	RORXQ $34, R11, R12
+	XORQ  R14, R13
+	XORQ  R9, R15
+
+	RORXQ $14, R8, R14
+	XORQ  R14, R13
+	RORXQ $39, R11, R14
+	ANDQ  R8, R15
+	ADDQ  R10, CX
+
+	ANDQ AX, DI
+	XORQ R12, R14
+
+	RORXQ $28, R11, R12
+	XORQ  R9, R15
+
+	XORQ R12, R14
+	MOVQ R11, R12
+	ANDQ BX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, R10
+
+	ADDQ R15, CX
+	ADDQ R15, R10
+	ADDQ DI, R10
+
+	VPSRLQ $19, Y2, Y3
+	VPSLLQ $(64-19), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y2, Y3
+	VPSLLQ $(64-61), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y4, Y4
+
+	VPSRLQ $6, Y4, Y8
+
+	MOVQ  R10, DI
+	RORXQ $41, CX, R13
+	ADDQ  2*8+frame_YFER(SP), R9
+
+	RORXQ $18, CX, R14
+	ORQ   AX, DI
+	MOVQ  R8, R15
+	XORQ  DX, R15
+
+	RORXQ $34, R10, R12
+	XORQ  R14, R13
+	ANDQ  CX, R15
+
+	RORXQ $14, CX, R14
+	ADDQ  R9, BX
+	ANDQ  R11, DI
+
+	XORQ  R14, R13
+	RORXQ $39, R10, R14
+	XORQ  DX, R15
+
+	XORQ  R12, R14
+	RORXQ $28, R10, R12
+
+	XORQ R12, R14
+	MOVQ R10, R12
+	ANDQ AX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, R9
+	ADDQ R15, BX
+	ADDQ R15, R9
+
+	ADDQ DI, R9
+
+	VPSRLQ $19, Y4, Y3
+	VPSLLQ $(64-19), Y4, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y4, Y3
+	VPSLLQ $(64-61), Y4, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y0, Y2
+
+	VPBLENDD $0xF0, Y2, Y4, Y4
+
+	MOVQ  R9, DI
+	RORXQ $41, BX, R13
+	RORXQ $18, BX, R14
+	ADDQ  3*8+frame_YFER(SP), DX
+	ORQ   R11, DI
+
+	MOVQ  CX, R15
+	RORXQ $34, R9, R12
+	XORQ  R14, R13
+	XORQ  R8, R15
+
+	RORXQ $14, BX, R14
+	ANDQ  BX, R15
+	ADDQ  DX, AX
+	ANDQ  R10, DI
+
+	XORQ R14, R13
+	XORQ R8, R15
+
+	RORXQ $39, R9, R14
+	ADDQ  R13, R15
+
+	XORQ R12, R14
+	ADDQ R15, AX
+
+	RORXQ $28, R9, R12
+
+	XORQ R12, R14
+	MOVQ R9, R12
+	ANDQ R11, R12
+	ORQ  R12, DI
+
+	ADDQ R14, DX
+	ADDQ R15, DX
+	ADDQ DI, DX
+
+	VPADDQ  1*32(BP), Y5, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+
+	MY_VPALIGNR(Y0, Y4, Y7, 8)
+
+	VPADDQ Y5, Y0, Y0
+
+	MY_VPALIGNR(Y1, Y6, Y5, 8)
+
+	VPSRLQ $1, Y1, Y2
+	VPSLLQ $(64-1), Y1, Y3
+	VPOR   Y2, Y3, Y3
+
+	VPSRLQ $7, Y1, Y8
+
+	MOVQ  DX, DI
+	RORXQ $41, AX, R13
+	RORXQ $18, AX, R14
+	ADDQ  frame_YFER(SP), R8
+	ORQ   R10, DI
+	MOVQ  BX, R15
+	RORXQ $34, DX, R12
+
+	XORQ  R14, R13
+	XORQ  CX, R15
+	RORXQ $14, AX, R14
+
+	ANDQ  AX, R15
+	XORQ  R14, R13
+	RORXQ $39, DX, R14
+	ADDQ  R8, R11
+
+	ANDQ  R9, DI
+	XORQ  R12, R14
+	RORXQ $28, DX, R12
+
+	XORQ CX, R15
+	XORQ R12, R14
+	MOVQ DX, R12
+	ANDQ R10, R12
+
+	ADDQ R13, R15
+	ORQ  R12, DI
+	ADDQ R14, R8
+
+	ADDQ R15, R11
+
+	ADDQ R15, R8
+	ADDQ DI, R8
+
+	VPSRLQ $8, Y1, Y2
+	VPSLLQ $(64-8), Y1, Y1
+	VPOR   Y2, Y1, Y1
+
+	VPXOR Y8, Y3, Y3
+	VPXOR Y1, Y3, Y1
+
+	VPADDQ Y1, Y0, Y0
+
+	VPERM2F128 $0x0, Y0, Y0, Y5
+
+	MOVQ  $MASK_YMM_LO<>(SB), R13
+	VPAND (R13), Y0, Y0
+
+	VPERM2F128 $0x11, Y4, Y4, Y2
+	VPSRLQ     $6, Y2, Y8
+
+	MOVQ  R8, DI
+	RORXQ $41, R11, R13
+	RORXQ $18, R11, R14
+	ADDQ  1*8+frame_YFER(SP), CX
+	ORQ   R9, DI
+
+	MOVQ  AX, R15
+	RORXQ $34, R8, R12
+	XORQ  R14, R13
+	XORQ  BX, R15
+
+	RORXQ $14, R11, R14
+	XORQ  R14, R13
+	RORXQ $39, R8, R14
+	ANDQ  R11, R15
+	ADDQ  CX, R10
+
+	ANDQ DX, DI
+	XORQ R12, R14
+
+	RORXQ $28, R8, R12
+	XORQ  BX, R15
+
+	XORQ R12, R14
+	MOVQ R8, R12
+	ANDQ R9, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, CX
+
+	ADDQ R15, R10
+	ADDQ R15, CX
+	ADDQ DI, CX
+
+	VPSRLQ $19, Y2, Y3
+	VPSLLQ $(64-19), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y2, Y3
+	VPSLLQ $(64-61), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y5, Y5
+
+	VPSRLQ $6, Y5, Y8
+
+	MOVQ  CX, DI
+	RORXQ $41, R10, R13
+	ADDQ  2*8+frame_YFER(SP), BX
+
+	RORXQ $18, R10, R14
+	ORQ   DX, DI
+	MOVQ  R11, R15
+	XORQ  AX, R15
+
+	RORXQ $34, CX, R12
+	XORQ  R14, R13
+	ANDQ  R10, R15
+
+	RORXQ $14, R10, R14
+	ADDQ  BX, R9
+	ANDQ  R8, DI
+
+	XORQ  R14, R13
+	RORXQ $39, CX, R14
+	XORQ  AX, R15
+
+	XORQ  R12, R14
+	RORXQ $28, CX, R12
+
+	XORQ R12, R14
+	MOVQ CX, R12
+	ANDQ DX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, BX
+	ADDQ R15, R9
+	ADDQ R15, BX
+
+	ADDQ DI, BX
+
+	VPSRLQ $19, Y5, Y3
+	VPSLLQ $(64-19), Y5, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y5, Y3
+	VPSLLQ $(64-61), Y5, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y0, Y2
+
+	VPBLENDD $0xF0, Y2, Y5, Y5
+
+	MOVQ  BX, DI
+	RORXQ $41, R9, R13
+	RORXQ $18, R9, R14
+	ADDQ  3*8+frame_YFER(SP), AX
+	ORQ   R8, DI
+
+	MOVQ  R10, R15
+	RORXQ $34, BX, R12
+	XORQ  R14, R13
+	XORQ  R11, R15
+
+	RORXQ $14, R9, R14
+	ANDQ  R9, R15
+	ADDQ  AX, DX
+	ANDQ  CX, DI
+
+	XORQ R14, R13
+	XORQ R11, R15
+
+	RORXQ $39, BX, R14
+	ADDQ  R13, R15
+
+	XORQ R12, R14
+	ADDQ R15, DX
+
+	RORXQ $28, BX, R12
+
+	XORQ R12, R14
+	MOVQ BX, R12
+	ANDQ R8, R12
+	ORQ  R12, DI
+
+	ADDQ R14, AX
+	ADDQ R15, AX
+	ADDQ DI, AX
+
+	VPADDQ  2*32(BP), Y6, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+
+	MY_VPALIGNR(Y0, Y5, Y4, 8)
+
+	VPADDQ Y6, Y0, Y0
+
+	MY_VPALIGNR(Y1, Y7, Y6, 8)
+
+	VPSRLQ $1, Y1, Y2
+	VPSLLQ $(64-1), Y1, Y3
+	VPOR   Y2, Y3, Y3
+
+	VPSRLQ $7, Y1, Y8
+
+	MOVQ  AX, DI
+	RORXQ $41, DX, R13
+	RORXQ $18, DX, R14
+	ADDQ  frame_YFER(SP), R11
+	ORQ   CX, DI
+	MOVQ  R9, R15
+	RORXQ $34, AX, R12
+
+	XORQ  R14, R13
+	XORQ  R10, R15
+	RORXQ $14, DX, R14
+
+	ANDQ  DX, R15
+	XORQ  R14, R13
+	RORXQ $39, AX, R14
+	ADDQ  R11, R8
+
+	ANDQ  BX, DI
+	XORQ  R12, R14
+	RORXQ $28, AX, R12
+
+	XORQ R10, R15
+	XORQ R12, R14
+	MOVQ AX, R12
+	ANDQ CX, R12
+
+	ADDQ R13, R15
+	ORQ  R12, DI
+	ADDQ R14, R11
+
+	ADDQ R15, R8
+
+	ADDQ R15, R11
+	ADDQ DI, R11
+
+	VPSRLQ $8, Y1, Y2
+	VPSLLQ $(64-8), Y1, Y1
+	VPOR   Y2, Y1, Y1
+
+	VPXOR Y8, Y3, Y3
+	VPXOR Y1, Y3, Y1
+
+	VPADDQ Y1, Y0, Y0
+
+	VPERM2F128 $0x0, Y0, Y0, Y6
+
+	MOVQ  $MASK_YMM_LO<>(SB), R13
+	VPAND (R13), Y0, Y0
+
+	VPERM2F128 $0x11, Y5, Y5, Y2
+	VPSRLQ     $6, Y2, Y8
+
+	MOVQ  R11, DI
+	RORXQ $41, R8, R13
+	RORXQ $18, R8, R14
+	ADDQ  1*8+frame_YFER(SP), R10
+	ORQ   BX, DI
+
+	MOVQ  DX, R15
+	RORXQ $34, R11, R12
+	XORQ  R14, R13
+	XORQ  R9, R15
+
+	RORXQ $14, R8, R14
+	XORQ  R14, R13
+	RORXQ $39, R11, R14
+	ANDQ  R8, R15
+	ADDQ  R10, CX
+
+	ANDQ AX, DI
+	XORQ R12, R14
+
+	RORXQ $28, R11, R12
+	XORQ  R9, R15
+
+	XORQ R12, R14
+	MOVQ R11, R12
+	ANDQ BX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, R10
+
+	ADDQ R15, CX
+	ADDQ R15, R10
+	ADDQ DI, R10
+
+	VPSRLQ $19, Y2, Y3
+	VPSLLQ $(64-19), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y2, Y3
+	VPSLLQ $(64-61), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y6, Y6
+
+	VPSRLQ $6, Y6, Y8
+
+	MOVQ  R10, DI
+	RORXQ $41, CX, R13
+	ADDQ  2*8+frame_YFER(SP), R9
+
+	RORXQ $18, CX, R14
+	ORQ   AX, DI
+	MOVQ  R8, R15
+	XORQ  DX, R15
+
+	RORXQ $34, R10, R12
+	XORQ  R14, R13
+	ANDQ  CX, R15
+
+	RORXQ $14, CX, R14
+	ADDQ  R9, BX
+	ANDQ  R11, DI
+
+	XORQ  R14, R13
+	RORXQ $39, R10, R14
+	XORQ  DX, R15
+
+	XORQ  R12, R14
+	RORXQ $28, R10, R12
+
+	XORQ R12, R14
+	MOVQ R10, R12
+	ANDQ AX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, R9
+	ADDQ R15, BX
+	ADDQ R15, R9
+
+	ADDQ DI, R9
+
+	VPSRLQ $19, Y6, Y3
+	VPSLLQ $(64-19), Y6, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y6, Y3
+	VPSLLQ $(64-61), Y6, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y0, Y2
+
+	VPBLENDD $0xF0, Y2, Y6, Y6
+
+	MOVQ  R9, DI
+	RORXQ $41, BX, R13
+	RORXQ $18, BX, R14
+	ADDQ  3*8+frame_YFER(SP), DX
+	ORQ   R11, DI
+
+	MOVQ  CX, R15
+	RORXQ $34, R9, R12
+	XORQ  R14, R13
+	XORQ  R8, R15
+
+	RORXQ $14, BX, R14
+	ANDQ  BX, R15
+	ADDQ  DX, AX
+	ANDQ  R10, DI
+
+	XORQ R14, R13
+	XORQ R8, R15
+
+	RORXQ $39, R9, R14
+	ADDQ  R13, R15
+
+	XORQ R12, R14
+	ADDQ R15, AX
+
+	RORXQ $28, R9, R12
+
+	XORQ R12, R14
+	MOVQ R9, R12
+	ANDQ R11, R12
+	ORQ  R12, DI
+
+	ADDQ R14, DX
+	ADDQ R15, DX
+	ADDQ DI, DX
+
+	VPADDQ  3*32(BP), Y7, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+	ADDQ    $(4*32), BP
+
+	MY_VPALIGNR(Y0, Y6, Y5, 8)
+
+	VPADDQ Y7, Y0, Y0
+
+	MY_VPALIGNR(Y1, Y4, Y7, 8)
+
+	VPSRLQ $1, Y1, Y2
+	VPSLLQ $(64-1), Y1, Y3
+	VPOR   Y2, Y3, Y3
+
+	VPSRLQ $7, Y1, Y8
+
+	MOVQ  DX, DI
+	RORXQ $41, AX, R13
+	RORXQ $18, AX, R14
+	ADDQ  frame_YFER(SP), R8
+	ORQ   R10, DI
+	MOVQ  BX, R15
+	RORXQ $34, DX, R12
+
+	XORQ  R14, R13
+	XORQ  CX, R15
+	RORXQ $14, AX, R14
+
+	ANDQ  AX, R15
+	XORQ  R14, R13
+	RORXQ $39, DX, R14
+	ADDQ  R8, R11
+
+	ANDQ  R9, DI
+	XORQ  R12, R14
+	RORXQ $28, DX, R12
+
+	XORQ CX, R15
+	XORQ R12, R14
+	MOVQ DX, R12
+	ANDQ R10, R12
+
+	ADDQ R13, R15
+	ORQ  R12, DI
+	ADDQ R14, R8
+
+	ADDQ R15, R11
+
+	ADDQ R15, R8
+	ADDQ DI, R8
+
+	VPSRLQ $8, Y1, Y2
+	VPSLLQ $(64-8), Y1, Y1
+	VPOR   Y2, Y1, Y1
+
+	VPXOR Y8, Y3, Y3
+	VPXOR Y1, Y3, Y1
+
+	VPADDQ Y1, Y0, Y0
+
+	VPERM2F128 $0x0, Y0, Y0, Y7
+
+	MOVQ  $MASK_YMM_LO<>(SB), R13
+	VPAND (R13), Y0, Y0
+
+	VPERM2F128 $0x11, Y6, Y6, Y2
+	VPSRLQ     $6, Y2, Y8
+
+	MOVQ  R8, DI
+	RORXQ $41, R11, R13
+	RORXQ $18, R11, R14
+	ADDQ  1*8+frame_YFER(SP), CX
+	ORQ   R9, DI
+
+	MOVQ  AX, R15
+	RORXQ $34, R8, R12
+	XORQ  R14, R13
+	XORQ  BX, R15
+
+	RORXQ $14, R11, R14
+	XORQ  R14, R13
+	RORXQ $39, R8, R14
+	ANDQ  R11, R15
+	ADDQ  CX, R10
+
+	ANDQ DX, DI
+	XORQ R12, R14
+
+	RORXQ $28, R8, R12
+	XORQ  BX, R15
+
+	XORQ R12, R14
+	MOVQ R8, R12
+	ANDQ R9, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, CX
+
+	ADDQ R15, R10
+	ADDQ R15, CX
+	ADDQ DI, CX
+
+	VPSRLQ $19, Y2, Y3
+	VPSLLQ $(64-19), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y2, Y3
+	VPSLLQ $(64-61), Y2, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y7, Y7
+
+	VPSRLQ $6, Y7, Y8
+
+	MOVQ  CX, DI
+	RORXQ $41, R10, R13
+	ADDQ  2*8+frame_YFER(SP), BX
+
+	RORXQ $18, R10, R14
+	ORQ   DX, DI
+	MOVQ  R11, R15
+	XORQ  AX, R15
+
+	RORXQ $34, CX, R12
+	XORQ  R14, R13
+	ANDQ  R10, R15
+
+	RORXQ $14, R10, R14
+	ADDQ  BX, R9
+	ANDQ  R8, DI
+
+	XORQ  R14, R13
+	RORXQ $39, CX, R14
+	XORQ  AX, R15
+
+	XORQ  R12, R14
+	RORXQ $28, CX, R12
+
+	XORQ R12, R14
+	MOVQ CX, R12
+	ANDQ DX, R12
+	ADDQ R13, R15
+
+	ORQ  R12, DI
+	ADDQ R14, BX
+	ADDQ R15, R9
+	ADDQ R15, BX
+
+	ADDQ DI, BX
+
+	VPSRLQ $19, Y7, Y3
+	VPSLLQ $(64-19), Y7, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+	VPSRLQ $61, Y7, Y3
+	VPSLLQ $(64-61), Y7, Y1
+	VPOR   Y1, Y3, Y3
+	VPXOR  Y3, Y8, Y8
+
+	VPADDQ Y8, Y0, Y2
+
+	VPBLENDD $0xF0, Y2, Y7, Y7
+
+	MOVQ  BX, DI
+	RORXQ $41, R9, R13
+	RORXQ $18, R9, R14
+	ADDQ  3*8+frame_YFER(SP), AX
+	ORQ   R8, DI
+
+	MOVQ  R10, R15
+	RORXQ $34, BX, R12
+	XORQ  R14, R13
+	XORQ  R11, R15
+
+	RORXQ $14, R9, R14
+	ANDQ  R9, R15
+	ADDQ  AX, DX
+	ANDQ  CX, DI
+
+	XORQ R14, R13
+	XORQ R11, R15
+
+	RORXQ $39, BX, R14
+	ADDQ  R13, R15
+
+	XORQ R12, R14
+	ADDQ R15, DX
+
+	RORXQ $28, BX, R12
+
+	XORQ R12, R14
+	MOVQ BX, R12
+	ANDQ R8, R12
+	ORQ  R12, DI
+
+	ADDQ R14, AX
+	ADDQ R15, AX
+	ADDQ DI, AX
+
+	SUBQ $1, frame_SRND(SP)
+	JNE  loop1
+
+	MOVQ $2, frame_SRND(SP)
+
+loop2:
+	VPADDQ  (BP), Y4, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+
+	MOVQ  R9, R15
+	RORXQ $41, DX, R13
+	RORXQ $18, DX, R14
+	XORQ  R10, R15
+
+	XORQ  R14, R13
+	RORXQ $14, DX, R14
+	ANDQ  DX, R15
+
+	XORQ  R14, R13
+	RORXQ $34, AX, R12
+	XORQ  R10, R15
+	RORXQ $39, AX, R14
+	MOVQ  AX, DI
+
+	XORQ  R12, R14
+	RORXQ $28, AX, R12
+	ADDQ  frame_YFER(SP), R11
+	ORQ   CX, DI
+
+	XORQ R12, R14
+	MOVQ AX, R12
+	ANDQ BX, DI
+	ANDQ CX, R12
+	ADDQ R13, R15
+
+	ADDQ R11, R8
+	ORQ  R12, DI
+	ADDQ R14, R11
+
+	ADDQ R15, R8
+
+	ADDQ  R15, R11
+	MOVQ  DX, R15
+	RORXQ $41, R8, R13
+	RORXQ $18, R8, R14
+	XORQ  R9, R15
+
+	XORQ  R14, R13
+	RORXQ $14, R8, R14
+	ANDQ  R8, R15
+	ADDQ  DI, R11
+
+	XORQ  R14, R13
+	RORXQ $34, R11, R12
+	XORQ  R9, R15
+	RORXQ $39, R11, R14
+	MOVQ  R11, DI
+
+	XORQ  R12, R14
+	RORXQ $28, R11, R12
+	ADDQ  8*1+frame_YFER(SP), R10
+	ORQ   BX, DI
+
+	XORQ R12, R14
+	MOVQ R11, R12
+	ANDQ AX, DI
+	ANDQ BX, R12
+	ADDQ R13, R15
+
+	ADDQ R10, CX
+	ORQ  R12, DI
+	ADDQ R14, R10
+
+	ADDQ R15, CX
+
+	ADDQ  R15, R10
+	MOVQ  R8, R15
+	RORXQ $41, CX, R13
+	RORXQ $18, CX, R14
+	XORQ  DX, R15
+
+	XORQ  R14, R13
+	RORXQ $14, CX, R14
+	ANDQ  CX, R15
+	ADDQ  DI, R10
+
+	XORQ  R14, R13
+	RORXQ $34, R10, R12
+	XORQ  DX, R15
+	RORXQ $39, R10, R14
+	MOVQ  R10, DI
+
+	XORQ  R12, R14
+	RORXQ $28, R10, R12
+	ADDQ  8*2+frame_YFER(SP), R9
+	ORQ   AX, DI
+
+	XORQ R12, R14
+	MOVQ R10, R12
+	ANDQ R11, DI
+	ANDQ AX, R12
+	ADDQ R13, R15
+
+	ADDQ R9, BX
+	ORQ  R12, DI
+	ADDQ R14, R9
+
+	ADDQ R15, BX
+
+	ADDQ  R15, R9
+	MOVQ  CX, R15
+	RORXQ $41, BX, R13
+	RORXQ $18, BX, R14
+	XORQ  R8, R15
+
+	XORQ  R14, R13
+	RORXQ $14, BX, R14
+	ANDQ  BX, R15
+	ADDQ  DI, R9
+
+	XORQ  R14, R13
+	RORXQ $34, R9, R12
+	XORQ  R8, R15
+	RORXQ $39, R9, R14
+	MOVQ  R9, DI
+
+	XORQ  R12, R14
+	RORXQ $28, R9, R12
+	ADDQ  8*3+frame_YFER(SP), DX
+	ORQ   R11, DI
+
+	XORQ R12, R14
+	MOVQ R9, R12
+	ANDQ R10, DI
+	ANDQ R11, R12
+	ADDQ R13, R15
+
+	ADDQ DX, AX
+	ORQ  R12, DI
+	ADDQ R14, DX
+
+	ADDQ R15, AX
+
+	ADDQ R15, DX
+
+	ADDQ DI, DX
+
+	VPADDQ  1*32(BP), Y5, Y0
+	VMOVDQU Y0, frame_YFER(SP)
+	ADDQ    $(2*32), BP
+
+	MOVQ  BX, R15
+	RORXQ $41, AX, R13
+	RORXQ $18, AX, R14
+	XORQ  CX, R15
+
+	XORQ  R14, R13
+	RORXQ $14, AX, R14
+	ANDQ  AX, R15
+
+	XORQ  R14, R13
+	RORXQ $34, DX, R12
+	XORQ  CX, R15
+	RORXQ $39, DX, R14
+	MOVQ  DX, DI
+
+	XORQ  R12, R14
+	RORXQ $28, DX, R12
+	ADDQ  frame_YFER(SP), R8
+	ORQ   R10, DI
+
+	XORQ R12, R14
+	MOVQ DX, R12
+	ANDQ R9, DI
+	ANDQ R10, R12
+	ADDQ R13, R15
+
+	ADDQ R8, R11
+	ORQ  R12, DI
+	ADDQ R14, R8
+
+	ADDQ R15, R11
+
+	ADDQ  R15, R8
+	MOVQ  AX, R15
+	RORXQ $41, R11, R13
+	RORXQ $18, R11, R14
+	XORQ  BX, R15
+
+	XORQ  R14, R13
+	RORXQ $14, R11, R14
+	ANDQ  R11, R15
+	ADDQ  DI, R8
+
+	XORQ  R14, R13
+	RORXQ $34, R8, R12
+	XORQ  BX, R15
+	RORXQ $39, R8, R14
+	MOVQ  R8, DI
+
+	XORQ  R12, R14
+	RORXQ $28, R8, R12
+	ADDQ  8*1+frame_YFER(SP), CX
+	ORQ   R9, DI
+
+	XORQ R12, R14
+	MOVQ R8, R12
+	ANDQ DX, DI
+	ANDQ R9, R12
+	ADDQ R13, R15
+
+	ADDQ CX, R10
+	ORQ  R12, DI
+	ADDQ R14, CX
+
+	ADDQ R15, R10
+
+	ADDQ  R15, CX
+	MOVQ  R11, R15
+	RORXQ $41, R10, R13
+	RORXQ $18, R10, R14
+	XORQ  AX, R15
+
+	XORQ  R14, R13
+	RORXQ $14, R10, R14
+	ANDQ  R10, R15
+	ADDQ  DI, CX
+
+	XORQ  R14, R13
+	RORXQ $34, CX, R12
+	XORQ  AX, R15
+	RORXQ $39, CX, R14
+	MOVQ  CX, DI
+
+	XORQ  R12, R14
+	RORXQ $28, CX, R12
+	ADDQ  8*2+frame_YFER(SP), BX
+	ORQ   DX, DI
+
+	XORQ R12, R14
+	MOVQ CX, R12
+	ANDQ R8, DI
+	ANDQ DX, R12
+	ADDQ R13, R15
+
+	ADDQ BX, R9
+	ORQ  R12, DI
+	ADDQ R14, BX
+
+	ADDQ R15, R9
+
+	ADDQ  R15, BX
+	MOVQ  R10, R15
+	RORXQ $41, R9, R13
+	RORXQ $18, R9, R14
+	XORQ  R11, R15
+
+	XORQ  R14, R13
+	RORXQ $14, R9, R14
+	ANDQ  R9, R15
+	ADDQ  DI, BX
+
+	XORQ  R14, R13
+	RORXQ $34, BX, R12
+	XORQ  R11, R15
+	RORXQ $39, BX, R14
+	MOVQ  BX, DI
+
+	XORQ  R12, R14
+	RORXQ $28, BX, R12
+	ADDQ  8*3+frame_YFER(SP), AX
+	ORQ   R8, DI
+
+	XORQ R12, R14
+	MOVQ BX, R12
+	ANDQ CX, DI
+	ANDQ R8, R12
+	ADDQ R13, R15
+
+	ADDQ AX, DX
+	ORQ  R12, DI
+	ADDQ R14, AX
+
+	ADDQ R15, DX
+
+	ADDQ R15, AX
+
+	ADDQ DI, AX
+
+	VMOVDQU Y6, Y4
+	VMOVDQU Y7, Y5
+
+	SUBQ $1, frame_SRND(SP)
+	JNE  loop2
+
+	addm(8*0(SI),AX)
+	addm(8*1(SI),BX)
+	addm(8*2(SI),CX)
+	addm(8*3(SI),R8)
+	addm(8*4(SI),DX)
+	addm(8*5(SI),R9)
+	addm(8*6(SI),R10)
+	addm(8*7(SI),R11)
+
+	MOVQ frame_INP(SP), DI
+	ADDQ $128, DI
+	CMPQ DI, frame_INPEND(SP)
+	JNE  loop0
+
+done_hash:
+	VZEROUPPER
+	RET
diff --git a/src/crypto/sha512/sha512block_decl.go b/src/crypto/sha512/sha512block_decl.go
index 8194506..613d1e0 100644
--- a/src/crypto/sha512/sha512block_decl.go
+++ b/src/crypto/sha512/sha512block_decl.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 s390x ppc64le
+// +build s390x ppc64le
 
 package sha512
 
diff --git a/src/crypto/sha512/sha512block_ppc64le.s b/src/crypto/sha512/sha512block_ppc64le.s
index 7b338d8..4419c00 100644
--- a/src/crypto/sha512/sha512block_ppc64le.s
+++ b/src/crypto/sha512/sha512block_ppc64le.s
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This is a derived work from OpenSSL of SHA-2 using assembly optimizations. The
+// original code was written by Andy Polyakov <appro at openssl.org> and it's dual
+// licensed under OpenSSL and CRYPTOGAMS licenses depending on where you obtain
+// it. For further details see http://www.openssl.org/~appro/cryptogams/.
+
 #include "textflag.h"
 
 // SHA512 block routine. See sha512block.go for Go equivalent.
@@ -44,250 +49,400 @@
 // H6 = g + H6
 // H7 = h + H7
 
-// Wt = Mt; for 0 <= t <= 15
-#define MSGSCHEDULE0(index) \
-	MOVD	(index*8)(R6), R14; \
-	RLWNM	$24, R14, $-1, R21; \
-	RLWMI	$8, R14, $0x00FF0000, R21; \
-	RLWMI	$8, R14, $0x000000FF, R21; \
-	SLD	$32, R21; \
-	SRD	$32, R14, R20; \
-	RLWNM	$24, R20, $-1, R14; \
-	RLWMI	$8, R20, $0x00FF0000, R14; \
-	RLWMI	$8, R20, $0x000000FF, R14; \
-	OR	R21, R14; \
-	MOVD	R14, (index*8)(R9)
-
-// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
-//   SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x)
-//   SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x)
-#define MSGSCHEDULE1(index) \
-	MOVD	((index-2)*8)(R9), R14; \
-	MOVD	R14, R16; \
-	RLDCL	$64-19, R14, $-1, R14; \
-	MOVD	R16, R17; \
-	RLDCL	$64-61, R16, $-1, R16; \
-	SRD	$6, R17; \
-	MOVD	((index-15)*8)(R9), R15; \
-	XOR	R16, R14; \
-	MOVD	R15, R16; \
-	XOR	R17, R14; \
-	RLDCL	$64-1, R15, $-1, R15; \
-	MOVD	R16, R17; \
-	SRD	$7, R17; \
-	RLDCL	$64-8, R16, $-1, R16; \
-	MOVD	((index-7)*8)(R9), R21; \
-	ADD	R21, R14; \
-	XOR	R16, R15; \
-	XOR	R17, R15; \
-	MOVD	((index-16)*8)(R9), R21; \
-	ADD	R21, R15; \
-	ADD	R15, R14; \
-	MOVD	R14, ((index)*8)(R9)
+#define CTX	R3
+#define INP	R4
+#define END	R5
+#define TBL	R6
+#define IDX	R7
+#define CNT	R8
+#define LEN	R9
+#define OFFLOAD	R11
+#define TEMP	R12
 
-// Calculate T1 in R14 - uses R14, R16 and R17 registers.
-// h is also used as an accumulator. Wt is passed in R14.
-//   T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
-//     BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x)
-//     Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
-#define SHA512T1(const, e, f, g, h) \
-	MOVD	$const, R17; \
-	ADD	R14, h; \
-	MOVD	e, R14; \
-	ADD	R17, h; \
-	MOVD	e, R16; \
-	RLDCL	$64-14, R14, $-1, R14; \
-	MOVD	e, R17; \
-	RLDCL	$64-18, R16, $-1, R16; \
-	XOR	R16, R14; \
-	MOVD	e, R16; \
-	RLDCL	$64-41, R17, $-1, R17; \
-	AND	f, R16; \
-	XOR	R14, R17; \
-	MOVD	e, R14; \
-	NOR	R14, R14, R14; \
-	ADD	R17, h; \
-	AND	g, R14; \
-	XOR	R16, R14; \
-	ADD	h, R14
+#define HEX00	R0
+#define HEX10	R10
+#define HEX20	R25
+#define HEX30	R26
+#define HEX40	R27
+#define HEX50	R28
+#define HEX60	R29
+#define HEX70	R31
 
-// Calculate T2 in R15 - uses R15, R16, R17 and R8 registers.
-//   T2 = BIGSIGMA0(a) + Maj(a, b, c)
-//     BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x)
-//     Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
-#define SHA512T2(a, b, c) \
-	MOVD	a, R8; \
-	MOVD	c, R15; \
-	RLDCL	$64-28, R8, $-1, R8; \
-	MOVD	a, R17; \
-	AND	b, R15; \
-	RLDCL	$64-34, R17, $-1, R17; \
-	MOVD	a, R16; \
-	AND	c, R16; \
-	XOR	R17, R8; \
-	XOR	R16, R15; \
-	MOVD	a, R17; \
-	MOVD	b, R16; \
-	RLDCL	$64-39, R17, $-1, R17; \
-	AND	a, R16; \
-	XOR	R16, R15; \
-	XOR	R17, R8; \
-	ADD	R8, R15
+// V0-V7 are A-H
+// V8-V23 are used for the message schedule
+#define KI	V24
+#define FUNC	V25
+#define S0	V26
+#define S1	V27
+#define s0	V28
+#define s1	V29
+#define LEMASK	V31	// Permutation control register for little endian
 
-// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
-// The values for e and a are stored in d and h, ready for rotation.
-#define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \
-	SHA512T1(const, e, f, g, h); \
-	SHA512T2(a, b, c); \
-	MOVD	R15, h; \
-	ADD	R14, d; \
-	ADD	R14, h
+// 2 copies of each Kt, to fill both doublewords of a vector register
+DATA  ·kcon+0x000(SB)/8, $0x428a2f98d728ae22
+DATA  ·kcon+0x008(SB)/8, $0x428a2f98d728ae22
+DATA  ·kcon+0x010(SB)/8, $0x7137449123ef65cd
+DATA  ·kcon+0x018(SB)/8, $0x7137449123ef65cd
+DATA  ·kcon+0x020(SB)/8, $0xb5c0fbcfec4d3b2f
+DATA  ·kcon+0x028(SB)/8, $0xb5c0fbcfec4d3b2f
+DATA  ·kcon+0x030(SB)/8, $0xe9b5dba58189dbbc
+DATA  ·kcon+0x038(SB)/8, $0xe9b5dba58189dbbc
+DATA  ·kcon+0x040(SB)/8, $0x3956c25bf348b538
+DATA  ·kcon+0x048(SB)/8, $0x3956c25bf348b538
+DATA  ·kcon+0x050(SB)/8, $0x59f111f1b605d019
+DATA  ·kcon+0x058(SB)/8, $0x59f111f1b605d019
+DATA  ·kcon+0x060(SB)/8, $0x923f82a4af194f9b
+DATA  ·kcon+0x068(SB)/8, $0x923f82a4af194f9b
+DATA  ·kcon+0x070(SB)/8, $0xab1c5ed5da6d8118
+DATA  ·kcon+0x078(SB)/8, $0xab1c5ed5da6d8118
+DATA  ·kcon+0x080(SB)/8, $0xd807aa98a3030242
+DATA  ·kcon+0x088(SB)/8, $0xd807aa98a3030242
+DATA  ·kcon+0x090(SB)/8, $0x12835b0145706fbe
+DATA  ·kcon+0x098(SB)/8, $0x12835b0145706fbe
+DATA  ·kcon+0x0A0(SB)/8, $0x243185be4ee4b28c
+DATA  ·kcon+0x0A8(SB)/8, $0x243185be4ee4b28c
+DATA  ·kcon+0x0B0(SB)/8, $0x550c7dc3d5ffb4e2
+DATA  ·kcon+0x0B8(SB)/8, $0x550c7dc3d5ffb4e2
+DATA  ·kcon+0x0C0(SB)/8, $0x72be5d74f27b896f
+DATA  ·kcon+0x0C8(SB)/8, $0x72be5d74f27b896f
+DATA  ·kcon+0x0D0(SB)/8, $0x80deb1fe3b1696b1
+DATA  ·kcon+0x0D8(SB)/8, $0x80deb1fe3b1696b1
+DATA  ·kcon+0x0E0(SB)/8, $0x9bdc06a725c71235
+DATA  ·kcon+0x0E8(SB)/8, $0x9bdc06a725c71235
+DATA  ·kcon+0x0F0(SB)/8, $0xc19bf174cf692694
+DATA  ·kcon+0x0F8(SB)/8, $0xc19bf174cf692694
+DATA  ·kcon+0x100(SB)/8, $0xe49b69c19ef14ad2
+DATA  ·kcon+0x108(SB)/8, $0xe49b69c19ef14ad2
+DATA  ·kcon+0x110(SB)/8, $0xefbe4786384f25e3
+DATA  ·kcon+0x118(SB)/8, $0xefbe4786384f25e3
+DATA  ·kcon+0x120(SB)/8, $0x0fc19dc68b8cd5b5
+DATA  ·kcon+0x128(SB)/8, $0x0fc19dc68b8cd5b5
+DATA  ·kcon+0x130(SB)/8, $0x240ca1cc77ac9c65
+DATA  ·kcon+0x138(SB)/8, $0x240ca1cc77ac9c65
+DATA  ·kcon+0x140(SB)/8, $0x2de92c6f592b0275
+DATA  ·kcon+0x148(SB)/8, $0x2de92c6f592b0275
+DATA  ·kcon+0x150(SB)/8, $0x4a7484aa6ea6e483
+DATA  ·kcon+0x158(SB)/8, $0x4a7484aa6ea6e483
+DATA  ·kcon+0x160(SB)/8, $0x5cb0a9dcbd41fbd4
+DATA  ·kcon+0x168(SB)/8, $0x5cb0a9dcbd41fbd4
+DATA  ·kcon+0x170(SB)/8, $0x76f988da831153b5
+DATA  ·kcon+0x178(SB)/8, $0x76f988da831153b5
+DATA  ·kcon+0x180(SB)/8, $0x983e5152ee66dfab
+DATA  ·kcon+0x188(SB)/8, $0x983e5152ee66dfab
+DATA  ·kcon+0x190(SB)/8, $0xa831c66d2db43210
+DATA  ·kcon+0x198(SB)/8, $0xa831c66d2db43210
+DATA  ·kcon+0x1A0(SB)/8, $0xb00327c898fb213f
+DATA  ·kcon+0x1A8(SB)/8, $0xb00327c898fb213f
+DATA  ·kcon+0x1B0(SB)/8, $0xbf597fc7beef0ee4
+DATA  ·kcon+0x1B8(SB)/8, $0xbf597fc7beef0ee4
+DATA  ·kcon+0x1C0(SB)/8, $0xc6e00bf33da88fc2
+DATA  ·kcon+0x1C8(SB)/8, $0xc6e00bf33da88fc2
+DATA  ·kcon+0x1D0(SB)/8, $0xd5a79147930aa725
+DATA  ·kcon+0x1D8(SB)/8, $0xd5a79147930aa725
+DATA  ·kcon+0x1E0(SB)/8, $0x06ca6351e003826f
+DATA  ·kcon+0x1E8(SB)/8, $0x06ca6351e003826f
+DATA  ·kcon+0x1F0(SB)/8, $0x142929670a0e6e70
+DATA  ·kcon+0x1F8(SB)/8, $0x142929670a0e6e70
+DATA  ·kcon+0x200(SB)/8, $0x27b70a8546d22ffc
+DATA  ·kcon+0x208(SB)/8, $0x27b70a8546d22ffc
+DATA  ·kcon+0x210(SB)/8, $0x2e1b21385c26c926
+DATA  ·kcon+0x218(SB)/8, $0x2e1b21385c26c926
+DATA  ·kcon+0x220(SB)/8, $0x4d2c6dfc5ac42aed
+DATA  ·kcon+0x228(SB)/8, $0x4d2c6dfc5ac42aed
+DATA  ·kcon+0x230(SB)/8, $0x53380d139d95b3df
+DATA  ·kcon+0x238(SB)/8, $0x53380d139d95b3df
+DATA  ·kcon+0x240(SB)/8, $0x650a73548baf63de
+DATA  ·kcon+0x248(SB)/8, $0x650a73548baf63de
+DATA  ·kcon+0x250(SB)/8, $0x766a0abb3c77b2a8
+DATA  ·kcon+0x258(SB)/8, $0x766a0abb3c77b2a8
+DATA  ·kcon+0x260(SB)/8, $0x81c2c92e47edaee6
+DATA  ·kcon+0x268(SB)/8, $0x81c2c92e47edaee6
+DATA  ·kcon+0x270(SB)/8, $0x92722c851482353b
+DATA  ·kcon+0x278(SB)/8, $0x92722c851482353b
+DATA  ·kcon+0x280(SB)/8, $0xa2bfe8a14cf10364
+DATA  ·kcon+0x288(SB)/8, $0xa2bfe8a14cf10364
+DATA  ·kcon+0x290(SB)/8, $0xa81a664bbc423001
+DATA  ·kcon+0x298(SB)/8, $0xa81a664bbc423001
+DATA  ·kcon+0x2A0(SB)/8, $0xc24b8b70d0f89791
+DATA  ·kcon+0x2A8(SB)/8, $0xc24b8b70d0f89791
+DATA  ·kcon+0x2B0(SB)/8, $0xc76c51a30654be30
+DATA  ·kcon+0x2B8(SB)/8, $0xc76c51a30654be30
+DATA  ·kcon+0x2C0(SB)/8, $0xd192e819d6ef5218
+DATA  ·kcon+0x2C8(SB)/8, $0xd192e819d6ef5218
+DATA  ·kcon+0x2D0(SB)/8, $0xd69906245565a910
+DATA  ·kcon+0x2D8(SB)/8, $0xd69906245565a910
+DATA  ·kcon+0x2E0(SB)/8, $0xf40e35855771202a
+DATA  ·kcon+0x2E8(SB)/8, $0xf40e35855771202a
+DATA  ·kcon+0x2F0(SB)/8, $0x106aa07032bbd1b8
+DATA  ·kcon+0x2F8(SB)/8, $0x106aa07032bbd1b8
+DATA  ·kcon+0x300(SB)/8, $0x19a4c116b8d2d0c8
+DATA  ·kcon+0x308(SB)/8, $0x19a4c116b8d2d0c8
+DATA  ·kcon+0x310(SB)/8, $0x1e376c085141ab53
+DATA  ·kcon+0x318(SB)/8, $0x1e376c085141ab53
+DATA  ·kcon+0x320(SB)/8, $0x2748774cdf8eeb99
+DATA  ·kcon+0x328(SB)/8, $0x2748774cdf8eeb99
+DATA  ·kcon+0x330(SB)/8, $0x34b0bcb5e19b48a8
+DATA  ·kcon+0x338(SB)/8, $0x34b0bcb5e19b48a8
+DATA  ·kcon+0x340(SB)/8, $0x391c0cb3c5c95a63
+DATA  ·kcon+0x348(SB)/8, $0x391c0cb3c5c95a63
+DATA  ·kcon+0x350(SB)/8, $0x4ed8aa4ae3418acb
+DATA  ·kcon+0x358(SB)/8, $0x4ed8aa4ae3418acb
+DATA  ·kcon+0x360(SB)/8, $0x5b9cca4f7763e373
+DATA  ·kcon+0x368(SB)/8, $0x5b9cca4f7763e373
+DATA  ·kcon+0x370(SB)/8, $0x682e6ff3d6b2b8a3
+DATA  ·kcon+0x378(SB)/8, $0x682e6ff3d6b2b8a3
+DATA  ·kcon+0x380(SB)/8, $0x748f82ee5defb2fc
+DATA  ·kcon+0x388(SB)/8, $0x748f82ee5defb2fc
+DATA  ·kcon+0x390(SB)/8, $0x78a5636f43172f60
+DATA  ·kcon+0x398(SB)/8, $0x78a5636f43172f60
+DATA  ·kcon+0x3A0(SB)/8, $0x84c87814a1f0ab72
+DATA  ·kcon+0x3A8(SB)/8, $0x84c87814a1f0ab72
+DATA  ·kcon+0x3B0(SB)/8, $0x8cc702081a6439ec
+DATA  ·kcon+0x3B8(SB)/8, $0x8cc702081a6439ec
+DATA  ·kcon+0x3C0(SB)/8, $0x90befffa23631e28
+DATA  ·kcon+0x3C8(SB)/8, $0x90befffa23631e28
+DATA  ·kcon+0x3D0(SB)/8, $0xa4506cebde82bde9
+DATA  ·kcon+0x3D8(SB)/8, $0xa4506cebde82bde9
+DATA  ·kcon+0x3E0(SB)/8, $0xbef9a3f7b2c67915
+DATA  ·kcon+0x3E8(SB)/8, $0xbef9a3f7b2c67915
+DATA  ·kcon+0x3F0(SB)/8, $0xc67178f2e372532b
+DATA  ·kcon+0x3F8(SB)/8, $0xc67178f2e372532b
+DATA  ·kcon+0x400(SB)/8, $0xca273eceea26619c
+DATA  ·kcon+0x408(SB)/8, $0xca273eceea26619c
+DATA  ·kcon+0x410(SB)/8, $0xd186b8c721c0c207
+DATA  ·kcon+0x418(SB)/8, $0xd186b8c721c0c207
+DATA  ·kcon+0x420(SB)/8, $0xeada7dd6cde0eb1e
+DATA  ·kcon+0x428(SB)/8, $0xeada7dd6cde0eb1e
+DATA  ·kcon+0x430(SB)/8, $0xf57d4f7fee6ed178
+DATA  ·kcon+0x438(SB)/8, $0xf57d4f7fee6ed178
+DATA  ·kcon+0x440(SB)/8, $0x06f067aa72176fba
+DATA  ·kcon+0x448(SB)/8, $0x06f067aa72176fba
+DATA  ·kcon+0x450(SB)/8, $0x0a637dc5a2c898a6
+DATA  ·kcon+0x458(SB)/8, $0x0a637dc5a2c898a6
+DATA  ·kcon+0x460(SB)/8, $0x113f9804bef90dae
+DATA  ·kcon+0x468(SB)/8, $0x113f9804bef90dae
+DATA  ·kcon+0x470(SB)/8, $0x1b710b35131c471b
+DATA  ·kcon+0x478(SB)/8, $0x1b710b35131c471b
+DATA  ·kcon+0x480(SB)/8, $0x28db77f523047d84
+DATA  ·kcon+0x488(SB)/8, $0x28db77f523047d84
+DATA  ·kcon+0x490(SB)/8, $0x32caab7b40c72493
+DATA  ·kcon+0x498(SB)/8, $0x32caab7b40c72493
+DATA  ·kcon+0x4A0(SB)/8, $0x3c9ebe0a15c9bebc
+DATA  ·kcon+0x4A8(SB)/8, $0x3c9ebe0a15c9bebc
+DATA  ·kcon+0x4B0(SB)/8, $0x431d67c49c100d4c
+DATA  ·kcon+0x4B8(SB)/8, $0x431d67c49c100d4c
+DATA  ·kcon+0x4C0(SB)/8, $0x4cc5d4becb3e42b6
+DATA  ·kcon+0x4C8(SB)/8, $0x4cc5d4becb3e42b6
+DATA  ·kcon+0x4D0(SB)/8, $0x597f299cfc657e2a
+DATA  ·kcon+0x4D8(SB)/8, $0x597f299cfc657e2a
+DATA  ·kcon+0x4E0(SB)/8, $0x5fcb6fab3ad6faec
+DATA  ·kcon+0x4E8(SB)/8, $0x5fcb6fab3ad6faec
+DATA  ·kcon+0x4F0(SB)/8, $0x6c44198c4a475817
+DATA  ·kcon+0x4F8(SB)/8, $0x6c44198c4a475817
+DATA  ·kcon+0x500(SB)/8, $0x0000000000000000
+DATA  ·kcon+0x508(SB)/8, $0x0000000000000000
+DATA  ·kcon+0x510(SB)/8, $0x1011121314151617
+DATA  ·kcon+0x518(SB)/8, $0x0001020304050607
+GLOBL ·kcon(SB), RODATA, $1312
 
-#define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \
-	MSGSCHEDULE0(index); \
-	SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+#define SHA512ROUND0(a, b, c, d, e, f, g, h, xi) \
+	VSEL		g, f, e, FUNC; \
+	VSHASIGMAD	$15, e, $1, S1; \
+	VADDUDM		xi, h, h; \
+	VSHASIGMAD	$0, a, $1, S0; \
+	VADDUDM		FUNC, h, h; \
+	VXOR		b, a, FUNC; \
+	VADDUDM		S1, h, h; \
+	VSEL		b, c, FUNC, FUNC; \
+	VADDUDM		KI, g, g; \
+	VADDUDM		h, d, d; \
+	VADDUDM		FUNC, S0, S0; \
+	LVX		(TBL)(IDX), KI; \
+	ADD		$16, IDX; \
+	VADDUDM		S0, h, h
 
-#define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
-	MSGSCHEDULE1(index); \
-	SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+#define SHA512ROUND1(a, b, c, d, e, f, g, h, xi, xj, xj_1, xj_9, xj_14) \
+	VSHASIGMAD	$0, xj_1, $0, s0; \
+	VSEL		g, f, e, FUNC; \
+	VSHASIGMAD	$15, e, $1, S1; \
+	VADDUDM		xi, h, h; \
+	VSHASIGMAD	$0, a, $1, S0; \
+	VSHASIGMAD	$15, xj_14, $0, s1; \
+	VADDUDM		FUNC, h, h; \
+	VXOR		b, a, FUNC; \
+	VADDUDM		xj_9, xj, xj; \
+	VADDUDM		S1, h, h; \
+	VSEL		b, c, FUNC, FUNC; \
+	VADDUDM		KI, g, g; \
+	VADDUDM		h, d, d; \
+	VADDUDM		FUNC, S0, S0; \
+	VADDUDM		s0, xj, xj; \
+	LVX		(TBL)(IDX), KI; \
+	ADD		$16, IDX; \
+	VADDUDM		S0, h, h; \
+	VADDUDM		s1, xj, xj
 
 // func block(dig *digest, p []byte)
-TEXT ·block(SB),0,$680-32
-	MOVD	p_base+8(FP), R6
-	MOVD	p_len+16(FP), R7
-	SRD	$7, R7
-	SLD	$7, R7
+TEXT ·block(SB),0,$128-32
+	MOVD	dig+0(FP), CTX
+	MOVD	p_base+8(FP), INP
+	MOVD	p_len+16(FP), LEN
+
+	SRD	$6, LEN
+	SLD	$6, LEN
 
-	ADD	R6, R7, R8
-	MOVD	R8, 640(R1)
-	CMP	R6, R8
+	ADD	INP, LEN, END
+
+	CMP	INP, END
 	BEQ	end
 
-	MOVD	dig+0(FP), R9
-	MOVD	(0*8)(R9), R22		// a = H0
-	MOVD	(1*8)(R9), R23		// b = H1
-	MOVD	(2*8)(R9), R24		// c = H2
-	MOVD	(3*8)(R9), R25		// d = H3
-	MOVD	(4*8)(R9), R26		// e = H4
-	MOVD	(5*8)(R9), R27		// f = H5
-	MOVD	(6*8)(R9), R28		// g = H6
-	MOVD	(7*8)(R9), R29		// h = H7
+	MOVD	$·kcon(SB), TBL
+	MOVD	R1, OFFLOAD
+
+	MOVD	R0, CNT
+	MOVWZ	$0x10, HEX10
+	MOVWZ	$0x20, HEX20
+	MOVWZ	$0x30, HEX30
+	MOVWZ	$0x40, HEX40
+	MOVWZ	$0x50, HEX50
+	MOVWZ	$0x60, HEX60
+	MOVWZ	$0x70, HEX70
+
+	MOVWZ	$8, IDX
+	LVSL	(IDX)(R0), LEMASK
+	VSPLTISB	$0x0F, KI
+	VXOR	KI, LEMASK, LEMASK
+
+	LXVD2X	(CTX)(HEX00), VS32	// v0 = vs32
+	LXVD2X	(CTX)(HEX10), VS34	// v2 = vs34
+	LXVD2X	(CTX)(HEX20), VS36	// v4 = vs36
+	// unpack the input values into vector registers
+	VSLDOI	$8, V0, V0, V1
+	LXVD2X	(CTX)(HEX30), VS38	// v6 = vs38
+	VSLDOI	$8, V2, V2, V3
+	VSLDOI	$8, V4, V4, V5
+	VSLDOI	$8, V6, V6, V7
 
 loop:
-	MOVD	R1, R9			// R9: message schedule
+	LVX	(TBL)(HEX00), KI
+	MOVWZ	$16, IDX
 
-	SHA512ROUND0(0, 0x428a2f98d728ae22, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND0(1, 0x7137449123ef65cd, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND0(3, 0xe9b5dba58189dbbc, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND0(4, 0x3956c25bf348b538, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND0(5, 0x59f111f1b605d019, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND0(6, 0x923f82a4af194f9b, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND0(7, 0xab1c5ed5da6d8118, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND0(8, 0xd807aa98a3030242, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND0(9, 0x12835b0145706fbe, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND0(10, 0x243185be4ee4b28c, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND0(12, 0x72be5d74f27b896f, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND0(13, 0x80deb1fe3b1696b1, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND0(14, 0x9bdc06a725c71235, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND0(15, 0xc19bf174cf692694, R23, R24, R25, R26, R27, R28, R29, R22)
+	LXVD2X	(INP)(R0), VS40	// load v8 (=vs40) in advance
+	ADD	$16, INP
 
-	SHA512ROUND1(16, 0xe49b69c19ef14ad2, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(17, 0xefbe4786384f25e3, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(19, 0x240ca1cc77ac9c65, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(20, 0x2de92c6f592b0275, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(21, 0x4a7484aa6ea6e483, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(23, 0x76f988da831153b5, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(24, 0x983e5152ee66dfab, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(25, 0xa831c66d2db43210, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(26, 0xb00327c898fb213f, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(27, 0xbf597fc7beef0ee4, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(28, 0xc6e00bf33da88fc2, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(29, 0xd5a79147930aa725, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(30, 0x06ca6351e003826f, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(31, 0x142929670a0e6e70, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(32, 0x27b70a8546d22ffc, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(33, 0x2e1b21385c26c926, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(35, 0x53380d139d95b3df, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(36, 0x650a73548baf63de, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(37, 0x766a0abb3c77b2a8, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(38, 0x81c2c92e47edaee6, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(39, 0x92722c851482353b, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(40, 0xa2bfe8a14cf10364, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(41, 0xa81a664bbc423001, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(42, 0xc24b8b70d0f89791, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(43, 0xc76c51a30654be30, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(44, 0xd192e819d6ef5218, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(45, 0xd69906245565a910, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(46, 0xf40e35855771202a, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(47, 0x106aa07032bbd1b8, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(49, 0x1e376c085141ab53, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(50, 0x2748774cdf8eeb99, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(52, 0x391c0cb3c5c95a63, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(54, 0x5b9cca4f7763e373, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(56, 0x748f82ee5defb2fc, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(57, 0x78a5636f43172f60, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(58, 0x84c87814a1f0ab72, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(59, 0x8cc702081a6439ec, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(60, 0x90befffa23631e28, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(61, 0xa4506cebde82bde9, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(62, 0xbef9a3f7b2c67915, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(63, 0xc67178f2e372532b, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(64, 0xca273eceea26619c, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(65, 0xd186b8c721c0c207, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(67, 0xf57d4f7fee6ed178, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(68, 0x06f067aa72176fba, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(69, 0x0a637dc5a2c898a6, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(70, 0x113f9804bef90dae, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(71, 0x1b710b35131c471b, R23, R24, R25, R26, R27, R28, R29, R22)
-	SHA512ROUND1(72, 0x28db77f523047d84, R22, R23, R24, R25, R26, R27, R28, R29)
-	SHA512ROUND1(73, 0x32caab7b40c72493, R29, R22, R23, R24, R25, R26, R27, R28)
-	SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R28, R29, R22, R23, R24, R25, R26, R27)
-	SHA512ROUND1(75, 0x431d67c49c100d4c, R27, R28, R29, R22, R23, R24, R25, R26)
-	SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R26, R27, R28, R29, R22, R23, R24, R25)
-	SHA512ROUND1(77, 0x597f299cfc657e2a, R25, R26, R27, R28, R29, R22, R23, R24)
-	SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R24, R25, R26, R27, R28, R29, R22, R23)
-	SHA512ROUND1(79, 0x6c44198c4a475817, R23, R24, R25, R26, R27, R28, R29, R22)
+	STVX	V0, (OFFLOAD+HEX00)
+	STVX	V1, (OFFLOAD+HEX10)
+	STVX	V2, (OFFLOAD+HEX20)
+	STVX	V3, (OFFLOAD+HEX30)
+	STVX	V4, (OFFLOAD+HEX40)
+	STVX	V5, (OFFLOAD+HEX50)
+	STVX	V6, (OFFLOAD+HEX60)
+	STVX	V7, (OFFLOAD+HEX70)
 
-	MOVD	dig+0(FP), R9
-	MOVD	(0*8)(R9), R21
-	ADD	R21, R22	// H0 = a + H0
-	MOVD	R22, (0*8)(R9)
-	MOVD	(1*8)(R9), R21
-	ADD	R21, R23	// H1 = b + H1
-	MOVD	R23, (1*8)(R9)
-	MOVD	(2*8)(R9), R21
-	ADD	R21, R24	// H2 = c + H2
-	MOVD	R24, (2*8)(R9)
-	MOVD	(3*8)(R9), R21
-	ADD	R21, R25	// H3 = d + H3
-	MOVD	R25, (3*8)(R9)
-	MOVD	(4*8)(R9), R21
-	ADD	R21, R26	// H4 = e + H4
-	MOVD	R26, (4*8)(R9)
-	MOVD	(5*8)(R9), R21
-	ADD	R21, R27	// H5 = f + H5
-	MOVD	R27, (5*8)(R9)
-	MOVD	(6*8)(R9), R21
-	ADD	R21, R28	// H6 = g + H6
-	MOVD	R28, (6*8)(R9)
-	MOVD	(7*8)(R9), R21
-	ADD	R21, R29	// H7 = h + H7
-	MOVD	R29, (7*8)(R9)
+	VADDUDM	KI, V7, V7	// h+K[i]
+	LVX	(TBL)(IDX), KI
+	ADD	$16, IDX
 
-	ADD	$128, R6
-	MOVD	640(R1), R21
-	CMPU	R6, R21
+	VPERM	V8, V8, LEMASK, V8
+	SHA512ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V8)
+	LXVD2X	(INP)(R0), VS42	// load v10 (=vs42) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V8, V8, V9
+	SHA512ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V9)
+	VPERM	V10, V10, LEMASK, V10
+	SHA512ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V10)
+	LXVD2X	(INP)(R0), VS44	// load v12 (=vs44) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V10, V10, V11
+	SHA512ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V11)
+	VPERM	V12, V12, LEMASK, V12
+	SHA512ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V12)
+	LXVD2X	(INP)(R0), VS46	// load v14 (=vs46) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V12, V12, V13
+	SHA512ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V13)
+	VPERM	V14, V14, LEMASK, V14
+	SHA512ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V14)
+	LXVD2X	(INP)(R0), VS48	// load v16 (=vs48) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V14, V14, V15
+	SHA512ROUND0(V1, V2, V3, V4, V5, V6, V7, V0, V15)
+	VPERM	V16, V16, LEMASK, V16
+	SHA512ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V16)
+	LXVD2X	(INP)(R0), VS50	// load v18 (=vs50) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V16, V16, V17
+	SHA512ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V17)
+	VPERM	V18, V18, LEMASK, V18
+	SHA512ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V18)
+	LXVD2X	(INP)(R0), VS52	// load v20 (=vs52) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V18, V18, V19
+	SHA512ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V19)
+	VPERM	V20, V20, LEMASK, V20
+	SHA512ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V20)
+	LXVD2X	(INP)(R0), VS54	// load v22 (=vs54) in advance
+	ADD	$16, INP, INP
+	VSLDOI	$8, V20, V20, V21
+	SHA512ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V21)
+	VPERM	V22, V22, LEMASK, V22
+	SHA512ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V22)
+	VSLDOI	$8, V22, V22, V23
+	SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+	MOVWZ	$4, TEMP
+	MOVWZ	TEMP, CTR
+
+L16_xx:
+	SHA512ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V18, V23)
+	SHA512ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V9, V10, V11, V19, V8)
+	SHA512ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V10, V11, V12, V20, V9)
+	SHA512ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V11, V12, V13, V21, V10)
+	SHA512ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V12, V13, V14, V22, V11)
+	SHA512ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V13, V14, V15, V23, V12)
+	SHA512ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V14, V15, V16, V8, V13)
+	SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V15, V16, V17, V9, V14)
+	SHA512ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V16, V17, V18, V10, V15)
+	SHA512ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V17, V18, V19, V11, V16)
+	SHA512ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V18, V19, V20, V12, V17)
+	SHA512ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V19, V20, V21, V13, V18)
+	SHA512ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V20, V21, V22, V14, V19)
+	SHA512ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V21, V22, V23, V15, V20)
+	SHA512ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V22, V23, V8, V16, V21)
+	SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+	BC	0x10, 0, L16_xx		// bdnz
+
+	LVX	(OFFLOAD)(HEX00), V10
+
+	LVX	(OFFLOAD)(HEX10), V11
+	VADDUDM	V10, V0, V0
+	LVX	(OFFLOAD)(HEX20), V12
+	VADDUDM	V11, V1, V1
+	LVX	(OFFLOAD)(HEX30), V13
+	VADDUDM	V12, V2, V2
+	LVX	(OFFLOAD)(HEX40), V14
+	VADDUDM	V13, V3, V3
+	LVX	(OFFLOAD)(HEX50), V15
+	VADDUDM	V14, V4, V4
+	LVX	(OFFLOAD)(HEX60), V16
+	VADDUDM	V15, V5, V5
+	LVX	(OFFLOAD)(HEX70), V17
+	VADDUDM	V16, V6, V6
+	VADDUDM	V17, V7, V7
+
+	CMPU	INP, END
 	BLT	loop
 
+	VPERM	V0, V1, KI, V0
+	VPERM	V2, V3, KI, V2
+	VPERM	V4, V5, KI, V4
+	VPERM	V6, V7, KI, V6
+	STXVD2X	VS32, (CTX+HEX00)	// v0 = vs32
+	STXVD2X	VS34, (CTX+HEX10)	// v2 = vs34
+	STXVD2X	VS36, (CTX+HEX20)	// v4 = vs36
+	STXVD2X	VS38, (CTX+HEX30)	// v6 = vs38
+
 end:
 	RET
+
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index de833a9..5860838 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -163,8 +163,8 @@ type ConnectionState struct {
 	HandshakeComplete           bool                  // TLS handshake is complete
 	DidResume                   bool                  // connection resumes a previous TLS connection
 	CipherSuite                 uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
-	NegotiatedProtocol          string                // negotiated next protocol (from Config.NextProtos)
-	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server
+	NegotiatedProtocol          string                // negotiated next protocol (not guaranteed to be from Config.NextProtos)
+	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server (client side only)
 	ServerName                  string                // server name requested by client, if any (server side only)
 	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
 	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
@@ -174,9 +174,9 @@ type ConnectionState struct {
 	// TLSUnique contains the "tls-unique" channel binding value (see RFC
 	// 5929, section 3). For resumed sessions this value will be nil
 	// because resumption does not include enough context (see
-	// https://secure-resumption.com/#channelbindings). This will change in
-	// future versions of Go once the TLS master-secret fix has been
-	// standardized and implemented.
+	// https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will
+	// change in future versions of Go once the TLS master-secret fix has
+	// been standardized and implemented.
 	TLSUnique []byte
 }
 
@@ -206,7 +206,8 @@ type ClientSessionState struct {
 // ClientSessionCache is a cache of ClientSessionState objects that can be used
 // by a client to resume a TLS session with a given server. ClientSessionCache
 // implementations should expect to be called concurrently from different
-// goroutines.
+// goroutines. Only ticket-based resumption is supported, not SessionID-based
+// resumption.
 type ClientSessionCache interface {
 	// Get searches for a ClientSessionState associated with the given key.
 	// On return, ok is true if one was found.
@@ -508,17 +509,13 @@ type Config struct {
 
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
 
-	// mutex protects sessionTicketKeys and originalConfig.
+	// mutex protects sessionTicketKeys.
 	mutex sync.RWMutex
 	// sessionTicketKeys contains zero or more ticket keys. If the length
 	// is zero, SessionTicketsDisabled must be true. The first key is used
 	// for new tickets and any subsequent keys can be used to decrypt old
 	// tickets.
 	sessionTicketKeys []ticketKey
-	// originalConfig is set to the Config that was passed to Server if
-	// this Config is returned by a GetConfigForClient callback. It's used
-	// by serverInit in order to copy session ticket keys if needed.
-	originalConfig *Config
 }
 
 // ticketKeyNameLen is the number of bytes of identifier that is prepended to
@@ -550,7 +547,7 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
 func (c *Config) Clone() *Config {
 	// Running serverInit ensures that it's safe to read
 	// SessionTicketsDisabled.
-	c.serverInitOnce.Do(c.serverInit)
+	c.serverInitOnce.Do(func() { c.serverInit(nil) })
 
 	var sessionTicketKeys []ticketKey
 	c.mutex.RLock()
@@ -584,20 +581,17 @@ func (c *Config) Clone() *Config {
 		Renegotiation:               c.Renegotiation,
 		KeyLogWriter:                c.KeyLogWriter,
 		sessionTicketKeys:           sessionTicketKeys,
-		// originalConfig is deliberately not duplicated.
 	}
 }
 
-func (c *Config) serverInit() {
+// serverInit is run under c.serverInitOnce to do initialization of c. If c was
+// returned by a GetConfigForClient callback then the argument should be the
+// Config that was passed to Server, otherwise it should be nil.
+func (c *Config) serverInit(originalConfig *Config) {
 	if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
 		return
 	}
 
-	var originalConfig *Config
-	c.mutex.Lock()
-	originalConfig, c.originalConfig = c.originalConfig, nil
-	c.mutex.Unlock()
-
 	alreadySet := false
 	for _, b := range c.SessionTicketKey {
 		if b != 0 {
@@ -947,9 +941,7 @@ func initDefaultCipherSuites() {
 	}
 
 	varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
-	for _, topCipher := range topCipherSuites {
-		varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher)
-	}
+	varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...)
 
 NextCipherSuite:
 	for _, suite := range cipherSuites {
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 03895a7..e6d85aa 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -1206,10 +1206,10 @@ func (c *Conn) Close() error {
 	var alertErr error
 
 	c.handshakeMutex.Lock()
-	defer c.handshakeMutex.Unlock()
 	if c.handshakeComplete {
 		alertErr = c.closeNotify()
 	}
+	c.handshakeMutex.Unlock()
 
 	if err := c.conn.Close(); err != nil {
 		return err
diff --git a/src/crypto/tls/conn_test.go b/src/crypto/tls/conn_test.go
index 5e5c7a2..e27c541 100644
--- a/src/crypto/tls/conn_test.go
+++ b/src/crypto/tls/conn_test.go
@@ -138,7 +138,7 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
 
 		tlsConn := Client(clientConn, config)
 		if err := tlsConn.Handshake(); err != nil {
-			t.Errorf("Error from client handshake: %s", err)
+			t.Errorf("Error from client handshake: %v", err)
 			return
 		}
 
@@ -147,12 +147,12 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
 		var recordSizes []int
 
 		for {
-			n, err := clientConn.Read(recordHeader[:])
+			n, err := io.ReadFull(clientConn, recordHeader[:])
 			if err == io.EOF {
 				break
 			}
 			if err != nil || n != len(recordHeader) {
-				t.Errorf("Error from client read: %s", err)
+				t.Errorf("io.ReadFull = %d, %v", n, err)
 				return
 			}
 
@@ -161,9 +161,9 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
 				record = make([]byte, length)
 			}
 
-			n, err = clientConn.Read(record[:length])
+			n, err = io.ReadFull(clientConn, record[:length])
 			if err != nil || n != length {
-				t.Errorf("Error from client read: %s", err)
+				t.Errorf("io.ReadFull = %d, %v", n, err)
 				return
 			}
 
@@ -241,3 +241,34 @@ func TestDynamicRecordSizingWithAEAD(t *testing.T) {
 	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
 	runDynamicRecordSizingTest(t, config)
 }
+
+// hairpinConn is a net.Conn that makes a “hairpin” call when closed, back into
+// the tls.Conn which is calling it.
+type hairpinConn struct {
+	net.Conn
+	tlsConn *Conn
+}
+
+func (conn *hairpinConn) Close() error {
+	conn.tlsConn.ConnectionState()
+	return nil
+}
+
+func TestHairpinInClose(t *testing.T) {
+	// This tests that the underlying net.Conn can call back into the
+	// tls.Conn when being closed without deadlocking.
+	client, server := net.Pipe()
+	defer server.Close()
+	defer client.Close()
+
+	conn := &hairpinConn{client, nil}
+	tlsConn := Server(conn, &Config{
+		GetCertificate: func(*ClientHelloInfo) (*Certificate, error) {
+			panic("unreachable")
+		},
+	})
+	conn.tlsConn = tlsConn
+
+	// This call should not deadlock.
+	tlsConn.Close()
+}
diff --git a/src/crypto/tls/generate_cert.go b/src/crypto/tls/generate_cert.go
index 83f9916..8ee2b59 100644
--- a/src/crypto/tls/generate_cert.go
+++ b/src/crypto/tls/generate_cert.go
@@ -33,7 +33,7 @@ var (
 	validFor   = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
 	isCA       = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
 	rsaBits    = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
-	ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521")
+	ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
 )
 
 func publicKey(priv interface{}) interface{} {
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 6eda18d..a4ca5d3 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -815,7 +815,7 @@ func hostnameInSNI(name string) string {
 	if net.ParseIP(host) != nil {
 		return ""
 	}
-	if len(name) > 0 && name[len(name)-1] == '.' {
+	for len(name) > 0 && name[len(name)-1] == '.' {
 		name = name[:len(name)-1]
 	}
 	return name
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 694bd91..0c7581f 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -4,7 +4,10 @@
 
 package tls
 
-import "bytes"
+import (
+	"bytes"
+	"strings"
+)
 
 type clientHelloMsg struct {
 	raw                          []byte
@@ -393,6 +396,12 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				}
 				if nameType == 0 {
 					m.serverName = string(d[:nameLen])
+					// An SNI value may not include a
+					// trailing dot. See
+					// https://tools.ietf.org/html/rfc6066#section-3.
+					if strings.HasSuffix(m.serverName, ".") {
+						return false
+					}
 					break
 				}
 				d = d[nameLen:]
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index f1154d4..7add97c 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"math/rand"
 	"reflect"
+	"strings"
 	"testing"
 	"testing/quick"
 )
@@ -123,6 +124,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 	}
 	if rand.Intn(10) > 5 {
 		m.serverName = randomString(rand.Intn(255), rand)
+		for strings.HasSuffix(m.serverName, ".") {
+			m.serverName = m.serverName[:len(m.serverName)-1]
+		}
 	}
 	m.ocspStapling = rand.Intn(10) > 5
 	m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index b786c30..ae32848 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -40,7 +40,7 @@ type serverHandshakeState struct {
 func (c *Conn) serverHandshake() error {
 	// If this is the first server handshake, we generate a random key to
 	// encrypt the tickets with.
-	c.config.serverInitOnce.Do(c.config.serverInit)
+	c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
 
 	hs := serverHandshakeState{
 		c: c,
@@ -129,11 +129,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
 			c.sendAlert(alertInternalError)
 			return false, err
 		} else if newConfig != nil {
-			newConfig.mutex.Lock()
-			newConfig.originalConfig = c.config
-			newConfig.mutex.Unlock()
-
-			newConfig.serverInitOnce.Do(newConfig.serverInit)
+			newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
 			c.config = newConfig
 		}
 	}
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index bcd3d43..63845c1 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -137,6 +137,10 @@ func TestNoRC4ByDefault(t *testing.T) {
 	testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
 }
 
+func TestRejectSNIWithTrailingDot(t *testing.T) {
+	testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: VersionTLS12, serverName: "foo.com."}, "unexpected message")
+}
+
 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.
diff --git a/src/crypto/x509/pkcs1.go b/src/crypto/x509/pkcs1.go
index df20a44..73bc762 100644
--- a/src/crypto/x509/pkcs1.go
+++ b/src/crypto/x509/pkcs1.go
@@ -35,6 +35,12 @@ type pkcs1AdditionalRSAPrime struct {
 	Coeff *big.Int
 }
 
+// pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key.
+type pkcs1PublicKey struct {
+	N *big.Int
+	E int
+}
+
 // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
 func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
 	var priv pkcs1PrivateKey
@@ -113,9 +119,3 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
 	b, _ := asn1.Marshal(priv)
 	return b
 }
-
-// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
-type rsaPublicKey struct {
-	N *big.Int
-	E int
-}
diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go
index 9317283..1371933 100644
--- a/src/crypto/x509/root_bsd.go
+++ b/src/crypto/x509/root_bsd.go
@@ -8,7 +8,8 @@ package x509
 
 // Possible certificate files; stop after finding one.
 var certFiles = []string{
-	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+	"/usr/local/etc/ssl/cert.pem",            // FreeBSD
 	"/etc/ssl/cert.pem",                      // OpenBSD
+	"/usr/local/share/certs/ca-root-nss.crt", // DragonFly
 	"/etc/openssl/certs/ca-certificates.crt", // NetBSD
 }
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index 7bcb3d6..65b5a5f 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -16,27 +16,51 @@ import (
 var certDirectories = []string{
 	"/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
 	"/system/etc/security/cacerts", // Android
+	"/usr/local/share/certs",       // FreeBSD
+	"/etc/pki/tls/certs",           // Fedora/RHEL
+	"/etc/openssl/certs",           // NetBSD
 }
 
+const (
+	// certFileEnv is the environment variable which identifies where to locate
+	// the SSL certificate file. If set this overrides the system default.
+	certFileEnv = "SSL_CERT_FILE"
+
+	// certDirEnv is the environment variable which identifies which directory
+	// to check for SSL certificate files. If set this overrides the system default.
+	certDirEnv = "SSL_CERT_DIR"
+)
+
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
 	return nil, nil
 }
 
 func loadSystemRoots() (*CertPool, error) {
 	roots := NewCertPool()
+
+	files := certFiles
+	if f := os.Getenv(certFileEnv); f != "" {
+		files = []string{f}
+	}
+
 	var firstErr error
-	for _, file := range certFiles {
+	for _, file := range files {
 		data, err := ioutil.ReadFile(file)
 		if err == nil {
 			roots.AppendCertsFromPEM(data)
-			return roots, nil
+			break
 		}
 		if firstErr == nil && !os.IsNotExist(err) {
 			firstErr = err
 		}
 	}
 
-	for _, directory := range certDirectories {
+	dirs := certDirectories
+	if d := os.Getenv(certDirEnv); d != "" {
+		dirs = []string{d}
+	}
+
+	for _, directory := range dirs {
 		fis, err := ioutil.ReadDir(directory)
 		if err != nil {
 			if firstErr == nil && !os.IsNotExist(err) {
@@ -56,5 +80,9 @@ func loadSystemRoots() (*CertPool, error) {
 		}
 	}
 
+	if len(roots.certs) > 0 {
+		return roots, nil
+	}
+
 	return nil, firstErr
 }
diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go
new file mode 100644
index 0000000..b6659d9
--- /dev/null
+++ b/src/crypto/x509/root_unix_test.go
@@ -0,0 +1,127 @@
+// Copyright 2017 The Go Authors. 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 linux netbsd openbsd solaris
+
+package x509
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+const (
+	testDir     = "testdata"
+	testDirCN   = "test-dir"
+	testFile    = "test-file.crt"
+	testFileCN  = "test-file"
+	testMissing = "missing"
+)
+
+func TestEnvVars(t *testing.T) {
+	testCases := []struct {
+		name    string
+		fileEnv string
+		dirEnv  string
+		files   []string
+		dirs    []string
+		cns     []string
+	}{
+		{
+			// Environment variables override the default locations preventing fall through.
+			name:    "override-defaults",
+			fileEnv: testMissing,
+			dirEnv:  testMissing,
+			files:   []string{testFile},
+			dirs:    []string{testDir},
+			cns:     nil,
+		},
+		{
+			// File environment overrides default file locations.
+			name:    "file",
+			fileEnv: testFile,
+			dirEnv:  "",
+			files:   nil,
+			dirs:    nil,
+			cns:     []string{testFileCN},
+		},
+		{
+			// Directory environment overrides default directory locations.
+			name:    "dir",
+			fileEnv: "",
+			dirEnv:  testDir,
+			files:   nil,
+			dirs:    nil,
+			cns:     []string{testDirCN},
+		},
+		{
+			// File & directory environment overrides both default locations.
+			name:    "file+dir",
+			fileEnv: testFile,
+			dirEnv:  testDir,
+			files:   nil,
+			dirs:    nil,
+			cns:     []string{testFileCN, testDirCN},
+		},
+		{
+			// Environment variable empty / unset uses default locations.
+			name:    "empty-fall-through",
+			fileEnv: "",
+			dirEnv:  "",
+			files:   []string{testFile},
+			dirs:    []string{testDir},
+			cns:     []string{testFileCN, testDirCN},
+		},
+	}
+
+	// Save old settings so we can restore before the test ends.
+	origCertFiles, origCertDirectories := certFiles, certDirectories
+	origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv)
+	defer func() {
+		certFiles = origCertFiles
+		certDirectories = origCertDirectories
+		os.Setenv(certFileEnv, origFile)
+		os.Setenv(certDirEnv, origDir)
+	}()
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			if err := os.Setenv(certFileEnv, tc.fileEnv); err != nil {
+				t.Fatalf("setenv %q failed: %v", certFileEnv, err)
+			}
+			if err := os.Setenv(certDirEnv, tc.dirEnv); err != nil {
+				t.Fatalf("setenv %q failed: %v", certDirEnv, err)
+			}
+
+			certFiles, certDirectories = tc.files, tc.dirs
+
+			r, err := loadSystemRoots()
+			if err != nil {
+				t.Fatal("unexpected failure: ", err)
+			}
+
+			if r == nil {
+				if tc.cns == nil {
+					// Expected nil
+					return
+				}
+				t.Fatal("nil roots")
+			}
+
+			for i, cn := range tc.cns {
+				if i > len(r.certs) {
+					t.Errorf("missing cert %v @ %v", cn, i)
+				} else if r.certs[i].Subject.CommonName != cn {
+					fmt.Printf("%#v\n", r.certs[0].Subject)
+					t.Errorf("unexpected cert common name %q expected %q", r.certs[i].Subject.CommonName, cn)
+				}
+			}
+
+			if len(r.certs) > len(tc.cns) {
+				t.Errorf("expected %v certs got %v", len(tc.cns), len(r.certs))
+			}
+		})
+	}
+}
diff --git a/src/crypto/x509/test-file.crt b/src/crypto/x509/test-file.crt
new file mode 100644
index 0000000..caa83b9
--- /dev/null
+++ b/src/crypto/x509/test-file.crt
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
+BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
+dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy
+MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD
+VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs
+i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW
+jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI
+KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St
+cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj
+iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw
+5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03
+Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv
+8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN
+fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A
+GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft
+C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf
+BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx
+AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK
+SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake
+pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT
+xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl
+r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls
+BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd
+4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+
+75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p
+z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc
+rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG
+vQ==
+-----END CERTIFICATE-----
diff --git a/src/crypto/x509/testdata/test-dir.crt b/src/crypto/x509/testdata/test-dir.crt
new file mode 100644
index 0000000..b7fc9c5
--- /dev/null
+++ b/src/crypto/x509/testdata/test-dir.crt
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
+BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
+dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz
+NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV
+BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3
+DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM
+WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu
+XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql
+MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN
+hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF
+k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk
++oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM
+uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY
+adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2
+cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio
+9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui
+dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD
+VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe
+xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3
+ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC
+6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc
+g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT
+Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
+3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA
+m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W
+PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC
+Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M
+JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo=
+-----END CERTIFICATE-----
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 29345a1..2b4f39d 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -87,7 +87,7 @@ func (h HostnameError) Error() string {
 			valid += san.String()
 		}
 	} else {
-		if len(c.DNSNames) > 0 {
+		if c.hasSANExtension() {
 			valid = strings.Join(c.DNSNames, ", ")
 		} else {
 			valid = c.Subject.CommonName
@@ -166,7 +166,7 @@ const (
 
 func matchNameConstraint(domain, constraint string) bool {
 	// The meaning of zero length constraints is not specified, but this
-	// code follows NSS and accepts them as valid for everything.
+	// code follows NSS and accepts them as matching everything.
 	if len(constraint) == 0 {
 		return true
 	}
@@ -220,6 +220,12 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
 		}
 	}
 
+	for _, constraint := range c.ExcludedDNSDomains {
+		if matchNameConstraint(opts.DNSName, constraint) {
+			return CertificateInvalidError{c, CANotAuthorizedForThisName}
+		}
+	}
+
 	// KeyUsage status flags are ignored. From Engineering Security, Peter
 	// Gutmann: A European government CA marked its signing certificates as
 	// being valid for encryption only, but no-one noticed. Another
@@ -482,7 +488,7 @@ func (c *Certificate) VerifyHostname(h string) error {
 
 	lowered := toLowerCaseASCII(h)
 
-	if len(c.DNSNames) > 0 {
+	if c.hasSANExtension() {
 		for _, match := range c.DNSNames {
 			if matchHostnames(toLowerCaseASCII(match), lowered) {
 				return nil
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 15c4091..335c477 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -263,6 +263,39 @@ var verifyTests = []verifyTest{
 
 		errorCallback: expectSubjectIssuerMismatcthError,
 	},
+	{
+		// An X.509 v1 certificate should not be accepted as an
+		// intermediate.
+		leaf:          x509v1TestLeaf,
+		intermediates: []string{x509v1TestIntermediate},
+		roots:         []string{x509v1TestRoot},
+		currentTime:   1481753183,
+		systemSkip:    true,
+
+		errorCallback: expectNotAuthorizedError,
+	},
+	{
+		// If any SAN extension is present (even one without any DNS
+		// names), the CN should be ignored.
+		leaf:        ignoreCNWithSANLeaf,
+		dnsName:     "foo.example.com",
+		roots:       []string{ignoreCNWithSANRoot},
+		currentTime: 1486684488,
+		systemSkip:  true,
+
+		errorCallback: expectHostnameError,
+	},
+	{
+		// Test that excluded names are respected.
+		leaf:          excludedNamesLeaf,
+		dnsName:       "bender.local",
+		intermediates: []string{excludedNamesIntermediate},
+		roots:         []string{excludedNamesRoot},
+		currentTime:   1486684488,
+		systemSkip:    true,
+
+		errorCallback: expectNameConstraintsError,
+	},
 }
 
 func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -330,6 +363,22 @@ func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool)
 	return true
 }
 
+func expectNameConstraintsError(t *testing.T, i int, err error) (ok bool) {
+	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
+		t.Errorf("#%d: error was not a CANotAuthorizedForThisName: %s", i, err)
+		return false
+	}
+	return true
+}
+
+func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) {
+	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign {
+		t.Errorf("#%d: error was not a NotAuthorizedToSign: %s", i, err)
+		return false
+	}
+	return true
+}
+
 func certificateFromPEM(pemBytes string) (*Certificate, error) {
 	block, _ := pem.Decode([]byte(pemBytes))
 	if block == nil {
@@ -1269,6 +1318,174 @@ vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
 -----END CERTIFICATE-----
 `
 
+const x509v1TestRoot = `
+-----BEGIN CERTIFICATE-----
+MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
+ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
+siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
+JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
+EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm
+YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md
+h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB
+/1JmacUUofl+HusHuLkDxmadogI=
+-----END CERTIFICATE-----`
+
+const x509v1TestIntermediate = `
+-----BEGIN CERTIFICATE-----
+MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
+b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
+MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
+ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL
+jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM
+k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8
+UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab
+DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR
+zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur
+x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
+-----END CERTIFICATE-----`
+
+const x509v1TestLeaf = `
+-----BEGIN CERTIFICATE-----
+MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
+BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
+MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
+BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR
++RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG
+Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD
+VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
+HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB
+CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9
+5R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL
+/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
+-----END CERTIFICATE-----`
+
+const ignoreCNWithSANRoot = `
+-----BEGIN CERTIFICATE-----
+MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
+ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
+MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
+BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW
+P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY
+VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf
+2FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3
+KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w
+OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE
+AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
+AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC
+AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j
+fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I
+VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy
+nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU
+aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu
+BJ6bvwEAasFiLGP6Zbdmxb2hIA==
+-----END CERTIFICATE-----`
+
+const ignoreCNWithSANLeaf = `
+-----BEGIN CERTIFICATE-----
+MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
+BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
+MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
+FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS
+ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3
+rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ
+hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW
+S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV
+nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD
+AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
+MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4
+HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ
+ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI
+Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv
+AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR
+sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY
+j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn
+xZbqP3Krgjj4XNaXjg==
+-----END CERTIFICATE-----`
+
+const excludedNamesLeaf = `
+-----BEGIN CERTIFICATE-----
+MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv
+ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx
+FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0
+eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA
+zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8
+Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu
+/9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP
+/Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB
+UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj
+LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB
+MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq
+sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP
+hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt
+qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+
+VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4
+oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A
+-----END CERTIFICATE-----
+`
+
+const excludedNamesIntermediate = `
+-----BEGIN CERTIFICATE-----
+MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5
+MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV
+UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD
+VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3
+MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz
+OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx
+3FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I
+CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE
+1AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL
+7oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS
+nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y
+E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA
+V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI
+JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7
+A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z
+LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS
+zMBX1/lk4wkFckeUIlkD55Y=
+-----END CERTIFICATE-----`
+
+const excludedNamesRoot = `
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU
+ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL
+MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH
+YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl
+Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm
+b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc
+7+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+
+8TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4
+gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb
+5Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb
+smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV
+m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww
+CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu
+ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs
+n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+
+Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ
+yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT
+6mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o
++NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy
+-----END CERTIFICATE-----`
+
 var unknownAuthorityErrorTests = []struct {
 	cert     string
 	expected string
@@ -1294,7 +1511,7 @@ func TestUnknownAuthorityError(t *testing.T) {
 			hintCert: c,
 		}
 		actual := uae.Error()
-		if strings.Compare(actual, tt.expected) != 0 {
+		if actual != tt.expected {
 			t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
 		}
 	}
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 949ce01..549b64b 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -3,6 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // Package x509 parses X.509-encoded keys and certificates.
+//
+// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR
+// can be used to override the system default locations for the SSL certificate
+// file and SSL certificate files directory, respectively.
 package x509
 
 import (
@@ -59,7 +63,7 @@ func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
 func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
 	switch pub := pub.(type) {
 	case *rsa.PublicKey:
-		publicKeyBytes, err = asn1.Marshal(rsaPublicKey{
+		publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{
 			N: pub.N,
 			E: pub.E,
 		})
@@ -69,9 +73,7 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
 		publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
 		// This is a NULL parameters value which is required by
 		// https://tools.ietf.org/html/rfc3279#section-2.3.1.
-		publicKeyAlgorithm.Parameters = asn1.RawValue{
-			Tag: 5,
-		}
+		publicKeyAlgorithm.Parameters = asn1.NullRawValue
 	case *ecdsa.PublicKey:
 		publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
 		oid, ok := oidFromNamedCurve(pub.Curve)
@@ -355,10 +357,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
 
 	params := pssParameters{
 		Hash: pkix.AlgorithmIdentifier{
-			Algorithm: hashOID,
-			Parameters: asn1.RawValue{
-				Tag: 5, /* ASN.1 NULL */
-			},
+			Algorithm:  hashOID,
+			Parameters: asn1.NullRawValue,
 		},
 		MGF: pkix.AlgorithmIdentifier{
 			Algorithm: oidMGF1,
@@ -368,10 +368,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
 	}
 
 	mgf1Params := pkix.AlgorithmIdentifier{
-		Algorithm: hashOID,
-		Parameters: asn1.RawValue{
-			Tag: 5, /* ASN.1 NULL */
-		},
+		Algorithm:  hashOID,
+		Parameters: asn1.NullRawValue,
 	}
 
 	var err error
@@ -418,11 +416,10 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm
 	// https://tools.ietf.org/html/rfc3447#section-8.1), that the
 	// salt length matches the hash length, and that the trailer
 	// field has the default value.
-	asn1NULL := []byte{0x05, 0x00}
-	if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) ||
+	if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) ||
 		!params.MGF.Algorithm.Equal(oidMGF1) ||
 		!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
-		!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) ||
+		!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) ||
 		params.TrailerField != 1 {
 		return UnknownSignatureAlgorithm
 	}
@@ -692,6 +689,7 @@ type Certificate struct {
 	// Name constraints
 	PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
 	PermittedDNSDomains         []string
+	ExcludedDNSDomains          []string
 
 	// CRL Distribution Points
 	CRLDistributionPoints []string
@@ -723,6 +721,10 @@ func (c *Certificate) Equal(other *Certificate) bool {
 	return bytes.Equal(c.Raw, other.Raw)
 }
 
+func (c *Certificate) hasSANExtension() bool {
+	return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
+}
+
 // Entrust have a broken root certificate (CN=Entrust.net Certification
 // Authority (2048)) which isn't marked as a CA certificate and is thus invalid
 // according to PKIX.
@@ -924,20 +926,17 @@ type distributionPointName struct {
 	RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
 }
 
-// asn1Null is the ASN.1 encoding of a NULL value.
-var asn1Null = []byte{5, 0}
-
 func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
 	asn1Data := keyData.PublicKey.RightAlign()
 	switch algo {
 	case RSA:
 		// RSA public keys must have a NULL in the parameters
 		// (https://tools.ietf.org/html/rfc3279#section-2.3.1).
-		if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) {
+		if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) {
 			return nil, errors.New("x509: RSA key missing NULL parameters")
 		}
 
-		p := new(rsaPublicKey)
+		p := new(pkcs1PublicKey)
 		rest, err := asn1.Unmarshal(asn1Data, p)
 		if err != nil {
 			return nil, err
@@ -1185,20 +1184,28 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					return nil, errors.New("x509: trailing data after X.509 NameConstraints")
 				}
 
-				if len(constraints.Excluded) > 0 && e.Critical {
-					return out, UnhandledCriticalExtension{}
-				}
-
-				for _, subtree := range constraints.Permitted {
-					if len(subtree.Name) == 0 {
-						if e.Critical {
-							return out, UnhandledCriticalExtension{}
+				getDNSNames := func(subtrees []generalSubtree, isCritical bool) (dnsNames []string, err error) {
+					for _, subtree := range subtrees {
+						if len(subtree.Name) == 0 {
+							if isCritical {
+								return nil, UnhandledCriticalExtension{}
+							}
+							continue
 						}
-						continue
+						dnsNames = append(dnsNames, subtree.Name)
 					}
-					out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
+
+					return dnsNames, nil
 				}
 
+				if out.PermittedDNSDomains, err = getDNSNames(constraints.Permitted, e.Critical); err != nil {
+					return out, err
+				}
+				if out.ExcludedDNSDomains, err = getDNSNames(constraints.Excluded, e.Critical); err != nil {
+					return out, err
+				}
+				out.PermittedDNSDomainsCritical = e.Critical
+
 			case 31:
 				// RFC 5280, 4.2.1.13
 
@@ -1451,7 +1458,7 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBy
 	return asn1.Marshal(rawValues)
 }
 
-func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
+func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.Extension, err error) {
 	ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
 	n := 0
 
@@ -1525,9 +1532,9 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 		n++
 	}
 
-	if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
+	if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
 		ret[n].Id = oidExtensionAuthorityKeyId
-		ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
+		ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId})
 		if err != nil {
 			return
 		}
@@ -1581,16 +1588,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 		n++
 	}
 
-	if len(template.PermittedDNSDomains) > 0 &&
+	if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0) &&
 		!oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) {
 		ret[n].Id = oidExtensionNameConstraints
 		ret[n].Critical = template.PermittedDNSDomainsCritical
 
 		var out nameConstraints
+
 		out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains))
 		for i, permitted := range template.PermittedDNSDomains {
 			out.Permitted[i] = generalSubtree{Name: permitted}
 		}
+		out.Excluded = make([]generalSubtree, len(template.ExcludedDNSDomains))
+		for i, excluded := range template.ExcludedDNSDomains {
+			out.Excluded[i] = generalSubtree{Name: excluded}
+		}
+
 		ret[n].Value, err = asn1.Marshal(out)
 		if err != nil {
 			return
@@ -1646,9 +1659,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
 		pubType = RSA
 		hashFunc = crypto.SHA256
 		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
-		sigAlgo.Parameters = asn1.RawValue{
-			Tag: 5,
-		}
+		sigAlgo.Parameters = asn1.NullRawValue
 
 	case *ecdsa.PublicKey:
 		pubType = ECDSA
@@ -1707,10 +1718,11 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
 }
 
 // CreateCertificate creates a new certificate based on a template. The
-// following members of template are used: SerialNumber, Subject, NotBefore,
-// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
-// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains, SignatureAlgorithm.
+// following members of template are used: AuthorityKeyId,
+// BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, IsCA,
+// KeyUsage, MaxPathLen, NotAfter, NotBefore, PermittedDNSDomains,
+// PermittedDNSDomainsCritical, SerialNumber, SignatureAlgorithm, Subject,
+// SubjectKeyId, and UnknownExtKeyUsage.
 //
 // The certificate is signed by parent. If parent is equal to template then the
 // certificate is self-signed. The parameter pub is the public key of the
@@ -1720,6 +1732,10 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
 //
 // All keys types that are implemented via crypto.Signer are supported (This
 // includes *rsa.PublicKey and *ecdsa.PublicKey.)
+//
+// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
+// unless the resulting certificate is self-signed. Otherwise the value from
+// template will be used.
 func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
 	key, ok := priv.(crypto.Signer)
 	if !ok {
@@ -1750,11 +1766,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
 		return
 	}
 
+	authorityKeyId := template.AuthorityKeyId
 	if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
-		template.AuthorityKeyId = parent.SubjectKeyId
+		authorityKeyId = parent.SubjectKeyId
 	}
 
-	extensions, err := buildExtensions(template)
+	extensions, err := buildExtensions(template, authorityKeyId)
 	if err != nil {
 		return
 	}
@@ -2025,10 +2042,10 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error)
 	return ret, nil
 }
 
-// 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.
+// CreateCertificateRequest creates a new certificate request based on a
+// template. The following members of template are used: Attributes, DNSNames,
+// EmailAddresses, ExtraExtensions, IPAddresses, SignatureAlgorithm, and
+// Subject. The private key is the private key of the signer.
 //
 // The returned slice is the certificate request in DER encoding.
 //
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index b085dad..2d1acf9 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -405,6 +405,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 
 			PolicyIdentifiers:   []asn1.ObjectIdentifier{[]int{1, 2, 3}},
 			PermittedDNSDomains: []string{".example.com", "example.com"},
+			ExcludedDNSDomains:  []string{"bar.example.com"},
 
 			CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
 
@@ -442,6 +443,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			t.Errorf("%s: failed to parse name constraints: %#v", test.name, cert.PermittedDNSDomains)
 		}
 
+		if len(cert.ExcludedDNSDomains) != 1 || cert.ExcludedDNSDomains[0] != "bar.example.com" {
+			t.Errorf("%s: failed to parse name constraint exclusions: %#v", test.name, cert.ExcludedDNSDomains)
+		}
+
 		if cert.Subject.CommonName != commonName {
 			t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
 		}
diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
index ea2f377..4983181 100644
--- a/src/database/sql/convert.go
+++ b/src/database/sql/convert.go
@@ -12,6 +12,7 @@ import (
 	"fmt"
 	"reflect"
 	"strconv"
+	"sync"
 	"time"
 	"unicode"
 	"unicode/utf8"
@@ -37,86 +38,180 @@ func validateNamedValueName(name string) error {
 	return fmt.Errorf("name %q does not begin with a letter", name)
 }
 
+func driverNumInput(ds *driverStmt) int {
+	ds.Lock()
+	defer ds.Unlock() // in case NumInput panics
+	return ds.si.NumInput()
+}
+
+// ccChecker wraps the driver.ColumnConverter and allows it to be used
+// as if it were a NamedValueChecker. If the driver ColumnConverter
+// is not present then the NamedValueChecker will return driver.ErrSkip.
+type ccChecker struct {
+	sync.Locker
+	cci  driver.ColumnConverter
+	want int
+}
+
+func (c ccChecker) CheckNamedValue(nv *driver.NamedValue) error {
+	if c.cci == nil {
+		return driver.ErrSkip
+	}
+	// The column converter shouldn't be called on any index
+	// it isn't expecting. The final error will be thrown
+	// in the argument converter loop.
+	index := nv.Ordinal - 1
+	if c.want <= index {
+		return nil
+	}
+
+	// First, see if the value itself knows how to convert
+	// itself to a driver type. For example, a NullString
+	// struct changing into a string or nil.
+	if vr, ok := nv.Value.(driver.Valuer); ok {
+		sv, err := callValuerValue(vr)
+		if err != nil {
+			return err
+		}
+		if !driver.IsValue(sv) {
+			return fmt.Errorf("non-subset type %T returned from Value", sv)
+		}
+		nv.Value = sv
+	}
+
+	// Second, ask the column to sanity check itself. For
+	// example, drivers might use this to make sure that
+	// an int64 values being inserted into a 16-bit
+	// integer field is in range (before getting
+	// truncated), or that a nil can't go into a NOT NULL
+	// column before going across the network to get the
+	// same error.
+	var err error
+	arg := nv.Value
+	c.Lock()
+	nv.Value, err = c.cci.ColumnConverter(index).ConvertValue(arg)
+	c.Unlock()
+	if err != nil {
+		return err
+	}
+	if !driver.IsValue(nv.Value) {
+		return fmt.Errorf("driver ColumnConverter error converted %T to unsupported type %T", arg, nv.Value)
+	}
+	return nil
+}
+
+// defaultCheckNamedValue wraps the default ColumnConverter to have the same
+// function signature as the CheckNamedValue in the driver.NamedValueChecker
+// interface.
+func defaultCheckNamedValue(nv *driver.NamedValue) (err error) {
+	nv.Value, err = driver.DefaultParameterConverter.ConvertValue(nv.Value)
+	return err
+}
+
 // driverArgs converts arguments from callers of Stmt.Exec and
 // Stmt.Query into driver Values.
 //
 // The statement ds may be nil, if no statement is available.
-func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) {
+func driverArgs(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) {
 	nvargs := make([]driver.NamedValue, len(args))
+
+	// -1 means the driver doesn't know how to count the number of
+	// placeholders, so we won't sanity check input here and instead let the
+	// driver deal with errors.
+	want := -1
+
 	var si driver.Stmt
+	var cc ccChecker
 	if ds != nil {
 		si = ds.si
+		want = driverNumInput(ds)
+		cc.Locker = ds.Locker
+		cc.want = want
 	}
-	cc, ok := si.(driver.ColumnConverter)
 
-	// Normal path, for a driver.Stmt that is not a ColumnConverter.
+	// Check all types of interfaces from the start.
+	// Drivers may opt to use the NamedValueChecker for special
+	// argument types, then return driver.ErrSkip to pass it along
+	// to the column converter.
+	nvc, ok := si.(driver.NamedValueChecker)
 	if !ok {
-		for n, arg := range args {
-			var err error
-			nv := &nvargs[n]
-			nv.Ordinal = n + 1
-			if np, ok := arg.(NamedArg); ok {
-				if err := validateNamedValueName(np.Name); err != nil {
-					return nil, err
-				}
-				arg = np.Value
-				nvargs[n].Name = np.Name
-			}
-			nv.Value, err = driver.DefaultParameterConverter.ConvertValue(arg)
-
-			if err != nil {
-				return nil, fmt.Errorf("sql: converting Exec argument %s type: %v", describeNamedValue(nv), err)
-			}
-		}
-		return nvargs, nil
+		nvc, ok = ci.(driver.NamedValueChecker)
+	}
+	cci, ok := si.(driver.ColumnConverter)
+	if ok {
+		cc.cci = cci
 	}
 
-	// Let the Stmt convert its own arguments.
-	for n, arg := range args {
+	// Loop through all the arguments, checking each one.
+	// If no error is returned simply increment the index
+	// and continue. However if driver.ErrRemoveArgument
+	// is returned the argument is not included in the query
+	// argument list.
+	var err error
+	var n int
+	for _, arg := range args {
 		nv := &nvargs[n]
-		nv.Ordinal = n + 1
 		if np, ok := arg.(NamedArg); ok {
-			if err := validateNamedValueName(np.Name); err != nil {
+			if err = validateNamedValueName(np.Name); err != nil {
 				return nil, err
 			}
 			arg = np.Value
 			nv.Name = np.Name
 		}
-		// First, see if the value itself knows how to convert
-		// itself to a driver type. For example, a NullString
-		// struct changing into a string or nil.
-		if vr, ok := arg.(driver.Valuer); ok {
-			sv, err := callValuerValue(vr)
-			if err != nil {
-				return nil, fmt.Errorf("sql: argument %s from Value: %v", describeNamedValue(nv), err)
-			}
-			if !driver.IsValue(sv) {
-				return nil, fmt.Errorf("sql: argument %s: non-subset type %T returned from Value", describeNamedValue(nv), sv)
-			}
-			arg = sv
+		nv.Ordinal = n + 1
+		nv.Value = arg
+
+		// Checking sequence has four routes:
+		// A: 1. Default
+		// B: 1. NamedValueChecker 2. Column Converter 3. Default
+		// C: 1. NamedValueChecker 3. Default
+		// D: 1. Column Converter 2. Default
+		//
+		// The only time a Column Converter is called is first
+		// or after NamedValueConverter. If first it is handled before
+		// the nextCheck label. Thus for repeats tries only when the
+		// NamedValueConverter is selected should the Column Converter
+		// be used in the retry.
+		checker := defaultCheckNamedValue
+		nextCC := false
+		switch {
+		case nvc != nil:
+			nextCC = cci != nil
+			checker = nvc.CheckNamedValue
+		case cci != nil:
+			checker = cc.CheckNamedValue
 		}
 
-		// Second, ask the column to sanity check itself. For
-		// example, drivers might use this to make sure that
-		// an int64 values being inserted into a 16-bit
-		// integer field is in range (before getting
-		// truncated), or that a nil can't go into a NOT NULL
-		// column before going across the network to get the
-		// same error.
-		var err error
-		ds.Lock()
-		nv.Value, err = cc.ColumnConverter(n).ConvertValue(arg)
-		ds.Unlock()
-		if err != nil {
+	nextCheck:
+		err = checker(nv)
+		switch err {
+		case nil:
+			n++
+			continue
+		case driver.ErrRemoveArgument:
+			nvargs = nvargs[:len(nvargs)-1]
+			continue
+		case driver.ErrSkip:
+			if nextCC {
+				nextCC = false
+				checker = cc.CheckNamedValue
+			} else {
+				checker = defaultCheckNamedValue
+			}
+			goto nextCheck
+		default:
 			return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err)
 		}
-		if !driver.IsValue(nv.Value) {
-			return nil, fmt.Errorf("sql: for argument %s, driver ColumnConverter error converted %T to unsupported type %T",
-				describeNamedValue(nv), arg, nv.Value)
-		}
+	}
+
+	// Check the length of arguments after convertion to allow for omitted
+	// arguments.
+	if want != -1 && len(nvargs) != want {
+		return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(nvargs))
 	}
 
 	return nvargs, nil
+
 }
 
 // convertAssign copies to dest the value in src, converting it if possible.
@@ -270,6 +365,11 @@ func convertAssign(dest, src interface{}) error {
 		return nil
 	}
 
+	// The following conversions use a string value as an intermediate representation
+	// to convert between various numeric types.
+	//
+	// This also allows scanning into user defined types such as "type Int int64".
+	// For symmetry, also check for string destination types.
 	switch dv.Kind() {
 	case reflect.Ptr:
 		if src == nil {
@@ -306,6 +406,15 @@ func convertAssign(dest, src interface{}) error {
 		}
 		dv.SetFloat(f64)
 		return nil
+	case reflect.String:
+		switch v := src.(type) {
+		case string:
+			dv.SetString(v)
+			return nil
+		case []byte:
+			dv.SetString(string(v))
+			return nil
+		}
 	}
 
 	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go
index 4dfab1f..cfe52d7 100644
--- a/src/database/sql/convert_test.go
+++ b/src/database/sql/convert_test.go
@@ -10,6 +10,7 @@ import (
 	"reflect"
 	"runtime"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 )
@@ -17,9 +18,11 @@ import (
 var someTime = time.Unix(123, 0)
 var answer int64 = 42
 
-type userDefined float64
-
-type userDefinedSlice []int
+type (
+	userDefined       float64
+	userDefinedSlice  []int
+	userDefinedString string
+)
 
 type conversionTest struct {
 	s, d interface{} // source and destination
@@ -39,6 +42,7 @@ type conversionTest struct {
 	wantptr    *int64 // if non-nil, *d's pointed value must be equal to *wantptr
 	wantnil    bool   // if true, *d must be *int64(nil)
 	wantusrdef userDefined
+	wantusrstr userDefinedString
 }
 
 // Target variables for scanning into.
@@ -171,6 +175,7 @@ var conversionTests = []conversionTest{
 	{s: int64(123), d: new(userDefined), wantusrdef: 123},
 	{s: "1.5", d: new(userDefined), wantusrdef: 1.5},
 	{s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
+	{s: "str", d: new(userDefinedString), wantusrstr: "str"},
 
 	// Other errors
 	{s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
@@ -260,6 +265,9 @@ func TestConversions(t *testing.T) {
 		if ct.wantusrdef != 0 && ct.wantusrdef != *ct.d.(*userDefined) {
 			errf("want userDefined %f, got %f", ct.wantusrdef, *ct.d.(*userDefined))
 		}
+		if len(ct.wantusrstr) != 0 && ct.wantusrstr != *ct.d.(*userDefinedString) {
+			errf("want userDefined %q, got %q", ct.wantusrstr, *ct.d.(*userDefinedString))
+		}
 	}
 }
 
@@ -461,8 +469,8 @@ func TestDriverArgs(t *testing.T) {
 		},
 	}
 	for i, tt := range tests {
-		ds := new(driverStmt)
-		got, err := driverArgs(ds, tt.args)
+		ds := &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{nil}}
+		got, err := driverArgs(nil, ds, tt.args)
 		if err != nil {
 			t.Errorf("test[%d]: %v", i, err)
 			continue
diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go
index d66196f..0262ca2 100644
--- a/src/database/sql/driver/driver.go
+++ b/src/database/sql/driver/driver.go
@@ -262,9 +262,39 @@ type StmtQueryContext interface {
 	QueryContext(ctx context.Context, args []NamedValue) (Rows, error)
 }
 
+// ErrRemoveArgument may be returned from NamedValueChecker to instruct the
+// sql package to not pass the argument to the driver query interface.
+// Return when accepting query specific options or structures that aren't
+// SQL query arguments.
+var ErrRemoveArgument = errors.New("driver: remove argument from query")
+
+// NamedValueChecker may be optionally implemented by Conn or Stmt. It provides
+// the driver more control to handle Go and database types beyond the default
+// Values types allowed.
+//
+// The sql package checks for value checkers in the following order,
+// stopping at the first found match: Stmt.NamedValueChecker, Conn.NamedValueChecker,
+// Stmt.ColumnConverter, DefaultParameterConverter.
+//
+// If CheckNamedValue returns ErrRemoveArgument, the NamedValue will not be included in
+// the final query arguments. This may be used to pass special options to
+// the query itself.
+//
+// If ErrSkip is returned the column converter error checking
+// path is used for the argument. Drivers may wish to return ErrSkip after
+// they have exhausted their own special cases.
+type NamedValueChecker interface {
+	// CheckNamedValue is called before passing arguments to the driver
+	// and is called in place of any ColumnConverter. CheckNamedValue must do type
+	// validation and conversion as appropriate for the driver.
+	CheckNamedValue(*NamedValue) error
+}
+
 // ColumnConverter may be optionally implemented by Stmt if the
 // statement is aware of its own columns' types and can convert from
 // any type to a driver Value.
+//
+// Deprecated: Drivers should implement NamedValueChecker.
 type ColumnConverter interface {
 	// ColumnConverter returns a ValueConverter for the provided
 	// column index. If the type of a specific column isn't known
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index 4b15f5b..4dcd096 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -58,9 +58,10 @@ type fakeDriver struct {
 type fakeDB struct {
 	name string
 
-	mu      sync.Mutex
-	tables  map[string]*table
-	badConn bool
+	mu       sync.Mutex
+	tables   map[string]*table
+	badConn  bool
+	allowAny bool
 }
 
 type table struct {
@@ -83,11 +84,20 @@ type row struct {
 	cols []interface{} // must be same size as its table colname + coltype
 }
 
+type memToucher interface {
+	// touchMem reads & writes some memory, to help find data races.
+	touchMem()
+}
+
 type fakeConn struct {
 	db *fakeDB // where to return ourselves to
 
 	currTx *fakeTx
 
+	// Every operation writes to line to enable the race detector
+	// check for data races.
+	line int64
+
 	// Stats for tests:
 	mu          sync.Mutex
 	stmtsMade   int
@@ -99,6 +109,10 @@ type fakeConn struct {
 	stickyBad bool
 }
 
+func (c *fakeConn) touchMem() {
+	c.line++
+}
+
 func (c *fakeConn) incrStat(v *int) {
 	c.mu.Lock()
 	*v++
@@ -116,6 +130,7 @@ type boundCol struct {
 }
 
 type fakeStmt struct {
+	memToucher
 	c *fakeConn
 	q string // just for debugging
 
@@ -298,6 +313,7 @@ func (c *fakeConn) Begin() (driver.Tx, error) {
 	if c.currTx != nil {
 		return nil, errors.New("already in a transaction")
 	}
+	c.touchMem()
 	c.currTx = &fakeTx{c: c}
 	return c.currTx, nil
 }
@@ -339,6 +355,7 @@ func (c *fakeConn) Close() (err error) {
 			drv.mu.Unlock()
 		}
 	}()
+	c.touchMem()
 	if c.currTx != nil {
 		return errors.New("can't close fakeConn; in a Transaction")
 	}
@@ -352,12 +369,14 @@ func (c *fakeConn) Close() (err error) {
 	return nil
 }
 
-func checkSubsetTypes(args []driver.NamedValue) error {
+func checkSubsetTypes(allowAny bool, args []driver.NamedValue) error {
 	for _, arg := range args {
 		switch arg.Value.(type) {
 		case int64, float64, bool, nil, []byte, string, time.Time:
 		default:
-			return fmt.Errorf("fakedb_test: invalid argument ordinal %[1]d: %[2]v, type %[2]T", arg.Ordinal, arg.Value)
+			if !allowAny {
+				return fmt.Errorf("fakedb_test: invalid argument ordinal %[1]d: %[2]v, type %[2]T", arg.Ordinal, arg.Value)
+			}
 		}
 	}
 	return nil
@@ -373,7 +392,7 @@ func (c *fakeConn) ExecContext(ctx context.Context, query string, args []driver.
 	// just to check that all the args are of the proper types.
 	// ErrSkip is returned so the caller acts as if we didn't
 	// implement this at all.
-	err := checkSubsetTypes(args)
+	err := checkSubsetTypes(c.db.allowAny, args)
 	if err != nil {
 		return nil, err
 	}
@@ -390,7 +409,7 @@ func (c *fakeConn) QueryContext(ctx context.Context, query string, args []driver
 	// just to check that all the args are of the proper types.
 	// ErrSkip is returned so the caller acts as if we didn't
 	// implement this at all.
-	err := checkSubsetTypes(args)
+	err := checkSubsetTypes(c.db.allowAny, args)
 	if err != nil {
 		return nil, err
 	}
@@ -524,13 +543,14 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm
 		return nil, driver.ErrBadConn
 	}
 
+	c.touchMem()
 	var firstStmt, prev *fakeStmt
 	for _, query := range strings.Split(query, ";") {
 		parts := strings.Split(query, "|")
 		if len(parts) < 1 {
 			return nil, errf("empty query")
 		}
-		stmt := &fakeStmt{q: query, c: c}
+		stmt := &fakeStmt{q: query, c: c, memToucher: c}
 		if firstStmt == nil {
 			firstStmt = stmt
 		}
@@ -612,6 +632,7 @@ func (s *fakeStmt) Close() error {
 	if s.c.db == nil {
 		panic("in fakeStmt.Close, conn's db is nil (already closed)")
 	}
+	s.touchMem()
 	if !s.closed {
 		s.c.incrStat(&s.c.stmtsClosed)
 		s.closed = true
@@ -642,10 +663,11 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d
 		return nil, driver.ErrBadConn
 	}
 
-	err := checkSubsetTypes(args)
+	err := checkSubsetTypes(s.c.db.allowAny, args)
 	if err != nil {
 		return nil, err
 	}
+	s.touchMem()
 
 	if s.wait > 0 {
 		time.Sleep(s.wait)
@@ -753,11 +775,12 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
 		return nil, driver.ErrBadConn
 	}
 
-	err := checkSubsetTypes(args)
+	err := checkSubsetTypes(s.c.db.allowAny, args)
 	if err != nil {
 		return nil, err
 	}
 
+	s.touchMem()
 	db := s.c.db
 	if len(args) != s.placeholders {
 		panic("error in pkg db; should only get here if size is correct")
@@ -853,11 +876,12 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
 	}
 
 	cursor := &rowsCursor{
-		posRow:  -1,
-		rows:    setMRows,
-		cols:    setColumns,
-		colType: setColType,
-		errPos:  -1,
+		parentMem: s.c,
+		posRow:    -1,
+		rows:      setMRows,
+		cols:      setColumns,
+		colType:   setColType,
+		errPos:    -1,
 	}
 	return cursor, nil
 }
@@ -877,6 +901,7 @@ func (tx *fakeTx) Commit() error {
 	if hookCommitBadConn != nil && hookCommitBadConn() {
 		return driver.ErrBadConn
 	}
+	tx.c.touchMem()
 	return nil
 }
 
@@ -888,16 +913,18 @@ func (tx *fakeTx) Rollback() error {
 	if hookRollbackBadConn != nil && hookRollbackBadConn() {
 		return driver.ErrBadConn
 	}
+	tx.c.touchMem()
 	return nil
 }
 
 type rowsCursor struct {
-	cols    [][]string
-	colType [][]string
-	posSet  int
-	posRow  int
-	rows    [][]*row
-	closed  bool
+	parentMem memToucher
+	cols      [][]string
+	colType   [][]string
+	posSet    int
+	posRow    int
+	rows      [][]*row
+	closed    bool
 
 	// errPos and err are for making Next return early with error.
 	errPos int
@@ -907,6 +934,16 @@ type rowsCursor struct {
 	// the original slice's first byte address.  we clone them
 	// just so we're able to corrupt them on close.
 	bytesClone map[*byte][]byte
+
+	// Every operation writes to line to enable the race detector
+	// check for data races.
+	// This is separate from the fakeConn.line to allow for drivers that
+	// can start multiple queries on the same transaction at the same time.
+	line int64
+}
+
+func (rc *rowsCursor) touchMem() {
+	rc.line++
 }
 
 func (rc *rowsCursor) Close() error {
@@ -915,6 +952,8 @@ func (rc *rowsCursor) Close() error {
 			bs[0] = 255 // first byte corrupted
 		}
 	}
+	rc.touchMem()
+	rc.parentMem.touchMem()
 	rc.closed = true
 	return nil
 }
@@ -937,6 +976,7 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
 	if rc.closed {
 		return errors.New("fakedb: cursor is closed")
 	}
+	rc.touchMem()
 	rc.posRow++
 	if rc.posRow == rc.errPos {
 		return rc.err
@@ -970,10 +1010,12 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
 }
 
 func (rc *rowsCursor) HasNextResultSet() bool {
+	rc.touchMem()
 	return rc.posSet < len(rc.rows)-1
 }
 
 func (rc *rowsCursor) NextResultSet() error {
+	rc.touchMem()
 	if rc.HasNextResultSet() {
 		rc.posSet++
 		rc.posRow = -1
@@ -1004,6 +1046,12 @@ func (fakeDriverString) ConvertValue(v interface{}) (driver.Value, error) {
 	return fmt.Sprintf("%v", v), nil
 }
 
+type anyTypeConverter struct{}
+
+func (anyTypeConverter) ConvertValue(v interface{}) (driver.Value, error) {
+	return v, nil
+}
+
 func converterForType(typ string) driver.ValueConverter {
 	switch typ {
 	case "bool":
@@ -1030,6 +1078,8 @@ func converterForType(typ string) driver.ValueConverter {
 		return driver.Null{Converter: driver.DefaultParameterConverter}
 	case "datetime":
 		return driver.DefaultParameterConverter
+	case "any":
+		return anyTypeConverter{}
 	}
 	panic("invalid fakedb column type of " + typ)
 }
@@ -1056,6 +1106,8 @@ func colTypeToReflectType(typ string) reflect.Type {
 		return reflect.TypeOf(NullFloat64{})
 	case "datetime":
 		return reflect.TypeOf(time.Time{})
+	case "any":
+		return reflect.TypeOf(new(interface{})).Elem()
 	}
 	panic("invalid fakedb column type of " + typ)
 }
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index f8a8844..59bbf59 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -278,6 +278,27 @@ type Scanner interface {
 	Scan(src interface{}) error
 }
 
+// Out may be used to retrieve OUTPUT value parameters from stored procedures.
+//
+// Not all drivers and databases support OUTPUT value parameters.
+//
+// Example usage:
+//
+//   var outArg string
+//   _, err := db.ExecContext(ctx, "ProcName", sql.Named("Arg1", Out{Dest: &outArg}))
+type Out struct {
+	_Named_Fields_Required struct{}
+
+	// Dest is a pointer to the value that will be set to the result of the
+	// stored procedure's OUTPUT parameter.
+	Dest interface{}
+
+	// In is whether the parameter is an INOUT parameter. If so, the input value to the stored
+	// procedure is the dereferenced value of Dest's pointer, which is then replaced with
+	// the output value.
+	In bool
+}
+
 // ErrNoRows is returned by Scan when QueryRow doesn't return a
 // row. In such a case, QueryRow returns a placeholder *Row value that
 // defers this error until a Scan.
@@ -372,11 +393,19 @@ func (dc *driverConn) expired(timeout time.Duration) bool {
 	return dc.createdAt.Add(timeout).Before(nowFunc())
 }
 
-func (dc *driverConn) prepareLocked(ctx context.Context, query string) (*driverStmt, error) {
+// prepareLocked prepares the query on dc. When cg == nil the dc must keep track of
+// the prepared statements in a pool.
+func (dc *driverConn) prepareLocked(ctx context.Context, cg stmtConnGrabber, query string) (*driverStmt, error) {
 	si, err := ctxDriverPrepare(ctx, dc.ci, query)
 	if err != nil {
 		return nil, err
 	}
+	ds := &driverStmt{Locker: dc, si: si}
+
+	// No need to manage open statements if there is a single connection grabber.
+	if cg != nil {
+		return ds, nil
+	}
 
 	// Track each driverConn's open statements, so we can close them
 	// before closing the conn.
@@ -385,9 +414,7 @@ func (dc *driverConn) prepareLocked(ctx context.Context, query string) (*driverS
 	if dc.openStmt == nil {
 		dc.openStmt = make(map[*driverStmt]bool)
 	}
-	ds := &driverStmt{Locker: dc, si: si}
 	dc.openStmt[ds] = true
-
 	return ds, nil
 }
 
@@ -583,6 +610,17 @@ func Open(driverName, dataSourceName string) (*DB, error) {
 	return db, nil
 }
 
+func (db *DB) pingDC(ctx context.Context, dc *driverConn, release func(error)) error {
+	var err error
+	if pinger, ok := dc.ci.(driver.Pinger); ok {
+		withLock(dc, func() {
+			err = pinger.Ping(ctx)
+		})
+	}
+	release(err)
+	return err
+}
+
 // PingContext verifies a connection to the database is still alive,
 // establishing a connection if necessary.
 func (db *DB) PingContext(ctx context.Context) error {
@@ -602,11 +640,7 @@ func (db *DB) PingContext(ctx context.Context) error {
 		return err
 	}
 
-	if pinger, ok := dc.ci.(driver.Pinger); ok {
-		err = pinger.Ping(ctx)
-	}
-	db.putConn(dc, err)
-	return err
+	return db.pingDC(ctx, dc, dc.releaseConn)
 }
 
 // Ping verifies a connection to the database is still alive,
@@ -975,9 +1009,9 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
 		db:        db,
 		createdAt: nowFunc(),
 		ci:        ci,
+		inUse:     true,
 	}
 	db.addDepLocked(dc, dc)
-	dc.inUse = true
 	db.mu.Unlock()
 	return dc, nil
 }
@@ -1137,22 +1171,39 @@ func (db *DB) prepare(ctx context.Context, query string, strategy connReuseStrat
 	if err != nil {
 		return nil, err
 	}
+	return db.prepareDC(ctx, dc, dc.releaseConn, nil, query)
+}
+
+// prepareDC prepares a query on the driverConn and calls release before
+// returning. When cg == nil it implies that a connection pool is used, and
+// when cg != nil only a single driver connection is used.
+func (db *DB) prepareDC(ctx context.Context, dc *driverConn, release func(error), cg stmtConnGrabber, query string) (*Stmt, error) {
 	var ds *driverStmt
+	var err error
+	defer func() {
+		release(err)
+	}()
 	withLock(dc, func() {
-		ds, err = dc.prepareLocked(ctx, query)
+		ds, err = dc.prepareLocked(ctx, cg, query)
 	})
 	if err != nil {
-		db.putConn(dc, err)
 		return nil, err
 	}
 	stmt := &Stmt{
-		db:            db,
-		query:         query,
-		css:           []connStmt{{dc, ds}},
-		lastNumClosed: atomic.LoadUint64(&db.numClosed),
+		db:    db,
+		query: query,
+		cg:    cg,
+		cgds:  ds,
+	}
+
+	// When cg == nil this statement will need to keep track of various
+	// connections they are prepared on and record the stmt dependency on
+	// the DB.
+	if cg == nil {
+		stmt.css = []connStmt{{dc, ds}}
+		stmt.lastNumClosed = atomic.LoadUint64(&db.numClosed)
+		db.addDep(stmt, stmt)
 	}
-	db.addDep(stmt, stmt)
-	db.putConn(dc, nil)
 	return stmt, nil
 }
 
@@ -1179,18 +1230,21 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
 	return db.ExecContext(context.Background(), query, args...)
 }
 
-func (db *DB) exec(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
+func (db *DB) exec(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (Result, error) {
 	dc, err := db.conn(ctx, strategy)
 	if err != nil {
 		return nil, err
 	}
+	return db.execDC(ctx, dc, dc.releaseConn, query, args)
+}
+
+func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []interface{}) (res Result, err error) {
 	defer func() {
-		db.putConn(dc, err)
+		release(err)
 	}()
-
 	if execer, ok := dc.ci.(driver.Execer); ok {
 		var dargs []driver.NamedValue
-		dargs, err = driverArgs(nil, args)
+		dargs, err = driverArgs(dc.ci, nil, args)
 		if err != nil {
 			return nil, err
 		}
@@ -1215,7 +1269,7 @@ func (db *DB) exec(ctx context.Context, query string, args []interface{}, strate
 	}
 	ds := &driverStmt{Locker: dc, si: si}
 	defer ds.Close()
-	return resultFromStatement(ctx, ds, args...)
+	return resultFromStatement(ctx, dc.ci, ds, args...)
 }
 
 // QueryContext executes a query that returns rows, typically a SELECT.
@@ -1242,19 +1296,21 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 }
 
 func (db *DB) query(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
-	ci, err := db.conn(ctx, strategy)
+	dc, err := db.conn(ctx, strategy)
 	if err != nil {
 		return nil, err
 	}
 
-	return db.queryConn(ctx, ci, ci.releaseConn, query, args)
+	return db.queryDC(ctx, nil, dc, dc.releaseConn, query, args)
 }
 
-// queryConn executes a query on the given connection.
+// queryDC executes a query on the given connection.
 // The connection gets released by the releaseConn function.
-func (db *DB) queryConn(ctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
+// The ctx context is from a query method and the txctx context is from an
+// optional transaction context.
+func (db *DB) queryDC(ctx, txctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
 	if queryer, ok := dc.ci.(driver.Queryer); ok {
-		dargs, err := driverArgs(nil, args)
+		dargs, err := driverArgs(dc.ci, nil, args)
 		if err != nil {
 			releaseConn(err)
 			return nil, err
@@ -1275,7 +1331,7 @@ func (db *DB) queryConn(ctx context.Context, dc *driverConn, releaseConn func(er
 				releaseConn: releaseConn,
 				rowsi:       rowsi,
 			}
-			rows.initContextClose(ctx)
+			rows.initContextClose(ctx, txctx)
 			return rows, nil
 		}
 	}
@@ -1291,7 +1347,7 @@ func (db *DB) queryConn(ctx context.Context, dc *driverConn, releaseConn func(er
 	}
 
 	ds := &driverStmt{Locker: dc, si: si}
-	rowsi, err := rowsiFromStatement(ctx, ds, args...)
+	rowsi, err := rowsiFromStatement(ctx, dc.ci, ds, args...)
 	if err != nil {
 		ds.Close()
 		releaseConn(err)
@@ -1306,13 +1362,16 @@ func (db *DB) queryConn(ctx context.Context, dc *driverConn, releaseConn func(er
 		rowsi:       rowsi,
 		closeStmt:   ds,
 	}
-	rows.initContextClose(ctx)
+	rows.initContextClose(ctx, txctx)
 	return rows, nil
 }
 
 // QueryRowContext executes a query that is expected to return at most one row.
 // QueryRowContext always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
 func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
 	rows, err := db.QueryContext(ctx, query, args...)
 	return &Row{rows: rows, err: err}
@@ -1321,6 +1380,9 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interfa
 // QueryRow executes a query that is expected to return at most one row.
 // QueryRow always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 	return db.QueryRowContext(context.Background(), query, args...)
 }
@@ -1361,12 +1423,17 @@ func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStra
 	if err != nil {
 		return nil, err
 	}
+	return db.beginDC(ctx, dc, dc.releaseConn, opts)
+}
+
+// beginDC starts a transaction. The provided dc must be valid and ready to use.
+func (db *DB) beginDC(ctx context.Context, dc *driverConn, release func(error), opts *TxOptions) (tx *Tx, err error) {
 	var txi driver.Tx
 	withLock(dc, func() {
 		txi, err = ctxDriverBegin(ctx, opts, dc.ci)
 	})
 	if err != nil {
-		db.putConn(dc, err)
+		release(err)
 		return nil, err
 	}
 
@@ -1374,11 +1441,12 @@ func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStra
 	// The cancel function in Tx will be called after done is set to true.
 	ctx, cancel := context.WithCancel(ctx)
 	tx = &Tx{
-		db:     db,
-		dc:     dc,
-		txi:    txi,
-		cancel: cancel,
-		ctx:    ctx,
+		db:          db,
+		dc:          dc,
+		releaseConn: release,
+		txi:         txi,
+		cancel:      cancel,
+		ctx:         ctx,
 	}
 	go tx.awaitDone()
 	return tx, nil
@@ -1389,6 +1457,189 @@ func (db *DB) Driver() driver.Driver {
 	return db.driver
 }
 
+// ErrConnDone is returned by any operation that is performed on a connection
+// that has already been committed or rolled back.
+var ErrConnDone = errors.New("database/sql: connection is already closed")
+
+// Conn returns a single connection by either opening a new connection
+// or returning an existing connection from the connection pool. Conn will
+// block until either a connection is returned or ctx is canceled.
+// Queries run on the same Conn will be run in the same database session.
+//
+// Every Conn must be returned to the database pool after use by
+// calling Conn.Close.
+func (db *DB) Conn(ctx context.Context) (*Conn, error) {
+	var dc *driverConn
+	var err error
+	for i := 0; i < maxBadConnRetries; i++ {
+		dc, err = db.conn(ctx, cachedOrNewConn)
+		if err != driver.ErrBadConn {
+			break
+		}
+	}
+	if err == driver.ErrBadConn {
+		dc, err = db.conn(ctx, cachedOrNewConn)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	conn := &Conn{
+		db: db,
+		dc: dc,
+	}
+	return conn, nil
+}
+
+type releaseConn func(error)
+
+// Conn represents a single database session rather a pool of database
+// sessions. Prefer running queries from DB unless there is a specific
+// need for a continuous single database session.
+//
+// A Conn must call Close to return the connection to the database pool
+// and may do so concurrently with a running query.
+//
+// After a call to Close, all operations on the
+// connection fail with ErrConnDone.
+type Conn struct {
+	db *DB
+
+	// closemu prevents the connection from closing while there
+	// is an active query. It is held for read during queries
+	// and exclusively during close.
+	closemu sync.RWMutex
+
+	// dc is owned until close, at which point
+	// it's returned to the connection pool.
+	dc *driverConn
+
+	// done transitions from 0 to 1 exactly once, on close.
+	// Once done, all operations fail with ErrConnDone.
+	// Use atomic operations on value when checking value.
+	done int32
+}
+
+func (c *Conn) grabConn(context.Context) (*driverConn, releaseConn, error) {
+	if atomic.LoadInt32(&c.done) != 0 {
+		return nil, nil, ErrConnDone
+	}
+	c.closemu.RLock()
+	return c.dc, c.closemuRUnlockCondReleaseConn, nil
+}
+
+// PingContext verifies the connection to the database is still alive.
+func (c *Conn) PingContext(ctx context.Context) error {
+	dc, release, err := c.grabConn(ctx)
+	if err != nil {
+		return err
+	}
+	return c.db.pingDC(ctx, dc, release)
+}
+
+// ExecContext executes a query without returning any rows.
+// The args are for any placeholder parameters in the query.
+func (c *Conn) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
+	dc, release, err := c.grabConn(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return c.db.execDC(ctx, dc, release, query, args)
+}
+
+// QueryContext executes a query that returns rows, typically a SELECT.
+// The args are for any placeholder parameters in the query.
+func (c *Conn) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+	dc, release, err := c.grabConn(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return c.db.queryDC(ctx, nil, dc, release, query, args)
+}
+
+// QueryRowContext executes a query that is expected to return at most one row.
+// QueryRowContext always returns a non-nil value. Errors are deferred until
+// Row's Scan method is called.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
+func (c *Conn) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
+	rows, err := c.QueryContext(ctx, query, args...)
+	return &Row{rows: rows, err: err}
+}
+
+// PrepareContext creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
+//
+// The provided context is used for the preparation of the statement, not for the
+// execution of the statement.
+func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
+	dc, release, err := c.grabConn(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return c.db.prepareDC(ctx, dc, release, c, query)
+}
+
+// BeginTx starts a transaction.
+//
+// The provided context is used until the transaction is committed or rolled back.
+// If the context is canceled, the sql package will roll back
+// the transaction. Tx.Commit will return an error if the context provided to
+// BeginTx is canceled.
+//
+// The provided TxOptions is optional and may be nil if defaults should be used.
+// If a non-default isolation level is used that the driver doesn't support,
+// an error will be returned.
+func (c *Conn) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
+	dc, release, err := c.grabConn(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return c.db.beginDC(ctx, dc, release, opts)
+}
+
+// closemuRUnlockCondReleaseConn read unlocks closemu
+// as the sql operation is done with the dc.
+func (c *Conn) closemuRUnlockCondReleaseConn(err error) {
+	c.closemu.RUnlock()
+	if err == driver.ErrBadConn {
+		c.close(err)
+	}
+}
+
+func (c *Conn) txCtx() context.Context {
+	return nil
+}
+
+func (c *Conn) close(err error) error {
+	if !atomic.CompareAndSwapInt32(&c.done, 0, 1) {
+		return ErrConnDone
+	}
+
+	// Lock around releasing the driver connection
+	// to ensure all queries have been stopped before doing so.
+	c.closemu.Lock()
+	defer c.closemu.Unlock()
+
+	c.dc.releaseConn(err)
+	c.dc = nil
+	c.db = nil
+	return err
+}
+
+// Close returns the connection to the connection pool.
+// All operations after a Close will return with ErrConnDone.
+// Close is safe to call concurrently with other operations and will
+// block until all other operations finish. It may be useful to first
+// cancel any used context and then call close directly after.
+func (c *Conn) Close() error {
+	return c.close(nil)
+}
+
 // Tx is an in-progress database transaction.
 //
 // A transaction must end with a call to Commit or Rollback.
@@ -1412,6 +1663,10 @@ type Tx struct {
 	dc  *driverConn
 	txi driver.Tx
 
+	// releaseConn is called once the Tx is closed to release
+	// any held driverConn back to the pool.
+	releaseConn func(error)
+
 	// done transitions from 0 to 1 exactly once, on Commit
 	// or Rollback. once done, all operations fail with
 	// ErrTxDone.
@@ -1425,7 +1680,7 @@ type Tx struct {
 		v []*Stmt
 	}
 
-	// cancel is called after done transitions from false to true.
+	// cancel is called after done transitions from 0 to 1.
 	cancel func()
 
 	// ctx lives for the life of the transaction.
@@ -1457,11 +1712,12 @@ var ErrTxDone = errors.New("sql: Transaction has already been committed or rolle
 // close returns the connection to the pool and
 // must only be called by Tx.rollback or Tx.Commit.
 func (tx *Tx) close(err error) {
+	tx.cancel()
+
 	tx.closemu.Lock()
 	defer tx.closemu.Unlock()
 
-	tx.db.putConn(tx.dc, err)
-	tx.cancel()
+	tx.releaseConn(err)
 	tx.dc = nil
 	tx.txi = nil
 }
@@ -1470,19 +1726,36 @@ func (tx *Tx) close(err error) {
 // a successful call to (*Tx).grabConn. For tests.
 var hookTxGrabConn func()
 
-func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
+func (tx *Tx) grabConn(ctx context.Context) (*driverConn, releaseConn, error) {
 	select {
 	default:
 	case <-ctx.Done():
-		return nil, ctx.Err()
+		return nil, nil, ctx.Err()
 	}
+
+	// closeme.RLock must come before the check for isDone to prevent the Tx from
+	// closing while a query is executing.
+	tx.closemu.RLock()
 	if tx.isDone() {
-		return nil, ErrTxDone
+		tx.closemu.RUnlock()
+		return nil, nil, ErrTxDone
 	}
 	if hookTxGrabConn != nil { // test hook
 		hookTxGrabConn()
 	}
-	return tx.dc, nil
+	return tx.dc, tx.closemuRUnlockRelease, nil
+}
+
+func (tx *Tx) txCtx() context.Context {
+	return tx.ctx
+}
+
+// closemuRUnlockRelease is used as a func(error) method value in
+// ExecContext and QueryContext. Unlocking in the releaseConn keeps
+// the driver conn from being returned to the connection pool until
+// the Rows has been closed.
+func (tx *Tx) closemuRUnlockRelease(error) {
+	tx.closemu.RUnlock()
 }
 
 // Closes all Stmts prepared for this transaction.
@@ -1551,44 +1824,15 @@ func (tx *Tx) Rollback() error {
 // for the execution of the returned statement. The returned statement
 // will run in the transaction context.
 func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
-	tx.closemu.RLock()
-	defer tx.closemu.RUnlock()
-
-	// TODO(bradfitz): We could be more efficient here and either
-	// provide a method to take an existing Stmt (created on
-	// perhaps a different Conn), and re-create it on this Conn if
-	// 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
-	// 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.
-	// Perhaps just looking at the reference count (by noting
-	// Stmt.Close) would be enough. We might also want a finalizer
-	// on Stmt to drop the reference count.
-	dc, err := tx.grabConn(ctx)
+	dc, release, err := tx.grabConn(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	var si driver.Stmt
-	withLock(dc, func() {
-		si, err = ctxDriverPrepare(ctx, dc.ci, query)
-	})
+	stmt, err := tx.db.prepareDC(ctx, dc, release, tx, query)
 	if err != nil {
 		return nil, err
 	}
-
-	stmt := &Stmt{
-		db: tx.db,
-		tx: tx,
-		txds: &driverStmt{
-			Locker: dc,
-			si:     si,
-		},
-		query: query,
-	}
 	tx.stmts.Lock()
 	tx.stmts.v = append(tx.stmts.v, stmt)
 	tx.stmts.Unlock()
@@ -1618,34 +1862,67 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 // The returned statement operates within the transaction and will be closed
 // when the transaction has been committed or rolled back.
 func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
-	tx.closemu.RLock()
-	defer tx.closemu.RUnlock()
-
-	// TODO(bradfitz): optimize this. Currently this re-prepares
-	// 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.
+	dc, release, err := tx.grabConn(ctx)
+	if err != nil {
+		return &Stmt{stickyErr: err}
+	}
+	defer release(nil)
 
 	if tx.db != stmt.db {
 		return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
 	}
-	dc, err := tx.grabConn(ctx)
-	if err != nil {
-		return &Stmt{stickyErr: err}
-	}
 	var si driver.Stmt
-	withLock(dc, func() {
-		si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
-	})
+	var parentStmt *Stmt
+	stmt.mu.Lock()
+	if stmt.closed || stmt.cg != nil {
+		// If the statement has been closed or already belongs to a
+		// transaction, we can't reuse it in this connection.
+		// Since tx.StmtContext should never need to be called with a
+		// Stmt already belonging to tx, we ignore this edge case and
+		// re-prepare the statement in this case. No need to add
+		// code-complexity for this.
+		stmt.mu.Unlock()
+		withLock(dc, func() {
+			si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
+		})
+		if err != nil {
+			return &Stmt{stickyErr: err}
+		}
+	} else {
+		stmt.removeClosedStmtLocked()
+		// See if the statement has already been prepared on this connection,
+		// and reuse it if possible.
+		for _, v := range stmt.css {
+			if v.dc == dc {
+				si = v.ds.si
+				break
+			}
+		}
+
+		stmt.mu.Unlock()
+
+		if si == nil {
+			cs, err := stmt.prepareOnConnLocked(ctx, dc)
+			if err != nil {
+				return &Stmt{stickyErr: err}
+			}
+			si = cs.si
+		}
+		parentStmt = stmt
+	}
+
 	txs := &Stmt{
 		db: tx.db,
-		tx: tx,
-		txds: &driverStmt{
+		cg: tx,
+		cgds: &driverStmt{
 			Locker: dc,
 			si:     si,
 		},
-		query:     stmt.query,
-		stickyErr: err,
+		parentStmt: parentStmt,
+		query:      stmt.query,
+	}
+	if parentStmt != nil {
+		tx.db.addDep(parentStmt, txs)
 	}
 	tx.stmts.Lock()
 	tx.stmts.v = append(tx.stmts.v, txs)
@@ -1672,42 +1949,11 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
 // ExecContext executes a query that doesn't return rows.
 // For example: an INSERT and UPDATE.
 func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
-	tx.closemu.RLock()
-	defer tx.closemu.RUnlock()
-
-	dc, err := tx.grabConn(ctx)
+	dc, release, err := tx.grabConn(ctx)
 	if err != nil {
 		return nil, err
 	}
-
-	if execer, ok := dc.ci.(driver.Execer); ok {
-		dargs, err := driverArgs(nil, args)
-		if err != nil {
-			return nil, err
-		}
-		var resi driver.Result
-		withLock(dc, func() {
-			resi, err = ctxDriverExec(ctx, execer, query, dargs)
-		})
-		if err == nil {
-			return driverResult{dc, resi}, nil
-		}
-		if err != driver.ErrSkip {
-			return nil, err
-		}
-	}
-
-	var si driver.Stmt
-	withLock(dc, func() {
-		si, err = ctxDriverPrepare(ctx, dc.ci, query)
-	})
-	if err != nil {
-		return nil, err
-	}
-	ds := &driverStmt{Locker: dc, si: si}
-	defer ds.Close()
-
-	return resultFromStatement(ctx, ds, args...)
+	return tx.db.execDC(ctx, dc, release, query, args)
 }
 
 // Exec executes a query that doesn't return rows.
@@ -1718,15 +1964,12 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
 
 // QueryContext executes a query that returns rows, typically a SELECT.
 func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
-	tx.closemu.RLock()
-	defer tx.closemu.RUnlock()
-
-	dc, err := tx.grabConn(ctx)
+	dc, release, err := tx.grabConn(ctx)
 	if err != nil {
 		return nil, err
 	}
-	releaseConn := func(error) {}
-	return tx.db.queryConn(ctx, dc, releaseConn, query, args)
+
+	return tx.db.queryDC(ctx, tx.ctx, dc, release, query, args)
 }
 
 // Query executes a query that returns rows, typically a SELECT.
@@ -1737,6 +1980,9 @@ func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
 // QueryRowContext executes a query that is expected to return at most one row.
 // QueryRowContext always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
 func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
 	rows, err := tx.QueryContext(ctx, query, args...)
 	return &Row{rows: rows, err: err}
@@ -1745,6 +1991,9 @@ func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interfa
 // QueryRow executes a query that is expected to return at most one row.
 // QueryRow always returns a non-nil value. Errors are deferred until
 // Row's Scan method is called.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
 func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
 	return tx.QueryRowContext(context.Background(), query, args...)
 }
@@ -1755,6 +2004,24 @@ type connStmt struct {
 	ds *driverStmt
 }
 
+// stmtConnGrabber represents a Tx or Conn that will return the underlying
+// driverConn and release function.
+type stmtConnGrabber interface {
+	// grabConn returns the driverConn and the associated release function
+	// that must be called when the operation completes.
+	grabConn(context.Context) (*driverConn, releaseConn, error)
+
+	// txCtx returns the transaction context if available.
+	// The returned context should be selected on along with
+	// any query context when awaiting a cancel.
+	txCtx() context.Context
+}
+
+var (
+	_ stmtConnGrabber = &Tx{}
+	_ stmtConnGrabber = &Conn{}
+)
+
 // Stmt is a prepared statement.
 // A Stmt is safe for concurrent use by multiple goroutines.
 type Stmt struct {
@@ -1765,17 +2032,29 @@ type Stmt struct {
 
 	closemu sync.RWMutex // held exclusively during close, for read otherwise.
 
-	// If in a transaction, else both nil:
-	tx   *Tx
-	txds *driverStmt
+	// If Stmt is prepared on a Tx or Conn then cg is present and will
+	// only ever grab a connection from cg.
+	// If cg is nil then the Stmt must grab an arbitrary connection
+	// from db and determine if it must prepare the stmt again by
+	// inspecting css.
+	cg   stmtConnGrabber
+	cgds *driverStmt
+
+	// parentStmt is set when a transaction-specific statement
+	// is requested from an identical statement prepared on the same
+	// conn. parentStmt is used to track the dependency of this statement
+	// on its originating ("parent") statement so that parentStmt may
+	// be closed by the user without them having to know whether or not
+	// any transactions are still using it.
+	parentStmt *Stmt
 
 	mu     sync.Mutex // protects the rest of the fields
 	closed bool
 
 	// css is a list of underlying driver statement interfaces
 	// 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.
+	// used if cg == nil and one is found that has idle
+	// connections. If cg != nil, cgds is always used.
 	css []connStmt
 
 	// lastNumClosed is copied from db.numClosed when Stmt is created
@@ -1790,8 +2069,12 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, er
 	defer s.closemu.RUnlock()
 
 	var res Result
-	for i := 0; i < maxBadConnRetries; i++ {
-		_, releaseConn, ds, err := s.connStmt(ctx)
+	strategy := cachedOrNewConn
+	for i := 0; i < maxBadConnRetries+1; i++ {
+		if i == maxBadConnRetries {
+			strategy = alwaysNewConn
+		}
+		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
 		if err != nil {
 			if err == driver.ErrBadConn {
 				continue
@@ -1799,7 +2082,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, er
 			return nil, err
 		}
 
-		res, err = resultFromStatement(ctx, ds, args...)
+		res, err = resultFromStatement(ctx, dc.ci, ds, args...)
 		releaseConn(err)
 		if err != driver.ErrBadConn {
 			return res, err
@@ -1814,23 +2097,8 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
 	return s.ExecContext(context.Background(), args...)
 }
 
-func driverNumInput(ds *driverStmt) int {
-	ds.Lock()
-	defer ds.Unlock() // in case NumInput panics
-	return ds.si.NumInput()
-}
-
-func resultFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}) (Result, error) {
-	want := driverNumInput(ds)
-
-	// -1 means the driver doesn't know how to count the number of
-	// placeholders, so we won't sanity check input here and instead let the
-	// driver deal with errors.
-	if want != -1 && len(args) != want {
-		return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
-	}
-
-	dargs, err := driverArgs(ds, args)
+func resultFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (Result, error) {
+	dargs, err := driverArgs(ci, ds, args)
 	if err != nil {
 		return nil, err
 	}
@@ -1874,7 +2142,7 @@ func (s *Stmt) removeClosedStmtLocked() {
 // connStmt returns a free driver connection on which to execute the
 // statement, a function to call to release the connection, and a
 // statement bound to that connection.
-func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
+func (s *Stmt) connStmt(ctx context.Context, strategy connReuseStrategy) (dc *driverConn, releaseConn func(error), ds *driverStmt, err error) {
 	if err = s.stickyErr; err != nil {
 		return
 	}
@@ -1885,22 +2153,21 @@ func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(e
 		return
 	}
 
-	// In a transaction, we always use the connection that the
-	// transaction was created on.
-	if s.tx != nil {
+	// In a transaction or connection, we always use the connection that the
+	// the stmt was created on.
+	if s.cg != nil {
 		s.mu.Unlock()
-		ci, err = s.tx.grabConn(ctx) // blocks, waiting for the connection.
+		dc, releaseConn, err = s.cg.grabConn(ctx) // blocks, waiting for the connection.
 		if err != nil {
 			return
 		}
-		releaseConn = func(error) {}
-		return ci, releaseConn, s.txds, nil
+		return dc, releaseConn, s.cgds, nil
 	}
 
 	s.removeClosedStmtLocked()
 	s.mu.Unlock()
 
-	dc, err := s.db.conn(ctx, cachedOrNewConn)
+	dc, err = s.db.conn(ctx, strategy)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -1916,18 +2183,28 @@ func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(e
 
 	// No luck; we need to prepare the statement on this connection
 	withLock(dc, func() {
-		ds, err = dc.prepareLocked(ctx, s.query)
+		ds, err = s.prepareOnConnLocked(ctx, dc)
 	})
 	if err != nil {
-		s.db.putConn(dc, err)
+		dc.releaseConn(err)
 		return nil, nil, nil, err
 	}
+
+	return dc, dc.releaseConn, ds, nil
+}
+
+// prepareOnConnLocked prepares the query in Stmt s on dc and adds it to the list of
+// open connStmt on the statement. It assumes the caller is holding the lock on dc.
+func (s *Stmt) prepareOnConnLocked(ctx context.Context, dc *driverConn) (*driverStmt, error) {
+	si, err := dc.prepareLocked(ctx, s.cg, s.query)
+	if err != nil {
+		return nil, err
+	}
+	cs := connStmt{dc, si}
 	s.mu.Lock()
-	cs := connStmt{dc, ds}
 	s.css = append(s.css, cs)
 	s.mu.Unlock()
-
-	return dc, dc.releaseConn, ds, nil
+	return cs.ds, nil
 }
 
 // QueryContext executes a prepared query statement with the given arguments
@@ -1937,8 +2214,12 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
 	defer s.closemu.RUnlock()
 
 	var rowsi driver.Rows
-	for i := 0; i < maxBadConnRetries; i++ {
-		dc, releaseConn, ds, err := s.connStmt(ctx)
+	strategy := cachedOrNewConn
+	for i := 0; i < maxBadConnRetries+1; i++ {
+		if i == maxBadConnRetries {
+			strategy = alwaysNewConn
+		}
+		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
 		if err != nil {
 			if err == driver.ErrBadConn {
 				continue
@@ -1946,7 +2227,7 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
 			return nil, err
 		}
 
-		rowsi, err = rowsiFromStatement(ctx, ds, args...)
+		rowsi, err = rowsiFromStatement(ctx, dc.ci, ds, args...)
 		if err == nil {
 			// Note: ownership of ci passes to the *Rows, to be freed
 			// with releaseConn.
@@ -1955,12 +2236,21 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
 				rowsi: rowsi,
 				// releaseConn set below
 			}
+			// addDep must be added before initContextClose or it could attempt
+			// to removeDep before it has been added.
 			s.db.addDep(s, rows)
+
+			// releaseConn must be set before initContextClose or it could
+			// release the connection before it is set.
 			rows.releaseConn = func(err error) {
 				releaseConn(err)
 				s.db.removeDep(s, rows)
 			}
-			rows.initContextClose(ctx)
+			var txctx context.Context
+			if s.cg != nil {
+				txctx = s.cg.txCtx()
+			}
+			rows.initContextClose(ctx, txctx)
 			return rows, nil
 		}
 
@@ -1978,7 +2268,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
 	return s.QueryContext(context.Background(), args...)
 }
 
-func rowsiFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}) (driver.Rows, error) {
+func rowsiFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (driver.Rows, error) {
 	var want int
 	withLock(ds, func() {
 		want = ds.si.NumInput()
@@ -1991,7 +2281,7 @@ func rowsiFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}
 		return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
 	}
 
-	dargs, err := driverArgs(ds, args)
+	dargs, err := driverArgs(ci, ds, args)
 	if err != nil {
 		return nil, err
 	}
@@ -2054,13 +2344,21 @@ func (s *Stmt) Close() error {
 		return nil
 	}
 	s.closed = true
+	txds := s.cgds
+	s.cgds = nil
+
 	s.mu.Unlock()
 
-	if s.tx != nil {
-		return s.txds.Close()
+	if s.cg == nil {
+		return s.db.removeDep(s, s)
 	}
 
-	return s.db.removeDep(s, s)
+	if s.parentStmt != nil {
+		// If parentStmt is set, we must not close s.txds since it's stored
+		// in the css array of the parentStmt.
+		return s.db.removeDep(s.parentStmt, s)
+	}
+	return txds.Close()
 }
 
 func (s *Stmt) finalClose() error {
@@ -2107,18 +2405,28 @@ type Rows struct {
 	lasterr error // non-nil only if closed is true
 
 	// lastcols is only used in Scan, Next, and NextResultSet which are expected
-	// not not be called concurrently.
+	// not to be called concurrently.
 	lastcols []driver.Value
 }
 
-func (rs *Rows) initContextClose(ctx context.Context) {
+func (rs *Rows) initContextClose(ctx, txctx context.Context) {
 	ctx, rs.cancel = context.WithCancel(ctx)
-	go rs.awaitDone(ctx)
+	go rs.awaitDone(ctx, txctx)
 }
 
-// awaitDone blocks until the rows are closed or the context canceled.
-func (rs *Rows) awaitDone(ctx context.Context) {
-	<-ctx.Done()
+// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided
+// from the query context and is canceled when the query Rows is closed.
+// If the query was issued in a transaction, the transaction's context
+// is also provided in txctx to ensure Rows is closed if the Tx is closed.
+func (rs *Rows) awaitDone(ctx, txctx context.Context) {
+	var txctxDone <-chan struct{}
+	if txctx != nil {
+		txctxDone = txctx.Done()
+	}
+	select {
+	case <-ctx.Done():
+	case <-txctxDone:
+	}
 	rs.close(ctx.Err())
 }
 
@@ -2407,7 +2715,7 @@ func (rs *Rows) Scan(dest ...interface{}) error {
 }
 
 // rowsCloseHook returns a function so tests may install the
-// hook throug a test only mutex.
+// hook through a test only mutex.
 var rowsCloseHook = func() func(*Rows, *error) { return nil }
 
 // Close closes the Rows, preventing further enumeration. If Next is called
@@ -2431,7 +2739,9 @@ func (rs *Rows) close(err error) error {
 		rs.lasterr = err
 	}
 
-	err = rs.rowsi.Close()
+	withLock(rs.dc, func() {
+		err = rs.rowsi.Close()
+	})
 	if fn := rowsCloseHook(); fn != nil {
 		fn(rs, &err)
 	}
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 381aafc..c935eb4 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -139,6 +139,7 @@ func closeDB(t testing.TB, db *DB) {
 			t.Errorf("Error closing fakeConn: %v", err)
 		}
 	})
+	db.mu.Lock()
 	for i, dc := range db.freeConn {
 		if n := len(dc.openStmt); n > 0 {
 			// Just a sanity check. This is legal in
@@ -149,6 +150,8 @@ func closeDB(t testing.TB, db *DB) {
 			t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
 		}
 	}
+	db.mu.Unlock()
+
 	err := db.Close()
 	if err != nil {
 		t.Fatalf("error closing DB: %v", err)
@@ -322,7 +325,7 @@ func TestQueryContext(t *testing.T) {
 	select {
 	case <-ctx.Done():
 		if err := ctx.Err(); err != context.Canceled {
-			t.Fatalf("context err = %v; want context.Canceled", ctx.Err())
+			t.Fatalf("context err = %v; want context.Canceled", err)
 		}
 	default:
 		t.Fatalf("context err = nil; want context.Canceled")
@@ -413,7 +416,7 @@ func TestTxContextWait(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
 
-	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*15)
+	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Millisecond)
 	defer cancel()
 
 	tx, err := db.BeginTx(ctx, nil)
@@ -590,13 +593,13 @@ func TestPoolExhaustOnCancel(t *testing.T) {
 	saturate.Wait()
 
 	// Now cancel the request while it is waiting.
-	ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
+	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 	defer cancel()
 
 	for i := 0; i < max; i++ {
 		ctxReq, cancelReq := context.WithCancel(ctx)
 		go func() {
-			time.Sleep(time.Millisecond * 100)
+			time.Sleep(100 * time.Millisecond)
 			cancelReq()
 		}()
 		err := db.PingContext(ctxReq)
@@ -874,7 +877,7 @@ func TestStatementClose(t *testing.T) {
 		msg  string
 	}{
 		{&Stmt{stickyErr: want}, "stickyErr not propagated"},
-		{&Stmt{tx: &Tx{}, txds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
+		{&Stmt{cg: &Tx{}, cgds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
 	}
 	for _, test := range tests {
 		if err := test.stmt.Close(); err != want {
@@ -1024,6 +1027,196 @@ func TestTxStmt(t *testing.T) {
 	}
 }
 
+func TestTxStmtPreparedOnce(t *testing.T) {
+	db := newTestDB(t, "")
+	defer closeDB(t, db)
+	exec(t, db, "CREATE|t1|name=string,age=int32")
+
+	prepares0 := numPrepares(t, db)
+
+	// db.Prepare increments numPrepares.
+	stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+	if err != nil {
+		t.Fatalf("Stmt, err = %v, %v", stmt, err)
+	}
+	defer stmt.Close()
+
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatalf("Begin = %v", err)
+	}
+
+	txs1 := tx.Stmt(stmt)
+	txs2 := tx.Stmt(stmt)
+
+	_, err = txs1.Exec("Go", 7)
+	if err != nil {
+		t.Fatalf("Exec = %v", err)
+	}
+	txs1.Close()
+
+	_, err = txs2.Exec("Gopher", 8)
+	if err != nil {
+		t.Fatalf("Exec = %v", err)
+	}
+	txs2.Close()
+
+	err = tx.Commit()
+	if err != nil {
+		t.Fatalf("Commit = %v", err)
+	}
+
+	if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+		t.Errorf("executed %d Prepare statements; want 1", prepares)
+	}
+}
+
+func TestTxStmtClosedRePrepares(t *testing.T) {
+	db := newTestDB(t, "")
+	defer closeDB(t, db)
+	exec(t, db, "CREATE|t1|name=string,age=int32")
+
+	prepares0 := numPrepares(t, db)
+
+	// db.Prepare increments numPrepares.
+	stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+	if err != nil {
+		t.Fatalf("Stmt, err = %v, %v", stmt, err)
+	}
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatalf("Begin = %v", err)
+	}
+	err = stmt.Close()
+	if err != nil {
+		t.Fatalf("stmt.Close() = %v", err)
+	}
+	// tx.Stmt increments numPrepares because stmt is closed.
+	txs := tx.Stmt(stmt)
+	if txs.stickyErr != nil {
+		t.Fatal(txs.stickyErr)
+	}
+	if txs.parentStmt != nil {
+		t.Fatal("expected nil parentStmt")
+	}
+	_, err = txs.Exec(`Eric`, 82)
+	if err != nil {
+		t.Fatalf("txs.Exec = %v", err)
+	}
+
+	err = txs.Close()
+	if err != nil {
+		t.Fatalf("txs.Close = %v", err)
+	}
+
+	tx.Rollback()
+
+	if prepares := numPrepares(t, db) - prepares0; prepares != 2 {
+		t.Errorf("executed %d Prepare statements; want 2", prepares)
+	}
+}
+
+func TestParentStmtOutlivesTxStmt(t *testing.T) {
+	db := newTestDB(t, "")
+	defer closeDB(t, db)
+	exec(t, db, "CREATE|t1|name=string,age=int32")
+
+	// Make sure everything happens on the same connection.
+	db.SetMaxOpenConns(1)
+
+	prepares0 := numPrepares(t, db)
+
+	// db.Prepare increments numPrepares.
+	stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+	if err != nil {
+		t.Fatalf("Stmt, err = %v, %v", stmt, err)
+	}
+	defer stmt.Close()
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatalf("Begin = %v", err)
+	}
+	txs := tx.Stmt(stmt)
+	if len(stmt.css) != 1 {
+		t.Fatalf("len(stmt.css) = %v; want 1", len(stmt.css))
+	}
+	err = txs.Close()
+	if err != nil {
+		t.Fatalf("txs.Close() = %v", err)
+	}
+	err = tx.Rollback()
+	if err != nil {
+		t.Fatalf("tx.Rollback() = %v", err)
+	}
+	// txs must not be valid.
+	_, err = txs.Exec("Suzan", 30)
+	if err == nil {
+		t.Fatalf("txs.Exec(), expected err")
+	}
+	// Stmt must still be valid.
+	_, err = stmt.Exec("Janina", 25)
+	if err != nil {
+		t.Fatalf("stmt.Exec() = %v", err)
+	}
+
+	if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+		t.Errorf("executed %d Prepare statements; want 1", prepares)
+	}
+}
+
+// Test that tx.Stmt called with a statement already
+// associated with tx as argument re-prepares the same
+// statement again.
+func TestTxStmtFromTxStmtRePrepares(t *testing.T) {
+	db := newTestDB(t, "")
+	defer closeDB(t, db)
+	exec(t, db, "CREATE|t1|name=string,age=int32")
+	prepares0 := numPrepares(t, db)
+	// db.Prepare increments numPrepares.
+	stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+	if err != nil {
+		t.Fatalf("Stmt, err = %v, %v", stmt, err)
+	}
+	defer stmt.Close()
+
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatalf("Begin = %v", err)
+	}
+	txs1 := tx.Stmt(stmt)
+
+	// tx.Stmt(txs1) increments numPrepares because txs1 already
+	// belongs to a transaction (albeit the same transaction).
+	txs2 := tx.Stmt(txs1)
+	if txs2.stickyErr != nil {
+		t.Fatal(txs2.stickyErr)
+	}
+	if txs2.parentStmt != nil {
+		t.Fatal("expected nil parentStmt")
+	}
+	_, err = txs2.Exec(`Eric`, 82)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = txs1.Close()
+	if err != nil {
+		t.Fatalf("txs1.Close = %v", err)
+	}
+	err = txs2.Close()
+	if err != nil {
+		t.Fatalf("txs1.Close = %v", err)
+	}
+	err = tx.Rollback()
+	if err != nil {
+		t.Fatalf("tx.Rollback = %v", err)
+	}
+
+	if prepares := numPrepares(t, db) - prepares0; prepares != 2 {
+		t.Errorf("executed %d Prepare statements; want 2", prepares)
+	}
+}
+
 // Issue: https://golang.org/issue/2784
 // This test didn't fail before because we got lucky with the fakedb driver.
 // It was failing, and now not, in github.com/bradfitz/go-sql-test
@@ -1108,6 +1301,69 @@ func TestTxErrBadConn(t *testing.T) {
 	}
 }
 
+func TestConnQuery(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	conn, err := db.Conn(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conn.Close()
+
+	var name string
+	err = conn.QueryRowContext(ctx, "SELECT|people|name|age=?", 3).Scan(&name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "Chris" {
+		t.Fatalf("unexpected result, got %q want Chris", name)
+	}
+
+	err = conn.PingContext(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestConnTx(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	conn, err := db.Conn(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conn.Close()
+
+	tx, err := conn.BeginTx(ctx, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	insertName, insertAge := "Nancy", 33
+	_, err = tx.ExecContext(ctx, "INSERT|people|name=?,age=?,photo=APHOTO", insertName, insertAge)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = tx.Commit()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var selectName string
+	err = conn.QueryRowContext(ctx, "SELECT|people|name|age=?", insertAge).Scan(&selectName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if selectName != insertName {
+		t.Fatalf("got %q want %q", selectName, insertName)
+	}
+}
+
 // Tests fix for issue 2542, that we release a lock when querying on
 // a closed connection.
 func TestIssue2542Deadlock(t *testing.T) {
@@ -1831,8 +2087,8 @@ func TestConnMaxLifetime(t *testing.T) {
 	}
 
 	// Expire first conn
-	offset = time.Second * 11
-	db.SetConnMaxLifetime(time.Second * 10)
+	offset = 11 * time.Second
+	db.SetConnMaxLifetime(10 * time.Second)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2078,9 +2334,13 @@ func TestStmtCloseOrder(t *testing.T) {
 // Test cases where there's more than maxBadConnRetries bad connections in the
 // pool (issue 8834)
 func TestManyErrBadConn(t *testing.T) {
-	manyErrBadConnSetup := func() *DB {
+	manyErrBadConnSetup := func(first ...func(db *DB)) *DB {
 		db := newTestDB(t, "people")
 
+		for _, f := range first {
+			f(db)
+		}
+
 		nconn := maxBadConnRetries + 1
 		db.SetMaxIdleConns(nconn)
 		db.SetMaxOpenConns(nconn)
@@ -2148,6 +2408,128 @@ func TestManyErrBadConn(t *testing.T) {
 	if err = stmt.Close(); err != nil {
 		t.Fatal(err)
 	}
+
+	// Stmt.Exec
+	db = manyErrBadConnSetup(func(db *DB) {
+		stmt, err = db.Prepare("INSERT|people|name=Julia,age=19")
+		if err != nil {
+			t.Fatal(err)
+		}
+	})
+	defer closeDB(t, db)
+	_, err = stmt.Exec()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = stmt.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Stmt.Query
+	db = manyErrBadConnSetup(func(db *DB) {
+		stmt, err = db.Prepare("SELECT|people|age,name|")
+		if err != nil {
+			t.Fatal(err)
+		}
+	})
+	defer closeDB(t, db)
+	rows, err = stmt.Query()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = rows.Close(); err != nil {
+		t.Fatal(err)
+	}
+	if err = stmt.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Conn
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	conn, err := db.Conn(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = conn.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Ping
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	err = db.PingContext(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+// TestIssue20575 ensures the Rows from query does not block
+// closing a transaction. Ensure Rows is closed while closing a trasaction.
+func TestIssue20575(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
+	defer cancel()
+	_, err = tx.QueryContext(ctx, "SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Do not close Rows from QueryContext.
+	err = tx.Rollback()
+	if err != nil {
+		t.Fatal(err)
+	}
+	select {
+	default:
+	case <-ctx.Done():
+		t.Fatal("timeout: failed to rollback query without closing rows:", ctx.Err())
+	}
+}
+
+// TestIssue20622 tests closing the transaction before rows is closed, requires
+// the race detector to fail.
+func TestIssue20622(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	tx, err := db.BeginTx(ctx, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	rows, err := tx.Query("SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	count := 0
+	for rows.Next() {
+		count++
+		var age int
+		var name string
+		if err := rows.Scan(&age, &name); err != nil {
+			t.Fatal("scan failed", err)
+		}
+
+		if count == 1 {
+			cancel()
+		}
+		time.Sleep(100 * time.Millisecond)
+	}
+	rows.Close()
+	tx.Commit()
 }
 
 // golang.org/issue/5718
@@ -2751,7 +3133,7 @@ func TestIssue18429(t *testing.T) {
 			if err != nil {
 				return
 			}
-			// This is expected to give a cancel error many, but not all the time.
+			// This is expected to give a cancel error most, but not all the time.
 			// Test failure will happen with a panic or other race condition being
 			// reported.
 			rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
@@ -2766,6 +3148,46 @@ func TestIssue18429(t *testing.T) {
 	wg.Wait()
 }
 
+// TestIssue20160 attempts to test a short context life on a stmt Query.
+func TestIssue20160(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	ctx := context.Background()
+	sem := make(chan bool, 20)
+	var wg sync.WaitGroup
+
+	const milliWait = 30
+
+	stmt, err := db.PrepareContext(ctx, "SELECT|people|name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stmt.Close()
+
+	for i := 0; i < 100; i++ {
+		sem <- true
+		wg.Add(1)
+		go func() {
+			defer func() {
+				<-sem
+				wg.Done()
+			}()
+			ctx, cancel := context.WithTimeout(ctx, time.Duration(rand.Intn(milliWait))*time.Millisecond)
+			defer cancel()
+
+			// This is expected to give a cancel error most, but not all the time.
+			// Test failure will happen with a panic or other race condition being
+			// reported.
+			rows, _ := stmt.QueryContext(ctx)
+			if rows != nil {
+				rows.Close()
+			}
+		}()
+	}
+	wg.Wait()
+}
+
 // TestIssue18719 closes the context right before use. The sql.driverConn
 // will nil out the ci on close in a lock, but if another process uses it right after
 // it will panic with on the nil ref.
@@ -2788,7 +3210,7 @@ func TestIssue18719(t *testing.T) {
 
 		// Wait for the context to cancel and tx to rollback.
 		for tx.isDone() == false {
-			time.Sleep(time.Millisecond * 3)
+			time.Sleep(3 * time.Millisecond)
 		}
 	}
 	defer func() { hookTxGrabConn = nil }()
@@ -2807,19 +3229,64 @@ func TestIssue18719(t *testing.T) {
 	// canceled context.
 
 	cancel()
-	waitForRowsClose(t, rows, 5*time.Second)
+}
+
+func TestIssue20647(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	conn, err := db.Conn(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conn.Close()
+
+	stmt, err := conn.PrepareContext(ctx, "SELECT|people|name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stmt.Close()
+
+	rows1, err := stmt.QueryContext(ctx)
+	if err != nil {
+		t.Fatal("rows1", err)
+	}
+	defer rows1.Close()
+
+	rows2, err := stmt.QueryContext(ctx)
+	if err != nil {
+		t.Fatal("rows2", err)
+	}
+	defer rows2.Close()
+
+	if rows1.dc != rows2.dc {
+		t.Fatal("stmt prepared on Conn does not use same connection")
+	}
 }
 
 func TestConcurrency(t *testing.T) {
-	doConcurrentTest(t, new(concurrentDBQueryTest))
-	doConcurrentTest(t, new(concurrentDBExecTest))
-	doConcurrentTest(t, new(concurrentStmtQueryTest))
-	doConcurrentTest(t, new(concurrentStmtExecTest))
-	doConcurrentTest(t, new(concurrentTxQueryTest))
-	doConcurrentTest(t, new(concurrentTxExecTest))
-	doConcurrentTest(t, new(concurrentTxStmtQueryTest))
-	doConcurrentTest(t, new(concurrentTxStmtExecTest))
-	doConcurrentTest(t, new(concurrentRandomTest))
+	list := []struct {
+		name string
+		ct   concurrentTest
+	}{
+		{"Query", new(concurrentDBQueryTest)},
+		{"Exec", new(concurrentDBExecTest)},
+		{"StmtQuery", new(concurrentStmtQueryTest)},
+		{"StmtExec", new(concurrentStmtExecTest)},
+		{"TxQuery", new(concurrentTxQueryTest)},
+		{"TxExec", new(concurrentTxExecTest)},
+		{"TxStmtQuery", new(concurrentTxStmtQueryTest)},
+		{"TxStmtExec", new(concurrentTxStmtExecTest)},
+		{"Random", new(concurrentRandomTest)},
+	}
+	for _, item := range list {
+		t.Run(item.name, func(t *testing.T) {
+			doConcurrentTest(t, item.ct)
+		})
+	}
 }
 
 func TestConnectionLeak(t *testing.T) {
@@ -2874,6 +3341,131 @@ func TestConnectionLeak(t *testing.T) {
 	wg.Wait()
 }
 
+type nvcDriver struct {
+	fakeDriver
+	skipNamedValueCheck bool
+}
+
+func (d *nvcDriver) Open(dsn string) (driver.Conn, error) {
+	c, err := d.fakeDriver.Open(dsn)
+	fc := c.(*fakeConn)
+	fc.db.allowAny = true
+	return &nvcConn{fc, d.skipNamedValueCheck}, err
+}
+
+type nvcConn struct {
+	*fakeConn
+	skipNamedValueCheck bool
+}
+
+type decimal struct {
+	value int
+}
+
+type doNotInclude struct{}
+
+var _ driver.NamedValueChecker = &nvcConn{}
+
+func (c *nvcConn) CheckNamedValue(nv *driver.NamedValue) error {
+	if c.skipNamedValueCheck {
+		return driver.ErrSkip
+	}
+	switch v := nv.Value.(type) {
+	default:
+		return driver.ErrSkip
+	case Out:
+		switch ov := v.Dest.(type) {
+		default:
+			return errors.New("unkown NameValueCheck OUTPUT type")
+		case *string:
+			*ov = "from-server"
+			nv.Value = "OUT:*string"
+		}
+		return nil
+	case decimal, []int64:
+		return nil
+	case doNotInclude:
+		return driver.ErrRemoveArgument
+	}
+}
+
+func TestNamedValueChecker(t *testing.T) {
+	Register("NamedValueCheck", &nvcDriver{})
+	db, err := Open("NamedValueCheck", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer db.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	_, err = db.ExecContext(ctx, "WIPE")
+	if err != nil {
+		t.Fatal("exec wipe", err)
+	}
+
+	_, err = db.ExecContext(ctx, "CREATE|keys|dec1=any,str1=string,out1=string,array1=any")
+	if err != nil {
+		t.Fatal("exec create", err)
+	}
+
+	o1 := ""
+	_, err = db.ExecContext(ctx, "INSERT|keys|dec1=?A,str1=?,out1=?O1,array1=?", Named("A", decimal{123}), "hello", Named("O1", Out{Dest: &o1}), []int64{42, 128, 707}, doNotInclude{})
+	if err != nil {
+		t.Fatal("exec insert", err)
+	}
+	var (
+		str1 string
+		dec1 decimal
+		arr1 []int64
+	)
+	err = db.QueryRowContext(ctx, "SELECT|keys|dec1,str1,array1|").Scan(&dec1, &str1, &arr1)
+	if err != nil {
+		t.Fatal("select", err)
+	}
+
+	list := []struct{ got, want interface{} }{
+		{o1, "from-server"},
+		{dec1, decimal{123}},
+		{str1, "hello"},
+		{arr1, []int64{42, 128, 707}},
+	}
+
+	for index, item := range list {
+		if !reflect.DeepEqual(item.got, item.want) {
+			t.Errorf("got %#v wanted %#v for index %d", item.got, item.want, index)
+		}
+	}
+}
+
+func TestNamedValueCheckerSkip(t *testing.T) {
+	Register("NamedValueCheckSkip", &nvcDriver{skipNamedValueCheck: true})
+	db, err := Open("NamedValueCheckSkip", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer db.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	_, err = db.ExecContext(ctx, "WIPE")
+	if err != nil {
+		t.Fatal("exec wipe", err)
+	}
+
+	_, err = db.ExecContext(ctx, "CREATE|keys|dec1=any")
+	if err != nil {
+		t.Fatal("exec create", err)
+	}
+
+	_, err = db.ExecContext(ctx, "INSERT|keys|dec1=?A", Named("A", decimal{123}))
+	if err == nil {
+		t.Fatalf("expected error with bad argument, got %v", err)
+	}
+}
+
 // badConn implements a bad driver.Conn, for TestBadDriver.
 // The Exec method panics.
 type badConn struct{}
@@ -2965,6 +3557,24 @@ func TestPing(t *testing.T) {
 	}
 }
 
+// Issue 18101.
+func TestTypedString(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	type Str string
+	var scanned Str
+
+	err := db.QueryRow("SELECT|people|name|name=?", "Alice").Scan(&scanned)
+	if err != nil {
+		t.Fatal(err)
+	}
+	expected := Str("Alice")
+	if scanned != expected {
+		t.Errorf("expected %+v, got %+v", expected, scanned)
+	}
+}
+
 func BenchmarkConcurrentDBExec(b *testing.B) {
 	b.ReportAllocs()
 	ct := new(concurrentDBExecTest)
diff --git a/src/debug/dwarf/export_test.go b/src/debug/dwarf/export_test.go
new file mode 100644
index 0000000..b8a25ff
--- /dev/null
+++ b/src/debug/dwarf/export_test.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+var PathJoin = pathJoin
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index ed82fee..4e6e142 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"io"
 	"path"
+	"strings"
 )
 
 // A LineReader reads a sequence of LineEntry structures from a DWARF
@@ -247,10 +248,10 @@ func (r *LineReader) readHeader() error {
 		if len(directory) == 0 {
 			break
 		}
-		if !path.IsAbs(directory) {
+		if !pathIsAbs(directory) {
 			// Relative paths are implicitly relative to
 			// the compilation directory.
-			directory = path.Join(r.directories[0], directory)
+			directory = pathJoin(r.directories[0], directory)
 		}
 		r.directories = append(r.directories, directory)
 	}
@@ -283,11 +284,11 @@ func (r *LineReader) readFileEntry() (bool, error) {
 	}
 	off := r.buf.off
 	dirIndex := int(r.buf.uint())
-	if !path.IsAbs(name) {
+	if !pathIsAbs(name) {
 		if dirIndex >= len(r.directories) {
 			return false, DecodeError{"line", off, "directory index too large"}
 		}
-		name = path.Join(r.directories[dirIndex], name)
+		name = pathJoin(r.directories[dirIndex], name)
 	}
 	mtime := r.buf.uint()
 	length := int(r.buf.uint())
@@ -588,3 +589,68 @@ func (r *LineReader) SeekPC(pc uint64, entry *LineEntry) error {
 		*entry = next
 	}
 }
+
+// pathIsAbs returns whether path is an absolute path (or "full path
+// name" in DWARF parlance). This is in "whatever form makes sense for
+// the host system", so this accepts both UNIX-style and DOS-style
+// absolute paths. We avoid the filepath package because we want this
+// to behave the same regardless of our host system and because we
+// don't know what system the paths came from.
+func pathIsAbs(path string) bool {
+	_, path = splitDrive(path)
+	return len(path) > 0 && (path[0] == '/' || path[0] == '\\')
+}
+
+// pathJoin joins dirname and filename. filename must be relative.
+// DWARF paths can be UNIX-style or DOS-style, so this handles both.
+func pathJoin(dirname, filename string) string {
+	if len(dirname) == 0 {
+		return filename
+	}
+	// dirname should be absolute, which means we can determine
+	// whether it's a DOS path reasonably reliably by looking for
+	// a drive letter or UNC path.
+	drive, dirname := splitDrive(dirname)
+	if drive == "" {
+		// UNIX-style path.
+		return path.Join(dirname, filename)
+	}
+	// DOS-style path.
+	drive2, filename := splitDrive(filename)
+	if drive2 != "" {
+		if strings.ToLower(drive) != strings.ToLower(drive2) {
+			// Different drives. There's not much we can
+			// do here, so just ignore the directory.
+			return drive2 + filename
+		}
+		// Drives are the same. Ignore drive on filename.
+	}
+	if !(strings.HasSuffix(dirname, "/") || strings.HasSuffix(dirname, `\`)) && dirname != "" {
+		dirname += `\`
+	}
+	return drive + dirname + filename
+}
+
+// splitDrive splits the DOS drive letter or UNC share point from
+// path, if any. path == drive + rest
+func splitDrive(path string) (drive, rest string) {
+	if len(path) >= 2 && path[1] == ':' {
+		if c := path[0]; 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
+			return path[:2], path[2:]
+		}
+	}
+	if len(path) > 3 && (path[0] == '\\' || path[0] == '/') && (path[1] == '\\' || path[1] == '/') {
+		// Normalize the path so we can search for just \ below.
+		npath := strings.Replace(path, "/", `\`, -1)
+		// Get the host part, which must be non-empty.
+		slash1 := strings.IndexByte(npath[2:], '\\') + 2
+		if slash1 > 2 {
+			// Get the mount-point part, which must be non-empty.
+			slash2 := strings.IndexByte(npath[slash1+1:], '\\') + slash1 + 1
+			if slash2 > slash1 {
+				return path[:slash2], path[slash2:]
+			}
+		}
+	}
+	return "", path
+}
diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go
index cc363f5..11a2544 100644
--- a/src/debug/dwarf/line_test.go
+++ b/src/debug/dwarf/line_test.go
@@ -7,6 +7,7 @@ package dwarf_test
 import (
 	. "debug/dwarf"
 	"io"
+	"strings"
 	"testing"
 )
 
@@ -46,6 +47,46 @@ func TestLineELFGCC(t *testing.T) {
 	testLineTable(t, want, elfData(t, "testdata/line-gcc.elf"))
 }
 
+func TestLineGCCWindows(t *testing.T) {
+	// Generated by:
+	//   > gcc --version
+	//   gcc (tdm64-1) 4.9.2
+	//   > gcc -g -o line-gcc-win.bin line1.c C:\workdir\go\src\debug\dwarf\testdata\line2.c
+
+	toWindows := func(lf *LineFile) *LineFile {
+		lf2 := *lf
+		lf2.Name = strings.Replace(lf2.Name, "/home/austin/go.dev/", "C:\\workdir\\go\\", -1)
+		lf2.Name = strings.Replace(lf2.Name, "/", "\\", -1)
+		return &lf2
+	}
+	file1C := toWindows(file1C)
+	file1H := toWindows(file1H)
+	file2C := toWindows(file2C)
+
+	// Line table based on objdump --dwarf=rawline,decodedline
+	want := []LineEntry{
+		{Address: 0x401530, File: file1H, Line: 2, IsStmt: true},
+		{Address: 0x401538, File: file1H, Line: 5, IsStmt: true},
+		{Address: 0x401541, File: file1H, Line: 6, IsStmt: true, Discriminator: 3},
+		{Address: 0x40154b, File: file1H, Line: 5, IsStmt: true, Discriminator: 3},
+		{Address: 0x40154f, File: file1H, Line: 5, IsStmt: false, Discriminator: 1},
+		{Address: 0x401555, File: file1H, Line: 7, IsStmt: true},
+		{Address: 0x40155b, File: file1C, Line: 6, IsStmt: true},
+		{Address: 0x401563, File: file1C, Line: 6, IsStmt: true},
+		{Address: 0x401568, File: file1C, Line: 7, IsStmt: true},
+		{Address: 0x40156d, File: file1C, Line: 8, IsStmt: true},
+		{Address: 0x401572, File: file1C, Line: 9, IsStmt: true},
+		{Address: 0x401578, EndSequence: true},
+
+		{Address: 0x401580, File: file2C, Line: 4, IsStmt: true},
+		{Address: 0x401588, File: file2C, Line: 5, IsStmt: true},
+		{Address: 0x401595, File: file2C, Line: 6, IsStmt: true},
+		{Address: 0x40159b, EndSequence: true},
+	}
+
+	testLineTable(t, want, peData(t, "testdata/line-gcc-win.bin"))
+}
+
 func TestLineELFClang(t *testing.T) {
 	// Generated by:
 	//   # clang --version | head -n1
@@ -183,6 +224,11 @@ func testLineTable(t *testing.T, want []LineEntry, d *Data) {
 				}
 				t.Fatal("lr.Next:", err)
 			}
+			// Ignore sources from the Windows build environment.
+			if strings.HasPrefix(line.File.Name, "C:\\crossdev\\") ||
+				strings.HasPrefix(line.File.Name, "C:/crossdev/") {
+				continue
+			}
 			got = append(got, line)
 		}
 	}
@@ -227,3 +273,42 @@ func dumpLines(t *testing.T, lines []LineEntry) {
 		t.Logf("  %+v File:%+v", l, l.File)
 	}
 }
+
+type joinTest struct {
+	dirname, filename string
+	path              string
+}
+
+var joinTests = []joinTest{
+	{"a", "b", "a/b"},
+	{"a", "", "a"},
+	{"", "b", "b"},
+	{"/a", "b", "/a/b"},
+	{"/a/", "b", "/a/b"},
+
+	{`C:\Windows\`, `System32`, `C:\Windows\System32`},
+	{`C:\Windows\`, ``, `C:\Windows\`},
+	{`C:\`, `Windows`, `C:\Windows`},
+	{`C:\Windows\`, `C:System32`, `C:\Windows\System32`},
+	{`C:\Windows`, `a/b`, `C:\Windows\a/b`},
+	{`\\host\share\`, `foo`, `\\host\share\foo`},
+	{`\\host\share\`, `foo\bar`, `\\host\share\foo\bar`},
+	{`//host/share/`, `foo/bar`, `//host/share/foo/bar`},
+
+	// The following are "best effort". We shouldn't see relative
+	// base directories in DWARF, but these test that pathJoin
+	// doesn't fail miserably if it sees one.
+	{`C:`, `a`, `C:a`},
+	{`C:`, `a\b`, `C:a\b`},
+	{`C:.`, `a`, `C:.\a`},
+	{`C:a`, `b`, `C:a\b`},
+}
+
+func TestPathJoin(t *testing.T) {
+	for _, test := range joinTests {
+		got := PathJoin(test.dirname, test.filename)
+		if test.path != got {
+			t.Errorf("pathJoin(%q, %q) = %q, want %q", test.dirname, test.filename, got, test.path)
+		}
+	}
+}
diff --git a/src/debug/dwarf/testdata/line-gcc-win.bin b/src/debug/dwarf/testdata/line-gcc-win.bin
new file mode 100644
index 0000000..583ad44
Binary files /dev/null and b/src/debug/dwarf/testdata/line-gcc-win.bin differ
diff --git a/src/debug/dwarf/type_test.go b/src/debug/dwarf/type_test.go
index 0283466..6c06731 100644
--- a/src/debug/dwarf/type_test.go
+++ b/src/debug/dwarf/type_test.go
@@ -8,6 +8,7 @@ import (
 	. "debug/dwarf"
 	"debug/elf"
 	"debug/macho"
+	"debug/pe"
 	"testing"
 )
 
@@ -67,6 +68,19 @@ func machoData(t *testing.T, name string) *Data {
 	return d
 }
 
+func peData(t *testing.T, name string) *Data {
+	f, err := pe.Open(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	d, err := f.DWARF()
+	if err != nil {
+		t.Fatal(err)
+	}
+	return d
+}
+
 func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
 
 func TestTypedefsMachO(t *testing.T) {
diff --git a/src/debug/pe/file_cgo_test.go b/src/debug/pe/file_cgo_test.go
new file mode 100644
index 0000000..739671d
--- /dev/null
+++ b/src/debug/pe/file_cgo_test.go
@@ -0,0 +1,31 @@
+// Copyright 2017 The Go Authors. 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
+
+package pe
+
+import (
+	"os/exec"
+	"testing"
+)
+
+func testCgoDWARF(t *testing.T, linktype int) {
+	if _, err := exec.LookPath("gcc"); err != nil {
+		t.Skip("skipping test: gcc is missing")
+	}
+	testDWARF(t, linktype)
+}
+
+func TestDefaultLinkerDWARF(t *testing.T) {
+	testCgoDWARF(t, linkCgoDefault)
+}
+
+func TestInternalLinkerDWARF(t *testing.T) {
+	testCgoDWARF(t, linkCgoInternal)
+}
+
+func TestExternalLinkerDWARF(t *testing.T) {
+	testCgoDWARF(t, linkCgoExternal)
+}
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index 5a740c8..8645d67 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -12,8 +12,11 @@ import (
 	"os/exec"
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"runtime"
+	"strconv"
 	"testing"
+	"text/template"
 )
 
 type fileTest struct {
@@ -288,28 +291,70 @@ func TestOpenFailure(t *testing.T) {
 	}
 }
 
-func TestDWARF(t *testing.T) {
+const (
+	linkNoCgo = iota
+	linkCgoDefault
+	linkCgoInternal
+	linkCgoExternal
+)
+
+func testDWARF(t *testing.T, linktype int) {
 	if runtime.GOOS != "windows" {
 		t.Skip("skipping windows only test")
 	}
+	testenv.MustHaveGoRun(t)
 
 	tmpdir, err := ioutil.TempDir("", "TestDWARF")
 	if err != nil {
-		t.Fatal("TempDir failed: ", err)
+		t.Fatal(err)
 	}
 	defer os.RemoveAll(tmpdir)
 
-	prog := `
-package main
-func main() {
-}
-`
 	src := filepath.Join(tmpdir, "a.go")
+	file, err := os.Create(src)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo)
+	if err != nil {
+		if err := file.Close(); err != nil {
+			t.Error(err)
+		}
+		t.Fatal(err)
+	}
+	if err := file.Close(); err != nil {
+		t.Fatal(err)
+	}
+
 	exe := filepath.Join(tmpdir, "a.exe")
-	err = ioutil.WriteFile(src, []byte(prog), 0644)
-	output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
+	args := []string{"build", "-o", exe}
+	switch linktype {
+	case linkNoCgo:
+	case linkCgoDefault:
+	case linkCgoInternal:
+		args = append(args, "-ldflags", "-linkmode=internal")
+	case linkCgoExternal:
+		args = append(args, "-ldflags", "-linkmode=external")
+	default:
+		t.Fatalf("invalid linktype parameter of %v", linktype)
+	}
+	args = append(args, src)
+	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
+	if err != nil {
+		t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out)
+	}
+	out, err = exec.Command(exe).CombinedOutput()
 	if err != nil {
-		t.Fatalf("building test executable failed: %s %s", err, output)
+		t.Fatalf("running test executable failed: %s %s", err, out)
+	}
+
+	matches := regexp.MustCompile("main=(.*)\n").FindStringSubmatch(string(out))
+	if len(matches) < 2 {
+		t.Fatalf("unexpected program output: %s", out)
+	}
+	wantaddr, err := strconv.ParseUint(matches[1], 0, 64)
+	if err != nil {
+		t.Fatalf("unexpected main address %q: %s", matches[1], err)
 	}
 
 	f, err := Open(exe)
@@ -318,6 +363,16 @@ func main() {
 	}
 	defer f.Close()
 
+	var foundDebugGDBScriptsSection bool
+	for _, sect := range f.Sections {
+		if sect.Name == ".debug_gdb_scripts" {
+			foundDebugGDBScriptsSection = true
+		}
+	}
+	if !foundDebugGDBScriptsSection {
+		t.Error(".debug_gdb_scripts section is not found")
+	}
+
 	d, err := f.DWARF()
 	if err != nil {
 		t.Fatal(err)
@@ -334,8 +389,8 @@ func main() {
 			break
 		}
 		if e.Tag == dwarf.TagSubprogram {
-			for _, f := range e.Field {
-				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
+			if name, ok := e.Val(dwarf.AttrName).(string); ok && name == "main.main" {
+				if addr, ok := e.Val(dwarf.AttrLowpc).(uint64); ok && addr == wantaddr {
 					return
 				}
 			}
@@ -415,3 +470,65 @@ main(void)
 		}
 	}
 }
+
+func TestDWARF(t *testing.T) {
+	testDWARF(t, linkNoCgo)
+}
+
+const testprog = `
+package main
+
+import "fmt"
+{{if .}}import "C"
+{{end}}
+
+func main() {
+	fmt.Printf("main=%p\n", main)
+}
+`
+
+func TestBuildingWindowsGUI(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	if runtime.GOOS != "windows" {
+		t.Skip("skipping windows only test")
+	}
+	tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	src := filepath.Join(tmpdir, "a.go")
+	err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+	exe := filepath.Join(tmpdir, "a.exe")
+	cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("building test executable failed: %s %s", err, out)
+	}
+
+	f, err := Open(exe)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
+
+	switch oh := f.OptionalHeader.(type) {
+	case *OptionalHeader32:
+		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
+			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
+		}
+	case *OptionalHeader64:
+		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
+			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
+		}
+	default:
+		t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
+	}
+}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 044f74a..b8e2770 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -22,6 +22,7 @@ package asn1
 import (
 	"errors"
 	"fmt"
+	"math"
 	"math/big"
 	"reflect"
 	"strconv"
@@ -206,6 +207,14 @@ func parseBitString(bytes []byte) (ret BitString, err error) {
 	return
 }
 
+// NULL
+
+// NullRawValue is a RawValue with its Tag set to the ASN.1 NULL type tag (5).
+var NullRawValue = RawValue{Tag: TagNull}
+
+// NullBytes contains bytes representing the DER-encoded ASN.1 NULL type.
+var NullBytes = []byte{TagNull, 0}
+
 // OBJECT IDENTIFIER
 
 // An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
@@ -293,16 +302,24 @@ type Flag bool
 // given byte slice. It returns the value and the new offset.
 func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
 	offset = initOffset
+	var ret64 int64
 	for shifted := 0; offset < len(bytes); shifted++ {
-		if shifted == 4 {
+		// 5 * 7 bits per byte == 35 bits of data
+		// Thus the representation is either non-minimal or too large for an int32
+		if shifted == 5 {
 			err = StructuralError{"base 128 integer too large"}
 			return
 		}
-		ret <<= 7
+		ret64 <<= 7
 		b := bytes[offset]
-		ret |= int(b & 0x7f)
+		ret64 |= int64(b & 0x7f)
 		offset++
 		if b&0x80 == 0 {
+			ret = int(ret64)
+			// Ensure that the returned value fits in an int on all platforms
+			if ret64 > math.MaxInt32 {
+				err = StructuralError{"base 128 integer too large"}
+			}
 			return
 		}
 	}
@@ -975,12 +992,12 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
 //
 // The following tags on struct fields have special meaning to Unmarshal:
 //
-//	application	specifies that a APPLICATION tag is used
-//	default:x	sets the default value for optional integer fields (only used if optional is also present)
-//	explicit	specifies that an additional, explicit tag wraps the implicit one
-//	optional	marks the field as ASN.1 OPTIONAL
-//	set		causes a SET, rather than a SEQUENCE type to be expected
-//	tag:x		specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+//	application specifies that a APPLICATION tag is used
+//	default:x   sets the default value for optional integer fields (only used if optional is also present)
+//	explicit    specifies that an additional, explicit tag wraps the implicit one
+//	optional    marks the field as ASN.1 OPTIONAL
+//	set         causes a SET, rather than a SEQUENCE type to be expected
+//	tag:x       specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
 //
 // If the type of the first field of a structure is RawContent then the raw
 // ASN1 contents of the struct will be stored in it.
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 9976656..c9eda40 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -7,6 +7,7 @@ package asn1
 import (
 	"bytes"
 	"fmt"
+	"math"
 	"math/big"
 	"reflect"
 	"strings"
@@ -386,6 +387,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{}},
+	// Tag numbers that fit in an int32 are valid. (The value below is 2^31 - 1.)
+	{[]byte{0x1f, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x00}, true, tagAndLength{tag: math.MaxInt32}},
 	// Long tag number form may not be used for tags that fit in short form.
 	{[]byte{0x1f, 0x1e, 0x00}, false, tagAndLength{}},
 }
@@ -476,6 +479,7 @@ var unmarshalTestData = []struct {
 	out interface{}
 }{
 	{[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
+	{[]byte{0x05, 0x00}, &RawValue{0, 5, false, []byte{}, []byte{0x05, 0x00}}},
 	{[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
 	{[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
 	{[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
@@ -1004,3 +1008,28 @@ func TestUnexportedStructField(t *testing.T) {
 		t.Errorf("got %v, want %v", err, want)
 	}
 }
+
+func TestNull(t *testing.T) {
+	marshaled, err := Marshal(NullRawValue)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(NullBytes, marshaled) {
+		t.Errorf("Expected Marshal of NullRawValue to yeild %x, got %x", NullBytes, marshaled)
+	}
+
+	unmarshaled := RawValue{}
+	if _, err := Unmarshal(NullBytes, &unmarshaled); err != nil {
+		t.Fatal(err)
+	}
+
+	unmarshaled.FullBytes = NullRawValue.FullBytes
+	if len(unmarshaled.Bytes) == 0 {
+		// DeepEqual considers a nil slice and an empty slice to be different.
+		unmarshaled.Bytes = NullRawValue.Bytes
+	}
+
+	if !reflect.DeepEqual(NullRawValue, unmarshaled) {
+		t.Errorf("Expected Unmarshal of NullBytes to yield %v, got %v", NullRawValue, unmarshaled)
+	}
+}
diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go
index 0695180..cd93b27 100644
--- a/src/encoding/asn1/common.go
+++ b/src/encoding/asn1/common.go
@@ -24,6 +24,7 @@ const (
 	TagInteger         = 2
 	TagBitString       = 3
 	TagOctetString     = 4
+	TagNull            = 5
 	TagOID             = 6
 	TagEnum            = 10
 	TagUTF8String      = 12
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index 225fd08..fdadb39 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -643,10 +643,12 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
 // In addition to the struct tags recognised by Unmarshal, the following can be
 // used:
 //
-//	ia5:		causes strings to be marshaled as ASN.1, IA5 strings
-//	omitempty:	causes empty slices to be skipped
-//	printable:	causes strings to be marshaled as ASN.1, PrintableString strings.
-//	utf8:		causes strings to be marshaled as ASN.1, UTF8 strings
+//	ia5:         causes strings to be marshaled as ASN.1, IA5String values
+//	omitempty:   causes empty slices to be skipped
+//	printable:   causes strings to be marshaled as ASN.1, PrintableString values
+//	utf8:        causes strings to be marshaled as ASN.1, UTF8String values
+//	utc:         causes time.Time to be marshaled as ASN.1, UTCTime values
+//	generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values
 func Marshal(val interface{}) ([]byte, error) {
 	e, err := makeField(reflect.ValueOf(val), fieldParameters{})
 	if err != nil {
diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go
index c193e65..437b41d 100644
--- a/src/encoding/base32/base32.go
+++ b/src/encoding/base32/base32.go
@@ -23,8 +23,14 @@ import (
 type Encoding struct {
 	encode    string
 	decodeMap [256]byte
+	padChar   rune
 }
 
+const (
+	StdPadding rune = '=' // Standard padding character
+	NoPadding  rune = -1  // No padding
+)
+
 const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
 const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
 
@@ -33,6 +39,8 @@ const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
 func NewEncoding(encoder string) *Encoding {
 	e := new(Encoding)
 	e.encode = encoder
+	e.padChar = StdPadding
+
 	for i := 0; i < len(e.decodeMap); i++ {
 		e.decodeMap[i] = 0xFF
 	}
@@ -57,6 +65,26 @@ var removeNewlinesMapper = func(r rune) rune {
 	return r
 }
 
+// WithPadding creates a new encoding identical to enc except
+// with a specified padding character, or NoPadding to disable padding.
+// The padding character must not be '\r' or '\n', must not
+// be contained in the encoding's alphabet and must be a rune equal or
+// below '\xff'.
+func (enc Encoding) WithPadding(padding rune) *Encoding {
+	if padding == '\r' || padding == '\n' || padding > 0xff {
+		panic("invalid padding")
+	}
+
+	for i := 0; i < len(enc.encode); i++ {
+		if rune(enc.encode[i]) == padding {
+			panic("padding contained in alphabet")
+		}
+	}
+
+	enc.padChar = padding
+	return &enc
+}
+
 /*
  * Encoder
  */
@@ -73,60 +101,63 @@ func (enc *Encoding) Encode(dst, src []byte) {
 	}
 
 	for len(src) > 0 {
-		var b0, b1, b2, b3, b4, b5, b6, b7 byte
+		var b [8]byte
 
 		// Unpack 8x 5-bit source blocks into a 5 byte
 		// destination quantum
 		switch len(src) {
 		default:
-			b7 = src[4] & 0x1F
-			b6 = src[4] >> 5
+			b[7] = src[4] & 0x1F
+			b[6] = src[4] >> 5
 			fallthrough
 		case 4:
-			b6 |= (src[3] << 3) & 0x1F
-			b5 = (src[3] >> 2) & 0x1F
-			b4 = src[3] >> 7
+			b[6] |= (src[3] << 3) & 0x1F
+			b[5] = (src[3] >> 2) & 0x1F
+			b[4] = src[3] >> 7
 			fallthrough
 		case 3:
-			b4 |= (src[2] << 1) & 0x1F
-			b3 = (src[2] >> 4) & 0x1F
+			b[4] |= (src[2] << 1) & 0x1F
+			b[3] = (src[2] >> 4) & 0x1F
 			fallthrough
 		case 2:
-			b3 |= (src[1] << 4) & 0x1F
-			b2 = (src[1] >> 1) & 0x1F
-			b1 = (src[1] >> 6) & 0x1F
+			b[3] |= (src[1] << 4) & 0x1F
+			b[2] = (src[1] >> 1) & 0x1F
+			b[1] = (src[1] >> 6) & 0x1F
 			fallthrough
 		case 1:
-			b1 |= (src[0] << 2) & 0x1F
-			b0 = src[0] >> 3
+			b[1] |= (src[0] << 2) & 0x1F
+			b[0] = src[0] >> 3
 		}
 
 		// Encode 5-bit blocks using the base32 alphabet
-		dst[0] = enc.encode[b0]
-		dst[1] = enc.encode[b1]
-		dst[2] = enc.encode[b2]
-		dst[3] = enc.encode[b3]
-		dst[4] = enc.encode[b4]
-		dst[5] = enc.encode[b5]
-		dst[6] = enc.encode[b6]
-		dst[7] = enc.encode[b7]
+		for i := 0; i < 8; i++ {
+			if len(dst) > i {
+				dst[i] = enc.encode[b[i]]
+			}
+		}
 
 		// Pad the final quantum
 		if len(src) < 5 {
-			dst[7] = '='
+			if enc.padChar == NoPadding {
+				break
+			}
+
+			dst[7] = byte(enc.padChar)
 			if len(src) < 4 {
-				dst[6] = '='
-				dst[5] = '='
+				dst[6] = byte(enc.padChar)
+				dst[5] = byte(enc.padChar)
 				if len(src) < 3 {
-					dst[4] = '='
+					dst[4] = byte(enc.padChar)
 					if len(src) < 2 {
-						dst[3] = '='
-						dst[2] = '='
+						dst[3] = byte(enc.padChar)
+						dst[2] = byte(enc.padChar)
 					}
 				}
 			}
+
 			break
 		}
+
 		src = src[5:]
 		dst = dst[8:]
 	}
@@ -219,7 +250,12 @@ func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
 
 // EncodedLen returns the length in bytes of the base32 encoding
 // of an input buffer of length n.
-func (enc *Encoding) EncodedLen(n int) int { return (n + 4) / 5 * 8 }
+func (enc *Encoding) EncodedLen(n int) int {
+	if enc.padChar == NoPadding {
+		return (n*8 + 4) / 5
+	}
+	return (n + 4) / 5 * 8
+}
 
 /*
  * Decoder
@@ -343,18 +379,33 @@ type decoder struct {
 	outbuf [1024 / 8 * 5]byte
 }
 
-func (d *decoder) Read(p []byte) (n int, err error) {
-	if d.err != nil {
-		return 0, d.err
+func readEncodedData(r io.Reader, buf []byte, min int) (n int, err error) {
+	for n < min && err == nil {
+		var nn int
+		nn, err = r.Read(buf[n:])
+		n += nn
+	}
+	if n < min && n > 0 && err == io.EOF {
+		err = io.ErrUnexpectedEOF
 	}
+	return
+}
 
+func (d *decoder) Read(p []byte) (n int, err error) {
 	// Use leftover decoded output from last read.
 	if len(d.out) > 0 {
 		n = copy(p, d.out)
 		d.out = d.out[n:]
+		if len(d.out) == 0 {
+			return n, d.err
+		}
 		return n, nil
 	}
 
+	if d.err != nil {
+		return 0, d.err
+	}
+
 	// Read a chunk.
 	nn := len(p) / 5 * 8
 	if nn < 8 {
@@ -363,7 +414,8 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 	if nn > len(d.buf) {
 		nn = len(d.buf)
 	}
-	nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
+
+	nn, d.err = readEncodedData(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
 	d.nbuf += nn
 	if d.nbuf < 8 {
 		return 0, d.err
@@ -373,21 +425,30 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 	nr := d.nbuf / 8 * 8
 	nw := d.nbuf / 8 * 5
 	if nw > len(p) {
-		nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+		nw, d.end, err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
 		d.out = d.outbuf[0:nw]
 		n = copy(p, d.out)
 		d.out = d.out[n:]
 	} else {
-		n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+		n, d.end, err = d.enc.decode(p, d.buf[0:nr])
 	}
 	d.nbuf -= nr
 	for i := 0; i < d.nbuf; i++ {
 		d.buf[i] = d.buf[i+nr]
 	}
 
-	if d.err == nil {
+	if err != nil && (d.err == nil || d.err == io.EOF) {
 		d.err = err
 	}
+
+	if len(d.out) > 0 {
+		// We cannot return all the decoded bytes to the caller in this
+		// invocation of Read, so we return a nil error to ensure that Read
+		// will be called again.  The error stored in d.err, if any, will be
+		// returned with the last set of decoded bytes.
+		return n, nil
+	}
+
 	return n, d.err
 }
 
@@ -407,7 +468,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) {
 				offset++
 			}
 		}
-		if offset > 0 {
+		if err != nil || offset > 0 {
 			return offset, err
 		}
 		// Previous buffer entirely whitespace, read again
diff --git a/src/encoding/base32/base32_test.go b/src/encoding/base32/base32_test.go
index 66a48a3..bd101b5 100644
--- a/src/encoding/base32/base32_test.go
+++ b/src/encoding/base32/base32_test.go
@@ -6,6 +6,7 @@ package base32
 
 import (
 	"bytes"
+	"errors"
 	"io"
 	"io/ioutil"
 	"strings"
@@ -123,6 +124,160 @@ func TestDecoder(t *testing.T) {
 	}
 }
 
+type badReader struct {
+	data   []byte
+	errs   []error
+	called int
+	limit  int
+}
+
+// Populates p with data, returns a count of the bytes written and an
+// error.  The error returned is taken from badReader.errs, with each
+// invocation of Read returning the next error in this slice, or io.EOF,
+// if all errors from the slice have already been returned.  The
+// number of bytes returned is determined by the size of the input buffer
+// the test passes to decoder.Read and will be a multiple of 8, unless
+// badReader.limit is non zero.
+func (b *badReader) Read(p []byte) (int, error) {
+	lim := len(p)
+	if b.limit != 0 && b.limit < lim {
+		lim = b.limit
+	}
+	if len(b.data) < lim {
+		lim = len(b.data)
+	}
+	for i := range p[:lim] {
+		p[i] = b.data[i]
+	}
+	b.data = b.data[lim:]
+	err := io.EOF
+	if b.called < len(b.errs) {
+		err = b.errs[b.called]
+	}
+	b.called++
+	return lim, err
+}
+
+// TestIssue20044 tests that decoder.Read behaves correctly when the caller
+// supplied reader returns an error.
+func TestIssue20044(t *testing.T) {
+	badErr := errors.New("bad reader error")
+	testCases := []struct {
+		r       badReader
+		res     string
+		err     error
+		dbuflen int
+	}{
+		// Check valid input data accompanied by an error is processed and the error is propagated.
+		{r: badReader{data: []byte("MY======"), errs: []error{badErr}},
+			res: "f", err: badErr},
+		// Check a read error accompanied by input data consisting of newlines only is propagated.
+		{r: badReader{data: []byte("\n\n\n\n\n\n\n\n"), errs: []error{badErr, nil}},
+			res: "", err: badErr},
+		// Reader will be called twice.  The first time it will return 8 newline characters.  The
+		// second time valid base32 encoded data and an error.  The data should be decoded
+		// correctly and the error should be propagated.
+		{r: badReader{data: []byte("\n\n\n\n\n\n\n\nMY======"), errs: []error{nil, badErr}},
+			res: "f", err: badErr, dbuflen: 8},
+		// Reader returns invalid input data (too short) and an error.  Verify the reader
+		// error is returned.
+		{r: badReader{data: []byte("MY====="), errs: []error{badErr}},
+			res: "", err: badErr},
+		// Reader returns invalid input data (too short) but no error.  Verify io.ErrUnexpectedEOF
+		// is returned.
+		{r: badReader{data: []byte("MY====="), errs: []error{nil}},
+			res: "", err: io.ErrUnexpectedEOF},
+		// Reader returns invalid input data and an error.  Verify the reader and not the
+		// decoder error is returned.
+		{r: badReader{data: []byte("Ma======"), errs: []error{badErr}},
+			res: "", err: badErr},
+		// Reader returns valid data and io.EOF.  Check data is decoded and io.EOF is propagated.
+		{r: badReader{data: []byte("MZXW6YTB"), errs: []error{io.EOF}},
+			res: "fooba", err: io.EOF},
+		// Check errors are properly reported when decoder.Read is called multiple times.
+		// decoder.Read will be called 8 times, badReader.Read will be called twice, returning
+		// valid data both times but an error on the second call.
+		{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, badErr}},
+			res: "leasure.", err: badErr, dbuflen: 1},
+		// Check io.EOF is properly reported when decoder.Read is called multiple times.
+		// decoder.Read will be called 8 times, badReader.Read will be called twice, returning
+		// valid data both times but io.EOF on the second call.
+		{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, io.EOF}},
+			res: "leasure.", err: io.EOF, dbuflen: 1},
+		// The following two test cases check that errors are propagated correctly when more than
+		// 8 bytes are read at a time.
+		{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{io.EOF}},
+			res: "leasure.", err: io.EOF, dbuflen: 11},
+		{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{badErr}},
+			res: "leasure.", err: badErr, dbuflen: 11},
+		// Check that errors are correctly propagated when the reader returns valid bytes in
+		// groups that are not divisible by 8.  The first read will return 11 bytes and no
+		// error.  The second will return 7 and an error.  The data should be decoded correctly
+		// and the error should be propagated.
+		{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, badErr}, limit: 11},
+			res: "leasure.", err: badErr},
+	}
+
+	for _, tc := range testCases {
+		input := tc.r.data
+		decoder := NewDecoder(StdEncoding, &tc.r)
+		var dbuflen int
+		if tc.dbuflen > 0 {
+			dbuflen = tc.dbuflen
+		} else {
+			dbuflen = StdEncoding.DecodedLen(len(input))
+		}
+		dbuf := make([]byte, dbuflen)
+		var err error
+		var res []byte
+		for err == nil {
+			var n int
+			n, err = decoder.Read(dbuf)
+			if n > 0 {
+				res = append(res, dbuf[:n]...)
+			}
+		}
+
+		testEqual(t, "Decoding of %q = %q, want %q", string(input), string(res), tc.res)
+		testEqual(t, "Decoding of %q err = %v, expected %v", string(input), err, tc.err)
+	}
+}
+
+// TestDecoderError verifies decode errors are propagated when there are no read
+// errors.
+func TestDecoderError(t *testing.T) {
+	for _, readErr := range []error{io.EOF, nil} {
+		input := "MZXW6YTb"
+		dbuf := make([]byte, StdEncoding.DecodedLen(len(input)))
+		br := badReader{data: []byte(input), errs: []error{readErr}}
+		decoder := NewDecoder(StdEncoding, &br)
+		n, err := decoder.Read(dbuf)
+		testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
+		if _, ok := err.(CorruptInputError); !ok {
+			t.Errorf("Corrupt input error expected.  Found %T", err)
+		}
+	}
+}
+
+// TestReaderEOF ensures decoder.Read behaves correctly when input data is
+// exhausted.
+func TestReaderEOF(t *testing.T) {
+	for _, readErr := range []error{io.EOF, nil} {
+		input := "MZXW6YTB"
+		br := badReader{data: []byte(input), errs: []error{nil, readErr}}
+		decoder := NewDecoder(StdEncoding, &br)
+		dbuf := make([]byte, StdEncoding.DecodedLen(len(input)))
+		n, err := decoder.Read(dbuf)
+		testEqual(t, "Decoding of %q err = %v, expected %v", string(input), err, error(nil))
+		n, err = decoder.Read(dbuf)
+		testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
+		testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF)
+		n, err = decoder.Read(dbuf)
+		testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
+		testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF)
+	}
+}
+
 func TestDecoderBuffering(t *testing.T) {
 	for bs := 1; bs <= 12; bs++ {
 		decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
@@ -300,3 +455,33 @@ func BenchmarkDecodeString(b *testing.B) {
 		StdEncoding.DecodeString(data)
 	}
 }
+
+func TestWithCustomPadding(t *testing.T) {
+	for _, testcase := range pairs {
+		defaultPadding := StdEncoding.EncodeToString([]byte(testcase.decoded))
+		customPadding := StdEncoding.WithPadding('@').EncodeToString([]byte(testcase.decoded))
+		expected := strings.Replace(defaultPadding, "=", "@", -1)
+
+		if expected != customPadding {
+			t.Errorf("Expected custom %s, got %s", expected, customPadding)
+		}
+		if testcase.encoded != defaultPadding {
+			t.Errorf("Expected %s, got %s", testcase.encoded, defaultPadding)
+		}
+	}
+}
+
+func TestWithoutPadding(t *testing.T) {
+	for _, testcase := range pairs {
+		defaultPadding := StdEncoding.EncodeToString([]byte(testcase.decoded))
+		customPadding := StdEncoding.WithPadding(NoPadding).EncodeToString([]byte(testcase.decoded))
+		expected := strings.TrimRight(defaultPadding, "=")
+
+		if expected != customPadding {
+			t.Errorf("Expected custom %s, got %s", expected, customPadding)
+		}
+		if testcase.encoded != defaultPadding {
+			t.Errorf("Expected %s, got %s", testcase.encoded, defaultPadding)
+		}
+	}
+}
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index d2efad4..b208f9e 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -35,13 +35,19 @@ const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678
 const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
 
 // NewEncoding returns a new padded Encoding defined by the given alphabet,
-// which must be a 64-byte string.
+// which must be a 64-byte string that does not contain the padding character
+// or CR / LF ('\r', '\n').
 // The resulting Encoding uses the default padding character ('='),
 // which may be changed or disabled via WithPadding.
 func NewEncoding(encoder string) *Encoding {
 	if len(encoder) != 64 {
 		panic("encoding alphabet is not 64-bytes long")
 	}
+	for i := 0; i < len(encoder); i++ {
+		if encoder[i] == '\n' || encoder[i] == '\r' {
+			panic("encoding alphabet contains newline character")
+		}
+	}
 
 	e := new(Encoding)
 	e.padChar = StdPadding
@@ -58,7 +64,20 @@ func NewEncoding(encoder string) *Encoding {
 
 // WithPadding creates a new encoding identical to enc except
 // with a specified padding character, or NoPadding to disable padding.
+// The padding character must not be '\r' or '\n', must not
+// be contained in the encoding's alphabet and must be a rune equal or
+// below '\xff'.
 func (enc Encoding) WithPadding(padding rune) *Encoding {
+	if padding == '\r' || padding == '\n' || padding > 0xff {
+		panic("invalid padding")
+	}
+
+	for i := 0; i < len(enc.encode); i++ {
+		if rune(enc.encode[i]) == padding {
+			panic("padding contained in alphabet")
+		}
+	}
+
 	enc.padChar = padding
 	return &enc
 }
@@ -256,19 +275,17 @@ func (e CorruptInputError) Error() string {
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 	si := 0
 
-	// skip over newlines
-	for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-		si++
-	}
-
 	for si < len(src) && !end {
 		// Decode quantum using the base64 alphabet
 		var dbuf [4]byte
 		dinc, dlen := 3, 4
 
-		for j := range dbuf {
+		for j := 0; j < len(dbuf); j++ {
 			if len(src) == si {
-				if enc.padChar != NoPadding || j < 2 {
+				switch {
+				case j == 0:
+					return n, false, nil
+				case j == 1, enc.padChar != NoPadding:
 					return n, false, CorruptInputError(si - j)
 				}
 				dinc, dlen, end = j-1, j, true
@@ -277,11 +294,17 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 			in := src[si]
 
 			si++
-			// skip over newlines
-			for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-				si++
+
+			out := enc.decodeMap[in]
+			if out != 0xFF {
+				dbuf[j] = out
+				continue
 			}
 
+			if in == '\n' || in == '\r' {
+				j--
+				continue
+			}
 			if rune(in) == enc.padChar {
 				// We've reached the end and there's padding
 				switch j {
@@ -290,6 +313,10 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 					return n, false, CorruptInputError(si - 1)
 				case 2:
 					// "==" is expected, the first "=" is already consumed.
+					// skip over newlines
+					for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+						si++
+					}
 					if si == len(src) {
 						// not enough padding
 						return n, false, CorruptInputError(len(src))
@@ -300,10 +327,10 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 					}
 
 					si++
-					// skip over newlines
-					for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-						si++
-					}
+				}
+				// skip over newlines
+				for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+					si++
 				}
 				if si < len(src) {
 					// trailing garbage
@@ -312,10 +339,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 				dinc, dlen, end = 3, j, true
 				break
 			}
-			dbuf[j] = enc.decodeMap[in]
-			if dbuf[j] == 0xFF {
-				return n, false, CorruptInputError(si - 1)
-			}
+			return n, false, CorruptInputError(si - 1)
 		}
 
 		// Convert 4x 6bit source bytes into 3 bytes
diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go
index e2e1d59..8ebf2b1 100644
--- a/src/encoding/base64/base64_test.go
+++ b/src/encoding/base64/base64_test.go
@@ -7,6 +7,7 @@ package base64
 import (
 	"bytes"
 	"errors"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"reflect"
@@ -63,7 +64,7 @@ func rawRef(ref string) string {
 }
 
 // Both URL and unpadding conversions
-func rawUrlRef(ref string) string {
+func rawURLRef(ref string) string {
 	return rawRef(urlRef(ref))
 }
 
@@ -83,12 +84,12 @@ var encodingTests = []encodingTest{
 	{StdEncoding, stdRef},
 	{URLEncoding, urlRef},
 	{RawStdEncoding, rawRef},
-	{RawURLEncoding, rawUrlRef},
+	{RawURLEncoding, rawURLRef},
 	{funnyEncoding, funnyRef},
 	{StdEncoding.Strict(), stdRef},
 	{URLEncoding.Strict(), urlRef},
 	{RawStdEncoding.Strict(), rawRef},
-	{RawURLEncoding.Strict(), rawUrlRef},
+	{RawURLEncoding.Strict(), rawURLRef},
 	{funnyEncoding.Strict(), funnyRef},
 }
 
@@ -202,6 +203,9 @@ func TestDecodeCorrupt(t *testing.T) {
 		offset int // -1 means no corruption.
 	}{
 		{"", -1},
+		{"\n", -1},
+		{"AAA=\n", -1},
+		{"AAAA\n", -1},
 		{"!!!!", 0},
 		{"====", 0},
 		{"x===", 1},
@@ -220,6 +224,8 @@ func TestDecodeCorrupt(t *testing.T) {
 		{"AAAA", -1},
 		{"AAAAAA=", 7},
 		{"YWJjZA=====", 8},
+		{"A!\n", 1},
+		{"A=\n", 1},
 	}
 	for _, tc := range testCases {
 		dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
@@ -466,10 +472,19 @@ func BenchmarkEncodeToString(b *testing.B) {
 }
 
 func BenchmarkDecodeString(b *testing.B) {
-	data := StdEncoding.EncodeToString(make([]byte, 8192))
-	b.SetBytes(int64(len(data)))
-	for i := 0; i < b.N; i++ {
-		StdEncoding.DecodeString(data)
+	sizes := []int{2, 4, 8, 64, 8192}
+	benchFunc := func(b *testing.B, benchSize int) {
+		data := StdEncoding.EncodeToString(make([]byte, benchSize))
+		b.SetBytes(int64(len(data)))
+		b.ResetTimer()
+		for i := 0; i < b.N; i++ {
+			StdEncoding.DecodeString(data)
+		}
+	}
+	for _, size := range sizes {
+		b.Run(fmt.Sprintf("%d", size), func(b *testing.B) {
+			benchFunc(b, size)
+		})
 	}
 }
 
diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go
index fc7f276..0547bee 100644
--- a/src/encoding/binary/binary_test.go
+++ b/src/encoding/binary/binary_test.go
@@ -500,3 +500,27 @@ func BenchmarkWriteSlice1000Int32s(b *testing.B) {
 	}
 	b.StopTimer()
 }
+
+func BenchmarkPutUint16(b *testing.B) {
+	buf := [2]byte{}
+	b.SetBytes(2)
+	for i := 0; i < b.N; i++ {
+		BigEndian.PutUint16(buf[:], uint16(i))
+	}
+}
+
+func BenchmarkPutUint32(b *testing.B) {
+	buf := [4]byte{}
+	b.SetBytes(4)
+	for i := 0; i < b.N; i++ {
+		BigEndian.PutUint32(buf[:], uint32(i))
+	}
+}
+
+func BenchmarkPutUint64(b *testing.B) {
+	buf := [8]byte{}
+	b.SetBytes(8)
+	for i := 0; i < b.N; i++ {
+		BigEndian.PutUint64(buf[:], uint64(i))
+	}
+}
diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go
index c8c4ca7..a3497c8 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -110,6 +110,10 @@ type Reader struct {
 	// 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
+	// ReuseRecord controls whether calls to Read may return a slice sharing
+	// the backing array of the previous call's returned slice for performance.
+	// By default, each call to Read returns newly allocated memory owned by the caller.
+	ReuseRecord bool
 
 	line   int
 	column int
@@ -122,6 +126,9 @@ type Reader struct {
 	// Indexes of fields inside lineBuffer
 	// The i'th field starts at offset fieldIndexes[i] in lineBuffer.
 	fieldIndexes []int
+
+	// only used when ReuseRecord == true
+	lastRecord []string
 }
 
 // NewReader returns a new Reader that reads from r.
@@ -147,26 +154,17 @@ func (r *Reader) error(err error) error {
 // Except for that case, Read always returns either a non-nil
 // record or a non-nil error, but not both.
 // If there is no data left to be read, Read returns nil, io.EOF.
+// If ReuseRecord is true, the returned slice may be shared
+// between multiple calls to Read.
 func (r *Reader) Read() (record []string, err error) {
-	for {
-		record, err = r.parseRecord()
-		if record != nil {
-			break
-		}
-		if err != nil {
-			return nil, err
-		}
+	if r.ReuseRecord {
+		record, err = r.readRecord(r.lastRecord)
+		r.lastRecord = record
+	} else {
+		record, err = r.readRecord(nil)
 	}
 
-	if r.FieldsPerRecord > 0 {
-		if len(record) != r.FieldsPerRecord {
-			r.column = 0 // report at start of record
-			return record, r.error(ErrFieldCount)
-		}
-	} else if r.FieldsPerRecord == 0 {
-		r.FieldsPerRecord = len(record)
-	}
-	return record, nil
+	return record, err
 }
 
 // ReadAll reads all the remaining records from r.
@@ -176,7 +174,7 @@ func (r *Reader) Read() (record []string, err error) {
 // reported.
 func (r *Reader) ReadAll() (records [][]string, err error) {
 	for {
-		record, err := r.Read()
+		record, err := r.readRecord(nil)
 		if err == io.EOF {
 			return records, nil
 		}
@@ -187,6 +185,31 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
 	}
 }
 
+// readRecord reads and parses a single csv record from r.
+// Unlike parseRecord, readRecord handles FieldsPerRecord.
+// If dst has enough capacity it will be used for the returned record.
+func (r *Reader) readRecord(dst []string) (record []string, err error) {
+	for {
+		record, err = r.parseRecord(dst)
+		if record != nil {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if r.FieldsPerRecord > 0 {
+		if len(record) != r.FieldsPerRecord {
+			r.column = 0 // report at start of record
+			return record, r.error(ErrFieldCount)
+		}
+	} else if r.FieldsPerRecord == 0 {
+		r.FieldsPerRecord = len(record)
+	}
+	return record, nil
+}
+
 // readRune reads one rune from r, folding \r\n to \n and keeping track
 // of how far into the line we have read.  r.column will point to the start
 // of this rune, not the end of this rune.
@@ -223,7 +246,8 @@ 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) {
+// If dst has enough capacity it will be used for the returned fields.
+func (r *Reader) parseRecord(dst []string) (fields []string, err error) {
 	// 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.
@@ -275,7 +299,12 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	// minimal and a tradeoff for better performance through the combined
 	// allocations.
 	line := r.lineBuffer.String()
-	fields = make([]string, fieldCount)
+
+	if cap(dst) >= fieldCount {
+		fields = dst[:fieldCount]
+	} else {
+		fields = make([]string, fieldCount)
+	}
 
 	for i, idx := range r.fieldIndexes {
 		if i == fieldCount-1 {
diff --git a/src/encoding/csv/reader_test.go b/src/encoding/csv/reader_test.go
index 7b3aca4..5ab1b61 100644
--- a/src/encoding/csv/reader_test.go
+++ b/src/encoding/csv/reader_test.go
@@ -24,6 +24,7 @@ var readTests = []struct {
 	LazyQuotes       bool
 	TrailingComma    bool
 	TrimLeadingSpace bool
+	ReuseRecord      bool
 
 	Error  string
 	Line   int // Expected error line if != 0
@@ -260,6 +261,15 @@ x,,,
 			{"c", "d", "e"},
 		},
 	},
+	{
+		Name:        "ReadAllReuseRecord",
+		ReuseRecord: true,
+		Input:       "a,b\nc,d",
+		Output: [][]string{
+			{"a", "b"},
+			{"c", "d"},
+		},
+	},
 }
 
 func TestRead(t *testing.T) {
@@ -274,6 +284,7 @@ func TestRead(t *testing.T) {
 		r.LazyQuotes = tt.LazyQuotes
 		r.TrailingComma = tt.TrailingComma
 		r.TrimLeadingSpace = tt.TrimLeadingSpace
+		r.ReuseRecord = tt.ReuseRecord
 		if tt.Comma != 0 {
 			r.Comma = tt.Comma
 		}
@@ -369,3 +380,23 @@ xxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzz
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 `, 3))
 }
+
+func BenchmarkReadReuseRecord(b *testing.B) {
+	benchmarkRead(b, func(r *Reader) { r.ReuseRecord = true }, benchmarkCSVData)
+}
+
+func BenchmarkReadReuseRecordWithFieldsPerRecord(b *testing.B) {
+	benchmarkRead(b, func(r *Reader) { r.ReuseRecord = true; r.FieldsPerRecord = 4 }, benchmarkCSVData)
+}
+
+func BenchmarkReadReuseRecordWithoutFieldsPerRecord(b *testing.B) {
+	benchmarkRead(b, func(r *Reader) { r.ReuseRecord = true; r.FieldsPerRecord = -1 }, benchmarkCSVData)
+}
+
+func BenchmarkReadReuseRecordLargeFields(b *testing.B) {
+	benchmarkRead(b, func(r *Reader) { r.ReuseRecord = true }, strings.Repeat(`xxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+xxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvv
+,,zzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+`, 3))
+}
diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index d4002cb..eb9f306 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -47,7 +47,6 @@ func testError(t *testing.T) {
 	if e := recover(); e != nil {
 		t.Error(e.(gobError).err) // Will re-panic if not one of our errors, such as a runtime error.
 	}
-	return
 }
 
 func newDecBuffer(data []byte) *decBuffer {
@@ -321,7 +320,7 @@ func TestScalarEncInstructions(t *testing.T) {
 	}
 }
 
-func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, value reflect.Value) {
+func execDec(instr *decInstr, state *decoderState, t *testing.T, value reflect.Value) {
 	defer testError(t)
 	v := int(state.decodeUint())
 	if v+state.fieldnum != 6 {
@@ -348,7 +347,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data bool
 		instr := &decInstr{decBool, 6, nil, ovfl}
 		state := newDecodeStateFromData(boolResult)
-		execDec("bool", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != true {
 			t.Errorf("bool a = %v not true", data)
 		}
@@ -358,7 +357,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data int
 		instr := &decInstr{decOpTable[reflect.Int], 6, nil, ovfl}
 		state := newDecodeStateFromData(signedResult)
-		execDec("int", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("int a = %v not 17", data)
 		}
@@ -369,7 +368,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uint
 		instr := &decInstr{decOpTable[reflect.Uint], 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uint", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uint a = %v not 17", data)
 		}
@@ -380,7 +379,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data int8
 		instr := &decInstr{decInt8, 6, nil, ovfl}
 		state := newDecodeStateFromData(signedResult)
-		execDec("int8", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("int8 a = %v not 17", data)
 		}
@@ -391,7 +390,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uint8
 		instr := &decInstr{decUint8, 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uint8", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uint8 a = %v not 17", data)
 		}
@@ -402,7 +401,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data int16
 		instr := &decInstr{decInt16, 6, nil, ovfl}
 		state := newDecodeStateFromData(signedResult)
-		execDec("int16", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("int16 a = %v not 17", data)
 		}
@@ -413,7 +412,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uint16
 		instr := &decInstr{decUint16, 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uint16", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uint16 a = %v not 17", data)
 		}
@@ -424,7 +423,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data int32
 		instr := &decInstr{decInt32, 6, nil, ovfl}
 		state := newDecodeStateFromData(signedResult)
-		execDec("int32", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("int32 a = %v not 17", data)
 		}
@@ -435,7 +434,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uint32
 		instr := &decInstr{decUint32, 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uint32", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uint32 a = %v not 17", data)
 		}
@@ -446,7 +445,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uintptr
 		instr := &decInstr{decOpTable[reflect.Uintptr], 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uintptr", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uintptr a = %v not 17", data)
 		}
@@ -457,7 +456,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data int64
 		instr := &decInstr{decInt64, 6, nil, ovfl}
 		state := newDecodeStateFromData(signedResult)
-		execDec("int64", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("int64 a = %v not 17", data)
 		}
@@ -468,7 +467,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data uint64
 		instr := &decInstr{decUint64, 6, nil, ovfl}
 		state := newDecodeStateFromData(unsignedResult)
-		execDec("uint64", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("uint64 a = %v not 17", data)
 		}
@@ -479,7 +478,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data float32
 		instr := &decInstr{decFloat32, 6, nil, ovfl}
 		state := newDecodeStateFromData(floatResult)
-		execDec("float32", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("float32 a = %v not 17", data)
 		}
@@ -490,7 +489,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data float64
 		instr := &decInstr{decFloat64, 6, nil, ovfl}
 		state := newDecodeStateFromData(floatResult)
-		execDec("float64", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17 {
 			t.Errorf("float64 a = %v not 17", data)
 		}
@@ -501,7 +500,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data complex64
 		instr := &decInstr{decOpTable[reflect.Complex64], 6, nil, ovfl}
 		state := newDecodeStateFromData(complexResult)
-		execDec("complex", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17+19i {
 			t.Errorf("complex a = %v not 17+19i", data)
 		}
@@ -512,7 +511,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data complex128
 		instr := &decInstr{decOpTable[reflect.Complex128], 6, nil, ovfl}
 		state := newDecodeStateFromData(complexResult)
-		execDec("complex", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != 17+19i {
 			t.Errorf("complex a = %v not 17+19i", data)
 		}
@@ -523,7 +522,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data []byte
 		instr := &decInstr{decUint8Slice, 6, nil, ovfl}
 		state := newDecodeStateFromData(bytesResult)
-		execDec("bytes", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if string(data) != "hello" {
 			t.Errorf(`bytes a = %q not "hello"`, string(data))
 		}
@@ -534,7 +533,7 @@ func TestScalarDecInstructions(t *testing.T) {
 		var data string
 		instr := &decInstr{decString, 6, nil, ovfl}
 		state := newDecodeStateFromData(bytesResult)
-		execDec("bytes", instr, state, t, reflect.ValueOf(&data))
+		execDec(instr, state, t, reflect.ValueOf(&data))
 		if data != "hello" {
 			t.Errorf(`bytes a = %q not "hello"`, data)
 		}
@@ -545,11 +544,18 @@ func TestEndToEnd(t *testing.T) {
 	type T2 struct {
 		T string
 	}
-	s1 := "string1"
-	s2 := "string2"
+	type T3 struct {
+		X float64
+		Z *int
+	}
 	type T1 struct {
 		A, B, C  int
 		M        map[string]*float64
+		M2       map[int]T3
+		Mstring  map[string]string
+		Mintptr  map[int]*int
+		Mcomp    map[complex128]complex128
+		Marr     map[[2]string][2]*float64
 		EmptyMap map[string]int // to check that we receive a non-nil map.
 		N        *[3]float64
 		Strs     *[2]string
@@ -561,11 +567,35 @@ func TestEndToEnd(t *testing.T) {
 	}
 	pi := 3.14159
 	e := 2.71828
+	two := 2.0
+	meaning := 42
+	fingers := 5
+	s1 := "string1"
+	s2 := "string2"
+	var comp1 complex128 = complex(1.0, 1.0)
+	var comp2 complex128 = complex(1.0, 1.0)
+	var arr1 [2]string
+	arr1[0] = s1
+	arr1[1] = s2
+	var arr2 [2]string
+	arr2[0] = s2
+	arr2[1] = s1
+	var floatArr1 [2]*float64
+	floatArr1[0] = &pi
+	floatArr1[1] = &e
+	var floatArr2 [2]*float64
+	floatArr2[0] = &e
+	floatArr2[1] = &two
 	t1 := &T1{
 		A:        17,
 		B:        18,
 		C:        -5,
 		M:        map[string]*float64{"pi": &pi, "e": &e},
+		M2:       map[int]T3{4: T3{X: pi, Z: &meaning}, 10: T3{X: e, Z: &fingers}},
+		Mstring:  map[string]string{"pi": "3.14", "e": "2.71"},
+		Mintptr:  map[int]*int{meaning: &fingers, fingers: &meaning},
+		Mcomp:    map[complex128]complex128{comp1: comp2, comp2: comp1},
+		Marr:     map[[2]string][2]*float64{arr1: floatArr1, arr2: floatArr2},
 		EmptyMap: make(map[string]int),
 		N:        &[3]float64{1.5, 2.5, 3.5},
 		Strs:     &[2]string{s1, s2},
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index 9645dc5..8dece42 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -11,6 +11,7 @@ import (
 	"errors"
 	"io"
 	"math"
+	"math/bits"
 	"reflect"
 )
 
@@ -313,12 +314,7 @@ func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
 // (for example) transmit more compactly. This routine does the
 // unswizzling.
 func float64FromBits(u uint64) float64 {
-	var v uint64
-	for i := 0; i < 8; i++ {
-		v <<= 8
-		v |= u & 0xFF
-		u >>= 8
-	}
+	v := bits.ReverseBytes64(u)
 	return math.Float64frombits(v)
 }
 
@@ -430,7 +426,7 @@ type decEngine struct {
 // decodeSingle decodes a top-level value that is not a struct and stores it in value.
 // Such values are preceded by a zero, making them have the memory layout of a
 // struct field (although with an illegal field number).
-func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
+func (dec *Decoder) decodeSingle(engine *decEngine, value reflect.Value) {
 	state := dec.newDecoderState(&dec.buf)
 	defer dec.freeDecoderState(state)
 	state.fieldnum = singletonField
@@ -446,7 +442,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value refl
 // 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.
-func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
+func (dec *Decoder) decodeStruct(engine *decEngine, value reflect.Value) {
 	state := dec.newDecoderState(&dec.buf)
 	defer dec.freeDecoderState(state)
 	state.fieldnum = -1
@@ -538,7 +534,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
 // (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) {
+func (dec *Decoder) decodeArray(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
 	if n := state.decodeUint(); n != uint64(length) {
 		errorf("length mismatch in decodeArray")
 	}
@@ -546,12 +542,12 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value re
 }
 
 // decodeIntoValue is a helper for map decoding.
-func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, ovfl error) reflect.Value {
-	instr := &decInstr{op, 0, nil, ovfl}
+func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Value, instr *decInstr) reflect.Value {
 	v := value
 	if isPtr {
 		v = decAlloc(value)
 	}
+
 	op(instr, state, v)
 	return value
 }
@@ -561,17 +557,24 @@ func decodeIntoValue(state *decoderState, op decOp, isPtr bool, value reflect.Va
 // Because the internals of maps are not visible to us, we must
 // use reflection rather than pointer magic.
 func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, ovfl error) {
+	n := int(state.decodeUint())
 	if value.IsNil() {
-		// Allocate map.
-		value.Set(reflect.MakeMap(mtyp))
+		value.Set(reflect.MakeMapWithSize(mtyp, n))
 	}
-	n := int(state.decodeUint())
 	keyIsPtr := mtyp.Key().Kind() == reflect.Ptr
 	elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr
+	keyInstr := &decInstr{keyOp, 0, nil, ovfl}
+	elemInstr := &decInstr{elemOp, 0, nil, ovfl}
+	keyP := reflect.New(mtyp.Key())
+	keyZ := reflect.Zero(mtyp.Key())
+	elemP := reflect.New(mtyp.Elem())
+	elemZ := reflect.Zero(mtyp.Elem())
 	for i := 0; i < n; i++ {
-		key := decodeIntoValue(state, keyOp, keyIsPtr, allocValue(mtyp.Key()), ovfl)
-		elem := decodeIntoValue(state, elemOp, elemIsPtr, allocValue(mtyp.Elem()), ovfl)
+		key := decodeIntoValue(state, keyOp, keyIsPtr, keyP.Elem(), keyInstr)
+		elem := decodeIntoValue(state, elemOp, elemIsPtr, elemP.Elem(), elemInstr)
 		value.SetMapIndex(key, elem)
+		keyP.Elem().Set(keyZ)
+		elemP.Elem().Set(elemZ)
 	}
 }
 
@@ -657,12 +660,12 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
 		errorf("name too long (%d bytes): %.20q...", len(name), name)
 	}
 	// The concrete type must be registered.
-	registerLock.RLock()
-	typ, ok := nameToConcreteType[string(name)]
-	registerLock.RUnlock()
+	typi, ok := nameToConcreteType.Load(string(name))
 	if !ok {
 		errorf("name not registered for interface: %q", name)
 	}
+	typ := typi.(reflect.Type)
+
 	// Read the type id of the concrete value.
 	concreteId := dec.decodeTypeSequence(true)
 	if concreteId < 0 {
@@ -813,7 +816,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
 			ovfl := overflow(name)
 			helper := decArrayHelper[t.Elem().Kind()]
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl, helper)
+				state.dec.decodeArray(state, value, *elemOp, t.Len(), ovfl, helper)
 			}
 
 		case reflect.Map:
@@ -854,7 +857,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
 			}
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
 				// indirect through enginePtr to delay evaluation for recursive structs.
-				dec.decodeStruct(*enginePtr, ut, value)
+				dec.decodeStruct(*enginePtr, value)
 			}
 		case reflect.Interface:
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
@@ -1197,9 +1200,9 @@ func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) {
 			name := base.Name()
 			errorf("type mismatch: no fields matched compiling decoder for %s", name)
 		}
-		dec.decodeStruct(engine, ut, value)
+		dec.decodeStruct(engine, value)
 	} else {
-		dec.decodeSingle(engine, ut, value)
+		dec.decodeSingle(engine, value)
 	}
 }
 
diff --git a/src/encoding/gob/doc.go b/src/encoding/gob/doc.go
index 1536574..554d113 100644
--- a/src/encoding/gob/doc.go
+++ b/src/encoding/gob/doc.go
@@ -175,6 +175,12 @@ the interface value.  (A nil interface value is identified by the empty string
 and transmits no value.) Upon receipt, the decoder verifies that the unpacked
 concrete item satisfies the interface of the receiving variable.
 
+If a value is passed to Encode and the type is not a struct (or pointer to struct,
+etc.), for simplicity of processing it is represented as a struct of one field.
+The only visible effect of this is to encode a zero byte after the value, just as
+after the last field of an encoded struct, so that the decode algorithm knows when
+the top-level value is complete.
+
 The representation of types is described below.  When a type is defined on a given
 connection between an Encoder and Decoder, it is assigned a signed integer type
 id.  When Encoder.Encode(v) is called, it makes sure there is an id assigned for
diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go
index 50cd6ad..5371e72 100644
--- a/src/encoding/gob/encode.go
+++ b/src/encoding/gob/encode.go
@@ -8,7 +8,9 @@ package gob
 
 import (
 	"encoding"
+	"encoding/binary"
 	"math"
+	"math/bits"
 	"reflect"
 	"sync"
 )
@@ -107,14 +109,12 @@ func (state *encoderState) encodeUint(x uint64) {
 		state.b.WriteByte(uint8(x))
 		return
 	}
-	i := uint64Size
-	for x > 0 {
-		state.buf[i] = uint8(x)
-		x >>= 8
-		i--
-	}
-	state.buf[i] = uint8(i - uint64Size) // = loop count, negated
-	state.b.Write(state.buf[i : uint64Size+1])
+
+	binary.BigEndian.PutUint64(state.buf[1:], x)
+	bc := bits.LeadingZeros64(x) >> 3      // 8 - bytelen(x)
+	state.buf[bc] = uint8(bc - uint64Size) // and then we subtract 8 to get -bytelen(x)
+
+	state.b.Write(state.buf[bc : uint64Size+1])
 }
 
 // encodeInt writes an encoded signed integer to state.w.
@@ -209,13 +209,7 @@ func encUint(i *encInstr, state *encoderState, v reflect.Value) {
 // swizzling.
 func floatBits(f float64) uint64 {
 	u := math.Float64bits(f)
-	var v uint64
-	for i := 0; i < 8; i++ {
-		v <<= 8
-		v |= u & 0xFF
-		u >>= 8
-	}
-	return v
+	return bits.ReverseBytes64(u)
 }
 
 // encFloat encodes the floating point value (float32 float64) referenced by v.
@@ -404,12 +398,12 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
 	}
 
 	ut := userType(iv.Elem().Type())
-	registerLock.RLock()
-	name, ok := concreteTypeToName[ut.base]
-	registerLock.RUnlock()
+	namei, ok := concreteTypeToName.Load(ut.base)
 	if !ok {
 		errorf("type not registered for interface: %s", ut.base)
 	}
+	name := namei.(string)
+
 	// Send the name.
 	state.encodeUint(uint64(len(name)))
 	state.b.WriteString(name)
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 9256848..a1ca252 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -55,6 +55,71 @@ func TestBasicEncoderDecoder(t *testing.T) {
 	}
 }
 
+func TestEncodeIntSlice(t *testing.T) {
+
+	s8 := []int8{1, 5, 12, 22, 35, 51, 70, 92, 117}
+	s16 := []int16{145, 176, 210, 247, 287, 330, 376, 425, 477}
+	s32 := []int32{532, 590, 651, 715, 782, 852, 925, 1001, 1080}
+	s64 := []int64{1162, 1247, 1335, 1426, 1520, 1617, 1717, 1820, 1926}
+
+	t.Run("int8", func(t *testing.T) {
+		var sink bytes.Buffer
+		enc := NewEncoder(&sink)
+		enc.Encode(s8)
+
+		dec := NewDecoder(&sink)
+		res := make([]int8, 9)
+		dec.Decode(&res)
+
+		if !reflect.DeepEqual(s8, res) {
+			t.Fatalf("EncodeIntSlice: expected %v, got %v", s8, res)
+		}
+	})
+
+	t.Run("int16", func(t *testing.T) {
+		var sink bytes.Buffer
+		enc := NewEncoder(&sink)
+		enc.Encode(s16)
+
+		dec := NewDecoder(&sink)
+		res := make([]int16, 9)
+		dec.Decode(&res)
+
+		if !reflect.DeepEqual(s16, res) {
+			t.Fatalf("EncodeIntSlice: expected %v, got %v", s16, res)
+		}
+	})
+
+	t.Run("int32", func(t *testing.T) {
+		var sink bytes.Buffer
+		enc := NewEncoder(&sink)
+		enc.Encode(s32)
+
+		dec := NewDecoder(&sink)
+		res := make([]int32, 9)
+		dec.Decode(&res)
+
+		if !reflect.DeepEqual(s32, res) {
+			t.Fatalf("EncodeIntSlice: expected %v, got %v", s32, res)
+		}
+	})
+
+	t.Run("int64", func(t *testing.T) {
+		var sink bytes.Buffer
+		enc := NewEncoder(&sink)
+		enc.Encode(s64)
+
+		dec := NewDecoder(&sink)
+		res := make([]int64, 9)
+		dec.Decode(&res)
+
+		if !reflect.DeepEqual(s64, res) {
+			t.Fatalf("EncodeIntSlice: expected %v, got %v", s64, res)
+		}
+	})
+
+}
+
 type ET0 struct {
 	A int
 	B string
diff --git a/src/encoding/gob/error.go b/src/encoding/gob/error.go
index 8b5265c..949333b 100644
--- a/src/encoding/gob/error.go
+++ b/src/encoding/gob/error.go
@@ -39,5 +39,4 @@ func catchError(err *error) {
 		}
 		*err = ge.err
 	}
-	return
 }
diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go
index ecc91ee..41a06b2 100644
--- a/src/encoding/gob/gobencdec_test.go
+++ b/src/encoding/gob/gobencdec_test.go
@@ -746,7 +746,7 @@ func (i *isZeroBugInterface) GobDecode(data []byte) error {
 }
 
 func TestGobEncodeIsZero(t *testing.T) {
-	x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
+	x := isZeroBug{time.Unix(1e9, 0), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
 	b := new(bytes.Buffer)
 	enc := NewEncoder(b)
 	err := enc.Encode(x)
diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go
index 424b7e6..3478bd2 100644
--- a/src/encoding/gob/timing_test.go
+++ b/src/encoding/gob/timing_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"io"
 	"os"
+	"reflect"
 	"runtime"
 	"testing"
 )
@@ -132,89 +133,60 @@ func TestCountDecodeMallocs(t *testing.T) {
 	}
 }
 
+func benchmarkEncodeSlice(b *testing.B, a interface{}) {
+	b.ResetTimer()
+	b.RunParallel(func(pb *testing.PB) {
+		var buf bytes.Buffer
+		enc := NewEncoder(&buf)
+
+		for pb.Next() {
+			buf.Reset()
+			err := enc.Encode(a)
+			if err != nil {
+				b.Fatal(err)
+			}
+		}
+	})
+}
+
 func BenchmarkEncodeComplex128Slice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]complex128, 1000)
 	for i := range a {
 		a[i] = 1.2 + 3.4i
 	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		err := enc.Encode(a)
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
+	benchmarkEncodeSlice(b, a)
 }
 
 func BenchmarkEncodeFloat64Slice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]float64, 1000)
 	for i := range a {
 		a[i] = 1.23e4
 	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		err := enc.Encode(a)
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
+	benchmarkEncodeSlice(b, a)
 }
 
 func BenchmarkEncodeInt32Slice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]int32, 1000)
 	for i := range a {
-		a[i] = 1234
-	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		err := enc.Encode(a)
-		if err != nil {
-			b.Fatal(err)
-		}
+		a[i] = int32(i * 100)
 	}
+	benchmarkEncodeSlice(b, a)
 }
 
 func BenchmarkEncodeStringSlice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]string, 1000)
 	for i := range a {
 		a[i] = "now is the time"
 	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		err := enc.Encode(a)
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
+	benchmarkEncodeSlice(b, a)
 }
 
 func BenchmarkEncodeInterfaceSlice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]interface{}, 1000)
 	for i := range a {
 		a[i] = "now is the time"
 	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		err := enc.Encode(a)
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
+	benchmarkEncodeSlice(b, a)
 }
 
 // benchmarkBuf is a read buffer we can reset
@@ -245,120 +217,96 @@ func (b *benchmarkBuf) reset() {
 	b.offset = 0
 }
 
-func BenchmarkDecodeComplex128Slice(b *testing.B) {
+func benchmarkDecodeSlice(b *testing.B, a interface{}) {
 	var buf bytes.Buffer
 	enc := NewEncoder(&buf)
-	a := make([]complex128, 1000)
-	for i := range a {
-		a[i] = 1.2 + 3.4i
-	}
 	err := enc.Encode(a)
 	if err != nil {
 		b.Fatal(err)
 	}
-	x := make([]complex128, 1000)
-	bbuf := benchmarkBuf{data: buf.Bytes()}
+
+	ra := reflect.ValueOf(a)
+	rt := ra.Type()
 	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		bbuf.reset()
-		dec := NewDecoder(&bbuf)
-		err := dec.Decode(&x)
-		if err != nil {
-			b.Fatal(i, err)
+
+	b.RunParallel(func(pb *testing.PB) {
+		// TODO(#19025): Move per-thread allocation before ResetTimer.
+		rp := reflect.New(rt)
+		rp.Elem().Set(reflect.MakeSlice(rt, ra.Len(), ra.Cap()))
+		p := rp.Interface()
+
+		bbuf := benchmarkBuf{data: buf.Bytes()}
+
+		for pb.Next() {
+			bbuf.reset()
+			dec := NewDecoder(&bbuf)
+			err := dec.Decode(p)
+			if err != nil {
+				b.Fatal(err)
+			}
 		}
+	})
+}
+
+func BenchmarkDecodeComplex128Slice(b *testing.B) {
+	a := make([]complex128, 1000)
+	for i := range a {
+		a[i] = 1.2 + 3.4i
 	}
+	benchmarkDecodeSlice(b, a)
 }
 
 func BenchmarkDecodeFloat64Slice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]float64, 1000)
 	for i := range a {
 		a[i] = 1.23e4
 	}
-	err := enc.Encode(a)
-	if err != nil {
-		b.Fatal(err)
-	}
-	x := make([]float64, 1000)
-	bbuf := benchmarkBuf{data: buf.Bytes()}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		bbuf.reset()
-		dec := NewDecoder(&bbuf)
-		err := dec.Decode(&x)
-		if err != nil {
-			b.Fatal(i, err)
-		}
-	}
+	benchmarkDecodeSlice(b, a)
 }
 
 func BenchmarkDecodeInt32Slice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]int32, 1000)
 	for i := range a {
 		a[i] = 1234
 	}
-	err := enc.Encode(a)
-	if err != nil {
-		b.Fatal(err)
-	}
-	x := make([]int32, 1000)
-	bbuf := benchmarkBuf{data: buf.Bytes()}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		bbuf.reset()
-		dec := NewDecoder(&bbuf)
-		err := dec.Decode(&x)
-		if err != nil {
-			b.Fatal(i, err)
-		}
-	}
+	benchmarkDecodeSlice(b, a)
 }
 
 func BenchmarkDecodeStringSlice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]string, 1000)
 	for i := range a {
 		a[i] = "now is the time"
 	}
-	err := enc.Encode(a)
-	if err != nil {
-		b.Fatal(err)
-	}
-	x := make([]string, 1000)
-	bbuf := benchmarkBuf{data: buf.Bytes()}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		bbuf.reset()
-		dec := NewDecoder(&bbuf)
-		err := dec.Decode(&x)
-		if err != nil {
-			b.Fatal(i, err)
-		}
-	}
+	benchmarkDecodeSlice(b, a)
 }
 
 func BenchmarkDecodeInterfaceSlice(b *testing.B) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
 	a := make([]interface{}, 1000)
 	for i := range a {
 		a[i] = "now is the time"
 	}
-	err := enc.Encode(a)
+	benchmarkDecodeSlice(b, a)
+}
+
+func BenchmarkDecodeMap(b *testing.B) {
+	count := 1000
+	m := make(map[int]int, count)
+	for i := 0; i < count; i++ {
+		m[i] = i
+	}
+	var buf bytes.Buffer
+	enc := NewEncoder(&buf)
+	err := enc.Encode(m)
 	if err != nil {
 		b.Fatal(err)
 	}
-	x := make([]interface{}, 1000)
 	bbuf := benchmarkBuf{data: buf.Bytes()}
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
+		var rm map[int]int
 		bbuf.reset()
 		dec := NewDecoder(&bbuf)
-		err := dec.Decode(&x)
+		err := dec.Decode(&rm)
 		if err != nil {
 			b.Fatal(i, err)
 		}
diff --git a/src/encoding/gob/type.go b/src/encoding/gob/type.go
index c27f7e9..31c0ef7 100644
--- a/src/encoding/gob/type.go
+++ b/src/encoding/gob/type.go
@@ -36,31 +36,21 @@ const (
 	xText              // encoding.TextMarshaler or encoding.TextUnmarshaler
 )
 
-var (
-	// Protected by an RWMutex because we read it a lot and write
-	// it only when we see a new type, typically when compiling.
-	userTypeLock  sync.RWMutex
-	userTypeCache = make(map[reflect.Type]*userTypeInfo)
-)
+var userTypeCache sync.Map // map[reflect.Type]*userTypeInfo
 
 // 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
 // is not set up.
-func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
-	userTypeLock.RLock()
-	ut = userTypeCache[rt]
-	userTypeLock.RUnlock()
-	if ut != nil {
-		return
-	}
-	// Now set the value under the write lock.
-	userTypeLock.Lock()
-	defer userTypeLock.Unlock()
-	if ut = userTypeCache[rt]; ut != nil {
-		// Lost the race; not a problem.
-		return
+func validUserType(rt reflect.Type) (*userTypeInfo, error) {
+	if ui, ok := userTypeCache.Load(rt); ok {
+		return ui.(*userTypeInfo), nil
 	}
-	ut = new(userTypeInfo)
+
+	// Construct a new userTypeInfo and atomically add it to the userTypeCache.
+	// If we lose the race, we'll waste a little CPU and create a little garbage
+	// but return the existing value anyway.
+
+	ut := new(userTypeInfo)
 	ut.base = rt
 	ut.user = rt
 	// A type that is just a cycle of pointers (such as type T *T) cannot
@@ -108,8 +98,8 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
 	// 	ut.externalDec, ut.decIndir = xText, indir
 	// }
 
-	userTypeCache[rt] = ut
-	return
+	ui, _ := userTypeCache.LoadOrStore(rt, ut)
+	return ui.(*userTypeInfo), nil
 }
 
 var (
@@ -808,9 +798,8 @@ type GobDecoder interface {
 }
 
 var (
-	registerLock       sync.RWMutex
-	nameToConcreteType = make(map[string]reflect.Type)
-	concreteTypeToName = make(map[reflect.Type]string)
+	nameToConcreteType sync.Map // map[string]reflect.Type
+	concreteTypeToName sync.Map // map[reflect.Type]string
 )
 
 // RegisterName is like Register but uses the provided name rather than the
@@ -820,21 +809,22 @@ func RegisterName(name string, value interface{}) {
 		// reserved for nil
 		panic("attempt to register empty name")
 	}
-	registerLock.Lock()
-	defer registerLock.Unlock()
+
 	ut := userType(reflect.TypeOf(value))
+
 	// Check for incompatible duplicates. The name must refer to the
 	// same user type, and vice versa.
-	if t, ok := nameToConcreteType[name]; ok && t != ut.user {
+
+	// Store the name and type provided by the user....
+	if t, dup := nameToConcreteType.LoadOrStore(name, reflect.TypeOf(value)); dup && t != ut.user {
 		panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", name, t, ut.user))
 	}
-	if n, ok := concreteTypeToName[ut.base]; ok && n != name {
+
+	// but the flattened type in the type table, since that's what decode needs.
+	if n, dup := concreteTypeToName.LoadOrStore(ut.base, name); dup && n != name {
+		nameToConcreteType.Delete(name)
 		panic(fmt.Sprintf("gob: registering duplicate names for %s: %q != %q", ut.user, n, name))
 	}
-	// Store the name and type provided by the user....
-	nameToConcreteType[name] = reflect.TypeOf(value)
-	// but the flattened type in the type table, since that's what decode needs.
-	concreteTypeToName[ut.base] = name
 }
 
 // Register records a type, identified by a value for that type, under its
diff --git a/src/encoding/gob/type_test.go b/src/encoding/gob/type_test.go
index e230d22..14f25d8 100644
--- a/src/encoding/gob/type_test.go
+++ b/src/encoding/gob/type_test.go
@@ -178,9 +178,7 @@ func TestRegistrationNaming(t *testing.T) {
 		Register(tc.t)
 
 		tct := reflect.TypeOf(tc.t)
-		registerLock.RLock()
-		ct := nameToConcreteType[tc.name]
-		registerLock.RUnlock()
+		ct, _ := nameToConcreteType.Load(tc.name)
 		if ct != tct {
 			t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
 		}
@@ -188,7 +186,7 @@ func TestRegistrationNaming(t *testing.T) {
 		if tct.Kind() == reflect.Ptr {
 			tct = tct.Elem()
 		}
-		if n := concreteTypeToName[tct]; n != tc.name {
+		if n, _ := concreteTypeToName.Load(tct); n != tc.name {
 			t.Errorf("concreteTypeToName[%v] got %v, want %v", tct, n, tc.name)
 		}
 	}
diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go
index b43c1c4..2768f1b 100644
--- a/src/encoding/hex/hex.go
+++ b/src/encoding/hex/hex.go
@@ -12,10 +12,7 @@ import (
 	"io"
 )
 
-var hextable = [16]byte{
-	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-	'a', 'b', 'c', 'd', 'e', 'f',
-}
+const hextable = "0123456789abcdef"
 
 // EncodedLen returns the length of an encoding of n source bytes.
 // Specifically, it returns n * 2.
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go
index cd7380b..85d7ae0 100644
--- a/src/encoding/json/bench_test.go
+++ b/src/encoding/json/bench_test.go
@@ -82,12 +82,14 @@ func BenchmarkCodeEncoder(b *testing.B) {
 		codeInit()
 		b.StartTimer()
 	}
-	enc := NewEncoder(ioutil.Discard)
-	for i := 0; i < b.N; i++ {
-		if err := enc.Encode(&codeStruct); err != nil {
-			b.Fatal("Encode:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		enc := NewEncoder(ioutil.Discard)
+		for pb.Next() {
+			if err := enc.Encode(&codeStruct); err != nil {
+				b.Fatal("Encode:", err)
+			}
 		}
-	}
+	})
 	b.SetBytes(int64(len(codeJSON)))
 }
 
@@ -97,11 +99,13 @@ func BenchmarkCodeMarshal(b *testing.B) {
 		codeInit()
 		b.StartTimer()
 	}
-	for i := 0; i < b.N; i++ {
-		if _, err := Marshal(&codeStruct); err != nil {
-			b.Fatal("Marshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			if _, err := Marshal(&codeStruct); err != nil {
+				b.Fatal("Marshal:", err)
+			}
 		}
-	}
+	})
 	b.SetBytes(int64(len(codeJSON)))
 }
 
@@ -111,19 +115,21 @@ func BenchmarkCodeDecoder(b *testing.B) {
 		codeInit()
 		b.StartTimer()
 	}
-	var buf bytes.Buffer
-	dec := NewDecoder(&buf)
-	var r codeResponse
-	for i := 0; i < b.N; i++ {
-		buf.Write(codeJSON)
-		// hide EOF
-		buf.WriteByte('\n')
-		buf.WriteByte('\n')
-		buf.WriteByte('\n')
-		if err := dec.Decode(&r); err != nil {
-			b.Fatal("Decode:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		var buf bytes.Buffer
+		dec := NewDecoder(&buf)
+		var r codeResponse
+		for pb.Next() {
+			buf.Write(codeJSON)
+			// hide EOF
+			buf.WriteByte('\n')
+			buf.WriteByte('\n')
+			buf.WriteByte('\n')
+			if err := dec.Decode(&r); err != nil {
+				b.Fatal("Decode:", err)
+			}
 		}
-	}
+	})
 	b.SetBytes(int64(len(codeJSON)))
 }
 
@@ -155,12 +161,14 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
 		codeInit()
 		b.StartTimer()
 	}
-	for i := 0; i < b.N; i++ {
-		var r codeResponse
-		if err := Unmarshal(codeJSON, &r); err != nil {
-			b.Fatal("Unmarshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			var r codeResponse
+			if err := Unmarshal(codeJSON, &r); err != nil {
+				b.Fatal("Unmarshal:", err)
+			}
 		}
-	}
+	})
 	b.SetBytes(int64(len(codeJSON)))
 }
 
@@ -170,54 +178,75 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
 		codeInit()
 		b.StartTimer()
 	}
-	var r codeResponse
-	for i := 0; i < b.N; i++ {
-		if err := Unmarshal(codeJSON, &r); err != nil {
-			b.Fatal("Unmarshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		var r codeResponse
+		for pb.Next() {
+			if err := Unmarshal(codeJSON, &r); err != nil {
+				b.Fatal("Unmarshal:", err)
+			}
 		}
-	}
+	})
+	// TODO(bcmills): Is there a missing b.SetBytes here?
 }
 
 func BenchmarkUnmarshalString(b *testing.B) {
 	data := []byte(`"hello, world"`)
-	var s string
-
-	for i := 0; i < b.N; i++ {
-		if err := Unmarshal(data, &s); err != nil {
-			b.Fatal("Unmarshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		var s string
+		for pb.Next() {
+			if err := Unmarshal(data, &s); err != nil {
+				b.Fatal("Unmarshal:", err)
+			}
 		}
-	}
+	})
 }
 
 func BenchmarkUnmarshalFloat64(b *testing.B) {
-	var f float64
 	data := []byte(`3.14`)
-
-	for i := 0; i < b.N; i++ {
-		if err := Unmarshal(data, &f); err != nil {
-			b.Fatal("Unmarshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		var f float64
+		for pb.Next() {
+			if err := Unmarshal(data, &f); err != nil {
+				b.Fatal("Unmarshal:", err)
+			}
 		}
-	}
+	})
 }
 
 func BenchmarkUnmarshalInt64(b *testing.B) {
-	var x int64
 	data := []byte(`3`)
-
-	for i := 0; i < b.N; i++ {
-		if err := Unmarshal(data, &x); err != nil {
-			b.Fatal("Unmarshal:", err)
+	b.RunParallel(func(pb *testing.PB) {
+		var x int64
+		for pb.Next() {
+			if err := Unmarshal(data, &x); err != nil {
+				b.Fatal("Unmarshal:", err)
+			}
 		}
-	}
+	})
 }
 
 func BenchmarkIssue10335(b *testing.B) {
 	b.ReportAllocs()
-	var s struct{}
 	j := []byte(`{"a":{ }}`)
-	for n := 0; n < b.N; n++ {
-		if err := Unmarshal(j, &s); err != nil {
-			b.Fatal(err)
+	b.RunParallel(func(pb *testing.PB) {
+		var s struct{}
+		for pb.Next() {
+			if err := Unmarshal(j, &s); err != nil {
+				b.Fatal(err)
+			}
 		}
-	}
+	})
+}
+
+func BenchmarkUnmapped(b *testing.B) {
+	b.ReportAllocs()
+	j := []byte(`{"s": "hello", "y": 2, "o": {"x": 0}, "a": [1, 99, {"x": 1}]}`)
+	b.RunParallel(func(pb *testing.PB) {
+		var s struct{}
+		for pb.Next() {
+			if err := Unmarshal(j, &s); err != nil {
+				b.Fatal(err)
+			}
+		}
+	})
 }
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 77fc460..710c835 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -22,7 +22,8 @@ import (
 )
 
 // Unmarshal parses the JSON-encoded data and stores the result
-// in the value pointed to by v.
+// in the value pointed to by v. If v is nil or not a pointer,
+// Unmarshal returns an InvalidUnmarshalError.
 //
 // Unmarshal uses the inverse of the encodings that
 // Marshal uses, allocating maps, slices, and pointers as necessary,
@@ -78,7 +79,9 @@ import (
 // or if a JSON number overflows the target type, Unmarshal
 // skips that field and completes the unmarshaling as best it can.
 // If no more serious errors are encountered, Unmarshal returns
-// an UnmarshalTypeError describing the earliest such error.
+// an UnmarshalTypeError describing the earliest such error. In any
+// case, it's not guaranteed that all the remaining fields following
+// the problematic one will be unmarshaled into the target object.
 //
 // The JSON null value unmarshals into an interface, map, pointer, or slice
 // by setting that Go value to nil. Because null is often used in JSON to mean
@@ -358,47 +361,40 @@ func (d *decodeState) scanWhile(op int) int {
 	return newOp
 }
 
+// discardObject and discardArray are dummy data targets
+// used by the (*decodeState).value method, which
+// accepts a zero reflect.Value to discard a value.
+// The (*decodeState).object and (*decodeState).array methods,
+// however, require a valid reflect.Value destination.
+// These are the target values used when the caller of value
+// wants to skip a field.
+//
+// Because these values refer to zero-sized objects
+// and thus can't be mutated, they're safe for concurrent use
+// by different goroutines unmarshalling skipped fields.
+var (
+	discardObject = reflect.ValueOf(struct{}{})
+	discardArray  = reflect.ValueOf([0]interface{}{})
+)
+
 // value decodes a JSON value from d.data[d.off:] into the value.
-// it updates d.off to point past the decoded value.
+// It updates d.off to point past the decoded value. If v is
+// invalid, the JSON value is discarded.
 func (d *decodeState) value(v reflect.Value) {
-	if !v.IsValid() {
-		_, rest, err := nextValue(d.data[d.off:], &d.nextscan)
-		if err != nil {
-			d.error(err)
-		}
-		d.off = len(d.data) - len(rest)
-
-		// d.scan thinks we're still at the beginning of the item.
-		// Feed in an empty string - the shortest, simplest value -
-		// so that it knows we got to the end of the value.
-		if d.scan.redo {
-			// rewind.
-			d.scan.redo = false
-			d.scan.step = stateBeginValue
-		}
-		d.scan.step(&d.scan, '"')
-		d.scan.step(&d.scan, '"')
-
-		n := len(d.scan.parseState)
-		if n > 0 && d.scan.parseState[n-1] == parseObjectKey {
-			// d.scan thinks we just read an object key; finish the object
-			d.scan.step(&d.scan, ':')
-			d.scan.step(&d.scan, '"')
-			d.scan.step(&d.scan, '"')
-			d.scan.step(&d.scan, '}')
-		}
-
-		return
-	}
-
 	switch op := d.scanWhile(scanSkipSpace); op {
 	default:
 		d.error(errPhase)
 
 	case scanBeginArray:
+		if !v.IsValid() {
+			v = discardArray
+		}
 		d.array(v)
 
 	case scanBeginObject:
+		if !v.IsValid() {
+			v = discardObject
+		}
 		d.object(v)
 
 	case scanBeginLiteral:
@@ -516,8 +512,7 @@ func (d *decodeState) array(v reflect.Value) {
 		d.off--
 		d.next()
 		return
-	case reflect.Array:
-	case reflect.Slice:
+	case reflect.Array, reflect.Slice:
 		break
 	}
 
@@ -796,7 +791,9 @@ func (d *decodeState) literal(v reflect.Value) {
 	d.off--
 	d.scan.undo(op)
 
-	d.literalStore(d.data[start:d.off], v, false)
+	if v.IsValid() {
+		d.literalStore(d.data[start:d.off], v, false)
+	}
 }
 
 // convertNumber converts the number literal s to a float64 or a Number
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 8f21dda..6fcea47 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -332,10 +332,7 @@ type encOpts struct {
 
 type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
 
-var encoderCache struct {
-	sync.RWMutex
-	m map[reflect.Type]encoderFunc
-}
+var encoderCache sync.Map // map[reflect.Type]encoderFunc
 
 func valueEncoder(v reflect.Value) encoderFunc {
 	if !v.IsValid() {
@@ -345,36 +342,31 @@ func valueEncoder(v reflect.Value) encoderFunc {
 }
 
 func typeEncoder(t reflect.Type) encoderFunc {
-	encoderCache.RLock()
-	f := encoderCache.m[t]
-	encoderCache.RUnlock()
-	if f != nil {
-		return f
+	if fi, ok := encoderCache.Load(t); ok {
+		return fi.(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
 	// func is only used for recursive types.
-	encoderCache.Lock()
-	if encoderCache.m == nil {
-		encoderCache.m = make(map[reflect.Type]encoderFunc)
-	}
-	var wg sync.WaitGroup
+	var (
+		wg sync.WaitGroup
+		f  encoderFunc
+	)
 	wg.Add(1)
-	encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) {
+	fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) {
 		wg.Wait()
 		f(e, v, opts)
+	}))
+	if loaded {
+		return fi.(encoderFunc)
 	}
-	encoderCache.Unlock()
 
-	// Compute fields without lock.
-	// Might duplicate effort but won't hold other computations back.
+	// Compute the real encoder and replace the indirect func with it.
 	f = newTypeEncoder(t, true)
 	wg.Done()
-	encoderCache.Lock()
-	encoderCache.m[t] = f
-	encoderCache.Unlock()
+	encoderCache.Store(t, f)
 	return f
 }
 
@@ -1101,7 +1093,7 @@ func typeFields(t reflect.Type) []field {
 			// Scan f.typ for fields to include.
 			for i := 0; i < f.typ.NumField(); i++ {
 				sf := f.typ.Field(i)
-				if sf.PkgPath != "" && !sf.Anonymous { // unexported
+				if sf.PkgPath != "" && (!sf.Anonymous || sf.Type.Kind() != reflect.Struct) { // unexported
 					continue
 				}
 				tag := sf.Tag.Get("json")
diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go
index 6d574cf..d5f5f0a 100644
--- a/src/encoding/json/encode_test.go
+++ b/src/encoding/json/encode_test.go
@@ -273,6 +273,59 @@ func TestAnonymousNonstruct(t *testing.T) {
 	}
 }
 
+type unexportedIntType int
+
+type MyStructWithUnexportedIntType struct {
+	unexportedIntType
+}
+
+func TestAnonymousNonstructWithUnexportedType(t *testing.T) {
+	a := MyStructWithUnexportedIntType{11}
+	const want = `{}`
+
+	b, err := Marshal(a)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+type MyStructContainingUnexportedStruct struct {
+	unexportedStructType1
+	unexportedIntType
+}
+
+type unexportedStructType1 struct {
+	ExportedIntType1
+	unexportedIntType
+	unexportedStructType2
+}
+
+type unexportedStructType2 struct {
+	ExportedIntType2
+	unexportedIntType
+}
+
+type ExportedIntType1 int
+type ExportedIntType2 int
+
+func TestUnexportedAnonymousStructWithExportedType(t *testing.T) {
+	s2 := unexportedStructType2{3, 4}
+	s1 := unexportedStructType1{1, 2, s2}
+	a := MyStructContainingUnexportedStruct{s1, 6}
+	const want = `{"ExportedIntType1":1,"ExportedIntType2":3}`
+
+	b, err := Marshal(a)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
 type BugA struct {
 	S string
 }
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index a6d8706..ae34418 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -15,6 +15,11 @@ package json
 
 import "strconv"
 
+// Valid reports whether data is a valid JSON encoding.
+func Valid(data []byte) bool {
+	return checkValid(data, &scanner{}) == nil
+}
+
 // checkValid verifies that data is valid JSON-encoded data.
 // scan is passed in for use by checkValid to avoid an allocation.
 func checkValid(data []byte, scan *scanner) error {
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index c5c1be3..0d4518a 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -12,6 +12,26 @@ import (
 	"testing"
 )
 
+var validTests = []struct {
+	data string
+	ok   bool
+}{
+	{`foo`, false},
+	{`}{`, false},
+	{`{]`, false},
+	{`{}`, true},
+	{`{"foo":"bar"}`, true},
+	{`{"foo":"bar","bar":{"baz":["qux"]}}`, true},
+}
+
+func TestValid(t *testing.T) {
+	for _, tt := range validTests {
+		if ok := Valid([]byte(tt.data)); ok != tt.ok {
+			t.Errorf("Valid(%#q) = %v, want %v", tt.data, ok, tt.ok)
+		}
+	}
+}
+
 // Tests of simple examples.
 
 type example struct {
diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go
index 84edeb1..d0b3ffb 100644
--- a/src/encoding/json/stream_test.go
+++ b/src/encoding/json/stream_test.go
@@ -268,11 +268,13 @@ func BenchmarkEncoderEncode(b *testing.B) {
 		X, Y string
 	}
 	v := &T{"foo", "bar"}
-	for i := 0; i < b.N; i++ {
-		if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
-			b.Fatal(err)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
+				b.Fatal(err)
+			}
 		}
-	}
+	})
 }
 
 type tokenStreamCase struct {
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
index fbf4999..5e1ab90 100644
--- a/src/encoding/pem/pem.go
+++ b/src/encoding/pem/pem.go
@@ -135,20 +135,26 @@ func Decode(data []byte) (p *Block, rest []byte) {
 		return decodeError(data, rest)
 	}
 
-	// After the "-----" of the ending line should be the same type and a
-	// final five dashes.
+	// After the "-----" of the ending line, there should be the same type
+	// and then a final five dashes.
 	endTrailer := rest[endTrailerIndex:]
 	endTrailerLen := len(typeLine) + len(pemEndOfLine)
 	if len(endTrailer) < endTrailerLen {
 		return decodeError(data, rest)
 	}
 
+	restOfEndLine := endTrailer[endTrailerLen:]
 	endTrailer = endTrailer[:endTrailerLen]
 	if !bytes.HasPrefix(endTrailer, typeLine) ||
 		!bytes.HasSuffix(endTrailer, pemEndOfLine) {
 		return decodeError(data, rest)
 	}
 
+	// The line must end with only whitespace.
+	if s, _ := getLine(restOfEndLine); len(s) != 0 {
+		return decodeError(data, rest)
+	}
+
 	base64Data := removeWhitespace(rest[:endIndex])
 	p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
 	n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go
index 6321dec..1a1250a 100644
--- a/src/encoding/pem/pem_test.go
+++ b/src/encoding/pem/pem_test.go
@@ -83,6 +83,16 @@ const pemTooFewEndingDashes = `
 dGVzdA==
 -----END FOO----`
 
+const pemTooManyEndingDashes = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END FOO------`
+
+const pemTrailingNonWhitespace = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END FOO----- .`
+
 const pemWrongEndingType = `
 -----BEGIN FOO-----
 dGVzdA==
@@ -102,6 +112,14 @@ var badPEMTests = []struct {
 		pemTooFewEndingDashes,
 	},
 	{
+		"too many trailing dashes",
+		pemTooManyEndingDashes,
+	},
+	{
+		"trailing non-whitespace",
+		pemTrailingNonWhitespace,
+	},
+	{
 		"incorrect ending type",
 		pemWrongEndingType,
 	},
@@ -188,10 +206,20 @@ func TestLineBreaker(t *testing.T) {
 }
 
 func TestFuzz(t *testing.T) {
+	// PEM is a text-based format. Assume header fields with leading/trailing spaces
+	// or embedded newlines will not round trip correctly and don't need to be tested.
+	isBad := func(s string) bool {
+		return strings.ContainsAny(s, "\r\n") || strings.TrimSpace(s) != s
+	}
+
 	testRoundtrip := func(block Block) bool {
-		for key := range block.Headers {
-			if strings.Contains(key, ":") {
-				// Keys with colons cannot be encoded.
+		if isBad(block.Type) {
+			return true
+		}
+		for key, val := range block.Headers {
+			// Reject bad key/val.
+			// Also, keys with colons cannot be encoded, because : is the key: val separator.
+			if isBad(key) || isBad(val) || strings.Contains(key, ":") {
 				return true
 			}
 		}
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 0126146..674c6b5 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -1652,28 +1652,31 @@ func TestMarshal(t *testing.T) {
 		if test.UnmarshalOnly {
 			continue
 		}
-		data, err := Marshal(test.Value)
-		if err != nil {
-			if test.MarshalError == "" {
-				t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
-				continue
+
+		t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
+			data, err := Marshal(test.Value)
+			if err != nil {
+				if test.MarshalError == "" {
+					t.Errorf("marshal(%#v): %s", test.Value, err)
+					return
+				}
+				if !strings.Contains(err.Error(), test.MarshalError) {
+					t.Errorf("marshal(%#v): %s, want %q", test.Value, err, test.MarshalError)
+				}
+				return
 			}
-			if !strings.Contains(err.Error(), test.MarshalError) {
-				t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError)
+			if test.MarshalError != "" {
+				t.Errorf("Marshal succeeded, want error %q", test.MarshalError)
+				return
 			}
-			continue
-		}
-		if test.MarshalError != "" {
-			t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError)
-			continue
-		}
-		if got, want := string(data), test.ExpectXML; got != want {
-			if strings.Contains(want, "\n") {
-				t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
-			} else {
-				t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
+			if got, want := string(data), test.ExpectXML; got != want {
+				if strings.Contains(want, "\n") {
+					t.Errorf("marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", test.Value, got, want)
+				} else {
+					t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", test.Value, got, want)
+				}
 			}
-		}
+		})
 	}
 }
 
@@ -1781,27 +1784,29 @@ func TestUnmarshal(t *testing.T) {
 		dest := reflect.New(vt.Elem()).Interface()
 		err := Unmarshal([]byte(test.ExpectXML), dest)
 
-		switch fix := dest.(type) {
-		case *Feed:
-			fix.Author.InnerXML = ""
-			for i := range fix.Entry {
-				fix.Entry[i].Author.InnerXML = ""
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			switch fix := dest.(type) {
+			case *Feed:
+				fix.Author.InnerXML = ""
+				for i := range fix.Entry {
+					fix.Entry[i].Author.InnerXML = ""
+				}
 			}
-		}
 
-		if err != nil {
-			if test.UnmarshalError == "" {
-				t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err)
-				continue
+			if err != nil {
+				if test.UnmarshalError == "" {
+					t.Errorf("unmarshal(%#v): %s", test.ExpectXML, err)
+					return
+				}
+				if !strings.Contains(err.Error(), test.UnmarshalError) {
+					t.Errorf("unmarshal(%#v): %s, want %q", test.ExpectXML, err, test.UnmarshalError)
+				}
+				return
 			}
-			if !strings.Contains(err.Error(), test.UnmarshalError) {
-				t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError)
+			if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+				t.Errorf("unmarshal(%q):\nhave %#v\nwant %#v", test.ExpectXML, got, want)
 			}
-			continue
-		}
-		if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
-			t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
-		}
+		})
 	}
 }
 
@@ -1896,17 +1901,21 @@ func TestMarshalFlush(t *testing.T) {
 
 func BenchmarkMarshal(b *testing.B) {
 	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		Marshal(atomValue)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Marshal(atomValue)
+		}
+	})
 }
 
 func BenchmarkUnmarshal(b *testing.B) {
 	b.ReportAllocs()
 	xml := []byte(atomXml)
-	for i := 0; i < b.N; i++ {
-		Unmarshal(xml, &Feed{})
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Unmarshal(xml, &Feed{})
+		}
+	})
 }
 
 // golang.org/issue/6556
@@ -2428,10 +2437,7 @@ func TestIssue16158(t *testing.T) {
 	err := Unmarshal([]byte(data), &struct {
 		B byte `xml:"b,attr,omitempty"`
 	}{})
-
-	// For Go 1.8.1 we've restored the old "no errors reported" behavior.
-	// We'll try again in Go 1.9 to report errors.
-	if err != nil {
-		t.Errorf("Unmarshal: expected nil, got error")
+	if err == nil {
+		t.Errorf("Unmarshal: expected error, got nil")
 	}
 }
diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go
index 799b57e..000d9fb 100644
--- a/src/encoding/xml/read.go
+++ b/src/encoding/xml/read.go
@@ -120,6 +120,9 @@ import (
 // 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.
 //
+// A missing element or empty attribute value will be unmarshaled as a zero value.
+// If the field is a slice, a zero value will be appended to the field. Otherwise, the
+// field will be set to its zero value.
 func Unmarshal(data []byte, v interface{}) error {
 	return NewDecoder(bytes.NewReader(data)).Decode(v)
 }
@@ -211,7 +214,7 @@ func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error
 // unmarshalTextInterface unmarshals a single XML element into val.
 // The chardata contained in the element (but not its children)
 // is passed to the text unmarshaler.
-func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *StartElement) error {
+func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
 	var buf []byte
 	depth := 1
 	for depth > 0 {
@@ -285,8 +288,7 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
 		return nil
 	}
 
-	copyValue(val, []byte(attr.Value))
-	return nil
+	return copyValue(val, []byte(attr.Value))
 }
 
 var (
@@ -342,13 +344,13 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
 	}
 
 	if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
-		return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler), start)
+		return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
 	}
 
 	if val.CanAddr() {
 		pv := val.Addr()
 		if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
-			return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler), start)
+			return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
 		}
 	}
 
@@ -608,24 +610,40 @@ func copyValue(dst reflect.Value, src []byte) (err error) {
 	default:
 		return errors.New("cannot unmarshal into " + dst0.Type().String())
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if len(src) == 0 {
+			dst.SetInt(0)
+			return nil
+		}
 		itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits())
 		if err != nil {
 			return err
 		}
 		dst.SetInt(itmp)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		if len(src) == 0 {
+			dst.SetUint(0)
+			return nil
+		}
 		utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits())
 		if err != nil {
 			return err
 		}
 		dst.SetUint(utmp)
 	case reflect.Float32, reflect.Float64:
+		if len(src) == 0 {
+			dst.SetFloat(0)
+			return nil
+		}
 		ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits())
 		if err != nil {
 			return err
 		}
 		dst.SetFloat(ftmp)
 	case reflect.Bool:
+		if len(src) == 0 {
+			dst.SetBool(false)
+			return nil
+		}
 		value, err := strconv.ParseBool(strings.TrimSpace(string(src)))
 		if err != nil {
 			return err
diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go
index 273c303..a1eb516 100644
--- a/src/encoding/xml/read_test.go
+++ b/src/encoding/xml/read_test.go
@@ -752,3 +752,159 @@ func TestInvalidInnerXMLType(t *testing.T) {
 		t.Errorf("NotInnerXML = %v, want nil", v.NotInnerXML)
 	}
 }
+
+type Child struct {
+	G struct {
+		I int
+	}
+}
+
+type ChildToEmbed struct {
+	X bool
+}
+
+type Parent struct {
+	I        int
+	IPtr     *int
+	Is       []int
+	IPtrs    []*int
+	F        float32
+	FPtr     *float32
+	Fs       []float32
+	FPtrs    []*float32
+	B        bool
+	BPtr     *bool
+	Bs       []bool
+	BPtrs    []*bool
+	Bytes    []byte
+	BytesPtr *[]byte
+	S        string
+	SPtr     *string
+	Ss       []string
+	SPtrs    []*string
+	MyI      MyInt
+	Child    Child
+	Children []Child
+	ChildPtr *Child
+	ChildToEmbed
+}
+
+const (
+	emptyXML = `
+<Parent>
+    <I></I>
+    <IPtr></IPtr>
+    <Is></Is>
+    <IPtrs></IPtrs>
+    <F></F>
+    <FPtr></FPtr>
+    <Fs></Fs>
+    <FPtrs></FPtrs>
+    <B></B>
+    <BPtr></BPtr>
+    <Bs></Bs>
+    <BPtrs></BPtrs>
+    <Bytes></Bytes>
+    <BytesPtr></BytesPtr>
+    <S></S>
+    <SPtr></SPtr>
+    <Ss></Ss>
+    <SPtrs></SPtrs>
+    <MyI></MyI>
+    <Child></Child>
+    <Children></Children>
+    <ChildPtr></ChildPtr>
+    <X></X>
+</Parent>
+`
+)
+
+// github.com/golang/go/issues/13417
+func TestUnmarshalEmptyValues(t *testing.T) {
+	// Test first with a zero-valued dst.
+	v := new(Parent)
+	if err := Unmarshal([]byte(emptyXML), v); err != nil {
+		t.Fatalf("zero: Unmarshal failed: got %v", err)
+	}
+
+	zBytes, zInt, zStr, zFloat, zBool := []byte{}, 0, "", float32(0), false
+	want := &Parent{
+		IPtr:         &zInt,
+		Is:           []int{zInt},
+		IPtrs:        []*int{&zInt},
+		FPtr:         &zFloat,
+		Fs:           []float32{zFloat},
+		FPtrs:        []*float32{&zFloat},
+		BPtr:         &zBool,
+		Bs:           []bool{zBool},
+		BPtrs:        []*bool{&zBool},
+		Bytes:        []byte{},
+		BytesPtr:     &zBytes,
+		SPtr:         &zStr,
+		Ss:           []string{zStr},
+		SPtrs:        []*string{&zStr},
+		Children:     []Child{{}},
+		ChildPtr:     new(Child),
+		ChildToEmbed: ChildToEmbed{},
+	}
+	if !reflect.DeepEqual(v, want) {
+		t.Fatalf("zero: Unmarshal:\nhave:  %#+v\nwant: %#+v", v, want)
+	}
+
+	// Test with a pre-populated dst.
+	// Multiple addressable copies, as pointer-to fields will replace value during unmarshal.
+	vBytes0, vInt0, vStr0, vFloat0, vBool0 := []byte("x"), 1, "x", float32(1), true
+	vBytes1, vInt1, vStr1, vFloat1, vBool1 := []byte("x"), 1, "x", float32(1), true
+	vInt2, vStr2, vFloat2, vBool2 := 1, "x", float32(1), true
+	v = &Parent{
+		I:            vInt0,
+		IPtr:         &vInt1,
+		Is:           []int{vInt0},
+		IPtrs:        []*int{&vInt2},
+		F:            vFloat0,
+		FPtr:         &vFloat1,
+		Fs:           []float32{vFloat0},
+		FPtrs:        []*float32{&vFloat2},
+		B:            vBool0,
+		BPtr:         &vBool1,
+		Bs:           []bool{vBool0},
+		BPtrs:        []*bool{&vBool2},
+		Bytes:        vBytes0,
+		BytesPtr:     &vBytes1,
+		S:            vStr0,
+		SPtr:         &vStr1,
+		Ss:           []string{vStr0},
+		SPtrs:        []*string{&vStr2},
+		MyI:          MyInt(vInt0),
+		Child:        Child{G: struct{ I int }{I: vInt0}},
+		Children:     []Child{{G: struct{ I int }{I: vInt0}}},
+		ChildPtr:     &Child{G: struct{ I int }{I: vInt0}},
+		ChildToEmbed: ChildToEmbed{X: vBool0},
+	}
+	if err := Unmarshal([]byte(emptyXML), v); err != nil {
+		t.Fatalf("populated: Unmarshal failed: got %v", err)
+	}
+
+	want = &Parent{
+		IPtr:     &zInt,
+		Is:       []int{vInt0, zInt},
+		IPtrs:    []*int{&vInt0, &zInt},
+		FPtr:     &zFloat,
+		Fs:       []float32{vFloat0, zFloat},
+		FPtrs:    []*float32{&vFloat0, &zFloat},
+		BPtr:     &zBool,
+		Bs:       []bool{vBool0, zBool},
+		BPtrs:    []*bool{&vBool0, &zBool},
+		Bytes:    []byte{},
+		BytesPtr: &zBytes,
+		SPtr:     &zStr,
+		Ss:       []string{vStr0, zStr},
+		SPtrs:    []*string{&vStr0, &zStr},
+		Child:    Child{G: struct{ I int }{I: vInt0}}, // I should == zInt0? (zero value)
+		Children: []Child{{G: struct{ I int }{I: vInt0}}, {}},
+		ChildPtr: &Child{G: struct{ I int }{I: vInt0}}, // I should == zInt0? (zero value)
+	}
+	if !reflect.DeepEqual(v, want) {
+		t.Fatalf("populated: Unmarshal:\nhave:  %#+v\nwant: %#+v", v, want)
+	}
+}
diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go
index 6623c78..751caa9 100644
--- a/src/encoding/xml/typeinfo.go
+++ b/src/encoding/xml/typeinfo.go
@@ -42,21 +42,18 @@ const (
 	fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny
 )
 
-var tinfoMap = make(map[reflect.Type]*typeInfo)
-var tinfoLock sync.RWMutex
+var tinfoMap sync.Map // map[reflect.Type]*typeInfo
 
 var nameType = reflect.TypeOf(Name{})
 
 // getTypeInfo returns the typeInfo structure with details necessary
 // for marshaling and unmarshaling typ.
 func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
-	tinfoLock.RLock()
-	tinfo, ok := tinfoMap[typ]
-	tinfoLock.RUnlock()
-	if ok {
-		return tinfo, nil
+	if ti, ok := tinfoMap.Load(typ); ok {
+		return ti.(*typeInfo), nil
 	}
-	tinfo = &typeInfo{}
+
+	tinfo := &typeInfo{}
 	if typ.Kind() == reflect.Struct && typ != nameType {
 		n := typ.NumField()
 		for i := 0; i < n; i++ {
@@ -105,10 +102,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
 			}
 		}
 	}
-	tinfoLock.Lock()
-	tinfoMap[typ] = tinfo
-	tinfoLock.Unlock()
-	return tinfo, nil
+
+	ti, _ := tinfoMap.LoadOrStore(typ, tinfo)
+	return ti.(*typeInfo), nil
 }
 
 // structFieldInfo builds and returns a fieldInfo for f.
diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go
index f43a5e7..dad6ed9 100644
--- a/src/encoding/xml/xml_test.go
+++ b/src/encoding/xml/xml_test.go
@@ -797,37 +797,3 @@ func TestIssue12417(t *testing.T) {
 		}
 	}
 }
-
-func TestIssue19333(t *testing.T) {
-	type X struct {
-		XMLName Name `xml:"X"`
-		A       int  `xml:",attr"`
-		C       int
-	}
-
-	var tests = []struct {
-		input string
-		ok    bool
-	}{
-		{`<X></X>`, true},
-		{`<X A=""></X>`, true},
-		{`<X A="bad"></X>`, true},
-		{`<X></X>`, true},
-		{`<X><C></C></X>`, false},
-		{`<X><C/></X>`, false},
-		{`<X><C>bad</C></X>`, false},
-	}
-
-	for _, tt := range tests {
-		err := Unmarshal([]byte(tt.input), new(X))
-		if tt.ok {
-			if err != nil {
-				t.Errorf("%s: unexpected error: %v", tt.input, err)
-			}
-		} else {
-			if err == nil {
-				t.Errorf("%s: unexpected success", tt.input)
-			}
-		}
-	}
-}
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index 7339fa0..64dae70 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -99,9 +99,9 @@ func (v *Float) Set(value float64) {
 
 // Map is a string-to-Var map variable that satisfies the Var interface.
 type Map struct {
-	mu   sync.RWMutex
-	m    map[string]Var
-	keys []string // sorted
+	m      sync.Map // map[string]Var
+	keysMu sync.RWMutex
+	keys   []string // sorted
 }
 
 // KeyValue represents a single entry in a Map.
@@ -111,12 +111,10 @@ type KeyValue struct {
 }
 
 func (v *Map) String() string {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
 	var b bytes.Buffer
 	fmt.Fprintf(&b, "{")
 	first := true
-	v.doLocked(func(kv KeyValue) {
+	v.Do(func(kv KeyValue) {
 		if !first {
 			fmt.Fprintf(&b, ", ")
 		}
@@ -127,79 +125,66 @@ func (v *Map) String() string {
 	return b.String()
 }
 
-func (v *Map) Init() *Map {
-	v.m = make(map[string]Var)
-	return v
-}
+func (v *Map) Init() *Map { return v }
 
 // updateKeys updates the sorted list of keys in v.keys.
-// must be called with v.mu held.
-func (v *Map) updateKeys() {
-	if len(v.m) == len(v.keys) {
-		// No new key.
-		return
-	}
-	v.keys = v.keys[:0]
-	for k := range v.m {
-		v.keys = append(v.keys, k)
-	}
+func (v *Map) addKey(key string) {
+	v.keysMu.Lock()
+	defer v.keysMu.Unlock()
+	v.keys = append(v.keys, key)
 	sort.Strings(v.keys)
 }
 
 func (v *Map) Get(key string) Var {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return v.m[key]
+	i, _ := v.m.Load(key)
+	av, _ := i.(Var)
+	return av
 }
 
 func (v *Map) Set(key string, av Var) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.m[key] = av
-	v.updateKeys()
+	// Before we store the value, check to see whether the key is new. Try a Load
+	// before LoadOrStore: LoadOrStore causes the key interface to escape even on
+	// the Load path.
+	if _, ok := v.m.Load(key); !ok {
+		if _, dup := v.m.LoadOrStore(key, av); !dup {
+			v.addKey(key)
+			return
+		}
+	}
+
+	v.m.Store(key, av)
 }
 
+// Add adds delta to the *Int value stored under the given map key.
 func (v *Map) Add(key string, delta int64) {
-	v.mu.RLock()
-	av, ok := v.m[key]
-	v.mu.RUnlock()
+	i, ok := v.m.Load(key)
 	if !ok {
-		// check again under the write lock
-		v.mu.Lock()
-		av, ok = v.m[key]
-		if !ok {
-			av = new(Int)
-			v.m[key] = av
-			v.updateKeys()
+		var dup bool
+		i, dup = v.m.LoadOrStore(key, new(Int))
+		if !dup {
+			v.addKey(key)
 		}
-		v.mu.Unlock()
 	}
 
 	// Add to Int; ignore otherwise.
-	if iv, ok := av.(*Int); ok {
+	if iv, ok := i.(*Int); ok {
 		iv.Add(delta)
 	}
 }
 
 // AddFloat adds delta to the *Float value stored under the given map key.
 func (v *Map) AddFloat(key string, delta float64) {
-	v.mu.RLock()
-	av, ok := v.m[key]
-	v.mu.RUnlock()
+	i, ok := v.m.Load(key)
 	if !ok {
-		// check again under the write lock
-		v.mu.Lock()
-		av, ok = v.m[key]
-		if !ok {
-			av = new(Float)
-			v.m[key] = av
-			v.updateKeys()
+		var dup bool
+		i, dup = v.m.LoadOrStore(key, new(Float))
+		if !dup {
+			v.addKey(key)
 		}
-		v.mu.Unlock()
 	}
 
 	// Add to Float; ignore otherwise.
-	if iv, ok := av.(*Float); ok {
+	if iv, ok := i.(*Float); ok {
 		iv.Add(delta)
 	}
 }
@@ -208,45 +193,34 @@ func (v *Map) AddFloat(key string, delta float64) {
 // The map is locked during the iteration,
 // but existing entries may be concurrently updated.
 func (v *Map) Do(f func(KeyValue)) {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	v.doLocked(f)
-}
-
-// doLocked calls f for each entry in the map.
-// v.mu must be held for reads.
-func (v *Map) doLocked(f func(KeyValue)) {
+	v.keysMu.RLock()
+	defer v.keysMu.RUnlock()
 	for _, k := range v.keys {
-		f(KeyValue{k, v.m[k]})
+		i, _ := v.m.Load(k)
+		f(KeyValue{k, i.(Var)})
 	}
 }
 
 // String is a string variable, and satisfies the Var interface.
 type String struct {
-	mu sync.RWMutex
-	s  string
+	s atomic.Value // string
 }
 
 func (v *String) Value() string {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return v.s
+	p, _ := v.s.Load().(string)
+	return p
 }
 
 // String implements the Val interface. To get the unquoted string
 // use Value.
 func (v *String) String() string {
-	v.mu.RLock()
-	s := v.s
-	v.mu.RUnlock()
+	s := v.Value()
 	b, _ := json.Marshal(s)
 	return string(b)
 }
 
 func (v *String) Set(value string) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.s = value
+	v.s.Store(value)
 }
 
 // Func implements Var by calling the function
@@ -264,21 +238,20 @@ func (f Func) String() string {
 
 // All published variables.
 var (
-	mutex   sync.RWMutex
-	vars    = make(map[string]Var)
-	varKeys []string // sorted
+	vars      sync.Map // map[string]Var
+	varKeysMu sync.RWMutex
+	varKeys   []string // sorted
 )
 
 // Publish declares a named exported variable. This should be called from a
 // package's init function when it creates its Vars. If the name is already
 // registered then this will log.Panic.
 func Publish(name string, v Var) {
-	mutex.Lock()
-	defer mutex.Unlock()
-	if _, existing := vars[name]; existing {
+	if _, dup := vars.LoadOrStore(name, v); dup {
 		log.Panicln("Reuse of exported var name:", name)
 	}
-	vars[name] = v
+	varKeysMu.Lock()
+	defer varKeysMu.Unlock()
 	varKeys = append(varKeys, name)
 	sort.Strings(varKeys)
 }
@@ -286,9 +259,9 @@ func Publish(name string, v Var) {
 // 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()
-	return vars[name]
+	i, _ := vars.Load(name)
+	v, _ := i.(Var)
+	return v
 }
 
 // Convenience functions for creating new exported variables.
@@ -321,10 +294,11 @@ func NewString(name string) *String {
 // The global variable map is locked during the iteration,
 // but existing entries may be concurrently updated.
 func Do(f func(KeyValue)) {
-	mutex.RLock()
-	defer mutex.RUnlock()
+	varKeysMu.RLock()
+	defer varKeysMu.RUnlock()
 	for _, k := range varKeys {
-		f(KeyValue{k, vars[k]})
+		val, _ := vars.Load(k)
+		f(KeyValue{k, val.(Var)})
 	}
 }
 
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 0efa864..7014063 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,21 +7,25 @@ package expvar
 import (
 	"bytes"
 	"encoding/json"
+	"fmt"
 	"net"
 	"net/http/httptest"
 	"reflect"
 	"runtime"
 	"strconv"
 	"sync"
+	"sync/atomic"
 	"testing"
 )
 
 // RemoveAll removes all exported variables.
 // This is for tests only.
 func RemoveAll() {
-	mutex.Lock()
-	defer mutex.Unlock()
-	vars = make(map[string]Var)
+	varKeysMu.Lock()
+	defer varKeysMu.Unlock()
+	for _, k := range varKeys {
+		vars.Delete(k)
+	}
 	varKeys = nil
 }
 
@@ -36,8 +40,8 @@ func TestNil(t *testing.T) {
 func TestInt(t *testing.T) {
 	RemoveAll()
 	reqs := NewInt("requests")
-	if reqs.i != 0 {
-		t.Errorf("reqs.i = %v, want 0", reqs.i)
+	if i := reqs.Value(); i != 0 {
+		t.Errorf("reqs.Value() = %v, want 0", i)
 	}
 	if reqs != Get("requests").(*Int) {
 		t.Errorf("Get() failed.")
@@ -45,8 +49,8 @@ func TestInt(t *testing.T) {
 
 	reqs.Add(1)
 	reqs.Add(3)
-	if reqs.i != 4 {
-		t.Errorf("reqs.i = %v, want 4", reqs.i)
+	if i := reqs.Value(); i != 4 {
+		t.Errorf("reqs.Value() = %v, want 4", i)
 	}
 
 	if s := reqs.String(); s != "4" {
@@ -54,12 +58,8 @@ func TestInt(t *testing.T) {
 	}
 
 	reqs.Set(-2)
-	if reqs.i != -2 {
-		t.Errorf("reqs.i = %v, want -2", reqs.i)
-	}
-
-	if v, want := reqs.Value(), int64(-2); v != want {
-		t.Errorf("reqs.Value() = %q, want %q", v, want)
+	if i := reqs.Value(); i != -2 {
+		t.Errorf("reqs.Value() = %v, want -2", i)
 	}
 }
 
@@ -132,27 +132,22 @@ func BenchmarkFloatSet(b *testing.B) {
 func TestString(t *testing.T) {
 	RemoveAll()
 	name := NewString("my-name")
-	if name.s != "" {
-		t.Errorf("name.s = %q, want \"\"", name.s)
+	if s := name.Value(); s != "" {
+		t.Errorf(`NewString("my-name").Value() = %q, want ""`, s)
 	}
 
 	name.Set("Mike")
-	if name.s != "Mike" {
-		t.Errorf("name.s = %q, want \"Mike\"", name.s)
-	}
-
 	if s, want := name.String(), `"Mike"`; s != want {
-		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
+		t.Errorf(`after name.Set("Mike"), name.String() = %q, want %q`, s, want)
 	}
-
 	if s, want := name.Value(), "Mike"; s != want {
-		t.Errorf("from %q, name.Value() = %q, want %q", name.s, s, want)
+		t.Errorf(`after name.Set("Mike"), name.Value() = %q, want %q`, s, want)
 	}
 
 	// Make sure we produce safe JSON output.
-	name.Set(`<`)
+	name.Set("<")
 	if s, want := name.String(), "\"\\u003c\""; s != want {
-		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
+		t.Errorf(`after name.Set("<"), name.String() = %q, want %q`, s, want)
 	}
 }
 
@@ -174,13 +169,13 @@ func TestMapCounter(t *testing.T) {
 	colors.Add("red", 2)
 	colors.Add("blue", 4)
 	colors.AddFloat(`green "midori"`, 4.125)
-	if x := colors.m["red"].(*Int).i; x != 3 {
+	if x := colors.Get("red").(*Int).Value(); x != 3 {
 		t.Errorf("colors.m[\"red\"] = %v, want 3", x)
 	}
-	if x := colors.m["blue"].(*Int).i; x != 4 {
+	if x := colors.Get("blue").(*Int).Value(); x != 4 {
 		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
 	}
-	if x := colors.m[`green "midori"`].(*Float).Value(); x != 4.125 {
+	if x := colors.Get(`green "midori"`).(*Float).Value(); x != 4.125 {
 		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
 	}
 
@@ -218,24 +213,117 @@ func BenchmarkMapSet(b *testing.B) {
 	})
 }
 
-func BenchmarkMapAddSame(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		m := new(Map).Init()
-		m.Add("red", 1)
-		m.Add("red", 1)
-		m.Add("red", 1)
-		m.Add("red", 1)
+func BenchmarkMapSetDifferent(b *testing.B) {
+	procKeys := make([][]string, runtime.GOMAXPROCS(0))
+	for i := range procKeys {
+		keys := make([]string, 4)
+		for j := range keys {
+			keys[j] = fmt.Sprint(i, j)
+		}
+		procKeys[i] = keys
 	}
+
+	m := new(Map).Init()
+	v := new(Int)
+	b.ResetTimer()
+
+	var n int32
+	b.RunParallel(func(pb *testing.PB) {
+		i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
+		keys := procKeys[i]
+
+		for pb.Next() {
+			for _, k := range keys {
+				m.Set(k, v)
+			}
+		}
+	})
+}
+
+func BenchmarkMapSetString(b *testing.B) {
+	m := new(Map).Init()
+
+	v := new(String)
+	v.Set("Hello, !")
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			m.Set("red", v)
+		}
+	})
+}
+
+func BenchmarkMapAddSame(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			m := new(Map).Init()
+			m.Add("red", 1)
+			m.Add("red", 1)
+			m.Add("red", 1)
+			m.Add("red", 1)
+		}
+	})
 }
 
 func BenchmarkMapAddDifferent(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		m := new(Map).Init()
-		m.Add("red", 1)
-		m.Add("blue", 1)
-		m.Add("green", 1)
-		m.Add("yellow", 1)
+	procKeys := make([][]string, runtime.GOMAXPROCS(0))
+	for i := range procKeys {
+		keys := make([]string, 4)
+		for j := range keys {
+			keys[j] = fmt.Sprint(i, j)
+		}
+		procKeys[i] = keys
+	}
+
+	b.ResetTimer()
+
+	var n int32
+	b.RunParallel(func(pb *testing.PB) {
+		i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
+		keys := procKeys[i]
+
+		for pb.Next() {
+			m := new(Map).Init()
+			for _, k := range keys {
+				m.Add(k, 1)
+			}
+		}
+	})
+}
+
+func BenchmarkMapAddSameSteadyState(b *testing.B) {
+	m := new(Map).Init()
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			m.Add("red", 1)
+		}
+	})
+}
+
+func BenchmarkMapAddDifferentSteadyState(b *testing.B) {
+	procKeys := make([][]string, runtime.GOMAXPROCS(0))
+	for i := range procKeys {
+		keys := make([]string, 4)
+		for j := range keys {
+			keys[j] = fmt.Sprint(i, j)
+		}
+		procKeys[i] = keys
 	}
+
+	m := new(Map).Init()
+	b.ResetTimer()
+
+	var n int32
+	b.RunParallel(func(pb *testing.PB) {
+		i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
+		keys := procKeys[i]
+
+		for pb.Next() {
+			for _, k := range keys {
+				m.Add(k, 1)
+			}
+		}
+	})
 }
 
 func TestFunc(t *testing.T) {
diff --git a/src/flag/flag.go b/src/flag/flag.go
index bbbc55a..b166c57 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -114,7 +114,7 @@ func newIntValue(val int, p *int) *intValue {
 }
 
 func (i *intValue) Set(s string) error {
-	v, err := strconv.ParseInt(s, 0, 64)
+	v, err := strconv.ParseInt(s, 0, strconv.IntSize)
 	*i = intValue(v)
 	return err
 }
@@ -150,7 +150,7 @@ func newUintValue(val uint, p *uint) *uintValue {
 }
 
 func (i *uintValue) Set(s string) error {
-	v, err := strconv.ParseUint(s, 0, 64)
+	v, err := strconv.ParseUint(s, 0, strconv.IntSize)
 	*i = uintValue(v)
 	return err
 }
diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go
index e2319ec..02da2c7 100644
--- a/src/flag/flag_test.go
+++ b/src/flag/flag_test.go
@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"os"
 	"sort"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -415,3 +416,19 @@ func TestPrintDefaults(t *testing.T) {
 		t.Errorf("got %q want %q\n", got, defaultOutput)
 	}
 }
+
+// Issue 19230: validate range of Int and Uint flag values.
+func TestIntFlagOverflow(t *testing.T) {
+	if strconv.IntSize != 32 {
+		return
+	}
+	ResetForTesting(nil)
+	Int("i", 0, "")
+	Uint("u", 0, "")
+	if err := Set("i", "2147483648"); err == nil {
+		t.Error("unexpected success setting Int")
+	}
+	if err := Set("u", "4294967296"); err == nil {
+		t.Error("unexpected success setting Uint")
+	}
+}
diff --git a/src/fmt/doc.go b/src/fmt/doc.go
index a2faecb..014ba06 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -38,7 +38,7 @@
 		%E	scientific notation, e.g. -1.234456E+78
 		%f	decimal point but no exponent, e.g. 123.456
 		%F	synonym for %f
-		%g	%e for large exponents, %f otherwise
+		%g	%e for large exponents, %f otherwise. Precision is discussed below.
 		%G	%E for large exponents, %F otherwise
 	String and slice of bytes (treated equivalently with these verbs):
 		%s	the uninterpreted bytes of the string or slice
@@ -94,7 +94,7 @@
 	precision sets the number of places after the decimal, if appropriate,
 	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
+	%.3g prints 12.3. The default precision for %e, %f and %#g 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
@@ -109,6 +109,8 @@
 			0X for hex (%#X); suppress 0x for %p (%#p);
 			for %q, print a raw (backquoted) string if strconv.CanBackquote
 			returns true;
+			always print a decimal point for %e, %E, %f, %F, %g and %G;
+			do not remove trailing zeros for %g and %G;
 			write e.g. U+0078 'x' if the character is printable for %U (%#U).
 		' '	(space) leave a space for elided sign in numbers (% d);
 			put spaces between bytes printing strings or slices in hex (% x, % X)
@@ -190,9 +192,9 @@
 	For example,
 		fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
 	will yield "22 11", while
-		fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),
+		fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6)
 	equivalent to
-		fmt.Sprintf("%6.2f", 12.0),
+		fmt.Sprintf("%6.2f", 12.0)
 	will yield " 12.00". Because an explicit index affects subsequent verbs,
 	this notation can be used to print the same values multiple times
 	by resetting the index for the first argument to be repeated:
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index b7089be..9bec6f3 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -416,6 +416,32 @@ var fmtTests = []struct {
 	{"% .3g", 1.0, " 1"},
 	{"%b", float32(1.0), "8388608p-23"},
 	{"%b", 1.0, "4503599627370496p-52"},
+	// Test sharp flag used with floats.
+	{"%#g", 1e-323, "1.00000e-323"},
+	{"%#g", -1.0, "-1.00000"},
+	{"%#g", 1.1, "1.10000"},
+	{"%#g", 123456.0, "123456."},
+	{"%#g", 1234567.0, "1.234567e+06"},
+	{"%#g", 1230000.0, "1.23000e+06"},
+	{"%#g", 1000000.0, "1.00000e+06"},
+	{"%#.0f", 1.0, "1."},
+	{"%#.0e", 1.0, "1.e+00"},
+	{"%#.0g", 1.0, "1."},
+	{"%#.0g", 1100000.0, "1.e+06"},
+	{"%#.4f", 1.0, "1.0000"},
+	{"%#.4e", 1.0, "1.0000e+00"},
+	{"%#.4g", 1.0, "1.000"},
+	{"%#.4g", 100000.0, "1.000e+05"},
+	{"%#.0f", 123.0, "123."},
+	{"%#.0e", 123.0, "1.e+02"},
+	{"%#.0g", 123.0, "1.e+02"},
+	{"%#.4f", 123.0, "123.0000"},
+	{"%#.4e", 123.0, "1.2300e+02"},
+	{"%#.4g", 123.0, "123.0"},
+	{"%#.4g", 123000.0, "1.230e+05"},
+	{"%#9.4g", 1.0, "    1.000"},
+	// The sharp flag has no effect for binary float format.
+	{"%#b", 1.0, "4503599627370496p-52"},
 	// Precision has no effect for binary float format.
 	{"%.4b", float32(1.0), "8388608p-23"},
 	{"%.4b", -1.0, "-4503599627370496p-52"},
@@ -466,8 +492,24 @@ var fmtTests = []struct {
 	{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
 	{"%+.3g", 1 + 2i, "(+1+2i)"},
 	{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
+	{"%#g", 1 + 2i, "(1.00000+2.00000i)"},
+	{"%#g", 123456 + 789012i, "(123456.+789012.i)"},
+	{"%#g", 1e-10i, "(0.00000+1.00000e-10i)"},
+	{"%#g", -1e10 - 1.11e100i, "(-1.00000e+10-1.11000e+100i)"},
+	{"%#.0f", 1.23 + 1.0i, "(1.+1.i)"},
+	{"%#.0e", 1.23 + 1.0i, "(1.e+00+1.e+00i)"},
+	{"%#.0g", 1.23 + 1.0i, "(1.+1.i)"},
+	{"%#.0g", 0 + 100000i, "(0.+1.e+05i)"},
+	{"%#.0g", 1230000 + 0i, "(1.e+06+0.i)"},
+	{"%#.4f", 1 + 1.23i, "(1.0000+1.2300i)"},
+	{"%#.4e", 123 + 1i, "(1.2300e+02+1.0000e+00i)"},
+	{"%#.4g", 123 + 1.23i, "(123.0+1.230i)"},
+	{"%#12.5g", 0 + 100000i, "(      0.0000 +1.0000e+05i)"},
+	{"%#12.5g", 1230000 - 0i, "(  1.2300e+06     +0.0000i)"},
 	{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
 	{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+	// The sharp flag has no effect for binary complex format.
+	{"%#b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
 	// Precision has no effect for binary complex format.
 	{"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
 	{"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
diff --git a/src/fmt/format.go b/src/fmt/format.go
index f770483..d4b92f8 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -480,6 +480,46 @@ func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
 		f.zero = oldZero
 		return
 	}
+	// The sharp flag forces printing a decimal point for non-binary formats
+	// and retains trailing zeros, which we may need to restore.
+	if f.sharp && verb != 'b' {
+		digits := 0
+		switch verb {
+		case 'v', 'g', 'G':
+			digits = prec
+			// If no precision is set explicitly use a precision of 6.
+			if digits == -1 {
+				digits = 6
+			}
+		}
+
+		// Buffer pre-allocated with enough room for
+		// exponent notations of the form "e+123".
+		var tailBuf [5]byte
+		tail := tailBuf[:0]
+
+		hasDecimalPoint := false
+		// Starting from i = 1 to skip sign at num[0].
+		for i := 1; i < len(num); i++ {
+			switch num[i] {
+			case '.':
+				hasDecimalPoint = true
+			case 'e', 'E':
+				tail = append(tail, num[i:]...)
+				num = num[:i]
+			default:
+				digits--
+			}
+		}
+		if !hasDecimalPoint {
+			num = append(num, '.')
+		}
+		for digits > 0 {
+			num = append(num, '0')
+			digits--
+		}
+		num = append(num, tail...)
+	}
 	// 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.
diff --git a/src/fmt/print.go b/src/fmt/print.go
index a7ef2e5..2bd88f9 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -684,8 +684,6 @@ func (p *pp) printArg(arg interface{}, verb rune) {
 	}
 }
 
-var byteType = reflect.TypeOf(byte(0))
-
 // 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) {
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index a197b5a..2ecc48b 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -848,6 +848,7 @@ type (
 	TypeSpec struct {
 		Doc     *CommentGroup // associated documentation; or nil
 		Name    *Ident        // type name
+		Assign  token.Pos     // position of '=', if any
 		Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
 		Comment *CommentGroup // line comments; or nil
 	}
diff --git a/src/go/build/build.go b/src/go/build/build.go
index f11bc0c..fd89871 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -155,6 +155,7 @@ func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
 	return hasSubdir(rootSym, dirSym)
 }
 
+// hasSubdir reports if dir is within root by performing lexical analysis only.
 func hasSubdir(root, dir string) (rel string, ok bool) {
 	const sep = string(filepath.Separator)
 	root = filepath.Clean(root)
@@ -290,7 +291,8 @@ 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", "go1.7", "go1.8"}
+	// NOTE: If you add to this list, also update the doc comment in doc.go.
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.9"}
 
 	env := os.Getenv("CGO_ENABLED")
 	if env == "" {
@@ -527,6 +529,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 		if !ctxt.isAbsPath(path) {
 			p.Dir = ctxt.joinPath(srcDir, path)
 		}
+		// p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
 		// Determine canonical import path, if any.
 		// Exclude results where the import path would include /testdata/.
 		inTestdata := func(sub string) bool {
@@ -681,6 +684,16 @@ Found:
 		}
 	}
 
+	// If it's a local import path, by the time we get here, we still haven't checked
+	// that p.Dir directory exists. This is the right time to do that check.
+	// We can't do it earlier, because we want to gather partial information for the
+	// non-nil *Package returned when an error occurs.
+	// We need to do this before we return early on FindOnly flag.
+	if IsLocalImport(path) && !ctxt.isDir(p.Dir) {
+		// package was not found
+		return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir)
+	}
+
 	if mode&FindOnly != 0 {
 		return p, pkgerr
 	}
@@ -716,7 +729,7 @@ Found:
 			p.InvalidGoFiles = append(p.InvalidGoFiles, name)
 		}
 
-		match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags, &p.BinaryOnly)
+		match, data, filename, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly)
 		if err != nil {
 			badFile(err)
 			continue
@@ -1030,19 +1043,19 @@ 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, nil)
+	match, _, _, err = ctxt.matchFile(dir, name, nil, nil)
 	return
 }
 
 // matchFile determines whether the file with the given name in the given directory
 // should be included in the package being constructed.
 // It returns the data read from the file.
-// If returnImports is true and name denotes a Go program, matchFile reads
-// until the end of the imports (and returns that data) even though it only
-// considers text until the first non-comment.
+// If name denotes a Go program, matchFile reads until the end of the
+// imports (and returns that data) even though it only 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, binaryOnly *bool) (match bool, data []byte, filename string, err error) {
+func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) {
 	if strings.HasPrefix(name, "_") ||
 		strings.HasPrefix(name, ".") {
 		return
@@ -1269,6 +1282,12 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 		}
 
 		switch verb {
+		case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS":
+			// Change relative paths to absolute.
+			ctxt.makePathsAbsolute(args, di.Dir)
+		}
+
+		switch verb {
 		case "CFLAGS":
 			di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
 		case "CPPFLAGS":
@@ -1296,40 +1315,63 @@ func expandSrcDir(str string, srcdir string) (string, bool) {
 	// to "/" before starting (eg: on windows).
 	srcdir = filepath.ToSlash(srcdir)
 
-	// Spaces are tolerated in ${SRCDIR}, but not anywhere else.
 	chunks := strings.Split(str, "${SRCDIR}")
 	if len(chunks) < 2 {
-		return str, safeCgoName(str, false)
+		return str, safeCgoName(str)
 	}
 	ok := true
 	for _, chunk := range chunks {
-		ok = ok && (chunk == "" || safeCgoName(chunk, false))
+		ok = ok && (chunk == "" || safeCgoName(chunk))
 	}
-	ok = ok && (srcdir == "" || safeCgoName(srcdir, true))
+	ok = ok && (srcdir == "" || safeCgoName(srcdir))
 	res := strings.Join(chunks, srcdir)
 	return res, ok && res != ""
 }
 
+// makePathsAbsolute looks for compiler options that take paths and
+// makes them absolute. We do this because through the 1.8 release we
+// ran the compiler in the package directory, so any relative -I or -L
+// options would be relative to that directory. In 1.9 we changed to
+// running the compiler in the build directory, to get consistent
+// build results (issue #19964). To keep builds working, we change any
+// relative -I or -L options to be absolute.
+//
+// Using filepath.IsAbs and filepath.Join here means the results will be
+// different on different systems, but that's OK: -I and -L options are
+// inherently system-dependent.
+func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) {
+	nextPath := false
+	for i, arg := range args {
+		if nextPath {
+			if !filepath.IsAbs(arg) {
+				args[i] = filepath.Join(srcDir, arg)
+			}
+			nextPath = false
+		} else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
+			if len(arg) == 2 {
+				nextPath = true
+			} else {
+				if !filepath.IsAbs(arg[2:]) {
+					args[i] = arg[:2] + filepath.Join(srcDir, arg[2:])
+				}
+			}
+		}
+	}
+}
+
 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
 // See golang.org/issue/6038.
 // The @ is for OS X. See golang.org/issue/13720.
 // The % is for Jenkins. See golang.org/issue/16959.
-const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%"
-const safeSpaces = " "
+const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% "
 
-var safeBytes = []byte(safeSpaces + safeString)
-
-func safeCgoName(s string, spaces bool) bool {
+func safeCgoName(s string) bool {
 	if s == "" {
 		return false
 	}
-	safe := safeBytes
-	if !spaces {
-		safe = safe[len(safeSpaces):]
-	}
 	for i := 0; i < len(s); i++ {
-		if c := s[i]; c < utf8.RuneSelf && bytes.IndexByte(safe, c) < 0 {
+		if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 {
 			return false
 		}
 	}
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index a997241..979f76c 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -285,9 +285,11 @@ func TestShellSafety(t *testing.T) {
 		{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
 		{"-I${SRCDIR}", "wtf$@%", "-Iwtf$@%", true},
 		{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
-		{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
+		{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", true},
 		{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
 		{"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
+		{"-I${SRCDIR}/dir", "/tmp/go go", "-I/tmp/go go/dir", true},
+		{"-I${SRCDIR}/dir dir", "/tmp/go", "-I/tmp/go/dir dir", true},
 	}
 	for _, test := range tests {
 		output, ok := expandSrcDir(test.input, test.srcdir)
@@ -300,6 +302,40 @@ func TestShellSafety(t *testing.T) {
 	}
 }
 
+// Want to get a "cannot find package" error when directory for package does not exist.
+// There should be valid partial information in the returned non-nil *Package.
+func TestImportDirNotExist(t *testing.T) {
+	testenv.MustHaveGoBuild(t) // really must just have source
+	ctxt := Default
+	ctxt.GOPATH = ""
+
+	tests := []struct {
+		label        string
+		path, srcDir string
+		mode         ImportMode
+	}{
+		{"Import(full, 0)", "go/build/doesnotexist", "", 0},
+		{"Import(local, 0)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), 0},
+		{"Import(full, FindOnly)", "go/build/doesnotexist", "", FindOnly},
+		{"Import(local, FindOnly)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), FindOnly},
+	}
+	for _, test := range tests {
+		p, err := ctxt.Import(test.path, test.srcDir, test.mode)
+		if err == nil || !strings.HasPrefix(err.Error(), "cannot find package") {
+			t.Errorf(`%s got error: %q, want "cannot find package" error`, test.label, err)
+		}
+		// If an error occurs, build.Import is documented to return
+		// a non-nil *Package containing partial information.
+		if p == nil {
+			t.Fatalf(`%s got nil p, want non-nil *Package`, test.label)
+		}
+		// Verify partial information in p.
+		if p.ImportPath != "go/build/doesnotexist" {
+			t.Errorf(`%s got p.ImportPath: %q, want "go/build/doesnotexist"`, test.label, p.ImportPath)
+		}
+	}
+}
+
 func TestImportVendor(t *testing.T) {
 	testenv.MustHaveGoBuild(t) // really must just have source
 	ctxt := Default
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 147eaf6..f9f655b 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -43,6 +43,7 @@ var pkgDeps = map[string][]string{
 	"sync":                    {"internal/race", "runtime", "sync/atomic", "unsafe"},
 	"sync/atomic":             {"unsafe"},
 	"unsafe":                  {},
+	"internal/cpu":            {"runtime"},
 
 	"L0": {
 		"errors",
@@ -52,11 +53,13 @@ var pkgDeps = map[string][]string{
 		"sync",
 		"sync/atomic",
 		"unsafe",
+		"internal/cpu",
 	},
 
 	// L1 adds simple functions and strings processing,
 	// but not Unicode tables.
-	"math":          {"unsafe"},
+	"math":          {"internal/cpu", "unsafe"},
+	"math/bits":     {},
 	"math/cmplx":    {"math"},
 	"math/rand":     {"L0", "math"},
 	"strconv":       {"L0", "unicode/utf8", "math"},
@@ -66,6 +69,7 @@ var pkgDeps = map[string][]string{
 	"L1": {
 		"L0",
 		"math",
+		"math/bits",
 		"math/cmplx",
 		"math/rand",
 		"sort",
@@ -150,7 +154,8 @@ var pkgDeps = map[string][]string{
 		"syscall",
 	},
 
-	"os":            {"L1", "os", "syscall", "time", "internal/syscall/windows"},
+	"internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+	"os":            {"L1", "os", "syscall", "time", "internal/poll", "internal/syscall/windows"},
 	"path/filepath": {"L2", "os", "syscall"},
 	"io/ioutil":     {"L2", "os", "path/filepath", "time"},
 	"os/exec":       {"L2", "os", "context", "path/filepath", "syscall"},
@@ -171,17 +176,16 @@ var pkgDeps = map[string][]string{
 	"log": {"L1", "os", "fmt", "time"},
 
 	// Packages used by testing must be low-level (L2+fmt).
-	"regexp":                            {"L2", "regexp/syntax"},
-	"regexp/syntax":                     {"L2"},
-	"runtime/debug":                     {"L2", "fmt", "io/ioutil", "os", "time"},
-	"runtime/pprof/internal/protopprof": {"L2", "fmt", "internal/pprof/profile", "os", "time"},
-	"runtime/pprof":                     {"L2", "fmt", "internal/pprof/profile", "os", "runtime/pprof/internal/protopprof", "text/tabwriter", "time"},
-	"runtime/trace":                     {"L0"},
-	"text/tabwriter":                    {"L2"},
-
-	"testing":          {"L2", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
+	"regexp":         {"L2", "regexp/syntax"},
+	"regexp/syntax":  {"L2"},
+	"runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"},
+	"runtime/pprof":  {"L2", "compress/gzip", "context", "encoding/binary", "fmt", "io/ioutil", "os", "text/tabwriter", "time"},
+	"runtime/trace":  {"L0"},
+	"text/tabwriter": {"L2"},
+
+	"testing":          {"L2", "flag", "fmt", "internal/race", "os", "os/signal", "runtime/debug", "runtime/pprof", "runtime/trace", "syscall", "time"},
 	"testing/iotest":   {"L2", "log"},
-	"testing/quick":    {"L2", "flag", "fmt", "reflect"},
+	"testing/quick":    {"L2", "flag", "fmt", "reflect", "time"},
 	"internal/testenv": {"L2", "OS", "flag", "testing", "syscall"},
 
 	// L4 is defined as L3+fmt+log+time, because in general once
@@ -215,59 +219,60 @@ var pkgDeps = map[string][]string{
 
 	// Go type checking.
 	"go/constant":               {"L4", "go/token", "math/big"},
-	"go/importer":               {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"},
+	"go/importer":               {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
 	"go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
 	"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
+	"go/internal/srcimporter":   {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
 	"go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
 
 	// One of a kind.
-	"archive/tar":               {"L4", "OS", "syscall"},
-	"archive/zip":               {"L4", "OS", "compress/flate"},
-	"container/heap":            {"sort"},
-	"compress/bzip2":            {"L4"},
-	"compress/flate":            {"L4"},
-	"compress/gzip":             {"L4", "compress/flate"},
-	"compress/lzw":              {"L4"},
-	"compress/zlib":             {"L4", "compress/flate"},
-	"context":                   {"errors", "fmt", "reflect", "sync", "time"},
-	"database/sql":              {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
-	"database/sql/driver":       {"L4", "context", "time", "database/sql/internal"},
-	"debug/dwarf":               {"L4"},
-	"debug/elf":                 {"L4", "OS", "debug/dwarf", "compress/zlib"},
-	"debug/gosym":               {"L4"},
-	"debug/macho":               {"L4", "OS", "debug/dwarf"},
-	"debug/pe":                  {"L4", "OS", "debug/dwarf"},
-	"debug/plan9obj":            {"L4", "OS"},
-	"encoding":                  {"L4"},
-	"encoding/ascii85":          {"L4"},
-	"encoding/asn1":             {"L4", "math/big"},
-	"encoding/csv":              {"L4"},
-	"encoding/gob":              {"L4", "OS", "encoding"},
-	"encoding/hex":              {"L4"},
-	"encoding/json":             {"L4", "encoding"},
-	"encoding/pem":              {"L4"},
-	"encoding/xml":              {"L4", "encoding"},
-	"flag":                      {"L4", "OS"},
-	"go/build":                  {"L4", "OS", "GOPARSER"},
-	"html":                      {"L4"},
-	"image/draw":                {"L4", "image/internal/imageutil"},
-	"image/gif":                 {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-	"image/internal/imageutil":  {"L4"},
-	"image/jpeg":                {"L4", "image/internal/imageutil"},
-	"image/png":                 {"L4", "compress/zlib"},
-	"index/suffixarray":         {"L4", "regexp"},
-	"internal/singleflight":     {"sync"},
-	"internal/trace":            {"L4", "OS"},
-	"internal/pprof/profile":    {"L4", "OS", "compress/gzip", "regexp"},
-	"math/big":                  {"L4"},
-	"mime":                      {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
-	"mime/quotedprintable":      {"L4"},
-	"net/internal/socktest":     {"L4", "OS", "syscall"},
-	"net/url":                   {"L4"},
-	"plugin":                    {"L0", "OS", "CGO"},
-	"testing/internal/testdeps": {"L4", "runtime/pprof", "regexp"},
-	"text/scanner":              {"L4", "OS"},
-	"text/template/parse":       {"L4"},
+	"archive/tar":              {"L4", "OS", "syscall"},
+	"archive/zip":              {"L4", "OS", "compress/flate"},
+	"container/heap":           {"sort"},
+	"compress/bzip2":           {"L4"},
+	"compress/flate":           {"L4"},
+	"compress/gzip":            {"L4", "compress/flate"},
+	"compress/lzw":             {"L4"},
+	"compress/zlib":            {"L4", "compress/flate"},
+	"context":                  {"errors", "fmt", "reflect", "sync", "time"},
+	"database/sql":             {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
+	"database/sql/driver":      {"L4", "context", "time", "database/sql/internal"},
+	"debug/dwarf":              {"L4"},
+	"debug/elf":                {"L4", "OS", "debug/dwarf", "compress/zlib"},
+	"debug/gosym":              {"L4"},
+	"debug/macho":              {"L4", "OS", "debug/dwarf"},
+	"debug/pe":                 {"L4", "OS", "debug/dwarf"},
+	"debug/plan9obj":           {"L4", "OS"},
+	"encoding":                 {"L4"},
+	"encoding/ascii85":         {"L4"},
+	"encoding/asn1":            {"L4", "math/big"},
+	"encoding/csv":             {"L4"},
+	"encoding/gob":             {"L4", "OS", "encoding"},
+	"encoding/hex":             {"L4"},
+	"encoding/json":            {"L4", "encoding"},
+	"encoding/pem":             {"L4"},
+	"encoding/xml":             {"L4", "encoding"},
+	"flag":                     {"L4", "OS"},
+	"go/build":                 {"L4", "OS", "GOPARSER"},
+	"html":                     {"L4"},
+	"image/draw":               {"L4", "image/internal/imageutil"},
+	"image/gif":                {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+	"image/internal/imageutil": {"L4"},
+	"image/jpeg":               {"L4", "image/internal/imageutil"},
+	"image/png":                {"L4", "compress/zlib"},
+	"index/suffixarray":        {"L4", "regexp"},
+	"internal/singleflight":    {"sync"},
+	"internal/trace":           {"L4", "OS"},
+	"math/big":                 {"L4"},
+	"mime":                     {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
+	"mime/quotedprintable":     {"L4"},
+	"net/internal/socktest":    {"L4", "OS", "syscall"},
+	"net/url":                  {"L4"},
+	"plugin":                   {"L0", "OS", "CGO"},
+	"runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"},
+	"testing/internal/testdeps":      {"L4", "runtime/pprof", "regexp"},
+	"text/scanner":                   {"L4", "OS"},
+	"text/template/parse":            {"L4"},
 
 	"html/template": {
 		"L4", "OS", "encoding/json", "html", "text/template",
@@ -299,8 +304,8 @@ var pkgDeps = map[string][]string{
 	// do networking portably, it must have a small dependency set: just L0+basic os.
 	"net": {
 		"L0", "CGO",
-		"context", "math/rand", "os", "sort", "syscall", "time",
-		"internal/nettrace",
+		"context", "math/rand", "os", "reflect", "sort", "syscall", "time",
+		"internal/nettrace", "internal/poll",
 		"internal/syscall/windows", "internal/singleflight", "internal/race",
 		"golang_org/x/net/lif", "golang_org/x/net/route",
 	},
@@ -391,6 +396,7 @@ var pkgDeps = map[string][]string{
 		"golang_org/x/net/http2/hpack",
 		"golang_org/x/net/idna",
 		"golang_org/x/net/lex/httplex",
+		"golang_org/x/net/proxy",
 		"golang_org/x/text/unicode/norm",
 		"golang_org/x/text/width",
 		"internal/nettrace",
@@ -406,8 +412,8 @@ var pkgDeps = map[string][]string{
 	"expvar":             {"L4", "OS", "encoding/json", "net/http"},
 	"net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
 	"net/http/cookiejar": {"L4", "NET", "net/http"},
-	"net/http/fcgi":      {"L4", "NET", "OS", "net/http", "net/http/cgi"},
-	"net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal"},
+	"net/http/fcgi":      {"L4", "NET", "OS", "context", "net/http", "net/http/cgi"},
+	"net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal", "crypto/x509"},
 	"net/http/httputil":  {"L4", "NET", "OS", "context", "net/http", "net/http/internal"},
 	"net/http/pprof":     {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
 	"net/rpc":            {"L4", "NET", "encoding/gob", "html/template", "net/http"},
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 979d047..422e1a5 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -105,6 +105,7 @@
 //	- "go1.6", from Go version 1.6 onward
 //	- "go1.7", from Go version 1.7 onward
 //	- "go1.8", from Go version 1.8 onward
+//	- "go1.9", from Go version 1.9 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/go/constant/value.go b/src/go/constant/value.go
index 7c32473..5474e73 100644
--- a/src/go/constant/value.go
+++ b/src/go/constant/value.go
@@ -205,13 +205,8 @@ func rtof(x ratVal) floatVal {
 
 func vtoc(x Value) complexVal { return complexVal{x, int64Val(0)} }
 
-var (
-	minInt64 = big.NewInt(-1 << 63)
-	maxInt64 = big.NewInt(1<<63 - 1)
-)
-
 func makeInt(x *big.Int) Value {
-	if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+	if x.IsInt64() {
 		return int64Val(x.Int64())
 	}
 	return intVal{x}
@@ -252,6 +247,13 @@ func makeFloatFromLiteral(lit string) Value {
 	if f, ok := newFloat().SetString(lit); ok {
 		if smallRat(f) {
 			// ok to use rationals
+			if f.Sign() == 0 {
+				// Issue 20228: If the float underflowed to zero, parse just "0".
+				// Otherwise, lit might contain a value with a large negative exponent,
+				// such as -6e-1886451601. As a float, that will underflow to 0,
+				// but it'll take forever to parse as a Rat.
+				lit = "0"
+			}
 			r, _ := newRat().SetString(lit)
 			return ratVal{r}
 		}
@@ -413,7 +415,7 @@ func Uint64Val(x Value) (uint64, bool) {
 	case int64Val:
 		return uint64(x), x >= 0
 	case intVal:
-		return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
+		return x.val.Uint64(), x.val.IsUint64()
 	case unknownVal:
 		return 0, false
 	default:
diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go
index 8a8a08e..954a0e0 100644
--- a/src/go/constant/value_test.go
+++ b/src/go/constant/value_test.go
@@ -244,7 +244,8 @@ 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
+	{"0e9999999999", "0", "0"},   // issue #16176
+	{"-6e-1886451601", "0", "0"}, // issue #20228
 
 	// Complex
 	{"0i", "(0 + 0i)", "(0 + 0i)"},
diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go
index 15e034b..4228e8c 100644
--- a/src/go/doc/comment.go
+++ b/src/go/doc/comment.go
@@ -48,12 +48,19 @@ const (
 	identRx = `[\pL_][\pL_0-9]*`
 
 	// Regexp for URLs
-	protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero`
-	hostPart = `[a-zA-Z0-9_@\-]+`
-	filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
-	urlRx    = `(` + protocol + `)://` +   // http://
-		hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
-		filePart + `([:.,;]` + filePart + `)*`
+	// Match parens, and check in pairedParensPrefixLen for balance - see #5043
+	// Match .,:;?! within path, but not at end - see #18139, #16565
+	// This excludes some rare yet valid urls ending in common punctuation
+	// in order to allow sentences ending in URLs.
+
+	// protocol (required) e.g. http
+	protoPart = `(https?|ftp|file|gopher|mailto|nntp)`
+	// host (required) e.g. www.example.com or [::1]:8080
+	hostPart = `([a-zA-Z0-9_@\-.\[\]:]+)`
+	// path+query+fragment (optional) e.g. /path/index.html?q=foo#bar
+	pathPart = `([.,:;?!]*[a-zA-Z0-9$'()*+&#=@~_/\-\[\]%])*`
+
+	urlRx = protoPart + `://` + hostPart + pathPart
 )
 
 var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
diff --git a/src/go/doc/comment_test.go b/src/go/doc/comment_test.go
index 76dfbea..0523ab8 100644
--- a/src/go/doc/comment_test.go
+++ b/src/go/doc/comment_test.go
@@ -150,6 +150,12 @@ func TestToText(t *testing.T) {
 var emphasizeTests = []struct {
 	in, out string
 }{
+	{"http://[::1]:8080/foo.txt", `<a href="http://[::1]:8080/foo.txt">http://[::1]:8080/foo.txt</a>`},
+	{"before (https://www.google.com) after", `before (<a href="https://www.google.com">https://www.google.com</a>) after`},
+	{"before https://www.google.com:30/x/y/z:b::c. After", `before <a href="https://www.google.com:30/x/y/z:b::c">https://www.google.com:30/x/y/z:b::c</a>. After`},
+	{"http://www.google.com/path/:;!-/?query=%34b#093124", `<a href="http://www.google.com/path/:;!-/?query=%34b#093124">http://www.google.com/path/:;!-/?query=%34b#093124</a>`},
+	{"http://www.google.com/path/:;!-/?query=%34bar#093124", `<a href="http://www.google.com/path/:;!-/?query=%34bar#093124">http://www.google.com/path/:;!-/?query=%34bar#093124</a>`},
+	{"http://www.google.com/index.html! After", `<a href="http://www.google.com/index.html">http://www.google.com/index.html</a>! After`},
 	{"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
 	{"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
 	{"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
diff --git a/src/go/doc/doc_test.go b/src/go/doc/doc_test.go
index 82e6310..ad8ba53 100644
--- a/src/go/doc/doc_test.go
+++ b/src/go/doc/doc_test.go
@@ -25,7 +25,7 @@ var files = flag.String("files", "", "consider only Go test files matching this
 
 const dataDir = "testdata"
 
-var templateTxt *template.Template
+var templateTxt = readTemplate("template.txt")
 
 func readTemplate(filename string) *template.Template {
 	t := template.New(filename)
@@ -96,9 +96,6 @@ func test(t *testing.T, mode Mode) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	if templateTxt == nil {
-		templateTxt = readTemplate("template.txt")
-	}
 
 	// test packages
 	for _, pkg := range pkgs {
diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go
index 4a12b1e..da9ea1f 100644
--- a/src/go/doc/exports.go
+++ b/src/go/doc/exports.go
@@ -150,7 +150,7 @@ func (r *reader) filterType(parent *namedType, typ ast.Expr) {
 	}
 }
 
-func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
+func (r *reader) filterSpec(spec ast.Spec) bool {
 	switch s := spec.(type) {
 	case *ast.ImportSpec:
 		// always keep imports so we can collect them
@@ -215,7 +215,7 @@ func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
 
 	j := 0
 	for _, s := range list {
-		if r.filterSpec(s, tok) {
+		if r.filterSpec(s) {
 			list[j] = s
 			j++
 		}
diff --git a/src/go/format/internal.go b/src/go/format/internal.go
index b8b470d..4918681 100644
--- a/src/go/format/internal.go
+++ b/src/go/format/internal.go
@@ -37,14 +37,14 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 
 	// If this is a declaration list, make it a source file
 	// by inserting a package clause.
-	// Insert using a ;, not a newline, so that the line numbers
+	// Insert using a ';', not a newline, so that the line numbers
 	// in psrc match the ones in src.
 	psrc := append([]byte("package p;"), src...)
 	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
 	if err == nil {
 		sourceAdj = func(src []byte, indent int) []byte {
 			// Remove the package clause.
-			// Gofmt has turned the ; into a \n.
+			// Gofmt has turned the ';' into a '\n'.
 			src = src[indent+len("package p\n"):]
 			return bytes.TrimSpace(src)
 		}
@@ -60,7 +60,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.
-	// Insert using a ;, not a newline, so that the line numbers
+	// Insert using a ';', not a newline, so that the line numbers
 	// in fsrc match the ones in src. Add an extra '\n' before the '}'
 	// to make sure comments are flushed before the '}'.
 	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}')
@@ -72,7 +72,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 				indent = 0
 			}
 			// Remove the wrapping.
-			// Gofmt has turned the ; into a \n\n.
+			// Gofmt has turned the ';' into a '\n'.
 			// There will be two non-blank lines with indent, hence 2*indent.
 			src = src[2*indent+len("package p\n\nfunc _() {"):]
 			// Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway
diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go
index f655bc1..fab6518 100644
--- a/src/go/importer/importer.go
+++ b/src/go/importer/importer.go
@@ -6,8 +6,11 @@
 package importer
 
 import (
+	"go/build"
 	"go/internal/gccgoimporter"
 	"go/internal/gcimporter"
+	"go/internal/srcimporter"
+	"go/token"
 	"go/types"
 	"io"
 	"runtime"
@@ -17,22 +20,30 @@ import (
 // a given import path, or an error if no matching package is found.
 type Lookup func(path string) (io.ReadCloser, error)
 
-// For returns an Importer for the given compiler and lookup interface,
-// or nil. Supported compilers are "gc", and "gccgo". If lookup is nil,
-// the default package lookup mechanism for the given compiler is used.
+// For returns an Importer for importing from installed packages
+// for the compilers "gc" and "gccgo", or for importing directly
+// from the source if the compiler argument is "source". In this
+// latter case, importing may fail under circumstances where the
+// exported API is not entirely defined in pure Go source code
+// (if the package API depends on cgo-defined entities, the type
+// checker won't have access to those).
+//
+// If lookup is nil, the default package lookup mechanism for the
+// given compiler is used.
+//
 // BUG(issue13847): For does not support non-nil lookup functions.
 func For(compiler string, lookup Lookup) types.Importer {
 	switch compiler {
 	case "gc":
 		if lookup != nil {
-			panic("gc importer for custom import path lookup not yet implemented")
+			panic("gc importer for custom import path lookup not supported (issue #13847).")
 		}
 
 		return make(gcimports)
 
 	case "gccgo":
 		if lookup != nil {
-			panic("gccgo importer for custom import path lookup not yet implemented")
+			panic("gccgo importer for custom import path lookup not supported (issue #13847).")
 		}
 
 		var inst gccgoimporter.GccgoInstallation
@@ -43,6 +54,13 @@ func For(compiler string, lookup Lookup) types.Importer {
 			packages: make(map[string]*types.Package),
 			importer: inst.GetImporter(nil, nil),
 		}
+
+	case "source":
+		if lookup != nil {
+			panic("source importer for custom import path lookup not supported (issue #13847).")
+		}
+
+		return srcimporter.New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
 	}
 
 	// compiler not supported
@@ -55,7 +73,7 @@ func Default() types.Importer {
 	return For(runtime.Compiler, nil)
 }
 
-// gc support
+// gc importer
 
 type gcimports map[string]*types.Package
 
@@ -70,7 +88,7 @@ func (m gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
 	return gcimporter.Import(m, path, srcDir)
 }
 
-// gccgo support
+// gccgo importer
 
 type gccgoimports struct {
 	packages map[string]*types.Package
diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go
index 2b45470..4fca828 100644
--- a/src/go/internal/gccgoimporter/importer_test.go
+++ b/src/go/internal/gccgoimporter/importer_test.go
@@ -101,6 +101,7 @@ var importerTests = [...]importerTest{
 	{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
 	{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
 	{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+	{pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"},
 }
 
 func TestGoxImporter(t *testing.T) {
diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go
index 3b97c96..8a1ad5f 100644
--- a/src/go/internal/gccgoimporter/parser.go
+++ b/src/go/internal/gccgoimporter/parser.go
@@ -370,27 +370,41 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
 	return types.NewConst(token.NoPos, pkg, name, typ, val)
 }
 
-// TypeName = ExportedName .
-func (p *parser) parseTypeName() *types.TypeName {
+// NamedType = TypeName [ "=" ] Type { Method } .
+// TypeName  = ExportedName .
+// Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
+func (p *parser) parseNamedType(n int) types.Type {
 	pkg, name := p.parseExportedName()
 	scope := pkg.Scope()
-	if obj := scope.Lookup(name); obj != nil {
-		return obj.(*types.TypeName)
+
+	if p.tok == '=' {
+		// type alias
+		p.next()
+		typ := p.parseType(pkg)
+		if obj := scope.Lookup(name); obj != nil {
+			typ = obj.Type() // use previously imported type
+			if typ == nil {
+				p.errorf("%v (type alias) used in cycle", obj)
+			}
+		} else {
+			obj = types.NewTypeName(token.NoPos, pkg, name, typ)
+			scope.Insert(obj)
+		}
+		p.typeMap[n] = typ
+		return typ
 	}
-	obj := types.NewTypeName(token.NoPos, pkg, name, nil)
-	// a named type may be referred to before the underlying type
-	// is known - set it up
-	types.NewNamed(obj, nil, nil)
-	scope.Insert(obj)
-	return obj
-}
 
-// NamedType = TypeName Type { Method } .
-// Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
-func (p *parser) parseNamedType(n int) types.Type {
-	obj := p.parseTypeName()
+	// named type
+	obj := scope.Lookup(name)
+	if obj == nil {
+		// a named type may be referred to before the underlying type
+		// is known - set it up
+		tname := types.NewTypeName(token.NoPos, pkg, name, nil)
+		types.NewNamed(tname, nil, nil)
+		scope.Insert(tname)
+		obj = tname
+	}
 
-	pkg := obj.Pkg()
 	typ := obj.Type()
 	p.typeMap[n] = typ
 
@@ -409,8 +423,8 @@ func (p *parser) parseNamedType(n int) types.Type {
 		nt.SetUnderlying(underlying.Underlying())
 	}
 
+	// collect associated methods
 	for p.tok == scanner.Ident {
-		// collect associated methods
 		p.expectKeyword("func")
 		p.expect('(')
 		receiver, _ := p.parseParam(pkg)
@@ -725,7 +739,7 @@ func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
 		case ';':
 			return
 		case '<':
-			p.parseType(p.pkg)
+			p.parseType(pkg)
 		case scanner.EOF:
 			p.error("unexpected EOF")
 		default:
diff --git a/src/go/internal/gccgoimporter/testdata/alias.gox b/src/go/internal/gccgoimporter/testdata/alias.gox
new file mode 100644
index 0000000..ced7d84
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/alias.gox
@@ -0,0 +1,4 @@
+v1;
+package alias;
+pkgpath alias;
+type <type 115 "I1" <type 116 interface { M1 (? <type 117 "IntAlias2" = <type 118 "IntAlias" = <type 119 "Int" <type -11>>>>) < type 114>; M2 () <type 1>; }>>;
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index a8f3490..2045f55 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -19,16 +19,18 @@ import (
 )
 
 type importer struct {
-	imports map[string]*types.Package
-	data    []byte
-	path    string
-	buf     []byte // for reading strings
-	version int    // export format version
+	imports    map[string]*types.Package
+	data       []byte
+	importpath string
+	buf        []byte // for reading strings
+	version    int    // export format version
 
 	// object lists
-	strList       []string         // in order of appearance
-	pkgList       []*types.Package // in order of appearance
-	typList       []types.Type     // in order of appearance
+	strList       []string           // in order of appearance
+	pathList      []string           // in order of appearance
+	pkgList       []*types.Package   // in order of appearance
+	typList       []types.Type       // in order of appearance
+	interfaceList []*types.Interface // for delayed completion only
 	trackAllTypes bool
 
 	// position encoding
@@ -47,24 +49,26 @@ type importer struct {
 // and returns the number of bytes consumed and a reference to the package.
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
-func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, _ *types.Package, err error) {
+func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
 	// catch panics and return them as errors
 	defer func() {
 		if e := recover(); e != nil {
 			// The package (filename) causing the problem is added to this
 			// error by a wrapper in the caller (Import in gcimporter.go).
+			// Return a (possibly nil or incomplete) package unchanged (see #16088).
 			err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e)
 		}
 	}()
 
 	p := importer{
-		imports: imports,
-		data:    data,
-		path:    path,
-		version: -1,           // unknown version
-		strList: []string{""}, // empty string is mapped to 0
-		fset:    fset,
-		files:   make(map[string]*token.File),
+		imports:    imports,
+		data:       data,
+		importpath: path,
+		version:    -1,           // unknown version
+		strList:    []string{""}, // empty string is mapped to 0
+		pathList:   []string{""}, // empty string is mapped to 0
+		fset:       fset,
+		files:      make(map[string]*token.File),
 	}
 
 	// read version info
@@ -98,10 +102,10 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
 	// read version specific flags - extend as necessary
 	switch p.version {
-	// case 4:
+	// case 6:
 	// 	...
 	//	fallthrough
-	case 3, 2, 1:
+	case 5, 4, 3, 2, 1:
 		p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
 		p.trackAllTypes = p.int() != 0
 		p.posInfoFormat = p.int() != 0
@@ -117,7 +121,7 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 	p.typList = append(p.typList, predeclared...)
 
 	// read package data
-	pkg := p.pkg()
+	pkg = p.pkg()
 
 	// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
 	objcount := 0
@@ -138,15 +142,9 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 	// ignore compiler-specific import data
 
 	// complete interfaces
-	for _, typ := range p.typList {
-		// 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()
-		}
+	// TODO(gri) re-investigate if we still need to do this in a delayed fashion
+	for _, typ := range p.interfaceList {
+		typ.Complete()
 	}
 
 	// record all referenced packages as imports
@@ -173,12 +171,17 @@ func (p *importer) pkg() *types.Package {
 
 	// otherwise, i is the package tag (< 0)
 	if i != packageTag {
-		errorf("unexpected package tag %d", i)
+		errorf("unexpected package tag %d version %d", i, p.version)
 	}
 
 	// read package data
 	name := p.string()
-	path := p.string()
+	var path string
+	if p.version >= 5 {
+		path = p.path()
+	} else {
+		path = p.string()
+	}
 
 	// we should never see an empty package name
 	if name == "" {
@@ -193,7 +196,7 @@ func (p *importer) pkg() *types.Package {
 
 	// if the package was imported before, use that one; otherwise create a new one
 	if path == "" {
-		path = p.path
+		path = p.importpath
 	}
 	pkg := p.imports[path]
 	if pkg == nil {
@@ -208,7 +211,6 @@ func (p *importer) pkg() *types.Package {
 }
 
 // objTag returns the tag value for each object kind.
-// obj must not be a *types.Alias.
 func objTag(obj types.Object) int {
 	switch obj.(type) {
 	case *types.Const:
@@ -219,7 +221,6 @@ func objTag(obj types.Object) int {
 		return varTag
 	case *types.Func:
 		return funcTag
-	// Aliases are not exported multiple times, thus we should not see them here.
 	default:
 		errorf("unexpected object: %v (%T)", obj, obj) // panics
 		panic("unreachable")
@@ -237,14 +238,14 @@ func (p *importer) declare(obj types.Object) {
 	pkg := obj.Pkg()
 	if alt := pkg.Scope().Insert(obj); alt != nil {
 		// This can only trigger if we import a (non-type) object a second time.
-		// Excluding aliases, this cannot happen because 1) we only import a package
+		// Excluding type aliases, this cannot 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.
-		// However, aliases require reexporting the original object, so we need
+		// However, type aliases require reexporting the original type, so we need
 		// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
 		// method importer.obj, switch case importing functions).
-		// Note that the original itself cannot be an alias.
+		// TODO(gri) review/update this comment once the gc compiler handles type aliases.
 		if !sameObj(obj, alt) {
 			errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
 		}
@@ -260,6 +261,13 @@ func (p *importer) obj(tag int) {
 		val := p.value()
 		p.declare(types.NewConst(pos, pkg, name, typ, val))
 
+	case aliasTag:
+		// TODO(gri) verify type alias hookup is correct
+		pos := p.pos()
+		pkg, name := p.qualifiedName()
+		typ := p.typ(nil)
+		p.declare(types.NewTypeName(pos, pkg, name, typ))
+
 	case typeTag:
 		p.typ(nil)
 
@@ -277,24 +285,13 @@ func (p *importer) obj(tag int) {
 		sig := types.NewSignature(nil, params, result, isddd)
 		p.declare(types.NewFunc(pos, pkg, name, sig))
 
-	case aliasTag:
-		pos := p.pos()
-		name := p.string()
-		var orig types.Object
-		if pkg, name := p.qualifiedName(); pkg != nil {
-			orig = pkg.Scope().Lookup(name)
-		}
-		// Alias-related code. Keep for now.
-		_ = pos
-		_ = name
-		_ = orig
-		// p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
-
 	default:
 		errorf("unexpected object tag %d", tag)
 	}
 }
 
+const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
+
 func (p *importer) pos() token.Pos {
 	if !p.posInfoFormat {
 		return token.NoPos
@@ -302,15 +299,26 @@ func (p *importer) pos() token.Pos {
 
 	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()
+	delta := p.int()
+	line += delta
+	if p.version >= 5 {
+		if delta == deltaNewFile {
+			if n := p.int(); n >= 0 {
+				// file changed
+				file = p.path()
+				line = n
+			}
+		}
+	} else {
+		if delta == 0 {
+			if n := p.int(); n >= 0 {
+				// file changed
+				file = p.prevFile[:n] + p.string()
+				line = p.int()
+			}
+		}
 	}
+	p.prevFile = file
 	p.prevLine = line
 
 	// Synthesize a token.Pos
@@ -349,9 +357,7 @@ var (
 
 func (p *importer) qualifiedName() (pkg *types.Package, name string) {
 	name = p.string()
-	if name != "" {
-		pkg = p.pkg()
-	}
+	pkg = p.pkg()
 	return
 }
 
@@ -501,12 +507,14 @@ func (p *importer) typ(parent *types.Package) types.Type {
 			p.record(nil)
 		}
 
-		// no embedded interfaces with gc compiler
-		if p.int() != 0 {
-			errorf("unexpected embedded interface")
+		var embeddeds []*types.Named
+		for n := p.int(); n > 0; n-- {
+			p.pos()
+			embeddeds = append(embeddeds, p.typ(parent).(*types.Named))
 		}
 
-		t := types.NewInterface(p.methodList(parent), nil)
+		t := types.NewInterface(p.methodList(parent), embeddeds)
+		p.interfaceList = append(p.interfaceList, t)
 		if p.trackAllTypes {
 			p.typList[n] = t
 		}
@@ -556,17 +564,17 @@ func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags [
 		fields = make([]*types.Var, n)
 		tags = make([]string, n)
 		for i := range fields {
-			fields[i] = p.field(parent)
-			tags[i] = p.string()
+			fields[i], tags[i] = p.field(parent)
 		}
 	}
 	return
 }
 
-func (p *importer) field(parent *types.Package) *types.Var {
+func (p *importer) field(parent *types.Package) (*types.Var, string) {
 	pos := p.pos()
-	pkg, name := p.fieldName(parent)
+	pkg, name, alias := p.fieldName(parent)
 	typ := p.typ(parent)
+	tag := p.string()
 
 	anonymous := false
 	if name == "" {
@@ -578,12 +586,15 @@ func (p *importer) field(parent *types.Package) *types.Var {
 		case *types.Named:
 			name = typ.Obj().Name()
 		default:
-			errorf("anonymous field expected")
+			errorf("named base type expected")
 		}
 		anonymous = true
+	} else if alias {
+		// anonymous field: we have an explicit name because it's an alias
+		anonymous = true
 	}
 
-	return types.NewField(pos, pkg, name, typ, anonymous)
+	return types.NewField(pos, pkg, name, typ, anonymous), tag
 }
 
 func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
@@ -598,31 +609,42 @@ func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
 
 func (p *importer) method(parent *types.Package) *types.Func {
 	pos := p.pos()
-	pkg, name := p.fieldName(parent)
+	pkg, name, _ := p.fieldName(parent)
 	params, isddd := p.paramList()
 	result, _ := p.paramList()
 	sig := types.NewSignature(nil, params, result, isddd)
 	return types.NewFunc(pos, pkg, name, sig)
 }
 
-func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
-	name := p.string()
-	pkg := parent
+func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) {
+	name = p.string()
+	pkg = parent
 	if pkg == nil {
 		// use the imported package instead
 		pkg = p.pkgList[0]
 	}
 	if p.version == 0 && name == "_" {
 		// version 0 didn't export a package for _ fields
-		return pkg, name
-	}
-	if name != "" && !exported(name) {
-		if name == "?" {
-			name = ""
-		}
+		return
+	}
+	switch name {
+	case "":
+		// 1) field name matches base type name and is exported: nothing to do
+	case "?":
+		// 2) field name matches base type name and is not exported: need package
+		name = ""
 		pkg = p.pkg()
+	case "@":
+		// 3) field name doesn't match type name (alias)
+		name = p.string()
+		alias = true
+		fallthrough
+	default:
+		if !exported(name) {
+			pkg = p.pkg()
+		}
 	}
-	return pkg, name
+	return
 }
 
 func (p *importer) paramList() (*types.Tuple, bool) {
@@ -774,6 +796,26 @@ func (p *importer) int64() int64 {
 	return p.rawInt64()
 }
 
+func (p *importer) path() string {
+	if p.debugFormat {
+		p.marker('p')
+	}
+	// if the path was seen before, i is its index (>= 0)
+	// (the empty string is at index 0)
+	i := p.rawInt64()
+	if i >= 0 {
+		return p.pathList[i]
+	}
+	// otherwise, i is the negative path length (< 0)
+	a := make([]string, -i)
+	for n := range a {
+		a[n] = p.string()
+	}
+	s := strings.Join(a, "/")
+	p.pathList = append(p.pathList, s)
+	return s
+}
+
 func (p *importer) string() string {
 	if p.debugFormat {
 		p.marker('s')
@@ -893,7 +935,7 @@ const (
 	nilTag     // only used by gc (appears in exported inlined function bodies)
 	unknownTag // not used by gc (only appears in packages with errors)
 
-	// Aliases
+	// Type aliases
 	aliasTag
 )
 
@@ -917,7 +959,7 @@ var predeclared = []types.Type{
 	types.Typ[types.Complex128],
 	types.Typ[types.String],
 
-	// aliases
+	// basic type aliases
 	types.Universe.Lookup("byte").Type(),
 	types.Universe.Lookup("rune").Type(),
 
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index f99f0f8..f3f90f2 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -43,6 +43,7 @@ func FindPkg(path, srcDir string) (filename, id string) {
 		}
 		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
 		if bp.PkgObj == "" {
+			id = path // make sure we have an id to print in error message
 			return
 		}
 		noext = strings.TrimSuffix(bp.PkgObj, ".a")
@@ -89,7 +90,7 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
 		if path == "unsafe" {
 			return types.Unsafe, nil
 		}
-		err = fmt.Errorf("can't find import: %s", id)
+		err = fmt.Errorf("can't find import: %q", id)
 		return
 	}
 
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index a0697fa..c34f07c 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -92,7 +92,6 @@ func TestImportTestdata(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
@@ -124,7 +123,6 @@ func TestVersionHandling(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	const dir = "./testdata/versions"
@@ -188,7 +186,6 @@ func TestImportStdLib(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	dt := maxTime
@@ -205,7 +202,7 @@ var importedObjectTests = []struct {
 }{
 	{"math.Pi", "const Pi untyped float"},
 	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
-	{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
+	{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
 	{"math.Sin", "func Sin(x float64) float64"},
 	// TODO(gri) add more tests
 }
@@ -216,7 +213,6 @@ func TestImportedTypes(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	for _, test := range importedObjectTests {
@@ -252,13 +248,9 @@ func TestIssue5815(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
-	pkg, err := Import(make(map[string]*types.Package), "strings", ".")
-	if err != nil {
-		t.Fatal(err)
-	}
+	pkg := importPkg(t, "strings")
 
 	scope := pkg.Scope()
 	for _, name := range scope.Names() {
@@ -285,7 +277,6 @@ func TestCorrectMethodPackage(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	imports := make(map[string]*types.Package)
@@ -309,7 +300,6 @@ func TestIssue13566(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -326,10 +316,7 @@ func TestIssue13566(t *testing.T) {
 	}
 
 	// import must succeed (test for issue at hand)
-	pkg, err := Import(make(map[string]*types.Package), "./testdata/b", ".")
-	if err != nil {
-		t.Fatal(err)
-	}
+	pkg := importPkg(t, "./testdata/b")
 
 	// make sure all indirectly imported packages have names
 	for _, imp := range pkg.Imports() {
@@ -345,7 +332,6 @@ func TestIssue13898(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// import go/internal/gcimporter which imports go/types partially
@@ -368,10 +354,7 @@ func TestIssue13898(t *testing.T) {
 	}
 
 	// look for go/types.Object type
-	obj := goTypesPkg.Scope().Lookup("Object")
-	if obj == nil {
-		t.Fatal("go/types.Object not found")
-	}
+	obj := lookupObj(t, goTypesPkg.Scope(), "Object")
 	typ, ok := obj.Type().(*types.Named)
 	if !ok {
 		t.Fatalf("go/types.Object type is %v; wanted named type", typ)
@@ -395,7 +378,6 @@ func TestIssue15517(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -434,7 +416,6 @@ func TestIssue15920(t *testing.T) {
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -447,8 +428,47 @@ func TestIssue15920(t *testing.T) {
 		defer os.Remove(f)
 	}
 
-	imports := make(map[string]*types.Package)
-	if _, err := Import(imports, "./testdata/issue15920", "."); err != nil {
+	importPkg(t, "./testdata/issue15920")
+}
+
+func TestIssue20046(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)
+	}
+
+	// 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", "issue20046.go"); f != "" {
+		defer os.Remove(f)
+	}
+
+	// "./issue20046".V.M must exist
+	pkg := importPkg(t, "./testdata/issue20046")
+	obj := lookupObj(t, pkg.Scope(), "V")
+	if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
+		t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
+	}
+}
+
+func importPkg(t *testing.T, path string) *types.Package {
+	pkg, err := Import(make(map[string]*types.Package), path, ".")
+	if err != nil {
 		t.Fatal(err)
 	}
+	return pkg
+}
+
+func lookupObj(t *testing.T, scope *types.Scope, name string) types.Object {
+	if obj := scope.Lookup(name); obj != nil {
+		return obj
+	}
+	t.Fatalf("%s not found", name)
+	return nil
 }
diff --git a/src/go/internal/gcimporter/testdata/issue20046.go b/src/go/internal/gcimporter/testdata/issue20046.go
new file mode 100644
index 0000000..c63ee82
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/issue20046.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. 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 V interface {
+	M()
+}
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.8_4.a b/src/go/internal/gcimporter/testdata/versions/test_go1.8_4.a
new file mode 100644
index 0000000..26b8531
Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.8_4.a differ
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.8_5.a b/src/go/internal/gcimporter/testdata/versions/test_go1.8_5.a
new file mode 100644
index 0000000..60e52ef
Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.8_5.a differ
diff --git a/src/go/internal/srcimporter/srcimporter.go b/src/go/internal/srcimporter/srcimporter.go
new file mode 100644
index 0000000..f259493
--- /dev/null
+++ b/src/go/internal/srcimporter/srcimporter.go
@@ -0,0 +1,208 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package srcimporter implements importing directly
+// from source files rather than installed packages.
+package srcimporter // import "go/internal/srcimporter"
+
+import (
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"path/filepath"
+	"sync"
+)
+
+// An Importer provides the context for importing packages from source code.
+type Importer struct {
+	ctxt     *build.Context
+	fset     *token.FileSet
+	sizes    types.Sizes
+	packages map[string]*types.Package
+}
+
+// NewImporter returns a new Importer for the given context, file set, and map
+// of packages. The context is used to resolve import paths to package paths,
+// and identifying the files belonging to the package. If the context provides
+// non-nil file system functions, they are used instead of the regular package
+// os functions. The file set is used to track position information of package
+// files; and imported packages are added to the packages map.
+func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Package) *Importer {
+	return &Importer{
+		ctxt:     ctxt,
+		fset:     fset,
+		sizes:    types.SizesFor(ctxt.Compiler, ctxt.GOARCH), // uses go/types default if GOARCH not found
+		packages: packages,
+	}
+}
+
+// Importing is a sentinel taking the place in Importer.packages
+// for a package that is in the process of being imported.
+var importing types.Package
+
+// Import(path) is a shortcut for ImportFrom(path, "", 0).
+func (p *Importer) Import(path string) (*types.Package, error) {
+	return p.ImportFrom(path, "", 0)
+}
+
+// ImportFrom imports the package with the given import path resolved from the given srcDir,
+// adds the new package to the set of packages maintained by the importer, and returns the
+// package. Package path resolution and file system operations are controlled by the context
+// maintained with the importer. The import mode must be zero but is otherwise ignored.
+// Packages that are not comprised entirely of pure Go files may fail to import because the
+// type checker may not be able to determine all exported entities (e.g. due to cgo dependencies).
+func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
+	if mode != 0 {
+		panic("non-zero import mode")
+	}
+
+	// determine package path (do vendor resolution)
+	var bp *build.Package
+	var err error
+	switch {
+	default:
+		if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
+			srcDir = abs
+		}
+		bp, err = p.ctxt.Import(path, srcDir, build.FindOnly)
+
+	case build.IsLocalImport(path):
+		// "./x" -> "srcDir/x"
+		bp, err = p.ctxt.ImportDir(filepath.Join(srcDir, path), build.FindOnly)
+
+	case p.isAbsPath(path):
+		return nil, fmt.Errorf("invalid absolute import path %q", path)
+	}
+	if err != nil {
+		return nil, err // err may be *build.NoGoError - return as is
+	}
+
+	// package unsafe is known to the type checker
+	if bp.ImportPath == "unsafe" {
+		return types.Unsafe, nil
+	}
+
+	// no need to re-import if the package was imported completely before
+	pkg := p.packages[bp.ImportPath]
+	if pkg != nil {
+		if pkg == &importing {
+			return nil, fmt.Errorf("import cycle through package %q", bp.ImportPath)
+		}
+		if !pkg.Complete() {
+			// Package exists but is not complete - we cannot handle this
+			// at the moment since the source importer replaces the package
+			// wholesale rather than augmenting it (see #19337 for details).
+			// Return incomplete package with error (see #16088).
+			return pkg, fmt.Errorf("reimported partially imported package %q", bp.ImportPath)
+		}
+		return pkg, nil
+	}
+
+	p.packages[bp.ImportPath] = &importing
+	defer func() {
+		// clean up in case of error
+		// TODO(gri) Eventually we may want to leave a (possibly empty)
+		// package in the map in all cases (and use that package to
+		// identify cycles). See also issue 16088.
+		if p.packages[bp.ImportPath] == &importing {
+			p.packages[bp.ImportPath] = nil
+		}
+	}()
+
+	// collect package files
+	bp, err = p.ctxt.ImportDir(bp.Dir, 0)
+	if err != nil {
+		return nil, err // err may be *build.NoGoError - return as is
+	}
+	var filenames []string
+	filenames = append(filenames, bp.GoFiles...)
+	filenames = append(filenames, bp.CgoFiles...)
+
+	files, err := p.parseFiles(bp.Dir, filenames)
+	if err != nil {
+		return nil, err
+	}
+
+	// type-check package files
+	conf := types.Config{
+		IgnoreFuncBodies: true,
+		FakeImportC:      true,
+		Importer:         p,
+		Sizes:            p.sizes,
+	}
+	pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil)
+	if err != nil {
+		// return (possibly nil or incomplete) package with error (see #16088)
+		return pkg, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err)
+	}
+
+	p.packages[bp.ImportPath] = pkg
+	return pkg, nil
+}
+
+func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, error) {
+	open := p.ctxt.OpenFile // possibly nil
+
+	files := make([]*ast.File, len(filenames))
+	errors := make([]error, len(filenames))
+
+	var wg sync.WaitGroup
+	wg.Add(len(filenames))
+	for i, filename := range filenames {
+		go func(i int, filepath string) {
+			defer wg.Done()
+			if open != nil {
+				src, err := open(filepath)
+				if err != nil {
+					errors[i] = fmt.Errorf("opening package file %s failed (%v)", filepath, err)
+					return
+				}
+				files[i], errors[i] = parser.ParseFile(p.fset, filepath, src, 0)
+				src.Close() // ignore Close error - parsing may have succeeded which is all we need
+			} else {
+				// Special-case when ctxt doesn't provide a custom OpenFile and use the
+				// parser's file reading mechanism directly. This appears to be quite a
+				// bit faster than opening the file and providing an io.ReaderCloser in
+				// both cases.
+				// TODO(gri) investigate performance difference (issue #19281)
+				files[i], errors[i] = parser.ParseFile(p.fset, filepath, nil, 0)
+			}
+		}(i, p.joinPath(dir, filename))
+	}
+	wg.Wait()
+
+	// if there are errors, return the first one for deterministic results
+	for _, err := range errors {
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return files, nil
+}
+
+// context-controlled file system operations
+
+func (p *Importer) absPath(path string) (string, error) {
+	// TODO(gri) This should be using p.ctxt.AbsPath which doesn't
+	// exist but probably should. See also issue #14282.
+	return filepath.Abs(path)
+}
+
+func (p *Importer) isAbsPath(path string) bool {
+	if f := p.ctxt.IsAbsPath; f != nil {
+		return f(path)
+	}
+	return filepath.IsAbs(path)
+}
+
+func (p *Importer) joinPath(elem ...string) string {
+	if f := p.ctxt.JoinPath; f != nil {
+		return f(elem...)
+	}
+	return filepath.Join(elem...)
+}
diff --git a/src/go/internal/srcimporter/srcimporter_test.go b/src/go/internal/srcimporter/srcimporter_test.go
new file mode 100644
index 0000000..79921b5
--- /dev/null
+++ b/src/go/internal/srcimporter/srcimporter_test.go
@@ -0,0 +1,150 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package srcimporter
+
+import (
+	"go/build"
+	"go/token"
+	"go/types"
+	"internal/testenv"
+	"io/ioutil"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+)
+
+const maxTime = 2 * time.Second
+
+var importer = New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
+
+func doImport(t *testing.T, path, srcDir string) {
+	t0 := time.Now()
+	if _, err := importer.ImportFrom(path, srcDir, 0); err != nil {
+		// don't report an error if there's no buildable Go files
+		if _, nogo := err.(*build.NoGoError); !nogo {
+			t.Errorf("import %q failed (%v)", path, err)
+		}
+		return
+	}
+	t.Logf("import %q: %v", path, time.Since(t0))
+}
+
+// walkDir imports the all the packages with the given path
+// prefix recursively. It returns the number of packages
+// imported and whether importing was aborted because time
+// has passed endTime.
+func walkDir(t *testing.T, path string, endTime time.Time) (int, bool) {
+	if time.Now().After(endTime) {
+		t.Log("testing time used up")
+		return 0, true
+	}
+
+	// ignore fake packages and testdata directories
+	if path == "builtin" || path == "unsafe" || strings.HasSuffix(path, "testdata") {
+		return 0, false
+	}
+
+	list, err := ioutil.ReadDir(filepath.Join(runtime.GOROOT(), "src", path))
+	if err != nil {
+		t.Fatalf("walkDir %s failed (%v)", path, err)
+	}
+
+	nimports := 0
+	hasGoFiles := false
+	for _, f := range list {
+		if f.IsDir() {
+			n, abort := walkDir(t, filepath.Join(path, f.Name()), endTime)
+			nimports += n
+			if abort {
+				return nimports, true
+			}
+		} else if strings.HasSuffix(f.Name(), ".go") {
+			hasGoFiles = true
+		}
+	}
+
+	if hasGoFiles {
+		doImport(t, path, "")
+		nimports++
+	}
+
+	return nimports, false
+}
+
+func TestImportStdLib(t *testing.T) {
+	if !testenv.HasSrc() {
+		t.Skip("no source code available")
+	}
+
+	dt := maxTime
+	if testing.Short() && testenv.Builder() == "" {
+		dt = 500 * time.Millisecond
+	}
+	nimports, _ := walkDir(t, "", time.Now().Add(dt)) // installed packages
+	t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+	name string
+	want string
+}{
+	{"flag.Bool", "func Bool(name string, value bool, usage string) *bool"},
+	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+	{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"}, // go/types.gcCompatibilityMode is off => interface not flattened
+	{"math.Pi", "const Pi untyped float"},
+	{"math.Sin", "func Sin(x float64) float64"},
+	{"math/big.Int", "type Int struct{neg bool; abs nat}"},
+	{"golang_org/x/text/unicode/norm.MaxSegmentSize", "const MaxSegmentSize untyped int"},
+}
+
+func TestImportedTypes(t *testing.T) {
+	if !testenv.HasSrc() {
+		t.Skip("no source code available")
+	}
+
+	for _, test := range importedObjectTests {
+		s := strings.Split(test.name, ".")
+		if len(s) != 2 {
+			t.Fatal("invalid test data format")
+		}
+		importPath := s[0]
+		objName := s[1]
+
+		pkg, err := importer.ImportFrom(importPath, ".", 0)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+
+		obj := pkg.Scope().Lookup(objName)
+		if obj == nil {
+			t.Errorf("%s: object not found", test.name)
+			continue
+		}
+
+		got := types.ObjectString(obj, types.RelativeTo(pkg))
+		if got != test.want {
+			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+		}
+	}
+}
+
+func TestReimport(t *testing.T) {
+	if !testenv.HasSrc() {
+		t.Skip("no source code available")
+	}
+
+	// Reimporting a partially imported (incomplete) package is not supported (see issue #19337).
+	// Make sure we recognize the situation and report an error.
+
+	mathPkg := types.NewPackage("math", "math") // incomplete package
+	importer := New(&build.Default, token.NewFileSet(), map[string]*types.Package{mathPkg.Path(): mathPkg})
+	_, err := importer.ImportFrom("math", ".", 0)
+	if err == nil || !strings.HasPrefix(err.Error(), "reimport") {
+		t.Errorf("got %v; want reimport error", err)
+	}
+}
diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go
index 1a08d5a..ef91e1e 100644
--- a/src/go/parser/error_test.go
+++ b/src/go/parser/error_test.go
@@ -66,7 +66,7 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
 // expectedErrors collects the regular expressions of ERROR comments found
 // in files and returns them as a map of error positions to error messages.
 //
-func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
+func expectedErrors(fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
 	errors := make(map[token.Pos]string)
 
 	var s scanner.Scanner
@@ -161,7 +161,7 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
 
 	// we are expecting the following errors
 	// (collect these after parsing a file so that it is found in the file set)
-	expected := expectedErrors(t, fset, filename, src)
+	expected := expectedErrors(fset, filename, src)
 
 	// verify errors returned by the parser
 	compareErrors(t, fset, expected, found)
diff --git a/src/go/parser/example_test.go b/src/go/parser/example_test.go
index 3c58e63..c2f7f29 100644
--- a/src/go/parser/example_test.go
+++ b/src/go/parser/example_test.go
@@ -13,9 +13,19 @@ import (
 func ExampleParseFile() {
 	fset := token.NewFileSet() // positions are relative to fset
 
-	// Parse the file containing this very example
-	// but stop after processing the imports.
-	f, err := parser.ParseFile(fset, "example_test.go", nil, parser.ImportsOnly)
+	src := `package foo
+
+import (
+	"fmt"
+	"time"
+)
+
+func bar() {
+	fmt.Println(time.Now())
+}`
+
+	// Parse src but stop after processing the imports.
+	f, err := parser.ParseFile(fset, "", src, parser.ImportsOnly)
 	if err != nil {
 		fmt.Println(err)
 		return
@@ -29,6 +39,5 @@ func ExampleParseFile() {
 	// output:
 	//
 	// "fmt"
-	// "go/parser"
-	// "go/token"
+	// "time"
 }
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index d3ef7db..1b4309b 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -327,7 +327,7 @@ func (p *parser) next() {
 			// The comment is on same line as the previous token; it
 			// cannot be a lead comment but may be a line comment.
 			comment, endline = p.consumeCommentGroup(0)
-			if p.file.Line(p.pos) != endline {
+			if p.file.Line(p.pos) != endline || p.tok == token.EOF {
 				// The next token is on a different line, thus
 				// the last comment group is a line comment.
 				p.lineComment = comment
@@ -2327,7 +2327,10 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.
 	// (Global identifiers are resolved in a separate phase after parsing.)
 	spec := &ast.TypeSpec{Doc: doc, Name: ident}
 	p.declare(spec, nil, p.topScope, ast.Typ, ident)
-
+	if p.tok == token.ASSIGN {
+		spec.Assign = p.pos
+		p.next()
+	}
 	spec.Type = p.parseType()
 	p.expectSemi() // call before accessing p.linecomment
 	spec.Comment = p.lineComment
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index c7bb36d..fb35a88 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -531,3 +531,18 @@ func TestIncompleteSelection(t *testing.T) {
 		}
 	}
 }
+
+func TestLastLineComment(t *testing.T) {
+	const src = `package main
+type x int // comment
+`
+	fset := token.NewFileSet()
+	f, err := ParseFile(fset, "", src, ParseComments)
+	if err != nil {
+		t.Fatal(err)
+	}
+	comment := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Comment.List[0].Text
+	if comment != "// comment" {
+		t.Errorf("got %q, want %q", comment, "// comment")
+	}
+}
diff --git a/src/go/parser/performance_test.go b/src/go/parser/performance_test.go
index b2e1c11..f2732c0 100644
--- a/src/go/parser/performance_test.go
+++ b/src/go/parser/performance_test.go
@@ -10,12 +10,17 @@ import (
 	"testing"
 )
 
-func BenchmarkParse(b *testing.B) {
-	src, err := ioutil.ReadFile("parser.go")
+var src = readFile("parser.go")
+
+func readFile(filename string) []byte {
+	data, err := ioutil.ReadFile(filename)
 	if err != nil {
-		b.Fatal(err)
+		panic(err)
 	}
-	b.ResetTimer()
+	return data
+}
+
+func BenchmarkParse(b *testing.B) {
 	b.SetBytes(int64(len(src)))
 	for i := 0; i < b.N; i++ {
 		if _, err := ParseFile(token.NewFileSet(), "", src, ParseComments); err != nil {
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index cdd343e..6f8ef6b 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -46,6 +46,8 @@ var valids = []string{
 	`package p; const (x = 0; y; z)`, // issue 9639
 	`package p; var _ = map[P]int{P{}:0, {}:1}`,
 	`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
+	`package p; type T = int`,
+	`package p; type (T = p.T; _ = struct{}; x = *T)`,
 }
 
 func TestValid(t *testing.T) {
diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
index ea43286..bea4ff2 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -887,8 +887,6 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 	default:
 		panic("unreachable")
 	}
-
-	return
 }
 
 func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
@@ -1268,8 +1266,6 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
 	default:
 		panic("unreachable")
 	}
-
-	return
 }
 
 // ----------------------------------------------------------------------------
@@ -1447,6 +1443,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
 		} else {
 			p.print(vtab)
 		}
+		if s.Assign.IsValid() {
+			p.print(token.ASSIGN, blank)
+		}
 		p.expr(s.Type)
 		p.setComment(s.Comment)
 
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index be61dad..57f9716 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -69,7 +69,7 @@ type printer struct {
 	// The out position differs from the pos position when the result
 	// formatting differs from the source formatting (in the amount of
 	// white space). If there's a difference and SourcePos is set in
-	// ConfigMode, //line comments are used in the output to restore
+	// ConfigMode, //line directives are used in the output to restore
 	// original source positions for a reader.
 	pos     token.Position // current position in AST (source) space
 	out     token.Position // current position in output space
@@ -203,19 +203,20 @@ func (p *printer) lineFor(pos token.Pos) int {
 	return p.cachedLine
 }
 
-// atLineBegin emits a //line comment if necessary and prints indentation.
-func (p *printer) atLineBegin(pos token.Position) {
-	// write a //line comment if necessary
-	if p.Config.Mode&SourcePos != 0 && pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
+// writeLineDirective writes a //line directive if necessary.
+func (p *printer) writeLineDirective(pos token.Position) {
+	if pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
 		p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation
 		p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...)
 		p.output = append(p.output, tabwriter.Escape)
-		// p.out must match the //line comment
+		// p.out must match the //line directive
 		p.out.Filename = pos.Filename
 		p.out.Line = pos.Line
 	}
+}
 
-	// write indentation
+// writeIndent writes indentation.
+func (p *printer) writeIndent() {
 	// use "hard" htabs - indentation columns
 	// must not be discarded by the tabwriter
 	n := p.Config.Indent + p.indent // include base indentation
@@ -230,9 +231,11 @@ func (p *printer) atLineBegin(pos token.Position) {
 }
 
 // writeByte writes ch n times to p.output and updates p.pos.
+// Only used to write formatting (white space) characters.
 func (p *printer) writeByte(ch byte, n int) {
 	if p.out.Column == 1 {
-		p.atLineBegin(p.pos)
+		// no need to write line directives before white space
+		p.writeIndent()
 	}
 
 	for i := 0; i < n; i++ {
@@ -265,13 +268,16 @@ func (p *printer) writeByte(ch byte, n int) {
 //
 func (p *printer) writeString(pos token.Position, s string, isLit bool) {
 	if p.out.Column == 1 {
-		p.atLineBegin(pos)
+		if p.Config.Mode&SourcePos != 0 {
+			p.writeLineDirective(pos)
+		}
+		p.writeIndent()
 	}
 
 	if pos.IsValid() {
 		// update p.pos (if pos is invalid, continue with existing p.pos)
 		// Note: Must do this after handling line beginnings because
-		// atLineBegin updates p.pos if there's indentation, but p.pos
+		// writeIndent updates p.pos if there's indentation, but p.pos
 		// is the position of s.
 		p.pos = pos
 	}
@@ -325,7 +331,7 @@ func (p *printer) writeString(pos token.Position, s string, isLit bool) {
 // after all pending comments, prev is the previous comment in
 // a group of comments (or nil), and tok is the next token.
 //
-func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, tok token.Token) {
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, tok token.Token) {
 	if len(p.output) == 0 {
 		// the comment is the first item to be printed - don't write any whitespace
 		return
@@ -733,7 +739,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
 	var last *ast.Comment
 	for p.commentBefore(next) {
 		for _, c := range p.comment.List {
-			p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok)
+			p.writeCommentPrefix(p.posFor(c.Pos()), next, last, tok)
 			p.writeComment(c)
 			last = c
 		}
@@ -1037,6 +1043,28 @@ func getDoc(n ast.Node) *ast.CommentGroup {
 	return nil
 }
 
+func getLastComment(n ast.Node) *ast.CommentGroup {
+	switch n := n.(type) {
+	case *ast.Field:
+		return n.Comment
+	case *ast.ImportSpec:
+		return n.Comment
+	case *ast.ValueSpec:
+		return n.Comment
+	case *ast.TypeSpec:
+		return n.Comment
+	case *ast.GenDecl:
+		if len(n.Specs) > 0 {
+			return getLastComment(n.Specs[len(n.Specs)-1])
+		}
+	case *ast.File:
+		if len(n.Comments) > 0 {
+			return n.Comments[len(n.Comments)-1]
+		}
+	}
+	return nil
+}
+
 func (p *printer) printNode(node interface{}) error {
 	// unpack *CommentedNode, if any
 	var comments []*ast.CommentGroup
@@ -1060,6 +1088,11 @@ func (p *printer) printNode(node interface{}) error {
 		if doc := getDoc(n); doc != nil {
 			beg = doc.Pos()
 		}
+		if com := getLastComment(n); com != nil {
+			if e := com.End(); e > end {
+				end = e
+			}
+		}
 		// token.Pos values are global offsets, we can
 		// compare them directly
 		i := 0
@@ -1237,7 +1270,7 @@ const (
 	RawFormat Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
 	TabIndent                  // use tabs for indentation independent of UseSpaces
 	UseSpaces                  // use spaces instead of tabs for alignment
-	SourcePos                  // emit //line comments to preserve original source positions
+	SourcePos                  // emit //line directives to preserve original source positions
 )
 
 // A Config node controls the output of Fprint.
diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go
index 0badbfb..5984d2c 100644
--- a/src/go/printer/printer_test.go
+++ b/src/go/printer/printer_test.go
@@ -363,7 +363,7 @@ func identCount(f *ast.File) int {
 	return n
 }
 
-// Verify that the SourcePos mode emits correct //line comments
+// Verify that the SourcePos mode emits correct //line directives
 // by testing that position information for matching identifiers
 // is maintained.
 func TestSourcePos(t *testing.T) {
@@ -394,7 +394,7 @@ func (t *t) foo(a, b, c int) int {
 	}
 
 	// parse pretty printed original
-	// (//line comments must be interpreted even w/o parser.ParseComments set)
+	// (//line directives must be interpreted even w/o parser.ParseComments set)
 	f2, err := parser.ParseFile(fset, "", buf.Bytes(), 0)
 	if err != nil {
 		t.Fatalf("%s\n%s", err, buf.Bytes())
@@ -434,6 +434,53 @@ func (t *t) foo(a, b, c int) int {
 	}
 }
 
+// Verify that the SourcePos mode doesn't emit unnecessary //line directives
+// before empty lines.
+func TestIssue5945(t *testing.T) {
+	const orig = `
+package p   // line 2
+func f() {} // line 3
+
+var x, y, z int
+
+
+func g() { // line 8
+}
+`
+
+	const want = `//line src.go:2
+package p
+
+//line src.go:3
+func f() {}
+
+var x, y, z int
+
+//line src.go:8
+func g() {
+}
+`
+
+	// parse original
+	f1, err := parser.ParseFile(fset, "src.go", orig, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// pretty-print original
+	var buf bytes.Buffer
+	err = (&Config{Mode: UseSpaces | SourcePos, Tabwidth: 8}).Fprint(&buf, fset, f1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	got := buf.String()
+
+	// compare original with desired output
+	if got != want {
+		t.Errorf("got:\n%s\nwant:\n%s\n", got, want)
+	}
+}
+
 var decls = []string{
 	`import "fmt"`,
 	"const pi = 3.1415\nconst e = 2.71828\n\nvar x = pi",
@@ -612,3 +659,54 @@ func _() {}
 		t.Error(err)
 	}
 }
+
+func TestCommentedNode(t *testing.T) {
+	const (
+		input = `package main
+
+func foo() {
+	// comment inside func
+}
+
+// leading comment
+type bar int // comment2
+
+`
+
+		foo = `func foo() {
+	// comment inside func
+}`
+
+		bar = `// leading comment
+type bar int	// comment2
+`
+	)
+
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "input.go", input, parser.ParseComments)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var buf bytes.Buffer
+
+	err = Fprint(&buf, fset, &CommentedNode{Node: f.Decls[0], Comments: f.Comments})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if buf.String() != foo {
+		t.Errorf("got %q, want %q", buf.String(), foo)
+	}
+
+	buf.Reset()
+
+	err = Fprint(&buf, fset, &CommentedNode{Node: f.Decls[1], Comments: f.Comments})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if buf.String() != bar {
+		t.Errorf("got %q, want %q", buf.String(), bar)
+	}
+}
diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden
index 82f5e0f..d4ea545 100644
--- a/src/go/printer/testdata/declarations.golden
+++ b/src/go/printer/testdata/declarations.golden
@@ -985,3 +985,18 @@ func _(struct {
 	x	int
 	y	int
 })	// no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int }
+type c3 = p.C
+type (
+	s	struct{}
+	a	= A
+	b	= A
+	c	= foo
+	d	= interface{}
+	ddd	= p.Foo
+)
diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input
index a0a3783..50386eb 100644
--- a/src/go/printer/testdata/declarations.input
+++ b/src/go/printer/testdata/declarations.input
@@ -999,3 +999,18 @@ func _(struct {
 	x int
 	y int
 }) // no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int}
+type c3 = p.C
+type (
+	s struct{}
+	a = A
+	b = A
+	c = foo
+	d = interface{}
+	ddd = p.Foo
+)
\ No newline at end of file
diff --git a/src/go/token/position.go b/src/go/token/position.go
index d4171d8..88d7416 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -71,7 +71,7 @@ func (pos Position) String() string {
 type Pos int
 
 // The zero value for Pos is NoPos; there is no file and line information
-// associated with it, and NoPos().IsValid() is false. NoPos is always
+// associated with it, and NoPos.IsValid() is false. NoPos is always
 // smaller than any other Pos value. The corresponding Position value
 // for NoPos is the zero value for Position.
 //
@@ -94,7 +94,8 @@ type File struct {
 	base int    // Pos value range for this file is [base...base+size]
 	size int    // file size as provided to AddFile
 
-	// lines and infos are protected by set.mutex
+	// lines and infos are protected by mutex
+	mutex sync.Mutex
 	lines []int // lines contains the offset of the first character for each line (the first entry is always 0)
 	infos []lineInfo
 }
@@ -116,9 +117,9 @@ func (f *File) Size() int {
 
 // LineCount returns the number of lines in file f.
 func (f *File) LineCount() int {
-	f.set.mutex.RLock()
+	f.mutex.Lock()
 	n := len(f.lines)
-	f.set.mutex.RUnlock()
+	f.mutex.Unlock()
 	return n
 }
 
@@ -127,11 +128,11 @@ func (f *File) LineCount() int {
 // and smaller than the file size; otherwise the line offset is ignored.
 //
 func (f *File) AddLine(offset int) {
-	f.set.mutex.Lock()
+	f.mutex.Lock()
 	if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size {
 		f.lines = append(f.lines, offset)
 	}
-	f.set.mutex.Unlock()
+	f.mutex.Unlock()
 }
 
 // MergeLine merges a line with the following line. It is akin to replacing
@@ -143,8 +144,8 @@ func (f *File) MergeLine(line int) {
 	if line <= 0 {
 		panic("illegal line number (line numbering starts at 1)")
 	}
-	f.set.mutex.Lock()
-	defer f.set.mutex.Unlock()
+	f.mutex.Lock()
+	defer f.mutex.Unlock()
 	if line >= len(f.lines) {
 		panic("illegal line number")
 	}
@@ -176,9 +177,9 @@ func (f *File) SetLines(lines []int) bool {
 	}
 
 	// set lines table
-	f.set.mutex.Lock()
+	f.mutex.Lock()
 	f.lines = lines
-	f.set.mutex.Unlock()
+	f.mutex.Unlock()
 	return true
 }
 
@@ -198,9 +199,9 @@ func (f *File) SetLinesForContent(content []byte) {
 	}
 
 	// set lines table
-	f.set.mutex.Lock()
+	f.mutex.Lock()
 	f.lines = lines
-	f.set.mutex.Unlock()
+	f.mutex.Unlock()
 }
 
 // A lineInfo object describes alternative file and line number
@@ -222,11 +223,11 @@ type lineInfo struct {
 // information for //line filename:line comments in source files.
 //
 func (f *File) AddLineInfo(offset int, filename string, line int) {
-	f.set.mutex.Lock()
+	f.mutex.Lock()
 	if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size {
 		f.infos = append(f.infos, lineInfo{offset, filename, line})
 	}
-	f.set.mutex.Unlock()
+	f.mutex.Unlock()
 }
 
 // Pos returns the Pos value for the given file offset;
@@ -267,6 +268,8 @@ func searchLineInfos(a []lineInfo, x int) int {
 // possibly adjusted by //line comments; otherwise those comments are ignored.
 //
 func (f *File) unpack(offset int, adjusted bool) (filename string, line, column int) {
+	f.mutex.Lock()
+	defer f.mutex.Unlock()
 	filename = f.name
 	if i := searchInts(f.lines, offset); i >= 0 {
 		line, column = i+1, offset-f.lines[i]+1
@@ -371,7 +374,7 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
 		panic("illegal base or size")
 	}
 	// base >= s.base && size >= 0
-	f := &File{s, filename, base, size, []int{0}, nil}
+	f := &File{set: s, name: filename, base: base, size: size, lines: []int{0}}
 	base += size + 1 // +1 because EOF also has a position
 	if base < 0 {
 		panic("token.Pos offset overflow (> 2G of source code in file set)")
@@ -446,9 +449,7 @@ func (s *FileSet) File(p Pos) (f *File) {
 func (s *FileSet) PositionFor(p Pos, adjusted bool) (pos Position) {
 	if p != NoPos {
 		if f := s.file(p); f != nil {
-			s.mutex.RLock()
-			pos = f.position(p, adjusted)
-			s.mutex.RUnlock()
+			return f.position(p, adjusted)
 		}
 	}
 	return
diff --git a/src/go/token/serialize.go b/src/go/token/serialize.go
index 4adc8f9..d0ea345 100644
--- a/src/go/token/serialize.go
+++ b/src/go/token/serialize.go
@@ -30,7 +30,14 @@ func (s *FileSet) Read(decode func(interface{}) error) error {
 	files := make([]*File, len(ss.Files))
 	for i := 0; i < len(ss.Files); i++ {
 		f := &ss.Files[i]
-		files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos}
+		files[i] = &File{
+			set:   s,
+			name:  f.Name,
+			base:  f.Base,
+			size:  f.Size,
+			lines: f.Lines,
+			infos: f.Infos,
+		}
 	}
 	s.files = files
 	s.last = nil
@@ -47,7 +54,15 @@ func (s *FileSet) Write(encode func(interface{}) error) error {
 	ss.Base = s.base
 	files := make([]serializedFile, len(s.files))
 	for i, f := range s.files {
-		files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos}
+		f.mutex.Lock()
+		files[i] = serializedFile{
+			Name:  f.name,
+			Base:  f.base,
+			Size:  f.size,
+			Lines: append([]int(nil), f.lines...),
+			Infos: append([]lineInfo(nil), f.infos...),
+		}
+		f.mutex.Unlock()
 	}
 	ss.Files = files
 	s.mutex.Unlock()
diff --git a/src/go/types/api.go b/src/go/types/api.go
index 5b911cb..11e7686 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -57,10 +57,9 @@ func (err Error) Error() string {
 // vendored packages. See https://golang.org/s/go15vendor.
 // If possible, external implementations should implement ImporterFrom.
 type Importer interface {
-	// Import returns the imported package for the given import
-	// path, or an error if the package couldn't be imported.
-	// Two calls to Import with the same path return the same
-	// package.
+	// Import returns the imported package for the given import path.
+	// The semantics is like for ImporterFrom.ImportFrom except that
+	// dir and mode are ignored (since they are not present).
 	Import(path string) (*Package, error)
 }
 
@@ -79,12 +78,15 @@ type ImporterFrom interface {
 	Importer
 
 	// ImportFrom returns the imported package for the given import
-	// path when imported by the package in srcDir, or an error
-	// if the package couldn't be imported. The mode value must
-	// be 0; it is reserved for future use.
-	// Two calls to ImportFrom with the same path and srcDir return
-	// the same package.
-	ImportFrom(path, srcDir string, mode ImportMode) (*Package, error)
+	// path when imported by a package file located in dir.
+	// If the import failed, besides returning an error, ImportFrom
+	// is encouraged to cache and return a package anyway, if one
+	// was created. This will reduce package inconsistencies and
+	// follow-on type checker errors due to the missing package.
+	// The mode value must be 0; it is reserved for future use.
+	// Two calls to ImportFrom with the same path and dir must
+	// return the same package.
+	ImportFrom(path, dir string, mode ImportMode) (*Package, error)
 }
 
 // A Config specifies the configuration for type checking.
@@ -99,7 +101,7 @@ type Config struct {
 	// identifiers referring to package C (which won't find an object).
 	// This feature is intended for the standard library cmd/api tool.
 	//
-	// Caution: Effects may be unpredictable due to follow-up errors.
+	// Caution: Effects may be unpredictable due to follow-on errors.
 	//          Do not use casually!
 	FakeImportC bool
 
@@ -121,7 +123,7 @@ type Config struct {
 	Importer Importer
 
 	// If Sizes != nil, it provides the sizing functions for package unsafe.
-	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
+	// Otherwise SizesFor("gc", "amd64") is used instead.
 	Sizes Sizes
 
 	// If DisableUnusedImportCheck is set, packages are not checked
@@ -243,7 +245,7 @@ func (info *Info) TypeOf(e ast.Expr) Type {
 // Precondition: the Uses and Defs maps are populated.
 //
 func (info *Info) ObjectOf(id *ast.Ident) Object {
-	if obj, _ := info.Defs[id]; obj != nil {
+	if obj := info.Defs[id]; obj != nil {
 		return obj
 	}
 	return info.Uses[id]
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 1208eb8..d4f3f35 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -1296,154 +1296,73 @@ func f(x int) { y := x; print(y) }
 	}
 }
 
-// Alias-related code. Keep for now.
-/*
-func TestAliases(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
-
-	const src = `
-package b
-
-import (
-	"./testdata/alias"
-	a "./testdata/alias"
-	"math"
-)
-
-const (
-	c1 = alias.Pi1
-	c2 => a.Pi1
-	c3 => a.Pi2
-	c4 => math.Pi
-)
-
-var (
-	v1 => alias.Default
-	v2 => a.Default
-	v3 = f1
-)
-
-type (
-	t1 => alias.Context
-	t2 => a.Context
-)
-
-func f1 => alias.Sin
-func f2 => a.Sin
-
-func _() {
-	assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
-	assert(c2 == c2 && c2 == c3 && c3 == c4)
-	v1 = v2 // must be assignable
-	var _ *t1 = new(t2) // must be assignable
-	var _ t2 = alias.Default
-	f1(1) // must be callable
-	f2(1)
-	_ = alias.Sin(1)
-	_ = a.Sin(1)
-}
-`
-
-	if out := compile(t, "testdata", "alias.go"); out != "" {
-		defer os.Remove(out)
-	}
-
-	DefPredeclaredTestFuncs() // declare assert built-in for testing
-	mustTypecheck(t, "Aliases", src, nil)
-}
-
-func compile(t *testing.T, dirname, filename string) string {
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
-	cmd.Dir = dirname
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Logf("%s", out)
-		t.Fatalf("go tool compile %s failed: %s", filename, err)
-	}
-	// filename should end with ".go"
-	return filepath.Join(dirname, filename[:len(filename)-2]+"o")
-}
-
-func TestAliasDefUses(t *testing.T) {
+// TestFailedImport tests that we don't get follow-on errors
+// elsewhere in a package due to failing to import a package.
+func TestFailedImport(t *testing.T) {
 	testenv.MustHaveGoBuild(t)
 
 	const src = `
 package p
 
-import(
-	"go/build"
-	"go/types"
-)
+import "foo" // should only see an error here
 
-// Defs
-const Invalid => types.Invalid
-type Struct => types.Struct
-var Default => build.Default
-func Implements => types.Implements
-
-// Uses
-const _ = Invalid
-var _ types.Struct = Struct{} // types must be identical
-var _ build.Context = Default
-var _ = Implements(nil, nil)
+const c = foo.C
+type T = foo.T
+var v T = c
+func f(x T) T { return foo.F(x) }
 `
-
-	info := Info{
-		Defs: make(map[*ast.Ident]Object),
-		Uses: make(map[*ast.Ident]Object),
-	}
-	mustTypecheck(t, "TestAliasDefUses", src, &info)
-
-	// verify Defs
-	defs := map[string]string{
-		"Invalid":    "types.Invalid",
-		"Struct":     "types.Struct",
-		"Default":    "build.Default",
-		"Implements": "types.Implements",
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "src", src, 0)
+	if err != nil {
+		t.Fatal(err)
 	}
-
-	for ident, obj := range info.Defs {
-		if alias, ok := obj.(*Alias); ok {
-			if want := defs[ident.Name]; want != "" {
-				orig := alias.Orig()
-				if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-					t.Errorf("%v: got %v, want %v", ident, got, want)
+	files := []*ast.File{f}
+
+	// type-check using all possible importers
+	for _, compiler := range []string{"gc", "gccgo", "source"} {
+		errcount := 0
+		conf := Config{
+			Error: func(err error) {
+				// we should only see the import error
+				if errcount > 0 || !strings.Contains(err.Error(), "could not import foo") {
+					t.Errorf("for %s importer, got unexpected error: %v", compiler, err)
 				}
-				delete(defs, ident.Name) // mark as found
-			} else {
-				t.Errorf("unexpected alias def of %v", ident)
-			}
+				errcount++
+			},
+			Importer: importer.For(compiler, nil),
 		}
-	}
 
-	if len(defs) != 0 {
-		t.Errorf("missing aliases: %v", defs)
-	}
+		info := &Info{
+			Uses: make(map[*ast.Ident]Object),
+		}
+		pkg, _ := conf.Check("p", fset, files, info)
+		if pkg == nil {
+			t.Errorf("for %s importer, type-checking failed to return a package", compiler)
+			continue
+		}
 
-	// verify Uses
-	uses := map[string]string{
-		"Invalid":    "types.Invalid",
-		"Struct":     "types.Struct",
-		"Default":    "build.Default",
-		"Implements": "types.Implements",
-	}
+		imports := pkg.Imports()
+		if len(imports) != 1 {
+			t.Errorf("for %s importer, got %d imports, want 1", compiler, len(imports))
+			continue
+		}
+		imp := imports[0]
+		if imp.Name() != "foo" {
+			t.Errorf(`for %s importer, got %q, want "foo"`, compiler, imp.Name())
+			continue
+		}
 
-	for ident, obj := range info.Uses {
-		if alias, ok := obj.(*Alias); ok {
-			if want := uses[ident.Name]; want != "" {
-				orig := alias.Orig()
-				if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-					t.Errorf("%v: got %v, want %v", ident, got, want)
+		// verify that all uses of foo refer to the imported package foo (imp)
+		for ident, obj := range info.Uses {
+			if ident.Name == "foo" {
+				if obj, ok := obj.(*PkgName); ok {
+					if obj.Imported() != imp {
+						t.Errorf("%s resolved to %v; want %v", ident, obj.Imported(), imp)
+					}
+				} else {
+					t.Errorf("%s resolved to %v; want package name", ident, obj)
 				}
-				delete(uses, ident.Name) // mark as found
-			} else {
-				t.Errorf("unexpected alias use of %v", ident)
 			}
 		}
 	}
-
-	if len(uses) != 0 {
-		t.Errorf("missing aliases: %v", defs)
-	}
 }
-*/
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 18f893d..e5ea071 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -219,7 +219,7 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
 			check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
 			return
 		}
-		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		check.errorf(rhs[0].Pos(), "cannot initialize %d variables with %d values", l, r)
 		return
 	}
 
@@ -253,7 +253,7 @@ func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
 	}
 	if l != r {
 		check.useGetter(get, r)
-		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		check.errorf(rhs[0].Pos(), "cannot assign %d values to %d variables", r, l)
 		return
 	}
 
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 8e5c537..ffd9629 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -93,7 +93,9 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
 func (check *Checker) use(arg ...ast.Expr) {
 	var x operand
 	for _, e := range arg {
-		check.rawExpr(&x, e, nil)
+		if e != nil { // be safe
+			check.rawExpr(&x, e, nil)
+		}
 	}
 }
 
@@ -250,7 +252,7 @@ func (check *Checker) argument(fun ast.Expr, sig *Signature, i int, x *operand,
 			check.errorf(ellipsis, "can only use ... with matching parameter")
 			return
 		}
-		if _, ok := x.typ.Underlying().(*Slice); !ok {
+		if _, ok := x.typ.Underlying().(*Slice); !ok && x.typ != Typ[UntypedNil] { // see issue #18268
 			check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
 			return
 		}
@@ -275,8 +277,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
 	// so we don't need a "package" mode for operands: package names
 	// can only appear in qualified identifiers which are mapped to
 	// selector expressions.
-	// (see also decl.go: checker.aliasDecl)
-	// TODO(gri) factor this code out and share with checker.aliasDecl
 	if ident, ok := e.X.(*ast.Ident); ok {
 		_, obj := check.scope.LookupParent(ident.Name, check.pos)
 		if pname, _ := obj.(*PkgName); pname != nil {
@@ -296,12 +296,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
 				// ok to continue
 			}
 			check.recordUse(e.Sel, exp)
-			exp = original(exp)
-
-			// avoid further errors if the imported object is an alias that's broken
-			if exp == nil {
-				goto Error
-			}
 
 			// Simplified version of the code for *ast.Idents:
 			// - imported objects are always fully initialized
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 28e94f1..26db576 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -57,6 +57,16 @@ type context struct {
 	hasCallOrRecv bool           // set if an expression contains a function call or channel receive operation
 }
 
+// An importKey identifies an imported package by import path and source directory
+// (directory containing the file containing the import). In practice, the directory
+// may always be the same, or may not matter. Given an (import path, directory), an
+// importer must always return the same package (but given two different import paths,
+// an importer may still return the same package by mapping them to the same package
+// paths).
+type importKey struct {
+	path, dir string
+}
+
 // A Checker maintains the state of the type checker.
 // It must be created with NewChecker.
 type Checker struct {
@@ -66,7 +76,8 @@ type Checker struct {
 	fset *token.FileSet
 	pkg  *Package
 	*Info
-	objMap map[Object]*declInfo // maps package-level object to declaration info
+	objMap map[Object]*declInfo   // maps package-level object to declaration info
+	impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
 
 	// information collected during type-checking of a set of package files
 	// (initialized by Files, valid only for the duration of check.Files;
@@ -162,6 +173,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
 		pkg:    pkg,
 		Info:   info,
 		objMap: make(map[Object]*declInfo),
+		impMap: make(map[importKey]*Package),
 	}
 }
 
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index f844575..24b3365 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -68,11 +68,11 @@ var tests = [][]string{
 	{"testdata/decls1.src"},
 	{"testdata/decls2a.src", "testdata/decls2b.src"},
 	{"testdata/decls3.src"},
+	{"testdata/decls4.src"},
 	{"testdata/const0.src"},
 	{"testdata/const1.src"},
 	{"testdata/constdecl.src"},
 	{"testdata/vardecl.src"},
-	//{"testdata/aliasdecl.src"},
 	{"testdata/expr0.src"},
 	{"testdata/expr1.src"},
 	{"testdata/expr2.src"},
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index dced7a6..7428f8f 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -81,14 +81,10 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
 		check.varDecl(obj, d.lhs, d.typ, d.init)
 	case *TypeName:
 		// invalid recursive types are detected via path
-		check.typeDecl(obj, d.typ, def, path)
+		check.typeDecl(obj, d.typ, def, path, d.alias)
 	case *Func:
 		// functions may be recursive - no need to track dependencies
 		check.funcDecl(obj, d)
-	// Alias-related code. Keep for now.
-	// case *Alias:
-	// 	// aliases cannot be recursive - no need to track dependencies
-	// 	check.aliasDecl(obj, d)
 	default:
 		unreachable()
 	}
@@ -219,33 +215,42 @@ func (n *Named) setUnderlying(typ Type) {
 	}
 }
 
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
 	assert(obj.typ == nil)
 
 	// type declarations cannot use iota
 	assert(check.iota == nil)
 
-	named := &Named{obj: obj}
-	def.setUnderlying(named)
-	obj.typ = named // make sure recursive type declarations terminate
-
-	// determine underlying type of named
-	check.typExpr(typ, named, append(path, obj))
-
-	// The underlying type of named may be itself a named type that is
-	// incomplete:
-	//
-	//	type (
-	//		A B
-	//		B *C
-	//		C A
-	//	)
-	//
-	// The type of C is the (named) type of A which is incomplete,
-	// and which has as its underlying type the named type B.
-	// Determine the (final, unnamed) underlying type by resolving
-	// any forward chain (they always end in an unnamed type).
-	named.underlying = underlying(named.underlying)
+	if alias {
+
+		obj.typ = Typ[Invalid]
+		obj.typ = check.typExpr(typ, nil, append(path, obj))
+
+	} else {
+
+		named := &Named{obj: obj}
+		def.setUnderlying(named)
+		obj.typ = named // make sure recursive type declarations terminate
+
+		// determine underlying type of named
+		check.typExpr(typ, named, append(path, obj))
+
+		// The underlying type of named may be itself a named type that is
+		// incomplete:
+		//
+		//	type (
+		//		A B
+		//		B *C
+		//		C A
+		//	)
+		//
+		// The type of C is the (named) type of A which is incomplete,
+		// and which has as its underlying type the named type B.
+		// Determine the (final, unnamed) underlying type by resolving
+		// any forward chain (they always end in an unnamed type).
+		named.underlying = underlying(named.underlying)
+
+	}
 
 	// check and add associated methods
 	// TODO(gri) It's easy to create pathological cases where the
@@ -268,21 +273,23 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
 
 	// spec: "If the base type is a struct type, the non-blank method
 	// and field names must be distinct."
-	base := obj.typ.(*Named)
-	if t, _ := base.underlying.(*Struct); t != nil {
-		for _, fld := range t.fields {
-			if fld.name != "_" {
-				assert(mset.insert(fld) == nil)
+	base, _ := obj.typ.(*Named) // nil if receiver base type is type alias
+	if base != nil {
+		if t, _ := base.underlying.(*Struct); t != nil {
+			for _, fld := range t.fields {
+				if fld.name != "_" {
+					assert(mset.insert(fld) == nil)
+				}
 			}
 		}
-	}
 
-	// Checker.Files may be called multiple times; additional package files
-	// may add methods to already type-checked types. Add pre-existing methods
-	// so that we can detect redeclarations.
-	for _, m := range base.methods {
-		assert(m.name != "_")
-		assert(mset.insert(m) == nil)
+		// Checker.Files may be called multiple times; additional package files
+		// may add methods to already type-checked types. Add pre-existing methods
+		// so that we can detect redeclarations.
+		for _, m := range base.methods {
+			assert(m.name != "_")
+			assert(mset.insert(m) == nil)
+		}
 	}
 
 	// type-check methods
@@ -295,7 +302,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
 				case *Var:
 					check.errorf(m.pos, "field and method with the same name %s", m.name)
 				case *Func:
-					check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+					check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
 				default:
 					unreachable()
 				}
@@ -303,9 +310,12 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
 				continue
 			}
 		}
+
+		// type-check
 		check.objDecl(m, nil, nil)
+
 		// methods with blank _ names cannot be found - don't keep them
-		if m.name != "_" {
+		if base != nil && m.name != "_" {
 			base.methods = append(base.methods, m)
 		}
 	}
@@ -333,106 +343,6 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
 	}
 }
 
-// original returns the original Object if obj is an Alias;
-// otherwise it returns obj. The result is never an Alias,
-// but it may be nil.
-func original(obj Object) Object {
-	// an alias stands for the original object; use that one instead
-	if alias, _ := obj.(*disabledAlias); alias != nil {
-		obj = alias.orig
-		// aliases always refer to non-alias originals
-		if _, ok := obj.(*disabledAlias); ok {
-			panic("original is an alias")
-		}
-	}
-	return obj
-}
-
-func (check *Checker) aliasDecl(obj *disabledAlias, decl *declInfo) {
-	assert(obj.typ == nil)
-
-	// alias declarations cannot use iota
-	assert(check.iota == nil)
-
-	// assume alias is invalid to start with
-	obj.typ = Typ[Invalid]
-
-	// rhs must be package-qualified identifer pkg.sel (see also call.go: checker.selector)
-	// TODO(gri) factor this code out and share with checker.selector
-	rhs := decl.init
-	var pkg *Package
-	var sel *ast.Ident
-	if sexpr, ok := rhs.(*ast.SelectorExpr); ok {
-		if ident, ok := sexpr.X.(*ast.Ident); ok {
-			_, obj := check.scope.LookupParent(ident.Name, check.pos)
-			if pname, _ := obj.(*PkgName); pname != nil {
-				assert(pname.pkg == check.pkg)
-				check.recordUse(ident, pname)
-				pname.used = true
-				pkg = pname.imported
-				sel = sexpr.Sel
-			}
-		}
-	}
-	if pkg == nil {
-		check.errorf(rhs.Pos(), "invalid alias: %v is not a package-qualified identifier", rhs)
-		return
-	}
-
-	// qualified identifier must denote an exported object
-	orig := pkg.scope.Lookup(sel.Name)
-	if orig == nil || !orig.Exported() {
-		if !pkg.fake {
-			check.errorf(rhs.Pos(), "%s is not exported by package %s", sel.Name, pkg.name)
-		}
-		return
-	}
-	check.recordUse(sel, orig)
-	orig = original(orig)
-
-	// avoid further errors if the imported object is an alias that's broken
-	if orig == nil {
-		return
-	}
-
-	// An alias declaration must not refer to package unsafe.
-	if orig.Pkg() == Unsafe {
-		check.errorf(rhs.Pos(), "invalid alias: %s refers to package unsafe (%v)", obj.Name(), orig)
-		return
-	}
-
-	// The original must be of the same kind as the alias declaration.
-	var why string
-	switch obj.kind {
-	case token.CONST:
-		if _, ok := orig.(*Const); !ok {
-			why = "constant"
-		}
-	case token.TYPE:
-		if _, ok := orig.(*TypeName); !ok {
-			why = "type"
-		}
-	case token.VAR:
-		if _, ok := orig.(*Var); !ok {
-			why = "variable"
-		}
-	case token.FUNC:
-		if _, ok := orig.(*Func); !ok {
-			why = "function"
-		}
-	default:
-		unreachable()
-	}
-	if why != "" {
-		check.errorf(rhs.Pos(), "invalid alias: %v is not a %s", orig, why)
-		return
-	}
-
-	// alias is valid
-	obj.typ = orig.Type()
-	obj.orig = orig
-}
-
 func (check *Checker) declStmt(decl ast.Decl) {
 	pkg := check.pkg
 
@@ -540,7 +450,7 @@ func (check *Checker) declStmt(decl ast.Decl) {
 				// the innermost containing block."
 				scopePos := s.Name.Pos()
 				check.declare(check.scope, s.Name, obj, scopePos)
-				check.typeDecl(obj, s.Type, nil, nil)
+				check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
 
 			default:
 				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
diff --git a/src/go/types/example_test.go b/src/go/types/example_test.go
index 8882e50..2a2fb3f 100644
--- a/src/go/types/example_test.go
+++ b/src/go/types/example_test.go
@@ -239,10 +239,10 @@ func fib(x int) int {
 	// type S string:
 	//   defined at fib.go:4:6
 	//   used at 6:23
-	// type int int:
+	// type int:
 	//   defined at -
 	//   used at 8:12, 8:17
-	// type string string:
+	// type string:
 	//   defined at -
 	//   used at 4:8
 	// var b S:
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index f76da17..1624858 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -633,13 +633,13 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
 	}
 
 	// spec: "The right operand in a shift expression must have unsigned
-	// integer type or be an untyped constant that can be converted to
-	// unsigned integer type."
+	// integer type or be an untyped constant representable by a value of
+	// type uint."
 	switch {
 	case isUnsigned(y.typ):
 		// nothing to do
 	case isUntyped(y.typ):
-		check.convertUntyped(y, Typ[UntypedInt])
+		check.convertUntyped(y, Typ[Uint])
 		if y.mode == invalid {
 			x.mode = invalid
 			return
@@ -800,10 +800,24 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
 		return
 	}
 
-	if (op == token.QUO || op == token.REM) && (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
-		check.invalidOp(y.pos(), "division by zero")
-		x.mode = invalid
-		return
+	if op == token.QUO || op == token.REM {
+		// check for zero divisor
+		if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
+			check.invalidOp(y.pos(), "division by zero")
+			x.mode = invalid
+			return
+		}
+
+		// check for divisor underflow in complex division (see issue 20227)
+		if x.mode == constant_ && y.mode == constant_ && isComplex(x.typ) {
+			re, im := constant.Real(y.val), constant.Imag(y.val)
+			re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
+			if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
+				check.invalidOp(y.pos(), "division by zero")
+				x.mode = invalid
+				return
+			}
+		}
 	}
 
 	if x.mode == constant_ && y.mode == constant_ {
@@ -1161,6 +1175,17 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
 			}
 
 		default:
+			// when "using" all elements unpack KeyValueExpr
+			// explicitly because check.use doesn't accept them
+			for _, e := range e.Elts {
+				if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+					// Ideally, we should also "use" kv.Key but we can't know
+					// if it's an externally defined struct key or not. Going
+					// forward anyway can lead to other errors. Give up instead.
+					e = kv.Value
+				}
+				check.use(e)
+			}
 			// if utyp is invalid, an error was reported before
 			if utyp != Typ[Invalid] {
 				check.errorf(e.Pos(), "invalid composite literal type %s", typ)
@@ -1182,6 +1207,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
 	case *ast.IndexExpr:
 		check.expr(x, e.X)
 		if x.mode == invalid {
+			check.use(e.Index)
 			goto Error
 		}
 
@@ -1251,6 +1277,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
 	case *ast.SliceExpr:
 		check.expr(x, e.X)
 		if x.mode == invalid {
+			check.use(e.Low, e.High, e.Max)
 			goto Error
 		}
 
diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go
index 0a36c08..196fc9b 100644
--- a/src/go/types/gotype.go
+++ b/src/go/types/gotype.go
@@ -7,40 +7,46 @@
 // Build this command explicitly: go build gotype.go
 
 /*
-The gotype command does syntactic and semantic analysis of Go files
-and packages like the front-end of a Go compiler. Errors are reported
-if the analysis fails; otherwise gotype is quiet (unless -v is set).
+The gotype command, like the front-end of a Go compiler, parses and
+type-checks a single Go package. Errors are reported if the analysis
+fails; otherwise gotype is quiet (unless -v is set).
 
 Without a list of paths, gotype reads from standard input, which
 must provide a single Go source file defining a complete package.
 
-If a single path is specified that is a directory, gotype checks
-the Go files in that directory; they must all belong to the same
-package.
+With a single directory argument, gotype checks the Go files in
+that directory, comprising a single package. Use -t to include the
+(in-package) _test.go files. Use -x to type check only external
+test files.
 
-Otherwise, each path must be the filename of Go file belonging to
-the same package.
+Otherwise, each path must be the filename of a Go file belonging
+to the same package.
+
+Imports are processed by importing directly from the source of
+imported packages (default), or by importing from compiled and
+installed packages (by setting -c to the respective compiler).
+
+The -c flag must be set to a compiler ("gc", "gccgo") when type-
+checking packages containing imports with relative import paths
+(import "./mypkg") because the source importer cannot know which
+files to include for such packages.
 
 Usage:
 	gotype [flags] [path...]
 
 The flags are:
-	-a
-		use all (incl. _test.go) files when processing a directory
+	-t
+		include local test files in a directory (ignored if -x is provided)
+	-x
+		consider only external test files in a directory
 	-e
 		report all errors (not just the first 10)
 	-v
 		verbose mode
 	-c
-		compiler used to compile packages (gc or gccgo); default: gc
-		(gotype based on Go1.5 and up only)
-	-gccgo
-		use gccimporter instead of gcimporter
-		(gotype based on Go1.4 and before only)
-
-Debugging flags:
-	-seq
-		parse sequentially, rather than in parallel
+		compiler used for installed packages (gc, gccgo, or source); default: source
+
+Flags controlling additional output:
 	-ast
 		print AST (forces -seq)
 	-trace
@@ -54,13 +60,14 @@ To check the files a.go, b.go, and c.go:
 
 	gotype a.go b.go c.go
 
-To check an entire package in the directory dir and print the processed files:
+To check an entire package including (in-package) tests in the directory dir and print the processed files:
 
-	gotype -v dir
+	gotype -t -v dir
 
-To check an entire package including tests in the local directory:
+To check the external test package (if any) in the current directory, based on installed packages compiled with
+cmd/compile:
 
-	gotype -a .
+	gotype -c=gc -x .
 
 To verify the output of a pipe:
 
@@ -82,18 +89,19 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"sync"
 	"time"
 )
 
 var (
 	// main operation modes
-	allFiles  = flag.Bool("a", false, "use all (incl. _test.go) files when processing a directory")
-	allErrors = flag.Bool("e", false, "report all errors (not just the first 10)")
-	verbose   = flag.Bool("v", false, "verbose mode")
-	gccgo     = flag.Bool("gccgo", false, "use gccgoimporter instead of gcimporter")
+	testFiles  = flag.Bool("t", false, "include in-package test files in a directory")
+	xtestFiles = flag.Bool("x", false, "consider only external test files in a directory")
+	allErrors  = flag.Bool("e", false, "report all errors, not just the first 10")
+	verbose    = flag.Bool("v", false, "verbose mode")
+	compiler   = flag.String("c", "source", "compiler used for installed packages (gc, gccgo, or source)")
 
-	// debugging support
-	sequential    = flag.Bool("seq", false, "parse sequentially, rather than in parallel")
+	// additional output control
 	printAST      = flag.Bool("ast", false, "print AST (forces -seq)")
 	printTrace    = flag.Bool("trace", false, "print parse trace (forces -seq)")
 	parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)")
@@ -102,36 +110,55 @@ var (
 var (
 	fset       = token.NewFileSet()
 	errorCount = 0
+	sequential = false
 	parserMode parser.Mode
-	sizes      types.Sizes
 )
 
 func initParserMode() {
 	if *allErrors {
 		parserMode |= parser.AllErrors
 	}
+	if *printAST {
+		sequential = true
+	}
 	if *printTrace {
 		parserMode |= parser.Trace
+		sequential = true
 	}
 	if *parseComments && (*printAST || *printTrace) {
 		parserMode |= parser.ParseComments
 	}
 }
 
-func initSizes() {
-	wordSize := 8
-	maxAlign := 8
-	switch build.Default.GOARCH {
-	case "386", "arm":
-		wordSize = 4
-		maxAlign = 4
-		// add more cases as needed
-	}
-	sizes = &types.StdSizes{WordSize: int64(wordSize), MaxAlign: int64(maxAlign)}
-}
+const usageString = `usage: gotype [flags] [path ...]
+
+The gotype command, like the front-end of a Go compiler, parses and
+type-checks a single Go package. Errors are reported if the analysis
+fails; otherwise gotype is quiet (unless -v is set).
+
+Without a list of paths, gotype reads from standard input, which
+must provide a single Go source file defining a complete package.
+
+With a single directory argument, gotype checks the Go files in
+that directory, comprising a single package. Use -t to include the
+(in-package) _test.go files. Use -x to type check only external
+test files.
+
+Otherwise, each path must be the filename of a Go file belonging
+to the same package.
+
+Imports are processed by importing directly from the source of
+imported packages (default), or by importing from compiled and
+installed packages (by setting -c to the respective compiler).
+
+The -c flag must be set to a compiler ("gc", "gccgo") when type-
+checking packages containing imports with relative import paths
+(import "./mypkg") because the source importer cannot know which
+files to include for such packages.
+`
 
 func usage() {
-	fmt.Fprintln(os.Stderr, "usage: gotype [flags] [path ...]")
+	fmt.Fprintln(os.Stderr, usageString)
 	flag.PrintDefaults()
 	os.Exit(2)
 }
@@ -165,60 +192,49 @@ func parseStdin() (*ast.File, error) {
 	return parse("<standard input>", src)
 }
 
-func parseFiles(filenames []string) ([]*ast.File, error) {
+func parseFiles(dir string, filenames []string) ([]*ast.File, error) {
 	files := make([]*ast.File, len(filenames))
+	errors := make([]error, len(filenames))
 
-	if *sequential {
-		for i, filename := range filenames {
-			var err error
-			files[i], err = parse(filename, nil)
-			if err != nil {
-				return nil, err // leave unfinished goroutines hanging
-			}
-		}
-	} else {
-		type parseResult struct {
-			file *ast.File
-			err  error
-		}
-
-		out := make(chan parseResult)
-		for _, filename := range filenames {
-			go func(filename string) {
-				file, err := parse(filename, nil)
-				out <- parseResult{file, err}
-			}(filename)
+	var wg sync.WaitGroup
+	for i, filename := range filenames {
+		wg.Add(1)
+		go func(i int, filepath string) {
+			defer wg.Done()
+			files[i], errors[i] = parse(filepath, nil)
+		}(i, filepath.Join(dir, filename))
+		if sequential {
+			wg.Wait()
 		}
+	}
+	wg.Wait()
 
-		for i := range filenames {
-			res := <-out
-			if res.err != nil {
-				return nil, res.err // leave unfinished goroutines hanging
-			}
-			files[i] = res.file
+	// if there are errors, return the first one for deterministic results
+	for _, err := range errors {
+		if err != nil {
+			return nil, err
 		}
 	}
 
 	return files, nil
 }
 
-func parseDir(dirname string) ([]*ast.File, error) {
+func parseDir(dir string) ([]*ast.File, error) {
 	ctxt := build.Default
-	pkginfo, err := ctxt.ImportDir(dirname, 0)
+	pkginfo, err := ctxt.ImportDir(dir, 0)
 	if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
 		return nil, err
 	}
-	filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
-	if *allFiles {
-		filenames = append(filenames, pkginfo.TestGoFiles...)
-	}
 
-	// complete file names
-	for i, filename := range filenames {
-		filenames[i] = filepath.Join(dirname, filename)
+	if *xtestFiles {
+		return parseFiles(dir, pkginfo.XTestGoFiles)
 	}
 
-	return parseFiles(filenames)
+	filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
+	if *testFiles {
+		filenames = append(filenames, pkginfo.TestGoFiles...)
+	}
+	return parseFiles(dir, filenames)
 }
 
 func getPkgFiles(args []string) ([]*ast.File, error) {
@@ -244,15 +260,13 @@ func getPkgFiles(args []string) ([]*ast.File, error) {
 	}
 
 	// list of files
-	return parseFiles(args)
+	return parseFiles("", args)
 }
 
 func checkPkgFiles(files []*ast.File) {
-	compiler := "gc"
-	if *gccgo {
-		compiler = "gccgo"
-	}
 	type bailout struct{}
+
+	// if checkPkgFiles is called multiple times, set up conf only once
 	conf := types.Config{
 		FakeImportC: true,
 		Error: func(err error) {
@@ -261,8 +275,8 @@ func checkPkgFiles(files []*ast.File) {
 			}
 			report(err)
 		},
-		Importer: importer.For(compiler, nil),
-		Sizes:    sizes,
+		Importer: importer.For(*compiler, nil),
+		Sizes:    types.SizesFor(build.Default.Compiler, build.Default.GOARCH),
 	}
 
 	defer func() {
@@ -297,11 +311,7 @@ func printStats(d time.Duration) {
 func main() {
 	flag.Usage = usage
 	flag.Parse()
-	if *printAST || *printTrace {
-		*sequential = true
-	}
 	initParserMode()
-	initSizes()
 
 	start := time.Now()
 
diff --git a/src/go/types/hilbert_test.go b/src/go/types/hilbert_test.go
index 3b56a82..916d6fd 100644
--- a/src/go/types/hilbert_test.go
+++ b/src/go/types/hilbert_test.go
@@ -50,8 +50,7 @@ func TestHilbert(t *testing.T) {
 func program(n int, out string) []byte {
 	var g gen
 
-	g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
-// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q)
+	g.p(`// Code generated by: go test -run=Hilbert -H=%d -out=%q. DO NOT EDIT.
 
 // This program tests arbitrary precision constant arithmetic
 // by generating the constant elements of a Hilbert matrix H,
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
index 3caca55..ee8202d 100644
--- a/src/go/types/lookup.go
+++ b/src/go/types/lookup.go
@@ -67,24 +67,22 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 	}
 
 	typ, isPtr := deref(T)
-	named, _ := typ.(*Named)
 
 	// *typ where typ is an interface has no methods.
-	if isPtr {
-		utyp := typ
-		if named != nil {
-			utyp = named.underlying
-		}
-		if _, ok := utyp.(*Interface); ok {
-			return
-		}
+	if isPtr && IsInterface(typ) {
+		return
 	}
 
 	// Start with typ as single entry at shallowest depth.
-	// If typ is not a named type, insert a nil type instead.
-	current := []embeddedType{{named, nil, isPtr, false}}
-
-	// named types that we have seen already, allocated lazily
+	current := []embeddedType{{typ, nil, isPtr, false}}
+
+	// Named types that we have seen already, allocated lazily.
+	// Used to avoid endless searches in case of recursive types.
+	// Since only Named types can be used for recursive types, we
+	// only need to track those.
+	// (If we ever allow type aliases to construct recursive types,
+	// we must use type identity rather than pointer equality for
+	// the map key comparison, as we do in consolidateMultiples.)
 	var seen map[*Named]bool
 
 	// search current depth
@@ -93,11 +91,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 
 		// look for (pkg, name) in all types at current depth
 		for _, e := range current {
-			// The very first time only, e.typ may be nil.
-			// In this case, we don't have a named type and
-			// we simply continue with the underlying type.
-			if e.typ != nil {
-				if seen[e.typ] {
+			typ := e.typ
+
+			// If we have a named type, we may have associated methods.
+			// Look for those first.
+			if named, _ := typ.(*Named); named != nil {
+				if seen[named] {
 					// We have seen this type before, at a more shallow depth
 					// (note that multiples of this type at the current depth
 					// were consolidated before). The type at that depth shadows
@@ -108,10 +107,10 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 				if seen == nil {
 					seen = make(map[*Named]bool)
 				}
-				seen[e.typ] = true
+				seen[named] = true
 
 				// look for a matching attached method
-				if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+				if i, m := lookupMethod(named.methods, pkg, name); m != nil {
 					// potential match
 					assert(m.typ != nil)
 					index = concat(e.index, i)
@@ -124,7 +123,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 				}
 
 				// continue with underlying type
-				typ = e.typ.underlying
+				typ = named.underlying
 			}
 
 			switch t := typ.(type) {
@@ -147,16 +146,15 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 					// we have a name collision on the same depth; in either
 					// case we don't need to look further).
 					// Embedded fields are always of the form T or *T where
-					// T is a named type. If e.typ appeared multiple times at
+					// T is a type name. If e.typ appeared multiple times at
 					// this depth, f.typ appears multiple times at the next
 					// depth.
 					if obj == nil && f.anonymous {
-						// Ignore embedded basic types - only user-defined
-						// named types can have methods or struct fields.
 						typ, isPtr := deref(f.typ)
-						if t, _ := typ.(*Named); t != nil {
-							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-						}
+						// TODO(gri) optimization: ignore types that can't
+						// have fields or methods (only Named, Struct, and
+						// Interface types need to be considered).
+						next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
 					}
 				}
 
@@ -193,12 +191,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
 	return nil, nil, false // not found
 }
 
-// embeddedType represents an embedded named type
+// embeddedType represents an embedded type
 type embeddedType struct {
-	typ       *Named // nil means use the outer typ variable instead
-	index     []int  // embedded field indices, starting with index at depth 0
-	indirect  bool   // if set, there was a pointer indirection on the path to this field
-	multiples bool   // if set, typ appears multiple times at this depth
+	typ       Type
+	index     []int // embedded field indices, starting with index at depth 0
+	indirect  bool  // if set, there was a pointer indirection on the path to this field
+	multiples bool  // if set, typ appears multiple times at this depth
 }
 
 // consolidateMultiples collects multiple list entries with the same type
@@ -209,10 +207,10 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
 		return list // at most one entry - nothing to do
 	}
 
-	n := 0                       // number of entries w/ unique type
-	prev := make(map[*Named]int) // index at which type was previously seen
+	n := 0                     // number of entries w/ unique type
+	prev := make(map[Type]int) // index at which type was previously seen
 	for _, e := range list {
-		if i, found := prev[e.typ]; found {
+		if i, found := lookupType(prev, e.typ); found {
 			list[i].multiples = true
 			// ignore this entry
 		} else {
@@ -224,6 +222,21 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
 	return list[:n]
 }
 
+func lookupType(m map[Type]int, typ Type) (int, bool) {
+	// fast path: maybe the types are equal
+	if i, found := m[typ]; found {
+		return i, true
+	}
+
+	for t, i := range m {
+		if Identical(t, typ) {
+			return i, true
+		}
+	}
+
+	return 0, false
+}
+
 // MissingMethod returns (nil, false) if V implements T, otherwise it
 // returns a missing method required by T and whether it is missing or
 // just has the wrong type.
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
index b27f2da..4f791d9 100644
--- a/src/go/types/methodset.go
+++ b/src/go/types/methodset.go
@@ -72,24 +72,22 @@ func NewMethodSet(T Type) *MethodSet {
 	var base methodSet
 
 	typ, isPtr := deref(T)
-	named, _ := typ.(*Named)
 
 	// *typ where typ is an interface has no methods.
-	if isPtr {
-		utyp := typ
-		if named != nil {
-			utyp = named.underlying
-		}
-		if _, ok := utyp.(*Interface); ok {
-			return &emptyMethodSet
-		}
+	if isPtr && IsInterface(typ) {
+		return &emptyMethodSet
 	}
 
 	// Start with typ as single entry at shallowest depth.
-	// If typ is not a named type, insert a nil type instead.
-	current := []embeddedType{{named, nil, isPtr, false}}
-
-	// named types that we have seen already, allocated lazily
+	current := []embeddedType{{typ, nil, isPtr, false}}
+
+	// Named types that we have seen already, allocated lazily.
+	// Used to avoid endless searches in case of recursive types.
+	// Since only Named types can be used for recursive types, we
+	// only need to track those.
+	// (If we ever allow type aliases to construct recursive types,
+	// we must use type identity rather than pointer equality for
+	// the map key comparison, as we do in consolidateMultiples.)
 	var seen map[*Named]bool
 
 	// collect methods at current depth
@@ -101,11 +99,12 @@ func NewMethodSet(T Type) *MethodSet {
 		var mset methodSet
 
 		for _, e := range current {
-			// The very first time only, e.typ may be nil.
-			// In this case, we don't have a named type and
-			// we simply continue with the underlying type.
-			if e.typ != nil {
-				if seen[e.typ] {
+			typ := e.typ
+
+			// If we have a named type, we may have associated methods.
+			// Look for those first.
+			if named, _ := typ.(*Named); named != nil {
+				if seen[named] {
 					// We have seen this type before, at a more shallow depth
 					// (note that multiples of this type at the current depth
 					// were consolidated before). The type at that depth shadows
@@ -116,12 +115,12 @@ func NewMethodSet(T Type) *MethodSet {
 				if seen == nil {
 					seen = make(map[*Named]bool)
 				}
-				seen[e.typ] = true
+				seen[named] = true
 
-				mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+				mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
 
 				// continue with underlying type
-				typ = e.typ.underlying
+				typ = named.underlying
 			}
 
 			switch t := typ.(type) {
@@ -130,16 +129,15 @@ func NewMethodSet(T Type) *MethodSet {
 					fset = fset.add(f, e.multiples)
 
 					// Embedded fields are always of the form T or *T where
-					// T is a named type. If typ appeared multiple times at
+					// T is a type name. If typ appeared multiple times at
 					// this depth, f.Type appears multiple times at the next
 					// depth.
 					if f.anonymous {
-						// Ignore embedded basic types - only user-defined
-						// named types can have methods or struct fields.
 						typ, isPtr := deref(f.typ)
-						if t, _ := typ.(*Named); t != nil {
-							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-						}
+						// TODO(gri) optimization: ignore types that can't
+						// have fields or methods (only Named, Struct, and
+						// Interface types need to be considered).
+						next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
 					}
 				}
 
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 6c0c5c4..f0bcd67 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -25,7 +25,7 @@ type Object interface {
 	Name() string   // package local object name
 	Type() Type     // object type
 	Exported() bool // reports whether the name starts with a capital letter
-	Id() string     // object id (see Id below)
+	Id() string     // object name if exported, qualified name if not exported (see func Id)
 
 	// String returns a human-readable string of the object.
 	String() string
@@ -64,15 +64,10 @@ func Id(pkg *Package, name string) string {
 	// inside a package and outside a package - which breaks some
 	// tests)
 	path := "_"
-	// TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
-	// if pkg == nil {
-	// 	panic("nil package in lookup of unexported name")
-	// }
-	if pkg != nil {
+	// pkg is nil for objects in Universe scope and possibly types
+	// introduced via Eval (see also comment in object.sameId)
+	if pkg != nil && pkg.path != "" {
 		path = pkg.path
-		if path == "" {
-			path = "_"
-		}
 	}
 	return path + "." + name
 }
@@ -154,7 +149,7 @@ func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.V
 func (obj *Const) Val() constant.Value { return obj.val }
 func (*Const) isDependency()           {} // a constant may be a dependency of an initialization expression
 
-// A TypeName represents a declared type.
+// A TypeName represents a name for a (named or alias) type.
 type TypeName struct {
 	object
 }
@@ -163,6 +158,30 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
 	return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
 }
 
+// IsAlias reports whether obj is an alias name for a type.
+func (obj *TypeName) IsAlias() bool {
+	switch t := obj.typ.(type) {
+	case nil:
+		return false
+	case *Basic:
+		// unsafe.Pointer is not an alias.
+		if obj.pkg == Unsafe {
+			return false
+		}
+		// Any user-defined type name for a basic type is an alias for a
+		// basic type (because basic types are pre-declared in the Universe
+		// scope, outside any package scope), and so is any type name with
+		// a different name than the name of the basic type it refers to.
+		// Additionally, we need to look for "byte" and "rune" because they
+		// are aliases but have the same names (for better error messages).
+		return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
+	case *Named:
+		return obj != t.obj
+	default:
+		return true
+	}
+}
+
 // A Variable represents a declared variable (including function parameters and results, and struct fields).
 type Var struct {
 	object
@@ -215,28 +234,6 @@ func (obj *Func) FullName() string {
 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
 func (*Func) isDependency()     {} // a function may be a dependency of an initialization expression
 
-// An Alias represents a declared alias.
-type disabledAlias struct {
-	object
-	orig Object      // aliased constant, type, variable, or function; never an alias
-	kind token.Token // token.CONST, token.TYPE, token.VAR, or token.FUNC (only needed during resolve phase)
-}
-
-func disabledNewAlias(pos token.Pos, pkg *Package, name string, orig Object) *disabledAlias {
-	var typ Type = Typ[Invalid]
-	if orig != nil {
-		typ = orig.Type()
-	}
-	// No need to set a valid Alias.kind - that field is only used during identifier
-	// resolution (1st type-checker pass). We could store the field outside but it's
-	// easier to keep it here.
-	return &disabledAlias{object{nil, pos, pkg, name, typ, 0, token.NoPos}, orig, token.ILLEGAL}
-}
-
-// Orig returns the aliased object, or nil if there was an error.
-// The returned object is never an Alias.
-func (obj *disabledAlias) disabledOrig() Object { return obj.orig }
-
 // A Label represents a declared label.
 type Label struct {
 	object
@@ -264,7 +261,9 @@ type Nil struct {
 }
 
 func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+	var tname *TypeName
 	typ := obj.Type()
+
 	switch obj := obj.(type) {
 	case *PkgName:
 		fmt.Fprintf(buf, "package %s", obj.Name())
@@ -277,8 +276,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
 		buf.WriteString("const")
 
 	case *TypeName:
+		tname = obj
 		buf.WriteString("type")
-		typ = typ.Underlying()
 
 	case *Var:
 		if obj.isField {
@@ -295,10 +294,6 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
 		}
 		return
 
-	// Alias-related code. Keep for now.
-	// case *Alias:
-	// 	buf.WriteString("alias")
-
 	case *Label:
 		buf.WriteString("label")
 		typ = nil
@@ -322,10 +317,27 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
 		writePackage(buf, obj.Pkg(), qf)
 	}
 	buf.WriteString(obj.Name())
-	if typ != nil {
-		buf.WriteByte(' ')
-		WriteType(buf, typ, qf)
+
+	if typ == nil {
+		return
 	}
+
+	if tname != nil {
+		// We have a type object: Don't print anything more for
+		// basic types since there's no more information (names
+		// are the same; see also comment in TypeName.IsAlias).
+		if _, ok := typ.(*Basic); ok {
+			return
+		}
+		if tname.IsAlias() {
+			buf.WriteString(" =")
+		} else {
+			typ = typ.Underlying()
+		}
+	}
+
+	buf.WriteByte(' ')
+	WriteType(buf, typ, qf)
 }
 
 func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
@@ -353,15 +365,14 @@ func ObjectString(obj Object, qf Qualifier) string {
 	return buf.String()
 }
 
-func (obj *PkgName) String() string       { return ObjectString(obj, nil) }
-func (obj *Const) String() string         { return ObjectString(obj, nil) }
-func (obj *TypeName) String() string      { return ObjectString(obj, nil) }
-func (obj *Var) String() string           { return ObjectString(obj, nil) }
-func (obj *Func) String() string          { return ObjectString(obj, nil) }
-func (obj *disabledAlias) String() string { return ObjectString(obj, nil) }
-func (obj *Label) String() string         { return ObjectString(obj, nil) }
-func (obj *Builtin) String() string       { return ObjectString(obj, nil) }
-func (obj *Nil) String() string           { return ObjectString(obj, nil) }
+func (obj *PkgName) String() string  { return ObjectString(obj, nil) }
+func (obj *Const) String() string    { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string      { return ObjectString(obj, nil) }
+func (obj *Func) String() string     { return ObjectString(obj, nil) }
+func (obj *Label) String() string    { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string  { return ObjectString(obj, nil) }
+func (obj *Nil) String() string      { return ObjectString(obj, nil) }
 
 func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
 	if f.typ != nil {
diff --git a/src/go/types/object_test.go b/src/go/types/object_test.go
new file mode 100644
index 0000000..b0acdd9
--- /dev/null
+++ b/src/go/types/object_test.go
@@ -0,0 +1,44 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import "testing"
+
+func TestIsAlias(t *testing.T) {
+	check := func(obj *TypeName, want bool) {
+		if got := obj.IsAlias(); got != want {
+			t.Errorf("%v: got IsAlias = %v; want %v", obj, got, want)
+		}
+	}
+
+	// predeclared types
+	check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false)
+	for _, name := range Universe.Names() {
+		if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
+			check(obj, name == "byte" || name == "rune")
+		}
+	}
+
+	// various other types
+	pkg := NewPackage("p", "p")
+	t1 := NewTypeName(0, pkg, "t1", nil)
+	n1 := NewNamed(t1, new(Struct), nil)
+	for _, test := range []struct {
+		name  *TypeName
+		alias bool
+	}{
+		{NewTypeName(0, nil, "t0", nil), false}, // no type yet
+		{NewTypeName(0, pkg, "t0", nil), false}, // no type yet
+		{t1, false},                             // type name refers to named type and vice versa
+		{NewTypeName(0, nil, "t2", new(Interface)), true}, // type name refers to unnamed type
+		{NewTypeName(0, pkg, "t3", n1), true},             // type name refers to named type with different type name
+		{NewTypeName(0, nil, "t4", Typ[Int32]), true},     // type name refers to basic type with different name
+		{NewTypeName(0, nil, "int32", Typ[Int32]), false}, // type name refers to basic type with same name
+		{NewTypeName(0, pkg, "int32", Typ[Int32]), true},  // type name is declared in user-defined package (outside Universe)
+		{NewTypeName(0, nil, "rune", Typ[Rune]), true},    // type name refers to basic type rune which is an alias already
+	} {
+		check(test.name, test.alias)
+	}
+}
diff --git a/src/go/types/package.go b/src/go/types/package.go
index a588ee7..cd202a0 100644
--- a/src/go/types/package.go
+++ b/src/go/types/package.go
@@ -19,13 +19,9 @@ type Package struct {
 	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
 }
 
-// NewPackage returns a new Package for the given package path and name;
-// the name must not be the blank identifier.
+// NewPackage returns a new Package for the given package path and name.
 // The package is not complete and contains no explicit imports.
 func NewPackage(path, name string) *Package {
-	if name == "_" {
-		panic("invalid package name _")
-	}
 	scope := NewScope(Universe, token.NoPos, token.NoPos, fmt.Sprintf("package %q", path))
 	return &Package{path: path, name: name, scope: scope}
 }
@@ -52,7 +48,7 @@ func (pkg *Package) Complete() bool { return pkg.complete }
 func (pkg *Package) MarkComplete() { pkg.complete = true }
 
 // Imports returns the list of packages directly imported by
-// pkg; the list is in source order. Package unsafe is excluded.
+// pkg; the list is in source order.
 //
 // If pkg was loaded from export data, Imports includes packages that
 // provide package-level objects referenced by pkg. This may be more or
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 21fd81e..c3b87dd 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -139,7 +139,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
 	case *Basic:
 		// Basic types are singletons except for the rune and byte
 		// aliases, thus we cannot solely rely on the x == y check
-		// above.
+		// above. See also comment in TypeName.IsAlias.
 		if y, ok := y.(*Basic); ok {
 			return x.kind == y.kind
 		}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 046e147..05603b3 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -14,13 +14,14 @@ import (
 	"unicode"
 )
 
-// A declInfo describes a package-level const, type, var, func, or alias declaration.
+// A declInfo describes a package-level const, type, var, or func declaration.
 type declInfo struct {
 	file  *Scope        // scope of file containing this declaration
 	lhs   []*Var        // lhs of n:1 variable declarations, or nil
 	typ   ast.Expr      // type, or nil
 	init  ast.Expr      // init/orig expression, or nil
 	fdecl *ast.FuncDecl // func declaration, or nil
+	alias bool          // type alias declaration
 
 	// The deps field tracks initialization expression dependencies.
 	// As a special (overloaded) case, it also tracks dependencies of
@@ -124,6 +125,73 @@ func (check *Checker) filename(fileNo int) string {
 	return fmt.Sprintf("file[%d]", fileNo)
 }
 
+func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package {
+	// If we already have a package for the given (path, dir)
+	// pair, use it instead of doing a full import.
+	// Checker.impMap only caches packages that are marked Complete
+	// or fake (dummy packages for failed imports). Incomplete but
+	// non-fake packages do require an import to complete them.
+	key := importKey{path, dir}
+	imp := check.impMap[key]
+	if imp != nil {
+		return imp
+	}
+
+	// no package yet => import it
+	if path == "C" && check.conf.FakeImportC {
+		imp = NewPackage("C", "C")
+		imp.fake = true
+	} else {
+		// ordinary import
+		var err error
+		if importer := check.conf.Importer; importer == nil {
+			err = fmt.Errorf("Config.Importer not installed")
+		} else if importerFrom, ok := importer.(ImporterFrom); ok {
+			imp, err = importerFrom.ImportFrom(path, dir, 0)
+			if imp == nil && err == nil {
+				err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
+			}
+		} else {
+			imp, err = importer.Import(path)
+			if imp == nil && err == nil {
+				err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
+			}
+		}
+		// make sure we have a valid package name
+		// (errors here can only happen through manipulation of packages after creation)
+		if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
+			err = fmt.Errorf("invalid package name: %q", imp.name)
+			imp = nil // create fake package below
+		}
+		if err != nil {
+			check.errorf(pos, "could not import %s (%s)", path, err)
+			if imp == nil {
+				// create a new fake package
+				// come up with a sensible package name (heuristic)
+				name := path
+				if i := len(name); i > 0 && name[i-1] == '/' {
+					name = name[:i-1]
+				}
+				if i := strings.LastIndex(name, "/"); i >= 0 {
+					name = name[i+1:]
+				}
+				imp = NewPackage(path, name)
+			}
+			// continue to use the package as best as we can
+			imp.fake = true // avoid follow-up lookup failures
+		}
+	}
+
+	// package should be complete or marked fake, but be cautious
+	if imp.complete || imp.fake {
+		check.impMap[key] = imp
+		return imp
+	}
+
+	// something went wrong (importer may have returned incomplete package without error)
+	return nil
+}
+
 // collectObjects collects all file and package objects and inserts them
 // into their respective scopes. It also performs imports and associates
 // methods with receiver base type names.
@@ -133,25 +201,14 @@ func (check *Checker) collectObjects() {
 	// pkgImports is the set of packages already imported by any package file seen
 	// so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
 	// it (pkg.imports may not be empty if we are checking test files incrementally).
+	// Note that pkgImports is keyed by package (and thus package path), not by an
+	// importKey value. Two different importKey values may map to the same package
+	// which is why we cannot use the check.impMap here.
 	var pkgImports = make(map[*Package]bool)
 	for _, imp := range pkg.imports {
 		pkgImports[imp] = true
 	}
 
-	// srcDir is the directory used by the Importer to look up packages.
-	// The typechecker itself doesn't need this information so it is not
-	// explicitly provided. Instead, we extract it from position info of
-	// the source files as needed.
-	// This is the only place where the type-checker (just the importer)
-	// needs to know the actual source location of a file.
-	// TODO(gri) can we come up with a better API instead?
-	var srcDir string
-	if len(check.files) > 0 {
-		// FileName may be "" (typically for tests) in which case
-		// we get "." as the srcDir which is what we would want.
-		srcDir = dir(check.fset.Position(check.files[0].Name.Pos()).Filename)
-	}
-
 	for fileNo, file := range check.files {
 		// The package identifier denotes the current package,
 		// but there is no corresponding package object.
@@ -167,6 +224,11 @@ func (check *Checker) collectObjects() {
 		fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
 		check.recordScope(file, fileScope)
 
+		// determine file directory, necessary to resolve imports
+		// FileName may be "" (typically for tests) in which case
+		// we get "." as the directory which is what we would want.
+		fileDir := dir(check.fset.Position(file.Name.Pos()).Filename)
+
 		for _, decl := range file.Decls {
 			switch d := decl.(type) {
 			case *ast.BadDecl:
@@ -178,35 +240,15 @@ func (check *Checker) collectObjects() {
 					switch s := spec.(type) {
 					case *ast.ImportSpec:
 						// import package
-						var imp *Package
 						path, err := validatedImportPath(s.Path.Value)
 						if err != nil {
 							check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
 							continue
 						}
-						if path == "C" && check.conf.FakeImportC {
-							// TODO(gri) shouldn't create a new one each time
-							imp = NewPackage("C", "C")
-							imp.fake = true
-						} else {
-							// ordinary import
-							if importer := check.conf.Importer; importer == nil {
-								err = fmt.Errorf("Config.Importer not installed")
-							} else if importerFrom, ok := importer.(ImporterFrom); ok {
-								imp, err = importerFrom.ImportFrom(path, srcDir, 0)
-								if imp == nil && err == nil {
-									err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, pkg.path)
-								}
-							} else {
-								imp, err = importer.Import(path)
-								if imp == nil && err == nil {
-									err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
-								}
-							}
-							if err != nil {
-								check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
-								continue
-							}
+
+						imp := check.importPackage(s.Path.Pos(), path, fileDir)
+						if imp == nil {
+							continue
 						}
 
 						// add package to list of explicit imports
@@ -214,9 +256,7 @@ func (check *Checker) collectObjects() {
 						// for clients; it is not needed for type-checking)
 						if !pkgImports[imp] {
 							pkgImports[imp] = true
-							if imp != Unsafe {
-								pkg.imports = append(pkg.imports, imp)
-							}
+							pkg.imports = append(pkg.imports, imp)
 						}
 
 						// local name overrides imported package name
@@ -274,13 +314,6 @@ func (check *Checker) collectObjects() {
 							check.declare(fileScope, nil, obj, token.NoPos)
 						}
 
-					// Alias-related code. Keep for now.
-					// case *ast.AliasSpec:
-					// 	obj := NewAlias(s.Name.Pos(), pkg, s.Name.Name, nil)
-					// 	obj.typ = nil // unresolved
-					// 	obj.kind = d.Tok
-					// 	check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, init: s.Orig})
-
 					case *ast.ValueSpec:
 						switch d.Tok {
 						case token.CONST:
@@ -347,7 +380,7 @@ func (check *Checker) collectObjects() {
 
 					case *ast.TypeSpec:
 						obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
-						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type, alias: s.Assign.IsValid()})
 
 					default:
 						check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
index 3bbe5ae..0821a61 100644
--- a/src/go/types/sizes.go
+++ b/src/go/types/sizes.go
@@ -153,8 +153,43 @@ func (s *StdSizes) Sizeof(T Type) int64 {
 	return s.WordSize // catch-all
 }
 
+// common architecture word sizes and alignments
+var gcArchSizes = map[string]*StdSizes{
+	"386":      {4, 4},
+	"arm":      {4, 4},
+	"arm64":    {8, 8},
+	"amd64":    {8, 8},
+	"amd64p32": {4, 8},
+	"mips":     {4, 4},
+	"mipsle":   {4, 4},
+	"mips64":   {8, 8},
+	"mips64le": {8, 8},
+	"ppc64":    {8, 8},
+	"ppc64le":  {8, 8},
+	"s390x":    {8, 8},
+	// When adding more architectures here,
+	// update the doc string of SizesFor below.
+}
+
+// SizesFor returns the Sizes used by a compiler for an architecture.
+// The result is nil if a compiler/architecture pair is not known.
+//
+// Supported architectures for compiler "gc":
+// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
+// "mips64", "mips64le", "ppc64", "ppc64le", "s390x".
+func SizesFor(compiler, arch string) Sizes {
+	if compiler != "gc" {
+		return nil
+	}
+	s, ok := gcArchSizes[arch]
+	if !ok {
+		return nil
+	}
+	return s
+}
+
 // stdSizes is used if Config.Sizes == nil.
-var stdSizes = StdSizes{8, 8}
+var stdSizes = SizesFor("gc", "amd64")
 
 func (conf *Config) alignof(T Type) int64 {
 	if s := conf.Sizes; s != nil {
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index 06d2c93..34029b8 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -96,12 +96,23 @@ func testTestDir(t *testing.T, path string, ignore ...string) {
 		// get per-file instructions
 		expectErrors := false
 		filename := filepath.Join(path, f.Name())
-		if cmd := firstComment(filename); cmd != "" {
-			switch cmd {
+		if comment := firstComment(filename); comment != "" {
+			fields := strings.Fields(comment)
+			switch fields[0] {
 			case "skip", "compiledir":
 				continue // ignore this file
 			case "errorcheck":
 				expectErrors = true
+				for _, arg := range fields[1:] {
+					if arg == "-0" || arg == "-+" || arg == "-std" {
+						// Marked explicitly as not expected errors (-0),
+						// or marked as compiling runtime/stdlib, which is only done
+						// to trigger runtime/stdlib-only error output.
+						// In both cases, the code should typecheck.
+						expectErrors = false
+						break
+					}
+				}
 			}
 		}
 
@@ -158,6 +169,9 @@ func TestStdFixed(t *testing.T) {
 		"issue15002.go", // uses Mmap; testTestDir should consult build tags
 		"issue16369.go", // go/types handles this correctly - not an issue
 		"issue18459.go", // go/types doesn't check validity of //go:xxx directives
+		"issue18882.go", // go/types doesn't check validity of //go:xxx directives
+		"issue20232.go", // go/types handles larger constants than gc
+		"issue20529.go", // go/types does not have constraints on stack size
 	)
 }
 
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
index 7fb7b58..ecdba51 100644
--- a/src/go/types/testdata/builtins.src
+++ b/src/go/types/testdata/builtins.src
@@ -19,6 +19,7 @@ func append1() {
 	_ = append(nil /* ERROR not a slice */ , s)
 	_ = append(x /* ERROR not a slice */ , s)
 	_ = append(s)
+	_ = append(s, nil...)
 	append /* ERROR not used */ (s)
 
 	_ = append(s, b)
diff --git a/src/go/types/testdata/decls1.src b/src/go/types/testdata/decls1.src
index cb162f7..1ef2806 100644
--- a/src/go/types/testdata/decls1.src
+++ b/src/go/types/testdata/decls1.src
@@ -78,7 +78,7 @@ var (
 	u2 = iface.([]int)
 	u3 = iface.(a /* ERROR "not a type" */ )
 	u4, ok = iface.(int)
-	u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+	u5, ok2, ok3 = iface /* ERROR "cannot initialize" */ .(int)
 )
 
 // Constant expression initializations
diff --git a/src/go/types/testdata/decls4.src b/src/go/types/testdata/decls4.src
new file mode 100644
index 0000000..5e5e2e9
--- /dev/null
+++ b/src/go/types/testdata/decls4.src
@@ -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.
+
+// type aliases
+
+package decls4
+
+type (
+	T0 [10]int
+	T1 []byte
+	T2 struct {
+		x int
+	}
+	T3 interface{
+		m() T2
+	}
+	T4 func(int, T0) chan T2
+)
+
+type (
+	Ai = int
+	A0 = T0
+	A1 = T1
+	A2 = T2
+	A3 = T3
+	A4 = T4
+
+	A10 = [10]int
+	A11 = []byte
+	A12 = struct {
+		x int
+	}
+	A13 = interface{
+		m() A2
+	}
+	A14 = func(int, A0) chan A2
+)
+
+// check assignment compatibility due to equality of types
+var (
+	xi_ int
+	ai Ai = xi_
+
+	x0 T0
+	a0 A0 = x0
+
+	x1 T1
+	a1 A1 = x1
+
+	x2 T2
+	a2 A2 = x2
+
+	x3 T3
+	a3 A3 = x3
+
+	x4 T4
+	a4 A4 = x4
+)
+
+// alias receiver types
+func (Ai /* ERROR "invalid receiver" */) m1() {}
+func (T0) m1() {}
+func (A0) m1 /* ERROR already declared */ () {}
+func (A0) m2 () {}
+func (A3 /* ERROR invalid receiver */ ) m1 () {}
+func (A10 /* ERROR invalid receiver */ ) m1() {}
+
+// x0 has methods m1, m2 declared via receiver type names T0 and A0
+var _ interface{ m1(); m2() } = x0
+
+// cycles
+type (
+	C2 /* ERROR illegal cycle */ = C2
+	C3 /* ERROR illegal cycle */ = C4
+	C4 = C3
+	C5 struct {
+		f *C6
+	}
+	C6 = C5
+	C7 /* ERROR illegal cycle */  struct {
+		f C8
+	}
+	C8 = C7
+)
+
+// embedded fields
+var (
+	s0 struct { T0 }
+	s1 struct { A0 } = s0 /* ERROR cannot use */ // embedded field names are different
+)
+
+// embedding and lookup of fields and methods
+func _(s struct{A0}) { s.A0 = x0 }
+
+type eX struct{xf int}
+
+func (eX) xm()
+
+type eY = struct{eX} // field/method set of eY includes xf, xm
+
+type eZ = *struct{eX} // field/method set of eZ includes xf, xm
+
+type eA struct {
+	eX // eX contributes xf, xm to eA
+}
+
+type eA2 struct {
+	*eX // *eX contributes xf, xm to eA
+}
+
+type eB struct {
+	eY // eY contributes xf, xm to eB
+}
+
+type eB2 struct {
+	*eY // *eY contributes xf, xm to eB
+}
+
+type eC struct {
+	eZ // eZ contributes xf, xm to eC
+}
+
+var (
+	_ = eA{}.xf
+	_ = eA{}.xm
+	_ = eA2{}.xf
+	_ = eA2{}.xm
+	_ = eB{}.xf
+	_ = eB{}.xm
+	_ = eB2{}.xf
+	_ = eB2{}.xm
+	_ = eC{}.xf
+	_ = eC{}.xm
+)
+
+// ambiguous selectors due to embedding via type aliases
+type eD struct {
+	eY
+	eZ
+}
+
+var (
+	_ = eD /* ERROR ambiguous selector */ {}.xf
+	_ = eD /* ERROR ambiguous selector */ {}.xm
+)
+
+var (
+	_ interface{ xm() } = eD /* ERROR missing method xm */ {}
+)
\ No newline at end of file
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index ab1a9f6..95d5c09 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -207,7 +207,7 @@ func struct_literals() {
 	_ = time.Time{}
 	_ = time.Time{sec /* ERROR "unknown field" */ : 0}
 	_ = time.Time{
-		0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+		0 /* ERROR implicit assignment to unexported field wall in time.Time literal */,
 		0 /* ERROR implicit assignment */ ,
 		nil /* ERROR implicit assignment */ ,
 	}
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
index 6579aa3..8729555 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -98,8 +98,8 @@ func issue10979() {
 // issue11347
 // These should not crash.
 var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1
-var a2, b2 /* ERROR cycle */ = 0 /* ERROR mismatch */ /* ERROR mismatch */ > 0<<""[b2]
-var a3, b3 /* ERROR cycle */ = int /* ERROR mismatch */ /* ERROR mismatch */ (1<<""[b3])
+var a2, b2 /* ERROR cycle */ = 0 /* ERROR cannot initialize */ /* ERROR cannot initialize */ > 0<<""[b2]
+var a3, b3 /* ERROR cycle */ = int /* ERROR cannot initialize */ /* ERROR cannot initialize */ (1<<""[b3])
 
 // issue10260
 // Check that error messages explain reason for interface assignment failures.
@@ -186,3 +186,24 @@ func issue15755() {
 	_ = u
 	_ = v
 }
+
+// Test that we don't get "declared but not used"
+// errors in the context of invalid/C objects.
+func issue20358() {
+	var F C /* ERROR "undeclared" */ .F
+	var A C /* ERROR "undeclared" */ .A
+	var S C /* ERROR "undeclared" */ .S
+	type T C /* ERROR "undeclared" */ .T
+	type P C /* ERROR "undeclared" */ .P
+
+	// these variables must be "used" even though
+	// the LHS expressions/types below in which
+	// context they are used are unknown/invalid
+	var f, a, s1, s2, s3, t, p int
+
+	_ = F(f)
+	_ = A[a]
+	_ = S[s1:s2:s3]
+	_ = T{t}
+	_ = P{f: p}
+}
diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
index 099c9ec..dc029fc 100644
--- a/src/go/types/testdata/shifts.src
+++ b/src/go/types/testdata/shifts.src
@@ -10,7 +10,7 @@ func shifts0() {
 		s = 10
 		_ = 0<<0
 		_ = 1<<s
-		_ = 1<<- /* ERROR "invalid shift" */ 1
+		_ = 1<<- /* ERROR "overflows uint" */ 1
 		_ = 1<<1075 /* ERROR "invalid shift" */
 		_ = 2.0<<1
 
@@ -39,12 +39,18 @@ func shifts1() {
 		_ = 1<<u
 		_ = 1<<"foo" /* ERROR "cannot convert" */
 		_ = i<<0
-		_ = i<<- /* ERROR "must not be negative" */ 1
+		_ = i<<- /* ERROR "overflows uint" */ 1
 		_ = 1 /* ERROR "overflows" */ <<100
 
 		_ uint = 1 << 0
 		_ uint = 1 << u
 		_ float32 = 1 /* ERROR "must be integer" */ << u
+
+		// for issue 14822
+		_ = 1<<( /* ERROR "invalid shift count" */ 1<<63)
+		_ = 1<<( /* ERROR "overflows uint" */ 1<<64)
+		_ = u<<(1<<63) // valid
+		_ = u<<( /* ERROR "overflows uint" */ 1<<64)
 	)
 }
 
@@ -321,11 +327,11 @@ func issue5895() {
 }
 
 func issue11325() {
-	var _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */ // example from issue 11325
-	_ = 0 >> 1.1 /* ERROR "must be unsigned integer" */
-	_ = 0 << 1.1 /* ERROR "must be unsigned integer" */
+	var _ = 0 >> 1.1 /* ERROR "truncated to uint" */ // example from issue 11325
+	_ = 0 >> 1.1 /* ERROR "truncated to uint" */
+	_ = 0 << 1.1 /* ERROR "truncated to uint" */
 	_ = 0 >> 1.
-	_ = 1 >> 1.1 /* ERROR "must be unsigned integer" */
+	_ = 1 >> 1.1 /* ERROR "truncated to uint" */
 	_ = 1 >> 1.
 	_ = 1. >> 1
 	_ = 1. >> 1.
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
index 87f08e4..446997a 100644
--- a/src/go/types/testdata/stmt0.src
+++ b/src/go/types/testdata/stmt0.src
@@ -15,19 +15,19 @@ func assignments0() (int, int) {
 	f3 := func() (int, int, int) { return 1, 2, 3 }
 
 	a, b, c = 1, 2, 3
-	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
-	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+	a, b, c = 1 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ , 2
+	a, b, c = 1 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ , 2, 3, 4
 	_, _, _ = a, b, c
 
 	a = f0 /* ERROR "used as value" */ ()
 	a = f1()
-	a = f2 /* ERROR "assignment count mismatch" */ ()
+	a = f2 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
 	a, b = f2()
-	a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+	a, b, c = f2 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
 	a, b, c = f3()
-	a, b = f3 /* ERROR "assignment count mismatch" */ ()
+	a, b = f3 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
 
-	a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+	a, b, c = <- /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ch
 
 	return /* ERROR "wrong number of return values" */
 	return /* ERROR "wrong number of return values" */ 1
@@ -43,7 +43,7 @@ func assignments1() {
 	c = s /* ERROR "cannot use .* in assignment" */
 	s = b /* ERROR "cannot use .* in assignment" */
 
-	v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+	v0, v1, v2 := 1 /* ERROR "cannot initialize" */ , 2, 3, 4
 	_, _, _ = v0, v1, v2
 
 	b = true
@@ -108,7 +108,7 @@ func assignments2() {
 	s, b = m["foo"]
 	_, d = m["bar"]
 	m["foo"] = nil
-	m["foo"] = nil /* ERROR assignment count mismatch */ , false
+	m["foo"] = nil /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
 	_ = append(m["foo"])
 	_ = append(m["foo"], true)
 
@@ -116,12 +116,12 @@ func assignments2() {
 	_, b = <-c
 	_, d = <-c
 	<- /* ERROR cannot assign */ c = 0
-	<-c = 0 /* ERROR assignment count mismatch */ , false
+	<-c = 0 /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
 
 	var x interface{}
 	_, b = x.(int)
 	x /* ERROR cannot assign */ .(int) = 0
-	x.(int) = 0 /* ERROR assignment count mismatch */ , false
+	x.(int) = 0 /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
 
 	assignments2 /* ERROR used as value */ () = nil
 	int /* ERROR not an expression */ = 0
diff --git a/src/go/types/testdata/vardecl.src b/src/go/types/testdata/vardecl.src
index 0082537..35f44e6 100644
--- a/src/go/types/testdata/vardecl.src
+++ b/src/go/types/testdata/vardecl.src
@@ -28,39 +28,39 @@ var _ = f /* ERROR "used as value" */ ()
 // Identifier and expression arity must match.
 var _, _ = 1, 2
 var _ = 1, 2 /* ERROR "extra init expr 2" */
-var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _ = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
 var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
 
 var _ = g /* ERROR "2-valued g" */ ()
 var _, _ = g()
-var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+var _, _, _ = g /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ()
 
 var _ = m["foo"]
 var _, _ = m["foo"]
-var _, _, _ = m  /* ERROR "assignment count mismatch" */ ["foo"]
+var _, _, _ = m  /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ["foo"]
 
 var _, _ int = 1, 2
 var _ int = 1, 2 /* ERROR "extra init expr 2" */
-var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _ int = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
 var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
 
 var (
 	_, _ = 1, 2
 	_ = 1, 2 /* ERROR "extra init expr 2" */
-	_, _ = 1 /* ERROR "assignment count mismatch" */
+	_, _ = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
 	_, _, _ /* ERROR "missing init expr for _" */ = 1, 2
 
 	_ = g /* ERROR "2-valued g" */ ()
 	_, _ = g()
-	_, _, _ = g /* ERROR "assignment count mismatch" */ ()
+	_, _, _ = g /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ()
 
 	_ = m["foo"]
 	_, _ = m["foo"]
-	_, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+	_, _, _ = m /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ["foo"]
 
 	_, _ int = 1, 2
 	_ int = 1, 2 /* ERROR "extra init expr 2" */
-	_, _ int = 1 /* ERROR "assignment count mismatch" */
+	_, _ int = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
 	_, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
 )
 
@@ -155,7 +155,7 @@ func (r T) _(a, b, c int) (u, v, w int) {
 func _() {
 	var a, b, c int
 	var x, y int
-	x, y = a /* ERROR assignment count mismatch */ , b, c
+	x, y = a /* ERROR cannot assign [0-9]+ values to [0-9]+ variables */ , b, c
 	_ = x
 	_ = y
 }
diff --git a/src/go/types/type.go b/src/go/types/type.go
index 01adee8..a0a1238 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -394,7 +394,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
 	return typ
 }
 
-// TypeName returns the type name for the named type t.
+// Obj returns the type name for the named type t.
 func (t *Named) Obj() *TypeName { return t.obj }
 
 // NumMethods returns the number of explicit methods whose receiver is named type t.
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
index 47378e7..0f8a7ad 100644
--- a/src/go/types/typestring.go
+++ b/src/go/types/typestring.go
@@ -56,6 +56,7 @@ func RelativeTo(pkg *Package) Qualifier {
 // This flag is exported in the x/tools/go/types package. We don't
 // need it at the moment in the std repo and so we don't export it
 // anymore. We should eventually try to remove it altogether.
+// TODO(gri) remove this
 var gcCompatibilityMode bool
 
 // TypeString returns the string representation of typ.
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
index 6365df5..b794ea8 100644
--- a/src/go/types/typestring_test.go
+++ b/src/go/types/typestring_test.go
@@ -17,7 +17,7 @@ import (
 
 const filename = "<src>"
 
-func makePkg(t *testing.T, src string) (*Package, error) {
+func makePkg(src string) (*Package, error) {
 	fset := token.NewFileSet()
 	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
 	if err != nil {
@@ -126,7 +126,7 @@ func TestTypeString(t *testing.T) {
 
 	for _, test := range tests {
 		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
-		pkg, err := makePkg(t, src)
+		pkg, err := makePkg(src)
 		if err != nil {
 			t.Errorf("%s: %s", src, err)
 			continue
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index ecc0a7d..5f1587b 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -45,17 +45,6 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
 		delete(check.unusedDotImports[scope], pkg)
 	}
 
-	// Alias-related code. Keep for now.
-	// An alias stands for the original object; use that one instead.
-	// TODO(gri) We should be able to factor out the Typ[Invalid] test.
-	// if alias, _ := obj.(*Alias); alias != nil {
-	// 	obj = original(obj)
-	// 	if obj == nil || typ == Typ[Invalid] {
-	// 		return
-	// 	}
-	// 	assert(typ == obj.Type())
-	// }
-
 	switch obj := obj.(type) {
 	case *PkgName:
 		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
@@ -634,7 +623,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
 	// current field typ and tag
 	var typ Type
 	var tag string
-	add := func(field *ast.Field, ident *ast.Ident, anonymous bool, pos token.Pos) {
+	add := func(ident *ast.Ident, anonymous bool, pos token.Pos) {
 		if tag != "" && tags == nil {
 			tags = make([]string, len(fields))
 		}
@@ -657,51 +646,45 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
 		if len(f.Names) > 0 {
 			// named fields
 			for _, name := range f.Names {
-				add(f, name, false, name.Pos())
+				add(name, false, name.Pos())
 			}
 		} else {
 			// anonymous field
-			name := anonymousFieldIdent(f.Type)
+			// spec: "An embedded type must be specified as a type name T or as a pointer
+			// to a non-interface type name *T, and T itself may not be a pointer type."
 			pos := f.Type.Pos()
+			name := anonymousFieldIdent(f.Type)
+			if name == nil {
+				check.invalidAST(pos, "anonymous field type %s has no name", f.Type)
+				continue
+			}
 			t, isPtr := deref(typ)
-			switch t := t.(type) {
+			// Because we have a name, typ must be of the form T or *T, where T is the name
+			// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
+			switch t := t.Underlying().(type) {
 			case *Basic:
 				if t == Typ[Invalid] {
 					// error was reported before
 					continue
 				}
+
 				// unsafe.Pointer is treated like a regular pointer
 				if t.kind == UnsafePointer {
 					check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
 					continue
 				}
-				add(f, name, true, pos)
-
-			case *Named:
-				// spec: "An embedded type must be specified as a type name
-				// T or as a pointer to a non-interface type name *T, and T
-				// itself may not be a pointer type."
-				switch u := t.underlying.(type) {
-				case *Basic:
-					// unsafe.Pointer is treated like a regular pointer
-					if u.kind == UnsafePointer {
-						check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
-						continue
-					}
-				case *Pointer:
-					check.errorf(pos, "anonymous field type cannot be a pointer")
+
+			case *Pointer:
+				check.errorf(pos, "anonymous field type cannot be a pointer")
+				continue
+
+			case *Interface:
+				if isPtr {
+					check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
 					continue
-				case *Interface:
-					if isPtr {
-						check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
-						continue
-					}
 				}
-				add(f, name, true, pos)
-
-			default:
-				check.invalidAST(pos, "anonymous field type %s must be named", typ)
 			}
+			add(name, true, pos)
 		}
 	}
 
@@ -714,7 +697,10 @@ func anonymousFieldIdent(e ast.Expr) *ast.Ident {
 	case *ast.Ident:
 		return e
 	case *ast.StarExpr:
-		return anonymousFieldIdent(e.X)
+		// *T is valid, but **T is not
+		if _, ok := e.X.(*ast.StarExpr); !ok {
+			return anonymousFieldIdent(e.X)
+		}
 	case *ast.SelectorExpr:
 		return e.Sel
 	}
diff --git a/src/hash/crc32/crc32_amd64.go b/src/hash/crc32/crc32_amd64.go
index 369a436..7017a89 100644
--- a/src/hash/crc32/crc32_amd64.go
+++ b/src/hash/crc32/crc32_amd64.go
@@ -8,23 +8,20 @@
 
 package crc32
 
-import "unsafe"
+import (
+	"internal/cpu"
+	"unsafe"
+)
 
 // This file contains the code to call the SSE 4.2 version of the Castagnoli
 // and IEEE CRC.
 
-// haveSSE41/haveSSE42/haveCLMUL are defined in crc_amd64.s and use
-// CPUID to test for SSE 4.1, 4.2 and CLMUL support.
-func haveSSE41() bool
-func haveSSE42() bool
-func haveCLMUL() bool
-
-// castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE4.2 CRC32
+// castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE 4.2 CRC32
 // instruction.
 //go:noescape
 func castagnoliSSE42(crc uint32, p []byte) uint32
 
-// castagnoliSSE42Triple is defined in crc32_amd64.s and uses the SSE4.2 CRC32
+// castagnoliSSE42Triple is defined in crc32_amd64.s and uses the SSE 4.2 CRC32
 // instruction.
 //go:noescape
 func castagnoliSSE42Triple(
@@ -38,9 +35,6 @@ func castagnoliSSE42Triple(
 //go:noescape
 func ieeeCLMUL(crc uint32, p []byte) uint32
 
-var sse42 = haveSSE42()
-var useFastIEEE = haveCLMUL() && haveSSE41()
-
 const castagnoliK1 = 168
 const castagnoliK2 = 1344
 
@@ -50,11 +44,11 @@ var castagnoliSSE42TableK1 *sse42Table
 var castagnoliSSE42TableK2 *sse42Table
 
 func archAvailableCastagnoli() bool {
-	return sse42
+	return cpu.X86.HasSSE42
 }
 
 func archInitCastagnoli() {
-	if !sse42 {
+	if !cpu.X86.HasSSE42 {
 		panic("arch-specific Castagnoli not available")
 	}
 	castagnoliSSE42TableK1 = new(sse42Table)
@@ -86,7 +80,7 @@ func castagnoliShift(table *sse42Table, crc uint32) uint32 {
 }
 
 func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
-	if !sse42 {
+	if !cpu.X86.HasSSE42 {
 		panic("not available")
 	}
 
@@ -197,13 +191,13 @@ func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
 }
 
 func archAvailableIEEE() bool {
-	return useFastIEEE
+	return cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41
 }
 
 var archIeeeTable8 *slicing8Table
 
 func archInitIEEE() {
-	if !useFastIEEE {
+	if !cpu.X86.HasPCLMULQDQ || !cpu.X86.HasSSE41 {
 		panic("not available")
 	}
 	// We still use slicing-by-8 for small buffers.
@@ -211,7 +205,7 @@ func archInitIEEE() {
 }
 
 func archUpdateIEEE(crc uint32, p []byte) uint32 {
-	if !useFastIEEE {
+	if !cpu.X86.HasPCLMULQDQ || !cpu.X86.HasSSE41 {
 		panic("not available")
 	}
 
diff --git a/src/hash/crc32/crc32_amd64.s b/src/hash/crc32/crc32_amd64.s
index 50c0ec8..d490936 100644
--- a/src/hash/crc32/crc32_amd64.s
+++ b/src/hash/crc32/crc32_amd64.s
@@ -134,36 +134,6 @@ loop:
 	MOVL DX, retC+104(FP)
 	RET
 
-// func haveSSE42() bool
-TEXT ·haveSSE42(SB),NOSPLIT,$0
-	XORQ AX, AX
-	INCL AX
-	CPUID
-	SHRQ $20, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
-	RET
-
-// func haveCLMUL() bool
-TEXT ·haveCLMUL(SB),NOSPLIT,$0
-	XORQ AX, AX
-	INCL AX
-	CPUID
-	SHRQ $1, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
-	RET
-
-// func haveSSE41() bool
-TEXT ·haveSSE41(SB),NOSPLIT,$0
-	XORQ AX, AX
-	INCL AX
-	CPUID
-	SHRQ $19, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
-	RET
-
 // CRC32 polynomial data
 //
 // These constants are lifted from the
diff --git a/src/hash/crc32/crc32_amd64p32.go b/src/hash/crc32/crc32_amd64p32.go
index 9d728fc..1ec44cb 100644
--- a/src/hash/crc32/crc32_amd64p32.go
+++ b/src/hash/crc32/crc32_amd64p32.go
@@ -4,33 +4,29 @@
 
 package crc32
 
+import "internal/cpu"
+
 // This file contains the code to call the SSE 4.2 version of the Castagnoli
 // CRC.
 
-// haveSSE42 is defined in crc32_amd64p32.s and uses CPUID to test for SSE 4.2
-// support.
-func haveSSE42() bool
-
 // castagnoliSSE42 is defined in crc32_amd64p32.s and uses the SSE4.2 CRC32
 // instruction.
 //go:noescape
 func castagnoliSSE42(crc uint32, p []byte) uint32
 
-var sse42 = haveSSE42()
-
 func archAvailableCastagnoli() bool {
-	return sse42
+	return cpu.X86.HasSSE42
 }
 
 func archInitCastagnoli() {
-	if !sse42 {
+	if !cpu.X86.HasSSE42 {
 		panic("not available")
 	}
 	// No initialization necessary.
 }
 
 func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
-	if !sse42 {
+	if !cpu.X86.HasSSE42 {
 		panic("not available")
 	}
 	return castagnoliSSE42(crc, p)
diff --git a/src/hash/crc32/crc32_amd64p32.s b/src/hash/crc32/crc32_amd64p32.s
index b6770eb..502bcea 100644
--- a/src/hash/crc32/crc32_amd64p32.s
+++ b/src/hash/crc32/crc32_amd64p32.s
@@ -51,14 +51,3 @@ done:
 	NOTL AX
 	MOVL AX, ret+16(FP)
 	RET
-
-// func haveSSE42() bool
-TEXT ·haveSSE42(SB),NOSPLIT,$0
-	XORQ AX, AX
-	INCL AX
-	CPUID
-	SHRQ $20, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
-	RET
-
diff --git a/src/hash/crc32/crc32_arm64.go b/src/hash/crc32/crc32_arm64.go
new file mode 100644
index 0000000..2df3702
--- /dev/null
+++ b/src/hash/crc32/crc32_arm64.go
@@ -0,0 +1,51 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// ARM64-specific hardware-assisted CRC32 algorithms. See crc32.go for a
+// description of the interface that each architecture-specific file
+// implements.
+
+package crc32
+
+func supportsCRC32() bool
+func castagnoliUpdate(crc uint32, p []byte) uint32
+func ieeeUpdate(crc uint32, p []byte) uint32
+
+var hasCRC32 = supportsCRC32()
+
+func archAvailableCastagnoli() bool {
+    return hasCRC32
+}
+
+func archInitCastagnoli() {
+    if !hasCRC32 {
+        panic("arch-specific crc32 instruction for Catagnoli not available")
+    }
+}
+
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+    if !hasCRC32 {
+        panic("arch-specific crc32 instruction for Castagnoli not available")
+    }
+
+    return ^castagnoliUpdate(^crc, p)
+}
+
+func archAvailableIEEE() bool {
+    return hasCRC32
+}
+
+func archInitIEEE() {
+    if !hasCRC32 {
+        panic("arch-specific crc32 instruction for IEEE not available")
+    }
+}
+
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+    if !hasCRC32 {
+        panic("arch-specific crc32 instruction for IEEE not available")
+    }
+
+    return ^ieeeUpdate(^crc, p)
+}
diff --git a/src/hash/crc32/crc32_arm64.s b/src/hash/crc32/crc32_arm64.s
new file mode 100644
index 0000000..26a86e4
--- /dev/null
+++ b/src/hash/crc32/crc32_arm64.s
@@ -0,0 +1,97 @@
+// Copyright 2017 The Go 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"
+
+// castagnoliUpdate updates the non-inverted crc with the given data.
+
+// func castagnoliUpdate(crc uint32, p []byte) uint32
+TEXT ·castagnoliUpdate(SB),NOSPLIT,$0-36
+	MOVWU	crc+0(FP), R9  // CRC value
+	MOVD	p+8(FP), R13  // data pointer
+	MOVD	p_len+16(FP), R11  // len(p)
+
+	CMP	$8, R11
+	BLT	less_than_8
+
+update:
+	MOVD.P	8(R13), R10
+	CRC32CX	R10, R9
+	SUB	$8, R11
+
+	CMP	$8, R11
+	BLT	less_than_8
+
+	JMP	update
+
+less_than_8:
+	TBZ	$2, R11, less_than_4
+
+	MOVWU.P	4(R13), R10
+	CRC32CW	R10, R9
+
+less_than_4:
+	TBZ	$1, R11, less_than_2
+
+	MOVHU.P	2(R13), R10
+	CRC32CH	R10, R9
+
+less_than_2:
+	TBZ	$0, R11, done
+
+	MOVBU	(R13), R10
+	CRC32CB	R10, R9
+
+done:
+	MOVWU	R9, ret+32(FP)
+	RET
+
+// ieeeUpdate updates the non-inverted crc with the given data.
+
+// func ieeeUpdate(crc uint32, p []byte) uint32
+TEXT ·ieeeUpdate(SB),NOSPLIT,$0-36
+	MOVWU	crc+0(FP), R9  // CRC value
+	MOVD	p+8(FP), R13  // data pointer
+	MOVD	p_len+16(FP), R11  // len(p)
+
+	CMP	$8, R11
+	BLT	less_than_8
+
+update:
+	MOVD.P	8(R13), R10
+	CRC32X	R10, R9
+	SUB	$8, R11
+
+	CMP	$8, R11
+	BLT	less_than_8
+
+	JMP	update
+
+less_than_8:
+	TBZ	$2, R11, less_than_4
+
+	MOVWU.P	4(R13), R10
+	CRC32W	R10, R9
+
+less_than_4:
+	TBZ	$1, R11, less_than_2
+
+	MOVHU.P	2(R13), R10
+	CRC32H	R10, R9
+
+less_than_2:
+	TBZ	$0, R11, done
+
+	MOVBU	(R13), R10
+	CRC32B	R10, R9
+
+done:
+	MOVWU	R9, ret+32(FP)
+	RET
+
+// func supportsCRC32() bool
+TEXT ·supportsCRC32(SB),NOSPLIT,$0-1
+	MOVB	runtime·supportCRC32(SB), R0
+	MOVB	R0, ret+0(FP)
+	RET
diff --git a/src/hash/crc32/crc32_otherarch.go b/src/hash/crc32/crc32_otherarch.go
index cc96076..6f3510a 100644
--- a/src/hash/crc32/crc32_otherarch.go
+++ b/src/hash/crc32/crc32_otherarch.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,!s390x
+// +build !amd64,!amd64p32,!s390x,!ppc64le,!arm64
 
 package crc32
 
diff --git a/src/hash/crc32/crc32_ppc64le.go b/src/hash/crc32/crc32_ppc64le.go
new file mode 100644
index 0000000..6867227
--- /dev/null
+++ b/src/hash/crc32/crc32_ppc64le.go
@@ -0,0 +1,87 @@
+// Copyright 2017 The Go Authors. 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 (
+	vecMinLen    = 16
+	vecAlignMask = 15 // align to 16 bytes
+	crcIEEE      = 1
+	crcCast      = 2
+)
+
+//go:noescape
+func ppc64SlicingUpdateBy8(crc uint32, table8 *slicing8Table, p []byte) uint32
+
+// this function requires the buffer to be 16 byte aligned and > 16 bytes long
+//go:noescape
+func vectorCrc32(crc uint32, poly uint32, p []byte) uint32
+
+var archCastagnoliTable8 *slicing8Table
+
+func archInitCastagnoli() {
+	archCastagnoliTable8 = slicingMakeTable(Castagnoli)
+}
+
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+	if len(p) >= 4*vecMinLen {
+		// If not aligned then process the initial unaligned bytes
+
+		if uint64(uintptr(unsafe.Pointer(&p[0])))&uint64(vecAlignMask) != 0 {
+			align := uint64(uintptr(unsafe.Pointer(&p[0]))) & uint64(vecAlignMask)
+			newlen := vecMinLen - align
+			crc = ppc64SlicingUpdateBy8(crc, archCastagnoliTable8, p[:newlen])
+			p = p[newlen:]
+		}
+		// p should be aligned now
+		aligned := len(p) & ^vecAlignMask
+		crc = vectorCrc32(crc, crcCast, p[:aligned])
+		p = p[aligned:]
+	}
+	if len(p) == 0 {
+		return crc
+	}
+	return ppc64SlicingUpdateBy8(crc, archCastagnoliTable8, p)
+}
+
+func archAvailableIEEE() bool {
+	return true
+}
+func archAvailableCastagnoli() bool {
+	return true
+}
+
+var archIeeeTable8 *slicing8Table
+
+func archInitIEEE() {
+	// We still use slicing-by-8 for small buffers.
+	archIeeeTable8 = slicingMakeTable(IEEE)
+}
+
+// archUpdateIEEE calculates the checksum of p using vectorizedIEEE.
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+
+	// Check if vector code should be used.  If not aligned, then handle those
+	// first up to the aligned bytes.
+
+	if len(p) >= 4*vecMinLen {
+		if uint64(uintptr(unsafe.Pointer(&p[0])))&uint64(vecAlignMask) != 0 {
+			align := uint64(uintptr(unsafe.Pointer(&p[0]))) & uint64(vecAlignMask)
+			newlen := vecMinLen - align
+			crc = ppc64SlicingUpdateBy8(crc, archIeeeTable8, p[:newlen])
+			p = p[newlen:]
+		}
+		aligned := len(p) & ^vecAlignMask
+		crc = vectorCrc32(crc, crcIEEE, p[:aligned])
+		p = p[aligned:]
+	}
+	if len(p) == 0 {
+		return crc
+	}
+	return ppc64SlicingUpdateBy8(crc, archIeeeTable8, p)
+}
diff --git a/src/hash/crc32/crc32_ppc64le.s b/src/hash/crc32/crc32_ppc64le.s
new file mode 100644
index 0000000..10d5dd6
--- /dev/null
+++ b/src/hash/crc32/crc32_ppc64le.s
@@ -0,0 +1,707 @@
+// Copyright 2017 The Go 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 vectorized implementation found below is a derived work
+// from code written by Anton Blanchard <anton at au.ibm.com> found
+// at https://github.com/antonblanchard/crc32-vpmsum.  The original
+// is dual licensed under GPL and Apache 2.  As the copyright holder
+// for the work, IBM has contributed this new work under
+// the golang license.
+
+// Changes include porting to Go assembler with modifications for
+// the Go ABI for ppc64le.
+
+#include "textflag.h"
+
+#define POWER8_OFFSET 132
+
+#define off16	R16
+#define off32	R17
+#define off48	R18
+#define off64	R19
+#define off80	R20
+#define off96	R21
+#define	off112	R22
+
+#define const1	V24
+#define const2	V25
+
+#define byteswap	V26
+#define mask_32bit	V27
+#define mask_64bit	V28
+#define zeroes		V29
+
+#define MAX_SIZE	32*1024
+#define REFLECT
+
+TEXT ·ppc64SlicingUpdateBy8(SB), NOSPLIT|NOFRAME, $0-44
+	MOVWZ	crc+0(FP), R3   // incoming crc
+	MOVD    table8+8(FP), R4   // *Table
+	MOVD    p+16(FP), R5
+	MOVD    p_len+24(FP), R6 // p len
+
+	CMP     $0,R6           // len == 0?
+	BNE     start
+	MOVW    R3,ret+40(FP)   // return crc
+	RET
+
+start:
+	NOR     R3,R3,R7        // ^crc
+	MOVWZ	R7,R7		// 32 bits
+	CMP	R6,$16
+	MOVD	R6,CTR
+	BLT	short
+	SRAD    $3,R6,R8        // 8 byte chunks
+	MOVD    R8,CTR
+
+loop:
+	MOVWZ	0(R5),R8	// 0-3 bytes of p ?Endian?
+	MOVWZ	4(R5),R9	// 4-7 bytes of p
+	MOVD	R4,R10		// &tab[0]
+	XOR	R7,R8,R7	// crc ^= byte[0:3]
+	RLDICL	$40,R9,$56,R17	// p[7]
+	SLD	$2,R17,R17	// p[7]*4
+	RLDICL	$40,R7,$56,R8	// crc>>24
+	ADD	R17,R10,R17	// &tab[0][p[7]]
+	SLD	$2,R8,R8	// crc>>24*4
+	RLDICL	$48,R9,$56,R18	// p[6]
+	SLD	$2,R18,R18	// p[6]*4
+	ADD	$1024,R10,R10	// tab[1]
+	MOVWZ	0(R17),R21	// tab[0][p[7]]
+	RLDICL	$56,R9,$56,R19	// p[5]
+	ADD	R10,R18,R18	// &tab[1][p[6]]
+	SLD	$2,R19,R19	// p[5]*4:1
+	MOVWZ	0(R18),R22	// tab[1][p[6]]
+	ADD	$1024,R10,R10	// tab[2]
+	XOR	R21,R22,R21	// xor done R22
+	ADD	R19,R10,R19	// &tab[2][p[5]]
+	ANDCC	$255,R9,R20	// p[4] ??
+	SLD	$2,R20,R20	// p[4]*4
+	MOVWZ	0(R19),R23	// tab[2][p[5]]
+	ADD	$1024,R10,R10	// &tab[3]
+	ADD	R20,R10,R20	// tab[3][p[4]]
+	XOR	R21,R23,R21	// xor done R23
+	ADD	$1024,R10,R10	// &tab[4]
+	MOVWZ	0(R20),R24	// tab[3][p[4]]
+	ADD	R10,R8,R23	// &tab[4][crc>>24]
+	XOR	R21,R24,R21	// xor done R24
+	MOVWZ	0(R23),R25	// tab[4][crc>>24]
+	RLDICL	$48,R7,$56,R24	// crc>>16&0xFF
+	XOR	R21,R25,R21	// xor done R25
+	ADD	$1024,R10,R10	// &tab[5]
+	SLD	$2,R24,R24	// crc>>16&0xFF*4
+	ADD	R24,R10,R24	// &tab[5][crc>>16&0xFF]
+	MOVWZ	0(R24),R26	// tab[5][crc>>16&0xFF]
+	XOR	R21,R26,R21	// xor done R26
+	RLDICL	$56,R7,$56,R25	// crc>>8
+	ADD	$1024,R10,R10	// &tab[6]
+	SLD	$2,R25,R25	// crc>>8&FF*2
+	ADD	R25,R10,R25	// &tab[6][crc>>8&0xFF]
+	MOVBZ   R7,R26          // crc&0xFF
+	ADD     $1024,R10,R10   // &tab[7]
+	MOVWZ	0(R25),R27	// tab[6][crc>>8&0xFF]
+	SLD	$2,R26,R26	// crc&0xFF*2
+	XOR	R21,R27,R21	// xor done R27
+	ADD	R26,R10,R26	// &tab[7][crc&0xFF]
+	ADD     $8,R5           // p = p[8:]
+	MOVWZ	0(R26),R28	// tab[7][crc&0xFF]
+	XOR	R21,R28,R21	// xor done R28
+	MOVWZ	R21,R7		// crc for next round
+	BC	16,0,loop	// next 8 bytes
+	ANDCC	$7,R6,R8	// any leftover bytes
+	BEQ	done		// none --> done
+	MOVD	R8,CTR		// byte count
+
+short:
+	MOVBZ   0(R5),R8        // get v
+	MOVBZ   R7,R9           // byte(crc) -> R8 BE vs LE?
+	MOVWZ	R7,R14
+	SRD	$8,R14,R14	// crc>>8
+	XOR     R8,R9,R8        // byte(crc)^v -> R8
+	ADD	$1,R5		// ptr to next v
+	SLD     $2,R8           // convert index-> bytes
+	ADD     R8,R4,R9        // &tab[byte(crc)^v]
+	MOVWZ   0(R9),R10       // tab[byte(crc)^v]
+	XOR     R10,R14,R7       // loop crc in R7
+	MOVWZ   R7,R7           // 32 bits
+	BC      16,0,short
+done:
+	NOR     R7,R7,R7        // ^crc
+	MOVW    R7,ret+40(FP)   // return crc
+	RET
+
+#ifdef BYTESWAP_DATA
+DATA ·byteswapcons+0(SB)/8,$0x0706050403020100
+DATA ·byteswapcons+8(SB)/8,$0x0f0e0d0c0b0a0908
+
+GLOBL ·byteswapcons+0(SB),RODATA,$16
+#endif
+
+TEXT ·vectorCrc32(SB), NOSPLIT|NOFRAME, $0-36
+	MOVWZ	crc+0(FP), R3   // incoming crc
+	MOVWZ	ctab+4(FP), R14   // crc poly id
+	MOVD    p+8(FP), R4
+	MOVD    p_len+16(FP), R5 // p len
+
+	// R3 = incoming crc
+	// R14 = constant table identifier
+	// R5 = address of bytes
+	// R6 = length of bytes
+
+	// defines for index loads
+
+	MOVD	$16,off16
+	MOVD	$32,off32
+	MOVD	$48,off48
+	MOVD	$64,off64
+	MOVD	$80,off80
+	MOVD	$96,off96
+	MOVD	$112,off112
+	MOVD	$0,R15
+
+	MOVD	R3,R10	// save initial crc
+
+	NOR	R3,R3,R3  // ^crc
+	MOVWZ	R3,R3	// 32 bits
+	VXOR	zeroes,zeroes,zeroes  // clear the V reg
+	VSPLTISW $-1,V0
+	VSLDOI	$4,V29,V0,mask_32bit
+	VSLDOI	$8,V29,V0,mask_64bit
+
+	VXOR	V8,V8,V8
+	MTVSRD	R3,VS40	// crc initial value VS40 = V8
+
+#ifdef REFLECT
+	VSLDOI	$8,zeroes,V8,V8  // or: VSLDOI V29,V8,V27,4 for top 32 bits?
+#else
+	VSLDOI	$4,V8,zeroes,V8
+#endif
+
+#ifdef BYTESWAP_DATA
+	MOVD    $·byteswapcons(SB),R3
+	LVX	(R3),byteswap
+#endif
+
+	CMPU	R5,$256		// length of bytes
+	BLT	short
+
+	RLDICR	$0,R5,$56,R6 // chunk to process
+
+	// First step for larger sizes
+l1:	MOVD	$32768,R7
+	MOVD	R7,R9
+	CMP	R6,R7   // compare R6, R7 (MAX SIZE)
+	BGT	top	// less than MAX, just do remainder
+	MOVD	R6,R7
+top:
+	SUB	R7,R6,R6
+
+	// mainloop does 128 bytes at a time
+	SRD	$7,R7
+
+	// determine the offset into the constants table to start with.
+	// Each constant is 128 bytes, used against 16 bytes of data.
+	SLD	$4,R7,R8
+	SRD	$3,R9,R9
+	SUB	R8,R9,R8
+
+	// The last iteration is reduced in a separate step
+	ADD	$-1,R7
+	MOVD	R7,CTR
+
+	// Determine which constant table (depends on poly)
+	CMP	R14,$1
+	BNE	castTable
+	MOVD	$·IEEEConst(SB),R3
+	BR	startConst
+castTable:
+	MOVD	$·CastConst(SB),R3
+
+startConst:
+	ADD	R3,R8,R3	// starting point in constants table
+
+	VXOR	V0,V0,V0	// clear the V regs
+	VXOR	V1,V1,V1
+	VXOR	V2,V2,V2
+	VXOR	V3,V3,V3
+	VXOR	V4,V4,V4
+	VXOR	V5,V5,V5
+	VXOR	V6,V6,V6
+	VXOR	V7,V7,V7
+
+	LVX	(R3),const1	// loading constant values
+
+	CMP	R15,$1		// Identify warm up pass
+	BEQ	next
+
+	// First warm up pass: load the bytes to process
+	LVX	(R4),V16
+	LVX	(R4+off16),V17
+	LVX	(R4+off32),V18
+	LVX	(R4+off48),V19
+	LVX	(R4+off64),V20
+	LVX	(R4+off80),V21
+	LVX	(R4+off96),V22
+	LVX	(R4+off112),V23
+	ADD	$128,R4		// bump up to next 128 bytes in buffer
+
+	VXOR	V16,V8,V16	// xor in initial CRC in V8
+
+next:
+	BC	18,0,first_warm_up_done
+
+	ADD	$16,R3		// bump up to next constants
+	LVX	(R3),const2	// table values
+
+	VPMSUMD	V16,const1,V8 // second warm up pass
+	LVX	(R4),V16	// load from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V17,const1,V9	// vpmsumd with constants
+	LVX	(R4+off16),V17	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V18,const1,V10	// vpmsumd with constants
+	LVX	(R4+off32),V18	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V19,const1,V11	// vpmsumd with constants
+	LVX	(R4+off48),V19	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V20,const1,V12	// vpmsumd with constants
+	LVX	(R4+off64),V20	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V21,const1,V13	// vpmsumd with constants
+	LVX	(R4+off80),V21	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V22,const1,V14	// vpmsumd with constants
+	LVX	(R4+off96),V22	// load next from buffer
+	OR	$0,R2,R2
+
+	VPMSUMD	V23,const1,V15	// vpmsumd with constants
+	LVX	(R4+off112),V23	// load next from buffer
+
+	ADD	$128,R4		// bump up to next 128 bytes in buffer
+
+	BC	18,0,first_cool_down
+
+cool_top:
+	LVX	(R3),const1	// constants
+	ADD	$16,R3		// inc to next constants
+	OR	$0,R2,R2
+
+	VXOR	V0,V8,V0	// xor in previous vpmsumd
+	VPMSUMD	V16,const2,V8	// vpmsumd with constants
+	LVX	(R4),V16	// buffer
+	OR	$0,R2,R2
+
+	VXOR	V1,V9,V1	// xor in previous
+	VPMSUMD	V17,const2,V9	// vpmsumd with constants
+	LVX	(R4+off16),V17	// next in buffer
+	OR	$0,R2,R2
+
+	VXOR	V2,V10,V2	// xor in previous
+	VPMSUMD	V18,const2,V10	// vpmsumd with constants
+	LVX	(R4+off32),V18	// next in buffer
+	OR	$0,R2,R2
+
+	VXOR	V3,V11,V3	// xor in previous
+	VPMSUMD	V19,const2,V11	// vpmsumd with constants
+	LVX	(R4+off48),V19	// next in buffer
+	LVX	(R3),const2	// get next constant
+	OR	$0,R2,R2
+
+	VXOR	V4,V12,V4	// xor in previous
+	VPMSUMD	V20,const1,V12	// vpmsumd with constants
+	LVX	(R4+off64),V20	// next in buffer
+	OR	$0,R2,R2
+
+	VXOR	V5,V13,V5	// xor in previous
+	VPMSUMD	V21,const1,V13	// vpmsumd with constants
+	LVX	(R4+off80),V21	// next in buffer
+	OR	$0,R2,R2
+
+	VXOR	V6,V14,V6	// xor in previous
+	VPMSUMD	V22,const1,V14	// vpmsumd with constants
+	LVX	(R4+off96),V22	// next in buffer
+	OR	$0,R2,R2
+
+	VXOR	V7,V15,V7	// xor in previous
+	VPMSUMD	V23,const1,V15	// vpmsumd with constants
+	LVX	(R4+off112),V23	// next in buffer
+
+	ADD	$128,R4		// bump up buffer pointer
+	BC	16,0,cool_top	// are we done?
+
+first_cool_down:
+
+	// load the constants
+	// xor in the previous value
+	// vpmsumd the result with constants
+
+	LVX	(R3),const1
+	ADD	$16,R3
+
+	VXOR	V0,V8,V0
+	VPMSUMD V16,const1,V8
+	OR	$0,R2,R2
+
+	VXOR	V1,V9,V1
+	VPMSUMD	V17,const1,V9
+	OR	$0,R2,R2
+
+	VXOR	V2,V10,V2
+	VPMSUMD	V18,const1,V10
+	OR	$0,R2,R2
+
+	VXOR	V3,V11,V3
+	VPMSUMD	V19,const1,V11
+	OR	$0,R2,R2
+
+	VXOR	V4,V12,V4
+	VPMSUMD	V20,const1,V12
+	OR	$0,R2,R2
+
+	VXOR	V5,V13,V5
+	VPMSUMD	V21,const1,V13
+	OR	$0,R2,R2
+
+	VXOR	V6,V14,V6
+	VPMSUMD	V22,const1,V14
+	OR	$0,R2,R2
+
+	VXOR	V7,V15,V7
+	VPMSUMD	V23,const1,V15
+	OR	$0,R2,R2
+
+second_cool_down:
+
+	VXOR    V0,V8,V0
+	VXOR    V1,V9,V1
+	VXOR    V2,V10,V2
+	VXOR    V3,V11,V3
+	VXOR    V4,V12,V4
+	VXOR    V5,V13,V5
+	VXOR    V6,V14,V6
+	VXOR    V7,V15,V7
+
+#ifdef REFLECT
+	VSLDOI  $4,V0,zeroes,V0
+	VSLDOI  $4,V1,zeroes,V1
+	VSLDOI  $4,V2,zeroes,V2
+	VSLDOI  $4,V3,zeroes,V3
+	VSLDOI  $4,V4,zeroes,V4
+	VSLDOI  $4,V5,zeroes,V5
+	VSLDOI  $4,V6,zeroes,V6
+	VSLDOI  $4,V7,zeroes,V7
+#endif
+
+	LVX	(R4),V8
+	LVX	(R4+off16),V9
+	LVX	(R4+off32),V10
+	LVX	(R4+off48),V11
+	LVX	(R4+off64),V12
+	LVX	(R4+off80),V13
+	LVX	(R4+off96),V14
+	LVX	(R4+off112),V15
+
+	ADD	$128,R4
+
+	VXOR	V0,V8,V16
+	VXOR	V1,V9,V17
+	VXOR	V2,V10,V18
+	VXOR	V3,V11,V19
+	VXOR	V4,V12,V20
+	VXOR	V5,V13,V21
+	VXOR	V6,V14,V22
+	VXOR	V7,V15,V23
+
+	MOVD    $1,R15
+	CMP     $0,R6
+	ADD     $128,R6
+
+	BNE	l1
+	ANDCC   $127,R5
+	SUBC	R5,$128,R6
+	ADD	R3,R6,R3
+
+	SRD	$4,R5,R7
+	MOVD	R7,CTR
+	LVX	(R3),V0
+	LVX	(R3+off16),V1
+	LVX	(R3+off32),V2
+	LVX	(R3+off48),V3
+	LVX	(R3+off64),V4
+	LVX	(R3+off80),V5
+	LVX	(R3+off96),V6
+	LVX	(R3+off112),V7
+
+	ADD	$128,R3
+
+	VPMSUMW	V16,V0,V0
+	VPMSUMW	V17,V1,V1
+	VPMSUMW	V18,V2,V2
+	VPMSUMW	V19,V3,V3
+	VPMSUMW	V20,V4,V4
+	VPMSUMW	V21,V5,V5
+	VPMSUMW	V22,V6,V6
+	VPMSUMW	V23,V7,V7
+
+	// now reduce the tail
+
+	CMP	$0,R7
+	BEQ	next1
+
+	LVX	(R4),V16
+	LVX	(R3),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off16),V16
+	LVX	(R3+off16),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off32),V16
+	LVX	(R3+off32),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off48),V16
+	LVX	(R3+off48),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off64),V16
+	LVX	(R3+off64),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off80),V16
+	LVX	(R3+off80),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+	BC	18,0,next1
+
+	LVX	(R4+off96),V16
+	LVX	(R3+off96),V17
+	VPMSUMW	V16,V17,V16
+	VXOR	V0,V16,V0
+
+next1:
+	VXOR	V0,V1,V0
+	VXOR	V2,V3,V2
+	VXOR	V4,V5,V4
+	VXOR	V6,V7,V6
+	VXOR	V0,V2,V0
+	VXOR	V4,V6,V4
+	VXOR	V0,V4,V0
+
+barrett_reduction:
+
+	CMP	R14,$1
+	BNE	barcstTable
+	MOVD	$·IEEEBarConst(SB),R3
+	BR	startbarConst
+barcstTable:
+	MOVD    $·CastBarConst(SB),R3
+
+startbarConst:
+	LVX	(R3),const1
+	LVX	(R3+off16),const2
+
+	VSLDOI	$8,V0,V0,V1
+	VXOR	V0,V1,V0
+
+#ifdef REFLECT
+	VSPLTISB $1,V1
+	VSL	V0,V1,V0
+#endif
+
+	VAND	V0,mask_64bit,V0
+
+#ifndef	REFLECT
+
+	VPMSUMD	V0,const1,V1
+	VSLDOI	$8,zeroes,V1,V1
+	VPMSUMD	V1,const2,V1
+	VXOR	V0,V1,V0
+	VSLDOI	$8,V0,zeroes,V0
+
+#else
+
+	VAND	V0,mask_32bit,V1
+	VPMSUMD	V1,const1,V1
+	VAND	V1,mask_32bit,V1
+	VPMSUMD	V1,const2,V1
+	VXOR	V0,V1,V0
+	VSLDOI  $4,V0,zeroes,V0
+
+#endif
+
+	MFVSRD	VS32,R3 // VS32 = V0
+
+	NOR	R3,R3,R3 // return ^crc
+	MOVW	R3,ret+32(FP)
+	RET
+
+first_warm_up_done:
+
+	LVX	(R3),const1
+	ADD	$16,R3
+
+	VPMSUMD	V16,const1,V8
+	VPMSUMD	V17,const1,V9
+	VPMSUMD	V18,const1,V10
+	VPMSUMD	V19,const1,V11
+	VPMSUMD	V20,const1,V12
+	VPMSUMD	V21,const1,V13
+	VPMSUMD	V22,const1,V14
+	VPMSUMD	V23,const1,V15
+
+	BR	second_cool_down
+
+short:
+	CMP	$0,R5
+	BEQ	zero
+
+	// compute short constants
+
+	CMP     R14,$1
+	BNE     castshTable
+	MOVD    $·IEEEConst(SB),R3
+	ADD	$4080,R3
+	BR      startshConst
+castshTable:
+	MOVD    $·CastConst(SB),R3
+	ADD	$4080,R3
+
+startshConst:
+	SUBC	R5,$256,R6	// sub from 256
+	ADD	R3,R6,R3
+
+	// calculate where to start
+
+	SRD	$4,R5,R7
+	MOVD	R7,CTR
+
+	VXOR	V19,V19,V19
+	VXOR	V20,V20,V20
+
+	LVX	(R4),V0
+	LVX	(R3),V16
+	VXOR	V0,V8,V0
+	VPMSUMW	V0,V16,V0
+	BC	18,0,v0
+
+	LVX	(R4+off16),V1
+	LVX	(R3+off16),V17
+	VPMSUMW	V1,V17,V1
+	BC	18,0,v1
+
+	LVX	(R4+off32),V2
+	LVX	(R3+off32),V16
+	VPMSUMW	V2,V16,V2
+	BC	18,0,v2
+
+	LVX	(R4+off48),V3
+	LVX	(R3+off48),V17
+	VPMSUMW	V3,V17,V3
+	BC	18,0,v3
+
+	LVX	(R4+off64),V4
+	LVX	(R3+off64),V16
+	VPMSUMW	V4,V16,V4
+	BC	18,0,v4
+
+	LVX	(R4+off80),V5
+	LVX	(R3+off80),V17
+	VPMSUMW	V5,V17,V5
+	BC	18,0,v5
+
+	LVX	(R4+off96),V6
+	LVX	(R3+off96),V16
+	VPMSUMW	V6,V16,V6
+	BC	18,0,v6
+
+	LVX	(R4+off112),V7
+	LVX	(R3+off112),V17
+	VPMSUMW	V7,V17,V7
+	BC	18,0,v7
+
+	ADD	$128,R3
+	ADD	$128,R4
+
+	LVX	(R4),V8
+	LVX	(R3),V16
+	VPMSUMW	V8,V16,V8
+	BC	18,0,v8
+
+	LVX	(R4+off16),V9
+	LVX	(R3+off16),V17
+	VPMSUMW	V9,V17,V9
+	BC	18,0,v9
+
+	LVX	(R4+off32),V10
+	LVX	(R3+off32),V16
+	VPMSUMW	V10,V16,V10
+	BC	18,0,v10
+
+	LVX	(R4+off48),V11
+	LVX	(R3+off48),V17
+	VPMSUMW	V11,V17,V11
+	BC	18,0,v11
+
+	LVX	(R4+off64),V12
+	LVX	(R3+off64),V16
+	VPMSUMW	V12,V16,V12
+	BC	18,0,v12
+
+	LVX	(R4+off80),V13
+	LVX	(R3+off80),V17
+	VPMSUMW	V13,V17,V13
+	BC	18,0,v13
+
+	LVX	(R4+off96),V14
+	LVX	(R3+off96),V16
+	VPMSUMW	V14,V16,V14
+	BC	18,0,v14
+
+	LVX	(R4+off112),V15
+	LVX	(R3+off112),V17
+	VPMSUMW	V15,V17,V15
+
+	VXOR	V19,V15,V19
+v14:	VXOR	V20,V14,V20
+v13:	VXOR	V19,V13,V19
+v12:	VXOR	V20,V12,V20
+v11:	VXOR	V19,V11,V19
+v10:	VXOR	V20,V10,V20
+v9:	VXOR	V19,V9,V19
+v8:	VXOR	V20,V8,V20
+v7:	VXOR	V19,V7,V19
+v6:	VXOR	V20,V6,V20
+v5:	VXOR	V19,V5,V19
+v4:	VXOR	V20,V4,V20
+v3:	VXOR	V19,V3,V19
+v2:	VXOR	V20,V2,V20
+v1:	VXOR	V19,V1,V19
+v0:	VXOR	V20,V0,V20
+
+	VXOR	V19,V20,V0
+
+	BR	barrett_reduction
+
+zero:
+	// This case is the original crc, so just return it
+	MOVW    R10,ret+32(FP)
+	RET
diff --git a/src/hash/crc32/crc32_s390x.s b/src/hash/crc32/crc32_s390x.s
index 0b83053..63aa609 100644
--- a/src/hash/crc32/crc32_s390x.s
+++ b/src/hash/crc32/crc32_s390x.s
@@ -227,7 +227,7 @@ final_fold:
 	// 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.
+	// with zero to not contribute to the intermediate results.
 
 
 	// T1(x) = floor( R(x) / x^32 ) GF2MUL u
diff --git a/src/hash/crc32/crc32_table_ppc64le.s b/src/hash/crc32/crc32_table_ppc64le.s
new file mode 100644
index 0000000..191810f
--- /dev/null
+++ b/src/hash/crc32/crc32_table_ppc64le.s
@@ -0,0 +1,3286 @@
+// autogenerated: do not edit!
+// generated from crc32/gen_const_ppc64le.go
+
+#include "textflag.h"
+
+	/* Reduce 262144 kbits to 1024 bits */
+	/* x^261184 mod p(x), x^261120 mod p(x) */
+DATA ·IEEEConst+0(SB)/8,$0x0000000099ea94a8
+DATA ·IEEEConst+8(SB)/8,$0x00000001651797d2
+
+	/* x^260160 mod p(x), x^260096 mod p(x) */
+DATA ·IEEEConst+16(SB)/8,$0x00000000945a8420
+DATA ·IEEEConst+24(SB)/8,$0x0000000021e0d56c
+
+	/* x^259136 mod p(x), x^259072 mod p(x) */
+DATA ·IEEEConst+32(SB)/8,$0x0000000030762706
+DATA ·IEEEConst+40(SB)/8,$0x000000000f95ecaa
+
+	/* x^258112 mod p(x), x^258048 mod p(x) */
+DATA ·IEEEConst+48(SB)/8,$0x00000001a52fc582
+DATA ·IEEEConst+56(SB)/8,$0x00000001ebd224ac
+
+	/* x^257088 mod p(x), x^257024 mod p(x) */
+DATA ·IEEEConst+64(SB)/8,$0x00000001a4a7167a
+DATA ·IEEEConst+72(SB)/8,$0x000000000ccb97ca
+
+	/* x^256064 mod p(x), x^256000 mod p(x) */
+DATA ·IEEEConst+80(SB)/8,$0x000000000c18249a
+DATA ·IEEEConst+88(SB)/8,$0x00000001006ec8a8
+
+	/* x^255040 mod p(x), x^254976 mod p(x) */
+DATA ·IEEEConst+96(SB)/8,$0x00000000a924ae7c
+DATA ·IEEEConst+104(SB)/8,$0x000000014f58f196
+
+	/* x^254016 mod p(x), x^253952 mod p(x) */
+DATA ·IEEEConst+112(SB)/8,$0x00000001e12ccc12
+DATA ·IEEEConst+120(SB)/8,$0x00000001a7192ca6
+
+	/* x^252992 mod p(x), x^252928 mod p(x) */
+DATA ·IEEEConst+128(SB)/8,$0x00000000a0b9d4ac
+DATA ·IEEEConst+136(SB)/8,$0x000000019a64bab2
+
+	/* x^251968 mod p(x), x^251904 mod p(x) */
+DATA ·IEEEConst+144(SB)/8,$0x0000000095e8ddfe
+DATA ·IEEEConst+152(SB)/8,$0x0000000014f4ed2e
+
+	/* x^250944 mod p(x), x^250880 mod p(x) */
+DATA ·IEEEConst+160(SB)/8,$0x00000000233fddc4
+DATA ·IEEEConst+168(SB)/8,$0x000000011092b6a2
+
+	/* x^249920 mod p(x), x^249856 mod p(x) */
+DATA ·IEEEConst+176(SB)/8,$0x00000001b4529b62
+DATA ·IEEEConst+184(SB)/8,$0x00000000c8a1629c
+
+	/* x^248896 mod p(x), x^248832 mod p(x) */
+DATA ·IEEEConst+192(SB)/8,$0x00000001a7fa0e64
+DATA ·IEEEConst+200(SB)/8,$0x000000017bf32e8e
+
+	/* x^247872 mod p(x), x^247808 mod p(x) */
+DATA ·IEEEConst+208(SB)/8,$0x00000001b5334592
+DATA ·IEEEConst+216(SB)/8,$0x00000001f8cc6582
+
+	/* x^246848 mod p(x), x^246784 mod p(x) */
+DATA ·IEEEConst+224(SB)/8,$0x000000011f8ee1b4
+DATA ·IEEEConst+232(SB)/8,$0x000000008631ddf0
+
+	/* x^245824 mod p(x), x^245760 mod p(x) */
+DATA ·IEEEConst+240(SB)/8,$0x000000006252e632
+DATA ·IEEEConst+248(SB)/8,$0x000000007e5a76d0
+
+	/* x^244800 mod p(x), x^244736 mod p(x) */
+DATA ·IEEEConst+256(SB)/8,$0x00000000ab973e84
+DATA ·IEEEConst+264(SB)/8,$0x000000002b09b31c
+
+	/* x^243776 mod p(x), x^243712 mod p(x) */
+DATA ·IEEEConst+272(SB)/8,$0x000000007734f5ec
+DATA ·IEEEConst+280(SB)/8,$0x00000001b2df1f84
+
+	/* x^242752 mod p(x), x^242688 mod p(x) */
+DATA ·IEEEConst+288(SB)/8,$0x000000007c547798
+DATA ·IEEEConst+296(SB)/8,$0x00000001d6f56afc
+
+	/* x^241728 mod p(x), x^241664 mod p(x) */
+DATA ·IEEEConst+304(SB)/8,$0x000000007ec40210
+DATA ·IEEEConst+312(SB)/8,$0x00000001b9b5e70c
+
+	/* x^240704 mod p(x), x^240640 mod p(x) */
+DATA ·IEEEConst+320(SB)/8,$0x00000001ab1695a8
+DATA ·IEEEConst+328(SB)/8,$0x0000000034b626d2
+
+	/* x^239680 mod p(x), x^239616 mod p(x) */
+DATA ·IEEEConst+336(SB)/8,$0x0000000090494bba
+DATA ·IEEEConst+344(SB)/8,$0x000000014c53479a
+
+	/* x^238656 mod p(x), x^238592 mod p(x) */
+DATA ·IEEEConst+352(SB)/8,$0x00000001123fb816
+DATA ·IEEEConst+360(SB)/8,$0x00000001a6d179a4
+
+	/* x^237632 mod p(x), x^237568 mod p(x) */
+DATA ·IEEEConst+368(SB)/8,$0x00000001e188c74c
+DATA ·IEEEConst+376(SB)/8,$0x000000015abd16b4
+
+	/* x^236608 mod p(x), x^236544 mod p(x) */
+DATA ·IEEEConst+384(SB)/8,$0x00000001c2d3451c
+DATA ·IEEEConst+392(SB)/8,$0x00000000018f9852
+
+	/* x^235584 mod p(x), x^235520 mod p(x) */
+DATA ·IEEEConst+400(SB)/8,$0x00000000f55cf1ca
+DATA ·IEEEConst+408(SB)/8,$0x000000001fb3084a
+
+	/* x^234560 mod p(x), x^234496 mod p(x) */
+DATA ·IEEEConst+416(SB)/8,$0x00000001a0531540
+DATA ·IEEEConst+424(SB)/8,$0x00000000c53dfb04
+
+	/* x^233536 mod p(x), x^233472 mod p(x) */
+DATA ·IEEEConst+432(SB)/8,$0x0000000132cd7ebc
+DATA ·IEEEConst+440(SB)/8,$0x00000000e10c9ad6
+
+	/* x^232512 mod p(x), x^232448 mod p(x) */
+DATA ·IEEEConst+448(SB)/8,$0x0000000073ab7f36
+DATA ·IEEEConst+456(SB)/8,$0x0000000025aa994a
+
+	/* x^231488 mod p(x), x^231424 mod p(x) */
+DATA ·IEEEConst+464(SB)/8,$0x0000000041aed1c2
+DATA ·IEEEConst+472(SB)/8,$0x00000000fa3a74c4
+
+	/* x^230464 mod p(x), x^230400 mod p(x) */
+DATA ·IEEEConst+480(SB)/8,$0x0000000136c53800
+DATA ·IEEEConst+488(SB)/8,$0x0000000033eb3f40
+
+	/* x^229440 mod p(x), x^229376 mod p(x) */
+DATA ·IEEEConst+496(SB)/8,$0x0000000126835a30
+DATA ·IEEEConst+504(SB)/8,$0x000000017193f296
+
+	/* x^228416 mod p(x), x^228352 mod p(x) */
+DATA ·IEEEConst+512(SB)/8,$0x000000006241b502
+DATA ·IEEEConst+520(SB)/8,$0x0000000043f6c86a
+
+	/* x^227392 mod p(x), x^227328 mod p(x) */
+DATA ·IEEEConst+528(SB)/8,$0x00000000d5196ad4
+DATA ·IEEEConst+536(SB)/8,$0x000000016b513ec6
+
+	/* x^226368 mod p(x), x^226304 mod p(x) */
+DATA ·IEEEConst+544(SB)/8,$0x000000009cfa769a
+DATA ·IEEEConst+552(SB)/8,$0x00000000c8f25b4e
+
+	/* x^225344 mod p(x), x^225280 mod p(x) */
+DATA ·IEEEConst+560(SB)/8,$0x00000000920e5df4
+DATA ·IEEEConst+568(SB)/8,$0x00000001a45048ec
+
+	/* x^224320 mod p(x), x^224256 mod p(x) */
+DATA ·IEEEConst+576(SB)/8,$0x0000000169dc310e
+DATA ·IEEEConst+584(SB)/8,$0x000000000c441004
+
+	/* x^223296 mod p(x), x^223232 mod p(x) */
+DATA ·IEEEConst+592(SB)/8,$0x0000000009fc331c
+DATA ·IEEEConst+600(SB)/8,$0x000000000e17cad6
+
+	/* x^222272 mod p(x), x^222208 mod p(x) */
+DATA ·IEEEConst+608(SB)/8,$0x000000010d94a81e
+DATA ·IEEEConst+616(SB)/8,$0x00000001253ae964
+
+	/* x^221248 mod p(x), x^221184 mod p(x) */
+DATA ·IEEEConst+624(SB)/8,$0x0000000027a20ab2
+DATA ·IEEEConst+632(SB)/8,$0x00000001d7c88ebc
+
+	/* x^220224 mod p(x), x^220160 mod p(x) */
+DATA ·IEEEConst+640(SB)/8,$0x0000000114f87504
+DATA ·IEEEConst+648(SB)/8,$0x00000001e7ca913a
+
+	/* x^219200 mod p(x), x^219136 mod p(x) */
+DATA ·IEEEConst+656(SB)/8,$0x000000004b076d96
+DATA ·IEEEConst+664(SB)/8,$0x0000000033ed078a
+
+	/* x^218176 mod p(x), x^218112 mod p(x) */
+DATA ·IEEEConst+672(SB)/8,$0x00000000da4d1e74
+DATA ·IEEEConst+680(SB)/8,$0x00000000e1839c78
+
+	/* x^217152 mod p(x), x^217088 mod p(x) */
+DATA ·IEEEConst+688(SB)/8,$0x000000001b81f672
+DATA ·IEEEConst+696(SB)/8,$0x00000001322b267e
+
+	/* x^216128 mod p(x), x^216064 mod p(x) */
+DATA ·IEEEConst+704(SB)/8,$0x000000009367c988
+DATA ·IEEEConst+712(SB)/8,$0x00000000638231b6
+
+	/* x^215104 mod p(x), x^215040 mod p(x) */
+DATA ·IEEEConst+720(SB)/8,$0x00000001717214ca
+DATA ·IEEEConst+728(SB)/8,$0x00000001ee7f16f4
+
+	/* x^214080 mod p(x), x^214016 mod p(x) */
+DATA ·IEEEConst+736(SB)/8,$0x000000009f47d820
+DATA ·IEEEConst+744(SB)/8,$0x0000000117d9924a
+
+	/* x^213056 mod p(x), x^212992 mod p(x) */
+DATA ·IEEEConst+752(SB)/8,$0x000000010d9a47d2
+DATA ·IEEEConst+760(SB)/8,$0x00000000e1a9e0c4
+
+	/* x^212032 mod p(x), x^211968 mod p(x) */
+DATA ·IEEEConst+768(SB)/8,$0x00000000a696c58c
+DATA ·IEEEConst+776(SB)/8,$0x00000001403731dc
+
+	/* x^211008 mod p(x), x^210944 mod p(x) */
+DATA ·IEEEConst+784(SB)/8,$0x000000002aa28ec6
+DATA ·IEEEConst+792(SB)/8,$0x00000001a5ea9682
+
+	/* x^209984 mod p(x), x^209920 mod p(x) */
+DATA ·IEEEConst+800(SB)/8,$0x00000001fe18fd9a
+DATA ·IEEEConst+808(SB)/8,$0x0000000101c5c578
+
+	/* x^208960 mod p(x), x^208896 mod p(x) */
+DATA ·IEEEConst+816(SB)/8,$0x000000019d4fc1ae
+DATA ·IEEEConst+824(SB)/8,$0x00000000dddf6494
+
+	/* x^207936 mod p(x), x^207872 mod p(x) */
+DATA ·IEEEConst+832(SB)/8,$0x00000001ba0e3dea
+DATA ·IEEEConst+840(SB)/8,$0x00000000f1c3db28
+
+	/* x^206912 mod p(x), x^206848 mod p(x) */
+DATA ·IEEEConst+848(SB)/8,$0x0000000074b59a5e
+DATA ·IEEEConst+856(SB)/8,$0x000000013112fb9c
+
+	/* x^205888 mod p(x), x^205824 mod p(x) */
+DATA ·IEEEConst+864(SB)/8,$0x00000000f2b5ea98
+DATA ·IEEEConst+872(SB)/8,$0x00000000b680b906
+
+	/* x^204864 mod p(x), x^204800 mod p(x) */
+DATA ·IEEEConst+880(SB)/8,$0x0000000187132676
+DATA ·IEEEConst+888(SB)/8,$0x000000001a282932
+
+	/* x^203840 mod p(x), x^203776 mod p(x) */
+DATA ·IEEEConst+896(SB)/8,$0x000000010a8c6ad4
+DATA ·IEEEConst+904(SB)/8,$0x0000000089406e7e
+
+	/* x^202816 mod p(x), x^202752 mod p(x) */
+DATA ·IEEEConst+912(SB)/8,$0x00000001e21dfe70
+DATA ·IEEEConst+920(SB)/8,$0x00000001def6be8c
+
+	/* x^201792 mod p(x), x^201728 mod p(x) */
+DATA ·IEEEConst+928(SB)/8,$0x00000001da0050e4
+DATA ·IEEEConst+936(SB)/8,$0x0000000075258728
+
+	/* x^200768 mod p(x), x^200704 mod p(x) */
+DATA ·IEEEConst+944(SB)/8,$0x00000000772172ae
+DATA ·IEEEConst+952(SB)/8,$0x000000019536090a
+
+	/* x^199744 mod p(x), x^199680 mod p(x) */
+DATA ·IEEEConst+960(SB)/8,$0x00000000e47724aa
+DATA ·IEEEConst+968(SB)/8,$0x00000000f2455bfc
+
+	/* x^198720 mod p(x), x^198656 mod p(x) */
+DATA ·IEEEConst+976(SB)/8,$0x000000003cd63ac4
+DATA ·IEEEConst+984(SB)/8,$0x000000018c40baf4
+
+	/* x^197696 mod p(x), x^197632 mod p(x) */
+DATA ·IEEEConst+992(SB)/8,$0x00000001bf47d352
+DATA ·IEEEConst+1000(SB)/8,$0x000000004cd390d4
+
+	/* x^196672 mod p(x), x^196608 mod p(x) */
+DATA ·IEEEConst+1008(SB)/8,$0x000000018dc1d708
+DATA ·IEEEConst+1016(SB)/8,$0x00000001e4ece95a
+
+	/* x^195648 mod p(x), x^195584 mod p(x) */
+DATA ·IEEEConst+1024(SB)/8,$0x000000002d4620a4
+DATA ·IEEEConst+1032(SB)/8,$0x000000001a3ee918
+
+	/* x^194624 mod p(x), x^194560 mod p(x) */
+DATA ·IEEEConst+1040(SB)/8,$0x0000000058fd1740
+DATA ·IEEEConst+1048(SB)/8,$0x000000007c652fb8
+
+	/* x^193600 mod p(x), x^193536 mod p(x) */
+DATA ·IEEEConst+1056(SB)/8,$0x00000000dadd9bfc
+DATA ·IEEEConst+1064(SB)/8,$0x000000011c67842c
+
+	/* x^192576 mod p(x), x^192512 mod p(x) */
+DATA ·IEEEConst+1072(SB)/8,$0x00000001ea2140be
+DATA ·IEEEConst+1080(SB)/8,$0x00000000254f759c
+
+	/* x^191552 mod p(x), x^191488 mod p(x) */
+DATA ·IEEEConst+1088(SB)/8,$0x000000009de128ba
+DATA ·IEEEConst+1096(SB)/8,$0x000000007ece94ca
+
+	/* x^190528 mod p(x), x^190464 mod p(x) */
+DATA ·IEEEConst+1104(SB)/8,$0x000000013ac3aa8e
+DATA ·IEEEConst+1112(SB)/8,$0x0000000038f258c2
+
+	/* x^189504 mod p(x), x^189440 mod p(x) */
+DATA ·IEEEConst+1120(SB)/8,$0x0000000099980562
+DATA ·IEEEConst+1128(SB)/8,$0x00000001cdf17b00
+
+	/* x^188480 mod p(x), x^188416 mod p(x) */
+DATA ·IEEEConst+1136(SB)/8,$0x00000001c1579c86
+DATA ·IEEEConst+1144(SB)/8,$0x000000011f882c16
+
+	/* x^187456 mod p(x), x^187392 mod p(x) */
+DATA ·IEEEConst+1152(SB)/8,$0x0000000068dbbf94
+DATA ·IEEEConst+1160(SB)/8,$0x0000000100093fc8
+
+	/* x^186432 mod p(x), x^186368 mod p(x) */
+DATA ·IEEEConst+1168(SB)/8,$0x000000004509fb04
+DATA ·IEEEConst+1176(SB)/8,$0x00000001cd684f16
+
+	/* x^185408 mod p(x), x^185344 mod p(x) */
+DATA ·IEEEConst+1184(SB)/8,$0x00000001202f6398
+DATA ·IEEEConst+1192(SB)/8,$0x000000004bc6a70a
+
+	/* x^184384 mod p(x), x^184320 mod p(x) */
+DATA ·IEEEConst+1200(SB)/8,$0x000000013aea243e
+DATA ·IEEEConst+1208(SB)/8,$0x000000004fc7e8e4
+
+	/* x^183360 mod p(x), x^183296 mod p(x) */
+DATA ·IEEEConst+1216(SB)/8,$0x00000001b4052ae6
+DATA ·IEEEConst+1224(SB)/8,$0x0000000130103f1c
+
+	/* x^182336 mod p(x), x^182272 mod p(x) */
+DATA ·IEEEConst+1232(SB)/8,$0x00000001cd2a0ae8
+DATA ·IEEEConst+1240(SB)/8,$0x0000000111b0024c
+
+	/* x^181312 mod p(x), x^181248 mod p(x) */
+DATA ·IEEEConst+1248(SB)/8,$0x00000001fe4aa8b4
+DATA ·IEEEConst+1256(SB)/8,$0x000000010b3079da
+
+	/* x^180288 mod p(x), x^180224 mod p(x) */
+DATA ·IEEEConst+1264(SB)/8,$0x00000001d1559a42
+DATA ·IEEEConst+1272(SB)/8,$0x000000010192bcc2
+
+	/* x^179264 mod p(x), x^179200 mod p(x) */
+DATA ·IEEEConst+1280(SB)/8,$0x00000001f3e05ecc
+DATA ·IEEEConst+1288(SB)/8,$0x0000000074838d50
+
+	/* x^178240 mod p(x), x^178176 mod p(x) */
+DATA ·IEEEConst+1296(SB)/8,$0x0000000104ddd2cc
+DATA ·IEEEConst+1304(SB)/8,$0x000000001b20f520
+
+	/* x^177216 mod p(x), x^177152 mod p(x) */
+DATA ·IEEEConst+1312(SB)/8,$0x000000015393153c
+DATA ·IEEEConst+1320(SB)/8,$0x0000000050c3590a
+
+	/* x^176192 mod p(x), x^176128 mod p(x) */
+DATA ·IEEEConst+1328(SB)/8,$0x0000000057e942c6
+DATA ·IEEEConst+1336(SB)/8,$0x00000000b41cac8e
+
+	/* x^175168 mod p(x), x^175104 mod p(x) */
+DATA ·IEEEConst+1344(SB)/8,$0x000000012c633850
+DATA ·IEEEConst+1352(SB)/8,$0x000000000c72cc78
+
+	/* x^174144 mod p(x), x^174080 mod p(x) */
+DATA ·IEEEConst+1360(SB)/8,$0x00000000ebcaae4c
+DATA ·IEEEConst+1368(SB)/8,$0x0000000030cdb032
+
+	/* x^173120 mod p(x), x^173056 mod p(x) */
+DATA ·IEEEConst+1376(SB)/8,$0x000000013ee532a6
+DATA ·IEEEConst+1384(SB)/8,$0x000000013e09fc32
+
+	/* x^172096 mod p(x), x^172032 mod p(x) */
+DATA ·IEEEConst+1392(SB)/8,$0x00000001bf0cbc7e
+DATA ·IEEEConst+1400(SB)/8,$0x000000001ed624d2
+
+	/* x^171072 mod p(x), x^171008 mod p(x) */
+DATA ·IEEEConst+1408(SB)/8,$0x00000000d50b7a5a
+DATA ·IEEEConst+1416(SB)/8,$0x00000000781aee1a
+
+	/* x^170048 mod p(x), x^169984 mod p(x) */
+DATA ·IEEEConst+1424(SB)/8,$0x0000000002fca6e8
+DATA ·IEEEConst+1432(SB)/8,$0x00000001c4d8348c
+
+	/* x^169024 mod p(x), x^168960 mod p(x) */
+DATA ·IEEEConst+1440(SB)/8,$0x000000007af40044
+DATA ·IEEEConst+1448(SB)/8,$0x0000000057a40336
+
+	/* x^168000 mod p(x), x^167936 mod p(x) */
+DATA ·IEEEConst+1456(SB)/8,$0x0000000016178744
+DATA ·IEEEConst+1464(SB)/8,$0x0000000085544940
+
+	/* x^166976 mod p(x), x^166912 mod p(x) */
+DATA ·IEEEConst+1472(SB)/8,$0x000000014c177458
+DATA ·IEEEConst+1480(SB)/8,$0x000000019cd21e80
+
+	/* x^165952 mod p(x), x^165888 mod p(x) */
+DATA ·IEEEConst+1488(SB)/8,$0x000000011b6ddf04
+DATA ·IEEEConst+1496(SB)/8,$0x000000013eb95bc0
+
+	/* x^164928 mod p(x), x^164864 mod p(x) */
+DATA ·IEEEConst+1504(SB)/8,$0x00000001f3e29ccc
+DATA ·IEEEConst+1512(SB)/8,$0x00000001dfc9fdfc
+
+	/* x^163904 mod p(x), x^163840 mod p(x) */
+DATA ·IEEEConst+1520(SB)/8,$0x0000000135ae7562
+DATA ·IEEEConst+1528(SB)/8,$0x00000000cd028bc2
+
+	/* x^162880 mod p(x), x^162816 mod p(x) */
+DATA ·IEEEConst+1536(SB)/8,$0x0000000190ef812c
+DATA ·IEEEConst+1544(SB)/8,$0x0000000090db8c44
+
+	/* x^161856 mod p(x), x^161792 mod p(x) */
+DATA ·IEEEConst+1552(SB)/8,$0x0000000067a2c786
+DATA ·IEEEConst+1560(SB)/8,$0x000000010010a4ce
+
+	/* x^160832 mod p(x), x^160768 mod p(x) */
+DATA ·IEEEConst+1568(SB)/8,$0x0000000048b9496c
+DATA ·IEEEConst+1576(SB)/8,$0x00000001c8f4c72c
+
+	/* x^159808 mod p(x), x^159744 mod p(x) */
+DATA ·IEEEConst+1584(SB)/8,$0x000000015a422de6
+DATA ·IEEEConst+1592(SB)/8,$0x000000001c26170c
+
+	/* x^158784 mod p(x), x^158720 mod p(x) */
+DATA ·IEEEConst+1600(SB)/8,$0x00000001ef0e3640
+DATA ·IEEEConst+1608(SB)/8,$0x00000000e3fccf68
+
+	/* x^157760 mod p(x), x^157696 mod p(x) */
+DATA ·IEEEConst+1616(SB)/8,$0x00000001006d2d26
+DATA ·IEEEConst+1624(SB)/8,$0x00000000d513ed24
+
+	/* x^156736 mod p(x), x^156672 mod p(x) */
+DATA ·IEEEConst+1632(SB)/8,$0x00000001170d56d6
+DATA ·IEEEConst+1640(SB)/8,$0x00000000141beada
+
+	/* x^155712 mod p(x), x^155648 mod p(x) */
+DATA ·IEEEConst+1648(SB)/8,$0x00000000a5fb613c
+DATA ·IEEEConst+1656(SB)/8,$0x000000011071aea0
+
+	/* x^154688 mod p(x), x^154624 mod p(x) */
+DATA ·IEEEConst+1664(SB)/8,$0x0000000040bbf7fc
+DATA ·IEEEConst+1672(SB)/8,$0x000000012e19080a
+
+	/* x^153664 mod p(x), x^153600 mod p(x) */
+DATA ·IEEEConst+1680(SB)/8,$0x000000016ac3a5b2
+DATA ·IEEEConst+1688(SB)/8,$0x0000000100ecf826
+
+	/* x^152640 mod p(x), x^152576 mod p(x) */
+DATA ·IEEEConst+1696(SB)/8,$0x00000000abf16230
+DATA ·IEEEConst+1704(SB)/8,$0x0000000069b09412
+
+	/* x^151616 mod p(x), x^151552 mod p(x) */
+DATA ·IEEEConst+1712(SB)/8,$0x00000001ebe23fac
+DATA ·IEEEConst+1720(SB)/8,$0x0000000122297bac
+
+	/* x^150592 mod p(x), x^150528 mod p(x) */
+DATA ·IEEEConst+1728(SB)/8,$0x000000008b6a0894
+DATA ·IEEEConst+1736(SB)/8,$0x00000000e9e4b068
+
+	/* x^149568 mod p(x), x^149504 mod p(x) */
+DATA ·IEEEConst+1744(SB)/8,$0x00000001288ea478
+DATA ·IEEEConst+1752(SB)/8,$0x000000004b38651a
+
+	/* x^148544 mod p(x), x^148480 mod p(x) */
+DATA ·IEEEConst+1760(SB)/8,$0x000000016619c442
+DATA ·IEEEConst+1768(SB)/8,$0x00000001468360e2
+
+	/* x^147520 mod p(x), x^147456 mod p(x) */
+DATA ·IEEEConst+1776(SB)/8,$0x0000000086230038
+DATA ·IEEEConst+1784(SB)/8,$0x00000000121c2408
+
+	/* x^146496 mod p(x), x^146432 mod p(x) */
+DATA ·IEEEConst+1792(SB)/8,$0x000000017746a756
+DATA ·IEEEConst+1800(SB)/8,$0x00000000da7e7d08
+
+	/* x^145472 mod p(x), x^145408 mod p(x) */
+DATA ·IEEEConst+1808(SB)/8,$0x0000000191b8f8f8
+DATA ·IEEEConst+1816(SB)/8,$0x00000001058d7652
+
+	/* x^144448 mod p(x), x^144384 mod p(x) */
+DATA ·IEEEConst+1824(SB)/8,$0x000000008e167708
+DATA ·IEEEConst+1832(SB)/8,$0x000000014a098a90
+
+	/* x^143424 mod p(x), x^143360 mod p(x) */
+DATA ·IEEEConst+1840(SB)/8,$0x0000000148b22d54
+DATA ·IEEEConst+1848(SB)/8,$0x0000000020dbe72e
+
+	/* x^142400 mod p(x), x^142336 mod p(x) */
+DATA ·IEEEConst+1856(SB)/8,$0x0000000044ba2c3c
+DATA ·IEEEConst+1864(SB)/8,$0x000000011e7323e8
+
+	/* x^141376 mod p(x), x^141312 mod p(x) */
+DATA ·IEEEConst+1872(SB)/8,$0x00000000b54d2b52
+DATA ·IEEEConst+1880(SB)/8,$0x00000000d5d4bf94
+
+	/* x^140352 mod p(x), x^140288 mod p(x) */
+DATA ·IEEEConst+1888(SB)/8,$0x0000000005a4fd8a
+DATA ·IEEEConst+1896(SB)/8,$0x0000000199d8746c
+
+	/* x^139328 mod p(x), x^139264 mod p(x) */
+DATA ·IEEEConst+1904(SB)/8,$0x0000000139f9fc46
+DATA ·IEEEConst+1912(SB)/8,$0x00000000ce9ca8a0
+
+	/* x^138304 mod p(x), x^138240 mod p(x) */
+DATA ·IEEEConst+1920(SB)/8,$0x000000015a1fa824
+DATA ·IEEEConst+1928(SB)/8,$0x00000000136edece
+
+	/* x^137280 mod p(x), x^137216 mod p(x) */
+DATA ·IEEEConst+1936(SB)/8,$0x000000000a61ae4c
+DATA ·IEEEConst+1944(SB)/8,$0x000000019b92a068
+
+	/* x^136256 mod p(x), x^136192 mod p(x) */
+DATA ·IEEEConst+1952(SB)/8,$0x0000000145e9113e
+DATA ·IEEEConst+1960(SB)/8,$0x0000000071d62206
+
+	/* x^135232 mod p(x), x^135168 mod p(x) */
+DATA ·IEEEConst+1968(SB)/8,$0x000000006a348448
+DATA ·IEEEConst+1976(SB)/8,$0x00000000dfc50158
+
+	/* x^134208 mod p(x), x^134144 mod p(x) */
+DATA ·IEEEConst+1984(SB)/8,$0x000000004d80a08c
+DATA ·IEEEConst+1992(SB)/8,$0x00000001517626bc
+
+	/* x^133184 mod p(x), x^133120 mod p(x) */
+DATA ·IEEEConst+2000(SB)/8,$0x000000014b6837a0
+DATA ·IEEEConst+2008(SB)/8,$0x0000000148d1e4fa
+
+	/* x^132160 mod p(x), x^132096 mod p(x) */
+DATA ·IEEEConst+2016(SB)/8,$0x000000016896a7fc
+DATA ·IEEEConst+2024(SB)/8,$0x0000000094d8266e
+
+	/* x^131136 mod p(x), x^131072 mod p(x) */
+DATA ·IEEEConst+2032(SB)/8,$0x000000014f187140
+DATA ·IEEEConst+2040(SB)/8,$0x00000000606c5e34
+
+	/* x^130112 mod p(x), x^130048 mod p(x) */
+DATA ·IEEEConst+2048(SB)/8,$0x000000019581b9da
+DATA ·IEEEConst+2056(SB)/8,$0x000000019766beaa
+
+	/* x^129088 mod p(x), x^129024 mod p(x) */
+DATA ·IEEEConst+2064(SB)/8,$0x00000001091bc984
+DATA ·IEEEConst+2072(SB)/8,$0x00000001d80c506c
+
+	/* x^128064 mod p(x), x^128000 mod p(x) */
+DATA ·IEEEConst+2080(SB)/8,$0x000000001067223c
+DATA ·IEEEConst+2088(SB)/8,$0x000000001e73837c
+
+	/* x^127040 mod p(x), x^126976 mod p(x) */
+DATA ·IEEEConst+2096(SB)/8,$0x00000001ab16ea02
+DATA ·IEEEConst+2104(SB)/8,$0x0000000064d587de
+
+	/* x^126016 mod p(x), x^125952 mod p(x) */
+DATA ·IEEEConst+2112(SB)/8,$0x000000013c4598a8
+DATA ·IEEEConst+2120(SB)/8,$0x00000000f4a507b0
+
+	/* x^124992 mod p(x), x^124928 mod p(x) */
+DATA ·IEEEConst+2128(SB)/8,$0x00000000b3735430
+DATA ·IEEEConst+2136(SB)/8,$0x0000000040e342fc
+
+	/* x^123968 mod p(x), x^123904 mod p(x) */
+DATA ·IEEEConst+2144(SB)/8,$0x00000001bb3fc0c0
+DATA ·IEEEConst+2152(SB)/8,$0x00000001d5ad9c3a
+
+	/* x^122944 mod p(x), x^122880 mod p(x) */
+DATA ·IEEEConst+2160(SB)/8,$0x00000001570ae19c
+DATA ·IEEEConst+2168(SB)/8,$0x0000000094a691a4
+
+	/* x^121920 mod p(x), x^121856 mod p(x) */
+DATA ·IEEEConst+2176(SB)/8,$0x00000001ea910712
+DATA ·IEEEConst+2184(SB)/8,$0x00000001271ecdfa
+
+	/* x^120896 mod p(x), x^120832 mod p(x) */
+DATA ·IEEEConst+2192(SB)/8,$0x0000000167127128
+DATA ·IEEEConst+2200(SB)/8,$0x000000009e54475a
+
+	/* x^119872 mod p(x), x^119808 mod p(x) */
+DATA ·IEEEConst+2208(SB)/8,$0x0000000019e790a2
+DATA ·IEEEConst+2216(SB)/8,$0x00000000c9c099ee
+
+	/* x^118848 mod p(x), x^118784 mod p(x) */
+DATA ·IEEEConst+2224(SB)/8,$0x000000003788f710
+DATA ·IEEEConst+2232(SB)/8,$0x000000009a2f736c
+
+	/* x^117824 mod p(x), x^117760 mod p(x) */
+DATA ·IEEEConst+2240(SB)/8,$0x00000001682a160e
+DATA ·IEEEConst+2248(SB)/8,$0x00000000bb9f4996
+
+	/* x^116800 mod p(x), x^116736 mod p(x) */
+DATA ·IEEEConst+2256(SB)/8,$0x000000007f0ebd2e
+DATA ·IEEEConst+2264(SB)/8,$0x00000001db688050
+
+	/* x^115776 mod p(x), x^115712 mod p(x) */
+DATA ·IEEEConst+2272(SB)/8,$0x000000002b032080
+DATA ·IEEEConst+2280(SB)/8,$0x00000000e9b10af4
+
+	/* x^114752 mod p(x), x^114688 mod p(x) */
+DATA ·IEEEConst+2288(SB)/8,$0x00000000cfd1664a
+DATA ·IEEEConst+2296(SB)/8,$0x000000012d4545e4
+
+	/* x^113728 mod p(x), x^113664 mod p(x) */
+DATA ·IEEEConst+2304(SB)/8,$0x00000000aa1181c2
+DATA ·IEEEConst+2312(SB)/8,$0x000000000361139c
+
+	/* x^112704 mod p(x), x^112640 mod p(x) */
+DATA ·IEEEConst+2320(SB)/8,$0x00000000ddd08002
+DATA ·IEEEConst+2328(SB)/8,$0x00000001a5a1a3a8
+
+	/* x^111680 mod p(x), x^111616 mod p(x) */
+DATA ·IEEEConst+2336(SB)/8,$0x00000000e8dd0446
+DATA ·IEEEConst+2344(SB)/8,$0x000000006844e0b0
+
+	/* x^110656 mod p(x), x^110592 mod p(x) */
+DATA ·IEEEConst+2352(SB)/8,$0x00000001bbd94a00
+DATA ·IEEEConst+2360(SB)/8,$0x00000000c3762f28
+
+	/* x^109632 mod p(x), x^109568 mod p(x) */
+DATA ·IEEEConst+2368(SB)/8,$0x00000000ab6cd180
+DATA ·IEEEConst+2376(SB)/8,$0x00000001d26287a2
+
+	/* x^108608 mod p(x), x^108544 mod p(x) */
+DATA ·IEEEConst+2384(SB)/8,$0x0000000031803ce2
+DATA ·IEEEConst+2392(SB)/8,$0x00000001f6f0bba8
+
+	/* x^107584 mod p(x), x^107520 mod p(x) */
+DATA ·IEEEConst+2400(SB)/8,$0x0000000024f40b0c
+DATA ·IEEEConst+2408(SB)/8,$0x000000002ffabd62
+
+	/* x^106560 mod p(x), x^106496 mod p(x) */
+DATA ·IEEEConst+2416(SB)/8,$0x00000001ba1d9834
+DATA ·IEEEConst+2424(SB)/8,$0x00000000fb4516b8
+
+	/* x^105536 mod p(x), x^105472 mod p(x) */
+DATA ·IEEEConst+2432(SB)/8,$0x0000000104de61aa
+DATA ·IEEEConst+2440(SB)/8,$0x000000018cfa961c
+
+	/* x^104512 mod p(x), x^104448 mod p(x) */
+DATA ·IEEEConst+2448(SB)/8,$0x0000000113e40d46
+DATA ·IEEEConst+2456(SB)/8,$0x000000019e588d52
+
+	/* x^103488 mod p(x), x^103424 mod p(x) */
+DATA ·IEEEConst+2464(SB)/8,$0x00000001415598a0
+DATA ·IEEEConst+2472(SB)/8,$0x00000001180f0bbc
+
+	/* x^102464 mod p(x), x^102400 mod p(x) */
+DATA ·IEEEConst+2480(SB)/8,$0x00000000bf6c8c90
+DATA ·IEEEConst+2488(SB)/8,$0x00000000e1d9177a
+
+	/* x^101440 mod p(x), x^101376 mod p(x) */
+DATA ·IEEEConst+2496(SB)/8,$0x00000001788b0504
+DATA ·IEEEConst+2504(SB)/8,$0x0000000105abc27c
+
+	/* x^100416 mod p(x), x^100352 mod p(x) */
+DATA ·IEEEConst+2512(SB)/8,$0x0000000038385d02
+DATA ·IEEEConst+2520(SB)/8,$0x00000000972e4a58
+
+	/* x^99392 mod p(x), x^99328 mod p(x) */
+DATA ·IEEEConst+2528(SB)/8,$0x00000001b6c83844
+DATA ·IEEEConst+2536(SB)/8,$0x0000000183499a5e
+
+	/* x^98368 mod p(x), x^98304 mod p(x) */
+DATA ·IEEEConst+2544(SB)/8,$0x0000000051061a8a
+DATA ·IEEEConst+2552(SB)/8,$0x00000001c96a8cca
+
+	/* x^97344 mod p(x), x^97280 mod p(x) */
+DATA ·IEEEConst+2560(SB)/8,$0x000000017351388a
+DATA ·IEEEConst+2568(SB)/8,$0x00000001a1a5b60c
+
+	/* x^96320 mod p(x), x^96256 mod p(x) */
+DATA ·IEEEConst+2576(SB)/8,$0x0000000132928f92
+DATA ·IEEEConst+2584(SB)/8,$0x00000000e4b6ac9c
+
+	/* x^95296 mod p(x), x^95232 mod p(x) */
+DATA ·IEEEConst+2592(SB)/8,$0x00000000e6b4f48a
+DATA ·IEEEConst+2600(SB)/8,$0x00000001807e7f5a
+
+	/* x^94272 mod p(x), x^94208 mod p(x) */
+DATA ·IEEEConst+2608(SB)/8,$0x0000000039d15e90
+DATA ·IEEEConst+2616(SB)/8,$0x000000017a7e3bc8
+
+	/* x^93248 mod p(x), x^93184 mod p(x) */
+DATA ·IEEEConst+2624(SB)/8,$0x00000000312d6074
+DATA ·IEEEConst+2632(SB)/8,$0x00000000d73975da
+
+	/* x^92224 mod p(x), x^92160 mod p(x) */
+DATA ·IEEEConst+2640(SB)/8,$0x000000017bbb2cc4
+DATA ·IEEEConst+2648(SB)/8,$0x000000017375d038
+
+	/* x^91200 mod p(x), x^91136 mod p(x) */
+DATA ·IEEEConst+2656(SB)/8,$0x000000016ded3e18
+DATA ·IEEEConst+2664(SB)/8,$0x00000000193680bc
+
+	/* x^90176 mod p(x), x^90112 mod p(x) */
+DATA ·IEEEConst+2672(SB)/8,$0x00000000f1638b16
+DATA ·IEEEConst+2680(SB)/8,$0x00000000999b06f6
+
+	/* x^89152 mod p(x), x^89088 mod p(x) */
+DATA ·IEEEConst+2688(SB)/8,$0x00000001d38b9ecc
+DATA ·IEEEConst+2696(SB)/8,$0x00000001f685d2b8
+
+	/* x^88128 mod p(x), x^88064 mod p(x) */
+DATA ·IEEEConst+2704(SB)/8,$0x000000018b8d09dc
+DATA ·IEEEConst+2712(SB)/8,$0x00000001f4ecbed2
+
+	/* x^87104 mod p(x), x^87040 mod p(x) */
+DATA ·IEEEConst+2720(SB)/8,$0x00000000e7bc27d2
+DATA ·IEEEConst+2728(SB)/8,$0x00000000ba16f1a0
+
+	/* x^86080 mod p(x), x^86016 mod p(x) */
+DATA ·IEEEConst+2736(SB)/8,$0x00000000275e1e96
+DATA ·IEEEConst+2744(SB)/8,$0x0000000115aceac4
+
+	/* x^85056 mod p(x), x^84992 mod p(x) */
+DATA ·IEEEConst+2752(SB)/8,$0x00000000e2e3031e
+DATA ·IEEEConst+2760(SB)/8,$0x00000001aeff6292
+
+	/* x^84032 mod p(x), x^83968 mod p(x) */
+DATA ·IEEEConst+2768(SB)/8,$0x00000001041c84d8
+DATA ·IEEEConst+2776(SB)/8,$0x000000009640124c
+
+	/* x^83008 mod p(x), x^82944 mod p(x) */
+DATA ·IEEEConst+2784(SB)/8,$0x00000000706ce672
+DATA ·IEEEConst+2792(SB)/8,$0x0000000114f41f02
+
+	/* x^81984 mod p(x), x^81920 mod p(x) */
+DATA ·IEEEConst+2800(SB)/8,$0x000000015d5070da
+DATA ·IEEEConst+2808(SB)/8,$0x000000009c5f3586
+
+	/* x^80960 mod p(x), x^80896 mod p(x) */
+DATA ·IEEEConst+2816(SB)/8,$0x0000000038f9493a
+DATA ·IEEEConst+2824(SB)/8,$0x00000001878275fa
+
+	/* x^79936 mod p(x), x^79872 mod p(x) */
+DATA ·IEEEConst+2832(SB)/8,$0x00000000a3348a76
+DATA ·IEEEConst+2840(SB)/8,$0x00000000ddc42ce8
+
+	/* x^78912 mod p(x), x^78848 mod p(x) */
+DATA ·IEEEConst+2848(SB)/8,$0x00000001ad0aab92
+DATA ·IEEEConst+2856(SB)/8,$0x0000000181d2c73a
+
+	/* x^77888 mod p(x), x^77824 mod p(x) */
+DATA ·IEEEConst+2864(SB)/8,$0x000000019e85f712
+DATA ·IEEEConst+2872(SB)/8,$0x0000000141c9320a
+
+	/* x^76864 mod p(x), x^76800 mod p(x) */
+DATA ·IEEEConst+2880(SB)/8,$0x000000005a871e76
+DATA ·IEEEConst+2888(SB)/8,$0x000000015235719a
+
+	/* x^75840 mod p(x), x^75776 mod p(x) */
+DATA ·IEEEConst+2896(SB)/8,$0x000000017249c662
+DATA ·IEEEConst+2904(SB)/8,$0x00000000be27d804
+
+	/* x^74816 mod p(x), x^74752 mod p(x) */
+DATA ·IEEEConst+2912(SB)/8,$0x000000003a084712
+DATA ·IEEEConst+2920(SB)/8,$0x000000006242d45a
+
+	/* x^73792 mod p(x), x^73728 mod p(x) */
+DATA ·IEEEConst+2928(SB)/8,$0x00000000ed438478
+DATA ·IEEEConst+2936(SB)/8,$0x000000009a53638e
+
+	/* x^72768 mod p(x), x^72704 mod p(x) */
+DATA ·IEEEConst+2944(SB)/8,$0x00000000abac34cc
+DATA ·IEEEConst+2952(SB)/8,$0x00000001001ecfb6
+
+	/* x^71744 mod p(x), x^71680 mod p(x) */
+DATA ·IEEEConst+2960(SB)/8,$0x000000005f35ef3e
+DATA ·IEEEConst+2968(SB)/8,$0x000000016d7c2d64
+
+	/* x^70720 mod p(x), x^70656 mod p(x) */
+DATA ·IEEEConst+2976(SB)/8,$0x0000000047d6608c
+DATA ·IEEEConst+2984(SB)/8,$0x00000001d0ce46c0
+
+	/* x^69696 mod p(x), x^69632 mod p(x) */
+DATA ·IEEEConst+2992(SB)/8,$0x000000002d01470e
+DATA ·IEEEConst+3000(SB)/8,$0x0000000124c907b4
+
+	/* x^68672 mod p(x), x^68608 mod p(x) */
+DATA ·IEEEConst+3008(SB)/8,$0x0000000158bbc7b0
+DATA ·IEEEConst+3016(SB)/8,$0x0000000018a555ca
+
+	/* x^67648 mod p(x), x^67584 mod p(x) */
+DATA ·IEEEConst+3024(SB)/8,$0x00000000c0a23e8e
+DATA ·IEEEConst+3032(SB)/8,$0x000000006b0980bc
+
+	/* x^66624 mod p(x), x^66560 mod p(x) */
+DATA ·IEEEConst+3040(SB)/8,$0x00000001ebd85c88
+DATA ·IEEEConst+3048(SB)/8,$0x000000008bbba964
+
+	/* x^65600 mod p(x), x^65536 mod p(x) */
+DATA ·IEEEConst+3056(SB)/8,$0x000000019ee20bb2
+DATA ·IEEEConst+3064(SB)/8,$0x00000001070a5a1e
+
+	/* x^64576 mod p(x), x^64512 mod p(x) */
+DATA ·IEEEConst+3072(SB)/8,$0x00000001acabf2d6
+DATA ·IEEEConst+3080(SB)/8,$0x000000002204322a
+
+	/* x^63552 mod p(x), x^63488 mod p(x) */
+DATA ·IEEEConst+3088(SB)/8,$0x00000001b7963d56
+DATA ·IEEEConst+3096(SB)/8,$0x00000000a27524d0
+
+	/* x^62528 mod p(x), x^62464 mod p(x) */
+DATA ·IEEEConst+3104(SB)/8,$0x000000017bffa1fe
+DATA ·IEEEConst+3112(SB)/8,$0x0000000020b1e4ba
+
+	/* x^61504 mod p(x), x^61440 mod p(x) */
+DATA ·IEEEConst+3120(SB)/8,$0x000000001f15333e
+DATA ·IEEEConst+3128(SB)/8,$0x0000000032cc27fc
+
+	/* x^60480 mod p(x), x^60416 mod p(x) */
+DATA ·IEEEConst+3136(SB)/8,$0x000000018593129e
+DATA ·IEEEConst+3144(SB)/8,$0x0000000044dd22b8
+
+	/* x^59456 mod p(x), x^59392 mod p(x) */
+DATA ·IEEEConst+3152(SB)/8,$0x000000019cb32602
+DATA ·IEEEConst+3160(SB)/8,$0x00000000dffc9e0a
+
+	/* x^58432 mod p(x), x^58368 mod p(x) */
+DATA ·IEEEConst+3168(SB)/8,$0x0000000142b05cc8
+DATA ·IEEEConst+3176(SB)/8,$0x00000001b7a0ed14
+
+	/* x^57408 mod p(x), x^57344 mod p(x) */
+DATA ·IEEEConst+3184(SB)/8,$0x00000001be49e7a4
+DATA ·IEEEConst+3192(SB)/8,$0x00000000c7842488
+
+	/* x^56384 mod p(x), x^56320 mod p(x) */
+DATA ·IEEEConst+3200(SB)/8,$0x0000000108f69d6c
+DATA ·IEEEConst+3208(SB)/8,$0x00000001c02a4fee
+
+	/* x^55360 mod p(x), x^55296 mod p(x) */
+DATA ·IEEEConst+3216(SB)/8,$0x000000006c0971f0
+DATA ·IEEEConst+3224(SB)/8,$0x000000003c273778
+
+	/* x^54336 mod p(x), x^54272 mod p(x) */
+DATA ·IEEEConst+3232(SB)/8,$0x000000005b16467a
+DATA ·IEEEConst+3240(SB)/8,$0x00000001d63f8894
+
+	/* x^53312 mod p(x), x^53248 mod p(x) */
+DATA ·IEEEConst+3248(SB)/8,$0x00000001551a628e
+DATA ·IEEEConst+3256(SB)/8,$0x000000006be557d6
+
+	/* x^52288 mod p(x), x^52224 mod p(x) */
+DATA ·IEEEConst+3264(SB)/8,$0x000000019e42ea92
+DATA ·IEEEConst+3272(SB)/8,$0x000000006a7806ea
+
+	/* x^51264 mod p(x), x^51200 mod p(x) */
+DATA ·IEEEConst+3280(SB)/8,$0x000000012fa83ff2
+DATA ·IEEEConst+3288(SB)/8,$0x000000016155aa0c
+
+	/* x^50240 mod p(x), x^50176 mod p(x) */
+DATA ·IEEEConst+3296(SB)/8,$0x000000011ca9cde0
+DATA ·IEEEConst+3304(SB)/8,$0x00000000908650ac
+
+	/* x^49216 mod p(x), x^49152 mod p(x) */
+DATA ·IEEEConst+3312(SB)/8,$0x00000000c8e5cd74
+DATA ·IEEEConst+3320(SB)/8,$0x00000000aa5a8084
+
+	/* x^48192 mod p(x), x^48128 mod p(x) */
+DATA ·IEEEConst+3328(SB)/8,$0x0000000096c27f0c
+DATA ·IEEEConst+3336(SB)/8,$0x0000000191bb500a
+
+	/* x^47168 mod p(x), x^47104 mod p(x) */
+DATA ·IEEEConst+3344(SB)/8,$0x000000002baed926
+DATA ·IEEEConst+3352(SB)/8,$0x0000000064e9bed0
+
+	/* x^46144 mod p(x), x^46080 mod p(x) */
+DATA ·IEEEConst+3360(SB)/8,$0x000000017c8de8d2
+DATA ·IEEEConst+3368(SB)/8,$0x000000009444f302
+
+	/* x^45120 mod p(x), x^45056 mod p(x) */
+DATA ·IEEEConst+3376(SB)/8,$0x00000000d43d6068
+DATA ·IEEEConst+3384(SB)/8,$0x000000019db07d3c
+
+	/* x^44096 mod p(x), x^44032 mod p(x) */
+DATA ·IEEEConst+3392(SB)/8,$0x00000000cb2c4b26
+DATA ·IEEEConst+3400(SB)/8,$0x00000001359e3e6e
+
+	/* x^43072 mod p(x), x^43008 mod p(x) */
+DATA ·IEEEConst+3408(SB)/8,$0x0000000145b8da26
+DATA ·IEEEConst+3416(SB)/8,$0x00000001e4f10dd2
+
+	/* x^42048 mod p(x), x^41984 mod p(x) */
+DATA ·IEEEConst+3424(SB)/8,$0x000000018fff4b08
+DATA ·IEEEConst+3432(SB)/8,$0x0000000124f5735e
+
+	/* x^41024 mod p(x), x^40960 mod p(x) */
+DATA ·IEEEConst+3440(SB)/8,$0x0000000150b58ed0
+DATA ·IEEEConst+3448(SB)/8,$0x0000000124760a4c
+
+	/* x^40000 mod p(x), x^39936 mod p(x) */
+DATA ·IEEEConst+3456(SB)/8,$0x00000001549f39bc
+DATA ·IEEEConst+3464(SB)/8,$0x000000000f1fc186
+
+	/* x^38976 mod p(x), x^38912 mod p(x) */
+DATA ·IEEEConst+3472(SB)/8,$0x00000000ef4d2f42
+DATA ·IEEEConst+3480(SB)/8,$0x00000000150e4cc4
+
+	/* x^37952 mod p(x), x^37888 mod p(x) */
+DATA ·IEEEConst+3488(SB)/8,$0x00000001b1468572
+DATA ·IEEEConst+3496(SB)/8,$0x000000002a6204e8
+
+	/* x^36928 mod p(x), x^36864 mod p(x) */
+DATA ·IEEEConst+3504(SB)/8,$0x000000013d7403b2
+DATA ·IEEEConst+3512(SB)/8,$0x00000000beb1d432
+
+	/* x^35904 mod p(x), x^35840 mod p(x) */
+DATA ·IEEEConst+3520(SB)/8,$0x00000001a4681842
+DATA ·IEEEConst+3528(SB)/8,$0x0000000135f3f1f0
+
+	/* x^34880 mod p(x), x^34816 mod p(x) */
+DATA ·IEEEConst+3536(SB)/8,$0x0000000167714492
+DATA ·IEEEConst+3544(SB)/8,$0x0000000074fe2232
+
+	/* x^33856 mod p(x), x^33792 mod p(x) */
+DATA ·IEEEConst+3552(SB)/8,$0x00000001e599099a
+DATA ·IEEEConst+3560(SB)/8,$0x000000001ac6e2ba
+
+	/* x^32832 mod p(x), x^32768 mod p(x) */
+DATA ·IEEEConst+3568(SB)/8,$0x00000000fe128194
+DATA ·IEEEConst+3576(SB)/8,$0x0000000013fca91e
+
+	/* x^31808 mod p(x), x^31744 mod p(x) */
+DATA ·IEEEConst+3584(SB)/8,$0x0000000077e8b990
+DATA ·IEEEConst+3592(SB)/8,$0x0000000183f4931e
+
+	/* x^30784 mod p(x), x^30720 mod p(x) */
+DATA ·IEEEConst+3600(SB)/8,$0x00000001a267f63a
+DATA ·IEEEConst+3608(SB)/8,$0x00000000b6d9b4e4
+
+	/* x^29760 mod p(x), x^29696 mod p(x) */
+DATA ·IEEEConst+3616(SB)/8,$0x00000001945c245a
+DATA ·IEEEConst+3624(SB)/8,$0x00000000b5188656
+
+	/* x^28736 mod p(x), x^28672 mod p(x) */
+DATA ·IEEEConst+3632(SB)/8,$0x0000000149002e76
+DATA ·IEEEConst+3640(SB)/8,$0x0000000027a81a84
+
+	/* x^27712 mod p(x), x^27648 mod p(x) */
+DATA ·IEEEConst+3648(SB)/8,$0x00000001bb8310a4
+DATA ·IEEEConst+3656(SB)/8,$0x0000000125699258
+
+	/* x^26688 mod p(x), x^26624 mod p(x) */
+DATA ·IEEEConst+3664(SB)/8,$0x000000019ec60bcc
+DATA ·IEEEConst+3672(SB)/8,$0x00000001b23de796
+
+	/* x^25664 mod p(x), x^25600 mod p(x) */
+DATA ·IEEEConst+3680(SB)/8,$0x000000012d8590ae
+DATA ·IEEEConst+3688(SB)/8,$0x00000000fe4365dc
+
+	/* x^24640 mod p(x), x^24576 mod p(x) */
+DATA ·IEEEConst+3696(SB)/8,$0x0000000065b00684
+DATA ·IEEEConst+3704(SB)/8,$0x00000000c68f497a
+
+	/* x^23616 mod p(x), x^23552 mod p(x) */
+DATA ·IEEEConst+3712(SB)/8,$0x000000015e5aeadc
+DATA ·IEEEConst+3720(SB)/8,$0x00000000fbf521ee
+
+	/* x^22592 mod p(x), x^22528 mod p(x) */
+DATA ·IEEEConst+3728(SB)/8,$0x00000000b77ff2b0
+DATA ·IEEEConst+3736(SB)/8,$0x000000015eac3378
+
+	/* x^21568 mod p(x), x^21504 mod p(x) */
+DATA ·IEEEConst+3744(SB)/8,$0x0000000188da2ff6
+DATA ·IEEEConst+3752(SB)/8,$0x0000000134914b90
+
+	/* x^20544 mod p(x), x^20480 mod p(x) */
+DATA ·IEEEConst+3760(SB)/8,$0x0000000063da929a
+DATA ·IEEEConst+3768(SB)/8,$0x0000000016335cfe
+
+	/* x^19520 mod p(x), x^19456 mod p(x) */
+DATA ·IEEEConst+3776(SB)/8,$0x00000001389caa80
+DATA ·IEEEConst+3784(SB)/8,$0x000000010372d10c
+
+	/* x^18496 mod p(x), x^18432 mod p(x) */
+DATA ·IEEEConst+3792(SB)/8,$0x000000013db599d2
+DATA ·IEEEConst+3800(SB)/8,$0x000000015097b908
+
+	/* x^17472 mod p(x), x^17408 mod p(x) */
+DATA ·IEEEConst+3808(SB)/8,$0x0000000122505a86
+DATA ·IEEEConst+3816(SB)/8,$0x00000001227a7572
+
+	/* x^16448 mod p(x), x^16384 mod p(x) */
+DATA ·IEEEConst+3824(SB)/8,$0x000000016bd72746
+DATA ·IEEEConst+3832(SB)/8,$0x000000009a8f75c0
+
+	/* x^15424 mod p(x), x^15360 mod p(x) */
+DATA ·IEEEConst+3840(SB)/8,$0x00000001c3faf1d4
+DATA ·IEEEConst+3848(SB)/8,$0x00000000682c77a2
+
+	/* x^14400 mod p(x), x^14336 mod p(x) */
+DATA ·IEEEConst+3856(SB)/8,$0x00000001111c826c
+DATA ·IEEEConst+3864(SB)/8,$0x00000000231f091c
+
+	/* x^13376 mod p(x), x^13312 mod p(x) */
+DATA ·IEEEConst+3872(SB)/8,$0x00000000153e9fb2
+DATA ·IEEEConst+3880(SB)/8,$0x000000007d4439f2
+
+	/* x^12352 mod p(x), x^12288 mod p(x) */
+DATA ·IEEEConst+3888(SB)/8,$0x000000002b1f7b60
+DATA ·IEEEConst+3896(SB)/8,$0x000000017e221efc
+
+	/* x^11328 mod p(x), x^11264 mod p(x) */
+DATA ·IEEEConst+3904(SB)/8,$0x00000000b1dba570
+DATA ·IEEEConst+3912(SB)/8,$0x0000000167457c38
+
+	/* x^10304 mod p(x), x^10240 mod p(x) */
+DATA ·IEEEConst+3920(SB)/8,$0x00000001f6397b76
+DATA ·IEEEConst+3928(SB)/8,$0x00000000bdf081c4
+
+	/* x^9280 mod p(x), x^9216 mod p(x) */
+DATA ·IEEEConst+3936(SB)/8,$0x0000000156335214
+DATA ·IEEEConst+3944(SB)/8,$0x000000016286d6b0
+
+	/* x^8256 mod p(x), x^8192 mod p(x) */
+DATA ·IEEEConst+3952(SB)/8,$0x00000001d70e3986
+DATA ·IEEEConst+3960(SB)/8,$0x00000000c84f001c
+
+	/* x^7232 mod p(x), x^7168 mod p(x) */
+DATA ·IEEEConst+3968(SB)/8,$0x000000003701a774
+DATA ·IEEEConst+3976(SB)/8,$0x0000000064efe7c0
+
+	/* x^6208 mod p(x), x^6144 mod p(x) */
+DATA ·IEEEConst+3984(SB)/8,$0x00000000ac81ef72
+DATA ·IEEEConst+3992(SB)/8,$0x000000000ac2d904
+
+	/* x^5184 mod p(x), x^5120 mod p(x) */
+DATA ·IEEEConst+4000(SB)/8,$0x0000000133212464
+DATA ·IEEEConst+4008(SB)/8,$0x00000000fd226d14
+
+	/* x^4160 mod p(x), x^4096 mod p(x) */
+DATA ·IEEEConst+4016(SB)/8,$0x00000000e4e45610
+DATA ·IEEEConst+4024(SB)/8,$0x000000011cfd42e0
+
+	/* x^3136 mod p(x), x^3072 mod p(x) */
+DATA ·IEEEConst+4032(SB)/8,$0x000000000c1bd370
+DATA ·IEEEConst+4040(SB)/8,$0x000000016e5a5678
+
+	/* x^2112 mod p(x), x^2048 mod p(x) */
+DATA ·IEEEConst+4048(SB)/8,$0x00000001a7b9e7a6
+DATA ·IEEEConst+4056(SB)/8,$0x00000001d888fe22
+
+	/* x^1088 mod p(x), x^1024 mod p(x) */
+DATA ·IEEEConst+4064(SB)/8,$0x000000007d657a10
+DATA ·IEEEConst+4072(SB)/8,$0x00000001af77fcd4
+
+	/* x^2048 mod p(x), x^2016 mod p(x), x^1984 mod p(x), x^1952 mod p(x) */
+DATA ·IEEEConst+4080(SB)/8,$0x99168a18ec447f11
+DATA ·IEEEConst+4088(SB)/8,$0xed837b2613e8221e
+
+	/* x^1920 mod p(x), x^1888 mod p(x), x^1856 mod p(x), x^1824 mod p(x) */
+DATA ·IEEEConst+4096(SB)/8,$0xe23e954e8fd2cd3c
+DATA ·IEEEConst+4104(SB)/8,$0xc8acdd8147b9ce5a
+
+	/* x^1792 mod p(x), x^1760 mod p(x), x^1728 mod p(x), x^1696 mod p(x) */
+DATA ·IEEEConst+4112(SB)/8,$0x92f8befe6b1d2b53
+DATA ·IEEEConst+4120(SB)/8,$0xd9ad6d87d4277e25
+
+	/* x^1664 mod p(x), x^1632 mod p(x), x^1600 mod p(x), x^1568 mod p(x) */
+DATA ·IEEEConst+4128(SB)/8,$0xf38a3556291ea462
+DATA ·IEEEConst+4136(SB)/8,$0xc10ec5e033fbca3b
+
+	/* x^1536 mod p(x), x^1504 mod p(x), x^1472 mod p(x), x^1440 mod p(x) */
+DATA ·IEEEConst+4144(SB)/8,$0x974ac56262b6ca4b
+DATA ·IEEEConst+4152(SB)/8,$0xc0b55b0e82e02e2f
+
+	/* x^1408 mod p(x), x^1376 mod p(x), x^1344 mod p(x), x^1312 mod p(x) */
+DATA ·IEEEConst+4160(SB)/8,$0x855712b3784d2a56
+DATA ·IEEEConst+4168(SB)/8,$0x71aa1df0e172334d
+
+	/* x^1280 mod p(x), x^1248 mod p(x), x^1216 mod p(x), x^1184 mod p(x) */
+DATA ·IEEEConst+4176(SB)/8,$0xa5abe9f80eaee722
+DATA ·IEEEConst+4184(SB)/8,$0xfee3053e3969324d
+
+	/* x^1152 mod p(x), x^1120 mod p(x), x^1088 mod p(x), x^1056 mod p(x) */
+DATA ·IEEEConst+4192(SB)/8,$0x1fa0943ddb54814c
+DATA ·IEEEConst+4200(SB)/8,$0xf44779b93eb2bd08
+
+	/* x^1024 mod p(x), x^992 mod p(x), x^960 mod p(x), x^928 mod p(x) */
+DATA ·IEEEConst+4208(SB)/8,$0xa53ff440d7bbfe6a
+DATA ·IEEEConst+4216(SB)/8,$0xf5449b3f00cc3374
+
+	/* x^896 mod p(x), x^864 mod p(x), x^832 mod p(x), x^800 mod p(x) */
+DATA ·IEEEConst+4224(SB)/8,$0xebe7e3566325605c
+DATA ·IEEEConst+4232(SB)/8,$0x6f8346e1d777606e
+
+	/* x^768 mod p(x), x^736 mod p(x), x^704 mod p(x), x^672 mod p(x) */
+DATA ·IEEEConst+4240(SB)/8,$0xc65a272ce5b592b8
+DATA ·IEEEConst+4248(SB)/8,$0xe3ab4f2ac0b95347
+
+	/* x^640 mod p(x), x^608 mod p(x), x^576 mod p(x), x^544 mod p(x) */
+DATA ·IEEEConst+4256(SB)/8,$0x5705a9ca4721589f
+DATA ·IEEEConst+4264(SB)/8,$0xaa2215ea329ecc11
+
+	/* x^512 mod p(x), x^480 mod p(x), x^448 mod p(x), x^416 mod p(x) */
+DATA ·IEEEConst+4272(SB)/8,$0xe3720acb88d14467
+DATA ·IEEEConst+4280(SB)/8,$0x1ed8f66ed95efd26
+
+	/* x^384 mod p(x), x^352 mod p(x), x^320 mod p(x), x^288 mod p(x) */
+DATA ·IEEEConst+4288(SB)/8,$0xba1aca0315141c31
+DATA ·IEEEConst+4296(SB)/8,$0x78ed02d5a700e96a
+
+	/* x^256 mod p(x), x^224 mod p(x), x^192 mod p(x), x^160 mod p(x) */
+DATA ·IEEEConst+4304(SB)/8,$0xad2a31b3ed627dae
+DATA ·IEEEConst+4312(SB)/8,$0xba8ccbe832b39da3
+
+	/* x^128 mod p(x), x^96 mod p(x), x^64 mod p(x), x^32 mod p(x) */
+DATA ·IEEEConst+4320(SB)/8,$0x6655004fa06a2517
+DATA ·IEEEConst+4328(SB)/8,$0xedb88320b1e6b092
+
+GLOBL ·IEEEConst(SB),RODATA,$4336
+
+ /* Barrett constant m - (4^32)/n */
+DATA ·IEEEBarConst(SB)/8,$0x00000001f7011641
+DATA ·IEEEBarConst+8(SB)/8,$0x0000000000000000
+DATA ·IEEEBarConst+16(SB)/8,$0x00000001db710641
+DATA ·IEEEBarConst+24(SB)/8,$0x0000000000000000
+GLOBL ·IEEEBarConst(SB),RODATA,$32
+
+	/* Reduce 262144 kbits to 1024 bits */
+	/* x^261184 mod p(x), x^261120 mod p(x) */
+DATA ·CastConst+0(SB)/8,$0x000000009c37c408
+DATA ·CastConst+8(SB)/8,$0x00000000b6ca9e20
+
+	/* x^260160 mod p(x), x^260096 mod p(x) */
+DATA ·CastConst+16(SB)/8,$0x00000001b51df26c
+DATA ·CastConst+24(SB)/8,$0x00000000350249a8
+
+	/* x^259136 mod p(x), x^259072 mod p(x) */
+DATA ·CastConst+32(SB)/8,$0x000000000724b9d0
+DATA ·CastConst+40(SB)/8,$0x00000001862dac54
+
+	/* x^258112 mod p(x), x^258048 mod p(x) */
+DATA ·CastConst+48(SB)/8,$0x00000001c00532fe
+DATA ·CastConst+56(SB)/8,$0x00000001d87fb48c
+
+	/* x^257088 mod p(x), x^257024 mod p(x) */
+DATA ·CastConst+64(SB)/8,$0x00000000f05a9362
+DATA ·CastConst+72(SB)/8,$0x00000001f39b699e
+
+	/* x^256064 mod p(x), x^256000 mod p(x) */
+DATA ·CastConst+80(SB)/8,$0x00000001e1007970
+DATA ·CastConst+88(SB)/8,$0x0000000101da11b4
+
+	/* x^255040 mod p(x), x^254976 mod p(x) */
+DATA ·CastConst+96(SB)/8,$0x00000000a57366ee
+DATA ·CastConst+104(SB)/8,$0x00000001cab571e0
+
+	/* x^254016 mod p(x), x^253952 mod p(x) */
+DATA ·CastConst+112(SB)/8,$0x0000000192011284
+DATA ·CastConst+120(SB)/8,$0x00000000c7020cfe
+
+	/* x^252992 mod p(x), x^252928 mod p(x) */
+DATA ·CastConst+128(SB)/8,$0x0000000162716d9a
+DATA ·CastConst+136(SB)/8,$0x00000000cdaed1ae
+
+	/* x^251968 mod p(x), x^251904 mod p(x) */
+DATA ·CastConst+144(SB)/8,$0x00000000cd97ecde
+DATA ·CastConst+152(SB)/8,$0x00000001e804effc
+
+	/* x^250944 mod p(x), x^250880 mod p(x) */
+DATA ·CastConst+160(SB)/8,$0x0000000058812bc0
+DATA ·CastConst+168(SB)/8,$0x0000000077c3ea3a
+
+	/* x^249920 mod p(x), x^249856 mod p(x) */
+DATA ·CastConst+176(SB)/8,$0x0000000088b8c12e
+DATA ·CastConst+184(SB)/8,$0x0000000068df31b4
+
+	/* x^248896 mod p(x), x^248832 mod p(x) */
+DATA ·CastConst+192(SB)/8,$0x00000001230b234c
+DATA ·CastConst+200(SB)/8,$0x00000000b059b6c2
+
+	/* x^247872 mod p(x), x^247808 mod p(x) */
+DATA ·CastConst+208(SB)/8,$0x00000001120b416e
+DATA ·CastConst+216(SB)/8,$0x0000000145fb8ed8
+
+	/* x^246848 mod p(x), x^246784 mod p(x) */
+DATA ·CastConst+224(SB)/8,$0x00000001974aecb0
+DATA ·CastConst+232(SB)/8,$0x00000000cbc09168
+
+	/* x^245824 mod p(x), x^245760 mod p(x) */
+DATA ·CastConst+240(SB)/8,$0x000000008ee3f226
+DATA ·CastConst+248(SB)/8,$0x000000005ceeedc2
+
+	/* x^244800 mod p(x), x^244736 mod p(x) */
+DATA ·CastConst+256(SB)/8,$0x00000001089aba9a
+DATA ·CastConst+264(SB)/8,$0x0000000047d74e86
+
+	/* x^243776 mod p(x), x^243712 mod p(x) */
+DATA ·CastConst+272(SB)/8,$0x0000000065113872
+DATA ·CastConst+280(SB)/8,$0x00000001407e9e22
+
+	/* x^242752 mod p(x), x^242688 mod p(x) */
+DATA ·CastConst+288(SB)/8,$0x000000005c07ec10
+DATA ·CastConst+296(SB)/8,$0x00000001da967bda
+
+	/* x^241728 mod p(x), x^241664 mod p(x) */
+DATA ·CastConst+304(SB)/8,$0x0000000187590924
+DATA ·CastConst+312(SB)/8,$0x000000006c898368
+
+	/* x^240704 mod p(x), x^240640 mod p(x) */
+DATA ·CastConst+320(SB)/8,$0x00000000e35da7c6
+DATA ·CastConst+328(SB)/8,$0x00000000f2d14c98
+
+	/* x^239680 mod p(x), x^239616 mod p(x) */
+DATA ·CastConst+336(SB)/8,$0x000000000415855a
+DATA ·CastConst+344(SB)/8,$0x00000001993c6ad4
+
+	/* x^238656 mod p(x), x^238592 mod p(x) */
+DATA ·CastConst+352(SB)/8,$0x0000000073617758
+DATA ·CastConst+360(SB)/8,$0x000000014683d1ac
+
+	/* x^237632 mod p(x), x^237568 mod p(x) */
+DATA ·CastConst+368(SB)/8,$0x0000000176021d28
+DATA ·CastConst+376(SB)/8,$0x00000001a7c93e6c
+
+	/* x^236608 mod p(x), x^236544 mod p(x) */
+DATA ·CastConst+384(SB)/8,$0x00000001c358fd0a
+DATA ·CastConst+392(SB)/8,$0x000000010211e90a
+
+	/* x^235584 mod p(x), x^235520 mod p(x) */
+DATA ·CastConst+400(SB)/8,$0x00000001ff7a2c18
+DATA ·CastConst+408(SB)/8,$0x000000001119403e
+
+	/* x^234560 mod p(x), x^234496 mod p(x) */
+DATA ·CastConst+416(SB)/8,$0x00000000f2d9f7e4
+DATA ·CastConst+424(SB)/8,$0x000000001c3261aa
+
+	/* x^233536 mod p(x), x^233472 mod p(x) */
+DATA ·CastConst+432(SB)/8,$0x000000016cf1f9c8
+DATA ·CastConst+440(SB)/8,$0x000000014e37a634
+
+	/* x^232512 mod p(x), x^232448 mod p(x) */
+DATA ·CastConst+448(SB)/8,$0x000000010af9279a
+DATA ·CastConst+456(SB)/8,$0x0000000073786c0c
+
+	/* x^231488 mod p(x), x^231424 mod p(x) */
+DATA ·CastConst+464(SB)/8,$0x0000000004f101e8
+DATA ·CastConst+472(SB)/8,$0x000000011dc037f8
+
+	/* x^230464 mod p(x), x^230400 mod p(x) */
+DATA ·CastConst+480(SB)/8,$0x0000000070bcf184
+DATA ·CastConst+488(SB)/8,$0x0000000031433dfc
+
+	/* x^229440 mod p(x), x^229376 mod p(x) */
+DATA ·CastConst+496(SB)/8,$0x000000000a8de642
+DATA ·CastConst+504(SB)/8,$0x000000009cde8348
+
+	/* x^228416 mod p(x), x^228352 mod p(x) */
+DATA ·CastConst+512(SB)/8,$0x0000000062ea130c
+DATA ·CastConst+520(SB)/8,$0x0000000038d3c2a6
+
+	/* x^227392 mod p(x), x^227328 mod p(x) */
+DATA ·CastConst+528(SB)/8,$0x00000001eb31cbb2
+DATA ·CastConst+536(SB)/8,$0x000000011b25f260
+
+	/* x^226368 mod p(x), x^226304 mod p(x) */
+DATA ·CastConst+544(SB)/8,$0x0000000170783448
+DATA ·CastConst+552(SB)/8,$0x000000001629e6f0
+
+	/* x^225344 mod p(x), x^225280 mod p(x) */
+DATA ·CastConst+560(SB)/8,$0x00000001a684b4c6
+DATA ·CastConst+568(SB)/8,$0x0000000160838b4c
+
+	/* x^224320 mod p(x), x^224256 mod p(x) */
+DATA ·CastConst+576(SB)/8,$0x00000000253ca5b4
+DATA ·CastConst+584(SB)/8,$0x000000007a44011c
+
+	/* x^223296 mod p(x), x^223232 mod p(x) */
+DATA ·CastConst+592(SB)/8,$0x0000000057b4b1e2
+DATA ·CastConst+600(SB)/8,$0x00000000226f417a
+
+	/* x^222272 mod p(x), x^222208 mod p(x) */
+DATA ·CastConst+608(SB)/8,$0x00000000b6bd084c
+DATA ·CastConst+616(SB)/8,$0x0000000045eb2eb4
+
+	/* x^221248 mod p(x), x^221184 mod p(x) */
+DATA ·CastConst+624(SB)/8,$0x0000000123c2d592
+DATA ·CastConst+632(SB)/8,$0x000000014459d70c
+
+	/* x^220224 mod p(x), x^220160 mod p(x) */
+DATA ·CastConst+640(SB)/8,$0x00000000159dafce
+DATA ·CastConst+648(SB)/8,$0x00000001d406ed82
+
+	/* x^219200 mod p(x), x^219136 mod p(x) */
+DATA ·CastConst+656(SB)/8,$0x0000000127e1a64e
+DATA ·CastConst+664(SB)/8,$0x0000000160c8e1a8
+
+	/* x^218176 mod p(x), x^218112 mod p(x) */
+DATA ·CastConst+672(SB)/8,$0x0000000056860754
+DATA ·CastConst+680(SB)/8,$0x0000000027ba8098
+
+	/* x^217152 mod p(x), x^217088 mod p(x) */
+DATA ·CastConst+688(SB)/8,$0x00000001e661aae8
+DATA ·CastConst+696(SB)/8,$0x000000006d92d018
+
+	/* x^216128 mod p(x), x^216064 mod p(x) */
+DATA ·CastConst+704(SB)/8,$0x00000000f82c6166
+DATA ·CastConst+712(SB)/8,$0x000000012ed7e3f2
+
+	/* x^215104 mod p(x), x^215040 mod p(x) */
+DATA ·CastConst+720(SB)/8,$0x00000000c4f9c7ae
+DATA ·CastConst+728(SB)/8,$0x000000002dc87788
+
+	/* x^214080 mod p(x), x^214016 mod p(x) */
+DATA ·CastConst+736(SB)/8,$0x0000000074203d20
+DATA ·CastConst+744(SB)/8,$0x0000000018240bb8
+
+	/* x^213056 mod p(x), x^212992 mod p(x) */
+DATA ·CastConst+752(SB)/8,$0x0000000198173052
+DATA ·CastConst+760(SB)/8,$0x000000001ad38158
+
+	/* x^212032 mod p(x), x^211968 mod p(x) */
+DATA ·CastConst+768(SB)/8,$0x00000001ce8aba54
+DATA ·CastConst+776(SB)/8,$0x00000001396b78f2
+
+	/* x^211008 mod p(x), x^210944 mod p(x) */
+DATA ·CastConst+784(SB)/8,$0x00000001850d5d94
+DATA ·CastConst+792(SB)/8,$0x000000011a681334
+
+	/* x^209984 mod p(x), x^209920 mod p(x) */
+DATA ·CastConst+800(SB)/8,$0x00000001d609239c
+DATA ·CastConst+808(SB)/8,$0x000000012104732e
+
+	/* x^208960 mod p(x), x^208896 mod p(x) */
+DATA ·CastConst+816(SB)/8,$0x000000001595f048
+DATA ·CastConst+824(SB)/8,$0x00000000a140d90c
+
+	/* x^207936 mod p(x), x^207872 mod p(x) */
+DATA ·CastConst+832(SB)/8,$0x0000000042ccee08
+DATA ·CastConst+840(SB)/8,$0x00000001b7215eda
+
+	/* x^206912 mod p(x), x^206848 mod p(x) */
+DATA ·CastConst+848(SB)/8,$0x000000010a389d74
+DATA ·CastConst+856(SB)/8,$0x00000001aaf1df3c
+
+	/* x^205888 mod p(x), x^205824 mod p(x) */
+DATA ·CastConst+864(SB)/8,$0x000000012a840da6
+DATA ·CastConst+872(SB)/8,$0x0000000029d15b8a
+
+	/* x^204864 mod p(x), x^204800 mod p(x) */
+DATA ·CastConst+880(SB)/8,$0x000000001d181c0c
+DATA ·CastConst+888(SB)/8,$0x00000000f1a96922
+
+	/* x^203840 mod p(x), x^203776 mod p(x) */
+DATA ·CastConst+896(SB)/8,$0x0000000068b7d1f6
+DATA ·CastConst+904(SB)/8,$0x00000001ac80d03c
+
+	/* x^202816 mod p(x), x^202752 mod p(x) */
+DATA ·CastConst+912(SB)/8,$0x000000005b0f14fc
+DATA ·CastConst+920(SB)/8,$0x000000000f11d56a
+
+	/* x^201792 mod p(x), x^201728 mod p(x) */
+DATA ·CastConst+928(SB)/8,$0x0000000179e9e730
+DATA ·CastConst+936(SB)/8,$0x00000001f1c022a2
+
+	/* x^200768 mod p(x), x^200704 mod p(x) */
+DATA ·CastConst+944(SB)/8,$0x00000001ce1368d6
+DATA ·CastConst+952(SB)/8,$0x0000000173d00ae2
+
+	/* x^199744 mod p(x), x^199680 mod p(x) */
+DATA ·CastConst+960(SB)/8,$0x0000000112c3a84c
+DATA ·CastConst+968(SB)/8,$0x00000001d4ffe4ac
+
+	/* x^198720 mod p(x), x^198656 mod p(x) */
+DATA ·CastConst+976(SB)/8,$0x00000000de940fee
+DATA ·CastConst+984(SB)/8,$0x000000016edc5ae4
+
+	/* x^197696 mod p(x), x^197632 mod p(x) */
+DATA ·CastConst+992(SB)/8,$0x00000000fe896b7e
+DATA ·CastConst+1000(SB)/8,$0x00000001f1a02140
+
+	/* x^196672 mod p(x), x^196608 mod p(x) */
+DATA ·CastConst+1008(SB)/8,$0x00000001f797431c
+DATA ·CastConst+1016(SB)/8,$0x00000000ca0b28a0
+
+	/* x^195648 mod p(x), x^195584 mod p(x) */
+DATA ·CastConst+1024(SB)/8,$0x0000000053e989ba
+DATA ·CastConst+1032(SB)/8,$0x00000001928e30a2
+
+	/* x^194624 mod p(x), x^194560 mod p(x) */
+DATA ·CastConst+1040(SB)/8,$0x000000003920cd16
+DATA ·CastConst+1048(SB)/8,$0x0000000097b1b002
+
+	/* x^193600 mod p(x), x^193536 mod p(x) */
+DATA ·CastConst+1056(SB)/8,$0x00000001e6f579b8
+DATA ·CastConst+1064(SB)/8,$0x00000000b15bf906
+
+	/* x^192576 mod p(x), x^192512 mod p(x) */
+DATA ·CastConst+1072(SB)/8,$0x000000007493cb0a
+DATA ·CastConst+1080(SB)/8,$0x00000000411c5d52
+
+	/* x^191552 mod p(x), x^191488 mod p(x) */
+DATA ·CastConst+1088(SB)/8,$0x00000001bdd376d8
+DATA ·CastConst+1096(SB)/8,$0x00000001c36f3300
+
+	/* x^190528 mod p(x), x^190464 mod p(x) */
+DATA ·CastConst+1104(SB)/8,$0x000000016badfee6
+DATA ·CastConst+1112(SB)/8,$0x00000001119227e0
+
+	/* x^189504 mod p(x), x^189440 mod p(x) */
+DATA ·CastConst+1120(SB)/8,$0x0000000071de5c58
+DATA ·CastConst+1128(SB)/8,$0x00000000114d4702
+
+	/* x^188480 mod p(x), x^188416 mod p(x) */
+DATA ·CastConst+1136(SB)/8,$0x00000000453f317c
+DATA ·CastConst+1144(SB)/8,$0x00000000458b5b98
+
+	/* x^187456 mod p(x), x^187392 mod p(x) */
+DATA ·CastConst+1152(SB)/8,$0x0000000121675cce
+DATA ·CastConst+1160(SB)/8,$0x000000012e31fb8e
+
+	/* x^186432 mod p(x), x^186368 mod p(x) */
+DATA ·CastConst+1168(SB)/8,$0x00000001f409ee92
+DATA ·CastConst+1176(SB)/8,$0x000000005cf619d8
+
+	/* x^185408 mod p(x), x^185344 mod p(x) */
+DATA ·CastConst+1184(SB)/8,$0x00000000f36b9c88
+DATA ·CastConst+1192(SB)/8,$0x0000000063f4d8b2
+
+	/* x^184384 mod p(x), x^184320 mod p(x) */
+DATA ·CastConst+1200(SB)/8,$0x0000000036b398f4
+DATA ·CastConst+1208(SB)/8,$0x000000004138dc8a
+
+	/* x^183360 mod p(x), x^183296 mod p(x) */
+DATA ·CastConst+1216(SB)/8,$0x00000001748f9adc
+DATA ·CastConst+1224(SB)/8,$0x00000001d29ee8e0
+
+	/* x^182336 mod p(x), x^182272 mod p(x) */
+DATA ·CastConst+1232(SB)/8,$0x00000001be94ec00
+DATA ·CastConst+1240(SB)/8,$0x000000006a08ace8
+
+	/* x^181312 mod p(x), x^181248 mod p(x) */
+DATA ·CastConst+1248(SB)/8,$0x00000000b74370d6
+DATA ·CastConst+1256(SB)/8,$0x0000000127d42010
+
+	/* x^180288 mod p(x), x^180224 mod p(x) */
+DATA ·CastConst+1264(SB)/8,$0x00000001174d0b98
+DATA ·CastConst+1272(SB)/8,$0x0000000019d76b62
+
+	/* x^179264 mod p(x), x^179200 mod p(x) */
+DATA ·CastConst+1280(SB)/8,$0x00000000befc06a4
+DATA ·CastConst+1288(SB)/8,$0x00000001b1471f6e
+
+	/* x^178240 mod p(x), x^178176 mod p(x) */
+DATA ·CastConst+1296(SB)/8,$0x00000001ae125288
+DATA ·CastConst+1304(SB)/8,$0x00000001f64c19cc
+
+	/* x^177216 mod p(x), x^177152 mod p(x) */
+DATA ·CastConst+1312(SB)/8,$0x0000000095c19b34
+DATA ·CastConst+1320(SB)/8,$0x00000000003c0ea0
+
+	/* x^176192 mod p(x), x^176128 mod p(x) */
+DATA ·CastConst+1328(SB)/8,$0x00000001a78496f2
+DATA ·CastConst+1336(SB)/8,$0x000000014d73abf6
+
+	/* x^175168 mod p(x), x^175104 mod p(x) */
+DATA ·CastConst+1344(SB)/8,$0x00000001ac5390a0
+DATA ·CastConst+1352(SB)/8,$0x00000001620eb844
+
+	/* x^174144 mod p(x), x^174080 mod p(x) */
+DATA ·CastConst+1360(SB)/8,$0x000000002a80ed6e
+DATA ·CastConst+1368(SB)/8,$0x0000000147655048
+
+	/* x^173120 mod p(x), x^173056 mod p(x) */
+DATA ·CastConst+1376(SB)/8,$0x00000001fa9b0128
+DATA ·CastConst+1384(SB)/8,$0x0000000067b5077e
+
+	/* x^172096 mod p(x), x^172032 mod p(x) */
+DATA ·CastConst+1392(SB)/8,$0x00000001ea94929e
+DATA ·CastConst+1400(SB)/8,$0x0000000010ffe206
+
+	/* x^171072 mod p(x), x^171008 mod p(x) */
+DATA ·CastConst+1408(SB)/8,$0x0000000125f4305c
+DATA ·CastConst+1416(SB)/8,$0x000000000fee8f1e
+
+	/* x^170048 mod p(x), x^169984 mod p(x) */
+DATA ·CastConst+1424(SB)/8,$0x00000001471e2002
+DATA ·CastConst+1432(SB)/8,$0x00000001da26fbae
+
+	/* x^169024 mod p(x), x^168960 mod p(x) */
+DATA ·CastConst+1440(SB)/8,$0x0000000132d2253a
+DATA ·CastConst+1448(SB)/8,$0x00000001b3a8bd88
+
+	/* x^168000 mod p(x), x^167936 mod p(x) */
+DATA ·CastConst+1456(SB)/8,$0x00000000f26b3592
+DATA ·CastConst+1464(SB)/8,$0x00000000e8f3898e
+
+	/* x^166976 mod p(x), x^166912 mod p(x) */
+DATA ·CastConst+1472(SB)/8,$0x00000000bc8b67b0
+DATA ·CastConst+1480(SB)/8,$0x00000000b0d0d28c
+
+	/* x^165952 mod p(x), x^165888 mod p(x) */
+DATA ·CastConst+1488(SB)/8,$0x000000013a826ef2
+DATA ·CastConst+1496(SB)/8,$0x0000000030f2a798
+
+	/* x^164928 mod p(x), x^164864 mod p(x) */
+DATA ·CastConst+1504(SB)/8,$0x0000000081482c84
+DATA ·CastConst+1512(SB)/8,$0x000000000fba1002
+
+	/* x^163904 mod p(x), x^163840 mod p(x) */
+DATA ·CastConst+1520(SB)/8,$0x00000000e77307c2
+DATA ·CastConst+1528(SB)/8,$0x00000000bdb9bd72
+
+	/* x^162880 mod p(x), x^162816 mod p(x) */
+DATA ·CastConst+1536(SB)/8,$0x00000000d4a07ec8
+DATA ·CastConst+1544(SB)/8,$0x0000000075d3bf5a
+
+	/* x^161856 mod p(x), x^161792 mod p(x) */
+DATA ·CastConst+1552(SB)/8,$0x0000000017102100
+DATA ·CastConst+1560(SB)/8,$0x00000000ef1f98a0
+
+	/* x^160832 mod p(x), x^160768 mod p(x) */
+DATA ·CastConst+1568(SB)/8,$0x00000000db406486
+DATA ·CastConst+1576(SB)/8,$0x00000000689c7602
+
+	/* x^159808 mod p(x), x^159744 mod p(x) */
+DATA ·CastConst+1584(SB)/8,$0x0000000192db7f88
+DATA ·CastConst+1592(SB)/8,$0x000000016d5fa5fe
+
+	/* x^158784 mod p(x), x^158720 mod p(x) */
+DATA ·CastConst+1600(SB)/8,$0x000000018bf67b1e
+DATA ·CastConst+1608(SB)/8,$0x00000001d0d2b9ca
+
+	/* x^157760 mod p(x), x^157696 mod p(x) */
+DATA ·CastConst+1616(SB)/8,$0x000000007c09163e
+DATA ·CastConst+1624(SB)/8,$0x0000000041e7b470
+
+	/* x^156736 mod p(x), x^156672 mod p(x) */
+DATA ·CastConst+1632(SB)/8,$0x000000000adac060
+DATA ·CastConst+1640(SB)/8,$0x00000001cbb6495e
+
+	/* x^155712 mod p(x), x^155648 mod p(x) */
+DATA ·CastConst+1648(SB)/8,$0x00000000bd8316ae
+DATA ·CastConst+1656(SB)/8,$0x000000010052a0b0
+
+	/* x^154688 mod p(x), x^154624 mod p(x) */
+DATA ·CastConst+1664(SB)/8,$0x000000019f09ab54
+DATA ·CastConst+1672(SB)/8,$0x00000001d8effb5c
+
+	/* x^153664 mod p(x), x^153600 mod p(x) */
+DATA ·CastConst+1680(SB)/8,$0x0000000125155542
+DATA ·CastConst+1688(SB)/8,$0x00000001d969853c
+
+	/* x^152640 mod p(x), x^152576 mod p(x) */
+DATA ·CastConst+1696(SB)/8,$0x000000018fdb5882
+DATA ·CastConst+1704(SB)/8,$0x00000000523ccce2
+
+	/* x^151616 mod p(x), x^151552 mod p(x) */
+DATA ·CastConst+1712(SB)/8,$0x00000000e794b3f4
+DATA ·CastConst+1720(SB)/8,$0x000000001e2436bc
+
+	/* x^150592 mod p(x), x^150528 mod p(x) */
+DATA ·CastConst+1728(SB)/8,$0x000000016f9bb022
+DATA ·CastConst+1736(SB)/8,$0x00000000ddd1c3a2
+
+	/* x^149568 mod p(x), x^149504 mod p(x) */
+DATA ·CastConst+1744(SB)/8,$0x00000000290c9978
+DATA ·CastConst+1752(SB)/8,$0x0000000019fcfe38
+
+	/* x^148544 mod p(x), x^148480 mod p(x) */
+DATA ·CastConst+1760(SB)/8,$0x0000000083c0f350
+DATA ·CastConst+1768(SB)/8,$0x00000001ce95db64
+
+	/* x^147520 mod p(x), x^147456 mod p(x) */
+DATA ·CastConst+1776(SB)/8,$0x0000000173ea6628
+DATA ·CastConst+1784(SB)/8,$0x00000000af582806
+
+	/* x^146496 mod p(x), x^146432 mod p(x) */
+DATA ·CastConst+1792(SB)/8,$0x00000001c8b4e00a
+DATA ·CastConst+1800(SB)/8,$0x00000001006388f6
+
+	/* x^145472 mod p(x), x^145408 mod p(x) */
+DATA ·CastConst+1808(SB)/8,$0x00000000de95d6aa
+DATA ·CastConst+1816(SB)/8,$0x0000000179eca00a
+
+	/* x^144448 mod p(x), x^144384 mod p(x) */
+DATA ·CastConst+1824(SB)/8,$0x000000010b7f7248
+DATA ·CastConst+1832(SB)/8,$0x0000000122410a6a
+
+	/* x^143424 mod p(x), x^143360 mod p(x) */
+DATA ·CastConst+1840(SB)/8,$0x00000001326e3a06
+DATA ·CastConst+1848(SB)/8,$0x000000004288e87c
+
+	/* x^142400 mod p(x), x^142336 mod p(x) */
+DATA ·CastConst+1856(SB)/8,$0x00000000bb62c2e6
+DATA ·CastConst+1864(SB)/8,$0x000000016c5490da
+
+	/* x^141376 mod p(x), x^141312 mod p(x) */
+DATA ·CastConst+1872(SB)/8,$0x0000000156a4b2c2
+DATA ·CastConst+1880(SB)/8,$0x00000000d1c71f6e
+
+	/* x^140352 mod p(x), x^140288 mod p(x) */
+DATA ·CastConst+1888(SB)/8,$0x000000011dfe763a
+DATA ·CastConst+1896(SB)/8,$0x00000001b4ce08a6
+
+	/* x^139328 mod p(x), x^139264 mod p(x) */
+DATA ·CastConst+1904(SB)/8,$0x000000007bcca8e2
+DATA ·CastConst+1912(SB)/8,$0x00000001466ba60c
+
+	/* x^138304 mod p(x), x^138240 mod p(x) */
+DATA ·CastConst+1920(SB)/8,$0x0000000186118faa
+DATA ·CastConst+1928(SB)/8,$0x00000001f6c488a4
+
+	/* x^137280 mod p(x), x^137216 mod p(x) */
+DATA ·CastConst+1936(SB)/8,$0x0000000111a65a88
+DATA ·CastConst+1944(SB)/8,$0x000000013bfb0682
+
+	/* x^136256 mod p(x), x^136192 mod p(x) */
+DATA ·CastConst+1952(SB)/8,$0x000000003565e1c4
+DATA ·CastConst+1960(SB)/8,$0x00000000690e9e54
+
+	/* x^135232 mod p(x), x^135168 mod p(x) */
+DATA ·CastConst+1968(SB)/8,$0x000000012ed02a82
+DATA ·CastConst+1976(SB)/8,$0x00000000281346b6
+
+	/* x^134208 mod p(x), x^134144 mod p(x) */
+DATA ·CastConst+1984(SB)/8,$0x00000000c486ecfc
+DATA ·CastConst+1992(SB)/8,$0x0000000156464024
+
+	/* x^133184 mod p(x), x^133120 mod p(x) */
+DATA ·CastConst+2000(SB)/8,$0x0000000001b951b2
+DATA ·CastConst+2008(SB)/8,$0x000000016063a8dc
+
+	/* x^132160 mod p(x), x^132096 mod p(x) */
+DATA ·CastConst+2016(SB)/8,$0x0000000048143916
+DATA ·CastConst+2024(SB)/8,$0x0000000116a66362
+
+	/* x^131136 mod p(x), x^131072 mod p(x) */
+DATA ·CastConst+2032(SB)/8,$0x00000001dc2ae124
+DATA ·CastConst+2040(SB)/8,$0x000000017e8aa4d2
+
+	/* x^130112 mod p(x), x^130048 mod p(x) */
+DATA ·CastConst+2048(SB)/8,$0x00000001416c58d6
+DATA ·CastConst+2056(SB)/8,$0x00000001728eb10c
+
+	/* x^129088 mod p(x), x^129024 mod p(x) */
+DATA ·CastConst+2064(SB)/8,$0x00000000a479744a
+DATA ·CastConst+2072(SB)/8,$0x00000001b08fd7fa
+
+	/* x^128064 mod p(x), x^128000 mod p(x) */
+DATA ·CastConst+2080(SB)/8,$0x0000000096ca3a26
+DATA ·CastConst+2088(SB)/8,$0x00000001092a16e8
+
+	/* x^127040 mod p(x), x^126976 mod p(x) */
+DATA ·CastConst+2096(SB)/8,$0x00000000ff223d4e
+DATA ·CastConst+2104(SB)/8,$0x00000000a505637c
+
+	/* x^126016 mod p(x), x^125952 mod p(x) */
+DATA ·CastConst+2112(SB)/8,$0x000000010e84da42
+DATA ·CastConst+2120(SB)/8,$0x00000000d94869b2
+
+	/* x^124992 mod p(x), x^124928 mod p(x) */
+DATA ·CastConst+2128(SB)/8,$0x00000001b61ba3d0
+DATA ·CastConst+2136(SB)/8,$0x00000001c8b203ae
+
+	/* x^123968 mod p(x), x^123904 mod p(x) */
+DATA ·CastConst+2144(SB)/8,$0x00000000680f2de8
+DATA ·CastConst+2152(SB)/8,$0x000000005704aea0
+
+	/* x^122944 mod p(x), x^122880 mod p(x) */
+DATA ·CastConst+2160(SB)/8,$0x000000008772a9a8
+DATA ·CastConst+2168(SB)/8,$0x000000012e295fa2
+
+	/* x^121920 mod p(x), x^121856 mod p(x) */
+DATA ·CastConst+2176(SB)/8,$0x0000000155f295bc
+DATA ·CastConst+2184(SB)/8,$0x000000011d0908bc
+
+	/* x^120896 mod p(x), x^120832 mod p(x) */
+DATA ·CastConst+2192(SB)/8,$0x00000000595f9282
+DATA ·CastConst+2200(SB)/8,$0x0000000193ed97ea
+
+	/* x^119872 mod p(x), x^119808 mod p(x) */
+DATA ·CastConst+2208(SB)/8,$0x0000000164b1c25a
+DATA ·CastConst+2216(SB)/8,$0x000000013a0f1c52
+
+	/* x^118848 mod p(x), x^118784 mod p(x) */
+DATA ·CastConst+2224(SB)/8,$0x00000000fbd67c50
+DATA ·CastConst+2232(SB)/8,$0x000000010c2c40c0
+
+	/* x^117824 mod p(x), x^117760 mod p(x) */
+DATA ·CastConst+2240(SB)/8,$0x0000000096076268
+DATA ·CastConst+2248(SB)/8,$0x00000000ff6fac3e
+
+	/* x^116800 mod p(x), x^116736 mod p(x) */
+DATA ·CastConst+2256(SB)/8,$0x00000001d288e4cc
+DATA ·CastConst+2264(SB)/8,$0x000000017b3609c0
+
+	/* x^115776 mod p(x), x^115712 mod p(x) */
+DATA ·CastConst+2272(SB)/8,$0x00000001eaac1bdc
+DATA ·CastConst+2280(SB)/8,$0x0000000088c8c922
+
+	/* x^114752 mod p(x), x^114688 mod p(x) */
+DATA ·CastConst+2288(SB)/8,$0x00000001f1ea39e2
+DATA ·CastConst+2296(SB)/8,$0x00000001751baae6
+
+	/* x^113728 mod p(x), x^113664 mod p(x) */
+DATA ·CastConst+2304(SB)/8,$0x00000001eb6506fc
+DATA ·CastConst+2312(SB)/8,$0x0000000107952972
+
+	/* x^112704 mod p(x), x^112640 mod p(x) */
+DATA ·CastConst+2320(SB)/8,$0x000000010f806ffe
+DATA ·CastConst+2328(SB)/8,$0x0000000162b00abe
+
+	/* x^111680 mod p(x), x^111616 mod p(x) */
+DATA ·CastConst+2336(SB)/8,$0x000000010408481e
+DATA ·CastConst+2344(SB)/8,$0x000000000d7b404c
+
+	/* x^110656 mod p(x), x^110592 mod p(x) */
+DATA ·CastConst+2352(SB)/8,$0x0000000188260534
+DATA ·CastConst+2360(SB)/8,$0x00000000763b13d4
+
+	/* x^109632 mod p(x), x^109568 mod p(x) */
+DATA ·CastConst+2368(SB)/8,$0x0000000058fc73e0
+DATA ·CastConst+2376(SB)/8,$0x00000000f6dc22d8
+
+	/* x^108608 mod p(x), x^108544 mod p(x) */
+DATA ·CastConst+2384(SB)/8,$0x00000000391c59b8
+DATA ·CastConst+2392(SB)/8,$0x000000007daae060
+
+	/* x^107584 mod p(x), x^107520 mod p(x) */
+DATA ·CastConst+2400(SB)/8,$0x000000018b638400
+DATA ·CastConst+2408(SB)/8,$0x000000013359ab7c
+
+	/* x^106560 mod p(x), x^106496 mod p(x) */
+DATA ·CastConst+2416(SB)/8,$0x000000011738f5c4
+DATA ·CastConst+2424(SB)/8,$0x000000008add438a
+
+	/* x^105536 mod p(x), x^105472 mod p(x) */
+DATA ·CastConst+2432(SB)/8,$0x000000008cf7c6da
+DATA ·CastConst+2440(SB)/8,$0x00000001edbefdea
+
+	/* x^104512 mod p(x), x^104448 mod p(x) */
+DATA ·CastConst+2448(SB)/8,$0x00000001ef97fb16
+DATA ·CastConst+2456(SB)/8,$0x000000004104e0f8
+
+	/* x^103488 mod p(x), x^103424 mod p(x) */
+DATA ·CastConst+2464(SB)/8,$0x0000000102130e20
+DATA ·CastConst+2472(SB)/8,$0x00000000b48a8222
+
+	/* x^102464 mod p(x), x^102400 mod p(x) */
+DATA ·CastConst+2480(SB)/8,$0x00000000db968898
+DATA ·CastConst+2488(SB)/8,$0x00000001bcb46844
+
+	/* x^101440 mod p(x), x^101376 mod p(x) */
+DATA ·CastConst+2496(SB)/8,$0x00000000b5047b5e
+DATA ·CastConst+2504(SB)/8,$0x000000013293ce0a
+
+	/* x^100416 mod p(x), x^100352 mod p(x) */
+DATA ·CastConst+2512(SB)/8,$0x000000010b90fdb2
+DATA ·CastConst+2520(SB)/8,$0x00000001710d0844
+
+	/* x^99392 mod p(x), x^99328 mod p(x) */
+DATA ·CastConst+2528(SB)/8,$0x000000004834a32e
+DATA ·CastConst+2536(SB)/8,$0x0000000117907f6e
+
+	/* x^98368 mod p(x), x^98304 mod p(x) */
+DATA ·CastConst+2544(SB)/8,$0x0000000059c8f2b0
+DATA ·CastConst+2552(SB)/8,$0x0000000087ddf93e
+
+	/* x^97344 mod p(x), x^97280 mod p(x) */
+DATA ·CastConst+2560(SB)/8,$0x0000000122cec508
+DATA ·CastConst+2568(SB)/8,$0x000000005970e9b0
+
+	/* x^96320 mod p(x), x^96256 mod p(x) */
+DATA ·CastConst+2576(SB)/8,$0x000000000a330cda
+DATA ·CastConst+2584(SB)/8,$0x0000000185b2b7d0
+
+	/* x^95296 mod p(x), x^95232 mod p(x) */
+DATA ·CastConst+2592(SB)/8,$0x000000014a47148c
+DATA ·CastConst+2600(SB)/8,$0x00000001dcee0efc
+
+	/* x^94272 mod p(x), x^94208 mod p(x) */
+DATA ·CastConst+2608(SB)/8,$0x0000000042c61cb8
+DATA ·CastConst+2616(SB)/8,$0x0000000030da2722
+
+	/* x^93248 mod p(x), x^93184 mod p(x) */
+DATA ·CastConst+2624(SB)/8,$0x0000000012fe6960
+DATA ·CastConst+2632(SB)/8,$0x000000012f925a18
+
+	/* x^92224 mod p(x), x^92160 mod p(x) */
+DATA ·CastConst+2640(SB)/8,$0x00000000dbda2c20
+DATA ·CastConst+2648(SB)/8,$0x00000000dd2e357c
+
+	/* x^91200 mod p(x), x^91136 mod p(x) */
+DATA ·CastConst+2656(SB)/8,$0x000000011122410c
+DATA ·CastConst+2664(SB)/8,$0x00000000071c80de
+
+	/* x^90176 mod p(x), x^90112 mod p(x) */
+DATA ·CastConst+2672(SB)/8,$0x00000000977b2070
+DATA ·CastConst+2680(SB)/8,$0x000000011513140a
+
+	/* x^89152 mod p(x), x^89088 mod p(x) */
+DATA ·CastConst+2688(SB)/8,$0x000000014050438e
+DATA ·CastConst+2696(SB)/8,$0x00000001df876e8e
+
+	/* x^88128 mod p(x), x^88064 mod p(x) */
+DATA ·CastConst+2704(SB)/8,$0x0000000147c840e8
+DATA ·CastConst+2712(SB)/8,$0x000000015f81d6ce
+
+	/* x^87104 mod p(x), x^87040 mod p(x) */
+DATA ·CastConst+2720(SB)/8,$0x00000001cc7c88ce
+DATA ·CastConst+2728(SB)/8,$0x000000019dd94dbe
+
+	/* x^86080 mod p(x), x^86016 mod p(x) */
+DATA ·CastConst+2736(SB)/8,$0x00000001476b35a4
+DATA ·CastConst+2744(SB)/8,$0x00000001373d206e
+
+	/* x^85056 mod p(x), x^84992 mod p(x) */
+DATA ·CastConst+2752(SB)/8,$0x000000013d52d508
+DATA ·CastConst+2760(SB)/8,$0x00000000668ccade
+
+	/* x^84032 mod p(x), x^83968 mod p(x) */
+DATA ·CastConst+2768(SB)/8,$0x000000008e4be32e
+DATA ·CastConst+2776(SB)/8,$0x00000001b192d268
+
+	/* x^83008 mod p(x), x^82944 mod p(x) */
+DATA ·CastConst+2784(SB)/8,$0x00000000024120fe
+DATA ·CastConst+2792(SB)/8,$0x00000000e30f3a78
+
+	/* x^81984 mod p(x), x^81920 mod p(x) */
+DATA ·CastConst+2800(SB)/8,$0x00000000ddecddb4
+DATA ·CastConst+2808(SB)/8,$0x000000010ef1f7bc
+
+	/* x^80960 mod p(x), x^80896 mod p(x) */
+DATA ·CastConst+2816(SB)/8,$0x00000000d4d403bc
+DATA ·CastConst+2824(SB)/8,$0x00000001f5ac7380
+
+	/* x^79936 mod p(x), x^79872 mod p(x) */
+DATA ·CastConst+2832(SB)/8,$0x00000001734b89aa
+DATA ·CastConst+2840(SB)/8,$0x000000011822ea70
+
+	/* x^78912 mod p(x), x^78848 mod p(x) */
+DATA ·CastConst+2848(SB)/8,$0x000000010e7a58d6
+DATA ·CastConst+2856(SB)/8,$0x00000000c3a33848
+
+	/* x^77888 mod p(x), x^77824 mod p(x) */
+DATA ·CastConst+2864(SB)/8,$0x00000001f9f04e9c
+DATA ·CastConst+2872(SB)/8,$0x00000001bd151c24
+
+	/* x^76864 mod p(x), x^76800 mod p(x) */
+DATA ·CastConst+2880(SB)/8,$0x00000000b692225e
+DATA ·CastConst+2888(SB)/8,$0x0000000056002d76
+
+	/* x^75840 mod p(x), x^75776 mod p(x) */
+DATA ·CastConst+2896(SB)/8,$0x000000019b8d3f3e
+DATA ·CastConst+2904(SB)/8,$0x000000014657c4f4
+
+	/* x^74816 mod p(x), x^74752 mod p(x) */
+DATA ·CastConst+2912(SB)/8,$0x00000001a874f11e
+DATA ·CastConst+2920(SB)/8,$0x0000000113742d7c
+
+	/* x^73792 mod p(x), x^73728 mod p(x) */
+DATA ·CastConst+2928(SB)/8,$0x000000010d5a4254
+DATA ·CastConst+2936(SB)/8,$0x000000019c5920ba
+
+	/* x^72768 mod p(x), x^72704 mod p(x) */
+DATA ·CastConst+2944(SB)/8,$0x00000000bbb2f5d6
+DATA ·CastConst+2952(SB)/8,$0x000000005216d2d6
+
+	/* x^71744 mod p(x), x^71680 mod p(x) */
+DATA ·CastConst+2960(SB)/8,$0x0000000179cc0e36
+DATA ·CastConst+2968(SB)/8,$0x0000000136f5ad8a
+
+	/* x^70720 mod p(x), x^70656 mod p(x) */
+DATA ·CastConst+2976(SB)/8,$0x00000001dca1da4a
+DATA ·CastConst+2984(SB)/8,$0x000000018b07beb6
+
+	/* x^69696 mod p(x), x^69632 mod p(x) */
+DATA ·CastConst+2992(SB)/8,$0x00000000feb1a192
+DATA ·CastConst+3000(SB)/8,$0x00000000db1e93b0
+
+	/* x^68672 mod p(x), x^68608 mod p(x) */
+DATA ·CastConst+3008(SB)/8,$0x00000000d1eeedd6
+DATA ·CastConst+3016(SB)/8,$0x000000000b96fa3a
+
+	/* x^67648 mod p(x), x^67584 mod p(x) */
+DATA ·CastConst+3024(SB)/8,$0x000000008fad9bb4
+DATA ·CastConst+3032(SB)/8,$0x00000001d9968af0
+
+	/* x^66624 mod p(x), x^66560 mod p(x) */
+DATA ·CastConst+3040(SB)/8,$0x00000001884938e4
+DATA ·CastConst+3048(SB)/8,$0x000000000e4a77a2
+
+	/* x^65600 mod p(x), x^65536 mod p(x) */
+DATA ·CastConst+3056(SB)/8,$0x00000001bc2e9bc0
+DATA ·CastConst+3064(SB)/8,$0x00000000508c2ac8
+
+	/* x^64576 mod p(x), x^64512 mod p(x) */
+DATA ·CastConst+3072(SB)/8,$0x00000001f9658a68
+DATA ·CastConst+3080(SB)/8,$0x0000000021572a80
+
+	/* x^63552 mod p(x), x^63488 mod p(x) */
+DATA ·CastConst+3088(SB)/8,$0x000000001b9224fc
+DATA ·CastConst+3096(SB)/8,$0x00000001b859daf2
+
+	/* x^62528 mod p(x), x^62464 mod p(x) */
+DATA ·CastConst+3104(SB)/8,$0x0000000055b2fb84
+DATA ·CastConst+3112(SB)/8,$0x000000016f788474
+
+	/* x^61504 mod p(x), x^61440 mod p(x) */
+DATA ·CastConst+3120(SB)/8,$0x000000018b090348
+DATA ·CastConst+3128(SB)/8,$0x00000001b438810e
+
+	/* x^60480 mod p(x), x^60416 mod p(x) */
+DATA ·CastConst+3136(SB)/8,$0x000000011ccbd5ea
+DATA ·CastConst+3144(SB)/8,$0x0000000095ddc6f2
+
+	/* x^59456 mod p(x), x^59392 mod p(x) */
+DATA ·CastConst+3152(SB)/8,$0x0000000007ae47f8
+DATA ·CastConst+3160(SB)/8,$0x00000001d977c20c
+
+	/* x^58432 mod p(x), x^58368 mod p(x) */
+DATA ·CastConst+3168(SB)/8,$0x0000000172acbec0
+DATA ·CastConst+3176(SB)/8,$0x00000000ebedb99a
+
+	/* x^57408 mod p(x), x^57344 mod p(x) */
+DATA ·CastConst+3184(SB)/8,$0x00000001c6e3ff20
+DATA ·CastConst+3192(SB)/8,$0x00000001df9e9e92
+
+	/* x^56384 mod p(x), x^56320 mod p(x) */
+DATA ·CastConst+3200(SB)/8,$0x00000000e1b38744
+DATA ·CastConst+3208(SB)/8,$0x00000001a4a3f952
+
+	/* x^55360 mod p(x), x^55296 mod p(x) */
+DATA ·CastConst+3216(SB)/8,$0x00000000791585b2
+DATA ·CastConst+3224(SB)/8,$0x00000000e2f51220
+
+	/* x^54336 mod p(x), x^54272 mod p(x) */
+DATA ·CastConst+3232(SB)/8,$0x00000000ac53b894
+DATA ·CastConst+3240(SB)/8,$0x000000004aa01f3e
+
+	/* x^53312 mod p(x), x^53248 mod p(x) */
+DATA ·CastConst+3248(SB)/8,$0x00000001ed5f2cf4
+DATA ·CastConst+3256(SB)/8,$0x00000000b3e90a58
+
+	/* x^52288 mod p(x), x^52224 mod p(x) */
+DATA ·CastConst+3264(SB)/8,$0x00000001df48b2e0
+DATA ·CastConst+3272(SB)/8,$0x000000000c9ca2aa
+
+	/* x^51264 mod p(x), x^51200 mod p(x) */
+DATA ·CastConst+3280(SB)/8,$0x00000000049c1c62
+DATA ·CastConst+3288(SB)/8,$0x0000000151682316
+
+	/* x^50240 mod p(x), x^50176 mod p(x) */
+DATA ·CastConst+3296(SB)/8,$0x000000017c460c12
+DATA ·CastConst+3304(SB)/8,$0x0000000036fce78c
+
+	/* x^49216 mod p(x), x^49152 mod p(x) */
+DATA ·CastConst+3312(SB)/8,$0x000000015be4da7e
+DATA ·CastConst+3320(SB)/8,$0x000000009037dc10
+
+	/* x^48192 mod p(x), x^48128 mod p(x) */
+DATA ·CastConst+3328(SB)/8,$0x000000010f38f668
+DATA ·CastConst+3336(SB)/8,$0x00000000d3298582
+
+	/* x^47168 mod p(x), x^47104 mod p(x) */
+DATA ·CastConst+3344(SB)/8,$0x0000000039f40a00
+DATA ·CastConst+3352(SB)/8,$0x00000001b42e8ad6
+
+	/* x^46144 mod p(x), x^46080 mod p(x) */
+DATA ·CastConst+3360(SB)/8,$0x00000000bd4c10c4
+DATA ·CastConst+3368(SB)/8,$0x00000000142a9838
+
+	/* x^45120 mod p(x), x^45056 mod p(x) */
+DATA ·CastConst+3376(SB)/8,$0x0000000042db1d98
+DATA ·CastConst+3384(SB)/8,$0x0000000109c7f190
+
+	/* x^44096 mod p(x), x^44032 mod p(x) */
+DATA ·CastConst+3392(SB)/8,$0x00000001c905bae6
+DATA ·CastConst+3400(SB)/8,$0x0000000056ff9310
+
+	/* x^43072 mod p(x), x^43008 mod p(x) */
+DATA ·CastConst+3408(SB)/8,$0x00000000069d40ea
+DATA ·CastConst+3416(SB)/8,$0x00000001594513aa
+
+	/* x^42048 mod p(x), x^41984 mod p(x) */
+DATA ·CastConst+3424(SB)/8,$0x000000008e4fbad0
+DATA ·CastConst+3432(SB)/8,$0x00000001e3b5b1e8
+
+	/* x^41024 mod p(x), x^40960 mod p(x) */
+DATA ·CastConst+3440(SB)/8,$0x0000000047bedd46
+DATA ·CastConst+3448(SB)/8,$0x000000011dd5fc08
+
+	/* x^40000 mod p(x), x^39936 mod p(x) */
+DATA ·CastConst+3456(SB)/8,$0x0000000026396bf8
+DATA ·CastConst+3464(SB)/8,$0x00000001675f0cc2
+
+	/* x^38976 mod p(x), x^38912 mod p(x) */
+DATA ·CastConst+3472(SB)/8,$0x00000000379beb92
+DATA ·CastConst+3480(SB)/8,$0x00000000d1c8dd44
+
+	/* x^37952 mod p(x), x^37888 mod p(x) */
+DATA ·CastConst+3488(SB)/8,$0x000000000abae54a
+DATA ·CastConst+3496(SB)/8,$0x0000000115ebd3d8
+
+	/* x^36928 mod p(x), x^36864 mod p(x) */
+DATA ·CastConst+3504(SB)/8,$0x0000000007e6a128
+DATA ·CastConst+3512(SB)/8,$0x00000001ecbd0dac
+
+	/* x^35904 mod p(x), x^35840 mod p(x) */
+DATA ·CastConst+3520(SB)/8,$0x000000000ade29d2
+DATA ·CastConst+3528(SB)/8,$0x00000000cdf67af2
+
+	/* x^34880 mod p(x), x^34816 mod p(x) */
+DATA ·CastConst+3536(SB)/8,$0x00000000f974c45c
+DATA ·CastConst+3544(SB)/8,$0x000000004c01ff4c
+
+	/* x^33856 mod p(x), x^33792 mod p(x) */
+DATA ·CastConst+3552(SB)/8,$0x00000000e77ac60a
+DATA ·CastConst+3560(SB)/8,$0x00000000f2d8657e
+
+	/* x^32832 mod p(x), x^32768 mod p(x) */
+DATA ·CastConst+3568(SB)/8,$0x0000000145895816
+DATA ·CastConst+3576(SB)/8,$0x000000006bae74c4
+
+	/* x^31808 mod p(x), x^31744 mod p(x) */
+DATA ·CastConst+3584(SB)/8,$0x0000000038e362be
+DATA ·CastConst+3592(SB)/8,$0x0000000152af8aa0
+
+	/* x^30784 mod p(x), x^30720 mod p(x) */
+DATA ·CastConst+3600(SB)/8,$0x000000007f991a64
+DATA ·CastConst+3608(SB)/8,$0x0000000004663802
+
+	/* x^29760 mod p(x), x^29696 mod p(x) */
+DATA ·CastConst+3616(SB)/8,$0x00000000fa366d3a
+DATA ·CastConst+3624(SB)/8,$0x00000001ab2f5afc
+
+	/* x^28736 mod p(x), x^28672 mod p(x) */
+DATA ·CastConst+3632(SB)/8,$0x00000001a2bb34f0
+DATA ·CastConst+3640(SB)/8,$0x0000000074a4ebd4
+
+	/* x^27712 mod p(x), x^27648 mod p(x) */
+DATA ·CastConst+3648(SB)/8,$0x0000000028a9981e
+DATA ·CastConst+3656(SB)/8,$0x00000001d7ab3a4c
+
+	/* x^26688 mod p(x), x^26624 mod p(x) */
+DATA ·CastConst+3664(SB)/8,$0x00000001dbc672be
+DATA ·CastConst+3672(SB)/8,$0x00000001a8da60c6
+
+	/* x^25664 mod p(x), x^25600 mod p(x) */
+DATA ·CastConst+3680(SB)/8,$0x00000000b04d77f6
+DATA ·CastConst+3688(SB)/8,$0x000000013cf63820
+
+	/* x^24640 mod p(x), x^24576 mod p(x) */
+DATA ·CastConst+3696(SB)/8,$0x0000000124400d96
+DATA ·CastConst+3704(SB)/8,$0x00000000bec12e1e
+
+	/* x^23616 mod p(x), x^23552 mod p(x) */
+DATA ·CastConst+3712(SB)/8,$0x000000014ca4b414
+DATA ·CastConst+3720(SB)/8,$0x00000001c6368010
+
+	/* x^22592 mod p(x), x^22528 mod p(x) */
+DATA ·CastConst+3728(SB)/8,$0x000000012fe2c938
+DATA ·CastConst+3736(SB)/8,$0x00000001e6e78758
+
+	/* x^21568 mod p(x), x^21504 mod p(x) */
+DATA ·CastConst+3744(SB)/8,$0x00000001faed01e6
+DATA ·CastConst+3752(SB)/8,$0x000000008d7f2b3c
+
+	/* x^20544 mod p(x), x^20480 mod p(x) */
+DATA ·CastConst+3760(SB)/8,$0x000000007e80ecfe
+DATA ·CastConst+3768(SB)/8,$0x000000016b4a156e
+
+	/* x^19520 mod p(x), x^19456 mod p(x) */
+DATA ·CastConst+3776(SB)/8,$0x0000000098daee94
+DATA ·CastConst+3784(SB)/8,$0x00000001c63cfeb6
+
+	/* x^18496 mod p(x), x^18432 mod p(x) */
+DATA ·CastConst+3792(SB)/8,$0x000000010a04edea
+DATA ·CastConst+3800(SB)/8,$0x000000015f902670
+
+	/* x^17472 mod p(x), x^17408 mod p(x) */
+DATA ·CastConst+3808(SB)/8,$0x00000001c00b4524
+DATA ·CastConst+3816(SB)/8,$0x00000001cd5de11e
+
+	/* x^16448 mod p(x), x^16384 mod p(x) */
+DATA ·CastConst+3824(SB)/8,$0x0000000170296550
+DATA ·CastConst+3832(SB)/8,$0x000000001acaec54
+
+	/* x^15424 mod p(x), x^15360 mod p(x) */
+DATA ·CastConst+3840(SB)/8,$0x0000000181afaa48
+DATA ·CastConst+3848(SB)/8,$0x000000002bd0ca78
+
+	/* x^14400 mod p(x), x^14336 mod p(x) */
+DATA ·CastConst+3856(SB)/8,$0x0000000185a31ffa
+DATA ·CastConst+3864(SB)/8,$0x0000000032d63d5c
+
+	/* x^13376 mod p(x), x^13312 mod p(x) */
+DATA ·CastConst+3872(SB)/8,$0x000000002469f608
+DATA ·CastConst+3880(SB)/8,$0x000000001c6d4e4c
+
+	/* x^12352 mod p(x), x^12288 mod p(x) */
+DATA ·CastConst+3888(SB)/8,$0x000000006980102a
+DATA ·CastConst+3896(SB)/8,$0x0000000106a60b92
+
+	/* x^11328 mod p(x), x^11264 mod p(x) */
+DATA ·CastConst+3904(SB)/8,$0x0000000111ea9ca8
+DATA ·CastConst+3912(SB)/8,$0x00000000d3855e12
+
+	/* x^10304 mod p(x), x^10240 mod p(x) */
+DATA ·CastConst+3920(SB)/8,$0x00000001bd1d29ce
+DATA ·CastConst+3928(SB)/8,$0x00000000e3125636
+
+	/* x^9280 mod p(x), x^9216 mod p(x) */
+DATA ·CastConst+3936(SB)/8,$0x00000001b34b9580
+DATA ·CastConst+3944(SB)/8,$0x000000009e8f7ea4
+
+	/* x^8256 mod p(x), x^8192 mod p(x) */
+DATA ·CastConst+3952(SB)/8,$0x000000003076054e
+DATA ·CastConst+3960(SB)/8,$0x00000001c82e562c
+
+	/* x^7232 mod p(x), x^7168 mod p(x) */
+DATA ·CastConst+3968(SB)/8,$0x000000012a608ea4
+DATA ·CastConst+3976(SB)/8,$0x00000000ca9f09ce
+
+	/* x^6208 mod p(x), x^6144 mod p(x) */
+DATA ·CastConst+3984(SB)/8,$0x00000000784d05fe
+DATA ·CastConst+3992(SB)/8,$0x00000000c63764e6
+
+	/* x^5184 mod p(x), x^5120 mod p(x) */
+DATA ·CastConst+4000(SB)/8,$0x000000016ef0d82a
+DATA ·CastConst+4008(SB)/8,$0x0000000168d2e49e
+
+	/* x^4160 mod p(x), x^4096 mod p(x) */
+DATA ·CastConst+4016(SB)/8,$0x0000000075bda454
+DATA ·CastConst+4024(SB)/8,$0x00000000e986c148
+
+	/* x^3136 mod p(x), x^3072 mod p(x) */
+DATA ·CastConst+4032(SB)/8,$0x000000003dc0a1c4
+DATA ·CastConst+4040(SB)/8,$0x00000000cfb65894
+
+	/* x^2112 mod p(x), x^2048 mod p(x) */
+DATA ·CastConst+4048(SB)/8,$0x00000000e9a5d8be
+DATA ·CastConst+4056(SB)/8,$0x0000000111cadee4
+
+	/* x^1088 mod p(x), x^1024 mod p(x) */
+DATA ·CastConst+4064(SB)/8,$0x00000001609bc4b4
+DATA ·CastConst+4072(SB)/8,$0x0000000171fb63ce
+
+	/* x^2048 mod p(x), x^2016 mod p(x), x^1984 mod p(x), x^1952 mod p(x) */
+DATA ·CastConst+4080(SB)/8,$0x5cf015c388e56f72
+DATA ·CastConst+4088(SB)/8,$0x7fec2963e5bf8048
+
+	/* x^1920 mod p(x), x^1888 mod p(x), x^1856 mod p(x), x^1824 mod p(x) */
+DATA ·CastConst+4096(SB)/8,$0x963a18920246e2e6
+DATA ·CastConst+4104(SB)/8,$0x38e888d4844752a9
+
+	/* x^1792 mod p(x), x^1760 mod p(x), x^1728 mod p(x), x^1696 mod p(x) */
+DATA ·CastConst+4112(SB)/8,$0x419a441956993a31
+DATA ·CastConst+4120(SB)/8,$0x42316c00730206ad
+
+	/* x^1664 mod p(x), x^1632 mod p(x), x^1600 mod p(x), x^1568 mod p(x) */
+DATA ·CastConst+4128(SB)/8,$0x924752ba2b830011
+DATA ·CastConst+4136(SB)/8,$0x543d5c543e65ddf9
+
+	/* x^1536 mod p(x), x^1504 mod p(x), x^1472 mod p(x), x^1440 mod p(x) */
+DATA ·CastConst+4144(SB)/8,$0x55bd7f9518e4a304
+DATA ·CastConst+4152(SB)/8,$0x78e87aaf56767c92
+
+	/* x^1408 mod p(x), x^1376 mod p(x), x^1344 mod p(x), x^1312 mod p(x) */
+DATA ·CastConst+4160(SB)/8,$0x6d76739fe0553f1e
+DATA ·CastConst+4168(SB)/8,$0x8f68fcec1903da7f
+
+	/* x^1280 mod p(x), x^1248 mod p(x), x^1216 mod p(x), x^1184 mod p(x) */
+DATA ·CastConst+4176(SB)/8,$0xc133722b1fe0b5c3
+DATA ·CastConst+4184(SB)/8,$0x3f4840246791d588
+
+	/* x^1152 mod p(x), x^1120 mod p(x), x^1088 mod p(x), x^1056 mod p(x) */
+DATA ·CastConst+4192(SB)/8,$0x64b67ee0e55ef1f3
+DATA ·CastConst+4200(SB)/8,$0x34c96751b04de25a
+
+	/* x^1024 mod p(x), x^992 mod p(x), x^960 mod p(x), x^928 mod p(x) */
+DATA ·CastConst+4208(SB)/8,$0x069db049b8fdb1e7
+DATA ·CastConst+4216(SB)/8,$0x156c8e180b4a395b
+
+	/* x^896 mod p(x), x^864 mod p(x), x^832 mod p(x), x^800 mod p(x) */
+DATA ·CastConst+4224(SB)/8,$0xa11bfaf3c9e90b9e
+DATA ·CastConst+4232(SB)/8,$0xe0b99ccbe661f7be
+
+	/* x^768 mod p(x), x^736 mod p(x), x^704 mod p(x), x^672 mod p(x) */
+DATA ·CastConst+4240(SB)/8,$0x817cdc5119b29a35
+DATA ·CastConst+4248(SB)/8,$0x041d37768cd75659
+
+	/* x^640 mod p(x), x^608 mod p(x), x^576 mod p(x), x^544 mod p(x) */
+DATA ·CastConst+4256(SB)/8,$0x1ce9d94b36c41f1c
+DATA ·CastConst+4264(SB)/8,$0x3a0777818cfaa965
+
+	/* x^512 mod p(x), x^480 mod p(x), x^448 mod p(x), x^416 mod p(x) */
+DATA ·CastConst+4272(SB)/8,$0x4f256efcb82be955
+DATA ·CastConst+4280(SB)/8,$0x0e148e8252377a55
+
+	/* x^384 mod p(x), x^352 mod p(x), x^320 mod p(x), x^288 mod p(x) */
+DATA ·CastConst+4288(SB)/8,$0xec1631edb2dea967
+DATA ·CastConst+4296(SB)/8,$0x9c25531d19e65dde
+
+	/* x^256 mod p(x), x^224 mod p(x), x^192 mod p(x), x^160 mod p(x) */
+DATA ·CastConst+4304(SB)/8,$0x5d27e147510ac59a
+DATA ·CastConst+4312(SB)/8,$0x790606ff9957c0a6
+
+	/* x^128 mod p(x), x^96 mod p(x), x^64 mod p(x), x^32 mod p(x) */
+DATA ·CastConst+4320(SB)/8,$0xa66805eb18b8ea18
+DATA ·CastConst+4328(SB)/8,$0x82f63b786ea2d55c
+
+GLOBL ·CastConst(SB),RODATA,$4336
+
+ /* Barrett constant m - (4^32)/n */
+DATA ·CastBarConst(SB)/8,$0x00000000dea713f1
+DATA ·CastBarConst+8(SB)/8,$0x0000000000000000
+DATA ·CastBarConst+16(SB)/8,$0x0000000105ec76f1
+DATA ·CastBarConst+24(SB)/8,$0x0000000000000000
+GLOBL ·CastBarConst(SB),RODATA,$32
+
+	/* Reduce 262144 kbits to 1024 bits */
+	/* x^261184 mod p(x), x^261120 mod p(x) */
+DATA ·KoopConst+0(SB)/8,$0x00000000d72535b2
+DATA ·KoopConst+8(SB)/8,$0x000000007fd74916
+
+	/* x^260160 mod p(x), x^260096 mod p(x) */
+DATA ·KoopConst+16(SB)/8,$0x0000000118a2a1b4
+DATA ·KoopConst+24(SB)/8,$0x000000010e944b56
+
+	/* x^259136 mod p(x), x^259072 mod p(x) */
+DATA ·KoopConst+32(SB)/8,$0x0000000147b5c49c
+DATA ·KoopConst+40(SB)/8,$0x00000000bfe71c20
+
+	/* x^258112 mod p(x), x^258048 mod p(x) */
+DATA ·KoopConst+48(SB)/8,$0x00000001ca76a040
+DATA ·KoopConst+56(SB)/8,$0x0000000021324d9a
+
+	/* x^257088 mod p(x), x^257024 mod p(x) */
+DATA ·KoopConst+64(SB)/8,$0x00000001e3152efc
+DATA ·KoopConst+72(SB)/8,$0x00000000d20972ce
+
+	/* x^256064 mod p(x), x^256000 mod p(x) */
+DATA ·KoopConst+80(SB)/8,$0x00000001b0349792
+DATA ·KoopConst+88(SB)/8,$0x000000003475ea06
+
+	/* x^255040 mod p(x), x^254976 mod p(x) */
+DATA ·KoopConst+96(SB)/8,$0x0000000120a60fe0
+DATA ·KoopConst+104(SB)/8,$0x00000001e40e36c4
+
+	/* x^254016 mod p(x), x^253952 mod p(x) */
+DATA ·KoopConst+112(SB)/8,$0x00000000b3c4b082
+DATA ·KoopConst+120(SB)/8,$0x00000000b2490102
+
+	/* x^252992 mod p(x), x^252928 mod p(x) */
+DATA ·KoopConst+128(SB)/8,$0x000000017fe9f3d2
+DATA ·KoopConst+136(SB)/8,$0x000000016b9e1332
+
+	/* x^251968 mod p(x), x^251904 mod p(x) */
+DATA ·KoopConst+144(SB)/8,$0x0000000145703cbe
+DATA ·KoopConst+152(SB)/8,$0x00000001d6c378f4
+
+	/* x^250944 mod p(x), x^250880 mod p(x) */
+DATA ·KoopConst+160(SB)/8,$0x0000000107551c9c
+DATA ·KoopConst+168(SB)/8,$0x0000000085796eac
+
+	/* x^249920 mod p(x), x^249856 mod p(x) */
+DATA ·KoopConst+176(SB)/8,$0x000000003865a702
+DATA ·KoopConst+184(SB)/8,$0x000000019d2f3aaa
+
+	/* x^248896 mod p(x), x^248832 mod p(x) */
+DATA ·KoopConst+192(SB)/8,$0x000000005504f9b8
+DATA ·KoopConst+200(SB)/8,$0x00000001554ddbd4
+
+	/* x^247872 mod p(x), x^247808 mod p(x) */
+DATA ·KoopConst+208(SB)/8,$0x00000000239bcdd4
+DATA ·KoopConst+216(SB)/8,$0x00000000a76376b0
+
+	/* x^246848 mod p(x), x^246784 mod p(x) */
+DATA ·KoopConst+224(SB)/8,$0x00000000caead774
+DATA ·KoopConst+232(SB)/8,$0x0000000139b7283c
+
+	/* x^245824 mod p(x), x^245760 mod p(x) */
+DATA ·KoopConst+240(SB)/8,$0x0000000022a3fa16
+DATA ·KoopConst+248(SB)/8,$0x0000000111087030
+
+	/* x^244800 mod p(x), x^244736 mod p(x) */
+DATA ·KoopConst+256(SB)/8,$0x000000011f89160e
+DATA ·KoopConst+264(SB)/8,$0x00000000ad786dc2
+
+	/* x^243776 mod p(x), x^243712 mod p(x) */
+DATA ·KoopConst+272(SB)/8,$0x00000001a976c248
+DATA ·KoopConst+280(SB)/8,$0x00000000b7a1d068
+
+	/* x^242752 mod p(x), x^242688 mod p(x) */
+DATA ·KoopConst+288(SB)/8,$0x00000000c20d09c8
+DATA ·KoopConst+296(SB)/8,$0x000000009c5c591c
+
+	/* x^241728 mod p(x), x^241664 mod p(x) */
+DATA ·KoopConst+304(SB)/8,$0x000000016264fe38
+DATA ·KoopConst+312(SB)/8,$0x000000016482aa1a
+
+	/* x^240704 mod p(x), x^240640 mod p(x) */
+DATA ·KoopConst+320(SB)/8,$0x00000001b57aee6a
+DATA ·KoopConst+328(SB)/8,$0x000000009a409ba8
+
+	/* x^239680 mod p(x), x^239616 mod p(x) */
+DATA ·KoopConst+336(SB)/8,$0x00000000e8f1be0a
+DATA ·KoopConst+344(SB)/8,$0x00000001ad8eaed8
+
+	/* x^238656 mod p(x), x^238592 mod p(x) */
+DATA ·KoopConst+352(SB)/8,$0x0000000053fcd0fc
+DATA ·KoopConst+360(SB)/8,$0x000000017558b57a
+
+	/* x^237632 mod p(x), x^237568 mod p(x) */
+DATA ·KoopConst+368(SB)/8,$0x000000012df9d496
+DATA ·KoopConst+376(SB)/8,$0x00000000cbb749c8
+
+	/* x^236608 mod p(x), x^236544 mod p(x) */
+DATA ·KoopConst+384(SB)/8,$0x000000004cb0db26
+DATA ·KoopConst+392(SB)/8,$0x000000008524fc5a
+
+	/* x^235584 mod p(x), x^235520 mod p(x) */
+DATA ·KoopConst+400(SB)/8,$0x00000001150c4584
+DATA ·KoopConst+408(SB)/8,$0x0000000028ce6b76
+
+	/* x^234560 mod p(x), x^234496 mod p(x) */
+DATA ·KoopConst+416(SB)/8,$0x0000000104f52056
+DATA ·KoopConst+424(SB)/8,$0x00000000e0c48bdc
+
+	/* x^233536 mod p(x), x^233472 mod p(x) */
+DATA ·KoopConst+432(SB)/8,$0x000000008ea11ac8
+DATA ·KoopConst+440(SB)/8,$0x000000003dd3bf9a
+
+	/* x^232512 mod p(x), x^232448 mod p(x) */
+DATA ·KoopConst+448(SB)/8,$0x00000001cc0a3942
+DATA ·KoopConst+456(SB)/8,$0x00000000cb71066c
+
+	/* x^231488 mod p(x), x^231424 mod p(x) */
+DATA ·KoopConst+464(SB)/8,$0x00000000d26231e6
+DATA ·KoopConst+472(SB)/8,$0x00000001d4ee1540
+
+	/* x^230464 mod p(x), x^230400 mod p(x) */
+DATA ·KoopConst+480(SB)/8,$0x00000000c70d5730
+DATA ·KoopConst+488(SB)/8,$0x00000001d82bed0a
+
+	/* x^229440 mod p(x), x^229376 mod p(x) */
+DATA ·KoopConst+496(SB)/8,$0x00000000e215dfc4
+DATA ·KoopConst+504(SB)/8,$0x000000016e0c7d86
+
+	/* x^228416 mod p(x), x^228352 mod p(x) */
+DATA ·KoopConst+512(SB)/8,$0x000000013870d0dc
+DATA ·KoopConst+520(SB)/8,$0x00000001437051b0
+
+	/* x^227392 mod p(x), x^227328 mod p(x) */
+DATA ·KoopConst+528(SB)/8,$0x0000000153e4cf3c
+DATA ·KoopConst+536(SB)/8,$0x00000000f9a8d4be
+
+	/* x^226368 mod p(x), x^226304 mod p(x) */
+DATA ·KoopConst+544(SB)/8,$0x0000000125f6fdf0
+DATA ·KoopConst+552(SB)/8,$0x000000016b09be1c
+
+	/* x^225344 mod p(x), x^225280 mod p(x) */
+DATA ·KoopConst+560(SB)/8,$0x0000000157ba3a82
+DATA ·KoopConst+568(SB)/8,$0x0000000105f50ed6
+
+	/* x^224320 mod p(x), x^224256 mod p(x) */
+DATA ·KoopConst+576(SB)/8,$0x00000001cf711064
+DATA ·KoopConst+584(SB)/8,$0x00000001ca7fe3cc
+
+	/* x^223296 mod p(x), x^223232 mod p(x) */
+DATA ·KoopConst+592(SB)/8,$0x00000001006353d2
+DATA ·KoopConst+600(SB)/8,$0x0000000192372e78
+
+	/* x^222272 mod p(x), x^222208 mod p(x) */
+DATA ·KoopConst+608(SB)/8,$0x000000010cd9faec
+DATA ·KoopConst+616(SB)/8,$0x000000008a47af7e
+
+	/* x^221248 mod p(x), x^221184 mod p(x) */
+DATA ·KoopConst+624(SB)/8,$0x000000012148b190
+DATA ·KoopConst+632(SB)/8,$0x00000000a67473e8
+
+	/* x^220224 mod p(x), x^220160 mod p(x) */
+DATA ·KoopConst+640(SB)/8,$0x00000000776473d6
+DATA ·KoopConst+648(SB)/8,$0x000000013689f2fa
+
+	/* x^219200 mod p(x), x^219136 mod p(x) */
+DATA ·KoopConst+656(SB)/8,$0x00000001ce765bd6
+DATA ·KoopConst+664(SB)/8,$0x00000000e7231774
+
+	/* x^218176 mod p(x), x^218112 mod p(x) */
+DATA ·KoopConst+672(SB)/8,$0x00000000b29165e8
+DATA ·KoopConst+680(SB)/8,$0x0000000011b5ae68
+
+	/* x^217152 mod p(x), x^217088 mod p(x) */
+DATA ·KoopConst+688(SB)/8,$0x0000000084ff5a68
+DATA ·KoopConst+696(SB)/8,$0x000000004fd5c188
+
+	/* x^216128 mod p(x), x^216064 mod p(x) */
+DATA ·KoopConst+704(SB)/8,$0x00000001921e9076
+DATA ·KoopConst+712(SB)/8,$0x000000012148fa22
+
+	/* x^215104 mod p(x), x^215040 mod p(x) */
+DATA ·KoopConst+720(SB)/8,$0x000000009a753a3c
+DATA ·KoopConst+728(SB)/8,$0x000000010cff4f3e
+
+	/* x^214080 mod p(x), x^214016 mod p(x) */
+DATA ·KoopConst+736(SB)/8,$0x000000000251401e
+DATA ·KoopConst+744(SB)/8,$0x00000001f9d991d4
+
+	/* x^213056 mod p(x), x^212992 mod p(x) */
+DATA ·KoopConst+752(SB)/8,$0x00000001f65541fa
+DATA ·KoopConst+760(SB)/8,$0x00000001c31db214
+
+	/* x^212032 mod p(x), x^211968 mod p(x) */
+DATA ·KoopConst+768(SB)/8,$0x00000001d8c8117a
+DATA ·KoopConst+776(SB)/8,$0x00000001849fba4a
+
+	/* x^211008 mod p(x), x^210944 mod p(x) */
+DATA ·KoopConst+784(SB)/8,$0x000000014f7a2200
+DATA ·KoopConst+792(SB)/8,$0x00000001cb603184
+
+	/* x^209984 mod p(x), x^209920 mod p(x) */
+DATA ·KoopConst+800(SB)/8,$0x000000005154a9f4
+DATA ·KoopConst+808(SB)/8,$0x0000000132db7116
+
+	/* x^208960 mod p(x), x^208896 mod p(x) */
+DATA ·KoopConst+816(SB)/8,$0x00000001dfc69196
+DATA ·KoopConst+824(SB)/8,$0x0000000010694e22
+
+	/* x^207936 mod p(x), x^207872 mod p(x) */
+DATA ·KoopConst+832(SB)/8,$0x00000001c29f1aa0
+DATA ·KoopConst+840(SB)/8,$0x0000000103b7b478
+
+	/* x^206912 mod p(x), x^206848 mod p(x) */
+DATA ·KoopConst+848(SB)/8,$0x000000013785f232
+DATA ·KoopConst+856(SB)/8,$0x000000000ab44030
+
+	/* x^205888 mod p(x), x^205824 mod p(x) */
+DATA ·KoopConst+864(SB)/8,$0x000000010133536e
+DATA ·KoopConst+872(SB)/8,$0x0000000131385b68
+
+	/* x^204864 mod p(x), x^204800 mod p(x) */
+DATA ·KoopConst+880(SB)/8,$0x00000001d45421dc
+DATA ·KoopConst+888(SB)/8,$0x00000001761dab66
+
+	/* x^203840 mod p(x), x^203776 mod p(x) */
+DATA ·KoopConst+896(SB)/8,$0x000000000b59cc28
+DATA ·KoopConst+904(SB)/8,$0x000000012cf0a2a6
+
+	/* x^202816 mod p(x), x^202752 mod p(x) */
+DATA ·KoopConst+912(SB)/8,$0x00000001f2f74aba
+DATA ·KoopConst+920(SB)/8,$0x00000001f4ce25a2
+
+	/* x^201792 mod p(x), x^201728 mod p(x) */
+DATA ·KoopConst+928(SB)/8,$0x00000000fb308e7e
+DATA ·KoopConst+936(SB)/8,$0x000000014c2aae20
+
+	/* x^200768 mod p(x), x^200704 mod p(x) */
+DATA ·KoopConst+944(SB)/8,$0x0000000167583fa6
+DATA ·KoopConst+952(SB)/8,$0x00000001c162a55a
+
+	/* x^199744 mod p(x), x^199680 mod p(x) */
+DATA ·KoopConst+960(SB)/8,$0x000000017ebb13e0
+DATA ·KoopConst+968(SB)/8,$0x0000000185681a40
+
+	/* x^198720 mod p(x), x^198656 mod p(x) */
+DATA ·KoopConst+976(SB)/8,$0x00000001ca653306
+DATA ·KoopConst+984(SB)/8,$0x00000001f2642b48
+
+	/* x^197696 mod p(x), x^197632 mod p(x) */
+DATA ·KoopConst+992(SB)/8,$0x0000000093bb6946
+DATA ·KoopConst+1000(SB)/8,$0x00000001d9cb5a78
+
+	/* x^196672 mod p(x), x^196608 mod p(x) */
+DATA ·KoopConst+1008(SB)/8,$0x00000000cbc1553e
+DATA ·KoopConst+1016(SB)/8,$0x000000008059328c
+
+	/* x^195648 mod p(x), x^195584 mod p(x) */
+DATA ·KoopConst+1024(SB)/8,$0x00000001f9a86fec
+DATA ·KoopConst+1032(SB)/8,$0x000000009373c360
+
+	/* x^194624 mod p(x), x^194560 mod p(x) */
+DATA ·KoopConst+1040(SB)/8,$0x0000000005c52d8a
+DATA ·KoopConst+1048(SB)/8,$0x00000001a14061d6
+
+	/* x^193600 mod p(x), x^193536 mod p(x) */
+DATA ·KoopConst+1056(SB)/8,$0x000000010d8dc668
+DATA ·KoopConst+1064(SB)/8,$0x00000000a9864d48
+
+	/* x^192576 mod p(x), x^192512 mod p(x) */
+DATA ·KoopConst+1072(SB)/8,$0x0000000158571310
+DATA ·KoopConst+1080(SB)/8,$0x000000011df8c040
+
+	/* x^191552 mod p(x), x^191488 mod p(x) */
+DATA ·KoopConst+1088(SB)/8,$0x0000000166102348
+DATA ·KoopConst+1096(SB)/8,$0x0000000023a3e6b6
+
+	/* x^190528 mod p(x), x^190464 mod p(x) */
+DATA ·KoopConst+1104(SB)/8,$0x0000000009513050
+DATA ·KoopConst+1112(SB)/8,$0x00000001207db28a
+
+	/* x^189504 mod p(x), x^189440 mod p(x) */
+DATA ·KoopConst+1120(SB)/8,$0x00000000b0725c74
+DATA ·KoopConst+1128(SB)/8,$0x00000000f94bc632
+
+	/* x^188480 mod p(x), x^188416 mod p(x) */
+DATA ·KoopConst+1136(SB)/8,$0x000000002985c7e2
+DATA ·KoopConst+1144(SB)/8,$0x00000000ea32cbf6
+
+	/* x^187456 mod p(x), x^187392 mod p(x) */
+DATA ·KoopConst+1152(SB)/8,$0x00000000a7d4da9e
+DATA ·KoopConst+1160(SB)/8,$0x0000000004eb981a
+
+	/* x^186432 mod p(x), x^186368 mod p(x) */
+DATA ·KoopConst+1168(SB)/8,$0x000000000a3f8792
+DATA ·KoopConst+1176(SB)/8,$0x00000000ca8ce712
+
+	/* x^185408 mod p(x), x^185344 mod p(x) */
+DATA ·KoopConst+1184(SB)/8,$0x00000001ca2c1ce4
+DATA ·KoopConst+1192(SB)/8,$0x0000000065ba801c
+
+	/* x^184384 mod p(x), x^184320 mod p(x) */
+DATA ·KoopConst+1200(SB)/8,$0x00000000e2900196
+DATA ·KoopConst+1208(SB)/8,$0x0000000194aade7a
+
+	/* x^183360 mod p(x), x^183296 mod p(x) */
+DATA ·KoopConst+1216(SB)/8,$0x00000001fbadf0e4
+DATA ·KoopConst+1224(SB)/8,$0x00000001e7939fb2
+
+	/* x^182336 mod p(x), x^182272 mod p(x) */
+DATA ·KoopConst+1232(SB)/8,$0x00000000d5d96c40
+DATA ·KoopConst+1240(SB)/8,$0x0000000098e5fe22
+
+	/* x^181312 mod p(x), x^181248 mod p(x) */
+DATA ·KoopConst+1248(SB)/8,$0x000000015c11d3f2
+DATA ·KoopConst+1256(SB)/8,$0x000000016bba0324
+
+	/* x^180288 mod p(x), x^180224 mod p(x) */
+DATA ·KoopConst+1264(SB)/8,$0x0000000111fb2648
+DATA ·KoopConst+1272(SB)/8,$0x0000000104dce052
+
+	/* x^179264 mod p(x), x^179200 mod p(x) */
+DATA ·KoopConst+1280(SB)/8,$0x00000001d9f3a564
+DATA ·KoopConst+1288(SB)/8,$0x00000001af31a42e
+
+	/* x^178240 mod p(x), x^178176 mod p(x) */
+DATA ·KoopConst+1296(SB)/8,$0x00000001b556cd1e
+DATA ·KoopConst+1304(SB)/8,$0x00000001c56c57ba
+
+	/* x^177216 mod p(x), x^177152 mod p(x) */
+DATA ·KoopConst+1312(SB)/8,$0x0000000101994d2c
+DATA ·KoopConst+1320(SB)/8,$0x00000000f6bb1a2e
+
+	/* x^176192 mod p(x), x^176128 mod p(x) */
+DATA ·KoopConst+1328(SB)/8,$0x00000001e8dbf09c
+DATA ·KoopConst+1336(SB)/8,$0x00000001abdbf2b2
+
+	/* x^175168 mod p(x), x^175104 mod p(x) */
+DATA ·KoopConst+1344(SB)/8,$0x000000015580543a
+DATA ·KoopConst+1352(SB)/8,$0x00000001a665a880
+
+	/* x^174144 mod p(x), x^174080 mod p(x) */
+DATA ·KoopConst+1360(SB)/8,$0x00000000c7074f24
+DATA ·KoopConst+1368(SB)/8,$0x00000000c102c700
+
+	/* x^173120 mod p(x), x^173056 mod p(x) */
+DATA ·KoopConst+1376(SB)/8,$0x00000000fa4112b0
+DATA ·KoopConst+1384(SB)/8,$0x00000000ee362a50
+
+	/* x^172096 mod p(x), x^172032 mod p(x) */
+DATA ·KoopConst+1392(SB)/8,$0x00000000e786c13e
+DATA ·KoopConst+1400(SB)/8,$0x0000000045f29038
+
+	/* x^171072 mod p(x), x^171008 mod p(x) */
+DATA ·KoopConst+1408(SB)/8,$0x00000001e45e3694
+DATA ·KoopConst+1416(SB)/8,$0x0000000117b9ab5c
+
+	/* x^170048 mod p(x), x^169984 mod p(x) */
+DATA ·KoopConst+1424(SB)/8,$0x000000005423dd8c
+DATA ·KoopConst+1432(SB)/8,$0x00000001115dff5e
+
+	/* x^169024 mod p(x), x^168960 mod p(x) */
+DATA ·KoopConst+1440(SB)/8,$0x00000001a1e67766
+DATA ·KoopConst+1448(SB)/8,$0x0000000117fad29c
+
+	/* x^168000 mod p(x), x^167936 mod p(x) */
+DATA ·KoopConst+1456(SB)/8,$0x0000000041a3f508
+DATA ·KoopConst+1464(SB)/8,$0x000000017de134e6
+
+	/* x^166976 mod p(x), x^166912 mod p(x) */
+DATA ·KoopConst+1472(SB)/8,$0x000000003e792f7e
+DATA ·KoopConst+1480(SB)/8,$0x00000000a2f5d19c
+
+	/* x^165952 mod p(x), x^165888 mod p(x) */
+DATA ·KoopConst+1488(SB)/8,$0x00000000c8948aaa
+DATA ·KoopConst+1496(SB)/8,$0x00000000dee13658
+
+	/* x^164928 mod p(x), x^164864 mod p(x) */
+DATA ·KoopConst+1504(SB)/8,$0x000000005d4ccb36
+DATA ·KoopConst+1512(SB)/8,$0x000000015355440c
+
+	/* x^163904 mod p(x), x^163840 mod p(x) */
+DATA ·KoopConst+1520(SB)/8,$0x00000000e92a78a2
+DATA ·KoopConst+1528(SB)/8,$0x0000000197a21778
+
+	/* x^162880 mod p(x), x^162816 mod p(x) */
+DATA ·KoopConst+1536(SB)/8,$0x000000016ba67caa
+DATA ·KoopConst+1544(SB)/8,$0x00000001a3835ec0
+
+	/* x^161856 mod p(x), x^161792 mod p(x) */
+DATA ·KoopConst+1552(SB)/8,$0x000000004838afc6
+DATA ·KoopConst+1560(SB)/8,$0x0000000011f20912
+
+	/* x^160832 mod p(x), x^160768 mod p(x) */
+DATA ·KoopConst+1568(SB)/8,$0x000000016644e308
+DATA ·KoopConst+1576(SB)/8,$0x00000001cce9d6cc
+
+	/* x^159808 mod p(x), x^159744 mod p(x) */
+DATA ·KoopConst+1584(SB)/8,$0x0000000037c22f42
+DATA ·KoopConst+1592(SB)/8,$0x0000000084d1e71c
+
+	/* x^158784 mod p(x), x^158720 mod p(x) */
+DATA ·KoopConst+1600(SB)/8,$0x00000001dedba6ca
+DATA ·KoopConst+1608(SB)/8,$0x0000000197c2ad54
+
+	/* x^157760 mod p(x), x^157696 mod p(x) */
+DATA ·KoopConst+1616(SB)/8,$0x0000000146a43500
+DATA ·KoopConst+1624(SB)/8,$0x000000018609261e
+
+	/* x^156736 mod p(x), x^156672 mod p(x) */
+DATA ·KoopConst+1632(SB)/8,$0x000000001cf762de
+DATA ·KoopConst+1640(SB)/8,$0x00000000b4b4c224
+
+	/* x^155712 mod p(x), x^155648 mod p(x) */
+DATA ·KoopConst+1648(SB)/8,$0x0000000022ff7eda
+DATA ·KoopConst+1656(SB)/8,$0x0000000080817496
+
+	/* x^154688 mod p(x), x^154624 mod p(x) */
+DATA ·KoopConst+1664(SB)/8,$0x00000001b6df625e
+DATA ·KoopConst+1672(SB)/8,$0x00000001aefb473c
+
+	/* x^153664 mod p(x), x^153600 mod p(x) */
+DATA ·KoopConst+1680(SB)/8,$0x00000001cc99ab58
+DATA ·KoopConst+1688(SB)/8,$0x000000013f1aa474
+
+	/* x^152640 mod p(x), x^152576 mod p(x) */
+DATA ·KoopConst+1696(SB)/8,$0x00000001c53f5ce2
+DATA ·KoopConst+1704(SB)/8,$0x000000010ca2c756
+
+	/* x^151616 mod p(x), x^151552 mod p(x) */
+DATA ·KoopConst+1712(SB)/8,$0x0000000082a9c60e
+DATA ·KoopConst+1720(SB)/8,$0x000000002c63533a
+
+	/* x^150592 mod p(x), x^150528 mod p(x) */
+DATA ·KoopConst+1728(SB)/8,$0x00000000ec78b570
+DATA ·KoopConst+1736(SB)/8,$0x00000001b7f2ad50
+
+	/* x^149568 mod p(x), x^149504 mod p(x) */
+DATA ·KoopConst+1744(SB)/8,$0x00000001d3fe1e8e
+DATA ·KoopConst+1752(SB)/8,$0x00000000acdf4c20
+
+	/* x^148544 mod p(x), x^148480 mod p(x) */
+DATA ·KoopConst+1760(SB)/8,$0x000000007f9a7bde
+DATA ·KoopConst+1768(SB)/8,$0x000000000bd29e8c
+
+	/* x^147520 mod p(x), x^147456 mod p(x) */
+DATA ·KoopConst+1776(SB)/8,$0x00000000e606f518
+DATA ·KoopConst+1784(SB)/8,$0x00000001eef6992e
+
+	/* x^146496 mod p(x), x^146432 mod p(x) */
+DATA ·KoopConst+1792(SB)/8,$0x000000008538cb96
+DATA ·KoopConst+1800(SB)/8,$0x00000000b01644e6
+
+	/* x^145472 mod p(x), x^145408 mod p(x) */
+DATA ·KoopConst+1808(SB)/8,$0x0000000131d030b2
+DATA ·KoopConst+1816(SB)/8,$0x0000000059c51acc
+
+	/* x^144448 mod p(x), x^144384 mod p(x) */
+DATA ·KoopConst+1824(SB)/8,$0x00000000115a4d0e
+DATA ·KoopConst+1832(SB)/8,$0x00000001a2849272
+
+	/* x^143424 mod p(x), x^143360 mod p(x) */
+DATA ·KoopConst+1840(SB)/8,$0x00000000e8a5356e
+DATA ·KoopConst+1848(SB)/8,$0x00000001a4e0b610
+
+	/* x^142400 mod p(x), x^142336 mod p(x) */
+DATA ·KoopConst+1856(SB)/8,$0x0000000158d988be
+DATA ·KoopConst+1864(SB)/8,$0x00000000084e81a6
+
+	/* x^141376 mod p(x), x^141312 mod p(x) */
+DATA ·KoopConst+1872(SB)/8,$0x00000001240db498
+DATA ·KoopConst+1880(SB)/8,$0x00000001b71f1fd8
+
+	/* x^140352 mod p(x), x^140288 mod p(x) */
+DATA ·KoopConst+1888(SB)/8,$0x000000009ce87826
+DATA ·KoopConst+1896(SB)/8,$0x000000017f7df380
+
+	/* x^139328 mod p(x), x^139264 mod p(x) */
+DATA ·KoopConst+1904(SB)/8,$0x0000000021944aae
+DATA ·KoopConst+1912(SB)/8,$0x00000001f7f4e190
+
+	/* x^138304 mod p(x), x^138240 mod p(x) */
+DATA ·KoopConst+1920(SB)/8,$0x00000001cea3d67e
+DATA ·KoopConst+1928(SB)/8,$0x0000000150220d86
+
+	/* x^137280 mod p(x), x^137216 mod p(x) */
+DATA ·KoopConst+1936(SB)/8,$0x000000004434e926
+DATA ·KoopConst+1944(SB)/8,$0x00000001db7d2b2e
+
+	/* x^136256 mod p(x), x^136192 mod p(x) */
+DATA ·KoopConst+1952(SB)/8,$0x0000000011db8cbe
+DATA ·KoopConst+1960(SB)/8,$0x00000000b6ba9668
+
+	/* x^135232 mod p(x), x^135168 mod p(x) */
+DATA ·KoopConst+1968(SB)/8,$0x00000001f6e0b8dc
+DATA ·KoopConst+1976(SB)/8,$0x0000000103fdcecc
+
+	/* x^134208 mod p(x), x^134144 mod p(x) */
+DATA ·KoopConst+1984(SB)/8,$0x00000001f163f4a0
+DATA ·KoopConst+1992(SB)/8,$0x0000000079816a22
+
+	/* x^133184 mod p(x), x^133120 mod p(x) */
+DATA ·KoopConst+2000(SB)/8,$0x000000007b6cc60e
+DATA ·KoopConst+2008(SB)/8,$0x0000000173483482
+
+	/* x^132160 mod p(x), x^132096 mod p(x) */
+DATA ·KoopConst+2016(SB)/8,$0x000000000f26c82c
+DATA ·KoopConst+2024(SB)/8,$0x00000000643ea4c0
+
+	/* x^131136 mod p(x), x^131072 mod p(x) */
+DATA ·KoopConst+2032(SB)/8,$0x00000000b0acad80
+DATA ·KoopConst+2040(SB)/8,$0x00000000a64752d2
+
+	/* x^130112 mod p(x), x^130048 mod p(x) */
+DATA ·KoopConst+2048(SB)/8,$0x000000013687e91c
+DATA ·KoopConst+2056(SB)/8,$0x00000000ca98eb3a
+
+	/* x^129088 mod p(x), x^129024 mod p(x) */
+DATA ·KoopConst+2064(SB)/8,$0x000000006bac3a96
+DATA ·KoopConst+2072(SB)/8,$0x00000001ca6ac8f8
+
+	/* x^128064 mod p(x), x^128000 mod p(x) */
+DATA ·KoopConst+2080(SB)/8,$0x00000001bf197d5c
+DATA ·KoopConst+2088(SB)/8,$0x00000001c48e2e68
+
+	/* x^127040 mod p(x), x^126976 mod p(x) */
+DATA ·KoopConst+2096(SB)/8,$0x00000000256e84f2
+DATA ·KoopConst+2104(SB)/8,$0x0000000070086782
+
+	/* x^126016 mod p(x), x^125952 mod p(x) */
+DATA ·KoopConst+2112(SB)/8,$0x000000003eff0d16
+DATA ·KoopConst+2120(SB)/8,$0x00000000f763621c
+
+	/* x^124992 mod p(x), x^124928 mod p(x) */
+DATA ·KoopConst+2128(SB)/8,$0x00000001748e9fd2
+DATA ·KoopConst+2136(SB)/8,$0x00000000ba58646a
+
+	/* x^123968 mod p(x), x^123904 mod p(x) */
+DATA ·KoopConst+2144(SB)/8,$0x000000015bb85b42
+DATA ·KoopConst+2152(SB)/8,$0x0000000138e157d8
+
+	/* x^122944 mod p(x), x^122880 mod p(x) */
+DATA ·KoopConst+2160(SB)/8,$0x0000000164d1a980
+DATA ·KoopConst+2168(SB)/8,$0x00000001bf0a09dc
+
+	/* x^121920 mod p(x), x^121856 mod p(x) */
+DATA ·KoopConst+2176(SB)/8,$0x000000001415c9f0
+DATA ·KoopConst+2184(SB)/8,$0x0000000098faf300
+
+	/* x^120896 mod p(x), x^120832 mod p(x) */
+DATA ·KoopConst+2192(SB)/8,$0x0000000195ae2f48
+DATA ·KoopConst+2200(SB)/8,$0x00000001f872f2c6
+
+	/* x^119872 mod p(x), x^119808 mod p(x) */
+DATA ·KoopConst+2208(SB)/8,$0x0000000059d1d81a
+DATA ·KoopConst+2216(SB)/8,$0x00000000f92577be
+
+	/* x^118848 mod p(x), x^118784 mod p(x) */
+DATA ·KoopConst+2224(SB)/8,$0x00000001bf80257a
+DATA ·KoopConst+2232(SB)/8,$0x00000001a4d975f4
+
+	/* x^117824 mod p(x), x^117760 mod p(x) */
+DATA ·KoopConst+2240(SB)/8,$0x000000011e39bfce
+DATA ·KoopConst+2248(SB)/8,$0x000000018b74eeca
+
+	/* x^116800 mod p(x), x^116736 mod p(x) */
+DATA ·KoopConst+2256(SB)/8,$0x00000001287a0456
+DATA ·KoopConst+2264(SB)/8,$0x00000000e8980404
+
+	/* x^115776 mod p(x), x^115712 mod p(x) */
+DATA ·KoopConst+2272(SB)/8,$0x00000000a5eb589c
+DATA ·KoopConst+2280(SB)/8,$0x0000000176ef2b74
+
+	/* x^114752 mod p(x), x^114688 mod p(x) */
+DATA ·KoopConst+2288(SB)/8,$0x000000017d71c452
+DATA ·KoopConst+2296(SB)/8,$0x0000000063c85caa
+
+	/* x^113728 mod p(x), x^113664 mod p(x) */
+DATA ·KoopConst+2304(SB)/8,$0x00000000fa941f08
+DATA ·KoopConst+2312(SB)/8,$0x00000001708012cc
+
+	/* x^112704 mod p(x), x^112640 mod p(x) */
+DATA ·KoopConst+2320(SB)/8,$0x0000000064ea030e
+DATA ·KoopConst+2328(SB)/8,$0x00000000474d58f6
+
+	/* x^111680 mod p(x), x^111616 mod p(x) */
+DATA ·KoopConst+2336(SB)/8,$0x000000019b7cc7ba
+DATA ·KoopConst+2344(SB)/8,$0x00000001c76085a6
+
+	/* x^110656 mod p(x), x^110592 mod p(x) */
+DATA ·KoopConst+2352(SB)/8,$0x00000000225cb7ba
+DATA ·KoopConst+2360(SB)/8,$0x000000018fb0681a
+
+	/* x^109632 mod p(x), x^109568 mod p(x) */
+DATA ·KoopConst+2368(SB)/8,$0x000000010ab3e1da
+DATA ·KoopConst+2376(SB)/8,$0x00000001fcee1f16
+
+	/* x^108608 mod p(x), x^108544 mod p(x) */
+DATA ·KoopConst+2384(SB)/8,$0x00000001ce5cc33e
+DATA ·KoopConst+2392(SB)/8,$0x00000000cfbffb7c
+
+	/* x^107584 mod p(x), x^107520 mod p(x) */
+DATA ·KoopConst+2400(SB)/8,$0x000000005e980f6e
+DATA ·KoopConst+2408(SB)/8,$0x000000017af8ee72
+
+	/* x^106560 mod p(x), x^106496 mod p(x) */
+DATA ·KoopConst+2416(SB)/8,$0x00000000d3bf3f46
+DATA ·KoopConst+2424(SB)/8,$0x000000001c2ad3e2
+
+	/* x^105536 mod p(x), x^105472 mod p(x) */
+DATA ·KoopConst+2432(SB)/8,$0x000000018d554ae0
+DATA ·KoopConst+2440(SB)/8,$0x00000000ee05450a
+
+	/* x^104512 mod p(x), x^104448 mod p(x) */
+DATA ·KoopConst+2448(SB)/8,$0x000000018e276eb0
+DATA ·KoopConst+2456(SB)/8,$0x000000000f7d5bac
+
+	/* x^103488 mod p(x), x^103424 mod p(x) */
+DATA ·KoopConst+2464(SB)/8,$0x000000001c0319ce
+DATA ·KoopConst+2472(SB)/8,$0x00000001cb26e004
+
+	/* x^102464 mod p(x), x^102400 mod p(x) */
+DATA ·KoopConst+2480(SB)/8,$0x00000001ca0c75ec
+DATA ·KoopConst+2488(SB)/8,$0x00000001553314e2
+
+	/* x^101440 mod p(x), x^101376 mod p(x) */
+DATA ·KoopConst+2496(SB)/8,$0x00000001fb075330
+DATA ·KoopConst+2504(SB)/8,$0x000000005729be2c
+
+	/* x^100416 mod p(x), x^100352 mod p(x) */
+DATA ·KoopConst+2512(SB)/8,$0x00000000677920e4
+DATA ·KoopConst+2520(SB)/8,$0x0000000192c4479c
+
+	/* x^99392 mod p(x), x^99328 mod p(x) */
+DATA ·KoopConst+2528(SB)/8,$0x00000000332247c8
+DATA ·KoopConst+2536(SB)/8,$0x0000000078d842b6
+
+	/* x^98368 mod p(x), x^98304 mod p(x) */
+DATA ·KoopConst+2544(SB)/8,$0x00000000ef84fc6c
+DATA ·KoopConst+2552(SB)/8,$0x0000000145ffa282
+
+	/* x^97344 mod p(x), x^97280 mod p(x) */
+DATA ·KoopConst+2560(SB)/8,$0x0000000139ba7690
+DATA ·KoopConst+2568(SB)/8,$0x000000019d679bf4
+
+	/* x^96320 mod p(x), x^96256 mod p(x) */
+DATA ·KoopConst+2576(SB)/8,$0x00000000029ef444
+DATA ·KoopConst+2584(SB)/8,$0x000000019412f7a0
+
+	/* x^95296 mod p(x), x^95232 mod p(x) */
+DATA ·KoopConst+2592(SB)/8,$0x00000001d872048c
+DATA ·KoopConst+2600(SB)/8,$0x00000000b28c5c96
+
+	/* x^94272 mod p(x), x^94208 mod p(x) */
+DATA ·KoopConst+2608(SB)/8,$0x000000016535d70a
+DATA ·KoopConst+2616(SB)/8,$0x00000000554bfd44
+
+	/* x^93248 mod p(x), x^93184 mod p(x) */
+DATA ·KoopConst+2624(SB)/8,$0x00000000761dd222
+DATA ·KoopConst+2632(SB)/8,$0x00000000ce9cfa48
+
+	/* x^92224 mod p(x), x^92160 mod p(x) */
+DATA ·KoopConst+2640(SB)/8,$0x00000001509a3a44
+DATA ·KoopConst+2648(SB)/8,$0x00000000a4702ab2
+
+	/* x^91200 mod p(x), x^91136 mod p(x) */
+DATA ·KoopConst+2656(SB)/8,$0x000000007e7019f2
+DATA ·KoopConst+2664(SB)/8,$0x00000001c967fbee
+
+	/* x^90176 mod p(x), x^90112 mod p(x) */
+DATA ·KoopConst+2672(SB)/8,$0x00000000fb4c56ea
+DATA ·KoopConst+2680(SB)/8,$0x00000000fd514b3e
+
+	/* x^89152 mod p(x), x^89088 mod p(x) */
+DATA ·KoopConst+2688(SB)/8,$0x000000012022e0ee
+DATA ·KoopConst+2696(SB)/8,$0x00000001c0b6f95e
+
+	/* x^88128 mod p(x), x^88064 mod p(x) */
+DATA ·KoopConst+2704(SB)/8,$0x0000000004bc6054
+DATA ·KoopConst+2712(SB)/8,$0x0000000180e103ce
+
+	/* x^87104 mod p(x), x^87040 mod p(x) */
+DATA ·KoopConst+2720(SB)/8,$0x000000017a1a0030
+DATA ·KoopConst+2728(SB)/8,$0x00000001a1630916
+
+	/* x^86080 mod p(x), x^86016 mod p(x) */
+DATA ·KoopConst+2736(SB)/8,$0x00000001c021a864
+DATA ·KoopConst+2744(SB)/8,$0x000000009a727fb2
+
+	/* x^85056 mod p(x), x^84992 mod p(x) */
+DATA ·KoopConst+2752(SB)/8,$0x000000009c54421e
+DATA ·KoopConst+2760(SB)/8,$0x00000000e83b081a
+
+	/* x^84032 mod p(x), x^83968 mod p(x) */
+DATA ·KoopConst+2768(SB)/8,$0x00000001b4e33e6a
+DATA ·KoopConst+2776(SB)/8,$0x000000006b1a1f44
+
+	/* x^83008 mod p(x), x^82944 mod p(x) */
+DATA ·KoopConst+2784(SB)/8,$0x000000015d615af0
+DATA ·KoopConst+2792(SB)/8,$0x00000000cf280394
+
+	/* x^81984 mod p(x), x^81920 mod p(x) */
+DATA ·KoopConst+2800(SB)/8,$0x00000001914a3ba8
+DATA ·KoopConst+2808(SB)/8,$0x00000001154b8a9a
+
+	/* x^80960 mod p(x), x^80896 mod p(x) */
+DATA ·KoopConst+2816(SB)/8,$0x000000005f72ec44
+DATA ·KoopConst+2824(SB)/8,$0x0000000149ec63e2
+
+	/* x^79936 mod p(x), x^79872 mod p(x) */
+DATA ·KoopConst+2832(SB)/8,$0x00000000a33746a8
+DATA ·KoopConst+2840(SB)/8,$0x000000018ef902c4
+
+	/* x^78912 mod p(x), x^78848 mod p(x) */
+DATA ·KoopConst+2848(SB)/8,$0x00000001c91e90d4
+DATA ·KoopConst+2856(SB)/8,$0x0000000069addb88
+
+	/* x^77888 mod p(x), x^77824 mod p(x) */
+DATA ·KoopConst+2864(SB)/8,$0x00000001052eb05e
+DATA ·KoopConst+2872(SB)/8,$0x00000000e90a29ae
+
+	/* x^76864 mod p(x), x^76800 mod p(x) */
+DATA ·KoopConst+2880(SB)/8,$0x000000006a32f754
+DATA ·KoopConst+2888(SB)/8,$0x00000000c53641ae
+
+	/* x^75840 mod p(x), x^75776 mod p(x) */
+DATA ·KoopConst+2896(SB)/8,$0x00000001ecbd6436
+DATA ·KoopConst+2904(SB)/8,$0x00000000a17c3796
+
+	/* x^74816 mod p(x), x^74752 mod p(x) */
+DATA ·KoopConst+2912(SB)/8,$0x000000000fd3f93a
+DATA ·KoopConst+2920(SB)/8,$0x000000015307a62c
+
+	/* x^73792 mod p(x), x^73728 mod p(x) */
+DATA ·KoopConst+2928(SB)/8,$0x00000001686a4c24
+DATA ·KoopConst+2936(SB)/8,$0x000000002f94bbda
+
+	/* x^72768 mod p(x), x^72704 mod p(x) */
+DATA ·KoopConst+2944(SB)/8,$0x00000001e40afca0
+DATA ·KoopConst+2952(SB)/8,$0x0000000072c8b5e6
+
+	/* x^71744 mod p(x), x^71680 mod p(x) */
+DATA ·KoopConst+2960(SB)/8,$0x000000012779a2b8
+DATA ·KoopConst+2968(SB)/8,$0x00000000f09b7424
+
+	/* x^70720 mod p(x), x^70656 mod p(x) */
+DATA ·KoopConst+2976(SB)/8,$0x00000000dcdaeb9e
+DATA ·KoopConst+2984(SB)/8,$0x00000001c57de3da
+
+	/* x^69696 mod p(x), x^69632 mod p(x) */
+DATA ·KoopConst+2992(SB)/8,$0x00000001674f7a2a
+DATA ·KoopConst+3000(SB)/8,$0x000000013922b30e
+
+	/* x^68672 mod p(x), x^68608 mod p(x) */
+DATA ·KoopConst+3008(SB)/8,$0x00000000dcb9e846
+DATA ·KoopConst+3016(SB)/8,$0x000000008759a6c2
+
+	/* x^67648 mod p(x), x^67584 mod p(x) */
+DATA ·KoopConst+3024(SB)/8,$0x00000000ea9a6af6
+DATA ·KoopConst+3032(SB)/8,$0x00000000545ae424
+
+	/* x^66624 mod p(x), x^66560 mod p(x) */
+DATA ·KoopConst+3040(SB)/8,$0x000000006d1f7a74
+DATA ·KoopConst+3048(SB)/8,$0x00000001e0cbafd2
+
+	/* x^65600 mod p(x), x^65536 mod p(x) */
+DATA ·KoopConst+3056(SB)/8,$0x000000006add215e
+DATA ·KoopConst+3064(SB)/8,$0x0000000018360c04
+
+	/* x^64576 mod p(x), x^64512 mod p(x) */
+DATA ·KoopConst+3072(SB)/8,$0x000000010a9ee4b0
+DATA ·KoopConst+3080(SB)/8,$0x00000000941dc432
+
+	/* x^63552 mod p(x), x^63488 mod p(x) */
+DATA ·KoopConst+3088(SB)/8,$0x00000000304c48d2
+DATA ·KoopConst+3096(SB)/8,$0x0000000004d3566e
+
+	/* x^62528 mod p(x), x^62464 mod p(x) */
+DATA ·KoopConst+3104(SB)/8,$0x0000000163d0e672
+DATA ·KoopConst+3112(SB)/8,$0x0000000096aed14e
+
+	/* x^61504 mod p(x), x^61440 mod p(x) */
+DATA ·KoopConst+3120(SB)/8,$0x0000000010049166
+DATA ·KoopConst+3128(SB)/8,$0x0000000087c13618
+
+	/* x^60480 mod p(x), x^60416 mod p(x) */
+DATA ·KoopConst+3136(SB)/8,$0x00000001d3913e34
+DATA ·KoopConst+3144(SB)/8,$0x00000001d52f7b0c
+
+	/* x^59456 mod p(x), x^59392 mod p(x) */
+DATA ·KoopConst+3152(SB)/8,$0x00000001e392d54a
+DATA ·KoopConst+3160(SB)/8,$0x000000000182058e
+
+	/* x^58432 mod p(x), x^58368 mod p(x) */
+DATA ·KoopConst+3168(SB)/8,$0x0000000173f2704a
+DATA ·KoopConst+3176(SB)/8,$0x00000001ed73aa02
+
+	/* x^57408 mod p(x), x^57344 mod p(x) */
+DATA ·KoopConst+3184(SB)/8,$0x000000019112b480
+DATA ·KoopConst+3192(SB)/8,$0x000000002721a82e
+
+	/* x^56384 mod p(x), x^56320 mod p(x) */
+DATA ·KoopConst+3200(SB)/8,$0x0000000093d295d6
+DATA ·KoopConst+3208(SB)/8,$0x000000012ca83da2
+
+	/* x^55360 mod p(x), x^55296 mod p(x) */
+DATA ·KoopConst+3216(SB)/8,$0x0000000114e37f44
+DATA ·KoopConst+3224(SB)/8,$0x00000000da358698
+
+	/* x^54336 mod p(x), x^54272 mod p(x) */
+DATA ·KoopConst+3232(SB)/8,$0x00000000fcfebc86
+DATA ·KoopConst+3240(SB)/8,$0x0000000011fad322
+
+	/* x^53312 mod p(x), x^53248 mod p(x) */
+DATA ·KoopConst+3248(SB)/8,$0x00000000834c48d6
+DATA ·KoopConst+3256(SB)/8,$0x000000012b25025c
+
+	/* x^52288 mod p(x), x^52224 mod p(x) */
+DATA ·KoopConst+3264(SB)/8,$0x000000017b909372
+DATA ·KoopConst+3272(SB)/8,$0x000000001290cd24
+
+	/* x^51264 mod p(x), x^51200 mod p(x) */
+DATA ·KoopConst+3280(SB)/8,$0x000000010156b9ac
+DATA ·KoopConst+3288(SB)/8,$0x000000016edd0b06
+
+	/* x^50240 mod p(x), x^50176 mod p(x) */
+DATA ·KoopConst+3296(SB)/8,$0x0000000113a82fa8
+DATA ·KoopConst+3304(SB)/8,$0x00000000c08e222a
+
+	/* x^49216 mod p(x), x^49152 mod p(x) */
+DATA ·KoopConst+3312(SB)/8,$0x0000000182dacb74
+DATA ·KoopConst+3320(SB)/8,$0x00000000cfb4d10e
+
+	/* x^48192 mod p(x), x^48128 mod p(x) */
+DATA ·KoopConst+3328(SB)/8,$0x000000010210dc40
+DATA ·KoopConst+3336(SB)/8,$0x000000013e156ece
+
+	/* x^47168 mod p(x), x^47104 mod p(x) */
+DATA ·KoopConst+3344(SB)/8,$0x000000008ab5ed20
+DATA ·KoopConst+3352(SB)/8,$0x00000000f12d89f8
+
+	/* x^46144 mod p(x), x^46080 mod p(x) */
+DATA ·KoopConst+3360(SB)/8,$0x00000000810386fa
+DATA ·KoopConst+3368(SB)/8,$0x00000001fce3337c
+
+	/* x^45120 mod p(x), x^45056 mod p(x) */
+DATA ·KoopConst+3376(SB)/8,$0x000000011dce2fe2
+DATA ·KoopConst+3384(SB)/8,$0x00000001c4bf3514
+
+	/* x^44096 mod p(x), x^44032 mod p(x) */
+DATA ·KoopConst+3392(SB)/8,$0x000000004bb0a390
+DATA ·KoopConst+3400(SB)/8,$0x00000001ae67c492
+
+	/* x^43072 mod p(x), x^43008 mod p(x) */
+DATA ·KoopConst+3408(SB)/8,$0x00000000028d486a
+DATA ·KoopConst+3416(SB)/8,$0x00000000302af704
+
+	/* x^42048 mod p(x), x^41984 mod p(x) */
+DATA ·KoopConst+3424(SB)/8,$0x000000010e4d63fe
+DATA ·KoopConst+3432(SB)/8,$0x00000001e375b250
+
+	/* x^41024 mod p(x), x^40960 mod p(x) */
+DATA ·KoopConst+3440(SB)/8,$0x000000014fd6f458
+DATA ·KoopConst+3448(SB)/8,$0x00000001678b58c0
+
+	/* x^40000 mod p(x), x^39936 mod p(x) */
+DATA ·KoopConst+3456(SB)/8,$0x00000000db7a83a2
+DATA ·KoopConst+3464(SB)/8,$0x0000000065103c1e
+
+	/* x^38976 mod p(x), x^38912 mod p(x) */
+DATA ·KoopConst+3472(SB)/8,$0x000000016cf9fa3c
+DATA ·KoopConst+3480(SB)/8,$0x000000000ccd28ca
+
+	/* x^37952 mod p(x), x^37888 mod p(x) */
+DATA ·KoopConst+3488(SB)/8,$0x000000016bb33912
+DATA ·KoopConst+3496(SB)/8,$0x0000000059c177d4
+
+	/* x^36928 mod p(x), x^36864 mod p(x) */
+DATA ·KoopConst+3504(SB)/8,$0x0000000135bda8bc
+DATA ·KoopConst+3512(SB)/8,$0x00000001d162f83a
+
+	/* x^35904 mod p(x), x^35840 mod p(x) */
+DATA ·KoopConst+3520(SB)/8,$0x000000004e8c6b76
+DATA ·KoopConst+3528(SB)/8,$0x00000001efc0230c
+
+	/* x^34880 mod p(x), x^34816 mod p(x) */
+DATA ·KoopConst+3536(SB)/8,$0x00000000e17cb750
+DATA ·KoopConst+3544(SB)/8,$0x00000001a2a2e2d2
+
+	/* x^33856 mod p(x), x^33792 mod p(x) */
+DATA ·KoopConst+3552(SB)/8,$0x000000010e8bb9cc
+DATA ·KoopConst+3560(SB)/8,$0x00000001145c9dc2
+
+	/* x^32832 mod p(x), x^32768 mod p(x) */
+DATA ·KoopConst+3568(SB)/8,$0x00000001859d1cae
+DATA ·KoopConst+3576(SB)/8,$0x00000000949e4a48
+
+	/* x^31808 mod p(x), x^31744 mod p(x) */
+DATA ·KoopConst+3584(SB)/8,$0x0000000167802bbe
+DATA ·KoopConst+3592(SB)/8,$0x0000000128beecbc
+
+	/* x^30784 mod p(x), x^30720 mod p(x) */
+DATA ·KoopConst+3600(SB)/8,$0x0000000086f5219c
+DATA ·KoopConst+3608(SB)/8,$0x00000001ffc96ae4
+
+	/* x^29760 mod p(x), x^29696 mod p(x) */
+DATA ·KoopConst+3616(SB)/8,$0x00000001349a4faa
+DATA ·KoopConst+3624(SB)/8,$0x00000001ba81e0aa
+
+	/* x^28736 mod p(x), x^28672 mod p(x) */
+DATA ·KoopConst+3632(SB)/8,$0x000000007da3353e
+DATA ·KoopConst+3640(SB)/8,$0x0000000104d7df14
+
+	/* x^27712 mod p(x), x^27648 mod p(x) */
+DATA ·KoopConst+3648(SB)/8,$0x00000000440fba4e
+DATA ·KoopConst+3656(SB)/8,$0x00000001c2ff8518
+
+	/* x^26688 mod p(x), x^26624 mod p(x) */
+DATA ·KoopConst+3664(SB)/8,$0x00000000507aba70
+DATA ·KoopConst+3672(SB)/8,$0x00000000ba6d4708
+
+	/* x^25664 mod p(x), x^25600 mod p(x) */
+DATA ·KoopConst+3680(SB)/8,$0x0000000015b578b6
+DATA ·KoopConst+3688(SB)/8,$0x00000001d49d4bba
+
+	/* x^24640 mod p(x), x^24576 mod p(x) */
+DATA ·KoopConst+3696(SB)/8,$0x0000000141633fb2
+DATA ·KoopConst+3704(SB)/8,$0x00000000d21247e6
+
+	/* x^23616 mod p(x), x^23552 mod p(x) */
+DATA ·KoopConst+3712(SB)/8,$0x0000000178712680
+DATA ·KoopConst+3720(SB)/8,$0x0000000063b4004a
+
+	/* x^22592 mod p(x), x^22528 mod p(x) */
+DATA ·KoopConst+3728(SB)/8,$0x000000001404c194
+DATA ·KoopConst+3736(SB)/8,$0x0000000094f55d2c
+
+	/* x^21568 mod p(x), x^21504 mod p(x) */
+DATA ·KoopConst+3744(SB)/8,$0x00000000469dbe46
+DATA ·KoopConst+3752(SB)/8,$0x00000001ca68fe74
+
+	/* x^20544 mod p(x), x^20480 mod p(x) */
+DATA ·KoopConst+3760(SB)/8,$0x00000000fb093fd8
+DATA ·KoopConst+3768(SB)/8,$0x00000001fd7d1b4c
+
+	/* x^19520 mod p(x), x^19456 mod p(x) */
+DATA ·KoopConst+3776(SB)/8,$0x00000000767a2bfe
+DATA ·KoopConst+3784(SB)/8,$0x0000000055982d0c
+
+	/* x^18496 mod p(x), x^18432 mod p(x) */
+DATA ·KoopConst+3792(SB)/8,$0x00000001344e22bc
+DATA ·KoopConst+3800(SB)/8,$0x00000000221553a6
+
+	/* x^17472 mod p(x), x^17408 mod p(x) */
+DATA ·KoopConst+3808(SB)/8,$0x0000000161cd9978
+DATA ·KoopConst+3816(SB)/8,$0x000000013d9a153a
+
+	/* x^16448 mod p(x), x^16384 mod p(x) */
+DATA ·KoopConst+3824(SB)/8,$0x00000001d702e906
+DATA ·KoopConst+3832(SB)/8,$0x00000001cd108b3c
+
+	/* x^15424 mod p(x), x^15360 mod p(x) */
+DATA ·KoopConst+3840(SB)/8,$0x00000001c7db9908
+DATA ·KoopConst+3848(SB)/8,$0x00000001d0af0f4a
+
+	/* x^14400 mod p(x), x^14336 mod p(x) */
+DATA ·KoopConst+3856(SB)/8,$0x00000001665d025c
+DATA ·KoopConst+3864(SB)/8,$0x00000001196cf0ec
+
+	/* x^13376 mod p(x), x^13312 mod p(x) */
+DATA ·KoopConst+3872(SB)/8,$0x000000012df97c0e
+DATA ·KoopConst+3880(SB)/8,$0x00000001c88c9704
+
+	/* x^12352 mod p(x), x^12288 mod p(x) */
+DATA ·KoopConst+3888(SB)/8,$0x000000006fed84da
+DATA ·KoopConst+3896(SB)/8,$0x000000002013d300
+
+	/* x^11328 mod p(x), x^11264 mod p(x) */
+DATA ·KoopConst+3904(SB)/8,$0x00000000b094146e
+DATA ·KoopConst+3912(SB)/8,$0x00000001c458501e
+
+	/* x^10304 mod p(x), x^10240 mod p(x) */
+DATA ·KoopConst+3920(SB)/8,$0x00000001ceb518a6
+DATA ·KoopConst+3928(SB)/8,$0x000000003ce14802
+
+	/* x^9280 mod p(x), x^9216 mod p(x) */
+DATA ·KoopConst+3936(SB)/8,$0x000000011f16db0a
+DATA ·KoopConst+3944(SB)/8,$0x00000000bb72bb98
+
+	/* x^8256 mod p(x), x^8192 mod p(x) */
+DATA ·KoopConst+3952(SB)/8,$0x00000001d4aa130e
+DATA ·KoopConst+3960(SB)/8,$0x00000000fb9aeaba
+
+	/* x^7232 mod p(x), x^7168 mod p(x) */
+DATA ·KoopConst+3968(SB)/8,$0x00000001991f01d2
+DATA ·KoopConst+3976(SB)/8,$0x000000000131f5e6
+
+	/* x^6208 mod p(x), x^6144 mod p(x) */
+DATA ·KoopConst+3984(SB)/8,$0x000000006bd58b4c
+DATA ·KoopConst+3992(SB)/8,$0x0000000089d5799a
+
+	/* x^5184 mod p(x), x^5120 mod p(x) */
+DATA ·KoopConst+4000(SB)/8,$0x000000007272c166
+DATA ·KoopConst+4008(SB)/8,$0x00000000474c43b0
+
+	/* x^4160 mod p(x), x^4096 mod p(x) */
+DATA ·KoopConst+4016(SB)/8,$0x000000013974e6f8
+DATA ·KoopConst+4024(SB)/8,$0x00000001db991f34
+
+	/* x^3136 mod p(x), x^3072 mod p(x) */
+DATA ·KoopConst+4032(SB)/8,$0x000000000bd6e03c
+DATA ·KoopConst+4040(SB)/8,$0x000000004b1bfd00
+
+	/* x^2112 mod p(x), x^2048 mod p(x) */
+DATA ·KoopConst+4048(SB)/8,$0x000000005988c652
+DATA ·KoopConst+4056(SB)/8,$0x000000004036b796
+
+	/* x^1088 mod p(x), x^1024 mod p(x) */
+DATA ·KoopConst+4064(SB)/8,$0x00000000129ef036
+DATA ·KoopConst+4072(SB)/8,$0x000000000c5ec3d4
+
+	/* x^2048 mod p(x), x^2016 mod p(x), x^1984 mod p(x), x^1952 mod p(x) */
+DATA ·KoopConst+4080(SB)/8,$0xd6f94847201b5bcb
+DATA ·KoopConst+4088(SB)/8,$0x1efc02e79571e892
+
+	/* x^1920 mod p(x), x^1888 mod p(x), x^1856 mod p(x), x^1824 mod p(x) */
+DATA ·KoopConst+4096(SB)/8,$0xce08adcc294c1393
+DATA ·KoopConst+4104(SB)/8,$0x0b269b5c5ab5f161
+
+	/* x^1792 mod p(x), x^1760 mod p(x), x^1728 mod p(x), x^1696 mod p(x) */
+DATA ·KoopConst+4112(SB)/8,$0x17315505e4201e72
+DATA ·KoopConst+4120(SB)/8,$0x2e841f4784acf3e9
+
+	/* x^1664 mod p(x), x^1632 mod p(x), x^1600 mod p(x), x^1568 mod p(x) */
+DATA ·KoopConst+4128(SB)/8,$0x37cfc3a67cc667e3
+DATA ·KoopConst+4136(SB)/8,$0x7020425856bc424b
+
+	/* x^1536 mod p(x), x^1504 mod p(x), x^1472 mod p(x), x^1440 mod p(x) */
+DATA ·KoopConst+4144(SB)/8,$0x8e2fa3369218d2c3
+DATA ·KoopConst+4152(SB)/8,$0xdf81bf923f7c6ef1
+
+	/* x^1408 mod p(x), x^1376 mod p(x), x^1344 mod p(x), x^1312 mod p(x) */
+DATA ·KoopConst+4160(SB)/8,$0x5ce20d2d39ed1981
+DATA ·KoopConst+4168(SB)/8,$0x9d0898a0af5ddc43
+
+	/* x^1280 mod p(x), x^1248 mod p(x), x^1216 mod p(x), x^1184 mod p(x) */
+DATA ·KoopConst+4176(SB)/8,$0x6f7f4546ca081e03
+DATA ·KoopConst+4184(SB)/8,$0x4992836903fda047
+
+	/* x^1152 mod p(x), x^1120 mod p(x), x^1088 mod p(x), x^1056 mod p(x) */
+DATA ·KoopConst+4192(SB)/8,$0xfd4f413b9bf11d68
+DATA ·KoopConst+4200(SB)/8,$0xf4ddf452094f781b
+
+	/* x^1024 mod p(x), x^992 mod p(x), x^960 mod p(x), x^928 mod p(x) */
+DATA ·KoopConst+4208(SB)/8,$0x11d84204062f61ea
+DATA ·KoopConst+4216(SB)/8,$0x9487f1e51f3588cf
+
+	/* x^896 mod p(x), x^864 mod p(x), x^832 mod p(x), x^800 mod p(x) */
+DATA ·KoopConst+4224(SB)/8,$0xfaedf111abf58a1f
+DATA ·KoopConst+4232(SB)/8,$0x31da2c22b1384ec9
+
+	/* x^768 mod p(x), x^736 mod p(x), x^704 mod p(x), x^672 mod p(x) */
+DATA ·KoopConst+4240(SB)/8,$0x0246b541e8f81b22
+DATA ·KoopConst+4248(SB)/8,$0xc857ede58a42eb47
+
+	/* x^640 mod p(x), x^608 mod p(x), x^576 mod p(x), x^544 mod p(x) */
+DATA ·KoopConst+4256(SB)/8,$0xd4dbfa9b92b0372e
+DATA ·KoopConst+4264(SB)/8,$0xe0354c0b2cd1c09a
+
+	/* x^512 mod p(x), x^480 mod p(x), x^448 mod p(x), x^416 mod p(x) */
+DATA ·KoopConst+4272(SB)/8,$0x5f36c79cfc4417ec
+DATA ·KoopConst+4280(SB)/8,$0x4b92cf8d54b8f25b
+
+	/* x^384 mod p(x), x^352 mod p(x), x^320 mod p(x), x^288 mod p(x) */
+DATA ·KoopConst+4288(SB)/8,$0xdad234918345041e
+DATA ·KoopConst+4296(SB)/8,$0x4e44c81828229301
+
+	/* x^256 mod p(x), x^224 mod p(x), x^192 mod p(x), x^160 mod p(x) */
+DATA ·KoopConst+4304(SB)/8,$0x56fd28cc8e02f1d0
+DATA ·KoopConst+4312(SB)/8,$0x3da5e43c8ee9ee84
+
+	/* x^128 mod p(x), x^96 mod p(x), x^64 mod p(x), x^32 mod p(x) */
+DATA ·KoopConst+4320(SB)/8,$0xa583017cdfcb9f08
+DATA ·KoopConst+4328(SB)/8,$0xeb31d82e0c62ab26
+
+GLOBL ·KoopConst(SB),RODATA,$4336
+
+ /* Barrett constant m - (4^32)/n */
+DATA ·KoopBarConst(SB)/8,$0x0000000017d232cd
+DATA ·KoopBarConst+8(SB)/8,$0x0000000000000000
+DATA ·KoopBarConst+16(SB)/8,$0x00000001d663b05d
+DATA ·KoopBarConst+24(SB)/8,$0x0000000000000000
+GLOBL ·KoopBarConst(SB),RODATA,$32
diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go
index 1356734..0492f46 100644
--- a/src/hash/crc32/crc32_test.go
+++ b/src/hash/crc32/crc32_test.go
@@ -5,6 +5,7 @@
 package crc32
 
 import (
+	"fmt"
 	"hash"
 	"math/rand"
 	"testing"
@@ -75,8 +76,9 @@ func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte)
 	// The AMD64 implementation has some cutoffs at lengths 168*3=504 and
 	// 1344*3=4032. We should make sure lengths around these values are in the
 	// list.
-	lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 100, 128,
-		500, 501, 502, 503, 504, 505, 512, 1000, 1024, 2000,
+	lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 63, 64, 65, 100,
+		127, 128, 129, 255, 256, 257, 300, 312, 384, 416, 448, 480,
+		500, 501, 502, 503, 504, 505, 512, 513, 1000, 1024, 2000,
 		4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
 	for _, length := range lengths {
 		p := make([]byte, length)
@@ -196,68 +198,28 @@ func TestGolden(t *testing.T) {
 	}
 }
 
-func BenchmarkIEEECrc40B(b *testing.B) {
-	benchmark(b, NewIEEE(), 40, 0)
+func BenchmarkCRC32(b *testing.B) {
+	b.Run("poly=IEEE", benchmarkAll(NewIEEE()))
+	b.Run("poly=Castagnoli", benchmarkAll(New(MakeTable(Castagnoli))))
+	b.Run("poly=Koopman", benchmarkAll(New(MakeTable(Koopman))))
 }
 
-func BenchmarkIEEECrc1KB(b *testing.B) {
-	benchmark(b, NewIEEE(), 1<<10, 0)
-}
-
-func BenchmarkIEEECrc4KB(b *testing.B) {
-	benchmark(b, NewIEEE(), 4<<10, 0)
-}
-
-func BenchmarkIEEECrc32KB(b *testing.B) {
-	benchmark(b, NewIEEE(), 32<<10, 0)
-}
-
-func BenchmarkCastagnoliCrc15B(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 15, 0)
-}
-
-func BenchmarkCastagnoliCrc15BMisaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 15, 1)
-}
-
-func BenchmarkCastagnoliCrc40B(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 40, 0)
-}
-
-func BenchmarkCastagnoliCrc40BMisaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 40, 1)
-}
-
-func BenchmarkCastagnoliCrc512(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 512, 0)
-}
-
-func BenchmarkCastagnoliCrc512Misaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 512, 1)
-}
-
-func BenchmarkCastagnoliCrc1KB(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 0)
-}
-
-func BenchmarkCastagnoliCrc1KBMisaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 1)
-}
-
-func BenchmarkCastagnoliCrc4KB(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 0)
-}
-
-func BenchmarkCastagnoliCrc4KBMisaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 1)
-}
-
-func BenchmarkCastagnoliCrc32KB(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 0)
-}
-
-func BenchmarkCastagnoliCrc32KBMisaligned(b *testing.B) {
-	benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 1)
+func benchmarkAll(h hash.Hash32) func(b *testing.B) {
+	return func(b *testing.B) {
+		for _, size := range []int{15, 40, 512, 1 << 10, 4 << 10, 32 << 10} {
+			name := fmt.Sprint(size)
+			if size >= 1024 {
+				name = fmt.Sprintf("%dkB", size/1024)
+			}
+			b.Run("size="+name, func(b *testing.B) {
+				for align := 0; align <= 1; align++ {
+					b.Run(fmt.Sprintf("align=%d", align), func(b *testing.B) {
+						benchmark(b, h, int64(size), int64(align))
+					})
+				}
+			})
+		}
+	}
 }
 
 func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
diff --git a/src/hash/crc32/gen_const_ppc64le.go b/src/hash/crc32/gen_const_ppc64le.go
new file mode 100644
index 0000000..bfb3b3a
--- /dev/null
+++ b/src/hash/crc32/gen_const_ppc64le.go
@@ -0,0 +1,150 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Generate the constant table associated with the poly used by the
+// vpmsumd crc32 algorithm.
+//
+// go run gen_const_ppc64le.go
+//
+// generates crc32_table_ppc64le.s
+
+// The following is derived from code written by Anton Blanchard
+// <anton at au.ibm.com> found at https://github.com/antonblanchard/crc32-vpmsum.
+// The original is dual licensed under GPL and Apache 2.  As the copyright holder
+// for the work, IBM has contributed this new work under the golang license.
+
+// This code was written in Go based on the original C implementation.
+
+// This is a tool needed to generate the appropriate constants needed for
+// the vpmsum algorithm.  It is included to generate new constant tables if
+// new polynomial values are included in the future.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+)
+
+var blocking = 32 * 1024
+
+func reflect_bits(b uint64, nr uint) uint64 {
+	var ref uint64
+
+	for bit := uint64(0); bit < uint64(nr); bit++ {
+		if (b & uint64(1)) == 1 {
+			ref |= (1 << (uint64(nr-1) - bit))
+		}
+		b = (b >> 1)
+	}
+	return ref
+}
+
+func get_remainder(poly uint64, deg uint, n uint) uint64 {
+
+	rem, _ := xnmodp(n, poly, deg)
+	return rem
+}
+
+func get_quotient(poly uint64, bits, n uint) uint64 {
+
+	_, div := xnmodp(n, poly, bits)
+	return div
+}
+
+// xnmodp returns two values, p and div:
+// p is the representation of the binary polynomial x**n mod (x ** deg + "poly")
+// That is p is the binary representation of the modulus polynomial except for its highest-order term.
+// div is the binary representation of the polynomial x**n / (x ** deg + "poly")
+func xnmodp(n uint, poly uint64, deg uint) (uint64, uint64) {
+
+	var mod, mask, high, div uint64
+
+	if n < deg {
+		div = 0
+		return poly, div
+	}
+	mask = 1<<deg - 1
+	poly &= mask
+	mod = poly
+	div = 1
+	deg--
+	n--
+	for n > deg {
+		high = (mod >> deg) & 1
+		div = (div << 1) | high
+		mod <<= 1
+		if high != 0 {
+			mod ^= poly
+		}
+		n--
+	}
+	return mod & mask, div
+}
+
+func main() {
+	w := new(bytes.Buffer)
+
+	fmt.Fprintf(w, "// autogenerated: do not edit!\n")
+	fmt.Fprintf(w, "// generated from crc32/gen_const_ppc64le.go\n")
+	fmt.Fprintln(w)
+	fmt.Fprintf(w, "#include \"textflag.h\"\n")
+
+	// These are the polynomials supported in vector now.
+	// If adding others, include the polynomial and a name
+	// to identify it.
+
+	genCrc32ConstTable(w, 0xedb88320, "IEEE")
+	genCrc32ConstTable(w, 0x82f63b78, "Cast")
+	genCrc32ConstTable(w, 0xeb31d82e, "Koop")
+	b := w.Bytes()
+
+	err := ioutil.WriteFile("crc32_table_ppc64le.s", b, 0666)
+	if err != nil {
+		fmt.Printf("can't write output: %s\n", err)
+	}
+}
+
+func genCrc32ConstTable(w *bytes.Buffer, poly uint32, polyid string) {
+
+	ref_poly := reflect_bits(uint64(poly), 32)
+	fmt.Fprintf(w, "\n\t/* Reduce %d kbits to 1024 bits */\n", blocking*8)
+	j := 0
+	for i := (blocking * 8) - 1024; i > 0; i -= 1024 {
+		a := reflect_bits(get_remainder(ref_poly, 32, uint(i)), 32) << 1
+		b := reflect_bits(get_remainder(ref_poly, 32, uint(i+64)), 32) << 1
+
+		fmt.Fprintf(w, "\t/* x^%d mod p(x)%s, x^%d mod p(x)%s */\n", uint(i+64), "", uint(i), "")
+		fmt.Fprintf(w, "DATA ·%sConst+%d(SB)/8,$0x%016x\n", polyid, j*8, b)
+		fmt.Fprintf(w, "DATA ·%sConst+%d(SB)/8,$0x%016x\n", polyid, (j+1)*8, a)
+
+		j += 2
+		fmt.Fprintf(w, "\n")
+	}
+
+	for i := (1024 * 2) - 128; i >= 0; i -= 128 {
+		a := reflect_bits(get_remainder(ref_poly, 32, uint(i+32)), 32)
+		b := reflect_bits(get_remainder(ref_poly, 32, uint(i+64)), 32)
+		c := reflect_bits(get_remainder(ref_poly, 32, uint(i+96)), 32)
+		d := reflect_bits(get_remainder(ref_poly, 32, uint(i+128)), 32)
+
+		fmt.Fprintf(w, "\t/* x^%d mod p(x)%s, x^%d mod p(x)%s, x^%d mod p(x)%s, x^%d mod p(x)%s */\n", i+128, "", i+96, "", i+64, "", i+32, "")
+		fmt.Fprintf(w, "DATA ·%sConst+%d(SB)/8,$0x%08x%08x\n", polyid, j*8, c, d)
+		fmt.Fprintf(w, "DATA ·%sConst+%d(SB)/8,$0x%08x%08x\n", polyid, (j+1)*8, a, b)
+
+		j += 2
+		fmt.Fprintf(w, "\n")
+	}
+
+	fmt.Fprintf(w, "GLOBL ·%sConst(SB),RODATA,$4336\n", polyid)
+	fmt.Fprintf(w, "\n /* Barrett constant m - (4^32)/n */\n")
+	fmt.Fprintf(w, "DATA ·%sBarConst(SB)/8,$0x%016x\n", polyid, reflect_bits(get_quotient(ref_poly, 32, 64), 33))
+	fmt.Fprintf(w, "DATA ·%sBarConst+8(SB)/8,$0x0000000000000000\n", polyid)
+	fmt.Fprintf(w, "DATA ·%sBarConst+16(SB)/8,$0x%016x\n", polyid, reflect_bits((uint64(1)<<32)|ref_poly, 33)) // reflected?
+	fmt.Fprintf(w, "DATA ·%sBarConst+24(SB)/8,$0x0000000000000000\n", polyid)
+	fmt.Fprintf(w, "GLOBL ·%sBarConst(SB),RODATA,$32\n", polyid)
+}
diff --git a/src/hash/fnv/fnv.go b/src/hash/fnv/fnv.go
index f1fbb25..3d2df73 100644
--- a/src/hash/fnv/fnv.go
+++ b/src/hash/fnv/fnv.go
@@ -13,17 +13,23 @@ import (
 )
 
 type (
-	sum32  uint32
-	sum32a uint32
-	sum64  uint64
-	sum64a uint64
+	sum32   uint32
+	sum32a  uint32
+	sum64   uint64
+	sum64a  uint64
+	sum128  [2]uint64
+	sum128a [2]uint64
 )
 
 const (
-	offset32 = 2166136261
-	offset64 = 14695981039346656037
-	prime32  = 16777619
-	prime64  = 1099511628211
+	offset32        = 2166136261
+	offset64        = 14695981039346656037
+	offset128Lower  = 0x62b821756295c58d
+	offset128Higher = 0x6c62272e07bb0142
+	prime32         = 16777619
+	prime64         = 1099511628211
+	prime128Lower   = 0x13b
+	prime128Shift   = 24
 )
 
 // New32 returns a new 32-bit FNV-1 hash.Hash.
@@ -54,10 +60,30 @@ func New64a() hash.Hash64 {
 	return &s
 }
 
-func (s *sum32) Reset()  { *s = offset32 }
-func (s *sum32a) Reset() { *s = offset32 }
-func (s *sum64) Reset()  { *s = offset64 }
-func (s *sum64a) Reset() { *s = offset64 }
+// New128 returns a new 128-bit FNV-1 hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
+func New128() hash.Hash {
+	var s sum128
+	s[0] = offset128Higher
+	s[1] = offset128Lower
+	return &s
+}
+
+// New128a returns a new 128-bit FNV-1a hash.Hash.
+// Its Sum method will lay the value out in big-endian byte order.
+func New128a() hash.Hash {
+	var s sum128a
+	s[0] = offset128Higher
+	s[1] = offset128Lower
+	return &s
+}
+
+func (s *sum32) Reset()   { *s = offset32 }
+func (s *sum32a) Reset()  { *s = offset32 }
+func (s *sum64) Reset()   { *s = offset64 }
+func (s *sum64a) Reset()  { *s = offset64 }
+func (s *sum128) Reset()  { s[0] = offset128Higher; s[1] = offset128Lower }
+func (s *sum128a) Reset() { s[0] = offset128Higher; s[1] = offset128Lower }
 
 func (s *sum32) Sum32() uint32  { return uint32(*s) }
 func (s *sum32a) Sum32() uint32 { return uint32(*s) }
@@ -104,15 +130,57 @@ func (s *sum64a) Write(data []byte) (int, error) {
 	return len(data), nil
 }
 
-func (s *sum32) Size() int  { return 4 }
-func (s *sum32a) Size() int { return 4 }
-func (s *sum64) Size() int  { return 8 }
-func (s *sum64a) Size() int { return 8 }
+func (s *sum128) Write(data []byte) (int, error) {
+	for _, c := range data {
+		// Compute the multiplication in 4 parts to simplify carrying
+		s1l := (s[1] & 0xffffffff) * prime128Lower
+		s1h := (s[1] >> 32) * prime128Lower
+		s0l := (s[0]&0xffffffff)*prime128Lower + (s[1]&0xffffffff)<<prime128Shift
+		s0h := (s[0]>>32)*prime128Lower + (s[1]>>32)<<prime128Shift
+		// Carries
+		s1h += s1l >> 32
+		s0l += s1h >> 32
+		s0h += s0l >> 32
+		// Update the values
+		s[1] = (s1l & 0xffffffff) + (s1h << 32)
+		s[0] = (s0l & 0xffffffff) + (s0h << 32)
+		s[1] ^= uint64(c)
+	}
+	return len(data), nil
+}
+
+func (s *sum128a) Write(data []byte) (int, error) {
+	for _, c := range data {
+		s[1] ^= uint64(c)
+		// Compute the multiplication in 4 parts to simplify carrying
+		s1l := (s[1] & 0xffffffff) * prime128Lower
+		s1h := (s[1] >> 32) * prime128Lower
+		s0l := (s[0]&0xffffffff)*prime128Lower + (s[1]&0xffffffff)<<prime128Shift
+		s0h := (s[0]>>32)*prime128Lower + (s[1]>>32)<<prime128Shift
+		// Carries
+		s1h += s1l >> 32
+		s0l += s1h >> 32
+		s0h += s0l >> 32
+		// Update the values
+		s[1] = (s1l & 0xffffffff) + (s1h << 32)
+		s[0] = (s0l & 0xffffffff) + (s0h << 32)
+	}
+	return len(data), nil
+}
 
-func (s *sum32) BlockSize() int  { return 1 }
-func (s *sum32a) BlockSize() int { return 1 }
-func (s *sum64) BlockSize() int  { return 1 }
-func (s *sum64a) BlockSize() int { return 1 }
+func (s *sum32) Size() int   { return 4 }
+func (s *sum32a) Size() int  { return 4 }
+func (s *sum64) Size() int   { return 8 }
+func (s *sum64a) Size() int  { return 8 }
+func (s *sum128) Size() int  { return 16 }
+func (s *sum128a) Size() int { return 16 }
+
+func (s *sum32) BlockSize() int   { return 1 }
+func (s *sum32a) BlockSize() int  { return 1 }
+func (s *sum64) BlockSize() int   { return 1 }
+func (s *sum64a) BlockSize() int  { return 1 }
+func (s *sum128) BlockSize() int  { return 1 }
+func (s *sum128a) BlockSize() int { return 1 }
 
 func (s *sum32) Sum(in []byte) []byte {
 	v := uint32(*s)
@@ -133,3 +201,17 @@ func (s *sum64a) Sum(in []byte) []byte {
 	v := uint64(*s)
 	return append(in, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
 }
+
+func (s *sum128) Sum(in []byte) []byte {
+	return append(in,
+		byte(s[0]>>56), byte(s[0]>>48), byte(s[0]>>40), byte(s[0]>>32), byte(s[0]>>24), byte(s[0]>>16), byte(s[0]>>8), byte(s[0]),
+		byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]),
+	)
+}
+
+func (s *sum128a) Sum(in []byte) []byte {
+	return append(in,
+		byte(s[0]>>56), byte(s[0]>>48), byte(s[0]>>40), byte(s[0]>>32), byte(s[0]>>24), byte(s[0]>>16), byte(s[0]>>8), byte(s[0]),
+		byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]),
+	)
+}
diff --git a/src/hash/fnv/fnv_test.go b/src/hash/fnv/fnv_test.go
index 89d39b3..7da15ba 100644
--- a/src/hash/fnv/fnv_test.go
+++ b/src/hash/fnv/fnv_test.go
@@ -44,6 +44,20 @@ var golden64a = []golden{
 	{[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc"},
 }
 
+var golden128 = []golden{
+	{[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""},
+	{[]byte{0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e}, "a"},
+	{[]byte{0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88}, "ab"},
+	{[]byte{0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b}, "abc"},
+}
+
+var golden128a = []golden{
+	{[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""},
+	{[]byte{0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64}, "a"},
+	{[]byte{0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62}, "ab"},
+	{[]byte{0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b}, "abc"},
+}
+
 func TestGolden32(t *testing.T) {
 	testGolden(t, New32(), golden32)
 }
@@ -60,6 +74,14 @@ func TestGolden64a(t *testing.T) {
 	testGolden(t, New64a(), golden64a)
 }
 
+func TestGolden128(t *testing.T) {
+	testGolden(t, New128(), golden128)
+}
+
+func TestGolden128a(t *testing.T) {
+	testGolden(t, New128a(), golden128a)
+}
+
 func testGolden(t *testing.T, hash hash.Hash, gold []golden) {
 	for _, g := range gold {
 		hash.Reset()
@@ -91,6 +113,13 @@ func TestIntegrity64(t *testing.T) {
 func TestIntegrity64a(t *testing.T) {
 	testIntegrity(t, New64a())
 }
+func TestIntegrity128(t *testing.T) {
+	testIntegrity(t, New128())
+}
+
+func TestIntegrity128a(t *testing.T) {
+	testIntegrity(t, New128a())
+}
 
 func testIntegrity(t *testing.T, h hash.Hash) {
 	data := []byte{'1', '2', 3, 4, 5}
@@ -129,6 +158,8 @@ func testIntegrity(t *testing.T, h hash.Hash) {
 		if sum64 != binary.BigEndian.Uint64(sum) {
 			t.Fatalf("Sum()=0x%x, but Sum64()=0x%x", sum, sum64)
 		}
+	case 16:
+		// There's no Sum128 function, so we don't need to test anything here.
 	}
 }
 
@@ -148,6 +179,14 @@ func BenchmarkFnv64aKB(b *testing.B) {
 	benchmarkKB(b, New64a())
 }
 
+func BenchmarkFnv128KB(b *testing.B) {
+	benchmarkKB(b, New128())
+}
+
+func BenchmarkFnv128aKB(b *testing.B) {
+	benchmarkKB(b, New128a())
+}
+
 func benchmarkKB(b *testing.B, h hash.Hash) {
 	b.SetBytes(1024)
 	data := make([]byte, 1024)
diff --git a/src/html/template/attr.go b/src/html/template/attr.go
index d65d340..7438f51 100644
--- a/src/html/template/attr.go
+++ b/src/html/template/attr.go
@@ -135,9 +135,8 @@ var attrTypeMap = map[string]contentType{
 }
 
 // attrType returns a conservative (upper-bound on authority) guess at the
-// type of the named attribute.
+// type of the lowercase named attribute.
 func attrType(name string) contentType {
-	name = strings.ToLower(name)
 	if strings.HasPrefix(name, "data-") {
 		// Strip data- so that custom attribute heuristics below are
 		// widely applied.
diff --git a/src/html/template/doc.go b/src/html/template/doc.go
index cb89812..35d171c 100644
--- a/src/html/template/doc.go
+++ b/src/html/template/doc.go
@@ -65,8 +65,10 @@ functions to each simple action pipeline, so given the excerpt
 At parse time each {{.}} is overwritten to add escaping functions as necessary.
 In this case it becomes
 
-  <a href="/search?q={{. | urlquery}}">{{. | html}}</a>
+  <a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
 
+where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping
+functions.
 
 Errors
 
diff --git a/src/html/template/error.go b/src/html/template/error.go
index cbcaf92..0e52706 100644
--- a/src/html/template/error.go
+++ b/src/html/template/error.go
@@ -183,6 +183,34 @@ const (
 	//   Look for missing semicolons inside branches, and maybe add
 	//   parentheses to make it clear which interpretation you intend.
 	ErrSlashAmbig
+
+	// ErrPredefinedEscaper: "predefined escaper ... disallowed in template"
+	// Example:
+	//   <div class={{. | html}}>Hello<div>
+	// Discussion:
+	//   Package html/template already contextually escapes all pipelines to
+	//   produce HTML output safe against code injection. Manually escaping
+	//   pipeline output using the predefined escapers "html" or "urlquery" is
+	//   unnecessary, and may affect the correctness or safety of the escaped
+	//   pipeline output in Go 1.8 and earlier.
+	//
+	//   In most cases, such as the given example, this error can be resolved by
+	//   simply removing the predefined escaper from the pipeline and letting the
+	//   contextual autoescaper handle the escaping of the pipeline. In other
+	//   instances, where the predefined escaper occurs in the middle of a
+	//   pipeline where subsequent commands expect escaped input, e.g.
+	//     {{.X | html | makeALink}}
+	//   where makeALink does
+	//     return `<a href="`+input+`">link</a>`
+	//   consider refactoring the surrounding template to make use of the
+	//   contextual autoescaper, i.e.
+	//     <a href="{{.X}}">link</a>
+	//
+	//   To ease migration to Go 1.9 and beyond, "html" and "urlquery" will
+	//   continue to be allowed as the last command in a pipeline. However, if the
+	//   pipeline occurs in an unquoted attribute value context, "html" is
+	//   disallowed. Avoid using "html" and "urlquery" entirely in new templates.
+	ErrPredefinedEscaper
 )
 
 func (e *Error) Error() string {
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 0e7d2be..92b1d08 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -44,6 +44,21 @@ func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
 	return nil
 }
 
+// evalArgs formats the list of arguments into a string. It is equivalent to
+// fmt.Sprint(args...), except that it deferences all pointers.
+func evalArgs(args ...interface{}) string {
+	// Optimization for simple common case of a single string argument.
+	if len(args) == 1 {
+		if s, ok := args[0].(string); ok {
+			return s
+		}
+	}
+	for i, arg := range args {
+		args[i] = indirectToStringerOrError(arg)
+	}
+	return fmt.Sprint(args...)
+}
+
 // funcMap maps command names to functions that render their inputs safe.
 var funcMap = template.FuncMap{
 	"_html_template_attrescaper":     attrEscaper,
@@ -60,16 +75,7 @@ var funcMap = template.FuncMap{
 	"_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",
+	"_eval_args_":                    evalArgs,
 }
 
 // escaper collects type inferences about templates and changes needed to make
@@ -140,6 +146,30 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 		return c
 	}
 	c = nudge(c)
+	// Check for disallowed use of predefined escapers in the pipeline.
+	for pos, idNode := range n.Pipe.Cmds {
+		node, ok := idNode.Args[0].(*parse.IdentifierNode)
+		if !ok {
+			// A predefined escaper "esc" will never be found as an identifier in a
+			// Chain or Field node, since:
+			// - "esc.x ..." is invalid, since predefined escapers return strings, and
+			//   strings do not have methods, keys or fields.
+			// - "... .esc" is invalid, since predefined escapers are global functions,
+			//   not methods or fields of any types.
+			// Therefore, it is safe to ignore these two node types.
+			continue
+		}
+		ident := node.Ident
+		if _, ok := predefinedEscapers[ident]; ok {
+			if pos < len(n.Pipe.Cmds)-1 ||
+				c.state == stateAttr && c.delim == delimSpaceOrTagEnd && ident == "html" {
+				return context{
+					state: stateError,
+					err:   errorf(ErrPredefinedEscaper, n, n.Line, "predefined escaper %q disallowed in template", ident),
+				}
+			}
+		}
+	}
 	s := make([]string, 0, 3)
 	switch c.state {
 	case stateError:
@@ -204,75 +234,98 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 	return c
 }
 
-// allIdents returns the names of the identifiers under the Ident field of the node,
-// which might be a singleton (Identifier) or a slice (Field or Chain).
-func allIdents(node parse.Node) []string {
-	switch node := node.(type) {
-	case *parse.IdentifierNode:
-		return []string{node.Ident}
-	case *parse.FieldNode:
-		return node.Ident
-	case *parse.ChainNode:
-		return node.Field
-	}
-	return nil
-}
-
-// ensurePipelineContains ensures that the pipeline has commands with
-// the identifiers in s in order.
-// If the pipeline already has some of the sanitizers, do not interfere.
-// For example, if p is (.X | html) and s is ["escapeJSVal", "html"] then it
-// has one matching, "html", and one to insert, "escapeJSVal", to produce
-// (.X | escapeJSVal | html).
+// ensurePipelineContains ensures that the pipeline ends with the commands with
+// the identifiers in s in order. If the pipeline ends with a predefined escaper
+// (i.e. "html" or "urlquery"), merge it with the identifiers in s.
 func ensurePipelineContains(p *parse.PipeNode, s []string) {
 	if len(s) == 0 {
+		// Do not rewrite pipeline if we have no escapers to insert.
 		return
 	}
-	n := len(p.Cmds)
-	// Find the identifiers at the end of the command chain.
-	idents := p.Cmds
-	for i := n - 1; i >= 0; i-- {
-		if cmd := p.Cmds[i]; len(cmd.Args) != 0 {
-			if _, ok := cmd.Args[0].(*parse.IdentifierNode); ok {
-				continue
-			}
-		}
-		idents = p.Cmds[i+1:]
-	}
-	dups := 0
-	for _, idNode := range idents {
-		for _, ident := range allIdents(idNode.Args[0]) {
-			if escFnsEq(s[dups], ident) {
-				dups++
-				if dups == len(s) {
-					return
+	// Precondition: p.Cmds contains at most one predefined escaper and the
+	// escaper will be present at p.Cmds[len(p.Cmds)-1]. This precondition is
+	// always true because of the checks in escapeAction.
+	pipelineLen := len(p.Cmds)
+	if pipelineLen > 0 {
+		lastCmd := p.Cmds[pipelineLen-1]
+		if idNode, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok {
+			if esc := idNode.Ident; predefinedEscapers[esc] {
+				// Pipeline ends with a predefined escaper.
+				if len(p.Cmds) == 1 && len(lastCmd.Args) > 1 {
+					// Special case: pipeline is of the form {{ esc arg1 arg2 ... argN }},
+					// where esc is the predefined escaper, and arg1...argN are its arguments.
+					// Convert this into the equivalent form
+					// {{ _eval_args_ arg1 arg2 ... argN | esc }}, so that esc can be easily
+					// merged with the escapers in s.
+					lastCmd.Args[0] = parse.NewIdentifier("_eval_args_").SetTree(nil).SetPos(lastCmd.Args[0].Position())
+					p.Cmds = appendCmd(p.Cmds, newIdentCmd(esc, p.Position()))
+					pipelineLen++
 				}
-			}
-		}
-	}
-	newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)
-	copy(newCmds, p.Cmds)
-	// Merge existing identifier commands with the sanitizers needed.
-	for _, idNode := range idents {
-		pos := idNode.Args[0].Position()
-		for _, ident := range allIdents(idNode.Args[0]) {
-			i := indexOfStr(ident, s, escFnsEq)
-			if i != -1 {
-				for _, name := range s[:i] {
-					newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+				// If any of the commands in s that we are about to insert is equivalent
+				// to the predefined escaper, use the predefined escaper instead.
+				dup := false
+				for i, escaper := range s {
+					if escFnsEq(esc, escaper) {
+						s[i] = idNode.Ident
+						dup = true
+					}
+				}
+				if dup {
+					// The predefined escaper will already be inserted along with the
+					// escapers in s, so do not copy it to the rewritten pipeline.
+					pipelineLen--
 				}
-				s = s[i+1:]
 			}
 		}
-		newCmds = appendCmd(newCmds, idNode)
 	}
-	// Create any remaining sanitizers.
+	// Rewrite the pipeline, creating the escapers in s at the end of the pipeline.
+	newCmds := make([]*parse.CommandNode, pipelineLen, pipelineLen+len(s))
+	copy(newCmds, p.Cmds)
 	for _, name := range s {
 		newCmds = appendCmd(newCmds, newIdentCmd(name, p.Position()))
 	}
 	p.Cmds = newCmds
 }
 
+// predefinedEscapers contains template predefined escapers that are equivalent
+// to some contextual escapers. Keep in sync with equivEscapers.
+var predefinedEscapers = map[string]bool{
+	"html":     true,
+	"urlquery": true,
+}
+
+// equivEscapers matches contextual escapers to equivalent predefined
+// template escapers.
+var equivEscapers = map[string]string{
+	// The following pairs of HTML escapers provide equivalent security
+	// guarantees, since they all escape '\000', '\'', '"', '&', '<', and '>'.
+	"_html_template_attrescaper":   "html",
+	"_html_template_htmlescaper":   "html",
+	"_html_template_rcdataescaper": "html",
+	// These two URL escapers produce URLs safe for embedding in a URL query by
+	// percent-encoding all the reserved characters specified in RFC 3986 Section
+	// 2.2
+	"_html_template_urlescaper": "urlquery",
+	// These two functions are not actually equivalent; urlquery is stricter as it
+	// escapes reserved characters (e.g. '#'), while _html_template_urlnormalizer
+	// does not. It is therefore only safe to replace _html_template_urlnormalizer
+	// with urlquery (this happens in ensurePipelineContains), but not the otherI've
+	// way around. We keep this entry around to preserve the behavior of templates
+	// written before Go 1.9, which might depend on this substitution taking place.
+	"_html_template_urlnormalizer": "urlquery",
+}
+
+// escFnsEq reports whether the two escaping functions are equivalent.
+func escFnsEq(a, b string) bool {
+	if e := equivEscapers[a]; e != "" {
+		a = e
+	}
+	if e := equivEscapers[b]; e != "" {
+		b = e
+	}
+	return a == b
+}
+
 // redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
 // for all x.
 var redundantFuncs = map[string]map[string]bool{
@@ -318,17 +371,6 @@ func indexOfStr(s string, strs []string, eq func(a, b string) bool) int {
 	return -1
 }
 
-// escFnsEq reports whether the two escaping functions are equivalent.
-func escFnsEq(a, b string) bool {
-	if e := equivEscapers[a]; e != "" {
-		a = e
-	}
-	if e := equivEscapers[b]; e != "" {
-		b = e
-	}
-	return a == b
-}
-
 // newIdentCmd produces a command containing a single identifier node.
 func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {
 	return &parse.CommandNode{
@@ -624,7 +666,7 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context {
 				// the entire comment is considered to be a
 				// LineTerminator for purposes of parsing by
 				// the syntactic grammar."
-				if bytes.IndexAny(s[written:i1], "\n\r\u2028\u2029") != -1 {
+				if bytes.ContainsAny(s[written:i1], "\n\r\u2028\u2029") {
 					b.WriteByte('\n')
 				} else {
 					b.WriteByte(' ')
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index f6ace49..d61683b 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -359,7 +359,7 @@ func TestEscape(t *testing.T) {
 		{
 			"styleStrEncodedProtocolEncoded",
 			`<a style="background: '{{"javascript\\3a alert(1337)"}}'">`,
-			// The CSS string 'javascript\\3a alert(1337)' does not contains a colon.
+			// The CSS string 'javascript\\3a alert(1337)' does not contain a colon.
 			`<a style="background: 'javascript\\3a alert\28 1337\29 '">`,
 		},
 		{
@@ -685,6 +685,40 @@ func TestEscape(t *testing.T) {
 	}
 }
 
+func TestEscapeMap(t *testing.T) {
+	data := map[string]string{
+		"html":     `<h1>Hi!</h1>`,
+		"urlquery": `http://www.foo.com/index.html?title=main`,
+	}
+	for _, test := range [...]struct {
+		desc, input, output string
+	}{
+		// covering issue 20323
+		{
+			"field with predefined escaper name 1",
+			`{{.html | print}}`,
+			`<h1>Hi!</h1>`,
+		},
+		// covering issue 20323
+		{
+			"field with predefined escaper name 2",
+			`{{.urlquery | print}}`,
+			`http://www.foo.com/index.html?title=main`,
+		},
+	} {
+		tmpl := Must(New("").Parse(test.input))
+		b := new(bytes.Buffer)
+		if err := tmpl.Execute(b, data); err != nil {
+			t.Errorf("%s: template execution failed: %s", test.desc, err)
+			continue
+		}
+		if w, g := test.output, b.String(); w != g {
+			t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.desc, w, g)
+			continue
+		}
+	}
+}
+
 func TestEscapeSet(t *testing.T) {
 	type dataItem struct {
 		Children []*dataItem
@@ -970,8 +1004,33 @@ func TestErrors(t *testing.T) {
 			`<a=foo>`,
 			`: expected space, attr name, or end of tag, but got "=foo>"`,
 		},
+		{
+			`Hello, {{. | urlquery | print}}!`,
+			// urlquery is disallowed if it is not the last command in the pipeline.
+			`predefined escaper "urlquery" disallowed in template`,
+		},
+		{
+			`Hello, {{. | html | print}}!`,
+			// html is disallowed if it is not the last command in the pipeline.
+			`predefined escaper "html" disallowed in template`,
+		},
+		{
+			`Hello, {{html . | print}}!`,
+			// A direct call to html is disallowed if it is not the last command in the pipeline.
+			`predefined escaper "html" disallowed in template`,
+		},
+		{
+			`<div class={{. | html}}>Hello<div>`,
+			// html is disallowed in a pipeline that is in an unquoted attribute context,
+			// even if it is the last command in the pipeline.
+			`predefined escaper "html" disallowed in template`,
+		},
+		{
+			`Hello, {{. | urlquery | html}}!`,
+			// html is allowed since it is the last command in the pipeline, but urlquery is not.
+			`predefined escaper "urlquery" disallowed in template`,
+		},
 	}
-
 	for _, test := range tests {
 		buf := new(bytes.Buffer)
 		tmpl, err := New("z").Parse(test.input)
@@ -1396,6 +1455,16 @@ func TestEscapeText(t *testing.T) {
 			`<script type="text/template">`,
 			context{state: stateText},
 		},
+		// covering issue 19968
+		{
+			`<script type="TEXT/JAVASCRIPT">`,
+			context{state: stateJS, element: elementScript},
+		},
+		// covering issue 19965
+		{
+			`<script TYPE="text/template">`,
+			context{state: stateText},
+		},
 		{
 			`<script type="notjs">`,
 			context{state: stateText},
@@ -1529,24 +1598,24 @@ func TestEnsurePipelineContains(t *testing.T) {
 			[]string{"html"},
 		},
 		{
-			"{{.X | html}}",
-			".X | html | urlquery",
-			[]string{"urlquery"},
+			"{{html .X}}",
+			"_eval_args_ .X | html | urlquery",
+			[]string{"html", "urlquery"},
 		},
 		{
-			"{{.X | html | urlquery}}",
-			".X | html | urlquery",
-			[]string{"urlquery"},
+			"{{html .X .Y .Z}}",
+			"_eval_args_ .X .Y .Z | html | urlquery",
+			[]string{"html", "urlquery"},
 		},
 		{
-			"{{.X | html | urlquery}}",
-			".X | html | urlquery",
-			[]string{"html", "urlquery"},
+			"{{.X | print}}",
+			".X | print | urlquery",
+			[]string{"urlquery"},
 		},
 		{
-			"{{.X | html | urlquery}}",
-			".X | html | urlquery",
-			[]string{"html"},
+			"{{.X | print | urlquery}}",
+			".X | print | urlquery",
+			[]string{"urlquery"},
 		},
 		{
 			"{{.X | urlquery}}",
@@ -1554,36 +1623,63 @@ func TestEnsurePipelineContains(t *testing.T) {
 			[]string{"html", "urlquery"},
 		},
 		{
-			"{{.X | html | print}}",
-			".X | urlquery | html | print",
+			"{{.X | print 2 | .f 3}}",
+			".X | print 2 | .f 3 | urlquery | html",
 			[]string{"urlquery", "html"},
 		},
 		{
-			"{{($).X | html | print}}",
-			"($).X | urlquery | html | print",
+			// covering issue 10801
+			"{{.X | println.x }}",
+			".X | println.x | urlquery | html",
 			[]string{"urlquery", "html"},
 		},
 		{
-			"{{.X | print 2 | .f 3}}",
-			".X | print 2 | .f 3 | urlquery | html",
+			// covering issue 10801
+			"{{.X | (print 12 | println).x }}",
+			".X | (print 12 | println).x | urlquery | html",
 			[]string{"urlquery", "html"},
 		},
+		// The following test cases ensure that the merging of internal escapers
+		// with the predefined "html" and "urlquery" escapers is correct.
 		{
-			"{{.X | html | print 2 | .f 3}}",
-			".X | urlquery | html | print 2 | .f 3",
-			[]string{"urlquery", "html"},
+			"{{.X | urlquery}}",
+			".X | _html_template_urlfilter | urlquery",
+			[]string{"_html_template_urlfilter", "_html_template_urlnormalizer"},
 		},
 		{
-			// covering issue 10801
-			"{{.X | js.x }}",
-			".X | js.x | urlquery | html",
-			[]string{"urlquery", "html"},
+			"{{.X | urlquery}}",
+			".X | urlquery | _html_template_urlfilter | _html_template_cssescaper",
+			[]string{"_html_template_urlfilter", "_html_template_cssescaper"},
 		},
 		{
-			// covering issue 10801
-			"{{.X | (print 12 | js).x }}",
-			".X | (print 12 | js).x | urlquery | html",
-			[]string{"urlquery", "html"},
+			"{{.X | urlquery}}",
+			".X | urlquery",
+			[]string{"_html_template_urlnormalizer"},
+		},
+		{
+			"{{.X | urlquery}}",
+			".X | urlquery",
+			[]string{"_html_template_urlescaper"},
+		},
+		{
+			"{{.X | html}}",
+			".X | html",
+			[]string{"_html_template_htmlescaper"},
+		},
+		{
+			"{{.X | html}}",
+			".X | html",
+			[]string{"_html_template_rcdataescaper"},
+		},
+		{
+			"{{.X | html}}",
+			".X | html | html",
+			[]string{"_html_template_htmlescaper", "_html_template_attrescaper"},
+		},
+		{
+			"{{.X | html}}",
+			".X | html | html",
+			[]string{"_html_template_rcdataescaper", "_html_template_attrescaper"},
 		},
 	}
 	for i, test := range tests {
@@ -1606,10 +1702,8 @@ func TestEscapeMalformedPipelines(t *testing.T) {
 	tests := []string{
 		"{{ 0 | $ }}",
 		"{{ 0 | $ | urlquery }}",
-		"{{ 0 | $ | urlquery | html }}",
 		"{{ 0 | (nil) }}",
 		"{{ 0 | (nil) | html }}",
-		"{{ 0 | (nil) | html | urlquery }}",
 	}
 	for _, test := range tests {
 		var b bytes.Buffer
diff --git a/src/html/template/js.go b/src/html/template/js.go
index 6434fa3..239395f 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -372,7 +372,7 @@ func isJSType(mimeType string) bool {
 	//   https://tools.ietf.org/html/rfc7231#section-3.1.1
 	//   https://tools.ietf.org/html/rfc4329#section-3
 	//   https://www.ietf.org/rfc/rfc4627.txt
-
+	mimeType = strings.ToLower(mimeType)
 	// discard parameters
 	if i := strings.Index(mimeType, ";"); i >= 0 {
 		mimeType = mimeType[:i]
diff --git a/src/html/template/template.go b/src/html/template/template.go
index b313a6b..246ef04 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -112,7 +112,8 @@ func (t *Template) escape() error {
 // If an error occurs executing the template or writing its output,
 // execution stops, but partial results may already have been written to
 // the output writer.
-// A template may be executed safely in parallel.
+// A template may be executed safely in parallel, although if parallel
+// executions share a Writer the output may be interleaved.
 func (t *Template) Execute(wr io.Writer, data interface{}) error {
 	if err := t.escape(); err != nil {
 		return err
@@ -125,7 +126,8 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
 // If an error occurs executing the template or writing its output,
 // execution stops, but partial results may already have been written to
 // the output writer.
-// A template may be executed safely in parallel.
+// A template may be executed safely in parallel, although if parallel
+// executions share a Writer the output may be interleaved.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
 	tmpl, err := t.lookupAndEscapeTemplate(name)
 	if err != nil {
@@ -325,6 +327,7 @@ func (t *Template) Name() string {
 type FuncMap map[string]interface{}
 
 // Funcs adds the elements of the argument map to the template's function map.
+// It must be called before the template is parsed.
 // It panics if a value in the map is not a function with appropriate return
 // type. However, it is legal to overwrite elements of the map. The return
 // value is the template, so calls can be chained.
diff --git a/src/html/template/transition.go b/src/html/template/transition.go
index 4a4716d..df7ac22 100644
--- a/src/html/template/transition.go
+++ b/src/html/template/transition.go
@@ -106,7 +106,7 @@ func tTag(c context, s []byte) (context, int) {
 		}, len(s)
 	}
 
-	attrName := string(s[i:j])
+	attrName := strings.ToLower(string(s[i:j]))
 	if c.element == elementScript && attrName == "type" {
 		attr = attrScriptType
 	} else {
@@ -246,7 +246,7 @@ func tAttr(c context, s []byte) (context, int) {
 
 // tURL is the context transition function for the URL state.
 func tURL(c context, s []byte) (context, int) {
-	if bytes.IndexAny(s, "#?") >= 0 {
+	if bytes.ContainsAny(s, "#?") {
 		c.urlPart = urlPartQueryOrFrag
 	} else if len(s) != eatWhiteSpace(s, 0) && c.urlPart == urlPartNone {
 		// HTML5 uses "Valid URL potentially surrounded by spaces" for
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 18d1a56..fd24430 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -61,8 +61,58 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
 	//	G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
 	//	B = Y' + 1.77200*(Cb-128)
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-
-	yy1 := int32(y) * 0x010100 // Convert 0x12 to 0x121200.
+	//
+	// Those formulae use non-integer multiplication factors. When computing,
+	// integer math is generally faster than floating point math. We multiply
+	// all of those factors by 1<<16 and round to the nearest integer:
+	//	 91881 = roundToNearestInteger(1.40200 * 65536).
+	//	 22554 = roundToNearestInteger(0.34414 * 65536).
+	//	 46802 = roundToNearestInteger(0.71414 * 65536).
+	//	116130 = roundToNearestInteger(1.77200 * 65536).
+	//
+	// Adding a rounding adjustment in the range [0, 1<<16-1] and then shifting
+	// right by 16 gives us an integer math version of the original formulae.
+	//	R = (65536*Y' +  91881 *(Cr-128)                  + adjustment) >> 16
+	//	G = (65536*Y' -  22554 *(Cb-128) - 46802*(Cr-128) + adjustment) >> 16
+	//	B = (65536*Y' + 116130 *(Cb-128)                  + adjustment) >> 16
+	// A constant rounding adjustment of 1<<15, one half of 1<<16, would mean
+	// round-to-nearest when dividing by 65536 (shifting right by 16).
+	// Similarly, a constant rounding adjustment of 0 would mean round-down.
+	//
+	// Defining YY1 = 65536*Y' + adjustment simplifies the formulae and
+	// requires fewer CPU operations:
+	//	R = (YY1 +  91881 *(Cr-128)                 ) >> 16
+	//	G = (YY1 -  22554 *(Cb-128) - 46802*(Cr-128)) >> 16
+	//	B = (YY1 + 116130 *(Cb-128)                 ) >> 16
+	//
+	// The inputs (y, cb, cr) are 8 bit color, ranging in [0x00, 0xff]. In this
+	// function, the output is also 8 bit color, but in the related YCbCr.RGBA
+	// method, below, the output is 16 bit color, ranging in [0x0000, 0xffff].
+	// Outputting 16 bit color simply requires changing the 16 to 8 in the "R =
+	// etc >> 16" equation, and likewise for G and B.
+	//
+	// As mentioned above, a constant rounding adjustment of 1<<15 is a natural
+	// choice, but there is an additional constraint: if c0 := YCbCr{Y: y, Cb:
+	// 0x80, Cr: 0x80} and c1 := Gray{Y: y} then c0.RGBA() should equal
+	// c1.RGBA(). Specifically, if y == 0 then "R = etc >> 8" should yield
+	// 0x0000 and if y == 0xff then "R = etc >> 8" should yield 0xffff. If we
+	// used a constant rounding adjustment of 1<<15, then it would yield 0x0080
+	// and 0xff80 respectively.
+	//
+	// Note that when cb == 0x80 and cr == 0x80 then the formulae collapse to:
+	//	R = YY1 >> n
+	//	G = YY1 >> n
+	//	B = YY1 >> n
+	// where n is 16 for this function (8 bit color output) and 8 for the
+	// YCbCr.RGBA method (16 bit color output).
+	//
+	// The solution is to make the rounding adjustment non-constant, and equal
+	// to 257*Y', which ranges over [0, 1<<16-1] as Y' ranges over [0, 255].
+	// YY1 is then defined as:
+	//	YY1 = 65536*Y' + 257*Y'
+	// or equivalently:
+	//	YY1 = Y' * 0x10101
+	yy1 := int32(y) * 0x10101
 	cb1 := int32(cb) - 128
 	cr1 := int32(cr) - 128
 
@@ -136,7 +186,7 @@ func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
 	//	0x7e18 0x808d 0x7db9
 	//	0x7e7e 0x8080 0x7d7d
 
-	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
+	yy1 := int32(c.Y) * 0x10101
 	cb1 := int32(c.Cb) - 128
 	cr1 := int32(c.Cr) - 128
 
@@ -196,7 +246,7 @@ type NYCbCrA struct {
 
 func (c NYCbCrA) RGBA() (uint32, uint32, uint32, uint32) {
 	// The first part of this method is the same as YCbCr.RGBA.
-	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
+	yy1 := int32(c.Y) * 0x10101
 	cb1 := int32(c.Cb) - 128
 	cr1 := int32(c.Cr) - 128
 
diff --git a/src/image/geom.go b/src/image/geom.go
index e1cd4dc..ed7dde2 100644
--- a/src/image/geom.go
+++ b/src/image/geom.go
@@ -161,7 +161,11 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle {
 	if r.Max.Y > s.Max.Y {
 		r.Max.Y = s.Max.Y
 	}
-	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+	// Letting r0 and s0 be the values of r and s at the time that the method
+	// is called, this next line is equivalent to:
+	//
+	// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
+	if r.Empty() {
 		return ZR
 	}
 	return r
diff --git a/src/image/geom_test.go b/src/image/geom_test.go
index 6e9c6a1..9fede02 100644
--- a/src/image/geom_test.go
+++ b/src/image/geom_test.go
@@ -28,6 +28,7 @@ func TestRectangle(t *testing.T) {
 
 	rects := []Rectangle{
 		Rect(0, 0, 10, 10),
+		Rect(10, 0, 20, 10),
 		Rect(1, 2, 3, 4),
 		Rect(4, 6, 10, 10),
 		Rect(2, 3, 12, 5),
@@ -62,9 +63,9 @@ func TestRectangle(t *testing.T) {
 			if err := in(a, s); err != nil {
 				t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err)
 			}
-			if a.Empty() == r.Overlaps(s) {
-				t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t",
-					r, s, a, a.Empty(), r.Overlaps(s))
+			if isZero, overlaps := a == (Rectangle{}), r.Overlaps(s); isZero == overlaps {
+				t.Errorf("Intersect: r=%s, s=%s, a=%s: isZero=%t same as overlaps=%t",
+					r, s, a, isZero, overlaps)
 			}
 			largerThanA := [4]Rectangle{a, a, a, a}
 			largerThanA[0].Min.X--
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index e611128..b1335e6 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -231,8 +231,8 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				}
 				return errNotEnough
 			}
-			// Both lzwr and br should be exhausted. Reading from them should
-			// yield (0, io.EOF).
+			// In theory, both lzwr and br should be exhausted. Reading from them
+			// should yield (0, io.EOF).
 			//
 			// The spec (Appendix F - Compression), says that "An End of
 			// Information code... must be the last code output by the encoder
@@ -248,11 +248,21 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				}
 				return errTooMuch
 			}
-			if n, err := br.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+
+			// In practice, some GIFs have an extra byte in the data sub-block
+			// stream, which we ignore. See https://golang.org/issue/16146.
+			for nExtraBytes := 0; ; {
+				n, err := br.Read(d.tmp[:2])
+				nExtraBytes += n
+				if nExtraBytes > 1 {
+					return errTooMuch
+				}
+				if err == io.EOF {
+					break
+				}
 				if err != nil {
 					return fmt.Errorf("gif: reading image data: %v", err)
 				}
-				return errTooMuch
 			}
 
 			// Check that the color indexes are inside the palette.
@@ -410,14 +420,29 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
 	height := int(d.tmp[6]) + int(d.tmp[7])<<8
 	d.imageFields = d.tmp[8]
 
-	// The GIF89a spec, Section 20 (Image Descriptor) says:
-	// "Each image must fit within the boundaries of the Logical
-	// Screen, as defined in the Logical Screen Descriptor."
-	bounds := image.Rect(left, top, left+width, top+height)
-	if bounds != bounds.Intersect(image.Rect(0, 0, d.width, d.height)) {
+	// The GIF89a spec, Section 20 (Image Descriptor) says: "Each image must
+	// fit within the boundaries of the Logical Screen, as defined in the
+	// Logical Screen Descriptor."
+	//
+	// This is conceptually similar to testing
+	//	frameBounds := image.Rect(left, top, left+width, top+height)
+	//	imageBounds := image.Rect(0, 0, d.width, d.height)
+	//	if !frameBounds.In(imageBounds) { etc }
+	// but the semantics of the Go image.Rectangle type is that r.In(s) is true
+	// whenever r is an empty rectangle, even if r.Min.X > s.Max.X. Here, we
+	// want something stricter.
+	//
+	// Note that, by construction, left >= 0 && top >= 0, so we only have to
+	// explicitly compare frameBounds.Max (left+width, top+height) against
+	// imageBounds.Max (d.width, d.height) and not frameBounds.Min (left, top)
+	// against imageBounds.Min (0, 0).
+	if left+width > d.width || top+height > d.height {
 		return nil, errors.New("gif: frame bounds larger than image bounds")
 	}
-	return image.NewPaletted(bounds, nil), nil
+	return image.NewPaletted(image.Rectangle{
+		Min: image.Point{left, top},
+		Max: image.Point{left + width, top + height},
+	}, nil), nil
 }
 
 func (d *decoder) readBlock() (int, error) {
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index 1267ba0..51c64b7 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -37,16 +37,35 @@ func lzwEncode(in []byte) []byte {
 }
 
 func TestDecode(t *testing.T) {
+	// extra contains superfluous bytes to inject into the GIF, either at the end
+	// of an existing data sub-block (past the LZW End of Information code) or in
+	// a separate data sub-block. The 0x02 values are arbitrary.
+	const extra = "\x02\x02\x02\x02"
+
 	testCases := []struct {
-		nPix    int  // The number of pixels in the image data.
-		extra   bool // Whether to write an extra block after the LZW-encoded data.
-		wantErr error
+		nPix int // The number of pixels in the image data.
+		// If non-zero, write this many extra bytes inside the data sub-block
+		// containing the LZW end code.
+		extraExisting int
+		// If non-zero, write an extra block of this many bytes.
+		extraSeparate int
+		wantErr       error
 	}{
-		{0, false, errNotEnough},
-		{1, false, errNotEnough},
-		{2, false, nil},
-		{2, true, errTooMuch},
-		{3, false, errTooMuch},
+		{0, 0, 0, errNotEnough},
+		{1, 0, 0, errNotEnough},
+		{2, 0, 0, nil},
+		// An extra data sub-block after the compressed section with 1 byte which we
+		// silently skip.
+		{2, 0, 1, nil},
+		// An extra data sub-block after the compressed section with 2 bytes. In
+		// this case we complain that there is too much data.
+		{2, 0, 2, errTooMuch},
+		// Too much pixel data.
+		{3, 0, 0, errTooMuch},
+		// An extra byte after LZW data, but inside the same data sub-block.
+		{2, 1, 0, nil},
+		// Two extra bytes after LZW data, but inside the same data sub-block.
+		{2, 2, 0, nil},
 	}
 	for _, tc := range testCases {
 		b := &bytes.Buffer{}
@@ -59,22 +78,35 @@ func TestDecode(t *testing.T) {
 		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 		if tc.nPix > 0 {
 			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))
+			if len(enc)+tc.extraExisting > 0xff {
+				t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d: compressed length %d is too large",
+					tc.nPix, tc.extraExisting, tc.extraSeparate, len(enc))
 				continue
 			}
-			b.WriteByte(byte(len(enc)))
+
+			// Write the size of the data sub-block containing the LZW data.
+			b.WriteByte(byte(len(enc) + tc.extraExisting))
+
+			// Write the LZW data.
 			b.Write(enc)
+
+			// Write extra bytes inside the same data sub-block where LZW data
+			// ended. Each arbitrarily 0x02.
+			b.WriteString(extra[:tc.extraExisting])
 		}
-		if tc.extra {
-			b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
+
+		if tc.extraSeparate > 0 {
+			// Data sub-block size. This indicates how many extra bytes follow.
+			b.WriteByte(byte(tc.extraSeparate))
+			b.WriteString(extra[:tc.extraSeparate])
 		}
 		b.WriteByte(0x00) // An empty block signifies the end of the image data.
 		b.WriteString(trailerStr)
 
 		got, err := Decode(b)
 		if err != tc.wantErr {
-			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
+			t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot  %v\nwant %v",
+				tc.nPix, tc.extraExisting, tc.extraSeparate, err, tc.wantErr)
 		}
 
 		if tc.wantErr != nil {
@@ -90,7 +122,8 @@ func TestDecode(t *testing.T) {
 			},
 		}
 		if !reflect.DeepEqual(got, want) {
-			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, got, want)
+			t.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot  %v\nwant %v",
+				tc.nPix, tc.extraExisting, tc.extraSeparate, got, want)
 		}
 	}
 }
diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go
index 1918196..e68f7a4 100644
--- a/src/image/gif/writer.go
+++ b/src/image/gif/writer.go
@@ -132,7 +132,12 @@ func (e *encoder) writeHeader() {
 		e.buf[1] = e.g.BackgroundIndex
 		e.buf[2] = 0x00 // Pixel Aspect Ratio.
 		e.write(e.buf[:3])
-		e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+		var err error
+		e.globalCT, err = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+		if err != nil && e.err == nil {
+			e.err = err
+			return
+		}
 		e.write(e.globalColorTable[:e.globalCT])
 	} else {
 		// All frames have a local color table, so a global color table
@@ -149,8 +154,9 @@ func (e *encoder) writeHeader() {
 		e.buf[1] = 0xff // Application Label.
 		e.buf[2] = 0x0b // Block Size.
 		e.write(e.buf[:3])
-		_, e.err = io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
-		if e.err != nil {
+		_, err := io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
+		if err != nil && e.err == nil {
+			e.err = err
 			return
 		}
 		e.buf[0] = 0x03 // Block Size.
@@ -161,11 +167,18 @@ func (e *encoder) writeHeader() {
 	}
 }
 
-func encodeColorTable(dst []byte, p color.Palette, size int) int {
+func encodeColorTable(dst []byte, p color.Palette, size int) (int, error) {
+	if uint(size) >= uint(len(log2Lookup)) {
+		return 0, errors.New("gif: cannot encode color table with more than 256 entries")
+	}
 	n := log2Lookup[size]
 	for i := 0; i < n; i++ {
 		if i < len(p) {
-			r, g, b, _ := p[i].RGBA()
+			c := p[i]
+			if c == nil {
+				return 0, errors.New("gif: cannot encode color table with nil entries")
+			}
+			r, g, b, _ := c.RGBA()
 			dst[3*i+0] = uint8(r >> 8)
 			dst[3*i+1] = uint8(g >> 8)
 			dst[3*i+2] = uint8(b >> 8)
@@ -176,7 +189,7 @@ func encodeColorTable(dst []byte, p color.Palette, size int) int {
 			dst[3*i+2] = 0x00
 		}
 	}
-	return 3 * n
+	return 3 * n, nil
 }
 
 func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
@@ -201,6 +214,10 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 
 	transparentIndex := -1
 	for i, c := range pm.Palette {
+		if c == nil {
+			e.err = errors.New("gif: cannot encode color table with nil entries")
+			return
+		}
 		if _, _, _, a := c.RGBA(); a == 0 {
 			transparentIndex = i
 			break
@@ -235,8 +252,12 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 	e.write(e.buf[:9])
 
 	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
-	ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
-	if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
+	if ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize); err != nil {
+		if e.err == nil {
+			e.err = err
+		}
+		return
+	} else if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
 		// Use a local color table.
 		e.writeByte(fColorTable | uint8(paddedSize))
 		e.write(e.localColorTable[:ct])
diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go
index 775ccea..bbedbfc 100644
--- a/src/image/gif/writer_test.go
+++ b/src/image/gif/writer_test.go
@@ -438,6 +438,39 @@ func TestEncodePalettes(t *testing.T) {
 	}
 }
 
+func TestEncodeBadPalettes(t *testing.T) {
+	const w, h = 5, 5
+	for _, n := range []int{256, 257} {
+		for _, nilColors := range []bool{false, true} {
+			pal := make(color.Palette, n)
+			if !nilColors {
+				for i := range pal {
+					pal[i] = color.Black
+				}
+			}
+
+			err := EncodeAll(ioutil.Discard, &GIF{
+				Image: []*image.Paletted{
+					image.NewPaletted(image.Rect(0, 0, w, h), pal),
+				},
+				Delay:    make([]int, 1),
+				Disposal: make([]byte, 1),
+				Config: image.Config{
+					ColorModel: pal,
+					Width:      w,
+					Height:     h,
+				},
+			})
+
+			got := err != nil
+			want := n > 256 || nilColors
+			if got != want {
+				t.Errorf("n=%d, nilColors=%t: err != nil: got %t, want %t", n, nilColors, got, want)
+			}
+		}
+	}
+}
+
 func BenchmarkEncode(b *testing.B) {
 	b.StopTimer()
 
diff --git a/src/image/image_test.go b/src/image/image_test.go
index 799c1a7..08ba61e 100644
--- a/src/image/image_test.go
+++ b/src/image/image_test.go
@@ -16,7 +16,7 @@ type image interface {
 	SubImage(Rectangle) Image
 }
 
-func cmp(t *testing.T, cm color.Model, c0, c1 color.Color) bool {
+func cmp(cm color.Model, c0, c1 color.Color) bool {
 	r0, g0, b0, a0 := cm.Convert(c0).RGBA()
 	r1, g1, b1, a1 := cm.Convert(c1).RGBA()
 	return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
@@ -42,12 +42,12 @@ func TestImage(t *testing.T) {
 			t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds())
 			continue
 		}
-		if !cmp(t, m.ColorModel(), Transparent, m.At(6, 3)) {
+		if !cmp(m.ColorModel(), Transparent, m.At(6, 3)) {
 			t.Errorf("%T: at (6, 3), want a zero color, got %v", m, m.At(6, 3))
 			continue
 		}
 		m.Set(6, 3, Opaque)
-		if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+		if !cmp(m.ColorModel(), Opaque, m.At(6, 3)) {
 			t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
 			continue
 		}
@@ -60,16 +60,16 @@ func TestImage(t *testing.T) {
 			t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
 			continue
 		}
-		if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+		if !cmp(m.ColorModel(), Opaque, m.At(6, 3)) {
 			t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
 			continue
 		}
-		if !cmp(t, m.ColorModel(), Transparent, m.At(3, 3)) {
+		if !cmp(m.ColorModel(), Transparent, m.At(3, 3)) {
 			t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", m, m.At(3, 3))
 			continue
 		}
 		m.Set(3, 3, Opaque)
-		if !cmp(t, m.ColorModel(), Opaque, m.At(3, 3)) {
+		if !cmp(m.ColorModel(), Opaque, m.At(3, 3)) {
 			t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
 			continue
 		}
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
index 6792b28..8b2c427 100644
--- a/src/image/internal/imageutil/gen.go
+++ b/src/image/internal/imageutil/gen.go
@@ -95,7 +95,7 @@ const sratioCase = `
 			%s
 
 				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
-				yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x10101
 				cb1 := int32(src.Cb[ci]) - 128
 				cr1 := int32(src.Cr[ci]) - 128
 
diff --git a/src/image/internal/imageutil/impl.go b/src/image/internal/imageutil/impl.go
index 3696b08..cfd5047 100644
--- a/src/image/internal/imageutil/impl.go
+++ b/src/image/internal/imageutil/impl.go
@@ -44,7 +44,7 @@ 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]) * 0x010100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x10101
 				cb1 := int32(src.Cb[ci]) - 128
 				cr1 := int32(src.Cr[ci]) - 128
 
@@ -101,7 +101,7 @@ 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]) * 0x010100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x10101
 				cb1 := int32(src.Cb[ci]) - 128
 				cr1 := int32(src.Cr[ci]) - 128
 
@@ -158,7 +158,7 @@ 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]) * 0x010100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x10101
 				cb1 := int32(src.Cb[ci]) - 128
 				cr1 := int32(src.Cr[ci]) - 128
 
@@ -214,7 +214,7 @@ 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]) * 0x010100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x10101
 				cb1 := int32(src.Cb[ci]) - 128
 				cr1 := int32(src.Cr[ci]) - 128
 
diff --git a/src/image/jpeg/huffman.go b/src/image/jpeg/huffman.go
index 4f8fe8e..95aaf71 100644
--- a/src/image/jpeg/huffman.go
+++ b/src/image/jpeg/huffman.go
@@ -101,7 +101,8 @@ func (d *decoder) processDHT(n int) error {
 			return FormatError("bad Tc value")
 		}
 		th := d.tmp[0] & 0x0f
-		if th > maxTh || !d.progressive && th > 1 {
+		// The baseline th <= 1 restriction is specified in table B.5.
+		if th > maxTh || (d.baseline && th > 1) {
 			return FormatError("bad Th value")
 		}
 		h := &d.huff[tc][th]
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index c583421..a915e96 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -48,7 +48,7 @@ const (
 )
 
 const (
-	sof0Marker = 0xc0 // Start Of Frame (Baseline).
+	sof0Marker = 0xc0 // Start Of Frame (Baseline Sequential).
 	sof1Marker = 0xc1 // Start Of Frame (Extended Sequential).
 	sof2Marker = 0xc2 // Start Of Frame (Progressive).
 	dhtMarker  = 0xc4 // Define Huffman Table.
@@ -126,9 +126,17 @@ type decoder struct {
 	blackPix    []byte
 	blackStride int
 
-	ri                  int // Restart Interval.
-	nComp               int
-	progressive         bool
+	ri    int // Restart Interval.
+	nComp int
+
+	// As per section 4.5, there are four modes of operation (selected by the
+	// SOF? markers): sequential DCT, progressive DCT, lossless and
+	// hierarchical, although this implementation does not support the latter
+	// two non-DCT modes. Sequential DCT is further split into baseline and
+	// extended, as per section 4.11.
+	baseline    bool
+	progressive bool
+
 	jfif                bool
 	adobeTransformValid bool
 	adobeTransform      uint8
@@ -596,6 +604,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 
 		switch marker {
 		case sof0Marker, sof1Marker, sof2Marker:
+			d.baseline = marker == sof0Marker
 			d.progressive = marker == sof2Marker
 			err = d.processSOF(n)
 			if configOnly && d.jfif {
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index e1104d2..712e7e3 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -92,12 +92,13 @@ func (d *decoder) processSOS(n int) error {
 		}
 		totalHV += d.comp[compIndex].h * d.comp[compIndex].v
 
+		// The baseline t <= 1 restriction is specified in table B.3.
 		scan[i].td = d.tmp[2+2*i] >> 4
-		if scan[i].td > maxTh {
+		if t := scan[i].td; t > maxTh || (d.baseline && t > 1) {
 			return FormatError("bad Td value")
 		}
 		scan[i].ta = d.tmp[2+2*i] & 0x0f
-		if scan[i].ta > maxTh {
+		if t := scan[i].ta; t > maxTh || (d.baseline && t > 1) {
 			return FormatError("bad Ta value")
 		}
 	}
@@ -122,7 +123,8 @@ func (d *decoder) processSOS(n int) error {
 	// by the second-least significant bit, followed by the least
 	// significant bit.
 	//
-	// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
+	// For sequential JPEGs, these parameters are hard-coded to 0/63/0/0, as
+	// per table B.3.
 	zigStart, zigEnd, ah, al := int32(0), int32(blockSize-1), uint32(0), uint32(0)
 	if d.progressive {
 		zigStart = int32(d.tmp[1+2*nComp])
@@ -177,7 +179,7 @@ func (d *decoder) processSOS(n int) error {
 					// 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.
 					//
-					// For a baseline 32x16 pixel image, the Y blocks visiting order is:
+					// For a sequential 32x16 pixel image, the Y blocks visiting order is:
 					//	0 1 4 5
 					//	2 3 6 7
 					//
diff --git a/src/image/jpeg/writer.go b/src/image/jpeg/writer.go
index 91bbde3..a600499 100644
--- a/src/image/jpeg/writer.go
+++ b/src/image/jpeg/writer.go
@@ -311,7 +311,7 @@ func (e *encoder) writeDQT() {
 	}
 }
 
-// writeSOF0 writes the Start Of Frame (Baseline) marker.
+// writeSOF0 writes the Start Of Frame (Baseline Sequential) marker.
 func (e *encoder) writeSOF0(size image.Point, nComponent int) {
 	markerlen := 8 + 3*nComponent
 	e.writeMarkerHeader(sof0Marker, markerlen)
@@ -441,6 +441,30 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
 	}
 }
 
+// yCbCrToYCbCr is a specialized version of toYCbCr for image.YCbCr images.
+func yCbCrToYCbCr(m *image.YCbCr, p image.Point, yBlock, cbBlock, crBlock *block) {
+	b := m.Bounds()
+	xmax := b.Max.X - 1
+	ymax := b.Max.Y - 1
+	for j := 0; j < 8; j++ {
+		sy := p.Y + j
+		if sy > ymax {
+			sy = ymax
+		}
+		for i := 0; i < 8; i++ {
+			sx := p.X + i
+			if sx > xmax {
+				sx = xmax
+			}
+			yi := m.YOffset(sx, sy)
+			ci := m.COffset(sx, sy)
+			yBlock[8*j+i] = int32(m.Y[yi])
+			cbBlock[8*j+i] = int32(m.Cb[ci])
+			crBlock[8*j+i] = int32(m.Cr[ci])
+		}
+	}
+}
+
 // scale scales the 16x16 region represented by the 4 src blocks to the 8x8
 // dst block.
 func scale(dst *block, src *[4]block) {
@@ -510,6 +534,7 @@ func (e *encoder) writeSOS(m image.Image) {
 		}
 	default:
 		rgba, _ := m.(*image.RGBA)
+		ycbcr, _ := m.(*image.YCbCr)
 		for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
 			for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
 				for i := 0; i < 4; i++ {
@@ -518,6 +543,8 @@ func (e *encoder) writeSOS(m image.Image) {
 					p := image.Pt(x+xOff, y+yOff)
 					if rgba != nil {
 						rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i])
+					} else if ycbcr != nil {
+						yCbCrToYCbCr(ycbcr, p, &b, &cb[i], &cr[i])
 					} else {
 						toYCbCr(m, p, &b, &cb[i], &cr[i])
 					}
diff --git a/src/image/jpeg/writer_test.go b/src/image/jpeg/writer_test.go
index 3df3cfc..a6c0561 100644
--- a/src/image/jpeg/writer_test.go
+++ b/src/image/jpeg/writer_test.go
@@ -208,7 +208,41 @@ func averageDelta(m0, m1 image.Image) int64 {
 	return sum / n
 }
 
-func BenchmarkEncode(b *testing.B) {
+func TestEncodeYCbCr(t *testing.T) {
+	bo := image.Rect(0, 0, 640, 480)
+	imgRGBA := image.NewRGBA(bo)
+	// Must use 444 subsampling to avoid lossy RGBA to YCbCr conversion.
+	imgYCbCr := image.NewYCbCr(bo, image.YCbCrSubsampleRatio444)
+	rnd := rand.New(rand.NewSource(123))
+	// Create identical rgba and ycbcr images.
+	for y := bo.Min.Y; y < bo.Max.Y; y++ {
+		for x := bo.Min.X; x < bo.Max.X; x++ {
+			col := color.RGBA{
+				uint8(rnd.Intn(256)),
+				uint8(rnd.Intn(256)),
+				uint8(rnd.Intn(256)),
+				255,
+			}
+			imgRGBA.SetRGBA(x, y, col)
+			yo := imgYCbCr.YOffset(x, y)
+			co := imgYCbCr.COffset(x, y)
+			cy, ccr, ccb := color.RGBToYCbCr(col.R, col.G, col.B)
+			imgYCbCr.Y[yo] = cy
+			imgYCbCr.Cb[co] = ccr
+			imgYCbCr.Cr[co] = ccb
+		}
+	}
+
+	// Now check that both images are identical after an encode.
+	var bufRGBA, bufYCbCr bytes.Buffer
+	Encode(&bufRGBA, imgRGBA, nil)
+	Encode(&bufYCbCr, imgYCbCr, nil)
+	if !bytes.Equal(bufRGBA.Bytes(), bufYCbCr.Bytes()) {
+		t.Errorf("RGBA and YCbCr encoded bytes differ")
+	}
+}
+
+func BenchmarkEncodeRGBA(b *testing.B) {
 	b.StopTimer()
 	img := image.NewRGBA(image.Rect(0, 0, 640, 480))
 	bo := img.Bounds()
@@ -230,3 +264,25 @@ func BenchmarkEncode(b *testing.B) {
 		Encode(ioutil.Discard, img, options)
 	}
 }
+
+func BenchmarkEncodeYCbCr(b *testing.B) {
+	b.StopTimer()
+	img := image.NewYCbCr(image.Rect(0, 0, 640, 480), image.YCbCrSubsampleRatio420)
+	bo := img.Bounds()
+	rnd := rand.New(rand.NewSource(123))
+	for y := bo.Min.Y; y < bo.Max.Y; y++ {
+		for x := bo.Min.X; x < bo.Max.X; x++ {
+			cy := img.YOffset(x, y)
+			ci := img.COffset(x, y)
+			img.Y[cy] = uint8(rnd.Intn(256))
+			img.Cb[ci] = uint8(rnd.Intn(256))
+			img.Cr[ci] = uint8(rnd.Intn(256))
+		}
+	}
+	b.SetBytes(640 * 480 * 3)
+	b.StartTimer()
+	options := &Options{Quality: 90}
+	for i := 0; i < b.N; i++ {
+		Encode(ioutil.Discard, img, options)
+	}
+}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 8299df5..4f043a0 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -613,12 +613,19 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 			}
 		case cbG8:
 			if d.useTransparent {
-				// Match error from Go 1.7 and earlier.
-				// Go 1.9 will decode this properly.
-				return nil, chunkOrderError
+				ty := d.transparent[1]
+				for x := 0; x < width; x++ {
+					ycol := cdat[x]
+					acol := uint8(0xff)
+					if ycol == ty {
+						acol = 0x00
+					}
+					nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, acol})
+				}
+			} else {
+				copy(gray.Pix[pixOffset:], cdat)
+				pixOffset += gray.Stride
 			}
-			copy(gray.Pix[pixOffset:], cdat)
-			pixOffset += gray.Stride
 		case cbGA8:
 			for x := 0; x < width; x++ {
 				ycol := cdat[2*x+0]
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index 503b5dc..cabf533 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -588,6 +588,67 @@ func TestUnknownChunkLengthUnderflow(t *testing.T) {
 	}
 }
 
+func TestGray8Transparent(t *testing.T) {
+	// These bytes come from https://github.com/golang/go/issues/19553
+	m, err := Decode(bytes.NewReader([]byte{
+		0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+		0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88,
+		0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00,
+		0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00,
+		0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac,
+		0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11,
+		0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63,
+		0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05,
+		0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b,
+		0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31,
+		0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1,
+		0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f,
+		0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+	}))
+	if err != nil {
+		t.Fatalf("Decode: %v", err)
+	}
+
+	const hex = "0123456789abcdef"
+	var got []byte
+	bounds := m.Bounds()
+	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+		for x := bounds.Min.X; x < bounds.Max.X; x++ {
+			if r, _, _, a := m.At(x, y).RGBA(); a != 0 {
+				got = append(got,
+					hex[0x0f&(r>>12)],
+					hex[0x0f&(r>>8)],
+					' ',
+				)
+			} else {
+				got = append(got,
+					'.',
+					'.',
+					' ',
+				)
+			}
+		}
+		got = append(got, '\n')
+	}
+
+	const want = "" +
+		".. .. .. ce bd bd bd bd bd bd bd bd bd bd e6 \n" +
+		".. .. .. 7b 84 94 94 94 94 94 94 94 94 6b bd \n" +
+		".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
+		".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
+		".. .. .. 7b d6 .. .. .. .. .. .. .. .. 8c bd \n" +
+		"e6 bd bd 7b a5 bd bd f7 .. .. .. .. .. 8c bd \n" +
+		"bd 6b 94 94 94 94 5a ef .. .. .. .. .. 8c bd \n" +
+		"bd 8c .. .. .. .. 63 ad ad ad ad ad ad 73 bd \n" +
+		"bd 8c .. .. .. .. 63 9c 9c 9c 9c 9c 9c 9c de \n" +
+		"bd 6b 94 94 94 94 5a ef .. .. .. .. .. .. .. \n" +
+		"e6 b5 b5 b5 b5 b5 b5 f7 .. .. .. .. .. .. .. \n"
+
+	if string(got) != want {
+		t.Errorf("got:\n%swant:\n%s", got, want)
+	}
+}
+
 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
 	b.StopTimer()
 	data, err := ioutil.ReadFile(filename)
@@ -629,13 +690,3 @@ func BenchmarkDecodeRGB(b *testing.B) {
 func BenchmarkDecodeInterlacing(b *testing.B) {
 	benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4)
 }
-
-func TestIssue19553(t *testing.T) {
-	var buf = []byte{
-		0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88, 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac, 0x34, 0x98 [...]
-	}
-	_, err := Decode(bytes.NewReader(buf))
-	if err != chunkOrderError {
-		t.Errorf("Decode: expected chunkOrderError for transparent gray8, got %v", err)
-	}
-}
diff --git a/src/image/png/writer.go b/src/image/png/writer.go
index dd87d81..49f1ad2 100644
--- a/src/image/png/writer.go
+++ b/src/image/png/writer.go
@@ -17,17 +17,37 @@ import (
 // Encoder configures encoding PNG images.
 type Encoder struct {
 	CompressionLevel CompressionLevel
+
+	// BufferPool optionally specifies a buffer pool to get temporary
+	// EncoderBuffers when encoding an image.
+	BufferPool EncoderBufferPool
+}
+
+// EncoderBufferPool is an interface for getting and returning temporary
+// instances of the EncoderBuffer struct. This can be used to reuse buffers
+// when encoding multiple images.
+type EncoderBufferPool interface {
+	Get() *EncoderBuffer
+	Put(*EncoderBuffer)
 }
 
+// EncoderBuffer holds the buffers used for encoding PNG images.
+type EncoderBuffer encoder
+
 type encoder struct {
-	enc    *Encoder
-	w      io.Writer
-	m      image.Image
-	cb     int
-	err    error
-	header [8]byte
-	footer [4]byte
-	tmp    [4 * 256]byte
+	enc     *Encoder
+	w       io.Writer
+	m       image.Image
+	cb      int
+	err     error
+	header  [8]byte
+	footer  [4]byte
+	tmp     [4 * 256]byte
+	cr      [nFilter][]uint8
+	pr      []uint8
+	zw      *zlib.Writer
+	zwLevel int
+	bw      *bufio.Writer
 }
 
 type CompressionLevel int
@@ -273,12 +293,24 @@ func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
 	return filter
 }
 
-func writeImage(w io.Writer, m image.Image, cb int, level int) error {
-	zw, err := zlib.NewWriterLevel(w, level)
-	if err != nil {
-		return err
+func zeroMemory(v []uint8) {
+	for i := range v {
+		v[i] = 0
+	}
+}
+
+func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) error {
+	if e.zw == nil || e.zwLevel != level {
+		zw, err := zlib.NewWriterLevel(w, level)
+		if err != nil {
+			return err
+		}
+		e.zw = zw
+		e.zwLevel = level
+	} else {
+		e.zw.Reset(w)
 	}
-	defer zw.Close()
+	defer e.zw.Close()
 
 	bpp := 0 // Bytes per pixel.
 
@@ -304,12 +336,23 @@ func writeImage(w io.Writer, m image.Image, cb int, level int) error {
 	// other PNG filter types. These buffers are allocated once and re-used for each row.
 	// The +1 is for the per-row filter type, which is at cr[*][0].
 	b := m.Bounds()
-	var cr [nFilter][]uint8
-	for i := range cr {
-		cr[i] = make([]uint8, 1+bpp*b.Dx())
-		cr[i][0] = uint8(i)
+	sz := 1 + bpp*b.Dx()
+	for i := range e.cr {
+		if cap(e.cr[i]) < sz {
+			e.cr[i] = make([]uint8, sz)
+		} else {
+			e.cr[i] = e.cr[i][:sz]
+		}
+		e.cr[i][0] = uint8(i)
+	}
+	cr := e.cr
+	if cap(e.pr) < sz {
+		e.pr = make([]uint8, sz)
+	} else {
+		e.pr = e.pr[:sz]
+		zeroMemory(e.pr)
 	}
-	pr := make([]uint8, 1+bpp*b.Dx())
+	pr := e.pr
 
 	gray, _ := m.(*image.Gray)
 	rgba, _ := m.(*image.RGBA)
@@ -429,7 +472,7 @@ func writeImage(w io.Writer, m image.Image, cb int, level int) error {
 		}
 
 		// Write the compressed bytes.
-		if _, err := zw.Write(cr[f]); err != nil {
+		if _, err := e.zw.Write(cr[f]); err != nil {
 			return err
 		}
 
@@ -444,13 +487,16 @@ func (e *encoder) writeIDATs() {
 	if e.err != nil {
 		return
 	}
-	var bw *bufio.Writer
-	bw = bufio.NewWriterSize(e, 1<<15)
-	e.err = writeImage(bw, e.m, e.cb, levelToZlib(e.enc.CompressionLevel))
+	if e.bw == nil {
+		e.bw = bufio.NewWriterSize(e, 1<<15)
+	} else {
+		e.bw.Reset(e)
+	}
+	e.err = e.writeImage(e.bw, e.m, e.cb, levelToZlib(e.enc.CompressionLevel))
 	if e.err != nil {
 		return
 	}
-	e.err = bw.Flush()
+	e.err = e.bw.Flush()
 }
 
 // This function is required because we want the zero value of
@@ -489,7 +535,19 @@ func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
 		return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10))
 	}
 
-	var e encoder
+	var e *encoder
+	if enc.BufferPool != nil {
+		buffer := enc.BufferPool.Get()
+		e = (*encoder)(buffer)
+
+	}
+	if e == nil {
+		e = &encoder{}
+	}
+	if enc.BufferPool != nil {
+		defer enc.BufferPool.Put((*EncoderBuffer)(e))
+	}
+
 	e.enc = enc
 	e.w = w
 	e.m = m
diff --git a/src/image/png/writer_test.go b/src/image/png/writer_test.go
index d67a815..b1f97b1 100644
--- a/src/image/png/writer_test.go
+++ b/src/image/png/writer_test.go
@@ -130,6 +130,31 @@ func BenchmarkEncodeGray(b *testing.B) {
 	}
 }
 
+type pool struct {
+	b *EncoderBuffer
+}
+
+func (p *pool) Get() *EncoderBuffer {
+	return p.b
+}
+
+func (p *pool) Put(b *EncoderBuffer) {
+	p.b = b
+}
+
+func BenchmarkEncodeGrayWithBufferPool(b *testing.B) {
+	b.StopTimer()
+	img := image.NewGray(image.Rect(0, 0, 640, 480))
+	e := Encoder{
+		BufferPool: &pool{},
+	}
+	b.SetBytes(640 * 480 * 1)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		e.Encode(ioutil.Discard, img)
+	}
+}
+
 func BenchmarkEncodeNRGBOpaque(b *testing.B) {
 	b.StopTimer()
 	img := image.NewNRGBA(image.Rect(0, 0, 640, 480))
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
new file mode 100644
index 0000000..2226b77
--- /dev/null
+++ b/src/internal/cpu/cpu.go
@@ -0,0 +1,32 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cpu implements processor feature detection
+// used by the Go standard libary.
+package cpu
+
+var X86 x86
+
+// The booleans in x86 contain the correspondingly named cpuid feature bit.
+// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers
+// in addition to the cpuid feature bit being set.
+// The struct is padded to avoid false sharing.
+type x86 struct {
+	_            [CacheLineSize]byte
+	HasAES       bool
+	HasAVX       bool
+	HasAVX2      bool
+	HasBMI1      bool
+	HasBMI2      bool
+	HasERMS      bool
+	HasOSXSAVE   bool
+	HasPCLMULQDQ bool
+	HasPOPCNT    bool
+	HasSSE2      bool
+	HasSSE3      bool
+	HasSSSE3     bool
+	HasSSE41     bool
+	HasSSE42     bool
+	_            [CacheLineSize]byte
+}
diff --git a/src/internal/cpu/cpu_arm.go b/src/internal/cpu/cpu_arm.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_arm.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_arm64.go b/src/internal/cpu/cpu_arm64.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips.go b/src/internal/cpu/cpu_mips.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips64.go b/src/internal/cpu/cpu_mips64.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips64le.go b/src/internal/cpu/cpu_mips64le.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips64le.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mipsle.go b/src/internal/cpu/cpu_mipsle.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mipsle.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_ppc64.go b/src/internal/cpu/cpu_ppc64.go
new file mode 100644
index 0000000..5b15150
--- /dev/null
+++ b/src/internal/cpu/cpu_ppc64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 128
diff --git a/src/internal/cpu/cpu_ppc64le.go b/src/internal/cpu/cpu_ppc64le.go
new file mode 100644
index 0000000..5b15150
--- /dev/null
+++ b/src/internal/cpu/cpu_ppc64le.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 128
diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go
new file mode 100644
index 0000000..4455809
--- /dev/null
+++ b/src/internal/cpu/cpu_s390x.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+const CacheLineSize = 256
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
new file mode 100644
index 0000000..ab9836a
--- /dev/null
+++ b/src/internal/cpu/cpu_test.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu_test
+
+import (
+	"internal/cpu"
+	"runtime"
+	"testing"
+)
+
+func TestAMD64minimalFeatures(t *testing.T) {
+	if runtime.GOARCH == "amd64" {
+		if !cpu.X86.HasSSE2 {
+			t.Fatalf("HasSSE2 expected true, got false")
+		}
+	}
+}
+
+func TestAVX2hasAVX(t *testing.T) {
+	if runtime.GOARCH == "amd64" {
+		if cpu.X86.HasAVX2 && !cpu.X86.HasAVX {
+			t.Fatalf("HasAVX expected true, got false")
+		}
+	}
+}
diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go
new file mode 100644
index 0000000..31e7084
--- /dev/null
+++ b/src/internal/cpu/cpu_x86.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+
+package cpu
+
+const CacheLineSize = 64
+
+// cpuid is implemented in cpu_x86.s.
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+
+// xgetbv with ecx = 0 is implemented in cpu_x86.s.
+func xgetbv() (eax, edx uint32)
+
+func init() {
+	maxId, _, _, _ := cpuid(0, 0)
+
+	if maxId < 1 {
+		return
+	}
+
+	_, _, ecx1, edx1 := cpuid(1, 0)
+	X86.HasSSE2 = isSet(26, edx1)
+
+	X86.HasSSE3 = isSet(0, ecx1)
+	X86.HasPCLMULQDQ = isSet(1, ecx1)
+	X86.HasSSSE3 = isSet(9, ecx1)
+	X86.HasSSE41 = isSet(19, ecx1)
+	X86.HasSSE42 = isSet(20, ecx1)
+	X86.HasPOPCNT = isSet(23, ecx1)
+	X86.HasAES = isSet(25, ecx1)
+	X86.HasOSXSAVE = isSet(27, ecx1)
+
+	osSupportsAVX := false
+	// For XGETBV, OSXSAVE bit is required and sufficient.
+	if X86.HasOSXSAVE {
+		eax, _ := xgetbv()
+		// Check if XMM and YMM registers have OS support.
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
+	}
+
+	X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
+
+	if maxId < 7 {
+		return
+	}
+
+	_, ebx7, _, _ := cpuid(7, 0)
+	X86.HasBMI1 = isSet(3, ebx7)
+	X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
+	X86.HasBMI2 = isSet(8, ebx7)
+	X86.HasERMS = isSet(9, ebx7)
+}
+
+func isSet(bitpos uint, value uint32) bool {
+	return value&(1<<bitpos) != 0
+}
diff --git a/src/internal/cpu/cpu_x86.s b/src/internal/cpu/cpu_x86.s
new file mode 100644
index 0000000..228fbcf
--- /dev/null
+++ b/src/internal/cpu/cpu_x86.s
@@ -0,0 +1,32 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32
+
+#include "textflag.h"
+
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+	MOVL eaxArg+0(FP), AX
+	MOVL ecxArg+4(FP), CX
+	CPUID
+	MOVL AX, eax+8(FP)
+	MOVL BX, ebx+12(FP)
+	MOVL CX, ecx+16(FP)
+	MOVL DX, edx+20(FP)
+	RET
+
+// func xgetbv() (eax, edx uint32)
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
+#ifdef GOOS_nacl
+	// nacl does not support XGETBV.
+	MOVL $0, eax+0(FP)
+	MOVL $0, edx+4(FP)
+#else
+	MOVL $0, CX
+	XGETBV
+	MOVL AX, eax+0(FP)
+	MOVL DX, edx+4(FP)
+#endif
+	RET
diff --git a/src/internal/poll/export_posix_test.go b/src/internal/poll/export_posix_test.go
new file mode 100644
index 0000000..73b2c11
--- /dev/null
+++ b/src/internal/poll/export_posix_test.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. 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
+
+// Export guts for testing on posix.
+// Since testing imports os and os imports internal/poll,
+// the internal/poll tests can not be in package poll.
+
+package poll
+
+func (fd *FD) EOFError(n int, err error) error {
+	return fd.eofError(n, err)
+}
diff --git a/src/internal/poll/export_test.go b/src/internal/poll/export_test.go
new file mode 100644
index 0000000..02664d9
--- /dev/null
+++ b/src/internal/poll/export_test.go
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Export guts for testing.
+// Since testing imports os and os imports internal/poll,
+// the internal/poll tests can not be in package poll.
+
+package poll
+
+var Consume = consume
+
+type FDMutex struct {
+	fdMutex
+}
+
+func (mu *FDMutex) Incref() bool {
+	return mu.incref()
+}
+
+func (mu *FDMutex) IncrefAndClose() bool {
+	return mu.increfAndClose()
+}
+
+func (mu *FDMutex) Decref() bool {
+	return mu.decref()
+}
+
+func (mu *FDMutex) RWLock(read bool) bool {
+	return mu.rwlock(read)
+}
+
+func (mu *FDMutex) RWUnlock(read bool) bool {
+	return mu.rwunlock(read)
+}
diff --git a/src/internal/poll/fd.go b/src/internal/poll/fd.go
new file mode 100644
index 0000000..f1454db
--- /dev/null
+++ b/src/internal/poll/fd.go
@@ -0,0 +1,57 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package poll supports non-blocking I/O on file descriptors with polling.
+// This supports I/O operations that block only a goroutine, not a thread.
+// This is used by the net and os packages.
+// It uses a poller built into the runtime, with support from the
+// runtime scheduler.
+package poll
+
+import "errors"
+
+// ErrNetClosing is returned when a network descriptor is used after
+// it has been closed. Keep this string consistent because of issue
+// #4373: since historically programs have not been able to detect
+// this error, they look for the string.
+var ErrNetClosing = errors.New("use of closed network connection")
+
+// ErrFileClosing is returned when a file descriptor is used after it
+// has been closed.
+var ErrFileClosing = errors.New("use of closed file")
+
+// Return the appropriate closing error based on isFile.
+func errClosing(isFile bool) error {
+	if isFile {
+		return ErrFileClosing
+	}
+	return ErrNetClosing
+}
+
+// ErrTimeout is returned for an expired deadline.
+var ErrTimeout error = &TimeoutError{}
+
+// TimeoutError is returned for an expired deadline.
+type TimeoutError struct{}
+
+// Implement the net.Error interface.
+func (e *TimeoutError) Error() string   { return "i/o timeout" }
+func (e *TimeoutError) Timeout() bool   { return true }
+func (e *TimeoutError) Temporary() bool { return true }
+
+// consume removes data from a slice of byte slices, for writev.
+func consume(v *[][]byte, n int64) {
+	for len(*v) > 0 {
+		ln0 := int64(len((*v)[0]))
+		if ln0 > n {
+			(*v)[0] = (*v)[0][n:]
+			return
+		}
+		n -= ln0
+		*v = (*v)[1:]
+	}
+}
+
+// TestHookDidWritev is a hook for testing writev.
+var TestHookDidWritev = func(wrote int) {}
diff --git a/src/internal/poll/fd_io_plan9.go b/src/internal/poll/fd_io_plan9.go
new file mode 100644
index 0000000..287d11b
--- /dev/null
+++ b/src/internal/poll/fd_io_plan9.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 poll
+
+import (
+	"runtime"
+	"sync"
+	"syscall"
+)
+
+// asyncIO implements asynchronous cancelable I/O.
+// An asyncIO represents a single asynchronous Read or Write
+// operation. The result is returned on the result channel.
+// The undergoing I/O system call can either complete or be
+// interrupted by a note.
+type asyncIO struct {
+	res chan result
+
+	// mu guards the pid field.
+	mu sync.Mutex
+
+	// pid holds the process id of
+	// the process running the IO operation.
+	pid int
+}
+
+// result is the return value of a Read or Write operation.
+type result struct {
+	n   int
+	err error
+}
+
+// newAsyncIO returns a new asyncIO that performs an I/O
+// operation by calling fn, which must do one and only one
+// interruptible system call.
+func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
+	aio := &asyncIO{
+		res: make(chan result, 0),
+	}
+	aio.mu.Lock()
+	go func() {
+		// Lock the current goroutine to its process
+		// and store the pid in io so that Cancel can
+		// interrupt it. We ignore the "hangup" signal,
+		// so the signal does not take down the entire
+		// Go runtime.
+		runtime.LockOSThread()
+		runtime_ignoreHangup()
+		aio.pid = syscall.Getpid()
+		aio.mu.Unlock()
+
+		n, err := fn(b)
+
+		aio.mu.Lock()
+		aio.pid = -1
+		runtime_unignoreHangup()
+		aio.mu.Unlock()
+
+		aio.res <- result{n, err}
+	}()
+	return aio
+}
+
+// Cancel interrupts the I/O operation, causing
+// the Wait function to return.
+func (aio *asyncIO) Cancel() {
+	aio.mu.Lock()
+	defer aio.mu.Unlock()
+	if aio.pid == -1 {
+		return
+	}
+	f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY)
+	if e != nil {
+		return
+	}
+	syscall.Write(f, []byte("hangup"))
+	syscall.Close(f)
+}
+
+// Wait for the I/O operation to complete.
+func (aio *asyncIO) Wait() (int, error) {
+	res := <-aio.res
+	return res.n, res.err
+}
+
+// The following functions, provided by the runtime, are used to
+// ignore and unignore the "hangup" signal received by the process.
+func runtime_ignoreHangup()
+func runtime_unignoreHangup()
diff --git a/src/internal/poll/fd_mutex.go b/src/internal/poll/fd_mutex.go
new file mode 100644
index 0000000..76174e5
--- /dev/null
+++ b/src/internal/poll/fd_mutex.go
@@ -0,0 +1,250 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "sync/atomic"
+
+// fdMutex is a specialized synchronization primitive that manages
+// lifetime of an fd and serializes access to Read, Write and Close
+// methods on FD.
+type fdMutex struct {
+	state uint64
+	rsema uint32
+	wsema uint32
+}
+
+// fdMutex.state is organized as follows:
+// 1 bit - whether FD is closed, if set all subsequent lock operations will fail.
+// 1 bit - lock for read operations.
+// 1 bit - lock for write operations.
+// 20 bits - total number of references (read+write+misc).
+// 20 bits - number of outstanding read waiters.
+// 20 bits - number of outstanding write waiters.
+const (
+	mutexClosed  = 1 << 0
+	mutexRLock   = 1 << 1
+	mutexWLock   = 1 << 2
+	mutexRef     = 1 << 3
+	mutexRefMask = (1<<20 - 1) << 3
+	mutexRWait   = 1 << 23
+	mutexRMask   = (1<<20 - 1) << 23
+	mutexWWait   = 1 << 43
+	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 operations must do increfAndClose/decref.
+
+// 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 {
+			return false
+		}
+		new := old + mutexRef
+		if new&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			return true
+		}
+	}
+}
+
+// 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 {
+			return false
+		}
+		// Mark as closed and acquire a reference.
+		new := (old | mutexClosed) + mutexRef
+		if new&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		// Remove all read and write waiters.
+		new &^= mutexRMask | mutexWMask
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			// Wake all read and write waiters,
+			// they will observe closed flag after wakeup.
+			for old&mutexRMask != 0 {
+				old -= mutexRWait
+				runtime_Semrelease(&mu.rsema)
+			}
+			for old&mutexWMask != 0 {
+				old -= mutexWWait
+				runtime_Semrelease(&mu.wsema)
+			}
+			return true
+		}
+	}
+}
+
+// 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 {
+			panic("inconsistent poll.fdMutex")
+		}
+		new := old - mutexRef
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			return new&(mutexClosed|mutexRefMask) == mutexClosed
+		}
+	}
+}
+
+// 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 {
+		mutexBit = mutexRLock
+		mutexWait = mutexRWait
+		mutexMask = mutexRMask
+		mutexSema = &mu.rsema
+	} else {
+		mutexBit = mutexWLock
+		mutexWait = mutexWWait
+		mutexMask = mutexWMask
+		mutexSema = &mu.wsema
+	}
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexClosed != 0 {
+			return false
+		}
+		var new uint64
+		if old&mutexBit == 0 {
+			// Lock is free, acquire it.
+			new = (old | mutexBit) + mutexRef
+			if new&mutexRefMask == 0 {
+				panic("inconsistent poll.fdMutex")
+			}
+		} else {
+			// Wait for lock.
+			new = old + mutexWait
+			if new&mutexMask == 0 {
+				panic("inconsistent poll.fdMutex")
+			}
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			if old&mutexBit == 0 {
+				return true
+			}
+			runtime_Semacquire(mutexSema)
+			// The signaller has subtracted mutexWait.
+		}
+	}
+}
+
+// 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 {
+		mutexBit = mutexRLock
+		mutexWait = mutexRWait
+		mutexMask = mutexRMask
+		mutexSema = &mu.rsema
+	} else {
+		mutexBit = mutexWLock
+		mutexWait = mutexWWait
+		mutexMask = mutexWMask
+		mutexSema = &mu.wsema
+	}
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexBit == 0 || old&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		// Drop lock, drop reference and wake read waiter if present.
+		new := (old &^ mutexBit) - mutexRef
+		if old&mutexMask != 0 {
+			new -= mutexWait
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			if old&mutexMask != 0 {
+				runtime_Semrelease(mutexSema)
+			}
+			return new&(mutexClosed|mutexRefMask) == mutexClosed
+		}
+	}
+}
+
+// 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 *FD) incref() error {
+	if !fd.fdmu.incref() {
+		return errClosing(fd.isFile)
+	}
+	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 *FD) decref() error {
+	if fd.fdmu.decref() {
+		return fd.destroy()
+	}
+	return nil
+}
+
+// readLock adds a reference to fd and locks fd for reading.
+// It returns an error when fd cannot be used for reading.
+func (fd *FD) readLock() error {
+	if !fd.fdmu.rwlock(true) {
+		return errClosing(fd.isFile)
+	}
+	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 *FD) 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 *FD) writeLock() error {
+	if !fd.fdmu.rwlock(false) {
+		return errClosing(fd.isFile)
+	}
+	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 *FD) writeUnlock() {
+	if fd.fdmu.rwunlock(false) {
+		fd.destroy()
+	}
+}
diff --git a/src/internal/poll/fd_mutex_test.go b/src/internal/poll/fd_mutex_test.go
new file mode 100644
index 0000000..bab81c6
--- /dev/null
+++ b/src/internal/poll/fd_mutex_test.go
@@ -0,0 +1,196 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll_test
+
+import (
+	. "internal/poll"
+	"math/rand"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func TestMutexLock(t *testing.T) {
+	var mu FDMutex
+
+	if !mu.Incref() {
+		t.Fatal("broken")
+	}
+	if mu.Decref() {
+		t.Fatal("broken")
+	}
+
+	if !mu.RWLock(true) {
+		t.Fatal("broken")
+	}
+	if mu.RWUnlock(true) {
+		t.Fatal("broken")
+	}
+
+	if !mu.RWLock(false) {
+		t.Fatal("broken")
+	}
+	if mu.RWUnlock(false) {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexClose(t *testing.T) {
+	var mu FDMutex
+	if !mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+
+	if mu.Incref() {
+		t.Fatal("broken")
+	}
+	if mu.RWLock(true) {
+		t.Fatal("broken")
+	}
+	if mu.RWLock(false) {
+		t.Fatal("broken")
+	}
+	if mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexCloseUnblock(t *testing.T) {
+	c := make(chan bool)
+	var mu FDMutex
+	mu.RWLock(true)
+	for i := 0; i < 4; i++ {
+		go func() {
+			if mu.RWLock(true) {
+				t.Error("broken")
+				return
+			}
+			c <- true
+		}()
+	}
+	// Concurrent goroutines must not be able to read lock the mutex.
+	time.Sleep(time.Millisecond)
+	select {
+	case <-c:
+		t.Fatal("broken")
+	default:
+	}
+	mu.IncrefAndClose() // Must unblock the readers.
+	for i := 0; i < 4; i++ {
+		select {
+		case <-c:
+		case <-time.After(10 * time.Second):
+			t.Fatal("broken")
+		}
+	}
+	if mu.Decref() {
+		t.Fatal("broken")
+	}
+	if !mu.RWUnlock(true) {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexPanic(t *testing.T) {
+	ensurePanics := func(f func()) {
+		defer func() {
+			if recover() == nil {
+				t.Fatal("does not panic")
+			}
+		}()
+		f()
+	}
+
+	var mu FDMutex
+	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) })
+
+	// ensure that it's still not broken
+	mu.Incref()
+	mu.Decref()
+	mu.RWLock(true)
+	mu.RWUnlock(true)
+	mu.RWLock(false)
+	mu.RWUnlock(false)
+}
+
+func TestMutexStress(t *testing.T) {
+	P := 8
+	N := int(1e6)
+	if testing.Short() {
+		P = 4
+		N = 1e4
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
+	done := make(chan bool)
+	var mu FDMutex
+	var readState [2]uint64
+	var writeState [2]uint64
+	for p := 0; p < P; p++ {
+		go func() {
+			r := rand.New(rand.NewSource(rand.Int63()))
+			for i := 0; i < N; i++ {
+				switch r.Intn(3) {
+				case 0:
+					if !mu.Incref() {
+						t.Error("broken")
+						return
+					}
+					if mu.Decref() {
+						t.Error("broken")
+						return
+					}
+				case 1:
+					if !mu.RWLock(true) {
+						t.Error("broken")
+						return
+					}
+					// Ensure that it provides mutual exclusion for readers.
+					if readState[0] != readState[1] {
+						t.Error("broken")
+						return
+					}
+					readState[0]++
+					readState[1]++
+					if mu.RWUnlock(true) {
+						t.Error("broken")
+						return
+					}
+				case 2:
+					if !mu.RWLock(false) {
+						t.Error("broken")
+						return
+					}
+					// Ensure that it provides mutual exclusion for writers.
+					if writeState[0] != writeState[1] {
+						t.Error("broken")
+						return
+					}
+					writeState[0]++
+					writeState[1]++
+					if mu.RWUnlock(false) {
+						t.Error("broken")
+						return
+					}
+				}
+			}
+			done <- true
+		}()
+	}
+	for p := 0; p < P; p++ {
+		<-done
+	}
+	if !mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+	if !mu.Decref() {
+		t.Fatal("broken")
+	}
+}
diff --git a/src/internal/poll/fd_plan9.go b/src/internal/poll/fd_plan9.go
new file mode 100644
index 0000000..107f454
--- /dev/null
+++ b/src/internal/poll/fd_plan9.go
@@ -0,0 +1,216 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import (
+	"errors"
+	"io"
+	"sync/atomic"
+	"time"
+)
+
+type atomicBool int32
+
+func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
+func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
+func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
+
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	Destroy func()
+
+	// deadlines
+	raio      *asyncIO
+	waio      *asyncIO
+	rtimer    *time.Timer
+	wtimer    *time.Timer
+	rtimedout atomicBool // set true when read deadline has been reached
+	wtimedout atomicBool // set true when write deadline has been reached
+
+	// Whether this is a normal file.
+	// On Plan 9 we do not use this package for ordinary files,
+	// so this is always false, but the field is present because
+	// shared code in fd_mutex.go checks it.
+	isFile bool
+}
+
+// We need this to close out a file descriptor when it is unlocked,
+// but the real implementation has to live in the net package because
+// it uses os.File's.
+func (fd *FD) destroy() error {
+	if fd.Destroy != nil {
+		fd.Destroy()
+	}
+	return nil
+}
+
+// Close handles the locking for closing an FD. The real operation
+// is in the net package.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	return nil
+}
+
+// Read implements io.Reader.
+func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
+	if fd.rtimedout.isSet() {
+		return 0, ErrTimeout
+	}
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	if len(b) == 0 {
+		return 0, nil
+	}
+	fd.raio = newAsyncIO(fn, b)
+	n, err := fd.raio.Wait()
+	fd.raio = nil
+	if isHangup(err) {
+		err = io.EOF
+	}
+	if isInterrupted(err) {
+		err = ErrTimeout
+	}
+	return n, err
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
+	if fd.wtimedout.isSet() {
+		return 0, ErrTimeout
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	fd.waio = newAsyncIO(fn, b)
+	n, err := fd.waio.Wait()
+	fd.waio = nil
+	if isInterrupted(err) {
+		err = ErrTimeout
+	}
+	return n, err
+}
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	d := t.Sub(time.Now())
+	if mode == 'r' || mode == 'r'+'w' {
+		fd.rtimedout.setFalse()
+	}
+	if mode == 'w' || mode == 'r'+'w' {
+		fd.wtimedout.setFalse()
+	}
+	if t.IsZero() || d < 0 {
+		// Stop timer
+		if mode == 'r' || mode == 'r'+'w' {
+			if fd.rtimer != nil {
+				fd.rtimer.Stop()
+			}
+			fd.rtimer = nil
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			if fd.wtimer != nil {
+				fd.wtimer.Stop()
+			}
+			fd.wtimer = nil
+		}
+	} else {
+		// Interrupt I/O operation once timer has expired
+		if mode == 'r' || mode == 'r'+'w' {
+			fd.rtimer = time.AfterFunc(d, func() {
+				fd.rtimedout.setTrue()
+				if fd.raio != nil {
+					fd.raio.Cancel()
+				}
+			})
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			fd.wtimer = time.AfterFunc(d, func() {
+				fd.wtimedout.setTrue()
+				if fd.waio != nil {
+					fd.waio.Cancel()
+				}
+			})
+		}
+	}
+	if !t.IsZero() && d < 0 {
+		// Interrupt current I/O operation
+		if mode == 'r' || mode == 'r'+'w' {
+			fd.rtimedout.setTrue()
+			if fd.raio != nil {
+				fd.raio.Cancel()
+			}
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			fd.wtimedout.setTrue()
+			if fd.waio != nil {
+				fd.waio.Cancel()
+			}
+		}
+	}
+	return nil
+}
+
+// On Plan 9 only, expose the locking for the net code.
+
+// ReadLock wraps FD.readLock.
+func (fd *FD) ReadLock() error {
+	return fd.readLock()
+}
+
+// ReadUnlock wraps FD.readUnlock.
+func (fd *FD) ReadUnlock() {
+	fd.readUnlock()
+}
+
+func isHangup(err error) bool {
+	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
+}
+
+func isInterrupted(err error) bool {
+	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return ^uintptr(0)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	return errors.New("not implemented")
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
diff --git a/src/internal/poll/fd_poll_nacl.go b/src/internal/poll/fd_poll_nacl.go
new file mode 100644
index 0000000..8fa75c5
--- /dev/null
+++ b/src/internal/poll/fd_poll_nacl.go
@@ -0,0 +1,92 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import (
+	"syscall"
+	"time"
+)
+
+type pollDesc struct {
+	fd      *FD
+	closing bool
+}
+
+func (pd *pollDesc) init(fd *FD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) close() {}
+
+func (pd *pollDesc) evict() {
+	pd.closing = true
+	if pd.fd != nil {
+		syscall.StopIO(pd.fd.Sysfd)
+	}
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return nil
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) }
+
+func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) }
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return ErrTimeout
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) }
+
+func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) }
+
+func (pd *pollDesc) waitCanceled(mode int) {}
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	d := t.UnixNano()
+	if t.IsZero() {
+		d = 0
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	switch mode {
+	case 'r':
+		syscall.SetReadDeadline(fd.Sysfd, d)
+	case 'w':
+		syscall.SetWriteDeadline(fd.Sysfd, d)
+	case 'r' + 'w':
+		syscall.SetReadDeadline(fd.Sysfd, d)
+		syscall.SetWriteDeadline(fd.Sysfd, d)
+	}
+	fd.decref()
+	return nil
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return ^uintptr(0)
+}
diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go
new file mode 100644
index 0000000..08b40c2
--- /dev/null
+++ b/src/internal/poll/fd_poll_runtime.go
@@ -0,0 +1,158 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
+
+package poll
+
+import (
+	"errors"
+	"sync"
+	"syscall"
+	"time"
+)
+
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
+func runtime_pollServerInit()
+func runtime_pollServerDescriptor() uintptr
+func runtime_pollOpen(fd uintptr) (uintptr, int)
+func runtime_pollClose(ctx uintptr)
+func runtime_pollWait(ctx uintptr, mode int) int
+func runtime_pollWaitCanceled(ctx uintptr, mode int) int
+func runtime_pollReset(ctx uintptr, mode int) int
+func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
+func runtime_pollUnblock(ctx uintptr)
+
+type pollDesc struct {
+	runtimeCtx uintptr
+}
+
+var serverInit sync.Once
+
+func (pd *pollDesc) init(fd *FD) error {
+	serverInit.Do(runtime_pollServerInit)
+	ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
+	if errno != 0 {
+		if ctx != 0 {
+			runtime_pollUnblock(ctx)
+			runtime_pollClose(ctx)
+		}
+		return syscall.Errno(errno)
+	}
+	pd.runtimeCtx = ctx
+	return nil
+}
+
+func (pd *pollDesc) close() {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollClose(pd.runtimeCtx)
+	pd.runtimeCtx = 0
+}
+
+// Evict evicts fd from the pending list, unblocking any I/O running on fd.
+func (pd *pollDesc) evict() {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollUnblock(pd.runtimeCtx)
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+	if pd.runtimeCtx == 0 {
+		return nil
+	}
+	res := runtime_pollReset(pd.runtimeCtx, mode)
+	return convertErr(res, isFile)
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error {
+	return pd.prepare('r', isFile)
+}
+
+func (pd *pollDesc) prepareWrite(isFile bool) error {
+	return pd.prepare('w', isFile)
+}
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	if pd.runtimeCtx == 0 {
+		return errors.New("waiting for unsupported file type")
+	}
+	res := runtime_pollWait(pd.runtimeCtx, mode)
+	return convertErr(res, isFile)
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error {
+	return pd.wait('r', isFile)
+}
+
+func (pd *pollDesc) waitWrite(isFile bool) error {
+	return pd.wait('w', isFile)
+}
+
+func (pd *pollDesc) waitCanceled(mode int) {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
+}
+
+func convertErr(res int, isFile bool) error {
+	switch res {
+	case 0:
+		return nil
+	case 1:
+		return errClosing(isFile)
+	case 2:
+		return ErrTimeout
+	}
+	println("unreachable: ", res)
+	panic("unreachable")
+}
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	diff := int64(time.Until(t))
+	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
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	if fd.pd.runtimeCtx == 0 {
+		return errors.New("file type does not support deadlines")
+	}
+	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
+	fd.decref()
+	return nil
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return runtime_pollServerDescriptor()
+}
diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go
new file mode 100644
index 0000000..e0e634c
--- /dev/null
+++ b/src/internal/poll/fd_posix.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package poll
+
+import (
+	"io"
+	"syscall"
+)
+
+// eofError returns io.EOF when fd is available for reading end of
+// file.
+func (fd *FD) eofError(n int, err error) error {
+	if n == 0 && err == nil && fd.ZeroReadIsEOF {
+		return io.EOF
+	}
+	return err
+}
+
+// Fchmod wraps syscall.Fchmod.
+func (fd *FD) Fchmod(mode uint32) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchmod(fd.Sysfd, mode)
+}
+
+// Fchown wraps syscall.Fchown.
+func (fd *FD) Fchown(uid, gid int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchown(fd.Sysfd, uid, gid)
+}
+
+// Ftruncate wraps syscall.Ftruncate.
+func (fd *FD) Ftruncate(size int64) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Ftruncate(fd.Sysfd, size)
+}
+
+// Fsync wraps syscall.Fsync.
+func (fd *FD) Fsync() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fsync(fd.Sysfd)
+}
diff --git a/src/internal/poll/fd_posix_test.go b/src/internal/poll/fd_posix_test.go
new file mode 100644
index 0000000..cbe015e
--- /dev/null
+++ b/src/internal/poll/fd_posix_test.go
@@ -0,0 +1,43 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package poll_test
+
+import (
+	. "internal/poll"
+	"io"
+	"testing"
+)
+
+var eofErrorTests = []struct {
+	n        int
+	err      error
+	fd       *FD
+	expected error
+}{
+	{100, nil, &FD{ZeroReadIsEOF: true}, nil},
+	{100, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{100, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
+	{0, nil, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{0, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{0, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
+
+	{100, nil, &FD{ZeroReadIsEOF: false}, nil},
+	{100, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
+	{100, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
+	{0, nil, &FD{ZeroReadIsEOF: false}, nil},
+	{0, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
+	{0, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
+}
+
+func TestEOFError(t *testing.T) {
+	for _, tt := range eofErrorTests {
+		actual := tt.fd.EOFError(tt.n, tt.err)
+		if actual != tt.expected {
+			t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.ZeroReadIsEOF, tt.expected, actual)
+		}
+	}
+}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
new file mode 100644
index 0000000..3ca6e15
--- /dev/null
+++ b/src/internal/poll/fd_unix.go
@@ -0,0 +1,450 @@
+// Copyright 2017 The Go Authors. 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 poll
+
+import (
+	"io"
+	"syscall"
+)
+
+// FD is a file descriptor. The net and os packages use this type as a
+// field of a larger type representing a network connection or OS file.
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	// System file descriptor. Immutable until Close.
+	Sysfd int
+
+	// I/O poller.
+	pd pollDesc
+
+	// Writev cache.
+	iovecs *[]syscall.Iovec
+
+	// Whether this is a streaming descriptor, as opposed to a
+	// packet-based descriptor like a UDP socket. Immutable.
+	IsStream bool
+
+	// Whether a zero byte read indicates EOF. This is false for a
+	// message based socket connection.
+	ZeroReadIsEOF bool
+
+	// Whether this is a file rather than a network socket.
+	isFile bool
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file".
+func (fd *FD) Init(net string, pollable bool) error {
+	// We don't actually care about the various network types.
+	if net == "file" {
+		fd.isFile = true
+	}
+	if !pollable {
+		return nil
+	}
+	return fd.pd.init(fd)
+}
+
+// Destroy closes the file descriptor. This is called when there are
+// no remaining references.
+func (fd *FD) destroy() error {
+	// Poller may want to unregister fd in readiness notification mechanism,
+	// so this must be executed before CloseFunc.
+	fd.pd.close()
+	err := CloseFunc(fd.Sysfd)
+	fd.Sysfd = -1
+	return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by the
+// destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	// 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
+	// fairly quickly, since all the I/O is non-blocking, and any
+	// attempts to block in the pollDesc will return errClosing(fd.isFile).
+	fd.pd.evict()
+	// The call to decref will call destroy if there are no other
+	// references.
+	return fd.decref()
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Shutdown(fd.Sysfd, how)
+}
+
+// Darwin and FreeBSD can't read or write 2GB+ files at a time,
+// even on 64-bit systems.
+// The same is true of socket implementations on many systems.
+// See golang.org/issue/7812 and golang.org/issue/16266.
+// Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned.
+const maxRW = 1 << 30
+
+// Read implements io.Reader.
+func (fd *FD) Read(p []byte) (int, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	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 which looks like
+		// io.EOF.
+		// TODO(bradfitz): make it wait for readability? (Issue 15735)
+		return 0, nil
+	}
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, err
+	}
+	if fd.IsStream && len(p) > maxRW {
+		p = p[:maxRW]
+	}
+	for {
+		n, err := syscall.Read(fd.Sysfd, p)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, err
+	}
+}
+
+// Pread wraps the pread system call.
+func (fd *FD) Pread(p []byte, off int64) (int, error) {
+	// Call incref, not readLock, because since pread specifies the
+	// offset it is independent from other reads.
+	// Similarly, using the poller doesn't make sense for pread.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	if fd.IsStream && len(p) > maxRW {
+		p = p[:maxRW]
+	}
+	n, err := syscall.Pread(fd.Sysfd, p, off)
+	if err != nil {
+		n = 0
+	}
+	fd.decref()
+	err = fd.eofError(n, err)
+	return n, err
+}
+
+// ReadFrom wraps the recvfrom network call.
+func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, nil, err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, nil, err
+	}
+	for {
+		n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, sa, err
+	}
+}
+
+// ReadMsg wraps the recvmsg network call.
+func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, 0, 0, nil, err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, 0, 0, nil, err
+	}
+	for {
+		n, oobn, flags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, 0)
+		if err != nil {
+			// TODO(dfc) should n and oobn be set to 0
+			if err == syscall.EAGAIN {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, oobn, flags, sa, err
+	}
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(p []byte) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+	var nn int
+	for {
+		max := len(p)
+		if fd.IsStream && max-nn > maxRW {
+			max = nn + maxRW
+		}
+		n, err := syscall.Write(fd.Sysfd, p[nn:max])
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if err == syscall.EAGAIN {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// Pwrite wraps the pwrite system call.
+func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
+	// Call incref, not writeLock, because since pwrite specifies the
+	// offset it is independent from other writes.
+	// Similarly, using the poller doesn't make sense for pwrite.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	var nn int
+	for {
+		max := len(p)
+		if fd.IsStream && max-nn > maxRW {
+			max = nn + maxRW
+		}
+		n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if err != nil {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// WriteTo wraps the sendto network call.
+func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+	for {
+		err := syscall.Sendto(fd.Sysfd, p, 0, sa)
+		if err == syscall.EAGAIN {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return 0, err
+		}
+		return len(p), nil
+	}
+}
+
+// WriteMsg wraps the sendmsg network call.
+func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); 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(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return n, 0, err
+		}
+		return n, len(oob), err
+	}
+}
+
+// Accept wraps the accept network call.
+func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
+	if err := fd.readLock(); err != nil {
+		return -1, nil, "", err
+	}
+	defer fd.readUnlock()
+
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return -1, nil, "", err
+	}
+	for {
+		s, rsa, errcall, err := accept(fd.Sysfd)
+		if err == nil {
+			return s, rsa, "", err
+		}
+		switch err {
+		case syscall.EAGAIN:
+			if err = fd.pd.waitRead(fd.isFile); err == nil {
+				continue
+			}
+		case syscall.ECONNABORTED:
+			// This means that a socket on the listen
+			// queue was closed before we Accept()ed it;
+			// it's a silly error, so try again.
+			continue
+		}
+		return -1, nil, errcall, err
+	}
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// ReadDirent wraps syscall.ReadDirent.
+// We treat this like an ordinary system call rather than a call
+// that tries to fill the buffer.
+func (fd *FD) ReadDirent(buf []byte) (int, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	for {
+		n, err := syscall.ReadDirent(fd.Sysfd, buf)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		// Do not call eofError; caller does not expect to see io.EOF.
+		return n, err
+	}
+}
+
+// Fchdir wraps syscall.Fchdir.
+func (fd *FD) Fchdir() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchdir(fd.Sysfd)
+}
+
+// Fstat wraps syscall.Fstat
+func (fd *FD) Fstat(s *syscall.Stat_t) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fstat(fd.Sysfd, s)
+}
+
+// On Unix variants only, expose the IO event for the net code.
+
+// WaitWrite waits until data can be read from fd.
+func (fd *FD) WaitWrite() error {
+	return fd.pd.waitWrite(fd.isFile)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	f(uintptr(fd.Sysfd))
+	return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	if err := fd.readLock(); err != nil {
+		return err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitRead(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	if err := fd.writeLock(); err != nil {
+		return err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitWrite(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go
new file mode 100644
index 0000000..9f40886
--- /dev/null
+++ b/src/internal/poll/fd_windows.go
@@ -0,0 +1,856 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import (
+	"errors"
+	"internal/race"
+	"io"
+	"runtime"
+	"sync"
+	"syscall"
+	"unicode/utf16"
+	"unicode/utf8"
+	"unsafe"
+)
+
+var (
+	initErr error
+	ioSync  uint64
+)
+
+// CancelIo Windows API cancels all outstanding IO for a particular
+// socket on current thread. To overcome that limitation, we run
+// special goroutine, locked to OS single thread, that both starts
+// and cancels IO. It means, there are 2 unavoidable thread switches
+// for every IO.
+// Some newer versions of Windows has new CancelIoEx API, that does
+// not have that limitation and can be used from any thread. This
+// package uses CancelIoEx API, if present, otherwise it fallback
+// to CancelIo.
+
+var (
+	canCancelIO                               bool // determines if CancelIoEx API is present
+	skipSyncNotif                             bool
+	hasLoadSetFileCompletionNotificationModes bool
+)
+
+func init() {
+	var d syscall.WSAData
+	e := syscall.WSAStartup(uint32(0x202), &d)
+	if e != nil {
+		initErr = e
+	}
+	canCancelIO = syscall.LoadCancelIoEx() == nil
+	hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
+	if hasLoadSetFileCompletionNotificationModes {
+		// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
+		// http://support.microsoft.com/kb/2568167
+		skipSyncNotif = true
+		protos := [2]int32{syscall.IPPROTO_TCP, 0}
+		var buf [32]syscall.WSAProtocolInfo
+		len := uint32(unsafe.Sizeof(buf))
+		n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
+		if err != nil {
+			skipSyncNotif = false
+		} else {
+			for i := int32(0); i < n; i++ {
+				if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
+					skipSyncNotif = false
+					break
+				}
+			}
+		}
+	}
+}
+
+// operation contains superset of data necessary to perform all async IO.
+type operation struct {
+	// Used by IOCP interface, it must be first field
+	// of the struct, as our code rely on it.
+	o syscall.Overlapped
+
+	// fields used by runtime.netpoll
+	runtimeCtx uintptr
+	mode       int32
+	errno      int32
+	qty        uint32
+
+	// fields used only by net package
+	fd     *FD
+	errc   chan error
+	buf    syscall.WSABuf
+	sa     syscall.Sockaddr
+	rsa    *syscall.RawSockaddrAny
+	rsan   int32
+	handle syscall.Handle
+	flags  uint32
+	bufs   []syscall.WSABuf
+}
+
+func (o *operation) InitBuf(buf []byte) {
+	o.buf.Len = uint32(len(buf))
+	o.buf.Buf = nil
+	if len(buf) != 0 {
+		o.buf.Buf = &buf[0]
+	}
+}
+
+func (o *operation) InitBufs(buf *[][]byte) {
+	if o.bufs == nil {
+		o.bufs = make([]syscall.WSABuf, 0, len(*buf))
+	} else {
+		o.bufs = o.bufs[:0]
+	}
+	for _, b := range *buf {
+		var p *byte
+		if len(b) > 0 {
+			p = &b[0]
+		}
+		o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
+	}
+}
+
+// ClearBufs clears all pointers to Buffers parameter captured
+// by InitBufs, so it can be released by garbage collector.
+func (o *operation) ClearBufs() {
+	for i := range o.bufs {
+		o.bufs[i].Buf = nil
+	}
+	o.bufs = o.bufs[:0]
+}
+
+// ioSrv executes net IO requests.
+type ioSrv struct {
+	req chan ioSrvReq
+}
+
+type ioSrvReq struct {
+	o      *operation
+	submit func(o *operation) error // if nil, cancel the operation
+}
+
+// ProcessRemoteIO will execute submit IO requests on behalf
+// of other goroutines, all on a single os thread, so it can
+// cancel them later. Results of all operations will be sent
+// back to their requesters via channel supplied in request.
+// It is used only when the CancelIoEx API is unavailable.
+func (s *ioSrv) ProcessRemoteIO() {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+	for r := range s.req {
+		if r.submit != nil {
+			r.o.errc <- r.submit(r.o)
+		} else {
+			r.o.errc <- syscall.CancelIo(r.o.fd.Sysfd)
+		}
+	}
+}
+
+// ExecIO executes a single IO operation o. It submits and cancels
+// IO in the current thread for systems where Windows CancelIoEx API
+// is available. Alternatively, it passes the request onto
+// runtime netpoll and waits for completion or cancels request.
+func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, error) {
+	if !canCancelIO {
+		onceStartServer.Do(startServer)
+	}
+
+	fd := o.fd
+	// Notify runtime netpoll about starting IO.
+	err := fd.pd.prepare(int(o.mode), fd.isFile)
+	if err != nil {
+		return 0, err
+	}
+	// Start IO.
+	if canCancelIO {
+		err = submit(o)
+	} else {
+		// Send request to a special dedicated thread,
+		// so it can stop the IO with CancelIO later.
+		s.req <- ioSrvReq{o, submit}
+		err = <-o.errc
+	}
+	switch err {
+	case nil:
+		// IO completed immediately
+		if o.fd.skipSyncNotif {
+			// No completion message will follow, so return immediately.
+			return int(o.qty), nil
+		}
+		// Need to get our completion message anyway.
+	case syscall.ERROR_IO_PENDING:
+		// IO started, and we have to wait for its completion.
+		err = nil
+	default:
+		return 0, err
+	}
+	// Wait for our request to complete.
+	err = fd.pd.wait(int(o.mode), fd.isFile)
+	if err == nil {
+		// All is good. Extract our IO results and return.
+		if o.errno != 0 {
+			err = syscall.Errno(o.errno)
+			return 0, err
+		}
+		return int(o.qty), nil
+	}
+	// IO is interrupted by "close" or "timeout"
+	netpollErr := err
+	switch netpollErr {
+	case ErrNetClosing, ErrFileClosing, ErrTimeout:
+		// will deal with those.
+	default:
+		panic("unexpected runtime.netpoll error: " + netpollErr.Error())
+	}
+	// Cancel our request.
+	if canCancelIO {
+		err := syscall.CancelIoEx(fd.Sysfd, &o.o)
+		// Assuming ERROR_NOT_FOUND is returned, if IO is completed.
+		if err != nil && err != syscall.ERROR_NOT_FOUND {
+			// TODO(brainman): maybe do something else, but panic.
+			panic(err)
+		}
+	} else {
+		s.req <- ioSrvReq{o, nil}
+		<-o.errc
+	}
+	// Wait for cancelation to complete.
+	fd.pd.waitCanceled(int(o.mode))
+	if o.errno != 0 {
+		err = syscall.Errno(o.errno)
+		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
+			err = netpollErr
+		}
+		return 0, err
+	}
+	// We issued a cancelation request. But, it seems, IO operation succeeded
+	// before the cancelation request run. We need to treat the IO operation as
+	// succeeded (the bytes are actually sent/recv from network).
+	return int(o.qty), nil
+}
+
+// Start helper goroutines.
+var rsrv, wsrv ioSrv
+var onceStartServer sync.Once
+
+func startServer() {
+	// This is called, once, when only the CancelIo API is available.
+	// Start two special goroutines, both locked to an OS thread,
+	// that start and cancel IO requests.
+	// One will process read requests, while the other will do writes.
+	rsrv.req = make(chan ioSrvReq)
+	go rsrv.ProcessRemoteIO()
+	wsrv.req = make(chan ioSrvReq)
+	go wsrv.ProcessRemoteIO()
+}
+
+// FD is a file descriptor. The net and os packages embed this type in
+// a larger type representing a network connection or OS file.
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	// System file descriptor. Immutable until Close.
+	Sysfd syscall.Handle
+
+	// Read operation.
+	rop operation
+	// Write operation.
+	wop operation
+
+	// I/O poller.
+	pd pollDesc
+
+	// Used to implement pread/pwrite.
+	l sync.Mutex
+
+	// For console I/O.
+	isConsole      bool
+	lastbits       []byte   // first few bytes of the last incomplete rune in last write
+	readuint16     []uint16 // buffer to hold uint16s obtained with ReadConsole
+	readbyte       []byte   // buffer to hold decoding of readuint16 from utf16 to utf8
+	readbyteOffset int      // readbyte[readOffset:] is yet to be consumed with file.Read
+
+	skipSyncNotif bool
+
+	// Whether this is a streaming descriptor, as opposed to a
+	// packet-based descriptor like a UDP socket.
+	IsStream bool
+
+	// Whether a zero byte read indicates EOF. This is false for a
+	// message based socket connection.
+	ZeroReadIsEOF bool
+
+	// Whether this is a normal file.
+	isFile bool
+
+	// Whether this is a directory.
+	isDir bool
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file" or "console" or "dir".
+func (fd *FD) Init(net string) (string, error) {
+	if initErr != nil {
+		return "", initErr
+	}
+
+	switch net {
+	case "file":
+		fd.isFile = true
+	case "console":
+		fd.isConsole = true
+	case "dir":
+		fd.isDir = true
+	case "tcp", "tcp4", "tcp6":
+	case "udp", "udp4", "udp6":
+	case "ip", "ip4", "ip6":
+	case "unix", "unixgram", "unixpacket":
+	default:
+		return "", errors.New("internal error: unknown network type " + net)
+	}
+
+	if err := fd.pd.init(fd); err != nil {
+		return "", err
+	}
+	if hasLoadSetFileCompletionNotificationModes {
+		// We do not use events, so we can skip them always.
+		flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
+		// It's not safe to skip completion notifications for UDP:
+		// http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
+		if skipSyncNotif && (net == "tcp" || net == "file") {
+			flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+		}
+		err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags)
+		if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
+			fd.skipSyncNotif = true
+		}
+	}
+	// Disable SIO_UDP_CONNRESET behavior.
+	// http://support.microsoft.com/kb/263823
+	switch net {
+	case "udp", "udp4", "udp6":
+		ret := uint32(0)
+		flag := uint32(0)
+		size := uint32(unsafe.Sizeof(flag))
+		err := syscall.WSAIoctl(fd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
+		if err != nil {
+			return "wsaioctl", err
+		}
+	}
+	fd.rop.mode = 'r'
+	fd.wop.mode = 'w'
+	fd.rop.fd = fd
+	fd.wop.fd = fd
+	fd.rop.runtimeCtx = fd.pd.runtimeCtx
+	fd.wop.runtimeCtx = fd.pd.runtimeCtx
+	if !canCancelIO {
+		fd.rop.errc = make(chan error)
+		fd.wop.errc = make(chan error)
+	}
+	return "", nil
+}
+
+func (fd *FD) destroy() error {
+	if fd.Sysfd == syscall.InvalidHandle {
+		return syscall.EINVAL
+	}
+	// Poller may want to unregister fd in readiness notification mechanism,
+	// so this must be executed before fd.CloseFunc.
+	fd.pd.close()
+	var err error
+	if fd.isFile || fd.isConsole {
+		err = syscall.CloseHandle(fd.Sysfd)
+	} else if fd.isDir {
+		err = syscall.FindClose(fd.Sysfd)
+	} else {
+		// The net package uses the CloseFunc variable for testing.
+		err = CloseFunc(fd.Sysfd)
+	}
+	fd.Sysfd = syscall.InvalidHandle
+	return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by
+// the destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	// unblock pending reader and writer
+	fd.pd.evict()
+	return fd.decref()
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Shutdown(fd.Sysfd, how)
+}
+
+// Read implements io.Reader.
+func (fd *FD) Read(buf []byte) (int, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+
+	var n int
+	var err error
+	if fd.isFile || fd.isDir || fd.isConsole {
+		fd.l.Lock()
+		defer fd.l.Unlock()
+		if fd.isConsole {
+			n, err = fd.readConsole(buf)
+		} else {
+			n, err = syscall.Read(fd.Sysfd, buf)
+		}
+		if err != nil {
+			n = 0
+		}
+	} else {
+		o := &fd.rop
+		o.InitBuf(buf)
+		n, err = rsrv.ExecIO(o, func(o *operation) error {
+			return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
+		})
+		if race.Enabled {
+			race.Acquire(unsafe.Pointer(&ioSync))
+		}
+	}
+	if len(buf) != 0 {
+		err = fd.eofError(n, err)
+	}
+	return n, err
+}
+
+var ReadConsole = syscall.ReadConsole // changed for testing
+
+// readConsole reads utf16 characters from console File,
+// encodes them into utf8 and stores them in buffer b.
+// It returns the number of utf8 bytes read and an error, if any.
+func (fd *FD) readConsole(b []byte) (int, error) {
+	if len(b) == 0 {
+		return 0, nil
+	}
+
+	if fd.readuint16 == nil {
+		// Note: syscall.ReadConsole fails for very large buffers.
+		// The limit is somewhere around (but not exactly) 16384.
+		// Stay well below.
+		fd.readuint16 = make([]uint16, 0, 10000)
+		fd.readbyte = make([]byte, 0, 4*cap(fd.readuint16))
+	}
+
+	for fd.readbyteOffset >= len(fd.readbyte) {
+		n := cap(fd.readuint16) - len(fd.readuint16)
+		if n > len(b) {
+			n = len(b)
+		}
+		var nw uint32
+		err := ReadConsole(fd.Sysfd, &fd.readuint16[:len(fd.readuint16)+1][len(fd.readuint16)], uint32(n), &nw, nil)
+		if err != nil {
+			return 0, err
+		}
+		uint16s := fd.readuint16[:len(fd.readuint16)+int(nw)]
+		fd.readuint16 = fd.readuint16[:0]
+		buf := fd.readbyte[:0]
+		for i := 0; i < len(uint16s); i++ {
+			r := rune(uint16s[i])
+			if utf16.IsSurrogate(r) {
+				if i+1 == len(uint16s) {
+					if nw > 0 {
+						// Save half surrogate pair for next time.
+						fd.readuint16 = fd.readuint16[:1]
+						fd.readuint16[0] = uint16(r)
+						break
+					}
+					r = utf8.RuneError
+				} else {
+					r = utf16.DecodeRune(r, rune(uint16s[i+1]))
+					if r != utf8.RuneError {
+						i++
+					}
+				}
+			}
+			n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
+			buf = buf[:len(buf)+n]
+		}
+		fd.readbyte = buf
+		fd.readbyteOffset = 0
+		if nw == 0 {
+			break
+		}
+	}
+
+	src := fd.readbyte[fd.readbyteOffset:]
+	var i int
+	for i = 0; i < len(src) && i < len(b); i++ {
+		x := src[i]
+		if x == 0x1A { // Ctrl-Z
+			if i == 0 {
+				fd.readbyteOffset++
+			}
+			break
+		}
+		b[i] = x
+	}
+	fd.readbyteOffset += i
+	return i, nil
+}
+
+// Pread emulates the Unix pread system call.
+func (fd *FD) Pread(b []byte, off int64) (int, error) {
+	// Call incref, not readLock, because since pread specifies the
+	// offset it is independent from other reads.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+	curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+	if e != nil {
+		return 0, e
+	}
+	defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+	o := syscall.Overlapped{
+		OffsetHigh: uint32(off >> 32),
+		Offset:     uint32(off),
+	}
+	var done uint32
+	e = syscall.ReadFile(fd.Sysfd, b, &done, &o)
+	if e != nil {
+		done = 0
+		if e == syscall.ERROR_HANDLE_EOF {
+			e = io.EOF
+		}
+	}
+	if len(b) != 0 {
+		e = fd.eofError(int(done), e)
+	}
+	return int(done), e
+}
+
+// ReadFrom wraps the recvfrom network call.
+func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
+	if len(buf) == 0 {
+		return 0, nil, nil
+	}
+	if err := fd.readLock(); err != nil {
+		return 0, nil, err
+	}
+	defer fd.readUnlock()
+	o := &fd.rop
+	o.InitBuf(buf)
+	n, err := rsrv.ExecIO(o, func(o *operation) error {
+		if o.rsa == nil {
+			o.rsa = new(syscall.RawSockaddrAny)
+		}
+		o.rsan = int32(unsafe.Sizeof(*o.rsa))
+		return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+	})
+	err = fd.eofError(n, err)
+	if err != nil {
+		return n, nil, err
+	}
+	sa, _ := o.rsa.Sockaddr()
+	return n, sa, nil
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(buf []byte) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+
+	var n int
+	var err error
+	if fd.isFile || fd.isDir || fd.isConsole {
+		fd.l.Lock()
+		defer fd.l.Unlock()
+		if fd.isConsole {
+			n, err = fd.writeConsole(buf)
+		} else {
+			n, err = syscall.Write(fd.Sysfd, buf)
+		}
+		if err != nil {
+			n = 0
+		}
+	} else {
+		if race.Enabled {
+			race.ReleaseMerge(unsafe.Pointer(&ioSync))
+		}
+		o := &fd.wop
+		o.InitBuf(buf)
+		n, err = wsrv.ExecIO(o, func(o *operation) error {
+			return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
+		})
+	}
+	return n, err
+}
+
+// writeConsole writes len(b) bytes to the console File.
+// It returns the number of bytes written and an error, if any.
+func (fd *FD) writeConsole(b []byte) (int, error) {
+	n := len(b)
+	runes := make([]rune, 0, 256)
+	if len(fd.lastbits) > 0 {
+		b = append(fd.lastbits, b...)
+		fd.lastbits = nil
+
+	}
+	for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
+		r, l := utf8.DecodeRune(b)
+		runes = append(runes, r)
+		b = b[l:]
+	}
+	if len(b) > 0 {
+		fd.lastbits = make([]byte, len(b))
+		copy(fd.lastbits, b)
+	}
+	// syscall.WriteConsole seems to fail, if given large buffer.
+	// So limit the buffer to 16000 characters. This number was
+	// discovered by experimenting with syscall.WriteConsole.
+	const maxWrite = 16000
+	for len(runes) > 0 {
+		m := len(runes)
+		if m > maxWrite {
+			m = maxWrite
+		}
+		chunk := runes[:m]
+		runes = runes[m:]
+		uint16s := utf16.Encode(chunk)
+		for len(uint16s) > 0 {
+			var written uint32
+			err := syscall.WriteConsole(fd.Sysfd, &uint16s[0], uint32(len(uint16s)), &written, nil)
+			if err != nil {
+				return 0, err
+			}
+			uint16s = uint16s[written:]
+		}
+	}
+	return n, nil
+}
+
+// Pwrite emulates the Unix pwrite system call.
+func (fd *FD) Pwrite(b []byte, off int64) (int, error) {
+	// Call incref, not writeLock, because since pwrite specifies the
+	// offset it is independent from other writes.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+	curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+	if e != nil {
+		return 0, e
+	}
+	defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+	o := syscall.Overlapped{
+		OffsetHigh: uint32(off >> 32),
+		Offset:     uint32(off),
+	}
+	var done uint32
+	e = syscall.WriteFile(fd.Sysfd, b, &done, &o)
+	if e != nil {
+		return 0, e
+	}
+	return int(done), nil
+}
+
+// Writev emulates the Unix writev system call.
+func (fd *FD) Writev(buf *[][]byte) (int64, error) {
+	if len(*buf) == 0 {
+		return 0, nil
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if race.Enabled {
+		race.ReleaseMerge(unsafe.Pointer(&ioSync))
+	}
+	o := &fd.wop
+	o.InitBufs(buf)
+	n, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.WSASend(o.fd.Sysfd, &o.bufs[0], uint32(len(o.bufs)), &o.qty, 0, &o.o, nil)
+	})
+	o.ClearBufs()
+	TestHookDidWritev(n)
+	consume(buf, int64(n))
+	return int64(n), err
+}
+
+// WriteTo wraps the sendto network call.
+func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+	if len(buf) == 0 {
+		return 0, nil
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	o := &fd.wop
+	o.InitBuf(buf)
+	o.sa = sa
+	n, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
+	})
+	return n, err
+}
+
+// Call ConnectEx. This doesn't need any locking, since it is only
+// called when the descriptor is first created. This is here rather
+// than in the net package so that it can use fd.wop.
+func (fd *FD) ConnectEx(ra syscall.Sockaddr) error {
+	o := &fd.wop
+	o.sa = ra
+	_, err := wsrv.ExecIO(o, func(o *operation) error {
+		return ConnectExFunc(o.fd.Sysfd, o.sa, nil, 0, nil, &o.o)
+	})
+	return err
+}
+
+func (fd *FD) acceptOne(s syscall.Handle, rawsa []syscall.RawSockaddrAny, o *operation) (string, error) {
+	// Submit accept request.
+	o.handle = s
+	o.rsan = int32(unsafe.Sizeof(rawsa[0]))
+	_, err := rsrv.ExecIO(o, func(o *operation) error {
+		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 {
+		CloseFunc(s)
+		return "acceptex", err
+	}
+
+	// Inherit properties of the listening socket.
+	err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.Sysfd)), int32(unsafe.Sizeof(fd.Sysfd)))
+	if err != nil {
+		CloseFunc(s)
+		return "setsockopt", err
+	}
+
+	return "", nil
+}
+
+// Accept handles accepting a socket. The sysSocket parameter is used
+// to allocate the net socket.
+func (fd *FD) Accept(sysSocket func() (syscall.Handle, error)) (syscall.Handle, []syscall.RawSockaddrAny, uint32, string, error) {
+	if err := fd.readLock(); err != nil {
+		return syscall.InvalidHandle, nil, 0, "", err
+	}
+	defer fd.readUnlock()
+
+	o := &fd.rop
+	var rawsa [2]syscall.RawSockaddrAny
+	for {
+		s, err := sysSocket()
+		if err != nil {
+			return syscall.InvalidHandle, nil, 0, "", err
+		}
+
+		errcall, err := fd.acceptOne(s, rawsa[:], o)
+		if err == nil {
+			return s, rawsa[:], uint32(o.rsan), "", nil
+		}
+
+		// Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is
+		// returned here. These happen if connection reset is received
+		// before AcceptEx could complete. These errors relate to new
+		// connection, not to AcceptEx, so ignore broken connection and
+		// try AcceptEx again for more connections.
+		errno, ok := err.(syscall.Errno)
+		if !ok {
+			return syscall.InvalidHandle, nil, 0, errcall, err
+		}
+		switch errno {
+		case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET:
+			// ignore these and try again
+		default:
+			return syscall.InvalidHandle, nil, 0, errcall, err
+		}
+	}
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+
+	return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// FindNextFile wraps syscall.FindNextFile.
+func (fd *FD) FindNextFile(data *syscall.Win32finddata) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.FindNextFile(fd.Sysfd, data)
+}
+
+// Fchdir wraps syscall.Fchdir.
+func (fd *FD) Fchdir() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchdir(fd.Sysfd)
+}
+
+// GetFileType wraps syscall.GetFileType.
+func (fd *FD) GetFileType() (uint32, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.GetFileType(fd.Sysfd)
+}
+
+// GetFileInformationByHandle wraps GetFileInformationByHandle.
+func (fd *FD) GetFileInformationByHandle(data *syscall.ByHandleFileInformation) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.GetFileInformationByHandle(fd.Sysfd, data)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	f(uintptr(fd.Sysfd))
+	return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
diff --git a/src/internal/poll/hook_cloexec.go b/src/internal/poll/hook_cloexec.go
new file mode 100644
index 0000000..73df6ed
--- /dev/null
+++ b/src/internal/poll/hook_cloexec.go
@@ -0,0 +1,12 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd linux
+
+package poll
+
+import "syscall"
+
+// Accept4Func is used to hook the accept4 call.
+var Accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
diff --git a/src/internal/poll/hook_unix.go b/src/internal/poll/hook_unix.go
new file mode 100644
index 0000000..85e102d
--- /dev/null
+++ b/src/internal/poll/hook_unix.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. 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 poll
+
+import "syscall"
+
+// CloseFunc is used to hook the close call.
+var CloseFunc func(int) error = syscall.Close
+
+// AcceptFunc is used to hook the accept call.
+var AcceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept
diff --git a/src/internal/poll/hook_windows.go b/src/internal/poll/hook_windows.go
new file mode 100644
index 0000000..0bd950e
--- /dev/null
+++ b/src/internal/poll/hook_windows.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// CloseFunc is used to hook the close call.
+var CloseFunc func(syscall.Handle) error = syscall.Closesocket
+
+// AcceptFunc is used to hook the accept call.
+var AcceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
+
+// ConnectExFunc is used to hook the ConnectEx call.
+var ConnectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go
new file mode 100644
index 0000000..980a75a
--- /dev/null
+++ b/src/internal/poll/sendfile_bsd.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. 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
+
+package poll
+
+import "syscall"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// SendFile wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		pos1 := pos
+		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+		if n > 0 {
+			pos += int64(n)
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
+				continue
+			}
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go
new file mode 100644
index 0000000..52955a1
--- /dev/null
+++ b/src/internal/poll/sendfile_linux.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// SendFile wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		n, err1 := syscall.Sendfile(dst, src, nil, n)
+		if n > 0 {
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
+				continue
+			}
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_solaris.go b/src/internal/poll/sendfile_solaris.go
new file mode 100644
index 0000000..2ce5323
--- /dev/null
+++ b/src/internal/poll/sendfile_solaris.go
@@ -0,0 +1,66 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// Not strictly needed, but very helpful for debugging, see issue #10221.
+//go:cgo_import_dynamic _ _ "libsendfile.so"
+//go:cgo_import_dynamic _ _ "libsocket.so"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// SendFile wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		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)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
+				continue
+			}
+		}
+		if err1 == syscall.EINTR {
+			continue
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go
new file mode 100644
index 0000000..c1a2d6d
--- /dev/null
+++ b/src/internal/poll/sendfile_windows.go
@@ -0,0 +1,23 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// SendFile wraps the TransmitFile call.
+func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+
+	o := &fd.wop
+	o.qty = uint32(n)
+	o.handle = src
+	done, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+	})
+	return int64(done), err
+}
diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go
new file mode 100644
index 0000000..0d5c8bd
--- /dev/null
+++ b/src/internal/poll/sock_cloexec.go
@@ -0,0 +1,50 @@
+// Copyright 2013 The Go 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 sysSocket and accept for platforms that
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build dragonfly freebsd linux
+
+package poll
+
+import "syscall"
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(s int) (int, syscall.Sockaddr, string, error) {
+	ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+	// On Linux the accept4 system call was introduced in 2.6.28
+	// kernel and on FreeBSD it was introduced in 10 kernel. If we
+	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
+	// error on Linux, fall back to using accept.
+	switch err {
+	case nil:
+		return ns, sa, "", nil
+	default: // errors other than the ones listed
+		return -1, sa, "accept4", err
+	case syscall.ENOSYS: // syscall missing
+	case syscall.EINVAL: // some Linux use this instead of ENOSYS
+	case syscall.EACCES: // some Linux use this instead of ENOSYS
+	case syscall.EFAULT: // some Linux use this instead of ENOSYS
+	}
+
+	// See ../syscall/exec_unix.go for description of ForkLock.
+	// It is probably okay to hold the lock across syscall.Accept
+	// because we have put fd.sysfd into non-blocking mode.
+	// However, a call to the File method will put it back into
+	// blocking mode. We can't take that risk, so no use of ForkLock here.
+	ns, sa, err = AcceptFunc(s)
+	if err == nil {
+		syscall.CloseOnExec(ns)
+	}
+	if err != nil {
+		return -1, nil, "accept", err
+	}
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		CloseFunc(ns)
+		return -1, nil, "setnonblock", err
+	}
+	return ns, sa, "", nil
+}
diff --git a/src/internal/poll/sockopt.go b/src/internal/poll/sockopt.go
new file mode 100644
index 0000000..f86ce70
--- /dev/null
+++ b/src/internal/poll/sockopt.go
@@ -0,0 +1,36 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+
+package poll
+
+import "syscall"
+
+// SetsockoptInt wraps the setsockopt network call with an int argument.
+func (fd *FD) SetsockoptInt(level, name, arg int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptInt(fd.Sysfd, level, name, arg)
+}
+
+// SetsockoptInet4Addr wraps the setsockopt network call with an IPv4 address.
+func (fd *FD) SetsockoptInet4Addr(level, name int, arg [4]byte) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptInet4Addr(fd.Sysfd, level, name, arg)
+}
+
+// SetsockoptLinger wraps the setsockopt network call with a Linger argument.
+func (fd *FD) SetsockoptLinger(level, name int, l *syscall.Linger) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptLinger(fd.Sysfd, level, name, l)
+}
diff --git a/src/internal/poll/sockopt_linux.go b/src/internal/poll/sockopt_linux.go
new file mode 100644
index 0000000..bc79c35
--- /dev/null
+++ b/src/internal/poll/sockopt_linux.go
@@ -0,0 +1,16 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// SetsockoptIPMreqn wraps the setsockopt network call with an IPMreqn argument.
+func (fd *FD) SetsockoptIPMreqn(level, name int, mreq *syscall.IPMreqn) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPMreqn(fd.Sysfd, level, name, mreq)
+}
diff --git a/src/internal/poll/sockopt_unix.go b/src/internal/poll/sockopt_unix.go
new file mode 100644
index 0000000..b33644d
--- /dev/null
+++ b/src/internal/poll/sockopt_unix.go
@@ -0,0 +1,18 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package poll
+
+import "syscall"
+
+// SetsockoptByte wraps the setsockopt network call with a byte argument.
+func (fd *FD) SetsockoptByte(level, name int, arg byte) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptByte(fd.Sysfd, level, name, arg)
+}
diff --git a/src/internal/poll/sockopt_windows.go b/src/internal/poll/sockopt_windows.go
new file mode 100644
index 0000000..dd5fb70
--- /dev/null
+++ b/src/internal/poll/sockopt_windows.go
@@ -0,0 +1,25 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import "syscall"
+
+// Setsockopt wraps the setsockopt network call.
+func (fd *FD) Setsockopt(level, optname int32, optval *byte, optlen int32) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Setsockopt(fd.Sysfd, level, optname, optval, optlen)
+}
+
+// WSAIoctl wraps the WSAIoctl network call.
+func (fd *FD) WSAIoctl(iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *syscall.Overlapped, completionRoutine uintptr) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.WSAIoctl(fd.Sysfd, iocc, inbuf, cbif, outbuf, cbob, cbbr, overlapped, completionRoutine)
+}
diff --git a/src/internal/poll/sockoptip.go b/src/internal/poll/sockoptip.go
new file mode 100644
index 0000000..5d5dff6
--- /dev/null
+++ b/src/internal/poll/sockoptip.go
@@ -0,0 +1,27 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd windows
+
+package poll
+
+import "syscall"
+
+// SetsockoptIPMreq wraps the setsockopt network call with an IPMreq argument.
+func (fd *FD) SetsockoptIPMreq(level, name int, mreq *syscall.IPMreq) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPMreq(fd.Sysfd, level, name, mreq)
+}
+
+// SetsockoptIPv6Mreq wraps the setsockopt network call with an IPv6Mreq argument.
+func (fd *FD) SetsockoptIPv6Mreq(level, name int, mreq *syscall.IPv6Mreq) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPv6Mreq(fd.Sysfd, level, name, mreq)
+}
diff --git a/src/internal/poll/strconv.go b/src/internal/poll/strconv.go
new file mode 100644
index 0000000..21cb40d
--- /dev/null
+++ b/src/internal/poll/strconv.go
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. 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
+
+// Simple conversions to avoid depending on strconv.
+
+package poll
+
+// Convert integer to decimal string
+func itoa(val int) string {
+	if val < 0 {
+		return "-" + uitoa(uint(-val))
+	}
+	return uitoa(uint(val))
+}
+
+// Convert unsigned integer to decimal string
+func uitoa(val uint) string {
+	if val == 0 { // avoid string allocation
+		return "0"
+	}
+	var buf [20]byte // big enough for 64bit value base 10
+	i := len(buf) - 1
+	for val >= 10 {
+		q := val / 10
+		buf[i] = byte('0' + val - q*10)
+		i--
+		val = q
+	}
+	// val < 10
+	buf[i] = byte('0' + val)
+	return string(buf[i:])
+}
+
+// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
+// suffix.
+func stringsHasSuffix(s, suffix string) bool {
+	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
diff --git a/src/internal/poll/sys_cloexec.go b/src/internal/poll/sys_cloexec.go
new file mode 100644
index 0000000..9ed35bd
--- /dev/null
+++ b/src/internal/poll/sys_cloexec.go
@@ -0,0 +1,36 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements sysSocket and accept for platforms that do not
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build darwin nacl netbsd openbsd solaris
+
+package poll
+
+import (
+	"syscall"
+)
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(s int) (int, syscall.Sockaddr, string, error) {
+	// See ../syscall/exec_unix.go for description of ForkLock.
+	// It is probably okay to hold the lock across syscall.Accept
+	// because we have put fd.sysfd into non-blocking mode.
+	// However, a call to the File method will put it back into
+	// blocking mode. We can't take that risk, so no use of ForkLock here.
+	ns, sa, err := AcceptFunc(s)
+	if err == nil {
+		syscall.CloseOnExec(ns)
+	}
+	if err != nil {
+		return -1, nil, "accept", err
+	}
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		CloseFunc(ns)
+		return -1, nil, "setnonblock", err
+	}
+	return ns, sa, "", nil
+}
diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go
new file mode 100644
index 0000000..4bf8804
--- /dev/null
+++ b/src/internal/poll/writev.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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package poll
+
+import (
+	"io"
+	"syscall"
+	"unsafe"
+)
+
+// Writev wraps the writev system call.
+func (fd *FD) Writev(v *[][]byte) (int64, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+
+	var iovecs []syscall.Iovec
+	if fd.iovecs != nil {
+		iovecs = *fd.iovecs
+	}
+	// TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
+	// 1024 and this seems conservative enough for now. Darwin's
+	// UIO_MAXIOV also seems to be 1024.
+	maxVec := 1024
+
+	var n int64
+	var err error
+	for len(*v) > 0 {
+		iovecs = iovecs[:0]
+		for _, chunk := range *v {
+			if len(chunk) == 0 {
+				continue
+			}
+			iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
+			if fd.IsStream && len(chunk) > 1<<30 {
+				iovecs[len(iovecs)-1].SetLen(1 << 30)
+				break // continue chunk on next writev
+			}
+			iovecs[len(iovecs)-1].SetLen(len(chunk))
+			if len(iovecs) == maxVec {
+				break
+			}
+		}
+		if len(iovecs) == 0 {
+			break
+		}
+		fd.iovecs = &iovecs // cache
+
+		wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
+			uintptr(fd.Sysfd),
+			uintptr(unsafe.Pointer(&iovecs[0])),
+			uintptr(len(iovecs)))
+		if wrote == ^uintptr(0) {
+			wrote = 0
+		}
+		TestHookDidWritev(int(wrote))
+		n += int64(wrote)
+		consume(v, int64(wrote))
+		if e0 == syscall.EAGAIN {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		} else if e0 != 0 {
+			err = syscall.Errno(e0)
+		}
+		if err != nil {
+			break
+		}
+		if n == 0 {
+			err = io.ErrUnexpectedEOF
+			break
+		}
+	}
+	return n, err
+}
diff --git a/src/internal/poll/writev_test.go b/src/internal/poll/writev_test.go
new file mode 100644
index 0000000..b46657c
--- /dev/null
+++ b/src/internal/poll/writev_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.
+
+package poll_test
+
+import (
+	"internal/poll"
+	"reflect"
+	"testing"
+)
+
+func TestConsume(t *testing.T) {
+	tests := []struct {
+		in      [][]byte
+		consume int64
+		want    [][]byte
+	}{
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 0,
+			want:    [][]byte{[]byte("foo"), []byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 2,
+			want:    [][]byte{[]byte("o"), []byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 3,
+			want:    [][]byte{[]byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 4,
+			want:    [][]byte{[]byte("ar")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil, []byte("bar")},
+			consume: 1,
+			want:    [][]byte{[]byte("ar")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil, []byte("foo")},
+			consume: 0,
+			want:    [][]byte{[]byte("foo")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil},
+			consume: 0,
+			want:    [][]byte{},
+		},
+	}
+	for i, tt := range tests {
+		in := tt.in
+		poll.Consume(&in, tt.consume)
+		if !reflect.DeepEqual(in, tt.want) {
+			t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
+		}
+	}
+}
diff --git a/src/internal/pprof/profile/profile.go b/src/internal/pprof/profile/profile.go
deleted file mode 100644
index 28e713d..0000000
--- a/src/internal/pprof/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/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index f7c4ad2..1a13ac3 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -114,6 +114,19 @@ func HasExec() bool {
 	return true
 }
 
+// HasSrc reports whether the entire source tree is available under GOROOT.
+func HasSrc() bool {
+	switch runtime.GOOS {
+	case "nacl":
+		return false
+	case "darwin":
+		if strings.HasPrefix(runtime.GOARCH, "arm") {
+			return false
+		}
+	}
+	return true
+}
+
 // MustHaveExec checks that the current system can start new processes
 // using os.StartProcess or (more commonly) exec.Command.
 // If not, MustHaveExec calls t.Skip with an explanation.
diff --git a/src/internal/testenv/testenv_windows.go b/src/internal/testenv/testenv_windows.go
index e593f64..eb8d6ac 100644
--- a/src/internal/testenv/testenv_windows.go
+++ b/src/internal/testenv/testenv_windows.go
@@ -30,7 +30,6 @@ func initWinHasSymlink() {
 			winSymlinkErr = err
 		}
 	}
-	os.Remove("target")
 }
 
 func hasSymlink() (ok bool, reason string) {
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index efa8540..1dd3ef1 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -40,6 +40,7 @@ type Event struct {
 	// for GoUnblock: the associated GoStart
 	// for blocking GoSysCall: the associated GoSysExit
 	// for GoSysExit: the next GoStart
+	// for GCMarkAssistStart: the associated GCMarkAssistDone
 	Link *Event
 }
 
@@ -127,7 +128,7 @@ func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]stri
 		return
 	}
 	switch ver {
-	case 1005, 1007, 1008:
+	case 1005, 1007, 1008, 1009:
 		// Note: When adding a new version, add canned traces
 		// from the old version to the test suite using mkcanned.bash.
 		break
@@ -501,10 +502,11 @@ func postProcessTrace(ver int, events []*Event) error {
 		gWaiting
 	)
 	type gdesc struct {
-		state    int
-		ev       *Event
-		evStart  *Event
-		evCreate *Event
+		state        int
+		ev           *Event
+		evStart      *Event
+		evCreate     *Event
+		evMarkAssist *Event
 	}
 	type pdesc struct {
 		running bool
@@ -579,6 +581,18 @@ func postProcessTrace(ver int, events []*Event) error {
 				return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
 			}
 			p.evSweep = ev
+		case EvGCMarkAssistStart:
+			if g.evMarkAssist != nil {
+				return fmt.Errorf("previous mark assist is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			g.evMarkAssist = ev
+		case EvGCMarkAssistDone:
+			// Unlike most events, mark assists can be in progress when a
+			// goroutine starts tracing, so we can't report an error here.
+			if g.evMarkAssist != nil {
+				g.evMarkAssist.Link = ev
+				g.evMarkAssist = nil
+			}
 		case EvGCSweepDone:
 			if p.evSweep == nil {
 				return fmt.Errorf("bogus sweeping end (offset %v, time %v)", ev.Off, ev.Ts)
@@ -835,16 +849,21 @@ func argNum(raw rawEvent, ver int) int {
 		if ver < 1007 {
 			narg++ // there was an unused arg before 1.7
 		}
+		return narg
+	}
+	narg++ // timestamp
+	if ver < 1007 {
+		narg++ // sequence
+	}
+	switch raw.typ {
+	case EvGCSweepDone:
+		if ver < 1009 {
+			narg -= 2 // 1.9 added two arguments
+		}
 	case EvGCStart, EvGoStart, EvGoUnblock:
 		if ver < 1007 {
 			narg-- // 1.7 added an additional seq arg
 		}
-		fallthrough
-	default:
-		narg++ // timestamp
-		if ver < 1007 {
-			narg++ // sequence
-		}
 	}
 	return narg
 }
@@ -853,52 +872,54 @@ func argNum(raw rawEvent, ver int) int {
 var BreakTimestampsForTesting bool
 
 // Event types in the trace.
-// Verbatim copy from src/runtime/trace.go.
+// Verbatim copy from src/runtime/trace.go with the "trace" prefix removed.
 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 {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, seq, stack id]
-	EvGCDone         = 8  // GC done [timestamp]
-	EvGCScanStart    = 9  // GC mark termination start [timestamp]
-	EvGCScanDone     = 10 // GC mark termination done [timestamp]
-	EvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
-	EvGCSweepDone    = 12 // GC sweep done [timestamp]
-	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, 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]
-	EvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
-	EvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
-	EvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
-	EvGoSysCall      = 28 // syscall enter [timestamp, stack]
-	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
-	EvGoSysBlock     = 30 // syscall blocks [timestamp]
-	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]
-	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]
-	EvGoStartLabel   = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
-	EvGoBlockGC      = 42 // goroutine blocks on GC assist [timestamp, stack]
-	EvCount          = 43
+	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 {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, seq, stack id]
+	EvGCDone            = 8  // GC done [timestamp]
+	EvGCScanStart       = 9  // GC mark termination start [timestamp]
+	EvGCScanDone        = 10 // GC mark termination done [timestamp]
+	EvGCSweepStart      = 11 // GC sweep start [timestamp, stack id]
+	EvGCSweepDone       = 12 // GC sweep done [timestamp, swept, reclaimed]
+	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, 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]
+	EvGoBlockSync       = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	EvGoBlockCond       = 26 // goroutine blocks on Cond [timestamp, stack]
+	EvGoBlockNet        = 27 // goroutine blocks on network [timestamp, stack]
+	EvGoSysCall         = 28 // syscall enter [timestamp, stack]
+	EvGoSysExit         = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
+	EvGoSysBlock        = 30 // syscall blocks [timestamp]
+	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]
+	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]
+	EvGoStartLabel      = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
+	EvGoBlockGC         = 42 // goroutine blocks on GC assist [timestamp, stack]
+	EvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack]
+	EvGCMarkAssistDone  = 44 // GC mark assist done [timestamp]
+	EvCount             = 45
 )
 
 var EventDescriptions = [EvCount]struct {
@@ -907,47 +928,49 @@ var EventDescriptions = [EvCount]struct {
 	Stack      bool
 	Args       []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"}},
-	EvGoStartLabel:   {"GoStartLabel", 1008, false, []string{"g", "seq", "label"}},
-	EvGoBlockGC:      {"GoBlockGC", 1008, true, []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{"swept", "reclaimed"}}, // before 1.9, format was {}
+	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"}},
+	EvGoStartLabel:      {"GoStartLabel", 1008, false, []string{"g", "seq", "label"}},
+	EvGoBlockGC:         {"GoBlockGC", 1008, true, []string{}},
+	EvGCMarkAssistStart: {"GCMarkAssistStart", 1009, true, []string{}},
+	EvGCMarkAssistDone:  {"GCMarkAssistDone", 1009, false, []string{}},
 }
diff --git a/src/internal/trace/testdata/http_1_9_good b/src/internal/trace/testdata/http_1_9_good
new file mode 100644
index 0000000..ca89278
Binary files /dev/null and b/src/internal/trace/testdata/http_1_9_good differ
diff --git a/src/internal/trace/testdata/stress_1_9_good b/src/internal/trace/testdata/stress_1_9_good
new file mode 100644
index 0000000..dcf17f1
Binary files /dev/null and b/src/internal/trace/testdata/stress_1_9_good differ
diff --git a/src/internal/trace/testdata/stress_start_stop_1_9_good b/src/internal/trace/testdata/stress_start_stop_1_9_good
new file mode 100644
index 0000000..f00f190
Binary files /dev/null and b/src/internal/trace/testdata/stress_start_stop_1_9_good differ
diff --git a/src/internal/trace/writer.go b/src/internal/trace/writer.go
index a481f50..af5fec8 100644
--- a/src/internal/trace/writer.go
+++ b/src/internal/trace/writer.go
@@ -9,7 +9,7 @@ type Writer struct {
 
 func NewWriter() *Writer {
 	w := new(Writer)
-	w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
+	w.Write([]byte("go 1.9 trace\x00\x00\x00\x00"))
 	return w
 }
 
diff --git a/src/io/ioutil/tempfile_test.go b/src/io/ioutil/tempfile_test.go
index 6a70aed..9d54bad 100644
--- a/src/io/ioutil/tempfile_test.go
+++ b/src/io/ioutil/tempfile_test.go
@@ -12,12 +12,19 @@ import (
 )
 
 func TestTempFile(t *testing.T) {
-	f, err := TempFile("/_not_exists_", "foo")
+	dir, err := TempDir("", "TestTempFile_BadDir")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+
+	nonexistentDir := filepath.Join(dir, "_not_exists_")
+	f, err := TempFile(nonexistentDir, "foo")
 	if f != nil || err == nil {
-		t.Errorf("TempFile(`/_not_exists_`, `foo`) = %v, %v", f, err)
+		t.Errorf("TempFile(%q, `foo`) = %v, %v", nonexistentDir, f, err)
 	}
 
-	dir := os.TempDir()
+	dir = os.TempDir()
 	f, err = TempFile(dir, "ioutil_test")
 	if f == nil || err != nil {
 		t.Errorf("TempFile(dir, `ioutil_test`) = %v, %v", f, err)
diff --git a/src/io/multi_test.go b/src/io/multi_test.go
index 1a6292f..0a7eb43 100644
--- a/src/io/multi_test.go
+++ b/src/io/multi_test.go
@@ -175,13 +175,26 @@ func (f readerFunc) Read(p []byte) (int, error) {
 	return f(p)
 }
 
+// callDepth returns the logical call depth for the given PCs.
+func callDepth(callers []uintptr) (depth int) {
+	frames := runtime.CallersFrames(callers)
+	more := true
+	for more {
+		_, more = frames.Next()
+		depth++
+	}
+	return
+}
+
 // 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)
+	n := runtime.Callers(0, pc)
+	var myDepth = callDepth(pc[:n])
 	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)
+		n := runtime.Callers(1, pc)
+		readDepth = callDepth(pc[:n])
 		return 0, errors.New("irrelevant")
 	}))
 
@@ -239,14 +252,17 @@ func TestMultiReaderFinalEOF(t *testing.T) {
 func TestMultiReaderFreesExhaustedReaders(t *testing.T) {
 	var mr Reader
 	closed := make(chan struct{})
-	{
+	// The closure ensures that we don't have a live reference to buf1
+	// on our stack after MultiReader is inlined (Issue 18819).  This
+	// is a work around for a limitation in liveness analysis.
+	func() {
 		buf1 := bytes.NewReader([]byte("foo"))
 		buf2 := bytes.NewReader([]byte("bar"))
 		mr = MultiReader(buf1, buf2)
 		runtime.SetFinalizer(buf1, func(*bytes.Reader) {
 			close(closed)
 		})
-	}
+	}()
 
 	buf := make([]byte, 4)
 	if n, err := ReadFull(mr, buf); err != nil || string(buf) != "foob" {
diff --git a/src/iostest.bash b/src/iostest.bash
index 5e09894..595b675 100755
--- a/src/iostest.bash
+++ b/src/iostest.bash
@@ -24,11 +24,11 @@ if [ "$GOARCH" != "arm" ] && [ "$GOARCH" != "arm64" ]; then
 	echo "iostest.bash requires GOARCH=arm or GOARCH=arm64, got GOARCH=$GOARCH" 1>&2
 	exit 1
 fi
-if [ "$GOARCH" == "arm" ]; then
+if [ "$GOARCH" = "arm" ]; then
 	export GOARM=7
 fi
 
-if [ "$1" == "-restart" ]; then
+if [ "$1" = "-restart" ]; then
 	# Reboot to make sure previous runs do not interfere with the current run.
 	# It is reasonably easy for a bad program leave an iOS device in an
 	# almost unusable state.
@@ -60,7 +60,7 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
 	-o ../bin/go_darwin_${GOARCH}_exec \
 	../misc/ios/go_darwin_arm_exec.go
 
-if [ "$GOIOS_DEV_ID" == "" ]; then
+if [ "$GOIOS_DEV_ID" = "" ]; then
 	echo "detecting iOS development identity"
 	eval $(GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go run ../misc/ios/detect.go)
 fi
diff --git a/src/log/log.go b/src/log/log.go
index 58b8788..0ea4b89 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -72,7 +72,7 @@ func (l *Logger) SetOutput(w io.Writer) {
 
 var std = New(os.Stderr, "", LstdFlags)
 
-// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
+// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
 func itoa(buf *[]byte, i int, wid int) {
 	// Assemble decimal in reverse order.
 	var b [20]byte
@@ -89,12 +89,16 @@ func itoa(buf *[]byte, i int, wid int) {
 	*buf = append(*buf, b[bp:]...)
 }
 
+// formatHeader writes log header to buf in following order:
+//   * l.prefix (if it's not blank),
+//   * date and/or time (if corresponding flags are provided),
+//   * file and line number (if corresponding flags are provided).
 func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 	*buf = append(*buf, l.prefix...)
-	if l.flag&LUTC != 0 {
-		t = t.UTC()
-	}
 	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
+		if l.flag&LUTC != 0 {
+			t = t.UTC()
+		}
 		if l.flag&Ldate != 0 {
 			year, month, day := t.Date()
 			itoa(buf, year, 4)
@@ -143,7 +147,11 @@ func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 // 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 {
-	now := time.Now() // get this early.
+	// Get time early if we need it.
+	var now time.Time
+	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
+		now = time.Now()
+	}
 	var file string
 	var line int
 	l.mu.Lock()
diff --git a/src/log/log_test.go b/src/log/log_test.go
index dd16c9d..966fdf3 100644
--- a/src/log/log_test.go
+++ b/src/log/log_test.go
@@ -182,3 +182,13 @@ func BenchmarkPrintln(b *testing.B) {
 		l.Println(testString)
 	}
 }
+
+func BenchmarkPrintlnNoFlags(b *testing.B) {
+	const testString = "test"
+	var buf bytes.Buffer
+	l := New(&buf, "", 0)
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		l.Println(testString)
+	}
+}
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index df9ffb8..dfd0028 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -102,15 +102,16 @@ type netConn struct {
 
 // 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.
+// priority (a combination of the syslog facility and severity) and
+// prefix tag. If tag is empty, the os.Args[0] is used.
 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
-// writer sends a log message with the given facility, severity and
-// tag.
+// writer sends a log message with the facility and severity
+// (from priority) and tag. If tag is empty, the os.Args[0] is used.
 // If network is empty, Dial will connect to the local syslog server.
 // Otherwise, see the documentation for net.Dial for valid values
 // of network and raddr.
@@ -301,10 +302,10 @@ func (n *netConn) close() error {
 	return n.conn.Close()
 }
 
-// NewLogger creates a log.Logger whose output is written to
-// the system log service with the specified priority. The logFlag
-// argument is the flag set passed through to log.New to create
-// the Logger.
+// NewLogger creates a log.Logger whose output is written to the
+// system log service with the specified priority, a combination of
+// the syslog facility and severity. The logFlag argument is the flag
+// set passed through to log.New to create the Logger.
 func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
 	s, err := New(p, "")
 	if err != nil {
diff --git a/src/make.bash b/src/make.bash
index 84aaab5..71e7531 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -107,8 +107,8 @@ done
 # Test for debian/kFreeBSD.
 # cmd/dist will detect kFreeBSD as freebsd/$GOARCH, but we need to
 # disable cgo manually.
-if [ "$(uname -s)" == "GNU/kFreeBSD" ]; then
-        export CGO_ENABLED=0
+if [ "$(uname -s)" = "GNU/kFreeBSD" ]; then
+	export CGO_ENABLED=0
 fi
 
 # Clean old generated file that will cause problems in the build.
@@ -125,7 +125,7 @@ if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
 	echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2
 	exit 1
 fi
-if [ "$GOROOT_BOOTSTRAP" == "$GOROOT" ]; then
+if [ "$GOROOT_BOOTSTRAP" = "$GOROOT" ]; then
 	echo "ERROR: \$GOROOT_BOOTSTRAP must not be set to \$GOROOT" >&2
 	echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2
 	exit 1
@@ -172,7 +172,20 @@ if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
 fi
 
 echo "##### Building packages and commands for $GOOS/$GOARCH."
+
+old_bin_files=$(cd $GOROOT/bin && echo *)
+
 CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std cmd
+
+# Check that there are no new files in $GOROOT/bin other than go and gofmt
+# and $GOOS_$GOARCH (a directory used when cross-compiling).
+(cd $GOROOT/bin && for f in *; do
+	if ! expr " $old_bin_files go gofmt ${GOOS}_${GOARCH} " : ".* $f " >/dev/null 2>/dev/null; then
+		echo 1>&2 "ERROR: unexpected new file in $GOROOT/bin: $f"
+		exit 1
+	fi
+done)
+
 echo
 
 rm -f "$GOTOOLDIR"/go_bootstrap
diff --git a/src/math/acos_s390x.s b/src/math/acos_s390x.s
new file mode 100644
index 0000000..306f45a
--- /dev/null
+++ b/src/math/acos_s390x.s
@@ -0,0 +1,144 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·acosrodataL13<> + 0(SB)/8, $0.314159265358979323E+01   //pi
+DATA ·acosrodataL13<> + 8(SB)/8, $-0.0
+DATA ·acosrodataL13<> + 16(SB)/8, $0x7ff8000000000000    //Nan
+DATA ·acosrodataL13<> + 24(SB)/8, $-1.0
+DATA ·acosrodataL13<> + 32(SB)/8, $1.0
+DATA ·acosrodataL13<> + 40(SB)/8, $0.166666666666651626E+00
+DATA ·acosrodataL13<> + 48(SB)/8, $0.750000000042621169E-01
+DATA ·acosrodataL13<> + 56(SB)/8, $0.446428567178116477E-01
+DATA ·acosrodataL13<> + 64(SB)/8, $0.303819660378071894E-01
+DATA ·acosrodataL13<> + 72(SB)/8, $0.223715011892010405E-01
+DATA ·acosrodataL13<> + 80(SB)/8, $0.173659424522364952E-01
+DATA ·acosrodataL13<> + 88(SB)/8, $0.137810186504372266E-01
+DATA ·acosrodataL13<> + 96(SB)/8, $0.134066870961173521E-01
+DATA ·acosrodataL13<> + 104(SB)/8, $-.412335502831898721E-02
+DATA ·acosrodataL13<> + 112(SB)/8, $0.867383739532082719E-01
+DATA ·acosrodataL13<> + 120(SB)/8, $-.328765950607171649E+00
+DATA ·acosrodataL13<> + 128(SB)/8, $0.110401073869414626E+01
+DATA ·acosrodataL13<> + 136(SB)/8, $-.270694366992537307E+01
+DATA ·acosrodataL13<> + 144(SB)/8, $0.500196500770928669E+01
+DATA ·acosrodataL13<> + 152(SB)/8, $-.665866959108585165E+01
+DATA ·acosrodataL13<> + 160(SB)/8, $-.344895269334086578E+01
+DATA ·acosrodataL13<> + 168(SB)/8, $0.927437952918301659E+00
+DATA ·acosrodataL13<> + 176(SB)/8, $0.610487478874645653E+01
+DATA ·acosrodataL13<> + 184(SB)/8, $0.157079632679489656e+01
+DATA ·acosrodataL13<> + 192(SB)/8, $0.0
+GLOBL ·acosrodataL13<> + 0(SB), RODATA, $200
+
+// Acos returns the arccosine, in radians, of the argument.
+//
+// Special case is:
+//      Acos(x) = NaN if x < -1 or x > 1
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·acosAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·acosrodataL13<>+0(SB), R9
+	WORD	$0xB3CD00C0	//lgdr %r12, %f0
+	FMOVD	F0, F10
+	SRAD	$32, R12
+	WORD	$0xC0293FE6	//iilf	%r2,1072079005
+	BYTE	$0xA0
+	BYTE	$0x9D
+	WORD	$0xB917001C	//llgtr	%r1,%r12
+	CMPW	R1,R2
+	BGT	L2
+	FMOVD	192(R9), F8
+	FMADD	F0, F0, F8
+	FMOVD	184(R9), F1
+L3:
+	WFMDB	V8, V8, V2
+	FMOVD	176(R9), F6
+	FMOVD	168(R9), F0
+	FMOVD	160(R9), F4
+	WFMADB	V2, V0, V6, V0
+	FMOVD	152(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	144(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	136(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	128(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	120(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	112(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	104(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	96(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	88(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	80(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	72(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	64(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	56(R9), F6
+	WFMADB	V2, V4, V6, V4
+	FMOVD	48(R9), F6
+	WFMADB	V2, V0, V6, V0
+	FMOVD	40(R9), F6
+	WFMADB	V2, V4, V6, V2
+	FMOVD	192(R9), F4
+	WFMADB	V8, V0, V2, V0
+	WFMADB	V10, V8, V4, V8
+	FMADD	F0, F8, F10
+	WFSDB	V10, V1, V10
+L1:
+	FMOVD	F10, ret+8(FP)
+	RET
+
+L2:
+	WORD	$0xC0293FEF	//iilf	%r2,1072693247
+	BYTE	$0xFF
+	BYTE	$0xFF
+	CMPW	R1, R2
+	BLE	L12
+L4:
+	WORD	$0xED009020	//cdb	%f0,.L34-.L13(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	BEQ	L8
+	WORD	$0xED009018	//cdb	%f0,.L35-.L13(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	BEQ	L9
+	WFCEDBS	V10, V10, V0
+	BVS	L1
+	FMOVD	16(R9), F10
+	BR	L1
+L12:
+	FMOVD	24(R9), F0
+	FMADD	F10, F10, F0
+	WORD	$0xB3130080	//lcdbr	%f8,%f0
+	WORD	$0xED009008	//cdb	%f0,.L37-.L13(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	FSQRT	F8, F10
+L5:
+	MOVW	R12, R4
+	CMPBLE	R4, $0, L7
+	WORD	$0xB31300AA	//lcdbr	%f10,%f10
+	FMOVD	$0, F1
+	BR	L3
+L9:
+	FMOVD	0(R9), F10
+	BR	L1
+L8:
+	FMOVD	$0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L7:
+	FMOVD	0(R9), F1
+	BR	L3
diff --git a/src/math/acosh.go b/src/math/acosh.go
index dce21b2..cc8195c 100644
--- a/src/math/acosh.go
+++ b/src/math/acosh.go
@@ -39,7 +39,9 @@ package math
 //	Acosh(+Inf) = +Inf
 //	Acosh(x) = NaN if x < 1
 //	Acosh(NaN) = NaN
-func Acosh(x float64) float64 {
+func Acosh(x float64) float64
+
+func acosh(x float64) float64 {
 	const (
 		Ln2   = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
 		Large = 1 << 28                    // 2**28
diff --git a/src/math/acosh_s390x.s b/src/math/acosh_s390x.s
new file mode 100644
index 0000000..e120285
--- /dev/null
+++ b/src/math/acosh_s390x.s
@@ -0,0 +1,172 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·acoshrodataL11<> + 0(SB)/8, $-1.0
+DATA ·acoshrodataL11<> + 8(SB)/8, $.41375273347623353626
+DATA ·acoshrodataL11<> + 16(SB)/8, $.51487302528619766235E+04
+DATA ·acoshrodataL11<> + 24(SB)/8, $-1.67526912689208984375
+DATA ·acoshrodataL11<> + 32(SB)/8, $0.181818181818181826E+00
+DATA ·acoshrodataL11<> + 40(SB)/8, $-.165289256198351540E-01
+DATA ·acoshrodataL11<> + 48(SB)/8, $0.200350613573012186E-02
+DATA ·acoshrodataL11<> + 56(SB)/8, $-.273205381970859341E-03
+DATA ·acoshrodataL11<> + 64(SB)/8, $0.397389654305194527E-04
+DATA ·acoshrodataL11<> + 72(SB)/8, $0.938370938292558173E-06
+DATA ·acoshrodataL11<> + 80(SB)/8, $-.602107458843052029E-05
+DATA ·acoshrodataL11<> + 88(SB)/8, $0.212881813645679599E-07
+DATA ·acoshrodataL11<> + 96(SB)/8, $-.148682720127920854E-06
+DATA ·acoshrodataL11<> + 104(SB)/8, $-5.5
+DATA ·acoshrodataL11<> + 112(SB)/8, $0x7ff8000000000000      //Nan
+GLOBL ·acoshrodataL11<> + 0(SB), RODATA, $120
+
+// Table of log correction terms
+DATA ·acoshtab2068<> + 0(SB)/8, $0.585235384085551248E-01
+DATA ·acoshtab2068<> + 8(SB)/8, $0.412206153771168640E-01
+DATA ·acoshtab2068<> + 16(SB)/8, $0.273839003221648339E-01
+DATA ·acoshtab2068<> + 24(SB)/8, $0.166383778368856480E-01
+DATA ·acoshtab2068<> + 32(SB)/8, $0.866678223433169637E-02
+DATA ·acoshtab2068<> + 40(SB)/8, $0.319831684989627514E-02
+DATA ·acoshtab2068<> + 48(SB)/8, $0.0
+DATA ·acoshtab2068<> + 56(SB)/8, $-.113006378583725549E-02
+DATA ·acoshtab2068<> + 64(SB)/8, $-.367979419636602491E-03
+DATA ·acoshtab2068<> + 72(SB)/8, $0.213172484510484979E-02
+DATA ·acoshtab2068<> + 80(SB)/8, $0.623271047682013536E-02
+DATA ·acoshtab2068<> + 88(SB)/8, $0.118140812789696885E-01
+DATA ·acoshtab2068<> + 96(SB)/8, $0.187681358930914206E-01
+DATA ·acoshtab2068<> + 104(SB)/8, $0.269985148668178992E-01
+DATA ·acoshtab2068<> + 112(SB)/8, $0.364186619761331328E-01
+DATA ·acoshtab2068<> + 120(SB)/8, $0.469505379381388441E-01
+GLOBL ·acoshtab2068<> + 0(SB), RODATA, $128
+
+// Acosh returns the inverse hyperbolic cosine of the argument.
+//
+// Special cases are:
+//      Acosh(+Inf) = +Inf
+//      Acosh(x) = NaN if x < 1
+//      Acosh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·acoshAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·acoshrodataL11<>+0(SB), R9
+	WORD	$0xB3CD0010	//lgdr %r1, %f0
+	WORD	$0xC0295FEF	//iilf	%r2,1609564159
+	BYTE	$0xFF
+	BYTE	$0xFF
+	SRAD	$32, R1
+	CMPW	R1, R2
+	BGT	L2
+	WORD	$0xC0293FEF	//iilf	%r2,1072693247
+	BYTE	$0xFF
+	BYTE	$0xFF
+	CMPW	R1, R2
+	BGT	L10
+L3:
+	WFCEDBS	V0, V0, V2
+	BVS	L1
+	FMOVD	112(R9), F0
+L1:
+	FMOVD	F0, ret+8(FP)
+	RET
+L2:
+	WORD	$0xC0297FEF	//iilf	%r2,2146435071
+	BYTE	$0xFF
+	BYTE	$0xFF
+	MOVW	R1, R6
+	MOVW	R2, R7
+	CMPBGT	R6, R7, L1
+	FMOVD	F0, F8
+	FMOVD	$0, F0
+	WFADB	V0, V8, V0
+	WORD	$0xC0398006	//iilf	%r3,2147909631
+	BYTE	$0x7F
+	BYTE	$0xFF
+	WORD	$0xB3CD0050	//lgdr %r5, %f0
+	SRAD	$32, R5
+	MOVH	$0x0, R1
+	SUBW	R5, R3
+	FMOVD	$0, F10
+	WORD	$0xEC4320AF	//risbg	%r4,%r3,32,128+47,0
+	BYTE	$0x00
+	BYTE	$0x55
+	WORD	$0xEC3339BC	//risbg	%r3,%r3,57,128+60,64-13
+	BYTE	$0x33
+	BYTE	$0x55
+	BYTE	$0x18	//lr	%r2,%r4
+	BYTE	$0x24
+	WORD	$0xEC14001F	//risbgn	%r1,%r4,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	SUBW	$0x100000, R2
+	SRAW	$8, R2, R2
+	ORW	$0x45000000, R2
+L5:
+	WORD	$0xB3C10001	//ldgr	%f0,%r1
+	FMOVD	104(R9), F2
+	FMADD	F8, F0, F2
+	FMOVD	96(R9), F4
+	WFMADB	V10, V0, V2, V0
+	FMOVD	88(R9), F6
+	FMOVD	80(R9), F2
+	WFMADB	V0, V6, V4, V6
+	FMOVD	72(R9), F1
+	WFMDB	V0, V0, V4
+	WFMADB	V0, V1, V2, V1
+	FMOVD	64(R9), F2
+	WFMADB	V6, V4, V1, V6
+	FMOVD	56(R9), F1
+	WORD	$0xEC3339BC	//risbg	%r3,%r3,57,128+60,0
+	BYTE	$0x00
+	BYTE	$0x55
+	WFMADB	V0, V2, V1, V2
+	FMOVD	48(R9), F1
+	WFMADB	V4, V6, V2, V6
+	FMOVD	40(R9), F2
+	WFMADB	V0, V1, V2, V1
+	VLVGF	$0, R2, V2
+	WFMADB	V4, V6, V1, V4
+	LDEBR	F2, F2
+	FMOVD	32(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	24(R9), F1
+	FMOVD	16(R9), F6
+	MOVD	$·acoshtab2068<>+0(SB), R1
+	WFMADB	V2, V1, V6, V2
+	FMOVD	0(R3)(R1*1), F3
+	WFMADB	V0, V4, V3, V0
+	FMOVD	8(R9), F4
+	FMADD	F4, F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L10:
+	FMOVD	F0, F8
+	FMOVD	0(R9), F0
+	FMADD	F8, F8, F0
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	FSQRT	F0, F10
+L4:
+	WFADB	V10, V8, V0
+	WORD	$0xC0398006	//iilf	%r3,2147909631
+	BYTE	$0x7F
+	BYTE	$0xFF
+	WORD	$0xB3CD0050	//lgdr %r5, %f0
+	SRAD	$32, R5
+	MOVH	$0x0, R1
+	SUBW	R5, R3
+	SRAW	$8, R3, R2
+	WORD	$0xEC4320AF	//risbg	%r4,%r3,32,128+47,0
+	BYTE	$0x00
+	BYTE	$0x55
+	ANDW	$0xFFFFFF00, R2
+	WORD	$0xEC3339BC	//risbg	%r3,%r3,57,128+60,64-13
+	BYTE	$0x33
+	BYTE	$0x55
+	ORW	$0x45000000, R2
+	WORD	$0xEC14001F	//risbgn	%r1,%r4,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	BR	L5
diff --git a/src/math/all_test.go b/src/math/all_test.go
index 3d8cd72..39a3a49 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -947,6 +947,11 @@ var vfexpSC = []float64{
 	2000,
 	Inf(1),
 	NaN(),
+	// smallest float64 that overflows Exp(x)
+	7.097827128933841e+02,
+	// Issue 18912
+	1.48852223e+09,
+	1.4885222e+09,
 }
 var expSC = []float64{
 	0,
@@ -954,6 +959,27 @@ var expSC = []float64{
 	Inf(1),
 	Inf(1),
 	NaN(),
+	Inf(1),
+	Inf(1),
+	Inf(1),
+}
+
+var vfexp2SC = []float64{
+	Inf(-1),
+	-2000,
+	2000,
+	Inf(1),
+	NaN(),
+	// smallest float64 that overflows Exp2(x)
+	1024,
+}
+var exp2SC = []float64{
+	0,
+	0,
+	Inf(1),
+	Inf(1),
+	NaN(),
+	Inf(1),
 }
 
 var vfexpm1SC = []float64{
@@ -1620,16 +1646,38 @@ var powSC = []float64{
 
 var vfpow10SC = []int{
 	MinInt32,
-	MaxInt32,
-	-325,
+	-324,
+	-323,
+	-50,
+	-22,
+	-1,
+	0,
+	1,
+	22,
+	50,
+	100,
+	200,
+	308,
 	309,
+	MaxInt32,
 }
 
 var pow10SC = []float64{
-	0,      // pow10(MinInt32)
-	Inf(1), // pow10(MaxInt32)
-	0,      // pow10(-325)
-	Inf(1), // pow10(309)
+	0,        // pow10(MinInt32)
+	0,        // pow10(-324)
+	1.0e-323, // pow10(-323)
+	1.0e-50,  // pow10(-50)
+	1.0e-22,  // pow10(-22)
+	1.0e-1,   // pow10(-1)
+	1.0e0,    // pow10(0)
+	1.0e1,    // pow10(1)
+	1.0e22,   // pow10(22)
+	1.0e50,   // pow10(50)
+	1.0e100,  // pow10(100)
+	1.0e200,  // pow10(200)
+	1.0e308,  // pow10(308)
+	Inf(1),   // pow10(309)
+	Inf(1),   // pow10(MaxInt32)
 }
 
 var vfsignbitSC = []float64{
@@ -1716,30 +1764,35 @@ var vfy0SC = []float64{
 	0,
 	Inf(1),
 	NaN(),
+	-1,
 }
 var y0SC = []float64{
 	NaN(),
 	Inf(-1),
 	0,
 	NaN(),
+	NaN(),
 }
 var y1SC = []float64{
 	NaN(),
 	Inf(-1),
 	0,
 	NaN(),
+	NaN(),
 }
 var y2SC = []float64{
 	NaN(),
 	Inf(-1),
 	0,
 	NaN(),
+	NaN(),
 }
 var yM3SC = []float64{
 	NaN(),
 	Inf(1),
 	0,
 	NaN(),
+	NaN(),
 }
 
 // arguments and expected results for boundary cases
@@ -2089,8 +2142,8 @@ func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
 			t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i])
 		}
 	}
-	for i := 0; i < len(vfexpSC); i++ {
-		if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
+	for i := 0; i < len(vfexp2SC); i++ {
+		if f := Exp2(vfexp2SC[i]); !alike(exp2SC[i], f) {
 			t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
 		}
 	}
@@ -2690,6 +2743,9 @@ func TestYn(t *testing.T) {
 			t.Errorf("Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i])
 		}
 	}
+	if f := Yn(0, 0); !alike(Inf(-1), f) {
+		t.Errorf("Yn(0, 0) = %g, want %g", f, Inf(-1))
+	}
 }
 
 // Check that math functions of high angle values
@@ -2768,327 +2824,452 @@ func TestFloatMinMax(t *testing.T) {
 
 // Benchmarks
 
+// Global exported variables are used to store the
+// return values of functions measured in the benchmarks.
+// Storing the results in these variables prevents the compiler
+// from completely optimizing the benchmarked functions away.
+var (
+	GlobalI int
+	GlobalB bool
+	GlobalF float64
+)
+
 func BenchmarkAcos(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Acos(.5)
+		x = Acos(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAcosh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Acosh(1.5)
+		x = Acosh(1.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAsin(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Asin(.5)
+		x = Asin(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAsinh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Asinh(.5)
+		x = Asinh(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAtan(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Atan(.5)
+		x = Atan(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAtanh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Atanh(.5)
+		x = Atanh(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAtan2(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Atan2(.5, 1)
+		x = Atan2(.5, 1)
 	}
+	GlobalF = x
 }
 
 func BenchmarkCbrt(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Cbrt(10)
+		x = Cbrt(10)
 	}
+	GlobalF = x
 }
 
 func BenchmarkCeil(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Ceil(.5)
+		x = Ceil(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkCopysign(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Copysign(.5, -1)
+		x = Copysign(.5, -1)
 	}
+	GlobalF = x
 }
 
 func BenchmarkCos(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Cos(.5)
+		x = Cos(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkCosh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Cosh(2.5)
+		x = Cosh(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkErf(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Erf(.5)
+		x = Erf(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkErfc(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Erfc(.5)
+		x = Erfc(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkExp(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Exp(.5)
+		x = Exp(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkExpGo(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		ExpGo(.5)
+		x = ExpGo(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkExpm1(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Expm1(.5)
+		x = Expm1(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkExp2(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Exp2(.5)
+		x = Exp2(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkExp2Go(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Exp2Go(.5)
+		x = Exp2Go(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkAbs(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Abs(.5)
+		x = Abs(.5)
 	}
+	GlobalF = x
+
 }
 
 func BenchmarkDim(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Dim(10, 3)
+		x = Dim(10, 3)
 	}
+	GlobalF = x
 }
 
 func BenchmarkFloor(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Floor(.5)
+		x = Floor(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkMax(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Max(10, 3)
+		x = Max(10, 3)
 	}
+	GlobalF = x
 }
 
 func BenchmarkMin(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Min(10, 3)
+		x = Min(10, 3)
 	}
+	GlobalF = x
 }
 
 func BenchmarkMod(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Mod(10, 3)
+		x = Mod(10, 3)
 	}
+	GlobalF = x
 }
 
 func BenchmarkFrexp(b *testing.B) {
+	x := 0.0
+	y := 0
 	for i := 0; i < b.N; i++ {
-		Frexp(8)
+		x, y = Frexp(8)
 	}
+	GlobalF = x
+	GlobalI = y
 }
 
 func BenchmarkGamma(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Gamma(2.5)
+		x = Gamma(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkHypot(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Hypot(3, 4)
+		x = Hypot(3, 4)
 	}
+	GlobalF = x
 }
 
 func BenchmarkHypotGo(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		HypotGo(3, 4)
+		x = HypotGo(3, 4)
 	}
+	GlobalF = x
 }
 
 func BenchmarkIlogb(b *testing.B) {
+	x := 0
 	for i := 0; i < b.N; i++ {
-		Ilogb(.5)
+		x = Ilogb(.5)
 	}
+	GlobalI = x
 }
 
 func BenchmarkJ0(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		J0(2.5)
+		x = J0(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkJ1(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		J1(2.5)
+		x = J1(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkJn(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Jn(2, 2.5)
+		x = Jn(2, 2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLdexp(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Ldexp(.5, 2)
+		x = Ldexp(.5, 2)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLgamma(b *testing.B) {
+	x := 0.0
+	y := 0
 	for i := 0; i < b.N; i++ {
-		Lgamma(2.5)
+		x, y = Lgamma(2.5)
 	}
+	GlobalF = x
+	GlobalI = y
 }
 
 func BenchmarkLog(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Log(.5)
+		x = Log(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLogb(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Logb(.5)
+		x = Logb(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLog1p(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Log1p(.5)
+		x = Log1p(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLog10(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Log10(.5)
+		x = Log10(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkLog2(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Log2(.5)
+		x = Log2(.5)
 	}
+	GlobalF += x
 }
 
 func BenchmarkModf(b *testing.B) {
+	x := 0.0
+	y := 0.0
 	for i := 0; i < b.N; i++ {
-		Modf(1.5)
+		x, y = Modf(1.5)
 	}
+	GlobalF += x
+	GlobalF += y
 }
 
 func BenchmarkNextafter32(b *testing.B) {
+	x := float32(0.0)
 	for i := 0; i < b.N; i++ {
-		Nextafter32(.5, 1)
+		x = Nextafter32(.5, 1)
 	}
+	GlobalF = float64(x)
 }
 
 func BenchmarkNextafter64(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Nextafter(.5, 1)
+		x = Nextafter(.5, 1)
 	}
+	GlobalF = x
 }
 
 func BenchmarkPowInt(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Pow(2, 2)
+		x = Pow(2, 2)
 	}
+	GlobalF = x
 }
 
 func BenchmarkPowFrac(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Pow(2.5, 1.5)
+		x = Pow(2.5, 1.5)
 	}
+	GlobalF = x
 }
 
+var pow10pos = int(300)
+
 func BenchmarkPow10Pos(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Pow10(300)
+		x = Pow10(pow10pos)
 	}
+	GlobalF = x
 }
 
+var pow10neg = int(-300)
+
 func BenchmarkPow10Neg(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Pow10(-300)
+		x = Pow10(pow10neg)
 	}
+	GlobalF = x
 }
 
 func BenchmarkRemainder(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Remainder(10, 3)
+		x = Remainder(10, 3)
 	}
+	GlobalF = x
 }
 
 func BenchmarkSignbit(b *testing.B) {
+	x := false
 	for i := 0; i < b.N; i++ {
-		Signbit(2.5)
+		x = Signbit(2.5)
 	}
+	GlobalB = x
 }
 
 func BenchmarkSin(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Sin(.5)
+		x = Sin(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkSincos(b *testing.B) {
+	x := 0.0
+	y := 0.0
 	for i := 0; i < b.N; i++ {
-		Sincos(.5)
+		x, y = Sincos(.5)
 	}
+	GlobalF += x
+	GlobalF += y
 }
 
 func BenchmarkSinh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Sinh(2.5)
+		x = Sinh(2.5)
 	}
+	GlobalF = x
 }
 
-var Global float64
-
 func BenchmarkSqrtIndirect(b *testing.B) {
 	x, y := 0.0, 10.0
 	f := Sqrt
 	for i := 0; i < b.N; i++ {
 		x += f(y)
 	}
-	Global = x
+	GlobalF = x
 }
 
 func BenchmarkSqrtLatency(b *testing.B) {
@@ -3096,7 +3277,7 @@ func BenchmarkSqrtLatency(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		x = Sqrt(x)
 	}
-	Global = x
+	GlobalF = x
 }
 
 func BenchmarkSqrtIndirectLatency(b *testing.B) {
@@ -3105,7 +3286,7 @@ func BenchmarkSqrtIndirectLatency(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		x = f(x)
 	}
-	Global = x
+	GlobalF = x
 }
 
 func BenchmarkSqrtGoLatency(b *testing.B) {
@@ -3113,7 +3294,7 @@ func BenchmarkSqrtGoLatency(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		x = SqrtGo(x)
 	}
-	Global = x
+	GlobalF = x
 }
 
 func isPrime(i int) bool {
@@ -3131,48 +3312,56 @@ func isPrime(i int) bool {
 }
 
 func BenchmarkSqrtPrime(b *testing.B) {
-	any := false
+	x := false
 	for i := 0; i < b.N; i++ {
-		if isPrime(100003) {
-			any = true
-		}
-	}
-	if any {
-		Global = 1
+		x = isPrime(100003)
 	}
+	GlobalB = x
 }
 
 func BenchmarkTan(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Tan(.5)
+		x = Tan(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkTanh(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Tanh(2.5)
+		x = Tanh(2.5)
 	}
+	GlobalF = x
 }
 func BenchmarkTrunc(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Trunc(.5)
+		x = Trunc(.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkY0(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Y0(2.5)
+		x = Y0(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkY1(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Y1(2.5)
+		x = Y1(2.5)
 	}
+	GlobalF = x
 }
 
 func BenchmarkYn(b *testing.B) {
+	x := 0.0
 	for i := 0; i < b.N; i++ {
-		Yn(2, 2.5)
+		x = Yn(2, 2.5)
 	}
+	GlobalF = x
 }
diff --git a/src/math/arith_s390x.go b/src/math/arith_s390x.go
index 892935a..4a1d2f8 100644
--- a/src/math/arith_s390x.go
+++ b/src/math/arith_s390x.go
@@ -22,6 +22,54 @@ func sinhAsm(x float64) float64
 func tanhTrampolineSetup(x float64) float64
 func tanhAsm(x float64) float64
 
+func log1pTrampolineSetup(x float64) float64
+func log1pAsm(x float64) float64
+
+func atanhTrampolineSetup(x float64) float64
+func atanhAsm(x float64) float64
+
+func acosTrampolineSetup(x float64) float64
+func acosAsm(x float64) float64
+
+func acoshTrampolineSetup(x float64) float64
+func acoshAsm(x float64) float64
+
+func asinTrampolineSetup(x float64) float64
+func asinAsm(x float64) float64
+
+func asinhTrampolineSetup(x float64) float64
+func asinhAsm(x float64) float64
+
+func erfTrampolineSetup(x float64) float64
+func erfAsm(x float64) float64
+
+func erfcTrampolineSetup(x float64) float64
+func erfcAsm(x float64) float64
+
+func atanTrampolineSetup(x float64) float64
+func atanAsm(x float64) float64
+
+func atan2TrampolineSetup(x, y float64) float64
+func atan2Asm(x, y float64) float64
+
+func cbrtTrampolineSetup(x float64) float64
+func cbrtAsm(x float64) float64
+
+func logTrampolineSetup(x float64) float64
+func logAsm(x float64) float64
+
+func tanTrampolineSetup(x float64) float64
+func tanAsm(x float64) float64
+
+func expTrampolineSetup(x float64) float64
+func expAsm(x float64) float64
+
+func expm1TrampolineSetup(x float64) float64
+func expm1Asm(x float64) float64
+
+func powTrampolineSetup(x, y float64) float64
+func powAsm(x, y float64) float64
+
 // hasVectorFacility reports whether the machine has the z/Architecture
 // vector facility installed and enabled.
 func hasVectorFacility() bool
diff --git a/src/math/arith_s390x_test.go b/src/math/arith_s390x_test.go
index b4f3070..cfbc7b7 100644
--- a/src/math/arith_s390x_test.go
+++ b/src/math/arith_s390x_test.go
@@ -106,6 +106,37 @@ func TestLargeSinNovec(t *testing.T) {
 	}
 }
 
+func TestLargeTanNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	large := float64(100000 * Pi)
+	for i := 0; i < len(vf); i++ {
+		f1 := tanLarge[i]
+		f2 := TanNovec(vf[i] + large)
+		if !close(f1, f2) {
+			t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
+		}
+	}
+}
+
+func TestTanNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := TanNovec(vf[i]); !veryclose(tan[i], f) {
+			t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
+		}
+	}
+	// same special cases as Sin
+	for i := 0; i < len(vfsinSC); i++ {
+		if f := TanNovec(vfsinSC[i]); !alike(sinSC[i], f) {
+			t.Errorf("Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+		}
+	}
+}
+
 func TestTanhNovec(t *testing.T) {
 	if !HasVX {
 		t.Skipf("no vector support")
@@ -142,3 +173,270 @@ func TestLog10Novec(t *testing.T) {
 		}
 	}
 }
+
+func TestLog1pNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 100
+		if f := Log1pNovec(a); !veryclose(log1p[i], f) {
+			t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
+		}
+	}
+	a := 9.0
+	if f := Log1pNovec(a); f != Ln10 {
+		t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
+	}
+	for i := 0; i < len(vflogSC); i++ {
+		if f := Log1pNovec(vflog1pSC[i]); !alike(log1pSC[i], f) {
+			t.Errorf("Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i])
+		}
+	}
+}
+
+func TestAtanhNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 10
+		if f := AtanhNovec(a); !veryclose(atanh[i], f) {
+			t.Errorf("Atanh(%g) = %g, want %g", a, f, atanh[i])
+		}
+	}
+	for i := 0; i < len(vfatanhSC); i++ {
+		if f := AtanhNovec(vfatanhSC[i]); !alike(atanhSC[i], f) {
+			t.Errorf("Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i])
+		}
+	}
+}
+
+func TestAcosNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 10
+		if f := AcosNovec(a); !close(acos[i], f) {
+			t.Errorf("Acos(%g) = %g, want %g", a, f, acos[i])
+		}
+	}
+	for i := 0; i < len(vfacosSC); i++ {
+		if f := AcosNovec(vfacosSC[i]); !alike(acosSC[i], f) {
+			t.Errorf("Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i])
+		}
+	}
+}
+
+func TestAsinNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 10
+		if f := AsinNovec(a); !veryclose(asin[i], f) {
+			t.Errorf("Asin(%g) = %g, want %g", a, f, asin[i])
+		}
+	}
+	for i := 0; i < len(vfasinSC); i++ {
+		if f := AsinNovec(vfasinSC[i]); !alike(asinSC[i], f) {
+			t.Errorf("Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i])
+		}
+	}
+}
+
+func TestAcoshNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := 1 + Abs(vf[i])
+		if f := AcoshNovec(a); !veryclose(acosh[i], f) {
+			t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
+		}
+	}
+	for i := 0; i < len(vfacoshSC); i++ {
+		if f := AcoshNovec(vfacoshSC[i]); !alike(acoshSC[i], f) {
+			t.Errorf("Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i])
+		}
+	}
+}
+
+func TestAsinhNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := AsinhNovec(vf[i]); !veryclose(asinh[i], f) {
+			t.Errorf("Asinh(%g) = %g, want %g", vf[i], f, asinh[i])
+		}
+	}
+	for i := 0; i < len(vfasinhSC); i++ {
+		if f := AsinhNovec(vfasinhSC[i]); !alike(asinhSC[i], f) {
+			t.Errorf("Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i])
+		}
+	}
+}
+
+func TestErfNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 10
+		if f := ErfNovec(a); !veryclose(erf[i], f) {
+			t.Errorf("Erf(%g) = %g, want %g", a, f, erf[i])
+		}
+	}
+	for i := 0; i < len(vferfSC); i++ {
+		if f := ErfNovec(vferfSC[i]); !alike(erfSC[i], f) {
+			t.Errorf("Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i])
+		}
+	}
+}
+
+func TestErfcNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 10
+		if f := ErfcNovec(a); !veryclose(erfc[i], f) {
+			t.Errorf("Erfc(%g) = %g, want %g", a, f, erfc[i])
+		}
+	}
+	for i := 0; i < len(vferfcSC); i++ {
+		if f := ErfcNovec(vferfcSC[i]); !alike(erfcSC[i], f) {
+			t.Errorf("Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i])
+		}
+	}
+}
+
+func TestAtanNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := AtanNovec(vf[i]); !veryclose(atan[i], f) {
+			t.Errorf("Atan(%g) = %g, want %g", vf[i], f, atan[i])
+		}
+	}
+	for i := 0; i < len(vfatanSC); i++ {
+		if f := AtanNovec(vfatanSC[i]); !alike(atanSC[i], f) {
+			t.Errorf("Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i])
+		}
+	}
+}
+
+func TestAtan2Novec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := Atan2Novec(10, vf[i]); !veryclose(atan2[i], f) {
+			t.Errorf("Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i])
+		}
+	}
+	for i := 0; i < len(vfatan2SC); i++ {
+		if f := Atan2Novec(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) {
+			t.Errorf("Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
+		}
+	}
+}
+
+func TestCbrtNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := CbrtNovec(vf[i]); !veryclose(cbrt[i], f) {
+			t.Errorf("Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i])
+		}
+	}
+	for i := 0; i < len(vfcbrtSC); i++ {
+		if f := CbrtNovec(vfcbrtSC[i]); !alike(cbrtSC[i], f) {
+			t.Errorf("Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i])
+		}
+	}
+}
+
+func TestLogNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := Abs(vf[i])
+		if f := LogNovec(a); log[i] != f {
+			t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
+		}
+	}
+	if f := LogNovec(10); f != Ln10 {
+		t.Errorf("Log(%g) = %g, want %g", 10.0, f, Ln10)
+	}
+	for i := 0; i < len(vflogSC); i++ {
+		if f := LogNovec(vflogSC[i]); !alike(logSC[i], f) {
+			t.Errorf("Log(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+		}
+	}
+}
+
+func TestExpNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	testExpNovec(t, Exp, "Exp")
+	testExpNovec(t, ExpGo, "ExpGo")
+}
+
+func testExpNovec(t *testing.T, Exp func(float64) float64, name string) {
+	for i := 0; i < len(vf); i++ {
+		if f := ExpNovec(vf[i]); !veryclose(exp[i], f) {
+			t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
+		}
+	}
+	for i := 0; i < len(vfexpSC); i++ {
+		if f := ExpNovec(vfexpSC[i]); !alike(expSC[i], f) {
+			t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+		}
+	}
+}
+
+func TestExpm1Novec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] / 100
+		if f := Expm1Novec(a); !veryclose(expm1[i], f) {
+			t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
+		}
+	}
+	for i := 0; i < len(vf); i++ {
+		a := vf[i] * 10
+		if f := Expm1Novec(a); !close(expm1Large[i], f) {
+			t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1Large[i])
+		}
+	}
+	for i := 0; i < len(vfexpm1SC); i++ {
+		if f := Expm1Novec(vfexpm1SC[i]); !alike(expm1SC[i], f) {
+			t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
+		}
+	}
+}
+
+func TestPowNovec(t *testing.T) {
+	if !HasVX {
+		t.Skipf("no vector support")
+	}
+	for i := 0; i < len(vf); i++ {
+		if f := PowNovec(10, vf[i]); !close(pow[i], f) {
+			t.Errorf("Pow(10, %g) = %g, want %g", vf[i], f, pow[i])
+		}
+	}
+	for i := 0; i < len(vfpowSC); i++ {
+		if f := PowNovec(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) {
+			t.Errorf("Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
+		}
+	}
+}
diff --git a/src/math/asin_s390x.s b/src/math/asin_s390x.s
new file mode 100644
index 0000000..fd5ab04
--- /dev/null
+++ b/src/math/asin_s390x.s
@@ -0,0 +1,162 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·asinrodataL15<> + 0(SB)/8, $-1.309611320495605469
+DATA ·asinrodataL15<> + 8(SB)/8, $0x3ff921fb54442d18
+DATA ·asinrodataL15<> + 16(SB)/8, $0xbff921fb54442d18
+DATA ·asinrodataL15<> + 24(SB)/8, $1.309611320495605469
+DATA ·asinrodataL15<> + 32(SB)/8, $-0.0
+DATA ·asinrodataL15<> + 40(SB)/8, $1.199437040755305217
+DATA ·asinrodataL15<> + 48(SB)/8, $0.166666666666651626E+00
+DATA ·asinrodataL15<> + 56(SB)/8, $0.750000000042621169E-01
+DATA ·asinrodataL15<> + 64(SB)/8, $0.446428567178116477E-01
+DATA ·asinrodataL15<> + 72(SB)/8, $0.303819660378071894E-01
+DATA ·asinrodataL15<> + 80(SB)/8, $0.223715011892010405E-01
+DATA ·asinrodataL15<> + 88(SB)/8, $0.173659424522364952E-01
+DATA ·asinrodataL15<> + 96(SB)/8, $0.137810186504372266E-01
+DATA ·asinrodataL15<> + 104(SB)/8, $0.134066870961173521E-01
+DATA ·asinrodataL15<> + 112(SB)/8, $-.412335502831898721E-02
+DATA ·asinrodataL15<> + 120(SB)/8, $0.867383739532082719E-01
+DATA ·asinrodataL15<> + 128(SB)/8, $-.328765950607171649E+00
+DATA ·asinrodataL15<> + 136(SB)/8, $0.110401073869414626E+01
+DATA ·asinrodataL15<> + 144(SB)/8, $-.270694366992537307E+01
+DATA ·asinrodataL15<> + 152(SB)/8, $0.500196500770928669E+01
+DATA ·asinrodataL15<> + 160(SB)/8, $-.665866959108585165E+01
+DATA ·asinrodataL15<> + 168(SB)/8, $-.344895269334086578E+01
+DATA ·asinrodataL15<> + 176(SB)/8, $0.927437952918301659E+00
+DATA ·asinrodataL15<> + 184(SB)/8, $0.610487478874645653E+01
+DATA ·asinrodataL15<> + 192(SB)/8, $0x7ff8000000000000			//+Inf
+DATA ·asinrodataL15<> + 200(SB)/8, $-1.0
+DATA ·asinrodataL15<> + 208(SB)/8, $1.0
+DATA ·asinrodataL15<> + 216(SB)/8, $1.00000000000000000e-20
+GLOBL ·asinrodataL15<> + 0(SB), RODATA, $224
+
+// Asin returns the arcsine, in radians, of the argument.
+//
+// Special cases are:
+//      Asin(±0) = ±0=
+//      Asin(x) = NaN if x < -1 or x > 1
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·asinAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·asinrodataL15<>+0(SB), R9
+	WORD	$0xB3CD0070	//lgdr %r7, %f0
+	FMOVD	F0, F8
+	SRAD	$32, R7
+	WORD	$0xC0193FE6 //iilf  %r1,1072079005
+	BYTE	$0xA0
+	BYTE	$0x9D
+	WORD	$0xB91700C7 //llgtr %r12,%r7
+	MOVW	R12, R8
+	MOVW	R1, R6
+	CMPBGT	R8, R6, L2
+	WORD	$0xC0193BFF //iilf  %r1,1006632959
+	BYTE	$0xFF
+	BYTE	$0xFF
+	MOVW	R1, R6
+	CMPBGT	R8, R6, L13
+L3:
+	FMOVD	216(R9), F0
+	FMADD	F0, F8, F8
+L1:
+	FMOVD	F8, ret+8(FP)
+	RET
+L2:
+	WORD	$0xC0193FEF	//iilf	%r1,1072693247
+	BYTE	$0xFF
+	BYTE	$0xFF
+	CMPW	R12, R1
+	BLE	L14
+L5:
+	WORD	$0xED0090D0	//cdb	%f0,.L17-.L15(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	BEQ		L9
+	WORD	$0xED0090C8	//cdb	%f0,.L18-.L15(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	BEQ	L10
+	WFCEDBS	V8, V8, V0
+	BVS	L1
+	FMOVD	192(R9), F8
+	BR	L1
+L13:
+	WFMDB	V0, V0, V10
+L4:
+	WFMDB	V10, V10, V0
+	FMOVD	184(R9), F6
+	FMOVD	176(R9), F2
+	FMOVD	168(R9), F4
+	WFMADB	V0, V2, V6, V2
+	FMOVD	160(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	152(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	144(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	136(R9), F6
+	WFMADB	V0, V2, V6, V2
+	WORD	$0xC0193FE6	//iilf	%r1,1072079005
+	BYTE	$0xA0
+	BYTE	$0x9D
+	FMOVD	128(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	120(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	112(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	104(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	96(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	88(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	80(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	72(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	64(R9), F6
+	WFMADB	V0, V4, V6, V4
+	FMOVD	56(R9), F6
+	WFMADB	V0, V2, V6, V2
+	FMOVD	48(R9), F6
+	WFMADB	V0, V4, V6, V0
+	WFMDB	V8, V10, V4
+	FMADD	F2, F10, F0
+	FMADD	F0, F4, F8
+	CMPW	R12, R1
+	BLE	L1
+	FMOVD	40(R9), F0
+	FMADD	F0, F1, F8
+	FMOVD	F8, ret+8(FP)
+	RET
+L14:
+	FMOVD	200(R9), F0
+	FMADD	F8, F8, F0
+	WORD	$0xB31300A0	//lcdbr	%f10,%f0
+	WORD	$0xED009020	//cdb	%f0,.L39-.L15(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	FSQRT	F10, F8
+L6:
+	MOVW	R7, R6
+	CMPBLE	R6, $0, L8
+	WORD	$0xB3130088	//lcdbr	%f8,%f8
+	FMOVD	24(R9), F1
+	BR	L4
+L10:
+	FMOVD	16(R9), F8
+	BR	L1
+L9:
+	FMOVD	8(R9), F8
+	FMOVD	F8, ret+8(FP)
+	RET
+L8:
+	FMOVD	0(R9), F1
+	BR	L4
diff --git a/src/math/asinh.go b/src/math/asinh.go
index 3b793b0..65ae4c6 100644
--- a/src/math/asinh.go
+++ b/src/math/asinh.go
@@ -36,7 +36,9 @@ package math
 //	Asinh(±0) = ±0
 //	Asinh(±Inf) = ±Inf
 //	Asinh(NaN) = NaN
-func Asinh(x float64) float64 {
+func Asinh(x float64) float64
+
+func asinh(x float64) float64 {
 	const (
 		Ln2      = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
 		NearZero = 1.0 / (1 << 28)            // 2**-28
diff --git a/src/math/asinh_s390x.s b/src/math/asinh_s390x.s
new file mode 100644
index 0000000..870a64a
--- /dev/null
+++ b/src/math/asinh_s390x.s
@@ -0,0 +1,223 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·asinhrodataL18<> + 0(SB)/8, $0.749999999977387502E-01
+DATA ·asinhrodataL18<> + 8(SB)/8, $-.166666666666657082E+00
+DATA ·asinhrodataL18<> + 16(SB)/8, $0.303819368237360639E-01
+DATA ·asinhrodataL18<> + 24(SB)/8, $-.446428569571752982E-01
+DATA ·asinhrodataL18<> + 32(SB)/8, $0.173500047922695924E-01
+DATA ·asinhrodataL18<> + 40(SB)/8, $-.223719767210027185E-01
+DATA ·asinhrodataL18<> + 48(SB)/8, $0.113655037946822130E-01
+DATA ·asinhrodataL18<> + 56(SB)/8, $0.579747490622448943E-02
+DATA ·asinhrodataL18<> + 64(SB)/8, $-.139372433914359122E-01
+DATA ·asinhrodataL18<> + 72(SB)/8, $-.218674325255800840E-02
+DATA ·asinhrodataL18<> + 80(SB)/8, $-.891074277756961157E-02
+DATA ·asinhrodataL18<> + 88(SB)/8, $.41375273347623353626
+DATA ·asinhrodataL18<> + 96(SB)/8, $.51487302528619766235E+04
+DATA ·asinhrodataL18<> + 104(SB)/8, $-1.67526912689208984375
+DATA ·asinhrodataL18<> + 112(SB)/8, $0.181818181818181826E+00
+DATA ·asinhrodataL18<> + 120(SB)/8, $-.165289256198351540E-01
+DATA ·asinhrodataL18<> + 128(SB)/8, $0.200350613573012186E-02
+DATA ·asinhrodataL18<> + 136(SB)/8, $-.273205381970859341E-03
+DATA ·asinhrodataL18<> + 144(SB)/8, $0.397389654305194527E-04
+DATA ·asinhrodataL18<> + 152(SB)/8, $0.938370938292558173E-06
+DATA ·asinhrodataL18<> + 160(SB)/8, $0.212881813645679599E-07
+DATA ·asinhrodataL18<> + 168(SB)/8, $-.602107458843052029E-05
+DATA ·asinhrodataL18<> + 176(SB)/8, $-.148682720127920854E-06
+DATA ·asinhrodataL18<> + 184(SB)/8, $-5.5
+DATA ·asinhrodataL18<> + 192(SB)/8, $1.0
+DATA ·asinhrodataL18<> + 200(SB)/8, $1.0E-20
+GLOBL ·asinhrodataL18<> + 0(SB), RODATA, $208
+
+// Table of log correction terms
+DATA ·asinhtab2080<> + 0(SB)/8, $0.585235384085551248E-01
+DATA ·asinhtab2080<> + 8(SB)/8, $0.412206153771168640E-01
+DATA ·asinhtab2080<> + 16(SB)/8, $0.273839003221648339E-01
+DATA ·asinhtab2080<> + 24(SB)/8, $0.166383778368856480E-01
+DATA ·asinhtab2080<> + 32(SB)/8, $0.866678223433169637E-02
+DATA ·asinhtab2080<> + 40(SB)/8, $0.319831684989627514E-02
+DATA ·asinhtab2080<> + 48(SB)/8, $0.0
+DATA ·asinhtab2080<> + 56(SB)/8, $-.113006378583725549E-02
+DATA ·asinhtab2080<> + 64(SB)/8, $-.367979419636602491E-03
+DATA ·asinhtab2080<> + 72(SB)/8, $0.213172484510484979E-02
+DATA ·asinhtab2080<> + 80(SB)/8, $0.623271047682013536E-02
+DATA ·asinhtab2080<> + 88(SB)/8, $0.118140812789696885E-01
+DATA ·asinhtab2080<> + 96(SB)/8, $0.187681358930914206E-01
+DATA ·asinhtab2080<> + 104(SB)/8, $0.269985148668178992E-01
+DATA ·asinhtab2080<> + 112(SB)/8, $0.364186619761331328E-01
+DATA ·asinhtab2080<> + 120(SB)/8, $0.469505379381388441E-01
+GLOBL ·asinhtab2080<> + 0(SB), RODATA, $128
+
+// Asinh returns the inverse hyperbolic sine of the argument.
+//
+// Special cases are:
+//      Asinh(±0) = ±0
+//      Asinh(±Inf) = ±Inf
+//      Asinh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·asinhAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·asinhrodataL18<>+0(SB), R9
+	WORD	$0xB3CD00C0	//lgdr %r12, %f0
+	WORD	$0xC0293FDF	//iilf	%r2,1071644671
+	BYTE	$0xFF
+	BYTE	$0xFF
+	SRAD	$32, R12
+	WORD	$0xB917001C	//llgtr	%r1,%r12
+	MOVW	R1, R6
+	MOVW	R2, R7
+	CMPBLE	R6, R7, L2
+	WORD	$0xC0295FEF	//iilf	%r2,1609564159
+	BYTE	$0xFF
+	BYTE	$0xFF
+	MOVW	R2, R7
+	CMPBLE	R6, R7, L14
+L3:
+	WORD	$0xC0297FEF	//iilf	%r2,2146435071
+	BYTE	$0xFF
+	BYTE	$0xFF
+	CMPW	R1, R2
+	BGT	L1
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	FMOVD	F0, F10
+	BLTU	L15
+L9:
+	FMOVD	$0, F0
+	WFADB	V0, V10, V0
+	WORD	$0xC0398006	//iilf	%r3,2147909631
+	BYTE	$0x7F
+	BYTE	$0xFF
+	WORD	$0xB3CD0050	//lgdr %r5, %f0
+	SRAD	$32, R5
+	MOVH	$0x0, R2
+	SUBW	R5, R3
+	FMOVD	$0, F8
+	WORD	$0xEC4320AF	//risbg	%r4,%r3,32,128+47,0
+	BYTE	$0x00
+	BYTE	$0x55
+	BYTE	$0x18	//lr	%r1,%r4
+	BYTE	$0x14
+	WORD	$0xEC24001F	//risbgn	%r2,%r4,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	SUBW	$0x100000, R1
+	SRAW	$8, R1, R1
+	ORW	$0x45000000, R1
+	BR	L6
+L2:
+	MOVD	$0x30000000, R2
+	CMPW	R1, R2
+	BGT	L16
+	FMOVD	200(R9), F2
+	FMADD	F2, F0, F0
+L1:
+	FMOVD	F0, ret+8(FP)
+	RET
+L14:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L17
+	FMOVD	F0, F10
+L4:
+	FMOVD	192(R9), F2
+	WFMADB	V0, V0, V2, V0
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	FSQRT	F0, F8
+L5:
+	WFADB	V8, V10, V0
+	WORD	$0xC0398006	//iilf	%r3,2147909631
+	BYTE	$0x7F
+	BYTE	$0xFF
+	WORD	$0xB3CD0050	//lgdr %r5, %f0
+	SRAD	$32, R5
+	MOVH	$0x0, R2
+	SUBW	R5, R3
+	WORD	$0xEC4320AF	//risbg	%r4,%r3,32,128+47,0
+	BYTE	$0x00
+	BYTE	$0x55
+	SRAW	$8, R4, R1
+	WORD	$0xEC24001F	//risbgn	%r2,%r4,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	ORW	$0x45000000, R1
+L6:
+	WORD	$0xB3C10022	//ldgr	%f2,%r2
+	FMOVD	184(R9), F0
+	WFMADB	V8, V2, V0, V8
+	FMOVD	176(R9), F4
+	WFMADB	V10, V2, V8, V2
+	FMOVD	168(R9), F0
+	FMOVD	160(R9), F6
+	FMOVD	152(R9), F1
+	WFMADB	V2, V6, V4, V6
+	WFMADB	V2, V1, V0, V1
+	WFMDB	V2, V2, V4
+	FMOVD	144(R9), F0
+	WFMADB	V6, V4, V1, V6
+	FMOVD	136(R9), F1
+	WORD	$0xEC3339BC	//risbg	%r3,%r3,57,128+60,64-13
+	BYTE	$0x33
+	BYTE	$0x55
+	WFMADB	V2, V0, V1, V0
+	FMOVD	128(R9), F1
+	WFMADB	V4, V6, V0, V6
+	FMOVD	120(R9), F0
+	WFMADB	V2, V1, V0, V1
+	VLVGF	$0, R1, V0
+	WFMADB	V4, V6, V1, V4
+	LDEBR	F0, F0
+	FMOVD	112(R9), F6
+	WFMADB	V2, V4, V6, V4
+	MOVD	$·asinhtab2080<>+0(SB), R1
+	FMOVD	104(R9), F1
+	WORD	$0x68331000	//ld	%f3,0(%r3,%r1)
+	FMOVD	96(R9), F6
+	WFMADB	V2, V4, V3, V2
+	WFMADB	V0, V1, V6, V0
+	FMOVD	88(R9), F4
+	WFMADB	V0, V4, V2, V0
+	MOVD	R12, R6
+	CMPBGT	R6, $0, L1
+
+	WORD	$0xB3130000	//lcdbr	%f0,%f0
+	FMOVD	F0, ret+8(FP)
+	RET
+L16:
+	WFMDB	V0, V0, V1
+	FMOVD	80(R9), F6
+	WFMDB	V1, V1, V4
+	FMOVD	72(R9), F2
+	WFMADB	V4, V2, V6, V2
+	FMOVD	64(R9), F3
+	FMOVD	56(R9), F6
+	WFMADB	V4, V2, V3, V2
+	FMOVD	48(R9), F3
+	WFMADB	V4, V6, V3, V6
+	FMOVD	40(R9), F5
+	FMOVD	32(R9), F3
+	WFMADB	V4, V2, V5, V2
+	WFMADB	V4, V6, V3, V6
+	FMOVD	24(R9), F5
+	FMOVD	16(R9), F3
+	WFMADB	V4, V2, V5, V2
+	WFMADB	V4, V6, V3, V6
+	FMOVD	8(R9), F5
+	FMOVD	0(R9), F3
+	WFMADB	V4, V2, V5, V2
+	WFMADB	V4, V6, V3, V4
+	WFMDB	V0, V1, V6
+	WFMADB	V1, V4, V2, V4
+	FMADD	F4, F6, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L17:
+	WORD	$0xB31300A0	//lcdbr	%f10,%f0
+	BR	L4
+L15:
+	WORD	$0xB31300A0	//lcdbr	%f10,%f0
+	BR	L9
diff --git a/src/math/asinh_stub.s b/src/math/asinh_stub.s
new file mode 100644
index 0000000..2c94aad
--- /dev/null
+++ b/src/math/asinh_stub.s
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm
+
+#include "textflag.h"
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+    JMP ·acosh(SB)
+
+TEXT ·Asinh(SB),NOSPLIT,$0
+    JMP ·asinh(SB)
+
+TEXT ·Atanh(SB),NOSPLIT,$0
+	JMP ·atanh(SB)
+
diff --git a/src/math/atan2_s390x.s b/src/math/atan2_s390x.s
new file mode 100644
index 0000000..5d90d48
--- /dev/null
+++ b/src/math/atan2_s390x.s
@@ -0,0 +1,302 @@
+// Copyright 2017 The Go 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 PosInf		0x7FF0000000000000
+#define NegInf		0xFFF0000000000000
+#define NegZero		0x8000000000000000
+#define Pi		0x400921FB54442D18
+#define NegPi		0xC00921FB54442D18
+#define Pi3Div4		0x4002D97C7F3321D2	// 3Pi/4
+#define NegPi3Div4	0xC002D97C7F3321D2	// -3Pi/4
+#define PiDiv4		0x3FE921FB54442D18	// Pi/4
+#define NegPiDiv4	0xBFE921FB54442D18	// -Pi/4
+
+// Minimax polynomial coefficients and other constants
+DATA ·atan2rodataL25<> + 0(SB)/8, $0.199999999999554423E+00
+DATA ·atan2rodataL25<> + 8(SB)/8, $-.333333333333330928E+00
+DATA ·atan2rodataL25<> + 16(SB)/8, $0.111111110136634272E+00
+DATA ·atan2rodataL25<> + 24(SB)/8, $-.142857142828026806E+00
+DATA ·atan2rodataL25<> + 32(SB)/8, $0.769228118888682505E-01
+DATA ·atan2rodataL25<> + 40(SB)/8, $0.588059263575587687E-01
+DATA ·atan2rodataL25<> + 48(SB)/8, $-.909090711945939878E-01
+DATA ·atan2rodataL25<> + 56(SB)/8, $-.666641501287528609E-01
+DATA ·atan2rodataL25<> + 64(SB)/8, $0.472329433805024762E-01
+DATA ·atan2rodataL25<> + 72(SB)/8, $-.525380587584426406E-01
+DATA ·atan2rodataL25<> + 80(SB)/8, $-.422172007412067035E-01
+DATA ·atan2rodataL25<> + 88(SB)/8, $0.366935664549587481E-01
+DATA ·atan2rodataL25<> + 96(SB)/8, $0.220852012160300086E-01
+DATA ·atan2rodataL25<> + 104(SB)/8, $-.299856214685512712E-01
+DATA ·atan2rodataL25<> + 112(SB)/8, $0.726338160757602439E-02
+DATA ·atan2rodataL25<> + 120(SB)/8, $0.134893651284712515E-04
+DATA ·atan2rodataL25<> + 128(SB)/8, $-.291935324869629616E-02
+DATA ·atan2rodataL25<> + 136(SB)/8, $-.154797890856877418E-03
+DATA ·atan2rodataL25<> + 144(SB)/8, $0.843488472994227321E-03
+DATA ·atan2rodataL25<> + 152(SB)/8, $-.139950258898989925E-01
+GLOBL ·atan2rodataL25<> + 0(SB), RODATA, $160
+
+DATA ·atan2xpi2h<> + 0(SB)/8, $0x3ff330e4e4fa7b1b
+DATA ·atan2xpi2h<> + 8(SB)/8, $0xbff330e4e4fa7b1b
+DATA ·atan2xpi2h<> + 16(SB)/8, $0x400330e4e4fa7b1b
+DATA ·atan2xpi2h<> + 24(SB)/8, $0xc00330e4e4fa7b1b
+GLOBL ·atan2xpi2h<> + 0(SB), RODATA, $32
+DATA ·atan2xpim<> + 0(SB)/8, $0x3ff4f42b00000000
+GLOBL ·atan2xpim<> + 0(SB), RODATA, $8
+
+// Atan2 returns the arc tangent of y/x, using
+// the signs of the two to determine the quadrant
+// of the return value.
+//
+// Special cases are (in order):
+//      Atan2(y, NaN) = NaN
+//      Atan2(NaN, x) = NaN
+//      Atan2(+0, x>=0) = +0
+//      Atan2(-0, x>=0) = -0
+//      Atan2(+0, x<=-0) = +Pi
+//      Atan2(-0, x<=-0) = -Pi
+//      Atan2(y>0, 0) = +Pi/2
+//      Atan2(y<0, 0) = -Pi/2
+//      Atan2(+Inf, +Inf) = +Pi/4
+//      Atan2(-Inf, +Inf) = -Pi/4
+//      Atan2(+Inf, -Inf) = 3Pi/4
+//      Atan2(-Inf, -Inf) = -3Pi/4
+//      Atan2(y, +Inf) = 0
+//      Atan2(y>0, -Inf) = +Pi
+//      Atan2(y<0, -Inf) = -Pi
+//      Atan2(+Inf, x) = +Pi/2
+//      Atan2(-Inf, x) = -Pi/2
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·atan2Asm(SB), NOSPLIT, $0-24
+	// special case
+	MOVD	x+0(FP), R1
+	MOVD	y+8(FP), R2
+
+	// special case Atan2(NaN, y) = NaN
+	MOVD	$~(1<<63), R5
+	AND	R1, R5		// x = |x|
+	MOVD	$PosInf, R3
+	CMPUBLT	R3, R5, returnX
+
+	// special case Atan2(x, NaN) = NaN
+	MOVD	$~(1<<63), R5
+	AND	R2, R5
+	CMPUBLT R3, R5, returnY
+
+	MOVD	$NegZero, R3
+	CMPUBEQ	R3, R1, xIsNegZero
+
+	MOVD	$0, R3
+	CMPUBEQ	R3, R1, xIsPosZero
+
+	MOVD	$PosInf, R4
+	CMPUBEQ	R4, R2, yIsPosInf
+
+	MOVD	$NegInf, R4
+	CMPUBEQ	R4, R2, yIsNegInf
+	BR	Normal
+xIsNegZero:
+	// special case Atan(-0, y>=0) = -0
+	MOVD	$0, R4
+	CMPBLE	R4, R2, returnX
+
+	//special case Atan2(-0, y<=-0) = -Pi
+	MOVD	$NegZero, R4
+	CMPBGE	R4, R2, returnNegPi
+	BR	Normal
+xIsPosZero:
+	//special case Atan2(0, 0) = 0
+	MOVD	$0, R4
+	CMPUBEQ	R4, R2, returnX
+
+	//special case Atan2(0, y<=-0) = Pi
+	MOVD	$NegZero, R4
+	CMPBGE	R4, R2, returnPi
+	BR Normal
+yIsNegInf:
+	//special case Atan2(+Inf, -Inf) = 3Pi/4
+	MOVD	$PosInf, R3
+	CMPUBEQ	R3, R1, posInfNegInf
+
+	//special case Atan2(-Inf, -Inf) = -3Pi/4
+	MOVD	$NegInf, R3
+	CMPUBEQ	R3, R1, negInfNegInf
+	BR Normal
+yIsPosInf:
+	//special case Atan2(+Inf, +Inf) = Pi/4
+	MOVD	$PosInf, R3
+	CMPUBEQ	R3, R1, posInfPosInf
+
+	//special case Atan2(-Inf, +Inf) = -Pi/4
+	MOVD	$NegInf, R3
+	CMPUBEQ	R3, R1, negInfPosInf
+
+	//special case Atan2(-Pi, +Inf) = Pi
+	MOVD	$NegPi, R3
+	CMPUBEQ	R3, R1, negPiPosInf
+
+Normal:
+	FMOVD	x+0(FP), F0
+	FMOVD	y+8(FP), F2
+	MOVD	$·atan2rodataL25<>+0(SB), R9
+	WORD	$0xB3CD0020	//lgdr	%r2,%f0
+	WORD	$0xB3CD0012	//lgdr	%r1,%f2
+	WORD	$0xEC2220BF	//risbgn	%r2,%r2,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	WORD	$0xEC1120BF	//risbgn	%r1,%r1,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	WORD	$0xB9170032	//llgtr	%r3,%r2
+	WORD	$0xEC523FBF	//risbg	%r5,%r2,64-1,128+63,64+32+1
+	BYTE	$0x61
+	BYTE	$0x55
+	WORD	$0xB9170041	//llgtr	%r4,%r1
+	WFLCDB	V0, V20
+	MOVW	R4, R6
+	MOVW	R3, R7
+	CMPUBLT	R6, R7, L17
+	WFDDB	V2, V0, V3
+	ADDW	$2, R5, R2
+	MOVW	R4, R6
+	MOVW	R3, R7
+	CMPUBLE	R6, R7, L20
+L3:
+	WFMDB	V3, V3, V4
+	VLEG	$0, 152(R9), V18
+	VLEG	$0, 144(R9), V16
+	FMOVD	136(R9), F1
+	FMOVD	128(R9), F5
+	FMOVD	120(R9), F6
+	WFMADB	V4, V16, V5, V16
+	WFMADB	V4, V6, V1, V6
+	FMOVD	112(R9), F7
+	WFMDB	V4, V4, V1
+	WFMADB	V4, V7, V18, V7
+	VLEG	$0, 104(R9), V18
+	WFMADB	V1, V6, V16, V6
+	CMPWU	R4, R3
+	FMOVD	96(R9), F5
+	VLEG	$0, 88(R9), V16
+	WFMADB	V4, V5, V18, V5
+	VLEG	$0, 80(R9), V18
+	VLEG	$0, 72(R9), V22
+	WFMADB	V4, V16, V18, V16
+	VLEG	$0, 64(R9), V18
+	WFMADB	V1, V7, V5, V7
+	WFMADB	V4, V18, V22, V18
+	WFMDB	V1, V1, V5
+	WFMADB	V1, V16, V18, V16
+	VLEG	$0, 56(R9), V18
+	WFMADB	V5, V6, V7, V6
+	VLEG	$0, 48(R9), V22
+	FMOVD	40(R9), F7
+	WFMADB	V4, V7, V18, V7
+	VLEG	$0, 32(R9), V18
+	WFMADB	V5, V6, V16, V6
+	WFMADB	V4, V18, V22, V18
+	VLEG	$0, 24(R9), V16
+	WFMADB	V1, V7, V18, V7
+	VLEG	$0, 16(R9), V18
+	VLEG	$0, 8(R9), V22
+	WFMADB	V4, V18, V16, V18
+	VLEG	$0, 0(R9), V16
+	WFMADB	V5, V6, V7, V6
+	WFMADB	V4, V16, V22, V16
+	FMUL	F3, F4
+	WFMADB	V1, V18, V16, V1
+	FMADD	F6, F5, F1
+	WFMADB	V4, V1, V3, V4
+	BLT	L18
+	BGT	L7
+	WORD	$0xB3120022	//ltdbr	%f2,%f2
+	BLTU	L21
+L8:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L22
+L9:
+	WFCHDBS	V2, V0, V0
+	BNE	L18
+L7:
+	MOVW	R1, R6
+	CMPBGE	R6, $0, L1
+L18:
+	WORD	$0xEC223ABC	//risbg	%r2,%r2,58,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	MOVD	$·atan2xpi2h<>+0(SB), R1
+	MOVD	·atan2xpim<>+0(SB), R3
+	WORD	$0xB3C10003	//ldgr	%f0,%r3
+	WORD	$0xED021000	//madb	%f4,%f0,0(%r2,%r1)
+	BYTE	$0x40
+	BYTE	$0x1E
+L1:
+	FMOVD	F4, ret+16(FP)
+	RET
+
+L20:
+	WORD	$0xB3120022	//ltdbr	%f2,%f2
+	BLTU	L23
+	FMOVD	F2, F6
+L4:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L24
+	FMOVD	F0, F4
+L5:
+	WFCHDBS	V6, V4, V4
+	BEQ	L3
+L17:
+	WFDDB	V0, V2, V4
+	BYTE	$0x18	//lr	%r2,%r5
+	BYTE	$0x25
+	WORD	$0xB3130034	//lcdbr	%f3,%f4
+	BR	L3
+L23:
+	WORD	$0xB3130062	//lcdbr	%f6,%f2
+	BR	L4
+L22:
+	VLR	V20, V0
+	BR	L9
+L21:
+	WORD	$0xB3130022	//lcdbr	%f2,%f2
+	BR	L8
+L24:
+	VLR	V20, V4
+	BR	L5
+returnX:	//the result is same as the first argument
+	MOVD	R1, ret+16(FP)
+	RET
+returnY:	//the result is same as the second argument
+	MOVD	R2, ret+16(FP)
+	RET
+returnPi:
+	MOVD	$Pi, R1
+	MOVD	R1, ret+16(FP)
+	RET
+returnNegPi:
+	MOVD	$NegPi, R1
+	MOVD	R1, ret+16(FP)
+	RET
+posInfNegInf:
+	MOVD	$Pi3Div4, R1
+	MOVD	R1, ret+16(FP)
+	RET
+negInfNegInf:
+	MOVD	$NegPi3Div4, R1
+	MOVD	R1, ret+16(FP)
+	RET
+posInfPosInf:
+	MOVD	$PiDiv4, R1
+	MOVD	R1, ret+16(FP)
+	RET
+negInfPosInf:
+	MOVD	$NegPiDiv4, R1
+	MOVD	R1, ret+16(FP)
+	RET
+negPiPosInf:
+	MOVD	$NegZero, R1
+	MOVD	R1, ret+16(FP)
+	RET
diff --git a/src/math/atan_s390x.s b/src/math/atan_s390x.s
new file mode 100644
index 0000000..9f4eaa2
--- /dev/null
+++ b/src/math/atan_s390x.s
@@ -0,0 +1,132 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·atanrodataL8<> + 0(SB)/8, $0.199999999999554423E+00
+DATA ·atanrodataL8<> + 8(SB)/8, $0.111111110136634272E+00
+DATA ·atanrodataL8<> + 16(SB)/8, $-.142857142828026806E+00
+DATA ·atanrodataL8<> + 24(SB)/8, $-.333333333333330928E+00
+DATA ·atanrodataL8<> + 32(SB)/8, $0.769228118888682505E-01
+DATA ·atanrodataL8<> + 40(SB)/8, $0.588059263575587687E-01
+DATA ·atanrodataL8<> + 48(SB)/8, $-.666641501287528609E-01
+DATA ·atanrodataL8<> + 56(SB)/8, $-.909090711945939878E-01
+DATA ·atanrodataL8<> + 64(SB)/8, $0.472329433805024762E-01
+DATA ·atanrodataL8<> + 72(SB)/8, $0.366935664549587481E-01
+DATA ·atanrodataL8<> + 80(SB)/8, $-.422172007412067035E-01
+DATA ·atanrodataL8<> + 88(SB)/8, $-.299856214685512712E-01
+DATA ·atanrodataL8<> + 96(SB)/8, $0.220852012160300086E-01
+DATA ·atanrodataL8<> + 104(SB)/8, $0.726338160757602439E-02
+DATA ·atanrodataL8<> + 112(SB)/8, $0.843488472994227321E-03
+DATA ·atanrodataL8<> + 120(SB)/8, $0.134893651284712515E-04
+DATA ·atanrodataL8<> + 128(SB)/8, $-.525380587584426406E-01
+DATA ·atanrodataL8<> + 136(SB)/8, $-.139950258898989925E-01
+DATA ·atanrodataL8<> + 144(SB)/8, $-.291935324869629616E-02
+DATA ·atanrodataL8<> + 152(SB)/8, $-.154797890856877418E-03
+GLOBL ·atanrodataL8<> + 0(SB), RODATA, $160
+
+DATA ·atanxpi2h<> + 0(SB)/8, $0x3ff330e4e4fa7b1b
+DATA ·atanxpi2h<> + 8(SB)/8, $0xbff330e4e4fa7b1b
+DATA ·atanxpi2h<> + 16(SB)/8, $0x400330e4e4fa7b1b
+DATA ·atanxpi2h<> + 24(SB)/4, $0xc00330e4e4fa7b1b
+GLOBL ·atanxpi2h<> + 0(SB), RODATA, $32
+DATA ·atanxpim<> + 0(SB)/8, $0x3ff4f42b00000000
+GLOBL ·atanxpim<> + 0(SB), RODATA, $8
+DATA ·atanxmone<> + 0(SB)/8, $-1.0
+GLOBL ·atanxmone<> + 0(SB), RODATA, $8
+
+// Atan returns the arctangent, in radians, of the argument.
+//
+// Special cases are:
+//      Atan(±0) = ±0
+//      Atan(±Inf) = ±Pi/2Pi
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·atanAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	//special case Atan(±0) = ±0
+	FMOVD   $(0.0), F1
+	FCMPU   F0, F1
+	BEQ     atanIsZero
+
+	MOVD	$·atanrodataL8<>+0(SB), R5
+	MOVH	$0x3FE0, R3
+	WORD	$0xB3CD0010	//lgdr	%r1,%f0
+	WORD	$0xEC1120BF	//risbgn	%r1,%r1,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	RLL	$16, R1, R2
+	ANDW	$0x7FF0, R2
+	MOVW	R2, R6
+	MOVW	R3, R7
+	CMPUBLE	R6, R7, L6
+	MOVD	$·atanxmone<>+0(SB), R3
+	FMOVD	0(R3), F2
+	WFDDB	V0, V2, V0
+	WORD	$0xEC113FBF	//risbg	%r1,%r1,64-1,128+63,64+32+1
+	BYTE	$0x61
+	BYTE	$0x55
+	MOVD	$·atanxpi2h<>+0(SB), R3
+	MOVWZ	R1, R1
+	SLD	$3, R1, R1
+	WORD	$0x68813000	//ld	%f8,0(%r1,%r3)
+L6:
+	WFMDB	V0, V0, V2
+	FMOVD	152(R5), F6
+	FMOVD	144(R5), F1
+	FMOVD	136(R5), F7
+	VLEG	$0, 128(R5), V16
+	FMOVD	120(R5), F4
+	FMOVD	112(R5), F5
+	WFMADB	V2, V4, V6, V4
+	WFMADB	V2, V5, V1, V5
+	WFMDB	V2, V2, V6
+	FMOVD	104(R5), F3
+	FMOVD	96(R5), F1
+	WFMADB	V2, V3, V7, V3
+	MOVH	$0x3FE0, R1
+	FMOVD	88(R5), F7
+	WFMADB	V2, V1, V7, V1
+	FMOVD	80(R5), F7
+	WFMADB	V6, V3, V1, V3
+	WFMADB	V6, V4, V5, V4
+	WFMDB	V6, V6, V1
+	FMOVD	72(R5), F5
+	WFMADB	V2, V5, V7, V5
+	FMOVD	64(R5), F7
+	WFMADB	V2, V7, V16, V7
+	VLEG	$0, 56(R5), V16
+	WFMADB	V6, V5, V7, V5
+	WFMADB	V1, V4, V3, V4
+	FMOVD	48(R5), F7
+	FMOVD	40(R5), F3
+	WFMADB	V2, V3, V7, V3
+	FMOVD	32(R5), F7
+	WFMADB	V2, V7, V16, V7
+	VLEG	$0, 24(R5), V16
+	WFMADB	V1, V4, V5, V4
+	FMOVD	16(R5), F5
+	WFMADB	V6, V3, V7, V3
+	FMOVD	8(R5), F7
+	WFMADB	V2, V7, V5, V7
+	FMOVD	0(R5), F5
+	WFMADB	V2, V5, V16, V5
+	WFMADB	V1, V4, V3, V4
+	WFMADB	V6, V7, V5, V6
+	FMUL	F0, F2
+	FMADD	F4, F1, F6
+	FMADD	F6, F2, F0
+	MOVW	R2, R6
+	MOVW	R1, R7
+	CMPUBLE	R6, R7, L1
+	MOVD	$·atanxpim<>+0(SB), R1
+	WORD	$0xED801000	//madb	%f0,%f8,0(%r1)
+	BYTE	$0x00
+	BYTE	$0x1E
+L1:
+atanIsZero:
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/atanh.go b/src/math/atanh.go
index d59a847..8904bd6 100644
--- a/src/math/atanh.go
+++ b/src/math/atanh.go
@@ -44,7 +44,9 @@ package math
 //	Atanh(-1) = -Inf
 //	Atanh(x) = NaN if x < -1 or x > 1
 //	Atanh(NaN) = NaN
-func Atanh(x float64) float64 {
+func Atanh(x float64) float64
+
+func atanh(x float64) float64 {
 	const NearZero = 1.0 / (1 << 28) // 2**-28
 	// special cases
 	switch {
diff --git a/src/math/atanh_s390x.s b/src/math/atanh_s390x.s
new file mode 100644
index 0000000..57b61a3
--- /dev/null
+++ b/src/math/atanh_s390x.s
@@ -0,0 +1,178 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·atanhrodataL10<> + 0(SB)/8, $.41375273347623353626
+DATA ·atanhrodataL10<> + 8(SB)/8, $.51487302528619766235E+04
+DATA ·atanhrodataL10<> + 16(SB)/8, $-1.67526912689208984375
+DATA ·atanhrodataL10<> + 24(SB)/8, $0.181818181818181826E+00
+DATA ·atanhrodataL10<> + 32(SB)/8, $-.165289256198351540E-01
+DATA ·atanhrodataL10<> + 40(SB)/8, $0.200350613573012186E-02
+DATA ·atanhrodataL10<> + 48(SB)/8, $0.397389654305194527E-04
+DATA ·atanhrodataL10<> + 56(SB)/8, $-.273205381970859341E-03
+DATA ·atanhrodataL10<> + 64(SB)/8, $0.938370938292558173E-06
+DATA ·atanhrodataL10<> + 72(SB)/8, $-.148682720127920854E-06
+DATA ·atanhrodataL10<> + 80(SB)/8, $ 0.212881813645679599E-07
+DATA ·atanhrodataL10<> + 88(SB)/8, $-.602107458843052029E-05
+DATA ·atanhrodataL10<> + 96(SB)/8, $-5.5
+DATA ·atanhrodataL10<> + 104(SB)/8, $-0.5
+DATA ·atanhrodataL10<> + 112(SB)/8, $0.0
+DATA ·atanhrodataL10<> + 120(SB)/8, $0x7ff8000000000000      //Nan
+DATA ·atanhrodataL10<> + 128(SB)/8, $-1.0
+DATA ·atanhrodataL10<> + 136(SB)/8, $1.0
+DATA ·atanhrodataL10<> + 144(SB)/8, $1.0E-20
+GLOBL ·atanhrodataL10<> + 0(SB), RODATA, $152
+
+// Table of log correction terms
+DATA ·atanhtab2076<> + 0(SB)/8, $0.585235384085551248E-01
+DATA ·atanhtab2076<> + 8(SB)/8, $0.412206153771168640E-01
+DATA ·atanhtab2076<> + 16(SB)/8, $0.273839003221648339E-01
+DATA ·atanhtab2076<> + 24(SB)/8, $0.166383778368856480E-01
+DATA ·atanhtab2076<> + 32(SB)/8, $0.866678223433169637E-02
+DATA ·atanhtab2076<> + 40(SB)/8, $0.319831684989627514E-02
+DATA ·atanhtab2076<> + 48(SB)/8, $0.000000000000000000E+00
+DATA ·atanhtab2076<> + 56(SB)/8, $-.113006378583725549E-02
+DATA ·atanhtab2076<> + 64(SB)/8, $-.367979419636602491E-03
+DATA ·atanhtab2076<> + 72(SB)/8, $0.213172484510484979E-02
+DATA ·atanhtab2076<> + 80(SB)/8, $0.623271047682013536E-02
+DATA ·atanhtab2076<> + 88(SB)/8, $0.118140812789696885E-01
+DATA ·atanhtab2076<> + 96(SB)/8, $0.187681358930914206E-01
+DATA ·atanhtab2076<> + 104(SB)/8, $0.269985148668178992E-01
+DATA ·atanhtab2076<> + 112(SB)/8, $0.364186619761331328E-01
+DATA ·atanhtab2076<> + 120(SB)/8, $0.469505379381388441E-01
+GLOBL ·atanhtab2076<> + 0(SB), RODATA, $128
+
+// Table of +/- .5
+DATA ·atanhtabh2075<> + 0(SB)/8, $0.5
+DATA ·atanhtabh2075<> + 8(SB)/8, $-.5
+GLOBL ·atanhtabh2075<> + 0(SB), RODATA, $16
+
+// Atanh returns the inverse hyperbolic tangent of the argument.
+//
+// Special cases are:
+//      Atanh(1) = +Inf
+//      Atanh(±0) = ±0
+//      Atanh(-1) = -Inf
+//      Atanh(x) = NaN if x < -1 or x > 1
+//      Atanh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT    ·atanhAsm(SB), NOSPLIT, $0-16
+    FMOVD   x+0(FP), F0
+    MOVD    $·atanhrodataL10<>+0(SB), R5
+    WORD    $0xB3CD0010	//lgdr %r1, %f0
+    WORD    $0xC0393FEF //iilf  %r3,1072693247
+    BYTE    $0xFF
+    BYTE    $0xFF
+    SRAD    $32, R1
+    WORD    $0xB9170021 //llgtr %r2,%r1
+    MOVW    R2, R6
+    MOVW    R3, R7
+    CMPBGT  R6, R7, L2
+    WORD    $0xC0392FFF //iilf  %r3,805306367
+    BYTE    $0xFF
+    BYTE    $0xFF
+    MOVW    R2, R6
+    MOVW    R3, R7
+    CMPBGT  R6, R7, L9
+L3:
+    FMOVD   144(R5), F2
+    FMADD   F2, F0, F0
+L1:
+    FMOVD   F0, ret+8(FP)
+    RET
+
+L2:
+    WORD    $0xED005088 //cdb   %f0,.L12-.L10(%r5)
+    BYTE    $0x00
+    BYTE    $0x19
+    BEQ L5
+    WORD    $0xED005080 //cdb   %f0,.L13-.L10(%r5)
+    BYTE    $0x00
+    BYTE    $0x19
+    BEQ L5
+    WFCEDBS V0, V0, V2
+    BVS L1
+    FMOVD   120(R5), F0
+    BR  L1
+L5:
+    WORD    $0xED005070 //ddb   %f0,.L15-.L10(%r5)
+    BYTE    $0x00
+    BYTE    $0x1D
+    FMOVD   F0, ret+8(FP)
+    RET
+
+L9:
+    FMOVD   F0, F2
+    MOVD    $·atanhtabh2075<>+0(SB), R2
+    SRW $31, R1, R1
+    FMOVD   104(R5), F4
+    MOVW    R1, R1
+    SLD $3, R1, R1
+    WORD    $0x68012000 //ld    %f0,0(%r1,%r2)
+    WFMADB  V2, V4, V0, V4
+    VLEG    $0, 96(R5), V16
+    FDIV    F4, F2
+    WORD    $0xC0298006 //iilf  %r2,2147909631
+    BYTE    $0x7F
+    BYTE    $0xFF
+    FMOVD   88(R5), F6
+    FMOVD   80(R5), F1
+    FMOVD   72(R5), F7
+    FMOVD   64(R5), F5
+    FMOVD   F2, F4
+    WORD    $0xED405088 //adb   %f4,.L12-.L10(%r5)
+    BYTE    $0x00
+    BYTE    $0x1A
+    WORD    $0xB3CD0044	//lgdr %r4, %f4
+    SRAD    $32, R4
+    FMOVD   F4, F3
+    WORD    $0xED305088 //sdb   %f3,.L12-.L10(%r5)
+    BYTE    $0x00
+    BYTE    $0x1B
+    SUBW    R4, R2
+    WFSDB   V3, V2, V3
+    WORD    $0xEC1220AF //risbg %r1,%r2,32,128+47,0
+    BYTE    $0x00
+    BYTE    $0x55
+    SLD $32, R1, R1
+    WORD    $0xB3C10021 //ldgr  %f2,%r1
+    WFMADB  V4, V2, V16, V4
+    SRAW    $8, R2, R1
+    WFMADB  V4, V5, V6, V5
+    WFMDB   V4, V4, V6
+    WFMADB  V4, V1, V7, V1
+    WFMADB  V2, V3, V4, V2
+    WFMADB  V1, V6, V5, V1
+    FMOVD   56(R5), F3
+    FMOVD   48(R5), F5
+    WFMADB  V4, V5, V3, V4
+    FMOVD   40(R5), F3
+    FMADD   F1, F6, F4
+    FMOVD   32(R5), F1
+    FMADD   F3, F2, F1
+    ANDW    $0xFFFFFF00, R1
+    WFMADB  V6, V4, V1, V6
+    FMOVD   24(R5), F3
+    ORW $0x45000000, R1
+    WFMADB  V2, V6, V3, V6
+    VLVGF   $0, R1, V4
+    LDEBR   F4, F4
+    WORD    $0xEC2239BC //risbg %r2,%r2,57,128+60,64-13
+    BYTE    $0x33
+    BYTE    $0x55
+    MOVD    $·atanhtab2076<>+0(SB), R1
+    FMOVD   16(R5), F3
+    WORD    $0x68521000 //ld    %f5,0(%r2,%r1)
+    FMOVD   8(R5), F1
+    WFMADB  V2, V6, V5, V2
+    WFMADB  V4, V3, V1, V4
+    FMOVD   0(R5), F6
+    FMADD   F6, F4, F2
+    FMUL    F2, F0
+    FMOVD   F0, ret+8(FP)
+    RET
diff --git a/src/math/big/arith.go b/src/math/big/arith.go
index d7ea838..ad35240 100644
--- a/src/math/big/arith.go
+++ b/src/math/big/arith.go
@@ -8,18 +8,17 @@
 
 package big
 
+import "math/bits"
+
 // A Word represents a single digit of a multi-precision unsigned integer.
-type Word uintptr
+type Word uint
 
 const (
-	// Compute the size _S of a Word in bytes.
-	_m    = ^Word(0)
-	_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
-	_S    = 1 << _logS
+	_S = _W / 8 // word size in bytes
 
-	_W = _S << 3 // word size in bits
-	_B = 1 << _W // digit base
-	_M = _B - 1  // digit mask
+	_W = bits.UintSize // word size in bits
+	_B = 1 << _W       // digit base
+	_M = _B - 1        // digit mask
 
 	_W2 = _W / 2   // half word size in bits
 	_B2 = 1 << _W2 // half digit base
@@ -77,54 +76,10 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
 	return
 }
 
-// Length of x in bits.
-func bitLen_g(x Word) (n int) {
-	for ; x >= 0x8000; x >>= 16 {
-		n += 16
-	}
-	if x >= 0x80 {
-		x >>= 8
-		n += 8
-	}
-	if x >= 0x8 {
-		x >>= 4
-		n += 4
-	}
-	if x >= 0x2 {
-		x >>= 2
-		n += 2
-	}
-	if x >= 0x1 {
-		n++
-	}
-	return
-}
-
-// log2 computes the integer binary logarithm of x.
-// The result is the integer n for which 2^n <= x < 2^(n+1).
-// If x == 0, the result is -1.
-func log2(x Word) int {
-	return bitLen(x) - 1
-}
-
 // nlz returns the number of leading zeros in x.
+// Wraps bits.LeadingZeros call for convenience.
 func nlz(x Word) uint {
-	return uint(_W - bitLen(x))
-}
-
-// nlz64 returns the number of leading zeros in x.
-func nlz64(x uint64) uint {
-	switch _W {
-	case 32:
-		w := x >> 32
-		if w == 0 {
-			return 32 + nlz(Word(x))
-		}
-		return nlz(Word(w))
-	case 64:
-		return nlz(Word(x))
-	}
-	panic("unreachable")
+	return uint(bits.LeadingZeros(uint(x)))
 }
 
 // q = (u1<<_W + u0 - r)/y
diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s
index 7c8ab8f..6c080f0 100644
--- a/src/math/big/arith_386.s
+++ b/src/math/big/arith_386.s
@@ -269,14 +269,3 @@ E7:	SUBL $1, BX		// i--
 
 	MOVL DX, r+32(FP)
 	RET
-
-// func bitLen(x Word) (n int)
-TEXT ·bitLen(SB),NOSPLIT,$0
-	BSRL x+0(FP), AX
-	JZ Z1
-	INCL AX
-	MOVL AX, n+4(FP)
-	RET
-
-Z1:	MOVL $0, n+4(FP)
-	RET
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index a7eba67..7e50224 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -450,14 +450,3 @@ E7:	SUBQ $1, BX		// i--
 
 	MOVQ DX, r+64(FP)
 	RET
-
-// func bitLen(x Word) (n int)
-TEXT ·bitLen(SB),NOSPLIT,$0
-	BSRQ x+0(FP), AX
-	JZ Z1
-	ADDQ $1, AX
-	MOVQ AX, n+8(FP)
-	RET
-
-Z1:	MOVQ $0, n+8(FP)
-	RET
diff --git a/src/math/big/arith_amd64p32.s b/src/math/big/arith_amd64p32.s
index 6006646..0a67238 100644
--- a/src/math/big/arith_amd64p32.s
+++ b/src/math/big/arith_amd64p32.s
@@ -38,6 +38,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 
 TEXT ·divWVW(SB),NOSPLIT,$0
 	JMP ·divWVW_g(SB)
-
-TEXT ·bitLen(SB),NOSPLIT,$0
-	JMP ·bitLen_g(SB)
diff --git a/src/math/big/arith_arm.s b/src/math/big/arith_arm.s
index 69590ff..ba65fd2 100644
--- a/src/math/big/arith_arm.s
+++ b/src/math/big/arith_arm.s
@@ -292,11 +292,3 @@ TEXT ·mulWW(SB),NOSPLIT,$0
 	MOVW	R4, z1+8(FP)
 	MOVW	R3, z0+12(FP)
 	RET
-
-// func bitLen(x Word) (n int)
-TEXT ·bitLen(SB),NOSPLIT,$0
-	MOVW	x+0(FP), R0
-	CLZ 	R0, R0
-	RSB	$32, R0
-	MOVW	R0, n+4(FP)
-	RET
diff --git a/src/math/big/arith_arm64.s b/src/math/big/arith_arm64.s
index 24a717c..397b463 100644
--- a/src/math/big/arith_arm64.s
+++ b/src/math/big/arith_arm64.s
@@ -165,13 +165,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 // func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
 TEXT ·divWVW(SB),NOSPLIT,$0
 	B ·divWVW_g(SB)
-
-
-// func bitLen(x Word) (n int)
-TEXT ·bitLen(SB),NOSPLIT,$0
-	MOVD	x+0(FP), R0
-	CLZ	R0, R0
-	MOVD	$64, R1
-	SUB	R0, R1, R0
-	MOVD	R0, n+8(FP)
-	RET
diff --git a/src/math/big/arith_decl.go b/src/math/big/arith_decl.go
index 5433b6d..41e5923 100644
--- a/src/math/big/arith_decl.go
+++ b/src/math/big/arith_decl.go
@@ -18,4 +18,3 @@ func shrVU(z, x []Word, s uint) (c Word)
 func mulAddVWW(z, x []Word, y, r Word) (c Word)
 func addMulVVW(z, x []Word, y Word) (c Word)
 func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
-func bitLen(x Word) (n int)
diff --git a/src/math/big/arith_decl_pure.go b/src/math/big/arith_decl_pure.go
index 21775dd..4ae49c1 100644
--- a/src/math/big/arith_decl_pure.go
+++ b/src/math/big/arith_decl_pure.go
@@ -49,7 +49,3 @@ func addMulVVW(z, x []Word, y Word) (c Word) {
 func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
 	return divWVW_g(z, xn, x, y)
 }
-
-func bitLen(x Word) (n int) {
-	return bitLen_g(x)
-}
diff --git a/src/math/big/arith_mips64x.s b/src/math/big/arith_mips64x.s
index f9288fc..983510e 100644
--- a/src/math/big/arith_mips64x.s
+++ b/src/math/big/arith_mips64x.s
@@ -41,6 +41,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 
 TEXT ·divWVW(SB),NOSPLIT,$0
 	JMP ·divWVW_g(SB)
-
-TEXT ·bitLen(SB),NOSPLIT,$0
-	JMP ·bitLen_g(SB)
diff --git a/src/math/big/arith_mipsx.s b/src/math/big/arith_mipsx.s
index ac23114..54cafbd 100644
--- a/src/math/big/arith_mipsx.s
+++ b/src/math/big/arith_mipsx.s
@@ -41,6 +41,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 
 TEXT ·divWVW(SB),NOSPLIT,$0
 	JMP	·divWVW_g(SB)
-
-TEXT ·bitLen(SB),NOSPLIT,$0
-	JMP	·bitLen_g(SB)
diff --git a/src/math/big/arith_ppc64.s b/src/math/big/arith_ppc64.s
deleted file mode 100644
index 47fe8f1..0000000
--- a/src/math/big/arith_ppc64.s
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !math_big_pure_go,ppc64
-
-#include "textflag.h"
-
-// This file provides fast assembly versions for the elementary
-// arithmetic operations on vectors implemented in arith.go.
-
-TEXT ·divWW(SB), NOSPLIT, $0
-	BR ·divWW_g(SB)
-
diff --git a/src/math/big/arith_ppc64le.s b/src/math/big/arith_ppc64le.s
deleted file mode 100644
index b78cdfe..0000000
--- a/src/math/big/arith_ppc64le.s
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2016 The Go Authors. 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,ppc64le
-
-#include "textflag.h"
-
-// This file provides fast assembly versions for the elementary
-// arithmetic operations on vectors implemented in arith.go.
-
-// func divWW(x1, x0, y Word) (q, r Word)
-TEXT ·divWW(SB), NOSPLIT, $0
-	MOVD x1+0(FP), R4
-	MOVD x0+8(FP), R5
-	MOVD y+16(FP), R6
-
-	CMPU R4, R6
-	BGE  divbigger
-
-	// from the programmer's note in ch. 3 of the ISA manual, p.74
-	DIVDEU R6, R4, R3
-	DIVDU  R6, R5, R7
-	MULLD  R6, R3, R8
-	MULLD  R6, R7, R20
-	SUB    R20, R5, R10
-	ADD    R7, R3, R3
-	SUB    R8, R10, R4
-	CMPU   R4, R10
-	BLT    adjust
-	CMPU   R4, R6
-	BLT    end
-
-adjust:
-	MOVD $1, R21
-	ADD  R21, R3, R3
-	SUB  R6, R4, R4
-
-end:
-	MOVD R3, q+24(FP)
-	MOVD R4, r+32(FP)
-
-	RET
-
-divbigger:
-	MOVD $-1, R7
-	MOVD R7, q+24(FP)
-	MOVD R7, r+32(FP)
-	RET
-
diff --git a/src/math/big/arith_ppc64x.s b/src/math/big/arith_ppc64x.s
index 89d1cbf..5ed3de6 100644
--- a/src/math/big/arith_ppc64x.s
+++ b/src/math/big/arith_ppc64x.s
@@ -19,8 +19,35 @@ TEXT ·mulWW(SB), NOSPLIT, $0
 	MOVD   R7, z0+24(FP)
 	RET
 
+// func addVV(z, y, y []Word) (c Word)
+// z[i] = x[i] + y[i] for all i, carrying
 TEXT ·addVV(SB), NOSPLIT, $0
-	BR ·addVV_g(SB)
+	MOVD  z_len+8(FP), R7
+	MOVD  x+24(FP), R8
+	MOVD  y+48(FP), R9
+	MOVD  z+0(FP), R10
+
+	MOVD  R0, R4
+	MOVD  R0, R6  // R6 will be the address index
+	ADDC R4, R4   // clear CA
+	MOVD  R7, CTR
+
+	CMP   R0, R7
+	BEQ   done
+
+loop:
+	MOVD  (R8)(R6), R11   // x[i]
+	MOVD  (R9)(R6), R12   // y[i]
+	ADDE  R12, R11, R15   // x[i] + y[i] + CA
+	MOVD  R15, (R10)(R6)  // z[i]
+
+	ADD $8, R6
+	BC  16, 0, loop	// bdnz
+
+done:
+	ADDZE R4
+	MOVD  R4, c+72(FP)
+	RET
 
 // func subVV(z, x, y []Word) (c Word)
 // z[i] = x[i] - y[i] for all i, carrying
@@ -30,32 +57,30 @@ TEXT ·subVV(SB), NOSPLIT, $0
 	MOVD y+48(FP), R9
 	MOVD z+0(FP), R10
 
-	MOVD $0, R4  // c = 0
-	MOVD $0, R5  // i = 0
-	MOVD $1, R29 // work around lack of ADDI
-	MOVD $8, R28 // work around lack of scaled addressing
-
+	MOVD  R0, R4  // c = 0
+	MOVD  R0, R6
 	SUBC R0, R0  // clear CA
-	JMP  sublend
+	MOVD  R7, CTR
+
+	CMP R0, R7
+	BEQ  sublend
 
 // amd64 saves and restores CF, but I believe they only have to do that because all of
 // their math operations clobber it - we should just be able to recover it at the end.
 subloop:
-	MULLD R5, R28, R6
 	MOVD  (R8)(R6), R11 // x[i]
 	MOVD  (R9)(R6), R12 // y[i]
 
 	SUBE R12, R11, R15
 	MOVD R15, (R10)(R6)
 
-	ADD R29, R5 // i++
+	ADD $8, R6
+	BC  16, 0, subloop  // bdnz
 
 sublend:
-	CMP R5, R7
-	BLT subloop
 
 	ADDZE R4
-	XOR   R29, R4
+	XOR   $1, R4
 	MOVD  R4, c+72(FP)
 	RET
 
@@ -173,14 +198,44 @@ end:
 	MOVD R4, c+56(FP)
 	RET
 
-TEXT ·divWVW(SB), NOSPLIT, $0
-	BR ·divWVW_g(SB)
+// func divWW(x1, x0, y Word) (q, r Word)
+TEXT ·divWW(SB), NOSPLIT, $0
+	MOVD x1+0(FP), R4
+	MOVD x0+8(FP), R5
+	MOVD y+16(FP), R6
+
+	CMPU R4, R6
+	BGE  divbigger
+
+	// from the programmer's note in ch. 3 of the ISA manual, p.74
+	DIVDEU R6, R4, R3
+	DIVDU  R6, R5, R7
+	MULLD  R6, R3, R8
+	MULLD  R6, R7, R20
+	SUB    R20, R5, R10
+	ADD    R7, R3, R3
+	SUB    R8, R10, R4
+	CMPU   R4, R10
+	BLT    adjust
+	CMPU   R4, R6
+	BLT    end
+
+adjust:
+	MOVD $1, R21
+	ADD  R21, R3, R3
+	SUB  R6, R4, R4
+
+end:
+	MOVD R3, q+24(FP)
+	MOVD R4, r+32(FP)
 
-// func bitLen(x Word) int
-TEXT ·bitLen(SB), NOSPLIT, $0
-	MOVD   x+0(FP), R4
-	CNTLZD R4, R4
-	MOVD   $64, R5
-	SUB    R4, R5
-	MOVD   R5, n+8(FP)
 	RET
+
+divbigger:
+	MOVD $-1, R7
+	MOVD R7, q+24(FP)
+	MOVD R7, r+32(FP)
+	RET
+
+TEXT ·divWVW(SB), NOSPLIT, $0
+	BR ·divWVW_g(SB)
diff --git a/src/math/big/arith_s390x.s b/src/math/big/arith_s390x.s
index bddfd9e..4520d16 100644
--- a/src/math/big/arith_s390x.s
+++ b/src/math/big/arith_s390x.s
@@ -1237,13 +1237,3 @@ E7:	SUB	$1, R7		// i--
 
 	MOVD	R10, r+64(FP)
 	RET
-
-// func bitLen(x Word) (n int)
-TEXT ·bitLen(SB),NOSPLIT,$0
-	MOVD  x+0(FP), R2
-	FLOGR R2, R2 // clobbers R3
-	MOVD  $64, R3
-	SUB   R2, R3
-	MOVD  R3, n+8(FP)
-	RET
-
diff --git a/src/math/big/arith_s390x_test.go b/src/math/big/arith_s390x_test.go
index 31a777e..eaf8f23 100644
--- a/src/math/big/arith_s390x_test.go
+++ b/src/math/big/arith_s390x_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.
 
-// +build s390x !math_big_pure_go
+// +build s390x,!math_big_pure_go
 
 package big
 
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index f2b3083..13b0436 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/big/arith_test.go
@@ -395,32 +395,3 @@ func BenchmarkAddMulVVW(b *testing.B) {
 		})
 	}
 }
-
-func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
-	for i := 0; i <= _W; i++ {
-		x := Word(1) << uint(i-1) // i == 0 => x == 0
-		n := f(x)
-		if n != i {
-			t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
-		}
-	}
-}
-
-func TestWordBitLen(t *testing.T) {
-	testWordBitLen(t, "bitLen", bitLen)
-	testWordBitLen(t, "bitLen_g", bitLen_g)
-}
-
-// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
-func 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)
-			}
-		})
-	}
-}
diff --git a/src/math/big/float.go b/src/math/big/float.go
index aabd7b4..7e11f1a 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -14,6 +14,7 @@ package big
 import (
 	"fmt"
 	"math"
+	"math/bits"
 )
 
 const debugFloat = false // enable for debugging
@@ -97,7 +98,7 @@ const (
 // the slice may (but doesn't have to) be shorter if the mantissa contains
 // trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e.,
 // the msb is shifted all the way "to the left"). Thus, if the mantissa has
-// trailing 0 bits or x.prec is not a multiple of the the Word size _W,
+// trailing 0 bits or x.prec is not a multiple of the Word size _W,
 // x.mant[0] has trailing zero bits. The msb of the mantissa corresponds
 // to the value 0.5; the exponent x.exp shifts the binary point as needed.
 //
@@ -498,8 +499,8 @@ func (z *Float) setBits64(neg bool, x uint64) *Float {
 	}
 	// x != 0
 	z.form = finite
-	s := nlz64(x)
-	z.mant = z.mant.setUint64(x << s)
+	s := bits.LeadingZeros64(x)
+	z.mant = z.mant.setUint64(x << uint(s))
 	z.exp = int32(64 - s) // always fits
 	if z.prec < 64 {
 		z.round(0)
@@ -1438,8 +1439,16 @@ func (z *Float) Add(x, y *Float) *Float {
 
 	if x.form == finite && y.form == finite {
 		// x + y (common case)
+
+		// Below we set z.neg = x.neg, and when z aliases y this will
+		// change the y operand's sign. This is fine, because if an
+		// operand aliases the receiver it'll be overwritten, but we still
+		// want the original x.neg and y.neg values when we evaluate
+		// x.neg != y.neg, so we need to save y.neg before setting z.neg.
+		yneg := y.neg
+
 		z.neg = x.neg
-		if x.neg == y.neg {
+		if x.neg == yneg {
 			// x + y == x + y
 			// (-x) + (-y) == -(x + y)
 			z.uadd(x, y)
@@ -1501,8 +1510,9 @@ func (z *Float) Sub(x, y *Float) *Float {
 
 	if x.form == finite && y.form == finite {
 		// x - y (common case)
+		yneg := y.neg
 		z.neg = x.neg
-		if x.neg != y.neg {
+		if x.neg != yneg {
 			// x - (-y) == x + y
 			// (-x) - y == -(x + y)
 			z.uadd(x, y)
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index 7d4bd31..5fd49bb 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -1325,6 +1325,34 @@ func TestFloatAdd64(t *testing.T) {
 	}
 }
 
+func TestIssue20490(t *testing.T) {
+	var tests = []struct {
+		a, b float64
+	}{
+		{4, 1},
+		{-4, 1},
+		{4, -1},
+		{-4, -1},
+	}
+
+	for _, test := range tests {
+		a, b := NewFloat(test.a), NewFloat(test.b)
+		diff := new(Float).Sub(a, b)
+		b.Sub(a, b)
+		if b.Cmp(diff) != 0 {
+			t.Errorf("got %g - %g = %g; want %g\n", a, NewFloat(test.b), b, diff)
+		}
+
+		b = NewFloat(test.b)
+		sum := new(Float).Add(a, b)
+		b.Add(a, b)
+		if b.Cmp(sum) != 0 {
+			t.Errorf("got %g + %g = %g; want %g\n", a, NewFloat(test.b), b, sum)
+		}
+
+	}
+}
+
 // TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
 // multiplication/division of arguments represented by Bits values with the
 // respective Float multiplication/division for a variety of precisions
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index edcb2eb..6d0f17d 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -8,10 +8,13 @@ import (
 	"bytes"
 	"fmt"
 	"math"
+	"math/bits"
 	"strconv"
 	"testing"
 )
 
+var zero_ float64
+
 func TestFloatSetFloat64String(t *testing.T) {
 	inf := math.Inf(0)
 	nan := math.NaN()
@@ -22,7 +25,7 @@ func TestFloatSetFloat64String(t *testing.T) {
 	}{
 		// basics
 		{"0", 0},
-		{"-0", -0},
+		{"-0", -zero_},
 		{"+0", 0},
 		{"1", 1},
 		{"-1", -1},
@@ -36,10 +39,10 @@ func TestFloatSetFloat64String(t *testing.T) {
 
 		// various zeros
 		{"0e100", 0},
-		{"-0e+100", 0},
+		{"-0e+100", -zero_},
 		{"+0e-100", 0},
 		{"0E100", 0},
-		{"-0E+100", 0},
+		{"-0E+100", -zero_},
 		{"+0E-100", 0},
 
 		// various decimal exponent formats
@@ -78,7 +81,7 @@ func TestFloatSetFloat64String(t *testing.T) {
 
 		// decimal mantissa, binary exponent
 		{"0p0", 0},
-		{"-0p0", -0},
+		{"-0p0", -zero_},
 		{"1p10", 1 << 10},
 		{"1p+10", 1 << 10},
 		{"+1p-10", 1.0 / (1 << 10)},
@@ -88,9 +91,9 @@ func TestFloatSetFloat64String(t *testing.T) {
 
 		// binary mantissa, decimal exponent
 		{"0b0", 0},
-		{"-0b0", -0},
+		{"-0b0", -zero_},
 		{"0b0e+10", 0},
-		{"-0b0e-10", -0},
+		{"-0b0e-10", -zero_},
 		{"0b1010", 10},
 		{"0B1010E2", 1000},
 		{"0b.1", 0.5},
@@ -99,7 +102,7 @@ func TestFloatSetFloat64String(t *testing.T) {
 
 		// binary mantissa, binary exponent
 		{"0b0p+10", 0},
-		{"-0b0p-10", -0},
+		{"-0b0p-10", -zero_},
 		{"0b.1010p4", 10},
 		{"0b1p-1", 0.5},
 		{"0b001p-3", 0.125},
@@ -108,9 +111,9 @@ func TestFloatSetFloat64String(t *testing.T) {
 
 		// hexadecimal mantissa and exponent
 		{"0x0", 0},
-		{"-0x0", -0},
+		{"-0x0", -zero_},
 		{"0x0p+10", 0},
-		{"-0x0p-10", -0},
+		{"-0x0p-10", -zero_},
 		{"0xff", 255},
 		{"0X.8p1", 1},
 		{"-0X0.00008p16", -0.5},
@@ -134,8 +137,8 @@ func TestFloatSetFloat64String(t *testing.T) {
 		}
 		f, _ := x.Float64()
 		want := new(Float).SetFloat64(test.x)
-		if x.Cmp(want) != 0 {
-			t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
+		if x.Cmp(want) != 0 || x.Signbit() != want.Signbit() {
+			t.Errorf("%s: got %v (%v); want %v", test.s, &x, f, test.x)
 		}
 	}
 }
@@ -326,9 +329,9 @@ func TestFloat64Text(t *testing.T) {
 
 // actualPrec returns the number of actually used mantissa bits.
 func actualPrec(x float64) uint {
-	if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 {
+	if mant := math.Float64bits(x); x != 0 && mant&(0x7ff<<52) == 0 {
 		// x is denormalized
-		return 64 - nlz64(bits&(1<<52-1))
+		return 64 - uint(bits.LeadingZeros64(mant&(1<<52-1)))
 	}
 	return 53
 }
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 1d8dabc..62f7fc5 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -324,22 +324,22 @@ func (x *Int) Cmp(y *Int) (r int) {
 	return
 }
 
-// low32 returns the least significant 32 bits of z.
-func low32(z nat) uint32 {
-	if len(z) == 0 {
+// low32 returns the least significant 32 bits of x.
+func low32(x nat) uint32 {
+	if len(x) == 0 {
 		return 0
 	}
-	return uint32(z[0])
+	return uint32(x[0])
 }
 
-// low64 returns the least significant 64 bits of z.
-func low64(z nat) uint64 {
-	if len(z) == 0 {
+// low64 returns the least significant 64 bits of x.
+func low64(x nat) uint64 {
+	if len(x) == 0 {
 		return 0
 	}
-	v := uint64(z[0])
-	if _W == 32 && len(z) > 1 {
-		v |= uint64(z[1]) << 32
+	v := uint64(x[0])
+	if _W == 32 && len(x) > 1 {
+		return uint64(x[1])<<32 | v
 	}
 	return v
 }
@@ -360,6 +360,20 @@ func (x *Int) Uint64() uint64 {
 	return low64(x.abs)
 }
 
+// IsInt64 reports whether x can be represented as an int64.
+func (x *Int) IsInt64() bool {
+	if len(x.abs) <= 64/_W {
+		w := int64(low64(x.abs))
+		return w >= 0 || x.neg && w == -w
+	}
+	return false
+}
+
+// IsUint64 reports whether x can be represented as a uint64.
+func (x *Int) IsUint64() bool {
+	return !x.neg && len(x.abs) <= 64/_W
+}
+
 // SetString sets z to the value of s, interpreted in the given base,
 // and returns z and a boolean indicating success. The entire string
 // (not just a prefix) must be valid for success. If SetString fails,
@@ -556,7 +570,7 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 // Rand sets z to a pseudo-random number in [0, n) and returns z.
 func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 	z.neg = false
-	if n.neg == true || len(n.abs) == 0 {
+	if n.neg || len(n.abs) == 0 {
 		z.abs = nil
 		return z
 	}
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index b8e0778..42e810b 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -7,8 +7,8 @@ package big
 import (
 	"bytes"
 	"encoding/hex"
-	"fmt"
 	"math/rand"
+	"strconv"
 	"strings"
 	"testing"
 	"testing/quick"
@@ -260,7 +260,7 @@ func BenchmarkBinomial(b *testing.B) {
 var divisionSignsTests = []struct {
 	x, y int64
 	q, r int64 // T-division
-	d, m int64 // Euclidian division
+	d, m int64 // Euclidean division
 }{
 	{5, 3, 1, 2, 1, 2},
 	{-5, 3, -1, -2, -2, 1},
@@ -903,56 +903,105 @@ func TestLshRsh(t *testing.T) {
 	}
 }
 
-var int64Tests = []int64{
-	0,
-	1,
-	-1,
-	4294967295,
-	-4294967295,
-	4294967296,
-	-4294967296,
-	9223372036854775807,
-	-9223372036854775807,
-	-9223372036854775808,
+var int64Tests = []string{
+	// int64
+	"0",
+	"1",
+	"-1",
+	"4294967295",
+	"-4294967295",
+	"4294967296",
+	"-4294967296",
+	"9223372036854775807",
+	"-9223372036854775807",
+	"-9223372036854775808",
+
+	// not int64
+	"0x8000000000000000",
+	"-0x8000000000000001",
+	"38579843757496759476987459679745",
+	"-38579843757496759476987459679745",
 }
 
 func TestInt64(t *testing.T) {
-	for i, testVal := range int64Tests {
-		in := NewInt(testVal)
-		out := in.Int64()
+	for _, s := range int64Tests {
+		var x Int
+		_, ok := x.SetString(s, 0)
+		if !ok {
+			t.Errorf("SetString(%s, 0) failed", s)
+			continue
+		}
+
+		want, err := strconv.ParseInt(s, 0, 64)
+		if err != nil {
+			if err.(*strconv.NumError).Err == strconv.ErrRange {
+				if x.IsInt64() {
+					t.Errorf("IsInt64(%s) succeeded unexpectedly", s)
+				}
+			} else {
+				t.Errorf("ParseInt(%s) failed", s)
+			}
+			continue
+		}
+
+		if !x.IsInt64() {
+			t.Errorf("IsInt64(%s) failed unexpectedly", s)
+		}
 
-		if out != testVal {
-			t.Errorf("#%d got %d want %d", i, out, testVal)
+		got := x.Int64()
+		if got != want {
+			t.Errorf("Int64(%s) = %d; want %d", s, got, want)
 		}
 	}
 }
 
-var uint64Tests = []uint64{
-	0,
-	1,
-	4294967295,
-	4294967296,
-	8589934591,
-	8589934592,
-	9223372036854775807,
-	9223372036854775808,
-	18446744073709551615, // 1<<64 - 1
+var uint64Tests = []string{
+	// uint64
+	"0",
+	"1",
+	"4294967295",
+	"4294967296",
+	"8589934591",
+	"8589934592",
+	"9223372036854775807",
+	"9223372036854775808",
+	"0x08000000000000000",
+
+	// not uint64
+	"0x10000000000000000",
+	"-0x08000000000000000",
+	"-1",
 }
 
 func TestUint64(t *testing.T) {
-	in := new(Int)
-	for i, testVal := range uint64Tests {
-		in.SetUint64(testVal)
-		out := in.Uint64()
+	for _, s := range uint64Tests {
+		var x Int
+		_, ok := x.SetString(s, 0)
+		if !ok {
+			t.Errorf("SetString(%s, 0) failed", s)
+			continue
+		}
+
+		want, err := strconv.ParseUint(s, 0, 64)
+		if err != nil {
+			// check for sign explicitly (ErrRange doesn't cover signed input)
+			if s[0] == '-' || err.(*strconv.NumError).Err == strconv.ErrRange {
+				if x.IsUint64() {
+					t.Errorf("IsUint64(%s) succeeded unexpectedly", s)
+				}
+			} else {
+				t.Errorf("ParseUint(%s) failed", s)
+			}
+			continue
+		}
 
-		if out != testVal {
-			t.Errorf("#%d got %d want %d", i, out, testVal)
+		if !x.IsUint64() {
+			t.Errorf("IsUint64(%s) failed unexpectedly", s)
 		}
 
-		str := fmt.Sprint(testVal)
-		strOut := in.String()
-		if strOut != str {
-			t.Errorf("#%d.String got %s want %s", i, strOut, str)
+		got := x.Uint64()
+		if got != want {
+			t.Errorf("Uint64(%s) = %d; want %d", s, got, want)
 		}
 	}
 }
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 9b1a626..889eacb 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -9,6 +9,7 @@
 package big
 
 import (
+	"math/bits"
 	"math/rand"
 	"sync"
 )
@@ -67,24 +68,14 @@ func (z nat) setWord(x Word) nat {
 }
 
 func (z nat) setUint64(x uint64) nat {
-	// single-digit values
+	// single-word value
 	if w := Word(x); uint64(w) == x {
 		return z.setWord(w)
 	}
-
-	// compute number of words n required to represent x
-	n := 0
-	for t := x; t > 0; t >>= _W {
-		n++
-	}
-
-	// split x into n words
-	z = z.make(n)
-	for i := range z {
-		z[i] = Word(x & _M)
-		x >>= _W
-	}
-
+	// 2-word value
+	z = z.make(2)
+	z[1] = Word(x >> 32)
+	z[0] = Word(x)
 	return z
 }
 
@@ -653,49 +644,11 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 // Length of x in bits. x must be normalized.
 func (x nat) bitLen() int {
 	if i := len(x) - 1; i >= 0 {
-		return i*_W + bitLen(x[i])
+		return i*_W + bits.Len(uint(x[i]))
 	}
 	return 0
 }
 
-const deBruijn32 = 0x077CB531
-
-var deBruijn32Lookup = [...]byte{
-	0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
-	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
-}
-
-const deBruijn64 = 0x03f79d71b4ca8b09
-
-var deBruijn64Lookup = [...]byte{
-	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
-	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
-	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
-	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
-}
-
-// trailingZeroBits returns the number of consecutive least significant zero
-// bits of x.
-func trailingZeroBits(x Word) uint {
-	// x & -x leaves only the right-most bit set in the word. Let k be the
-	// index of that bit. Since only a single bit is set, the value is two
-	// to the power of k. Multiplying by a power of two is equivalent to
-	// left shifting, in this case by k bits. The de Bruijn constant is
-	// such that all six bit, consecutive substrings are distinct.
-	// Therefore, if we have a left shifted version of this constant we can
-	// find by how many bits it was shifted by looking at which six bit
-	// substring ended up at the top of the word.
-	// (Knuth, volume 4, section 7.3.1)
-	switch _W {
-	case 32:
-		return uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
-	case 64:
-		return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
-	default:
-		panic("unknown word size")
-	}
-}
-
 // trailingZeroBits returns the number of consecutive least significant zero
 // bits of x.
 func (x nat) trailingZeroBits() uint {
@@ -707,7 +660,7 @@ func (x nat) trailingZeroBits() uint {
 		i++
 	}
 	// x[i] != 0
-	return i*_W + trailingZeroBits(x[i])
+	return i*_W + uint(bits.TrailingZeros(uint(x[i])))
 }
 
 // z = x << s
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index ebb2985..200a247 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -303,36 +303,6 @@ func TestModW(t *testing.T) {
 	}
 }
 
-func TestTrailingZeroBits(t *testing.T) {
-	// test 0 case explicitly
-	if n := trailingZeroBits(0); n != 0 {
-		t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
-	}
-
-	x := Word(1)
-	for i := uint(0); i < _W; i++ {
-		n := trailingZeroBits(x)
-		if n != i {
-			t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
-		}
-		x <<= 1
-	}
-
-	// test 0 case explicitly
-	if n := nat(nil).trailingZeroBits(); n != 0 {
-		t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
-	}
-
-	y := nat(nil).set(natOne)
-	for i := uint(0); i <= 3*_W; i++ {
-		n := y.trailingZeroBits()
-		if n != i {
-			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i)
-		}
-		y = y.shl(y, 1)
-	}
-}
-
 var montgomeryTests = []struct {
 	x, y, m      string
 	k0           uint64
diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go
index 4454784..25a345e 100644
--- a/src/math/big/natconv.go
+++ b/src/math/big/natconv.go
@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"io"
 	"math"
+	"math/bits"
 	"sync"
 )
 
@@ -262,7 +263,7 @@ func (x nat) itoa(neg bool, base int) []byte {
 	// convert power of two and non power of two bases separately
 	if b := Word(base); b == b&-b {
 		// shift is base b digit size in bits
-		shift := trailingZeroBits(b) // shift > 0 because b >= 2
+		shift := uint(bits.TrailingZeros(uint(b))) // shift > 0 because b >= 2
 		mask := Word(1<<shift - 1)
 		w := x[0]         // current word
 		nbits := uint(_W) // number of unprocessed bits in w
diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go
index bdb60e6..898a39f 100644
--- a/src/math/big/natconv_test.go
+++ b/src/math/big/natconv_test.go
@@ -8,10 +8,18 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"math/bits"
 	"strings"
 	"testing"
 )
 
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+	return bits.Len(uint(x)) - 1
+}
+
 func itoa(x nat, base int) []byte {
 	// special cases
 	switch {
diff --git a/src/math/big/prime_test.go b/src/math/big/prime_test.go
index a2d3d18..7760519 100644
--- a/src/math/big/prime_test.go
+++ b/src/math/big/prime_test.go
@@ -200,7 +200,7 @@ func testPseudoprimes(t *testing.T, name string, cond func(nat) bool, want []int
 		n[0] = Word(i)
 		pseudo := cond(n)
 		if pseudo && (len(want) == 0 || i != want[0]) {
-			t.Errorf("%s(%v, base=2) = %v, want false", name, i)
+			t.Errorf("%s(%v, base=2) = true, want false", name, i)
 		} else if !pseudo && len(want) >= 1 && i == want[0] {
 			t.Errorf("%s(%v, base=2) = false, want true", name, i)
 		}
diff --git a/src/math/bits/bits.go b/src/math/bits/bits.go
new file mode 100644
index 0000000..989baac
--- /dev/null
+++ b/src/math/bits/bits.go
@@ -0,0 +1,330 @@
+// Copyright 2017 The Go 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 make_tables.go
+
+// Package bits implements bit counting and manipulation
+// functions for the predeclared unsigned integer types.
+package bits
+
+const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
+
+// UintSize is the size of a uint in bits.
+const UintSize = uintSize
+
+// --- LeadingZeros ---
+
+// LeadingZeros returns the number of leading zero bits in x; the result is UintSize for x == 0.
+func LeadingZeros(x uint) int { return UintSize - Len(x) }
+
+// LeadingZeros8 returns the number of leading zero bits in x; the result is 8 for x == 0.
+func LeadingZeros8(x uint8) int { return 8 - Len8(x) }
+
+// LeadingZeros16 returns the number of leading zero bits in x; the result is 16 for x == 0.
+func LeadingZeros16(x uint16) int { return 16 - Len16(x) }
+
+// LeadingZeros32 returns the number of leading zero bits in x; the result is 32 for x == 0.
+func LeadingZeros32(x uint32) int { return 32 - Len32(x) }
+
+// LeadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0.
+func LeadingZeros64(x uint64) int { return 64 - Len64(x) }
+
+// --- TrailingZeros ---
+
+// See http://supertech.csail.mit.edu/papers/debruijn.pdf
+const deBruijn32 = 0x077CB531
+
+var deBruijn32tab = [32]byte{
+	0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64tab = [64]byte{
+	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// TrailingZeros returns the number of trailing zero bits in x; the result is UintSize for x == 0.
+func TrailingZeros(x uint) int {
+	if UintSize == 32 {
+		return TrailingZeros32(uint32(x))
+	}
+	return TrailingZeros64(uint64(x))
+}
+
+// TrailingZeros8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
+func TrailingZeros8(x uint8) int {
+	return int(ntz8tab[x])
+}
+
+// TrailingZeros16 returns the number of trailing zero bits in x; the result is 16 for x == 0.
+func TrailingZeros16(x uint16) (n int) {
+	if x == 0 {
+		return 16
+	}
+	// see comment in TrailingZeros64
+	return int(deBruijn32tab[uint32(x&-x)*deBruijn32>>(32-5)])
+}
+
+// TrailingZeros32 returns the number of trailing zero bits in x; the result is 32 for x == 0.
+func TrailingZeros32(x uint32) int {
+	if x == 0 {
+		return 32
+	}
+	// see comment in TrailingZeros64
+	return int(deBruijn32tab[(x&-x)*deBruijn32>>(32-5)])
+}
+
+// TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
+func TrailingZeros64(x uint64) int {
+	if x == 0 {
+		return 64
+	}
+	// If popcount is fast, replace code below with return popcount(^x & (x - 1)).
+	//
+	// 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 (64 bit) constant
+	// is such that all six bit, consecutive substrings are distinct.
+	// Therefore, if we have a left shifted version of this constant we can
+	// find by how many bits it was shifted by looking at which six bit
+	// substring ended up at the top of the word.
+	// (Knuth, volume 4, section 7.3.1)
+	return int(deBruijn64tab[(x&-x)*deBruijn64>>(64-6)])
+}
+
+// --- OnesCount ---
+
+const m0 = 0x5555555555555555 // 01010101 ...
+const m1 = 0x3333333333333333 // 00110011 ...
+const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
+const m3 = 0x00ff00ff00ff00ff // etc.
+const m4 = 0x0000ffff0000ffff
+
+// OnesCount returns the number of one bits ("population count") in x.
+func OnesCount(x uint) int {
+	if UintSize == 32 {
+		return OnesCount32(uint32(x))
+	}
+	return OnesCount64(uint64(x))
+}
+
+// OnesCount8 returns the number of one bits ("population count") in x.
+func OnesCount8(x uint8) int {
+	return int(pop8tab[x])
+}
+
+// OnesCount16 returns the number of one bits ("population count") in x.
+func OnesCount16(x uint16) int {
+	return int(pop8tab[x>>8] + pop8tab[x&0xff])
+}
+
+// OnesCount32 returns the number of one bits ("population count") in x.
+func OnesCount32(x uint32) int {
+	return int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff])
+}
+
+// OnesCount64 returns the number of one bits ("population count") in x.
+func OnesCount64(x uint64) int {
+	// Implementation: Parallel summing of adjacent bits.
+	// See "Hacker's Delight", Chap. 5: Counting Bits.
+	// The following pattern shows the general approach:
+	//
+	//   x = x>>1&(m0&m) + x&(m0&m)
+	//   x = x>>2&(m1&m) + x&(m1&m)
+	//   x = x>>4&(m2&m) + x&(m2&m)
+	//   x = x>>8&(m3&m) + x&(m3&m)
+	//   x = x>>16&(m4&m) + x&(m4&m)
+	//   x = x>>32&(m5&m) + x&(m5&m)
+	//   return int(x)
+	//
+	// Masking (& operations) can be left away when there's no
+	// danger that a field's sum will carry over into the next
+	// field: Since the result cannot be > 64, 8 bits is enough
+	// and we can ignore the masks for the shifts by 8 and up.
+	// Per "Hacker's Delight", the first line can be simplified
+	// more, but it saves at best one instruction, so we leave
+	// it alone for clarity.
+	const m = 1<<64 - 1
+	x = x>>1&(m0&m) + x&(m0&m)
+	x = x>>2&(m1&m) + x&(m1&m)
+	x = (x>>4 + x) & (m2 & m)
+	x += x >> 8
+	x += x >> 16
+	x += x >> 32
+	return int(x) & (1<<7 - 1)
+}
+
+// --- RotateLeft ---
+
+// RotateLeft returns the value of x rotated left by (k mod UintSize) bits.
+// To rotate x right by k bits, call RotateLeft(x, -k).
+func RotateLeft(x uint, k int) uint {
+	if UintSize == 32 {
+		return uint(RotateLeft32(uint32(x), k))
+	}
+	return uint(RotateLeft64(uint64(x), k))
+}
+
+// RotateLeft8 returns the value of x rotated left by (k mod 8) bits.
+// To rotate x right by k bits, call RotateLeft8(x, -k).
+func RotateLeft8(x uint8, k int) uint8 {
+	const n = 8
+	s := uint(k) & (n - 1)
+	return x<<s | x>>(n-s)
+}
+
+// RotateLeft16 returns the value of x rotated left by (k mod 16) bits.
+// To rotate x right by k bits, call RotateLeft16(x, -k).
+func RotateLeft16(x uint16, k int) uint16 {
+	const n = 16
+	s := uint(k) & (n - 1)
+	return x<<s | x>>(n-s)
+}
+
+// RotateLeft32 returns the value of x rotated left by (k mod 32) bits.
+// To rotate x right by k bits, call RotateLeft32(x, -k).
+func RotateLeft32(x uint32, k int) uint32 {
+	const n = 32
+	s := uint(k) & (n - 1)
+	return x<<s | x>>(n-s)
+}
+
+// RotateLeft64 returns the value of x rotated left by (k mod 64) bits.
+// To rotate x right by k bits, call RotateLeft64(x, -k).
+func RotateLeft64(x uint64, k int) uint64 {
+	const n = 64
+	s := uint(k) & (n - 1)
+	return x<<s | x>>(n-s)
+}
+
+// --- Reverse ---
+
+// Reverse returns the value of x with its bits in reversed order.
+func Reverse(x uint) uint {
+	if UintSize == 32 {
+		return uint(Reverse32(uint32(x)))
+	}
+	return uint(Reverse64(uint64(x)))
+}
+
+// Reverse8 returns the value of x with its bits in reversed order.
+func Reverse8(x uint8) uint8 {
+	return rev8tab[x]
+}
+
+// Reverse16 returns the value of x with its bits in reversed order.
+func Reverse16(x uint16) uint16 {
+	return uint16(rev8tab[x>>8]) | uint16(rev8tab[x&0xff])<<8
+}
+
+// Reverse32 returns the value of x with its bits in reversed order.
+func Reverse32(x uint32) uint32 {
+	const m = 1<<32 - 1
+	x = x>>1&(m0&m) | x&(m0&m)<<1
+	x = x>>2&(m1&m) | x&(m1&m)<<2
+	x = x>>4&(m2&m) | x&(m2&m)<<4
+	x = x>>8&(m3&m) | x&(m3&m)<<8
+	return x>>16 | x<<16
+}
+
+// Reverse64 returns the value of x with its bits in reversed order.
+func Reverse64(x uint64) uint64 {
+	const m = 1<<64 - 1
+	x = x>>1&(m0&m) | x&(m0&m)<<1
+	x = x>>2&(m1&m) | x&(m1&m)<<2
+	x = x>>4&(m2&m) | x&(m2&m)<<4
+	x = x>>8&(m3&m) | x&(m3&m)<<8
+	x = x>>16&(m4&m) | x&(m4&m)<<16
+	return x>>32 | x<<32
+}
+
+// --- ReverseBytes ---
+
+// ReverseBytes returns the value of x with its bytes in reversed order.
+func ReverseBytes(x uint) uint {
+	if UintSize == 32 {
+		return uint(ReverseBytes32(uint32(x)))
+	}
+	return uint(ReverseBytes64(uint64(x)))
+}
+
+// ReverseBytes16 returns the value of x with its bytes in reversed order.
+func ReverseBytes16(x uint16) uint16 {
+	return x>>8 | x<<8
+}
+
+// ReverseBytes32 returns the value of x with its bytes in reversed order.
+func ReverseBytes32(x uint32) uint32 {
+	const m = 1<<32 - 1
+	x = x>>8&(m3&m) | x&(m3&m)<<8
+	return x>>16 | x<<16
+}
+
+// ReverseBytes64 returns the value of x with its bytes in reversed order.
+func ReverseBytes64(x uint64) uint64 {
+	const m = 1<<64 - 1
+	x = x>>8&(m3&m) | x&(m3&m)<<8
+	x = x>>16&(m4&m) | x&(m4&m)<<16
+	return x>>32 | x<<32
+}
+
+// --- Len ---
+
+// Len returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len(x uint) int {
+	if UintSize == 32 {
+		return Len32(uint32(x))
+	}
+	return Len64(uint64(x))
+}
+
+// Len8 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len8(x uint8) int {
+	return int(len8tab[x])
+}
+
+// Len16 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len16(x uint16) (n int) {
+	if x >= 1<<8 {
+		x >>= 8
+		n = 8
+	}
+	return n + int(len8tab[x])
+}
+
+// Len32 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len32(x uint32) (n int) {
+	if x >= 1<<16 {
+		x >>= 16
+		n = 16
+	}
+	if x >= 1<<8 {
+		x >>= 8
+		n += 8
+	}
+	return n + int(len8tab[x])
+}
+
+// Len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len64(x uint64) (n int) {
+	if x >= 1<<32 {
+		x >>= 32
+		n = 32
+	}
+	if x >= 1<<16 {
+		x >>= 16
+		n += 16
+	}
+	if x >= 1<<8 {
+		x >>= 8
+		n += 8
+	}
+	return n + int(len8tab[x])
+}
diff --git a/src/math/bits/bits_tables.go b/src/math/bits/bits_tables.go
new file mode 100644
index 0000000..f1e15a0
--- /dev/null
+++ b/src/math/bits/bits_tables.go
@@ -0,0 +1,83 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by go run make_tables.go. DO NOT EDIT.
+
+package bits
+
+var ntz8tab = [256]uint8{
+	0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+	0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+}
+
+var pop8tab = [256]uint8{
+	0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+	0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+	0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+	0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+	0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+	0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+	0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+	0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08,
+}
+
+var rev8tab = [256]uint8{
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+var len8tab = [256]uint8{
+	0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+}
diff --git a/src/math/bits/bits_test.go b/src/math/bits/bits_test.go
new file mode 100644
index 0000000..ba05210
--- /dev/null
+++ b/src/math/bits/bits_test.go
@@ -0,0 +1,747 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bits
+
+import (
+	"testing"
+	"unsafe"
+)
+
+func TestUintSize(t *testing.T) {
+	var x uint
+	if want := unsafe.Sizeof(x) * 8; UintSize != want {
+		t.Fatalf("UintSize = %d; want %d", UintSize, want)
+	}
+}
+
+func TestLeadingZeros(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		nlz := tab[i].nlz
+		for k := 0; k < 64-8; k++ {
+			x := uint64(i) << uint(k)
+			if x <= 1<<8-1 {
+				got := LeadingZeros8(uint8(x))
+				want := nlz - k + (8 - 8)
+				if x == 0 {
+					want = 8
+				}
+				if got != want {
+					t.Fatalf("LeadingZeros8(%#02x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<16-1 {
+				got := LeadingZeros16(uint16(x))
+				want := nlz - k + (16 - 8)
+				if x == 0 {
+					want = 16
+				}
+				if got != want {
+					t.Fatalf("LeadingZeros16(%#04x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<32-1 {
+				got := LeadingZeros32(uint32(x))
+				want := nlz - k + (32 - 8)
+				if x == 0 {
+					want = 32
+				}
+				if got != want {
+					t.Fatalf("LeadingZeros32(%#08x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 32 {
+					got = LeadingZeros(uint(x))
+					if got != want {
+						t.Fatalf("LeadingZeros(%#08x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+
+			if x <= 1<<64-1 {
+				got := LeadingZeros64(uint64(x))
+				want := nlz - k + (64 - 8)
+				if x == 0 {
+					want = 64
+				}
+				if got != want {
+					t.Fatalf("LeadingZeros64(%#016x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 64 {
+					got = LeadingZeros(uint(x))
+					if got != want {
+						t.Fatalf("LeadingZeros(%#016x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+		}
+	}
+}
+
+// Exported (global) variable serving as input for some
+// of the benchmarks to ensure side-effect free calls
+// are not optimized away.
+var Input uint64 = deBruijn64
+
+// Exported (global) variable to store function results
+// during benchmarking to ensure side-effect free calls
+// are not optimized away.
+var Output int
+
+func BenchmarkLeadingZeros(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += LeadingZeros(uint(Input) >> (uint(i) % UintSize))
+	}
+	Output = s
+}
+
+func BenchmarkLeadingZeros8(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += LeadingZeros8(uint8(Input) >> (uint(i) % 8))
+	}
+	Output = s
+}
+
+func BenchmarkLeadingZeros16(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += LeadingZeros16(uint16(Input) >> (uint(i) % 16))
+	}
+	Output = s
+}
+
+func BenchmarkLeadingZeros32(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += LeadingZeros32(uint32(Input) >> (uint(i) % 32))
+	}
+	Output = s
+}
+
+func BenchmarkLeadingZeros64(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += LeadingZeros64(uint64(Input) >> (uint(i) % 64))
+	}
+	Output = s
+}
+
+func TestTrailingZeros(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		ntz := tab[i].ntz
+		for k := 0; k < 64-8; k++ {
+			x := uint64(i) << uint(k)
+			want := ntz + k
+			if x <= 1<<8-1 {
+				got := TrailingZeros8(uint8(x))
+				if x == 0 {
+					want = 8
+				}
+				if got != want {
+					t.Fatalf("TrailingZeros8(%#02x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<16-1 {
+				got := TrailingZeros16(uint16(x))
+				if x == 0 {
+					want = 16
+				}
+				if got != want {
+					t.Fatalf("TrailingZeros16(%#04x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<32-1 {
+				got := TrailingZeros32(uint32(x))
+				if x == 0 {
+					want = 32
+				}
+				if got != want {
+					t.Fatalf("TrailingZeros32(%#08x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 32 {
+					got = TrailingZeros(uint(x))
+					if got != want {
+						t.Fatalf("TrailingZeros(%#08x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+
+			if x <= 1<<64-1 {
+				got := TrailingZeros64(uint64(x))
+				if x == 0 {
+					want = 64
+				}
+				if got != want {
+					t.Fatalf("TrailingZeros64(%#016x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 64 {
+					got = TrailingZeros(uint(x))
+					if got != want {
+						t.Fatalf("TrailingZeros(%#016x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+		}
+	}
+}
+
+func BenchmarkTrailingZeros(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += TrailingZeros(uint(Input) << (uint(i) % UintSize))
+	}
+	Output = s
+}
+
+func BenchmarkTrailingZeros8(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += TrailingZeros8(uint8(Input) << (uint(i) % 8))
+	}
+	Output = s
+}
+
+func BenchmarkTrailingZeros16(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += TrailingZeros16(uint16(Input) << (uint(i) % 16))
+	}
+	Output = s
+}
+
+func BenchmarkTrailingZeros32(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += TrailingZeros32(uint32(Input) << (uint(i) % 32))
+	}
+	Output = s
+}
+
+func BenchmarkTrailingZeros64(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += TrailingZeros64(uint64(Input) << (uint(i) % 64))
+	}
+	Output = s
+}
+
+func TestOnesCount(t *testing.T) {
+	var x uint64
+	for i := 0; i <= 64; i++ {
+		testOnesCount(t, x, i)
+		x = x<<1 | 1
+	}
+
+	for i := 64; i >= 0; i-- {
+		testOnesCount(t, x, i)
+		x = x << 1
+	}
+
+	for i := 0; i < 256; i++ {
+		for k := 0; k < 64-8; k++ {
+			testOnesCount(t, uint64(i)<<uint(k), tab[i].pop)
+		}
+	}
+}
+
+func testOnesCount(t *testing.T, x uint64, want int) {
+	if x <= 1<<8-1 {
+		got := OnesCount8(uint8(x))
+		if got != want {
+			t.Fatalf("OnesCount8(%#02x) == %d; want %d", uint8(x), got, want)
+		}
+	}
+
+	if x <= 1<<16-1 {
+		got := OnesCount16(uint16(x))
+		if got != want {
+			t.Fatalf("OnesCount16(%#04x) == %d; want %d", uint16(x), got, want)
+		}
+	}
+
+	if x <= 1<<32-1 {
+		got := OnesCount32(uint32(x))
+		if got != want {
+			t.Fatalf("OnesCount32(%#08x) == %d; want %d", uint32(x), got, want)
+		}
+		if UintSize == 32 {
+			got = OnesCount(uint(x))
+			if got != want {
+				t.Fatalf("OnesCount(%#08x) == %d; want %d", uint32(x), got, want)
+			}
+		}
+	}
+
+	if x <= 1<<64-1 {
+		got := OnesCount64(uint64(x))
+		if got != want {
+			t.Fatalf("OnesCount64(%#016x) == %d; want %d", x, got, want)
+		}
+		if UintSize == 64 {
+			got = OnesCount(uint(x))
+			if got != want {
+				t.Fatalf("OnesCount(%#016x) == %d; want %d", x, got, want)
+			}
+		}
+	}
+}
+
+func BenchmarkOnesCount(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += OnesCount(uint(Input))
+	}
+	Output = s
+}
+
+func BenchmarkOnesCount8(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += OnesCount8(uint8(Input))
+	}
+	Output = s
+}
+
+func BenchmarkOnesCount16(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += OnesCount16(uint16(Input))
+	}
+	Output = s
+}
+
+func BenchmarkOnesCount32(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += OnesCount32(uint32(Input))
+	}
+	Output = s
+}
+
+func BenchmarkOnesCount64(b *testing.B) {
+	var s int
+	for i := 0; i < b.N; i++ {
+		s += OnesCount64(uint64(Input))
+	}
+	Output = s
+}
+
+func TestRotateLeft(t *testing.T) {
+	var m uint64 = deBruijn64
+
+	for k := uint(0); k < 128; k++ {
+		x8 := uint8(m)
+		got8 := RotateLeft8(x8, int(k))
+		want8 := x8<<(k&0x7) | x8>>(8-k&0x7)
+		if got8 != want8 {
+			t.Fatalf("RotateLeft8(%#02x, %d) == %#02x; want %#02x", x8, k, got8, want8)
+		}
+		got8 = RotateLeft8(want8, -int(k))
+		if got8 != x8 {
+			t.Fatalf("RotateLeft8(%#02x, -%d) == %#02x; want %#02x", want8, k, got8, x8)
+		}
+
+		x16 := uint16(m)
+		got16 := RotateLeft16(x16, int(k))
+		want16 := x16<<(k&0xf) | x16>>(16-k&0xf)
+		if got16 != want16 {
+			t.Fatalf("RotateLeft16(%#04x, %d) == %#04x; want %#04x", x16, k, got16, want16)
+		}
+		got16 = RotateLeft16(want16, -int(k))
+		if got16 != x16 {
+			t.Fatalf("RotateLeft16(%#04x, -%d) == %#04x; want %#04x", want16, k, got16, x16)
+		}
+
+		x32 := uint32(m)
+		got32 := RotateLeft32(x32, int(k))
+		want32 := x32<<(k&0x1f) | x32>>(32-k&0x1f)
+		if got32 != want32 {
+			t.Fatalf("RotateLeft32(%#08x, %d) == %#08x; want %#08x", x32, k, got32, want32)
+		}
+		got32 = RotateLeft32(want32, -int(k))
+		if got32 != x32 {
+			t.Fatalf("RotateLeft32(%#08x, -%d) == %#08x; want %#08x", want32, k, got32, x32)
+		}
+		if UintSize == 32 {
+			x := uint(m)
+			got := RotateLeft(x, int(k))
+			want := x<<(k&0x1f) | x>>(32-k&0x1f)
+			if got != want {
+				t.Fatalf("RotateLeft(%#08x, %d) == %#08x; want %#08x", x, k, got, want)
+			}
+			got = RotateLeft(want, -int(k))
+			if got != x {
+				t.Fatalf("RotateLeft(%#08x, -%d) == %#08x; want %#08x", want, k, got, x)
+			}
+		}
+
+		x64 := uint64(m)
+		got64 := RotateLeft64(x64, int(k))
+		want64 := x64<<(k&0x3f) | x64>>(64-k&0x3f)
+		if got64 != want64 {
+			t.Fatalf("RotateLeft64(%#016x, %d) == %#016x; want %#016x", x64, k, got64, want64)
+		}
+		got64 = RotateLeft64(want64, -int(k))
+		if got64 != x64 {
+			t.Fatalf("RotateLeft64(%#016x, -%d) == %#016x; want %#016x", want64, k, got64, x64)
+		}
+		if UintSize == 64 {
+			x := uint(m)
+			got := RotateLeft(x, int(k))
+			want := x<<(k&0x3f) | x>>(64-k&0x3f)
+			if got != want {
+				t.Fatalf("RotateLeft(%#016x, %d) == %#016x; want %#016x", x, k, got, want)
+			}
+			got = RotateLeft(want, -int(k))
+			if got != x {
+				t.Fatalf("RotateLeft(%#08x, -%d) == %#08x; want %#08x", want, k, got, x)
+			}
+		}
+	}
+}
+
+func BenchmarkRotateLeft(b *testing.B) {
+	var s uint
+	for i := 0; i < b.N; i++ {
+		s += RotateLeft(uint(Input), i)
+	}
+	Output = int(s)
+}
+
+func BenchmarkRotateLeft8(b *testing.B) {
+	var s uint8
+	for i := 0; i < b.N; i++ {
+		s += RotateLeft8(uint8(Input), i)
+	}
+	Output = int(s)
+}
+
+func BenchmarkRotateLeft16(b *testing.B) {
+	var s uint16
+	for i := 0; i < b.N; i++ {
+		s += RotateLeft16(uint16(Input), i)
+	}
+	Output = int(s)
+}
+
+func BenchmarkRotateLeft32(b *testing.B) {
+	var s uint32
+	for i := 0; i < b.N; i++ {
+		s += RotateLeft32(uint32(Input), i)
+	}
+	Output = int(s)
+}
+
+func BenchmarkRotateLeft64(b *testing.B) {
+	var s uint64
+	for i := 0; i < b.N; i++ {
+		s += RotateLeft64(uint64(Input), i)
+	}
+	Output = int(s)
+}
+
+func TestReverse(t *testing.T) {
+	// test each bit
+	for i := uint(0); i < 64; i++ {
+		testReverse(t, uint64(1)<<i, uint64(1)<<(63-i))
+	}
+
+	// test a few patterns
+	for _, test := range []struct {
+		x, r uint64
+	}{
+		{0, 0},
+		{0x1, 0x8 << 60},
+		{0x2, 0x4 << 60},
+		{0x3, 0xc << 60},
+		{0x4, 0x2 << 60},
+		{0x5, 0xa << 60},
+		{0x6, 0x6 << 60},
+		{0x7, 0xe << 60},
+		{0x8, 0x1 << 60},
+		{0x9, 0x9 << 60},
+		{0xa, 0x5 << 60},
+		{0xb, 0xd << 60},
+		{0xc, 0x3 << 60},
+		{0xd, 0xb << 60},
+		{0xe, 0x7 << 60},
+		{0xf, 0xf << 60},
+		{0x5686487, 0xe12616a000000000},
+		{0x0123456789abcdef, 0xf7b3d591e6a2c480},
+	} {
+		testReverse(t, test.x, test.r)
+		testReverse(t, test.r, test.x)
+	}
+}
+
+func testReverse(t *testing.T, x64, want64 uint64) {
+	x8 := uint8(x64)
+	got8 := Reverse8(x8)
+	want8 := uint8(want64 >> (64 - 8))
+	if got8 != want8 {
+		t.Fatalf("Reverse8(%#02x) == %#02x; want %#02x", x8, got8, want8)
+	}
+
+	x16 := uint16(x64)
+	got16 := Reverse16(x16)
+	want16 := uint16(want64 >> (64 - 16))
+	if got16 != want16 {
+		t.Fatalf("Reverse16(%#04x) == %#04x; want %#04x", x16, got16, want16)
+	}
+
+	x32 := uint32(x64)
+	got32 := Reverse32(x32)
+	want32 := uint32(want64 >> (64 - 32))
+	if got32 != want32 {
+		t.Fatalf("Reverse32(%#08x) == %#08x; want %#08x", x32, got32, want32)
+	}
+	if UintSize == 32 {
+		x := uint(x32)
+		got := Reverse(x)
+		want := uint(want32)
+		if got != want {
+			t.Fatalf("Reverse(%#08x) == %#08x; want %#08x", x, got, want)
+		}
+	}
+
+	got64 := Reverse64(x64)
+	if got64 != want64 {
+		t.Fatalf("Reverse64(%#016x) == %#016x; want %#016x", x64, got64, want64)
+	}
+	if UintSize == 64 {
+		x := uint(x64)
+		got := Reverse(x)
+		want := uint(want64)
+		if got != want {
+			t.Fatalf("Reverse(%#08x) == %#016x; want %#016x", x, got, want)
+		}
+	}
+}
+
+func BenchmarkReverse(b *testing.B) {
+	var s uint
+	for i := 0; i < b.N; i++ {
+		s += Reverse(uint(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverse8(b *testing.B) {
+	var s uint8
+	for i := 0; i < b.N; i++ {
+		s += Reverse8(uint8(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverse16(b *testing.B) {
+	var s uint16
+	for i := 0; i < b.N; i++ {
+		s += Reverse16(uint16(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverse32(b *testing.B) {
+	var s uint32
+	for i := 0; i < b.N; i++ {
+		s += Reverse32(uint32(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverse64(b *testing.B) {
+	var s uint64
+	for i := 0; i < b.N; i++ {
+		s += Reverse64(uint64(i))
+	}
+	Output = int(s)
+}
+
+func TestReverseBytes(t *testing.T) {
+	for _, test := range []struct {
+		x, r uint64
+	}{
+		{0, 0},
+		{0x01, 0x01 << 56},
+		{0x0123, 0x2301 << 48},
+		{0x012345, 0x452301 << 40},
+		{0x01234567, 0x67452301 << 32},
+		{0x0123456789, 0x8967452301 << 24},
+		{0x0123456789ab, 0xab8967452301 << 16},
+		{0x0123456789abcd, 0xcdab8967452301 << 8},
+		{0x0123456789abcdef, 0xefcdab8967452301 << 0},
+	} {
+		testReverseBytes(t, test.x, test.r)
+		testReverseBytes(t, test.r, test.x)
+	}
+}
+
+func testReverseBytes(t *testing.T, x64, want64 uint64) {
+	x16 := uint16(x64)
+	got16 := ReverseBytes16(x16)
+	want16 := uint16(want64 >> (64 - 16))
+	if got16 != want16 {
+		t.Fatalf("ReverseBytes16(%#04x) == %#04x; want %#04x", x16, got16, want16)
+	}
+
+	x32 := uint32(x64)
+	got32 := ReverseBytes32(x32)
+	want32 := uint32(want64 >> (64 - 32))
+	if got32 != want32 {
+		t.Fatalf("ReverseBytes32(%#08x) == %#08x; want %#08x", x32, got32, want32)
+	}
+	if UintSize == 32 {
+		x := uint(x32)
+		got := ReverseBytes(x)
+		want := uint(want32)
+		if got != want {
+			t.Fatalf("ReverseBytes(%#08x) == %#08x; want %#08x", x, got, want)
+		}
+	}
+
+	got64 := ReverseBytes64(x64)
+	if got64 != want64 {
+		t.Fatalf("ReverseBytes64(%#016x) == %#016x; want %#016x", x64, got64, want64)
+	}
+	if UintSize == 64 {
+		x := uint(x64)
+		got := ReverseBytes(x)
+		want := uint(want64)
+		if got != want {
+			t.Fatalf("ReverseBytes(%#016x) == %#016x; want %#016x", x, got, want)
+		}
+	}
+}
+
+func BenchmarkReverseBytes(b *testing.B) {
+	var s uint
+	for i := 0; i < b.N; i++ {
+		s += ReverseBytes(uint(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverseBytes16(b *testing.B) {
+	var s uint16
+	for i := 0; i < b.N; i++ {
+		s += ReverseBytes16(uint16(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverseBytes32(b *testing.B) {
+	var s uint32
+	for i := 0; i < b.N; i++ {
+		s += ReverseBytes32(uint32(i))
+	}
+	Output = int(s)
+}
+
+func BenchmarkReverseBytes64(b *testing.B) {
+	var s uint64
+	for i := 0; i < b.N; i++ {
+		s += ReverseBytes64(uint64(i))
+	}
+	Output = int(s)
+}
+
+func TestLen(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		len := 8 - tab[i].nlz
+		for k := 0; k < 64-8; k++ {
+			x := uint64(i) << uint(k)
+			want := 0
+			if x != 0 {
+				want = len + k
+			}
+			if x <= 1<<8-1 {
+				got := Len8(uint8(x))
+				if got != want {
+					t.Fatalf("Len8(%#02x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<16-1 {
+				got := Len16(uint16(x))
+				if got != want {
+					t.Fatalf("Len16(%#04x) == %d; want %d", x, got, want)
+				}
+			}
+
+			if x <= 1<<32-1 {
+				got := Len32(uint32(x))
+				if got != want {
+					t.Fatalf("Len32(%#08x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 32 {
+					got := Len(uint(x))
+					if got != want {
+						t.Fatalf("Len(%#08x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+
+			if x <= 1<<64-1 {
+				got := Len64(uint64(x))
+				if got != want {
+					t.Fatalf("Len64(%#016x) == %d; want %d", x, got, want)
+				}
+				if UintSize == 64 {
+					got := Len(uint(x))
+					if got != want {
+						t.Fatalf("Len(%#016x) == %d; want %d", x, got, want)
+					}
+				}
+			}
+		}
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Testing support
+
+type entry = struct {
+	nlz, ntz, pop int
+}
+
+// tab contains results for all uint8 values
+var tab [256]entry
+
+func init() {
+	tab[0] = entry{8, 8, 0}
+	for i := 1; i < len(tab); i++ {
+		// nlz
+		x := i // x != 0
+		n := 0
+		for x&0x80 == 0 {
+			n++
+			x <<= 1
+		}
+		tab[i].nlz = n
+
+		// ntz
+		x = i // x != 0
+		n = 0
+		for x&1 == 0 {
+			n++
+			x >>= 1
+		}
+		tab[i].ntz = n
+
+		// pop
+		x = i // x != 0
+		n = 0
+		for x != 0 {
+			n += int(x & 1)
+			x >>= 1
+		}
+		tab[i].pop = n
+	}
+}
diff --git a/src/math/bits/make_tables.go b/src/math/bits/make_tables.go
new file mode 100644
index 0000000..ff2fe2e
--- /dev/null
+++ b/src/math/bits/make_tables.go
@@ -0,0 +1,92 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program generates bits_tables.go.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/format"
+	"io"
+	"io/ioutil"
+	"log"
+)
+
+var header = []byte(`// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by go run make_tables.go. DO NOT EDIT.
+
+package bits
+
+`)
+
+func main() {
+	buf := bytes.NewBuffer(header)
+
+	gen(buf, "ntz8tab", ntz8)
+	gen(buf, "pop8tab", pop8)
+	gen(buf, "rev8tab", rev8)
+	gen(buf, "len8tab", len8)
+
+	out, err := format.Source(buf.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	err = ioutil.WriteFile("bits_tables.go", out, 0666)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func gen(w io.Writer, name string, f func(uint8) uint8) {
+	fmt.Fprintf(w, "var %s = [256]uint8{", name)
+	for i := 0; i < 256; i++ {
+		if i%16 == 0 {
+			fmt.Fprint(w, "\n\t")
+		} else {
+			fmt.Fprint(w, " ")
+		}
+		fmt.Fprintf(w, "%#02x,", f(uint8(i)))
+	}
+	fmt.Fprint(w, "\n}\n\n")
+}
+
+func ntz8(x uint8) (n uint8) {
+	for x&1 == 0 && n < 8 {
+		x >>= 1
+		n++
+	}
+	return
+}
+
+func pop8(x uint8) (n uint8) {
+	for x != 0 {
+		x &= x - 1
+		n++
+	}
+	return
+}
+
+func rev8(x uint8) (r uint8) {
+	for i := 8; i > 0; i-- {
+		r = r<<1 | x&1
+		x >>= 1
+	}
+	return
+}
+
+func len8(x uint8) (n uint8) {
+	for x != 0 {
+		x >>= 1
+		n++
+	}
+	return
+}
diff --git a/src/math/cbrt.go b/src/math/cbrt.go
index f009faf..4afd4a8 100644
--- a/src/math/cbrt.go
+++ b/src/math/cbrt.go
@@ -22,7 +22,9 @@ package math
 //	Cbrt(±0) = ±0
 //	Cbrt(±Inf) = ±Inf
 //	Cbrt(NaN) = NaN
-func Cbrt(x float64) float64 {
+func Cbrt(x float64) float64
+
+func cbrt(x float64) float64 {
 	const (
 		B1             = 715094163                   // (682-0.03306235651)*2**20
 		B2             = 696219795                   // (664-0.03306235651)*2**20
diff --git a/src/math/cbrt_s390x.s b/src/math/cbrt_s390x.s
new file mode 100644
index 0000000..20d9fe6
--- /dev/null
+++ b/src/math/cbrt_s390x.s
@@ -0,0 +1,162 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·cbrtrodataL9<> + 0(SB)/8, $-.00016272731015974436E+00
+DATA ·cbrtrodataL9<> + 8(SB)/8, $0.66639548758285293179E+00
+DATA ·cbrtrodataL9<> + 16(SB)/8, $0.55519402697349815993E+00
+DATA ·cbrtrodataL9<> + 24(SB)/8, $0.49338566048766782004E+00
+DATA ·cbrtrodataL9<> + 32(SB)/8, $0.45208160036325611486E+00
+DATA ·cbrtrodataL9<> + 40(SB)/8, $0.43099892837778637816E+00
+DATA ·cbrtrodataL9<> + 48(SB)/8, $1.000244140625
+DATA ·cbrtrodataL9<> + 56(SB)/8, $0.33333333333333333333E+00
+DATA ·cbrtrodataL9<> + 64(SB)/8, $79228162514264337593543950336.
+GLOBL ·cbrtrodataL9<> + 0(SB), RODATA, $72
+
+// Index tables
+DATA ·cbrttab32069<> + 0(SB)/8, $0x404030303020202
+DATA ·cbrttab32069<> + 8(SB)/8, $0x101010101000000
+DATA ·cbrttab32069<> + 16(SB)/8, $0x808070706060605
+DATA ·cbrttab32069<> + 24(SB)/8, $0x505040404040303
+DATA ·cbrttab32069<> + 32(SB)/8, $0xe0d0c0c0b0b0b0a
+DATA ·cbrttab32069<> + 40(SB)/8, $0xa09090908080808
+DATA ·cbrttab32069<> + 48(SB)/8, $0x11111010100f0f0f
+DATA ·cbrttab32069<> + 56(SB)/8, $0xe0e0e0e0e0d0d0d
+DATA ·cbrttab32069<> + 64(SB)/8, $0x1515141413131312
+DATA ·cbrttab32069<> + 72(SB)/8, $0x1212111111111010
+GLOBL ·cbrttab32069<> + 0(SB), RODATA, $80
+
+DATA ·cbrttab22068<> + 0(SB)/8, $0x151015001420141
+DATA ·cbrttab22068<> + 8(SB)/8, $0x140013201310130
+DATA ·cbrttab22068<> + 16(SB)/8, $0x122012101200112
+DATA ·cbrttab22068<> + 24(SB)/8, $0x111011001020101
+DATA ·cbrttab22068<> + 32(SB)/8, $0x10000f200f100f0
+DATA ·cbrttab22068<> + 40(SB)/8, $0xe200e100e000d2
+DATA ·cbrttab22068<> + 48(SB)/8, $0xd100d000c200c1
+DATA ·cbrttab22068<> + 56(SB)/8, $0xc000b200b100b0
+DATA ·cbrttab22068<> + 64(SB)/8, $0xa200a100a00092
+DATA ·cbrttab22068<> + 72(SB)/8, $0x91009000820081
+DATA ·cbrttab22068<> + 80(SB)/8, $0x80007200710070
+DATA ·cbrttab22068<> + 88(SB)/8, $0x62006100600052
+DATA ·cbrttab22068<> + 96(SB)/8, $0x51005000420041
+DATA ·cbrttab22068<> + 104(SB)/8, $0x40003200310030
+DATA ·cbrttab22068<> + 112(SB)/8, $0x22002100200012
+DATA ·cbrttab22068<> + 120(SB)/8, $0x11001000020001
+GLOBL ·cbrttab22068<> + 0(SB), RODATA, $128
+
+DATA ·cbrttab12067<> + 0(SB)/8, $0x53e1529051324fe1
+DATA ·cbrttab12067<> + 8(SB)/8, $0x4e904d324be14a90
+DATA ·cbrttab12067<> + 16(SB)/8, $0x493247e146904532
+DATA ·cbrttab12067<> + 24(SB)/8, $0x43e1429041323fe1
+DATA ·cbrttab12067<> + 32(SB)/8, $0x3e903d323be13a90
+DATA ·cbrttab12067<> + 40(SB)/8, $0x393237e136903532
+DATA ·cbrttab12067<> + 48(SB)/8, $0x33e1329031322fe1
+DATA ·cbrttab12067<> + 56(SB)/8, $0x2e902d322be12a90
+DATA ·cbrttab12067<> + 64(SB)/8, $0xd3e1d290d132cfe1
+DATA ·cbrttab12067<> + 72(SB)/8, $0xce90cd32cbe1ca90
+DATA ·cbrttab12067<> + 80(SB)/8, $0xc932c7e1c690c532
+DATA ·cbrttab12067<> + 88(SB)/8, $0xc3e1c290c132bfe1
+DATA ·cbrttab12067<> + 96(SB)/8, $0xbe90bd32bbe1ba90
+DATA ·cbrttab12067<> + 104(SB)/8, $0xb932b7e1b690b532
+DATA ·cbrttab12067<> + 112(SB)/8, $0xb3e1b290b132afe1
+DATA ·cbrttab12067<> + 120(SB)/8, $0xae90ad32abe1aa90
+GLOBL ·cbrttab12067<> + 0(SB), RODATA, $128
+
+// Cbrt returns the cube root of the argument.
+//
+// Special cases are:
+//      Cbrt(±0) = ±0
+//      Cbrt(±Inf) = ±Inf
+//      Cbrt(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·cbrtAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·cbrtrodataL9<>+0(SB), R9
+	WORD	$0xB3CD0020	//lgdr %r2, %f0
+	WORD	$0xC039000F	//iilf	%r3,1048575
+	BYTE	$0xFF
+	BYTE	$0xFF
+	SRAD	$32, R2
+	WORD	$0xB9170012	//llgtr	%r1,%r2
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBLE	R6, R7, L2
+	WORD	$0xC0397FEF	//iilf	%r3,2146435071
+	BYTE	$0xFF
+	BYTE	$0xFF
+	MOVW	R3, R7
+	CMPBLE	R6, R7, L8
+L1:
+	FMOVD	F0, ret+8(FP)
+	RET
+L3:
+L2:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BEQ	L1
+	FMOVD	F0, F2
+	WORD	$0xED209040	//mdb	%f2,.L10-.L9(%r9)
+	BYTE	$0x00
+	BYTE	$0x1C
+	MOVH	$0x200, R4
+	WORD	$0xB3CD0022	//lgdr %r2, %f2
+	SRAD	$32, R2
+L4:
+	WORD	$0xEC3239BE	//risbg	%r3,%r2,57,128+62,64-25
+	BYTE	$0x27
+	BYTE	$0x55
+	MOVD	$·cbrttab12067<>+0(SB), R1
+	WORD	$0x48131000	//lh	%r1,0(%r3,%r1)
+	WORD	$0xEC3239BE	//risbg	%r3,%r2,57,128+62,64-19
+	BYTE	$0x2D
+	BYTE	$0x55
+	MOVD	$·cbrttab22068<>+0(SB), R5
+	WORD	$0xEC223CBF	//risbgn	%r2,%r2,64-4,128+63,64+44+4
+	BYTE	$0x70
+	BYTE	$0x59
+	WORD	$0x4A135000	//ah	%r1,0(%r3,%r5)
+	BYTE	$0x18	//lr	%r3,%r1
+	BYTE	$0x31
+	MOVD	$·cbrttab32069<>+0(SB), R1
+	FMOVD	56(R9), F1
+	FMOVD	48(R9), F5
+	WORD	$0xEC23393B	//rosbg	%r2,%r3,57,59,4
+	BYTE	$0x04
+	BYTE	$0x56
+	WORD	$0xE3121000	//llc	%r1,0(%r2,%r1)
+	BYTE	$0x00
+	BYTE	$0x94
+	ADDW	R3, R1
+	ADDW	R4, R1
+	SLW	$16, R1, R1
+	SLD	$32, R1, R1
+	WORD	$0xB3C10021	//ldgr	%f2,%r1
+	WFMDB	V2, V2, V4
+	WFMDB	V4, V0, V6
+	WFMSDB	V4, V6, V2, V4
+	FMOVD	40(R9), F6
+	FMSUB	F1, F4, F2
+	FMOVD	32(R9), F4
+	WFMDB	V2, V2, V3
+	FMOVD	24(R9), F1
+	FMUL	F3, F0
+	FMOVD	16(R9), F3
+	WFMADB	V2, V0, V5, V2
+	FMOVD	8(R9), F5
+	FMADD	F6, F2, F4
+	WFMADB	V2, V1, V3, V1
+	WFMDB	V2, V2, V6
+	FMOVD	0(R9), F3
+	WFMADB	V4, V6, V1, V4
+	WFMADB	V2, V5, V3, V2
+	FMADD	F4, F6, F2
+	FMADD	F2, F0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L8:
+	MOVH	$0x0, R4
+	BR	L4
diff --git a/src/math/cbrt_stub.s b/src/math/cbrt_stub.s
new file mode 100644
index 0000000..65300d4
--- /dev/null
+++ b/src/math/cbrt_stub.s
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm
+
+#include "textflag.h"
+
+TEXT ·Cbrt(SB),NOSPLIT,$0
+    JMP ·cbrt(SB)
+
diff --git a/src/math/const.go b/src/math/const.go
index b440538..20b7065 100644
--- a/src/math/const.go
+++ b/src/math/const.go
@@ -3,6 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // Package math provides basic constants and mathematical functions.
+//
+// This package does not guarantee bit-identical results across architectures.
 package math
 
 // Mathematical constants.
diff --git a/src/math/cosh_s390x.s b/src/math/cosh_s390x.s
index d061bd0..343ae22 100644
--- a/src/math/cosh_s390x.s
+++ b/src/math/cosh_s390x.s
@@ -109,7 +109,7 @@ L14:
 	FMOVD   0(R1), F3
 	WFMADB  V1, V7, V3, V7
 	FNEG    F2, F3
-	WORD    $0xB3CD0015     //lgdr %r1,%f5
+	LGDR    F5, R1
 	MOVD    $coshe2<>+0(SB), R3
 	WFCEDBS V4, V0, V0
 	FMOVD   0(R3), F5
@@ -127,15 +127,15 @@ L14:
 	MOVD    $coshtab<>+0(SB), R3
 	WFMADB  V3, V6, V1, V6
 	WORD    $0x68043000     //ld    %f0,0(%r4,%r3)
-	FMSUB   F0, F3, F2, F2
+	FMSUB   F0, F3, F2
 	WORD    $0xA71AF000     //ahi   %r1,-4096
 	WFMADB  V2, V6, V0, V6
 L17:
 	WORD    $0xEC21000F     //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
-	WORD    $0xB3C10022     //ldgr %f2,%r2
-	FMADD   F2, F6, F2, F2
+	LDGR    R2, F2
+	FMADD   F2, F6, F2
 	MOVD    $coshx4ff<>+0(SB), R1
 	FMOVD   0(R1), F0
 	FMUL    F2, F0
@@ -153,7 +153,7 @@ L20:
 	FMOVD   coshrodataL23<>+8(SB), F4
 	FADD    F3, F2
 	MOVD    $coshe6<>+0(SB), R1
-	FMSUB   F4, F2, F0, F0
+	FMSUB   F4, F2, F0
 	FMOVD   0(R1), F6
 	WFMDB   V0, V0, V1
 	MOVD    $coshe4<>+0(SB), R1
@@ -161,7 +161,7 @@ L20:
 	MOVD    $coshe5<>+0(SB), R1
 	FMOVD   coshrodataL23<>+0(SB), F5
 	WFMADB  V1, V6, V4, V6
-	FMADD   F5, F2, F0, F0
+	FMADD   F5, F2, F0
 	FMOVD   0(R1), F2
 	MOVD    $coshe3<>+0(SB), R1
 	FMOVD   0(R1), F4
@@ -173,7 +173,7 @@ L20:
 	MOVD    $coshe1<>+0(SB), R1
 	FMOVD   0(R1), F5
 	WFMADB  V1, V2, V5, V1
-	WORD    $0xB3CD0013     //lgdr  %r1,%f3
+	LGDR    F3, R1
 	MOVD    $coshtab<>+0(SB), R5
 	WFMADB  V4, V6, V1, V3
 	WORD    $0xEC4139BC     //risbg %r4,%r1,57,128+60,3
@@ -183,13 +183,13 @@ L20:
 	WORD    $0x68145000     //ld %f1,0(%r4,%r5)
 	WFMSDB  V4, V1, V0, V2
 	WORD    $0xA7487FBE     //lhi %r4,32702
-	FMADD   F3, F2, F1, F1
+	FMADD   F3, F2, F1
 	SUBW    R1, R4
 	WORD    $0xECC439BC     //risbg %r12,%r4,57,128+60,3
 	BYTE    $0x03
 	BYTE    $0x55
 	WORD    $0x682C5000     //ld %f2,0(%r12,%r5)
-	FMSUB   F2, F4, F0, F0
+	FMSUB   F2, F4, F0
 	WORD    $0xEC21000F     //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
@@ -197,10 +197,10 @@ L20:
 	WORD    $0xEC34000F     //risbgn %r3,%r4,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
-	WORD    $0xB3C10022     //ldgr %f2,%r2
-	WORD    $0xB3C10003     //ldgr %f0,%r3
-	FMADD   F2, F1, F2, F2
-	FMADD   F0, F6, F0, F0
+	LDGR    R2, F2
+	LDGR    R3, F0
+	FMADD   F2, F1, F2
+	FMADD   F0, F6, F0
 	FADD    F2, F0
 	FMOVD   F0, ret+8(FP)
 	RET
@@ -214,7 +214,7 @@ L22:
 	BYTE    $0x03
 	BYTE    $0x55
 	WORD    $0x68034000     //ld %f0,0(%r3,%r4)
-	FMSUB   F0, F3, F2, F2
+	FMSUB   F0, F3, F2
 	WORD    $0xA7386FBE     //lhi %r3,28606
 	WFMADB  V2, V6, V0, V6
 	SUBW    R1, R3, R1
diff --git a/src/math/erf.go b/src/math/erf.go
index 8ddd5f9..9b4048f 100644
--- a/src/math/erf.go
+++ b/src/math/erf.go
@@ -185,7 +185,9 @@ const (
 //	Erf(+Inf) = 1
 //	Erf(-Inf) = -1
 //	Erf(NaN) = NaN
-func Erf(x float64) float64 {
+func Erf(x float64) float64
+
+func erf(x float64) float64 {
 	const (
 		VeryTiny = 2.848094538889218e-306 // 0x0080000000000000
 		Small    = 1.0 / (1 << 28)        // 2**-28
@@ -262,7 +264,9 @@ func Erf(x float64) float64 {
 //	Erfc(+Inf) = 0
 //	Erfc(-Inf) = 2
 //	Erfc(NaN) = NaN
-func Erfc(x float64) float64 {
+func Erfc(x float64) float64
+
+func erfc(x float64) float64 {
 	const Tiny = 1.0 / (1 << 56) // 2**-56
 	// special cases
 	switch {
diff --git a/src/math/erf_s390x.s b/src/math/erf_s390x.s
new file mode 100644
index 0000000..5b62bda
--- /dev/null
+++ b/src/math/erf_s390x.s
@@ -0,0 +1,299 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial coefficients and other constants
+DATA ·erfrodataL13<> + 0(SB)/8, $0.243673229298474689E+01
+DATA ·erfrodataL13<> + 8(SB)/8, $-.654905018503145600E+00
+DATA ·erfrodataL13<> + 16(SB)/8, $0.404669310217538718E+01
+DATA ·erfrodataL13<> + 24(SB)/8, $-.564189219162765367E+00
+DATA ·erfrodataL13<> + 32(SB)/8, $-.200104300906596851E+01
+DATA ·erfrodataL13<> + 40(SB)/8, $0.5
+DATA ·erfrodataL13<> + 48(SB)/8, $0.144070097650207154E+00
+DATA ·erfrodataL13<> + 56(SB)/8, $-.116697735205906191E+00
+DATA ·erfrodataL13<> + 64(SB)/8, $0.256847684882319665E-01
+DATA ·erfrodataL13<> + 72(SB)/8, $-.510805169106229148E-02
+DATA ·erfrodataL13<> + 80(SB)/8, $0.885258164825590267E-03
+DATA ·erfrodataL13<> + 88(SB)/8, $-.133861989591931411E-03
+DATA ·erfrodataL13<> + 96(SB)/8, $0.178294867340272534E-04
+DATA ·erfrodataL13<> + 104(SB)/8, $-.211436095674019218E-05
+DATA ·erfrodataL13<> + 112(SB)/8, $0.225503753499344434E-06
+DATA ·erfrodataL13<> + 120(SB)/8, $-.218247939190783624E-07
+DATA ·erfrodataL13<> + 128(SB)/8, $0.193179206264594029E-08
+DATA ·erfrodataL13<> + 136(SB)/8, $-.157440643541715319E-09
+DATA ·erfrodataL13<> + 144(SB)/8, $0.118878583237342616E-10
+DATA ·erfrodataL13<> + 152(SB)/8, $0.554289288424588473E-13
+DATA ·erfrodataL13<> + 160(SB)/8, $-.277649758489502214E-14
+DATA ·erfrodataL13<> + 168(SB)/8, $-.839318416990049443E-12
+DATA ·erfrodataL13<> + 176(SB)/8, $-2.25
+DATA ·erfrodataL13<> + 184(SB)/8, $.12837916709551258632
+DATA ·erfrodataL13<> + 192(SB)/8, $1.0
+DATA ·erfrodataL13<> + 200(SB)/8, $0.500000000000004237e+00
+DATA ·erfrodataL13<> + 208(SB)/8, $1.0
+DATA ·erfrodataL13<> + 216(SB)/8, $0.416666664838056960e-01
+DATA ·erfrodataL13<> + 224(SB)/8, $0.166666666630345592e+00
+DATA ·erfrodataL13<> + 232(SB)/8, $0.138926439368309441e-02
+DATA ·erfrodataL13<> + 240(SB)/8, $0.833349307718286047e-02
+DATA ·erfrodataL13<> + 248(SB)/8, $-.693147180559945286e+00
+DATA ·erfrodataL13<> + 256(SB)/8, $-.144269504088896339e+01
+DATA ·erfrodataL13<> + 264(SB)/8, $281475245147134.9375
+DATA ·erfrodataL13<> + 272(SB)/8, $0.358256136398192529E+01
+DATA ·erfrodataL13<> + 280(SB)/8, $-.554084396500738270E+00
+DATA ·erfrodataL13<> + 288(SB)/8, $0.203630123025312046E+02
+DATA ·erfrodataL13<> + 296(SB)/8, $-.735750304705934424E+01
+DATA ·erfrodataL13<> + 304(SB)/8, $0.250491598091071797E+02
+DATA ·erfrodataL13<> + 312(SB)/8, $-.118955882760959931E+02
+DATA ·erfrodataL13<> + 320(SB)/8, $0.942903335085524187E+01
+DATA ·erfrodataL13<> + 328(SB)/8, $-.564189522219085689E+00
+DATA ·erfrodataL13<> + 336(SB)/8, $-.503767199403555540E+01
+DATA ·erfrodataL13<> + 344(SB)/8, $0xbbc79ca10c924223
+DATA ·erfrodataL13<> + 352(SB)/8, $0.004099975562609307E+01
+DATA ·erfrodataL13<> + 360(SB)/8, $-.324434353381296556E+00
+DATA ·erfrodataL13<> + 368(SB)/8, $0.945204812084476250E-01
+DATA ·erfrodataL13<> + 376(SB)/8, $-.221407443830058214E-01
+DATA ·erfrodataL13<> + 384(SB)/8, $0.426072376238804349E-02
+DATA ·erfrodataL13<> + 392(SB)/8, $-.692229229127016977E-03
+DATA ·erfrodataL13<> + 400(SB)/8, $0.971111253652087188E-04
+DATA ·erfrodataL13<> + 408(SB)/8, $-.119752226272050504E-04
+DATA ·erfrodataL13<> + 416(SB)/8, $0.131662993588532278E-05
+DATA ·erfrodataL13<> + 424(SB)/8, $0.115776482315851236E-07
+DATA ·erfrodataL13<> + 432(SB)/8, $-.780118522218151687E-09
+DATA ·erfrodataL13<> + 440(SB)/8, $-.130465975877241088E-06
+DATA ·erfrodataL13<> + 448(SB)/8, $-0.25
+GLOBL ·erfrodataL13<> + 0(SB), RODATA, $456
+
+// Table of log correction terms
+DATA ·erftab2066<> + 0(SB)/8, $0.442737824274138381e-01
+DATA ·erftab2066<> + 8(SB)/8, $0.263602189790660309e-01
+DATA ·erftab2066<> + 16(SB)/8, $0.122565642281703586e-01
+DATA ·erftab2066<> + 24(SB)/8, $0.143757052860721398e-02
+DATA ·erftab2066<> + 32(SB)/8, $-.651375034121276075e-02
+DATA ·erftab2066<> + 40(SB)/8, $-.119317678849450159e-01
+DATA ·erftab2066<> + 48(SB)/8, $-.150868749549871069e-01
+DATA ·erftab2066<> + 56(SB)/8, $-.161992609578469234e-01
+DATA ·erftab2066<> + 64(SB)/8, $-.154492360403337917e-01
+DATA ·erftab2066<> + 72(SB)/8, $-.129850717389178721e-01
+DATA ·erftab2066<> + 80(SB)/8, $-.892902649276657891e-02
+DATA ·erftab2066<> + 88(SB)/8, $-.338202636596794887e-02
+DATA ·erftab2066<> + 96(SB)/8, $0.357266307045684762e-02
+DATA ·erftab2066<> + 104(SB)/8, $0.118665304327406698e-01
+DATA ·erftab2066<> + 112(SB)/8, $0.214434994118118914e-01
+DATA ·erftab2066<> + 120(SB)/8, $0.322580645161290314e-01
+GLOBL ·erftab2066<> + 0(SB), RODATA, $128
+
+// Table of +/- 1.0
+DATA ·erftab12067<> + 0(SB)/8, $1.0
+DATA ·erftab12067<> + 8(SB)/8, $-1.0
+GLOBL ·erftab12067<> + 0(SB), RODATA, $16
+
+// Erf returns the error function of the argument.
+//
+// Special cases are:
+//      Erf(+Inf) = 1
+//      Erf(-Inf) = -1
+//      Erf(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·erfAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·erfrodataL13<>+0(SB), R5
+	WORD	$0xB3CD0010	//lgdr %r1, %f0
+	FMOVD	F0, F6
+	SRAD	$48, R1
+	MOVH	$16383, R3
+	WORD	$0xEC2131BF	//risbg	%r2,%r1,49,128+63,0
+	BYTE	$0x00
+	BYTE	$0x55
+	MOVW	R2, R6
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L2
+	MOVH	$12287, R1
+	MOVW	R1, R7
+	CMPBLE	R6, R7 ,L12
+	MOVH	$16367, R1
+	MOVW	R1, R7
+	CMPBGT	R6, R7, L5
+	FMOVD	448(R5), F4
+	FMADD	F0, F0, F4
+	FMOVD	440(R5), F3
+	WFMDB	V4, V4, V2
+	FMOVD	432(R5), F0
+	FMOVD	424(R5), F1
+	WFMADB	V2, V0, V3, V0
+	FMOVD	416(R5), F3
+	WFMADB	V2, V1, V3, V1
+	FMOVD	408(R5), F5
+	FMOVD	400(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V1, V3, V1
+	FMOVD	392(R5), F5
+	FMOVD	384(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V1, V3, V1
+	FMOVD	376(R5), F5
+	FMOVD	368(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V1, V3, V1
+	FMOVD	360(R5), F5
+	FMOVD	352(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V1, V3, V2
+	WFMADB	V4, V0, V2, V0
+	WFMADB	V6, V0, V6, V0
+L1:
+	FMOVD	F0, ret+8(FP)
+	RET
+L2:
+	MOVH	R1, R1
+	MOVH	$16407, R3
+	SRW	$31, R1, R1
+	MOVW	R2, R6
+	MOVW	R3, R7
+	CMPBLE	R6, R7, L6
+	MOVW	R1, R1
+	SLD	$3, R1, R1
+	MOVD	$·erftab12067<>+0(SB), R3
+	WORD    $0x68013000     //ld %f0,0(%r1,%r3)
+	MOVH	$32751, R1
+	MOVW	R1, R7
+	CMPBGT	R6, R7, L7
+	FMOVD	344(R5), F2
+	FMADD	F2, F0, F0
+L7:
+	WFCEDBS	V6, V6, V2
+	BEQ	L1
+	FMOVD	F6, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+
+L6:
+	MOVW	R1, R1
+	SLD	$3, R1, R1
+	MOVD	$·erftab12067<>+0(SB), R4
+	WFMDB	V0, V0, V1
+	MOVH	$0x0, R3
+	WORD    $0x68014000     //ld %f0,0(%r1,%r4)
+	MOVH	$16399, R1
+	MOVW	R2, R6
+	MOVW	R1, R7
+	CMPBGT	R6, R7, L8
+	FMOVD	336(R5), F3
+	FMOVD	328(R5), F2
+	FMOVD	F1, F4
+	WFMADB	V1, V2, V3, V2
+	WORD	$0xED405140	//adb %f4,.L30-.L13(%r5)
+	BYTE	$0x00
+	BYTE	$0x1A
+	FMOVD	312(R5), F3
+	WFMADB	V1, V2, V3, V2
+	FMOVD	304(R5), F3
+	WFMADB	V1, V4, V3, V4
+	FMOVD	296(R5), F3
+	WFMADB	V1, V2, V3, V2
+	FMOVD	288(R5), F3
+	WFMADB	V1, V4, V3, V4
+	FMOVD	280(R5), F3
+	WFMADB	V1, V2, V3, V2
+	FMOVD	272(R5), F3
+	WFMADB	V1, V4, V3, V4
+L9:
+	FMOVD	264(R5), F3
+	FMUL	F4, F6
+	FMOVD	256(R5), F4
+	WFMADB	V1, V4, V3, V4
+	FDIV	F6, F2
+	WORD	$0xB3CD0014	//lgdr %r1, %f4
+	FSUB	F3, F4
+	FMOVD	248(R5), F6
+	WFMSDB	V4, V6, V1, V4
+	FMOVD	240(R5), F1
+	FMOVD	232(R5), F6
+	WFMADB	V4, V6, V1, V6
+	FMOVD	224(R5), F1
+	FMOVD	216(R5), F3
+	WFMADB	V4, V3, V1, V3
+	WFMDB	V4, V4, V1
+	FMOVD	208(R5), F5
+	WFMADB	V6, V1, V3, V6
+	FMOVD	200(R5), F3
+	MOVH	R1,R1
+	WFMADB	V4, V3, V5, V3
+	WORD	$0xEC2139BC	//risbg	%r2,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WFMADB	V1, V6, V3, V6
+	WORD	$0xEC31000F	//risbgn %r3,%r1,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	MOVD	$·erftab2066<>+0(SB), R1
+	FMOVD	192(R5), F1
+	WORD	$0xB3C10033	//ldgr %f3,%r3
+	WORD	$0xED221000	//madb %f2,%f2,0(%r2,%r1)
+	BYTE	$0x20
+	BYTE	$0x1E
+	WFMADB	V4, V6, V1, V4
+	FMUL	F3, F2
+	FMADD	F4, F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L12:
+	FMOVD	184(R5), F0
+	WFMADB	V6, V0, V6, V0
+	FMOVD	F0, ret+8(FP)
+	RET
+L5:
+	FMOVD	176(R5), F1
+	FMADD	F0, F0, F1
+	FMOVD	168(R5), F3
+	WFMDB	V1, V1, V2
+	FMOVD	160(R5), F0
+	FMOVD	152(R5), F4
+	WFMADB	V2, V0, V3, V0
+	FMOVD	144(R5), F3
+	WFMADB	V2, V4, V3, V4
+	FMOVD	136(R5), F5
+	FMOVD	128(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V4
+	FMOVD	120(R5), F5
+	FMOVD	112(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V4
+	FMOVD	104(R5), F5
+	FMOVD	96(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V4
+	FMOVD	88(R5), F5
+	FMOVD	80(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V4
+	FMOVD	72(R5), F5
+	FMOVD	64(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V4
+	FMOVD	56(R5), F5
+	FMOVD	48(R5), F3
+	WFMADB	V2, V0, V5, V0
+	WFMADB	V2, V4, V3, V2
+	FMOVD	40(R5), F4
+	WFMADB	V1, V0, V2, V0
+	FMUL	F6, F0
+	FMADD	F4, F6, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L8:
+	FMOVD	32(R5), F3
+	FMOVD	24(R5), F2
+	FMOVD	F1, F4
+	WFMADB	V1, V2, V3, V2
+	WORD	$0xED405010	//adb %f4,.L68-.L13(%r5)
+	BYTE	$0x00
+	BYTE	$0x1A
+	FMOVD	8(R5), F3
+	WFMADB	V1, V2, V3, V2
+	FMOVD	·erfrodataL13<>+0(SB), F3
+	WFMADB	V1, V4, V3, V4
+	BR	L9
diff --git a/src/math/erf_stub.s b/src/math/erf_stub.s
new file mode 100644
index 0000000..a1eccc7
--- /dev/null
+++ b/src/math/erf_stub.s
@@ -0,0 +1,14 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm
+
+#include "textflag.h"
+
+TEXT ·Erf(SB),NOSPLIT,$0
+    JMP ·erf(SB)
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+    JMP ·erfc(SB)
+
diff --git a/src/math/erfc_s390x.s b/src/math/erfc_s390x.s
new file mode 100644
index 0000000..edf5144
--- /dev/null
+++ b/src/math/erfc_s390x.s
@@ -0,0 +1,530 @@
+// Copyright 2017 The Go 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 NegInf 0xFFF0000000000000
+
+// Minimax polynomial coefficients and other constants
+DATA ·erfcrodataL38<> + 0(SB)/8, $.234875460637085087E-01
+DATA ·erfcrodataL38<> + 8(SB)/8, $.234469449299256284E-01
+DATA ·erfcrodataL38<> + 16(SB)/8, $-.606918710392844955E-04
+DATA ·erfcrodataL38<> + 24(SB)/8, $-.198827088077636213E-04
+DATA ·erfcrodataL38<> + 32(SB)/8, $.257805645845475331E-06
+DATA ·erfcrodataL38<> + 40(SB)/8, $-.184427218110620284E-09
+DATA ·erfcrodataL38<> + 48(SB)/8, $.122408098288933181E-10
+DATA ·erfcrodataL38<> + 56(SB)/8, $.484691106751495392E-07
+DATA ·erfcrodataL38<> + 64(SB)/8, $-.150147637632890281E-08
+DATA ·erfcrodataL38<> + 72(SB)/8, $23.999999999973521625
+DATA ·erfcrodataL38<> + 80(SB)/8, $27.226017111108365754
+DATA ·erfcrodataL38<> + 88(SB)/8, $-2.0
+DATA ·erfcrodataL38<> + 96(SB)/8, $0.100108802034478228E+00
+DATA ·erfcrodataL38<> + 104(SB)/8, $0.244588413746558125E+00
+DATA ·erfcrodataL38<> + 112(SB)/8, $-.669188879646637174E-01
+DATA ·erfcrodataL38<> + 120(SB)/8, $0.151311447000953551E-01
+DATA ·erfcrodataL38<> + 128(SB)/8, $-.284720833493302061E-02
+DATA ·erfcrodataL38<> + 136(SB)/8, $0.455491239358743212E-03
+DATA ·erfcrodataL38<> + 144(SB)/8, $-.631850539280720949E-04
+DATA ·erfcrodataL38<> + 152(SB)/8, $0.772532660726086679E-05
+DATA ·erfcrodataL38<> + 160(SB)/8, $-.843706007150936940E-06
+DATA ·erfcrodataL38<> + 168(SB)/8, $-.735330214904227472E-08
+DATA ·erfcrodataL38<> + 176(SB)/8, $0.753002008837084967E-09
+DATA ·erfcrodataL38<> + 184(SB)/8, $0.832482036660624637E-07
+DATA ·erfcrodataL38<> + 192(SB)/8, $-0.75
+DATA ·erfcrodataL38<> + 200(SB)/8, $.927765678007128609E-01
+DATA ·erfcrodataL38<> + 208(SB)/8, $.903621209344751506E-01
+DATA ·erfcrodataL38<> + 216(SB)/8, $-.344203375025257265E-02
+DATA ·erfcrodataL38<> + 224(SB)/8, $-.869243428221791329E-03
+DATA ·erfcrodataL38<> + 232(SB)/8, $.174699813107105603E-03
+DATA ·erfcrodataL38<> + 240(SB)/8, $.649481036316130000E-05
+DATA ·erfcrodataL38<> + 248(SB)/8, $-.895265844897118382E-05
+DATA ·erfcrodataL38<> + 256(SB)/8, $.135970046909529513E-05
+DATA ·erfcrodataL38<> + 264(SB)/8, $.277617717014748015E-06
+DATA ·erfcrodataL38<> + 272(SB)/8, $.810628018408232910E-08
+DATA ·erfcrodataL38<> + 280(SB)/8, $.210430084693497985E-07
+DATA ·erfcrodataL38<> + 288(SB)/8, $-.342138077525615091E-08
+DATA ·erfcrodataL38<> + 296(SB)/8, $-.165467946798610800E-06
+DATA ·erfcrodataL38<> + 304(SB)/8, $5.999999999988412824
+DATA ·erfcrodataL38<> + 312(SB)/8, $.468542210149072159E-01
+DATA ·erfcrodataL38<> + 320(SB)/8, $.465343528567604256E-01
+DATA ·erfcrodataL38<> + 328(SB)/8, $-.473338083650201733E-03
+DATA ·erfcrodataL38<> + 336(SB)/8, $-.147220659069079156E-03
+DATA ·erfcrodataL38<> + 344(SB)/8, $.755284723554388339E-05
+DATA ·erfcrodataL38<> + 352(SB)/8, $.116158570631428789E-05
+DATA ·erfcrodataL38<> + 360(SB)/8, $-.155445501551602389E-06
+DATA ·erfcrodataL38<> + 368(SB)/8, $-.616940119847805046E-10
+DATA ·erfcrodataL38<> + 376(SB)/8, $-.728705590727563158E-10
+DATA ·erfcrodataL38<> + 384(SB)/8, $-.983452460354586779E-08
+DATA ·erfcrodataL38<> + 392(SB)/8, $.365156164194346316E-08
+DATA ·erfcrodataL38<> + 400(SB)/8, $11.999999999996530775
+DATA ·erfcrodataL38<> + 408(SB)/8, $0.467773498104726584E-02
+DATA ·erfcrodataL38<> + 416(SB)/8, $0.206669853540920535E-01
+DATA ·erfcrodataL38<> + 424(SB)/8, $0.413339707081841473E-01
+DATA ·erfcrodataL38<> + 432(SB)/8, $0.482229658262131320E-01
+DATA ·erfcrodataL38<> + 440(SB)/8, $0.344449755901841897E-01
+DATA ·erfcrodataL38<> + 448(SB)/8, $0.130890907240765465E-01
+DATA ·erfcrodataL38<> + 456(SB)/8, $-.459266344100642687E-03
+DATA ·erfcrodataL38<> + 464(SB)/8, $-.337888800856913728E-02
+DATA ·erfcrodataL38<> + 472(SB)/8, $-.159103061687062373E-02
+DATA ·erfcrodataL38<> + 480(SB)/8, $-.501128905515922644E-04
+DATA ·erfcrodataL38<> + 488(SB)/8, $0.262775855852903132E-03
+DATA ·erfcrodataL38<> + 496(SB)/8, $0.103860982197462436E-03
+DATA ·erfcrodataL38<> + 504(SB)/8, $-.548835785414200775E-05
+DATA ·erfcrodataL38<> + 512(SB)/8, $-.157075054646618214E-04
+DATA ·erfcrodataL38<> + 520(SB)/8, $-.480056366276045110E-05
+DATA ·erfcrodataL38<> + 528(SB)/8, $0.198263013759701555E-05
+DATA ·erfcrodataL38<> + 536(SB)/8, $-.224394262958888780E-06
+DATA ·erfcrodataL38<> + 544(SB)/8, $-.321853693146683428E-06
+DATA ·erfcrodataL38<> + 552(SB)/8, $0.445073894984683537E-07
+DATA ·erfcrodataL38<> + 560(SB)/8, $0.660425940000555729E-06
+DATA ·erfcrodataL38<> + 568(SB)/8, $2.0
+DATA ·erfcrodataL38<> + 576(SB)/8, $8.63616855509444462538e-78
+DATA ·erfcrodataL38<> + 584(SB)/8, $1.00000000000000222044
+DATA ·erfcrodataL38<> + 592(SB)/8, $0.500000000000004237e+00
+DATA ·erfcrodataL38<> + 600(SB)/8, $0.416666664838056960e-01
+DATA ·erfcrodataL38<> + 608(SB)/8, $0.166666666630345592e+00
+DATA ·erfcrodataL38<> + 616(SB)/8, $0.138926439368309441e-02
+DATA ·erfcrodataL38<> + 624(SB)/8, $0.833349307718286047e-02
+DATA ·erfcrodataL38<> + 632(SB)/8, $-.693147180558298714e+00
+DATA ·erfcrodataL38<> + 640(SB)/8, $-.164659495826017651e-11
+DATA ·erfcrodataL38<> + 648(SB)/8, $.179001151181866548E+00
+DATA ·erfcrodataL38<> + 656(SB)/8, $-.144269504088896339e+01
+DATA ·erfcrodataL38<> + 664(SB)/8, $+281475245147134.9375
+DATA ·erfcrodataL38<> + 672(SB)/8, $.163116780021877404E+00
+DATA ·erfcrodataL38<> + 680(SB)/8, $-.201574395828120710E-01
+DATA ·erfcrodataL38<> + 688(SB)/8, $-.185726336009394125E-02
+DATA ·erfcrodataL38<> + 696(SB)/8, $.199349204957273749E-02
+DATA ·erfcrodataL38<> + 704(SB)/8, $-.554902415532606242E-03
+DATA ·erfcrodataL38<> + 712(SB)/8, $-.638914789660242846E-05
+DATA ·erfcrodataL38<> + 720(SB)/8, $-.424441522653742898E-04
+DATA ·erfcrodataL38<> + 728(SB)/8, $.827967511921486190E-04
+DATA ·erfcrodataL38<> + 736(SB)/8, $.913965446284062654E-05
+DATA ·erfcrodataL38<> + 744(SB)/8, $.277344791076320853E-05
+DATA ·erfcrodataL38<> + 752(SB)/8, $-.467239678927239526E-06
+DATA ·erfcrodataL38<> + 760(SB)/8, $.344814065920419986E-07
+DATA ·erfcrodataL38<> + 768(SB)/8, $-.366013491552527132E-05
+DATA ·erfcrodataL38<> + 776(SB)/8, $.181242810023783439E-05
+DATA ·erfcrodataL38<> + 784(SB)/8, $2.999999999991234567
+DATA ·erfcrodataL38<> + 792(SB)/8, $1.0
+GLOBL ·erfcrodataL38<> + 0(SB), RODATA, $800
+
+// Table of log correction terms
+DATA ·erfctab2069<> + 0(SB)/8, $0.442737824274138381e-01
+DATA ·erfctab2069<> + 8(SB)/8, $0.263602189790660309e-01
+DATA ·erfctab2069<> + 16(SB)/8, $0.122565642281703586e-01
+DATA ·erfctab2069<> + 24(SB)/8, $0.143757052860721398e-02
+DATA ·erfctab2069<> + 32(SB)/8, $-.651375034121276075e-02
+DATA ·erfctab2069<> + 40(SB)/8, $-.119317678849450159e-01
+DATA ·erfctab2069<> + 48(SB)/8, $-.150868749549871069e-01
+DATA ·erfctab2069<> + 56(SB)/8, $-.161992609578469234e-01
+DATA ·erfctab2069<> + 64(SB)/8, $-.154492360403337917e-01
+DATA ·erfctab2069<> + 72(SB)/8, $-.129850717389178721e-01
+DATA ·erfctab2069<> + 80(SB)/8, $-.892902649276657891e-02
+DATA ·erfctab2069<> + 88(SB)/8, $-.338202636596794887e-02
+DATA ·erfctab2069<> + 96(SB)/8, $0.357266307045684762e-02
+DATA ·erfctab2069<> + 104(SB)/8, $0.118665304327406698e-01
+DATA ·erfctab2069<> + 112(SB)/8, $0.214434994118118914e-01
+DATA ·erfctab2069<> + 120(SB)/8, $0.322580645161290314e-01
+GLOBL ·erfctab2069<> + 0(SB), RODATA, $128
+
+// Erfc returns the complementary error function of the argument.
+//
+// Special cases are:
+//      Erfc(+Inf) = 0
+//      Erfc(-Inf) = 2
+//      Erfc(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·erfcAsm(SB), NOSPLIT, $0-16
+	//special case Erfc(+Inf) = 0
+	MOVD	x+0(FP), R1
+	MOVD	$NegInf, R2
+	CMPUBEQ	R1, R2, erfcIsPosInf
+
+	FMOVD	x+0(FP), F0
+	MOVD	$·erfcrodataL38<>+0(SB), R9
+	WORD	$0xB3CD0010	//lgdr %r1, %f0
+	FMOVD	F0, F2
+	SRAD	$48, R1
+	MOVH	$0x3FFF, R3
+	MOVH	R1, R2
+	ANDW	$0x7FFF, R1
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L2
+	MOVH	$0x3FEF, R3
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L3
+	MOVH	$0x2FFF, R2
+	MOVW	R2, R7
+	CMPBGT	R6, R7, L4
+	FMOVD	792(R9), F0
+	WFSDB	V2, V0, V2
+	FMOVD	F2, ret+8(FP)
+	RET
+
+L2:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	MOVH	$0x0, R4
+	BLTU	L3
+	FMOVD	F0, F1
+L9:
+	MOVH	$0x400F, R3
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L10
+	FMOVD	784(R9), F3
+	FSUB	F1, F3
+	VLEG	$0, 776(R9), V20
+	WFDDB	V1, V3, V6
+	VLEG	$0, 768(R9), V18
+	FMOVD	760(R9), F7
+	FMOVD	752(R9), F5
+	VLEG	$0, 744(R9), V16
+	FMOVD	736(R9), F3
+	FMOVD	728(R9), F2
+	FMOVD	720(R9), F4
+	WFMDB	V6, V6, V1
+	FMUL	F0, F0
+	MOVH	$0x0, R3
+	WFMADB	V1, V7, V20, V7
+	WFMADB	V1, V5, V18, V5
+	WFMADB	V1, V7, V16, V7
+	WFMADB	V1, V5, V3, V5
+	WFMADB	V1, V7, V4, V7
+	WFMADB	V1, V5, V2, V5
+	FMOVD	712(R9), F2
+	WFMADB	V1, V7, V2, V7
+	FMOVD	704(R9), F2
+	WFMADB	V1, V5, V2, V5
+	FMOVD	696(R9), F2
+	WFMADB	V1, V7, V2, V7
+	FMOVD	688(R9), F2
+	MOVH	$0x0, R1
+	WFMADB	V1, V5, V2, V5
+	FMOVD	680(R9), F2
+	WFMADB	V1, V7, V2, V7
+	FMOVD	672(R9), F2
+	WFMADB	V1, V5, V2, V1
+	FMOVD	664(R9), F3
+	WFMADB	V6, V7, V1, V7
+	FMOVD	656(R9), F5
+	FMOVD	648(R9), F2
+	WFMADB	V0, V5, V3, V5
+	WFMADB	V6, V7, V2, V7
+L11:
+	WORD	$0xB3CD0065	//lgdr %r6, %f5
+	WFSDB	V0, V0, V2
+	WORD	$0xED509298	//sdb	%f5,.L55-.L38(%r9)
+	BYTE	$0x00
+	BYTE	$0x1B
+	FMOVD	640(R9), F6
+	FMOVD	632(R9), F4
+	WFMSDB	V5, V6, V2, V6
+	WFMSDB	V5, V4, V0, V4
+	FMOVD	624(R9), F2
+	FADD	F6, F4
+	FMOVD	616(R9), F0
+	FMOVD	608(R9), F6
+	WFMADB	V4, V0, V2, V0
+	FMOVD	600(R9), F3
+	WFMDB	V4, V4, V2
+	MOVH	R6,R6
+	ADD	R6, R3
+	WFMADB	V4, V3, V6, V3
+	FMOVD	592(R9), F6
+	WFMADB	V0, V2, V3, V0
+	FMOVD	584(R9), F3
+	WFMADB	V4, V6, V3, V6
+	WORD	$0xECC339BC	//risbg	%r12,%r3,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WFMADB	V2, V0, V6, V0
+	MOVD	$·erfctab2069<>+0(SB), R5
+	WORD	$0x682C5000	//ld	%f2,0(%r12,%r5)
+	FMADD	F2, F4, F4
+	WORD	$0xEC43000F	//risbgn	%r4,%r3,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WFMADB	V4, V0, V2, V4
+	WORD	$0xB3C10024	//ldgr	%f2,%r4
+	FMADD	F4, F2, F2
+	MOVW	R2, R6
+	CMPBLE	R6, $0, L20
+	MOVW	R1, R6
+	CMPBEQ	R6, $0, L21
+	WORD	$0xED709240	//mdb	%f7,.L66-.L38(%r9)
+	BYTE	$0x00
+	BYTE	$0x1C
+L21:
+	FMUL	F7, F2
+L1:
+	FMOVD	F2, ret+8(FP)
+	RET
+L3:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L30
+	FMOVD	568(R9), F2
+	WFSDB	V0, V2, V0
+L8:
+	WFMDB	V0, V0, V4
+	FMOVD	560(R9), F2
+	FMOVD	552(R9), F6
+	FMOVD	544(R9), F1
+	WFMADB	V4, V6, V2, V6
+	FMOVD	536(R9), F2
+	WFMADB	V4, V1, V2, V1
+	FMOVD	528(R9), F3
+	FMOVD	520(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	512(R9), F3
+	FMOVD	504(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	496(R9), F3
+	FMOVD	488(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	480(R9), F3
+	FMOVD	472(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	464(R9), F3
+	FMOVD	456(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	448(R9), F3
+	FMOVD	440(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	432(R9), F3
+	FMOVD	424(R9), F2
+	WFMADB	V4, V6, V3, V6
+	WFMADB	V4, V1, V2, V1
+	FMOVD	416(R9), F3
+	FMOVD	408(R9), F2
+	WFMADB	V4, V6, V3, V6
+	FMADD	F1, F4, F2
+	FMADD	F6, F0, F2
+	MOVW	R2, R6
+	CMPBGE	R6, $0, L1
+	FMOVD	568(R9), F0
+	WFSDB	V2, V0, V2
+	BR	L1
+L10:
+	MOVH	$0x401F, R3
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBLE	R6, R7, L36
+	MOVH	$0x402F, R3
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L13
+	FMOVD	400(R9), F3
+	FSUB	F1, F3
+	VLEG	$0, 392(R9), V20
+	WFDDB	V1, V3, V6
+	VLEG	$0, 384(R9), V18
+	FMOVD	376(R9), F2
+	FMOVD	368(R9), F4
+	VLEG	$0, 360(R9), V16
+	FMOVD	352(R9), F7
+	FMOVD	344(R9), F3
+	FMUL	F0, F0
+	WFMDB	V6, V6, V1
+	FMOVD	656(R9), F5
+	MOVH	$0x0, R3
+	WFMADB	V1, V2, V20, V2
+	WFMADB	V1, V4, V18, V4
+	WFMADB	V1, V2, V16, V2
+	WFMADB	V1, V4, V7, V4
+	WFMADB	V1, V2, V3, V2
+	FMOVD	336(R9), F3
+	WFMADB	V1, V4, V3, V4
+	FMOVD	328(R9), F3
+	WFMADB	V1, V2, V3, V2
+	FMOVD	320(R9), F3
+	WFMADB	V1, V4, V3, V1
+	FMOVD	312(R9), F7
+	WFMADB	V6, V2, V1, V2
+	MOVH	$0x0, R1
+	FMOVD	664(R9), F3
+	FMADD	F2, F6, F7
+	WFMADB	V0, V5, V3, V5
+	BR	L11
+L35:
+	WORD	$0xB3130010	//lcdbr	%f1,%f0
+	BR	L9
+L36:
+	FMOVD	304(R9), F3
+	FSUB	F1, F3
+	VLEG	$0, 296(R9), V20
+	WFDDB	V1, V3, V6
+	FMOVD	288(R9), F5
+	FMOVD	280(R9), F1
+	FMOVD	272(R9), F2
+	VLEG	$0, 264(R9), V18
+	VLEG	$0, 256(R9), V16
+	FMOVD	248(R9), F3
+	FMOVD	240(R9), F4
+	WFMDB	V6, V6, V7
+	FMUL	F0, F0
+	MOVH	$0x0, R3
+	FMADD	F5, F7, F1
+	WFMADB	V7, V2, V20, V2
+	WFMADB	V7, V1, V18, V1
+	WFMADB	V7, V2, V16, V2
+	WFMADB	V7, V1, V3, V1
+	WFMADB	V7, V2, V4, V2
+	FMOVD	232(R9), F4
+	WFMADB	V7, V1, V4, V1
+	FMOVD	224(R9), F4
+	WFMADB	V7, V2, V4, V2
+	FMOVD	216(R9), F4
+	WFMADB	V7, V1, V4, V1
+	FMOVD	208(R9), F4
+	MOVH	$0x0, R1
+	WFMADB	V7, V2, V4, V7
+	FMOVD	656(R9), F5
+	WFMADB	V6, V1, V7, V1
+	FMOVD	664(R9), F3
+	FMOVD	200(R9), F7
+	WFMADB	V0, V5, V3, V5
+	FMADD	F1, F6, F7
+	BR	L11
+L4:
+	FMOVD	192(R9), F1
+	FMADD	F0, F0, F1
+	FMOVD	184(R9), F3
+	WFMDB	V1, V1, V0
+	FMOVD	176(R9), F4
+	FMOVD	168(R9), F6
+	WFMADB	V0, V4, V3, V4
+	FMOVD	160(R9), F3
+	WFMADB	V0, V6, V3, V6
+	FMOVD	152(R9), F5
+	FMOVD	144(R9), F3
+	WFMADB	V0, V4, V5, V4
+	WFMADB	V0, V6, V3, V6
+	FMOVD	136(R9), F5
+	FMOVD	128(R9), F3
+	WFMADB	V0, V4, V5, V4
+	WFMADB	V0, V6, V3, V6
+	FMOVD	120(R9), F5
+	FMOVD	112(R9), F3
+	WFMADB	V0, V4, V5, V4
+	WFMADB	V0, V6, V3, V6
+	FMOVD	104(R9), F5
+	FMOVD	96(R9), F3
+	WFMADB	V0, V4, V5, V4
+	WFMADB	V0, V6, V3, V0
+	FMOVD	F2, F6
+	FMADD	F4, F1, F0
+	WORD	$0xED609318	//sdb	%f6,.L39-.L38(%r9)
+	BYTE	$0x00
+	BYTE	$0x1B
+	WFMSDB	V2, V0, V6, V2
+	FMOVD	F2, ret+8(FP)
+	RET
+L30:
+	WORD	$0xED009238	//adb	%f0,.L67-.L38(%r9)
+	BYTE	$0x00
+	BYTE	$0x1A
+	BR	L8
+L20:
+	FMOVD	88(R9), F0
+	WFMADB	V7, V2, V0, V2
+	WORD	$0xB3130022	//lcdbr	%f2,%f2
+	FMOVD	F2, ret+8(FP)
+	RET
+L13:
+	MOVH	$0x403A, R3
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBLE	R6, R7, L4
+	WORD	$0xED109050	//cdb	%f1,.L128-.L38(%r9)
+	BYTE	$0x00
+	BYTE	$0x19
+	BGE	L37
+	BVS	L37
+	FMOVD	72(R9), F6
+	FSUB	F1, F6
+	MOVH	$0x1000, R3
+	FDIV	F1, F6
+	MOVH	$0x1000, R1
+L17:
+	WFMDB	V6, V6, V1
+	FMOVD	64(R9), F2
+	FMOVD	56(R9), F4
+	FMOVD	48(R9), F3
+	WFMADB	V1, V3, V2, V3
+	FMOVD	40(R9), F2
+	WFMADB	V1, V2, V4, V2
+	FMOVD	32(R9), F4
+	WFMADB	V1, V3, V4, V3
+	FMOVD	24(R9), F4
+	WFMADB	V1, V2, V4, V2
+	FMOVD	16(R9), F4
+	WFMADB	V1, V3, V4, V3
+	FMOVD	8(R9), F4
+	WFMADB	V1, V2, V4, V1
+	FMUL	F0, F0
+	WFMADB	V3, V6, V1, V3
+	FMOVD	656(R9), F5
+	FMOVD	664(R9), F4
+	FMOVD	0(R9), F7
+	WFMADB	V0, V5, V4, V5
+	FMADD	F6, F3, F7
+	BR	L11
+L14:
+	FMOVD	72(R9), F6
+	FSUB	F1, F6
+	MOVH	$0x403A, R3
+	FDIV	F1, F6
+	MOVW	R1, R6
+	MOVW	R3, R7
+	CMPBEQ	R6, R7, L23
+	MOVH	$0x0, R3
+	MOVH	$0x0, R1
+	BR	L17
+L37:
+	WFCEDBS	V0, V0, V0
+	BVS	L1
+	MOVW	R2, R6
+	CMPBLE	R6, $0, L18
+	MOVH	$0x7FEF, R2
+	MOVW	R1, R6
+	MOVW	R2, R7
+	CMPBGT	R6, R7, L24
+
+	WORD	$0xA5400010	//iihh	%r4,16
+	WORD	$0xB3C10024	//ldgr	%f2,%r4
+	FMUL	F2, F2
+	BR	L1
+L23:
+	MOVH	$0x1000, R3
+	MOVH	$0x1000, R1
+	BR	L17
+L24:
+	FMOVD	$0, F2
+	BR	L1
+L18:
+	MOVH	$0x7FEF, R2
+	MOVW	R1, R6
+	MOVW	R2, R7
+	CMPBGT	R6, R7, L25
+	WORD	$0xA5408010	//iihh	%r4,32784
+	FMOVD	568(R9), F2
+	WORD	$0xB3C10004	//ldgr	%f0,%r4
+	FMADD	F2, F0, F2
+	BR	L1
+L25:
+	FMOVD	568(R9), F2
+	BR	L1
+erfcIsPosInf:
+	FMOVD	$(2.0), F1
+	FMOVD	F1, ret+8(FP)
+	RET
+
diff --git a/src/math/exp_amd64.s b/src/math/exp_amd64.s
index f63efec..96f01b7 100644
--- a/src/math/exp_amd64.s
+++ b/src/math/exp_amd64.s
@@ -31,10 +31,11 @@
 #define T7 2.4801587301587301587e-5
 #define PosInf 0x7FF0000000000000
 #define NegInf 0xFFF0000000000000
+#define Overflow 7.09782712893384e+02
 
 // func Exp(x float64) float64
 TEXT ·Exp(SB),NOSPLIT,$0
-// test bits for not-finite
+	// test bits for not-finite
 	MOVQ    x+0(FP), BX
 	MOVQ    $~(1<<63), AX // sign bit mask
 	MOVQ    BX, DX
@@ -42,7 +43,11 @@ TEXT ·Exp(SB),NOSPLIT,$0
 	MOVQ    $PosInf, AX
 	CMPQ    AX, DX
 	JLE     notFinite
+	// check if argument will overflow
 	MOVQ    BX, X0
+	MOVSD   $Overflow, X1
+	COMISD  X1, X0
+	JA      overflow
 	MOVSD   $LOG2E, X1
 	MULSD   X0, X1
 	CVTSD2SL X1, BX // BX = exponent
diff --git a/src/math/exp_s390x.s b/src/math/exp_s390x.s
new file mode 100644
index 0000000..dac0a5c
--- /dev/null
+++ b/src/math/exp_s390x.s
@@ -0,0 +1,185 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial approximation and other constants
+DATA ·exprodataL22<> + 0(SB)/8, $800.0E+00
+DATA ·exprodataL22<> + 8(SB)/8, $1.0000000000000022e+00
+DATA ·exprodataL22<> + 16(SB)/8, $0.500000000000004237e+00
+DATA ·exprodataL22<> + 24(SB)/8, $0.166666666630345592e+00
+DATA ·exprodataL22<> + 32(SB)/8, $0.138926439368309441e-02
+DATA ·exprodataL22<> + 40(SB)/8, $0.833349307718286047e-02
+DATA ·exprodataL22<> + 48(SB)/8, $0.416666664838056960e-01
+DATA ·exprodataL22<> + 56(SB)/8, $-.231904681384629956E-16
+DATA ·exprodataL22<> + 64(SB)/8, $-.693147180559945286E+00
+DATA ·exprodataL22<> + 72(SB)/8, $0.144269504088896339E+01
+DATA ·exprodataL22<> + 80(SB)/8, $704.0E+00
+GLOBL ·exprodataL22<> + 0(SB), RODATA, $88
+
+DATA ·expxinf<> + 0(SB)/8, $0x7ff0000000000000
+GLOBL ·expxinf<> + 0(SB), RODATA, $8
+DATA ·expx4ff<> + 0(SB)/8, $0x4ff0000000000000
+GLOBL ·expx4ff<> + 0(SB), RODATA, $8
+DATA ·expx2ff<> + 0(SB)/8, $0x2ff0000000000000
+GLOBL ·expx2ff<> + 0(SB), RODATA, $8
+DATA ·expxaddexp<> + 0(SB)/8, $0xc2f0000100003fef
+GLOBL ·expxaddexp<> + 0(SB), RODATA, $8
+
+// Log multipliers table
+DATA ·exptexp<> + 0(SB)/8, $0.442737824274138381E-01
+DATA ·exptexp<> + 8(SB)/8, $0.263602189790660309E-01
+DATA ·exptexp<> + 16(SB)/8, $0.122565642281703586E-01
+DATA ·exptexp<> + 24(SB)/8, $0.143757052860721398E-02
+DATA ·exptexp<> + 32(SB)/8, $-.651375034121276075E-02
+DATA ·exptexp<> + 40(SB)/8, $-.119317678849450159E-01
+DATA ·exptexp<> + 48(SB)/8, $-.150868749549871069E-01
+DATA ·exptexp<> + 56(SB)/8, $-.161992609578469234E-01
+DATA ·exptexp<> + 64(SB)/8, $-.154492360403337917E-01
+DATA ·exptexp<> + 72(SB)/8, $-.129850717389178721E-01
+DATA ·exptexp<> + 80(SB)/8, $-.892902649276657891E-02
+DATA ·exptexp<> + 88(SB)/8, $-.338202636596794887E-02
+DATA ·exptexp<> + 96(SB)/8, $0.357266307045684762E-02
+DATA ·exptexp<> + 104(SB)/8, $0.118665304327406698E-01
+DATA ·exptexp<> + 112(SB)/8, $0.214434994118118914E-01
+DATA ·exptexp<> + 120(SB)/8, $0.322580645161290314E-01
+GLOBL ·exptexp<> + 0(SB), RODATA, $128
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+//      Exp(+Inf) = +Inf
+//      Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+// The algorithm used is minimax polynomial approximation using a table of
+// polynomial coefficients determined with a Remez exchange algorithm.
+
+TEXT	·expAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·exprodataL22<>+0(SB), R5
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L20
+	FMOVD	F0, F2
+L2:
+	WORD	$0xED205050	//cdb	%f2,.L23-.L22(%r5)
+	BYTE	$0x00
+	BYTE	$0x19
+	BGE	L16
+	BVS	L16
+	WFCEDBS	V2, V2, V2
+	BVS	LEXITTAGexp
+	MOVD	$·expxaddexp<>+0(SB), R1
+	FMOVD	72(R5), F6
+	FMOVD	0(R1), F2
+	WFMSDB	V0, V6, V2, V6
+	FMOVD	64(R5), F4
+	FADD	F6, F2
+	FMOVD	56(R5), F1
+	FMADD	F4, F2, F0
+	FMOVD	48(R5), F3
+	WFMADB	V2, V1, V0, V2
+	FMOVD	40(R5), F1
+	FMOVD	32(R5), F4
+	FMUL	F0, F0
+	WFMADB	V2, V4, V1, V4
+	WORD	$0xB3CD0016	//lgdr	%r1,%f6
+	FMOVD	24(R5), F1
+	WFMADB	V2, V3, V1, V3
+	FMOVD	16(R5), F1
+	WFMADB	V0, V4, V3, V4
+	FMOVD	8(R5), F3
+	WFMADB	V2, V1, V3, V1
+	WORD	$0xEC3139BC	//risbg	%r3,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WFMADB	V0, V4, V1, V0
+	MOVD	$·exptexp<>+0(SB), R2
+	WORD	$0x68432000	//ld	%f4,0(%r3,%r2)
+	FMADD	F4, F2, F2
+	SLD	$48, R1, R2
+	WFMADB	V2, V0, V4, V2
+	WORD	$0xB3C10002	//ldgr	%f0,%r2
+	FMADD	F0, F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L16:
+	WFCEDBS	V2, V2, V4
+	BVS	LEXITTAGexp
+	WORD	$0xED205000	//cdb	%f2,.L33-.L22(%r5)
+	BYTE	$0x00
+	BYTE	$0x19
+	BLT	L6
+	WFCEDBS	V2, V0, V0
+	BVS	L13
+	MOVD	$·expxinf<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L20:
+	WORD	$0xB3130020	//lcdbr	%f2,%f0
+	BR	L2
+L6:
+	MOVD	$·expxaddexp<>+0(SB), R1
+	FMOVD	72(R5), F3
+	FMOVD	0(R1), F4
+	WFMSDB	V0, V3, V4, V3
+	FMOVD	64(R5), F6
+	FADD	F3, F4
+	FMOVD	56(R5), F5
+	WFMADB	V4, V6, V0, V6
+	FMOVD	32(R5), F1
+	WFMADB	V4, V5, V6, V4
+	FMOVD	40(R5), F5
+	FMUL	F6, F6
+	WFMADB	V4, V1, V5, V1
+	FMOVD	48(R5), F7
+	WORD	$0xB3CD0013	//lgdr	%r1,%f3
+	FMOVD	24(R5), F5
+	WFMADB	V4, V7, V5, V7
+	FMOVD	16(R5), F5
+	WFMADB	V6, V1, V7, V1
+	FMOVD	8(R5), F7
+	WFMADB	V4, V5, V7, V5
+	WORD	$0xEC3139BC	//risbg	%r3,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WFMADB	V6, V1, V5, V6
+	MOVD	$·exptexp<>+0(SB), R2
+	WFCHDBS	V2, V0, V0
+	WORD	$0x68132000	//ld	%f1,0(%r3,%r2)
+	FMADD	F1, F4, F4
+	MOVD	$0x4086000000000000, R2
+	WFMADB	V4, V6, V1, V4
+	BEQ	L21
+	ADDW	$0xF000, R1
+	WORD	$0xEC21000F	//risbgn	%r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xB3C10002	//ldgr	%f0,%r2
+	FMADD	F0, F4, F0
+	MOVD	$·expx4ff<>+0(SB), R3
+	FMOVD	0(R3), F2
+	FMUL	F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L13:
+	FMOVD	$0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L21:
+	ADDW	$0x1000, R1
+	WORD	$0xEC21000F	//risbgn	%r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xB3C10002	//ldgr	%f0,%r2
+	FMADD	F0, F4, F0
+	MOVD	$·expx2ff<>+0(SB), R3
+	FMOVD	0(R3), F2
+	FMUL	F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+LEXITTAGexp:
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/expm1_s390x.s b/src/math/expm1_s390x.s
new file mode 100644
index 0000000..641b2a8
--- /dev/null
+++ b/src/math/expm1_s390x.s
@@ -0,0 +1,202 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial approximation and other constants
+DATA ·expm1rodataL22<> + 0(SB)/8, $-1.0
+DATA ·expm1rodataL22<> + 8(SB)/8, $800.0E+00
+DATA ·expm1rodataL22<> + 16(SB)/8, $1.0
+DATA ·expm1rodataL22<> + 24(SB)/8, $-.231904681384629956E-16
+DATA ·expm1rodataL22<> + 32(SB)/8, $0.50000000000000029671E+00
+DATA ·expm1rodataL22<> + 40(SB)/8, $0.16666666666666676570E+00
+DATA ·expm1rodataL22<> + 48(SB)/8, $0.83333333323590973444E-02
+DATA ·expm1rodataL22<> + 56(SB)/8, $0.13889096526400683566E-02
+DATA ·expm1rodataL22<> + 64(SB)/8, $0.41666666661701152924E-01
+DATA ·expm1rodataL22<> + 72(SB)/8, $0.19841562053987360264E-03
+DATA ·expm1rodataL22<> + 80(SB)/8, $-.693147180559945286E+00
+DATA ·expm1rodataL22<> + 88(SB)/8, $0.144269504088896339E+01
+DATA ·expm1rodataL22<> + 96(SB)/8, $704.0E+00
+GLOBL ·expm1rodataL22<> + 0(SB), RODATA, $104
+
+DATA ·expm1xmone<> + 0(SB)/8, $0xbff0000000000000
+GLOBL ·expm1xmone<> + 0(SB), RODATA, $8
+DATA ·expm1xinf<> + 0(SB)/8, $0x7ff0000000000000
+GLOBL ·expm1xinf<> + 0(SB), RODATA, $8
+DATA ·expm1x4ff<> + 0(SB)/8, $0x4ff0000000000000
+GLOBL ·expm1x4ff<> + 0(SB), RODATA, $8
+DATA ·expm1x2ff<> + 0(SB)/8, $0x2ff0000000000000
+GLOBL ·expm1x2ff<> + 0(SB), RODATA, $8
+DATA ·expm1xaddexp<> + 0(SB)/8, $0xc2f0000100003ff0
+GLOBL ·expm1xaddexp<> + 0(SB), RODATA, $8
+
+// Log multipliers table
+DATA ·expm1tab<> + 0(SB)/8, $0.0
+DATA ·expm1tab<> + 8(SB)/8, $-.171540871271399150E-01
+DATA ·expm1tab<> + 16(SB)/8, $-.306597931864376363E-01
+DATA ·expm1tab<> + 24(SB)/8, $-.410200970469965021E-01
+DATA ·expm1tab<> + 32(SB)/8, $-.486343079978231466E-01
+DATA ·expm1tab<> + 40(SB)/8, $-.538226193725835820E-01
+DATA ·expm1tab<> + 48(SB)/8, $-.568439602538111520E-01
+DATA ·expm1tab<> + 56(SB)/8, $-.579091847395528847E-01
+DATA ·expm1tab<> + 64(SB)/8, $-.571909584179366341E-01
+DATA ·expm1tab<> + 72(SB)/8, $-.548312665987204407E-01
+DATA ·expm1tab<> + 80(SB)/8, $-.509471843643441085E-01
+DATA ·expm1tab<> + 88(SB)/8, $-.456353588448863359E-01
+DATA ·expm1tab<> + 96(SB)/8, $-.389755254243262365E-01
+DATA ·expm1tab<> + 104(SB)/8, $-.310332908285244231E-01
+DATA ·expm1tab<> + 112(SB)/8, $-.218623539150173528E-01
+DATA ·expm1tab<> + 120(SB)/8, $-.115062908917949451E-01
+GLOBL ·expm1tab<> + 0(SB), RODATA, $128
+
+// Expm1 returns e**x - 1, the base-e exponential of x minus 1.
+// It is more accurate than Exp(x) - 1 when x is near zero.
+//
+// Special cases are:
+//      Expm1(+Inf) = +Inf
+//      Expm1(-Inf) = -1
+//      Expm1(NaN) = NaN
+// Very large values overflow to -1 or +Inf.
+// The algorithm used is minimax polynomial approximation using a table of
+// polynomial coefficients determined with a Remez exchange algorithm.
+
+TEXT	·expm1Asm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·expm1rodataL22<>+0(SB), R5
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L20
+	FMOVD	F0, F2
+L2:
+	WORD	$0xED205060	//cdb	%f2,.L23-.L22(%r5)
+	BYTE	$0x00
+	BYTE	$0x19
+	BGE	L16
+	BVS	L16
+	WFCEDBS	V2, V2, V2
+	BVS	LEXITTAGexpm1
+	MOVD	$·expm1xaddexp<>+0(SB), R1
+	FMOVD	88(R5), F1
+	FMOVD	0(R1), F2
+	WFMSDB	V0, V1, V2, V1
+	FMOVD	80(R5), F6
+	WFADB	V1, V2, V4
+	FMOVD	72(R5), F2
+	FMADD	F6, F4, F0
+	FMOVD	64(R5), F3
+	FMOVD	56(R5), F6
+	FMOVD	48(R5), F5
+	FMADD	F2, F0, F6
+	WFMADB	V0, V5, V3, V5
+	WFMDB	V0, V0, V2
+	WORD	$0xB3CD0011	//lgdr	%r1,%f1
+	WFMADB	V6, V2, V5, V6
+	FMOVD	40(R5), F3
+	FMOVD	32(R5), F5
+	WFMADB	V0, V3, V5, V3
+	FMOVD	24(R5), F5
+	WFMADB	V2, V6, V3, V2
+	FMADD	F5, F4, F0
+	FMOVD	16(R5), F6
+	WFMADB	V0, V2, V6, V2
+	WORD	$0xEC3139BC	//risbg	%r3,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WORD	$0xB3130022	//lcdbr	%f2,%f2
+	MOVD	$·expm1tab<>+0(SB), R2
+	WORD	$0x68432000	//ld	%f4,0(%r3,%r2)
+	FMADD	F4, F0, F0
+	SLD	$48, R1, R2
+	WFMSDB	V2, V0, V4, V0
+	WORD	$0xB3C10042	//ldgr	%f4,%r2
+	WORD	$0xB3130000	//lcdbr	%f0,%f0
+	FSUB	F4, F6
+	WFMSDB	V0, V4, V6, V0
+	FMOVD	F0, ret+8(FP)
+	RET
+L16:
+	WFCEDBS	V2, V2, V4
+	BVS	LEXITTAGexpm1
+	WORD	$0xED205008	//cdb	%f2,.L34-.L22(%r5)
+	BYTE	$0x00
+	BYTE	$0x19
+	BLT	L6
+	WFCEDBS	V2, V0, V0
+	BVS	L7
+	MOVD	$·expm1xinf<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L20:
+	WORD	$0xB3130020	//lcdbr	%f2,%f0
+	BR	L2
+L6:
+	MOVD	$·expm1xaddexp<>+0(SB), R1
+	FMOVD	88(R5), F5
+	FMOVD	0(R1), F4
+	WFMSDB	V0, V5, V4, V5
+	FMOVD	80(R5), F3
+	WFADB	V5, V4, V1
+	VLEG	$0, 48(R5), V16
+	WFMADB	V1, V3, V0, V3
+	FMOVD	56(R5), F4
+	FMOVD	64(R5), F7
+	FMOVD	72(R5), F6
+	WFMADB	V3, V16, V7, V16
+	WFMADB	V3, V6, V4, V6
+	WFMDB	V3, V3, V4
+	MOVD	$·expm1tab<>+0(SB), R2
+	WFMADB	V6, V4, V16, V6
+	VLEG	$0, 32(R5), V16
+	FMOVD	40(R5), F7
+	WFMADB	V3, V7, V16, V7
+	VLEG	$0, 24(R5), V16
+	WFMADB	V4, V6, V7, V4
+	WFMADB	V1, V16, V3, V1
+	FMOVD	16(R5), F6
+	FMADD	F4, F1, F6
+	WORD	$0xB3CD0015	//lgdr	%r1,%f5
+	WORD	$0xB3130066	//lcdbr	%f6,%f6
+	WORD	$0xEC3139BC	//risbg	%r3,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WORD	$0x68432000	//ld	%f4,0(%r3,%r2)
+	FMADD	F4, F1, F1
+	MOVD	$0x4086000000000000, R2
+	FMSUB	F1, F6, F4
+	WORD	$0xB3130044	//lcdbr	%f4,%f4
+	WFCHDBS	V2, V0, V0
+	BEQ	L21
+	ADDW	$0xF000, R1
+	WORD	$0xEC21000F	//risbgn	%r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xB3C10002	//ldgr	%f0,%r2
+	FMADD	F0, F4, F0
+	MOVD	$·expm1x4ff<>+0(SB), R3
+	FMOVD	0(R5), F4
+	FMOVD	0(R3), F2
+	WFMADB	V2, V0, V4, V0
+	FMOVD	F0, ret+8(FP)
+	RET
+L7:
+	MOVD	$·expm1xmone<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L21:
+	ADDW	$0x1000, R1
+	WORD	$0xEC21000F	//risbgn	%r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xB3C10002	//ldgr	%f0,%r2
+	FMADD	F0, F4, F0
+	MOVD	$·expm1x2ff<>+0(SB), R3
+	FMOVD	0(R5), F4
+	FMOVD	0(R3), F2
+	WFMADB	V2, V0, V4, V0
+	FMOVD	F0, ret+8(FP)
+	RET
+LEXITTAGexpm1:
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/export_s390x_test.go b/src/math/export_s390x_test.go
index 3fdbd86..827bf1c 100644
--- a/src/math/export_s390x_test.go
+++ b/src/math/export_s390x_test.go
@@ -11,4 +11,21 @@ var CoshNoVec = cosh
 var SinNoVec = sin
 var SinhNoVec = sinh
 var TanhNoVec = tanh
+var Log1pNovec = log1p
+var AtanhNovec = atanh
+var AcosNovec = acos
+var AcoshNovec = acosh
+var AsinNovec = asin
+var AsinhNovec = asinh
+var ErfNovec = erf
+var ErfcNovec = erfc
+var AtanNovec = atan
+var Atan2Novec = atan2
+var CbrtNovec = cbrt
+var LogNovec = log
+var TanNovec = tan
+var ExpNovec = exp
+var Expm1Novec = expm1
+var PowNovec = pow
+var HypotNovec = hypot
 var HasVX = hasVX
diff --git a/src/math/floor_amd64.s b/src/math/floor_amd64.s
index aa10ee8..678d643 100644
--- a/src/math/floor_amd64.s
+++ b/src/math/floor_amd64.s
@@ -6,20 +6,9 @@
 
 #define Big		0x4330000000000000 // 2**52
 
-// func hasSSE4() bool
-// returns whether SSE4.1 is supported
-TEXT ·hasSSE4(SB),NOSPLIT,$0
-	XORQ AX, AX
-	INCL AX
-	CPUID
-	SHRQ $19, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
-	RET
-
 // func Floor(x float64) float64
 TEXT ·Floor(SB),NOSPLIT,$0
-	CMPB    math·useSSE4(SB), $1
+	CMPB    ·useSSE41(SB), $1
 	JNE     nosse4
 	ROUNDSD $1, x+0(FP), X0
 	MOVQ X0, ret+8(FP)
@@ -47,7 +36,7 @@ isBig_floor:
 
 // func Ceil(x float64) float64
 TEXT ·Ceil(SB),NOSPLIT,$0
-	CMPB    math·useSSE4(SB), $1
+	CMPB    ·useSSE41(SB), $1
 	JNE     nosse4
 	ROUNDSD $2, x+0(FP), X0
 	MOVQ X0, ret+8(FP)
diff --git a/src/math/floor_asm.go b/src/math/floor_asm.go
index 28e56a5..fdec112 100644
--- a/src/math/floor_asm.go
+++ b/src/math/floor_asm.go
@@ -6,7 +6,6 @@
 
 package math
 
-//defined in floor_amd64.s
-func hasSSE4() bool
+import "internal/cpu"
 
-var useSSE4 = hasSSE4()
+var useSSE41 = cpu.X86.HasSSE41
diff --git a/src/math/jn.go b/src/math/jn.go
index 3422782..4a8ddfa 100644
--- a/src/math/jn.go
+++ b/src/math/jn.go
@@ -226,10 +226,10 @@ func Jn(n int, x float64) float64 {
 //
 // Special cases are:
 //	Yn(n, +Inf) = 0
-//	Yn(n > 0, 0) = -Inf
+//	Yn(n ≥ 0, 0) = -Inf
 //	Yn(n < 0, 0) = +Inf if n is odd, -Inf if n is even
-//	Y1(n, x < 0) = NaN
-//	Y1(n, NaN) = NaN
+//	Yn(n, x < 0) = NaN
+//	Yn(n, NaN) = NaN
 func Yn(n int, x float64) float64 {
 	const Two302 = 1 << 302 // 2**302 0x52D0000000000000
 	// special cases
diff --git a/src/math/log10_s390x.s b/src/math/log10_s390x.s
index 460bcd9..edbc181 100644
--- a/src/math/log10_s390x.s
+++ b/src/math/log10_s390x.s
@@ -108,7 +108,7 @@ L8:
 	ORW     $0x45000000, R2
 L4:
 	FMOVD   log10rodataL19<>+120(SB), F2
-	WORD    $0xB3C10041     //ldgr  %f4,%r1
+	LDGR    R1, F4
 	WFMADB  V4, V0, V2, V0
 	FMOVD   log10rodataL19<>+112(SB), F4
 	FMOVD   log10rodataL19<>+104(SB), F6
@@ -140,7 +140,7 @@ L4:
 	WORD    $0x68331000     //ld %f3,0(%r3,%r1)
 	WFMADB  V0, V4, V3, V0
 	FMOVD   log10rodataL19<>+24(SB), F4
-	FMADD   F4, F2, F0, F0
+	FMADD   F4, F2, F0
 	FMOVD   F0, ret+8(FP)
 	RET
 
diff --git a/src/math/log1p_s390x.s b/src/math/log1p_s390x.s
new file mode 100644
index 0000000..c7e9860
--- /dev/null
+++ b/src/math/log1p_s390x.s
@@ -0,0 +1,186 @@
+// Copyright 2017 The Go 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"
+
+// Constants
+DATA ·log1pxlim<> + 0(SB)/4, $0xfff00000
+GLOBL ·log1pxlim<> + 0(SB), RODATA, $4
+DATA ·log1pxzero<> + 0(SB)/8, $0.0
+GLOBL ·log1pxzero<> + 0(SB), RODATA, $8
+DATA ·log1pxminf<> + 0(SB)/8, $0xfff0000000000000
+GLOBL ·log1pxminf<> + 0(SB), RODATA, $8
+DATA ·log1pxnan<> + 0(SB)/8, $0x7ff8000000000000
+GLOBL ·log1pxnan<> + 0(SB), RODATA, $8
+DATA ·log1pyout<> + 0(SB)/8, $0x40fce621e71da000
+GLOBL ·log1pyout<> + 0(SB), RODATA, $8
+DATA ·log1pxout<> + 0(SB)/8, $0x40f1000000000000
+GLOBL ·log1pxout<> + 0(SB), RODATA, $8
+DATA ·log1pxl2<> + 0(SB)/8, $0xbfda7aecbeba4e46
+GLOBL ·log1pxl2<> + 0(SB), RODATA, $8
+DATA ·log1pxl1<> + 0(SB)/8, $0x3ffacde700000000
+GLOBL ·log1pxl1<> + 0(SB), RODATA, $8
+DATA ·log1pxa<> + 0(SB)/8, $5.5
+GLOBL ·log1pxa<> + 0(SB), RODATA, $8
+DATA ·log1pxmone<> + 0(SB)/8, $-1.0
+GLOBL ·log1pxmone<> + 0(SB), RODATA, $8
+
+// Minimax polynomial approximations
+DATA ·log1pc8<> + 0(SB)/8, $0.212881813645679599E-07
+GLOBL ·log1pc8<> + 0(SB), RODATA, $8
+DATA ·log1pc7<> + 0(SB)/8, $-.148682720127920854E-06
+GLOBL ·log1pc7<> + 0(SB), RODATA, $8
+DATA ·log1pc6<> + 0(SB)/8, $0.938370938292558173E-06
+GLOBL ·log1pc6<> + 0(SB), RODATA, $8
+DATA ·log1pc5<> + 0(SB)/8, $-.602107458843052029E-05
+GLOBL ·log1pc5<> + 0(SB), RODATA, $8
+DATA ·log1pc4<> + 0(SB)/8, $0.397389654305194527E-04
+GLOBL ·log1pc4<> + 0(SB), RODATA, $8
+DATA ·log1pc3<> + 0(SB)/8, $-.273205381970859341E-03
+GLOBL ·log1pc3<> + 0(SB), RODATA, $8
+DATA ·log1pc2<> + 0(SB)/8, $0.200350613573012186E-02
+GLOBL ·log1pc2<> + 0(SB), RODATA, $8
+DATA ·log1pc1<> + 0(SB)/8, $-.165289256198351540E-01
+GLOBL ·log1pc1<> + 0(SB), RODATA, $8
+DATA ·log1pc0<> + 0(SB)/8, $0.181818181818181826E+00
+GLOBL ·log1pc0<> + 0(SB), RODATA, $8
+
+
+// Table of log10 correction terms
+DATA ·log1ptab<> + 0(SB)/8, $0.585235384085551248E-01
+DATA ·log1ptab<> + 8(SB)/8, $0.412206153771168640E-01
+DATA ·log1ptab<> + 16(SB)/8, $0.273839003221648339E-01
+DATA ·log1ptab<> + 24(SB)/8, $0.166383778368856480E-01
+DATA ·log1ptab<> + 32(SB)/8, $0.866678223433169637E-02
+DATA ·log1ptab<> + 40(SB)/8, $0.319831684989627514E-02
+DATA ·log1ptab<> + 48(SB)/8, $-.000000000000000000E+00
+DATA ·log1ptab<> + 56(SB)/8, $-.113006378583725549E-02
+DATA ·log1ptab<> + 64(SB)/8, $-.367979419636602491E-03
+DATA ·log1ptab<> + 72(SB)/8, $0.213172484510484979E-02
+DATA ·log1ptab<> + 80(SB)/8, $0.623271047682013536E-02
+DATA ·log1ptab<> + 88(SB)/8, $0.118140812789696885E-01
+DATA ·log1ptab<> + 96(SB)/8, $0.187681358930914206E-01
+DATA ·log1ptab<> + 104(SB)/8, $0.269985148668178992E-01
+DATA ·log1ptab<> + 112(SB)/8, $0.364186619761331328E-01
+DATA ·log1ptab<> + 120(SB)/8, $0.469505379381388441E-01
+GLOBL ·log1ptab<> + 0(SB), RODATA, $128
+
+// Log1p returns the natural logarithm of 1 plus its argument x.
+// It is more accurate than Log(1 + x) when x is near zero.
+//
+// Special cases are:
+//      Log1p(+Inf) = +Inf
+//      Log1p(±0) = ±0
+//      Log1p(-1) = -Inf
+//      Log1p(x < -1) = NaN
+//      Log1p(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT	·log1pAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·log1pxmone<>+0(SB), R1
+	MOVD	·log1pxout<>+0(SB), R2
+	FMOVD	0(R1), F3
+	MOVD	$·log1pxa<>+0(SB), R1
+	MOVWZ	·log1pxlim<>+0(SB), R0
+	FMOVD	0(R1), F1
+	MOVD	$·log1pc8<>+0(SB), R1
+	FMOVD	0(R1), F5
+	MOVD	$·log1pc7<>+0(SB), R1
+	VLEG	$0, 0(R1), V20
+	MOVD	$·log1pc6<>+0(SB), R1
+	WFSDB	V0, V3, V4
+	VLEG	$0, 0(R1), V18
+	MOVD	$·log1pc5<>+0(SB), R1
+	VLEG	$0, 0(R1), V16
+	MOVD	R2, R5
+	WORD	$0xB3CD0034	//lgdr	%r3,%f4
+	WORD	$0xC0190006	//iilf	%r1,425983
+	BYTE	$0x7F
+	BYTE	$0xFF
+	SRAD	$32, R3, R3
+	SUBW	R3, R1
+	SRW	$16, R1, R1
+	BYTE	$0x18	//lr	%r4,%r1
+	BYTE	$0x41
+	WORD	$0xEC24000F	//risbgn	%r2,%r4,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xEC54101F	//risbgn	%r5,%r4,64-64+16,64-64+16+16-1,64-16-16
+	BYTE	$0x20
+	BYTE	$0x59
+	MOVW	R0, R6
+	MOVW	R3, R7
+	CMPBGT	R6, R7, L8
+	WFCEDBS	V4, V4, V6
+	MOVD	$·log1pxzero<>+0(SB), R1
+	FMOVD	0(R1), F2
+	BVS	LEXITTAGlog1p
+	WORD	$0xB3130044
+	WFCEDBS	V2, V4, V6
+	BEQ	L9
+	WFCHDBS	V4, V2, V2
+	BEQ	LEXITTAGlog1p
+	MOVD	$·log1pxnan<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+
+L8:
+	WORD	$0xB3C10022	//ldgr	%f2,%r2
+	FSUB	F4, F3
+	FMADD	F2, F4, F1
+	MOVD	$·log1pc4<>+0(SB), R2
+	WORD	$0xB3130041
+	FMOVD	0(R2), F7
+	FSUB	F3, F0
+	MOVD	$·log1pc3<>+0(SB), R2
+	FMOVD	0(R2), F3
+	MOVD	$·log1pc2<>+0(SB), R2
+	WFMDB	V1, V1, V6
+	FMADD	F7, F4, F3
+	WFMSDB	V0, V2, V1, V0
+	FMOVD	0(R2), F7
+	WFMADB	V4, V5, V20, V5
+	MOVD	$·log1pc1<>+0(SB), R2
+	FMOVD	0(R2), F2
+	FMADD	F7, F4, F2
+	WFMADB	V4, V18, V16, V4
+	FMADD	F3, F6, F2
+	WFMADB	V5, V6, V4, V5
+	FMUL	F6, F6
+	MOVD	$·log1pc0<>+0(SB), R2
+	WFMADB	V6, V5, V2, V6
+	FMOVD	0(R2), F4
+	WFMADB	V0, V6, V4, V6
+	WORD	$0xEC1139BC	//risbg	%r1,%r1,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	MOVD	$·log1ptab<>+0(SB), R2
+	MOVD	$·log1pxl1<>+0(SB), R3
+	WORD	$0x68112000	//ld	%f1,0(%r1,%r2)
+	FMOVD	0(R3), F2
+	WFMADB	V0, V6, V1, V0
+	MOVD	$·log1pyout<>+0(SB), R1
+	WORD	$0xB3C10065	//ldgr	%f6,%r5
+	FMOVD	0(R1), F4
+	WFMSDB	V2, V6, V4, V2
+	MOVD	$·log1pxl2<>+0(SB), R1
+	FMOVD	0(R1), F4
+	FMADD	F4, F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+
+L9:
+	MOVD	$·log1pxminf<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+
+
+LEXITTAGlog1p:
+	FMOVD	F0, ret+8(FP)
+	RET
+
diff --git a/src/math/log_amd64.s b/src/math/log_amd64.s
index bd2d063..3d76389 100644
--- a/src/math/log_amd64.s
+++ b/src/math/log_amd64.s
@@ -41,6 +41,7 @@ TEXT ·Log(SB),NOSPLIT,$0
 	SHRQ    $52, BX
 	ANDL    $0x7FF, BX
 	SUBL    $0x3FE, BX
+	XORPS   X1, X1 // break dependency for CVTSL2SD
 	CVTSL2SD BX, X1 // x1= k, x2= f1
 	// if f1 < math.Sqrt2/2 { k -= 1; f1 *= 2 }
 	MOVSD   $HSqrt2, X0 // x0= 0.7071, x1= k, x2= f1
diff --git a/src/math/log_s390x.s b/src/math/log_s390x.s
new file mode 100644
index 0000000..b0e193f
--- /dev/null
+++ b/src/math/log_s390x.s
@@ -0,0 +1,180 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial approximations
+DATA ·logrodataL21<> + 0(SB)/8, $-.499999999999999778E+00
+DATA ·logrodataL21<> + 8(SB)/8, $0.333333333333343751E+00
+DATA ·logrodataL21<> + 16(SB)/8, $-.250000000001606881E+00
+DATA ·logrodataL21<> + 24(SB)/8, $0.199999999971603032E+00
+DATA ·logrodataL21<> + 32(SB)/8, $-.166666663114122038E+00
+DATA ·logrodataL21<> + 40(SB)/8, $-.125002923782692399E+00
+DATA ·logrodataL21<> + 48(SB)/8, $0.111142014580396256E+00
+DATA ·logrodataL21<> + 56(SB)/8, $0.759438932618934220E-01
+DATA ·logrodataL21<> + 64(SB)/8, $0.142857144267212549E+00
+DATA ·logrodataL21<> + 72(SB)/8, $-.993038938793590759E-01
+DATA ·logrodataL21<> + 80(SB)/8, $-1.0
+GLOBL ·logrodataL21<> + 0(SB), RODATA, $88
+
+// Constants
+DATA ·logxminf<> + 0(SB)/8, $0xfff0000000000000
+GLOBL ·logxminf<> + 0(SB), RODATA, $8
+DATA ·logxnan<> + 0(SB)/8, $0x7ff8000000000000
+GLOBL ·logxnan<> + 0(SB), RODATA, $8
+DATA ·logx43f<> + 0(SB)/8, $0x43f0000000000000
+GLOBL ·logx43f<> + 0(SB), RODATA, $8
+DATA ·logxl2<> + 0(SB)/8, $0x3fda7aecbeba4e46
+GLOBL ·logxl2<> + 0(SB), RODATA, $8
+DATA ·logxl1<> + 0(SB)/8, $0x3ffacde700000000
+GLOBL ·logxl1<> + 0(SB), RODATA, $8
+
+/* Input transform scale and add constants */
+DATA ·logxm<> + 0(SB)/8, $0x3fc77604e63c84b1
+DATA ·logxm<> + 8(SB)/8, $0x40fb39456ab53250
+DATA ·logxm<> + 16(SB)/8, $0x3fc9ee358b945f3f
+DATA ·logxm<> + 24(SB)/8, $0x40fb39418bf3b137
+DATA ·logxm<> + 32(SB)/8, $0x3fccfb2e1304f4b6
+DATA ·logxm<> + 40(SB)/8, $0x40fb393d3eda3022
+DATA ·logxm<> + 48(SB)/8, $0x3fd0000000000000
+DATA ·logxm<> + 56(SB)/8, $0x40fb393969e70000
+DATA ·logxm<> + 64(SB)/8, $0x3fd11117aafbfe04
+DATA ·logxm<> + 72(SB)/8, $0x40fb3936eaefafcf
+DATA ·logxm<> + 80(SB)/8, $0x3fd2492af5e658b2
+DATA ·logxm<> + 88(SB)/8, $0x40fb39343ff01715
+DATA ·logxm<> + 96(SB)/8, $0x3fd3b50c622a43dd
+DATA ·logxm<> + 104(SB)/8, $0x40fb39315adae2f3
+DATA ·logxm<> + 112(SB)/8, $0x3fd56bbeea918777
+DATA ·logxm<> + 120(SB)/8, $0x40fb392e21698552
+GLOBL ·logxm<> + 0(SB), RODATA, $128
+
+// Log returns the natural logarithm of the argument.
+//
+// Special cases are:
+//      Log(+Inf) = +Inf
+//      Log(0) = -Inf
+//      Log(x < 0) = NaN
+//      Log(NaN) = NaN
+// The algorithm used is minimax polynomial approximation using a table of
+// polynomial coefficients determined with a Remez exchange algorithm.
+
+TEXT	·logAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	MOVD	$·logrodataL21<>+0(SB), R9
+	MOVH	$0x8006, R4
+	WORD	$0xB3CD0010	//lgdr	%r1,%f0
+	MOVD	$0x3FF0000000000000, R6
+	SRAD	$48, R1, R1
+	MOVD	$0x40F03E8000000000, R8
+	SUBW	R1, R4
+	WORD	$0xEC2420BB	//risbg	%r2,%r4,32,128+59,0
+	BYTE	$0x00
+	BYTE	$0x55
+	WORD	$0xEC62000F	//risbgn	%r6,%r2,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xEC82101F	//risbgn	%r8,%r2,64-64+16,64-64+16+16-1,64-16-16
+	BYTE	$0x20
+	BYTE	$0x59
+	MOVW	R1, R7
+	CMPBGT	R7, $22, L17
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	MOVD	$·logx43f<>+0(SB), R1
+	FMOVD	0(R1), F2
+	BLEU	L3
+	MOVH	$0x8005, R12
+	MOVH	$0x8405, R0
+	BR	L15
+L7:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLEU	L3
+L15:
+	FMUL	F2, F0
+	WORD	$0xB3CD0010	//lgdr	%r1,%f0
+	SRAD	$48, R1, R1
+	SUBW	R1, R0, R2
+	SUBW	R1, R12, R3
+	BYTE	$0x18	//lr	%r4,%r2
+	BYTE	$0x42
+	ANDW	$0xFFFFFFF0, R3
+	ANDW	$0xFFFFFFF0, R2
+	BYTE	$0x18	//lr	%r5,%r1
+	BYTE	$0x51
+	MOVW	R1, R7
+	CMPBLE	R7, $22, L7
+	WORD	$0xEC63000F	//risbgn	%r6,%r3,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WORD	$0xEC82101F	//risbgn	%r8,%r2,64-64+16,64-64+16+16-1,64-16-16
+	BYTE	$0x20
+	BYTE	$0x59
+L2:
+	MOVH	R5, R5
+	MOVH	$0x7FEF, R1
+	CMPW	R5, R1
+	BGT	L1
+	WORD	$0xB3C10026	//ldgr	%f2,%r6
+	FMUL	F2, F0
+	WORD	$0xEC4439BB	//risbg	%r4,%r4,57,128+59,3
+	BYTE	$0x03
+	BYTE	$0x55
+	FMOVD	80(R9), F2
+	MOVD	$·logxm<>+0(SB), R7
+	ADD	R7, R4
+	FMOVD	72(R9), F4
+	WORD	$0xED004000	//madb	%f2,%f0,0(%r4)
+	BYTE	$0x20
+	BYTE	$0x1E
+	FMOVD	64(R9), F1
+	FMOVD	F2, F0
+	FMOVD	56(R9), F2
+	WFMADB	V0, V2, V4, V2
+	WFMDB	V0, V0, V6
+	FMOVD	48(R9), F4
+	WFMADB	V0, V2, V4, V2
+	FMOVD	40(R9), F4
+	WFMADB	V2, V6, V1, V2
+	FMOVD	32(R9), F1
+	WFMADB	V6, V4, V1, V4
+	FMOVD	24(R9), F1
+	WFMADB	V6, V2, V1, V2
+	FMOVD	16(R9), F1
+	WFMADB	V6, V4, V1, V4
+	MOVD	$·logxl1<>+0(SB), R1
+	FMOVD	8(R9), F1
+	WFMADB	V6, V2, V1, V2
+	FMOVD	0(R9), F1
+	WFMADB	V6, V4, V1, V4
+	FMOVD	8(R4), F1
+	WFMADB	V0, V2, V4, V2
+	WORD	$0xB3C10048	//ldgr	%f4,%r8
+	WFMADB	V6, V2, V0, V2
+	WORD	$0xED401000	//msdb	%f1,%f4,0(%r1)
+	BYTE	$0x10
+	BYTE	$0x1F
+	MOVD	·logxl2<>+0(SB), R1
+	WORD	$0xB3130001	//lcdbr	%f0,%f1
+	WORD	$0xB3C10041	//ldgr	%f4,%r1
+	WFMADB	V0, V4, V2, V0
+L1:
+	FMOVD	F0, ret+8(FP)
+	RET
+L3:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BEQ	L20
+	BGE	L1
+	BVS	L1
+
+	MOVD	$·logxnan<>+0(SB), R1
+	FMOVD	0(R1), F0
+	BR	L1
+L20:
+	MOVD	$·logxminf<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L17:
+	BYTE	$0x18	//lr	%r5,%r1
+	BYTE	$0x51
+	BR	L2
diff --git a/src/math/pow.go b/src/math/pow.go
index 77af256..b3bfadf 100644
--- a/src/math/pow.go
+++ b/src/math/pow.go
@@ -35,7 +35,9 @@ func isOddInt(x float64) bool {
 //	Pow(+Inf, y) = +0 for y < 0
 //	Pow(-Inf, y) = Pow(-0, -y)
 //	Pow(x, y) = NaN for finite x < 0 and finite non-integer y
-func Pow(x, y float64) float64 {
+func Pow(x, y float64) float64
+
+func pow(x, y float64) float64 {
 	switch {
 	case y == 0 || x == 1:
 		return 1
diff --git a/src/math/pow10.go b/src/math/pow10.go
index f5ad28b..1234e20 100644
--- a/src/math/pow10.go
+++ b/src/math/pow10.go
@@ -4,37 +4,43 @@
 
 package math
 
-// This table might overflow 127-bit exponent representations.
-// In that case, truncate it after 1.0e38.
-var pow10tab [70]float64
+// pow10tab stores the pre-computed values 10**i for i < 32.
+var pow10tab = [...]float64{
+	1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+	1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
+	1e30, 1e31,
+}
+
+// pow10postab32 stores the pre-computed value for 10**(i*32) at index i.
+var pow10postab32 = [...]float64{
+	1e00, 1e32, 1e64, 1e96, 1e128, 1e160, 1e192, 1e224, 1e256, 1e288,
+}
+
+// pow10negtab32 stores the pre-computed value for 10**(-i*32) at index i.
+var pow10negtab32 = [...]float64{
+	1e-00, 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, 1e-288, 1e-320,
+}
 
-// Pow10 returns 10**e, the base-10 exponential of e.
+// Pow10 returns 10**n, the base-10 exponential of n.
 //
 // Special cases are:
-//	Pow10(e) = +Inf for e > 309
-//	Pow10(e) = 0 for e < -324
-func Pow10(e int) float64 {
-	if e <= -325 {
-		return 0
-	} else if e > 309 {
-		return Inf(1)
+//	Pow10(n) =    0 for n < -323
+//	Pow10(n) = +Inf for n > 308
+func Pow10(n int) float64 {
+	if 0 <= n && n <= 308 {
+		return pow10postab32[uint(n)/32] * pow10tab[uint(n)%32]
 	}
 
-	if e < 0 {
-		return 1 / Pow10(-e)
-	}
-	if e < len(pow10tab) {
-		return pow10tab[e]
+	if -323 <= n && n <= 0 {
+		return pow10negtab32[uint(-n)/32] / pow10tab[uint(-n)%32]
 	}
-	m := e / 2
-	return Pow10(m) * Pow10(e-m)
-}
 
-func init() {
-	pow10tab[0] = 1.0e0
-	pow10tab[1] = 1.0e1
-	for i := 2; i < len(pow10tab); i++ {
-		m := i / 2
-		pow10tab[i] = pow10tab[m] * pow10tab[i-m]
+	// n < -323 || 308 < n
+	if n > 0 {
+		return Inf(1)
 	}
+
+	// n < -323
+	return 0
 }
diff --git a/src/math/pow_s390x.s b/src/math/pow_s390x.s
new file mode 100644
index 0000000..fa8decb
--- /dev/null
+++ b/src/math/pow_s390x.s
@@ -0,0 +1,666 @@
+// Copyright 2017 The Go 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 PosInf   0x7FF0000000000000
+#define NaN      0x7FF8000000000001
+#define NegInf   0xFFF0000000000000
+#define PosOne   0x3FF0000000000000
+#define NegOne   0xBFF0000000000000
+#define NegZero  0x8000000000000000
+
+// Minimax polynomial approximation
+DATA ·powrodataL51<> + 0(SB)/8, $-1.0
+DATA ·powrodataL51<> + 8(SB)/8, $1.0
+DATA ·powrodataL51<> + 16(SB)/8, $0.24022650695910110361E+00
+DATA ·powrodataL51<> + 24(SB)/8, $0.69314718055994686185E+00
+DATA ·powrodataL51<> + 32(SB)/8, $0.96181291057109484809E-02
+DATA ·powrodataL51<> + 40(SB)/8, $0.15403814778342868389E-03
+DATA ·powrodataL51<> + 48(SB)/8, $0.55504108652095235601E-01
+DATA ·powrodataL51<> + 56(SB)/8, $0.13333818813168698658E-02
+DATA ·powrodataL51<> + 64(SB)/8, $0.68205322933914439200E-12
+DATA ·powrodataL51<> + 72(SB)/8, $-.18466496523378731640E-01
+DATA ·powrodataL51<> + 80(SB)/8, $0.19697596291603973706E-02
+DATA ·powrodataL51<> + 88(SB)/8, $0.23083120654155209200E+00
+DATA ·powrodataL51<> + 96(SB)/8, $0.55324356012093416771E-06
+DATA ·powrodataL51<> + 104(SB)/8, $-.40340677224649339048E-05
+DATA ·powrodataL51<> + 112(SB)/8, $0.30255507904062541562E-04
+DATA ·powrodataL51<> + 120(SB)/8, $-.77453979912413008787E-07
+DATA ·powrodataL51<> + 128(SB)/8, $-.23637115549923464737E-03
+DATA ·powrodataL51<> + 136(SB)/8, $0.11016119077267717198E-07
+DATA ·powrodataL51<> + 144(SB)/8, $0.22608272174486123035E-09
+DATA ·powrodataL51<> + 152(SB)/8, $-.15895808101370190382E-08
+DATA ·powrodataL51<> + 160(SB)/8, $0x4540190000000000
+GLOBL ·powrodataL51<> + 0(SB), RODATA, $168
+
+// Constants
+DATA ·pow_x001a<> + 0(SB)/8, $0x1a000000000000
+GLOBL ·pow_x001a<> + 0(SB), RODATA, $8
+DATA ·pow_xinf<> + 0(SB)/8, $0x7ff0000000000000      //+Inf
+GLOBL ·pow_xinf<> + 0(SB), RODATA, $8
+DATA ·pow_xnan<> + 0(SB)/8, $0x7ff8000000000000      //NaN
+GLOBL ·pow_xnan<> + 0(SB), RODATA, $8
+DATA ·pow_x434<> + 0(SB)/8, $0x4340000000000000
+GLOBL ·pow_x434<> + 0(SB), RODATA, $8
+DATA ·pow_x433<> + 0(SB)/8, $0x4330000000000000
+GLOBL ·pow_x433<> + 0(SB), RODATA, $8
+DATA ·pow_x43f<> + 0(SB)/8, $0x43f0000000000000
+GLOBL ·pow_x43f<> + 0(SB), RODATA, $8
+DATA ·pow_xadd<> + 0(SB)/8, $0xc2f0000100003fef
+GLOBL ·pow_xadd<> + 0(SB), RODATA, $8
+DATA ·pow_xa<> + 0(SB)/8, $0x4019000000000000
+GLOBL ·pow_xa<> + 0(SB), RODATA, $8
+
+// Scale correction tables
+DATA powiadd<> + 0(SB)/8, $0xf000000000000000
+DATA powiadd<> + 8(SB)/8, $0x1000000000000000
+GLOBL powiadd<> + 0(SB), RODATA, $16
+DATA powxscale<> + 0(SB)/8, $0x4ff0000000000000
+DATA powxscale<> + 8(SB)/8, $0x2ff0000000000000
+GLOBL powxscale<> + 0(SB), RODATA, $16
+
+// Fractional powers of 2 table
+DATA ·powtexp<> + 0(SB)/8, $0.442737824274138381E-01
+DATA ·powtexp<> + 8(SB)/8, $0.263602189790660309E-01
+DATA ·powtexp<> + 16(SB)/8, $0.122565642281703586E-01
+DATA ·powtexp<> + 24(SB)/8, $0.143757052860721398E-02
+DATA ·powtexp<> + 32(SB)/8, $-.651375034121276075E-02
+DATA ·powtexp<> + 40(SB)/8, $-.119317678849450159E-01
+DATA ·powtexp<> + 48(SB)/8, $-.150868749549871069E-01
+DATA ·powtexp<> + 56(SB)/8, $-.161992609578469234E-01
+DATA ·powtexp<> + 64(SB)/8, $-.154492360403337917E-01
+DATA ·powtexp<> + 72(SB)/8, $-.129850717389178721E-01
+DATA ·powtexp<> + 80(SB)/8, $-.892902649276657891E-02
+DATA ·powtexp<> + 88(SB)/8, $-.338202636596794887E-02
+DATA ·powtexp<> + 96(SB)/8, $0.357266307045684762E-02
+DATA ·powtexp<> + 104(SB)/8, $0.118665304327406698E-01
+DATA ·powtexp<> + 112(SB)/8, $0.214434994118118914E-01
+DATA ·powtexp<> + 120(SB)/8, $0.322580645161290314E-01
+GLOBL ·powtexp<> + 0(SB), RODATA, $128
+
+// Log multiplier tables
+DATA ·powtl<> + 0(SB)/8, $0xbdf9723a80db6a05
+DATA ·powtl<> + 8(SB)/8, $0x3e0cfe4a0babe862
+DATA ·powtl<> + 16(SB)/8, $0xbe163b42dd33dada
+DATA ·powtl<> + 24(SB)/8, $0xbe0cdf9de2a8429c
+DATA ·powtl<> + 32(SB)/8, $0xbde9723a80db6a05
+DATA ·powtl<> + 40(SB)/8, $0xbdb37fcae081745e
+DATA ·powtl<> + 48(SB)/8, $0xbdd8b2f901ac662c
+DATA ·powtl<> + 56(SB)/8, $0xbde867dc68c36cc9
+DATA ·powtl<> + 64(SB)/8, $0xbdd23e36b47256b7
+DATA ·powtl<> + 72(SB)/8, $0xbde4c9b89fcc7933
+DATA ·powtl<> + 80(SB)/8, $0xbdd16905cad7cf66
+DATA ·powtl<> + 88(SB)/8, $0x3ddb417414aa5529
+DATA ·powtl<> + 96(SB)/8, $0xbdce046f2889983c
+DATA ·powtl<> + 104(SB)/8, $0x3dc2c3865d072897
+DATA ·powtl<> + 112(SB)/8, $0x8000000000000000
+DATA ·powtl<> + 120(SB)/8, $0x3dc1ca48817f8afe
+DATA ·powtl<> + 128(SB)/8, $0xbdd703518a88bfb7
+DATA ·powtl<> + 136(SB)/8, $0x3dc64afcc46942ce
+DATA ·powtl<> + 144(SB)/8, $0xbd9d79191389891a
+DATA ·powtl<> + 152(SB)/8, $0x3ddd563044da4fa0
+DATA ·powtl<> + 160(SB)/8, $0x3e0f42b5e5f8f4b6
+DATA ·powtl<> + 168(SB)/8, $0x3e0dfa2c2cbf6ead
+DATA ·powtl<> + 176(SB)/8, $0x3e14e25e91661293
+DATA ·powtl<> + 184(SB)/8, $0x3e0aac461509e20c
+GLOBL ·powtl<> + 0(SB), RODATA, $192
+
+DATA ·powtm<> + 0(SB)/8, $0x3da69e13
+DATA ·powtm<> + 8(SB)/8, $0x100003d66fcb6
+DATA ·powtm<> + 16(SB)/8, $0x200003d1538df
+DATA ·powtm<> + 24(SB)/8, $0x300003cab729e
+DATA ·powtm<> + 32(SB)/8, $0x400003c1a784c
+DATA ·powtm<> + 40(SB)/8, $0x500003ac9b074
+DATA ·powtm<> + 48(SB)/8, $0x60000bb498d22
+DATA ·powtm<> + 56(SB)/8, $0x68000bb8b29a2
+DATA ·powtm<> + 64(SB)/8, $0x70000bb9a32d4
+DATA ·powtm<> + 72(SB)/8, $0x74000bb9946bb
+DATA ·powtm<> + 80(SB)/8, $0x78000bb92e34b
+DATA ·powtm<> + 88(SB)/8, $0x80000bb6c57dc
+DATA ·powtm<> + 96(SB)/8, $0x84000bb4020f7
+DATA ·powtm<> + 104(SB)/8, $0x8c000ba93832d
+DATA ·powtm<> + 112(SB)/8, $0x9000080000000
+DATA ·powtm<> + 120(SB)/8, $0x940003aa66c4c
+DATA ·powtm<> + 128(SB)/8, $0x980003b2fb12a
+DATA ·powtm<> + 136(SB)/8, $0xa00003bc1def6
+DATA ·powtm<> + 144(SB)/8, $0xa80003c1eb0eb
+DATA ·powtm<> + 152(SB)/8, $0xb00003c64dcec
+DATA ·powtm<> + 160(SB)/8, $0xc00003cc49e4e
+DATA ·powtm<> + 168(SB)/8, $0xd00003d12f1de
+DATA ·powtm<> + 176(SB)/8, $0xe00003d4a9c6f
+DATA ·powtm<> + 184(SB)/8, $0xf00003d846c66
+GLOBL ·powtm<> + 0(SB), RODATA, $192
+
+// Table of indeces into multiplier tables
+// Adjusted from asm to remove offset and convert
+DATA ·powtabi<> + 0(SB)/8, $0x1010101
+DATA ·powtabi<> + 8(SB)/8, $0x101020202020203
+DATA ·powtabi<> + 16(SB)/8, $0x303030404040405
+DATA ·powtabi<> + 24(SB)/8, $0x505050606060708
+DATA ·powtabi<> + 32(SB)/8, $0x90a0b0c0d0e0f10
+DATA ·powtabi<> + 40(SB)/8, $0x1011111212121313
+DATA ·powtabi<> + 48(SB)/8, $0x1314141414151515
+DATA ·powtabi<> + 56(SB)/8, $0x1516161617171717
+GLOBL ·powtabi<> + 0(SB), RODATA, $64
+
+// Pow returns x**y, the base-x exponential of y.
+//
+// Special cases are (in order):
+//      Pow(x, ±0) = 1 for any x
+//      Pow(1, y) = 1 for any y
+//      Pow(x, 1) = x for any x
+//      Pow(NaN, y) = NaN
+//      Pow(x, NaN) = NaN
+//      Pow(±0, y) = ±Inf for y an odd integer < 0
+//      Pow(±0, -Inf) = +Inf
+//      Pow(±0, +Inf) = +0
+//      Pow(±0, y) = +Inf for finite y < 0 and not an odd integer
+//      Pow(±0, y) = ±0 for y an odd integer > 0
+//      Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+//      Pow(-1, ±Inf) = 1
+//      Pow(x, +Inf) = +Inf for |x| > 1
+//      Pow(x, -Inf) = +0 for |x| > 1
+//      Pow(x, +Inf) = +0 for |x| < 1
+//      Pow(x, -Inf) = +Inf for |x| < 1
+//      Pow(+Inf, y) = +Inf for y > 0
+//      Pow(+Inf, y) = +0 for y < 0
+//      Pow(-Inf, y) = Pow(-0, -y)
+//      Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+
+TEXT	·powAsm(SB), NOSPLIT, $0-24
+	// special case
+	MOVD	x+0(FP), R1
+	MOVD	y+8(FP), R2
+
+	// special case Pow(1, y) = 1 for any y
+	MOVD	$PosOne, R3
+	CMPUBEQ	R1, R3, xIsOne
+
+	// special case Pow(x, 1) = x for any x
+	MOVD	$PosOne, R4
+	CMPUBEQ	R2, R4, yIsOne
+
+	// special case Pow(x, NaN) = NaN for any x
+	MOVD	$~(1<<63), R5
+	AND	R2, R5    // y = |y|
+	MOVD	$PosInf, R4
+	CMPUBLT R4, R5, yIsNan
+
+	MOVD	$NegInf, R3
+	CMPUBEQ	R1, R3, xIsNegInf
+
+	MOVD	$NegOne, R3
+	CMPUBEQ	R1, R3, xIsNegOne
+
+	MOVD	$PosInf, R3
+	CMPUBEQ	R1, R3, xIsPosInf
+
+	MOVD	$NegZero, R3
+	CMPUBEQ	R1, R3, xIsNegZero
+
+	MOVD	$PosInf, R4
+	CMPUBEQ	R2, R4, yIsPosInf
+
+	MOVD	$0x0, R3
+	CMPUBEQ	R1, R3, xIsPosZero
+	CMPBLT	R1, R3, xLtZero
+	BR	Normal
+xIsPosInf:
+	// special case Pow(+Inf, y) = +Inf for y > 0
+	MOVD	$0x0, R4
+	CMPBGT	R2, R4, posInfGeZero
+	BR	Normal
+xIsNegInf:
+	//Pow(-Inf, y) = Pow(-0, -y)
+	FMOVD y+8(FP), F2
+	FNEG F2, F2			// y = -y
+	BR negZeroNegY		// call Pow(-0, -y)
+xIsNegOne:
+	// special case Pow(-1, ±Inf) = 1
+	MOVD	$PosInf, R4
+	CMPUBEQ	R2, R4, negOnePosInf
+	MOVD	$NegInf, R4
+	CMPUBEQ	R2, R4, negOneNegInf
+	BR	Normal
+xIsPosZero:
+	// special case Pow(+0, -Inf) = +Inf
+	MOVD	$NegInf, R4
+	CMPUBEQ	R2, R4, zeroNegInf
+
+	// special case Pow(+0, y < 0) = +Inf
+	FMOVD	y+8(FP), F2
+	FMOVD	$(0.0), F4
+	FCMPU	F2, F4
+	BLT	posZeroLtZero				//y < 0.0
+	BR	Normal
+xIsNegZero:
+	// special case Pow(-0, -Inf) = +Inf
+	MOVD	$NegInf, R4
+	CMPUBEQ	R2, R4, zeroNegInf
+	FMOVD	y+8(FP), F2
+negZeroNegY:
+	// special case Pow(x, ±0) = 1 for any x
+	FMOVD	$(0.0), F4
+	FCMPU	F4, F2
+	BLT	negZeroGtZero		// y > 0.0
+	BEQ yIsZero				// y = 0.0
+
+	FMOVD $(-0.0), F4
+	FCMPU F4, F2
+	BLT negZeroGtZero				// y > -0.0
+	BEQ yIsZero				// y = -0.0
+
+	// special case Pow(-0, y) = -Inf for y an odd integer < 0
+	// special case Pow(-0, y) = +Inf for finite y < 0 and not an odd integer
+	FIDBR	$5, F2, F4		//F2 translate to integer F4
+	FCMPU	F2, F4
+	BNE	zeroNotOdd			// y is not an (odd) integer and y < 0
+	FMOVD	$(2.0), F4
+	FDIV	F4, F2			// F2 = F2 / 2.0
+	FIDBR	$5, F2, F4		//F2 translate to integer F4
+	FCMPU	F2, F4
+	BNE	negZeroOddInt		// y is an odd integer and y < 0
+	BR	zeroNotOdd			// y is not an (odd) integer and y < 0
+
+negZeroGtZero:
+	// special case Pow(-0, y) = -0 for y an odd integer > 0
+	// special case Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+	FIDBR	$5, F2, F4      //F2 translate to integer F4
+	FCMPU	F2, F4
+	BNE	zeroNotOddGtZero    // y is not an (odd) integer and y > 0
+	FMOVD	$(2.0), F4
+	FDIV	F4, F2          // F2 = F2 / 2.0
+	FIDBR	$5, F2, F4      //F2 translate to integer F4
+	FCMPU	F2, F4
+	BNE	negZeroOddIntGtZero       // y is an odd integer and y > 0
+	BR	zeroNotOddGtZero          // y is not an (odd) integer
+
+xLtZero:
+	// special case Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+	FMOVD	y+8(FP), F2
+	FIDBR	$5, F2, F4
+	FCMPU	F2, F4
+	BNE	ltZeroInt
+	BR	Normal
+yIsPosInf:
+	// special case Pow(x, +Inf) = +Inf for |x| > 1
+	FMOVD	x+0(FP), F1
+	FMOVD	$(1.0), F3
+	FCMPU	F1, F3
+	BGT	gtOnePosInf
+	FMOVD	$(-1.0), F3
+	FCMPU	F1, F3
+	BLT	ltNegOnePosInf
+Normal:
+	FMOVD	x+0(FP), F0
+	FMOVD	y+8(FP), F2
+	MOVD	$·powrodataL51<>+0(SB), R9
+	WORD	$0xB3CD0030	//lgdr	%r3,%f0
+	WORD	$0xC0298009	//iilf	%r2,2148095317
+	BYTE	$0x55
+	BYTE	$0x55
+	WORD	$0xEC1320BF	//risbgn	%r1,%r3,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	SUBW	R1, R2
+	WORD	$0xEC323ABF	//risbgn	%r3,%r2,64-6,128+63,64+44+6
+	BYTE	$0x72
+	BYTE	$0x59
+	BYTE	$0x18	//lr	%r5,%r1
+	BYTE	$0x51
+	MOVD	$·powtabi<>+0(SB), R12
+	WORD	$0xE303C000	//llgc	%r0,0(%r3,%r12)
+	BYTE	$0x00
+	BYTE	$0x90
+	SUBW	$0x1A0000, R5
+	SLD	$3, R0, R3
+	MOVD	$·powtm<>+0(SB), R4
+	MOVH	$0x0, R8
+	ANDW	$0x7FF00000, R2
+	ORW	R5, R1
+	WORD	$0x5A234000	//a	%r2,0(%r3,%r4)
+	MOVD	$0x3FF0000000000000, R5
+	WORD	$0xEC3228BF	//risbg	%r3,%r2,64-24,128+63,64+32+24
+	BYTE	$0x78
+	BYTE	$0x55
+	WORD	$0xEC82001F	//risbgn	%r8,%r2,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	ORW	$0x45000000, R3
+	MOVW	R1, R6
+	CMPBLT	R6, $0, L42
+	FMOVD	F0, F4
+L2:
+	VLVGF	$0, R3, V1
+	MOVD	$·pow_xa<>+0(SB), R2
+	WORD	$0xED3090A0	//lde	%f3,.L52-.L51(%r9)
+	BYTE	$0x00
+	BYTE	$0x24
+	FMOVD	0(R2), F6
+	FSUBS	F1, F3
+	WORD	$0xB3C10018	//ldgr	%f1,%r8
+	WFMSDB	V4, V1, V6, V4
+	FMOVD	152(R9), F6
+	WFMDB	V4, V4, V7
+	FMOVD	144(R9), F1
+	FMOVD	136(R9), F5
+	WFMADB	V4, V1, V6, V1
+	VLEG	$0, 128(R9), V16
+	FMOVD	120(R9), F6
+	WFMADB	V4, V5, V6, V5
+	FMOVD	112(R9), F6
+	WFMADB	V1, V7, V5, V1
+	WFMADB	V4, V6, V16, V16
+	SLD	$3, R0, R2
+	FMOVD	104(R9), F5
+	WORD	$0xED824004	//ldeb	%f8,4(%r2,%r4)
+	BYTE	$0x00
+	BYTE	$0x04
+	LDEBR	F3, F3
+	FMOVD	96(R9), F6
+	WFMADB	V4, V6, V5, V6
+	FADD	F8, F3
+	WFMADB	V7, V6, V16, V6
+	FMUL	F7, F7
+	FMOVD	88(R9), F5
+	FMADD	F7, F1, F6
+	WFMADB	V4, V5, V3, V16
+	FMOVD	80(R9), F1
+	WFSDB	V16, V3, V3
+	MOVD	$·powtl<>+0(SB), R3
+	WFMADB	V4, V6, V1, V6
+	FMADD	F5, F4, F3
+	FMOVD	72(R9), F1
+	WFMADB	V4, V6, V1, V6
+	WORD	$0xED323000	//adb	%f3,0(%r2,%r3)
+	BYTE	$0x00
+	BYTE	$0x1A
+	FMOVD	64(R9), F1
+	WFMADB	V4, V6, V1, V6
+	MOVD	$·pow_xadd<>+0(SB), R2
+	WFMADB	V4, V6, V3, V4
+	FMOVD	0(R2), F5
+	WFADB	V4, V16, V3
+	VLEG	$0, 56(R9), V20
+	WFMSDB	V2, V3, V5, V3
+	VLEG	$0, 48(R9), V18
+	WFADB	V3, V5, V6
+	WORD	$0xB3CD0023	//lgdr	%r2,%f3
+	WFMSDB	V2, V16, V6, V16
+	FMOVD	40(R9), F1
+	WFMADB	V2, V4, V16, V4
+	FMOVD	32(R9), F7
+	WFMDB	V4, V4, V3
+	WFMADB	V4, V1, V20, V1
+	WFMADB	V4, V7, V18, V7
+	VLEG	$0, 24(R9), V16
+	WFMADB	V1, V3, V7, V1
+	FMOVD	16(R9), F5
+	WFMADB	V4, V5, V16, V5
+	WORD	$0xEC4239BC	//risbg	%r4,%r2,57,128+60,3
+	BYTE	$0x03
+	BYTE	$0x55
+	WFMADB	V3, V1, V5, V1
+	MOVD	$·powtexp<>+0(SB), R3
+	WORD	$0x68343000	//ld	%f3,0(%r4,%r3)
+	FMADD	F3, F4, F4
+	WORD	$0xEC52000F	//risbgn	%r5,%r2,64-64+0,64-64+0+16-1,64-0-16
+	BYTE	$0x30
+	BYTE	$0x59
+	WFMADB	V4, V1, V3, V4
+	WORD	$0xB3CD0026	//lgdr	%r2,%f6
+	WORD	$0xB3C10015	//ldgr	%f1,%r5
+	SRAD	$48, R2, R2
+	FMADD	F1, F4, F1
+	RLL	$16, R2, R2
+	ANDW	$0x7FFF0000, R2
+	WORD	$0xC22B3F71	//alfi	%r2,1064370176
+	BYTE	$0x00
+	BYTE	$0x00
+	ORW	R2, R1, R3
+	MOVW	R3, R6
+	CMPBLT	R6, $0, L43
+L1:
+	FMOVD	F1, ret+16(FP)
+	RET
+L43:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L44
+	FMOVD	F0, F3
+L7:
+	MOVD	$·pow_xinf<>+0(SB), R3
+	FMOVD	0(R3), F5
+	WFCEDBS	V3, V5, V7
+	BVS	L8
+	WFMDB	V3, V2, V6
+L8:
+	WFCEDBS	V2, V2, V3
+	BVS	L9
+	WORD	$0xB3120022	//ltdbr	%f2,%f2
+	BEQ	L26
+	MOVW	R1, R6
+	CMPBLT	R6, $0, L45
+L11:
+	WORD	$0xC0190003	//iilf	%r1,262143
+	BYTE	$0xFF
+	BYTE	$0xFF
+	MOVW	R2, R7
+	MOVW	R1, R6
+	CMPBLE	R7, R6, L34
+	WORD	$0xEC1520BF	//risbgn	%r1,%r5,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	WORD	$0xB3CD0026	//lgdr	%r2,%f6
+	MOVD	$powiadd<>+0(SB), R3
+	WORD	$0xEC223CBC	//risbg	%r2,%r2,60,128+60,64-60
+	BYTE	$0x04
+	BYTE	$0x55
+	WORD	$0x5A123000	//a	%r1,0(%r2,%r3)
+	WORD	$0xEC51001F	//risbgn	%r5,%r1,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	WORD	$0xB3C10015	//ldgr	%f1,%r5
+	FMADD	F1, F4, F1
+	MOVD	$powxscale<>+0(SB), R1
+	WORD	$0xED121000	//mdb	%f1,0(%r2,%r1)
+	BYTE	$0x00
+	BYTE	$0x1C
+	BR	L1
+L42:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L46
+	FMOVD	F0, F4
+L3:
+	MOVD	$·pow_x001a<>+0(SB), R2
+	WORD	$0xED402000	//cdb	%f4,0(%r2)
+	BYTE	$0x00
+	BYTE	$0x19
+	BGE	L2
+	BVS	L2
+	MOVD	$·pow_x43f<>+0(SB), R2
+	WORD	$0xED402000	//mdb	%f4,0(%r2)
+	BYTE	$0x00
+	BYTE	$0x1C
+	WORD	$0xC0298009	//iilf	%r2,2148095317
+	BYTE	$0x55
+	BYTE	$0x55
+	WORD	$0xB3CD0034	//lgdr	%r3,%f4
+	WORD	$0xEC3320BF	//risbgn	%r3,%r3,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	SUBW	R3, R2, R3
+	WORD	$0xEC2321AB	//risbg	%r2,%r3,33,128+43,0
+	BYTE	$0x00
+	BYTE	$0x55
+	WORD	$0xEC333ABF	//risbgn	%r3,%r3,64-6,128+63,64+44+6
+	BYTE	$0x72
+	BYTE	$0x59
+	WORD	$0xE303C000	//llgc	%r0,0(%r3,%r12)
+	BYTE	$0x00
+	BYTE	$0x90
+	SLD	$3, R0, R3
+	WORD	$0x5A234000	//a	%r2,0(%r3,%r4)
+	BYTE	$0x18	//lr	%r3,%r2
+	BYTE	$0x32
+	WORD	$0xEC83001F	//risbgn	%r8,%r3,64-64+0,64-64+0+32-1,64-0-32
+	BYTE	$0x20
+	BYTE	$0x59
+	ADDW	$0x4000000, R3
+	BLEU	L5
+	WORD	$0xEC3328BF	//risbg	%r3,%r3,64-24,128+63,64+32+24
+	BYTE	$0x78
+	BYTE	$0x55
+	ORW	$0x45000000, R3
+	BR	L2
+L9:
+	WFCEDBS	V0, V0, V4
+	BVS	L35
+	FMOVD	F2, F1
+	BR	L1
+L46:
+	WORD	$0xB3130040	//lcdbr	%f4,%f0
+	BR	L3
+L44:
+	WORD	$0xB3130030	//lcdbr	%f3,%f0
+	BR	L7
+L35:
+	FMOVD	F0, F1
+	BR	L1
+L26:
+	FMOVD	8(R9), F1
+	BR	L1
+L34:
+	FMOVD	8(R9), F4
+L19:
+	WORD	$0xB3120066	//ltdbr	%f6,%f6
+	BLEU	L47
+L18:
+	WFMDB	V4, V5, V1
+	BR	L1
+L5:
+	WORD	$0xEC3321B2	//risbg	%r3,%r3,33,128+50,64-1
+	BYTE	$0x3F
+	BYTE	$0x55
+	WORD	$0xC23B4000	//alfi	%r3,1073741824
+	BYTE	$0x00
+	BYTE	$0x00
+	RLL	$24, R3, R3
+	ORW	$0x45000000, R3
+	BR	L2
+L45:
+	WFCEDBS	V0, V0, V4
+	BVS	L35
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLEU	L48
+	FMOVD	8(R9), F4
+L12:
+	MOVW	R2, R6
+	CMPBLT	R6, $0, L19
+	FMUL	F4, F1
+	BR	L1
+L47:
+	BLT	L40
+	WFCEDBS	V0, V0, V2
+	BVS	L49
+L16:
+	MOVD	·pow_xnan<>+0(SB), R1
+	WORD	$0xB3C10001	//ldgr	%f0,%r1
+	WFMDB	V4, V0, V1
+	BR	L1
+L48:
+	WORD	$0xB3CD0030	//lgdr	%r3,%f0
+	WORD	$0xEC1320BF	//risbgn	%r1,%r3,64-32,128+63,64+0+32
+	BYTE	$0x60
+	BYTE	$0x59
+	MOVW	R1, R6
+	CMPBEQ	R6, $0, L29
+	WORD	$0xB3120022	//ltdbr	%f2,%f2
+	BLTU	L50
+	FMOVD	F2, F4
+L14:
+	MOVD	$·pow_x433<>+0(SB), R1
+	FMOVD	0(R1), F7
+	WFCHDBS	V4, V7, V3
+	BEQ	L15
+	WFADB	V7, V4, V3
+	FSUB	F7, F3
+	WFCEDBS	V4, V3, V3
+	BEQ	L15
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	FMOVD	8(R9), F4
+	BNE	L16
+L13:
+	WORD	$0xB3120022	//ltdbr	%f2,%f2
+	BLT	L18
+L40:
+	FMOVD	$0, F0
+	WFMDB	V4, V0, V1
+	BR	L1
+L49:
+	WFMDB	V0, V4, V1
+	BR	L1
+L29:
+	FMOVD	8(R9), F4
+	BR	L13
+L15:
+	MOVD	$·pow_x434<>+0(SB), R1
+	FMOVD	0(R1), F7
+	WFCHDBS	V4, V7, V3
+	BEQ	L32
+	WFADB	V7, V4, V3
+	FSUB	F7, F3
+	WFCEDBS	V4, V3, V4
+	BEQ	L32
+	FMOVD	0(R9), F4
+L17:
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BNE	L12
+	BR	L13
+L32:
+	FMOVD	8(R9), F4
+	BR	L17
+L50:
+	WORD	$0xB3130042	//lcdbr	%f4,%f2
+	BR	L14
+xIsOne:			// Pow(1, y) = 1 for any y
+yIsOne:			// Pow(x, 1) = x for any x
+posInfGeZero:	// Pow(+Inf, y) = +Inf for y > 0
+	MOVD	R1, ret+16(FP)
+	RET
+yIsNan:			//  Pow(NaN, y) = NaN
+ltZeroInt:		// Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+	MOVD	$NaN, R2
+	MOVD	R2, ret+16(FP)
+	RET
+negOnePosInf:	// Pow(-1, ±Inf) = 1
+negOneNegInf:
+	MOVD	$PosOne, R3
+	MOVD	R3, ret+16(FP)
+	RET
+negZeroOddInt:
+	MOVD	$NegInf, R3
+	MOVD	R3, ret+16(FP)
+	RET
+zeroNotOdd:		// Pow(±0, y) = +Inf for finite y < 0 and not an odd integer
+posZeroLtZero:	// special case Pow(+0, y < 0) = +Inf
+zeroNegInf:		// Pow(±0, -Inf) = +Inf
+	MOVD	$PosInf, R3
+	MOVD	R3, ret+16(FP)
+	RET
+gtOnePosInf:	//Pow(x, +Inf) = +Inf for |x| > 1
+ltNegOnePosInf:
+	MOVD	R2, ret+16(FP)
+	RET
+yIsZero:		//Pow(x, ±0) = 1 for any x
+	MOVD	$PosOne, R4
+	MOVD	R4, ret+16(FP)
+	RET
+negZeroOddIntGtZero:        // Pow(-0, y) = -0 for y an odd integer > 0
+	MOVD	$NegZero, R3
+	MOVD	R3, ret+16(FP)
+	RET
+zeroNotOddGtZero:        // Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+	MOVD	$0, ret+16(FP)
+	RET
diff --git a/src/math/pow_stub.s b/src/math/pow_stub.s
new file mode 100644
index 0000000..322d6c4
--- /dev/null
+++ b/src/math/pow_stub.s
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm
+
+#include "textflag.h"
+
+TEXT ·Pow(SB),NOSPLIT,$0
+    JMP ·pow(SB)
+
diff --git a/src/math/sin_s390x.s b/src/math/sin_s390x.s
index 5dc823c..39cc054 100644
--- a/src/math/sin_s390x.s
+++ b/src/math/sin_s390x.s
@@ -100,15 +100,15 @@ L2:
 	FADD    F3, F6
 	MOVD    $sincosxpi2h<>+0(SB), R1
 	FMOVD   0(R1), F2
-	FMSUB   F2, F6, F0, F0
+	FMSUB   F2, F6, F0
 	MOVD    $sincosxpi2m<>+0(SB), R1
 	FMOVD   0(R1), F4
-	FMADD   F4, F6, F0, F0
+	FMADD   F4, F6, F0
 	MOVD    $sincosxpi2l<>+0(SB), R1
 	WFMDB   V0, V0, V1
 	FMOVD   0(R1), F7
 	WFMDB   V1, V1, V2
-	WORD    $0xB3CD0013     //lgdr  %r1,%f3
+	LGDR    F3, R1
 	MOVD    $sincosxlim<>+0(SB), R2
 	WORD    $0xA7110001     //tmll  %r1,1
 	BEQ     L6
@@ -156,7 +156,7 @@ L6:
 	WFMADB  V6, V7, V0, V6
 	FMOVD   0(R2), F0
 	MOVD    $sincoss4<>+0(SB), R2
-	FMADD   F4, F1, F0, F0
+	FMADD   F4, F1, F0
 	FMOVD   0(R2), F3
 	MOVD    $sincoss2<>+0(SB), R2
 	FMOVD   0(R2), F4
@@ -192,7 +192,7 @@ L18:
 	WFMADB  V2, V6, V3, V6
 	FMUL    F0, F2
 	WFMADB  V1, V4, V6, V4
-	FMADD   F4, F2, F0, F0
+	FMADD   F4, F2, F0
 	FMOVD   F0, ret+8(FP)
 	RET
 
@@ -245,7 +245,7 @@ L21:
 	WFMSDB  V0, V2, V3, V2
 	FMOVD   0(R1), F3
 	WFCHDBS V3, V1, V3
-	WORD    $0xB3CD0012     //lgdr %r1,%f2
+	LGDR    F2, R1
 	BEQ     L36
 	MOVD    $sincosxadd<>+0(SB), R2
 	FMOVD   0(R2), F4
@@ -312,16 +312,16 @@ L25:
 	FMOVD   0(R2), F7
 	WFMADB  V6, V3, V7, V3
 	MOVD    $sincoss3<>+0(SB), R2
-	FMADD   F5, F4, F0, F0
+	FMADD   F5, F4, F0
 	FMOVD   0(R2), F4
 	MOVD    $sincoss1<>+0(SB), R2
-	FMADD   F1, F6, F4, F4
+	FMADD   F1, F6, F4
 	FMOVD   0(R2), F1
-	FMADD   F3, F2, F1, F1
+	FMADD   F3, F2, F1
 	FMUL    F0, F2
 	WFMADB  V6, V4, V1, V6
 	WORD    $0xA7110002     //tmll  %r1,2
-	FMADD   F6, F2, F0, F0
+	FMADD   F6, F2, F0
 	BNE     L34
 	FMOVD   F0, ret+8(FP)
 	RET
diff --git a/src/math/sincos.go b/src/math/sincos.go
index 6e663d0..3ae193a 100644
--- a/src/math/sincos.go
+++ b/src/math/sincos.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !386
+
 package math
 
 // Coefficients _sin[] and _cos[] are found in pkg/math/sin.go.
@@ -12,9 +14,7 @@ package math
 //	Sincos(±0) = ±0, 1
 //	Sincos(±Inf) = NaN, NaN
 //	Sincos(NaN) = NaN, NaN
-func Sincos(x float64) (sin, cos float64)
-
-func sincos(x float64) (sin, cos float64) {
+func Sincos(x float64) (sin, cos float64) {
 	const (
 		PI4A = 7.85398125648498535156E-1                             // 0x3fe921fb40000000, Pi/4 split into three parts
 		PI4B = 3.77489470793079817668E-8                             // 0x3e64442d00000000,
diff --git a/src/math/sincos_386.go b/src/math/sincos_386.go
new file mode 100644
index 0000000..38bb050
--- /dev/null
+++ b/src/math/sincos_386.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Sincos returns Sin(x), Cos(x).
+//
+// Special cases are:
+//	Sincos(±0) = ±0, 1
+//	Sincos(±Inf) = NaN, NaN
+//	Sincos(NaN) = NaN, NaN
+func Sincos(x float64) (sin, cos float64)
diff --git a/src/math/sincos_amd64.s b/src/math/sincos_amd64.s
deleted file mode 100644
index b9ef88c..0000000
--- a/src/math/sincos_amd64.s
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-// The method is based on a paper by Naoki Shibata: "Efficient evaluation
-// methods of elementary functions suitable for SIMD computation", Proc.
-// of International Supercomputing Conference 2010 (ISC'10), pp. 25 -- 32
-// (May 2010). The paper is available at
-// http://www.springerlink.com/content/340228x165742104/
-//
-// The original code and the constants below are from the author's
-// implementation available at http://freshmeat.net/projects/sleef.
-// The README file says, "The software is in public domain.
-// You can use the software without any obligation."
-//
-// This code is a simplified version of the original.
-
-#define PosOne 0x3FF0000000000000
-#define PosInf 0x7FF0000000000000
-#define NaN    0x7FF8000000000001
-#define PI4A 0.7853981554508209228515625 // pi/4 split into three parts
-#define PI4B 0.794662735614792836713604629039764404296875e-8
-#define PI4C 0.306161699786838294306516483068750264552437361480769e-16
-#define M4PI 1.273239544735162542821171882678754627704620361328125 // 4/pi
-#define T0 1.0
-#define T1 -8.33333333333333333333333e-02 // (-1.0/12)
-#define T2 2.77777777777777777777778e-03 // (+1.0/360)
-#define T3 -4.96031746031746031746032e-05 // (-1.0/20160)
-#define T4 5.51146384479717813051146e-07 // (+1.0/1814400)
-
-// func Sincos(d float64) (sin, cos float64)
-TEXT ·Sincos(SB),NOSPLIT,$0
-	// test for special cases
-	MOVQ    $~(1<<63), DX // sign bit mask
-	MOVQ    x+0(FP), BX
-	ANDQ    BX, DX
-	JEQ     isZero
-	MOVQ    $PosInf, AX
-	CMPQ    AX, DX
-	JLE     isInfOrNaN
-	// Reduce argument
-	MOVQ    BX, X7 // x7= d
-	MOVQ    DX, X0 // x0= |d|
-	MOVSD   $M4PI, X2
-	MULSD   X0, X2
-	CVTTSD2SQ X2, BX // bx= q
-	MOVQ    $1, AX
-	ANDQ    BX, AX
-	ADDQ    BX, AX
-	CVTSQ2SD AX, X2
-	MOVSD   $PI4A, X3
-	MULSD   X2, X3
-	SUBSD   X3, X0
-	MOVSD   $PI4B, X3
-	MULSD   X2, X3
-	SUBSD   X3, X0
-	MOVSD   $PI4C, X3
-	MULSD   X2, X3
-	SUBSD   X3, X0
-	MULSD   $0.125, X0 // x0= x, x7= d, bx= q
-	// Evaluate Taylor series
-	MULSD   X0, X0
-	MOVSD   $T4, X2
-	MULSD   X0, X2
-	ADDSD   $T3, X2
-	MULSD   X0, X2
-	ADDSD   $T2, X2
-	MULSD   X0, X2
-	ADDSD   $T1, X2
-	MULSD   X0, X2
-	ADDSD   $T0, X2
-	MULSD   X2, X0 // x0= x, x7= d, bx= q
-	// Apply double angle formula
-	MOVSD   $4.0, X2
-	SUBSD   X0, X2
-	MULSD   X2, X0
-	MOVSD   $4.0, X2
-	SUBSD   X0, X2
-	MULSD   X2, X0
-	MOVSD   $4.0, X2
-	SUBSD   X0, X2
-	MULSD   X2, X0
-	MULSD   $0.5, X0 // x0= x, x7= d, bx= q
-	// sin = sqrt((2 - x) * x)
-	MOVSD   $2.0, X2
-	SUBSD   X0, X2
-	MULSD   X0, X2
-	SQRTSD  X2, X2 // x0= x, x2= z, x7= d, bx= q
-	// cos = 1 - x
-	MOVSD   $1.0, X1
-	SUBSD   X0, X1 // x1= x, x2= z, x7= d, bx= q
-	// if ((q + 1) & 2) != 0 { sin, cos = cos, sin }
-	MOVQ    $1, DX
-	ADDQ    BX, DX
-	ANDQ    $2, DX
-	SHRQ    $1, DX
-	SUBQ	$1, DX
-	MOVQ    DX, X3
-	// sin = (y & z) | (^y & x)
-	MOVAPD  X2, X0
-	ANDPD   X3, X0 // x0= sin
-	MOVAPD  X3, X4
-	ANDNPD  X1, X4
-	ORPD    X4, X0 // x0= sin, x1= x, x2= z, x3= y, x7= d, bx= q
-	// cos = (y & x) | (^y & z)
-	ANDPD   X3, X1 // x1= cos
-	ANDNPD  X2, X3
-	ORPD    X3, X1 // x0= sin, x1= cos, x7= d, bx= q
-	// if ((q & 4) != 0) != (d < 0) { sin = -sin }
-	MOVQ    BX, AX
-	MOVQ    $61, CX
-	SHLQ    CX, AX
-	MOVQ    AX, X3
-	XORPD   X7, X3
-	MOVQ    $(1<<63), AX
-	MOVQ    AX, X2 // x2= -0.0
-	ANDPD   X2, X3
-	ORPD    X3, X0 // x0= sin, x1= cos, x2= -0.0, bx= q
-	// if ((q + 2) & 4) != 0 { cos = -cos }
-	MOVQ    $2, AX
-	ADDQ    AX, BX
-	MOVQ    $61, CX
-	SHLQ    CX, BX
-	MOVQ    BX, X3
-	ANDPD   X2, X3
-	ORPD    X3, X1 // x0= sin, x1= cos
-	// return (sin, cos)
-	MOVSD   X0, sin+8(FP)
-	MOVSD   X1, cos+16(FP)
-	RET
-isZero: // return (±0.0, 1.0)
-	MOVQ    BX, sin+8(FP)
-	MOVQ    $PosOne, AX
-	MOVQ    AX, cos+16(FP)
-	RET
-isInfOrNaN: // return (NaN, NaN)
-	MOVQ    $NaN, AX
-	MOVQ    AX, sin+8(FP)
-	MOVQ    AX, cos+16(FP)
-	RET
diff --git a/src/math/sincos_amd64p32.s b/src/math/sincos_amd64p32.s
deleted file mode 100644
index db86029..0000000
--- a/src/math/sincos_amd64p32.s
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "sincos_amd64.s"
diff --git a/src/math/sincos_arm.s b/src/math/sincos_arm.s
deleted file mode 100644
index d8d833c..0000000
--- a/src/math/sincos_arm.s
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-TEXT ·Sincos(SB),NOSPLIT,$0
-	B ·sincos(SB)
diff --git a/src/math/sinh_s390x.s b/src/math/sinh_s390x.s
index e492415..aa494de 100644
--- a/src/math/sinh_s390x.s
+++ b/src/math/sinh_s390x.s
@@ -112,7 +112,7 @@ L6:
 	MOVD    $sinhxadd<>+0(SB), R2
 	FMOVD   0(R2), F0
 	MOVD    sinhrlog2<>+0(SB), R2
-	WORD    $0xB3C10062     //ldgr  %f6,%r2
+	LDGR    R2, F6
 	WFMSDB  V4, V6, V0, V16
 	FMOVD   sinhrodataL21<>+8(SB), F6
 	WFADB   V0, V16, V0
@@ -168,7 +168,7 @@ L6:
 	WORD    $0xEC12000F     //risbgn %r1,%r2,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
-	WORD    $0xB3C10021     //ldgr %f2,%r1
+	LDGR    R1, F2
 	FMUL    F2, F0
 	FMOVD   F0, ret+8(FP)
 	RET
@@ -177,29 +177,29 @@ L20:
 	MOVD    $sinhxadd<>+0(SB), R2
 	FMOVD   0(R2), F2
 	MOVD    sinhrlog2<>+0(SB), R2
-	WORD    $0xB3C10002     //ldgr  %f0,%r2
+	LDGR    R2, F0
 	WFMSDB  V4, V0, V2, V6
 	FMOVD   sinhrodataL21<>+8(SB), F0
 	FADD    F6, F2
 	MOVD    $sinhe9<>+0(SB), R2
-	FMSUB   F0, F2, F4, F4
+	FMSUB   F0, F2, F4
 	FMOVD   0(R2), F1
 	FMOVD   sinhrodataL21<>+0(SB), F3
 	MOVD    $sinhe7<>+0(SB), R2
-	FMADD   F3, F2, F4, F4
+	FMADD   F3, F2, F4
 	FMOVD   0(R2), F0
 	MOVD    $sinhe8<>+0(SB), R2
 	WFMDB   V4, V4, V2
 	FMOVD   0(R2), F3
 	MOVD    $sinhe6<>+0(SB), R2
 	FMOVD   0(R2), F5
-	WORD    $0xB3CD0026     //lgdr %r2,%f6
+	LGDR    F6, R2
 	RLL     $3, R2, R2
 	WORD    $0xEC12000F     //risbgn %r1,%r2,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
 	WFMADB  V2, V1, V0, V1
-	WORD    $0xB3C10001     //ldgr  %f0,%r1
+	LDGR    R1, F0
 	MOVD    $sinhe5<>+0(SB), R1
 	WFMADB  V2, V3, V5, V3
 	FMOVD   0(R1), F5
@@ -214,7 +214,7 @@ L20:
 	WORD    $0xEC32000F     //risbgn %r3,%r2,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
-	WORD    $0xB3C10063     //ldgr  %f6,%r3
+	LDGR    R3, F6
 	WFADB   V0, V6, V16
 	MOVD    $sinhe4<>+0(SB), R1
 	WFMADB  V1, V7, V5, V1
@@ -245,7 +245,7 @@ L9:
 	WORD    $0xEC12000F     //risbgn %r1,%r2,64-64+0,64-64+0+16-1,64-0-16
 	BYTE    $0x30
 	BYTE    $0x59
-	WORD    $0xB3C10021     //ldgr %f2,%r1
+	LDGR    R1, F2
 	FMUL    F2, F0
 	FMOVD   F0, ret+8(FP)
 	RET
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
index d8c9aa8..ea8d339 100644
--- a/src/math/stubs_arm64.s
+++ b/src/math/stubs_arm64.s
@@ -12,15 +12,33 @@ TEXT ·Asin(SB),NOSPLIT,$0
 TEXT ·Acos(SB),NOSPLIT,$0
 	B ·acos(SB)
 
+TEXT ·Asinh(SB),NOSPLIT,$0
+        B ·asinh(SB)
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+        B ·acosh(SB)
+
 TEXT ·Atan2(SB),NOSPLIT,$0
 	B ·atan2(SB)
 
 TEXT ·Atan(SB),NOSPLIT,$0
 	B ·atan(SB)
 
+TEXT ·Atanh(SB),NOSPLIT,$0
+	B ·atanh(SB)
+
 TEXT ·Exp2(SB),NOSPLIT,$0
 	B ·exp2(SB)
 
+TEXT ·Erf(SB),NOSPLIT,$0
+	B ·erf(SB)
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+	B ·erfc(SB)
+
+TEXT ·Cbrt(SB),NOSPLIT,$0
+	B ·cbrt(SB)
+
 TEXT ·Cosh(SB),NOSPLIT,$0
 	B ·cosh(SB)
 
@@ -57,9 +75,6 @@ TEXT ·Mod(SB),NOSPLIT,$0
 TEXT ·Remainder(SB),NOSPLIT,$0
 	B ·remainder(SB)
 
-TEXT ·Sincos(SB),NOSPLIT,$0
-	B ·sincos(SB)
-
 TEXT ·Sin(SB),NOSPLIT,$0
 	B ·sin(SB)
 
@@ -74,3 +89,6 @@ TEXT ·Tan(SB),NOSPLIT,$0
 
 TEXT ·Tanh(SB),NOSPLIT,$0
 	B ·tanh(SB)
+
+TEXT ·Pow(SB),NOSPLIT,$0
+	B ·pow(SB)
diff --git a/src/math/stubs_mips64x.s b/src/math/stubs_mips64x.s
index 21df5cc..a0e0e38 100644
--- a/src/math/stubs_mips64x.s
+++ b/src/math/stubs_mips64x.s
@@ -12,12 +12,21 @@ TEXT ·Asin(SB),NOSPLIT,$0
 TEXT ·Acos(SB),NOSPLIT,$0
 	JMP ·acos(SB)
 
+TEXT ·Asinh(SB),NOSPLIT,$0
+        JMP ·asinh(SB)
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+        JMP ·acosh(SB)
+
 TEXT ·Atan2(SB),NOSPLIT,$0
 	JMP ·atan2(SB)
 
 TEXT ·Atan(SB),NOSPLIT,$0
 	JMP ·atan(SB)
 
+TEXT ·Atanh(SB),NOSPLIT,$0
+	JMP ·atanh(SB)
+
 TEXT ·Dim(SB),NOSPLIT,$0
 	JMP ·dim(SB)
 
@@ -27,6 +36,12 @@ TEXT ·Min(SB),NOSPLIT,$0
 TEXT ·Max(SB),NOSPLIT,$0
 	JMP ·max(SB)
 
+TEXT ·Erf(SB),NOSPLIT,$0
+	JMP ·erf(SB)
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+	JMP ·erfc(SB)
+
 TEXT ·Exp2(SB),NOSPLIT,$0
 	JMP ·exp2(SB)
 
@@ -75,9 +90,6 @@ TEXT ·Mod(SB),NOSPLIT,$0
 TEXT ·Remainder(SB),NOSPLIT,$0
 	JMP ·remainder(SB)
 
-TEXT ·Sincos(SB),NOSPLIT,$0
-	JMP ·sincos(SB)
-
 TEXT ·Sin(SB),NOSPLIT,$0
 	JMP ·sin(SB)
 
@@ -98,3 +110,9 @@ TEXT ·Tan(SB),NOSPLIT,$0
 
 TEXT ·Tanh(SB),NOSPLIT,$0
 	JMP ·tanh(SB)
+
+TEXT ·Cbrt(SB),NOSPLIT,$0
+	JMP ·cbrt(SB)
+
+TEXT ·Pow(SB),NOSPLIT,$0
+	JMP ·pow(SB)
diff --git a/src/math/stubs_mipsx.s b/src/math/stubs_mipsx.s
index b869768..e959f07 100644
--- a/src/math/stubs_mipsx.s
+++ b/src/math/stubs_mipsx.s
@@ -12,12 +12,21 @@ TEXT ·Asin(SB),NOSPLIT,$0
 TEXT ·Acos(SB),NOSPLIT,$0
 	JMP	·acos(SB)
 
+TEXT ·Asinh(SB),NOSPLIT,$0
+        JMP ·asinh(SB)
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+        JMP ·acosh(SB)
+
 TEXT ·Atan2(SB),NOSPLIT,$0
 	JMP	·atan2(SB)
 
 TEXT ·Atan(SB),NOSPLIT,$0
 	JMP	·atan(SB)
 
+TEXT ·Atanh(SB),NOSPLIT,$0
+	JMP	·atanh(SB)
+
 TEXT ·Dim(SB),NOSPLIT,$0
 	JMP	·dim(SB)
 
@@ -27,6 +36,12 @@ TEXT ·Min(SB),NOSPLIT,$0
 TEXT ·Max(SB),NOSPLIT,$0
 	JMP	·max(SB)
 
+TEXT ·Erf(SB),NOSPLIT,$0
+	JMP	·erf(SB)
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+	JMP	·erfc(SB)
+
 TEXT ·Exp2(SB),NOSPLIT,$0
 	JMP	·exp2(SB)
 
@@ -75,9 +90,6 @@ TEXT ·Mod(SB),NOSPLIT,$0
 TEXT ·Remainder(SB),NOSPLIT,$0
 	JMP	·remainder(SB)
 
-TEXT ·Sincos(SB),NOSPLIT,$0
-	JMP	·sincos(SB)
-
 TEXT ·Sin(SB),NOSPLIT,$0
 	JMP	·sin(SB)
 
@@ -96,3 +108,9 @@ TEXT ·Tan(SB),NOSPLIT,$0
 TEXT ·Tanh(SB),NOSPLIT,$0
         JMP ·tanh(SB)
 
+TEXT ·Cbrt(SB),NOSPLIT,$0
+        JMP ·cbrt(SB)
+
+TEXT ·Pow(SB),NOSPLIT,$0
+        JMP ·pow(SB)
+
diff --git a/src/math/stubs_ppc64x.s b/src/math/stubs_ppc64x.s
index b622016..9d46ebf 100644
--- a/src/math/stubs_ppc64x.s
+++ b/src/math/stubs_ppc64x.s
@@ -12,12 +12,21 @@ TEXT ·Asin(SB),NOSPLIT,$0
 TEXT ·Acos(SB),NOSPLIT,$0
 	BR ·acos(SB)
 
+TEXT ·Asinh(SB),NOSPLIT,$0
+        BR ·asinh(SB)
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+        BR ·acosh(SB)
+
 TEXT ·Atan2(SB),NOSPLIT,$0
 	BR ·atan2(SB)
 
 TEXT ·Atan(SB),NOSPLIT,$0
 	BR ·atan(SB)
 
+TEXT ·Atanh(SB),NOSPLIT,$0
+	BR ·atanh(SB)
+
 TEXT ·Dim(SB),NOSPLIT,$0
 	BR ·dim(SB)
 
@@ -27,6 +36,12 @@ TEXT ·Min(SB),NOSPLIT,$0
 TEXT ·Max(SB),NOSPLIT,$0
 	BR ·max(SB)
 
+TEXT ·Erf(SB),NOSPLIT,$0
+	BR ·erf(SB)
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+	BR ·erfc(SB)
+
 TEXT ·Exp2(SB),NOSPLIT,$0
 	BR ·exp2(SB)
 
@@ -66,9 +81,6 @@ TEXT ·Mod(SB),NOSPLIT,$0
 TEXT ·Remainder(SB),NOSPLIT,$0
 	BR ·remainder(SB)
 
-TEXT ·Sincos(SB),NOSPLIT,$0
-	BR ·sincos(SB)
-
 TEXT ·Sin(SB),NOSPLIT,$0
 	BR ·sin(SB)
 
@@ -86,3 +98,10 @@ TEXT ·Tan(SB),NOSPLIT,$0
 
 TEXT ·Tanh(SB),NOSPLIT,$0
 	BR ·tanh(SB)
+
+TEXT ·Cbrt(SB),NOSPLIT,$0
+	BR ·cbrt(SB)
+
+TEXT ·Pow(SB),NOSPLIT,$0
+	BR ·pow(SB)
+
diff --git a/src/math/stubs_s390x.s b/src/math/stubs_s390x.s
index 8da55c5..889e248 100644
--- a/src/math/stubs_s390x.s
+++ b/src/math/stubs_s390x.s
@@ -4,27 +4,9 @@
 
 #include "textflag.h"
 
-TEXT ·Asin(SB),NOSPLIT,$0
-	BR ·asin(SB)
-
-TEXT ·Acos(SB),NOSPLIT,$0
-	BR ·acos(SB)
-
-TEXT ·Atan2(SB),NOSPLIT,$0
-	BR ·atan2(SB)
-
-TEXT ·Atan(SB),NOSPLIT,$0
-	BR ·atan(SB)
-
 TEXT ·Exp2(SB),NOSPLIT,$0
 	BR ·exp2(SB)
 
-TEXT ·Expm1(SB),NOSPLIT,$0
-	BR ·expm1(SB)
-
-TEXT ·Exp(SB),NOSPLIT,$0
-	BR ·exp(SB)
-
 TEXT ·Frexp(SB),NOSPLIT,$0
 	BR ·frexp(SB)
 
@@ -37,12 +19,6 @@ TEXT ·Ldexp(SB),NOSPLIT,$0
 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)
 
@@ -52,12 +28,6 @@ TEXT ·Mod(SB),NOSPLIT,$0
 TEXT ·Remainder(SB),NOSPLIT,$0
 	BR ·remainder(SB)
 
-TEXT ·Sincos(SB),NOSPLIT,$0
-	BR ·sincos(SB)
-
-TEXT ·Tan(SB),NOSPLIT,$0
-	BR ·tan(SB)
-
 //if go assembly use vector instruction
 TEXT ·hasVectorFacility(SB),NOSPLIT,$24-1
 	MOVD    $x-24(SP), R1
@@ -80,129 +50,463 @@ novector:
 	RET
 
 TEXT ·Log10(SB),NOSPLIT,$0
-	MOVD    log10vectorfacility+0x00(SB),R1
+	MOVD    ·log10vectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·log10TrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $log10vectorfacility+0x00(SB), R1
+	MOVD    $·log10vectorfacility+0x00(SB), R1
 	MOVD    $·log10(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·log10(SB)
 vectorimpl:
-	MOVD    $log10vectorfacility+0x00(SB), R1
+	MOVD    $·log10vectorfacility+0x00(SB), R1
 	MOVD    $·log10Asm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·log10Asm(SB)
 
-GLOBL log10vectorfacility+0x00(SB), NOPTR, $8
-DATA log10vectorfacility+0x00(SB)/8, $·log10TrampolineSetup(SB)
+GLOBL ·log10vectorfacility+0x00(SB), NOPTR, $8
+DATA ·log10vectorfacility+0x00(SB)/8, $·log10TrampolineSetup(SB)
 
 
 TEXT ·Cos(SB),NOSPLIT,$0
-	MOVD    cosvectorfacility+0x00(SB),R1
+	MOVD    ·cosvectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·cosTrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $cosvectorfacility+0x00(SB), R1
+	MOVD    $·cosvectorfacility+0x00(SB), R1
 	MOVD    $·cos(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·cos(SB)
 vectorimpl:
-	MOVD    $cosvectorfacility+0x00(SB), R1
+	MOVD    $·cosvectorfacility+0x00(SB), R1
 	MOVD    $·cosAsm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·cosAsm(SB)
 
-GLOBL cosvectorfacility+0x00(SB), NOPTR, $8
-DATA cosvectorfacility+0x00(SB)/8, $·cosTrampolineSetup(SB)
+GLOBL ·cosvectorfacility+0x00(SB), NOPTR, $8
+DATA ·cosvectorfacility+0x00(SB)/8, $·cosTrampolineSetup(SB)
 
 
 TEXT ·Cosh(SB),NOSPLIT,$0
-	MOVD    coshvectorfacility+0x00(SB),R1
+	MOVD    ·coshvectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·coshTrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $coshvectorfacility+0x00(SB), R1
+	MOVD    $·coshvectorfacility+0x00(SB), R1
 	MOVD    $·cosh(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·cosh(SB)
 vectorimpl:
-	MOVD    $coshvectorfacility+0x00(SB), R1
+	MOVD    $·coshvectorfacility+0x00(SB), R1
 	MOVD    $·coshAsm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·coshAsm(SB)
 
-GLOBL coshvectorfacility+0x00(SB), NOPTR, $8
-DATA coshvectorfacility+0x00(SB)/8, $·coshTrampolineSetup(SB)
+GLOBL ·coshvectorfacility+0x00(SB), NOPTR, $8
+DATA ·coshvectorfacility+0x00(SB)/8, $·coshTrampolineSetup(SB)
 
 
 TEXT ·Sin(SB),NOSPLIT,$0
-	MOVD    sinvectorfacility+0x00(SB),R1
+	MOVD    ·sinvectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·sinTrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $sinvectorfacility+0x00(SB), R1
+	MOVD    $·sinvectorfacility+0x00(SB), R1
 	MOVD    $·sin(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·sin(SB)
 vectorimpl:
-	MOVD    $sinvectorfacility+0x00(SB), R1
+	MOVD    $·sinvectorfacility+0x00(SB), R1
 	MOVD    $·sinAsm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·sinAsm(SB)
 
-GLOBL sinvectorfacility+0x00(SB), NOPTR, $8
-DATA sinvectorfacility+0x00(SB)/8, $·sinTrampolineSetup(SB)
+GLOBL ·sinvectorfacility+0x00(SB), NOPTR, $8
+DATA ·sinvectorfacility+0x00(SB)/8, $·sinTrampolineSetup(SB)
 
 
 TEXT ·Sinh(SB),NOSPLIT,$0
-	MOVD    sinhvectorfacility+0x00(SB),R1
+	MOVD    ·sinhvectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·sinhTrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $sinhvectorfacility+0x00(SB), R1
+	MOVD    $·sinhvectorfacility+0x00(SB), R1
 	MOVD    $·sinh(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·sinh(SB)
 vectorimpl:
-	MOVD    $sinhvectorfacility+0x00(SB), R1
+	MOVD    $·sinhvectorfacility+0x00(SB), R1
 	MOVD    $·sinhAsm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·sinhAsm(SB)
 
-GLOBL sinhvectorfacility+0x00(SB), NOPTR, $8
-DATA sinhvectorfacility+0x00(SB)/8, $·sinhTrampolineSetup(SB)
-
+GLOBL ·sinhvectorfacility+0x00(SB), NOPTR, $8
+DATA ·sinhvectorfacility+0x00(SB)/8, $·sinhTrampolineSetup(SB)
 
 
 TEXT ·Tanh(SB),NOSPLIT,$0
-	MOVD    tanhvectorfacility+0x00(SB),R1
+	MOVD    ·tanhvectorfacility+0x00(SB),R1
 	BR      (R1)
 
 TEXT ·tanhTrampolineSetup(SB),NOSPLIT, $0
 	MOVB    ·hasVX(SB), R1
 	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
-	MOVD    $tanhvectorfacility+0x00(SB), R1
+	MOVD    $·tanhvectorfacility+0x00(SB), R1
 	MOVD    $·tanh(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·tanh(SB)
 vectorimpl:
-	MOVD    $tanhvectorfacility+0x00(SB), R1
+	MOVD    $·tanhvectorfacility+0x00(SB), R1
 	MOVD    $·tanhAsm(SB), R2
 	MOVD    R2, 0(R1)
 	BR      ·tanhAsm(SB)
 
-GLOBL tanhvectorfacility+0x00(SB), NOPTR, $8
-DATA tanhvectorfacility+0x00(SB)/8, $·tanhTrampolineSetup(SB)
+GLOBL ·tanhvectorfacility+0x00(SB), NOPTR, $8
+DATA ·tanhvectorfacility+0x00(SB)/8, $·tanhTrampolineSetup(SB)
+
+
+TEXT ·Log1p(SB),NOSPLIT,$0
+	MOVD    ·log1pvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·log1pTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·log1pvectorfacility+0x00(SB), R1
+	MOVD    $·log1p(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·log1p(SB)
+vectorimpl:
+	MOVD    $·log1pvectorfacility+0x00(SB), R1
+	MOVD    $·log1pAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·log1pAsm(SB)
+
+GLOBL ·log1pvectorfacility+0x00(SB), NOPTR, $8
+DATA ·log1pvectorfacility+0x00(SB)/8, $·log1pTrampolineSetup(SB)
+
+
+TEXT ·Atanh(SB),NOSPLIT,$0
+	MOVD    ·atanhvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·atanhTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·atanhvectorfacility+0x00(SB), R1
+	MOVD    $·atanh(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atanh(SB)
+vectorimpl:
+	MOVD    $·atanhvectorfacility+0x00(SB), R1
+	MOVD    $·atanhAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atanhAsm(SB)
+
+GLOBL ·atanhvectorfacility+0x00(SB), NOPTR, $8
+DATA ·atanhvectorfacility+0x00(SB)/8, $·atanhTrampolineSetup(SB)
+
+
+TEXT ·Acos(SB),NOSPLIT,$0
+	MOVD    ·acosvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·acosTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·acosvectorfacility+0x00(SB), R1
+	MOVD    $·acos(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·acos(SB)
+vectorimpl:
+	MOVD    $·acosvectorfacility+0x00(SB), R1
+	MOVD    $·acosAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·acosAsm(SB)
+
+GLOBL ·acosvectorfacility+0x00(SB), NOPTR, $8
+DATA ·acosvectorfacility+0x00(SB)/8, $·acosTrampolineSetup(SB)
+
+
+TEXT ·Asin(SB),NOSPLIT,$0
+	MOVD    ·asinvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·asinTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·asinvectorfacility+0x00(SB), R1
+	MOVD    $·asin(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·asin(SB)
+vectorimpl:
+	MOVD    $·asinvectorfacility+0x00(SB), R1
+	MOVD    $·asinAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·asinAsm(SB)
+
+GLOBL ·asinvectorfacility+0x00(SB), NOPTR, $8
+DATA ·asinvectorfacility+0x00(SB)/8, $·asinTrampolineSetup(SB)
+
+
+TEXT ·Asinh(SB),NOSPLIT,$0
+	MOVD    ·asinhvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·asinhTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·asinhvectorfacility+0x00(SB), R1
+	MOVD    $·asinh(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·asinh(SB)
+vectorimpl:
+	MOVD    $·asinhvectorfacility+0x00(SB), R1
+	MOVD    $·asinhAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·asinhAsm(SB)
+
+GLOBL ·asinhvectorfacility+0x00(SB), NOPTR, $8
+DATA ·asinhvectorfacility+0x00(SB)/8, $·asinhTrampolineSetup(SB)
+
+
+TEXT ·Acosh(SB),NOSPLIT,$0
+	MOVD    ·acoshvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·acoshTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·acoshvectorfacility+0x00(SB), R1
+	MOVD    $·acosh(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·acosh(SB)
+vectorimpl:
+	MOVD    $·acoshvectorfacility+0x00(SB), R1
+	MOVD    $·acoshAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·acoshAsm(SB)
+
+GLOBL ·acoshvectorfacility+0x00(SB), NOPTR, $8
+DATA ·acoshvectorfacility+0x00(SB)/8, $·acoshTrampolineSetup(SB)
+
+
+TEXT ·Erf(SB),NOSPLIT,$0
+	MOVD    ·erfvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·erfTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·erfvectorfacility+0x00(SB), R1
+	MOVD    $·erf(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·erf(SB)
+vectorimpl:
+	MOVD    $·erfvectorfacility+0x00(SB), R1
+	MOVD    $·erfAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·erfAsm(SB)
+
+GLOBL ·erfvectorfacility+0x00(SB), NOPTR, $8
+DATA ·erfvectorfacility+0x00(SB)/8, $·erfTrampolineSetup(SB)
+
+
+TEXT ·Erfc(SB),NOSPLIT,$0
+	MOVD    ·erfcvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·erfcTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·erfcvectorfacility+0x00(SB), R1
+	MOVD    $·erfc(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·erfc(SB)
+vectorimpl:
+	MOVD    $·erfcvectorfacility+0x00(SB), R1
+	MOVD    $·erfcAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·erfcAsm(SB)
+
+GLOBL ·erfcvectorfacility+0x00(SB), NOPTR, $8
+DATA ·erfcvectorfacility+0x00(SB)/8, $·erfcTrampolineSetup(SB)
+
+
+TEXT ·Atan(SB),NOSPLIT,$0
+	MOVD    ·atanvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·atanTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·atanvectorfacility+0x00(SB), R1
+	MOVD    $·atan(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atan(SB)
+vectorimpl:
+	MOVD    $·atanvectorfacility+0x00(SB), R1
+	MOVD    $·atanAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atanAsm(SB)
+
+GLOBL ·atanvectorfacility+0x00(SB), NOPTR, $8
+DATA ·atanvectorfacility+0x00(SB)/8, $·atanTrampolineSetup(SB)
+
+
+TEXT ·Atan2(SB),NOSPLIT,$0
+	MOVD    ·atan2vectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·atan2TrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·atan2vectorfacility+0x00(SB), R1
+	MOVD    $·atan2(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atan2(SB)
+vectorimpl:
+	MOVD    $·atan2vectorfacility+0x00(SB), R1
+	MOVD    $·atan2Asm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·atan2Asm(SB)
+
+GLOBL ·atan2vectorfacility+0x00(SB), NOPTR, $8
+DATA ·atan2vectorfacility+0x00(SB)/8, $·atan2TrampolineSetup(SB)
+
+
+TEXT ·Cbrt(SB),NOSPLIT,$0
+	MOVD    ·cbrtvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·cbrtTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·cbrtvectorfacility+0x00(SB), R1
+	MOVD    $·cbrt(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·cbrt(SB)
+vectorimpl:
+	MOVD    $·cbrtvectorfacility+0x00(SB), R1
+	MOVD    $·cbrtAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·cbrtAsm(SB)
+
+GLOBL ·cbrtvectorfacility+0x00(SB), NOPTR, $8
+DATA ·cbrtvectorfacility+0x00(SB)/8, $·cbrtTrampolineSetup(SB)
+
+
+TEXT ·Log(SB),NOSPLIT,$0
+	MOVD    ·logvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·logTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·logvectorfacility+0x00(SB), R1
+	MOVD    $·log(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·log(SB)
+vectorimpl:
+	MOVD    $·logvectorfacility+0x00(SB), R1
+	MOVD    $·logAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·logAsm(SB)
+
+GLOBL ·logvectorfacility+0x00(SB), NOPTR, $8
+DATA ·logvectorfacility+0x00(SB)/8, $·logTrampolineSetup(SB)
+
+
+TEXT ·Tan(SB),NOSPLIT,$0
+	MOVD    ·tanvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·tanTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·tanvectorfacility+0x00(SB), R1
+	MOVD    $·tan(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·tan(SB)
+vectorimpl:
+	MOVD    $·tanvectorfacility+0x00(SB), R1
+	MOVD    $·tanAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·tanAsm(SB)
+
+GLOBL ·tanvectorfacility+0x00(SB), NOPTR, $8
+DATA ·tanvectorfacility+0x00(SB)/8, $·tanTrampolineSetup(SB)
+
+TEXT ·Exp(SB),NOSPLIT,$0
+	MOVD    ·expvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·expTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·expvectorfacility+0x00(SB), R1
+	MOVD    $·exp(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·exp(SB)
+vectorimpl:
+	MOVD    $·expvectorfacility+0x00(SB), R1
+	MOVD    $·expAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·expAsm(SB)
+
+GLOBL ·expvectorfacility+0x00(SB), NOPTR, $8
+DATA ·expvectorfacility+0x00(SB)/8, $·expTrampolineSetup(SB)
+
+
+TEXT ·Expm1(SB),NOSPLIT,$0
+	MOVD    ·expm1vectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·expm1TrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·expm1vectorfacility+0x00(SB), R1
+	MOVD    $·expm1(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·expm1(SB)
+vectorimpl:
+	MOVD    $·expm1vectorfacility+0x00(SB), R1
+	MOVD    $·expm1Asm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·expm1Asm(SB)
+
+GLOBL ·expm1vectorfacility+0x00(SB), NOPTR, $8
+DATA ·expm1vectorfacility+0x00(SB)/8, $·expm1TrampolineSetup(SB)
+
+
+TEXT ·Pow(SB),NOSPLIT,$0
+	MOVD    ·powvectorfacility+0x00(SB),R1
+	BR      (R1)
+
+TEXT ·powTrampolineSetup(SB),NOSPLIT, $0
+	MOVB    ·hasVX(SB), R1
+	CMPBEQ  R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+	MOVD    $·powvectorfacility+0x00(SB), R1
+	MOVD    $·pow(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·pow(SB)
+vectorimpl:
+	MOVD    $·powvectorfacility+0x00(SB), R1
+	MOVD    $·powAsm(SB), R2
+	MOVD    R2, 0(R1)
+	BR      ·powAsm(SB)
+
+GLOBL ·powvectorfacility+0x00(SB), NOPTR, $8
+DATA ·powvectorfacility+0x00(SB)/8, $·powTrampolineSetup(SB)
 
 
diff --git a/src/math/tan_s390x.s b/src/math/tan_s390x.s
new file mode 100644
index 0000000..c03b240
--- /dev/null
+++ b/src/math/tan_s390x.s
@@ -0,0 +1,110 @@
+// Copyright 2017 The Go 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"
+
+// Minimax polynomial approximations
+DATA ·tanrodataL13<> + 0(SB)/8, $0.181017336383229927e-07
+DATA ·tanrodataL13<> + 8(SB)/8, $-.256590857271311164e-03
+DATA ·tanrodataL13<> + 16(SB)/8, $-.464359274328689195e+00
+DATA ·tanrodataL13<> + 24(SB)/8, $1.0
+DATA ·tanrodataL13<> + 32(SB)/8, $-.333333333333333464e+00
+DATA ·tanrodataL13<> + 40(SB)/8, $0.245751217306830032e-01
+DATA ·tanrodataL13<> + 48(SB)/8, $-.245391301343844510e-03
+DATA ·tanrodataL13<> + 56(SB)/8, $0.214530914428992319e-01
+DATA ·tanrodataL13<> + 64(SB)/8, $0.108285667160535624e-31
+DATA ·tanrodataL13<> + 72(SB)/8, $0.612323399573676480e-16
+DATA ·tanrodataL13<> + 80(SB)/8, $0.157079632679489656e+01
+DATA ·tanrodataL13<> + 88(SB)/8, $0.636619772367581341e+00
+GLOBL ·tanrodataL13<> + 0(SB), RODATA, $96
+
+// Constants
+DATA ·tanxnan<> + 0(SB)/8, $0x7ff8000000000000
+GLOBL ·tanxnan<> + 0(SB), RODATA, $8
+DATA ·tanxlim<> + 0(SB)/8, $0x432921fb54442d19
+GLOBL ·tanxlim<> + 0(SB), RODATA, $8
+DATA ·tanxadd<> + 0(SB)/8, $0xc338000000000000
+GLOBL ·tanxadd<> + 0(SB), RODATA, $8
+
+// Tan returns the tangent of the radian argument.
+//
+// Special cases are:
+//      Tan(±0) = ±0
+//      Tan(±Inf) = NaN
+//      Tan(NaN) = NaN
+// The algorithm used is minimax polynomial approximation using a table of
+// polynomial coefficients determined with a Remez exchange algorithm.
+
+TEXT	·tanAsm(SB), NOSPLIT, $0-16
+	FMOVD	x+0(FP), F0
+	//specail case Tan(±0) = ±0
+	FMOVD   $(0.0), F1
+	FCMPU   F0, F1
+	BEQ     atanIsZero
+
+	MOVD	$·tanrodataL13<>+0(SB), R5
+	WORD	$0xB3120000	//ltdbr	%f0,%f0
+	BLTU	L10
+	FMOVD	F0, F2
+L2:
+	MOVD	$·tanxlim<>+0(SB), R1
+	WORD	$0xED201000	//cdb	%f2,0(%r1)
+	BYTE	$0x00
+	BYTE	$0x19
+	BGE	L11
+	BVS	L11
+	MOVD	$·tanxadd<>+0(SB), R1
+	FMOVD	88(R5), F6
+	FMOVD	0(R1), F4
+	WFMSDB	V0, V6, V4, V6
+	FMOVD	80(R5), F1
+	FADD	F6, F4
+	FMOVD	72(R5), F2
+	FMSUB	F1, F4, F0
+	FMOVD	64(R5), F3
+	WFMADB	V4, V2, V0, V2
+	FMOVD	56(R5), F1
+	WFMADB	V4, V3, V2, V4
+	FMUL	F2, F2
+	VLEG	$0, 48(R5), V18
+	WORD	$0xB3CD0016	//lgdr	%r1,%f6
+	FMOVD	40(R5), F5
+	FMOVD	32(R5), F3
+	FMADD	F1, F2, F3
+	FMOVD	24(R5), F1
+	FMOVD	16(R5), F7
+	FMOVD	8(R5), F0
+	WFMADB	V2, V7, V1, V7
+	WFMADB	V2, V0, V5, V0
+	WFMDB	V2, V2, V1
+	FMOVD	0(R5), F5
+	WFLCDB	V4, V16
+	WFMADB	V2, V5, V18, V5
+	WFMADB	V1, V0, V7, V0
+	WORD	$0xA7110001	//tmll	%r1,1
+	WFMADB	V1, V5, V3, V1
+	BNE	L12
+	WFDDB	V0, V1, V0
+	WFMDB	V2, V16, V2
+	WFMADB	V2, V0, V4, V0
+	WORD	$0xB3130000	//lcdbr	%f0,%f0
+	FMOVD	F0, ret+8(FP)
+	RET
+L12:
+	WFMSDB	V2, V1, V0, V2
+	WFMDB	V16, V2, V2
+	FDIV	F2, F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L11:
+	MOVD	$·tanxnan<>+0(SB), R1
+	FMOVD	0(R1), F0
+	FMOVD	F0, ret+8(FP)
+	RET
+L10:
+	WORD	$0xB3130020	//lcdbr	%f2,%f0
+	BR	L2
+atanIsZero:
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/tanh_s390x.s b/src/math/tanh_s390x.s
index 1b76c14..026d989 100644
--- a/src/math/tanh_s390x.s
+++ b/src/math/tanh_s390x.s
@@ -59,7 +59,7 @@ GLOBL tanhtab<>+0(SB), RODATA, $128
 
 TEXT ·tanhAsm(SB),NOSPLIT,$0-16
 	FMOVD   x+0(FP), F0
-	//specail case Tanh(±0) = ±0
+	// special case Tanh(±0) = ±0
 	FMOVD   $(0.0), F1
 	FCMPU   F0, F1
 	BEQ     tanhIsZero
@@ -72,10 +72,10 @@ L2:
 	MOVD    $tanhxadd<>+0(SB), R2
 	FMOVD   0(R2), F2
 	MOVD    tanhrlog2<>+0(SB), R2
-	WORD    $0xB3C10042     //ldgr %f4,%r2
+	LDGR    R2, F4
 	WFMSDB  V0, V4, V2, V4
 	MOVD    $tanhtab<>+0(SB), R3
-	WORD    $0xB3CD0024     //lgdr %r2,%f4
+	LGDR    F4, R2
 	WORD    $0xEC4239BC     //risbg %r4,%r2,57,128+60,3
 	BYTE    $0x03
 	BYTE    $0x55
@@ -86,7 +86,7 @@ L2:
 	BYTE    $0x30
 	BYTE    $0x59
 	WORD    $0x68543000     //ld %f5,0(%r4,%r3)
-	WORD    $0xB3C10061     //ldgr %f6,%r1
+	LDGR    R1, F6
 	BLT     L3
 	MOVD    $tanhxzero<>+0(SB), R1
 	FMOVD   0(R1), F2
@@ -102,7 +102,7 @@ L2:
 L3:
 	FADD    F4, F2
 	FMOVD   tanhrodataL18<>+80(SB), F4
-	FMADD   F4, F2, F0, F0
+	FMADD   F4, F2, F0
 	FMOVD   tanhrodataL18<>+72(SB), F1
 	WFMDB   V0, V0, V3
 	FMOVD   tanhrodataL18<>+64(SB), F2
@@ -154,7 +154,7 @@ L15:
 L16:
 	FADD    F6, F2
 	FMOVD   tanhrodataL18<>+8(SB), F0
-	FMADD   F4, F2, F0, F0
+	FMADD   F4, F2, F0
 	FMOVD   tanhrodataL18<>+0(SB), F4
 	FNEG    F0, F0
 	WFMADB  V0, V2, V4, V0
diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go
index c3ca4ba..99eb432 100644
--- a/src/mime/encodedword.go
+++ b/src/mime/encodedword.go
@@ -188,27 +188,35 @@ type WordDecoder struct {
 	// charset into UTF-8.
 	// Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets
 	// are handled by default.
-	// One of the the CharsetReader's result values must be non-nil.
+	// One of the CharsetReader's result values must be non-nil.
 	CharsetReader func(charset string, input io.Reader) (io.Reader, error)
 }
 
 // Decode decodes an RFC 2047 encoded-word.
 func (d *WordDecoder) Decode(word string) (string, error) {
-	if !strings.HasPrefix(word, "=?") || !strings.HasSuffix(word, "?=") || strings.Count(word, "?") != 4 {
+	// See https://tools.ietf.org/html/rfc2047#section-2 for details.
+	// Our decoder is permissive, we accept empty encoded-text.
+	if len(word) < 8 || !strings.HasPrefix(word, "=?") || !strings.HasSuffix(word, "?=") || strings.Count(word, "?") != 4 {
 		return "", errInvalidWord
 	}
 	word = word[2 : len(word)-2]
 
 	// split delimits the first 2 fields
 	split := strings.IndexByte(word, '?')
-	// the field after split must only be one byte
-	if word[split+2] != '?' {
-		return "", errInvalidWord
-	}
 
 	// split word "UTF-8?q?ascii" into "UTF-8", 'q', and "ascii"
 	charset := word[:split]
+	if len(charset) == 0 {
+		return "", errInvalidWord
+	}
+	if len(word) < split+3 {
+		return "", errInvalidWord
+	}
 	encoding := word[split+1]
+	// the field after split must only be one byte
+	if word[split+2] != '?' {
+		return "", errInvalidWord
+	}
 	text := word[split+3:]
 
 	content, err := decode(encoding, text)
diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go
index b7ca4d0..6c54e50 100644
--- a/src/mime/encodedword_test.go
+++ b/src/mime/encodedword_test.go
@@ -88,6 +88,9 @@ func TestDecodeWord(t *testing.T) {
 		{"=?UTF-8?Q?A=B?=", "", true},
 		{"=?UTF-8?Q?=A?=", "", true},
 		{"=?UTF-8?A?A?=", "", true},
+		{"=????=", "", true},
+		{"=?UTF-8???=", "", true},
+		{"=?UTF-8?Q??=", "", false},
 	}
 
 	for _, test := range tests {
diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go
index 75cc903..5557672 100644
--- a/src/mime/mediatype.go
+++ b/src/mime/mediatype.go
@@ -94,11 +94,19 @@ func checkMediaTypeDisposition(s string) error {
 	return nil
 }
 
+// ErrInvalidMediaParameter is returned by ParseMediaType if
+// the media type value was found but there was an error parsing
+// the optional parameters
+var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter")
+
 // ParseMediaType parses a media type value and any optional
 // parameters, per RFC 1521.  Media types are the values in
 // Content-Type and Content-Disposition headers (RFC 2183).
 // On success, ParseMediaType returns the media type converted
 // to lowercase and trimmed of white space and a non-nil map.
+// If there is an error parsing the optional parameter,
+// the media type will be returned along with the error
+// ErrInvalidMediaParameter.
 // The returned map, params, maps from the lowercase
 // attribute to the attribute value with its case preserved.
 func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
@@ -134,7 +142,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
 				return
 			}
 			// Parse error.
-			return "", nil, errors.New("mime: invalid media parameter")
+			return mediatype, nil, ErrInvalidMediaParameter
 		}
 
 		pmap := params
diff --git a/src/mime/mediatype_test.go b/src/mime/mediatype_test.go
index c5fc906..3ba8ee1 100644
--- a/src/mime/mediatype_test.go
+++ b/src/mime/mediatype_test.go
@@ -253,13 +253,18 @@ func TestParseMediaType(t *testing.T) {
 
 type badMediaTypeTest struct {
 	in  string
+	mt  string
 	err string
 }
 
 var badMediaTypeTests = []badMediaTypeTest{
-	{"bogus ;=========", "mime: invalid media parameter"},
-	{"bogus/<script>alert</script>", "mime: expected token after slash"},
-	{"bogus/bogus<script>alert</script>", "mime: unexpected content after media subtype"},
+	{"bogus ;=========", "bogus", "mime: invalid media parameter"},
+	// The following example is from real email delivered by gmail (error: missing semicolon)
+	// and it is there to check behavior described in #19498
+	{"application/pdf; x-mac-type=\"3F3F3F3F\"; x-mac-creator=\"3F3F3F3F\" name=\"a.pdf\";",
+		"application/pdf", "mime: invalid media parameter"},
+	{"bogus/<script>alert</script>", "", "mime: expected token after slash"},
+	{"bogus/bogus<script>alert</script>", "", "mime: unexpected content after media subtype"},
 }
 
 func TestParseMediaTypeBogus(t *testing.T) {
@@ -275,8 +280,11 @@ func TestParseMediaTypeBogus(t *testing.T) {
 		if params != nil {
 			t.Errorf("ParseMediaType(%q): got non-nil params on error", tt.in)
 		}
-		if mt != "" {
-			t.Errorf("ParseMediaType(%q): got non-empty media type string on error", tt.in)
+		if err != ErrInvalidMediaParameter && mt != "" {
+			t.Errorf("ParseMediaType(%q): got unexpected non-empty media type string", tt.in)
+		}
+		if err == ErrInvalidMediaParameter && mt != tt.mt {
+			t.Errorf("ParseMediaType(%q): in case of invalid parameters: expected type %q, got %q", tt.in, tt.mt, mt)
 		}
 	}
 }
diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
index c9e3188..832d0ad 100644
--- a/src/mime/multipart/formdata.go
+++ b/src/mime/multipart/formdata.go
@@ -13,13 +13,20 @@ import (
 	"os"
 )
 
+// ErrMessageTooLarge is returned by ReadForm if the message form
+// data is too large to be processed.
+var ErrMessageTooLarge = errors.New("multipart: message too large")
+
 // TODO(adg,bradfitz): find a way to unify the DoS-prevention strategy here
 // with that of the http package's ParseForm.
 
 // ReadForm parses an entire multipart message whose parts have
 // 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.
+// It stores up to maxMemory bytes + 10MB (reserved for non-file parts)
+// in memory. File parts which can't be stored in memory will be stored on
+// disk in temporary files.
+// It returns ErrMessageTooLarge if all non-file parts can't be stored in
+// memory.
 func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
 	return r.readForm(maxMemory)
 }
@@ -32,7 +39,8 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
 		}
 	}()
 
-	maxValueBytes := int64(10 << 20) // 10 MB is a lot of text.
+	// Reserve an additional 10 MB for non-file parts.
+	maxValueBytes := maxMemory + int64(10<<20)
 	for {
 		p, err := r.NextPart()
 		if err == io.EOF {
@@ -52,13 +60,13 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
 
 		if filename == "" {
 			// value, store as string in memory
-			n, err := io.CopyN(&b, p, maxValueBytes)
+			n, err := io.CopyN(&b, p, maxValueBytes+1)
 			if err != nil && err != io.EOF {
 				return nil, err
 			}
 			maxValueBytes -= n
-			if maxValueBytes == 0 {
-				return nil, errors.New("multipart: message too large")
+			if maxValueBytes < 0 {
+				return nil, ErrMessageTooLarge
 			}
 			form.Value[name] = append(form.Value[name], b.String())
 			continue
@@ -79,7 +87,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
 			if err != nil {
 				return nil, err
 			}
-			_, err = io.Copy(file, io.MultiReader(&b, p))
+			size, err := io.Copy(file, io.MultiReader(&b, p))
 			if cerr := file.Close(); err == nil {
 				err = cerr
 			}
@@ -88,9 +96,12 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
 				return nil, err
 			}
 			fh.tmpfile = file.Name()
+			fh.Size = size
 		} else {
 			fh.content = b.Bytes()
+			fh.Size = int64(len(fh.content))
 			maxMemory -= n
+			maxValueBytes -= n
 		}
 		form.File[name] = append(form.File[name], fh)
 	}
@@ -128,6 +139,7 @@ func (f *Form) RemoveAll() error {
 type FileHeader struct {
 	Filename string
 	Header   textproto.MIMEHeader
+	Size     int64
 
 	content []byte
 	tmpfile string
diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
index 1deca0b..979ae5c 100644
--- a/src/mime/multipart/formdata_test.go
+++ b/src/mime/multipart/formdata_test.go
@@ -8,14 +8,12 @@ import (
 	"bytes"
 	"io"
 	"os"
-	"regexp"
 	"strings"
 	"testing"
 )
 
 func TestReadForm(t *testing.T) {
-	testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
-	b := strings.NewReader(testBody)
+	b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
 	r := NewReader(b, boundary)
 	f, err := r.ReadForm(25)
 	if err != nil {
@@ -44,6 +42,9 @@ func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
 	if fh.Filename != efn {
 		t.Errorf("filename = %q, want %q", fh.Filename, efn)
 	}
+	if fh.Size != int64(len(econtent)) {
+		t.Errorf("size = %d, want %d", fh.Size, len(econtent))
+	}
 	f, err := fh.Open()
 	if err != nil {
 		t.Fatal("opening file:", err)
@@ -124,3 +125,44 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
 	r.sawErr = err
 	return
 }
+
+// TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied
+// while processing non-file form data as well as file form data.
+func TestReadForm_NonFileMaxMemory(t *testing.T) {
+	largeTextValue := strings.Repeat("1", (10<<20)+25)
+	message := `--MyBoundary
+Content-Disposition: form-data; name="largetext"
+
+` + largeTextValue + `
+--MyBoundary--
+`
+
+	testBody := strings.Replace(message, "\n", "\r\n", -1)
+	testCases := []struct {
+		name      string
+		maxMemory int64
+		err       error
+	}{
+		{"smaller", 50, nil},
+		{"exact-fit", 25, nil},
+		{"too-large", 0, ErrMessageTooLarge},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			b := strings.NewReader(testBody)
+			r := NewReader(b, boundary)
+			f, err := r.ReadForm(tc.maxMemory)
+			if err == nil {
+				defer f.RemoveAll()
+			}
+			if tc.err != err {
+				t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err)
+			}
+			if err == nil {
+				if g := f.Value["largetext"][0]; g != largeTextValue {
+					t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue))
+				}
+			}
+		})
+	}
+}
diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go
index f82756d..3dd0c8f 100644
--- a/src/mime/multipart/writer.go
+++ b/src/mime/multipart/writer.go
@@ -41,22 +41,27 @@ func (w *Writer) Boundary() string {
 //
 // SetBoundary must be called before any parts are created, may only
 // contain certain ASCII characters, and must be non-empty and
-// at most 69 bytes long.
+// at most 70 bytes long.
 func (w *Writer) SetBoundary(boundary string) error {
 	if w.lastpart != nil {
 		return errors.New("mime: SetBoundary called after write")
 	}
 	// rfc2046#section-5.1.1
-	if len(boundary) < 1 || len(boundary) > 69 {
+	if len(boundary) < 1 || len(boundary) > 70 {
 		return errors.New("mime: invalid boundary length")
 	}
-	for _, b := range boundary {
+	end := len(boundary) - 1
+	for i, b := range boundary {
 		if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' {
 			continue
 		}
 		switch b {
 		case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?':
 			continue
+		case ' ':
+			if i != end {
+				continue
+			}
 		}
 		return errors.New("mime: invalid boundary character")
 	}
diff --git a/src/mime/multipart/writer_test.go b/src/mime/multipart/writer_test.go
index 9670c66..8b1bcd6 100644
--- a/src/mime/multipart/writer_test.go
+++ b/src/mime/multipart/writer_test.go
@@ -80,8 +80,6 @@ func TestWriter(t *testing.T) {
 }
 
 func TestWriterSetBoundary(t *testing.T) {
-	var b bytes.Buffer
-	w := NewWriter(&b)
 	tests := []struct {
 		b  string
 		ok bool
@@ -90,12 +88,16 @@ func TestWriterSetBoundary(t *testing.T) {
 		{"", false},
 		{"ungültig", false},
 		{"!", false},
-		{strings.Repeat("x", 69), true},
-		{strings.Repeat("x", 70), false},
+		{strings.Repeat("x", 70), true},
+		{strings.Repeat("x", 71), false},
 		{"bad!ascii!", false},
 		{"my-separator", true},
+		{"with space", true},
+		{"badspace ", false},
 	}
 	for i, tt := range tests {
+		var b bytes.Buffer
+		w := NewWriter(&b)
 		err := w.SetBoundary(tt.b)
 		got := err == nil
 		if got != tt.ok {
@@ -105,12 +107,13 @@ func TestWriterSetBoundary(t *testing.T) {
 			if got != tt.b {
 				t.Errorf("boundary = %q; want %q", got, tt.b)
 			}
+			w.Close()
+			wantSub := "\r\n--" + tt.b + "--\r\n"
+			if got := b.String(); !strings.Contains(got, wantSub) {
+				t.Errorf("expected %q in output. got: %q", wantSub, got)
+			}
 		}
 	}
-	w.Close()
-	if got := b.String(); !strings.Contains(got, "\r\n--my-separator--\r\n") {
-		t.Errorf("expected my-separator in output. got: %q", got)
-	}
 }
 
 func TestWriterBoundaryGoroutines(t *testing.T) {
diff --git a/src/mime/type.go b/src/mime/type.go
index d369259..78fc6b6 100644
--- a/src/mime/type.go
+++ b/src/mime/type.go
@@ -12,24 +12,48 @@ import (
 )
 
 var (
-	mimeLock       sync.RWMutex      // guards following 3 maps
-	mimeTypes      map[string]string // ".Z" => "application/x-compress"
-	mimeTypesLower map[string]string // ".z" => "application/x-compress"
+	mimeTypes      sync.Map // map[string]string; ".Z" => "application/x-compress"
+	mimeTypesLower sync.Map // map[string]string; ".z" => "application/x-compress"
 
 	// extensions maps from MIME type to list of lowercase file
 	// extensions: "image/jpeg" => [".jpg", ".jpeg"]
-	extensions map[string][]string
+	extensionsMu sync.Mutex // Guards stores (but not loads) on extensions.
+	extensions   sync.Map   // map[string][]string; slice values are append-only.
 )
 
+func clearSyncMap(m *sync.Map) {
+	m.Range(func(k, _ interface{}) bool {
+		m.Delete(k)
+		return true
+	})
+}
+
 // setMimeTypes is used by initMime's non-test path, and by tests.
-// The two maps must not be the same, or nil.
 func setMimeTypes(lowerExt, mixExt map[string]string) {
-	if lowerExt == nil || mixExt == nil {
-		panic("nil map")
+	clearSyncMap(&mimeTypes)
+	clearSyncMap(&mimeTypesLower)
+	clearSyncMap(&extensions)
+
+	for k, v := range lowerExt {
+		mimeTypesLower.Store(k, v)
+	}
+	for k, v := range mixExt {
+		mimeTypes.Store(k, v)
+	}
+
+	extensionsMu.Lock()
+	defer extensionsMu.Unlock()
+	for k, v := range lowerExt {
+		justType, _, err := ParseMediaType(v)
+		if err != nil {
+			panic(err)
+		}
+		var exts []string
+		if ei, ok := extensions.Load(k); ok {
+			exts = ei.([]string)
+		}
+		extensions.Store(justType, append(exts, k))
 	}
-	mimeTypesLower = lowerExt
-	mimeTypes = mixExt
-	extensions = invert(lowerExt)
 }
 
 var builtinTypesLower = map[string]string{
@@ -45,29 +69,6 @@ var builtinTypesLower = map[string]string{
 	".xml":  "text/xml; charset=utf-8",
 }
 
-func clone(m map[string]string) map[string]string {
-	m2 := make(map[string]string, len(m))
-	for k, v := range m {
-		m2[k] = v
-		if strings.ToLower(k) != k {
-			panic("keys in builtinTypesLower must be lowercase")
-		}
-	}
-	return m2
-}
-
-func invert(m map[string]string) map[string][]string {
-	m2 := make(map[string][]string, len(m))
-	for k, v := range m {
-		justType, _, err := ParseMediaType(v)
-		if err != nil {
-			panic(err)
-		}
-		m2[justType] = append(m2[justType], k)
-	}
-	return m2
-}
-
 var once sync.Once // guards initMime
 
 var testInitMime, osInitMime func()
@@ -76,7 +77,7 @@ func initMime() {
 	if fn := testInitMime; fn != nil {
 		fn()
 	} else {
-		setMimeTypes(builtinTypesLower, clone(builtinTypesLower))
+		setMimeTypes(builtinTypesLower, builtinTypesLower)
 		osInitMime()
 	}
 }
@@ -100,12 +101,10 @@ func initMime() {
 // Text types have the charset parameter set to "utf-8" by default.
 func TypeByExtension(ext string) string {
 	once.Do(initMime)
-	mimeLock.RLock()
-	defer mimeLock.RUnlock()
 
 	// Case-sensitive lookup.
-	if v := mimeTypes[ext]; v != "" {
-		return v
+	if v, ok := mimeTypes.Load(ext); ok {
+		return v.(string)
 	}
 
 	// Case-insensitive lookup.
@@ -118,7 +117,9 @@ func TypeByExtension(ext string) string {
 		c := ext[i]
 		if c >= utf8RuneSelf {
 			// Slow path.
-			return mimeTypesLower[strings.ToLower(ext)]
+			si, _ := mimeTypesLower.Load(strings.ToLower(ext))
+			s, _ := si.(string)
+			return s
 		}
 		if 'A' <= c && c <= 'Z' {
 			lower = append(lower, c+('a'-'A'))
@@ -126,9 +127,9 @@ func TypeByExtension(ext string) string {
 			lower = append(lower, c)
 		}
 	}
-	// The conversion from []byte to string doesn't allocate in
-	// a map lookup.
-	return mimeTypesLower[string(lower)]
+	si, _ := mimeTypesLower.Load(string(lower))
+	s, _ := si.(string)
+	return s
 }
 
 // ExtensionsByType returns the extensions known to be associated with the MIME
@@ -142,13 +143,11 @@ func ExtensionsByType(typ string) ([]string, error) {
 	}
 
 	once.Do(initMime)
-	mimeLock.RLock()
-	defer mimeLock.RUnlock()
-	s, ok := extensions[justType]
+	s, ok := extensions.Load(justType)
 	if !ok {
 		return nil, nil
 	}
-	return append([]string{}, s...), nil
+	return append([]string{}, s.([]string)...), nil
 }
 
 // AddExtensionType sets the MIME type associated with
@@ -173,15 +172,20 @@ func setExtensionType(extension, mimeType string) error {
 	}
 	extLower := strings.ToLower(extension)
 
-	mimeLock.Lock()
-	defer mimeLock.Unlock()
-	mimeTypes[extension] = mimeType
-	mimeTypesLower[extLower] = mimeType
-	for _, v := range extensions[justType] {
+	mimeTypes.Store(extension, mimeType)
+	mimeTypesLower.Store(extLower, mimeType)
+
+	extensionsMu.Lock()
+	defer extensionsMu.Unlock()
+	var exts []string
+	if ei, ok := extensions.Load(justType); ok {
+		exts = ei.([]string)
+	}
+	for _, v := range exts {
 		if v == extLower {
 			return nil
 		}
 	}
-	extensions[justType] = append(extensions[justType], extLower)
+	extensions.Store(justType, append(exts, extLower))
 	return nil
 }
diff --git a/src/mime/type_test.go b/src/mime/type_test.go
index c6c1491..e7aef9a 100644
--- a/src/mime/type_test.go
+++ b/src/mime/type_test.go
@@ -148,3 +148,43 @@ func TestLookupMallocs(t *testing.T) {
 		t.Errorf("allocs = %v; want 0", n)
 	}
 }
+
+func BenchmarkTypeByExtension(b *testing.B) {
+	initMime()
+	b.ResetTimer()
+
+	for _, ext := range []string{
+		".html",
+		".HTML",
+		".unused",
+	} {
+		b.Run(ext, func(b *testing.B) {
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					TypeByExtension(ext)
+				}
+			})
+		})
+	}
+}
+
+func BenchmarkExtensionsByType(b *testing.B) {
+	initMime()
+	b.ResetTimer()
+
+	for _, typ := range []string{
+		"text/html",
+		"text/html; charset=utf-8",
+		"application/octet-stream",
+	} {
+		b.Run(typ, func(b *testing.B) {
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					if _, err := ExtensionsByType(typ); err != nil {
+						b.Fatal(err)
+					}
+				}
+			})
+		})
+	}
+}
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 56d34b6..d5173d6 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -192,7 +192,7 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) {
 			addrs = append(addrs, addr)
 		case C.AF_INET6:
 			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-			addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneToString(int(sa.Scope_id))}
+			addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneCache.name(int(sa.Scope_id))}
 			addrs = append(addrs, addr)
 		}
 	}
@@ -317,7 +317,7 @@ func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) {
 		return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4)
 	}
 	if ip6 := ip.To16(); ip6 != nil {
-		return cgoSockaddrInet6(ip6, zoneToInt(zone)), C.socklen_t(syscall.SizeofSockaddrInet6)
+		return cgoSockaddrInet6(ip6, zoneCache.index(zone)), C.socklen_t(syscall.SizeofSockaddrInet6)
 	}
 	return nil, 0
 }
diff --git a/src/net/dial.go b/src/net/dial.go
index 50bba5a..631ca44 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -7,6 +7,7 @@ package net
 import (
 	"context"
 	"internal/nettrace"
+	"internal/poll"
 	"time"
 )
 
@@ -110,7 +111,7 @@ func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, er
 	}
 	timeRemaining := deadline.Sub(now)
 	if timeRemaining <= 0 {
-		return time.Time{}, errTimeout
+		return time.Time{}, poll.ErrTimeout
 	}
 	// Tentatively allocate equal time to each remaining address.
 	timeout := timeRemaining / time.Duration(addrsRemaining)
@@ -134,23 +135,26 @@ func (d *Dialer) fallbackDelay() time.Duration {
 	}
 }
 
-func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err error) {
-	i := last(net, ':')
+func parseNetwork(ctx context.Context, network string, needsProto bool) (afnet string, proto int, err error) {
+	i := last(network, ':')
 	if i < 0 { // no colon
-		switch net {
+		switch network {
 		case "tcp", "tcp4", "tcp6":
 		case "udp", "udp4", "udp6":
 		case "ip", "ip4", "ip6":
+			if needsProto {
+				return "", 0, UnknownNetworkError(network)
+			}
 		case "unix", "unixgram", "unixpacket":
 		default:
-			return "", 0, UnknownNetworkError(net)
+			return "", 0, UnknownNetworkError(network)
 		}
-		return net, 0, nil
+		return network, 0, nil
 	}
-	afnet = net[:i]
+	afnet = network[:i]
 	switch afnet {
 	case "ip", "ip4", "ip6":
-		protostr := net[i+1:]
+		protostr := network[i+1:]
 		proto, i, ok := dtoi(protostr)
 		if !ok || i != len(protostr) {
 			proto, err = lookupProtocol(ctx, protostr)
@@ -160,14 +164,14 @@ func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err
 		}
 		return afnet, proto, nil
 	}
-	return "", 0, UnknownNetworkError(net)
+	return "", 0, UnknownNetworkError(network)
 }
 
 // resolveAddrList resolves addr using hint and returns a list of
 // addresses. The result contains at least one address when error is
 // nil.
 func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
-	afnet, _, err := parseNetwork(ctx, network)
+	afnet, _, err := parseNetwork(ctx, network, true)
 	if err != nil {
 		return nil, err
 	}
@@ -538,12 +542,18 @@ func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error)
 }
 
 // Listen announces on the local network address laddr.
+//
 // The network net must be a stream-oriented network: "tcp", "tcp4",
 // "tcp6", "unix" or "unixpacket".
-// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
+//
+// For TCP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
 // If host is omitted, as in ":8080", Listen listens on all available interfaces
 // instead of just the interface with the given host address.
-// See Dial for more details about address syntax.
+// Listening on network "tcp" with host "0.0.0.0" or "[::]" may listen on both
+// IPv4 and IPv6. To only use IPv4, use network "tcp4". To explicitly use both,
+// listen on ":port" without a host.
+//
+// See Dial for more details about the address syntax.
 //
 // Listening on a hostname is not recommended because this creates a socket
 // for at most one of its IP addresses.
@@ -568,12 +578,18 @@ func Listen(net, laddr string) (Listener, error) {
 }
 
 // ListenPacket announces on the local network address laddr.
+//
 // The network net must be a packet-oriented network: "udp", "udp4",
 // "udp6", "ip", "ip4", "ip6" or "unixgram".
-// For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
-// If host is omitted, as in ":8080", ListenPacket listens on all available interfaces
-// instead of just the interface with the given host address.
-// See Dial for the syntax of laddr.
+//
+// For UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080".
+// If host is omitted, as in ":8080", ListenPacket listens on all available
+// interfaces instead of just the interface with the given host address.
+// Listening on network "udp" with host "0.0.0.0" or "[::]" may listen on both
+// IPv4 and IPv6. To only use IPv4, use network "udp4". To explicitly use both,
+// listen on ":port" without a host.
+//
+// See Dial for more details about the address syntax.
 //
 // Listening on a hostname is not recommended because this creates a socket
 // for at most one of its IP addresses.
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 9919d72..a892bf1 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -7,9 +7,9 @@ package net
 import (
 	"bufio"
 	"context"
+	"internal/poll"
 	"internal/testenv"
 	"io"
-	"net/internal/socktest"
 	"runtime"
 	"sync"
 	"testing"
@@ -31,7 +31,7 @@ func TestProhibitionaryDialArg(t *testing.T) {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	if !supportsIPv4map {
+	if !supportsIPv4map() {
 		t.Skip("mapping ipv4 address inside ipv6 address not supported")
 	}
 
@@ -72,70 +72,6 @@ func TestDialLocal(t *testing.T) {
 	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
-
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		origTestHookDialChannel := testHookDialChannel
-		testHookDialChannel = func() { time.Sleep(2 * T) }
-		defer func() { testHookDialChannel = origTestHookDialChannel }()
-		if runtime.GOOS == "plan9" {
-			break
-		}
-		fallthrough
-	default:
-		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
-			time.Sleep(2 * T)
-			return nil, errTimeout
-		})
-		defer sw.Set(socktest.FilterConnect, nil)
-	}
-
-	// Avoid tracking open-close jitterbugs between netFD and
-	// socket that leads to confusion of information inside
-	// socktest.Switch.
-	// It may happen when the Dial call bumps against TCP
-	// simultaneous open. See selfConnect in tcpsock_posix.go.
-	defer func() { sw.Set(socktest.FilterClose, nil) }()
-	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, nil
-	})
-
-	const N = 100
-	var wg sync.WaitGroup
-	wg.Add(N)
-	for i := 0; i < N; i++ {
-		go func() {
-			defer wg.Done()
-			// This dial never starts to send any SYN
-			// segment because of above socket filter and
-			// test hook.
-			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
-			if err == nil {
-				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
-				c.Close()
-			}
-		}()
-	}
-	wg.Wait()
-	if attempts < N {
-		t.Errorf("got %d; want >= %d", attempts, N)
-	}
-}
-
 func TestDialerDualStackFDLeak(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
@@ -145,7 +81,7 @@ func TestDialerDualStackFDLeak(t *testing.T) {
 	case "openbsd":
 		testenv.SkipFlaky(t, 15157)
 	}
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -254,7 +190,7 @@ func dialClosedPort() (actual, expected time.Duration) {
 func TestDialParallel(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -425,7 +361,7 @@ func lookupSlowFast(ctx context.Context, fn func(context.Context, string) ([]IPA
 func TestDialerFallbackDelay(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -491,7 +427,7 @@ func TestDialerFallbackDelay(t *testing.T) {
 }
 
 func TestDialParallelSpuriousConnection(t *testing.T) {
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -585,22 +521,22 @@ func TestDialerPartialDeadline(t *testing.T) {
 		{now, noDeadline, 1, noDeadline, nil},
 		// Step the clock forward and cross the deadline.
 		{now.Add(-1 * time.Millisecond), now, 1, now, nil},
-		{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
-		{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
+		{now.Add(0 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
+		{now.Add(1 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
 	}
 	for i, tt := range testCases {
 		deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
 		if err != tt.expectErr {
 			t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
 		}
-		if deadline != tt.expectDeadline {
+		if !deadline.Equal(tt.expectDeadline) {
 			t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
 		}
 	}
 }
 
 func TestDialerLocalAddr(t *testing.T) {
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -654,7 +590,7 @@ func TestDialerLocalAddr(t *testing.T) {
 		{"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
 	}
 
-	if supportsIPv4map {
+	if supportsIPv4map() {
 		tests = append(tests, test{
 			"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
 		})
@@ -714,12 +650,9 @@ func TestDialerLocalAddr(t *testing.T) {
 }
 
 func TestDialerDualStack(t *testing.T) {
-	// This test is known to be flaky. Don't frighten regular
-	// users about it; only fail on the build dashboard.
-	if testenv.Builder() == "" {
-		testenv.SkipFlaky(t, 13324)
-	}
-	if !supportsIPv4 || !supportsIPv6 {
+	testenv.SkipFlaky(t, 13324)
+
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -822,7 +755,7 @@ func TestDialCancel(t *testing.T) {
 	}
 
 	blackholeIPPort := JoinHostPort(slowDst4, "1234")
-	if !supportsIPv4 {
+	if !supportsIPv4() {
 		blackholeIPPort = JoinHostPort(slowDst6, "1234")
 	}
 
@@ -954,3 +887,24 @@ func TestCancelAfterDial(t *testing.T) {
 		try()
 	}
 }
+
+// Issue 18806: it should always be possible to net.Dial a
+// net.Listener().Addr().String when the listen address was ":n", even
+// if the machine has halfway configured IPv6 such that it can bind on
+// "::" not connect back to that same address.
+func TestDialListenerAddr(t *testing.T) {
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
+	}
+	ln, err := Listen("tcp", ":0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+	addr := ln.Addr().String()
+	c, err := Dial("tcp", addr)
+	if err != nil {
+		t.Fatalf("for addr %q, dial error: %v", addr, err)
+	}
+	c.Close()
+}
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 4dd4e16..acbf6c3 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -25,13 +25,6 @@ import (
 	"time"
 )
 
-// A dnsDialer provides dialing suitable for DNS queries.
-type dnsDialer interface {
-	dialDNS(ctx context.Context, network, addr string) (dnsConn, error)
-}
-
-var testHookDNSDialer = func() dnsDialer { return &Dialer{} }
-
 // A dnsConn represents a DNS transport endpoint.
 type dnsConn interface {
 	io.Closer
@@ -43,14 +36,14 @@ type dnsConn interface {
 	dnsRoundTrip(query *dnsMsg) (*dnsMsg, error)
 }
 
-func (c *UDPConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) {
-	return dnsRoundTripUDP(c, query)
+// dnsPacketConn implements the dnsConn interface for RFC 1035's
+// "UDP usage" transport mechanism. Conn is a packet-oriented connection,
+// such as a *UDPConn.
+type dnsPacketConn struct {
+	Conn
 }
 
-// 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) {
+func (c *dnsPacketConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) {
 	b, ok := query.Pack()
 	if !ok {
 		return nil, errors.New("cannot marshal DNS message")
@@ -76,14 +69,14 @@ func dnsRoundTripUDP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
 	}
 }
 
-func (c *TCPConn) dnsRoundTrip(out *dnsMsg) (*dnsMsg, error) {
-	return dnsRoundTripTCP(c, out)
+// dnsStreamConn implements the dnsConn interface for RFC 1035's
+// "TCP usage" transport mechanism. Conn is a stream-oriented connection,
+// such as a *TCPConn.
+type dnsStreamConn struct {
+	Conn
 }
 
-// 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) {
+func (c *dnsStreamConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) {
 	b, ok := query.Pack()
 	if !ok {
 		return nil, errors.New("cannot marshal DNS message")
@@ -116,33 +109,8 @@ func dnsRoundTripTCP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
 	return resp, nil
 }
 
-func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, error) {
-	switch network {
-	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
-	default:
-		return nil, UnknownNetworkError(network)
-	}
-	// Calling Dial here is scary -- we have to be sure not to
-	// dial a name that will require a DNS lookup, or Dial will
-	// call back here to translate it. The DNS config parser has
-	// already checked that all the cfg.servers are IP
-	// addresses, which Dial will use without a DNS lookup.
-	c, err := d.DialContext(ctx, network, server)
-	if err != nil {
-		return nil, mapErr(err)
-	}
-	switch network {
-	case "tcp", "tcp4", "tcp6":
-		return c.(*TCPConn), nil
-	case "udp", "udp4", "udp6":
-		return c.(*UDPConn), nil
-	}
-	panic("unreachable")
-}
-
 // exchange sends a query on the connection and hopes for a response.
-func exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
-	d := testHookDNSDialer()
+func (r *Resolver) exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
 	out := dnsMsg{
 		dnsMsgHdr: dnsMsgHdr{
 			recursion_desired: true,
@@ -158,7 +126,7 @@ func exchange(ctx context.Context, server, name string, qtype uint16, timeout ti
 		ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
 		defer cancel()
 
-		c, err := d.dialDNS(ctx, network, server)
+		c, err := r.dial(ctx, network, server)
 		if err != nil {
 			return nil, err
 		}
@@ -181,7 +149,7 @@ func exchange(ctx context.Context, server, name string, qtype uint16, timeout ti
 
 // Do a lookup for a single name, which must be rooted
 // (otherwise answer will not find the answers).
-func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
+func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
 	var lastErr error
 	serverOffset := cfg.serverOffset()
 	sLen := uint32(len(cfg.servers))
@@ -190,7 +158,7 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16)
 		for j := uint32(0); j < sLen; j++ {
 			server := cfg.servers[(serverOffset+j)%sLen]
 
-			msg, err := exchange(ctx, server, name, qtype, cfg.timeout)
+			msg, err := r.exchange(ctx, server, name, qtype, cfg.timeout)
 			if err != nil {
 				lastErr = &DNSError{
 					Err:    err.Error(),
@@ -200,6 +168,11 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16)
 				if nerr, ok := err.(Error); ok && nerr.Timeout() {
 					lastErr.(*DNSError).IsTimeout = true
 				}
+				// Set IsTemporary for socket-level errors. Note that this flag
+				// may also be used to indicate a SERVFAIL response.
+				if _, ok := err.(*OpError); ok {
+					lastErr.(*DNSError).IsTemporary = true
+				}
 				continue
 			}
 			// libresolv continues to the next server when it receives
@@ -314,7 +287,7 @@ func (conf *resolverConfig) releaseSema() {
 	<-conf.ch
 }
 
-func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
+func (r *Resolver) lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 	if !isDomainName(name) {
 		// We used to use "invalid domain name" as the error,
 		// but that is a detail of the specific lookup mechanism.
@@ -328,10 +301,15 @@ func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs [
 	conf := resolvConf.dnsConfig
 	resolvConf.mu.RUnlock()
 	for _, fqdn := range conf.nameList(name) {
-		cname, rrs, err = tryOneName(ctx, conf, fqdn, qtype)
+		cname, rrs, err = r.tryOneName(ctx, conf, fqdn, qtype)
 		if err == nil {
 			break
 		}
+		if nerr, ok := err.(Error); ok && nerr.Temporary() && r.StrictErrors {
+			// If we hit a temporary error with StrictErrors enabled,
+			// stop immediately instead of trying more names.
+			break
+		}
 	}
 	if err, ok := err.(*DNSError); ok {
 		// Show original name passed to lookup, not suffixed one.
@@ -432,11 +410,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(ctx context.Context, name string) (addrs []string, err error) {
-	return goLookupHostOrder(ctx, name, hostLookupFilesDNS)
+func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
+	return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS)
 }
 
-func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
+func (r *Resolver) 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)
@@ -444,7 +422,7 @@ func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder)
 			return
 		}
 	}
-	ips, _, err := goLookupIPCNAMEOrder(ctx, name, order)
+	ips, _, err := r.goLookupIPCNAMEOrder(ctx, name, order)
 	if err != nil {
 		return
 	}
@@ -470,13 +448,13 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
 
 // goLookupIP is the native Go implementation of LookupIP.
 // The libc versions are in cgo_*.go.
-func goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+func (r *Resolver) goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
 	order := systemConf().hostLookupOrder(host)
-	addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+	addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order)
 	return
 }
 
-func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) {
+func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) {
 	if order == hostLookupFilesDNS || order == hostLookupFiles {
 		addrs = goLookupIPFiles(name)
 		if len(addrs) > 0 || order == hostLookupFiles {
@@ -502,15 +480,20 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde
 	for _, fqdn := range conf.nameList(name) {
 		for _, qtype := range qtypes {
 			go func(qtype uint16) {
-				cname, rrs, err := tryOneName(ctx, conf, fqdn, qtype)
+				cname, rrs, err := r.tryOneName(ctx, conf, fqdn, qtype)
 				lane <- racer{cname, rrs, err}
 			}(qtype)
 		}
+		hitStrictError := false
 		for range qtypes {
 			racer := <-lane
 			if racer.error != nil {
-				// Prefer error for original name.
-				if lastErr == nil || fqdn == name+"." {
+				if nerr, ok := racer.error.(Error); ok && nerr.Temporary() && r.StrictErrors {
+					// This error will abort the nameList loop.
+					hitStrictError = true
+					lastErr = racer.error
+				} else if lastErr == nil || fqdn == name+"." {
+					// Prefer error for original name.
 					lastErr = racer.error
 				}
 				continue
@@ -520,6 +503,13 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde
 				cname = racer.cname
 			}
 		}
+		if hitStrictError {
+			// If either family hit an error with StrictErrors enabled,
+			// discard all addresses. This ensures that network flakiness
+			// cannot turn a dualstack hostname IPv4/IPv6-only.
+			addrs = nil
+			break
+		}
 		if len(addrs) > 0 {
 			break
 		}
@@ -543,9 +533,9 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde
 }
 
 // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
-func goLookupCNAME(ctx context.Context, host string) (cname string, err error) {
+func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (cname string, err error) {
 	order := systemConf().hostLookupOrder(host)
-	_, cname, err = goLookupIPCNAMEOrder(ctx, host, order)
+	_, cname, err = r.goLookupIPCNAMEOrder(ctx, host, order)
 	return
 }
 
@@ -554,7 +544,7 @@ func goLookupCNAME(ctx context.Context, host 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(ctx context.Context, addr string) ([]string, error) {
+func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) {
 	names := lookupStaticAddr(addr)
 	if len(names) > 0 {
 		return names, nil
@@ -563,7 +553,7 @@ func goLookupPTR(ctx context.Context, addr string) ([]string, error) {
 	if err != nil {
 		return nil, err
 	}
-	_, rrs, err := lookup(ctx, arpa, dnsTypePTR)
+	_, rrs, err := r.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 85267bb..73b628c 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -8,8 +8,9 @@ package net
 
 import (
 	"context"
+	"errors"
 	"fmt"
-	"internal/testenv"
+	"internal/poll"
 	"io/ioutil"
 	"os"
 	"path"
@@ -20,9 +21,14 @@ import (
 	"time"
 )
 
+var goResolver = Resolver{PreferGo: true}
+
 // Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
 const TestAddr uint32 = 0xc0000201
 
+// Test address from 2001:db8::/32 block, reserved by RFC 3849 for documentation.
+var TestAddr6 = [16]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+
 var dnsTransportFallbackTests = []struct {
 	server  string
 	name    string
@@ -37,18 +43,33 @@ var dnsTransportFallbackTests = []struct {
 }
 
 func TestDNSTransportFallback(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
+	fake := fakeDNSServer{
+		rh: func(n, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+			r := &dnsMsg{
+				dnsMsgHdr: dnsMsgHdr{
+					id:       q.id,
+					response: true,
+					rcode:    dnsRcodeSuccess,
+				},
+				question: q.question,
+			}
+			if n == "udp" {
+				r.truncated = true
+			}
+			return r, nil
+		},
+	}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 	for _, tt := range dnsTransportFallbackTests {
 		ctx, cancel := context.WithCancel(context.Background())
 		defer cancel()
-		msg, err := exchange(ctx, tt.server, tt.name, tt.qtype, time.Second)
+		msg, err := r.exchange(ctx, tt.server, tt.name, tt.qtype, time.Second)
 		if err != nil {
 			t.Error(err)
 			continue
 		}
 		switch msg.rcode {
-		case tt.rcode, dnsRcodeServerFailure:
+		case tt.rcode:
 		default:
 			t.Errorf("got %v from %v; want %v", msg.rcode, tt.server, tt.rcode)
 			continue
@@ -78,13 +99,30 @@ var specialDomainNameTests = []struct {
 }
 
 func TestSpecialDomainName(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
+	fake := fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+		r := &dnsMsg{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       q.id,
+				response: true,
+			},
+			question: q.question,
+		}
+
+		switch q.question[0].Name {
+		case "example.com.":
+			r.rcode = dnsRcodeSuccess
+		default:
+			r.rcode = dnsRcodeNameError
+		}
 
+		return r, nil
+	}}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 	server := "8.8.8.8:53"
 	for _, tt := range specialDomainNameTests {
 		ctx, cancel := context.WithCancel(context.Background())
 		defer cancel()
-		msg, err := exchange(ctx, server, tt.name, tt.qtype, 3*time.Second)
+		msg, err := r.exchange(ctx, server, tt.name, tt.qtype, 3*time.Second)
 		if err != nil {
 			t.Error(err)
 			continue
@@ -139,15 +177,40 @@ func TestAvoidDNSName(t *testing.T) {
 	}
 }
 
+var fakeDNSServerSuccessful = fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+	r := &dnsMsg{
+		dnsMsgHdr: dnsMsgHdr{
+			id:       q.id,
+			response: true,
+		},
+		question: q.question,
+	}
+	if len(q.question) == 1 && 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
+}}
+
 // 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)
-	}
+	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
+	addrs, err := r.LookupIPAddr(context.Background(), "foo.onion")
 	if err != nil {
 		t.Fatalf("lookup = %v; want nil", err)
 	}
+	if len(addrs) > 0 {
+		t.Errorf("unexpected addresses: %v", addrs)
+	}
 }
 
 type resolvConfTest struct {
@@ -237,7 +300,7 @@ var updateResolvConfTests = []struct {
 }
 
 func TestUpdateResolvConf(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
+	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
 
 	conf, err := newResolvConfTest()
 	if err != nil {
@@ -257,7 +320,7 @@ func TestUpdateResolvConf(t *testing.T) {
 			for j := 0; j < N; j++ {
 				go func(name string) {
 					defer wg.Done()
-					ips, err := goLookupIP(context.Background(), name)
+					ips, err := r.LookupIPAddr(context.Background(), name)
 					if err != nil {
 						t.Error(err)
 						return
@@ -392,7 +455,60 @@ var goLookupIPWithResolverConfigTests = []struct {
 }
 
 func TestGoLookupIPWithResolverConfig(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
+	fake := fakeDNSServer{func(n, s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+		switch s {
+		case "[2001:4860:4860::8888]:53", "8.8.8.8:53":
+			break
+		default:
+			time.Sleep(10 * time.Millisecond)
+			return nil, poll.ErrTimeout
+		}
+		r := &dnsMsg{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       q.id,
+				response: true,
+			},
+			question: q.question,
+		}
+		for _, question := range q.question {
+			switch question.Qtype {
+			case dnsTypeA:
+				switch question.Name {
+				case "hostname.as112.net.":
+					break
+				case "ipv4.google.com.":
+					r.answer = append(r.answer, &dnsRR_A{
+						Hdr: dnsRR_Header{
+							Name:     q.question[0].Name,
+							Rrtype:   dnsTypeA,
+							Class:    dnsClassINET,
+							Rdlength: 4,
+						},
+						A: TestAddr,
+					})
+				default:
+
+				}
+			case dnsTypeAAAA:
+				switch question.Name {
+				case "hostname.as112.net.":
+					break
+				case "ipv6.google.com.":
+					r.answer = append(r.answer, &dnsRR_AAAA{
+						Hdr: dnsRR_Header{
+							Name:     q.question[0].Name,
+							Rrtype:   dnsTypeAAAA,
+							Class:    dnsClassINET,
+							Rdlength: 16,
+						},
+						AAAA: TestAddr6,
+					})
+				}
+			}
+		}
+		return r, nil
+	}}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 
 	conf, err := newResolvConfTest()
 	if err != nil {
@@ -405,14 +521,8 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
 			t.Error(err)
 			continue
 		}
-		addrs, err := goLookupIP(context.Background(), tt.name)
+		addrs, err := r.LookupIPAddr(context.Background(), tt.name)
 		if err != nil {
-			// 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 connectivity 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)
 			}
@@ -437,7 +547,17 @@ 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) {
-	testenv.MustHaveExternalNetwork(t)
+	fake := fakeDNSServer{func(n, s string, q *dnsMsg, tm time.Time) (*dnsMsg, error) {
+		r := &dnsMsg{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       q.id,
+				response: true,
+			},
+			question: q.question,
+		}
+		return r, nil
+	}}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 
 	// Add a config that simulates no dns servers being available.
 	conf, err := newResolvConfTest()
@@ -455,14 +575,14 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
 		name := fmt.Sprintf("order %v", order)
 
 		// First ensure that we get an error when contacting a non-existent host.
-		_, _, err := goLookupIPCNAMEOrder(context.Background(), "notarealhost", order)
+		_, _, err := r.goLookupIPCNAMEOrder(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 := goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
+		addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
 		if err != nil {
 			t.Errorf("%s: expected to successfully lookup host entry", name)
 			continue
@@ -485,9 +605,6 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
 func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 	const fqdn = "doesnotexist.domain"
 
-	origTestHookDNSDialer := testHookDNSDialer
-	defer func() { testHookDNSDialer = origTestHookDNSDialer }()
-
 	conf, err := newResolvConfTest()
 	if err != nil {
 		t.Fatal(err)
@@ -498,14 +615,13 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	d := &fakeDNSDialer{}
-	testHookDNSDialer = func() dnsDialer { return d }
-
-	d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+	fake := fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
 		r := &dnsMsg{
 			dnsMsgHdr: dnsMsgHdr{
-				id: q.id,
+				id:       q.id,
+				response: true,
 			},
+			question: q.question,
 		}
 
 		switch q.question[0].Name {
@@ -516,24 +632,31 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 		}
 
 		return r, nil
-	}
+	}}
 
-	_, err = goLookupIP(context.Background(), fqdn)
-	if err == nil {
-		t.Fatal("expected an error")
+	cases := []struct {
+		strictErrors bool
+		wantErr      *DNSError
+	}{
+		{true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}},
+		{false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error()}},
 	}
+	for _, tt := range cases {
+		r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext}
+		_, err = r.LookupIPAddr(context.Background(), fqdn)
+		if err == nil {
+			t.Fatal("expected an error")
+		}
 
-	want := &DNSError{Name: fqdn, Err: errNoSuchHost.Error()}
-	if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err {
-		t.Errorf("got %v; want %v", err, want)
+		want := tt.wantErr
+		if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err || err.IsTemporary != want.IsTemporary {
+			t.Errorf("got %v; want %v", err, want)
+		}
 	}
 }
 
 // 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)
@@ -545,10 +668,7 @@ func TestIgnoreLameReferrals(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	d := &fakeDNSDialer{}
-	testHookDNSDialer = func() dnsDialer { return d }
-
-	d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+	fake := fakeDNSServer{func(_, s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
 		t.Log(s, q)
 		r := &dnsMsg{
 			dnsMsgHdr: dnsMsgHdr{
@@ -576,9 +696,10 @@ func TestIgnoreLameReferrals(t *testing.T) {
 		}
 
 		return r, nil
-	}
+	}}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 
-	addrs, err := goLookupIP(context.Background(), "www.golang.org")
+	addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -597,7 +718,7 @@ func BenchmarkGoLookupIP(b *testing.B) {
 	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP(ctx, "www.example.com")
+		goResolver.LookupIPAddr(ctx, "www.example.com")
 	}
 }
 
@@ -606,7 +727,7 @@ func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
 	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP(ctx, "some.nonexistent")
+		goResolver.LookupIPAddr(ctx, "some.nonexistent")
 	}
 }
 
@@ -629,38 +750,70 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
 	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP(ctx, "www.example.com")
+		goResolver.LookupIPAddr(ctx, "www.example.com")
 	}
 }
 
-type fakeDNSDialer struct {
-	// reply handler
-	rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
+type fakeDNSServer struct {
+	rh func(n, s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
 }
 
-func (f *fakeDNSDialer) dialDNS(_ context.Context, n, s string) (dnsConn, error) {
-	return &fakeDNSConn{f.rh, s, time.Time{}}, nil
+func (server *fakeDNSServer) DialContext(_ context.Context, n, s string) (Conn, error) {
+	return &fakeDNSConn{nil, server, n, s, nil, time.Time{}}, nil
 }
 
 type fakeDNSConn struct {
-	rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
-	s  string
-	t  time.Time
+	Conn
+	server *fakeDNSServer
+	n      string
+	s      string
+	q      *dnsMsg
+	t      time.Time
 }
 
 func (f *fakeDNSConn) Close() error {
 	return nil
 }
 
+func (f *fakeDNSConn) Read(b []byte) (int, error) {
+	resp, err := f.server.rh(f.n, f.s, f.q, f.t)
+	if err != nil {
+		return 0, err
+	}
+
+	bb, ok := resp.Pack()
+	if !ok {
+		return 0, errors.New("cannot marshal DNS message")
+	}
+	if len(b) < len(bb) {
+		return 0, errors.New("read would fragment DNS message")
+	}
+
+	copy(b, bb)
+	return len(bb), nil
+}
+
+func (f *fakeDNSConn) ReadFrom(b []byte) (int, Addr, error) {
+	return 0, nil, nil
+}
+
+func (f *fakeDNSConn) Write(b []byte) (int, error) {
+	f.q = new(dnsMsg)
+	if !f.q.Unpack(b) {
+		return 0, errors.New("cannot unmarshal DNS message")
+	}
+	return len(b), nil
+}
+
+func (f *fakeDNSConn) WriteTo(b []byte, addr Addr) (int, error) {
+	return 0, nil
+}
+
 func (f *fakeDNSConn) SetDeadline(t time.Time) error {
 	f.t = t
 	return nil
 }
 
-func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) {
-	return f.rh(f.s, q, f.t)
-}
-
 // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
 func TestIgnoreDNSForgeries(t *testing.T) {
 	c, s := Pipe()
@@ -723,7 +876,8 @@ func TestIgnoreDNSForgeries(t *testing.T) {
 		},
 	}
 
-	resp, err := dnsRoundTripUDP(c, msg)
+	dc := &dnsPacketConn{c}
+	resp, err := dc.dnsRoundTrip(msg)
 	if err != nil {
 		t.Fatalf("dnsRoundTripUDP failed: %v", err)
 	}
@@ -735,9 +889,6 @@ func TestIgnoreDNSForgeries(t *testing.T) {
 
 // Issue 16865. If a name server times out, continue to the next.
 func TestRetryTimeout(t *testing.T) {
-	origTestHookDNSDialer := testHookDNSDialer
-	defer func() { testHookDNSDialer = origTestHookDNSDialer }()
-
 	conf, err := newResolvConfTest()
 	if err != nil {
 		t.Fatal(err)
@@ -752,12 +903,9 @@ func TestRetryTimeout(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	d := &fakeDNSDialer{}
-	testHookDNSDialer = func() dnsDialer { return d }
-
 	var deadline0 time.Time
 
-	d.rh = func(s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
+	fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
 		t.Log(s, q, deadline)
 
 		if deadline.IsZero() {
@@ -767,17 +915,18 @@ func TestRetryTimeout(t *testing.T) {
 		if s == "192.0.2.1:53" {
 			deadline0 = deadline
 			time.Sleep(10 * time.Millisecond)
-			return nil, errTimeout
+			return nil, poll.ErrTimeout
 		}
 
-		if deadline == deadline0 {
+		if deadline.Equal(deadline0) {
 			t.Error("deadline didn't change")
 		}
 
 		return mockTXTResponse(q), nil
-	}
+	}}
+	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
 
-	_, err = LookupTXT("www.golang.org")
+	_, err = r.LookupTXT(context.Background(), "www.golang.org")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -796,9 +945,6 @@ func TestRotate(t *testing.T) {
 }
 
 func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
-	origTestHookDNSDialer := testHookDNSDialer
-	defer func() { testHookDNSDialer = origTestHookDNSDialer }()
-
 	conf, err := newResolvConfTest()
 	if err != nil {
 		t.Fatal(err)
@@ -817,18 +963,16 @@ func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
 		t.Fatal(err)
 	}
 
-	d := &fakeDNSDialer{}
-	testHookDNSDialer = func() dnsDialer { return d }
-
 	var usedServers []string
-	d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+	fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
 		usedServers = append(usedServers, s)
 		return mockTXTResponse(q), nil
-	}
+	}}
+	r := Resolver{PreferGo: true, Dial: fake.DialContext}
 
 	// len(nameservers) + 1 to allow rotation to get back to start
 	for i := 0; i < len(nameservers)+1; i++ {
-		if _, err := LookupTXT("www.golang.org"); err != nil {
+		if _, err := r.LookupTXT(context.Background(), "www.golang.org"); err != nil {
 			t.Fatal(err)
 		}
 	}
@@ -860,3 +1004,311 @@ func mockTXTResponse(q *dnsMsg) *dnsMsg {
 
 	return r
 }
+
+// Issue 17448. With StrictErrors enabled, temporary errors should make
+// LookupIP fail rather than return a partial result.
+func TestStrictErrorsLookupIP(t *testing.T) {
+	conf, err := newResolvConfTest()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conf.teardown()
+
+	confData := []string{
+		"nameserver 192.0.2.53",
+		"search x.golang.org y.golang.org",
+	}
+	if err := conf.writeAndUpdate(confData); err != nil {
+		t.Fatal(err)
+	}
+
+	const name = "test-issue19592"
+	const server = "192.0.2.53:53"
+	const searchX = "test-issue19592.x.golang.org."
+	const searchY = "test-issue19592.y.golang.org."
+	const ip4 = "192.0.2.1"
+	const ip6 = "2001:db8::1"
+
+	type resolveWhichEnum int
+	const (
+		resolveOK resolveWhichEnum = iota
+		resolveOpError
+		resolveServfail
+		resolveTimeout
+	)
+
+	makeTempError := func(err string) error {
+		return &DNSError{
+			Err:         err,
+			Name:        name,
+			Server:      server,
+			IsTemporary: true,
+		}
+	}
+	makeTimeout := func() error {
+		return &DNSError{
+			Err:       poll.ErrTimeout.Error(),
+			Name:      name,
+			Server:    server,
+			IsTimeout: true,
+		}
+	}
+	makeNxDomain := func() error {
+		return &DNSError{
+			Err:    errNoSuchHost.Error(),
+			Name:   name,
+			Server: server,
+		}
+	}
+
+	cases := []struct {
+		desc          string
+		resolveWhich  func(quest *dnsQuestion) resolveWhichEnum
+		wantStrictErr error
+		wantLaxErr    error
+		wantIPs       []string
+	}{
+		{
+			desc: "No errors",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				return resolveOK
+			},
+			wantIPs: []string{ip4, ip6},
+		},
+		{
+			desc: "searchX error fails in strict mode",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchX {
+					return resolveTimeout
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTimeout(),
+			wantIPs:       []string{ip4, ip6},
+		},
+		{
+			desc: "searchX IPv4-only timeout fails in strict mode",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchX && quest.Qtype == dnsTypeA {
+					return resolveTimeout
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTimeout(),
+			wantIPs:       []string{ip4, ip6},
+		},
+		{
+			desc: "searchX IPv6-only servfail fails in strict mode",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchX && quest.Qtype == dnsTypeAAAA {
+					return resolveServfail
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTempError("server misbehaving"),
+			wantIPs:       []string{ip4, ip6},
+		},
+		{
+			desc: "searchY error always fails",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchY {
+					return resolveTimeout
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTimeout(),
+			wantLaxErr:    makeNxDomain(), // This one reaches the "test." FQDN.
+		},
+		{
+			desc: "searchY IPv4-only socket error fails in strict mode",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchY && quest.Qtype == dnsTypeA {
+					return resolveOpError
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTempError("write: socket on fire"),
+			wantIPs:       []string{ip6},
+		},
+		{
+			desc: "searchY IPv6-only timeout fails in strict mode",
+			resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
+				if quest.Name == searchY && quest.Qtype == dnsTypeAAAA {
+					return resolveTimeout
+				}
+				return resolveOK
+			},
+			wantStrictErr: makeTimeout(),
+			wantIPs:       []string{ip4},
+		},
+	}
+
+	for i, tt := range cases {
+		fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
+			t.Log(s, q)
+
+			switch tt.resolveWhich(&q.question[0]) {
+			case resolveOK:
+				// Handle below.
+			case resolveOpError:
+				return nil, &OpError{Op: "write", Err: fmt.Errorf("socket on fire")}
+			case resolveServfail:
+				return &dnsMsg{
+					dnsMsgHdr: dnsMsgHdr{
+						id:       q.id,
+						response: true,
+						rcode:    dnsRcodeServerFailure,
+					},
+					question: q.question,
+				}, nil
+			case resolveTimeout:
+				return nil, poll.ErrTimeout
+			default:
+				t.Fatal("Impossible resolveWhich")
+			}
+
+			switch q.question[0].Name {
+			case searchX, name + ".":
+				// Return NXDOMAIN to utilize the search list.
+				return &dnsMsg{
+					dnsMsgHdr: dnsMsgHdr{
+						id:       q.id,
+						response: true,
+						rcode:    dnsRcodeNameError,
+					},
+					question: q.question,
+				}, nil
+			case searchY:
+				// Return records below.
+			default:
+				return nil, fmt.Errorf("Unexpected Name: %v", q.question[0].Name)
+			}
+
+			r := &dnsMsg{
+				dnsMsgHdr: dnsMsgHdr{
+					id:       q.id,
+					response: true,
+				},
+				question: q.question,
+			}
+			switch q.question[0].Qtype {
+			case dnsTypeA:
+				r.answer = []dnsRR{
+					&dnsRR_A{
+						Hdr: dnsRR_Header{
+							Name:     q.question[0].Name,
+							Rrtype:   dnsTypeA,
+							Class:    dnsClassINET,
+							Rdlength: 4,
+						},
+						A: TestAddr,
+					},
+				}
+			case dnsTypeAAAA:
+				r.answer = []dnsRR{
+					&dnsRR_AAAA{
+						Hdr: dnsRR_Header{
+							Name:     q.question[0].Name,
+							Rrtype:   dnsTypeAAAA,
+							Class:    dnsClassINET,
+							Rdlength: 16,
+						},
+						AAAA: TestAddr6,
+					},
+				}
+			default:
+				return nil, fmt.Errorf("Unexpected Qtype: %v", q.question[0].Qtype)
+			}
+			return r, nil
+		}}
+
+		for _, strict := range []bool{true, false} {
+			r := Resolver{PreferGo: true, StrictErrors: strict, Dial: fake.DialContext}
+			ips, err := r.LookupIPAddr(context.Background(), name)
+
+			var wantErr error
+			if strict {
+				wantErr = tt.wantStrictErr
+			} else {
+				wantErr = tt.wantLaxErr
+			}
+			if !reflect.DeepEqual(err, wantErr) {
+				t.Errorf("#%d (%s) strict=%v: got err %#v; want %#v", i, tt.desc, strict, err, wantErr)
+			}
+
+			gotIPs := map[string]struct{}{}
+			for _, ip := range ips {
+				gotIPs[ip.String()] = struct{}{}
+			}
+			wantIPs := map[string]struct{}{}
+			if wantErr == nil {
+				for _, ip := range tt.wantIPs {
+					wantIPs[ip] = struct{}{}
+				}
+			}
+			if !reflect.DeepEqual(gotIPs, wantIPs) {
+				t.Errorf("#%d (%s) strict=%v: got ips %v; want %v", i, tt.desc, strict, gotIPs, wantIPs)
+			}
+		}
+	}
+}
+
+// Issue 17448. With StrictErrors enabled, temporary errors should make
+// LookupTXT stop walking the search list.
+func TestStrictErrorsLookupTXT(t *testing.T) {
+	conf, err := newResolvConfTest()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conf.teardown()
+
+	confData := []string{
+		"nameserver 192.0.2.53",
+		"search x.golang.org y.golang.org",
+	}
+	if err := conf.writeAndUpdate(confData); err != nil {
+		t.Fatal(err)
+	}
+
+	const name = "test"
+	const server = "192.0.2.53:53"
+	const searchX = "test.x.golang.org."
+	const searchY = "test.y.golang.org."
+	const txt = "Hello World"
+
+	fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
+		t.Log(s, q)
+
+		switch q.question[0].Name {
+		case searchX:
+			return nil, poll.ErrTimeout
+		case searchY:
+			return mockTXTResponse(q), nil
+		default:
+			return nil, fmt.Errorf("Unexpected Name: %v", q.question[0].Name)
+		}
+	}}
+
+	for _, strict := range []bool{true, false} {
+		r := Resolver{StrictErrors: strict, Dial: fake.DialContext}
+		_, rrs, err := r.lookup(context.Background(), name, dnsTypeTXT)
+		var wantErr error
+		var wantRRs int
+		if strict {
+			wantErr = &DNSError{
+				Err:       poll.ErrTimeout.Error(),
+				Name:      name,
+				Server:    server,
+				IsTimeout: true,
+			}
+		} else {
+			wantRRs = 1
+		}
+		if !reflect.DeepEqual(err, wantErr) {
+			t.Errorf("strict=%v: got err %#v; want %#v", strict, err, wantErr)
+		}
+		if len(rrs) != wantRRs {
+			t.Errorf("strict=%v: got %v; want %v", strict, len(rrs), wantRRs)
+		}
+	}
+}
diff --git a/src/net/error_posix.go b/src/net/error_posix.go
new file mode 100644
index 0000000..dd9754c
--- /dev/null
+++ b/src/net/error_posix.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+// wrapSyscallError takes an error and a syscall name. If the error is
+// a syscall.Errno, it wraps it in a os.SyscallError using the syscall name.
+func wrapSyscallError(name string, err error) error {
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError(name, err)
+	}
+	return err
+}
diff --git a/src/net/error_test.go b/src/net/error_test.go
index c23da49..9791e6f 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -7,11 +7,13 @@ package net
 import (
 	"context"
 	"fmt"
+	"internal/poll"
 	"io"
 	"io/ioutil"
 	"net/internal/socktest"
 	"os"
 	"runtime"
+	"strings"
 	"testing"
 	"time"
 )
@@ -87,7 +89,7 @@ second:
 		return nil
 	}
 	switch err := nestedErr.(type) {
-	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
 		return nil
 	case *os.SyscallError:
 		nestedErr = err.Err
@@ -97,7 +99,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress,
+	case errCanceled, poll.ErrNetClosing, errMissingAddress, errNoSuitableAddress,
 		context.DeadlineExceeded, context.Canceled:
 		return nil
 	}
@@ -213,7 +215,7 @@ func TestDialAddrError(t *testing.T) {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -432,7 +434,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errClosing, errTimeout:
+	case poll.ErrNetClosing, poll.ErrTimeout:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -467,14 +469,14 @@ second:
 		return nil
 	}
 	switch err := nestedErr.(type) {
-	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
 		return nil
 	case *os.SyscallError:
 		nestedErr = err.Err
 		goto third
 	}
 	switch nestedErr {
-	case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+	case errCanceled, poll.ErrNetClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -489,11 +491,21 @@ third:
 // parseCloseError parses nestedErr and reports whether it is a valid
 // error value from Close functions.
 // It returns nil when nestedErr is valid.
-func parseCloseError(nestedErr error) error {
+func parseCloseError(nestedErr error, isShutdown bool) error {
 	if nestedErr == nil {
 		return nil
 	}
 
+	// Because historically we have not exported the error that we
+	// return for an operation on a closed network connection,
+	// there are programs that test for the exact error string.
+	// Verify that string here so that we don't break those
+	// programs unexpectedly. See issues #4373 and #19252.
+	want := "use of closed network connection"
+	if !isShutdown && !strings.Contains(nestedErr.Error(), want) {
+		return fmt.Errorf("error string %q does not contain expected string %q", nestedErr, want)
+	}
+
 	switch err := nestedErr.(type) {
 	case *OpError:
 		if err := err.isValid(); err != nil {
@@ -517,7 +529,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errClosing:
+	case poll.ErrNetClosing:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -547,23 +559,23 @@ func TestCloseError(t *testing.T) {
 
 	for i := 0; i < 3; i++ {
 		err = c.(*TCPConn).CloseRead()
-		if perr := parseCloseError(err); perr != nil {
+		if perr := parseCloseError(err, true); perr != nil {
 			t.Errorf("#%d: %v", i, perr)
 		}
 	}
 	for i := 0; i < 3; i++ {
 		err = c.(*TCPConn).CloseWrite()
-		if perr := parseCloseError(err); perr != nil {
+		if perr := parseCloseError(err, true); perr != nil {
 			t.Errorf("#%d: %v", i, perr)
 		}
 	}
 	for i := 0; i < 3; i++ {
 		err = c.Close()
-		if perr := parseCloseError(err); perr != nil {
+		if perr := parseCloseError(err, false); perr != nil {
 			t.Errorf("#%d: %v", i, perr)
 		}
 		err = ln.Close()
-		if perr := parseCloseError(err); perr != nil {
+		if perr := parseCloseError(err, false); perr != nil {
 			t.Errorf("#%d: %v", i, perr)
 		}
 	}
@@ -576,7 +588,7 @@ func TestCloseError(t *testing.T) {
 
 	for i := 0; i < 3; i++ {
 		err = pc.Close()
-		if perr := parseCloseError(err); perr != nil {
+		if perr := parseCloseError(err, false); perr != nil {
 			t.Errorf("#%d: %v", i, perr)
 		}
 	}
@@ -613,7 +625,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errClosing, errTimeout:
+	case poll.ErrNetClosing, poll.ErrTimeout:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -692,7 +704,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errClosing:
+	case poll.ErrNetClosing:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
diff --git a/src/net/example_test.go b/src/net/example_test.go
index 9dd1732..f8f10e3 100644
--- a/src/net/example_test.go
+++ b/src/net/example_test.go
@@ -36,6 +36,70 @@ func ExampleListener() {
 	}
 }
 
+func ExampleIPv4() {
+	fmt.Println(net.IPv4(8, 8, 8, 8))
+
+	// Output:
+	// 8.8.8.8
+}
+
+func ExampleParseCIDR() {
+	ipv4Addr, ipv4Net, err := net.ParseCIDR("192.0.2.1/24")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(ipv4Addr)
+	fmt.Println(ipv4Net)
+
+	ipv6Addr, ipv6Net, err := net.ParseCIDR("2001:db8:a0b:12f0::1/32")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(ipv6Addr)
+	fmt.Println(ipv6Net)
+
+	// Output:
+	// 192.0.2.1
+	// 192.0.2.0/24
+	// 2001:db8:a0b:12f0::1
+	// 2001:db8::/32
+}
+
+func ExampleParseIP() {
+	fmt.Println(net.ParseIP("192.0.2.1"))
+	fmt.Println(net.ParseIP("2001:db8::68"))
+	fmt.Println(net.ParseIP("192.0.2"))
+
+	// Output:
+	// 192.0.2.1
+	// 2001:db8::68
+	// <nil>
+}
+
+func ExampleIP_DefaultMask() {
+	ip := net.ParseIP("192.0.2.1")
+	fmt.Println(ip.DefaultMask())
+
+	// Output:
+	// ffffff00
+}
+
+func ExampleIP_Mask() {
+	ipv4Addr := net.ParseIP("192.0.2.1")
+	// This mask corresponds to a /24 subnet for IPv4.
+	ipv4Mask := net.CIDRMask(24, 32)
+	fmt.Println(ipv4Addr.Mask(ipv4Mask))
+
+	ipv6Addr := net.ParseIP("2001:db8:a0b:12f0::1")
+	// This mask corresponds to a /32 subnet for IPv6.
+	ipv6Mask := net.CIDRMask(32, 128)
+	fmt.Println(ipv6Addr.Mask(ipv6Mask))
+
+	// Output:
+	// 192.0.2.0
+	// 2001:db8::
+}
+
 func ExampleCIDRMask() {
 	// This mask corresponds to a /31 subnet for IPv4.
 	fmt.Println(net.CIDRMask(31, 32))
@@ -47,3 +111,10 @@ func ExampleCIDRMask() {
 	// fffffffe
 	// ffffffffffffffff0000000000000000
 }
+
+func ExampleIPv4Mask() {
+	fmt.Println(net.IPv4Mask(255, 255, 255, 0))
+
+	// Output:
+	// ffffff00
+}
diff --git a/src/net/external_test.go b/src/net/external_test.go
index e18b547..38788ef 100644
--- a/src/net/external_test.go
+++ b/src/net/external_test.go
@@ -15,7 +15,7 @@ import (
 func TestResolveGoogle(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+	if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -62,7 +62,7 @@ var dialGoogleTests = []struct {
 func TestDialGoogle(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+	if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
diff --git a/src/net/fd_io_plan9.go b/src/net/fd_io_plan9.go
deleted file mode 100644
index 76da0c5..0000000
--- a/src/net/fd_io_plan9.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"os"
-	"runtime"
-	"sync"
-	"syscall"
-)
-
-// asyncIO implements asynchronous cancelable I/O.
-// An asyncIO represents a single asynchronous Read or Write
-// operation. The result is returned on the result channel.
-// The undergoing I/O system call can either complete or be
-// interrupted by a note.
-type asyncIO struct {
-	res chan result
-
-	// mu guards the pid field.
-	mu sync.Mutex
-
-	// pid holds the process id of
-	// the process running the IO operation.
-	pid int
-}
-
-// result is the return value of a Read or Write operation.
-type result struct {
-	n   int
-	err error
-}
-
-// newAsyncIO returns a new asyncIO that performs an I/O
-// operation by calling fn, which must do one and only one
-// interruptible system call.
-func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
-	aio := &asyncIO{
-		res: make(chan result, 0),
-	}
-	aio.mu.Lock()
-	go func() {
-		// Lock the current goroutine to its process
-		// and store the pid in io so that Cancel can
-		// interrupt it. We ignore the "hangup" signal,
-		// so the signal does not take down the entire
-		// Go runtime.
-		runtime.LockOSThread()
-		runtime_ignoreHangup()
-		aio.pid = os.Getpid()
-		aio.mu.Unlock()
-
-		n, err := fn(b)
-
-		aio.mu.Lock()
-		aio.pid = -1
-		runtime_unignoreHangup()
-		aio.mu.Unlock()
-
-		aio.res <- result{n, err}
-	}()
-	return aio
-}
-
-var hangupNote os.Signal = syscall.Note("hangup")
-
-// Cancel interrupts the I/O operation, causing
-// the Wait function to return.
-func (aio *asyncIO) Cancel() {
-	aio.mu.Lock()
-	defer aio.mu.Unlock()
-	if aio.pid == -1 {
-		return
-	}
-	proc, err := os.FindProcess(aio.pid)
-	if err != nil {
-		return
-	}
-	proc.Signal(hangupNote)
-}
-
-// Wait for the I/O operation to complete.
-func (aio *asyncIO) Wait() (int, error) {
-	res := <-aio.res
-	return res.n, res.err
-}
-
-// The following functions, provided by the runtime, are used to
-// ignore and unignore the "hangup" signal received by the process.
-func runtime_ignoreHangup()
-func runtime_unignoreHangup()
diff --git a/src/net/fd_mutex.go b/src/net/fd_mutex.go
deleted file mode 100644
index 4591fd1..0000000
--- a/src/net/fd_mutex.go
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import "sync/atomic"
-
-// 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
-	wsema uint32
-}
-
-// fdMutex.state is organized as follows:
-// 1 bit - whether netFD is closed, if set all subsequent lock operations will fail.
-// 1 bit - lock for read operations.
-// 1 bit - lock for write operations.
-// 20 bits - total number of references (read+write+misc).
-// 20 bits - number of outstanding read waiters.
-// 20 bits - number of outstanding write waiters.
-const (
-	mutexClosed  = 1 << 0
-	mutexRLock   = 1 << 1
-	mutexWLock   = 1 << 2
-	mutexRef     = 1 << 3
-	mutexRefMask = (1<<20 - 1) << 3
-	mutexRWait   = 1 << 23
-	mutexRMask   = (1<<20 - 1) << 23
-	mutexWWait   = 1 << 43
-	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 operations must do increfAndClose/decref.
-
-// 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 {
-			return false
-		}
-		new := old + mutexRef
-		if new&mutexRefMask == 0 {
-			panic("net: inconsistent fdMutex")
-		}
-		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
-			return true
-		}
-	}
-}
-
-// 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 {
-			return false
-		}
-		// Mark as closed and acquire a reference.
-		new := (old | mutexClosed) + mutexRef
-		if new&mutexRefMask == 0 {
-			panic("net: inconsistent fdMutex")
-		}
-		// Remove all read and write waiters.
-		new &^= mutexRMask | mutexWMask
-		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
-			// Wake all read and write waiters,
-			// they will observe closed flag after wakeup.
-			for old&mutexRMask != 0 {
-				old -= mutexRWait
-				runtime_Semrelease(&mu.rsema)
-			}
-			for old&mutexWMask != 0 {
-				old -= mutexWWait
-				runtime_Semrelease(&mu.wsema)
-			}
-			return true
-		}
-	}
-}
-
-// 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 {
-			panic("net: inconsistent fdMutex")
-		}
-		new := old - mutexRef
-		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
-			return new&(mutexClosed|mutexRefMask) == mutexClosed
-		}
-	}
-}
-
-// 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 {
-		mutexBit = mutexRLock
-		mutexWait = mutexRWait
-		mutexMask = mutexRMask
-		mutexSema = &mu.rsema
-	} else {
-		mutexBit = mutexWLock
-		mutexWait = mutexWWait
-		mutexMask = mutexWMask
-		mutexSema = &mu.wsema
-	}
-	for {
-		old := atomic.LoadUint64(&mu.state)
-		if old&mutexClosed != 0 {
-			return false
-		}
-		var new uint64
-		if old&mutexBit == 0 {
-			// Lock is free, acquire it.
-			new = (old | mutexBit) + mutexRef
-			if new&mutexRefMask == 0 {
-				panic("net: inconsistent fdMutex")
-			}
-		} else {
-			// Wait for lock.
-			new = old + mutexWait
-			if new&mutexMask == 0 {
-				panic("net: inconsistent fdMutex")
-			}
-		}
-		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
-			if old&mutexBit == 0 {
-				return true
-			}
-			runtime_Semacquire(mutexSema)
-			// The signaller has subtracted mutexWait.
-		}
-	}
-}
-
-// 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 {
-		mutexBit = mutexRLock
-		mutexWait = mutexRWait
-		mutexMask = mutexRMask
-		mutexSema = &mu.rsema
-	} else {
-		mutexBit = mutexWLock
-		mutexWait = mutexWWait
-		mutexMask = mutexWMask
-		mutexSema = &mu.wsema
-	}
-	for {
-		old := atomic.LoadUint64(&mu.state)
-		if old&mutexBit == 0 || old&mutexRefMask == 0 {
-			panic("net: inconsistent fdMutex")
-		}
-		// Drop lock, drop reference and wake read waiter if present.
-		new := (old &^ mutexBit) - mutexRef
-		if old&mutexMask != 0 {
-			new -= mutexWait
-		}
-		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
-			if old&mutexMask != 0 {
-				runtime_Semrelease(mutexSema)
-			}
-			return new&(mutexClosed|mutexRefMask) == mutexClosed
-		}
-	}
-}
-
-// 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
deleted file mode 100644
index 3542c70..0000000
--- a/src/net/fd_mutex_test.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"math/rand"
-	"runtime"
-	"testing"
-	"time"
-)
-
-func TestMutexLock(t *testing.T) {
-	var mu fdMutex
-
-	if !mu.incref() {
-		t.Fatal("broken")
-	}
-	if mu.decref() {
-		t.Fatal("broken")
-	}
-
-	if !mu.rwlock(true) {
-		t.Fatal("broken")
-	}
-	if mu.rwunlock(true) {
-		t.Fatal("broken")
-	}
-
-	if !mu.rwlock(false) {
-		t.Fatal("broken")
-	}
-	if mu.rwunlock(false) {
-		t.Fatal("broken")
-	}
-}
-
-func TestMutexClose(t *testing.T) {
-	var mu fdMutex
-	if !mu.increfAndClose() {
-		t.Fatal("broken")
-	}
-
-	if mu.incref() {
-		t.Fatal("broken")
-	}
-	if mu.rwlock(true) {
-		t.Fatal("broken")
-	}
-	if mu.rwlock(false) {
-		t.Fatal("broken")
-	}
-	if mu.increfAndClose() {
-		t.Fatal("broken")
-	}
-}
-
-func TestMutexCloseUnblock(t *testing.T) {
-	c := make(chan bool)
-	var mu fdMutex
-	mu.rwlock(true)
-	for i := 0; i < 4; i++ {
-		go func() {
-			if mu.rwlock(true) {
-				t.Error("broken")
-				return
-			}
-			c <- true
-		}()
-	}
-	// Concurrent goroutines must not be able to read lock the mutex.
-	time.Sleep(time.Millisecond)
-	select {
-	case <-c:
-		t.Fatal("broken")
-	default:
-	}
-	mu.increfAndClose() // Must unblock the readers.
-	for i := 0; i < 4; i++ {
-		select {
-		case <-c:
-		case <-time.After(10 * time.Second):
-			t.Fatal("broken")
-		}
-	}
-	if mu.decref() {
-		t.Fatal("broken")
-	}
-	if !mu.rwunlock(true) {
-		t.Fatal("broken")
-	}
-}
-
-func TestMutexPanic(t *testing.T) {
-	ensurePanics := func(f func()) {
-		defer func() {
-			if recover() == nil {
-				t.Fatal("does not panic")
-			}
-		}()
-		f()
-	}
-
-	var mu fdMutex
-	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) })
-
-	// ensure that it's still not broken
-	mu.incref()
-	mu.decref()
-	mu.rwlock(true)
-	mu.rwunlock(true)
-	mu.rwlock(false)
-	mu.rwunlock(false)
-}
-
-func TestMutexStress(t *testing.T) {
-	P := 8
-	N := int(1e6)
-	if testing.Short() {
-		P = 4
-		N = 1e4
-	}
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
-	done := make(chan bool)
-	var mu fdMutex
-	var readState [2]uint64
-	var writeState [2]uint64
-	for p := 0; p < P; p++ {
-		go func() {
-			r := rand.New(rand.NewSource(rand.Int63()))
-			for i := 0; i < N; i++ {
-				switch r.Intn(3) {
-				case 0:
-					if !mu.incref() {
-						t.Error("broken")
-						return
-					}
-					if mu.decref() {
-						t.Error("broken")
-						return
-					}
-				case 1:
-					if !mu.rwlock(true) {
-						t.Error("broken")
-						return
-					}
-					// Ensure that it provides mutual exclusion for readers.
-					if readState[0] != readState[1] {
-						t.Error("broken")
-						return
-					}
-					readState[0]++
-					readState[1]++
-					if mu.rwunlock(true) {
-						t.Error("broken")
-						return
-					}
-				case 2:
-					if !mu.rwlock(false) {
-						t.Error("broken")
-						return
-					}
-					// Ensure that it provides mutual exclusion for writers.
-					if writeState[0] != writeState[1] {
-						t.Error("broken")
-						return
-					}
-					writeState[0]++
-					writeState[1]++
-					if mu.rwunlock(false) {
-						t.Error("broken")
-						return
-					}
-				}
-			}
-			done <- true
-		}()
-	}
-	for p := 0; p < P; p++ {
-		<-done
-	}
-	if !mu.increfAndClose() {
-		t.Fatal("broken")
-	}
-	if !mu.decref() {
-		t.Fatal("broken")
-	}
-}
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go
index 300d8c4..46ee5d9 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -5,23 +5,15 @@
 package net
 
 import (
+	"internal/poll"
 	"io"
 	"os"
-	"sync/atomic"
 	"syscall"
-	"time"
 )
 
-type atomicBool int32
-
-func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
-func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
-func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
-
 // Network file descriptor.
 type netFD struct {
-	// locking/lifetime of sysfd + serialize access to Read and Write methods
-	fdmu fdMutex
+	pfd poll.FD
 
 	// immutable until Close
 	net               string
@@ -30,26 +22,12 @@ type netFD struct {
 	listen, ctl, data *os.File
 	laddr, raddr      Addr
 	isStream          bool
-
-	// deadlines
-	raio      *asyncIO
-	waio      *asyncIO
-	rtimer    *time.Timer
-	wtimer    *time.Timer
-	rtimedout atomicBool // set true when read deadline has been reached
-	wtimedout atomicBool // set true when write deadline has been reached
 }
 
-var (
-	netdir string // default network
-)
-
-func sysInit() {
-	netdir = "/net"
-}
+var netdir = "/net" // default network
 
 func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
-	return &netFD{
+	ret := &netFD{
 		net:    net,
 		n:      name,
 		dir:    netdir + "/" + net + "/" + name,
@@ -57,7 +35,9 @@ func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*ne
 		ctl:    ctl, data: data,
 		laddr: laddr,
 		raddr: raddr,
-	}, nil
+	}
+	ret.pfd.Destroy = ret.destroy
+	return ret, nil
 }
 
 func (fd *netFD) init() error {
@@ -99,28 +79,10 @@ func (fd *netFD) destroy() {
 }
 
 func (fd *netFD) Read(b []byte) (n int, err error) {
-	if fd.rtimedout.isSet() {
-		return 0, errTimeout
-	}
 	if !fd.ok() || fd.data == nil {
 		return 0, syscall.EINVAL
 	}
-	if err := fd.readLock(); err != nil {
-		return 0, err
-	}
-	defer fd.readUnlock()
-	if len(b) == 0 {
-		return 0, nil
-	}
-	fd.raio = newAsyncIO(fd.data.Read, b)
-	n, err = fd.raio.Wait()
-	fd.raio = nil
-	if isHangup(err) {
-		err = io.EOF
-	}
-	if isInterrupted(err) {
-		err = errTimeout
-	}
+	n, err = fd.pfd.Read(fd.data.Read, b)
 	if fd.net == "udp" && err == io.EOF {
 		n = 0
 		err = nil
@@ -129,23 +91,10 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
 }
 
 func (fd *netFD) Write(b []byte) (n int, err error) {
-	if fd.wtimedout.isSet() {
-		return 0, errTimeout
-	}
 	if !fd.ok() || fd.data == nil {
 		return 0, syscall.EINVAL
 	}
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	fd.waio = newAsyncIO(fd.data.Write, b)
-	n, err = fd.waio.Wait()
-	fd.waio = nil
-	if isInterrupted(err) {
-		err = errTimeout
-	}
-	return
+	return fd.pfd.Write(fd.data.Write, b)
 }
 
 func (fd *netFD) closeRead() error {
@@ -163,8 +112,8 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) Close() error {
-	if !fd.fdmu.increfAndClose() {
-		return errClosing
+	if err := fd.pfd.Close(); err != nil {
+		return err
 	}
 	if !fd.ok() {
 		return syscall.EINVAL
@@ -216,77 +165,6 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
 	return os.NewFile(uintptr(dfd), s), nil
 }
 
-func (fd *netFD) setDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r'+'w')
-}
-
-func (fd *netFD) setReadDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r')
-}
-
-func (fd *netFD) setWriteDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'w')
-}
-
-func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-	d := t.Sub(time.Now())
-	if mode == 'r' || mode == 'r'+'w' {
-		fd.rtimedout.setFalse()
-	}
-	if mode == 'w' || mode == 'r'+'w' {
-		fd.wtimedout.setFalse()
-	}
-	if t.IsZero() || d < 0 {
-		// Stop timer
-		if mode == 'r' || mode == 'r'+'w' {
-			if fd.rtimer != nil {
-				fd.rtimer.Stop()
-			}
-			fd.rtimer = nil
-		}
-		if mode == 'w' || mode == 'r'+'w' {
-			if fd.wtimer != nil {
-				fd.wtimer.Stop()
-			}
-			fd.wtimer = nil
-		}
-	} else {
-		// Interrupt I/O operation once timer has expired
-		if mode == 'r' || mode == 'r'+'w' {
-			fd.rtimer = time.AfterFunc(d, func() {
-				fd.rtimedout.setTrue()
-				if fd.raio != nil {
-					fd.raio.Cancel()
-				}
-			})
-		}
-		if mode == 'w' || mode == 'r'+'w' {
-			fd.wtimer = time.AfterFunc(d, func() {
-				fd.wtimedout.setTrue()
-				if fd.waio != nil {
-					fd.waio.Cancel()
-				}
-			})
-		}
-	}
-	if !t.IsZero() && d < 0 {
-		// Interrupt current I/O operation
-		if mode == 'r' || mode == 'r'+'w' {
-			fd.rtimedout.setTrue()
-			if fd.raio != nil {
-				fd.raio.Cancel()
-			}
-		}
-		if mode == 'w' || mode == 'r'+'w' {
-			fd.wtimedout.setTrue()
-			if fd.waio != nil {
-				fd.waio.Cancel()
-			}
-		}
-	}
-	return nil
-}
-
 func setReadBuffer(fd *netFD, bytes int) error {
 	return syscall.EPLAN9
 }
@@ -294,11 +172,3 @@ 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")
-}
-
-func isInterrupted(err error) bool {
-	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
-}
diff --git a/src/net/fd_poll_nacl.go b/src/net/fd_poll_nacl.go
deleted file mode 100644
index 8398760..0000000
--- a/src/net/fd_poll_nacl.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"runtime"
-	"syscall"
-	"time"
-)
-
-type pollDesc struct {
-	fd      *netFD
-	closing bool
-}
-
-func (pd *pollDesc) init(fd *netFD) error { pd.fd = fd; return nil }
-
-func (pd *pollDesc) close() {}
-
-func (pd *pollDesc) evict() {
-	pd.closing = true
-	if pd.fd != nil {
-		syscall.StopIO(pd.fd.sysfd)
-		runtime.KeepAlive(pd.fd)
-	}
-}
-
-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) prepareWrite() error { return pd.prepare('w') }
-
-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) waitWrite() error { return pd.wait('w') }
-
-func (pd *pollDesc) waitCanceled(mode int) {}
-
-func (pd *pollDesc) waitCanceledRead() {}
-
-func (pd *pollDesc) waitCanceledWrite() {}
-
-func (fd *netFD) setDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r'+'w')
-}
-
-func (fd *netFD) setReadDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r')
-}
-
-func (fd *netFD) setWriteDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'w')
-}
-
-func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-	d := t.UnixNano()
-	if t.IsZero() {
-		d = 0
-	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	switch mode {
-	case 'r':
-		syscall.SetReadDeadline(fd.sysfd, d)
-	case 'w':
-		syscall.SetWriteDeadline(fd.sysfd, d)
-	case 'r' + 'w':
-		syscall.SetReadDeadline(fd.sysfd, d)
-		syscall.SetWriteDeadline(fd.sysfd, d)
-	}
-	fd.decref()
-	return nil
-}
diff --git a/src/net/fd_poll_runtime.go b/src/net/fd_poll_runtime.go
deleted file mode 100644
index 62b69fc..0000000
--- a/src/net/fd_poll_runtime.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
-
-package net
-
-import (
-	"runtime"
-	"sync"
-	"syscall"
-	"time"
-)
-
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() int64
-
-func runtime_pollServerInit()
-func runtime_pollOpen(fd uintptr) (uintptr, int)
-func runtime_pollClose(ctx uintptr)
-func runtime_pollWait(ctx uintptr, mode int) int
-func runtime_pollWaitCanceled(ctx uintptr, mode int) int
-func runtime_pollReset(ctx uintptr, mode int) int
-func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
-func runtime_pollUnblock(ctx uintptr)
-
-type pollDesc struct {
-	runtimeCtx uintptr
-}
-
-var serverInit sync.Once
-
-func (pd *pollDesc) init(fd *netFD) error {
-	serverInit.Do(runtime_pollServerInit)
-	ctx, errno := runtime_pollOpen(uintptr(fd.sysfd))
-	runtime.KeepAlive(fd)
-	if errno != 0 {
-		return syscall.Errno(errno)
-	}
-	pd.runtimeCtx = ctx
-	return nil
-}
-
-func (pd *pollDesc) close() {
-	if pd.runtimeCtx == 0 {
-		return
-	}
-	runtime_pollClose(pd.runtimeCtx)
-	pd.runtimeCtx = 0
-}
-
-// Evict evicts fd from the pending list, unblocking any I/O running on fd.
-func (pd *pollDesc) evict() {
-	if pd.runtimeCtx == 0 {
-		return
-	}
-	runtime_pollUnblock(pd.runtimeCtx)
-}
-
-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) prepareWrite() error {
-	return pd.prepare('w')
-}
-
-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) waitWrite() error {
-	return pd.wait('w')
-}
-
-func (pd *pollDesc) waitCanceled(mode int) {
-	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
-}
-
-func (pd *pollDesc) waitCanceledRead() {
-	pd.waitCanceled('r')
-}
-
-func (pd *pollDesc) waitCanceledWrite() {
-	pd.waitCanceled('w')
-}
-
-func convertErr(res int) error {
-	switch res {
-	case 0:
-		return nil
-	case 1:
-		return errClosing
-	case 2:
-		return errTimeout
-	}
-	println("unreachable: ", res)
-	panic("unreachable")
-}
-
-func (fd *netFD) setDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r'+'w')
-}
-
-func (fd *netFD) setReadDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'r')
-}
-
-func (fd *netFD) setWriteDeadline(t time.Time) error {
-	return setDeadlineImpl(fd, t, 'w')
-}
-
-func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-	diff := int64(time.Until(t))
-	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
-	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
-	fd.decref()
-	return nil
-}
diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go
deleted file mode 100644
index b4b908a..0000000
--- a/src/net/fd_posix.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
-
-package net
-
-import (
-	"io"
-	"syscall"
-)
-
-// eofError returns io.EOF when fd is available for reading end of
-// file.
-func (fd *netFD) eofError(n int, err error) error {
-	if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
-		return io.EOF
-	}
-	return err
-}
diff --git a/src/net/fd_posix_test.go b/src/net/fd_posix_test.go
deleted file mode 100644
index 85711ef..0000000
--- a/src/net/fd_posix_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
-
-package net
-
-import (
-	"io"
-	"syscall"
-	"testing"
-)
-
-var eofErrorTests = []struct {
-	n        int
-	err      error
-	fd       *netFD
-	expected error
-}{
-	{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
-}
-
-func TestEOFError(t *testing.T) {
-	for _, tt := range eofErrorTests {
-		actual := tt.fd.eofError(tt.n, tt.err)
-		if actual != tt.expected {
-			t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
-		}
-	}
-}
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 3c95fc0..1122ee4 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -8,7 +8,7 @@ package net
 
 import (
 	"context"
-	"io"
+	"internal/poll"
 	"os"
 	"runtime"
 	"sync/atomic"
@@ -17,38 +17,33 @@ import (
 
 // Network file descriptor.
 type netFD struct {
-	// locking/lifetime of sysfd + serialize access to Read and Write methods
-	fdmu fdMutex
+	pfd poll.FD
 
 	// immutable until Close
-	sysfd       int
 	family      int
 	sotype      int
-	isStream    bool
 	isConnected bool
 	net         string
 	laddr       Addr
 	raddr       Addr
-
-	// writev cache.
-	iovecs *[]syscall.Iovec
-
-	// wait server
-	pd pollDesc
-}
-
-func sysInit() {
 }
 
 func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
-	return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
+	ret := &netFD{
+		pfd: poll.FD{
+			Sysfd:         sysfd,
+			IsStream:      sotype == syscall.SOCK_STREAM,
+			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
+		},
+		family: family,
+		sotype: sotype,
+		net:    net,
+	}
+	return ret, nil
 }
 
 func (fd *netFD) init() error {
-	if err := fd.pd.init(fd); err != nil {
-		return err
-	}
-	return nil
+	return fd.pfd.Init(fd.net, true)
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -72,7 +67,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 	// 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 {
+	switch err := connectFunc(fd.pfd.Sysfd, ra); err {
 	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 	case nil, syscall.EISCONN:
 		select {
@@ -80,9 +75,10 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 			return mapErr(ctx.Err())
 		default:
 		}
-		if err := fd.init(); err != nil {
+		if err := fd.pfd.Init(fd.net, true); err != nil {
 			return err
 		}
+		runtime.KeepAlive(fd)
 		return nil
 	case syscall.EINVAL:
 		// On Solaris we can see EINVAL if the socket has
@@ -97,12 +93,12 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 	default:
 		return os.NewSyscallError("connect", err)
 	}
-	if err := fd.init(); err != nil {
+	if err := fd.pfd.Init(fd.net, true); err != nil {
 		return err
 	}
 	if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
-		fd.setWriteDeadline(deadline)
-		defer fd.setWriteDeadline(noDeadline)
+		fd.pfd.SetWriteDeadline(deadline)
+		defer fd.pfd.SetWriteDeadline(noDeadline)
 	}
 
 	// Start the "interrupter" goroutine, if this context might be canceled.
@@ -119,7 +115,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 		defer func() {
 			close(done)
 			if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
-				// The interrupter goroutine called setWriteDeadline,
+				// The interrupter goroutine called SetWriteDeadline,
 				// but the connect code below had returned from
 				// waitWrite already and did a successful connect (ret
 				// == nil). Because we've now poisoned the connection
@@ -135,7 +131,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 				// Force the runtime's poller to immediately give up
 				// waiting for writability, unblocking waitWrite
 				// below.
-				fd.setWriteDeadline(aLongTimeAgo)
+				fd.pfd.SetWriteDeadline(aLongTimeAgo)
 				testHookCanceledDial()
 				interruptRes <- ctx.Err()
 			case <-done:
@@ -153,7 +149,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 		// 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.pfd.WaitWrite(); err != nil {
 			select {
 			case <-ctx.Done():
 				return mapErr(ctx.Err())
@@ -161,7 +157,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 			}
 			return err
 		}
-		nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
 		if err != nil {
 			return os.NewSyscallError("getsockopt", err)
 		}
@@ -174,45 +170,26 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
 			// 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 {
+			switch err := connectFunc(fd.pfd.Sysfd, ra); err {
 			case nil, syscall.EISCONN:
 				return nil
 			}
 		default:
 			return os.NewSyscallError("getsockopt", err)
 		}
+		runtime.KeepAlive(fd)
 	}
 }
 
-func (fd *netFD) destroy() {
-	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closeFunc.
-	fd.pd.close()
-	closeFunc(fd.sysfd)
-	fd.sysfd = -1
-	runtime.SetFinalizer(fd, nil)
-}
-
 func (fd *netFD) Close() error {
-	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
-	// 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.decref()
-	return nil
+	runtime.SetFinalizer(fd, nil)
+	return fd.pfd.Close()
 }
 
 func (fd *netFD) shutdown(how int) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
+	err := fd.pfd.Shutdown(how)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("shutdown", err)
 }
 
 func (fd *netFD) closeRead() error {
@@ -224,233 +201,59 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) Read(p []byte) (n int, err error) {
-	if err := fd.readLock(); err != nil {
-		return 0, err
-	}
-	defer fd.readUnlock()
-	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
-	}
-	if fd.isStream && len(p) > 1<<30 {
-		p = p[:1<<30]
-	}
-	for {
-		n, err = syscall.Read(fd.sysfd, p)
-		if err != nil {
-			n = 0
-			if err == syscall.EAGAIN {
-				if err = fd.pd.waitRead(); err == nil {
-					continue
-				}
-			}
-		}
-		err = fd.eofError(n, err)
-		break
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("read", err)
-	}
-	return
+	n, err = fd.pfd.Read(p)
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("read", err)
 }
 
 func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
-	if err := fd.readLock(); err != nil {
-		return 0, nil, err
-	}
-	defer fd.readUnlock()
-	if err := fd.pd.prepareRead(); err != nil {
-		return 0, nil, err
-	}
-	for {
-		n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
-		if err != nil {
-			n = 0
-			if err == syscall.EAGAIN {
-				if err = fd.pd.waitRead(); err == nil {
-					continue
-				}
-			}
-		}
-		err = fd.eofError(n, err)
-		break
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("recvfrom", err)
-	}
-	return
+	n, sa, err = fd.pfd.ReadFrom(p)
+	runtime.KeepAlive(fd)
+	return n, sa, wrapSyscallError("recvfrom", err)
 }
 
 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
-	if err := fd.readLock(); err != nil {
-		return 0, 0, 0, nil, err
-	}
-	defer fd.readUnlock()
-	if err := fd.pd.prepareRead(); err != nil {
-		return 0, 0, 0, nil, err
-	}
-	for {
-		n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
-		if err != nil {
-			// TODO(dfc) should n and oobn be set to 0
-			if err == syscall.EAGAIN {
-				if err = fd.pd.waitRead(); err == nil {
-					continue
-				}
-			}
-		}
-		err = fd.eofError(n, err)
-		break
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("recvmsg", err)
-	}
-	return
+	n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
+	runtime.KeepAlive(fd)
+	return n, oobn, flags, sa, wrapSyscallError("recvmsg", err)
 }
 
 func (fd *netFD) Write(p []byte) (nn int, err error) {
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	if err := fd.pd.prepareWrite(); err != nil {
-		return 0, err
-	}
-	for {
-		var n int
-		max := len(p)
-		if fd.isStream && max-nn > 1<<30 {
-			max = nn + 1<<30
-		}
-		n, err = syscall.Write(fd.sysfd, p[nn:max])
-		if n > 0 {
-			nn += n
-		}
-		if nn == len(p) {
-			break
-		}
-		if err == syscall.EAGAIN {
-			if err = fd.pd.waitWrite(); err == nil {
-				continue
-			}
-		}
-		if err != nil {
-			break
-		}
-		if n == 0 {
-			err = io.ErrUnexpectedEOF
-			break
-		}
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("write", err)
-	}
-	return nn, err
+	nn, err = fd.pfd.Write(p)
+	runtime.KeepAlive(fd)
+	return nn, wrapSyscallError("write", err)
 }
 
 func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	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 {
-				continue
-			}
-		}
-		break
-	}
-	if err == nil {
-		n = len(p)
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("sendto", err)
-	}
-	return
+	n, err = fd.pfd.WriteTo(p, sa)
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("sendto", err)
 }
 
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
-	if err := fd.writeLock(); err != nil {
-		return 0, 0, err
-	}
-	defer fd.writeUnlock()
-	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 {
-				continue
-			}
-		}
-		break
-	}
-	if err == nil {
-		oobn = len(oob)
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("sendmsg", err)
-	}
-	return
+	n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
+	runtime.KeepAlive(fd)
+	return n, oobn, wrapSyscallError("sendmsg", err)
 }
 
 func (fd *netFD) accept() (netfd *netFD, err error) {
-	if err := fd.readLock(); err != nil {
-		return nil, err
-	}
-	defer fd.readUnlock()
-
-	var s int
-	var rsa syscall.Sockaddr
-	if err = fd.pd.prepareRead(); err != nil {
-		return nil, err
-	}
-	for {
-		s, rsa, err = accept(fd.sysfd)
-		if err != nil {
-			nerr, ok := err.(*os.SyscallError)
-			if !ok {
-				return nil, err
-			}
-			switch nerr.Err {
-			case syscall.EAGAIN:
-				if err = fd.pd.waitRead(); err == nil {
-					continue
-				}
-			case syscall.ECONNABORTED:
-				// This means that a socket on the
-				// listen queue was closed before we
-				// Accept()ed it; it's a silly error,
-				// so try again.
-				continue
-			}
-			return nil, err
+	d, rsa, errcall, err := fd.pfd.Accept()
+	if err != nil {
+		if errcall != "" {
+			err = wrapSyscallError(errcall, err)
 		}
-		break
+		return nil, err
 	}
 
-	if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
-		closeFunc(s)
+	if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
+		poll.CloseFunc(d)
 		return nil, err
 	}
 	if err = netfd.init(); err != nil {
 		fd.Close()
 		return nil, err
 	}
-	lsa, _ := syscall.Getsockname(netfd.sysfd)
+	lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
 	netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
 	return netfd, nil
 }
@@ -503,7 +306,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 }
 
 func (fd *netFD) dup() (f *os.File, err error) {
-	ns, err := dupCloseOnExec(fd.sysfd)
+	ns, err := dupCloseOnExec(fd.pfd.Sysfd)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index a976f2a..0e5d37a 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -6,64 +6,13 @@ package net
 
 import (
 	"context"
-	"internal/race"
+	"internal/poll"
 	"os"
 	"runtime"
-	"sync"
 	"syscall"
 	"unsafe"
 )
 
-var (
-	initErr error
-	ioSync  uint64
-)
-
-// CancelIo Windows API cancels all outstanding IO for a particular
-// socket on current thread. To overcome that limitation, we run
-// special goroutine, locked to OS single thread, that both starts
-// and cancels IO. It means, there are 2 unavoidable thread switches
-// for every IO.
-// Some newer versions of Windows has new CancelIoEx API, that does
-// not have that limitation and can be used from any thread. This
-// package uses CancelIoEx API, if present, otherwise it fallback
-// to CancelIo.
-
-var (
-	canCancelIO                               bool // determines if CancelIoEx API is present
-	skipSyncNotif                             bool
-	hasLoadSetFileCompletionNotificationModes bool
-)
-
-func sysInit() {
-	var d syscall.WSAData
-	e := syscall.WSAStartup(uint32(0x202), &d)
-	if e != nil {
-		initErr = os.NewSyscallError("wsastartup", e)
-	}
-	canCancelIO = syscall.LoadCancelIoEx() == nil
-	hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
-	if hasLoadSetFileCompletionNotificationModes {
-		// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
-		// http://support.microsoft.com/kb/2568167
-		skipSyncNotif = true
-		protos := [2]int32{syscall.IPPROTO_TCP, 0}
-		var buf [32]syscall.WSAProtocolInfo
-		len := uint32(unsafe.Sizeof(buf))
-		n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
-		if err != nil {
-			skipSyncNotif = false
-		} else {
-			for i := int32(0); i < n; i++ {
-				if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
-					skipSyncNotif = false
-					break
-				}
-			}
-		}
-	}
-}
-
 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
 // for the given network type.
 func canUseConnectEx(net string) bool {
@@ -75,257 +24,39 @@ func canUseConnectEx(net string) bool {
 	return false
 }
 
-// operation contains superset of data necessary to perform all async IO.
-type operation struct {
-	// Used by IOCP interface, it must be first field
-	// of the struct, as our code rely on it.
-	o syscall.Overlapped
-
-	// fields used by runtime.netpoll
-	runtimeCtx uintptr
-	mode       int32
-	errno      int32
-	qty        uint32
-
-	// fields used only by net package
-	fd     *netFD
-	errc   chan error
-	buf    syscall.WSABuf
-	sa     syscall.Sockaddr
-	rsa    *syscall.RawSockaddrAny
-	rsan   int32
-	handle syscall.Handle
-	flags  uint32
-	bufs   []syscall.WSABuf
-}
-
-func (o *operation) InitBuf(buf []byte) {
-	o.buf.Len = uint32(len(buf))
-	o.buf.Buf = nil
-	if len(buf) != 0 {
-		o.buf.Buf = &buf[0]
-	}
-}
-
-func (o *operation) InitBufs(buf *Buffers) {
-	if o.bufs == nil {
-		o.bufs = make([]syscall.WSABuf, 0, len(*buf))
-	} else {
-		o.bufs = o.bufs[:0]
-	}
-	for _, b := range *buf {
-		var p *byte
-		if len(b) > 0 {
-			p = &b[0]
-		}
-		o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
-	}
-}
-
-// ClearBufs clears all pointers to Buffers parameter captured
-// by InitBufs, so it can be released by garbage collector.
-func (o *operation) ClearBufs() {
-	for i := range o.bufs {
-		o.bufs[i].Buf = nil
-	}
-	o.bufs = o.bufs[:0]
-}
-
-// ioSrv executes net IO requests.
-type ioSrv struct {
-	req chan ioSrvReq
-}
-
-type ioSrvReq struct {
-	o      *operation
-	submit func(o *operation) error // if nil, cancel the operation
-}
-
-// ProcessRemoteIO will execute submit IO requests on behalf
-// of other goroutines, all on a single os thread, so it can
-// cancel them later. Results of all operations will be sent
-// back to their requesters via channel supplied in request.
-// It is used only when the CancelIoEx API is unavailable.
-func (s *ioSrv) ProcessRemoteIO() {
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-	for r := range s.req {
-		if r.submit != nil {
-			r.o.errc <- r.submit(r.o)
-		} else {
-			r.o.errc <- syscall.CancelIo(r.o.fd.sysfd)
-		}
-	}
-}
-
-// ExecIO executes a single IO operation o. It submits and cancels
-// IO in the current thread for systems where Windows CancelIoEx API
-// is available. Alternatively, it passes the request onto
-// runtime netpoll and waits for completion or cancels request.
-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))
-	if err != nil {
-		return 0, err
-	}
-	// Start IO.
-	if canCancelIO {
-		err = submit(o)
-	} else {
-		// Send request to a special dedicated thread,
-		// so it can stop the IO with CancelIO later.
-		s.req <- ioSrvReq{o, submit}
-		err = <-o.errc
-	}
-	switch err {
-	case nil:
-		// IO completed immediately
-		if o.fd.skipSyncNotif {
-			// No completion message will follow, so return immediately.
-			return int(o.qty), nil
-		}
-		// Need to get our completion message anyway.
-	case syscall.ERROR_IO_PENDING:
-		// IO started, and we have to wait for its completion.
-		err = nil
-	default:
-		return 0, err
-	}
-	// Wait for our request to complete.
-	err = fd.pd.wait(int(o.mode))
-	if err == nil {
-		// All is good. Extract our IO results and return.
-		if o.errno != 0 {
-			err = syscall.Errno(o.errno)
-			return 0, err
-		}
-		return int(o.qty), nil
-	}
-	// IO is interrupted by "close" or "timeout"
-	netpollErr := err
-	switch netpollErr {
-	case errClosing, errTimeout:
-		// will deal with those.
-	default:
-		panic("net: unexpected runtime.netpoll error: " + netpollErr.Error())
-	}
-	// Cancel our request.
-	if canCancelIO {
-		err := syscall.CancelIoEx(fd.sysfd, &o.o)
-		// Assuming ERROR_NOT_FOUND is returned, if IO is completed.
-		if err != nil && err != syscall.ERROR_NOT_FOUND {
-			// TODO(brainman): maybe do something else, but panic.
-			panic(err)
-		}
-	} else {
-		s.req <- ioSrvReq{o, nil}
-		<-o.errc
-	}
-	// Wait for cancelation to complete.
-	fd.pd.waitCanceled(int(o.mode))
-	if o.errno != 0 {
-		err = syscall.Errno(o.errno)
-		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
-			err = netpollErr
-		}
-		return 0, err
-	}
-	// We issued a cancelation request. But, it seems, IO operation succeeded
-	// before the cancelation request run. We need to treat the IO operation as
-	// succeeded (the bytes are actually sent/recv from network).
-	return int(o.qty), nil
-}
-
-// Start helper goroutines.
-var rsrv, wsrv *ioSrv
-var onceStartServer sync.Once
-
-func startServer() {
-	rsrv = new(ioSrv)
-	wsrv = new(ioSrv)
-	if !canCancelIO {
-		// Only CancelIo API is available. Lets start two special goroutines
-		// locked to an OS thread, that both starts and cancels IO. One will
-		// process read requests, while other will do writes.
-		rsrv.req = make(chan ioSrvReq)
-		go rsrv.ProcessRemoteIO()
-		wsrv.req = make(chan ioSrvReq)
-		go wsrv.ProcessRemoteIO()
-	}
-}
-
 // Network file descriptor.
 type netFD struct {
-	// locking/lifetime of sysfd + serialize access to Read and Write methods
-	fdmu fdMutex
+	pfd poll.FD
 
 	// immutable until Close
-	sysfd         syscall.Handle
-	family        int
-	sotype        int
-	isStream      bool
-	isConnected   bool
-	skipSyncNotif bool
-	net           string
-	laddr         Addr
-	raddr         Addr
-
-	rop operation // read operation
-	wop operation // write operation
-
-	// wait server
-	pd pollDesc
+	family      int
+	sotype      int
+	isConnected bool
+	net         string
+	laddr       Addr
+	raddr       Addr
 }
 
 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
-	if initErr != nil {
-		return nil, initErr
+	ret := &netFD{
+		pfd: poll.FD{
+			Sysfd:         sysfd,
+			IsStream:      sotype == syscall.SOCK_STREAM,
+			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
+		},
+		family: family,
+		sotype: sotype,
+		net:    net,
 	}
-	onceStartServer.Do(startServer)
-	return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
+	return ret, nil
 }
 
 func (fd *netFD) init() error {
-	if err := fd.pd.init(fd); err != nil {
-		return err
-	}
-	if hasLoadSetFileCompletionNotificationModes {
-		// We do not use events, so we can skip them always.
-		flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
-		// It's not safe to skip completion notifications for UDP:
-		// http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
-		if skipSyncNotif && fd.net == "tcp" {
-			flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
-		}
-		err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags)
-		if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
-			fd.skipSyncNotif = true
-		}
+	errcall, err := fd.pfd.Init(fd.net)
+	if errcall != "" {
+		err = wrapSyscallError(errcall, err)
 	}
-	// Disable SIO_UDP_CONNRESET behavior.
-	// http://support.microsoft.com/kb/263823
-	switch fd.net {
-	case "udp", "udp4", "udp6":
-		ret := uint32(0)
-		flag := uint32(0)
-		size := uint32(unsafe.Sizeof(flag))
-		err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
-		if err != nil {
-			return os.NewSyscallError("wsaioctl", err)
-		}
-	}
-	fd.rop.mode = 'r'
-	fd.wop.mode = 'w'
-	fd.rop.fd = fd
-	fd.wop.fd = fd
-	fd.rop.runtimeCtx = fd.pd.runtimeCtx
-	fd.wop.runtimeCtx = fd.pd.runtimeCtx
-	if !canCancelIO {
-		fd.rop.errc = make(chan error)
-		fd.wop.errc = make(chan error)
-	}
-	return nil
+	return err
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -342,11 +73,11 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
 		return err
 	}
 	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
-		fd.setWriteDeadline(deadline)
-		defer fd.setWriteDeadline(noDeadline)
+		fd.pfd.SetWriteDeadline(deadline)
+		defer fd.pfd.SetWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		err := connectFunc(fd.sysfd, ra)
+		err := connectFunc(fd.pfd.Sysfd, ra)
 		return os.NewSyscallError("connect", err)
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
@@ -359,13 +90,10 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
 		default:
 			panic("unexpected type in connect")
 		}
-		if err := syscall.Bind(fd.sysfd, la); err != nil {
+		if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
 			return os.NewSyscallError("bind", err)
 		}
 	}
-	// Call ConnectEx API.
-	o := &fd.wop
-	o.sa = ra
 
 	// Wait for the goroutine converting context.Done into a write timeout
 	// to exist, otherwise our caller might cancel the context and
@@ -377,16 +105,14 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
 		case <-ctx.Done():
 			// Force the runtime's poller to immediately give
 			// up waiting for writability.
-			fd.setWriteDeadline(aLongTimeAgo)
+			fd.pfd.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 {
+	// Call ConnectEx API.
+	if err := fd.pfd.ConnectEx(ra); err != nil {
 		select {
 		case <-ctx.Done():
 			return mapErr(ctx.Err())
@@ -398,38 +124,18 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
 		}
 	}
 	// Refresh socket properties.
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
-}
-
-func (fd *netFD) destroy() {
-	if fd.sysfd == syscall.InvalidHandle {
-		return
-	}
-	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closeFunc.
-	fd.pd.close()
-	closeFunc(fd.sysfd)
-	fd.sysfd = syscall.InvalidHandle
-	// no need for a finalizer anymore
-	runtime.SetFinalizer(fd, nil)
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd))))
 }
 
 func (fd *netFD) Close() error {
-	if !fd.fdmu.increfAndClose() {
-		return errClosing
-	}
-	// unblock pending reader and writer
-	fd.pd.evict()
-	fd.decref()
-	return nil
+	runtime.SetFinalizer(fd, nil)
+	return fd.pfd.Close()
 }
 
 func (fd *netFD) shutdown(how int) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return syscall.Shutdown(fd.sysfd, how)
+	err := fd.pfd.Shutdown(how)
+	runtime.KeepAlive(fd)
+	return err
 }
 
 func (fd *netFD) closeRead() error {
@@ -441,72 +147,21 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) Read(buf []byte) (int, error) {
-	if err := fd.readLock(); err != nil {
-		return 0, err
-	}
-	defer fd.readUnlock()
-	o := &fd.rop
-	o.InitBuf(buf)
-	n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
-		return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
-	})
-	if race.Enabled {
-		race.Acquire(unsafe.Pointer(&ioSync))
-	}
-	if len(buf) != 0 {
-		err = fd.eofError(n, err)
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsarecv", err)
-	}
-	return n, err
+	n, err := fd.pfd.Read(buf)
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("wsarecv", err)
 }
 
 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
-	if len(buf) == 0 {
-		return 0, nil, nil
-	}
-	if err := fd.readLock(); err != nil {
-		return 0, nil, err
-	}
-	defer fd.readUnlock()
-	o := &fd.rop
-	o.InitBuf(buf)
-	n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
-		if o.rsa == nil {
-			o.rsa = new(syscall.RawSockaddrAny)
-		}
-		o.rsan = int32(unsafe.Sizeof(*o.rsa))
-		return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
-	})
-	err = fd.eofError(n, err)
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsarecvfrom", err)
-	}
-	if err != nil {
-		return n, nil, err
-	}
-	sa, _ := o.rsa.Sockaddr()
-	return n, sa, nil
+	n, sa, err := fd.pfd.ReadFrom(buf)
+	runtime.KeepAlive(fd)
+	return n, sa, wrapSyscallError("wsarecvfrom", err)
 }
 
 func (fd *netFD) Write(buf []byte) (int, error) {
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	if race.Enabled {
-		race.ReleaseMerge(unsafe.Pointer(&ioSync))
-	}
-	o := &fd.wop
-	o.InitBuf(buf)
-	n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
-		return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
-	})
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsasend", err)
-	}
-	return n, err
+	n, err := fd.pfd.Write(buf)
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("wsasend", err)
 }
 
 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
@@ -515,67 +170,39 @@ func (c *conn) writeBuffers(v *Buffers) (int64, error) {
 	}
 	n, err := c.fd.writeBuffers(v)
 	if err != nil {
-		return n, &OpError{Op: "WSASend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+		return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	return n, nil
 }
 
 func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
-	if len(*buf) == 0 {
-		return 0, nil
-	}
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	if race.Enabled {
-		race.ReleaseMerge(unsafe.Pointer(&ioSync))
-	}
-	o := &fd.wop
-	o.InitBufs(buf)
-	n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
-		return syscall.WSASend(o.fd.sysfd, &o.bufs[0], uint32(len(*buf)), &o.qty, 0, &o.o, nil)
-	})
-	o.ClearBufs()
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsasend", err)
-	}
-	testHookDidWritev(n)
-	buf.consume(int64(n))
-	return int64(n), err
+	n, err := fd.pfd.Writev((*[][]byte)(buf))
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("wsasend", err)
 }
 
 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
-	if len(buf) == 0 {
-		return 0, nil
-	}
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	o := &fd.wop
-	o.InitBuf(buf)
-	o.sa = sa
-	n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
-		return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
-	})
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsasendto", err)
-	}
-	return n, err
+	n, err := fd.pfd.WriteTo(buf, sa)
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("wsasendto", err)
 }
 
-func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
-	// Get new socket.
-	s, err := sysSocket(fd.family, fd.sotype, 0)
+func (fd *netFD) accept() (*netFD, error) {
+	s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
+		return sysSocket(fd.family, fd.sotype, 0)
+	})
+
 	if err != nil {
+		if errcall != "" {
+			err = wrapSyscallError(errcall, err)
+		}
 		return nil, err
 	}
 
 	// Associate our new socket with IOCP.
 	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
 	if err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, err
 	}
 	if err := netfd.init(); err != nil {
@@ -583,71 +210,11 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 		return nil, err
 	}
 
-	// Submit accept request.
-	o.handle = s
-	o.rsan = int32(unsafe.Sizeof(rawsa[0]))
-	_, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
-		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()
-		if _, ok := err.(syscall.Errno); ok {
-			err = os.NewSyscallError("acceptex", err)
-		}
-		return nil, err
-	}
-
-	// Inherit properties of the listening socket.
-	err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
-	if err != nil {
-		netfd.Close()
-		return nil, os.NewSyscallError("setsockopt", err)
-	}
-	runtime.KeepAlive(fd)
-	return netfd, nil
-}
-
-func (fd *netFD) accept() (*netFD, error) {
-	if err := fd.readLock(); err != nil {
-		return nil, err
-	}
-	defer fd.readUnlock()
-
-	o := &fd.rop
-	var netfd *netFD
-	var err error
-	var rawsa [2]syscall.RawSockaddrAny
-	for {
-		netfd, err = fd.acceptOne(rawsa[:], o)
-		if err == nil {
-			break
-		}
-		// Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is
-		// returned here. These happen if connection reset is received
-		// before AcceptEx could complete. These errors relate to new
-		// connection, not to AcceptEx, so ignore broken connection and
-		// try AcceptEx again for more connections.
-		nerr, ok := err.(*os.SyscallError)
-		if !ok {
-			return nil, err
-		}
-		errno, ok := nerr.Err.(syscall.Errno)
-		if !ok {
-			return nil, err
-		}
-		switch errno {
-		case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET:
-			// ignore these and try again
-		default:
-			return nil, err
-		}
-	}
-
 	// Get local and peer addr out of AcceptEx buffer.
 	var lrsa, rrsa *syscall.RawSockaddrAny
 	var llen, rlen int32
 	syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
-		0, uint32(o.rsan), uint32(o.rsan), &lrsa, &llen, &rrsa, &rlen)
+		0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
 	lsa, _ := lrsa.Sockaddr()
 	rsa, _ := rrsa.Sockaddr()
 
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 6566ce2..abf8b3a 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -90,7 +90,7 @@ func TestFileConn(t *testing.T) {
 			f, err = c1.File()
 		}
 		if err := c1.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Error(err)
@@ -256,7 +256,7 @@ func TestFilePacketConn(t *testing.T) {
 			f, err = c1.File()
 		}
 		if err := c1.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Error(err)
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 9e581fc..d67dff8 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"internal/poll"
 	"os"
 	"syscall"
 )
@@ -17,7 +18,7 @@ func dupSocket(f *os.File) (int, error) {
 		return -1, err
 	}
 	if err := syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
@@ -31,7 +32,7 @@ func newFileFD(f *os.File) (*netFD, error) {
 	family := syscall.AF_UNSPEC
 	sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, os.NewSyscallError("getsockopt", err)
 	}
 	lsa, _ := syscall.Getsockname(s)
@@ -44,12 +45,12 @@ func newFileFD(f *os.File) (*netFD, error) {
 	case *syscall.SockaddrUnix:
 		family = syscall.AF_UNIX
 	default:
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, syscall.EPROTONOSUPPORT
 	}
 	fd, err := newFD(s, family, sotype, "")
 	if err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, err
 	}
 	laddr := fd.addrFunc()(lsa)
diff --git a/src/net/hook_cloexec.go b/src/net/hook_cloexec.go
deleted file mode 100644
index 870f0d7..0000000
--- a/src/net/hook_cloexec.go
+++ /dev/null
@@ -1,14 +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 freebsd linux
-
-package net
-
-import "syscall"
-
-var (
-	// Placeholders for socket system calls.
-	accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
-)
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
index cf52567..fee62a9 100644
--- a/src/net/hook_unix.go
+++ b/src/net/hook_unix.go
@@ -13,10 +13,8 @@ var (
 	testHookCanceledDial = func() {} // for golang.org/issue/16523
 
 	// Placeholders for socket system calls.
-	socketFunc        func(int, int, int) (int, error)         = syscall.Socket
-	closeFunc         func(int) error                          = syscall.Close
-	connectFunc       func(int, syscall.Sockaddr) error        = syscall.Connect
-	listenFunc        func(int, int) error                     = syscall.Listen
-	acceptFunc        func(int) (int, syscall.Sockaddr, error) = syscall.Accept
-	getsockoptIntFunc func(int, int, int) (int, error)         = syscall.GetsockoptInt
+	socketFunc        func(int, int, int) (int, error)  = syscall.Socket
+	connectFunc       func(int, syscall.Sockaddr) error = syscall.Connect
+	listenFunc        func(int, int) error              = syscall.Listen
+	getsockoptIntFunc func(int, int, int) (int, error)  = syscall.GetsockoptInt
 )
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
index 63ea35a..4e64dce 100644
--- a/src/net/hook_windows.go
+++ b/src/net/hook_windows.go
@@ -13,10 +13,7 @@ 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
-	acceptFunc    func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
+	socketFunc  func(int, int, int) (syscall.Handle, error)  = syscall.Socket
+	connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
+	listenFunc  func(syscall.Handle, int) error              = syscall.Listen
 )
diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go
index 1121334..15c169d 100644
--- a/src/net/http/cgi/host_test.go
+++ b/src/net/http/cgi/host_test.go
@@ -409,7 +409,7 @@ func TestCopyError(t *testing.T) {
 	}
 
 	childRunning := func() bool {
-		return isProcessRunning(t, pid)
+		return isProcessRunning(pid)
 	}
 
 	if !childRunning() {
diff --git a/src/net/http/cgi/plan9_test.go b/src/net/http/cgi/plan9_test.go
index c823583..cc20fe0 100644
--- a/src/net/http/cgi/plan9_test.go
+++ b/src/net/http/cgi/plan9_test.go
@@ -9,10 +9,9 @@ package cgi
 import (
 	"os"
 	"strconv"
-	"testing"
 )
 
-func isProcessRunning(t *testing.T, pid int) bool {
+func isProcessRunning(pid int) bool {
 	_, err := os.Stat("/proc/" + strconv.Itoa(pid))
 	return err == nil
 }
diff --git a/src/net/http/cgi/posix_test.go b/src/net/http/cgi/posix_test.go
index 5ff9e7d..9396ce0 100644
--- a/src/net/http/cgi/posix_test.go
+++ b/src/net/http/cgi/posix_test.go
@@ -9,10 +9,9 @@ package cgi
 import (
 	"os"
 	"syscall"
-	"testing"
 )
 
-func isProcessRunning(t *testing.T, pid int) bool {
+func isProcessRunning(pid int) bool {
 	p, err := os.FindProcess(pid)
 	if err != nil {
 		return false
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 0005538..fbdc41b 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -38,20 +38,20 @@ import (
 // When following redirects, the Client will forward all headers set on the
 // initial Request except:
 //
-//	* when forwarding sensitive headers like "Authorization",
-//	  "WWW-Authenticate", and "Cookie" to untrusted targets.
-//	  These headers will be ignored when following a redirect to a domain
-//	  that is not a subdomain match or exact match of the initial domain.
-//	  For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com"
-//	  will forward the sensitive headers, but a redirect to "bar.com" will not.
-//
-//	* when forwarding the "Cookie" header with a non-nil cookie Jar.
-//	  Since each redirect may mutate the state of the cookie jar,
-//	  a redirect may possibly alter a cookie set in the initial request.
-//	  When forwarding the "Cookie" header, any mutated cookies will be omitted,
-//	  with the expectation that the Jar will insert those mutated cookies
-//	  with the updated values (assuming the origin matches).
-//	  If Jar is nil, the initial cookies are forwarded without change.
+// • when forwarding sensitive headers like "Authorization",
+// "WWW-Authenticate", and "Cookie" to untrusted targets.
+// These headers will be ignored when following a redirect to a domain
+// that is not a subdomain match or exact match of the initial domain.
+// For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com"
+// will forward the sensitive headers, but a redirect to "bar.com" will not.
+//
+// • when forwarding the "Cookie" header with a non-nil cookie Jar.
+// Since each redirect may mutate the state of the cookie jar,
+// a redirect may possibly alter a cookie set in the initial request.
+// When forwarding the "Cookie" header, any mutated cookies will be omitted,
+// with the expectation that the Jar will insert those mutated cookies
+// with the updated values (assuming the origin matches).
+// If Jar is nil, the initial cookies are forwarded without change.
 //
 type Client struct {
 	// Transport specifies the mechanism by which individual
@@ -524,10 +524,12 @@ func (c *Client) Do(req *Request) (*Response, error) {
 		if len(reqs) > 0 {
 			loc := resp.Header.Get("Location")
 			if loc == "" {
+				resp.closeBody()
 				return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode))
 			}
 			u, err := req.URL.Parse(loc)
 			if err != nil {
+				resp.closeBody()
 				return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err))
 			}
 			ireq := reqs[0]
@@ -542,6 +544,7 @@ func (c *Client) Do(req *Request) (*Response, error) {
 			if includeBody && ireq.GetBody != nil {
 				req.Body, err = ireq.GetBody()
 				if err != nil {
+					resp.closeBody()
 					return nil, uerr(err)
 				}
 				req.ContentLength = ireq.ContentLength
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 4f674dd..b9a1c31 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -10,7 +10,6 @@ import (
 	"bytes"
 	"context"
 	"crypto/tls"
-	"crypto/x509"
 	"encoding/base64"
 	"errors"
 	"fmt"
@@ -73,7 +72,7 @@ func TestClient(t *testing.T) {
 	ts := httptest.NewServer(robotsTxtHandler)
 	defer ts.Close()
 
-	c := &Client{Transport: &Transport{DisableKeepAlives: true}}
+	c := ts.Client()
 	r, err := c.Get(ts.URL)
 	var b []byte
 	if err == nil {
@@ -220,10 +219,7 @@ func TestClientRedirects(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	_, err := c.Get(ts.URL)
 	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
 		t.Errorf("with default client Get, expected error %q, got %q", e, g)
@@ -252,13 +248,10 @@ func TestClientRedirects(t *testing.T) {
 	var checkErr error
 	var lastVia []*Request
 	var lastReq *Request
-	c = &Client{
-		Transport: tr,
-		CheckRedirect: func(req *Request, via []*Request) error {
-			lastReq = req
-			lastVia = via
-			return checkErr
-		},
+	c.CheckRedirect = func(req *Request, via []*Request) error {
+		lastReq = req
+		lastVia = via
+		return checkErr
 	}
 	res, err := c.Get(ts.URL)
 	if err != nil {
@@ -304,6 +297,7 @@ func TestClientRedirects(t *testing.T) {
 	}
 }
 
+// Tests that Client redirects' contexts are derived from the original request's context.
 func TestClientRedirectContext(t *testing.T) {
 	setParallel(t)
 	defer afterTest(t)
@@ -312,19 +306,16 @@ func TestClientRedirectContext(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
 	ctx, cancel := context.WithCancel(context.Background())
-	c := &Client{
-		Transport: tr,
-		CheckRedirect: func(req *Request, via []*Request) error {
-			cancel()
-			if len(via) > 2 {
-				return errors.New("too many redirects")
-			}
+	c := ts.Client()
+	c.CheckRedirect = func(req *Request, via []*Request) error {
+		cancel()
+		select {
+		case <-req.Context().Done():
 			return nil
-		},
+		case <-time.After(5 * time.Second):
+			return errors.New("redirected request's context never expired after root request canceled")
+		}
 	}
 	req, _ := NewRequest("GET", ts.URL, nil)
 	req = req.WithContext(ctx)
@@ -458,11 +449,12 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
 	}))
 	defer ts.Close()
 
+	c := ts.Client()
 	for _, tt := range table {
 		content := tt.redirectBody
 		req, _ := NewRequest(method, ts.URL+tt.suffix, strings.NewReader(content))
 		req.GetBody = func() (io.ReadCloser, error) { return ioutil.NopCloser(strings.NewReader(content)), nil }
-		res, err := DefaultClient.Do(req)
+		res, err := c.Do(req)
 
 		if err != nil {
 			t.Fatal(err)
@@ -516,17 +508,12 @@ func TestClientRedirectUseResponse(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
-	c := &Client{
-		Transport: tr,
-		CheckRedirect: func(req *Request, via []*Request) error {
-			if req.Response == nil {
-				t.Error("expected non-nil Request.Response")
-			}
-			return ErrUseLastResponse
-		},
+	c := ts.Client()
+	c.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 {
@@ -555,7 +542,8 @@ func TestClientRedirect308NoLocation(t *testing.T) {
 		w.WriteHeader(308)
 	}))
 	defer ts.Close()
-	res, err := Get(ts.URL)
+	c := ts.Client()
+	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -582,8 +570,9 @@ func TestClientRedirect308NoGetBody(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
+	c := ts.Client()
 	req.GetBody = nil // so it can't rewind.
-	res, err := DefaultClient.Do(req)
+	res, err := c.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -673,12 +662,8 @@ func TestRedirectCookiesJar(t *testing.T) {
 	var ts *httptest.Server
 	ts = httptest.NewServer(echoCookiesRedirectHandler)
 	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{
-		Transport: tr,
-		Jar:       new(TestJar),
-	}
+	c := ts.Client()
+	c.Jar = new(TestJar)
 	u, _ := url.Parse(ts.URL)
 	c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
 	resp, err := c.Get(ts.URL)
@@ -722,13 +707,10 @@ func TestJarCalls(t *testing.T) {
 	}))
 	defer ts.Close()
 	jar := new(RecordingJar)
-	c := &Client{
-		Jar: jar,
-		Transport: &Transport{
-			Dial: func(_ string, _ string) (net.Conn, error) {
-				return net.Dial("tcp", ts.Listener.Addr().String())
-			},
-		},
+	c := ts.Client()
+	c.Jar = jar
+	c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) {
+		return net.Dial("tcp", ts.Listener.Addr().String())
 	}
 	_, err := c.Get("http://firsthost.fake/")
 	if err != nil {
@@ -840,7 +822,8 @@ func TestClientWrites(t *testing.T) {
 		}
 		return c, err
 	}
-	c := &Client{Transport: &Transport{Dial: dialer}}
+	c := ts.Client()
+	c.Transport.(*Transport).Dial = dialer
 
 	_, err := c.Get(ts.URL)
 	if err != nil {
@@ -873,14 +856,11 @@ func TestClientInsecureTransport(t *testing.T) {
 	// TODO(bradfitz): add tests for skipping hostname checks too?
 	// would require a new cert for testing, and probably
 	// redundant with these tests.
+	c := ts.Client()
 	for _, insecure := range []bool{true, false} {
-		tr := &Transport{
-			TLSClientConfig: &tls.Config{
-				InsecureSkipVerify: insecure,
-			},
+		c.Transport.(*Transport).TLSClientConfig = &tls.Config{
+			InsecureSkipVerify: insecure,
 		}
-		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
 		res, err := c.Get(ts.URL)
 		if (err == nil) != insecure {
 			t.Errorf("insecure=%v: got unexpected err=%v", insecure, err)
@@ -914,22 +894,6 @@ func TestClientErrorWithRequestURI(t *testing.T) {
 	}
 }
 
-func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport {
-	certs := x509.NewCertPool()
-	for _, c := range ts.TLS.Certificates {
-		roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
-		if err != nil {
-			t.Fatalf("error parsing server's root cert: %v", err)
-		}
-		for _, root := range roots {
-			certs.AddCert(root)
-		}
-	}
-	return &Transport{
-		TLSClientConfig: &tls.Config{RootCAs: certs},
-	}
-}
-
 func TestClientWithCorrectTLSServerName(t *testing.T) {
 	defer afterTest(t)
 
@@ -941,9 +905,8 @@ func TestClientWithCorrectTLSServerName(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	trans := newTLSTransport(t, ts)
-	trans.TLSClientConfig.ServerName = serverName
-	c := &Client{Transport: trans}
+	c := ts.Client()
+	c.Transport.(*Transport).TLSClientConfig.ServerName = serverName
 	if _, err := c.Get(ts.URL); err != nil {
 		t.Fatalf("expected successful TLS connection, got error: %v", err)
 	}
@@ -956,9 +919,8 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
 	errc := make(chanWriter, 10) // but only expecting 1
 	ts.Config.ErrorLog = log.New(errc, "", 0)
 
-	trans := newTLSTransport(t, ts)
-	trans.TLSClientConfig.ServerName = "badserver"
-	c := &Client{Transport: trans}
+	c := ts.Client()
+	c.Transport.(*Transport).TLSClientConfig.ServerName = "badserver"
 	_, err := c.Get(ts.URL)
 	if err == nil {
 		t.Fatalf("expected an error")
@@ -992,13 +954,12 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := newTLSTransport(t, ts)
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 	tr.TLSClientConfig.ServerName = "example.com" // one of httptest's Server cert names
 	tr.Dial = func(netw, addr string) (net.Conn, error) {
 		return net.Dial(netw, ts.Listener.Addr().String())
 	}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
 	res, err := c.Get("https://some-other-host.tld/")
 	if err != nil {
 		t.Fatal(err)
@@ -1013,13 +974,12 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := newTLSTransport(t, ts)
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 	tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
 	tr.Dial = func(netw, addr string) (net.Conn, error) {
 		return net.Dial(netw, ts.Listener.Addr().String())
 	}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
 	res, err := c.Get("https://example.com/")
 	if err != nil {
 		t.Fatal(err)
@@ -1114,14 +1074,12 @@ func TestEmptyPasswordAuth(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
 	req, err := NewRequest("GET", ts.URL, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	req.URL.User = url.User(gopher)
+	c := ts.Client()
 	resp, err := c.Do(req)
 	if err != nil {
 		t.Fatal(err)
@@ -1498,21 +1456,17 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) {
 	defer ts2.Close()
 	ts2URL = ts2.URL
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{
-		Transport: tr,
-		CheckRedirect: func(r *Request, via []*Request) error {
-			want := Header{
-				"User-Agent": []string{ua},
-				"X-Foo":      []string{xfoo},
-				"Referer":    []string{ts2URL},
-			}
-			if !reflect.DeepEqual(r.Header, want) {
-				t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want)
-			}
-			return nil
-		},
+	c := ts1.Client()
+	c.CheckRedirect = func(r *Request, via []*Request) error {
+		want := Header{
+			"User-Agent": []string{ua},
+			"X-Foo":      []string{xfoo},
+			"Referer":    []string{ts2URL},
+		}
+		if !reflect.DeepEqual(r.Header, want) {
+			t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want)
+		}
+		return nil
 	}
 
 	req, _ := NewRequest("GET", ts2.URL, nil)
@@ -1601,13 +1555,9 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
 	jar, _ := cookiejar.New(nil)
-	c := &Client{
-		Transport: tr,
-		Jar:       jar,
-	}
+	c := ts.Client()
+	c.Jar = jar
 
 	u, _ := url.Parse(ts.URL)
 	req, _ := NewRequest("GET", ts.URL, nil)
@@ -1725,9 +1675,7 @@ func TestClientRedirectTypes(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
+	c := ts.Client()
 	for i, tt := range tests {
 		handlerc <- func(w ResponseWriter, r *Request) {
 			w.Header().Set("Location", ts.URL)
@@ -1740,7 +1688,6 @@ func TestClientRedirectTypes(t *testing.T) {
 			continue
 		}
 
-		c := &Client{Transport: tr}
 		c.CheckRedirect = func(req *Request, via []*Request) error {
 			if got, want := req.Method, tt.wantMethod; got != want {
 				return fmt.Errorf("#%d: got next method %q; want %q", i, got, want)
@@ -1780,8 +1727,8 @@ func (b issue18239Body) Close() error {
 	return nil
 }
 
-// Issue 18239: make sure the Transport doesn't retry requests with bodies.
-// (Especially if Request.GetBody is not defined.)
+// Issue 18239: make sure the Transport doesn't retry requests with bodies
+// if Request.GetBody is not defined.
 func TestTransportBodyReadError(t *testing.T) {
 	setParallel(t)
 	defer afterTest(t)
@@ -1794,9 +1741,8 @@ func TestTransportBodyReadError(t *testing.T) {
 		w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err))
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	// Do one initial successful request to create an idle TCP connection
 	// for the subsequent request to reuse. (The Transport only retries
@@ -1816,6 +1762,7 @@ func TestTransportBodyReadError(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
+	req = req.WithT(t)
 	_, err = tr.RoundTrip(req)
 	if err != someErr {
 		t.Errorf("Got error: %v; want Request.Body read error: %v", err, someErr)
diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go
index 5a67476..cf52248 100644
--- a/src/net/http/cookie.go
+++ b/src/net/http/cookie.go
@@ -328,7 +328,7 @@ func sanitizeCookieValue(v string) string {
 	if len(v) == 0 {
 		return v
 	}
-	if v[0] == ' ' || v[0] == ',' || v[len(v)-1] == ' ' || v[len(v)-1] == ',' {
+	if strings.IndexByte(v, ' ') >= 0 || strings.IndexByte(v, ',') >= 0 {
 		return `"` + v + `"`
 	}
 	return v
diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go
index b3e54f8..9d199a3 100644
--- a/src/net/http/cookie_test.go
+++ b/src/net/http/cookie_test.go
@@ -69,7 +69,7 @@ var writeSetCookiesTests = []struct {
 	// are disallowed by RFC 6265 but are common in the wild.
 	{
 		&Cookie{Name: "special-1", Value: "a z"},
-		`special-1=a z`,
+		`special-1="a z"`,
 	},
 	{
 		&Cookie{Name: "special-2", Value: " z"},
@@ -85,7 +85,7 @@ var writeSetCookiesTests = []struct {
 	},
 	{
 		&Cookie{Name: "special-5", Value: "a,z"},
-		`special-5=a,z`,
+		`special-5="a,z"`,
 	},
 	{
 		&Cookie{Name: "special-6", Value: ",z"},
@@ -398,9 +398,12 @@ func TestCookieSanitizeValue(t *testing.T) {
 		{"foo\"bar", "foobar"},
 		{"\x00\x7e\x7f\x80", "\x7e"},
 		{`"withquotes"`, "withquotes"},
-		{"a z", "a z"},
+		{"a z", `"a z"`},
 		{" z", `" z"`},
 		{"a ", `"a "`},
+		{"a,z", `"a,z"`},
+		{",z", `",z"`},
+		{"a,", `"a,"`},
 	}
 	for _, tt := range tests {
 		if got := sanitizeCookieValue(tt.in); got != tt.want {
diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go
index f89abbc..ef8c35b 100644
--- a/src/net/http/cookiejar/jar.go
+++ b/src/net/http/cookiejar/jar.go
@@ -331,7 +331,7 @@ func jarKey(host string, psl PublicSuffixList) string {
 	var i int
 	if psl == nil {
 		i = strings.LastIndex(host, ".")
-		if i == -1 {
+		if i <= 0 {
 			return host
 		}
 	} else {
@@ -345,6 +345,9 @@ func jarKey(host string, psl PublicSuffixList) string {
 			// Storing cookies under host is a safe stopgap.
 			return host
 		}
+		// Only len(suffix) is used to determine the jar key from
+		// here on, so it is okay if psl.PublicSuffix("www.buggy.psl")
+		// returns "com" as the jar key is generated from host.
 	}
 	prevDot := strings.LastIndex(host[:i-1], ".")
 	return host[prevDot+1:]
diff --git a/src/net/http/cookiejar/jar_test.go b/src/net/http/cookiejar/jar_test.go
index 3aa6015..47fb1ab 100644
--- a/src/net/http/cookiejar/jar_test.go
+++ b/src/net/http/cookiejar/jar_test.go
@@ -19,6 +19,9 @@ var tNow = time.Date(2013, 1, 1, 12, 0, 0, 0, time.UTC)
 
 // testPSL implements PublicSuffixList with just two rules: "co.uk"
 // and the default rule "*".
+// The implementation has two intentional bugs:
+//    PublicSuffix("www.buggy.psl") == "xy"
+//    PublicSuffix("www2.buggy.psl") == "com"
 type testPSL struct{}
 
 func (testPSL) String() string {
@@ -28,6 +31,12 @@ func (testPSL) PublicSuffix(d string) string {
 	if d == "co.uk" || strings.HasSuffix(d, ".co.uk") {
 		return "co.uk"
 	}
+	if d == "www.buggy.psl" {
+		return "xy"
+	}
+	if d == "www2.buggy.psl" {
+		return "com"
+	}
 	return d[strings.LastIndex(d, ".")+1:]
 }
 
@@ -125,6 +134,17 @@ var canonicalHostTests = map[string]string{
 	"[2001:4860:0:::68]:8080": "2001:4860:0:::68",
 	"www.bücher.de":           "www.xn--bcher-kva.de",
 	"www.example.com.":        "www.example.com",
+	// TODO: Fix canonicalHost so that all of the following malformed
+	// domain names trigger an error. (This list is not exhaustive, e.g.
+	// malformed internationalized domain names are missing.)
+	".":                       "",
+	"..":                      ".",
+	"...":                     "..",
+	".net":                    ".net",
+	".net.":                   ".net",
+	"a..":                     "a.",
+	"b.a..":                   "b.a.",
+	"weird.stuff...":          "weird.stuff..",
 	"[bad.unmatched.bracket:": "error",
 }
 
@@ -133,7 +153,7 @@ func TestCanonicalHost(t *testing.T) {
 		got, err := canonicalHost(h)
 		if want == "error" {
 			if err == nil {
-				t.Errorf("%q: got nil error, want non-nil", h)
+				t.Errorf("%q: got %q and nil error, want non-nil", h, got)
 			}
 			continue
 		}
@@ -176,6 +196,17 @@ var jarKeyTests = map[string]string{
 	"co.uk":               "co.uk",
 	"uk":                  "uk",
 	"192.168.0.5":         "192.168.0.5",
+	"www.buggy.psl":       "www.buggy.psl",
+	"www2.buggy.psl":      "buggy.psl",
+	// The following are actual outputs of canonicalHost for
+	// malformed inputs to canonicalHost (see above).
+	"":              "",
+	".":             ".",
+	"..":            ".",
+	".net":          ".net",
+	"a.":            "a.",
+	"b.a.":          "a.",
+	"weird.stuff..": ".",
 }
 
 func TestJarKey(t *testing.T) {
@@ -197,6 +228,15 @@ var jarKeyNilPSLTests = map[string]string{
 	"co.uk":               "co.uk",
 	"uk":                  "uk",
 	"192.168.0.5":         "192.168.0.5",
+	// The following are actual outputs of canonicalHost for
+	// malformed inputs to canonicalHost.
+	"":              "",
+	".":             ".",
+	"..":            "..",
+	".net":          ".net",
+	"a.":            "a.",
+	"b.a.":          "a.",
+	"weird.stuff..": "stuff..",
 }
 
 func TestJarKeyNilPSL(t *testing.T) {
@@ -1265,3 +1305,18 @@ func TestDomainHandling(t *testing.T) {
 		test.run(t, jar)
 	}
 }
+
+func TestIssue19384(t *testing.T) {
+	cookies := []*http.Cookie{{Name: "name", Value: "value"}}
+	for _, host := range []string{"", ".", "..", "..."} {
+		jar, _ := New(nil)
+		u := &url.URL{Scheme: "http", Host: host, Path: "/"}
+		if got := jar.Cookies(u); len(got) != 0 {
+			t.Errorf("host %q, got %v", host, got)
+		}
+		jar.SetCookies(u, cookies)
+		if got := jar.Cookies(u); len(got) != 1 || got[0].Value != "value" {
+			t.Errorf("host %q, got %v", host, got)
+		}
+	}
+}
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index b61f58b..2ef145e 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -8,24 +8,29 @@
 package http
 
 import (
+	"context"
 	"net"
 	"sort"
 	"sync"
+	"testing"
 	"time"
 )
 
 var (
-	DefaultUserAgent             = defaultUserAgent
-	NewLoggingConn               = newLoggingConn
-	ExportAppendTime             = appendTime
-	ExportRefererForURL          = refererForURL
-	ExportServerNewConn          = (*Server).newConn
-	ExportCloseWriteAndWait      = (*conn).closeWriteAndWait
-	ExportErrRequestCanceled     = errRequestCanceled
-	ExportErrRequestCanceledConn = errRequestCanceledConn
-	ExportServeFile              = serveFile
-	ExportScanETag               = scanETag
-	ExportHttp2ConfigureServer   = http2ConfigureServer
+	DefaultUserAgent                  = defaultUserAgent
+	NewLoggingConn                    = newLoggingConn
+	ExportAppendTime                  = appendTime
+	ExportRefererForURL               = refererForURL
+	ExportServerNewConn               = (*Server).newConn
+	ExportCloseWriteAndWait           = (*conn).closeWriteAndWait
+	ExportErrRequestCanceled          = errRequestCanceled
+	ExportErrRequestCanceledConn      = errRequestCanceledConn
+	ExportErrServerClosedIdle         = errServerClosedIdle
+	ExportServeFile                   = serveFile
+	ExportScanETag                    = scanETag
+	ExportHttp2ConfigureServer        = http2ConfigureServer
+	Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect
+	Export_writeStatusLine            = writeStatusLine
 )
 
 func init() {
@@ -186,8 +191,6 @@ func ExportHttp2ConfigureTransport(t *Transport) error {
 	return nil
 }
 
-var Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect
-
 func (s *Server) ExportAllConnsIdle() bool {
 	s.mu.Lock()
 	defer s.mu.Unlock()
@@ -199,3 +202,7 @@ func (s *Server) ExportAllConnsIdle() bool {
 	}
 	return true
 }
+
+func (r *Request) WithT(t *testing.T) *Request {
+	return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf))
+}
diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go
index 8870424..30a6b2c 100644
--- a/src/net/http/fcgi/child.go
+++ b/src/net/http/fcgi/child.go
@@ -7,6 +7,7 @@ package fcgi
 // This file implements FastCGI from the perspective of a child process.
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"io"
@@ -31,6 +32,10 @@ type request struct {
 	keepConn  bool
 }
 
+// envVarsContextKey uniquely identifies a mapping of CGI
+// environment variables to their values in a request context
+type envVarsContextKey struct{}
+
 func newRequest(reqId uint16, flags uint8) *request {
 	r := &request{
 		reqId:    reqId,
@@ -259,6 +264,18 @@ func (c *child) handleRecord(rec *record) error {
 	}
 }
 
+// filterOutUsedEnvVars returns a new map of env vars without the
+// variables in the given envVars map that are read for creating each http.Request
+func filterOutUsedEnvVars(envVars map[string]string) map[string]string {
+	withoutUsedEnvVars := make(map[string]string)
+	for k, v := range envVars {
+		if addFastCGIEnvToContext(k) {
+			withoutUsedEnvVars[k] = v
+		}
+	}
+	return withoutUsedEnvVars
+}
+
 func (c *child) serveRequest(req *request, body io.ReadCloser) {
 	r := newResponse(c, req)
 	httpReq, err := cgi.RequestFromMap(req.params)
@@ -268,6 +285,9 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
 		c.conn.writeRecord(typeStderr, req.reqId, []byte(err.Error()))
 	} else {
 		httpReq.Body = body
+		withoutUsedEnvVars := filterOutUsedEnvVars(req.params)
+		envVarCtx := context.WithValue(httpReq.Context(), envVarsContextKey{}, withoutUsedEnvVars)
+		httpReq = httpReq.WithContext(envVarCtx)
 		c.handler.ServeHTTP(r, httpReq)
 	}
 	r.Close()
@@ -329,3 +349,39 @@ func Serve(l net.Listener, handler http.Handler) error {
 		go c.serve()
 	}
 }
+
+// ProcessEnv returns FastCGI environment variables associated with the request r
+// for which no effort was made to be included in the request itself - the data
+// is hidden in the request's context. As an example, if REMOTE_USER is set for a
+// request, it will not be found anywhere in r, but it will be included in
+// ProcessEnv's response (via r's context).
+func ProcessEnv(r *http.Request) map[string]string {
+	env, _ := r.Context().Value(envVarsContextKey{}).(map[string]string)
+	return env
+}
+
+// addFastCGIEnvToContext reports whether to include the FastCGI environment variable s
+// in the http.Request.Context, accessible via ProcessEnv.
+func addFastCGIEnvToContext(s string) bool {
+	// Exclude things supported by net/http natively:
+	switch s {
+	case "CONTENT_LENGTH", "CONTENT_TYPE", "HTTPS",
+		"PATH_INFO", "QUERY_STRING", "REMOTE_ADDR",
+		"REMOTE_HOST", "REMOTE_PORT", "REQUEST_METHOD",
+		"REQUEST_URI", "SCRIPT_NAME", "SERVER_PROTOCOL":
+		return false
+	}
+	if strings.HasPrefix(s, "HTTP_") {
+		return false
+	}
+	// Explicitly include FastCGI-specific things.
+	// This list is redundant with the default "return true" below.
+	// Consider this documentation of the sorts of things we expect
+	// to maybe see.
+	switch s {
+	case "REMOTE_USER":
+		return true
+	}
+	// Unknown, so include it to be safe.
+	return true
+}
diff --git a/src/net/http/fcgi/fcgi.go b/src/net/http/fcgi/fcgi.go
index 5057d70..8f3449a 100644
--- a/src/net/http/fcgi/fcgi.go
+++ b/src/net/http/fcgi/fcgi.go
@@ -24,7 +24,7 @@ import (
 )
 
 // recType is a record type, as defined by
-// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8
+// https://web.archive.org/web/20150420080736/http://www.fastcgi.com/drupal/node/6?q=node/22#S8
 type recType uint8
 
 const (
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index b6013bf..e9d2b34 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -278,3 +278,69 @@ func TestMalformedParams(t *testing.T) {
 	c := newChild(rw, http.DefaultServeMux)
 	c.serve()
 }
+
+// a series of FastCGI records that start and end a request
+var streamFullRequestStdin = bytes.Join([][]byte{
+	// set up request
+	makeRecord(typeBeginRequest, 1,
+		[]byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}),
+	// add required parameters
+	makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")),
+	makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")),
+	// set optional parameters
+	makeRecord(typeParams, 1, nameValuePair11("REMOTE_USER", "jane.doe")),
+	makeRecord(typeParams, 1, nameValuePair11("QUERY_STRING", "/foo/bar")),
+	makeRecord(typeParams, 1, nil),
+	// begin sending body of request
+	makeRecord(typeStdin, 1, []byte("0123456789abcdef")),
+	// end request
+	makeRecord(typeEndRequest, 1, nil),
+},
+	nil)
+
+var envVarTests = []struct {
+	input               []byte
+	envVar              string
+	expectedVal         string
+	expectedFilteredOut bool
+}{
+	{
+		streamFullRequestStdin,
+		"REMOTE_USER",
+		"jane.doe",
+		false,
+	},
+	{
+		streamFullRequestStdin,
+		"QUERY_STRING",
+		"",
+		true,
+	},
+}
+
+// Test that environment variables set for a request can be
+// read by a handler. Ensures that variables not set will not
+// be exposed to a handler.
+func TestChildServeReadsEnvVars(t *testing.T) {
+	for _, tt := range envVarTests {
+		input := make([]byte, len(tt.input))
+		copy(input, tt.input)
+		rc := nopWriteCloser{bytes.NewBuffer(input)}
+		done := make(chan bool)
+		c := newChild(rc, http.HandlerFunc(func(
+			w http.ResponseWriter,
+			r *http.Request,
+		) {
+			env := ProcessEnv(r)
+			if _, ok := env[tt.envVar]; ok && tt.expectedFilteredOut {
+				t.Errorf("Expected environment variable %s to not be set, but set to %s",
+					tt.envVar, env[tt.envVar])
+			} else if env[tt.envVar] != tt.expectedVal {
+				t.Errorf("Expected %s, got %s", tt.expectedVal, env[tt.envVar])
+			}
+			done <- true
+		}))
+		go c.serve()
+		<-done
+	}
+}
diff --git a/src/net/http/filetransport_test.go b/src/net/http/filetransport_test.go
index 6f1a537..2a2f32c 100644
--- a/src/net/http/filetransport_test.go
+++ b/src/net/http/filetransport_test.go
@@ -49,6 +49,7 @@ func TestFileTransport(t *testing.T) {
 			t.Fatalf("for %s, nil Body", urlstr)
 		}
 		slurp, err := ioutil.ReadAll(res.Body)
+		res.Body.Close()
 		check("ReadAll "+urlstr, err)
 		if string(slurp) != "Bar" {
 			t.Errorf("for %s, got content %q, want %q", urlstr, string(slurp), "Bar")
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index bf63bb5..90a3729 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -33,18 +33,42 @@ import (
 // An empty Dir is treated as ".".
 type Dir string
 
+// mapDirOpenError maps the provided non-nil error from opening name
+// to a possibly better non-nil error. In particular, it turns OS-specific errors
+// about opening files in non-directories into os.ErrNotExist. See Issue 18984.
+func mapDirOpenError(originalErr error, name string) error {
+	if os.IsNotExist(originalErr) || os.IsPermission(originalErr) {
+		return originalErr
+	}
+
+	parts := strings.Split(name, string(filepath.Separator))
+	for i := range parts {
+		if parts[i] == "" {
+			continue
+		}
+		fi, err := os.Stat(strings.Join(parts[:i+1], string(filepath.Separator)))
+		if err != nil {
+			return originalErr
+		}
+		if !fi.IsDir() {
+			return os.ErrNotExist
+		}
+	}
+	return originalErr
+}
+
 func (d Dir) Open(name string) (File, error) {
-	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
-		strings.Contains(name, "\x00") {
+	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
 		return nil, errors.New("http: invalid character in file path")
 	}
 	dir := string(d)
 	if dir == "" {
 		dir = "."
 	}
-	f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))
+	fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
+	f, err := os.Open(fullName)
 	if err != nil {
-		return nil, err
+		return nil, mapDirOpenError(err, fullName)
 	}
 	return f, nil
 }
@@ -291,7 +315,7 @@ func scanETag(s string) (etag string, remain string) {
 		case c == '"':
 			return string(s[:i+1]), s[i+1:]
 		default:
-			break
+			return "", ""
 		}
 	}
 	return "", ""
@@ -349,7 +373,7 @@ func checkIfMatch(w ResponseWriter, r *Request) condResult {
 	return condFalse
 }
 
-func checkIfUnmodifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+func checkIfUnmodifiedSince(r *Request, modtime time.Time) condResult {
 	ius := r.Header.Get("If-Unmodified-Since")
 	if ius == "" || isZeroTime(modtime) {
 		return condNone
@@ -394,7 +418,7 @@ func checkIfNoneMatch(w ResponseWriter, r *Request) condResult {
 	return condTrue
 }
 
-func checkIfModifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+func checkIfModifiedSince(r *Request, modtime time.Time) condResult {
 	if r.Method != "GET" && r.Method != "HEAD" {
 		return condNone
 	}
@@ -479,7 +503,7 @@ func checkPreconditions(w ResponseWriter, r *Request, modtime time.Time) (done b
 	// This function carefully follows RFC 7232 section 6.
 	ch := checkIfMatch(w, r)
 	if ch == condNone {
-		ch = checkIfUnmodifiedSince(w, r, modtime)
+		ch = checkIfUnmodifiedSince(r, modtime)
 	}
 	if ch == condFalse {
 		w.WriteHeader(StatusPreconditionFailed)
@@ -495,7 +519,7 @@ func checkPreconditions(w ResponseWriter, r *Request, modtime time.Time) (done b
 			return true, ""
 		}
 	case condNone:
-		if checkIfModifiedSince(w, r, modtime) == condFalse {
+		if checkIfModifiedSince(r, modtime) == condFalse {
 			writeNotModified(w)
 			return true, ""
 		}
@@ -580,7 +604,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 
 	// Still a directory? (we didn't find an index.html file)
 	if d.IsDir() {
-		if checkIfModifiedSince(w, r, d.ModTime()) == condFalse {
+		if checkIfModifiedSince(r, d.ModTime()) == condFalse {
 			writeNotModified(w)
 			return
 		}
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 17a0e4a..f1037c4 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -74,6 +74,7 @@ func TestServeFile(t *testing.T) {
 		ServeFile(w, r, "testdata/file")
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
 	var err error
 
@@ -91,7 +92,7 @@ func TestServeFile(t *testing.T) {
 	req.Method = "GET"
 
 	// straight GET
-	_, body := getBody(t, "straight get", req)
+	_, body := getBody(t, "straight get", req, c)
 	if !bytes.Equal(body, file) {
 		t.Fatalf("body mismatch: got %q, want %q", body, file)
 	}
@@ -102,7 +103,7 @@ Cases:
 		if rt.r != "" {
 			req.Header.Set("Range", rt.r)
 		}
-		resp, body := getBody(t, fmt.Sprintf("range test %q", rt.r), req)
+		resp, body := getBody(t, fmt.Sprintf("range test %q", rt.r), req, c)
 		if resp.StatusCode != rt.code {
 			t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, resp.StatusCode, rt.code)
 		}
@@ -704,7 +705,8 @@ func TestDirectoryIfNotModified(t *testing.T) {
 	req, _ := NewRequest("GET", ts.URL, nil)
 	req.Header.Set("If-Modified-Since", lastMod)
 
-	res, err = DefaultClient.Do(req)
+	c := ts.Client()
+	res, err = c.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -716,7 +718,7 @@ func TestDirectoryIfNotModified(t *testing.T) {
 	// Advance the index.html file's modtime, but not the directory's.
 	indexFile.modtime = indexFile.modtime.Add(1 * time.Hour)
 
-	res, err = DefaultClient.Do(req)
+	res, err = c.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -995,7 +997,9 @@ func TestServeContent(t *testing.T) {
 		for k, v := range tt.reqHeader {
 			req.Header.Set(k, v)
 		}
-		res, err := DefaultClient.Do(req)
+
+		c := ts.Client()
+		res, err := c.Do(req)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1050,8 +1054,9 @@ func TestServeContentErrorMessages(t *testing.T) {
 	}
 	ts := httptest.NewServer(FileServer(fs))
 	defer ts.Close()
+	c := ts.Client()
 	for _, code := range []int{403, 404, 500} {
-		res, err := DefaultClient.Get(fmt.Sprintf("%s/%d", ts.URL, code))
+		res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, code))
 		if err != nil {
 			t.Errorf("Error fetching /%d: %v", code, err)
 			continue
@@ -1086,12 +1091,15 @@ func TestLinuxSendfile(t *testing.T) {
 
 	syscalls := "sendfile,sendfile64"
 	switch runtime.GOARCH {
-	case "mips64le", "s390x":
+	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"
-	case "mips64":
-		t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/33430")
+	}
+
+	// Attempt to run strace, and skip on failure - this test requires SYS_PTRACE.
+	if err := exec.Command("strace", "-f", "-q", "-e", "trace="+syscalls, os.Args[0], "-test.run=^$").Run(); err != nil {
+		t.Skipf("skipping; failed to run strace: %v", err)
 	}
 
 	var buf bytes.Buffer
@@ -1125,8 +1133,8 @@ func TestLinuxSendfile(t *testing.T) {
 	}
 }
 
-func getBody(t *testing.T, testName string, req Request) (*Response, []byte) {
-	r, err := DefaultClient.Do(&req)
+func getBody(t *testing.T, testName string, req Request, client *Client) (*Response, []byte) {
+	r, err := client.Do(&req)
 	if err != nil {
 		t.Fatalf("%s: for URL %q, send error: %v", testName, req.URL.String(), err)
 	}
@@ -1161,6 +1169,50 @@ func TestLinuxSendfileChild(*testing.T) {
 	}
 }
 
+// Issue 18984: tests that requests for paths beyond files return not-found errors
+func TestFileServerNotDirError(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(FileServer(Dir("testdata")))
+	defer ts.Close()
+
+	res, err := Get(ts.URL + "/index.html/not-a-file")
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+	if res.StatusCode != 404 {
+		t.Errorf("StatusCode = %v; want 404", res.StatusCode)
+	}
+
+	test := func(name string, dir Dir) {
+		t.Run(name, func(t *testing.T) {
+			_, err = dir.Open("/index.html/not-a-file")
+			if err == nil {
+				t.Fatal("err == nil; want != nil")
+			}
+			if !os.IsNotExist(err) {
+				t.Errorf("err = %v; os.IsNotExist(err) = %v; want true", err, os.IsNotExist(err))
+			}
+
+			_, err = dir.Open("/index.html/not-a-dir/not-a-file")
+			if err == nil {
+				t.Fatal("err == nil; want != nil")
+			}
+			if !os.IsNotExist(err) {
+				t.Errorf("err = %v; os.IsNotExist(err) = %v; want true", err, os.IsNotExist(err))
+			}
+		})
+	}
+
+	absPath, err := filepath.Abs("testdata")
+	if err != nil {
+		t.Fatal("get abs path:", err)
+	}
+
+	test("RelativePath", Dir("testdata"))
+	test("AbsolutePath", Dir(absPath))
+}
+
 func TestFileServerCleanPath(t *testing.T) {
 	tests := []struct {
 		path     string
@@ -1210,10 +1262,10 @@ func Test_scanETag(t *testing.T) {
 		{`"etag-2"`, `"etag-2"`, ""},
 		{`"etag-1", "etag-2"`, `"etag-1"`, `, "etag-2"`},
 		{"", "", ""},
-		{"", "", ""},
 		{"W/", "", ""},
 		{`W/"truc`, "", ""},
 		{`w/"case-sensitive"`, "", ""},
+		{`"spaced etag"`, "", ""},
 	}
 	for _, test := range tests {
 		etag, remain := ExportScanETag(test.in)
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index e473bb2..671e0f7 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -48,6 +48,642 @@ import (
 	"golang_org/x/net/lex/httplex"
 )
 
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.txt
+
+const (
+	http2cipher_TLS_NULL_WITH_NULL_NULL               uint16 = 0x0000
+	http2cipher_TLS_RSA_WITH_NULL_MD5                 uint16 = 0x0001
+	http2cipher_TLS_RSA_WITH_NULL_SHA                 uint16 = 0x0002
+	http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5        uint16 = 0x0003
+	http2cipher_TLS_RSA_WITH_RC4_128_MD5              uint16 = 0x0004
+	http2cipher_TLS_RSA_WITH_RC4_128_SHA              uint16 = 0x0005
+	http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5    uint16 = 0x0006
+	http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA             uint16 = 0x0007
+	http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA     uint16 = 0x0008
+	http2cipher_TLS_RSA_WITH_DES_CBC_SHA              uint16 = 0x0009
+	http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA         uint16 = 0x000A
+	http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA  uint16 = 0x000B
+	http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA           uint16 = 0x000C
+	http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA      uint16 = 0x000D
+	http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA  uint16 = 0x000E
+	http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA           uint16 = 0x000F
+	http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA      uint16 = 0x0010
+	http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
+	http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA          uint16 = 0x0012
+	http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA     uint16 = 0x0013
+	http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
+	http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA          uint16 = 0x0015
+	http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA     uint16 = 0x0016
+	http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5    uint16 = 0x0017
+	http2cipher_TLS_DH_anon_WITH_RC4_128_MD5          uint16 = 0x0018
+	http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
+	http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA          uint16 = 0x001A
+	http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA     uint16 = 0x001B
+	// Reserved uint16 =  0x001C-1D
+	http2cipher_TLS_KRB5_WITH_DES_CBC_SHA             uint16 = 0x001E
+	http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA        uint16 = 0x001F
+	http2cipher_TLS_KRB5_WITH_RC4_128_SHA             uint16 = 0x0020
+	http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA            uint16 = 0x0021
+	http2cipher_TLS_KRB5_WITH_DES_CBC_MD5             uint16 = 0x0022
+	http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5        uint16 = 0x0023
+	http2cipher_TLS_KRB5_WITH_RC4_128_MD5             uint16 = 0x0024
+	http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5            uint16 = 0x0025
+	http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA   uint16 = 0x0026
+	http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA   uint16 = 0x0027
+	http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA       uint16 = 0x0028
+	http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5   uint16 = 0x0029
+	http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5   uint16 = 0x002A
+	http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5       uint16 = 0x002B
+	http2cipher_TLS_PSK_WITH_NULL_SHA                 uint16 = 0x002C
+	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA             uint16 = 0x002D
+	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA             uint16 = 0x002E
+	http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA          uint16 = 0x002F
+	http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA       uint16 = 0x0030
+	http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA       uint16 = 0x0031
+	http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA      uint16 = 0x0032
+	http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA      uint16 = 0x0033
+	http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA      uint16 = 0x0034
+	http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA          uint16 = 0x0035
+	http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA       uint16 = 0x0036
+	http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA       uint16 = 0x0037
+	http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA      uint16 = 0x0038
+	http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0x0039
+	http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA      uint16 = 0x003A
+	http2cipher_TLS_RSA_WITH_NULL_SHA256              uint16 = 0x003B
+	http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256       uint16 = 0x003C
+	http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256       uint16 = 0x003D
+	http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256    uint16 = 0x003E
+	http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256    uint16 = 0x003F
+	http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256   uint16 = 0x0040
+	http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA     uint16 = 0x0041
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA  uint16 = 0x0042
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA  uint16 = 0x0043
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
+	// Reserved uint16 =  0x0047-4F
+	// Reserved uint16 =  0x0050-58
+	// Reserved uint16 =  0x0059-5C
+	// Unassigned uint16 =  0x005D-5F
+	// Reserved uint16 =  0x0060-66
+	http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
+	http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256  uint16 = 0x0068
+	http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256  uint16 = 0x0069
+	http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
+	http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
+	http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
+	http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
+	// Unassigned uint16 =  0x006E-83
+	http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA        uint16 = 0x0084
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA     uint16 = 0x0085
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA     uint16 = 0x0086
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0087
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0088
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA    uint16 = 0x0089
+	http2cipher_TLS_PSK_WITH_RC4_128_SHA                 uint16 = 0x008A
+	http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA            uint16 = 0x008B
+	http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA             uint16 = 0x008C
+	http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA             uint16 = 0x008D
+	http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA             uint16 = 0x008E
+	http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA        uint16 = 0x008F
+	http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA         uint16 = 0x0090
+	http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA         uint16 = 0x0091
+	http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA             uint16 = 0x0092
+	http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA        uint16 = 0x0093
+	http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA         uint16 = 0x0094
+	http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA         uint16 = 0x0095
+	http2cipher_TLS_RSA_WITH_SEED_CBC_SHA                uint16 = 0x0096
+	http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA             uint16 = 0x0097
+	http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA             uint16 = 0x0098
+	http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA            uint16 = 0x0099
+	http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA            uint16 = 0x009A
+	http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA            uint16 = 0x009B
+	http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256          uint16 = 0x009C
+	http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384          uint16 = 0x009D
+	http2cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256      uint16 = 0x009E
+	http2cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384      uint16 = 0x009F
+	http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256       uint16 = 0x00A0
+	http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384       uint16 = 0x00A1
+	http2cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256      uint16 = 0x00A2
+	http2cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384      uint16 = 0x00A3
+	http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256       uint16 = 0x00A4
+	http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384       uint16 = 0x00A5
+	http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256      uint16 = 0x00A6
+	http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384      uint16 = 0x00A7
+	http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256          uint16 = 0x00A8
+	http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384          uint16 = 0x00A9
+	http2cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256      uint16 = 0x00AA
+	http2cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384      uint16 = 0x00AB
+	http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256      uint16 = 0x00AC
+	http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384      uint16 = 0x00AD
+	http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256          uint16 = 0x00AE
+	http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384          uint16 = 0x00AF
+	http2cipher_TLS_PSK_WITH_NULL_SHA256                 uint16 = 0x00B0
+	http2cipher_TLS_PSK_WITH_NULL_SHA384                 uint16 = 0x00B1
+	http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256      uint16 = 0x00B2
+	http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384      uint16 = 0x00B3
+	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256             uint16 = 0x00B4
+	http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384             uint16 = 0x00B5
+	http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256      uint16 = 0x00B6
+	http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384      uint16 = 0x00B7
+	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256             uint16 = 0x00B8
+	http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384             uint16 = 0x00B9
+	http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0x00BA
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0x00BB
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0x00BC
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
+	http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256     uint16 = 0x00C0
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256  uint16 = 0x00C1
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256  uint16 = 0x00C2
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
+	// Unassigned uint16 =  0x00C6-FE
+	http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
+	// Unassigned uint16 =  0x01-55,*
+	http2cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
+	// Unassigned                                   uint16 = 0x5601 - 0xC000
+	http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA                 uint16 = 0xC001
+	http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA              uint16 = 0xC002
+	http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA         uint16 = 0xC003
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA          uint16 = 0xC004
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA          uint16 = 0xC005
+	http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA                uint16 = 0xC006
+	http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA             uint16 = 0xC007
+	http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC008
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA         uint16 = 0xC009
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA         uint16 = 0xC00A
+	http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA                   uint16 = 0xC00B
+	http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA                uint16 = 0xC00C
+	http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0xC00D
+	http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA            uint16 = 0xC00E
+	http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA            uint16 = 0xC00F
+	http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA                  uint16 = 0xC010
+	http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA               uint16 = 0xC011
+	http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC012
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA           uint16 = 0xC013
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA           uint16 = 0xC014
+	http2cipher_TLS_ECDH_anon_WITH_NULL_SHA                  uint16 = 0xC015
+	http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA               uint16 = 0xC016
+	http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC017
+	http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA           uint16 = 0xC018
+	http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA           uint16 = 0xC019
+	http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA            uint16 = 0xC01A
+	http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC01B
+	http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA        uint16 = 0xC01C
+	http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA             uint16 = 0xC01D
+	http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA         uint16 = 0xC01E
+	http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA         uint16 = 0xC01F
+	http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA             uint16 = 0xC020
+	http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA         uint16 = 0xC021
+	http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA         uint16 = 0xC022
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256      uint16 = 0xC023
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384      uint16 = 0xC024
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256       uint16 = 0xC025
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384       uint16 = 0xC026
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256        uint16 = 0xC027
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384        uint16 = 0xC028
+	http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256         uint16 = 0xC029
+	http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384         uint16 = 0xC02A
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256      uint16 = 0xC02B
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384      uint16 = 0xC02C
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256       uint16 = 0xC02D
+	http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384       uint16 = 0xC02E
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256        uint16 = 0xC02F
+	http2cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384        uint16 = 0xC030
+	http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0xC031
+	http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0xC032
+	http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA               uint16 = 0xC033
+	http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA          uint16 = 0xC034
+	http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA           uint16 = 0xC035
+	http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA           uint16 = 0xC036
+	http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256        uint16 = 0xC037
+	http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384        uint16 = 0xC038
+	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA                  uint16 = 0xC039
+	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256               uint16 = 0xC03A
+	http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384               uint16 = 0xC03B
+	http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256             uint16 = 0xC03C
+	http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384             uint16 = 0xC03D
+	http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256          uint16 = 0xC03E
+	http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384          uint16 = 0xC03F
+	http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256          uint16 = 0xC040
+	http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384          uint16 = 0xC041
+	http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC042
+	http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC043
+	http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC044
+	http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC045
+	http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC046
+	http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC047
+	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256     uint16 = 0xC048
+	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384     uint16 = 0xC049
+	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256      uint16 = 0xC04A
+	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384      uint16 = 0xC04B
+	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256       uint16 = 0xC04C
+	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384       uint16 = 0xC04D
+	http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256        uint16 = 0xC04E
+	http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384        uint16 = 0xC04F
+	http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256             uint16 = 0xC050
+	http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384             uint16 = 0xC051
+	http2cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC052
+	http2cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC053
+	http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256          uint16 = 0xC054
+	http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384          uint16 = 0xC055
+	http2cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC056
+	http2cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC057
+	http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256          uint16 = 0xC058
+	http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384          uint16 = 0xC059
+	http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC05A
+	http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC05B
+	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256     uint16 = 0xC05C
+	http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384     uint16 = 0xC05D
+	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256      uint16 = 0xC05E
+	http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384      uint16 = 0xC05F
+	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256       uint16 = 0xC060
+	http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384       uint16 = 0xC061
+	http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256        uint16 = 0xC062
+	http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384        uint16 = 0xC063
+	http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256             uint16 = 0xC064
+	http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384             uint16 = 0xC065
+	http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC066
+	http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC067
+	http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256         uint16 = 0xC068
+	http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384         uint16 = 0xC069
+	http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256             uint16 = 0xC06A
+	http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384             uint16 = 0xC06B
+	http2cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC06C
+	http2cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC06D
+	http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256         uint16 = 0xC06E
+	http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384         uint16 = 0xC06F
+	http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256       uint16 = 0xC070
+	http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384       uint16 = 0xC071
+	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
+	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
+	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256  uint16 = 0xC074
+	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384  uint16 = 0xC075
+	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256   uint16 = 0xC076
+	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384   uint16 = 0xC077
+	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256    uint16 = 0xC078
+	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384    uint16 = 0xC079
+	http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256         uint16 = 0xC07A
+	http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384         uint16 = 0xC07B
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC07C
+	http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC07D
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256      uint16 = 0xC07E
+	http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384      uint16 = 0xC07F
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC080
+	http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC081
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256      uint16 = 0xC082
+	http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384      uint16 = 0xC083
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC084
+	http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC085
+	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
+	http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
+	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256  uint16 = 0xC088
+	http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384  uint16 = 0xC089
+	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256   uint16 = 0xC08A
+	http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384   uint16 = 0xC08B
+	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256    uint16 = 0xC08C
+	http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384    uint16 = 0xC08D
+	http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256         uint16 = 0xC08E
+	http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384         uint16 = 0xC08F
+	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC090
+	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC091
+	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256     uint16 = 0xC092
+	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384     uint16 = 0xC093
+	http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256         uint16 = 0xC094
+	http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384         uint16 = 0xC095
+	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0xC096
+	http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384     uint16 = 0xC097
+	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256     uint16 = 0xC098
+	http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384     uint16 = 0xC099
+	http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256   uint16 = 0xC09A
+	http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384   uint16 = 0xC09B
+	http2cipher_TLS_RSA_WITH_AES_128_CCM                     uint16 = 0xC09C
+	http2cipher_TLS_RSA_WITH_AES_256_CCM                     uint16 = 0xC09D
+	http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM                 uint16 = 0xC09E
+	http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM                 uint16 = 0xC09F
+	http2cipher_TLS_RSA_WITH_AES_128_CCM_8                   uint16 = 0xC0A0
+	http2cipher_TLS_RSA_WITH_AES_256_CCM_8                   uint16 = 0xC0A1
+	http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8               uint16 = 0xC0A2
+	http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8               uint16 = 0xC0A3
+	http2cipher_TLS_PSK_WITH_AES_128_CCM                     uint16 = 0xC0A4
+	http2cipher_TLS_PSK_WITH_AES_256_CCM                     uint16 = 0xC0A5
+	http2cipher_TLS_DHE_PSK_WITH_AES_128_CCM                 uint16 = 0xC0A6
+	http2cipher_TLS_DHE_PSK_WITH_AES_256_CCM                 uint16 = 0xC0A7
+	http2cipher_TLS_PSK_WITH_AES_128_CCM_8                   uint16 = 0xC0A8
+	http2cipher_TLS_PSK_WITH_AES_256_CCM_8                   uint16 = 0xC0A9
+	http2cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8               uint16 = 0xC0AA
+	http2cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8               uint16 = 0xC0AB
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM             uint16 = 0xC0AC
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM             uint16 = 0xC0AD
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8           uint16 = 0xC0AE
+	http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8           uint16 = 0xC0AF
+	// Unassigned uint16 =  0xC0B0-FF
+	// Unassigned uint16 =  0xC1-CB,*
+	// Unassigned uint16 =  0xCC00-A7
+	http2cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   uint16 = 0xCCA8
+	http2cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
+	http2cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAA
+	http2cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256         uint16 = 0xCCAB
+	http2cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256   uint16 = 0xCCAC
+	http2cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAD
+	http2cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256     uint16 = 0xCCAE
+)
+
+// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
+// References:
+// https://tools.ietf.org/html/rfc7540#appendix-A
+// Reject cipher suites from Appendix A.
+// "This list includes those cipher suites that do not
+// offer an ephemeral key exchange and those that are
+// based on the TLS null, stream or block cipher type"
+func http2isBadCipher(cipher uint16) bool {
+	switch cipher {
+	case http2cipher_TLS_NULL_WITH_NULL_NULL,
+		http2cipher_TLS_RSA_WITH_NULL_MD5,
+		http2cipher_TLS_RSA_WITH_NULL_SHA,
+		http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+		http2cipher_TLS_RSA_WITH_RC4_128_MD5,
+		http2cipher_TLS_RSA_WITH_RC4_128_SHA,
+		http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+		http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA,
+		http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_DES_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,
+		http2cipher_TLS_DH_anon_WITH_RC4_128_MD5,
+		http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_KRB5_WITH_DES_CBC_SHA,
+		http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_KRB5_WITH_RC4_128_SHA,
+		http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA,
+		http2cipher_TLS_KRB5_WITH_DES_CBC_MD5,
+		http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5,
+		http2cipher_TLS_KRB5_WITH_RC4_128_MD5,
+		http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5,
+		http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA,
+		http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA,
+		http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA,
+		http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5,
+		http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5,
+		http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5,
+		http2cipher_TLS_PSK_WITH_NULL_SHA,
+		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA,
+		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA,
+		http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_NULL_SHA256,
+		http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA,
+		http2cipher_TLS_PSK_WITH_RC4_128_SHA,
+		http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA,
+		http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA,
+		http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA,
+		http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_PSK_WITH_NULL_SHA256,
+		http2cipher_TLS_PSK_WITH_NULL_SHA384,
+		http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256,
+		http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
+		http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
+		http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA,
+		http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA,
+		http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA,
+		http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDH_anon_WITH_NULL_SHA,
+		http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+		http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
+		http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+		http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+		http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+		http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA,
+		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256,
+		http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384,
+		http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+		http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+		http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+		http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+		http2cipher_TLS_RSA_WITH_AES_128_CCM,
+		http2cipher_TLS_RSA_WITH_AES_256_CCM,
+		http2cipher_TLS_RSA_WITH_AES_128_CCM_8,
+		http2cipher_TLS_RSA_WITH_AES_256_CCM_8,
+		http2cipher_TLS_PSK_WITH_AES_128_CCM,
+		http2cipher_TLS_PSK_WITH_AES_256_CCM,
+		http2cipher_TLS_PSK_WITH_AES_128_CCM_8,
+		http2cipher_TLS_PSK_WITH_AES_256_CCM_8:
+		return true
+	default:
+		return false
+	}
+}
+
 // ClientConnPool manages a pool of HTTP/2 client connections.
 type http2ClientConnPool interface {
 	GetClientConn(req *Request, addr string) (*http2ClientConn, error)
@@ -126,7 +762,7 @@ type http2dialCall struct {
 // requires p.mu is held.
 func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall {
 	if call, ok := p.dialing[addr]; ok {
-
+		// A dial is already in-flight. Don't start another.
 		return call
 	}
 	call := &http2dialCall{p: p, done: make(chan struct{})}
@@ -254,7 +890,12 @@ func (p *http2clientConnPool) MarkDead(cc *http2ClientConn) {
 func (p *http2clientConnPool) closeIdleConnections() {
 	p.mu.Lock()
 	defer p.mu.Unlock()
-
+	// TODO: don't close a cc if it was just added to the pool
+	// milliseconds ago and has never been used. There's currently
+	// a small race window with the HTTP/1 Transport's integration
+	// where it can add an idle conn just before using it, and
+	// somebody else can concurrently call CloseIdleConns and
+	// break some caller's RoundTrip.
 	for _, vv := range p.conns {
 		for _, cc := range vv {
 			cc.closeIfIdle()
@@ -269,7 +910,8 @@ func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) [
 			out = append(out, v)
 		}
 	}
-
+	// If we filtered it out, zero out the last item to prevent
+	// the GC from seeing it.
 	if len(in) != len(out) {
 		in[len(in)-1] = nil
 	}
@@ -277,7 +919,7 @@ func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) [
 }
 
 // noDialClientConnPool is an implementation of http2.ClientConnPool
-// which never dials.  We let the HTTP/1.1 client dial and use its TLS
+// which never dials. We let the HTTP/1.1 client dial and use its TLS
 // connection instead.
 type http2noDialClientConnPool struct{ *http2clientConnPool }
 
@@ -310,7 +952,10 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 			go c.Close()
 			return http2erringRoundTripper{err}
 		} else if !used {
-
+			// Turns out we don't need this c.
+			// For example, two goroutines made requests to the same host
+			// at the same time, both kicking off TCP dials. (since protocol
+			// was unknown)
 			go c.Close()
 		}
 		return t2
@@ -326,7 +971,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 }
 
 // registerHTTPSProtocol calls Transport.RegisterProtocol but
-// convering panics into errors.
+// converting panics into errors.
 func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
 	defer func() {
 		if e := recover(); e != nil {
@@ -349,6 +994,141 @@ func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) {
 	return res, err
 }
 
+// Buffer chunks are allocated from a pool to reduce pressure on GC.
+// The maximum wasted space per dataBuffer is 2x the largest size class,
+// which happens when the dataBuffer has multiple chunks and there is
+// one unread byte in both the first and last chunks. We use a few size
+// classes to minimize overheads for servers that typically receive very
+// small request bodies.
+//
+// TODO: Benchmark to determine if the pools are necessary. The GC may have
+// improved enough that we can instead allocate chunks like this:
+// make([]byte, max(16<<10, expectedBytesRemaining))
+var (
+	http2dataChunkSizeClasses = []int{
+		1 << 10,
+		2 << 10,
+		4 << 10,
+		8 << 10,
+		16 << 10,
+	}
+	http2dataChunkPools = [...]sync.Pool{
+		{New: func() interface{} { return make([]byte, 1<<10) }},
+		{New: func() interface{} { return make([]byte, 2<<10) }},
+		{New: func() interface{} { return make([]byte, 4<<10) }},
+		{New: func() interface{} { return make([]byte, 8<<10) }},
+		{New: func() interface{} { return make([]byte, 16<<10) }},
+	}
+)
+
+func http2getDataBufferChunk(size int64) []byte {
+	i := 0
+	for ; i < len(http2dataChunkSizeClasses)-1; i++ {
+		if size <= int64(http2dataChunkSizeClasses[i]) {
+			break
+		}
+	}
+	return http2dataChunkPools[i].Get().([]byte)
+}
+
+func http2putDataBufferChunk(p []byte) {
+	for i, n := range http2dataChunkSizeClasses {
+		if len(p) == n {
+			http2dataChunkPools[i].Put(p)
+			return
+		}
+	}
+	panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
+}
+
+// dataBuffer is an io.ReadWriter backed by a list of data chunks.
+// Each dataBuffer is used to read DATA frames on a single stream.
+// The buffer is divided into chunks so the server can limit the
+// total memory used by a single connection without limiting the
+// request body size on any single stream.
+type http2dataBuffer struct {
+	chunks   [][]byte
+	r        int   // next byte to read is chunks[0][r]
+	w        int   // next byte to write is chunks[len(chunks)-1][w]
+	size     int   // total buffered bytes
+	expected int64 // we expect at least this many bytes in future Write calls (ignored if <= 0)
+}
+
+var http2errReadEmpty = errors.New("read from empty dataBuffer")
+
+// Read copies bytes from the buffer into p.
+// It is an error to read when no data is available.
+func (b *http2dataBuffer) Read(p []byte) (int, error) {
+	if b.size == 0 {
+		return 0, http2errReadEmpty
+	}
+	var ntotal int
+	for len(p) > 0 && b.size > 0 {
+		readFrom := b.bytesFromFirstChunk()
+		n := copy(p, readFrom)
+		p = p[n:]
+		ntotal += n
+		b.r += n
+		b.size -= n
+		// If the first chunk has been consumed, advance to the next chunk.
+		if b.r == len(b.chunks[0]) {
+			http2putDataBufferChunk(b.chunks[0])
+			end := len(b.chunks) - 1
+			copy(b.chunks[:end], b.chunks[1:])
+			b.chunks[end] = nil
+			b.chunks = b.chunks[:end]
+			b.r = 0
+		}
+	}
+	return ntotal, nil
+}
+
+func (b *http2dataBuffer) bytesFromFirstChunk() []byte {
+	if len(b.chunks) == 1 {
+		return b.chunks[0][b.r:b.w]
+	}
+	return b.chunks[0][b.r:]
+}
+
+// Len returns the number of bytes of the unread portion of the buffer.
+func (b *http2dataBuffer) Len() int {
+	return b.size
+}
+
+// Write appends p to the buffer.
+func (b *http2dataBuffer) Write(p []byte) (int, error) {
+	ntotal := len(p)
+	for len(p) > 0 {
+		// If the last chunk is empty, allocate a new chunk. Try to allocate
+		// enough to fully copy p plus any additional bytes we expect to
+		// receive. However, this may allocate less than len(p).
+		want := int64(len(p))
+		if b.expected > want {
+			want = b.expected
+		}
+		chunk := b.lastChunkOrAlloc(want)
+		n := copy(chunk[b.w:], p)
+		p = p[n:]
+		b.w += n
+		b.size += n
+		b.expected -= int64(n)
+	}
+	return ntotal, nil
+}
+
+func (b *http2dataBuffer) lastChunkOrAlloc(want int64) []byte {
+	if len(b.chunks) != 0 {
+		last := b.chunks[len(b.chunks)-1]
+		if b.w < len(last) {
+			return last
+		}
+	}
+	chunk := http2getDataBufferChunk(want)
+	b.chunks = append(b.chunks, chunk)
+	b.w = 0
+	return chunk
+}
+
 // An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
 type http2ErrCode uint32
 
@@ -429,11 +1209,16 @@ type http2goAwayFlowError struct{}
 
 func (http2goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
 
+// connError represents an HTTP/2 ConnectionError error code, along
+// with a string (for debugging) explaining why.
+//
 // Errors of this type are only returned by the frame parser functions
-// and converted into ConnectionError(ErrCodeProtocol).
+// and converted into ConnectionError(Code), after stashing away
+// the Reason into the Framer's errDetail field, accessible via
+// the (*Framer).ErrorDetail method.
 type http2connError struct {
-	Code   http2ErrCode
-	Reason string
+	Code   http2ErrCode // the ConnectionError error code
+	Reason string       // additional reason
 }
 
 func (e http2connError) Error() string {
@@ -469,56 +1254,6 @@ var (
 	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 {
-	buf  []byte
-	r, w int
-}
-
-var (
-	http2errReadEmpty = errors.New("read from empty fixedBuffer")
-	http2errWriteFull = errors.New("write on full fixedBuffer")
-)
-
-// Read copies bytes from the buffer into p.
-// It is an error to read when no data is available.
-func (b *http2fixedBuffer) Read(p []byte) (n int, err error) {
-	if b.r == b.w {
-		return 0, http2errReadEmpty
-	}
-	n = copy(p, b.buf[b.r:b.w])
-	b.r += n
-	if b.r == b.w {
-		b.r = 0
-		b.w = 0
-	}
-	return n, nil
-}
-
-// Len returns the number of bytes of the unread portion of the buffer.
-func (b *http2fixedBuffer) Len() int {
-	return b.w - b.r
-}
-
-// Write copies bytes from p into the buffer.
-// It is an error to write more data than the buffer can hold.
-func (b *http2fixedBuffer) Write(p []byte) (n int, err error) {
-
-	if b.r > 0 && len(p) > len(b.buf)-b.w {
-		copy(b.buf, b.buf[b.r:b.w])
-		b.w -= b.r
-		b.r = 0
-	}
-
-	n = copy(b.buf[b.w:], p)
-	b.w += n
-	if n < len(p) {
-		err = http2errWriteFull
-	}
-	return n, err
-}
-
 // flow is the flow control window's size.
 type http2flow struct {
 	// n is the number of DATA bytes we're allowed to send.
@@ -666,7 +1401,7 @@ var http2flagName = map[http2FrameType]map[http2Flags]string{
 // a frameParser parses a frame given its FrameHeader and payload
 // bytes. The length of payload will always equal fh.Length (which
 // might be 0).
-type http2frameParser func(fh http2FrameHeader, payload []byte) (http2Frame, error)
+type http2frameParser func(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error)
 
 var http2frameParsers = map[http2FrameType]http2frameParser{
 	http2FrameData:         http2parseDataFrame,
@@ -855,25 +1590,33 @@ type http2Framer struct {
 	// If the limit is hit, MetaHeadersFrame.Truncated is set true.
 	MaxHeaderListSize uint32
 
+	// TODO: track which type of frame & with which flags was sent
+	// last. Then return an error (unless AllowIllegalWrites) if
+	// we're in the middle of a header block and a
+	// non-Continuation or Continuation on a different stream is
+	// attempted to be written.
+
 	logReads, logWrites bool
 
 	debugFramer       *http2Framer // only use for logging written writes
 	debugFramerBuf    *bytes.Buffer
 	debugReadLoggerf  func(string, ...interface{})
 	debugWriteLoggerf func(string, ...interface{})
+
+	frameCache *http2frameCache // nil if frames aren't reused (default)
 }
 
 func (fr *http2Framer) maxHeaderListSize() uint32 {
 	if fr.MaxHeaderListSize == 0 {
-		return 16 << 20
+		return 16 << 20 // sane default, per docs
 	}
 	return fr.MaxHeaderListSize
 }
 
 func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) {
-
+	// Write the FrameHeader.
 	f.wbuf = append(f.wbuf[:0],
-		0,
+		0, // 3 bytes of length, filled in in endWrite
 		0,
 		0,
 		byte(ftype),
@@ -885,7 +1628,8 @@ func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamI
 }
 
 func (f *http2Framer) endWrite() error {
-
+	// Now that we know the final size, fill in the FrameHeader in
+	// the space previously reserved for it. Abuse append.
 	length := len(f.wbuf) - http2frameHeaderLen
 	if length >= (1 << 24) {
 		return http2ErrFrameTooLarge
@@ -909,8 +1653,9 @@ func (f *http2Framer) logWrite() {
 	if f.debugFramer == nil {
 		f.debugFramerBuf = new(bytes.Buffer)
 		f.debugFramer = http2NewFramer(nil, f.debugFramerBuf)
-		f.debugFramer.logReads = false
-
+		f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
+		// Let us read anything, even if we accidentally wrote it
+		// in the wrong order:
 		f.debugFramer.AllowIllegalReads = true
 	}
 	f.debugFramerBuf.Write(f.wbuf)
@@ -937,6 +1682,27 @@ const (
 	http2maxFrameSize    = 1<<24 - 1
 )
 
+// SetReuseFrames allows the Framer to reuse Frames.
+// If called on a Framer, Frames returned by calls to ReadFrame are only
+// valid until the next call to ReadFrame.
+func (fr *http2Framer) SetReuseFrames() {
+	if fr.frameCache != nil {
+		return
+	}
+	fr.frameCache = &http2frameCache{}
+}
+
+type http2frameCache struct {
+	dataFrame http2DataFrame
+}
+
+func (fc *http2frameCache) getDataFrame() *http2DataFrame {
+	if fc == nil {
+		return &http2DataFrame{}
+	}
+	return &fc.dataFrame
+}
+
 // NewFramer returns a Framer that writes frames to w and reads them from r.
 func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
 	fr := &http2Framer{
@@ -1016,7 +1782,7 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
 	if _, err := io.ReadFull(fr.r, payload); err != nil {
 		return nil, err
 	}
-	f, err := http2typeFrameParser(fh.Type)(fh, payload)
+	f, err := http2typeFrameParser(fh.Type)(fr.frameCache, fh, payload)
 	if err != nil {
 		if ce, ok := err.(http2connError); ok {
 			return nil, fr.connError(ce.Code, ce.Reason)
@@ -1104,14 +1870,18 @@ func (f *http2DataFrame) Data() []byte {
 	return f.data
 }
 
-func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
 	if fh.StreamID == 0 {
-
+		// DATA frames MUST be associated with a stream. If a
+		// DATA frame is received whose stream identifier
+		// field is 0x0, the recipient MUST respond with a
+		// connection error (Section 5.4.1) of type
+		// PROTOCOL_ERROR.
 		return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"}
 	}
-	f := &http2DataFrame{
-		http2FrameHeader: fh,
-	}
+	f := fc.getDataFrame()
+	f.http2FrameHeader = fh
+
 	var padSize byte
 	if fh.Flags.Has(http2FlagDataPadded) {
 		var err error
@@ -1121,7 +1891,10 @@ func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error
 		}
 	}
 	if int(padSize) > len(payload) {
-
+		// If the length of the padding is greater than the
+		// length of the frame payload, the recipient MUST
+		// treat this as a connection error.
+		// Filed: https://github.com/http2/http2-spec/issues/610
 		return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"}
 	}
 	f.data = payload[:len(payload)-int(padSize)]
@@ -1132,6 +1905,7 @@ var (
 	http2errStreamID    = errors.New("invalid stream ID")
 	http2errDepStreamID = errors.New("invalid dependent stream ID")
 	http2errPadLength   = errors.New("pad length too large")
+	http2errPadBytes    = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled")
 )
 
 func http2validStreamIDOrZero(streamID uint32) bool {
@@ -1155,6 +1929,7 @@ func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) er
 //
 // If pad is nil, the padding bit is not sent.
 // The length of pad must not exceed 255 bytes.
+// The bytes of pad must all be zero, unless f.AllowIllegalWrites is set.
 //
 // It will perform exactly one Write to the underlying Writer.
 // It is the caller's responsibility not to violate the maximum frame size
@@ -1163,8 +1938,18 @@ func (f *http2Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad
 	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
 		return http2errStreamID
 	}
-	if len(pad) > 255 {
-		return http2errPadLength
+	if len(pad) > 0 {
+		if len(pad) > 255 {
+			return http2errPadLength
+		}
+		if !f.AllowIllegalWrites {
+			for _, b := range pad {
+				if b != 0 {
+					// "Padding octets MUST be set to zero when sending."
+					return http2errPadBytes
+				}
+			}
+		}
 	}
 	var flags http2Flags
 	if endStream {
@@ -1192,22 +1977,35 @@ type http2SettingsFrame struct {
 	p []byte
 }
 
-func http2parseSettingsFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	if fh.Flags.Has(http2FlagSettingsAck) && fh.Length > 0 {
-
+		// When this (ACK 0x1) bit is set, the payload of the
+		// SETTINGS frame MUST be empty. Receipt of a
+		// SETTINGS frame with the ACK flag set and a length
+		// field value other than 0 MUST be treated as a
+		// connection error (Section 5.4.1) of type
+		// FRAME_SIZE_ERROR.
 		return nil, http2ConnectionError(http2ErrCodeFrameSize)
 	}
 	if fh.StreamID != 0 {
-
+		// SETTINGS frames always apply to a connection,
+		// never a single stream. The stream identifier for a
+		// SETTINGS frame MUST be zero (0x0).  If an endpoint
+		// receives a SETTINGS frame whose stream identifier
+		// field is anything other than 0x0, the endpoint MUST
+		// respond with a connection error (Section 5.4.1) of
+		// type PROTOCOL_ERROR.
 		return nil, http2ConnectionError(http2ErrCodeProtocol)
 	}
 	if len(p)%6 != 0 {
-
+		// Expecting even number of 6 byte settings.
 		return nil, http2ConnectionError(http2ErrCodeFrameSize)
 	}
 	f := &http2SettingsFrame{http2FrameHeader: fh, p: p}
 	if v, ok := f.Value(http2SettingInitialWindowSize); ok && v > (1<<31)-1 {
-
+		// Values above the maximum flow control window size of 2^31 - 1 MUST
+		// be treated as a connection error (Section 5.4.1) of type
+		// FLOW_CONTROL_ERROR.
 		return nil, http2ConnectionError(http2ErrCodeFlowControl)
 	}
 	return f, nil
@@ -1281,7 +2079,7 @@ type http2PingFrame struct {
 
 func (f *http2PingFrame) IsAck() bool { return f.Flags.Has(http2FlagPingAck) }
 
-func http2parsePingFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parsePingFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
 	if len(payload) != 8 {
 		return nil, http2ConnectionError(http2ErrCodeFrameSize)
 	}
@@ -1321,7 +2119,7 @@ func (f *http2GoAwayFrame) DebugData() []byte {
 	return f.debugData
 }
 
-func http2parseGoAwayFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseGoAwayFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	if fh.StreamID != 0 {
 		return nil, http2ConnectionError(http2ErrCodeProtocol)
 	}
@@ -1361,7 +2159,7 @@ func (f *http2UnknownFrame) Payload() []byte {
 	return f.p
 }
 
-func http2parseUnknownFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseUnknownFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	return &http2UnknownFrame{fh, p}, nil
 }
 
@@ -1372,13 +2170,18 @@ type http2WindowUpdateFrame struct {
 	Increment uint32 // never read with high bit set
 }
 
-func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	if len(p) != 4 {
 		return nil, http2ConnectionError(http2ErrCodeFrameSize)
 	}
-	inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff
+	inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
 	if inc == 0 {
-
+		// A receiver MUST treat the receipt of a
+		// WINDOW_UPDATE frame with an flow control window
+		// increment of 0 as a stream error (Section 5.4.2) of
+		// type PROTOCOL_ERROR; errors on the connection flow
+		// control window MUST be treated as a connection
+		// error (Section 5.4.1).
 		if fh.StreamID == 0 {
 			return nil, http2ConnectionError(http2ErrCodeProtocol)
 		}
@@ -1395,7 +2198,7 @@ func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, err
 // If the Stream ID is zero, the window update applies to the
 // connection as a whole.
 func (f *http2Framer) WriteWindowUpdate(streamID, incr uint32) error {
-
+	// "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
 	if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
 		return errors.New("illegal window increment value")
 	}
@@ -1432,12 +2235,15 @@ func (f *http2HeadersFrame) HasPriority() bool {
 	return f.http2FrameHeader.Flags.Has(http2FlagHeadersPriority)
 }
 
-func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
 	hf := &http2HeadersFrame{
 		http2FrameHeader: fh,
 	}
 	if fh.StreamID == 0 {
-
+		// HEADERS frames MUST be associated with a stream. If a HEADERS frame
+		// is received whose stream identifier field is 0x0, the recipient MUST
+		// respond with a connection error (Section 5.4.1) of type
+		// PROTOCOL_ERROR.
 		return nil, http2connError{http2ErrCodeProtocol, "HEADERS frame with stream ID 0"}
 	}
 	var padLength uint8
@@ -1453,7 +2259,7 @@ func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err er
 			return nil, err
 		}
 		hf.Priority.StreamDep = v & 0x7fffffff
-		hf.Priority.Exclusive = (v != hf.Priority.StreamDep)
+		hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
 		p, hf.Priority.Weight, err = http2readByte(p)
 		if err != nil {
 			return nil, err
@@ -1556,7 +2362,7 @@ type http2PriorityParam struct {
 	Exclusive bool
 
 	// Weight is the stream's zero-indexed weight. It should be
-	// set together with StreamDep, or neither should be set.  Per
+	// set together with StreamDep, or neither should be set. Per
 	// the spec, "Add one to the value to obtain a weight between
 	// 1 and 256."
 	Weight uint8
@@ -1566,7 +2372,7 @@ func (p http2PriorityParam) IsZero() bool {
 	return p == http2PriorityParam{}
 }
 
-func http2parsePriorityFrame(fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parsePriorityFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
 	if fh.StreamID == 0 {
 		return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
 	}
@@ -1574,13 +2380,13 @@ func http2parsePriorityFrame(fh http2FrameHeader, payload []byte) (http2Frame, e
 		return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
 	}
 	v := binary.BigEndian.Uint32(payload[:4])
-	streamID := v & 0x7fffffff
+	streamID := v & 0x7fffffff // mask off high bit
 	return &http2PriorityFrame{
 		http2FrameHeader: fh,
 		http2PriorityParam: http2PriorityParam{
 			Weight:    payload[4],
 			StreamDep: streamID,
-			Exclusive: streamID != v,
+			Exclusive: streamID != v, // was high bit set?
 		},
 	}, nil
 }
@@ -1613,7 +2419,7 @@ type http2RSTStreamFrame struct {
 	ErrCode http2ErrCode
 }
 
-func http2parseRSTStreamFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseRSTStreamFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	if len(p) != 4 {
 		return nil, http2ConnectionError(http2ErrCodeFrameSize)
 	}
@@ -1643,7 +2449,7 @@ type http2ContinuationFrame struct {
 	headerFragBuf []byte
 }
 
-func http2parseContinuationFrame(fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseContinuationFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
 	if fh.StreamID == 0 {
 		return nil, http2connError{http2ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
 	}
@@ -1693,12 +2499,17 @@ func (f *http2PushPromiseFrame) HeadersEnded() bool {
 	return f.http2FrameHeader.Flags.Has(http2FlagPushPromiseEndHeaders)
 }
 
-func http2parsePushPromise(fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
 	pp := &http2PushPromiseFrame{
 		http2FrameHeader: fh,
 	}
 	if pp.StreamID == 0 {
-
+		// PUSH_PROMISE frames MUST be associated with an existing,
+		// peer-initiated stream. The stream identifier of a
+		// PUSH_PROMISE frame indicates the stream it is associated
+		// with. If the stream identifier field specifies the value
+		// 0x0, a recipient MUST respond with a connection error
+		// (Section 5.4.1) of type PROTOCOL_ERROR.
 		return nil, http2ConnectionError(http2ErrCodeProtocol)
 	}
 	// The PUSH_PROMISE frame includes optional padding.
@@ -1717,7 +2528,7 @@ func http2parsePushPromise(fh http2FrameHeader, p []byte) (_ http2Frame, err err
 	pp.PromiseID = pp.PromiseID & (1<<31 - 1)
 
 	if int(padLength) > len(p) {
-
+		// like the DATA frame, error out if padding is longer than the body.
 		return nil, http2ConnectionError(http2ErrCodeProtocol)
 	}
 	pp.headerFragBuf = p[:len(p)-int(padLength)]
@@ -1887,7 +2698,9 @@ func (mh *http2MetaHeadersFrame) checkPseudos() error {
 		default:
 			return http2pseudoHeaderError(hf.Name)
 		}
-
+		// Check for duplicates.
+		// This would be a bad algorithm, but N is 4.
+		// And this doesn't allocate.
 		for _, hf2 := range pf[:i] {
 			if hf.Name == hf2.Name {
 				return http2duplicatePseudoHeaderError(hf.Name)
@@ -1905,7 +2718,8 @@ func (fr *http2Framer) maxHeaderStringLen() int {
 	if uint32(int(v)) == v {
 		return int(v)
 	}
-
+	// They had a crazy big number for MaxHeaderBytes anyway,
+	// so give them unlimited header lengths:
 	return 0
 }
 
@@ -1960,7 +2774,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
 
 		mh.Fields = append(mh.Fields, hf)
 	})
-
+	// Lose reference to MetaHeadersFrame:
 	defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
 
 	var hc http2headersOrContinuation = hf
@@ -1976,7 +2790,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
 		if f, err := fr.ReadFrame(); err != nil {
 			return nil, err
 		} else {
-			hc = f.(*http2ContinuationFrame)
+			hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder
 		}
 	}
 
@@ -2018,7 +2832,7 @@ func http2summarizeFrame(f http2Frame) string {
 			return nil
 		})
 		if n > 0 {
-			buf.Truncate(buf.Len() - 1)
+			buf.Truncate(buf.Len() - 1) // remove trailing comma
 		}
 	case *http2DataFrame:
 		data := f.Data()
@@ -2050,29 +2864,6 @@ 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
 }
@@ -2164,7 +2955,11 @@ func (cc *http2ClientConn) Ping(ctx context.Context) error {
 	return cc.ping(ctx)
 }
 
-func http2cloneTLSConfig(c *tls.Config) *tls.Config { return c.Clone() }
+func http2cloneTLSConfig(c *tls.Config) *tls.Config {
+	c2 := c.Clone()
+	c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264
+	return c2
+}
 
 var _ Pusher = (*http2responseWriter)(nil)
 
@@ -2201,6 +2996,11 @@ func http2reqBodyIsNoBody(body io.ReadCloser) bool {
 	return body == NoBody
 }
 
+func http2configureServer19(s *Server, conf *http2Server) error {
+	s.RegisterOnShutdown(conf.state.startGracefulShutdown)
+	return nil
+}
+
 var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
 
 type http2goroutineLock uint64
@@ -2237,7 +3037,7 @@ func http2curGoroutineID() uint64 {
 	defer http2littleBuf.Put(bp)
 	b := *bp
 	b = b[:runtime.Stack(b, false)]
-
+	// Parse the 4707 out of "goroutine 4707 ["
 	b = bytes.TrimPrefix(b, http2goroutineSpace)
 	i := bytes.IndexByte(b, ' ')
 	if i < 0 {
@@ -2273,9 +3073,10 @@ func http2parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error)
 		goto Error
 
 	case 2 <= base && base <= 36:
+		// valid base; nothing to do
 
 	case base == 0:
-
+		// Look for octal, hex prefix.
 		switch {
 		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
 			base = 16
@@ -2321,7 +3122,7 @@ func http2parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error)
 		}
 
 		if n >= cutoff {
-
+			// n*base overflows
 			n = 1<<64 - 1
 			err = strconv.ErrRange
 			goto Error
@@ -2330,7 +3131,7 @@ func http2parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error)
 
 		n1 := n + uint64(v)
 		if n1 < n || n1 > maxVal {
-
+			// n+v overflows
 			n = 1<<64 - 1
 			err = strconv.ErrRange
 			goto Error
@@ -2514,7 +3315,7 @@ func (s http2Setting) String() string {
 
 // Valid reports whether the setting is valid.
 func (s http2Setting) Valid() error {
-
+	// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
 	switch s.ID {
 	case http2SettingEnablePush:
 		if s.Val != 1 && s.Val != 0 {
@@ -2758,7 +3559,8 @@ func (s *http2sorter) Keys(h Header) []string {
 }
 
 func (s *http2sorter) SortStrings(ss []string) {
-
+	// Our sorter works on s.v, which sorter owns, so
+	// stash it away while we sort the user's buffer.
 	save := s.v
 	s.v = ss
 	sort.Sort(s)
@@ -2768,27 +3570,31 @@ func (s *http2sorter) SortStrings(ss []string) {
 // validPseudoPath reports whether v is a valid :path pseudo-header
 // value. It must be either:
 //
-//     *) a non-empty string starting with '/', but not with with "//",
+//     *) a non-empty string starting with '/'
 //     *) the string '*', for OPTIONS requests.
 //
 // For now this is only used a quick check for deciding when to clean
 // up Opaque URLs before sending requests from the Transport.
 // See golang.org/issue/16847
+//
+// We used to enforce that the path also didn't start with "//", but
+// Google's GFE accepts such paths and Chrome sends them, so ignore
+// that part of the spec. See golang.org/issue/19103.
 func http2validPseudoPath(v string) bool {
-	return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*"
+	return (len(v) > 0 && v[0] == '/') || v == "*"
 }
 
-// pipe is a goroutine-safe io.Reader/io.Writer pair.  It's like
+// 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)
 type http2pipe struct {
 	mu       sync.Mutex
-	c        sync.Cond // c.L lazily initialized to &p.mu
-	b        http2pipeBuffer
-	err      error         // read error once empty. non-nil means closed.
-	breakErr error         // immediate read error (caller doesn't see rest of b)
-	donec    chan struct{} // closed on error
-	readFn   func()        // optional code to run in Read before error
+	c        sync.Cond       // c.L lazily initialized to &p.mu
+	b        http2pipeBuffer // nil when done reading
+	err      error           // read error once empty. non-nil means closed.
+	breakErr error           // immediate read error (caller doesn't see rest of b)
+	donec    chan struct{}   // closed on error
+	readFn   func()          // optional code to run in Read before error
 }
 
 type http2pipeBuffer interface {
@@ -2800,6 +3606,9 @@ type http2pipeBuffer interface {
 func (p *http2pipe) Len() int {
 	p.mu.Lock()
 	defer p.mu.Unlock()
+	if p.b == nil {
+		return 0
+	}
 	return p.b.Len()
 }
 
@@ -2815,14 +3624,15 @@ func (p *http2pipe) Read(d []byte) (n int, err error) {
 		if p.breakErr != nil {
 			return 0, p.breakErr
 		}
-		if p.b.Len() > 0 {
+		if p.b != nil && p.b.Len() > 0 {
 			return p.b.Read(d)
 		}
 		if p.err != nil {
 			if p.readFn != nil {
-				p.readFn()
-				p.readFn = nil
+				p.readFn()     // e.g. copy trailers
+				p.readFn = nil // not sticky like p.err
 			}
+			p.b = nil
 			return 0, p.err
 		}
 		p.c.Wait()
@@ -2843,6 +3653,9 @@ func (p *http2pipe) Write(d []byte) (n int, err error) {
 	if p.err != nil {
 		return 0, http2errClosedPipeWrite
 	}
+	if p.breakErr != nil {
+		return len(d), nil // discard when there is no reader
+	}
 	return p.b.Write(d)
 }
 
@@ -2873,10 +3686,13 @@ func (p *http2pipe) closeWithError(dst *error, err error, fn func()) {
 	}
 	defer p.c.Signal()
 	if *dst != nil {
-
+		// Already been done.
 		return
 	}
 	p.readFn = fn
+	if dst == &p.breakErr {
+		p.b = nil
+	}
 	*dst = err
 	p.closeDoneLocked()
 }
@@ -2886,7 +3702,8 @@ func (p *http2pipe) closeDoneLocked() {
 	if p.donec == nil {
 		return
 	}
-
+	// Close if unclosed. This isn't racy since we always
+	// hold p.mu while closing.
 	select {
 	case <-p.donec:
 	default:
@@ -2912,7 +3729,7 @@ func (p *http2pipe) Done() <-chan struct{} {
 	if p.donec == nil {
 		p.donec = make(chan struct{})
 		if p.err != nil || p.breakErr != nil {
-
+			// Already hit an error.
 			p.closeDoneLocked()
 		}
 	}
@@ -2980,9 +3797,41 @@ type http2Server struct {
 	// activity for the purposes of IdleTimeout.
 	IdleTimeout time.Duration
 
+	// MaxUploadBufferPerConnection is the size of the initial flow
+	// control window for each connections. The HTTP/2 spec does not
+	// allow this to be smaller than 65535 or larger than 2^32-1.
+	// If the value is outside this range, a default value will be
+	// used instead.
+	MaxUploadBufferPerConnection int32
+
+	// MaxUploadBufferPerStream is the size of the initial flow control
+	// window for each stream. The HTTP/2 spec does not allow this to
+	// be larger than 2^32-1. If the value is zero or larger than the
+	// maximum, a default value will be used instead.
+	MaxUploadBufferPerStream int32
+
 	// NewWriteScheduler constructs a write scheduler for a connection.
 	// If nil, a default scheduler is chosen.
 	NewWriteScheduler func() http2WriteScheduler
+
+	// Internal state. This is a pointer (rather than embedded directly)
+	// so that we don't embed a Mutex in this struct, which will make the
+	// struct non-copyable, which might break some callers.
+	state *http2serverInternalState
+}
+
+func (s *http2Server) initialConnRecvWindowSize() int32 {
+	if s.MaxUploadBufferPerConnection > http2initialWindowSize {
+		return s.MaxUploadBufferPerConnection
+	}
+	return 1 << 20
+}
+
+func (s *http2Server) initialStreamRecvWindowSize() int32 {
+	if s.MaxUploadBufferPerStream > 0 {
+		return s.MaxUploadBufferPerStream
+	}
+	return 1 << 20
 }
 
 func (s *http2Server) maxReadFrameSize() uint32 {
@@ -2999,6 +3848,40 @@ func (s *http2Server) maxConcurrentStreams() uint32 {
 	return http2defaultMaxStreams
 }
 
+type http2serverInternalState struct {
+	mu          sync.Mutex
+	activeConns map[*http2serverConn]struct{}
+}
+
+func (s *http2serverInternalState) registerConn(sc *http2serverConn) {
+	if s == nil {
+		return // if the Server was used without calling ConfigureServer
+	}
+	s.mu.Lock()
+	s.activeConns[sc] = struct{}{}
+	s.mu.Unlock()
+}
+
+func (s *http2serverInternalState) unregisterConn(sc *http2serverConn) {
+	if s == nil {
+		return // if the Server was used without calling ConfigureServer
+	}
+	s.mu.Lock()
+	delete(s.activeConns, sc)
+	s.mu.Unlock()
+}
+
+func (s *http2serverInternalState) startGracefulShutdown() {
+	if s == nil {
+		return // if the Server was used without calling ConfigureServer
+	}
+	s.mu.Lock()
+	for sc := range s.activeConns {
+		sc.startGracefulShutdown()
+	}
+	s.mu.Unlock()
+}
+
 // ConfigureServer adds HTTP/2 support to a net/http Server.
 //
 // The configuration conf may be nil.
@@ -3011,9 +3894,13 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
 	if conf == nil {
 		conf = new(http2Server)
 	}
+	conf.state = &http2serverInternalState{activeConns: make(map[*http2serverConn]struct{})}
 	if err := http2configureServer18(s, conf); err != nil {
 		return err
 	}
+	if err := http2configureServer19(s, conf); err != nil {
+		return err
+	}
 
 	if s.TLSConfig == nil {
 		s.TLSConfig = new(tls.Config)
@@ -3039,6 +3926,13 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
 		}
 	}
 
+	// Note: not setting MinVersion to tls.VersionTLS12,
+	// as we don't want to interfere with HTTP/1.1 traffic
+	// on the user's server. We enforce TLS 1.2 later once
+	// we accept a connection. Ideally this should be done
+	// during next-proto selection, but using TLS <1.2 with
+	// HTTP/2 is still the client's bug.
+
 	s.TLSConfig.PreferServerCipherSuites = true
 
 	haveNPN := false
@@ -3118,29 +4012,37 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 	defer cancel()
 
 	sc := &http2serverConn{
-		srv:               s,
-		hs:                opts.baseConfig(),
-		conn:              c,
-		baseCtx:           baseCtx,
-		remoteAddrStr:     c.RemoteAddr().String(),
-		bw:                http2newBufferedWriter(c),
-		handler:           opts.handler(),
-		streams:           make(map[uint32]*http2stream),
-		readFrameCh:       make(chan http2readFrameResult),
-		wantWriteFrameCh:  make(chan http2FrameWriteRequest, 8),
-		wantStartPushCh:   make(chan http2startPushRequest, 8),
-		wroteFrameCh:      make(chan http2frameWriteResult, 1),
-		bodyReadCh:        make(chan http2bodyReadMsg),
-		doneServing:       make(chan struct{}),
-		clientMaxStreams:  math.MaxUint32,
-		advMaxStreams:     s.maxConcurrentStreams(),
-		initialWindowSize: http2initialWindowSize,
-		maxFrameSize:      http2initialMaxFrameSize,
-		headerTableSize:   http2initialHeaderTableSize,
-		serveG:            http2newGoroutineLock(),
-		pushEnabled:       true,
-	}
-
+		srv:                         s,
+		hs:                          opts.baseConfig(),
+		conn:                        c,
+		baseCtx:                     baseCtx,
+		remoteAddrStr:               c.RemoteAddr().String(),
+		bw:                          http2newBufferedWriter(c),
+		handler:                     opts.handler(),
+		streams:                     make(map[uint32]*http2stream),
+		readFrameCh:                 make(chan http2readFrameResult),
+		wantWriteFrameCh:            make(chan http2FrameWriteRequest, 8),
+		serveMsgCh:                  make(chan interface{}, 8),
+		wroteFrameCh:                make(chan http2frameWriteResult, 1), // buffered; one send in writeFrameAsync
+		bodyReadCh:                  make(chan http2bodyReadMsg),         // buffering doesn't matter either way
+		doneServing:                 make(chan struct{}),
+		clientMaxStreams:            math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
+		advMaxStreams:               s.maxConcurrentStreams(),
+		initialStreamSendWindowSize: http2initialWindowSize,
+		maxFrameSize:                http2initialMaxFrameSize,
+		headerTableSize:             http2initialHeaderTableSize,
+		serveG:                      http2newGoroutineLock(),
+		pushEnabled:                 true,
+	}
+
+	s.state.registerConn(sc)
+	defer s.state.unregisterConn(sc)
+
+	// The net/http package sets the write deadline from the
+	// http.Server.WriteTimeout during the TLS handshake, but then
+	// passes the connection off to us with the deadline already set.
+	// Write deadlines are set per stream in serverConn.newStream.
+	// Disarm the net.Conn write deadline here.
 	if sc.hs.WriteTimeout != 0 {
 		sc.conn.SetWriteDeadline(time.Time{})
 	}
@@ -3151,6 +4053,9 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 		sc.writeSched = http2NewRandomWriteScheduler()
 	}
 
+	// These start at the RFC-specified defaults. If there is a higher
+	// configured value for inflow, that will be updated when we send a
+	// WINDOW_UPDATE shortly after sending SETTINGS.
 	sc.flow.add(http2initialWindowSize)
 	sc.inflow.add(http2initialWindowSize)
 	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
@@ -3164,18 +4069,44 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 	if tc, ok := c.(http2connectionStater); ok {
 		sc.tlsState = new(tls.ConnectionState)
 		*sc.tlsState = tc.ConnectionState()
-
+		// 9.2 Use of TLS Features
+		// An implementation of HTTP/2 over TLS MUST use TLS
+		// 1.2 or higher with the restrictions on feature set
+		// and cipher suite described in this section. Due to
+		// implementation limitations, it might not be
+		// possible to fail TLS negotiation. An endpoint MUST
+		// immediately terminate an HTTP/2 connection that
+		// does not meet the TLS requirements described in
+		// this section with a connection error (Section
+		// 5.4.1) of type INADEQUATE_SECURITY.
 		if sc.tlsState.Version < tls.VersionTLS12 {
 			sc.rejectConn(http2ErrCodeInadequateSecurity, "TLS version too low")
 			return
 		}
 
 		if sc.tlsState.ServerName == "" {
-
+			// Client must use SNI, but we don't enforce that anymore,
+			// since it was causing problems when connecting to bare IP
+			// addresses during development.
+			//
+			// TODO: optionally enforce? Or enforce at the time we receive
+			// a new request, and verify the the ServerName matches the :authority?
+			// But that precludes proxy situations, perhaps.
+			//
+			// So for now, do nothing here again.
 		}
 
 		if !s.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
-
+			// "Endpoints MAY choose to generate a connection error
+			// (Section 5.4.1) of type INADEQUATE_SECURITY if one of
+			// the prohibited cipher suites are negotiated."
+			//
+			// We choose that. In my opinion, the spec is weak
+			// here. It also says both parties must support at least
+			// TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no
+			// excuses here. If we really must, we could allow an
+			// "AllowInsecureWeakCiphers" option on the server later.
+			// Let's see how it plays out first.
 			sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
 			return
 		}
@@ -3189,7 +4120,7 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 
 func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
 	sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
-
+	// ignoring errors. hanging up anyway.
 	sc.framer.WriteGoAway(0, err, []byte(debug))
 	sc.bw.Flush()
 	sc.conn.Close()
@@ -3207,10 +4138,9 @@ type http2serverConn struct {
 	doneServing      chan struct{}               // closed when serverConn.serve ends
 	readFrameCh      chan http2readFrameResult   // written by serverConn.readFrames
 	wantWriteFrameCh chan http2FrameWriteRequest // from handlers -> serve
-	wantStartPushCh  chan http2startPushRequest  // from handlers -> serve
 	wroteFrameCh     chan http2frameWriteResult  // from writeFrameAsync -> serve, tickles more frame writes
 	bodyReadCh       chan http2bodyReadMsg       // from handlers -> serve
-	testHookCh       chan func(int)              // code to run on the serve loop
+	serveMsgCh       chan interface{}            // misc messages & code to send to / run on the serve loop
 	flow             http2flow                   // conn-wide (not stream-specific) outbound flow control
 	inflow           http2flow                   // conn-wide inbound flow control
 	tlsState         *tls.ConnectionState        // shared by all handlers, like net/http
@@ -3218,38 +4148,39 @@ type http2serverConn struct {
 	writeSched       http2WriteScheduler
 
 	// Everything following is owned by the serve loop; use serveG.check():
-	serveG                http2goroutineLock // used to verify funcs are on serve()
-	pushEnabled           bool
-	sawFirstSettings      bool // got the initial SETTINGS frame after the preface
-	needToSendSettingsAck bool
-	unackedSettings       int    // how many SETTINGS have we sent without ACKs?
-	clientMaxStreams      uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
-	advMaxStreams         uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
-	curClientStreams      uint32 // number of open streams initiated by the client
-	curPushedStreams      uint32 // number of open streams initiated by server push
-	maxClientStreamID     uint32 // max ever seen from client (odd), or 0 if there have been no client requests
-	maxPushPromiseID      uint32 // ID of the last push promise (even), or 0 if there have been no pushes
-	streams               map[uint32]*http2stream
-	initialWindowSize     int32
-	maxFrameSize          int32
-	headerTableSize       uint32
-	peerMaxHeaderListSize uint32            // zero means unknown (default)
-	canonHeader           map[string]string // http2-lower-case -> Go-Canonical-Case
-	writingFrame          bool              // started writing a frame (on serve goroutine or separate)
-	writingFrameAsync     bool              // started a frame on its own goroutine but haven't heard back on wroteFrameCh
-	needsFrameFlush       bool              // last frame write wasn't a flush
-	inGoAway              bool              // we've started to or sent GOAWAY
-	inFrameScheduleLoop   bool              // whether we're in the scheduleFrameWrite loop
-	needToSendGoAway      bool              // we need to schedule a GOAWAY frame write
-	goAwayCode            http2ErrCode
-	shutdownTimerCh       <-chan time.Time // nil until used
-	shutdownTimer         *time.Timer      // nil until used
-	idleTimer             *time.Timer      // nil if unused
-	idleTimerCh           <-chan time.Time // nil if unused
+	serveG                      http2goroutineLock // used to verify funcs are on serve()
+	pushEnabled                 bool
+	sawFirstSettings            bool // got the initial SETTINGS frame after the preface
+	needToSendSettingsAck       bool
+	unackedSettings             int    // how many SETTINGS have we sent without ACKs?
+	clientMaxStreams            uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
+	advMaxStreams               uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
+	curClientStreams            uint32 // number of open streams initiated by the client
+	curPushedStreams            uint32 // number of open streams initiated by server push
+	maxClientStreamID           uint32 // max ever seen from client (odd), or 0 if there have been no client requests
+	maxPushPromiseID            uint32 // ID of the last push promise (even), or 0 if there have been no pushes
+	streams                     map[uint32]*http2stream
+	initialStreamSendWindowSize int32
+	maxFrameSize                int32
+	headerTableSize             uint32
+	peerMaxHeaderListSize       uint32            // zero means unknown (default)
+	canonHeader                 map[string]string // http2-lower-case -> Go-Canonical-Case
+	writingFrame                bool              // started writing a frame (on serve goroutine or separate)
+	writingFrameAsync           bool              // started a frame on its own goroutine but haven't heard back on wroteFrameCh
+	needsFrameFlush             bool              // last frame write wasn't a flush
+	inGoAway                    bool              // we've started to or sent GOAWAY
+	inFrameScheduleLoop         bool              // whether we're in the scheduleFrameWrite loop
+	needToSendGoAway            bool              // we need to schedule a GOAWAY frame write
+	goAwayCode                  http2ErrCode
+	shutdownTimer               *time.Timer // nil until used
+	idleTimer                   *time.Timer // nil if unused
 
 	// Owned by the writeFrameAsync goroutine:
 	headerWriteBuf bytes.Buffer
 	hpackEncoder   *hpack.Encoder
+
+	// Used by startGracefulShutdown.
+	shutdownOnce sync.Once
 }
 
 func (sc *http2serverConn) maxHeaderListSize() uint32 {
@@ -3294,10 +4225,10 @@ type http2stream struct {
 	numTrailerValues int64
 	weight           uint8
 	state            http2streamState
-	resetQueued      bool   // RST_STREAM queued for write; set by sc.resetStream
-	gotTrailerHeader bool   // HEADER frame for trailers was seen
-	wroteHeaders     bool   // whether we wrote headers (not status 100)
-	reqBuf           []byte // if non-nil, body pipe buffer to return later at EOF
+	resetQueued      bool        // RST_STREAM queued for write; set by sc.resetStream
+	gotTrailerHeader bool        // HEADER frame for trailers was seen
+	wroteHeaders     bool        // whether we wrote headers (not status 100)
+	writeDeadline    *time.Timer // nil if unused
 
 	trailer    Header // accumulated trailers
 	reqTrailer Header // handler's Request.Trailer
@@ -3315,11 +4246,16 @@ func (sc *http2serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
 
 func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2stream) {
 	sc.serveG.check()
-
+	// http://tools.ietf.org/html/rfc7540#section-5.1
 	if st, ok := sc.streams[streamID]; ok {
 		return st.state, st
 	}
-
+	// "The first use of a new stream identifier implicitly closes all
+	// streams in the "idle" state that might have been initiated by
+	// that peer with a lower-valued stream identifier. For example, if
+	// a client sends a HEADERS frame on stream 7 without ever sending a
+	// frame on stream 5, then stream 5 transitions to the "closed"
+	// state when the first frame for stream 7 is sent or received."
 	if streamID%2 == 1 {
 		if streamID <= sc.maxClientStreamID {
 			return http2stateClosed, nil
@@ -3373,11 +4309,18 @@ func http2isClosedConnError(err error) bool {
 		return false
 	}
 
+	// TODO: remove this string search and be more like the Windows
+	// case below. That might involve modifying the standard library
+	// to return better error types.
 	str := err.Error()
 	if strings.Contains(str, "use of closed network connection") {
 		return true
 	}
 
+	// TODO(bradfitz): x/tools/cmd/bundle doesn't really support
+	// build tags, so I can't make an http2_windows.go file with
+	// Windows-specific stuff. Fix that and move this, once we
+	// have a way to bundle this into std's net/http somehow.
 	if runtime.GOOS == "windows" {
 		if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
 			if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
@@ -3397,7 +4340,7 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{
 		return
 	}
 	if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) {
-
+		// Boring, expected errors.
 		sc.vlogf(format, args...)
 	} else {
 		sc.logf(format, args...)
@@ -3487,7 +4430,7 @@ func (sc *http2serverConn) stopShutdownTimer() {
 }
 
 func (sc *http2serverConn) notePanic() {
-
+	// Note: this is for serverConn.serve panicking, not http.Handler code.
 	if http2testHookOnPanicMu != nil {
 		http2testHookOnPanicMu.Lock()
 		defer http2testHookOnPanicMu.Unlock()
@@ -3507,7 +4450,7 @@ func (sc *http2serverConn) serve() {
 	defer sc.conn.Close()
 	defer sc.closeAllStreamsOnConnClose()
 	defer sc.stopShutdownTimer()
-	defer close(sc.doneServing)
+	defer close(sc.doneServing) // unblocks handlers trying to send
 
 	if http2VerboseLogs {
 		sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
@@ -3518,44 +4461,48 @@ func (sc *http2serverConn) serve() {
 			{http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
 			{http2SettingMaxConcurrentStreams, sc.advMaxStreams},
 			{http2SettingMaxHeaderListSize, sc.maxHeaderListSize()},
+			{http2SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
 		},
 	})
 	sc.unackedSettings++
 
+	// Each connection starts with intialWindowSize inflow tokens.
+	// If a higher value is configured, we add more tokens.
+	if diff := sc.srv.initialConnRecvWindowSize() - http2initialWindowSize; diff > 0 {
+		sc.sendWindowUpdate(nil, int(diff))
+	}
+
 	if err := sc.readPreface(); err != nil {
 		sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
 		return
 	}
-
+	// Now that we've got the preface, get us out of the
+	// "StateNew" state. We can't go directly to idle, though.
+	// Active means we read some data and anticipate a request. We'll
+	// do another Active when we get a HEADERS frame.
 	sc.setConnState(StateActive)
 	sc.setConnState(StateIdle)
 
 	if sc.srv.IdleTimeout != 0 {
-		sc.idleTimer = time.NewTimer(sc.srv.IdleTimeout)
+		sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
 		defer sc.idleTimer.Stop()
-		sc.idleTimerCh = sc.idleTimer.C
 	}
 
-	var gracefulShutdownCh chan struct{}
-	if sc.hs != nil {
-		ch := http2h1ServerShutdownChan(sc.hs)
-		if ch != nil {
-			gracefulShutdownCh = make(chan struct{})
-			go sc.awaitGracefulShutdown(ch, gracefulShutdownCh)
-		}
-	}
+	go sc.readFrames() // closed by defer sc.conn.Close above
 
-	go sc.readFrames()
+	settingsTimer := time.AfterFunc(http2firstSettingsTimeout, sc.onSettingsTimer)
+	defer settingsTimer.Stop()
 
-	settingsTimer := time.NewTimer(http2firstSettingsTimeout)
 	loopNum := 0
 	for {
 		loopNum++
 		select {
 		case wr := <-sc.wantWriteFrameCh:
+			if se, ok := wr.write.(http2StreamError); ok {
+				sc.resetStream(se)
+				break
+			}
 			sc.writeFrame(wr)
-		case spr := <-sc.wantStartPushCh:
-			sc.startPush(spr)
 		case res := <-sc.wroteFrameCh:
 			sc.wroteFrame(res)
 		case res := <-sc.readFrameCh:
@@ -3563,26 +4510,37 @@ func (sc *http2serverConn) serve() {
 				return
 			}
 			res.readMore()
-			if settingsTimer.C != nil {
+			if settingsTimer != nil {
 				settingsTimer.Stop()
-				settingsTimer.C = nil
+				settingsTimer = nil
 			}
 		case m := <-sc.bodyReadCh:
 			sc.noteBodyRead(m.st, m.n)
-		case <-settingsTimer.C:
-			sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
-			return
-		case <-gracefulShutdownCh:
-			gracefulShutdownCh = nil
-			sc.startGracefulShutdown()
-		case <-sc.shutdownTimerCh:
-			sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
-			return
-		case <-sc.idleTimerCh:
-			sc.vlogf("connection is idle")
-			sc.goAway(http2ErrCodeNo)
-		case fn := <-sc.testHookCh:
-			fn(loopNum)
+		case msg := <-sc.serveMsgCh:
+			switch v := msg.(type) {
+			case func(int):
+				v(loopNum) // for testing
+			case *http2serverMessage:
+				switch v {
+				case http2settingsTimerMsg:
+					sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
+					return
+				case http2idleTimerMsg:
+					sc.vlogf("connection is idle")
+					sc.goAway(http2ErrCodeNo)
+				case http2shutdownTimerMsg:
+					sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
+					return
+				case http2gracefulShutdownMsg:
+					sc.startGracefulShutdownInternal()
+				default:
+					panic("unknown timer")
+				}
+			case *http2startPushRequest:
+				sc.startPush(v)
+			default:
+				panic(fmt.Sprintf("unexpected type %T", v))
+			}
 		}
 
 		if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame {
@@ -3599,12 +4557,36 @@ func (sc *http2serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, priva
 	}
 }
 
+type http2serverMessage int
+
+// Message values sent to serveMsgCh.
+var (
+	http2settingsTimerMsg    = new(http2serverMessage)
+	http2idleTimerMsg        = new(http2serverMessage)
+	http2shutdownTimerMsg    = new(http2serverMessage)
+	http2gracefulShutdownMsg = new(http2serverMessage)
+)
+
+func (sc *http2serverConn) onSettingsTimer() { sc.sendServeMsg(http2settingsTimerMsg) }
+
+func (sc *http2serverConn) onIdleTimer() { sc.sendServeMsg(http2idleTimerMsg) }
+
+func (sc *http2serverConn) onShutdownTimer() { sc.sendServeMsg(http2shutdownTimerMsg) }
+
+func (sc *http2serverConn) sendServeMsg(msg interface{}) {
+	sc.serveG.checkNotOn() // NOT
+	select {
+	case sc.serveMsgCh <- msg:
+	case <-sc.doneServing:
+	}
+}
+
 // readPreface reads the ClientPreface greeting from the peer
 // or returns an error on timeout or an invalid greeting.
 func (sc *http2serverConn) readPreface() error {
 	errc := make(chan error, 1)
 	go func() {
-
+		// Read the client preface
 		buf := make([]byte, len(http2ClientPreface))
 		if _, err := io.ReadFull(sc.conn, buf); err != nil {
 			errc <- err
@@ -3614,7 +4596,7 @@ func (sc *http2serverConn) readPreface() error {
 			errc <- nil
 		}
 	}()
-	timer := time.NewTimer(http2prefaceTimeout)
+	timer := time.NewTimer(http2prefaceTimeout) // TODO: configurable on *Server?
 	defer timer.Stop()
 	select {
 	case <-timer.C:
@@ -3658,7 +4640,13 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
 	case <-sc.doneServing:
 		return http2errClientDisconnected
 	case <-stream.cw:
-
+		// If both ch and stream.cw were ready (as might
+		// happen on the final Write after an http.Handler
+		// ends), prefer the write result. Otherwise this
+		// might just be us successfully closing the stream.
+		// The writeFrameAsync and serve goroutines guarantee
+		// that the ch send will happen before the stream.cw
+		// close.
 		select {
 		case err = <-ch:
 			frameWriteDone = true
@@ -3681,12 +4669,13 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
 // buffered and is read by serve itself). If you're on the serve
 // goroutine, call writeFrame instead.
 func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) error {
-	sc.serveG.checkNotOn()
+	sc.serveG.checkNotOn() // NOT
 	select {
 	case sc.wantWriteFrameCh <- wr:
 		return nil
 	case <-sc.doneServing:
-
+		// Serve loop is gone.
+		// Client has closed their connection to the server.
 		return http2errClientDisconnected
 	}
 }
@@ -3705,6 +4694,24 @@ func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
 	// If true, wr will not be written and wr.done will not be signaled.
 	var ignoreWrite bool
 
+	// We are not allowed to write frames on closed streams. RFC 7540 Section
+	// 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on
+	// a closed stream." Our server never sends PRIORITY, so that exception
+	// does not apply.
+	//
+	// The serverConn might close an open stream while the stream's handler
+	// is still running. For example, the server might close a stream when it
+	// receives bad data from the client. If this happens, the handler might
+	// attempt to write a frame after the stream has been closed (since the
+	// handler hasn't yet been notified of the close). In this case, we simply
+	// ignore the frame. The handler will notice that the stream is closed when
+	// it waits for the frame to be written.
+	//
+	// As an exception to this rule, we allow sending RST_STREAM after close.
+	// This allows us to immediately reject new streams without tracking any
+	// state for those streams (except for the queued RST_STREAM frame). This
+	// may result in duplicate RST_STREAMs in some cases, but the client should
+	// ignore those.
 	if wr.StreamID() != 0 {
 		_, isReset := wr.write.(http2StreamError)
 		if state, _ := sc.state(wr.StreamID()); state == http2stateClosed && !isReset {
@@ -3712,12 +4719,15 @@ func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
 		}
 	}
 
+	// Don't send a 100-continue response if we've already sent headers.
+	// See golang.org/issue/14030.
 	switch wr.write.(type) {
 	case *http2writeResHeaders:
 		wr.stream.wroteHeaders = true
 	case http2write100ContinueHeadersFrame:
 		if wr.stream.wroteHeaders {
-
+			// We do not need to notify wr.done because this frame is
+			// never written with wr.done != nil.
 			if wr.done != nil {
 				panic("wr.done != nil for write100ContinueHeadersFrame")
 			}
@@ -3746,7 +4756,8 @@ func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
 		case http2stateHalfClosedLocal:
 			switch wr.write.(type) {
 			case http2StreamError, http2handlerPanicRST, http2writeWindowUpdate:
-
+				// RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE
+				// in this state. (We never send PRIORITY from the server, so that is not checked.)
 			default:
 				panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
 			}
@@ -3800,16 +4811,29 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
 		}
 		switch st.state {
 		case http2stateOpen:
-
+			// Here we would go to stateHalfClosedLocal in
+			// theory, but since our handler is done and
+			// the net/http package provides no mechanism
+			// for closing a ResponseWriter while still
+			// reading data (see possible TODO at top of
+			// this file), we go into closed state here
+			// anyway, after telling the peer we're
+			// hanging up on them. We'll transition to
+			// stateClosed after the RST_STREAM frame is
+			// written.
 			st.state = http2stateHalfClosedLocal
-			sc.resetStream(http2streamError(st.id, http2ErrCodeCancel))
+			// Section 8.1: a server MAY request that the client abort
+			// transmission of a request without error by sending a
+			// RST_STREAM with an error code of NO_ERROR after sending
+			// a complete response.
+			sc.resetStream(http2streamError(st.id, http2ErrCodeNo))
 		case http2stateHalfClosedRemote:
 			sc.closeStream(st, http2errHandlerComplete)
 		}
 	} else {
 		switch v := wr.write.(type) {
 		case http2StreamError:
-
+			// st may be unknown if the RST_STREAM was generated to reject bad input.
 			if st, ok := sc.streams[v.StreamID]; ok {
 				sc.closeStream(st, v)
 			}
@@ -3818,6 +4842,7 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
 		}
 	}
 
+	// Reply (if requested) to unblock the ServeHTTP goroutine.
 	wr.replyToWriter(res.err)
 
 	sc.scheduleFrameWrite()
@@ -3865,7 +4890,7 @@ func (sc *http2serverConn) scheduleFrameWrite() {
 		}
 		if sc.needsFrameFlush {
 			sc.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}})
-			sc.needsFrameFlush = false
+			sc.needsFrameFlush = false // after startFrameWrite, since it sets this true
 			continue
 		}
 		break
@@ -3873,10 +4898,19 @@ func (sc *http2serverConn) scheduleFrameWrite() {
 	sc.inFrameScheduleLoop = false
 }
 
-// startGracefulShutdown sends a GOAWAY with ErrCodeNo to tell the
-// client we're gracefully shutting down. The connection isn't closed
-// until all current streams are done.
+// startGracefulShutdown gracefully shuts down a connection. This
+// sends GOAWAY with ErrCodeNo to tell the client we're gracefully
+// shutting down. The connection isn't closed until all current
+// streams are done.
+//
+// startGracefulShutdown returns immediately; it does not wait until
+// the connection has shut down.
 func (sc *http2serverConn) startGracefulShutdown() {
+	sc.serveG.checkNotOn() // NOT
+	sc.shutdownOnce.Do(func() { sc.sendServeMsg(http2gracefulShutdownMsg) })
+}
+
+func (sc *http2serverConn) startGracefulShutdownInternal() {
 	sc.goAwayIn(http2ErrCodeNo, 0)
 }
 
@@ -3886,7 +4920,7 @@ func (sc *http2serverConn) goAway(code http2ErrCode) {
 	if code != http2ErrCodeNo {
 		forceCloseIn = 250 * time.Millisecond
 	} else {
-
+		// TODO: configurable
 		forceCloseIn = 1 * time.Second
 	}
 	sc.goAwayIn(code, forceCloseIn)
@@ -3908,8 +4942,7 @@ func (sc *http2serverConn) goAwayIn(code http2ErrCode, forceCloseIn time.Duratio
 
 func (sc *http2serverConn) shutDownIn(d time.Duration) {
 	sc.serveG.check()
-	sc.shutdownTimer = time.NewTimer(d)
-	sc.shutdownTimerCh = sc.shutdownTimer.C
+	sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer)
 }
 
 func (sc *http2serverConn) resetStream(se http2StreamError) {
@@ -3929,11 +4962,18 @@ func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool
 	if err != nil {
 		if err == http2ErrFrameTooLarge {
 			sc.goAway(http2ErrCodeFrameSize)
-			return true
+			return true // goAway will close the loop
 		}
 		clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err)
 		if clientGone {
-
+			// TODO: could we also get into this state if
+			// the peer does a half close
+			// (e.g. CloseWrite) because they're done
+			// sending frames but they're still wanting
+			// our open replies?  Investigate.
+			// TODO: add CloseWrite to crypto/tls.Conn first
+			// so we have a way to test this? I suppose
+			// just for testing we could have a non-TLS mode.
 			return false
 		}
 	} else {
@@ -3957,7 +4997,7 @@ func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool
 	case http2ConnectionError:
 		sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
 		sc.goAway(http2ErrCode(ev))
-		return true
+		return true // goAway will handle shutdown
 	default:
 		if res.err != nil {
 			sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
@@ -3971,6 +5011,7 @@ func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool
 func (sc *http2serverConn) processFrame(f http2Frame) error {
 	sc.serveG.check()
 
+	// First frame received must be SETTINGS.
 	if !sc.sawFirstSettings {
 		if _, ok := f.(*http2SettingsFrame); !ok {
 			return http2ConnectionError(http2ErrCodeProtocol)
@@ -3996,7 +5037,8 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
 	case *http2GoAwayFrame:
 		return sc.processGoAway(f)
 	case *http2PushPromiseFrame:
-
+		// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
+		// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
 		return http2ConnectionError(http2ErrCodeProtocol)
 	default:
 		sc.vlogf("http2: server ignoring frame: %v", f.Header())
@@ -4007,11 +5049,16 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
 func (sc *http2serverConn) processPing(f *http2PingFrame) error {
 	sc.serveG.check()
 	if f.IsAck() {
-
+		// 6.7 PING: " An endpoint MUST NOT respond to PING frames
+		// containing this flag."
 		return nil
 	}
 	if f.StreamID != 0 {
-
+		// "PING frames are not associated with any individual
+		// stream. If a PING frame is received with a stream
+		// identifier field value other than 0x0, the recipient MUST
+		// respond with a connection error (Section 5.4.1) of type
+		// PROTOCOL_ERROR."
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 	if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
@@ -4024,20 +5071,27 @@ func (sc *http2serverConn) processPing(f *http2PingFrame) error {
 func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error {
 	sc.serveG.check()
 	switch {
-	case f.StreamID != 0:
+	case f.StreamID != 0: // stream-level flow control
 		state, st := sc.state(f.StreamID)
 		if state == http2stateIdle {
-
+			// Section 5.1: "Receiving any frame other than HEADERS
+			// or PRIORITY on a stream in this state MUST be
+			// treated as a connection error (Section 5.4.1) of
+			// type PROTOCOL_ERROR."
 			return http2ConnectionError(http2ErrCodeProtocol)
 		}
 		if st == nil {
-
+			// "WINDOW_UPDATE can be sent by a peer that has sent a
+			// frame bearing the END_STREAM flag. This means that a
+			// receiver could receive a WINDOW_UPDATE frame on a "half
+			// closed (remote)" or "closed" stream. A receiver MUST
+			// NOT treat this as an error, see Section 5.1."
 			return nil
 		}
 		if !st.flow.add(int32(f.Increment)) {
 			return http2streamError(f.StreamID, http2ErrCodeFlowControl)
 		}
-	default:
+	default: // connection-level flow control
 		if !sc.flow.add(int32(f.Increment)) {
 			return http2goAwayFlowError{}
 		}
@@ -4051,7 +5105,11 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
 
 	state, st := sc.state(f.StreamID)
 	if state == http2stateIdle {
-
+		// 6.4 "RST_STREAM frames MUST NOT be sent for a
+		// stream in the "idle" state. If a RST_STREAM frame
+		// identifying an idle stream is received, the
+		// recipient MUST treat this as a connection error
+		// (Section 5.4.1) of type PROTOCOL_ERROR.
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 	if st != nil {
@@ -4067,6 +5125,9 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
 		panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
 	}
 	st.state = http2stateClosed
+	if st.writeDeadline != nil {
+		st.writeDeadline.Stop()
+	}
 	if st.isPushed() {
 		sc.curPushedStreams--
 	} else {
@@ -4079,16 +5140,17 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
 			sc.idleTimer.Reset(sc.srv.IdleTimeout)
 		}
 		if http2h1ServerKeepAlivesDisabled(sc.hs) {
-			sc.startGracefulShutdown()
+			sc.startGracefulShutdownInternal()
 		}
 	}
 	if p := st.body; p != nil {
-
+		// Return any buffered unread bytes worth of conn-level flow control.
+		// See golang.org/issue/16481
 		sc.sendWindowUpdate(nil, p.Len())
 
 		p.CloseWithError(err)
 	}
-	st.cw.Close()
+	st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
 	sc.writeSched.CloseStream(st.id)
 }
 
@@ -4097,7 +5159,9 @@ func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
 	if f.IsAck() {
 		sc.unackedSettings--
 		if sc.unackedSettings < 0 {
-
+			// Why is the peer ACKing settings we never sent?
+			// The spec doesn't mention this case, but
+			// hang up on them anyway.
 			return http2ConnectionError(http2ErrCodeProtocol)
 		}
 		return nil
@@ -4129,11 +5193,13 @@ func (sc *http2serverConn) processSetting(s http2Setting) error {
 	case http2SettingInitialWindowSize:
 		return sc.processSettingInitialWindowSize(s.Val)
 	case http2SettingMaxFrameSize:
-		sc.maxFrameSize = int32(s.Val)
+		sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31
 	case http2SettingMaxHeaderListSize:
 		sc.peerMaxHeaderListSize = s.Val
 	default:
-
+		// Unknown setting: "An endpoint that receives a SETTINGS
+		// frame with any unknown or unsupported identifier MUST
+		// ignore that setting."
 		if http2VerboseLogs {
 			sc.vlogf("http2: server ignoring unknown setting %v", s)
 		}
@@ -4143,13 +5209,26 @@ func (sc *http2serverConn) processSetting(s http2Setting) error {
 
 func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
 	sc.serveG.check()
-
-	old := sc.initialWindowSize
-	sc.initialWindowSize = int32(val)
-	growth := sc.initialWindowSize - old
+	// Note: val already validated to be within range by
+	// processSetting's Valid call.
+
+	// "A SETTINGS frame can alter the initial flow control window
+	// size for all current streams. When the value of
+	// SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST
+	// adjust the size of all stream flow control windows that it
+	// maintains by the difference between the new value and the
+	// old value."
+	old := sc.initialStreamSendWindowSize
+	sc.initialStreamSendWindowSize = int32(val)
+	growth := int32(val) - old // may be negative
 	for _, st := range sc.streams {
 		if !st.flow.add(growth) {
-
+			// 6.9.2 Initial Flow Control Window Size
+			// "An endpoint MUST treat a change to
+			// SETTINGS_INITIAL_WINDOW_SIZE that causes any flow
+			// control window to exceed the maximum size as a
+			// connection error (Section 5.4.1) of type
+			// FLOW_CONTROL_ERROR."
 			return http2ConnectionError(http2ErrCodeFlowControl)
 		}
 	}
@@ -4163,23 +5242,40 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
 	}
 	data := f.Data()
 
+	// "If a DATA frame is received whose stream is not in "open"
+	// or "half closed (local)" state, the recipient MUST respond
+	// with a stream error (Section 5.4.2) of type STREAM_CLOSED."
 	id := f.Header().StreamID
 	state, st := sc.state(id)
 	if id == 0 || state == http2stateIdle {
-
+		// Section 5.1: "Receiving any frame other than HEADERS
+		// or PRIORITY on a stream in this state MUST be
+		// treated as a connection error (Section 5.4.1) of
+		// type PROTOCOL_ERROR."
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 	if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued {
-
+		// This includes sending a RST_STREAM if the stream is
+		// in stateHalfClosedLocal (which currently means that
+		// the http.Handler returned, so it's done reading &
+		// done writing). Try to stop the client from sending
+		// more DATA.
+
+		// But still enforce their connection-level flow control,
+		// and return any flow control bytes since we're not going
+		// to consume them.
 		if sc.inflow.available() < int32(f.Length) {
 			return http2streamError(id, http2ErrCodeFlowControl)
 		}
-
+		// Deduct the flow control from inflow, since we're
+		// going to immediately add it back in
+		// sendWindowUpdate, which also schedules sending the
+		// frames.
 		sc.inflow.take(int32(f.Length))
-		sc.sendWindowUpdate(nil, int(f.Length))
+		sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
 
 		if st != nil && st.resetQueued {
-
+			// Already have a stream error in flight. Don't send another.
 			return nil
 		}
 		return http2streamError(id, http2ErrCodeStreamClosed)
@@ -4188,12 +5284,13 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
 		panic("internal error: should have a body in this state")
 	}
 
+	// Sender sending more than they'd declared?
 	if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
 		st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
 		return http2streamError(id, http2ErrCodeStreamClosed)
 	}
 	if f.Length > 0 {
-
+		// Check whether the client has flow control quota.
 		if st.inflow.available() < int32(f.Length) {
 			return http2streamError(id, http2ErrCodeFlowControl)
 		}
@@ -4210,6 +5307,8 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
 			st.bodyBytes += int64(len(data))
 		}
 
+		// Return any padded flow control now, since we won't
+		// refund it later on body reads.
 		if pad := int32(f.Length) - int32(len(data)); pad > 0 {
 			sc.sendWindowUpdate32(nil, pad)
 			sc.sendWindowUpdate32(st, pad)
@@ -4228,8 +5327,9 @@ func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error {
 	} else {
 		sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
 	}
-	sc.startGracefulShutdown()
-
+	sc.startGracefulShutdownInternal()
+	// http://tools.ietf.org/html/rfc7540#section-6.8
+	// We should not create any new streams, which means we should disable push.
 	sc.pushEnabled = false
 	return nil
 }
@@ -4260,32 +5360,51 @@ func (st *http2stream) endStream() {
 func (st *http2stream) copyTrailersToHandlerRequest() {
 	for k, vv := range st.trailer {
 		if _, ok := st.reqTrailer[k]; ok {
-
+			// Only copy it over it was pre-declared.
 			st.reqTrailer[k] = vv
 		}
 	}
 }
 
+// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
+// when the stream's WriteTimeout has fired.
+func (st *http2stream) onWriteTimeout() {
+	st.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2streamError(st.id, http2ErrCodeInternal)})
+}
+
 func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
 	sc.serveG.check()
 	id := f.StreamID
 	if sc.inGoAway {
-
+		// Ignore.
 		return nil
 	}
-
+	// http://tools.ietf.org/html/rfc7540#section-5.1.1
+	// Streams initiated by a client MUST use odd-numbered stream
+	// identifiers. [...] An endpoint that receives an unexpected
+	// stream identifier MUST respond with a connection error
+	// (Section 5.4.1) of type PROTOCOL_ERROR.
 	if id%2 != 1 {
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
-
+	// A HEADERS frame can be used to create a new stream or
+	// send a trailer for an open one. If we already have a stream
+	// open, let it process its own HEADERS frame (trailers at this
+	// point, if it's valid).
 	if st := sc.streams[f.StreamID]; st != nil {
 		if st.resetQueued {
-
+			// We're sending RST_STREAM to close the stream, so don't bother
+			// processing this frame.
 			return nil
 		}
 		return st.processTrailerHeaders(f)
 	}
 
+	// [...] The identifier of a newly established stream MUST be
+	// numerically greater than all streams that the initiating
+	// endpoint has opened or reserved. [...]  An endpoint that
+	// receives an unexpected stream identifier MUST respond with
+	// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
 	if id <= sc.maxClientStreamID {
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
@@ -4295,12 +5414,22 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
 		sc.idleTimer.Stop()
 	}
 
+	// http://tools.ietf.org/html/rfc7540#section-5.1.2
+	// [...] Endpoints MUST NOT exceed the limit set by their peer. An
+	// endpoint that receives a HEADERS frame that causes their
+	// advertised concurrent stream limit to be exceeded MUST treat
+	// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR
+	// or REFUSED_STREAM.
 	if sc.curClientStreams+1 > sc.advMaxStreams {
 		if sc.unackedSettings == 0 {
-
+			// They should know better.
 			return http2streamError(id, http2ErrCodeProtocol)
 		}
-
+		// Assume it's a network race, where they just haven't
+		// received our last SETTINGS update. But actually
+		// this can't happen yet, because we don't yet provide
+		// a way for users to adjust server parameters at
+		// runtime.
 		return http2streamError(id, http2ErrCodeRefusedStream)
 	}
 
@@ -4325,17 +5454,24 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
 	if st.reqTrailer != nil {
 		st.trailer = make(Header)
 	}
-	st.body = req.Body.(*http2requestBody).pipe
+	st.body = req.Body.(*http2requestBody).pipe // may be nil
 	st.declBodyBytes = req.ContentLength
 
 	handler := sc.handler.ServeHTTP
 	if f.Truncated {
-
+		// Their header list was too long. Send a 431 error.
 		handler = http2handleHeaderListTooLong
 	} else if err := http2checkValidHTTP2RequestHeaders(req.Header); err != nil {
 		handler = http2new400Handler(err)
 	}
 
+	// The net/http package sets the read deadline from the
+	// http.Server.ReadTimeout during the TLS handshake, but then
+	// passes the connection off to us with the deadline already
+	// set. Disarm it here after the request headers are read,
+	// similar to how the http1 server works. Here it's
+	// technically more like the http1 Server's ReadHeaderTimeout
+	// (in Go 1.8), though. That's a more sane option anyway.
 	if sc.hs.ReadTimeout != 0 {
 		sc.conn.SetReadDeadline(time.Time{})
 	}
@@ -4362,7 +5498,9 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
 		for _, hf := range f.RegularFields() {
 			key := sc.canonicalHeader(hf.Name)
 			if !http2ValidTrailerHeader(key) {
-
+				// TODO: send more details to the peer somehow. But http2 has
+				// no way to send debug data at a stream level. Discuss with
+				// HTTP folk.
 				return http2streamError(st.id, http2ErrCodeProtocol)
 			}
 			st.trailer[key] = append(st.trailer[key], hf.Value)
@@ -4374,7 +5512,10 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
 
 func http2checkPriority(streamID uint32, p http2PriorityParam) error {
 	if streamID == p.StreamDep {
-
+		// Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
+		// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
+		// Section 5.3.3 says that a stream can depend on one of its dependencies,
+		// so it's only self-dependencies that are forbidden.
 		return http2streamError(streamID, http2ErrCodeProtocol)
 	}
 	return nil
@@ -4406,10 +5547,13 @@ func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState
 		cancelCtx: cancelCtx,
 	}
 	st.cw.Init()
-	st.flow.conn = &sc.flow
-	st.flow.add(sc.initialWindowSize)
-	st.inflow.conn = &sc.inflow
-	st.inflow.add(http2initialWindowSize)
+	st.flow.conn = &sc.flow // link to conn-level counter
+	st.flow.add(sc.initialStreamSendWindowSize)
+	st.inflow.conn = &sc.inflow // link to conn-level counter
+	st.inflow.add(sc.srv.initialStreamRecvWindowSize())
+	if sc.hs.WriteTimeout != 0 {
+		st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
+	}
 
 	sc.streams[id] = st
 	sc.writeSched.OpenStream(st.id, http2OpenStreamOptions{PusherID: pusherID})
@@ -4441,13 +5585,22 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
 			return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
 		}
 	} else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
-
+		// See 8.1.2.6 Malformed Requests and Responses:
+		//
+		// Malformed requests or responses that are detected
+		// MUST be treated as a stream error (Section 5.4.2)
+		// of type PROTOCOL_ERROR."
+		//
+		// 8.1.2.3 Request Pseudo-Header Fields
+		// "All HTTP/2 requests MUST include exactly one valid
+		// value for the :method, :scheme, and :path
+		// pseudo-header fields"
 		return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
 	}
 
 	bodyOpen := !f.StreamEnded()
 	if rp.method == "HEAD" && bodyOpen {
-
+		// HEAD requests can't have bodies
 		return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
 	}
 
@@ -4464,16 +5617,14 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
 		return nil, nil, err
 	}
 	if bodyOpen {
-		st.reqBuf = http2getRequestBodyBuf()
-		req.Body.(*http2requestBody).pipe = &http2pipe{
-			b: &http2fixedBuffer{buf: st.reqBuf},
-		}
-
 		if vv, ok := rp.header["Content-Length"]; ok {
 			req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
 		} else {
 			req.ContentLength = -1
 		}
+		req.Body.(*http2requestBody).pipe = &http2pipe{
+			b: &http2dataBuffer{expected: req.ContentLength},
+		}
 	}
 	return rw, req, nil
 }
@@ -4496,7 +5647,7 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
 	if needsContinue {
 		rp.header.Del("Expect")
 	}
-
+	// Merge Cookie headers into one "; "-delimited value.
 	if cookies := rp.header["Cookie"]; len(cookies) > 1 {
 		rp.header.Set("Cookie", strings.Join(cookies, "; "))
 	}
@@ -4508,7 +5659,8 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
 			key = CanonicalHeaderKey(strings.TrimSpace(key))
 			switch key {
 			case "Transfer-Encoding", "Trailer", "Content-Length":
-
+				// Bogus. (copy of http1 rules)
+				// Ignore.
 			default:
 				if trailer == nil {
 					trailer = make(Header)
@@ -4523,7 +5675,7 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
 	var requestURI string
 	if rp.method == "CONNECT" {
 		url_ = &url.URL{Host: rp.authority}
-		requestURI = rp.authority
+		requestURI = rp.authority // mimic HTTP/1 server behavior
 	} else {
 		var err error
 		url_, err = url.ParseRequestURI(rp.path)
@@ -4556,7 +5708,7 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
 
 	rws := http2responseWriterStatePool.Get().(*http2responseWriterState)
 	bwSave := rws.bw
-	*rws = http2responseWriterState{}
+	*rws = http2responseWriterState{} // zero all the fields
 	rws.conn = sc
 	rws.bw = bwSave
 	rws.bw.Reset(http2chunkWriter{rws})
@@ -4568,24 +5720,6 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
 	return rw, req, nil
 }
 
-var http2reqBodyCache = make(chan []byte, 8)
-
-func http2getRequestBodyBuf() []byte {
-	select {
-	case b := <-http2reqBodyCache:
-		return b
-	default:
-		return make([]byte, http2initialWindowSize)
-	}
-}
-
-func http2putRequestBodyBuf(b []byte) {
-	select {
-	case http2reqBodyCache <- b:
-	default:
-	}
-}
-
 // Run on its own goroutine.
 func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
 	didPanic := true
@@ -4597,7 +5731,7 @@ func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, han
 				write:  http2handlerPanicRST{rw.rws.stream.id},
 				stream: rw.rws.stream,
 			})
-
+			// Same as net/http:
 			if http2shouldLogPanic(e) {
 				const size = 64 << 10
 				buf := make([]byte, size)
@@ -4625,10 +5759,13 @@ func http2handleHeaderListTooLong(w ResponseWriter, r *Request) {
 // called from handler goroutines.
 // h may be nil.
 func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) error {
-	sc.serveG.checkNotOn()
+	sc.serveG.checkNotOn() // NOT on
 	var errc chan error
 	if headerData.h != nil {
-
+		// If there's a header map (which we don't own), so we have to block on
+		// waiting for this frame to be written, so an http.Flush mid-handler
+		// writes out the correct value of keys, before a handler later potentially
+		// mutates it.
 		errc = http2errChanPool.Get().(chan error)
 	}
 	if err := sc.writeFrameFromHandler(http2FrameWriteRequest{
@@ -4671,26 +5808,21 @@ type http2bodyReadMsg struct {
 // Notes that the handler for the given stream ID read n bytes of its body
 // and schedules flow control tokens to be sent.
 func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err error) {
-	sc.serveG.checkNotOn()
+	sc.serveG.checkNotOn() // NOT on
 	if n > 0 {
 		select {
 		case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
 		case <-sc.doneServing:
 		}
 	}
-	if err == io.EOF {
-		if buf := st.reqBuf; buf != nil {
-			st.reqBuf = nil
-			http2putRequestBodyBuf(buf)
-		}
-	}
 }
 
 func (sc *http2serverConn) noteBodyRead(st *http2stream, n int) {
 	sc.serveG.check()
-	sc.sendWindowUpdate(nil, n)
+	sc.sendWindowUpdate(nil, n) // conn-level
 	if st.state != http2stateHalfClosedRemote && st.state != http2stateClosed {
-
+		// Don't send this WINDOW_UPDATE if the stream is closed
+		// remotely.
 		sc.sendWindowUpdate(st, n)
 	}
 }
@@ -4777,8 +5909,8 @@ func (b *http2requestBody) Read(p []byte) (n int, err error) {
 	return
 }
 
-// responseWriter is the http.ResponseWriter implementation.  It's
-// intentionally small (1 pointer wide) to minimize garbage.  The
+// responseWriter is the http.ResponseWriter implementation. It's
+// intentionally small (1 pointer wide) to minimize garbage. The
 // responseWriterState pointer inside is zeroed at the end of a
 // request (in handlerDone) and calls on the responseWriter thereafter
 // simply crash (caller's mistake), but the much larger responseWriterState
@@ -4832,7 +5964,7 @@ func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailer
 func (rws *http2responseWriterState) declareTrailer(k string) {
 	k = CanonicalHeaderKey(k)
 	if !http2ValidTrailerHeader(k) {
-
+		// Forbidden by RFC 2616 14.40.
 		rws.conn.logf("ignoring invalid trailer %q", k)
 		return
 	}
@@ -4874,7 +6006,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
 		}
 		var date string
 		if _, ok := rws.snapHeader["Date"]; !ok {
-
+			// TODO(bradfitz): be faster here, like net/http? measure.
 			date = time.Now().UTC().Format(TimeFormat)
 		}
 
@@ -4912,7 +6044,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
 
 	endStream := rws.handlerDone && !rws.hasTrailers()
 	if len(p) > 0 || endStream {
-
+		// only send a 0 byte DATA frame if we're ending the stream.
 		if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
 			return 0, err
 		}
@@ -4952,7 +6084,7 @@ const http2TrailerPrefix = "Trailer:"
 // says you SHOULD (but not must) predeclare any trailers in the
 // header, the official ResponseWriter rules said trailers in Go must
 // be predeclared, and then we reuse the same ResponseWriter.Header()
-// map to mean both Headers and Trailers.  When it's time to write the
+// map to mean both Headers and Trailers. When it's time to write the
 // Trailers, we pick out the fields of Headers that were declared as
 // trailers. That worked for a while, until we found the first major
 // user of Trailers in the wild: gRPC (using them only over http2),
@@ -4989,11 +6121,14 @@ func (w *http2responseWriter) Flush() {
 	}
 	if rws.bw.Buffered() > 0 {
 		if err := rws.bw.Flush(); err != nil {
-
+			// Ignore the error. The frame writer already knows.
 			return
 		}
 	} else {
-
+		// The bufio.Writer won't call chunkWriter.Write
+		// (writeChunk with zero bytes, so we have to do it
+		// ourselves to force the HTTP response header and/or
+		// final DATA frame (with END_STREAM) to be sent.
 		rws.writeChunk(nil)
 	}
 }
@@ -5010,7 +6145,7 @@ func (w *http2responseWriter) CloseNotify() <-chan bool {
 		rws.closeNotifierCh = ch
 		cw := rws.stream.cw
 		go func() {
-			cw.Wait()
+			cw.Wait() // wait for close
 			ch <- true
 		}()
 	}
@@ -5085,9 +6220,9 @@ func (w *http2responseWriter) write(lenData int, dataB []byte, dataS string) (n
 	if !http2bodyAllowedForStatus(rws.status) {
 		return 0, ErrBodyNotAllowed
 	}
-	rws.wroteBytes += int64(len(dataB)) + int64(len(dataS))
+	rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // only one can be set
 	if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen {
-
+		// TODO: send a RST_STREAM
 		return 0, errors.New("http2: handler wrote more than declared Content-Length")
 	}
 
@@ -5124,10 +6259,13 @@ func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
 	sc := st.sc
 	sc.serveG.checkNotOn()
 
+	// No recursive pushes: "PUSH_PROMISE frames MUST only be sent on a peer-initiated stream."
+	// http://tools.ietf.org/html/rfc7540#section-6.6
 	if st.isPushed() {
 		return http2ErrRecursivePush
 	}
 
+	// Default options.
 	if opts.Method == "" {
 		opts.Method = "GET"
 	}
@@ -5139,6 +6277,7 @@ func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
 		wantScheme = "https"
 	}
 
+	// Validate the request.
 	u, err := url.Parse(target)
 	if err != nil {
 		return err
@@ -5161,7 +6300,10 @@ func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
 		if strings.HasPrefix(k, ":") {
 			return fmt.Errorf("promised request headers cannot include pseudo header %q", k)
 		}
-
+		// These headers are meaningful only if the request has a body,
+		// but PUSH_PROMISE requests cannot have a body.
+		// http://tools.ietf.org/html/rfc7540#section-8.2
+		// Also disallow Host, since the promised URL must be absolute.
 		switch strings.ToLower(k) {
 		case "content-length", "content-encoding", "trailer", "te", "expect", "host":
 			return fmt.Errorf("promised request headers cannot include %q", k)
@@ -5171,11 +6313,14 @@ func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
 		return err
 	}
 
+	// The RFC effectively limits promised requests to GET and HEAD:
+	// "Promised requests MUST be cacheable [GET, HEAD, or POST], and MUST be safe [GET or HEAD]"
+	// http://tools.ietf.org/html/rfc7540#section-8.2
 	if opts.Method != "GET" && opts.Method != "HEAD" {
 		return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
 	}
 
-	msg := http2startPushRequest{
+	msg := &http2startPushRequest{
 		parent: st,
 		method: opts.Method,
 		url:    u,
@@ -5188,7 +6333,7 @@ func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
 		return http2errClientDisconnected
 	case <-st.cw:
 		return http2errStreamClosed
-	case sc.wantStartPushCh <- msg:
+	case sc.serveMsgCh <- msg:
 	}
 
 	select {
@@ -5210,48 +6355,66 @@ type http2startPushRequest struct {
 	done   chan error
 }
 
-func (sc *http2serverConn) startPush(msg http2startPushRequest) {
+func (sc *http2serverConn) startPush(msg *http2startPushRequest) {
 	sc.serveG.check()
 
+	// http://tools.ietf.org/html/rfc7540#section-6.6.
+	// PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
+	// is in either the "open" or "half-closed (remote)" state.
 	if msg.parent.state != http2stateOpen && msg.parent.state != http2stateHalfClosedRemote {
-
+		// responseWriter.Push checks that the stream is peer-initiaed.
 		msg.done <- http2errStreamClosed
 		return
 	}
 
+	// http://tools.ietf.org/html/rfc7540#section-6.6.
 	if !sc.pushEnabled {
 		msg.done <- ErrNotSupported
 		return
 	}
 
+	// PUSH_PROMISE frames must be sent in increasing order by stream ID, so
+	// we allocate an ID for the promised stream lazily, when the PUSH_PROMISE
+	// is written. Once the ID is allocated, we start the request handler.
 	allocatePromisedID := func() (uint32, error) {
 		sc.serveG.check()
 
+		// Check this again, just in case. Technically, we might have received
+		// an updated SETTINGS by the time we got around to writing this frame.
 		if !sc.pushEnabled {
 			return 0, ErrNotSupported
 		}
-
+		// http://tools.ietf.org/html/rfc7540#section-6.5.2.
 		if sc.curPushedStreams+1 > sc.clientMaxStreams {
 			return 0, http2ErrPushLimitReached
 		}
 
+		// http://tools.ietf.org/html/rfc7540#section-5.1.1.
+		// Streams initiated by the server MUST use even-numbered identifiers.
+		// A server that is unable to establish a new stream identifier can send a GOAWAY
+		// frame so that the client is forced to open a new connection for new streams.
 		if sc.maxPushPromiseID+2 >= 1<<31 {
-			sc.startGracefulShutdown()
+			sc.startGracefulShutdownInternal()
 			return 0, http2ErrPushLimitReached
 		}
 		sc.maxPushPromiseID += 2
 		promisedID := sc.maxPushPromiseID
 
+		// http://tools.ietf.org/html/rfc7540#section-8.2.
+		// Strictly speaking, the new stream should start in "reserved (local)", then
+		// transition to "half closed (remote)" after sending the initial HEADERS, but
+		// we start in "half closed (remote)" for simplicity.
+		// See further comments at the definition of stateHalfClosedRemote.
 		promised := sc.newStream(promisedID, msg.parent.id, http2stateHalfClosedRemote)
 		rw, req, err := sc.newWriterAndRequestNoBody(promised, http2requestParam{
 			method:    msg.method,
 			scheme:    msg.url.Scheme,
 			authority: msg.url.Host,
 			path:      msg.url.RequestURI(),
-			header:    http2cloneHeader(msg.header),
+			header:    http2cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
 		})
 		if err != nil {
-
+			// Should not happen, since we've already validated msg.url.
 			panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
 		}
 
@@ -5356,31 +6519,6 @@ var http2badTrailer = map[string]bool{
 	"Www-Authenticate":    true,
 }
 
-// h1ServerShutdownChan returns a channel that will be closed when the
-// provided *http.Server wants to shut down.
-//
-// This is a somewhat hacky way to get at http1 innards. It works
-// when the http2 code is bundled into the net/http package in the
-// standard library. The alternatives ended up making the cmd/go tool
-// depend on http Servers. This is the lightest option for now.
-// This is tested via the TestServeShutdown* tests in net/http.
-func http2h1ServerShutdownChan(hs *Server) <-chan struct{} {
-	if fn := http2testh1ServerShutdownChan; fn != nil {
-		return fn(hs)
-	}
-	var x interface{} = hs
-	type I interface {
-		getDoneChan() <-chan struct{}
-	}
-	if hs, ok := x.(I); ok {
-		return hs.getDoneChan()
-	}
-	return nil
-}
-
-// optional test hook for h1ServerShutdownChan.
-var http2testh1ServerShutdownChan func(hs *Server) <-chan struct{}
-
 // h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
 // disabled. See comments on h1ServerShutdownChan above for why
 // the code is written this way.
@@ -5486,7 +6624,7 @@ var http2errTransportVersion = errors.New("http2: ConfigureTransport is only sup
 // It requires Go 1.6 or later and returns an error if the net/http package is too old
 // or if t1 has already been HTTP/2-enabled.
 func http2ConfigureTransport(t1 *Transport) error {
-	_, err := http2configureTransport(t1)
+	_, err := http2configureTransport(t1) // in configure_transport.go (go1.6) or not_go16.go
 	return err
 }
 
@@ -5669,7 +6807,7 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
 // and returns a host:port. The port 443 is added if needed.
 func http2authorityAddr(scheme string, authority string) (addr string) {
 	host, port, err := net.SplitHostPort(authority)
-	if err != nil {
+	if err != nil { // authority didn't have a port
 		port = "443"
 		if scheme == "http" {
 			port = "80"
@@ -5679,7 +6817,7 @@ func http2authorityAddr(scheme string, authority string) (addr string) {
 	if a, err := idna.ToASCII(host); err == nil {
 		host = a
 	}
-
+	// IPv6 address literal, without a port:
 	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
 		return host + ":" + port
 	}
@@ -5742,12 +6880,14 @@ func http2shouldRetryRequest(req *Request, err error) (*Request, error) {
 	case http2errClientConnUnusable, http2errClientConnGotGoAway:
 		return req, nil
 	case http2errClientConnGotGoAwayAfterSomeReqBody:
-
+		// If the Body is nil (or http.NoBody), it's safe to reuse
+		// this request and its Body.
 		if req.Body == nil || http2reqBodyIsNoBody(req.Body) {
 			return req, nil
 		}
-
-		getBody := http2reqGetBody(req)
+		// Otherwise we depend on the Request having its GetBody
+		// func defined.
+		getBody := http2reqGetBody(req) // Go 1.8: getBody = req.GetBody
 		if getBody == nil {
 			return nil, errors.New("http2: Transport: peer server initiated graceful shutdown after some of Request.Body was written; define Request.GetBody to avoid this error")
 		}
@@ -5840,9 +6980,9 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
 		tconn:                c,
 		readerDone:           make(chan struct{}),
 		nextStreamID:         1,
-		maxFrameSize:         16 << 10,
-		initialWindowSize:    65535,
-		maxConcurrentStreams: 1000,
+		maxFrameSize:         16 << 10, // spec default
+		initialWindowSize:    65535,    // spec default
+		maxConcurrentStreams: 1000,     // "infinite", per spec. 1000 seems good enough.
 		streams:              make(map[uint32]*http2clientStream),
 		singleUse:            singleUse,
 		wantSettingsAck:      true,
@@ -5859,12 +6999,16 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
 	cc.cond = sync.NewCond(&cc.mu)
 	cc.flow.add(int32(http2initialWindowSize))
 
+	// TODO: adjust this writer size to account for frame size +
+	// MTU + crypto/tls record padding.
 	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()
 
+	// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
+	// henc in response to SETTINGS frames?
 	cc.henc = hpack.NewEncoder(&cc.hbuf)
 
 	if cs, ok := c.(http2connectionStater); ok {
@@ -5900,6 +7044,7 @@ func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
 	old := cc.goAway
 	cc.goAway = f
 
+	// Merge the previous and current GoAway error frames.
 	if cc.goAwayDebug == "" {
 		cc.goAwayDebug = string(f.DebugData())
 	}
@@ -5932,7 +7077,7 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
 		cc.nextStreamID < math.MaxInt32
 }
 
-// onIdleTimeout is called from a time.AfterFunc goroutine.  It will
+// onIdleTimeout is called from a time.AfterFunc goroutine. It will
 // only be called when we're idle, but because we're coming from a new
 // goroutine, there could be a new request coming in at the same time,
 // so this simply calls the synchronized closeIfIdle to shut down this
@@ -5950,7 +7095,7 @@ func (cc *http2ClientConn) closeIfIdle() {
 	}
 	cc.closed = true
 	nextID := cc.nextStreamID
-
+	// TODO: do clients send GOAWAY too? maybe? Just Close:
 	cc.mu.Unlock()
 
 	if http2VerboseLogs {
@@ -5996,7 +7141,7 @@ func (cc *http2ClientConn) putFrameScratchBuffer(buf []byte) {
 			return
 		}
 	}
-
+	// forget about it.
 }
 
 // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
@@ -6024,7 +7169,10 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
 	if cc.t.t1 != nil {
 		return cc.t.t1.ResponseHeaderTimeout
 	}
-
+	// No way to do this (yet?) with just an http2.Transport. Probably
+	// no need. Request.Cancel this is the new way. We only need to support
+	// this for compatibility with the old http.Transport fields when
+	// we're doing transparent http2.
 	return 0
 }
 
@@ -6088,10 +7236,24 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 		req.Header.Get("Accept-Encoding") == "" &&
 		req.Header.Get("Range") == "" &&
 		req.Method != "HEAD" {
-
+		// Request gzip only, not deflate. Deflate is ambiguous and
+		// not as universally supported anyway.
+		// See: http://www.gzip.org/zlib/zlib_faq.html#faq38
+		//
+		// Note that we don't request this for HEAD requests,
+		// due to a bug in nginx:
+		//   http://trac.nginx.org/nginx/ticket/358
+		//   https://golang.org/issue/5522
+		//
+		// We don't request gzip if the request is for a range, since
+		// auto-decoding a portion of a gzipped document will just fail
+		// anyway. See https://golang.org/issue/8923
 		requestedGzip = true
 	}
 
+	// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
+	// sent by writeRequestBody below, along with any Trailers,
+	// again in form HEADERS{1}, CONTINUATION{0,})
 	hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
 	if err != nil {
 		cc.mu.Unlock()
@@ -6114,11 +7276,12 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 
 	if werr != nil {
 		if hasBody {
-			req.Body.Close()
+			req.Body.Close() // per RoundTripper contract
 			bodyWriter.cancel()
 		}
 		cc.forgetStreamID(cs.ID)
-
+		// Don't bother sending a RST_STREAM (our write already failed;
+		// no need to keep writing)
 		http2traceWroteRequest(cs.trace, werr)
 		return nil, werr
 	}
@@ -6142,7 +7305,15 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 	handleReadLoopResponse := func(re http2resAndError) (*Response, error) {
 		res := re.res
 		if re.err != nil || res.StatusCode > 299 {
-
+			// On error or status code 3xx, 4xx, 5xx, etc abort any
+			// ongoing write, assuming that the server doesn't care
+			// about our request body. If the server replied with 1xx or
+			// 2xx, however, then assume the server DOES potentially
+			// want our body (e.g. full-duplex streaming:
+			// golang.org/issue/13444). If it turns out the server
+			// doesn't, they'll RST_STREAM us soon enough. This is a
+			// heuristic to avoid adding knobs to Transport. Hopefully
+			// we can keep it.
 			bodyWriter.cancel()
 			cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
 		}
@@ -6194,10 +7365,12 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 			}
 			return nil, http2errRequestCanceled
 		case <-cs.peerReset:
-
+			// processResetStream already removed the
+			// stream from the streams map; no need for
+			// forgetStreamID.
 			return nil, cs.resetErr
 		case err := <-bodyWriter.resc:
-
+			// Prefer the read loop's response, if available. Issue 16102.
 			select {
 			case re := <-readLoopResCh:
 				return handleReadLoopResponse(re)
@@ -6218,7 +7391,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 
 // requires cc.wmu be held
 func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error {
-	first := true
+	first := true // first frame written (HEADERS is first, then CONTINUATION)
 	frameSize := int(cc.maxFrameSize)
 	for len(hdrs) > 0 && cc.werr == nil {
 		chunk := hdrs
@@ -6239,7 +7412,10 @@ func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []
 			cc.fr.WriteContinuation(streamID, endHeaders, chunk)
 		}
 	}
-
+	// TODO(bradfitz): this Flush could potentially block (as
+	// could the WriteHeaders call(s) above), which means they
+	// wouldn't respond to Request.Cancel being readable. That's
+	// rare, but this should probably be in a goroutine.
 	cc.bw.Flush()
 	return cc.werr
 }
@@ -6255,13 +7431,16 @@ var (
 
 func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) {
 	cc := cs.cc
-	sentEnd := false
+	sentEnd := false // whether we sent the final DATA frame w/ END_STREAM
 	buf := cc.frameScratchBuffer()
 	defer cc.putFrameScratchBuffer(buf)
 
 	defer func() {
 		http2traceWroteRequest(cs.trace, err)
-
+		// TODO: write h12Compare test showing whether
+		// Request.Body is closed by the Transport,
+		// and in multiple cases: server replies <=299 and >299
+		// while still writing request body
 		cerr := bodyCloser.Close()
 		if err == nil {
 			err = cerr
@@ -6300,7 +7479,12 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
 			sentEnd = sawEOF && len(remain) == 0 && !hasTrailers
 			err = cc.fr.WriteData(cs.ID, sentEnd, data)
 			if err == nil {
-
+				// TODO(bradfitz): this flush is for latency, not bandwidth.
+				// Most requests won't need this. Make this opt-in or
+				// opt-out?  Use some heuristic on the body type? Nagel-like
+				// timers?  Based on 'n'? Only last chunk of this for loop,
+				// unless flow control tokens are low? For now, always.
+				// If we change this, see comment below.
 				err = cc.bw.Flush()
 			}
 			cc.wmu.Unlock()
@@ -6311,7 +7495,9 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
 	}
 
 	if sentEnd {
-
+		// Already sent END_STREAM (which implies we have no
+		// trailers) and flushed, because currently all
+		// WriteData frames above get a flush. So we're done.
 		return nil
 	}
 
@@ -6325,6 +7511,8 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
 	cc.wmu.Lock()
 	defer cc.wmu.Unlock()
 
+	// Two ways to send END_STREAM: either with trailers, or
+	// with an empty DATA frame.
 	if len(trls) > 0 {
 		err = cc.writeHeaders(cs.ID, true, trls)
 	} else {
@@ -6358,7 +7546,7 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er
 			take := a
 			if int(take) > maxBytes {
 
-				take = int32(maxBytes)
+				take = int32(maxBytes) // can't truncate int; take is int32
 			}
 			if take > int32(cc.maxFrameSize) {
 				take = int32(cc.maxFrameSize)
@@ -6406,6 +7594,9 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 		}
 	}
 
+	// Check for any invalid headers and return an error before we
+	// potentially pollute our hpack state. (We want to be able to
+	// continue to reuse the hpack encoder for future requests)
 	for k, vv := range req.Header {
 		if !httplex.ValidHeaderFieldName(k) {
 			return nil, fmt.Errorf("invalid HTTP header name %q", k)
@@ -6417,6 +7608,11 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 		}
 	}
 
+	// 8.1.2.3 Request Pseudo-Header Fields
+	// The :path pseudo-header field includes the path and query parts of the
+	// target URI (the path-absolute production and optionally a '?' character
+	// followed by the query production (see Sections 3.3 and 3.4 of
+	// [RFC3986]).
 	cc.writeHeader(":authority", host)
 	cc.writeHeader(":method", req.Method)
 	if req.Method != "CONNECT" {
@@ -6432,13 +7628,20 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 		lowKey := strings.ToLower(k)
 		switch lowKey {
 		case "host", "content-length":
-
+			// Host is :authority, already sent.
+			// Content-Length is automatic, set below.
 			continue
 		case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive":
-
+			// Per 8.1.2.2 Connection-Specific Header
+			// Fields, don't send connection-specific
+			// fields. We have already checked if any
+			// are error-worthy so just ignore the rest.
 			continue
 		case "user-agent":
-
+			// Match Go's http1 behavior: at most one
+			// User-Agent. If set to nil or empty string,
+			// then omit it. Otherwise if not mentioned,
+			// include the default (below).
 			didUA = true
 			if len(vv) < 1 {
 				continue
@@ -6476,7 +7679,8 @@ func http2shouldSendReqContentLength(method string, contentLength int64) bool {
 	if contentLength < 0 {
 		return false
 	}
-
+	// For zero bodies, whether we send a content-length depends on the method.
+	// It also kinda doesn't matter for http2 either way, with END_STREAM.
 	switch method {
 	case "POST", "PUT", "PATCH":
 		return true
@@ -6489,7 +7693,8 @@ func http2shouldSendReqContentLength(method string, contentLength int64) bool {
 func (cc *http2ClientConn) encodeTrailers(req *Request) []byte {
 	cc.hbuf.Reset()
 	for k, vv := range req.Trailer {
-
+		// Transfer-Encoding, etc.. have already been filter at the
+		// start of RoundTrip
 		lowKey := strings.ToLower(k)
 		for _, v := range vv {
 			cc.writeHeader(lowKey, v)
@@ -6543,7 +7748,7 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
 			cc.idleTimer.Reset(cc.idleTimeout)
 		}
 		close(cs.done)
-		cc.cond.Broadcast()
+		cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
 	}
 	return cs
 }
@@ -6602,6 +7807,9 @@ func (rl *http2clientConnReadLoop) cleanup() {
 		cc.idleTimer.Stop()
 	}
 
+	// Close any response bodies if the server closes prematurely.
+	// TODO: also do this if we've written the headers but not
+	// gotten a response yet.
 	err := cc.readerErr
 	cc.mu.Lock()
 	if cc.goAway != nil && http2isEOFOrNetReadError(err) {
@@ -6631,7 +7839,7 @@ func (rl *http2clientConnReadLoop) cleanup() {
 func (rl *http2clientConnReadLoop) run() error {
 	cc := rl.cc
 	rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
-	gotReply := false
+	gotReply := false // ever saw a HEADERS reply
 	gotSettings := false
 	for {
 		f, err := cc.fr.ReadFrame()
@@ -6639,7 +7847,7 @@ func (rl *http2clientConnReadLoop) run() error {
 			cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
 		}
 		if se, ok := err.(http2StreamError); ok {
-			if cs := cc.streamByID(se.StreamID, true); cs != nil {
+			if cs := cc.streamByID(se.StreamID, true /*ended; remove it*/); cs != nil {
 				cs.cc.writeStreamReset(cs.ID, se.Code, err)
 				if se.Cause == nil {
 					se.Cause = cc.fr.errDetail
@@ -6660,7 +7868,7 @@ func (rl *http2clientConnReadLoop) run() error {
 			}
 			gotSettings = true
 		}
-		maybeIdle := false
+		maybeIdle := false // whether frame might transition us to idle
 
 		switch f := f.(type) {
 		case *http2MetaHeadersFrame:
@@ -6703,12 +7911,17 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
 	cc := rl.cc
 	cs := cc.streamByID(f.StreamID, f.StreamEnded())
 	if cs == nil {
-
+		// We'd get here if we canceled a request while the
+		// server had its response still in flight. So if this
+		// was just something we canceled, ignore it.
 		return nil
 	}
 	if !cs.firstByte {
 		if cs.trace != nil {
-
+			// TODO(bradfitz): move first response byte earlier,
+			// when we first read the 9 byte header, not waiting
+			// until all the HEADERS+CONTINUATION frames have been
+			// merged. This works for now.
 			http2traceFirstResponseByte(cs.trace)
 		}
 		cs.firstByte = true
@@ -6724,13 +7937,13 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
 		if _, ok := err.(http2ConnectionError); ok {
 			return err
 		}
-
+		// Any other error type is a stream error.
 		cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err)
 		cs.resc <- http2resAndError{err: err}
-		return nil
+		return nil // return nil from process* funcs to keep conn alive
 	}
 	if res == nil {
-
+		// (nil, nil) special case. See handleResponse docs.
 		return nil
 	}
 	if res.Body != http2noBody {
@@ -6765,9 +7978,9 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
 	if statusCode == 100 {
 		http2traceGot100Continue(cs.trace)
 		if cs.on100 != nil {
-			cs.on100()
+			cs.on100() // forces any write delay timer to fire
 		}
-		cs.pastHeaders = false
+		cs.pastHeaders = false // do it all again
 		return nil, nil
 	}
 
@@ -6803,10 +8016,12 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
 			if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
 				res.ContentLength = clen64
 			} else {
-
+				// TODO: care? unlike http/1, it won't mess up our framing, so it's
+				// more safe smuggling-wise to ignore.
 			}
 		} else if len(clens) > 1 {
-
+			// TODO: care? unlike http/1, it won't mess up our framing, so it's
+			// more safe smuggling-wise to ignore.
 		}
 	}
 
@@ -6815,8 +8030,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
 		return res, nil
 	}
 
-	buf := new(bytes.Buffer)
-	cs.bufPipe = http2pipe{b: buf}
+	cs.bufPipe = http2pipe{b: &http2dataBuffer{expected: res.ContentLength}}
 	cs.bytesRemain = res.ContentLength
 	res.Body = http2transportResponseBody{cs}
 	go cs.awaitRequestCancel(cs.req)
@@ -6833,16 +8047,18 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
 
 func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *http2MetaHeadersFrame) error {
 	if cs.pastTrailers {
-
+		// Too many HEADERS frames for this stream.
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 	cs.pastTrailers = true
 	if !f.StreamEnded() {
-
+		// We expect that any headers for trailers also
+		// has END_STREAM.
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 	if len(f.PseudoFields()) > 0 {
-
+		// No pseudo header fields are defined for trailers.
+		// TODO: ConnectionError might be overly harsh? Check.
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
 
@@ -6890,7 +8106,7 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
 		}
 	}
 	if n == 0 {
-
+		// No flow control tokens to send back.
 		return
 	}
 
@@ -6898,13 +8114,15 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
 	defer cc.mu.Unlock()
 
 	var connAdd, streamAdd int32
-
+	// Check the conn-level first, before the stream-level.
 	if v := cc.inflow.available(); v < http2transportDefaultConnFlow/2 {
 		connAdd = http2transportDefaultConnFlow - v
 		cc.inflow.add(connAdd)
 	}
-	if err == nil {
-
+	if err == nil { // No need to refresh if the stream is over or failed.
+		// Consider any buffered body data (read from the conn but not
+		// consumed by the client) when computing flow control for this
+		// stream.
 		v := int(cs.inflow.available()) + cs.bufPipe.Len()
 		if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
 			streamAdd = int32(http2transportDefaultStreamFlow - v)
@@ -6939,8 +8157,9 @@ func (b http2transportResponseBody) Close() error {
 		cc.wmu.Lock()
 		if !serverSentStreamEnd {
 			cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel)
+			cs.didReset = true
 		}
-
+		// Return connection-level flow control.
 		if unread > 0 {
 			cc.inflow.add(int32(unread))
 			cc.fr.WriteWindowUpdate(0, uint32(unread))
@@ -6963,11 +8182,16 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 		neverSent := cc.nextStreamID
 		cc.mu.Unlock()
 		if f.StreamID >= neverSent {
-
+			// We never asked for this.
 			cc.logf("http2: Transport received unsolicited DATA frame; closing connection")
 			return http2ConnectionError(http2ErrCodeProtocol)
 		}
+		// We probably did ask for this, but canceled. Just ignore it.
+		// TODO: be stricter here? only silently ignore things which
+		// we canceled, but not things which were closed normally
+		// by the peer? Tough without accumulating too much state.
 
+		// But at least return their flow control:
 		if f.Length > 0 {
 			cc.mu.Lock()
 			cc.inflow.add(int32(f.Length))
@@ -6981,12 +8205,7 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 		return nil
 	}
 	if f.Length > 0 {
-		if len(data) > 0 && cs.bufPipe.b == nil {
-
-			cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
-			return http2ConnectionError(http2ErrCodeProtocol)
-		}
-
+		// Check connection-level flow control.
 		cc.mu.Lock()
 		if cs.inflow.available() >= int32(f.Length) {
 			cs.inflow.take(int32(f.Length))
@@ -6994,7 +8213,8 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 			cc.mu.Unlock()
 			return http2ConnectionError(http2ErrCodeFlowControl)
 		}
-
+		// Return any padded flow control now, since we won't
+		// refund it later on body reads.
 		if pad := int32(f.Length) - int32(len(data)); pad > 0 {
 			cs.inflow.add(pad)
 			cc.inflow.add(pad)
@@ -7024,7 +8244,8 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 var http2errInvalidTrailers = errors.New("http2: invalid trailers")
 
 func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
-
+	// TODO: check that any declared content-length matches, like
+	// server.go's (*stream).endStream method.
 	rl.endStreamError(cs, nil)
 }
 
@@ -7060,7 +8281,7 @@ func (rl *http2clientConnReadLoop) processGoAway(f *http2GoAwayFrame) error {
 	cc := rl.cc
 	cc.t.connPool().MarkDead(cc)
 	if f.ErrCode != 0 {
-
+		// TODO: deal with GOAWAY more. particularly the error code
 		cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
 	}
 	cc.setGoAway(f)
@@ -7087,11 +8308,17 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
 		case http2SettingMaxConcurrentStreams:
 			cc.maxConcurrentStreams = s.Val
 		case http2SettingInitialWindowSize:
-
+			// Values above the maximum flow-control
+			// window size of 2^31-1 MUST be treated as a
+			// connection error (Section 5.4.1) of type
+			// FLOW_CONTROL_ERROR.
 			if s.Val > math.MaxInt32 {
 				return http2ConnectionError(http2ErrCodeFlowControl)
 			}
 
+			// Adjust flow control of currently-open
+			// frames by the difference of the old initial
+			// window size and this one.
 			delta := int32(s.Val) - int32(cc.initialWindowSize)
 			for _, cs := range cc.streams {
 				cs.flow.add(delta)
@@ -7100,7 +8327,7 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
 
 			cc.initialWindowSize = s.Val
 		default:
-
+			// TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably.
 			cc.vlogf("Unhandled Setting: %v", s)
 		}
 		return nil
@@ -7141,18 +8368,21 @@ func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame
 func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) error {
 	cs := rl.cc.streamByID(f.StreamID, true)
 	if cs == nil {
-
+		// TODO: return error if server tries to RST_STEAM an idle stream
 		return nil
 	}
 	select {
 	case <-cs.peerReset:
-
+		// Already reset.
+		// This is the only goroutine
+		// which closes this, so there
+		// isn't a race.
 	default:
 		err := http2streamError(cs.ID, f.ErrCode)
 		cs.resetErr = err
 		close(cs.peerReset)
 		cs.bufPipe.CloseWithError(err)
-		cs.cc.cond.Broadcast()
+		cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
 	}
 	delete(rl.activeRes, cs.ID)
 	return nil
@@ -7169,7 +8399,7 @@ func (cc *http2ClientConn) ping(ctx http2contextContext) error {
 			return err
 		}
 		cc.mu.Lock()
-
+		// check for dup before insert
 		if _, found := cc.pings[p]; !found {
 			cc.pings[p] = c
 			cc.mu.Unlock()
@@ -7193,7 +8423,7 @@ func (cc *http2ClientConn) ping(ctx http2contextContext) error {
 	case <-ctx.Done():
 		return ctx.Err()
 	case <-cc.readerDone:
-
+		// connection closed
 		return cc.readerErr
 	}
 }
@@ -7203,7 +8433,7 @@ func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
 		cc := rl.cc
 		cc.mu.Lock()
 		defer cc.mu.Unlock()
-
+		// If ack, notify listener if any
 		if c, ok := cc.pings[f.Data]; ok {
 			close(c)
 			delete(cc.pings, f.Data)
@@ -7220,12 +8450,21 @@ func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
 }
 
 func (rl *http2clientConnReadLoop) processPushPromise(f *http2PushPromiseFrame) error {
-
+	// We told the peer we don't want them.
+	// Spec says:
+	// "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH
+	// setting of the peer endpoint is set to 0. An endpoint that
+	// has set this setting and has received acknowledgement MUST
+	// treat the receipt of a PUSH_PROMISE frame as a connection
+	// error (Section 5.4.1) of type PROTOCOL_ERROR."
 	return http2ConnectionError(http2ErrCodeProtocol)
 }
 
 func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, err error) {
-
+	// TODO: map err to more interesting error codes, once the
+	// HTTP community comes up with some. But currently for
+	// RST_STREAM there's no equivalent to GOAWAY frame's debug
+	// data, and the error codes are all pretty vague ("cancel").
 	cc.wmu.Lock()
 	cc.fr.WriteRSTStream(streamID, code)
 	cc.bw.Flush()
@@ -7354,7 +8593,8 @@ func (s http2bodyWriterState) cancel() {
 
 func (s http2bodyWriterState) on100() {
 	if s.timer == nil {
-
+		// If we didn't do a delayed write, ignore the server's
+		// bogus 100 continue response.
 		return
 	}
 	s.timer.Stop()
@@ -7366,7 +8606,9 @@ func (s http2bodyWriterState) on100() {
 // called until after the headers have been written.
 func (s http2bodyWriterState) scheduleBodyWrite() {
 	if s.timer == nil {
-
+		// We're not doing a delayed write (see
+		// getBodyWriterState), so just start the writing
+		// goroutine immediately.
 		go s.fn()
 		return
 	}
@@ -7421,7 +8663,9 @@ func http2writeEndsStream(w http2writeFramer) bool {
 	case *http2writeResHeaders:
 		return v.endStream
 	case nil:
-
+		// This can only happen if the caller reuses w after it's
+		// been intentionally nil'ed out to prevent use. Keep this
+		// here to catch future refactoring breaking it.
 		panic("writeEndsStream called on nil writeFramer")
 	}
 	return false
@@ -7455,14 +8699,14 @@ type http2writeGoAway struct {
 func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error {
 	err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
 	if p.code != 0 {
-		ctx.Flush()
+		ctx.Flush() // ignore error: we're hanging up on them anyway
 		time.Sleep(50 * time.Millisecond)
 		ctx.CloseConn()
 	}
 	return err
 }
 
-func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false }
+func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes
 
 type http2writeData struct {
 	streamID  uint32
@@ -7567,7 +8811,13 @@ func http2encKV(enc *hpack.Encoder, k, v string) {
 }
 
 func (w *http2writeResHeaders) staysWithinBuffer(max int) bool {
-
+	// TODO: this is a common one. It'd be nice to return true
+	// here and get into the fast path if we could be clever and
+	// calculate the size fast enough, or at least a conservative
+	// uppper bound that usually fires. (Maybe if w.h and
+	// w.trailers are nil, so we don't need to enumerate it.)
+	// Otherwise I'm afraid that just calculating the length to
+	// answer this question would be slower than the ~2µs benefit.
 	return false
 }
 
@@ -7626,7 +8876,7 @@ type http2writePushPromise struct {
 }
 
 func (w *http2writePushPromise) staysWithinBuffer(max int) bool {
-
+	// TODO: see writeResHeaders.staysWithinBuffer
 	return false
 }
 
@@ -7678,7 +8928,7 @@ func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) err
 }
 
 func (w http2write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
-
+	// Sloppy but conservative:
 	return 9+2*(len(":status")+len("100")) <= max
 }
 
@@ -7698,7 +8948,9 @@ func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
 func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
 	if keys == nil {
 		sorter := http2sorterPool.Get().(*http2sorter)
-
+		// Using defer here, since the returned keys from the
+		// sorter.Keys method is only valid until the sorter
+		// is returned:
 		defer http2sorterPool.Put(sorter)
 		keys = sorter.Keys(h)
 	}
@@ -7706,16 +8958,19 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
 		vv := h[k]
 		k = http2lowerHeader(k)
 		if !http2validWireHeaderFieldName(k) {
-
+			// Skip it as backup paranoia. Per
+			// golang.org/issue/14048, these should
+			// already be rejected at a higher level.
 			continue
 		}
 		isTE := k == "transfer-encoding"
 		for _, v := range vv {
 			if !httplex.ValidHeaderFieldValue(v) {
-
+				// TODO: return an error? golang.org/issue/14048
+				// For now just omit it.
 				continue
 			}
-
+			// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
 			if isTE && v != "trailers" {
 				continue
 			}
@@ -7783,7 +9038,10 @@ type http2FrameWriteRequest struct {
 func (wr http2FrameWriteRequest) StreamID() uint32 {
 	if wr.stream == nil {
 		if se, ok := wr.write.(http2StreamError); ok {
-
+			// (*serverConn).resetStream doesn't set
+			// stream because it doesn't necessarily have
+			// one. So special case this type of write
+			// message.
 			return se.StreamID
 		}
 		return 0
@@ -7813,11 +9071,13 @@ func (wr http2FrameWriteRequest) DataSize() int {
 func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) {
 	var empty http2FrameWriteRequest
 
+	// Non-DATA frames are always consumed whole.
 	wd, ok := wr.write.(*http2writeData)
 	if !ok || len(wd.p) == 0 {
 		return wr, empty, 1
 	}
 
+	// Might need to split after applying limits.
 	allowed := wr.stream.flow.available()
 	if n < allowed {
 		allowed = n
@@ -7835,10 +9095,13 @@ func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2
 			write: &http2writeData{
 				streamID: wd.streamID,
 				p:        wd.p[:allowed],
-
+				// Even if the original had endStream set, there
+				// are bytes remaining because len(wd.p) > allowed,
+				// so we know endStream is false.
 				endStream: false,
 			},
-
+			// Our caller is blocking on the final DATA frame, not
+			// this intermediate frame, so no need to wait.
 			done: nil,
 		}
 		rest := http2FrameWriteRequest{
@@ -7853,6 +9116,8 @@ func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2
 		return consumed, rest, 2
 	}
 
+	// The frame is consumed whole.
+	// NB: This cast cannot overflow because allowed is <= math.MaxInt32.
 	wr.stream.flow.take(int32(len(wd.p)))
 	return wr, empty, 1
 }
@@ -7879,7 +9144,7 @@ func (wr *http2FrameWriteRequest) replyToWriter(err error) {
 	default:
 		panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
 	}
-	wr.write = nil
+	wr.write = nil // prevent use (assume it's tainted after wr.done send)
 }
 
 // writeQueue is used by implementations of WriteScheduler.
@@ -7898,7 +9163,7 @@ func (q *http2writeQueue) shift() http2FrameWriteRequest {
 		panic("invalid use of queue")
 	}
 	wr := q.s[0]
-
+	// TODO: less copy-happy queue.
 	copy(q.s, q.s[1:])
 	q.s[len(q.s)-1] = http2FrameWriteRequest{}
 	q.s = q.s[:len(q.s)-1]
@@ -7928,6 +9193,8 @@ func (q *http2writeQueue) consume(n int32) (http2FrameWriteRequest, bool) {
 type http2writeQueuePool []*http2writeQueue
 
 // put inserts an unused writeQueue into the pool.
+
+// put inserts an unused writeQueue into the pool.
 func (p *http2writeQueuePool) put(q *http2writeQueue) {
 	for i := range q.s {
 		q.s[i] = http2FrameWriteRequest{}
@@ -7992,11 +9259,12 @@ type http2PriorityWriteSchedulerConfig struct {
 }
 
 // NewPriorityWriteScheduler constructs a WriteScheduler that schedules
-// frames by following HTTP/2 priorities as described in RFC 7340 Section 5.3.
+// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
 // If cfg is nil, default options are used.
 func http2NewPriorityWriteScheduler(cfg *http2PriorityWriteSchedulerConfig) http2WriteScheduler {
 	if cfg == nil {
-
+		// For justification of these defaults, see:
+		// https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
 		cfg = &http2PriorityWriteSchedulerConfig{
 			MaxClosedNodesInTree:     10,
 			MaxIdleNodesInTree:       10,
@@ -8051,7 +9319,7 @@ func (n *http2priorityNode) setParent(parent *http2priorityNode) {
 	if n.parent == parent {
 		return
 	}
-
+	// Unlink from current parent.
 	if parent := n.parent; parent != nil {
 		if n.prev == nil {
 			parent.kids = n.next
@@ -8062,7 +9330,9 @@ func (n *http2priorityNode) setParent(parent *http2priorityNode) {
 			n.next.prev = n.prev
 		}
 	}
-
+	// Link to new parent.
+	// If parent=nil, remove n from the tree.
+	// Always insert at the head of parent.kids (this is assumed by walkReadyInOrder).
 	n.parent = parent
 	if parent == nil {
 		n.next = nil
@@ -8098,10 +9368,15 @@ func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2prior
 		return false
 	}
 
+	// Don't consider the root "open" when updating openParent since
+	// we can't send data frames on the root stream (only control frames).
 	if n.id != 0 {
 		openParent = openParent || (n.state == http2priorityNodeOpen)
 	}
 
+	// Common case: only one kid or all kids have the same weight.
+	// Some clients don't use weights; other clients (like web browsers)
+	// use mostly-linear priority trees.
 	w := n.kids.weight
 	needSort := false
 	for k := n.kids.next; k != nil; k = k.next {
@@ -8119,6 +9394,8 @@ func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2prior
 		return false
 	}
 
+	// Uncommon case: sort the child nodes. We remove the kids from the parent,
+	// then re-insert after sorting so we can reuse tmp for future sort calls.
 	*tmp = (*tmp)[:0]
 	for n.kids != nil {
 		*tmp = append(*tmp, n.kids)
@@ -8126,7 +9403,7 @@ func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2prior
 	}
 	sort.Sort(http2sortPriorityNodeSiblings(*tmp))
 	for i := len(*tmp) - 1; i >= 0; i-- {
-		(*tmp)[i].setParent(n)
+		(*tmp)[i].setParent(n) // setParent inserts at the head of n.kids
 	}
 	for k := n.kids; k != nil; k = k.next {
 		if k.walkReadyInOrder(openParent, tmp, f) {
@@ -8143,7 +9420,8 @@ func (z http2sortPriorityNodeSiblings) Len() int { return len(z) }
 func (z http2sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] }
 
 func (z http2sortPriorityNodeSiblings) Less(i, k int) bool {
-
+	// Prefer the subtree that has sent fewer bytes relative to its weight.
+	// See sections 5.3.2 and 5.3.4.
 	wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
 	wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
 	if bi == 0 && bk == 0 {
@@ -8185,7 +9463,7 @@ type http2priorityWriteScheduler struct {
 }
 
 func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
-
+	// The stream may be currently idle but cannot be opened or closed.
 	if curr := ws.nodes[streamID]; curr != nil {
 		if curr.state != http2priorityNodeIdle {
 			panic(fmt.Sprintf("stream %d already opened", streamID))
@@ -8194,6 +9472,10 @@ func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2
 		return
 	}
 
+	// RFC 7540, Section 5.3.5:
+	//  "All streams are initially assigned a non-exclusive dependency on stream 0x0.
+	//  Pushed streams initially depend on their associated stream. In both cases,
+	//  streams are assigned a default weight of 16."
 	parent := ws.nodes[options.PusherID]
 	if parent == nil {
 		parent = &ws.root
@@ -8241,6 +9523,9 @@ func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority ht
 		panic("adjustPriority on root")
 	}
 
+	// If streamID does not exist, there are two cases:
+	// - A closed stream that has been removed (this will have ID <= maxID)
+	// - An idle stream that is being used for "grouping" (this will have ID > maxID)
 	n := ws.nodes[streamID]
 	if n == nil {
 		if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
@@ -8258,6 +9543,8 @@ func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority ht
 		ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
 	}
 
+	// Section 5.3.1: A dependency on a stream that is not currently in the tree
+	// results in that stream being given a default priority (Section 5.3.5).
 	parent := ws.nodes[priority.StreamDep]
 	if parent == nil {
 		n.setParent(&ws.root)
@@ -8265,10 +9552,18 @@ func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority ht
 		return
 	}
 
+	// Ignore if the client tries to make a node its own parent.
 	if n == parent {
 		return
 	}
 
+	// Section 5.3.3:
+	//   "If a stream is made dependent on one of its own dependencies, the
+	//   formerly dependent stream is first moved to be dependent on the
+	//   reprioritized stream's previous parent. The moved dependency retains
+	//   its weight."
+	//
+	// That is: if parent depends on n, move parent to depend on n.parent.
 	for x := parent.parent; x != nil; x = x.parent {
 		if x == n {
 			parent.setParent(n.parent)
@@ -8276,6 +9571,9 @@ func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority ht
 		}
 	}
 
+	// Section 5.3.3: The exclusive flag causes the stream to become the sole
+	// dependency of its parent stream, causing other dependencies to become
+	// dependent on the exclusive stream.
 	if priority.Exclusive {
 		k := parent.kids
 		for k != nil {
@@ -8298,7 +9596,11 @@ func (ws *http2priorityWriteScheduler) Push(wr http2FrameWriteRequest) {
 	} else {
 		n = ws.nodes[id]
 		if n == nil {
-
+			// id is an idle or closed stream. wr should not be a HEADERS or
+			// DATA frame. However, wr can be a RST_STREAM. In this case, we
+			// push wr onto the root, rather than creating a new priorityNode,
+			// since RST_STREAM is tiny and the stream's priority is unknown
+			// anyway. See issue #17919.
 			if wr.DataSize() > 0 {
 				panic("add DATA on non-open stream")
 			}
@@ -8319,7 +9621,9 @@ func (ws *http2priorityWriteScheduler) Pop() (wr http2FrameWriteRequest, ok bool
 			return false
 		}
 		n.addBytes(int64(wr.DataSize()))
-
+		// If B depends on A and B continuously has data available but A
+		// does not, gradually increase the throttling limit to allow B to
+		// steal more and more bandwidth from A.
 		if openParent {
 			ws.writeThrottleLimit += 1024
 			if ws.writeThrottleLimit < 0 {
@@ -8338,7 +9642,7 @@ func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorit
 		return
 	}
 	if len(*list) == maxSize {
-
+		// Remove the oldest node, then shift left.
 		ws.removeNode((*list)[0])
 		x := (*list)[1:]
 		copy(*list, x)
@@ -8376,7 +9680,7 @@ type http2randomWriteScheduler struct {
 }
 
 func (ws *http2randomWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
-
+	// no-op: idle streams are not tracked
 }
 
 func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) {
@@ -8389,7 +9693,7 @@ func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) {
 }
 
 func (ws *http2randomWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
-
+	// no-op: priorities are ignored
 }
 
 func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) {
@@ -8407,11 +9711,11 @@ func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) {
 }
 
 func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) {
-
+	// Control frames first.
 	if !ws.zero.empty() {
 		return ws.zero.shift(), true
 	}
-
+	// Iterate over all non-idle streams until finding one that can be consumed.
 	for _, q := range ws.sq {
 		if wr, ok := q.consume(math.MaxInt32); ok {
 			return wr, true
diff --git a/src/net/http/httptest/example_test.go b/src/net/http/httptest/example_test.go
index bd2c496..e3d3921 100644
--- a/src/net/http/httptest/example_test.go
+++ b/src/net/http/httptest/example_test.go
@@ -54,3 +54,25 @@ func ExampleServer() {
 	fmt.Printf("%s", greeting)
 	// Output: Hello, client
 }
+
+func ExampleNewTLSServer() {
+	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprintln(w, "Hello, client")
+	}))
+	defer ts.Close()
+
+	client := ts.Client()
+	res, err := client.Get(ts.URL)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	greeting, err := ioutil.ReadAll(res.Body)
+	res.Body.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Printf("%s", greeting)
+	// Output: Hello, client
+}
diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go
index 5f1aa6a..741f076 100644
--- a/src/net/http/httptest/recorder.go
+++ b/src/net/http/httptest/recorder.go
@@ -6,6 +6,7 @@ package httptest
 
 import (
 	"bytes"
+	"fmt"
 	"io/ioutil"
 	"net/http"
 	"strconv"
@@ -176,7 +177,7 @@ func (rw *ResponseRecorder) Result() *http.Response {
 	if res.StatusCode == 0 {
 		res.StatusCode = 200
 	}
-	res.Status = http.StatusText(res.StatusCode)
+	res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
 	if rw.Body != nil {
 		res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes()))
 	}
diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go
index 9afba4e..a6259eb 100644
--- a/src/net/http/httptest/recorder_test.go
+++ b/src/net/http/httptest/recorder_test.go
@@ -23,7 +23,15 @@ func TestRecorder(t *testing.T) {
 			return nil
 		}
 	}
-	hasResultStatus := func(wantCode int) checkFunc {
+	hasResultStatus := func(want string) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			if rec.Result().Status != want {
+				return fmt.Errorf("Result().Status = %q; want %q", rec.Result().Status, want)
+			}
+			return nil
+		}
+	}
+	hasResultStatusCode := 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)
@@ -235,7 +243,8 @@ func TestRecorder(t *testing.T) {
 				hasOldHeader("X-Foo", "1"),
 				hasStatus(0),
 				hasHeader("X-Foo", "1"),
-				hasResultStatus(200),
+				hasResultStatus("200 OK"),
+				hasResultStatusCode(200),
 			),
 		},
 		{
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index 7118214..549ef04 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -9,6 +9,7 @@ package httptest
 import (
 	"bytes"
 	"crypto/tls"
+	"crypto/x509"
 	"flag"
 	"fmt"
 	"log"
@@ -35,6 +36,9 @@ type Server struct {
 	// before Start or StartTLS.
 	Config *http.Server
 
+	// certificate is a parsed version of the TLS config certificate, if present.
+	certificate *x509.Certificate
+
 	// wg counts the number of outstanding HTTP requests on this server.
 	// Close blocks until all requests are finished.
 	wg sync.WaitGroup
@@ -42,6 +46,10 @@ type Server struct {
 	mu     sync.Mutex // guards closed and conns
 	closed bool
 	conns  map[net.Conn]http.ConnState // except terminal states
+
+	// client is configured for use with the server.
+	// Its transport is automatically closed when Close is called.
+	client *http.Client
 }
 
 func newLocalListener() net.Listener {
@@ -85,6 +93,9 @@ func NewUnstartedServer(handler http.Handler) *Server {
 	return &Server{
 		Listener: newLocalListener(),
 		Config:   &http.Server{Handler: handler},
+		client: &http.Client{
+			Transport: &http.Transport{},
+		},
 	}
 }
 
@@ -124,6 +135,17 @@ func (s *Server) StartTLS() {
 	if len(s.TLS.Certificates) == 0 {
 		s.TLS.Certificates = []tls.Certificate{cert}
 	}
+	s.certificate, err = x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0])
+	if err != nil {
+		panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
+	}
+	certpool := x509.NewCertPool()
+	certpool.AddCert(s.certificate)
+	s.client.Transport = &http.Transport{
+		TLSClientConfig: &tls.Config{
+			RootCAs: certpool,
+		},
+	}
 	s.Listener = tls.NewListener(s.Listener, s.TLS)
 	s.URL = "https://" + s.Listener.Addr().String()
 	s.wrap()
@@ -186,6 +208,13 @@ func (s *Server) Close() {
 		t.CloseIdleConnections()
 	}
 
+	// Also close the client idle connections.
+	if s.client != nil {
+		if t, ok := s.client.Transport.(closeIdleTransport); ok {
+			t.CloseIdleConnections()
+		}
+	}
+
 	s.wg.Wait()
 }
 
@@ -228,6 +257,19 @@ func (s *Server) CloseClientConnections() {
 	}
 }
 
+// Certificate returns the certificate used by the server, or nil if
+// the server doesn't use TLS.
+func (s *Server) Certificate() *x509.Certificate {
+	return s.certificate
+}
+
+// Client returns an HTTP client configured for making requests to the server.
+// It is configured to trust the server's TLS test certificate and will
+// close its idle connections on Server.Close.
+func (s *Server) Client() *http.Client {
+	return s.client
+}
+
 func (s *Server) goServe() {
 	s.wg.Add(1)
 	go func() {
diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go
index d032c59..d97cec5 100644
--- a/src/net/http/httptest/server_test.go
+++ b/src/net/http/httptest/server_test.go
@@ -22,6 +22,7 @@ func TestServer(t *testing.T) {
 		t.Fatal(err)
 	}
 	got, err := ioutil.ReadAll(res.Body)
+	res.Body.Close()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -98,3 +99,66 @@ func TestServerCloseClientConnections(t *testing.T) {
 		t.Fatalf("Unexpected response: %#v", res)
 	}
 }
+
+// Tests that the Server.Client method works and returns an http.Client that can hit
+// NewTLSServer without cert warnings.
+func TestServerClient(t *testing.T) {
+	ts := NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("hello"))
+	}))
+	defer ts.Close()
+	client := ts.Client()
+	res, err := client.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	got, err := ioutil.ReadAll(res.Body)
+	res.Body.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(got) != "hello" {
+		t.Errorf("got %q, want hello", string(got))
+	}
+}
+
+// Tests that the Server.Client.Transport interface is implemented
+// by a *http.Transport.
+func TestServerClientTransportType(t *testing.T) {
+	ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+	}))
+	defer ts.Close()
+	client := ts.Client()
+	if _, ok := client.Transport.(*http.Transport); !ok {
+		t.Errorf("got %T, want *http.Transport", client.Transport)
+	}
+}
+
+// Tests that the TLS Server.Client.Transport interface is implemented
+// by a *http.Transport.
+func TestTLSServerClientTransportType(t *testing.T) {
+	ts := NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+	}))
+	defer ts.Close()
+	client := ts.Client()
+	if _, ok := client.Transport.(*http.Transport); !ok {
+		t.Errorf("got %T, want *http.Transport", client.Transport)
+	}
+}
+
+type onlyCloseListener struct {
+	net.Listener
+}
+
+func (onlyCloseListener) Close() error { return nil }
+
+// Issue 19729: panic in Server.Close for values created directly
+// without a constructor (so the unexported client field is nil).
+func TestServerZeroValueClose(t *testing.T) {
+	ts := &Server{
+		Listener: onlyCloseListener{},
+		Config:   &http.Server{},
+	}
+
+	ts.Close() // tests that it doesn't panic
+}
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 79c8fe2..fd78d45 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -149,12 +149,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		}()
 	}
 
-	outreq := new(http.Request)
-	*outreq = *req // includes shallow copies of maps, but okay
+	outreq := req.WithContext(ctx) // includes shallow copies of maps, but okay
 	if req.ContentLength == 0 {
 		outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
 	}
-	outreq = outreq.WithContext(ctx)
 
 	p.Director(outreq)
 	outreq.Close = false
@@ -235,7 +233,8 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 
 	// The "Trailer" header isn't included in the Transport's response,
 	// at least for *http.Transport. Build it up from Trailer.
-	if len(res.Trailer) > 0 {
+	announcedTrailers := len(res.Trailer)
+	if announcedTrailers > 0 {
 		trailerKeys := make([]string, 0, len(res.Trailer))
 		for k := range res.Trailer {
 			trailerKeys = append(trailerKeys, k)
@@ -254,7 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	}
 	p.copyResponse(rw, res.Body)
 	res.Body.Close() // close now, instead of defer, to populate res.Trailer
-	copyHeader(rw.Header(), res.Trailer)
+
+	if len(res.Trailer) == announcedTrailers {
+		copyHeader(rw.Header(), res.Trailer)
+		return
+	}
+
+	for k, vv := range res.Trailer {
+		k = http.TrailerPrefix + k
+		for _, v := range vv {
+			rw.Header().Add(k, v)
+		}
+	}
 }
 
 func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
@@ -288,7 +298,7 @@ func (p *ReverseProxy) copyBuffer(dst io.Writer, src io.Reader, buf []byte) (int
 	var written int64
 	for {
 		nr, rerr := src.Read(buf)
-		if rerr != nil && rerr != io.EOF {
+		if rerr != nil && rerr != io.EOF && rerr != context.Canceled {
 			p.logf("httputil: ReverseProxy read error during body copy: %v", rerr)
 		}
 		if nr > 0 {
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 20c4e16..57503cc 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -69,6 +69,7 @@ func TestReverseProxy(t *testing.T) {
 		w.WriteHeader(backendStatus)
 		w.Write([]byte(backendResponse))
 		w.Header().Set("X-Trailer", "trailer_value")
+		w.Header().Set(http.TrailerPrefix+"X-Unannounced-Trailer", "unannounced_trailer_value")
 	}))
 	defer backend.Close()
 	backendURL, err := url.Parse(backend.URL)
@@ -79,6 +80,7 @@ func TestReverseProxy(t *testing.T) {
 	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
 	frontend := httptest.NewServer(proxyHandler)
 	defer frontend.Close()
+	frontendClient := frontend.Client()
 
 	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
 	getReq.Host = "some-name"
@@ -86,7 +88,7 @@ func TestReverseProxy(t *testing.T) {
 	getReq.Header.Set("Proxy-Connection", "should be deleted")
 	getReq.Header.Set("Upgrade", "foo")
 	getReq.Close = true
-	res, err := http.DefaultClient.Do(getReq)
+	res, err := frontendClient.Do(getReq)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -121,12 +123,15 @@ 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)
 	}
+	if g, e := res.Trailer.Get("X-Unannounced-Trailer"), "unannounced_trailer_value"; g != e {
+		t.Errorf("Trailer(X-Unannounced-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)
+	res, err = frontendClient.Do(getReq)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -172,7 +177,7 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
 	getReq.Header.Set("Connection", "Upgrade, "+fakeConnectionToken)
 	getReq.Header.Set("Upgrade", "original value")
 	getReq.Header.Set(fakeConnectionToken, "should be deleted")
-	res, err := http.DefaultClient.Do(getReq)
+	res, err := frontend.Client().Do(getReq)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -220,7 +225,7 @@ func TestXForwardedFor(t *testing.T) {
 	getReq.Header.Set("Connection", "close")
 	getReq.Header.Set("X-Forwarded-For", prevForwardedFor)
 	getReq.Close = true
-	res, err := http.DefaultClient.Do(getReq)
+	res, err := frontend.Client().Do(getReq)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -259,7 +264,7 @@ func TestReverseProxyQuery(t *testing.T) {
 		frontend := httptest.NewServer(NewSingleHostReverseProxy(backendURL))
 		req, _ := http.NewRequest("GET", frontend.URL+tt.reqSuffix, nil)
 		req.Close = true
-		res, err := http.DefaultClient.Do(req)
+		res, err := frontend.Client().Do(req)
 		if err != nil {
 			t.Fatalf("%d. Get: %v", i, err)
 		}
@@ -295,7 +300,7 @@ func TestReverseProxyFlushInterval(t *testing.T) {
 
 	req, _ := http.NewRequest("GET", frontend.URL, nil)
 	req.Close = true
-	res, err := http.DefaultClient.Do(req)
+	res, err := frontend.Client().Do(req)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -349,13 +354,14 @@ func TestReverseProxyCancelation(t *testing.T) {
 
 	frontend := httptest.NewServer(proxyHandler)
 	defer frontend.Close()
+	frontendClient := frontend.Client()
 
 	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
 	go func() {
 		<-reqInFlight
-		http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
+		frontendClient.Transport.(*http.Transport).CancelRequest(getReq)
 	}()
-	res, err := http.DefaultClient.Do(getReq)
+	res, err := frontendClient.Do(getReq)
 	if res != nil {
 		t.Errorf("got response %v; want nil", res.Status)
 	}
@@ -363,7 +369,7 @@ func TestReverseProxyCancelation(t *testing.T) {
 		// This should be an error like:
 		// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
 		//    use of closed network connection
-		t.Error("DefaultClient.Do() returned nil error; want non-nil error")
+		t.Error("Server.Client().Do() returned nil error; want non-nil error")
 	}
 }
 
@@ -428,11 +434,12 @@ func TestUserAgentHeader(t *testing.T) {
 	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
 	frontend := httptest.NewServer(proxyHandler)
 	defer frontend.Close()
+	frontendClient := frontend.Client()
 
 	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
 	getReq.Header.Set("User-Agent", explicitUA)
 	getReq.Close = true
-	res, err := http.DefaultClient.Do(getReq)
+	res, err := frontendClient.Do(getReq)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -441,7 +448,7 @@ func TestUserAgentHeader(t *testing.T) {
 	getReq, _ = http.NewRequest("GET", frontend.URL+"/noua", nil)
 	getReq.Header.Set("User-Agent", "")
 	getReq.Close = true
-	res, err = http.DefaultClient.Do(getReq)
+	res, err = frontendClient.Do(getReq)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -493,7 +500,7 @@ func TestReverseProxyGetPutBuffer(t *testing.T) {
 
 	req, _ := http.NewRequest("GET", frontend.URL, nil)
 	req.Close = true
-	res, err := http.DefaultClient.Do(req)
+	res, err := frontend.Client().Do(req)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -540,7 +547,7 @@ func TestReverseProxy_Post(t *testing.T) {
 	defer frontend.Close()
 
 	postReq, _ := http.NewRequest("POST", frontend.URL, bytes.NewReader(requestBody))
-	res, err := http.DefaultClient.Do(postReq)
+	res, err := frontend.Client().Do(postReq)
 	if err != nil {
 		t.Fatalf("Do: %v", err)
 	}
@@ -573,7 +580,7 @@ func TestReverseProxy_NilBody(t *testing.T) {
 	frontend := httptest.NewServer(proxyHandler)
 	defer frontend.Close()
 
-	res, err := http.DefaultClient.Get(frontend.URL)
+	res, err := frontend.Client().Get(frontend.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -664,3 +671,68 @@ func TestReverseProxy_CopyBuffer(t *testing.T) {
 		}
 	}
 }
+
+type staticTransport struct {
+	res *http.Response
+}
+
+func (t *staticTransport) RoundTrip(r *http.Request) (*http.Response, error) {
+	return t.res, nil
+}
+
+func BenchmarkServeHTTP(b *testing.B) {
+	res := &http.Response{
+		StatusCode: 200,
+		Body:       ioutil.NopCloser(strings.NewReader("")),
+	}
+	proxy := &ReverseProxy{
+		Director:  func(*http.Request) {},
+		Transport: &staticTransport{res},
+	}
+
+	w := httptest.NewRecorder()
+	r := httptest.NewRequest("GET", "/", nil)
+
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		proxy.ServeHTTP(w, r)
+	}
+}
+
+func TestServeHTTPDeepCopy(t *testing.T) {
+	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("Hello Gopher!"))
+	}))
+	defer backend.Close()
+	backendURL, err := url.Parse(backend.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	type result struct {
+		before, after string
+	}
+
+	resultChan := make(chan result, 1)
+	proxyHandler := NewSingleHostReverseProxy(backendURL)
+	frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		before := r.URL.String()
+		proxyHandler.ServeHTTP(w, r)
+		after := r.URL.String()
+		resultChan <- result{before: before, after: after}
+	}))
+	defer frontend.Close()
+
+	want := result{before: "/", after: "/"}
+
+	res, err := frontend.Client().Get(frontend.URL)
+	if err != nil {
+		t.Fatalf("Do: %v", err)
+	}
+	res.Body.Close()
+
+	got := <-resultChan
+	if got != want {
+		t.Errorf("got = %+v; want = %+v", got, want)
+	}
+}
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index 438bd2e..fc0437e 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -151,7 +151,3 @@ func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error
 	}
 	return err
 }
-
-func closeClient(c *http.Client) {
-	c.Transport.(*http.Transport).CloseIdleConnections()
-}
diff --git a/src/net/http/npn_test.go b/src/net/http/npn_test.go
index 4c1f6b5..618bdbe 100644
--- a/src/net/http/npn_test.go
+++ b/src/net/http/npn_test.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"crypto/tls"
+	"crypto/x509"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -43,10 +44,7 @@ func TestNextProtoUpgrade(t *testing.T) {
 
 	// Normal request, without NPN.
 	{
-		tr := newTLSTransport(t, ts)
-		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
+		c := ts.Client()
 		res, err := c.Get(ts.URL)
 		if err != nil {
 			t.Fatal(err)
@@ -63,11 +61,18 @@ func TestNextProtoUpgrade(t *testing.T) {
 	// Request to an advertised but unhandled NPN protocol.
 	// Server will hang up.
 	{
-		tr := newTLSTransport(t, ts)
-		tr.TLSClientConfig.NextProtos = []string{"unhandled-proto"}
+		certPool := x509.NewCertPool()
+		certPool.AddCert(ts.Certificate())
+		tr := &Transport{
+			TLSClientConfig: &tls.Config{
+				RootCAs:    certPool,
+				NextProtos: []string{"unhandled-proto"},
+			},
+		}
 		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
+		c := &Client{
+			Transport: tr,
+		}
 		res, err := c.Get(ts.URL)
 		if err == nil {
 			defer res.Body.Close()
@@ -80,7 +85,8 @@ func TestNextProtoUpgrade(t *testing.T) {
 	// Request using the "tls-0.9" protocol, which we register here.
 	// It is HTTP/0.9 over TLS.
 	{
-		tlsConfig := newTLSTransport(t, ts).TLSClientConfig
+		c := ts.Client()
+		tlsConfig := c.Transport.(*Transport).TLSClientConfig
 		tlsConfig.NextProtos = []string{"tls-0.9"}
 		conn, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig)
 		if err != nil {
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index 126e9ea..da15344 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -90,6 +90,11 @@ func sleep(w http.ResponseWriter, d time.Duration) {
 	}
 }
 
+func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool {
+	srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server)
+	return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds()
+}
+
 // Profile responds with the pprof-formatted cpu profile.
 // The package initialization registers it as /debug/pprof/profile.
 func Profile(w http.ResponseWriter, r *http.Request) {
@@ -98,6 +103,14 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 		sec = 30
 	}
 
+	if durationExceedsWriteTimeout(r, float64(sec)) {
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.Header().Set("X-Go-Pprof", "1")
+		w.WriteHeader(http.StatusBadRequest)
+		fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
+		return
+	}
+
 	// Set Content Type assuming StartCPUProfile will work,
 	// because if it does it starts writing.
 	w.Header().Set("Content-Type", "application/octet-stream")
@@ -106,6 +119,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 		// Can change header back to text content
 		// and send error code.
 		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.Header().Set("X-Go-Pprof", "1")
 		w.WriteHeader(http.StatusInternalServerError)
 		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
 		return
@@ -123,6 +137,14 @@ func Trace(w http.ResponseWriter, r *http.Request) {
 		sec = 1
 	}
 
+	if durationExceedsWriteTimeout(r, sec) {
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.Header().Set("X-Go-Pprof", "1")
+		w.WriteHeader(http.StatusBadRequest)
+		fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
+		return
+	}
+
 	// Set Content Type assuming trace.Start will work,
 	// because if it does it starts writing.
 	w.Header().Set("Content-Type", "application/octet-stream")
@@ -130,6 +152,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
 		// trace.Start failed, so no writes yet.
 		// Can change header back to text content and send error code.
 		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.Header().Set("X-Go-Pprof", "1")
 		w.WriteHeader(http.StatusInternalServerError)
 		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
 		return
@@ -207,7 +230,6 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		runtime.GC()
 	}
 	p.WriteTo(w, debug)
-	return
 }
 
 // Index responds with the pprof-formatted profile named by the request.
diff --git a/src/net/http/proxy_test.go b/src/net/http/proxy_test.go
index 823d144..f59a551 100644
--- a/src/net/http/proxy_test.go
+++ b/src/net/http/proxy_test.go
@@ -75,7 +75,13 @@ func TestCacheKeys(t *testing.T) {
 
 func ResetProxyEnv() {
 	for _, v := range []string{"HTTP_PROXY", "http_proxy", "NO_PROXY", "no_proxy"} {
-		os.Setenv(v, "")
+		os.Unsetenv(v)
 	}
 	ResetCachedEnvironment()
 }
+
+func TestInvalidNoProxy(t *testing.T) {
+	ResetProxyEnv()
+	os.Setenv("NO_PROXY", ":1")
+	useProxy("example.com:80") // should not panic
+}
diff --git a/src/net/http/request.go b/src/net/http/request.go
index fb6bb0a..699b31a 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -27,8 +27,6 @@ import (
 	"sync"
 
 	"golang_org/x/net/idna"
-	"golang_org/x/text/unicode/norm"
-	"golang_org/x/text/width"
 )
 
 const (
@@ -331,6 +329,16 @@ func (r *Request) WithContext(ctx context.Context) *Request {
 	r2 := new(Request)
 	*r2 = *r
 	r2.ctx = ctx
+
+	// Deep copy the URL because it isn't
+	// a map and the URL is mutable by users
+	// of WithContext.
+	if r.URL != nil {
+		r2URL := new(url.URL)
+		*r2URL = *r.URL
+		r2.URL = r2URL
+	}
+
 	return r2
 }
 
@@ -341,18 +349,6 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
 		r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
-// protoAtLeastOutgoing is like ProtoAtLeast, but is for outgoing
-// requests (see issue 18407) where these fields aren't supposed to
-// matter.  As a minor fix for Go 1.8, at least treat (0, 0) as
-// matching HTTP/1.1 or HTTP/1.0.  Only HTTP/1.1 is used.
-// TODO(bradfitz): ideally remove this whole method. It shouldn't be used.
-func (r *Request) protoAtLeastOutgoing(major, minor int) bool {
-	if r.ProtoMajor == 0 && r.ProtoMinor == 0 && major == 1 && minor <= 1 {
-		return true
-	}
-	return r.ProtoAtLeast(major, minor)
-}
-
 // UserAgent returns the client's User-Agent, if sent in the request.
 func (r *Request) UserAgent() string {
 	return r.Header.Get("User-Agent")
@@ -621,6 +617,9 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
 	// Write body and trailer
 	err = tw.WriteBody(w)
 	if err != nil {
+		if tw.bodyReadError == err {
+			err = requestBodyReadError{err}
+		}
 		return err
 	}
 
@@ -630,17 +629,25 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
 	return nil
 }
 
+// requestBodyReadError wraps an error from (*Request).write to indicate
+// that the error came from a Read call on the Request.Body.
+// This error type should not escape the net/http package to users.
+type requestBodyReadError struct{ error }
+
 func idnaASCII(v string) (string, error) {
+	// TODO: Consider removing this check after verifying performance is okay.
+	// Right now punycode verification, length checks, context checks, and the
+	// permissible character tests are all omitted. It also prevents the ToASCII
+	// call from salvaging an invalid IDN, when possible. As a result it may be
+	// possible to have two IDNs that appear identical to the user where the
+	// ASCII-only version causes an error downstream whereas the non-ASCII
+	// version does not.
+	// Note that for correct ASCII IDNs ToASCII will only do considerably more
+	// work, but it will not cause an allocation.
 	if isASCII(v) {
 		return v, nil
 	}
-	// The idna package doesn't do everything from
-	// https://tools.ietf.org/html/rfc5895 so we do it here.
-	// TODO(bradfitz): should the idna package do this instead?
-	v = strings.ToLower(v)
-	v = width.Fold.String(v)
-	v = norm.NFC.String(v)
-	return idna.ToASCII(v)
+	return idna.Lookup.ToASCII(v)
 }
 
 // cleanHost cleans up the host sent in request's Host header.
@@ -930,6 +937,9 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
 	if !ok {
 		return nil, &badStringError{"malformed HTTP request", s}
 	}
+	if !validMethod(req.Method) {
+		return nil, &badStringError{"invalid method", req.Method}
+	}
 	rawurl := req.RequestURI
 	if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
 		return nil, &badStringError{"malformed HTTP version", req.Proto}
@@ -1021,11 +1031,6 @@ type maxBytesReader struct {
 	err error         // sticky error
 }
 
-func (l *maxBytesReader) tooLarge() (n int, err error) {
-	l.err = errors.New("http: request body too large")
-	return 0, l.err
-}
-
 func (l *maxBytesReader) Read(p []byte) (n int, err error) {
 	if l.err != nil {
 		return 0, l.err
@@ -1297,7 +1302,7 @@ func (r *Request) closeBody() {
 }
 
 func (r *Request) isReplayable() bool {
-	if r.Body == nil {
+	if r.Body == nil || r.Body == NoBody || r.GetBody != nil {
 		switch valueOrDefault(r.Method, "GET") {
 		case "GET", "HEAD", "OPTIONS", "TRACE":
 			return true
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index e674837..967156b 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -7,6 +7,7 @@ package http_test
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"encoding/base64"
 	"fmt"
 	"io"
@@ -785,6 +786,28 @@ func TestMaxBytesReaderStickyError(t *testing.T) {
 	}
 }
 
+func TestWithContextDeepCopiesURL(t *testing.T) {
+	req, err := NewRequest("POST", "https://golang.org/", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	reqCopy := req.WithContext(context.Background())
+	reqCopy.URL.Scheme = "http"
+
+	firstURL, secondURL := req.URL.String(), reqCopy.URL.String()
+	if firstURL == secondURL {
+		t.Errorf("unexpected change to original request's URL")
+	}
+
+	// And also check we don't crash on nil (Issue 20601)
+	req.URL = nil
+	reqCopy = req.WithContext(context.Background())
+	if reqCopy.URL != nil {
+		t.Error("expected nil URL in cloned request")
+	}
+}
+
 // verify that NewRequest sets Request.GetBody and that it works
 func TestNewRequestGetBody(t *testing.T) {
 	tests := []struct {
diff --git a/src/net/http/response.go b/src/net/http/response.go
index ae118fb..0357b60 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -37,9 +37,10 @@ type Response struct {
 	// 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
-	// duplicated by other fields in this struct (e.g., ContentLength) are
-	// omitted from Header.
+	// be semantically equivalent to a comma-delimited sequence.) When
+	// Header values are duplicated by other fields in this struct (e.g.,
+	// ContentLength, TransferEncoding, Trailer), the field values are
+	// authoritative.
 	//
 	// Keys in the map are canonicalized (see CanonicalHeaderKey).
 	Header Header
@@ -152,23 +153,23 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
 		}
 		return nil, err
 	}
-	f := strings.SplitN(line, " ", 3)
-	if len(f) < 2 {
+	if i := strings.IndexByte(line, ' '); i == -1 {
 		return nil, &badStringError{"malformed HTTP response", line}
+	} else {
+		resp.Proto = line[:i]
+		resp.Status = strings.TrimLeft(line[i+1:], " ")
 	}
-	reasonPhrase := ""
-	if len(f) > 2 {
-		reasonPhrase = f[2]
+	statusCode := resp.Status
+	if i := strings.IndexByte(resp.Status, ' '); i != -1 {
+		statusCode = resp.Status[:i]
 	}
-	if len(f[1]) != 3 {
-		return nil, &badStringError{"malformed HTTP status code", f[1]}
+	if len(statusCode) != 3 {
+		return nil, &badStringError{"malformed HTTP status code", statusCode}
 	}
-	resp.StatusCode, err = strconv.Atoi(f[1])
+	resp.StatusCode, err = strconv.Atoi(statusCode)
 	if err != nil || resp.StatusCode < 0 {
-		return nil, &badStringError{"malformed HTTP status code", f[1]}
+		return nil, &badStringError{"malformed HTTP status code", statusCode}
 	}
-	resp.Status = f[1] + " " + reasonPhrase
-	resp.Proto = f[0]
 	var ok bool
 	if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
 		return nil, &badStringError{"malformed HTTP version", resp.Proto}
@@ -320,3 +321,9 @@ func (r *Response) Write(w io.Writer) error {
 	// Success
 	return nil
 }
+
+func (r *Response) closeBody() {
+	if r.Body != nil {
+		r.Body.Close()
+	}
+}
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 660d517..f1a50bd 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -318,7 +318,7 @@ var respTests = []respTest{
 	{
 		"HTTP/1.0 303\r\n\r\n",
 		Response{
-			Status:        "303 ",
+			Status:        "303",
 			StatusCode:    303,
 			Proto:         "HTTP/1.0",
 			ProtoMajor:    1,
@@ -532,6 +532,29 @@ some body`,
 		},
 		"\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
 	},
+
+	// Issue 19989: two spaces between HTTP version and status.
+	{
+		"HTTP/1.0  401 Unauthorized\r\n" +
+			"Content-type: text/html\r\n" +
+			"WWW-Authenticate: Basic realm=\"\"\r\n\r\n" +
+			"Your Authentication failed.\r\n",
+		Response{
+			Status:     "401 Unauthorized",
+			StatusCode: 401,
+			Proto:      "HTTP/1.0",
+			ProtoMajor: 1,
+			ProtoMinor: 0,
+			Request:    dummyReq("GET"),
+			Header: Header{
+				"Content-Type":     {"text/html"},
+				"Www-Authenticate": {`Basic realm=""`},
+			},
+			Close:         true,
+			ContentLength: -1,
+		},
+		"Your Authentication failed.\r\n",
+	},
 }
 
 // tests successful calls to ReadResponse, and inspects the returned Response.
@@ -926,3 +949,29 @@ func TestNeedsSniff(t *testing.T) {
 		t.Errorf("needsSniff empty Content-Type = %t; want %t", got, want)
 	}
 }
+
+// A response should only write out single Connection: close header. Tests #19499.
+func TestResponseWritesOnlySingleConnectionClose(t *testing.T) {
+	const connectionCloseHeader = "Connection: close"
+
+	res, err := ReadResponse(bufio.NewReader(strings.NewReader("HTTP/1.0 200 OK\r\n\r\nAAAA")), nil)
+	if err != nil {
+		t.Fatalf("ReadResponse failed %v", err)
+	}
+
+	var buf1 bytes.Buffer
+	if err = res.Write(&buf1); err != nil {
+		t.Fatalf("Write failed %v", err)
+	}
+	if res, err = ReadResponse(bufio.NewReader(&buf1), nil); err != nil {
+		t.Fatalf("ReadResponse failed %v", err)
+	}
+
+	var buf2 bytes.Buffer
+	if err = res.Write(&buf2); err != nil {
+		t.Fatalf("Write failed %v", err)
+	}
+	if count := strings.Count(buf2.String(), connectionCloseHeader); count != 1 {
+		t.Errorf("Found %d %q header", count, connectionCloseHeader)
+	}
+}
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 73dd56e..7137599 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -337,6 +337,7 @@ var serveMuxTests = []struct {
 	{"GET", "codesearch.google.com", "/search/", 203, "codesearch.google.com/"},
 	{"GET", "codesearch.google.com", "/search/foo", 203, "codesearch.google.com/"},
 	{"GET", "codesearch.google.com", "/", 203, "codesearch.google.com/"},
+	{"GET", "codesearch.google.com:443", "/", 203, "codesearch.google.com/"},
 	{"GET", "images.google.com", "/search", 201, "/search"},
 	{"GET", "images.google.com", "/search/", 404, ""},
 	{"GET", "images.google.com", "/search/foo", 404, ""},
@@ -460,31 +461,86 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
 	}
 }
 
+func BenchmarkServeMux(b *testing.B) {
+
+	type test struct {
+		path string
+		code int
+		req  *Request
+	}
+
+	// Build example handlers and requests
+	var tests []test
+	endpoints := []string{"search", "dir", "file", "change", "count", "s"}
+	for _, e := range endpoints {
+		for i := 200; i < 230; i++ {
+			p := fmt.Sprintf("/%s/%d/", e, i)
+			tests = append(tests, test{
+				path: p,
+				code: i,
+				req:  &Request{Method: "GET", Host: "localhost", URL: &url.URL{Path: p}},
+			})
+		}
+	}
+	mux := NewServeMux()
+	for _, tt := range tests {
+		mux.Handle(tt.path, serve(tt.code))
+	}
+
+	rw := httptest.NewRecorder()
+	b.ReportAllocs()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		for _, tt := range tests {
+			*rw = httptest.ResponseRecorder{}
+			h, pattern := mux.Handler(tt.req)
+			h.ServeHTTP(rw, tt.req)
+			if pattern != tt.path || rw.Code != tt.code {
+				b.Fatalf("got %d, %q, want %d, %q", rw.Code, pattern, tt.code, tt.path)
+			}
+		}
+	}
+}
+
 func TestServerTimeouts(t *testing.T) {
 	setParallel(t)
 	defer afterTest(t)
+	// Try three times, with increasing timeouts.
+	tries := []time.Duration{250 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second}
+	for i, timeout := range tries {
+		err := testServerTimeouts(timeout)
+		if err == nil {
+			return
+		}
+		t.Logf("failed at %v: %v", timeout, err)
+		if i != len(tries)-1 {
+			t.Logf("retrying at %v ...", tries[i+1])
+		}
+	}
+	t.Fatal("all attempts failed")
+}
+
+func testServerTimeouts(timeout time.Duration) error {
 	reqNum := 0
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
 		reqNum++
 		fmt.Fprintf(res, "req=%d", reqNum)
 	}))
-	ts.Config.ReadTimeout = 250 * time.Millisecond
-	ts.Config.WriteTimeout = 250 * time.Millisecond
+	ts.Config.ReadTimeout = timeout
+	ts.Config.WriteTimeout = timeout
 	ts.Start()
 	defer ts.Close()
 
 	// Hit the HTTP server successfully.
-	tr := &Transport{DisableKeepAlives: true} // they interfere with this test
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	r, err := c.Get(ts.URL)
 	if err != nil {
-		t.Fatalf("http Get #1: %v", err)
+		return fmt.Errorf("http Get #1: %v", err)
 	}
 	got, err := ioutil.ReadAll(r.Body)
 	expected := "req=1"
 	if string(got) != expected || err != nil {
-		t.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
+		return fmt.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
 			string(got), err, expected)
 	}
 
@@ -492,17 +548,18 @@ func TestServerTimeouts(t *testing.T) {
 	t1 := time.Now()
 	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
 	if err != nil {
-		t.Fatalf("Dial: %v", err)
+		return fmt.Errorf("Dial: %v", err)
 	}
 	buf := make([]byte, 1)
 	n, err := conn.Read(buf)
 	conn.Close()
 	latency := time.Since(t1)
 	if n != 0 || err != io.EOF {
-		t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
+		return fmt.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
 	}
-	if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
-		t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
+	minLatency := timeout / 5 * 4
+	if latency < minLatency {
+		return fmt.Errorf("got EOF after %s, want >= %s", latency, minLatency)
 	}
 
 	// Hit the HTTP server successfully again, verifying that the
@@ -510,29 +567,31 @@ func TestServerTimeouts(t *testing.T) {
 	// get "req=2", not "req=3")
 	r, err = c.Get(ts.URL)
 	if err != nil {
-		t.Fatalf("http Get #2: %v", err)
+		return fmt.Errorf("http Get #2: %v", err)
 	}
 	got, err = ioutil.ReadAll(r.Body)
+	r.Body.Close()
 	expected = "req=2"
 	if string(got) != expected || err != nil {
-		t.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
+		return fmt.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
 	}
 
 	if !testing.Short() {
 		conn, err := net.Dial("tcp", ts.Listener.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial: %v", err)
+			return fmt.Errorf("long Dial: %v", err)
 		}
 		defer conn.Close()
 		go io.Copy(ioutil.Discard, conn)
 		for i := 0; i < 5; i++ {
 			_, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
 			if err != nil {
-				t.Fatalf("on write %d: %v", i, err)
+				return fmt.Errorf("on write %d: %v", i, err)
 			}
-			time.Sleep(ts.Config.ReadTimeout / 2)
+			time.Sleep(timeout / 2)
 		}
 	}
+	return nil
 }
 
 // Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437)
@@ -548,12 +607,10 @@ func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) {
 	ts.StartTLS()
 	defer ts.Close()
 
-	tr := newTLSTransport(t, ts)
-	defer tr.CloseIdleConnections()
-	if err := ExportHttp2ConfigureTransport(tr); err != nil {
+	c := ts.Client()
+	if err := ExportHttp2ConfigureTransport(c.Transport.(*Transport)); err != nil {
 		t.Fatal(err)
 	}
-	c := &Client{Transport: tr}
 
 	for i := 1; i <= 3; i++ {
 		req, err := NewRequest("GET", ts.URL, nil)
@@ -585,13 +642,139 @@ func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) {
 	}
 }
 
+// tryTimeouts runs testFunc with increasing timeouts. Test passes on first success,
+// and fails if all timeouts fail.
+func tryTimeouts(t *testing.T, testFunc func(timeout time.Duration) error) {
+	tries := []time.Duration{250 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second}
+	for i, timeout := range tries {
+		err := testFunc(timeout)
+		if err == nil {
+			return
+		}
+		t.Logf("failed at %v: %v", timeout, err)
+		if i != len(tries)-1 {
+			t.Logf("retrying at %v ...", tries[i+1])
+		}
+	}
+	t.Fatal("all attempts failed")
+}
+
+// Test that the HTTP/2 server RSTs stream on slow write.
+func TestHTTP2WriteDeadlineEnforcedPerStream(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	setParallel(t)
+	defer afterTest(t)
+	tryTimeouts(t, testHTTP2WriteDeadlineEnforcedPerStream)
+}
+
+func testHTTP2WriteDeadlineEnforcedPerStream(timeout time.Duration) error {
+	reqNum := 0
+	ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
+		reqNum++
+		if reqNum == 1 {
+			return // first request succeeds
+		}
+		time.Sleep(timeout) // second request times out
+	}))
+	ts.Config.WriteTimeout = timeout / 2
+	ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
+	ts.StartTLS()
+	defer ts.Close()
+
+	c := ts.Client()
+	if err := ExportHttp2ConfigureTransport(c.Transport.(*Transport)); err != nil {
+		return fmt.Errorf("ExportHttp2ConfigureTransport: %v", err)
+	}
+
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		return fmt.Errorf("NewRequest: %v", err)
+	}
+	r, err := c.Do(req)
+	if err != nil {
+		return fmt.Errorf("http2 Get #1: %v", err)
+	}
+	r.Body.Close()
+	if r.ProtoMajor != 2 {
+		return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
+	}
+
+	req, err = NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		return fmt.Errorf("NewRequest: %v", err)
+	}
+	r, err = c.Do(req)
+	if err == nil {
+		r.Body.Close()
+		if r.ProtoMajor != 2 {
+			return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
+		}
+		return fmt.Errorf("http2 Get #2 expected error, got nil")
+	}
+	expected := "stream ID 3; INTERNAL_ERROR" // client IDs are odd, second stream should be 3
+	if !strings.Contains(err.Error(), expected) {
+		return fmt.Errorf("http2 Get #2: expected error to contain %q, got %q", expected, err)
+	}
+	return nil
+}
+
+// Test that the HTTP/2 server does not send RST when WriteDeadline not set.
+func TestHTTP2NoWriteDeadline(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	setParallel(t)
+	defer afterTest(t)
+	tryTimeouts(t, testHTTP2NoWriteDeadline)
+}
+
+func testHTTP2NoWriteDeadline(timeout time.Duration) error {
+	reqNum := 0
+	ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
+		reqNum++
+		if reqNum == 1 {
+			return // first request succeeds
+		}
+		time.Sleep(timeout) // second request timesout
+	}))
+	ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
+	ts.StartTLS()
+	defer ts.Close()
+
+	c := ts.Client()
+	if err := ExportHttp2ConfigureTransport(c.Transport.(*Transport)); err != nil {
+		return fmt.Errorf("ExportHttp2ConfigureTransport: %v", err)
+	}
+
+	for i := 0; i < 2; i++ {
+		req, err := NewRequest("GET", ts.URL, nil)
+		if err != nil {
+			return fmt.Errorf("NewRequest: %v", err)
+		}
+		r, err := c.Do(req)
+		if err != nil {
+			return fmt.Errorf("http2 Get #%d: %v", i, err)
+		}
+		r.Body.Close()
+		if r.ProtoMajor != 2 {
+			return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
+		}
+	}
+	return nil
+}
+
 // golang.org/issue/4741 -- setting only a write timeout that triggers
 // shouldn't cause a handler to block forever on reads (next HTTP
 // request) that will never happen.
 func TestOnlyWriteTimeout(t *testing.T) {
 	setParallel(t)
 	defer afterTest(t)
-	var conn net.Conn
+	var (
+		mu   sync.RWMutex
+		conn net.Conn
+	)
 	var afterTimeoutErrc = make(chan error, 1)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, req *Request) {
 		buf := make([]byte, 512<<10)
@@ -600,17 +783,21 @@ func TestOnlyWriteTimeout(t *testing.T) {
 			t.Errorf("handler Write error: %v", err)
 			return
 		}
+		mu.RLock()
+		defer mu.RUnlock()
+		if conn == nil {
+			t.Error("no established connection found")
+			return
+		}
 		conn.SetWriteDeadline(time.Now().Add(-30 * time.Second))
 		_, err = w.Write(buf)
 		afterTimeoutErrc <- err
 	}))
-	ts.Listener = trackLastConnListener{ts.Listener, &conn}
+	ts.Listener = trackLastConnListener{ts.Listener, &mu, &conn}
 	ts.Start()
 	defer ts.Close()
 
-	tr := &Transport{DisableKeepAlives: false}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	errc := make(chan error)
 	go func() {
@@ -620,6 +807,7 @@ func TestOnlyWriteTimeout(t *testing.T) {
 			return
 		}
 		_, err = io.Copy(ioutil.Discard, res.Body)
+		res.Body.Close()
 		errc <- err
 	}()
 	select {
@@ -638,12 +826,18 @@ func TestOnlyWriteTimeout(t *testing.T) {
 // trackLastConnListener tracks the last net.Conn that was accepted.
 type trackLastConnListener struct {
 	net.Listener
+
+	mu   *sync.RWMutex
 	last *net.Conn // destination
 }
 
 func (l trackLastConnListener) Accept() (c net.Conn, err error) {
 	c, err = l.Listener.Accept()
-	*l.last = c
+	if err == nil {
+		l.mu.Lock()
+		*l.last = c
+		l.mu.Unlock()
+	}
 	return
 }
 
@@ -671,8 +865,7 @@ func TestIdentityResponse(t *testing.T) {
 	ts := httptest.NewServer(handler)
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+	c := ts.Client()
 
 	// Note: this relies on the assumption (which is true) that
 	// Get sends HTTP/1.1 or greater requests. Otherwise the
@@ -936,7 +1129,6 @@ func (c *blockingRemoteAddrConn) RemoteAddr() net.Addr {
 
 // Issue 12943
 func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
-	setParallel(t)
 	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		fmt.Fprintf(w, "RA:%s", r.RemoteAddr)
@@ -949,21 +1141,22 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
 	ts.Start()
 	defer ts.Close()
 
-	tr := &Transport{DisableKeepAlives: true}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr, Timeout: time.Second}
+	c := ts.Client()
+	c.Timeout = time.Second
+	// Force separate connection for each:
+	c.Transport.(*Transport).DisableKeepAlives = true
 
-	fetch := func(response chan string) {
+	fetch := func(num int, response chan<- string) {
 		resp, err := c.Get(ts.URL)
 		if err != nil {
-			t.Error(err)
+			t.Errorf("Request %d: %v", num, err)
 			response <- ""
 			return
 		}
 		defer resp.Body.Close()
 		body, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
-			t.Error(err)
+			t.Errorf("Request %d: %v", num, err)
 			response <- ""
 			return
 		}
@@ -972,14 +1165,14 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
 
 	// Start a request. The server will block on getting conn.RemoteAddr.
 	response1c := make(chan string, 1)
-	go fetch(response1c)
+	go fetch(1, response1c)
 
 	// Wait for the server to accept it; grab the connection.
 	conn1 := <-conns
 
 	// Start another request and grab its connection
 	response2c := make(chan string, 1)
-	go fetch(response2c)
+	go fetch(2, response2c)
 	var conn2 net.Conn
 
 	select {
@@ -1022,9 +1215,7 @@ func TestIdentityResponseHeaders(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
-
+	c := ts.Client()
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatalf("Get error: %v", err)
@@ -1145,12 +1336,7 @@ func TestTLSServer(t *testing.T) {
 			t.Errorf("expected test TLS server to start with https://, got %q", ts.URL)
 			return
 		}
-		noVerifyTransport := &Transport{
-			TLSClientConfig: &tls.Config{
-				InsecureSkipVerify: true,
-			},
-		}
-		client := &Client{Transport: noVerifyTransport}
+		client := ts.Client()
 		res, err := client.Get(ts.URL)
 		if err != nil {
 			t.Error(err)
@@ -1171,6 +1357,59 @@ func TestTLSServer(t *testing.T) {
 	})
 }
 
+func TestServeTLS(t *testing.T) {
+	// Not parallel: uses global test hooks.
+	defer afterTest(t)
+	defer SetTestHookServerServe(nil)
+
+	cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tlsConf := &tls.Config{
+		Certificates: []tls.Certificate{cert},
+	}
+
+	ln := newLocalListener(t)
+	defer ln.Close()
+	addr := ln.Addr().String()
+
+	serving := make(chan bool, 1)
+	SetTestHookServerServe(func(s *Server, ln net.Listener) {
+		serving <- true
+	})
+	handler := HandlerFunc(func(w ResponseWriter, r *Request) {})
+	s := &Server{
+		Addr:      addr,
+		TLSConfig: tlsConf,
+		Handler:   handler,
+	}
+	errc := make(chan error, 1)
+	go func() { errc <- s.ServeTLS(ln, "", "") }()
+	select {
+	case err := <-errc:
+		t.Fatalf("ServeTLS: %v", err)
+	case <-serving:
+	case <-time.After(5 * time.Second):
+		t.Fatal("timeout")
+	}
+
+	c, err := tls.Dial("tcp", ln.Addr().String(), &tls.Config{
+		InsecureSkipVerify: true,
+		NextProtos:         []string{"h2", "http/1.1"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	if got, want := c.ConnectionState().NegotiatedProtocol, "h2"; got != want {
+		t.Errorf("NegotiatedProtocol = %q; want %q", got, want)
+	}
+	if got, want := c.ConnectionState().NegotiatedProtocolIsMutual, true; got != want {
+		t.Errorf("NegotiatedProtocolIsMutual = %v; want %v", got, want)
+	}
+}
+
 // Issue 15908
 func TestAutomaticHTTP2_Serve_NoTLSConfig(t *testing.T) {
 	testAutomaticHTTP2_Serve(t, nil, true)
@@ -1967,8 +2206,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
 	ts := httptest.NewServer(TimeoutHandler(delayHi, 20*time.Millisecond, ""))
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+	c := ts.Client()
 
 	var wg sync.WaitGroup
 	gate := make(chan bool, 10)
@@ -2011,8 +2249,8 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
 	if testing.Short() {
 		n = 10
 	}
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+
+	c := ts.Client()
 	for i := 0; i < n; i++ {
 		gate <- true
 		wg.Add(1)
@@ -2099,8 +2337,7 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
 	ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+	c := ts.Client()
 
 	// Issue was caused by the timeout handler starting the timer when
 	// was created, not when the request. So wait for more than the timeout
@@ -2127,8 +2364,7 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) {
 	ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+	c := ts.Client()
 
 	res, err := c.Get(ts.URL)
 	if err != nil {
@@ -2364,9 +2600,7 @@ func TestServerWriteHijackZeroBytes(t *testing.T) {
 	ts.Start()
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -2411,8 +2645,7 @@ func TestStripPrefix(t *testing.T) {
 	ts := httptest.NewServer(StripPrefix("/foo", h))
 	defer ts.Close()
 
-	c := &Client{Transport: new(Transport)}
-	defer closeClient(c)
+	c := ts.Client()
 
 	res, err := c.Get(ts.URL + "/foo/bar")
 	if err != nil {
@@ -2433,6 +2666,16 @@ func TestStripPrefix(t *testing.T) {
 	res.Body.Close()
 }
 
+// https://golang.org/issue/18952.
+func TestStripPrefix_notModifyRequest(t *testing.T) {
+	h := StripPrefix("/foo", NotFoundHandler())
+	req := httptest.NewRequest("GET", "/foo/bar", nil)
+	h.ServeHTTP(httptest.NewRecorder(), req)
+	if req.URL.Path != "/foo/bar" {
+		t.Errorf("StripPrefix should not modify the provided Request, but it did")
+	}
+}
+
 func TestRequestLimit_h1(t *testing.T) { testRequestLimit(t, h1Mode) }
 func TestRequestLimit_h2(t *testing.T) { testRequestLimit(t, h2Mode) }
 func testRequestLimit(t *testing.T, h2 bool) {
@@ -3512,8 +3755,8 @@ func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
 
 // Test that a hanging Request.Body.Read from another goroutine can't
 // cause the Handler goroutine's Request.Body.Close to block.
+// See issue 7121.
 func TestRequestBodyCloseDoesntBlock(t *testing.T) {
-	t.Skipf("Skipping known issue; see golang.org/issue/7121")
 	if testing.Short() {
 		t.Skip("skipping in -short mode")
 	}
@@ -3644,9 +3887,7 @@ func TestServerConnState(t *testing.T) {
 	}
 	ts.Start()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	mustGet := func(url string, headers ...string) {
 		req, err := NewRequest("GET", url, nil)
@@ -4170,6 +4411,9 @@ func TestServerValidatesHostHeader(t *testing.T) {
 		// Make an exception for HTTP upgrade requests:
 		{"PRI * HTTP/2.0", "", 200},
 
+		// Also an exception for CONNECT requests: (Issue 18215)
+		{"CONNECT golang.org:443 HTTP/1.1", "", 200},
+
 		// But not other HTTP/2 stuff:
 		{"PRI / HTTP/2.0", "", 400},
 		{"GET / HTTP/2.0", "", 400},
@@ -4373,13 +4617,6 @@ func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
 		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)
@@ -4389,6 +4626,37 @@ func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
 	res.Body.Close()
 }
 
+func TestServerContext_LocalAddrContextKey_h1(t *testing.T) {
+	testServerContext_LocalAddrContextKey(t, h1Mode)
+}
+func TestServerContext_LocalAddrContextKey_h2(t *testing.T) {
+	testServerContext_LocalAddrContextKey(t, h2Mode)
+}
+func testServerContext_LocalAddrContextKey(t *testing.T, h2 bool) {
+	setParallel(t)
+	defer afterTest(t)
+	ch := make(chan interface{}, 1)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		ch <- r.Context().Value(LocalAddrContextKey)
+	}))
+	defer cst.close()
+	if _, err := cst.c.Head(cst.ts.URL); err != nil {
+		t.Fatal(err)
+	}
+
+	host := cst.ts.Listener.Addr().String()
+	select {
+	case got := <-ch:
+		if addr, ok := got.(net.Addr); !ok {
+			t.Errorf("local addr value = %T; want net.Addr", got)
+		} else if fmt.Sprint(addr) != host {
+			t.Errorf("local addr = %v; want %v", addr, host)
+		}
+	case <-time.After(5 * time.Second):
+		t.Error("timed out")
+	}
+}
+
 // https://golang.org/issue/15960
 func TestHandlerSetTransferEncodingChunked(t *testing.T) {
 	setParallel(t)
@@ -4481,15 +4749,9 @@ func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) {
 	b.ResetTimer()
 	b.SetParallelism(parallelism)
 	b.RunParallel(func(pb *testing.PB) {
-		noVerifyTransport := &Transport{
-			TLSClientConfig: &tls.Config{
-				InsecureSkipVerify: true,
-			},
-		}
-		defer noVerifyTransport.CloseIdleConnections()
-		client := &Client{Transport: noVerifyTransport}
+		c := ts.Client()
 		for pb.Next() {
-			res, err := client.Get(ts.URL)
+			res, err := c.Get(ts.URL)
 			if err != nil {
 				b.Logf("Get: %v", err)
 				continue
@@ -4924,10 +5186,7 @@ func TestServerIdleTimeout(t *testing.T) {
 	ts.Config.IdleTimeout = 2 * time.Second
 	ts.Start()
 	defer ts.Close()
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	get := func() string {
 		res, err := c.Get(ts.URL)
@@ -4988,9 +5247,8 @@ func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	get := func() string { return get(t, c, ts.URL) }
 
@@ -5030,7 +5288,8 @@ func testServerShutdown(t *testing.T, h2 bool) {
 	defer afterTest(t)
 	var doShutdown func() // set later
 	var shutdownRes = make(chan error, 1)
-	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+	var gotOnShutdown = make(chan struct{}, 1)
+	handler := HandlerFunc(func(w ResponseWriter, r *Request) {
 		go doShutdown()
 		// Shutdown is graceful, so it should not interrupt
 		// this in-flight response. Add a tiny sleep here to
@@ -5038,7 +5297,10 @@ func testServerShutdown(t *testing.T, h2 bool) {
 		// bugs.
 		time.Sleep(20 * time.Millisecond)
 		io.WriteString(w, r.RemoteAddr)
-	}))
+	})
+	cst := newClientServerTest(t, h2, handler, func(srv *httptest.Server) {
+		srv.Config.RegisterOnShutdown(func() { gotOnShutdown <- struct{}{} })
+	})
 	defer cst.close()
 
 	doShutdown = func() {
@@ -5049,6 +5311,11 @@ func testServerShutdown(t *testing.T, h2 bool) {
 	if err := <-shutdownRes; err != nil {
 		t.Fatalf("Shutdown: %v", err)
 	}
+	select {
+	case <-gotOnShutdown:
+	case <-time.After(5 * time.Second):
+		t.Errorf("onShutdown callback not called, RegisterOnShutdown broken?")
+	}
 
 	res, err := cst.c.Get(cst.ts.URL)
 	if err == nil {
@@ -5109,9 +5376,7 @@ func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) {
 	ts.Start()
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	res, err := c.Get(ts.URL)
 	if err != nil {
@@ -5312,3 +5577,41 @@ func TestServerHijackGetsBackgroundByte_big(t *testing.T) {
 		t.Error("timeout")
 	}
 }
+
+// Issue 18319: test that the Server validates the request method.
+func TestServerValidatesMethod(t *testing.T) {
+	tests := []struct {
+		method string
+		want   int
+	}{
+		{"GET", 200},
+		{"GE(T", 400},
+	}
+	for _, tt := range tests {
+		conn := &testConn{closec: make(chan bool, 1)}
+		io.WriteString(&conn.readBuf, tt.method+" / HTTP/1.1\r\nHost: foo.example\r\n\r\n")
+
+		ln := &oneConnListener{conn}
+		go Serve(ln, serve(200))
+		<-conn.closec
+		res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
+		if err != nil {
+			t.Errorf("For %s, ReadResponse: %v", tt.method, res)
+			continue
+		}
+		if res.StatusCode != tt.want {
+			t.Errorf("For %s, Status = %d; want %d", tt.method, res.StatusCode, tt.want)
+		}
+	}
+}
+
+func BenchmarkResponseStatusLine(b *testing.B) {
+	b.ReportAllocs()
+	b.RunParallel(func(pb *testing.PB) {
+		bw := bufio.NewWriter(ioutil.Discard)
+		var buf3 [3]byte
+		for pb.Next() {
+			Export_writeStatusLine(bw, true, 200, buf3[:])
+		}
+	})
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index df70a15..c1b98da 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -439,9 +439,10 @@ type response struct {
 
 	handlerDone atomicBool // set true when the handler exits
 
-	// Buffers for Date and Content-Length
-	dateBuf [len(TimeFormat)]byte
-	clenBuf [10]byte
+	// Buffers for Date, Content-Length, and status code
+	dateBuf   [len(TimeFormat)]byte
+	clenBuf   [10]byte
+	statusBuf [3]byte
 
 	// closeNotifyCh is the channel returned by CloseNotify.
 	// TODO(bradfitz): this is currently (for Go 1.8) always
@@ -622,7 +623,6 @@ type connReader struct {
 	mu      sync.Mutex // guards following
 	hasByte bool
 	byteBuf [1]byte
-	bgErr   error // non-nil means error happened on background read
 	cond    *sync.Cond
 	inRead  bool
 	aborted bool  // set true before conn.rwc deadline is set to past
@@ -731,11 +731,6 @@ func (cr *connReader) Read(p []byte) (n int, err error) {
 		cr.unlock()
 		return 0, io.EOF
 	}
-	if cr.bgErr != nil {
-		err = cr.bgErr
-		cr.unlock()
-		return 0, err
-	}
 	if len(p) == 0 {
 		cr.unlock()
 		return 0, nil
@@ -839,7 +834,7 @@ func (srv *Server) initialReadLimitSize() int64 {
 	return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
 }
 
-// wrapper around io.ReaderCloser which on first read, sends an
+// wrapper around io.ReadCloser which on first read, sends an
 // HTTP/1.1 100 Continue header
 type expectContinueReader struct {
 	resp       *response
@@ -948,7 +943,7 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
 
 	hosts, haveHost := req.Header["Host"]
 	isH2Upgrade := req.isH2Upgrade()
-	if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade {
+	if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != "CONNECT" {
 		return nil, badRequestError("missing required Host header")
 	}
 	if len(hosts) > 1 {
@@ -1379,7 +1374,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		}
 	}
 
-	w.conn.bufw.WriteString(statusLine(w.req, code))
+	writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:])
 	cw.header.WriteSubset(w.conn.bufw, excludeHeader)
 	setHeader.Write(w.conn.bufw)
 	w.conn.bufw.Write(crlf)
@@ -1403,49 +1398,25 @@ func foreachHeaderElement(v string, fn func(string)) {
 	}
 }
 
-// statusLines is a cache of Status-Line strings, keyed by code (for
-// HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a
-// map keyed by struct of two fields. This map's max size is bounded
-// by 2*len(statusText), two protocol types for each known official
-// status code in the statusText map.
-var (
-	statusMu    sync.RWMutex
-	statusLines = make(map[int]string)
-)
-
-// statusLine returns a response Status-Line (RFC 2616 Section 6.1)
-// for the given request and response status code.
-func statusLine(req *Request, code int) string {
-	// Fast path:
-	key := code
-	proto11 := req.ProtoAtLeast(1, 1)
-	if !proto11 {
-		key = -key
-	}
-	statusMu.RLock()
-	line, ok := statusLines[key]
-	statusMu.RUnlock()
-	if ok {
-		return line
-	}
-
-	// Slow path:
-	proto := "HTTP/1.0"
-	if proto11 {
-		proto = "HTTP/1.1"
-	}
-	codestring := fmt.Sprintf("%03d", code)
-	text, ok := statusText[code]
-	if !ok {
-		text = "status code " + codestring
+// writeStatusLine writes an HTTP/1.x Status-Line (RFC 2616 Section 6.1)
+// to bw. is11 is whether the HTTP request is HTTP/1.1. false means HTTP/1.0.
+// code is the response status code.
+// scratch is an optional scratch buffer. If it has at least capacity 3, it's used.
+func writeStatusLine(bw *bufio.Writer, is11 bool, code int, scratch []byte) {
+	if is11 {
+		bw.WriteString("HTTP/1.1 ")
+	} else {
+		bw.WriteString("HTTP/1.0 ")
 	}
-	line = proto + " " + codestring + " " + text + "\r\n"
-	if ok {
-		statusMu.Lock()
-		defer statusMu.Unlock()
-		statusLines[key] = line
+	if text, ok := statusText[code]; ok {
+		bw.Write(strconv.AppendInt(scratch[:0], int64(code), 10))
+		bw.WriteByte(' ')
+		bw.WriteString(text)
+		bw.WriteString("\r\n")
+	} else {
+		// don't worry about performance
+		fmt.Fprintf(bw, "%03d status code %d\r\n", code, code)
 	}
-	return line
 }
 
 // bodyAllowed reports whether a Write is allowed for this response type.
@@ -1714,6 +1685,7 @@ func isCommonNetReadError(err error) bool {
 // Serve a new connection.
 func (c *conn) serve(ctx context.Context) {
 	c.remoteAddr = c.rwc.RemoteAddr().String()
+	ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
 	defer func() {
 		if err := recover(); err != nil && err != ErrAbortHandler {
 			const size = 64 << 10
@@ -1973,8 +1945,12 @@ func StripPrefix(prefix string, h Handler) Handler {
 	}
 	return HandlerFunc(func(w ResponseWriter, r *Request) {
 		if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
-			r.URL.Path = p
-			h.ServeHTTP(w, r)
+			r2 := new(Request)
+			*r2 = *r
+			r2.URL = new(url.URL)
+			*r2.URL = *r.URL
+			r2.URL.Path = p
+			h.ServeHTTP(w, r2)
 		} else {
 			NotFound(w, r)
 		}
@@ -2163,9 +2139,29 @@ func cleanPath(p string) string {
 	return np
 }
 
-// Find a handler on a handler map given a path string
-// Most-specific (longest) pattern wins
+// stripHostPort returns h without any trailing ":<port>".
+func stripHostPort(h string) string {
+	// If no port on host, return unchanged
+	if strings.IndexByte(h, ':') == -1 {
+		return h
+	}
+	host, _, err := net.SplitHostPort(h)
+	if err != nil {
+		return h // on error, return unchanged
+	}
+	return host
+}
+
+// Find a handler on a handler map given a path string.
+// Most-specific (longest) pattern wins.
 func (mux *ServeMux) match(path string) (h Handler, pattern string) {
+	// Check for exact match first.
+	v, ok := mux.m[path]
+	if ok {
+		return v.h, v.pattern
+	}
+
+	// Check for longest valid match.
 	var n = 0
 	for k, v := range mux.m {
 		if !pathMatch(k, path) {
@@ -2184,7 +2180,10 @@ func (mux *ServeMux) match(path string) (h Handler, pattern string) {
 // consulting r.Method, r.Host, and r.URL.Path. It always returns
 // a non-nil handler. If the path is not in its canonical form, the
 // handler will be an internally-generated handler that redirects
-// to the canonical path.
+// to the canonical path. If the host contains a port, it is ignored
+// when matching handlers.
+//
+// The path and host are used unchanged for CONNECT requests.
 //
 // Handler also returns the registered pattern that matches the
 // request or, in the case of internally-generated redirects,
@@ -2193,16 +2192,24 @@ func (mux *ServeMux) match(path string) (h Handler, pattern string) {
 // If there is no registered handler that applies to the request,
 // Handler returns a ``page not found'' handler and an empty pattern.
 func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
-	if r.Method != "CONNECT" {
-		if p := cleanPath(r.URL.Path); p != r.URL.Path {
-			_, pattern = mux.handler(r.Host, p)
-			url := *r.URL
-			url.Path = p
-			return RedirectHandler(url.String(), StatusMovedPermanently), pattern
-		}
+
+	// CONNECT requests are not canonicalized.
+	if r.Method == "CONNECT" {
+		return mux.handler(r.Host, r.URL.Path)
+	}
+
+	// All other requests have any port stripped and path cleaned
+	// before passing to mux.handler.
+	host := stripHostPort(r.Host)
+	path := cleanPath(r.URL.Path)
+	if path != r.URL.Path {
+		_, pattern = mux.handler(host, path)
+		url := *r.URL
+		url.Path = path
+		return RedirectHandler(url.String(), StatusMovedPermanently), pattern
 	}
 
-	return mux.handler(r.Host, r.URL.Path)
+	return mux.handler(host, r.URL.Path)
 }
 
 // handler is the main implementation of Handler.
@@ -2307,12 +2314,27 @@ func Serve(l net.Listener, handler Handler) error {
 	return srv.Serve(l)
 }
 
+// Serve accepts incoming HTTPS connections on the listener l,
+// 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.
+//
+// Additionally, files containing a certificate and matching private key
+// for the server must be provided. If the certificate is signed by a
+// certificate authority, the certFile should be the concatenation
+// of the server's certificate, any intermediates, and the CA's certificate.
+func ServeTLS(l net.Listener, handler Handler, certFile, keyFile string) error {
+	srv := &Server{Handler: handler}
+	return srv.ServeTLS(l, certFile, keyFile)
+}
+
 // 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
-	TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
+	TLSConfig *tls.Config // optional TLS config, used by ServeTLS and ListenAndServeTLS
 
 	// ReadTimeout is the maximum duration for reading the entire
 	// request, including the body.
@@ -2379,6 +2401,7 @@ type Server struct {
 	listeners  map[net.Listener]struct{}
 	activeConn map[*conn]struct{}
 	doneChan   chan struct{}
+	onShutdown []func()
 }
 
 func (s *Server) getDoneChan() <-chan struct{} {
@@ -2441,7 +2464,12 @@ var shutdownPollInterval = 500 * time.Millisecond
 // listeners, then closing all idle connections, and then waiting
 // indefinitely for connections to return to idle and then shut down.
 // If the provided context expires before the shutdown is complete,
-// then the context's error is returned.
+// Shutdown returns the context's error, otherwise it returns any
+// error returned from closing the Server's underlying Listener(s).
+//
+// When Shutdown is called, Serve, ListenAndServe, and
+// ListenAndServeTLS immediately return ErrServerClosed. Make sure the
+// program doesn't exit and waits instead for Shutdown to return.
 //
 // Shutdown does not attempt to close nor wait for hijacked
 // connections such as WebSockets. The caller of Shutdown should
@@ -2454,6 +2482,9 @@ func (srv *Server) Shutdown(ctx context.Context) error {
 	srv.mu.Lock()
 	lnerr := srv.closeListenersLocked()
 	srv.closeDoneChanLocked()
+	for _, f := range srv.onShutdown {
+		go f()
+	}
 	srv.mu.Unlock()
 
 	ticker := time.NewTicker(shutdownPollInterval)
@@ -2470,6 +2501,17 @@ func (srv *Server) Shutdown(ctx context.Context) error {
 	}
 }
 
+// RegisterOnShutdown registers a function to call on Shutdown.
+// This can be used to gracefully shutdown connections that have
+// undergone NPN/ALPN protocol upgrade or that have been hijacked.
+// This function should start protocol-specific graceful shutdown,
+// but should not wait for shutdown to complete.
+func (srv *Server) RegisterOnShutdown(f func()) {
+	srv.mu.Lock()
+	srv.onShutdown = append(srv.onShutdown, f)
+	srv.mu.Unlock()
+}
+
 // closeIdleConns closes all idle connections and reports whether the
 // server is quiescent.
 func (s *Server) closeIdleConns() bool {
@@ -2609,6 +2651,8 @@ func (srv *Server) shouldConfigureHTTP2ForServe() bool {
 	return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS)
 }
 
+// ErrServerClosed is returned by the Server's Serve, ServeTLS, ListenAndServe,
+// and ListenAndServeTLS methods after a call to Shutdown or Close.
 var ErrServerClosed = errors.New("http: Server closed")
 
 // Serve accepts incoming connections on the Listener l, creating a
@@ -2638,7 +2682,6 @@ func (srv *Server) Serve(l net.Listener) error {
 
 	baseCtx := context.Background() // base is always background, per Issue 16220
 	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
-	ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())
 	for {
 		rw, e := l.Accept()
 		if e != nil {
@@ -2669,6 +2712,49 @@ func (srv *Server) Serve(l net.Listener) error {
 	}
 }
 
+// ServeTLS 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.
+//
+// Additionally, files containing a certificate and matching private key for
+// the server must be provided if neither the Server's TLSConfig.Certificates
+// nor TLSConfig.GetCertificate are populated.. If the certificate is signed by
+// a certificate authority, the certFile should be the concatenation of the
+// server's certificate, any intermediates, and the CA's certificate.
+//
+// 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.
+//
+// ServeTLS always returns a non-nil error. After Shutdown or Close, the
+// returned error is ErrServerClosed.
+func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error {
+	// Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
+	// before we clone it and create the TLS Listener.
+	if err := srv.setupHTTP2_ServeTLS(); err != nil {
+		return err
+	}
+
+	config := cloneTLSConfig(srv.TLSConfig)
+	if !strSliceContains(config.NextProtos, "http/1.1") {
+		config.NextProtos = append(config.NextProtos, "http/1.1")
+	}
+
+	configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil
+	if !configHasCert || certFile != "" || keyFile != "" {
+		var err error
+		config.Certificates = make([]tls.Certificate, 1)
+		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+		if err != nil {
+			return err
+		}
+	}
+
+	tlsListener := tls.NewListener(l, config)
+	return srv.Serve(tlsListener)
+}
+
 func (s *Server) trackListener(ln net.Listener, add bool) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
@@ -2840,47 +2926,25 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 		addr = ":https"
 	}
 
-	// Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
-	// before we clone it and create the TLS Listener.
-	if err := srv.setupHTTP2_ListenAndServeTLS(); err != nil {
-		return err
-	}
-
-	config := cloneTLSConfig(srv.TLSConfig)
-	if !strSliceContains(config.NextProtos, "http/1.1") {
-		config.NextProtos = append(config.NextProtos, "http/1.1")
-	}
-
-	configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil
-	if !configHasCert || certFile != "" || keyFile != "" {
-		var err error
-		config.Certificates = make([]tls.Certificate, 1)
-		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
-		if err != nil {
-			return err
-		}
-	}
-
 	ln, err := net.Listen("tcp", addr)
 	if err != nil {
 		return err
 	}
 
-	tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
-	return srv.Serve(tlsListener)
+	return srv.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, certFile, keyFile)
 }
 
-// setupHTTP2_ListenAndServeTLS conditionally configures HTTP/2 on
+// setupHTTP2_ServeTLS conditionally configures HTTP/2 on
 // srv and returns whether there was an error setting it up. If it is
 // not configured for policy reasons, nil is returned.
-func (srv *Server) setupHTTP2_ListenAndServeTLS() error {
+func (srv *Server) setupHTTP2_ServeTLS() error {
 	srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
 	return srv.nextProtoErr
 }
 
 // setupHTTP2_Serve is called from (*Server).Serve and conditionally
 // configures HTTP/2 on srv using a more conservative policy than
-// setupHTTP2_ListenAndServeTLS because Serve may be called
+// setupHTTP2_ServeTLS because Serve may be called
 // concurrently.
 //
 // The tests named TestTransportAutomaticHTTP2* and
@@ -2907,7 +2971,10 @@ func (srv *Server) onceSetNextProtoDefaults() {
 	// Enable HTTP/2 by default if the user hasn't otherwise
 	// configured their TLSNextProto map.
 	if srv.TLSNextProto == nil {
-		srv.nextProtoErr = http2ConfigureServer(srv, nil)
+		conf := &http2Server{
+			NewWriteScheduler: func() http2WriteScheduler { return http2NewPriorityWriteScheduler(nil) },
+		}
+		srv.nextProtoErr = http2ConfigureServer(srv, conf)
 	}
 }
 
diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go
index 0d21b44..ecc65e4 100644
--- a/src/net/http/sniff.go
+++ b/src/net/http/sniff.go
@@ -107,8 +107,8 @@ var sniffSignatures = []sniffSig{
 		ct:   "audio/basic",
 	},
 	&maskedSig{
-		mask: []byte("OggS\x00"),
-		pat:  []byte("\x4F\x67\x67\x53\x00"),
+		mask: []byte("\xFF\xFF\xFF\xFF\xFF"),
+		pat:  []byte("OggS\x00"),
 		ct:   "application/ogg",
 	},
 	&maskedSig{
diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go
index 38f3f81..24f1298 100644
--- a/src/net/http/sniff_test.go
+++ b/src/net/http/sniff_test.go
@@ -45,7 +45,11 @@ var sniffTests = []struct {
 	{"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"},
+	{"Must not match OGG", []byte("owow\x00"), "application/octet-stream"},
+	{"Must not match OGG", []byte("oooS\x00"), "application/octet-stream"},
+	{"Must not match OGG", []byte("oggS\x00"), "application/octet-stream"},
 
 	// Video types.
 	{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 4f47637..8faff2d 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -51,6 +51,19 @@ func (br *byteReader) Read(p []byte) (n int, err error) {
 	return 1, io.EOF
 }
 
+// transferBodyReader is an io.Reader that reads from tw.Body
+// and records any non-EOF error in tw.bodyReadError.
+// It is exactly 1 pointer wide to avoid allocations into interfaces.
+type transferBodyReader struct{ tw *transferWriter }
+
+func (br transferBodyReader) Read(p []byte) (n int, err error) {
+	n, err = br.tw.Body.Read(p)
+	if err != nil && err != io.EOF {
+		br.tw.bodyReadError = err
+	}
+	return
+}
+
 // transferWriter inspects the fields of a user-supplied Request or Response,
 // sanitizes them without changing the user object and provides methods for
 // writing the respective header, body and trailer in wire format.
@@ -62,8 +75,10 @@ type transferWriter struct {
 	ContentLength    int64 // -1 means unknown, 0 means exactly none
 	Close            bool
 	TransferEncoding []string
+	Header           Header
 	Trailer          Header
 	IsResponse       bool
+	bodyReadError    error // any non-EOF error from reading Body
 
 	FlushHeaders bool            // flush headers to network before body
 	ByteReadCh   chan readResult // non-nil if probeRequestBody called
@@ -82,14 +97,15 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 		t.Method = valueOrDefault(rr.Method, "GET")
 		t.Close = rr.Close
 		t.TransferEncoding = rr.TransferEncoding
+		t.Header = rr.Header
 		t.Trailer = rr.Trailer
-		atLeastHTTP11 = rr.protoAtLeastOutgoing(1, 1)
 		t.Body = rr.Body
 		t.BodyCloser = rr.Body
 		t.ContentLength = rr.outgoingLength()
-		if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 && t.shouldSendChunkedRequestBody() {
+		if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && t.shouldSendChunkedRequestBody() {
 			t.TransferEncoding = []string{"chunked"}
 		}
+		atLeastHTTP11 = true // Transport requests are always 1.1 or 2.0
 	case *Response:
 		t.IsResponse = true
 		if rr.Request != nil {
@@ -100,6 +116,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 		t.ContentLength = rr.ContentLength
 		t.Close = rr.Close
 		t.TransferEncoding = rr.TransferEncoding
+		t.Header = rr.Header
 		t.Trailer = rr.Trailer
 		atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
 		t.ResponseToHEAD = noResponseBodyExpected(t.Method)
@@ -252,7 +269,7 @@ func (t *transferWriter) shouldSendContentLength() bool {
 }
 
 func (t *transferWriter) WriteHeader(w io.Writer) error {
-	if t.Close {
+	if t.Close && !hasToken(t.Header.get("Connection"), "close") {
 		if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
 			return err
 		}
@@ -304,24 +321,25 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 
 	// Write body
 	if t.Body != nil {
+		var body = transferBodyReader{t}
 		if chunked(t.TransferEncoding) {
 			if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
 				w = &internal.FlushAfterChunkWriter{Writer: bw}
 			}
 			cw := internal.NewChunkedWriter(w)
-			_, err = io.Copy(cw, t.Body)
+			_, err = io.Copy(cw, body)
 			if err == nil {
 				err = cw.Close()
 			}
 		} else if t.ContentLength == -1 {
-			ncopy, err = io.Copy(w, t.Body)
+			ncopy, err = io.Copy(w, body)
 		} else {
-			ncopy, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+			ncopy, err = io.Copy(w, io.LimitReader(body, t.ContentLength))
 			if err != nil {
 				return err
 			}
 			var nextra int64
-			nextra, err = io.Copy(ioutil.Discard, t.Body)
+			nextra, err = io.Copy(ioutil.Discard, body)
 			ncopy += nextra
 		}
 		if err != nil {
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 571943d..9dedc22 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -29,6 +29,7 @@ import (
 	"time"
 
 	"golang_org/x/net/lex/httplex"
+	"golang_org/x/net/proxy"
 )
 
 // DefaultTransport is the default implementation of Transport and is
@@ -275,13 +276,17 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) {
 		return nil, nil
 	}
 	proxyURL, err := url.Parse(proxy)
-	if err != nil || !strings.HasPrefix(proxyURL.Scheme, "http") {
+	if err != nil ||
+		(proxyURL.Scheme != "http" &&
+			proxyURL.Scheme != "https" &&
+			proxyURL.Scheme != "socks5") {
 		// proxy was bogus. Try prepending "http://" to it and
 		// see if that parses correctly. If not, we fall
 		// through and complain about the original one.
 		if proxyURL, err := url.Parse("http://" + proxy); err == nil {
 			return proxyURL, nil
 		}
+
 	}
 	if err != nil {
 		return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
@@ -298,11 +303,15 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
 }
 
 // transportRequest is a wrapper around a *Request that adds
-// optional extra headers to write.
+// optional extra headers to write and stores any error to return
+// from roundTrip.
 type transportRequest struct {
 	*Request                        // original request, not to be mutated
 	extra    Header                 // extra headers to write, or nil
 	trace    *httptrace.ClientTrace // optional
+
+	mu  sync.Mutex // guards err
+	err error      // first setError value for mapRoundTripError to consider
 }
 
 func (tr *transportRequest) extraHeaders() Header {
@@ -312,6 +321,14 @@ func (tr *transportRequest) extraHeaders() Header {
 	return tr.extra
 }
 
+func (tr *transportRequest) setError(err error) {
+	tr.mu.Lock()
+	if tr.err == nil {
+		tr.err = err
+	}
+	tr.mu.Unlock()
+}
+
 // RoundTrip implements the RoundTripper interface.
 //
 // For higher-level HTTP client support (such as handling of cookies
@@ -402,6 +419,18 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 			return nil, err
 		}
 		testHookRoundTripRetried()
+
+		// Rewind the body if we're able to.  (HTTP/2 does this itself so we only
+		// need to do it for HTTP/1.1 connections.)
+		if req.GetBody != nil && pconn.alt == nil {
+			newReq := *req
+			var err error
+			newReq.Body, err = req.GetBody()
+			if err != nil {
+				return nil, err
+			}
+			req = &newReq
+		}
 	}
 }
 
@@ -433,8 +462,9 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
 		return false
 	}
 	if _, ok := err.(nothingWrittenError); ok {
-		// We never wrote anything, so it's safe to retry.
-		return true
+		// We never wrote anything, so it's safe to retry, if there's no body or we
+		// can "rewind" the body with GetBody.
+		return req.outgoingLength() == 0 || req.GetBody != nil
 	}
 	if !req.isReplayable() {
 		// Don't retry non-idempotent requests.
@@ -788,7 +818,7 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
 	}
 	t.idleLRU.remove(pconn)
 	key := pconn.cacheKey
-	pconns, _ := t.idleConn[key]
+	pconns := t.idleConn[key]
 	switch len(pconns) {
 	case 0:
 		// Nothing
@@ -964,6 +994,23 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
 	}
 }
 
+type oneConnDialer <-chan net.Conn
+
+func newOneConnDialer(c net.Conn) proxy.Dialer {
+	ch := make(chan net.Conn, 1)
+	ch <- c
+	return oneConnDialer(ch)
+}
+
+func (d oneConnDialer) Dial(network, addr string) (net.Conn, error) {
+	select {
+	case c := <-d:
+		return c, nil
+	default:
+		return nil, io.EOF
+	}
+}
+
 func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) {
 	pconn := &persistConn{
 		t:             t,
@@ -1020,6 +1067,23 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
 	switch {
 	case cm.proxyURL == nil:
 		// Do nothing. Not using a proxy.
+	case cm.proxyURL.Scheme == "socks5":
+		conn := pconn.conn
+		var auth *proxy.Auth
+		if u := cm.proxyURL.User; u != nil {
+			auth = &proxy.Auth{}
+			auth.User = u.Username()
+			auth.Password, _ = u.Password()
+		}
+		p, err := proxy.SOCKS5("", cm.addr(), auth, newOneConnDialer(conn))
+		if err != nil {
+			conn.Close()
+			return nil, err
+		}
+		if _, err := p.Dial("tcp", cm.targetAddr); err != nil {
+			conn.Close()
+			return nil, err
+		}
 	case cm.targetScheme == "http":
 		pconn.isProxy = true
 		if pa := cm.proxyAuth(); pa != "" {
@@ -1176,6 +1240,10 @@ func useProxy(addr string) bool {
 		if addr == p {
 			return false
 		}
+		if len(p) == 0 {
+			// There is no host part, likely the entry is malformed; ignore.
+			continue
+		}
 		if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
 			// no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
 			return false
@@ -1193,19 +1261,21 @@ func useProxy(addr string) bool {
 //
 // A connect method may be of the following types:
 //
-// Cache key form                Description
-// -----------------             -------------------------
-// |http|foo.com                 http directly to server, no proxy
-// |https|foo.com                https directly to server, no proxy
-// http://proxy.com|https|foo.com  http to proxy, then CONNECT to foo.com
-// http://proxy.com|http           http to proxy, http to anywhere after that
+// Cache key form                    Description
+// -----------------                 -------------------------
+// |http|foo.com                     http directly to server, no proxy
+// |https|foo.com                    https directly to server, no proxy
+// http://proxy.com|https|foo.com    http to proxy, then CONNECT to foo.com
+// http://proxy.com|http             http to proxy, http to anywhere after that
+// socks5://proxy.com|http|foo.com   socks5 to proxy, then http to foo.com
+// socks5://proxy.com|https|foo.com  socks5 to proxy, then https to foo.com
 //
 // Note: no support to https to the proxy yet.
 //
 type connectMethod struct {
 	proxyURL     *url.URL // nil for no proxy, else full proxy URL
 	targetScheme string   // "http" or "https"
-	targetAddr   string   // Not used if proxy + http targetScheme (4th example in table)
+	targetAddr   string   // Not used if http proxy + http targetScheme (4th example in table)
 }
 
 func (cm *connectMethod) key() connectMethodKey {
@@ -1213,7 +1283,7 @@ func (cm *connectMethod) key() connectMethodKey {
 	targetAddr := cm.targetAddr
 	if cm.proxyURL != nil {
 		proxyStr = cm.proxyURL.String()
-		if cm.targetScheme == "http" {
+		if strings.HasPrefix(cm.proxyURL.Scheme, "http") && cm.targetScheme == "http" {
 			targetAddr = ""
 		}
 	}
@@ -1379,63 +1449,53 @@ func (pc *persistConn) closeConnIfStillIdle() {
 	pc.close(errIdleConnTimeout)
 }
 
-// mapRoundTripErrorFromReadLoop maps the provided readLoop error into
-// the error value that should be returned from persistConn.roundTrip.
+// mapRoundTripError returns the appropriate error value for
+// persistConn.roundTrip.
+//
+// The provided err is the first error that (*persistConn).roundTrip
+// happened to receive from its select statement.
 //
 // The startBytesWritten value should be the value of pc.nwrite before the roundTrip
 // started writing the request.
-func (pc *persistConn) mapRoundTripErrorFromReadLoop(req *Request, startBytesWritten int64, err error) (out error) {
+func (pc *persistConn) mapRoundTripError(req *transportRequest, startBytesWritten int64, err error) error {
 	if err == nil {
 		return nil
 	}
-	if err := pc.canceled(); err != nil {
-		return err
+
+	// If the request was canceled, that's better than network
+	// failures that were likely the result of tearing down the
+	// connection.
+	if cerr := pc.canceled(); cerr != nil {
+		return cerr
 	}
+
+	// See if an error was set explicitly.
+	req.mu.Lock()
+	reqErr := req.err
+	req.mu.Unlock()
+	if reqErr != nil {
+		return reqErr
+	}
+
 	if err == errServerClosedIdle {
+		// Don't decorate
 		return err
 	}
+
 	if _, ok := err.(transportReadFromServerError); ok {
+		// Don't decorate
 		return err
 	}
 	if pc.isBroken() {
 		<-pc.writeLoopDone
-		if pc.nwrite == startBytesWritten && req.outgoingLength() == 0 {
+		if pc.nwrite == startBytesWritten {
 			return nothingWrittenError{err}
 		}
+		return fmt.Errorf("net/http: HTTP/1.x transport connection broken: %v", 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(req *Request, startBytesWritten int64) error {
-	if err := pc.canceled(); err != nil {
-		return err
-	}
-	err := pc.closed
-	if err == errServerClosedIdle {
-		// Don't decorate
-		return err
-	}
-	if _, ok := err.(transportReadFromServerError); ok {
-		// 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 && req.outgoingLength() == 0 {
-		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() {
@@ -1497,16 +1557,6 @@ func (pc *persistConn) readLoop() {
 				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
-			// same *Request pointer, and we don't want to set call
-			// t.setReqCanceler from this persistConn while the Transport
-			// potentially spins up a different persistConn for the
-			// caller's subsequent request.
-			if !pc.shouldRetryRequest(rc.req, err) {
-				pc.t.setReqCanceler(rc.req, nil)
-			}
 			select {
 			case rc.ch <- responseAndError{err: err}:
 			case <-rc.callerGone:
@@ -1579,7 +1629,7 @@ func (pc *persistConn) readLoop() {
 		}
 
 		resp.Body = body
-		if rc.addedGzip && resp.Header.Get("Content-Encoding") == "gzip" {
+		if rc.addedGzip && strings.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") {
 			resp.Body = &gzipReader{body: body}
 			resp.Header.Del("Content-Encoding")
 			resp.Header.Del("Content-Length")
@@ -1705,12 +1755,23 @@ func (pc *persistConn) writeLoop() {
 		case wr := <-pc.writech:
 			startBytesWritten := pc.nwrite
 			err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))
+			if bre, ok := err.(requestBodyReadError); ok {
+				err = bre.error
+				// Errors reading from the user's
+				// Request.Body are high priority.
+				// Set it here before sending on the
+				// channels below or calling
+				// pc.close() which tears town
+				// connections and causes other
+				// errors.
+				wr.req.setError(err)
+			}
 			if err == nil {
 				err = pc.bw.Flush()
 			}
 			if err != nil {
 				wr.req.Request.closeBody()
-				if pc.nwrite == startBytesWritten && wr.req.outgoingLength() == 0 {
+				if pc.nwrite == startBytesWritten {
 					err = nothingWrittenError{err}
 				}
 			}
@@ -1872,6 +1933,14 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 	gone := make(chan struct{})
 	defer close(gone)
 
+	defer func() {
+		if err != nil {
+			pc.t.setReqCanceler(req.Request, nil)
+		}
+	}()
+
+	const debugRoundTrip = false
+
 	// Write the request concurrently with waiting for a response,
 	// in case the server decides to reply before reading our full
 	// request body.
@@ -1888,38 +1957,50 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 		callerGone: gone,
 	}
 
-	var re responseAndError
 	var respHeaderTimer <-chan time.Time
 	cancelChan := req.Request.Cancel
 	ctxDoneChan := req.Context().Done()
-WaitResponse:
 	for {
 		testHookWaitResLoop()
 		select {
 		case err := <-writeErrCh:
+			if debugRoundTrip {
+				req.logf("writeErrCh resv: %T/%#v", err, err)
+			}
 			if err != nil {
-				if cerr := pc.canceled(); cerr != nil {
-					err = cerr
-				}
-				re = responseAndError{err: err}
 				pc.close(fmt.Errorf("write error: %v", err))
-				break WaitResponse
+				return nil, pc.mapRoundTripError(req, startBytesWritten, err)
 			}
 			if d := pc.t.ResponseHeaderTimeout; d > 0 {
+				if debugRoundTrip {
+					req.logf("starting timer for %v", d)
+				}
 				timer := time.NewTimer(d)
 				defer timer.Stop() // prevent leaks
 				respHeaderTimer = timer.C
 			}
 		case <-pc.closech:
-			re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(req.Request, startBytesWritten)}
-			break WaitResponse
+			if debugRoundTrip {
+				req.logf("closech recv: %T %#v", pc.closed, pc.closed)
+			}
+			return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
 		case <-respHeaderTimer:
+			if debugRoundTrip {
+				req.logf("timeout waiting for response headers.")
+			}
 			pc.close(errTimeout)
-			re = responseAndError{err: errTimeout}
-			break WaitResponse
-		case re = <-resc:
-			re.err = pc.mapRoundTripErrorFromReadLoop(req.Request, startBytesWritten, re.err)
-			break WaitResponse
+			return nil, errTimeout
+		case re := <-resc:
+			if (re.res == nil) == (re.err == nil) {
+				panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil))
+			}
+			if debugRoundTrip {
+				req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err)
+			}
+			if re.err != nil {
+				return nil, pc.mapRoundTripError(req, startBytesWritten, re.err)
+			}
+			return re.res, nil
 		case <-cancelChan:
 			pc.t.CancelRequest(req.Request)
 			cancelChan = nil
@@ -1929,14 +2010,16 @@ WaitResponse:
 			ctxDoneChan = nil
 		}
 	}
+}
 
-	if re.err != nil {
-		pc.t.setReqCanceler(req.Request, nil)
-	}
-	if (re.res == nil) == (re.err == nil) {
-		panic("internal error: exactly one of res or err should be set")
+// tLogKey is a context WithValue key for test debugging contexts containing
+// a t.Logf func. See export_test.go's Request.WithT method.
+type tLogKey struct{}
+
+func (r *transportRequest) logf(format string, args ...interface{}) {
+	if logf, ok := r.Request.Context().Value(tLogKey{}).(func(string, ...interface{})); ok {
+		logf(time.Now().Format(time.RFC3339Nano)+": "+format, args...)
 	}
-	return re.res, re.err
 }
 
 // markReused marks this connection as having been successfully used for a
@@ -1982,8 +2065,9 @@ func (pc *persistConn) closeLocked(err error) {
 }
 
 var portMap = map[string]string{
-	"http":  "80",
-	"https": "443",
+	"http":   "80",
+	"https":  "443",
+	"socks5": "1080",
 }
 
 // canonicalAddr returns url.Host but always with a ":port" suffix
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
index 3d24fc1..594bf6e 100644
--- a/src/net/http/transport_internal_test.go
+++ b/src/net/http/transport_internal_test.go
@@ -9,6 +9,7 @@ package http
 import (
 	"errors"
 	"net"
+	"strings"
 	"testing"
 )
 
@@ -30,6 +31,7 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
 
 	tr := new(Transport)
 	req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
+	req = req.WithT(t)
 	treq := &transportRequest{Request: req}
 	cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
 	pc, err := tr.getConn(treq, cm)
@@ -47,13 +49,13 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
 
 	_, err = pc.roundTrip(treq)
 	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
-		t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+		t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
 	}
 
 	<-pc.closech
 	err = pc.closed
 	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
-		t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+		t.Errorf("pc.closed = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
 	}
 }
 
@@ -80,6 +82,19 @@ func dummyRequest(method string) *Request {
 	}
 	return req
 }
+func dummyRequestWithBody(method string) *Request {
+	req, err := NewRequest(method, "http://fake.tld/", strings.NewReader("foo"))
+	if err != nil {
+		panic(err)
+	}
+	return req
+}
+
+func dummyRequestWithBodyNoGetBody(method string) *Request {
+	req := dummyRequestWithBody(method)
+	req.GetBody = nil
+	return req
+}
 
 func TestTransportShouldRetryRequest(t *testing.T) {
 	tests := []struct {
@@ -131,6 +146,18 @@ func TestTransportShouldRetryRequest(t *testing.T) {
 			err:  errServerClosedIdle,
 			want: true,
 		},
+		7: {
+			pc:   &persistConn{reused: true},
+			req:  dummyRequestWithBody("POST"),
+			err:  nothingWrittenError{},
+			want: true,
+		},
+		8: {
+			pc:   &persistConn{reused: true},
+			req:  dummyRequestWithBodyNoGetBody("POST"),
+			err:  nothingWrittenError{},
+			want: false,
+		},
 	}
 	for i, tt := range tests {
 		got := tt.pc.shouldRetryRequest(tt.req, tt.err)
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index a58b183..27b55dc 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -16,6 +16,7 @@ import (
 	"context"
 	"crypto/rand"
 	"crypto/tls"
+	"encoding/binary"
 	"errors"
 	"fmt"
 	"internal/nettrace"
@@ -130,11 +131,9 @@ func TestTransportKeepAlives(t *testing.T) {
 	ts := httptest.NewServer(hostPortHandler)
 	defer ts.Close()
 
+	c := ts.Client()
 	for _, disableKeepAlive := range []bool{false, true} {
-		tr := &Transport{DisableKeepAlives: disableKeepAlive}
-		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
+		c.Transport.(*Transport).DisableKeepAlives = disableKeepAlive
 		fetch := func(n int) string {
 			res, err := c.Get(ts.URL)
 			if err != nil {
@@ -165,12 +164,11 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
 
 	connSet, testDial := makeTestDial(t)
 
-	for _, connectionClose := range []bool{false, true} {
-		tr := &Transport{
-			Dial: testDial,
-		}
-		c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
+	tr.Dial = testDial
 
+	for _, connectionClose := range []bool{false, true} {
 		fetch := func(n int) string {
 			req := new(Request)
 			var err error
@@ -216,12 +214,10 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 
 	connSet, testDial := makeTestDial(t)
 
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
+	tr.Dial = testDial
 	for _, connectionClose := range []bool{false, true} {
-		tr := &Transport{
-			Dial: testDial,
-		}
-		c := &Client{Transport: tr}
-
 		fetch := func(n int) string {
 			req := new(Request)
 			var err error
@@ -272,10 +268,9 @@ func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) {
 	ts := httptest.NewServer(hostPortHandler)
 	defer ts.Close()
 
-	tr := &Transport{
-		DisableKeepAlives: true,
-	}
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	c.Transport.(*Transport).DisableKeepAlives = true
+
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -290,9 +285,8 @@ func TestTransportIdleCacheKeys(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(hostPortHandler)
 	defer ts.Close()
-
-	tr := &Transport{DisableKeepAlives: false}
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
 		t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
@@ -384,9 +378,11 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
+
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 	maxIdleConnsPerHost := 2
-	tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConnsPerHost}
-	c := &Client{Transport: tr}
+	tr.MaxIdleConnsPerHost = maxIdleConnsPerHost
 
 	// Start 3 outstanding requests and wait for the server to get them.
 	// Their responses will hang until we write to resch, though.
@@ -449,9 +445,8 @@ func TestTransportRemovesDeadIdleConnections(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	doReq := func(name string) string {
 		// Do a POST instead of a GET to prevent the Transport's
@@ -495,9 +490,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(hostPortHandler)
 	defer ts.Close()
-
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	fetch := func(n, retries int) string {
 		condFatalf := func(format string, arg ...interface{}) {
@@ -563,10 +556,7 @@ func TestStressSurpriseServerCloses(t *testing.T) {
 		conn.Close()
 	}))
 	defer ts.Close()
-
-	tr := &Transport{DisableKeepAlives: false}
-	c := &Client{Transport: tr}
-	defer tr.CloseIdleConnections()
+	c := ts.Client()
 
 	// Do a bunch of traffic from different goroutines. Send to activityc
 	// after each request completes, regardless of whether it failed.
@@ -619,9 +609,8 @@ func TestTransportHeadResponses(t *testing.T) {
 		w.WriteHeader(200)
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
-	tr := &Transport{DisableKeepAlives: false}
-	c := &Client{Transport: tr}
 	for i := 0; i < 2; i++ {
 		res, err := c.Head(ts.URL)
 		if err != nil {
@@ -655,10 +644,7 @@ func TestTransportHeadChunkedResponse(t *testing.T) {
 		w.WriteHeader(200)
 	}))
 	defer ts.Close()
-
-	tr := &Transport{DisableKeepAlives: false}
-	c := &Client{Transport: tr}
-	defer tr.CloseIdleConnections()
+	c := ts.Client()
 
 	// Ensure that we wait for the readLoop to complete before
 	// calling Head again
@@ -719,6 +705,7 @@ func TestRoundTripGzip(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
+	tr := ts.Client().Transport.(*Transport)
 
 	for i, test := range roundTripTests {
 		// Test basic request (no accept-encoding)
@@ -726,7 +713,7 @@ func TestRoundTripGzip(t *testing.T) {
 		if test.accept != "" {
 			req.Header.Set("Accept-Encoding", test.accept)
 		}
-		res, err := DefaultTransport.RoundTrip(req)
+		res, err := tr.RoundTrip(req)
 		var body []byte
 		if test.compressed {
 			var r *gzip.Reader
@@ -791,10 +778,9 @@ func TestTransportGzip(t *testing.T) {
 		gz.Close()
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
 	for _, chunked := range []string{"1", "0"} {
-		c := &Client{Transport: &Transport{}}
-
 		// First fetch something large, but only read some of it.
 		res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked)
 		if err != nil {
@@ -844,7 +830,6 @@ func TestTransportGzip(t *testing.T) {
 	}
 
 	// And a HEAD request too, because they're always weird.
-	c := &Client{Transport: &Transport{}}
 	res, err := c.Head(ts.URL)
 	if err != nil {
 		t.Fatalf("Head: %v", err)
@@ -914,11 +899,13 @@ func TestTransportExpect100Continue(t *testing.T) {
 		{path: "/timeout", body: []byte("hello"), sent: 5, status: 200},   // Timeout exceeded and entire body is sent.
 	}
 
+	c := ts.Client()
 	for i, v := range tests {
-		tr := &Transport{ExpectContinueTimeout: 2 * time.Second}
+		tr := &Transport{
+			ExpectContinueTimeout: 2 * time.Second,
+		}
 		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
+		c.Transport = tr
 		body := bytes.NewReader(v.body)
 		req, err := NewRequest("PUT", ts.URL+v.path, body)
 		if err != nil {
@@ -943,6 +930,99 @@ func TestTransportExpect100Continue(t *testing.T) {
 	}
 }
 
+func TestSocks5Proxy(t *testing.T) {
+	defer afterTest(t)
+	ch := make(chan string, 1)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		ch <- "real server"
+	}))
+	defer ts.Close()
+	l := newLocalListener(t)
+	defer l.Close()
+	go func() {
+		defer close(ch)
+		s, err := l.Accept()
+		if err != nil {
+			t.Errorf("socks5 proxy Accept(): %v", err)
+			return
+		}
+		defer s.Close()
+		var buf [22]byte
+		if _, err := io.ReadFull(s, buf[:3]); err != nil {
+			t.Errorf("socks5 proxy initial read: %v", err)
+			return
+		}
+		if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) {
+			t.Errorf("socks5 proxy initial read: got %v, want %v", buf[:3], want)
+			return
+		}
+		if _, err := s.Write([]byte{5, 0}); err != nil {
+			t.Errorf("socks5 proxy initial write: %v", err)
+			return
+		}
+		if _, err := io.ReadFull(s, buf[:4]); err != nil {
+			t.Errorf("socks5 proxy second read: %v", err)
+			return
+		}
+		if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) {
+			t.Errorf("socks5 proxy second read: got %v, want %v", buf[:3], want)
+			return
+		}
+		var ipLen int
+		switch buf[3] {
+		case 1:
+			ipLen = 4
+		case 4:
+			ipLen = 16
+		default:
+			t.Fatalf("socks5 proxy second read: unexpected address type %v", buf[4])
+		}
+		if _, err := io.ReadFull(s, buf[4:ipLen+6]); err != nil {
+			t.Errorf("socks5 proxy address read: %v", err)
+			return
+		}
+		ip := net.IP(buf[4 : ipLen+4])
+		port := binary.BigEndian.Uint16(buf[ipLen+4 : ipLen+6])
+		copy(buf[:3], []byte{5, 0, 0})
+		if _, err := s.Write(buf[:ipLen+6]); err != nil {
+			t.Errorf("socks5 proxy connect write: %v", err)
+			return
+		}
+		done := make(chan struct{})
+		srv := &Server{Handler: HandlerFunc(func(w ResponseWriter, r *Request) {
+			done <- struct{}{}
+		})}
+		srv.Serve(&oneConnListener{conn: s})
+		<-done
+		srv.Shutdown(context.Background())
+		ch <- fmt.Sprintf("proxy for %s:%d", ip, port)
+	}()
+
+	pu, err := url.Parse("socks5://" + l.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	c := ts.Client()
+	c.Transport.(*Transport).Proxy = ProxyURL(pu)
+	if _, err := c.Head(ts.URL); err != nil {
+		t.Error(err)
+	}
+	var got string
+	select {
+	case got = <-ch:
+	case <-time.After(5 * time.Second):
+		t.Fatal("timeout connecting to socks5 proxy")
+	}
+	tsu, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "proxy for " + tsu.Host
+	if got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
 func TestTransportProxy(t *testing.T) {
 	defer afterTest(t)
 	ch := make(chan string, 1)
@@ -959,12 +1039,20 @@ func TestTransportProxy(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}}
-	c.Head(ts.URL)
-	got := <-ch
+	c := ts.Client()
+	c.Transport.(*Transport).Proxy = ProxyURL(pu)
+	if _, err := c.Head(ts.URL); err != nil {
+		t.Error(err)
+	}
+	var got string
+	select {
+	case got = <-ch:
+	case <-time.After(5 * time.Second):
+		t.Fatal("timeout connecting to http proxy")
+	}
 	want := "proxy for " + ts.URL + "/"
 	if got != want {
-		t.Errorf("want %q, got %q", want, got)
+		t.Errorf("got %q, want %q", got, want)
 	}
 }
 
@@ -1022,9 +1110,7 @@ func TestTransportGzipRecursive(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -1052,9 +1138,7 @@ func TestTransportGzipShort(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -1095,9 +1179,8 @@ func TestTransportPersistConnLeak(t *testing.T) {
 		w.WriteHeader(204)
 	}))
 	defer ts.Close()
-
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	n0 := runtime.NumGoroutine()
 
@@ -1160,9 +1243,8 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 	}))
 	defer ts.Close()
-
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	n0 := runtime.NumGoroutine()
 	body := []byte("Hello")
@@ -1194,8 +1276,7 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
 // This used to crash; https://golang.org/issue/3266
 func TestTransportIdleConnCrash(t *testing.T) {
 	defer afterTest(t)
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	var tr *Transport
 
 	unblockCh := make(chan bool, 1)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1203,6 +1284,8 @@ func TestTransportIdleConnCrash(t *testing.T) {
 		tr.CloseIdleConnections()
 	}))
 	defer ts.Close()
+	c := ts.Client()
+	tr = c.Transport.(*Transport)
 
 	didreq := make(chan bool)
 	go func() {
@@ -1232,8 +1315,7 @@ func TestIssue3644(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -1258,8 +1340,7 @@ func TestIssue3595(t *testing.T) {
 		Error(w, deniedMsg, StatusUnauthorized)
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a'))
 	if err != nil {
 		t.Errorf("Post: %v", err)
@@ -1283,8 +1364,8 @@ func TestChunkedNoContent(t *testing.T) {
 	}))
 	defer ts.Close()
 
+	c := ts.Client()
 	for _, closeBody := range []bool{true, false} {
-		c := &Client{Transport: &Transport{}}
 		const n = 4
 		for i := 1; i <= n; i++ {
 			res, err := c.Get(ts.URL)
@@ -1324,10 +1405,7 @@ func TestTransportConcurrency(t *testing.T) {
 	SetPendingDialHooks(func() { wg.Add(1) }, wg.Done)
 	defer SetPendingDialHooks(nil, nil)
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
-	c := &Client{Transport: tr}
+	c := ts.Client()
 	reqs := make(chan string)
 	defer close(reqs)
 
@@ -1369,23 +1447,20 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 		io.Copy(w, neverEnding('a'))
 	})
 	ts := httptest.NewServer(mux)
+	defer ts.Close()
 	timeout := 100 * time.Millisecond
 
-	client := &Client{
-		Transport: &Transport{
-			Dial: func(n, addr string) (net.Conn, error) {
-				conn, err := net.Dial(n, addr)
-				if err != nil {
-					return nil, err
-				}
-				conn.SetDeadline(time.Now().Add(timeout))
-				if debug {
-					conn = NewLoggingConn("client", conn)
-				}
-				return conn, nil
-			},
-			DisableKeepAlives: true,
-		},
+	c := ts.Client()
+	c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) {
+		conn, err := net.Dial(n, addr)
+		if err != nil {
+			return nil, err
+		}
+		conn.SetDeadline(time.Now().Add(timeout))
+		if debug {
+			conn = NewLoggingConn("client", conn)
+		}
+		return conn, nil
 	}
 
 	getFailed := false
@@ -1397,7 +1472,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 		if debug {
 			println("run", i+1, "of", nRuns)
 		}
-		sres, err := client.Get(ts.URL + "/get")
+		sres, err := c.Get(ts.URL + "/get")
 		if err != nil {
 			if !getFailed {
 				// Make the timeout longer, once.
@@ -1419,7 +1494,6 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 	if debug {
 		println("tests complete; waiting for handlers to finish")
 	}
-	ts.Close()
 }
 
 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
@@ -1437,21 +1511,17 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 	ts := httptest.NewServer(mux)
 	timeout := 100 * time.Millisecond
 
-	client := &Client{
-		Transport: &Transport{
-			Dial: func(n, addr string) (net.Conn, error) {
-				conn, err := net.Dial(n, addr)
-				if err != nil {
-					return nil, err
-				}
-				conn.SetDeadline(time.Now().Add(timeout))
-				if debug {
-					conn = NewLoggingConn("client", conn)
-				}
-				return conn, nil
-			},
-			DisableKeepAlives: true,
-		},
+	c := ts.Client()
+	c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) {
+		conn, err := net.Dial(n, addr)
+		if err != nil {
+			return nil, err
+		}
+		conn.SetDeadline(time.Now().Add(timeout))
+		if debug {
+			conn = NewLoggingConn("client", conn)
+		}
+		return conn, nil
 	}
 
 	getFailed := false
@@ -1463,7 +1533,7 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 		if debug {
 			println("run", i+1, "of", nRuns)
 		}
-		sres, err := client.Get(ts.URL + "/get")
+		sres, err := c.Get(ts.URL + "/get")
 		if err != nil {
 			if !getFailed {
 				// Make the timeout longer, once.
@@ -1477,7 +1547,7 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 			break
 		}
 		req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body)
-		_, err = client.Do(req)
+		_, err = c.Do(req)
 		if err == nil {
 			sres.Body.Close()
 			t.Errorf("Unexpected successful PUT")
@@ -1509,11 +1579,8 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
 	ts := httptest.NewServer(mux)
 	defer ts.Close()
 
-	tr := &Transport{
-		ResponseHeaderTimeout: 500 * time.Millisecond,
-	}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	c.Transport.(*Transport).ResponseHeaderTimeout = 500 * time.Millisecond
 
 	tests := []struct {
 		path    string
@@ -1525,7 +1592,9 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
 		{path: "/fast", want: 200},
 	}
 	for i, tt := range tests {
-		res, err := c.Get(ts.URL + tt.path)
+		req, _ := NewRequest("GET", ts.URL+tt.path, nil)
+		req = req.WithT(t)
+		res, err := c.Do(req)
 		select {
 		case <-inHandler:
 		case <-time.After(5 * time.Second):
@@ -1578,9 +1647,8 @@ func TestTransportCancelRequest(t *testing.T) {
 	defer ts.Close()
 	defer close(unblockc)
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	req, _ := NewRequest("GET", ts.URL, nil)
 	res, err := c.Do(req)
@@ -1688,9 +1756,8 @@ func TestCancelRequestWithChannel(t *testing.T) {
 	defer ts.Close()
 	defer close(unblockc)
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	req, _ := NewRequest("GET", ts.URL, nil)
 	ch := make(chan struct{})
@@ -1747,9 +1814,7 @@ func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
 	defer ts.Close()
 	defer close(unblockc)
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
 
 	req, _ := NewRequest("GET", ts.URL, nil)
 	if withCtx {
@@ -1837,9 +1902,8 @@ func TestTransportCloseResponseBody(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	req, _ := NewRequest("GET", ts.URL, nil)
 	defer tr.CancelRequest(req)
@@ -1959,18 +2023,12 @@ func TestTransportSocketLateBinding(t *testing.T) {
 	defer ts.Close()
 
 	dialGate := make(chan bool, 1)
-	tr := &Transport{
-		Dial: func(n, addr string) (net.Conn, error) {
-			if <-dialGate {
-				return net.Dial(n, addr)
-			}
-			return nil, errors.New("manually closed")
-		},
-		DisableKeepAlives: false,
-	}
-	defer tr.CloseIdleConnections()
-	c := &Client{
-		Transport: tr,
+	c := ts.Client()
+	c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) {
+		if <-dialGate {
+			return net.Dial(n, addr)
+		}
+		return nil, errors.New("manually closed")
 	}
 
 	dialGate <- true // only allow one dial
@@ -2160,6 +2218,7 @@ var proxyFromEnvTests = []proxyFromEnvTest{
 	{env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"},
 	{env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"},
 	{env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"},
+	{env: "socks5://127.0.0.1", want: "socks5://127.0.0.1"},
 
 	// Don't use secure for http
 	{req: "http://insecure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://http.proxy.tld"},
@@ -2184,6 +2243,7 @@ var proxyFromEnvTests = []proxyFromEnvTest{
 
 func TestProxyFromEnvironment(t *testing.T) {
 	ResetProxyEnv()
+	defer ResetProxyEnv()
 	for _, tt := range proxyFromEnvTests {
 		os.Setenv("HTTP_PROXY", tt.env)
 		os.Setenv("HTTPS_PROXY", tt.httpsenv)
@@ -2223,14 +2283,11 @@ func TestIdleConnChannelLeak(t *testing.T) {
 	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
 	defer SetReadLoopBeforeNextReadHook(nil)
 
-	tr := &Transport{
-		Dial: func(netw, addr string) (net.Conn, error) {
-			return net.Dial(netw, ts.Listener.Addr().String())
-		},
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
+	tr.Dial = func(netw, addr string) (net.Conn, error) {
+		return net.Dial(netw, ts.Listener.Addr().String())
 	}
-	defer tr.CloseIdleConnections()
-
-	c := &Client{Transport: tr}
 
 	// First, without keep-alives.
 	for _, disableKeep := range []bool{true, false} {
@@ -2273,13 +2330,11 @@ func TestTransportClosesRequestBody(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	cl := &Client{Transport: tr}
+	c := ts.Client()
 
 	closes := 0
 
-	res, err := cl.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
+	res, err := c.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2365,20 +2420,16 @@ func TestTLSServerClosesConnection(t *testing.T) {
 		fmt.Fprintf(w, "hello")
 	}))
 	defer ts.Close()
-	tr := &Transport{
-		TLSClientConfig: &tls.Config{
-			InsecureSkipVerify: true,
-		},
-	}
-	defer tr.CloseIdleConnections()
-	client := &Client{Transport: tr}
+
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
 
 	var nSuccess = 0
 	var errs []error
 	const trials = 20
 	for i := 0; i < trials; i++ {
 		tr.CloseIdleConnections()
-		res, err := client.Get(ts.URL + "/keep-alive-then-die")
+		res, err := c.Get(ts.URL + "/keep-alive-then-die")
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2393,7 +2444,7 @@ func TestTLSServerClosesConnection(t *testing.T) {
 
 		// Now try again and see if we successfully
 		// pick a new connection.
-		res, err = client.Get(ts.URL + "/")
+		res, err = c.Get(ts.URL + "/")
 		if err != nil {
 			errs = append(errs, err)
 			continue
@@ -2472,22 +2523,20 @@ func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
 		go io.Copy(ioutil.Discard, conn)
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	client := &Client{Transport: tr}
+	c := ts.Client()
 
 	const bodySize = 256 << 10
 	finalBit := make(byteFromChanReader, 1)
 	req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit))
 	req.ContentLength = bodySize
-	res, err := client.Do(req)
+	res, err := c.Do(req)
 	if err := wantBody(res, err, "foo"); err != nil {
 		t.Errorf("POST response: %v", err)
 	}
 	donec := make(chan bool)
 	go func() {
 		defer close(donec)
-		res, err = client.Get(ts.URL)
+		res, err = c.Get(ts.URL)
 		if err := wantBody(res, err, "bar"); err != nil {
 			t.Errorf("GET response: %v", err)
 			return
@@ -2519,10 +2568,9 @@ func TestTransportIssue10457(t *testing.T) {
 		conn.Close()
 	}))
 	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	cl := &Client{Transport: tr}
-	res, err := cl.Get(ts.URL)
+	c := ts.Client()
+
+	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatalf("Get: %v", err)
 	}
@@ -2553,89 +2601,160 @@ type writerFuncConn struct {
 
 func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) }
 
-// Issue 4677. 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.
+// Issues 4677, 18241, and 17844. 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.
 //
-// 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
-// automatically prevents an infinite resend loop because we'll run out of the
-// cached keep-alive connections eventually.
-func TestRetryIdempotentRequestsOnError(t *testing.T) {
-	defer afterTest(t)
+// NOTE: we resend a request only if:
+//   - we reused a keep-alive connection
+//   - we haven't yet received any header data
+//   - either we wrote no bytes to the server, or the request is idempotent
+// This automatically prevents an infinite resend loop because we'll run out of
+// the cached keep-alive connections eventually.
+func TestRetryRequestsOnError(t *testing.T) {
+	newRequest := func(method, urlStr string, body io.Reader) *Request {
+		req, err := NewRequest(method, urlStr, body)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return req
+	}
 
-	var (
-		mu     sync.Mutex
-		logbuf bytes.Buffer
-	)
-	logf := func(format string, args ...interface{}) {
-		mu.Lock()
-		defer mu.Unlock()
-		fmt.Fprintf(&logbuf, format, args...)
-		logbuf.WriteByte('\n')
+	testCases := []struct {
+		name       string
+		failureN   int
+		failureErr error
+		// Note that we can't just re-use the Request object across calls to c.Do
+		// because we need to rewind Body between calls.  (GetBody is only used to
+		// rewind Body on failure and redirects, not just because it's done.)
+		req       func() *Request
+		reqString string
+	}{
+		{
+			name: "IdempotentNoBodySomeWritten",
+			// Believe that we've written some bytes to the server, so we know we're
+			// not just in the "retry when no bytes sent" case".
+			failureN: 1,
+			// Use the specific error that shouldRetryRequest looks for with idempotent requests.
+			failureErr: ExportErrServerClosedIdle,
+			req: func() *Request {
+				return newRequest("GET", "http://fake.golang", nil)
+			},
+			reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
+		},
+		{
+			name: "IdempotentGetBodySomeWritten",
+			// Believe that we've written some bytes to the server, so we know we're
+			// not just in the "retry when no bytes sent" case".
+			failureN: 1,
+			// Use the specific error that shouldRetryRequest looks for with idempotent requests.
+			failureErr: ExportErrServerClosedIdle,
+			req: func() *Request {
+				return newRequest("GET", "http://fake.golang", strings.NewReader("foo\n"))
+			},
+			reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
+		},
+		{
+			name: "NothingWrittenNoBody",
+			// It's key that we return 0 here -- that's what enables Transport to know
+			// that nothing was written, even though this is a non-idempotent request.
+			failureN:   0,
+			failureErr: errors.New("second write fails"),
+			req: func() *Request {
+				return newRequest("DELETE", "http://fake.golang", nil)
+			},
+			reqString: `DELETE / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
+		},
+		{
+			name: "NothingWrittenGetBody",
+			// It's key that we return 0 here -- that's what enables Transport to know
+			// that nothing was written, even though this is a non-idempotent request.
+			failureN:   0,
+			failureErr: errors.New("second write fails"),
+			// Note that NewRequest will set up GetBody for strings.Reader, which is
+			// required for the retry to occur
+			req: func() *Request {
+				return newRequest("POST", "http://fake.golang", strings.NewReader("foo\n"))
+			},
+			reqString: `POST / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
+		},
 	}
 
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		logf("Handler")
-		w.Header().Set("X-Status", "ok")
-	}))
-	defer ts.Close()
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			defer afterTest(t)
 
-	var writeNumAtomic int32
-	tr := &Transport{
-		Dial: func(network, addr string) (net.Conn, error) {
-			logf("Dial")
-			c, err := net.Dial(network, ts.Listener.Addr().String())
-			if err != nil {
-				logf("Dial error: %v", err)
-				return nil, err
+			var (
+				mu     sync.Mutex
+				logbuf bytes.Buffer
+			)
+			logf := func(format string, args ...interface{}) {
+				mu.Lock()
+				defer mu.Unlock()
+				fmt.Fprintf(&logbuf, format, args...)
+				logbuf.WriteByte('\n')
 			}
-			return &writerFuncConn{
-				Conn: c,
-				write: func(p []byte) (n int, err error) {
-					if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
-						logf("intentional write failure")
-						return 0, errors.New("second write fails")
-					}
-					logf("Write(%q)", p)
-					return c.Write(p)
-				},
-			}, nil
-		},
-	}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
 
-	SetRoundTripRetried(func() {
-		logf("Retried.")
-	})
-	defer SetRoundTripRetried(nil)
+			ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+				logf("Handler")
+				w.Header().Set("X-Status", "ok")
+			}))
+			defer ts.Close()
+
+			var writeNumAtomic int32
+			c := ts.Client()
+			c.Transport.(*Transport).Dial = func(network, addr string) (net.Conn, error) {
+				logf("Dial")
+				c, err := net.Dial(network, ts.Listener.Addr().String())
+				if err != nil {
+					logf("Dial error: %v", err)
+					return nil, err
+				}
+				return &writerFuncConn{
+					Conn: c,
+					write: func(p []byte) (n int, err error) {
+						if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
+							logf("intentional write failure")
+							return tc.failureN, tc.failureErr
+						}
+						logf("Write(%q)", p)
+						return c.Write(p)
+					},
+				}, nil
+			}
 
-	for i := 0; i < 3; i++ {
-		res, err := c.Get("http://fake.golang/")
-		if err != nil {
-			t.Fatalf("i=%d: Get = %v", i, err)
-		}
-		res.Body.Close()
-	}
+			SetRoundTripRetried(func() {
+				logf("Retried.")
+			})
+			defer SetRoundTripRetried(nil)
 
-	mu.Lock()
-	got := logbuf.String()
-	mu.Unlock()
-	const want = `Dial
-Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+			for i := 0; i < 3; i++ {
+				res, err := c.Do(tc.req())
+				if err != nil {
+					t.Fatalf("i=%d: Do = %v", i, err)
+				}
+				res.Body.Close()
+			}
+
+			mu.Lock()
+			got := logbuf.String()
+			mu.Unlock()
+			want := fmt.Sprintf(`Dial
+Write("%s")
 Handler
 intentional write failure
 Retried.
 Dial
-Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Write("%s")
 Handler
-Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n")
+Write("%s")
 Handler
-`
-	if got != want {
-		t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
+`, tc.reqString, tc.reqString, tc.reqString)
+			if got != want {
+				t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
+			}
+		})
 	}
 }
 
@@ -2649,6 +2768,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
 		readBody <- err
 	}))
 	defer ts.Close()
+	c := ts.Client()
 	fakeErr := errors.New("fake error")
 	didClose := make(chan bool, 1)
 	req, _ := NewRequest("POST", ts.URL, struct {
@@ -2664,7 +2784,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
 			return nil
 		}),
 	})
-	res, err := DefaultClient.Do(req)
+	res, err := c.Do(req)
 	if res != nil {
 		defer res.Body.Close()
 	}
@@ -2698,23 +2818,19 @@ func TestTransportDialTLS(t *testing.T) {
 		mu.Unlock()
 	}))
 	defer ts.Close()
-	tr := &Transport{
-		DialTLS: func(netw, addr string) (net.Conn, error) {
-			mu.Lock()
-			didDial = true
-			mu.Unlock()
-			c, err := tls.Dial(netw, addr, &tls.Config{
-				InsecureSkipVerify: true,
-			})
-			if err != nil {
-				return nil, err
-			}
-			return c, c.Handshake()
-		},
+	c := ts.Client()
+	c.Transport.(*Transport).DialTLS = func(netw, addr string) (net.Conn, error) {
+		mu.Lock()
+		didDial = true
+		mu.Unlock()
+		c, err := tls.Dial(netw, addr, c.Transport.(*Transport).TLSClientConfig)
+		if err != nil {
+			return nil, err
+		}
+		return c, c.Handshake()
 	}
-	defer tr.CloseIdleConnections()
-	client := &Client{Transport: tr}
-	res, err := client.Get(ts.URL)
+
+	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2796,10 +2912,11 @@ func TestTransportRangeAndGzip(t *testing.T) {
 		reqc <- r
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
 	req, _ := NewRequest("GET", ts.URL, nil)
 	req.Header.Set("Range", "bytes=7-11")
-	res, err := DefaultClient.Do(req)
+	res, err := c.Do(req)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2828,9 +2945,7 @@ func TestTransportResponseCancelRace(t *testing.T) {
 		w.Write(b[:])
 	}))
 	defer ts.Close()
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
+	tr := ts.Client().Transport.(*Transport)
 
 	req, err := NewRequest("GET", ts.URL, nil)
 	if err != nil {
@@ -2859,14 +2974,46 @@ func TestTransportResponseCancelRace(t *testing.T) {
 	res.Body.Close()
 }
 
+// Test for issue 19248: Content-Encoding's value is case insensitive.
+func TestTransportContentEncodingCaseInsensitive(t *testing.T) {
+	setParallel(t)
+	defer afterTest(t)
+	for _, ce := range []string{"gzip", "GZIP"} {
+		ce := ce
+		t.Run(ce, func(t *testing.T) {
+			const encodedString = "Hello Gopher"
+			ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+				w.Header().Set("Content-Encoding", ce)
+				gz := gzip.NewWriter(w)
+				gz.Write([]byte(encodedString))
+				gz.Close()
+			}))
+			defer ts.Close()
+
+			res, err := ts.Client().Get(ts.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			body, err := ioutil.ReadAll(res.Body)
+			res.Body.Close()
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			if string(body) != encodedString {
+				t.Fatalf("Expected body %q, got: %q\n", encodedString, string(body))
+			}
+		})
+	}
+}
+
 func TestTransportDialCancelRace(t *testing.T) {
 	defer afterTest(t)
 
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
 	defer ts.Close()
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
+	tr := ts.Client().Transport.(*Transport)
 
 	req, err := NewRequest("GET", ts.URL, nil)
 	if err != nil {
@@ -2993,6 +3140,7 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
 		w.WriteHeader(StatusOK)
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
 	fail := 0
 	count := 100
@@ -3002,10 +3150,7 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		tr := new(Transport)
-		defer tr.CloseIdleConnections()
-		client := &Client{Transport: tr}
-		resp, err := client.Do(req)
+		resp, err := c.Do(req)
 		if err != nil {
 			fail++
 			t.Logf("%d = %#v", i, err)
@@ -3218,10 +3363,8 @@ func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) {
 		w.Write(rgz) // arbitrary gzip response
 	}))
 	defer ts.Close()
+	c := ts.Client()
 
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
 	for i := 0; i < 2; i++ {
 		res, err := c.Get(ts.URL)
 		if err != nil {
@@ -3250,12 +3393,9 @@ func TestTransportResponseHeaderLength(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
+	c := ts.Client()
+	c.Transport.(*Transport).MaxResponseHeaderBytes = 512 << 10
 
-	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 {
@@ -3426,16 +3566,26 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
 	}
 }
 
-func TestTransportEventTraceRealDNS(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" {
-		// Skip this test in short mode (the default for
-		// all.bash), in case the user is using a shady/ISP
-		// DNS server hijacking queries.
-		// See issues 16732, 16716.
-		// Our builders use 8.8.8.8, though, which correctly
-		// returns NXDOMAIN, so still run this test there.
-		t.Skip("skipping in short mode")
+var (
+	isDNSHijackedOnce sync.Once
+	isDNSHijacked     bool
+)
+
+func skipIfDNSHijacked(t *testing.T) {
+	// Skip this test if the user is using a shady/ISP
+	// DNS server hijacking queries.
+	// See issues 16732, 16716.
+	isDNSHijackedOnce.Do(func() {
+		addrs, _ := net.LookupHost("dns-should-not-resolve.golang")
+		isDNSHijacked = len(addrs) != 0
+	})
+	if isDNSHijacked {
+		t.Skip("skipping; test requires non-hijacking DNS server")
 	}
+}
+
+func TestTransportEventTraceRealDNS(t *testing.T) {
+	skipIfDNSHijacked(t)
 	defer afterTest(t)
 	tr := &Transport{}
 	defer tr.CloseIdleConnections()
@@ -3506,8 +3656,8 @@ func TestTransportRejectsAlphaPort(t *testing.T) {
 // connections. The http2 test is done in TestTransportEventTrace_h2
 func TestTLSHandshakeTrace(t *testing.T) {
 	defer afterTest(t)
-	s := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
-	defer s.Close()
+	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+	defer ts.Close()
 
 	var mu sync.Mutex
 	var start, done bool
@@ -3527,10 +3677,8 @@ func TestTLSHandshakeTrace(t *testing.T) {
 		},
 	}
 
-	tr := &Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
-	req, err := NewRequest("GET", s.URL, nil)
+	c := ts.Client()
+	req, err := NewRequest("GET", ts.URL, nil)
 	if err != nil {
 		t.Fatal("Unable to construct test request:", err)
 	}
@@ -3557,16 +3705,14 @@ func TestTransportMaxIdleConns(t *testing.T) {
 		// No body for convenience.
 	}))
 	defer ts.Close()
-	tr := &Transport{
-		MaxIdleConns: 4,
-	}
-	defer tr.CloseIdleConnections()
+	c := ts.Client()
+	tr := c.Transport.(*Transport)
+	tr.MaxIdleConns = 4
 
 	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
 	})
@@ -3862,17 +4008,16 @@ func TestTransportProxyConnectHeader(t *testing.T) {
 		c.Close()
 	}))
 	defer ts.Close()
-	tr := &Transport{
-		ProxyConnectHeader: Header{
-			"User-Agent": {"foo"},
-			"Other":      {"bar"},
-		},
-		Proxy: func(r *Request) (*url.URL, error) {
-			return url.Parse(ts.URL)
-		},
+
+	c := ts.Client()
+	c.Transport.(*Transport).Proxy = func(r *Request) (*url.URL, error) {
+		return url.Parse(ts.URL)
 	}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
+	c.Transport.(*Transport).ProxyConnectHeader = Header{
+		"User-Agent": {"foo"},
+		"Other":      {"bar"},
+	}
+
 	res, err := c.Get("https://dummy.tld/") // https to force a CONNECT
 	if err == nil {
 		res.Body.Close()
diff --git a/src/net/interface.go b/src/net/interface.go
index b3297f2..4036a7f 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -211,30 +211,30 @@ func (zc *ipv6ZoneCache) update(ift []Interface) {
 	}
 }
 
-func zoneToString(zone int) string {
-	if zone == 0 {
+func (zc *ipv6ZoneCache) name(index int) string {
+	if index == 0 {
 		return ""
 	}
 	zoneCache.update(nil)
 	zoneCache.RLock()
 	defer zoneCache.RUnlock()
-	name, ok := zoneCache.toName[zone]
+	name, ok := zoneCache.toName[index]
 	if !ok {
-		name = uitoa(uint(zone))
+		name = uitoa(uint(index))
 	}
 	return name
 }
 
-func zoneToInt(zone string) int {
-	if zone == "" {
+func (zc *ipv6ZoneCache) index(name string) int {
+	if name == "" {
 		return 0
 	}
 	zoneCache.update(nil)
 	zoneCache.RLock()
 	defer zoneCache.RUnlock()
-	index, ok := zoneCache.toIndex[zone]
+	index, ok := zoneCache.toIndex[name]
 	if !ok {
-		index, _, _ = dtoi(zone)
+		index, _, _ = dtoi(name)
 	}
 	return index
 }
diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go
index 5e391b2..441ab2f 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -162,7 +162,7 @@ loop:
 				if err != nil {
 					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
 				}
-				ifa := newAddr(ifi, ifam, attrs)
+				ifa := newAddr(ifam, attrs)
 				if ifa != nil {
 					ifat = append(ifat, ifa)
 				}
@@ -172,7 +172,7 @@ loop:
 	return ifat, nil
 }
 
-func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
+func newAddr(ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
 	var ipPointToPoint bool
 	// Seems like we need to make sure whether the IP interface
 	// stack consists of IP point-to-point numbered or unnumbered
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 38a2ca4..534137a 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -262,13 +262,13 @@ func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
 
 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 {
+	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 {
+	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
@@ -290,7 +290,7 @@ func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) err
 		// 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 {
+		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)
 		}
 	}
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index 8b976e5..b08d158 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -24,10 +24,7 @@ func probeWindowsIPStack() (supportsVistaIP bool) {
 	if err != nil {
 		return true // Windows 10 and above will deprecate this API
 	}
-	if byte(v) < 6 { // major version of Windows Vista is 6
-		return false
-	}
-	return true
+	return byte(v) >= 6 // major version of Windows Vista is 6
 }
 
 // adapterAddresses returns a list of IP adapter and address
diff --git a/src/net/internal/socktest/sys_cloexec.go b/src/net/internal/socktest/sys_cloexec.go
index 340ff07..d1b8f4f 100644
--- a/src/net/internal/socktest/sys_cloexec.go
+++ b/src/net/internal/socktest/sys_cloexec.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd linux
+// +build dragonfly freebsd linux
 
 package socktest
 
@@ -15,7 +15,7 @@ func (sw *Switch) Accept4(s, flags int) (ns int, sa syscall.Sockaddr, err error)
 		return syscall.Accept4(s, flags)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterAccept]
+	f := sw.fltab[FilterAccept]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go
index f983e26..9fe86b5 100644
--- a/src/net/internal/socktest/sys_unix.go
+++ b/src/net/internal/socktest/sys_unix.go
@@ -14,7 +14,7 @@ func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
 
 	so := &Status{Cookie: cookie(family, sotype, proto)}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterSocket]
+	f := sw.fltab[FilterSocket]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
@@ -47,7 +47,7 @@ func (sw *Switch) Close(s int) (err error) {
 		return syscall.Close(s)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterClose]
+	f := sw.fltab[FilterClose]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
@@ -77,7 +77,7 @@ func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) {
 		return syscall.Connect(s, sa)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterConnect]
+	f := sw.fltab[FilterConnect]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
@@ -106,7 +106,7 @@ func (sw *Switch) Listen(s, backlog int) (err error) {
 		return syscall.Listen(s, backlog)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterListen]
+	f := sw.fltab[FilterListen]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
@@ -135,7 +135,7 @@ func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) {
 		return syscall.Accept(s)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterAccept]
+	f := sw.fltab[FilterAccept]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
@@ -168,7 +168,7 @@ func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
 		return syscall.GetsockoptInt(s, level, opt)
 	}
 	sw.fmu.RLock()
-	f, _ := sw.fltab[FilterGetsockoptInt]
+	f := sw.fltab[FilterGetsockoptInt]
 	sw.fmu.RUnlock()
 
 	af, err := f.apply(so)
diff --git a/src/net/ip.go b/src/net/ip.go
index db3364c..668818c 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -12,6 +12,8 @@
 
 package net
 
+import _ "unsafe" // for go:linkname
+
 // IP address lengths (bytes).
 const (
 	IPv4len = 4
@@ -338,7 +340,8 @@ func ipEmptyString(ip IP) string {
 }
 
 // MarshalText implements the encoding.TextMarshaler interface.
-// The encoding is the same as returned by String.
+// The encoding is the same as returned by String, with one exception:
+// When len(ip) is zero, it returns an empty slice.
 func (ip IP) MarshalText() ([]byte, error) {
 	if len(ip) == 0 {
 		return []byte(""), nil
@@ -381,17 +384,9 @@ func (ip IP) Equal(x IP) bool {
 	return false
 }
 
-func bytesEqual(x, y []byte) bool {
-	if len(x) != len(y) {
-		return false
-	}
-	for i, b := range x {
-		if y[i] != b {
-			return false
-		}
-	}
-	return true
-}
+// bytes.Equal is implemented in runtime/asm_$goarch.s
+//go:linkname bytesEqual bytes.Equal
+func bytesEqual(x, y []byte) bool
 
 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
@@ -667,7 +662,7 @@ func ParseIP(s string) IP {
 // It returns the IP address and the network implied by the IP and
 // prefix length.
 // For example, ParseCIDR("192.0.2.1/24") returns the IP address
-// 198.0.2.1 and the network 198.0.2.0/24.
+// 192.0.2.1 and the network 192.0.2.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 4655163..ad13388 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"bytes"
+	"math/rand"
 	"reflect"
 	"runtime"
 	"testing"
@@ -468,61 +469,77 @@ func TestNetworkNumberAndMask(t *testing.T) {
 	}
 }
 
-var splitJoinTests = []struct {
-	host string
-	port string
-	join string
-}{
-	{"www.google.com", "80", "www.google.com:80"},
-	{"127.0.0.1", "1234", "127.0.0.1:1234"},
-	{"::1", "80", "[::1]:80"},
-	{"fe80::1%lo0", "80", "[fe80::1%lo0]:80"},
-	{"localhost%lo0", "80", "[localhost%lo0]:80"},
-	{"", "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 behavior
-	{"www.google.com", "", "www.google.com:"},           // Go 1.0 behavior
-}
-
-var splitFailureTests = []struct {
-	hostPort string
-	err      string
-}{
-	{"www.google.com", "missing port in address"},
-	{"127.0.0.1", "missing port in address"},
-	{"[::1]", "missing port in address"},
-	{"[fe80::1%lo0]", "missing port in address"},
-	{"[localhost%lo0]", "missing port in address"},
-	{"localhost%lo0", "missing port in address"},
-
-	{"::1", "too many colons in address"},
-	{"fe80::1%lo0", "too many colons in address"},
-	{"fe80::1%lo0:80", "too many colons in address"},
+func TestSplitHostPort(t *testing.T) {
+	for _, tt := range []struct {
+		hostPort string
+		host     string
+		port     string
+	}{
+		// Host name
+		{"localhost:http", "localhost", "http"},
+		{"localhost:80", "localhost", "80"},
+
+		// Go-specific host name with zone identifier
+		{"localhost%lo0:http", "localhost%lo0", "http"},
+		{"localhost%lo0:80", "localhost%lo0", "80"},
+		{"[localhost%lo0]:http", "localhost%lo0", "http"}, // Go 1 behavior
+		{"[localhost%lo0]:80", "localhost%lo0", "80"},     // Go 1 behavior
+
+		// IP literal
+		{"127.0.0.1:http", "127.0.0.1", "http"},
+		{"127.0.0.1:80", "127.0.0.1", "80"},
+		{"[::1]:http", "::1", "http"},
+		{"[::1]:80", "::1", "80"},
+
+		// IP literal with zone identifier
+		{"[::1%lo0]:http", "::1%lo0", "http"},
+		{"[::1%lo0]:80", "::1%lo0", "80"},
+
+		// Go-specific wildcard for host name
+		{":http", "", "http"}, // Go 1 behavior
+		{":80", "", "80"},     // Go 1 behavior
+
+		// Go-specific wildcard for service name or transport port number
+		{"golang.org:", "golang.org", ""}, // Go 1 behavior
+		{"127.0.0.1:", "127.0.0.1", ""},   // Go 1 behavior
+		{"[::1]:", "::1", ""},             // Go 1 behavior
+
+		// Opaque service name
+		{"golang.org:https%foo", "golang.org", "https%foo"}, // Go 1 behavior
+	} {
+		if host, port, err := SplitHostPort(tt.hostPort); host != tt.host || port != tt.port || err != nil {
+			t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.hostPort, host, port, err, tt.host, tt.port)
+		}
+	}
 
-	{"localhost%lo0:80", "missing brackets in address"},
+	for _, tt := range []struct {
+		hostPort string
+		err      string
+	}{
+		{"golang.org", "missing port in address"},
+		{"127.0.0.1", "missing port in address"},
+		{"[::1]", "missing port in address"},
+		{"[fe80::1%lo0]", "missing port in address"},
+		{"[localhost%lo0]", "missing port in address"},
+		{"localhost%lo0", "missing port in address"},
 
-	// Test cases that didn't fail in Go 1.0
+		{"::1", "too many colons in address"},
+		{"fe80::1%lo0", "too many colons in address"},
+		{"fe80::1%lo0:80", "too many colons in address"},
 
-	{"[foo:bar]", "missing port in address"},
-	{"[foo:bar]baz", "missing port in address"},
-	{"[foo]bar:baz", "missing port in address"},
+		// Test cases that didn't fail in Go 1
 
-	{"[foo]:[bar]:baz", "too many colons in address"},
+		{"[foo:bar]", "missing port in address"},
+		{"[foo:bar]baz", "missing port in address"},
+		{"[foo]bar:baz", "missing port in address"},
 
-	{"[foo]:[bar]baz", "unexpected '[' in address"},
-	{"foo[bar]:baz", "unexpected '[' in address"},
+		{"[foo]:[bar]:baz", "too many colons in address"},
 
-	{"foo]bar:baz", "unexpected ']' in address"},
-}
+		{"[foo]:[bar]baz", "unexpected '[' in address"},
+		{"foo[bar]:baz", "unexpected '[' in address"},
 
-func TestSplitHostPort(t *testing.T) {
-	for _, tt := range splitJoinTests {
-		if host, port, err := SplitHostPort(tt.join); host != tt.host || port != tt.port || err != nil {
-			t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.join, host, port, err, tt.host, tt.port)
-		}
-	}
-	for _, tt := range splitFailureTests {
+		{"foo]bar:baz", "unexpected ']' in address"},
+	} {
 		if host, port, err := SplitHostPort(tt.hostPort); err == nil {
 			t.Errorf("SplitHostPort(%q) should have failed", tt.hostPort)
 		} else {
@@ -538,9 +555,43 @@ func TestSplitHostPort(t *testing.T) {
 }
 
 func TestJoinHostPort(t *testing.T) {
-	for _, tt := range splitJoinTests {
-		if join := JoinHostPort(tt.host, tt.port); join != tt.join {
-			t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.host, tt.port, join, tt.join)
+	for _, tt := range []struct {
+		host     string
+		port     string
+		hostPort string
+	}{
+		// Host name
+		{"localhost", "http", "localhost:http"},
+		{"localhost", "80", "localhost:80"},
+
+		// Go-specific host name with zone identifier
+		{"localhost%lo0", "http", "localhost%lo0:http"},
+		{"localhost%lo0", "80", "localhost%lo0:80"},
+
+		// IP literal
+		{"127.0.0.1", "http", "127.0.0.1:http"},
+		{"127.0.0.1", "80", "127.0.0.1:80"},
+		{"::1", "http", "[::1]:http"},
+		{"::1", "80", "[::1]:80"},
+
+		// IP literal with zone identifier
+		{"::1%lo0", "http", "[::1%lo0]:http"},
+		{"::1%lo0", "80", "[::1%lo0]:80"},
+
+		// Go-specific wildcard for host name
+		{"", "http", ":http"}, // Go 1 behavior
+		{"", "80", ":80"},     // Go 1 behavior
+
+		// Go-specific wildcard for service name or transport port number
+		{"golang.org", "", "golang.org:"}, // Go 1 behavior
+		{"127.0.0.1", "", "127.0.0.1:"},   // Go 1 behavior
+		{"::1", "", "[::1]:"},             // Go 1 behavior
+
+		// Opaque service name
+		{"golang.org", "https%foo", "golang.org:https%foo"}, // Go 1 behavior
+	} {
+		if hostPort := JoinHostPort(tt.host, tt.port); hostPort != tt.hostPort {
+			t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.host, tt.port, hostPort, tt.hostPort)
 		}
 	}
 }
@@ -645,3 +696,32 @@ func TestIPAddrScope(t *testing.T) {
 		}
 	}
 }
+
+func BenchmarkIPEqual(b *testing.B) {
+	b.Run("IPv4", func(b *testing.B) {
+		benchmarkIPEqual(b, IPv4len)
+	})
+	b.Run("IPv6", func(b *testing.B) {
+		benchmarkIPEqual(b, IPv6len)
+	})
+}
+
+func benchmarkIPEqual(b *testing.B, size int) {
+	ips := make([]IP, 1000)
+	for i := range ips {
+		ips[i] = make(IP, size)
+		rand.Read(ips[i])
+	}
+	// Half of the N are equal.
+	for i := 0; i < b.N/2; i++ {
+		x := ips[i%len(ips)]
+		y := ips[i%len(ips)]
+		x.Equal(y)
+	}
+	// The other half are not equal.
+	for i := 0; i < b.N/2; i++ {
+		x := ips[i%len(ips)]
+		y := ips[(i+1)%len(ips)]
+		x.Equal(y)
+	}
+}
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index d994fc6..408d63f 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -71,7 +71,7 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
 	if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
 		net = "ip"
 	}
-	afnet, _, err := parseNetwork(context.Background(), net)
+	afnet, _, err := parseNetwork(context.Background(), net, false)
 	if err != nil {
 		return nil, err
 	}
@@ -93,6 +93,15 @@ type IPConn struct {
 	conn
 }
 
+// SyscallConn returns a raw network connection.
+// This implements the syscall.Conn interface.
+func (c *IPConn) SyscallConn() (syscall.RawConn, error) {
+	if !c.ok() {
+		return nil, syscall.EINVAL
+	}
+	return newRawConn(c.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.
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 8f4b702..64c6016 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -16,7 +16,7 @@ func sockaddrToIP(sa syscall.Sockaddr) Addr {
 	case *syscall.SockaddrInet4:
 		return &IPAddr{IP: sa.Addr[0:]}
 	case *syscall.SockaddrInet6:
-		return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
+		return &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return nil
 }
@@ -52,7 +52,7 @@ func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
 		addr = &IPAddr{IP: sa.Addr[0:]}
 		n = stripIPv4Header(n, b)
 	case *syscall.SockaddrInet6:
-		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
+		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return n, addr, err
 }
@@ -79,7 +79,7 @@ func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err e
 	case *syscall.SockaddrInet4:
 		addr = &IPAddr{IP: sa.Addr[0:]}
 	case *syscall.SockaddrInet6:
-		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
+		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return
 }
@@ -113,7 +113,7 @@ func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error)
 }
 
 func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
-	network, proto, err := parseNetwork(ctx, netProto)
+	network, proto, err := parseNetwork(ctx, netProto, true)
 	if err != nil {
 		return nil, err
 	}
@@ -133,7 +133,7 @@ func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn
 }
 
 func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
-	network, proto, err := parseNetwork(ctx, netProto)
+	network, proto, err := parseNetwork(ctx, netProto, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/net/iprawsock_test.go b/src/net/iprawsock_test.go
index 5d33b26..8972051 100644
--- a/src/net/iprawsock_test.go
+++ b/src/net/iprawsock_test.go
@@ -117,3 +117,75 @@ func TestIPConnRemoteName(t *testing.T) {
 		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
 	}
 }
+
+func TestDialListenIPArgs(t *testing.T) {
+	type test struct {
+		argLists   [][2]string
+		shouldFail bool
+	}
+	tests := []test{
+		{
+			argLists: [][2]string{
+				{"ip", "127.0.0.1"},
+				{"ip:", "127.0.0.1"},
+				{"ip::", "127.0.0.1"},
+				{"ip", "::1"},
+				{"ip:", "::1"},
+				{"ip::", "::1"},
+				{"ip4", "127.0.0.1"},
+				{"ip4:", "127.0.0.1"},
+				{"ip4::", "127.0.0.1"},
+				{"ip6", "::1"},
+				{"ip6:", "::1"},
+				{"ip6::", "::1"},
+			},
+			shouldFail: true,
+		},
+	}
+	if testableNetwork("ip") {
+		priv := test{shouldFail: false}
+		for _, tt := range []struct {
+			network, address string
+			args             [2]string
+		}{
+			{"ip4:47", "127.0.0.1", [2]string{"ip4:47", "127.0.0.1"}},
+			{"ip6:47", "::1", [2]string{"ip6:47", "::1"}},
+		} {
+			c, err := ListenPacket(tt.network, tt.address)
+			if err != nil {
+				continue
+			}
+			c.Close()
+			priv.argLists = append(priv.argLists, tt.args)
+		}
+		if len(priv.argLists) > 0 {
+			tests = append(tests, priv)
+		}
+	}
+
+	for _, tt := range tests {
+		for _, args := range tt.argLists {
+			_, err := Dial(args[0], args[1])
+			if tt.shouldFail != (err != nil) {
+				t.Errorf("Dial(%q, %q) = %v; want (err != nil) is %t", args[0], args[1], err, tt.shouldFail)
+			}
+			_, err = ListenPacket(args[0], args[1])
+			if tt.shouldFail != (err != nil) {
+				t.Errorf("ListenPacket(%q, %q) = %v; want (err != nil) is %t", args[0], args[1], err, tt.shouldFail)
+			}
+			a, err := ResolveIPAddr("ip", args[1])
+			if err != nil {
+				t.Errorf("ResolveIPAddr(\"ip\", %q) = %v", args[1], err)
+				continue
+			}
+			_, err = DialIP(args[0], nil, a)
+			if tt.shouldFail != (err != nil) {
+				t.Errorf("DialIP(%q, %v) = %v; want (err != nil) is %t", args[0], a, err, tt.shouldFail)
+			}
+			_, err = ListenIP(args[0], a)
+			if tt.shouldFail != (err != nil) {
+				t.Errorf("ListenIP(%q, %v) = %v; want (err != nil) is %t", args[0], a, err, tt.shouldFail)
+			}
+		}
+	}
+}
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index f1394a7..6049692 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Internet protocol family sockets
-
 package net
 
 import (
 	"context"
+	"sync"
 )
 
 // BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
@@ -17,20 +16,36 @@ import (
 // both address families are to be supported.
 // See inet6(4) for details.
 
-var (
-	// supportsIPv4 reports whether the platform supports IPv4
-	// networking functionality.
-	supportsIPv4 bool
+type ipStackCapabilities struct {
+	sync.Once             // guards following
+	ipv4Enabled           bool
+	ipv6Enabled           bool
+	ipv4MappedIPv6Enabled bool
+}
 
-	// supportsIPv6 reports whether the platform supports IPv6
-	// networking functionality.
-	supportsIPv6 bool
+var ipStackCaps ipStackCapabilities
 
-	// 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.
-	supportsIPv4map bool
-)
+// supportsIPv4 reports whether the platform supports IPv4 networking
+// functionality.
+func supportsIPv4() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv4Enabled
+}
+
+// supportsIPv6 reports whether the platform supports IPv6 networking
+// functionality.
+func supportsIPv6() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv6Enabled
+}
+
+// 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.
+func supportsIPv4map() bool {
+	ipStackCaps.Once.Do(ipStackCaps.probe)
+	return ipStackCaps.ipv4MappedIPv6Enabled
+}
 
 // An addrList represents a list of network endpoint addresses.
 type addrList []Addr
@@ -107,10 +122,11 @@ 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
-// must be enclosed in square brackets, as in "[::1]:80",
-// "[ipv6-host]:http" or "[ipv6-host%zone]:80".
+// "host%zone:port", "[host]:port" or "[host%zone]:port" into host or
+// host%zone and port.
+//
+// A literal IPv6 address in hostport must be enclosed in square
+// brackets, as in "[::1]:80", "[::1%lo0]:80".
 func SplitHostPort(hostport string) (host, port string, err error) {
 	const (
 		missingPort   = "missing port in address"
@@ -154,9 +170,6 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 		if byteIndex(host, ':') >= 0 {
 			return addrErr(hostport, tooManyColons)
 		}
-		if byteIndex(host, '%') >= 0 {
-			return addrErr(hostport, "missing brackets in address")
-		}
 	}
 	if byteIndex(hostport[j:], '[') >= 0 {
 		return addrErr(hostport, "unexpected '[' in address")
@@ -181,11 +194,12 @@ func splitHostZone(s string) (host, zone string) {
 }
 
 // JoinHostPort combines host and port into a network address of the
-// form "host:port" or, if host contains a colon or a percent sign,
-// "[host]:port".
+// form "host:port" or "host%zone:port", if host is a literal IPv6
+// address, "[host]:port" or [host%zone]:port.
 func JoinHostPort(host, port string) string {
-	// If host has colons or a percent sign, have to bracket it.
-	if byteIndex(host, ':') >= 0 || byteIndex(host, '%') >= 0 {
+	// We assume that host is a literal IPv6 address if host has
+	// colons.
+	if byteIndex(host, ':') >= 0 {
 		return "[" + host + "]:" + port
 	}
 	return host + ":" + port
@@ -240,6 +254,13 @@ func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addr
 		ips = []IPAddr{{IP: ip}}
 	} else if ip, zone := parseIPv6(host, true); ip != nil {
 		ips = []IPAddr{{IP: ip, Zone: zone}}
+		// Issue 18806: if the machine has halfway configured
+		// IPv6 such that it can bind on "::" (IPv6unspecified)
+		// but not connect back to that same address, fall
+		// back to dialing 0.0.0.0.
+		if ip.Equal(IPv6unspecified) {
+			ips = append(ips, IPAddr{IP: IPv4zero})
+		}
 	} else {
 		// Try as a DNS name.
 		ips, err = r.LookupIPAddr(ctx, host)
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index b7fd344..312e4ad 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.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.
 
-// Internet protocol family sockets for Plan 9
-
 package net
 
 import (
@@ -12,12 +10,25 @@ import (
 	"syscall"
 )
 
+// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
+// capabilities.
+//
+// Plan 9 uses IPv6 natively, see ip(3).
+func (p *ipStackCapabilities) probe() {
+	p.ipv4Enabled = probe(netdir+"/iproute", "4i")
+	p.ipv6Enabled = probe(netdir+"/iproute", "6i")
+	if p.ipv4Enabled && p.ipv6Enabled {
+		p.ipv4MappedIPv6Enabled = true
+	}
+}
+
 func probe(filename, query string) bool {
 	var file *file
 	var err error
 	if file, err = open(filename); err != nil {
 		return false
 	}
+	defer file.close()
 
 	r := false
 	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
@@ -32,27 +43,9 @@ func probe(filename, query string) bool {
 			}
 		}
 	}
-	file.close()
 	return r
 }
 
-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
-// second boolean value is true, kernel supports IPv6 IPv4-mapping.
-func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
-	// Plan 9 uses IPv6 natively, see ip(3).
-	r := probe(netdir+"/iproute", "6i")
-	v := false
-	if r {
-		v = probe(netdir+"/iproute", "4i")
-	}
-	return r, v
-}
-
 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
 	addr := IPv4zero // address contains port only
@@ -249,10 +242,10 @@ func (fd *netFD) netFD() (*netFD, error) {
 
 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
 	defer func() { fixErr(err) }()
-	if err := fd.readLock(); err != nil {
+	if err := fd.pfd.ReadLock(); err != nil {
 		return nil, err
 	}
-	defer fd.readUnlock()
+	defer fd.pfd.ReadUnlock()
 	listen, err := os.Open(fd.dir + "/listen")
 	if err != nil {
 		return nil, err
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index ff280c3..d659bf0 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -8,35 +8,29 @@ package net
 
 import (
 	"context"
+	"internal/poll"
 	"runtime"
 	"syscall"
 )
 
-func probeIPv4Stack() bool {
+// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
+// capabilities which are controlled by the IPV6_V6ONLY socket option
+// and kernel configuration.
+//
+// Should we try to use the IPv4 socket interface if we're only
+// dealing with IPv4 sockets? As long as the host system understands
+// IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to
+// the IPv6 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.
+func (p *ipStackCapabilities) probe() {
 	s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 	switch err {
 	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
-		return false
 	case nil:
-		closeFunc(s)
+		poll.CloseFunc(s)
+		p.ipv4Enabled = true
 	}
-	return true
-}
-
-// 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.
-// Unfortunately, we need to run on kernels built without IPv6
-// 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
-// boolean value is true, kernel supports IPv6 IPv4-mapping.
-func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
 		laddr TCPAddr
 		value int
@@ -46,29 +40,19 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		// IPv4-mapped IPv6 address communication capability
 		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
-	var supps [2]bool
 	switch runtime.GOOS {
 	case "dragonfly", "openbsd":
-		// Some released versions of DragonFly BSD pretend to
-		// accept IPV6_V6ONLY=0 successfully, but the state
-		// still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
-		// stops pretending, but the transition period would
-		// cause unpredictable behavior and we need to avoid
-		// it.
-		//
-		// OpenBSD also doesn't support IPV6_V6ONLY=0 but it
-		// never pretends to accept IPV6_V6OLY=0. It always
-		// returns an error and we don't need to probe the
-		// capability.
+		// The latest DragonFly BSD and OpenBSD kernels don't
+		// support IPV6_V6ONLY=0. They always return an error
+		// and we don't need to probe the capability.
 		probes = probes[:1]
 	}
-
 	for i := range probes {
 		s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 		if err != nil {
 			continue
 		}
-		defer closeFunc(s)
+		defer poll.CloseFunc(s)
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
 		sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
 		if err != nil {
@@ -77,51 +61,55 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		if err := syscall.Bind(s, sa); err != nil {
 			continue
 		}
-		supps[i] = true
+		if i == 0 {
+			p.ipv6Enabled = true
+		} else {
+			p.ipv4MappedIPv6Enabled = true
+		}
 	}
-
-	return supps[0], supps[1]
 }
 
-// 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"
-// 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:
+// favoriteAddrFamily returns the appropriate address family for the
+// given network, laddr, raddr and mode.
+//
+// If mode indicates "listen" and laddr is a wildcard, we assume that
+// the user wants to make a passive-open connection with a wildcard
+// address family, both AF_INET and AF_INET6, and a wildcard address
+// like the following:
 //
-//	1. A wild-wild listen, "tcp" + ""
-//	If the platform supports both IPv6 and IPv6 IPv4-mapping
-//	capabilities, or does not support IPv4, we assume that
-//	the user wants to listen on both IPv4 and IPv6 wildcard
-//	addresses over an AF_INET6 socket with IPV6_V6ONLY=0.
-//	Otherwise we prefer an IPv4 wildcard address listen over
-//	an AF_INET socket.
+//	- A listen for a wildcard communication domain, "tcp" or
+//	  "udp", with a wildcard address: If the platform supports
+//	  both IPv6 and IPv4-mapped IPv6 communication capabilities,
+//	  or does not support IPv4, we use a dual stack, AF_INET6 and
+//	  IPV6_V6ONLY=0, wildcard address listen. The dual stack
+//	  wildcard address listen may fall back to an IPv6-only,
+//	  AF_INET6 and IPV6_V6ONLY=1, wildcard address listen.
+//	  Otherwise we prefer an IPv4-only, AF_INET, wildcard address
+//	  listen.
 //
-//	2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
-//	Same as 1.
+//	- A listen for a wildcard communication domain, "tcp" or
+//	  "udp", with an IPv4 wildcard address: same as above.
 //
-//	3. A wild-ipv6wild listen, "tcp" + "[::]"
-//	Almost same as 1 but we prefer an IPv6 wildcard address
-//	listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
-//	the platform supports IPv6 capability but not IPv6 IPv4-
-//	mapping capability.
+//	- A listen for a wildcard communication domain, "tcp" or
+//	  "udp", with an IPv6 wildcard address: same as above.
 //
-//	4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
-//	We use an IPv4 (AF_INET) wildcard address listen.
+//	- A listen for an IPv4 communication domain, "tcp4" or "udp4",
+//	  with an IPv4 wildcard address: We use an IPv4-only, AF_INET,
+//	  wildcard address listen.
 //
-//	5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
-//	We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
-//	listen.
+//	- A listen for an IPv6 communication domain, "tcp6" or "udp6",
+//	  with an IPv6 wildcard address: We use an IPv6-only, AF_INET6
+//	  and IPV6_V6ONLY=1, wildcard address listen.
 //
-// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
-// or else returns AF_INET6.  It also returns a boolean value what
+// Otherwise guess: If the addresses are IPv4 then returns AF_INET,
+// or else returns AF_INET6. It also returns a boolean value what
 // designates IPV6_V6ONLY option.
 //
-// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
-// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
-func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
-	switch net[len(net)-1] {
+// Note that the latest DragonFly BSD and OpenBSD kernels allow
+// neither "net.inet6.ip6.v6only=1" change nor IPPROTO_IPV6 level
+// IPV6_V6ONLY socket option setting.
+func favoriteAddrFamily(network string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
+	switch network[len(network)-1] {
 	case '4':
 		return syscall.AF_INET, false
 	case '6':
@@ -129,7 +117,7 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
 	}
 
 	if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
-		if supportsIPv4map || !supportsIPv4 {
+		if supportsIPv4map() || !supportsIPv4() {
 			return syscall.AF_INET6, false
 		}
 		if laddr == nil {
@@ -145,7 +133,6 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
 	return syscall.AF_INET6, false
 }
 
-// Internet sockets (TCP, UDP, IP)
 func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string) (fd *netFD, err error) {
 	if (runtime.GOOS == "windows" || runtime.GOOS == "openbsd" || runtime.GOOS == "nacl") && mode == "dial" && raddr.isWildcard() {
 		raddr = raddr.toLocal(net)
@@ -187,7 +174,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 		if ip6 == nil {
 			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
 		}
-		sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneToInt(zone))}
+		sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
 		copy(sa.Addr[:], ip6)
 		return sa, nil
 	}
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index 1d0f00f..aede354 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -215,7 +215,7 @@ var addrListTests = []struct {
 }
 
 func TestAddrList(t *testing.T) {
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
index 6037f36..21ad446 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -225,7 +225,7 @@ func TestDualStackTCPListener(t *testing.T) {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -235,7 +235,7 @@ func TestDualStackTCPListener(t *testing.T) {
 			continue
 		}
 
-		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
+		if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) {
 			tt.xerr = nil
 		}
 		var firstErr, secondErr error
@@ -315,7 +315,7 @@ func TestDualStackUDPListener(t *testing.T) {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	if !supportsIPv4 || !supportsIPv6 {
+	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -325,7 +325,7 @@ func TestDualStackUDPListener(t *testing.T) {
 			continue
 		}
 
-		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
+		if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) {
 			tt.xerr = nil
 		}
 		var firstErr, secondErr error
@@ -454,7 +454,7 @@ func checkDualStackAddrFamily(fd *netFD) error {
 		// and IPv6 IPv4-mapping capability, we can assume
 		// that the node listens on a wildcard address with an
 		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+		if supportsIPv4map() && fd.laddr.(*TCPAddr).isWildcard() {
 			if fd.family != syscall.AF_INET6 {
 				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
 			}
@@ -468,7 +468,7 @@ func checkDualStackAddrFamily(fd *netFD) error {
 		// and IPv6 IPv4-mapping capability, we can assume
 		// that the node listens on a wildcard address with an
 		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+		if supportsIPv4map() && fd.laddr.(*UDPAddr).isWildcard() {
 			if fd.family != syscall.AF_INET6 {
 				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
 			}
@@ -535,7 +535,7 @@ func TestIPv4MulticastListener(t *testing.T) {
 	case "solaris":
 		t.Skipf("not supported on solaris, see golang.org/issue/7399")
 	}
-	if !supportsIPv4 {
+	if !supportsIPv4() {
 		t.Skip("IPv4 is not supported")
 	}
 
@@ -610,7 +610,7 @@ func TestIPv6MulticastListener(t *testing.T) {
 	case "solaris":
 		t.Skipf("not supported on solaris, see issue 7399")
 	}
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		t.Skip("IPv6 is not supported")
 	}
 	if os.Getuid() != 0 {
diff --git a/src/net/lookup.go b/src/net/lookup.go
index cc2013e..abc56de 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -97,6 +97,27 @@ type Resolver struct {
 	// GODEBUG=netdns=go, but scoped to just this resolver.
 	PreferGo bool
 
+	// StrictErrors controls the behavior of temporary errors
+	// (including timeout, socket errors, and SERVFAIL) when using
+	// Go's built-in resolver. For a query composed of multiple
+	// sub-queries (such as an A+AAAA address lookup, or walking the
+	// DNS search list), this option causes such errors to abort the
+	// whole query instead of returning a partial result. This is
+	// not enabled by default because it may affect compatibility
+	// with resolvers that process AAAA queries incorrectly.
+	StrictErrors bool
+
+	// Dial optionally specifies an alternate dialer for use by
+	// Go's built-in DNS resolver to make TCP and UDP connections
+	// to DNS services. The provided addr will always be an IP
+	// address and not a hostname.
+	// If the Conn returned is also a PacketConn, sent and received DNS
+	// messages must adhere to section 4.2.1. "UDP usage" of RFC 1035.
+	// Otherwise, DNS messages transmitted over Conn must adhere to section
+	// 4.2.2. "TCP usage".
+	// If nil, the default dialer is used.
+	Dial func(ctx context.Context, network, addr string) (Conn, error)
+
 	// TODO(bradfitz): optional interface impl override hook
 	// TODO(bradfitz): Timeout time.Duration?
 }
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 36db56a..68a7abe 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -63,7 +63,7 @@ func TestLookupGoogleSRV(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -99,7 +99,7 @@ func TestLookupGmailMX(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -131,7 +131,7 @@ func TestLookupGmailNS(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -164,7 +164,7 @@ func TestLookupGmailTXT(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -199,7 +199,7 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+	if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
@@ -220,7 +220,7 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
 }
 
 func TestLookupIPv6LinkLocalAddr(t *testing.T) {
-	if !supportsIPv6 || !*testIPv6 {
+	if !supportsIPv6() || !*testIPv6 {
 		t.Skip("IPv6 is required")
 	}
 
@@ -256,7 +256,7 @@ func TestLookupCNAME(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -283,7 +283,7 @@ func TestLookupGoogleHost(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -315,7 +315,7 @@ func TestLookupGoogleIP(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -450,7 +450,7 @@ func TestDNSFlood(t *testing.T) {
 }
 
 func TestLookupDotsWithLocalSource(t *testing.T) {
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
@@ -499,7 +499,7 @@ func TestLookupDotsWithRemoteSource(t *testing.T) {
 		testenv.MustHaveExternalNetwork(t)
 	}
 
-	if !supportsIPv4 || !*testIPv4 {
+	if !supportsIPv4() || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
 
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index be2ced9..8968363 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -16,28 +16,31 @@ var onceReadProtocols sync.Once
 // readProtocols loads contents of /etc/protocols into protocols map
 // for quick access.
 func readProtocols() {
-	if file, err := open("/etc/protocols"); err == nil {
-		for line, ok := file.readLine(); ok; line, ok = file.readLine() {
-			// tcp    6   TCP    # transmission control protocol
-			if i := byteIndex(line, '#'); i >= 0 {
-				line = line[0:i]
-			}
-			f := getFields(line)
-			if len(f) < 2 {
-				continue
+	file, err := open("/etc/protocols")
+	if err != nil {
+		return
+	}
+	defer file.close()
+
+	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+		// tcp    6   TCP    # transmission control protocol
+		if i := byteIndex(line, '#'); i >= 0 {
+			line = line[0:i]
+		}
+		f := getFields(line)
+		if len(f) < 2 {
+			continue
+		}
+		if proto, _, ok := dtoi(f[1]); ok {
+			if _, ok := protocols[f[0]]; !ok {
+				protocols[f[0]] = proto
 			}
-			if proto, _, ok := dtoi(f[1]); ok {
-				if _, ok := protocols[f[0]]; !ok {
-					protocols[f[0]] = proto
-				}
-				for _, alias := range f[2:] {
-					if _, ok := protocols[alias]; !ok {
-						protocols[alias] = proto
-					}
+			for _, alias := range f[2:] {
+				if _, ok := protocols[alias]; !ok {
+					protocols[alias] = proto
 				}
 			}
 		}
-		file.close()
 	}
 }
 
@@ -48,6 +51,29 @@ func lookupProtocol(_ context.Context, name string) (int, error) {
 	return lookupProtocolMap(name)
 }
 
+func (r *Resolver) dial(ctx context.Context, network, server string) (dnsConn, error) {
+	// Calling Dial here is scary -- we have to be sure not to
+	// dial a name that will require a DNS lookup, or Dial will
+	// call back here to translate it. The DNS config parser has
+	// already checked that all the cfg.servers are IP
+	// addresses, which Dial will use without a DNS lookup.
+	var c Conn
+	var err error
+	if r.Dial != nil {
+		c, err = r.Dial(ctx, network, server)
+	} else {
+		var d Dialer
+		c, err = d.DialContext(ctx, network, server)
+	}
+	if err != nil {
+		return nil, mapErr(err)
+	}
+	if _, ok := c.(PacketConn); ok {
+		return &dnsPacketConn{c}, nil
+	}
+	return &dnsStreamConn{c}, nil
+}
+
 func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
 	order := systemConf().hostLookupOrder(host)
 	if !r.PreferGo && order == hostLookupCgo {
@@ -57,12 +83,12 @@ func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string,
 		// cgo not available (or netgo); fall back to Go's DNS resolver
 		order = hostLookupFilesDNS
 	}
-	return goLookupHostOrder(ctx, host, order)
+	return r.goLookupHostOrder(ctx, host, order)
 }
 
 func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
 	if r.PreferGo {
-		return goLookupIP(ctx, host)
+		return r.goLookupIP(ctx, host)
 	}
 	order := systemConf().hostLookupOrder(host)
 	if order == hostLookupCgo {
@@ -72,7 +98,7 @@ func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, e
 		// cgo not available (or netgo); fall back to Go's DNS resolver
 		order = hostLookupFilesDNS
 	}
-	addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order)
+	addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order)
 	return
 }
 
@@ -98,17 +124,17 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error)
 			return cname, err
 		}
 	}
-	return goLookupCNAME(ctx, name)
+	return r.goLookupCNAME(ctx, name)
 }
 
-func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+func (r *Resolver) 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(ctx, target, dnsTypeSRV)
+	cname, rrs, err := r.lookup(ctx, target, dnsTypeSRV)
 	if err != nil {
 		return "", nil, err
 	}
@@ -121,8 +147,8 @@ func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (st
 	return cname, srvs, nil
 }
 
-func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
-	_, rrs, err := lookup(ctx, name, dnsTypeMX)
+func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
+	_, rrs, err := r.lookup(ctx, name, dnsTypeMX)
 	if err != nil {
 		return nil, err
 	}
@@ -135,8 +161,8 @@ func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
 	return mxs, nil
 }
 
-func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
-	_, rrs, err := lookup(ctx, name, dnsTypeNS)
+func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
+	_, rrs, err := r.lookup(ctx, name, dnsTypeNS)
 	if err != nil {
 		return nil, err
 	}
@@ -148,7 +174,7 @@ func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
 }
 
 func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
-	_, rrs, err := lookup(ctx, name, dnsTypeTXT)
+	_, rrs, err := r.lookup(ctx, name, dnsTypeTXT)
 	if err != nil {
 		return nil, err
 	}
@@ -165,5 +191,5 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error
 			return ptrs, err
 		}
 	}
-	return goLookupPTR(ctx, addr)
+	return r.goLookupPTR(ctx, addr)
 }
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 5808293..0036d89 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -107,7 +107,7 @@ func (r *Resolver) lookupIP(ctx context.Context, name string) ([]IPAddr, error)
 				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))
+				zone := zoneCache.name(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}}
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 702b765..765abe2 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -387,13 +387,15 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 	debug.Printf("consumePhrase: [%s]", p.s)
 	// phrase = 1*word
 	var words []string
+	var isPrevEncoded bool
 	for {
 		// word = atom / quoted-string
 		var word string
 		p.skipSpace()
 		if p.empty() {
-			return "", errors.New("mail: missing phrase")
+			break
 		}
+		isEncoded := false
 		if p.peek() == '"' {
 			// quoted-string
 			word, err = p.consumeQuotedString()
@@ -403,7 +405,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			// than what RFC 5322 specifies.
 			word, err = p.consumeAtom(true, true)
 			if err == nil {
-				word, err = p.decodeRFC2047Word(word)
+				word, isEncoded, err = p.decodeRFC2047Word(word)
 			}
 		}
 
@@ -411,7 +413,12 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			break
 		}
 		debug.Printf("consumePhrase: consumed %q", word)
-		words = append(words, word)
+		if isPrevEncoded && isEncoded {
+			words[len(words)-1] += word
+		} else {
+			words = append(words, word)
+		}
+		isPrevEncoded = isEncoded
 	}
 	// Ignore any error if we got at least one word.
 	if err != nil && len(words) == 0 {
@@ -540,22 +547,23 @@ func (p *addrParser) len() int {
 	return len(p.s)
 }
 
-func (p *addrParser) decodeRFC2047Word(s string) (string, error) {
+func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) {
 	if p.dec != nil {
-		return p.dec.DecodeHeader(s)
+		word, err = p.dec.Decode(s)
+	} else {
+		word, err = rfc2047Decoder.Decode(s)
 	}
 
-	dec, err := rfc2047Decoder.Decode(s)
 	if err == nil {
-		return dec, nil
+		return word, true, nil
 	}
 
 	if _, ok := err.(charsetError); ok {
-		return s, err
+		return s, true, err
 	}
 
 	// Ignore invalid RFC 2047 encoded-word errors.
-	return s, nil
+	return s, false, nil
 }
 
 var rfc2047Decoder = mime.WordDecoder{
diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
index f0761ab..2106a0b 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -136,6 +136,7 @@ func TestAddressParsingError(t *testing.T) {
 		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"},
+		7: {"John Doe", "no angle-addr"},
 	}
 
 	for i, tc := range mustErrTestCases {
@@ -235,6 +236,16 @@ func TestAddressParsing(t *testing.T) {
 				},
 			},
 		},
+		// RFC 2047 "Q"-encoded UTF-8 address with multiple encoded-words.
+		{
+			`=?utf-8?q?J=C3=B6rg?=  =?utf-8?q?Doe?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `JörgDoe`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
 		// RFC 2047, Section 8.
 		{
 			`=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD at vm1.ulg.ac.be>`,
diff --git a/src/net/main_cloexec_test.go b/src/net/main_cloexec_test.go
index 7903819..fa1ed02 100644
--- a/src/net/main_cloexec_test.go
+++ b/src/net/main_cloexec_test.go
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd linux
+// +build dragonfly freebsd linux
 
 package net
 
+import "internal/poll"
+
 func init() {
 	extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook)
 	extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook)
@@ -13,13 +15,13 @@ func init() {
 
 var (
 	// Placeholders for saving original socket system calls.
-	origAccept4 = accept4Func
+	origAccept4 = poll.Accept4Func
 )
 
 func installAccept4TestHook() {
-	accept4Func = sw.Accept4
+	poll.Accept4Func = sw.Accept4
 }
 
 func uninstallAccept4TestHook() {
-	accept4Func = origAccept4
+	poll.Accept4Func = origAccept4
 }
diff --git a/src/net/main_test.go b/src/net/main_test.go
index 28a8ff6..bbf32cf 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -70,7 +70,7 @@ var (
 )
 
 func setupTestData() {
-	if supportsIPv4 {
+	if supportsIPv4() {
 		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
 			{"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
 			{"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
@@ -85,7 +85,7 @@ func setupTestData() {
 		}...)
 	}
 
-	if supportsIPv6 {
+	if supportsIPv6() {
 		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil})
 		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil})
 		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
@@ -95,15 +95,15 @@ func setupTestData() {
 	if ifi != nil {
 		index := fmt.Sprintf("%v", ifi.Index)
 		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
-			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
+			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
 			{"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
 		}...)
 		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
-			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
+			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
 			{"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
 		}...)
 		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
-			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
+			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneCache.name(ifi.Index)}, nil},
 			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
 		}...)
 	}
diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go
index 0cc129f..9cfbc8e 100644
--- a/src/net/main_unix_test.go
+++ b/src/net/main_unix_test.go
@@ -6,13 +6,15 @@
 
 package net
 
+import "internal/poll"
+
 var (
 	// Placeholders for saving original socket system calls.
 	origSocket        = socketFunc
-	origClose         = closeFunc
+	origClose         = poll.CloseFunc
 	origConnect       = connectFunc
 	origListen        = listenFunc
-	origAccept        = acceptFunc
+	origAccept        = poll.AcceptFunc
 	origGetsockoptInt = getsockoptIntFunc
 
 	extraTestHookInstallers   []func()
@@ -21,10 +23,10 @@ var (
 
 func installTestHooks() {
 	socketFunc = sw.Socket
-	closeFunc = sw.Close
+	poll.CloseFunc = sw.Close
 	connectFunc = sw.Connect
 	listenFunc = sw.Listen
-	acceptFunc = sw.Accept
+	poll.AcceptFunc = sw.Accept
 	getsockoptIntFunc = sw.GetsockoptInt
 
 	for _, fn := range extraTestHookInstallers {
@@ -34,10 +36,10 @@ func installTestHooks() {
 
 func uninstallTestHooks() {
 	socketFunc = origSocket
-	closeFunc = origClose
+	poll.CloseFunc = origClose
 	connectFunc = origConnect
 	listenFunc = origListen
-	acceptFunc = origAccept
+	poll.AcceptFunc = origAccept
 	getsockoptIntFunc = origGetsockoptInt
 
 	for _, fn := range extraTestHookUninstallers {
@@ -48,6 +50,6 @@ func uninstallTestHooks() {
 // forceCloseSockets must be called only from TestMain.
 func forceCloseSockets() {
 	for s := range sw.Sockets() {
-		closeFunc(s)
+		poll.CloseFunc(s)
 	}
 }
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
index 6ea318c..f38a3a0 100644
--- a/src/net/main_windows_test.go
+++ b/src/net/main_windows_test.go
@@ -4,37 +4,39 @@
 
 package net
 
+import "internal/poll"
+
 var (
 	// Placeholders for saving original socket system calls.
 	origSocket      = socketFunc
-	origClosesocket = closeFunc
+	origClosesocket = poll.CloseFunc
 	origConnect     = connectFunc
-	origConnectEx   = connectExFunc
+	origConnectEx   = poll.ConnectExFunc
 	origListen      = listenFunc
-	origAccept      = acceptFunc
+	origAccept      = poll.AcceptFunc
 )
 
 func installTestHooks() {
 	socketFunc = sw.Socket
-	closeFunc = sw.Closesocket
+	poll.CloseFunc = sw.Closesocket
 	connectFunc = sw.Connect
-	connectExFunc = sw.ConnectEx
+	poll.ConnectExFunc = sw.ConnectEx
 	listenFunc = sw.Listen
-	acceptFunc = sw.AcceptEx
+	poll.AcceptFunc = sw.AcceptEx
 }
 
 func uninstallTestHooks() {
 	socketFunc = origSocket
-	closeFunc = origClosesocket
+	poll.CloseFunc = origClosesocket
 	connectFunc = origConnect
-	connectExFunc = origConnectEx
+	poll.ConnectExFunc = origConnectEx
 	listenFunc = origListen
-	acceptFunc = origAccept
+	poll.AcceptFunc = origAccept
 }
 
 // forceCloseSockets must be called only from TestMain.
 func forceCloseSockets() {
 	for s := range sw.Sockets() {
-		closeFunc(s)
+		poll.CloseFunc(s)
 	}
 }
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index 766de6a..44581d9 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -31,20 +31,20 @@ func testUnixAddr() string {
 func newLocalListener(network string) (Listener, error) {
 	switch network {
 	case "tcp":
-		if supportsIPv4 {
+		if supportsIPv4() {
 			if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil {
 				return ln, nil
 			}
 		}
-		if supportsIPv6 {
+		if supportsIPv6() {
 			return Listen("tcp6", "[::1]:0")
 		}
 	case "tcp4":
-		if supportsIPv4 {
+		if supportsIPv4() {
 			return Listen("tcp4", "127.0.0.1:0")
 		}
 	case "tcp6":
-		if supportsIPv6 {
+		if supportsIPv6() {
 			return Listen("tcp6", "[::1]:0")
 		}
 	case "unix", "unixpacket":
@@ -333,18 +333,18 @@ func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
 func newLocalPacketListener(network string) (PacketConn, error) {
 	switch network {
 	case "udp":
-		if supportsIPv4 {
+		if supportsIPv4() {
 			return ListenPacket("udp4", "127.0.0.1:0")
 		}
-		if supportsIPv6 {
+		if supportsIPv6() {
 			return ListenPacket("udp6", "[::1]:0")
 		}
 	case "udp4":
-		if supportsIPv4 {
+		if supportsIPv4() {
 			return ListenPacket("udp4", "127.0.0.1:0")
 		}
 	case "udp6":
-		if supportsIPv6 {
+		if supportsIPv6() {
 			return ListenPacket("udp6", "[::1]:0")
 		}
 	case "unixgram":
diff --git a/src/net/net.go b/src/net/net.go
index a8b5736..91ec048 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -81,6 +81,7 @@ package net
 import (
 	"context"
 	"errors"
+	"internal/poll"
 	"io"
 	"os"
 	"syscall"
@@ -95,12 +96,6 @@ var (
 	netCgo bool // set true in conf_netcgo.go for build tag "netcgo"
 )
 
-func init() {
-	sysInit()
-	supportsIPv4 = probeIPv4Stack()
-	supportsIPv6, supportsIPv4map = probeIPv6Stack()
-}
-
 // Addr represents a network end point address.
 //
 // The two methods Network and String conventionally return strings
@@ -234,7 +229,7 @@ func (c *conn) SetDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setDeadline(t); err != nil {
+	if err := c.fd.pfd.SetDeadline(t); err != nil {
 		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
@@ -245,7 +240,7 @@ func (c *conn) SetReadDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setReadDeadline(t); err != nil {
+	if err := c.fd.pfd.SetReadDeadline(t); err != nil {
 		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
@@ -256,7 +251,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setWriteDeadline(t); err != nil {
+	if err := c.fd.pfd.SetWriteDeadline(t); err != nil {
 		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
@@ -391,10 +386,8 @@ var (
 	errMissingAddress = errors.New("missing address")
 
 	// For both read and write operations.
-	errTimeout          error = &timeoutError{}
-	errCanceled               = errors.New("operation was canceled")
-	errClosing                = errors.New("use of closed network connection")
-	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
+	errCanceled         = errors.New("operation was canceled")
+	ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
 )
 
 // mapErr maps from the context errors to the historical internal net
@@ -407,7 +400,7 @@ func mapErr(err error) error {
 	case context.Canceled:
 		return errCanceled
 	case context.DeadlineExceeded:
-		return errTimeout
+		return poll.ErrTimeout
 	default:
 		return err
 	}
@@ -502,12 +495,6 @@ func (e *OpError) Temporary() bool {
 	return ok && t.Temporary()
 }
 
-type timeoutError struct{}
-
-func (e *timeoutError) Error() string   { return "i/o timeout" }
-func (e *timeoutError) Timeout() bool   { return true }
-func (e *timeoutError) Temporary() bool { return true }
-
 // A ParseError is the error type of literal network address parsers.
 type ParseError struct {
 	// Type is the type of string that was expected, such as
@@ -632,8 +619,6 @@ type buffersWriter interface {
 	writeBuffers(*Buffers) (int64, error)
 }
 
-var testHookDidWritev = func(wrote int) {}
-
 // Buffers contains zero or more runs of bytes to write.
 //
 // On certain machines, for certain types of connections, this is
diff --git a/src/net/net_test.go b/src/net/net_test.go
index 9a9a7e5..024505e 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -54,7 +54,7 @@ func TestCloseRead(t *testing.T) {
 			err = c.CloseRead()
 		}
 		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, true); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
@@ -94,7 +94,7 @@ func TestCloseWrite(t *testing.T) {
 			err = c.CloseWrite()
 		}
 		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, true); perr != nil {
 				t.Error(perr)
 			}
 			t.Error(err)
@@ -139,7 +139,7 @@ func TestCloseWrite(t *testing.T) {
 			err = c.CloseWrite()
 		}
 		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, true); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
@@ -184,7 +184,7 @@ func TestConnClose(t *testing.T) {
 		defer c.Close()
 
 		if err := c.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
@@ -215,7 +215,7 @@ func TestListenerClose(t *testing.T) {
 
 		dst := ln.Addr().String()
 		if err := ln.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
@@ -269,7 +269,7 @@ func TestPacketConnClose(t *testing.T) {
 		defer c.Close()
 
 		if err := c.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
@@ -292,7 +292,7 @@ func TestListenCloseListen(t *testing.T) {
 		}
 		addr := ln.Addr().String()
 		if err := ln.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
+			if perr := parseCloseError(err, false); perr != nil {
 				t.Error(perr)
 			}
 			t.Fatal(err)
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index 38edbc2..e36ea11 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -503,21 +503,26 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
 	}
 }
 
-func getmacSpeaksEnglish(t *testing.T) bool {
+// check that getmac exists as a powershell command, and that it
+// speaks English.
+func checkGetmac(t *testing.T) {
 	out, err := runCmd("getmac", "/?")
 	if err != nil {
+		if strings.Contains(err.Error(), "term 'getmac' is not recognized as the name of a cmdlet") {
+			t.Skipf("getmac not available")
+		}
 		t.Fatal(err)
 	}
-	return bytes.Contains(out, []byte("network adapters on a system"))
+	if !bytes.Contains(out, []byte("network adapters on a system")) {
+		t.Skipf("skipping test on non-English system")
+	}
 }
 
 func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
 	if isWindowsXP(t) {
 		t.Skip("Windows XP does not have powershell command")
 	}
-	if !getmacSpeaksEnglish(t) {
-		t.Skip("English version of getmac required for this test")
-	}
+	checkGetmac(t)
 
 	ift, err := Interfaces()
 	if err != nil {
@@ -559,39 +564,49 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
 	//Transport Name:   Disconnected
 	//
 	want := make(map[string]string)
-	var name string
+	group := make(map[string]string) // name / values for single adapter
+	getValue := func(name string) string {
+		value, found := group[name]
+		if !found {
+			t.Fatalf("%q has no %q line in it", group, name)
+		}
+		if value == "" {
+			t.Fatalf("%q has empty %q value", group, name)
+		}
+		return value
+	}
+	processGroup := func() {
+		if len(group) == 0 {
+			return
+		}
+		tname := strings.ToLower(getValue("Transport Name"))
+		if tname == "n/a" {
+			// skip these
+			return
+		}
+		addr := strings.ToLower(getValue("Physical Address"))
+		if addr == "disabled" || addr == "n/a" {
+			// skip these
+			return
+		}
+		addr = strings.Replace(addr, "-", ":", -1)
+		cname := getValue("Connection Name")
+		want[cname] = addr
+		group = nil
+	}
 	lines := bytes.Split(out, []byte{'\r', '\n'})
 	for _, line := range lines {
-		if bytes.Contains(line, []byte("Connection Name:")) {
-			f := bytes.Split(line, []byte{':'})
-			if len(f) != 2 {
-				t.Fatalf("unexpected \"Connection Name\" line: %q", line)
-			}
-			name = string(bytes.TrimSpace(f[1]))
-			if name == "" {
-				t.Fatalf("empty name on \"Connection Name\" line: %q", line)
-			}
+		if len(line) == 0 {
+			processGroup()
+			continue
 		}
-		if bytes.Contains(line, []byte("Physical Address:")) {
-			if name == "" {
-				t.Fatalf("no matching name found: %q", string(out))
-			}
-			f := bytes.Split(line, []byte{':'})
-			if len(f) != 2 {
-				t.Fatalf("unexpected \"Physical Address\" line: %q", line)
-			}
-			addr := string(bytes.ToLower(bytes.TrimSpace(f[1])))
-			if addr == "" {
-				t.Fatalf("empty address on \"Physical Address\" line: %q", line)
-			}
-			if addr == "disabled" || addr == "n/a" {
-				continue
-			}
-			addr = strings.Replace(addr, "-", ":", -1)
-			want[name] = addr
-			name = ""
+		i := bytes.IndexByte(line, ':')
+		if i == -1 {
+			t.Fatalf("line %q has no : in it", line)
 		}
+		group[string(line[:i])] = string(bytes.TrimSpace(line[i+1:]))
 	}
+	processGroup()
 
 	for name, wantAddr := range want {
 		haveAddr, ok := have[name]
diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go
index 5f1eb19..47901b0 100644
--- a/src/net/netgo_unix_test.go
+++ b/src/net/netgo_unix_test.go
@@ -22,7 +22,7 @@ func TestGoLookupIP(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	if _, err := goLookupIP(ctx, host); err != nil {
+	if _, err := DefaultResolver.goLookupIP(ctx, host); err != nil {
 		t.Error(err)
 	}
 }
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index 2a14095..5841ca3 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -50,11 +50,11 @@ func testableNetwork(network string) bool {
 	}
 	switch ss[0] {
 	case "tcp4", "udp4", "ip4":
-		if !supportsIPv4 {
+		if !supportsIPv4() {
 			return false
 		}
 	case "tcp6", "udp6", "ip6":
-		if !supportsIPv6 {
+		if !supportsIPv6() {
 			return false
 		}
 	}
@@ -117,25 +117,25 @@ func testableListenArgs(network, address, client string) bool {
 
 	// Test functionality of IPv4 communication using AF_INET and
 	// IPv6 communication using AF_INET6 sockets.
-	if !supportsIPv4 && ip.To4() != nil {
+	if !supportsIPv4() && ip.To4() != nil {
 		return false
 	}
-	if !supportsIPv6 && ip.To16() != nil && ip.To4() == nil {
+	if !supportsIPv6() && ip.To16() != nil && ip.To4() == nil {
 		return false
 	}
 	cip := ParseIP(client)
 	if cip != nil {
-		if !supportsIPv4 && cip.To4() != nil {
+		if !supportsIPv4() && cip.To4() != nil {
 			return false
 		}
-		if !supportsIPv6 && cip.To16() != nil && cip.To4() == nil {
+		if !supportsIPv6() && cip.To16() != nil && cip.To4() == nil {
 			return false
 		}
 	}
 
 	// Test functionality of IPv4 communication using AF_INET6
 	// sockets.
-	if !supportsIPv4map && supportsIPv4 && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
+	if !supportsIPv4map() && supportsIPv4() && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
 		// At this point, we prefer IPv4 when ip is nil.
 		// See favoriteAddrFamily for further information.
 		if ip.To16() != nil && ip.To4() == nil && cip.To4() != nil { // a pair of IPv6 server and IPv4 client
diff --git a/src/net/port_unix.go b/src/net/port_unix.go
index 868d1e4..829f51f 100644
--- a/src/net/port_unix.go
+++ b/src/net/port_unix.go
@@ -17,6 +17,8 @@ func readServices() {
 	if err != nil {
 		return
 	}
+	defer file.close()
+
 	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
 		// "http 80/tcp www www-http # World Wide Web HTTP"
 		if i := byteIndex(line, '#'); i >= 0 {
@@ -43,7 +45,6 @@ func readServices() {
 			}
 		}
 	}
-	file.close()
 }
 
 // goLookupPort is the native Go implementation of LookupPort.
diff --git a/src/net/rawconn.go b/src/net/rawconn.go
new file mode 100644
index 0000000..d67be64
--- /dev/null
+++ b/src/net/rawconn.go
@@ -0,0 +1,62 @@
+// Copyright 2017 The Go Authors. 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 (
+	"runtime"
+	"syscall"
+)
+
+// BUG(mikio): On Windows, the Read and Write methods of
+// syscall.RawConn are not implemented.
+
+// BUG(mikio): On NaCl and Plan 9, the Control, Read and Write methods
+// of syscall.RawConn are not implemented.
+
+type rawConn struct {
+	fd *netFD
+}
+
+func (c *rawConn) ok() bool { return c != nil && c.fd != nil }
+
+func (c *rawConn) Control(f func(uintptr)) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	err := c.fd.pfd.RawControl(f)
+	runtime.KeepAlive(c.fd)
+	if err != nil {
+		err = &OpError{Op: "raw-control", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return err
+}
+
+func (c *rawConn) Read(f func(uintptr) bool) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	err := c.fd.pfd.RawRead(f)
+	runtime.KeepAlive(c.fd)
+	if err != nil {
+		err = &OpError{Op: "raw-read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
+}
+
+func (c *rawConn) Write(f func(uintptr) bool) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	err := c.fd.pfd.RawWrite(f)
+	runtime.KeepAlive(c.fd)
+	if err != nil {
+		err = &OpError{Op: "raw-write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
+}
+
+func newRawConn(fd *netFD) (*rawConn, error) {
+	return &rawConn{fd: fd}, nil
+}
diff --git a/src/net/rawconn_unix_test.go b/src/net/rawconn_unix_test.go
new file mode 100644
index 0000000..294249b
--- /dev/null
+++ b/src/net/rawconn_unix_test.go
@@ -0,0 +1,94 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+	"bytes"
+	"syscall"
+	"testing"
+)
+
+func TestRawConn(t *testing.T) {
+	handler := func(ls *localServer, ln Listener) {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		defer c.Close()
+		var b [32]byte
+		n, err := c.Read(b[:])
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		if _, err := c.Write(b[:n]); err != nil {
+			t.Error(err)
+			return
+		}
+	}
+	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)
+	}
+	defer c.Close()
+	cc, err := c.(*TCPConn).SyscallConn()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var operr error
+	data := []byte("HELLO-R-U-THERE")
+	err = cc.Write(func(s uintptr) bool {
+		_, operr = syscall.Write(int(s), data)
+		if operr == syscall.EAGAIN {
+			return false
+		}
+		return true
+	})
+	if err != nil || operr != nil {
+		t.Fatal(err, operr)
+	}
+
+	var nr int
+	var b [32]byte
+	err = cc.Read(func(s uintptr) bool {
+		nr, operr = syscall.Read(int(s), b[:])
+		if operr == syscall.EAGAIN {
+			return false
+		}
+		return true
+	})
+	if err != nil || operr != nil {
+		t.Fatal(err, operr)
+	}
+	if bytes.Compare(b[:nr], data) != 0 {
+		t.Fatalf("got %#v; want %#v", b[:nr], data)
+	}
+
+	fn := func(s uintptr) {
+		operr = syscall.SetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+	}
+	err = cc.Control(fn)
+	if err != nil || operr != nil {
+		t.Fatal(err, operr)
+	}
+	c.Close()
+	err = cc.Control(fn)
+	if err == nil {
+		t.Fatal("should fail")
+	}
+}
diff --git a/src/net/rawconn_windows_test.go b/src/net/rawconn_windows_test.go
new file mode 100644
index 0000000..5fb6de7
--- /dev/null
+++ b/src/net/rawconn_windows_test.go
@@ -0,0 +1,36 @@
+// Copyright 2017 The Go Authors. 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"
+	"testing"
+)
+
+func TestRawConn(t *testing.T) {
+	c, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	cc, err := c.(*UDPConn).SyscallConn()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var operr error
+	fn := func(s uintptr) {
+		operr = syscall.SetsockoptInt(syscall.Handle(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+	}
+	err = cc.Control(fn)
+	if err != nil || operr != nil {
+		t.Fatal(err, operr)
+	}
+	c.Close()
+	err = cc.Control(fn)
+	if err == nil {
+		t.Fatal("should fail")
+	}
+}
diff --git a/src/net/rpc/debug.go b/src/net/rpc/debug.go
index 98b2c1c..a1d799f 100644
--- a/src/net/rpc/debug.go
+++ b/src/net/rpc/debug.go
@@ -71,20 +71,17 @@ type debugHTTP struct {
 // Runs at /debug/rpc
 func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	// Build a sorted version of the data.
-	var services = make(serviceArray, len(server.serviceMap))
-	i := 0
-	server.mu.Lock()
-	for sname, service := range server.serviceMap {
-		services[i] = debugService{service, sname, make(methodArray, len(service.method))}
-		j := 0
-		for mname, method := range service.method {
-			services[i].Method[j] = debugMethod{method, mname}
-			j++
+	var services serviceArray
+	server.serviceMap.Range(func(snamei, svci interface{}) bool {
+		svc := svci.(*service)
+		ds := debugService{svc, snamei.(string), make(methodArray, 0, len(svc.method))}
+		for mname, method := range svc.method {
+			ds.Method = append(ds.Method, debugMethod{method, mname})
 		}
-		sort.Sort(services[i].Method)
-		i++
-	}
-	server.mu.Unlock()
+		sort.Sort(ds.Method)
+		services = append(services, ds)
+		return true
+	})
 	sort.Sort(services)
 	err := debug.Execute(w, services)
 	if err != nil {
diff --git a/src/net/rpc/jsonrpc/all_test.go b/src/net/rpc/jsonrpc/all_test.go
index b811d3c..bbb8eb0 100644
--- a/src/net/rpc/jsonrpc/all_test.go
+++ b/src/net/rpc/jsonrpc/all_test.go
@@ -13,6 +13,7 @@ import (
 	"io/ioutil"
 	"net"
 	"net/rpc"
+	"reflect"
 	"strings"
 	"testing"
 )
@@ -55,8 +56,26 @@ func (t *Arith) Error(args *Args, reply *Reply) error {
 	panic("ERROR")
 }
 
+type BuiltinTypes struct{}
+
+func (BuiltinTypes) Map(i int, reply *map[int]int) error {
+	(*reply)[i] = i
+	return nil
+}
+
+func (BuiltinTypes) Slice(i int, reply *[]int) error {
+	*reply = append(*reply, i)
+	return nil
+}
+
+func (BuiltinTypes) Array(i int, reply *[1]int) error {
+	(*reply)[0] = i
+	return nil
+}
+
 func init() {
 	rpc.Register(new(Arith))
+	rpc.Register(BuiltinTypes{})
 }
 
 func TestServerNoParams(t *testing.T) {
@@ -182,6 +201,45 @@ func TestClient(t *testing.T) {
 	}
 }
 
+func TestBuiltinTypes(t *testing.T) {
+	cli, srv := net.Pipe()
+	go ServeConn(srv)
+
+	client := NewClient(cli)
+	defer client.Close()
+
+	// Map
+	arg := 7
+	replyMap := map[int]int{}
+	err := client.Call("BuiltinTypes.Map", arg, &replyMap)
+	if err != nil {
+		t.Errorf("Map: expected no error but got string %q", err.Error())
+	}
+	if replyMap[arg] != arg {
+		t.Errorf("Map: expected %d got %d", arg, replyMap[arg])
+	}
+
+	// Slice
+	replySlice := []int{}
+	err = client.Call("BuiltinTypes.Slice", arg, &replySlice)
+	if err != nil {
+		t.Errorf("Slice: expected no error but got string %q", err.Error())
+	}
+	if e := []int{arg}; !reflect.DeepEqual(replySlice, e) {
+		t.Errorf("Slice: expected %v got %v", e, replySlice)
+	}
+
+	// Array
+	replyArray := [1]int{}
+	err = client.Call("BuiltinTypes.Array", arg, &replyArray)
+	if err != nil {
+		t.Errorf("Array: expected no error but got string %q", err.Error())
+	}
+	if e := [1]int{arg}; !reflect.DeepEqual(replyArray, e) {
+		t.Errorf("Array: expected %v got %v", e, replyArray)
+	}
+}
+
 func TestMalformedInput(t *testing.T) {
 	cli, srv := net.Pipe()
 	go cli.Write([]byte(`{id:1}`)) // invalid json
diff --git a/src/net/rpc/jsonrpc/client.go b/src/net/rpc/jsonrpc/client.go
index da1b816..e6359be 100644
--- a/src/net/rpc/jsonrpc/client.go
+++ b/src/net/rpc/jsonrpc/client.go
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package jsonrpc implements a JSON-RPC ClientCodec and ServerCodec
+// Package jsonrpc implements a JSON-RPC 1.0 ClientCodec and ServerCodec
 // for the rpc package.
+// For JSON-RPC 2.0 support, see https://godoc.org/?q=json-rpc+2.0
 package jsonrpc
 
 import (
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index 18ea629..29aae7e 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -187,8 +187,7 @@ type Response struct {
 
 // Server represents an RPC Server.
 type Server struct {
-	mu         sync.RWMutex // protects the serviceMap
-	serviceMap map[string]*service
+	serviceMap sync.Map   // map[string]*service
 	reqLock    sync.Mutex // protects freeReq
 	freeReq    *Request
 	respLock   sync.Mutex // protects freeResp
@@ -197,7 +196,7 @@ type Server struct {
 
 // NewServer returns a new Server.
 func NewServer() *Server {
-	return &Server{serviceMap: make(map[string]*service)}
+	return &Server{}
 }
 
 // DefaultServer is the default instance of *Server.
@@ -240,11 +239,6 @@ func (server *Server) RegisterName(name string, rcvr interface{}) error {
 }
 
 func (server *Server) register(rcvr interface{}, name string, useName bool) error {
-	server.mu.Lock()
-	defer server.mu.Unlock()
-	if server.serviceMap == nil {
-		server.serviceMap = make(map[string]*service)
-	}
 	s := new(service)
 	s.typ = reflect.TypeOf(rcvr)
 	s.rcvr = reflect.ValueOf(rcvr)
@@ -262,9 +256,6 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
 		log.Print(s)
 		return errors.New(s)
 	}
-	if _, present := server.serviceMap[sname]; present {
-		return errors.New("rpc: service already defined: " + sname)
-	}
 	s.name = sname
 
 	// Install the methods
@@ -283,7 +274,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
 		log.Print(str)
 		return errors.New(str)
 	}
-	server.serviceMap[s.name] = s
+
+	if _, dup := server.serviceMap.LoadOrStore(sname, s); dup {
+		return errors.New("rpc: service already defined: " + sname)
+	}
 	return nil
 }
 
@@ -571,10 +565,17 @@ func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *m
 	}
 
 	replyv = reflect.New(mtype.ReplyType.Elem())
+
+	switch mtype.ReplyType.Elem().Kind() {
+	case reflect.Map:
+		replyv.Elem().Set(reflect.MakeMap(mtype.ReplyType.Elem()))
+	case reflect.Slice:
+		replyv.Elem().Set(reflect.MakeSlice(mtype.ReplyType.Elem(), 0, 0))
+	}
 	return
 }
 
-func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, keepReading bool, err error) {
+func (server *Server) readRequestHeader(codec ServerCodec) (svc *service, mtype *methodType, req *Request, keepReading bool, err error) {
 	// Grab the request header.
 	req = server.getRequest()
 	err = codec.ReadRequestHeader(req)
@@ -600,14 +601,13 @@ func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mt
 	methodName := req.ServiceMethod[dot+1:]
 
 	// Look up the request.
-	server.mu.RLock()
-	service = server.serviceMap[serviceName]
-	server.mu.RUnlock()
-	if service == nil {
+	svci, ok := server.serviceMap.Load(serviceName)
+	if !ok {
 		err = errors.New("rpc: can't find service " + req.ServiceMethod)
 		return
 	}
-	mtype = service.method[methodName]
+	svc = svci.(*service)
+	mtype = svc.method[methodName]
 	if mtype == nil {
 		err = errors.New("rpc: can't find method " + req.ServiceMethod)
 	}
diff --git a/src/net/rpc/server_test.go b/src/net/rpc/server_test.go
index 8369c9d..fb97f82 100644
--- a/src/net/rpc/server_test.go
+++ b/src/net/rpc/server_test.go
@@ -11,6 +11,7 @@ import (
 	"log"
 	"net"
 	"net/http/httptest"
+	"reflect"
 	"runtime"
 	"strings"
 	"sync"
@@ -85,6 +86,24 @@ type Embed struct {
 	hidden
 }
 
+type BuiltinTypes struct{}
+
+func (BuiltinTypes) Map(args *Args, reply *map[int]int) error {
+	(*reply)[args.A] = args.B
+	return nil
+}
+
+func (BuiltinTypes) Slice(args *Args, reply *[]int) error {
+	*reply = append(*reply, args.A, args.B)
+	return nil
+}
+
+func (BuiltinTypes) Array(args *Args, reply *[2]int) error {
+	(*reply)[0] = args.A
+	(*reply)[1] = args.B
+	return nil
+}
+
 func listenTCP() (net.Listener, string) {
 	l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
 	if e != nil {
@@ -97,6 +116,7 @@ func startServer() {
 	Register(new(Arith))
 	Register(new(Embed))
 	RegisterName("net.rpc.Arith", new(Arith))
+	Register(BuiltinTypes{})
 
 	var l net.Listener
 	l, serverAddr = listenTCP()
@@ -326,6 +346,49 @@ func testHTTPRPC(t *testing.T, path string) {
 	}
 }
 
+func TestBuiltinTypes(t *testing.T) {
+	once.Do(startServer)
+
+	client, err := DialHTTP("tcp", httpServerAddr)
+	if err != nil {
+		t.Fatal("dialing", err)
+	}
+	defer client.Close()
+
+	// Map
+	args := &Args{7, 8}
+	replyMap := map[int]int{}
+	err = client.Call("BuiltinTypes.Map", args, &replyMap)
+	if err != nil {
+		t.Errorf("Map: expected no error but got string %q", err.Error())
+	}
+	if replyMap[args.A] != args.B {
+		t.Errorf("Map: expected %d got %d", args.B, replyMap[args.A])
+	}
+
+	// Slice
+	args = &Args{7, 8}
+	replySlice := []int{}
+	err = client.Call("BuiltinTypes.Slice", args, &replySlice)
+	if err != nil {
+		t.Errorf("Slice: expected no error but got string %q", err.Error())
+	}
+	if e := []int{args.A, args.B}; !reflect.DeepEqual(replySlice, e) {
+		t.Errorf("Slice: expected %v got %v", e, replySlice)
+	}
+
+	// Array
+	args = &Args{7, 8}
+	replyArray := [2]int{}
+	err = client.Call("BuiltinTypes.Array", args, &replyArray)
+	if err != nil {
+		t.Errorf("Array: expected no error but got string %q", err.Error())
+	}
+	if e := [2]int{args.A, args.B}; !reflect.DeepEqual(replyArray, e) {
+		t.Errorf("Array: expected %v got %v", e, replyArray)
+	}
+}
+
 // CodecEmulator provides a client-like api and a ServerCodec interface.
 // Can be used to test ServeRequest.
 type CodecEmulator struct {
@@ -619,13 +682,13 @@ func TestErrorAfterClientClose(t *testing.T) {
 
 // Tests the fix to issue 11221. Without the fix, this loops forever or crashes.
 func TestAcceptExitAfterListenerClose(t *testing.T) {
-	newServer = NewServer()
+	newServer := NewServer()
 	newServer.Register(new(Arith))
 	newServer.RegisterName("net.rpc.Arith", new(Arith))
 	newServer.RegisterName("newServer.Arith", new(Arith))
 
 	var l net.Listener
-	l, newServerAddr = listenTCP()
+	l, _ = listenTCP()
 	l.Close()
 	newServer.Accept(l)
 }
diff --git a/src/net/sendfile_bsd.go b/src/net/sendfile_bsd.go
new file mode 100644
index 0000000..7a2b48c
--- /dev/null
+++ b/src/net/sendfile_bsd.go
@@ -0,0 +1,67 @@
+// Copyright 2011 The Go Authors. 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
+
+package net
+
+import (
+	"internal/poll"
+	"io"
+	"os"
+)
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
+	// FreeBSD and DragonFly use 0 as the "until EOF" value.
+	// If you pass in more bytes than the file contains, it will
+	// loop back to the beginning ad nauseam until it's sent
+	// exactly the number of bytes told to. As such, we need to
+	// know exactly how many bytes to send.
+	var remain int64 = 0
+
+	lr, ok := r.(*io.LimitedReader)
+	if ok {
+		remain, r = lr.N, lr.R
+		if remain <= 0 {
+			return 0, nil, true
+		}
+	}
+	f, ok := r.(*os.File)
+	if !ok {
+		return 0, nil, false
+	}
+
+	if remain == 0 {
+		fi, err := f.Stat()
+		if err != nil {
+			return 0, err, false
+		}
+
+		remain = fi.Size()
+	}
+
+	// The other quirk with FreeBSD/DragonFly's sendfile
+	// implementation is that it doesn't use the current position
+	// of the file -- if you pass it offset 0, it starts from
+	// offset 0. There's no way to tell it "start from current
+	// position", so we have to manage that explicitly.
+	pos, err := f.Seek(0, io.SeekCurrent)
+	if err != nil {
+		return 0, err, false
+	}
+
+	written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
+
+	if lr != nil {
+		lr.N = remain - written
+	}
+	return written, wrapSyscallError("sendfile", err), written > 0
+}
diff --git a/src/net/sendfile_dragonfly.go b/src/net/sendfile_dragonfly.go
deleted file mode 100644
index d4b825c..0000000
--- a/src/net/sendfile_dragonfly.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"io"
-	"os"
-	"syscall"
-)
-
-// maxSendfileSize is the largest chunk size we ask the kernel to copy
-// at a time.
-const maxSendfileSize int = 4 << 20
-
-// sendFile copies the contents of r to c using the sendfile
-// system call to minimize copies.
-//
-// if handled == true, sendFile returns the number of bytes copied and any
-// non-EOF error.
-//
-// if handled == false, sendFile performed no work.
-func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
-	// DragonFly uses 0 as the "until EOF" value. If you pass in more bytes than the
-	// file contains, it will loop back to the beginning ad nauseam until it's sent
-	// exactly the number of bytes told to. As such, we need to know exactly how many
-	// bytes to send.
-	var remain int64 = 0
-
-	lr, ok := r.(*io.LimitedReader)
-	if ok {
-		remain, r = lr.N, lr.R
-		if remain <= 0 {
-			return 0, nil, true
-		}
-	}
-	f, ok := r.(*os.File)
-	if !ok {
-		return 0, nil, false
-	}
-
-	if remain == 0 {
-		fi, err := f.Stat()
-		if err != nil {
-			return 0, err, false
-		}
-
-		remain = fi.Size()
-	}
-
-	// The other quirk with DragonFly's sendfile implementation is that it doesn't
-	// use the current position of the file -- if you pass it offset 0, it starts
-	// from offset 0. There's no way to tell it "start from current position", so
-	// we have to manage that explicitly.
-	pos, err := f.Seek(0, io.SeekCurrent)
-	if err != nil {
-		return 0, err, false
-	}
-
-	if err := c.writeLock(); err != nil {
-		return 0, err, true
-	}
-	defer c.writeUnlock()
-
-	dst := c.sysfd
-	src := int(f.Fd())
-	for remain > 0 {
-		n := maxSendfileSize
-		if int64(n) > remain {
-			n = int(remain)
-		}
-		pos1 := pos
-		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
-		if n > 0 {
-			pos += int64(n)
-			written += int64(n)
-			remain -= int64(n)
-		}
-		if n == 0 && err1 == nil {
-			break
-		}
-		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.waitWrite(); err1 == nil {
-				continue
-			}
-		}
-		if err1 == syscall.EINTR {
-			continue
-		}
-		if err1 != nil {
-			// This includes syscall.ENOSYS (no kernel
-			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
-			break
-		}
-	}
-	if lr != nil {
-		lr.N = remain
-	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
-	}
-	return written, err, written > 0
-}
diff --git a/src/net/sendfile_freebsd.go b/src/net/sendfile_freebsd.go
deleted file mode 100644
index 18cbb27..0000000
--- a/src/net/sendfile_freebsd.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"io"
-	"os"
-	"syscall"
-)
-
-// maxSendfileSize is the largest chunk size we ask the kernel to copy
-// at a time.
-const maxSendfileSize int = 4 << 20
-
-// sendFile copies the contents of r to c using the sendfile
-// system call to minimize copies.
-//
-// if handled == true, sendFile returns the number of bytes copied and any
-// non-EOF error.
-//
-// if handled == false, sendFile performed no work.
-func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
-	// FreeBSD uses 0 as the "until EOF" value. If you pass in more bytes than the
-	// file contains, it will loop back to the beginning ad nauseam until it's sent
-	// exactly the number of bytes told to. As such, we need to know exactly how many
-	// bytes to send.
-	var remain int64 = 0
-
-	lr, ok := r.(*io.LimitedReader)
-	if ok {
-		remain, r = lr.N, lr.R
-		if remain <= 0 {
-			return 0, nil, true
-		}
-	}
-	f, ok := r.(*os.File)
-	if !ok {
-		return 0, nil, false
-	}
-
-	if remain == 0 {
-		fi, err := f.Stat()
-		if err != nil {
-			return 0, err, false
-		}
-
-		remain = fi.Size()
-	}
-
-	// The other quirk with FreeBSD's sendfile implementation is that it doesn't
-	// use the current position of the file -- if you pass it offset 0, it starts
-	// from offset 0. There's no way to tell it "start from current position", so
-	// we have to manage that explicitly.
-	pos, err := f.Seek(0, io.SeekCurrent)
-	if err != nil {
-		return 0, err, false
-	}
-
-	if err := c.writeLock(); err != nil {
-		return 0, err, true
-	}
-	defer c.writeUnlock()
-
-	dst := c.sysfd
-	src := int(f.Fd())
-	for remain > 0 {
-		n := maxSendfileSize
-		if int64(n) > remain {
-			n = int(remain)
-		}
-		pos1 := pos
-		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
-		if n > 0 {
-			pos += int64(n)
-			written += int64(n)
-			remain -= int64(n)
-		}
-		if n == 0 && err1 == nil {
-			break
-		}
-		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.waitWrite(); err1 == nil {
-				continue
-			}
-		}
-		if err1 == syscall.EINTR {
-			continue
-		}
-		if err1 != nil {
-			// This includes syscall.ENOSYS (no kernel
-			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
-			break
-		}
-	}
-	if lr != nil {
-		lr.N = remain
-	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
-	}
-	return written, err, written > 0
-}
diff --git a/src/net/sendfile_linux.go b/src/net/sendfile_linux.go
index 7e741f9..c537ea6 100644
--- a/src/net/sendfile_linux.go
+++ b/src/net/sendfile_linux.go
@@ -5,15 +5,11 @@
 package net
 
 import (
+	"internal/poll"
 	"io"
 	"os"
-	"syscall"
 )
 
-// maxSendfileSize is the largest chunk size we ask the kernel to copy
-// at a time.
-const maxSendfileSize int = 4 << 20
-
 // sendFile copies the contents of r to c using the sendfile
 // system call to minimize copies.
 //
@@ -36,44 +32,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		return 0, nil, false
 	}
 
-	if err := c.writeLock(); err != nil {
-		return 0, err, true
-	}
-	defer c.writeUnlock()
+	written, err = poll.SendFile(&c.pfd, int(f.Fd()), remain)
 
-	dst := c.sysfd
-	src := int(f.Fd())
-	for remain > 0 {
-		n := maxSendfileSize
-		if int64(n) > remain {
-			n = int(remain)
-		}
-		n, err1 := syscall.Sendfile(dst, src, nil, n)
-		if n > 0 {
-			written += int64(n)
-			remain -= int64(n)
-		}
-		if n == 0 && err1 == nil {
-			break
-		}
-		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.waitWrite(); err1 == nil {
-				continue
-			}
-		}
-		if err1 != nil {
-			// This includes syscall.ENOSYS (no kernel
-			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
-			break
-		}
-	}
 	if lr != nil {
-		lr.N = remain
-	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
+		lr.N = remain - written
 	}
-	return written, err, written > 0
+	return written, wrapSyscallError("sendfile", err), written > 0
 }
diff --git a/src/net/sendfile_solaris.go b/src/net/sendfile_solaris.go
index add70c3..63ca9d4 100644
--- a/src/net/sendfile_solaris.go
+++ b/src/net/sendfile_solaris.go
@@ -5,19 +5,11 @@
 package net
 
 import (
+	"internal/poll"
 	"io"
 	"os"
-	"syscall"
 )
 
-// Not strictly needed, but very helpful for debugging, see issue #10221.
-//go:cgo_import_dynamic _ _ "libsendfile.so"
-//go:cgo_import_dynamic _ _ "libsocket.so"
-
-// maxSendfileSize is the largest chunk size we ask the kernel to copy
-// at a time.
-const maxSendfileSize int = 4 << 20
-
 // sendFile copies the contents of r to c using the sendfile
 // system call to minimize copies.
 //
@@ -62,56 +54,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		return 0, err, false
 	}
 
-	if err := c.writeLock(); err != nil {
-		return 0, err, true
-	}
-	defer c.writeUnlock()
+	written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
 
-	dst := c.sysfd
-	src := int(f.Fd())
-	for remain > 0 {
-		n := maxSendfileSize
-		if int64(n) > remain {
-			n = int(remain)
-		}
-		pos1 := pos
-		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
-		if 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)
-			remain -= int64(n)
-		}
-		if n == 0 && err1 == nil {
-			break
-		}
-		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.waitWrite(); err1 == nil {
-				continue
-			}
-		}
-		if err1 == syscall.EINTR {
-			continue
-		}
-		if err1 != nil {
-			// This includes syscall.ENOSYS (no kernel
-			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
-			break
-		}
-	}
 	if lr != nil {
-		lr.N = remain
-	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
+		lr.N = remain - written
 	}
-	return written, err, written > 0
+	return written, wrapSyscallError("sendfile", err), written > 0
 }
diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go
index bc0b7fb..bccd8b1 100644
--- a/src/net/sendfile_windows.go
+++ b/src/net/sendfile_windows.go
@@ -5,6 +5,7 @@
 package net
 
 import (
+	"internal/poll"
 	"io"
 	"os"
 	"syscall"
@@ -34,19 +35,10 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
 		return 0, nil, false
 	}
 
-	if err := fd.writeLock(); err != nil {
-		return 0, err, true
-	}
-	defer fd.writeUnlock()
+	done, err := poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n)
 
-	o := &fd.wop
-	o.qty = uint32(n)
-	o.handle = syscall.Handle(f.Fd())
-	done, err := wsrv.ExecIO(o, "TransmitFile", func(o *operation) error {
-		return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
-	})
 	if err != nil {
-		return 0, os.NewSyscallError("transmitfile", err), false
+		return 0, wrapSyscallError("transmitfile", err), false
 	}
 	if lr != nil {
 		lr.N -= int64(done)
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index a408fa5..28472e4 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -298,7 +298,7 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
 // messages is accomplished by including an email address in the to
 // parameter but not including it in the msg headers.
 //
-// The SendMail function and the the net/smtp package are low-level
+// The SendMail function and the net/smtp package are low-level
 // mechanisms and provide no support for DKIM signing, MIME
 // attachments (see the mime/multipart package), or other mail
 // functionality. Higher-level packages exist outside of the standard
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
index c48fae6..9dbe3eb 100644
--- a/src/net/smtp/smtp_test.go
+++ b/src/net/smtp/smtp_test.go
@@ -9,9 +9,11 @@ import (
 	"bytes"
 	"crypto/tls"
 	"crypto/x509"
+	"internal/testenv"
 	"io"
 	"net"
 	"net/textproto"
+	"runtime"
 	"strings"
 	"testing"
 	"time"
@@ -592,6 +594,9 @@ QUIT
 `
 
 func TestTLSClient(t *testing.T) {
+	if runtime.GOOS == "freebsd" && runtime.GOARCH == "amd64" {
+		testenv.SkipFlaky(t, 19229)
+	}
 	ln := newLocalListener(t)
 	defer ln.Close()
 	errc := make(chan error)
diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go
index 616a101..06ff10d 100644
--- a/src/net/sock_cloexec.go
+++ b/src/net/sock_cloexec.go
@@ -5,11 +5,12 @@
 // This file implements sysSocket and accept for platforms that
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build freebsd linux
+// +build dragonfly freebsd linux
 
 package net
 
 import (
+	"internal/poll"
 	"os"
 	"syscall"
 )
@@ -42,46 +43,8 @@ func sysSocket(family, sotype, proto int) (int, error) {
 		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
-
-// Wrapper around the accept system call that marks the returned file
-// descriptor as nonblocking and close-on-exec.
-func accept(s int) (int, syscall.Sockaddr, error) {
-	ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
-	// On Linux the accept4 system call was introduced in 2.6.28
-	// kernel and on FreeBSD it was introduced in 10 kernel. If we
-	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
-	// error on Linux, fall back to using accept.
-	switch err {
-	case nil:
-		return ns, sa, nil
-	default: // errors other than the ones listed
-		return -1, sa, os.NewSyscallError("accept4", err)
-	case syscall.ENOSYS: // syscall missing
-	case syscall.EINVAL: // some Linux use this instead of ENOSYS
-	case syscall.EACCES: // some Linux use this instead of ENOSYS
-	case syscall.EFAULT: // some Linux use this instead of ENOSYS
-	}
-
-	// See ../syscall/exec_unix.go for description of ForkLock.
-	// It is probably okay to hold the lock across syscall.Accept
-	// because we have put fd.sysfd into non-blocking mode.
-	// However, a call to the File method will put it back into
-	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	ns, sa, err = acceptFunc(s)
-	if err == nil {
-		syscall.CloseOnExec(ns)
-	}
-	if err != nil {
-		return -1, nil, os.NewSyscallError("accept", err)
-	}
-	if err = syscall.SetNonblock(ns, true); err != nil {
-		closeFunc(ns)
-		return -1, nil, os.NewSyscallError("setnonblock", err)
-	}
-	return ns, sa, nil
-}
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index 16351e1..8985f8f 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -8,6 +8,7 @@ package net
 
 import (
 	"context"
+	"internal/poll"
 	"os"
 	"syscall"
 )
@@ -43,11 +44,11 @@ func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only
 		return nil, err
 	}
 	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, err
 	}
 	if fd, err = newFD(s, family, sotype, net); err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return nil, err
 	}
 
@@ -127,7 +128,7 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
 		if lsa, err = laddr.sockaddr(fd.family); err != nil {
 			return err
 		} else if lsa != nil {
-			if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+			if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
 				return os.NewSyscallError("bind", err)
 			}
 		}
@@ -146,8 +147,8 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
 			return err
 		}
 	}
-	lsa, _ = syscall.Getsockname(fd.sysfd)
-	if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
+	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
+	if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
 		fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
 	} else {
 		fd.setAddr(fd.addrFunc()(lsa), raddr)
@@ -156,23 +157,23 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
 }
 
 func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
-	if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
+	if err := setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
 		return err
 	}
 	if lsa, err := laddr.sockaddr(fd.family); err != nil {
 		return err
 	} else if lsa != nil {
-		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+		if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
 			return os.NewSyscallError("bind", err)
 		}
 	}
-	if err := listenFunc(fd.sysfd, backlog); err != nil {
+	if err := listenFunc(fd.pfd.Sysfd, backlog); err != nil {
 		return os.NewSyscallError("listen", err)
 	}
 	if err := fd.init(); err != nil {
 		return err
 	}
-	lsa, _ := syscall.Getsockname(fd.sysfd)
+	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
 	fd.setAddr(fd.addrFunc()(lsa), nil)
 	return nil
 }
@@ -188,7 +189,7 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
 		// multiple UDP listeners that listen on the same UDP
 		// port to join the same group address.
 		if addr.IP != nil && addr.IP.IsMulticast() {
-			if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
+			if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
 				return err
 			}
 			addr := *addr
@@ -204,14 +205,14 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
 	if lsa, err := laddr.sockaddr(fd.family); err != nil {
 		return err
 	} else if lsa != nil {
-		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+		if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
 			return os.NewSyscallError("bind", err)
 		}
 	}
 	if err := fd.init(); err != nil {
 		return err
 	}
-	lsa, _ := syscall.Getsockname(fd.sysfd)
+	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
 	fd.setAddr(fd.addrFunc()(lsa), nil)
 	return nil
 }
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 567e4e1..4ecc8cb 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -25,7 +25,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
 		}
 	}
-	if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+	if supportsIPv4map() && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
 		// is otherwise. Note that some operating systems
 		// never admit this option.
diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go
index cd3d562..e8af84f 100644
--- a/src/net/sockopt_posix.go
+++ b/src/net/sockopt_posix.go
@@ -7,7 +7,7 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 )
 
@@ -101,27 +101,21 @@ done:
 }
 
 func setReadBuffer(fd *netFD, bytes int) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
+	err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setWriteBuffer(fd *netFD, bytes int) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
+	err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setKeepAlive(fd *netFD, keepalive bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
+	err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setLinger(fd *netFD, sec int) error {
@@ -133,9 +127,7 @@ func setLinger(fd *netFD, sec int) error {
 		l.Onoff = 0
 		l.Linger = 0
 	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
+	err := fd.pfd.SetsockoptLinger(syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/sockoptip_bsd.go b/src/net/sockoptip_bsd.go
index b15c639..b11f3a4 100644
--- a/src/net/sockoptip_bsd.go
+++ b/src/net/sockoptip_bsd.go
@@ -7,28 +7,24 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 )
 
 func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 	ip, err := interfaceToIPv4Addr(ifi)
 	if err != nil {
-		return os.NewSyscallError("setsockopt", err)
+		return wrapSyscallError("setsockopt", err)
 	}
 	var a [4]byte
 	copy(a[:], ip.To4())
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a))
+	err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))))
+	err := fd.pfd.SetsockoptByte(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/sockoptip_linux.go b/src/net/sockoptip_linux.go
index c1dcc91..bd7d834 100644
--- a/src/net/sockoptip_linux.go
+++ b/src/net/sockoptip_linux.go
@@ -5,7 +5,7 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 )
 
@@ -15,17 +15,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 		v = int32(ifi.Index)
 	}
 	mreq := &syscall.IPMreqn{Ifindex: v}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq))
+	err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/sockoptip_posix.go b/src/net/sockoptip_posix.go
index d508860..4e10f2a 100644
--- a/src/net/sockoptip_posix.go
+++ b/src/net/sockoptip_posix.go
@@ -7,7 +7,7 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 )
 
@@ -16,11 +16,9 @@ func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
 	if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
 		return err
 	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+	err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
@@ -28,19 +26,15 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
 	if ifi != nil {
 		v = ifi.Index
 	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv6MulticastLoopback(fd *netFD, v bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
@@ -49,9 +43,7 @@ func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
 	if ifi != nil {
 		mreq.Interface = uint32(ifi.Index)
 	}
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
+	err := fd.pfd.SetsockoptIPv6Mreq(syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/sockoptip_windows.go b/src/net/sockoptip_windows.go
index 916debe..6267603 100644
--- a/src/net/sockoptip_windows.go
+++ b/src/net/sockoptip_windows.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"os"
+	"runtime"
 	"syscall"
 	"unsafe"
 )
@@ -17,17 +18,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 	}
 	var a [4]byte
 	copy(a[:], ip.To4())
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&a[0])), 4))
+	err = fd.pfd.Setsockopt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&a[0])), 4)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go
index ba266e6..c4dc6c7 100644
--- a/src/net/sys_cloexec.go
+++ b/src/net/sys_cloexec.go
@@ -5,11 +5,12 @@
 // This file implements sysSocket and accept for platforms that do not
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build darwin dragonfly nacl netbsd openbsd solaris
+// +build darwin nacl netbsd openbsd solaris
 
 package net
 
 import (
+	"internal/poll"
 	"os"
 	"syscall"
 )
@@ -28,30 +29,8 @@ func sysSocket(family, sotype, proto int) (int, error) {
 		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
+		poll.CloseFunc(s)
 		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
-
-// Wrapper around the accept system call that marks the returned file
-// descriptor as nonblocking and close-on-exec.
-func accept(s int) (int, syscall.Sockaddr, error) {
-	// See ../syscall/exec_unix.go for description of ForkLock.
-	// It is probably okay to hold the lock across syscall.Accept
-	// because we have put fd.sysfd into non-blocking mode.
-	// However, a call to the File method will put it back into
-	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	ns, sa, err := acceptFunc(s)
-	if err == nil {
-		syscall.CloseOnExec(ns)
-	}
-	if err != nil {
-		return -1, nil, os.NewSyscallError("accept", err)
-	}
-	if err = syscall.SetNonblock(ns, true); err != nil {
-		closeFunc(ns)
-		return -1, nil, os.NewSyscallError("setnonblock", err)
-	}
-	return ns, sa, nil
-}
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index 69731eb..91571bd 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -80,6 +80,15 @@ type TCPConn struct {
 	conn
 }
 
+// SyscallConn returns a raw network connection.
+// This implements the syscall.Conn interface.
+func (c *TCPConn) SyscallConn() (syscall.RawConn, error) {
+	if !c.ok() {
+		return nil, syscall.EINVAL
+	}
+	return newRawConn(c.fd)
+}
+
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
 	if !c.ok() {
@@ -255,7 +264,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 	if !l.ok() {
 		return syscall.EINVAL
 	}
-	if err := l.fd.setDeadline(t); err != nil {
+	if err := l.fd.pfd.SetDeadline(t); err != nil {
 		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
 	return nil
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index d286060..e37f065 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -48,6 +48,9 @@ func (ln *TCPListener) accept() (*TCPConn, error) {
 }
 
 func (ln *TCPListener) close() error {
+	if err := ln.fd.pfd.Close(); err != nil {
+		return err
+	}
 	if _, err := ln.fd.ctl.WriteString("hangup"); err != nil {
 		ln.fd.ctl.Close()
 		return err
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index 9641e5c..58c7e49 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -18,7 +18,7 @@ func sockaddrToTCP(sa syscall.Sockaddr) Addr {
 	case *syscall.SockaddrInet4:
 		return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
 	case *syscall.SockaddrInet6:
-		return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
+		return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return nil
 }
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
index 54bf0cf..09f6516 100644
--- a/src/net/tcpsock_test.go
+++ b/src/net/tcpsock_test.go
@@ -32,28 +32,28 @@ func BenchmarkTCP4PersistentTimeout(b *testing.B) {
 }
 
 func BenchmarkTCP6OneShot(b *testing.B) {
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("ipv6 is not supported")
 	}
 	benchmarkTCP(b, false, false, "[::1]:0")
 }
 
 func BenchmarkTCP6OneShotTimeout(b *testing.B) {
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("ipv6 is not supported")
 	}
 	benchmarkTCP(b, false, true, "[::1]:0")
 }
 
 func BenchmarkTCP6Persistent(b *testing.B) {
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("ipv6 is not supported")
 	}
 	benchmarkTCP(b, true, false, "[::1]:0")
 }
 
 func BenchmarkTCP6PersistentTimeout(b *testing.B) {
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("ipv6 is not supported")
 	}
 	benchmarkTCP(b, true, true, "[::1]:0")
@@ -163,7 +163,7 @@ func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
 }
 
 func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("ipv6 is not supported")
 	}
 	benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
@@ -372,7 +372,7 @@ func TestTCPListenerName(t *testing.T) {
 func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		t.Skip("IPv6 is not supported")
 	}
 
diff --git a/src/net/tcpsockopt_darwin.go b/src/net/tcpsockopt_darwin.go
index 0d1310e..7415c76 100644
--- a/src/net/tcpsockopt_darwin.go
+++ b/src/net/tcpsockopt_darwin.go
@@ -5,7 +5,7 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 	"time"
 )
@@ -13,17 +13,15 @@ import (
 const sysTCP_KEEPINTVL = 0x101
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
 	// The kernel expects seconds so round to next highest second.
 	d += (time.Second - time.Nanosecond)
 	secs := int(d.Seconds())
-	switch err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err {
+	switch err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err {
 	case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option
 	default:
-		return os.NewSyscallError("setsockopt", err)
+		return wrapSyscallError("setsockopt", err)
 	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/tcpsockopt_dragonfly.go b/src/net/tcpsockopt_dragonfly.go
index 7cc716b..2b018f2 100644
--- a/src/net/tcpsockopt_dragonfly.go
+++ b/src/net/tcpsockopt_dragonfly.go
@@ -5,22 +5,20 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 	"time"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
 	// The kernel expects milliseconds so round to next highest
 	// millisecond.
 	d += (time.Millisecond - time.Nanosecond)
 	msecs := int(d / time.Millisecond)
-	if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil {
-		return os.NewSyscallError("setsockopt", err)
+	if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil {
+		return wrapSyscallError("setsockopt", err)
 	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/tcpsockopt_posix.go b/src/net/tcpsockopt_posix.go
index 805b56b..9cef434 100644
--- a/src/net/tcpsockopt_posix.go
+++ b/src/net/tcpsockopt_posix.go
@@ -7,14 +7,12 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 )
 
 func setNoDelay(fd *netFD, noDelay bool) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/tcpsockopt_solaris.go b/src/net/tcpsockopt_solaris.go
index 76285e5..019fe34 100644
--- a/src/net/tcpsockopt_solaris.go
+++ b/src/net/tcpsockopt_solaris.go
@@ -5,16 +5,12 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 	"time"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
 	// The kernel expects milliseconds so round to next highest
 	// millisecond.
 	d += (time.Millisecond - time.Nanosecond)
@@ -31,5 +27,7 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	// allocate a constant with a different meaning for the value of
 	// TCP_KEEPINTVL on illumos.
 
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go
index 8d44fb2..c1df660 100644
--- a/src/net/tcpsockopt_unix.go
+++ b/src/net/tcpsockopt_unix.go
@@ -7,21 +7,19 @@
 package net
 
 import (
-	"os"
+	"runtime"
 	"syscall"
 	"time"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
 	// The kernel expects seconds so round to next highest second.
 	d += (time.Second - time.Nanosecond)
 	secs := int(d.Seconds())
-	if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
-		return os.NewSyscallError("setsockopt", err)
+	if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
+		return wrapSyscallError("setsockopt", err)
 	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs))
+	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)
+	runtime.KeepAlive(fd)
+	return wrapSyscallError("setsockopt", err)
 }
diff --git a/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go
index 45a4dca..73dead1 100644
--- a/src/net/tcpsockopt_windows.go
+++ b/src/net/tcpsockopt_windows.go
@@ -6,16 +6,13 @@ package net
 
 import (
 	"os"
+	"runtime"
 	"syscall"
 	"time"
 	"unsafe"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	if err := fd.incref(); err != nil {
-		return err
-	}
-	defer fd.decref()
 	// The kernel expects milliseconds so round to next highest
 	// millisecond.
 	d += (time.Millisecond - time.Nanosecond)
@@ -27,6 +24,7 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	}
 	ret := uint32(0)
 	size := uint32(unsafe.Sizeof(ka))
-	err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+	err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+	runtime.KeepAlive(fd)
 	return os.NewSyscallError("wsaioctl", err)
 }
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 55bbf44..9de7801 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"fmt"
+	"internal/poll"
 	"internal/testenv"
 	"io"
 	"io/ioutil"
@@ -145,9 +146,9 @@ var acceptTimeoutTests = []struct {
 }{
 	// Tests that accept deadlines in the past work, even if
 	// there's incoming connections available.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	{-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+	{50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestAcceptTimeout(t *testing.T) {
@@ -299,9 +300,9 @@ var readTimeoutTests = []struct {
 }{
 	// Tests that read deadlines work, even if there's data ready
 	// to be read.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	{-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+	{50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestReadTimeout(t *testing.T) {
@@ -423,9 +424,9 @@ var readFromTimeoutTests = []struct {
 }{
 	// Tests that read deadlines work, even if there's data ready
 	// to be read.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	{-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+	{50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestReadFromTimeout(t *testing.T) {
@@ -496,9 +497,9 @@ var writeTimeoutTests = []struct {
 }{
 	// Tests that write deadlines work, even if there's buffer
 	// space available to write.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	{-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+	{10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestWriteTimeout(t *testing.T) {
@@ -610,9 +611,9 @@ var writeToTimeoutTests = []struct {
 }{
 	// Tests that write deadlines work, even if there's buffer
 	// space available to write.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	{-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+	{10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestWriteToTimeout(t *testing.T) {
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 841ef53..33959d5 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -83,6 +83,15 @@ type UDPConn struct {
 	conn
 }
 
+// SyscallConn returns a raw network connection.
+// This implements the syscall.Conn interface.
+func (c *UDPConn) SyscallConn() (syscall.RawConn, error) {
+	if !c.ok() {
+		return nil, syscall.EINVAL
+	}
+	return newRawConn(c.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.
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 72aadca..a126506 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -16,7 +16,7 @@ func sockaddrToUDP(sa syscall.Sockaddr) Addr {
 	case *syscall.SockaddrInet4:
 		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
 	case *syscall.SockaddrInet6:
-		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
+		return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return nil
 }
@@ -49,7 +49,7 @@ func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
 	case *syscall.SockaddrInet4:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
 	case *syscall.SockaddrInet6:
-		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
+		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return n, addr, err
 }
@@ -61,7 +61,7 @@ func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err
 	case *syscall.SockaddrInet4:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
 	case *syscall.SockaddrInet6:
-		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
+		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
 	}
 	return
 }
diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go
index 708cc10..6d4974e 100644
--- a/src/net/udpsock_test.go
+++ b/src/net/udpsock_test.go
@@ -15,7 +15,7 @@ import (
 func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
 	testHookUninstaller.Do(uninstallTestHooks)
 
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		b.Skip("IPv6 is not supported")
 	}
 	ifi := loopbackInterface()
@@ -279,7 +279,7 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
-	if !supportsIPv6 {
+	if !supportsIPv6() {
 		t.Skip("IPv6 is not supported")
 	}
 
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index b25d492..2485bab 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -60,6 +60,15 @@ type UnixConn struct {
 	conn
 }
 
+// SyscallConn returns a raw network connection.
+// This implements the syscall.Conn interface.
+func (c *UnixConn) SyscallConn() (syscall.RawConn, error) {
+	if !c.ok() {
+		return nil, syscall.EINVAL
+	}
+	return newRawConn(c.fd)
+}
+
 // CloseRead shuts down the reading side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseRead() error {
@@ -264,7 +273,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
 	if !l.ok() {
 		return syscall.EINVAL
 	}
-	if err := l.fd.setDeadline(t); err != nil {
+	if err := l.fd.pfd.SetDeadline(t); err != nil {
 		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
 	return nil
diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go
index 4ae7724..d352c55 100644
--- a/src/net/url/example_test.go
+++ b/src/net/url/example_test.go
@@ -8,8 +8,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"log"
-	"net/http"
-	"net/http/httputil"
 	"net/url"
 	"strings"
 )
@@ -59,33 +57,6 @@ func ExampleURL_roundtrip() {
 	// https://example.com/foo%2fbar
 }
 
-func ExampleURL_opaque() {
-	// Sending a literal '%' in an HTTP request's Path
-	req := &http.Request{
-		Method: "GET",
-		Host:   "example.com", // takes precedence over URL.Host
-		URL: &url.URL{
-			Host:   "ignored",
-			Scheme: "https",
-			Opaque: "/%2f/",
-		},
-		Header: http.Header{
-			"User-Agent": {"godoc-example/0.1"},
-		},
-	}
-	out, err := httputil.DumpRequestOut(req, true)
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Println(strings.Replace(string(out), "\r", "", -1))
-	// Output:
-	// GET /%2f/ HTTP/1.1
-	// Host: example.com
-	// User-Agent: godoc-example/0.1
-	// Accept-Encoding: gzip
-	//
-}
-
 func ExampleURL_ResolveReference() {
 	u, err := url.Parse("../../..//search?q=dotnet")
 	if err != nil {
@@ -110,6 +81,31 @@ func ExampleParseQuery() {
 	// {"x":["1"], "y":["2", "3"], "z":[""]}
 }
 
+func ExampleURL_Hostname() {
+	u, err := url.Parse("https://example.org:8000/path")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(u.Hostname())
+	u, err = url.Parse("https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(u.Hostname())
+	// Output:
+	// example.org
+	// 2001:0db8:85a3:0000:0000:8a2e:0370:7334
+}
+
+func ExampleURL_RequestURI() {
+	u, err := url.Parse("https://example.org/path?foo=bar")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(u.RequestURI())
+	// Output: /path?foo=bar
+}
+
 func toJSON(m interface{}) string {
 	js, err := json.Marshal(m)
 	if err != nil {
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 42a514b..2ac2472 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -309,9 +309,10 @@ func escape(s string, mode encoding) string {
 }
 
 // A URL represents a parsed URL (technically, a URI reference).
+//
 // The general form represented is:
 //
-//	scheme://[userinfo@]host/path[?query][#fragment]
+//	[scheme:][//[userinfo@]host][/]path[?query][#fragment]
 //
 // URLs that do not start with a slash after the scheme are interpreted as:
 //
@@ -321,26 +322,19 @@ func escape(s string, mode encoding) string {
 // A consequence is that it is impossible to tell which slashes in the Path were
 // slashes in the raw URL and which were %2f. This distinction is rarely important,
 // but when it is, code must not use Path directly.
-//
-// Go 1.5 introduced the RawPath field to hold the encoded form of Path.
 // The Parse function sets both Path and RawPath in the URL it returns,
 // and URL's String method uses RawPath if it is a valid encoding of Path,
 // by calling the EscapedPath method.
-//
-// In earlier versions of Go, the more indirect workarounds were that an
-// HTTP server could consult req.RequestURI and an HTTP client could
-// construct a URL struct directly and set the Opaque field instead of Path.
-// These still work as well.
 type URL struct {
 	Scheme     string
 	Opaque     string    // encoded opaque data
 	User       *Userinfo // username and password information
 	Host       string    // host or host:port
-	Path       string
-	RawPath    string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
-	ForceQuery bool   // append a query ('?') even if RawQuery is empty
-	RawQuery   string // encoded query values, without '?'
-	Fragment   string // fragment for references, without '#'
+	Path       string    // path (relative paths may omit leading slash)
+	RawPath    string    // encoded path hint (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
@@ -351,6 +345,7 @@ func User(username string) *Userinfo {
 
 // UserPassword returns a Userinfo containing the provided username
 // and password.
+//
 // This functionality should only be used with legacy web sites.
 // RFC 2396 warns that interpreting Userinfo this way
 // ``is NOT RECOMMENDED, because the passing of authentication
@@ -974,6 +969,8 @@ func (u *URL) ResolveReference(ref *URL) *URL {
 }
 
 // Query parses RawQuery and returns the corresponding values.
+// It silently discards malformed value pairs.
+// To check errors use ParseQuery.
 func (u *URL) Query() Values {
 	v, _ := ParseQuery(u.RawQuery)
 	return v
diff --git a/src/net/writev_test.go b/src/net/writev_test.go
index 7160d28..4c05be4 100644
--- a/src/net/writev_test.go
+++ b/src/net/writev_test.go
@@ -7,6 +7,7 @@ package net
 import (
 	"bytes"
 	"fmt"
+	"internal/poll"
 	"io"
 	"io/ioutil"
 	"reflect"
@@ -99,13 +100,13 @@ func TestBuffers_WriteTo(t *testing.T) {
 }
 
 func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
-	oldHook := testHookDidWritev
-	defer func() { testHookDidWritev = oldHook }()
+	oldHook := poll.TestHookDidWritev
+	defer func() { poll.TestHookDidWritev = oldHook }()
 	var writeLog struct {
 		sync.Mutex
 		log []int
 	}
-	testHookDidWritev = func(size int) {
+	poll.TestHookDidWritev = func(size int) {
 		writeLog.Lock()
 		writeLog.log = append(writeLog.log, size)
 		writeLog.Unlock()
diff --git a/src/net/writev_unix.go b/src/net/writev_unix.go
index 174e6bc..bf0fbf8 100644
--- a/src/net/writev_unix.go
+++ b/src/net/writev_unix.go
@@ -7,10 +7,8 @@
 package net
 
 import (
-	"io"
-	"os"
+	"runtime"
 	"syscall"
-	"unsafe"
 )
 
 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
@@ -25,71 +23,7 @@ func (c *conn) writeBuffers(v *Buffers) (int64, error) {
 }
 
 func (fd *netFD) writeBuffers(v *Buffers) (n int64, err error) {
-	if err := fd.writeLock(); err != nil {
-		return 0, err
-	}
-	defer fd.writeUnlock()
-	if err := fd.pd.prepareWrite(); err != nil {
-		return 0, err
-	}
-
-	var iovecs []syscall.Iovec
-	if fd.iovecs != nil {
-		iovecs = *fd.iovecs
-	}
-	// TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
-	// 1024 and this seems conservative enough for now. Darwin's
-	// UIO_MAXIOV also seems to be 1024.
-	maxVec := 1024
-
-	for len(*v) > 0 {
-		iovecs = iovecs[:0]
-		for _, chunk := range *v {
-			if len(chunk) == 0 {
-				continue
-			}
-			iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
-			if fd.isStream && len(chunk) > 1<<30 {
-				iovecs[len(iovecs)-1].SetLen(1 << 30)
-				break // continue chunk on next writev
-			}
-			iovecs[len(iovecs)-1].SetLen(len(chunk))
-			if len(iovecs) == maxVec {
-				break
-			}
-		}
-		if len(iovecs) == 0 {
-			break
-		}
-		fd.iovecs = &iovecs // cache
-
-		wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
-			uintptr(fd.sysfd),
-			uintptr(unsafe.Pointer(&iovecs[0])),
-			uintptr(len(iovecs)))
-		if wrote == ^uintptr(0) {
-			wrote = 0
-		}
-		testHookDidWritev(int(wrote))
-		n += int64(wrote)
-		v.consume(int64(wrote))
-		if e0 == syscall.EAGAIN {
-			if err = fd.pd.waitWrite(); err == nil {
-				continue
-			}
-		} else if e0 != 0 {
-			err = syscall.Errno(e0)
-		}
-		if err != nil {
-			break
-		}
-		if n == 0 {
-			err = io.ErrUnexpectedEOF
-			break
-		}
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("writev", err)
-	}
-	return n, err
+	n, err = fd.pfd.Writev((*[][]byte)(v))
+	runtime.KeepAlive(fd)
+	return n, wrapSyscallError("writev", err)
 }
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 03d949a..3424688 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -8,6 +8,7 @@ package os
 
 import (
 	"io"
+	"runtime"
 	"syscall"
 )
 
@@ -63,9 +64,10 @@ func (f *File) readdirnames(n int) (names []string, err error) {
 		if d.bufp >= d.nbuf {
 			d.bufp = 0
 			var errno error
-			d.nbuf, errno = fixCount(syscall.ReadDirent(f.fd, d.buf))
+			d.nbuf, errno = f.pfd.ReadDirent(d.buf)
+			runtime.KeepAlive(f)
 			if errno != nil {
-				return names, NewSyscallError("readdirent", errno)
+				return names, wrapSyscallError("readdirent", errno)
 			}
 			if d.nbuf <= 0 {
 				break // EOF
diff --git a/src/os/dir_windows.go b/src/os/dir_windows.go
index 76024fc..a738af2 100644
--- a/src/os/dir_windows.go
+++ b/src/os/dir_windows.go
@@ -6,6 +6,7 @@ package os
 
 import (
 	"io"
+	"runtime"
 	"syscall"
 )
 
@@ -16,9 +17,6 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
 	if !file.isdir() {
 		return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
 	}
-	if !file.dirinfo.isempty && file.fd == syscall.InvalidHandle {
-		return nil, syscall.EINVAL
-	}
 	wantAll := n <= 0
 	size := n
 	if wantAll {
@@ -29,7 +27,8 @@ 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(file.fd, d)
+			e := file.pfd.FindNextFile(d)
+			runtime.KeepAlive(file)
 			if e != nil {
 				if e == syscall.ERROR_NO_MORE_FILES {
 					break
@@ -57,7 +56,8 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
 				FileSizeHigh:   d.FileSizeHigh,
 				FileSizeLow:    d.FileSizeLow,
 			},
-			path: file.dirinfo.path + `\` + name,
+			path:             file.dirinfo.path,
+			appendNameToPath: true,
 		}
 		n--
 		fi = append(fi, f)
diff --git a/src/os/error_posix.go b/src/os/error_posix.go
new file mode 100644
index 0000000..2049e44
--- /dev/null
+++ b/src/os/error_posix.go
@@ -0,0 +1,18 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package os
+
+import "syscall"
+
+// wrapSyscallError takes an error and a syscall name. If the error is
+// a syscall.Errno, it wraps it in a os.SyscallError using the syscall name.
+func wrapSyscallError(name string, err error) error {
+	if _, ok := err.(syscall.Errno); ok {
+		err = NewSyscallError(name, err)
+	}
+	return err
+}
diff --git a/src/os/example_test.go b/src/os/example_test.go
index 07f9c76..d10bab4 100644
--- a/src/os/example_test.go
+++ b/src/os/example_test.go
@@ -21,6 +21,20 @@ func ExampleOpenFile() {
 	}
 }
 
+func ExampleOpenFile_append() {
+	// If the file doesn't exist, create it, or append to the file
+	f, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if _, err := f.Write([]byte("appended some data\n")); err != nil {
+		log.Fatal(err)
+	}
+	if err := f.Close(); err != nil {
+		log.Fatal(err)
+	}
+}
+
 func ExampleChmod() {
 	if err := os.Chmod("some-filename", 0644); err != nil {
 		log.Fatal(err)
diff --git a/src/os/exec/env_test.go b/src/os/exec/env_test.go
new file mode 100644
index 0000000..b5ac398
--- /dev/null
+++ b/src/os/exec/env_test.go
@@ -0,0 +1,39 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestDedupEnv(t *testing.T) {
+	tests := []struct {
+		noCase bool
+		in     []string
+		want   []string
+	}{
+		{
+			noCase: true,
+			in:     []string{"k1=v1", "k2=v2", "K1=v3"},
+			want:   []string{"K1=v3", "k2=v2"},
+		},
+		{
+			noCase: false,
+			in:     []string{"k1=v1", "K1=V2", "k1=v3"},
+			want:   []string{"k1=v3", "K1=V2"},
+		},
+		{
+			in:   []string{"=a", "=b", "foo", "bar"},
+			want: []string{"=b", "foo", "bar"},
+		},
+	}
+	for _, tt := range tests {
+		got := dedupEnvCase(tt.noCase, tt.in)
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("Dedup(%v, %q) = %q; want %q", tt.noCase, tt.in, got, tt.want)
+		}
+	}
+}
diff --git a/src/os/exec/example_test.go b/src/os/exec/example_test.go
index 5ccb21a..b70b990 100644
--- a/src/os/exec/example_test.go
+++ b/src/os/exec/example_test.go
@@ -12,6 +12,7 @@ import (
 	"io"
 	"io/ioutil"
 	"log"
+	"os"
 	"os/exec"
 	"strings"
 	"time"
@@ -37,6 +38,17 @@ func ExampleCommand() {
 	fmt.Printf("in all caps: %q\n", out.String())
 }
 
+func ExampleCommand_environment() {
+	cmd := exec.Command("prog")
+	cmd.Env = append(os.Environ(),
+		"FOO=duplicate_value", // ignored
+		"FOO=actual_value",    // this value is used
+	)
+	if err := cmd.Run(); err != nil {
+		log.Fatal(err)
+	}
+}
+
 func ExampleCmd_Output() {
 	out, err := exec.Command("date").Output()
 	if err != nil {
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index c4c5168..7f0d68b 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -55,7 +55,11 @@ type Cmd struct {
 	Args []string
 
 	// Env specifies the environment of the process.
-	// If Env is nil, Run uses the current process's environment.
+	// Each entry is of the form "key=value".
+	// If Env is nil, the new process uses the current process's
+	// environment.
+	// If Env contains duplicate environment keys, only the last
+	// value in the slice for each duplicate key is used.
 	Env []string
 
 	// Dir specifies the working directory of the command.
@@ -79,17 +83,14 @@ type Cmd struct {
 	// If either is nil, Run connects the corresponding file descriptor
 	// to the null device (os.DevNull).
 	//
-	// If Stdout and Stderr are the same writer, at most one
-	// goroutine at a time will call Write.
+	// If Stdout and Stderr are the same writer, and have a type that can be compared with ==,
+	// at most one goroutine at a time will call Write.
 	Stdout io.Writer
 	Stderr io.Writer
 
 	// ExtraFiles specifies additional open files to be inherited by the
 	// new process. It does not include standard input, standard output, or
 	// standard error. If non-nil, entry i becomes file descriptor 3+i.
-	//
-	// BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
-	// https://golang.org/issue/2603
 	ExtraFiles []*os.File
 
 	// SysProcAttr holds optional, operating system-specific attributes.
@@ -270,9 +271,8 @@ func (c *Cmd) closeDescriptors(closers []io.Closer) {
 // copying stdin, stdout, and stderr, and exits with a zero exit
 // status.
 //
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
+// If the command starts but does not complete successfully, the error is of
+// type *ExitError. Other error types may be returned for other situations.
 func (c *Cmd) Run() error {
 	if err := c.Start(); err != nil {
 		return err
@@ -354,7 +354,7 @@ func (c *Cmd) Start() error {
 	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
 		Dir:   c.Dir,
 		Files: c.childFiles,
-		Env:   c.envv(),
+		Env:   dedupEnv(c.envv()),
 		Sys:   c.SysProcAttr,
 	})
 	if err != nil {
@@ -712,3 +712,35 @@ func minInt(a, b int) int {
 	}
 	return b
 }
+
+// dedupEnv returns a copy of env with any duplicates removed, in favor of
+// later values.
+// Items not of the normal environment "key=value" form are preserved unchanged.
+func dedupEnv(env []string) []string {
+	return dedupEnvCase(runtime.GOOS == "windows", env)
+}
+
+// dedupEnvCase is dedupEnv with a case option for testing.
+// If caseInsensitive is true, the case of keys is ignored.
+func dedupEnvCase(caseInsensitive bool, env []string) []string {
+	out := make([]string, 0, len(env))
+	saw := map[string]int{} // key => index into out
+	for _, kv := range env {
+		eq := strings.Index(kv, "=")
+		if eq < 0 {
+			out = append(out, kv)
+			continue
+		}
+		k := kv[:eq]
+		if caseInsensitive {
+			k = strings.ToLower(k)
+		}
+		if dupIdx, isDup := saw[k]; isDup {
+			out[dupIdx] = kv
+			continue
+		}
+		saw[k] = len(out)
+		out = append(out, kv)
+	}
+	return out
+}
diff --git a/src/os/exec/exec_posix.go b/src/os/exec/exec_posix.go
deleted file mode 100644
index 5e11137..0000000
--- a/src/os/exec/exec_posix.go
+++ /dev/null
@@ -1,24 +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 !plan9
-
-package exec
-
-import (
-	"os"
-	"syscall"
-)
-
-func init() {
-	skipStdinCopyError = func(err error) bool {
-		// Ignore EPIPE errors copying to stdin if the program
-		// completed successfully otherwise.
-		// See Issue 9173.
-		pe, ok := err.(*os.PathError)
-		return ok &&
-			pe.Op == "write" && pe.Path == "|1" &&
-			pe.Err == syscall.EPIPE
-	}
-}
diff --git a/src/os/exec/exec_posix_test.go b/src/os/exec/exec_posix_test.go
new file mode 100644
index 0000000..865b6c3
--- /dev/null
+++ b/src/os/exec/exec_posix_test.go
@@ -0,0 +1,83 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package exec_test
+
+import (
+	"os/user"
+	"strconv"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestCredentialNoSetGroups(t *testing.T) {
+	u, err := user.Current()
+	if err != nil {
+		t.Fatalf("error getting current user: %v", err)
+	}
+
+	uid, err := strconv.Atoi(u.Uid)
+	if err != nil {
+		t.Fatalf("error converting Uid=%s to integer: %v", u.Uid, err)
+	}
+
+	gid, err := strconv.Atoi(u.Gid)
+	if err != nil {
+		t.Fatalf("error converting Gid=%s to integer: %v", u.Gid, err)
+	}
+
+	// If NoSetGroups is true, setgroups isn't called and cmd.Run should succeed
+	cmd := helperCommand(t, "echo", "foo")
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Credential: &syscall.Credential{
+			Uid:         uint32(uid),
+			Gid:         uint32(gid),
+			NoSetGroups: true,
+		},
+	}
+
+	if err = cmd.Run(); err != nil {
+		t.Errorf("Failed to run command: %v", err)
+	}
+}
+
+// For issue #19314: make sure that SIGSTOP does not cause the process
+// to appear done.
+func TestWaitid(t *testing.T) {
+	t.Parallel()
+
+	cmd := helperCommand(t, "sleep")
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	// The sleeps here are unnecessary in the sense that the test
+	// should still pass, but they are useful to make it more
+	// likely that we are testing the expected state of the child.
+	time.Sleep(100 * time.Millisecond)
+
+	if err := cmd.Process.Signal(syscall.SIGSTOP); err != nil {
+		cmd.Process.Kill()
+		t.Fatal(err)
+	}
+
+	ch := make(chan error)
+	go func() {
+		ch <- cmd.Wait()
+	}()
+
+	time.Sleep(100 * time.Millisecond)
+
+	if err := cmd.Process.Signal(syscall.SIGCONT); err != nil {
+		t.Error(err)
+		syscall.Kill(cmd.Process.Pid, syscall.SIGCONT)
+	}
+
+	cmd.Process.Kill()
+
+	<-ch
+}
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index bd20dd4..0132906 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -12,6 +12,7 @@ import (
 	"bytes"
 	"context"
 	"fmt"
+	"internal/poll"
 	"internal/testenv"
 	"io"
 	"io/ioutil"
@@ -288,8 +289,51 @@ func TestStdinCloseRace(t *testing.T) {
 
 // Issue 5071
 func TestPipeLookPathLeak(t *testing.T) {
-	fd0, lsof0 := numOpenFDS(t)
-	for i := 0; i < 4; i++ {
+	// If we are reading from /proc/self/fd we (should) get an exact result.
+	tolerance := 0
+
+	// Reading /proc/self/fd is more reliable than calling lsof, so try that
+	// first.
+	numOpenFDs := func() (int, []byte, error) {
+		fds, err := ioutil.ReadDir("/proc/self/fd")
+		if err != nil {
+			return 0, nil, err
+		}
+		return len(fds), nil, nil
+	}
+	want, before, err := numOpenFDs()
+	if err != nil {
+		// We encountered a problem reading /proc/self/fd (we might be on
+		// a platform that doesn't have it). Fall back onto lsof.
+		t.Logf("using lsof because: %v", err)
+		numOpenFDs = func() (int, []byte, error) {
+			// Android's stock lsof does not obey the -p option,
+			// so extra filtering is needed.
+			// https://golang.org/issue/10206
+			if runtime.GOOS == "android" {
+				// numOpenFDsAndroid handles errors itself and
+				// might skip or fail the test.
+				n, lsof := numOpenFDsAndroid(t)
+				return n, lsof, nil
+			}
+			lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+			return bytes.Count(lsof, []byte("\n")), lsof, err
+		}
+
+		// lsof may see file descriptors associated with the fork itself,
+		// so we allow some extra margin if we have to use it.
+		// https://golang.org/issue/19243
+		tolerance = 5
+
+		// Retry reading the number of open file descriptors.
+		want, before, err = numOpenFDs()
+		if err != nil {
+			t.Log(err)
+			t.Skipf("skipping test; error finding or running lsof")
+		}
+	}
+
+	for i := 0; i < 6; i++ {
 		cmd := exec.Command("something-that-does-not-exist-binary")
 		cmd.StdoutPipe()
 		cmd.StderrPipe()
@@ -298,36 +342,20 @@ func TestPipeLookPathLeak(t *testing.T) {
 			t.Fatal("unexpected success")
 		}
 	}
-	for triesLeft := 3; triesLeft >= 0; triesLeft-- {
-		open, lsof := numOpenFDS(t)
-		fdGrowth := open - fd0
-		if fdGrowth > 2 {
-			if triesLeft > 0 {
-				// Work around what appears to be a race with Linux's
-				// proc filesystem (as used by lsof). It seems to only
-				// be eventually consistent. Give it awhile to settle.
-				// See golang.org/issue/7808
-				time.Sleep(100 * time.Millisecond)
-				continue
-			}
-			t.Errorf("leaked %d fds; want ~0; have:\n%s\noriginally:\n%s", fdGrowth, lsof, lsof0)
-		}
-		break
-	}
-}
-
-func numOpenFDS(t *testing.T) (n int, lsof []byte) {
-	if runtime.GOOS == "android" {
-		// Android's stock lsof does not obey the -p option,
-		// so extra filtering is needed. (golang.org/issue/10206)
-		return numOpenFDsAndroid(t)
-	}
-
-	lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+	got, after, err := numOpenFDs()
 	if err != nil {
-		t.Skip("skipping test; error finding or running lsof")
+		// numOpenFDs has already succeeded once, it should work here.
+		t.Errorf("unexpected failure: %v", err)
+	}
+	if got-want > tolerance {
+		t.Errorf("number of open file descriptors changed: got %v, want %v", got, want)
+		if before != nil {
+			t.Errorf("before:\n%v\n", before)
+		}
+		if after != nil {
+			t.Errorf("after:\n%v\n", after)
+		}
 	}
-	return bytes.Count(lsof, []byte("\n")), lsof
 }
 
 func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) {
@@ -373,12 +401,16 @@ var testedAlreadyLeaked = false
 
 // basefds returns the number of expected file descriptors
 // to be present in a process at start.
+// stdin, stdout, stderr, epoll/kqueue
 func basefds() uintptr {
 	return os.Stderr.Fd() + 1
 }
 
 func closeUnexpectedFds(t *testing.T, m string) {
 	for fd := basefds(); fd <= 101; fd++ {
+		if fd == poll.PollDescriptor() {
+			continue
+		}
 		err := os.NewFile(fd, "").Close()
 		if err == nil {
 			t.Logf("%s: Something already leaked - closed fd %d", m, fd)
@@ -661,6 +693,11 @@ func TestHelperProcess(*testing.T) {
 			iargs = append(iargs, s)
 		}
 		fmt.Println(iargs...)
+	case "echoenv":
+		for _, s := range args {
+			fmt.Println(os.Getenv(s))
+		}
+		os.Exit(0)
 	case "cat":
 		if len(args) == 0 {
 			io.Copy(os.Stdout, os.Stdin)
@@ -736,6 +773,9 @@ func TestHelperProcess(*testing.T) {
 			// Now verify that there are no other open fds.
 			var files []*os.File
 			for wantfd := basefds() + 1; wantfd <= 100; wantfd++ {
+				if wantfd == poll.PollDescriptor() {
+					continue
+				}
 				f, err := os.Open(os.Args[0])
 				if err != nil {
 					fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
@@ -828,31 +868,50 @@ func TestHelperProcess(*testing.T) {
 	case "stderrfail":
 		fmt.Fprintf(os.Stderr, "some stderr text\n")
 		os.Exit(1)
+	case "sleep":
+		time.Sleep(3 * time.Second)
+		os.Exit(0)
 	default:
 		fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
 		os.Exit(2)
 	}
 }
 
+type delayedInfiniteReader struct{}
+
+func (delayedInfiniteReader) Read(b []byte) (int, error) {
+	time.Sleep(100 * time.Millisecond)
+	for i := range b {
+		b[i] = 'x'
+	}
+	return len(b), nil
+}
+
 // Issue 9173: ignore stdin pipe writes if the program completes successfully.
 func TestIgnorePipeErrorOnSuccess(t *testing.T) {
 	testenv.MustHaveExec(t)
 
-	// We really only care about testing this on Unixy things.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+	// We really only care about testing this on Unixy and Windowsy things.
+	if runtime.GOOS == "plan9" {
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	cmd := helperCommand(t, "echo", "foo")
-	var out bytes.Buffer
-	cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20))
-	cmd.Stdout = &out
-	if err := cmd.Run(); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := out.String(), "foo\n"; got != want {
-		t.Errorf("output = %q; want %q", got, want)
+	testWith := func(r io.Reader) func(*testing.T) {
+		return func(t *testing.T) {
+			cmd := helperCommand(t, "echo", "foo")
+			var out bytes.Buffer
+			cmd.Stdin = r
+			cmd.Stdout = &out
+			if err := cmd.Run(); err != nil {
+				t.Fatal(err)
+			}
+			if got, want := out.String(), "foo\n"; got != want {
+				t.Errorf("output = %q; want %q", got, want)
+			}
+		}
 	}
+	t.Run("10MB", testWith(strings.NewReader(strings.Repeat("x", 10<<20))))
+	t.Run("Infinite", testWith(delayedInfiniteReader{}))
 }
 
 type badWriter struct{}
@@ -1008,3 +1067,18 @@ func TestContextCancel(t *testing.T) {
 		t.Logf("exit status: %v", err)
 	}
 }
+
+// test that environment variables are de-duped.
+func TestDedupEnvEcho(t *testing.T) {
+	testenv.MustHaveExec(t)
+
+	cmd := helperCommand(t, "echoenv", "FOO")
+	cmd.Env = append(cmd.Env, "FOO=bad", "FOO=good")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got, want := strings.TrimSpace(string(out)), "good"; got != want {
+		t.Errorf("output = %q; want %q", got, want)
+	}
+}
diff --git a/src/os/exec/exec_unix.go b/src/os/exec/exec_unix.go
new file mode 100644
index 0000000..9c3e17d
--- /dev/null
+++ b/src/os/exec/exec_unix.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!windows
+
+package exec
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	skipStdinCopyError = func(err error) bool {
+		// Ignore EPIPE errors copying to stdin if the program
+		// completed successfully otherwise.
+		// See Issue 9173.
+		pe, ok := err.(*os.PathError)
+		return ok &&
+			pe.Op == "write" && pe.Path == "|1" &&
+			pe.Err == syscall.EPIPE
+	}
+}
diff --git a/src/os/exec/exec_windows.go b/src/os/exec/exec_windows.go
new file mode 100644
index 0000000..af8cd97
--- /dev/null
+++ b/src/os/exec/exec_windows.go
@@ -0,0 +1,23 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	skipStdinCopyError = func(err error) bool {
+		// Ignore ERROR_BROKEN_PIPE and ERROR_NO_DATA errors copying
+		// to stdin if the program completed successfully otherwise.
+		// See Issue 20445.
+		const _ERROR_NO_DATA = syscall.Errno(0xe8)
+		pe, ok := err.(*os.PathError)
+		return ok &&
+			pe.Op == "write" && pe.Path == "|1" &&
+			(pe.Err == syscall.ERROR_BROKEN_PIPE || pe.Err == _ERROR_NO_DATA)
+	}
+}
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index d89db20..d5d553a 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -97,17 +97,79 @@ func findProcess(pid int) (p *Process, err error) {
 }
 
 func init() {
-	var argc int32
-	cmd := syscall.GetCommandLine()
-	argv, e := syscall.CommandLineToArgv(cmd, &argc)
-	if e != nil {
-		return
+	p := syscall.GetCommandLine()
+	cmd := syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(p))[:])
+	if len(cmd) == 0 {
+		arg0, _ := Executable()
+		Args = []string{arg0}
+	} else {
+		Args = commandLineToArgv(cmd)
 	}
-	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
-	Args = make([]string, argc)
-	for i, v := range (*argv)[:argc] {
-		Args[i] = syscall.UTF16ToString((*v)[:])
+}
+
+// appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
+func appendBSBytes(b []byte, n int) []byte {
+	for ; n > 0; n-- {
+		b = append(b, '\\')
+	}
+	return b
+}
+
+// readNextArg splits command line string cmd into next
+// argument and command line remainder.
+func readNextArg(cmd string) (arg []byte, rest string) {
+	var b []byte
+	var inquote bool
+	var nslash int
+	for ; len(cmd) > 0; cmd = cmd[1:] {
+		c := cmd[0]
+		switch c {
+		case ' ', '\t':
+			if !inquote {
+				return appendBSBytes(b, nslash), cmd[1:]
+			}
+		case '"':
+			b = appendBSBytes(b, nslash/2)
+			if nslash%2 == 0 {
+				// use "Prior to 2008" rule from
+				// http://daviddeley.com/autohotkey/parameters/parameters.htm
+				// section 5.2 to deal with double double quotes
+				if inquote && len(cmd) > 1 && cmd[1] == '"' {
+					b = append(b, c)
+					cmd = cmd[1:]
+				}
+				inquote = !inquote
+			} else {
+				b = append(b, c)
+			}
+			nslash = 0
+			continue
+		case '\\':
+			nslash++
+			continue
+		}
+		b = appendBSBytes(b, nslash)
+		nslash = 0
+		b = append(b, c)
+	}
+	return appendBSBytes(b, nslash), ""
+}
+
+// commandLineToArgv splits a command line into individual argument
+// strings, following the Windows conventions documented
+// at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
+func commandLineToArgv(cmd string) []string {
+	var args []string
+	for len(cmd) > 0 {
+		if cmd[0] == ' ' || cmd[0] == '\t' {
+			cmd = cmd[1:]
+			continue
+		}
+		var arg []byte
+		arg, cmd = readNextArg(cmd)
+		args = append(args, string(arg))
 	}
+	return args
 }
 
 func ftToDuration(ft *syscall.Filetime) time.Duration {
diff --git a/src/os/export_windows_test.go b/src/os/export_windows_test.go
index 3bb2d20..f36fadb 100644
--- a/src/os/export_windows_test.go
+++ b/src/os/export_windows_test.go
@@ -7,7 +7,7 @@ package os
 // Export for testing.
 
 var (
-	FixLongPath     = fixLongPath
-	NewConsoleFile  = newConsoleFile
-	ReadConsoleFunc = &readConsole
+	FixLongPath       = fixLongPath
+	NewConsoleFile    = newConsoleFile
+	CommandLineToArgv = commandLineToArgv
 )
diff --git a/src/os/file.go b/src/os/file.go
index d45a00b..876bffd 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -37,6 +37,8 @@
 package os
 
 import (
+	"errors"
+	"internal/poll"
 	"io"
 	"syscall"
 )
@@ -99,13 +101,7 @@ func (f *File) Read(b []byte) (n int, err error) {
 		return 0, err
 	}
 	n, e := f.read(b)
-	if n == 0 && len(b) > 0 && e == nil {
-		return 0, io.EOF
-	}
-	if e != nil {
-		err = &PathError{"read", f.name, e}
-	}
-	return n, err
+	return n, f.wrapErr("read", e)
 }
 
 // ReadAt reads len(b) bytes from the File starting at byte offset off.
@@ -116,13 +112,15 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
 	if err := f.checkValid("read"); err != nil {
 		return 0, err
 	}
+
+	if off < 0 {
+		return 0, &PathError{"readat", f.name, errors.New("negative offset")}
+	}
+
 	for len(b) > 0 {
 		m, e := f.pread(b, off)
-		if m == 0 && e == nil {
-			return n, io.EOF
-		}
 		if e != nil {
-			err = &PathError{"read", f.name, e}
+			err = f.wrapErr("read", e)
 			break
 		}
 		n += m
@@ -150,8 +148,9 @@ func (f *File) Write(b []byte) (n int, err error) {
 	epipecheck(f, e)
 
 	if e != nil {
-		err = &PathError{"write", f.name, e}
+		err = f.wrapErr("write", e)
 	}
+
 	return n, err
 }
 
@@ -162,10 +161,15 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
 	if err := f.checkValid("write"); err != nil {
 		return 0, err
 	}
+
+	if off < 0 {
+		return 0, &PathError{"writeat", f.name, errors.New("negative offset")}
+	}
+
 	for len(b) > 0 {
 		m, e := f.pwrite(b, off)
 		if e != nil {
-			err = &PathError{"write", f.name, e}
+			err = f.wrapErr("write", e)
 			break
 		}
 		n += m
@@ -189,7 +193,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
 		e = syscall.EISDIR
 	}
 	if e != nil {
-		return 0, &PathError{"seek", f.name, e}
+		return 0, f.wrapErr("seek", e)
 	}
 	return r, nil
 }
@@ -226,19 +230,6 @@ func Chdir(dir string) error {
 	return nil
 }
 
-// Chdir changes the current working directory to the file,
-// which must be a directory.
-// If there is an error, it will be of type *PathError.
-func (f *File) Chdir() error {
-	if err := f.checkValid("chdir"); err != nil {
-		return err
-	}
-	if e := syscall.Fchdir(f.fd); e != nil {
-		return &PathError{"chdir", f.name, e}
-	}
-	return nil
-}
-
 // 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.
@@ -276,14 +267,28 @@ func fixCount(n int, err error) (int, error) {
 	return n, err
 }
 
-// checkValid checks whether f is valid for use.
-// If not, it returns an appropriate error, perhaps incorporating the operation name op.
-func (f *File) checkValid(op string) error {
-	if f == nil {
-		return ErrInvalid
+// wrapErr wraps an error that occurred during an operation on an open file.
+// It passes io.EOF through unchanged, otherwise converts
+// poll.ErrFileClosing to ErrClosed and wraps the error in a PathError.
+func (f *File) wrapErr(op string, err error) error {
+	if err == nil || err == io.EOF {
+		return err
 	}
-	if f.fd == badFd {
-		return &PathError{op, f.name, ErrClosed}
+	if err == poll.ErrFileClosing {
+		err = ErrClosed
 	}
-	return nil
+	return &PathError{op, f.name, err}
+}
+
+// TempDir returns the default directory to use for temporary files.
+//
+// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
+// On Windows, it uses GetTempPath, returning the first non-empty
+// value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
+// On Plan 9, it returns /tmp.
+//
+// The directory is neither guaranteed to exist nor have accessible
+// permissions.
+func TempDir() string {
+	return tempDir()
 }
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index 5276a7e..d0d230b 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -35,7 +35,9 @@ func (f *File) Fd() uintptr {
 	return uintptr(f.fd)
 }
 
-// NewFile returns a new File with the given file descriptor and name.
+// NewFile returns a new File with the given file descriptor and
+// name. The returned value will be nil if fd is not a valid file
+// descriptor.
 func NewFile(fd uintptr, name string) *File {
 	fdi := int(fd)
 	if fdi < 0 {
@@ -244,14 +246,22 @@ func (f *File) Sync() error {
 // read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 func (f *File) read(b []byte) (n int, err error) {
-	return fixCount(syscall.Read(f.fd, b))
+	n, e := fixCount(syscall.Read(f.fd, b))
+	if n == 0 && len(b) > 0 && e == nil {
+		return 0, io.EOF
+	}
+	return n, e
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
 // EOF is signaled by a zero count with err set to nil.
 func (f *File) pread(b []byte, off int64) (n int, err error) {
-	return fixCount(syscall.Pread(f.fd, b, off))
+	n, e := fixCount(syscall.Pread(f.fd, b, off))
+	if n == 0 && len(b) > 0 && e == nil {
+		return 0, io.EOF
+	}
+	return n, e
 }
 
 // write writes len(b) bytes to the File.
@@ -468,7 +478,31 @@ func (f *File) Chown(uid, gid int) error {
 	return &PathError{"chown", f.name, syscall.EPLAN9}
 }
 
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
+func tempDir() string {
 	return "/tmp"
 }
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+// If there is an error, it will be of type *PathError.
+func (f *File) Chdir() error {
+	if err := f.checkValid("chdir"); err != nil {
+		return err
+	}
+	if e := syscall.Fchdir(f.fd); e != nil {
+		return &PathError{"chdir", f.name, e}
+	}
+	return nil
+}
+
+// checkValid checks whether f is valid for use.
+// If not, it returns an appropriate error, perhaps incorporating the operation name op.
+func (f *File) checkValid(op string) error {
+	if f == nil {
+		return ErrInvalid
+	}
+	if f.fd == badFd {
+		return &PathError{op, f.name, ErrClosed}
+	}
+	return nil
+}
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index d817f34..6ee7eeb 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -60,8 +60,8 @@ func (f *File) Chmod(mode FileMode) error {
 	if err := f.checkValid("chmod"); err != nil {
 		return err
 	}
-	if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
-		return &PathError{"chmod", f.name, e}
+	if e := f.pfd.Fchmod(syscallMode(mode)); e != nil {
+		return f.wrapErr("chmod", e)
 	}
 	return nil
 }
@@ -92,8 +92,8 @@ func (f *File) Chown(uid, gid int) error {
 	if err := f.checkValid("chown"); err != nil {
 		return err
 	}
-	if e := syscall.Fchown(f.fd, uid, gid); e != nil {
-		return &PathError{"chown", f.name, e}
+	if e := f.pfd.Fchown(uid, gid); e != nil {
+		return f.wrapErr("chown", e)
 	}
 	return nil
 }
@@ -105,8 +105,8 @@ func (f *File) Truncate(size int64) error {
 	if err := f.checkValid("truncate"); err != nil {
 		return err
 	}
-	if e := syscall.Ftruncate(f.fd, size); e != nil {
-		return &PathError{"truncate", f.name, e}
+	if e := f.pfd.Ftruncate(size); e != nil {
+		return f.wrapErr("truncate", e)
 	}
 	return nil
 }
@@ -118,8 +118,8 @@ func (f *File) Sync() error {
 	if err := f.checkValid("sync"); err != nil {
 		return err
 	}
-	if e := syscall.Fsync(f.fd); e != nil {
-		return &PathError{"sync", f.name, e}
+	if e := f.pfd.Fsync(); e != nil {
+		return f.wrapErr("sync", e)
 	}
 	return nil
 }
@@ -139,3 +139,25 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
 	}
 	return nil
 }
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+// If there is an error, it will be of type *PathError.
+func (f *File) Chdir() error {
+	if err := f.checkValid("chdir"); err != nil {
+		return err
+	}
+	if e := f.pfd.Fchdir(); e != nil {
+		return f.wrapErr("chdir", e)
+	}
+	return nil
+}
+
+// checkValid checks whether f is valid for use.
+// If not, it returns an appropriate error, perhaps incorporating the operation name op.
+func (f *File) checkValid(op string) error {
+	if f == nil {
+		return ErrInvalid
+	}
+	return nil
+}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 1cff93a..8b600d8 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -7,6 +7,7 @@
 package os
 
 import (
+	"internal/poll"
 	"runtime"
 	"syscall"
 )
@@ -19,11 +20,22 @@ func fixLongPath(path string) string {
 func rename(oldname, newname string) error {
 	fi, err := Lstat(newname)
 	if err == nil && fi.IsDir() {
+		// There are two independent errors this function can return:
+		// one for a bad oldname, and one for a bad newname.
+		// At this point we've determined the newname is bad.
+		// But just in case oldname is also bad, prioritize returning
+		// the oldname error because that's what we did historically.
+		if _, err := Lstat(oldname); err != nil {
+			if pe, ok := err.(*PathError); ok {
+				err = pe.Err
+			}
+			return &LinkError{"rename", oldname, newname, err}
+		}
 		return &LinkError{"rename", oldname, newname, syscall.EEXIST}
 	}
-	e := syscall.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
+	err = syscall.Rename(oldname, newname)
+	if err != nil {
+		return &LinkError{"rename", oldname, newname, err}
 	}
 	return nil
 }
@@ -33,9 +45,10 @@ func rename(oldname, newname string) error {
 // can overwrite this data, which could cause the finalizer
 // to close the wrong file descriptor.
 type file struct {
-	fd      int
-	name    string
-	dirinfo *dirInfo // nil unless directory being read
+	pfd      poll.FD
+	name     string
+	dirinfo  *dirInfo // nil unless directory being read
+	nonblock bool     // whether we set nonblocking mode
 }
 
 // Fd returns the integer Unix file descriptor referencing the open file.
@@ -44,16 +57,64 @@ func (f *File) Fd() uintptr {
 	if f == nil {
 		return ^(uintptr(0))
 	}
-	return uintptr(f.fd)
+
+	// If we put the file descriptor into nonblocking mode,
+	// then set it to blocking mode before we return it,
+	// because historically we have always returned a descriptor
+	// opened in blocking mode. The File will continue to work,
+	// but any blocking operation will tie up a thread.
+	if f.nonblock {
+		syscall.SetNonblock(f.pfd.Sysfd, false)
+	}
+
+	return uintptr(f.pfd.Sysfd)
 }
 
-// NewFile returns a new File with the given file descriptor and name.
+// NewFile returns a new File with the given file descriptor and
+// name. The returned value will be nil if fd is not a valid file
+// descriptor.
 func NewFile(fd uintptr, name string) *File {
+	return newFile(fd, name, false)
+}
+
+// newFile is like NewFile, but if pollable is true it tries to add the
+// file to the runtime poller.
+func newFile(fd uintptr, name string, pollable bool) *File {
 	fdi := int(fd)
 	if fdi < 0 {
 		return nil
 	}
-	f := &File{&file{fd: fdi, name: name}}
+	f := &File{&file{
+		pfd: poll.FD{
+			Sysfd:         fdi,
+			IsStream:      true,
+			ZeroReadIsEOF: true,
+		},
+		name: name,
+	}}
+
+	// Don't try to use kqueue with regular files on FreeBSD.
+	// It crashes the system unpredictably while running all.bash.
+	// Issue 19093.
+	if runtime.GOOS == "freebsd" {
+		pollable = false
+	}
+
+	if err := f.pfd.Init("file", pollable); err != nil {
+		// An error here indicates a failure to register
+		// with the netpoll system. That can happen for
+		// a file descriptor that is not supported by
+		// epoll/kqueue; for example, disk files on
+		// GNU/Linux systems. We assume that any real error
+		// will show up in later I/O.
+	} else if pollable {
+		// We successfully registered with netpoll, so put
+		// the file into nonblocking mode.
+		if err := syscall.SetNonblock(fdi, true); err == nil {
+			f.nonblock = true
+		}
+	}
+
 	runtime.SetFinalizer(f.file, (*file).close)
 	return f
 }
@@ -69,7 +130,7 @@ type dirInfo struct {
 // output or standard error. See the SIGPIPE docs in os/signal, and
 // issue 11845.
 func epipecheck(file *File, e error) {
-	if e == syscall.EPIPE && (file.fd == 1 || file.fd == 2) {
+	if e == syscall.EPIPE && (file.pfd.Sysfd == 1 || file.pfd.Sysfd == 2) {
 		sigpipe()
 	}
 }
@@ -120,7 +181,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 		syscall.CloseOnExec(r)
 	}
 
-	return NewFile(uintptr(r), name), nil
+	return newFile(uintptr(r), name, true), nil
 }
 
 // Close closes the File, rendering it unusable for I/O.
@@ -133,83 +194,53 @@ func (f *File) Close() error {
 }
 
 func (file *file) close() error {
-	if file == nil || file.fd == badFd {
+	if file == nil {
 		return syscall.EINVAL
 	}
 	var err error
-	if e := syscall.Close(file.fd); e != nil {
+	if e := file.pfd.Close(); e != nil {
+		if e == poll.ErrFileClosing {
+			e = ErrClosed
+		}
 		err = &PathError{"close", file.name, e}
 	}
-	file.fd = -1 // so it can't be closed again
 
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(file, nil)
 	return err
 }
 
-// Darwin and FreeBSD can't read or write 2GB+ at a time,
-// even on 64-bit systems. See golang.org/issue/7812.
-// Use 1GB instead of, say, 2GB-1, to keep subsequent
-// reads aligned.
-const (
-	needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
-	maxRW      = 1 << 30
-)
-
 // read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 func (f *File) read(b []byte) (n int, err error) {
-	if needsMaxRW && len(b) > maxRW {
-		b = b[:maxRW]
-	}
-	return fixCount(syscall.Read(f.fd, b))
+	n, err = f.pfd.Read(b)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
 // EOF is signaled by a zero count with err set to nil.
 func (f *File) pread(b []byte, off int64) (n int, err error) {
-	if needsMaxRW && len(b) > maxRW {
-		b = b[:maxRW]
-	}
-	return fixCount(syscall.Pread(f.fd, b, off))
+	n, err = f.pfd.Pread(b, off)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // write writes len(b) bytes to the File.
 // It returns the number of bytes written and an error, if any.
 func (f *File) write(b []byte) (n int, err error) {
-	for {
-		bcap := b
-		if needsMaxRW && len(bcap) > maxRW {
-			bcap = bcap[:maxRW]
-		}
-		m, err := fixCount(syscall.Write(f.fd, bcap))
-		n += m
-
-		// If the syscall wrote some data but not all (short write)
-		// or it returned EINTR, then assume it stopped early for
-		// reasons that are uninteresting to the caller, and try again.
-		if 0 < m && m < len(bcap) || err == syscall.EINTR {
-			b = b[m:]
-			continue
-		}
-
-		if needsMaxRW && len(bcap) != len(b) && err == nil {
-			b = b[m:]
-			continue
-		}
-
-		return n, err
-	}
+	n, err = f.pfd.Write(b)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // pwrite writes len(b) bytes to the File starting at byte offset off.
 // It returns the number of bytes written and an error, if any.
 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
-	if needsMaxRW && len(b) > maxRW {
-		b = b[:maxRW]
-	}
-	return fixCount(syscall.Pwrite(f.fd, b, off))
+	n, err = f.pfd.Pwrite(b, off)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // seek sets the offset for the next Read or Write on file to offset, interpreted
@@ -217,7 +248,9 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
 // relative to the current offset, and 2 means relative to the end.
 // It returns the new offset and an error, if any.
 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
-	return syscall.Seek(f.fd, offset, whence)
+	ret, err = f.pfd.Seek(offset, whence)
+	runtime.KeepAlive(f)
+	return ret, err
 }
 
 // Truncate changes the size of the named file.
@@ -261,8 +294,7 @@ func Remove(name string) error {
 	return &PathError{"remove", name, e}
 }
 
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
+func tempDir() string {
 	dir := Getenv("TMPDIR")
 	if dir == "" {
 		if runtime.GOOS == "android" {
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index 97be324..93b6c13 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -5,13 +5,11 @@
 package os
 
 import (
+	"internal/poll"
 	"internal/syscall/windows"
-	"io"
 	"runtime"
-	"sync"
 	"syscall"
 	"unicode/utf16"
-	"unicode/utf8"
 	"unsafe"
 )
 
@@ -20,17 +18,9 @@ import (
 // can overwrite this data, which could cause the finalizer
 // to close the wrong file descriptor.
 type file struct {
-	fd      syscall.Handle
+	pfd     poll.FD
 	name    string
-	dirinfo *dirInfo   // nil unless directory being read
-	l       sync.Mutex // used to implement windows pread/pwrite
-
-	// only for console io
-	isConsole      bool
-	lastbits       []byte   // first few bytes of the last incomplete rune in last write
-	readuint16     []uint16 // buffer to hold uint16s obtained with ReadConsole
-	readbyte       []byte   // buffer to hold decoding of readuint16 from utf16 to utf8
-	readbyteOffset int      // readbyte[readOffset:] is yet to be consumed with file.Read
+	dirinfo *dirInfo // nil unless directory being read
 }
 
 // Fd returns the Windows handle referencing the open file.
@@ -39,35 +29,50 @@ func (file *File) Fd() uintptr {
 	if file == nil {
 		return uintptr(syscall.InvalidHandle)
 	}
-	return uintptr(file.fd)
+	return uintptr(file.pfd.Sysfd)
 }
 
 // newFile returns a new File with the given file handle and name.
 // Unlike NewFile, it does not check that h is syscall.InvalidHandle.
-func newFile(h syscall.Handle, name string) *File {
-	f := &File{&file{fd: h, name: name}}
+func newFile(h syscall.Handle, name string, kind string) *File {
+	if kind == "file" {
+		var m uint32
+		if syscall.GetConsoleMode(h, &m) == nil {
+			kind = "console"
+		}
+	}
+
+	f := &File{&file{
+		pfd: poll.FD{
+			Sysfd:         h,
+			IsStream:      true,
+			ZeroReadIsEOF: true,
+		},
+		name: name,
+	}}
 	runtime.SetFinalizer(f.file, (*file).close)
+
+	// Ignore initialization errors.
+	// Assume any problems will show up in later I/O.
+	f.pfd.Init(kind)
+
 	return f
 }
 
 // newConsoleFile creates new File that will be used as console.
 func newConsoleFile(h syscall.Handle, name string) *File {
-	f := newFile(h, name)
-	f.isConsole = true
-	return f
+	return newFile(h, name, "console")
 }
 
-// NewFile returns a new File with the given file descriptor and name.
+// NewFile returns a new File with the given file descriptor and
+// name. The returned value will be nil if fd is not a valid file
+// descriptor.
 func NewFile(fd uintptr, name string) *File {
 	h := syscall.Handle(fd)
 	if h == syscall.InvalidHandle {
 		return nil
 	}
-	var m uint32
-	if syscall.GetConsoleMode(h, &m) == nil {
-		return newConsoleFile(h, name)
-	}
-	return newFile(h, name)
+	return newFile(h, name, "file")
 }
 
 // Auxiliary information if the File describes a directory
@@ -90,7 +95,7 @@ func openFile(name string, flag int, perm FileMode) (file *File, err error) {
 	if e != nil {
 		return nil, e
 	}
-	return NewFile(uintptr(r), name), nil
+	return newFile(r, name, "file"), nil
 }
 
 func openDir(name string) (file *File, err error) {
@@ -137,7 +142,7 @@ func openDir(name string) (file *File, err error) {
 			return nil, e
 		}
 	}
-	f := newFile(r, name)
+	f := newFile(r, name, "dir")
 	f.dirinfo = d
 	return f, nil
 }
@@ -183,213 +188,50 @@ func (file *file) close() error {
 		// "special" empty directories
 		return nil
 	}
-	if file.fd == syscall.InvalidHandle {
-		return syscall.EINVAL
-	}
-	var e error
-	if file.isdir() {
-		e = syscall.FindClose(file.fd)
-	} else {
-		e = syscall.CloseHandle(file.fd)
-	}
 	var err error
-	if e != nil {
+	if e := file.pfd.Close(); e != nil {
+		if e == poll.ErrFileClosing {
+			e = ErrClosed
+		}
 		err = &PathError{"close", file.name, e}
 	}
-	file.fd = badFd // so it can't be closed again
 
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(file, nil)
 	return err
 }
 
-var readConsole = syscall.ReadConsole // changed for testing
-
-// readConsole reads utf16 characters from console File,
-// encodes them into utf8 and stores them in buffer b.
-// It returns the number of utf8 bytes read and an error, if any.
-func (f *File) readConsole(b []byte) (n int, err error) {
-	if len(b) == 0 {
-		return 0, nil
-	}
-
-	if f.readuint16 == nil {
-		// Note: syscall.ReadConsole fails for very large buffers.
-		// The limit is somewhere around (but not exactly) 16384.
-		// Stay well below.
-		f.readuint16 = make([]uint16, 0, 10000)
-		f.readbyte = make([]byte, 0, 4*cap(f.readuint16))
-	}
-
-	for f.readbyteOffset >= len(f.readbyte) {
-		n := cap(f.readuint16) - len(f.readuint16)
-		if n > len(b) {
-			n = len(b)
-		}
-		var nw uint32
-		err := readConsole(f.fd, &f.readuint16[:len(f.readuint16)+1][len(f.readuint16)], uint32(n), &nw, nil)
-		if err != nil {
-			return 0, err
-		}
-		uint16s := f.readuint16[:len(f.readuint16)+int(nw)]
-		f.readuint16 = f.readuint16[:0]
-		buf := f.readbyte[:0]
-		for i := 0; i < len(uint16s); i++ {
-			r := rune(uint16s[i])
-			if utf16.IsSurrogate(r) {
-				if i+1 == len(uint16s) {
-					if nw > 0 {
-						// Save half surrogate pair for next time.
-						f.readuint16 = f.readuint16[:1]
-						f.readuint16[0] = uint16(r)
-						break
-					}
-					r = utf8.RuneError
-				} else {
-					r = utf16.DecodeRune(r, rune(uint16s[i+1]))
-					if r != utf8.RuneError {
-						i++
-					}
-				}
-			}
-			n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
-			buf = buf[:len(buf)+n]
-		}
-		f.readbyte = buf
-		f.readbyteOffset = 0
-		if nw == 0 {
-			break
-		}
-	}
-
-	src := f.readbyte[f.readbyteOffset:]
-	var i int
-	for i = 0; i < len(src) && i < len(b); i++ {
-		x := src[i]
-		if x == 0x1A { // Ctrl-Z
-			if i == 0 {
-				f.readbyteOffset++
-			}
-			break
-		}
-		b[i] = x
-	}
-	f.readbyteOffset += i
-	return i, nil
-}
-
 // read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 func (f *File) read(b []byte) (n int, err error) {
-	f.l.Lock()
-	defer f.l.Unlock()
-	if f.isConsole {
-		return f.readConsole(b)
-	}
-	return fixCount(syscall.Read(f.fd, b))
+	n, err = f.pfd.Read(b)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
 // EOF is signaled by a zero count with err set to 0.
 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, io.SeekCurrent)
-	if e != nil {
-		return 0, e
-	}
-	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
-	o := syscall.Overlapped{
-		OffsetHigh: uint32(off >> 32),
-		Offset:     uint32(off),
-	}
-	var done uint32
-	e = syscall.ReadFile(f.fd, b, &done, &o)
-	if e != nil {
-		if e == syscall.ERROR_HANDLE_EOF {
-			// end of file
-			return 0, nil
-		}
-		return 0, e
-	}
-	return int(done), nil
-}
-
-// writeConsole writes len(b) bytes to the console File.
-// It returns the number of bytes written and an error, if any.
-func (f *File) writeConsole(b []byte) (n int, err error) {
-	n = len(b)
-	runes := make([]rune, 0, 256)
-	if len(f.lastbits) > 0 {
-		b = append(f.lastbits, b...)
-		f.lastbits = nil
-
-	}
-	for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
-		r, l := utf8.DecodeRune(b)
-		runes = append(runes, r)
-		b = b[l:]
-	}
-	if len(b) > 0 {
-		f.lastbits = make([]byte, len(b))
-		copy(f.lastbits, b)
-	}
-	// syscall.WriteConsole seems to fail, if given large buffer.
-	// So limit the buffer to 16000 characters. This number was
-	// discovered by experimenting with syscall.WriteConsole.
-	const maxWrite = 16000
-	for len(runes) > 0 {
-		m := len(runes)
-		if m > maxWrite {
-			m = maxWrite
-		}
-		chunk := runes[:m]
-		runes = runes[m:]
-		uint16s := utf16.Encode(chunk)
-		for len(uint16s) > 0 {
-			var written uint32
-			err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len(uint16s)), &written, nil)
-			if err != nil {
-				return 0, nil
-			}
-			uint16s = uint16s[written:]
-		}
-	}
-	return n, nil
+	n, err = f.pfd.Pread(b, off)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // write writes len(b) bytes to the File.
 // It returns the number of bytes written and an error, if any.
 func (f *File) write(b []byte) (n int, err error) {
-	f.l.Lock()
-	defer f.l.Unlock()
-	if f.isConsole {
-		return f.writeConsole(b)
-	}
-	return fixCount(syscall.Write(f.fd, b))
+	n, err = f.pfd.Write(b)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // pwrite writes len(b) bytes to the File starting at byte offset off.
 // It returns the number of bytes written and an error, if any.
 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, io.SeekCurrent)
-	if e != nil {
-		return 0, e
-	}
-	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
-	o := syscall.Overlapped{
-		OffsetHigh: uint32(off >> 32),
-		Offset:     uint32(off),
-	}
-	var done uint32
-	e = syscall.WriteFile(f.fd, b, &done, &o)
-	if e != nil {
-		return 0, e
-	}
-	return int(done), nil
+	n, err = f.pfd.Pwrite(b, off)
+	runtime.KeepAlive(f)
+	return n, err
 }
 
 // seek sets the offset for the next Read or Write on file to offset, interpreted
@@ -397,9 +239,9 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
 // relative to the current offset, and 2 means relative to the end.
 // It returns the new offset and an error, if any.
 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
-	f.l.Lock()
-	defer f.l.Unlock()
-	return syscall.Seek(f.fd, offset, whence)
+	ret, err = f.pfd.Seek(offset, whence)
+	runtime.KeepAlive(f)
+	return ret, err
 }
 
 // Truncate changes the size of the named file.
@@ -480,11 +322,10 @@ func Pipe() (r *File, w *File, err error) {
 	syscall.CloseOnExec(p[1])
 	syscall.ForkLock.RUnlock()
 
-	return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
+	return newFile(p[0], "|0", "file"), newFile(p[1], "|1", "file"), nil
 }
 
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
+func tempDir() string {
 	n := uint32(syscall.MAX_PATH)
 	for {
 		b := make([]uint16, n)
@@ -556,5 +397,3 @@ func Symlink(oldname, newname string) error {
 	}
 	return nil
 }
-
-const badFd = syscall.InvalidHandle
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 7ad9aac..91c6be6 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -17,6 +17,7 @@ import (
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"runtime/debug"
 	"sort"
 	"strings"
 	"sync"
@@ -54,15 +55,12 @@ var sysdir = func() *sysDir {
 	case "darwin":
 		switch runtime.GOARCH {
 		case "arm", "arm64":
-			/// At this point the test harness has not had a chance
-			// to move us into the ./src/os directory, so the
-			// current working directory is the root of the app.
 			wd, err := syscall.Getwd()
 			if err != nil {
 				wd = err.Error()
 			}
 			return &sysDir{
-				wd,
+				filepath.Join(wd, "..", ".."),
 				[]string{
 					"ResourceRules.plist",
 					"Info.plist",
@@ -112,7 +110,7 @@ func size(name string, t *testing.T) int64 {
 			break
 		}
 		if e != nil {
-			t.Fatal("read failed:", err)
+			t.Fatal("read failed:", e)
 		}
 	}
 	return int64(len)
@@ -176,6 +174,45 @@ func TestStat(t *testing.T) {
 	}
 }
 
+func TestStatError(t *testing.T) {
+	defer chtmpdir(t)()
+
+	path := "no-such-file"
+	Remove(path) // Just in case
+
+	fi, err := Stat(path)
+	if err == nil {
+		t.Fatal("got nil, want error")
+	}
+	if fi != nil {
+		t.Errorf("got %v, want nil", fi)
+	}
+	if perr, ok := err.(*PathError); !ok {
+		t.Errorf("got %T, want %T", err, perr)
+	}
+
+	testenv.MustHaveSymlink(t)
+
+	link := "symlink"
+	Remove(link) // Just in case
+	err = Symlink(path, link)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer Remove(link)
+
+	fi, err = Stat(link)
+	if err == nil {
+		t.Fatal("got nil, want error")
+	}
+	if fi != nil {
+		t.Errorf("got %v, want nil", fi)
+	}
+	if perr, ok := err.(*PathError); !ok {
+		t.Errorf("got %T, want %T", err, perr)
+	}
+}
+
 func TestFstat(t *testing.T) {
 	path := sfdir + "/" + sfname
 	file, err1 := Open(path)
@@ -361,6 +398,50 @@ func BenchmarkReaddir(b *testing.B) {
 	benchmarkReaddir(".", b)
 }
 
+func benchmarkStat(b *testing.B, path string) {
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := Stat(path)
+		if err != nil {
+			b.Fatalf("Stat(%q) failed: %v", path, err)
+		}
+	}
+}
+
+func benchmarkLstat(b *testing.B, path string) {
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := Lstat(path)
+		if err != nil {
+			b.Fatalf("Lstat(%q) failed: %v", path, err)
+		}
+	}
+}
+
+func BenchmarkStatDot(b *testing.B) {
+	benchmarkStat(b, ".")
+}
+
+func BenchmarkStatFile(b *testing.B) {
+	benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
+}
+
+func BenchmarkStatDir(b *testing.B) {
+	benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
+}
+
+func BenchmarkLstatDot(b *testing.B) {
+	benchmarkLstat(b, ".")
+}
+
+func BenchmarkLstatFile(b *testing.B) {
+	benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
+}
+
+func BenchmarkLstatDir(b *testing.B) {
+	benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
+}
+
 // Read the directory one entry at a time.
 func smallReaddirnames(file *File, length int, t *testing.T) []string {
 	names := make([]string, length)
@@ -675,55 +756,58 @@ func TestSymlink(t *testing.T) {
 	Remove(from) // Just in case.
 	file, err := Create(to)
 	if err != nil {
-		t.Fatalf("open %q failed: %v", to, err)
+		t.Fatalf("Create(%q) failed: %v", to, err)
 	}
 	defer Remove(to)
 	if err = file.Close(); err != nil {
-		t.Errorf("close %q failed: %v", to, err)
+		t.Errorf("Close(%q) failed: %v", to, err)
 	}
 	err = Symlink(to, from)
 	if err != nil {
-		t.Fatalf("symlink %q, %q failed: %v", to, from, err)
+		t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
 	}
 	defer Remove(from)
 	tostat, err := Lstat(to)
 	if err != nil {
-		t.Fatalf("stat %q failed: %v", to, err)
+		t.Fatalf("Lstat(%q) failed: %v", to, err)
 	}
 	if tostat.Mode()&ModeSymlink != 0 {
-		t.Fatalf("stat %q claims to have found a symlink", to)
+		t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink)
 	}
 	fromstat, err := Stat(from)
 	if err != nil {
-		t.Fatalf("stat %q failed: %v", from, err)
+		t.Fatalf("Stat(%q) failed: %v", from, err)
 	}
 	if !SameFile(tostat, fromstat) {
-		t.Errorf("symlink %q, %q did not create symlink", to, from)
+		t.Errorf("Symlink(%q, %q) did not create symlink", to, from)
 	}
 	fromstat, err = Lstat(from)
 	if err != nil {
-		t.Fatalf("lstat %q failed: %v", from, err)
+		t.Fatalf("Lstat(%q) failed: %v", from, err)
 	}
 	if fromstat.Mode()&ModeSymlink == 0 {
-		t.Fatalf("symlink %q, %q did not create symlink", to, from)
+		t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink)
 	}
 	fromstat, err = Stat(from)
 	if err != nil {
-		t.Fatalf("stat %q failed: %v", from, err)
+		t.Fatalf("Stat(%q) failed: %v", from, err)
+	}
+	if fromstat.Name() != from {
+		t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from)
 	}
 	if fromstat.Mode()&ModeSymlink != 0 {
-		t.Fatalf("stat %q did not follow symlink", from)
+		t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink)
 	}
 	s, err := Readlink(from)
 	if err != nil {
-		t.Fatalf("readlink %q failed: %v", from, err)
+		t.Fatalf("Readlink(%q) failed: %v", from, err)
 	}
 	if s != to {
-		t.Fatalf("after symlink %q != %q", s, to)
+		t.Fatalf("Readlink(%q) = %q, want %q", from, s, to)
 	}
 	file, err = Open(from)
 	if err != nil {
-		t.Fatalf("open %q failed: %v", from, err)
+		t.Fatalf("Open(%q) failed: %v", from, err)
 	}
 	file.Close()
 }
@@ -846,6 +930,18 @@ func TestRenameFailed(t *testing.T) {
 	}
 }
 
+func TestRenameNotExisting(t *testing.T) {
+	defer chtmpdir(t)()
+	from, to := "doesnt-exist", "dest"
+
+	Mkdir(to, 0777)
+	defer Remove(to)
+
+	if err := Rename(from, to); !IsNotExist(err) {
+		t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
+	}
+}
+
 func TestRenameToDirFailed(t *testing.T) {
 	defer chtmpdir(t)()
 	from, to := "renamefrom", "renameto"
@@ -1056,14 +1152,22 @@ func testChtimes(t *testing.T, name string) {
 	}
 	postStat := st
 
-	/* Plan 9, NaCl:
-		Mtime is the time of the last change of content.  Similarly, atime is set whenever the
-	    contents are accessed; also, it is set whenever mtime is set.
-	*/
 	pat := Atime(postStat)
 	pmt := postStat.ModTime()
-	if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" {
-		t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
+	if !pat.Before(at) {
+		switch runtime.GOOS {
+		case "plan9", "nacl":
+			// Ignore.
+			// Plan 9, NaCl:
+			// Mtime is the time of the last change of
+			// content.  Similarly, atime is set whenever
+			// the contents are accessed; also, it is set
+			// whenever mtime is set.
+		case "netbsd":
+			t.Logf("AccessTime didn't go backwards; was=%d, after=%d (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat)
+		default:
+			t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
+		}
 	}
 
 	if !pmt.Before(mt) {
@@ -1241,6 +1345,32 @@ func TestSeek(t *testing.T) {
 	}
 }
 
+func TestSeekError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9", "nacl":
+		t.Skipf("skipping test on %v", runtime.GOOS)
+	}
+
+	r, w, err := Pipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = r.Seek(0, 0)
+	if err == nil {
+		t.Fatal("Seek on pipe should fail")
+	}
+	if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
+		t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
+	}
+	_, err = w.Seek(0, 0)
+	if err == nil {
+		t.Fatal("Seek on pipe should fail")
+	}
+	if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
+		t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
+	}
+}
+
 type openErrorTest struct {
 	path  string
 	mode  int
@@ -1445,6 +1575,26 @@ func TestReadAtOffset(t *testing.T) {
 	}
 }
 
+// Verify that ReadAt doesn't allow negative offset.
+func TestReadAtNegativeOffset(t *testing.T) {
+	f := newFile("TestReadAtNegativeOffset", 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, -10)
+
+	const wantsub = "negative offset"
+	if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
+		t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
+	}
+}
+
 func TestWriteAt(t *testing.T) {
 	f := newFile("TestWriteAt", t)
 	defer Remove(f.Name())
@@ -1467,6 +1617,20 @@ func TestWriteAt(t *testing.T) {
 	}
 }
 
+// Verify that WriteAt doesn't allow negative offset.
+func TestWriteAtNegativeOffset(t *testing.T) {
+	f := newFile("TestWriteAtNegativeOffset", t)
+	defer Remove(f.Name())
+	defer f.Close()
+
+	n, err := f.WriteAt([]byte("WORLD"), -10)
+
+	const wantsub = "negative offset"
+	if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
+		t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
+	}
+}
+
 func writeFile(t *testing.T, fname string, flag int, text string) string {
 	f, err := OpenFile(fname, flag, 0666)
 	if err != nil {
@@ -1669,6 +1833,17 @@ func TestStatStdin(t *testing.T) {
 		Exit(0)
 	}
 
+	fi, err := Stdin.Stat()
+	if err != nil {
+		t.Fatal(err)
+	}
+	switch mode := fi.Mode(); {
+	case mode&ModeCharDevice != 0:
+	case mode&ModeNamedPipe != 0:
+	default:
+		t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode)
+	}
+
 	var cmd *osexec.Cmd
 	if runtime.GOOS == "windows" {
 		cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
@@ -1688,6 +1863,60 @@ func TestStatStdin(t *testing.T) {
 	}
 }
 
+func TestStatRelativeSymlink(t *testing.T) {
+	testenv.MustHaveSymlink(t)
+
+	tmpdir, err := ioutil.TempDir("", "TestStatRelativeSymlink")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer RemoveAll(tmpdir)
+
+	target := filepath.Join(tmpdir, "target")
+	f, err := Create(target)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	st, err := f.Stat()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	link := filepath.Join(tmpdir, "link")
+	err = Symlink(filepath.Base(target), link)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	st1, err := Stat(link)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !SameFile(st, st1) {
+		t.Error("Stat doesn't follow relative symlink")
+	}
+
+	if runtime.GOOS == "windows" {
+		Remove(link)
+		err = Symlink(target[len(filepath.VolumeName(target)):], link)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		st1, err := Stat(link)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if !SameFile(st, st1) {
+			t.Error("Stat doesn't follow relative symlink")
+		}
+	}
+}
+
 func TestReadAtEOF(t *testing.T) {
 	f := newFile("TestReadAtEOF", t)
 	defer Remove(f.Name())
@@ -1929,3 +2158,99 @@ func TestRemoveAllRace(t *testing.T) {
 	close(hold) // let workers race to remove root
 	wg.Wait()
 }
+
+// Test that reading from a pipe doesn't use up a thread.
+func TestPipeThreads(t *testing.T) {
+	switch runtime.GOOS {
+	case "freebsd":
+		t.Skip("skipping on FreeBSD; issue 19093")
+	case "solaris":
+		t.Skip("skipping on Solaris; issue 19111")
+	case "windows":
+		t.Skip("skipping on Windows; issue 19098")
+	case "plan9":
+		t.Skip("skipping on Plan 9; does not support runtime poller")
+	}
+
+	threads := 100
+
+	// OpenBSD has a low default for max number of files.
+	if runtime.GOOS == "openbsd" {
+		threads = 50
+	}
+
+	r := make([]*File, threads)
+	w := make([]*File, threads)
+	for i := 0; i < threads; i++ {
+		rp, wp, err := Pipe()
+		if err != nil {
+			for j := 0; j < i; j++ {
+				r[j].Close()
+				w[j].Close()
+			}
+			t.Fatal(err)
+		}
+		r[i] = rp
+		w[i] = wp
+	}
+
+	defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2))
+
+	var wg sync.WaitGroup
+	wg.Add(threads)
+	c := make(chan bool, threads)
+	for i := 0; i < threads; i++ {
+		go func(i int) {
+			defer wg.Done()
+			var b [1]byte
+			c <- true
+			if _, err := r[i].Read(b[:]); err != nil {
+				t.Error(err)
+			}
+		}(i)
+	}
+
+	for i := 0; i < threads; i++ {
+		<-c
+	}
+
+	// If we are still alive, it means that the 100 goroutines did
+	// not require 100 threads.
+
+	for i := 0; i < threads; i++ {
+		if _, err := w[i].Write([]byte{0}); err != nil {
+			t.Error(err)
+		}
+		if err := w[i].Close(); err != nil {
+			t.Error(err)
+		}
+	}
+
+	wg.Wait()
+
+	for i := 0; i < threads; i++ {
+		if err := r[i].Close(); err != nil {
+			t.Error(err)
+		}
+	}
+}
+
+func TestDoubleCloseError(t *testing.T) {
+	path := sfdir + "/" + sfname
+	file, err := Open(path)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := file.Close(); err != nil {
+		t.Fatalf("unexpected error from Close: %v", err)
+	}
+	if err := file.Close(); err == nil {
+		t.Error("second Close did not fail")
+	} else if pe, ok := err.(*PathError); !ok {
+		t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe)
+	} else if pe.Err != ErrClosed {
+		t.Errorf("second Close returned %q, wanted %q", err, ErrClosed)
+	} else {
+		t.Logf("second close returned expected error %q", err)
+	}
+}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 54ba99b..04c4a4a 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -6,6 +6,7 @@ package os_test
 
 import (
 	"fmt"
+	"internal/poll"
 	"internal/syscall/windows"
 	"internal/testenv"
 	"io"
@@ -104,6 +105,10 @@ func testDirLinks(t *testing.T, tests []dirLinkTest) {
 	if err != nil {
 		t.Fatal(err)
 	}
+	fi, err := os.Stat(dir)
+	if err != nil {
+		t.Fatal(err)
+	}
 	err = ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("abc"), 0644)
 	if err != nil {
 		t.Fatal(err)
@@ -112,7 +117,7 @@ func testDirLinks(t *testing.T, tests []dirLinkTest) {
 		link := filepath.Join(tmpdir, test.name+"_link")
 		err := test.mklink(link, dir)
 		if err != nil {
-			t.Errorf("creating link for %s test failed: %v", test.name, err)
+			t.Errorf("creating link for %q test failed: %v", test.name, err)
 			continue
 		}
 
@@ -131,15 +136,35 @@ func testDirLinks(t *testing.T, tests []dirLinkTest) {
 			continue
 		}
 
-		fi, err := os.Stat(link)
+		fi1, err := os.Stat(link)
 		if err != nil {
 			t.Errorf("failed to stat link %v: %v", link, err)
 			continue
 		}
-		expected := filepath.Base(dir)
-		got := fi.Name()
-		if !fi.IsDir() || expected != got {
-			t.Errorf("link should point to %v but points to %v instead", expected, got)
+		if !fi1.IsDir() {
+			t.Errorf("%q should be a directory", link)
+			continue
+		}
+		if fi1.Name() != filepath.Base(link) {
+			t.Errorf("Stat(%q).Name() = %q, want %q", link, fi1.Name(), filepath.Base(link))
+			continue
+		}
+		if !os.SameFile(fi, fi1) {
+			t.Errorf("%q should point to %q", link, dir)
+			continue
+		}
+
+		fi2, err := os.Lstat(link)
+		if err != nil {
+			t.Errorf("failed to lstat link %v: %v", link, err)
+			continue
+		}
+		if m := fi2.Mode(); m&os.ModeSymlink == 0 {
+			t.Errorf("%q should be a link, but is not (mode=0x%x)", link, uint32(m))
+			continue
+		}
+		if m := fi2.Mode(); m&os.ModeDir != 0 {
+			t.Errorf("%q should be a link, not a directory (mode=0x%x)", link, uint32(m))
 			continue
 		}
 	}
@@ -404,6 +429,8 @@ func TestDirectorySymbolicLink(t *testing.T) {
 func TestNetworkSymbolicLink(t *testing.T) {
 	testenv.MustHaveSymlink(t)
 
+	const _NERR_ServerNotStarted = syscall.Errno(2114)
+
 	dir, err := ioutil.TempDir("", "TestNetworkSymbolicLink")
 	if err != nil {
 		t.Fatal(err)
@@ -454,6 +481,9 @@ func TestNetworkSymbolicLink(t *testing.T) {
 		if err == syscall.ERROR_ACCESS_DENIED {
 			t.Skip("you don't have enough privileges to add network share")
 		}
+		if err == _NERR_ServerNotStarted {
+			t.Skip(_NERR_ServerNotStarted.Error())
+		}
 		t.Fatal(err)
 	}
 	defer func() {
@@ -637,15 +667,15 @@ func TestStatSymlinkLoop(t *testing.T) {
 	defer os.Remove("x")
 
 	_, err = os.Stat("x")
-	if perr, ok := err.(*os.PathError); !ok || perr.Err != syscall.ELOOP {
-		t.Errorf("expected *PathError with ELOOP, got %T: %v\n", err, err)
+	if _, ok := err.(*os.PathError); !ok {
+		t.Errorf("expected *PathError, got %T: %v\n", err, err)
 	}
 }
 
 func TestReadStdin(t *testing.T) {
-	old := *os.ReadConsoleFunc
+	old := poll.ReadConsole
 	defer func() {
-		*os.ReadConsoleFunc = old
+		poll.ReadConsole = old
 	}()
 
 	testConsole := os.NewConsoleFile(syscall.Stdin, "test")
@@ -664,7 +694,7 @@ func TestReadStdin(t *testing.T) {
 			for _, s := range tests {
 				t.Run(fmt.Sprintf("c%d/r%d/%s", consoleSize, readSize, s), func(t *testing.T) {
 					s16 := utf16.Encode([]rune(s))
-					*os.ReadConsoleFunc = func(h syscall.Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) error {
+					poll.ReadConsole = func(h syscall.Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) error {
 						if inputControl != nil {
 							t.Fatalf("inputControl not nil")
 						}
@@ -722,3 +752,137 @@ func TestStatPagefile(t *testing.T) {
 	}
 	t.Fatal(err)
 }
+
+// syscallCommandLineToArgv calls syscall.CommandLineToArgv
+// and converts returned result into []string.
+func syscallCommandLineToArgv(cmd string) ([]string, error) {
+	var argc int32
+	argv, err := syscall.CommandLineToArgv(&syscall.StringToUTF16(cmd)[0], &argc)
+	if err != nil {
+		return nil, err
+	}
+	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
+
+	var args []string
+	for _, v := range (*argv)[:argc] {
+		args = append(args, syscall.UTF16ToString((*v)[:]))
+	}
+	return args, nil
+}
+
+// compareCommandLineToArgvWithSyscall ensures that
+// os.CommandLineToArgv(cmd) and syscall.CommandLineToArgv(cmd)
+// return the same result.
+func compareCommandLineToArgvWithSyscall(t *testing.T, cmd string) {
+	syscallArgs, err := syscallCommandLineToArgv(cmd)
+	if err != nil {
+		t.Fatal(err)
+	}
+	args := os.CommandLineToArgv(cmd)
+	if want, have := fmt.Sprintf("%q", syscallArgs), fmt.Sprintf("%q", args); want != have {
+		t.Errorf("testing os.commandLineToArgv(%q) failed: have %q want %q", cmd, args, syscallArgs)
+		return
+	}
+}
+
+func TestCmdArgs(t *testing.T) {
+	tmpdir, err := ioutil.TempDir("", "TestCmdArgs")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	const prog = `
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func main() {
+	fmt.Printf("%q", os.Args)
+}
+`
+	src := filepath.Join(tmpdir, "main.go")
+	err = ioutil.WriteFile(src, []byte(prog), 0666)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	exe := filepath.Join(tmpdir, "main.exe")
+	cmd := osexec.Command("go", "build", "-o", exe, src)
+	cmd.Dir = tmpdir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("building main.exe failed: %v\n%s", err, out)
+	}
+
+	var cmds = []string{
+		``,
+		` a b c`,
+		` "`,
+		` ""`,
+		` """`,
+		` "" a`,
+		` "123"`,
+		` \"123\"`,
+		` \"123 456\"`,
+		` \\"`,
+		` \\\"`,
+		` \\\\\"`,
+		` \\\"x`,
+		` """"\""\\\"`,
+		` abc`,
+		` \\\\\""x"""y z`,
+		"\tb\t\"x\ty\"",
+		` "Брад" d e`,
+		// examples from https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+		` "abc" d e`,
+		` a\\b d"e f"g h`,
+		` a\\\"b c d`,
+		` a\\\\"b c" d e`,
+		// http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
+		// from 5.4  Examples
+		` CallMeIshmael`,
+		` "Call Me Ishmael"`,
+		` Cal"l Me I"shmael`,
+		` CallMe\"Ishmael`,
+		` "CallMe\"Ishmael"`,
+		` "Call Me Ishmael\\"`,
+		` "CallMe\\\"Ishmael"`,
+		` a\\\b`,
+		` "a\\\b"`,
+		// from 5.5  Some Common Tasks
+		` "\"Call Me Ishmael\""`,
+		` "C:\TEST A\\"`,
+		` "\"C:\TEST A\\\""`,
+		// from 5.6  The Microsoft Examples Explained
+		` "a b c"  d  e`,
+		` "ab\"c"  "\\"  d`,
+		` a\\\b d"e f"g h`,
+		` a\\\"b c d`,
+		` a\\\\"b c" d e`,
+		// from 5.7  Double Double Quote Examples (pre 2008)
+		` "a b c""`,
+		` """CallMeIshmael"""  b  c`,
+		` """Call Me Ishmael"""`,
+		` """"Call Me Ishmael"" b c`,
+	}
+	for _, cmd := range cmds {
+		compareCommandLineToArgvWithSyscall(t, "test"+cmd)
+		compareCommandLineToArgvWithSyscall(t, `"cmd line"`+cmd)
+		compareCommandLineToArgvWithSyscall(t, exe+cmd)
+
+		// test both syscall.EscapeArg and os.commandLineToArgv
+		args := os.CommandLineToArgv(exe + cmd)
+		out, err := osexec.Command(args[0], args[1:]...).CombinedOutput()
+		if err != nil {
+			t.Fatalf("running %q failed: %v\n%v", args, err, string(out))
+		}
+		if want, have := fmt.Sprintf("%q", args), string(out); want != have {
+			t.Errorf("wrong output of executing %q: have %q want %q", args, have, want)
+			continue
+		}
+	}
+}
diff --git a/src/os/pipe_bsd.go b/src/os/pipe_bsd.go
index 3b81ed2..ffd201c 100644
--- a/src/os/pipe_bsd.go
+++ b/src/os/pipe_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
+// +build darwin dragonfly nacl netbsd openbsd solaris
 
 package os
 
@@ -24,5 +24,5 @@ func Pipe() (r *File, w *File, err error) {
 	syscall.CloseOnExec(p[1])
 	syscall.ForkLock.RUnlock()
 
-	return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
+	return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil
 }
diff --git a/src/os/pipe_freebsd.go b/src/os/pipe_freebsd.go
new file mode 100644
index 0000000..ea6622c
--- /dev/null
+++ b/src/os/pipe_freebsd.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an error, if any.
+func Pipe() (r *File, w *File, err error) {
+	var p [2]int
+
+	e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
+	if e != nil {
+		// Fallback support for FreeBSD 9, which lacks Pipe2.
+		//
+		// TODO: remove this for Go 1.10 when FreeBSD 9
+		// is removed (Issue 19072).
+
+		// See ../syscall/exec.go for description of lock.
+		syscall.ForkLock.RLock()
+		e := syscall.Pipe(p[0:])
+		if e != nil {
+			syscall.ForkLock.RUnlock()
+			return nil, nil, NewSyscallError("pipe", e)
+		}
+		syscall.CloseOnExec(p[0])
+		syscall.CloseOnExec(p[1])
+		syscall.ForkLock.RUnlock()
+	}
+
+	return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil
+}
diff --git a/src/os/pipe_linux.go b/src/os/pipe_linux.go
index 9bafad8..96f2ce9 100644
--- a/src/os/pipe_linux.go
+++ b/src/os/pipe_linux.go
@@ -29,5 +29,5 @@ func Pipe() (r *File, w *File, err error) {
 		return nil, nil, NewSyscallError("pipe2", e)
 	}
 
-	return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
+	return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil
 }
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 74cce80..7c4cbb1 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -10,11 +10,16 @@ package os_test
 import (
 	"fmt"
 	"internal/testenv"
+	"io/ioutil"
 	"os"
 	osexec "os/exec"
 	"os/signal"
+	"runtime"
+	"strconv"
+	"strings"
 	"syscall"
 	"testing"
+	"time"
 )
 
 func TestEPIPE(t *testing.T) {
@@ -82,7 +87,7 @@ func TestStdPipe(t *testing.T) {
 					t.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest, sig)
 				}
 			} else {
-				t.Errorf("unexpected exit status %v for descriptor %ds sig %t", err, dest, sig)
+				t.Errorf("unexpected exit status %v for descriptor %d sig %t", err, dest, sig)
 			}
 		}
 	}
@@ -111,3 +116,73 @@ func TestStdPipeHelper(t *testing.T) {
 	// For descriptor 3, a normal exit is expected.
 	os.Exit(0)
 }
+
+func testClosedPipeRace(t *testing.T, read bool) {
+	switch runtime.GOOS {
+	case "freebsd":
+		t.Skip("FreeBSD does not use the poller; issue 19093")
+	}
+
+	limit := 1
+	if !read {
+		// Get the amount we have to write to overload a pipe
+		// with no reader.
+		limit = 65537
+		if b, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size"); err == nil {
+			if i, err := strconv.Atoi(strings.TrimSpace(string(b))); err == nil {
+				limit = i + 1
+			}
+		}
+		t.Logf("using pipe write limit of %d", limit)
+	}
+
+	r, w, err := os.Pipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer r.Close()
+	defer w.Close()
+
+	// Close the read end of the pipe in a goroutine while we are
+	// writing to the write end, or vice-versa.
+	go func() {
+		// Give the main goroutine a chance to enter the Read or
+		// Write call. This is sloppy but the test will pass even
+		// if we close before the read/write.
+		time.Sleep(20 * time.Millisecond)
+
+		var err error
+		if read {
+			err = r.Close()
+		} else {
+			err = w.Close()
+		}
+		if err != nil {
+			t.Error(err)
+		}
+	}()
+
+	b := make([]byte, limit)
+	if read {
+		_, err = r.Read(b[:])
+	} else {
+		_, err = w.Write(b[:])
+	}
+	if err == nil {
+		t.Error("I/O on closed pipe unexpectedly succeeded")
+	} else if pe, ok := err.(*os.PathError); !ok {
+		t.Errorf("I/O on closed pipe returned unexpected error type %T; expected os.PathError", pe)
+	} else if pe.Err != os.ErrClosed {
+		t.Errorf("got error %q but expected %q", pe.Err, os.ErrClosed)
+	} else {
+		t.Logf("I/O returned expected error %q", err)
+	}
+}
+
+func TestClosedPipeRaceRead(t *testing.T) {
+	testClosedPipeRace(t, true)
+}
+
+func TestClosedPipeRaceWrite(t *testing.T) {
+	testClosedPipeRace(t, false)
+}
diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go
index 73b01a2..16f49c7 100644
--- a/src/os/signal/doc.go
+++ b/src/os/signal/doc.go
@@ -181,10 +181,11 @@ If the Go runtime sees an existing signal handler for the SIGCANCEL or
 SIGSETXID signals (which are used only on GNU/Linux), it will turn on
 the SA_ONSTACK flag and otherwise keep the signal handler.
 
-For the synchronous signals, the Go runtime will install a signal
-handler. It will save any existing signal handler. If a synchronous
-signal arrives while executing non-Go code, the Go runtime will invoke
-the existing signal handler instead of the Go signal handler.
+For the synchronous signals and SIGPIPE, the Go runtime will install a
+signal handler. It will save any existing signal handler. If a
+synchronous signal arrives while executing non-Go code, the Go runtime
+will invoke the existing signal handler instead of the Go signal
+handler.
 
 Go code built with -buildmode=c-archive or -buildmode=c-shared will
 not install any other signal handlers by default. If there is an
diff --git a/src/os/signal/signal_plan9_test.go b/src/os/signal/signal_plan9_test.go
index 10bfdc3..49b7aff 100644
--- a/src/os/signal/signal_plan9_test.go
+++ b/src/os/signal/signal_plan9_test.go
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package signal
+package signal_test
 
 import (
 	"os"
+	. "os/signal"
 	"runtime"
 	"syscall"
 	"testing"
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 406102c..146dc81 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -4,13 +4,14 @@
 
 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
-package signal
+package signal_test
 
 import (
 	"flag"
 	"io/ioutil"
 	"os"
 	"os/exec"
+	. "os/signal"
 	"runtime"
 	"strconv"
 	"syscall"
diff --git a/src/os/signal/signal_windows_test.go b/src/os/signal/signal_windows_test.go
index c2b5901..2892125 100644
--- a/src/os/signal/signal_windows_test.go
+++ b/src/os/signal/signal_windows_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.
 
-package signal
+package signal_test
 
 import (
 	"bytes"
diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go
index 1733d3f..1dd5714 100644
--- a/src/os/stat_unix.go
+++ b/src/os/stat_unix.go
@@ -17,7 +17,7 @@ func (f *File) Stat() (FileInfo, error) {
 		return nil, ErrInvalid
 	}
 	var fs fileStat
-	err := syscall.Fstat(f.fd, &fs.sys)
+	err := f.pfd.Fstat(&fs.sys)
 	if err != nil {
 		return nil, &PathError{"stat", f.name, err}
 	}
diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go
index fdabf73..667b999 100644
--- a/src/os/stat_windows.go
+++ b/src/os/stat_windows.go
@@ -16,7 +16,7 @@ func (file *File) Stat() (FileInfo, error) {
 	if file == nil {
 		return nil, ErrInvalid
 	}
-	if file == nil || file.fd < 0 {
+	if file == nil {
 		return nil, syscall.EINVAL
 	}
 	if file.isdir() {
@@ -27,16 +27,17 @@ func (file *File) Stat() (FileInfo, error) {
 		return &devNullStat, nil
 	}
 
-	ft, err := syscall.GetFileType(file.fd)
+	ft, err := file.pfd.GetFileType()
 	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
+	switch ft {
+	case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
+		return &fileStat{name: basename(file.name), filetype: ft}, nil
 	}
 
 	var d syscall.ByHandleFileInformation
-	err = syscall.GetFileInformationByHandle(file.fd, &d)
+	err = file.pfd.GetFileInformationByHandle(&d)
 	if err != nil {
 		return nil, &PathError{"GetFileInformationByHandle", file.name, err}
 	}
@@ -50,32 +51,111 @@ func (file *File) Stat() (FileInfo, error) {
 			FileSizeHigh:   d.FileSizeHigh,
 			FileSizeLow:    d.FileSizeLow,
 		},
-		vol:   d.VolumeSerialNumber,
-		idxhi: d.FileIndexHigh,
-		idxlo: d.FileIndexLow,
-		pipe:  false,
+		filetype: ft,
+		vol:      d.VolumeSerialNumber,
+		idxhi:    d.FileIndexHigh,
+		idxlo:    d.FileIndexLow,
 	}, nil
 }
 
 // Stat returns a FileInfo structure describing the named file.
 // If there is an error, it will be of type *PathError.
 func Stat(name string) (FileInfo, error) {
-	var fi FileInfo
-	var err error
-	for i := 0; i < 255; i++ {
-		fi, err = Lstat(name)
-		if err != nil {
-			return fi, err
+	if len(name) == 0 {
+		return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
+	}
+	if name == DevNull {
+		return &devNullStat, nil
+	}
+	namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
+	if err != nil {
+		return nil, &PathError{"Stat", name, err}
+	}
+	// Apparently (see https://github.com/golang/go/issues/19922#issuecomment-300031421)
+	// GetFileAttributesEx is fastest approach to get file info.
+	// It does not work for symlinks. But symlinks are rare,
+	// so try GetFileAttributesEx first.
+	var fs fileStat
+	err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys)))
+	if err == nil && fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
+		fs.path = name
+		if !isAbs(fs.path) {
+			fs.path, err = syscall.FullPath(fs.path)
+			if err != nil {
+				return nil, &PathError{"FullPath", name, err}
+			}
 		}
-		if fi.Mode()&ModeSymlink == 0 {
-			return fi, nil
+		fs.name = basename(name)
+		return &fs, nil
+	}
+	// Use Windows I/O manager to dereference the symbolic link, as per
+	// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
+	h, err := syscall.CreateFile(namep, 0, 0, nil,
+		syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+	if err != nil {
+		if err == windows.ERROR_SHARING_VIOLATION {
+			// try FindFirstFile now that CreateFile failed
+			return statWithFindFirstFile(name, namep)
 		}
-		name, err = Readlink(name)
+		return nil, &PathError{"CreateFile", name, err}
+	}
+	defer syscall.CloseHandle(h)
+
+	var d syscall.ByHandleFileInformation
+	err = syscall.GetFileInformationByHandle(h, &d)
+	if err != nil {
+		return nil, &PathError{"GetFileInformationByHandle", name, err}
+	}
+	return &fileStat{
+		name: basename(name),
+		sys: syscall.Win32FileAttributeData{
+			FileAttributes: d.FileAttributes,
+			CreationTime:   d.CreationTime,
+			LastAccessTime: d.LastAccessTime,
+			LastWriteTime:  d.LastWriteTime,
+			FileSizeHigh:   d.FileSizeHigh,
+			FileSizeLow:    d.FileSizeLow,
+		},
+		vol:   d.VolumeSerialNumber,
+		idxhi: d.FileIndexHigh,
+		idxlo: d.FileIndexLow,
+		// fileStat.path is used by os.SameFile to decide if it needs
+		// to fetch vol, idxhi and idxlo. But these are already set,
+		// so set fileStat.path to "" to prevent os.SameFile doing it again.
+		// Also do not set fileStat.filetype, because it is only used for
+		// console and stdin/stdout. But you cannot call os.Stat for these.
+	}, nil
+}
+
+// statWithFindFirstFile is used by Stat to handle special case of statting
+// c:\pagefile.sys. We might discover that other files need similar treatment.
+func statWithFindFirstFile(name string, namep *uint16) (FileInfo, error) {
+	var fd syscall.Win32finddata
+	h, err := syscall.FindFirstFile(namep, &fd)
+	if err != nil {
+		return nil, &PathError{"FindFirstFile", name, err}
+	}
+	syscall.FindClose(h)
+
+	fullpath := name
+	if !isAbs(fullpath) {
+		fullpath, err = syscall.FullPath(fullpath)
 		if err != nil {
-			return fi, err
+			return nil, &PathError{"FullPath", name, err}
 		}
 	}
-	return nil, &PathError{"Stat", name, syscall.ELOOP}
+	return &fileStat{
+		name: basename(name),
+		path: fullpath,
+		sys: syscall.Win32FileAttributeData{
+			FileAttributes: fd.FileAttributes,
+			CreationTime:   fd.CreationTime,
+			LastAccessTime: fd.LastAccessTime,
+			LastWriteTime:  fd.LastWriteTime,
+			FileSizeHigh:   fd.FileSizeHigh,
+			FileSizeLow:    fd.FileSizeLow,
+		},
+	}, nil
 }
 
 // Lstat returns the FileInfo structure describing the named file.
@@ -100,25 +180,13 @@ func Lstat(name string) (FileInfo, error) {
 			return nil, &PathError{"GetFileAttributesEx", name, e}
 		}
 		// try FindFirstFile now that GetFileAttributesEx failed
-		var fd syscall.Win32finddata
-		h, e2 := syscall.FindFirstFile(namep, &fd)
-		if e2 != nil {
-			return nil, &PathError{"FindFirstFile", name, e}
-		}
-		syscall.FindClose(h)
-
-		fs.sys.FileAttributes = fd.FileAttributes
-		fs.sys.CreationTime = fd.CreationTime
-		fs.sys.LastAccessTime = fd.LastAccessTime
-		fs.sys.LastWriteTime = fd.LastWriteTime
-		fs.sys.FileSizeHigh = fd.FileSizeHigh
-		fs.sys.FileSizeLow = fd.FileSizeLow
+		return statWithFindFirstFile(name, namep)
 	}
 	fs.path = name
 	if !isAbs(fs.path) {
 		fs.path, e = syscall.FullPath(fs.path)
 		if e != nil {
-			return nil, e
+			return nil, &PathError{"FullPath", name, e}
 		}
 	}
 	return fs, nil
diff --git a/src/os/sys_darwin.go b/src/os/sys_darwin.go
index 7a8330a..11d678e 100644
--- a/src/os/sys_darwin.go
+++ b/src/os/sys_darwin.go
@@ -4,28 +4,8 @@
 
 package os
 
-import "syscall"
-
 // supportsCloseOnExec reports whether the platform supports the
 // O_CLOEXEC flag.
-var supportsCloseOnExec bool
-
-func init() {
-	// Seems like kern.osreldate is veiled on latest OS X. We use
-	// kern.osrelease instead.
-	osver, err := syscall.Sysctl("kern.osrelease")
-	if err != nil {
-		return
-	}
-	var i int
-	for i = range osver {
-		if osver[i] != '.' {
-			continue
-		}
-	}
-	// The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin
-	// 11.0.0). See http://support.apple.com/kb/HT1633.
-	if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
-		supportsCloseOnExec = true
-	}
-}
+// The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin 11.0.0).
+// See http://support.apple.com/kb/HT1633.
+const supportsCloseOnExec = true
diff --git a/src/os/types_unix.go b/src/os/types_unix.go
index 1f61481..c0259ae 100644
--- a/src/os/types_unix.go
+++ b/src/os/types_unix.go
@@ -29,5 +29,3 @@ func (fs *fileStat) Sys() interface{}   { return &fs.sys }
 func sameFile(fs1, fs2 *fileStat) bool {
 	return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
 }
-
-const badFd = -1
diff --git a/src/os/types_windows.go b/src/os/types_windows.go
index ad4e863..01d6b62 100644
--- a/src/os/types_windows.go
+++ b/src/os/types_windows.go
@@ -12,16 +12,17 @@ import (
 
 // A fileStat is the implementation of FileInfo returned by Stat and Lstat.
 type fileStat struct {
-	name string
-	sys  syscall.Win32FileAttributeData
-	pipe bool
+	name     string
+	sys      syscall.Win32FileAttributeData
+	filetype uint32 // what syscall.GetFileType returns
 
 	// used to implement SameFile
 	sync.Mutex
-	path  string
-	vol   uint32
-	idxhi uint32
-	idxlo uint32
+	path             string
+	vol              uint32
+	idxhi            uint32
+	idxlo            uint32
+	appendNameToPath bool
 }
 
 func (fs *fileStat) Size() int64 {
@@ -32,19 +33,22 @@ func (fs *fileStat) Mode() (m FileMode) {
 	if fs == &devNullStat {
 		return ModeDevice | ModeCharDevice | 0666
 	}
-	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
-		m |= ModeDir | 0111
-	}
 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
 		m |= 0444
 	} else {
 		m |= 0666
 	}
 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-		m |= ModeSymlink
+		return m | ModeSymlink
+	}
+	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+		m |= ModeDir | 0111
 	}
-	if fs.pipe {
+	switch fs.filetype {
+	case syscall.FILE_TYPE_PIPE:
 		m |= ModeNamedPipe
+	case syscall.FILE_TYPE_CHAR:
+		m |= ModeCharDevice
 	}
 	return m
 }
@@ -63,7 +67,13 @@ func (fs *fileStat) loadFileId() error {
 		// already done
 		return nil
 	}
-	pathp, err := syscall.UTF16PtrFromString(fs.path)
+	var path string
+	if fs.appendNameToPath {
+		path = fs.path + `\` + fs.name
+	} else {
+		path = fs.path
+	}
+	pathp, err := syscall.UTF16PtrFromString(path)
 	if err != nil {
 		return err
 	}
diff --git a/src/os/user/lookup_unix.go b/src/os/user/cgo_lookup_unix.go
similarity index 100%
copy from src/os/user/lookup_unix.go
copy to src/os/user/cgo_lookup_unix.go
diff --git a/src/os/user/lookup.go b/src/os/user/lookup.go
index 3b4421b..2243a25 100644
--- a/src/os/user/lookup.go
+++ b/src/os/user/lookup.go
@@ -4,20 +4,40 @@
 
 package user
 
+import "sync"
+
 // Current returns the current user.
 func Current() (*User, error) {
-	return current()
+	cache.Do(func() { cache.u, cache.err = current() })
+	if cache.err != nil {
+		return nil, cache.err
+	}
+	u := *cache.u // copy
+	return &u, nil
+}
+
+// cache of the current user
+var cache struct {
+	sync.Once
+	u   *User
+	err 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) {
+	if u, err := Current(); err == nil && u.Username == username {
+		return u, err
+	}
 	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) {
+	if u, err := Current(); err == nil && u.Uid == uid {
+		return u, err
+	}
 	return lookupUserId(uid)
 }
 
diff --git a/src/os/user/lookup_android.go b/src/os/user/lookup_android.go
index b1be3dc..8ca30b8 100644
--- a/src/os/user/lookup_android.go
+++ b/src/os/user/lookup_android.go
@@ -8,15 +8,6 @@ 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")
 }
@@ -32,7 +23,3 @@ func lookupGroup(string) (*Group, error) {
 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_stubs.go b/src/os/user/lookup_stubs.go
index ebf24f7..d23870f 100644
--- a/src/os/user/lookup_stubs.go
+++ b/src/os/user/lookup_stubs.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !cgo,!windows,!plan9,!android
+// +build !cgo,!windows,!plan9 android
 
 package user
 
@@ -15,7 +15,6 @@ import (
 )
 
 func init() {
-	userImplemented = false
 	groupImplemented = false
 }
 
@@ -27,7 +26,9 @@ func current() (*User, error) {
 		Name:     "", // ignored
 		HomeDir:  os.Getenv("HOME"),
 	}
-	if runtime.GOOS == "nacl" {
+	// On NaCL and Android, return a dummy user instead of failing.
+	switch runtime.GOOS {
+	case "nacl":
 		if u.Uid == "" {
 			u.Uid = "1"
 		}
@@ -35,7 +36,17 @@ func current() (*User, error) {
 			u.Username = "nacl"
 		}
 		if u.HomeDir == "" {
-			u.HomeDir = "/home/nacl"
+			u.HomeDir = "/"
+		}
+	case "android":
+		if u.Uid == "" {
+			u.Uid = "1"
+		}
+		if u.Username == "" {
+			u.Username = "android"
+		}
+		if u.HomeDir == "" {
+			u.HomeDir = "/sdcard"
 		}
 	}
 	// cgo isn't available, but if we found the minimum information
@@ -46,23 +57,10 @@ func current() (*User, error) {
 	return u, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
 }
 
-func lookupUser(username string) (*User, error) {
-	return nil, errors.New("user: Lookup requires cgo")
-}
-
-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) {
+	if runtime.GOOS == "android" {
+		return nil, errors.New("user: GroupIds not implemented on Android")
+	}
 	return nil, errors.New("user: GroupIds requires cgo")
 }
 
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index 58ecf32..5f34ba8 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -1,271 +1,197 @@
-// Copyright 2011 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.
 
-// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
-// +build cgo
+// +build darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
+// +build !cgo
 
 package user
 
 import (
-	"fmt"
+	"bufio"
+	"bytes"
+	"errors"
+	"io"
+	"os"
 	"strconv"
 	"strings"
-	"syscall"
-	"unsafe"
 )
 
-/*
-#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
-#include <unistd.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <stdlib.h>
+const groupFile = "/etc/group"
+const userFile = "/etc/passwd"
 
-static int mygetpwuid_r(int uid, struct passwd *pwd,
-	char *buf, size_t buflen, struct passwd **result) {
-	return getpwuid_r(uid, pwd, buf, buflen, result);
-}
-
-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);
-}
+var colon = []byte{':'}
 
-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);
+func init() {
+	groupImplemented = false
 }
 
-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"
+// lineFunc returns a value, an error, or (nil, nil) to skip the row.
+type lineFunc func(line []byte) (v interface{}, err error)
 
-func current() (*User, error) {
-	return lookupUnixUid(syscall.Getuid())
+// readColonFile parses r as an /etc/group or /etc/passwd style file, running
+// fn for each row. readColonFile returns a value, an error, or (nil, nil) if
+// the end of the file is reached without a match.
+func readColonFile(r io.Reader, fn lineFunc) (v interface{}, err error) {
+	bs := bufio.NewScanner(r)
+	for bs.Scan() {
+		line := bs.Bytes()
+		// There's no spec for /etc/passwd or /etc/group, but we try to follow
+		// the same rules as the glibc parser, which allows comments and blank
+		// space at the beginning of a line.
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 || line[0] == '#' {
+			continue
+		}
+		v, err = fn(line)
+		if v != nil || err != nil {
+			return
+		}
+	}
+	return nil, bs.Err()
 }
 
-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)
+func matchGroupIndexValue(value string, idx int) lineFunc {
+	var leadColon string
+	if idx > 0 {
+		leadColon = ":"
 	}
-	if result == nil {
-		return nil, UnknownUserError(username)
+	substr := []byte(leadColon + value + ":")
+	return func(line []byte) (v interface{}, err error) {
+		if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 3 {
+			return
+		}
+		// wheel:*:0:root
+		parts := strings.SplitN(string(line), ":", 4)
+		if len(parts) < 4 || parts[0] == "" || parts[idx] != value ||
+			// If the file contains +foo and you search for "foo", glibc
+			// returns an "invalid argument" error. Similarly, if you search
+			// for a gid for a row where the group name starts with "+" or "-",
+			// glibc fails to find the record.
+			parts[0][0] == '+' || parts[0][0] == '-' {
+			return
+		}
+		if _, err := strconv.Atoi(parts[2]); err != nil {
+			return nil, nil
+		}
+		return &Group{Name: parts[0], Gid: parts[2]}, nil
 	}
-	return buildUser(&pwd), err
 }
 
-func lookupUserId(uid string) (*User, error) {
-	i, e := strconv.Atoi(uid)
-	if e != nil {
-		return nil, e
+func findGroupId(id string, r io.Reader) (*Group, error) {
+	if v, err := readColonFile(r, matchGroupIndexValue(id, 2)); err != nil {
+		return nil, err
+	} else if v != nil {
+		return v.(*Group), nil
 	}
-	return lookupUnixUid(i)
+	return nil, UnknownGroupIdError(id)
 }
 
-func lookupUnixUid(uid int) (*User, error) {
-	var pwd C.struct_passwd
-	var result *C.struct_passwd
-
-	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.
-		return syscall.Errno(C.mygetpwuid_r(C.int(uid),
-			&pwd,
-			(*C.char)(buf.ptr),
-			C.size_t(buf.size),
-			&result))
-	})
-	if err != nil {
-		return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
+func findGroupName(name string, r io.Reader) (*Group, error) {
+	if v, err := readColonFile(r, matchGroupIndexValue(name, 0)); err != nil {
+		return nil, err
+	} else if v != nil {
+		return v.(*Group), nil
 	}
-	if result == nil {
-		return nil, UnknownUserIdError(uid)
-	}
-	return buildUser(&pwd), nil
+	return nil, UnknownGroupError(name)
 }
 
-func buildUser(pwd *C.struct_passwd) *User {
-	u := &User{
-		Uid:      strconv.Itoa(int(pwd.pw_uid)),
-		Gid:      strconv.Itoa(int(pwd.pw_gid)),
-		Username: C.GoString(pwd.pw_name),
-		Name:     C.GoString(pwd.pw_gecos),
-		HomeDir:  C.GoString(pwd.pw_dir),
+// returns a *User for a row if that row's has the given value at the
+// given index.
+func matchUserIndexValue(value string, idx int) lineFunc {
+	var leadColon string
+	if idx > 0 {
+		leadColon = ":"
 	}
-	// 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]
+	substr := []byte(leadColon + value + ":")
+	return func(line []byte) (v interface{}, err error) {
+		if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 6 {
+			return
+		}
+		// kevin:x:1005:1006::/home/kevin:/usr/bin/zsh
+		parts := strings.SplitN(string(line), ":", 7)
+		if len(parts) < 6 || parts[idx] != value || parts[0] == "" ||
+			parts[0][0] == '+' || parts[0][0] == '-' {
+			return
+		}
+		if _, err := strconv.Atoi(parts[2]); err != nil {
+			return nil, nil
+		}
+		if _, err := strconv.Atoi(parts[3]); err != nil {
+			return nil, nil
+		}
+		u := &User{
+			Username: parts[0],
+			Uid:      parts[2],
+			Gid:      parts[3],
+			Name:     parts[4],
+			HomeDir:  parts[5],
+		}
+		// 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)
+func findUserId(uid string, r io.Reader) (*User, error) {
+	i, e := strconv.Atoi(uid)
+	if e != nil {
+		return nil, errors.New("user: invalid userid " + uid)
 	}
-	if result == nil {
-		return nil, UnknownGroupError(groupname)
+	if v, err := readColonFile(r, matchUserIndexValue(uid, 2)); err != nil {
+		return nil, err
+	} else if v != nil {
+		return v.(*User), nil
 	}
-	return buildGroup(&grp), nil
+	return nil, UnknownUserIdError(i)
 }
 
-func lookupGroupId(gid string) (*Group, error) {
-	i, e := strconv.Atoi(gid)
-	if e != nil {
-		return nil, e
+func findUsername(name string, r io.Reader) (*User, error) {
+	if v, err := readColonFile(r, matchUserIndexValue(name, 0)); err != nil {
+		return nil, err
+	} else if v != nil {
+		return v.(*User), nil
 	}
-	return lookupUnixGid(i)
+	return nil, UnknownUserError(name)
 }
 
-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))
-	})
+func lookupGroup(groupname string) (*Group, error) {
+	f, err := os.Open(groupFile)
 	if err != nil {
-		return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
-	}
-	if result == nil {
-		return nil, UnknownGroupIdError(strconv.Itoa(gid))
+		return nil, err
 	}
-	return buildGroup(&grp), nil
+	defer f.Close()
+	return findGroupName(groupname, f)
 }
 
-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
+func lookupGroupId(id string) (*Group, error) {
+	f, err := os.Open(groupFile)
+	if err != nil {
+		return nil, err
 	}
-	return C.size_t(sz)
+	defer f.Close()
+	return findGroupId(id, f)
 }
 
-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 lookupUser(username string) (*User, error) {
+	f, err := os.Open(userFile)
+	if err != nil {
+		return nil, err
 	}
+	defer f.Close()
+	return findUsername(username, f)
 }
 
-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)
+func lookupUserId(uid string) (*User, error) {
+	f, err := os.Open(userFile)
+	if err != nil {
+		return nil, err
 	}
-}
-
-const maxBufferSize = 1 << 20
-
-func isSizeReasonable(sz int64) bool {
-	return sz > 0 && sz <= maxBufferSize
+	defer f.Close()
+	return findUserId(uid, f)
 }
diff --git a/src/os/user/lookup_unix_test.go b/src/os/user/lookup_unix_test.go
new file mode 100644
index 0000000..02c88ab
--- /dev/null
+++ b/src/os/user/lookup_unix_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.
+
+// +build darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
+// +build !cgo
+
+package user
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+const testGroupFile = `# See the opendirectoryd(8) man page for additional 
+# information about Open Directory.
+##
+nobody:*:-2:
+nogroup:*:-1:
+wheel:*:0:root
+emptyid:*::root
+invalidgid:*:notanumber:root
++plussign:*:20:root
+-minussign:*:21:root
+      
+daemon:*:1:root
+    indented:*:7:
+# comment:*:4:found
+     # comment:*:4:found
+kmem:*:2:root
+`
+
+var groupTests = []struct {
+	in   string
+	name string
+	gid  string
+}{
+	{testGroupFile, "nobody", "-2"},
+	{testGroupFile, "kmem", "2"},
+	{testGroupFile, "notinthefile", ""},
+	{testGroupFile, "comment", ""},
+	{testGroupFile, "plussign", ""},
+	{testGroupFile, "+plussign", ""},
+	{testGroupFile, "-minussign", ""},
+	{testGroupFile, "minussign", ""},
+	{testGroupFile, "emptyid", ""},
+	{testGroupFile, "invalidgid", ""},
+	{testGroupFile, "indented", "7"},
+	{testGroupFile, "# comment", ""},
+	{"", "emptyfile", ""},
+}
+
+func TestFindGroupName(t *testing.T) {
+	for _, tt := range groupTests {
+		got, err := findGroupName(tt.name, strings.NewReader(tt.in))
+		if tt.gid == "" {
+			if err == nil {
+				t.Errorf("findGroupName(%s): got nil error, expected err", tt.name)
+				continue
+			}
+			switch terr := err.(type) {
+			case UnknownGroupError:
+				if terr.Error() != "group: unknown group "+tt.name {
+					t.Errorf("findGroupName(%s): got %v, want %v", tt.name, terr, tt.name)
+				}
+			default:
+				t.Errorf("findGroupName(%s): got unexpected error %v", tt.name, terr)
+			}
+		} else {
+			if err != nil {
+				t.Fatalf("findGroupName(%s): got unexpected error %v", tt.name, err)
+			}
+			if got.Gid != tt.gid {
+				t.Errorf("findGroupName(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid)
+			}
+			if got.Name != tt.name {
+				t.Errorf("findGroupName(%s): got name %s, want %s", tt.name, got.Name, tt.name)
+			}
+		}
+	}
+}
+
+var groupIdTests = []struct {
+	in   string
+	gid  string
+	name string
+}{
+	{testGroupFile, "-2", "nobody"},
+	{testGroupFile, "2", "kmem"},
+	{testGroupFile, "notinthefile", ""},
+	{testGroupFile, "comment", ""},
+	{testGroupFile, "7", "indented"},
+	{testGroupFile, "4", ""},
+	{testGroupFile, "20", ""}, // row starts with a plus
+	{testGroupFile, "21", ""}, // row starts with a minus
+	{"", "emptyfile", ""},
+}
+
+func TestFindGroupId(t *testing.T) {
+	for _, tt := range groupIdTests {
+		got, err := findGroupId(tt.gid, strings.NewReader(tt.in))
+		if tt.name == "" {
+			if err == nil {
+				t.Errorf("findGroupId(%s): got nil error, expected err", tt.gid)
+				continue
+			}
+			switch terr := err.(type) {
+			case UnknownGroupIdError:
+				if terr.Error() != "group: unknown groupid "+tt.gid {
+					t.Errorf("findGroupId(%s): got %v, want %v", tt.name, terr, tt.name)
+				}
+			default:
+				t.Errorf("findGroupId(%s): got unexpected error %v", tt.name, terr)
+			}
+		} else {
+			if err != nil {
+				t.Fatalf("findGroupId(%s): got unexpected error %v", tt.name, err)
+			}
+			if got.Gid != tt.gid {
+				t.Errorf("findGroupId(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid)
+			}
+			if got.Name != tt.name {
+				t.Errorf("findGroupId(%s): got name %s, want %s", tt.name, got.Name, tt.name)
+			}
+		}
+	}
+}
+
+const testUserFile = `   # Example user file
+root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
+bin:x:2:3:bin:/bin:/usr/sbin/nologin
+     indented:x:3:3:indented:/dev:/usr/sbin/nologin
+sync:x:4:65534:sync:/bin:/bin/sync
+negative:x:-5:60:games:/usr/games:/usr/sbin/nologin
+man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
+allfields:x:6:12:mansplit,man2,man3,man4:/home/allfields:/usr/sbin/nologin
++plussign:x:8:10:man:/var/cache/man:/usr/sbin/nologin
+-minussign:x:9:10:man:/var/cache/man:/usr/sbin/nologin
+
+malformed:x:27:12 # more:colons:after:comment
+
+struid:x:notanumber:12 # more:colons:after:comment
+
+# commented:x:28:12:commented:/var/cache/man:/usr/sbin/nologin
+      # commentindented:x:29:12:commentindented:/var/cache/man:/usr/sbin/nologin
+
+struid2:x:30:badgid:struid2name:/home/struid:/usr/sbin/nologin
+`
+
+var userIdTests = []struct {
+	in   string
+	uid  string
+	name string
+}{
+	{testUserFile, "-5", "negative"},
+	{testUserFile, "2", "bin"},
+	{testUserFile, "100", ""}, // not in the file
+	{testUserFile, "8", ""},   // plus sign, glibc doesn't find it
+	{testUserFile, "9", ""},   // minus sign, glibc doesn't find it
+	{testUserFile, "27", ""},  // malformed
+	{testUserFile, "28", ""},  // commented out
+	{testUserFile, "29", ""},  // commented out, indented
+	{testUserFile, "3", "indented"},
+	{testUserFile, "30", ""}, // the Gid is not valid, shouldn't match
+	{"", "1", ""},
+}
+
+func TestInvalidUserId(t *testing.T) {
+	_, err := findUserId("notanumber", strings.NewReader(""))
+	if err == nil {
+		t.Fatalf("findUserId('notanumber'): got nil error")
+	}
+	if want := "user: invalid userid notanumber"; err.Error() != want {
+		t.Errorf("findUserId('notanumber'): got %v, want %s", err, want)
+	}
+}
+
+func TestLookupUserId(t *testing.T) {
+	for _, tt := range userIdTests {
+		got, err := findUserId(tt.uid, strings.NewReader(tt.in))
+		if tt.name == "" {
+			if err == nil {
+				t.Errorf("findUserId(%s): got nil error, expected err", tt.uid)
+				continue
+			}
+			switch terr := err.(type) {
+			case UnknownUserIdError:
+				if want := "user: unknown userid " + tt.uid; terr.Error() != want {
+					t.Errorf("findUserId(%s): got %v, want %v", tt.name, terr, want)
+				}
+			default:
+				t.Errorf("findUserId(%s): got unexpected error %v", tt.name, terr)
+			}
+		} else {
+			if err != nil {
+				t.Fatalf("findUserId(%s): got unexpected error %v", tt.name, err)
+			}
+			if got.Uid != tt.uid {
+				t.Errorf("findUserId(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid)
+			}
+			if got.Username != tt.name {
+				t.Errorf("findUserId(%s): got name %s, want %s", tt.name, got.Username, tt.name)
+			}
+		}
+	}
+}
+
+func TestLookupUserPopulatesAllFields(t *testing.T) {
+	u, err := findUsername("allfields", strings.NewReader(testUserFile))
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := &User{
+		Username: "allfields",
+		Uid:      "6",
+		Gid:      "12",
+		Name:     "mansplit",
+		HomeDir:  "/home/allfields",
+	}
+	if !reflect.DeepEqual(u, want) {
+		t.Errorf("findUsername: got %#v, want %#v", u, want)
+	}
+}
+
+var userTests = []struct {
+	in   string
+	name string
+	uid  string
+}{
+	{testUserFile, "negative", "-5"},
+	{testUserFile, "bin", "2"},
+	{testUserFile, "notinthefile", ""},
+	{testUserFile, "indented", "3"},
+	{testUserFile, "plussign", ""},
+	{testUserFile, "+plussign", ""},
+	{testUserFile, "minussign", ""},
+	{testUserFile, "-minussign", ""},
+	{testUserFile, "   indented", ""},
+	{testUserFile, "commented", ""},
+	{testUserFile, "commentindented", ""},
+	{testUserFile, "malformed", ""},
+	{testUserFile, "# commented", ""},
+	{"", "emptyfile", ""},
+}
+
+func TestLookupUser(t *testing.T) {
+	for _, tt := range userTests {
+		got, err := findUsername(tt.name, strings.NewReader(tt.in))
+		if tt.uid == "" {
+			if err == nil {
+				t.Errorf("lookupUser(%s): got nil error, expected err", tt.uid)
+				continue
+			}
+			switch terr := err.(type) {
+			case UnknownUserError:
+				if want := "user: unknown user " + tt.name; terr.Error() != want {
+					t.Errorf("lookupUser(%s): got %v, want %v", tt.name, terr, want)
+				}
+			default:
+				t.Errorf("lookupUser(%s): got unexpected error %v", tt.name, terr)
+			}
+		} else {
+			if err != nil {
+				t.Fatalf("lookupUser(%s): got unexpected error %v", tt.name, err)
+			}
+			if got.Uid != tt.uid {
+				t.Errorf("lookupUser(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid)
+			}
+			if got.Username != tt.name {
+				t.Errorf("lookupUser(%s): got name %s, want %s", tt.name, got.Username, tt.name)
+			}
+		}
+	}
+}
diff --git a/src/os/user/user_test.go b/src/os/user/user_test.go
index 9d8d94d..b3aeed8 100644
--- a/src/os/user/user_test.go
+++ b/src/os/user/user_test.go
@@ -16,9 +16,6 @@ func checkUser(t *testing.T) {
 }
 
 func TestCurrent(t *testing.T) {
-	if runtime.GOOS == "android" {
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
 	u, err := Current()
 	if err != nil {
 		t.Fatalf("Current: %v (got %#v)", err, u)
@@ -31,6 +28,12 @@ func TestCurrent(t *testing.T) {
 	}
 }
 
+func BenchmarkCurrent(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		Current()
+	}
+}
+
 func compare(t *testing.T, want, got *User) {
 	if want.Uid != got.Uid {
 		t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)
@@ -64,6 +67,9 @@ func TestLookup(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Current: %v", err)
 	}
+	// TODO: Lookup() has a fast path that calls Current() and returns if the
+	// usernames match, so this test does not exercise very much. It would be
+	// good to try and test finding a different user than the current user.
 	got, err := Lookup(want.Username)
 	if err != nil {
 		t.Fatalf("Lookup: %v", err)
diff --git a/src/os/wait_unimp.go b/src/os/wait_unimp.go
index 7059e59..b71e93f 100644
--- a/src/os/wait_unimp.go
+++ b/src/os/wait_unimp.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build dragonfly nacl netbsd openbsd solaris
+// +build darwin dragonfly nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
index 653fce9..a6c5c72 100644
--- a/src/os/wait_waitid.go
+++ b/src/os/wait_waitid.go
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin linux
+// We used to used this code for Darwin, but according to issue #19314
+// waitid returns if the process is stopped, even when using WEXITED.
+
+// +build linux
 
 package os
 
diff --git a/src/path/example_test.go b/src/path/example_test.go
index e8d684f..07f9de3 100644
--- a/src/path/example_test.go
+++ b/src/path/example_test.go
@@ -11,7 +11,12 @@ import (
 
 func ExampleBase() {
 	fmt.Println(path.Base("/a/b"))
-	// Output: b
+	fmt.Println(path.Base("/"))
+	fmt.Println(path.Base(""))
+	// Output:
+	// b
+	// /
+	// .
 }
 
 func ExampleClean() {
@@ -22,6 +27,7 @@ func ExampleClean() {
 		"a/c/b/..",
 		"/../a/c",
 		"/../a/b/../././/c",
+		"",
 	}
 
 	for _, p := range paths {
@@ -35,16 +41,29 @@ func ExampleClean() {
 	// Clean("a/c/b/..") = "a/c"
 	// Clean("/../a/c") = "/a/c"
 	// Clean("/../a/b/../././/c") = "/a/c"
+	// Clean("") = "."
 }
 
 func ExampleDir() {
 	fmt.Println(path.Dir("/a/b/c"))
-	// Output: /a/b
+	fmt.Println(path.Dir("a/b/c"))
+	fmt.Println(path.Dir("/"))
+	fmt.Println(path.Dir(""))
+	// Output:
+	// /a/b
+	// a/b
+	// /
+	// .
 }
 
 func ExampleExt() {
 	fmt.Println(path.Ext("/a/b/c/bar.css"))
-	// Output: .css
+	fmt.Println(path.Ext("/"))
+	fmt.Println(path.Ext(""))
+	// Output:
+	// .css
+	//
+	//
 }
 
 func ExampleIsAbs() {
@@ -56,15 +75,24 @@ func ExampleJoin() {
 	fmt.Println(path.Join("a", "b", "c"))
 	fmt.Println(path.Join("a", "b/c"))
 	fmt.Println(path.Join("a/b", "c"))
-	fmt.Println(path.Join("a/b", "/c"))
+	fmt.Println(path.Join("", ""))
+	fmt.Println(path.Join("a", ""))
+	fmt.Println(path.Join("", "a"))
 	// Output:
 	// a/b/c
 	// a/b/c
 	// a/b/c
-	// a/b/c
+	//
+	// a
+	// a
 }
 
 func ExampleSplit() {
 	fmt.Println(path.Split("static/myfile.css"))
-	// Output: static/ myfile.css
+	fmt.Println(path.Split("myfile.css"))
+	fmt.Println(path.Split(""))
+	// Output:
+	// static/ myfile.css
+	//  myfile.css
+	//
 }
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index 1d8e35c..c242143 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -4,6 +4,11 @@
 
 // Package filepath implements utility routines for manipulating filename paths
 // in a way compatible with the target operating system-defined file paths.
+//
+// The filepath package uses either forward slashes or backslashes,
+// depending on the operating system. To process paths such as URLs
+// that always use forward slashes regardless of the operating
+// system, see the path package.
 package filepath
 
 import (
@@ -461,6 +466,10 @@ func Dir(path string) string {
 		i--
 	}
 	dir := Clean(path[len(vol) : i+1])
+	if dir == "." && len(vol) > 2 {
+		// must be UNC
+		return vol
+	}
 	return vol + dir
 }
 
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 921b238..315f61e 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -6,12 +6,14 @@ package filepath_test
 
 import (
 	"errors"
+	"fmt"
 	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"sort"
 	"strings"
 	"testing"
 )
@@ -386,7 +388,7 @@ func checkMarks(t *testing.T, report bool) {
 // Assumes that each node name is unique. Good enough for a test.
 // If clear is true, any incoming error is cleared before return. The errors
 // are always accumulated, though.
-func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
+func mark(info os.FileInfo, err error, errors *[]error, clear bool) error {
 	if err != nil {
 		*errors = append(*errors, err)
 		if clear {
@@ -435,7 +437,7 @@ func TestWalk(t *testing.T) {
 	errors := make([]error, 0, 10)
 	clear := true
 	markFn := func(path string, info os.FileInfo, err error) error {
-		return mark(path, info, err, &errors, clear)
+		return mark(info, err, &errors, clear)
 	}
 	// Expect no errors.
 	err := filepath.Walk(tree.name, markFn)
@@ -665,6 +667,7 @@ var windirtests = []PathTest{
 	{`c:\a\b`, `c:\a`},
 	{`c:a\b`, `c:a`},
 	{`c:a\b\c`, `c:a\b`},
+	{`\\host\share`, `\\host\share`},
 	{`\\host\share\`, `\\host\share\`},
 	{`\\host\share\a`, `\\host\share\`},
 	{`\\host\share\a\b`, `\\host\share\a`},
@@ -1326,3 +1329,53 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
 		t.Fatalf("%q not seen", ken)
 	}
 }
+
+func testWalkSymlink(t *testing.T, mklink func(target, link string) error) {
+	tmpdir, err := ioutil.TempDir("", "testWalkSymlink")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Chdir(wd)
+
+	err = os.Chdir(tmpdir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = mklink(tmpdir, "link")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var visited []string
+	err = filepath.Walk(tmpdir, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			t.Fatal(err)
+		}
+		rel, err := filepath.Rel(tmpdir, path)
+		if err != nil {
+			t.Fatal(err)
+		}
+		visited = append(visited, rel)
+		return nil
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	sort.Strings(visited)
+	want := []string{".", "link"}
+	if fmt.Sprintf("%q", visited) != fmt.Sprintf("%q", want) {
+		t.Errorf("unexpected paths visited %q, want %q", visited, want)
+	}
+}
+
+func TestWalkSymlink(t *testing.T) {
+	testenv.MustHaveSymlink(t)
+	testWalkSymlink(t, os.Symlink)
+}
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index 73e74be..d759a83 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -7,6 +7,7 @@ package filepath_test
 import (
 	"flag"
 	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -67,6 +68,9 @@ func testWinSplitListTestIsValid(t *testing.T, ti int, tt SplitListTest,
 		}
 	}
 
+	// on some systems, SystemRoot is required for cmd to work
+	systemRoot := os.Getenv("SystemRoot")
+
 	for i, d := range tt.result {
 		if d == "" {
 			continue
@@ -75,7 +79,7 @@ func testWinSplitListTestIsValid(t *testing.T, ti int, tt SplitListTest,
 		cmd := &exec.Cmd{
 			Path: comspec,
 			Args: []string{`/c`, cmdfile},
-			Env:  []string{`Path=` + tt.list},
+			Env:  []string{`Path=` + tt.list, `SystemRoot=` + systemRoot},
 			Dir:  tmp,
 		}
 		out, err := cmd.CombinedOutput()
@@ -430,3 +434,27 @@ func TestUNC(t *testing.T) {
 	defer debug.SetMaxStack(debug.SetMaxStack(1e6))
 	filepath.Glob(`\\?\c:\*`)
 }
+
+func testWalkMklink(t *testing.T, linktype string) {
+	output, _ := exec.Command("cmd", "/c", "mklink", "/?").Output()
+	if !strings.Contains(string(output), fmt.Sprintf(" /%s ", linktype)) {
+		t.Skipf(`skipping test; mklink does not supports /%s parameter`, linktype)
+	}
+	testWalkSymlink(t, func(target, link string) error {
+		output, err := exec.Command("cmd", "/c", "mklink", "/"+linktype, link, target).CombinedOutput()
+		if err != nil {
+			return fmt.Errorf(`"mklink /%s %v %v" command failed: %v\n%v`, linktype, link, target, err, string(output))
+		}
+		return nil
+	})
+}
+
+func TestWalkDirectoryJunction(t *testing.T) {
+	testenv.MustHaveSymlink(t)
+	testWalkMklink(t, "J")
+}
+
+func TestWalkDirectorySymlink(t *testing.T) {
+	testenv.MustHaveSymlink(t)
+	testWalkMklink(t, "D")
+}
diff --git a/src/path/path.go b/src/path/path.go
index 76c7814..5c90511 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -5,7 +5,10 @@
 // Package path implements utility routines for manipulating slash-separated
 // paths.
 //
-// To manipulate operating system paths, use the path/filepath package.
+// The path package should only be used for paths separated by forward
+// slashes, such as the paths in URLs. This package does not deal with
+// Windows paths with drive letters or backslashes; to manipulate
+// operating system paths, use the path/filepath package.
 package path
 
 import (
diff --git a/src/plugin/plugin.go b/src/plugin/plugin.go
index b86099a..3dc7964 100644
--- a/src/plugin/plugin.go
+++ b/src/plugin/plugin.go
@@ -44,9 +44,6 @@ func (p *Plugin) Lookup(symName string) (Symbol, error) {
 //
 //	package main
 //
-//	// // No C code needed.
-//	import "C"
-//
 //	import "fmt"
 //
 //	var V int
diff --git a/src/plugin/plugin_dlopen.go b/src/plugin/plugin_dlopen.go
index c5b0a47..3237598 100644
--- a/src/plugin/plugin_dlopen.go
+++ b/src/plugin/plugin_dlopen.go
@@ -39,6 +39,47 @@ import (
 	"unsafe"
 )
 
+// avoid a dependency on strings
+func lastIndexByte(s string, c byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
+
+// pathToPrefix converts raw string to the prefix that will be used in the symbol
+// table. If modifying, modify the version in internal/obj/sym.go as well.
+func pathToPrefix(s string) string {
+	slash := lastIndexByte(s, '/')
+	// check for chars that need escaping
+	n := 0
+	for r := 0; r < len(s); r++ {
+		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+			n++
+		}
+	}
+
+	// quick exit
+	if n == 0 {
+		return s
+	}
+
+	// escape
+	const hex = "0123456789abcdef"
+	p := make([]byte, 0, len(s)+2*n)
+	for r := 0; r < len(s); r++ {
+		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+			p = append(p, '%', hex[c>>4], hex[c&0xF])
+		} else {
+			p = append(p, c)
+		}
+	}
+
+	return string(p)
+}
+
 func open(name string) (*Plugin, error) {
 	cPath := (*C.char)(C.malloc(C.PATH_MAX + 1))
 	defer C.free(unsafe.Pointer(cPath))
@@ -82,7 +123,6 @@ func open(name string) (*Plugin, error) {
 	p := &Plugin{
 		pluginpath: pluginpath,
 		loaded:     make(chan struct{}),
-		syms:       syms,
 	}
 	plugins[filepath] = p
 	pluginsMu.Unlock()
@@ -97,14 +137,14 @@ func open(name string) (*Plugin, error) {
 	}
 
 	// Fill out the value of each plugin symbol.
+	updatedSyms := map[string]interface{}{}
 	for symName, sym := range syms {
 		isFunc := symName[0] == '.'
 		if isFunc {
 			delete(syms, symName)
 			symName = symName[1:]
 		}
-
-		cname := C.CString(pluginpath + "." + symName)
+		cname := C.CString(pathToPrefix(pluginpath) + "." + symName)
 		p := C.pluginLookup(h, cname, &cErr)
 		C.free(unsafe.Pointer(cname))
 		if p == nil {
@@ -116,8 +156,12 @@ func open(name string) (*Plugin, error) {
 		} else {
 			(*valp)[1] = p
 		}
-		syms[symName] = sym
+		// we can't add to syms during iteration as we'll end up processing
+		// some symbols twice with the inability to tell if the symbol is a function
+		updatedSyms[symName] = sym
 	}
+	p.syms = updatedSyms
+
 	close(p.loaded)
 	return p, nil
 }
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 7f8c129..308cb77 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -1576,9 +1576,11 @@ func BenchmarkCallArgCopy(b *testing.B) {
 			args := []Value{size.arg}
 			b.SetBytes(int64(size.arg.Len()))
 			b.ResetTimer()
-			for i := 0; i < b.N; i++ {
-				size.fv.Call(args)
-			}
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					size.fv.Call(args)
+				}
+			})
 		}
 		name := fmt.Sprintf("size=%v", size.arg.Len())
 		b.Run(name, bench)
@@ -2556,6 +2558,28 @@ func TestPtrToGC(t *testing.T) {
 	}
 }
 
+func BenchmarkPtrTo(b *testing.B) {
+	// Construct a type with a zero ptrToThis.
+	type T struct{ int }
+	t := SliceOf(TypeOf(T{}))
+	ptrToThis := ValueOf(t).Elem().FieldByName("ptrToThis")
+	if !ptrToThis.IsValid() {
+		b.Fatalf("%v has no ptrToThis field; was it removed from rtype?", t)
+	}
+	if ptrToThis.Int() != 0 {
+		b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
+	}
+	b.ResetTimer()
+
+	// Now benchmark calling PtrTo on it: we'll have to hit the ptrMap cache on
+	// every call.
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			PtrTo(t)
+		}
+	})
+}
+
 func TestAddr(t *testing.T) {
 	var p struct {
 		X, Y int
@@ -3731,7 +3755,7 @@ func checkSameType(t *testing.T, x, y interface{}) {
 
 func TestArrayOf(t *testing.T) {
 	// check construction and use of type not in binary
-	for _, table := range []struct {
+	tests := []struct {
 		n          int
 		value      func(i int) interface{}
 		comparable bool
@@ -3809,7 +3833,9 @@ func TestArrayOf(t *testing.T) {
 			comparable: true,
 			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
 		},
-	} {
+	}
+
+	for _, table := range tests {
 		at := ArrayOf(table.n, TypeOf(table.value(0)))
 		v := New(at).Elem()
 		vok := New(at).Elem()
@@ -4037,6 +4063,54 @@ func TestSliceOfGC(t *testing.T) {
 	}
 }
 
+func TestStructOfFieldName(t *testing.T) {
+	// invalid field name "1nvalid"
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Name: "valid", Type: TypeOf("")},
+			StructField{Name: "1nvalid", Type: TypeOf("")},
+		})
+	})
+
+	// invalid field name "+"
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Name: "val1d", Type: TypeOf("")},
+			StructField{Name: "+", Type: TypeOf("")},
+		})
+	})
+
+	// no field name
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Name: "", Type: TypeOf("")},
+		})
+	})
+
+	// verify creation of a struct with valid struct fields
+	validFields := []StructField{
+		StructField{
+			Name: "φ",
+			Type: TypeOf(""),
+		},
+		StructField{
+			Name: "ValidName",
+			Type: TypeOf(""),
+		},
+		StructField{
+			Name: "Val1dNam5",
+			Type: TypeOf(""),
+		},
+	}
+
+	validStruct := StructOf(validFields)
+
+	const structStr = `struct { φ string; ValidName string; Val1dNam5 string }`
+	if got, want := validStruct.String(), structStr; got != want {
+		t.Errorf("StructOf(validFields).String()=%q, want %q", got, want)
+	}
+}
+
 func TestStructOf(t *testing.T) {
 	// check construction and use of type not in binary
 	fields := []StructField{
@@ -4175,50 +4249,58 @@ func TestStructOfExportRules(t *testing.T) {
 		f()
 	}
 
-	for i, test := range []struct {
+	tests := []struct {
 		field     StructField
 		mustPanic bool
 		exported  bool
 	}{
 		{
-			field:     StructField{Name: "", Type: TypeOf(S1{})},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{})},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*S1)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil))},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf(s2{})},
-			mustPanic: false,
-			exported:  false,
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{})},
+			mustPanic: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*s2)(nil))},
-			mustPanic: false,
-			exported:  false,
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil))},
+			mustPanic: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			field:     StructField{Name: "Name", Type: nil, PkgPath: ""},
 			mustPanic: true,
-			exported:  true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: ""},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
 			mustPanic: true,
-			exported:  true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+			field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "S", Type: TypeOf(S1{})},
@@ -4226,81 +4308,68 @@ func TestStructOfExportRules(t *testing.T) {
 			exported:  true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf((*S1)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf(s2{})},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf(s2{})},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf((*s2)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+			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,
+			mustPanic: true,
 		},
 		{
 			field:     StructField{Name: "", Type: TypeOf(φType{})},
-			mustPanic: false,
-			exported:  false,
+			mustPanic: true,
 		},
 		{
-			field:     StructField{Name: "Φ", Type: TypeOf(0)},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "Φ", Type: TypeOf(0)},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "φ", Type: TypeOf(0)},
-			mustPanic: false,
-			exported:  false,
+			field:    StructField{Name: "φ", Type: TypeOf(0)},
+			exported: false,
 		},
-	} {
+	}
+
+	for i, test := range tests {
 		testPanic(i, test.mustPanic, func() {
 			typ := StructOf([]StructField{test.field})
 			if typ == nil {
@@ -4310,7 +4379,7 @@ func TestStructOfExportRules(t *testing.T) {
 			field := typ.Field(0)
 			n := field.Name
 			if n == "" {
-				n = field.Type.Name()
+				panic("field.Name must not be empty")
 			}
 			exported := isExported(n)
 			if exported != test.exported {
@@ -4388,7 +4457,7 @@ func TestStructOfGenericAlg(t *testing.T) {
 		{Name: "S1", Type: st1},
 	})
 
-	for _, table := range []struct {
+	tests := []struct {
 		rt  Type
 		idx []int
 	}{
@@ -4469,7 +4538,9 @@ func TestStructOfGenericAlg(t *testing.T) {
 			),
 			idx: []int{2},
 		},
-	} {
+	}
+
+	for _, table := range tests {
 		v1 := New(table.rt).Elem()
 		v2 := New(table.rt).Elem()
 
@@ -4571,18 +4642,21 @@ func TestStructOfWithInterface(t *testing.T) {
 	type Iface interface {
 		Get() int
 	}
-	for i, table := range []struct {
+	tests := []struct {
+		name string
 		typ  Type
 		val  Value
 		impl bool
 	}{
 		{
+			name: "StructI",
 			typ:  TypeOf(StructI(want)),
 			val:  ValueOf(StructI(want)),
 			impl: true,
 		},
 		{
-			typ: PtrTo(TypeOf(StructI(want))),
+			name: "StructI",
+			typ:  PtrTo(TypeOf(StructI(want))),
 			val: ValueOf(func() interface{} {
 				v := StructI(want)
 				return &v
@@ -4590,7 +4664,8 @@ func TestStructOfWithInterface(t *testing.T) {
 			impl: true,
 		},
 		{
-			typ: PtrTo(TypeOf(StructIPtr(want))),
+			name: "StructIPtr",
+			typ:  PtrTo(TypeOf(StructIPtr(want))),
 			val: ValueOf(func() interface{} {
 				v := StructIPtr(want)
 				return &v
@@ -4598,6 +4673,7 @@ func TestStructOfWithInterface(t *testing.T) {
 			impl: true,
 		},
 		{
+			name: "StructIPtr",
 			typ:  TypeOf(StructIPtr(want)),
 			val:  ValueOf(StructIPtr(want)),
 			impl: false,
@@ -4607,13 +4683,16 @@ func TestStructOfWithInterface(t *testing.T) {
 		//	val:  ValueOf(StructI(want)),
 		//	impl: true,
 		// },
-	} {
+	}
+
+	for i, table := range tests {
 		rt := StructOf(
 			[]StructField{
 				{
-					Name:    "",
-					PkgPath: "",
-					Type:    table.typ,
+					Name:      table.name,
+					Anonymous: true,
+					PkgPath:   "",
+					Type:      table.typ,
 				},
 			},
 		)
@@ -4902,16 +4981,20 @@ type B1 struct {
 
 func BenchmarkFieldByName1(b *testing.B) {
 	t := TypeOf(B1{})
-	for i := 0; i < b.N; i++ {
-		t.FieldByName("Z")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			t.FieldByName("Z")
+		}
+	})
 }
 
 func BenchmarkFieldByName2(b *testing.B) {
 	t := TypeOf(S3{})
-	for i := 0; i < b.N; i++ {
-		t.FieldByName("B")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			t.FieldByName("B")
+		}
+	})
 }
 
 type R0 struct {
@@ -4994,9 +5077,11 @@ func TestEmbed(t *testing.T) {
 
 func BenchmarkFieldByName3(b *testing.B) {
 	t := TypeOf(R0{})
-	for i := 0; i < b.N; i++ {
-		t.FieldByName("X")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			t.FieldByName("X")
+		}
+	})
 }
 
 type S struct {
@@ -5006,9 +5091,11 @@ type S struct {
 
 func BenchmarkInterfaceBig(b *testing.B) {
 	v := ValueOf(S{})
-	for i := 0; i < b.N; i++ {
-		v.Interface()
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			v.Interface()
+		}
+	})
 	b.StopTimer()
 }
 
@@ -5024,9 +5111,11 @@ func TestAllocsInterfaceBig(t *testing.T) {
 
 func BenchmarkInterfaceSmall(b *testing.B) {
 	v := ValueOf(int64(0))
-	for i := 0; i < b.N; i++ {
-		v.Interface()
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			v.Interface()
+		}
+	})
 }
 
 func TestAllocsInterfaceSmall(t *testing.T) {
@@ -5820,7 +5909,7 @@ func TestTypeOfTypeOf(t *testing.T) {
 	check("SliceOf", SliceOf(TypeOf(T{})))
 }
 
-type XM struct{}
+type XM struct{ _ bool }
 
 func (*XM) String() string { return "" }
 
@@ -5843,6 +5932,24 @@ func TestMapAlloc(t *testing.T) {
 	if allocs > 0.5 {
 		t.Errorf("allocs per map assignment: want 0 got %f", allocs)
 	}
+
+	const size = 1000
+	tmp := 0
+	val := ValueOf(&tmp).Elem()
+	allocs = testing.AllocsPerRun(100, func() {
+		mv := MakeMapWithSize(TypeOf(map[int]int{}), size)
+		// Only adding half of the capacity to not trigger re-allocations due too many overloaded buckets.
+		for i := 0; i < size/2; i++ {
+			val.SetInt(int64(i))
+			mv.SetMapIndex(val, val)
+		}
+	})
+	if allocs > 10 {
+		t.Errorf("allocs per map assignment: want at most 10 got %f", allocs)
+	}
+	// Empirical testing shows that with capacity hint single run will trigger 3 allocations and without 91. I set
+	// the threshold to 10, to not make it overly brittle if something changes in the initial allocation of the
+	// map, but to still catch a regression where we keep re-allocating in the hashmap as new entries are added.
 }
 
 func TestChanAlloc(t *testing.T) {
@@ -5956,6 +6063,8 @@ func TestTypeStrings(t *testing.T) {
 		{TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"},
 		{ChanOf(3, TypeOf(XM{})), "chan reflect_test.XM"},
 		{MapOf(TypeOf(int(0)), TypeOf(XM{})), "map[int]reflect_test.XM"},
+		{ArrayOf(3, TypeOf(XM{})), "[3]reflect_test.XM"},
+		{ArrayOf(3, TypeOf(struct{}{})), "[3]struct {}"},
 	}
 
 	for i, test := range stringTests {
@@ -5982,9 +6091,11 @@ func TestOffsetLock(t *testing.T) {
 
 func BenchmarkNew(b *testing.B) {
 	v := TypeOf(XM{})
-	for i := 0; i < b.N; i++ {
-		New(v)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			New(v)
+		}
+	})
 }
 
 func TestSwapper(t *testing.T) {
@@ -6059,6 +6170,7 @@ func TestSwapper(t *testing.T) {
 			want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
 		},
 	}
+
 	for i, tt := range tests {
 		inStr := fmt.Sprint(tt.in)
 		Swapper(tt.in)(tt.i, tt.j)
@@ -6084,3 +6196,36 @@ func TestUnaddressableField(t *testing.T) {
 		lv.Set(rv)
 	})
 }
+
+type Tint int
+
+type Tint2 = Tint
+
+type Talias1 struct {
+	byte
+	uint8
+	int
+	int32
+	rune
+}
+
+type Talias2 struct {
+	Tint
+	Tint2
+}
+
+func TestAliasNames(t *testing.T) {
+	t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
+	out := fmt.Sprintf("%#v", t1)
+	want := "reflect_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
+	if out != want {
+		t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
+	}
+
+	t2 := Talias2{Tint: 1, Tint2: 2}
+	out = fmt.Sprintf("%#v", t2)
+	want = "reflect_test.Talias2{Tint:1, Tint2:2}"
+	if out != want {
+		t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
+	}
+}
diff --git a/src/reflect/set_test.go b/src/reflect/set_test.go
index bc35c78..7c39623 100644
--- a/src/reflect/set_test.go
+++ b/src/reflect/set_test.go
@@ -7,6 +7,7 @@ package reflect_test
 import (
 	"bytes"
 	"go/ast"
+	"go/token"
 	"io"
 	. "reflect"
 	"testing"
@@ -172,6 +173,23 @@ var implementsTests = []struct {
 	{new(bytes.Buffer), new(io.Reader), false},
 	{new(*bytes.Buffer), new(io.ReaderAt), false},
 	{new(*ast.Ident), new(ast.Expr), true},
+	{new(*notAnExpr), new(ast.Expr), false},
+	{new(*ast.Ident), new(notASTExpr), false},
+	{new(notASTExpr), new(ast.Expr), false},
+	{new(ast.Expr), new(notASTExpr), false},
+	{new(*notAnExpr), new(notASTExpr), true},
+}
+
+type notAnExpr struct{}
+
+func (notAnExpr) Pos() token.Pos { return token.NoPos }
+func (notAnExpr) End() token.Pos { return token.NoPos }
+func (notAnExpr) exprNode()      {}
+
+type notASTExpr interface {
+	Pos() token.Pos
+	End() token.Pos
+	exprNode()
 }
 
 func TestImplements(t *testing.T) {
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 5d3c5c6..14c16fc 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -19,6 +19,8 @@ import (
 	"runtime"
 	"strconv"
 	"sync"
+	"unicode"
+	"unicode/utf8"
 	"unsafe"
 )
 
@@ -289,9 +291,11 @@ const (
 // 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.
+//
+// rtype must be kept in sync with ../runtime/type.go:/^type._type.
 type rtype struct {
 	size       uintptr
-	ptrdata    uintptr
+	ptrdata    uintptr  // number of bytes in the type that can contain pointers
 	hash       uint32   // hash of type; avoids computation in hash tables
 	tflag      tflag    // extra type information flags
 	align      uint8    // alignment of variable with this type
@@ -417,9 +421,17 @@ type sliceType struct {
 
 // Struct field
 type structField struct {
-	name   name    // name is empty for embedded fields
-	typ    *rtype  // type of field
-	offset uintptr // byte offset of field within struct
+	name       name    // name is always non-empty
+	typ        *rtype  // type of field
+	offsetAnon uintptr // byte offset of field<<1 | isAnonymous
+}
+
+func (f *structField) offset() uintptr {
+	return f.offsetAnon >> 1
+}
+
+func (f *structField) anon() bool {
+	return f.offsetAnon&1 != 0
 }
 
 // structType represents a struct type.
@@ -772,18 +784,12 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
 
 func (t *rtype) common() *rtype { return t }
 
-var methodCache struct {
-	sync.RWMutex
-	m map[*rtype][]method
-}
+var methodCache sync.Map // map[*rtype][]method
 
 func (t *rtype) exportedMethods() []method {
-	methodCache.RLock()
-	methods, found := methodCache.m[t]
-	methodCache.RUnlock()
-
+	methodsi, found := methodCache.Load(t)
 	if found {
-		return methods
+		return methodsi.([]method)
 	}
 
 	ut := t.uncommon()
@@ -799,6 +805,7 @@ func (t *rtype) exportedMethods() []method {
 			break
 		}
 	}
+	var methods []method
 	if allExported {
 		methods = allm
 	} else {
@@ -812,14 +819,8 @@ func (t *rtype) exportedMethods() []method {
 		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
+	methodsi, _ = methodCache.LoadOrStore(t, methods)
+	return methodsi.([]method)
 }
 
 func (t *rtype) NumMethod() int {
@@ -828,7 +829,7 @@ func (t *rtype) NumMethod() int {
 		return tt.NumMethod()
 	}
 	if t.tflag&tflagUncommon == 0 {
-		return 0 // avoid methodCache lock in zero case
+		return 0 // avoid methodCache synchronization
 	}
 	return len(t.exportedMethods())
 }
@@ -1215,16 +1216,8 @@ func (t *structType) Field(i int) (f StructField) {
 	}
 	p := &t.fields[i]
 	f.Type = toType(p.typ)
-	if name := p.name.name(); name != "" {
-		f.Name = name
-	} else {
-		t := f.Type
-		if t.Kind() == Ptr {
-			t = t.Elem()
-		}
-		f.Name = t.Name()
-		f.Anonymous = true
-	}
+	f.Name = p.name.name()
+	f.Anonymous = p.anon()
 	if !p.name.isExported() {
 		f.PkgPath = p.name.pkgPath()
 		if f.PkgPath == "" {
@@ -1234,7 +1227,7 @@ func (t *structType) Field(i int) (f StructField) {
 	if tag := p.name.tag(); tag != "" {
 		f.Tag = StructTag(tag)
 	}
-	f.Offset = p.offset
+	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,
@@ -1321,19 +1314,15 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
 			visited[t] = true
 			for i := range t.fields {
 				f := &t.fields[i]
-				// Find name and type for field f.
-				var fname string
+				// Find name and (for anonymous field) type for field f.
+				fname := f.name.name()
 				var ntyp *rtype
-				if name := f.name.name(); name != "" {
-					fname = name
-				} else {
+				if f.anon() {
 					// Anonymous field of type T or *T.
-					// Name taken from type.
 					ntyp = f.typ
 					if ntyp.Kind() == Ptr {
 						ntyp = ntyp.Elem().common()
 					}
-					fname = ntyp.Name()
 				}
 
 				// Does it match?
@@ -1390,14 +1379,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
 	if name != "" {
 		for i := range t.fields {
 			tf := &t.fields[i]
-			tfname := tf.name.name()
-			if tfname == "" {
-				hasAnon = true
-				continue
-			}
-			if tfname == name {
+			if tf.name.name() == name {
 				return t.Field(i), true
 			}
+			if tf.anon() {
+				hasAnon = true
+			}
 		}
 	}
 	if !hasAnon {
@@ -1414,10 +1401,7 @@ func TypeOf(i interface{}) Type {
 }
 
 // ptrMap is the cache for PtrTo.
-var ptrMap struct {
-	sync.RWMutex
-	m map[*rtype]*ptrType
-}
+var ptrMap sync.Map // map[*rtype]*ptrType
 
 // PtrTo returns the pointer type with element t.
 // For example, if t represents type Foo, PtrTo(t) represents *Foo.
@@ -1431,35 +1415,19 @@ func (t *rtype) ptrTo() *rtype {
 	}
 
 	// Check the cache.
-	ptrMap.RLock()
-	if m := ptrMap.m; m != nil {
-		if p := m[t]; p != nil {
-			ptrMap.RUnlock()
-			return &p.rtype
-		}
-	}
-	ptrMap.RUnlock()
-
-	ptrMap.Lock()
-	if ptrMap.m == nil {
-		ptrMap.m = make(map[*rtype]*ptrType)
-	}
-	p := ptrMap.m[t]
-	if p != nil {
-		// some other goroutine won the race and created it
-		ptrMap.Unlock()
-		return &p.rtype
+	if pi, ok := ptrMap.Load(t); ok {
+		return &pi.(*ptrType).rtype
 	}
 
 	// Look in known types.
 	s := "*" + t.String()
 	for _, tt := range typesByString(s) {
-		p = (*ptrType)(unsafe.Pointer(tt))
-		if p.elem == t {
-			ptrMap.m[t] = p
-			ptrMap.Unlock()
-			return &p.rtype
+		p := (*ptrType)(unsafe.Pointer(tt))
+		if p.elem != t {
+			continue
 		}
+		pi, _ := ptrMap.LoadOrStore(t, p)
+		return &pi.(*ptrType).rtype
 	}
 
 	// Create a new ptrType starting with the description
@@ -1480,9 +1448,8 @@ func (t *rtype) ptrTo() *rtype {
 
 	pp.elem = t
 
-	ptrMap.m[t] = &pp
-	ptrMap.Unlock()
-	return &pp.rtype
+	pi, _ := ptrMap.LoadOrStore(t, &pp)
+	return &pi.(*ptrType).rtype
 }
 
 // fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
@@ -1550,8 +1517,23 @@ func implements(T, V *rtype) bool {
 		i := 0
 		for j := 0; j < len(v.methods); j++ {
 			tm := &t.methods[i]
+			tmName := t.nameOff(tm.name)
 			vm := &v.methods[j]
-			if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
+			vmName := V.nameOff(vm.name)
+			if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
+				if !tmName.isExported() {
+					tmPkgPath := tmName.pkgPath()
+					if tmPkgPath == "" {
+						tmPkgPath = t.pkgPath.name()
+					}
+					vmPkgPath := vmName.pkgPath()
+					if vmPkgPath == "" {
+						vmPkgPath = v.pkgPath.name()
+					}
+					if tmPkgPath != vmPkgPath {
+						continue
+					}
+				}
 				if i++; i >= len(t.methods) {
 					return true
 				}
@@ -1568,8 +1550,23 @@ func implements(T, V *rtype) bool {
 	vmethods := v.methods()
 	for j := 0; j < int(v.mcount); j++ {
 		tm := &t.methods[i]
+		tmName := t.nameOff(tm.name)
 		vm := vmethods[j]
-		if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
+		vmName := V.nameOff(vm.name)
+		if vmName.name() == tmName.name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
+			if !tmName.isExported() {
+				tmPkgPath := tmName.pkgPath()
+				if tmPkgPath == "" {
+					tmPkgPath = t.pkgPath.name()
+				}
+				vmPkgPath := vmName.pkgPath()
+				if vmPkgPath == "" {
+					vmPkgPath = V.nameOff(v.pkgPath).name()
+				}
+				if tmPkgPath != vmPkgPath {
+					continue
+				}
+			}
 			if i++; i >= len(t.methods) {
 				return true
 			}
@@ -1695,7 +1692,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
 			if cmpTags && tf.name.tag() != vf.name.tag() {
 				return false
 			}
-			if tf.offset != vf.offset {
+			if tf.offsetAnon != vf.offsetAnon {
 				return false
 			}
 			if !tf.name.isExported() {
@@ -1783,10 +1780,7 @@ func typesByString(s string) []*rtype {
 }
 
 // The lookupCache caches ArrayOf, ChanOf, MapOf and SliceOf lookups.
-var lookupCache struct {
-	sync.RWMutex
-	m map[cacheKey]*rtype
-}
+var lookupCache sync.Map // map[cacheKey]*rtype
 
 // A cacheKey is the key for use in the lookupCache.
 // Four values describe any of the types we are looking for:
@@ -1798,47 +1792,15 @@ type cacheKey struct {
 	extra uintptr
 }
 
-// cacheGet looks for a type under the key k in the lookupCache.
-// If it finds one, it returns that type.
-// If not, it returns nil with the cache locked.
-// The caller is expected to use cachePut to unlock the cache.
-func cacheGet(k cacheKey) Type {
-	lookupCache.RLock()
-	t := lookupCache.m[k]
-	lookupCache.RUnlock()
-	if t != nil {
-		return t
-	}
-
-	lookupCache.Lock()
-	t = lookupCache.m[k]
-	if t != nil {
-		lookupCache.Unlock()
-		return t
-	}
-
-	if lookupCache.m == nil {
-		lookupCache.m = make(map[cacheKey]*rtype)
-	}
-
-	return nil
-}
-
-// cachePut stores the given type in the cache, unlocks the cache,
-// and returns the type. It is expected that the cache is locked
-// because cacheGet returned nil.
-func cachePut(k cacheKey, t *rtype) Type {
-	lookupCache.m[k] = t
-	lookupCache.Unlock()
-	return t
-}
-
 // The funcLookupCache caches FuncOf lookups.
 // FuncOf does not share the common lookupCache since cacheKey is not
 // sufficient to represent functions unambiguously.
 var funcLookupCache struct {
-	sync.RWMutex
-	m map[uint32][]*rtype // keyed by hash calculated in FuncOf
+	sync.Mutex // Guards stores (but not loads) on m.
+
+	// m is a map[uint32][]*rtype keyed by the hash calculated in FuncOf.
+	// Elements of m are append-only and thus safe for concurrent reading.
+	m sync.Map
 }
 
 // ChanOf returns the channel type with the given direction and element type.
@@ -1851,13 +1813,12 @@ func ChanOf(dir ChanDir, t Type) Type {
 
 	// Look in cache.
 	ckey := cacheKey{Chan, typ, nil, uintptr(dir)}
-	if ch := cacheGet(ckey); ch != nil {
-		return ch
+	if ch, ok := lookupCache.Load(ckey); ok {
+		return ch.(*rtype)
 	}
 
 	// This restriction is imposed by the gc compiler and the runtime.
 	if typ.size >= 1<<16 {
-		lookupCache.Unlock()
 		panic("reflect.ChanOf: element size too large")
 	}
 
@@ -1866,7 +1827,6 @@ func ChanOf(dir ChanDir, t Type) Type {
 	var s string
 	switch dir {
 	default:
-		lookupCache.Unlock()
 		panic("reflect.ChanOf: invalid dir")
 	case SendDir:
 		s = "chan<- " + typ.String()
@@ -1878,7 +1838,8 @@ func ChanOf(dir ChanDir, t Type) Type {
 	for _, tt := range typesByString(s) {
 		ch := (*chanType)(unsafe.Pointer(tt))
 		if ch.elem == typ && ch.dir == uintptr(dir) {
-			return cachePut(ckey, tt)
+			ti, _ := lookupCache.LoadOrStore(ckey, tt)
+			return ti.(Type)
 		}
 	}
 
@@ -1892,7 +1853,8 @@ func ChanOf(dir ChanDir, t Type) Type {
 	ch.hash = fnv1(typ.hash, 'c', byte(dir))
 	ch.elem = typ
 
-	return cachePut(ckey, &ch.rtype)
+	ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
+	return ti.(Type)
 }
 
 func ismapkey(*rtype) bool // implemented in runtime
@@ -1913,8 +1875,8 @@ func MapOf(key, elem Type) Type {
 
 	// Look in cache.
 	ckey := cacheKey{Map, ktyp, etyp, 0}
-	if mt := cacheGet(ckey); mt != nil {
-		return mt
+	if mt, ok := lookupCache.Load(ckey); ok {
+		return mt.(Type)
 	}
 
 	// Look in known types.
@@ -1922,7 +1884,8 @@ func MapOf(key, elem Type) Type {
 	for _, tt := range typesByString(s) {
 		mt := (*mapType)(unsafe.Pointer(tt))
 		if mt.key == ktyp && mt.elem == etyp {
-			return cachePut(ckey, tt)
+			ti, _ := lookupCache.LoadOrStore(ckey, tt)
+			return ti.(Type)
 		}
 	}
 
@@ -1954,7 +1917,8 @@ func MapOf(key, elem Type) Type {
 	mt.needkeyupdate = needKeyUpdate(ktyp)
 	mt.ptrToThis = 0
 
-	return cachePut(ckey, &mt.rtype)
+	ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
+	return ti.(Type)
 }
 
 type funcTypeFixed4 struct {
@@ -2059,42 +2023,46 @@ func FuncOf(in, out []Type, variadic bool) Type {
 	}
 
 	// Look in cache.
-	funcLookupCache.RLock()
-	for _, t := range funcLookupCache.m[hash] {
-		if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
-			funcLookupCache.RUnlock()
-			return t
+	if ts, ok := funcLookupCache.m.Load(hash); ok {
+		for _, t := range ts.([]*rtype) {
+			if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
+				return t
+			}
 		}
 	}
-	funcLookupCache.RUnlock()
 
 	// Not in cache, lock and retry.
 	funcLookupCache.Lock()
 	defer funcLookupCache.Unlock()
-	if funcLookupCache.m == nil {
-		funcLookupCache.m = make(map[uint32][]*rtype)
+	if ts, ok := funcLookupCache.m.Load(hash); ok {
+		for _, t := range ts.([]*rtype) {
+			if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
+				return t
+			}
+		}
 	}
-	for _, t := range funcLookupCache.m[hash] {
-		if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
-			return t
+
+	addToCache := func(tt *rtype) Type {
+		var rts []*rtype
+		if rti, ok := funcLookupCache.m.Load(hash); ok {
+			rts = rti.([]*rtype)
 		}
+		funcLookupCache.m.Store(hash, append(rts, tt))
+		return tt
 	}
 
 	// Look in known types for the same string representation.
 	str := funcStr(ft)
 	for _, tt := range typesByString(str) {
 		if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
-			funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
-			return tt
+			return addToCache(tt)
 		}
 	}
 
 	// Populate the remaining fields of ft and store in cache.
 	ft.str = resolveReflectName(newName(str, "", "", false))
 	ft.ptrToThis = 0
-	funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
-
-	return &ft.rtype
+	return addToCache(&ft.rtype)
 }
 
 // funcStr builds a string representation of a funcType.
@@ -2211,9 +2179,6 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 	// Prepare GC data if any.
 	// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes,
 	// or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap.
-	// Normally the enforced limit on pointer maps is 16 bytes,
-	// but larger ones are acceptable, 33 bytes isn't too too big,
-	// and it's easier to generate a pointer bitmap than a GC program.
 	// Note that since the key and value are known to be <= 128 bytes,
 	// they're guaranteed to have bitmaps instead of GC programs.
 	var gcdata *byte
@@ -2240,7 +2205,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 				panic("reflect: unexpected GC program in MapOf")
 			}
 			kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata))
-			for i := uintptr(0); i < ktyp.size/ptrSize; i++ {
+			for i := uintptr(0); i < ktyp.ptrdata/ptrSize; i++ {
 				if (kmask[i/8]>>(i%8))&1 != 0 {
 					for j := uintptr(0); j < bucketSize; j++ {
 						word := base + j*ktyp.size/ptrSize + i
@@ -2256,7 +2221,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 				panic("reflect: unexpected GC program in MapOf")
 			}
 			emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata))
-			for i := uintptr(0); i < etyp.size/ptrSize; i++ {
+			for i := uintptr(0); i < etyp.ptrdata/ptrSize; i++ {
 				if (emask[i/8]>>(i%8))&1 != 0 {
 					for j := uintptr(0); j < bucketSize; j++ {
 						word := base + j*etyp.size/ptrSize + i
@@ -2301,8 +2266,8 @@ func SliceOf(t Type) Type {
 
 	// Look in cache.
 	ckey := cacheKey{Slice, typ, nil, 0}
-	if slice := cacheGet(ckey); slice != nil {
-		return slice
+	if slice, ok := lookupCache.Load(ckey); ok {
+		return slice.(Type)
 	}
 
 	// Look in known types.
@@ -2310,7 +2275,8 @@ func SliceOf(t Type) Type {
 	for _, tt := range typesByString(s) {
 		slice := (*sliceType)(unsafe.Pointer(tt))
 		if slice.elem == typ {
-			return cachePut(ckey, tt)
+			ti, _ := lookupCache.LoadOrStore(ckey, tt)
+			return ti.(Type)
 		}
 	}
 
@@ -2324,17 +2290,19 @@ func SliceOf(t Type) Type {
 	slice.elem = typ
 	slice.ptrToThis = 0
 
-	return cachePut(ckey, &slice.rtype)
+	ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
+	return ti.(Type)
 }
 
 // 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
+	sync.Mutex // Guards stores (but not loads) on m.
+
+	// m is a map[uint32][]Type keyed by the hash calculated in StructOf.
+	// Elements in m are append-only and thus safe for concurrent reading.
+	m sync.Map
 }
 
 type structTypeUncommon struct {
@@ -2378,6 +2346,31 @@ type structTypeFixed32 struct {
 	m [32]method
 }
 
+// isLetter returns true if a given 'rune' is classified as a Letter.
+func isLetter(ch rune) bool {
+	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
+}
+
+// isValidFieldName checks if a string is a valid (struct) field name or not.
+//
+// According to the language spec, a field name should be an identifier.
+//
+// identifier = letter { letter | unicode_digit } .
+// letter = unicode_letter | "_" .
+func isValidFieldName(fieldName string) bool {
+	for i, c := range fieldName {
+		if i == 0 && !isLetter(c) {
+			return false
+		}
+
+		if !(isLetter(c) || unicode.IsDigit(c)) {
+			return false
+		}
+	}
+
+	return len(fieldName) > 0
+}
+
 // StructOf returns the struct type containing fields.
 // The Offset and Index fields are ignored and computed as they would be
 // by the compiler.
@@ -2404,6 +2397,12 @@ func StructOf(fields []StructField) Type {
 	lastzero := uintptr(0)
 	repr = append(repr, "struct {"...)
 	for i, field := range fields {
+		if field.Name == "" {
+			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
+		}
+		if !isValidFieldName(field.Name) {
+			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name")
+		}
 		if field.Type == nil {
 			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
 		}
@@ -2416,13 +2415,11 @@ func StructOf(fields []StructField) Type {
 			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 {
+		name := f.name.name()
+		hash = fnv1(hash, []byte(name)...)
+		repr = append(repr, (" " + name)...)
+		if f.anon() {
 			// Embedded field
 			if f.typ.Kind() == Ptr {
 				// Embedded ** and *interface{} are illegal
@@ -2430,11 +2427,7 @@ func StructOf(fields []StructField) Type {
 				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:
@@ -2566,11 +2559,12 @@ func StructOf(fields []StructField) Type {
 		comparable = comparable && (ft.alg.equal != nil)
 		hashable = hashable && (ft.alg.hash != nil)
 
-		f.offset = align(size, uintptr(ft.align))
+		offset := align(size, uintptr(ft.align))
 		if ft.align > typalign {
 			typalign = ft.align
 		}
-		size = f.offset + ft.size
+		size = offset + ft.size
+		f.offsetAnon |= offset << 1
 
 		if ft.size == 0 {
 			lastzero = size
@@ -2590,40 +2584,32 @@ func StructOf(fields []StructField) Type {
 
 	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")
 	}
@@ -2646,30 +2632,35 @@ func StructOf(fields []StructField) Type {
 	*typ = *prototype
 	typ.fields = fs
 
-	// Look in cache
-	structLookupCache.RLock()
-	for _, st := range structLookupCache.m[hash] {
-		t := st.common()
-		if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
-			structLookupCache.RUnlock()
-			return t
+	// Look in cache.
+	if ts, ok := structLookupCache.m.Load(hash); ok {
+		for _, st := range ts.([]Type) {
+			t := st.common()
+			if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
+				return t
+			}
 		}
 	}
-	structLookupCache.RUnlock()
 
-	// not in cache, lock and retry
+	// Not in cache, lock and retry.
 	structLookupCache.Lock()
 	defer structLookupCache.Unlock()
-	if structLookupCache.m == nil {
-		structLookupCache.m = make(map[uint32][]interface {
-			common() *rtype
-		})
+	if ts, ok := structLookupCache.m.Load(hash); ok {
+		for _, st := range ts.([]Type) {
+			t := st.common()
+			if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
+				return t
+			}
+		}
 	}
-	for _, st := range structLookupCache.m[hash] {
-		t := st.common()
-		if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
-			return t
+
+	addToCache := func(t Type) Type {
+		var ts []Type
+		if ti, ok := structLookupCache.m.Load(hash); ok {
+			ts = ti.([]Type)
 		}
+		structLookupCache.m.Store(hash, append(ts, t))
+		return t
 	}
 
 	// Look in known types.
@@ -2678,8 +2669,7 @@ func StructOf(fields []StructField) Type {
 			// 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
+			return addToCache(t)
 		}
 	}
 
@@ -2762,7 +2752,7 @@ func StructOf(fields []StructField) Type {
 		typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
 			o := seed
 			for _, ft := range typ.fields {
-				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				pi := unsafe.Pointer(uintptr(p) + ft.offset())
 				o = ft.typ.alg.hash(pi, o)
 			}
 			return o
@@ -2772,8 +2762,8 @@ func StructOf(fields []StructField) Type {
 	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)
+				pi := unsafe.Pointer(uintptr(p) + ft.offset())
+				qi := unsafe.Pointer(uintptr(q) + ft.offset())
 				if !ft.typ.alg.equal(pi, qi) {
 					return false
 				}
@@ -2790,30 +2780,31 @@ func StructOf(fields []StructField) Type {
 		typ.kind &^= kindDirectIface
 	}
 
-	structLookupCache.m[hash] = append(structLookupCache.m[hash], typPin)
-	return &typ.rtype
+	return addToCache(&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")
-		}
+	if field.PkgPath != "" {
+		panic("reflect.StructOf: StructOf does not allow unexported fields")
+	}
+
+	// Best-effort check for misuse.
+	// Since PkgPath is empty, not much harm done if Unicode lowercase slips through.
+	c := field.Name[0]
+	if 'a' <= c && c <= 'z' || c == '_' {
+		panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
+	}
+
+	offsetAnon := uintptr(0)
+	if field.Anonymous {
+		offsetAnon |= 1
 	}
 
-	_ = resolveReflectType(field.Type.common())
+	resolveReflectType(field.Type.common()) // install in runtime
 	return structField{
-		name:   newName(field.Name, string(field.Tag), field.PkgPath, exported),
-		typ:    field.Type.common(),
-		offset: 0,
+		name:       newName(field.Name, string(field.Tag), "", true),
+		typ:        field.Type.common(),
+		offsetAnon: offsetAnon,
 	}
 }
 
@@ -2836,7 +2827,7 @@ func typeptrdata(t *rtype) uintptr {
 			}
 		}
 		f := st.fields[field]
-		return f.offset + f.typ.ptrdata
+		return f.offset() + f.typ.ptrdata
 
 	default:
 		panic("reflect.typeptrdata: unexpected type, " + t.String())
@@ -2853,15 +2844,11 @@ const maxPtrmaskBytes = 2048
 // ArrayOf panics.
 func ArrayOf(count int, elem Type) Type {
 	typ := elem.(*rtype)
-	// call SliceOf here as it calls cacheGet/cachePut.
-	// ArrayOf also calls cacheGet/cachePut and thus may modify the state of
-	// the lookupCache mutex.
-	slice := SliceOf(elem)
 
 	// Look in cache.
 	ckey := cacheKey{Array, typ, nil, uintptr(count)}
-	if array := cacheGet(ckey); array != nil {
-		return array
+	if array, ok := lookupCache.Load(ckey); ok {
+		return array.(Type)
 	}
 
 	// Look in known types.
@@ -2869,7 +2856,8 @@ func ArrayOf(count int, elem Type) Type {
 	for _, tt := range typesByString(s) {
 		array := (*arrayType)(unsafe.Pointer(tt))
 		if array.elem == typ {
-			return cachePut(ckey, tt)
+			ti, _ := lookupCache.LoadOrStore(ckey, tt)
+			return ti.(Type)
 		}
 	}
 
@@ -2877,6 +2865,7 @@ func ArrayOf(count int, elem Type) Type {
 	var iarray interface{} = [1]unsafe.Pointer{}
 	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
 	array := *prototype
+	array.tflag = 0
 	array.str = resolveReflectName(newName(s, "", "", false))
 	array.hash = fnv1(typ.hash, '[')
 	for n := uint32(count); n > 0; n >>= 8 {
@@ -2885,9 +2874,11 @@ func ArrayOf(count int, elem Type) Type {
 	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")
+	if typ.size > 0 {
+		max := ^uintptr(0) / typ.size
+		if uintptr(count) > max {
+			panic("reflect.ArrayOf: array size would exceed virtual address space")
+		}
 	}
 	array.size = typ.size * uintptr(count)
 	if count > 0 && typ.ptrdata != 0 {
@@ -2896,7 +2887,7 @@ func ArrayOf(count int, elem Type) Type {
 	array.align = typ.align
 	array.fieldAlign = typ.fieldAlign
 	array.len = uintptr(count)
-	array.slice = slice.(*rtype)
+	array.slice = SliceOf(elem).(*rtype)
 
 	array.kind &^= kindNoPointers
 	switch {
@@ -3015,7 +3006,8 @@ func ArrayOf(count int, elem Type) Type {
 		array.kind &^= kindDirectIface
 	}
 
-	return cachePut(ckey, &array.rtype)
+	ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
+	return ti.(Type)
 }
 
 func appendVarint(x []byte, v uintptr) []byte {
@@ -3051,10 +3043,7 @@ type layoutType struct {
 	framePool *sync.Pool
 }
 
-var layoutCache struct {
-	sync.RWMutex
-	m map[layoutKey]layoutType
-}
+var layoutCache sync.Map // map[layoutKey]layoutType
 
 // funcLayout computes a struct type representing the layout of the
 // function arguments and return values for the function type t.
@@ -3070,16 +3059,9 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 		panic("reflect: funcLayout with interface receiver " + rcvr.String())
 	}
 	k := layoutKey{t, rcvr}
-	layoutCache.RLock()
-	if x := layoutCache.m[k]; x.t != nil {
-		layoutCache.RUnlock()
-		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
-	}
-	layoutCache.RUnlock()
-	layoutCache.Lock()
-	if x := layoutCache.m[k]; x.t != nil {
-		layoutCache.Unlock()
-		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
+	if lti, ok := layoutCache.Load(k); ok {
+		lt := lti.(layoutType)
+		return lt.t, lt.argSize, lt.retOffset, lt.stack, lt.framePool
 	}
 
 	tt := (*funcType)(unsafe.Pointer(t))
@@ -3140,21 +3122,18 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	x.str = resolveReflectName(newName(s, "", "", false))
 
 	// cache result for future callers
-	if layoutCache.m == nil {
-		layoutCache.m = make(map[layoutKey]layoutType)
-	}
 	framePool = &sync.Pool{New: func() interface{} {
 		return unsafe_New(x)
 	}}
-	layoutCache.m[k] = layoutType{
+	lti, _ := layoutCache.LoadOrStore(k, layoutType{
 		t:         x,
 		argSize:   argSize,
 		retOffset: retOffset,
 		stack:     ptrmap,
 		framePool: framePool,
-	}
-	layoutCache.Unlock()
-	return x, argSize, retOffset, ptrmap, framePool
+	})
+	lt := lti.(layoutType)
+	return lt.t, lt.argSize, lt.retOffset, lt.stack, lt.framePool
 }
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
@@ -3162,7 +3141,7 @@ func ifaceIndir(t *rtype) bool {
 	return t.kind&kindDirectIface == 0
 }
 
-// Layout matches runtime.BitVector (well enough).
+// Layout matches runtime.gobitvector (well enough).
 type bitVector struct {
 	n    uint32 // number of bits
 	data []byte
@@ -3210,7 +3189,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
 		tt := (*structType)(unsafe.Pointer(t))
 		for i := range tt.fields {
 			f := &tt.fields[i]
-			addTypeBits(bv, offset+f.offset, f.typ)
+			addTypeBits(bv, offset+f.offset(), f.typ)
 		}
 	}
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 387b9f3..a84af8c 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -30,9 +30,9 @@ const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ide
 // the underlying Go value can be used concurrently for the equivalent
 // direct operations.
 //
-// Using == on two Values does not compare the underlying values
-// they represent, but rather the contents of the Value structs.
 // To compare two Values, compare the results of the Interface method.
+// Using == on two Values does not compare the underlying values
+// they represent.
 type Value struct {
 	// typ holds the type of the value represented by a Value.
 	typ *rtype
@@ -769,7 +769,7 @@ func (v Value) Field(i int) Value {
 	fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
 	// Using an unexported field forces flagRO.
 	if !field.name.isExported() {
-		if field.name.name() == "" {
+		if field.anon() {
 			fl |= flagEmbedRO
 		} else {
 			fl |= flagStickyRO
@@ -780,7 +780,7 @@ func (v Value) Field(i int) Value {
 	// In the former case, we want v.ptr + offset.
 	// In the latter case, we must have field.offset = 0,
 	// so v.ptr + field.offset is still okay.
-	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
+	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset())
 	return Value{typ, ptr, fl}
 }
 
@@ -1304,7 +1304,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
 	} else {
 		p = unsafe.Pointer(&val.ptr)
 	}
-	selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+	selected, ok := chanrecv(v.pointer(), nb, p)
 	if !selected {
 		val = Value{}
 	}
@@ -1335,7 +1335,7 @@ func (v Value) send(x Value, nb bool) (selected bool) {
 	} else {
 		p = unsafe.Pointer(&x.ptr)
 	}
-	return chansend(v.typ, v.pointer(), p, nb)
+	return chansend(v.pointer(), p, nb)
 }
 
 // Set assigns x to the value v.
@@ -2077,12 +2077,17 @@ func MakeChan(typ Type, buffer int) Value {
 	return Value{typ.common(), ch, flag(Chan)}
 }
 
-// MakeMap creates a new map of the specified type.
+// MakeMap creates a new map with the specified type.
 func MakeMap(typ Type) Value {
+	return MakeMapWithSize(typ, 0)
+}
+
+// MakeMapWithSize creates a new map with the specified type and initial capacity.
+func MakeMapWithSize(typ Type, cap int) Value {
 	if typ.Kind() != Map {
-		panic("reflect.MakeMap of non-map type")
+		panic("reflect.MakeMapWithSize of non-map type")
 	}
-	m := makemap(typ.(*rtype))
+	m := makemap(typ.(*rtype), cap)
 	return Value{typ.common(), m, flag(Map)}
 }
 
@@ -2159,7 +2164,6 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
 	case directlyAssignable(dst, v.typ):
 		// Overwrite type so that they match.
 		// Same memory layout, so no harm done.
-		v.typ = dst
 		fl := v.flag & (flagRO | flagAddr | flagIndir)
 		fl |= flag(dst.Kind())
 		return Value{dst, v.ptr, fl}
@@ -2471,13 +2475,13 @@ func chanlen(ch unsafe.Pointer) int
 // (due to the escapes() call in ValueOf).
 
 //go:noescape
-func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
 
 //go:noescape
-func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
+func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
 
 func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
-func makemap(t *rtype) (m unsafe.Pointer)
+func makemap(t *rtype, cap int) (m unsafe.Pointer)
 
 //go:noescape
 func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index beb46e7..28fe20c 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -9,6 +9,7 @@ import (
 	"regexp/syntax"
 	"strings"
 	"testing"
+	"unicode/utf8"
 )
 
 var goodRe = []string{
@@ -354,6 +355,7 @@ type MetaTest struct {
 var metaTests = []MetaTest{
 	{``, ``, ``, true},
 	{`foo`, `foo`, `foo`, true},
+	{`日本語+`, `日本語\+`, `日本語`, false},
 	{`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
 	{`foo.\$`, `foo\.\\\$`, `foo`, false},     // has escaped operators and real operators
 	{`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
@@ -822,7 +824,13 @@ func BenchmarkMatchParallelCopied(b *testing.B) {
 var sink string
 
 func BenchmarkQuoteMetaAll(b *testing.B) {
-	s := string(specialBytes)
+	specials := make([]byte, 0)
+	for i := byte(0); i < utf8.RuneSelf; i++ {
+		if special(i) {
+			specials = append(specials, i)
+		}
+	}
+	s := string(specials)
 	b.SetBytes(int64(len(s)))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 977619c..f8fe7b5 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -309,12 +309,14 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
 // onepass runs the machine over the input starting at pos.
 // It reports whether a match was found.
 // If so, m.matchcap holds the submatch information.
-func (m *machine) onepass(i input, pos int) bool {
+// ncap is the number of captures.
+func (m *machine) onepass(i input, pos, ncap int) bool {
 	startCond := m.re.cond
 	if startCond == ^syntax.EmptyOp(0) { // impossible
 		return false
 	}
 	m.matched = false
+	m.matchcap = m.matchcap[:ncap]
 	for i := range m.matchcap {
 		m.matchcap[i] = -1
 	}
@@ -428,7 +430,7 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
 		size = len(s)
 	}
 	if m.op != notOnePass {
-		if !m.onepass(i, pos) {
+		if !m.onepass(i, pos, ncap) {
 			re.put(m)
 			return nil
 		}
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 766394d..5f8e747 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -681,6 +681,35 @@ func BenchmarkMatch(b *testing.B) {
 	}
 }
 
+func BenchmarkMatch_onepass_regex(b *testing.B) {
+	isRaceBuilder := strings.HasSuffix(testenv.Builder(), "-race")
+	r := MustCompile(`(?s)\A.*\z`)
+	if r.get().op == notOnePass {
+		b.Fatalf("want onepass regex, but %q is not onepass", r)
+	}
+	for _, size := range benchSizes {
+		if isRaceBuilder && size.n > 1<<10 {
+			continue
+		}
+		t := makeText(size.n)
+		bs := make([][]byte, len(t))
+		for i, s := range t {
+			bs[i] = []byte{s}
+		}
+		b.Run(size.name, func(b *testing.B) {
+			b.SetBytes(int64(size.n))
+			b.ReportAllocs()
+			for i := 0; i < b.N; i++ {
+				for _, byts := range bs {
+					if !r.Match(byts) {
+						b.Fatal("not match!")
+					}
+				}
+			}
+		})
+	}
+}
+
 var benchData = []struct{ name, re string }{
 	{"Easy0", "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
 	{"Easy0i", "(?i)ABCDEFGHIJklmnopqrstuvwxyz$"},
diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go
index 1b0564c..3ceb461 100644
--- a/src/regexp/onepass.go
+++ b/src/regexp/onepass.go
@@ -222,9 +222,10 @@ func onePassCopy(prog *syntax.Prog) *onePassProg {
 	p := &onePassProg{
 		Start:  prog.Start,
 		NumCap: prog.NumCap,
+		Inst:   make([]onePassInst, len(prog.Inst)),
 	}
-	for _, inst := range prog.Inst {
-		p.Inst = append(p.Inst, onePassInst{Inst: inst})
+	for i, inst := range prog.Inst {
+		p.Inst[i] = onePassInst{Inst: inst}
 	}
 
 	// rewrites one or more common Prog constructs that enable some otherwise
@@ -304,13 +305,13 @@ func makeOnePass(p *onePassProg) *onePassProg {
 	var (
 		instQueue    = newQueue(len(p.Inst))
 		visitQueue   = newQueue(len(p.Inst))
-		check        func(uint32, map[uint32]bool) bool
+		check        func(uint32, []bool) bool
 		onePassRunes = make([][]rune, len(p.Inst))
 	)
 
 	// check that paths from Alt instructions are unambiguous, and rebuild the new
 	// program as a onepass program
-	check = func(pc uint32, m map[uint32]bool) (ok bool) {
+	check = func(pc uint32, m []bool) (ok bool) {
 		ok = true
 		inst := &p.Inst[pc]
 		if visitQueue.contains(pc) {
@@ -349,21 +350,20 @@ func makeOnePass(p *onePassProg) *onePassProg {
 			m[pc] = m[inst.Out]
 			// pass matching runes back through these no-ops.
 			onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
-			inst.Next = []uint32{}
-			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
-				inst.Next = append(inst.Next, inst.Out)
+			inst.Next = make([]uint32, len(onePassRunes[pc])/2+1)
+			for i := range inst.Next {
+				inst.Next[i] = inst.Out
 			}
 		case syntax.InstEmptyWidth:
 			ok = check(inst.Out, m)
 			m[pc] = m[inst.Out]
 			onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
-			inst.Next = []uint32{}
-			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
-				inst.Next = append(inst.Next, inst.Out)
+			inst.Next = make([]uint32, len(onePassRunes[pc])/2+1)
+			for i := range inst.Next {
+				inst.Next[i] = inst.Out
 			}
 		case syntax.InstMatch, syntax.InstFail:
 			m[pc] = inst.Op == syntax.InstMatch
-			break
 		case syntax.InstRune:
 			m[pc] = false
 			if len(inst.Next) > 0 {
@@ -387,9 +387,9 @@ func makeOnePass(p *onePassProg) *onePassProg {
 				runes = append(runes, inst.Rune...)
 			}
 			onePassRunes[pc] = runes
-			inst.Next = []uint32{}
-			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
-				inst.Next = append(inst.Next, inst.Out)
+			inst.Next = make([]uint32, len(onePassRunes[pc])/2+1)
+			for i := range inst.Next {
+				inst.Next[i] = inst.Out
 			}
 			inst.Op = syntax.InstRune
 		case syntax.InstRune1:
@@ -411,9 +411,9 @@ func makeOnePass(p *onePassProg) *onePassProg {
 				runes = append(runes, inst.Rune[0], inst.Rune[0])
 			}
 			onePassRunes[pc] = runes
-			inst.Next = []uint32{}
-			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
-				inst.Next = append(inst.Next, inst.Out)
+			inst.Next = make([]uint32, len(onePassRunes[pc])/2+1)
+			for i := range inst.Next {
+				inst.Next[i] = inst.Out
 			}
 			inst.Op = syntax.InstRune
 		case syntax.InstRuneAny:
@@ -431,9 +431,9 @@ func makeOnePass(p *onePassProg) *onePassProg {
 			}
 			instQueue.insert(inst.Out)
 			onePassRunes[pc] = append([]rune{}, anyRuneNotNL...)
-			inst.Next = []uint32{}
-			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
-				inst.Next = append(inst.Next, inst.Out)
+			inst.Next = make([]uint32, len(onePassRunes[pc])/2+1)
+			for i := range inst.Next {
+				inst.Next[i] = inst.Out
 			}
 		}
 		return
@@ -441,7 +441,7 @@ func makeOnePass(p *onePassProg) *onePassProg {
 
 	instQueue.clear()
 	instQueue.insert(uint32(p.Start))
-	m := make(map[uint32]bool, len(p.Inst))
+	m := make([]bool, len(p.Inst))
 	for !instQueue.empty() {
 		visitQueue.clear()
 		pc := instQueue.next()
diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go
index f4e336c..b1caa44 100644
--- a/src/regexp/onepass_test.go
+++ b/src/regexp/onepass_test.go
@@ -7,6 +7,7 @@ package regexp
 import (
 	"reflect"
 	"regexp/syntax"
+	"strings"
 	"testing"
 )
 
@@ -173,6 +174,7 @@ var onePassTests = []struct {
 	{`^.bc(d|e)*$`, onePass},
 	{`^(?:(?:aa)|.)$`, notOnePass},
 	{`^(?:(?:a{1,2}){1,2})$`, notOnePass},
+	{`^l` + strings.Repeat("o", 2<<8) + `ng$`, onePass},
 }
 
 func TestCompileOnePass(t *testing.T) {
@@ -223,3 +225,23 @@ func TestRunOnePass(t *testing.T) {
 		}
 	}
 }
+
+func BenchmarkCompileOnepass(b *testing.B) {
+	for _, test := range onePassTests {
+		if test.onePass == notOnePass {
+			continue
+		}
+		name := test.re
+		if len(name) > 20 {
+			name = name[:20] + "..."
+		}
+		b.Run(name, func(b *testing.B) {
+			b.ReportAllocs()
+			for i := 0; i < b.N; i++ {
+				if _, err := Compile(test.re); err != nil {
+					b.Fatal(err)
+				}
+			}
+		})
+	}
+}
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 01093d4..b1af23e 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -76,7 +76,8 @@ import (
 )
 
 // Regexp is the representation of a compiled regular expression.
-// A Regexp is safe for concurrent use by multiple goroutines.
+// A Regexp is safe for concurrent use by multiple goroutines,
+// except for configuration methods, such as Longest.
 type Regexp struct {
 	// read-only after Compile
 	regexpRO
@@ -159,6 +160,8 @@ func CompilePOSIX(expr string) (*Regexp, error) {
 // That is, when matching against text, the regexp returns a match that
 // begins as early as possible in the input (leftmost), and among those
 // it chooses a match that is as long as possible.
+// This method modifies the Regexp and may not be called concurrently
+// with any other methods.
 func (re *Regexp) Longest() {
 	re.longest = true
 }
@@ -313,11 +316,19 @@ func (i *inputString) index(re *Regexp, pos int) int {
 
 func (i *inputString) context(pos int) syntax.EmptyOp {
 	r1, r2 := endOfText, endOfText
-	if pos > 0 && pos <= len(i.str) {
-		r1, _ = utf8.DecodeLastRuneInString(i.str[:pos])
+	// 0 < pos && pos <= len(i.str)
+	if uint(pos-1) < uint(len(i.str)) {
+		r1 = rune(i.str[pos-1])
+		if r1 >= utf8.RuneSelf {
+			r1, _ = utf8.DecodeLastRuneInString(i.str[:pos])
+		}
 	}
-	if pos < len(i.str) {
-		r2, _ = utf8.DecodeRuneInString(i.str[pos:])
+	// 0 <= pos && pos < len(i.str)
+	if uint(pos) < uint(len(i.str)) {
+		r2 = rune(i.str[pos])
+		if r2 >= utf8.RuneSelf {
+			r2, _ = utf8.DecodeRuneInString(i.str[pos:])
+		}
 	}
 	return syntax.EmptyOpContext(r1, r2)
 }
@@ -352,11 +363,19 @@ func (i *inputBytes) index(re *Regexp, pos int) int {
 
 func (i *inputBytes) context(pos int) syntax.EmptyOp {
 	r1, r2 := endOfText, endOfText
-	if pos > 0 && pos <= len(i.str) {
-		r1, _ = utf8.DecodeLastRune(i.str[:pos])
+	// 0 < pos && pos <= len(i.str)
+	if uint(pos-1) < uint(len(i.str)) {
+		r1 = rune(i.str[pos-1])
+		if r1 >= utf8.RuneSelf {
+			r1, _ = utf8.DecodeLastRune(i.str[:pos])
+		}
 	}
-	if pos < len(i.str) {
-		r2, _ = utf8.DecodeRune(i.str[pos:])
+	// 0 <= pos && pos < len(i.str)
+	if uint(pos) < uint(len(i.str)) {
+		r2 = rune(i.str[pos])
+		if r2 >= utf8.RuneSelf {
+			r2, _ = utf8.DecodeRune(i.str[pos:])
+		}
 	}
 	return syntax.EmptyOpContext(r1, r2)
 }
@@ -590,10 +609,18 @@ func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
 	})
 }
 
-var specialBytes = []byte(`\.+*?()|[]{}^$`)
+// Bitmap used by func special to check whether a character needs to be escaped.
+var specialBytes [16]byte
 
+// special reports whether byte b needs to be escaped by QuoteMeta.
 func special(b byte) bool {
-	return bytes.IndexByte(specialBytes, b) >= 0
+	return b < utf8.RuneSelf && specialBytes[b%16]&(1<<(b/16)) != 0
+}
+
+func init() {
+	for _, b := range []byte(`\.+*?()|[]{}^$`) {
+		specialBytes[b%16] |= 1 << (b / 16)
+	}
 }
 
 // QuoteMeta returns a string that quotes all regular expression metacharacters
diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
index 7b8be55..8c6d43a 100644
--- a/src/regexp/syntax/parse.go
+++ b/src/regexp/syntax/parse.go
@@ -381,7 +381,7 @@ func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
 		}
 	}
 	if op == OpAlternate {
-		re.Sub = p.factor(re.Sub, re.Flags)
+		re.Sub = p.factor(re.Sub)
 		if len(re.Sub) == 1 {
 			old := re
 			re = re.Sub[0]
@@ -402,7 +402,7 @@ func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
 // which simplifies by character class introduction to
 //     A(B[CD]|EF)|BC[XY]
 //
-func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
+func (p *parser) factor(sub []*Regexp) []*Regexp {
 	if len(sub) < 2 {
 		return sub
 	}
diff --git a/src/run.bash b/src/run.bash
index 293b775..1fde5f4 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -8,9 +8,17 @@ set -e
 eval $(go env)
 export GOROOT   # the api test requires GOROOT to be set.
 
+# We disallow local import for non-local packages, if $GOROOT happens
+# to be under $GOPATH, then some tests below will fail.  $GOPATH needs
+# to be set to a non-empty string, else Go will set a default value
+# that may also conflict with $GOROOT.  The $GOPATH value doesn't need
+# to point to an actual directory, it just needs to pass the semantic
+# checks performed by Go.  Use $GOROOT to define $GOPATH so that we
+# don't blunder into a user-defined symbolic link.
+GOPATH=$GOROOT/nonexistentpath
+export GOPATH
+
 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
@@ -28,12 +36,12 @@ ulimit -c 0
 # This is a system misconfiguration and should be fixed on the
 # broken system, not "fixed" by ignoring the failure here.
 # See longer discussion on golang.org/issue/7381. 
-[ "$(ulimit -H -n)" == "unlimited" ] || ulimit -S -n $(ulimit -H -n)
-[ "$(ulimit -H -d)" == "unlimited" ] || ulimit -S -d $(ulimit -H -d)
+[ "$(ulimit -H -n)" = "unlimited" ] || ulimit -S -n $(ulimit -H -n)
+[ "$(ulimit -H -d)" = "unlimited" ] || ulimit -S -d $(ulimit -H -d)
 
 # Thread count limit on NetBSD 7.
 if ulimit -T &> /dev/null; then
-	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
+	[ "$(ulimit -H -T)" = "unlimited" ] || ulimit -S -T $(ulimit -H -T)
 fi
 
 exec go tool dist test -rebuild "$@"
diff --git a/src/runtime/HACKING.md b/src/runtime/HACKING.md
index ea7c5c1..883559c 100644
--- a/src/runtime/HACKING.md
+++ b/src/runtime/HACKING.md
@@ -238,11 +238,11 @@ go:notinheap
 ------------
 
 `go:notinheap` applies to type declarations. It indicates that a type
-must never be heap allocated. Specifically, pointers to this type must
-always fail the `runtime.inheap` check. The type may be used for
-global variables, for stack variables, or for objects in unmanaged
-memory (e.g., allocated with `sysAlloc`, `persistentalloc`, or
-`fixalloc`). Specifically:
+must never be allocated from the GC'd heap. Specifically, pointers to
+this type must always fail the `runtime.inheap` check. The type may be
+used for global variables, for stack variables, or for objects in
+unmanaged memory (e.g., allocated with `sysAlloc`, `persistentalloc`,
+`fixalloc`, or from a manually-managed span). Specifically:
 
 1. `new(T)`, `make([]T)`, `append([]T, ...)` and implicit heap
    allocation of T are disallowed. (Though implicit allocations are
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 5c378c6..8d388da 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -206,16 +206,16 @@ func strequal(p, q unsafe.Pointer) bool {
 	return *(*string)(p) == *(*string)(q)
 }
 func interequal(p, q unsafe.Pointer) bool {
-	return ifaceeq(*(*iface)(p), *(*iface)(q))
+	x := *(*iface)(p)
+	y := *(*iface)(q)
+	return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data)
 }
 func nilinterequal(p, q unsafe.Pointer) bool {
-	return efaceeq(*(*eface)(p), *(*eface)(q))
+	x := *(*eface)(p)
+	y := *(*eface)(q)
+	return x._type == y._type && efaceeq(x._type, x.data, y.data)
 }
-func efaceeq(x, y eface) bool {
-	t := x._type
-	if t != y._type {
-		return false
-	}
+func efaceeq(t *_type, x, y unsafe.Pointer) bool {
 	if t == nil {
 		return true
 	}
@@ -224,27 +224,23 @@ func efaceeq(x, y eface) bool {
 		panic(errorString("comparing uncomparable type " + t.string()))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
+		return eq(noescape(unsafe.Pointer(&x)), noescape(unsafe.Pointer(&y)))
 	}
-	return eq(x.data, y.data)
+	return eq(x, y)
 }
-func ifaceeq(x, y iface) bool {
-	xtab := x.tab
-	if xtab != y.tab {
-		return false
-	}
-	if xtab == nil {
+func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
+	if tab == nil {
 		return true
 	}
-	t := xtab._type
+	t := tab._type
 	eq := t.alg.equal
 	if eq == nil {
 		panic(errorString("comparing uncomparable type " + t.string()))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
+		return eq(noescape(unsafe.Pointer(&x)), noescape(unsafe.Pointer(&y)))
 	}
-	return eq(x.data, y.data)
+	return eq(x, y)
 }
 
 // Testing adapters for hash quality tests (see hash_test.go)
@@ -287,9 +283,9 @@ func alginit() {
 	// Install aes hash algorithm if we have the instructions we need
 	if (GOARCH == "386" || GOARCH == "amd64") &&
 		GOOS != "nacl" &&
-		cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
-		cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
-		cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
+		support_aes && // AESENC
+		support_ssse3 && // PSHUFB
+		support_sse41 { // PINSR{D,Q}
 		useAeshash = true
 		algarray[alg_MEM32].hash = aeshash32
 		algarray[alg_MEM64].hash = aeshash64
diff --git a/src/runtime/asm.s b/src/runtime/asm.s
index 3ddea7c..2646172 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -14,3 +14,24 @@ GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
 
 GLOBL runtime·mheap_(SB), NOPTR, $0
 GLOBL runtime·memstats(SB), NOPTR, $0
+
+// NaCl requires that these skips be verifiable machine code.
+#ifdef GOARCH_amd64
+#define SKIP4 BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90
+#endif
+#ifdef GOARCH_386
+#define SKIP4 BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90
+#endif
+#ifdef GOARCH_amd64p32
+#define SKIP4 BYTE $0x90; BYTE $0x90; BYTE $0x90; BYTE $0x90
+#endif
+#ifndef SKIP4
+#define SKIP4 WORD $0
+#endif
+
+#define SKIP16 SKIP4; SKIP4; SKIP4; SKIP4
+#define SKIP64 SKIP16; SKIP16; SKIP16; SKIP16
+
+// This function must be sizeofSkipFunction bytes.
+TEXT runtime·skipPleaseUseCallersFrames(SB),NOSPLIT,$0-0
+	SKIP64; SKIP64; SKIP64; SKIP64
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 3d0b74c..5bbf286 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -67,30 +67,86 @@ has_cpuid:
 	JNE	notintel
 	CMPL	CX, $0x6C65746E  // "ntel"
 	JNE	notintel
+	MOVB	$1, runtime·isIntel(SB)
 	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
-	MOVL	AX, runtime·cpuid_ecx(SB)
-	MOVL	DX, runtime·cpuid_edx(SB)
+	MOVL	CX, DI // Move to global variable clobbers CX when generating PIC
+	MOVL	AX, runtime·processorVersionInfo(SB)
 
 	// Check for MMX support
-	TESTL	$(1<<23), DX	// MMX
-	JZ 	bad_proc
+	TESTL	$(1<<23), DX // MMX
+	JZ	bad_proc
 
+	TESTL	$(1<<26), DX // SSE2
+	SETNE	runtime·support_sse2(SB)
+
+	TESTL	$(1<<9), DI // SSSE3
+	SETNE	runtime·support_ssse3(SB)
+
+	TESTL	$(1<<19), DI // SSE4.1
+	SETNE	runtime·support_sse41(SB)
+
+	TESTL	$(1<<20), DI // SSE4.2
+	SETNE	runtime·support_sse42(SB)
+
+	TESTL	$(1<<23), DI // POPCNT
+	SETNE	runtime·support_popcnt(SB)
+
+	TESTL	$(1<<25), DI // AES
+	SETNE	runtime·support_aes(SB)
+
+	TESTL	$(1<<27), DI // OSXSAVE
+	SETNE	runtime·support_osxsave(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx will be set back to false later.
+	TESTL	$(1<<28), DI // AVX
+	SETNE	runtime·support_avx(SB)
+
+eax7:
 	// Load EAX=7/ECX=0 cpuid flags
 	CMPL	SI, $7
-	JLT	nocpuinfo
+	JLT	osavx
 	MOVL	$7, AX
 	MOVL	$0, CX
 	CPUID
-	MOVL	BX, runtime·cpuid_ebx7(SB)
 
-nocpuinfo:	
+	TESTL	$(1<<3), BX // BMI1
+	SETNE	runtime·support_bmi1(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx2 will be set back to false later.
+	TESTL	$(1<<5), BX
+	SETNE	runtime·support_avx2(SB)
+
+	TESTL	$(1<<8), BX // BMI2
+	SETNE	runtime·support_bmi2(SB)
+
+	TESTL	$(1<<9), BX // ERMS
+	SETNE	runtime·support_erms(SB)
+
+osavx:
+	// nacl does not support XGETBV to test
+	// for XMM and YMM OS support.
+#ifndef GOOS_nacl
+	CMPB	runtime·support_osxsave(SB), $1
+	JNE	noavx
+	MOVL	$0, CX
+	// For XGETBV, OSXSAVE bit is required and sufficient
+	XGETBV
+	ANDL	$6, AX
+	CMPL	AX, $6 // Check for OS support of XMM and YMM registers.
+	JE nocpuinfo
+#endif
+noavx:
+	MOVB $0, runtime·support_avx(SB)
+	MOVB $0, runtime·support_avx2(SB)
 
+nocpuinfo:
 	// if there is an _cgo_init, call it to let it
 	// initialize and to set up GS.  if not,
 	// we set up GS ourselves.
@@ -415,22 +471,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
 	MOVL	$0, DX
 	JMP runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVL	g(CX), CX
-	MOVL	(g_stkbar+slice_array)(CX), DX
-	MOVL	g_stkbarPos(CX), BX
-	IMULL	$stkbar__size, BX	// Too big for SIB.
-	MOVL	stkbar_savedLRVal(DX)(BX*1), BX
-	// Record that this stack barrier was hit.
-	ADDL	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -812,33 +852,13 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-4(AX),AX		// get calling pc
-	CMPL	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVL	0(SP), AX
-nobar:
 	MOVL	AX, ret+4(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
-	MOVL	argp+0(FP),AX		// addr of first arg
-	MOVL	pc+4(FP), BX
-	MOVL	-4(AX), DX
-	CMPL	DX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
-	MOVL	BX, -4(AX)		// set calling pc
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVL	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
-
 // func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-8
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // no sse2, no mfence
-	JEQ	done
+	CMPB	runtime·support_sse2(SB), $1
+	JNE	done
 	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
 	JNE	mfence
 	BYTE	$0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
@@ -1345,8 +1365,8 @@ TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
 hugeloop:
 	CMPL	BX, $64
 	JB	bigloop
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JE	bigloop
+	CMPB	runtime·support_sse2(SB), $1
+	JNE	bigloop
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	MOVOU	16(SI), X2
@@ -1489,8 +1509,8 @@ TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	JEQ	allsame
 	CMPL	BP, $4
 	JB	small
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JE	mediumloop
+	CMPB	runtime·support_sse2(SB), $1
+	JNE	mediumloop
 largeloop:
 	CMPL	BP, $16
 	JB	mediumloop
@@ -1595,20 +1615,6 @@ allsame:
 	MOVL	BX, (AX)
 	RET
 
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
-	get_tls(CX)
-	MOVL	g(CX), AX
-	MOVL	g_m(AX), AX
-	MOVL	m_fastrand(AX), DX
-	ADDL	DX, DX
-	MOVL	DX, BX
-	XORL	$0x88888eef, DX
-	JPL	2(PC)
-	MOVL	BX, DX
-	MOVL	DX, m_fastrand(AX)
-	MOVL	DX, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB), NOSPLIT, $0
 	MOVL	$0, AX
 	RET
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index cb428d6..6405be9 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -26,10 +26,10 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	MOVQ	SP, (g_stack+stack_hi)(DI)
 
 	// find out information about the processor we're on
-	MOVQ	$0, AX
+	MOVL	$0, AX
 	CPUID
-	MOVQ	AX, SI
-	CMPQ	AX, $0
+	MOVL	AX, SI
+	CMPL	AX, $0
 	JE	nocpuinfo
 
 	// Figure out how to serialize RDTSC.
@@ -41,60 +41,77 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	JNE	notintel
 	CMPL	CX, $0x6C65746E  // "ntel"
 	JNE	notintel
+	MOVB	$1, runtime·isIntel(SB)
 	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
 notintel:
 
 	// Load EAX=1 cpuid flags
-	MOVQ	$1, AX
+	MOVL	$1, AX
 	CPUID
-	MOVL	CX, runtime·cpuid_ecx(SB)
-	MOVL	DX, runtime·cpuid_edx(SB)
+	MOVL	AX, runtime·processorVersionInfo(SB)
+
+	TESTL	$(1<<26), DX // SSE2
+	SETNE	runtime·support_sse2(SB)
+
+	TESTL	$(1<<9), CX // SSSE3
+	SETNE	runtime·support_ssse3(SB)
+
+	TESTL	$(1<<19), CX // SSE4.1
+	SETNE	runtime·support_sse41(SB)
+
+	TESTL	$(1<<20), CX // SSE4.2
+	SETNE	runtime·support_sse42(SB)
+
+	TESTL	$(1<<23), CX // POPCNT
+	SETNE	runtime·support_popcnt(SB)
+
+	TESTL	$(1<<25), CX // AES
+	SETNE	runtime·support_aes(SB)
+
+	TESTL	$(1<<27), CX // OSXSAVE
+	SETNE	runtime·support_osxsave(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx will be set back to false later.
+	TESTL	$(1<<28), CX // AVX
+	SETNE	runtime·support_avx(SB)
 
+eax7:
 	// Load EAX=7/ECX=0 cpuid flags
-	CMPQ	SI, $7
-	JLT	no7
+	CMPL	SI, $7
+	JLT	osavx
 	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
-	MOVL    $0, CX
+
+	TESTL	$(1<<3), BX // BMI1
+	SETNE	runtime·support_bmi1(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx2 will be set back to false later.
+	TESTL	$(1<<5), BX
+	SETNE	runtime·support_avx2(SB)
+
+	TESTL	$(1<<8), BX // BMI2
+	SETNE	runtime·support_bmi2(SB)
+
+	TESTL	$(1<<9), BX // ERMS
+	SETNE	runtime·support_erms(SB)
+
+osavx:
+	CMPB	runtime·support_osxsave(SB), $1
+	JNE	noavx
+	MOVL	$0, CX
 	// For XGETBV, OSXSAVE bit is required and sufficient
 	XGETBV
-	ANDL    $6, AX
-	CMPL    AX, $6 // Check for OS support of YMM registers
-	JNE     noavx
-	MOVB    $1, runtime·support_avx(SB)
-	TESTL   $(1<<5), runtime·cpuid_ebx7(SB) // check for AVX2 bit
-	JEQ     noavx2
-	MOVB    $1, runtime·support_avx2(SB)
-	JMP     testbmi1
+	ANDL	$6, AX
+	CMPL	AX, $6 // Check for OS support of XMM and YMM registers.
+	JE nocpuinfo
 noavx:
-	MOVB    $0, runtime·support_avx(SB)
-noavx2:
-	MOVB    $0, runtime·support_avx2(SB)
-testbmi1:
-	// Detect BMI1 and BMI2 extensions as per
-	// 5.1.16.1 Detection of VEX-encoded GPR Instructions,
-	//   LZCNT and TZCNT, PREFETCHW chapter of [1]
-	MOVB    $0, runtime·support_bmi1(SB)
-	TESTL   $(1<<3), runtime·cpuid_ebx7(SB) // check for BMI1 bit
-	JEQ     testbmi2
-	MOVB    $1, runtime·support_bmi1(SB)
-testbmi2:
-	MOVB    $0, runtime·support_bmi2(SB)
-	TESTL   $(1<<8), runtime·cpuid_ebx7(SB) // check for BMI2 bit
-	JEQ     nocpuinfo
-	MOVB    $1, runtime·support_bmi2(SB)
-nocpuinfo:	
-	
+	MOVB $0, runtime·support_avx(SB)
+	MOVB $0, runtime·support_avx2(SB)
+
+nocpuinfo:
 	// if there is an _cgo_init, call it.
 	MOVQ	_cgo_init(SB), AX
 	TESTQ	AX, AX
@@ -405,28 +422,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVQ	g(CX), CX
-	MOVQ	(g_stkbar+slice_array)(CX), DX
-	MOVQ	g_stkbarPos(CX), BX
-	IMULQ	$stkbar__size, BX	// Too big for SIB.
-	MOVQ	stkbar_savedLRPtr(DX)(BX*1), R8
-	MOVQ	stkbar_savedLRVal(DX)(BX*1), BX
-	// Assert that we're popping the right saved LR.
-	ADDQ	$8, R8
-	CMPQ	R8, SP
-	JEQ	2(PC)
-	MOVL	$0, 0
-	// Record that this stack barrier was hit.
-	ADDQ	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -841,29 +836,9 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
 	MOVQ	argp+0(FP),AX		// addr of first arg
 	MOVQ	-8(AX),AX		// get calling pc
-	CMPQ	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVQ	0(SP), AX
-nobar:
 	MOVQ	AX, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
-	MOVQ	argp+0(FP),AX		// addr of first arg
-	MOVQ	pc+8(FP), BX
-	MOVQ	-8(AX), CX
-	CMPQ	CX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
-	MOVQ	BX, -8(AX)		// set calling pc
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVQ	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
-
 // func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
@@ -1728,17 +1703,6 @@ big_loop_avx2_exit:
 	VZEROUPPER
 	JMP loop
 
-
-TEXT strings·supportAVX2(SB),NOSPLIT,$0-1
-	MOVBLZX runtime·support_avx2(SB), AX
-	MOVB AX, ret+0(FP)
-	RET
-
-TEXT bytes·supportAVX2(SB),NOSPLIT,$0-1
-	MOVBLZX runtime·support_avx2(SB), AX
-	MOVB AX, ret+0(FP)
-	RET
-
 TEXT strings·indexShortStr(SB),NOSPLIT,$0-40
 	MOVQ s+0(FP), DI
 	// We want len in DX and AX, because PCMPESTRI implicitly consumes them
@@ -1967,9 +1931,8 @@ success_avx2:
 	VZEROUPPER
 	JMP success
 sse42:
-	MOVL runtime·cpuid_ecx(SB), CX
-	ANDL $0x100000, CX
-	JZ no_sse42
+	CMPB runtime·support_sse42(SB), $1
+	JNE no_sse42
 	CMPQ AX, $12
 	// PCMPESTRI is slower than normal compare,
 	// so using it makes sense only if we advance 4+ bytes per compare
@@ -2163,17 +2126,194 @@ eqret:
 	MOVB	$0, ret+48(FP)
 	RET
 
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
-	get_tls(CX)
-	MOVQ	g(CX), AX
-	MOVQ	g_m(AX), AX
-	MOVL	m_fastrand(AX), DX
-	ADDL	DX, DX
-	MOVL	DX, BX
-	XORL	$0x88888eef, DX
-	CMOVLMI	BX, DX
-	MOVL	DX, m_fastrand(AX)
-	MOVL	DX, ret+0(FP)
+
+TEXT bytes·countByte(SB),NOSPLIT,$0-40
+	MOVQ s+0(FP), SI
+	MOVQ s_len+8(FP), BX
+	MOVB c+24(FP), AL
+	LEAQ ret+32(FP), R8
+	JMP  runtime·countByte(SB)
+
+TEXT strings·countByte(SB),NOSPLIT,$0-32
+	MOVQ s+0(FP), SI
+	MOVQ s_len+8(FP), BX
+	MOVB c+16(FP), AL
+	LEAQ ret+24(FP), R8
+	JMP  runtime·countByte(SB)
+
+// input:
+//   SI: data
+//   BX: data len
+//   AL: byte sought
+//   R8: address to put result
+// This requires the POPCNT instruction
+TEXT runtime·countByte(SB),NOSPLIT,$0
+	// 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
+
+	CMPQ BX, $16
+	JLT small
+
+	MOVQ $0, R12 // Accumulator
+
+	MOVQ SI, DI
+
+	CMPQ BX, $32
+	JA avx2
+sse:
+	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
+	// Count number of matching bytes
+	POPCNTL DX, DX
+	// Accumulate into R12
+	ADDQ DX, R12
+	// Advance to next block.
+	ADDQ	$16, DI
+sseloopentry:
+	CMPQ	DI, AX
+	JBE	sseloop
+
+	// Get the number of bytes to consider in the last 16 bytes
+	ANDQ $15, BX
+	JZ end
+
+	// Create mask to ignore overlap between previous 16 byte block
+	// and the next.
+	MOVQ $16,CX
+	SUBQ BX, CX
+	MOVQ $0xFFFF, R10
+	SARQ CL, R10
+	SALQ CL, R10
+
+	// Process the last 16-byte chunk. This chunk may overlap with the
+	// chunks we've already searched so we need to mask part of it.
+	MOVOU	(AX), X1
+	PCMPEQB	X0, X1
+	PMOVMSKB X1, DX
+	// Apply mask
+	ANDQ R10, DX
+	POPCNTL DX, DX
+	ADDQ DX, R12
+end:
+	MOVQ R12, (R8)
+	RET
+
+// handle for lengths < 16
+small:
+	TESTQ	BX, BX
+	JEQ	endzero
+
+	// Check if we'll load across a page boundary.
+	LEAQ	16(SI), AX
+	TESTW	$0xff0, AX
+	JEQ	endofpage
+
+	// We must ignore high bytes as they aren't part of our slice.
+	// Create mask.
+	MOVB BX, CX
+	MOVQ $1, R10
+	SALQ CL, R10
+	SUBQ $1, R10
+
+	// Load data
+	MOVOU	(SI), X1
+	// Compare target byte with each byte in data.
+	PCMPEQB	X0, X1
+	// Move result bits to integer register.
+	PMOVMSKB X1, DX
+	// Apply mask
+	ANDQ R10, DX
+	POPCNTL DX, DX
+	// Directly return DX, we don't need to accumulate
+	// since we have <16 bytes.
+	MOVQ	DX, (R8)
+	RET
+endzero:
+	MOVQ $0, (R8)
+	RET
+
+endofpage:
+	// We must ignore low bytes as they aren't part of our slice.
+	MOVQ $16,CX
+	SUBQ BX, CX
+	MOVQ $0xFFFF, R10
+	SARQ CL, R10
+	SALQ CL, R10
+
+	// Load data into the high end of X1.
+	MOVOU	-16(SI)(BX*1), X1
+	// Compare target byte with each byte in data.
+	PCMPEQB	X0, X1
+	// Move result bits to integer register.
+	PMOVMSKB X1, DX
+	// Apply mask
+	ANDQ R10, DX
+	// Directly return DX, we don't need to accumulate
+	// since we have <16 bytes.
+	POPCNTL DX, DX
+	MOVQ	DX, (R8)
+	RET
+
+avx2:
+	CMPB   runtime·support_avx2(SB), $1
+	JNE sse
+	MOVD AX, X0
+	LEAQ -32(SI)(BX*1), R11
+	VPBROADCASTB  X0, Y1
+avx2_loop:
+	VMOVDQU (DI), Y2
+	VPCMPEQB Y1, Y2, Y3
+	VPMOVMSKB Y3, DX
+	POPCNTL DX, DX
+	ADDQ DX, R12
+	ADDQ $32, DI
+	CMPQ DI, R11
+	JLE avx2_loop
+
+	// If last block is already processed,
+	// skip to the end.
+	CMPQ DI, R11
+	JEQ endavx
+
+	// Load address of the last 32 bytes.
+	// There is an overlap with the previous block.
+	MOVQ R11, DI
+	VMOVDQU (DI), Y2
+	VPCMPEQB Y1, Y2, Y3
+	VPMOVMSKB Y3, DX
+	// Exit AVX mode.
+	VZEROUPPER
+
+	// Create mask to ignore overlap between previous 32 byte block
+	// and the next.
+	ANDQ $31, BX
+	MOVQ $32,CX
+	SUBQ BX, CX
+	MOVQ $0xFFFFFFFF, R10
+	SARQ CL, R10
+	SALQ CL, R10
+	// Apply mask
+	ANDQ R10, DX
+	POPCNTL DX, DX
+	ADDQ DX, R12
+	MOVQ R12, (R8)
+	RET
+endavx:
+	// Exit AVX mode.
+	VZEROUPPER
+	MOVQ R12, (R8)
 	RET
 
 TEXT runtime·return0(SB), NOSPLIT, $0
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index c3c1c15..6367b3f 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -28,16 +28,92 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	MOVL	SP, (g_stack+stack_hi)(DI)
 
 	// find out information about the processor we're on
-	MOVQ	$0, AX
+	MOVL	$0, AX
 	CPUID
-	CMPQ	AX, $0
+	CMPL	AX, $0
 	JE	nocpuinfo
-	MOVQ	$1, AX
+
+	CMPL	BX, $0x756E6547  // "Genu"
+	JNE	notintel
+	CMPL	DX, $0x49656E69  // "ineI"
+	JNE	notintel
+	CMPL	CX, $0x6C65746E  // "ntel"
+	JNE	notintel
+	MOVB	$1, runtime·isIntel(SB)
+notintel:
+
+	// Load EAX=1 cpuid flags
+	MOVL	$1, AX
 	CPUID
-	MOVL	CX, runtime·cpuid_ecx(SB)
-	MOVL	DX, runtime·cpuid_edx(SB)
-nocpuinfo:	
-	
+	MOVL	AX, runtime·processorVersionInfo(SB)
+
+	TESTL	$(1<<26), DX // SSE2
+	SETNE	runtime·support_sse2(SB)
+
+	TESTL	$(1<<9), CX // SSSE3
+	SETNE	runtime·support_ssse3(SB)
+
+	TESTL	$(1<<19), CX // SSE4.1
+	SETNE	runtime·support_sse41(SB)
+
+	TESTL	$(1<<20), CX // SSE4.2
+	SETNE	runtime·support_sse42(SB)
+
+	TESTL	$(1<<23), CX // POPCNT
+	SETNE	runtime·support_popcnt(SB)
+
+	TESTL	$(1<<25), CX // AES
+	SETNE	runtime·support_aes(SB)
+
+	TESTL	$(1<<27), CX // OSXSAVE
+	SETNE	runtime·support_osxsave(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx will be set back to false later.
+	TESTL	$(1<<28), CX // AVX
+	SETNE	runtime·support_avx(SB)
+
+eax7:
+	// Load EAX=7/ECX=0 cpuid flags
+	CMPL	SI, $7
+	JLT	osavx
+	MOVL	$7, AX
+	MOVL	$0, CX
+	CPUID
+
+	TESTL	$(1<<3), BX // BMI1
+	SETNE	runtime·support_bmi1(SB)
+
+	// If OS support for XMM and YMM is not present
+	// support_avx2 will be set back to false later.
+	TESTL	$(1<<5), BX
+	SETNE	runtime·support_avx2(SB)
+
+	TESTL	$(1<<8), BX // BMI2
+	SETNE	runtime·support_bmi2(SB)
+
+	TESTL	$(1<<9), BX // ERMS
+	SETNE	runtime·support_erms(SB)
+
+osavx:
+	// nacl does not support XGETBV to test
+	// for XMM and YMM OS support.
+#ifndef GOOS_nacl
+	CMPB	runtime·support_osxsave(SB), $1
+	JNE	noavx
+	MOVL	$0, CX
+	// For XGETBV, OSXSAVE bit is required and sufficient
+	XGETBV
+	ANDL	$6, AX
+	CMPL	AX, $6 // Check for OS support of XMM and YMM registers.
+	JE nocpuinfo
+#endif
+noavx:
+	MOVB $0, runtime·support_avx(SB)
+	MOVB $0, runtime·support_avx2(SB)
+
+nocpuinfo:
+
 needtls:
 	LEAL	runtime·m0+m_tls(SB), DI
 	CALL	runtime·settls(SB)
@@ -309,23 +385,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVL	g(CX), CX
-	MOVL	(g_stkbar+slice_array)(CX), DX
-	MOVL	g_stkbarPos(CX), BX
-	IMULL	$stkbar__size, BX	// Too big for SIB.
-	ADDL	DX, BX
-	MOVL	stkbar_savedLRVal(BX), BX
-	// Record that this stack barrier was hit.
-	ADDL	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -521,29 +580,9 @@ TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-8
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-12
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-8(AX),AX		// get calling pc
-	CMPL	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVL	0(SP), AX
-nobar:
 	MOVL	AX, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-8
-	MOVL	argp+0(FP),AX		// addr of first arg
-	MOVL	pc+4(FP), BX		// pc to set
-	MOVL	-8(AX), CX
-	CMPL	CX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
-	MOVQ	BX, -8(AX)		// set calling pc
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVL	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
-
 // int64 runtime·cputicks(void)
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	RDTSC
@@ -991,19 +1030,6 @@ eqret:
 	MOVB	AX, ret+24(FP)
 	RET
 
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
-	get_tls(CX)
-	MOVL	g(CX), AX
-	MOVL	g_m(AX), AX
-	MOVL	m_fastrand(AX), DX
-	ADDL	DX, DX
-	MOVL	DX, BX
-	XORL	$0x88888eef, DX
-	CMOVLMI	BX, DX
-	MOVL	DX, m_fastrand(AX)
-	MOVL	DX, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB), NOSPLIT, $0
 	MOVL	$0, AX
 	RET
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 79c28a8..87f9378 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -340,23 +340,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
 	MOVW	$0, R7
 	B runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R0 may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVW	(g_stkbar+slice_array)(g), R4
-	MOVW	g_stkbarPos(g), R5
-	MOVW	$stkbar__size, R6
-	MUL	R5, R6
-	ADD	R4, R6
-	MOVW	stkbar_savedLRVal(R6), R6
-	// Record that this stack barrier was hit.
-	ADD	$1, R5
-	MOVW	R5, g_stkbarPos(g)
-	// Jump to the original return PC.
-	B	(R6)
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -696,30 +679,9 @@ TEXT setg<>(SB),NOSPLIT,$-4-0
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
 	MOVW	8(R13), R0		// LR saved by caller
-	MOVW	runtime·stackBarrierPC(SB), R1
-	CMP	R0, R1
-	BNE	nobar
-	// Get original return PC.
-	BL	runtime·nextBarrierPC(SB)
-	MOVW	4(R13), R0
-nobar:
 	MOVW	R0, ret+4(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
-	MOVW	pc+4(FP), R0
-	MOVW	8(R13), R1
-	MOVW	runtime·stackBarrierPC(SB), R2
-	CMP	R1, R2
-	BEQ	setbar
-	MOVW	R0, 8(R13)		// set LR in caller
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVW	R0, 4(R13)
-	BL	runtime·setNextBarrierPC(SB)
-	RET
-
 TEXT runtime·emptyfunc(SB),0,$0-0
 	RET
 
@@ -971,15 +933,6 @@ _sib_notfound:
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·fastrand(SB),NOSPLIT,$-4-4
-	MOVW	g_m(g), R1
-	MOVW	m_fastrand(R1), R0
-	ADD.S	R0, R0
-	EOR.MI	$0x88888eef, R0
-	MOVW	R0, m_fastrand(R1)
-	MOVW	R0, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB),NOSPLIT,$0
 	MOVW	$0, R0
 	RET
@@ -988,6 +941,7 @@ TEXT runtime·procyield(SB),NOSPLIT,$-4
 	MOVW	cycles+0(FP), R1
 	MOVW	$0, R0
 yieldloop:
+	WORD	$0xe320f001	// YIELD (NOP pre-ARMv6K)
 	CMP	R0, R1
 	B.NE	2(PC)
 	RET
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index 0e286d4..30ecec7 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -315,23 +315,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
 	MOVW	$0, R26
 	B runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R0 may be live (see return0). Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVD	(g_stkbar+slice_array)(g), R4
-	MOVD	g_stkbarPos(g), R5
-	MOVD	$stkbar__size, R6
-	MUL	R5, R6
-	ADD	R4, R6
-	MOVD	stkbar_savedLRVal(R6), R6
-	// Record that this stack barrier was hit.
-	ADD	$1, R5
-	MOVD	R5, g_stkbarPos(g)
-	// Jump to the original return PC.
-	B	(R6)
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -723,30 +706,9 @@ TEXT setg_gcc<>(SB),NOSPLIT,$8
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
 	MOVD	16(RSP), R0		// LR saved by caller
-	MOVD	runtime·stackBarrierPC(SB), R1
-	CMP	R0, R1
-	BNE	nobar
-	// Get original return PC.
-	BL	runtime·nextBarrierPC(SB)
-	MOVD	8(RSP), R0
-nobar:
 	MOVD	R0, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
-	MOVD	pc+8(FP), R0
-	MOVD	16(RSP), R1
-	MOVD	runtime·stackBarrierPC(SB), R2
-	CMP	R1, R2
-	BEQ	setbar
-	MOVD	R0, 16(RSP)		// set LR in caller
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVD	R0, 8(RSP)
-	BL	runtime·setNextBarrierPC(SB)
-	RET
-
 TEXT runtime·abort(SB),NOSPLIT,$-8-0
 	B	(ZR)
 	UNDEF
@@ -959,18 +921,6 @@ equal:
 	MOVB	R0, ret+48(FP)
 	RET
 
-TEXT runtime·fastrand(SB),NOSPLIT,$-8-4
-	MOVD	g_m(g), R1
-	MOVWU	m_fastrand(R1), R0
-	ADD	R0, R0
-	CMPW	$0, R0
-	BGE	notneg
-	EOR	$0x88888eef, R0
-notneg:
-	MOVW	R0, m_fastrand(R1)
-	MOVW	R0, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB), NOSPLIT, $0
 	MOVW	$0, R0
 	RET
diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s
index c2d991d..57d4578 100644
--- a/src/runtime/asm_mips64x.s
+++ b/src/runtime/asm_mips64x.s
@@ -286,24 +286,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-8-0
 	MOVV	R0, REGCTXT
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R1 may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVV	(g_stkbar+slice_array)(g), R2
-	MOVV	g_stkbarPos(g), R3
-	MOVV	$stkbar__size, R4
-	MULVU	R3, R4
-	MOVV	LO, R4
-	ADDV	R2, R4
-	MOVV	stkbar_savedLRVal(R4), R4
-	// Record that this stack barrier was hit.
-	ADDV	$1, R3
-	MOVV	R3, g_stkbarPos(g)
-	// Jump to the original return PC.
-	JMP	(R4)
-
 // 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
@@ -636,28 +618,9 @@ TEXT setg_gcc<>(SB),NOSPLIT,$0-0
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
 	MOVV	16(R29), R1		// LR saved by caller
-	MOVV	runtime·stackBarrierPC(SB), R2
-	BNE	R1, R2, nobar
-	// Get original return PC.
-	JAL	runtime·nextBarrierPC(SB)
-	MOVV	8(R29), R1
-nobar:
 	MOVV	R1, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
-	MOVV	pc+8(FP), R1
-	MOVV	16(R29), R2
-	MOVV	runtime·stackBarrierPC(SB), R3
-	BEQ	R2, R3, setbar
-	MOVV	R1, 16(R29)		// set LR in caller
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVV	R1, 8(R29)
-	JAL	runtime·setNextBarrierPC(SB)
-	RET
-
 TEXT runtime·abort(SB),NOSPLIT,$-8-0
 	MOVW	(R0), R0
 	UNDEF
@@ -831,16 +794,6 @@ notfound:
 	MOVV	R1, ret+24(FP)
 	RET
 
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
-	MOVV	g_m(g), R2
-	MOVWU	m_fastrand(R2), R1
-	ADDU	R1, R1
-	BGEZ	R1, 2(PC)
-	XOR	$0x88888eef, R1
-	MOVW	R1, m_fastrand(R2)
-	MOVW	R1, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB), NOSPLIT, $0
 	MOVW	$0, R1
 	RET
diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s
index 73da768..536c315 100644
--- a/src/runtime/asm_mipsx.s
+++ b/src/runtime/asm_mipsx.s
@@ -287,22 +287,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
 	MOVW	R0, REGCTXT
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R1 may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVW	(g_stkbar+slice_array)(g), R2
-	MOVW	g_stkbarPos(g), R3
-	MOVW	$stkbar__size, R4
-	MULU	R3, R4
-	MOVW	LO, R4
-	ADDU	R2, R4
-	MOVW	stkbar_savedLRVal(R4), R4
-	ADDU	$1, R3
-	MOVW	R3, g_stkbarPos(g)	// Record that this stack barrier was hit.
-	JMP	(R4)	// Jump to the original return PC.
-
 // 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
@@ -637,26 +621,9 @@ TEXT setg_gcc<>(SB),NOSPLIT,$0
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
 	MOVW	8(R29), R1	// LR saved by caller
-	MOVW	runtime·stackBarrierPC(SB), R2
-	BNE	R1, R2, nobar
-	JAL	runtime·nextBarrierPC(SB)	// Get original return PC.
-	MOVW	4(R29), R1
-nobar:
 	MOVW	R1, ret+4(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
-	MOVW	pc+4(FP), R1
-	MOVW	8(R29), R2
-	MOVW	runtime·stackBarrierPC(SB), R3
-	BEQ	R2, R3, setbar
-	MOVW	R1, 8(R29)	// set LR in caller
-	RET
-setbar:
-	MOVW	R1, 4(R29)
-	JAL	runtime·setNextBarrierPC(SB)	// Set the stack barrier return PC.
-	RET
-
 TEXT runtime·abort(SB),NOSPLIT,$0-0
 	UNDEF
 
@@ -904,16 +871,6 @@ cmp_ret:
 	MOVW	R8, ret+24(FP)
 	RET
 
-TEXT runtime·fastrand(SB),NOSPLIT,$0-4
-	MOVW	g_m(g), R2
-	MOVW	m_fastrand(R2), R1
-	ADDU	R1, R1
-	BGEZ	R1, 2(PC)
-	XOR	$0x88888eef, R1
-	MOVW	R1, m_fastrand(R2)
-	MOVW	R1, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB),NOSPLIT,$0
 	MOVW	$0, R1
 	RET
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 1d6adcc..616861e 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -85,14 +85,14 @@ nocgo:
 	// start this M
 	BL	runtime·mstart(SB)
 
-	MOVD	R0, 1(R0)
+	MOVD	R0, 0(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) // TODO: TD
+	MOVD	R0, 0(R0) // TODO: TD
 	RET
 
 TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
@@ -341,24 +341,6 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0
 	MOVD	R0, R11
 	BR	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R3 may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVD	(g_stkbar+slice_array)(g), R4
-	MOVD	g_stkbarPos(g), R5
-	MOVD	$stkbar__size, R6
-	MULLD	R5, R6
-	ADD	R4, R6
-	MOVD	stkbar_savedLRVal(R6), R6
-	// Record that this stack barrier was hit.
-	ADD	$1, R5
-	MOVD	R5, g_stkbarPos(g)
-	// Jump to the original return PC.
-	MOVD	R6, CTR
-	BR	(CTR)
-
 // reflectcall: call a function with the given argument list
 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
 // we don't have variable-sized frames, so we use a small number
@@ -734,30 +716,9 @@ TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
 	MOVD	FIXED_FRAME+8(R1), R3		// LR saved by caller
-	MOVD	runtime·stackBarrierPC(SB), R4
-	CMP	R3, R4
-	BNE	nobar
-	// Get original return PC.
-	BL	runtime·nextBarrierPC(SB)
-	MOVD	FIXED_FRAME+0(R1), R3
-nobar:
 	MOVD	R3, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
-	MOVD	pc+8(FP), R3
-	MOVD	FIXED_FRAME+8(R1), R4
-	MOVD	runtime·stackBarrierPC(SB), R5
-	CMP	R4, R5
-	BEQ	setbar
-	MOVD	R3, FIXED_FRAME+8(R1)		// set LR in caller
-	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVD	R3, FIXED_FRAME+0(R1)
-	BL	runtime·setNextBarrierPC(SB)
-	RET
-
 TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
 	MOVW	(R0), R0
 	UNDEF
@@ -1152,53 +1113,183 @@ equal:
 	MOVBZ	R3,ret+48(FP)
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
-	MOVD	s+0(FP), R3
-	MOVD	s_len+8(FP), R4
-	MOVBZ	c+24(FP), R5	// byte to find
-	MOVD	R3, R6		// store base for later
-	SUB	$1, R3
-	ADD	R3, R4		// end-1
+TEXT bytes·IndexByte(SB),NOSPLIT|NOFRAME,$0-40
+	MOVD	s+0(FP), R3		// R3 = byte array pointer
+	MOVD	s_len+8(FP), R4		// R4 = length
+	MOVBZ	c+24(FP), R5		// R5 = byte
+	MOVD	$ret+32(FP), R14	// R14 = &ret
+	BR	runtime·indexbytebody<>(SB)
+
+TEXT strings·IndexByte(SB),NOSPLIT|NOFRAME,$0-32
+	MOVD	s+0(FP), R3	  // R3 = string
+	MOVD	s_len+8(FP), R4	  // R4 = length
+	MOVBZ	c+16(FP), R5	  // R5 = byte
+	MOVD	$ret+24(FP), R14  // R14 = &ret
+	BR	runtime·indexbytebody<>(SB)
+
+TEXT runtime·indexbytebody<>(SB),NOSPLIT|NOFRAME,$0-0
+	DCBT	(R3)		// Prepare cache line.
+	MOVD	R3,R10		// Save base address for calculating the index later.
+	RLDICR	$0,R3,$60,R8	// Align address to doubleword boundary in R8.
+	RLDIMI	$8,R5,$48,R5	// Replicating the byte across the register.
+
+	// Calculate last acceptable address and check for possible overflow
+	// using a saturated add.
+	// Overflows set last acceptable address to 0xffffffffffffffff.
+	ADD	R4,R3,R7
+	SUBC	R3,R7,R6
+	SUBE	R0,R0,R9
+	MOVW	R9,R6
+	OR	R6,R7,R7
+
+	RLDIMI	$16,R5,$32,R5
+	CMPU	R4,$32		// Check if it's a small string (<32 bytes). Those will be processed differently.
+	MOVD	$-1,R9
+	WORD $0x54661EB8	// Calculate padding in R6 (rlwinm r6,r3,3,26,28).
+	RLDIMI	$32,R5,$0,R5
+	ADD	$-1,R7,R7
+#ifdef GOARCH_ppc64le
+	SLD	R6,R9,R9	// Prepare mask for Little Endian
+#else
+	SRD	R6,R9,R9	// Same for Big Endian
+#endif
+	BLE	small_string	// Jump to the small string case if it's <32 bytes.
+
+	// Case for length >32 bytes
+	MOVD	0(R8),R12	// Load one doubleword from the aligned address in R8.
+	CMPB	R12,R5,R3	// Check for a match.
+	AND	R9,R3,R3	// Mask bytes below s_base
+	RLDICL	$0,R7,$61,R4	// length-1
+	RLDICR	$0,R7,$60,R7	// Last doubleword in R7
+	CMPU	R3,$0,CR7	// If we have a match, jump to the final computation
+	BNE	CR7,done
+
+	// Check for doubleword alignment and jump to the loop setup if aligned.
+	MOVFL	R8,CR7
+	BC	12,28,loop_setup
+
+	// Not aligned, so handle the second doubleword
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR7
+	BNE	CR7,done
+
+loop_setup:
+	// We are now aligned to a 16-byte boundary. We will load two doublewords
+	// per loop iteration. The last doubleword is in R7, so our loop counter
+	// starts at (R7-R8)/16.
+	SUB	R8,R7,R6
+	SRD	$4,R6,R6
+	MOVD	R6,CTR
 
+	// Note: when we have an align directive, align this loop to 32 bytes so
+	// it fits in a single icache sector.
 loop:
-	CMP	R3, R4
+	// Load two doublewords, then compare and merge in a single register. We
+	// will check two doublewords per iteration, then find out which of them
+	// contains the byte later. This speeds up the search.
+	MOVD	8(R8),R12
+	MOVDU	16(R8),R11
+	CMPB	R12,R5,R3
+	CMPB	R11,R5,R9
+	OR	R3,R9,R6
+	CMPU	R6,$0,CR7
+	BNE	CR7,found
+	BC	16,0,loop
+
+	// Counter zeroed, but we may have another doubleword to read
+	CMPU	R8,R7
 	BEQ	notfound
-	MOVBZU	1(R3), R7
-	CMP	R7, R5
-	BNE	loop
 
-	SUB	R6, R3		// remove base
-	MOVD	R3, ret+32(FP)
-	RET
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR6
+	BNE	CR6,done
 
 notfound:
-	MOVD	$-1, R3
-	MOVD	R3, ret+32(FP)
+	MOVD	$-1,R3
+	MOVD	R3,(R14)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0-32
-	MOVD	p+0(FP), R3
-	MOVD	b_len+8(FP), R4
-	MOVBZ	c+16(FP), R5	// byte to find
-	MOVD	R3, R6		// store base for later
-	SUB	$1, R3
-	ADD	R3, R4		// end-1
+found:
+	// One of the doublewords from the loop contains the byte we are looking
+	// for. Check the first doubleword and adjust the address if found.
+	CMPU	R3,$0,CR6
+	ADD	$-8,R8,R8
+	BNE	CR6,done
+
+	// Not found, so it must be in the second doubleword of the merged pair.
+	MOVD	R9,R3
+	ADD	$8,R8,R8
+
+done:
+	// At this point, R3 has 0xFF in the same position as the byte we are
+	// looking for in the doubleword. Use that to calculate the exact index
+	// of the byte.
+#ifdef GOARCH_ppc64le
+	ADD	$-1,R3,R11
+	ANDN	R3,R11,R11
+	POPCNTD	R11,R11		// Count trailing zeros (Little Endian).
+#else
+	CNTLZD	R3,R11		// Count leading zeros (Big Endian).
+#endif
+	CMPU	R8,R7		// Check if we are at the last doubleword.
+	SRD	$3,R11		// Convert trailing zeros to bytes.
+	ADD	R11,R8,R3
+	CMPU	R11,R4,CR7	// If at the last doubleword, check the byte offset.
+	BNE	return
+	BLE	CR7,return
+	MOVD	$-1,R3
+	MOVD	R3,(R14)
+	RET
 
-loop:
-	CMP	R3, R4
+return:
+	SUB	R10,R3		// Calculate index.
+	MOVD	R3,(R14)
+	RET
+
+small_string:
+	// We unroll this loop for better performance.
+	CMPU	R4,$0		// Check for length=0
 	BEQ	notfound
-	MOVBZU	1(R3), R7
-	CMP	R7, R5
-	BNE	loop
 
-	SUB	R6, R3		// remove base
-	MOVD	R3, ret+24(FP)
-	RET
+	MOVD	0(R8),R12	// Load one doubleword from the aligned address in R8.
+	CMPB	R12,R5,R3	// Check for a match.
+	AND	R9,R3,R3	// Mask bytes below s_base.
+	CMPU	R3,$0,CR7	// If we have a match, jump to the final computation.
+	RLDICL	$0,R7,$61,R4	// length-1
+	RLDICR	$0,R7,$60,R7	// Last doubleword in R7.
+        CMPU	R8,R7
+	BNE	CR7,done
+	BEQ	notfound	// Hit length.
+
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR6
+	CMPU	R8,R7
+	BNE	CR6,done
+	BEQ	notfound
 
-notfound:
-	MOVD	$-1, R3
-	MOVD	R3, ret+24(FP)
-	RET
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR6
+	CMPU	R8,R7
+	BNE	CR6,done
+	BEQ	notfound
+
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR6
+	CMPU	R8,R7
+	BNE	CR6,done
+	BEQ	notfound
+
+	MOVDU	8(R8),R12
+	CMPB	R12,R5,R3
+	CMPU	R3,$0,CR6
+	CMPU	R8,R7
+	BNE	CR6,done
+	BR	notfound
 
 TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
 	MOVD	s1_base+0(FP), R5
@@ -1224,17 +1315,6 @@ TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56
 	BR      cmpbodyBE<>(SB)
 #endif
 
-TEXT runtime·fastrand(SB), NOSPLIT, $0-4
-	MOVD	g_m(g), R4
-	MOVWZ	m_fastrand(R4), R3
-	ADD	R3, R3
-	CMPW	R3, $0
-	BGE	2(PC)
-	XOR	$0x88888eef, R3
-	MOVW	R3, m_fastrand(R4)
-	MOVW	R3, ret+0(FP)
-	RET
-
 TEXT runtime·return0(SB), NOSPLIT, $0
 	MOVW	$0, R3
 	RET
diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s
index c2212a5..20e740b 100644
--- a/src/runtime/asm_s390x.s
+++ b/src/runtime/asm_s390x.s
@@ -298,23 +298,6 @@ 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
@@ -675,28 +658,9 @@ TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0
 
 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·abort(SB),NOSPLIT|NOFRAME,$0-0
 	MOVW	(R0), R0
 	UNDEF
@@ -851,17 +815,6 @@ TEXT runtime·memeqbodyclc(SB),NOSPLIT|NOFRAME,$0-0
 	CLC	$1, 0(R3), 0(R5)
 	RET
 
-TEXT runtime·fastrand(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|NOFRAME,$0-40
 	MOVD	s+0(FP), R3     // s => R3
 	MOVD	s_len+8(FP), R4 // s_len => R4
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
index 9cf7b58..395d54a 100644
--- a/src/runtime/cgo.go
+++ b/src/runtime/cgo.go
@@ -16,6 +16,7 @@ import "unsafe"
 //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
+//go:linkname _cgo_yield _cgo_yield
 
 var (
 	_cgo_init                     unsafe.Pointer
@@ -24,6 +25,7 @@ var (
 	_cgo_notify_runtime_init_done unsafe.Pointer
 	_cgo_callers                  unsafe.Pointer
 	_cgo_set_context_function     unsafe.Pointer
+	_cgo_yield                    unsafe.Pointer
 )
 
 // iscgo is set to true by the runtime/cgo package
@@ -48,3 +50,5 @@ func cgoUse(interface{}) { throw("cgoUse should not be called") }
 // so it emits the test and keeps the call, giving the desired
 // escape analysis result. The test is cheaper than the call.
 var cgoAlwaysFalse bool
+
+var cgo_yield = &_cgo_yield
diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s
index dded1be..1cf27dd 100644
--- a/src/runtime/cgo/asm_ppc64x.s
+++ b/src/runtime/cgo/asm_ppc64x.s
@@ -16,6 +16,8 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
 	// Start with standard C stack frame layout and linkage
 	MOVD	LR, R0
 	MOVD	R0, 16(R1)	// Save LR in caller's frame
+	MOVW	CR, R0		// Save CR in caller's frame
+	MOVD	R0, 8(R1)
 	MOVD	R2, 24(R1)	// Save TOC in caller's frame
 
 	BL	saveregs2<>(SB)
@@ -38,6 +40,8 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
 	BL	restoreregs2<>(SB)
 
 	MOVD	24(R1), R2
+	MOVD	8(R1), R0
+	MOVFL	R0, $0xff
 	MOVD	16(R1), R0
 	MOVD	R0, LR
 	RET
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
index 9bde5a9..8590aa3 100644
--- a/src/runtime/cgo/callbacks.go
+++ b/src/runtime/cgo/callbacks.go
@@ -92,5 +92,15 @@ var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
 var x_cgo_set_context_function byte
 var _cgo_set_context_function = &x_cgo_set_context_function
 
+// Calls a libc function to execute background work injected via libc
+// interceptors, such as processing pending signals under the thread
+// sanitizer.
+//
+// Left as a nil pointer if no libc interceptors are expected.
+
+//go:cgo_import_static _cgo_yield
+//go:linkname _cgo_yield _cgo_yield
+var _cgo_yield unsafe.Pointer
+
 //go:cgo_export_static _cgo_topofstack
 //go:cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/gcc_android_arm.c b/src/runtime/cgo/gcc_android_arm.c
index c7b13f9..d8936ea 100644
--- a/src/runtime/cgo/gcc_android_arm.c
+++ b/src/runtime/cgo/gcc_android_arm.c
@@ -10,13 +10,6 @@
 
 #define magic1 (0x23581321U)
 
-// PTHREAD_KEYS_MAX has been added to sys/limits.h at head in bionic:
-// https://android.googlesource.com/platform/bionic/+/master/libc/include/sys/limits.h
-// TODO(crawshaw): remove this definition when NDK r10d is required.
-#ifndef PTHREAD_KEYS_MAX
-#define PTHREAD_KEYS_MAX 128
-#endif
-
 // inittls allocates a thread-local storage slot for g.
 //
 // It finds the first available slot using pthread_key_create and uses
@@ -32,7 +25,11 @@ inittls(void **tlsg, void **tlsbase)
 		fatalf("pthread_key_create failed: %d", err);
 	}
 	pthread_setspecific(k, (void*)magic1);
-	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+	// If thread local slots are laid out as we expect, our magic word will
+	// be located at some low offset from tlsbase. However, just in case something went
+	// wrong, the search is limited to sensible offsets. PTHREAD_KEYS_MAX was the
+	// original limit, but issue 19472 made a higher limit necessary.
+	for (i=0; i<384; i++) {
 		if (*(tlsbase+i) == (void*)magic1) {
 			*tlsg = (void*)(i*sizeof(void *));
 			pthread_setspecific(k, 0);
diff --git a/src/runtime/cgo/gcc_android_arm64.c b/src/runtime/cgo/gcc_android_arm64.c
index f8ad684..499a11f 100644
--- a/src/runtime/cgo/gcc_android_arm64.c
+++ b/src/runtime/cgo/gcc_android_arm64.c
@@ -25,7 +25,11 @@ inittls(void **tlsg, void **tlsbase)
 		fatalf("pthread_key_create failed: %d", err);
 	}
 	pthread_setspecific(k, (void*)magic1);
-	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+	// If thread local slots are laid out as we expect, our magic word will
+	// be located at some low offset from tlsbase. However, just in case something went
+	// wrong, the search is limited to sensible offsets. PTHREAD_KEYS_MAX was the
+	// original limit, but issue 19472 made a higher limit necessary.
+	for (i=0; i<384; i++) {
 		if (*(tlsbase+i) == (void*)magic1) {
 			*tlsg = (void*)(i*sizeof(void *));
 			pthread_setspecific(k, 0);
diff --git a/src/runtime/cgo/gcc_darwin_arm.c b/src/runtime/cgo/gcc_darwin_arm.c
index b3f8046..bcdddd1 100644
--- a/src/runtime/cgo/gcc_darwin_arm.c
+++ b/src/runtime/cgo/gcc_darwin_arm.c
@@ -107,30 +107,42 @@ init_working_dir()
 		return;
 	}
 	CFStringRef url_str_ref = CFURLGetString(url_ref);
-	char url[MAXPATHLEN];
-        if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) {
+	char buf[MAXPATHLEN];
+	Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
+	CFRelease(url_ref);
+	if (!res) {
 		fprintf(stderr, "runtime/cgo: cannot get URL string\n");
 		return;
 	}
 
 	// url is of the form "file:///path/to/Info.plist".
 	// strip it down to the working directory "/path/to".
-	int url_len = strlen(url);
+	int url_len = strlen(buf);
 	if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
-		fprintf(stderr, "runtime/cgo: bad URL: %s\n", url);
+		fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
 		return;
 	}
-	url[url_len-sizeof("/Info.plist")+1] = 0;
-	char *dir = &url[0] + sizeof("file://")-1;
+	buf[url_len-sizeof("/Info.plist")+1] = 0;
+	char *dir = &buf[0] + sizeof("file://")-1;
 
 	if (chdir(dir) != 0) {
 		fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
 	}
 
-	// No-op to set a breakpoint on, immediately after the real chdir.
-	// Gives the test harness in go_darwin_arm_exec (which uses lldb) a
-	// chance to move the working directory.
-	getwd(dir);
+	// The test harness in go_darwin_arm_exec passes the relative working directory
+	// in the GoExecWrapperWorkingDirectory property of the app bundle.
+	CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
+	if (wd_ref != NULL) {
+		if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
+			fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
+			return;
+		}
+		if (chdir(buf) != 0) {
+			fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", buf);
+		}
+		// Notify the test harness that we're correctly set up
+		raise(SIGINT);
+	}
 }
 
 void
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
index 039dcc0..0a69c5d 100644
--- a/src/runtime/cgo/gcc_darwin_arm64.c
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -109,30 +109,42 @@ init_working_dir()
 		return;
 	}
 	CFStringRef url_str_ref = CFURLGetString(url_ref);
-	char url[MAXPATHLEN];
-        if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) {
+	char buf[MAXPATHLEN];
+	Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
+	CFRelease(url_ref);
+	if (!res) {
 		fprintf(stderr, "runtime/cgo: cannot get URL string\n");
 		return;
 	}
 
 	// url is of the form "file:///path/to/Info.plist".
 	// strip it down to the working directory "/path/to".
-	int url_len = strlen(url);
+	int url_len = strlen(buf);
 	if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
-		fprintf(stderr, "runtime/cgo: bad URL: %s\n", url);
+		fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
 		return;
 	}
-	url[url_len-sizeof("/Info.plist")+1] = 0;
-	char *dir = &url[0] + sizeof("file://")-1;
+	buf[url_len-sizeof("/Info.plist")+1] = 0;
+	char *dir = &buf[0] + sizeof("file://")-1;
 
 	if (chdir(dir) != 0) {
 		fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
 	}
 
-	// No-op to set a breakpoint on, immediately after the real chdir.
-	// Gives the test harness in go_darwin_arm_exec (which uses lldb) a
-	// chance to move the working directory.
-	getwd(dir);
+	// The test harness in go_darwin_arm_exec passes the relative working directory
+	// in the GoExecWrapperWorkingDirectory property of the app bundle.
+	CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
+	if (wd_ref != NULL) {
+		if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
+			fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
+			return;
+		}
+		if (chdir(buf) != 0) {
+			fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", buf);
+		}
+		// Notify the test harness that we're correctly set up
+		raise(SIGINT);
+	}
 }
 
 void
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index f6fbaa3..31594ad 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo
-// +build darwin dragonfly freebsd linux netbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include <pthread.h>
 #include <errno.h>
diff --git a/src/runtime/cgo/gcc_libinit_openbsd.c b/src/runtime/cgo/gcc_libinit_openbsd.c
deleted file mode 100644
index c8308e5..0000000
--- a/src/runtime/cgo/gcc_libinit_openbsd.c
+++ /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.
-
-#include <sys/types.h>
-#include <errno.h>
-#include <pthread.h>
-#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) {
-	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
-	abort();
-}
-
-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.
-}
-
-// 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;
-}
-
-// _cgo_try_pthread_create retries sys_pthread_create if it fails with
-// EAGAIN.
-int
-_cgo_openbsd_try_pthread_create(int (*sys_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*),
-	pthread_t* thread, const pthread_attr_t* attr, void* (*pfn)(void*), void* arg) {
-	int tries;
-	int err;
-	struct timespec ts;
-
-	for (tries = 0; tries < 100; tries++) {
-		err = sys_pthread_create(thread, attr, pfn, arg);
-		if (err != EAGAIN) {
-			return err;
-		}
-		ts.tv_sec = 0;
-		ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
-		nanosleep(&ts, nil);
-	}
-	return EAGAIN;
-}
diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c
index 088bcb2..29acd3c 100644
--- a/src/runtime/cgo/gcc_mmap.c
+++ b/src/runtime/cgo/gcc_mmap.c
@@ -6,6 +6,7 @@
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <sys/mman.h>
 
 #include "libcgo.h"
@@ -23,3 +24,16 @@ x_cgo_mmap(void *addr, uintptr_t length, int32_t prot, int32_t flags, int32_t fd
 	}
 	return p;
 }
+
+void
+x_cgo_munmap(void *addr, uintptr_t length) {
+	int r;
+
+	_cgo_tsan_acquire();
+	r = munmap(addr, length);
+	_cgo_tsan_release();
+	if (r < 0) {
+		/* The Go runtime is not prepared for munmap to fail.  */
+		abort();
+	}
+}
diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c
index 0cac047..cfc09e5 100644
--- a/src/runtime/cgo/gcc_openbsd_386.c
+++ b/src/runtime/cgo/gcc_openbsd_386.c
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 #include <sys/types.h>
-#include <dlfcn.h>
-#include <errno.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
@@ -14,125 +12,6 @@
 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 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);
-void __set_tcb(void *);
-
-static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
-	void *(*start_routine)(void *), void *arg);
-
-struct thread_args {
-	void *(*func)(void *);
-	void *arg;
-};
-
-static int has_tib = 0;
-
-static void
-tcb_fixup(int mainthread)
-{
-	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 or TIB that has been setup via librthread.
-
-	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(tls, TLS_SIZE);
-
-	oldtcb = __get_tcb();
-	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
-	// has proper support for PT_TLS.
-}
-
-static void *
-thread_start_wrapper(void *arg)
-{
-	struct thread_args args = *(struct thread_args *)arg;
-
-	free(arg);
-	tcb_fixup(0);
-
-	return args.func(args.arg);
-}
-
-static void init_pthread_wrapper(void) {
-	void *handle;
-
-	// Locate symbol for the system pthread_create function.
-	handle = dlopen("libpthread.so", RTLD_LAZY);
-	if(handle == NULL) {
-		fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
-		abort();
-	}
-	sys_pthread_create = dlsym(handle, "pthread_create");
-	if(sys_pthread_create == NULL) {
-		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);
-}
-
-static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
-
-int
-pthread_create(pthread_t *thread, const pthread_attr_t *attr,
-	void *(*start_routine)(void *), void *arg)
-{
-	struct thread_args *p;
-
-	// we must initialize our wrapper in pthread_create, because it is valid to call
-	// pthread_create in a static constructor, and in fact, our test for issue 9456
-	// does just that.
-	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-		abort();
-	}
-
-	p = malloc(sizeof(*p));
-	if(p == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	p->func = start_routine;
-	p->arg = arg;
-
-	return sys_pthread_create(thread, attr, thread_start_wrapper, p);
-}
-
 void
 x_cgo_init(G *g, void (*setg)(void*))
 {
@@ -144,16 +23,8 @@ x_cgo_init(G *g, void (*setg)(void*))
 	pthread_attr_getstacksize(&attr, &size);
 	g->stacklo = (uintptr)&attr - size + 4096;
 	pthread_attr_destroy(&attr);
-
-	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-		abort();
-	}
-
-	tcb_fixup(1);
 }
 
-
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
@@ -171,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
 	ts->g->stackhi = size;
-	err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
+	err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
 
 	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
@@ -186,8 +57,6 @@ threadentry(void *v)
 {
 	ThreadStart ts;
 
-	tcb_fixup(0);
-
 	ts = *(ThreadStart*)v;
 	free(v);
 
diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c
index 86a9185..ce626c4 100644
--- a/src/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/runtime/cgo/gcc_openbsd_amd64.c
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 #include <sys/types.h>
-#include <dlfcn.h>
-#include <errno.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
@@ -14,125 +12,6 @@
 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 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);
-void __set_tcb(void *);
-
-static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
-	void *(*start_routine)(void *), void *arg);
-
-struct thread_args {
-	void *(*func)(void *);
-	void *arg;
-};
-
-static int has_tib = 0;
-
-static void
-tcb_fixup(int mainthread)
-{
-	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 or TIB that has been setup via librthread.
-
-	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(tls, TLS_SIZE);
-
-	oldtcb = __get_tcb();
-	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
-	// has proper support for PT_TLS.
-}
-
-static void *
-thread_start_wrapper(void *arg)
-{
-	struct thread_args args = *(struct thread_args *)arg;
-
-	free(arg);
-	tcb_fixup(0);
-
-	return args.func(args.arg);
-}
-
-static void init_pthread_wrapper(void) {
-	void *handle;
-
-	// Locate symbol for the system pthread_create function.
-	handle = dlopen("libpthread.so", RTLD_LAZY);
-	if(handle == NULL) {
-		fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
-		abort();
-	}
-	sys_pthread_create = dlsym(handle, "pthread_create");
-	if(sys_pthread_create == NULL) {
-		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);
-}
-
-static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
-
-int
-pthread_create(pthread_t *thread, const pthread_attr_t *attr,
-	void *(*start_routine)(void *), void *arg)
-{
-	struct thread_args *p;
-
-	// we must initialize our wrapper in pthread_create, because it is valid to call
-	// pthread_create in a static constructor, and in fact, our test for issue 9456
-	// does just that.
-	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-		abort();
-	}
-
-	p = malloc(sizeof(*p));
-	if(p == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	p->func = start_routine;
-	p->arg = arg;
-
-	return sys_pthread_create(thread, attr, thread_start_wrapper, p);
-}
-
 void
 x_cgo_init(G *g, void (*setg)(void*))
 {
@@ -144,16 +23,8 @@ x_cgo_init(G *g, void (*setg)(void*))
 	pthread_attr_getstacksize(&attr, &size);
 	g->stacklo = (uintptr)&attr - size + 4096;
 	pthread_attr_destroy(&attr);
-
-	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
-		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
-		abort();
-	}
-
-	tcb_fixup(1);
 }
 
-
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
@@ -171,7 +42,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
 	ts->g->stackhi = size;
-	err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
+	err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
 
 	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
@@ -186,8 +57,6 @@ threadentry(void *v)
 {
 	ThreadStart ts;
 
-	tcb_fixup(0);
-
 	ts = *(ThreadStart*)v;
 	free(v);
 
diff --git a/src/runtime/cgo/gcc_sigaction.c b/src/runtime/cgo/gcc_sigaction.c
index 5aca271..72fb08d 100644
--- a/src/runtime/cgo/gcc_sigaction.c
+++ b/src/runtime/cgo/gcc_sigaction.c
@@ -10,6 +10,8 @@
 #include <string.h>
 #include <signal.h>
 
+#include "libcgo.h"
+
 // go_sigaction_t is a C version of the sigactiont struct from
 // defs_linux_amd64.go.  This definition — and its conversion to and from struct
 // sigaction — are specific to linux/amd64.
@@ -33,6 +35,8 @@ x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *ol
 	struct sigaction oldact;
 	int i;
 
+	_cgo_tsan_acquire();
+
 	memset(&act, 0, sizeof act);
 	memset(&oldact, 0, sizeof oldact);
 
@@ -53,7 +57,8 @@ x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *ol
 
 	ret = sigaction(signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
 	if (ret == -1) {
-		/* This is what the Go code expects on failure. */
+		// runtime.rt_sigaction expects _cgo_sigaction to return errno on error.
+		_cgo_tsan_release();
 		return errno;
 	}
 
@@ -65,12 +70,13 @@ x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *ol
 		}
 		oldgoact->mask = 0;
 		for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
-			if (sigismember(&act.sa_mask, i+1) == 1) {
+			if (sigismember(&oldact.sa_mask, i+1) == 1) {
 				oldgoact->mask |= (uint64_t)(1)<<i;
 			}
 		}
-		oldgoact->flags = act.sa_flags;
+		oldgoact->flags = oldact.sa_flags;
 	}
 
+	_cgo_tsan_release();
 	return ret;
 }
diff --git a/src/runtime/cgo/gcc_util.c b/src/runtime/cgo/gcc_util.c
index 99af021..2d5382a 100644
--- a/src/runtime/cgo/gcc_util.c
+++ b/src/runtime/cgo/gcc_util.c
@@ -22,3 +22,39 @@ x_cgo_thread_start(ThreadStart *arg)
 
 	_cgo_sys_thread_start(ts);	/* OS-dependent half */
 }
+
+#ifndef CGO_TSAN
+void(* const _cgo_yield)() = NULL;
+#else
+
+#include <string.h>
+
+/*
+Stub for allowing libc interceptors to execute.
+
+_cgo_yield is set to NULL if we do not expect libc interceptors to exist.
+*/
+static void
+x_cgo_yield()
+{
+	/*
+	The libc function(s) we call here must form a no-op and include at least one
+	call that triggers TSAN to process pending asynchronous signals.
+
+	sleep(0) would be fine, but it's not portable C (so it would need more header
+	guards).
+	free(NULL) has a fast-path special case in TSAN, so it doesn't
+	trigger signal delivery.
+	free(malloc(0)) would work (triggering the interceptors in malloc), but
+	it also runs a bunch of user-supplied malloc hooks.
+
+	So we choose strncpy(_, _, 0): it requires an extra header,
+	but it's standard and should be very efficient.
+	*/
+	char nothing = 0;
+	strncpy(&nothing, &nothing, 0);
+}
+
+void(* const _cgo_yield)() = &x_cgo_yield;
+
+#endif  /* GO_TSAN */
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index 01f9e72..2b8b4e2 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -111,6 +111,11 @@ extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
 #ifdef CGO_TSAN
 
 // These must match the definitions in yesTsanProlog in cmd/cgo/out.go.
+// In general we should call _cgo_tsan_acquire when we enter C code,
+// and call _cgo_tsan_release when we return to Go code.
+// This is only necessary when calling code that might be instrumented
+// by TSAN, which mostly means system library calls that TSAN intercepts.
+// See the comment in cmd/cgo/out.go for more details.
 
 long long _cgo_sync __attribute__ ((common));
 
diff --git a/src/runtime/cgo/mmap.go b/src/runtime/cgo/mmap.go
index ff98359..ad5f6df 100644
--- a/src/runtime/cgo/mmap.go
+++ b/src/runtime/cgo/mmap.go
@@ -15,8 +15,17 @@ import _ "unsafe"
 // C/C++ code; this permits that code to see the Go code as normal
 // program addresses that have been initialized.
 
+// To support interceptors that look for both mmap and munmap,
+// also call the C library for munmap.
+
 //go:cgo_import_static x_cgo_mmap
 //go:linkname x_cgo_mmap x_cgo_mmap
 //go:linkname _cgo_mmap _cgo_mmap
 var x_cgo_mmap byte
 var _cgo_mmap = &x_cgo_mmap
+
+//go:cgo_import_static x_cgo_munmap
+//go:linkname x_cgo_munmap x_cgo_munmap
+//go:linkname _cgo_munmap _cgo_munmap
+var x_cgo_munmap byte
+var _cgo_munmap = &x_cgo_munmap
diff --git a/src/runtime/cgo/openbsd.go b/src/runtime/cgo/openbsd.go
index 5c70dbd..81c73bf 100644
--- a/src/runtime/cgo/openbsd.go
+++ b/src/runtime/cgo/openbsd.go
@@ -8,24 +8,13 @@ package cgo
 
 import _ "unsafe" // for go:linkname
 
-// Supply environ, __progname and __guard_local, because
-// we don't link against the standard OpenBSD crt0.o and
-// the libc dynamic library needs them.
+// Supply __guard_local because we don't link against the standard
+// OpenBSD crt0.o and the libc dynamic library needs it.
 
-//go:linkname _environ environ
-//go:linkname _progname __progname
 //go:linkname _guard_local __guard_local
 
-var _environ uintptr
-var _progname uintptr
 var _guard_local uintptr
 
-//go:cgo_export_dynamic environ environ
-//go:cgo_export_dynamic __progname __progname
-
 // This is normally marked as hidden and placed in the
 // .openbsd.randomdata section.
 //go:cgo_export_dynamic __guard_local __guard_local
-
-// We override pthread_create to support PT_TLS.
-//go:cgo_export_dynamic pthread_create pthread_create
diff --git a/src/runtime/cgo_mmap.go b/src/runtime/cgo_mmap.go
index 5a2a1a2..aa531b9 100644
--- a/src/runtime/cgo_mmap.go
+++ b/src/runtime/cgo_mmap.go
@@ -15,6 +15,11 @@ import "unsafe"
 //go:linkname _cgo_mmap _cgo_mmap
 var _cgo_mmap unsafe.Pointer
 
+// _cgo_munmap is filled in by runtime/cgo when it is linked into the
+// program, so it is only non-nil when using cgo.
+//go:linkname _cgo_munmap _cgo_munmap
+var _cgo_munmap unsafe.Pointer
+
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
 	if _cgo_mmap != nil {
 		// Make ret a uintptr so that writing to it in the
@@ -32,9 +37,24 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uns
 	return sysMmap(addr, n, prot, flags, fd, off)
 }
 
+func munmap(addr unsafe.Pointer, n uintptr) {
+	if _cgo_munmap != nil {
+		systemstack(func() { callCgoMunmap(addr, n) })
+		return
+	}
+	sysMunmap(addr, n)
+}
+
 // 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
 
 // callCgoMmap calls the mmap function in the runtime/cgo package
 // using the GCC calling convention. It is implemented in assembly.
 func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr
+
+// sysMunmap calls the munmap system call. It is implemented in assembly.
+func sysMunmap(addr unsafe.Pointer, n uintptr)
+
+// callCgoMunmap calls the munmap function in the runtime/cgo package
+// using the GCC calling convention. It is implemented in assembly.
+func callCgoMunmap(addr unsafe.Pointer, n uintptr)
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 69e29ef..755269e 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -110,6 +110,7 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
 	mp := getg().m
 	mp.ncgocall++
 	mp.ncgo++
+	mp.incgo = true
 
 	// Reset traceback.
 	mp.cgoCallers[0] = 0
@@ -151,6 +152,7 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
 
 //go:nosplit
 func endcgo(mp *m) {
+	mp.incgo = false
 	mp.ncgo--
 
 	if raceenabled {
@@ -180,9 +182,11 @@ func cgocallbackg(ctxt uintptr) {
 	savedsp := unsafe.Pointer(gp.syscallsp)
 	savedpc := gp.syscallpc
 	exitsyscall(0) // coming out of cgo call
+	gp.m.incgo = false
 
 	cgocallbackg1(ctxt)
 
+	gp.m.incgo = true
 	// going back to cgo call
 	reentersyscall(savedpc, uintptr(savedsp))
 
@@ -531,7 +535,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
 			return
 		}
 		for _, f := range st.fields {
-			cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
+			cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
 		}
 	case kindPtr, kindUnsafePointer:
 		if indir {
diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go
index 8cac5d9..61aaa0a 100644
--- a/src/runtime/cgocheck.go
+++ b/src/runtime/cgocheck.go
@@ -124,7 +124,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
 	aoff := uintptr(src) - mheap_.arena_start
 	idx := aoff >> _PageShift
 	s := mheap_.spans[idx]
-	if s.state == _MSpanStack {
+	if s.state == _MSpanManual {
 		// There are no heap bits for value stored on the stack.
 		// For a channel receive src might be on the stack of some
 		// other goroutine, so we can't unwind the stack even if
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index b54a46c..6294678 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -109,8 +109,8 @@ func chanbuf(c *hchan, i uint) unsafe.Pointer {
 
 // entry point for c <- x from compiled code
 //go:nosplit
-func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
-	chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t)))
+func chansend1(c *hchan, elem unsafe.Pointer) {
+	chansend(c, elem, true, getcallerpc(unsafe.Pointer(&c)))
 }
 
 /*
@@ -125,14 +125,7 @@ func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
  * been closed.  it is easiest to loop and re-run
  * the operation; we'll see that it's now closed.
  */
-func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
-	if raceenabled {
-		raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend))
-	}
-	if msanenabled {
-		msanread(ep, t.elem.size)
-	}
-
+func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
 	if c == nil {
 		if !block {
 			return false
@@ -183,7 +176,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	if sg := c.recvq.dequeue(); sg != nil {
 		// Found a waiting receiver. We pass the value we want to send
 		// directly to the receiver, bypassing the channel buffer (if any).
-		send(c, sg, ep, func() { unlock(&c.lock) })
+		send(c, sg, ep, func() { unlock(&c.lock) }, 3)
 		return true
 	}
 
@@ -254,7 +247,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 // Channel c must be empty and locked.  send unlocks c with unlockf.
 // sg must already be dequeued from c.
 // ep must be non-nil and point to the heap or the caller's stack.
-func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
+func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
 	if raceenabled {
 		if c.dataqsiz == 0 {
 			racesync(c, sg)
@@ -284,7 +277,7 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp, 4)
+	goready(gp, skip+1)
 }
 
 // Sends and receives on unbuffered or empty-buffered channels are the
@@ -391,13 +384,13 @@ func closechan(c *hchan) {
 
 // entry points for <- c from compiled code
 //go:nosplit
-func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) {
-	chanrecv(t, c, elem, true)
+func chanrecv1(c *hchan, elem unsafe.Pointer) {
+	chanrecv(c, elem, true)
 }
 
 //go:nosplit
-func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
-	_, received = chanrecv(t, c, elem, true)
+func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {
+	_, received = chanrecv(c, elem, true)
 	return
 }
 
@@ -407,7 +400,7 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
 // Otherwise, if c is closed, zeros *ep and returns (true, false).
 // Otherwise, fills in *ep with an element and returns (true, true).
 // A non-nil ep must point to the heap or the caller's stack.
-func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
+func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
 	// raceenabled: don't need to check ep, as it is always on the stack
 	// or is new memory allocated by reflect.
 
@@ -464,7 +457,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		// 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) })
+		recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
 		return true, true
 	}
 
@@ -540,7 +533,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 // Channel c must be full and locked. recv unlocks c with unlockf.
 // sg must already be dequeued from c.
 // A non-nil ep must point to the heap or the caller's stack.
-func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
+func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
 	if c.dataqsiz == 0 {
 		if raceenabled {
 			racesync(c, sg)
@@ -580,7 +573,7 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp, 4)
+	goready(gp, skip+1)
 }
 
 // compiler implements
@@ -600,8 +593,8 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 //		... bar
 //	}
 //
-func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
-	return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t)))
+func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
+	return chansend(c, elem, false, getcallerpc(unsafe.Pointer(&c)))
 }
 
 // compiler implements
@@ -621,8 +614,8 @@ func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
 //		... bar
 //	}
 //
-func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
-	selected, _ = chanrecv(t, c, elem, false)
+func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) {
+	selected, _ = chanrecv(c, elem, false)
 	return
 }
 
@@ -643,20 +636,20 @@ func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
 //		... bar
 //	}
 //
-func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
+func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
 	// TODO(khr): just return 2 values from this function, now that it is in Go.
-	selected, *received = chanrecv(t, c, elem, false)
+	selected, *received = chanrecv(c, elem, false)
 	return
 }
 
 //go:linkname reflect_chansend reflect.chansend
-func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
-	return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
+func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
+	return chansend(c, elem, !nb, getcallerpc(unsafe.Pointer(&c)))
 }
 
 //go:linkname reflect_chanrecv reflect.chanrecv
-func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
-	return chanrecv(t, c, elem, !nb)
+func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
+	return chanrecv(c, elem, !nb)
 }
 
 //go:linkname reflect_chanlen reflect.chanlen
diff --git a/src/runtime/complex.go b/src/runtime/complex.go
index 73f1161..07c596f 100644
--- a/src/runtime/complex.go
+++ b/src/runtime/complex.go
@@ -4,68 +4,58 @@
 
 package runtime
 
-func isposinf(f float64) bool { return f > maxFloat64 }
-func isneginf(f float64) bool { return f < -maxFloat64 }
-func isnan(f float64) bool    { return f != f }
-
-func nan() float64 {
-	var f float64 = 0
-	return f / f
-}
-
-func posinf() float64 {
-	var f float64 = maxFloat64
-	return f * f
-}
-
-func neginf() float64 {
-	var f float64 = maxFloat64
-	return -f * f
+// inf2one returns a signed 1 if f is an infinity and a signed 0 otherwise.
+// The sign of the result is the sign of f.
+func inf2one(f float64) float64 {
+	g := 0.0
+	if isInf(f) {
+		g = 1.0
+	}
+	return copysign(g, f)
 }
 
-func complex128div(n complex128, d complex128) complex128 {
-	// Special cases as in C99.
-	ninf := isposinf(real(n)) || isneginf(real(n)) ||
-		isposinf(imag(n)) || isneginf(imag(n))
-	dinf := isposinf(real(d)) || isneginf(real(d)) ||
-		isposinf(imag(d)) || isneginf(imag(d))
-
-	nnan := !ninf && (isnan(real(n)) || isnan(imag(n)))
-	dnan := !dinf && (isnan(real(d)) || isnan(imag(d)))
+func complex128div(n complex128, m complex128) complex128 {
+	var e, f float64 // complex(e, f) = n/m
+
+	// Algorithm for robust complex division as described in
+	// Robert L. Smith: Algorithm 116: Complex division. Commun. ACM 5(8): 435 (1962).
+	if abs(real(m)) >= abs(imag(m)) {
+		ratio := imag(m) / real(m)
+		denom := real(m) + ratio*imag(m)
+		e = (real(n) + imag(n)*ratio) / denom
+		f = (imag(n) - real(n)*ratio) / denom
+	} else {
+		ratio := real(m) / imag(m)
+		denom := imag(m) + ratio*real(m)
+		e = (real(n)*ratio + imag(n)) / denom
+		f = (imag(n)*ratio - real(n)) / denom
+	}
 
-	switch {
-	case nnan || dnan:
-		return complex(nan(), nan())
-	case ninf && !dinf:
-		return complex(posinf(), posinf())
-	case !ninf && dinf:
-		return complex(0, 0)
-	case real(d) == 0 && imag(d) == 0:
-		if real(n) == 0 && imag(n) == 0 {
-			return complex(nan(), nan())
-		} else {
-			return complex(posinf(), posinf())
-		}
-	default:
-		// Standard complex arithmetic, factored to avoid unnecessary overflow.
-		a := real(d)
-		if a < 0 {
-			a = -a
-		}
-		b := imag(d)
-		if b < 0 {
-			b = -b
-		}
-		if a <= b {
-			ratio := real(d) / imag(d)
-			denom := real(d)*ratio + imag(d)
-			return complex((real(n)*ratio+imag(n))/denom,
-				(imag(n)*ratio-real(n))/denom)
-		} else {
-			ratio := imag(d) / real(d)
-			denom := imag(d)*ratio + real(d)
-			return complex((imag(n)*ratio+real(n))/denom,
-				(imag(n)-real(n)*ratio)/denom)
+	if isNaN(e) && isNaN(f) {
+		// Correct final result to infinities and zeros if applicable.
+		// Matches C99: ISO/IEC 9899:1999 - G.5.1  Multiplicative operators.
+
+		a, b := real(n), imag(n)
+		c, d := real(m), imag(m)
+
+		switch {
+		case m == 0 && (!isNaN(a) || !isNaN(b)):
+			e = copysign(inf, c) * a
+			f = copysign(inf, c) * b
+
+		case (isInf(a) || isInf(b)) && isFinite(c) && isFinite(d):
+			a = inf2one(a)
+			b = inf2one(b)
+			e = inf * (a*c + b*d)
+			f = inf * (b*c - a*d)
+
+		case (isInf(c) || isInf(d)) && isFinite(a) && isFinite(b):
+			c = inf2one(c)
+			d = inf2one(d)
+			e = 0 * (a*c + b*d)
+			f = 0 * (b*c - a*d)
 		}
 	}
+
+	return complex(e, f)
 }
diff --git a/src/runtime/cpuflags_amd64.go b/src/runtime/cpuflags_amd64.go
index 026f0cd..3e408da 100644
--- a/src/runtime/cpuflags_amd64.go
+++ b/src/runtime/cpuflags_amd64.go
@@ -4,72 +4,17 @@
 
 package runtime
 
-var vendorStringBytes [12]byte
-var maxInputValue uint32
-var featureFlags uint32
-var processorVersionInfo uint32
-
-var useRepMovs = true
-
-func hasFeature(feature uint32) bool {
-	return (featureFlags & feature) != 0
-}
-
-func cpuid_low(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32) // implemented in cpuidlow_amd64.s
-func xgetbv_low(arg1 uint32) (eax, edx uint32)                // implemented in cpuidlow_amd64.s
+var useAVXmemmove bool
 
 func init() {
-	const cfOSXSAVE uint32 = 1 << 27
-	const cfAVX uint32 = 1 << 28
-
-	leaf0()
-	leaf1()
-
-	enabledAVX := false
-	// Let's check if OS has set CR4.OSXSAVE[bit 18]
-	// to enable XGETBV instruction.
-	if hasFeature(cfOSXSAVE) {
-		eax, _ := xgetbv_low(0)
-		// Let's check that XCR0[2:1] = ‘11b’
-		// i.e. XMM state and YMM state are enabled by OS.
-		enabledAVX = (eax & 0x6) == 0x6
-	}
-
-	isIntelBridgeFamily := (processorVersionInfo == 0x206A0 ||
-		processorVersionInfo == 0x206D0 ||
-		processorVersionInfo == 0x306A0 ||
-		processorVersionInfo == 0x306E0) &&
-		isIntel()
-
-	useRepMovs = !(hasFeature(cfAVX) && enabledAVX) || isIntelBridgeFamily
-}
-
-func leaf0() {
-	eax, ebx, ecx, edx := cpuid_low(0, 0)
-	maxInputValue = eax
-	int32ToBytes(ebx, vendorStringBytes[0:4])
-	int32ToBytes(edx, vendorStringBytes[4:8])
-	int32ToBytes(ecx, vendorStringBytes[8:12])
-}
-
-func leaf1() {
-	if maxInputValue < 1 {
-		return
-	}
-	eax, _, ecx, _ := cpuid_low(1, 0)
 	// Let's remove stepping and reserved fields
-	processorVersionInfo = eax & 0x0FFF3FF0
-	featureFlags = ecx
-}
+	processor := processorVersionInfo & 0x0FFF3FF0
 
-func int32ToBytes(arg uint32, buffer []byte) {
-	buffer[3] = byte(arg >> 24)
-	buffer[2] = byte(arg >> 16)
-	buffer[1] = byte(arg >> 8)
-	buffer[0] = byte(arg)
-}
+	isIntelBridgeFamily := isIntel &&
+		processor == 0x206A0 ||
+		processor == 0x206D0 ||
+		processor == 0x306A0 ||
+		processor == 0x306E0
 
-func isIntel() bool {
-	intelSignature := [12]byte{'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l'}
-	return vendorStringBytes == intelSignature
+	useAVXmemmove = support_avx && !isIntelBridgeFamily
 }
diff --git a/src/runtime/cpuidlow_amd64.s b/src/runtime/cpuidlow_amd64.s
deleted file mode 100644
index 64316c9..0000000
--- a/src/runtime/cpuidlow_amd64.s
+++ /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.
-
-// func cpuid_low(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32)
-TEXT ·cpuid_low(SB), 4, $0-24
-    MOVL    arg1+0(FP), AX
-    MOVL    arg2+4(FP), CX
-    CPUID
-    MOVL AX, eax+8(FP)
-    MOVL BX, ebx+12(FP)
-    MOVL CX, ecx+16(FP)
-    MOVL DX, edx+20(FP)
-    RET
-// func xgetbv_low(arg1 uint32) (eax, edx uint32)
-TEXT ·xgetbv_low(SB), 4, $0-16
-    MOVL arg1+0(FP), CX
-    // XGETBV
-    BYTE $0x0F; BYTE $0x01; BYTE $0xD0
-    MOVL AX,eax+8(FP)
-    MOVL DX,edx+12(FP)
-    RET
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index a4b14d3..c761e44 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -3,118 +3,45 @@
 // license that can be found in the LICENSE file.
 
 // CPU profiling.
-// Based on algorithms and data structures used in
-// https://github.com/google/pprof.
-//
-// The main difference between this code and the google-perftools
-// code is that this code is written to allow copying the profile data
-// to an arbitrary io.Writer, while the google-perftools code always
-// 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
-// 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
-// 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
-// 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,
-// 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 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
-// 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,
-// and the goroutine is now in charge of flushing the data left in the hash table
-// to the log and returning that data.
-//
-// The handoff field is manipulated using atomic operations.
-// For the most part, the manipulation of handoff is orderly: if handoff == 0
-// 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,
-// in order to let the log closer set the high bit to indicate "EOF" safely
-// in the situation when normally the goroutine "owns" handoff.
+// to a log of recent traces. The log is read by a user goroutine that
+// turns it into formatted profile data. If the reader does not keep up
+// with the log, those writes will be recorded as a count of lost records.
+// The actual profile buffer is in profbuf.go.
 
 package runtime
 
 import (
 	"runtime/internal/atomic"
+	"runtime/internal/sys"
 	"unsafe"
 )
 
-const (
-	numBuckets      = 1 << 10
-	logSize         = 1 << 17
-	assoc           = 4
-	maxCPUProfStack = 64
-)
-
-type cpuprofEntry struct {
-	count uintptr
-	depth int
-	stack [maxCPUProfStack]uintptr
-}
+const maxCPUProfStack = 64
 
-//go:notinheap
 type cpuProfile struct {
-	on     bool    // profiling is on
-	wait   note    // goroutine waits here
-	count  uintptr // tick count
-	evicts uintptr // eviction count
-	lost   uintptr // lost ticks that need to be logged
-
-	// Active recent stack traces.
-	hash [numBuckets]struct {
-		entry [assoc]cpuprofEntry
-	}
-
-	// Log of traces evicted from hash.
-	// Signal handler has filled log[toggle][:nlog].
-	// Goroutine is writing log[1-toggle][:handoff].
-	log     [2][logSize / 2]uintptr
-	nlog    int
-	toggle  int32
-	handoff uint32
-
-	// Writer state.
-	// Writer maintains its own toggle to avoid races
-	// looking at signal handler's toggle.
-	wtoggle  uint32
-	wholding bool // holding & need to release a log half
-	flushing bool // flushing hash table - profile is over
-	eodSent  bool // special end-of-data record sent; => flushing
+	lock mutex
+	on   bool     // profiling is on
+	log  *profBuf // profile events written here
+
+	// extra holds extra stacks accumulated in addNonGo
+	// corresponding to profiling signals arriving on
+	// non-Go-created threads. Those stacks are written
+	// to log the next time a normal Go thread gets the
+	// signal handler.
+	// Assuming the stacks are 2 words each (we don't get
+	// a full traceback from those threads), plus one word
+	// size for framing, 100 Hz profiling would generate
+	// 300 words per second.
+	// Hopefully a normal Go thread will get the profiling
+	// signal at least once every few seconds.
+	extra     [1000]uintptr
+	numExtra  int
+	lostExtra uint64 // count of frames lost because extra is full
 }
 
-var (
-	cpuprofLock mutex
-	cpuprof     *cpuProfile
-
-	eod = [3]uintptr{0, 1, 0}
-)
-
-func setcpuprofilerate(hz int32) {
-	systemstack(func() {
-		setcpuprofilerate_m(hz)
-	})
-}
-
-// lostProfileData is a no-op function used in profiles
-// to mark the number of profiling stack traces that were
-// discarded due to slow data writers.
-func lostProfileData() {}
+var cpuprof cpuProfile
 
 // SetCPUProfileRate sets the CPU profiling rate to hz samples per second.
 // If hz <= 0, SetCPUProfileRate turns off profiling.
@@ -132,323 +59,144 @@ func SetCPUProfileRate(hz int) {
 		hz = 1000000
 	}
 
-	lock(&cpuprofLock)
+	lock(&cpuprof.lock)
 	if hz > 0 {
-		if cpuprof == nil {
-			cpuprof = (*cpuProfile)(sysAlloc(unsafe.Sizeof(cpuProfile{}), &memstats.other_sys))
-			if cpuprof == nil {
-				print("runtime: cpu profiling cannot allocate memory\n")
-				unlock(&cpuprofLock)
-				return
-			}
-		}
-		if cpuprof.on || cpuprof.handoff != 0 {
+		if cpuprof.on || cpuprof.log != nil {
 			print("runtime: cannot set cpu profile rate until previous profile has finished.\n")
-			unlock(&cpuprofLock)
+			unlock(&cpuprof.lock)
 			return
 		}
 
 		cpuprof.on = true
-		// pprof binary header format.
-		// 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
-		p[2] = 0                 // version number
-		p[3] = uintptr(1e6 / hz) // period (microseconds)
-		p[4] = 0
-		cpuprof.nlog = 5
-		cpuprof.toggle = 0
-		cpuprof.wholding = false
-		cpuprof.wtoggle = 0
-		cpuprof.flushing = false
-		cpuprof.eodSent = false
-		noteclear(&cpuprof.wait)
-
+		cpuprof.log = newProfBuf(1, 1<<17, 1<<14)
+		hdr := [1]uint64{uint64(hz)}
+		cpuprof.log.write(nil, nanotime(), hdr[:], nil)
 		setcpuprofilerate(int32(hz))
-	} else if cpuprof != nil && cpuprof.on {
+	} else if cpuprof.on {
 		setcpuprofilerate(0)
 		cpuprof.on = false
-
-		// Now add is not running anymore, and getprofile owns the entire log.
-		// Set the high bit in cpuprof.handoff to tell getprofile.
-		for {
-			n := cpuprof.handoff
-			if n&0x80000000 != 0 {
-				print("runtime: setcpuprofile(off) twice\n")
-			}
-			if atomic.Cas(&cpuprof.handoff, n, n|0x80000000) {
-				if n == 0 {
-					// we did the transition from 0 -> nonzero so we wake getprofile
-					notewakeup(&cpuprof.wait)
-				}
-				break
-			}
-		}
+		cpuprof.addExtra()
+		cpuprof.log.close()
 	}
-	unlock(&cpuprofLock)
+	unlock(&cpuprof.lock)
 }
 
 // add adds the stack trace to the profile.
 // It is called from signal handlers and other limited environments
 // and cannot allocate memory or acquire locks that might be
 // held at the time of the signal, nor can it use substantial amounts
-// of stack. It is allowed to call evict.
+// of stack.
 //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]
-	}
-
-	// Compute hash.
-	h := uintptr(0)
-	for _, x := range pc {
-		h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
-		h += x * 41
+func (p *cpuProfile) add(gp *g, stk []uintptr) {
+	// Simple cas-lock to coordinate with setcpuprofilerate.
+	for !atomic.Cas(&prof.signalLock, 0, 1) {
+		osyield()
 	}
-	p.count++
 
-	// Add to entry count if already present in table.
-	b := &p.hash[h%numBuckets]
-Assoc:
-	for i := range b.entry {
-		e := &b.entry[i]
-		if e.depth != len(pc) {
-			continue
+	if prof.hz != 0 { // implies cpuprof.log != nil
+		if p.numExtra > 0 || p.lostExtra > 0 {
+			p.addExtra()
 		}
-		for j := range pc {
-			if e.stack[j] != pc[j] {
-				continue Assoc
-			}
-		}
-		e.count++
-		return
+		hdr := [1]uint64{1}
+		// Note: write "knows" that the argument is &gp.labels,
+		// because otherwise its write barrier behavior may not
+		// be correct. See the long comment there before
+		// changing the argument here.
+		cpuprof.log.write(&gp.labels, nanotime(), hdr[:], stk)
 	}
 
-	// Evict entry with smallest count.
-	var e *cpuprofEntry
-	for i := range b.entry {
-		if e == nil || b.entry[i].count < e.count {
-			e = &b.entry[i]
-		}
-	}
-	if e.count > 0 {
-		if !p.evict(e, flushlog) {
-			// Could not evict entry. Record lost stack.
-			p.lost++
-			return
-		}
-		p.evicts++
-	}
-
-	// Reuse the newly evicted entry.
-	e.depth = len(pc)
-	e.count = 1
-	copy(e.stack[:], pc)
+	atomic.Store(&prof.signalLock, 0)
 }
 
-// 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, 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.
+// addNonGo adds the non-Go stack trace to the profile.
+// It is called from a non-Go thread, so we cannot use much stack at all,
+// nor do anything that needs a g or an m.
+// In particular, we can't call cpuprof.log.write.
+// Instead, we copy the stack into cpuprof.extra,
+// which will be drained the next time a Go thread
+// gets the signal handling event.
 //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 !flushlog() {
-			return false
-		}
-		log = &p.log[p.toggle]
+func (p *cpuProfile) addNonGo(stk []uintptr) {
+	// Simple cas-lock to coordinate with SetCPUProfileRate.
+	// (Other calls to add or addNonGo should be blocked out
+	// by the fact that only one SIGPROF can be handled by the
+	// process at a time. If not, this lock will serialize those too.)
+	for !atomic.Cas(&prof.signalLock, 0, 1) {
+		osyield()
 	}
 
-	q := p.nlog
-	log[q] = e.count
-	q++
-	log[q] = uintptr(d)
-	q++
-	copy(log[q:], e.stack[:d])
-	q += d
-	p.nlog = q
-	e.count = 0
-	return true
-}
-
-// 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
-// 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
+	if cpuprof.numExtra+1+len(stk) < len(cpuprof.extra) {
+		i := cpuprof.numExtra
+		cpuprof.extra[i] = uintptr(1 + len(stk))
+		copy(cpuprof.extra[i+1:], stk)
+		cpuprof.numExtra += 1 + len(stk)
+	} else {
+		cpuprof.lostExtra++
 	}
-	notewakeup(&p.wait)
 
-	p.toggle = 1 - p.toggle
-	log := &p.log[p.toggle]
-	q := 0
-	if p.lost > 0 {
-		lostPC := funcPC(lostProfileData)
-		log[0] = p.lost
-		log[1] = 1
-		log[2] = lostPC
-		q = 3
-		p.lost = 0
-	}
-	p.nlog = q
-	return true
+	atomic.Store(&prof.signalLock, 0)
 }
 
-// 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.
-func (p *cpuProfile) getprofile() []byte {
-	if p == nil {
-		return nil
-	}
-
-	if p.wholding {
-		// Release previous log to signal handling side.
-		// Loop because we are racing against SetCPUProfileRate(0).
-		for {
-			n := p.handoff
-			if n == 0 {
-				print("runtime: phase error during cpu profile handoff\n")
-				return nil
-			}
-			if n&0x80000000 != 0 {
-				p.wtoggle = 1 - p.wtoggle
-				p.wholding = false
-				p.flushing = true
-				goto Flush
-			}
-			if atomic.Cas(&p.handoff, n, 0) {
-				break
-			}
-		}
-		p.wtoggle = 1 - p.wtoggle
-		p.wholding = false
-	}
-
-	if p.flushing {
-		goto Flush
-	}
-
-	if !p.on && p.handoff == 0 {
-		return nil
-	}
-
-	// Wait for new log.
-	notetsleepg(&p.wait, -1)
-	noteclear(&p.wait)
-
-	switch n := p.handoff; {
-	case n == 0:
-		print("runtime: phase error during cpu profile wait\n")
-		return nil
-	case n == 0x80000000:
-		p.flushing = true
-		goto Flush
-	default:
-		n &^= 0x80000000
-
-		// Return new log to caller.
-		p.wholding = true
-
-		return uintptrBytes(p.log[p.wtoggle][:n])
-	}
-
-	// In flush mode.
-	// 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:
-	for i := range p.hash {
-		b := &p.hash[i]
-		for j := range b.entry {
-			e := &b.entry[j]
-			if e.count > 0 && !p.evict(e, p.flushlog) {
-				// Filled the log. Stop the loop and return what we've got.
-				break Flush
-			}
+// addExtra adds the "extra" profiling events,
+// queued by addNonGo, to the profile log.
+// addExtra is called either from a signal handler on a Go thread
+// or from an ordinary goroutine; either way it can use stack
+// and has a g. The world may be stopped, though.
+func (p *cpuProfile) addExtra() {
+	// Copy accumulated non-Go profile events.
+	hdr := [1]uint64{1}
+	for i := 0; i < p.numExtra; {
+		p.log.write(nil, 0, hdr[:], p.extra[i+1:i+int(p.extra[i])])
+		i += int(p.extra[i])
+	}
+	p.numExtra = 0
+
+	// Report any lost events.
+	if p.lostExtra > 0 {
+		hdr := [1]uint64{p.lostExtra}
+		lostStk := [2]uintptr{
+			funcPC(_LostExternalCode) + sys.PCQuantum,
+			funcPC(_ExternalCode) + sys.PCQuantum,
 		}
+		cpuprof.log.write(nil, 0, hdr[:], lostStk[:])
 	}
-
-	// Return pending log data.
-	if p.nlog > 0 {
-		// Note that we're using toggle now, not wtoggle,
-		// because we're working on the log directly.
-		n := p.nlog
-		p.nlog = 0
-		return uintptrBytes(p.log[p.toggle][:n])
-	}
-
-	// Made it through the table without finding anything to log.
-	if !p.eodSent {
-		// We may not have space to append this to the partial log buf,
-		// so we always return a new slice for the end-of-data marker.
-		p.eodSent = true
-		return uintptrBytes(eod[:])
-	}
-
-	// 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")
-	}
-	return nil
 }
 
-func uintptrBytes(p []uintptr) (ret []byte) {
-	pp := (*slice)(unsafe.Pointer(&p))
-	rp := (*slice)(unsafe.Pointer(&ret))
-
-	rp.array = pp.array
-	rp.len = pp.len * int(unsafe.Sizeof(p[0]))
-	rp.cap = rp.len
-
-	return
-}
-
-// 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
-// data accumulated while it was on has been returned, CPUProfile returns nil.
-// The caller must save the returned data before calling CPUProfile again.
+// CPUProfile panics.
+// It formerly provided raw access to chunks of
+// a pprof-format profile generated by the runtime.
+// The details of generating that format have changed,
+// so this functionality has been removed.
 //
-// Most clients should use the runtime/pprof package or
-// the testing package's -test.cpuprofile flag instead of calling
-// CPUProfile directly.
+// Deprecated: use the runtime/pprof package,
+// or the handlers in the net/http/pprof package,
+// or the testing package's -test.cpuprofile flag instead.
 func CPUProfile() []byte {
-	return cpuprof.getprofile()
+	panic("CPUProfile no longer available")
 }
 
 //go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond
 func runtime_pprof_runtime_cyclesPerSecond() int64 {
 	return tickspersecond()
 }
+
+// readProfile, provided to runtime/pprof, 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 data accumulated while it was
+// on has been returned, readProfile returns eof=true.
+// The caller must save the returned data and tags before calling readProfile again.
+//
+//go:linkname runtime_pprof_readProfile runtime/pprof.readProfile
+func runtime_pprof_readProfile() ([]uint64, []unsafe.Pointer, bool) {
+	lock(&cpuprof.lock)
+	log := cpuprof.log
+	unlock(&cpuprof.lock)
+	data, tags, eof := log.read(profBufBlocking)
+	if len(data) == 0 && eof {
+		lock(&cpuprof.lock)
+		cpuprof.log = nil
+		unlock(&cpuprof.lock)
+	}
+	return data, tags, eof
+}
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 347b820..c102608 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -282,33 +282,43 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) {
 
 	got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput()
 	if err != nil {
+		if testenv.Builder() == "linux-amd64-alpine" {
+			// See Issue 18243 and Issue 19938.
+			t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
+		}
 		t.Fatal(err)
 	}
 	fn := strings.TrimSpace(string(got))
 	defer os.Remove(fn)
 
-	cmd := testEnv(exec.Command(testenv.GoToolPath(t), "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
+	for try := 0; try < 2; try++ {
+		cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1"))
+		// Check that pprof works both with and without explicit executable on command line.
+		if try == 0 {
+			cmd.Args = append(cmd.Args, exe, fn)
+		} else {
+			cmd.Args = append(cmd.Args, fn)
 		}
-	}
-	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)
-	}
+		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())
+		}
 
-	if !bytes.Contains(top, []byte("cpuHog")) {
-		t.Error("missing cpuHog in pprof output")
+		top, err := cmd.CombinedOutput()
+		t.Logf("%s:\n%s", cmd.Args, top)
+		if err != nil {
+			t.Error(err)
+		} else if !bytes.Contains(top, []byte("cpuHog")) {
+			t.Error("missing cpuHog in pprof output")
+		}
 	}
 }
 
@@ -385,3 +395,16 @@ func TestRaceSignal(t *testing.T) {
 		t.Errorf("expected %q got %s", want, got)
 	}
 }
+
+func TestCgoNumGoroutine(t *testing.T) {
+	switch runtime.GOOS {
+	case "windows", "plan9":
+		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
+	}
+	t.Parallel()
+	got := runTestProg(t, "testprogcgo", "NumGoroutine")
+	want := "OK\n"
+	if got != want {
+		t.Errorf("expected %q got %v", want, got)
+	}
+}
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 9ec0ae4..7753809 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -164,6 +164,12 @@ func checkStaleRuntime(t *testing.T) {
 			return
 		}
 		if string(out) != "false\n" {
+			t.Logf("go list -f {{.Stale}} runtime:\n%s", out)
+			out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.StaleReason}}", "runtime")).CombinedOutput()
+			if err != nil {
+				t.Logf("go list -f {{.StaleReason}} failed: %v", err)
+			}
+			t.Logf("go list -f {{.StaleReason}} runtime:\n%s", out)
 			staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.")
 		}
 	})
@@ -302,7 +308,9 @@ func TestNoHelperGoroutines(t *testing.T) {
 
 func TestBreakpoint(t *testing.T) {
 	output := runTestProg(t, "testprog", "Breakpoint")
-	want := "runtime.Breakpoint()"
+	// If runtime.Breakpoint() is inlined, then the stack trace prints
+	// "runtime.Breakpoint(...)" instead of "runtime.Breakpoint()".
+	want := "runtime.Breakpoint("
 	if !strings.Contains(output, want) {
 		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
 	}
@@ -467,28 +475,33 @@ func TestMemPprof(t *testing.T) {
 	fn := strings.TrimSpace(string(got))
 	defer os.Remove(fn)
 
-	cmd := testEnv(exec.Command(testenv.GoToolPath(t), "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
+	for try := 0; try < 2; try++ {
+		cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top"))
+		// Check that pprof works both with and without explicit executable on command line.
+		if try == 0 {
+			cmd.Args = append(cmd.Args, exe, fn)
+		} else {
+			cmd.Args = append(cmd.Args, 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())
 		}
-	}
-	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")
+		top, err := cmd.CombinedOutput()
+		t.Logf("%s:\n%s", cmd.Args, top)
+		if err != nil {
+			t.Error(err)
+		} else if !bytes.Contains(top, []byte("MemProf")) {
+			t.Error("missing MemProf in pprof output")
+		}
 	}
 }
 
@@ -527,3 +540,77 @@ func TestConcurrentMapIterateWrite(t *testing.T) {
 		t.Fatalf("output does not start with %q:\n%s", want, output)
 	}
 }
+
+type point struct {
+	x, y *int
+}
+
+func (p *point) negate() {
+	*p.x = *p.x * -1
+	*p.y = *p.y * -1
+}
+
+// Test for issue #10152.
+func TestPanicInlined(t *testing.T) {
+	defer func() {
+		r := recover()
+		if r == nil {
+			t.Fatalf("recover failed")
+		}
+		buf := make([]byte, 2048)
+		n := runtime.Stack(buf, false)
+		buf = buf[:n]
+		if !bytes.Contains(buf, []byte("(*point).negate(")) {
+			t.Fatalf("expecting stack trace to contain call to (*point).negate()")
+		}
+	}()
+
+	pt := new(point)
+	pt.negate()
+}
+
+// Test for issues #3934 and #20018.
+// We want to delay exiting until a panic print is complete.
+func TestPanicRace(t *testing.T) {
+	testenv.MustHaveGoRun(t)
+
+	exe, err := buildTestProg(t, "testprog")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// The test is intentionally racy, and in my testing does not
+	// produce the expected output about 0.05% of the time.
+	// So run the program in a loop and only fail the test if we
+	// get the wrong output ten times in a row.
+	const tries = 10
+retry:
+	for i := 0; i < tries; i++ {
+		got, err := testEnv(exec.Command(exe, "PanicRace")).CombinedOutput()
+		if err == nil {
+			t.Logf("try %d: program exited successfully, should have failed", i+1)
+			continue
+		}
+
+		if i > 0 {
+			t.Logf("try %d:\n", i+1)
+		}
+		t.Logf("%s\n", got)
+
+		wants := []string{
+			"panic: crash",
+			"PanicRace",
+			"created by ",
+		}
+		for _, want := range wants {
+			if !bytes.Contains(got, []byte(want)) {
+				t.Logf("did not find expected string %q", want)
+				continue retry
+			}
+		}
+
+		// Test generated expected output.
+		return
+	}
+	t.Errorf("test ran %d times without producing expected output", tries)
+}
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 182c84b..fdb3267 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -251,3 +251,16 @@ func TestSignalIgnoreSIGTRAP(t *testing.T) {
 		t.Fatalf("want %s, got %s\n", want, output)
 	}
 }
+
+func TestSignalDuringExec(t *testing.T) {
+	switch runtime.GOOS {
+	case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
+	default:
+		t.Skipf("skipping test on %s", runtime.GOOS)
+	}
+	output := runTestProg(t, "testprognet", "SignalDuringExec")
+	want := "OK\n"
+	if output != want {
+		t.Fatalf("want %s, got %s\n", want, output)
+	}
+}
diff --git a/src/runtime/debug/garbage.go b/src/runtime/debug/garbage.go
index c82c024..785e9d4 100644
--- a/src/runtime/debug/garbage.go
+++ b/src/runtime/debug/garbage.go
@@ -89,9 +89,7 @@ func ReadGCStats(stats *GCStats) {
 // at startup, or 100 if the variable is not set.
 // A negative percentage disables garbage collection.
 func SetGCPercent(percent int) int {
-	old := setGCPercent(int32(percent))
-	runtime.GC()
-	return int(old)
+	return int(setGCPercent(int32(percent)))
 }
 
 // FreeOSMemory forces a garbage collection followed by an
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index 04e954b..69e769e 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -5,6 +5,7 @@
 package debug_test
 
 import (
+	"internal/testenv"
 	"runtime"
 	. "runtime/debug"
 	"testing"
@@ -104,15 +105,78 @@ func TestFreeOSMemory(t *testing.T) {
 	}
 }
 
+var (
+	setGCPercentBallast interface{}
+	setGCPercentSink    interface{}
+)
+
 func TestSetGCPercent(t *testing.T) {
+	testenv.SkipFlaky(t, 20076)
+
 	// Test that the variable is being set and returned correctly.
-	// Assume the percentage itself is implemented fine during GC,
-	// which is harder to test.
 	old := SetGCPercent(123)
 	new := SetGCPercent(old)
 	if new != 123 {
 		t.Errorf("SetGCPercent(123); SetGCPercent(x) = %d, want 123", new)
 	}
+
+	// Test that the percentage is implemented correctly.
+	defer func() {
+		SetGCPercent(old)
+		setGCPercentBallast, setGCPercentSink = nil, nil
+	}()
+	SetGCPercent(100)
+	runtime.GC()
+	// Create 100 MB of live heap as a baseline.
+	const baseline = 100 << 20
+	var ms runtime.MemStats
+	runtime.ReadMemStats(&ms)
+	setGCPercentBallast = make([]byte, baseline-ms.Alloc)
+	runtime.GC()
+	runtime.ReadMemStats(&ms)
+	if abs64(baseline-int64(ms.Alloc)) > 10<<20 {
+		t.Fatalf("failed to set up baseline live heap; got %d MB, want %d MB", ms.Alloc>>20, baseline>>20)
+	}
+	// NextGC should be ~200 MB.
+	const thresh = 20 << 20 // TODO: Figure out why this is so noisy on some builders
+	if want := int64(2 * baseline); abs64(want-int64(ms.NextGC)) > thresh {
+		t.Errorf("NextGC = %d MB, want %d±%d MB", ms.NextGC>>20, want>>20, thresh>>20)
+	}
+	// Create some garbage, but not enough to trigger another GC.
+	for i := 0; i < int(1.2*baseline); i += 1 << 10 {
+		setGCPercentSink = make([]byte, 1<<10)
+	}
+	setGCPercentSink = nil
+	// Adjust GOGC to 50. NextGC should be ~150 MB.
+	SetGCPercent(50)
+	runtime.ReadMemStats(&ms)
+	if want := int64(1.5 * baseline); abs64(want-int64(ms.NextGC)) > thresh {
+		t.Errorf("NextGC = %d MB, want %d±%d MB", ms.NextGC>>20, want>>20, thresh>>20)
+	}
+
+	// Trigger a GC and get back to 100 MB live with GOGC=100.
+	SetGCPercent(100)
+	runtime.GC()
+	// Raise live to 120 MB.
+	setGCPercentSink = make([]byte, int(0.2*baseline))
+	// Lower GOGC to 10. This must force a GC.
+	runtime.ReadMemStats(&ms)
+	ngc1 := ms.NumGC
+	SetGCPercent(10)
+	// It may require an allocation to actually force the GC.
+	setGCPercentSink = make([]byte, 1<<20)
+	runtime.ReadMemStats(&ms)
+	ngc2 := ms.NumGC
+	if ngc1 == ngc2 {
+		t.Errorf("expected GC to run but it did not")
+	}
+}
+
+func abs64(a int64) int64 {
+	if a < 0 {
+		return -a
+	}
+	return a
 }
 
 func TestSetMaxThreadsOvf(t *testing.T) {
diff --git a/src/runtime/defs_freebsd.go b/src/runtime/defs_freebsd.go
index 73422b7..0a11d09 100644
--- a/src/runtime/defs_freebsd.go
+++ b/src/runtime/defs_freebsd.go
@@ -28,9 +28,20 @@ package runtime
 #include <sys/thr.h>
 #include <sys/_sigset.h>
 #include <sys/unistd.h>
+#include <sys/sysctl.h>
+#include <sys/cpuset.h>
+#include <sys/param.h>
 */
 import "C"
 
+// Local consts.
+const (
+	_NBBY            = C.NBBY            // Number of bits in a byte.
+	_CTL_MAXNAME     = C.CTL_MAXNAME     // Largest number of components supported.
+	_CPU_LEVEL_WHICH = C.CPU_LEVEL_WHICH // Actual mask/id for which.
+	_CPU_WHICH_PID   = C.CPU_WHICH_PID   // Specifies a process id.
+)
+
 const (
 	EINTR  = C.EINTR
 	EFAULT = C.EFAULT
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
index 0c05d71..92b0550 100644
--- a/src/runtime/defs_freebsd_386.go
+++ b/src/runtime/defs_freebsd_386.go
@@ -6,6 +6,13 @@ package runtime
 import "unsafe"
 
 const (
+	_NBBY            = 0x8
+	_CTL_MAXNAME     = 0x18
+	_CPU_LEVEL_WHICH = 0x3
+	_CPU_WHICH_PID   = 0x2
+)
+
+const (
 	_EINTR  = 0x4
 	_EFAULT = 0xe
 
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
index b416044..645e205 100644
--- a/src/runtime/defs_freebsd_amd64.go
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -6,6 +6,13 @@ package runtime
 import "unsafe"
 
 const (
+	_NBBY            = 0x8
+	_CTL_MAXNAME     = 0x18
+	_CPU_LEVEL_WHICH = 0x3
+	_CPU_WHICH_PID   = 0x2
+)
+
+const (
 	_EINTR  = 0x4
 	_EFAULT = 0xe
 
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
index 8f85f17..c8a198f 100644
--- a/src/runtime/defs_freebsd_arm.go
+++ b/src/runtime/defs_freebsd_arm.go
@@ -6,6 +6,13 @@ package runtime
 import "unsafe"
 
 const (
+	_NBBY            = 0x8
+	_CTL_MAXNAME     = 0x18
+	_CPU_LEVEL_WHICH = 0x3
+	_CPU_WHICH_PID   = 0x2
+)
+
+const (
 	_EINTR  = 0x4
 	_EFAULT = 0xe
 
diff --git a/src/runtime/duff_386.s b/src/runtime/duff_386.s
index 5575455..ab01430 100644
--- a/src/runtime/duff_386.s
+++ b/src/runtime/duff_386.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/duff_amd64.s b/src/runtime/duff_amd64.s
index 6ed7f65..a1112a4 100644
--- a/src/runtime/duff_amd64.s
+++ b/src/runtime/duff_amd64.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/duff_arm.s b/src/runtime/duff_arm.s
index da9f0cb..ba8235b 100644
--- a/src/runtime/duff_arm.s
+++ b/src/runtime/duff_arm.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/duff_arm64.s b/src/runtime/duff_arm64.s
index 5a147fa..60a0e26 100644
--- a/src/runtime/duff_arm64.s
+++ b/src/runtime/duff_arm64.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/duff_mips64x.s b/src/runtime/duff_mips64x.s
index 062e04a..e21b81d 100644
--- a/src/runtime/duff_mips64x.s
+++ b/src/runtime/duff_mips64x.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/duff_ppc64x.s b/src/runtime/duff_ppc64x.s
index c8204c4..b4bb9e7 100644
--- a/src/runtime/duff_ppc64x.s
+++ b/src/runtime/duff_ppc64x.s
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mkduff.go
+// Code generated by mkduff.go; DO NOT EDIT.
 // Run go generate from src/runtime to update.
 // See mkduff.go for comments.
 
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index da34425..6b45a43 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -13,7 +13,7 @@ func gogetenv(key string) string {
 	if env == nil {
 		throw("getenv before env init")
 	}
-	for _, s := range environ() {
+	for _, s := range env {
 		if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
 			return s[len(key)+1:]
 		}
diff --git a/src/runtime/error.go b/src/runtime/error.go
index 0238c5e..eafcc9b 100644
--- a/src/runtime/error.go
+++ b/src/runtime/error.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+import _ "unsafe" // for go:linkname
+
 // The Error interface identifies a run time error.
 type Error interface {
 	error
@@ -72,8 +74,6 @@ func typestring(x interface{}) string {
 
 // For calling from C.
 // Prints an argument passed to panic.
-// There's room for arbitrary complexity here, but we keep it
-// simple and handle just a few important cases: int, string, and Stringer.
 func printany(i interface{}) {
 	switch v := i.(type) {
 	case nil:
@@ -82,8 +82,38 @@ func printany(i interface{}) {
 		print(v.String())
 	case error:
 		print(v.Error())
+	case bool:
+		print(v)
 	case int:
 		print(v)
+	case int8:
+		print(v)
+	case int16:
+		print(v)
+	case int32:
+		print(v)
+	case int64:
+		print(v)
+	case uint:
+		print(v)
+	case uint8:
+		print(v)
+	case uint16:
+		print(v)
+	case uint32:
+		print(v)
+	case uint64:
+		print(v)
+	case uintptr:
+		print(v)
+	case float32:
+		print(v)
+	case float64:
+		print(v)
+	case complex64:
+		print(v)
+	case complex128:
+		print(v)
 	case string:
 		print(v)
 	default:
@@ -91,7 +121,41 @@ func printany(i interface{}) {
 	}
 }
 
+// strings.IndexByte is implemented in runtime/asm_$goarch.s
+// but amusingly we need go:linkname to get access to it here in the runtime.
+//go:linkname stringsIndexByte strings.IndexByte
+func stringsIndexByte(s string, c byte) int
+
 // called from generated code
-func panicwrap(pkg, typ, meth string) {
+func panicwrap() {
+	pc := make([]uintptr, 1)
+	n := Callers(2, pc)
+	if n == 0 {
+		throw("panicwrap: Callers failed")
+	}
+	frames := CallersFrames(pc)
+	frame, _ := frames.Next()
+	name := frame.Function
+	// name is something like "main.(*T).F".
+	// We want to extract pkg ("main"), typ ("T"), and meth ("F").
+	// Do it by finding the parens.
+	i := stringsIndexByte(name, '(')
+	if i < 0 {
+		throw("panicwrap: no ( in " + frame.Function)
+	}
+	pkg := name[:i-1]
+	if i+2 >= len(name) || name[i-1:i+2] != ".(*" {
+		throw("panicwrap: unexpected string after package name: " + frame.Function)
+	}
+	name = name[i+2:]
+	i = stringsIndexByte(name, ')')
+	if i < 0 {
+		throw("panicwrap: no ) in " + frame.Function)
+	}
+	if i+2 >= len(name) || name[i:i+2] != ")." {
+		throw("panicwrap: unexpected string after type name: " + frame.Function)
+	}
+	typ := name[:i]
+	meth := name[i+2:]
 	panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
 }
diff --git a/src/runtime/example_test.go b/src/runtime/example_test.go
new file mode 100644
index 0000000..e4912a5
--- /dev/null
+++ b/src/runtime/example_test.go
@@ -0,0 +1,54 @@
+// Copyright 2017 The Go Authors. 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"
+	"strings"
+)
+
+func ExampleFrames() {
+	c := func() {
+		// Ask runtime.Callers for up to 10 pcs, including runtime.Callers itself.
+		pc := make([]uintptr, 10)
+		n := runtime.Callers(0, pc)
+		if n == 0 {
+			// No pcs available. Stop now.
+			// This can happen if the first argument to runtime.Callers is large.
+			return
+		}
+
+		pc = pc[:n] // pass only valid pcs to runtime.CallersFrames
+		frames := runtime.CallersFrames(pc)
+
+		// Loop to get frames.
+		// A fixed number of pcs can expand to an indefinite number of Frames.
+		for {
+			frame, more := frames.Next()
+			// To keep this example's output stable
+			// even if there are changes in the testing package,
+			// stop unwinding when we leave package runtime.
+			if !strings.Contains(frame.File, "runtime/") {
+				break
+			}
+			fmt.Printf("- more:%v | %s\n", more, frame.Function)
+			if !more {
+				break
+			}
+		}
+	}
+
+	b := func() { c() }
+	a := func() { b() }
+
+	a()
+	// Output:
+	// - more:true | runtime.Callers
+	// - more:true | runtime_test.ExampleFrames.func1
+	// - more:true | runtime_test.ExampleFrames.func2
+	// - more:true | runtime_test.ExampleFrames.func3
+	// - more:true | runtime_test.ExampleFrames
+}
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 3b33c84..af91d52 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -41,11 +41,11 @@ type LFNode struct {
 }
 
 func LFStackPush(head *uint64, node *LFNode) {
-	lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
+	(*lfstack)(head).push((*lfnode)(unsafe.Pointer(node)))
 }
 
 func LFStackPop(head *uint64) *LFNode {
-	return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
+	return (*LFNode)(unsafe.Pointer((*lfstack)(head).pop()))
 }
 
 func GCMask(x interface{}) (ret []byte) {
@@ -246,6 +246,97 @@ func CountPagesInUse() (pagesInUse, counted uintptr) {
 	return
 }
 
+func Fastrand() uint32          { return fastrand() }
+func Fastrandn(n uint32) uint32 { return fastrandn(n) }
+
+type ProfBuf profBuf
+
+func NewProfBuf(hdrsize, bufwords, tags int) *ProfBuf {
+	return (*ProfBuf)(newProfBuf(hdrsize, bufwords, tags))
+}
+
+func (p *ProfBuf) Write(tag *unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
+	(*profBuf)(p).write(tag, now, hdr, stk)
+}
+
+const (
+	ProfBufBlocking    = profBufBlocking
+	ProfBufNonBlocking = profBufNonBlocking
+)
+
+func (p *ProfBuf) Read(mode profBufReadMode) ([]uint64, []unsafe.Pointer, bool) {
+	return (*profBuf)(p).read(profBufReadMode(mode))
+}
+
+func (p *ProfBuf) Close() {
+	(*profBuf)(p).close()
+}
+
+// ReadMemStatsSlow returns both the runtime-computed MemStats and
+// MemStats accumulated by scanning the heap.
+func ReadMemStatsSlow() (base, slow MemStats) {
+	stopTheWorld("ReadMemStatsSlow")
+
+	// Run on the system stack to avoid stack growth allocation.
+	systemstack(func() {
+		// Make sure stats don't change.
+		getg().m.mallocing++
+
+		readmemstats_m(&base)
+
+		// Initialize slow from base and zero the fields we're
+		// recomputing.
+		slow = base
+		slow.Alloc = 0
+		slow.TotalAlloc = 0
+		slow.Mallocs = 0
+		slow.Frees = 0
+		var bySize [_NumSizeClasses]struct {
+			Mallocs, Frees uint64
+		}
+
+		// Add up current allocations in spans.
+		for _, s := range mheap_.allspans {
+			if s.state != mSpanInUse {
+				continue
+			}
+			if sizeclass := s.spanclass.sizeclass(); sizeclass == 0 {
+				slow.Mallocs++
+				slow.Alloc += uint64(s.elemsize)
+			} else {
+				slow.Mallocs += uint64(s.allocCount)
+				slow.Alloc += uint64(s.allocCount) * uint64(s.elemsize)
+				bySize[sizeclass].Mallocs += uint64(s.allocCount)
+			}
+		}
+
+		// Add in frees. readmemstats_m flushed the cached stats, so
+		// these are up-to-date.
+		var smallFree uint64
+		slow.Frees = mheap_.nlargefree
+		for i := range mheap_.nsmallfree {
+			slow.Frees += mheap_.nsmallfree[i]
+			bySize[i].Frees = mheap_.nsmallfree[i]
+			bySize[i].Mallocs += mheap_.nsmallfree[i]
+			smallFree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
+		}
+		slow.Frees += memstats.tinyallocs
+		slow.Mallocs += slow.Frees
+
+		slow.TotalAlloc = slow.Alloc + mheap_.largefree + smallFree
+
+		for i := range slow.BySize {
+			slow.BySize[i].Mallocs = bySize[i].Mallocs
+			slow.BySize[i].Frees = bySize[i].Frees
+		}
+
+		getg().m.mallocing--
+	})
+
+	startTheWorld()
+	return
+}
+
 // BlockOnSystemStack switches to the system stack, prints "x\n" to
 // stderr, and blocks in a stack containing
 // "runtime.blockOnSystemStackInternal".
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 1b53367..6e6c674 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -50,13 +50,6 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines
 	onto smaller stacks. In this mode, a goroutine's stack can only grow.
 
-	gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers
-	that allow the garbage collector to avoid repeating a stack scan during the
-	mark termination phase.
-
-	gcstackbarrierall: setting gcstackbarrierall=1 installs stack barriers
-	in every stack frame, rather than in exponentially-spaced frames.
-
 	gcrescanstacks: setting gcrescanstacks=1 enables stack
 	re-scanning during the STW mark termination phase. This is
 	helpful for debugging if objects are being prematurely
@@ -85,7 +78,7 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	for mark/scan are broken down in to assist time (GC performed in
 	line with allocation), background GC time, and idle GC time.
 	If the line ends with "(forced)", this GC was forced by a
-	runtime.GC() call and all phases are STW.
+	runtime.GC() call.
 
 	Setting gctrace to any value > 0 also causes the garbage collector
 	to emit a summary when memory is released back to the system.
@@ -173,33 +166,26 @@ import "runtime/internal/sys"
 // 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.
 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
-	// "called" sigpanic.
-	var rpc [2]uintptr
+	// Make room for three PCs: the one we were asked for,
+	// what it called, so that CallersFrames can see if it "called"
+	// sigpanic, and possibly a PC for skipPleaseUseCallersFrames.
+	var rpc [3]uintptr
 	if callers(1+skip-1, rpc[:]) < 2 {
 		return
 	}
-	f := findfunc(rpc[1])
-	if f == nil {
-		// TODO(rsc): Probably a bug?
-		// The C version said "have retpc at least"
-		// but actually returned pc=0.
-		ok = true
+	var stackExpander stackExpander
+	callers := stackExpander.init(rpc[:])
+	// We asked for one extra, so skip that one. If this is sigpanic,
+	// stepping over this frame will set up state in Frames so the
+	// next frame is correct.
+	callers, _, ok = stackExpander.next(callers)
+	if !ok {
 		return
 	}
-	pc = rpc[1]
-	xpc := pc
-	g := findfunc(rpc[0])
-	// All architectures turn faults into apparent calls to sigpanic.
-	// If we see a call to sigpanic, we do not back up the PC to find
-	// the line number of the call instruction, because there is no call.
-	if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
-		xpc--
-	}
-	file, line32 := funcline(f, xpc)
-	line = int(line32)
-	ok = true
+	_, frame, _ := stackExpander.next(callers)
+	pc = frame.PC
+	file = frame.File
+	line = frame.Line
 	return
 }
 
@@ -209,11 +195,13 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 // 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 normally return the file and line number of the instruction immediately
-// following the call.
-// To easily look up file/line information for the call sequence, use Frames.
+// To translate these PCs into symbolic information such as function
+// names and line numbers, use CallersFrames. CallersFrames accounts
+// for inlined functions and adjusts the return program counters into
+// call program counters. Iterating over the returned slice of PCs
+// directly is discouraged, as is using FuncForPC on any of the
+// returned PCs, since these cannot account for inlining or return
+// program counter adjustment.
 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
@@ -247,5 +235,5 @@ func Version() string {
 const GOOS string = sys.GOOS
 
 // GOARCH is the running program's architecture target:
-// 386, amd64, arm, or s390x.
+// one of 386, amd64, arm, s390x, and so on.
 const GOARCH string = sys.GOARCH
diff --git a/src/runtime/fastlog2.go b/src/runtime/fastlog2.go
index 5f3fb53..1f251bf 100644
--- a/src/runtime/fastlog2.go
+++ b/src/runtime/fastlog2.go
@@ -4,8 +4,6 @@
 
 package runtime
 
-import "unsafe"
-
 // fastlog2 implements a fast approximation to the base 2 log of a
 // float64. This is used to compute a geometric distribution for heap
 // sampling, without introducing dependencies into package math. This
@@ -27,7 +25,3 @@ func fastlog2(x float64) float64 {
 	low, high := fastlog2Table[xManIndex], fastlog2Table[xManIndex+1]
 	return float64(xExp) + low + (high-low)*float64(xManScale)*fastlogScaleRatio
 }
-
-// float64bits returns the IEEE 754 binary representation of f.
-// Taken from math.Float64bits to avoid dependencies into package math.
-func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
diff --git a/src/runtime/float.go b/src/runtime/float.go
new file mode 100644
index 0000000..459e58d
--- /dev/null
+++ b/src/runtime/float.go
@@ -0,0 +1,53 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+var inf = float64frombits(0x7FF0000000000000)
+
+// isNaN reports whether f is an IEEE 754 ``not-a-number'' value.
+func isNaN(f float64) (is bool) {
+	// IEEE 754 says that only NaNs satisfy f != f.
+	return f != f
+}
+
+// isFinite reports whether f is neither NaN nor an infinity.
+func isFinite(f float64) bool {
+	return !isNaN(f - f)
+}
+
+// isInf reports whether f is an infinity.
+func isInf(f float64) bool {
+	return !isNaN(f) && !isFinite(f)
+}
+
+// Abs returns the absolute value of x.
+//
+// Special cases are:
+//	Abs(±Inf) = +Inf
+//	Abs(NaN) = NaN
+func abs(x float64) float64 {
+	const sign = 1 << 63
+	return float64frombits(float64bits(x) &^ sign)
+}
+
+// copysign returns a value with the magnitude
+// of x and the sign of y.
+func copysign(x, y float64) float64 {
+	const sign = 1 << 63
+	return float64frombits(float64bits(x)&^sign | float64bits(y)&sign)
+}
+
+// Float64bits returns the IEEE 754 binary representation of f.
+func float64bits(f float64) uint64 {
+	return *(*uint64)(unsafe.Pointer(&f))
+}
+
+// Float64frombits returns the floating point number corresponding
+// the IEEE 754 binary representation b.
+func float64frombits(b uint64) float64 {
+	return *(*float64)(unsafe.Pointer(&b))
+}
diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h
index 82992e2..27d5a2f 100644
--- a/src/runtime/funcdata.h
+++ b/src/runtime/funcdata.h
@@ -6,14 +6,14 @@
 // in Go binaries. It is included by assembly sources, so it must
 // be written using #defines.
 //
-// The Go compiler also #includes this file, for now.
-//
-// symtab.go also contains a copy of these constants.
+// These must agree with symtab.go and ../cmd/internal/obj/funcdata.go.
 
 #define PCDATA_StackMapIndex 0
+#define PCDATA_InlTreeIndex 1
 
 #define FUNCDATA_ArgsPointerMaps 0 /* garbage collector blocks */
 #define FUNCDATA_LocalsPointerMaps 1
+#define FUNCDATA_InlTree 2
 
 // Pseudo-assembly statements.
 
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 4a32f15..03acc8a 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+	"fmt"
 	"os"
 	"reflect"
 	"runtime"
@@ -448,3 +449,53 @@ func TestPageAccounting(t *testing.T) {
 		t.Fatalf("mheap_.pagesInUse is %d, but direct count is %d", pagesInUse, counted)
 	}
 }
+
+func TestReadMemStats(t *testing.T) {
+	base, slow := runtime.ReadMemStatsSlow()
+	if base != slow {
+		logDiff(t, "MemStats", reflect.ValueOf(base), reflect.ValueOf(slow))
+		t.Fatal("memstats mismatch")
+	}
+}
+
+func logDiff(t *testing.T, prefix string, got, want reflect.Value) {
+	typ := got.Type()
+	switch typ.Kind() {
+	case reflect.Array, reflect.Slice:
+		if got.Len() != want.Len() {
+			t.Logf("len(%s): got %v, want %v", prefix, got, want)
+			return
+		}
+		for i := 0; i < got.Len(); i++ {
+			logDiff(t, fmt.Sprintf("%s[%d]", prefix, i), got.Index(i), want.Index(i))
+		}
+	case reflect.Struct:
+		for i := 0; i < typ.NumField(); i++ {
+			gf, wf := got.Field(i), want.Field(i)
+			logDiff(t, prefix+"."+typ.Field(i).Name, gf, wf)
+		}
+	case reflect.Map:
+		t.Fatal("not implemented: logDiff for map")
+	default:
+		if got.Interface() != want.Interface() {
+			t.Logf("%s: got %v, want %v", prefix, got, want)
+		}
+	}
+}
+
+func BenchmarkReadMemStats(b *testing.B) {
+	var ms runtime.MemStats
+	const heapSize = 100 << 20
+	x := make([]*[1024]byte, heapSize/1024)
+	for i := range x {
+		x[i] = new([1024]byte)
+	}
+	hugeSink = x
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		runtime.ReadMemStats(&ms)
+	}
+
+	hugeSink = nil
+}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 086d374..11ce0cb 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -116,6 +116,11 @@ type hmap struct {
 	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
 	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
 
+	extra *mapextra // optional fields
+}
+
+// mapextra holds fields that are not present on all maps.
+type mapextra struct {
 	// If both key and value do not contain pointers and are inline, then we mark bucket
 	// type as containing no pointers. This avoids scanning such maps.
 	// However, bmap.overflow is a pointer. In order to keep overflow buckets
@@ -123,9 +128,11 @@ type hmap struct {
 	// Overflow is used only if key and value do not contain pointers.
 	// overflow[0] contains overflow buckets for hmap.buckets.
 	// overflow[1] contains overflow buckets for hmap.oldbuckets.
-	// The first indirection allows us to reduce static size of hmap.
-	// The second indirection allows to store a pointer to the slice in hiter.
-	overflow *[2]*[]*bmap
+	// The indirection allows to store a pointer to the slice in hiter.
+	overflow [2]*[]*bmap
+
+	// nextOverflow holds a pointer to a free overflow bucket.
+	nextOverflow *bmap
 }
 
 // A bucket for a Go map.
@@ -170,6 +177,10 @@ func (b *bmap) overflow(t *maptype) *bmap {
 	return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize))
 }
 
+func (b *bmap) setoverflow(t *maptype, ovf *bmap) {
+	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf
+}
+
 // incrnoverflow increments h.noverflow.
 // noverflow counts the number of overflow buckets.
 // This is used to trigger same-size map growth.
@@ -196,21 +207,40 @@ func (h *hmap) incrnoverflow() {
 	}
 }
 
-func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
+func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap {
+	var ovf *bmap
+	if h.extra != nil && h.extra.nextOverflow != nil {
+		// We have preallocated overflow buckets available.
+		// See makeBucketArray for more details.
+		ovf = h.extra.nextOverflow
+		if ovf.overflow(t) == nil {
+			// We're not at the end of the preallocated overflow buckets. Bump the pointer.
+			h.extra.nextOverflow = (*bmap)(add(unsafe.Pointer(ovf), uintptr(t.bucketsize)))
+		} else {
+			// This is the last preallocated overflow bucket.
+			// Reset the overflow pointer on this bucket,
+			// which was set to a non-nil sentinel value.
+			ovf.setoverflow(t, nil)
+			h.extra.nextOverflow = nil
+		}
+	} else {
+		ovf = (*bmap)(newobject(t.bucket))
+	}
 	h.incrnoverflow()
 	if t.bucket.kind&kindNoPointers != 0 {
 		h.createOverflow()
-		*h.overflow[0] = append(*h.overflow[0], ovf)
+		*h.extra.overflow[0] = append(*h.extra.overflow[0], ovf)
 	}
-	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf
+	b.setoverflow(t, ovf)
+	return ovf
 }
 
 func (h *hmap) createOverflow() {
-	if h.overflow == nil {
-		h.overflow = new([2]*[]*bmap)
+	if h.extra == nil {
+		h.extra = new(mapextra)
 	}
-	if h.overflow[0] == nil {
-		h.overflow[0] = new([]*bmap)
+	if h.extra.overflow[0] == nil {
+		h.extra.overflow[0] = new([]*bmap)
 	}
 }
 
@@ -225,9 +255,8 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 		throw("bad hmap size")
 	}
 
-	if hint < 0 || int64(int32(hint)) != hint {
-		panic(plainError("makemap: size out of range"))
-		// TODO: make hint an int, then none of this nonsense
+	if hint < 0 || hint > int64(maxSliceCap(t.bucket.size)) {
+		hint = 0
 	}
 
 	if !ismapkey(t.key) {
@@ -277,8 +306,14 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	// if B == 0, the buckets field is allocated lazily later (in mapassign)
 	// If hint is large zeroing this memory could take a while.
 	buckets := bucket
+	var extra *mapextra
 	if B != 0 {
-		buckets = newarray(t.bucket, 1<<B)
+		var nextOverflow *bmap
+		buckets, nextOverflow = makeBucketArray(t, B)
+		if nextOverflow != nil {
+			extra = new(mapextra)
+			extra.nextOverflow = nextOverflow
+		}
 	}
 
 	// initialize Hmap
@@ -287,6 +322,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	}
 	h.count = 0
 	h.B = B
+	h.extra = extra
 	h.flags = 0
 	h.hash0 = fastrand()
 	h.buckets = buckets
@@ -498,11 +534,13 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map writes")
 	}
-	h.flags |= hashWriting
-
 	alg := t.key.alg
 	hash := alg.hash(key, uintptr(h.hash0))
 
+	// Set hashWriting after calling alg.hash, since alg.hash may panic,
+	// in which case we have not actually done a write.
+	h.flags |= hashWriting
+
 	if h.buckets == nil {
 		h.buckets = newarray(t.bucket, 1)
 	}
@@ -563,8 +601,7 @@ again:
 
 	if inserti == nil {
 		// all current buckets are full, allocate a new one.
-		newb := (*bmap)(newobject(t.bucket))
-		h.setoverflow(t, b, newb)
+		newb := h.newoverflow(t, b)
 		inserti = &newb.tophash[0]
 		insertk = add(unsafe.Pointer(newb), dataOffset)
 		val = add(insertk, bucketCnt*uintptr(t.keysize))
@@ -611,10 +648,14 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map writes")
 	}
-	h.flags |= hashWriting
 
 	alg := t.key.alg
 	hash := alg.hash(key, uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash, since alg.hash may panic,
+	// in which case we have not actually done a write (delete).
+	h.flags |= hashWriting
+
 	bucket := hash & (uintptr(1)<<h.B - 1)
 	if h.growing() {
 		growWork(t, h, bucket)
@@ -702,7 +743,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 		// the table grows and/or overflow buckets are added to the table
 		// while we are iterating.
 		h.createOverflow()
-		it.overflow = *h.overflow
+		it.overflow = h.extra.overflow
 	}
 
 	// decide where to start
@@ -867,6 +908,36 @@ next:
 	goto next
 }
 
+func makeBucketArray(t *maptype, b uint8) (buckets unsafe.Pointer, nextOverflow *bmap) {
+	base := uintptr(1 << b)
+	nbuckets := base
+	// For small b, overflow buckets are unlikely.
+	// Avoid the overhead of the calculation.
+	if b >= 4 {
+		// Add on the estimated number of overflow buckets
+		// required to insert the median number of elements
+		// used with this value of b.
+		nbuckets += 1 << (b - 4)
+		sz := t.bucket.size * nbuckets
+		up := roundupsize(sz)
+		if up != sz {
+			nbuckets = up / t.bucket.size
+		}
+	}
+	buckets = newarray(t.bucket, int(nbuckets))
+	if base != nbuckets {
+		// We preallocated some overflow buckets.
+		// To keep the overhead of tracking these overflow buckets to a minimum,
+		// we use the convention that if a preallocated overflow bucket's overflow
+		// pointer is nil, then there are more available by bumping the pointer.
+		// We need a safe non-nil pointer for the last overflow bucket; just use buckets.
+		nextOverflow = (*bmap)(add(buckets, base*uintptr(t.bucketsize)))
+		last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.bucketsize)))
+		last.setoverflow(t, (*bmap)(buckets))
+	}
+	return buckets, nextOverflow
+}
+
 func hashGrow(t *maptype, h *hmap) {
 	// If we've hit the load factor, get bigger.
 	// Otherwise, there are too many overflow buckets,
@@ -877,7 +948,8 @@ func hashGrow(t *maptype, h *hmap) {
 		h.flags |= sameSizeGrow
 	}
 	oldbuckets := h.buckets
-	newbuckets := newarray(t.bucket, 1<<(h.B+bigger))
+	newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger)
+
 	flags := h.flags &^ (iterator | oldIterator)
 	if h.flags&iterator != 0 {
 		flags |= oldIterator
@@ -890,13 +962,19 @@ func hashGrow(t *maptype, h *hmap) {
 	h.nevacuate = 0
 	h.noverflow = 0
 
-	if h.overflow != nil {
+	if h.extra != nil && h.extra.overflow[0] != nil {
 		// Promote current overflow buckets to the old generation.
-		if h.overflow[1] != nil {
+		if h.extra.overflow[1] != nil {
 			throw("overflow is not nil")
 		}
-		h.overflow[1] = h.overflow[0]
-		h.overflow[0] = nil
+		h.extra.overflow[1] = h.extra.overflow[0]
+		h.extra.overflow[0] = nil
+	}
+	if nextOverflow != nil {
+		if h.extra == nil {
+			h.extra = new(mapextra)
+		}
+		h.extra.nextOverflow = nextOverflow
 	}
 
 	// the actual copying of the hash table data is done incrementally
@@ -906,7 +984,7 @@ func hashGrow(t *maptype, h *hmap) {
 // overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor.
 func overLoadFactor(count int64, B uint8) bool {
 	// TODO: rewrite to use integer math and comparison?
-	return count >= bucketCnt && float32(count) >= loadFactor*float32((uintptr(1)<<B))
+	return count >= bucketCnt && float32(count) >= loadFactor*float32((uint64(1)<<B))
 }
 
 // tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<<B buckets.
@@ -958,6 +1036,11 @@ func growWork(t *maptype, h *hmap, bucket uintptr) {
 	}
 }
 
+func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool {
+	b := (*bmap)(add(h.oldbuckets, bucket*uintptr(t.bucketsize)))
+	return evacuated(b)
+}
+
 func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 	b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
 	newbit := h.noldbuckets()
@@ -1034,8 +1117,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				if useX {
 					b.tophash[i] = evacuatedX
 					if xi == bucketCnt {
-						newx := (*bmap)(newobject(t.bucket))
-						h.setoverflow(t, x, newx)
+						newx := h.newoverflow(t, x)
 						x = newx
 						xi = 0
 						xk = add(unsafe.Pointer(x), dataOffset)
@@ -1058,8 +1140,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				} else {
 					b.tophash[i] = evacuatedY
 					if yi == bucketCnt {
-						newy := (*bmap)(newobject(t.bucket))
-						h.setoverflow(t, y, newy)
+						newy := h.newoverflow(t, y)
 						y = newy
 						yi = 0
 						yk = add(unsafe.Pointer(y), dataOffset)
@@ -1098,14 +1179,23 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 	// Advance evacuation mark
 	if oldbucket == h.nevacuate {
 		h.nevacuate = oldbucket + 1
-		if oldbucket+1 == newbit { // newbit == # of oldbuckets
+		// Experiments suggest that 1024 is overkill by at least an order of magnitude.
+		// Put it in there as a safeguard anyway, to ensure O(1) behavior.
+		stop := h.nevacuate + 1024
+		if stop > newbit {
+			stop = newbit
+		}
+		for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) {
+			h.nevacuate++
+		}
+		if h.nevacuate == newbit { // newbit == # of oldbuckets
 			// Growing is all done. Free old main bucket array.
 			h.oldbuckets = nil
 			// Can discard old overflow buckets as well.
 			// If they are still referenced by an iterator,
 			// then the iterator holds a pointers to the slice.
-			if h.overflow != nil {
-				h.overflow[1] = nil
+			if h.extra != nil {
+				h.extra.overflow[1] = nil
 			}
 			h.flags &^= sameSizeGrow
 		}
@@ -1119,8 +1209,8 @@ func ismapkey(t *_type) bool {
 // Reflect stubs. Called from ../reflect/asm_*.s
 
 //go:linkname reflect_makemap reflect.makemap
-func reflect_makemap(t *maptype) *hmap {
-	return makemap(t, 0, nil, nil)
+func reflect_makemap(t *maptype, cap int) *hmap {
+	return makemap(t, int64(cap), nil, nil)
 }
 
 //go:linkname reflect_mapaccess reflect.mapaccess
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index b5ecc2d..1f9b313 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -45,7 +45,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
 			if k != key {
 				continue
 			}
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -94,7 +94,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
 			if k != key {
 				continue
 			}
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -143,7 +143,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
 			if k != key {
 				continue
 			}
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -192,7 +192,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
 			if k != key {
 				continue
 			}
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -223,7 +223,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 		if key.len < 32 {
 			// short key, doing lots of comparisons is ok
 			for i := uintptr(0); i < bucketCnt; i++ {
-				x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+				x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 				if x == empty {
 					continue
 				}
@@ -240,7 +240,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 		// long key, try not to do more comparisons than necessary
 		keymaybe := uintptr(bucketCnt)
 		for i := uintptr(0); i < bucketCnt; i++ {
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -252,8 +252,6 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 				return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
 			}
 			// check first 4 bytes
-			// TODO: on amd64/386 at least, make this compile to one 4-byte comparison instead of
-			// four 1-byte comparisons.
 			if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
 				continue
 			}
@@ -295,7 +293,7 @@ dohash:
 	}
 	for {
 		for i := uintptr(0); i < bucketCnt; i++ {
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x != top {
 				continue
 			}
@@ -332,7 +330,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 		if key.len < 32 {
 			// short key, doing lots of comparisons is ok
 			for i := uintptr(0); i < bucketCnt; i++ {
-				x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+				x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 				if x == empty {
 					continue
 				}
@@ -349,7 +347,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 		// long key, try not to do more comparisons than necessary
 		keymaybe := uintptr(bucketCnt)
 		for i := uintptr(0); i < bucketCnt; i++ {
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x == empty {
 				continue
 			}
@@ -402,7 +400,7 @@ dohash:
 	}
 	for {
 		for i := uintptr(0); i < bucketCnt; i++ {
-			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+			x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check
 			if x != top {
 				continue
 			}
@@ -420,3 +418,441 @@ dohash:
 		}
 	}
 }
+
+func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
+	if h == nil {
+		panic(plainError("assignment to entry in nil map"))
+	}
+	if raceenabled {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32))
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapassign.
+	h.flags |= hashWriting
+
+	if h.buckets == nil {
+		h.buckets = newarray(t.bucket, 1)
+	}
+
+again:
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+
+	var inserti *uint8
+	var insertk unsafe.Pointer
+	var val unsafe.Pointer
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				if b.tophash[i] == empty && inserti == nil {
+					inserti = &b.tophash[i]
+					insertk = add(unsafe.Pointer(b), dataOffset+i*4)
+					val = add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
+				}
+				continue
+			}
+			k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4)))
+			if k != key {
+				continue
+			}
+			val = add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
+			goto done
+		}
+		ovf := b.overflow(t)
+		if ovf == nil {
+			break
+		}
+		b = ovf
+	}
+
+	// Did not find mapping for key. Allocate new cell & add entry.
+
+	// If we hit the max load factor or we have too many overflow buckets,
+	// and we're not already in the middle of growing, start growing.
+	if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
+		hashGrow(t, h)
+		goto again // Growing the table invalidates everything, so try again
+	}
+
+	if inserti == nil {
+		// all current buckets are full, allocate a new one.
+		newb := h.newoverflow(t, b)
+		inserti = &newb.tophash[0]
+		insertk = add(unsafe.Pointer(newb), dataOffset)
+		val = add(insertk, bucketCnt*4)
+	}
+
+	// store new key/value at insert position
+	*((*uint32)(insertk)) = key
+	*inserti = top
+	h.count++
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+	return val
+}
+
+func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
+	if h == nil {
+		panic(plainError("assignment to entry in nil map"))
+	}
+	if raceenabled {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64))
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapassign.
+	h.flags |= hashWriting
+
+	if h.buckets == nil {
+		h.buckets = newarray(t.bucket, 1)
+	}
+
+again:
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+
+	var inserti *uint8
+	var insertk unsafe.Pointer
+	var val unsafe.Pointer
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				if b.tophash[i] == empty && inserti == nil {
+					inserti = &b.tophash[i]
+					insertk = add(unsafe.Pointer(b), dataOffset+i*8)
+					val = add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
+				}
+				continue
+			}
+			k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8)))
+			if k != key {
+				continue
+			}
+			val = add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
+			goto done
+		}
+		ovf := b.overflow(t)
+		if ovf == nil {
+			break
+		}
+		b = ovf
+	}
+
+	// Did not find mapping for key. Allocate new cell & add entry.
+
+	// If we hit the max load factor or we have too many overflow buckets,
+	// and we're not already in the middle of growing, start growing.
+	if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
+		hashGrow(t, h)
+		goto again // Growing the table invalidates everything, so try again
+	}
+
+	if inserti == nil {
+		// all current buckets are full, allocate a new one.
+		newb := h.newoverflow(t, b)
+		inserti = &newb.tophash[0]
+		insertk = add(unsafe.Pointer(newb), dataOffset)
+		val = add(insertk, bucketCnt*8)
+	}
+
+	// store new key/value at insert position
+	*((*uint64)(insertk)) = key
+	*inserti = top
+	h.count++
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+	return val
+}
+
+func mapassign_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
+	if h == nil {
+		panic(plainError("assignment to entry in nil map"))
+	}
+	if raceenabled {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_faststr))
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+	key := stringStructOf(&ky)
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapassign.
+	h.flags |= hashWriting
+
+	if h.buckets == nil {
+		h.buckets = newarray(t.bucket, 1)
+	}
+
+again:
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+
+	var inserti *uint8
+	var insertk unsafe.Pointer
+	var val unsafe.Pointer
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				if b.tophash[i] == empty && inserti == nil {
+					inserti = &b.tophash[i]
+					insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+					val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+				}
+				continue
+			}
+			k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+			if k.len != key.len {
+				continue
+			}
+			if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) {
+				continue
+			}
+			// already have a mapping for key. Update it.
+			val = add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
+			goto done
+		}
+		ovf := b.overflow(t)
+		if ovf == nil {
+			break
+		}
+		b = ovf
+	}
+
+	// Did not find mapping for key. Allocate new cell & add entry.
+
+	// If we hit the max load factor or we have too many overflow buckets,
+	// and we're not already in the middle of growing, start growing.
+	if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
+		hashGrow(t, h)
+		goto again // Growing the table invalidates everything, so try again
+	}
+
+	if inserti == nil {
+		// all current buckets are full, allocate a new one.
+		newb := h.newoverflow(t, b)
+		inserti = &newb.tophash[0]
+		insertk = add(unsafe.Pointer(newb), dataOffset)
+		val = add(insertk, bucketCnt*2*sys.PtrSize)
+	}
+
+	// store new key/value at insert position
+	*((*stringStruct)(insertk)) = *key
+	*inserti = top
+	h.count++
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+	return val
+}
+
+func mapdelete_fast32(t *maptype, h *hmap, key uint32) {
+	if raceenabled && h != nil {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast32))
+	}
+	if h == nil || h.count == 0 {
+		return
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapdelete
+	h.flags |= hashWriting
+
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				continue
+			}
+			k := (*uint32)(add(unsafe.Pointer(b), dataOffset+i*4))
+			if key != *k {
+				continue
+			}
+			*k = 0
+			v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*4 + i*uintptr(t.valuesize))
+			typedmemclr(t.elem, v)
+			b.tophash[i] = empty
+			h.count--
+			goto done
+		}
+		b = b.overflow(t)
+		if b == nil {
+			goto done
+		}
+	}
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+}
+
+func mapdelete_fast64(t *maptype, h *hmap, key uint64) {
+	if raceenabled && h != nil {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast64))
+	}
+	if h == nil || h.count == 0 {
+		return
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapdelete
+	h.flags |= hashWriting
+
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				continue
+			}
+			k := (*uint64)(add(unsafe.Pointer(b), dataOffset+i*8))
+			if key != *k {
+				continue
+			}
+			*k = 0
+			v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*8 + i*uintptr(t.valuesize))
+			typedmemclr(t.elem, v)
+			b.tophash[i] = empty
+			h.count--
+			goto done
+		}
+		b = b.overflow(t)
+		if b == nil {
+			goto done
+		}
+	}
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+}
+
+func mapdelete_faststr(t *maptype, h *hmap, ky string) {
+	if raceenabled && h != nil {
+		callerpc := getcallerpc(unsafe.Pointer(&t))
+		racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_faststr))
+	}
+	if h == nil || h.count == 0 {
+		return
+	}
+	if h.flags&hashWriting != 0 {
+		throw("concurrent map writes")
+	}
+
+	key := stringStructOf(&ky)
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+
+	// Set hashWriting after calling alg.hash for consistency with mapdelete
+	h.flags |= hashWriting
+
+	bucket := hash & (uintptr(1)<<h.B - 1)
+	if h.growing() {
+		growWork(t, h, bucket)
+	}
+	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
+	top := uint8(hash >> (sys.PtrSize*8 - 8))
+	if top < minTopHash {
+		top += minTopHash
+	}
+	for {
+		for i := uintptr(0); i < bucketCnt; i++ {
+			if b.tophash[i] != top {
+				continue
+			}
+			k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize))
+			if k.len != key.len {
+				continue
+			}
+			if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) {
+				continue
+			}
+			typedmemclr(t.key, unsafe.Pointer(k))
+			v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*2*sys.PtrSize + i*uintptr(t.valuesize))
+			typedmemclr(t.elem, v)
+			b.tophash[i] = empty
+			h.count--
+			goto done
+		}
+		b = b.overflow(t)
+		if b == nil {
+			goto done
+		}
+	}
+
+done:
+	if h.flags&hashWriting == 0 {
+		throw("concurrent map writes")
+	}
+	h.flags &^= hashWriting
+}
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 6039417..35f6124 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -548,7 +548,7 @@ func dumpmemstats() {
 	dumpint(memstats.gc_sys)
 	dumpint(memstats.other_sys)
 	dumpint(memstats.next_gc)
-	dumpint(memstats.last_gc)
+	dumpint(memstats.last_gc_unix)
 	dumpint(memstats.pause_total_ns)
 	for i := 0; i < 256; i++ {
 		dumpint(memstats.pause_ns[i])
@@ -565,7 +565,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
 	for i := uintptr(0); i < nstk; i++ {
 		pc := stk[i]
 		f := findfunc(pc)
-		if f == nil {
+		if !f.valid() {
 			var buf [64]byte
 			n := len(buf)
 			n--
@@ -653,7 +653,7 @@ func writeheapdump_m(fd uintptr) {
 	// Update stats so we can dump them.
 	// As a side effect, flushes all the MCaches so the MSpan.freelist
 	// lists contain all the free objects.
-	updatememstats(nil)
+	updatememstats()
 
 	// Set dump file.
 	dumpfd = fd
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 46010d5..58ed61e 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -53,7 +53,7 @@ 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 {
+				if m.bad {
 					if !canfail {
 						// this can only happen if the conversion
 						// was already done once using the , ok form
@@ -78,7 +78,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 	m._type = typ
 	additab(m, true, canfail)
 	unlock(&ifaceLock)
-	if m.bad != 0 {
+	if m.bad {
 		return nil
 	}
 	return m
@@ -130,7 +130,7 @@ func additab(m *itab, locked, canfail bool) {
 			}
 			panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
 		}
-		m.bad = 1
+		m.bad = true
 		break
 	nextimethod:
 	}
@@ -139,7 +139,7 @@ func additab(m *itab, locked, canfail bool) {
 	}
 	h := itabhash(inter, typ)
 	m.link = hash[h]
-	m.inhash = 1
+	m.inhash = true
 	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
 }
 
@@ -152,7 +152,7 @@ func itabsinit() {
 			// and thanks to the way global symbol resolution works, the
 			// pointed-to itab may already have been inserted into the
 			// global 'hash'.
-			if i.inhash == 0 {
+			if !i.inhash {
 				additab(i, true, false)
 			}
 		}
@@ -160,11 +160,11 @@ func itabsinit() {
 	unlock(&ifaceLock)
 }
 
-// panicdottype is called when doing an i.(T) conversion and the conversion fails.
+// panicdottypeE is called when doing an e.(T) conversion and the conversion fails.
 // have = the dynamic type we have.
 // want = the static type we're trying to convert to.
 // iface = the static type we're converting from.
-func panicdottype(have, want, iface *_type) {
+func panicdottypeE(have, want, iface *_type) {
 	haveString := ""
 	if have != nil {
 		haveString = have.string()
@@ -172,6 +172,16 @@ func panicdottype(have, want, iface *_type) {
 	panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
 }
 
+// panicdottypeI is called when doing an i.(T) conversion and the conversion fails.
+// Same args as panicdottypeE, but "have" is the dynamic itab we have.
+func panicdottypeI(have *itab, want, iface *_type) {
+	var t *_type
+	if have != nil {
+		t = have._type
+	}
+	panicdottypeE(t, want, iface)
+}
+
 // panicnildottype is called when doing a i.(T) conversion and the interface i is nil.
 // want = the static type we're trying to convert to.
 func panicnildottype(want *_type) {
@@ -195,19 +205,124 @@ func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
 	if msanenabled {
 		msanread(elem, t.size)
 	}
-	if isDirectIface(t) {
-		// This case is implemented directly by the compiler.
-		throw("direct convT2E")
-	}
-	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.
+	x := mallocgc(t.size, t, true)
+	// TODO: We allocate a zeroed object only to overwrite it with actual data.
+	// Figure out how to avoid zeroing. Also below in convT2Eslice, convT2I, convT2Islice.
 	typedmemmove(t, x, elem)
 	e._type = t
 	e.data = x
 	return
 }
 
+func convT2E16(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E16))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint16)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(2, t, false)
+		*(*uint16)(x) = *(*uint16)(elem)
+	}
+	e._type = t
+	e.data = x
+	return
+}
+
+func convT2E32(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E32))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint32)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(4, t, false)
+		*(*uint32)(x) = *(*uint32)(elem)
+	}
+	e._type = t
+	e.data = x
+	return
+}
+
+func convT2E64(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E64))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint64)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(8, t, false)
+		*(*uint64)(x) = *(*uint64)(elem)
+	}
+	e._type = t
+	e.data = x
+	return
+}
+
+func convT2Estring(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2Estring))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*string)(elem) == "" {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(t.size, t, true)
+		*(*string)(x) = *(*string)(elem)
+	}
+	e._type = t
+	e.data = x
+	return
+}
+
+func convT2Eslice(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2Eslice))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if v := *(*slice)(elem); uintptr(v.array) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(t.size, t, true)
+		*(*slice)(x) = *(*slice)(elem)
+	}
+	e._type = t
+	e.data = x
+	return
+}
+
+func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) {
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2Enoptr))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	x := mallocgc(t.size, t, false)
+	memmove(x, elem, t.size)
+	e._type = t
+	e.data = x
+	return
+}
+
 func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
 	t := tab._type
 	if raceenabled {
@@ -216,17 +331,128 @@ func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
 	if msanenabled {
 		msanread(elem, t.size)
 	}
-	if isDirectIface(t) {
-		// This case is implemented directly by the compiler.
-		throw("direct convT2I")
-	}
-	x := newobject(t)
+	x := mallocgc(t.size, t, true)
 	typedmemmove(t, x, elem)
 	i.tab = tab
 	i.data = x
 	return
 }
 
+func convT2I16(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I16))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint16)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(2, t, false)
+		*(*uint16)(x) = *(*uint16)(elem)
+	}
+	i.tab = tab
+	i.data = x
+	return
+}
+
+func convT2I32(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I32))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint32)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(4, t, false)
+		*(*uint32)(x) = *(*uint32)(elem)
+	}
+	i.tab = tab
+	i.data = x
+	return
+}
+
+func convT2I64(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I64))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*uint64)(elem) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(8, t, false)
+		*(*uint64)(x) = *(*uint64)(elem)
+	}
+	i.tab = tab
+	i.data = x
+	return
+}
+
+func convT2Istring(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2Istring))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if *(*string)(elem) == "" {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(t.size, t, true)
+		*(*string)(x) = *(*string)(elem)
+	}
+	i.tab = tab
+	i.data = x
+	return
+}
+
+func convT2Islice(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2Islice))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	var x unsafe.Pointer
+	if v := *(*slice)(elem); uintptr(v.array) == 0 {
+		x = unsafe.Pointer(&zeroVal[0])
+	} else {
+		x = mallocgc(t.size, t, true)
+		*(*slice)(x) = *(*slice)(elem)
+	}
+	i.tab = tab
+	i.data = x
+	return
+}
+
+func convT2Inoptr(tab *itab, elem unsafe.Pointer) (i iface) {
+	t := tab._type
+	if raceenabled {
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2Inoptr))
+	}
+	if msanenabled {
+		msanread(elem, t.size)
+	}
+	x := mallocgc(t.size, t, false)
+	memmove(x, elem, t.size)
+	i.tab = tab
+	i.data = x
+	return
+}
+
 func convI2I(inter *interfacetype, i iface) (r iface) {
 	tab := i.tab
 	if tab == nil {
@@ -313,3 +539,39 @@ func iterate_itabs(fn func(*itab)) {
 		}
 	}
 }
+
+// staticbytes is used to avoid convT2E for byte-sized values.
+var staticbytes = [...]byte{
+	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,
+}
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go
index 7f27baa..6d8f861 100644
--- a/src/runtime/iface_test.go
+++ b/src/runtime/iface_test.go
@@ -29,6 +29,20 @@ func (TM) Method2() {}
 func (TL) Method1() {}
 func (TL) Method2() {}
 
+type T8 uint8
+type T16 uint16
+type T32 uint32
+type T64 uint64
+type Tstr string
+type Tslice []byte
+
+func (T8) Method1()     {}
+func (T16) Method1()    {}
+func (T32) Method1()    {}
+func (T64) Method1()    {}
+func (Tstr) Method1()   {}
+func (Tslice) Method1() {}
+
 var (
 	e  interface{}
 	e_ interface{}
@@ -261,3 +275,129 @@ func TestNonEscapingConvT2I(t *testing.T) {
 		t.Fatalf("want 0 allocs, got %v", n)
 	}
 }
+
+func TestZeroConvT2x(t *testing.T) {
+	tests := []struct {
+		name string
+		fn   func()
+	}{
+		{name: "E8", fn: func() { e = eight8 }},  // any byte-sized value does not allocate
+		{name: "E16", fn: func() { e = zero16 }}, // zero values do not allocate
+		{name: "E32", fn: func() { e = zero32 }},
+		{name: "E64", fn: func() { e = zero64 }},
+		{name: "Estr", fn: func() { e = zerostr }},
+		{name: "Eslice", fn: func() { e = zeroslice }},
+		{name: "Econstflt", fn: func() { e = 99.0 }}, // constants do not allocate
+		{name: "Econststr", fn: func() { e = "change" }},
+		{name: "I8", fn: func() { i1 = eight8I }},
+		{name: "I16", fn: func() { i1 = zero16I }},
+		{name: "I32", fn: func() { i1 = zero32I }},
+		{name: "I64", fn: func() { i1 = zero64I }},
+		{name: "Istr", fn: func() { i1 = zerostrI }},
+		{name: "Islice", fn: func() { i1 = zerosliceI }},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			n := testing.AllocsPerRun(1000, test.fn)
+			if n != 0 {
+				t.Errorf("want zero allocs, got %v", n)
+			}
+		})
+	}
+}
+
+var (
+	eight8  uint8 = 8
+	eight8I T8    = 8
+
+	zero16  uint16 = 0
+	zero16I T16    = 0
+	one16   uint16 = 1
+
+	zero32  uint32 = 0
+	zero32I T32    = 0
+	one32   uint32 = 1
+
+	zero64  uint64 = 0
+	zero64I T64    = 0
+	one64   uint64 = 1
+
+	zerostr  string = ""
+	zerostrI Tstr   = ""
+	nzstr    string = "abc"
+
+	zeroslice  []byte = nil
+	zerosliceI Tslice = nil
+	nzslice    []byte = []byte("abc")
+
+	zerobig [512]byte
+	nzbig   [512]byte = [512]byte{511: 1}
+)
+
+func BenchmarkConvT2Ezero(b *testing.B) {
+	b.Run("zero", func(b *testing.B) {
+		b.Run("16", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zero16
+			}
+		})
+		b.Run("32", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zero32
+			}
+		})
+		b.Run("64", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zero64
+			}
+		})
+		b.Run("str", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zerostr
+			}
+		})
+		b.Run("slice", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zeroslice
+			}
+		})
+		b.Run("big", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = zerobig
+			}
+		})
+	})
+	b.Run("nonzero", func(b *testing.B) {
+		b.Run("16", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = one16
+			}
+		})
+		b.Run("32", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = one32
+			}
+		})
+		b.Run("64", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = one64
+			}
+		})
+		b.Run("str", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = nzstr
+			}
+		})
+		b.Run("slice", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = nzslice
+			}
+		})
+		b.Run("big", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				e = nzbig
+			}
+		})
+	})
+}
diff --git a/src/runtime/internal/atomic/asm_mips64x.s b/src/runtime/internal/atomic/asm_mips64x.s
index 80b178d..19d131e 100644
--- a/src/runtime/internal/atomic/asm_mips64x.s
+++ b/src/runtime/internal/atomic/asm_mips64x.s
@@ -6,12 +6,6 @@
 
 #include "textflag.h"
 
-#define LL(base, rt)	WORD	$((060<<26)|((base)<<21)|((rt)<<16))
-#define LLV(base, rt)	WORD	$((064<<26)|((base)<<21)|((rt)<<16))
-#define SC(base, rt)	WORD	$((070<<26)|((base)<<21)|((rt)<<16))
-#define SCV(base, rt)	WORD	$((074<<26)|((base)<<21)|((rt)<<16))
-#define SYNC	WORD $0xf
-
 // bool cas(uint32 *ptr, uint32 old, uint32 new)
 // Atomically:
 //	if(*val == old){
@@ -26,9 +20,9 @@ TEXT ·Cas(SB), NOSPLIT, $0-17
 	SYNC
 cas_again:
 	MOVV	R5, R3
-	LL(1, 4)	// R4 = *R1
+	LL	(R1), R4
 	BNE	R2, R4, cas_fail
-	SC(1, 3)	// *R1 = R3
+	SC	R3, (R1)
 	BEQ	R3, cas_again
 	MOVV	$1, R1
 	MOVB	R1, ret+16(FP)
@@ -53,9 +47,9 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25
 	SYNC
 cas64_again:
 	MOVV	R5, R3
-	LLV(1, 4)	// R4 = *R1
+	LLV	(R1), R4
 	BNE	R2, R4, cas64_fail
-	SCV(1, 3)	// *R1 = R3
+	SCV	R3, (R1)
 	BEQ	R3, cas64_again
 	MOVV	$1, R1
 	MOVB	R1, ret+24(FP)
@@ -104,10 +98,10 @@ TEXT ·Xadd(SB), NOSPLIT, $0-20
 	MOVV	ptr+0(FP), R2
 	MOVW	delta+8(FP), R3
 	SYNC
-	LL(2, 1)	// R1 = *R2
+	LL	(R2), R1
 	ADDU	R1, R3, R4
 	MOVV	R4, R1
-	SC(2, 4)	// *R2 = R4
+	SC	R4, (R2)
 	BEQ	R4, -4(PC)
 	MOVW	R1, ret+16(FP)
 	SYNC
@@ -117,10 +111,10 @@ TEXT ·Xadd64(SB), NOSPLIT, $0-24
 	MOVV	ptr+0(FP), R2
 	MOVV	delta+8(FP), R3
 	SYNC
-	LLV(2, 1)	// R1 = *R2
+	LLV	(R2), R1
 	ADDVU	R1, R3, R4
 	MOVV	R4, R1
-	SCV(2, 4)	// *R2 = R4
+	SCV	R4, (R2)
 	BEQ	R4, -4(PC)
 	MOVV	R1, ret+16(FP)
 	SYNC
@@ -132,8 +126,8 @@ TEXT ·Xchg(SB), NOSPLIT, $0-20
 
 	SYNC
 	MOVV	R5, R3
-	LL(2, 1)	// R1 = *R2
-	SC(2, 3)	// *R2 = R3
+	LL	(R2), R1
+	SC	R3, (R2)
 	BEQ	R3, -3(PC)
 	MOVW	R1, ret+16(FP)
 	SYNC
@@ -145,8 +139,8 @@ TEXT ·Xchg64(SB), NOSPLIT, $0-24
 
 	SYNC
 	MOVV	R5, R3
-	LLV(2, 1)	// R1 = *R2
-	SCV(2, 3)	// *R2 = R3
+	LLV	(R2), R1
+	SCV	R3, (R2)
 	BEQ	R3, -3(PC)
 	MOVV	R1, ret+16(FP)
 	SYNC
@@ -193,9 +187,9 @@ TEXT ·Or8(SB), NOSPLIT, $0-9
 	SLLV	R4, R2
 
 	SYNC
-	LL(3, 4)	// R4 = *R3
+	LL	(R3), R4
 	OR	R2, R4
-	SC(3, 4)	// *R3 = R4
+	SC	R4, (R3)
 	BEQ	R4, -4(PC)
 	SYNC
 	RET
@@ -223,9 +217,9 @@ TEXT ·And8(SB), NOSPLIT, $0-9
 	OR	R5, R2
 
 	SYNC
-	LL(3, 4)	// R4 = *R3
+	LL	(R3), R4
 	AND	R2, R4
-	SC(3, 4)	// *R3 = R4
+	SC	R4, (R3)
 	BEQ	R4, -4(PC)
 	SYNC
 	RET
diff --git a/src/runtime/internal/atomic/asm_ppc64x.s b/src/runtime/internal/atomic/asm_ppc64x.s
index aa6067e..7117aef 100644
--- a/src/runtime/internal/atomic/asm_ppc64x.s
+++ b/src/runtime/internal/atomic/asm_ppc64x.s
@@ -165,32 +165,12 @@ TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
 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.
-	// Big endian.  ptr = ptr ^ 3
-	XOR	$3, R3
-	// 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:
-	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
 
@@ -198,34 +178,11 @@ again:
 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.
-	// Big endian.  ptr = ptr ^ 3
-	XOR	$3, R3
-	// R6 = ((ptr & 3) * 8) = (ptr << 3) & (3*8)
-	RLDC	$3, R3, $(3*8), R6
-	// Shift val for aligned ptr.  R4 = val << R6 | ^(0xFF << R6)
-	MOVD	$0xFF, R7
-	SLD	R6, R4
-	SLD	R6, R7
-	XOR	$-1, R7
-	OR	R7, R4
-	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/sys/intrinsics.go b/src/runtime/internal/sys/intrinsics.go
index db2cbec..4e119b0 100644
--- a/src/runtime/internal/sys/intrinsics.go
+++ b/src/runtime/internal/sys/intrinsics.go
@@ -32,22 +32,22 @@ var deBruijnIdx32 = [32]byte{
 
 // Ctz64 counts trailing (low-order) zeroes,
 // and if all are zero, then 64.
-func Ctz64(x uint64) uint64 {
+func Ctz64(x uint64) int {
 	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
+	i := int(deBruijnIdx64[y])   // convert to bit index
+	z := int((x - 1) >> 57 & 64) // adjustment if zero
+	return i + z
 }
 
 // Ctz32 counts trailing (low-order) zeroes,
 // and if all are zero, then 32.
-func Ctz32(x uint32) uint32 {
+func Ctz32(x uint32) int {
 	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
+	i := int(deBruijnIdx32[y])   // convert to bit index
+	z := int((x - 1) >> 26 & 32) // adjustment if zero
+	return i + z
 }
 
 // Bswap64 returns its input with byte order reversed
diff --git a/src/runtime/internal/sys/intrinsics_386.s b/src/runtime/internal/sys/intrinsics_386.s
index bc63e5e..4bb4cd6 100644
--- a/src/runtime/internal/sys/intrinsics_386.s
+++ b/src/runtime/internal/sys/intrinsics_386.s
@@ -4,14 +4,12 @@
 
 #include "textflag.h"
 
-TEXT runtime∕internal∕sys·Ctz64(SB), NOSPLIT, $0-16
-	MOVL	$0, ret_hi+12(FP)
-
+TEXT runtime∕internal∕sys·Ctz64(SB), NOSPLIT, $0-12
 	// Try low 32 bits.
 	MOVL	x_lo+0(FP), AX
 	BSFL	AX, AX
 	JZ	tryhigh
-	MOVL	AX, ret_lo+8(FP)
+	MOVL	AX, ret+8(FP)
 	RET
 
 tryhigh:
@@ -20,12 +18,12 @@ tryhigh:
 	BSFL	AX, AX
 	JZ	none
 	ADDL	$32, AX
-	MOVL	AX, ret_lo+8(FP)
+	MOVL	AX, ret+8(FP)
 	RET
 
 none:
 	// No bits are set.
-	MOVL	$64, ret_lo+8(FP)
+	MOVL	$64, ret+8(FP)
 	RET
 
 TEXT runtime∕internal∕sys·Ctz32(SB), NOSPLIT, $0-8
diff --git a/src/runtime/internal/sys/intrinsics_stubs.go b/src/runtime/internal/sys/intrinsics_stubs.go
index d351048..4d991f4 100644
--- a/src/runtime/internal/sys/intrinsics_stubs.go
+++ b/src/runtime/internal/sys/intrinsics_stubs.go
@@ -6,7 +6,7 @@
 
 package sys
 
-func Ctz64(x uint64) uint64
-func Ctz32(x uint32) uint32
+func Ctz64(x uint64) int
+func Ctz32(x uint32) int
 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
index 1f2c8da..0444183 100644
--- a/src/runtime/internal/sys/intrinsics_test.go
+++ b/src/runtime/internal/sys/intrinsics_test.go
@@ -6,17 +6,17 @@ import (
 )
 
 func TestCtz64(t *testing.T) {
-	for i := uint(0); i <= 64; i++ {
-		x := uint64(5) << i
-		if got := sys.Ctz64(x); got != uint64(i) {
+	for i := 0; i <= 64; i++ {
+		x := uint64(5) << uint(i)
+		if got := sys.Ctz64(x); got != 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) {
+	for i := 0; i <= 32; i++ {
+		x := uint32(5) << uint(i)
+		if got := sys.Ctz32(x); got != i {
 			t.Errorf("Ctz32(%d)=%d, want %d", x, got, i)
 		}
 	}
diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go
index 8e33ce1..4787c5b 100644
--- a/src/runtime/lfstack.go
+++ b/src/runtime/lfstack.go
@@ -3,10 +3,6 @@
 // license that can be found in the LICENSE file.
 
 // Lock-free 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,32 +11,47 @@ import (
 	"unsafe"
 )
 
-func lfstackpush(head *uint64, node *lfnode) {
+// lfstack is the head of a lock-free stack.
+//
+// The zero value of lfstack is an empty list.
+//
+// This stack is intrusive. Nodes must embed lfnode as the first field.
+//
+// The stack does not keep GC-visible pointers to nodes, so the caller
+// is responsible for ensuring the nodes are not garbage collected
+// (typically by allocating them from manually-managed memory).
+type lfstack uint64
+
+func (head *lfstack) push(node *lfnode) {
 	node.pushcnt++
 	new := lfstackPack(node, node.pushcnt)
 	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")
+		print("runtime: lfstack.push invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n")
+		throw("lfstack.push")
 	}
 	for {
-		old := atomic.Load64(head)
+		old := atomic.Load64((*uint64)(head))
 		node.next = old
-		if atomic.Cas64(head, old, new) {
+		if atomic.Cas64((*uint64)(head), old, new) {
 			break
 		}
 	}
 }
 
-func lfstackpop(head *uint64) unsafe.Pointer {
+func (head *lfstack) pop() unsafe.Pointer {
 	for {
-		old := atomic.Load64(head)
+		old := atomic.Load64((*uint64)(head))
 		if old == 0 {
 			return nil
 		}
 		node := lfstackUnpack(old)
 		next := atomic.Load64(&node.next)
-		if atomic.Cas64(head, old, next) {
+		if atomic.Cas64((*uint64)(head), old, next) {
 			return unsafe.Pointer(node)
 		}
 	}
 }
+
+func (head *lfstack) empty() bool {
+	return atomic.Load64((*uint64)(head)) == 0
+}
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index 073136a..9d55bd1 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -38,6 +38,7 @@ const (
 // affect mutex's state.
 
 // We use the uintptr mutex.key and note.key as a uint32.
+//go:nosplit
 func key32(p *uintptr) *uint32 {
 	return (*uint32)(unsafe.Pointer(p))
 }
@@ -140,9 +141,17 @@ func notesleep(n *note) {
 	if gp != gp.m.g0 {
 		throw("notesleep not on g0")
 	}
+	ns := int64(-1)
+	if *cgo_yield != nil {
+		// Sleep for an arbitrary-but-moderate interval to poll libc interceptors.
+		ns = 10e6
+	}
 	for atomic.Load(key32(&n.key)) == 0 {
 		gp.m.blocked = true
-		futexsleep(key32(&n.key), 0, -1)
+		futexsleep(key32(&n.key), 0, ns)
+		if *cgo_yield != nil {
+			asmcgocall(*cgo_yield, nil)
+		}
 		gp.m.blocked = false
 	}
 }
@@ -156,9 +165,16 @@ func notetsleep_internal(n *note, ns int64) bool {
 	gp := getg()
 
 	if ns < 0 {
+		if *cgo_yield != nil {
+			// Sleep for an arbitrary-but-moderate interval to poll libc interceptors.
+			ns = 10e6
+		}
 		for atomic.Load(key32(&n.key)) == 0 {
 			gp.m.blocked = true
-			futexsleep(key32(&n.key), 0, -1)
+			futexsleep(key32(&n.key), 0, ns)
+			if *cgo_yield != nil {
+				asmcgocall(*cgo_yield, nil)
+			}
 			gp.m.blocked = false
 		}
 		return true
@@ -170,8 +186,14 @@ func notetsleep_internal(n *note, ns int64) bool {
 
 	deadline := nanotime() + ns
 	for {
+		if *cgo_yield != nil && ns > 10e6 {
+			ns = 10e6
+		}
 		gp.m.blocked = true
 		futexsleep(key32(&n.key), 0, ns)
+		if *cgo_yield != nil {
+			asmcgocall(*cgo_yield, nil)
+		}
 		gp.m.blocked = false
 		if atomic.Load(key32(&n.key)) != 0 {
 			break
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index 0fa0481..5b0169d 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -163,7 +163,16 @@ func notesleep(n *note) {
 	}
 	// Queued. Sleep.
 	gp.m.blocked = true
-	semasleep(-1)
+	if *cgo_yield == nil {
+		semasleep(-1)
+	} else {
+		// Sleep for an arbitrary-but-moderate interval to poll libc interceptors.
+		const ns = 10e6
+		for atomic.Loaduintptr(&n.key) == 0 {
+			semasleep(ns)
+			asmcgocall(*cgo_yield, nil)
+		}
+	}
 	gp.m.blocked = false
 }
 
@@ -186,7 +195,15 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 	if ns < 0 {
 		// Queued. Sleep.
 		gp.m.blocked = true
-		semasleep(-1)
+		if *cgo_yield == nil {
+			semasleep(-1)
+		} else {
+			// Sleep in arbitrary-but-moderate intervals to poll libc interceptors.
+			const ns = 10e6
+			for semasleep(ns) < 0 {
+				asmcgocall(*cgo_yield, nil)
+			}
+		}
 		gp.m.blocked = false
 		return true
 	}
@@ -195,12 +212,18 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 	for {
 		// Registered. Sleep.
 		gp.m.blocked = true
+		if *cgo_yield != nil && ns > 10e6 {
+			ns = 10e6
+		}
 		if semasleep(ns) >= 0 {
 			gp.m.blocked = false
 			// Acquired semaphore, semawakeup unregistered us.
 			// Done.
 			return true
 		}
+		if *cgo_yield != nil {
+			asmcgocall(*cgo_yield, nil)
+		}
 		gp.m.blocked = false
 		// Interrupted or timed out. Still registered. Semaphore not acquired.
 		ns = deadline - nanotime()
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 6f07731..8850659 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -111,7 +111,7 @@ const (
 
 	// Tiny allocator parameters, see "Tiny allocator" comment in malloc.go.
 	_TinySize      = 16
-	_TinySizeClass = 2
+	_TinySizeClass = int8(2)
 
 	_FixAllocChunk  = 16 << 10               // Chunk size for FixAlloc
 	_MaxMHeapList   = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap.
@@ -148,7 +148,11 @@ const (
 	_MHeapMap_TotalBits = (_64bit*sys.GoosWindows)*35 + (_64bit*(1-sys.GoosWindows)*(1-sys.GoosDarwin*sys.GoarchArm64))*39 + sys.GoosDarwin*sys.GoarchArm64*31 + (1-_64bit)*(32-(sys.GoarchMips+sys.GoarchMipsle))
 	_MHeapMap_Bits      = _MHeapMap_TotalBits - _PageShift
 
-	_MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
+	// _MaxMem is the maximum heap arena size minus 1.
+	//
+	// On 32-bit, this is also the maximum heap pointer value,
+	// since the arena starts at address 0.
+	_MaxMem = 1<<_MHeapMap_TotalBits - 1
 
 	// Max number of threads to run garbage collection.
 	// 2, 3, and 4 are all plausible maximums depending
@@ -156,8 +160,6 @@ const (
 	// collector scales well to 32 cpus.
 	_MaxGcproc = 32
 
-	_MaxArena32 = 1<<32 - 1
-
 	// minLegalPointer is the smallest possible legal pointer.
 	// This is the smallest possible architectural page size,
 	// since we assume that the first page is never mapped.
@@ -238,18 +240,21 @@ func mallocinit() {
 		throw("bad system page size")
 	}
 
-	var p, bitmapSize, spansSize, pSize, limit uintptr
+	// The auxiliary regions start at p and are laid out in the
+	// following order: spans, bitmap, arena.
+	var p, pSize uintptr
 	var reserved bool
 
-	// limit = runtime.memlimit();
-	// See https://golang.org/issue/5049
-	// TODO(rsc): Fix after 1.1.
-	limit = 0
+	// The spans array holds one *mspan per _PageSize of arena.
+	var spansSize uintptr = (_MaxMem + 1) / _PageSize * sys.PtrSize
+	spansSize = round(spansSize, _PageSize)
+	// The bitmap holds 2 bits per word of arena.
+	var bitmapSize uintptr = (_MaxMem + 1) / (sys.PtrSize * 8 / 2)
+	bitmapSize = round(bitmapSize, _PageSize)
 
 	// 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 2 bits per allocated word.
-	if sys.PtrSize == 8 && (limit == 0 || limit > 1<<30) {
+	// allocated data will be found.
+	if sys.PtrSize == 8 {
 		// On a 64-bit machine, allocate from a single contiguous reservation.
 		// 512 GB (MaxMem) should be big enough for now.
 		//
@@ -280,9 +285,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 / 2)
-		spansSize = arenaSize / _PageSize * sys.PtrSize
-		spansSize = round(spansSize, _PageSize)
+		pSize = bitmapSize + spansSize + arenaSize + _PageSize
 		for i := 0; i <= 0x7f; i++ {
 			switch {
 			case GOARCH == "arm64" && GOOS == "darwin":
@@ -292,7 +295,6 @@ func mallocinit() {
 			default:
 				p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
 			}
-			pSize = bitmapSize + spansSize + arenaSize + _PageSize
 			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
 			if p != 0 {
 				break
@@ -310,6 +312,15 @@ func mallocinit() {
 		// When that gets used up, we'll start asking the kernel
 		// for any memory anywhere.
 
+		// We want to start the arena low, but if we're linked
+		// against C code, it's possible global constructors
+		// have called malloc and adjusted the process' brk.
+		// Query the brk so we can avoid trying to map the
+		// arena over it (which will cause the kernel to put
+		// the arena somewhere else, likely at a high
+		// address).
+		procBrk := sbrk0()
+
 		// 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.
@@ -323,15 +334,6 @@ func mallocinit() {
 		}
 
 		for _, arenaSize := range arenaSizes {
-			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
-				spansSize = arenaSize / _PageSize * sys.PtrSize
-			}
-			spansSize = round(spansSize, _PageSize)
-
 			// SysReserve treats the address we ask for, end, as a hint,
 			// not as an absolute requirement. If we ask for the end
 			// of the data segment but the operating system requires
@@ -343,6 +345,12 @@ func mallocinit() {
 			// to a MB boundary.
 			p = round(firstmoduledata.end+(1<<18), 1<<20)
 			pSize = bitmapSize + spansSize + arenaSize + _PageSize
+			if p <= procBrk && procBrk < p+pSize {
+				// Move the start above the brk,
+				// leaving some room for future brk
+				// expansion.
+				p = round(procBrk+(1<<20), 1<<20)
+			}
 			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
 			if p != 0 {
 				break
@@ -357,18 +365,22 @@ func mallocinit() {
 	// so SysReserve can give us a PageSize-unaligned pointer.
 	// To overcome this we ask for PageSize more and round up the pointer.
 	p1 := round(p, _PageSize)
+	pSize -= p1 - p
 
 	spansStart := p1
-	mheap_.bitmap = p1 + spansSize + bitmapSize
+	p1 += spansSize
+	mheap_.bitmap = p1 + bitmapSize
+	p1 += 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_start = p1
 	}
 	mheap_.arena_end = p + pSize
-	mheap_.arena_used = p1 + (spansSize + bitmapSize)
+	mheap_.arena_used = p1
+	mheap_.arena_alloc = p1
 	mheap_.arena_reserved = reserved
 
 	if mheap_.arena_start&(_PageSize-1) != 0 {
@@ -387,12 +399,18 @@ func mallocinit() {
 // 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.
+	// strandLimit is the maximum number of bytes to strand from
+	// the current arena block. If we would need to strand more
+	// than this, we fall back to sysAlloc'ing just enough for
+	// this allocation.
+	const strandLimit = 16 << 20
+
+	if n > h.arena_end-h.arena_alloc {
+		// If we haven't grown the arena to _MaxMem yet, try
+		// to reserve some more address 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-1 <= _MaxArena32 {
+		if h.arena_end <= new_end && new_end-h.arena_start-1 <= _MaxMem {
 			// TODO: It would be bad if part of the arena
 			// is reserved and part is not.
 			var reserved bool
@@ -403,46 +421,53 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 			// p can be just about anywhere in the address
 			// space, including before arena_end.
 			if p == h.arena_end {
+				// The new block is contiguous with
+				// the current block. Extend the
+				// current arena block.
 				h.arena_end = new_end
 				h.arena_reserved = reserved
-			} else if h.arena_end < p && p+p_size-h.arena_start-1 <= _MaxArena32 {
+			} else if h.arena_start <= p && p+p_size-h.arena_start-1 <= _MaxMem && h.arena_end-h.arena_alloc < strandLimit {
+				// We were able to reserve more memory
+				// within the arena space, but it's
+				// not contiguous with our previous
+				// reservation. It could be before or
+				// after our current arena_used.
+				//
 				// Keep everything page-aligned.
 				// Our pages are bigger than hardware pages.
 				h.arena_end = p + p_size
-				used := p + (-p & (_PageSize - 1))
-				h.mapBits(used)
-				h.mapSpans(used)
-				h.arena_used = used
+				p = round(p, _PageSize)
+				h.arena_alloc = p
 				h.arena_reserved = reserved
 			} else {
-				// We got a mapping, but it's not
-				// linear with our current arena, so
-				// we can't use it.
+				// We got a mapping, but either
+				//
+				// 1) It's not in the arena, so we
+				// can't use it. (This should never
+				// happen on 32-bit.)
+				//
+				// 2) We would need to discard too
+				// much of our current arena block to
+				// use it.
 				//
-				// TODO: Make it possible to allocate
-				// from this. We can't decrease
-				// arena_used, but we could introduce
-				// a new variable for the current
-				// allocation position.
-
 				// We haven't added this allocation to
 				// the stats, so subtract it from a
 				// fake stat (but avoid underflow).
+				//
+				// We'll fall back to a small sysAlloc.
 				stat := uint64(p_size)
 				sysFree(unsafe.Pointer(p), p_size, &stat)
 			}
 		}
 	}
 
-	if n <= h.arena_end-h.arena_used {
+	if n <= h.arena_end-h.arena_alloc {
 		// Keep taking from our reservation.
-		p := h.arena_used
+		p := h.arena_alloc
 		sysMap(unsafe.Pointer(p), n, h.arena_reserved, &memstats.heap_sys)
-		h.mapBits(p + n)
-		h.mapSpans(p + n)
-		h.arena_used = p + n
-		if raceenabled {
-			racemapshadow(unsafe.Pointer(p), n)
+		h.arena_alloc += n
+		if h.arena_alloc > h.arena_used {
+			h.setArenaUsed(h.arena_alloc, true)
 		}
 
 		if p&(_PageSize-1) != 0 {
@@ -452,7 +477,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 	}
 
 	// If using 64-bit, our reservation is all we have.
-	if h.arena_end-h.arena_start > _MaxArena32 {
+	if sys.PtrSize != 4 {
 		return nil
 	}
 
@@ -464,28 +489,18 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 		return nil
 	}
 
-	if p < h.arena_start || p+p_size-h.arena_start > _MaxArena32 {
-		top := ^uintptr(0)
-		if top-h.arena_start-1 > _MaxArena32 {
-			top = h.arena_start + _MaxArena32 + 1
-		}
+	if p < h.arena_start || p+p_size-h.arena_start > _MaxMem {
+		// This shouldn't be possible because _MaxMem is the
+		// whole address space on 32-bit.
+		top := uint64(h.arena_start) + _MaxMem
 		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)
 		return nil
 	}
 
-	p_end := p + p_size
 	p += -p & (_PageSize - 1)
 	if p+n > h.arena_used {
-		h.mapBits(p + n)
-		h.mapSpans(p + n)
-		h.arena_used = p + n
-		if p_end > h.arena_end {
-			h.arena_end = p_end
-		}
-		if raceenabled {
-			racemapshadow(unsafe.Pointer(p), n)
-		}
+		h.setArenaUsed(p+n, true)
 	}
 
 	if p&(_PageSize-1) != 0 {
@@ -508,7 +523,7 @@ func nextFreeFast(s *mspan) gclinkptr {
 			if freeidx%64 == 0 && freeidx != s.nelems {
 				return 0
 			}
-			s.allocCache >>= (theBit + 1)
+			s.allocCache >>= uint(theBit + 1)
 			s.freeindex = freeidx
 			v := gclinkptr(result*s.elemsize + s.base())
 			s.allocCount++
@@ -524,8 +539,8 @@ func nextFreeFast(s *mspan) gclinkptr {
 // 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 uint8) (v gclinkptr, s *mspan, shouldhelpgc bool) {
-	s = c.alloc[sizeclass]
+func (c *mcache) nextFree(spc spanClass) (v gclinkptr, s *mspan, shouldhelpgc bool) {
+	s = c.alloc[spc]
 	shouldhelpgc = false
 	freeIndex := s.nextFreeIndex()
 	if freeIndex == s.nelems {
@@ -535,10 +550,10 @@ func (c *mcache) nextFree(sizeclass uint8) (v gclinkptr, s *mspan, shouldhelpgc
 			throw("s.allocCount != s.nelems && freeIndex == s.nelems")
 		}
 		systemstack(func() {
-			c.refill(int32(sizeclass))
+			c.refill(spc)
 		})
 		shouldhelpgc = true
-		s = c.alloc[sizeclass]
+		s = c.alloc[spc]
 
 		freeIndex = s.nextFreeIndex()
 	}
@@ -662,10 +677,10 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 				return x
 			}
 			// Allocate a new maxTinySize block.
-			span := c.alloc[tinySizeClass]
+			span := c.alloc[tinySpanClass]
 			v := nextFreeFast(span)
 			if v == 0 {
-				v, _, shouldhelpgc = c.nextFree(tinySizeClass)
+				v, _, shouldhelpgc = c.nextFree(tinySpanClass)
 			}
 			x = unsafe.Pointer(v)
 			(*[2]uint64)(x)[0] = 0
@@ -685,10 +700,11 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 				sizeclass = size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]
 			}
 			size = uintptr(class_to_size[sizeclass])
-			span := c.alloc[sizeclass]
+			spc := makeSpanClass(sizeclass, noscan)
+			span := c.alloc[spc]
 			v := nextFreeFast(span)
 			if v == 0 {
-				v, span, shouldhelpgc = c.nextFree(sizeclass)
+				v, span, shouldhelpgc = c.nextFree(spc)
 			}
 			x = unsafe.Pointer(v)
 			if needzero && span.needzero != 0 {
@@ -699,7 +715,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 		var s *mspan
 		shouldhelpgc = true
 		systemstack(func() {
-			s = largeAlloc(size, needzero)
+			s = largeAlloc(size, needzero, noscan)
 		})
 		s.freeindex = 1
 		s.allocCount = 1
@@ -708,9 +724,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 	}
 
 	var scanSize uintptr
-	if noscan {
-		heapBitsSetTypeNoScan(uintptr(x))
-	} else {
+	if !noscan {
 		// If allocating a defer+arg block, now that we've picked a malloc size
 		// large enough to hold everything, cut the "asked for" size down to
 		// just the defer header, so that the GC bitmap will record the arg block
@@ -781,14 +795,16 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 		assistG.gcAssistBytes -= int64(size - dataSize)
 	}
 
-	if shouldhelpgc && gcShouldStart(false) {
-		gcStart(gcBackgroundMode, false)
+	if shouldhelpgc {
+		if t := (gcTrigger{kind: gcTriggerHeap}); t.test() {
+			gcStart(gcBackgroundMode, t)
+		}
 	}
 
 	return x
 }
 
-func largeAlloc(size uintptr, needzero bool) *mspan {
+func largeAlloc(size uintptr, needzero bool, noscan bool) *mspan {
 	// print("largeAlloc size=", size, "\n")
 
 	if size+_PageSize < size {
@@ -804,7 +820,7 @@ func largeAlloc(size uintptr, needzero bool) *mspan {
 	// pays the debt down to npage pages.
 	deductSweepCredit(npages*_PageSize, npages)
 
-	s := mheap_.alloc(npages, 0, true, needzero)
+	s := mheap_.alloc(npages, makeSpanClass(0, noscan), true, needzero)
 	if s == nil {
 		throw("out of memory")
 	}
@@ -894,7 +910,7 @@ func nextSampleNoFP() int32 {
 		rate = 0x3fffffff
 	}
 	if rate != 0 {
-		return int32(int(fastrand()) % (2 * rate))
+		return int32(fastrand() % uint32(2*rate))
 	}
 	return 0
 }
diff --git a/src/runtime/malloc_test.go b/src/runtime/malloc_test.go
index 0cf9cfb..d9487ee 100644
--- a/src/runtime/malloc_test.go
+++ b/src/runtime/malloc_test.go
@@ -6,6 +6,8 @@ package runtime_test
 
 import (
 	"flag"
+	"fmt"
+	"reflect"
 	. "runtime"
 	"testing"
 	"time"
@@ -20,24 +22,62 @@ func TestMemStats(t *testing.T) {
 	st := new(MemStats)
 	ReadMemStats(st)
 
-	// Everything except HeapReleased, HeapIdle, and NumGC,
-	// because they indeed can be 0.
-	if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 ||
-		st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 ||
-		st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 ||
-		st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 ||
-		st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 ||
-		st.NextGC == 0 || st.NumForcedGC == 0 {
-		t.Fatalf("Zero value: %+v", *st)
+	nz := func(x interface{}) error {
+		if x != reflect.Zero(reflect.TypeOf(x)).Interface() {
+			return nil
+		}
+		return fmt.Errorf("zero value")
+	}
+	le := func(thresh float64) func(interface{}) error {
+		return func(x interface{}) error {
+			if reflect.ValueOf(x).Convert(reflect.TypeOf(thresh)).Float() < thresh {
+				return nil
+			}
+			return fmt.Errorf("insanely high value (overflow?); want <= %v", thresh)
+		}
+	}
+	eq := func(x interface{}) func(interface{}) error {
+		return func(y interface{}) error {
+			if x == y {
+				return nil
+			}
+			return fmt.Errorf("want %v", x)
+		}
+	}
+	// Of the uint fields, HeapReleased, HeapIdle can be 0.
+	// PauseTotalNs can be 0 if timer resolution is poor.
+	//
+	// TODO: Test that GCCPUFraction is <= 0.99. This currently
+	// fails on windows/386. (Issue #19319)
+	fields := map[string][]func(interface{}) error{
+		"Alloc": {nz, le(1e10)}, "TotalAlloc": {nz, le(1e11)}, "Sys": {nz, le(1e10)},
+		"Lookups": {nz, le(1e10)}, "Mallocs": {nz, le(1e10)}, "Frees": {nz, le(1e10)},
+		"HeapAlloc": {nz, le(1e10)}, "HeapSys": {nz, le(1e10)}, "HeapIdle": {le(1e10)},
+		"HeapInuse": {nz, le(1e10)}, "HeapReleased": {le(1e10)}, "HeapObjects": {nz, le(1e10)},
+		"StackInuse": {nz, le(1e10)}, "StackSys": {nz, le(1e10)},
+		"MSpanInuse": {nz, le(1e10)}, "MSpanSys": {nz, le(1e10)},
+		"MCacheInuse": {nz, le(1e10)}, "MCacheSys": {nz, le(1e10)},
+		"BuckHashSys": {nz, le(1e10)}, "GCSys": {nz, le(1e10)}, "OtherSys": {nz, le(1e10)},
+		"NextGC": {nz, le(1e10)}, "LastGC": {nz},
+		"PauseTotalNs": {le(1e11)}, "PauseNs": nil, "PauseEnd": nil,
+		"NumGC": {nz, le(1e9)}, "NumForcedGC": {nz, le(1e9)},
+		"GCCPUFraction": nil, "EnableGC": {eq(true)}, "DebugGC": {eq(false)},
+		"BySize": nil,
 	}
 
-	if st.Alloc > 1e10 || st.TotalAlloc > 1e11 || st.Sys > 1e10 || st.Lookups > 1e10 ||
-		st.Mallocs > 1e10 || st.Frees > 1e10 || st.HeapAlloc > 1e10 || st.HeapSys > 1e10 ||
-		st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
-		st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
-		st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
-		st.NextGC > 1e10 || st.NumGC > 1e9 || st.NumForcedGC > 1e9 || st.PauseTotalNs > 1e11 {
-		t.Fatalf("Insanely high value (overflow?): %+v", *st)
+	rst := reflect.ValueOf(st).Elem()
+	for i := 0; i < rst.Type().NumField(); i++ {
+		name, val := rst.Type().Field(i).Name, rst.Field(i).Interface()
+		checks, ok := fields[name]
+		if !ok {
+			t.Errorf("unknown MemStats field %s", name)
+			continue
+		}
+		for _, check := range checks {
+			if err := check(val); err != nil {
+				t.Errorf("%s = %v: %s", name, val, err)
+			}
+		}
 	}
 
 	if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index aacd091..81f05a0 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -10,6 +10,7 @@ import (
 	"reflect"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"testing"
@@ -587,6 +588,14 @@ func TestMapLargeValNoPointer(t *testing.T) {
 	}
 }
 
+// Test that making a map with a large or invalid hint
+// doesn't panic. (Issue 19926).
+func TestIgnoreBogusMapHint(t *testing.T) {
+	for _, hint := range []int64{-1, 1 << 62} {
+		_ = make(map[int]int, hint)
+	}
+}
+
 func benchmarkMapPop(b *testing.B, n int) {
 	m := map[int]int{}
 	for i := 0; i < b.N; i++ {
@@ -617,3 +626,86 @@ func TestNonEscapingMap(t *testing.T) {
 		t.Fatalf("want 0 allocs, got %v", n)
 	}
 }
+
+func benchmarkMapAssignInt32(b *testing.B, n int) {
+	a := make(map[int32]int)
+	for i := 0; i < b.N; i++ {
+		a[int32(i&(n-1))] = i
+	}
+}
+
+func benchmarkMapDeleteInt32(b *testing.B, n int) {
+	a := make(map[int32]int)
+	for i := 0; i < n*b.N; i++ {
+		a[int32(i)] = i
+	}
+	b.ResetTimer()
+	for i := 0; i < n*b.N; i = i + n {
+		delete(a, int32(i))
+	}
+}
+
+func benchmarkMapAssignInt64(b *testing.B, n int) {
+	a := make(map[int64]int)
+	for i := 0; i < b.N; i++ {
+		a[int64(i&(n-1))] = i
+	}
+}
+
+func benchmarkMapDeleteInt64(b *testing.B, n int) {
+	a := make(map[int64]int)
+	for i := 0; i < n*b.N; i++ {
+		a[int64(i)] = i
+	}
+	b.ResetTimer()
+	for i := 0; i < n*b.N; i = i + n {
+		delete(a, int64(i))
+	}
+}
+
+func benchmarkMapAssignStr(b *testing.B, n int) {
+	k := make([]string, n)
+	for i := 0; i < len(k); i++ {
+		k[i] = strconv.Itoa(i)
+	}
+	b.ResetTimer()
+	a := make(map[string]int)
+	for i := 0; i < b.N; i++ {
+		a[k[i&(n-1)]] = i
+	}
+}
+
+func benchmarkMapDeleteStr(b *testing.B, n int) {
+	k := make([]string, n*b.N)
+	for i := 0; i < n*b.N; i++ {
+		k[i] = strconv.Itoa(i)
+	}
+	a := make(map[string]int)
+	for i := 0; i < n*b.N; i++ {
+		a[k[i]] = i
+	}
+	b.ResetTimer()
+	for i := 0; i < n*b.N; i = i + n {
+		delete(a, k[i])
+	}
+}
+
+func runWith(f func(*testing.B, int), v ...int) func(*testing.B) {
+	return func(b *testing.B) {
+		for _, n := range v {
+			b.Run(strconv.Itoa(n), func(b *testing.B) { f(b, n) })
+		}
+	}
+}
+
+func BenchmarkMapAssign(b *testing.B) {
+	b.Run("Int32", runWith(benchmarkMapAssignInt32, 1<<8, 1<<16))
+	b.Run("Int64", runWith(benchmarkMapAssignInt64, 1<<8, 1<<16))
+	b.Run("Str", runWith(benchmarkMapAssignStr, 1<<8, 1<<16))
+}
+
+func BenchmarkMapDelete(b *testing.B) {
+	b.Run("Int32", runWith(benchmarkMapDeleteInt32, 1, 2, 4))
+	b.Run("Int64", runWith(benchmarkMapDeleteInt64, 1, 2, 4))
+	b.Run("Str", runWith(benchmarkMapDeleteStr, 1, 2, 4))
+}
diff --git a/src/runtime/mapspeed_test.go b/src/runtime/mapspeed_test.go
index ac93119..aec0c51 100644
--- a/src/runtime/mapspeed_test.go
+++ b/src/runtime/mapspeed_test.go
@@ -5,6 +5,7 @@ package runtime_test
 
 import (
 	"fmt"
+	"strconv"
 	"strings"
 	"testing"
 )
@@ -308,6 +309,20 @@ func BenchmarkSmallKeyMap(b *testing.B) {
 	}
 }
 
+func BenchmarkMapPopulate(b *testing.B) {
+	for size := 1; size < 1000000; size *= 10 {
+		b.Run(strconv.Itoa(size), func(b *testing.B) {
+			b.ReportAllocs()
+			for i := 0; i < b.N; i++ {
+				m := make(map[int]bool)
+				for j := 0; j < size; j++ {
+					m[j] = true
+				}
+			}
+		})
+	}
+}
+
 type ComplexAlgKey struct {
 	a, b, c int64
 	_       int
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index 5848b43..3713c50 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -149,6 +149,11 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) {
 		// combine the read and the write. Checking inheap is
 		// insufficient since we need to track changes to
 		// roots outside the heap.
+		//
+		// Note: profbuf.go omits a barrier during signal handler
+		// profile logging; that's safe only because this deletion barrier exists.
+		// If we remove the deletion barrier, we'll have to work out
+		// a new way to handle the profile logging.
 		if slot1 := uintptr(unsafe.Pointer(slot)); slot1 >= minPhysPageSize {
 			if optr := *slot; optr != 0 {
 				shade(optr)
@@ -231,6 +236,7 @@ func writebarrierptr_prewrite(dst *uintptr, src uintptr) {
 }
 
 // typedmemmove copies a value of type t to dst from src.
+// Must be nosplit, see #16026.
 //go:nosplit
 func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
 	if typ.kind&kindNoPointers == 0 {
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 9b988fa..2a9f1b8 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -45,6 +45,11 @@
 // not checkmarked, and is the dead encoding.
 // These properties must be preserved when modifying the encoding.
 //
+// The bitmap for noscan spans is not maintained. Code must ensure
+// that an object is scannable before consulting its bitmap by
+// checking either the noscan bit in the span or by consulting its
+// type's information.
+//
 // Checkmarks
 //
 // In a concurrent garbage collector, one worries about failing to mark
@@ -134,13 +139,9 @@ func subtract1(p *byte) *byte {
 	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1))
 }
 
-// mHeap_MapBits is called each time arena_used is extended.
-// It maps any additional bitmap memory needed for the new arena memory.
-// It must be called with the expected new value of arena_used,
-// *before* h.arena_used has been updated.
-// Waiting to update arena_used until after the memory has been mapped
-// avoids faults when other threads try access the bitmap immediately
-// after observing the change to arena_used.
+// mapBits maps any additional bitmap memory needed for the new arena memory.
+//
+// Don't call this directly. Call mheap.setArenaUsed.
 //
 //go:nowritebarrier
 func (h *mheap) mapBits(arena_used uintptr) {
@@ -186,10 +187,8 @@ type markBits struct {
 
 //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}
+	bytep, mask := s.allocBits.bitp(allocBitIndex)
+	return markBits{bytep, mask, allocBitIndex}
 }
 
 // refillaCache takes 8 bytes s.allocBits starting at whichByte
@@ -197,7 +196,7 @@ func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits {
 // 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)))
+	bytes := (*[8]uint8)(unsafe.Pointer(s.allocBits.bytep(whichByte)))
 	aCache := uint64(0)
 	aCache |= uint64(bytes[0])
 	aCache |= uint64(bytes[1]) << (1 * 8)
@@ -248,7 +247,7 @@ func (s *mspan) nextFreeIndex() uintptr {
 		return snelems
 	}
 
-	s.allocCache >>= (bitIndex + 1)
+	s.allocCache >>= uint(bitIndex + 1)
 	sfreeindex = result + 1
 
 	if sfreeindex%64 == 0 && sfreeindex != snelems {
@@ -269,10 +268,8 @@ func (s *mspan) isFree(index uintptr) bool {
 	if index < s.freeindex {
 		return false
 	}
-	whichByte := index / 8
-	whichBit := index % 8
-	byteVal := *addb(s.allocBits, whichByte)
-	return byteVal&uint8(1<<whichBit) == 0
+	bytep, mask := s.allocBits.bitp(index)
+	return *bytep&mask == 0
 }
 
 func (s *mspan) objIndex(p uintptr) uintptr {
@@ -294,14 +291,12 @@ func markBitsForAddr(p uintptr) markBits {
 }
 
 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}
+	bytep, mask := s.gcmarkBits.bitp(objIndex)
+	return markBits{bytep, mask, objIndex}
 }
 
 func (s *mspan) markBitsForBase() markBits {
-	return markBits{s.gcmarkBits, uint8(1), 0}
+	return markBits{(*uint8)(s.gcmarkBits), uint8(1), 0}
 }
 
 // isMarked reports whether mark bit m is set.
@@ -332,11 +327,6 @@ func (m markBits) clearMarked() {
 	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 {
@@ -401,7 +391,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 	// Consult the span table to find the block beginning.
 	s = mheap_.spans[idx]
 	if s == nil || p < s.base() || p >= s.limit || s.state != mSpanInUse {
-		if s == nil || s.state == _MSpanStack {
+		if s == nil || s.state == _MSpanManual {
 			// If s is nil, the virtual address has never been part of the heap.
 			// This pointer may be to some mmap'd region, so we allow it.
 			// Pointers into stacks are also ok, the runtime manages these explicitly.
@@ -431,6 +421,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 				print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
 				gcDumpObject("object", refBase, refOff)
 			}
+			getg().m.traceback = 2
 			throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)")
 		}
 		return
@@ -510,16 +501,6 @@ func (h heapBits) isPointer() bool {
 	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 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
-	}
-	return (*h.bitp>>h.shift)&bitScan != 0
-}
-
 // isCheckmarked reports whether the heap bits have the checkmarked bit set.
 // It must be told how large the object at h is, because the encoding of the
 // checkmark bit varies by size.
@@ -579,29 +560,9 @@ func bulkBarrierPreWrite(dst, src, size uintptr) {
 		return
 	}
 	if !inheap(dst) {
-		// If dst is on the stack and in a higher frame than the
-		// caller, we either need to execute write barriers on
-		// it (which is what happens for normal stack writes
-		// through pointers to higher frames), or we need to
-		// force the mark termination stack scan to scan the
-		// frame containing dst.
-		//
-		// Executing write barriers on dst is complicated in the
-		// general case because we either need to unwind the
-		// stack to get the stack map, or we need the type's
-		// bitmap, which may be a GC program.
-		//
-		// Hence, we opt for forcing the re-scan to scan the
-		// frame containing dst, which we can do by simply
-		// unwinding the stack barriers between the current SP
-		// and dst's frame.
 		gp := getg().m.curg
 		if gp != nil && gp.stack.lo <= dst && dst < gp.stack.hi {
-			// Run on the system stack to give it more
-			// stack space.
-			systemstack(func() {
-				gcUnwindBarriers(gp, dst)
-			})
+			// Destination is our own stack. No need for barriers.
 			return
 		}
 
@@ -849,23 +810,23 @@ var oneBitCount = [256]uint8{
 	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.
+// countAlloc returns the number of objects allocated in span s by
+// scanning the allocation bitmap.
 // TODO:(rlh) Use popcount intrinsic.
-func (s *mspan) countFree() int {
+func (s *mspan) countAlloc() int {
 	count := 0
 	maxIndex := s.nelems / 8
 	for i := uintptr(0); i < maxIndex; i++ {
-		mrkBits := *addb(s.gcmarkBits, i)
+		mrkBits := *s.gcmarkBits.bytep(i)
 		count += int(oneBitCount[mrkBits])
 	}
 	if bitsInLastByte := s.nelems % 8; bitsInLastByte != 0 {
-		mrkBits := *addb(s.gcmarkBits, maxIndex)
+		mrkBits := *s.gcmarkBits.bytep(maxIndex)
 		mask := uint8((1 << bitsInLastByte) - 1)
 		bits := mrkBits & mask
 		count += int(oneBitCount[bits])
 	}
-	return int(s.nelems) - count
+	return count
 }
 
 // heapBitsSetType records that the new allocation [x, x+size)
@@ -1086,7 +1047,9 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 					endnb += endnb
 				}
 				// Truncate to a multiple of original ptrmask.
-				endnb = maxBits / nb * nb
+				// Because nb+nb <= maxBits, nb fits in a byte.
+				// Byte division is cheaper than uintptr division.
+				endnb = uintptr(maxBits/byte(nb)) * nb
 				pbits &= 1<<endnb - 1
 				b = pbits
 				nb = endnb
@@ -1364,13 +1327,6 @@ 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 | bitScan) << h.shift
-}
-
 var debugPtrmask struct {
 	lock mutex
 	data *byte
@@ -1903,7 +1859,7 @@ func getgcmask(ep interface{}) (mask []byte) {
 		frame.sp = uintptr(p)
 		_g_ := getg()
 		gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
-		if frame.fn != nil {
+		if frame.fn.valid() {
 			f := frame.fn
 			targetpc := frame.continpc
 			if targetpc == 0 {
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
index c483310..96fb273 100644
--- a/src/runtime/mcache.go
+++ b/src/runtime/mcache.go
@@ -33,7 +33,8 @@ type mcache struct {
 	local_tinyallocs uintptr // number of tiny allocs not counted in other stats
 
 	// The rest is not accessed on every malloc.
-	alloc [_NumSizeClasses]*mspan // spans to allocate from
+
+	alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClass
 
 	stackcache [_NumStackOrders]stackfreelist
 
@@ -77,7 +78,7 @@ func allocmcache() *mcache {
 	lock(&mheap_.lock)
 	c := (*mcache)(mheap_.cachealloc.alloc())
 	unlock(&mheap_.lock)
-	for i := 0; i < _NumSizeClasses; i++ {
+	for i := range c.alloc {
 		c.alloc[i] = &emptymspan
 	}
 	c.next_sample = nextSample()
@@ -103,12 +104,12 @@ 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.
-func (c *mcache) refill(sizeclass int32) *mspan {
+func (c *mcache) refill(spc spanClass) *mspan {
 	_g_ := getg()
 
 	_g_.m.locks++
 	// Return the current cached span to the central lists.
-	s := c.alloc[sizeclass]
+	s := c.alloc[spc]
 
 	if uintptr(s.allocCount) != s.nelems {
 		throw("refill of span with free space remaining")
@@ -119,7 +120,7 @@ func (c *mcache) refill(sizeclass int32) *mspan {
 	}
 
 	// Get a new cached span from the central lists.
-	s = mheap_.central[sizeclass].mcentral.cacheSpan()
+	s = mheap_.central[spc].mcentral.cacheSpan()
 	if s == nil {
 		throw("out of memory")
 	}
@@ -128,13 +129,13 @@ func (c *mcache) refill(sizeclass int32) *mspan {
 		throw("span has no free space")
 	}
 
-	c.alloc[sizeclass] = s
+	c.alloc[spc] = s
 	_g_.m.locks--
 	return s
 }
 
 func (c *mcache) releaseAll() {
-	for i := 0; i < _NumSizeClasses; i++ {
+	for i := range c.alloc {
 		s := c.alloc[i]
 		if s != &emptymspan {
 			mheap_.central[i].mcentral.uncacheSpan(s)
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index ddcf81e..eaabcb9 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -19,14 +19,19 @@ import "runtime/internal/atomic"
 //go:notinheap
 type mcentral struct {
 	lock      mutex
-	sizeclass int32
+	spanclass spanClass
 	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)
+
+	// nmalloc is the cumulative count of objects allocated from
+	// this mcentral, assuming all spans in mcaches are
+	// fully-allocated. Written atomically, read under STW.
+	nmalloc uint64
 }
 
 // Initialize a single central free list.
-func (c *mcentral) init(sizeclass int32) {
-	c.sizeclass = sizeclass
+func (c *mcentral) init(spc spanClass) {
+	c.spanclass = spc
 	c.nonempty.init()
 	c.empty.init()
 }
@@ -34,10 +39,14 @@ func (c *mcentral) init(sizeclass int32) {
 // Allocate a span to use in an MCache.
 func (c *mcentral) cacheSpan() *mspan {
 	// Deduct credit for this span allocation and sweep if necessary.
-	spanBytes := uintptr(class_to_allocnpages[c.sizeclass]) * _PageSize
+	spanBytes := uintptr(class_to_allocnpages[c.spanclass.sizeclass()]) * _PageSize
 	deductSweepCredit(spanBytes, 0)
 
 	lock(&c.lock)
+	traceDone := false
+	if trace.enabled {
+		traceGCSweepStart()
+	}
 	sg := mheap_.sweepgen
 retry:
 	var s *mspan
@@ -87,6 +96,10 @@ retry:
 		// all subsequent ones must also be either swept or in process of sweeping
 		break
 	}
+	if trace.enabled {
+		traceGCSweepDone()
+		traceDone = true
+	}
 	unlock(&c.lock)
 
 	// Replenish central list if empty.
@@ -101,15 +114,18 @@ retry:
 	// At this point s is a non-empty span, queued at the end of the empty list,
 	// c is unlocked.
 havespan:
+	if trace.enabled && !traceDone {
+		traceGCSweepDone()
+	}
 	cap := int32((s.npages << _PageShift) / s.elemsize)
 	n := cap - int32(s.allocCount)
 	if n == 0 || s.freeindex == s.nelems || uintptr(s.allocCount) == s.nelems {
 		throw("span has no free objects")
 	}
+	// Assume all objects from this span will be allocated in the
+	// mcache. If it gets uncached, we'll adjust this.
+	atomic.Xadd64(&c.nmalloc, int64(n))
 	usedBytes := uintptr(s.allocCount) * s.elemsize
-	if usedBytes > 0 {
-		reimburseSweepCredit(usedBytes)
-	}
 	atomic.Xadd64(&memstats.heap_live, int64(spanBytes)-int64(usedBytes))
 	if trace.enabled {
 		// heap_live changed.
@@ -150,6 +166,10 @@ func (c *mcentral) uncacheSpan(s *mspan) {
 		// mCentral_CacheSpan conservatively counted
 		// unallocated slots in heap_live. Undo this.
 		atomic.Xadd64(&memstats.heap_live, -int64(n)*int64(s.elemsize))
+		// cacheSpan updated alloc assuming all objects on s
+		// were going to be allocated. Adjust for any that
+		// weren't.
+		atomic.Xadd64(&c.nmalloc, -int64(n))
 	}
 	unlock(&c.lock)
 }
@@ -205,11 +225,11 @@ func (c *mcentral) freeSpan(s *mspan, preserve bool, wasempty bool) bool {
 
 // 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])
+	npages := uintptr(class_to_allocnpages[c.spanclass.sizeclass()])
+	size := uintptr(class_to_size[c.spanclass.sizeclass()])
 	n := (npages << _PageShift) / size
 
-	s := mheap_.alloc(npages, c.sizeclass, false, true)
+	s := mheap_.alloc(npages, c.spanclass, false, true)
 	if s == nil {
 		return nil
 	}
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
index a65933f..e0d2347 100644
--- a/src/runtime/mem_bsd.go
+++ b/src/runtime/mem_bsd.go
@@ -59,6 +59,7 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
 	return p
 }
 
+const _sunosEAGAIN = 11
 const _ENOMEM = 12
 
 func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
@@ -76,7 +77,7 @@ func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
 			flags |= _MAP_FIXED
 		}
 		p := mmap(v, n, _PROT_READ|_PROT_WRITE, flags, -1, 0)
-		if uintptr(p) == _ENOMEM {
+		if uintptr(p) == _ENOMEM || (GOOS == "solaris" && uintptr(p) == _sunosEAGAIN) {
 			throw("runtime: out of memory")
 		}
 		if p != v {
@@ -87,7 +88,7 @@ func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
 	}
 
 	p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
-	if uintptr(p) == _ENOMEM {
+	if uintptr(p) == _ENOMEM || (GOOS == "solaris" && uintptr(p) == _sunosEAGAIN) {
 		throw("runtime: out of memory")
 	}
 	if p != v {
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index ef6e602..1adb26b 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -27,8 +27,8 @@ tail:
 	JBE	_5through8
 	CMPL	BX, $16
 	JBE	_9through16
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JEQ	nosse2
+	CMPB	runtime·support_sse2(SB), $1
+	JNE	nosse2
 	PXOR	X0, X0
 	CMPL	BX, $32
 	JBE	_17through32
diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s
index b712ea1..e76201b 100644
--- a/src/runtime/memmove_386.s
+++ b/src/runtime/memmove_386.s
@@ -49,8 +49,8 @@ tail:
 	JBE	move_5through8
 	CMPL	BX, $16
 	JBE	move_9through16
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JEQ	nosse2
+	CMPB	runtime·support_sse2(SB), $1
+	JNE	nosse2
 	CMPL	BX, $32
 	JBE	move_17through32
 	CMPL	BX, $64
@@ -71,8 +71,8 @@ nosse2:
  */
 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
+	CMPB	runtime·support_erms(SB), $1 // enhanced REP MOVSB/STOSB
+	JNE	fwdBy4
 
 	// Check alignment
 	MOVL	SI, AX
diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s
index c2286d3..21bf8e47 100644
--- a/src/runtime/memmove_amd64.s
+++ b/src/runtime/memmove_amd64.s
@@ -64,8 +64,8 @@ tail:
 	JBE	move_129through256
 	// TODO: use branch table and BSR to make this just a single dispatch
 
-	TESTB	$1, runtime·useRepMovs(SB)
-	JZ	avxUnaligned
+	TESTB	$1, runtime·useAVXmemmove(SB)
+	JNZ	avxUnaligned
 
 /*
  * check and set for backwards
@@ -81,8 +81,8 @@ forward:
 	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
+	CMPB	runtime·support_erms(SB), $1 // enhanced REP MOVSB/STOSB
+	JNE	fwdBy8
 
 	// Check alignment
 	MOVL	SI, AX
@@ -407,7 +407,7 @@ gobble_big_data_fwd:
 gobble_mem_fwd_loop:
 	PREFETCHNTA 0x1C0(SI)
 	PREFETCHNTA 0x280(SI)
-	// Prefetch values were choosen empirically.
+	// Prefetch values were chosen empirically.
 	// Approach for prefetch usage as in 7.6.6 of [1]
 	// [1] 64-ia-32-architectures-optimization-manual.pdf
 	// http://www.intel.ru/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 7e191d4..a8729b1 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -12,8 +12,12 @@ import (
 	"unsafe"
 )
 
+// finblock is an array of finalizers to be executed. finblocks are
+// arranged in a linked list for the finalizer queue.
+//
 // finblock is allocated from non-GC'd memory, so any heap pointers
-// must be specially handled.
+// must be specially handled. GC currently assumes that the finalizer
+// queue does not grow during marking (but it can shrink).
 //
 //go:notinheap
 type finblock struct {
@@ -71,6 +75,16 @@ var finalizer1 = [...]byte{
 }
 
 func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
+	if gcphase != _GCoff {
+		// Currently we assume that the finalizer queue won't
+		// grow during marking so we don't have to rescan it
+		// during mark termination. If we ever need to lift
+		// this assumption, we can do it by adding the
+		// necessary barriers to queuefinalizer (which it may
+		// have automatically).
+		throw("queuefinalizer during GC")
+	}
+
 	lock(&finlock)
 	if finq == nil || finq.cnt == uint32(len(finq.fin)) {
 		if finc == nil {
@@ -441,7 +455,7 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
 	}
 
 	n = s.elemsize
-	if s.sizeclass != 0 {
+	if s.spanclass.sizeclass() != 0 {
 		x = add(x, (uintptr(v)-uintptr(x))/n*n)
 	}
 	return
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
index fe4b0fc..7496671 100644
--- a/src/runtime/mfixalloc.go
+++ b/src/runtime/mfixalloc.go
@@ -29,7 +29,7 @@ type fixalloc struct {
 	first  func(arg, p unsafe.Pointer) // called first time p is returned
 	arg    unsafe.Pointer
 	list   *mlink
-	chunk  unsafe.Pointer
+	chunk  uintptr // use uintptr instead of unsafe.Pointer to avoid write barriers
 	nchunk uint32
 	inuse  uintptr // in-use bytes now
 	stat   *uint64
@@ -54,7 +54,7 @@ func (f *fixalloc) init(size uintptr, first func(arg, p unsafe.Pointer), arg uns
 	f.first = first
 	f.arg = arg
 	f.list = nil
-	f.chunk = nil
+	f.chunk = 0
 	f.nchunk = 0
 	f.inuse = 0
 	f.stat = stat
@@ -77,15 +77,15 @@ func (f *fixalloc) alloc() unsafe.Pointer {
 		return v
 	}
 	if uintptr(f.nchunk) < f.size {
-		f.chunk = persistentalloc(_FixAllocChunk, 0, f.stat)
+		f.chunk = uintptr(persistentalloc(_FixAllocChunk, 0, f.stat))
 		f.nchunk = _FixAllocChunk
 	}
 
-	v := f.chunk
+	v := unsafe.Pointer(f.chunk)
 	if f.first != nil {
 		f.first(f.arg, v)
 	}
-	f.chunk = add(f.chunk, f.size)
+	f.chunk = f.chunk + f.size
 	f.nchunk -= uint32(f.size)
 	f.inuse += f.size
 	return v
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 8f42492..22e8c31 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -178,17 +178,21 @@ func gcinit() {
 		throw("size of Workbuf is suboptimal")
 	}
 
+	// No sweep on the first cycle.
+	mheap_.sweepdone = 1
+
+	// Set a reasonable initial GC trigger.
+	memstats.triggerRatio = 7 / 8.0
+
+	// Fake a heap_marked value so it looks like a trigger at
+	// heapminimum is the appropriate growth from heap_marked.
+	// This will go into computing the initial GC goal.
+	memstats.heap_marked = uint64(float64(heapminimum) / (1 + memstats.triggerRatio))
+
+	// Set gcpercent from the environment. This will also compute
+	// and set the GC trigger and goal.
 	_ = setGCPercent(readgogc())
-	memstats.gc_trigger = heapminimum
-	// Compute the goal heap size based on the trigger:
-	//   trigger = marked * (1 + triggerRatio)
-	//   marked = trigger / (1 + triggerRatio)
-	//   goal = marked * (1 + GOGC/100)
-	//        = trigger / (1 + triggerRatio) * (1 + GOGC/100)
-	memstats.next_gc = uint64(float64(memstats.gc_trigger) / (1 + gcController.triggerRatio) * (1 + float64(gcpercent)/100))
-	if gcpercent < 0 {
-		memstats.next_gc = ^uint64(0)
-	}
+
 	work.startSema = 1
 	work.markDoneSema = 1
 }
@@ -223,12 +227,8 @@ func setGCPercent(in int32) (out int32) {
 	}
 	gcpercent = in
 	heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100
-	if gcController.triggerRatio > float64(gcpercent)/100 {
-		gcController.triggerRatio = float64(gcpercent) / 100
-	}
-	// This is either in gcinit or followed by a STW GC, both of
-	// which will reset other stats like memstats.gc_trigger and
-	// memstats.next_gc to appropriate values.
+	// Update pacing in response to gcpercent change.
+	gcSetTriggerRatio(memstats.triggerRatio)
 	unlock(&mheap_.lock)
 	return out
 }
@@ -238,7 +238,9 @@ func setGCPercent(in int32) (out int32) {
 var gcphase uint32
 
 // The compiler knows about this variable.
-// If you change it, you must change the compiler too.
+// If you change it, you must change builtin/runtime.go, too.
+// If you change the first four bytes, you must also change the write
+// barrier insertion code.
 var writeBarrier struct {
 	enabled bool    // compiler emits a check of this before calling write barrier
 	pad     [3]byte // compiler uses 32-bit load for "enabled" field
@@ -328,10 +330,10 @@ var gcMarkWorkerModeStrings = [...]string{
 // utilization between assist and background marking to be 25% of
 // GOMAXPROCS. The high-level design of this algorithm is documented
 // at https://golang.org/s/go15gcpacing.
-var gcController = gcControllerState{
-	// Initial trigger ratio guess.
-	triggerRatio: 7 / 8.0,
-}
+//
+// All fields of gcController are used only during a single mark
+// cycle.
+var gcController gcControllerState
 
 type gcControllerState struct {
 	// scanWork is the total scan work performed this cycle. This
@@ -402,14 +404,6 @@ type gcControllerState struct {
 	// beginning of each cycle.
 	fractionalUtilizationGoal float64
 
-	// triggerRatio is the heap growth ratio at which the garbage
-	// collection cycle should start. E.g., if this is 0.6, then
-	// GC should start when the live heap has reached 1.6 times
-	// the heap size marked by the previous cycle. This should be
-	// ≤ GOGC/100 so the trigger heap size is less than the goal
-	// heap size. This is updated at the end of of each cycle.
-	triggerRatio float64
-
 	_ [sys.CacheLineSize]byte
 
 	// fractionalMarkWorkersNeeded is the number of fractional
@@ -438,7 +432,7 @@ func (c *gcControllerState) startCycle() {
 	// first cycle) or may be much smaller (resulting in a large
 	// error response).
 	if memstats.gc_trigger <= heapminimum {
-		memstats.heap_marked = uint64(float64(memstats.gc_trigger) / (1 + c.triggerRatio))
+		memstats.heap_marked = uint64(float64(memstats.gc_trigger) / (1 + memstats.triggerRatio))
 	}
 
 	// Re-compute the heap goal for this cycle in case something
@@ -494,17 +488,12 @@ func (c *gcControllerState) startCycle() {
 
 // revise updates the assist ratio during the GC cycle to account for
 // improved estimates. This should be called either under STW or
-// whenever memstats.heap_scan or memstats.heap_live is updated (with
-// mheap_.lock held).
+// whenever memstats.heap_scan, memstats.heap_live, or
+// memstats.next_gc is updated (with mheap_.lock held).
 //
 // 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.
 	//
@@ -535,7 +524,7 @@ func (c *gcControllerState) revise() {
 	}
 
 	// Compute the heap distance remaining.
-	heapDistance := int64(memstats.next_gc) - int64(memstats.heap_live)
+	heapDistance := int64(memstats.next_gc) - int64(atomic.Load64(&memstats.heap_live))
 	if heapDistance <= 0 {
 		// This shouldn't happen, but if it does, avoid
 		// dividing by zero or setting the assist negative.
@@ -549,10 +538,15 @@ func (c *gcControllerState) revise() {
 	c.assistBytesPerWork = float64(heapDistance) / float64(scanWorkExpected)
 }
 
-// endCycle updates the GC controller state at the end of the
-// concurrent part of the GC cycle.
-func (c *gcControllerState) endCycle() {
-	h_t := c.triggerRatio // For debugging
+// endCycle computes the trigger ratio for the next cycle.
+func (c *gcControllerState) endCycle() float64 {
+	if work.userForced {
+		// Forced GC means this cycle didn't start at the
+		// trigger, so where it finished isn't good
+		// information about how to adjust the trigger.
+		// Just leave it where it is.
+		return memstats.triggerRatio
+	}
 
 	// Proportional response gain for the trigger controller. Must
 	// be in [0, 1]. Lower values smooth out transient effects but
@@ -581,25 +575,17 @@ func (c *gcControllerState) endCycle() {
 		utilization += float64(c.assistTime) / float64(assistDuration*int64(gomaxprocs))
 	}
 
-	triggerError := goalGrowthRatio - c.triggerRatio - utilization/gcGoalUtilization*(actualGrowthRatio-c.triggerRatio)
+	triggerError := goalGrowthRatio - memstats.triggerRatio - utilization/gcGoalUtilization*(actualGrowthRatio-memstats.triggerRatio)
 
 	// Finally, we adjust the trigger for next time by this error,
 	// damped by the proportional gain.
-	c.triggerRatio += triggerGain * triggerError
-	if c.triggerRatio < 0 {
-		// This can happen if the mutator is allocating very
-		// quickly or the GC is scanning very slowly.
-		c.triggerRatio = 0
-	} else if c.triggerRatio > goalGrowthRatio*0.95 {
-		// Ensure there's always a little margin so that the
-		// mutator assist ratio isn't infinity.
-		c.triggerRatio = goalGrowthRatio * 0.95
-	}
+	triggerRatio := memstats.triggerRatio + triggerGain*triggerError
 
 	if debug.gcpacertrace > 0 {
 		// Print controller state in terms of the design
 		// document.
 		H_m_prev := memstats.heap_marked
+		h_t := memstats.triggerRatio
 		H_T := memstats.gc_trigger
 		h_a := actualGrowthRatio
 		H_a := memstats.heap_live
@@ -619,6 +605,8 @@ func (c *gcControllerState) endCycle() {
 			" u_a/u_g=", u_a/u_g,
 			"\n")
 	}
+
+	return triggerRatio
 }
 
 // enlistWorker encourages another dedicated mark worker to start on
@@ -650,7 +638,7 @@ func (c *gcControllerState) enlistWorker() {
 	}
 	myID := gp.m.p.ptr().id
 	for tries := 0; tries < 5; tries++ {
-		id := int32(fastrand() % uint32(gomaxprocs-1))
+		id := int32(fastrandn(uint32(gomaxprocs - 1)))
 		if id >= myID {
 			id++
 		}
@@ -760,6 +748,120 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
 	return gp
 }
 
+// gcSetTriggerRatio sets the trigger ratio and updates everything
+// derived from it: the absolute trigger, the heap goal, mark pacing,
+// and sweep pacing.
+//
+// This can be called any time. If GC is the in the middle of a
+// concurrent phase, it will adjust the pacing of that phase.
+//
+// This depends on gcpercent, memstats.heap_marked, and
+// memstats.heap_live. These must be up to date.
+//
+// mheap_.lock must be held or the world must be stopped.
+func gcSetTriggerRatio(triggerRatio float64) {
+	// Set the trigger ratio, capped to reasonable bounds.
+	if triggerRatio < 0 {
+		// This can happen if the mutator is allocating very
+		// quickly or the GC is scanning very slowly.
+		triggerRatio = 0
+	} else if gcpercent >= 0 {
+		// Ensure there's always a little margin so that the
+		// mutator assist ratio isn't infinity.
+		maxTriggerRatio := 0.95 * float64(gcpercent) / 100
+		if triggerRatio > maxTriggerRatio {
+			triggerRatio = maxTriggerRatio
+		}
+	}
+	memstats.triggerRatio = triggerRatio
+
+	// Compute the absolute GC trigger from the trigger ratio.
+	//
+	// We trigger the next GC cycle when the allocated heap has
+	// grown by the trigger ratio over the marked heap size.
+	trigger := ^uint64(0)
+	if gcpercent >= 0 {
+		trigger = uint64(float64(memstats.heap_marked) * (1 + triggerRatio))
+		// Don't trigger below the minimum heap size.
+		minTrigger := heapminimum
+		if !gosweepdone() {
+			// Concurrent sweep happens in the heap growth
+			// from heap_live to gc_trigger, so ensure
+			// that concurrent sweep has some heap growth
+			// in which to perform sweeping before we
+			// start the next GC cycle.
+			sweepMin := atomic.Load64(&memstats.heap_live) + sweepMinHeapDistance*uint64(gcpercent)/100
+			if sweepMin > minTrigger {
+				minTrigger = sweepMin
+			}
+		}
+		if trigger < minTrigger {
+			trigger = minTrigger
+		}
+		if int64(trigger) < 0 {
+			print("runtime: next_gc=", memstats.next_gc, " heap_marked=", memstats.heap_marked, " heap_live=", memstats.heap_live, " initialHeapLive=", work.initialHeapLive, "triggerRatio=", triggerRatio, " minTrigger=", minTrigger, "\n")
+			throw("gc_trigger underflow")
+		}
+	}
+	memstats.gc_trigger = trigger
+
+	// Compute the next GC goal, which is when the allocated heap
+	// has grown by GOGC/100 over the heap marked by the last
+	// cycle.
+	goal := ^uint64(0)
+	if gcpercent >= 0 {
+		goal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
+		if goal < trigger {
+			// The trigger ratio is always less than GOGC/100, but
+			// other bounds on the trigger may have raised it.
+			// Push up the goal, too.
+			goal = trigger
+		}
+	}
+	memstats.next_gc = goal
+	if trace.enabled {
+		traceNextGC()
+	}
+
+	// Update mark pacing.
+	if gcphase != _GCoff {
+		gcController.revise()
+	}
+
+	// Update sweep pacing.
+	if gosweepdone() {
+		mheap_.sweepPagesPerByte = 0
+	} else {
+		// Concurrent sweep needs to sweep all of the in-use
+		// pages by the time the allocated heap reaches the GC
+		// trigger. Compute the ratio of in-use pages to sweep
+		// per byte allocated, accounting for the fact that
+		// some might already be swept.
+		heapLiveBasis := atomic.Load64(&memstats.heap_live)
+		heapDistance := int64(trigger) - int64(heapLiveBasis)
+		// Add a little margin so rounding errors and
+		// concurrent sweep are less likely to leave pages
+		// unswept when GC starts.
+		heapDistance -= 1024 * 1024
+		if heapDistance < _PageSize {
+			// Avoid setting the sweep ratio extremely high
+			heapDistance = _PageSize
+		}
+		pagesSwept := atomic.Load64(&mheap_.pagesSwept)
+		sweepDistancePages := int64(mheap_.pagesInUse) - int64(pagesSwept)
+		if sweepDistancePages <= 0 {
+			mheap_.sweepPagesPerByte = 0
+		} else {
+			mheap_.sweepPagesPerByte = float64(sweepDistancePages) / float64(heapDistance)
+			mheap_.sweepHeapLiveBasis = heapLiveBasis
+			// Write pagesSweptBasis last, since this
+			// signals concurrent sweeps to recompute
+			// their debt.
+			atomic.Store64(&mheap_.pagesSweptBasis, pagesSwept)
+		}
+	}
+}
+
 // gcGoalUtilization is the goal CPU utilization for background
 // marking as a fraction of GOMAXPROCS.
 const gcGoalUtilization = 0.25
@@ -782,10 +884,23 @@ const gcAssistTimeSlack = 5000
 const gcOverAssistWork = 64 << 10
 
 var work struct {
-	full  uint64                   // lock-free list of full blocks workbuf
-	empty uint64                   // lock-free list of empty blocks workbuf
+	full  lfstack                  // lock-free list of full blocks workbuf
+	empty lfstack                  // lock-free list of empty blocks workbuf
 	pad0  [sys.CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait
 
+	wbufSpans struct {
+		lock mutex
+		// free is a list of spans dedicated to workbufs, but
+		// that don't currently contain any workbufs.
+		free mSpanList
+		// busy is a list of all spans containing workbufs on
+		// one of the workbuf lists.
+		busy mSpanList
+	}
+
+	// Restore 64-bit alignment on 32-bit.
+	_ uint32
+
 	// bytesMarked is the number of bytes marked this cycle. This
 	// includes bytes blackened in scanned objects, noscan objects
 	// that go straight to black, and permagrey objects scanned by
@@ -815,15 +930,13 @@ var work struct {
 	// should pass gcDrainBlock to gcDrain to block in the
 	// getfull() barrier. Otherwise, they should pass gcDrainNoBlock.
 	//
-	// TODO: This is a temporary fallback to support
-	// debug.gcrescanstacks > 0 and to work around some known
-	// races. Remove this when we remove the debug option and fix
-	// the races.
+	// TODO: This is a temporary fallback to work around races
+	// that cause early mark termination.
 	helperDrainBlock bool
 
 	// Number of roots of various root types. Set by gcMarkRootPrepare.
-	nFlushCacheRoots                                             int
-	nDataRoots, nBSSRoots, nSpanRoots, nStackRoots, nRescanRoots int
+	nFlushCacheRoots                               int
+	nDataRoots, nBSSRoots, nSpanRoots, nStackRoots int
 
 	// markrootDone indicates that roots have been marked at least
 	// once during the current GC cycle. This is checked by root
@@ -859,6 +972,10 @@ var work struct {
 	// mode is the concurrency mode of the current GC cycle.
 	mode gcMode
 
+	// userForced indicates the current GC cycle was forced by an
+	// explicit user call.
+	userForced bool
+
 	// totaltime is the CPU nanoseconds spent in GC since the
 	// program started if debug.gctrace > 0.
 	totaltime int64
@@ -875,14 +992,19 @@ 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 {
+	// sweepWaiters is a list of blocked goroutines to wake when
+	// we transition from mark termination to sweep.
+	sweepWaiters struct {
 		lock mutex
-		list []guintptr
+		head guintptr
 	}
 
+	// cycles is the number of completed GC cycles, where a GC
+	// cycle is sweep termination, mark, mark termination, and
+	// sweep. This differs from memstats.numgc, which is
+	// incremented at mark termination.
+	cycles uint32
+
 	// Timing/utilization stats for this cycle.
 	stwprocs, maxprocs                 int32
 	tSweepTerm, tMark, tMarkTerm, tEnd int64 // nanotime() of phase start
@@ -898,7 +1020,94 @@ var work struct {
 // garbage collection is complete. It may also block the entire
 // program.
 func GC() {
-	gcStart(gcForceBlockMode, false)
+	// We consider a cycle to be: sweep termination, mark, mark
+	// termination, and sweep. This function shouldn't return
+	// until a full cycle has been completed, from beginning to
+	// end. Hence, we always want to finish up the current cycle
+	// and start a new one. That means:
+	//
+	// 1. In sweep termination, mark, or mark termination of cycle
+	// N, wait until mark termination N completes and transitions
+	// to sweep N.
+	//
+	// 2. In sweep N, help with sweep N.
+	//
+	// At this point we can begin a full cycle N+1.
+	//
+	// 3. Trigger cycle N+1 by starting sweep termination N+1.
+	//
+	// 4. Wait for mark termination N+1 to complete.
+	//
+	// 5. Help with sweep N+1 until it's done.
+	//
+	// This all has to be written to deal with the fact that the
+	// GC may move ahead on its own. For example, when we block
+	// until mark termination N, we may wake up in cycle N+2.
+
+	gp := getg()
+
+	// Prevent the GC phase or cycle count from changing.
+	lock(&work.sweepWaiters.lock)
+	n := atomic.Load(&work.cycles)
+	if gcphase == _GCmark {
+		// Wait until sweep termination, mark, and mark
+		// termination of cycle N complete.
+		gp.schedlink = work.sweepWaiters.head
+		work.sweepWaiters.head.set(gp)
+		goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
+	} else {
+		// We're in sweep N already.
+		unlock(&work.sweepWaiters.lock)
+	}
+
+	// We're now in sweep N or later. Trigger GC cycle N+1, which
+	// will first finish sweep N if necessary and then enter sweep
+	// termination N+1.
+	gcStart(gcBackgroundMode, gcTrigger{kind: gcTriggerCycle, n: n + 1})
+
+	// Wait for mark termination N+1 to complete.
+	lock(&work.sweepWaiters.lock)
+	if gcphase == _GCmark && atomic.Load(&work.cycles) == n+1 {
+		gp.schedlink = work.sweepWaiters.head
+		work.sweepWaiters.head.set(gp)
+		goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
+	} else {
+		unlock(&work.sweepWaiters.lock)
+	}
+
+	// Finish sweep N+1 before returning. We do this both to
+	// complete the cycle and because runtime.GC() is often used
+	// as part of tests and benchmarks to get the system into a
+	// relatively stable and isolated state.
+	for atomic.Load(&work.cycles) == n+1 && gosweepone() != ^uintptr(0) {
+		sweep.nbgsweep++
+		Gosched()
+	}
+
+	// Callers may assume that the heap profile reflects the
+	// just-completed cycle when this returns (historically this
+	// happened because this was a STW GC), but right now the
+	// profile still reflects mark termination N, not N+1.
+	//
+	// As soon as all of the sweep frees from cycle N+1 are done,
+	// we can go ahead and publish the heap profile.
+	//
+	// First, wait for sweeping to finish. (We know there are no
+	// more spans on the sweep queue, but we may be concurrently
+	// sweeping spans, so we have to wait.)
+	for atomic.Load(&work.cycles) == n+1 && atomic.Load(&mheap_.sweepers) != 0 {
+		Gosched()
+	}
+
+	// Now we're really done with sweeping, so we can publish the
+	// stable heap profile. Only do this if we haven't already hit
+	// another mark termination.
+	mp := acquirem()
+	cycle := atomic.Load(&work.cycles)
+	if cycle == n+1 || (gcphase == _GCmark && cycle == n+2) {
+		mProf_PostSweep()
+	}
+	releasem(mp)
 }
 
 // gcMode indicates how concurrent a GC cycle should be.
@@ -910,24 +1119,75 @@ const (
 	gcForceBlockMode               // stop-the-world GC now and STW sweep (forced by user)
 )
 
-// gcShouldStart returns true if the exit condition for the _GCoff
-// phase has been met. The exit condition should be tested when
-// allocating.
-//
-// If forceTrigger is true, it ignores the current heap size, but
-// checks all other conditions. In general this should be false.
-func gcShouldStart(forceTrigger bool) bool {
-	return gcphase == _GCoff && (forceTrigger || memstats.heap_live >= memstats.gc_trigger) && memstats.enablegc && panicking == 0 && gcpercent >= 0
+// A gcTrigger is a predicate for starting a GC cycle. Specifically,
+// it is an exit condition for the _GCoff phase.
+type gcTrigger struct {
+	kind gcTriggerKind
+	now  int64  // gcTriggerTime: current time
+	n    uint32 // gcTriggerCycle: cycle number to start
+}
+
+type gcTriggerKind int
+
+const (
+	// gcTriggerAlways indicates that a cycle should be started
+	// unconditionally, even if GOGC is off or we're in a cycle
+	// right now. This cannot be consolidated with other cycles.
+	gcTriggerAlways gcTriggerKind = iota
+
+	// gcTriggerHeap indicates that a cycle should be started when
+	// the heap size reaches the trigger heap size computed by the
+	// controller.
+	gcTriggerHeap
+
+	// gcTriggerTime indicates that a cycle should be started when
+	// it's been more than forcegcperiod nanoseconds since the
+	// previous GC cycle.
+	gcTriggerTime
+
+	// gcTriggerCycle indicates that a cycle should be started if
+	// we have not yet started cycle number gcTrigger.n (relative
+	// to work.cycles).
+	gcTriggerCycle
+)
+
+// test returns true if the trigger condition is satisfied, meaning
+// that the exit condition for the _GCoff phase has been met. The exit
+// condition should be tested when allocating.
+func (t gcTrigger) test() bool {
+	if !memstats.enablegc || panicking != 0 {
+		return false
+	}
+	if t.kind == gcTriggerAlways {
+		return true
+	}
+	if gcphase != _GCoff || gcpercent < 0 {
+		return false
+	}
+	switch t.kind {
+	case gcTriggerHeap:
+		// Non-atomic access to heap_live for performance. If
+		// we are going to trigger on this, this thread just
+		// atomically wrote heap_live anyway and we'll see our
+		// own write.
+		return memstats.heap_live >= memstats.gc_trigger
+	case gcTriggerTime:
+		lastgc := int64(atomic.Load64(&memstats.last_gc_nanotime))
+		return lastgc != 0 && t.now-lastgc > forcegcperiod
+	case gcTriggerCycle:
+		// t.n > work.cycles, but accounting for wraparound.
+		return int32(t.n-work.cycles) > 0
+	}
+	return true
 }
 
-// gcStart transitions the GC from _GCoff to _GCmark (if mode ==
-// gcBackgroundMode) or _GCmarktermination (if mode !=
-// gcBackgroundMode) by performing sweep termination and GC
-// initialization.
+// gcStart transitions the GC from _GCoff to _GCmark (if
+// !mode.stwMark) or _GCmarktermination (if mode.stwMark) by
+// performing sweep termination and GC initialization.
 //
 // This may return without performing this transition in some cases,
 // such as when called on a system stack or with locks held.
-func gcStart(mode gcMode, forceTrigger bool) {
+func gcStart(mode gcMode, trigger gcTrigger) {
 	// Since this is called from malloc and malloc is called in
 	// the guts of a number of libraries that might be holding
 	// locks, don't attempt to start GC in non-preemptible or
@@ -950,29 +1210,21 @@ func gcStart(mode gcMode, forceTrigger bool) {
 	//
 	// We check the transition condition continuously here in case
 	// this G gets delayed in to the next GC cycle.
-	for (mode != gcBackgroundMode || gcShouldStart(forceTrigger)) && gosweepone() != ^uintptr(0) {
+	for trigger.test() && gosweepone() != ^uintptr(0) {
 		sweep.nbgsweep++
 	}
 
 	// Perform GC initialization and the sweep termination
 	// transition.
-	//
-	// If this is a forced GC, don't acquire the transition lock
-	// or re-check the transition condition because we
-	// specifically *don't* want to share the transition with
-	// another thread.
-	useStartSema := mode == gcBackgroundMode
-	if useStartSema {
-		semacquire(&work.startSema, 0)
-		// Re-check transition condition under transition lock.
-		if !gcShouldStart(forceTrigger) {
-			semrelease(&work.startSema)
-			return
-		}
+	semacquire(&work.startSema)
+	// Re-check transition condition under transition lock.
+	if !trigger.test() {
+		semrelease(&work.startSema)
+		return
 	}
 
 	// For stats, check if this GC was forced by the user.
-	forced := mode != gcBackgroundMode
+	work.userForced = trigger.kind == gcTriggerAlways || trigger.kind == gcTriggerCycle
 
 	// In gcstoptheworld debug mode, upgrade the mode accordingly.
 	// We do this after re-checking the transition condition so
@@ -987,7 +1239,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 	}
 
 	// Ok, we're doing it!  Stop everybody else
-	semacquire(&worldsema, 0)
+	semacquire(&worldsema)
 
 	if trace.enabled {
 		traceGCStart()
@@ -1002,7 +1254,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 	now := nanotime()
 	work.stwprocs, work.maxprocs = gcprocs(), gomaxprocs
 	work.tSweepTerm = now
-	work.heap0 = memstats.heap_live
+	work.heap0 = atomic.Load64(&memstats.heap_live)
 	work.pauseNS = 0
 	work.mode = mode
 
@@ -1016,6 +1268,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 	// reclaimed until the next GC cycle.
 	clearpools()
 
+	work.cycles++
 	if mode == gcBackgroundMode { // Do as much work concurrently as possible
 		gcController.startCycle()
 		work.heapGoal = memstats.next_gc
@@ -1028,18 +1281,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 		// the time we start the world and begin
 		// scanning.
 		//
-		// It's necessary to enable write barriers
-		// during the scan phase for several reasons:
-		//
-		// They must be enabled for writes to higher
-		// stack frames before we scan stacks and
-		// install stack barriers because this is how
-		// we track writes to inactive stack frames.
-		// (Alternatively, we could not install stack
-		// barriers over frame boundaries with
-		// up-pointers).
-		//
-		// They must be enabled before assists are
+		// Write barriers must be enabled before assists are
 		// enabled because they must be enabled before
 		// any non-leaf heap objects are marked. Since
 		// allocations are blocked until assists can
@@ -1078,17 +1320,11 @@ func gcStart(mode gcMode, forceTrigger bool) {
 		work.tMark, work.tMarkTerm = t, t
 		work.heapGoal = work.heap0
 
-		if forced {
-			memstats.numforcedgc++
-		}
-
 		// Perform mark termination. This will restart the world.
-		gcMarkTermination()
+		gcMarkTermination(memstats.triggerRatio)
 	}
 
-	if useStartSema {
-		semrelease(&work.startSema)
-	}
+	semrelease(&work.startSema)
 }
 
 // gcMarkDone transitions the GC from mark 1 to mark 2 and from mark 2
@@ -1108,7 +1344,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 // by mark termination.
 func gcMarkDone() {
 top:
-	semacquire(&work.markDoneSema, 0)
+	semacquire(&work.markDoneSema)
 
 	// Re-check transition condition under transition lock.
 	if !(gcphase == _GCmark && work.nwait == work.nproc && !gcMarkWorkAvailable(nil)) {
@@ -1203,14 +1439,14 @@ top:
 
 		// endCycle depends on all gcWork cache stats being
 		// flushed. This is ensured by mark 2.
-		gcController.endCycle()
+		nextTriggerRatio := gcController.endCycle()
 
 		// Perform mark termination. This will restart the world.
-		gcMarkTermination()
+		gcMarkTermination(nextTriggerRatio)
 	}
 }
 
-func gcMarkTermination() {
+func gcMarkTermination(nextTriggerRatio float64) {
 	// World is stopped.
 	// Start marktermination which includes enabling the write barrier.
 	atomic.Store(&gcBlackenEnabled, 0)
@@ -1292,11 +1528,17 @@ func gcMarkTermination() {
 		throw("gc done but gcphase != _GCoff")
 	}
 
+	// Update GC trigger and pacing for the next cycle.
+	gcSetTriggerRatio(nextTriggerRatio)
+
 	// Update timing memstats
-	now, unixNow := nanotime(), unixnanotime()
+	now := nanotime()
+	sec, nsec, _ := time_now()
+	unixNow := sec*1e9 + int64(nsec)
 	work.pauseNS += now - work.pauseStart
 	work.tEnd = now
-	atomic.Store64(&memstats.last_gc, uint64(unixNow)) // must be Unix time to make sense to user
+	atomic.Store64(&memstats.last_gc_unix, uint64(unixNow)) // must be Unix time to make sense to user
+	atomic.Store64(&memstats.last_gc_nanotime, uint64(now)) // monotonic time for us
 	memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(work.pauseNS)
 	memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow)
 	memstats.pause_total_ns += uint64(work.pauseNS)
@@ -1314,36 +1556,40 @@ func gcMarkTermination() {
 	totalCpu := sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs)
 	memstats.gc_cpu_fraction = float64(work.totaltime) / float64(totalCpu)
 
-	memstats.numgc++
-
 	// Reset sweep state.
 	sweep.nbgsweep = 0
 	sweep.npausesweep = 0
 
+	if work.userForced {
+		memstats.numforcedgc++
+	}
+
+	// Bump GC cycle count and wake goroutines waiting on sweep.
+	lock(&work.sweepWaiters.lock)
+	memstats.numgc++
+	injectglist(work.sweepWaiters.head.ptr())
+	work.sweepWaiters.head = 0
+	unlock(&work.sweepWaiters.lock)
+
+	// Finish the current heap profiling cycle and start a new
+	// heap profiling cycle. We do this before starting the world
+	// so events don't leak into the wrong cycle.
+	mProf_NextCycle()
+
 	systemstack(startTheWorldWithSema)
 
-	// Update heap profile stats if gcSweep didn't do it. This is
-	// relatively expensive, so we don't want to do it while the
-	// world is stopped, but it needs to happen ASAP after
-	// starting the world to prevent too many allocations from the
-	// next cycle leaking in. It must happen before releasing
-	// worldsema since there are applications that do a
-	// runtime.GC() to update the heap profile and then
-	// immediately collect the profile.
-	if _ConcurrentSweep && work.mode != gcForceBlockMode {
-		mProf_GC()
-	}
+	// Flush the heap profile so we can start a new cycle next GC.
+	// This is relatively expensive, so we don't do it with the
+	// world stopped.
+	mProf_Flush()
+
+	// Prepare workbufs for freeing by the sweeper. We do this
+	// asynchronously because it can take non-trivial time.
+	prepareFreeWorkbufs()
 
 	// 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.
@@ -1377,7 +1623,7 @@ func gcMarkTermination() {
 			work.heap0>>20, "->", work.heap1>>20, "->", work.heap2>>20, " MB, ",
 			work.heapGoal>>20, " MB goal, ",
 			work.maxprocs, " P")
-		if work.mode != gcBackgroundMode {
+		if work.userForced {
 			print(" (forced)")
 		}
 		print("\n")
@@ -1599,7 +1845,7 @@ func gcMarkWorkAvailable(p *p) bool {
 	if p != nil && !p.gcw.empty() {
 		return true
 	}
-	if atomic.Load64(&work.full) != 0 {
+	if !work.full.empty() {
 		return true // global work available
 	}
 	if work.markrootNext < work.markrootJobs {
@@ -1629,24 +1875,22 @@ func gcMark(start_time int64) {
 	work.ndone = 0
 	work.nproc = uint32(gcprocs())
 
-	if debug.gcrescanstacks == 0 && work.full == 0 && work.nDataRoots+work.nBSSRoots+work.nSpanRoots+work.nStackRoots+work.nRescanRoots == 0 {
+	if work.full == 0 && work.nDataRoots+work.nBSSRoots+work.nSpanRoots+work.nStackRoots == 0 {
 		// There's no work on the work queue and no root jobs
 		// that can produce work, so don't bother entering the
 		// getfull() barrier.
 		//
-		// With the hybrid barrier enabled, this will be the
-		// situation the vast majority of the time after
-		// concurrent mark. However, we still need a fallback
-		// for STW GC and because there are some known races
-		// that occasionally leave work around for mark
-		// termination.
+		// This will be the situation the vast majority of the
+		// time after concurrent mark. However, we still need
+		// a fallback for STW GC and because there are some
+		// known races that occasionally leave work around for
+		// mark termination.
 		//
 		// We're still hedging our bets here: if we do
 		// accidentally produce some work, we'll still process
 		// it, just not necessarily in parallel.
 		//
-		// TODO(austin): When we eliminate
-		// debug.gcrescanstacks: fix the races, and remove
+		// TODO(austin): Fix the races and and remove
 		// work draining from mark termination so we don't
 		// need the fallback path.
 		work.helperDrainBlock = false
@@ -1710,52 +1954,14 @@ func gcMark(start_time int64) {
 	// Update the marked heap stat.
 	memstats.heap_marked = work.bytesMarked
 
-	// Trigger the next GC cycle when the allocated heap has grown
-	// by triggerRatio over the marked heap size. Assume that
-	// we're in steady state, so the marked heap size is the
-	// same now as it was at the beginning of the GC cycle.
-	memstats.gc_trigger = uint64(float64(memstats.heap_marked) * (1 + gcController.triggerRatio))
-	if memstats.gc_trigger < heapminimum {
-		memstats.gc_trigger = heapminimum
-	}
-	if int64(memstats.gc_trigger) < 0 {
-		print("next_gc=", memstats.next_gc, " bytesMarked=", work.bytesMarked, " heap_live=", memstats.heap_live, " initialHeapLive=", work.initialHeapLive, "\n")
-		throw("gc_trigger underflow")
-	}
-
 	// Update other GC heap size stats. This must happen after
 	// cachestats (which flushes local statistics to these) and
 	// flushallmcaches (which modifies heap_live).
 	memstats.heap_live = work.bytesMarked
 	memstats.heap_scan = uint64(gcController.scanWork)
 
-	minTrigger := memstats.heap_live + sweepMinHeapDistance*uint64(gcpercent)/100
-	if memstats.gc_trigger < minTrigger {
-		// The allocated heap is already past the trigger.
-		// This can happen if the triggerRatio is very low and
-		// the marked heap is less than the live heap size.
-		//
-		// Concurrent sweep happens in the heap growth from
-		// heap_live to gc_trigger, so bump gc_trigger up to ensure
-		// that concurrent sweep has some heap growth in which
-		// to perform sweeping before we start the next GC
-		// cycle.
-		memstats.gc_trigger = minTrigger
-	}
-
-	// The next GC cycle should finish before the allocated heap
-	// has grown by GOGC/100.
-	memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
-	if gcpercent < 0 {
-		memstats.next_gc = ^uint64(0)
-	}
-	if memstats.next_gc < memstats.gc_trigger {
-		memstats.next_gc = memstats.gc_trigger
-	}
-
 	if trace.enabled {
 		traceHeapAlloc()
-		traceNextGC()
 	}
 }
 
@@ -1773,6 +1979,7 @@ func gcSweep(mode gcMode) {
 		// with an empty swept list.
 		throw("non-empty swept list")
 	}
+	mheap_.pagesSwept = 0
 	unlock(&mheap_.lock)
 
 	if !_ConcurrentSweep || mode == gcForceBlockMode {
@@ -1780,35 +1987,23 @@ func gcSweep(mode gcMode) {
 		// Record that no proportional sweeping has to happen.
 		lock(&mheap_.lock)
 		mheap_.sweepPagesPerByte = 0
-		mheap_.pagesSwept = 0
 		unlock(&mheap_.lock)
 		// Sweep all spans eagerly.
 		for sweepone() != ^uintptr(0) {
 			sweep.npausesweep++
 		}
-		// Do an additional mProf_GC, because all 'free' events are now real as well.
-		mProf_GC()
-		mProf_GC()
+		// Free workbufs eagerly.
+		prepareFreeWorkbufs()
+		for freeSomeWbufs(false) {
+		}
+		// All "free" events for this mark/sweep cycle have
+		// now happened, so we can make this profile cycle
+		// available immediately.
+		mProf_NextCycle()
+		mProf_Flush()
 		return
 	}
 
-	// Concurrent sweep needs to sweep all of the in-use pages by
-	// the time the allocated heap reaches the GC trigger. Compute
-	// the ratio of in-use pages to sweep per byte allocated.
-	heapDistance := int64(memstats.gc_trigger) - int64(memstats.heap_live)
-	// Add a little margin so rounding errors and concurrent
-	// sweep are less likely to leave pages unswept when GC starts.
-	heapDistance -= 1024 * 1024
-	if heapDistance < _PageSize {
-		// Avoid setting the sweep ratio extremely high
-		heapDistance = _PageSize
-	}
-	lock(&mheap_.lock)
-	mheap_.sweepPagesPerByte = float64(mheap_.pagesInUse) / float64(heapDistance)
-	mheap_.pagesSwept = 0
-	mheap_.spanBytesAlloc = 0
-	unlock(&mheap_.lock)
-
 	// Background sweep.
 	lock(&sweep.lock)
 	if sweep.parked {
@@ -1826,24 +2021,16 @@ func gcSweep(mode gcMode) {
 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.initialHeapLive = atomic.Load64(&memstats.heap_live)
 	work.markrootDone = false
 }
 
diff --git a/src/runtime/mgclarge.go b/src/runtime/mgclarge.go
new file mode 100644
index 0000000..757e88d
--- /dev/null
+++ b/src/runtime/mgclarge.go
@@ -0,0 +1,326 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Page heap.
+//
+// See malloc.go for the general overview.
+//
+// Large spans are the subject of this file. Spans consisting of less than
+// _MaxMHeapLists are held in lists of like sized spans. Larger spans
+// are held in a treap. See https://en.wikipedia.org/wiki/Treap or
+// http://faculty.washington.edu/aragon/pubs/rst89.pdf for an overview.
+// sema.go also holds an implementation of a treap.
+//
+// Each treapNode holds a single span. The treap is sorted by page size
+// and for spans of the same size a secondary sort based on start address
+// is done.
+// Spans are returned based on a best fit algorithm and for spans of the same
+// size the one at the lowest address is selected.
+//
+// The primary routines are
+// insert: adds a span to the treap
+// remove: removes the span from that treap that best fits the required size
+// removeSpan: which removes a specific span from the treap
+//
+// _mheap.lock must be held when manipulating this data structure.
+
+package runtime
+
+import (
+	"unsafe"
+)
+
+//go:notinheap
+type mTreap struct {
+	treap *treapNode
+}
+
+//go:notinheap
+type treapNode struct {
+	right     *treapNode // all treapNodes > this treap node
+	left      *treapNode // all treapNodes < this treap node
+	parent    *treapNode // direct parent of this node, nil if root
+	npagesKey uintptr    // number of pages in spanKey, used as primary sort key
+	spanKey   *mspan     // span of size npagesKey, used as secondary sort key
+	priority  uint32     // random number used by treap algorithm keep tree probablistically balanced
+}
+
+func (t *treapNode) init() {
+	t.right = nil
+	t.left = nil
+	t.parent = nil
+	t.spanKey = nil
+	t.npagesKey = 0
+	t.priority = 0
+}
+
+// isSpanInTreap is handy for debugging. One should hold the heap lock, usually
+// mheap_.lock().
+func (t *treapNode) isSpanInTreap(s *mspan) bool {
+	if t == nil {
+		return false
+	}
+	return t.spanKey == s || t.left.isSpanInTreap(s) || t.right.isSpanInTreap(s)
+}
+
+// walkTreap is handy for debugging.
+// Starting at some treapnode t, for example the root, do a depth first preorder walk of
+// the tree executing fn at each treap node. One should hold the heap lock, usually
+// mheap_.lock().
+func (t *treapNode) walkTreap(fn func(tn *treapNode)) {
+	if t == nil {
+		return
+	}
+	fn(t)
+	t.left.walkTreap(fn)
+	t.right.walkTreap(fn)
+}
+
+// checkTreapNode when used in conjunction with walkTreap can usually detect a
+// poorly formed treap.
+func checkTreapNode(t *treapNode) {
+	// lessThan is used to order the treap.
+	// npagesKey and npages are the primary keys.
+	// spanKey and span are the secondary keys.
+	// span == nil (0) will always be lessThan all
+	// spans of the same size.
+	lessThan := func(npages uintptr, s *mspan) bool {
+		if t.npagesKey != npages {
+			return t.npagesKey < npages
+		}
+		// t.npagesKey == npages
+		return uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(s))
+	}
+
+	if t == nil {
+		return
+	}
+	if t.spanKey.npages != t.npagesKey || t.spanKey.next != nil {
+		println("runtime: checkTreapNode treapNode t=", t, "     t.npagesKey=", t.npagesKey,
+			"t.spanKey.npages=", t.spanKey.npages)
+		throw("why does span.npages and treap.ngagesKey do not match?")
+	}
+	if t.left != nil && lessThan(t.left.npagesKey, t.left.spanKey) {
+		throw("t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
+	}
+	if t.right != nil && !lessThan(t.right.npagesKey, t.right.spanKey) {
+		throw("!t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
+	}
+}
+
+// insert adds span to the large span treap.
+func (root *mTreap) insert(span *mspan) {
+	npages := span.npages
+	var last *treapNode
+	pt := &root.treap
+	for t := *pt; t != nil; t = *pt {
+		last = t
+		if t.npagesKey < npages {
+			pt = &t.right
+		} else if t.npagesKey > npages {
+			pt = &t.left
+		} else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
+			// t.npagesKey == npages, so sort on span addresses.
+			pt = &t.right
+		} else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
+			pt = &t.left
+		} else {
+			throw("inserting span already in treap")
+		}
+	}
+
+	// Add t as new leaf in tree of span size and unique addrs.
+	// The balanced tree is a treap using priority as the random heap priority.
+	// That is, it is a binary tree ordered according to the npagesKey,
+	// but then among the space of possible binary trees respecting those
+	// npagesKeys, it is kept balanced on average by maintaining a heap ordering
+	// on the priority: s.priority <= both s.right.priority and s.right.priority.
+	// https://en.wikipedia.org/wiki/Treap
+	// http://faculty.washington.edu/aragon/pubs/rst89.pdf
+
+	t := (*treapNode)(mheap_.treapalloc.alloc())
+	t.init()
+	t.npagesKey = span.npages
+	t.priority = fastrand()
+	t.spanKey = span
+	t.parent = last
+	*pt = t // t now at a leaf.
+	// Rotate up into tree according to priority.
+	for t.parent != nil && t.parent.priority > t.priority {
+		if t != nil && t.spanKey.npages != t.npagesKey {
+			println("runtime: insert t=", t, "t.npagesKey=", t.npagesKey)
+			println("runtime:      t.spanKey=", t.spanKey, "t.spanKey.npages=", t.spanKey.npages)
+			throw("span and treap sizes do not match?")
+		}
+		if t.parent.left == t {
+			root.rotateRight(t.parent)
+		} else {
+			if t.parent.right != t {
+				throw("treap insert finds a broken treap")
+			}
+			root.rotateLeft(t.parent)
+		}
+	}
+}
+
+func (root *mTreap) removeNode(t *treapNode) *mspan {
+	if t.spanKey.npages != t.npagesKey {
+		throw("span and treap node npages do not match")
+	}
+	result := t.spanKey
+
+	// Rotate t down to be leaf of tree for removal, respecting priorities.
+	for t.right != nil || t.left != nil {
+		if t.right == nil || t.left != nil && t.left.priority < t.right.priority {
+			root.rotateRight(t)
+		} else {
+			root.rotateLeft(t)
+		}
+	}
+	// Remove t, now a leaf.
+	if t.parent != nil {
+		if t.parent.left == t {
+			t.parent.left = nil
+		} else {
+			t.parent.right = nil
+		}
+	} else {
+		root.treap = nil
+	}
+	// Return the found treapNode's span after freeing the treapNode.
+	t.spanKey = nil
+	t.npagesKey = 0
+	mheap_.treapalloc.free(unsafe.Pointer(t))
+	return result
+}
+
+// remove searches for, finds, removes from the treap, and returns the smallest
+// span that can hold npages. If no span has at least npages return nil.
+// This is slightly more complicated than a simple binary tree search
+// since if an exact match is not found the next larger node is
+// returned.
+// If the last node inspected > npagesKey not holding
+// a left node (a smaller npages) is the "best fit" node.
+func (root *mTreap) remove(npages uintptr) *mspan {
+	t := root.treap
+	for t != nil {
+		if t.spanKey == nil {
+			throw("treap node with nil spanKey found")
+		}
+		if t.npagesKey < npages {
+			t = t.right
+		} else if t.left != nil && t.left.npagesKey >= npages {
+			t = t.left
+		} else {
+			result := t.spanKey
+			root.removeNode(t)
+			return result
+		}
+	}
+	return nil
+}
+
+// removeSpan searches for, finds, deletes span along with
+// the associated treap node. If the span is not in the treap
+// then t will eventually be set to nil and the t.spanKey
+// will throw.
+func (root *mTreap) removeSpan(span *mspan) {
+	npages := span.npages
+	t := root.treap
+	for t.spanKey != span {
+		if t.npagesKey < npages {
+			t = t.right
+		} else if t.npagesKey > npages {
+			t = t.left
+		} else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
+			t = t.right
+		} else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
+			t = t.left
+		}
+	}
+	root.removeNode(t)
+}
+
+// scavengetreap visits each node in the treap and scavenges the
+// treapNode's span.
+func scavengetreap(treap *treapNode, now, limit uint64) uintptr {
+	if treap == nil {
+		return 0
+	}
+	return scavengeTreapNode(treap, now, limit) +
+		scavengetreap(treap.left, now, limit) +
+		scavengetreap(treap.right, now, limit)
+}
+
+// rotateLeft rotates the tree rooted at node x.
+// turning (x a (y b c)) into (y (x a b) c).
+func (root *mTreap) rotateLeft(x *treapNode) {
+	// p -> (x a (y b c))
+	p := x.parent
+	a, y := x.left, x.right
+	b, c := y.left, y.right
+
+	y.left = x
+	x.parent = y
+	y.right = c
+	if c != nil {
+		c.parent = y
+	}
+	x.left = a
+	if a != nil {
+		a.parent = x
+	}
+	x.right = b
+	if b != nil {
+		b.parent = x
+	}
+
+	y.parent = p
+	if p == nil {
+		root.treap = y
+	} else if p.left == x {
+		p.left = y
+	} else {
+		if p.right != x {
+			throw("large span treap rotateLeft")
+		}
+		p.right = y
+	}
+}
+
+// rotateRight rotates the tree rooted at node y.
+// turning (y (x a b) c) into (x a (y b c)).
+func (root *mTreap) rotateRight(y *treapNode) {
+	// p -> (y (x a b) c)
+	p := y.parent
+	x, c := y.left, y.right
+	a, b := x.left, x.right
+
+	x.left = a
+	if a != nil {
+		a.parent = x
+	}
+	x.right = y
+	y.parent = x
+	y.left = b
+	if b != nil {
+		b.parent = y
+	}
+	y.right = c
+	if c != nil {
+		c.parent = y
+	}
+
+	x.parent = p
+	if p == nil {
+		root.treap = x
+	} else if p.left == y {
+		p.left = x
+	} else {
+		if p.right != y {
+			throw("large span treap rotateRight")
+		}
+		p.right = x
+	}
+}
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 85130bf..dbca5cd 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -107,21 +107,24 @@ func gcMarkRootPrepare() {
 		// 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.
+		// The hybrid barrier ensures that stacks can't
+		// contain pointers to unmarked objects, so on the
+		// second markroot, there's no need to scan stacks.
 		work.nStackRoots = 0
-		work.nRescanRoots = len(work.rescan.list)
+
+		if debug.gcrescanstacks > 0 {
+			// Scan stacks anyway for debugging.
+			work.nStackRoots = int(atomic.Loaduintptr(&allglen))
+		}
 	}
 
 	work.markrootNext = 0
-	work.markrootJobs = uint32(fixedRootCount + work.nFlushCacheRoots + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots + work.nRescanRoots)
+	work.markrootJobs = uint32(fixedRootCount + work.nFlushCacheRoots + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots)
 }
 
 // gcMarkRootCheck checks that all roots have been scanned. It is
@@ -180,8 +183,7 @@ func markroot(gcw *gcWork, i uint32) {
 	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)
+	end := baseStacks + uint32(work.nStackRoots)
 
 	// Note: if you add a case here, please also update heapdump.go:dumproots.
 	switch {
@@ -199,6 +201,11 @@ func markroot(gcw *gcWork, i uint32) {
 		}
 
 	case i == fixedRootFinalizers:
+		// Only do this once per GC cycle since we don't call
+		// queuefinalizer during marking.
+		if work.markrootDone {
+			break
+		}
 		for fb := allfin; fb != nil; fb = fb.alllink {
 			cnt := uintptr(atomic.Load(&fb.cnt))
 			scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), cnt*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], gcw)
@@ -220,15 +227,8 @@ func markroot(gcw *gcWork, i uint32) {
 	default:
 		// the rest is scanning goroutine stacks
 		var gp *g
-		if baseStacks <= i && i < baseRescan {
+		if baseStacks <= i && i < end {
 			gp = allgs[i-baseStacks]
-		} else if baseRescan <= i && i < end {
-			gp = work.rescan.list[i-baseRescan].ptr()
-			if gp.gcRescan != int32(i-baseRescan) {
-				// Looking for issue #17099.
-				println("runtime: gp", gp, "found at rescan index", i-baseRescan, "but should be at", gp.gcRescan)
-				throw("bad g rescan index")
-			}
 		} else {
 			throw("markroot: bad index")
 		}
@@ -415,6 +415,10 @@ func gcAssistAlloc(gp *g) {
 		return
 	}
 
+	if trace.enabled {
+		traceGCMarkAssistStart()
+	}
+
 retry:
 	// Compute the amount of scan work we need to do to make the
 	// balance positive. When the required amount of work is low,
@@ -450,6 +454,9 @@ retry:
 		if scanWork == 0 {
 			// We were able to steal all of the credit we
 			// needed.
+			if trace.enabled {
+				traceGCMarkAssistDone()
+			}
 			return
 		}
 	}
@@ -496,6 +503,9 @@ retry:
 		// At this point either background GC has satisfied
 		// this G's assist debt, or the GC cycle is over.
 	}
+	if trace.enabled {
+		traceGCMarkAssistDone()
+	}
 }
 
 // gcAssistAlloc1 is the part of gcAssistAlloc that runs on the system
@@ -716,10 +726,6 @@ func gcFlushBgCredit(scanWork int64) {
 
 // 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.
 //
@@ -762,94 +768,14 @@ func scanstack(gp *g, gcw *gcWork) {
 		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.
-		barrierOffset = uintptr(firstStackBarrierOffset)
-		nextBarrier = sp + barrierOffset
-
-		if debug.gcstackbarrieroff > 0 {
-			nextBarrier = ^uintptr(0)
-		}
-
-		// 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.
-			nextBarrier = ^uintptr(0)
-		} else {
-			// Only re-scan up to the lowest un-hit
-			// barrier. Any frames above this have not
-			// executed since the concurrent scan of gp and
-			// any writes through up-pointers to above
-			// this barrier had write barriers.
-			nextBarrier = gp.stkbar[gp.stkbarPos].savedLRPtr
-			if debugStackBarrier {
-				print("rescan below ", hex(nextBarrier), " in [", hex(sp), ",", hex(gp.stack.hi), ") goid=", gp.goid, "\n")
-			}
-		}
-
-	default:
-		throw("scanstack in wrong phase")
-	}
-
 	// Scan the stack.
 	var cache pcvalueCache
-	n := 0
 	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
 		scanframeworker(frame, &cache, gcw)
-
-		if frame.fp > nextBarrier {
-			// We skip installing a barrier on bottom-most
-			// frame because on LR machines this LR is not
-			// on the stack.
-			if gcphase == _GCmark && n != 0 {
-				if gcInstallStackBarrier(gp, frame) {
-					barrierOffset *= 2
-					nextBarrier = sp + barrierOffset
-				}
-			} else if gcphase == _GCmarktermination {
-				// We just scanned a frame containing
-				// a return to a stack barrier. Since
-				// this frame never returned, we can
-				// stop scanning.
-				return false
-			}
-		}
-		n++
-
 		return true
 	}
 	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
 	tracebackdefers(gp, scanframe, nil)
-	gcUnlockStackBarriers(gp)
-	if gcphase == _GCmark {
-		// 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
 }
 
@@ -926,73 +852,6 @@ 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 debug.gcrescanstacks == 0 {
-		// Clear gcscanvalid to keep assertions happy.
-		//
-		// TODO: Remove gcscanvalid entirely when we remove
-		// stack rescanning.
-		gp.gcscanvalid = false
-		return
-	}
-
-	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 debug.gcrescanstacks == 0 {
-		return
-	}
-
-	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 (
@@ -1268,7 +1127,7 @@ func scanobject(b uintptr, gcw *gcWork) {
 			// paths), in which case we must *not* enqueue
 			// oblets since their bitmaps will be
 			// uninitialized.
-			if !hbits.hasPointers(n) {
+			if s.spanclass.noscan() {
 				// Bypass the whole scan.
 				gcw.bytesMarked += uint64(n)
 				return
@@ -1371,6 +1230,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 			// Dump the object
 			gcDumpObject("obj", obj, ^uintptr(0))
 
+			getg().m.traceback = 2
 			throw("checkmark found unmarked object")
 		}
 		if hbits.isCheckmarked(span.elemsize) {
@@ -1385,6 +1245,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 			print("runtime: marking free object ", hex(obj), " found at *(", hex(base), "+", hex(off), ")\n")
 			gcDumpObject("base", base, off)
 			gcDumpObject("obj", obj, ^uintptr(0))
+			getg().m.traceback = 2
 			throw("marking free object")
 		}
 
@@ -1396,7 +1257,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 		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) {
+		if span.spanclass.noscan() {
 			gcw.bytesMarked += uint64(span.elemsize)
 			return
 		}
@@ -1429,7 +1290,7 @@ func gcDumpObject(label string, obj, off uintptr) {
 		print(" s=nil\n")
 		return
 	}
-	print(" s.base()=", hex(s.base()), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, " s.state=")
+	print(" s.base()=", hex(s.base()), " s.limit=", hex(s.limit), " s.spanclass=", s.spanclass, " s.elemsize=", s.elemsize, " s.state=")
 	if 0 <= s.state && int(s.state) < len(mSpanStateNames) {
 		print(mSpanStateNames[s.state], "\n")
 	} else {
@@ -1438,7 +1299,7 @@ func gcDumpObject(label string, obj, off uintptr) {
 
 	skipped := false
 	size := s.elemsize
-	if s.state == _MSpanStack && size == 0 {
+	if s.state == _MSpanManual && size == 0 {
 		// We're printing something from a stack frame. We
 		// don't know how big it is, so just show up to an
 		// including off.
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index fb5c488..1bb19ec 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -22,10 +22,6 @@ type sweepdata struct {
 
 	nbgsweep    uint32
 	npausesweep uint32
-
-	// pacertracegen is the sweepgen at which the last pacer trace
-	// "sweep finished" message was printed.
-	pacertracegen uint32
 }
 
 // finishsweep_m ensures that all spans are swept.
@@ -60,6 +56,9 @@ func bgsweep(c chan int) {
 			sweep.nbgsweep++
 			Gosched()
 		}
+		for freeSomeWbufs(true) {
+			Gosched()
+		}
 		lock(&sweep.lock)
 		if !gosweepdone() {
 			// This can happen if a GC runs between
@@ -78,20 +77,24 @@ func bgsweep(c chan int) {
 //go:nowritebarrier
 func sweepone() uintptr {
 	_g_ := getg()
+	sweepRatio := mheap_.sweepPagesPerByte // For debugging
 
 	// increment locks to ensure that the goroutine is not preempted
 	// in the middle of sweep thus leaving the span in an inconsistent state for next GC
 	_g_.m.locks++
+	if atomic.Load(&mheap_.sweepdone) != 0 {
+		_g_.m.locks--
+		return ^uintptr(0)
+	}
+	atomic.Xadd(&mheap_.sweepers, +1)
+
+	npages := ^uintptr(0)
 	sg := mheap_.sweepgen
 	for {
 		s := mheap_.sweepSpans[1-sg/2%2].pop()
 		if s == nil {
-			mheap_.sweepdone = 1
-			_g_.m.locks--
-			if debug.gcpacertrace > 0 && atomic.Cas(&sweep.pacertracegen, sg-2, sg) {
-				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)
+			atomic.Store(&mheap_.sweepdone, 1)
+			break
 		}
 		if s.state != mSpanInUse {
 			// This can happen if direct sweeping already
@@ -106,16 +109,25 @@ func sweepone() uintptr {
 		if s.sweepgen != sg-2 || !atomic.Cas(&s.sweepgen, sg-2, sg-1) {
 			continue
 		}
-		npages := s.npages
+		npages = s.npages
 		if !s.sweep(false) {
 			// Span is still in-use, so this returned no
 			// pages to the heap and the span needs to
 			// move to the swept in-use list.
 			npages = 0
 		}
-		_g_.m.locks--
-		return npages
+		break
+	}
+
+	// Decrement the number of active sweepers and if this is the
+	// last one print trace information.
+	if atomic.Xadd(&mheap_.sweepers, -1) == 0 && atomic.Load(&mheap_.sweepdone) != 0 {
+		if debug.gcpacertrace > 0 {
+			print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", (memstats.heap_live-mheap_.sweepHeapLiveBasis)>>20, "MB during sweep; swept ", mheap_.pagesSwept, " pages at ", sweepRatio, " pages/byte\n")
+		}
 	}
+	_g_.m.locks--
+	return npages
 }
 
 //go:nowritebarrier
@@ -178,15 +190,14 @@ func (s *mspan) sweep(preserve bool) bool {
 	}
 
 	if trace.enabled {
-		traceGCSweepStart()
+		traceGCSweepSpan(s.npages * _PageSize)
 	}
 
 	atomic.Xadd64(&mheap_.pagesSwept, int64(s.npages))
 
-	cl := s.sizeclass
+	spc := s.spanclass
 	size := s.elemsize
 	res := false
-	nfree := 0
 
 	c := _g_.m.mcache
 	freeToHeap := false
@@ -276,21 +287,23 @@ func (s *mspan) sweep(preserve bool) bool {
 	}
 
 	// Count the number of free objects in this span.
-	nfree = s.countFree()
-	if cl == 0 && nfree != 0 {
+	nalloc := uint16(s.countAlloc())
+	if spc.sizeclass() == 0 && nalloc == 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")
+		print("runtime: nelems=", s.nelems, " nalloc=", nalloc, " previous allocCount=", s.allocCount, " nfreed=", nfreed, "\n")
 		throw("sweep increased allocation count")
 	}
 
 	s.allocCount = nalloc
 	wasempty := s.nextFreeIndex() == s.nelems
 	s.freeindex = 0 // reset allocation index to start of span.
+	if trace.enabled {
+		getg().m.p.ptr().traceReclaimed += uintptr(nfreed) * s.elemsize
+	}
 
 	// gcmarkBits becomes the allocBits.
 	// get a fresh cleared gcmarkBits in preparation for next GC
@@ -318,9 +331,9 @@ func (s *mspan) sweep(preserve bool) bool {
 		atomic.Store(&s.sweepgen, sweepgen)
 	}
 
-	if nfreed > 0 && cl != 0 {
-		c.local_nsmallfree[cl] += uintptr(nfreed)
-		res = mheap_.central[cl].mcentral.freeSpan(s, preserve, wasempty)
+	if nfreed > 0 && spc.sizeclass() != 0 {
+		c.local_nsmallfree[spc.sizeclass()] += uintptr(nfreed)
+		res = mheap_.central[spc].mcentral.freeSpan(s, preserve, wasempty)
 		// MCentral_FreeSpan updates sweepgen
 	} else if freeToHeap {
 		// Free large span to heap
@@ -354,9 +367,6 @@ func (s *mspan) sweep(preserve bool) bool {
 		// it on the swept in-use list.
 		mheap_.sweepSpans[sweepgen/2%2].push(s)
 	}
-	if trace.enabled {
-		traceGCSweepDone()
-	}
 	return res
 }
 
@@ -369,8 +379,7 @@ func (s *mspan) sweep(preserve bool) bool {
 //
 // deductSweepCredit makes a worst-case assumption that all spanBytes
 // bytes of the ultimately allocated span will be available for object
-// allocation. The caller should call reimburseSweepCredit if that
-// turns out not to be the case once the span is allocated.
+// allocation.
 //
 // deductSweepCredit is the core of the "proportional sweep" system.
 // It uses statistics gathered by the garbage collector to perform
@@ -384,31 +393,28 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
 		return
 	}
 
-	// Account for this span allocation.
-	spanBytesAlloc := atomic.Xadd64(&mheap_.spanBytesAlloc, int64(spanBytes))
+	if trace.enabled {
+		traceGCSweepStart()
+	}
+
+retry:
+	sweptBasis := atomic.Load64(&mheap_.pagesSweptBasis)
 
 	// Fix debt if necessary.
-	pagesOwed := int64(mheap_.sweepPagesPerByte * float64(spanBytesAlloc))
-	for pagesOwed-int64(atomic.Load64(&mheap_.pagesSwept)) > int64(callerSweepPages) {
+	newHeapLive := uintptr(atomic.Load64(&memstats.heap_live)-mheap_.sweepHeapLiveBasis) + spanBytes
+	pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages)
+	for pagesTarget > int64(atomic.Load64(&mheap_.pagesSwept)-sweptBasis) {
 		if gosweepone() == ^uintptr(0) {
 			mheap_.sweepPagesPerByte = 0
 			break
 		}
+		if atomic.Load64(&mheap_.pagesSweptBasis) != sweptBasis {
+			// Sweep pacing changed. Recompute debt.
+			goto retry
+		}
 	}
-}
 
-// reimburseSweepCredit records that unusableBytes bytes of a
-// just-allocated span are not available for object allocation. This
-// offsets the worst-case charge performed by deductSweepCredit.
-func reimburseSweepCredit(unusableBytes uintptr) {
-	if mheap_.sweepPagesPerByte == 0 {
-		// Nobody cares about the credit. Avoid the atomic.
-		return
-	}
-	nval := atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))
-	if int64(nval) < 0 {
-		// Debugging for #18043.
-		print("runtime: bad spanBytesAlloc=", nval, " (was ", nval+uint64(unusableBytes), ") unusableBytes=", unusableBytes, " sweepPagesPerByte=", mheap_.sweepPagesPerByte, "\n")
-		throw("spanBytesAlloc underflow")
+	if trace.enabled {
+		traceGCSweepDone()
 	}
 }
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index 5eb05a7..461679b 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -12,8 +12,22 @@ import (
 
 const (
 	_WorkbufSize = 2048 // in bytes; larger values result in less contention
+
+	// workbufAlloc is the number of bytes to allocate at a time
+	// for new workbufs. This must be a multiple of pageSize and
+	// should be a multiple of _WorkbufSize.
+	//
+	// Larger values reduce workbuf allocation overhead. Smaller
+	// values reduce heap fragmentation.
+	workbufAlloc = 32 << 10
 )
 
+func init() {
+	if workbufAlloc%pageSize != 0 || workbufAlloc%_WorkbufSize != 0 {
+		throw("bad workbufAlloc")
+	}
+}
+
 // Garbage collector work pool abstraction.
 //
 // This implements a producer/consumer model for pointers to grey
@@ -25,21 +39,6 @@ const (
 // grey objects, thus blackening them, and then scans them,
 // potentially producing new pointers to grey objects.
 
-// A wbufptr holds a workbuf*, but protects it from write barriers.
-// workbufs never live on the heap, so write barriers are unnecessary.
-// Write barriers on workbuf pointers may also be dangerous in the GC.
-//
-// TODO: Since workbuf is now go:notinheap, this isn't necessary.
-type wbufptr uintptr
-
-func wbufptrOf(w *workbuf) wbufptr {
-	return wbufptr(unsafe.Pointer(w))
-}
-
-func (wp wbufptr) ptr() *workbuf {
-	return (*workbuf)(unsafe.Pointer(wp))
-}
-
 // A gcWork provides the interface to produce and consume work for the
 // garbage collector.
 //
@@ -75,7 +74,7 @@ type gcWork struct {
 	// next.
 	//
 	// Invariant: Both wbuf1 and wbuf2 are nil or neither are.
-	wbuf1, wbuf2 wbufptr
+	wbuf1, wbuf2 *workbuf
 
 	// Bytes marked (blackened) on this gcWork. This is aggregated
 	// into work.bytesMarked by dispose.
@@ -87,12 +86,12 @@ type gcWork struct {
 }
 
 func (w *gcWork) init() {
-	w.wbuf1 = wbufptrOf(getempty())
+	w.wbuf1 = getempty()
 	wbuf2 := trygetfull()
 	if wbuf2 == nil {
 		wbuf2 = getempty()
 	}
-	w.wbuf2 = wbufptrOf(wbuf2)
+	w.wbuf2 = wbuf2
 }
 
 // put enqueues a pointer for the garbage collector to trace.
@@ -100,18 +99,18 @@ func (w *gcWork) init() {
 //go:nowritebarrier
 func (w *gcWork) put(obj uintptr) {
 	flushed := false
-	wbuf := w.wbuf1.ptr()
+	wbuf := w.wbuf1
 	if wbuf == nil {
 		w.init()
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		// wbuf is empty at this point.
 	} else if wbuf.nobj == len(wbuf.obj) {
 		w.wbuf1, w.wbuf2 = w.wbuf2, w.wbuf1
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		if wbuf.nobj == len(wbuf.obj) {
 			putfull(wbuf)
 			wbuf = getempty()
-			w.wbuf1 = wbufptrOf(wbuf)
+			w.wbuf1 = wbuf
 			flushed = true
 		}
 	}
@@ -132,7 +131,7 @@ func (w *gcWork) put(obj uintptr) {
 // otherwise it returns false and the caller needs to call put.
 //go:nowritebarrier
 func (w *gcWork) putFast(obj uintptr) bool {
-	wbuf := w.wbuf1.ptr()
+	wbuf := w.wbuf1
 	if wbuf == nil {
 		return false
 	} else if wbuf.nobj == len(wbuf.obj) {
@@ -151,15 +150,15 @@ func (w *gcWork) putFast(obj uintptr) bool {
 // other gcWork instances or other caches.
 //go:nowritebarrier
 func (w *gcWork) tryGet() uintptr {
-	wbuf := w.wbuf1.ptr()
+	wbuf := w.wbuf1
 	if wbuf == nil {
 		w.init()
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		// wbuf is empty at this point.
 	}
 	if wbuf.nobj == 0 {
 		w.wbuf1, w.wbuf2 = w.wbuf2, w.wbuf1
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		if wbuf.nobj == 0 {
 			owbuf := wbuf
 			wbuf = trygetfull()
@@ -167,7 +166,7 @@ func (w *gcWork) tryGet() uintptr {
 				return 0
 			}
 			putempty(owbuf)
-			w.wbuf1 = wbufptrOf(wbuf)
+			w.wbuf1 = wbuf
 		}
 	}
 
@@ -180,7 +179,7 @@ func (w *gcWork) tryGet() uintptr {
 // the caller is expected to call tryGet().
 //go:nowritebarrier
 func (w *gcWork) tryGetFast() uintptr {
-	wbuf := w.wbuf1.ptr()
+	wbuf := w.wbuf1
 	if wbuf == nil {
 		return 0
 	}
@@ -197,15 +196,15 @@ func (w *gcWork) tryGetFast() uintptr {
 // been retrieved.  get returns 0 if there are no pointers remaining.
 //go:nowritebarrier
 func (w *gcWork) get() uintptr {
-	wbuf := w.wbuf1.ptr()
+	wbuf := w.wbuf1
 	if wbuf == nil {
 		w.init()
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		// wbuf is empty at this point.
 	}
 	if wbuf.nobj == 0 {
 		w.wbuf1, w.wbuf2 = w.wbuf2, w.wbuf1
-		wbuf = w.wbuf1.ptr()
+		wbuf = w.wbuf1
 		if wbuf.nobj == 0 {
 			owbuf := wbuf
 			wbuf = getfull()
@@ -213,7 +212,7 @@ func (w *gcWork) get() uintptr {
 				return 0
 			}
 			putempty(owbuf)
-			w.wbuf1 = wbufptrOf(wbuf)
+			w.wbuf1 = wbuf
 		}
 	}
 
@@ -231,21 +230,21 @@ func (w *gcWork) get() uintptr {
 //
 //go:nowritebarrier
 func (w *gcWork) dispose() {
-	if wbuf := w.wbuf1.ptr(); wbuf != nil {
+	if wbuf := w.wbuf1; wbuf != nil {
 		if wbuf.nobj == 0 {
 			putempty(wbuf)
 		} else {
 			putfull(wbuf)
 		}
-		w.wbuf1 = 0
+		w.wbuf1 = nil
 
-		wbuf = w.wbuf2.ptr()
+		wbuf = w.wbuf2
 		if wbuf.nobj == 0 {
 			putempty(wbuf)
 		} else {
 			putfull(wbuf)
 		}
-		w.wbuf2 = 0
+		w.wbuf2 = nil
 	}
 	if w.bytesMarked != 0 {
 		// dispose happens relatively infrequently. If this
@@ -265,14 +264,14 @@ func (w *gcWork) dispose() {
 // global queue.
 //go:nowritebarrier
 func (w *gcWork) balance() {
-	if w.wbuf1 == 0 {
+	if w.wbuf1 == nil {
 		return
 	}
-	if wbuf := w.wbuf2.ptr(); wbuf.nobj != 0 {
+	if wbuf := w.wbuf2; wbuf.nobj != 0 {
 		putfull(wbuf)
-		w.wbuf2 = wbufptrOf(getempty())
-	} else if wbuf := w.wbuf1.ptr(); wbuf.nobj > 4 {
-		w.wbuf1 = wbufptrOf(handoff(wbuf))
+		w.wbuf2 = getempty()
+	} else if wbuf := w.wbuf1; wbuf.nobj > 4 {
+		w.wbuf1 = handoff(wbuf)
 	} else {
 		return
 	}
@@ -285,7 +284,7 @@ func (w *gcWork) balance() {
 // empty returns true if w has no mark work available.
 //go:nowritebarrier
 func (w *gcWork) empty() bool {
-	return w.wbuf1 == 0 || (w.wbuf1.ptr().nobj == 0 && w.wbuf2.ptr().nobj == 0)
+	return w.wbuf1 == nil || (w.wbuf1.nobj == 0 && w.wbuf2.nobj == 0)
 }
 
 // Internally, the GC work pool is kept in arrays in work buffers.
@@ -327,23 +326,56 @@ func (b *workbuf) checkempty() {
 func getempty() *workbuf {
 	var b *workbuf
 	if work.empty != 0 {
-		b = (*workbuf)(lfstackpop(&work.empty))
+		b = (*workbuf)(work.empty.pop())
 		if b != nil {
 			b.checkempty()
 		}
 	}
 	if b == nil {
-		b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), sys.CacheLineSize, &memstats.gc_sys))
+		// Allocate more workbufs.
+		var s *mspan
+		if work.wbufSpans.free.first != nil {
+			lock(&work.wbufSpans.lock)
+			s = work.wbufSpans.free.first
+			if s != nil {
+				work.wbufSpans.free.remove(s)
+				work.wbufSpans.busy.insert(s)
+			}
+			unlock(&work.wbufSpans.lock)
+		}
+		if s == nil {
+			systemstack(func() {
+				s = mheap_.allocManual(workbufAlloc/pageSize, &memstats.gc_sys)
+			})
+			if s == nil {
+				throw("out of memory")
+			}
+			// Record the new span in the busy list.
+			lock(&work.wbufSpans.lock)
+			work.wbufSpans.busy.insert(s)
+			unlock(&work.wbufSpans.lock)
+		}
+		// Slice up the span into new workbufs. Return one and
+		// put the rest on the empty list.
+		for i := uintptr(0); i+_WorkbufSize <= workbufAlloc; i += _WorkbufSize {
+			newb := (*workbuf)(unsafe.Pointer(s.base() + i))
+			newb.nobj = 0
+			if i == 0 {
+				b = newb
+			} else {
+				putempty(newb)
+			}
+		}
 	}
 	return b
 }
 
 // putempty puts a workbuf onto the work.empty list.
-// Upon entry this go routine owns b. The lfstackpush relinquishes ownership.
+// Upon entry this go routine owns b. The lfstack.push relinquishes ownership.
 //go:nowritebarrier
 func putempty(b *workbuf) {
 	b.checkempty()
-	lfstackpush(&work.empty, &b.node)
+	work.empty.push(&b.node)
 }
 
 // putfull puts the workbuf on the work.full list for the GC.
@@ -352,14 +384,14 @@ func putempty(b *workbuf) {
 //go:nowritebarrier
 func putfull(b *workbuf) {
 	b.checknonempty()
-	lfstackpush(&work.full, &b.node)
+	work.full.push(&b.node)
 }
 
 // trygetfull tries to get a full or partially empty workbuffer.
 // If one is not immediately available return nil
 //go:nowritebarrier
 func trygetfull() *workbuf {
-	b := (*workbuf)(lfstackpop(&work.full))
+	b := (*workbuf)(work.full.pop())
 	if b != nil {
 		b.checknonempty()
 		return b
@@ -380,7 +412,7 @@ func trygetfull() *workbuf {
 // phase.
 //go:nowritebarrier
 func getfull() *workbuf {
-	b := (*workbuf)(lfstackpop(&work.full))
+	b := (*workbuf)(work.full.pop())
 	if b != nil {
 		b.checknonempty()
 		return b
@@ -398,7 +430,7 @@ func getfull() *workbuf {
 				println("runtime: work.nwait=", decnwait, "work.nproc=", work.nproc)
 				throw("work.nwait > work.nproc")
 			}
-			b = (*workbuf)(lfstackpop(&work.full))
+			b = (*workbuf)(work.full.pop())
 			if b != nil {
 				b.checknonempty()
 				return b
@@ -412,15 +444,11 @@ func getfull() *workbuf {
 		if work.nwait == work.nproc && work.markrootNext >= work.markrootJobs {
 			return nil
 		}
-		_g_ := getg()
 		if i < 10 {
-			_g_.m.gcstats.nprocyield++
 			procyield(20)
 		} else if i < 20 {
-			_g_.m.gcstats.nosyield++
 			osyield()
 		} else {
-			_g_.m.gcstats.nsleep++
 			usleep(100)
 		}
 	}
@@ -434,11 +462,49 @@ func handoff(b *workbuf) *workbuf {
 	b.nobj -= n
 	b1.nobj = n
 	memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), uintptr(n)*unsafe.Sizeof(b1.obj[0]))
-	_g_ := getg()
-	_g_.m.gcstats.nhandoff++
-	_g_.m.gcstats.nhandoffcnt += uint64(n)
 
 	// Put b on full list - let first half of b get stolen.
 	putfull(b)
 	return b1
 }
+
+// prepareFreeWorkbufs moves busy workbuf spans to free list so they
+// can be freed to the heap. This must only be called when all
+// workbufs are on the empty list.
+func prepareFreeWorkbufs() {
+	lock(&work.wbufSpans.lock)
+	if work.full != 0 {
+		throw("cannot free workbufs when work.full != 0")
+	}
+	// Since all workbufs are on the empty list, we don't care
+	// which ones are in which spans. We can wipe the entire empty
+	// list and move all workbuf spans to the free list.
+	work.empty = 0
+	work.wbufSpans.free.takeAll(&work.wbufSpans.busy)
+	unlock(&work.wbufSpans.lock)
+}
+
+// freeSomeWbufs frees some workbufs back to the heap and returns
+// true if it should be called again to free more.
+func freeSomeWbufs(preemptible bool) bool {
+	const batchSize = 64 // ~1–2 µs per span.
+	lock(&work.wbufSpans.lock)
+	if gcphase != _GCoff || work.wbufSpans.free.isEmpty() {
+		unlock(&work.wbufSpans.lock)
+		return false
+	}
+	systemstack(func() {
+		gp := getg().m.curg
+		for i := 0; i < batchSize && !(preemptible && gp.preempt); i++ {
+			span := work.wbufSpans.free.first
+			if span == nil {
+				break
+			}
+			work.wbufSpans.free.remove(span)
+			mheap_.freeManual(span, &memstats.gc_sys)
+		}
+	})
+	more := !work.wbufSpans.free.isEmpty()
+	unlock(&work.wbufSpans.lock)
+	return more
+}
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index ef62eff..60676ab 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -29,12 +29,13 @@ const minPhysPageSize = 4096
 //go:notinheap
 type mheap struct {
 	lock      mutex
-	free      [_MaxMHeapList]mSpanList // free lists of given length
-	freelarge mSpanList                // free lists length >= _MaxMHeapList
-	busy      [_MaxMHeapList]mSpanList // busy lists of large objects of given length
-	busylarge mSpanList                // busy lists of large objects length >= _MaxMHeapList
+	free      [_MaxMHeapList]mSpanList // free lists of given length up to _MaxMHeapList
+	freelarge mTreap                   // free treap of length >= _MaxMHeapList
+	busy      [_MaxMHeapList]mSpanList // busy lists of large spans of given length
+	busylarge mSpanList                // busy lists of large spans length >= _MaxMHeapList
 	sweepgen  uint32                   // sweep generation, see comment in mspan
 	sweepdone uint32                   // all spans are swept
+	sweepers  uint32                   // number of active sweepone calls
 
 	// allspans is a slice of all mspans ever created. Each mspan
 	// appears exactly once.
@@ -74,37 +75,82 @@ type mheap struct {
 	_ uint32 // align uint64 fields on 32-bit for atomics
 
 	// Proportional sweep
-	pagesInUse        uint64  // pages of spans in stats _MSpanInUse; R/W with mheap.lock
-	spanBytesAlloc    uint64  // bytes of spans allocated this cycle; updated atomically
-	pagesSwept        uint64  // pages swept this cycle; updated atomically
-	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
+	//
+	// These parameters represent a linear function from heap_live
+	// to page sweep count. The proportional sweep system works to
+	// stay in the black by keeping the current page sweep count
+	// above this line at the current heap_live.
+	//
+	// The line has slope sweepPagesPerByte and passes through a
+	// basis point at (sweepHeapLiveBasis, pagesSweptBasis). At
+	// any given time, the system is at (memstats.heap_live,
+	// pagesSwept) in this space.
+	//
+	// It's important that the line pass through a point we
+	// control rather than simply starting at a (0,0) origin
+	// because that lets us adjust sweep pacing at any time while
+	// accounting for current progress. If we could only adjust
+	// the slope, it would create a discontinuity in debt if any
+	// progress has already been made.
+	pagesInUse         uint64  // pages of spans in stats _MSpanInUse; R/W with mheap.lock
+	pagesSwept         uint64  // pages swept this cycle; updated atomically
+	pagesSweptBasis    uint64  // pagesSwept to use as the origin of the sweep ratio; updated atomically
+	sweepHeapLiveBasis uint64  // value of heap_live to use as the origin of sweep ratio; written with lock, read without
+	sweepPagesPerByte  float64 // proportional sweep ratio; written with lock, read without
 	// TODO(austin): pagesInUse should be a uintptr, but the 386
 	// compiler can't 8-byte align fields.
 
 	// Malloc stats.
-	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
-	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
-	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
+	largealloc  uint64                  // bytes allocated for large objects
+	nlargealloc uint64                  // number of large object allocations
+	largefree   uint64                  // bytes freed for large objects (>maxsmallsize)
+	nlargefree  uint64                  // number of frees for large objects (>maxsmallsize)
+	nsmallfree  [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
 
 	// range of addresses we might see in the heap
-	bitmap         uintptr // 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
-	arena_end      uintptr
+	bitmap        uintptr // Points to one byte past the end of the bitmap
+	bitmap_mapped uintptr
+
+	// The arena_* fields indicate the addresses of the Go heap.
+	//
+	// The maximum range of the Go heap is
+	// [arena_start, arena_start+_MaxMem+1).
+	//
+	// The range of the current Go heap is
+	// [arena_start, arena_used). Parts of this range may not be
+	// mapped, but the metadata structures are always mapped for
+	// the full range.
+	arena_start uintptr
+	arena_used  uintptr // Set with setArenaUsed.
+
+	// The heap is grown using a linear allocator that allocates
+	// from the block [arena_alloc, arena_end). arena_alloc is
+	// often, but *not always* equal to arena_used.
+	arena_alloc uintptr
+	arena_end   uintptr
+
+	// arena_reserved indicates that the memory [arena_alloc,
+	// arena_end) is reserved (e.g., mapped PROT_NONE). If this is
+	// false, we have to be careful not to clobber existing
+	// mappings here. If this is true, then we own the mapping
+	// here and *must* clobber it to use it.
 	arena_reserved bool
 
+	_ uint32 // ensure 64-bit alignment
+
 	// central free lists for small size classes.
 	// the padding makes sure that the MCentrals are
 	// spaced CacheLineSize bytes apart, so that each MCentral.lock
 	// gets its own cache line.
-	central [_NumSizeClasses]struct {
+	// central is indexed by spanClass.
+	central [numSpanClasses]struct {
 		mcentral mcentral
-		pad      [sys.CacheLineSize]byte
+		pad      [sys.CacheLineSize - unsafe.Sizeof(mcentral{})%sys.CacheLineSize]byte
 	}
 
 	spanalloc             fixalloc // allocator for span*
 	cachealloc            fixalloc // allocator for mcache*
+	treapalloc            fixalloc // allocator for treapNodes* used by large objects
 	specialfinalizeralloc fixalloc // allocator for specialfinalizer*
 	specialprofilealloc   fixalloc // allocator for specialprofile*
 	speciallock           mutex    // lock for special record allocators.
@@ -117,7 +163,7 @@ var mheap_ mheap
 // When a MSpan is in the heap free list, state == MSpanFree
 // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
 //
-// When a MSpan is allocated, state == MSpanInUse or MSpanStack
+// When a MSpan is allocated, state == MSpanInUse or MSpanManual
 // and heapmap(i) == span for all s->start <= i < s->start+s->npages.
 
 // Every MSpan is in one doubly-linked list,
@@ -125,25 +171,25 @@ var mheap_ mheap
 // MCentral's span lists.
 
 // An MSpan representing actual memory has state _MSpanInUse,
-// _MSpanStack, or _MSpanFree. Transitions between these states are
+// _MSpanManual, or _MSpanFree. Transitions between these states are
 // constrained as follows:
 //
-// * A span may transition from free to in-use or stack during any GC
+// * A span may transition from free to in-use or manual during any GC
 //   phase.
 //
 // * During sweeping (gcphase == _GCoff), a span may transition from
-//   in-use to free (as a result of sweeping) or stack to free (as a
+//   in-use to free (as a result of sweeping) or manual to free (as a
 //   result of stacks being freed).
 //
 // * During GC (gcphase != _GCoff), a span *must not* transition from
-//   stack or in-use to free. Because concurrent GC may read a pointer
+//   manual or in-use to free. Because concurrent GC may read a pointer
 //   and then look up its span, the span state must be monotonic.
 type mSpanState uint8
 
 const (
-	_MSpanDead  mSpanState = iota
-	_MSpanInUse            // allocated for garbage collected heap
-	_MSpanStack            // allocated for use by stack allocator
+	_MSpanDead   mSpanState = iota
+	_MSpanInUse             // allocated for garbage collected heap
+	_MSpanManual            // allocated for manual management (e.g., stack allocator)
 	_MSpanFree
 )
 
@@ -152,7 +198,7 @@ const (
 var mSpanStateNames = []string{
 	"_MSpanDead",
 	"_MSpanInUse",
-	"_MSpanStack",
+	"_MSpanManual",
 	"_MSpanFree",
 }
 
@@ -170,15 +216,16 @@ type mspan struct {
 	prev *mspan     // previous span in list, or nil if none
 	list *mSpanList // For debugging. TODO: Remove.
 
-	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
+	startAddr uintptr // address of first byte of span aka s.base()
+	npages    uintptr // number of pages in span
+
+	manualFreeList gclinkptr // list of free objects in _MSpanManual spans
 
 	// 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.
+	// just past the newly discovered free object.
 	//
 	// If freeindex == nelem, this span has no free objects.
 	//
@@ -224,8 +271,8 @@ type mspan struct {
 	// 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
+	allocBits  *gcBits
+	gcmarkBits *gcBits
 
 	// sweep generation:
 	// if sweepgen == h->sweepgen - 2, the span needs sweeping
@@ -236,8 +283,8 @@ type mspan struct {
 	sweepgen    uint32
 	divMul      uint16     // for divide by elemsize - divMagic.mul
 	baseMask    uint16     // if non-0, elemsize is a power of 2, & this will get object allocation base
-	allocCount  uint16     // capacity - number of objects in freelist
-	sizeclass   uint8      // size class
+	allocCount  uint16     // number of allocated objects
+	spanclass   spanClass  // size class and noscan (uint8)
 	incache     bool       // being used by an mcache
 	state       mSpanState // mspaninuse etc
 	needzero    uint8      // needs to be zeroed before allocation
@@ -292,8 +339,33 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
 	h.allspans = append(h.allspans, s)
 }
 
+// A spanClass represents the size class and noscan-ness of a span.
+//
+// Each size class has a noscan spanClass and a scan spanClass. The
+// noscan spanClass contains only noscan objects, which do not contain
+// pointers and thus do not need to be scanned by the garbage
+// collector.
+type spanClass uint8
+
+const (
+	numSpanClasses = _NumSizeClasses << 1
+	tinySpanClass  = spanClass(tinySizeClass<<1 | 1)
+)
+
+func makeSpanClass(sizeclass uint8, noscan bool) spanClass {
+	return spanClass(sizeclass<<1) | spanClass(bool2int(noscan))
+}
+
+func (sc spanClass) sizeclass() int8 {
+	return int8(sc >> 1)
+}
+
+func (sc spanClass) noscan() bool {
+	return sc&1 != 0
+}
+
 // inheap reports whether b is a pointer into a (potentially dead) heap object.
-// It returns false for pointers into stack spans.
+// It returns false for pointers into _MSpanManual spans.
 // Non-preemptible because it is used by write barriers.
 //go:nowritebarrier
 //go:nosplit
@@ -309,7 +381,9 @@ func inheap(b uintptr) bool {
 	return true
 }
 
-// inHeapOrStack is a variant of inheap that returns true for pointers into stack spans.
+// inHeapOrStack is a variant of inheap that returns true for pointers
+// into any allocated heap span.
+//
 //go:nowritebarrier
 //go:nosplit
 func inHeapOrStack(b uintptr) bool {
@@ -322,10 +396,8 @@ func inHeapOrStack(b uintptr) bool {
 		return false
 	}
 	switch s.state {
-	case mSpanInUse:
+	case mSpanInUse, _MSpanManual:
 		return b < s.limit
-	case _MSpanStack:
-		return b < s.base()+s.npages<<_PageShift
 	default:
 		return false
 	}
@@ -376,7 +448,7 @@ func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
 	}
 
 	p := s.base()
-	if s.sizeclass == 0 {
+	if s.spanclass.sizeclass() == 0 {
 		// Large object.
 		if base != nil {
 			*base = p
@@ -401,6 +473,7 @@ func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
 
 // Initialize the heap.
 func (h *mheap) init(spansStart, spansBytes uintptr) {
+	h.treapalloc.init(unsafe.Sizeof(treapNode{}), nil, nil, &memstats.other_sys)
 	h.spanalloc.init(unsafe.Sizeof(mspan{}), recordspan, unsafe.Pointer(h), &memstats.mspan_sys)
 	h.cachealloc.init(unsafe.Sizeof(mcache{}), nil, nil, &memstats.mcache_sys)
 	h.specialfinalizeralloc.init(unsafe.Sizeof(specialfinalizer{}), nil, nil, &memstats.other_sys)
@@ -421,10 +494,9 @@ func (h *mheap) init(spansStart, spansBytes uintptr) {
 		h.busy[i].init()
 	}
 
-	h.freelarge.init()
 	h.busylarge.init()
 	for i := range h.central {
-		h.central[i].mcentral.init(int32(i))
+		h.central[i].mcentral.init(spanClass(i))
 	}
 
 	sp := (*slice)(unsafe.Pointer(&h.spans))
@@ -433,14 +505,35 @@ func (h *mheap) init(spansStart, spansBytes uintptr) {
 	sp.cap = int(spansBytes / sys.PtrSize)
 }
 
-// mHeap_MapSpans makes sure that the spans are mapped
+// setArenaUsed extends the usable arena to address arena_used and
+// maps auxiliary VM regions for any newly usable arena space.
+//
+// racemap indicates that this memory should be managed by the race
+// detector. racemap should be true unless this is covering a VM hole.
+func (h *mheap) setArenaUsed(arena_used uintptr, racemap bool) {
+	// Map auxiliary structures *before* h.arena_used is updated.
+	// Waiting to update arena_used until after the memory has been mapped
+	// avoids faults when other threads try access these regions immediately
+	// after observing the change to arena_used.
+
+	// Map the bitmap.
+	h.mapBits(arena_used)
+
+	// Map spans array.
+	h.mapSpans(arena_used)
+
+	// Tell the race detector about the new heap memory.
+	if racemap && raceenabled {
+		racemapshadow(unsafe.Pointer(h.arena_used), arena_used-h.arena_used)
+	}
+
+	h.arena_used = arena_used
+}
+
+// mapSpans makes sure that the spans are mapped
 // up to the new value of arena_used.
 //
-// It must be called with the expected new value of arena_used,
-// *before* h.arena_used has been updated.
-// Waiting to update arena_used until after the memory has been mapped
-// avoids faults when other threads try access the bitmap immediately
-// after observing the change to arena_used.
+// Don't call this directly. Call mheap.setArenaUsed.
 func (h *mheap) mapSpans(arena_used uintptr) {
 	// Map spans array, PageSize at a time.
 	n := arena_used
@@ -466,7 +559,7 @@ retry:
 		if s.sweepgen == sg-2 && atomic.Cas(&s.sweepgen, sg-2, sg-1) {
 			list.remove(s)
 			// swept spans are at the end of the list
-			list.insertBack(s)
+			list.insertBack(s) // Puts it back on a busy list. s is not in the treap at this point.
 			unlock(&h.lock)
 			snpages := s.npages
 			if s.sweep(false) {
@@ -533,7 +626,7 @@ func (h *mheap) reclaim(npage uintptr) {
 
 // Allocate a new span of npage pages from the heap for GC'd memory
 // and record its size class in the HeapMap and HeapMapCache.
-func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
+func (h *mheap) alloc_m(npage uintptr, spanclass spanClass, large bool) *mspan {
 	_g_ := getg()
 	if _g_ != _g_.m.g0 {
 		throw("_mheap_alloc not on g0 stack")
@@ -550,7 +643,13 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 		// If GC kept a bit for whether there were any marks
 		// in a span, we could release these free spans
 		// at the end of GC and eliminate this entirely.
+		if trace.enabled {
+			traceGCSweepStart()
+		}
 		h.reclaim(npage)
+		if trace.enabled {
+			traceGCSweepDone()
+		}
 	}
 
 	// transfer stats from cache to global
@@ -559,7 +658,7 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 	memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
 	_g_.m.mcache.local_tinyallocs = 0
 
-	s := h.allocSpanLocked(npage)
+	s := h.allocSpanLocked(npage, &memstats.heap_inuse)
 	if s != nil {
 		// Record span info, because gc needs to be
 		// able to map interior pointer to containing span.
@@ -567,8 +666,8 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 		h.sweepSpans[h.sweepgen/2%2].push(s) // Add to swept in-use list.
 		s.state = _MSpanInUse
 		s.allocCount = 0
-		s.sizeclass = uint8(sizeclass)
-		if sizeclass == 0 {
+		s.spanclass = spanclass
+		if sizeclass := spanclass.sizeclass(); sizeclass == 0 {
 			s.elemsize = s.npages << _PageShift
 			s.divShift = 0
 			s.divMul = 0
@@ -587,9 +686,11 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 		h.pagesInUse += uint64(npage)
 		if large {
 			memstats.heap_objects++
+			mheap_.largealloc += uint64(s.elemsize)
+			mheap_.nlargealloc++
 			atomic.Xadd64(&memstats.heap_live, int64(npage<<_PageShift))
 			// Swept spans are at the end of lists.
-			if s.npages < uintptr(len(h.free)) {
+			if s.npages < uintptr(len(h.busy)) {
 				h.busy[s.npages].insertBack(s)
 			} else {
 				h.busylarge.insertBack(s)
@@ -618,13 +719,13 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 	return s
 }
 
-func (h *mheap) alloc(npage uintptr, sizeclass int32, large bool, needzero bool) *mspan {
+func (h *mheap) alloc(npage uintptr, spanclass spanClass, large bool, needzero bool) *mspan {
 	// Don't do any operations that lock the heap on the G stack.
 	// It might trigger stack growth, and the stack growth code needs
 	// to be able to allocate heap.
 	var s *mspan
 	systemstack(func() {
-		s = h.alloc_m(npage, sizeclass, large)
+		s = h.alloc_m(npage, spanclass, large)
 	})
 
 	if s != nil {
@@ -636,29 +737,46 @@ func (h *mheap) alloc(npage uintptr, sizeclass int32, large bool, needzero bool)
 	return s
 }
 
-func (h *mheap) allocStack(npage uintptr) *mspan {
-	_g_ := getg()
-	if _g_ != _g_.m.g0 {
-		throw("mheap_allocstack not on g0 stack")
-	}
+// allocManual allocates a manually-managed span of npage pages.
+// allocManual returns nil if allocation fails.
+//
+// allocManual adds the bytes used to *stat, which should be a
+// memstats in-use field. Unlike allocations in the GC'd heap, the
+// allocation does *not* count toward heap_inuse or heap_sys.
+//
+// The memory backing the returned span may not be zeroed if
+// span.needzero is set.
+//
+// allocManual must be called on the system stack to prevent stack
+// growth. Since this is used by the stack allocator, stack growth
+// during allocManual would self-deadlock.
+//
+//go:systemstack
+func (h *mheap) allocManual(npage uintptr, stat *uint64) *mspan {
 	lock(&h.lock)
-	s := h.allocSpanLocked(npage)
+	s := h.allocSpanLocked(npage, stat)
 	if s != nil {
-		s.state = _MSpanStack
-		s.stackfreelist = 0
+		s.state = _MSpanManual
+		s.manualFreeList = 0
 		s.allocCount = 0
-		memstats.stacks_inuse += uint64(s.npages << _PageShift)
+		s.spanclass = 0
+		s.nelems = 0
+		s.elemsize = 0
+		s.limit = s.base() + s.npages<<_PageShift
+		// Manually manged memory doesn't count toward heap_sys.
+		memstats.heap_sys -= uint64(s.npages << _PageShift)
 	}
 
-	// This unlock acts as a release barrier. See mHeap_Alloc_m.
+	// This unlock acts as a release barrier. See mheap.alloc_m.
 	unlock(&h.lock)
+
 	return s
 }
 
 // Allocates a span of the given size.  h must be locked.
 // The returned span has been removed from the
 // free list, but its state is still MSpanFree.
-func (h *mheap) allocSpanLocked(npage uintptr) *mspan {
+func (h *mheap) allocSpanLocked(npage uintptr, stat *uint64) *mspan {
 	var list *mSpanList
 	var s *mspan
 
@@ -667,13 +785,12 @@ func (h *mheap) allocSpanLocked(npage uintptr) *mspan {
 		list = &h.free[i]
 		if !list.isEmpty() {
 			s = list.first
+			list.remove(s)
 			goto HaveSpan
 		}
 	}
-
 	// Best fit in list of large spans.
-	list = &h.freelarge
-	s = h.allocLarge(npage)
+	s = h.allocLarge(npage) // allocLarge removed s from h.freelarge for us
 	if s == nil {
 		if !h.grow(npage) {
 			return nil
@@ -692,10 +809,6 @@ HaveSpan:
 	if s.npages < npage {
 		throw("MHeap_AllocLocked - bad npages")
 	}
-	list.remove(s)
-	if s.inList() {
-		throw("still in list")
-	}
 	if s.npreleased > 0 {
 		sysUsed(unsafe.Pointer(s.base()), s.npages<<_PageShift)
 		memstats.heap_released -= uint64(s.npreleased << _PageShift)
@@ -714,8 +827,8 @@ HaveSpan:
 		h.spans[p] = t
 		h.spans[p+t.npages-1] = t
 		t.needzero = s.needzero
-		s.state = _MSpanStack // prevent coalescing with s
-		t.state = _MSpanStack
+		s.state = _MSpanManual // prevent coalescing with s
+		t.state = _MSpanManual
 		h.freeSpanLocked(t, false, false, s.unusedsince)
 		s.state = _MSpanFree
 	}
@@ -726,7 +839,7 @@ HaveSpan:
 		h.spans[p+n] = s
 	}
 
-	memstats.heap_inuse += uint64(npage << _PageShift)
+	*stat += uint64(npage << _PageShift)
 	memstats.heap_idle -= uint64(npage << _PageShift)
 
 	//println("spanalloc", hex(s.start<<_PageShift))
@@ -736,24 +849,24 @@ HaveSpan:
 	return s
 }
 
-// Allocate a span of exactly npage pages from the list of large spans.
+// Large spans have a minimum size of 1MByte. The maximum number of large spans to support
+// 1TBytes is 1 million, experimentation using random sizes indicates that the depth of
+// the tree is less that 2x that of a perfectly balanced tree. For 1TByte can be referenced
+// by a perfectly balanced tree with a a depth of 20. Twice that is an acceptable 40.
+func (h *mheap) isLargeSpan(npages uintptr) bool {
+	return npages >= uintptr(len(h.free))
+}
+
+// Allocate a span of exactly npage pages from the treap of large spans.
 func (h *mheap) allocLarge(npage uintptr) *mspan {
-	return bestFit(&h.freelarge, npage, nil)
+	return bestFitTreap(&h.freelarge, npage)
 }
 
-// Search list for smallest span with >= npage pages.
-// If there are multiple smallest spans, take the one
+// Search treap for smallest span with >= npage pages.
+// If there are multiple smallest spans, select the one
 // with the earliest starting address.
-func bestFit(list *mSpanList, npage uintptr, best *mspan) *mspan {
-	for s := list.first; s != nil; s = s.next {
-		if s.npages < npage {
-			continue
-		}
-		if best == nil || s.npages < best.npages || (s.npages == best.npages && s.base() < best.base()) {
-			best = s
-		}
-	}
-	return best
+func bestFitTreap(treap *mTreap, npage uintptr) *mspan {
+	return treap.remove(npage)
 }
 
 // Try to add at least npage pages of memory to the heap,
@@ -852,22 +965,30 @@ func (h *mheap) freeSpan(s *mspan, acct int32) {
 	})
 }
 
-func (h *mheap) freeStack(s *mspan) {
-	_g_ := getg()
-	if _g_ != _g_.m.g0 {
-		throw("mheap_freestack not on g0 stack")
-	}
+// freeManual frees a manually-managed span returned by allocManual.
+// stat must be the same as the stat passed to the allocManual that
+// allocated s.
+//
+// This must only be called when gcphase == _GCoff. See mSpanState for
+// an explanation.
+//
+// freeManual must be called on the system stack to prevent stack
+// growth, just like allocManual.
+//
+//go:systemstack
+func (h *mheap) freeManual(s *mspan, stat *uint64) {
 	s.needzero = 1
 	lock(&h.lock)
-	memstats.stacks_inuse -= uint64(s.npages << _PageShift)
-	h.freeSpanLocked(s, true, true, 0)
+	*stat -= uint64(s.npages << _PageShift)
+	memstats.heap_sys += uint64(s.npages << _PageShift)
+	h.freeSpanLocked(s, false, true, 0)
 	unlock(&h.lock)
 }
 
 // s must be on a busy list (h.busy or h.busylarge) or unlinked.
 func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool, unusedsince int64) {
 	switch s.state {
-	case _MSpanStack:
+	case _MSpanManual:
 		if s.allocCount != 0 {
 			throw("MHeap_FreeSpanLocked - invalid stack free")
 		}
@@ -903,50 +1024,98 @@ func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool, unusedsince i
 	// Coalesce with earlier, later spans.
 	p := (s.base() - h.arena_start) >> _PageShift
 	if p > 0 {
-		t := h.spans[p-1]
-		if t != nil && t.state == _MSpanFree {
-			s.startAddr = t.startAddr
-			s.npages += t.npages
-			s.npreleased = t.npreleased // absorb released pages
-			s.needzero |= t.needzero
-			p -= t.npages
+		before := h.spans[p-1]
+		if before != nil && before.state == _MSpanFree {
+			// Now adjust s.
+			s.startAddr = before.startAddr
+			s.npages += before.npages
+			s.npreleased = before.npreleased // absorb released pages
+			s.needzero |= before.needzero
+			p -= before.npages
 			h.spans[p] = s
-			h.freeList(t.npages).remove(t)
-			t.state = _MSpanDead
-			h.spanalloc.free(unsafe.Pointer(t))
+			// The size is potentially changing so the treap needs to delete adjacent nodes and
+			// insert back as a combined node.
+			if h.isLargeSpan(before.npages) {
+				// We have a t, it is large so it has to be in the treap so we can remove it.
+				h.freelarge.removeSpan(before)
+			} else {
+				h.freeList(before.npages).remove(before)
+			}
+			before.state = _MSpanDead
+			h.spanalloc.free(unsafe.Pointer(before))
 		}
 	}
+
+	// Now check to see if next (greater addresses) span is free and can be coalesced.
 	if (p + s.npages) < uintptr(len(h.spans)) {
-		t := h.spans[p+s.npages]
-		if t != nil && t.state == _MSpanFree {
-			s.npages += t.npages
-			s.npreleased += t.npreleased
-			s.needzero |= t.needzero
+		after := h.spans[p+s.npages]
+		if after != nil && after.state == _MSpanFree {
+			s.npages += after.npages
+			s.npreleased += after.npreleased
+			s.needzero |= after.needzero
 			h.spans[p+s.npages-1] = s
-			h.freeList(t.npages).remove(t)
-			t.state = _MSpanDead
-			h.spanalloc.free(unsafe.Pointer(t))
+			if h.isLargeSpan(after.npages) {
+				h.freelarge.removeSpan(after)
+			} else {
+				h.freeList(after.npages).remove(after)
+			}
+			after.state = _MSpanDead
+			h.spanalloc.free(unsafe.Pointer(after))
 		}
 	}
 
-	// Insert s into appropriate list.
-	h.freeList(s.npages).insert(s)
+	// Insert s into appropriate list or treap.
+	if h.isLargeSpan(s.npages) {
+		h.freelarge.insert(s)
+	} else {
+		h.freeList(s.npages).insert(s)
+	}
 }
 
 func (h *mheap) freeList(npages uintptr) *mSpanList {
-	if npages < uintptr(len(h.free)) {
-		return &h.free[npages]
-	}
-	return &h.freelarge
+	return &h.free[npages]
 }
 
 func (h *mheap) busyList(npages uintptr) *mSpanList {
-	if npages < uintptr(len(h.free)) {
+	if npages < uintptr(len(h.busy)) {
 		return &h.busy[npages]
 	}
 	return &h.busylarge
 }
 
+func scavengeTreapNode(t *treapNode, now, limit uint64) uintptr {
+	s := t.spanKey
+	var sumreleased uintptr
+	if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages {
+		start := s.base()
+		end := start + s.npages<<_PageShift
+		if 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 + physPageSize - 1) &^ (physPageSize - 1)
+			end &^= physPageSize - 1
+			if end <= start {
+				// start and end don't span a
+				// whole physical page.
+				return sumreleased
+			}
+		}
+		len := end - start
+		released := len - (s.npreleased << _PageShift)
+		if physPageSize > _PageSize && released == 0 {
+			return sumreleased
+		}
+		memstats.heap_released += uint64(released)
+		sumreleased += released
+		s.npreleased = len >> _PageShift
+		sysUnused(unsafe.Pointer(start), len)
+	}
+	return sumreleased
+}
+
 func scavengelist(list *mSpanList, now, limit uint64) uintptr {
 	if list.isEmpty() {
 		return 0
@@ -987,27 +1156,31 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr {
 }
 
 func (h *mheap) scavenge(k int32, now, limit uint64) {
+	// Disallow malloc or panic while holding the heap lock. We do
+	// this here because this is an non-mallocgc entry-point to
+	// the mheap API.
+	gp := getg()
+	gp.m.mallocing++
 	lock(&h.lock)
 	var sumreleased uintptr
 	for i := 0; i < len(h.free); i++ {
 		sumreleased += scavengelist(&h.free[i], now, limit)
 	}
-	sumreleased += scavengelist(&h.freelarge, now, limit)
+	sumreleased += scavengetreap(h.freelarge.treap, now, limit)
 	unlock(&h.lock)
+	gp.m.mallocing--
 
 	if debug.gctrace > 0 {
 		if sumreleased > 0 {
 			print("scvg", k, ": ", sumreleased>>20, " MB released\n")
 		}
-		// TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
-		// But we can't call ReadMemStats on g0 holding locks.
 		print("scvg", k, ": inuse: ", memstats.heap_inuse>>20, ", idle: ", memstats.heap_idle>>20, ", sys: ", memstats.heap_sys>>20, ", released: ", memstats.heap_released>>20, ", consumed: ", (memstats.heap_sys-memstats.heap_released)>>20, " (MB)\n")
 	}
 }
 
 //go:linkname runtime_debug_freeOSMemory runtime/debug.freeOSMemory
 func runtime_debug_freeOSMemory() {
-	gcStart(gcForceBlockMode, false)
+	GC()
 	systemstack(func() { mheap_.scavenge(-1, ^uint64(0), 0) })
 }
 
@@ -1020,7 +1193,7 @@ func (span *mspan) init(base uintptr, npages uintptr) {
 	span.startAddr = base
 	span.npages = npages
 	span.allocCount = 0
-	span.sizeclass = 0
+	span.spanclass = 0
 	span.incache = false
 	span.elemsize = 0
 	span.state = _MSpanDead
@@ -1046,7 +1219,8 @@ func (list *mSpanList) init() {
 
 func (list *mSpanList) remove(span *mspan) {
 	if span.list != list {
-		println("runtime: failed MSpanList_Remove", span, span.prev, span.list, list)
+		print("runtime: failed MSpanList_Remove span.npages=", span.npages,
+			" span=", span, " prev=", span.prev, " span.list=", span.list, " list=", list, "\n")
 		throw("MSpanList_Remove")
 	}
 	if list.first == span {
@@ -1088,7 +1262,7 @@ func (list *mSpanList) insert(span *mspan) {
 
 func (list *mSpanList) insertBack(span *mspan) {
 	if span.next != nil || span.prev != nil || span.list != nil {
-		println("failed MSpanList_InsertBack", span, span.next, span.prev, span.list)
+		println("runtime: failed MSpanList_InsertBack", span, span.next, span.prev, span.list)
 		throw("MSpanList_InsertBack")
 	}
 	span.prev = list.last
@@ -1103,6 +1277,31 @@ func (list *mSpanList) insertBack(span *mspan) {
 	span.list = list
 }
 
+// takeAll removes all spans from other and inserts them at the front
+// of list.
+func (list *mSpanList) takeAll(other *mSpanList) {
+	if other.isEmpty() {
+		return
+	}
+
+	// Reparent everything in other to list.
+	for s := other.first; s != nil; s = s.next {
+		s.list = list
+	}
+
+	// Concatenate the lists.
+	if list.isEmpty() {
+		*list = *other
+	} else {
+		// Neither list is empty. Put other before list.
+		other.last.next = list.first
+		list.first.prev = other.last
+		list.first = other.first
+	}
+
+	other.first, other.last = nil, nil
+}
+
 const (
 	_KindSpecialFinalizer = 1
 	_KindSpecialProfile   = 2
@@ -1316,6 +1515,22 @@ func freespecial(s *special, p unsafe.Pointer, size uintptr) {
 	}
 }
 
+// gcBits is an alloc/mark bitmap. This is always used as *gcBits.
+//
+//go:notinheap
+type gcBits uint8
+
+// bytep returns a pointer to the n'th byte of b.
+func (b *gcBits) bytep(n uintptr) *uint8 {
+	return addb((*uint8)(b), n)
+}
+
+// bitp returns a pointer to the byte containing bit n and a mask for
+// selecting that bit from *bytep.
+func (b *gcBits) bitp(n uintptr) (bytep *uint8, mask uint8) {
+	return b.bytep(n / 8), 1 << (n % 8)
+}
+
 const gcBitsChunkBytes = uintptr(64 << 10)
 const gcBitsHeaderBytes = unsafe.Sizeof(gcBitsHeader{})
 
@@ -1325,42 +1540,87 @@ type gcBitsHeader struct {
 }
 
 //go:notinheap
-type gcBits struct {
+type gcBitsArena 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
+	free uintptr // free is the index into bits of the next free byte; read/write atomically
+	next *gcBitsArena
+	bits [gcBitsChunkBytes - gcBitsHeaderBytes]gcBits
 }
 
 var gcBitsArenas struct {
 	lock     mutex
-	free     *gcBits
-	next     *gcBits
-	current  *gcBits
-	previous *gcBits
+	free     *gcBitsArena
+	next     *gcBitsArena // Read atomically. Write atomically under lock.
+	current  *gcBitsArena
+	previous *gcBitsArena
+}
+
+// tryAlloc allocates from b or returns nil if b does not have enough room.
+// This is safe to call concurrently.
+func (b *gcBitsArena) tryAlloc(bytes uintptr) *gcBits {
+	if b == nil || atomic.Loaduintptr(&b.free)+bytes > uintptr(len(b.bits)) {
+		return nil
+	}
+	// Try to allocate from this block.
+	end := atomic.Xadduintptr(&b.free, bytes)
+	if end > uintptr(len(b.bits)) {
+		return nil
+	}
+	// There was enough room.
+	start := end - bytes
+	return &b.bits[start]
 }
 
 // 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)
+func newMarkBits(nelems uintptr) *gcBits {
 	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)
+
+	// Try directly allocating from the current head arena.
+	head := (*gcBitsArena)(atomic.Loadp(unsafe.Pointer(&gcBitsArenas.next)))
+	if p := head.tryAlloc(bytesNeeded); p != nil {
+		return p
+	}
+
+	// There's not enough room in the head arena. We may need to
+	// allocate a new arena.
+	lock(&gcBitsArenas.lock)
+	// Try the head arena again, since it may have changed. Now
+	// that we hold the lock, the list head can't change, but its
+	// free position still can.
+	if p := gcBitsArenas.next.tryAlloc(bytesNeeded); p != nil {
+		unlock(&gcBitsArenas.lock)
+		return p
+	}
+
+	// Allocate a new arena. This may temporarily drop the lock.
+	fresh := newArenaMayUnlock()
+	// If newArenaMayUnlock dropped the lock, another thread may
+	// have put a fresh arena on the "next" list. Try allocating
+	// from next again.
+	if p := gcBitsArenas.next.tryAlloc(bytesNeeded); p != nil {
+		// Put fresh back on the free list.
+		// TODO: Mark it "already zeroed"
+		fresh.next = gcBitsArenas.free
+		gcBitsArenas.free = fresh
+		unlock(&gcBitsArenas.lock)
+		return p
+	}
+
+	// Allocate from the fresh arena. We haven't linked it in yet, so
+	// this cannot race and is guaranteed to succeed.
+	p := fresh.tryAlloc(bytesNeeded)
+	if p == nil {
 		throw("markBits overflow")
 	}
-	result := &gcBitsArenas.next.bits[gcBitsArenas.next.free]
-	gcBitsArenas.next.free += bytesNeeded
+
+	// Add the fresh arena to the "next" list.
+	fresh.next = gcBitsArenas.next
+	atomic.StorepNoWB(unsafe.Pointer(&gcBitsArenas.next), unsafe.Pointer(fresh))
+
 	unlock(&gcBitsArenas.lock)
-	return result
+	return p
 }
 
 // newAllocBits returns a pointer to 8 byte aligned bytes
@@ -1369,7 +1629,7 @@ func newMarkBits(nelems uintptr) *uint8 {
 // 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 {
+func newAllocBits(nelems uintptr) *gcBits {
 	return newMarkBits(nelems)
 }
 
@@ -1403,18 +1663,21 @@ func nextMarkBitArenaEpoch() {
 	}
 	gcBitsArenas.previous = gcBitsArenas.current
 	gcBitsArenas.current = gcBitsArenas.next
-	gcBitsArenas.next = nil // newMarkBits calls newArena when needed
+	atomic.StorepNoWB(unsafe.Pointer(&gcBitsArenas.next), nil) // newMarkBits calls newArena when needed
 	unlock(&gcBitsArenas.lock)
 }
 
-// newArena allocates and zeroes a gcBits arena.
-func newArena() *gcBits {
-	var result *gcBits
+// newArenaMayUnlock allocates and zeroes a gcBits arena.
+// The caller must hold gcBitsArena.lock. This may temporarily release it.
+func newArenaMayUnlock() *gcBitsArena {
+	var result *gcBitsArena
 	if gcBitsArenas.free == nil {
-		result = (*gcBits)(sysAlloc(gcBitsChunkBytes, &memstats.gc_sys))
+		unlock(&gcBitsArenas.lock)
+		result = (*gcBitsArena)(sysAlloc(gcBitsChunkBytes, &memstats.gc_sys))
 		if result == nil {
 			throw("runtime: cannot allocate memory")
 		}
+		lock(&gcBitsArenas.lock)
 	} else {
 		result = gcBitsArenas.free
 		gcBitsArenas.free = gcBitsArenas.free.next
@@ -1423,7 +1686,7 @@ func newArena() *gcBits {
 	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 {
+	if uintptr(unsafe.Offsetof(gcBitsArena{}.bits))&7 == 0 {
 		result.free = 0
 	} else {
 		result.free = 8 - (uintptr(unsafe.Pointer(&result.bits[0])) & 7)
diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go
index cf6b37f..d15f1f7 100644
--- a/src/runtime/mkduff.go
+++ b/src/runtime/mkduff.go
@@ -43,7 +43,7 @@ func main() {
 func gen(arch string, tags, zero, copy func(io.Writer)) {
 	var buf bytes.Buffer
 
-	fmt.Fprintln(&buf, "// AUTO-GENERATED by mkduff.go")
+	fmt.Fprintln(&buf, "// Code generated by mkduff.go; DO NOT EDIT.")
 	fmt.Fprintln(&buf, "// Run go generate from src/runtime to update.")
 	fmt.Fprintln(&buf, "// See mkduff.go for comments.")
 	tags(&buf)
diff --git a/src/runtime/mknacl.sh b/src/runtime/mknacl.sh
index 0a74db1..3454b62 100644
--- a/src/runtime/mknacl.sh
+++ b/src/runtime/mknacl.sh
@@ -6,7 +6,7 @@
 cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
 	awk '
 	BEGIN {
-		printf("// generated by mknacl.sh - do not edit\n")
+		printf("// Code generated by mknacl.sh; DO NOT EDIT.\n")
 	}
 	NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
 		name=$2
diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go
index 0f897ba..0cb2b33 100644
--- a/src/runtime/mksizeclasses.go
+++ b/src/runtime/mksizeclasses.go
@@ -48,7 +48,7 @@ func main() {
 	flag.Parse()
 
 	var b bytes.Buffer
-	fmt.Fprintln(&b, "// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT")
+	fmt.Fprintln(&b, "// Code generated by mksizeclasses.go; DO NOT EDIT.")
 	fmt.Fprintln(&b, "//go:generate go run mksizeclasses.go")
 	fmt.Fprintln(&b)
 	fmt.Fprintln(&b, "package runtime")
diff --git a/src/runtime/mmap.go b/src/runtime/mmap.go
index 53617e4..62f3780 100644
--- a/src/runtime/mmap.go
+++ b/src/runtime/mmap.go
@@ -17,3 +17,6 @@ import "unsafe"
 // 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
+
+// munmap calls the munmap system call. It is implemented in assembly.
+func munmap(addr unsafe.Pointer, n uintptr)
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index fc06d8d..2bd09b6 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -64,27 +64,70 @@ type memRecord struct {
 	// come only after a GC during concurrent sweeping. So if we would
 	// naively count them, we would get a skew toward mallocs.
 	//
-	// Mallocs are accounted in recent stats.
-	// Explicit frees are accounted in recent stats.
-	// GC frees are accounted in prev stats.
-	// After GC prev stats are added to final stats and
-	// recent stats are moved into prev stats.
-	allocs      uintptr
-	frees       uintptr
-	alloc_bytes uintptr
-	free_bytes  uintptr
-
-	// changes between next-to-last GC and last GC
-	prev_allocs      uintptr
-	prev_frees       uintptr
-	prev_alloc_bytes uintptr
-	prev_free_bytes  uintptr
-
-	// changes since last GC
-	recent_allocs      uintptr
-	recent_frees       uintptr
-	recent_alloc_bytes uintptr
-	recent_free_bytes  uintptr
+	// Hence, we delay information to get consistent snapshots as
+	// of mark termination. Allocations count toward the next mark
+	// termination's snapshot, while sweep frees count toward the
+	// previous mark termination's snapshot:
+	//
+	//              MT          MT          MT          MT
+	//             .·|         .·|         .·|         .·|
+	//          .·˙  |      .·˙  |      .·˙  |      .·˙  |
+	//       .·˙     |   .·˙     |   .·˙     |   .·˙     |
+	//    .·˙        |.·˙        |.·˙        |.·˙        |
+	//
+	//       alloc → ▲ ← free
+	//               ┠┅┅┅┅┅┅┅┅┅┅┅P
+	//       C+2     →    C+1    →  C
+	//
+	//                   alloc → ▲ ← free
+	//                           ┠┅┅┅┅┅┅┅┅┅┅┅P
+	//                   C+2     →    C+1    →  C
+	//
+	// Since we can't publish a consistent snapshot until all of
+	// the sweep frees are accounted for, we wait until the next
+	// mark termination ("MT" above) to publish the previous mark
+	// termination's snapshot ("P" above). To do this, allocation
+	// and free events are accounted to *future* heap profile
+	// cycles ("C+n" above) and we only publish a cycle once all
+	// of the events from that cycle must be done. Specifically:
+	//
+	// Mallocs are accounted to cycle C+2.
+	// Explicit frees are accounted to cycle C+2.
+	// GC frees (done during sweeping) are accounted to cycle C+1.
+	//
+	// After mark termination, we increment the global heap
+	// profile cycle counter and accumulate the stats from cycle C
+	// into the active profile.
+
+	// active is the currently published profile. A profiling
+	// cycle can be accumulated into active once its complete.
+	active memRecordCycle
+
+	// future records the profile events we're counting for cycles
+	// that have not yet been published. This is ring buffer
+	// indexed by the global heap profile cycle C and stores
+	// cycles C, C+1, and C+2. Unlike active, these counts are
+	// only for a single cycle; they are not cumulative across
+	// cycles.
+	//
+	// We store cycle C here because there's a window between when
+	// C becomes the active cycle and when we've flushed it to
+	// active.
+	future [3]memRecordCycle
+}
+
+// memRecordCycle
+type memRecordCycle struct {
+	allocs, frees           uintptr
+	alloc_bytes, free_bytes uintptr
+}
+
+// add accumulates b into a. It does not zero b.
+func (a *memRecordCycle) add(b *memRecordCycle) {
+	a.allocs += b.allocs
+	a.frees += b.frees
+	a.alloc_bytes += b.alloc_bytes
+	a.free_bytes += b.free_bytes
 }
 
 // A blockRecord is the bucket data for a bucket of type blockProfile,
@@ -100,8 +143,21 @@ var (
 	xbuckets  *bucket // mutex profile buckets
 	buckhash  *[179999]*bucket
 	bucketmem uintptr
+
+	mProf struct {
+		// All fields in mProf are protected by proflock.
+
+		// cycle is the global heap profile cycle. This wraps
+		// at mProfCycleWrap.
+		cycle uint32
+		// flushed indicates that future[cycle] in all buckets
+		// has been flushed to the active profile.
+		flushed bool
+	}
 )
 
+const mProfCycleWrap = uint32(len(memRecord{}.future)) * (2 << 24)
+
 // newBucket allocates a bucket with the given type and number of stack entries.
 func newBucket(typ bucketType, nstk int) *bucket {
 	size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(uintptr(0))
@@ -212,30 +268,71 @@ func eqslice(x, y []uintptr) bool {
 	return true
 }
 
-func mprof_GC() {
+// mProf_NextCycle publishes the next heap profile cycle and creates a
+// fresh heap profile cycle. This operation is fast and can be done
+// during STW. The caller must call mProf_Flush before calling
+// mProf_NextCycle again.
+//
+// This is called by mark termination during STW so allocations and
+// frees after the world is started again count towards a new heap
+// profiling cycle.
+func mProf_NextCycle() {
+	lock(&proflock)
+	// We explicitly wrap mProf.cycle rather than depending on
+	// uint wraparound because the memRecord.future ring does not
+	// itself wrap at a power of two.
+	mProf.cycle = (mProf.cycle + 1) % mProfCycleWrap
+	mProf.flushed = false
+	unlock(&proflock)
+}
+
+// mProf_Flush flushes the events from the current heap profiling
+// cycle into the active profile. After this it is safe to start a new
+// heap profiling cycle with mProf_NextCycle.
+//
+// This is called by GC after mark termination starts the world. In
+// contrast with mProf_NextCycle, this is somewhat expensive, but safe
+// to do concurrently.
+func mProf_Flush() {
+	lock(&proflock)
+	if !mProf.flushed {
+		mProf_FlushLocked()
+		mProf.flushed = true
+	}
+	unlock(&proflock)
+}
+
+func mProf_FlushLocked() {
+	c := mProf.cycle
 	for b := mbuckets; b != nil; b = b.allnext {
 		mp := b.mp()
-		mp.allocs += mp.prev_allocs
-		mp.frees += mp.prev_frees
-		mp.alloc_bytes += mp.prev_alloc_bytes
-		mp.free_bytes += mp.prev_free_bytes
 
-		mp.prev_allocs = mp.recent_allocs
-		mp.prev_frees = mp.recent_frees
-		mp.prev_alloc_bytes = mp.recent_alloc_bytes
-		mp.prev_free_bytes = mp.recent_free_bytes
-
-		mp.recent_allocs = 0
-		mp.recent_frees = 0
-		mp.recent_alloc_bytes = 0
-		mp.recent_free_bytes = 0
+		// Flush cycle C into the published profile and clear
+		// it for reuse.
+		mpc := &mp.future[c%uint32(len(mp.future))]
+		mp.active.add(mpc)
+		*mpc = memRecordCycle{}
 	}
 }
 
-// Record that a gc just happened: all the 'recent' statistics are now real.
-func mProf_GC() {
+// mProf_PostSweep records that all sweep frees for this GC cycle have
+// completed. This has the effect of publishing the heap profile
+// snapshot as of the last mark termination without advancing the heap
+// profile cycle.
+func mProf_PostSweep() {
 	lock(&proflock)
-	mprof_GC()
+	// Flush cycle C+1 to the active profile so everything as of
+	// the last mark termination becomes visible. *Don't* advance
+	// the cycle, since we're still accumulating allocs in cycle
+	// C+2, which have to become C+1 in the next mark termination
+	// and so on.
+	c := mProf.cycle
+	for b := mbuckets; b != nil; b = b.allnext {
+		mp := b.mp()
+		mpc := &mp.future[(c+1)%uint32(len(mp.future))]
+		mp.active.add(mpc)
+		*mpc = memRecordCycle{}
+	}
 	unlock(&proflock)
 }
 
@@ -245,9 +342,11 @@ func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 	nstk := callers(4, stk[:])
 	lock(&proflock)
 	b := stkbucket(memProfile, size, stk[:nstk], true)
+	c := mProf.cycle
 	mp := b.mp()
-	mp.recent_allocs++
-	mp.recent_alloc_bytes += size
+	mpc := &mp.future[(c+2)%uint32(len(mp.future))]
+	mpc.allocs++
+	mpc.alloc_bytes += size
 	unlock(&proflock)
 
 	// Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
@@ -262,9 +361,11 @@ func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 // Called when freeing a profiled block.
 func mProf_Free(b *bucket, size uintptr) {
 	lock(&proflock)
+	c := mProf.cycle
 	mp := b.mp()
-	mp.prev_frees++
-	mp.prev_free_bytes += size
+	mpc := &mp.future[(c+1)%uint32(len(mp.future))]
+	mpc.frees++
+	mpc.free_bytes += size
 	unlock(&proflock)
 }
 
@@ -298,7 +399,7 @@ func blockevent(cycles int64, skip int) {
 		cycles = 1
 	}
 	if blocksampled(cycles) {
-		saveblockevent(cycles, skip+1, blockProfile, &blockprofilerate)
+		saveblockevent(cycles, skip+1, blockProfile)
 	}
 }
 
@@ -310,7 +411,7 @@ func blocksampled(cycles int64) bool {
 	return true
 }
 
-func saveblockevent(cycles int64, skip int, which bucketType, ratep *uint64) {
+func saveblockevent(cycles int64, skip int, which bucketType) {
 	gp := getg()
 	var nstk int
 	var stk [maxStack]uintptr
@@ -353,7 +454,7 @@ func mutexevent(cycles int64, skip int) {
 	// TODO(pjw): measure impact of always calling fastrand vs using something
 	// like malloc.go:nextSample()
 	if rate > 0 && int64(fastrand())%rate == 0 {
-		saveblockevent(cycles, skip+1, mutexProfile, &mutexprofilerate)
+		saveblockevent(cycles, skip+1, mutexProfile)
 	}
 }
 
@@ -441,13 +542,17 @@ func (r *MemProfileRecord) Stack() []uintptr {
 // of calling MemProfile directly.
 func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
 	lock(&proflock)
+	// If we're between mProf_NextCycle and mProf_Flush, take care
+	// of flushing to the active profile so we only have to look
+	// at the active profile below.
+	mProf_FlushLocked()
 	clear := true
 	for b := mbuckets; b != nil; b = b.allnext {
 		mp := b.mp()
-		if inuseZero || mp.alloc_bytes != mp.free_bytes {
+		if inuseZero || mp.active.alloc_bytes != mp.active.free_bytes {
 			n++
 		}
-		if mp.allocs != 0 || mp.frees != 0 {
+		if mp.active.allocs != 0 || mp.active.frees != 0 {
 			clear = false
 		}
 	}
@@ -455,13 +560,15 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
 		// Absolutely no data, suggesting that a garbage collection
 		// has not yet happened. In order to allow profiling when
 		// garbage collection is disabled from the beginning of execution,
-		// accumulate stats as if a GC just happened, and recount buckets.
-		mprof_GC()
-		mprof_GC()
+		// accumulate all of the cycles, and recount buckets.
 		n = 0
 		for b := mbuckets; b != nil; b = b.allnext {
 			mp := b.mp()
-			if inuseZero || mp.alloc_bytes != mp.free_bytes {
+			for c := range mp.future {
+				mp.active.add(&mp.future[c])
+				mp.future[c] = memRecordCycle{}
+			}
+			if inuseZero || mp.active.alloc_bytes != mp.active.free_bytes {
 				n++
 			}
 		}
@@ -471,7 +578,7 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
 		idx := 0
 		for b := mbuckets; b != nil; b = b.allnext {
 			mp := b.mp()
-			if inuseZero || mp.alloc_bytes != mp.free_bytes {
+			if inuseZero || mp.active.alloc_bytes != mp.active.free_bytes {
 				record(&p[idx], b)
 				idx++
 			}
@@ -484,10 +591,10 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) {
 // Write b's data to r.
 func record(r *MemProfileRecord, b *bucket) {
 	mp := b.mp()
-	r.AllocBytes = int64(mp.alloc_bytes)
-	r.FreeBytes = int64(mp.free_bytes)
-	r.AllocObjects = int64(mp.allocs)
-	r.FreeObjects = int64(mp.frees)
+	r.AllocBytes = int64(mp.active.alloc_bytes)
+	r.FreeBytes = int64(mp.active.free_bytes)
+	r.AllocObjects = int64(mp.active.allocs)
+	r.FreeObjects = int64(mp.active.frees)
 	if raceenabled {
 		racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(unsafe.Pointer(&r)), funcPC(MemProfile))
 	}
@@ -504,7 +611,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, b.nstk, &b.stk()[0], b.size, mp.allocs, mp.frees)
+		fn(b, b.nstk, &b.stk()[0], b.size, mp.active.allocs, mp.active.frees)
 	}
 	unlock(&proflock)
 }
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
index 438c987..0accb83 100644
--- a/src/runtime/msize.go
+++ b/src/runtime/msize.go
@@ -9,28 +9,6 @@
 
 package runtime
 
-// sizeToClass(0 <= n <= MaxSmallSize) returns the size class,
-//	1 <= sizeclass < NumSizeClasses, for n.
-//	Size class 0 is reserved to mean "not small".
-//
-// The sizeToClass lookup is implemented using two arrays,
-// one mapping sizes <= 1024 to their class and one mapping
-// sizes >= 1024 and <= MaxSmallSize to their class.
-// All objects are 8-aligned, so the first array is indexed by
-// the size divided by 8 (rounded up).  Objects >= 1024 bytes
-// are 128-aligned, so the second array is indexed by the
-// size divided by 128 (rounded up).  The arrays are constants
-// in sizeclass.go generated by mksizeclass.go.
-func sizeToClass(size uint32) uint32 {
-	if size > _MaxSmallSize {
-		throw("invalid size")
-	}
-	if size > smallSizeMax-8 {
-		return uint32(size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv])
-	}
-	return uint32(size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv])
-}
-
 // Returns size of the memory block that mallocgc will allocate if you ask for the size.
 func roundupsize(size uintptr) uintptr {
 	if size < _MaxSmallSize {
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 41b9005..1cb44a1 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -33,13 +33,12 @@ type mstats struct {
 	// Statistics about malloc heap.
 	// Protected by mheap.lock
 	//
-	// In mstats, heap_sys and heap_inuse includes stack memory,
-	// while in MemStats stack memory is separated out from the
-	// heap stats.
+	// Like MemStats, heap_sys and heap_inuse do not count memory
+	// in manually-managed spans.
 	heap_alloc    uint64 // bytes allocated and not yet freed (same as alloc above)
-	heap_sys      uint64 // virtual address space obtained from system
+	heap_sys      uint64 // virtual address space obtained from system for GC'd heap
 	heap_idle     uint64 // bytes in idle spans
-	heap_inuse    uint64 // bytes in non-idle spans
+	heap_inuse    uint64 // bytes in _MSpanInUse spans
 	heap_released uint64 // bytes released to the os
 	heap_objects  uint64 // total number of allocated objects
 
@@ -59,7 +58,7 @@ type mstats struct {
 
 	// Statistics about allocation of low-level fixed-size structures.
 	// Protected by FixAlloc locks.
-	stacks_inuse uint64 // this number is included in heap_inuse above; differs from MemStats.StackInuse
+	stacks_inuse uint64 // bytes in manually-managed stack spans
 	stacks_sys   uint64 // only counts newosproc0 stack in mstats; differs from MemStats.StackSys
 	mspan_inuse  uint64 // mspan structures
 	mspan_sys    uint64
@@ -72,7 +71,7 @@ type mstats struct {
 	// Statistics about garbage collector.
 	// Protected by mheap or stopping the world during GC.
 	next_gc         uint64 // goal heap_live for when next GC ends; ^0 if disabled
-	last_gc         uint64 // last gc (in absolute time)
+	last_gc_unix    uint64 // last gc (in unix time)
 	pause_total_ns  uint64
 	pause_ns        [256]uint64 // circular buffer of recent gc pause lengths
 	pause_end       [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
@@ -92,13 +91,26 @@ type mstats struct {
 
 	// Statistics below here are not exported to MemStats directly.
 
-	tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+	last_gc_nanotime uint64 // last gc (monotonic time)
+	tinyallocs       uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+
+	// triggerRatio is the heap growth ratio that triggers marking.
+	//
+	// E.g., if this is 0.6, then GC should start when the live
+	// heap has reached 1.6 times the heap size marked by the
+	// previous cycle. This should be ≤ GOGC/100 so the trigger
+	// heap size is less than the goal heap size. This is set
+	// during mark termination for the next cycle's trigger.
+	triggerRatio float64
 
 	// gc_trigger is the heap size that triggers marking.
 	//
 	// When heap_live ≥ gc_trigger, the mark phase will start.
 	// This is also the heap size by which proportional sweeping
 	// must be complete.
+	//
+	// This is computed from triggerRatio during mark termination
+	// for the next cycle's trigger.
 	gc_trigger uint64
 
 	// heap_live is the number of bytes considered live by the GC.
@@ -121,6 +133,8 @@ type mstats struct {
 	// leads to a conservative GC rate rather than a GC rate that
 	// is potentially too low.
 	//
+	// Reads should likewise be atomic (or during STW).
+	//
 	// Whenever this is updated, call traceHeapAlloc() and
 	// gcController.revise().
 	heap_live uint64
@@ -451,17 +465,16 @@ func ReadMemStats(m *MemStats) {
 }
 
 func readmemstats_m(stats *MemStats) {
-	updatememstats(nil)
+	updatememstats()
 
 	// The size of the trailing by_size array differs between
 	// mstats and MemStats. NumSizeClasses was changed, but we
 	// cannot change MemStats 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
+	// memstats.stacks_sys is only memory mapped directly for OS stacks.
+	// Add in heap-allocated stack memory for user consumption.
 	stats.StackSys += stats.StackInuse
-	stats.HeapInuse -= stats.StackInuse
-	stats.HeapSys -= stats.StackInuse
 }
 
 //go:linkname readGCStats runtime/debug.readGCStats
@@ -497,7 +510,7 @@ func readGCStats_m(pauses *[]uint64) {
 		p[n+i] = memstats.pause_end[j]
 	}
 
-	p[n+n] = memstats.last_gc
+	p[n+n] = memstats.last_gc_unix
 	p[n+n+1] = uint64(memstats.numgc)
 	p[n+n+2] = memstats.pause_total_ns
 	unlock(&mheap_.lock)
@@ -505,26 +518,15 @@ func readGCStats_m(pauses *[]uint64) {
 }
 
 //go:nowritebarrier
-func updatememstats(stats *gcstats) {
-	if stats != nil {
-		*stats = gcstats{}
-	}
-	for mp := allm; mp != nil; mp = mp.alllink {
-		if stats != nil {
-			src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats))
-			dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats))
-			for i, v := range src {
-				dst[i] += v
-			}
-			mp.gcstats = gcstats{}
-		}
-	}
-
+func updatememstats() {
 	memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse)
 	memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse)
 	memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys +
 		memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys
 
+	// We also count stacks_inuse as sys memory.
+	memstats.sys += memstats.stacks_inuse
+
 	// Calculate memory allocator stats.
 	// During program execution we only count number of frees and amount of freed memory.
 	// Current number of alive object in the heap and amount of alive heap memory
@@ -547,45 +549,49 @@ func updatememstats(stats *gcstats) {
 	// Aggregate local stats.
 	cachestats()
 
-	// Scan all spans and count number of alive objects.
-	lock(&mheap_.lock)
-	for _, s := range mheap_.allspans {
-		if s.state != mSpanInUse {
+	// Collect allocation stats. This is safe and consistent
+	// because the world is stopped.
+	var smallFree, totalAlloc, totalFree uint64
+	// Collect per-spanclass stats.
+	for spc := range mheap_.central {
+		// The mcaches are now empty, so mcentral stats are
+		// up-to-date.
+		c := &mheap_.central[spc].mcentral
+		memstats.nmalloc += c.nmalloc
+		i := spanClass(spc).sizeclass()
+		memstats.by_size[i].nmalloc += c.nmalloc
+		totalAlloc += c.nmalloc * uint64(class_to_size[i])
+	}
+	// Collect per-sizeclass stats.
+	for i := 0; i < _NumSizeClasses; i++ {
+		if i == 0 {
+			memstats.nmalloc += mheap_.nlargealloc
+			totalAlloc += mheap_.largealloc
+			totalFree += mheap_.largefree
+			memstats.nfree += mheap_.nlargefree
 			continue
 		}
-		if s.sizeclass == 0 {
-			memstats.nmalloc++
-			memstats.alloc += uint64(s.elemsize)
-		} else {
-			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)
 
-	// Aggregate by size class.
-	smallfree := uint64(0)
-	memstats.nfree = mheap_.nlargefree
-	for i := 0; i < len(memstats.by_size); i++ {
+		// The mcache stats have been flushed to mheap_.
 		memstats.nfree += mheap_.nsmallfree[i]
 		memstats.by_size[i].nfree = mheap_.nsmallfree[i]
-		memstats.by_size[i].nmalloc += mheap_.nsmallfree[i]
-		smallfree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
+		smallFree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
 	}
+	totalFree += smallFree
+
 	memstats.nfree += memstats.tinyallocs
-	memstats.nmalloc += memstats.nfree
+	memstats.nmalloc += memstats.tinyallocs
 
 	// Calculate derived stats.
-	memstats.total_alloc = memstats.alloc + mheap_.largefree + smallfree
+	memstats.total_alloc = totalAlloc
+	memstats.alloc = totalAlloc - totalFree
 	memstats.heap_alloc = memstats.alloc
 	memstats.heap_objects = memstats.nmalloc - memstats.nfree
 }
 
 //go:nowritebarrier
 func cachestats() {
-	for i := 0; ; i++ {
-		p := allp[i]
+	for _, p := range &allp {
 		if p == nil {
 			break
 		}
diff --git a/src/runtime/mstkbar.go b/src/runtime/mstkbar.go
deleted file mode 100644
index 4415559..0000000
--- a/src/runtime/mstkbar.go
+++ /dev/null
@@ -1,393 +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.
-
-// Garbage collector: stack barriers
-//
-// Stack barriers enable the garbage collector to determine how much
-// of a gorountine stack has changed between when a stack is scanned
-// during the concurrent scan phase and when it is re-scanned during
-// the stop-the-world mark termination phase. Mark termination only
-// needs to re-scan the changed part, so for deep stacks this can
-// significantly reduce GC pause time compared to the alternative of
-// re-scanning whole stacks. The deeper the stacks, the more stack
-// barriers help.
-//
-// When stacks are scanned during the concurrent scan phase, the stack
-// scan installs stack barriers by selecting stack frames and
-// overwriting the saved return PCs (or link registers) of these
-// frames with the PC of a "stack barrier trampoline". Later, when a
-// selected frame returns, it "returns" to this trampoline instead of
-// returning to its actual caller. The trampoline records that the
-// stack has unwound past this frame and jumps to the original return
-// PC recorded when the stack barrier was installed. Mark termination
-// re-scans only as far as the first frame that hasn't hit a stack
-// barrier and then removes and un-hit stack barriers.
-//
-// This scheme is very lightweight. No special code is required in the
-// mutator to record stack unwinding and the trampoline is only a few
-// assembly instructions.
-//
-// Book-keeping
-// ------------
-//
-// The primary cost of stack barriers is book-keeping: the runtime has
-// to record the locations of all stack barriers and the original
-// return PCs in order to return to the correct caller when a stack
-// barrier is hit and so it can remove un-hit stack barriers. In order
-// to minimize this cost, the Go runtime places stack barriers in
-// exponentially-spaced frames, starting 1K past the current frame.
-// The book-keeping structure hence grows logarithmically with the
-// size of the stack and mark termination re-scans at most twice as
-// much stack as necessary.
-//
-// The runtime reserves space for this book-keeping structure at the
-// top of the stack allocation itself (just above the outermost
-// frame). This is necessary because the regular memory allocator can
-// itself grow the stack, and hence can't be used when allocating
-// stack-related structures.
-//
-// For debugging, the runtime also supports installing stack barriers
-// at every frame. However, this requires significantly more
-// book-keeping space.
-//
-// Correctness
-// -----------
-//
-// The runtime and the compiler cooperate to ensure that all objects
-// reachable from the stack as of mark termination are marked.
-// Anything unchanged since the concurrent scan phase will be marked
-// because it is marked by the concurrent scan. After the concurrent
-// scan, there are three possible classes of stack modifications that
-// must be tracked:
-//
-// 1) Mutator writes below the lowest un-hit stack barrier. This
-// includes all writes performed by an executing function to its own
-// stack frame. This part of the stack will be re-scanned by mark
-// termination, which will mark any objects made reachable from
-// modifications to this part of the stack.
-//
-// 2) Mutator writes above the lowest un-hit stack barrier. It's
-// possible for a mutator to modify the stack above the lowest un-hit
-// stack barrier if a higher frame has passed down a pointer to a
-// stack variable in its frame. This is called an "up-pointer". The
-// compiler ensures that writes through up-pointers have an
-// accompanying write barrier (it simply doesn't distinguish between
-// writes through up-pointers and writes through heap pointers). This
-// write barrier marks any object made reachable from modifications to
-// this part of the stack.
-//
-// 3) Runtime writes to the stack. Various runtime operations such as
-// sends to unbuffered channels can write to arbitrary parts of the
-// stack, including above the lowest un-hit stack barrier. We solve
-// this in two ways. In many cases, the runtime can perform an
-// explicit write barrier operation like in case 2. However, in the
-// case of bulk memory move (typedmemmove), the runtime doesn't
-// necessary have ready access to a pointer bitmap for the memory
-// being copied, so it simply unwinds any stack barriers below the
-// destination.
-//
-// Gotchas
-// -------
-//
-// Anything that inspects or manipulates the stack potentially needs
-// to understand stack barriers. The most obvious case is that
-// gentraceback needs to use the original return PC when it encounters
-// the stack barrier trampoline. Anything that unwinds the stack such
-// as panic/recover must unwind stack barriers in tandem with
-// unwinding the stack.
-//
-// Stack barriers require that any goroutine whose stack has been
-// scanned must execute write barriers. Go solves this by simply
-// enabling write barriers globally during the concurrent scan phase.
-// However, traditionally, write barriers are not enabled during this
-// phase.
-//
-// Synchronization
-// ---------------
-//
-// For the most part, accessing and modifying stack barriers is
-// synchronized around GC safe points. Installing stack barriers
-// forces the G to a safe point, while all other operations that
-// modify stack barriers run on the G and prevent it from reaching a
-// safe point.
-//
-// Subtlety arises when a G may be tracebacked when *not* at a safe
-// point. This happens during sigprof. For this, each G has a "stack
-// barrier lock" (see gcLockStackBarriers, gcUnlockStackBarriers).
-// Operations that manipulate stack barriers acquire this lock, while
-// sigprof tries to acquire it and simply skips the traceback if it
-// can't acquire it. There is one exception for performance and
-// complexity reasons: hitting a stack barrier manipulates the stack
-// barrier list without acquiring the stack barrier lock. For this,
-// gentraceback performs a special fix up if the traceback starts in
-// the stack barrier function.
-
-package runtime
-
-import (
-	"runtime/internal/atomic"
-	"runtime/internal/sys"
-	"unsafe"
-)
-
-const debugStackBarrier = false
-
-// firstStackBarrierOffset is the approximate byte offset at
-// which to place the first stack barrier from the current SP.
-// This is a lower bound on how much stack will have to be
-// re-scanned during mark termination. Subsequent barriers are
-// placed at firstStackBarrierOffset * 2^n offsets.
-//
-// For debugging, this can be set to 0, which will install a
-// stack barrier at every frame. If you do this, you may also
-// have to raise _StackMin, since the stack barrier
-// bookkeeping will use a large amount of each stack.
-var firstStackBarrierOffset = 1024
-
-// gcMaxStackBarriers returns the maximum number of stack barriers
-// that can be installed in a stack of stackSize bytes.
-func gcMaxStackBarriers(stackSize int) (n int) {
-	if debug.gcstackbarrieroff > 0 {
-		return 0
-	}
-
-	if firstStackBarrierOffset == 0 {
-		// Special debugging case for inserting stack barriers
-		// at every frame. Steal half of the stack for the
-		// []stkbar. Technically, if the stack were to consist
-		// solely of return PCs we would need two thirds of
-		// the stack, but stealing that much breaks things and
-		// this doesn't happen in practice.
-		return stackSize / 2 / int(unsafe.Sizeof(stkbar{}))
-	}
-
-	offset := firstStackBarrierOffset
-	for offset < stackSize {
-		n++
-		offset *= 2
-	}
-	return n + 1
-}
-
-// gcInstallStackBarrier installs a stack barrier over the return PC of frame.
-//go:nowritebarrier
-func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
-	if frame.lr == 0 {
-		if debugStackBarrier {
-			print("not installing stack barrier with no LR, goid=", gp.goid, "\n")
-		}
-		return false
-	}
-
-	if frame.fn.entry == cgocallback_gofuncPC {
-		// cgocallback_gofunc doesn't return to its LR;
-		// instead, its return path puts LR in g.sched.pc and
-		// switches back to the system stack on which
-		// cgocallback_gofunc was originally called. We can't
-		// have a stack barrier in g.sched.pc, so don't
-		// install one in this frame.
-		if debugStackBarrier {
-			print("not installing stack barrier over LR of cgocallback_gofunc, goid=", gp.goid, "\n")
-		}
-		return false
-	}
-
-	// Save the return PC and overwrite it with stackBarrier.
-	var lrUintptr uintptr
-	if usesLR {
-		lrUintptr = frame.sp
-	} else {
-		lrUintptr = frame.fp - sys.RegSize
-	}
-	lrPtr := (*sys.Uintreg)(unsafe.Pointer(lrUintptr))
-	if debugStackBarrier {
-		print("install stack barrier at ", hex(lrUintptr), " over ", hex(*lrPtr), ", goid=", gp.goid, "\n")
-		if uintptr(*lrPtr) != frame.lr {
-			print("frame.lr=", hex(frame.lr))
-			throw("frame.lr differs from stack LR")
-		}
-	}
-
-	gp.stkbar = gp.stkbar[:len(gp.stkbar)+1]
-	stkbar := &gp.stkbar[len(gp.stkbar)-1]
-	stkbar.savedLRPtr = lrUintptr
-	stkbar.savedLRVal = uintptr(*lrPtr)
-	*lrPtr = sys.Uintreg(stackBarrierPC)
-	return true
-}
-
-// 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")
-	}
-
-	// Remove stack barriers that we didn't hit.
-	for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
-		gcRemoveStackBarrier(gp, stkbar)
-	}
-
-	// Clear recorded stack barriers so copystack doesn't try to
-	// adjust them.
-	gp.stkbarPos = 0
-	gp.stkbar = gp.stkbar[:0]
-}
-
-// gcRemoveStackBarrier removes a single stack barrier. It is the
-// inverse operation of gcInstallStackBarrier.
-//
-// This is nosplit to ensure gp's stack does not move.
-//
-//go:nowritebarrier
-//go:nosplit
-func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
-	if debugStackBarrier {
-		print("remove stack barrier at ", hex(stkbar.savedLRPtr), " with ", hex(stkbar.savedLRVal), ", goid=", gp.goid, "\n")
-	}
-	lrPtr := (*sys.Uintreg)(unsafe.Pointer(stkbar.savedLRPtr))
-	if val := *lrPtr; val != sys.Uintreg(stackBarrierPC) {
-		printlock()
-		print("at *", hex(stkbar.savedLRPtr), " expected stack barrier PC ", hex(stackBarrierPC), ", found ", hex(val), ", goid=", gp.goid, "\n")
-		print("gp.stkbar=")
-		gcPrintStkbars(gp, -1)
-		print(", gp.stack=[", hex(gp.stack.lo), ",", hex(gp.stack.hi), ")\n")
-		throw("stack barrier lost")
-	}
-	*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.
-func gcPrintStkbars(gp *g, marker int) {
-	print("[")
-	for i, s := range gp.stkbar {
-		if i > 0 {
-			print(" ")
-		}
-		if i == int(gp.stkbarPos) {
-			print("@@@ ")
-		}
-		if i == marker {
-			print("==> ")
-		}
-		print("*", hex(s.savedLRPtr), "=", hex(s.savedLRVal))
-	}
-	if int(gp.stkbarPos) == len(gp.stkbar) {
-		print(" @@@")
-	}
-	if marker == len(gp.stkbar) {
-		print(" ==>")
-	}
-	print("]")
-}
-
-// gcUnwindBarriers marks all stack barriers up the frame containing
-// sp as hit and removes them. This is used during stack unwinding for
-// panic/recover and by heapBitsBulkBarrier to force stack re-scanning
-// when its destination is on the stack.
-//
-// This is nosplit to ensure gp's stack does not move.
-//
-//go:nosplit
-func gcUnwindBarriers(gp *g, sp uintptr) {
-	gcLockStackBarriers(gp)
-	// On LR machines, if there is a stack barrier on the return
-	// from the frame containing sp, this will mark it as hit even
-	// though it isn't, but it's okay to be conservative.
-	before := gp.stkbarPos
-	for int(gp.stkbarPos) < len(gp.stkbar) && gp.stkbar[gp.stkbarPos].savedLRPtr < sp {
-		gcRemoveStackBarrier(gp, gp.stkbar[gp.stkbarPos])
-		gp.stkbarPos++
-	}
-	gcUnlockStackBarriers(gp)
-	if debugStackBarrier && gp.stkbarPos != before {
-		print("skip barriers below ", hex(sp), " in goid=", gp.goid, ": ")
-		// We skipped barriers between the "==>" marker
-		// (before) and the "@@@" marker (gp.stkbarPos).
-		gcPrintStkbars(gp, int(before))
-		print("\n")
-	}
-}
-
-// nextBarrierPC returns the original return PC of the next stack barrier.
-// Used by getcallerpc, so it must be nosplit.
-//go:nosplit
-func nextBarrierPC() uintptr {
-	gp := getg()
-	return gp.stkbar[gp.stkbarPos].savedLRVal
-}
-
-// setNextBarrierPC sets the return PC of the next stack barrier.
-// Used by setcallerpc, so it must be nosplit.
-//go:nosplit
-func setNextBarrierPC(pc uintptr) {
-	gp := getg()
-	gcLockStackBarriers(gp)
-	gp.stkbar[gp.stkbarPos].savedLRVal = pc
-	gcUnlockStackBarriers(gp)
-}
-
-// gcLockStackBarriers synchronizes with tracebacks of gp's stack
-// during sigprof for installation or removal of stack barriers. It
-// blocks until any current sigprof is done tracebacking gp's stack
-// and then disallows profiling tracebacks of gp's stack.
-//
-// This is necessary because a sigprof during barrier installation or
-// removal could observe inconsistencies between the stkbar array and
-// the stack itself and crash.
-//
-//go:nosplit
-func gcLockStackBarriers(gp *g) {
-	// Disable preemption so scanstack cannot run while the caller
-	// is manipulating the stack barriers.
-	acquirem()
-	for !atomic.Cas(&gp.stackLock, 0, 1) {
-		osyield()
-	}
-}
-
-//go:nosplit
-func gcTryLockStackBarriers(gp *g) bool {
-	mp := acquirem()
-	result := atomic.Cas(&gp.stackLock, 0, 1)
-	if !result {
-		releasem(mp)
-	}
-	return result
-}
-
-func gcUnlockStackBarriers(gp *g) {
-	atomic.Store(&gp.stackLock, 0)
-	releasem(getg().m)
-}
diff --git a/src/runtime/net_plan9.go b/src/runtime/net_plan9.go
index 10fd089..b1ac7c7 100644
--- a/src/runtime/net_plan9.go
+++ b/src/runtime/net_plan9.go
@@ -8,12 +8,12 @@ import (
 	_ "unsafe"
 )
 
-//go:linkname runtime_ignoreHangup net.runtime_ignoreHangup
+//go:linkname runtime_ignoreHangup internal/poll.runtime_ignoreHangup
 func runtime_ignoreHangup() {
 	getg().m.ignoreHangup = true
 }
 
-//go:linkname runtime_unignoreHangup net.runtime_unignoreHangup
+//go:linkname runtime_unignoreHangup internal/poll.runtime_unignoreHangup
 func runtime_unignoreHangup(sig string) {
 	getg().m.ignoreHangup = false
 }
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 10a3c88..8dd4fb6 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -77,12 +77,13 @@ type pollCache struct {
 }
 
 var (
-	netpollInited uint32
-	pollcache     pollCache
+	netpollInited  uint32
+	pollcache      pollCache
+	netpollWaiters uint32
 )
 
-//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
-func net_runtime_pollServerInit() {
+//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
+func poll_runtime_pollServerInit() {
 	netpollinit()
 	atomic.Store(&netpollInited, 1)
 }
@@ -91,15 +92,23 @@ func netpollinited() bool {
 	return atomic.Load(&netpollInited) != 0
 }
 
-//go:linkname net_runtime_pollOpen net.runtime_pollOpen
-func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
+//go:linkname poll_runtime_pollServerDescriptor internal/poll.runtime_pollServerDescriptor
+
+// poll_runtime_pollServerDescriptor returns the descriptor being used,
+// or ^uintptr(0) if the system does not use a poll descriptor.
+func poll_runtime_pollServerDescriptor() uintptr {
+	return netpolldescriptor()
+}
+
+//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
+func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	pd := pollcache.alloc()
 	lock(&pd.lock)
 	if pd.wg != 0 && pd.wg != pdReady {
-		throw("netpollOpen: blocked write on free descriptor")
+		throw("runtime: blocked write on free polldesc")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		throw("netpollOpen: blocked read on free descriptor")
+		throw("runtime: blocked read on free polldesc")
 	}
 	pd.fd = fd
 	pd.closing = false
@@ -115,16 +124,16 @@ func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	return pd, int(errno)
 }
 
-//go:linkname net_runtime_pollClose net.runtime_pollClose
-func net_runtime_pollClose(pd *pollDesc) {
+//go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose
+func poll_runtime_pollClose(pd *pollDesc) {
 	if !pd.closing {
-		throw("netpollClose: close w/o unblock")
+		throw("runtime: close polldesc w/o unblock")
 	}
 	if pd.wg != 0 && pd.wg != pdReady {
-		throw("netpollClose: blocked write on closing descriptor")
+		throw("runtime: blocked write on closing polldesc")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		throw("netpollClose: blocked read on closing descriptor")
+		throw("runtime: blocked read on closing polldesc")
 	}
 	netpollclose(pd.fd)
 	pollcache.free(pd)
@@ -137,8 +146,8 @@ func (c *pollCache) free(pd *pollDesc) {
 	unlock(&c.lock)
 }
 
-//go:linkname net_runtime_pollReset net.runtime_pollReset
-func net_runtime_pollReset(pd *pollDesc, mode int) int {
+//go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
+func poll_runtime_pollReset(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
@@ -151,8 +160,8 @@ func net_runtime_pollReset(pd *pollDesc, mode int) int {
 	return 0
 }
 
-//go:linkname net_runtime_pollWait net.runtime_pollWait
-func net_runtime_pollWait(pd *pollDesc, mode int) int {
+//go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
+func poll_runtime_pollWait(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
@@ -173,16 +182,16 @@ func net_runtime_pollWait(pd *pollDesc, mode int) int {
 	return 0
 }
 
-//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled
-func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
+//go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
+func poll_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
 	// This function is used only on windows after a failed attempt to cancel
 	// a pending async IO operation. Wait for ioready, ignore closing or timeouts.
 	for !netpollblock(pd, int32(mode), true) {
 	}
 }
 
-//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline
-func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+//go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
+func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 	lock(&pd.lock)
 	if pd.closing {
 		unlock(&pd.lock)
@@ -244,18 +253,18 @@ func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 3)
+		netpollgoready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg, 3)
+		netpollgoready(wg, 3)
 	}
 }
 
-//go:linkname net_runtime_pollUnblock net.runtime_pollUnblock
-func net_runtime_pollUnblock(pd *pollDesc) {
+//go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock
+func poll_runtime_pollUnblock(pd *pollDesc) {
 	lock(&pd.lock)
 	if pd.closing {
-		throw("netpollUnblock: already closing")
+		throw("runtime: unblock on closing polldesc")
 	}
 	pd.closing = true
 	pd.seq++
@@ -273,10 +282,10 @@ func net_runtime_pollUnblock(pd *pollDesc) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 3)
+		netpollgoready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg, 3)
+		netpollgoready(wg, 3)
 	}
 }
 
@@ -312,7 +321,19 @@ func netpollcheckerr(pd *pollDesc, mode int32) int {
 }
 
 func netpollblockcommit(gp *g, gpp unsafe.Pointer) bool {
-	return atomic.Casuintptr((*uintptr)(gpp), pdWait, uintptr(unsafe.Pointer(gp)))
+	r := atomic.Casuintptr((*uintptr)(gpp), pdWait, uintptr(unsafe.Pointer(gp)))
+	if r {
+		// Bump the count of goroutines waiting for the poller.
+		// The scheduler uses this to decide whether to block
+		// waiting for the poller if there is nothing else to do.
+		atomic.Xadd(&netpollWaiters, 1)
+	}
+	return r
+}
+
+func netpollgoready(gp *g, traceskip int) {
+	atomic.Xadd(&netpollWaiters, -1)
+	goready(gp, traceskip+1)
 }
 
 // returns true if IO is ready, or false if timedout or closed
@@ -331,7 +352,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 			return true
 		}
 		if old != 0 {
-			throw("netpollblock: double wait")
+			throw("runtime: double wait")
 		}
 		if atomic.Casuintptr(gpp, 0, pdWait) {
 			break
@@ -347,7 +368,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 	// be careful to not lose concurrent READY notification
 	old := atomic.Xchguintptr(gpp, 0)
 	if old > pdWait {
-		throw("netpollblock: corrupted state")
+		throw("runtime: corrupted polldesc")
 	}
 	return old == pdReady
 }
@@ -393,7 +414,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var rg *g
 	if read {
 		if pd.rd <= 0 || pd.rt.f == nil {
-			throw("netpolldeadlineimpl: inconsistent read deadline")
+			throw("runtime: inconsistent read deadline")
 		}
 		pd.rd = -1
 		atomicstorep(unsafe.Pointer(&pd.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock
@@ -402,7 +423,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var wg *g
 	if write {
 		if pd.wd <= 0 || pd.wt.f == nil && !read {
-			throw("netpolldeadlineimpl: inconsistent write deadline")
+			throw("runtime: inconsistent write deadline")
 		}
 		pd.wd = -1
 		atomicstorep(unsafe.Pointer(&pd.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock
@@ -410,10 +431,10 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 0)
+		netpollgoready(rg, 0)
 	}
 	if wg != nil {
-		goready(wg, 0)
+		netpollgoready(wg, 0)
 	}
 }
 
diff --git a/src/runtime/netpoll_epoll.go b/src/runtime/netpoll_epoll.go
index e06eff8..1908220 100644
--- a/src/runtime/netpoll_epoll.go
+++ b/src/runtime/netpoll_epoll.go
@@ -32,8 +32,12 @@ func netpollinit() {
 		closeonexec(epfd)
 		return
 	}
-	println("netpollinit: failed to create epoll descriptor", -epfd)
-	throw("netpollinit: failed to create descriptor")
+	println("runtime: epollcreate failed with", -epfd)
+	throw("runtime: netpollinit failed")
+}
+
+func netpolldescriptor() uintptr {
+	return uintptr(epfd)
 }
 
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
@@ -49,7 +53,7 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	throw("unused")
+	throw("runtime: unused")
 }
 
 // polls for ready network connections
@@ -68,7 +72,7 @@ retry:
 	if n < 0 {
 		if n != -_EINTR {
 			println("runtime: epollwait on fd", epfd, "failed with", -n)
-			throw("epollwait failed")
+			throw("runtime: netpoll failed")
 		}
 		goto retry
 	}
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 337377a..71de98b 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -23,12 +23,16 @@ var (
 func netpollinit() {
 	kq = kqueue()
 	if kq < 0 {
-		println("netpollinit: kqueue failed with", -kq)
-		throw("netpollinit: kqueue failed")
+		println("runtime: kqueue failed with", -kq)
+		throw("runtime: netpollinit failed")
 	}
 	closeonexec(kq)
 }
 
+func netpolldescriptor() uintptr {
+	return uintptr(kq)
+}
+
 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
@@ -56,7 +60,7 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	throw("unused")
+	throw("runtime: unused")
 }
 
 // Polls for ready network connections.
@@ -76,7 +80,7 @@ retry:
 	if n < 0 {
 		if n != -_EINTR {
 			println("runtime: kevent on fd", kq, "failed with", -n)
-			throw("kevent failed")
+			throw("runtime: netpoll failed")
 		}
 		goto retry
 	}
diff --git a/src/runtime/netpoll_nacl.go b/src/runtime/netpoll_nacl.go
index 5cbc300..dc5a55e 100644
--- a/src/runtime/netpoll_nacl.go
+++ b/src/runtime/netpoll_nacl.go
@@ -10,6 +10,10 @@ package runtime
 func netpollinit() {
 }
 
+func netpolldescriptor() uintptr {
+	return ^uintptr(0)
+}
+
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
 	return 0
 }
diff --git a/src/runtime/netpoll_solaris.go b/src/runtime/netpoll_solaris.go
index 53b2aac..853e5f6 100644
--- a/src/runtime/netpoll_solaris.go
+++ b/src/runtime/netpoll_solaris.go
@@ -117,8 +117,12 @@ func netpollinit() {
 		return
 	}
 
-	print("netpollinit: failed to create port (", errno(), ")\n")
-	throw("netpollinit: failed to create port")
+	print("runtime: port_create failed (errno=", errno(), ")\n")
+	throw("runtime: netpollinit failed")
+}
+
+func netpolldescriptor() uintptr {
+	return uintptr(portfd)
 }
 
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
@@ -154,8 +158,8 @@ func netpollupdate(pd *pollDesc, set, clear uint32) {
 	}
 
 	if events != 0 && port_associate(portfd, _PORT_SOURCE_FD, pd.fd, events, uintptr(unsafe.Pointer(pd))) != 0 {
-		print("netpollupdate: failed to associate (", errno(), ")\n")
-		throw("netpollupdate: failed to associate")
+		print("runtime: port_associate failed (errno=", errno(), ")\n")
+		throw("runtime: netpollupdate failed")
 	}
 	pd.user = events
 }
@@ -169,7 +173,7 @@ func netpollarm(pd *pollDesc, mode int) {
 	case 'w':
 		netpollupdate(pd, _POLLOUT, 0)
 	default:
-		throw("netpollarm: bad mode")
+		throw("runtime: bad mode")
 	}
 	unlock(&pd.lock)
 }
@@ -192,8 +196,8 @@ retry:
 	var n uint32 = 1
 	if port_getn(portfd, &events[0], uint32(len(events)), &n, wait) < 0 {
 		if e := errno(); e != _EINTR {
-			print("runtime: port_getn on fd ", portfd, " failed with ", e, "\n")
-			throw("port_getn failed")
+			print("runtime: port_getn on fd ", portfd, " failed (errno=", e, ")\n")
+			throw("runtime: netpoll failed")
 		}
 		goto retry
 	}
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
index 09f64ad..a4d6b46 100644
--- a/src/runtime/netpoll_stub.go
+++ b/src/runtime/netpoll_stub.go
@@ -6,6 +6,8 @@
 
 package runtime
 
+var netpollWaiters uint32
+
 // Polls for ready network connections.
 // Returns list of goroutines that become runnable.
 func netpoll(block bool) (gp *g) {
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
index 7ad1158..79dafb0 100644
--- a/src/runtime/netpoll_windows.go
+++ b/src/runtime/netpoll_windows.go
@@ -12,7 +12,8 @@ const _DWORD_MAX = 0xffffffff
 
 const _INVALID_HANDLE_VALUE = ^uintptr(0)
 
-// net_op must be the same as beginning of net.operation. Keep these in sync.
+// net_op must be the same as beginning of internal/poll.operation.
+// Keep these in sync.
 type net_op struct {
 	// used by windows
 	o overlapped
@@ -35,11 +36,15 @@ var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
 func netpollinit() {
 	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")
+		println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
+		throw("runtime: netpollinit failed")
 	}
 }
 
+func netpolldescriptor() uintptr {
+	return iocphandle
+}
+
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
 	if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
 		return -int32(getlasterror())
@@ -53,7 +58,7 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	throw("unused")
+	throw("runtime: unused")
 }
 
 // Polls for completed network IO.
@@ -89,8 +94,8 @@ retry:
 			if !block && errno == _WAIT_TIMEOUT {
 				return nil
 			}
-			println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
-			throw("netpoll: GetQueuedCompletionStatusEx failed")
+			println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
+			throw("runtime: netpoll failed")
 		}
 		mp.blocked = false
 		for i = 0; i < n; i++ {
@@ -116,8 +121,8 @@ retry:
 				return nil
 			}
 			if op == nil {
-				println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
-				throw("netpoll: GetQueuedCompletionStatus failed")
+				println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")")
+				throw("runtime: netpoll failed")
 			}
 			// dequeued failed IO packet, so report that
 		}
@@ -132,12 +137,13 @@ retry:
 
 func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
 	if op == nil {
-		throw("netpoll: GetQueuedCompletionStatus returned op == nil")
+		println("runtime: GetQueuedCompletionStatus returned op == nil")
+		throw("runtime: netpoll failed")
 	}
 	mode := op.mode
 	if mode != 'r' && mode != 'w' {
-		println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
-		throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
+		println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode)
+		throw("runtime: netpoll failed")
 	}
 	op.errno = errno
 	op.qty = qty
diff --git a/src/runtime/numcpu_freebsd_test.go b/src/runtime/numcpu_freebsd_test.go
new file mode 100644
index 0000000..e78890a
--- /dev/null
+++ b/src/runtime/numcpu_freebsd_test.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. 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 "testing"
+
+func TestFreeBSDNumCPU(t *testing.T) {
+	got := runTestProg(t, "testprog", "FreeBSDNumCPU")
+	want := "OK\n"
+	if got != want {
+		t.Fatalf("expected %q, but got:\n%s", want, got)
+	}
+}
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
index 26b4acd..5d4b5a6 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -62,7 +62,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
 		// but we do recognize the top pointer on the stack as code,
 		// then assume this was a call to non-code and treat like
 		// pc == 0, to make unwinding show the context.
-		if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+		if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
 			pc = 0
 		}
 
@@ -146,7 +146,10 @@ func sigdisable(sig uint32) {
 func sigignore(sig uint32) {
 }
 
-func resetcpuprofiler(hz int32) {
+func setProcessCPUProfiler(hz int32) {
+}
+
+func setThreadCPUProfiler(hz int32) {
 	// TODO: Enable profiling interrupts.
 	getg().m.profilehz = hz
 }
diff --git a/src/runtime/os_darwin_arm.go b/src/runtime/os_darwin_arm.go
index ee1bd17..8eb5655 100644
--- a/src/runtime/os_darwin_arm.go
+++ b/src/runtime/os_darwin_arm.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func checkgoarm() {
 	// TODO(minux): FP checks like in os_linux_arm.go.
 
diff --git a/src/runtime/os_darwin_arm64.go b/src/runtime/os_darwin_arm64.go
index 8de132d..01285af 100644
--- a/src/runtime/os_darwin_arm64.go
+++ b/src/runtime/os_darwin_arm64.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var supportCRC32 = false
+
 //go:nosplit
 func cputicks() int64 {
 	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 35ed026..7c989de 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -42,21 +42,87 @@ func osyield()
 // From FreeBSD's <sys/sysctl.h>
 const (
 	_CTL_HW      = 6
-	_HW_NCPU     = 3
 	_HW_PAGESIZE = 7
 )
 
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
+// Undocumented numbers from FreeBSD's lib/libc/gen/sysctlnametomib.c.
+const (
+	_CTL_QUERY     = 0
+	_CTL_QUERY_MIB = 3
+)
+
+// sysctlnametomib fill mib with dynamically assigned sysctl entries of name,
+// return count of effected mib slots, return 0 on error.
+func sysctlnametomib(name []byte, mib *[_CTL_MAXNAME]uint32) uint32 {
+	oid := [2]uint32{_CTL_QUERY, _CTL_QUERY_MIB}
+	miblen := uintptr(_CTL_MAXNAME)
+	if sysctl(&oid[0], 2, (*byte)(unsafe.Pointer(mib)), &miblen, (*byte)(unsafe.Pointer(&name[0])), (uintptr)(len(name))) < 0 {
+		return 0
+	}
+	miblen /= unsafe.Sizeof(uint32(0))
+	if miblen <= 0 {
+		return 0
+	}
+	return uint32(miblen)
+}
+
+const (
+	_CPU_SETSIZE_MAX = 32 // Limited by _MaxGomaxprocs(256) in runtime2.go.
+	_CPU_CURRENT_PID = -1 // Current process ID.
+)
+
+//go:noescape
+func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
+
 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)
+	var mask [_CPU_SETSIZE_MAX]byte
+	var mib [_CTL_MAXNAME]uint32
+
+	// According to FreeBSD's /usr/src/sys/kern/kern_cpuset.c,
+	// cpuset_getaffinity return ERANGE when provided buffer size exceed the limits in kernel.
+	// Querying kern.smp.maxcpus to calculate maximum buffer size.
+	// See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=200802
+
+	// Variable kern.smp.maxcpus introduced at Dec 23 2003, revision 123766,
+	// with dynamically assigned sysctl entries.
+	miblen := sysctlnametomib([]byte("kern.smp.maxcpus"), &mib)
+	if miblen == 0 {
+		return 1
+	}
+
+	// Query kern.smp.maxcpus.
+	dstsize := uintptr(4)
+	maxcpus := uint32(0)
+	if sysctl(&mib[0], miblen, (*byte)(unsafe.Pointer(&maxcpus)), &dstsize, nil, 0) != 0 {
+		return 1
+	}
+
+	size := maxcpus / _NBBY
+	ptrsize := uint32(unsafe.Sizeof(uintptr(0)))
+	if size < ptrsize {
+		size = ptrsize
+	}
+	if size > _CPU_SETSIZE_MAX {
+		return 1
 	}
-	return 1
+
+	if cpuset_getaffinity(_CPU_LEVEL_WHICH, _CPU_WHICH_PID, _CPU_CURRENT_PID,
+		int(size), (*byte)(unsafe.Pointer(&mask[0]))) != 0 {
+		return 1
+	}
+	n := int32(0)
+	for _, v := range mask[:size] {
+		for v != 0 {
+			n += int32(v & 1)
+			v >>= 1
+		}
+	}
+	if n == 0 {
+		return 1
+	}
+	return n
 }
 
 func getPageSize() uintptr {
@@ -174,6 +240,20 @@ func minit() {
 		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
 	}
 
+	// On FreeBSD before about April 2017 there was a bug such
+	// that calling execve from a thread other than the main
+	// thread did not reset the signal stack. That would confuse
+	// minitSignals, which calls minitSignalStack, which checks
+	// whether there is currently a signal stack and uses it if
+	// present. To avoid this confusion, explicitly disable the
+	// signal stack on the main thread when not running in a
+	// library. This can be removed when we are confident that all
+	// FreeBSD users are running a patched kernel. See issue #15658.
+	if gp := getg(); !isarchive && !islibrary && gp.m == &m0 && gp == gp.m.g0 {
+		st := stackt{ss_flags: _SS_DISABLE}
+		sigaltstack(&st, nil)
+	}
+
 	minitSignals()
 }
 
diff --git a/src/runtime/os_freebsd_arm.go b/src/runtime/os_freebsd_arm.go
index 0399499..6e2bc97 100644
--- a/src/runtime/os_freebsd_arm.go
+++ b/src/runtime/os_freebsd_arm.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func checkgoarm() {
 	// TODO(minux): FP checks like in os_linux_arm.go.
 
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
index 896ec15..7c925d7 100644
--- a/src/runtime/os_linux_arm.go
+++ b/src/runtime/os_linux_arm.go
@@ -11,11 +11,13 @@ const (
 
 	_HWCAP_VFP   = 1 << 6  // introduced in at least 2.6.11
 	_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
+	_HWCAP_IDIVA = 1 << 17
 )
 
 var randomNumber uint32
 var armArch uint8 = 6 // we default to ARMv6
 var hwcap uint32      // set by setup_auxv
+var hardDiv bool      // set if a hardware divider is available
 
 func checkgoarm() {
 	// On Android, /proc/self/auxv might be unreadable and hwcap won't
@@ -53,6 +55,7 @@ func archauxv(tag, val uintptr) {
 
 	case _AT_HWCAP: // CPU capability bit flags
 		hwcap = uint32(val)
+		hardDiv = (hwcap & _HWCAP_IDIVA) != 0
 	}
 }
 
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
index bdc341d..986a341 100644
--- a/src/runtime/os_linux_arm64.go
+++ b/src/runtime/os_linux_arm64.go
@@ -4,7 +4,12 @@
 
 package runtime
 
+const (
+	_ARM64_FEATURE_HAS_CRC32 = 0x80
+)
+
 var randomNumber uint32
+var supportCRC32 bool
 
 func archauxv(tag, val uintptr) {
 	switch tag {
@@ -14,6 +19,8 @@ func archauxv(tag, val uintptr) {
 		// it as a byte array.
 		randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 |
 			uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24
+	case _AT_HWCAP:
+		supportCRC32 = val&_ARM64_FEATURE_HAS_CRC32 != 0
 	}
 }
 
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 7015316..18e6ce6 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -88,6 +88,11 @@ func msigrestore(sigmask sigset) {
 }
 
 //go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {
+}
+
+//go:nosplit
 func sigblock() {
 }
 
@@ -273,7 +278,8 @@ func raisebadsignal(sig uint32) {
 
 func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
 func munmap(addr unsafe.Pointer, n uintptr)               {}
-func resetcpuprofiler(hz int32)                           {}
+func setProcessCPUProfiler(hz int32)                      {}
+func setThreadCPUProfiler(hz int32)                       {}
 func sigdisable(uint32)                                   {}
 func sigenable(uint32)                                    {}
 func sigignore(uint32)                                    {}
diff --git a/src/runtime/os_nacl_arm.go b/src/runtime/os_nacl_arm.go
index 8669ee7..c64ebf3 100644
--- a/src/runtime/os_nacl_arm.go
+++ b/src/runtime/os_nacl_arm.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func checkgoarm() {
 	// TODO(minux): FP checks like in os_linux_arm.go.
 
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index c79b50b..c26c3c9 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -167,13 +167,23 @@ func newosproc(mp *m, stk unsafe.Pointer) {
 	var uc ucontextt
 	getcontext(unsafe.Pointer(&uc))
 
+	// _UC_SIGMASK does not seem to work here.
+	// It would be nice if _UC_SIGMASK and _UC_STACK
+	// worked so that we could do all the work setting
+	// the sigmask and the stack here, instead of setting
+	// the mask here and the stack in netbsdMstart.
+	// For now do the blocking manually.
 	uc.uc_flags = _UC_SIGMASK | _UC_CPU
 	uc.uc_link = nil
 	uc.uc_sigmask = sigset_all
 
+	var oset sigset
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+
 	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart))
 
 	ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
+	sigprocmask(_SIG_SETMASK, &oset, nil)
 	if ret < 0 {
 		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
 		if ret == -_EAGAIN {
diff --git a/src/runtime/os_netbsd_arm.go b/src/runtime/os_netbsd_arm.go
index 95603da..b02e36a 100644
--- a/src/runtime/os_netbsd_arm.go
+++ b/src/runtime/os_netbsd_arm.go
@@ -6,6 +6,8 @@ package runtime
 
 import "unsafe"
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
 	// Machine dependent mcontext initialisation for LWP.
 	mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp))
diff --git a/src/runtime/os_openbsd_arm.go b/src/runtime/os_openbsd_arm.go
index be2e1e9..c318578 100644
--- a/src/runtime/os_openbsd_arm.go
+++ b/src/runtime/os_openbsd_arm.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func checkgoarm() {
 	// TODO(minux): FP checks like in os_linux_arm.go.
 
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index ba2d5c5..45e881a 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -173,6 +173,11 @@ func msigsave(mp *m) {
 func msigrestore(sigmask sigset) {
 }
 
+//go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {
+}
+
 func sigblock() {
 }
 
diff --git a/src/runtime/os_plan9_arm.go b/src/runtime/os_plan9_arm.go
index fdce1e7..1ce0141 100644
--- a/src/runtime/os_plan9_arm.go
+++ b/src/runtime/os_plan9_arm.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+var hardDiv bool // TODO: set if a hardware divider is available
+
 func checkgoarm() {
 	return // TODO(minux)
 }
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 75b8acd..72b57ad 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -50,6 +50,7 @@ const (
 //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"
+//go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll"
 
 type stdFunction unsafe.Pointer
 
@@ -73,9 +74,12 @@ var (
 	_GetQueuedCompletionStatus,
 	_GetStdHandle,
 	_GetSystemInfo,
+	_GetSystemTimeAsFileTime,
 	_GetThreadContext,
 	_LoadLibraryW,
 	_LoadLibraryA,
+	_QueryPerformanceCounter,
+	_QueryPerformanceFrequency,
 	_ResumeThread,
 	_SetConsoleCtrlHandler,
 	_SetErrorMode,
@@ -93,6 +97,7 @@ var (
 	_WriteConsoleW,
 	_WriteFile,
 	_timeBeginPeriod,
+	_timeEndPeriod,
 	_ stdFunction
 
 	// Following syscalls are only available on some Windows PCs.
@@ -188,6 +193,11 @@ func loadOptionalSyscalls() {
 		throw("ntdll.dll not found")
 	}
 	_NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
+
+	if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
+		// running on Wine
+		initWine(k32)
+	}
 }
 
 //go:nosplit
@@ -260,6 +270,21 @@ var useLoadLibraryEx bool
 
 var timeBeginPeriodRetValue uint32
 
+// osRelax is called by the scheduler when transitioning to and from
+// all Ps being idle.
+//
+// On Windows, it adjusts the system-wide timer resolution. Go needs a
+// high resolution timer while running and there's little extra cost
+// if we're already using the CPU, but if all Ps are idle there's no
+// need to consume extra power to drive the high-res timer.
+func osRelax(relax bool) uint32 {
+	if relax {
+		return uint32(stdcall1(_timeEndPeriod, 1))
+	} else {
+		return uint32(stdcall1(_timeBeginPeriod, 1))
+	}
+}
+
 func osinit() {
 	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
 	usleep2Addr = unsafe.Pointer(funcPC(usleep2))
@@ -279,7 +304,7 @@ func osinit() {
 
 	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
 
-	timeBeginPeriodRetValue = uint32(stdcall1(_timeBeginPeriod, 1))
+	timeBeginPeriodRetValue = osRelax(false)
 
 	ncpu = getproccount()
 
@@ -292,6 +317,79 @@ func osinit() {
 	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
 }
 
+func nanotime() int64
+
+// useQPCTime controls whether time.now and nanotime use QueryPerformanceCounter.
+// This is only set to 1 when running under Wine.
+var useQPCTime uint8
+
+var qpcStartCounter int64
+var qpcMultiplier int64
+
+//go:nosplit
+func nanotimeQPC() int64 {
+	var counter int64 = 0
+	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
+
+	// returns number of nanoseconds
+	return (counter - qpcStartCounter) * qpcMultiplier
+}
+
+//go:nosplit
+func nowQPC() (sec int64, nsec int32, mono int64) {
+	var ft int64
+	stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))
+
+	t := (ft - 116444736000000000) * 100
+
+	sec = t / 1000000000
+	nsec = int32(t - sec*1000000000)
+
+	mono = nanotimeQPC()
+	return
+}
+
+func initWine(k32 uintptr) {
+	_GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
+	if _GetSystemTimeAsFileTime == nil {
+		throw("could not find GetSystemTimeAsFileTime() syscall")
+	}
+
+	_QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
+	_QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
+	if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
+		throw("could not find QPC syscalls")
+	}
+
+	// We can not simply fallback to GetSystemTimeAsFileTime() syscall, since its time is not monotonic,
+	// instead we use QueryPerformanceCounter family of syscalls to implement monotonic timer
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
+
+	var tmp int64
+	stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
+	if tmp == 0 {
+		throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
+	}
+
+	// This should not overflow, it is a number of ticks of the performance counter per second,
+	// its resolution is at most 10 per usecond (on Wine, even smaller on real hardware), so it will be at most 10 millions here,
+	// panic if overflows.
+	if tmp > (1<<31 - 1) {
+		throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
+	}
+	qpcFrequency := int32(tmp)
+	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))
+
+	// Since we are supposed to run this time calls only on Wine, it does not lose precision,
+	// since Wine's timer is kind of emulated at 10 Mhz, so it will be a nice round multiplier of 100
+	// but for general purpose system (like 3.3 Mhz timer on i7) it will not be very precise.
+	// We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows
+	// int64 and resulted time will always be invalid.
+	qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
+
+	useQPCTime = 1
+}
+
 //go:nosplit
 func getRandomData(r []byte) {
 	n := 0
@@ -559,6 +657,11 @@ func msigrestore(sigmask sigset) {
 }
 
 //go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {
+}
+
+//go:nosplit
 func sigblock() {
 }
 
@@ -578,51 +681,6 @@ func unminit() {
 	*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
@@ -787,10 +845,7 @@ func profileloop1(param uintptr) uint32 {
 	}
 }
 
-var cpuprofilerlock mutex
-
-func resetcpuprofiler(hz int32) {
-	lock(&cpuprofilerlock)
+func setProcessCPUProfiler(hz int32) {
 	if profiletimer == 0 {
 		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
 		atomic.Storeuintptr(&profiletimer, timer)
@@ -798,8 +853,9 @@ func resetcpuprofiler(hz int32) {
 		stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
 		stdcall1(_CloseHandle, thread)
 	}
-	unlock(&cpuprofilerlock)
+}
 
+func setThreadCPUProfiler(hz int32) {
 	ms := int32(0)
 	due := ^int64(^uint64(1 << 63))
 	if hz > 0 {
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 876bca7..43bfdd7 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -456,6 +456,8 @@ func gopanic(e interface{}) {
 	p.link = gp._panic
 	gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
 
+	atomic.Xadd(&runningPanicDefers, 1)
+
 	for {
 		d := gp._defer
 		if d == nil {
@@ -504,6 +506,8 @@ func gopanic(e interface{}) {
 		sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
 		freedefer(d)
 		if p.recovered {
+			atomic.Xadd(&runningPanicDefers, -1)
+
 			gp._panic = p.link
 			// Aborted panics are marked but remain on the g.panic list.
 			// Remove them from the list.
@@ -527,6 +531,11 @@ func gopanic(e interface{}) {
 	// and String methods to prepare the panic strings before startpanic.
 	preprintpanics(gp._panic)
 	startpanic()
+
+	// startpanic set panicking, which will block main from exiting,
+	// so now OK to decrement runningPanicDefers.
+	atomic.Xadd(&runningPanicDefers, -1)
+
 	printpanics(gp._panic)
 	dopanic(0)       // should not return
 	*(*int)(nil) = 0 // not reached
@@ -597,7 +606,17 @@ func throw(s string) {
 	*(*int)(nil) = 0 // not reached
 }
 
-//uint32 runtime·panicking;
+// runningPanicDefers is non-zero while running deferred functions for panic.
+// runningPanicDefers is incremented and decremented atomically.
+// This is used to try hard to get a panic stack trace out when exiting.
+var runningPanicDefers uint32
+
+// panicking is non-zero when crashing the program for an unrecovered panic.
+// panicking is incremented and decremented atomically.
+var panicking uint32
+
+// paniclk is held while printing the panic information and stack trace,
+// so that two concurrent panics don't overlap their output.
 var paniclk mutex
 
 // Unwind the stack after a deferred function calls recover
@@ -617,7 +636,6 @@ func recovery(gp *g) {
 	// Make the deferproc for this d return again,
 	// this time returning 1.  The calling function will
 	// jump to the standard return epilogue.
-	gcUnwindBarriers(gp, sp)
 	gp.sched.sp = sp
 	gp.sched.pc = pc
 	gp.sched.lr = 0
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
index 8edb29c..682caac 100644
--- a/src/runtime/plugin.go
+++ b/src/runtime/plugin.go
@@ -56,7 +56,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
 
 	lock(&ifaceLock)
 	for _, i := range md.itablinks {
-		if i.inhash == 0 {
+		if !i.inhash {
 			additab(i, true, false)
 		}
 	}
@@ -95,7 +95,7 @@ func pluginftabverify(md *moduledata) {
 			continue
 		}
 
-		f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
+		f := funcInfo{(*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff])), md}
 		name := funcname(f)
 
 		// A common bug is f.entry has a relocation to a duplicate
@@ -104,7 +104,7 @@ func pluginftabverify(md *moduledata) {
 		name2 := "none"
 		entry2 := uintptr(0)
 		f2 := findfunc(entry)
-		if f2 != nil {
+		if f2.valid() {
 			name2 = funcname(f2)
 			entry2 = f2.entry
 		}
diff --git a/src/runtime/pprof/elf.go b/src/runtime/pprof/elf.go
new file mode 100644
index 0000000..a8b5ea6
--- /dev/null
+++ b/src/runtime/pprof/elf.go
@@ -0,0 +1,109 @@
+// Copyright 2017 The Go Authors. 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
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"os"
+)
+
+var (
+	errBadELF    = errors.New("malformed ELF binary")
+	errNoBuildID = errors.New("no NT_GNU_BUILD_ID found in ELF binary")
+)
+
+// elfBuildID returns the GNU build ID of the named ELF binary,
+// without introducing a dependency on debug/elf and its dependencies.
+func elfBuildID(file string) (string, error) {
+	buf := make([]byte, 256)
+	f, err := os.Open(file)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	if _, err := f.ReadAt(buf[:64], 0); err != nil {
+		return "", err
+	}
+
+	// ELF file begins with \x7F E L F.
+	if buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F' {
+		return "", errBadELF
+	}
+
+	var byteOrder binary.ByteOrder
+	switch buf[5] {
+	default:
+		return "", errBadELF
+	case 1: // little-endian
+		byteOrder = binary.LittleEndian
+	case 2: // big-endian
+		byteOrder = binary.BigEndian
+	}
+
+	var shnum int
+	var shoff, shentsize int64
+	switch buf[4] {
+	default:
+		return "", errBadELF
+	case 1: // 32-bit file header
+		shoff = int64(byteOrder.Uint32(buf[32:]))
+		shentsize = int64(byteOrder.Uint16(buf[46:]))
+		if shentsize != 40 {
+			return "", errBadELF
+		}
+		shnum = int(byteOrder.Uint16(buf[48:]))
+	case 2: // 64-bit file header
+		shoff = int64(byteOrder.Uint64(buf[40:]))
+		shentsize = int64(byteOrder.Uint16(buf[58:]))
+		if shentsize != 64 {
+			return "", errBadELF
+		}
+		shnum = int(byteOrder.Uint16(buf[60:]))
+	}
+
+	for i := 0; i < shnum; i++ {
+		if _, err := f.ReadAt(buf[:shentsize], shoff+int64(i)*shentsize); err != nil {
+			return "", err
+		}
+		if typ := byteOrder.Uint32(buf[4:]); typ != 7 { // SHT_NOTE
+			continue
+		}
+		var off, size int64
+		if shentsize == 40 {
+			// 32-bit section header
+			off = int64(byteOrder.Uint32(buf[16:]))
+			size = int64(byteOrder.Uint32(buf[20:]))
+		} else {
+			// 64-bit section header
+			off = int64(byteOrder.Uint64(buf[24:]))
+			size = int64(byteOrder.Uint64(buf[32:]))
+		}
+		size += off
+		for off < size {
+			if _, err := f.ReadAt(buf[:16], off); err != nil { // room for header + name GNU\x00
+				return "", err
+			}
+			nameSize := int(byteOrder.Uint32(buf[0:]))
+			descSize := int(byteOrder.Uint32(buf[4:]))
+			noteType := int(byteOrder.Uint32(buf[8:]))
+			descOff := off + int64(12+(nameSize+3)&^3)
+			off = descOff + int64((descSize+3)&^3)
+			if nameSize != 4 || noteType != 3 || buf[12] != 'G' || buf[13] != 'N' || buf[14] != 'U' || buf[15] != '\x00' { // want name GNU\x00 type 3 (NT_GNU_BUILD_ID)
+				continue
+			}
+			if descSize > len(buf) {
+				return "", errBadELF
+			}
+			if _, err := f.ReadAt(buf[:descSize], descOff); err != nil {
+				return "", err
+			}
+			return fmt.Sprintf("%x", buf[:descSize]), nil
+		}
+	}
+	return "", errNoBuildID
+}
diff --git a/src/internal/pprof/profile/encode.go b/src/runtime/pprof/internal/profile/encode.go
similarity index 100%
rename from src/internal/pprof/profile/encode.go
rename to src/runtime/pprof/internal/profile/encode.go
diff --git a/src/internal/pprof/profile/filter.go b/src/runtime/pprof/internal/profile/filter.go
similarity index 100%
rename from src/internal/pprof/profile/filter.go
rename to src/runtime/pprof/internal/profile/filter.go
diff --git a/src/internal/pprof/profile/legacy_profile.go b/src/runtime/pprof/internal/profile/legacy_profile.go
similarity index 100%
rename from src/internal/pprof/profile/legacy_profile.go
rename to src/runtime/pprof/internal/profile/legacy_profile.go
diff --git a/src/runtime/pprof/internal/profile/profile.go b/src/runtime/pprof/internal/profile/profile.go
new file mode 100644
index 0000000..9b6a6f9
--- /dev/null
+++ b/src/runtime/pprof/internal/profile/profile.go
@@ -0,0 +1,575 @@
+// Copyright 2014 The Go Authors. 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.
+//
+// This package is only for testing runtime/pprof.
+// It is not used by production Go programs.
+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/internal/pprof/profile/profile_test.go b/src/runtime/pprof/internal/profile/profile_test.go
similarity index 100%
rename from src/internal/pprof/profile/profile_test.go
rename to src/runtime/pprof/internal/profile/profile_test.go
diff --git a/src/internal/pprof/profile/proto.go b/src/runtime/pprof/internal/profile/proto.go
similarity index 100%
rename from src/internal/pprof/profile/proto.go
rename to src/runtime/pprof/internal/profile/proto.go
diff --git a/src/internal/pprof/profile/proto_test.go b/src/runtime/pprof/internal/profile/proto_test.go
similarity index 100%
rename from src/internal/pprof/profile/proto_test.go
rename to src/runtime/pprof/internal/profile/proto_test.go
diff --git a/src/internal/pprof/profile/prune.go b/src/runtime/pprof/internal/profile/prune.go
similarity index 100%
rename from src/internal/pprof/profile/prune.go
rename to src/runtime/pprof/internal/profile/prune.go
diff --git a/src/runtime/pprof/internal/protopprof/protomemprofile.go b/src/runtime/pprof/internal/protopprof/protomemprofile.go
deleted file mode 100644
index c2ab5b5..0000000
--- a/src/runtime/pprof/internal/protopprof/protomemprofile.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package protopprof
-
-import (
-	"internal/pprof/profile"
-	"math"
-	"runtime"
-	"time"
-)
-
-// EncodeMemProfile converts MemProfileRecords to a Profile.
-func EncodeMemProfile(mr []runtime.MemProfileRecord, rate int64, t time.Time) *profile.Profile {
-	p := &profile.Profile{
-		Period:     rate,
-		PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"},
-		SampleType: []*profile.ValueType{
-			{Type: "alloc_objects", Unit: "count"},
-			{Type: "alloc_space", Unit: "bytes"},
-			{Type: "inuse_objects", Unit: "count"},
-			{Type: "inuse_space", Unit: "bytes"},
-		},
-		TimeNanos: int64(t.UnixNano()),
-	}
-
-	locs := make(map[uintptr]*profile.Location)
-	for _, r := range mr {
-		stack := r.Stack()
-		sloc := make([]*profile.Location, len(stack))
-		for i, addr := range stack {
-			loc := locs[addr]
-			if loc == nil {
-				loc = &profile.Location{
-					ID:      uint64(len(p.Location) + 1),
-					Address: uint64(addr),
-				}
-				locs[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			sloc[i] = loc
-		}
-
-		ao, ab := scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
-		uo, ub := scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
-
-		p.Sample = append(p.Sample, &profile.Sample{
-			Value:    []int64{ao, ab, uo, ub},
-			Location: sloc,
-		})
-	}
-	if runtime.GOOS == "linux" {
-		addMappings(p)
-	}
-	return p
-}
-
-// scaleHeapSample adjusts the data from a heap Sample to
-// account for its probability of appearing in the collected
-// data. heap 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. heap 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)
-}
diff --git a/src/runtime/pprof/internal/protopprof/protomemprofile_test.go b/src/runtime/pprof/internal/protopprof/protomemprofile_test.go
deleted file mode 100644
index a10fe77..0000000
--- a/src/runtime/pprof/internal/protopprof/protomemprofile_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package protopprof
-
-import (
-	"bytes"
-	"internal/pprof/profile"
-	"io/ioutil"
-	"reflect"
-	"runtime"
-	"testing"
-	"time"
-)
-
-// TestSampledHeapAllocProfile tests encoding of a memory profile from
-// runtime.MemProfileRecord data.
-func TestSampledHeapAllocProfile(t *testing.T) {
-	if runtime.GOOS != "linux" {
-		t.Skip("Test requires a system with /proc/self/maps")
-	}
-
-	// Figure out two addresses from /proc/self/maps.
-	mmap, err := ioutil.ReadFile("/proc/self/maps")
-	if err != nil {
-		t.Fatal("Cannot read /proc/self/maps")
-	}
-	rd := bytes.NewReader(mmap)
-	mprof := &profile.Profile{}
-	if err = mprof.ParseMemoryMap(rd); err != nil {
-		t.Fatalf("Cannot parse /proc/self/maps")
-	}
-	if len(mprof.Mapping) < 2 {
-		// It is possible for a binary to only have 1 executable
-		// region of memory.
-		t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping))
-	}
-	address1 := mprof.Mapping[0].Start
-	address2 := mprof.Mapping[1].Start
-
-	var buf bytes.Buffer
-
-	rec, rate := testMemRecords(address1, address2)
-	p := EncodeMemProfile(rec, rate, time.Now())
-	if err := p.Write(&buf); err != nil {
-		t.Fatalf("Failed to write profile: %v", err)
-	}
-
-	p, err = profile.Parse(&buf)
-	if err != nil {
-		t.Fatalf("Could not parse Profile profile: %v", err)
-	}
-
-	// Expected PeriodType, SampleType and Sample.
-	expectedPeriodType := &profile.ValueType{Type: "space", Unit: "bytes"}
-	expectedSampleType := []*profile.ValueType{
-		{Type: "alloc_objects", Unit: "count"},
-		{Type: "alloc_space", Unit: "bytes"},
-		{Type: "inuse_objects", Unit: "count"},
-		{Type: "inuse_space", Unit: "bytes"},
-	}
-	// Expected samples, with values unsampled according to the profiling rate.
-	expectedSample := []*profile.Sample{
-		{Value: []int64{2050, 2099200, 1537, 1574400}, Location: []*profile.Location{
-			{ID: 1, Mapping: mprof.Mapping[0], Address: address1},
-			{ID: 2, Mapping: mprof.Mapping[1], Address: address2},
-		}},
-		{Value: []int64{1, 829411, 1, 829411}, Location: []*profile.Location{
-			{ID: 3, Mapping: mprof.Mapping[1], Address: address2 + 1},
-			{ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 2},
-		}},
-		{Value: []int64{1, 829411, 0, 0}, Location: []*profile.Location{
-			{ID: 5, Mapping: mprof.Mapping[0], Address: address1 + 1},
-			{ID: 6, Mapping: mprof.Mapping[0], Address: address1 + 2},
-			{ID: 7, Mapping: mprof.Mapping[1], Address: address2 + 3},
-		}},
-	}
-
-	if p.Period != 512*1024 {
-		t.Fatalf("Sampling periods do not match")
-	}
-	if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) {
-		t.Fatalf("Period types do not match")
-	}
-	if !reflect.DeepEqual(p.SampleType, expectedSampleType) {
-		t.Fatalf("Sample types do not match")
-	}
-	if !reflect.DeepEqual(p.Sample, expectedSample) {
-		t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample),
-			getSampleAsString(p.Sample))
-	}
-}
-
-func testMemRecords(a1, a2 uint64) ([]runtime.MemProfileRecord, int64) {
-	addr1, addr2 := uintptr(a1), uintptr(a2)
-	rate := int64(512 * 1024)
-	rec := []runtime.MemProfileRecord{
-		{4096, 1024, 4, 1, [32]uintptr{addr1, addr2}},
-		{512 * 1024, 0, 1, 0, [32]uintptr{addr2 + 1, addr2 + 2}},
-		{512 * 1024, 512 * 1024, 1, 1, [32]uintptr{addr1 + 1, addr1 + 2, addr2 + 3}},
-	}
-	return rec, rate
-}
diff --git a/src/runtime/pprof/internal/protopprof/protopprof.go b/src/runtime/pprof/internal/protopprof/protopprof.go
deleted file mode 100644
index 5d269c4..0000000
--- a/src/runtime/pprof/internal/protopprof/protopprof.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package protopprof converts the runtime's raw profile logs
-// to Profile structs containing a representation of the pprof
-// protocol buffer profile format.
-package protopprof
-
-import (
-	"fmt"
-	"os"
-	"runtime"
-	"time"
-	"unsafe"
-
-	"internal/pprof/profile"
-)
-
-// TranslateCPUProfile parses binary CPU profiling stack trace data
-// generated by runtime.CPUProfile() into a profile struct.
-func TranslateCPUProfile(b []byte, startTime time.Time) (*profile.Profile, error) {
-	const wordSize = unsafe.Sizeof(uintptr(0))
-	const minRawProfile = 5 * wordSize // Need a minimum of 5 words.
-	if uintptr(len(b)) < minRawProfile {
-		return nil, fmt.Errorf("truncated profile")
-	}
-	n := int(uintptr(len(b)) / wordSize)
-	data := ((*[1 << 28]uintptr)(unsafe.Pointer(&b[0])))[:n:n]
-	period := data[3]
-	data = data[5:] // skip header
-
-	// profile initialization taken from pprof tool
-	p := &profile.Profile{
-		Period:     int64(period) * 1000,
-		PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"},
-		SampleType: []*profile.ValueType{
-			{Type: "samples", Unit: "count"},
-			{Type: "cpu", Unit: "nanoseconds"},
-		},
-		TimeNanos:     int64(startTime.UnixNano()),
-		DurationNanos: time.Since(startTime).Nanoseconds(),
-	}
-	// Parse CPU samples from the profile.
-	locs := make(map[uint64]*profile.Location)
-	for len(b) > 0 {
-		if len(data) < 2 || uintptr(len(data)) < 2+data[1] {
-			return nil, fmt.Errorf("truncated profile")
-		}
-		count := data[0]
-		nstk := data[1]
-		if uintptr(len(data)) < 2+nstk {
-			return nil, fmt.Errorf("truncated profile")
-		}
-		stk := data[2 : 2+nstk]
-		data = data[2+nstk:]
-
-		if count == 0 && nstk == 1 && stk[0] == 0 {
-			// end of data marker
-			break
-		}
-
-		sloc := make([]*profile.Location, len(stk))
-		for i, addr := range stk {
-			addr := uint64(addr)
-			// 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 loc == nil {
-				loc = &profile.Location{
-					ID:      uint64(len(p.Location) + 1),
-					Address: addr,
-				}
-				locs[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			sloc[i] = loc
-		}
-		p.Sample = append(p.Sample, &profile.Sample{
-			Value:    []int64{int64(count), int64(count) * int64(p.Period)},
-			Location: sloc,
-		})
-	}
-
-	if runtime.GOOS == "linux" {
-		if err := addMappings(p); err != nil {
-			return nil, err
-		}
-	}
-	return p, nil
-}
-
-func addMappings(p *profile.Profile) error {
-	// Parse memory map from /proc/self/maps
-	f, err := os.Open("/proc/self/maps")
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-	return p.ParseMemoryMap(f)
-}
diff --git a/src/runtime/pprof/internal/protopprof/protopprof_test.go b/src/runtime/pprof/internal/protopprof/protopprof_test.go
deleted file mode 100644
index f1937b5..0000000
--- a/src/runtime/pprof/internal/protopprof/protopprof_test.go
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package protopprof
-
-import (
-	"bytes"
-	"fmt"
-	"internal/pprof/profile"
-	"io/ioutil"
-	"reflect"
-	"runtime"
-	"testing"
-	"time"
-	"unsafe"
-)
-
-// Helper function to initialize empty cpu profile with sampling period provided.
-func createEmptyProfileWithPeriod(t *testing.T, periodMs uint64) bytes.Buffer {
-	// Mock the sample header produced by cpu profiler. Write a sample
-	// period of 2000 microseconds, followed by no samples.
-	buf := new(bytes.Buffer)
-	// Profile header is as follows:
-	// The first, third and fifth words are 0. The second word is 3.
-	// The fourth word is the period.
-	// EOD marker:
-	// The sixth word -- count is initialized to 0 above.
-	// The code below sets the seventh word -- nstk to 1
-	// The eighth word -- addr is initialized to 0 above.
-	words := []int{0, 3, 0, int(periodMs), 0, 0, 1, 0}
-	n := int(unsafe.Sizeof(0)) * len(words)
-	data := ((*[1 << 29]byte)(unsafe.Pointer(&words[0])))[:n:n]
-	if _, err := buf.Write(data); err != nil {
-		t.Fatalf("createEmptyProfileWithPeriod failed: %v", err)
-	}
-	return *buf
-}
-
-// Helper function to initialize cpu profile with two sample values.
-func createProfileWithTwoSamples(t *testing.T, periodMs uintptr, count1 uintptr, count2 uintptr,
-	address1 uintptr, address2 uintptr) bytes.Buffer {
-	// Mock the sample header produced by cpu profiler. Write a sample
-	// period of 2000 microseconds, followed by no samples.
-	buf := new(bytes.Buffer)
-	words := []uintptr{0, 3, 0, uintptr(periodMs), 0, uintptr(count1), 2,
-		uintptr(address1), uintptr(address1 + 2),
-		uintptr(count2), 2, uintptr(address2), uintptr(address2 + 2),
-		0, 1, 0}
-	for _, n := range words {
-		var err error
-		switch unsafe.Sizeof(int(0)) {
-		case 8:
-			_, err = buf.Write((*[8]byte)(unsafe.Pointer(&n))[:8:8])
-		case 4:
-			_, err = buf.Write((*[4]byte)(unsafe.Pointer(&n))[:4:4])
-		}
-		if err != nil {
-			t.Fatalf("createProfileWithTwoSamples failed: %v", err)
-		}
-	}
-	return *buf
-}
-
-// Tests TranslateCPUProfile parses correct sampling period in an otherwise empty cpu profile.
-func TestTranlateCPUProfileSamplingPeriod(t *testing.T) {
-	// A test server with mock cpu profile data.
-	var buf bytes.Buffer
-
-	startTime := time.Now()
-	b := createEmptyProfileWithPeriod(t, 2000)
-	p, err := TranslateCPUProfile(b.Bytes(), startTime)
-	if err != nil {
-		t.Fatalf("translate failed: %v", err)
-	}
-	if err := p.Write(&buf); err != nil {
-		t.Fatalf("write failed: %v", err)
-	}
-
-	p, err = profile.Parse(&buf)
-	if err != nil {
-		t.Fatalf("Could not parse Profile profile: %v", err)
-	}
-
-	// Expected PeriodType and SampleType.
-	expectedPeriodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
-	expectedSampleType := []*profile.ValueType{
-		{Type: "samples", Unit: "count"},
-		{Type: "cpu", Unit: "nanoseconds"},
-	}
-	if p.Period != 2000*1000 || !reflect.DeepEqual(p.PeriodType, expectedPeriodType) ||
-		!reflect.DeepEqual(p.SampleType, expectedSampleType) || p.Sample != nil {
-		t.Fatalf("Unexpected Profile fields")
-	}
-}
-
-func getSampleAsString(sample []*profile.Sample) string {
-	var str string
-	for _, x := range sample {
-		for _, y := range x.Location {
-			if y.Mapping != nil {
-				str += fmt.Sprintf("Mapping:%v\n", *y.Mapping)
-			}
-			str += fmt.Sprintf("Location:%v\n", y)
-		}
-		str += fmt.Sprintf("Sample:%v\n", *x)
-	}
-	return str
-}
-
-// Tests TranslateCPUProfile parses a cpu profile with sample values present.
-func TestTranslateCPUProfileWithSamples(t *testing.T) {
-	if runtime.GOOS != "linux" {
-		t.Skip("test requires a system with /proc/self/maps")
-	}
-	// Figure out two addresses from /proc/self/maps.
-	mmap, err := ioutil.ReadFile("/proc/self/maps")
-	if err != nil {
-		t.Fatal("Cannot read /proc/self/maps")
-	}
-	rd := bytes.NewReader(mmap)
-	mprof := &profile.Profile{}
-	if err = mprof.ParseMemoryMap(rd); err != nil {
-		t.Fatalf("Cannot parse /proc/self/maps")
-	}
-	if len(mprof.Mapping) < 2 {
-		// It is possible for a binary to only have 1 executable
-		// region of memory.
-		t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping))
-	}
-	address1 := mprof.Mapping[0].Start
-	address2 := mprof.Mapping[1].Start
-	// A test server with mock cpu profile data.
-
-	startTime := time.Now()
-	b := createProfileWithTwoSamples(t, 2000, 20, 40, uintptr(address1), uintptr(address2))
-	p, err := TranslateCPUProfile(b.Bytes(), startTime)
-
-	if err != nil {
-		t.Fatalf("Could not parse Profile profile: %v", err)
-	}
-	// Expected PeriodType, SampleType and Sample.
-	expectedPeriodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
-	expectedSampleType := []*profile.ValueType{
-		{Type: "samples", Unit: "count"},
-		{Type: "cpu", Unit: "nanoseconds"},
-	}
-	expectedSample := []*profile.Sample{
-		{Value: []int64{20, 20 * 2000 * 1000}, Location: []*profile.Location{
-			{ID: 1, Mapping: mprof.Mapping[0], Address: address1},
-			{ID: 2, Mapping: mprof.Mapping[0], Address: address1 + 1},
-		}},
-		{Value: []int64{40, 40 * 2000 * 1000}, Location: []*profile.Location{
-			{ID: 3, Mapping: mprof.Mapping[1], Address: address2},
-			{ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 1},
-		}},
-	}
-	if p.Period != 2000*1000 {
-		t.Fatalf("Sampling periods do not match")
-	}
-	if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) {
-		t.Fatalf("Period types do not match")
-	}
-	if !reflect.DeepEqual(p.SampleType, expectedSampleType) {
-		t.Fatalf("Sample types do not match")
-	}
-	if !reflect.DeepEqual(p.Sample, expectedSample) {
-		t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample),
-			getSampleAsString(p.Sample))
-	}
-}
diff --git a/src/runtime/pprof/label.go b/src/runtime/pprof/label.go
new file mode 100644
index 0000000..44da3f8
--- /dev/null
+++ b/src/runtime/pprof/label.go
@@ -0,0 +1,85 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"context"
+)
+
+type label struct {
+	key   string
+	value string
+}
+
+// LabelSet is a set of labels.
+type LabelSet struct {
+	list []label
+}
+
+// labelContextKey is the type of contextKeys used for profiler labels.
+type labelContextKey struct{}
+
+func labelValue(ctx context.Context) labelMap {
+	labels, _ := ctx.Value(labelContextKey{}).(*labelMap)
+	if labels == nil {
+		return labelMap(nil)
+	}
+	return *labels
+}
+
+// labelMap is the representation of the label set held in the context type.
+// This is an initial implementation, but it will be replaced with something
+// that admits incremental immutable modification more efficiently.
+type labelMap map[string]string
+
+// WithLabels returns a new context.Context with the given labels added.
+// A label overwrites a prior label with the same key.
+func WithLabels(ctx context.Context, labels LabelSet) context.Context {
+	childLabels := make(labelMap)
+	parentLabels := labelValue(ctx)
+	// TODO(matloob): replace the map implementation with something
+	// more efficient so creating a child context WithLabels doesn't need
+	// to clone the map.
+	for k, v := range parentLabels {
+		childLabels[k] = v
+	}
+	for _, label := range labels.list {
+		childLabels[label.key] = label.value
+	}
+	return context.WithValue(ctx, labelContextKey{}, &childLabels)
+}
+
+// Labels takes an even number of strings representing key-value pairs
+// and makes a LabelList containing them.
+// A label overwrites a prior label with the same key.
+func Labels(args ...string) LabelSet {
+	if len(args)%2 != 0 {
+		panic("uneven number of arguments to pprof.Labels")
+	}
+	labels := LabelSet{}
+	for i := 0; i+1 < len(args); i += 2 {
+		labels.list = append(labels.list, label{key: args[i], value: args[i+1]})
+	}
+	return labels
+}
+
+// Label returns the value of the label with the given key on ctx, and a boolean indicating
+// whether that label exists.
+func Label(ctx context.Context, key string) (string, bool) {
+	ctxLabels := labelValue(ctx)
+	v, ok := ctxLabels[key]
+	return v, ok
+}
+
+// ForLabels invokes f with each label set on the context.
+// The function f should return true to continue iteration or false to stop iteration early.
+func ForLabels(ctx context.Context, f func(key, value string) bool) {
+	ctxLabels := labelValue(ctx)
+	for k, v := range ctxLabels {
+		if !f(k, v) {
+			break
+		}
+	}
+}
diff --git a/src/runtime/pprof/label_test.go b/src/runtime/pprof/label_test.go
new file mode 100644
index 0000000..240445f
--- /dev/null
+++ b/src/runtime/pprof/label_test.go
@@ -0,0 +1,82 @@
+package pprof
+
+import (
+	"context"
+	"reflect"
+	"sort"
+	"testing"
+)
+
+func labelsSorted(ctx context.Context) []label {
+	ls := []label{}
+	ForLabels(ctx, func(key, value string) bool {
+		ls = append(ls, label{key, value})
+		return true
+	})
+	sort.Sort(labelSorter(ls))
+	return ls
+}
+
+type labelSorter []label
+
+func (s labelSorter) Len() int           { return len(s) }
+func (s labelSorter) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s labelSorter) Less(i, j int) bool { return s[i].key < s[j].key }
+
+func TestContextLabels(t *testing.T) {
+	// Background context starts with no lablels.
+	ctx := context.Background()
+	labels := labelsSorted(ctx)
+	if len(labels) != 0 {
+		t.Errorf("labels on background context: want [], got %v ", labels)
+	}
+
+	// Add a single label.
+	ctx = WithLabels(ctx, Labels("key", "value"))
+	// Retrieve it with Label.
+	v, ok := Label(ctx, "key")
+	if !ok || v != "value" {
+		t.Errorf(`Label(ctx, "key"): got %v, %v; want "value", ok`, v, ok)
+	}
+	gotLabels := labelsSorted(ctx)
+	wantLabels := []label{{"key", "value"}}
+	if !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
+	}
+
+	// Add a label with a different key.
+	ctx = WithLabels(ctx, Labels("key2", "value2"))
+	v, ok = Label(ctx, "key2")
+	if !ok || v != "value2" {
+		t.Errorf(`Label(ctx, "key2"): got %v, %v; want "value2", ok`, v, ok)
+	}
+	gotLabels = labelsSorted(ctx)
+	wantLabels = []label{{"key", "value"}, {"key2", "value2"}}
+	if !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
+	}
+
+	// Add label with first key to test label replacement.
+	ctx = WithLabels(ctx, Labels("key", "value3"))
+	v, ok = Label(ctx, "key")
+	if !ok || v != "value3" {
+		t.Errorf(`Label(ctx, "key3"): got %v, %v; want "value3", ok`, v, ok)
+	}
+	gotLabels = labelsSorted(ctx)
+	wantLabels = []label{{"key", "value3"}, {"key2", "value2"}}
+	if !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
+	}
+
+	// Labels called with two labels with the same key should pick the second.
+	ctx = WithLabels(ctx, Labels("key4", "value4a", "key4", "value4b"))
+	v, ok = Label(ctx, "key4")
+	if !ok || v != "value4b" {
+		t.Errorf(`Label(ctx, "key4"): got %v, %v; want "value4b", ok`, v, ok)
+	}
+	gotLabels = labelsSorted(ctx)
+	wantLabels = []label{{"key", "value3"}, {"key2", "value2"}, {"key4", "value4b"}}
+	if !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("(sorted) labels on context: got %v, want %v", gotLabels, wantLabels)
+	}
+}
diff --git a/src/runtime/pprof/map.go b/src/runtime/pprof/map.go
new file mode 100644
index 0000000..a271ad0
--- /dev/null
+++ b/src/runtime/pprof/map.go
@@ -0,0 +1,89 @@
+// Copyright 2017 The Go Authors. 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
+
+import "unsafe"
+
+// A profMap is a map from (stack, tag) to mapEntry.
+// It grows without bound, but that's assumed to be OK.
+type profMap struct {
+	hash    map[uintptr]*profMapEntry
+	all     *profMapEntry
+	last    *profMapEntry
+	free    []profMapEntry
+	freeStk []uintptr
+}
+
+// A profMapEntry is a single entry in the profMap.
+type profMapEntry struct {
+	nextHash *profMapEntry // next in hash list
+	nextAll  *profMapEntry // next in list of all entries
+	stk      []uintptr
+	tag      unsafe.Pointer
+	count    int64
+}
+
+func (m *profMap) lookup(stk []uint64, tag unsafe.Pointer) *profMapEntry {
+	// Compute hash of (stk, tag).
+	h := uintptr(0)
+	for _, x := range stk {
+		h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
+		h += uintptr(x) * 41
+	}
+	h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
+	h += uintptr(tag) * 41
+
+	// Find entry if present.
+	var last *profMapEntry
+Search:
+	for e := m.hash[h]; e != nil; last, e = e, e.nextHash {
+		if len(e.stk) != len(stk) || e.tag != tag {
+			continue
+		}
+		for j := range stk {
+			if e.stk[j] != uintptr(stk[j]) {
+				continue Search
+			}
+		}
+		// Move to front.
+		if last != nil {
+			last.nextHash = e.nextHash
+			e.nextHash = m.hash[h]
+			m.hash[h] = e
+		}
+		return e
+	}
+
+	// Add new entry.
+	if len(m.free) < 1 {
+		m.free = make([]profMapEntry, 128)
+	}
+	e := &m.free[0]
+	m.free = m.free[1:]
+	e.nextHash = m.hash[h]
+	e.tag = tag
+
+	if len(m.freeStk) < len(stk) {
+		m.freeStk = make([]uintptr, 1024)
+	}
+	e.stk = m.freeStk[:len(stk)]
+	m.freeStk = m.freeStk[len(stk):]
+
+	for j := range stk {
+		e.stk[j] = uintptr(stk[j])
+	}
+	if m.hash == nil {
+		m.hash = make(map[uintptr]*profMapEntry)
+	}
+	m.hash[h] = e
+	if m.all == nil {
+		m.all = e
+		m.last = e
+	} else {
+		m.last.nextAll = e
+		m.last = e
+	}
+	return e
+}
diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go
index df4f6f8..4c14527 100644
--- a/src/runtime/pprof/mprof_test.go
+++ b/src/runtime/pprof/mprof_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.
 
-package pprof_test
+package pprof
 
 import (
 	"bytes"
@@ -10,7 +10,6 @@ import (
 	"reflect"
 	"regexp"
 	"runtime"
-	. "runtime/pprof"
 	"testing"
 	"unsafe"
 )
@@ -86,22 +85,22 @@ func TestMemoryProfiler(t *testing.T) {
 
 	tests := []string{
 		fmt.Sprintf(`%v: %v \[%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\.allocatePersistent1K\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:41
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:75
+#	0x[0-9,a-f]+	runtime/pprof\.allocatePersistent1K\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:40
+#	0x[0-9,a-f]+	runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:74
 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*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]+	runtime/pprof_test\.allocateTransient1M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:22
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:73
+#	0x[0-9,a-f]+	runtime/pprof\.allocateTransient1M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:21
+#	0x[0-9,a-f]+	runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:72
 `, (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]+	runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:28
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:74
+#	0x[0-9,a-f]+	runtime/pprof\.allocateTransient2M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:27
+#	0x[0-9,a-f]+	runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:73
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
 
 		fmt.Sprintf(`0: 0 \[%v: %v\] @( 0x[0-9,a-f]+)+
-#	0x[0-9,a-f]+	runtime/pprof_test\.allocateReflectTransient\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:49
+#	0x[0-9,a-f]+	runtime/pprof\.allocateReflectTransient\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:48
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
 	}
 
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 871fba0..21ea25c 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -33,7 +33,9 @@
 //            }
 //            defer pprof.StopCPUProfile()
 //        }
-//        ...
+//
+//        // ... rest of the program ...
+//
 //        if *memprofile != "" {
 //            f, err := os.Create(*memprofile)
 //            if err != nil {
@@ -73,15 +75,14 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
-	"internal/pprof/profile"
 	"io"
 	"runtime"
-	"runtime/pprof/internal/protopprof"
 	"sort"
 	"strings"
 	"sync"
 	"text/tabwriter"
 	"time"
+	"unsafe"
 )
 
 // BUG(rsc): Profiles are only as good as the kernel support used to generate them.
@@ -183,6 +184,8 @@ func unlockProfiles() {
 // If a profile with that name already exists, NewProfile panics.
 // The convention is to use a 'import/path.' prefix to create
 // separate name spaces for each package.
+// For compatibility with various tools that read pprof data,
+// profile names should not contain spaces.
 func NewProfile(name string) *Profile {
 	lockProfiles()
 	defer unlockProfiles()
@@ -264,13 +267,18 @@ func (p *Profile) Add(value interface{}, skip int) {
 
 	stk := make([]uintptr, 32)
 	n := runtime.Callers(skip+1, stk[:])
+	stk = stk[:n]
+	if len(stk) == 0 {
+		// The value for skip is too large, and there's no stack trace to record.
+		stk = []uintptr{funcPC(lostProfileEvent)}
+	}
 
 	p.mu.Lock()
 	defer p.mu.Unlock()
 	if p.m[value] != nil {
 		panic("pprof: Profile.Add of duplicate value")
 	}
-	p.m[value] = stk[:n]
+	p.m[value] = stk
 }
 
 // Remove removes the execution stack associated with value from the profile.
@@ -303,8 +311,8 @@ func (p *Profile) WriteTo(w io.Writer, debug int) error {
 	}
 
 	// Obtain consistent snapshot under lock; then process without lock.
-	all := make([][]uintptr, 0, len(p.m))
 	p.mu.Lock()
+	all := make([][]uintptr, 0, len(p.m))
 	for _, stk := range p.m {
 		all = append(all, stk)
 	}
@@ -380,35 +388,29 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
 	}
 
 	// Output profile in protobuf form.
-	prof := &profile.Profile{
-		PeriodType: &profile.ValueType{Type: name, Unit: "count"},
-		Period:     1,
-		Sample:     make([]*profile.Sample, 0, len(keys)),
-		SampleType: []*profile.ValueType{{Type: name, Unit: "count"}},
-	}
-	locMap := make(map[uintptr]*profile.Location)
+	b := newProfileBuilder(w)
+	b.pbValueType(tagProfile_PeriodType, name, "count")
+	b.pb.int64Opt(tagProfile_Period, 1)
+	b.pbValueType(tagProfile_SampleType, name, "count")
+
+	values := []int64{0}
+	var locs []uint64
 	for _, k := range keys {
-		stk := p.Stack(index[k])
-		c := count[k]
-		locs := make([]*profile.Location, len(stk))
-		for i, addr := range stk {
-			loc := locMap[addr]
-			if loc == nil {
-				loc = &profile.Location{
-					ID:      uint64(len(locMap) + 1),
-					Address: uint64(addr - 1),
-				}
-				prof.Location = append(prof.Location, loc)
-				locMap[addr] = loc
+		values[0] = int64(count[k])
+		locs = locs[:0]
+		for _, addr := range p.Stack(index[k]) {
+			// For count profiles, all stack addresses are
+			// return PCs, which is what locForPC expects.
+			l := b.locForPC(addr)
+			if l == 0 { // runtime.goexit
+				continue
 			}
-			locs[i] = loc
+			locs = append(locs, l)
 		}
-		prof.Sample = append(prof.Sample, &profile.Sample{
-			Location: locs,
-			Value:    []int64{int64(c)},
-		})
+		b.pbSample(values, locs, nil)
 	}
-	return prof.Write(w)
+	b.build()
+	return nil
 }
 
 // keysByCount sorts keys with higher counts first, breaking ties by key string order.
@@ -496,8 +498,7 @@ func writeHeap(w io.Writer, debug int) error {
 	}
 
 	if debug == 0 {
-		pp := protopprof.EncodeMemProfile(p, int64(runtime.MemProfileRate), time.Now())
-		return pp.Write(w)
+		return writeHeapProto(w, p, int64(runtime.MemProfileRate))
 	}
 
 	sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() })
@@ -562,8 +563,12 @@ func writeHeap(w io.Writer, debug int) error {
 	fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys)
 
 	fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+	fmt.Fprintf(w, "# LastGC = %d\n", s.LastGC)
 	fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+	fmt.Fprintf(w, "# PauseEnd = %d\n", s.PauseEnd)
 	fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+	fmt.Fprintf(w, "# NumForcedGC = %d\n", s.NumForcedGC)
+	fmt.Fprintf(w, "# GCCPUFraction = %v\n", s.GCCPUFraction)
 	fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
 
 	tw.Flush()
@@ -689,30 +694,32 @@ func StartCPUProfile(w io.Writer) error {
 	return nil
 }
 
+// readProfile, provided by the runtime, 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 data accumulated while it was
+// on has been returned, readProfile returns eof=true.
+// The caller must save the returned data and tags before calling readProfile again.
+func readProfile() (data []uint64, tags []unsafe.Pointer, eof bool)
+
 func profileWriter(w io.Writer) {
-	startTime := time.Now()
-	// This will buffer the entire profile into buf and then
-	// translate it into a profile.Profile structure. This will
-	// create two copies of all the data in the profile in memory.
-	// TODO(matloob): Convert each chunk of the proto output and
-	// stream it out instead of converting the entire profile.
-	var buf bytes.Buffer
+	b := newProfileBuilder(w)
+	var err error
 	for {
-		data := runtime.CPUProfile()
-		if data == nil {
+		time.Sleep(100 * time.Millisecond)
+		data, tags, eof := readProfile()
+		if e := b.addCPUData(data, tags); e != nil && err == nil {
+			err = e
+		}
+		if eof {
 			break
 		}
-		buf.Write(data)
 	}
-
-	profile, err := protopprof.TranslateCPUProfile(buf.Bytes(), startTime)
 	if err != nil {
 		// The runtime should never produce an invalid or truncated profile.
 		// It drops records that can't fit into its log buffers.
-		panic(fmt.Errorf("could not translate binary profile to proto format: %v", err))
+		panic("runtime/pprof: converting profile: " + err.Error())
 	}
-
-	profile.Write(w)
+	b.build()
 	cpu.done <- true
 }
 
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 8372283..22fea0a 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -4,22 +4,20 @@
 
 // +build !nacl
 
-package pprof_test
+package pprof
 
 import (
 	"bytes"
-	"compress/gzip"
+	"context"
 	"fmt"
-	"internal/pprof/profile"
 	"internal/testenv"
 	"io"
-	"io/ioutil"
 	"math/big"
 	"os"
 	"os/exec"
 	"regexp"
 	"runtime"
-	. "runtime/pprof"
+	"runtime/pprof/internal/profile"
 	"strings"
 	"sync"
 	"testing"
@@ -71,14 +69,14 @@ func cpuHog2() {
 }
 
 func TestCPUProfile(t *testing.T) {
-	testCPUProfile(t, []string{"runtime/pprof_test.cpuHog1"}, func(dur time.Duration) {
+	testCPUProfile(t, []string{"runtime/pprof.cpuHog1"}, func(dur time.Duration) {
 		cpuHogger(cpuHog1, dur)
 	})
 }
 
 func TestCPUProfileMultithreaded(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
-	testCPUProfile(t, []string{"runtime/pprof_test.cpuHog1", "runtime/pprof_test.cpuHog2"}, func(dur time.Duration) {
+	testCPUProfile(t, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog2"}, func(dur time.Duration) {
 		c := make(chan int)
 		go func() {
 			cpuHogger(cpuHog1, dur)
@@ -89,18 +87,41 @@ func TestCPUProfileMultithreaded(t *testing.T) {
 	})
 }
 
-func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) {
+func TestCPUProfileInlining(t *testing.T) {
+	testCPUProfile(t, []string{"runtime/pprof.inlinedCallee", "runtime/pprof.inlinedCaller"}, func(dur time.Duration) {
+		cpuHogger(inlinedCaller, dur)
+	})
+}
+
+func inlinedCaller() {
+	inlinedCallee()
+}
+
+func inlinedCallee() {
+	// We could just use cpuHog1, but for loops prevent inlining
+	// right now. :(
+	foo := salt1
+	i := 0
+loop:
+	if foo > 0 {
+		foo *= foo
+	} else {
+		foo *= foo + 1
+	}
+	if i++; i < 1e5 {
+		goto loop
+	}
+	salt1 = foo
+}
+
+func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Location, map[string][]string)) {
 	p, err := profile.Parse(bytes.NewReader(valBytes))
 	if err != nil {
 		t.Fatal(err)
 	}
 	for _, sample := range p.Sample {
 		count := uintptr(sample.Value[0])
-		stk := make([]uintptr, len(sample.Location))
-		for i := range sample.Location {
-			stk[i] = uintptr(sample.Location[i].Address)
-		}
-		f(count, stk)
+		f(count, sample.Location, sample.Label)
 	}
 }
 
@@ -124,8 +145,7 @@ func testCPUProfile(t *testing.T, need []string, f func(dur time.Duration)) {
 
 	const maxDuration = 5 * time.Second
 	// If we're running a long test, start with a long duration
-	// because some of the tests (e.g., TestStackBarrierProfiling)
-	// are trying to make sure something *doesn't* happen.
+	// for tests that try to make sure something *doesn't* happen.
 	duration := 5 * time.Second
 	if testing.Short() {
 		duration = 200 * time.Millisecond
@@ -169,31 +189,45 @@ func testCPUProfile(t *testing.T, need []string, f func(dur time.Duration)) {
 	t.FailNow()
 }
 
+func contains(slice []string, s string) bool {
+	for i := range slice {
+		if slice[i] == s {
+			return true
+		}
+	}
+	return false
+}
+
 func profileOk(t *testing.T, need []string, prof bytes.Buffer, duration time.Duration) (ok bool) {
 	ok = true
 
 	// Check that profile is well formed and contains need.
 	have := make([]uintptr, len(need))
 	var samples uintptr
-	parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
+	var buf bytes.Buffer
+	parseProfile(t, prof.Bytes(), func(count uintptr, stk []*profile.Location, labels map[string][]string) {
+		fmt.Fprintf(&buf, "%d:", count)
+		fprintStack(&buf, stk)
 		samples += count
-		for _, pc := range stk {
-			f := runtime.FuncForPC(pc)
-			if f == nil {
-				continue
-			}
-			for i, name := range need {
-				if strings.Contains(f.Name(), name) {
-					have[i] += count
+		for i, name := range need {
+			if semi := strings.Index(name, ";"); semi > -1 {
+				kv := strings.SplitN(name[semi+1:], "=", 2)
+				if len(kv) != 2 || !contains(labels[kv[0]], kv[1]) {
+					continue
 				}
+				name = name[:semi]
 			}
-			if strings.Contains(f.Name(), "stackBarrier") {
-				// The runtime should have unwound this.
-				t.Fatalf("profile includes stackBarrier")
+			for _, loc := range stk {
+				for _, line := range loc.Line {
+					if strings.Contains(line.Function.Name, name) {
+						have[i] += count
+					}
+				}
 			}
 		}
+		fmt.Fprintf(&buf, "\n")
 	})
-	t.Logf("total %d CPU profile samples collected", samples)
+	t.Logf("total %d CPU profile samples collected:\n%s", samples, buf.String())
 
 	if samples < 10 && runtime.GOOS == "windows" {
 		// On some windows machines we end up with
@@ -300,36 +334,43 @@ func TestGoroutineSwitch(t *testing.T) {
 
 		// Read profile to look for entries for runtime.gogo with an attempt at a traceback.
 		// The special entry
-		parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
+		parseProfile(t, prof.Bytes(), func(count uintptr, stk []*profile.Location, _ map[string][]string) {
 			// An entry with two frames with 'System' in its top frame
 			// exists to record a PC without a traceback. Those are okay.
 			if len(stk) == 2 {
-				f := runtime.FuncForPC(stk[1])
-				if f != nil && (f.Name() == "runtime._System" || f.Name() == "runtime._ExternalCode" || f.Name() == "runtime._GC") {
+				name := stk[1].Line[0].Function.Name
+				if name == "runtime._System" || name == "runtime._ExternalCode" || name == "runtime._GC" {
 					return
 				}
 			}
 
 			// Otherwise, should not see runtime.gogo.
 			// The place we'd see it would be the inner most frame.
-			f := runtime.FuncForPC(stk[0])
-			if f != nil && f.Name() == "runtime.gogo" {
+			name := stk[0].Line[0].Function.Name
+			if name == "runtime.gogo" {
 				var buf bytes.Buffer
-				for _, pc := range stk {
-					f := runtime.FuncForPC(pc)
-					if f == nil {
-						fmt.Fprintf(&buf, "%#x ?:0\n", pc)
-					} else {
-						file, line := f.FileLine(pc)
-						fmt.Fprintf(&buf, "%#x %s:%d\n", pc, file, line)
-					}
-				}
+				fprintStack(&buf, stk)
 				t.Fatalf("found profile entry for runtime.gogo:\n%s", buf.String())
 			}
 		})
 	}
 }
 
+func fprintStack(w io.Writer, stk []*profile.Location) {
+	for _, loc := range stk {
+		fmt.Fprintf(w, " %#x", loc.Address)
+		fmt.Fprintf(w, " (")
+		for i, line := range loc.Line {
+			if i > 0 {
+				fmt.Fprintf(w, " ")
+			}
+			fmt.Fprintf(w, "%s:%d", line.Function.Name, line.Line)
+		}
+		fmt.Fprintf(w, ")")
+	}
+	fmt.Fprintf(w, "\n")
+}
+
 // Test that profiling of division operations is okay, especially on ARM. See issue 6681.
 func TestMathBigDivide(t *testing.T) {
 	testCPUProfile(t, nil, func(duration time.Duration) {
@@ -350,111 +391,6 @@ func TestMathBigDivide(t *testing.T) {
 	})
 }
 
-func slurpString(r io.Reader) string {
-	slurp, _ := ioutil.ReadAll(r)
-	return string(slurp)
-}
-
-func getLinuxKernelConfig() string {
-	if f, err := os.Open("/proc/config"); err == nil {
-		defer f.Close()
-		return slurpString(f)
-	}
-	if f, err := os.Open("/proc/config.gz"); err == nil {
-		defer f.Close()
-		r, err := gzip.NewReader(f)
-		if err != nil {
-			return ""
-		}
-		return slurpString(r)
-	}
-	if f, err := os.Open("/boot/config"); err == nil {
-		defer f.Close()
-		return slurpString(f)
-	}
-	uname, _ := exec.Command("uname", "-r").Output()
-	if len(uname) > 0 {
-		if f, err := os.Open("/boot/config-" + strings.TrimSpace(string(uname))); err == nil {
-			defer f.Close()
-			return slurpString(f)
-		}
-	}
-	return ""
-}
-
-func haveLinuxHiresTimers() bool {
-	config := getLinuxKernelConfig()
-	return strings.Contains(config, "CONFIG_HIGH_RES_TIMERS=y")
-}
-
-func TestStackBarrierProfiling(t *testing.T) {
-	if (runtime.GOOS == "linux" && runtime.GOARCH == "arm") ||
-		runtime.GOOS == "openbsd" ||
-		runtime.GOOS == "solaris" ||
-		runtime.GOOS == "dragonfly" ||
-		runtime.GOOS == "freebsd" {
-		// This test currently triggers a large number of
-		// usleep(100)s. These kernels/arches have poor
-		// resolution timers, so this gives up a whole
-		// scheduling quantum. On Linux and the BSDs (and
-		// probably Solaris), profiling signals are only
-		// generated when a process completes a whole
-		// scheduling quantum, so this test often gets zero
-		// profiling signals and fails.
-		t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405)")
-		return
-	}
-
-	if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "mips") {
-		if !haveLinuxHiresTimers() {
-			t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405, golang.org/issue/17936)")
-		}
-	}
-
-	if !strings.Contains(os.Getenv("GODEBUG"), "gcstackbarrierall=1") {
-		// Re-execute this test with constant GC and stack
-		// barriers at every frame.
-		testenv.MustHaveExec(t)
-		if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
-			t.Skip("gcstackbarrierall doesn't work on ppc64")
-		}
-		args := []string{"-test.run=TestStackBarrierProfiling"}
-		if testing.Short() {
-			args = append(args, "-test.short")
-		}
-		cmd := exec.Command(os.Args[0], args...)
-		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)
-		}
-		return
-	}
-
-	testCPUProfile(t, nil, func(duration time.Duration) {
-		// In long mode, we're likely to get one or two
-		// samples in stackBarrier.
-		t := time.After(duration)
-		for {
-			deepStack(1000)
-			select {
-			case <-t:
-				return
-			default:
-			}
-		}
-	})
-}
-
-var x []byte
-
-func deepStack(depth int) int {
-	if depth == 0 {
-		return 0
-	}
-	x = make([]byte, 1024)
-	return deepStack(depth-1) + 1
-}
-
 // Operating systems that are expected to fail the tests. See issue 13841.
 var badOS = map[string]bool{
 	"darwin":    true,
@@ -472,46 +408,46 @@ func TestBlockProfile(t *testing.T) {
 	}
 	tests := [...]TestCase{
 		{"chan recv", blockChanRecv, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/runtime/chan.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	runtime\.chanrecv1\+0x[0-9a-f]+	.*/src/runtime/chan.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockChanRecv\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"chan send", blockChanSend, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	runtime\.chansend1\+0x[0-9,a-f]+	.*/src/runtime/chan.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	runtime\.chansend1\+0x[0-9a-f]+	.*/src/runtime/chan.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockChanSend\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"chan close", blockChanClose, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/runtime/chan.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	runtime\.chanrecv1\+0x[0-9a-f]+	.*/src/runtime/chan.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockChanClose\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"select recv async", blockSelectRecvAsync, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/runtime/select.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	runtime\.selectgo\+0x[0-9a-f]+	.*/src/runtime/select.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockSelectRecvAsync\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"select send sync", blockSelectSendSync, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/runtime/select.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	runtime\.selectgo\+0x[0-9a-f]+	.*/src/runtime/select.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockSelectSendSync\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"mutex", blockMutex, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+	.*/src/sync/mutex\.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockMutex\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	sync\.\(\*Mutex\)\.Lock\+0x[0-9a-f]+	.*/src/sync/mutex\.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockMutex\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"cond", blockCond, `
-[0-9]+ [0-9]+ @ 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]+
-#	0x[0-9,a-f]+	sync\.\(\*Cond\)\.Wait\+0x[0-9,a-f]+	.*/src/sync/cond\.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.blockCond\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
-#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+[0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+
+#	0x[0-9a-f]+	sync\.\(\*Cond\)\.Wait\+0x[0-9a-f]+	.*/src/sync/cond\.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.blockCond\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
+#	0x[0-9a-f]+	runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+	.*/src/runtime/pprof/pprof_test.go:[0-9]+
 `},
 	}
 
@@ -606,6 +542,10 @@ func blockMutex() {
 		time.Sleep(blockDelay)
 		mu.Unlock()
 	}()
+	// Note: Unlock releases mu before recording the mutex event,
+	// so it's theoretically possible for this to proceed and
+	// capture the profile before the event is recorded. As long
+	// as this is blocked before the unlock happens, it's okay.
 	mu.Lock()
 }
 
@@ -653,7 +593,7 @@ func TestMutexProfile(t *testing.T) {
 	if ok, err := regexp.MatchString(r2, lines[3]); err != nil || !ok {
 		t.Errorf("%q didn't match %q", lines[3], r2)
 	}
-	r3 := "^#.*runtime/pprof_test.blockMutex.*$"
+	r3 := "^#.*runtime/pprof.blockMutex.*$"
 	if ok, err := regexp.MatchString(r3, lines[5]); err != nil || !ok {
 		t.Errorf("%q didn't match %q", lines[5], r3)
 	}
@@ -665,22 +605,25 @@ 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)
-	}
+	// Setting GOMAXPROCS to 1 ensures we can force all goroutines to the
+	// desired blocking point.
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
 	c := make(chan int)
 	for i := 0; i < 100; i++ {
-		if i%10 == 0 {
+		switch {
+		case i%10 == 0:
 			go func1(c)
-			continue
-		}
-		if i%2 == 0 {
+		case i%2 == 0:
 			go func2(c)
-			continue
+		default:
+			go func3(c)
+		}
+		// Let goroutines block on channel
+		for j := 0; j < 5; j++ {
+			runtime.Gosched()
 		}
-		go func3(c)
 	}
-	time.Sleep(10 * time.Millisecond) // let goroutines block on channel
 
 	var w bytes.Buffer
 	goroutineProf := Lookup("goroutine")
@@ -743,3 +686,30 @@ func containsCounts(prof *profile.Profile, counts []int64) bool {
 	}
 	return true
 }
+
+// Issue 18836.
+func TestEmptyCallStack(t *testing.T) {
+	t.Parallel()
+	var buf bytes.Buffer
+	p := NewProfile("test18836")
+	p.Add("foo", 47674)
+	p.WriteTo(&buf, 1)
+	p.Remove("foo")
+	got := buf.String()
+	prefix := "test18836 profile: total 1\n"
+	if !strings.HasPrefix(got, prefix) {
+		t.Fatalf("got:\n\t%q\nwant prefix:\n\t%q\n", got, prefix)
+	}
+	lostevent := "lostProfileEvent"
+	if !strings.Contains(got, lostevent) {
+		t.Fatalf("got:\n\t%q\ndoes not contain:\n\t%q\n", got, lostevent)
+	}
+}
+
+func TestCPUProfileLabel(t *testing.T) {
+	testCPUProfile(t, []string{"runtime/pprof.cpuHogger;key=value"}, func(dur time.Duration) {
+		Do(context.Background(), Labels("key", "value"), func(context.Context) {
+			cpuHogger(cpuHog1, dur)
+		})
+	})
+}
diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go
new file mode 100644
index 0000000..9e16e58
--- /dev/null
+++ b/src/runtime/pprof/proto.go
@@ -0,0 +1,510 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"bytes"
+	"compress/gzip"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"runtime"
+	"sort"
+	"strconv"
+	"time"
+	"unsafe"
+)
+
+// lostProfileEvent is the function to which lost profiling
+// events are attributed.
+// (The name shows up in the pprof graphs.)
+func lostProfileEvent() { lostProfileEvent() }
+
+// funcPC returns the PC for the func value f.
+func funcPC(f interface{}) uintptr {
+	return *(*[2]*uintptr)(unsafe.Pointer(&f))[1]
+}
+
+// A profileBuilder writes a profile incrementally from a
+// stream of profile samples delivered by the runtime.
+type profileBuilder struct {
+	start      time.Time
+	end        time.Time
+	havePeriod bool
+	period     int64
+	m          profMap
+
+	// encoding state
+	w         io.Writer
+	zw        *gzip.Writer
+	pb        protobuf
+	strings   []string
+	stringMap map[string]int
+	locs      map[uintptr]int
+	funcs     map[string]int // Package path-qualified function name to Function.ID
+	mem       []memMap
+}
+
+type memMap struct {
+	start uintptr
+	end   uintptr
+}
+
+const (
+	// message Profile
+	tagProfile_SampleType    = 1  // repeated ValueType
+	tagProfile_Sample        = 2  // repeated Sample
+	tagProfile_Mapping       = 3  // repeated Mapping
+	tagProfile_Location      = 4  // repeated Location
+	tagProfile_Function      = 5  // repeated Function
+	tagProfile_StringTable   = 6  // repeated string
+	tagProfile_DropFrames    = 7  // int64 (string table index)
+	tagProfile_KeepFrames    = 8  // int64 (string table index)
+	tagProfile_TimeNanos     = 9  // int64
+	tagProfile_DurationNanos = 10 // int64
+	tagProfile_PeriodType    = 11 // ValueType (really optional string???)
+	tagProfile_Period        = 12 // int64
+
+	// message ValueType
+	tagValueType_Type = 1 // int64 (string table index)
+	tagValueType_Unit = 2 // int64 (string table index)
+
+	// message Sample
+	tagSample_Location = 1 // repeated uint64
+	tagSample_Value    = 2 // repeated int64
+	tagSample_Label    = 3 // repeated Label
+
+	// message Label
+	tagLabel_Key = 1 // int64 (string table index)
+	tagLabel_Str = 2 // int64 (string table index)
+	tagLabel_Num = 3 // int64
+
+	// message Mapping
+	tagMapping_ID              = 1  // uint64
+	tagMapping_Start           = 2  // uint64
+	tagMapping_Limit           = 3  // uint64
+	tagMapping_Offset          = 4  // uint64
+	tagMapping_Filename        = 5  // int64 (string table index)
+	tagMapping_BuildID         = 6  // int64 (string table index)
+	tagMapping_HasFunctions    = 7  // bool
+	tagMapping_HasFilenames    = 8  // bool
+	tagMapping_HasLineNumbers  = 9  // bool
+	tagMapping_HasInlineFrames = 10 // bool
+
+	// message Location
+	tagLocation_ID        = 1 // uint64
+	tagLocation_MappingID = 2 // uint64
+	tagLocation_Address   = 3 // uint64
+	tagLocation_Line      = 4 // repeated Line
+
+	// message Line
+	tagLine_FunctionID = 1 // uint64
+	tagLine_Line       = 2 // int64
+
+	// message Function
+	tagFunction_ID         = 1 // uint64
+	tagFunction_Name       = 2 // int64 (string table index)
+	tagFunction_SystemName = 3 // int64 (string table index)
+	tagFunction_Filename   = 4 // int64 (string table index)
+	tagFunction_StartLine  = 5 // int64
+)
+
+// stringIndex adds s to the string table if not already present
+// and returns the index of s in the string table.
+func (b *profileBuilder) stringIndex(s string) int64 {
+	id, ok := b.stringMap[s]
+	if !ok {
+		id = len(b.strings)
+		b.strings = append(b.strings, s)
+		b.stringMap[s] = id
+	}
+	return int64(id)
+}
+
+func (b *profileBuilder) flush() {
+	const dataFlush = 4096
+	if b.pb.nest == 0 && len(b.pb.data) > dataFlush {
+		b.zw.Write(b.pb.data)
+		b.pb.data = b.pb.data[:0]
+	}
+}
+
+// pbValueType encodes a ValueType message to b.pb.
+func (b *profileBuilder) pbValueType(tag int, typ, unit string) {
+	start := b.pb.startMessage()
+	b.pb.int64(tagValueType_Type, b.stringIndex(typ))
+	b.pb.int64(tagValueType_Unit, b.stringIndex(unit))
+	b.pb.endMessage(tag, start)
+}
+
+// pbSample encodes a Sample message to b.pb.
+func (b *profileBuilder) pbSample(values []int64, locs []uint64, labels func()) {
+	start := b.pb.startMessage()
+	b.pb.int64s(tagSample_Value, values)
+	b.pb.uint64s(tagSample_Location, locs)
+	if labels != nil {
+		labels()
+	}
+	b.pb.endMessage(tagProfile_Sample, start)
+	b.flush()
+}
+
+// pbLabel encodes a Label message to b.pb.
+func (b *profileBuilder) pbLabel(tag int, key, str string, num int64) {
+	start := b.pb.startMessage()
+	b.pb.int64Opt(tagLabel_Key, b.stringIndex(key))
+	b.pb.int64Opt(tagLabel_Str, b.stringIndex(str))
+	b.pb.int64Opt(tagLabel_Num, num)
+	b.pb.endMessage(tag, start)
+}
+
+// pbLine encodes a Line message to b.pb.
+func (b *profileBuilder) pbLine(tag int, funcID uint64, line int64) {
+	start := b.pb.startMessage()
+	b.pb.uint64Opt(tagLine_FunctionID, funcID)
+	b.pb.int64Opt(tagLine_Line, line)
+	b.pb.endMessage(tag, start)
+}
+
+// pbMapping encodes a Mapping message to b.pb.
+func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file, buildID string) {
+	start := b.pb.startMessage()
+	b.pb.uint64Opt(tagMapping_ID, id)
+	b.pb.uint64Opt(tagMapping_Start, base)
+	b.pb.uint64Opt(tagMapping_Limit, limit)
+	b.pb.uint64Opt(tagMapping_Offset, offset)
+	b.pb.int64Opt(tagMapping_Filename, b.stringIndex(file))
+	b.pb.int64Opt(tagMapping_BuildID, b.stringIndex(buildID))
+	// TODO: Set any of HasInlineFrames, HasFunctions, HasFilenames, HasLineNumbers?
+	// It seems like they should all be true, but they've never been set.
+	b.pb.endMessage(tag, start)
+}
+
+// locForPC returns the location ID for addr.
+// addr must be a return PC. This returns the location of the call.
+// It may emit to b.pb, so there must be no message encoding in progress.
+func (b *profileBuilder) locForPC(addr uintptr) uint64 {
+	id := uint64(b.locs[addr])
+	if id != 0 {
+		return id
+	}
+
+	// Expand this one address using CallersFrames so we can cache
+	// each expansion. In general, CallersFrames takes a whole
+	// stack, but in this case we know there will be no skips in
+	// the stack and we have return PCs anyway.
+	frames := runtime.CallersFrames([]uintptr{addr})
+	frame, more := frames.Next()
+	if frame.Function == "runtime.goexit" {
+		// Short-circuit if we see runtime.goexit so the loop
+		// below doesn't allocate a useless empty location.
+		return 0
+	}
+
+	if frame.PC == 0 {
+		// If we failed to resolve the frame, at least make up
+		// a reasonable call PC. This mostly happens in tests.
+		frame.PC = addr - 1
+	}
+
+	// We can't write out functions while in the middle of the
+	// Location message, so record new functions we encounter and
+	// write them out after the Location.
+	type newFunc struct {
+		id         uint64
+		name, file string
+	}
+	newFuncs := make([]newFunc, 0, 8)
+
+	id = uint64(len(b.locs)) + 1
+	b.locs[addr] = int(id)
+	start := b.pb.startMessage()
+	b.pb.uint64Opt(tagLocation_ID, id)
+	b.pb.uint64Opt(tagLocation_Address, uint64(frame.PC))
+	for frame.Function != "runtime.goexit" {
+		// Write out each line in frame expansion.
+		funcID := uint64(b.funcs[frame.Function])
+		if funcID == 0 {
+			funcID = uint64(len(b.funcs)) + 1
+			b.funcs[frame.Function] = int(funcID)
+			newFuncs = append(newFuncs, newFunc{funcID, frame.Function, frame.File})
+		}
+		b.pbLine(tagLocation_Line, funcID, int64(frame.Line))
+		if !more {
+			break
+		}
+		frame, more = frames.Next()
+	}
+	if len(b.mem) > 0 {
+		i := sort.Search(len(b.mem), func(i int) bool {
+			return b.mem[i].end > addr
+		})
+		if i < len(b.mem) && b.mem[i].start <= addr && addr < b.mem[i].end {
+			b.pb.uint64Opt(tagLocation_MappingID, uint64(i+1))
+		}
+	}
+	b.pb.endMessage(tagProfile_Location, start)
+
+	// Write out functions we found during frame expansion.
+	for _, fn := range newFuncs {
+		start := b.pb.startMessage()
+		b.pb.uint64Opt(tagFunction_ID, fn.id)
+		b.pb.int64Opt(tagFunction_Name, b.stringIndex(fn.name))
+		b.pb.int64Opt(tagFunction_SystemName, b.stringIndex(fn.name))
+		b.pb.int64Opt(tagFunction_Filename, b.stringIndex(fn.file))
+		b.pb.endMessage(tagProfile_Function, start)
+	}
+
+	b.flush()
+	return id
+}
+
+// newProfileBuilder returns a new profileBuilder.
+// CPU profiling data obtained from the runtime can be added
+// by calling b.addCPUData, and then the eventual profile
+// can be obtained by calling b.finish.
+func newProfileBuilder(w io.Writer) *profileBuilder {
+	zw, _ := gzip.NewWriterLevel(w, gzip.BestSpeed)
+	b := &profileBuilder{
+		w:         w,
+		zw:        zw,
+		start:     time.Now(),
+		strings:   []string{""},
+		stringMap: map[string]int{"": 0},
+		locs:      map[uintptr]int{},
+		funcs:     map[string]int{},
+	}
+	b.readMapping()
+	return b
+}
+
+// addCPUData adds the CPU profiling data to the profile.
+// The data must be a whole number of records,
+// as delivered by the runtime.
+func (b *profileBuilder) addCPUData(data []uint64, tags []unsafe.Pointer) error {
+	if !b.havePeriod {
+		// first record is period
+		if len(data) < 3 {
+			return fmt.Errorf("truncated profile")
+		}
+		if data[0] != 3 || data[2] == 0 {
+			return fmt.Errorf("malformed profile")
+		}
+		// data[2] is sampling rate in Hz. Convert to sampling
+		// period in nanoseconds.
+		b.period = 1e9 / int64(data[2])
+		b.havePeriod = true
+		data = data[3:]
+	}
+
+	// Parse CPU samples from the profile.
+	// Each sample is 3+n uint64s:
+	//	data[0] = 3+n
+	//	data[1] = time stamp (ignored)
+	//	data[2] = count
+	//	data[3:3+n] = stack
+	// If the count is 0 and the stack has length 1,
+	// that's an overflow record inserted by the runtime
+	// to indicate that stack[0] samples were lost.
+	// Otherwise the count is usually 1,
+	// but in a few special cases like lost non-Go samples
+	// there can be larger counts.
+	// Because many samples with the same stack arrive,
+	// we want to deduplicate immediately, which we do
+	// using the b.m profMap.
+	for len(data) > 0 {
+		if len(data) < 3 || data[0] > uint64(len(data)) {
+			return fmt.Errorf("truncated profile")
+		}
+		if data[0] < 3 || tags != nil && len(tags) < 1 {
+			return fmt.Errorf("malformed profile")
+		}
+		count := data[2]
+		stk := data[3:data[0]]
+		data = data[data[0]:]
+		var tag unsafe.Pointer
+		if tags != nil {
+			tag = tags[0]
+			tags = tags[1:]
+		}
+
+		if count == 0 && len(stk) == 1 {
+			// overflow record
+			count = uint64(stk[0])
+			stk = []uint64{
+				uint64(funcPC(lostProfileEvent)),
+			}
+		}
+		b.m.lookup(stk, tag).count += int64(count)
+	}
+	return nil
+}
+
+// build completes and returns the constructed profile.
+func (b *profileBuilder) build() error {
+	b.end = time.Now()
+
+	b.pb.int64Opt(tagProfile_TimeNanos, b.start.UnixNano())
+	if b.havePeriod { // must be CPU profile
+		b.pbValueType(tagProfile_SampleType, "samples", "count")
+		b.pbValueType(tagProfile_SampleType, "cpu", "nanoseconds")
+		b.pb.int64Opt(tagProfile_DurationNanos, b.end.Sub(b.start).Nanoseconds())
+		b.pbValueType(tagProfile_PeriodType, "cpu", "nanoseconds")
+		b.pb.int64Opt(tagProfile_Period, b.period)
+	}
+
+	values := []int64{0, 0}
+	var locs []uint64
+	for e := b.m.all; e != nil; e = e.nextAll {
+		values[0] = e.count
+		values[1] = e.count * b.period
+
+		var labels func()
+		if e.tag != nil {
+			labels = func() {
+				for k, v := range *(*labelMap)(e.tag) {
+					b.pbLabel(tagSample_Label, k, v, 0)
+				}
+			}
+		}
+
+		locs = locs[:0]
+		for i, addr := range e.stk {
+			// Addresses from stack traces point to the
+			// next instruction after each call, except
+			// for the leaf, which points to where the
+			// signal occurred. locForPC expects return
+			// PCs, so increment the leaf address to look
+			// like a return PC.
+			if i == 0 {
+				addr++
+			}
+			l := b.locForPC(addr)
+			if l == 0 { // runtime.goexit
+				continue
+			}
+			locs = append(locs, l)
+		}
+		b.pbSample(values, locs, labels)
+	}
+
+	// TODO: Anything for tagProfile_DropFrames?
+	// TODO: Anything for tagProfile_KeepFrames?
+
+	b.pb.strings(tagProfile_StringTable, b.strings)
+	b.zw.Write(b.pb.data)
+	b.zw.Close()
+	return nil
+}
+
+// readMapping reads /proc/self/maps and writes mappings to b.pb.
+// It saves the address ranges of the mappings in b.mem for use
+// when emitting locations.
+func (b *profileBuilder) readMapping() {
+	data, _ := ioutil.ReadFile("/proc/self/maps")
+	parseProcSelfMaps(data, b.addMapping)
+}
+
+func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, buildID string)) {
+	// $ cat /proc/self/maps
+	// 00400000-0040b000 r-xp 00000000 fc:01 787766                             /bin/cat
+	// 0060a000-0060b000 r--p 0000a000 fc:01 787766                             /bin/cat
+	// 0060b000-0060c000 rw-p 0000b000 fc:01 787766                             /bin/cat
+	// 014ab000-014cc000 rw-p 00000000 00:00 0                                  [heap]
+	// 7f7d76af8000-7f7d7797c000 r--p 00000000 fc:01 1318064                    /usr/lib/locale/locale-archive
+	// 7f7d7797c000-7f7d77b36000 r-xp 00000000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+	// 7f7d77b36000-7f7d77d36000 ---p 001ba000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+	// 7f7d77d36000-7f7d77d3a000 r--p 001ba000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+	// 7f7d77d3a000-7f7d77d3c000 rw-p 001be000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+	// 7f7d77d3c000-7f7d77d41000 rw-p 00000000 00:00 0
+	// 7f7d77d41000-7f7d77d64000 r-xp 00000000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+	// 7f7d77f3f000-7f7d77f42000 rw-p 00000000 00:00 0
+	// 7f7d77f61000-7f7d77f63000 rw-p 00000000 00:00 0
+	// 7f7d77f63000-7f7d77f64000 r--p 00022000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+	// 7f7d77f64000-7f7d77f65000 rw-p 00023000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+	// 7f7d77f65000-7f7d77f66000 rw-p 00000000 00:00 0
+	// 7ffc342a2000-7ffc342c3000 rw-p 00000000 00:00 0                          [stack]
+	// 7ffc34343000-7ffc34345000 r-xp 00000000 00:00 0                          [vdso]
+	// ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+
+	var line []byte
+	// next removes and returns the next field in the line.
+	// It also removes from line any spaces following the field.
+	next := func() []byte {
+		j := bytes.IndexByte(line, ' ')
+		if j < 0 {
+			f := line
+			line = nil
+			return f
+		}
+		f := line[:j]
+		line = line[j+1:]
+		for len(line) > 0 && line[0] == ' ' {
+			line = line[1:]
+		}
+		return f
+	}
+
+	for len(data) > 0 {
+		i := bytes.IndexByte(data, '\n')
+		if i < 0 {
+			line, data = data, nil
+		} else {
+			line, data = data[:i], data[i+1:]
+		}
+		addr := next()
+		i = bytes.IndexByte(addr, '-')
+		if i < 0 {
+			continue
+		}
+		lo, err := strconv.ParseUint(string(addr[:i]), 16, 64)
+		if err != nil {
+			continue
+		}
+		hi, err := strconv.ParseUint(string(addr[i+1:]), 16, 64)
+		if err != nil {
+			continue
+		}
+		perm := next()
+		if len(perm) < 4 || perm[2] != 'x' {
+			// Only interested in executable mappings.
+			continue
+		}
+		offset, err := strconv.ParseUint(string(next()), 16, 64)
+		if err != nil {
+			continue
+		}
+		next()          // dev
+		inode := next() // inode
+		if line == nil {
+			continue
+		}
+		file := string(line)
+		if len(inode) == 1 && inode[0] == '0' && file == "" {
+			// Huge-page text mappings list the initial fragment of
+			// mapped but unpopulated memory as being inode 0.
+			// Don't report that part.
+			// But [vdso] and [vsyscall] are inode 0, so let non-empty file names through.
+			continue
+		}
+
+		// TODO: pprof's remapMappingIDs makes two adjustments:
+		// 1. If there is an /anon_hugepage mapping first and it is
+		// consecutive to a next mapping, drop the /anon_hugepage.
+		// 2. If start-offset = 0x400000, change start to 0x400000 and offset to 0.
+		// There's no indication why either of these is needed.
+		// Let's try not doing these and see what breaks.
+		// If we do need them, they would go here, before we
+		// enter the mappings into b.mem in the first place.
+
+		buildID, _ := elfBuildID(file)
+		addMapping(lo, hi, offset, file, buildID)
+	}
+}
+
+func (b *profileBuilder) addMapping(lo, hi, offset uint64, file, buildID string) {
+	b.mem = append(b.mem, memMap{uintptr(lo), uintptr(hi)})
+	b.pbMapping(tagProfile_Mapping, uint64(len(b.mem)), lo, hi, offset, file, buildID)
+}
diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go
new file mode 100644
index 0000000..dab929c
--- /dev/null
+++ b/src/runtime/pprof/proto_test.go
@@ -0,0 +1,222 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"reflect"
+	"runtime"
+	"runtime/pprof/internal/profile"
+	"strings"
+	"testing"
+)
+
+// translateCPUProfile parses binary CPU profiling stack trace data
+// generated by runtime.CPUProfile() into a profile struct.
+// This is only used for testing. Real conversions stream the
+// data into the profileBuilder as it becomes available.
+func translateCPUProfile(data []uint64) (*profile.Profile, error) {
+	var buf bytes.Buffer
+	b := newProfileBuilder(&buf)
+	if err := b.addCPUData(data, nil); err != nil {
+		return nil, err
+	}
+	b.build()
+	return profile.Parse(&buf)
+}
+
+// fmtJSON returns a pretty-printed JSON form for x.
+// It works reasonbly well for printing protocol-buffer
+// data structures like profile.Profile.
+func fmtJSON(x interface{}) string {
+	js, _ := json.MarshalIndent(x, "", "\t")
+	return string(js)
+}
+
+func TestConvertCPUProfileEmpty(t *testing.T) {
+	// A test server with mock cpu profile data.
+	var buf bytes.Buffer
+
+	b := []uint64{3, 0, 500} // empty profile at 500 Hz (2ms sample period)
+	p, err := translateCPUProfile(b)
+	if err != nil {
+		t.Fatalf("translateCPUProfile: %v", err)
+	}
+	if err := p.Write(&buf); err != nil {
+		t.Fatalf("writing profile: %v", err)
+	}
+
+	p, err = profile.Parse(&buf)
+	if err != nil {
+		t.Fatalf("profile.Parse: %v", err)
+	}
+
+	// Expected PeriodType and SampleType.
+	periodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
+	sampleType := []*profile.ValueType{
+		{Type: "samples", Unit: "count"},
+		{Type: "cpu", Unit: "nanoseconds"},
+	}
+
+	checkProfile(t, p, 2000*1000, periodType, sampleType, nil)
+}
+
+func f1() { f1() }
+func f2() { f2() }
+
+// testPCs returns two PCs and two corresponding memory mappings
+// to use in test profiles.
+func testPCs(t *testing.T) (addr1, addr2 uint64, map1, map2 *profile.Mapping) {
+	switch runtime.GOOS {
+	case "linux", "android", "netbsd":
+		// Figure out two addresses from /proc/self/maps.
+		mmap, err := ioutil.ReadFile("/proc/self/maps")
+		if err != nil {
+			t.Fatal(err)
+		}
+		mprof := &profile.Profile{}
+		if err = mprof.ParseMemoryMap(bytes.NewReader(mmap)); err != nil {
+			t.Fatalf("parsing /proc/self/maps: %v", err)
+		}
+		if len(mprof.Mapping) < 2 {
+			// It is possible for a binary to only have 1 executable
+			// region of memory.
+			t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping))
+		}
+		addr1 = mprof.Mapping[0].Start
+		map1 = mprof.Mapping[0]
+		map1.BuildID, _ = elfBuildID(map1.File)
+		addr2 = mprof.Mapping[1].Start
+		map2 = mprof.Mapping[1]
+		map2.BuildID, _ = elfBuildID(map2.File)
+	default:
+		addr1 = uint64(funcPC(f1))
+		addr2 = uint64(funcPC(f2))
+	}
+	return
+}
+
+func TestConvertCPUProfile(t *testing.T) {
+	addr1, addr2, map1, map2 := testPCs(t)
+
+	b := []uint64{
+		3, 0, 500, // hz = 500
+		5, 0, 10, uint64(addr1), uint64(addr1 + 2), // 10 samples in addr1
+		5, 0, 40, uint64(addr2), uint64(addr2 + 2), // 40 samples in addr2
+		5, 0, 10, uint64(addr1), uint64(addr1 + 2), // 10 samples in addr1
+	}
+	p, err := translateCPUProfile(b)
+	if err != nil {
+		t.Fatalf("translating profile: %v", err)
+	}
+	period := int64(2000 * 1000)
+	periodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
+	sampleType := []*profile.ValueType{
+		{Type: "samples", Unit: "count"},
+		{Type: "cpu", Unit: "nanoseconds"},
+	}
+	samples := []*profile.Sample{
+		{Value: []int64{20, 20 * 2000 * 1000}, Location: []*profile.Location{
+			{ID: 1, Mapping: map1, Address: addr1},
+			{ID: 2, Mapping: map1, Address: addr1 + 1},
+		}},
+		{Value: []int64{40, 40 * 2000 * 1000}, Location: []*profile.Location{
+			{ID: 3, Mapping: map2, Address: addr2},
+			{ID: 4, Mapping: map2, Address: addr2 + 1},
+		}},
+	}
+	checkProfile(t, p, period, periodType, sampleType, samples)
+}
+
+func checkProfile(t *testing.T, p *profile.Profile, period int64, periodType *profile.ValueType, sampleType []*profile.ValueType, samples []*profile.Sample) {
+	if p.Period != period {
+		t.Fatalf("p.Period = %d, want %d", p.Period, period)
+	}
+	if !reflect.DeepEqual(p.PeriodType, periodType) {
+		t.Fatalf("p.PeriodType = %v\nwant = %v", fmtJSON(p.PeriodType), fmtJSON(periodType))
+	}
+	if !reflect.DeepEqual(p.SampleType, sampleType) {
+		t.Fatalf("p.SampleType = %v\nwant = %v", fmtJSON(p.SampleType), fmtJSON(sampleType))
+	}
+	// Clear line info since it is not in the expected samples.
+	// If we used f1 and f2 above, then the samples will have line info.
+	for _, s := range p.Sample {
+		for _, l := range s.Location {
+			l.Line = nil
+		}
+	}
+	if fmtJSON(p.Sample) != fmtJSON(samples) { // ignore unexported fields
+		if len(p.Sample) == len(samples) {
+			for i := range p.Sample {
+				if !reflect.DeepEqual(p.Sample[i], samples[i]) {
+					t.Errorf("sample %d = %v\nwant = %v\n", i, fmtJSON(p.Sample[i]), fmtJSON(samples[i]))
+				}
+			}
+			if t.Failed() {
+				t.FailNow()
+			}
+		}
+		t.Fatalf("p.Sample = %v\nwant = %v", fmtJSON(p.Sample), fmtJSON(samples))
+	}
+}
+
+var profSelfMapsTests = `
+00400000-0040b000 r-xp 00000000 fc:01 787766                             /bin/cat
+0060a000-0060b000 r--p 0000a000 fc:01 787766                             /bin/cat
+0060b000-0060c000 rw-p 0000b000 fc:01 787766                             /bin/cat
+014ab000-014cc000 rw-p 00000000 00:00 0                                  [heap]
+7f7d76af8000-7f7d7797c000 r--p 00000000 fc:01 1318064                    /usr/lib/locale/locale-archive
+7f7d7797c000-7f7d77b36000 r-xp 00000000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+7f7d77b36000-7f7d77d36000 ---p 001ba000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+7f7d77d36000-7f7d77d3a000 r--p 001ba000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+7f7d77d3a000-7f7d77d3c000 rw-p 001be000 fc:01 1180226                    /lib/x86_64-linux-gnu/libc-2.19.so
+7f7d77d3c000-7f7d77d41000 rw-p 00000000 00:00 0
+7f7d77d41000-7f7d77d64000 r-xp 00000000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+7f7d77f3f000-7f7d77f42000 rw-p 00000000 00:00 0
+7f7d77f61000-7f7d77f63000 rw-p 00000000 00:00 0
+7f7d77f63000-7f7d77f64000 r--p 00022000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+7f7d77f64000-7f7d77f65000 rw-p 00023000 fc:01 1180217                    /lib/x86_64-linux-gnu/ld-2.19.so
+7f7d77f65000-7f7d77f66000 rw-p 00000000 00:00 0
+7ffc342a2000-7ffc342c3000 rw-p 00000000 00:00 0                          [stack]
+7ffc34343000-7ffc34345000 r-xp 00000000 00:00 0                          [vdso]
+ffffffffff600000-ffffffffff601000 r-xp 00000090 00:00 0                  [vsyscall]
+->
+00400000 0040b000 00000000 /bin/cat
+7f7d7797c000 7f7d77b36000 00000000 /lib/x86_64-linux-gnu/libc-2.19.so
+7f7d77d41000 7f7d77d64000 00000000 /lib/x86_64-linux-gnu/ld-2.19.so
+7ffc34343000 7ffc34345000 00000000 [vdso]
+ffffffffff600000 ffffffffff601000 00000090 [vsyscall]
+
+00400000-07000000 r-xp 00000000 00:00 0 
+07000000-07093000 r-xp 06c00000 00:2e 536754                             /path/to/gobench_server_main
+07093000-0722d000 rw-p 06c92000 00:2e 536754                             /path/to/gobench_server_main
+0722d000-07b21000 rw-p 00000000 00:00 0 
+c000000000-c000036000 rw-p 00000000 00:00 0 
+->
+07000000 07093000 06c00000 /path/to/gobench_server_main
+`
+
+func TestProcSelfMaps(t *testing.T) {
+	for tx, tt := range strings.Split(profSelfMapsTests, "\n\n") {
+		i := strings.Index(tt, "->\n")
+		if i < 0 {
+			t.Fatal("malformed test case")
+		}
+		in, out := tt[:i], tt[i+len("->\n"):]
+		if len(out) > 0 && out[len(out)-1] != '\n' {
+			out += "\n"
+		}
+		var buf bytes.Buffer
+		parseProcSelfMaps([]byte(in), func(lo, hi, offset uint64, file, buildID string) {
+			fmt.Fprintf(&buf, "%08x %08x %08x %s\n", lo, hi, offset, file)
+		})
+		if buf.String() != out {
+			t.Errorf("#%d: have:\n%s\nwant:\n%s\n%q\n%q", tx, buf.String(), out, buf.String(), out)
+		}
+	}
+}
diff --git a/src/runtime/pprof/protobuf.go b/src/runtime/pprof/protobuf.go
new file mode 100644
index 0000000..7b99095
--- /dev/null
+++ b/src/runtime/pprof/protobuf.go
@@ -0,0 +1,141 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pprof
+
+// A protobuf is a simple protocol buffer encoder.
+type protobuf struct {
+	data []byte
+	tmp  [16]byte
+	nest int
+}
+
+func (b *protobuf) varint(x uint64) {
+	for x >= 128 {
+		b.data = append(b.data, byte(x)|0x80)
+		x >>= 7
+	}
+	b.data = append(b.data, byte(x))
+}
+
+func (b *protobuf) length(tag int, len int) {
+	b.varint(uint64(tag)<<3 | 2)
+	b.varint(uint64(len))
+}
+
+func (b *protobuf) uint64(tag int, x uint64) {
+	// append varint to b.data
+	b.varint(uint64(tag)<<3 | 0)
+	b.varint(x)
+}
+
+func (b *protobuf) uint64s(tag int, x []uint64) {
+	if len(x) > 2 {
+		// Use packed encoding
+		n1 := len(b.data)
+		for _, u := range x {
+			b.varint(u)
+		}
+		n2 := len(b.data)
+		b.length(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 {
+		b.uint64(tag, u)
+	}
+}
+
+func (b *protobuf) uint64Opt(tag int, x uint64) {
+	if x == 0 {
+		return
+	}
+	b.uint64(tag, x)
+}
+
+func (b *protobuf) int64(tag int, x int64) {
+	u := uint64(x)
+	b.uint64(tag, u)
+}
+
+func (b *protobuf) int64Opt(tag int, x int64) {
+	if x == 0 {
+		return
+	}
+	b.int64(tag, x)
+}
+
+func (b *protobuf) int64s(tag int, x []int64) {
+	if len(x) > 2 {
+		// Use packed encoding
+		n1 := len(b.data)
+		for _, u := range x {
+			b.varint(uint64(u))
+		}
+		n2 := len(b.data)
+		b.length(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 {
+		b.int64(tag, u)
+	}
+}
+
+func (b *protobuf) string(tag int, x string) {
+	b.length(tag, len(x))
+	b.data = append(b.data, x...)
+}
+
+func (b *protobuf) strings(tag int, x []string) {
+	for _, s := range x {
+		b.string(tag, s)
+	}
+}
+
+func (b *protobuf) stringOpt(tag int, x string) {
+	if x == "" {
+		return
+	}
+	b.string(tag, x)
+}
+
+func (b *protobuf) bool(tag int, x bool) {
+	if x {
+		b.uint64(tag, 1)
+	} else {
+		b.uint64(tag, 0)
+	}
+}
+
+func (b *protobuf) boolOpt(tag int, x bool) {
+	if x == false {
+		return
+	}
+	b.bool(tag, x)
+}
+
+type msgOffset int
+
+func (b *protobuf) startMessage() msgOffset {
+	b.nest++
+	return msgOffset(len(b.data))
+}
+
+func (b *protobuf) endMessage(tag int, start msgOffset) {
+	n1 := int(start)
+	n2 := len(b.data)
+	b.length(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])
+	b.nest--
+}
diff --git a/src/runtime/pprof/protomem.go b/src/runtime/pprof/protomem.go
new file mode 100644
index 0000000..2756cfd
--- /dev/null
+++ b/src/runtime/pprof/protomem.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.
+
+package pprof
+
+import (
+	"io"
+	"math"
+	"runtime"
+	"strings"
+)
+
+// writeHeapProto writes the current heap profile in protobuf format to w.
+func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64) error {
+	b := newProfileBuilder(w)
+	b.pbValueType(tagProfile_PeriodType, "space", "bytes")
+	b.pb.int64Opt(tagProfile_Period, rate)
+	b.pbValueType(tagProfile_SampleType, "alloc_objects", "count")
+	b.pbValueType(tagProfile_SampleType, "alloc_space", "bytes")
+	b.pbValueType(tagProfile_SampleType, "inuse_objects", "count")
+	b.pbValueType(tagProfile_SampleType, "inuse_space", "bytes")
+
+	values := []int64{0, 0, 0, 0}
+	var locs []uint64
+	for _, r := range p {
+		locs = locs[:0]
+		hideRuntime := true
+		for tries := 0; tries < 2; tries++ {
+			for _, addr := range r.Stack() {
+				// For heap profiles, all stack
+				// addresses are return PCs, which is
+				// what locForPC expects.
+				if hideRuntime {
+					if f := runtime.FuncForPC(addr); f != nil && strings.HasPrefix(f.Name(), "runtime.") {
+						continue
+					}
+					// Found non-runtime. Show any runtime uses above it.
+					hideRuntime = false
+				}
+				l := b.locForPC(addr)
+				if l == 0 { // runtime.goexit
+					continue
+				}
+				locs = append(locs, l)
+			}
+			if len(locs) > 0 {
+				break
+			}
+			hideRuntime = false // try again, and show all frames
+		}
+
+		values[0], values[1] = scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
+		values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
+		var blockSize int64
+		if values[0] > 0 {
+			blockSize = values[1] / values[0]
+		}
+		b.pbSample(values, locs, func() {
+			if blockSize != 0 {
+				b.pbLabel(tagSample_Label, "bytes", "", blockSize)
+			}
+		})
+	}
+	b.build()
+	return nil
+}
+
+// scaleHeapSample adjusts the data from a heap Sample to
+// account for its probability of appearing in the collected
+// data. heap 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. heap 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)
+}
diff --git a/src/runtime/pprof/protomem_test.go b/src/runtime/pprof/protomem_test.go
new file mode 100644
index 0000000..1e30ed9
--- /dev/null
+++ b/src/runtime/pprof/protomem_test.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.
+
+package pprof
+
+import (
+	"bytes"
+	"runtime"
+	"runtime/pprof/internal/profile"
+	"testing"
+)
+
+func TestConvertMemProfile(t *testing.T) {
+	addr1, addr2, map1, map2 := testPCs(t)
+
+	var buf bytes.Buffer
+	// MemProfileRecord stacks are return PCs, so add one to the
+	// addresses recorded in the "profile". The proto profile
+	// locations are call PCs, so conversion will subtract one
+	// from these and get back to addr1 and addr2.
+	a1, a2 := uintptr(addr1)+1, uintptr(addr2)+1
+	rate := int64(512 * 1024)
+	rec := []runtime.MemProfileRecord{
+		{AllocBytes: 4096, FreeBytes: 1024, AllocObjects: 4, FreeObjects: 1, Stack0: [32]uintptr{a1, a2}},
+		{AllocBytes: 512 * 1024, FreeBytes: 0, AllocObjects: 1, FreeObjects: 0, Stack0: [32]uintptr{a2 + 1, a2 + 2}},
+		{AllocBytes: 512 * 1024, FreeBytes: 512 * 1024, AllocObjects: 1, FreeObjects: 1, Stack0: [32]uintptr{a1 + 1, a1 + 2, a2 + 3}},
+	}
+
+	if err := writeHeapProto(&buf, rec, rate); err != nil {
+		t.Fatalf("writing profile: %v", err)
+	}
+
+	p, err := profile.Parse(&buf)
+	if err != nil {
+		t.Fatalf("profile.Parse: %v", err)
+	}
+
+	periodType := &profile.ValueType{Type: "space", Unit: "bytes"}
+	sampleType := []*profile.ValueType{
+		{Type: "alloc_objects", Unit: "count"},
+		{Type: "alloc_space", Unit: "bytes"},
+		{Type: "inuse_objects", Unit: "count"},
+		{Type: "inuse_space", Unit: "bytes"},
+	}
+	samples := []*profile.Sample{
+		{
+			Value: []int64{2050, 2099200, 1537, 1574400},
+			Location: []*profile.Location{
+				{ID: 1, Mapping: map1, Address: addr1},
+				{ID: 2, Mapping: map2, Address: addr2},
+			},
+			NumLabel: map[string][]int64{"bytes": {1024}},
+		},
+		{
+			Value: []int64{1, 829411, 1, 829411},
+			Location: []*profile.Location{
+				{ID: 3, Mapping: map2, Address: addr2 + 1},
+				{ID: 4, Mapping: map2, Address: addr2 + 2},
+			},
+			NumLabel: map[string][]int64{"bytes": {829411}},
+		},
+		{
+			Value: []int64{1, 829411, 0, 0},
+			Location: []*profile.Location{
+				{ID: 5, Mapping: map1, Address: addr1 + 1},
+				{ID: 6, Mapping: map1, Address: addr1 + 2},
+				{ID: 7, Mapping: map2, Address: addr2 + 3},
+			},
+			NumLabel: map[string][]int64{"bytes": {829411}},
+		},
+	}
+	checkProfile(t, p, rate, periodType, sampleType, samples)
+}
diff --git a/src/runtime/pprof/runtime.go b/src/runtime/pprof/runtime.go
new file mode 100644
index 0000000..e6aace8
--- /dev/null
+++ b/src/runtime/pprof/runtime.go
@@ -0,0 +1,36 @@
+// Copyright 2017 The Go Authors. 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
+
+import (
+	"context"
+	"unsafe"
+)
+
+// runtime_setProfLabel is defined in runtime/proflabel.go.
+func runtime_setProfLabel(labels unsafe.Pointer)
+
+// runtime_getProfLabel is defined in runtime/proflabel.go.
+func runtime_getProfLabel() unsafe.Pointer
+
+// SetGoroutineLabels sets the current goroutine's labels to match ctx.
+// This is a lower-level API than Do, which should be used instead when possible.
+func SetGoroutineLabels(ctx context.Context) {
+	ctxLabels, _ := ctx.Value(labelContextKey{}).(*labelMap)
+	runtime_setProfLabel(unsafe.Pointer(ctxLabels))
+}
+
+// Do calls f with a copy of the parent context with the
+// given labels added to the parent's label map.
+// Each key/value pair in labels is inserted into the label map in the
+// order provided, overriding any previous value for the same key.
+// The augmented label map will be set for the duration of the call to f
+// and restored once f returns.
+func Do(ctx context.Context, labels LabelSet, f func(context.Context)) {
+	defer SetGoroutineLabels(ctx)
+	ctx = WithLabels(ctx, labels)
+	SetGoroutineLabels(ctx)
+	f(ctx)
+}
diff --git a/src/runtime/pprof/runtime_test.go b/src/runtime/pprof/runtime_test.go
new file mode 100644
index 0000000..0dd5324
--- /dev/null
+++ b/src/runtime/pprof/runtime_test.go
@@ -0,0 +1,96 @@
+// Copyright 2017 The Go Authors. 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
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func TestSetGoroutineLabels(t *testing.T) {
+	sync := make(chan struct{})
+
+	wantLabels := map[string]string{}
+	if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("Expected parent goroutine's profile labels to be empty before test, got %v", gotLabels)
+	}
+	go func() {
+		if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+			t.Errorf("Expected child goroutine's profile labels to be empty before test, got %v", gotLabels)
+		}
+		sync <- struct{}{}
+	}()
+	<-sync
+
+	wantLabels = map[string]string{"key": "value"}
+	ctx := WithLabels(context.Background(), Labels("key", "value"))
+	SetGoroutineLabels(ctx)
+	if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("parent goroutine's profile labels: got %v, want %v", gotLabels, wantLabels)
+	}
+	go func() {
+		if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+			t.Errorf("child goroutine's profile labels: got %v, want %v", gotLabels, wantLabels)
+		}
+		sync <- struct{}{}
+	}()
+	<-sync
+
+	wantLabels = map[string]string{}
+	ctx = context.Background()
+	SetGoroutineLabels(ctx)
+	if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("Expected parent goroutine's profile labels to be empty, got %v", gotLabels)
+	}
+	go func() {
+		if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+			t.Errorf("Expected child goroutine's profile labels to be empty, got %v", gotLabels)
+		}
+		sync <- struct{}{}
+	}()
+	<-sync
+}
+
+func TestDo(t *testing.T) {
+	wantLabels := map[string]string{}
+	if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+		t.Errorf("Expected parent goroutine's profile labels to be empty before Do, got %v", gotLabels)
+	}
+
+	Do(context.Background(), Labels("key1", "value1", "key2", "value2"), func(ctx context.Context) {
+		wantLabels := map[string]string{"key1": "value1", "key2": "value2"}
+		if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+			t.Errorf("parent goroutine's profile labels: got %v, want %v", gotLabels, wantLabels)
+		}
+
+		sync := make(chan struct{})
+		go func() {
+			wantLabels := map[string]string{"key1": "value1", "key2": "value2"}
+			if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+				t.Errorf("child goroutine's profile labels: got %v, want %v", gotLabels, wantLabels)
+			}
+			sync <- struct{}{}
+		}()
+		<-sync
+
+	})
+
+	wantLabels = map[string]string{}
+	if gotLabels := getProfLabel(); !reflect.DeepEqual(gotLabels, wantLabels) {
+		fmt.Printf("%#v", gotLabels)
+		fmt.Printf("%#v", wantLabels)
+		t.Errorf("Expected parent goroutine's profile labels to be empty after Do, got %v", gotLabels)
+	}
+}
+
+func getProfLabel() map[string]string {
+	l := (*labelMap)(runtime_getProfLabel())
+	if l == nil {
+		return map[string]string{}
+	}
+	return *l
+}
diff --git a/src/runtime/pprof/testdata/README b/src/runtime/pprof/testdata/README
new file mode 100644
index 0000000..876538e
--- /dev/null
+++ b/src/runtime/pprof/testdata/README
@@ -0,0 +1,9 @@
+These binaries were generated by:
+
+$ cat empty.s
+.global _start
+_start:
+$ as --32 -o empty.o empty.s && ld  --build-id -m elf_i386 -o test32 empty.o
+$ as --64 -o empty.o empty.s && ld --build-id -o test64 empty.o
+$ powerpc-linux-gnu-as -o empty.o empty.s && powerpc-linux-gnu-ld --build-id -o test32be empty.o
+$ powerpc64-linux-gnu-as -o empty.o empty.s && powerpc64-linux-gnu-ld --build-id -o test64be empty.o
diff --git a/src/runtime/pprof/testdata/test32 b/src/runtime/pprof/testdata/test32
new file mode 100755
index 0000000..ce59472
Binary files /dev/null and b/src/runtime/pprof/testdata/test32 differ
diff --git a/src/runtime/pprof/testdata/test32be b/src/runtime/pprof/testdata/test32be
new file mode 100755
index 0000000..f13a732
Binary files /dev/null and b/src/runtime/pprof/testdata/test32be differ
diff --git a/src/runtime/pprof/testdata/test64 b/src/runtime/pprof/testdata/test64
new file mode 100755
index 0000000..3fb42fb
Binary files /dev/null and b/src/runtime/pprof/testdata/test64 differ
diff --git a/src/runtime/pprof/testdata/test64be b/src/runtime/pprof/testdata/test64be
new file mode 100755
index 0000000..09b4b01
Binary files /dev/null and b/src/runtime/pprof/testdata/test64be differ
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index f41672d..f6e07f8 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -190,8 +190,17 @@ func main() {
 	// Make racy client program work: if panicking on
 	// another goroutine at the same time as main returns,
 	// let the other goroutine finish printing the panic trace.
-	// Once it does, it will exit. See issue 3934.
-	if panicking != 0 {
+	// Once it does, it will exit. See issues 3934 and 20018.
+	if atomic.Load(&runningPanicDefers) != 0 {
+		// Running deferred functions should not take long.
+		for c := 0; c < 1000; c++ {
+			if atomic.Load(&runningPanicDefers) == 0 {
+				break
+			}
+			Gosched()
+		}
+	}
+	if atomic.Load(&panicking) != 0 {
 		gopark(nil, nil, "panicwait", traceEvGoStop, 1)
 	}
 
@@ -228,26 +237,23 @@ func forcegchelper() {
 		if debug.gctrace > 0 {
 			println("GC forced")
 		}
-		gcStart(gcBackgroundMode, true)
+		// Time-triggered, fully concurrent.
+		gcStart(gcBackgroundMode, gcTrigger{kind: gcTriggerTime, now: nanotime()})
 	}
 }
 
-//go:nosplit
-
 // Gosched yields the processor, allowing other goroutines to run. It does not
 // suspend the current goroutine, so execution resumes automatically.
+//go:nosplit
 func Gosched() {
 	mcall(gosched_m)
 }
 
-var alwaysFalse bool
-
-// goschedguarded does nothing, but is written in a way that guarantees a preemption check in its prologue.
-// Calls to this function are inserted by the compiler in otherwise uninterruptible loops (see insertLoopReschedChecks).
+// goschedguarded yields the processor like gosched, but also checks
+// for forbidden states and opts out of the yield in those cases.
+//go:nosplit
 func goschedguarded() {
-	if alwaysFalse {
-		goschedguarded()
-	}
+	mcall(goschedguarded_m)
 }
 
 // Puts the current goroutine into a waiting state and calls unlockf.
@@ -432,16 +438,6 @@ 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)
 }
 
@@ -795,9 +791,8 @@ func casgstatus(gp *g, oldval, newval uint32) {
 			nextYield = nanotime() + yieldDelay/2
 		}
 	}
-	if newval == _Grunning && gp.gcscanvalid {
-		// Run queueRescan on the system stack so it has more space.
-		systemstack(func() { queueRescan(gp) })
+	if newval == _Grunning {
+		gp.gcscanvalid = false
 	}
 }
 
@@ -827,8 +822,6 @@ func scang(gp *g, gcw *gcWork) {
 	// Nothing is racing with us now, but gcscandone might be set to true left over
 	// from an earlier round of stack scanning (we scan twice per GC).
 	// We use gcscandone to record whether the scan has been done during this round.
-	// It is important that the scan happens exactly once: if called twice,
-	// the installation of stack barriers will detect the double scan and die.
 
 	gp.gcscandone = false
 
@@ -941,7 +934,7 @@ func restartg(gp *g) {
 // in panic or being exited, this may not reliably stop all
 // goroutines.
 func stopTheWorld(reason string) {
-	semacquire(&worldsema, 0)
+	semacquire(&worldsema)
 	getg().m.preemptoff = reason
 	systemstack(stopTheWorldWithSema)
 }
@@ -1416,6 +1409,7 @@ func needm(x byte) {
 	// running at all (that is, there's no garbage collection
 	// running right now).
 	mp.needextram = mp.schedlink == 0
+	extraMCount--
 	unlockextra(mp.schedlink.ptr())
 
 	// Save and block signals before installing g.
@@ -1441,6 +1435,10 @@ func needm(x byte) {
 	// Initialize this thread to use the m.
 	asminit()
 	minit()
+
+	// mp.curg is now a real goroutine.
+	casgstatus(mp.curg, _Gdead, _Gsyscall)
+	atomic.Xadd(&sched.ngsys, -1)
 }
 
 var earlycgocallback = []byte("fatal error: cgo callback before cgo call\n")
@@ -1481,12 +1479,13 @@ func oneNewExtraM() {
 	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.gcscanvalid = true
 	gp.gcscandone = true
-	gp.gcRescan = -1
-	// malg returns status as Gidle, change to Gsyscall before adding to allg
-	// where GC will see it.
-	casgstatus(gp, _Gidle, _Gsyscall)
+	// malg returns status as _Gidle. Change to _Gdead before
+	// adding to allg where GC can see it. We use _Gdead to hide
+	// this from tracebacks and stack scans since it isn't a
+	// "real" goroutine until needm grabs it.
+	casgstatus(gp, _Gidle, _Gdead)
 	gp.m = mp
 	mp.curg = gp
 	mp.locked = _LockInternal
@@ -1499,9 +1498,16 @@ func oneNewExtraM() {
 	// put on allg for garbage collector
 	allgadd(gp)
 
+	// gp is now on the allg list, but we don't want it to be
+	// counted by gcount. It would be more "proper" to increment
+	// sched.ngfree, but that requires locking. Incrementing ngsys
+	// has the same effect.
+	atomic.Xadd(&sched.ngsys, +1)
+
 	// Add m to the extra list.
 	mnext := lockextra(true)
 	mp.schedlink.set(mnext)
+	extraMCount++
 	unlockextra(mp)
 }
 
@@ -1534,6 +1540,10 @@ func dropm() {
 	// with no pointer manipulation.
 	mp := getg().m
 
+	// Return mp.curg to dead state.
+	casgstatus(mp.curg, _Gsyscall, _Gdead)
+	atomic.Xadd(&sched.ngsys, +1)
+
 	// Block signals before unminit.
 	// Unminit unregisters the signal handling stack (but needs g on some systems).
 	// Setg(nil) clears g, which is the signal handler's cue not to run Go handlers.
@@ -1543,6 +1553,7 @@ func dropm() {
 	unminit()
 
 	mnext := lockextra(true)
+	extraMCount++
 	mp.schedlink.set(mnext)
 
 	setg(nil)
@@ -1559,6 +1570,7 @@ func getm() uintptr {
 }
 
 var extram uintptr
+var extraMCount uint32 // Protected by lockextra
 var extraMWaiters uint32
 
 // lockextra locks the extra list and returns the list head.
@@ -1879,7 +1891,7 @@ func execute(gp *g, inheritTime bool) {
 	// Check whether the profiler needs to be turned on or off.
 	hz := sched.profilehz
 	if _g_.m.profilehz != hz {
-		resetcpuprofiler(hz)
+		setThreadCPUProfiler(hz)
 	}
 
 	if trace.enabled {
@@ -1917,6 +1929,9 @@ top:
 			ready(gp, 0, true)
 		}
 	}
+	if *cgo_yield != nil {
+		asmcgocall(*cgo_yield, nil)
+	}
 
 	// local runq
 	if gp, inheritTime := runqget(_p_); gp != nil {
@@ -2074,7 +2089,7 @@ stop:
 	}
 
 	// poll network
-	if netpollinited() && atomic.Xchg64(&sched.lastpoll, 0) != 0 {
+	if netpollinited() && atomic.Load(&netpollWaiters) > 0 && atomic.Xchg64(&sched.lastpoll, 0) != 0 {
 		if _g_.m.p != 0 {
 			throw("findrunnable: netpoll with p")
 		}
@@ -2115,7 +2130,7 @@ func pollWork() bool {
 	if !runqempty(p) {
 		return true
 	}
-	if netpollinited() && sched.lastpoll != 0 {
+	if netpollinited() && atomic.Load(&netpollWaiters) > 0 && sched.lastpoll != 0 {
 		if gp := netpoll(false); gp != nil {
 			injectglist(gp)
 			return true
@@ -2263,7 +2278,7 @@ func park_m(gp *g) {
 	_g_ := getg()
 
 	if trace.enabled {
-		traceGoPark(_g_.m.waittraceev, _g_.m.waittraceskip, gp)
+		traceGoPark(_g_.m.waittraceev, _g_.m.waittraceskip)
 	}
 
 	casgstatus(gp, _Grunning, _Gwaiting)
@@ -2308,6 +2323,19 @@ func gosched_m(gp *g) {
 	goschedImpl(gp)
 }
 
+// goschedguarded is a forbidden-states-avoided version of gosched_m
+func goschedguarded_m(gp *g) {
+
+	if gp.m.locks != 0 || gp.m.mallocing != 0 || gp.m.preemptoff != "" || gp.m.p.ptr().status != _Prunning {
+		gogo(&gp.sched) // never return
+	}
+
+	if trace.enabled {
+		traceGoSched()
+	}
+	goschedImpl(gp)
+}
+
 func gopreempt_m(gp *g) {
 	if trace.enabled {
 		traceGoPreempt()
@@ -2343,10 +2371,11 @@ func goexit0(gp *g) {
 	gp.writebuf = nil
 	gp.waitreason = ""
 	gp.param = nil
+	gp.labels = nil
+	gp.timer = 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.
+	// stack.
 	gp.gcscanvalid = true
 	dropg()
 
@@ -2775,12 +2804,12 @@ func exitsyscall0(gp *g) {
 func beforefork() {
 	gp := getg().m.curg
 
-	// Fork can hang if preempted with signals frequently enough (see issue 5517).
-	// Ensure that we stay on the same M where we disable profiling.
+	// Block signals during a fork, so that the child does not run
+	// a signal handler before exec if a signal is sent to the process
+	// group. See issue #18600.
 	gp.m.locks++
-	if gp.m.profilehz != 0 {
-		resetcpuprofiler(0)
-	}
+	msigsave(gp.m)
+	sigblock()
 
 	// This function is called before fork in syscall package.
 	// Code between fork and exec must not allocate memory nor even try to grow stack.
@@ -2799,13 +2828,11 @@ func syscall_runtime_BeforeFork() {
 func afterfork() {
 	gp := getg().m.curg
 
-	// See the comment in beforefork.
+	// See the comments in beforefork.
 	gp.stackguard0 = gp.stack.lo + _StackGuard
 
-	hz := sched.profilehz
-	if hz != 0 {
-		resetcpuprofiler(hz)
-	}
+	msigrestore(gp.m.sigmask)
+
 	gp.m.locks--
 }
 
@@ -2816,17 +2843,30 @@ func syscall_runtime_AfterFork() {
 	systemstack(afterfork)
 }
 
+// Called from syscall package after fork in child.
+// It resets non-sigignored signals to the default handler, and
+// restores the signal mask in preparation for the exec.
+//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild
+//go:nosplit
+//go:nowritebarrierrec
+func syscall_runtime_AfterForkInChild() {
+	clearSignalHandlers()
+
+	// When we are the child we are the only thread running,
+	// so we know that nothing else has changed gp.m.sigmask.
+	msigrestore(getg().m.sigmask)
+}
+
 // Allocate a new g, with a stack big enough for stacksize bytes.
 func malg(stacksize int32) *g {
 	newg := new(g)
 	if stacksize >= 0 {
 		stacksize = round2(_StackSystem + stacksize)
 		systemstack(func() {
-			newg.stack, newg.stkbar = stackalloc(uint32(stacksize))
+			newg.stack = stackalloc(uint32(stacksize))
 		})
 		newg.stackguard0 = newg.stack.lo + _StackGuard
 		newg.stackguard1 = ^uintptr(0)
-		newg.stackAlloc = uintptr(stacksize)
 	}
 	return newg
 }
@@ -2874,7 +2914,6 @@ 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 {
@@ -2920,20 +2959,13 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
 	gostartcallfn(&newg.sched, fn)
 	newg.gopc = callerpc
 	newg.startpc = fn.fn
+	if _g_.m.curg != nil {
+		newg.labels = _g_.m.curg.labels
+	}
 	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
-	}
+	newg.gcscanvalid = false
 	casgstatus(newg, _Gdead, _Grunnable)
 
 	if _p_.goidcache == _p_.goidcacheend {
@@ -2971,20 +3003,14 @@ func gfput(_p_ *p, gp *g) {
 		throw("gfput: bad status (not Gdead)")
 	}
 
-	stksize := gp.stackAlloc
+	stksize := gp.stack.hi - gp.stack.lo
 
 	if stksize != _FixedStack {
 		// non-standard stack size - free it.
-		stackfree(gp.stack, gp.stackAlloc)
+		stackfree(gp.stack)
 		gp.stack.lo = 0
 		gp.stack.hi = 0
 		gp.stackguard0 = 0
-		gp.stkbar = nil
-		gp.stkbarPos = 0
-	} else {
-		// Reset stack barriers.
-		gp.stkbar = gp.stkbar[:0]
-		gp.stkbarPos = 0
 	}
 
 	gp.schedlink.set(_p_.gfree)
@@ -3041,16 +3067,15 @@ retry:
 		if gp.stack.lo == 0 {
 			// Stack was deallocated in gfput. Allocate a new one.
 			systemstack(func() {
-				gp.stack, gp.stkbar = stackalloc(_FixedStack)
+				gp.stack = stackalloc(_FixedStack)
 			})
 			gp.stackguard0 = gp.stack.lo + _StackGuard
-			gp.stackAlloc = _FixedStack
 		} else {
 			if raceenabled {
-				racemalloc(unsafe.Pointer(gp.stack.lo), gp.stackAlloc)
+				racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
 			}
 			if msanenabled {
-				msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stackAlloc)
+				msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
 			}
 		}
 	}
@@ -3145,8 +3170,7 @@ func badunlockosthread() {
 
 func gcount() int32 {
 	n := int32(allglen) - sched.ngfree - int32(atomic.Load(&sched.ngsys))
-	for i := 0; ; i++ {
-		_p_ := allp[i]
+	for _, _p_ := range &allp {
 		if _p_ == nil {
 			break
 		}
@@ -3166,13 +3190,14 @@ func mcount() int32 {
 }
 
 var prof struct {
-	lock uint32
-	hz   int32
+	signalLock uint32
+	hz         int32
 }
 
-func _System()       { _System() }
-func _ExternalCode() { _ExternalCode() }
-func _GC()           { _GC() }
+func _System()           { _System() }
+func _ExternalCode()     { _ExternalCode() }
+func _LostExternalCode() { _LostExternalCode() }
+func _GC()               { _GC() }
 
 // Called if we receive a SIGPROF signal.
 // Called by the signal handler, may run during STW.
@@ -3260,7 +3285,6 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 		traceback = false
 	}
 	var stk [maxCPUProfStack]uintptr
-	var haveStackLock *g
 	n := 0
 	if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
 		cgoOff := 0
@@ -3278,26 +3302,9 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 		}
 
 		// 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[cgoOff], len(stk)-cgoOff, 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
-		if gp.m.curg != nil && gcTryLockStackBarriers(gp.m.curg) {
-			// It's safe to traceback the user stack.
-			haveStackLock = gp.m.curg
-			flags |= _TraceJumpStack
-		}
-		// Traceback is safe if we're on the system stack (if
-		// necessary, flags will stop it before switching to
-		// the user stack), or if we locked the user stack.
-		if gp != gp.m.curg || haveStackLock != nil {
-			n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, flags)
-		}
-	}
-	if haveStackLock != nil {
-		gcUnlockStackBarriers(haveStackLock)
+		n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
 	}
 
 	if n <= 0 {
@@ -3307,10 +3314,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 		if GOOS == "windows" && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
 			// Libcall, i.e. runtime syscall on windows.
 			// Collect Go stack that leads to the call.
-			if gcTryLockStackBarriers(mp.libcallg.ptr()) {
-				n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)
-				gcUnlockStackBarriers(mp.libcallg.ptr())
-			}
+			n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)
 		}
 		if n == 0 {
 			// If all of the above has failed, account it against abstract "System" or "GC".
@@ -3329,14 +3333,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	}
 
 	if prof.hz != 0 {
-		// Simple cas-lock to coordinate with setcpuprofilerate.
-		for !atomic.Cas(&prof.lock, 0, 1) {
-			osyield()
-		}
-		if prof.hz != 0 {
-			cpuprof.add(stk[:n])
-		}
-		atomic.Store(&prof.lock, 0)
+		cpuprof.add(gp, stk[:n])
 	}
 	getg().m.mallocing--
 }
@@ -3359,15 +3356,7 @@ func sigprofNonGo() {
 		for n < len(sigprofCallers) && sigprofCallers[n] != 0 {
 			n++
 		}
-
-		// Simple cas-lock to coordinate with setcpuprofilerate.
-		for !atomic.Cas(&prof.lock, 0, 1) {
-			osyield()
-		}
-		if prof.hz != 0 {
-			cpuprof.addNonGo(sigprofCallers[:n])
-		}
-		atomic.Store(&prof.lock, 0)
+		cpuprof.addNonGo(sigprofCallers[:n])
 	}
 
 	atomic.Store(&sigprofCallersUse, 0)
@@ -3380,19 +3369,11 @@ func sigprofNonGo() {
 //go:nowritebarrierrec
 func sigprofNonGoPC(pc uintptr) {
 	if prof.hz != 0 {
-		pc := []uintptr{
+		stk := []uintptr{
 			pc,
 			funcPC(_ExternalCode) + sys.PCQuantum,
 		}
-
-		// Simple cas-lock to coordinate with setcpuprofilerate.
-		for !atomic.Cas(&prof.lock, 0, 1) {
-			osyield()
-		}
-		if prof.hz != 0 {
-			cpuprof.addNonGo(pc)
-		}
-		atomic.Store(&prof.lock, 0)
+		cpuprof.addNonGo(stk)
 	}
 }
 
@@ -3408,7 +3389,7 @@ func sigprofNonGoPC(pc uintptr) {
 // or putting one on the stack at the right offset.
 func setsSP(pc uintptr) bool {
 	f := findfunc(pc)
-	if f == nil {
+	if !f.valid() {
 		// couldn't find the function for this PC,
 		// so assume the worst and stop traceback
 		return true
@@ -3420,8 +3401,9 @@ func setsSP(pc uintptr) bool {
 	return false
 }
 
-// Arrange to call fn with a traceback hz times a second.
-func setcpuprofilerate_m(hz int32) {
+// setcpuprofilerate sets the CPU profiling rate to hz times per second.
+// If hz <= 0, setcpuprofilerate turns off CPU profiling.
+func setcpuprofilerate(hz int32) {
 	// Force sane arguments.
 	if hz < 0 {
 		hz = 0
@@ -3435,20 +3417,23 @@ func setcpuprofilerate_m(hz int32) {
 	// Stop profiler on this thread so that it is safe to lock prof.
 	// if a profiling signal came in while we had prof locked,
 	// it would deadlock.
-	resetcpuprofiler(0)
+	setThreadCPUProfiler(0)
 
-	for !atomic.Cas(&prof.lock, 0, 1) {
+	for !atomic.Cas(&prof.signalLock, 0, 1) {
 		osyield()
 	}
-	prof.hz = hz
-	atomic.Store(&prof.lock, 0)
+	if prof.hz != hz {
+		setProcessCPUProfiler(hz)
+		prof.hz = hz
+	}
+	atomic.Store(&prof.signalLock, 0)
 
 	lock(&sched.lock)
 	sched.profilehz = hz
 	unlock(&sched.lock)
 
 	if hz != 0 {
-		resetcpuprofiler(hz)
+		setThreadCPUProfiler(hz)
 	}
 
 	_g_.m.locks--
@@ -3802,7 +3787,9 @@ func sysmon() {
 				if scavengelimit < forcegcperiod {
 					maxsleep = scavengelimit / 2
 				}
+				osRelax(true)
 				notetsleep(&sched.sysmonnote, maxsleep)
+				osRelax(false)
 				lock(&sched.lock)
 				atomic.Store(&sched.sysmonwait, 0)
 				noteclear(&sched.sysmonnote)
@@ -3811,10 +3798,13 @@ func sysmon() {
 			}
 			unlock(&sched.lock)
 		}
+		// trigger libc interceptors if needed
+		if *cgo_yield != nil {
+			asmcgocall(*cgo_yield, nil)
+		}
 		// poll network if not polled for more than 10ms
 		lastpoll := int64(atomic.Load64(&sched.lastpoll))
 		now := nanotime()
-		unixnow := unixnanotime()
 		if lastpoll != 0 && lastpoll+10*1000*1000 < now {
 			atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
 			gp := netpoll(false) // non-blocking - returns list of goroutines
@@ -3839,8 +3829,7 @@ func sysmon() {
 			idle++
 		}
 		// check if we need to force a GC
-		lastgc := int64(atomic.Load64(&memstats.last_gc))
-		if gcphase == _GCoff && lastgc != 0 && unixnow-lastgc > forcegcperiod && atomic.Load(&forcegc.idle) != 0 {
+		if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && atomic.Load(&forcegc.idle) != 0 {
 			lock(&forcegc.lock)
 			forcegc.idle = 0
 			forcegc.g.schedlink = 0
@@ -3860,7 +3849,7 @@ func sysmon() {
 	}
 }
 
-var pdesc [_MaxGomaxprocs]struct {
+type sysmontick struct {
 	schedtick   uint32
 	schedwhen   int64
 	syscalltick uint32
@@ -3878,7 +3867,7 @@ func retake(now int64) uint32 {
 		if _p_ == nil {
 			continue
 		}
-		pd := &pdesc[i]
+		pd := &_p_.sysmontick
 		s := _p_.status
 		if s == _Psyscall {
 			// Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
@@ -4274,7 +4263,7 @@ func runqputslow(_p_ *p, gp *g, h, t uint32) bool {
 
 	if randomizeScheduler {
 		for i := uint32(1); i <= n; i++ {
-			j := fastrand() % (i + 1)
+			j := fastrandn(i + 1)
 			batch[i], batch[j] = batch[j], batch[i]
 		}
 	}
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 22e4dca..90a6cab 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -53,14 +53,14 @@ func TestStopTheWorldDeadlock(t *testing.T) {
 }
 
 func TestYieldProgress(t *testing.T) {
-	testYieldProgress(t, false)
+	testYieldProgress(false)
 }
 
 func TestYieldLockedProgress(t *testing.T) {
-	testYieldProgress(t, true)
+	testYieldProgress(true)
 }
 
-func testYieldProgress(t *testing.T, locked bool) {
+func testYieldProgress(locked bool) {
 	c := make(chan bool)
 	cack := make(chan bool)
 	go func() {
@@ -428,10 +428,13 @@ func TestPingPongHog(t *testing.T) {
 	<-lightChan
 
 	// Check that hogCount and lightCount are within a factor of
-	// 2, which indicates that both pairs of goroutines handed off
-	// the P within a time-slice to their buddy.
-	if hogCount > lightCount*2 || lightCount > hogCount*2 {
-		t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount))
+	// 5, which indicates that both pairs of goroutines handed off
+	// the P within a time-slice to their buddy. We can use a
+	// fairly large factor here to make this robust: if the
+	// scheduler isn't working right, the gap should be ~1000X.
+	const factor = 5
+	if hogCount > lightCount*factor || lightCount > hogCount*factor {
+		t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount))
 	}
 }
 
diff --git a/src/runtime/profbuf.go b/src/runtime/profbuf.go
new file mode 100644
index 0000000..2719238
--- /dev/null
+++ b/src/runtime/profbuf.go
@@ -0,0 +1,561 @@
+// Copyright 2017 The Go Authors.  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"
+)
+
+// A profBuf is a lock-free buffer for profiling events,
+// safe for concurrent use by one reader and one writer.
+// The writer may be a signal handler running without a user g.
+// The reader is assumed to be a user g.
+//
+// Each logged event corresponds to a fixed size header, a list of
+// uintptrs (typically a stack), and exactly one unsafe.Pointer tag.
+// The header and uintptrs are stored in the circular buffer data and the
+// tag is stored in a circular buffer tags, running in parallel.
+// In the circular buffer data, each event takes 2+hdrsize+len(stk)
+// words: the value 2+hdrsize+len(stk), then the time of the event, then
+// hdrsize words giving the fixed-size header, and then len(stk) words
+// for the stack.
+//
+// The current effective offsets into the tags and data circular buffers
+// for reading and writing are stored in the high 30 and low 32 bits of r and w.
+// The bottom bits of the high 32 are additional flag bits in w, unused in r.
+// "Effective" offsets means the total number of reads or writes, mod 2^length.
+// The offset in the buffer is the effective offset mod the length of the buffer.
+// To make wraparound mod 2^length match wraparound mod length of the buffer,
+// the length of the buffer must be a power of two.
+//
+// If the reader catches up to the writer, a flag passed to read controls
+// whether the read blocks until more data is available. A read returns a
+// pointer to the buffer data itself; the caller is assumed to be done with
+// that data at the next read. The read offset rNext tracks the next offset to
+// be returned by read. By definition, r ≤ rNext ≤ w (before wraparound),
+// and rNext is only used by the reader, so it can be accessed without atomics.
+//
+// If the writer gets ahead of the reader, so that the buffer fills,
+// future writes are discarded and replaced in the output stream by an
+// overflow entry, which has size 2+hdrsize+1, time set to the time of
+// the first discarded write, a header of all zeroed words, and a "stack"
+// containing one word, the number of discarded writes.
+//
+// Between the time the buffer fills and the buffer becomes empty enough
+// to hold more data, the overflow entry is stored as a pending overflow
+// entry in the fields overflow and overflowTime. The pending overflow
+// entry can be turned into a real record by either the writer or the
+// reader. If the writer is called to write a new record and finds that
+// the output buffer has room for both the pending overflow entry and the
+// new record, the writer emits the pending overflow entry and the new
+// record into the buffer. If the reader is called to read data and finds
+// that the output buffer is empty but that there is a pending overflow
+// entry, the reader will return a synthesized record for the pending
+// overflow entry.
+//
+// Only the writer can create or add to a pending overflow entry, but
+// either the reader or the writer can clear the pending overflow entry.
+// A pending overflow entry is indicated by the low 32 bits of 'overflow'
+// holding the number of discarded writes, and overflowTime holding the
+// time of the first discarded write. The high 32 bits of 'overflow'
+// increment each time the low 32 bits transition from zero to non-zero
+// or vice versa. This sequence number avoids ABA problems in the use of
+// compare-and-swap to coordinate between reader and writer.
+// The overflowTime is only written when the low 32 bits of overflow are
+// zero, that is, only when there is no pending overflow entry, in
+// preparation for creating a new one. The reader can therefore fetch and
+// clear the entry atomically using
+//
+//	for {
+//		overflow = load(&b.overflow)
+//		if uint32(overflow) == 0 {
+//			// no pending entry
+//			break
+//		}
+//		time = load(&b.overflowTime)
+//		if cas(&b.overflow, overflow, ((overflow>>32)+1)<<32) {
+//			// pending entry cleared
+//			break
+//		}
+//	}
+//	if uint32(overflow) > 0 {
+//		emit entry for uint32(overflow), time
+//	}
+//
+type profBuf struct {
+	// accessed atomically
+	r, w         profAtomic
+	overflow     uint64
+	overflowTime uint64
+	eof          uint32
+
+	// immutable (excluding slice content)
+	hdrsize uintptr
+	data    []uint64
+	tags    []unsafe.Pointer
+
+	// owned by reader
+	rNext       profIndex
+	overflowBuf []uint64 // for use by reader to return overflow record
+	wait        note
+}
+
+// A profAtomic is the atomically-accessed word holding a profIndex.
+type profAtomic uint64
+
+// A profIndex is the packet tag and data counts and flags bits, described above.
+type profIndex uint64
+
+const (
+	profReaderSleeping profIndex = 1 << 32 // reader is sleeping and must be woken up
+	profWriteExtra     profIndex = 1 << 33 // overflow or eof waiting
+)
+
+func (x *profAtomic) load() profIndex {
+	return profIndex(atomic.Load64((*uint64)(x)))
+}
+
+func (x *profAtomic) store(new profIndex) {
+	atomic.Store64((*uint64)(x), uint64(new))
+}
+
+func (x *profAtomic) cas(old, new profIndex) bool {
+	return atomic.Cas64((*uint64)(x), uint64(old), uint64(new))
+}
+
+func (x profIndex) dataCount() uint32 {
+	return uint32(x)
+}
+
+func (x profIndex) tagCount() uint32 {
+	return uint32(x >> 34)
+}
+
+// countSub subtracts two counts obtained from profIndex.dataCount or profIndex.tagCount,
+// assuming that they are no more than 2^29 apart (guaranteed since they are never more than
+// len(data) or len(tags) apart, respectively).
+// tagCount wraps at 2^30, while dataCount wraps at 2^32.
+// This function works for both.
+func countSub(x, y uint32) int {
+	// x-y is 32-bit signed or 30-bit signed; sign-extend to 32 bits and convert to int.
+	return int(int32(x-y) << 2 >> 2)
+}
+
+// addCountsAndClearFlags returns the packed form of "x + (data, tag) - all flags".
+func (x profIndex) addCountsAndClearFlags(data, tag int) profIndex {
+	return profIndex((uint64(x)>>34+uint64(uint32(tag)<<2>>2))<<34 | uint64(uint32(x)+uint32(data)))
+}
+
+// hasOverflow reports whether b has any overflow records pending.
+func (b *profBuf) hasOverflow() bool {
+	return uint32(atomic.Load64(&b.overflow)) > 0
+}
+
+// takeOverflow consumes the pending overflow records, returning the overflow count
+// and the time of the first overflow.
+// When called by the reader, it is racing against incrementOverflow.
+func (b *profBuf) takeOverflow() (count uint32, time uint64) {
+	overflow := atomic.Load64(&b.overflow)
+	time = atomic.Load64(&b.overflowTime)
+	for {
+		count = uint32(overflow)
+		if count == 0 {
+			time = 0
+			break
+		}
+		// Increment generation, clear overflow count in low bits.
+		if atomic.Cas64(&b.overflow, overflow, ((overflow>>32)+1)<<32) {
+			break
+		}
+		overflow = atomic.Load64(&b.overflow)
+		time = atomic.Load64(&b.overflowTime)
+	}
+	return uint32(overflow), time
+}
+
+// incrementOverflow records a single overflow at time now.
+// It is racing against a possible takeOverflow in the reader.
+func (b *profBuf) incrementOverflow(now int64) {
+	for {
+		overflow := atomic.Load64(&b.overflow)
+
+		// Once we see b.overflow reach 0, it's stable: no one else is changing it underfoot.
+		// We need to set overflowTime if we're incrementing b.overflow from 0.
+		if uint32(overflow) == 0 {
+			// Store overflowTime first so it's always available when overflow != 0.
+			atomic.Store64(&b.overflowTime, uint64(now))
+			atomic.Store64(&b.overflow, (((overflow>>32)+1)<<32)+1)
+			break
+		}
+		// Otherwise we're racing to increment against reader
+		// who wants to set b.overflow to 0.
+		// Out of paranoia, leave 2³²-1 a sticky overflow value,
+		// to avoid wrapping around. Extremely unlikely.
+		if int32(overflow) == -1 {
+			break
+		}
+		if atomic.Cas64(&b.overflow, overflow, overflow+1) {
+			break
+		}
+	}
+}
+
+// newProfBuf returns a new profiling buffer with room for
+// a header of hdrsize words and a buffer of at least bufwords words.
+func newProfBuf(hdrsize, bufwords, tags int) *profBuf {
+	if min := 2 + hdrsize + 1; bufwords < min {
+		bufwords = min
+	}
+
+	// Buffer sizes must be power of two, so that we don't have to
+	// worry about uint32 wraparound changing the effective position
+	// within the buffers. We store 30 bits of count; limiting to 28
+	// gives us some room for intermediate calculations.
+	if bufwords >= 1<<28 || tags >= 1<<28 {
+		throw("newProfBuf: buffer too large")
+	}
+	var i int
+	for i = 1; i < bufwords; i <<= 1 {
+	}
+	bufwords = i
+	for i = 1; i < tags; i <<= 1 {
+	}
+	tags = i
+
+	b := new(profBuf)
+	b.hdrsize = uintptr(hdrsize)
+	b.data = make([]uint64, bufwords)
+	b.tags = make([]unsafe.Pointer, tags)
+	b.overflowBuf = make([]uint64, 2+b.hdrsize+1)
+	return b
+}
+
+// canWriteRecord reports whether the buffer has room
+// for a single contiguous record with a stack of length nstk.
+func (b *profBuf) canWriteRecord(nstk int) bool {
+	br := b.r.load()
+	bw := b.w.load()
+
+	// room for tag?
+	if countSub(br.tagCount(), bw.tagCount())+len(b.tags) < 1 {
+		return false
+	}
+
+	// room for data?
+	nd := countSub(br.dataCount(), bw.dataCount()) + len(b.data)
+	want := 2 + int(b.hdrsize) + nstk
+	i := int(bw.dataCount() % uint32(len(b.data)))
+	if i+want > len(b.data) {
+		// Can't fit in trailing fragment of slice.
+		// Skip over that and start over at beginning of slice.
+		nd -= len(b.data) - i
+	}
+	return nd >= want
+}
+
+// canWriteTwoRecords reports whether the buffer has room
+// for two records with stack lengths nstk1, nstk2, in that order.
+// Each record must be contiguous on its own, but the two
+// records need not be contiguous (one can be at the end of the buffer
+// and the other can wrap around and start at the beginning of the buffer).
+func (b *profBuf) canWriteTwoRecords(nstk1, nstk2 int) bool {
+	br := b.r.load()
+	bw := b.w.load()
+
+	// room for tag?
+	if countSub(br.tagCount(), bw.tagCount())+len(b.tags) < 2 {
+		return false
+	}
+
+	// room for data?
+	nd := countSub(br.dataCount(), bw.dataCount()) + len(b.data)
+
+	// first record
+	want := 2 + int(b.hdrsize) + nstk1
+	i := int(bw.dataCount() % uint32(len(b.data)))
+	if i+want > len(b.data) {
+		// Can't fit in trailing fragment of slice.
+		// Skip over that and start over at beginning of slice.
+		nd -= len(b.data) - i
+		i = 0
+	}
+	i += want
+	nd -= want
+
+	// second record
+	want = 2 + int(b.hdrsize) + nstk2
+	if i+want > len(b.data) {
+		// Can't fit in trailing fragment of slice.
+		// Skip over that and start over at beginning of slice.
+		nd -= len(b.data) - i
+		i = 0
+	}
+	return nd >= want
+}
+
+// write writes an entry to the profiling buffer b.
+// The entry begins with a fixed hdr, which must have
+// length b.hdrsize, followed by a variable-sized stack
+// and a single tag pointer *tagPtr (or nil if tagPtr is nil).
+// No write barriers allowed because this might be called from a signal handler.
+func (b *profBuf) write(tagPtr *unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
+	if b == nil {
+		return
+	}
+	if len(hdr) > int(b.hdrsize) {
+		throw("misuse of profBuf.write")
+	}
+
+	if hasOverflow := b.hasOverflow(); hasOverflow && b.canWriteTwoRecords(1, len(stk)) {
+		// Room for both an overflow record and the one being written.
+		// Write the overflow record if the reader hasn't gotten to it yet.
+		// Only racing against reader, not other writers.
+		count, time := b.takeOverflow()
+		if count > 0 {
+			var stk [1]uintptr
+			stk[0] = uintptr(count)
+			b.write(nil, int64(time), nil, stk[:])
+		}
+	} else if hasOverflow || !b.canWriteRecord(len(stk)) {
+		// Pending overflow without room to write overflow and new records
+		// or no overflow but also no room for new record.
+		b.incrementOverflow(now)
+		b.wakeupExtra()
+		return
+	}
+
+	// There's room: write the record.
+	br := b.r.load()
+	bw := b.w.load()
+
+	// Profiling tag
+	//
+	// The tag is a pointer, but we can't run a write barrier here.
+	// We have interrupted the OS-level execution of gp, but the
+	// runtime still sees gp as executing. In effect, we are running
+	// in place of the real gp. Since gp is the only goroutine that
+	// can overwrite gp.labels, the value of gp.labels is stable during
+	// this signal handler: it will still be reachable from gp when
+	// we finish executing. If a GC is in progress right now, it must
+	// keep gp.labels alive, because gp.labels is reachable from gp.
+	// If gp were to overwrite gp.labels, the deletion barrier would
+	// still shade that pointer, which would preserve it for the
+	// in-progress GC, so all is well. Any future GC will see the
+	// value we copied when scanning b.tags (heap-allocated).
+	// We arrange that the store here is always overwriting a nil,
+	// so there is no need for a deletion barrier on b.tags[wt].
+	wt := int(bw.tagCount() % uint32(len(b.tags)))
+	if tagPtr != nil {
+		*(*uintptr)(unsafe.Pointer(&b.tags[wt])) = uintptr(unsafe.Pointer(*tagPtr))
+	}
+
+	// Main record.
+	// It has to fit in a contiguous section of the slice, so if it doesn't fit at the end,
+	// leave a rewind marker (0) and start over at the beginning of the slice.
+	wd := int(bw.dataCount() % uint32(len(b.data)))
+	nd := countSub(br.dataCount(), bw.dataCount()) + len(b.data)
+	skip := 0
+	if wd+2+int(b.hdrsize)+len(stk) > len(b.data) {
+		b.data[wd] = 0
+		skip = len(b.data) - wd
+		nd -= skip
+		wd = 0
+	}
+	data := b.data[wd:]
+	data[0] = uint64(2 + b.hdrsize + uintptr(len(stk))) // length
+	data[1] = uint64(now)                               // time stamp
+	// header, zero-padded
+	i := uintptr(copy(data[2:2+b.hdrsize], hdr))
+	for ; i < b.hdrsize; i++ {
+		data[2+i] = 0
+	}
+	for i, pc := range stk {
+		data[2+b.hdrsize+uintptr(i)] = uint64(pc)
+	}
+
+	for {
+		// Commit write.
+		// Racing with reader setting flag bits in b.w, to avoid lost wakeups.
+		old := b.w.load()
+		new := old.addCountsAndClearFlags(skip+2+len(stk)+int(b.hdrsize), 1)
+		if !b.w.cas(old, new) {
+			continue
+		}
+		// If there was a reader, wake it up.
+		if old&profReaderSleeping != 0 {
+			notewakeup(&b.wait)
+		}
+		break
+	}
+}
+
+// close signals that there will be no more writes on the buffer.
+// Once all the data has been read from the buffer, reads will return eof=true.
+func (b *profBuf) close() {
+	if atomic.Load(&b.eof) > 0 {
+		throw("runtime: profBuf already closed")
+	}
+	atomic.Store(&b.eof, 1)
+	b.wakeupExtra()
+}
+
+// wakeupExtra must be called after setting one of the "extra"
+// atomic fields b.overflow or b.eof.
+// It records the change in b.w and wakes up the reader if needed.
+func (b *profBuf) wakeupExtra() {
+	for {
+		old := b.w.load()
+		new := old | profWriteExtra
+		if !b.w.cas(old, new) {
+			continue
+		}
+		if old&profReaderSleeping != 0 {
+			notewakeup(&b.wait)
+		}
+		break
+	}
+}
+
+// profBufReadMode specifies whether to block when no data is available to read.
+type profBufReadMode int
+
+const (
+	profBufBlocking profBufReadMode = iota
+	profBufNonBlocking
+)
+
+var overflowTag [1]unsafe.Pointer // always nil
+
+func (b *profBuf) read(mode profBufReadMode) (data []uint64, tags []unsafe.Pointer, eof bool) {
+	if b == nil {
+		return nil, nil, true
+	}
+
+	br := b.rNext
+
+	// Commit previous read, returning that part of the ring to the writer.
+	// First clear tags that have now been read, both to avoid holding
+	// up the memory they point at for longer than necessary
+	// and so that b.write can assume it is always overwriting
+	// nil tag entries (see comment in b.write).
+	rPrev := b.r.load()
+	if rPrev != br {
+		ntag := countSub(br.tagCount(), rPrev.tagCount())
+		ti := int(rPrev.tagCount() % uint32(len(b.tags)))
+		for i := 0; i < ntag; i++ {
+			b.tags[ti] = nil
+			if ti++; ti == len(b.tags) {
+				ti = 0
+			}
+		}
+		b.r.store(br)
+	}
+
+Read:
+	bw := b.w.load()
+	numData := countSub(bw.dataCount(), br.dataCount())
+	if numData == 0 {
+		if b.hasOverflow() {
+			// No data to read, but there is overflow to report.
+			// Racing with writer flushing b.overflow into a real record.
+			count, time := b.takeOverflow()
+			if count == 0 {
+				// Lost the race, go around again.
+				goto Read
+			}
+			// Won the race, report overflow.
+			dst := b.overflowBuf
+			dst[0] = uint64(2 + b.hdrsize + 1)
+			dst[1] = uint64(time)
+			for i := uintptr(0); i < b.hdrsize; i++ {
+				dst[2+i] = 0
+			}
+			dst[2+b.hdrsize] = uint64(count)
+			return dst[:2+b.hdrsize+1], overflowTag[:1], false
+		}
+		if atomic.Load(&b.eof) > 0 {
+			// No data, no overflow, EOF set: done.
+			return nil, nil, true
+		}
+		if bw&profWriteExtra != 0 {
+			// Writer claims to have published extra information (overflow or eof).
+			// Attempt to clear notification and then check again.
+			// If we fail to clear the notification it means b.w changed,
+			// so we still need to check again.
+			b.w.cas(bw, bw&^profWriteExtra)
+			goto Read
+		}
+
+		// Nothing to read right now.
+		// Return or sleep according to mode.
+		if mode == profBufNonBlocking {
+			return nil, nil, false
+		}
+		if !b.w.cas(bw, bw|profReaderSleeping) {
+			goto Read
+		}
+		// Committed to sleeping.
+		notetsleepg(&b.wait, -1)
+		noteclear(&b.wait)
+		goto Read
+	}
+	data = b.data[br.dataCount()%uint32(len(b.data)):]
+	if len(data) > numData {
+		data = data[:numData]
+	} else {
+		numData -= len(data) // available in case of wraparound
+	}
+	skip := 0
+	if data[0] == 0 {
+		// Wraparound record. Go back to the beginning of the ring.
+		skip = len(data)
+		data = b.data
+		if len(data) > numData {
+			data = data[:numData]
+		}
+	}
+
+	ntag := countSub(bw.tagCount(), br.tagCount())
+	if ntag == 0 {
+		throw("runtime: malformed profBuf buffer - tag and data out of sync")
+	}
+	tags = b.tags[br.tagCount()%uint32(len(b.tags)):]
+	if len(tags) > ntag {
+		tags = tags[:ntag]
+	}
+
+	// Count out whole data records until either data or tags is done.
+	// They are always in sync in the buffer, but due to an end-of-slice
+	// wraparound we might need to stop early and return the rest
+	// in the next call.
+	di := 0
+	ti := 0
+	for di < len(data) && data[di] != 0 && ti < len(tags) {
+		if uintptr(di)+uintptr(data[di]) > uintptr(len(data)) {
+			throw("runtime: malformed profBuf buffer - invalid size")
+		}
+		di += int(data[di])
+		ti++
+	}
+
+	// Remember how much we returned, to commit read on next call.
+	b.rNext = br.addCountsAndClearFlags(skip+di, ti)
+
+	if raceenabled {
+		// Match racewritepc in runtime_setProfLabel,
+		// so that the setting of the labels in runtime_setProfLabel
+		// is treated as happening before any use of the labels
+		// by our caller. The synchronization on labelSync itself is a fiction
+		// for the race detector. The actual synchronization is handled
+		// by the fact that the signal handler only reads from the current
+		// goroutine and uses atomics to write the updated queue indices,
+		// and then the read-out from the signal handler buffer uses
+		// atomics to read those queue indices.
+		raceacquire(unsafe.Pointer(&labelSync))
+	}
+
+	return data[:di], tags[:ti], false
+}
diff --git a/src/runtime/profbuf_test.go b/src/runtime/profbuf_test.go
new file mode 100644
index 0000000..d9c5264
--- /dev/null
+++ b/src/runtime/profbuf_test.go
@@ -0,0 +1,182 @@
+// Copyright 2017 The Go Authors. 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 (
+	"reflect"
+	. "runtime"
+	"testing"
+	"time"
+	"unsafe"
+)
+
+func TestProfBuf(t *testing.T) {
+	const hdrSize = 2
+
+	write := func(t *testing.T, b *ProfBuf, tag unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
+		b.Write(&tag, now, hdr, stk)
+	}
+	read := func(t *testing.T, b *ProfBuf, data []uint64, tags []unsafe.Pointer) {
+		rdata, rtags, eof := b.Read(ProfBufNonBlocking)
+		if !reflect.DeepEqual(rdata, data) || !reflect.DeepEqual(rtags, tags) {
+			t.Fatalf("unexpected profile read:\nhave data %#x\nwant data %#x\nhave tags %#x\nwant tags %#x", rdata, data, rtags, tags)
+		}
+		if eof {
+			t.Fatalf("unexpected eof")
+		}
+	}
+	readBlock := func(t *testing.T, b *ProfBuf, data []uint64, tags []unsafe.Pointer) func() {
+		c := make(chan int)
+		go func() {
+			eof := data == nil
+			rdata, rtags, reof := b.Read(ProfBufBlocking)
+			if !reflect.DeepEqual(rdata, data) || !reflect.DeepEqual(rtags, tags) || reof != eof {
+				// Errorf, not Fatalf, because called in goroutine.
+				t.Errorf("unexpected profile read:\nhave data %#x\nwant data %#x\nhave tags %#x\nwant tags %#x\nhave eof=%v, want %v", rdata, data, rtags, tags, reof, eof)
+			}
+			c <- 1
+		}()
+		time.Sleep(10 * time.Millisecond) // let goroutine run and block
+		return func() {
+			select {
+			case <-c:
+			case <-time.After(1 * time.Second):
+				t.Fatalf("timeout waiting for blocked read")
+			}
+		}
+	}
+	readEOF := func(t *testing.T, b *ProfBuf) {
+		rdata, rtags, eof := b.Read(ProfBufBlocking)
+		if rdata != nil || rtags != nil || !eof {
+			t.Errorf("unexpected profile read: %#x, %#x, eof=%v; want nil, nil, eof=true", rdata, rtags, eof)
+		}
+		rdata, rtags, eof = b.Read(ProfBufNonBlocking)
+		if rdata != nil || rtags != nil || !eof {
+			t.Errorf("unexpected profile read (non-blocking): %#x, %#x, eof=%v; want nil, nil, eof=true", rdata, rtags, eof)
+		}
+	}
+
+	myTags := make([]byte, 100)
+	t.Logf("myTags is %p", &myTags[0])
+
+	t.Run("BasicWriteRead", func(t *testing.T) {
+		b := NewProfBuf(2, 11, 1)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+		read(t, b, nil, nil) // release data returned by previous read
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		read(t, b, []uint64{8, 99, 101, 102, 201, 202, 203, 204}, []unsafe.Pointer{unsafe.Pointer(&myTags[2])})
+	})
+
+	t.Run("ReadMany", func(t *testing.T) {
+		b := NewProfBuf(2, 50, 50)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		write(t, b, unsafe.Pointer(&myTags[1]), 500, []uint64{502, 504}, []uintptr{506})
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 99, 101, 102, 201, 202, 203, 204, 5, 500, 502, 504, 506}, []unsafe.Pointer{unsafe.Pointer(&myTags[0]), unsafe.Pointer(&myTags[2]), unsafe.Pointer(&myTags[1])})
+	})
+
+	t.Run("ReadManyShortData", func(t *testing.T) {
+		b := NewProfBuf(2, 50, 50)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 99, 101, 102, 201, 202, 203, 204}, []unsafe.Pointer{unsafe.Pointer(&myTags[0]), unsafe.Pointer(&myTags[2])})
+	})
+
+	t.Run("ReadManyShortTags", func(t *testing.T) {
+		b := NewProfBuf(2, 50, 50)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 99, 101, 102, 201, 202, 203, 204}, []unsafe.Pointer{unsafe.Pointer(&myTags[0]), unsafe.Pointer(&myTags[2])})
+	})
+
+	t.Run("ReadAfterOverflow1", func(t *testing.T) {
+		// overflow record synthesized by write
+		b := NewProfBuf(2, 16, 5)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})           // uses 10
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])}) // reads 10 but still in use until next read
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5})                       // uses 6
+		read(t, b, []uint64{6, 1, 2, 3, 4, 5}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})              // reads 6 but still in use until next read
+		// now 10 available
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204, 205, 206, 207, 208, 209}) // no room
+		for i := 0; i < 299; i++ {
+			write(t, b, unsafe.Pointer(&myTags[3]), int64(100+i), []uint64{101, 102}, []uintptr{201, 202, 203, 204}) // no room for overflow+this record
+		}
+		write(t, b, unsafe.Pointer(&myTags[1]), 500, []uint64{502, 504}, []uintptr{506}) // room for overflow+this record
+		read(t, b, []uint64{5, 99, 0, 0, 300, 5, 500, 502, 504, 506}, []unsafe.Pointer{nil, unsafe.Pointer(&myTags[1])})
+	})
+
+	t.Run("ReadAfterOverflow2", func(t *testing.T) {
+		// overflow record synthesized by read
+		b := NewProfBuf(2, 16, 5)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213})
+		for i := 0; i < 299; i++ {
+			write(t, b, unsafe.Pointer(&myTags[3]), 100, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		}
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])}) // reads 10 but still in use until next read
+		write(t, b, unsafe.Pointer(&myTags[1]), 500, []uint64{502, 504}, []uintptr{})                     // still overflow
+		read(t, b, []uint64{5, 99, 0, 0, 301}, []unsafe.Pointer{nil})                                     // overflow synthesized by read
+		write(t, b, unsafe.Pointer(&myTags[1]), 500, []uint64{502, 505}, []uintptr{506})                  // written
+		read(t, b, []uint64{5, 500, 502, 505, 506}, []unsafe.Pointer{unsafe.Pointer(&myTags[1])})
+	})
+
+	t.Run("ReadAtEndAfterOverflow", func(t *testing.T) {
+		b := NewProfBuf(2, 12, 5)
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		for i := 0; i < 299; i++ {
+			write(t, b, unsafe.Pointer(&myTags[3]), 100, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		}
+		read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+		read(t, b, []uint64{5, 99, 0, 0, 300}, []unsafe.Pointer{nil})
+		write(t, b, unsafe.Pointer(&myTags[1]), 500, []uint64{502, 504}, []uintptr{506})
+		read(t, b, []uint64{5, 500, 502, 504, 506}, []unsafe.Pointer{unsafe.Pointer(&myTags[1])})
+	})
+
+	t.Run("BlockingWriteRead", func(t *testing.T) {
+		b := NewProfBuf(2, 11, 1)
+		wait := readBlock(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+		write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+		wait()
+		wait = readBlock(t, b, []uint64{8, 99, 101, 102, 201, 202, 203, 204}, []unsafe.Pointer{unsafe.Pointer(&myTags[2])})
+		time.Sleep(10 * time.Millisecond)
+		write(t, b, unsafe.Pointer(&myTags[2]), 99, []uint64{101, 102}, []uintptr{201, 202, 203, 204})
+		wait()
+		wait = readBlock(t, b, nil, nil)
+		b.Close()
+		wait()
+		wait = readBlock(t, b, nil, nil)
+		wait()
+		readEOF(t, b)
+	})
+
+	t.Run("DataWraparound", func(t *testing.T) {
+		b := NewProfBuf(2, 16, 1024)
+		for i := 0; i < 10; i++ {
+			write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+			read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+			read(t, b, nil, nil) // release data returned by previous read
+		}
+	})
+
+	t.Run("TagWraparound", func(t *testing.T) {
+		b := NewProfBuf(2, 1024, 2)
+		for i := 0; i < 10; i++ {
+			write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+			read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+			read(t, b, nil, nil) // release data returned by previous read
+		}
+	})
+
+	t.Run("BothWraparound", func(t *testing.T) {
+		b := NewProfBuf(2, 16, 2)
+		for i := 0; i < 10; i++ {
+			write(t, b, unsafe.Pointer(&myTags[0]), 1, []uint64{2, 3}, []uintptr{4, 5, 6, 7, 8, 9})
+			read(t, b, []uint64{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []unsafe.Pointer{unsafe.Pointer(&myTags[0])})
+			read(t, b, nil, nil) // release data returned by previous read
+		}
+	})
+}
diff --git a/src/runtime/proflabel.go b/src/runtime/proflabel.go
new file mode 100644
index 0000000..1b41a8a
--- /dev/null
+++ b/src/runtime/proflabel.go
@@ -0,0 +1,25 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+var labelSync uintptr
+
+//go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel
+func runtime_setProfLabel(labels unsafe.Pointer) {
+	// Introduce race edge for read-back via profile.
+	// This would more properly use &getg().labels as the sync address,
+	// but we do the read in a signal handler and can't call the race runtime then.
+	if raceenabled {
+		racerelease(unsafe.Pointer(&labelSync))
+	}
+	getg().labels = labels
+}
+
+//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel
+func runtime_getProfLabel() unsafe.Pointer {
+	return getg().labels
+}
diff --git a/src/runtime/race.go b/src/runtime/race.go
index d8483c0..49495cc 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -17,9 +17,6 @@ func RaceWrite(addr unsafe.Pointer)
 func RaceReadRange(addr unsafe.Pointer, len int)
 func RaceWriteRange(addr unsafe.Pointer, len int)
 
-func RaceSemacquire(s *uint32)
-func RaceSemrelease(s *uint32)
-
 func RaceErrors() int {
 	var n uint64
 	racecall(&__tsan_report_count, uintptr(unsafe.Pointer(&n)), 0, 0, 0)
@@ -101,7 +98,7 @@ func raceSymbolizeCode(ctx *symbolizeCodeContext) {
 	if f != nil {
 		file, line := f.FileLine(ctx.pc)
 		if line != 0 {
-			ctx.fn = cfuncname(f.raw())
+			ctx.fn = cfuncname(f.funcInfo())
 			ctx.line = uintptr(line)
 			ctx.file = &bytes(file)[0] // assume NUL-terminated
 			ctx.off = ctx.pc - f.Entry()
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
index 587540f..e73e6b3 100644
--- a/src/runtime/race/output_test.go
+++ b/src/runtime/race/output_test.go
@@ -181,10 +181,12 @@ func TestFail(t *testing.T) {
 	}()
 	x = 43
 	<-done
+	t.Log(t.Failed())
 }
 `, `
 ==================
 --- FAIL: TestFail \(0...s\)
+.*main_test.go:13: true
 .*testing.go:.*: race detected during execution of test
 FAIL`},
 
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 8cdf52d..a0b8531 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -68,7 +68,7 @@ func TestRace(t *testing.T) {
 	}
 
 	if totalTests == 0 {
-		t.Fatalf("failed to parse test output")
+		t.Fatalf("failed to parse test output:\n%s", testOutput)
 	}
 	fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n",
 		passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg)
diff --git a/src/runtime/rand_test.go b/src/runtime/rand_test.go
new file mode 100644
index 0000000..f8831b0
--- /dev/null
+++ b/src/runtime/rand_test.go
@@ -0,0 +1,45 @@
+// Copyright 2017 The Go Authors. 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"
+	"strconv"
+	"testing"
+)
+
+func BenchmarkFastrand(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Fastrand()
+		}
+	})
+}
+
+func BenchmarkFastrandHashiter(b *testing.B) {
+	var m = make(map[int]int, 10)
+	for i := 0; i < 10; i++ {
+		m[i] = i
+	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			for _ = range m {
+				break
+			}
+		}
+	})
+}
+
+var sink32 uint32
+
+func BenchmarkFastrandn(b *testing.B) {
+	for n := uint32(2); n <= 5; n++ {
+		b.Run(strconv.Itoa(int(n)), func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				sink32 = Fastrandn(n)
+			}
+		})
+	}
+}
diff --git a/src/runtime/relax_stub.go b/src/runtime/relax_stub.go
new file mode 100644
index 0000000..78c3273
--- /dev/null
+++ b/src/runtime/relax_stub.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. 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 runtime
+
+// osRelax is called by the scheduler when transitioning to and from
+// all Ps being idle.
+func osRelax(relax bool) {}
diff --git a/src/runtime/rt0_linux_mips64x.s b/src/runtime/rt0_linux_mips64x.s
index beb4ef2..0891c68 100644
--- a/src/runtime/rt0_linux_mips64x.s
+++ b/src/runtime/rt0_linux_mips64x.s
@@ -30,7 +30,7 @@ TEXT main(SB),NOSPLIT,$-8
 	// in external linking, glibc jumps to main with argc in R4
 	// and argv in R5
 
-	// initalize REGSB = PC&0xffffffff00000000
+	// initialize REGSB = PC&0xffffffff00000000
 	BGEZAL	R0, 1(PC)
 	SRLV	$32, R31, RSB
 	SLLV	$32, RSB
diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s
index 2c55413..81b9913 100644
--- a/src/runtime/rt0_linux_ppc64le.s
+++ b/src/runtime/rt0_linux_ppc64le.s
@@ -8,6 +8,8 @@ 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.
+	MOVW	CR, R0     // Save CR in caller's frame
+	MOVD	R0, 8(R1)
 	MOVD	R2, 24(R1) // Save TOC in caller's frame.
 	MOVDU	R1, -320(R1) // Allocate frame.
 	
@@ -53,6 +55,9 @@ TEXT _rt0_ppc64le_linux_lib(SB),NOSPLIT,$-8
 	MOVD	R4, _rt0_ppc64le_linux_lib_argv<>(SB)
 
 	// Synchronous initialization.
+	MOVD	$runtime·reginit(SB), R12
+	MOVD	R12, CTR
+	BL	(CTR)
 	MOVD	$runtime·libpreinit(SB), R12
 	MOVD	R12, CTR
 	BL	(CTR)
@@ -117,6 +122,8 @@ done:
 
 	ADD	$320, R1
 	MOVD	24(R1), R2
+	MOVD	8(R1), R0
+	MOVFL	R0, $0xff
 	MOVD	16(R1), R0
 	MOVD	R0, LR
 	RET
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index 5c9b2a0..dd1f79b 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -416,8 +416,37 @@ def find_goroutine(goid):
 		if ptr['atomicstatus'] == 6:  # 'gdead'
 			continue
 		if ptr['goid'] == goid:
-			return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
-	return None, None
+			break
+	else:
+		return None, None
+	# Get the goroutine's saved state.
+	pc, sp = ptr['sched']['pc'], ptr['sched']['sp']
+	# If the goroutine is stopped, sched.sp will be non-0.
+	if sp != 0:
+		return pc.cast(vp), sp.cast(vp)
+	# If the goroutine is in a syscall, use syscallpc/sp.
+	pc, sp = ptr['syscallpc'], ptr['syscallsp']
+	if sp != 0:
+		return pc.cast(vp), sp.cast(vp)
+	# Otherwise, the goroutine is running, so it doesn't have
+	# saved scheduler state. Find G's OS thread.
+	m = ptr['m']
+	if m == 0:
+		return None, None
+	for thr in gdb.selected_inferior().threads():
+		if thr.ptid[1] == m['procid']:
+			break
+	else:
+		return None, None
+	# Get scheduler state from the G's OS thread state.
+	curthr = gdb.selected_thread()
+	try:
+		thr.switch()
+		pc = gdb.parse_and_eval('$pc')
+		sp = gdb.parse_and_eval('$sp')
+	finally:
+		curthr.switch()
+	return pc.cast(vp), sp.cast(vp)
 
 
 class GoroutineCmd(gdb.Command):
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index f886961..b025e18 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -69,6 +69,7 @@ func checkGdbPython(t *testing.T) {
 
 const helloSource = `
 import "fmt"
+import "runtime"
 var gslice []string
 func main() {
 	mapvar := make(map[string]string,5)
@@ -78,9 +79,10 @@ func main() {
 	ptrvar := &strvar
 	slicevar := make([]string, 0, 16)
 	slicevar = append(slicevar, mapvar["abc"])
-	fmt.Println("hi") // line 12
+	fmt.Println("hi") // line 13
 	_ = ptrvar
 	gslice = slicevar
+	runtime.KeepAlive(mapvar)
 }
 `
 
@@ -89,6 +91,9 @@ func TestGdbPython(t *testing.T) {
 }
 
 func TestGdbPythonCgo(t *testing.T) {
+	if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
+		testenv.SkipFlaky(t, 18784)
+	}
 	testGdbPython(t, true)
 }
 
@@ -152,6 +157,9 @@ func testGdbPython(t *testing.T, cgo bool) {
 		"-ex", "info locals",
 		"-ex", "echo END\n",
 		"-ex", "down", // back to fmt.Println (goroutine 2 below only works at bottom of stack.  TODO: fix that)
+		"-ex", "echo BEGIN goroutine 1 bt\n",
+		"-ex", "goroutine 1 bt",
+		"-ex", "echo END\n",
 		"-ex", "echo BEGIN goroutine 2 bt\n",
 		"-ex", "goroutine 2 bt",
 		"-ex", "echo END\n",
@@ -208,8 +216,13 @@ func testGdbPython(t *testing.T, cgo bool) {
 		t.Fatalf("info locals failed: %s", bl)
 	}
 
-	btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`)
-	if bl := blocks["goroutine 2 bt"]; !btGoroutineRe.MatchString(bl) {
+	btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?fmt\.Println.+at`)
+	if bl := blocks["goroutine 1 bt"]; !btGoroutine1Re.MatchString(bl) {
+		t.Fatalf("goroutine 1 bt failed: %s", bl)
+	}
+
+	btGoroutine2Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?runtime.+at`)
+	if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) {
 		t.Fatalf("goroutine 2 bt failed: %s", bl)
 	}
 }
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index 5d0bf81..c073348 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -35,15 +35,14 @@ var traceback_env uint32
 //go:nosplit
 func gotraceback() (level int32, all, crash bool) {
 	_g_ := getg()
-	all = _g_.m.throwing > 0
+	t := atomic.Load(&traceback_cache)
+	crash = t&tracebackCrash != 0
+	all = _g_.m.throwing > 0 || t&tracebackAll != 0
 	if _g_.m.traceback != 0 {
 		level = int32(_g_.m.traceback)
-		return
+	} else {
+		level = int32(t >> tracebackShift)
 	}
-	t := atomic.Load(&traceback_cache)
-	crash = t&tracebackCrash != 0
-	all = all || t&tracebackAll != 0
-	level = int32(t >> tracebackShift)
 	return
 }
 
@@ -319,23 +318,20 @@ type dbgVar struct {
 // existing int var for that value, which may
 // already have an initial value.
 var debug struct {
-	allocfreetrace    int32
-	cgocheck          int32
-	efence            int32
-	gccheckmark       int32
-	gcpacertrace      int32
-	gcshrinkstackoff  int32
-	gcstackbarrieroff int32
-	gcstackbarrierall int32
-	gcrescanstacks    int32
-	gcstoptheworld    int32
-	gctrace           int32
-	invalidptr        int32
-	sbrk              int32
-	scavenge          int32
-	scheddetail       int32
-	schedtrace        int32
-	wbshadow          int32
+	allocfreetrace   int32
+	cgocheck         int32
+	efence           int32
+	gccheckmark      int32
+	gcpacertrace     int32
+	gcshrinkstackoff int32
+	gcrescanstacks   int32
+	gcstoptheworld   int32
+	gctrace          int32
+	invalidptr       int32
+	sbrk             int32
+	scavenge         int32
+	scheddetail      int32
+	schedtrace       int32
 }
 
 var dbgvars = []dbgVar{
@@ -345,8 +341,6 @@ var dbgvars = []dbgVar{
 	{"gccheckmark", &debug.gccheckmark},
 	{"gcpacertrace", &debug.gcpacertrace},
 	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
-	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
-	{"gcstackbarrierall", &debug.gcstackbarrierall},
 	{"gcrescanstacks", &debug.gcrescanstacks},
 	{"gcstoptheworld", &debug.gcstoptheworld},
 	{"gctrace", &debug.gctrace},
@@ -355,7 +349,6 @@ var dbgvars = []dbgVar{
 	{"scavenge", &debug.scavenge},
 	{"scheddetail", &debug.scheddetail},
 	{"schedtrace", &debug.schedtrace},
-	{"wbshadow", &debug.wbshadow},
 }
 
 func parsedebugvars() {
@@ -398,17 +391,6 @@ func parsedebugvars() {
 	setTraceback(gogetenv("GOTRACEBACK"))
 	traceback_env = traceback_cache
 
-	if debug.gcrescanstacks == 0 {
-		// Without rescanning, there's no need for stack
-		// barriers.
-		debug.gcstackbarrieroff = 1
-		debug.gcstackbarrierall = 0
-	}
-
-	if debug.gcstackbarrierall > 0 {
-		firstStackBarrierOffset = 0
-	}
-
 	// For cgocheck > 1, we turn on the write barrier at all times
 	// and check all pointer writes.
 	if debug.cgocheck > 1 {
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 1ceab0a..6871d9c 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -270,7 +270,7 @@ type gobuf struct {
 type sudog struct {
 	// The following fields are protected by the hchan.lock of the
 	// channel this sudog is blocking on. shrinkstack depends on
-	// this.
+	// this for sudogs involved in channel ops.
 
 	g          *g
 	selectdone *uint32 // CAS to 1 to win select race (may point to stack)
@@ -279,25 +279,19 @@ type sudog struct {
 	elem       unsafe.Pointer // data element (may point to stack)
 
 	// The following fields are never accessed concurrently.
-	// waitlink is only accessed by g.
+	// For channels, waitlink is only accessed by g.
+	// For semaphores, all fields (including the ones above)
+	// are only accessed when holding a semaRoot lock.
 
 	acquiretime int64
 	releasetime int64
 	ticket      uint32
-	waitlink    *sudog // g.waiting list
+	parent      *sudog // semaRoot binary tree
+	waitlink    *sudog // g.waiting list or semaRoot
+	waittail    *sudog // semaRoot
 	c           *hchan // channel
 }
 
-type gcstats struct {
-	// the struct must consist of only uint64's,
-	// because it is casted to uint64[].
-	nhandoff    uint64
-	nhandoffcnt uint64
-	nprocyield  uint64
-	nosyield    uint64
-	nsleep      uint64
-}
-
 type libcall struct {
 	fn   uintptr
 	n    uintptr // number of parameters
@@ -323,12 +317,6 @@ type stack struct {
 	hi uintptr
 }
 
-// stkbar records the state of a G's stack barrier.
-type stkbar struct {
-	savedLRPtr uintptr // location overwritten by stack barrier PC
-	savedLRVal uintptr // value overwritten at savedLRPtr
-}
-
 type g struct {
 	// Stack parameters.
 	// stack describes the actual stack memory: [stack.lo, stack.hi).
@@ -344,12 +332,9 @@ type g struct {
 	_panic         *_panic // innermost panic - offset known to liblink
 	_defer         *_defer // innermost defer
 	m              *m      // current m; offset known to arm liblink
-	stackAlloc     uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc)
 	sched          gobuf
 	syscallsp      uintptr        // if status==Gsyscall, syscallsp = sched.sp to use during gc
 	syscallpc      uintptr        // if status==Gsyscall, syscallpc = sched.pc to use during gc
-	stkbar         []stkbar       // stack barriers, from low to high (see top of mstkbar.go)
-	stkbarPos      uintptr        // index of lowest stack barrier not hit
 	stktopsp       uintptr        // expected sp at top of stack, to check in traceback
 	param          unsafe.Pointer // passed parameter on wakeup
 	atomicstatus   uint32
@@ -362,7 +347,7 @@ type g struct {
 	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
+	gcscanvalid    bool     // false at start of gc cycle, true if G has not run since last scan; TODO: remove?
 	throwsplit     bool     // must not split stack
 	raceignore     int8     // ignore race detection events
 	sysblocktraced bool     // StartTrace has emitted EvGoInSyscall about this goroutine
@@ -378,18 +363,13 @@ 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); in lock order
-	cgoCtxt        []uintptr // cgo traceback context
+	waiting        *sudog         // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
+	cgoCtxt        []uintptr      // cgo traceback context
+	labels         unsafe.Pointer // profiler labels
+	timer          *timer         // cached timer for time.Sleep
 
 	// 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
 	// to allocate gcAssistBytes bytes without assisting. If this
@@ -429,6 +409,7 @@ type m struct {
 	inwb          bool // m is executing a write barrier
 	newSigstack   bool // minit on C thread called sigaltstack
 	printlock     int8
+	incgo         bool // m is executing a cgo call
 	fastrand      uint32
 	ncgocall      uint64      // number of cgo calls in total
 	ncgo          int32       // number of cgo calls currently in progress
@@ -445,7 +426,6 @@ type m struct {
 	fflag         uint32      // floating point compare flags
 	locked        uint32      // tracking for lockosthread
 	nextwaitm     uintptr     // next m waiting for lock
-	gcstats       gcstats
 	needextram    bool
 	traceback     uint8
 	waitunlockf   unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
@@ -473,9 +453,10 @@ type p struct {
 	id          int32
 	status      uint32 // one of pidle/prunning/...
 	link        puintptr
-	schedtick   uint32   // incremented on every scheduler call
-	syscalltick uint32   // incremented on every system call
-	m           muintptr // back-link to associated m (nil if idle)
+	schedtick   uint32     // incremented on every scheduler call
+	syscalltick uint32     // incremented on every system call
+	sysmontick  sysmontick // last tick observed by sysmon
+	m           muintptr   // back-link to associated m (nil if idle)
 	mcache      *mcache
 	racectx     uintptr
 
@@ -510,6 +491,14 @@ type p struct {
 
 	tracebuf traceBufPtr
 
+	// traceSweep indicates the sweep events should be traced.
+	// This is used to defer the sweep start event until a span
+	// has actually been swept.
+	traceSweep bool
+	// traceSwept and traceReclaimed track the number of bytes
+	// swept and reclaimed by sweeping in the current sweep loop.
+	traceSwept, traceReclaimed uintptr
+
 	palloc persistentAlloc // per-P to avoid mutex
 
 	// Per-P GC state
@@ -530,7 +519,7 @@ type p struct {
 const (
 	// The max value of GOMAXPROCS.
 	// There are no fundamental restrictions on the value.
-	_MaxGomaxprocs = 1 << 8
+	_MaxGomaxprocs = 1 << 10
 )
 
 type schedt struct {
@@ -607,7 +596,6 @@ const (
 	_SigThrow                // if signal.Notify doesn't take it, exit loudly
 	_SigPanic                // if the signal is from the kernel, panic
 	_SigDefault              // if the signal isn't explicitly requested, don't monitor it
-	_SigHandling             // our signal handler is registered
 	_SigGoExit               // cause all runtime procs to exit (only used on Plan 9).
 	_SigSetStack             // add SA_ONSTACK to libc handler
 	_SigUnblock              // unblocked in minit
@@ -639,8 +627,10 @@ type itab struct {
 	inter  *interfacetype
 	_type  *_type
 	link   *itab
-	bad    int32
-	inhash int32      // has this itab been added to hash?
+	hash   uint32 // copy of _type.hash. Used for type switches.
+	bad    bool   // type does not implement interface
+	inhash bool   // has this itab been added to hash?
+	unused [2]byte
 	fun    [1]uintptr // variable sized
 }
 
@@ -704,7 +694,7 @@ type _panic struct {
 
 // stack traces
 type stkframe struct {
-	fn       *_func     // function being run
+	fn       funcInfo   // function being run
 	pc       uintptr    // program counter within fn
 	continpc uintptr    // program counter where execution can continue, or 0 if not
 	lr       uintptr    // program counter at caller aka link register
@@ -731,22 +721,30 @@ var (
 	allm        *m
 	allp        [_MaxGomaxprocs + 1]*p
 	gomaxprocs  int32
-	panicking   uint32
 	ncpu        int32
 	forcegc     forcegcstate
 	sched       schedt
 	newprocs    int32
 
 	// Information about what cpu features are available.
-	// Set on startup in asm_{x86,amd64}.s.
-	cpuid_ecx         uint32
-	cpuid_edx         uint32
-	cpuid_ebx7        uint32
-	lfenceBeforeRdtsc bool
-	support_avx       bool
-	support_avx2      bool
-	support_bmi1      bool
-	support_bmi2      bool
+	// Set on startup in asm_{386,amd64,amd64p32}.s.
+	// Packages outside the runtime should not use these
+	// as they are not an external api.
+	processorVersionInfo uint32
+	isIntel              bool
+	lfenceBeforeRdtsc    bool
+	support_aes          bool
+	support_avx          bool
+	support_avx2         bool
+	support_bmi1         bool
+	support_bmi2         bool
+	support_erms         bool
+	support_osxsave      bool
+	support_popcnt       bool
+	support_sse2         bool
+	support_sse41        bool
+	support_sse42        bool
+	support_ssse3        bool
 
 	goarm                uint8 // set by cmd/link on arm systems
 	framepointer_enabled bool  // set by cmd/link
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index 9febbe6..e9bc256 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -50,6 +50,23 @@ func BenchmarkIfaceCmpNil100(b *testing.B) {
 	}
 }
 
+var efaceCmp1 interface{}
+var efaceCmp2 interface{}
+
+func BenchmarkEfaceCmpDiff(b *testing.B) {
+	x := 5
+	efaceCmp1 = &x
+	y := 6
+	efaceCmp2 = &y
+	for i := 0; i < b.N; i++ {
+		for j := 0; j < 100; j++ {
+			if efaceCmp1 == efaceCmp2 {
+				b.Fatal("bad comparison")
+			}
+		}
+	}
+}
+
 func BenchmarkDefer(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		defer1()
@@ -62,7 +79,6 @@ func defer1() {
 			panic("bad recover")
 		}
 	}(1, 2, 3)
-	return
 }
 
 func BenchmarkDefer10(b *testing.B) {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 0d846b1..715cee8 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -11,11 +11,12 @@ import (
 	"unsafe"
 )
 
-const (
-	debugSelect = false
+const debugSelect = false
 
+const (
 	// scase.kind
-	caseRecv = iota
+	caseNil = iota
+	caseRecv
 	caseSend
 	caseDefault
 )
@@ -37,10 +38,9 @@ type hselect struct {
 type scase struct {
 	elem        unsafe.Pointer // data element
 	c           *hchan         // chan
-	pc          uintptr        // return pc
+	pc          uintptr        // return pc (for race detector / msan)
 	kind        uint16
-	so          uint16 // vararg of selected bool
-	receivedp   *bool  // pointer to received bool (recv2)
+	receivedp   *bool // pointer to received bool, if any
 	releasetime int64
 }
 
@@ -72,92 +72,63 @@ func newselect(sel *hselect, selsize int64, size int32) {
 	}
 }
 
-//go:nosplit
-func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
-	// nil cases do not compete
-	if c != nil {
-		selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
-	}
-	return
-}
-
-// cut in half to give stack a chance to split
-func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
+func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
+	pc := getcallerpc(unsafe.Pointer(&sel))
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectsend: too many cases")
 	}
 	sel.ncase = i + 1
+	if c == nil {
+		return
+	}
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
-
 	cas.pc = pc
 	cas.c = c
-	cas.so = uint16(so)
 	cas.kind = caseSend
 	cas.elem = elem
 
 	if debugSelect {
-		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
+		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
 	}
 }
 
-//go:nosplit
-func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
-	// nil cases do not compete
-	if c != nil {
-		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
-	}
-	return
-}
-
-//go:nosplit
-func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
-	// nil cases do not compete
-	if c != nil {
-		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
-	}
-	return
-}
-
-func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
+func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
+	pc := getcallerpc(unsafe.Pointer(&sel))
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectrecv: too many cases")
 	}
 	sel.ncase = i + 1
+	if c == nil {
+		return
+	}
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 	cas.pc = pc
 	cas.c = c
-	cas.so = uint16(so)
 	cas.kind = caseRecv
 	cas.elem = elem
 	cas.receivedp = received
 
 	if debugSelect {
-		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
+		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
 	}
 }
 
-//go:nosplit
-func selectdefault(sel *hselect) (selected bool) {
-	selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
-	return
-}
-
-func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
+func selectdefault(sel *hselect) {
+	pc := getcallerpc(unsafe.Pointer(&sel))
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectdefault: too many cases")
 	}
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
-	cas.pc = callerpc
+	cas.pc = pc
 	cas.c = nil
-	cas.so = uint16(so)
 	cas.kind = caseDefault
 
 	if debugSelect {
-		print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n")
+		print("selectdefault s=", sel, " pc=", hex(cas.pc), "\n")
 	}
 }
 
@@ -181,14 +152,11 @@ func selunlock(scases []scase, lockorder []uint16) {
 	// 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 := len(scases)
-	r := 0
-	// skip the default case
-	if n > 0 && scases[lockorder[0]].c == nil {
-		r = 1
-	}
-	for i := n - 1; i >= r; i-- {
+	for i := len(scases) - 1; i >= 0; i-- {
 		c := scases[lockorder[i]].c
+		if c == nil {
+			break
+		}
 		if i > 0 && c == scases[lockorder[i-1]].c {
 			continue // will unlock it on the next iteration
 		}
@@ -229,23 +197,15 @@ func block() {
 // *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)
-	*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
-	setcallerpc(unsafe.Pointer(&sel), pc)
-}
-
-// selectgoImpl returns scase.pc and scase.so for the select
-// case which fired.
-func selectgoImpl(sel *hselect) (uintptr, uint16) {
+// selectgo returns the index of the chosen scase, which matches the
+// ordinal position of its respective select{recv,send,default} call.
+func selectgo(sel *hselect) int {
 	if debugSelect {
 		print("select: sel=", sel, "\n")
 	}
+	if sel.ncase != sel.tcase {
+		throw("selectgo: case count mismatch")
+	}
 
 	scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
 	scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
@@ -270,7 +230,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
 	pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
 	for i := 1; i < int(sel.ncase); i++ {
-		j := int(fastrand()) % (i + 1)
+		j := fastrandn(uint32(i + 1))
 		pollorder[i] = pollorder[j]
 		pollorder[j] = uint16(i)
 	}
@@ -338,13 +298,19 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 
 loop:
 	// pass 1 - look for something already waiting
+	var dfli int
 	var dfl *scase
+	var casi int
 	var cas *scase
 	for i := 0; i < int(sel.ncase); i++ {
-		cas = &scases[pollorder[i]]
+		casi = int(pollorder[i])
+		cas = &scases[casi]
 		c = cas.c
 
 		switch cas.kind {
+		case caseNil:
+			continue
+
 		case caseRecv:
 			sg = c.sendq.dequeue()
 			if sg != nil {
@@ -373,12 +339,14 @@ loop:
 			}
 
 		case caseDefault:
+			dfli = casi
 			dfl = cas
 		}
 	}
 
 	if dfl != nil {
 		selunlock(scases, lockorder)
+		casi = dfli
 		cas = dfl
 		goto retc
 	}
@@ -391,7 +359,11 @@ loop:
 	}
 	nextp = &gp.waiting
 	for _, casei := range lockorder {
-		cas = &scases[casei]
+		casi = int(casei)
+		cas = &scases[casi]
+		if cas.kind == caseNil {
+			continue
+		}
 		c = cas.c
 		sg := acquireSudog()
 		sg.g = gp
@@ -420,7 +392,7 @@ loop:
 
 	// wait for someone to wake us up
 	gp.param = nil
-	gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 2)
+	gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 1)
 
 	// While we were asleep, some goroutine came along and completed
 	// one of the cases in the select and woke us up (called ready).
@@ -485,6 +457,7 @@ loop:
 	// otherwise they stack up on quiet channels
 	// record the successful case, if any.
 	// We singly-linked up the SudoGs in lock order.
+	casi = -1
 	cas = nil
 	sglist = gp.waiting
 	// Clear all elem before unlinking from gp.waiting.
@@ -497,11 +470,15 @@ loop:
 
 	for _, casei := range lockorder {
 		k = &scases[casei]
+		if k.kind == caseNil {
+			continue
+		}
 		if sglist.releasetime > 0 {
 			k.releasetime = sglist.releasetime
 		}
 		if sg == sglist {
 			// sg has already been dequeued by the G that woke us up.
+			casi = int(casei)
 			cas = k
 		} else {
 			c = k.c
@@ -609,7 +586,7 @@ bufsend:
 
 recv:
 	// can receive from sleeping sender (sg)
-	recv(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
+	recv(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2)
 	if debugSelect {
 		print("syncrecv: sel=", sel, " c=", c, "\n")
 	}
@@ -640,7 +617,7 @@ send:
 	if msanenabled {
 		msanread(cas.elem, c.elemtype.size)
 	}
-	send(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
+	send(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2)
 	if debugSelect {
 		print("syncsend: sel=", sel, " c=", c, "\n")
 	}
@@ -648,9 +625,9 @@ send:
 
 retc:
 	if cas.releasetime > 0 {
-		blockevent(cas.releasetime-t0, 2)
+		blockevent(cas.releasetime-t0, 1)
 	}
-	return cas.pc, cas.so
+	return casi
 
 sclose:
 	// send on closed channel
@@ -694,22 +671,15 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
 		rc := &cases[i]
 		switch rc.dir {
 		case selectDefault:
-			selectdefaultImpl(sel, uintptr(i), 0)
+			selectdefault(sel)
 		case selectSend:
-			if rc.ch == nil {
-				break
-			}
-			selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
+			selectsend(sel, rc.ch, rc.val)
 		case selectRecv:
-			if rc.ch == nil {
-				break
-			}
-			selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
+			selectrecv(sel, rc.ch, rc.val, r)
 		}
 	}
 
-	pc, _ := selectgoImpl(sel)
-	chosen = int(pc)
+	chosen = selectgo(sel)
 	recvOK = *r
 	return
 }
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index 37318ff..8715e07 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -27,10 +27,19 @@ import (
 
 // Asynchronous semaphore for sync.Mutex.
 
+// A semaRoot holds a balanced tree of sudog with distinct addresses (s.elem).
+// Each of those sudog may in turn point (through s.waitlink) to a list
+// of other sudogs waiting on the same address.
+// The operations on the inner lists of sudogs with the same address
+// are all O(1). The scanning of the top-level semaRoot list is O(log n),
+// where n is the number of distinct addresses with goroutines blocked
+// on them that hash to the given semaRoot.
+// See golang.org/issue/17953 for a program that worked badly
+// before we introduced the second level of list, and test/locklinear.go
+// for a test that exercises this.
 type semaRoot struct {
 	lock  mutex
-	head  *sudog
-	tail  *sudog
+	treap *sudog // root of balanced tree of unique waiters.
 	nwait uint32 // Number of waiters. Read w/o the lock.
 }
 
@@ -44,26 +53,26 @@ var semtable [semTabSize]struct {
 
 //go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
 func sync_runtime_Semacquire(addr *uint32) {
-	semacquire(addr, semaBlockProfile)
+	semacquire1(addr, false, semaBlockProfile)
 }
 
-//go:linkname net_runtime_Semacquire net.runtime_Semacquire
-func net_runtime_Semacquire(addr *uint32) {
-	semacquire(addr, semaBlockProfile)
+//go:linkname poll_runtime_Semacquire internal/poll.runtime_Semacquire
+func poll_runtime_Semacquire(addr *uint32) {
+	semacquire1(addr, false, semaBlockProfile)
 }
 
 //go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
-func sync_runtime_Semrelease(addr *uint32) {
-	semrelease(addr)
+func sync_runtime_Semrelease(addr *uint32, handoff bool) {
+	semrelease1(addr, handoff)
 }
 
 //go:linkname sync_runtime_SemacquireMutex sync.runtime_SemacquireMutex
-func sync_runtime_SemacquireMutex(addr *uint32) {
-	semacquire(addr, semaBlockProfile|semaMutexProfile)
+func sync_runtime_SemacquireMutex(addr *uint32, lifo bool) {
+	semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile)
 }
 
-//go:linkname net_runtime_Semrelease net.runtime_Semrelease
-func net_runtime_Semrelease(addr *uint32) {
+//go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease
+func poll_runtime_Semrelease(addr *uint32) {
 	semrelease(addr)
 }
 
@@ -82,7 +91,11 @@ const (
 )
 
 // Called from runtime.
-func semacquire(addr *uint32, profile semaProfileFlags) {
+func semacquire(addr *uint32) {
+	semacquire1(addr, false, 0)
+}
+
+func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags) {
 	gp := getg()
 	if gp != gp.m.curg {
 		throw("semacquire not on the G stack")
@@ -104,6 +117,7 @@ func semacquire(addr *uint32, profile semaProfileFlags) {
 	t0 := int64(0)
 	s.releasetime = 0
 	s.acquiretime = 0
+	s.ticket = 0
 	if profile&semaBlockProfile != 0 && blockprofilerate > 0 {
 		t0 = cputicks()
 		s.releasetime = -1
@@ -126,9 +140,9 @@ func semacquire(addr *uint32, profile semaProfileFlags) {
 		}
 		// Any semrelease after the cansemacquire knows we're waiting
 		// (we set nwait above), so go to sleep.
-		root.queue(addr, s)
+		root.queue(addr, s, lifo)
 		goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
-		if cansemacquire(addr) {
+		if s.ticket != 0 || cansemacquire(addr) {
 			break
 		}
 	}
@@ -139,6 +153,10 @@ func semacquire(addr *uint32, profile semaProfileFlags) {
 }
 
 func semrelease(addr *uint32) {
+	semrelease1(addr, false)
+}
+
+func semrelease1(addr *uint32, handoff bool) {
 	root := semroot(addr)
 	atomic.Xadd(addr, 1)
 
@@ -157,28 +175,22 @@ func semrelease(addr *uint32) {
 		unlock(&root.lock)
 		return
 	}
-	s := root.head
-	for ; s != nil; s = s.next {
-		if s.elem == unsafe.Pointer(addr) {
-			atomic.Xadd(&root.nwait, -1)
-			root.dequeue(s)
-			break
-		}
-	}
+	s, t0 := root.dequeue(addr)
 	if s != nil {
-		if s.acquiretime != 0 {
-			t0 := cputicks()
-			for x := root.head; x != nil; x = x.next {
-				if x.elem == unsafe.Pointer(addr) {
-					x.acquiretime = t0
-					break
-				}
-			}
-			mutexevent(t0-s.acquiretime, 3)
-		}
+		atomic.Xadd(&root.nwait, -1)
 	}
 	unlock(&root.lock)
 	if s != nil { // May be slow, so unlock first
+		acquiretime := s.acquiretime
+		if acquiretime != 0 {
+			mutexevent(t0-acquiretime, 3)
+		}
+		if s.ticket != 0 {
+			throw("corrupted semaphore ticket")
+		}
+		if handoff && cansemacquire(addr) {
+			s.ticket = 1
+		}
 		readyWithTime(s, 5)
 	}
 }
@@ -199,33 +211,230 @@ func cansemacquire(addr *uint32) bool {
 	}
 }
 
-func (root *semaRoot) queue(addr *uint32, s *sudog) {
+// queue adds s to the blocked goroutines in semaRoot.
+func (root *semaRoot) queue(addr *uint32, s *sudog, lifo bool) {
 	s.g = getg()
 	s.elem = unsafe.Pointer(addr)
 	s.next = nil
-	s.prev = root.tail
-	if root.tail != nil {
-		root.tail.next = s
-	} else {
-		root.head = s
+	s.prev = nil
+
+	var last *sudog
+	pt := &root.treap
+	for t := *pt; t != nil; t = *pt {
+		if t.elem == unsafe.Pointer(addr) {
+			// Already have addr in list.
+			if lifo {
+				// Substitute s in t's place in treap.
+				*pt = s
+				s.ticket = t.ticket
+				s.acquiretime = t.acquiretime
+				s.parent = t.parent
+				s.prev = t.prev
+				s.next = t.next
+				if s.prev != nil {
+					s.prev.parent = s
+				}
+				if s.next != nil {
+					s.next.parent = s
+				}
+				// Add t first in s's wait list.
+				s.waitlink = t
+				s.waittail = t.waittail
+				if s.waittail == nil {
+					s.waittail = t
+				}
+				t.parent = nil
+				t.prev = nil
+				t.next = nil
+				t.waittail = nil
+			} else {
+				// Add s to end of t's wait list.
+				if t.waittail == nil {
+					t.waitlink = s
+				} else {
+					t.waittail.waitlink = s
+				}
+				t.waittail = s
+				s.waitlink = nil
+			}
+			return
+		}
+		last = t
+		if uintptr(unsafe.Pointer(addr)) < uintptr(t.elem) {
+			pt = &t.prev
+		} else {
+			pt = &t.next
+		}
+	}
+
+	// Add s as new leaf in tree of unique addrs.
+	// The balanced tree is a treap using ticket as the random heap priority.
+	// That is, it is a binary tree ordered according to the elem addresses,
+	// but then among the space of possible binary trees respecting those
+	// addresses, it is kept balanced on average by maintaining a heap ordering
+	// on the ticket: s.ticket <= both s.prev.ticket and s.next.ticket.
+	// https://en.wikipedia.org/wiki/Treap
+	// http://faculty.washington.edu/aragon/pubs/rst89.pdf
+	s.ticket = fastrand()
+	s.parent = last
+	*pt = s
+
+	// Rotate up into tree according to ticket (priority).
+	for s.parent != nil && s.parent.ticket > s.ticket {
+		if s.parent.prev == s {
+			root.rotateRight(s.parent)
+		} else {
+			if s.parent.next != s {
+				panic("semaRoot queue")
+			}
+			root.rotateLeft(s.parent)
+		}
 	}
-	root.tail = s
 }
 
-func (root *semaRoot) dequeue(s *sudog) {
-	if s.next != nil {
-		s.next.prev = s.prev
-	} else {
-		root.tail = s.prev
+// dequeue searches for and finds the first goroutine
+// in semaRoot blocked on addr.
+// If the sudog was being profiled, dequeue returns the time
+// at which it was woken up as now. Otherwise now is 0.
+func (root *semaRoot) dequeue(addr *uint32) (found *sudog, now int64) {
+	ps := &root.treap
+	s := *ps
+	for ; s != nil; s = *ps {
+		if s.elem == unsafe.Pointer(addr) {
+			goto Found
+		}
+		if uintptr(unsafe.Pointer(addr)) < uintptr(s.elem) {
+			ps = &s.prev
+		} else {
+			ps = &s.next
+		}
 	}
-	if s.prev != nil {
-		s.prev.next = s.next
+	return nil, 0
+
+Found:
+	now = int64(0)
+	if s.acquiretime != 0 {
+		now = cputicks()
+	}
+	if t := s.waitlink; t != nil {
+		// Substitute t, also waiting on addr, for s in root tree of unique addrs.
+		*ps = t
+		t.ticket = s.ticket
+		t.parent = s.parent
+		t.prev = s.prev
+		if t.prev != nil {
+			t.prev.parent = t
+		}
+		t.next = s.next
+		if t.next != nil {
+			t.next.parent = t
+		}
+		if t.waitlink != nil {
+			t.waittail = s.waittail
+		} else {
+			t.waittail = nil
+		}
+		t.acquiretime = now
+		s.waitlink = nil
+		s.waittail = nil
 	} else {
-		root.head = s.next
+		// Rotate s down to be leaf of tree for removal, respecting priorities.
+		for s.next != nil || s.prev != nil {
+			if s.next == nil || s.prev != nil && s.prev.ticket < s.next.ticket {
+				root.rotateRight(s)
+			} else {
+				root.rotateLeft(s)
+			}
+		}
+		// Remove s, now a leaf.
+		if s.parent != nil {
+			if s.parent.prev == s {
+				s.parent.prev = nil
+			} else {
+				s.parent.next = nil
+			}
+		} else {
+			root.treap = nil
+		}
 	}
+	s.parent = nil
 	s.elem = nil
 	s.next = nil
 	s.prev = nil
+	s.ticket = 0
+	return s, now
+}
+
+// rotateLeft rotates the tree rooted at node x.
+// turning (x a (y b c)) into (y (x a b) c).
+func (root *semaRoot) rotateLeft(x *sudog) {
+	// p -> (x a (y b c))
+	p := x.parent
+	a, y := x.prev, x.next
+	b, c := y.prev, y.next
+
+	y.prev = x
+	x.parent = y
+	y.next = c
+	if c != nil {
+		c.parent = y
+	}
+	x.prev = a
+	if a != nil {
+		a.parent = x
+	}
+	x.next = b
+	if b != nil {
+		b.parent = x
+	}
+
+	y.parent = p
+	if p == nil {
+		root.treap = y
+	} else if p.prev == x {
+		p.prev = y
+	} else {
+		if p.next != x {
+			throw("semaRoot rotateLeft")
+		}
+		p.next = y
+	}
+}
+
+// rotateRight rotates the tree rooted at node y.
+// turning (y (x a b) c) into (x a (y b c)).
+func (root *semaRoot) rotateRight(y *sudog) {
+	// p -> (y (x a b) c)
+	p := y.parent
+	x, c := y.prev, y.next
+	a, b := x.prev, x.next
+
+	x.prev = a
+	if a != nil {
+		a.parent = x
+	}
+	x.next = y
+	y.parent = x
+	y.prev = b
+	if b != nil {
+		b.parent = y
+	}
+	y.next = c
+	if c != nil {
+		c.parent = y
+	}
+
+	x.parent = p
+	if p == nil {
+		root.treap = x
+	} else if p.prev == y {
+		p.prev = x
+	} else {
+		if p.next != y {
+			throw("semaRoot rotateRight")
+		}
+		p.next = x
+	}
 }
 
 // notifyList is a ticket-based notification list used to implement sync.Cond.
@@ -352,10 +561,22 @@ func notifyListNotifyOne(l *notifyList) {
 		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.
+	// Update the next notify ticket number.
 	atomic.Store(&l.notify, t+1)
+
+	// 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.
+	//
+	// This scan looks linear but essentially always stops quickly.
+	// Because g's queue separately from taking numbers,
+	// there may be minor reorderings in the list, but we
+	// expect the g we're looking for to be near the front.
+	// The g has others in front of it on the list only to the
+	// extent that it lost the race, so the iteration will not
+	// be too long. This applies even when the g is missing:
+	// it hasn't yet gotten to sleep and has lost the race to
+	// the (few) other g's that we find on the list.
 	for p, s := (*sudog)(nil), l.head; s != nil; p, s = s, s.next {
 		if s.ticket == t {
 			n := s.next
@@ -383,3 +604,8 @@ func notifyListCheck(sz uintptr) {
 		throw("bad notifyList size")
 	}
 }
+
+//go:linkname sync_nanotime sync.runtime_nanotime
+func sync_nanotime() int64 {
+	return nanotime()
+}
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
index 8807552..416c7c2 100644
--- a/src/runtime/signal_386.go
+++ b/src/runtime/signal_386.go
@@ -60,7 +60,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// but we do recognize the top pointer on the stack as code,
 	// then assume this was a call to non-code and treat like
 	// pc == 0, to make unwinding show the context.
-	if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
index c8a6513..fad5fc0 100644
--- a/src/runtime/signal_amd64x.go
+++ b/src/runtime/signal_amd64x.go
@@ -71,7 +71,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// but we do recognize the top pointer on the stack as code,
 	// then assume this was a call to non-code and treat like
 	// pc == 0, to make unwinding show the context.
-	if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(*(*uintptr)(unsafe.Pointer(sp))).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index 9748544..d00b225 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -57,7 +57,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// but we do recognize the link register as code,
 	// then assume this was a call to non-code and treat like
 	// pc == 0, to make unwinding show the context.
-	if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index 4c6df42..1db0525 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.go
@@ -73,7 +73,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// but we do recognize the link register as code,
 	// then assume this was a call to non-code and treat like
 	// pc == 0, to make unwinding show the context.
-	if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.lr())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go
index de71ee9..a31f436 100644
--- a/src/runtime/signal_linux_s390x.go
+++ b/src/runtime/signal_linux_s390x.go
@@ -103,7 +103,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// 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 {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go
index 973ec2d..9546a5a 100644
--- a/src/runtime/signal_mips64x.go
+++ b/src/runtime/signal_mips64x.go
@@ -77,7 +77,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// 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 {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go
index 62df79c..1c545ec 100644
--- a/src/runtime/signal_mipsx.go
+++ b/src/runtime/signal_mipsx.go
@@ -74,7 +74,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// 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 {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
index f09f890..03cb996 100644
--- a/src/runtime/signal_ppc64x.go
+++ b/src/runtime/signal_ppc64x.go
@@ -78,7 +78,7 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
 	// 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 {
+	if pc != 0 && !findfunc(pc).valid() && findfunc(uintptr(c.link())).valid() {
 		pc = 0
 	}
 
diff --git a/src/runtime/signal_sighandler.go b/src/runtime/signal_sighandler.go
index 758e42f..b2e15a6 100644
--- a/src/runtime/signal_sighandler.go
+++ b/src/runtime/signal_sighandler.go
@@ -111,7 +111,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 
 	if docrash {
 		crashing++
-		if crashing < sched.mcount {
+		if crashing < sched.mcount-int32(extraMCount) {
 			// 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
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 49c7579..539b165 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -7,6 +7,7 @@
 package runtime
 
 import (
+	"runtime/internal/atomic"
 	"runtime/internal/sys"
 	"unsafe"
 )
@@ -31,11 +32,18 @@ const (
 // Stores the signal handlers registered before Go installed its own.
 // These signal handlers will be invoked in cases where Go doesn't want to
 // handle a particular signal (e.g., signal occurred on a non-Go thread).
-// See sigfwdgo() for more information on when the signals are forwarded.
+// See sigfwdgo for more information on when the signals are forwarded.
 //
-// Signal forwarding is currently available only on Darwin and Linux.
+// This is read by the signal handler; accesses should use
+// atomic.Loaduintptr and atomic.Storeuintptr.
 var fwdSig [_NSIG]uintptr
 
+// handlingSig is indexed by signal number and is non-zero if we are
+// currently handling the signal. Or, to put it another way, whether
+// the signal handler is currently set to the Go signal handler or not.
+// This is uint32 rather than bool so that we can use atomic instructions.
+var handlingSig [_NSIG]uint32
+
 // channels for synchronizing signal mask updates with the signal mask
 // thread
 var (
@@ -76,6 +84,9 @@ func initsig(preinit bool) {
 		if t.flags == 0 || t.flags&_SigDefault != 0 {
 			continue
 		}
+
+		// We don't need to use atomic operations here because
+		// there shouldn't be any other goroutines running yet.
 		fwdSig[i] = getsig(i)
 
 		if !sigInstallGoHandler(i) {
@@ -87,7 +98,7 @@ func initsig(preinit bool) {
 			continue
 		}
 
-		t.flags |= _SigHandling
+		handlingSig[i] = 1
 		setsig(i, funcPC(sighandler))
 	}
 }
@@ -100,7 +111,7 @@ func sigInstallGoHandler(sig uint32) bool {
 	// Even these signals can be fetched using the os/signal package.
 	switch sig {
 	case _SIGHUP, _SIGINT:
-		if fwdSig[sig] == _SIG_IGN {
+		if atomic.Loaduintptr(&fwdSig[sig]) == _SIG_IGN {
 			return false
 		}
 	}
@@ -111,37 +122,52 @@ func sigInstallGoHandler(sig uint32) bool {
 	}
 
 	// When built using c-archive or c-shared, only install signal
-	// handlers for synchronous signals.
-	if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
+	// handlers for synchronous signals and SIGPIPE.
+	if (isarchive || islibrary) && t.flags&_SigPanic == 0 && sig != _SIGPIPE {
 		return false
 	}
 
 	return true
 }
 
+// sigenable enables the Go signal handler to catch the signal sig.
+// It is only called while holding the os/signal.handlers lock,
+// via os/signal.enableSignal and signal_enable.
 func sigenable(sig uint32) {
 	if sig >= uint32(len(sigtable)) {
 		return
 	}
 
+	// SIGPROF is handled specially for profiling.
+	if sig == _SIGPROF {
+		return
+	}
+
 	t := &sigtable[sig]
 	if t.flags&_SigNotify != 0 {
 		ensureSigM()
 		enableSigChan <- sig
 		<-maskUpdatedChan
-		if t.flags&_SigHandling == 0 {
-			t.flags |= _SigHandling
-			fwdSig[sig] = getsig(sig)
+		if atomic.Cas(&handlingSig[sig], 0, 1) {
+			atomic.Storeuintptr(&fwdSig[sig], getsig(sig))
 			setsig(sig, funcPC(sighandler))
 		}
 	}
 }
 
+// sigdisable disables the Go signal handler for the signal sig.
+// It is only called while holding the os/signal.handlers lock,
+// via os/signal.disableSignal and signal_disable.
 func sigdisable(sig uint32) {
 	if sig >= uint32(len(sigtable)) {
 		return
 	}
 
+	// SIGPROF is handled specially for profiling.
+	if sig == _SIGPROF {
+		return
+	}
+
 	t := &sigtable[sig]
 	if t.flags&_SigNotify != 0 {
 		ensureSigM()
@@ -152,25 +178,71 @@ func sigdisable(sig uint32) {
 		// signal, then to go back to the state before Notify
 		// we should remove the one we installed.
 		if !sigInstallGoHandler(sig) {
-			t.flags &^= _SigHandling
-			setsig(sig, fwdSig[sig])
+			atomic.Store(&handlingSig[sig], 0)
+			setsig(sig, atomic.Loaduintptr(&fwdSig[sig]))
 		}
 	}
 }
 
+// sigignore ignores the signal sig.
+// It is only called while holding the os/signal.handlers lock,
+// via os/signal.ignoreSignal and signal_ignore.
 func sigignore(sig uint32) {
 	if sig >= uint32(len(sigtable)) {
 		return
 	}
 
+	// SIGPROF is handled specially for profiling.
+	if sig == _SIGPROF {
+		return
+	}
+
 	t := &sigtable[sig]
 	if t.flags&_SigNotify != 0 {
-		t.flags &^= _SigHandling
+		atomic.Store(&handlingSig[sig], 0)
 		setsig(sig, _SIG_IGN)
 	}
 }
 
-func resetcpuprofiler(hz int32) {
+// clearSignalHandlers clears all signal handlers that are not ignored
+// back to the default. This is called by the child after a fork, so that
+// we can enable the signal mask for the exec without worrying about
+// running a signal handler in the child.
+//go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {
+	for i := uint32(0); i < _NSIG; i++ {
+		if atomic.Load(&handlingSig[i]) != 0 {
+			setsig(i, _SIG_DFL)
+		}
+	}
+}
+
+// setProcessCPUProfiler is called when the profiling timer changes.
+// It is called with prof.lock held. hz is the new timer, and is 0 if
+// profiling is being disabled. Enable or disable the signal as
+// required for -buildmode=c-archive.
+func setProcessCPUProfiler(hz int32) {
+	if hz != 0 {
+		// Enable the Go signal handler if not enabled.
+		if atomic.Cas(&handlingSig[_SIGPROF], 0, 1) {
+			atomic.Storeuintptr(&fwdSig[_SIGPROF], getsig(_SIGPROF))
+			setsig(_SIGPROF, funcPC(sighandler))
+		}
+	} else {
+		// If the Go signal handler should be disabled by default,
+		// disable it if it is enabled.
+		if !sigInstallGoHandler(_SIGPROF) {
+			if atomic.Cas(&handlingSig[_SIGPROF], 1, 0) {
+				setsig(_SIGPROF, atomic.Loaduintptr(&fwdSig[_SIGPROF]))
+			}
+		}
+	}
+}
+
+// setThreadCPUProfiler makes any thread-specific changes required to
+// implement profiling at a rate of hz.
+func setThreadCPUProfiler(hz int32) {
 	var it itimerval
 	if hz == 0 {
 		setitimer(_ITIMER_PROF, &it, nil)
@@ -252,6 +324,11 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
 	}
 
 	setg(g.m.gsignal)
+
+	if g.stackguard0 == stackFork {
+		signalDuringFork(sig)
+	}
+
 	c := &sigctxt{info, ctx}
 	c.fixsigcode(sig)
 	sighandler(sig, info, ctx, g)
@@ -348,7 +425,7 @@ func raisebadsignal(sig uint32, c *sigctxt) {
 	if sig >= _NSIG {
 		handler = _SIG_DFL
 	} else {
-		handler = fwdSig[sig]
+		handler = atomic.Loaduintptr(&fwdSig[sig])
 	}
 
 	// Reset the signal handler and raise the signal.
@@ -463,6 +540,16 @@ func sigNotOnStack(sig uint32) {
 	throw("non-Go code set up signal handler without SA_ONSTACK flag")
 }
 
+// signalDuringFork is called if we receive a signal while doing a fork.
+// We do not want signals at that time, as a signal sent to the process
+// group may be delivered to the child process, causing confusion.
+// This should never be called, because we block signals across the fork;
+// this function is just a safety check. See issue 18600 for background.
+func signalDuringFork(sig uint32) {
+	println("signal", sig, "received during fork")
+	throw("signal received during fork")
+}
+
 // This runs on a foreign stack, without an m or a g. No stack split.
 //go:nosplit
 //go:norace
@@ -490,7 +577,7 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
 	if sig >= uint32(len(sigtable)) {
 		return false
 	}
-	fwdFn := fwdSig[sig]
+	fwdFn := atomic.Loaduintptr(&fwdSig[sig])
 
 	if !signalsOK {
 		// The only way we can get here is if we are in a
@@ -505,35 +592,44 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
 		return true
 	}
 
-	flags := sigtable[sig].flags
-
 	// If there is no handler to forward to, no need to forward.
 	if fwdFn == _SIG_DFL {
 		return false
 	}
 
 	// If we aren't handling the signal, forward it.
-	if flags&_SigHandling == 0 {
+	// Really if we aren't handling the signal, we shouldn't get here,
+	// but on Darwin setsigstack can lead us here because it sets
+	// the sa_tramp field. The sa_tramp field is not returned by
+	// sigaction, so the fix for that is non-obvious.
+	if atomic.Load(&handlingSig[sig]) == 0 {
 		sigfwd(fwdFn, sig, info, ctx)
 		return true
 	}
 
-	// Only forward synchronous signals.
+	flags := sigtable[sig].flags
+
 	c := &sigctxt{info, ctx}
-	if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+	// Only forward synchronous signals and SIGPIPE.
+	// Unfortunately, user generated SIGPIPEs will also be forwarded, because si_code
+	// is set to _SI_USER even for a SIGPIPE raised from a write to a closed socket
+	// or pipe.
+	if (c.sigcode() == _SI_USER || flags&_SigPanic == 0) && sig != _SIGPIPE {
 		return false
 	}
 	// Determine if the signal occurred inside Go code. We test that:
 	//   (1) we were in a goroutine (i.e., m.curg != nil), and
-	//   (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+	//   (2) we weren't in CGO.
 	g := getg()
-	if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+	if g != nil && g.m != nil && g.m.curg != nil && !g.m.incgo {
 		return false
 	}
+
 	// Signal not handled by Go, forward it.
 	if fwdFn != _SIG_IGN {
 		sigfwd(fwdFn, sig, info, ctx)
 	}
+
 	return true
 }
 
@@ -645,7 +741,6 @@ type gsignalStack struct {
 	stack       stack
 	stackguard0 uintptr
 	stackguard1 uintptr
-	stackAlloc  uintptr
 	stktopsp    uintptr
 }
 
@@ -662,7 +757,6 @@ func setGsignalStack(st *stackt, old *gsignalStack) {
 		old.stack = g.m.gsignal.stack
 		old.stackguard0 = g.m.gsignal.stackguard0
 		old.stackguard1 = g.m.gsignal.stackguard1
-		old.stackAlloc = g.m.gsignal.stackAlloc
 		old.stktopsp = g.m.gsignal.stktopsp
 	}
 	stsp := uintptr(unsafe.Pointer(st.ss_sp))
@@ -670,7 +764,6 @@ func setGsignalStack(st *stackt, old *gsignalStack) {
 	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
 }
 
 // restoreGsignalStack restores the gsignal stack to the value it had
@@ -682,7 +775,6 @@ func restoreGsignalStack(st *gsignalStack) {
 	gp.stack = st.stack
 	gp.stackguard0 = st.stackguard0
 	gp.stackguard1 = st.stackguard1
-	gp.stackAlloc = st.stackAlloc
 	gp.stktopsp = st.stktopsp
 }
 
diff --git a/src/runtime/sizeclasses.go b/src/runtime/sizeclasses.go
index e616e95..5366564 100644
--- a/src/runtime/sizeclasses.go
+++ b/src/runtime/sizeclasses.go
@@ -1,4 +1,4 @@
-// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT
+// Code generated by mksizeclasses.go; DO NOT EDIT.
 //go:generate go run mksizeclasses.go
 
 package runtime
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
index 3cbb4b3..8519f4c 100644
--- a/src/runtime/softfloat_arm.go
+++ b/src/runtime/softfloat_arm.go
@@ -653,3 +653,8 @@ func sfloat2(pc uint32, regs *[15]uint32) uint32 {
 	}
 	return pc
 }
+
+// Stubs to pacify vet. Not safe to call from Go.
+// Calls to these functions are inserted by the compiler.
+func _sfloat()
+func udiv()
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 0f1a5c1..525d0b1 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -102,15 +102,6 @@ const (
 	_StackLimit = _StackGuard - _StackSystem - _StackSmall
 )
 
-// Goroutine preemption request.
-// Stored into g->stackguard0 to cause split stack check failure.
-// Must be greater than any real sp.
-// 0xfffffade in hex.
-const (
-	_StackPreempt = uintptrMask & -1314
-	_StackFork    = uintptrMask & -1234
-)
-
 const (
 	// stackDebug == 0: no logging
 	//            == 1: logging of per-stack operations
@@ -121,8 +112,7 @@ const (
 	stackFromSystem  = 0 // allocate stacks from system memory instead of the heap
 	stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free
 	stackPoisonCopy  = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
-
-	stackCache = 1
+	stackNoCache     = 0 // disable per-P small stack caches
 
 	// check the BP links during traceback.
 	debugCheckBP = false
@@ -186,30 +176,31 @@ func stackpoolalloc(order uint8) gclinkptr {
 	s := list.first
 	if s == nil {
 		// no free stacks. Allocate another span worth.
-		s = mheap_.allocStack(_StackCacheSize >> _PageShift)
+		s = mheap_.allocManual(_StackCacheSize>>_PageShift, &memstats.stacks_inuse)
 		if s == nil {
 			throw("out of memory")
 		}
 		if s.allocCount != 0 {
 			throw("bad allocCount")
 		}
-		if s.stackfreelist.ptr() != nil {
-			throw("bad stackfreelist")
+		if s.manualFreeList.ptr() != nil {
+			throw("bad manualFreeList")
 		}
-		for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
+		s.elemsize = _FixedStack << order
+		for i := uintptr(0); i < _StackCacheSize; i += s.elemsize {
 			x := gclinkptr(s.base() + i)
-			x.ptr().next = s.stackfreelist
-			s.stackfreelist = x
+			x.ptr().next = s.manualFreeList
+			s.manualFreeList = x
 		}
 		list.insert(s)
 	}
-	x := s.stackfreelist
+	x := s.manualFreeList
 	if x.ptr() == nil {
 		throw("span has no free stacks")
 	}
-	s.stackfreelist = x.ptr().next
+	s.manualFreeList = x.ptr().next
 	s.allocCount++
-	if s.stackfreelist.ptr() == nil {
+	if s.manualFreeList.ptr() == nil {
 		// all stacks in s are allocated.
 		list.remove(s)
 	}
@@ -219,15 +210,15 @@ func stackpoolalloc(order uint8) gclinkptr {
 // 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 {
+	if s.state != _MSpanManual {
 		throw("freeing stack not in a stack span")
 	}
-	if s.stackfreelist.ptr() == nil {
+	if s.manualFreeList.ptr() == nil {
 		// s will now have a free stack
 		stackpool[order].insert(s)
 	}
-	x.ptr().next = s.stackfreelist
-	s.stackfreelist = x
+	x.ptr().next = s.manualFreeList
+	s.manualFreeList = x
 	s.allocCount--
 	if gcphase == _GCoff && s.allocCount == 0 {
 		// Span is completely free. Return it to the heap
@@ -246,8 +237,8 @@ func stackpoolfree(x gclinkptr, order uint8) {
 		//
 		// By not freeing, we prevent step #4 until GC is done.
 		stackpool[order].remove(s)
-		s.stackfreelist = 0
-		mheap_.freeStack(s)
+		s.manualFreeList = 0
+		mheap_.freeManual(s, &memstats.stacks_inuse)
 	}
 }
 
@@ -320,7 +311,7 @@ func stackcache_clear(c *mcache) {
 // resources and must not split the stack.
 //
 //go:systemstack
-func stackalloc(n uint32) (stack, []stkbar) {
+func stackalloc(n uint32) stack {
 	// Stackalloc must be called on scheduler stack, so that we
 	// never try to grow the stack during the code that stackalloc runs.
 	// Doing so would cause a deadlock (issue 1547).
@@ -335,28 +326,20 @@ func stackalloc(n uint32) (stack, []stkbar) {
 		print("stackalloc ", n, "\n")
 	}
 
-	// Compute the size of stack barrier array.
-	maxstkbar := gcMaxStackBarriers(int(n))
-	nstkbar := unsafe.Sizeof(stkbar{}) * uintptr(maxstkbar)
-	var stkbarSlice slice
-
 	if debug.efence != 0 || stackFromSystem != 0 {
-		v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys)
+		n = uint32(round(uintptr(n), physPageSize))
+		v := sysAlloc(uintptr(n), &memstats.stacks_sys)
 		if v == nil {
 			throw("out of memory (stackalloc)")
 		}
-		top := uintptr(n) - nstkbar
-		if maxstkbar != 0 {
-			stkbarSlice = slice{add(v, top), 0, maxstkbar}
-		}
-		return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+		return stack{uintptr(v), uintptr(v) + uintptr(n)}
 	}
 
 	// Small stacks are allocated with a fixed-size free-list allocator.
 	// If we need a stack of a bigger size, we fall back on allocating
 	// a dedicated span.
 	var v unsafe.Pointer
-	if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+	if n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
 		order := uint8(0)
 		n2 := n
 		for n2 > _FixedStack {
@@ -365,7 +348,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
 		}
 		var x gclinkptr
 		c := thisg.m.mcache
-		if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
+		if stackNoCache != 0 || c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
 			// c == nil can happen in the guts of exitsyscall or
 			// procresize. Just get a stack from the global pool.
 			// Also don't touch stackcache during gc
@@ -398,10 +381,11 @@ func stackalloc(n uint32) (stack, []stkbar) {
 
 		if s == nil {
 			// Allocate a new stack from the heap.
-			s = mheap_.allocStack(npage)
+			s = mheap_.allocManual(npage, &memstats.stacks_inuse)
 			if s == nil {
 				throw("out of memory")
 			}
+			s.elemsize = uintptr(n)
 		}
 		v = unsafe.Pointer(s.base())
 	}
@@ -415,11 +399,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
 	if stackDebug >= 1 {
 		print("  allocated ", v, "\n")
 	}
-	top := uintptr(n) - nstkbar
-	if maxstkbar != 0 {
-		stkbarSlice = slice{add(v, top), 0, maxstkbar}
-	}
-	return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+	return stack{uintptr(v), uintptr(v) + uintptr(n)}
 }
 
 // stackfree frees an n byte stack allocation at stk.
@@ -428,9 +408,10 @@ func stackalloc(n uint32) (stack, []stkbar) {
 // resources and must not split the stack.
 //
 //go:systemstack
-func stackfree(stk stack, n uintptr) {
+func stackfree(stk stack) {
 	gp := getg()
 	v := unsafe.Pointer(stk.lo)
+	n := stk.hi - stk.lo
 	if n&(n-1) != 0 {
 		throw("stack not a power of 2")
 	}
@@ -452,7 +433,7 @@ func stackfree(stk stack, n uintptr) {
 	if msanenabled {
 		msanfree(v, n)
 	}
-	if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+	if n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
 		order := uint8(0)
 		n2 := n
 		for n2 > _FixedStack {
@@ -461,7 +442,7 @@ func stackfree(stk stack, n uintptr) {
 		}
 		x := gclinkptr(v)
 		c := gp.m.mcache
-		if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
+		if stackNoCache != 0 || c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
 			lock(&stackpoolmu)
 			stackpoolfree(x, order)
 			unlock(&stackpoolmu)
@@ -475,14 +456,14 @@ func stackfree(stk stack, n uintptr) {
 		}
 	} else {
 		s := mheap_.lookup(v)
-		if s.state != _MSpanStack {
+		if s.state != _MSpanManual {
 			println(hex(s.base()), v)
 			throw("bad span state")
 		}
 		if gcphase == _GCoff {
 			// Free the stack immediately if we're
 			// sweeping.
-			mheap_.freeStack(s)
+			mheap_.freeManual(s, &memstats.stacks_inuse)
 		} else {
 			// If the GC is running, we can't return a
 			// stack span to the heap because it could be
@@ -581,7 +562,7 @@ func ptrbit(bv *gobitvector, i uintptr) uint8 {
 
 // bv describes the memory starting at address scanp.
 // Adjust any pointers contained therein.
-func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
+func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f funcInfo) {
 	bv := gobv(*cbv)
 	minp := adjinfo.old.lo
 	maxp := adjinfo.old.hi
@@ -601,7 +582,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
 			pp := (*uintptr)(add(scanp, i*sys.PtrSize))
 		retry:
 			p := *pp
-			if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
+			if f.valid() && 0 < p && p < minLegalPointer && debug.invalidptr != 0 {
 				// Looks like a junk value in a pointer slot.
 				// Live analysis wrong?
 				getg().m.traceback = 2
@@ -725,7 +706,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
 		if stackDebug >= 3 {
 			print("      args\n")
 		}
-		adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
+		adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, funcInfo{})
 	}
 	return true
 }
@@ -774,12 +755,6 @@ func adjustsudogs(gp *g, adjinfo *adjustinfo) {
 	}
 }
 
-func adjuststkbar(gp *g, adjinfo *adjustinfo) {
-	for i := int(gp.stkbarPos); i < len(gp.stkbar); i++ {
-		adjustpointer(adjinfo, unsafe.Pointer(&gp.stkbar[i].savedLRPtr))
-	}
-}
-
 func fillstack(stk stack, b byte) {
 	for p := stk.lo; p < stk.hi; p++ {
 		*(*byte)(unsafe.Pointer(p)) = b
@@ -866,12 +841,12 @@ func copystack(gp *g, newsize uintptr, sync bool) {
 	used := old.hi - gp.sched.sp
 
 	// allocate new stack
-	new, newstkbar := stackalloc(uint32(newsize))
+	new := stackalloc(uint32(newsize))
 	if stackPoisonCopy != 0 {
 		fillstack(new, 0xfd)
 	}
 	if stackDebug >= 1 {
-		print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", gp.stackAlloc, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
+		print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]", " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
 	}
 
 	// Compute adjustment.
@@ -900,44 +875,30 @@ func copystack(gp *g, newsize uintptr, sync bool) {
 	// 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)
-	adjuststkbar(gp, &adjinfo)
 	if adjinfo.sghi != 0 {
 		adjinfo.sghi += adjinfo.delta
 	}
 
-	// copy old stack barriers to new stack barrier array
-	newstkbar = newstkbar[:len(gp.stkbar)]
-	copy(newstkbar, gp.stkbar)
-
 	// Swap out old stack for new one
 	gp.stack = new
 	gp.stackguard0 = new.lo + _StackGuard // NOTE: might clobber a preempt request
 	gp.sched.sp = new.hi - used
-	oldsize := gp.stackAlloc
-	gp.stackAlloc = newsize
-	gp.stkbar = newstkbar
 	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
 	if stackPoisonCopy != 0 {
 		fillstack(old, 0xfc)
 	}
-	stackfree(old, oldsize)
+	stackfree(old)
 }
 
 // round x up to a power of 2.
@@ -1082,9 +1043,9 @@ func newstack(ctxt unsafe.Pointer) {
 	}
 
 	// Allocate a bigger segment and move the stack.
-	oldsize := int(gp.stackAlloc)
+	oldsize := gp.stack.hi - gp.stack.lo
 	newsize := oldsize * 2
-	if uintptr(newsize) > maxstacksize {
+	if newsize > maxstacksize {
 		print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
 		throw("stack overflow")
 	}
@@ -1095,7 +1056,7 @@ func newstack(ctxt unsafe.Pointer) {
 
 	// 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), true)
+	copystack(gp, newsize, true)
 	if stackDebug >= 1 {
 		print("stack grow done\n")
 	}
@@ -1129,11 +1090,9 @@ func shrinkstack(gp *g) {
 		if gp.stack.lo != 0 {
 			// Free whole stack - it will get reallocated
 			// if G is used again.
-			stackfree(gp.stack, gp.stackAlloc)
+			stackfree(gp.stack)
 			gp.stack.lo = 0
 			gp.stack.hi = 0
-			gp.stkbar = nil
-			gp.stkbarPos = 0
 		}
 		return
 	}
@@ -1153,7 +1112,7 @@ func shrinkstack(gp *g) {
 		return
 	}
 
-	oldsize := gp.stackAlloc
+	oldsize := gp.stack.hi - gp.stack.lo
 	newsize := oldsize / 2
 	// Don't shrink the allocation below the minimum-sized stack
 	// allocation.
@@ -1197,8 +1156,8 @@ func freeStackSpans() {
 			next := s.next
 			if s.allocCount == 0 {
 				list.remove(s)
-				s.stackfreelist = 0
-				mheap_.freeStack(s)
+				s.manualFreeList = 0
+				mheap_.freeManual(s, &memstats.stacks_inuse)
 			}
 			s = next
 		}
@@ -1212,7 +1171,7 @@ func freeStackSpans() {
 		for s := stackLarge.free[i].first; s != nil; {
 			next := s.next
 			stackLarge.free[i].remove(s)
-			mheap_.freeStack(s)
+			mheap_.freeManual(s, &memstats.stacks_inuse)
 			s = next
 		}
 	}
@@ -1222,6 +1181,6 @@ func freeStackSpans() {
 //go:nosplit
 func morestackc() {
 	systemstack(func() {
-		throw("attempt to execute C code on Go stack")
+		throw("attempt to execute system stack code on user stack")
 	})
 }
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go
index a32b68b..485e327 100644
--- a/src/runtime/stack_test.go
+++ b/src/runtime/stack_test.go
@@ -8,6 +8,7 @@ import (
 	. "runtime"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"testing"
 	"time"
 )
@@ -97,9 +98,11 @@ func TestStackGrowth(t *testing.T) {
 	go func() {
 		defer wg.Done()
 		done := make(chan bool)
+		var started uint32
 		go func() {
 			s := new(string)
 			SetFinalizer(s, func(ss *string) {
+				atomic.StoreUint32(&started, 1)
 				growStack()
 				done <- true
 			})
@@ -111,6 +114,9 @@ func TestStackGrowth(t *testing.T) {
 		select {
 		case <-done:
 		case <-time.After(20 * time.Second):
+			if atomic.LoadUint32(&started) == 0 {
+				t.Log("finalizer did not start")
+			}
 			t.Error("finalizer did not run")
 			return
 		}
@@ -315,17 +321,17 @@ func TestPanicFar(t *testing.T) {
 	defer func() {
 		// At this point we created a large stack and unwound
 		// it via recovery. Force a stack walk, which will
-		// check the consistency of stack barriers.
+		// check the stack's consistency.
 		Callers(0, pc)
 	}()
 	defer func() {
 		recover()
 	}()
 	useStackAndCall(100, func() {
-		// Kick off the GC and make it do something nontrivial
-		// to keep stack barriers installed for a while.
+		// Kick off the GC and make it do something nontrivial.
+		// (This used to force stack barriers to stick around.)
 		xtree = makeTree(18)
-		// Give the GC time to install stack barriers.
+		// Give the GC time to start scanning stacks.
 		time.Sleep(time.Millisecond)
 		panic(1)
 	})
@@ -447,3 +453,175 @@ func count(n int) int {
 	}
 	return 1 + count(n-1)
 }
+
+func BenchmarkStackCopyNoCache(b *testing.B) {
+	c := make(chan bool)
+	for i := 0; i < b.N; i++ {
+		go func() {
+			count1(1000000)
+			c <- true
+		}()
+		<-c
+	}
+}
+
+func count1(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count2(n-1)
+}
+
+func count2(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count3(n-1)
+}
+
+func count3(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count4(n-1)
+}
+
+func count4(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count5(n-1)
+}
+
+func count5(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count6(n-1)
+}
+
+func count6(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count7(n-1)
+}
+
+func count7(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count8(n-1)
+}
+
+func count8(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count9(n-1)
+}
+
+func count9(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count10(n-1)
+}
+
+func count10(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count11(n-1)
+}
+
+func count11(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count12(n-1)
+}
+
+func count12(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count13(n-1)
+}
+
+func count13(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count14(n-1)
+}
+
+func count14(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count15(n-1)
+}
+
+func count15(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count16(n-1)
+}
+
+func count16(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count17(n-1)
+}
+
+func count17(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count18(n-1)
+}
+
+func count18(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count19(n-1)
+}
+
+func count19(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count20(n-1)
+}
+
+func count20(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count21(n-1)
+}
+
+func count21(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count22(n-1)
+}
+
+func count22(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count23(n-1)
+}
+
+func count23(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count1(n-1)
+}
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 822adaa..0ccc81e 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -69,7 +69,7 @@ func concatstring5(buf *tmpBuf, a [5]string) string {
 
 // Buf is a fixed-size buffer for the result,
 // it is not nil if the result does not escape.
-func slicebytetostring(buf *tmpBuf, b []byte) string {
+func slicebytetostring(buf *tmpBuf, b []byte) (str string) {
 	l := len(b)
 	if l == 0 {
 		// Turns out to be a relatively common case.
@@ -77,18 +77,26 @@ func slicebytetostring(buf *tmpBuf, b []byte) string {
 		// you find the indices and convert the subslice to string.
 		return ""
 	}
-	if raceenabled && l > 0 {
+	if raceenabled {
 		racereadrangepc(unsafe.Pointer(&b[0]),
 			uintptr(l),
 			getcallerpc(unsafe.Pointer(&buf)),
 			funcPC(slicebytetostring))
 	}
-	if msanenabled && l > 0 {
+	if msanenabled {
 		msanread(unsafe.Pointer(&b[0]), uintptr(l))
 	}
-	s, c := rawstringtmp(buf, l)
-	copy(c, b)
-	return s
+
+	var p unsafe.Pointer
+	if buf != nil && len(b) <= len(buf) {
+		p = unsafe.Pointer(buf)
+	} else {
+		p = mallocgc(uintptr(len(b)), nil, false)
+	}
+	stringStructOf(&str).str = p
+	stringStructOf(&str).len = len(b)
+	memmove(p, (*(*slice)(unsafe.Pointer(&b))).array, uintptr(len(b)))
+	return
 }
 
 // stringDataOnStack reports whether the string's data is
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index fcfc522..7633cfd 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -6,6 +6,7 @@ package runtime_test
 
 import (
 	"runtime"
+	"strconv"
 	"strings"
 	"testing"
 )
@@ -89,6 +90,20 @@ func BenchmarkConcatStringAndBytes(b *testing.B) {
 	}
 }
 
+var escapeString string
+
+func BenchmarkSliceByteToString(b *testing.B) {
+	buf := []byte{'!'}
+	for n := 0; n < 8; n++ {
+		b.Run(strconv.Itoa(len(buf)), func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				escapeString = string(buf)
+			}
+		})
+		buf = append(buf, buf...)
+	}
+}
+
 var stringdata = []struct{ name, data string }{
 	{"ASCII", "01234567890"},
 	{"Japanese", "日本語日本語日本語"},
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 107f260..c4f32a8 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -93,8 +93,22 @@ func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
 // exported value for testing
 var hashLoad = loadFactor
 
-// in asm_*.s
-func fastrand() uint32
+//go:nosplit
+func fastrand() uint32 {
+	mp := getg().m
+	fr := mp.fastrand
+	mx := uint32(int32(fr)>>31) & 0xa8888eef
+	fr = fr<<1 ^ mx
+	mp.fastrand = fr
+	return fr
+}
+
+//go:nosplit
+func fastrandn(n uint32) uint32 {
+	// This is similar to fastrand() % n, but faster.
+	// See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+	return uint32(uint64(fastrand()) * uint64(n) >> 32)
+}
 
 //go:linkname sync_fastrand sync.fastrand
 func sync_fastrand() uint32 { return fastrand() }
@@ -150,7 +164,7 @@ type neverCallThisFunction struct{}
 // This function must never be called directly. Call goexit1 instead.
 // gentraceback assumes that goexit terminates the stack. A direct
 // call on the stack will cause gentraceback to stop walking the stack
-// prematurely and if there are leftover stack barriers it may panic.
+// prematurely and if there is leftover state it may panic.
 func goexit(neverCallThisFunction)
 
 // Not all cgocallback_gofunc frames are actually cgocallback_gofunc,
@@ -178,9 +192,6 @@ func cgocallback_gofunc(fv uintptr, frame uintptr, framesize, ctxt uintptr)
 // data dependency ordering.
 func publicationBarrier()
 
-//go:noescape
-func setcallerpc(argp unsafe.Pointer, pc uintptr)
-
 // getcallerpc returns the program counter (PC) of its caller's caller.
 // getcallersp returns the stack pointer (SP) of its caller's caller.
 // For both, the argp must be a pointer to the caller's first function argument.
@@ -227,13 +238,6 @@ func morestack()
 func morestack_noctxt()
 func rt0_go()
 
-// stackBarrier records that the stack has been unwound past a certain
-// point. It is installed over a return PC on the stack. It must
-// retrieve the original return PC from g.stkbuf, increment
-// g.stkbufPos to record that the barrier was hit, and jump to the
-// original return PC.
-func stackBarrier()
-
 // return0 is a stub used to return 0 from deferproc.
 // It is called at the very end of deferproc to signal
 // the calling Go function that it should not jump
@@ -241,9 +245,6 @@ func stackBarrier()
 // in asm_*.s
 func return0()
 
-//go:linkname time_now time.now
-func time_now() (sec int64, nsec int32)
-
 // in asm_*.s
 // not called directly; definitions here supply type information for traceback.
 func call32(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
@@ -280,11 +281,6 @@ func prefetcht1(addr uintptr)
 func prefetcht2(addr uintptr)
 func prefetchnta(addr uintptr)
 
-func unixnanotime() int64 {
-	sec, nsec := time_now()
-	return sec*1e9 + int64(nsec)
-}
-
 // round n up to a multiple of a.  a must be a power of 2.
 func round(n, a uintptr) uintptr {
 	return (n + a - 1) &^ (a - 1)
@@ -295,3 +291,10 @@ func checkASM() bool
 
 func memequal_varlen(a, b unsafe.Pointer) bool
 func eqstring(s1, s2 string) bool
+
+// bool2int returns 0 if x is false or 1 if x is true.
+func bool2int(x bool) int {
+	// Avoid branches. In the SSA compiler, this compiles to
+	// exactly what you would want it to.
+	return int(uint8(*(*uint8)(unsafe.Pointer(&x))))
+}
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
index 95db924..8390d8f 100644
--- a/src/runtime/stubs2.go
+++ b/src/runtime/stubs2.go
@@ -18,8 +18,6 @@ func exit(code int32)
 func nanotime() int64
 func usleep(usec uint32)
 
-func munmap(addr unsafe.Pointer, n uintptr)
-
 //go:noescape
 func write(fd uintptr, p unsafe.Pointer, n int32) int32
 
diff --git a/src/runtime/stubs_linux.go b/src/runtime/stubs_linux.go
new file mode 100644
index 0000000..d10f657
--- /dev/null
+++ b/src/runtime/stubs_linux.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package runtime
+
+func sbrk0() uintptr
diff --git a/src/runtime/stubs_nonlinux.go b/src/runtime/stubs_nonlinux.go
new file mode 100644
index 0000000..e1ea05c
--- /dev/null
+++ b/src/runtime/stubs_nonlinux.go
@@ -0,0 +1,12 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !linux
+
+package runtime
+
+// sbrk0 returns the current process brk, or 0 if not implemented.
+func sbrk0() uintptr {
+	return 0
+}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index ed82783..029c2f1 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -13,108 +13,268 @@ import (
 // Frames may be used to get function/file/line information for a
 // slice of PC values returned by Callers.
 type Frames struct {
+	// callers is a slice of PCs that have not yet been expanded.
 	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
+	// stackExpander expands callers into a sequence of Frames,
+	// tracking the necessary state across PCs.
+	stackExpander stackExpander
 }
 
 // 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 is the program counter for the location in this frame.
+	// For a frame that calls another frame, this will be the
+	// program counter of a call instruction. Because of inlining,
+	// multiple frames may have the same PC value, but different
+	// symbolic information.
 	PC uintptr
 
-	// Func for this frame; may be nil for non-Go code or fully
-	// inlined functions.
+	// Func is the Func value of this call frame. This 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.
+	// Function is the package path-qualified function name of
+	// this call frame. If non-empty, this string uniquely
+	// identifies a single function in the program.
+	// This may be the empty string 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().
+	// File and Line are the file name and line number of the
+	// location in this frame. For non-leaf frames, this will be
+	// the location of a call. These may be the empty string and
+	// zero, respectively, if not known.
+	File string
+	Line int
+
+	// Entry point program counter for the function; may be zero
+	// if not known. If Func is not nil then Entry ==
+	// Func.Entry().
 	Entry uintptr
 }
 
+// stackExpander expands a call stack of PCs into a sequence of
+// Frames. It tracks state across PCs necessary to perform this
+// expansion.
+//
+// This is the core of the Frames implementation, but is a separate
+// internal API to make it possible to use within the runtime without
+// heap-allocating the PC slice. The only difference with the public
+// Frames API is that the caller is responsible for threading the PC
+// slice between expansion steps in this API. If escape analysis were
+// smarter, we may not need this (though it may have to be a lot
+// smarter).
+type stackExpander struct {
+	// pcExpander expands the current PC into a sequence of Frames.
+	pcExpander pcExpander
+
+	// If previous caller in iteration was a panic, then the next
+	// PC in the call stack is the address of the faulting
+	// instruction instead of the return address of the call.
+	wasPanic bool
+
+	// skip > 0 indicates that skip frames in the expansion of the
+	// first PC should be skipped over and callers[1] should also
+	// be skipped.
+	skip int
+}
+
 // 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}
+	ci := &Frames{}
+	ci.callers = ci.stackExpander.init(callers)
+	return ci
+}
+
+func (se *stackExpander) init(callers []uintptr) []uintptr {
+	if len(callers) >= 1 {
+		pc := callers[0]
+		s := pc - skipPC
+		if s >= 0 && s < sizeofSkipFunction {
+			// Ignore skip frame callers[0] since this means the caller trimmed the PC slice.
+			return callers[1:]
+		}
+	}
+	if len(callers) >= 2 {
+		pc := callers[1]
+		s := pc - skipPC
+		if s > 0 && s < sizeofSkipFunction {
+			// Skip the first s inlined frames when we expand the first PC.
+			se.skip = int(s)
+		}
+	}
+	return 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:]
+	ci.callers, frame, more = ci.stackExpander.next(ci.callers)
+	return
+}
+
+func (se *stackExpander) next(callers []uintptr) (ncallers []uintptr, frame Frame, more bool) {
+	ncallers = callers
+	if !se.pcExpander.more {
+		// Expand the next PC.
+		if len(ncallers) == 0 {
+			se.wasPanic = false
+			return ncallers, Frame{}, false
+		}
+		se.pcExpander.init(ncallers[0], se.wasPanic)
+		ncallers = ncallers[1:]
+		se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
+		if se.skip > 0 {
+			for ; se.skip > 0; se.skip-- {
+				se.pcExpander.next()
+			}
+			se.skip = 0
+			// Drop skipPleaseUseCallersFrames.
+			ncallers = ncallers[1:]
+		}
+		if !se.pcExpander.more {
+			// No symbolic information for this PC.
+			// However, we return at least one frame for
+			// every PC, so return an invalid frame.
+			return ncallers, Frame{}, len(ncallers) > 0
 		}
-		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
+	frame = se.pcExpander.next()
+	return ncallers, frame, se.pcExpander.more || len(ncallers) > 0
+}
+
+// A pcExpander expands a single PC into a sequence of Frames.
+type pcExpander struct {
+	// more indicates that the next call to next will return a
+	// valid frame.
+	more bool
+
+	// pc is the pc being expanded.
+	pc uintptr
+
+	// frames is a pre-expanded set of Frames to return from the
+	// iterator. If this is set, then this is everything that will
+	// be returned from the iterator.
+	frames []Frame
+
+	// funcInfo is the funcInfo of the function containing pc.
+	funcInfo funcInfo
+
+	// inlTree is the inlining tree of the function containing pc.
+	inlTree *[1 << 20]inlinedCall
+
+	// file and line are the file name and line number of the next
+	// frame.
+	file string
+	line int32
+
+	// inlIndex is the inlining index of the next frame, or -1 if
+	// the next frame is an outermost frame.
+	inlIndex int32
+}
+
+// init initializes this pcExpander to expand pc. It sets ex.more if
+// pc expands to any Frames.
+//
+// A pcExpander can be reused by calling init again.
+//
+// If pc was a "call" to sigpanic, panicCall should be true. In this
+// case, pc is treated as the address of a faulting instruction
+// instead of the return address of a call.
+func (ex *pcExpander) init(pc uintptr, panicCall bool) {
+	ex.more = false
+
+	ex.funcInfo = findfunc(pc)
+	if !ex.funcInfo.valid() {
 		if cgoSymbolizer != nil {
-			return ci.cgoNext(pc, more)
+			// Pre-expand cgo frames. We could do this
+			// incrementally, too, but there's no way to
+			// avoid allocation in this case anyway.
+			ex.frames = expandCgoFrames(pc)
+			ex.more = len(ex.frames) > 0
 		}
-		return Frame{}, more
+		return
 	}
 
-	entry := f.Entry()
-	xpc := pc
-	if xpc > entry && !ci.wasPanic {
-		xpc--
+	ex.more = true
+	entry := ex.funcInfo.entry
+	ex.pc = pc
+	if ex.pc > entry && !panicCall {
+		ex.pc--
 	}
-	file, line := f.FileLine(xpc)
 
-	function := f.Name()
-	ci.wasPanic = entry == sigpanicPC
+	// file and line are the innermost position at pc.
+	ex.file, ex.line = funcline1(ex.funcInfo, ex.pc, false)
+
+	// Get inlining tree at pc
+	inldata := funcdata(ex.funcInfo, _FUNCDATA_InlTree)
+	if inldata != nil {
+		ex.inlTree = (*[1 << 20]inlinedCall)(inldata)
+		ex.inlIndex = pcdatavalue(ex.funcInfo, _PCDATA_InlTreeIndex, ex.pc, nil)
+	} else {
+		ex.inlTree = nil
+		ex.inlIndex = -1
+	}
+}
 
-	frame = Frame{
-		PC:       xpc,
-		Func:     f,
-		Function: function,
-		File:     file,
-		Line:     line,
-		Entry:    entry,
+// next returns the next Frame in the expansion of pc and sets ex.more
+// if there are more Frames to follow.
+func (ex *pcExpander) next() Frame {
+	if !ex.more {
+		return Frame{}
 	}
 
-	return frame, more
+	if len(ex.frames) > 0 {
+		// Return pre-expended frame.
+		frame := ex.frames[0]
+		ex.frames = ex.frames[1:]
+		ex.more = len(ex.frames) > 0
+		return frame
+	}
+
+	if ex.inlIndex >= 0 {
+		// Return inner inlined frame.
+		call := ex.inlTree[ex.inlIndex]
+		frame := Frame{
+			PC:       ex.pc,
+			Func:     nil, // nil for inlined functions
+			Function: funcnameFromNameoff(ex.funcInfo, call.func_),
+			File:     ex.file,
+			Line:     int(ex.line),
+			Entry:    ex.funcInfo.entry,
+		}
+		ex.file = funcfile(ex.funcInfo, call.file)
+		ex.line = call.line
+		ex.inlIndex = call.parent
+		return frame
+	}
+
+	// No inlining or pre-expanded frames.
+	ex.more = false
+	return Frame{
+		PC:       ex.pc,
+		Func:     ex.funcInfo._Func(),
+		Function: funcname(ex.funcInfo),
+		File:     ex.file,
+		Line:     int(ex.line),
+		Entry:    ex.funcInfo.entry,
+	}
 }
 
-// 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) {
+// expandCgoFrames expands frame information for pc, known to be
+// a non-Go function, using the cgoSymbolizer hook. expandCgoFrames
+// returns nil if pc could not be expanded.
+func expandCgoFrames(pc uintptr) []Frame {
 	arg := cgoSymbolizerArg{pc: pc}
 	callCgoSymbolizer(&arg)
 
 	if arg.file == nil && arg.funcName == nil {
 		// No useful information from symbolizer.
-		return Frame{}, more
+		return nil
 	}
 
 	var frames []Frame
@@ -140,24 +300,14 @@ func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
 	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
+	return frames
 }
 
 // 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{}.
-// All code operating on a *Func must call raw to get the *_func instead.
+// All code operating on a *Func must call raw() to get the *_func
+// or funcInfo() to get the funcInfo instead.
 
 // A Func represents a Go function in the running binary.
 type Func struct {
@@ -168,11 +318,20 @@ func (f *Func) raw() *_func {
 	return (*_func)(unsafe.Pointer(f))
 }
 
-// funcdata.h
+func (f *Func) funcInfo() funcInfo {
+	fn := f.raw()
+	return funcInfo{fn, findmoduledatap(fn.entry)}
+}
+
+// PCDATA and FUNCDATA table indexes.
+//
+// See funcdata.h and ../cmd/internal/obj/funcdata.go.
 const (
 	_PCDATA_StackMapIndex       = 0
+	_PCDATA_InlTreeIndex        = 1
 	_FUNCDATA_ArgsPointerMaps   = 0
 	_FUNCDATA_LocalsPointerMaps = 1
+	_FUNCDATA_InlTree           = 2
 	_ArgsSizeUnknown            = -0x80000000
 )
 
@@ -361,15 +520,15 @@ func moduledataverify1(datap *moduledata) {
 	for i := 0; i < nftab; i++ {
 		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
 		if datap.ftab[i].entry > datap.ftab[i+1].entry {
-			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
-			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+			f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
+			f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
 			f2name := "end"
 			if i+1 < nftab {
 				f2name = funcname(f2)
 			}
 			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
 			for j := 0; j <= i; j++ {
-				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
+				print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
 			}
 			throw("invalid runtime symbol table")
 		}
@@ -382,10 +541,10 @@ func moduledataverify1(datap *moduledata) {
 			// But don't use the next PC if it corresponds to a foreign object chunk
 			// (no pcln table, f2.pcln == 0). That chunk might have an alignment
 			// more than 16 bytes.
-			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
+			f := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
 			end := f.entry
 			if i+1 < nftab {
-				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+				f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
 				if f2.pcln != 0 {
 					end = f2.entry - 16
 					if end < f.entry {
@@ -415,12 +574,12 @@ func moduledataverify1(datap *moduledata) {
 // FuncForPC returns a *Func describing the function that contains the
 // given program counter address, or else nil.
 func FuncForPC(pc uintptr) *Func {
-	return (*Func)(unsafe.Pointer(findfunc(pc)))
+	return findfunc(pc)._Func()
 }
 
 // Name returns the name of the function.
 func (f *Func) Name() string {
-	return funcname(f.raw())
+	return funcname(f.funcInfo())
 }
 
 // Entry returns the entry address of the function.
@@ -435,7 +594,7 @@ func (f *Func) Entry() uintptr {
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
 	// Pass strict=false here, because anyone can call this function,
 	// and they might just be wrong about targetpc belonging to f.
-	file, line32 := funcline1(f.raw(), pc, false)
+	file, line32 := funcline1(f.funcInfo(), pc, false)
 	return file, int(line32)
 }
 
@@ -448,10 +607,23 @@ func findmoduledatap(pc uintptr) *moduledata {
 	return nil
 }
 
-func findfunc(pc uintptr) *_func {
+type funcInfo struct {
+	*_func
+	datap *moduledata
+}
+
+func (f funcInfo) valid() bool {
+	return f._func != nil
+}
+
+func (f funcInfo) _Func() *Func {
+	return (*Func)(unsafe.Pointer(f._func))
+}
+
+func findfunc(pc uintptr) funcInfo {
 	datap := findmoduledatap(pc)
 	if datap == nil {
-		return nil
+		return funcInfo{}
 	}
 	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
@@ -487,7 +659,7 @@ func findfunc(pc uintptr) *_func {
 			idx++
 		}
 	}
-	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
+	return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
 }
 
 type pcvalueCache struct {
@@ -502,7 +674,7 @@ type pcvalueCacheEnt struct {
 	val int32
 }
 
-func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
+func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
 	if off == 0 {
 		return -1
 	}
@@ -514,26 +686,27 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
 	// cheaper than doing the hashing for a less associative
 	// cache.
 	if cache != nil {
-		for _, ent := range cache.entries {
+		for i := range cache.entries {
 			// We check off first because we're more
 			// likely to have multiple entries with
 			// different offsets for the same targetpc
 			// than the other way around, so we'll usually
 			// fail in the first clause.
+			ent := &cache.entries[i]
 			if ent.off == off && ent.targetpc == targetpc {
 				return ent.val
 			}
 		}
 	}
 
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
+	if !f.valid() {
 		if strict && panicking == 0 {
 			print("runtime: no module data for ", hex(f.entry), "\n")
 			throw("no module data")
 		}
 		return -1
 	}
+	datap := f.datap
 	p := datap.pclntable[off:]
 	pc := f.entry
 	val := int32(-1)
@@ -549,7 +722,7 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
 			// a recursive stack's cycle is slightly
 			// larger than the cache.
 			if cache != nil {
-				ci := fastrand() % uint32(len(cache.entries))
+				ci := fastrandn(uint32(len(cache.entries)))
 				cache.entries[ci] = pcvalueCacheEnt{
 					targetpc: targetpc,
 					off:      off,
@@ -585,24 +758,37 @@ func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict
 	return -1
 }
 
-func cfuncname(f *_func) *byte {
-	if f == nil || f.nameoff == 0 {
+func cfuncname(f funcInfo) *byte {
+	if !f.valid() || f.nameoff == 0 {
 		return nil
 	}
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
-		return nil
-	}
-	return &datap.pclntable[f.nameoff]
+	return &f.datap.pclntable[f.nameoff]
 }
 
-func funcname(f *_func) string {
+func funcname(f funcInfo) string {
 	return gostringnocopy(cfuncname(f))
 }
 
-func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
+func funcnameFromNameoff(f funcInfo, nameoff int32) string {
+	datap := f.datap
+	if !f.valid() {
+		return ""
+	}
+	cstr := &datap.pclntable[nameoff]
+	return gostringnocopy(cstr)
+}
+
+func funcfile(f funcInfo, fileno int32) string {
+	datap := f.datap
+	if !f.valid() {
+		return "?"
+	}
+	return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
+}
+
+func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
+	datap := f.datap
+	if !f.valid() {
 		return "?", 0
 	}
 	fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
@@ -615,11 +801,11 @@ func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32
 	return
 }
 
-func funcline(f *_func, targetpc uintptr) (file string, line int32) {
+func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
 	return funcline1(f, targetpc, true)
 }
 
-func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
+func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
 	x := pcvalue(f, f.pcsp, targetpc, cache, true)
 	if x&(sys.PtrSize-1) != 0 {
 		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
@@ -627,7 +813,7 @@ func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
 	return x
 }
 
-func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
+func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
 	if table < 0 || table >= f.npcdata {
 		return -1
 	}
@@ -635,14 +821,14 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) i
 	return pcvalue(f, off, targetpc, cache, true)
 }
 
-func funcdata(f *_func, i int32) unsafe.Pointer {
+func funcdata(f funcInfo, i int32) unsafe.Pointer {
 	if i < 0 || i >= f.nfuncdata {
 		return nil
 	}
 	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
 	if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
-		if uintptr(unsafe.Pointer(f))&4 != 0 {
-			println("runtime: misaligned func", f)
+		if uintptr(unsafe.Pointer(f._func))&4 != 0 {
+			println("runtime: misaligned func", f._func)
 		}
 		p = add(p, 4)
 	}
@@ -651,35 +837,47 @@ func funcdata(f *_func, i int32) unsafe.Pointer {
 
 // step advances to the next pc, value pair in the encoded table.
 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
-	p, uvdelta := readvarint(p)
+	// For both uvdelta and pcdelta, the common case (~70%)
+	// is that they are a single byte. If so, avoid calling readvarint.
+	uvdelta := uint32(p[0])
 	if uvdelta == 0 && !first {
 		return nil, false
 	}
+	n := uint32(1)
+	if uvdelta&0x80 != 0 {
+		n, uvdelta = readvarint(p)
+	}
+	p = p[n:]
 	if uvdelta&1 != 0 {
 		uvdelta = ^(uvdelta >> 1)
 	} else {
 		uvdelta >>= 1
 	}
 	vdelta := int32(uvdelta)
-	p, pcdelta := readvarint(p)
+	pcdelta := uint32(p[0])
+	n = 1
+	if pcdelta&0x80 != 0 {
+		n, pcdelta = readvarint(p)
+	}
+	p = p[n:]
 	*pc += uintptr(pcdelta * sys.PCQuantum)
 	*val += vdelta
 	return p, true
 }
 
 // readvarint reads a varint from p.
-func readvarint(p []byte) (newp []byte, val uint32) {
-	var v, shift uint32
+func readvarint(p []byte) (read uint32, val uint32) {
+	var v, shift, n uint32
 	for {
-		b := p[0]
-		p = p[1:]
-		v |= (uint32(b) & 0x7F) << shift
+		b := p[n]
+		n++
+		v |= uint32(b&0x7F) << (shift & 31)
 		if b&0x80 == 0 {
 			break
 		}
 		shift += 7
 	}
-	return p, v
+	return n, v
 }
 
 type stackmap struct {
@@ -693,5 +891,13 @@ func stackmapdata(stkmap *stackmap, n int32) bitvector {
 	if n < 0 || n >= stkmap.n {
 		throw("stackmapdata: index out of range")
 	}
-	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)/8))))}
+	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)>>3))))}
+}
+
+// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
+type inlinedCall struct {
+	parent int32 // index of parent in the inltree, or < 0
+	file   int32 // fileno index into filetab
+	line   int32 // line number of the call site
+	func_  int32 // offset into pclntab for name of called function
 }
diff --git a/src/runtime/symtab_test.go b/src/runtime/symtab_test.go
index b15a2e9..57642a4 100644
--- a/src/runtime/symtab_test.go
+++ b/src/runtime/symtab_test.go
@@ -26,10 +26,14 @@ func TestCaller(t *testing.T) {
 	}
 }
 
+// These are marked noinline so that we can use FuncForPC
+// in testCallerBar.
+//go:noinline
 func testCallerFoo(t *testing.T) {
 	testCallerBar(t)
 }
 
+//go:noinline
 func testCallerBar(t *testing.T) {
 	for i := 0; i < 2; i++ {
 		pc, file, line, ok := runtime.Caller(i)
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index 200961f..5c62bfd 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -114,6 +114,16 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
 // 64-bit unix nanoseconds returned in DX:AX.
 // I'd much rather write this in C but we need
 // assembly for the 96-bit multiply and RDTSC.
+//
+// Note that we could arrange to return monotonic time here
+// as well, but we don't bother, for two reasons:
+// 1. macOS only supports 64-bit systems, so no one should
+// be using the 32-bit code in production.
+// This code is only maintained to make it easier for developers
+// using Macs to test the 32-bit compiler.
+// 2. On some (probably now unsupported) CPUs,
+// the code falls back to the system call always,
+// so it can't even use the comm page at all. 
 TEXT runtime·now(SB),NOSPLIT,$40
 	MOVL	$0xffff0000, BP /* comm page base */
 	
@@ -217,9 +227,15 @@ inreg:
 	ADCL	$0, DX
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$0
+// func now() (sec int64, nsec int32, mono uint64)
+TEXT time·now(SB),NOSPLIT,$0-20
 	CALL	runtime·now(SB)
+	MOVL	AX, BX
+	MOVL	DX, BP
+	SUBL	runtime·startNano(SB), BX
+	SBBL	runtime·startNano+4(SB), BP
+	MOVL	BX, mono+12(FP)
+	MOVL	BP, mono+16(FP)
 	MOVL	$1000000000, CX
 	DIVL	CX
 	MOVL	AX, sec+0(FP)
@@ -230,6 +246,8 @@ TEXT time·now(SB),NOSPLIT,$0
 // func nanotime() int64
 TEXT runtime·nanotime(SB),NOSPLIT,$0
 	CALL	runtime·now(SB)
+	SUBL	runtime·startNano(SB), AX
+	SBBL	runtime·startNano+4(SB), DX
 	MOVL	AX, ret_lo+0(FP)
 	MOVL	DX, ret_hi+4(FP)
 	RET
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 96fa5b9..a8dc700 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -117,14 +117,44 @@ TEXT runtime·madvise(SB), NOSPLIT, $0
 #define	gtod_ns_base	0x70
 #define	gtod_sec_base	0x78
 
-TEXT nanotime<>(SB), NOSPLIT, $32
+TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+	MOVQ	$0x7fffffe00000, BP	/* comm page base */
+	// Loop trying to take a consistent snapshot
+	// of the time parameters.
+timeloop:
+	MOVL	nt_generation(BP), R9
+	TESTL	R9, R9
+	JZ	timeloop
+	RDTSC
+	MOVQ	nt_tsc_base(BP), R10
+	MOVL	nt_scale(BP), R11
+	MOVQ	nt_ns_base(BP), R12
+	CMPL	nt_generation(BP), R9
+	JNE	timeloop
+
+	// Gathered all the data we need. Compute monotonic time:
+	//	((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base
+	// The multiply and shift extracts the top 64 bits of the 96-bit product.
+	SHLQ	$32, DX
+	ADDQ	DX, AX
+	SUBQ	R10, AX
+	MULQ	R11
+	SHRQ	$32, AX:DX
+	ADDQ	R12, AX
+	MOVQ	runtime·startNano(SB), CX
+	SUBQ	CX, AX
+	MOVQ	AX, ret+0(FP)
+	RET
+
+TEXT time·now(SB), NOSPLIT, $32-24
+	// Note: The 32 bytes of stack frame requested on the TEXT line
+	// are used in the systime fallback, as the timeval address
+	// filled in by the system call.
 	MOVQ	$0x7fffffe00000, BP	/* comm page base */
 	// Loop trying to take a consistent snapshot
 	// of the time parameters.
 timeloop:
 	MOVL	gtod_generation(BP), R8
-	TESTL	R8, R8
-	JZ	systime
 	MOVL	nt_generation(BP), R9
 	TESTL	R9, R9
 	JZ	timeloop
@@ -139,8 +169,8 @@ timeloop:
 	CMPL	gtod_generation(BP), R8
 	JNE	timeloop
 
-	// Gathered all the data we need. Compute time.
-	//	((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9
+	// Gathered all the data we need. Compute:
+	//	monotonic_time = ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base
 	// The multiply and shift extracts the top 64 bits of the 96-bit product.
 	SHLQ	$32, DX
 	ADDQ	DX, AX
@@ -148,9 +178,33 @@ timeloop:
 	MULQ	R11
 	SHRQ	$32, AX:DX
 	ADDQ	R12, AX
+	MOVQ	AX, BX
+	MOVQ	runtime·startNano(SB), CX
+	SUBQ	CX, BX
+	MOVQ	BX, monotonic+16(FP)
+
+	// Compute:
+	//	wall_time = monotonic time - gtod_ns_base + gtod_sec_base*1e9
+	// or, if gtod_generation==0, invoke the system call.
+	TESTL	R8, R8
+	JZ	systime
 	SUBQ	R13, AX
 	IMULQ	$1000000000, R14
 	ADDQ	R14, AX
+
+	// Split wall time into sec, nsec.
+	// generated code for
+	//	func f(x uint64) (uint64, uint64) { return x/1e9, x%1e9 }
+	// adapted to reduce duplication
+	MOVQ	AX, CX
+	SHRQ	$9, AX
+	MOVQ	$19342813113834067, DX
+	MULQ	DX
+	SHRQ	$11, DX
+	MOVQ	DX, sec+0(FP)
+	IMULQ	$1000000000, DX
+	SUBQ	DX, CX
+	MOVL	CX, nsec+8(FP)
 	RET
 
 systime:
@@ -166,34 +220,9 @@ systime:
 	MOVL	8(SP), DX
 inreg:
 	// sec is in AX, usec in DX
-	// return nsec in AX
-	IMULQ	$1000000000, AX
 	IMULQ	$1000, DX
-	ADDQ	DX, AX
-	RET
-
-TEXT runtime·nanotime(SB),NOSPLIT,$0-8
-	CALL	nanotime<>(SB)
-	MOVQ	AX, ret+0(FP)
-	RET
-
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$0-12
-	CALL	nanotime<>(SB)
-
-	// generated code for
-	//	func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
-	// adapted to reduce duplication
-	MOVQ	AX, CX
-	MOVQ	$1360296554856532783, AX
-	MULQ	CX
-	ADDQ	CX, DX
-	RCRQ	$1, DX
-	SHRQ	$29, DX
-	MOVQ	DX, sec+0(FP)
-	IMULQ	$1000000000, DX
-	SUBQ	DX, CX
-	MOVL	CX, nsec+8(FP)
+	MOVQ	AX, sec+0(FP)
+	MOVL	DX, nsec+8(FP)
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
@@ -231,14 +260,15 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
 	POPQ	BP
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$32
+TEXT runtime·sigtramp(SB),NOSPLIT,$40
 	MOVL SI, 24(SP) // save infostyle for sigreturn below
+	MOVQ R8, 32(SP) // save ctx
 	MOVL DX, 0(SP)  // sig
 	MOVQ CX, 8(SP)  // info
 	MOVQ R8, 16(SP) // ctx
 	MOVQ $runtime·sigtrampgo(SB), AX
 	CALL AX
-	MOVQ 16(SP), DI // ctx
+	MOVQ 32(SP), DI // ctx
 	MOVL 24(SP), SI // infostyle
 	MOVL $(0x2000000+184), AX
 	SYSCALL
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 2c03c91..ea559b5 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -159,7 +159,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT time·now(SB), 7, $32
+TEXT runtime·walltime(SB), 7, $32
 	MOVW	$8(R13), R0  // timeval
 	MOVW	$0, R1  // zone
 	MOVW	$0, R2	// see issue 16570
@@ -171,9 +171,9 @@ TEXT time·now(SB), 7, $32
 	MOVW	12(R13), R1
 inreg:
 	MOVW    R1, R2  // usec
-	MOVW	R0, sec+0(FP)
+	MOVW	R0, sec_lo+0(FP)
 	MOVW	$0, R1
-	MOVW	R1, loc+4(FP)
+	MOVW	R1, sec_hi+4(FP)
 	MOVW	$1000, R3
 	MUL	R3, R2
 	MOVW	R2, nsec+8(FP)
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index c02d000..0e91d5b 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -151,7 +151,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
 	SVC	$0x80
 	RET
 
-TEXT time·now(SB),NOSPLIT,$40-12
+TEXT runtime·walltime(SB),NOSPLIT,$40-12
 	MOVD	RSP, R0	// timeval
 	MOVD	R0, R9	// this is how dyld calls gettimeofday
 	MOVW	$0, R1	// zone
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index b950b69..f355268 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -148,8 +148,8 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	SYSCALL
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVL	$232, AX // clock_gettime
 	MOVQ	$0, DI  	// CLOCK_REALTIME
 	LEAQ	8(SP), SI
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index 8b6ee1f..0f5df21 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -159,8 +159,8 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
 	INT	$0x80
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVL	$232, AX // clock_gettime
 	LEAL	12(SP), BX
 	MOVL	$0, 4(SP)	// CLOCK_REALTIME
@@ -170,8 +170,8 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVL	16(SP), BX	// nsec
 
 	// sec is in AX, nsec in BX
-	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
+	MOVL	AX, sec_lo+0(FP)
+	MOVL	$0, sec_hi+4(FP)
 	MOVL	BX, nsec+8(FP)
 	RET
 
@@ -398,4 +398,13 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$32
 	NEGL	AX
 	RET
 
+// func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
+TEXT runtime·cpuset_getaffinity(SB), NOSPLIT, $0-28
+	MOVL	$487, AX
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	MOVL	AX, ret+24(FP)
+	RET
+
 GLOBL runtime·tlsoffset(SB),NOPTR,$4
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 158a60d..5d072a9 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -142,8 +142,8 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	SYSCALL
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVL	$232, AX // clock_gettime
 	MOVQ	$0, DI		// CLOCK_REALTIME
 	LEAQ	8(SP), SI
@@ -354,3 +354,17 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
 	MOVL	$92, AX		// fcntl
 	SYSCALL
 	RET
+
+// func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
+TEXT runtime·cpuset_getaffinity(SB), NOSPLIT, $0-44
+	MOVQ	level+0(FP), DI
+	MOVQ	which+8(FP), SI
+	MOVQ	id+16(FP), DX
+	MOVQ	size+24(FP), R10
+	MOVQ	mask+32(FP), R8
+	MOVL	$487, AX
+	SYSCALL
+	JCC	2(PC)
+	NEGQ	AX
+	MOVL	AX, ret+40(FP)
+	RET
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 3c5a5cb..2851587 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -39,8 +39,9 @@
 #define SYS_thr_kill (SYS_BASE + 433)
 #define SYS__umtx_op (SYS_BASE + 454)
 #define SYS_thr_new (SYS_BASE + 455)
-#define SYS_mmap (SYS_BASE + 477) 
-	
+#define SYS_mmap (SYS_BASE + 477)
+#define SYS_cpuset_getaffinity (SYS_BASE + 487)
+
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
 	MOVW addr+0(FP), R0
 	MOVW mode+4(FP), R1
@@ -166,8 +167,8 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	SWI $0
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVW $0, R0 // CLOCK_REALTIME
 	MOVW $8(R13), R1
 	MOVW $SYS_clock_gettime, R7
@@ -376,3 +377,17 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
 	RET
+
+// func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
+TEXT runtime·cpuset_getaffinity(SB), NOSPLIT, $0-28
+	MOVW	level+0(FP), R0
+	MOVW	which+4(FP), R1
+	MOVW	id_lo+8(FP), R2
+	MOVW	id_hi+12(FP), R3
+	ADD	$20, R13	// Pass size and mask on stack.
+	MOVW	$SYS_cpuset_getaffinity, R7
+	SWI	$0
+	RSB.CS	$0, R0
+	SUB	$20, R13
+	MOVW	R0, ret+24(FP)
+	RET
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index ba6f7cc..6061833 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -154,8 +154,8 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-16
 	MOVL	AX, ret+12(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVL	$265, AX			// syscall - clock_gettime
 	MOVL	$0, BX		// CLOCK_REALTIME
 	LEAL	8(SP), CX
@@ -165,8 +165,8 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVL	12(SP), BX	// nsec
 
 	// sec is in AX, nsec in BX
-	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
+	MOVL	AX, sec_lo+0(FP)
+	MOVL	$0, sec_hi+4(FP)
 	MOVL	BX, nsec+8(FP)
 	RET
 
@@ -599,3 +599,12 @@ TEXT runtime·socket(SB),NOSPLIT,$0-16
 	INVOKE_SYSCALL
 	MOVL	AX, ret+12(FP)
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$0-4
+	// Implemented as brk(NULL).
+	MOVL	$45, AX  // syscall - brk
+	MOVL	$0, BX  // NULL
+	INVOKE_SYSCALL
+	MOVL	AX, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 8ab8d12..e0dc3e1 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -138,8 +138,8 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-28
 	MOVL	AX, ret+24(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$16
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	// Be careful. We're calling a function with gcc calling convention here.
 	// We're guaranteed 128 bytes on entry, and we've taken 16, and the
 	// call uses another 8.
@@ -393,7 +393,7 @@ TEXT runtime·callCgoMmap(SB),NOSPLIT,$16
 	MOVQ	AX, ret+32(FP)
 	RET
 
-TEXT runtime·munmap(SB),NOSPLIT,$0
+TEXT runtime·sysMunmap(SB),NOSPLIT,$0
 	MOVQ	addr+0(FP), DI
 	MOVQ	n+8(FP), SI
 	MOVQ	$11, AX	// munmap
@@ -403,6 +403,19 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
+// Call the function stored in _cgo_munmap using the GCC calling convention.
+// This must be called on the system stack.
+TEXT runtime·callCgoMunmap(SB),NOSPLIT,$16-16
+	MOVQ	addr+0(FP), DI
+	MOVQ	n+8(FP), SI
+	MOVQ	_cgo_munmap(SB), AX
+	MOVQ	SP, BX
+	ANDQ	$~15, SP	// alignment as per amd64 psABI
+	MOVQ	BX, 0(SP)
+	CALL	AX
+	MOVQ	0(SP), SP
+	RET
+
 TEXT runtime·madvise(SB),NOSPLIT,$0
 	MOVQ	addr+0(FP), DI
 	MOVQ	n+8(FP), SI
@@ -601,3 +614,12 @@ TEXT runtime·socket(SB),NOSPLIT,$0-20
 	SYSCALL
 	MOVL	AX, ret+16(FP)
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$0-8
+	// Implemented as brk(NULL).
+	MOVQ	$0, DI
+	MOVL	$12, AX  // syscall entry
+	SYSCALL
+	MOVQ	AX, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index f21a351..64beed8 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -48,6 +48,7 @@
 #define SYS_access (SYS_BASE + 33)
 #define SYS_connect (SYS_BASE + 283)
 #define SYS_socket (SYS_BASE + 281)
+#define SYS_brk (SYS_BASE + 45)
 
 #define ARM_BASE (SYS_BASE + 0x0f0000)
 
@@ -197,7 +198,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT time·now(SB), NOSPLIT, $32
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVW	$0, R0  // CLOCK_REALTIME
 	MOVW	$8(R13), R1  // timespec
 	MOVW	$SYS_clock_gettime, R7
@@ -206,9 +207,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW	8(R13), R0  // sec
 	MOVW	12(R13), R2  // nsec
 	
-	MOVW	R0, sec+0(FP)
+	MOVW	R0, sec_lo+0(FP)
 	MOVW	$0, R1
-	MOVW	R1, loc+4(FP)
+	MOVW	R1, sec_hi+4(FP)
 	MOVW	R2, nsec+8(FP)
 	RET	
 
@@ -507,3 +508,12 @@ TEXT runtime·socket(SB),NOSPLIT,$0
 	SWI	$0
 	MOVW	R0, ret+12(FP)
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$0-4
+	// Implemented as brk(NULL).
+	MOVW	$0, R0
+	MOVW	$SYS_brk, R7
+	SWI	$0
+	MOVW	R0, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 1b91b44..e921f99 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -46,6 +46,7 @@
 #define SYS_faccessat		48
 #define SYS_socket		198
 #define SYS_connect		203
+#define SYS_brk			214
 
 TEXT runtime·exit(SB),NOSPLIT,$-8-4
 	MOVW	code+0(FP), R0
@@ -182,8 +183,8 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
 	MOVW	R0, ret+24(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$24-12
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$24-12
 	MOVW	$0, R0 // CLOCK_REALTIME
 	MOVD	RSP, R1
 	MOVD	$SYS_clock_gettime, R8
@@ -483,3 +484,12 @@ TEXT runtime·socket(SB),NOSPLIT,$0-20
 	SVC
 	MOVW	R0, ret+16(FP)
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$0-8
+	// Implemented as brk(NULL).
+	MOVD	$0, R0
+	MOVD	$SYS_brk, R8
+	SVC
+	MOVD	R0, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index 5a75bb8..27de7b0 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -45,6 +45,7 @@
 #define SYS_epoll_wait		5209
 #define SYS_clock_gettime	5222
 #define SYS_epoll_create1	5285
+#define SYS_brk			5012
 
 TEXT runtime·exit(SB),NOSPLIT,$-8-4
 	MOVW	code+0(FP), R4
@@ -172,8 +173,8 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
 	MOVW	R2, ret+24(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$16
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	MOVW	$0, R4 // CLOCK_REALTIME
 	MOVV	$0(R29), R5
 	MOVV	$SYS_clock_gettime, R2
@@ -426,3 +427,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$-8
 	MOVV	$SYS_fcntl, R2
 	SYSCALL
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$-8-8
+	// Implemented as brk(NULL).
+	MOVV	$0, R4
+	MOVV	$SYS_brk, R2
+	SYSCALL
+	MOVV	R2, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index 73ce061..39bd731 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -45,6 +45,7 @@
 #define SYS_epoll_wait		    4250
 #define SYS_clock_gettime	    4263
 #define SYS_epoll_create1	    4326
+#define SYS_brk			    4045
 
 TEXT runtime·exit(SB),NOSPLIT,$0-4
 	MOVW	code+0(FP), R4
@@ -175,8 +176,8 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-16
 	MOVW	R2, ret+12(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$8-12
 	MOVW	$0, R4	// CLOCK_REALTIME
 	MOVW	$4(R29), R5
 	MOVW	$SYS_clock_gettime, R2
@@ -323,7 +324,7 @@ TEXT runtime·futex(SB),NOSPLIT,$20-28
 	RET
 
 
-// int32 clone(int32 flags, void *stk, M *mm, G *gg, void (*fn)(void));
+// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$-4-24
 	MOVW	flags+0(FP), R4
 	MOVW	stk+4(FP), R5
@@ -335,9 +336,9 @@ TEXT runtime·clone(SB),NOSPLIT,$-4-24
 	// stack so that any syscall invoked immediately in the new thread won't fail.
 	ADD	$-32, R5
 
-	// Copy mm, gg, fn off parent stack for use by child.
-	MOVW	mm+8(FP), R16
-	MOVW	gg+12(FP), R17
+	// Copy mp, gp, fn off parent stack for use by child.
+	MOVW	mp+8(FP), R16
+	MOVW	gp+12(FP), R17
 	MOVW	fn+16(FP), R18
 
 	MOVW	$1234, R1
@@ -465,3 +466,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0-4
 	MOVW	$SYS_fcntl, R2
 	SYSCALL
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT,$0-4
+	// Implemented as brk(NULL).
+	MOVW	$0, R4
+	MOVW	$SYS_brk, R2
+	SYSCALL
+	MOVW	R2, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index a40fe3b..2b2aa61 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -21,6 +21,7 @@
 #define SYS_close		  6
 #define SYS_getpid		 20
 #define SYS_kill		 37
+#define SYS_brk			 45
 #define SYS_fcntl		 55
 #define SYS_gettimeofday	 78
 #define SYS_select		 82	// always return -ENOSYS
@@ -157,8 +158,8 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
 	MOVW	R3, ret+24(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$16
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	MOVD	$0, R3 // CLOCK_REALTIME
 	MOVD	$0(R1), R4
 	SYSCALL	$SYS_clock_gettime
@@ -189,7 +190,7 @@ TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
 	MOVW	size+24(FP), R6
 	SYSCALL	$SYS_rt_sigprocmask
 	BVC	2(PC)
-	MOVD	R0, 0xf1(R0)	// crash
+	MOVD	R0, 0xf0(R0)	// crash
 	RET
 
 TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
@@ -273,7 +274,7 @@ TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
 	MOVD	n+8(FP), R4
 	SYSCALL	$SYS_munmap
 	BVC	2(PC)
-	MOVD	R0, 0xf3(R0)
+	MOVD	R0, 0xf0(R0)
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
@@ -366,7 +367,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
 	MOVD	old+8(FP), R4
 	SYSCALL	$SYS_sigaltstack
 	BVC	2(PC)
-	MOVD	R0, 0xf1(R0)  // crash
+	MOVD	R0, 0xf0(R0)  // crash
 	RET
 
 TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
@@ -422,3 +423,11 @@ TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
 	MOVD    $1, R5  // FD_CLOEXEC
 	SYSCALL	$SYS_fcntl
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT|NOFRAME,$0
+	// Implemented as brk(NULL).
+	MOVD	$0, R3
+	SYSCALL	$SYS_brk
+	MOVD	R3, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index 47f34d9..b8099e2 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -16,6 +16,7 @@
 #define SYS_close                 6
 #define SYS_getpid               20
 #define SYS_kill                 37
+#define SYS_brk			 45
 #define SYS_fcntl                55
 #define SYS_gettimeofday         78
 #define SYS_mmap                 90
@@ -169,8 +170,8 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
 	MOVW	R2, ret+24(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$16
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	MOVW	$0, R2 // CLOCK_REALTIME
 	MOVD	$tp-16(SP), R3
 	MOVW	$SYS_clock_gettime, R1
@@ -434,3 +435,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
 	MOVW	$SYS_fcntl, R1
 	SYSCALL
 	RET
+
+// func sbrk0() uintptr
+TEXT runtime·sbrk0(SB),NOSPLIT|NOFRAME,$0-8
+	// Implemented as brk(NULL).
+	MOVD	$0, R2
+	MOVW	$SYS_brk, R1
+	SYSCALL
+	MOVD	R2, ret+0(FP)
+	RET
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index 05de20c..d945453 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -233,7 +233,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$32
 	MOVL	AX, ret+24(FP)
 	RET
 
-TEXT time·now(SB),NOSPLIT,$20
+TEXT runtime·walltime(SB),NOSPLIT,$20
 	MOVL $0, 0(SP) // real time clock
 	LEAL 8(SP), AX
 	MOVL AX, 4(SP) // timespec
@@ -243,13 +243,13 @@ TEXT time·now(SB),NOSPLIT,$20
 	MOVL 16(SP), BX // nsec
 
 	// sec is in AX, nsec in BX
-	MOVL	AX, sec+0(FP)
-	MOVL	CX, sec+4(FP)
+	MOVL	AX, sec_lo+0(FP)
+	MOVL	CX, sec_hi+4(FP)
 	MOVL	BX, nsec+8(FP)
 	RET
 
 TEXT syscall·now(SB),NOSPLIT,$0
-	JMP time·now(SB)
+	JMP runtime·walltime(SB)
 
 TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$8
 	MOVL arg1+0(FP), AX
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index c2a24e8..2a39983 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -242,7 +242,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$8
 	MOVL	AX, ret+24(FP)
 	RET
 
-TEXT time·now(SB),NOSPLIT,$16
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	MOVQ runtime·faketime(SB), AX
 	CMPQ AX, $0
 	JEQ realtime
@@ -262,13 +262,13 @@ realtime:
 	MOVL 8(SP), BX // nsec
 
 	// sec is in AX, nsec in BX
-	MOVL	AX, sec+0(FP)
-	MOVL	CX, sec+4(FP)
+	MOVL	AX, sec_lo+0(FP)
+	MOVL	CX, sec_hi+4(FP)
 	MOVL	BX, nsec+8(FP)
 	RET
 
 TEXT syscall·now(SB),NOSPLIT,$0
-	JMP time·now(SB)
+	JMP runtime·walltime(SB)
 
 TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
 	MOVL arg1+0(FP), DI
@@ -366,40 +366,40 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
 	// 136(SI) is saved EFLAGS, never to be seen again
 	JMP	SI
 
-debughandler:
-	// print basic information
-	LEAL	ctxt+0(FP), DI
-	MOVL	$runtime·sigtrampf(SB), AX
-	MOVL	AX, 0(SP)
-	MOVQ	(16*4+16*8)(DI), BX // rip
-	MOVQ	BX, 8(SP)
-	MOVQ	(16*4+0*8)(DI), BX // rax
-	MOVQ	BX, 16(SP)
-	MOVQ	(16*4+1*8)(DI), BX // rcx
-	MOVQ	BX, 24(SP)
-	MOVQ	(16*4+2*8)(DI), BX // rdx
-	MOVQ	BX, 32(SP)
-	MOVQ	(16*4+3*8)(DI), BX // rbx
-	MOVQ	BX, 40(SP)
-	MOVQ	(16*4+7*8)(DI), BX // rdi
-	MOVQ	BX, 48(SP)
-	MOVQ	(16*4+15*8)(DI), BX // r15
-	MOVQ	BX, 56(SP)
-	MOVQ	(16*4+4*8)(DI), BX // rsp
-	MOVQ	0(BX), BX
-	MOVQ	BX, 64(SP)
-	CALL	runtime·printf(SB)
-	
-	LEAL	ctxt+0(FP), DI
-	MOVQ	(16*4+16*8)(DI), BX // rip
-	MOVL	BX, 0(SP)
-	MOVQ	(16*4+4*8)(DI), BX // rsp
-	MOVL	BX, 4(SP)
-	MOVL	$0, 8(SP)	// lr
-	get_tls(CX)
-	MOVL	g(CX), BX
-	MOVL	BX, 12(SP)	// gp
-	CALL	runtime·traceback(SB)
+//debughandler:
+	//// print basic information
+	//LEAL	ctxt+0(FP), DI
+	//MOVL	$runtime·sigtrampf(SB), AX
+	//MOVL	AX, 0(SP)
+	//MOVQ	(16*4+16*8)(DI), BX // rip
+	//MOVQ	BX, 8(SP)
+	//MOVQ	(16*4+0*8)(DI), BX // rax
+	//MOVQ	BX, 16(SP)
+	//MOVQ	(16*4+1*8)(DI), BX // rcx
+	//MOVQ	BX, 24(SP)
+	//MOVQ	(16*4+2*8)(DI), BX // rdx
+	//MOVQ	BX, 32(SP)
+	//MOVQ	(16*4+3*8)(DI), BX // rbx
+	//MOVQ	BX, 40(SP)
+	//MOVQ	(16*4+7*8)(DI), BX // rdi
+	//MOVQ	BX, 48(SP)
+	//MOVQ	(16*4+15*8)(DI), BX // r15
+	//MOVQ	BX, 56(SP)
+	//MOVQ	(16*4+4*8)(DI), BX // rsp
+	//MOVQ	0(BX), BX
+	//MOVQ	BX, 64(SP)
+	//CALL	runtime·printf(SB)
+	//
+	//LEAL	ctxt+0(FP), DI
+	//MOVQ	(16*4+16*8)(DI), BX // rip
+	//MOVL	BX, 0(SP)
+	//MOVQ	(16*4+4*8)(DI), BX // rsp
+	//MOVL	BX, 4(SP)
+	//MOVL	$0, 8(SP)	// lr
+	//get_tls(CX)
+	//MOVL	g(CX), BX
+	//MOVL	BX, 12(SP)	// gp
+	//CALL	runtime·traceback(SB)
 
 notls:
 	MOVL	0, AX
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index 6cbc23f..6a6ef4e 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -196,20 +196,20 @@ TEXT runtime·mmap(SB),NOSPLIT,$8
 	MOVW	R0, ret+24(FP)
 	RET
 
-TEXT time·now(SB),NOSPLIT,$16
+TEXT runtime·walltime(SB),NOSPLIT,$16
 	MOVW	$0, R0 // real time clock
 	MOVW	$4(R13), R1
 	NACL_SYSCALL(SYS_clock_gettime)
 	MOVW	4(R13), R0 // low 32-bit sec
 	MOVW	8(R13), R1 // high 32-bit sec
 	MOVW	12(R13), R2 // nsec
-	MOVW	R0, sec+0(FP)
-	MOVW	R1, sec+4(FP)
-	MOVW	R2, sec+8(FP)
+	MOVW	R0, sec_lo+0(FP)
+	MOVW	R1, sec_hi+4(FP)
+	MOVW	R2, nsec+8(FP)
 	RET
 
 TEXT syscall·now(SB),NOSPLIT,$0
-	B time·now(SB)
+	B runtime·walltime(SB)
 
 TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
 	MOVW	arg1+0(FP), R0
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 8c4f004..742193c 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -134,8 +134,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-4
 	INT	$0x80
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	LEAL	12(SP), BX
 	MOVL	$0, 4(SP)		// arg 1 - clock_id
 	MOVL	BX, 8(SP)		// arg 2 - tp
@@ -143,9 +143,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	INT	$0x80
 
 	MOVL	12(SP), AX		// sec - l32
-	MOVL	AX, sec+0(FP)
+	MOVL	AX, sec_lo+0(FP)
 	MOVL	16(SP), AX		// sec - h32
-	MOVL	AX, sec+4(FP)
+	MOVL	AX, sec_hi+4(FP)
 
 	MOVL	20(SP), BX		// nsec
 	MOVL	BX, nsec+8(FP)
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index 7c7771b..c632a0b 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -169,8 +169,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	SYSCALL
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVQ	$0, DI			// arg 1 - clock_id
 	LEAQ	8(SP), SI		// arg 2 - tp
 	MOVL	$427, AX		// sys_clock_gettime
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index a8914c1..789b12e 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -137,8 +137,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-4
 	SWI $0xa001a9	// sys_setitimer
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVW $0, R0	// CLOCK_REALTIME
 	MOVW $8(R13), R1
 	SWI $0xa001ab	// clock_gettime
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 76d22b0..fb2a688 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -140,8 +140,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-4
 	INT	$0x80
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	LEAL	12(SP), BX
 	MOVL	$0, 4(SP)		// arg 1 - clock_id
 	MOVL	BX, 8(SP)		// arg 2 - tp
@@ -149,9 +149,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	INT	$0x80
 
 	MOVL	12(SP), AX		// sec - l32
-	MOVL	AX, sec+0(FP)
+	MOVL	AX, sec_lo+0(FP)
 	MOVL	16(SP), AX		// sec - h32
-	MOVL	AX, sec+4(FP)
+	MOVL	AX, sec_hi+4(FP)
 
 	MOVL	20(SP), BX		// nsec
 	MOVL	BX, nsec+8(FP)
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index cf7a3fb..9a52e5d 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -180,8 +180,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	SYSCALL
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVQ	$0, DI			// arg 1 - clock_id
 	LEAQ	8(SP), SI		// arg 2 - tp
 	MOVL	$87, AX			// sys_clock_gettime
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index f573a02..93a5d5b 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -150,8 +150,8 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
 	SWI	$0
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB), NOSPLIT, $32
 	MOVW	CLOCK_REALTIME, R0	// arg 1 - clock_id
 	MOVW	$8(R13), R1		// arg 2 - tp
 	MOVW	$87, R12		// sys_clock_gettime
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index 41aa2fd..688bd23 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -102,16 +102,16 @@ TEXT runtime·nsec(SB),NOSPLIT,$8
 	MOVL	$-1, ret_hi+8(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$8-12
 	CALL	runtime·nanotime(SB)
 	MOVL	0(SP), AX
 	MOVL	4(SP), DX
 
 	MOVL	$1000000000, CX
 	DIVL	CX
-	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
+	MOVL	AX, sec_lo+0(FP)
+	MOVL	$0, sec_hi+4(FP)
 	MOVL	DX, nsec+8(FP)
 	RET
 
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 149505f..d7bd92c 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -92,8 +92,8 @@ TEXT runtime·nsec(SB),NOSPLIT,$0
 	MOVQ	AX, ret+8(FP)
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$8-12
 	CALL	runtime·nanotime(SB)
 	MOVQ	0(SP), AX
 
diff --git a/src/runtime/sys_plan9_arm.s b/src/runtime/sys_plan9_arm.s
index d54f56f..94a6f63 100644
--- a/src/runtime/sys_plan9_arm.s
+++ b/src/runtime/sys_plan9_arm.s
@@ -54,21 +54,21 @@
 //func open(name *byte, mode, perm int32) int32
 TEXT runtime·open(SB),NOSPLIT,$0-16
 	MOVW    $SYS_OPEN, R0
-	SWI	0
+	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
+	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
+	SWI	$0
 	MOVW	R0, ret+20(FP)
 	RET
 
@@ -79,7 +79,7 @@ TEXT runtime·seek(SB),NOSPLIT,$0-24
 	MOVW	R0, 0(R13)
 	MOVW.W	R1, -4(R13)
 	MOVW	$SYS_SEEK, R0
-	SWI	0
+	SWI	$0
 	MOVW.W	R1, 4(R13)
 	CMP	$-1, R0
 	MOVW.EQ	R0, ret_lo+16(FP)
@@ -89,48 +89,48 @@ TEXT runtime·seek(SB),NOSPLIT,$0-24
 //func closefd(fd int32) int32
 TEXT runtime·closefd(SB),NOSPLIT,$0-8
 	MOVW	$SYS_CLOSE, R0
-	SWI	0
+	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
+	SWI	$0
 	RET
 
 //func brk_(addr unsafe.Pointer) int32
 TEXT runtime·brk_(SB),NOSPLIT,$0-8
 	MOVW    $SYS_BRK_, R0
-	SWI	0
+	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
+	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
+	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
+	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
+	SWI	$0
 	MOVW	arg+0(FP), R1
 	MOVW	0(R1), R0
 	MOVW	R0, ret_lo+4(FP)
@@ -139,12 +139,12 @@ TEXT runtime·nsec(SB),NOSPLIT,$-4-12
 	RET
 
 // time.now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$12-12
+TEXT runtime·walltime(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
+	SWI	$0
 	MOVW	sysnsec_lo-8(SP), R1	// R1:R2 = nsec
 	MOVW	sysnsec_hi-4(SP), R2
 
@@ -181,28 +181,28 @@ TEXT time·now(SB),NOSPLIT,$12-12
 //func notify(fn unsafe.Pointer) int32
 TEXT runtime·notify(SB),NOSPLIT,$0-8
 	MOVW	$SYS_NOTIFY, R0
-	SWI	0
+	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
+	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
+	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
+	SWI	$0
 	MOVW	R0, ret+4(FP)
 	RET
 
@@ -297,7 +297,7 @@ TEXT runtime·errstr(SB),NOSPLIT,$0-8
 	MOVW	$ERRMAX, R2
 	MOVW	R2, ret_len+4(FP)
 	MOVW    $SYS_ERRSTR, R0
-	SWI	0
+	SWI	$0
 	MOVW	R1, R2
 	MOVBU	0(R2), R0
 	CMP	$0, R0
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index c542db3..aeb2e2c 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -354,8 +354,8 @@ TEXT runtime·osyield1(SB),NOSPLIT,$0
 	CALL	AX
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
+// func walltime() (sec int64, nsec int32)
+TEXT runtime·walltime(SB),NOSPLIT,$8-12
 	CALL	runtime·nanotime(SB)
 	MOVQ	0(SP), AX
 
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index bd5de33..128e8ab 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -152,7 +152,7 @@ done:
 	// RET 4 (return and pop 4 bytes parameters)
 	BYTE $0xC2; WORD $4
 	RET // unreached; make assembler happy
- 
+
 TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
 	MOVL	$runtime·exceptionhandler(SB), AX
 	JMP	runtime·sigtramp(SB)
@@ -432,15 +432,113 @@ TEXT runtime·switchtothread(SB),NOSPLIT,$0
 	MOVL	BP, SP
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
-	CALL	runtime·unixnano(SB)
-	MOVL	0(SP), AX
-	MOVL	4(SP), DX
+// See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
+#define _INTERRUPT_TIME 0x7ffe0008
+#define _SYSTEM_TIME 0x7ffe0014
+#define time_lo 0
+#define time_hi1 4
+#define time_hi2 8
+
+TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+	CMPB	runtime·useQPCTime(SB), $0
+	JNE	useQPC
+loop:
+	MOVL	(_INTERRUPT_TIME+time_hi1), AX
+	MOVL	(_INTERRUPT_TIME+time_lo), CX
+	MOVL	(_INTERRUPT_TIME+time_hi2), DI
+	CMPL	AX, DI
+	JNE	loop
+
+	// wintime = DI:CX, multiply by 100
+	MOVL	$100, AX
+	MULL	CX
+	IMULL	$100, DI
+	ADDL	DI, DX
+	// wintime*100 = DX:AX, subtract startNano and return
+	SUBL	runtime·startNano+0(SB), AX
+	SBBL	runtime·startNano+4(SB), DX
+	MOVL	AX, ret_lo+0(FP)
+	MOVL	DX, ret_hi+4(FP)
+	RET
+useQPC:
+	JMP	runtime·nanotimeQPC(SB)
+	RET
 
+TEXT time·now(SB),NOSPLIT,$0-20
+	CMPB	runtime·useQPCTime(SB), $0
+	JNE	useQPC
+loop:
+	MOVL	(_INTERRUPT_TIME+time_hi1), AX
+	MOVL	(_INTERRUPT_TIME+time_lo), CX
+	MOVL	(_INTERRUPT_TIME+time_hi2), DI
+	CMPL	AX, DI
+	JNE	loop
+
+	// w = DI:CX
+	// multiply by 100
+	MOVL	$100, AX
+	MULL	CX
+	IMULL	$100, DI
+	ADDL	DI, DX
+	// w*100 = DX:AX
+	// subtract startNano and save for return
+	SUBL	runtime·startNano+0(SB), AX
+	SBBL	runtime·startNano+4(SB), DX
+	MOVL	AX, mono+12(FP)
+	MOVL	DX, mono+16(FP)
+
+wall:
+	MOVL	(_SYSTEM_TIME+time_hi1), CX
+	MOVL	(_SYSTEM_TIME+time_lo), AX
+	MOVL	(_SYSTEM_TIME+time_hi2), DX
+	CMPL	CX, DX
+	JNE	wall
+	
+	// w = DX:AX
+	// convert to Unix epoch (but still 100ns units)
+	#define delta 116444736000000000
+	SUBL	$(delta & 0xFFFFFFFF), AX
+	SBBL $(delta >> 32), DX
+	
+	// nano/100 = DX:AX
+	// split into two decimal halves by div 1e9.
+	// (decimal point is two spots over from correct place,
+	// but we avoid overflow in the high word.)
 	MOVL	$1000000000, CX
 	DIVL	CX
+	MOVL	AX, DI
+	MOVL	DX, SI
+	
+	// DI = nano/100/1e9 = nano/1e11 = sec/100, DX = SI = nano/100%1e9
+	// split DX into seconds and nanoseconds by div 1e7 magic multiply.
+	MOVL	DX, AX
+	MOVL	$1801439851, CX
+	MULL	CX
+	SHRL	$22, DX
+	MOVL	DX, BX
+	IMULL	$10000000, DX
+	MOVL	SI, CX
+	SUBL	DX, CX
+	
+	// DI = sec/100 (still)
+	// BX = (nano/100%1e9)/1e7 = (nano/1e9)%100 = sec%100
+	// CX = (nano/100%1e9)%1e7 = (nano%1e9)/100 = nsec/100
+	// store nsec for return
+	IMULL	$100, CX
+	MOVL	CX, nsec+8(FP)
+
+	// DI = sec/100 (still)
+	// BX = sec%100
+	// construct DX:AX = 64-bit sec and store for return
+	MOVL	$0, DX
+	MOVL	$100, AX
+	MULL	DI
+	ADDL	BX, AX
+	ADCL	$0, DX
 	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
-	MOVL	DX, nsec+8(FP)
+	MOVL	DX, sec+4(FP)
+	RET
+useQPC:
+	JMP	runtime·nowQPC(SB)
 	RET
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index c61b79d..744e78c 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -465,10 +465,62 @@ TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
 	MOVQ	32(SP), SP
 	RET
 
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB),NOSPLIT,$8-12
-	CALL	runtime·unixnano(SB)
-	MOVQ	0(SP), AX
+// See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
+#define _INTERRUPT_TIME 0x7ffe0008
+#define _SYSTEM_TIME 0x7ffe0014
+#define time_lo 0
+#define time_hi1 4
+#define time_hi2 8
+
+TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+	CMPB	runtime·useQPCTime(SB), $0
+	JNE	useQPC
+	MOVQ	$_INTERRUPT_TIME, DI
+loop:
+	MOVL	time_hi1(DI), AX
+	MOVL	time_lo(DI), BX
+	MOVL	time_hi2(DI), CX
+	CMPL	AX, CX
+	JNE	loop
+	SHLQ	$32, CX
+	ORQ	BX, CX
+	IMULQ	$100, CX
+	SUBQ	runtime·startNano(SB), CX
+	MOVQ	CX, ret+0(FP)
+	RET
+useQPC:
+	JMP	runtime·nanotimeQPC(SB)
+	RET
+
+TEXT time·now(SB),NOSPLIT,$0-24
+	CMPB	runtime·useQPCTime(SB), $0
+	JNE	useQPC
+	MOVQ	$_INTERRUPT_TIME, DI
+loop:
+	MOVL	time_hi1(DI), AX
+	MOVL	time_lo(DI), BX
+	MOVL	time_hi2(DI), CX
+	CMPL	AX, CX
+	JNE	loop
+	SHLQ	$32, AX
+	ORQ	BX, AX
+	IMULQ	$100, AX
+	SUBQ	runtime·startNano(SB), AX
+	MOVQ	AX, mono+16(FP)
+
+	MOVQ	$_SYSTEM_TIME, DI
+wall:
+	MOVL	time_hi1(DI), AX
+	MOVL	time_lo(DI), BX
+	MOVL	time_hi2(DI), CX
+	CMPL	AX, CX
+	JNE	wall
+	SHLQ	$32, AX
+	ORQ	BX, AX
+	MOVQ	$116444736000000000, DI
+	SUBQ	DI, AX
+	IMULQ	$100, AX
 
 	// generated code for
 	//	func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
@@ -484,4 +536,6 @@ TEXT time·now(SB),NOSPLIT,$8-12
 	SUBQ	DX, CX
 	MOVL	CX, nsec+8(FP)
 	RET
-
+useQPC:
+	JMP	runtime·nowQPC(SB)
+	RET
diff --git a/src/runtime/syscall_nacl.h b/src/runtime/syscall_nacl.h
index 834ecfc..5ee75ab 100644
--- a/src/runtime/syscall_nacl.h
+++ b/src/runtime/syscall_nacl.h
@@ -1,4 +1,4 @@
-// generated by mknacl.sh - do not edit
+// Code generated by mknacl.sh; DO NOT EDIT.
 #define SYS_null 1
 #define SYS_nameservice 2
 #define SYS_dup 8
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index cd23b8d..ca8ea8b 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -207,3 +207,9 @@ func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
+
+//go:linkname syscall_exit syscall.Exit
+//go:nosplit
+func syscall_exit(code int) {
+	exit(int32(code))
+}
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 11e67df..3da154d 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -1037,7 +1037,7 @@ func BenchmarkRunningGoProgram(b *testing.B) {
 	defer os.RemoveAll(tmpdir)
 
 	src := filepath.Join(tmpdir, "main.go")
-	err = ioutil.WriteFile(src, []byte(benchmarkRunnigGoProgram), 0666)
+	err = ioutil.WriteFile(src, []byte(benchmarkRunningGoProgram), 0666)
 	if err != nil {
 		b.Fatal(err)
 	}
@@ -1055,14 +1055,16 @@ func BenchmarkRunningGoProgram(b *testing.B) {
 		cmd := exec.Command(exe)
 		out, err := cmd.CombinedOutput()
 		if err != nil {
-			b.Fatalf("runing main.exe failed: %v\n%s", err, out)
+			b.Fatalf("running main.exe failed: %v\n%s", err, out)
 		}
 	}
 }
 
-const benchmarkRunnigGoProgram = `
+const benchmarkRunningGoProgram = `
 package main
 
+import _ "os" // average Go program will use "os" package, do the same here
+
 func main() {
 }
 `
diff --git a/src/runtime/testdata/testprog/numcpu_freebsd.go b/src/runtime/testdata/testprog/numcpu_freebsd.go
new file mode 100644
index 0000000..035c534
--- /dev/null
+++ b/src/runtime/testdata/testprog/numcpu_freebsd.go
@@ -0,0 +1,126 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"os/exec"
+	"runtime"
+	"strconv"
+	"strings"
+	"syscall"
+)
+
+func init() {
+	register("FreeBSDNumCPU", FreeBSDNumCPU)
+	register("FreeBSDNumCPUHelper", FreeBSDNumCPUHelper)
+}
+
+func FreeBSDNumCPUHelper() {
+	fmt.Printf("%d\n", runtime.NumCPU())
+}
+
+func FreeBSDNumCPU() {
+	_, err := exec.LookPath("cpuset")
+	if err != nil {
+		// Can not test without cpuset command.
+		fmt.Println("OK")
+		return
+	}
+	_, err = exec.LookPath("sysctl")
+	if err != nil {
+		// Can not test without sysctl command.
+		fmt.Println("OK")
+		return
+	}
+	cmd := exec.Command("sysctl", "-n", "kern.smp.active")
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Printf("fail to launch '%s', error: %s, output: %s\n", strings.Join(cmd.Args, " "), err, output)
+		return
+	}
+	if bytes.Equal(output, []byte("1\n")) == false {
+		// SMP mode deactivated in kernel.
+		fmt.Println("OK")
+		return
+	}
+
+	list, err := getList()
+	if err != nil {
+		fmt.Printf("%s\n", err)
+		return
+	}
+	err = checkNCPU(list)
+	if err != nil {
+		fmt.Printf("%s\n", err)
+		return
+	}
+	if len(list) >= 2 {
+		err = checkNCPU(list[:len(list)-1])
+		if err != nil {
+			fmt.Printf("%s\n", err)
+			return
+		}
+	}
+	fmt.Println("OK")
+	return
+}
+
+func getList() ([]string, error) {
+	pid := syscall.Getpid()
+
+	// Launch cpuset to print a list of available CPUs: pid <PID> mask: 0, 1, 2, 3.
+	cmd := exec.Command("cpuset", "-g", "-p", strconv.Itoa(pid))
+	cmdline := strings.Join(cmd.Args, " ")
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
+	}
+	pos := bytes.IndexRune(output, ':')
+	if pos == -1 {
+		return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
+	}
+
+	var list []string
+	for _, val := range bytes.Split(output[pos+1:], []byte(",")) {
+		index := string(bytes.TrimSpace(val))
+		if len(index) == 0 {
+			continue
+		}
+		list = append(list, index)
+	}
+	if len(list) == 0 {
+		return nil, fmt.Errorf("empty CPU list from '%s': %s", cmdline, output)
+	}
+	return list, nil
+}
+
+func checkNCPU(list []string) error {
+	listString := strings.Join(list, ",")
+	if len(listString) == 0 {
+		return fmt.Errorf("could not check against an empty CPU list")
+	}
+
+	// Launch FreeBSDNumCPUHelper() with specified CPUs list.
+	cmd := exec.Command("cpuset", "-l", listString, os.Args[0], "FreeBSDNumCPUHelper")
+	cmdline := strings.Join(cmd.Args, " ")
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("fail to launch child '%s', error: %s, output: %s", cmdline, err, output)
+	}
+
+	// NumCPU from FreeBSDNumCPUHelper come with '\n'.
+	output = bytes.TrimSpace(output)
+	n, err := strconv.Atoi(string(output))
+	if err != nil {
+		return fmt.Errorf("fail to parse output from child '%s', error: %s, output: %s", cmdline, err, output)
+	}
+	if n != len(list) {
+		return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, listString)
+	}
+	return nil
+}
diff --git a/src/runtime/testdata/testprog/panicrace.go b/src/runtime/testdata/testprog/panicrace.go
new file mode 100644
index 0000000..f058994
--- /dev/null
+++ b/src/runtime/testdata/testprog/panicrace.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go Authors. 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"
+	"sync"
+)
+
+func init() {
+	register("PanicRace", PanicRace)
+}
+
+func PanicRace() {
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		defer func() {
+			wg.Done()
+			runtime.Gosched()
+		}()
+		panic("crash")
+	}()
+	wg.Wait()
+}
diff --git a/src/runtime/testdata/testprogcgo/numgoroutine.go b/src/runtime/testdata/testprogcgo/numgoroutine.go
new file mode 100644
index 0000000..12fda49
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/numgoroutine.go
@@ -0,0 +1,99 @@
+// Copyright 2017 The Go Authors. 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
+
+/*
+#include <stddef.h>
+#include <pthread.h>
+
+extern void CallbackNumGoroutine();
+
+static void* thread2(void* arg __attribute__ ((unused))) {
+	CallbackNumGoroutine();
+	return NULL;
+}
+
+static void CheckNumGoroutine() {
+	pthread_t tid;
+	pthread_create(&tid, NULL, thread2, NULL);
+	pthread_join(tid, NULL);
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"runtime"
+	"strings"
+)
+
+var baseGoroutines int
+
+func init() {
+	register("NumGoroutine", NumGoroutine)
+}
+
+func NumGoroutine() {
+	// Test that there are just the expected number of goroutines
+	// running. Specifically, test that the spare M's goroutine
+	// doesn't show up.
+	//
+	// On non-Windows platforms there's a signal handling thread
+	// started by os/signal.init in addition to the main
+	// goroutine.
+	if runtime.GOOS != "windows" {
+		baseGoroutines = 1
+	}
+	if _, ok := checkNumGoroutine("first", 1+baseGoroutines); !ok {
+		return
+	}
+
+	// Test that the goroutine for a callback from C appears.
+	if C.CheckNumGoroutine(); !callbackok {
+		return
+	}
+
+	// Make sure we're back to the initial goroutines.
+	if _, ok := checkNumGoroutine("third", 1+baseGoroutines); !ok {
+		return
+	}
+
+	fmt.Println("OK")
+}
+
+func checkNumGoroutine(label string, want int) (string, bool) {
+	n := runtime.NumGoroutine()
+	if n != want {
+		fmt.Printf("%s NumGoroutine: want %d; got %d\n", label, want, n)
+		return "", false
+	}
+
+	sbuf := make([]byte, 32<<10)
+	sbuf = sbuf[:runtime.Stack(sbuf, true)]
+	n = strings.Count(string(sbuf), "goroutine ")
+	if n != want {
+		fmt.Printf("%s Stack: want %d; got %d:\n%s\n", label, want, n, string(sbuf))
+		return "", false
+	}
+	return string(sbuf), true
+}
+
+var callbackok bool
+
+//export CallbackNumGoroutine
+func CallbackNumGoroutine() {
+	stk, ok := checkNumGoroutine("second", 2+baseGoroutines)
+	if !ok {
+		return
+	}
+	if !strings.Contains(stk, "CallbackNumGoroutine") {
+		fmt.Printf("missing CallbackNumGoroutine from stack:\n%s\n", stk)
+		return
+	}
+
+	callbackok = true
+}
diff --git a/src/runtime/testdata/testprognet/signalexec.go b/src/runtime/testdata/testprognet/signalexec.go
new file mode 100644
index 0000000..4a988ef
--- /dev/null
+++ b/src/runtime/testdata/testprognet/signalexec.go
@@ -0,0 +1,70 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+// This is in testprognet instead of testprog because testprog
+// must not import anything (like net, but also like os/signal)
+// that kicks off background goroutines during init.
+
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"os/signal"
+	"sync"
+	"syscall"
+	"time"
+)
+
+func init() {
+	register("SignalDuringExec", SignalDuringExec)
+	register("Nop", Nop)
+}
+
+func SignalDuringExec() {
+	pgrp := syscall.Getpgrp()
+
+	const tries = 10
+
+	var wg sync.WaitGroup
+	c := make(chan os.Signal, tries)
+	signal.Notify(c, syscall.SIGWINCH)
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		for range c {
+		}
+	}()
+
+	for i := 0; i < tries; i++ {
+		time.Sleep(time.Microsecond)
+		wg.Add(2)
+		go func() {
+			defer wg.Done()
+			cmd := exec.Command(os.Args[0], "Nop")
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			if err := cmd.Run(); err != nil {
+				fmt.Printf("Start failed: %v", err)
+			}
+		}()
+		go func() {
+			defer wg.Done()
+			syscall.Kill(-pgrp, syscall.SIGWINCH)
+		}()
+	}
+
+	signal.Stop(c)
+	close(c)
+	wg.Wait()
+
+	fmt.Println("OK")
+}
+
+func Nop() {
+	// This is just for SignalDuringExec.
+}
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 604ccde..88ab8b9 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -50,7 +50,12 @@ func timeSleep(ns int64) {
 		return
 	}
 
-	t := new(timer)
+	t := getg().timer
+	if t == nil {
+		t = new(timer)
+		getg().timer = t
+	}
+	*t = timer{}
 	t.when = nanotime() + ns
 	t.f = goroutineReady
 	t.arg = getg()
@@ -292,8 +297,8 @@ func siftdownTimer(i int) {
 
 // Entry points for net, time to call nanotime.
 
-//go:linkname net_runtimeNano net.runtimeNano
-func net_runtimeNano() int64 {
+//go:linkname poll_runtimeNano internal/poll.runtimeNano
+func poll_runtimeNano() int64 {
 	return nanotime()
 }
 
@@ -301,3 +306,5 @@ func net_runtimeNano() int64 {
 func time_runtimeNano() int64 {
 	return nanotime()
 }
+
+var startNano int64 = nanotime()
diff --git a/src/runtime/timeasm.go b/src/runtime/timeasm.go
new file mode 100644
index 0000000..7474bec
--- /dev/null
+++ b/src/runtime/timeasm.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Declarations for operating systems implementing time.now directly in assembly.
+// Those systems are also expected to have nanotime subtract startNano,
+// so that time.now and nanotime return the same monotonic clock readings.
+
+// +build darwin,amd64 darwin,386 windows
+
+package runtime
+
+import _ "unsafe"
+
+//go:linkname time_now time.now
+func time_now() (sec int64, nsec int32, mono int64)
diff --git a/src/runtime/timestub.go b/src/runtime/timestub.go
new file mode 100644
index 0000000..adc3a86
--- /dev/null
+++ b/src/runtime/timestub.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Declarations for operating systems implementing time.now
+// indirectly, in terms of walltime and nanotime assembly.
+
+// +build !darwin !amd64,!386
+// +build !windows
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+func walltime() (sec int64, nsec int32)
+
+//go:linkname time_now time.now
+func time_now() (sec int64, nsec int32, mono int64) {
+	sec, nsec = walltime()
+	return sec, nsec, nanotime() - startNano
+}
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index 32bfcf8..a5f5003 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -35,7 +35,7 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4
 	// nothing to do as nacl/arm does not use TLS at all.
 	MOVW	g, R0 // preserve R0 across call to setg<>
 	RET
-#endif
+#else
 	// If the host does not support MRC the linker will replace it with
 	// a call to runtime.read_tls_fallback which jumps to __kuser_get_tls.
 	// The replacement function saves LR in R11 over the call to read_tls_fallback.
@@ -46,6 +46,7 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4
 	MOVW	g, 0(R0)
 	MOVW	g, R0 // preserve R0 across call to setg<>
 	RET
+#endif
 
 // load_g loads the g register from pthread-provided
 // thread-local memory, for use after calling externally compiled
@@ -54,7 +55,7 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 #ifdef GOOS_nacl
 	// nothing to do as nacl/arm does not use TLS at all.
 	RET
-#endif
+#else
 	// See save_g
 	MRC	15, 0, R0, C13, C0, 3 // fetch TLS base pointer
 	BIC $3, R0 // Darwin/ARM might return unaligned pointer
@@ -62,6 +63,7 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 	ADD	R11, R0
 	MOVW	0(R0), g
 	RET
+#endif
 
 // This is called from rt0_go, which runs on the system stack
 // using the initial stack allocated by the OS.
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index a8f4ab6..826dc9a 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -19,50 +19,52 @@ import (
 
 // Event types in the trace, args are given in square brackets.
 const (
-	traceEvNone           = 0  // unused
-	traceEvBatch          = 1  // start of per-P batch of events [pid, timestamp]
-	traceEvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
-	traceEvStack          = 3  // stack [stack id, number of PCs, array of {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, seq, stack id]
-	traceEvGCDone         = 8  // GC done [timestamp]
-	traceEvGCScanStart    = 9  // GC mark termination start [timestamp]
-	traceEvGCScanDone     = 10 // GC mark termination done [timestamp]
-	traceEvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
-	traceEvGCSweepDone    = 12 // GC sweep done [timestamp]
-	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, 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]
-	traceEvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
-	traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
-	traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
-	traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
-	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
-	traceEvGoSysBlock     = 30 // syscall blocks [timestamp]
-	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]
-	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]
-	traceEvGoStartLabel   = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
-	traceEvGoBlockGC      = 42 // goroutine blocks on GC assist [timestamp, stack]
-	traceEvCount          = 43
+	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 {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, seq, stack id]
+	traceEvGCDone            = 8  // GC done [timestamp]
+	traceEvGCScanStart       = 9  // GC mark termination start [timestamp]
+	traceEvGCScanDone        = 10 // GC mark termination done [timestamp]
+	traceEvGCSweepStart      = 11 // GC sweep start [timestamp, stack id]
+	traceEvGCSweepDone       = 12 // GC sweep done [timestamp, swept, reclaimed]
+	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, 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]
+	traceEvGoBlockSync       = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	traceEvGoBlockCond       = 26 // goroutine blocks on Cond [timestamp, stack]
+	traceEvGoBlockNet        = 27 // goroutine blocks on network [timestamp, stack]
+	traceEvGoSysCall         = 28 // syscall enter [timestamp, stack]
+	traceEvGoSysExit         = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
+	traceEvGoSysBlock        = 30 // syscall blocks [timestamp]
+	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]
+	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]
+	traceEvGoStartLabel      = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
+	traceEvGoBlockGC         = 42 // goroutine blocks on GC assist [timestamp, stack]
+	traceEvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack]
+	traceEvGCMarkAssistDone  = 44 // GC mark assist done [timestamp]
+	traceEvCount             = 45
 )
 
 const (
@@ -311,7 +313,7 @@ func StopTrace() {
 
 	// The world is started but we've set trace.shutdown, so new tracing can't start.
 	// Wait for the trace reader to flush pending buffers and stop.
-	semacquire(&trace.shutdownSema, 0)
+	semacquire(&trace.shutdownSema)
 	if raceenabled {
 		raceacquire(unsafe.Pointer(&trace.shutdownSema))
 	}
@@ -380,7 +382,7 @@ func ReadTrace() []byte {
 		trace.headerWritten = true
 		trace.lockOwner = nil
 		unlock(&trace.lock)
-		return []byte("go 1.8 trace\x00\x00\x00\x00")
+		return []byte("go 1.9 trace\x00\x00\x00\x00")
 	}
 	// Wait for new data.
 	if trace.fullHead == 0 && !trace.shutdown {
@@ -570,12 +572,7 @@ func traceStackID(mp *m, buf []uintptr, skip int) uint64 {
 		nstk = callers(skip+1, buf[:])
 	} else if gp != nil {
 		gp = mp.curg
-		// This may happen when tracing a system call,
-		// so we must lock the stack.
-		if gcTryLockStackBarriers(gp) {
-			nstk = gcallers(gp, skip, buf[:])
-			gcUnlockStackBarriers(gp)
-		}
+		nstk = gcallers(gp, skip, buf[:])
 	}
 	if nstk > 0 {
 		nstk-- // skip runtime.goexit
@@ -767,10 +764,22 @@ func (tab *traceStackTable) newStack(n int) *traceStack {
 	return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*sys.PtrSize))
 }
 
+// allFrames returns all of the Frames corresponding to pcs.
+func allFrames(pcs []uintptr) []Frame {
+	frames := make([]Frame, 0, len(pcs))
+	ci := CallersFrames(pcs)
+	for {
+		f, more := ci.Next()
+		frames = append(frames, f)
+		if !more {
+			return frames
+		}
+	}
+}
+
 // dump writes all previously cached stacks to trace buffers,
 // releases all memory and resets state.
 func (tab *traceStackTable) dump() {
-	frames := make(map[uintptr]traceFrame)
 	var tmp [(2 + 4*traceStackSize) * traceBytesPerNumber]byte
 	buf := traceFlush(0).ptr()
 	for _, stk := range tab.tab {
@@ -778,11 +787,12 @@ func (tab *traceStackTable) dump() {
 		for ; stk != nil; stk = stk.link.ptr() {
 			tmpbuf := tmp[:0]
 			tmpbuf = traceAppend(tmpbuf, uint64(stk.id))
-			tmpbuf = traceAppend(tmpbuf, uint64(stk.n))
-			for _, pc := range stk.stack() {
+			frames := allFrames(stk.stack())
+			tmpbuf = traceAppend(tmpbuf, uint64(len(frames)))
+			for _, f := range frames {
 				var frame traceFrame
-				frame, buf = traceFrameForPC(buf, frames, pc)
-				tmpbuf = traceAppend(tmpbuf, uint64(pc))
+				frame, buf = traceFrameForPC(buf, f)
+				tmpbuf = traceAppend(tmpbuf, uint64(f.PC))
 				tmpbuf = traceAppend(tmpbuf, uint64(frame.funcID))
 				tmpbuf = traceAppend(tmpbuf, uint64(frame.fileID))
 				tmpbuf = traceAppend(tmpbuf, uint64(frame.line))
@@ -812,26 +822,17 @@ type traceFrame struct {
 	line   uint64
 }
 
-func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) (traceFrame, *traceBuf) {
-	if frame, ok := frames[pc]; ok {
-		return frame, buf
-	}
-
+func traceFrameForPC(buf *traceBuf, f Frame) (traceFrame, *traceBuf) {
 	var frame traceFrame
-	f := findfunc(pc)
-	if f == nil {
-		frames[pc] = frame
-		return frame, buf
-	}
 
-	fn := funcname(f)
+	fn := f.Function
 	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)
+	frame.line = uint64(f.Line)
+	file := f.File
 	if len(file) > maxLen {
 		file = file[len(file)-maxLen:]
 	}
@@ -931,12 +932,52 @@ func traceGCScanDone() {
 	traceEvent(traceEvGCScanDone, -1)
 }
 
+// traceGCSweepStart prepares to trace a sweep loop. This does not
+// emit any events until traceGCSweepSpan is called.
+//
+// traceGCSweepStart must be paired with traceGCSweepDone and there
+// must be no preemption points between these two calls.
 func traceGCSweepStart() {
-	traceEvent(traceEvGCSweepStart, 1)
+	// Delay the actual GCSweepStart event until the first span
+	// sweep. If we don't sweep anything, don't emit any events.
+	_p_ := getg().m.p.ptr()
+	if _p_.traceSweep {
+		throw("double traceGCSweepStart")
+	}
+	_p_.traceSweep, _p_.traceSwept, _p_.traceReclaimed = true, 0, 0
+}
+
+// traceGCSweepSpan traces the sweep of a single page.
+//
+// This may be called outside a traceGCSweepStart/traceGCSweepDone
+// pair; however, it will not emit any trace events in this case.
+func traceGCSweepSpan(bytesSwept uintptr) {
+	_p_ := getg().m.p.ptr()
+	if _p_.traceSweep {
+		if _p_.traceSwept == 0 {
+			traceEvent(traceEvGCSweepStart, 1)
+		}
+		_p_.traceSwept += bytesSwept
+	}
 }
 
 func traceGCSweepDone() {
-	traceEvent(traceEvGCSweepDone, -1)
+	_p_ := getg().m.p.ptr()
+	if !_p_.traceSweep {
+		throw("missing traceGCSweepStart")
+	}
+	if _p_.traceSwept != 0 {
+		traceEvent(traceEvGCSweepDone, -1, uint64(_p_.traceSwept), uint64(_p_.traceReclaimed))
+	}
+	_p_.traceSweep = false
+}
+
+func traceGCMarkAssistStart() {
+	traceEvent(traceEvGCMarkAssistStart, 1)
+}
+
+func traceGCMarkAssistDone() {
+	traceEvent(traceEvGCMarkAssistDone, -1)
 }
 
 func traceGoCreate(newg *g, pc uintptr) {
@@ -977,7 +1018,7 @@ func traceGoPreempt() {
 	traceEvent(traceEvGoPreempt, 1)
 }
 
-func traceGoPark(traceEv byte, skip int, gp *g) {
+func traceGoPark(traceEv byte, skip int) {
 	if traceEv&traceFutileWakeup != 0 {
 		traceEvent(traceEvFutileWakeup, -1)
 	}
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
index c37b33d..274cdf7 100644
--- a/src/runtime/trace/trace_stack_test.go
+++ b/src/runtime/trace/trace_stack_test.go
@@ -151,7 +151,7 @@ func TestTraceSymbolize(t *testing.T) {
 			{"testing.tRunner", 0},
 		}},
 		{trace.EvGoCreate, []frame{
-			{"runtime/trace_test.TestTraceSymbolize", 39},
+			{"runtime/trace_test.TestTraceSymbolize", 37},
 			{"testing.tRunner", 0},
 		}},
 		{trace.EvGoStop, []frame{
@@ -231,6 +231,7 @@ func TestTraceSymbolize(t *testing.T) {
 	if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
 		want = append(want, []eventDesc{
 			{trace.EvGoBlockNet, []frame{
+				{"internal/poll.(*FD).Accept", 0},
 				{"net.(*netFD).accept", 0},
 				{"net.(*TCPListener).accept", 0},
 				{"net.(*TCPListener).Accept", 0},
@@ -239,6 +240,7 @@ func TestTraceSymbolize(t *testing.T) {
 			{trace.EvGoSysCall, []frame{
 				{"syscall.read", 0},
 				{"syscall.Read", 0},
+				{"internal/poll.(*FD).Read", 0},
 				{"os.(*File).read", 0},
 				{"os.(*File).Read", 0},
 				{"runtime/trace_test.TestTraceSymbolize.func11", 102},
@@ -274,9 +276,10 @@ func TestTraceSymbolize(t *testing.T) {
 				continue
 			}
 			for _, f := range ev.Stk {
-				t.Logf("  %v:%v", f.Fn, f.Line)
+				t.Logf("  %v :: %s:%v", f.Fn, f.File, f.Line)
 			}
 			t.Logf("---")
 		}
+		t.Logf("======")
 	}
 }
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 180489f..c74d438 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -51,8 +51,8 @@ var (
 	gcBgMarkWorkerPC     uintptr
 	systemstack_switchPC uintptr
 	systemstackPC        uintptr
-	stackBarrierPC       uintptr
 	cgocallback_gofuncPC uintptr
+	skipPC               uintptr
 
 	gogoPC uintptr
 
@@ -78,8 +78,8 @@ func tracebackinit() {
 	gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
 	systemstack_switchPC = funcPC(systemstack_switch)
 	systemstackPC = funcPC(systemstack)
-	stackBarrierPC = funcPC(stackBarrier)
 	cgocallback_gofuncPC = funcPC(cgocallback_gofunc)
+	skipPC = funcPC(skipPleaseUseCallersFrames)
 
 	// used by sigprof handler
 	gogoPC = funcPC(gogo)
@@ -94,14 +94,14 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 		if fn == nil {
 			// Defer of nil function. Args don't matter.
 			frame.pc = 0
-			frame.fn = nil
+			frame.fn = funcInfo{}
 			frame.argp = 0
 			frame.arglen = 0
 			frame.argmap = nil
 		} else {
 			frame.pc = fn.fn
 			f := findfunc(frame.pc)
-			if f == nil {
+			if !f.valid() {
 				print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
 				throw("unknown pc")
 			}
@@ -116,11 +116,25 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 	}
 }
 
+const sizeofSkipFunction = 256
+
+// This function is defined in asm.s to be sizeofSkipFunction bytes long.
+func skipPleaseUseCallersFrames()
+
 // 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.
+//
+// The skip argument is only valid with pcbuf != nil and counts the number
+// of logical frames to skip rather than physical frames (with inlining, a
+// PC in pcbuf can represent multiple calls). If a PC is partially skipped
+// and max > 1, pcbuf[1] will be runtime.skipPleaseUseCallersFrames+N where
+// N indicates the number of logical frames to skip in pcbuf[0].
 func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
+	if skip > 0 && callback != nil {
+		throw("gentraceback callback cannot be used with non-zero skip")
+	}
 	if goexitPC == 0 {
 		throw("gentraceback before goexitPC initialization")
 	}
@@ -143,11 +157,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 	}
 	level, _, _ := gotraceback()
 
-	// Fix up returns to the stack barrier by fetching the
-	// original return PC from gp.stkbar.
-	stkbarG := gp
-	stkbar := stkbarG.stkbar[stkbarG.stkbarPos:]
-
 	if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
 		if gp.syscallsp != 0 {
 			pc0 = gp.syscallpc
@@ -193,35 +202,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 	}
 
 	f := findfunc(frame.pc)
-	if f != nil && f.entry == stackBarrierPC {
-		// We got caught in the middle of a stack barrier
-		// (presumably by a signal), so stkbar may be
-		// inconsistent with the barriers on the stack.
-		// Simulate the completion of the barrier.
-		//
-		// On x86, SP will be exactly one word above
-		// savedLRPtr. On LR machines, SP will be above
-		// savedLRPtr by some frame size.
-		var stkbarPos uintptr
-		if len(stkbar) > 0 && stkbar[0].savedLRPtr < sp0 {
-			// stackBarrier has not incremented stkbarPos.
-			stkbarPos = gp.stkbarPos
-		} else if gp.stkbarPos > 0 && gp.stkbar[gp.stkbarPos-1].savedLRPtr < sp0 {
-			// stackBarrier has incremented stkbarPos.
-			stkbarPos = gp.stkbarPos - 1
-		} else {
-			printlock()
-			print("runtime: failed to unwind through stackBarrier at SP ", hex(sp0), "; ")
-			gcPrintStkbars(gp, int(gp.stkbarPos))
-			print("\n")
-			throw("inconsistent state in stackBarrier")
-		}
-
-		frame.pc = gp.stkbar[stkbarPos].savedLRVal
-		stkbar = gp.stkbar[stkbarPos+1:]
-		f = findfunc(frame.pc)
-	}
-	if f == nil {
+	if !f.valid() {
 		if callback != nil {
 			print("runtime: unknown pc ", hex(frame.pc), "\n")
 			throw("unknown pc")
@@ -257,8 +238,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			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))
@@ -267,10 +246,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 				frame.fp += sys.RegSize
 			}
 		}
-		var flr *_func
+		var flr funcInfo
 		if topofstack(f) {
 			frame.lr = 0
-			flr = nil
+			flr = funcInfo{}
 		} else if usesLR && f.entry == jmpdeferPC {
 			// jmpdefer modifies SP/LR/PC non-atomically.
 			// If a profiling interrupt arrives during jmpdefer,
@@ -295,19 +274,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 					frame.lr = uintptr(*(*sys.Uintreg)(unsafe.Pointer(lrPtr)))
 				}
 			}
-			if frame.lr == stackBarrierPC {
-				// Recover original PC.
-				if len(stkbar) == 0 || stkbar[0].savedLRPtr != lrPtr {
-					print("found next stack barrier at ", hex(lrPtr), "; expected ")
-					gcPrintStkbars(stkbarG, len(stkbarG.stkbar)-len(stkbar))
-					print("\n")
-					throw("missed stack barrier")
-				}
-				frame.lr = stkbar[0].savedLRVal
-				stkbar = stkbar[1:]
-			}
 			flr = findfunc(frame.lr)
-			if flr == nil {
+			if !flr.valid() {
 				// This happens if you get a profiling interrupt at just the wrong time.
 				// In that context it is okay to stop early.
 				// But if callback is set, we're doing a garbage collection and must
@@ -366,20 +334,59 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			_defer = _defer.link
 		}
 
-		if skip > 0 {
-			skip--
-			goto skipped
-		}
-
-		if pcbuf != nil {
-			(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = frame.pc
-		}
 		if callback != nil {
 			if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) {
 				return n
 			}
 		}
+
+		if pcbuf != nil {
+			if skip == 0 {
+				(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = frame.pc
+			} else {
+				// backup to CALL instruction to read inlining info (same logic as below)
+				tracepc := frame.pc
+				if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
+					tracepc--
+				}
+				inldata := funcdata(f, _FUNCDATA_InlTree)
+
+				// no inlining info, skip the physical frame
+				if inldata == nil {
+					skip--
+					goto skipped
+				}
+
+				ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, &cache)
+				inltree := (*[1 << 20]inlinedCall)(inldata)
+				// skip the logical (inlined) frames
+				logicalSkipped := 0
+				for ix >= 0 && skip > 0 {
+					skip--
+					logicalSkipped++
+					ix = inltree[ix].parent
+				}
+
+				// skip the physical frame if there's more to skip
+				if skip > 0 {
+					skip--
+					goto skipped
+				}
+
+				// now we have a partially skipped frame
+				(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = frame.pc
+
+				// if there's room, pcbuf[1] is a skip PC that encodes the number of skipped frames in pcbuf[0]
+				if n+1 < max {
+					n++
+					skipPC := funcPC(skipPleaseUseCallersFrames) + uintptr(logicalSkipped)
+					(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = skipPC
+				}
+			}
+		}
+
 		if printing {
+			// assume skip=0 for printing
 			if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp, nprint == 0) {
 				// Print during crash.
 				//	main(0x1, 0x2, 0x3)
@@ -389,6 +396,21 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 				if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
 					tracepc--
 				}
+				file, line := funcline(f, tracepc)
+				inldata := funcdata(f, _FUNCDATA_InlTree)
+				if inldata != nil {
+					inltree := (*[1 << 20]inlinedCall)(inldata)
+					ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, nil)
+					for ix != -1 {
+						name := funcnameFromNameoff(f, inltree[ix].func_)
+						print(name, "(...)\n")
+						print("\t", file, ":", line, "\n")
+
+						file = funcfile(f, inltree[ix].file)
+						line = inltree[ix].line
+						ix = inltree[ix].parent
+					}
+				}
 				name := funcname(f)
 				if name == "runtime.gopanic" {
 					name = "panic"
@@ -406,13 +428,12 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 					print(hex(argp[i]))
 				}
 				print(")\n")
-				file, line := funcline(f, tracepc)
 				print("\t", file, ":", line)
 				if frame.pc > f.entry {
 					print(" +", hex(frame.pc-f.entry))
 				}
 				if g.m.throwing > 0 && gp == g.m.curg || level >= 2 {
-					print(" fp=", hex(frame.fp), " sp=", hex(frame.sp))
+					print(" fp=", hex(frame.fp), " sp=", hex(frame.sp), " pc=", hex(frame.pc))
 				}
 				print("\n")
 				nprint++
@@ -436,7 +457,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		waspanic = f.entry == sigpanicPC
 
 		// Do not unwind past the bottom of the stack.
-		if flr == nil {
+		if !flr.valid() {
 			break
 		}
 
@@ -459,7 +480,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			}
 			f = findfunc(frame.pc)
 			frame.fn = f
-			if f == nil {
+			if !f.valid() {
 				frame.pc = x
 			} else if funcspdelta(f, frame.pc, &cache) == 0 {
 				frame.lr = x
@@ -530,13 +551,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		throw("traceback has leftover defers")
 	}
 
-	if callback != nil && n < max && len(stkbar) > 0 {
-		print("runtime: g", gp.goid, ": leftover stack barriers ")
-		gcPrintStkbars(stkbarG, len(stkbarG.stkbar)-len(stkbar))
-		print("\n")
-		throw("traceback has leftover stack barriers")
-	}
-
 	if callback != nil && n < max && frame.sp != gp.stktopsp {
 		print("runtime: g", gp.goid, ": frame.sp=", hex(frame.sp), " top=", hex(gp.stktopsp), "\n")
 		print("\tstack=[", hex(gp.stack.lo), "-", hex(gp.stack.hi), "] n=", n, " max=", max, "\n")
@@ -561,7 +575,7 @@ type reflectMethodValue struct {
 // call, ctxt must be nil (getArgInfo will retrieve what it needs from
 // the active stack frame). If this is a deferred call, ctxt must be
 // the function object that was deferred.
-func getArgInfo(frame *stkframe, f *_func, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
+func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
 	arglen = uintptr(f.args)
 	if needArgMap && f.args == _ArgsSizeUnknown {
 		// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
@@ -633,7 +647,7 @@ func printcreatedby(gp *g) {
 	// Show what created goroutine, except main goroutine (goid 1).
 	pc := gp.gopc
 	f := findfunc(pc)
-	if f != nil && showframe(f, gp, false) && gp.goid != 1 {
+	if f.valid() && showframe(f, gp, false) && gp.goid != 1 {
 		print("created by ", funcname(f), "\n")
 		tracepc := pc // back up to CALL instruction for funcline.
 		if pc > f.entry {
@@ -713,7 +727,7 @@ func gcallers(gp *g, skip int, pcbuf []uintptr) int {
 	return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
 }
 
-func showframe(f *_func, gp *g, firstFrame bool) bool {
+func showframe(f funcInfo, gp *g, firstFrame bool) bool {
 	g := getg()
 	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
 		return true
@@ -730,7 +744,7 @@ func showframe(f *_func, gp *g, firstFrame bool) bool {
 		return true
 	}
 
-	return level > 1 || f != nil && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+	return level > 1 || f.valid() && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
 }
 
 // isExportedRuntime reports whether name is an exported runtime function.
@@ -821,7 +835,7 @@ func tracebackothers(me *g) {
 }
 
 // Does f mark the top of a goroutine stack?
-func topofstack(f *_func) bool {
+func topofstack(f funcInfo) bool {
 	pc := f.entry
 	return pc == goexitPC ||
 		pc == mstartPC ||
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 3ecc54c..bf54d54 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -22,7 +22,7 @@ const (
 	tflagNamed     tflag = 1 << 2
 )
 
-// Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize,
+// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
 // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
 // ../reflect/type.go:/^type.rtype.
 type _type struct {
@@ -390,9 +390,13 @@ type ptrtype struct {
 }
 
 type structfield struct {
-	name   name
-	typ    *_type
-	offset uintptr
+	name       name
+	typ        *_type
+	offsetAnon uintptr
+}
+
+func (f *structfield) offset() uintptr {
+	return f.offsetAnon >> 1
 }
 
 type structtype struct {
@@ -507,7 +511,8 @@ func typelinksinit() {
 			for _, tl := range md.typelinks {
 				t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
 				for _, candidate := range typehash[t.hash] {
-					if typesEqual(t, candidate) {
+					seen := map[_typePair]struct{}{}
+					if typesEqual(t, candidate, seen) {
 						t = candidate
 						break
 					}
@@ -520,6 +525,11 @@ func typelinksinit() {
 	}
 }
 
+type _typePair struct {
+	t1 *_type
+	t2 *_type
+}
+
 // typesEqual reports whether two types are equal.
 //
 // Everywhere in the runtime and reflect packages, it is assumed that
@@ -532,7 +542,17 @@ func typelinksinit() {
 // back into earlier ones.
 //
 // Only typelinksinit needs this function.
-func typesEqual(t, v *_type) bool {
+func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
+	tp := _typePair{t, v}
+	if _, ok := seen[tp]; ok {
+		return true
+	}
+
+	// mark these types as seen, and thus equivalent which prevents an infinite loop if
+	// the two types are identical, but recursively defined and loaded from
+	// different modules
+	seen[tp] = struct{}{}
+
 	if t == v {
 		return true
 	}
@@ -564,11 +584,11 @@ func typesEqual(t, v *_type) bool {
 	case kindArray:
 		at := (*arraytype)(unsafe.Pointer(t))
 		av := (*arraytype)(unsafe.Pointer(v))
-		return typesEqual(at.elem, av.elem) && at.len == av.len
+		return typesEqual(at.elem, av.elem, seen) && 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)
+		return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
 	case kindFunc:
 		ft := (*functype)(unsafe.Pointer(t))
 		fv := (*functype)(unsafe.Pointer(v))
@@ -577,13 +597,13 @@ func typesEqual(t, v *_type) bool {
 		}
 		tin, vin := ft.in(), fv.in()
 		for i := 0; i < len(tin); i++ {
-			if !typesEqual(tin[i], vin[i]) {
+			if !typesEqual(tin[i], vin[i], seen) {
 				return false
 			}
 		}
 		tout, vout := ft.out(), fv.out()
 		for i := 0; i < len(tout); i++ {
-			if !typesEqual(tout[i], vout[i]) {
+			if !typesEqual(tout[i], vout[i], seen) {
 				return false
 			}
 		}
@@ -612,7 +632,7 @@ func typesEqual(t, v *_type) bool {
 			}
 			tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
 			vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
-			if !typesEqual(tityp, vityp) {
+			if !typesEqual(tityp, vityp, seen) {
 				return false
 			}
 		}
@@ -620,15 +640,15 @@ func typesEqual(t, v *_type) bool {
 	case kindMap:
 		mt := (*maptype)(unsafe.Pointer(t))
 		mv := (*maptype)(unsafe.Pointer(v))
-		return typesEqual(mt.key, mv.key) && typesEqual(mt.elem, mv.elem)
+		return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
 	case kindPtr:
 		pt := (*ptrtype)(unsafe.Pointer(t))
 		pv := (*ptrtype)(unsafe.Pointer(v))
-		return typesEqual(pt.elem, pv.elem)
+		return typesEqual(pt.elem, pv.elem, seen)
 	case kindSlice:
 		st := (*slicetype)(unsafe.Pointer(t))
 		sv := (*slicetype)(unsafe.Pointer(v))
-		return typesEqual(st.elem, sv.elem)
+		return typesEqual(st.elem, sv.elem, seen)
 	case kindStruct:
 		st := (*structtype)(unsafe.Pointer(t))
 		sv := (*structtype)(unsafe.Pointer(v))
@@ -644,13 +664,13 @@ func typesEqual(t, v *_type) bool {
 			if tf.name.pkgPath() != vf.name.pkgPath() {
 				return false
 			}
-			if !typesEqual(tf.typ, vf.typ) {
+			if !typesEqual(tf.typ, vf.typ, seen) {
 				return false
 			}
 			if tf.name.tag() != vf.name.tag() {
 				return false
 			}
-			if tf.offset != vf.offset {
+			if tf.offsetAnon != vf.offsetAnon {
 				return false
 			}
 		}
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index d4c411c..7489a65 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -28,26 +28,10 @@
 #include "funcdata.h"
 #include "textflag.h"
 
-/* replaced use of R10 by R11 because the former can be the data segment base register */
-
-TEXT _mulv(SB), NOSPLIT, $0
-	MOVW	l0+0(FP), R2	/* l0 */
-	MOVW	h0+4(FP), R11	/* h0 */
-	MOVW	l1+8(FP), R4	/* l1 */
-	MOVW	h1+12(FP), R5	/* h1 */
-	MULLU	R4, R2, (R7,R6)
-	MUL	R11, R4, R8
-	ADD	R8, R7
-	MUL	R2, R5, R8
-	ADD	R8, R7
-	MOVW	R6, ret_lo+16(FP)
-	MOVW	R7, ret_hi+20(FP)
-	RET
-
 // trampoline for _sfloat2. passes LR as arg0 and
 // saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can
 // be changed by _sfloat2.
-TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return value
+TEXT runtime·_sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return value
 	MOVW	R14, 4(R13)
 	MOVW	R0, 8(R13)
 	MOVW	$12(R13), R0
@@ -106,7 +90,7 @@ TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
 	MOVW	g_sigpc(g), LR
 	B	runtime·sigpanic(SB)
 
-// func udiv(n, d uint32) (q, r uint32)
+// func runtime·udiv(n, d uint32) (q, r uint32)
 // compiler knowns the register usage of this function
 // Reference: 
 // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
@@ -118,7 +102,11 @@ TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
 #define Ra	R11
 
 // Be careful: Ra == R11 will be used by the linker for synthesized instructions.
-TEXT udiv(SB),NOSPLIT,$-4
+TEXT runtime·udiv(SB),NOSPLIT,$-4
+	MOVBU	runtime·hardDiv(SB), Ra
+	CMP	$0, Ra
+	BNE	udiv_hardware
+
 	CLZ 	Rq, Rs // find normalizing shift
 	MOVW.S	Rq<<Rs, Ra
 	MOVW	$fast_udiv_tab<>-64(SB), RM
@@ -154,6 +142,14 @@ TEXT udiv(SB),NOSPLIT,$-4
 	ADD.PL	$2, Rq
 	RET
 
+// use hardware divider
+udiv_hardware:
+	DIVUHW	Rq, Rr, Rs
+	MUL	Rs, Rq, RM
+	RSB	Rr, RM, Rr
+	MOVW	Rs, Rq
+	RET
+
 udiv_by_large_d:
 	// at this point we know d>=2^(31-6)=2^25
 	SUB 	$4, Ra, Ra
@@ -203,118 +199,6 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
 GLOBL fast_udiv_tab<>(SB), RODATA, $64
 
-// The linker will pass numerator in R8
-#define Rn R8
-// The linker expects the result in RTMP
-#define RTMP R11
-
-TEXT _divu(SB), NOSPLIT, $16-0
-	// It's not strictly true that there are no local pointers.
-	// It could be that the saved registers Rq, Rr, Rs, and Rm
-	// contain pointers. However, the only way this can matter
-	// is if the stack grows (which it can't, udiv is nosplit)
-	// or if a fault happens and more frames are added to
-	// the stack due to deferred functions.
-	// In the latter case, the stack can grow arbitrarily,
-	// and garbage collection can happen, and those
-	// operations care about pointers, but in that case
-	// the calling frame is dead, and so are the saved
-	// registers. So we can claim there are no pointers here.
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-
-	MOVW	Rn, Rr			/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	BL  	udiv(SB)
-	MOVW	Rq, RTMP
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
-	RET
-
-TEXT _modu(SB), NOSPLIT, $16-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-
-	MOVW	Rn, Rr			/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	BL  	udiv(SB)
-	MOVW	Rr, RTMP
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
-	RET
-
-TEXT _div(SB),NOSPLIT,$16-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-	MOVW	Rn, Rr			/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	CMP 	$0, Rr
-	BGE 	d1
-	RSB 	$0, Rr, Rr
-	CMP 	$0, Rq
-	BGE 	d2
-	RSB 	$0, Rq, Rq
-d0:
-	BL  	udiv(SB)  		/* none/both neg */
-	MOVW	Rq, RTMP
-	B	out1
-d1:
-	CMP 	$0, Rq
-	BGE 	d0
-	RSB 	$0, Rq, Rq
-d2:
-	BL  	udiv(SB)  		/* one neg */
-	RSB	$0, Rq, RTMP
-out1:
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
-	RET
-
-TEXT _mod(SB),NOSPLIT,$16-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-	MOVW	Rn, Rr			/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	CMP 	$0, Rq
-	RSB.LT	$0, Rq, Rq
-	CMP 	$0, Rr
-	BGE 	m1
-	RSB 	$0, Rr, Rr
-	BL  	udiv(SB)  		/* neg numerator */
-	RSB 	$0, Rr, RTMP
-	B   	out
-m1:
-	BL  	udiv(SB)  		/* pos numerator */
-	MOVW	Rr, RTMP
-out:
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
-	RET
-
 // _mul64by32 and _div64by32 not implemented on arm
 TEXT runtime·_mul64by32(SB), NOSPLIT, $0
 	MOVW	$0, R0
diff --git a/src/runtime/write_err_android.go b/src/runtime/write_err_android.go
index 748dec6..bf99b5f 100644
--- a/src/runtime/write_err_android.go
+++ b/src/runtime/write_err_android.go
@@ -144,7 +144,7 @@ func writeLogdHeader() int {
 	//      hdr[3:7] sec unsigned uint32, little endian.
 	//      hdr[7:11] nsec unsigned uint32, little endian.
 	hdr[0] = 0 // LOG_ID_MAIN
-	sec, nsec := time_now()
+	sec, nsec := walltime()
 	packUint32(hdr[3:7], uint32(sec))
 	packUint32(hdr[7:11], uint32(nsec))
 
diff --git a/src/sort/example_test.go b/src/sort/example_test.go
index 980c0d0..89ebe79 100644
--- a/src/sort/example_test.go
+++ b/src/sort/example_test.go
@@ -41,3 +41,31 @@ func ExampleSlice() {
 	// Output: By name: [{Alice 55} {Bob 75} {Gopher 7} {Vera 24}]
 	// By age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
 }
+
+func ExampleSliceStable() {
+
+	people := []struct {
+		Name string
+		Age  int
+	}{
+		{"Alice", 25},
+		{"Elizabeth", 75},
+		{"Alice", 75},
+		{"Bob", 75},
+		{"Alice", 75},
+		{"Bob", 25},
+		{"Colin", 25},
+		{"Elizabeth", 25},
+	}
+
+	// Sort by name, preserving original order
+	sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })
+	fmt.Println("By name:", people)
+
+	// Sort by age preserving name order
+	sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })
+	fmt.Println("By age,name:", people)
+
+	// Output: By name: [{Alice 25} {Alice 75} {Alice 75} {Bob 75} {Bob 25} {Colin 25} {Elizabeth 75} {Elizabeth 25}]
+	// By age,name: [{Alice 25} {Bob 25} {Colin 25} {Elizabeth 25} {Alice 75} {Alice 75} {Bob 75} {Elizabeth 75}]
+}
diff --git a/src/sort/genzfunc.go b/src/sort/genzfunc.go
index 6d2b471..3bb7691 100644
--- a/src/sort/genzfunc.go
+++ b/src/sort/genzfunc.go
@@ -115,6 +115,10 @@ func rewriteCall(ce *ast.CallExpr) {
 		// e.g. skip SelectorExpr (data.Less(..) calls)
 		return
 	}
+	// skip casts
+	if ident.Name == "int" || ident.Name == "uint" {
+		return
+	}
 	if len(ce.Args) < 1 {
 		return
 	}
diff --git a/src/sort/search.go b/src/sort/search.go
index b9640a4..fcff0f9 100644
--- a/src/sort/search.go
+++ b/src/sort/search.go
@@ -24,7 +24,7 @@ package sort
 //
 // For instance, given a slice data sorted in ascending order,
 // the call Search(len(data), func(i int) bool { return data[i] >= 23 })
-// returns the smallest index i such that data[i] >= 23.  If the caller
+// returns the smallest index i such that data[i] >= 23. If the caller
 // wants to find whether 23 is in the slice, it must test data[i] == 23
 // separately.
 //
@@ -61,7 +61,7 @@ func Search(n int, f func(int) bool) int {
 	// Invariant: f(i-1) == false, f(j) == true.
 	i, j := 0, n
 	for i < j {
-		h := i + (j-i)/2 // avoid overflow when computing h
+		h := int(uint(i+j) >> 1) // avoid overflow when computing h
 		// i ≤ h < j
 		if !f(h) {
 			i = h + 1 // preserves f(i-1) == false
diff --git a/src/sort/sort.go b/src/sort/sort.go
index 72d24ef..081b700 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -96,7 +96,7 @@ func swapRange(data Interface, a, b, n int) {
 }
 
 func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
-	m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
+	m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow.
 	if hi-lo > 40 {
 		// Tukey's ``Ninther,'' median of three medians of three.
 		s := (hi - lo) / 8
@@ -314,7 +314,8 @@ func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 // Sort is a convenience method.
 func (p IntSlice) Sort() { Sort(p) }
 
-// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
+// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order
+// (not-a-number values are treated as less than other values).
 type Float64Slice []float64
 
 func (p Float64Slice) Len() int           { return len(p) }
@@ -344,7 +345,8 @@ func (p StringSlice) Sort() { Sort(p) }
 // Ints sorts a slice of ints in increasing order.
 func Ints(a []int) { Sort(IntSlice(a)) }
 
-// Float64s sorts a slice of float64s in increasing order.
+// Float64s sorts a slice of float64s in increasing order
+// (not-a-number values are treated as less than other values).
 func Float64s(a []float64) { Sort(Float64Slice(a)) }
 
 // Strings sorts a slice of strings in increasing order.
@@ -353,7 +355,8 @@ func Strings(a []string) { Sort(StringSlice(a)) }
 // IntsAreSorted tests whether a slice of ints is sorted in increasing order.
 func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
 
-// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
+// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order
+// (not-a-number values are treated as less than other values).
 func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
 
 // StringsAreSorted tests whether a slice of strings is sorted in increasing order.
@@ -447,7 +450,7 @@ func symMerge(data Interface, a, m, b int) {
 		i := m
 		j := b
 		for i < j {
-			h := i + (j-i)/2
+			h := int(uint(i+j) >> 1)
 			if data.Less(h, a) {
 				i = h + 1
 			} else {
@@ -471,7 +474,7 @@ func symMerge(data Interface, a, m, b int) {
 		i := a
 		j := m
 		for i < j {
-			h := i + (j-i)/2
+			h := int(uint(i+j) >> 1)
 			if !data.Less(m, h) {
 				i = h + 1
 			} else {
@@ -485,7 +488,7 @@ func symMerge(data Interface, a, m, b int) {
 		return
 	}
 
-	mid := a + (b-a)/2
+	mid := int(uint(a+b) >> 1)
 	n := mid + m
 	var start, r int
 	if m > mid {
@@ -498,7 +501,7 @@ func symMerge(data Interface, a, m, b int) {
 	p := n - 1
 
 	for start < r {
-		c := start + (r-start)/2
+		c := int(uint(start+r) >> 1)
 		if !data.Less(p-c, c) {
 			start = c + 1
 		} else {
diff --git a/src/sort/zfuncversion.go b/src/sort/zfuncversion.go
index 7abb18a..99c95a2 100644
--- a/src/sort/zfuncversion.go
+++ b/src/sort/zfuncversion.go
@@ -70,7 +70,7 @@ func swapRange_func(data lessSwap, a, b, n int) {
 
 // Auto-generated variant of sort.go:doPivot
 func doPivot_func(data lessSwap, lo, hi int) (midlo, midhi int) {
-	m := lo + (hi-lo)/2
+	m := int(uint(lo+hi) >> 1)
 	if hi-lo > 40 {
 		s := (hi - lo) / 8
 		medianOfThree_func(data, lo, lo+s, lo+2*s)
@@ -189,7 +189,7 @@ func symMerge_func(data lessSwap, a, m, b int) {
 		i := m
 		j := b
 		for i < j {
-			h := i + (j-i)/2
+			h := int(uint(i+j) >> 1)
 			if data.Less(h, a) {
 				i = h + 1
 			} else {
@@ -205,7 +205,7 @@ func symMerge_func(data lessSwap, a, m, b int) {
 		i := a
 		j := m
 		for i < j {
-			h := i + (j-i)/2
+			h := int(uint(i+j) >> 1)
 			if !data.Less(m, h) {
 				i = h + 1
 			} else {
@@ -217,7 +217,7 @@ func symMerge_func(data lessSwap, a, m, b int) {
 		}
 		return
 	}
-	mid := a + (b-a)/2
+	mid := int(uint(a+b) >> 1)
 	n := mid + m
 	var start, r int
 	if m > mid {
@@ -229,7 +229,7 @@ func symMerge_func(data lessSwap, a, m, b int) {
 	}
 	p := n - 1
 	for start < r {
-		c := start + (r-start)/2
+		c := int(uint(start+r) >> 1)
 		if !data.Less(p-c, c) {
 			start = c + 1
 		} else {
diff --git a/src/strconv/itoa.go b/src/strconv/itoa.go
index f50d877..78527c8 100644
--- a/src/strconv/itoa.go
+++ b/src/strconv/itoa.go
@@ -4,10 +4,15 @@
 
 package strconv
 
+const fastSmalls = true // enable fast path for small integers
+
 // FormatUint returns the string representation of i in the given base,
 // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
 // for digit values >= 10.
 func FormatUint(i uint64, base int) string {
+	if fastSmalls && i < nSmalls && base == 10 {
+		return small(int(i))
+	}
 	_, s := formatBits(nil, i, base, false, false)
 	return s
 }
@@ -16,6 +21,9 @@ func FormatUint(i uint64, base int) string {
 // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
 // for digit values >= 10.
 func FormatInt(i int64, base int) string {
+	if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
+		return small(int(i))
+	}
 	_, s := formatBits(nil, uint64(i), base, i < 0, false)
 	return s
 }
@@ -28,6 +36,9 @@ func Itoa(i int) string {
 // AppendInt appends the string form of the integer i,
 // as generated by FormatInt, to dst and returns the extended buffer.
 func AppendInt(dst []byte, i int64, base int) []byte {
+	if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
+		return append(dst, small(int(i))...)
+	}
 	dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
 	return dst
 }
@@ -35,13 +46,38 @@ func AppendInt(dst []byte, i int64, base int) []byte {
 // AppendUint appends the string form of the unsigned integer i,
 // as generated by FormatUint, to dst and returns the extended buffer.
 func AppendUint(dst []byte, i uint64, base int) []byte {
+	if fastSmalls && i < nSmalls && base == 10 {
+		return append(dst, small(int(i))...)
+	}
 	dst, _ = formatBits(dst, i, base, false, true)
 	return dst
 }
 
-const (
-	digits = "0123456789abcdefghijklmnopqrstuvwxyz"
-)
+// small returns the string for an i with 0 <= i < nSmalls.
+func small(i int) string {
+	off := 0
+	if i < 10 {
+		off = 1
+	}
+	return smallsString[i*2+off : i*2+2]
+}
+
+const nSmalls = 100
+
+const smallsString = "00010203040506070809" +
+	"10111213141516171819" +
+	"20212223242526272829" +
+	"30313233343536373839" +
+	"40414243444546474849" +
+	"50515253545556575859" +
+	"60616263646566676869" +
+	"70717273747576777879" +
+	"80818283848586878889" +
+	"90919293949596979899"
+
+const host32bit = ^uint(0)>>32 == 0
+
+const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
 
 var shifts = [len(digits) + 1]uint{
 	1 << 1: 1,
@@ -71,61 +107,84 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 	}
 
 	// convert bits
+	// We use uint values where we can because those will
+	// fit into a single register even on a 32bit machine.
 	if base == 10 {
 		// common case: use constants for / because
 		// the compiler can optimize it into a multiply+shift
 
-		if ^uintptr(0)>>32 == 0 {
-			for u > uint64(^uintptr(0)) {
+		if host32bit {
+			// convert the lower digits using 32bit operations
+			for u >= 1e9 {
+				// Avoid using r = a%b in addition to q = a/b
+				// since 64bit division and modulo operations
+				// are calculated by runtime functions on 32bit machines.
 				q := u / 1e9
-				us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
-				for j := 9; j > 0; j-- {
-					i--
-					qs := us / 10
-					a[i] = byte(us - qs*10 + '0')
-					us = qs
+				us := uint(u - q*1e9) // u % 1e9 fits into a uint
+				for j := 4; j > 0; j-- {
+					is := us % 100 * 2
+					us /= 100
+					i -= 2
+					a[i+1] = smallsString[is+1]
+					a[i+0] = smallsString[is+0]
 				}
+
+				// us < 10, since it contains the last digit
+				// from the initial 9-digit us.
+				i--
+				a[i] = smallsString[us*2+1]
+
 				u = q
 			}
+			// u < 1e9
 		}
 
-		// u guaranteed to fit into a uintptr
-		us := uintptr(u)
-		for us >= 10 {
-			i--
-			q := us / 10
-			a[i] = byte(us - q*10 + '0')
-			us = q
+		// u guaranteed to fit into a uint
+		us := uint(u)
+		for us >= 100 {
+			is := us % 100 * 2
+			us /= 100
+			i -= 2
+			a[i+1] = smallsString[is+1]
+			a[i+0] = smallsString[is+0]
 		}
-		// u < 10
+
+		// us < 100
+		is := us * 2
 		i--
-		a[i] = byte(us + '0')
+		a[i] = smallsString[is+1]
+		if us >= 10 {
+			i--
+			a[i] = smallsString[is]
+		}
 
 	} else if s := shifts[base]; s > 0 {
 		// base is power of 2: use shifts and masks instead of / and %
 		b := uint64(base)
-		m := uintptr(b) - 1 // == 1<<s - 1
+		m := uint(base) - 1 // == 1<<s - 1
 		for u >= b {
 			i--
-			a[i] = digits[uintptr(u)&m]
+			a[i] = digits[uint(u)&m]
 			u >>= s
 		}
 		// u < base
 		i--
-		a[i] = digits[uintptr(u)]
-
+		a[i] = digits[uint(u)]
 	} else {
 		// general case
 		b := uint64(base)
 		for u >= b {
 			i--
+			// Avoid using r = a%b in addition to q = a/b
+			// since 64bit division and modulo operations
+			// are calculated by runtime functions on 32bit machines.
 			q := u / b
-			a[i] = digits[uintptr(u-q*b)]
+			a[i] = digits[uint(u-q*b)]
 			u = q
 		}
 		// u < base
 		i--
-		a[i] = digits[uintptr(u)]
+		a[i] = digits[uint(u)]
 	}
 
 	// add sign, if any
diff --git a/src/strconv/itoa_test.go b/src/strconv/itoa_test.go
index 48dc03e..89c2de6 100644
--- a/src/strconv/itoa_test.go
+++ b/src/strconv/itoa_test.go
@@ -126,10 +126,46 @@ func TestUitoa(t *testing.T) {
 	}
 }
 
+var varlenUints = []struct {
+	in  uint64
+	out string
+}{
+	{1, "1"},
+	{12, "12"},
+	{123, "123"},
+	{1234, "1234"},
+	{12345, "12345"},
+	{123456, "123456"},
+	{1234567, "1234567"},
+	{12345678, "12345678"},
+	{123456789, "123456789"},
+	{1234567890, "1234567890"},
+	{12345678901, "12345678901"},
+	{123456789012, "123456789012"},
+	{1234567890123, "1234567890123"},
+	{12345678901234, "12345678901234"},
+	{123456789012345, "123456789012345"},
+	{1234567890123456, "1234567890123456"},
+	{12345678901234567, "12345678901234567"},
+	{123456789012345678, "123456789012345678"},
+	{1234567890123456789, "1234567890123456789"},
+	{12345678901234567890, "12345678901234567890"},
+}
+
+func TestFormatUintVarlen(t *testing.T) {
+	for _, test := range varlenUints {
+		s := FormatUint(test.in, 10)
+		if s != test.out {
+			t.Errorf("FormatUint(%v, 10) = %v want %v", test.in, s, test.out)
+		}
+	}
+}
+
 func BenchmarkFormatInt(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		for _, test := range itob64tests {
-			FormatInt(test.in, test.base)
+			s := FormatInt(test.in, test.base)
+			BenchSink += len(s)
 		}
 	}
 }
@@ -138,7 +174,8 @@ func BenchmarkAppendInt(b *testing.B) {
 	dst := make([]byte, 0, 30)
 	for i := 0; i < b.N; i++ {
 		for _, test := range itob64tests {
-			AppendInt(dst, test.in, test.base)
+			dst = AppendInt(dst[:0], test.in, test.base)
+			BenchSink += len(dst)
 		}
 	}
 }
@@ -146,7 +183,8 @@ func BenchmarkAppendInt(b *testing.B) {
 func BenchmarkFormatUint(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		for _, test := range uitob64tests {
-			FormatUint(test.in, test.base)
+			s := FormatUint(test.in, test.base)
+			BenchSink += len(s)
 		}
 	}
 }
@@ -155,7 +193,39 @@ func BenchmarkAppendUint(b *testing.B) {
 	dst := make([]byte, 0, 30)
 	for i := 0; i < b.N; i++ {
 		for _, test := range uitob64tests {
-			AppendUint(dst, test.in, test.base)
+			dst = AppendUint(dst[:0], test.in, test.base)
+			BenchSink += len(dst)
 		}
 	}
 }
+
+func BenchmarkFormatIntSmall(b *testing.B) {
+	const smallInt = 42
+	for i := 0; i < b.N; i++ {
+		s := FormatInt(smallInt, 10)
+		BenchSink += len(s)
+	}
+}
+
+func BenchmarkAppendIntSmall(b *testing.B) {
+	dst := make([]byte, 0, 30)
+	const smallInt = 42
+	for i := 0; i < b.N; i++ {
+		dst = AppendInt(dst[:0], smallInt, 10)
+		BenchSink += len(dst)
+	}
+}
+
+func BenchmarkAppendUintVarlen(b *testing.B) {
+	for _, test := range varlenUints {
+		b.Run(test.out, func(b *testing.B) {
+			dst := make([]byte, 0, 30)
+			for j := 0; j < b.N; j++ {
+				dst = AppendUint(dst[:0], test.in, 10)
+				BenchSink += len(dst)
+			}
+		})
+	}
+}
+
+var BenchSink int // make sure compiler cannot optimize away benchmarks
diff --git a/src/strconv/quote.go b/src/strconv/quote.go
index 76c5c2a..db57065 100644
--- a/src/strconv/quote.go
+++ b/src/strconv/quote.go
@@ -32,7 +32,7 @@ func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly b
 			buf = append(buf, lowerhex[s[0]&0xF])
 			continue
 		}
-		buf = appendEscapedRune(buf, r, width, quote, ASCIIonly, graphicOnly)
+		buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly)
 	}
 	buf = append(buf, quote)
 	return buf
@@ -43,12 +43,12 @@ func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly
 	if !utf8.ValidRune(r) {
 		r = utf8.RuneError
 	}
-	buf = appendEscapedRune(buf, r, utf8.RuneLen(r), quote, ASCIIonly, graphicOnly)
+	buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly)
 	buf = append(buf, quote)
 	return buf
 }
 
-func appendEscapedRune(buf []byte, r rune, width int, quote byte, ASCIIonly, graphicOnly bool) []byte {
+func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
 	var runeTmp [utf8.UTFMax]byte
 	if r == rune(quote) || r == '\\' { // always backslashed
 		buf = append(buf, '\\')
diff --git a/src/strings/replace_test.go b/src/strings/replace_test.go
index 77e48b9..34b5bad 100644
--- a/src/strings/replace_test.go
+++ b/src/strings/replace_test.go
@@ -540,3 +540,44 @@ func BenchmarkByteByteMap(b *testing.B) {
 		Map(fn, str)
 	}
 }
+
+var mapdata = []struct{ name, data string }{
+	{"ASCII", "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"},
+	{"Greek", "α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω"},
+}
+
+func BenchmarkMap(b *testing.B) {
+	mapidentity := func(r rune) rune {
+		return r
+	}
+
+	b.Run("identity", func(b *testing.B) {
+		for _, md := range mapdata {
+			b.Run(md.name, func(b *testing.B) {
+				for i := 0; i < b.N; i++ {
+					Map(mapidentity, md.data)
+				}
+			})
+		}
+	})
+
+	mapchange := func(r rune) rune {
+		if 'a' <= r && r <= 'z' {
+			return r + 'A' - 'a'
+		}
+		if 'α' <= r && r <= 'ω' {
+			return r + 'Α' - 'α'
+		}
+		return r
+	}
+
+	b.Run("change", func(b *testing.B) {
+		for _, md := range mapdata {
+			b.Run(md.name, func(b *testing.B) {
+				for i := 0; i < b.N; i++ {
+					Map(mapchange, md.data)
+				}
+			})
+		}
+	})
+}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 60a281a..0c836c0 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -72,22 +72,20 @@ func hashStrRev(sep string) (uint32, uint32) {
 	return hash, pow
 }
 
-// Count counts the number of non-overlapping instances of sep in s.
-// If sep is an empty string, Count returns 1 + the number of Unicode code points in s.
-func Count(s, sep string) int {
-	n := 0
-	// special cases
-	if len(sep) == 0 {
+// countGeneric implements Count.
+func countGeneric(s, substr string) int {
+	// special case
+	if len(substr) == 0 {
 		return utf8.RuneCountInString(s) + 1
 	}
-	offset := 0
+	n := 0
 	for {
-		i := Index(s[offset:], sep)
+		i := Index(s, substr)
 		if i == -1 {
 			return n
 		}
 		n++
-		offset += i + len(sep)
+		s = s[i+len(substr):]
 	}
 }
 
@@ -106,16 +104,16 @@ func ContainsRune(s string, r rune) bool {
 	return IndexRune(s, r) >= 0
 }
 
-// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
-func LastIndex(s, sep string) int {
-	n := len(sep)
+// LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s.
+func LastIndex(s, substr string) int {
+	n := len(substr)
 	switch {
 	case n == 0:
 		return len(s)
 	case n == 1:
-		return LastIndexByte(s, sep[0])
+		return LastIndexByte(s, substr[0])
 	case n == len(s):
-		if sep == s {
+		if substr == s {
 			return 0
 		}
 		return -1
@@ -123,20 +121,20 @@ func LastIndex(s, sep string) int {
 		return -1
 	}
 	// Rabin-Karp search from the end of the string
-	hashsep, pow := hashStrRev(sep)
+	hashss, pow := hashStrRev(substr)
 	last := len(s) - n
 	var h uint32
 	for i := len(s) - 1; i >= last; i-- {
 		h = h*primeRK + uint32(s[i])
 	}
-	if h == hashsep && s[last:] == sep {
+	if h == hashss && s[last:] == substr {
 		return last
 	}
 	for i := last - 1; i >= 0; i-- {
 		h *= primeRK
 		h += uint32(s[i])
 		h -= pow * uint32(s[i+n])
-		if h == hashsep && s[i:i+n] == sep {
+		if h == hashss && s[i:i+n] == substr {
 			return i
 		}
 	}
@@ -240,61 +238,187 @@ func genSplit(s, sep string, sepSave, n int) []string {
 	if n < 0 {
 		n = Count(s, sep) + 1
 	}
-	c := sep[0]
-	start := 0
+
 	a := make([]string, n)
-	na := 0
-	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
-		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
-			a[na] = s[start : i+sepSave]
-			na++
-			start = i + len(sep)
-			i += len(sep) - 1
-		}
+	n--
+	i := 0
+	for i < n {
+		m := Index(s, sep)
+		if m < 0 {
+			break
+		}
+		a[i] = s[:m+sepSave]
+		s = s[m+len(sep):]
+		i++
 	}
-	a[na] = s[start:]
-	return a[0 : na+1]
+	a[i] = s
+	return a[:i+1]
 }
 
 // SplitN slices s into substrings separated by sep and returns a slice of
 // the substrings between those separators.
-// If sep is empty, SplitN splits after each UTF-8 sequence.
+//
 // The count determines the number of substrings to return:
 //   n > 0: at most n substrings; the last substring will be the unsplit remainder.
 //   n == 0: the result is nil (zero substrings)
 //   n < 0: all substrings
+//
+// Edge cases for s and sep (for example, empty strings) are handled
+// as described in the documentation for Split.
 func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
 
 // SplitAfterN slices s into substrings after each instance of sep and
 // returns a slice of those substrings.
-// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
+//
 // The count determines the number of substrings to return:
 //   n > 0: at most n substrings; the last substring will be the unsplit remainder.
 //   n == 0: the result is nil (zero substrings)
 //   n < 0: all substrings
+//
+// Edge cases for s and sep (for example, empty strings) are handled
+// as described in the documentation for SplitAfter.
 func SplitAfterN(s, sep string, n int) []string {
 	return genSplit(s, sep, len(sep), n)
 }
 
 // Split slices s into all substrings separated by sep and returns a slice of
 // the substrings between those separators.
-// If sep is empty, Split splits after each UTF-8 sequence.
+//
+// If s does not contain sep and sep is not empty, Split returns a
+// slice of length 1 whose only element is s.
+//
+// If sep is empty, Split splits after each UTF-8 sequence. If both s
+// and sep are empty, Split returns an empty slice.
+//
 // It is equivalent to SplitN with a count of -1.
 func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
 
 // SplitAfter slices s into all substrings after each instance of sep and
 // returns a slice of those substrings.
-// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+//
+// If s does not contain sep and sep is not empty, SplitAfter returns
+// a slice of length 1 whose only element is s.
+//
+// If sep is empty, SplitAfter splits after each UTF-8 sequence. If
+// both s and sep are empty, SplitAfter returns an empty slice.
+//
 // It is equivalent to SplitAfterN with a count of -1.
 func SplitAfter(s, sep string) []string {
 	return genSplit(s, sep, len(sep), -1)
 }
 
+var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
+
 // Fields splits the string s around each instance of one or more consecutive white space
 // characters, as defined by unicode.IsSpace, returning an array of substrings of s or an
 // empty list if s contains only white space.
 func Fields(s string) []string {
-	return FieldsFunc(s, unicode.IsSpace)
+	// First count the fields.
+	// This is an exact count if s is ASCII, otherwise it is an approximation.
+	n := 0
+	wasSpace := 1
+	// setBits is used to track which bits are set in the bytes of s.
+	setBits := uint8(0)
+	for i := 0; i < len(s); i++ {
+		r := s[i]
+		setBits |= r
+		isSpace := int(asciiSpace[r])
+		n += wasSpace & ^isSpace
+		wasSpace = isSpace
+	}
+
+	if setBits < utf8.RuneSelf { // ASCII fast path
+		a := make([]string, n)
+		na := 0
+		fieldStart := 0
+		i := 0
+		// Skip spaces in the front of the input.
+		for i < len(s) && asciiSpace[s[i]] != 0 {
+			i++
+		}
+		fieldStart = i
+		for i < len(s) {
+			if asciiSpace[s[i]] == 0 {
+				i++
+				continue
+			}
+			a[na] = s[fieldStart:i]
+			na++
+			i++
+			// Skip spaces in between fields.
+			for i < len(s) && asciiSpace[s[i]] != 0 {
+				i++
+			}
+			fieldStart = i
+		}
+		if fieldStart < len(s) { // Last field might end at EOF.
+			a[na] = s[fieldStart:]
+		}
+		return a
+	}
+
+	// Some runes in the input string are not ASCII.
+	// Same general approach as in the ASCII path but
+	// uses DecodeRuneInString and unicode.IsSpace if
+	// a non-ASCII rune needs to be decoded and checked
+	// if it corresponds to a space.
+	a := make([]string, 0, n)
+	fieldStart := 0
+	i := 0
+	// Skip spaces in the front of the input.
+	for i < len(s) {
+		if c := s[i]; c < utf8.RuneSelf {
+			if asciiSpace[c] == 0 {
+				break
+			}
+			i++
+		} else {
+			r, w := utf8.DecodeRuneInString(s[i:])
+			if !unicode.IsSpace(r) {
+				break
+			}
+			i += w
+		}
+	}
+	fieldStart = i
+	for i < len(s) {
+		if c := s[i]; c < utf8.RuneSelf {
+			if asciiSpace[c] == 0 {
+				i++
+				continue
+			}
+			a = append(a, s[fieldStart:i])
+			i++
+		} else {
+			r, w := utf8.DecodeRuneInString(s[i:])
+			if !unicode.IsSpace(r) {
+				i += w
+				continue
+			}
+			a = append(a, s[fieldStart:i])
+			i += w
+		}
+		// Skip spaces in between fields.
+		for i < len(s) {
+			if c := s[i]; c < utf8.RuneSelf {
+				if asciiSpace[c] == 0 {
+					break
+				}
+				i++
+			} else {
+				r, w := utf8.DecodeRuneInString(s[i:])
+				if !unicode.IsSpace(r) {
+					break
+				}
+				i += w
+			}
+		}
+		fieldStart = i
+	}
+	if fieldStart < len(s) { // Last field might end at EOF.
+		a = append(a, s[fieldStart:])
+	}
+	return a
 }
 
 // FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
@@ -383,40 +507,71 @@ 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.
-	maxbytes := len(s) // length of b
-	nbytes := 0        // number of bytes encoded in b
+
 	// The output buffer b is initialized on demand, the first
 	// time a character differs.
 	var b []byte
+	// nbytes is the number of bytes encoded in b.
+	var nbytes int
 
 	for i, c := range s {
 		r := mapping(c)
-		if b == nil {
-			if r == c {
-				continue
-			}
-			b = make([]byte, maxbytes)
-			nbytes = copy(b, s[:i])
+		if r == c {
+			continue
 		}
+
+		b = make([]byte, len(s)+utf8.UTFMax)
+		nbytes = copy(b, s[:i])
 		if r >= 0 {
-			wid := 1
-			if r >= utf8.RuneSelf {
-				wid = utf8.RuneLen(r)
+			if r <= utf8.RuneSelf {
+				b[nbytes] = byte(r)
+				nbytes++
+			} else {
+				nbytes += utf8.EncodeRune(b[nbytes:], r)
 			}
-			if nbytes+wid > maxbytes {
-				// Grow the buffer.
-				maxbytes = maxbytes*2 + utf8.UTFMax
-				nb := make([]byte, maxbytes)
-				copy(nb, b[0:nbytes])
-				b = nb
-			}
-			nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r)
 		}
+
+		if c == utf8.RuneError {
+			// RuneError is the result of either decoding
+			// an invalid sequence or '\uFFFD'. Determine
+			// the correct number of bytes we need to advance.
+			_, w := utf8.DecodeRuneInString(s[i:])
+			i += w
+		} else {
+			i += utf8.RuneLen(c)
+		}
+
+		s = s[i:]
+		break
 	}
+
 	if b == nil {
 		return s
 	}
-	return string(b[0:nbytes])
+
+	for _, c := range s {
+		r := mapping(c)
+
+		// common case
+		if (0 <= r && r <= utf8.RuneSelf) && nbytes < len(b) {
+			b[nbytes] = byte(r)
+			nbytes++
+			continue
+		}
+
+		// b is not big enough or r is not a ASCII rune.
+		if r >= 0 {
+			if nbytes+utf8.UTFMax >= len(b) {
+				// Grow the buffer.
+				nb := make([]byte, 2*len(b))
+				copy(nb, b[:nbytes])
+				b = nb
+			}
+			nbytes += utf8.EncodeRune(b[nbytes:], r)
+		}
+	}
+
+	return string(b[:nbytes])
 }
 
 // Repeat returns a new string consisting of count copies of the string s.
@@ -561,17 +716,10 @@ func LastIndexFunc(s string, f func(rune) bool) int {
 // truth==false, the sense of the predicate function is
 // inverted.
 func indexFunc(s string, f func(rune) bool, truth bool) int {
-	start := 0
-	for start < len(s) {
-		wid := 1
-		r := rune(s[start])
-		if r >= utf8.RuneSelf {
-			r, wid = utf8.DecodeRuneInString(s[start:])
-		}
+	for i, r := range s {
 		if f(r) == truth {
-			return start
+			return i
 		}
-		start += wid
 	}
 	return -1
 }
diff --git a/src/strings/strings_amd64.go b/src/strings/strings_amd64.go
index 23a98d5..a9c01bb 100644
--- a/src/strings/strings_amd64.go
+++ b/src/strings/strings_amd64.go
@@ -4,44 +4,46 @@
 
 package strings
 
+import "internal/cpu"
+
 //go:noescape
 
 // indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s.
 // indexShortStr requires 2 <= len(c) <= shortStringLen
-func indexShortStr(s, c string) int // ../runtime/asm_$GOARCH.s
-func supportAVX2() bool             // ../runtime/asm_$GOARCH.s
+func indexShortStr(s, c string) int  // ../runtime/asm_amd64.s
+func countByte(s string, c byte) int // ../runtime/asm_amd64.s
 
 var shortStringLen int
 
 func init() {
-	if supportAVX2() {
+	if cpu.X86.HasAVX2 {
 		shortStringLen = 63
 	} else {
 		shortStringLen = 31
 	}
 }
 
-// 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 string) int {
-	n := len(sep)
+// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
+func Index(s, substr string) int {
+	n := len(substr)
 	switch {
 	case n == 0:
 		return 0
 	case n == 1:
-		return IndexByte(s, sep[0])
+		return IndexByte(s, substr[0])
 	case n == len(s):
-		if sep == s {
+		if substr == s {
 			return 0
 		}
 		return -1
 	case n > len(s):
 		return -1
 	case n <= shortStringLen:
-		// Use brute force when s and sep both are small
+		// Use brute force when s and substr both are small
 		if len(s) <= 64 {
-			return indexShortStr(s, sep)
+			return indexShortStr(s, substr)
 		}
-		c := sep[0]
+		c := substr[0]
 		i := 0
 		t := s[:len(s)-n+1]
 		fails := 0
@@ -55,7 +57,7 @@ func Index(s, sep string) int {
 				}
 				i += o
 			}
-			if s[i:i+n] == sep {
+			if s[i:i+n] == substr {
 				return i
 			}
 			fails++
@@ -64,7 +66,7 @@ func Index(s, sep string) int {
 			// Too many means more that 1 error per 8 characters.
 			// Allow some errors in the beginning.
 			if fails > (i+16)/8 {
-				r := indexShortStr(s[i:], sep)
+				r := indexShortStr(s[i:], substr)
 				if r >= 0 {
 					return r + i
 				}
@@ -74,12 +76,12 @@ func Index(s, sep string) int {
 		return -1
 	}
 	// Rabin-Karp search
-	hashsep, pow := hashStr(sep)
+	hashss, pow := hashStr(substr)
 	var h uint32
 	for i := 0; i < n; i++ {
 		h = h*primeRK + uint32(s[i])
 	}
-	if h == hashsep && s[:n] == sep {
+	if h == hashss && s[:n] == substr {
 		return 0
 	}
 	for i := n; i < len(s); {
@@ -87,9 +89,18 @@ func Index(s, sep string) int {
 		h += uint32(s[i])
 		h -= pow * uint32(s[i-n])
 		i++
-		if h == hashsep && s[i-n:i] == sep {
+		if h == hashss && s[i-n:i] == substr {
 			return i - n
 		}
 	}
 	return -1
 }
+
+// Count counts the number of non-overlapping instances of substr in s.
+// If substr is an empty string, Count returns 1 + the number of Unicode code points in s.
+func Count(s, substr string) int {
+	if len(substr) == 1 && cpu.X86.HasPOPCNT {
+		return countByte(s, byte(substr[0]))
+	}
+	return countGeneric(s, substr)
+}
diff --git a/src/strings/strings_generic.go b/src/strings/strings_generic.go
index 6e80559..5429a74 100644
--- a/src/strings/strings_generic.go
+++ b/src/strings/strings_generic.go
@@ -9,16 +9,16 @@ package strings
 // TODO: implements short string optimization on non amd64 platforms
 // and get rid of strings_amd64.go
 
-// 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 string) int {
-	n := len(sep)
+// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
+func Index(s, substr string) int {
+	n := len(substr)
 	switch {
 	case n == 0:
 		return 0
 	case n == 1:
-		return IndexByte(s, sep[0])
+		return IndexByte(s, substr[0])
 	case n == len(s):
-		if sep == s {
+		if substr == s {
 			return 0
 		}
 		return -1
@@ -26,12 +26,12 @@ func Index(s, sep string) int {
 		return -1
 	}
 	// Rabin-Karp search
-	hashsep, pow := hashStr(sep)
+	hashss, pow := hashStr(substr)
 	var h uint32
 	for i := 0; i < n; i++ {
 		h = h*primeRK + uint32(s[i])
 	}
-	if h == hashsep && s[:n] == sep {
+	if h == hashss && s[:n] == substr {
 		return 0
 	}
 	for i := n; i < len(s); {
@@ -39,9 +39,15 @@ func Index(s, sep string) int {
 		h += uint32(s[i])
 		h -= pow * uint32(s[i-n])
 		i++
-		if h == hashsep && s[i-n:i] == sep {
+		if h == hashss && s[i-n:i] == substr {
 			return i - n
 		}
 	}
 	return -1
 }
+
+// Count counts the number of non-overlapping instances of substr in s.
+// If substr is an empty string, Count returns 1 + the number of Unicode code points in s.
+func Count(s, substr string) int {
+	return countGeneric(s, substr)
+}
diff --git a/src/strings/strings_s390x.go b/src/strings/strings_s390x.go
index 316a1b8..ccf2da6 100644
--- a/src/strings/strings_s390x.go
+++ b/src/strings/strings_s390x.go
@@ -24,27 +24,27 @@ func init() {
 	}
 }
 
-// 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 string) int {
-	n := len(sep)
+// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
+func Index(s, substr string) int {
+	n := len(substr)
 	switch {
 	case n == 0:
 		return 0
 	case n == 1:
-		return IndexByte(s, sep[0])
+		return IndexByte(s, substr[0])
 	case n == len(s):
-		if sep == s {
+		if substr == s {
 			return 0
 		}
 		return -1
 	case n > len(s):
 		return -1
 	case n <= shortStringLen:
-		// Use brute force when s and sep both are small
+		// Use brute force when s and substr both are small
 		if len(s) <= 64 {
-			return indexShortStr(s, sep)
+			return indexShortStr(s, substr)
 		}
-		c := sep[0]
+		c := substr[0]
 		i := 0
 		t := s[:len(s)-n+1]
 		fails := 0
@@ -58,7 +58,7 @@ func Index(s, sep string) int {
 				}
 				i += o
 			}
-			if s[i:i+n] == sep {
+			if s[i:i+n] == substr {
 				return i
 			}
 			fails++
@@ -67,7 +67,7 @@ func Index(s, sep string) int {
 			// Too many means more that 1 error per 8 characters.
 			// Allow some errors in the beginning.
 			if fails > (i+16)/8 {
-				r := indexShortStr(s[i:], sep)
+				r := indexShortStr(s[i:], substr)
 				if r >= 0 {
 					return r + i
 				}
@@ -77,12 +77,12 @@ func Index(s, sep string) int {
 		return -1
 	}
 	// Rabin-Karp search
-	hashsep, pow := hashStr(sep)
+	hashss, pow := hashStr(substr)
 	var h uint32
 	for i := 0; i < n; i++ {
 		h = h*primeRK + uint32(s[i])
 	}
-	if h == hashsep && s[:n] == sep {
+	if h == hashss && s[:n] == substr {
 		return 0
 	}
 	for i := n; i < len(s); {
@@ -90,9 +90,15 @@ func Index(s, sep string) int {
 		h += uint32(s[i])
 		h -= pow * uint32(s[i-n])
 		i++
-		if h == hashsep && s[i-n:i] == sep {
+		if h == hashss && s[i-n:i] == substr {
 			return i - n
 		}
 	}
 	return -1
 }
+
+// Count counts the number of non-overlapping instances of substr in s.
+// If substr is an empty string, Count returns 1 + the number of Unicode code points in s.
+func Count(s, substr string) int {
+	return countGeneric(s, substr)
+}
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index 4397949..869be9c 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -452,6 +452,7 @@ var fieldstests = []FieldsTest{
 	{"", []string{}},
 	{" ", []string{}},
 	{" \t ", []string{}},
+	{"\u2000", []string{}},
 	{"  abc  ", []string{"abc"}},
 	{"1 2 3 4", []string{"1", "2", "3", "4"}},
 	{"1  2  3  4", []string{"1", "2", "3", "4"}},
@@ -459,6 +460,9 @@ var fieldstests = []FieldsTest{
 	{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
 	{"\u2000\u2001\u2002", []string{}},
 	{"\n™\t™\n", []string{"™", "™"}},
+	{"\n\u20001™2\u2000 \u2001 ™", []string{"1™2", "™"}},
+	{"\n1\uFFFD \uFFFD2\u20003\uFFFD4", []string{"1\uFFFD", "\uFFFD2", "3\uFFFD4"}},
+	{"1\xFF\u2000\xFF2\xFF \xFF", []string{"1\xFF", "\xFF2\xFF", "\xFF"}},
 	{faces, []string{faces}},
 }
 
@@ -625,6 +629,19 @@ func TestMap(t *testing.T) {
 		(*reflect.StringHeader)(unsafe.Pointer(&m)).Data {
 		t.Error("unexpected copy during identity map")
 	}
+
+	// 7. Handle invalid UTF-8 sequence
+	replaceNotLatin := func(r rune) rune {
+		if unicode.Is(unicode.Latin, r) {
+			return r
+		}
+		return '?'
+	}
+	m = Map(replaceNotLatin, "Hello\255World")
+	expect = "Hello?World"
+	if m != expect {
+		t.Errorf("replace invalid sequence: expected %q got %q", expect, m)
+	}
 }
 
 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
@@ -1440,6 +1457,24 @@ func BenchmarkCountTortureOverlapping(b *testing.B) {
 	}
 }
 
+func BenchmarkCountByte(b *testing.B) {
+	indexSizes := []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
+	benchStr := Repeat(benchmarkString,
+		(indexSizes[len(indexSizes)-1]+len(benchmarkString)-1)/len(benchmarkString))
+	benchFunc := func(b *testing.B, benchStr string) {
+		b.SetBytes(int64(len(benchStr)))
+		for i := 0; i < b.N; i++ {
+			Count(benchStr, "=")
+		}
+	}
+	for _, size := range indexSizes {
+		b.Run(fmt.Sprintf("%d", size), func(b *testing.B) {
+			benchFunc(b, benchStr[:size])
+		})
+	}
+
+}
+
 var makeFieldsInput = func() string {
 	x := make([]byte, 1<<20)
 	// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
@@ -1460,40 +1495,88 @@ var makeFieldsInput = func() string {
 	return string(x)
 }
 
-var fieldsInput = makeFieldsInput()
+var makeFieldsInputASCII = func() string {
+	x := make([]byte, 1<<20)
+	// Input is ~10% space, rest ASCII non-space.
+	for i := range x {
+		if rand.Intn(10) == 0 {
+			x[i] = ' '
+		} else {
+			x[i] = 'x'
+		}
+	}
+	return string(x)
+}
+
+var stringdata = []struct{ name, data string }{
+	{"ASCII", makeFieldsInputASCII()},
+	{"Mixed", makeFieldsInput()},
+}
 
 func BenchmarkFields(b *testing.B) {
-	b.SetBytes(int64(len(fieldsInput)))
-	for i := 0; i < b.N; i++ {
-		Fields(fieldsInput)
+	for _, sd := range stringdata {
+		b.Run(sd.name, func(b *testing.B) {
+			for j := 1 << 4; j <= 1<<20; j <<= 4 {
+				b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
+					b.ReportAllocs()
+					b.SetBytes(int64(j))
+					data := sd.data[:j]
+					for i := 0; i < b.N; i++ {
+						Fields(data)
+					}
+				})
+			}
+		})
 	}
 }
 
 func BenchmarkFieldsFunc(b *testing.B) {
-	b.SetBytes(int64(len(fieldsInput)))
-	for i := 0; i < b.N; i++ {
-		FieldsFunc(fieldsInput, unicode.IsSpace)
+	for _, sd := range stringdata {
+		b.Run(sd.name, func(b *testing.B) {
+			for j := 1 << 4; j <= 1<<20; j <<= 4 {
+				b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
+					b.ReportAllocs()
+					b.SetBytes(int64(j))
+					data := sd.data[:j]
+					for i := 0; i < b.N; i++ {
+						FieldsFunc(data, unicode.IsSpace)
+					}
+				})
+			}
+		})
 	}
 }
 
-func BenchmarkSplit1(b *testing.B) {
+func BenchmarkSplitEmptySeparator(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Split(benchInputHard, "")
 	}
 }
 
-func BenchmarkSplit2(b *testing.B) {
+func BenchmarkSplitSingleByteSeparator(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Split(benchInputHard, "/")
 	}
 }
 
-func BenchmarkSplit3(b *testing.B) {
+func BenchmarkSplitMultiByteSeparator(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Split(benchInputHard, "hello")
 	}
 }
 
+func BenchmarkSplitNSingleByteSeparator(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		SplitN(benchInputHard, "/", 10)
+	}
+}
+
+func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		SplitN(benchInputHard, "hello", 10)
+	}
+}
+
 func BenchmarkRepeat(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Repeat("-", 80)
diff --git a/src/sync/atomic/asm_mips64x.s b/src/sync/atomic/asm_mips64x.s
index b7d4168..03aac87 100644
--- a/src/sync/atomic/asm_mips64x.s
+++ b/src/sync/atomic/asm_mips64x.s
@@ -6,12 +6,6 @@
 
 #include "textflag.h"
 
-#define LL(base, rt)	WORD	$((060<<26)|((base)<<21)|((rt)<<16))
-#define LLV(base, rt)	WORD	$((064<<26)|((base)<<21)|((rt)<<16))
-#define SC(base, rt)	WORD	$((070<<26)|((base)<<21)|((rt)<<16))
-#define SCV(base, rt)	WORD	$((074<<26)|((base)<<21)|((rt)<<16))
-#define SYNC	WORD $0xf
-
 TEXT ·SwapInt32(SB),NOSPLIT,$0-20
 	JMP	·SwapUint32(SB)
 
@@ -20,8 +14,8 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-20
 	MOVW	new+8(FP), R5
 	SYNC
 	MOVV	R5, R3
-	LL(2, 1)	// R1 = *R2
-	SC(2, 3)	// *R2 = R3
+	LL	(R2), R1
+	SC	R3, (R2)
 	BEQ	R3, -3(PC)
 	MOVW	R1, old+16(FP)
 	SYNC
@@ -35,8 +29,8 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 	MOVV	new+8(FP), R5
 	SYNC
 	MOVV	R5, R3
-	LLV(2, 1)	// R1 = *R2
-	SCV(2, 3)	// *R2 = R3
+	LLV	(R2), R1
+	SCV	R3, (R2)
 	BEQ	R3, -3(PC)
 	MOVV	R1, old+16(FP)
 	SYNC
@@ -55,9 +49,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 	SYNC
 cas_again:
 	MOVV	R5, R3
-	LL(1, 4)	// R4 = *R1
+	LL	(R1), R4
 	BNE	R2, R4, cas_fail
-	SC(1, 3)	// *R1 = R3
+	SC	R3, (R1)
 	BEQ	R3, cas_again
 	MOVV	$1, R1
 	MOVB	R1, swapped+16(FP)
@@ -80,9 +74,9 @@ TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
 	SYNC
 cas64_again:
 	MOVV	R5, R3
-	LLV(1, 4)	// R4 = *R1
+	LLV	(R1), R4
 	BNE	R2, R4, cas64_fail
-	SCV(1, 3)	// *R1 = R3
+	SCV	R3, (R1)
 	BEQ	R3, cas64_again
 	MOVV	$1, R1
 	MOVB	R1, swapped+24(FP)
@@ -99,10 +93,10 @@ TEXT ·AddUint32(SB),NOSPLIT,$0-20
 	MOVV	addr+0(FP), R2
 	MOVW	delta+8(FP), R3
 	SYNC
-	LL(2, 1)	// R1 = *R2
+	LL	(R2), R1
 	ADDU	R1, R3, R4
 	MOVV	R4, R1
-	SC(2, 4)	// *R2 = R4
+	SC	R4, (R2)
 	BEQ	R4, -4(PC)
 	MOVW	R1, new+16(FP)
 	SYNC
@@ -118,10 +112,10 @@ TEXT ·AddUint64(SB),NOSPLIT,$0-24
 	MOVV	addr+0(FP), R2
 	MOVV	delta+8(FP), R3
 	SYNC
-	LLV(2, 1)	// R1 = *R2
+	LLV	(R2), R1
 	ADDVU	R1, R3, R4
 	MOVV	R4, R1
-	SCV(2, 4)	// *R2 = R4
+	SCV	R4, (R2)
 	BEQ	R4, -4(PC)
 	MOVV	R1, new+16(FP)
 	SYNC
diff --git a/src/sync/atomic/asm_mipsx.s b/src/sync/atomic/asm_mipsx.s
index cf3318f..042b00b 100644
--- a/src/sync/atomic/asm_mipsx.s
+++ b/src/sync/atomic/asm_mipsx.s
@@ -12,13 +12,13 @@ TEXT ·SwapInt32(SB),NOSPLIT,$0-12
 TEXT ·SwapUint32(SB),NOSPLIT,$0-12
 	JMP	runtime∕internal∕atomic·Xchg(SB)
 
-TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+TEXT ·SwapInt64(SB),NOSPLIT,$0-20
 	JMP	runtime∕internal∕atomic·Xchg64(SB)
 
-TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+TEXT ·SwapUint64(SB),NOSPLIT,$0-20
 	JMP	runtime∕internal∕atomic·Xchg64(SB)
 
-TEXT ·SwapUintptr(SB),NOSPLIT,$0-20
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
 	JMP	runtime∕internal∕atomic·Xchg(SB)
 
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-13
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index 6d0831c..17baccb 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -953,16 +953,20 @@ func hammerSwapUint64(addr *uint64, count int) {
 	}
 }
 
+const arch32 = unsafe.Sizeof(uintptr(0)) == 4
+
 func hammerSwapUintptr64(uaddr *uint64, count int) {
 	// only safe when uintptr is 64-bit.
 	// not called on 32-bit systems.
-	addr := (*uintptr)(unsafe.Pointer(uaddr))
-	seed := int(uintptr(unsafe.Pointer(&count)))
-	for i := 0; i < count; i++ {
-		new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32
-		old := SwapUintptr(addr, new)
-		if old>>32 != old<<32>>32 {
-			panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+	if !arch32 {
+		addr := (*uintptr)(unsafe.Pointer(uaddr))
+		seed := int(uintptr(unsafe.Pointer(&count)))
+		for i := 0; i < count; i++ {
+			new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32
+			old := SwapUintptr(addr, new)
+			if old>>32 != old<<32>>32 {
+				panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+			}
 		}
 	}
 }
@@ -1116,8 +1120,6 @@ func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) {
 
 func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) {
 	addr := (*uintptr)(paddr)
-	var test64 uint64 = 1 << 50
-	arch32 := uintptr(test64) == 0
 	v := LoadUintptr(addr)
 	new := v
 	if arch32 {
@@ -1144,8 +1146,6 @@ func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) {
 
 func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) {
 	addr := (*unsafe.Pointer)(paddr)
-	var test64 uint64 = 1 << 50
-	arch32 := uintptr(test64) == 0
 	v := uintptr(LoadPointer(addr))
 	new := v
 	if arch32 {
@@ -1398,7 +1398,7 @@ func TestUnaligned64(t *testing.T) {
 
 	switch runtime.GOARCH {
 	default:
-		if unsafe.Sizeof(int(0)) != 4 {
+		if !arch32 {
 			t.Skip("test only runs on 32-bit systems")
 		}
 	case "amd64p32":
diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go
index 30abf72..1fc1f68 100644
--- a/src/sync/atomic/value.go
+++ b/src/sync/atomic/value.go
@@ -9,7 +9,6 @@ import (
 )
 
 // A Value provides an atomic load and store of a consistently typed value.
-// 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.
 //
diff --git a/src/sync/cond.go b/src/sync/cond.go
index c070d9d..14e2f6b 100644
--- a/src/sync/cond.go
+++ b/src/sync/cond.go
@@ -17,7 +17,6 @@ import (
 // which must be held when changing the condition and
 // when calling the Wait method.
 //
-// A Cond can be created as part of other structures.
 // A Cond must not be copied after first use.
 type Cond struct {
 	noCopy noCopy
diff --git a/src/sync/map.go b/src/sync/map.go
new file mode 100644
index 0000000..1238368
--- /dev/null
+++ b/src/sync/map.go
@@ -0,0 +1,367 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+import (
+	"sync/atomic"
+	"unsafe"
+)
+
+// Map is a concurrent map with amortized-constant-time loads, stores, and deletes.
+// It is safe for multiple goroutines to call a Map's methods concurrently.
+//
+// The zero Map is valid and empty.
+//
+// A Map must not be copied after first use.
+type Map struct {
+	mu Mutex
+
+	// read contains the portion of the map's contents that are safe for
+	// concurrent access (with or without mu held).
+	//
+	// The read field itself is always safe to load, but must only be stored with
+	// mu held.
+	//
+	// Entries stored in read may be updated concurrently without mu, but updating
+	// a previously-expunged entry requires that the entry be copied to the dirty
+	// map and unexpunged with mu held.
+	read atomic.Value // readOnly
+
+	// dirty contains the portion of the map's contents that require mu to be
+	// held. To ensure that the dirty map can be promoted to the read map quickly,
+	// it also includes all of the non-expunged entries in the read map.
+	//
+	// Expunged entries are not stored in the dirty map. An expunged entry in the
+	// clean map must be unexpunged and added to the dirty map before a new value
+	// can be stored to it.
+	//
+	// If the dirty map is nil, the next write to the map will initialize it by
+	// making a shallow copy of the clean map, omitting stale entries.
+	dirty map[interface{}]*entry
+
+	// misses counts the number of loads since the read map was last updated that
+	// needed to lock mu to determine whether the key was present.
+	//
+	// Once enough misses have occurred to cover the cost of copying the dirty
+	// map, the dirty map will be promoted to the read map (in the unamended
+	// state) and the next store to the map will make a new dirty copy.
+	misses int
+}
+
+// readOnly is an immutable struct stored atomically in the Map.read field.
+type readOnly struct {
+	m       map[interface{}]*entry
+	amended bool // true if the dirty map contains some key not in m.
+}
+
+// expunged is an arbitrary pointer that marks entries which have been deleted
+// from the dirty map.
+var expunged = unsafe.Pointer(new(interface{}))
+
+// An entry is a slot in the map corresponding to a particular key.
+type entry struct {
+	// p points to the interface{} value stored for the entry.
+	//
+	// If p == nil, the entry has been deleted and m.dirty == nil.
+	//
+	// If p == expunged, the entry has been deleted, m.dirty != nil, and the entry
+	// is missing from m.dirty.
+	//
+	// Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty
+	// != nil, in m.dirty[key].
+	//
+	// An entry can be deleted by atomic replacement with nil: when m.dirty is
+	// next created, it will atomically replace nil with expunged and leave
+	// m.dirty[key] unset.
+	//
+	// An entry's associated value can be updated by atomic replacement, provided
+	// p != expunged. If p == expunged, an entry's associated value can be updated
+	// only after first setting m.dirty[key] = e so that lookups using the dirty
+	// map find the entry.
+	p unsafe.Pointer // *interface{}
+}
+
+func newEntry(i interface{}) *entry {
+	return &entry{p: unsafe.Pointer(&i)}
+}
+
+// Load returns the value stored in the map for a key, or nil if no
+// value is present.
+// The ok result indicates whether value was found in the map.
+func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
+	read, _ := m.read.Load().(readOnly)
+	e, ok := read.m[key]
+	if !ok && read.amended {
+		m.mu.Lock()
+		// Avoid reporting a spurious miss if m.dirty got promoted while we were
+		// blocked on m.mu. (If further loads of the same key will not miss, it's
+		// not worth copying the dirty map for this key.)
+		read, _ = m.read.Load().(readOnly)
+		e, ok = read.m[key]
+		if !ok && read.amended {
+			e, ok = m.dirty[key]
+			// Regardless of whether the entry was present, record a miss: this key
+			// will take the slow path until the dirty map is promoted to the read
+			// map.
+			m.missLocked()
+		}
+		m.mu.Unlock()
+	}
+	if !ok {
+		return nil, false
+	}
+	return e.load()
+}
+
+func (e *entry) load() (value interface{}, ok bool) {
+	p := atomic.LoadPointer(&e.p)
+	if p == nil || p == expunged {
+		return nil, false
+	}
+	return *(*interface{})(p), true
+}
+
+// Store sets the value for a key.
+func (m *Map) Store(key, value interface{}) {
+	read, _ := m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok && e.tryStore(&value) {
+		return
+	}
+
+	m.mu.Lock()
+	read, _ = m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		if e.unexpungeLocked() {
+			// The entry was previously expunged, which implies that there is a
+			// non-nil dirty map and this entry is not in it.
+			m.dirty[key] = e
+		}
+		e.storeLocked(&value)
+	} else if e, ok := m.dirty[key]; ok {
+		e.storeLocked(&value)
+	} else {
+		if !read.amended {
+			// We're adding the first new key to the dirty map.
+			// Make sure it is allocated and mark the read-only map as incomplete.
+			m.dirtyLocked()
+			m.read.Store(readOnly{m: read.m, amended: true})
+		}
+		m.dirty[key] = newEntry(value)
+	}
+	m.mu.Unlock()
+}
+
+// tryStore stores a value if the entry has not been expunged.
+//
+// If the entry is expunged, tryStore returns false and leaves the entry
+// unchanged.
+func (e *entry) tryStore(i *interface{}) bool {
+	p := atomic.LoadPointer(&e.p)
+	if p == expunged {
+		return false
+	}
+	for {
+		if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
+			return true
+		}
+		p = atomic.LoadPointer(&e.p)
+		if p == expunged {
+			return false
+		}
+	}
+}
+
+// unexpungeLocked ensures that the entry is not marked as expunged.
+//
+// If the entry was previously expunged, it must be added to the dirty map
+// before m.mu is unlocked.
+func (e *entry) unexpungeLocked() (wasExpunged bool) {
+	return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
+}
+
+// storeLocked unconditionally stores a value to the entry.
+//
+// The entry must be known not to be expunged.
+func (e *entry) storeLocked(i *interface{}) {
+	atomic.StorePointer(&e.p, unsafe.Pointer(i))
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
+	// Avoid locking if it's a clean hit.
+	read, _ := m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		actual, loaded, ok := e.tryLoadOrStore(value)
+		if ok {
+			return actual, loaded
+		}
+	}
+
+	m.mu.Lock()
+	read, _ = m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		if e.unexpungeLocked() {
+			m.dirty[key] = e
+		}
+		actual, loaded, _ = e.tryLoadOrStore(value)
+	} else if e, ok := m.dirty[key]; ok {
+		actual, loaded, _ = e.tryLoadOrStore(value)
+		m.missLocked()
+	} else {
+		if !read.amended {
+			// We're adding the first new key to the dirty map.
+			// Make sure it is allocated and mark the read-only map as incomplete.
+			m.dirtyLocked()
+			m.read.Store(readOnly{m: read.m, amended: true})
+		}
+		m.dirty[key] = newEntry(value)
+		actual, loaded = value, false
+	}
+	m.mu.Unlock()
+
+	return actual, loaded
+}
+
+// tryLoadOrStore atomically loads or stores a value if the entry is not
+// expunged.
+//
+// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
+// returns with ok==false.
+func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) {
+	p := atomic.LoadPointer(&e.p)
+	if p == expunged {
+		return nil, false, false
+	}
+	if p != nil {
+		return *(*interface{})(p), true, true
+	}
+
+	// Copy the interface after the first load to make this method more amenable
+	// to escape analysis: if we hit the "load" path or the entry is expunged, we
+	// shouldn't bother heap-allocating.
+	ic := i
+	for {
+		if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
+			return i, false, true
+		}
+		p = atomic.LoadPointer(&e.p)
+		if p == expunged {
+			return nil, false, false
+		}
+		if p != nil {
+			return *(*interface{})(p), true, true
+		}
+	}
+}
+
+// Delete deletes the value for a key.
+func (m *Map) Delete(key interface{}) {
+	read, _ := m.read.Load().(readOnly)
+	e, ok := read.m[key]
+	if !ok && read.amended {
+		m.mu.Lock()
+		read, _ = m.read.Load().(readOnly)
+		e, ok = read.m[key]
+		if !ok && read.amended {
+			delete(m.dirty, key)
+		}
+		m.mu.Unlock()
+	}
+	if ok {
+		e.delete()
+	}
+}
+
+func (e *entry) delete() (hadValue bool) {
+	for {
+		p := atomic.LoadPointer(&e.p)
+		if p == nil || p == expunged {
+			return false
+		}
+		if atomic.CompareAndSwapPointer(&e.p, p, nil) {
+			return true
+		}
+	}
+}
+
+// Range calls f sequentially for each key and value present in the map.
+// If f returns false, range stops the iteration.
+//
+// Range does not necessarily correspond to any consistent snapshot of the Map's
+// contents: no key will be visited more than once, but if the value for any key
+// is stored or deleted concurrently, Range may reflect any mapping for that key
+// from any point during the Range call.
+//
+// Range may be O(N) with the number of elements in the map even if f returns
+// false after a constant number of calls.
+func (m *Map) Range(f func(key, value interface{}) bool) {
+	// We need to be able to iterate over all of the keys that were already
+	// present at the start of the call to Range.
+	// If read.amended is false, then read.m satisfies that property without
+	// requiring us to hold m.mu for a long time.
+	read, _ := m.read.Load().(readOnly)
+	if read.amended {
+		// m.dirty contains keys not in read.m. Fortunately, Range is already O(N)
+		// (assuming the caller does not break out early), so a call to Range
+		// amortizes an entire copy of the map: we can promote the dirty copy
+		// immediately!
+		m.mu.Lock()
+		read, _ = m.read.Load().(readOnly)
+		if read.amended {
+			read = readOnly{m: m.dirty}
+			m.read.Store(read)
+			m.dirty = nil
+			m.misses = 0
+		}
+		m.mu.Unlock()
+	}
+
+	for k, e := range read.m {
+		v, ok := e.load()
+		if !ok {
+			continue
+		}
+		if !f(k, v) {
+			break
+		}
+	}
+}
+
+func (m *Map) missLocked() {
+	m.misses++
+	if m.misses < len(m.dirty) {
+		return
+	}
+	m.read.Store(readOnly{m: m.dirty})
+	m.dirty = nil
+	m.misses = 0
+}
+
+func (m *Map) dirtyLocked() {
+	if m.dirty != nil {
+		return
+	}
+
+	read, _ := m.read.Load().(readOnly)
+	m.dirty = make(map[interface{}]*entry, len(read.m))
+	for k, e := range read.m {
+		if !e.tryExpungeLocked() {
+			m.dirty[k] = e
+		}
+	}
+}
+
+func (e *entry) tryExpungeLocked() (isExpunged bool) {
+	p := atomic.LoadPointer(&e.p)
+	for p == nil {
+		if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
+			return true
+		}
+		p = atomic.LoadPointer(&e.p)
+	}
+	return p == expunged
+}
diff --git a/src/sync/map_bench_test.go b/src/sync/map_bench_test.go
new file mode 100644
index 0000000..a5590a5
--- /dev/null
+++ b/src/sync/map_bench_test.go
@@ -0,0 +1,217 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+	"fmt"
+	"reflect"
+	"sync"
+	"sync/atomic"
+	"testing"
+)
+
+type bench struct {
+	setup func(*testing.B, mapInterface)
+	perG  func(b *testing.B, pb *testing.PB, i int, m mapInterface)
+}
+
+func benchMap(b *testing.B, bench bench) {
+	for _, m := range [...]mapInterface{&DeepCopyMap{}, &RWMutexMap{}, &sync.Map{}} {
+		b.Run(fmt.Sprintf("%T", m), func(b *testing.B) {
+			m = reflect.New(reflect.TypeOf(m).Elem()).Interface().(mapInterface)
+			if bench.setup != nil {
+				bench.setup(b, m)
+			}
+
+			b.ResetTimer()
+
+			var i int64
+			b.RunParallel(func(pb *testing.PB) {
+				id := int(atomic.AddInt64(&i, 1) - 1)
+				bench.perG(b, pb, id*b.N, m)
+			})
+		})
+	}
+}
+
+func BenchmarkLoadMostlyHits(b *testing.B) {
+	const hits, misses = 1023, 1
+
+	benchMap(b, bench{
+		setup: func(_ *testing.B, m mapInterface) {
+			for i := 0; i < hits; i++ {
+				m.LoadOrStore(i, i)
+			}
+			// Prime the map to get it into a steady state.
+			for i := 0; i < hits*2; i++ {
+				m.Load(i % hits)
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.Load(i % (hits + misses))
+			}
+		},
+	})
+}
+
+func BenchmarkLoadMostlyMisses(b *testing.B) {
+	const hits, misses = 1, 1023
+
+	benchMap(b, bench{
+		setup: func(_ *testing.B, m mapInterface) {
+			for i := 0; i < hits; i++ {
+				m.LoadOrStore(i, i)
+			}
+			// Prime the map to get it into a steady state.
+			for i := 0; i < hits*2; i++ {
+				m.Load(i % hits)
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.Load(i % (hits + misses))
+			}
+		},
+	})
+}
+
+func BenchmarkLoadOrStoreBalanced(b *testing.B) {
+	const hits, misses = 128, 128
+
+	benchMap(b, bench{
+		setup: func(b *testing.B, m mapInterface) {
+			if _, ok := m.(*DeepCopyMap); ok {
+				b.Skip("DeepCopyMap has quadratic running time.")
+			}
+			for i := 0; i < hits; i++ {
+				m.LoadOrStore(i, i)
+			}
+			// Prime the map to get it into a steady state.
+			for i := 0; i < hits*2; i++ {
+				m.Load(i % hits)
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				j := i % (hits + misses)
+				if j < hits {
+					if _, ok := m.LoadOrStore(j, i); !ok {
+						b.Fatalf("unexpected miss for %v", j)
+					}
+				} else {
+					if v, loaded := m.LoadOrStore(i, i); loaded {
+						b.Fatalf("failed to store %v: existing value %v", i, v)
+					}
+				}
+			}
+		},
+	})
+}
+
+func BenchmarkLoadOrStoreUnique(b *testing.B) {
+	benchMap(b, bench{
+		setup: func(b *testing.B, m mapInterface) {
+			if _, ok := m.(*DeepCopyMap); ok {
+				b.Skip("DeepCopyMap has quadratic running time.")
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.LoadOrStore(i, i)
+			}
+		},
+	})
+}
+
+func BenchmarkLoadOrStoreCollision(b *testing.B) {
+	benchMap(b, bench{
+		setup: func(_ *testing.B, m mapInterface) {
+			m.LoadOrStore(0, 0)
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.LoadOrStore(0, 0)
+			}
+		},
+	})
+}
+
+func BenchmarkRange(b *testing.B) {
+	const mapSize = 1 << 10
+
+	benchMap(b, bench{
+		setup: func(_ *testing.B, m mapInterface) {
+			for i := 0; i < mapSize; i++ {
+				m.Store(i, i)
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.Range(func(_, _ interface{}) bool { return true })
+			}
+		},
+	})
+}
+
+// BenchmarkAdversarialAlloc tests performance when we store a new value
+// immediately whenever the map is promoted to clean and otherwise load a
+// unique, missing key.
+//
+// This forces the Load calls to always acquire the map's mutex.
+func BenchmarkAdversarialAlloc(b *testing.B) {
+	benchMap(b, bench{
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			var stores, loadsSinceStore int64
+			for ; pb.Next(); i++ {
+				m.Load(i)
+				if loadsSinceStore++; loadsSinceStore > stores {
+					m.LoadOrStore(i, stores)
+					loadsSinceStore = 0
+					stores++
+				}
+			}
+		},
+	})
+}
+
+// BenchmarkAdversarialDelete tests performance when we periodically delete
+// one key and add a different one in a large map.
+//
+// This forces the Load calls to always acquire the map's mutex and periodically
+// makes a full copy of the map despite changing only one entry.
+func BenchmarkAdversarialDelete(b *testing.B) {
+	const mapSize = 1 << 10
+
+	benchMap(b, bench{
+		setup: func(_ *testing.B, m mapInterface) {
+			for i := 0; i < mapSize; i++ {
+				m.Store(i, i)
+			}
+		},
+
+		perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
+			for ; pb.Next(); i++ {
+				m.Load(i)
+
+				if i%mapSize == 0 {
+					var key int
+					m.Range(func(k, _ interface{}) bool {
+						key = k.(int)
+						return false
+					})
+					m.Delete(key)
+					m.Store(i, i)
+				}
+			}
+		},
+	})
+}
diff --git a/src/sync/map_reference_test.go b/src/sync/map_reference_test.go
new file mode 100644
index 0000000..b21018c
--- /dev/null
+++ b/src/sync/map_reference_test.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.
+
+package sync_test
+
+import (
+	"sync"
+	"sync/atomic"
+)
+
+// This file contains reference map implementations for unit-tests.
+
+// mapInterface is the interface Map implements.
+type mapInterface interface {
+	Load(interface{}) (interface{}, bool)
+	Store(key, value interface{})
+	LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
+	Delete(interface{})
+	Range(func(key, value interface{}) (shouldContinue bool))
+}
+
+// RWMutexMap is an implementation of mapInterface using a sync.RWMutex.
+type RWMutexMap struct {
+	mu    sync.RWMutex
+	dirty map[interface{}]interface{}
+}
+
+func (m *RWMutexMap) Load(key interface{}) (value interface{}, ok bool) {
+	m.mu.RLock()
+	value, ok = m.dirty[key]
+	m.mu.RUnlock()
+	return
+}
+
+func (m *RWMutexMap) Store(key, value interface{}) {
+	m.mu.Lock()
+	if m.dirty == nil {
+		m.dirty = make(map[interface{}]interface{})
+	}
+	m.dirty[key] = value
+	m.mu.Unlock()
+}
+
+func (m *RWMutexMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
+	m.mu.Lock()
+	actual, loaded = m.dirty[key]
+	if !loaded {
+		actual = value
+		if m.dirty == nil {
+			m.dirty = make(map[interface{}]interface{})
+		}
+		m.dirty[key] = value
+	}
+	m.mu.Unlock()
+	return actual, loaded
+}
+
+func (m *RWMutexMap) Delete(key interface{}) {
+	m.mu.Lock()
+	delete(m.dirty, key)
+	m.mu.Unlock()
+}
+
+func (m *RWMutexMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
+	m.mu.RLock()
+	defer m.mu.RUnlock()
+	for k, v := range m.dirty {
+		if !f(k, v) {
+			break
+		}
+	}
+}
+
+// DeepCopyMap is an implementation of mapInterface using a Mutex and
+// atomic.Value.  It makes deep copies of the map on every write to avoid
+// acquiring the Mutex in Load.
+type DeepCopyMap struct {
+	mu    sync.Mutex
+	clean atomic.Value
+}
+
+func (m *DeepCopyMap) Load(key interface{}) (value interface{}, ok bool) {
+	clean, _ := m.clean.Load().(map[interface{}]interface{})
+	value, ok = clean[key]
+	return value, ok
+}
+
+func (m *DeepCopyMap) Store(key, value interface{}) {
+	m.mu.Lock()
+	dirty := m.dirty()
+	dirty[key] = value
+	m.clean.Store(dirty)
+	m.mu.Unlock()
+}
+
+func (m *DeepCopyMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
+	clean, _ := m.clean.Load().(map[interface{}]interface{})
+	actual, loaded = clean[key]
+	if loaded {
+		return actual, loaded
+	}
+
+	m.mu.Lock()
+	// Reload clean in case it changed while we were waiting on m.mu.
+	clean, _ = m.clean.Load().(map[interface{}]interface{})
+	actual, loaded = clean[key]
+	if !loaded {
+		dirty := m.dirty()
+		dirty[key] = value
+		actual = value
+		m.clean.Store(dirty)
+	}
+	m.mu.Unlock()
+	return actual, loaded
+}
+
+func (m *DeepCopyMap) Delete(key interface{}) {
+	m.mu.Lock()
+	dirty := m.dirty()
+	delete(dirty, key)
+	m.clean.Store(dirty)
+	m.mu.Unlock()
+}
+
+func (m *DeepCopyMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
+	clean, _ := m.clean.Load().(map[interface{}]interface{})
+	for k, v := range clean {
+		if !f(k, v) {
+			break
+		}
+	}
+}
+
+func (m *DeepCopyMap) dirty() map[interface{}]interface{} {
+	clean, _ := m.clean.Load().(map[interface{}]interface{})
+	dirty := make(map[interface{}]interface{}, len(clean)+1)
+	for k, v := range clean {
+		dirty[k] = v
+	}
+	return dirty
+}
diff --git a/src/sync/map_test.go b/src/sync/map_test.go
new file mode 100644
index 0000000..b60a1c7
--- /dev/null
+++ b/src/sync/map_test.go
@@ -0,0 +1,170 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+	"math/rand"
+	"reflect"
+	"runtime"
+	"sync"
+	"testing"
+	"testing/quick"
+)
+
+type mapOp string
+
+const (
+	opLoad        = mapOp("Load")
+	opStore       = mapOp("Store")
+	opLoadOrStore = mapOp("LoadOrStore")
+	opDelete      = mapOp("Delete")
+)
+
+var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opDelete}
+
+// mapCall is a quick.Generator for calls on mapInterface.
+type mapCall struct {
+	op   mapOp
+	k, v interface{}
+}
+
+func (c mapCall) apply(m mapInterface) (interface{}, bool) {
+	switch c.op {
+	case opLoad:
+		return m.Load(c.k)
+	case opStore:
+		m.Store(c.k, c.v)
+		return nil, false
+	case opLoadOrStore:
+		return m.LoadOrStore(c.k, c.v)
+	case opDelete:
+		m.Delete(c.k)
+		return nil, false
+	default:
+		panic("invalid mapOp")
+	}
+}
+
+type mapResult struct {
+	value interface{}
+	ok    bool
+}
+
+func randValue(r *rand.Rand) interface{} {
+	b := make([]byte, r.Intn(4))
+	for i := range b {
+		b[i] = 'a' + byte(rand.Intn(26))
+	}
+	return string(b)
+}
+
+func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
+	c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)}
+	switch c.op {
+	case opStore, opLoadOrStore:
+		c.v = randValue(r)
+	}
+	return reflect.ValueOf(c)
+}
+
+func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
+	for _, c := range calls {
+		v, ok := c.apply(m)
+		results = append(results, mapResult{v, ok})
+	}
+
+	final = make(map[interface{}]interface{})
+	m.Range(func(k, v interface{}) bool {
+		final[k] = v
+		return true
+	})
+
+	return results, final
+}
+
+func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
+	return applyCalls(new(sync.Map), calls)
+}
+
+func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
+	return applyCalls(new(RWMutexMap), calls)
+}
+
+func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
+	return applyCalls(new(DeepCopyMap), calls)
+}
+
+func TestMapMatchesRWMutex(t *testing.T) {
+	if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestMapMatchesDeepCopy(t *testing.T) {
+	if err := quick.CheckEqual(applyMap, applyDeepCopyMap, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestConcurrentRange(t *testing.T) {
+	const mapSize = 1 << 10
+
+	m := new(sync.Map)
+	for n := int64(1); n <= mapSize; n++ {
+		m.Store(n, int64(n))
+	}
+
+	done := make(chan struct{})
+	var wg sync.WaitGroup
+	defer func() {
+		close(done)
+		wg.Wait()
+	}()
+	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
+		r := rand.New(rand.NewSource(g))
+		wg.Add(1)
+		go func(g int64) {
+			defer wg.Done()
+			for i := int64(0); ; i++ {
+				select {
+				case <-done:
+					return
+				default:
+				}
+				for n := int64(1); n < mapSize; n++ {
+					if r.Int63n(mapSize) == 0 {
+						m.Store(n, n*i*g)
+					} else {
+						m.Load(n)
+					}
+				}
+			}
+		}(g)
+	}
+
+	iters := 1 << 10
+	if testing.Short() {
+		iters = 16
+	}
+	for n := iters; n > 0; n-- {
+		seen := make(map[int64]bool, mapSize)
+
+		m.Range(func(ki, vi interface{}) bool {
+			k, v := ki.(int64), vi.(int64)
+			if v%k != 0 {
+				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
+			}
+			if seen[k] {
+				t.Fatalf("Range visited key %v twice", k)
+			}
+			seen[k] = true
+			return true
+		})
+
+		if len(seen) != mapSize {
+			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
+		}
+	}
+}
diff --git a/src/sync/mutex.go b/src/sync/mutex.go
index 8c9366f..1232c62 100644
--- a/src/sync/mutex.go
+++ b/src/sync/mutex.go
@@ -19,8 +19,7 @@ import (
 func throw(string) // provided by runtime
 
 // 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.
+// The zero value for a Mutex is an unlocked mutex.
 //
 // A Mutex must not be copied after first use.
 type Mutex struct {
@@ -37,7 +36,34 @@ type Locker interface {
 const (
 	mutexLocked = 1 << iota // mutex is locked
 	mutexWoken
+	mutexStarving
 	mutexWaiterShift = iota
+
+	// Mutex fairness.
+	//
+	// Mutex can be in 2 modes of operations: normal and starvation.
+	// In normal mode waiters are queued in FIFO order, but a woken up waiter
+	// does not own the mutex and competes with new arriving goroutines over
+	// the ownership. New arriving goroutines have an advantage -- they are
+	// already running on CPU and there can be lots of them, so a woken up
+	// waiter has good chances of losing. In such case it is queued at front
+	// of the wait queue. If a waiter fails to acquire the mutex for more than 1ms,
+	// it switches mutex to the starvation mode.
+	//
+	// In starvation mode ownership of the mutex is directly handed off from
+	// the unlocking goroutine to the waiter at the front of the queue.
+	// New arriving goroutines don't try to acquire the mutex even if it appears
+	// to be unlocked, and don't try to spin. Instead they queue themselves at
+	// the tail of the wait queue.
+	//
+	// If a waiter receives ownership of the mutex and sees that either
+	// (1) it is the last waiter in the queue, or (2) it waited for less than 1 ms,
+	// it switches mutex back to normal operation mode.
+	//
+	// Normal mode has considerably better performance as a goroutine can acquire
+	// a mutex several times in a row even if there are blocked waiters.
+	// Starvation mode is important to prevent pathological cases of tail latency.
+	starvationThresholdNs = 1e6
 )
 
 // Lock locks m.
@@ -52,41 +78,86 @@ func (m *Mutex) Lock() {
 		return
 	}
 
+	var waitStartTime int64
+	starving := false
 	awoke := false
 	iter := 0
+	old := m.state
 	for {
-		old := m.state
-		new := old | mutexLocked
-		if old&mutexLocked != 0 {
-			if runtime_canSpin(iter) {
-				// Active spinning makes sense.
-				// Try to set mutexWoken flag to inform Unlock
-				// to not wake other blocked goroutines.
-				if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
-					atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
-					awoke = true
-				}
-				runtime_doSpin()
-				iter++
-				continue
+		// Don't spin in starvation mode, ownership is handed off to waiters
+		// so we won't be able to acquire the mutex anyway.
+		if old&(mutexLocked|mutexStarving) == mutexLocked && runtime_canSpin(iter) {
+			// Active spinning makes sense.
+			// Try to set mutexWoken flag to inform Unlock
+			// to not wake other blocked goroutines.
+			if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
+				atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
+				awoke = true
 			}
-			new = old + 1<<mutexWaiterShift
+			runtime_doSpin()
+			iter++
+			old = m.state
+			continue
+		}
+		new := old
+		// Don't try to acquire starving mutex, new arriving goroutines must queue.
+		if old&mutexStarving == 0 {
+			new |= mutexLocked
+		}
+		if old&(mutexLocked|mutexStarving) != 0 {
+			new += 1 << mutexWaiterShift
+		}
+		// The current goroutine switches mutex to starvation mode.
+		// But if the mutex is currently unlocked, don't do the switch.
+		// Unlock expects that starving mutex has waiters, which will not
+		// be true in this case.
+		if starving && old&mutexLocked != 0 {
+			new |= mutexStarving
 		}
 		if awoke {
 			// The goroutine has been woken from sleep,
 			// so we need to reset the flag in either case.
 			if new&mutexWoken == 0 {
-				throw("sync: inconsistent mutex state")
+				panic("sync: inconsistent mutex state")
 			}
 			new &^= mutexWoken
 		}
 		if atomic.CompareAndSwapInt32(&m.state, old, new) {
-			if old&mutexLocked == 0 {
+			if old&(mutexLocked|mutexStarving) == 0 {
+				break // locked the mutex with CAS
+			}
+			// If we were already waiting before, queue at the front of the queue.
+			queueLifo := waitStartTime != 0
+			if waitStartTime == 0 {
+				waitStartTime = runtime_nanotime()
+			}
+			runtime_SemacquireMutex(&m.sema, queueLifo)
+			starving = starving || runtime_nanotime()-waitStartTime > starvationThresholdNs
+			old = m.state
+			if old&mutexStarving != 0 {
+				// If this goroutine was woken and mutex is in starvation mode,
+				// ownership was handed off to us but mutex is in somewhat
+				// inconsistent state: mutexLocked is not set and we are still
+				// accounted as waiter. Fix that.
+				if old&(mutexLocked|mutexWoken) != 0 || old>>mutexWaiterShift == 0 {
+					panic("sync: inconsistent mutex state")
+				}
+				delta := int32(mutexLocked - 1<<mutexWaiterShift)
+				if !starving || old>>mutexWaiterShift == 1 {
+					// Exit starvation mode.
+					// Critical to do it here and consider wait time.
+					// Starvation mode is so inefficient, that two goroutines
+					// can go lock-step infinitely once they switch mutex
+					// to starvation mode.
+					delta -= mutexStarving
+				}
+				atomic.AddInt32(&m.state, delta)
 				break
 			}
-			runtime_SemacquireMutex(&m.sema)
 			awoke = true
 			iter = 0
+		} else {
+			old = m.state
 		}
 	}
 
@@ -110,22 +181,33 @@ func (m *Mutex) Unlock() {
 	// Fast path: drop lock bit.
 	new := atomic.AddInt32(&m.state, -mutexLocked)
 	if (new+mutexLocked)&mutexLocked == 0 {
-		throw("sync: unlock of unlocked mutex")
+		panic("sync: unlock of unlocked mutex")
 	}
-
-	old := new
-	for {
-		// If there are no waiters or a goroutine has already
-		// been woken or grabbed the lock, no need to wake anyone.
-		if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
-			return
-		}
-		// Grab the right to wake someone.
-		new = (old - 1<<mutexWaiterShift) | mutexWoken
-		if atomic.CompareAndSwapInt32(&m.state, old, new) {
-			runtime_Semrelease(&m.sema)
-			return
+	if new&mutexStarving == 0 {
+		old := new
+		for {
+			// If there are no waiters or a goroutine has already
+			// been woken or grabbed the lock, no need to wake anyone.
+			// In starvation mode ownership is directly handed off from unlocking
+			// goroutine to the next waiter. We are not part of this chain,
+			// since we did not observe mutexStarving when we unlocked the mutex above.
+			// So get off the way.
+			if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken|mutexStarving) != 0 {
+				return
+			}
+			// Grab the right to wake someone.
+			new = (old - 1<<mutexWaiterShift) | mutexWoken
+			if atomic.CompareAndSwapInt32(&m.state, old, new) {
+				runtime_Semrelease(&m.sema, false)
+				return
+			}
+			old = m.state
 		}
-		old = m.state
+	} else {
+		// Starving mode: handoff mutex ownership to the next waiter.
+		// Note: mutexLocked is not set, the waiter will set it after wakeup.
+		// But mutex is still considered locked if mutexStarving is set,
+		// so new coming goroutines won't acquire it.
+		runtime_Semrelease(&m.sema, true)
 	}
 }
diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go
index 88dbccf..784471d 100644
--- a/src/sync/mutex_test.go
+++ b/src/sync/mutex_test.go
@@ -15,12 +15,13 @@ import (
 	"strings"
 	. "sync"
 	"testing"
+	"time"
 )
 
 func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
 	for i := 0; i < loops; i++ {
 		Runtime_Semacquire(s)
-		Runtime_Semrelease(s)
+		Runtime_Semrelease(s, false)
 	}
 	cdone <- true
 }
@@ -174,6 +175,38 @@ func TestMutexMisuse(t *testing.T) {
 	}
 }
 
+func TestMutexFairness(t *testing.T) {
+	var mu Mutex
+	stop := make(chan bool)
+	defer close(stop)
+	go func() {
+		for {
+			mu.Lock()
+			time.Sleep(100 * time.Microsecond)
+			mu.Unlock()
+			select {
+			case <-stop:
+				return
+			default:
+			}
+		}
+	}()
+	done := make(chan bool)
+	go func() {
+		for i := 0; i < 10; i++ {
+			time.Sleep(100 * time.Microsecond)
+			mu.Lock()
+			mu.Unlock()
+		}
+		done <- true
+	}()
+	select {
+	case <-done:
+	case <-time.After(10 * time.Second):
+		t.Fatalf("can't acquire Mutex in 10 seconds")
+	}
+}
+
 func BenchmarkMutexUncontended(b *testing.B) {
 	type PaddedMutex struct {
 		Mutex
diff --git a/src/sync/pool.go b/src/sync/pool.go
index 0acdbde..e54f917 100644
--- a/src/sync/pool.go
+++ b/src/sync/pool.go
@@ -54,11 +54,18 @@ type Pool struct {
 }
 
 // Local per-P Pool appendix.
-type poolLocal struct {
+type poolLocalInternal struct {
 	private interface{}   // Can be used only by the respective P.
 	shared  []interface{} // Can be used by any P.
 	Mutex                 // Protects shared.
-	pad     [128]byte     // Prevents false sharing.
+}
+
+type poolLocal struct {
+	poolLocalInternal
+
+	// Prevents false sharing on widespread platforms with
+	// 128 mod (cache line size) = 0 .
+	pad [128 - unsafe.Sizeof(poolLocalInternal{})%128]byte
 }
 
 // from runtime
@@ -241,7 +248,8 @@ func init() {
 }
 
 func indexLocal(l unsafe.Pointer, i int) *poolLocal {
-	return &(*[1000000]poolLocal)(l)[i]
+	lp := unsafe.Pointer(uintptr(l) + uintptr(i)*unsafe.Sizeof(poolLocal{}))
+	return (*poolLocal)(lp)
 }
 
 // Implemented in runtime.
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index 4d22ce6..be16bcc 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -14,13 +14,15 @@ import "unsafe"
 func runtime_Semacquire(s *uint32)
 
 // SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
-func runtime_SemacquireMutex(*uint32)
+// If lifo is true, queue waiter at the head of wait queue.
+func runtime_SemacquireMutex(s *uint32, lifo bool)
 
 // Semrelease atomically increments *s and notifies a waiting goroutine
 // if one is blocked in Semacquire.
 // It is intended as a simple wakeup primitive for use by the synchronization
 // library and should not be used directly.
-func runtime_Semrelease(s *uint32)
+// If handoff is true, pass count directly to the first waiter.
+func runtime_Semrelease(s *uint32, handoff bool)
 
 // Approximation of notifyList in runtime/sema.go. Size and alignment must
 // agree.
@@ -57,3 +59,5 @@ func runtime_canSpin(i int) bool
 
 // runtime_doSpin does active spinning.
 func runtime_doSpin()
+
+func runtime_nanotime() int64
diff --git a/src/sync/runtime_sema_test.go b/src/sync/runtime_sema_test.go
index a2382f4..a680847 100644
--- a/src/sync/runtime_sema_test.go
+++ b/src/sync/runtime_sema_test.go
@@ -18,7 +18,7 @@ func BenchmarkSemaUncontended(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		sem := new(PaddedSem)
 		for pb.Next() {
-			Runtime_Semrelease(&sem.sem)
+			Runtime_Semrelease(&sem.sem, false)
 			Runtime_Semacquire(&sem.sem)
 		}
 	})
@@ -44,7 +44,7 @@ func benchmarkSema(b *testing.B, block, work bool) {
 	b.RunParallel(func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
-			Runtime_Semrelease(&sem)
+			Runtime_Semrelease(&sem, false)
 			if work {
 				for i := 0; i < 100; i++ {
 					foo *= 2
@@ -54,7 +54,7 @@ func benchmarkSema(b *testing.B, block, work bool) {
 			Runtime_Semacquire(&sem)
 		}
 		_ = foo
-		Runtime_Semrelease(&sem)
+		Runtime_Semrelease(&sem, false)
 	})
 }
 
diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go
index 71064ee..9488914 100644
--- a/src/sync/rwmutex.go
+++ b/src/sync/rwmutex.go
@@ -12,16 +12,16 @@ 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 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.
+// If a goroutine holds a RWMutex for reading and another goroutine might
+// call Lock, no goroutine should expect to be able to acquire a read lock
+// until the initial 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
@@ -33,6 +33,10 @@ type RWMutex struct {
 const rwmutexMaxReaders = 1 << 30
 
 // RLock locks rw for reading.
+//
+// It should not be used for recursive read locking; a blocked Lock
+// call excludes new readers from acquiring the lock. See the
+// documentation on the RWMutex type.
 func (rw *RWMutex) RLock() {
 	if race.Enabled {
 		_ = rw.w.state
@@ -66,7 +70,7 @@ func (rw *RWMutex) RUnlock() {
 		// A writer is pending.
 		if atomic.AddInt32(&rw.readerWait, -1) == 0 {
 			// The last reader unblocks the writer.
-			runtime_Semrelease(&rw.writerSem)
+			runtime_Semrelease(&rw.writerSem, false)
 		}
 	}
 	if race.Enabled {
@@ -119,7 +123,7 @@ func (rw *RWMutex) Unlock() {
 	}
 	// Unblock blocked readers, if any.
 	for i := 0; i < int(r); i++ {
-		runtime_Semrelease(&rw.readerSem)
+		runtime_Semrelease(&rw.readerSem, false)
 	}
 	// Allow other writers to proceed.
 	rw.w.Unlock()
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go
index b386e1f..4b23540 100644
--- a/src/sync/waitgroup.go
+++ b/src/sync/waitgroup.go
@@ -91,7 +91,7 @@ func (wg *WaitGroup) Add(delta int) {
 	// Reset waiters count to 0.
 	*statep = 0
 	for ; w != 0; w-- {
-		runtime_Semrelease(&wg.sema)
+		runtime_Semrelease(&wg.sema, false)
 	}
 }
 
diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go
index 8ec34fd..e3e3096 100644
--- a/src/sync/waitgroup_test.go
+++ b/src/sync/waitgroup_test.go
@@ -18,11 +18,11 @@ func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
 	wg2.Add(n)
 	exited := make(chan bool, n)
 	for i := 0; i != n; i++ {
-		go func(i int) {
+		go func() {
 			wg1.Done()
 			wg2.Wait()
 			exited <- true
-		}(i)
+		}()
 	}
 	wg1.Wait()
 	for i := 0; i != n; i++ {
@@ -70,11 +70,8 @@ func TestWaitGroupMisuse(t *testing.T) {
 
 func TestWaitGroupMisuse2(t *testing.T) {
 	knownRacy(t)
-	if testing.Short() {
-		t.Skip("skipping flaky test in short mode; see issue 11443")
-	}
-	if runtime.NumCPU() <= 2 {
-		t.Skip("NumCPU<=2, skipping: this test requires parallelism")
+	if runtime.NumCPU() <= 4 {
+		t.Skip("NumCPU<=4, skipping: this test requires parallelism")
 	}
 	defer func() {
 		err := recover()
@@ -86,24 +83,37 @@ func TestWaitGroupMisuse2(t *testing.T) {
 	}()
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 	done := make(chan interface{}, 2)
-	// The detection is opportunistically, so we want it to panic
+	// The detection is opportunistic, so we want it to panic
 	// at least in one run out of a million.
 	for i := 0; i < 1e6; i++ {
 		var wg WaitGroup
+		var here uint32
 		wg.Add(1)
 		go func() {
 			defer func() {
 				done <- recover()
 			}()
+			atomic.AddUint32(&here, 1)
+			for atomic.LoadUint32(&here) != 3 {
+				// spin
+			}
 			wg.Wait()
 		}()
 		go func() {
 			defer func() {
 				done <- recover()
 			}()
+			atomic.AddUint32(&here, 1)
+			for atomic.LoadUint32(&here) != 3 {
+				// spin
+			}
 			wg.Add(1) // This is the bad guy.
 			wg.Done()
 		}()
+		atomic.AddUint32(&here, 1)
+		for atomic.LoadUint32(&here) != 3 {
+			// spin
+		}
 		wg.Done()
 		for j := 0; j < 2; j++ {
 			if err := <-done; err != nil {
diff --git a/src/syscall/asm.s b/src/syscall/asm.s
deleted file mode 100644
index 06449eb..0000000
--- a/src/syscall/asm.s
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-TEXT ·use(SB),NOSPLIT,$0
-	RET
diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s
index 6634875..b7cd541 100644
--- a/src/syscall/asm_linux_amd64.s
+++ b/src/syscall/asm_linux_amd64.s
@@ -111,6 +111,29 @@ ok2:
 	MOVQ	$0, err+72(FP)
 	RET
 
+// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-32
+	MOVQ	a1+8(FP), DI
+	MOVQ	$0, SI
+	MOVQ	$0, DX
+	MOVQ	$0, R10
+	MOVQ	$0, R8
+	MOVQ	$0, R9
+	MOVQ	trap+0(FP), AX	// syscall entry
+	POPQ	R12 // preserve return address
+	SYSCALL
+	PUSHQ	R12
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	ok2
+	MOVQ	$-1, r1+16(FP)
+	NEGQ	AX
+	MOVQ	AX, err+24(FP)
+	RET
+ok2:
+	MOVQ	AX, r1+16(FP)
+	MOVQ	$0, err+24(FP)
+	RET
+
 // func gettimeofday(tv *Timeval) (err uintptr)
 TEXT ·gettimeofday(SB),NOSPLIT,$0-16
 	MOVQ	tv+0(FP), DI
diff --git a/src/syscall/asm_linux_mipsx.s b/src/syscall/asm_linux_mipsx.s
index 957f2a8..40ab82b 100644
--- a/src/syscall/asm_linux_mipsx.s
+++ b/src/syscall/asm_linux_mipsx.s
@@ -88,15 +88,15 @@ TEXT ·Syscall9(SB),NOSPLIT,$28-52
 	SYSCALL
 	BEQ	R7, ok9
 	MOVW	$-1, R1
-	MOVW	R1, r1+28(FP)	// r1
-	MOVW	R0, r2+32(FP)	// r2
-	MOVW	R2, err+36(FP)	// errno
+	MOVW	R1, r1+40(FP)	// r1
+	MOVW	R0, r2+44(FP)	// r2
+	MOVW	R2, err+48(FP)	// errno
 	JAL	runtime·exitsyscall(SB)
 	RET
 ok9:
-	MOVW	R2, r1+28(FP)	// r1
-	MOVW	R3, r2+32(FP)	// r2
-	MOVW	R0, err+36(FP)	// errno
+	MOVW	R2, r1+40(FP)	// r1
+	MOVW	R3, r2+44(FP)	// r2
+	MOVW	R0, err+48(FP)	// errno
 	JAL	runtime·exitsyscall(SB)
 	RET
 
diff --git a/src/syscall/asm_plan9_arm.s b/src/syscall/asm_plan9_arm.s
index aad515f..2a338a0 100644
--- a/src/syscall/asm_plan9_arm.s
+++ b/src/syscall/asm_plan9_arm.s
@@ -27,7 +27,7 @@ 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
+	SWI		$0
 	MOVM.DB.W	[R1-R2],(R13)	// push LR and caller's LR
 	MOVW	$0, R2
 	MOVW	$r1+16(FP), R1
@@ -42,7 +42,7 @@ 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
+	SWI		$0
 	MOVM.DB.W	[R1-R2],(R13)	// push LR and caller's LR
 	MOVW	$0, R1
 	MOVW	$r1+28(FP), R1
@@ -55,7 +55,7 @@ TEXT	·Syscall6(SB),NOSPLIT,$0-44
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVW	trap+0(FP), R0	// syscall num
 	MOVM.IA.W	(R13),[R1]		// pop caller's LR
-	SWI		0
+	SWI		$0
 	MOVM.DB.W	[R1],(R13)		// push caller's LR
 	MOVW	R0, r1+16(FP)
 	MOVW	R0, r2+20(FP)
@@ -67,7 +67,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVW	trap+0(FP), R0	// syscall num
 	MOVM.IA.W	(R13),[R1]		// pop caller's LR
-	SWI		0
+	SWI		$0
 	MOVM.DB.W	[R1],(R13)		// push caller's LR
 	MOVW	R0, r1+28(FP)
 	MOVW	R0, r2+32(FP)
@@ -80,7 +80,7 @@ TEXT ·seek(SB),NOSPLIT,$0-36
 	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
+	SWI		$0
 	MOVM.DB.W	[R1],(R13)		// push LR
 	CMP		$-1, R0
 	MOVW.EQ	R0, 0(R5)
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index 864473b..2ee85a0 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -87,7 +87,6 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) {
 		return nil, err
 	}
 	a, e := getprocaddress(uintptr(d.Handle), namep)
-	use(unsafe.Pointer(namep))
 	if e != 0 {
 		return nil, &DLLError{
 			Err:     e,
diff --git a/src/syscall/errors_plan9.go b/src/syscall/errors_plan9.go
index 6952562..74a5659 100644
--- a/src/syscall/errors_plan9.go
+++ b/src/syscall/errors_plan9.go
@@ -45,6 +45,7 @@ var (
 	// what package os and others expect.
 	EACCES       = NewError("access permission denied")
 	EAFNOSUPPORT = NewError("address family not supported by protocol")
+	ESPIPE       = NewError("illegal seek")
 )
 
 // Notes
diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go
index 317645f..17ca6f0 100644
--- a/src/syscall/exec_bsd.go
+++ b/src/syscall/exec_bsd.go
@@ -27,6 +27,7 @@ type SysProcAttr struct {
 // Implemented in runtime package.
 func runtime_BeforeFork()
 func runtime_AfterFork()
+func runtime_AfterForkInChild()
 
 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
 // If a dup or exec fails, write the errno error to pipe.
@@ -88,6 +89,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 
 	// Fork succeeded, now in child.
 
+	runtime_AfterForkInChild()
+
 	// Enable tracing if requested.
 	if sys.Ptrace {
 		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
@@ -146,9 +149,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		if ngroups > 0 {
 			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
 		}
-		_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
-		if err1 != 0 {
-			goto childerror
+		if !cred.NoSetGroups {
+			_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+			if err1 != 0 {
+				goto childerror
+			}
 		}
 		_, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
 		if err1 != 0 {
@@ -254,17 +259,3 @@ childerror:
 		RawSyscall(SYS_EXIT, 253, 0, 0)
 	}
 }
-
-// Try to open a pipe with O_CLOEXEC set on both file descriptors.
-func forkExecPipe(p []int) error {
-	err := Pipe(p)
-	if err != nil {
-		return err
-	}
-	_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
-	if err != nil {
-		return err
-	}
-	_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
-	return err
-}
diff --git a/src/syscall/exec_freebsd.go b/src/syscall/exec_freebsd.go
new file mode 100644
index 0000000..4ed32c0
--- /dev/null
+++ b/src/syscall/exec_freebsd.go
@@ -0,0 +1,25 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func forkExecPipe(p []int) error {
+	err := Pipe2(p, O_CLOEXEC)
+	if err == nil {
+		return nil
+	}
+
+	// FreeBSD 9 fallback.
+	// TODO: remove this for Go 1.10 per Issue 19072
+	err = Pipe(p)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+	return err
+}
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 979b6a2..e631cd6 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,9 +42,15 @@ type SysProcAttr struct {
 	GidMappingsEnableSetgroups bool
 }
 
+var (
+	none  = [...]byte{'n', 'o', 'n', 'e', 0}
+	slash = [...]byte{'/', 0}
+)
+
 // Implemented in runtime package.
 func runtime_BeforeFork()
 func runtime_AfterFork()
+func runtime_AfterForkInChild()
 
 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
 // If a dup or exec fails, write the errno error to pipe.
@@ -95,9 +101,12 @@ 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()
-	if runtime.GOARCH == "s390x" {
+	switch {
+	case runtime.GOARCH == "amd64" && sys.Cloneflags&CLONE_NEWUSER == 0:
+		r1, err1 = rawVforkSyscall(SYS_CLONE, uintptr(SIGCHLD|CLONE_VFORK|CLONE_VM)|sys.Cloneflags)
+	case runtime.GOARCH == "s390x":
 		r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0)
-	} else {
+	default:
 		r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
 	}
 	if err1 != 0 {
@@ -125,6 +134,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 
 	// Fork succeeded, now in child.
 
+	runtime_AfterForkInChild()
+
 	// Wait for User ID/Group ID mappings to be written.
 	if sys.UidMappings != nil || sys.GidMappings != nil {
 		if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
@@ -187,17 +198,30 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Chroot
-	if chroot != nil {
-		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
+	// Unshare
+	if sys.Unshareflags != 0 {
+		_, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0)
 		if err1 != 0 {
 			goto childerror
 		}
+		// The unshare system call in Linux doesn't unshare mount points
+		// mounted with --shared. Systemd mounts / with --shared. For a
+		// long discussion of the pros and cons of this see debian bug 739593.
+		// The Go model of unsharing is more like Plan 9, where you ask
+		// to unshare and the namespaces are unconditionally unshared.
+		// To make this model work we must further mark / as MS_PRIVATE.
+		// This is what the standard unshare command does.
+		if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+			_, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0)
+			if err1 != 0 {
+				goto childerror
+			}
+		}
 	}
 
-	// Unshare
-	if sys.Unshareflags != 0 {
-		_, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0)
+	// Chroot
+	if chroot != nil {
+		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -210,10 +234,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		if ngroups > 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) {
+		if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) && !cred.NoSetGroups {
 			_, _, err1 = RawSyscall(_SYS_setgroups, ngroups, groups, 0)
 			if err1 != 0 {
 				goto childerror
@@ -324,7 +345,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 
 	// Set the controlling TTY to Ctty
 	if sys.Setctty {
-		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
+		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 1)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..7a88968 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,9 +7,12 @@
 package syscall_test
 
 import (
+	"flag"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"os/exec"
+	"path/filepath"
 	"strings"
 	"syscall"
 	"testing"
@@ -205,9 +208,10 @@ func TestGroupCleanup(t *testing.T) {
 		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)"
+	expected := "uid=0(root) gid=0(root)"
 	// Just check prefix because some distros reportedly output a
 	// context parameter; see https://golang.org/issue/16224.
+	// Alpine does not output groups; see https://golang.org/issue/19938.
 	if !strings.HasPrefix(strOut, expected) {
 		t.Errorf("id command output: %q, expected prefix: %q", strOut, expected)
 	}
@@ -245,6 +249,7 @@ func TestGroupCleanupUserNamespace(t *testing.T) {
 		"uid=0(root) gid=0(root) groups=0(root),65534(nobody)",
 		"uid=0(root) gid=0(root) groups=0(root),65534(nogroup)",
 		"uid=0(root) gid=0(root) groups=0(root),65534",
+		"uid=0(root) gid=0(root) groups=0(root),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody)", // Alpine; see https://golang.org/issue/19938
 	}
 	for _, e := range expected {
 		if strOut == e {
@@ -253,3 +258,127 @@ func TestGroupCleanupUserNamespace(t *testing.T) {
 	}
 	t.Errorf("id command output: %q, expected one of %q", strOut, expected)
 }
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+		return
+	}
+	defer os.Exit(0)
+	if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+		fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+		os.Exit(2)
+	}
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(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")
+	}
+
+	d, err := ioutil.TempDir("", "unshare")
+	if err != nil {
+		t.Fatalf("tempdir: %v", err)
+	}
+
+	cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+	o, err := cmd.CombinedOutput()
+	if err != nil {
+		if strings.Contains(err.Error(), ": permission denied") {
+			t.Skipf("Skipping test (golang.org/issue/19698); unshare failed due to permissions: %s, %v", o, err)
+		}
+		t.Fatalf("unshare failed: %s, %v", o, err)
+	}
+
+	// How do we tell if the namespace was really unshared? It turns out
+	// to be simple: just try to remove the directory. If it's still mounted
+	// on the rm will fail with EBUSY. Then we have some cleanup to do:
+	// we must unmount it, then try to remove it again.
+
+	if err := os.Remove(d); err != nil {
+		t.Errorf("rmdir failed on %v: %v", d, err)
+		if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+			t.Errorf("Can't unmount %v: %v", d, err)
+		}
+		if err := os.Remove(d); err != nil {
+			t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+		}
+	}
+}
+
+// Test for Issue 20103: unshare fails when chroot is used
+func TestUnshareMountNameSpaceChroot(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")
+	}
+
+	d, err := ioutil.TempDir("", "unshare")
+	if err != nil {
+		t.Fatalf("tempdir: %v", err)
+	}
+
+	// Since we are doing a chroot, we need the binary there,
+	// and it must be statically linked.
+	x := filepath.Join(d, "syscall.test")
+	cmd := exec.Command("go", "test", "-c", "-o", x, "syscall")
+	cmd.Env = append(os.Environ(), "CGO_ENABLED=0")
+	if o, err := cmd.CombinedOutput(); err != nil {
+		t.Fatalf("Build of syscall in chroot failed, output %v, err %v", o, err)
+	}
+
+	cmd = exec.Command("/syscall.test", "-test.run=TestUnshareMountNameSpaceHelper", "/")
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
+
+	o, err := cmd.CombinedOutput()
+	if err != nil {
+		if strings.Contains(err.Error(), ": permission denied") {
+			t.Skipf("Skipping test (golang.org/issue/19698); unshare failed due to permissions: %s, %v", o, err)
+		}
+		t.Fatalf("unshare failed: %s, %v", o, err)
+	}
+
+	// How do we tell if the namespace was really unshared? It turns out
+	// to be simple: just try to remove the executable. If it's still mounted
+	// on, the rm will fail. Then we have some cleanup to do:
+	// we must force unmount it, then try to remove it again.
+
+	if err := os.Remove(x); err != nil {
+		t.Errorf("rm failed on %v: %v", x, err)
+		if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+			t.Fatalf("Can't unmount %v: %v", d, err)
+		}
+		if err := os.Remove(x); err != nil {
+			t.Fatalf("rm failed on %v: %v", x, err)
+		}
+	}
+
+	if err := os.Remove(d); err != nil {
+		t.Errorf("rmdir failed on %v: %v", d, err)
+	}
+}
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_solaris.go
index fcb481c..448207e 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_solaris.go
@@ -23,6 +23,7 @@ type SysProcAttr struct {
 // Implemented in runtime package.
 func runtime_BeforeFork()
 func runtime_AfterFork()
+func runtime_AfterForkInChild()
 
 func chdir(path uintptr) (err Errno)
 func chroot1(path uintptr) (err Errno)
@@ -93,6 +94,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 
 	// Fork succeeded, now in child.
 
+	runtime_AfterForkInChild()
+
 	// Session ID
 	if sys.Setsid {
 		_, err1 = setsid()
@@ -143,9 +146,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		if ngroups > 0 {
 			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
 		}
-		err1 = setgroups1(ngroups, groups)
-		if err1 != 0 {
-			goto childerror
+		if !cred.NoSetGroups {
+			err1 = setgroups1(ngroups, groups)
+			if err1 != 0 {
+				goto childerror
+			}
 		}
 		err1 = setgid(uintptr(cred.Gid))
 		if err1 != 0 {
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index af59c5d..e4f047f 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -112,9 +112,10 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
 // Credential holds user and group identities to be assumed
 // by a child process started by StartProcess.
 type Credential struct {
-	Uid    uint32   // User ID.
-	Gid    uint32   // Group ID.
-	Groups []uint32 // Supplementary group IDs.
+	Uid         uint32   // User ID.
+	Gid         uint32   // Group ID.
+	Groups      []uint32 // Supplementary group IDs.
+	NoSetGroups bool     // If true, don't set supplementary groups
 }
 
 // ProcAttr holds attributes that will be applied to a new process started
diff --git a/src/syscall/forkpipe_bsd.go b/src/syscall/forkpipe_bsd.go
new file mode 100644
index 0000000..d418072
--- /dev/null
+++ b/src/syscall/forkpipe_bsd.go
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. 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 openbsd
+
+package syscall
+
+func forkExecPipe(p []int) error {
+	err := Pipe(p)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+	return err
+}
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 987ac23..a7549ac 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -89,6 +89,8 @@ case "$1" in
 -syscalls)
 	for i in zsyscall*go
 	do
+		# Run the command line that appears in the first line
+		# of the generated file to regenerate it.
 		sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
 		rm _$i
 	done
@@ -292,7 +294,7 @@ esac
 		syscall_goos="syscall_bsd.go $syscall_goos"
  		;;
  	esac
-	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
+	if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $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 |go run mkpost.go >ztypes_$GOOSARCH.go"; fi
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index 6ee7c3c..699982e 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -30,6 +30,7 @@ my $netbsd = 0;
 my $dragonfly = 0;
 my $nacl = 0;
 my $arm = 0; # 64-bit value should use (even, odd)-pair
+my $tags = "";  # build tags
 
 if($ARGV[0] eq "-b32") {
 	$_32bit = "big-endian";
@@ -62,9 +63,14 @@ if($ARGV[0] eq "-arm") {
 	$arm = 1;
 	shift;
 }
+if($ARGV[0] eq "-tags") {
+	shift;
+	$tags = $ARGV[0];
+	shift;
+}
 
 if($ARGV[0] =~ /^-/) {
-	print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
+	print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n";
 	exit 1;
 }
 
@@ -132,7 +138,6 @@ while(<>) {
 
 	# Prepare arguments to Syscall.
 	my @args = ();
-	my @uses = ();
 	my $n = 0;
 	foreach my $p (@in) {
 		my ($name, $type) = parseparam($p);
@@ -143,14 +148,12 @@ while(<>) {
 			$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
 			$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
 			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			push @uses, "use(unsafe.Pointer(_p$n))";
 			$n++;
 		} elsif($type eq "string") {
 			print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
 			$text .= "\tvar _p$n *byte\n";
 			$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
 			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			push @uses, "use(unsafe.Pointer(_p$n))";
 			$n++;
 		} elsif($type =~ /^\[\](.*)/) {
 			# Convert slice into pointer, length.
@@ -185,7 +188,7 @@ while(<>) {
 			}
 		} elsif($type eq "int64" && $_32bit ne "") {
 			if(@args % 2 && $arm) {
-				# arm abi specifies 64-bit argument uses 
+				# arm abi specifies 64-bit argument uses
 				# (even, odd) pair
 				push @args, "0"
 			}
@@ -281,11 +284,8 @@ while(<>) {
 	} else {
 		$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
 	}
-	foreach my $use (@uses) {
-		$text .= "\t$use\n";
-	}
 	$text .= $body;
-	
+
 	if ($plan9 && $ret[2] eq "e1") {
 		$text .= "\tif int32(r0) == -1 {\n";
 		$text .= "\t\terr = e1\n";
@@ -310,6 +310,8 @@ print <<EOF;
 // $cmdline
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build $tags
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl
index cd69ebc..a4cc1ac 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -12,7 +12,7 @@
 #	* The parameter lists must give a type for each argument:
 #	  the (x, y, z int) shorthand is not allowed.
 #	* If the return parameter is an error number, it must be named err.
-#	* If go func name needs to be different than its libc name, 
+#	* If go func name needs to be different than its libc name,
 #	* or the function is not in libc, name could be specified
 #	* at the end, after "=" sign, like
 #	  //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
@@ -22,6 +22,7 @@ use strict;
 my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
 my $errors = 0;
 my $_32bit = "";
+my $tags = "";  # build tags
 
 binmode STDOUT;
 
@@ -32,14 +33,14 @@ if($ARGV[0] eq "-b32") {
 	$_32bit = "little-endian";
 	shift;
 }
-
-if($ARGV[0] =~ /^-/) {
-	print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [file ...]\n";
-	exit 1;
+if($ARGV[0] eq "-tags") {
+	shift;
+	$tags = $ARGV[0];
+	shift;
 }
 
-if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") {
-	print STDERR "GOARCH or GOOS not defined in environment\n";
+if($ARGV[0] =~ /^-/) {
+	print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n";
 	exit 1;
 }
 
@@ -141,7 +142,6 @@ while(<>) {
 
 	# Prepare arguments to Syscall.
 	my @args = ();
-	my @uses = ();
 	my $n = 0;
 	foreach my $p (@in) {
 		my ($name, $type) = parseparam($p);
@@ -152,14 +152,12 @@ while(<>) {
 			$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
 			$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
 			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			push @uses, "use(unsafe.Pointer(_p$n))";
 			$n++;
 		} elsif($type eq "string") {
 			print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
 			$text .= "\tvar _p$n $strconvtype\n";
 			$text .= "\t_p$n, _ = $strconvfunc($name)\n";
 			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			push @uses, "use(unsafe.Pointer(_p$n))";
 			$n++;
 		} elsif($type =~ /^\[\](.*)/) {
 			# Convert slice into pointer, length.
@@ -246,9 +244,6 @@ while(<>) {
 	} else {
 		$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
 	}
-	foreach my $use (@uses) {
-		$text .= "\t$use\n";
-	}
 	$text .= $body;
 
 	if ($do_errno) {
@@ -268,7 +263,7 @@ print <<EOF;
 // $cmdline
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build $ENV{'GOARCH'},$ENV{'GOOS'}
+// +build $tags
 
 package $package
 
diff --git a/src/syscall/net.go b/src/syscall/net.go
new file mode 100644
index 0000000..272d3af
--- /dev/null
+++ b/src/syscall/net.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. 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
+
+// A RawConn is a raw network connection.
+type RawConn interface {
+	// Control invokes f on the underlying connection's file
+	// descriptor or handle.
+	// The file descriptor fd is guaranteed to remain valid while
+	// f executes but not after f returns.
+	Control(f func(fd uintptr)) error
+
+	// Read invokes f on the underlying connection's file
+	// descriptor or handle; f is expected to try to read from the
+	// file descriptor.
+	// If f returns true, Read returns. Otherwise Read blocks
+	// waiting for the connection to be ready for reading and
+	// tries again repeatedly.
+	// The file descriptor is guaranteed to remain valid while f
+	// executes but not after f returns.
+	Read(f func(fd uintptr) (done bool)) error
+
+	// Write is like Read but for writing.
+	Write(f func(fd uintptr) (done bool)) error
+}
+
+// Conn is implemented by some types in the net package to provide
+// access to the underlying file descriptor or handle.
+type Conn interface {
+	// SyscallConn returns a raw network connection.
+	SyscallConn() (RawConn, error)
+}
diff --git a/src/syscall/net_nacl.go b/src/syscall/net_nacl.go
index 9dc5d0c..b019cbf 100644
--- a/src/syscall/net_nacl.go
+++ b/src/syscall/net_nacl.go
@@ -177,6 +177,11 @@ func (sa *SockaddrInet4) copy() Sockaddr {
 
 func (sa *SockaddrInet4) key() interface{} { return *sa }
 
+func isIPv4Localhost(sa Sockaddr) bool {
+	sa4, ok := sa.(*SockaddrInet4)
+	return ok && sa4.Addr == [4]byte{127, 0, 0, 1}
+}
+
 type SockaddrInet6 struct {
 	Port   int
 	ZoneId uint32
@@ -601,6 +606,14 @@ func (f *netFile) connect(sa Sockaddr) error {
 		return EISCONN
 	}
 	l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
+	if !ok {
+		// If we're dialing 127.0.0.1 but found nothing, try
+		// 0.0.0.0 also. (Issue 20611)
+		if isIPv4Localhost(sa) {
+			sa = &SockaddrInet4{Port: sa.(*SockaddrInet4).Port}
+			l, ok = net.listener[netAddr{f.proto, f.sotype, sa.key()}]
+		}
+	}
 	if !ok || l.listenerClosed() {
 		net.Unlock()
 		return ECONNREFUSED
diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go
index 2fbe624..7db994b 100644
--- a/src/syscall/syscall.go
+++ b/src/syscall/syscall.go
@@ -22,12 +22,13 @@
 // Go repository should be migrated to use the corresponding
 // package in the golang.org/x/sys repository. That is also where updates
 // required by new systems or versions should be applied.
-// See https://golang.org/s/go1.4-syscall for more information.
+// Signal, Errno and SysProcAttr are not yet available in
+// golang.org/x/sys and must still be referenced from the
+// syscall package. See https://golang.org/s/go1.4-syscall
+// for more information.
 //
 package syscall
 
-import "unsafe"
-
 //go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
 
 // StringByteSlice converts a string to a NUL-terminated []byte,
@@ -98,11 +99,3 @@ func (tv *Timeval) Nano() int64 {
 // Getpagesize is provided by the runtime.
 
 func Getpagesize() int
-
-// use is a no-op, but the compiler cannot see that it is.
-// Calling use(p) ensures that p is kept live until that point.
-// This was needed until Go 1.6 to call syscall.Syscall correctly.
-// As of Go 1.6 the compiler handles that case automatically.
-// The uses and definition of use can be removed early in the Go 1.7 cycle.
-//go:noescape
-func use(p unsafe.Pointer)
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index 689bc14..a1c360d 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -127,7 +127,6 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (
 		uintptr(options),
 		0,
 	)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		return nil, e1
 	}
@@ -180,7 +179,6 @@ 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_dragonfly.go b/src/syscall/syscall_dragonfly.go
index 980687c..7d4fa4d 100644
--- a/src/syscall/syscall_dragonfly.go
+++ b/src/syscall/syscall_dragonfly.go
@@ -1,8 +1,8 @@
-// Copyright 2009,2010 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.
 
-// DragonflyBSD system calls.
+// DragonFly BSD system calls.
 // This file is compiled as ordinary Go code,
 // but it is also input to mksyscall,
 // which parses the //sys lines and generates system call stubs.
@@ -65,7 +65,7 @@ func direntReclen(buf []byte) (uint64, bool) {
 	if !ok {
 		return 0, false
 	}
-	return (16 + namlen + 1 + 7) & ^uint64(7), true
+	return (16 + namlen + 1 + 7) &^ 7, true
 }
 
 func direntNamlen(buf []byte) (uint64, bool) {
@@ -92,6 +92,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	return extpwrite(fd, p, 0, offset)
 }
 
+func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
+	var rsa RawSockaddrAny
+	var len _Socklen = SizeofSockaddrAny
+	nfd, err = accept4(fd, &rsa, &len, flags)
+	if err != nil {
+		return
+	}
+	if len > SizeofSockaddrAny {
+		panic("RawSockaddrAny too small")
+	}
+	sa, err = anyToSockaddr(&rsa)
+	if err != nil {
+		Close(nfd)
+		nfd = 0
+	}
+	return
+}
+
 func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 	var _p0 unsafe.Pointer
 	var bufsize uintptr
@@ -100,7 +118,6 @@ 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
@@ -193,6 +210,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 //sys   munmap(addr uintptr, length uintptr) (err error)
 //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
 //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
+//sys	accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
 
 /*
  * Unimplemented
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 2a304cd..64c881a 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -68,12 +68,26 @@ func direntNamlen(buf []byte) (uint64, bool) {
 
 //sysnb pipe() (r int, w int, err error)
 
-func Pipe(p []int) (err error) {
+func Pipe(p []int) error {
 	if len(p) != 2 {
 		return EINVAL
 	}
+	var err error
 	p[0], p[1], err = pipe()
-	return
+	return err
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) 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 err
 }
 
 func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
@@ -113,7 +127,6 @@ 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 a8801ad..8099a5f 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -127,7 +127,6 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
 		return err
 	}
 	err = futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
-	use(unsafe.Pointer(pathp))
 	return err
 }
 
@@ -790,7 +789,6 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 		return err
 	}
 	err = mount(source, target, fstype, flags, datap)
-	use(unsafe.Pointer(datap))
 	return err
 }
 
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 00cf262..2c5d9a3 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -354,7 +354,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return err
 	}
 	_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
-	use(unsafe.Pointer(pathp))
 	if e != 0 {
 		err = e
 	}
@@ -376,3 +375,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 0184d7d..eaba868 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -134,3 +134,5 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint64(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno)
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index 2ed31f0..5c652b2 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -123,7 +123,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return err
 	}
 	_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
-	use(unsafe.Pointer(pathp))
 	if e != 0 {
 		err = e
 	}
@@ -216,3 +215,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
index 4462139..4e81673 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -139,3 +139,7 @@ const (
 	SYS_EPOLL_CREATE = 1042
 	SYS_EPOLL_WAIT   = 1069
 )
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go
index 9fd7982..671cfe6 100644
--- a/src/syscall/syscall_linux_mips64x.go
+++ b/src/syscall/syscall_linux_mips64x.go
@@ -198,3 +198,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint64(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go
index 48e79ea..1da265d 100644
--- a/src/syscall/syscall_linux_mipsx.go
+++ b/src/syscall/syscall_linux_mipsx.go
@@ -72,7 +72,6 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
 
 func Fstatfs(fd int, buf *Statfs_t) (err error) {
 	_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
-	use(unsafe.Pointer(buf))
 	if e != 0 {
 		err = errnoErr(e)
 	}
@@ -85,7 +84,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return err
 	}
 	_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(p)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
-	use(unsafe.Pointer(p))
 	if e != 0 {
 		err = errnoErr(e)
 	}
@@ -220,3 +218,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go
index 307abc9..53086f9 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -115,3 +115,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint64(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go
index 148790e..8f3bbfc 100644
--- a/src/syscall/syscall_linux_s390x.go
+++ b/src/syscall/syscall_linux_s390x.go
@@ -96,7 +96,6 @@ func Pipe2(p []int, flags int) (err error) {
 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)
@@ -287,3 +286,7 @@ func (msghdr *Msghdr) SetControllen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint64(length)
 }
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+	panic("not implemented")
+}
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index 0691889..b7a0d54 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -251,9 +251,7 @@ func Unmount(name, old string) (err error) {
 			return err
 		}
 		r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
-		use(unsafe.Pointer(namep))
 	}
-	use(unsafe.Pointer(oldp))
 
 	if int32(r0) == -1 {
 		err = e
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index 2f25d18..b1fe78d 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -78,12 +78,16 @@ func TestFcntlFlock(t *testing.T) {
 	}
 	if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
 		// parent
-		name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+		tempDir, err := ioutil.TempDir("", "TestFcntlFlock")
+		if err != nil {
+			t.Fatalf("Failed to create temp dir: %v", err)
+		}
+		name := filepath.Join(tempDir, "TestFcntlFlock")
 		fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
 		if err != nil {
 			t.Fatalf("Open failed: %v", err)
 		}
-		defer syscall.Unlink(name)
+		defer os.RemoveAll(tempDir)
 		defer syscall.Close(fd)
 		if err := syscall.Ftruncate(fd, 1<<20); err != nil {
 			t.Fatalf("Ftruncate(1<<20) failed: %v", err)
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index f4f8f3a..4619ce2 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -57,7 +57,7 @@ func UTF16ToString(s []uint16) string {
 
 // StringToUTF16Ptr returns pointer to the UTF-16 encoding of
 // the UTF-8 string s, with a terminating NUL added. If s
-// If s contains a NUL byte this function panics instead of
+// contains a NUL byte this function panics instead of
 // returning an error.
 //
 // Deprecated: Use UTF16PtrFromString instead.
@@ -110,7 +110,7 @@ func (e Errno) Error() string {
 }
 
 func (e Errno) Temporary() bool {
-	return e == EINTR || e == EMFILE || e.Timeout()
+	return e == EINTR || e == EMFILE || e == WSAECONNABORTED || e == WSAECONNRESET || e.Timeout()
 }
 
 func (e Errno) Timeout() bool {
@@ -236,7 +236,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 
 // syscall interface implementation for other packages
 
-func Exit(code int) { ExitProcess(uint32(code)) }
+// Implemented in ../runtime/syscall_windows.go.
+func Exit(code int)
 
 func makeInheritSa() *SecurityAttributes {
 	var sa SecurityAttributes
@@ -348,7 +349,7 @@ func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
 	// use GetFileType to check pipe, pipe can't do seek
 	ft, _ := GetFileType(fd)
 	if ft == FILE_TYPE_PIPE {
-		return 0, EPIPE
+		return 0, ESPIPE
 	}
 	rlo, e := SetFilePointer(fd, lo, &hi, w)
 	if e != nil {
diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go
index 15d300f..cf36c44 100644
--- a/src/syscall/zerrors_dragonfly_amd64.go
+++ b/src/syscall/zerrors_dragonfly_amd64.go
@@ -1094,8 +1094,10 @@ const (
 	SIOCSLIFPHYADDR                   = 0x8118694a
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SOCK_CLOEXEC                      = 0x10000000
 	SOCK_DGRAM                        = 0x2
 	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_NONBLOCK                     = 0x20000000
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
 	SOCK_SEQPACKET                    = 0x5
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 9c3ba5a..200407e 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
+// mksyscall.pl -l32 -tags darwin,386 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,darwin
+// +build darwin,386
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -302,7 +300,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -328,7 +325,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -344,7 +340,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -360,7 +355,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -376,7 +370,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -392,7 +385,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -444,8 +436,6 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -722,7 +712,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -743,8 +732,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -770,7 +757,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -786,7 +772,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -802,7 +787,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -818,7 +802,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -902,7 +885,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -919,7 +901,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -993,7 +974,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -1015,8 +995,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1032,7 +1010,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1048,7 +1025,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1115,7 +1091,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1222,7 +1197,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1238,7 +1212,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1259,8 +1232,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1286,7 +1257,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1310,7 +1280,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1326,7 +1295,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1342,7 +1310,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 12f4782..1303f62 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
+// mksyscall.pl -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,darwin
+// +build darwin,amd64
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -302,7 +300,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -328,7 +325,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -344,7 +340,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -360,7 +355,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -376,7 +370,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -392,7 +385,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -444,8 +436,6 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -722,7 +712,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -743,8 +732,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -770,7 +757,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -786,7 +772,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -802,7 +787,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -818,7 +802,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -902,7 +885,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -919,7 +901,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -993,7 +974,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -1015,8 +995,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1032,7 +1010,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1048,7 +1025,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1115,7 +1091,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1222,7 +1197,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1238,7 +1212,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1259,8 +1232,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1286,7 +1257,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1310,7 +1280,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1326,7 +1295,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1342,7 +1310,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
index ab5b4a9..8b63729 100644
--- a/src/syscall/zsyscall_darwin_arm.go
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
+// mksyscall.pl -l32 -tags darwin,arm syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,darwin
+// +build darwin,arm
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -302,7 +300,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -328,7 +325,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -344,7 +340,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -360,7 +355,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -376,7 +370,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -392,7 +385,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -444,8 +436,6 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -722,7 +712,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -743,8 +732,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -770,7 +757,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -786,7 +772,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -802,7 +787,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -818,7 +802,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -902,7 +885,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -919,7 +901,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -993,7 +974,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -1015,8 +995,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1032,7 +1010,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1048,7 +1025,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1115,7 +1091,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1222,7 +1197,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1238,7 +1212,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1259,8 +1232,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1286,7 +1257,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1310,7 +1280,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1326,7 +1295,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1342,7 +1310,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
index c260cc7..73a834c 100644
--- a/src/syscall/zsyscall_darwin_arm64.go
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
+// mksyscall.pl -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm64,darwin
+// +build darwin,arm64
 
 package syscall
 
@@ -13,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -23,7 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -34,7 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -45,7 +45,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -55,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -65,7 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -76,7 +76,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -86,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -96,7 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -106,7 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -126,7 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -136,7 +136,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -153,7 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -169,7 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -191,7 +191,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -202,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -218,7 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,9 +232,8 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -244,7 +243,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -255,7 +254,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +264,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -277,7 +276,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -287,7 +286,7 @@ func pipe() (r int, w int, err error) {
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,9 +300,8 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -313,7 +311,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -327,9 +325,8 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -343,9 +340,8 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,9 +355,8 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -375,9 +370,8 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -391,9 +385,8 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -403,7 +396,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -411,10 +404,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -422,9 +415,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -443,10 +436,8 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -463,7 +454,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -473,7 +464,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -483,7 +474,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -493,7 +484,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -503,7 +494,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -514,7 +505,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -524,7 +515,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -534,7 +525,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -544,7 +535,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -554,7 +545,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -571,7 +562,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -614,7 +605,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +640,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +650,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -669,7 +660,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -680,7 +671,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -707,7 +698,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,9 +712,8 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -742,10 +732,8 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -755,7 +743,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -769,9 +757,8 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -785,9 +772,8 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -801,9 +787,8 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -817,9 +802,8 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -835,7 +819,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -845,7 +829,7 @@ func Mlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -861,7 +845,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -877,7 +861,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -887,7 +871,7 @@ func Munlock(b []byte) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -901,10 +885,9 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -918,10 +901,9 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -938,7 +920,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -955,7 +937,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -972,7 +954,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -992,10 +974,9 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1014,10 +995,8 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1031,9 +1010,8 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1047,9 +1025,8 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1060,7 +1037,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1070,7 +1047,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1080,7 +1057,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1090,7 +1067,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1100,7 +1077,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1114,9 +1091,8 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1126,7 +1102,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1136,7 +1112,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1146,7 +1122,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1156,7 +1132,7 @@ func Setprivexec(flag int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1166,7 +1142,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1176,7 +1152,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1163,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1173,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1183,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1221,9 +1197,8 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,9 +1212,8 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1258,10 +1232,8 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1271,7 +1243,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,9 +1257,8 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,9 +1280,8 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1325,9 +1295,8 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1341,9 +1310,8 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1360,7 +1328,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1371,7 +1339,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1381,7 +1349,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1392,7 +1360,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1403,7 +1371,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1415,7 +1383,7 @@ func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
 	sec = int64(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 85d2777..7a21510 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
+// mksyscall.pl -dragonfly -tags dragonfly,amd64 syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,dragonfly
+// +build dragonfly,amd64
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -316,7 +314,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -342,7 +339,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -358,7 +354,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -374,7 +369,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -390,7 +384,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -406,7 +399,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -734,7 +726,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -755,8 +746,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -782,7 +771,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -798,7 +786,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -814,7 +801,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -830,7 +816,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -856,7 +841,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -873,7 +857,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -913,7 +896,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -935,8 +917,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -952,7 +932,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -968,7 +947,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1035,7 +1013,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1132,7 +1109,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1148,7 +1124,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1169,8 +1144,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1196,7 +1169,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1220,7 +1192,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1236,7 +1207,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1252,7 +1222,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1318,3 +1287,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	}
 	return
 }
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index b9ed271..63061b2 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
+// mksyscall.pl -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,freebsd
+// +build freebsd,386
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -275,6 +273,16 @@ func pipe() (r int, w int, err error) {
 
 // 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
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -282,7 +290,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -308,7 +315,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -324,7 +330,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -340,7 +345,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -356,7 +360,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -372,7 +375,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -700,7 +702,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -721,8 +722,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -748,7 +747,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -764,7 +762,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -780,7 +777,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -796,7 +792,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -822,7 +817,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -839,7 +833,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -913,7 +906,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -935,8 +927,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -952,7 +942,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -968,7 +957,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1035,7 +1023,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1132,7 +1119,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1148,7 +1134,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1169,8 +1154,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1196,7 +1179,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1220,7 +1202,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1236,7 +1217,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1252,7 +1232,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 12d1db0..8120980 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
+// mksyscall.pl -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,freebsd
+// +build freebsd,amd64
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -275,6 +273,16 @@ func pipe() (r int, w int, err error) {
 
 // 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
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -282,7 +290,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -308,7 +315,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -324,7 +330,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -340,7 +345,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -356,7 +360,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -372,7 +375,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -700,7 +702,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -721,8 +722,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -748,7 +747,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -764,7 +762,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -780,7 +777,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -796,7 +792,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -822,7 +817,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -839,7 +833,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -913,7 +906,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -935,8 +927,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -952,7 +942,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -968,7 +957,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1035,7 +1023,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1132,7 +1119,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1148,7 +1134,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1169,8 +1154,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1196,7 +1179,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1220,7 +1202,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1236,7 +1217,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1252,7 +1232,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 78b7c07..f6c44c7 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
+// mksyscall.pl -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,freebsd
+// +build freebsd,arm
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -275,6 +273,16 @@ func pipe() (r int, w int, err error) {
 
 // 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
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -282,7 +290,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -308,7 +315,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -324,7 +330,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -340,7 +345,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -356,7 +360,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -372,7 +375,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -700,7 +702,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -721,8 +722,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -748,7 +747,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -764,7 +762,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -780,7 +777,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -796,7 +792,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -822,7 +817,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -839,7 +833,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -913,7 +906,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -935,8 +927,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -952,7 +942,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -968,7 +957,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1035,7 +1023,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1132,7 +1119,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1148,7 +1134,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1169,8 +1154,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1196,7 +1179,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1220,7 +1202,6 @@ func Undelete(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1236,7 +1217,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1252,7 +1232,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index 195228d..3536bb7 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go
+// mksyscall.pl -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,linux
+// +build linux,386
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1327,7 +1292,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1343,7 +1307,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1475,7 +1438,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1501,7 +1463,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index f413a19..92bcd09 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_linux.go syscall_linux_amd64.go
+// mksyscall.pl -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,linux
+// +build linux,amd64
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1327,7 +1292,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1353,7 +1317,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1527,7 +1490,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1543,7 +1505,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1569,7 +1530,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index 7773436..8131899 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
+// mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,linux
+// +build linux,arm
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1466,7 +1431,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1492,7 +1456,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1611,7 +1574,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1682,7 +1644,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go
index 8e02f3c..7dffb75 100644
--- a/src/syscall/zsyscall_linux_arm64.go
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_linux.go syscall_linux_arm64.go
+// mksyscall.pl -tags linux,arm64 syscall_linux.go syscall_linux_arm64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm64,linux
+// +build linux,arm64
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1224,7 +1189,6 @@ func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1470,7 +1434,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1496,7 +1459,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go
index 0fa1452..f1297bf 100644
--- a/src/syscall/zsyscall_linux_mips.go
+++ b/src/syscall/zsyscall_linux_mips.go
@@ -1,6 +1,8 @@
-// mksyscall.pl -b32 -arm syscall_linux.go syscall_linux_mipsx.go
+// mksyscall.pl -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build linux,mips
+
 package syscall
 
 import "unsafe"
@@ -19,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -36,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -59,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -81,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -98,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -114,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -130,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -194,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -220,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -238,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -265,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -384,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -430,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -446,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -587,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -605,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -677,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -694,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -751,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -800,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -822,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -923,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1007,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1043,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1264,7 +1231,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1437,7 +1403,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length>>32), uintptr(length), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1684,7 +1649,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1710,7 +1674,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go
index b9708e3..901bafd 100644
--- a/src/syscall/zsyscall_linux_mips64.go
+++ b/src/syscall/zsyscall_linux_mips64.go
@@ -1,6 +1,8 @@
-// mksyscall.pl syscall_linux.go syscall_linux_mips64x.go
+// mksyscall.pl -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build linux,mips64
+
 package syscall
 
 import "unsafe"
@@ -19,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -36,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -59,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -81,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -98,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -114,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -130,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -194,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -220,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -238,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -265,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -384,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -430,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -446,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -587,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -605,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -677,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -694,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -751,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -800,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -822,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -923,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1007,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1043,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1295,7 +1262,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1479,7 +1445,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1505,7 +1470,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1724,8 +1688,8 @@ func pipe2(p *[2]_C_int, flags int) (err error) {
 
 // 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)
+func fstat(fd int, st *stat_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1734,14 +1698,13 @@ func fstat(fd int, stat *stat_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func lstat(path string, stat *stat_t) (err error) {
+func lstat(path string, st *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))
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1750,14 +1713,13 @@ func lstat(path string, stat *stat_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func stat(path string, stat *stat_t) (err error) {
+func stat(path string, st *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))
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go
index b9708e3..5af854b 100644
--- a/src/syscall/zsyscall_linux_mips64le.go
+++ b/src/syscall/zsyscall_linux_mips64le.go
@@ -1,6 +1,8 @@
-// mksyscall.pl syscall_linux.go syscall_linux_mips64x.go
+// mksyscall.pl -tags linux,mips64le syscall_linux.go syscall_linux_mips64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build linux,mips64le
+
 package syscall
 
 import "unsafe"
@@ -19,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -36,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -59,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -81,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -98,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -114,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -130,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -194,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -220,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -238,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -265,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -384,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -430,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -446,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -587,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -605,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -677,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -694,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -751,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -800,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -822,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -923,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1007,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1043,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1295,7 +1262,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1479,7 +1445,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1505,7 +1470,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1724,8 +1688,8 @@ func pipe2(p *[2]_C_int, flags int) (err error) {
 
 // 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)
+func fstat(fd int, st *stat_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1734,14 +1698,13 @@ func fstat(fd int, stat *stat_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func lstat(path string, stat *stat_t) (err error) {
+func lstat(path string, st *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))
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1750,14 +1713,13 @@ func lstat(path string, stat *stat_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func stat(path string, stat *stat_t) (err error) {
+func stat(path string, st *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))
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go
index 527e3ef..b2fcb91 100644
--- a/src/syscall/zsyscall_linux_mipsle.go
+++ b/src/syscall/zsyscall_linux_mipsle.go
@@ -1,6 +1,8 @@
-// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_mipsx.go
+// mksyscall.pl -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build linux,mipsle
+
 package syscall
 
 import "unsafe"
@@ -19,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -36,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -59,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -81,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -98,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -114,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -130,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -194,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -220,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -238,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -265,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -384,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -430,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -446,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -587,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -605,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -677,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -694,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -751,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -800,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -822,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -923,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1007,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1043,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1264,7 +1231,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1437,7 +1403,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1684,7 +1649,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1710,7 +1674,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go
index b5315cd..51ef5ae 100644
--- a/src/syscall/zsyscall_linux_ppc64.go
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
+// mksyscall.pl -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build ppc64,linux
+// +build linux,ppc64
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1327,7 +1292,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1353,7 +1317,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1527,7 +1490,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1543,7 +1505,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1569,7 +1530,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
index 501d680..9ef2118 100644
--- a/src/syscall/zsyscall_linux_ppc64le.go
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -1,7 +1,7 @@
-// mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
+// mksyscall.pl -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build ppc64le,linux
+// +build linux,ppc64le
 
 package syscall
 
@@ -21,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -38,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -61,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -83,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -100,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -116,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -132,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -196,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -222,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -240,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -267,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -283,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -432,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -448,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -589,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -607,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -679,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -696,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -712,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -753,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -802,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -824,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -925,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1009,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1045,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1327,7 +1292,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1353,7 +1317,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1527,7 +1490,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1543,7 +1505,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1569,7 +1530,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go
index b33ce68..abc2c4b 100644
--- a/src/syscall/zsyscall_linux_s390x.go
+++ b/src/syscall/zsyscall_linux_s390x.go
@@ -1,6 +1,8 @@
-// mksyscall.pl syscall_linux.go syscall_linux_s390x.go
+// mksyscall.pl -tags linux,s390x syscall_linux.go syscall_linux_s390x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build linux,s390x
+
 package syscall
 
 import "unsafe"
@@ -19,8 +21,6 @@ func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags in
 		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)
 	}
@@ -36,7 +36,6 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 		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)
@@ -59,7 +58,6 @@ func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
 		_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)
@@ -81,8 +79,6 @@ func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
 		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)
 	}
@@ -98,7 +94,6 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -114,7 +109,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -130,7 +124,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 		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)
 	}
@@ -194,7 +187,6 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 		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)
 	}
@@ -220,9 +212,6 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 		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)
 	}
@@ -238,7 +227,6 @@ func Acct(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -265,7 +253,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +268,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -384,7 +370,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -430,7 +415,6 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 		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)
 	}
@@ -446,7 +430,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 		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)
 	}
@@ -587,8 +570,6 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 		_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)
@@ -605,7 +586,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 		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)
@@ -677,7 +657,6 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 		_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)
@@ -694,7 +673,6 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,7 +688,6 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 		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)
 	}
@@ -751,8 +728,6 @@ func PivotRoot(newroot string, putold string) (err error) {
 		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)
 	}
@@ -800,8 +775,6 @@ func Removexattr(path string, attr string) (err error) {
 		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)
 	}
@@ -822,8 +795,6 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 		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)
 	}
@@ -923,8 +894,6 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 		_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)
 	}
@@ -1007,7 +976,6 @@ func Unmount(target string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1043,7 +1011,6 @@ func Utime(path string, buf *Utimbuf) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1305,7 +1272,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1321,7 +1287,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1485,7 +1450,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1501,7 +1465,6 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1527,7 +1490,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index bf3f9e3..b66ec69 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// mksyscall.pl -l32 -nacl -tags nacl,386 syscall_nacl.go syscall_nacl_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,nacl
+// +build nacl,386
 
 package syscall
 
diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go
index 3f08da6..e74931b 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// mksyscall.pl -nacl -tags nacl,amd64p32 syscall_nacl.go syscall_nacl_amd64p32.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64p32,nacl
+// +build nacl,amd64p32
 
 package syscall
 
diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go
index 77d46c3..4a1ca38 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go
+// mksyscall.pl -l32 -nacl -arm -tags nacl,arm syscall_nacl.go syscall_nacl_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,nacl
+// +build nacl,arm
 
 package syscall
 
diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index 61b52cd..ec32d9c 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
+// mksyscall.pl -l32 -netbsd -tags netbsd,386 syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,netbsd
+// +build netbsd,386
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -299,7 +297,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -325,7 +322,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -341,7 +337,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -357,7 +352,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -373,7 +367,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -389,7 +382,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -682,7 +674,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -703,8 +694,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -730,7 +719,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -746,7 +734,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -762,7 +749,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -778,7 +764,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -804,7 +789,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -821,7 +805,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -895,7 +878,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -917,8 +899,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -934,7 +914,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -950,7 +929,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1098,7 +1076,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1119,8 +1096,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1146,7 +1121,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1170,7 +1144,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1186,7 +1159,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index 52987ba..8845202 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
+// mksyscall.pl -netbsd -tags netbsd,amd64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,netbsd
+// +build netbsd,amd64
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -299,7 +297,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -325,7 +322,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -341,7 +337,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -357,7 +352,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -373,7 +367,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -389,7 +382,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -682,7 +674,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -703,8 +694,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -730,7 +719,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -746,7 +734,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -762,7 +749,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -778,7 +764,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -804,7 +789,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -821,7 +805,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -895,7 +878,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -917,8 +899,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -934,7 +914,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -950,7 +929,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1098,7 +1076,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1119,8 +1096,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1146,7 +1121,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1170,7 +1144,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1186,7 +1159,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 5c59a0d..70df9b4 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
+// mksyscall.pl -l32 -arm -tags netbsd,arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,netbsd
+// +build netbsd,arm
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -299,7 +297,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -325,7 +322,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -341,7 +337,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -357,7 +352,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -373,7 +367,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -389,7 +382,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -682,7 +674,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -703,8 +694,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -730,7 +719,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -746,7 +734,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -762,7 +749,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -778,7 +764,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -804,7 +789,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -821,7 +805,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -895,7 +878,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -917,8 +899,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -934,7 +914,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -950,7 +929,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1098,7 +1076,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1119,8 +1096,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1146,7 +1121,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1170,7 +1144,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1186,7 +1159,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index 37bbd85..2a5542f 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
+// mksyscall.pl -l32 -openbsd -tags openbsd,386 syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,openbsd
+// +build openbsd,386
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -297,7 +295,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -323,7 +320,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -339,7 +335,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -355,7 +350,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -371,7 +365,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -387,7 +380,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -690,7 +682,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -711,8 +702,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -738,7 +727,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -754,7 +742,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -770,7 +757,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -786,7 +772,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -812,7 +797,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -829,7 +813,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -903,7 +886,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -925,8 +907,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -942,7 +922,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -958,7 +937,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1025,7 +1003,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1122,7 +1099,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1138,7 +1114,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1159,8 +1134,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1186,7 +1159,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1210,7 +1182,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1226,7 +1197,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index 0d831df..9c6a39d 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
+// mksyscall.pl -openbsd -tags openbsd,amd64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,openbsd
+// +build openbsd,amd64
 
 package syscall
 
@@ -217,7 +217,6 @@ 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)
 	}
@@ -233,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -297,7 +295,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -323,7 +320,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -339,7 +335,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -355,7 +350,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -371,7 +365,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -387,7 +380,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -690,7 +682,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -711,8 +702,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -738,7 +727,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -754,7 +742,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -770,7 +757,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -786,7 +772,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -812,7 +797,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -829,7 +813,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -903,7 +886,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -925,8 +907,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -942,7 +922,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -958,7 +937,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1025,7 +1003,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1122,7 +1099,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1138,7 +1114,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1159,8 +1134,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1186,7 +1159,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1210,7 +1182,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1226,7 +1197,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go
index f40fb31..1ddd238 100644
--- a/src/syscall/zsyscall_openbsd_arm.go
+++ b/src/syscall/zsyscall_openbsd_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -openbsd -arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
+// mksyscall.pl -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,openbsd
+// +build openbsd,arm
 
 package syscall
 
@@ -232,7 +232,6 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -296,7 +295,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -322,7 +320,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -338,7 +335,6 @@ func Chflags(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -354,7 +350,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -370,7 +365,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -386,7 +380,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -689,7 +682,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -710,8 +702,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -737,7 +727,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -753,7 +742,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -769,7 +757,6 @@ func Mkfifo(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -785,7 +772,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -811,7 +797,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -828,7 +813,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -902,7 +886,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -924,8 +907,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -941,7 +922,6 @@ func Revoke(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -957,7 +937,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1024,7 +1003,6 @@ func Setlogin(name string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1121,7 +1099,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1137,7 +1114,6 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1158,8 +1134,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1185,7 +1159,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1209,7 +1182,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -1225,7 +1197,6 @@ func Unmount(path string, flags int) (err error) {
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index a424e78..502716d 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// mksyscall.pl -l32 -plan9 -tags plan9,386 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,plan9
+// +build plan9,386
 
 package syscall
 
@@ -59,7 +59,6 @@ func open(path string, mode int) (fd int, err error) {
 		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
@@ -76,7 +75,6 @@ func create(path string, mode int, perm uint32) (fd int, err error) {
 		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
@@ -93,7 +91,6 @@ func remove(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -115,7 +112,6 @@ func stat(path string, edir []byte) (n int, err error) {
 		_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
@@ -137,8 +133,6 @@ func bind(name string, old string, flag int) (err error) {
 		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
 	}
@@ -159,8 +153,6 @@ func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 		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
 	}
@@ -182,7 +174,6 @@ func wstat(path string, edir []byte) (err error) {
 		_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
 	}
@@ -198,7 +189,6 @@ func chdir(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index d58556b..d3e8b31 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// mksyscall.pl -l32 -plan9 -tags plan9,amd64 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,plan9
+// +build plan9,amd64
 
 package syscall
 
@@ -59,7 +59,6 @@ func open(path string, mode int) (fd int, err error) {
 		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
@@ -76,7 +75,6 @@ func create(path string, mode int, perm uint32) (fd int, err error) {
 		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
@@ -93,7 +91,6 @@ func remove(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -115,7 +112,6 @@ func stat(path string, edir []byte) (n int, err error) {
 		_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
@@ -137,8 +133,6 @@ func bind(name string, old string, flag int) (err error) {
 		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
 	}
@@ -159,8 +153,6 @@ func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 		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
 	}
@@ -182,7 +174,6 @@ func wstat(path string, edir []byte) (err error) {
 		_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
 	}
@@ -198,7 +189,6 @@ func chdir(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_plan9_arm.go b/src/syscall/zsyscall_plan9_arm.go
index d54aeff..3c0d25b 100644
--- a/src/syscall/zsyscall_plan9_arm.go
+++ b/src/syscall/zsyscall_plan9_arm.go
@@ -1,7 +1,7 @@
-// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// mksyscall.pl -l32 -plan9 -tags plan9,arm syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,plan9
+// +build plan9,arm
 
 package syscall
 
@@ -59,7 +59,6 @@ func open(path string, mode int) (fd int, err error) {
 		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
@@ -76,7 +75,6 @@ func create(path string, mode int, perm uint32) (fd int, err error) {
 		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
@@ -93,7 +91,6 @@ func remove(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -115,7 +112,6 @@ func stat(path string, edir []byte) (n int, err error) {
 		_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
@@ -137,8 +133,6 @@ func bind(name string, old string, flag int) (err error) {
 		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
 	}
@@ -159,8 +153,6 @@ func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 		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
 	}
@@ -182,7 +174,6 @@ func wstat(path string, edir []byte) (err error) {
 		_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
 	}
@@ -198,7 +189,6 @@ func chdir(path string) (err error) {
 		return
 	}
 	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index 8cc3740..fbc815d 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,7 +1,7 @@
-// mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
+// mksyscall_solaris.pl -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,solaris
+// +build solaris,amd64
 
 package syscall
 
@@ -74,7 +74,7 @@ import "unsafe"
 //go:cgo_import_dynamic libc_Ftruncate ftruncate "libc.so"
 //go:cgo_import_dynamic libc_Umask umask "libc.so"
 //go:cgo_import_dynamic libc_Unlink unlink "libc.so"
-//go:cgo_import_dynamic libc_Utimes utimes "libc.so"
+//go:cgo_import_dynamic libc_utimes utimes "libc.so"
 //go:cgo_import_dynamic libc___xnet_bind __xnet_bind "libsocket.so"
 //go:cgo_import_dynamic libc___xnet_connect __xnet_connect "libsocket.so"
 //go:cgo_import_dynamic libc_mmap mmap "libc.so"
@@ -158,7 +158,7 @@ import "unsafe"
 //go:linkname libc_Ftruncate libc_Ftruncate
 //go:linkname libc_Umask libc_Umask
 //go:linkname libc_Unlink libc_Unlink
-//go:linkname libc_Utimes libc_Utimes
+//go:linkname libc_utimes libc_utimes
 //go:linkname libc___xnet_bind libc___xnet_bind
 //go:linkname libc___xnet_connect libc___xnet_connect
 //go:linkname libc_mmap libc_mmap
@@ -245,7 +245,7 @@ var (
 	libc_Ftruncate,
 	libc_Umask,
 	libc_Unlink,
-	libc_Utimes,
+	libc_utimes,
 	libc___xnet_bind,
 	libc___xnet_connect,
 	libc_mmap,
@@ -327,7 +327,6 @@ func Access(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Access)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -349,7 +348,6 @@ func Chdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -363,7 +361,6 @@ func Chmod(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chmod)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -377,7 +374,6 @@ func Chown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -391,7 +387,6 @@ func Chroot(path string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chroot)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -550,7 +545,6 @@ func Lchown(path string, uid int, gid int) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lchown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -569,8 +563,6 @@ func Link(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Link)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -592,7 +584,6 @@ func Lstat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lstat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -606,7 +597,6 @@ func Mkdir(path string, mode uint32) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mkdir)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -620,7 +610,6 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mknod)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -642,7 +631,6 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 		return
 	}
 	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Open)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -657,7 +645,6 @@ func Pathconf(path string, name int) (val int, err error) {
 		return
 	}
 	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pathconf)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -715,7 +702,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
 		_p1 = &buf[0]
 	}
 	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Readlink)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -735,8 +721,6 @@ func Rename(from string, to string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rename)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -750,7 +734,6 @@ func Rmdir(path string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rmdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -871,7 +854,6 @@ func Stat(path string, stat *Stat_t) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Stat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -890,8 +872,6 @@ func Symlink(path string, link string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Symlink)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -913,7 +893,6 @@ func Truncate(path string, length int64) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Truncate)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -949,7 +928,6 @@ func Unlink(path string) (err error) {
 		return
 	}
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Unlink)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -962,8 +940,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Utimes)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
-	use(unsafe.Pointer(_p0))
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_utimes)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go
index 277478d..3c2e342 100644
--- a/src/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/syscall/zsysnum_dragonfly_amd64.go
@@ -301,4 +301,5 @@ const (
 	SYS_LPATHCONF              = 533 // { int lpathconf(char *path, int name); }
 	SYS_VMM_GUEST_CTL          = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
 	SYS_VMM_GUEST_SYNC_ADDR    = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
+	SYS_ACCEPT4                = 541 // { int accept4(int s, caddr_t name, int *anamelen, int flags); }
 )
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index 1fb6f5c..bc9bd4d 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -27,6 +27,7 @@ const (
 	ERROR_NOT_FOUND           Errno = 1168
 	ERROR_PRIVILEGE_NOT_HELD  Errno = 1314
 	WSAEACCES                 Errno = 10013
+	WSAECONNABORTED           Errno = 10053
 	WSAECONNRESET             Errno = 10054
 )
 
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index bcebb41..18a46d9 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -47,6 +47,7 @@ type InternalBenchmark struct {
 // affecting benchmark results.
 type B struct {
 	common
+	importPath       string // import path of the package containing the benchmark
 	context          *benchContext
 	N                int
 	previousN        int           // number of iterations in the previous run
@@ -72,9 +73,11 @@ type B struct {
 // a call to StopTimer.
 func (b *B) StartTimer() {
 	if !b.timerOn {
-		runtime.ReadMemStats(&memStats)
-		b.startAllocs = memStats.Mallocs
-		b.startBytes = memStats.TotalAlloc
+		if *benchmarkMemory || b.showAllocResult {
+			runtime.ReadMemStats(&memStats)
+			b.startAllocs = memStats.Mallocs
+			b.startBytes = memStats.TotalAlloc
+		}
 		b.start = time.Now()
 		b.timerOn = true
 	}
@@ -86,9 +89,11 @@ func (b *B) StartTimer() {
 func (b *B) StopTimer() {
 	if b.timerOn {
 		b.duration += time.Now().Sub(b.start)
-		runtime.ReadMemStats(&memStats)
-		b.netAllocs += memStats.Mallocs - b.startAllocs
-		b.netBytes += memStats.TotalAlloc - b.startBytes
+		if *benchmarkMemory || b.showAllocResult {
+			runtime.ReadMemStats(&memStats)
+			b.netAllocs += memStats.Mallocs - b.startAllocs
+			b.netBytes += memStats.TotalAlloc - b.startBytes
+		}
 		b.timerOn = false
 	}
 }
@@ -97,9 +102,11 @@ func (b *B) StopTimer() {
 // It does not affect whether the timer is running.
 func (b *B) ResetTimer() {
 	if b.timerOn {
-		runtime.ReadMemStats(&memStats)
-		b.startAllocs = memStats.Mallocs
-		b.startBytes = memStats.TotalAlloc
+		if *benchmarkMemory || b.showAllocResult {
+			runtime.ReadMemStats(&memStats)
+			b.startAllocs = memStats.Mallocs
+			b.startBytes = memStats.TotalAlloc
+		}
 		b.start = time.Now()
 	}
 	b.duration = 0
@@ -233,9 +240,18 @@ func (b *B) run1() bool {
 	return true
 }
 
+var labelsOnce sync.Once
+
 // run executes the benchmark in a separate goroutine, including all of its
 // subbenchmarks. b must not have subbenchmarks.
 func (b *B) run() BenchmarkResult {
+	labelsOnce.Do(func() {
+		fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS)
+		fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH)
+		if b.importPath != "" {
+			fmt.Fprintf(b.w, "pkg: %s\n", b.importPath)
+		}
+	})
 	if b.context != nil {
 		// Running go test --test.bench
 		b.context.processBench(b) // Must call doBench.
@@ -284,6 +300,8 @@ func (b *B) launch() {
 }
 
 // The results of a benchmark run.
+// MemAllocs and MemBytes may be zero if memory benchmarking is not requested
+// using B.ReportAllocs or the -benchmem command line flag.
 type BenchmarkResult struct {
 	N         int           // The number of iterations.
 	T         time.Duration // The total time taken.
@@ -306,6 +324,7 @@ func (r BenchmarkResult) mbPerSec() float64 {
 	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
 }
 
+// AllocsPerOp returns r.MemAllocs / r.N.
 func (r BenchmarkResult) AllocsPerOp() int64 {
 	if r.N <= 0 {
 		return 0
@@ -313,6 +332,7 @@ func (r BenchmarkResult) AllocsPerOp() int64 {
 	return int64(r.MemAllocs) / int64(r.N)
 }
 
+// AllocedBytesPerOp returns r.MemBytes / r.N.
 func (r BenchmarkResult) AllocedBytesPerOp() int64 {
 	if r.N <= 0 {
 		return 0
@@ -340,6 +360,7 @@ func (r BenchmarkResult) String() string {
 	return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
 }
 
+// MemString returns r.AllocedBytesPerOp and r.AllocsPerOp in the same format as 'go test'.
 func (r BenchmarkResult) MemString() string {
 	return fmt.Sprintf("%8d B/op\t%8d allocs/op",
 		r.AllocedBytesPerOp(), r.AllocsPerOp())
@@ -363,10 +384,10 @@ type benchContext struct {
 // 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) {
-	runBenchmarks(matchString, benchmarks)
+	runBenchmarks("", matchString, benchmarks)
 }
 
-func runBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
+func runBenchmarks(importPath string, matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
 	// If no flag was specified, don't run benchmarks.
 	if len(*matchBenchmarks) == 0 {
 		return true
@@ -398,6 +419,7 @@ func runBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 			w:      os.Stdout,
 			chatty: *chatty,
 		},
+		importPath: importPath,
 		benchFunc: func(b *B) {
 			for _, Benchmark := range bs {
 				b.Run(Benchmark.Name, Benchmark.F)
@@ -486,9 +508,10 @@ func (b *B) Run(name string, f func(b *B)) bool {
 			w:      b.w,
 			chatty: b.chatty,
 		},
-		benchFunc: f,
-		benchTime: b.benchTime,
-		context:   b.context,
+		importPath: b.importPath,
+		benchFunc:  f,
+		benchTime:  b.benchTime,
+		context:    b.context,
 	}
 	if sub.run1() {
 		sub.run()
@@ -634,10 +657,10 @@ func Benchmark(f func(b *B)) BenchmarkResult {
 		benchFunc: f,
 		benchTime: *benchTime,
 	}
-	if !b.run1() {
-		return BenchmarkResult{}
+	if b.run1() {
+		b.run()
 	}
-	return b.run()
+	return b.result
 }
 
 type discard struct{}
diff --git a/src/testing/helper_test.go b/src/testing/helper_test.go
new file mode 100644
index 0000000..f5cb27c
--- /dev/null
+++ b/src/testing/helper_test.go
@@ -0,0 +1,70 @@
+// Copyright 2017 The Go Authors. 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"
+)
+
+func TestTBHelper(t *T) {
+	var buf bytes.Buffer
+	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
+	t1 := &T{
+		common: common{
+			signal: make(chan bool),
+			w:      &buf,
+		},
+		context: ctx,
+	}
+	t1.Run("Test", testHelper)
+
+	want := `--- FAIL: Test (?s)
+helperfuncs_test.go:12: 0
+helperfuncs_test.go:33: 1
+helperfuncs_test.go:21: 2
+helperfuncs_test.go:35: 3
+helperfuncs_test.go:42: 4
+helperfuncs_test.go:47: 5
+--- FAIL: Test/sub (?s)
+helperfuncs_test.go:50: 6
+helperfuncs_test.go:21: 7
+helperfuncs_test.go:53: 8
+`
+	lines := strings.Split(buf.String(), "\n")
+	durationRE := regexp.MustCompile(`\(.*\)$`)
+	for i, line := range lines {
+		line = strings.TrimSpace(line)
+		line = durationRE.ReplaceAllString(line, "(?s)")
+		lines[i] = line
+	}
+	got := strings.Join(lines, "\n")
+	if got != want {
+		t.Errorf("got output:\n\n%s\nwant:\n\n%s", got, want)
+	}
+}
+
+func TestTBHelperParallel(t *T) {
+	var buf bytes.Buffer
+	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
+	t1 := &T{
+		common: common{
+			signal: make(chan bool),
+			w:      &buf,
+		},
+		context: ctx,
+	}
+	t1.Run("Test", parallelTestHelper)
+
+	lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
+	if len(lines) != 6 {
+		t.Fatalf("parallelTestHelper gave %d lines of output; want 6", len(lines))
+	}
+	want := "helperfuncs_test.go:21: parallel"
+	if got := strings.TrimSpace(lines[1]); got != want {
+		t.Errorf("got output line %q; want %q", got, want)
+	}
+}
diff --git a/src/testing/helperfuncs_test.go b/src/testing/helperfuncs_test.go
new file mode 100644
index 0000000..7cb2e2c
--- /dev/null
+++ b/src/testing/helperfuncs_test.go
@@ -0,0 +1,67 @@
+// Copyright 2017 The Go Authors. 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 "sync"
+
+// The line numbering of this file is important for TestTBHelper.
+
+func notHelper(t *T, msg string) {
+	t.Error(msg)
+}
+
+func helper(t *T, msg string) {
+	t.Helper()
+	t.Error(msg)
+}
+
+func notHelperCallingHelper(t *T, msg string) {
+	helper(t, msg)
+}
+
+func helperCallingHelper(t *T, msg string) {
+	t.Helper()
+	helper(t, msg)
+}
+
+func testHelper(t *T) {
+	// Check combinations of directly and indirectly
+	// calling helper functions.
+	notHelper(t, "0")
+	helper(t, "1")
+	notHelperCallingHelper(t, "2")
+	helperCallingHelper(t, "3")
+
+	// Check a function literal closing over t that uses Helper.
+	fn := func(msg string) {
+		t.Helper()
+		t.Error(msg)
+	}
+	fn("4")
+
+	// Check that calling Helper from inside this test entry function
+	// doesn't have an effect.
+	t.Helper()
+	t.Error("5")
+
+	t.Run("sub", func(t *T) {
+		helper(t, "6")
+		notHelperCallingHelper(t, "7")
+		t.Helper()
+		t.Error("8")
+	})
+}
+
+func parallelTestHelper(t *T) {
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(1)
+		go func() {
+			notHelperCallingHelper(t, "parallel")
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/testing/internal/testdeps/deps.go b/src/testing/internal/testdeps/deps.go
index b08300b..042f696 100644
--- a/src/testing/internal/testdeps/deps.go
+++ b/src/testing/internal/testdeps/deps.go
@@ -49,3 +49,10 @@ func (TestDeps) WriteHeapProfile(w io.Writer) error {
 func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error {
 	return pprof.Lookup(name).WriteTo(w, debug)
 }
+
+// ImportPath is the import path of the testing binary, set by the generated main function.
+var ImportPath string
+
+func (TestDeps) ImportPath() string {
+	return ImportPath
+}
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 95860fd..94d8739 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -14,6 +14,7 @@ import (
 	"math/rand"
 	"reflect"
 	"strings"
+	"time"
 )
 
 var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
@@ -43,8 +44,10 @@ func randFloat64(rand *rand.Rand) float64 {
 	return f
 }
 
-// randInt64 returns a random integer taking half the range of an int64.
-func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+// randInt64 returns a random int64.
+func randInt64(rand *rand.Rand) int64 {
+	return int64(rand.Uint64())
+}
 
 // complexSize is the maximum length of arbitrary values that contain other
 // values.
@@ -193,7 +196,7 @@ var defaultConfig Config
 // getRand returns the *rand.Rand to use for a given Config.
 func (c *Config) getRand() *rand.Rand {
 	if c.Rand == nil {
-		return rand.New(rand.NewSource(0))
+		return rand.New(rand.NewSource(time.Now().UnixNano()))
 	}
 	return c.Rand
 }
diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go
index fe44359..4246cd1 100644
--- a/src/testing/quick/quick_test.go
+++ b/src/testing/quick/quick_test.go
@@ -307,3 +307,21 @@ func TestNonZeroSliceAndMap(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestInt64(t *testing.T) {
+	var lo, hi int64
+	f := func(x int64) bool {
+		if x < lo {
+			lo = x
+		}
+		if x > hi {
+			hi = x
+		}
+		return true
+	}
+	cfg := &Config{MaxCount: 100000}
+	Check(f, cfg)
+	if uint64(lo)>>62 == 0 || uint64(hi)>>62 == 0 {
+		t.Errorf("int64 returned range %#016x,%#016x; does not look like full range", lo, hi)
+	}
+}
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index bb7b3e0..ab145b5 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -7,12 +7,20 @@ package testing
 import (
 	"bytes"
 	"fmt"
+	"os"
 	"regexp"
+	"runtime"
 	"strings"
+	"sync"
 	"sync/atomic"
 	"time"
 )
 
+func init() {
+	// Make benchmark tests run 10* faster.
+	*benchTime = 100 * time.Millisecond
+}
+
 func TestTestContext(t *T) {
 	const (
 		add1 = 0
@@ -455,8 +463,14 @@ func TestBRun(t *T) {
 					_ = append([]byte(nil), buf[:]...)
 				}
 			}
-			b.Run("", func(b *B) { alloc(b) })
-			b.Run("", func(b *B) { alloc(b) })
+			b.Run("", func(b *B) {
+				alloc(b)
+				b.ReportAllocs()
+			})
+			b.Run("", func(b *B) {
+				alloc(b)
+				b.ReportAllocs()
+			})
 			// 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
@@ -517,6 +531,16 @@ func TestBenchmarkOutput(t *T) {
 	Benchmark(func(b *B) {})
 }
 
+func TestBenchmarkStartsFrom1(t *T) {
+	var first = true
+	Benchmark(func(b *B) {
+		if first && b.N != 1 {
+			panic(fmt.Sprintf("Benchmark() first N=%v; want 1", b.N))
+		}
+		first = false
+	})
+}
+
 func TestParallelSub(t *T) {
 	c := make(chan int)
 	block := make(chan int)
@@ -532,3 +556,60 @@ func TestParallelSub(t *T) {
 		<-c
 	}
 }
+
+type funcWriter func([]byte) (int, error)
+
+func (fw funcWriter) Write(b []byte) (int, error) { return fw(b) }
+
+func TestRacyOutput(t *T) {
+	var runs int32  // The number of running Writes
+	var races int32 // Incremented for each race detected
+	raceDetector := func(b []byte) (int, error) {
+		// Check if some other goroutine is concurrently calling Write.
+		if atomic.LoadInt32(&runs) > 0 {
+			atomic.AddInt32(&races, 1) // Race detected!
+		}
+		atomic.AddInt32(&runs, 1)
+		defer atomic.AddInt32(&runs, -1)
+		runtime.Gosched() // Increase probability of a race
+		return len(b), nil
+	}
+
+	var wg sync.WaitGroup
+	root := &T{
+		common:  common{w: funcWriter(raceDetector), chatty: true},
+		context: newTestContext(1, newMatcher(regexp.MatchString, "", "")),
+	}
+	root.Run("", func(t *T) {
+		for i := 0; i < 100; i++ {
+			wg.Add(1)
+			go func(i int) {
+				defer wg.Done()
+				t.Run(fmt.Sprint(i), func(t *T) {
+					t.Logf("testing run %d", i)
+				})
+			}(i)
+		}
+	})
+	wg.Wait()
+
+	if races > 0 {
+		t.Errorf("detected %d racy Writes", races)
+	}
+}
+
+func TestBenchmark(t *T) {
+	res := Benchmark(func(b *B) {
+		for i := 0; i < 5; i++ {
+			b.Run("", func(b *B) {
+				fmt.Fprintf(os.Stderr, "b.N: %v\n", b.N)
+				for i := 0; i < b.N; i++ {
+					time.Sleep(time.Millisecond)
+				}
+			})
+		}
+	})
+	if res.NsPerOp() < 4000000 {
+		t.Errorf("want >5ms; got %v", time.Duration(res.NsPerOp()))
+	}
+}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index bd19a31..dbe9089 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -83,16 +83,30 @@
 // ignores leading and trailing space.) These are examples of an example:
 //
 //     func ExampleHello() {
-//             fmt.Println("hello")
-//             // Output: hello
+//         fmt.Println("hello")
+//         // Output: hello
 //     }
 //
 //     func ExampleSalutations() {
-//             fmt.Println("hello, and")
-//             fmt.Println("goodbye")
-//             // Output:
-//             // hello, and
-//             // goodbye
+//         fmt.Println("hello, and")
+//         fmt.Println("goodbye")
+//         // Output:
+//         // hello, and
+//         // goodbye
+//     }
+//
+// The comment prefix "Unordered output:" is like "Output:", but matches any
+// line order:
+//
+//     func ExamplePerm() {
+//         for _, value := range Perm(4) {
+//             fmt.Println(value)
+//         }
+//         // Unordered output: 4
+//         // 2
+//         // 1
+//         // 3
+//         // 0
 //     }
 //
 // Example functions without output comments are compiled but not executed.
@@ -210,13 +224,16 @@ import (
 	"internal/race"
 	"io"
 	"os"
+	"os/signal"
 	"runtime"
 	"runtime/debug"
 	"runtime/trace"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
 	"sync/atomic"
+	"syscall"
 	"time"
 )
 
@@ -238,6 +255,7 @@ var (
 	chatty               = flag.Bool("test.v", false, "verbose: print additional output")
 	count                = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
 	coverProfile         = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
+	matchList            = flag.String("test.list", "", "list tests, examples, and benchmarch maching `regexp` then exit")
 	match                = flag.String("test.run", "", "run only tests and examples matching `regexp`")
 	memProfile           = flag.String("test.memprofile", "", "write a memory profile to `file`")
 	memProfileRate       = flag.Int("test.memprofilerate", 0, "set memory profiling `rate` (see runtime.MemProfileRate)")
@@ -254,22 +272,29 @@ var (
 	haveExamples bool // are there examples?
 
 	cpuList []int
+
+	inProgressMu       sync.Mutex // guards this group of fields
+	inProgressRegistry = make(map[string]int)
+	inProgressIdx      int
 )
 
 // common holds the elements common between T and B and
 // captures common methods such as Errorf.
 type common struct {
-	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.
-	ran        bool         // Test or benchmark (or one of its subtests) was executed.
-	failed     bool         // Test or benchmark has failed.
-	skipped    bool         // Test of benchmark has been skipped.
-	finished   bool         // Test function has completed.
-	done       bool         // Test is finished and all subtests have completed.
-	hasSub     int32        // written atomically
-	raceErrors int          // number of races detected during test
+	mu      sync.RWMutex        // guards this group of fields
+	output  []byte              // Output generated by test or benchmark.
+	w       io.Writer           // For flushToParent.
+	ran     bool                // Test or benchmark (or one of its subtests) was executed.
+	failed  bool                // Test or benchmark has failed.
+	skipped bool                // Test of benchmark has been skipped.
+	done    bool                // Test is finished and all subtests have completed.
+	helpers map[string]struct{} // functions to be skipped when writing file/line info
+
+	chatty     bool   // A copy of the chatty flag.
+	finished   bool   // Test function has completed.
+	hasSub     int32  // written atomically
+	raceErrors int    // number of races detected during test
+	runner     string // function name of tRunner running the test
 
 	parent   *common
 	level    int       // Nesting depth of test or benchmark.
@@ -298,10 +323,48 @@ func Verbose() bool {
 	return *chatty
 }
 
+// frameSkip searches, starting after skip frames, for the first caller frame
+// in a function not marked as a helper and returns the frames to skip
+// to reach that site. The search stops if it finds a tRunner function that
+// was the entry point into the test.
+// This function must be called with c.mu held.
+func (c *common) frameSkip(skip int) int {
+	if c.helpers == nil {
+		return skip
+	}
+	var pc [50]uintptr
+	// Skip two extra frames to account for this function
+	// and runtime.Callers itself.
+	n := runtime.Callers(skip+2, pc[:])
+	if n == 0 {
+		panic("testing: zero callers found")
+	}
+	frames := runtime.CallersFrames(pc[:n])
+	var frame runtime.Frame
+	more := true
+	for i := 0; more; i++ {
+		frame, more = frames.Next()
+		if frame.Function == c.runner {
+			// We've gone up all the way to the tRunner calling
+			// the test function (so the user must have
+			// called tb.Helper from inside that test function).
+			// Only skip up to the test function itself.
+			return skip + i - 1
+		}
+		if _, ok := c.helpers[frame.Function]; !ok {
+			// Found a frame that wasn't inside a helper function.
+			return skip + i
+		}
+	}
+	return skip
+}
+
 // decorate prefixes the string with the file and line of the call site
 // and inserts the final newline if needed and indentation tabs for formatting.
-func decorate(s string) string {
-	_, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+// This function must be called with c.mu held.
+func (c *common) decorate(s string) string {
+	skip := c.frameSkip(3) // decorate + log + public function.
+	_, file, line, ok := runtime.Caller(skip)
 	if ok {
 		// Truncate file name at last file name separator.
 		if index := strings.LastIndex(file, "/"); index >= 0 {
@@ -391,6 +454,7 @@ type TB interface {
 	SkipNow()
 	Skipf(format string, args ...interface{})
 	Skipped() bool
+	Helper()
 
 	// A private method to prevent users implementing the
 	// interface and so future additions to it will not
@@ -450,8 +514,9 @@ func (c *common) Fail() {
 // Failed reports whether the function has failed.
 func (c *common) Failed() bool {
 	c.mu.RLock()
-	defer c.mu.RUnlock()
-	return c.failed
+	failed := c.failed
+	c.mu.RUnlock()
+	return failed || c.raceErrors+race.Errors() > 0
 }
 
 // FailNow marks the function as having failed and stops its execution.
@@ -490,7 +555,7 @@ func (c *common) FailNow() {
 func (c *common) log(s string) {
 	c.mu.Lock()
 	defer c.mu.Unlock()
-	c.output = append(c.output, decorate(s)...)
+	c.output = append(c.output, c.decorate(s)...)
 }
 
 // Log formats its arguments using default formatting, analogous to Println,
@@ -568,8 +633,38 @@ func (c *common) Skipped() bool {
 	return c.skipped
 }
 
+// Helper marks the calling function as a test helper function.
+// When printing file and line information, that function will be skipped.
+// Helper may be called simultaneously from multiple goroutines.
+// Helper has no effect if it is called directly from a TestXxx/BenchmarkXxx
+// function or a subtest/sub-benchmark function.
+func (c *common) Helper() {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.helpers == nil {
+		c.helpers = make(map[string]struct{})
+	}
+	c.helpers[callerName(1)] = struct{}{}
+}
+
+// callerName gives the function name (qualified with a package path)
+// for the caller after skip frames (where 0 means the current function).
+func callerName(skip int) string {
+	// Make room for the skip PC.
+	var pc [2]uintptr
+	n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName
+	if n == 0 {
+		panic("testing: zero callers found")
+	}
+	frames := runtime.CallersFrames(pc[:n])
+	frame, _ := frames.Next()
+	return frame.Function
+}
+
 // Parallel signals that this test is to be run in parallel with (and only with)
-// other parallel tests.
+// other parallel tests. When a test is run multiple times due to use of
+// -test.count or -test.cpu, multiple instances of a single test never run in
+// parallel with each other.
 func (t *T) Parallel() {
 	if t.isParallel {
 		panic("testing: t.Parallel called multiple times")
@@ -600,6 +695,8 @@ type InternalTest struct {
 }
 
 func tRunner(t *T, fn func(t *T)) {
+	t.runner = callerName(0)
+
 	// 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
@@ -658,11 +755,12 @@ func tRunner(t *T, fn func(t *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.
+// Run runs f as a subtest of t called name. It reports whether f succeeded. Run
+// runs f in a separate goroutine and will block until all its parallel subtests
+// have completed.
 //
-// Run may be called simultaneously from multiple goroutines, but all such
-// calls must happen before the outer test function for t returns.
+// Run may be called simultaneously from multiple goroutines, but all such calls
+// must happen before the outer test function for t returns.
 func (t *T) Run(name string, f func(t *T)) bool {
 	atomic.StoreInt32(&t.hasSub, 1)
 	testName, ok := t.context.match.fullName(&t.common, name)
@@ -687,7 +785,12 @@ func (t *T) Run(name string, f func(t *T)) bool {
 		root := t.parent
 		for ; root.parent != nil; root = root.parent {
 		}
+		inProgressMu.Lock()
+		root.mu.Lock()
+		t.registerInProgress()
 		fmt.Fprintf(root.w, "=== RUN   %s\n", t.name)
+		root.mu.Unlock()
+		inProgressMu.Unlock()
 	}
 	// Instead of reducing the running count of this test before calling the
 	// tRunner and increasing it afterwards, we rely on tRunner keeping the
@@ -764,6 +867,7 @@ func (f matchStringOnly) StartCPUProfile(w io.Writer) error           { return e
 func (f matchStringOnly) StopCPUProfile()                             {}
 func (f matchStringOnly) WriteHeapProfile(w io.Writer) error          { return errMain }
 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
+func (f matchStringOnly) ImportPath() string                          { return "" }
 
 // Main is an internal function, part of the implementation of the "go test" command.
 // It was exported because it is cross-package and predates "internal" packages.
@@ -793,6 +897,7 @@ type testDeps interface {
 	StopCPUProfile()
 	WriteHeapProfile(io.Writer) error
 	WriteProfileTo(string, io.Writer, int) error
+	ImportPath() string
 }
 
 // MainStart is meant for use by tests generated by 'go test'.
@@ -814,6 +919,11 @@ func (m *M) Run() int {
 		flag.Parse()
 	}
 
+	if len(*matchList) != 0 {
+		listTests(m.deps.MatchString, m.tests, m.benchmarks, m.examples)
+		return 0
+	}
+
 	parseCpuList()
 
 	m.before()
@@ -825,7 +935,7 @@ func (m *M) Run() int {
 	if !testRan && !exampleRan && *matchBenchmarks == "" {
 		fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
 	}
-	if !testOk || !exampleOk || !runBenchmarks(m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
+	if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
 		fmt.Println("FAIL")
 		m.after()
 		return 1
@@ -842,6 +952,11 @@ func (t *T) report() {
 	}
 	dstr := fmtDuration(t.duration)
 	format := "--- %s: %s (%s)\n"
+
+	inProgressMu.Lock()
+	defer inProgressMu.Unlock()
+	defer t.registerComplete()
+
 	if t.Failed() {
 		t.flushToParent(format, "FAIL", t.name, dstr)
 	} else if t.chatty {
@@ -853,6 +968,62 @@ func (t *T) report() {
 	}
 }
 
+func (t *T) registerInProgress() {
+	if !t.chatty {
+		return
+	}
+	inProgressRegistry[t.name] = inProgressIdx
+	inProgressIdx++
+}
+
+func (t *T) registerComplete() {
+	if !t.chatty {
+		return
+	}
+	delete(inProgressRegistry, t.name)
+}
+
+func reportTestsInProgress() {
+	if len(inProgressRegistry) == 0 {
+		return
+	}
+	idxToName := make(map[int]string)
+	var indexes []int
+	for name, idx := range inProgressRegistry {
+		idxToName[idx] = name
+		indexes = append(indexes, idx)
+	}
+	sort.Ints(indexes)
+	var namesInOrder []string
+	for _, idx := range indexes {
+		namesInOrder = append(namesInOrder, idxToName[idx])
+	}
+	fmt.Printf("\ntests in progress: %s\n", strings.Join(namesInOrder, ", "))
+}
+
+func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
+	if _, err := matchString(*matchList, "non-empty"); err != nil {
+		fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
+		os.Exit(1)
+	}
+
+	for _, test := range tests {
+		if ok, _ := matchString(*matchList, test.Name); ok {
+			fmt.Println(test.Name)
+		}
+	}
+	for _, bench := range benchmarks {
+		if ok, _ := matchString(*matchList, bench.Name); ok {
+			fmt.Println(bench.Name)
+		}
+	}
+	for _, example := range examples {
+		if ok, _ := matchString(*matchList, example.Name); ok && example.Output != "" {
+			fmt.Println(example.Name)
+		}
+	}
+}
+
 // An internal function but exported because it is cross-package; part of the implementation
 // of the "go test" command.
 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
@@ -933,6 +1104,24 @@ func (m *M) before() {
 		fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
 		os.Exit(2)
 	}
+	if Verbose() {
+		sigCh := make(chan os.Signal, 1)
+		signal.Notify(sigCh, os.Interrupt)
+		go func() {
+			<-sigCh
+			signal.Stop(sigCh)
+			inProgressMu.Lock()
+			reportTestsInProgress()
+			inProgressMu.Unlock()
+			proc, err := os.FindProcess(syscall.Getpid())
+			if err == nil {
+				err = proc.Signal(os.Interrupt)
+			}
+			if err != nil {
+				os.Exit(2)
+			}
+		}()
+	}
 }
 
 // after runs after all testing.
diff --git a/src/text/scanner/example_test.go b/src/text/scanner/example_test.go
index 1d5d34a..97e22a9 100644
--- a/src/text/scanner/example_test.go
+++ b/src/text/scanner/example_test.go
@@ -12,28 +12,25 @@ import (
 
 func Example() {
 	const src = `
-	// This is scanned code.
-	if a > 10 {
-		someParsable = text
-	}`
+// This is scanned code.
+if a > 10 {
+	someParsable = text
+}`
 	var s scanner.Scanner
-	s.Filename = "example"
 	s.Init(strings.NewReader(src))
-	var tok rune
-	for tok != scanner.EOF {
-		tok = s.Scan()
-		fmt.Println("At position", s.Pos(), ":", s.TokenText())
+	s.Filename = "example"
+	for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
+		fmt.Printf("%s: %s\n", s.Position, s.TokenText())
 	}
 
 	// Output:
-	// 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 :
+	// example:3:1: if
+	// example:3:4: a
+	// example:3:6: >
+	// example:3:8: 10
+	// example:3:11: {
+	// example:4:2: someParsable
+	// example:4:15: =
+	// example:4:17: text
+	// example:5:1: }
 }
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index e085f8a..6fb0422 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -166,7 +166,8 @@ type Scanner struct {
 	// The Filename field is always left untouched by the Scanner.
 	// If an error is reported (via Error) and Position is invalid,
 	// the scanner is not inside a token. Call Pos to obtain an error
-	// position in that case.
+	// position in that case, or to obtain the position immediately
+	// after the most recently scanned token.
 	Position
 }
 
@@ -637,6 +638,8 @@ redo:
 
 // Pos returns the position of the character immediately after
 // the character or token returned by the last call to Next or Scan.
+// Use the Scanner's Position field for the start position of the most
+// recently scanned token.
 func (s *Scanner) Pos() (pos Position) {
 	pos.Filename = s.Filename
 	pos.Offset = s.srcBufOffset + s.srcPos - s.lastCharLen
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index fe59e3f..d174ebd 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -20,7 +20,8 @@ The input text for a template is UTF-8-encoded text in any format.
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
 Except for raw strings, actions may not span newlines, although comments can.
 
-Once parsed, a template may be executed safely in parallel.
+Once parsed, a template may be executed safely in parallel, although if parallel
+executions share a Writer the output may be interleaved.
 
 Here is a trivial example that prints "17 items are made of wool".
 
@@ -80,14 +81,14 @@ data, defined in detail in the corresponding sections that follow.
 
 	{{if pipeline}} T1 {{end}}
 		If the value of the pipeline is empty, no output is generated;
-		otherwise, T1 is executed.  The empty values are false, 0, any
+		otherwise, T1 is executed. The empty values are false, 0, any
 		nil pointer or interface value, and any array, slice, map, or
 		string of length zero.
 		Dot is unaffected.
 
 	{{if pipeline}} T1 {{else}} T0 {{end}}
 		If the value of the pipeline is empty, T0 is executed;
-		otherwise, T1 is executed.  Dot is unaffected.
+		otherwise, T1 is executed. Dot is unaffected.
 
 	{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
 		To simplify the appearance of if-else chains, the else action
@@ -241,19 +242,19 @@ where $variable is the name of the variable. An action that declares a
 variable produces no output.
 
 If a "range" action initializes a variable, the variable is set to the
-successive elements of the iteration.  Also, a "range" may declare two
+successive elements of the iteration. Also, a "range" may declare two
 variables, separated by a comma:
 
 	range $index, $element := pipeline
 
 in which case $index and $element are set to the successive values of the
-array/slice index or map key and element, respectively.  Note that if there is
+array/slice index or map key and element, respectively. Note that if there is
 only one variable, it is assigned the element; this is opposite to the
 convention in Go range clauses.
 
 A variable's scope extends to the "end" action of the control structure ("if",
 "with", or "range") in which it is declared, or to the end of the template if
-there is no such control structure.  A template invocation does not inherit
+there is no such control structure. A template invocation does not inherit
 variables from the point of its invocation.
 
 When execution begins, $ is set to the data argument passed to Execute, that is,
@@ -314,7 +315,8 @@ Predefined global functions are named as follows.
 		or the returned error value is non-nil, execution stops.
 	html
 		Returns the escaped HTML equivalent of the textual
-		representation of its arguments.
+		representation of its arguments. This function is unavailable
+		in html/template, with a few exceptions.
 	index
 		Returns the result of indexing its first argument by the
 		following arguments. Thus "index x 1 2 3" is, in Go syntax,
@@ -340,6 +342,8 @@ Predefined global functions are named as follows.
 	urlquery
 		Returns the escaped value of the textual representation of
 		its arguments in a form suitable for embedding in a URL query.
+		This function is unavailable in html/template, with a few
+		exceptions.
 
 The boolean functions take any zero value to be false and a non-zero
 value to be true.
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index ea964dc..e54a579 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -153,7 +153,8 @@ func errRecover(errp *error) {
 // If an error occurs executing the template or writing its output,
 // execution stops, but partial results may already have been written to
 // the output writer.
-// A template may be executed safely in parallel.
+// A template may be executed safely in parallel, although if parallel
+// executions share a Writer the output may be interleaved.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
 	var tmpl *Template
 	if t.common != nil {
@@ -170,7 +171,8 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
 // If an error occurs executing the template or writing its output,
 // execution stops, but partial results may already have been written to
 // the output writer.
-// A template may be executed safely in parallel.
+// A template may be executed safely in parallel, although if parallel
+// executions share a Writer the output may be interleaved.
 //
 // If data is a reflect.Value, the template applies to the concrete
 // value that the reflect.Value holds, as in fmt.Print.
@@ -551,7 +553,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
 	// Unless it's an interface, need to get to a value of type *T to guarantee
 	// we see all methods of T and *T.
 	ptr := receiver
-	if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
+	if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() {
 		ptr = ptr.Addr()
 	}
 	if method := ptr.MethodByName(fieldName); method.IsValid() {
@@ -628,7 +630,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
 		if numIn < numFixed {
 			s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
 		}
-	} else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() {
+	} else if numIn != typ.NumIn() {
 		s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args))
 	}
 	if !goodFunc(typ) {
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index 5892b27..9f7e637 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -147,6 +147,8 @@ var tVal = &T{
 	Tmpl:                 Must(New("x").Parse("test template")), // "x" is the value of .X
 }
 
+var tSliceOfNil = []*T{nil}
+
 // A non-empty interface.
 type I interface {
 	Method0() string
@@ -337,6 +339,7 @@ var execTests = []execTest{
 		"true", tVal, true},
 	{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
 	{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
+	{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
 
 	// Function call builtin.
 	{".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index 3047b27..9107431 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -489,6 +489,7 @@ var (
 	htmlAmp  = []byte("&")
 	htmlLt   = []byte("<")
 	htmlGt   = []byte(">")
+	htmlNull = []byte("\uFFFD")
 )
 
 // HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
@@ -497,6 +498,8 @@ func HTMLEscape(w io.Writer, b []byte) {
 	for i, c := range b {
 		var html []byte
 		switch c {
+		case '\000':
+			html = htmlNull
 		case '"':
 			html = htmlQuot
 		case '\'':
@@ -520,7 +523,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.ContainsAny(s, `'"&<>`) {
+	if !strings.ContainsAny(s, "'\"&<>\000") {
 		return s
 	}
 	var b bytes.Buffer
diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go
index d655d78..2c73bb6 100644
--- a/src/text/template/parse/lex_test.go
+++ b/src/text/template/parse/lex_test.go
@@ -498,7 +498,7 @@ func TestShutdown(t *testing.T) {
 	// We need to duplicate template.Parse here to hold on to the lexer.
 	const text = "erroneous{{define}}{{else}}1234"
 	lexer := lex("foo", text, "{{", "}}")
-	_, err := New("root").parseLexer(lexer, text)
+	_, err := New("root").parseLexer(lexer)
 	if err == nil {
 		t.Fatalf("expected error")
 	}
@@ -511,7 +511,7 @@ func TestShutdown(t *testing.T) {
 
 // parseLexer is a local version of parse that lets us pass in the lexer instead of building it.
 // We expect an error, so the tree set and funcs list are explicitly nil.
-func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) {
+func (t *Tree) parseLexer(lex *lexer) (tree *Tree, err error) {
 	defer t.recover(&err)
 	t.ParseName = t.Name
 	t.startParse(nil, lex, map[string]*Tree{})
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index 6060c6d..a91a544 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -202,7 +202,6 @@ func (t *Tree) recover(errp *error) {
 		}
 		*errp = e.(error)
 	}
-	return
 }
 
 // startParse initializes the parser, using the lexer.
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 3b4f34b..2246f67 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -159,6 +159,7 @@ func (t *Template) Delims(left, right string) *Template {
 }
 
 // Funcs adds the elements of the argument map to the template's function map.
+// It must be called before the template is parsed.
 // It panics if a value in the map is not a function with appropriate return
 // type or if the name cannot be used syntactically as a function in a template.
 // It is legal to overwrite elements of the map. The return value is the template,
diff --git a/src/time/export_test.go b/src/time/export_test.go
index 6cd535f..4c08ab1 100644
--- a/src/time/export_test.go
+++ b/src/time/export_test.go
@@ -18,7 +18,20 @@ func ForceUSPacificForTesting() {
 	localOnce.Do(initTestingZone)
 }
 
+func ZoneinfoForTesting() *string {
+	return zoneinfo
+}
+
+func ResetZoneinfoForTesting() {
+	zoneinfo = nil
+	zoneinfoOnce = sync.Once{}
+}
+
 var (
 	ForceZipFileForTesting = forceZipFileForTesting
 	ParseTimeZone          = parseTimeZone
+	SetMono                = (*Time).setMono
+	GetMono                = (*Time).mono
+	ErrLocation            = errLocation
+	ReadFile               = readFile
 )
diff --git a/src/time/format.go b/src/time/format.go
index b903e14..37e759f 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -424,8 +424,37 @@ func formatNano(b []byte, nanosec uint, n int, trim bool) []byte {
 
 // String returns the time formatted using the format string
 //	"2006-01-02 15:04:05.999999999 -0700 MST"
+//
+// If the time has a monotonic clock reading, the returned string
+// includes a final field "m=±<value>", where value is the monotonic
+// clock reading formatted as a decimal number of seconds.
 func (t Time) String() string {
-	return t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
+	s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
+
+	// Format monotonic clock reading as m=±ddd.nnnnnnnnn.
+	if t.wall&hasMonotonic != 0 {
+		m2 := uint64(t.ext)
+		sign := byte('+')
+		if t.ext < 0 {
+			sign = '-'
+			m2 = -m2
+		}
+		m1, m2 := m2/1e9, m2%1e9
+		m0, m1 := m1/1e9, m1%1e9
+		var buf []byte
+		buf = append(buf, " m="...)
+		buf = append(buf, sign)
+		wid := 0
+		if m0 != 0 {
+			buf = appendInt(buf, int(m0), 0)
+			wid = 9
+		}
+		buf = appendInt(buf, int(m1), wid)
+		buf = append(buf, '.')
+		buf = appendInt(buf, int(m2), 9)
+		s += string(buf)
+	}
+	return s
 }
 
 // Format returns a textual representation of the time value formatted
@@ -725,11 +754,6 @@ func skip(value, prefix string) (string, error) {
 // location and zone in the returned time. Otherwise it records the time as
 // being in a fabricated location with time fixed at the given zone offset.
 //
-// No checking is done that the day of the month is within the month's
-// valid dates; any one- or two-digit value is accepted. For example
-// February 31 and even February 99 are valid dates, specifying dates
-// in March and May. This behavior is consistent with time.Date.
-//
 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation
 // has a defined offset in the current location, then that offset is used.
 // The zone abbreviation "UTC" is recognized as UTC regardless of location.
@@ -1022,11 +1046,11 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
 
 	if zoneOffset != -1 {
 		t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
-		t.sec -= int64(zoneOffset)
+		t.addSec(-int64(zoneOffset))
 
 		// Look for local zone with the given offset.
 		// If that zone was in effect at the given time, use it.
-		name, offset, _, _, _ := local.lookup(t.sec + internalToUnix)
+		name, offset, _, _, _ := local.lookup(t.unixSec())
 		if offset == zoneOffset && (zoneName == "" || name == zoneName) {
 			t.setLoc(local)
 			return t, nil
@@ -1041,9 +1065,9 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
 		t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
 		// Look for local zone with the given offset.
 		// If that zone was in effect at the given time, use it.
-		offset, _, ok := local.lookupName(zoneName, t.sec+internalToUnix)
+		offset, _, ok := local.lookupName(zoneName, t.unixSec())
 		if ok {
-			t.sec -= int64(offset)
+			t.addSec(-int64(offset))
 			t.setLoc(local)
 			return t, nil
 		}
diff --git a/src/time/format_test.go b/src/time/format_test.go
index d0013bc..710de59 100644
--- a/src/time/format_test.go
+++ b/src/time/format_test.go
@@ -378,8 +378,8 @@ func checkTime(time Time, test *ParseTest, t *testing.T) {
 func TestFormatAndParse(t *testing.T) {
 	const fmt = "Mon MST " + RFC3339 // all fields
 	f := func(sec int64) bool {
-		t1 := Unix(sec, 0)
-		if t1.Year() < 1000 || t1.Year() > 9999 {
+		t1 := Unix(sec/2, 0)
+		if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec {
 			// not required to work
 			return true
 		}
diff --git a/src/time/genzabbrs.go b/src/time/genzabbrs.go
index 6281f73..824a67f 100644
--- a/src/time/genzabbrs.go
+++ b/src/time/genzabbrs.go
@@ -142,8 +142,8 @@ const prog = `
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// generated by genzabbrs.go from
-// {{.URL}}
+// Code generated by genzabbrs.go; DO NOT EDIT.
+// Based on information from {{.URL}}
 
 package time
 
diff --git a/src/time/mono_test.go b/src/time/mono_test.go
new file mode 100644
index 0000000..8778ab7
--- /dev/null
+++ b/src/time/mono_test.go
@@ -0,0 +1,261 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+	"strings"
+	"testing"
+	. "time"
+)
+
+func TestHasMonotonicClock(t *testing.T) {
+	yes := func(expr string, tt Time) {
+		if GetMono(&tt) == 0 {
+			t.Errorf("%s: missing monotonic clock reading", expr)
+		}
+	}
+	no := func(expr string, tt Time) {
+		if GetMono(&tt) != 0 {
+			t.Errorf("%s: unexpected monotonic clock reading", expr)
+		}
+	}
+
+	yes("<-After(1)", <-After(1))
+	ticker := NewTicker(1)
+	yes("<-Tick(1)", <-ticker.C)
+	ticker.Stop()
+	no("Date(2009, 11, 23, 0, 0, 0, 0, UTC)", Date(2009, 11, 23, 0, 0, 0, 0, UTC))
+	tp, _ := Parse(UnixDate, "Sat Mar  7 11:06:39 PST 2015")
+	no(`Parse(UnixDate, "Sat Mar  7 11:06:39 PST 2015")`, tp)
+	no("Unix(1486057371, 0)", Unix(1486057371, 0))
+
+	yes("Now()", Now())
+
+	tu := Unix(1486057371, 0)
+	tm := tu
+	SetMono(&tm, 123456)
+	no("tu", tu)
+	yes("tm", tm)
+
+	no("tu.Add(1)", tu.Add(1))
+	no("tu.In(UTC)", tu.In(UTC))
+	no("tu.AddDate(1, 1, 1)", tu.AddDate(1, 1, 1))
+	no("tu.AddDate(0, 0, 0)", tu.AddDate(0, 0, 0))
+	no("tu.Local()", tu.Local())
+	no("tu.UTC()", tu.UTC())
+	no("tu.Round(2)", tu.Round(2))
+	no("tu.Truncate(2)", tu.Truncate(2))
+
+	yes("tm.Add(1)", tm.Add(1))
+	no("tm.AddDate(1, 1, 1)", tm.AddDate(1, 1, 1))
+	no("tm.AddDate(0, 0, 0)", tm.AddDate(0, 0, 0))
+	no("tm.In(UTC)", tm.In(UTC))
+	no("tm.Local()", tm.Local())
+	no("tm.UTC()", tm.UTC())
+	no("tm.Round(2)", tm.Round(2))
+	no("tm.Truncate(2)", tm.Truncate(2))
+}
+
+func TestMonotonicAdd(t *testing.T) {
+	tm := Unix(1486057371, 123456)
+	SetMono(&tm, 123456789012345)
+
+	t2 := tm.Add(1e8)
+	if t2.Nanosecond() != 100123456 {
+		t.Errorf("t2.Nanosecond() = %d, want 100123456", t2.Nanosecond())
+	}
+	if GetMono(&t2) != 123456889012345 {
+		t.Errorf("t2.mono = %d, want 123456889012345", GetMono(&t2))
+	}
+
+	t3 := tm.Add(-9e18) // wall now out of range
+	if t3.Nanosecond() != 123456 {
+		t.Errorf("t3.Nanosecond() = %d, want 123456", t3.Nanosecond())
+	}
+	if GetMono(&t3) != 0 {
+		t.Errorf("t3.mono = %d, want 0 (wall time out of range for monotonic reading)", GetMono(&t3))
+	}
+
+	t4 := tm.Add(+9e18) // wall now out of range
+	if t4.Nanosecond() != 123456 {
+		t.Errorf("t4.Nanosecond() = %d, want 123456", t4.Nanosecond())
+	}
+	if GetMono(&t4) != 0 {
+		t.Errorf("t4.mono = %d, want 0 (wall time out of range for monotonic reading)", GetMono(&t4))
+	}
+
+	tn := Now()
+	tn1 := tn.Add(1 * Hour)
+	Sleep(100 * Millisecond)
+	d := Until(tn1)
+	if d < 59*Minute {
+		t.Errorf("Until(Now().Add(1*Hour)) = %v, wanted at least 59m", d)
+	}
+	now := Now()
+	if now.After(tn1) {
+		t.Errorf("Now().After(Now().Add(1*Hour)) = true, want false")
+	}
+	if !tn1.After(now) {
+		t.Errorf("Now().Add(1*Hour).After(now) = false, want true")
+	}
+	if tn1.Before(now) {
+		t.Errorf("Now().Add(1*Hour).Before(Now()) = true, want false")
+	}
+	if !now.Before(tn1) {
+		t.Errorf("Now().Before(Now().Add(1*Hour)) = false, want true")
+	}
+}
+
+func TestMonotonicSub(t *testing.T) {
+	t1 := Unix(1483228799, 995e6)
+	SetMono(&t1, 123456789012345)
+
+	t2 := Unix(1483228799, 5e6)
+	SetMono(&t2, 123456789012345+10e6)
+
+	t3 := Unix(1483228799, 995e6)
+	SetMono(&t3, 123456789012345+1e9)
+
+	t1w := t1.AddDate(0, 0, 0)
+	if GetMono(&t1w) != 0 {
+		t.Fatalf("AddDate didn't strip monotonic clock reading")
+	}
+	t2w := t2.AddDate(0, 0, 0)
+	if GetMono(&t2w) != 0 {
+		t.Fatalf("AddDate didn't strip monotonic clock reading")
+	}
+	t3w := t3.AddDate(0, 0, 0)
+	if GetMono(&t3w) != 0 {
+		t.Fatalf("AddDate didn't strip monotonic clock reading")
+	}
+
+	sub := func(txs, tys string, tx, txw, ty, tyw Time, d, dw Duration) {
+		check := func(expr string, d, want Duration) {
+			if d != want {
+				t.Errorf("%s = %v, want %v", expr, d, want)
+			}
+		}
+		check(txs+".Sub("+tys+")", tx.Sub(ty), d)
+		check(txs+"w.Sub("+tys+")", txw.Sub(ty), dw)
+		check(txs+".Sub("+tys+"w)", tx.Sub(tyw), dw)
+		check(txs+"w.Sub("+tys+"w)", txw.Sub(tyw), dw)
+	}
+	sub("t1", "t1", t1, t1w, t1, t1w, 0, 0)
+	sub("t1", "t2", t1, t1w, t2, t2w, -10*Millisecond, 990*Millisecond)
+	sub("t1", "t3", t1, t1w, t3, t3w, -1000*Millisecond, 0)
+
+	sub("t2", "t1", t2, t2w, t1, t1w, 10*Millisecond, -990*Millisecond)
+	sub("t2", "t2", t2, t2w, t2, t2w, 0, 0)
+	sub("t2", "t3", t2, t2w, t3, t3w, -990*Millisecond, -990*Millisecond)
+
+	sub("t3", "t1", t3, t3w, t1, t1w, 1000*Millisecond, 0)
+	sub("t3", "t2", t3, t3w, t2, t2w, 990*Millisecond, 990*Millisecond)
+	sub("t3", "t3", t3, t3w, t3, t3w, 0, 0)
+
+	cmp := func(txs, tys string, tx, txw, ty, tyw Time, c, cw int) {
+		check := func(expr string, b, want bool) {
+			if b != want {
+				t.Errorf("%s = %v, want %v", expr, b, want)
+			}
+		}
+		check(txs+".After("+tys+")", tx.After(ty), c > 0)
+		check(txs+"w.After("+tys+")", txw.After(ty), cw > 0)
+		check(txs+".After("+tys+"w)", tx.After(tyw), cw > 0)
+		check(txs+"w.After("+tys+"w)", txw.After(tyw), cw > 0)
+
+		check(txs+".Before("+tys+")", tx.Before(ty), c < 0)
+		check(txs+"w.Before("+tys+")", txw.Before(ty), cw < 0)
+		check(txs+".Before("+tys+"w)", tx.Before(tyw), cw < 0)
+		check(txs+"w.Before("+tys+"w)", txw.Before(tyw), cw < 0)
+
+		check(txs+".Equal("+tys+")", tx.Equal(ty), c == 0)
+		check(txs+"w.Equal("+tys+")", txw.Equal(ty), cw == 0)
+		check(txs+".Equal("+tys+"w)", tx.Equal(tyw), cw == 0)
+		check(txs+"w.Equal("+tys+"w)", txw.Equal(tyw), cw == 0)
+	}
+
+	cmp("t1", "t1", t1, t1w, t1, t1w, 0, 0)
+	cmp("t1", "t2", t1, t1w, t2, t2w, -1, +1)
+	cmp("t1", "t3", t1, t1w, t3, t3w, -1, 0)
+
+	cmp("t2", "t1", t2, t2w, t1, t1w, +1, -1)
+	cmp("t2", "t2", t2, t2w, t2, t2w, 0, 0)
+	cmp("t2", "t3", t2, t2w, t3, t3w, -1, -1)
+
+	cmp("t3", "t1", t3, t3w, t1, t1w, +1, 0)
+	cmp("t3", "t2", t3, t3w, t2, t2w, +1, +1)
+	cmp("t3", "t3", t3, t3w, t3, t3w, 0, 0)
+}
+
+func TestMonotonicOverflow(t *testing.T) {
+	t1 := Now().Add(-30 * Second)
+	d := Until(t1)
+	if d < -35*Second || -30*Second < d {
+		t.Errorf("Until(Now().Add(-30s)) = %v, want roughly -30s (-35s to -30s)", d)
+	}
+
+	t1 = Now().Add(30 * Second)
+	d = Until(t1)
+	if d < 25*Second || 30*Second < d {
+		t.Errorf("Until(Now().Add(-30s)) = %v, want roughly 30s (25s to 30s)", d)
+	}
+
+	t0 := Now()
+	t1 = t0.Add(Duration(1<<63 - 1))
+	if GetMono(&t1) != 0 {
+		t.Errorf("Now().Add(maxDuration) has monotonic clock reading (%v => %v %d %d)", t0.String(), t1.String(), t0.Unix(), t1.Unix())
+	}
+	t2 := t1.Add(-Duration(1<<63 - 1))
+	d = Since(t2)
+	if d < -10*Second || 10*Second < d {
+		t.Errorf("Since(Now().Add(max).Add(-max)) = %v, want [-10s, 10s]", d)
+	}
+
+	t0 = Now()
+	t1 = t0.Add(1 * Hour)
+	Sleep(100 * Millisecond)
+	t2 = Now().Add(-5 * Second)
+	if !t1.After(t2) {
+		t.Errorf("Now().Add(1*Hour).After(Now().Add(-5*Second)) = false, want true\nt1=%v\nt2=%v", t1, t2)
+	}
+	if t2.After(t1) {
+		t.Errorf("Now().Add(-5*Second).After(Now().Add(1*Hour)) = true, want false\nt1=%v\nt2=%v", t1, t2)
+	}
+	if t1.Before(t2) {
+		t.Errorf("Now().Add(1*Hour).Before(Now().Add(-5*Second)) = true, want false\nt1=%v\nt2=%v", t1, t2)
+	}
+	if !t2.Before(t1) {
+		t.Errorf("Now().Add(-5*Second).Before(Now().Add(1*Hour)) = false, want true\nt1=%v\nt2=%v", t1, t2)
+	}
+}
+
+var monotonicStringTests = []struct {
+	mono int64
+	want string
+}{
+	{0, "m=+0.000000000"},
+	{123456789, "m=+0.123456789"},
+	{-123456789, "m=-0.123456789"},
+	{123456789000, "m=+123.456789000"},
+	{-123456789000, "m=-123.456789000"},
+	{9e18, "m=+9000000000.000000000"},
+	{-9e18, "m=-9000000000.000000000"},
+	{-1 << 63, "m=-9223372036.854775808"},
+}
+
+func TestMonotonicString(t *testing.T) {
+	t1 := Now()
+	t.Logf("Now() = %v", t1)
+
+	for _, tt := range monotonicStringTests {
+		t1 := Now()
+		SetMono(&t1, tt.mono)
+		s := t1.String()
+		got := s[strings.LastIndex(s, " ")+1:]
+		if got != tt.want {
+			t.Errorf("with mono=%d: got %q; want %q", tt.mono, got, tt.want)
+		}
+	}
+}
diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go
index dd0a820..9b4a3cc 100644
--- a/src/time/sleep_test.go
+++ b/src/time/sleep_test.go
@@ -227,7 +227,7 @@ func TestAfterQueuing(t *testing.T) {
 	err := errors.New("!=nil")
 	for i := 0; i < attempts && err != nil; i++ {
 		delta := Duration(20+i*50) * Millisecond
-		if err = testAfterQueuing(t, delta); err != nil {
+		if err = testAfterQueuing(delta); err != nil {
 			t.Logf("attempt %v failed: %v", i, err)
 		}
 	}
@@ -247,7 +247,7 @@ func await(slot int, result chan<- afterResult, ac <-chan Time) {
 	result <- afterResult{slot, <-ac}
 }
 
-func testAfterQueuing(t *testing.T, delta Duration) error {
+func testAfterQueuing(delta Duration) error {
 	// make the result channel buffered because we don't want
 	// to depend on channel queueing semantics that might
 	// possibly change in the future.
diff --git a/src/time/sys_plan9.go b/src/time/sys_plan9.go
index 11365a7..9086a6e 100644
--- a/src/time/sys_plan9.go
+++ b/src/time/sys_plan9.go
@@ -19,6 +19,7 @@ func interrupt() {
 // readFile reads and returns the content of the named file.
 // It is a trivial implementation of ioutil.ReadFile, reimplemented
 // here to avoid depending on io/ioutil or os.
+// It returns an error if name exceeds maxFileSize bytes.
 func readFile(name string) ([]byte, error) {
 	f, err := syscall.Open(name, syscall.O_RDONLY)
 	if err != nil {
@@ -38,6 +39,9 @@ func readFile(name string) ([]byte, error) {
 		if n == 0 || err != nil {
 			break
 		}
+		if len(ret) > maxFileSize {
+			return nil, fileSizeError(name)
+		}
 	}
 	return ret, err
 }
diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go
index 91d54c9..d4db8f9 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -19,6 +19,7 @@ func interrupt() {
 // readFile reads and returns the content of the named file.
 // It is a trivial implementation of ioutil.ReadFile, reimplemented
 // here to avoid depending on io/ioutil or os.
+// It returns an error if name exceeds maxFileSize bytes.
 func readFile(name string) ([]byte, error) {
 	f, err := syscall.Open(name, syscall.O_RDONLY, 0)
 	if err != nil {
@@ -38,6 +39,9 @@ func readFile(name string) ([]byte, error) {
 		if n == 0 || err != nil {
 			break
 		}
+		if len(ret) > maxFileSize {
+			return nil, fileSizeError(name)
+		}
 	}
 	return ret, err
 }
diff --git a/src/time/sys_windows.go b/src/time/sys_windows.go
index a4a068f..9e38165 100644
--- a/src/time/sys_windows.go
+++ b/src/time/sys_windows.go
@@ -16,6 +16,7 @@ func interrupt() {
 // readFile reads and returns the content of the named file.
 // It is a trivial implementation of ioutil.ReadFile, reimplemented
 // here to avoid depending on io/ioutil or os.
+// It returns an error if name exceeds maxFileSize bytes.
 func readFile(name string) ([]byte, error) {
 	f, err := syscall.Open(name, syscall.O_RDONLY, 0)
 	if err != nil {
@@ -35,6 +36,9 @@ func readFile(name string) ([]byte, error) {
 		if n == 0 || err != nil {
 			break
 		}
+		if len(ret) > maxFileSize {
+			return nil, fileSizeError(name)
+		}
 	}
 	return ret, err
 }
diff --git a/src/time/time.go b/src/time/time.go
index 10b3246..bd65546 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -6,6 +6,74 @@
 //
 // The calendrical calculations always assume a Gregorian calendar, with
 // no leap seconds.
+//
+// Monotonic Clocks
+//
+// Operating systems provide both a “wall clock,” which is subject to
+// changes for clock synchronization, and a “monotonic clock,” which is
+// not. The general rule is that the wall clock is for telling time and
+// the monotonic clock is for measuring time. Rather than split the API,
+// in this package the Time returned by time.Now contains both a wall
+// clock reading and a monotonic clock reading; later time-telling
+// operations use the wall clock reading, but later time-measuring
+// operations, specifically comparisons and subtractions, use the
+// monotonic clock reading.
+//
+// For example, this code always computes a positive elapsed time of
+// approximately 20 milliseconds, even if the wall clock is changed during
+// the operation being timed:
+//
+//	t := time.Now()
+//	... operation that takes 20 milliseconds ...
+//	u := time.Now()
+//	elapsed := t.Sub(u)
+//
+// Other idioms, such as time.Since(start), time.Until(deadline), and
+// time.Now().Before(deadline), are similarly robust against wall clock
+// resets.
+//
+// The rest of this section gives the precise details of how operations
+// use monotonic clocks, but understanding those details is not required
+// to use this package.
+//
+// The Time returned by time.Now contains a monotonic clock reading.
+// If Time t has a monotonic clock reading, t.Add adds the same duration to
+// both the wall clock and monotonic clock readings to compute the result.
+// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time
+// computations, they always strip any monotonic clock reading from their results.
+// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation
+// of the wall time, they also strip any monotonic clock reading from their results.
+// The canonical way to strip a monotonic clock reading is to use t = t.Round(0).
+//
+// If Times t and u both contain monotonic clock readings, the operations
+// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out
+// using the monotonic clock readings alone, ignoring the wall clock
+// readings. If either t or u contains no monotonic clock reading, these
+// operations fall back to using the wall clock readings.
+//
+// Because the monotonic clock reading has no meaning outside
+// the current process, the serialized forms generated by t.GobEncode,
+// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic
+// clock reading, and t.Format provides no format for it. Similarly, the
+// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix,
+// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary.
+// t.UnmarshalJSON, and t.UnmarshalText always create times with
+// no monotonic clock reading.
+//
+// Note that the Go == operator compares not just the time instant but also
+// the Location and the monotonic clock reading. If time values returned
+// from time.Now and time values constructed by other means (for example,
+// by time.Parse or time.Unix) are meant to compare equal when used as map
+// keys, the times returned by time.Now must have the monotonic clock
+// reading stripped, by setting t = t.Round(0). In general, prefer
+// t.Equal(u) to t == u, since t.Equal uses the most accurate comparison
+// available and correctly handles the case when only one of its arguments
+// has a monotonic clock reading.
+//
+// For debugging, the result of t.String does include the monotonic
+// clock reading if present. If t != u because of different monotonic clock readings,
+// that difference will be visible when printing t.String() and u.String().
+//
 package time
 
 import "errors"
@@ -14,8 +82,11 @@ import "errors"
 //
 // 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
-// multiple goroutines simultaneously.
+// type time.Time, not *time.Time.
+//
+// A Time value can be used by multiple goroutines simultaneously except
+// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and
+// UnmarshalText are not concurrency-safe.
 //
 // Time instants can be compared using the Before, After, and Equal methods.
 // The Sub method subtracts two instants, producing a Duration.
@@ -33,19 +104,34 @@ import "errors"
 // computations described in earlier paragraphs.
 //
 // Note that the Go == operator compares not just the time instant but also the
-// Location. Therefore, Time values should not be used as map or database keys
-// without first guaranteeing that the identical Location has been set for all
-// values, which can be achieved through use of the UTC or Local method.
+// Location and the monotonic clock reading. Therefore, Time values should not
+// be used as map or database keys without first guaranteeing that the
+// identical Location has been set for all values, which can be achieved
+// through use of the UTC or Local method, and that the monotonic clock reading
+// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u)
+// to t == u, since t.Equal uses the most accurate comparison available and
+// correctly handles the case when only one of its arguments has a monotonic
+// clock reading.
+//
+// In addition to the required “wall clock” reading, a Time may contain an optional
+// reading of the current process's monotonic clock, to provide additional precision
+// for comparison or subtraction.
+// See the “Monotonic Clocks” section in the package documentation for details.
 //
 type Time struct {
-	// sec gives the number of seconds elapsed since
-	// January 1, year 1 00:00:00 UTC.
-	sec int64
-
-	// nsec specifies a non-negative nanosecond
-	// offset within the second named by Seconds.
-	// It must be in the range [0, 999999999].
-	nsec int32
+	// wall and ext encode the wall time seconds, wall time nanoseconds,
+	// and optional monotonic clock reading in nanoseconds.
+	//
+	// From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
+	// a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
+	// The nanoseconds field is in the range [0, 999999999].
+	// If the hasMonotonic bit is 0, then the 33-bit field must be zero
+	// and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
+	// If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
+	// unsigned wall seconds since Jan 1 year 1885, and ext holds a
+	// signed 64-bit monotonic clock reading, nanoseconds since process start.
+	wall uint64
+	ext  int64
 
 	// loc specifies the Location that should be used to
 	// determine the minute, hour, month, day, and year
@@ -55,29 +141,124 @@ type Time struct {
 	loc *Location
 }
 
+const (
+	hasMonotonic = 1 << 63
+	maxWall      = wallToInternal + (1<<33 - 1) // year 2157
+	minWall      = wallToInternal               // year 1885
+	nsecMask     = 1<<30 - 1
+	nsecShift    = 30
+)
+
+// These helpers for manipulating the wall and monotonic clock readings
+// take pointer receivers, even when they don't modify the time,
+// to make them cheaper to call.
+
+// nsec returns the time's nanoseconds.
+func (t *Time) nsec() int32 {
+	return int32(t.wall & nsecMask)
+}
+
+// sec returns the time's seconds since Jan 1 year 1.
+func (t *Time) sec() int64 {
+	if t.wall&hasMonotonic != 0 {
+		return wallToInternal + int64(t.wall<<1>>(nsecShift+1))
+	}
+	return int64(t.ext)
+}
+
+// unixSec returns the time's seconds since Jan 1 1970 (Unix time).
+func (t *Time) unixSec() int64 { return t.sec() + internalToUnix }
+
+// addSec adds d seconds to the time.
+func (t *Time) addSec(d int64) {
+	if t.wall&hasMonotonic != 0 {
+		sec := int64(t.wall << 1 >> (nsecShift + 1))
+		dsec := sec + d
+		if 0 <= dsec && dsec <= 1<<33-1 {
+			t.wall = t.wall&nsecMask | uint64(dsec)<<nsecShift | hasMonotonic
+			return
+		}
+		// Wall second now out of range for packed field.
+		// Move to ext.
+		t.stripMono()
+	}
+
+	// TODO: Check for overflow.
+	t.ext += d
+}
+
+// setLoc sets the location associated with the time.
 func (t *Time) setLoc(loc *Location) {
 	if loc == &utcLoc {
 		loc = nil
 	}
+	t.stripMono()
 	t.loc = loc
 }
 
+// stripMono strips the monotonic clock reading in t.
+func (t *Time) stripMono() {
+	if t.wall&hasMonotonic != 0 {
+		t.ext = t.sec()
+		t.wall &= nsecMask
+	}
+}
+
+// setMono sets the monotonic clock reading in t.
+// If t cannot hold a monotonic clock reading,
+// because its wall time is too large,
+// setMono is a no-op.
+func (t *Time) setMono(m int64) {
+	if t.wall&hasMonotonic == 0 {
+		sec := int64(t.ext)
+		if sec < minWall || maxWall < sec {
+			return
+		}
+		t.wall |= hasMonotonic | uint64(sec-minWall)<<nsecShift
+	}
+	t.ext = m
+}
+
+// mono returns t's monotonic clock reading.
+// It returns 0 for a missing reading.
+// This function is used only for testing,
+// so it's OK that technically 0 is a valid
+// monotonic clock reading as well.
+func (t *Time) mono() int64 {
+	if t.wall&hasMonotonic == 0 {
+		return 0
+	}
+	return t.ext
+}
+
 // After reports whether the time instant t is after u.
 func (t Time) After(u Time) bool {
-	return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec
+	if t.wall&u.wall&hasMonotonic != 0 {
+		return t.ext > u.ext
+	}
+	ts := t.sec()
+	us := u.sec()
+	return ts > us || ts == us && t.nsec() > u.nsec()
 }
 
 // Before reports whether the time instant t is before u.
 func (t Time) Before(u Time) bool {
-	return t.sec < u.sec || t.sec == u.sec && t.nsec < u.nsec
+	if t.wall&u.wall&hasMonotonic != 0 {
+		return t.ext < u.ext
+	}
+	return t.sec() < u.sec() || t.sec() == u.sec() && t.nsec() < u.nsec()
 }
 
 // Equal reports whether t and u represent the same time instant.
 // Two times can be equal even if they are in different locations.
 // For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
-// Do not use == with Time values.
+// See the documentation on the Time type for the pitfalls of using == with
+// Time values; most code should use Equal instead.
 func (t Time) Equal(u Time) bool {
-	return t.sec == u.sec && t.nsec == u.nsec
+	if t.wall&u.wall&hasMonotonic != 0 {
+		return t.ext == u.ext
+	}
+	return t.sec() == u.sec() && t.nsec() == u.nsec()
 }
 
 // A Month specifies a month of the year (January = 1, ...).
@@ -162,7 +343,7 @@ func (d Weekday) String() string { return days[d] }
 // The zero Time value does not force a specific epoch for the time
 // 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
+// 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
 // epoch, and that's what we do.
 //
@@ -194,7 +375,7 @@ func (d Weekday) String() string { return days[d] }
 // everywhere.
 //
 // 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
+// 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
 // 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
@@ -208,7 +389,7 @@ func (d Weekday) String() string { return days[d] }
 //
 // These three considerations—choose an epoch as early as possible, that
 // uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds
-// earlier than 1970—bring us to the year -292277022399.  We refer to
+// earlier than 1970—bring us to the year -292277022399. We refer to
 // this year as the absolute zero year, and to times measured as a uint64
 // seconds since this year as absolute times.
 //
@@ -219,9 +400,9 @@ func (d Weekday) String() string { return days[d] }
 // times.
 //
 // It is tempting to just use the year 1 as the absolute epoch, defining
-// that the routines are only valid for years >= 1.  However, the
+// that the routines are only valid for years >= 1. However, the
 // 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
+// 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
 // the year -292277022399.
@@ -245,12 +426,15 @@ const (
 
 	unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
 	internalToUnix int64 = -unixToInternal
+
+	wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay
+	internalToWall int64 = -wallToInternal
 )
 
 // IsZero reports whether t represents the zero time instant,
 // January 1, year 1, 00:00:00 UTC.
 func (t Time) IsZero() bool {
-	return t.sec == 0 && t.nsec == 0
+	return t.sec() == 0 && t.nsec() == 0
 }
 
 // abs returns the time t as an absolute time, adjusted by the zone offset.
@@ -261,7 +445,7 @@ func (t Time) abs() uint64 {
 	if l == nil || l == &localLoc {
 		l = l.get()
 	}
-	sec := t.sec + internalToUnix
+	sec := t.unixSec()
 	if l != &utcLoc {
 		if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
 			sec += int64(l.cacheZone.offset)
@@ -281,7 +465,7 @@ func (t Time) locabs() (name string, offset int, abs uint64) {
 		l = l.get()
 	}
 	// Avoid function call if we hit the local time cache.
-	sec := t.sec + internalToUnix
+	sec := t.unixSec()
 	if l != &utcLoc {
 		if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
 			name = l.cacheZone.name
@@ -425,7 +609,7 @@ func (t Time) Second() int {
 // Nanosecond returns the nanosecond offset within the second specified by t,
 // in the range [0, 999999999].
 func (t Time) Nanosecond() int {
-	return int(t.nsec)
+	return int(t.nsec())
 }
 
 // YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years,
@@ -543,8 +727,8 @@ func (d Duration) String() string {
 }
 
 // fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
-// tail of buf, omitting trailing zeros.  it omits the decimal
-// point too when the fraction is 0.  It returns the index where the
+// tail of buf, omitting trailing zeros. it omits the decimal
+// point too when the fraction is 0. It returns the index where the
 // output bytes begin and the value v/10**prec.
 func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
 	// Omit trailing zeros up to and including decimal point.
@@ -616,18 +800,73 @@ func (d Duration) Hours() float64 {
 	return float64(hour) + float64(nsec)/(60*60*1e9)
 }
 
+// Truncate returns the result of rounding d toward zero to a multiple of m.
+// If m <= 0, Truncate returns d unchanged.
+func (d Duration) Truncate(m Duration) Duration {
+	if m <= 0 {
+		return d
+	}
+	return d - d%m
+}
+
+// lessThanHalf reports whether x+x < y but avoids overflow,
+// assuming x and y are both positive (Duration is signed).
+func lessThanHalf(x, y Duration) bool {
+	return uint64(x)+uint64(x) < uint64(y)
+}
+
+// Round returns the result of rounding d to the nearest multiple of m.
+// The rounding behavior for halfway values is to round away from zero.
+// If the result exceeds the maximum (or minimum)
+// value that can be stored in a Duration,
+// Round returns the maximum (or minimum) duration.
+// If m <= 0, Round returns d unchanged.
+func (d Duration) Round(m Duration) Duration {
+	if m <= 0 {
+		return d
+	}
+	r := d % m
+	if d < 0 {
+		r = -r
+		if lessThanHalf(r, m) {
+			return d + r
+		}
+		if d1 := d - m + r; d1 < d {
+			return d1
+		}
+		return minDuration // overflow
+	}
+	if lessThanHalf(r, m) {
+		return d - r
+	}
+	if d1 := d + m - r; d1 > d {
+		return d1
+	}
+	return maxDuration // overflow
+}
+
 // Add returns the time t+d.
 func (t Time) Add(d Duration) Time {
-	t.sec += int64(d / 1e9)
-	nsec := t.nsec + int32(d%1e9)
+	dsec := int64(d / 1e9)
+	nsec := t.nsec() + int32(d%1e9)
 	if nsec >= 1e9 {
-		t.sec++
+		dsec++
 		nsec -= 1e9
 	} else if nsec < 0 {
-		t.sec--
+		dsec--
 		nsec += 1e9
 	}
-	t.nsec = nsec
+	t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec
+	t.addSec(dsec)
+	if t.wall&hasMonotonic != 0 {
+		te := t.ext + int64(d)
+		if d < 0 && te > int64(t.ext) || d > 0 && te < int64(t.ext) {
+			// Monotonic clock reading now out of range; degrade to wall-only.
+			t.stripMono()
+		} else {
+			t.ext = te
+		}
+	}
 	return t
 }
 
@@ -636,7 +875,19 @@ 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(t.nsec-u.nsec)
+	if t.wall&u.wall&hasMonotonic != 0 {
+		te := int64(t.ext)
+		ue := int64(u.ext)
+		d := Duration(te - ue)
+		if d < 0 && te > ue {
+			return maxDuration // t - u is positive out of range
+		}
+		if d > 0 && te < ue {
+			return minDuration // t - u is negative out of range
+		}
+		return d
+	}
+	d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec())
 	// Check for overflow or underflow.
 	switch {
 	case u.Add(d).Equal(t):
@@ -671,7 +922,7 @@ func Until(t Time) Duration {
 func (t Time) AddDate(years int, months int, days int) Time {
 	year, month, day := t.Date()
 	hour, min, sec := t.Clock()
-	return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.Location())
+	return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location())
 }
 
 const (
@@ -718,7 +969,7 @@ func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
 
 	// Cut off years within a 4-year cycle.
 	// The last year is a leap year, so on the last day of that year,
-	// day / 365 will be 4 instead of 3.  Cut it back down to 3
+	// day / 365 will be 4 instead of 3. Cut it back down to 3
 	// by subtracting n>>2.
 	n = d / 365
 	n -= n >> 2
@@ -791,12 +1042,20 @@ func daysIn(m Month, year int) int {
 }
 
 // Provided by package runtime.
-func now() (sec int64, nsec int32)
+func now() (sec int64, nsec int32, mono int64)
 
 // Now returns the current local time.
 func Now() Time {
-	sec, nsec := now()
-	return Time{sec + unixToInternal, nsec, Local}
+	sec, nsec, mono := now()
+	sec += unixToInternal - minWall
+	if uint64(sec)>>33 != 0 {
+		return Time{uint64(nsec), sec + minWall, Local}
+	}
+	return Time{hasMonotonic | uint64(sec)<<nsecShift | uint64(nsec), mono, Local}
+}
+
+func unixTime(sec int64, nsec int32) Time {
+	return Time{uint64(nsec), sec + unixToInternal, Local}
 }
 
 // UTC returns t with the location set to UTC.
@@ -834,14 +1093,14 @@ func (t Time) Location() *Location {
 // Zone computes the time zone in effect at time t, returning the abbreviated
 // name of the zone (such as "CET") and its offset in seconds east of UTC.
 func (t Time) Zone() (name string, offset int) {
-	name, offset, _, _, _ = t.loc.lookup(t.sec + internalToUnix)
+	name, offset, _, _, _ = t.loc.lookup(t.unixSec())
 	return
 }
 
 // Unix returns t as a Unix time, the number of seconds elapsed
 // since January 1, 1970 UTC.
 func (t Time) Unix() int64 {
-	return t.sec + internalToUnix
+	return t.unixSec()
 }
 
 // UnixNano returns t as a Unix time, the number of nanoseconds elapsed
@@ -850,7 +1109,7 @@ func (t Time) Unix() int64 {
 // 1678 or after 2262). Note that this means the result of calling UnixNano
 // on the zero Time is undefined.
 func (t Time) UnixNano() int64 {
-	return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
+	return (t.unixSec())*1e9 + int64(t.nsec())
 }
 
 const timeBinaryVersion byte = 1
@@ -873,20 +1132,22 @@ func (t Time) MarshalBinary() ([]byte, error) {
 		offsetMin = int16(offset)
 	}
 
+	sec := t.sec()
+	nsec := t.nsec()
 	enc := []byte{
 		timeBinaryVersion, // byte 0 : version
-		byte(t.sec >> 56), // bytes 1-8: seconds
-		byte(t.sec >> 48),
-		byte(t.sec >> 40),
-		byte(t.sec >> 32),
-		byte(t.sec >> 24),
-		byte(t.sec >> 16),
-		byte(t.sec >> 8),
-		byte(t.sec),
-		byte(t.nsec >> 24), // bytes 9-12: nanoseconds
-		byte(t.nsec >> 16),
-		byte(t.nsec >> 8),
-		byte(t.nsec),
+		byte(sec >> 56),   // bytes 1-8: seconds
+		byte(sec >> 48),
+		byte(sec >> 40),
+		byte(sec >> 32),
+		byte(sec >> 24),
+		byte(sec >> 16),
+		byte(sec >> 8),
+		byte(sec),
+		byte(nsec >> 24), // bytes 9-12: nanoseconds
+		byte(nsec >> 16),
+		byte(nsec >> 8),
+		byte(nsec),
 		byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
 		byte(offsetMin),
 	}
@@ -910,18 +1171,22 @@ func (t *Time) UnmarshalBinary(data []byte) error {
 	}
 
 	buf = buf[1:]
-	t.sec = int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 |
+	sec := int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 |
 		int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56
 
 	buf = buf[8:]
-	t.nsec = int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24
+	nsec := int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24
 
 	buf = buf[4:]
 	offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
 
+	*t = Time{}
+	t.wall = uint64(nsec)
+	t.ext = sec
+
 	if offset == -1*60 {
 		t.setLoc(&utcLoc)
-	} else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
+	} else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff {
 		t.setLoc(Local)
 	} else {
 		t.setLoc(FixedZone("", offset))
@@ -1008,7 +1273,7 @@ func Unix(sec int64, nsec int64) Time {
 			sec--
 		}
 	}
-	return Time{sec + unixToInternal, int32(nsec), Local}
+	return unixTime(sec, int32(nsec))
 }
 
 func isLeap(year int) bool {
@@ -1117,7 +1382,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
 		unix -= int64(offset)
 	}
 
-	t := Time{unix + unixToInternal, int32(nsec), nil}
+	t := unixTime(unix, int32(nsec))
 	t.setLoc(loc)
 	return t
 }
@@ -1130,6 +1395,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
 // time. Thus, Truncate(Hour) may return a time with a non-zero
 // minute, depending on the time's Location.
 func (t Time) Truncate(d Duration) Time {
+	t.stripMono()
 	if d <= 0 {
 		return t
 	}
@@ -1146,11 +1412,12 @@ func (t Time) Truncate(d Duration) Time {
 // time. Thus, Round(Hour) may return a time with a non-zero
 // minute, depending on the time's Location.
 func (t Time) Round(d Duration) Time {
+	t.stripMono()
 	if d <= 0 {
 		return t
 	}
 	_, r := div(t, d)
-	if r+r < d {
+	if lessThanHalf(r, d) {
 		return t.Add(-r)
 	}
 	return t.Add(d - r)
@@ -1161,15 +1428,16 @@ 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 := t.nsec
-	if t.sec < 0 {
+	nsec := t.nsec()
+	sec := t.sec()
+	if sec < 0 {
 		// Operate on absolute value.
 		neg = true
-		t.sec = -t.sec
+		sec = -sec
 		nsec = -nsec
 		if nsec < 0 {
 			nsec += 1e9
-			t.sec-- // t.sec >= 1 before the -- so safe
+			sec-- // sec >= 1 before the -- so safe
 		}
 	}
 
@@ -1182,8 +1450,8 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
 	// Special case: d is a multiple of 1 second.
 	case d%Second == 0:
 		d1 := int64(d / Second)
-		qmod2 = int(t.sec/d1) & 1
-		r = Duration(t.sec%d1)*Second + Duration(nsec)
+		qmod2 = int(sec/d1) & 1
+		r = Duration(sec%d1)*Second + Duration(nsec)
 
 	// General case.
 	// This could be faster if more cleverness were applied,
@@ -1191,7 +1459,7 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
 	// No one will care about these cases.
 	default:
 		// Compute nanoseconds as 128-bit number.
-		sec := uint64(t.sec)
+		sec := uint64(sec)
 		tmp := (sec >> 32) * 1e9
 		u1 := tmp >> 32
 		u0 := tmp << 32
diff --git a/src/time/time_test.go b/src/time/time_test.go
index 2922560..dba8e0d 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -11,7 +11,9 @@ import (
 	"fmt"
 	"math/big"
 	"math/rand"
+	"os"
 	"runtime"
+	"strings"
 	"testing"
 	"testing/quick"
 	. "time"
@@ -231,6 +233,7 @@ var truncateRoundTests = []struct {
 	{Date(-1, January, 1, 12, 15, 31, 5e8, UTC), 3},
 	{Date(2012, January, 1, 12, 15, 30, 5e8, UTC), Second},
 	{Date(2012, January, 1, 12, 15, 31, 5e8, UTC), Second},
+	{Unix(-19012425939, 649146258), 7435029458905025217}, // 5.8*d rounds to 6*d, but .8*d+.8*d < 0 < d
 }
 
 func TestTruncateRound(t *testing.T) {
@@ -1056,6 +1059,66 @@ func TestDurationHours(t *testing.T) {
 	}
 }
 
+var durationTruncateTests = []struct {
+	d    Duration
+	m    Duration
+	want Duration
+}{
+	{0, Second, 0},
+	{Minute, -7 * Second, Minute},
+	{Minute, 0, Minute},
+	{Minute, 1, Minute},
+	{Minute + 10*Second, 10 * Second, Minute + 10*Second},
+	{2*Minute + 10*Second, Minute, 2 * Minute},
+	{10*Minute + 10*Second, 3 * Minute, 9 * Minute},
+	{Minute + 10*Second, Minute + 10*Second + 1, 0},
+	{Minute + 10*Second, Hour, 0},
+	{-Minute, Second, -Minute},
+	{-10 * Minute, 3 * Minute, -9 * Minute},
+	{-10 * Minute, Hour, 0},
+}
+
+func TestDurationTruncate(t *testing.T) {
+	for _, tt := range durationTruncateTests {
+		if got := tt.d.Truncate(tt.m); got != tt.want {
+			t.Errorf("Duration(%s).Truncate(%s) = %s; want: %s", tt.d, tt.m, got, tt.want)
+		}
+	}
+}
+
+var durationRoundTests = []struct {
+	d    Duration
+	m    Duration
+	want Duration
+}{
+	{0, Second, 0},
+	{Minute, -11 * Second, Minute},
+	{Minute, 0, Minute},
+	{Minute, 1, Minute},
+	{2 * Minute, Minute, 2 * Minute},
+	{2*Minute + 10*Second, Minute, 2 * Minute},
+	{2*Minute + 30*Second, Minute, 3 * Minute},
+	{2*Minute + 50*Second, Minute, 3 * Minute},
+	{-Minute, 1, -Minute},
+	{-2 * Minute, Minute, -2 * Minute},
+	{-2*Minute - 10*Second, Minute, -2 * Minute},
+	{-2*Minute - 30*Second, Minute, -3 * Minute},
+	{-2*Minute - 50*Second, Minute, -3 * Minute},
+	{8e18, 3e18, 9e18},
+	{9e18, 5e18, 1<<63 - 1},
+	{-8e18, 3e18, -9e18},
+	{-9e18, 5e18, -1 << 63},
+	{3<<61 - 1, 3 << 61, 3 << 61},
+}
+
+func TestDurationRound(t *testing.T) {
+	for _, tt := range durationRoundTests {
+		if got := tt.d.Round(tt.m); got != tt.want {
+			t.Errorf("Duration(%s).Round(%s) = %s; want: %s", tt.d, tt.m, got, tt.want)
+		}
+	}
+}
+
 var defaultLocTests = []struct {
 	name string
 	f    func(t1, t2 Time) bool
@@ -1254,3 +1317,14 @@ func TestZeroMonthString(t *testing.T) {
 		t.Errorf("zero month = %q; want %q", got, want)
 	}
 }
+
+func TestReadFileLimit(t *testing.T) {
+	const zero = "/dev/zero"
+	if _, err := os.Stat(zero); err != nil {
+		t.Skip("skipping test without a /dev/zero")
+	}
+	_, err := ReadFile(zero)
+	if err == nil || !strings.Contains(err.Error(), "is too large") {
+		t.Errorf("readFile(%q) error = %v; want error containing 'is too large'", zero, err)
+	}
+}
diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go
index fb0aa39..dfe857f 100644
--- a/src/time/zoneinfo.go
+++ b/src/time/zoneinfo.go
@@ -5,6 +5,7 @@
 package time
 
 import (
+	"errors"
 	"sync"
 	"syscall"
 )
@@ -256,7 +257,10 @@ func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool,
 // NOTE(rsc): Eventually we will need to accept the POSIX TZ environment
 // syntax too, but I don't feel like implementing it today.
 
-var zoneinfo, _ = syscall.Getenv("ZONEINFO")
+var errLocation = errors.New("time: invalid location name")
+
+var zoneinfo *string
+var zoneinfoOnce sync.Once
 
 // LoadLocation returns the Location with the given name.
 //
@@ -279,11 +283,33 @@ func LoadLocation(name string) (*Location, error) {
 	if name == "Local" {
 		return Local, nil
 	}
-	if zoneinfo != "" {
-		if z, err := loadZoneFile(zoneinfo, name); err == nil {
+	if containsDotDot(name) || name[0] == '/' || name[0] == '\\' {
+		// No valid IANA Time Zone name contains a single dot,
+		// much less dot dot. Likewise, none begin with a slash.
+		return nil, errLocation
+	}
+	zoneinfoOnce.Do(func() {
+		env, _ := syscall.Getenv("ZONEINFO")
+		zoneinfo = &env
+	})
+	if zoneinfo != nil && *zoneinfo != "" {
+		if z, err := loadZoneFile(*zoneinfo, name); err == nil {
 			z.name = name
 			return z, nil
 		}
 	}
 	return loadLocation(name)
 }
+
+// containsDotDot reports whether s contains "..".
+func containsDotDot(s string) bool {
+	if len(s) < 2 {
+		return false
+	}
+	for i := 0; i < len(s)-1; i++ {
+		if s[i] == '.' && s[i+1] == '.' {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go
index 9425db8..db0bbfd 100644
--- a/src/time/zoneinfo_abbrs_windows.go
+++ b/src/time/zoneinfo_abbrs_windows.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// generated by genzabbrs.go from
-// http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
+// Code generated by genzabbrs.go; DO NOT EDIT.
+// Based on information from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
 
 package time
 
@@ -22,124 +22,128 @@ var abbrs = map[string]abbr{
 	"Namibia Standard Time":           {"WAT", "WAST"},    // Africa/Windhoek
 	"Aleutian Standard Time":          {"HST", "HDT"},     // America/Adak
 	"Alaskan Standard Time":           {"AKST", "AKDT"},   // America/Anchorage
-	"Tocantins Standard Time":         {"BRT", "BRT"},     // America/Araguaina
-	"Paraguay Standard Time":          {"PYT", "PYST"},    // America/Asuncion
-	"Bahia Standard Time":             {"BRT", "BRT"},     // America/Bahia
-	"SA Pacific Standard Time":        {"COT", "COT"},     // America/Bogota
-	"Argentina Standard Time":         {"ART", "ART"},     // America/Buenos_Aires
+	"Tocantins Standard Time":         {"-03", "-03"},     // America/Araguaina
+	"Paraguay Standard Time":          {"-04", "-03"},     // America/Asuncion
+	"Bahia Standard Time":             {"-03", "-03"},     // America/Bahia
+	"SA Pacific Standard Time":        {"-05", "-05"},     // America/Bogota
+	"Argentina Standard Time":         {"-03", "-03"},     // 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
+	"Venezuela Standard Time":         {"-04", "-04"},     // America/Caracas
+	"SA Eastern Standard Time":        {"-03", "-03"},     // America/Cayenne
 	"Central Standard Time":           {"CST", "CDT"},     // America/Chicago
 	"Mountain Standard Time (Mexico)": {"MST", "MDT"},     // America/Chihuahua
-	"Central Brazilian Standard Time": {"AMT", "AMST"},    // America/Cuiaba
+	"Central Brazilian Standard Time": {"-04", "-03"},     // America/Cuiaba
 	"Mountain Standard Time":          {"MST", "MDT"},     // America/Denver
-	"Greenland Standard Time":         {"WGT", "WGST"},    // America/Godthab
+	"Greenland Standard Time":         {"-03", "-02"},     // America/Godthab
 	"Turks And Caicos Standard Time":  {"AST", "AST"},     // America/Grand_Turk
 	"Central America Standard Time":   {"CST", "CST"},     // America/Guatemala
 	"Atlantic Standard Time":          {"AST", "ADT"},     // America/Halifax
 	"Cuba Standard Time":              {"CST", "CDT"},     // America/Havana
 	"US Eastern Standard Time":        {"EST", "EDT"},     // America/Indianapolis
-	"SA Western Standard Time":        {"BOT", "BOT"},     // America/La_Paz
+	"SA Western Standard Time":        {"-04", "-04"},     // America/La_Paz
 	"Pacific Standard Time":           {"PST", "PDT"},     // America/Los_Angeles
 	"Central Standard Time (Mexico)":  {"CST", "CDT"},     // America/Mexico_City
-	"Saint Pierre Standard Time":      {"PMST", "PMDT"},   // America/Miquelon
-	"Montevideo Standard Time":        {"UYT", "UYT"},     // America/Montevideo
+	"Saint Pierre Standard Time":      {"-03", "-02"},     // America/Miquelon
+	"Montevideo Standard Time":        {"-03", "-03"},     // America/Montevideo
 	"Eastern Standard Time":           {"EST", "EDT"},     // America/New_York
 	"US Mountain Standard Time":       {"MST", "MST"},     // America/Phoenix
-	"Haiti Standard Time":             {"EST", "EST"},     // America/Port-au-Prince
+	"Haiti Standard Time":             {"EST", "EDT"},     // America/Port-au-Prince
+	"Magallanes Standard Time":        {"-03", "-03"},     // America/Punta_Arenas
 	"Canada Central Standard Time":    {"CST", "CST"},     // America/Regina
-	"Pacific SA Standard Time":        {"CLT", "CLST"},    // America/Santiago
-	"E. South America Standard Time":  {"BRT", "BRST"},    // America/Sao_Paulo
+	"Pacific SA Standard Time":        {"-04", "-03"},     // America/Santiago
+	"E. South America Standard Time":  {"-03", "-02"},     // America/Sao_Paulo
 	"Newfoundland Standard Time":      {"NST", "NDT"},     // America/St_Johns
 	"Pacific Standard Time (Mexico)":  {"PST", "PDT"},     // America/Tijuana
 	"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", "AZT"},     // Asia/Baku
-	"SE Asia Standard Time":           {"ICT", "ICT"},     // Asia/Bangkok
-	"Altai Standard Time":             {"+06", "+07"},     // Asia/Barnaul
+	"Arabic Standard Time":            {"+03", "+03"},     // Asia/Baghdad
+	"Azerbaijan Standard Time":        {"+04", "+04"},     // Asia/Baku
+	"SE Asia Standard Time":           {"+07", "+07"},     // Asia/Bangkok
+	"Altai Standard Time":             {"+07", "+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
+	"Transbaikal Standard Time":       {"+09", "+09"},     // Asia/Chita
+	"Sri Lanka Standard Time":         {"+0530", "+0530"}, // Asia/Colombo
 	"Syria Standard Time":             {"EET", "EEST"},    // Asia/Damascus
-	"Bangladesh Standard Time":        {"BDT", "BDT"},     // Asia/Dhaka
-	"Arabian Standard Time":           {"GST", "GST"},     // Asia/Dubai
+	"Bangladesh Standard Time":        {"+06", "+06"},     // Asia/Dhaka
+	"Arabian Standard Time":           {"+04", "+04"},     // Asia/Dubai
 	"West Bank Standard Time":         {"EET", "EEST"},    // Asia/Hebron
-	"W. Mongolia Standard Time":       {"HOVT", "HOVST"},  // Asia/Hovd
-	"North Asia East Standard Time":   {"IRKT", "IRKT"},   // Asia/Irkutsk
+	"W. Mongolia Standard Time":       {"+07", "+07"},     // Asia/Hovd
+	"North Asia East Standard Time":   {"+08", "+08"},     // Asia/Irkutsk
 	"Israel Standard Time":            {"IST", "IDT"},     // Asia/Jerusalem
-	"Afghanistan Standard Time":       {"AFT", "AFT"},     // Asia/Kabul
-	"Russia Time Zone 11":             {"PETT", "PETT"},   // Asia/Kamchatka
+	"Afghanistan Standard Time":       {"+0430", "+0430"}, // Asia/Kabul
+	"Russia Time Zone 11":             {"+12", "+12"},     // 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":   {"+06", "+07"},     // Asia/Novosibirsk
+	"Nepal Standard Time":             {"+0545", "+0545"}, // Asia/Katmandu
+	"North Asia Standard Time":        {"+07", "+07"},     // Asia/Krasnoyarsk
+	"Magadan Standard Time":           {"+11", "+11"},     // Asia/Magadan
+	"N. Central Asia Standard Time":   {"+07", "+07"},     // Asia/Novosibirsk
+	"Omsk Standard Time":              {"+06", "+06"},     // Asia/Omsk
 	"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
+	"Myanmar Standard Time":           {"+0630", "+0630"}, // Asia/Rangoon
+	"Arab Standard Time":              {"+03", "+03"},     // Asia/Riyadh
+	"Sakhalin Standard Time":          {"+11", "+11"},     // 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
+	"Singapore Standard Time":         {"+08", "+08"},     // Asia/Singapore
+	"Russia Time Zone 10":             {"+11", "+11"},     // 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
+	"West Asia Standard Time":         {"+05", "+05"},     // Asia/Tashkent
+	"Georgian Standard Time":          {"+04", "+04"},     // Asia/Tbilisi
+	"Iran Standard Time":              {"+0330", "+0430"}, // Asia/Tehran
 	"Tokyo Standard Time":             {"JST", "JST"},     // Asia/Tokyo
-	"Tomsk Standard Time":             {"+06", "+07"},     // Asia/Tomsk
-	"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
-	"Caucasus Standard Time":          {"AMT", "AMT"},     // Asia/Yerevan
-	"Azores Standard Time":            {"AZOT", "AZOST"},  // Atlantic/Azores
-	"Cape Verde Standard Time":        {"CVT", "CVT"},     // Atlantic/Cape_Verde
+	"Tomsk Standard Time":             {"+07", "+07"},     // Asia/Tomsk
+	"Ulaanbaatar Standard Time":       {"+08", "+08"},     // Asia/Ulaanbaatar
+	"Vladivostok Standard Time":       {"+10", "+10"},     // Asia/Vladivostok
+	"Yakutsk Standard Time":           {"+09", "+09"},     // Asia/Yakutsk
+	"Ekaterinburg Standard Time":      {"+05", "+05"},     // Asia/Yekaterinburg
+	"Caucasus Standard Time":          {"+04", "+04"},     // Asia/Yerevan
+	"Azores Standard Time":            {"-01", "+00"},     // Atlantic/Azores
+	"Cape Verde Standard Time":        {"-01", "-01"},     // Atlantic/Cape_Verde
 	"Greenwich Standard Time":         {"GMT", "GMT"},     // Atlantic/Reykjavik
 	"Cen. Australia Standard Time":    {"ACST", "ACDT"},   // Australia/Adelaide
 	"E. Australia Standard Time":      {"AEST", "AEST"},   // Australia/Brisbane
 	"AUS Central Standard Time":       {"ACST", "ACST"},   // Australia/Darwin
-	"Aus Central W. Standard Time":    {"ACWST", "ACWST"}, // Australia/Eucla
+	"Aus Central W. Standard Time":    {"+0845", "+0845"}, // Australia/Eucla
 	"Tasmania Standard Time":          {"AEST", "AEDT"},   // Australia/Hobart
-	"Lord Howe Standard Time":         {"LHST", "LHDT"},   // Australia/Lord_Howe
+	"Lord Howe Standard Time":         {"+1030", "+11"},   // Australia/Lord_Howe
 	"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-08":                         {"GMT+8", "GMT+8"},   // Etc/GMT+8
-	"UTC-09":                         {"GMT+9", "GMT+9"},   // Etc/GMT+9
-	"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":      {"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":            {"WSST", "WSDT"},     // Pacific/Apia
-	"New Zealand Standard Time":      {"NZST", "NZDT"},     // Pacific/Auckland
-	"Bougainville Standard Time":     {"BST", "BST"},       // Pacific/Bougainville
-	"Chatham Islands Standard Time":  {"CHAST", "CHADT"},   // Pacific/Chatham
-	"Easter Island Standard Time":    {"EAST", "EASST"},    // Pacific/Easter
-	"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
-	"Marquesas Standard Time":        {"MART", "MART"},     // Pacific/Marquesas
-	"Norfolk Standard Time":          {"NFT", "NFT"},       // Pacific/Norfolk
-	"West Pacific Standard Time":     {"PGT", "PGT"},       // Pacific/Port_Moresby
-	"Tonga Standard Time":            {"TOT", "TOT"},       // Pacific/Tongatapu
+	"UTC":                            {"GMT", "GMT"},     // Etc/GMT
+	"UTC-11":                         {"-11", "-11"},     // Etc/GMT+11
+	"Dateline Standard Time":         {"-12", "-12"},     // Etc/GMT+12
+	"UTC-02":                         {"-02", "-02"},     // Etc/GMT+2
+	"UTC-08":                         {"-08", "-08"},     // Etc/GMT+8
+	"UTC-09":                         {"-09", "-09"},     // Etc/GMT+9
+	"UTC+12":                         {"+12", "+12"},     // Etc/GMT-12
+	"UTC+13":                         {"+13", "+13"},     // Etc/GMT-13
+	"Astrakhan Standard Time":        {"+04", "+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":           {"+03", "+03"},     // Europe/Istanbul
+	"Kaliningrad Standard Time":      {"EET", "EET"},     // Europe/Kaliningrad
+	"FLE Standard Time":              {"EET", "EEST"},    // Europe/Kiev
+	"GMT Standard Time":              {"GMT", "BST"},     // Europe/London
+	"Belarus Standard Time":          {"+03", "+03"},     // Europe/Minsk
+	"Russian Standard Time":          {"MSK", "MSK"},     // Europe/Moscow
+	"Romance Standard Time":          {"CET", "CEST"},    // Europe/Paris
+	"Russia Time Zone 3":             {"+04", "+04"},     // Europe/Samara
+	"Saratov Standard Time":          {"+03", "+04"},     // Europe/Saratov
+	"Central European Standard Time": {"CET", "CEST"},    // Europe/Warsaw
+	"Mauritius Standard Time":        {"+04", "+04"},     // Indian/Mauritius
+	"Samoa Standard Time":            {"+13", "+14"},     // Pacific/Apia
+	"New Zealand Standard Time":      {"NZST", "NZDT"},   // Pacific/Auckland
+	"Bougainville Standard Time":     {"+11", "+11"},     // Pacific/Bougainville
+	"Chatham Islands Standard Time":  {"+1245", "+1345"}, // Pacific/Chatham
+	"Easter Island Standard Time":    {"-06", "-05"},     // Pacific/Easter
+	"Fiji Standard Time":             {"+12", "+13"},     // Pacific/Fiji
+	"Central Pacific Standard Time":  {"+11", "+11"},     // Pacific/Guadalcanal
+	"Hawaiian Standard Time":         {"HST", "HST"},     // Pacific/Honolulu
+	"Line Islands Standard Time":     {"+14", "+14"},     // Pacific/Kiritimati
+	"Marquesas Standard Time":        {"-0930", "-0930"}, // Pacific/Marquesas
+	"Norfolk Standard Time":          {"+11", "+11"},     // Pacific/Norfolk
+	"West Pacific Standard Time":     {"+10", "+10"},     // Pacific/Port_Moresby
+	"Tonga Standard Time":            {"+13", "+14"},     // Pacific/Tongatapu
 }
diff --git a/src/time/zoneinfo_plan9.go b/src/time/zoneinfo_plan9.go
index 0694f0a..26637a1 100644
--- a/src/time/zoneinfo_plan9.go
+++ b/src/time/zoneinfo_plan9.go
@@ -95,7 +95,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
 
 	// Fill in the cache with information about right now,
 	// since that will be the most common lookup.
-	sec, _ := now()
+	sec, _, _ := now()
 	for i := range tx {
 		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
 			l.cacheStart = tx[i].when
diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go
index 19cd40d..b0cd9da 100644
--- a/src/time/zoneinfo_read.go
+++ b/src/time/zoneinfo_read.go
@@ -11,6 +11,17 @@ package time
 
 import "errors"
 
+// maxFileSize is the max permitted size of files read by readFile.
+// As reference, the zoneinfo.zip distributed by Go is ~350 KB,
+// so 10MB is overkill.
+const maxFileSize = 10 << 20
+
+type fileSizeError string
+
+func (f fileSizeError) Error() string {
+	return "time: file " + string(f) + " is too large"
+}
+
 // Copies of io.Seek* constants to avoid importing "io":
 const (
 	seekStart   = 0
@@ -188,7 +199,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
 
 	// Fill in the cache with information about right now,
 	// since that will be the most common lookup.
-	sec, _ := now()
+	sec, _, _ := now()
 	for i := range tx {
 		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
 			l.cacheStart = tx[i].when
diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go
index 4b50dc5..452262f 100644
--- a/src/time/zoneinfo_test.go
+++ b/src/time/zoneinfo_test.go
@@ -5,10 +5,56 @@
 package time_test
 
 import (
+	"fmt"
+	"os"
 	"testing"
 	"time"
 )
 
+func init() {
+	if time.ZoneinfoForTesting() != nil {
+		panic(fmt.Errorf("zoneinfo initialized before first LoadLocation"))
+	}
+}
+
+func TestEnvVarUsage(t *testing.T) {
+	time.ResetZoneinfoForTesting()
+
+	const testZoneinfo = "foo.zip"
+	const env = "ZONEINFO"
+
+	defer os.Setenv(env, os.Getenv(env))
+	os.Setenv(env, testZoneinfo)
+
+	// Result isn't important, we're testing the side effect of this command
+	time.LoadLocation("Asia/Jerusalem")
+	defer time.ResetZoneinfoForTesting()
+
+	if zoneinfo := time.ZoneinfoForTesting(); testZoneinfo != *zoneinfo {
+		t.Errorf("zoneinfo does not match env variable: got %q want %q", zoneinfo, testZoneinfo)
+	}
+}
+
+func TestLoadLocationValidatesNames(t *testing.T) {
+	time.ResetZoneinfoForTesting()
+	const env = "ZONEINFO"
+	defer os.Setenv(env, os.Getenv(env))
+	os.Setenv(env, "")
+
+	bad := []string{
+		"/usr/foo/Foo",
+		"\\UNC\foo",
+		"..",
+		"a..",
+	}
+	for _, v := range bad {
+		_, err := time.LoadLocation(v)
+		if err != time.ErrLocation {
+			t.Errorf("LoadLocation(%q) error = %v; want ErrLocation", v, err)
+		}
+	}
+}
+
 func TestVersion3(t *testing.T) {
 	time.ForceZipFileForTesting(true)
 	defer time.ForceZipFileForTesting(false)
@@ -41,8 +87,8 @@ func TestFirstZone(t *testing.T) {
 		{
 			"Pacific/Fakaofo",
 			1325242799,
-			"Thu, 29 Dec 2011 23:59:59 -1100 (TKT)",
-			"Sat, 31 Dec 2011 00:00:00 +1300 (TKT)",
+			"Thu, 29 Dec 2011 23:59:59 -1100 (-11)",
+			"Sat, 31 Dec 2011 00:00:00 +1300 (+13)",
 		},
 	}
 
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index a6e227b..c201f4b 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -132,7 +132,7 @@ func pseudoUnix(year int, d *syscall.Systemtime) int64 {
 			day -= 7
 		}
 	}
-	return t.sec + int64(day-1)*secondsPerDay + internalToUnix
+	return t.sec() + int64(day-1)*secondsPerDay + internalToUnix
 }
 
 func initLocalFromTZI(i *syscall.Timezoneinformation) {
diff --git a/src/unicode/letter.go b/src/unicode/letter.go
index b43cc66..90b0b41 100644
--- a/src/unicode/letter.go
+++ b/src/unicode/letter.go
@@ -46,7 +46,7 @@ type Range32 struct {
 
 // CaseRange represents a range of Unicode code points for simple (one
 // code point to one code point) case conversion.
-// The range runs from Lo to Hi inclusive, with a fixed stride of 1.  Deltas
+// 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
 // means the character is in the corresponding case. There is a special
@@ -308,7 +308,7 @@ func (special SpecialCase) ToLower(r rune) rune {
 }
 
 // caseOrbit is defined in tables.go as []foldPair. Right now all the
-// entries fit in uint16, so use uint16.  If that changes, compilation
+// 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.
 type foldPair struct {
diff --git a/src/unicode/maketables.go b/src/unicode/maketables.go
index fdfcde4..e52d9c2 100644
--- a/src/unicode/maketables.go
+++ b/src/unicode/maketables.go
@@ -443,9 +443,9 @@ const progHeader = `// Copyright 2013 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Generated by running
+// Code generated by maketables; DO NOT EDIT.
+// To regenerate, run:
 //	maketables --tables=%s --data=%s --casefolding=%s
-// DO NOT EDIT
 
 package unicode
 
diff --git a/src/unicode/tables.go b/src/unicode/tables.go
index 15fecd9..548a7d5 100644
--- a/src/unicode/tables.go
+++ b/src/unicode/tables.go
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Generated by running
+// Code generated by maketables; DO NOT EDIT.
+// To regenerate, run:
 //	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
 
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
index eb6739a..3f0dcb9 100644
--- a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539.
-package chacha20poly1305
+package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
 
 import (
 	"crypto/cipher"
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
index 4755033..1e523b9 100644
--- a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
@@ -14,13 +14,60 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
 //go:noescape
 func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
 
-//go:noescape
-func haveSSSE3() bool
+// cpuid is implemented in chacha20poly1305_amd64.s.
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+
+// xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
+func xgetbv() (eax, edx uint32)
 
-var canUseASM bool
+var (
+	useASM  bool
+	useAVX2 bool
+)
 
 func init() {
-	canUseASM = haveSSSE3()
+	detectCpuFeatures()
+}
+
+// detectCpuFeatures is used to detect if cpu instructions
+// used by the functions implemented in assembler in
+// chacha20poly1305_amd64.s are supported.
+func detectCpuFeatures() {
+	maxId, _, _, _ := cpuid(0, 0)
+	if maxId < 1 {
+		return
+	}
+
+	_, _, ecx1, _ := cpuid(1, 0)
+
+	haveSSSE3 := isSet(9, ecx1)
+	useASM = haveSSSE3
+
+	haveOSXSAVE := isSet(27, ecx1)
+
+	osSupportsAVX := false
+	// For XGETBV, OSXSAVE bit is required and sufficient.
+	if haveOSXSAVE {
+		eax, _ := xgetbv()
+		// Check if XMM and YMM registers have OS support.
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
+	}
+	haveAVX := isSet(28, ecx1) && osSupportsAVX
+
+	if maxId < 7 {
+		return
+	}
+
+	_, ebx7, _, _ := cpuid(7, 0)
+	haveAVX2 := isSet(5, ebx7) && haveAVX
+	haveBMI2 := isSet(8, ebx7)
+
+	useAVX2 = haveAVX2 && haveBMI2
+}
+
+// isSet checks if bit at bitpos is set in value.
+func isSet(bitpos uint, value uint32) bool {
+	return value&(1<<bitpos) != 0
 }
 
 // setupState writes a ChaCha20 input matrix to state. See
@@ -47,7 +94,7 @@ func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
 }
 
 func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
-	if !canUseASM {
+	if !useASM {
 		return c.sealGeneric(dst, nonce, plaintext, additionalData)
 	}
 
@@ -60,7 +107,7 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
 }
 
 func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
-	if !canUseASM {
+	if !useASM {
 		return c.openGeneric(dst, nonce, ciphertext, additionalData)
 	}
 
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
index 39c58b4..1c57e38 100644
--- a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
@@ -278,15 +278,8 @@ TEXT ·chacha20Poly1305Open(SB), 0, $288-97
 	MOVQ ad+72(FP), adp
 
 	// Check for AVX2 support
-	CMPB runtime·support_avx2(SB), $0
-	JE   noavx2bmi2Open
-
-	// Check BMI2 bit for MULXQ.
-	// runtime·cpuid_ebx7 is always available here
-	// because it passed avx2 check
-	TESTL $(1<<8), runtime·cpuid_ebx7(SB)
-	JNE   chacha20Poly1305Open_AVX2
-noavx2bmi2Open:
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Open_AVX2
 
 	// Special optimization, for very short buffers
 	CMPQ inl, $128
@@ -1491,16 +1484,8 @@ TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
 	MOVQ src_len+56(FP), inl
 	MOVQ ad+72(FP), adp
 
-	// Check for AVX2 support
-	CMPB runtime·support_avx2(SB), $0
-	JE   noavx2bmi2Seal
-
-	// Check BMI2 bit for MULXQ.
-	// runtime·cpuid_ebx7 is always available here
-	// because it passed avx2 check
-	TESTL $(1<<8), runtime·cpuid_ebx7(SB)
-	JNE   chacha20Poly1305Seal_AVX2
-noavx2bmi2Seal:
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Seal_AVX2
 
 	// Special optimization, for very short buffers
 	CMPQ inl, $128
@@ -2709,13 +2694,21 @@ sealAVX2Tail512LoopB:
 
 	JMP sealAVX2SealHash
 
-// func haveSSSE3() bool
-TEXT ·haveSSSE3(SB), NOSPLIT, $0
-	XORQ AX, AX
-	INCL AX
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+	MOVL eaxArg+0(FP), AX
+	MOVL ecxArg+4(FP), CX
 	CPUID
-	SHRQ $9, CX
-	ANDQ $1, CX
-	MOVB CX, ret+0(FP)
+	MOVL AX, eax+8(FP)
+	MOVL BX, ebx+12(FP)
+	MOVL CX, ecx+16(FP)
+	MOVL DX, edx+20(FP)
 	RET
 
+// func xgetbv() (eax, edx uint32)
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
+	MOVL $0, CX
+	XGETBV
+	MOVL AX, eax+0(FP)
+	MOVL DX, edx+4(FP)
+	RET
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
similarity index 100%
rename from src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go
rename to src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
index ca9663f..b80d34c 100644
--- a/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
@@ -1,3 +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 chacha20
 
 import (
diff --git a/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s
index 45484d1..cd793a5 100644
--- a/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s
+++ b/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s
@@ -2,87 +2,64 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This code was translated into a form compatible with 6a from the public
-// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
-
 // +build amd64,!gccgo,!appengine
 
-// func cswap(inout *[5]uint64, v uint64)
+// func cswap(inout *[4][5]uint64, v uint64)
 TEXT ·cswap(SB),7,$0
 	MOVQ inout+0(FP),DI
 	MOVQ v+8(FP),SI
 
-	CMPQ SI,$1
-	MOVQ 0(DI),SI
-	MOVQ 80(DI),DX
-	MOVQ 8(DI),CX
-	MOVQ 88(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,0(DI)
-	MOVQ DX,80(DI)
-	MOVQ CX,8(DI)
-	MOVQ R8,88(DI)
-	MOVQ 16(DI),SI
-	MOVQ 96(DI),DX
-	MOVQ 24(DI),CX
-	MOVQ 104(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,16(DI)
-	MOVQ DX,96(DI)
-	MOVQ CX,24(DI)
-	MOVQ R8,104(DI)
-	MOVQ 32(DI),SI
-	MOVQ 112(DI),DX
-	MOVQ 40(DI),CX
-	MOVQ 120(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,32(DI)
-	MOVQ DX,112(DI)
-	MOVQ CX,40(DI)
-	MOVQ R8,120(DI)
-	MOVQ 48(DI),SI
-	MOVQ 128(DI),DX
-	MOVQ 56(DI),CX
-	MOVQ 136(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,48(DI)
-	MOVQ DX,128(DI)
-	MOVQ CX,56(DI)
-	MOVQ R8,136(DI)
-	MOVQ 64(DI),SI
-	MOVQ 144(DI),DX
-	MOVQ 72(DI),CX
-	MOVQ 152(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,64(DI)
-	MOVQ DX,144(DI)
-	MOVQ CX,72(DI)
-	MOVQ R8,152(DI)
-	MOVQ DI,AX
-	MOVQ SI,DX
+	SUBQ $1, SI
+	NOTQ SI
+	MOVQ SI, X15
+	PSHUFD $0x44, X15, X15
+
+	MOVOU 0(DI), X0
+	MOVOU 16(DI), X2
+	MOVOU 32(DI), X4
+	MOVOU 48(DI), X6
+	MOVOU 64(DI), X8
+	MOVOU 80(DI), X1
+	MOVOU 96(DI), X3
+	MOVOU 112(DI), X5
+	MOVOU 128(DI), X7
+	MOVOU 144(DI), X9
+
+	MOVO X1, X10
+	MOVO X3, X11
+	MOVO X5, X12
+	MOVO X7, X13
+	MOVO X9, X14
+
+	PXOR X0, X10
+	PXOR X2, X11
+	PXOR X4, X12
+	PXOR X6, X13
+	PXOR X8, X14
+	PAND X15, X10
+	PAND X15, X11
+	PAND X15, X12
+	PAND X15, X13
+	PAND X15, X14
+	PXOR X10, X0
+	PXOR X10, X1
+	PXOR X11, X2
+	PXOR X11, X3
+	PXOR X12, X4
+	PXOR X12, X5
+	PXOR X13, X6
+	PXOR X13, X7
+	PXOR X14, X8
+	PXOR X14, X9
+
+	MOVOU X0, 0(DI)
+	MOVOU X2, 16(DI)
+	MOVOU X4, 32(DI)
+	MOVOU X6, 48(DI)
+	MOVOU X8, 64(DI)
+	MOVOU X1, 80(DI)
+	MOVOU X3, 96(DI)
+	MOVOU X5, 112(DI)
+	MOVOU X7, 128(DI)
+	MOVOU X9, 144(DI)
 	RET
diff --git a/src/vendor/golang_org/x/crypto/curve25519/curve25519.go b/src/vendor/golang_org/x/crypto/curve25519/curve25519.go
index 6918c47..2d14c2a 100644
--- a/src/vendor/golang_org/x/crypto/curve25519/curve25519.go
+++ b/src/vendor/golang_org/x/crypto/curve25519/curve25519.go
@@ -8,6 +8,10 @@
 
 package curve25519
 
+import (
+	"encoding/binary"
+)
+
 // This code is a port of the public domain, "ref10" implementation of
 // curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
 
@@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
 //
 // Preconditions: b in {0,1}.
 func feCSwap(f, g *fieldElement, b int32) {
-	var x fieldElement
 	b = -b
-	for i := range x {
-		x[i] = b & (f[i] ^ g[i])
-	}
-
 	for i := range f {
-		f[i] ^= x[i]
-	}
-	for i := range g {
-		g[i] ^= x[i]
+		t := b & (f[i] ^ g[i])
+		f[i] ^= t
+		g[i] ^= t
 	}
 }
 
@@ -75,12 +73,7 @@ func load3(in []byte) int64 {
 
 // load4 reads a 32-bit, little-endian value from in.
 func load4(in []byte) int64 {
-	var r int64
-	r = int64(in[0])
-	r |= int64(in[1]) << 8
-	r |= int64(in[2]) << 16
-	r |= int64(in[3]) << 24
-	return r
+	return int64(binary.LittleEndian.Uint32(in))
 }
 
 func feFromBytes(dst *fieldElement, src *[32]byte) {
diff --git a/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go b/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go
index 14b0ee8..051a830 100644
--- a/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go
+++ b/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go
@@ -27,3 +27,13 @@ func TestBaseScalarMult(t *testing.T) {
 		t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
 	}
 }
+
+func BenchmarkScalarBaseMult(b *testing.B) {
+	var in, out [32]byte
+	in[0] = 1
+
+	b.SetBytes(32)
+	for i := 0; i < b.N; i++ {
+		ScalarBaseMult(&out, &in)
+	}
+}
diff --git a/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go b/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go
index 91b8e2b..017027f 100644
--- a/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go
+++ b/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go
@@ -6,10 +6,14 @@ package poly1305
 
 import (
 	"bytes"
+	"encoding/hex"
+	"flag"
 	"testing"
 	"unsafe"
 )
 
+var stressFlag = flag.Bool("stress", false, "run slow stress tests")
+
 var testData = []struct {
 	in, k, correct []byte
 }{
@@ -39,6 +43,36 @@ var testData = []struct {
 		[]byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d},
 		[]byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14},
 	},
+	{
+		// This test generates a result of (2^130-1) % (2^130-5).
+		[]byte{
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		},
+		[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+		[]byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	},
+	{
+		// This test generates a result of (2^130-6) % (2^130-5).
+		[]byte{
+			0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		},
+		[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+		[]byte{0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+	},
+	{
+		// This test generates a result of (2^130-5) % (2^130-5).
+		[]byte{
+			0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		},
+		[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+		[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	},
 }
 
 func testSum(t *testing.T, unaligned bool) {
@@ -58,6 +92,39 @@ func testSum(t *testing.T, unaligned bool) {
 	}
 }
 
+func TestBurnin(t *testing.T) {
+	// This test can be used to sanity-check significant changes. It can
+	// take about many minutes to run, even on fast machines. It's disabled
+	// by default.
+	if !*stressFlag {
+		t.Skip("skipping without -stress")
+	}
+
+	var key [32]byte
+	var input [25]byte
+	var output [16]byte
+
+	for i := range key {
+		key[i] = 1
+	}
+	for i := range input {
+		input[i] = 2
+	}
+
+	for i := uint64(0); i < 1e10; i++ {
+		Sum(&output, input[:], &key)
+		copy(key[0:], output[:])
+		copy(key[16:], output[:])
+		copy(input[:], output[:])
+		copy(input[16:], output[:])
+	}
+
+	const expected = "5e3b866aea0b636d240c83c428f84bfa"
+	if got := hex.EncodeToString(output[:]); got != expected {
+		t.Errorf("expected %s, got %s", expected, got)
+	}
+}
+
 func TestSum(t *testing.T)          { testSum(t, false) }
 func TestSumUnaligned(t *testing.T) { testSum(t, true) }
 
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go b/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go
index dbe50e7..b2805a5 100644
--- a/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go
@@ -6,1526 +6,136 @@
 
 package poly1305
 
-// Based on original, public domain implementation from NaCl by D. J.
-// Bernstein.
+import "encoding/binary"
 
-import "math"
-
-const (
-	alpham80 = 0.00000000558793544769287109375
-	alpham48 = 24.0
-	alpham16 = 103079215104.0
-	alpha0   = 6755399441055744.0
-	alpha18  = 1770887431076116955136.0
-	alpha32  = 29014219670751100192948224.0
-	alpha50  = 7605903601369376408980219232256.0
-	alpha64  = 124615124604835863084731911901282304.0
-	alpha82  = 32667107224410092492483962313449748299776.0
-	alpha96  = 535217884764734955396857238543560676143529984.0
-	alpha112 = 35076039295941670036888435985190792471742381031424.0
-	alpha130 = 9194973245195333150150082162901855101712434733101613056.0
-	scale    = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125
-	offset0  = 6755408030990331.0
-	offset1  = 29014256564239239022116864.0
-	offset2  = 124615283061160854719918951570079744.0
-	offset3  = 535219245894202480694386063513315216128475136.0
-)
-
-// Sum generates an authenticator for m using a one-time key and puts the
+// Sum generates an authenticator for msg using a one-time key and puts the
 // 16-byte result into out. Authenticating two different messages with the same
 // key allows an attacker to forge messages at will.
-func Sum(out *[16]byte, m []byte, key *[32]byte) {
-	r := key
-	s := key[16:]
+func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
 	var (
-		y7        float64
-		y6        float64
-		y1        float64
-		y0        float64
-		y5        float64
-		y4        float64
-		x7        float64
-		x6        float64
-		x1        float64
-		x0        float64
-		y3        float64
-		y2        float64
-		x5        float64
-		r3lowx0   float64
-		x4        float64
-		r0lowx6   float64
-		x3        float64
-		r3highx0  float64
-		x2        float64
-		r0highx6  float64
-		r0lowx0   float64
-		sr1lowx6  float64
-		r0highx0  float64
-		sr1highx6 float64
-		sr3low    float64
-		r1lowx0   float64
-		sr2lowx6  float64
-		r1highx0  float64
-		sr2highx6 float64
-		r2lowx0   float64
-		sr3lowx6  float64
-		r2highx0  float64
-		sr3highx6 float64
-		r1highx4  float64
-		r1lowx4   float64
-		r0highx4  float64
-		r0lowx4   float64
-		sr3highx4 float64
-		sr3lowx4  float64
-		sr2highx4 float64
-		sr2lowx4  float64
-		r0lowx2   float64
-		r0highx2  float64
-		r1lowx2   float64
-		r1highx2  float64
-		r2lowx2   float64
-		r2highx2  float64
-		sr3lowx2  float64
-		sr3highx2 float64
-		z0        float64
-		z1        float64
-		z2        float64
-		z3        float64
-		m0        int64
-		m1        int64
-		m2        int64
-		m3        int64
-		m00       uint32
-		m01       uint32
-		m02       uint32
-		m03       uint32
-		m10       uint32
-		m11       uint32
-		m12       uint32
-		m13       uint32
-		m20       uint32
-		m21       uint32
-		m22       uint32
-		m23       uint32
-		m30       uint32
-		m31       uint32
-		m32       uint32
-		m33       uint64
-		lbelow2   int32
-		lbelow3   int32
-		lbelow4   int32
-		lbelow5   int32
-		lbelow6   int32
-		lbelow7   int32
-		lbelow8   int32
-		lbelow9   int32
-		lbelow10  int32
-		lbelow11  int32
-		lbelow12  int32
-		lbelow13  int32
-		lbelow14  int32
-		lbelow15  int32
-		s00       uint32
-		s01       uint32
-		s02       uint32
-		s03       uint32
-		s10       uint32
-		s11       uint32
-		s12       uint32
-		s13       uint32
-		s20       uint32
-		s21       uint32
-		s22       uint32
-		s23       uint32
-		s30       uint32
-		s31       uint32
-		s32       uint32
-		s33       uint32
-		bits32    uint64
-		f         uint64
-		f0        uint64
-		f1        uint64
-		f2        uint64
-		f3        uint64
-		f4        uint64
-		g         uint64
-		g0        uint64
-		g1        uint64
-		g2        uint64
-		g3        uint64
-		g4        uint64
+		h0, h1, h2, h3, h4 uint32 // the hash accumulators
+		r0, r1, r2, r3, r4 uint64 // the r part of the key
 	)
 
-	var p int32
-
-	l := int32(len(m))
-
-	r00 := uint32(r[0])
-
-	r01 := uint32(r[1])
-
-	r02 := uint32(r[2])
-	r0 := int64(2151)
-
-	r03 := uint32(r[3])
-	r03 &= 15
-	r0 <<= 51
-
-	r10 := uint32(r[4])
-	r10 &= 252
-	r01 <<= 8
-	r0 += int64(r00)
-
-	r11 := uint32(r[5])
-	r02 <<= 16
-	r0 += int64(r01)
-
-	r12 := uint32(r[6])
-	r03 <<= 24
-	r0 += int64(r02)
-
-	r13 := uint32(r[7])
-	r13 &= 15
-	r1 := int64(2215)
-	r0 += int64(r03)
-
-	d0 := r0
-	r1 <<= 51
-	r2 := int64(2279)
-
-	r20 := uint32(r[8])
-	r20 &= 252
-	r11 <<= 8
-	r1 += int64(r10)
-
-	r21 := uint32(r[9])
-	r12 <<= 16
-	r1 += int64(r11)
-
-	r22 := uint32(r[10])
-	r13 <<= 24
-	r1 += int64(r12)
-
-	r23 := uint32(r[11])
-	r23 &= 15
-	r2 <<= 51
-	r1 += int64(r13)
-
-	d1 := r1
-	r21 <<= 8
-	r2 += int64(r20)
-
-	r30 := uint32(r[12])
-	r30 &= 252
-	r22 <<= 16
-	r2 += int64(r21)
-
-	r31 := uint32(r[13])
-	r23 <<= 24
-	r2 += int64(r22)
-
-	r32 := uint32(r[14])
-	r2 += int64(r23)
-	r3 := int64(2343)
-
-	d2 := r2
-	r3 <<= 51
-
-	r33 := uint32(r[15])
-	r33 &= 15
-	r31 <<= 8
-	r3 += int64(r30)
-
-	r32 <<= 16
-	r3 += int64(r31)
-
-	r33 <<= 24
-	r3 += int64(r32)
-
-	r3 += int64(r33)
-	h0 := alpha32 - alpha32
-
-	d3 := r3
-	h1 := alpha32 - alpha32
-
-	h2 := alpha32 - alpha32
-
-	h3 := alpha32 - alpha32
-
-	h4 := alpha32 - alpha32
-
-	r0low := math.Float64frombits(uint64(d0))
-	h5 := alpha32 - alpha32
-
-	r1low := math.Float64frombits(uint64(d1))
-	h6 := alpha32 - alpha32
-
-	r2low := math.Float64frombits(uint64(d2))
-	h7 := alpha32 - alpha32
-
-	r0low -= alpha0
-
-	r1low -= alpha32
-
-	r2low -= alpha64
-
-	r0high := r0low + alpha18
-
-	r3low := math.Float64frombits(uint64(d3))
-
-	r1high := r1low + alpha50
-	sr1low := scale * r1low
-
-	r2high := r2low + alpha82
-	sr2low := scale * r2low
-
-	r0high -= alpha18
-	r0high_stack := r0high
-
-	r3low -= alpha96
-
-	r1high -= alpha50
-	r1high_stack := r1high
-
-	sr1high := sr1low + alpham80
-
-	r0low -= r0high
-
-	r2high -= alpha82
-	sr3low = scale * r3low
-
-	sr2high := sr2low + alpham48
-
-	r1low -= r1high
-	r1low_stack := r1low
-
-	sr1high -= alpham80
-	sr1high_stack := sr1high
-
-	r2low -= r2high
-	r2low_stack := r2low
-
-	sr2high -= alpham48
-	sr2high_stack := sr2high
-
-	r3high := r3low + alpha112
-	r0low_stack := r0low
-
-	sr1low -= sr1high
-	sr1low_stack := sr1low
-
-	sr3high := sr3low + alpham16
-	r2high_stack := r2high
-
-	sr2low -= sr2high
-	sr2low_stack := sr2low
-
-	r3high -= alpha112
-	r3high_stack := r3high
-
-	sr3high -= alpham16
-	sr3high_stack := sr3high
-
-	r3low -= r3high
-	r3low_stack := r3low
-
-	sr3low -= sr3high
-	sr3low_stack := sr3low
-
-	if l < 16 {
-		goto addatmost15bytes
-	}
-
-	m00 = uint32(m[p+0])
-	m0 = 2151
-
-	m0 <<= 51
-	m1 = 2215
-	m01 = uint32(m[p+1])
-
-	m1 <<= 51
-	m2 = 2279
-	m02 = uint32(m[p+2])
-
-	m2 <<= 51
-	m3 = 2343
-	m03 = uint32(m[p+3])
-
-	m10 = uint32(m[p+4])
-	m01 <<= 8
-	m0 += int64(m00)
-
-	m11 = uint32(m[p+5])
-	m02 <<= 16
-	m0 += int64(m01)
-
-	m12 = uint32(m[p+6])
-	m03 <<= 24
-	m0 += int64(m02)
-
-	m13 = uint32(m[p+7])
-	m3 <<= 51
-	m0 += int64(m03)
-
-	m20 = uint32(m[p+8])
-	m11 <<= 8
-	m1 += int64(m10)
-
-	m21 = uint32(m[p+9])
-	m12 <<= 16
-	m1 += int64(m11)
-
-	m22 = uint32(m[p+10])
-	m13 <<= 24
-	m1 += int64(m12)
-
-	m23 = uint32(m[p+11])
-	m1 += int64(m13)
-
-	m30 = uint32(m[p+12])
-	m21 <<= 8
-	m2 += int64(m20)
-
-	m31 = uint32(m[p+13])
-	m22 <<= 16
-	m2 += int64(m21)
-
-	m32 = uint32(m[p+14])
-	m23 <<= 24
-	m2 += int64(m22)
-
-	m33 = uint64(m[p+15])
-	m2 += int64(m23)
-
-	d0 = m0
-	m31 <<= 8
-	m3 += int64(m30)
-
-	d1 = m1
-	m32 <<= 16
-	m3 += int64(m31)
-
-	d2 = m2
-	m33 += 256
-
-	m33 <<= 24
-	m3 += int64(m32)
-
-	m3 += int64(m33)
-	d3 = m3
-
-	p += 16
-	l -= 16
-
-	z0 = math.Float64frombits(uint64(d0))
-
-	z1 = math.Float64frombits(uint64(d1))
-
-	z2 = math.Float64frombits(uint64(d2))
-
-	z3 = math.Float64frombits(uint64(d3))
-
-	z0 -= alpha0
-
-	z1 -= alpha32
-
-	z2 -= alpha64
-
-	z3 -= alpha96
-
-	h0 += z0
-
-	h1 += z1
-
-	h3 += z2
-
-	h5 += z3
-
-	if l < 16 {
-		goto multiplyaddatmost15bytes
+	r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff)
+	r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03)
+	r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff)
+	r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff)
+	r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff)
+
+	R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5
+
+	for len(msg) >= TagSize {
+		// h += msg
+		h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff
+		h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff
+		h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff
+		h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff
+		h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | (1 << 24)
+
+		// h *= r
+		d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1)
+		d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2)
+		d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3)
+		d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4)
+		d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0)
+
+		// h %= p
+		h0 = uint32(d0) & 0x3ffffff
+		h1 = uint32(d1) & 0x3ffffff
+		h2 = uint32(d2) & 0x3ffffff
+		h3 = uint32(d3) & 0x3ffffff
+		h4 = uint32(d4) & 0x3ffffff
+
+		h0 += uint32(d4>>26) * 5
+		h1 += h0 >> 26
+		h0 = h0 & 0x3ffffff
+
+		msg = msg[TagSize:]
 	}
 
-multiplyaddatleast16bytes:
-
-	m2 = 2279
-	m20 = uint32(m[p+8])
-	y7 = h7 + alpha130
-
-	m2 <<= 51
-	m3 = 2343
-	m21 = uint32(m[p+9])
-	y6 = h6 + alpha130
-
-	m3 <<= 51
-	m0 = 2151
-	m22 = uint32(m[p+10])
-	y1 = h1 + alpha32
-
-	m0 <<= 51
-	m1 = 2215
-	m23 = uint32(m[p+11])
-	y0 = h0 + alpha32
-
-	m1 <<= 51
-	m30 = uint32(m[p+12])
-	y7 -= alpha130
-
-	m21 <<= 8
-	m2 += int64(m20)
-	m31 = uint32(m[p+13])
-	y6 -= alpha130
-
-	m22 <<= 16
-	m2 += int64(m21)
-	m32 = uint32(m[p+14])
-	y1 -= alpha32
-
-	m23 <<= 24
-	m2 += int64(m22)
-	m33 = uint64(m[p+15])
-	y0 -= alpha32
-
-	m2 += int64(m23)
-	m00 = uint32(m[p+0])
-	y5 = h5 + alpha96
-
-	m31 <<= 8
-	m3 += int64(m30)
-	m01 = uint32(m[p+1])
-	y4 = h4 + alpha96
-
-	m32 <<= 16
-	m02 = uint32(m[p+2])
-	x7 = h7 - y7
-	y7 *= scale
-
-	m33 += 256
-	m03 = uint32(m[p+3])
-	x6 = h6 - y6
-	y6 *= scale
-
-	m33 <<= 24
-	m3 += int64(m31)
-	m10 = uint32(m[p+4])
-	x1 = h1 - y1
-
-	m01 <<= 8
-	m3 += int64(m32)
-	m11 = uint32(m[p+5])
-	x0 = h0 - y0
-
-	m3 += int64(m33)
-	m0 += int64(m00)
-	m12 = uint32(m[p+6])
-	y5 -= alpha96
-
-	m02 <<= 16
-	m0 += int64(m01)
-	m13 = uint32(m[p+7])
-	y4 -= alpha96
-
-	m03 <<= 24
-	m0 += int64(m02)
-	d2 = m2
-	x1 += y7
-
-	m0 += int64(m03)
-	d3 = m3
-	x0 += y6
-
-	m11 <<= 8
-	m1 += int64(m10)
-	d0 = m0
-	x7 += y5
-
-	m12 <<= 16
-	m1 += int64(m11)
-	x6 += y4
-
-	m13 <<= 24
-	m1 += int64(m12)
-	y3 = h3 + alpha64
-
-	m1 += int64(m13)
-	d1 = m1
-	y2 = h2 + alpha64
-
-	x0 += x1
-
-	x6 += x7
-
-	y3 -= alpha64
-	r3low = r3low_stack
-
-	y2 -= alpha64
-	r0low = r0low_stack
-
-	x5 = h5 - y5
-	r3lowx0 = r3low * x0
-	r3high = r3high_stack
-
-	x4 = h4 - y4
-	r0lowx6 = r0low * x6
-	r0high = r0high_stack
-
-	x3 = h3 - y3
-	r3highx0 = r3high * x0
-	sr1low = sr1low_stack
-
-	x2 = h2 - y2
-	r0highx6 = r0high * x6
-	sr1high = sr1high_stack
-
-	x5 += y3
-	r0lowx0 = r0low * x0
-	r1low = r1low_stack
-
-	h6 = r3lowx0 + r0lowx6
-	sr1lowx6 = sr1low * x6
-	r1high = r1high_stack
-
-	x4 += y2
-	r0highx0 = r0high * x0
-	sr2low = sr2low_stack
-
-	h7 = r3highx0 + r0highx6
-	sr1highx6 = sr1high * x6
-	sr2high = sr2high_stack
-
-	x3 += y1
-	r1lowx0 = r1low * x0
-	r2low = r2low_stack
-
-	h0 = r0lowx0 + sr1lowx6
-	sr2lowx6 = sr2low * x6
-	r2high = r2high_stack
-
-	x2 += y0
-	r1highx0 = r1high * x0
-	sr3low = sr3low_stack
-
-	h1 = r0highx0 + sr1highx6
-	sr2highx6 = sr2high * x6
-	sr3high = sr3high_stack
-
-	x4 += x5
-	r2lowx0 = r2low * x0
-	z2 = math.Float64frombits(uint64(d2))
-
-	h2 = r1lowx0 + sr2lowx6
-	sr3lowx6 = sr3low * x6
-
-	x2 += x3
-	r2highx0 = r2high * x0
-	z3 = math.Float64frombits(uint64(d3))
-
-	h3 = r1highx0 + sr2highx6
-	sr3highx6 = sr3high * x6
-
-	r1highx4 = r1high * x4
-	z2 -= alpha64
-
-	h4 = r2lowx0 + sr3lowx6
-	r1lowx4 = r1low * x4
-
-	r0highx4 = r0high * x4
-	z3 -= alpha96
-
-	h5 = r2highx0 + sr3highx6
-	r0lowx4 = r0low * x4
-
-	h7 += r1highx4
-	sr3highx4 = sr3high * x4
-
-	h6 += r1lowx4
-	sr3lowx4 = sr3low * x4
-
-	h5 += r0highx4
-	sr2highx4 = sr2high * x4
-
-	h4 += r0lowx4
-	sr2lowx4 = sr2low * x4
-
-	h3 += sr3highx4
-	r0lowx2 = r0low * x2
-
-	h2 += sr3lowx4
-	r0highx2 = r0high * x2
-
-	h1 += sr2highx4
-	r1lowx2 = r1low * x2
-
-	h0 += sr2lowx4
-	r1highx2 = r1high * x2
-
-	h2 += r0lowx2
-	r2lowx2 = r2low * x2
-
-	h3 += r0highx2
-	r2highx2 = r2high * x2
-
-	h4 += r1lowx2
-	sr3lowx2 = sr3low * x2
-
-	h5 += r1highx2
-	sr3highx2 = sr3high * x2
-
-	p += 16
-	l -= 16
-	h6 += r2lowx2
-
-	h7 += r2highx2
-
-	z1 = math.Float64frombits(uint64(d1))
-	h0 += sr3lowx2
-
-	z0 = math.Float64frombits(uint64(d0))
-	h1 += sr3highx2
-
-	z1 -= alpha32
-
-	z0 -= alpha0
-
-	h5 += z3
-
-	h3 += z2
-
-	h1 += z1
-
-	h0 += z0
-
-	if l >= 16 {
-		goto multiplyaddatleast16bytes
-	}
-
-multiplyaddatmost15bytes:
-
-	y7 = h7 + alpha130
-
-	y6 = h6 + alpha130
-
-	y1 = h1 + alpha32
-
-	y0 = h0 + alpha32
-
-	y7 -= alpha130
-
-	y6 -= alpha130
-
-	y1 -= alpha32
-
-	y0 -= alpha32
-
-	y5 = h5 + alpha96
-
-	y4 = h4 + alpha96
-
-	x7 = h7 - y7
-	y7 *= scale
-
-	x6 = h6 - y6
-	y6 *= scale
-
-	x1 = h1 - y1
-
-	x0 = h0 - y0
-
-	y5 -= alpha96
-
-	y4 -= alpha96
-
-	x1 += y7
-
-	x0 += y6
-
-	x7 += y5
-
-	x6 += y4
-
-	y3 = h3 + alpha64
-
-	y2 = h2 + alpha64
-
-	x0 += x1
-
-	x6 += x7
-
-	y3 -= alpha64
-	r3low = r3low_stack
-
-	y2 -= alpha64
-	r0low = r0low_stack
-
-	x5 = h5 - y5
-	r3lowx0 = r3low * x0
-	r3high = r3high_stack
-
-	x4 = h4 - y4
-	r0lowx6 = r0low * x6
-	r0high = r0high_stack
-
-	x3 = h3 - y3
-	r3highx0 = r3high * x0
-	sr1low = sr1low_stack
-
-	x2 = h2 - y2
-	r0highx6 = r0high * x6
-	sr1high = sr1high_stack
-
-	x5 += y3
-	r0lowx0 = r0low * x0
-	r1low = r1low_stack
-
-	h6 = r3lowx0 + r0lowx6
-	sr1lowx6 = sr1low * x6
-	r1high = r1high_stack
-
-	x4 += y2
-	r0highx0 = r0high * x0
-	sr2low = sr2low_stack
-
-	h7 = r3highx0 + r0highx6
-	sr1highx6 = sr1high * x6
-	sr2high = sr2high_stack
-
-	x3 += y1
-	r1lowx0 = r1low * x0
-	r2low = r2low_stack
-
-	h0 = r0lowx0 + sr1lowx6
-	sr2lowx6 = sr2low * x6
-	r2high = r2high_stack
-
-	x2 += y0
-	r1highx0 = r1high * x0
-	sr3low = sr3low_stack
-
-	h1 = r0highx0 + sr1highx6
-	sr2highx6 = sr2high * x6
-	sr3high = sr3high_stack
-
-	x4 += x5
-	r2lowx0 = r2low * x0
-
-	h2 = r1lowx0 + sr2lowx6
-	sr3lowx6 = sr3low * x6
-
-	x2 += x3
-	r2highx0 = r2high * x0
-
-	h3 = r1highx0 + sr2highx6
-	sr3highx6 = sr3high * x6
-
-	r1highx4 = r1high * x4
-
-	h4 = r2lowx0 + sr3lowx6
-	r1lowx4 = r1low * x4
-
-	r0highx4 = r0high * x4
-
-	h5 = r2highx0 + sr3highx6
-	r0lowx4 = r0low * x4
-
-	h7 += r1highx4
-	sr3highx4 = sr3high * x4
-
-	h6 += r1lowx4
-	sr3lowx4 = sr3low * x4
-
-	h5 += r0highx4
-	sr2highx4 = sr2high * x4
-
-	h4 += r0lowx4
-	sr2lowx4 = sr2low * x4
-
-	h3 += sr3highx4
-	r0lowx2 = r0low * x2
-
-	h2 += sr3lowx4
-	r0highx2 = r0high * x2
-
-	h1 += sr2highx4
-	r1lowx2 = r1low * x2
-
-	h0 += sr2lowx4
-	r1highx2 = r1high * x2
-
-	h2 += r0lowx2
-	r2lowx2 = r2low * x2
-
-	h3 += r0highx2
-	r2highx2 = r2high * x2
-
-	h4 += r1lowx2
-	sr3lowx2 = sr3low * x2
-
-	h5 += r1highx2
-	sr3highx2 = sr3high * x2
-
-	h6 += r2lowx2
-
-	h7 += r2highx2
-
-	h0 += sr3lowx2
-
-	h1 += sr3highx2
-
-addatmost15bytes:
-
-	if l == 0 {
-		goto nomorebytes
+	if len(msg) > 0 {
+		var block [TagSize]byte
+		off := copy(block[:], msg)
+		block[off] = 0x01
+
+		// h += msg
+		h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff
+		h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff
+		h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff
+		h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff
+		h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8)
+
+		// h *= r
+		d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1)
+		d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2)
+		d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3)
+		d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4)
+		d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0)
+
+		// h %= p
+		h0 = uint32(d0) & 0x3ffffff
+		h1 = uint32(d1) & 0x3ffffff
+		h2 = uint32(d2) & 0x3ffffff
+		h3 = uint32(d3) & 0x3ffffff
+		h4 = uint32(d4) & 0x3ffffff
+
+		h0 += uint32(d4>>26) * 5
+		h1 += h0 >> 26
+		h0 = h0 & 0x3ffffff
 	}
 
-	lbelow2 = l - 2
-
-	lbelow3 = l - 3
-
-	lbelow2 >>= 31
-	lbelow4 = l - 4
-
-	m00 = uint32(m[p+0])
-	lbelow3 >>= 31
-	p += lbelow2
-
-	m01 = uint32(m[p+1])
-	lbelow4 >>= 31
-	p += lbelow3
-
-	m02 = uint32(m[p+2])
-	p += lbelow4
-	m0 = 2151
-
-	m03 = uint32(m[p+3])
-	m0 <<= 51
-	m1 = 2215
-
-	m0 += int64(m00)
-	m01 &^= uint32(lbelow2)
-
-	m02 &^= uint32(lbelow3)
-	m01 -= uint32(lbelow2)
-
-	m01 <<= 8
-	m03 &^= uint32(lbelow4)
-
-	m0 += int64(m01)
-	lbelow2 -= lbelow3
-
-	m02 += uint32(lbelow2)
-	lbelow3 -= lbelow4
-
-	m02 <<= 16
-	m03 += uint32(lbelow3)
-
-	m03 <<= 24
-	m0 += int64(m02)
-
-	m0 += int64(m03)
-	lbelow5 = l - 5
-
-	lbelow6 = l - 6
-	lbelow7 = l - 7
-
-	lbelow5 >>= 31
-	lbelow8 = l - 8
-
-	lbelow6 >>= 31
-	p += lbelow5
-
-	m10 = uint32(m[p+4])
-	lbelow7 >>= 31
-	p += lbelow6
-
-	m11 = uint32(m[p+5])
-	lbelow8 >>= 31
-	p += lbelow7
-
-	m12 = uint32(m[p+6])
-	m1 <<= 51
-	p += lbelow8
-
-	m13 = uint32(m[p+7])
-	m10 &^= uint32(lbelow5)
-	lbelow4 -= lbelow5
-
-	m10 += uint32(lbelow4)
-	lbelow5 -= lbelow6
-
-	m11 &^= uint32(lbelow6)
-	m11 += uint32(lbelow5)
-
-	m11 <<= 8
-	m1 += int64(m10)
-
-	m1 += int64(m11)
-	m12 &^= uint32(lbelow7)
-
-	lbelow6 -= lbelow7
-	m13 &^= uint32(lbelow8)
-
-	m12 += uint32(lbelow6)
-	lbelow7 -= lbelow8
-
-	m12 <<= 16
-	m13 += uint32(lbelow7)
-
-	m13 <<= 24
-	m1 += int64(m12)
-
-	m1 += int64(m13)
-	m2 = 2279
-
-	lbelow9 = l - 9
-	m3 = 2343
-
-	lbelow10 = l - 10
-	lbelow11 = l - 11
-
-	lbelow9 >>= 31
-	lbelow12 = l - 12
-
-	lbelow10 >>= 31
-	p += lbelow9
-
-	m20 = uint32(m[p+8])
-	lbelow11 >>= 31
-	p += lbelow10
-
-	m21 = uint32(m[p+9])
-	lbelow12 >>= 31
-	p += lbelow11
-
-	m22 = uint32(m[p+10])
-	m2 <<= 51
-	p += lbelow12
-
-	m23 = uint32(m[p+11])
-	m20 &^= uint32(lbelow9)
-	lbelow8 -= lbelow9
-
-	m20 += uint32(lbelow8)
-	lbelow9 -= lbelow10
-
-	m21 &^= uint32(lbelow10)
-	m21 += uint32(lbelow9)
-
-	m21 <<= 8
-	m2 += int64(m20)
-
-	m2 += int64(m21)
-	m22 &^= uint32(lbelow11)
-
-	lbelow10 -= lbelow11
-	m23 &^= uint32(lbelow12)
-
-	m22 += uint32(lbelow10)
-	lbelow11 -= lbelow12
-
-	m22 <<= 16
-	m23 += uint32(lbelow11)
-
-	m23 <<= 24
-	m2 += int64(m22)
-
-	m3 <<= 51
-	lbelow13 = l - 13
-
-	lbelow13 >>= 31
-	lbelow14 = l - 14
-
-	lbelow14 >>= 31
-	p += lbelow13
-	lbelow15 = l - 15
-
-	m30 = uint32(m[p+12])
-	lbelow15 >>= 31
-	p += lbelow14
-
-	m31 = uint32(m[p+13])
-	p += lbelow15
-	m2 += int64(m23)
-
-	m32 = uint32(m[p+14])
-	m30 &^= uint32(lbelow13)
-	lbelow12 -= lbelow13
-
-	m30 += uint32(lbelow12)
-	lbelow13 -= lbelow14
-
-	m3 += int64(m30)
-	m31 &^= uint32(lbelow14)
-
-	m31 += uint32(lbelow13)
-	m32 &^= uint32(lbelow15)
-
-	m31 <<= 8
-	lbelow14 -= lbelow15
-
-	m3 += int64(m31)
-	m32 += uint32(lbelow14)
-	d0 = m0
-
-	m32 <<= 16
-	m33 = uint64(lbelow15 + 1)
-	d1 = m1
-
-	m33 <<= 24
-	m3 += int64(m32)
-	d2 = m2
-
-	m3 += int64(m33)
-	d3 = m3
-
-	z3 = math.Float64frombits(uint64(d3))
-
-	z2 = math.Float64frombits(uint64(d2))
-
-	z1 = math.Float64frombits(uint64(d1))
-
-	z0 = math.Float64frombits(uint64(d0))
-
-	z3 -= alpha96
-
-	z2 -= alpha64
-
-	z1 -= alpha32
-
-	z0 -= alpha0
-
-	h5 += z3
-
-	h3 += z2
-
-	h1 += z1
-
-	h0 += z0
-
-	y7 = h7 + alpha130
-
-	y6 = h6 + alpha130
-
-	y1 = h1 + alpha32
-
-	y0 = h0 + alpha32
-
-	y7 -= alpha130
-
-	y6 -= alpha130
-
-	y1 -= alpha32
-
-	y0 -= alpha32
-
-	y5 = h5 + alpha96
-
-	y4 = h4 + alpha96
-
-	x7 = h7 - y7
-	y7 *= scale
-
-	x6 = h6 - y6
-	y6 *= scale
-
-	x1 = h1 - y1
-
-	x0 = h0 - y0
-
-	y5 -= alpha96
-
-	y4 -= alpha96
-
-	x1 += y7
-
-	x0 += y6
-
-	x7 += y5
-
-	x6 += y4
-
-	y3 = h3 + alpha64
-
-	y2 = h2 + alpha64
-
-	x0 += x1
-
-	x6 += x7
-
-	y3 -= alpha64
-	r3low = r3low_stack
-
-	y2 -= alpha64
-	r0low = r0low_stack
-
-	x5 = h5 - y5
-	r3lowx0 = r3low * x0
-	r3high = r3high_stack
-
-	x4 = h4 - y4
-	r0lowx6 = r0low * x6
-	r0high = r0high_stack
-
-	x3 = h3 - y3
-	r3highx0 = r3high * x0
-	sr1low = sr1low_stack
-
-	x2 = h2 - y2
-	r0highx6 = r0high * x6
-	sr1high = sr1high_stack
-
-	x5 += y3
-	r0lowx0 = r0low * x0
-	r1low = r1low_stack
-
-	h6 = r3lowx0 + r0lowx6
-	sr1lowx6 = sr1low * x6
-	r1high = r1high_stack
-
-	x4 += y2
-	r0highx0 = r0high * x0
-	sr2low = sr2low_stack
-
-	h7 = r3highx0 + r0highx6
-	sr1highx6 = sr1high * x6
-	sr2high = sr2high_stack
-
-	x3 += y1
-	r1lowx0 = r1low * x0
-	r2low = r2low_stack
-
-	h0 = r0lowx0 + sr1lowx6
-	sr2lowx6 = sr2low * x6
-	r2high = r2high_stack
-
-	x2 += y0
-	r1highx0 = r1high * x0
-	sr3low = sr3low_stack
-
-	h1 = r0highx0 + sr1highx6
-	sr2highx6 = sr2high * x6
-	sr3high = sr3high_stack
-
-	x4 += x5
-	r2lowx0 = r2low * x0
-
-	h2 = r1lowx0 + sr2lowx6
-	sr3lowx6 = sr3low * x6
-
-	x2 += x3
-	r2highx0 = r2high * x0
-
-	h3 = r1highx0 + sr2highx6
-	sr3highx6 = sr3high * x6
-
-	r1highx4 = r1high * x4
-
-	h4 = r2lowx0 + sr3lowx6
-	r1lowx4 = r1low * x4
-
-	r0highx4 = r0high * x4
-
-	h5 = r2highx0 + sr3highx6
-	r0lowx4 = r0low * x4
-
-	h7 += r1highx4
-	sr3highx4 = sr3high * x4
-
-	h6 += r1lowx4
-	sr3lowx4 = sr3low * x4
-
-	h5 += r0highx4
-	sr2highx4 = sr2high * x4
-
-	h4 += r0lowx4
-	sr2lowx4 = sr2low * x4
-
-	h3 += sr3highx4
-	r0lowx2 = r0low * x2
-
-	h2 += sr3lowx4
-	r0highx2 = r0high * x2
-
-	h1 += sr2highx4
-	r1lowx2 = r1low * x2
-
-	h0 += sr2lowx4
-	r1highx2 = r1high * x2
-
-	h2 += r0lowx2
-	r2lowx2 = r2low * x2
-
-	h3 += r0highx2
-	r2highx2 = r2high * x2
-
-	h4 += r1lowx2
-	sr3lowx2 = sr3low * x2
-
-	h5 += r1highx2
-	sr3highx2 = sr3high * x2
-
-	h6 += r2lowx2
-
-	h7 += r2highx2
-
-	h0 += sr3lowx2
-
-	h1 += sr3highx2
-
-nomorebytes:
-
-	y7 = h7 + alpha130
-
-	y0 = h0 + alpha32
-
-	y1 = h1 + alpha32
-
-	y2 = h2 + alpha64
-
-	y7 -= alpha130
-
-	y3 = h3 + alpha64
-
-	y4 = h4 + alpha96
-
-	y5 = h5 + alpha96
-
-	x7 = h7 - y7
-	y7 *= scale
-
-	y0 -= alpha32
-
-	y1 -= alpha32
-
-	y2 -= alpha64
-
-	h6 += x7
-
-	y3 -= alpha64
-
-	y4 -= alpha96
-
-	y5 -= alpha96
-
-	y6 = h6 + alpha130
-
-	x0 = h0 - y0
-
-	x1 = h1 - y1
-
-	x2 = h2 - y2
-
-	y6 -= alpha130
-
-	x0 += y7
-
-	x3 = h3 - y3
-
-	x4 = h4 - y4
-
-	x5 = h5 - y5
-
-	x6 = h6 - y6
-
-	y6 *= scale
-
-	x2 += y0
-
-	x3 += y1
-
-	x4 += y2
-
-	x0 += y6
-
-	x5 += y3
-
-	x6 += y4
-
-	x2 += x3
-
-	x0 += x1
-
-	x4 += x5
-
-	x6 += y5
-
-	x2 += offset1
-	d1 = int64(math.Float64bits(x2))
-
-	x0 += offset0
-	d0 = int64(math.Float64bits(x0))
-
-	x4 += offset2
-	d2 = int64(math.Float64bits(x4))
-
-	x6 += offset3
-	d3 = int64(math.Float64bits(x6))
-
-	f0 = uint64(d0)
-
-	f1 = uint64(d1)
-	bits32 = math.MaxUint64
-
-	f2 = uint64(d2)
-	bits32 >>= 32
-
-	f3 = uint64(d3)
-	f = f0 >> 32
-
-	f0 &= bits32
-	f &= 255
-
-	f1 += f
-	g0 = f0 + 5
-
-	g = g0 >> 32
-	g0 &= bits32
-
-	f = f1 >> 32
-	f1 &= bits32
-
-	f &= 255
-	g1 = f1 + g
-
-	g = g1 >> 32
-	f2 += f
-
-	f = f2 >> 32
-	g1 &= bits32
-
-	f2 &= bits32
-	f &= 255
-
-	f3 += f
-	g2 = f2 + g
-
-	g = g2 >> 32
-	g2 &= bits32
-
-	f4 = f3 >> 32
-	f3 &= bits32
-
-	f4 &= 255
-	g3 = f3 + g
-
-	g = g3 >> 32
-	g3 &= bits32
-
-	g4 = f4 + g
-
-	g4 = g4 - 4
-	s00 = uint32(s[0])
-
-	f = uint64(int64(g4) >> 63)
-	s01 = uint32(s[1])
-
-	f0 &= f
-	g0 &^= f
-	s02 = uint32(s[2])
-
-	f1 &= f
-	f0 |= g0
-	s03 = uint32(s[3])
-
-	g1 &^= f
-	f2 &= f
-	s10 = uint32(s[4])
-
-	f3 &= f
-	g2 &^= f
-	s11 = uint32(s[5])
-
-	g3 &^= f
-	f1 |= g1
-	s12 = uint32(s[6])
-
-	f2 |= g2
-	f3 |= g3
-	s13 = uint32(s[7])
-
-	s01 <<= 8
-	f0 += uint64(s00)
-	s20 = uint32(s[8])
-
-	s02 <<= 16
-	f0 += uint64(s01)
-	s21 = uint32(s[9])
-
-	s03 <<= 24
-	f0 += uint64(s02)
-	s22 = uint32(s[10])
-
-	s11 <<= 8
-	f1 += uint64(s10)
-	s23 = uint32(s[11])
-
-	s12 <<= 16
-	f1 += uint64(s11)
-	s30 = uint32(s[12])
-
-	s13 <<= 24
-	f1 += uint64(s12)
-	s31 = uint32(s[13])
-
-	f0 += uint64(s03)
-	f1 += uint64(s13)
-	s32 = uint32(s[14])
-
-	s21 <<= 8
-	f2 += uint64(s20)
-	s33 = uint32(s[15])
-
-	s22 <<= 16
-	f2 += uint64(s21)
-
-	s23 <<= 24
-	f2 += uint64(s22)
-
-	s31 <<= 8
-	f3 += uint64(s30)
-
-	s32 <<= 16
-	f3 += uint64(s31)
-
-	s33 <<= 24
-	f3 += uint64(s32)
-
-	f2 += uint64(s23)
-	f3 += uint64(s33)
-
-	out[0] = byte(f0)
-	f0 >>= 8
-	out[1] = byte(f0)
-	f0 >>= 8
-	out[2] = byte(f0)
-	f0 >>= 8
-	out[3] = byte(f0)
-	f0 >>= 8
-	f1 += f0
-
-	out[4] = byte(f1)
-	f1 >>= 8
-	out[5] = byte(f1)
-	f1 >>= 8
-	out[6] = byte(f1)
-	f1 >>= 8
-	out[7] = byte(f1)
-	f1 >>= 8
-	f2 += f1
-
-	out[8] = byte(f2)
-	f2 >>= 8
-	out[9] = byte(f2)
-	f2 >>= 8
-	out[10] = byte(f2)
-	f2 >>= 8
-	out[11] = byte(f2)
-	f2 >>= 8
-	f3 += f2
-
-	out[12] = byte(f3)
-	f3 >>= 8
-	out[13] = byte(f3)
-	f3 >>= 8
-	out[14] = byte(f3)
-	f3 >>= 8
-	out[15] = byte(f3)
+	// h %= p reduction
+	h2 += h1 >> 26
+	h1 &= 0x3ffffff
+	h3 += h2 >> 26
+	h2 &= 0x3ffffff
+	h4 += h3 >> 26
+	h3 &= 0x3ffffff
+	h0 += 5 * (h4 >> 26)
+	h4 &= 0x3ffffff
+	h1 += h0 >> 26
+	h0 &= 0x3ffffff
+
+	// h - p
+	t0 := h0 + 5
+	t1 := h1 + (t0 >> 26)
+	t2 := h2 + (t1 >> 26)
+	t3 := h3 + (t2 >> 26)
+	t4 := h4 + (t3 >> 26) - (1 << 26)
+	t0 &= 0x3ffffff
+	t1 &= 0x3ffffff
+	t2 &= 0x3ffffff
+	t3 &= 0x3ffffff
+
+	// select h if h < p else h - p
+	t_mask := (t4 >> 31) - 1
+	h_mask := ^t_mask
+	h0 = (h0 & h_mask) | (t0 & t_mask)
+	h1 = (h1 & h_mask) | (t1 & t_mask)
+	h2 = (h2 & h_mask) | (t2 & t_mask)
+	h3 = (h3 & h_mask) | (t3 & t_mask)
+	h4 = (h4 & h_mask) | (t4 & t_mask)
+
+	// h %= 2^128
+	h0 |= h1 << 26
+	h1 = ((h1 >> 6) | (h2 << 20))
+	h2 = ((h2 >> 12) | (h3 << 14))
+	h3 = ((h3 >> 18) | (h4 << 8))
+
+	// s: the s part of the key
+	// tag = (h + s) % (2^128)
+	t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:]))
+	h0 = uint32(t)
+	t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32)
+	h1 = uint32(t)
+	t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32)
+	h2 = uint32(t)
+	t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32)
+	h3 = uint32(t)
+
+	binary.LittleEndian.PutUint32(out[0:], h0)
+	binary.LittleEndian.PutUint32(out[4:], h1)
+	binary.LittleEndian.PutUint32(out[8:], h2)
+	binary.LittleEndian.PutUint32(out[12:], h3)
 }
diff --git a/src/vendor/golang_org/x/net/http2/hpack/encode.go b/src/vendor/golang_org/x/net/http2/hpack/encode.go
index f9bb033..54726c2 100644
--- a/src/vendor/golang_org/x/net/http2/hpack/encode.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/encode.go
@@ -39,13 +39,14 @@ func NewEncoder(w io.Writer) *Encoder {
 		tableSizeUpdate: false,
 		w:               w,
 	}
+	e.dynTab.table.init()
 	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.
+// if necessary. If produced, it is done before encoding f.
 func (e *Encoder) WriteField(f HeaderField) error {
 	e.buf = e.buf[:0]
 
@@ -88,29 +89,17 @@ func (e *Encoder) WriteField(f HeaderField) error {
 // 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
+	i, nameValueMatch = staticTable.search(f)
+	if nameValueMatch {
+		return i, true
 	}
 
-	j, nameValueMatch := e.dynTab.search(f)
+	j, nameValueMatch := e.dynTab.table.search(f)
 	if nameValueMatch || (i == 0 && j != 0) {
-		i = j + uint64(len(staticTable))
+		return j + uint64(staticTable.len()), nameValueMatch
 	}
-	return
+
+	return i, false
 }
 
 // SetMaxDynamicTableSize changes the dynamic header table size to v.
diff --git a/src/vendor/golang_org/x/net/http2/hpack/encode_test.go b/src/vendor/golang_org/x/net/http2/hpack/encode_test.go
index 92286f3..05f12db 100644
--- a/src/vendor/golang_org/x/net/http2/hpack/encode_test.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/encode_test.go
@@ -7,6 +7,8 @@ package hpack
 import (
 	"bytes"
 	"encoding/hex"
+	"fmt"
+	"math/rand"
 	"reflect"
 	"strings"
 	"testing"
@@ -101,17 +103,20 @@ func TestEncoderSearchTable(t *testing.T) {
 		wantMatch bool
 	}{
 		// Name and Value match
-		{pair("foo", "bar"), uint64(len(staticTable) + 3), true},
-		{pair("blake", "miz"), uint64(len(staticTable) + 2), true},
+		{pair("foo", "bar"), uint64(staticTable.len()) + 3, true},
+		{pair("blake", "miz"), uint64(staticTable.len()) + 2, true},
 		{pair(":method", "GET"), 2, true},
 
-		// Only name match because Sensitive == true
-		{HeaderField{":method", "GET", true}, 2, false},
+		// Only name match because Sensitive == true. This is allowed to match
+		// any ":method" entry. The current implementation uses the last entry
+		// added in newStaticTable.
+		{HeaderField{":method", "GET", true}, 3, false},
 
 		// Only Name matches
-		{pair("foo", "..."), uint64(len(staticTable) + 3), false},
-		{pair("blake", "..."), uint64(len(staticTable) + 2), false},
-		{pair(":method", "..."), 2, false},
+		{pair("foo", "..."), uint64(staticTable.len()) + 3, false},
+		{pair("blake", "..."), uint64(staticTable.len()) + 2, false},
+		// As before, this is allowed to match any ":method" entry.
+		{pair(":method", "..."), 3, false},
 
 		// None match
 		{pair("foo-", "bar"), 0, false},
@@ -328,3 +333,54 @@ func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
 func removeSpace(s string) string {
 	return strings.Replace(s, " ", "", -1)
 }
+
+func BenchmarkEncoderSearchTable(b *testing.B) {
+	e := NewEncoder(nil)
+
+	// A sample of possible header fields.
+	// This is not based on any actual data from HTTP/2 traces.
+	var possible []HeaderField
+	for _, f := range staticTable.ents {
+		if f.Value == "" {
+			possible = append(possible, f)
+			continue
+		}
+		// Generate 5 random values, except for cookie and set-cookie,
+		// which we know can have many values in practice.
+		num := 5
+		if f.Name == "cookie" || f.Name == "set-cookie" {
+			num = 25
+		}
+		for i := 0; i < num; i++ {
+			f.Value = fmt.Sprintf("%s-%d", f.Name, i)
+			possible = append(possible, f)
+		}
+	}
+	for k := 0; k < 10; k++ {
+		f := HeaderField{
+			Name:      fmt.Sprintf("x-header-%d", k),
+			Sensitive: rand.Int()%2 == 0,
+		}
+		for i := 0; i < 5; i++ {
+			f.Value = fmt.Sprintf("%s-%d", f.Name, i)
+			possible = append(possible, f)
+		}
+	}
+
+	// Add a random sample to the dynamic table. This very loosely simulates
+	// a history of 100 requests with 20 header fields per request.
+	for r := 0; r < 100*20; r++ {
+		f := possible[rand.Int31n(int32(len(possible)))]
+		// Skip if this is in the staticTable verbatim.
+		if _, has := staticTable.search(f); !has {
+			e.dynTab.add(f)
+		}
+	}
+
+	b.ResetTimer()
+	for n := 0; n < b.N; n++ {
+		for _, f := range possible {
+			e.searchTable(f)
+		}
+	}
+}
diff --git a/src/vendor/golang_org/x/net/http2/hpack/hpack.go b/src/vendor/golang_org/x/net/http2/hpack/hpack.go
index 8aa197a..176644a 100644
--- a/src/vendor/golang_org/x/net/http2/hpack/hpack.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/hpack.go
@@ -57,11 +57,11 @@ func (hf HeaderField) String() string {
 	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.
+// Size returns the size of an entry per RFC 7541 section 4.1.
 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
+	// 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
@@ -102,6 +102,7 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod
 		emit:        emitFunc,
 		emitEnabled: true,
 	}
+	d.dynTab.table.init()
 	d.dynTab.allowedMaxSize = maxDynamicTableSize
 	d.dynTab.setMaxSize(maxDynamicTableSize)
 	return d
@@ -154,12 +155,9 @@ func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
 }
 
 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
+	table          headerFieldTable
+	size           uint32 // in bytes
 	maxSize        uint32 // current maxSize
 	allowedMaxSize uint32 // maxSize may go up to this, inclusive
 }
@@ -169,95 +167,45 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
 	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.table.addEntry(f)
 	dt.size += f.Size()
 	dt.evict()
 }
 
-// If we're too big, evict old stuff (front of the slice)
+// If we're too big, evict old stuff.
 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)]
+	var n int
+	for dt.size > dt.maxSize && n < dt.table.len() {
+		dt.size -= dt.table.ents[n].Size()
+		n++
 	}
-}
-
-// 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
+	dt.table.evictOldest(n)
 }
 
 func (d *Decoder) maxTableIndex() int {
-	return len(d.dynTab.ents) + len(staticTable)
+	// This should never overflow. RFC 7540 Section 6.5.2 limits the size of
+	// the dynamic table to 2^32 bytes, where each entry will occupy more than
+	// one byte. Further, the staticTable has a fixed, small length.
+	return d.dynTab.table.len() + staticTable.len()
 }
 
 func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
-	if i < 1 {
+	// See Section 2.3.3.
+	if i == 0 {
 		return
 	}
+	if i <= uint64(staticTable.len()) {
+		return staticTable.ents[i-1], true
+	}
 	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
+	// In the dynamic table, newer entries have lower indices.
+	// However, dt.ents[0] is the oldest entry. Hence, dt.ents is
+	// the reversed dynamic table.
+	dt := d.dynTab.table
+	return dt.ents[dt.len()-(int(i)-staticTable.len())], true
 }
 
 // Decode decodes an entire block.
@@ -307,7 +255,7 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
 		err = d.parseHeaderFieldRepr()
 		if err == errNeedMore {
 			// Extra paranoia, making sure saveBuf won't
-			// get too large.  All the varint and string
+			// 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.
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
index 4c7b17b..bc7f476 100644
--- a/src/vendor/golang_org/x/net/http2/hpack/hpack_test.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/hpack_test.go
@@ -5,117 +5,16 @@
 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))
@@ -132,10 +31,10 @@ func TestDynamicTableAt(t *testing.T) {
 	}
 	d.dynTab.add(pair("foo", "bar"))
 	d.dynTab.add(pair("blake", "miz"))
-	if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
+	if got, want := at(staticTable.len()+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 {
+	if got, want := at(staticTable.len()+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 {
@@ -143,41 +42,6 @@ func TestDynamicTableAt(t *testing.T) {
 	}
 }
 
-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 {
@@ -196,7 +60,7 @@ func TestDynamicTableSizeEvict(t *testing.T) {
 	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 {
+	if got, want := d.mustAt(staticTable.len()+1), (pair("foo", "bar")); got != want {
 		t.Errorf("at(dyn 1) = %v; want %v", got, want)
 	}
 	add(pair("long", strings.Repeat("x", 500)))
@@ -255,9 +119,9 @@ func TestDecoderDecode(t *testing.T) {
 }
 
 func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
-	hf = make([]HeaderField, len(dt.ents))
+	hf = make([]HeaderField, len(dt.table.ents))
 	for i := range hf {
-		hf[i] = dt.ents[len(dt.ents)-1-i]
+		hf[i] = dt.table.ents[len(dt.table.ents)-1-i]
 	}
 	return
 }
@@ -784,6 +648,10 @@ func TestHuffmanFuzzCrash(t *testing.T) {
 	}
 }
 
+func pair(name, value string) HeaderField {
+	return HeaderField{Name: name, Value: value}
+}
+
 func dehex(s string) []byte {
 	s = strings.Replace(s, " ", "", -1)
 	s = strings.Replace(s, "\n", "", -1)
diff --git a/src/vendor/golang_org/x/net/http2/hpack/tables.go b/src/vendor/golang_org/x/net/http2/hpack/tables.go
index b9283a0..8bd975d 100644
--- a/src/vendor/golang_org/x/net/http2/hpack/tables.go
+++ b/src/vendor/golang_org/x/net/http2/hpack/tables.go
@@ -4,73 +4,200 @@
 
 package hpack
 
-func pair(name, value string) HeaderField {
-	return HeaderField{Name: name, Value: value}
+import (
+	"fmt"
+)
+
+// headerFieldTable implements a list of HeaderFields.
+// This is used to implement the static and dynamic tables.
+type headerFieldTable struct {
+	// For static tables, entries are never evicted.
+	//
+	// For dynamic tables, entries are evicted from ents[0] and added to the end.
+	// Each entry has a unique id that starts at one and increments for each
+	// entry that is added. This unique id is stable across evictions, meaning
+	// it can be used as a pointer to a specific entry. As in hpack, unique ids
+	// are 1-based. The unique id for ents[k] is k + evictCount + 1.
+	//
+	// Zero is not a valid unique id.
+	//
+	// evictCount should not overflow in any remotely practical situation. In
+	// practice, we will have one dynamic table per HTTP/2 connection. If we
+	// assume a very powerful server that handles 1M QPS per connection and each
+	// request adds (then evicts) 100 entries from the table, it would still take
+	// 2M years for evictCount to overflow.
+	ents       []HeaderField
+	evictCount uint64
+
+	// byName maps a HeaderField name to the unique id of the newest entry with
+	// the same name. See above for a definition of "unique id".
+	byName map[string]uint64
+
+	// byNameValue maps a HeaderField name/value pair to the unique id of the newest
+	// entry with the same name and value. See above for a definition of "unique id".
+	byNameValue map[pairNameValue]uint64
+}
+
+type pairNameValue struct {
+	name, value string
+}
+
+func (t *headerFieldTable) init() {
+	t.byName = make(map[string]uint64)
+	t.byNameValue = make(map[pairNameValue]uint64)
+}
+
+// len reports the number of entries in the table.
+func (t *headerFieldTable) len() int {
+	return len(t.ents)
+}
+
+// addEntry adds a new entry.
+func (t *headerFieldTable) addEntry(f HeaderField) {
+	id := uint64(t.len()) + t.evictCount + 1
+	t.byName[f.Name] = id
+	t.byNameValue[pairNameValue{f.Name, f.Value}] = id
+	t.ents = append(t.ents, f)
+}
+
+// evictOldest evicts the n oldest entries in the table.
+func (t *headerFieldTable) evictOldest(n int) {
+	if n > t.len() {
+		panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len()))
+	}
+	for k := 0; k < n; k++ {
+		f := t.ents[k]
+		id := t.evictCount + uint64(k) + 1
+		if t.byName[f.Name] == id {
+			delete(t.byName, f.Name)
+		}
+		if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
+			delete(t.byNameValue, p)
+		}
+	}
+	copy(t.ents, t.ents[n:])
+	for k := t.len() - n; k < t.len(); k++ {
+		t.ents[k] = HeaderField{} // so strings can be garbage collected
+	}
+	t.ents = t.ents[:t.len()-n]
+	if t.evictCount+uint64(n) < t.evictCount {
+		panic("evictCount overflow")
+	}
+	t.evictCount += uint64(n)
+}
+
+// search finds f in the table. 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.
+//
+// The returned index is a 1-based HPACK index. For dynamic tables, HPACK says
+// that index 1 should be the newest entry, but t.ents[0] is the oldest entry,
+// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
+// table, the return value i actually refers to the entry t.ents[t.len()-i].
+//
+// All tables are assumed to be a dynamic tables except for the global
+// staticTable pointer.
+//
+// See Section 2.3.3.
+func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
+	if !f.Sensitive {
+		if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 {
+			return t.idToIndex(id), true
+		}
+	}
+	if id := t.byName[f.Name]; id != 0 {
+		return t.idToIndex(id), false
+	}
+	return 0, false
+}
+
+// idToIndex converts a unique id to an HPACK index.
+// See Section 2.3.3.
+func (t *headerFieldTable) idToIndex(id uint64) uint64 {
+	if id <= t.evictCount {
+		panic(fmt.Sprintf("id (%v) <= evictCount (%v)", id, t.evictCount))
+	}
+	k := id - t.evictCount - 1 // convert id to an index t.ents[k]
+	if t != staticTable {
+		return uint64(t.len()) - k // dynamic table
+	}
+	return k + 1
 }
 
 // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
-var staticTable = [...]HeaderField{
-	pair(":authority", ""), // index 1 (1-based)
-	pair(":method", "GET"),
-	pair(":method", "POST"),
-	pair(":path", "/"),
-	pair(":path", "/index.html"),
-	pair(":scheme", "http"),
-	pair(":scheme", "https"),
-	pair(":status", "200"),
-	pair(":status", "204"),
-	pair(":status", "206"),
-	pair(":status", "304"),
-	pair(":status", "400"),
-	pair(":status", "404"),
-	pair(":status", "500"),
-	pair("accept-charset", ""),
-	pair("accept-encoding", "gzip, deflate"),
-	pair("accept-language", ""),
-	pair("accept-ranges", ""),
-	pair("accept", ""),
-	pair("access-control-allow-origin", ""),
-	pair("age", ""),
-	pair("allow", ""),
-	pair("authorization", ""),
-	pair("cache-control", ""),
-	pair("content-disposition", ""),
-	pair("content-encoding", ""),
-	pair("content-language", ""),
-	pair("content-length", ""),
-	pair("content-location", ""),
-	pair("content-range", ""),
-	pair("content-type", ""),
-	pair("cookie", ""),
-	pair("date", ""),
-	pair("etag", ""),
-	pair("expect", ""),
-	pair("expires", ""),
-	pair("from", ""),
-	pair("host", ""),
-	pair("if-match", ""),
-	pair("if-modified-since", ""),
-	pair("if-none-match", ""),
-	pair("if-range", ""),
-	pair("if-unmodified-since", ""),
-	pair("last-modified", ""),
-	pair("link", ""),
-	pair("location", ""),
-	pair("max-forwards", ""),
-	pair("proxy-authenticate", ""),
-	pair("proxy-authorization", ""),
-	pair("range", ""),
-	pair("referer", ""),
-	pair("refresh", ""),
-	pair("retry-after", ""),
-	pair("server", ""),
-	pair("set-cookie", ""),
-	pair("strict-transport-security", ""),
-	pair("transfer-encoding", ""),
-	pair("user-agent", ""),
-	pair("vary", ""),
-	pair("via", ""),
-	pair("www-authenticate", ""),
+var staticTable = newStaticTable()
+var staticTableEntries = [...]HeaderField{
+	HeaderField{Name: ":authority"},
+	HeaderField{Name: ":method", Value: "GET"},
+	HeaderField{Name: ":method", Value: "POST"},
+	HeaderField{Name: ":path", Value: "/"},
+	HeaderField{Name: ":path", Value: "/index.html"},
+	HeaderField{Name: ":scheme", Value: "http"},
+	HeaderField{Name: ":scheme", Value: "https"},
+	HeaderField{Name: ":status", Value: "200"},
+	HeaderField{Name: ":status", Value: "204"},
+	HeaderField{Name: ":status", Value: "206"},
+	HeaderField{Name: ":status", Value: "304"},
+	HeaderField{Name: ":status", Value: "400"},
+	HeaderField{Name: ":status", Value: "404"},
+	HeaderField{Name: ":status", Value: "500"},
+	HeaderField{Name: "accept-charset"},
+	HeaderField{Name: "accept-encoding", Value: "gzip, deflate"},
+	HeaderField{Name: "accept-language"},
+	HeaderField{Name: "accept-ranges"},
+	HeaderField{Name: "accept"},
+	HeaderField{Name: "access-control-allow-origin"},
+	HeaderField{Name: "age"},
+	HeaderField{Name: "allow"},
+	HeaderField{Name: "authorization"},
+	HeaderField{Name: "cache-control"},
+	HeaderField{Name: "content-disposition"},
+	HeaderField{Name: "content-encoding"},
+	HeaderField{Name: "content-language"},
+	HeaderField{Name: "content-length"},
+	HeaderField{Name: "content-location"},
+	HeaderField{Name: "content-range"},
+	HeaderField{Name: "content-type"},
+	HeaderField{Name: "cookie"},
+	HeaderField{Name: "date"},
+	HeaderField{Name: "etag"},
+	HeaderField{Name: "expect"},
+	HeaderField{Name: "expires"},
+	HeaderField{Name: "from"},
+	HeaderField{Name: "host"},
+	HeaderField{Name: "if-match"},
+	HeaderField{Name: "if-modified-since"},
+	HeaderField{Name: "if-none-match"},
+	HeaderField{Name: "if-range"},
+	HeaderField{Name: "if-unmodified-since"},
+	HeaderField{Name: "last-modified"},
+	HeaderField{Name: "link"},
+	HeaderField{Name: "location"},
+	HeaderField{Name: "max-forwards"},
+	HeaderField{Name: "proxy-authenticate"},
+	HeaderField{Name: "proxy-authorization"},
+	HeaderField{Name: "range"},
+	HeaderField{Name: "referer"},
+	HeaderField{Name: "refresh"},
+	HeaderField{Name: "retry-after"},
+	HeaderField{Name: "server"},
+	HeaderField{Name: "set-cookie"},
+	HeaderField{Name: "strict-transport-security"},
+	HeaderField{Name: "transfer-encoding"},
+	HeaderField{Name: "user-agent"},
+	HeaderField{Name: "vary"},
+	HeaderField{Name: "via"},
+	HeaderField{Name: "www-authenticate"},
+}
+
+func newStaticTable() *headerFieldTable {
+	t := &headerFieldTable{}
+	t.init()
+	for _, e := range staticTableEntries[:] {
+		t.addEntry(e)
+	}
+	return t
 }
 
 var huffmanCodes = [256]uint32{
diff --git a/src/vendor/golang_org/x/net/http2/hpack/tables_test.go b/src/vendor/golang_org/x/net/http2/hpack/tables_test.go
new file mode 100644
index 0000000..d963f36
--- /dev/null
+++ b/src/vendor/golang_org/x/net/http2/hpack/tables_test.go
@@ -0,0 +1,214 @@
+// Copyright 2017 The Go Authors. 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"
+	"regexp"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func TestHeaderFieldTable(t *testing.T) {
+	table := &headerFieldTable{}
+	table.init()
+	table.addEntry(pair("key1", "value1-1"))
+	table.addEntry(pair("key2", "value2-1"))
+	table.addEntry(pair("key1", "value1-2"))
+	table.addEntry(pair("key3", "value3-1"))
+	table.addEntry(pair("key4", "value4-1"))
+	table.addEntry(pair("key2", "value2-2"))
+
+	// Tests will be run twice: once before evicting anything, and
+	// again after evicting the three oldest entries.
+	tests := []struct {
+		f                 HeaderField
+		beforeWantStaticI uint64
+		beforeWantMatch   bool
+		afterWantStaticI  uint64
+		afterWantMatch    bool
+	}{
+		{HeaderField{"key1", "value1-1", false}, 1, true, 0, false},
+		{HeaderField{"key1", "value1-2", false}, 3, true, 0, false},
+		{HeaderField{"key1", "value1-3", false}, 3, false, 0, false},
+		{HeaderField{"key2", "value2-1", false}, 2, true, 3, false},
+		{HeaderField{"key2", "value2-2", false}, 6, true, 3, true},
+		{HeaderField{"key2", "value2-3", false}, 6, false, 3, false},
+		{HeaderField{"key4", "value4-1", false}, 5, true, 2, true},
+		// Name match only, because sensitive.
+		{HeaderField{"key4", "value4-1", true}, 5, false, 2, false},
+		// Key not found.
+		{HeaderField{"key5", "value5-x", false}, 0, false, 0, false},
+	}
+
+	staticToDynamic := func(i uint64) uint64 {
+		if i == 0 {
+			return 0
+		}
+		return uint64(table.len()) - i + 1 // dynamic is the reversed table
+	}
+
+	searchStatic := func(f HeaderField) (uint64, bool) {
+		old := staticTable
+		staticTable = table
+		defer func() { staticTable = old }()
+		return staticTable.search(f)
+	}
+
+	searchDynamic := func(f HeaderField) (uint64, bool) {
+		return table.search(f)
+	}
+
+	for _, test := range tests {
+		gotI, gotMatch := searchStatic(test.f)
+		if wantI, wantMatch := test.beforeWantStaticI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch {
+			t.Errorf("before evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
+		}
+		gotI, gotMatch = searchDynamic(test.f)
+		wantDynamicI := staticToDynamic(test.beforeWantStaticI)
+		if wantI, wantMatch := wantDynamicI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch {
+			t.Errorf("before evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
+		}
+	}
+
+	table.evictOldest(3)
+
+	for _, test := range tests {
+		gotI, gotMatch := searchStatic(test.f)
+		if wantI, wantMatch := test.afterWantStaticI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch {
+			t.Errorf("after evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
+		}
+		gotI, gotMatch = searchDynamic(test.f)
+		wantDynamicI := staticToDynamic(test.afterWantStaticI)
+		if wantI, wantMatch := wantDynamicI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch {
+			t.Errorf("after evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
+		}
+	}
+}
+
+func TestHeaderFieldTable_LookupMapEviction(t *testing.T) {
+	table := &headerFieldTable{}
+	table.init()
+	table.addEntry(pair("key1", "value1-1"))
+	table.addEntry(pair("key2", "value2-1"))
+	table.addEntry(pair("key1", "value1-2"))
+	table.addEntry(pair("key3", "value3-1"))
+	table.addEntry(pair("key4", "value4-1"))
+	table.addEntry(pair("key2", "value2-2"))
+
+	// evict all pairs
+	table.evictOldest(table.len())
+
+	if l := table.len(); l > 0 {
+		t.Errorf("table.len() = %d, want 0", l)
+	}
+
+	if l := len(table.byName); l > 0 {
+		t.Errorf("len(table.byName) = %d, want 0", l)
+	}
+
+	if l := len(table.byNameValue); l > 0 {
+		t.Errorf("len(table.byNameValue) = %d, want 0", l)
+	}
+}
+
+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 > staticTable.len() {
+			t.Errorf("Bogus index %d on line %q", i, l)
+			continue
+		}
+		if got, want := staticTable.ents[i-1].Name, m[2]; got != want {
+			t.Errorf("header index %d name = %q; want %q", i, got, want)
+		}
+		if got, want := staticTable.ents[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)
+	}
+}
diff --git a/src/vendor/golang_org/x/net/idna/idna.go b/src/vendor/golang_org/x/net/idna/idna.go
index 3daa897..e8307f9 100644
--- a/src/vendor/golang_org/x/net/idna/idna.go
+++ b/src/vendor/golang_org/x/net/idna/idna.go
@@ -1,61 +1,661 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package idna implements IDNA2008 (Internationalized Domain Names for
-// Applications), defined in RFC 5890, RFC 5891, RFC 5892, RFC 5893 and
-// RFC 5894.
-package idna // import "golang.org/x/net/idna"
+// Package idna implements IDNA2008 using the compatibility processing
+// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
+// deal with the transition from IDNA2003.
+//
+// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
+// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
+// UTS #46 is defined in http://www.unicode.org/reports/tr46.
+// See http://unicode.org/cldr/utility/idna.jsp for a visualization of the
+// differences between these two standards.
+package idna // import "golang_org/x/text/internal/export/idna"
 
 import (
+	"fmt"
 	"strings"
 	"unicode/utf8"
-)
 
-// TODO(nigeltao): specify when errors occur. For example, is ToASCII(".") or
-// ToASCII("foo\x00") an error? See also http://www.unicode.org/faq/idn.html#11
+	"golang_org/x/text/secure/bidirule"
+	"golang_org/x/text/unicode/norm"
+)
 
-// acePrefix is the ASCII Compatible Encoding prefix.
-const acePrefix = "xn--"
+// NOTE: Unlike common practice in Go APIs, the functions will return a
+// sanitized domain name in case of errors. Browsers sometimes use a partially
+// evaluated string as lookup.
+// TODO: the current error handling is, in my opinion, the least opinionated.
+// Other strategies are also viable, though:
+// Option 1) Return an empty string in case of error, but allow the user to
+//    specify explicitly which errors to ignore.
+// Option 2) Return the partially evaluated string if it is itself a valid
+//    string, otherwise return the empty string in case of error.
+// Option 3) Option 1 and 2.
+// Option 4) Always return an empty string for now and implement Option 1 as
+//    needed, and document that the return string may not be empty in case of
+//    error in the future.
+// I think Option 1 is best, but it is quite opinionated.
 
-// ToASCII converts a domain or domain label to its ASCII form. For example,
-// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
-// ToASCII("golang") is "golang".
+// ToASCII is a wrapper for Punycode.ToASCII.
 func ToASCII(s string) (string, error) {
-	if ascii(s) {
-		return s, nil
-	}
-	labels := strings.Split(s, ".")
-	for i, label := range labels {
-		if !ascii(label) {
-			a, err := encode(acePrefix, label)
-			if err != nil {
-				return "", err
-			}
-			labels[i] = a
+	return Punycode.process(s, true)
+}
+
+// ToUnicode is a wrapper for Punycode.ToUnicode.
+func ToUnicode(s string) (string, error) {
+	return Punycode.process(s, false)
+}
+
+// An Option configures a Profile at creation time.
+type Option func(*options)
+
+// Transitional sets a Profile to use the Transitional mapping as defined in UTS
+// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
+// transitional mapping provides a compromise between IDNA2003 and IDNA2008
+// compatibility. It is used by most browsers when resolving domain names. This
+// option is only meaningful if combined with MapForLookup.
+func Transitional(transitional bool) Option {
+	return func(o *options) { o.transitional = true }
+}
+
+// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
+// are longer than allowed by the RFC.
+func VerifyDNSLength(verify bool) Option {
+	return func(o *options) { o.verifyDNSLength = verify }
+}
+
+// ValidateLabels sets whether to check the mandatory label validation criteria
+// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
+// of hyphens ('-'), normalization, validity of runes, and the context rules.
+func ValidateLabels(enable bool) Option {
+	return func(o *options) {
+		// Don't override existing mappings, but set one that at least checks
+		// normalization if it is not set.
+		if o.mapping == nil && enable {
+			o.mapping = normalize
 		}
+		o.trie = trie
+		o.validateLabels = enable
+		o.fromPuny = validateFromPunycode
 	}
-	return strings.Join(labels, "."), nil
+}
+
+// StrictDomainName limits the set of permissable ASCII characters to those
+// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
+// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
+//
+// This option is useful, for instance, for browsers that allow characters
+// outside this range, for example a '_' (U+005F LOW LINE). See
+// http://www.rfc-editor.org/std/std3.txt for more details This option
+// corresponds to the UseSTD3ASCIIRules option in UTS #46.
+func StrictDomainName(use bool) Option {
+	return func(o *options) {
+		o.trie = trie
+		o.useSTD3Rules = use
+		o.fromPuny = validateFromPunycode
+	}
+}
+
+// NOTE: the following options pull in tables. The tables should not be linked
+// in as long as the options are not used.
+
+// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
+// that relies on proper validation of labels should include this rule.
+func BidiRule() Option {
+	return func(o *options) { o.bidirule = bidirule.ValidString }
+}
+
+// ValidateForRegistration sets validation options to verify that a given IDN is
+// properly formatted for registration as defined by Section 4 of RFC 5891.
+func ValidateForRegistration() Option {
+	return func(o *options) {
+		o.mapping = validateRegistration
+		StrictDomainName(true)(o)
+		ValidateLabels(true)(o)
+		VerifyDNSLength(true)(o)
+		BidiRule()(o)
+	}
+}
+
+// MapForLookup sets validation and mapping options such that a given IDN is
+// transformed for domain name lookup according to the requirements set out in
+// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
+// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
+// to add this check.
+//
+// The mappings include normalization and mapping case, width and other
+// compatibility mappings.
+func MapForLookup() Option {
+	return func(o *options) {
+		o.mapping = validateAndMap
+		StrictDomainName(true)(o)
+		ValidateLabels(true)(o)
+	}
+}
+
+type options struct {
+	transitional    bool
+	useSTD3Rules    bool
+	validateLabels  bool
+	verifyDNSLength bool
+
+	trie *idnaTrie
+
+	// fromPuny calls validation rules when converting A-labels to U-labels.
+	fromPuny func(p *Profile, s string) error
+
+	// mapping implements a validation and mapping step as defined in RFC 5895
+	// or UTS 46, tailored to, for example, domain registration or lookup.
+	mapping func(p *Profile, s string) (string, error)
+
+	// bidirule, if specified, checks whether s conforms to the Bidi Rule
+	// defined in RFC 5893.
+	bidirule func(s string) bool
+}
+
+// A Profile defines the configuration of a IDNA mapper.
+type Profile struct {
+	options
+}
+
+func apply(o *options, opts []Option) {
+	for _, f := range opts {
+		f(o)
+	}
+}
+
+// New creates a new Profile.
+//
+// With no options, the returned Profile is the most permissive and equals the
+// Punycode Profile. Options can be passed to further restrict the Profile. The
+// MapForLookup and ValidateForRegistration options set a collection of options,
+// for lookup and registration purposes respectively, which can be tailored by
+// adding more fine-grained options, where later options override earlier
+// options.
+func New(o ...Option) *Profile {
+	p := &Profile{}
+	apply(&p.options, o)
+	return p
+}
+
+// ToASCII converts a domain or domain label to its ASCII form. For example,
+// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
+// ToASCII("golang") is "golang". If an error is encountered it will return
+// an error and a (partially) processed result.
+func (p *Profile) ToASCII(s string) (string, error) {
+	return p.process(s, true)
 }
 
 // ToUnicode converts a domain or domain label to its Unicode form. For example,
 // ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
-// ToUnicode("golang") is "golang".
-func ToUnicode(s string) (string, error) {
-	if !strings.Contains(s, acePrefix) {
-		return s, nil
+// ToUnicode("golang") is "golang". If an error is encountered it will return
+// an error and a (partially) processed result.
+func (p *Profile) ToUnicode(s string) (string, error) {
+	pp := *p
+	pp.transitional = false
+	return pp.process(s, false)
+}
+
+// String reports a string with a description of the profile for debugging
+// purposes. The string format may change with different versions.
+func (p *Profile) String() string {
+	s := ""
+	if p.transitional {
+		s = "Transitional"
+	} else {
+		s = "NonTransitional"
+	}
+	if p.useSTD3Rules {
+		s += ":UseSTD3Rules"
+	}
+	if p.validateLabels {
+		s += ":ValidateLabels"
+	}
+	if p.verifyDNSLength {
+		s += ":VerifyDNSLength"
+	}
+	return s
+}
+
+var (
+	// Punycode is a Profile that does raw punycode processing with a minimum
+	// of validation.
+	Punycode *Profile = punycode
+
+	// Lookup is the recommended profile for looking up domain names, according
+	// to Section 5 of RFC 5891. The exact configuration of this profile may
+	// change over time.
+	Lookup *Profile = lookup
+
+	// Display is the recommended profile for displaying domain names.
+	// The configuration of this profile may change over time.
+	Display *Profile = display
+
+	// Registration is the recommended profile for checking whether a given
+	// IDN is valid for registration, according to Section 4 of RFC 5891.
+	Registration *Profile = registration
+
+	punycode = &Profile{}
+	lookup   = &Profile{options{
+		transitional:   true,
+		useSTD3Rules:   true,
+		validateLabels: true,
+		trie:           trie,
+		fromPuny:       validateFromPunycode,
+		mapping:        validateAndMap,
+		bidirule:       bidirule.ValidString,
+	}}
+	display = &Profile{options{
+		useSTD3Rules:   true,
+		validateLabels: true,
+		trie:           trie,
+		fromPuny:       validateFromPunycode,
+		mapping:        validateAndMap,
+		bidirule:       bidirule.ValidString,
+	}}
+	registration = &Profile{options{
+		useSTD3Rules:    true,
+		validateLabels:  true,
+		verifyDNSLength: true,
+		trie:            trie,
+		fromPuny:        validateFromPunycode,
+		mapping:         validateRegistration,
+		bidirule:        bidirule.ValidString,
+	}}
+
+	// TODO: profiles
+	// Register: recommended for approving domain names: don't do any mappings
+	// but rather reject on invalid input. Bundle or block deviation characters.
+)
+
+type labelError struct{ label, code_ string }
+
+func (e labelError) code() string { return e.code_ }
+func (e labelError) Error() string {
+	return fmt.Sprintf("idna: invalid label %q", e.label)
+}
+
+type runeError rune
+
+func (e runeError) code() string { return "P1" }
+func (e runeError) Error() string {
+	return fmt.Sprintf("idna: disallowed rune %U", e)
+}
+
+// process implements the algorithm described in section 4 of UTS #46,
+// see http://www.unicode.org/reports/tr46.
+func (p *Profile) process(s string, toASCII bool) (string, error) {
+	var err error
+	if p.mapping != nil {
+		s, err = p.mapping(p, s)
+	}
+	// Remove leading empty labels.
+	for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
+	}
+	// It seems like we should only create this error on ToASCII, but the
+	// UTS 46 conformance tests suggests we should always check this.
+	if err == nil && p.verifyDNSLength && s == "" {
+		err = &labelError{s, "A4"}
 	}
-	labels := strings.Split(s, ".")
-	for i, label := range labels {
+	labels := labelIter{orig: s}
+	for ; !labels.done(); labels.next() {
+		label := labels.label()
+		if label == "" {
+			// Empty labels are not okay. The label iterator skips the last
+			// label if it is empty.
+			if err == nil && p.verifyDNSLength {
+				err = &labelError{s, "A4"}
+			}
+			continue
+		}
 		if strings.HasPrefix(label, acePrefix) {
-			u, err := decode(label[len(acePrefix):])
-			if err != nil {
-				return "", err
+			u, err2 := decode(label[len(acePrefix):])
+			if err2 != nil {
+				if err == nil {
+					err = err2
+				}
+				// Spec says keep the old label.
+				continue
+			}
+			labels.set(u)
+			if err == nil && p.validateLabels {
+				err = p.fromPuny(p, u)
+			}
+			if err == nil {
+				// This should be called on NonTransitional, according to the
+				// spec, but that currently does not have any effect. Use the
+				// original profile to preserve options.
+				err = p.validateLabel(u)
+			}
+		} else if err == nil {
+			err = p.validateLabel(label)
+		}
+	}
+	if toASCII {
+		for labels.reset(); !labels.done(); labels.next() {
+			label := labels.label()
+			if !ascii(label) {
+				a, err2 := encode(acePrefix, label)
+				if err == nil {
+					err = err2
+				}
+				label = a
+				labels.set(a)
+			}
+			n := len(label)
+			if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
+				err = &labelError{label, "A4"}
+			}
+		}
+	}
+	s = labels.result()
+	if toASCII && p.verifyDNSLength && err == nil {
+		// Compute the length of the domain name minus the root label and its dot.
+		n := len(s)
+		if n > 0 && s[n-1] == '.' {
+			n--
+		}
+		if len(s) < 1 || n > 253 {
+			err = &labelError{s, "A4"}
+		}
+	}
+	return s, err
+}
+
+func normalize(p *Profile, s string) (string, error) {
+	return norm.NFC.String(s), nil
+}
+
+func validateRegistration(p *Profile, s string) (string, error) {
+	if !norm.NFC.IsNormalString(s) {
+		return s, &labelError{s, "V1"}
+	}
+	var err error
+	for i := 0; i < len(s); {
+		v, sz := trie.lookupString(s[i:])
+		i += sz
+		// Copy bytes not copied so far.
+		switch p.simplify(info(v).category()) {
+		// TODO: handle the NV8 defined in the Unicode idna data set to allow
+		// for strict conformance to IDNA2008.
+		case valid, deviation:
+		case disallowed, mapped, unknown, ignored:
+			if err == nil {
+				r, _ := utf8.DecodeRuneInString(s[i:])
+				err = runeError(r)
+			}
+		}
+	}
+	return s, err
+}
+
+func validateAndMap(p *Profile, s string) (string, error) {
+	var (
+		err error
+		b   []byte
+		k   int
+	)
+	for i := 0; i < len(s); {
+		v, sz := trie.lookupString(s[i:])
+		start := i
+		i += sz
+		// Copy bytes not copied so far.
+		switch p.simplify(info(v).category()) {
+		case valid:
+			continue
+		case disallowed:
+			if err == nil {
+				r, _ := utf8.DecodeRuneInString(s[i:])
+				err = runeError(r)
 			}
-			labels[i] = u
+			continue
+		case mapped, deviation:
+			b = append(b, s[k:start]...)
+			b = info(v).appendMapping(b, s[start:i])
+		case ignored:
+			b = append(b, s[k:start]...)
+			// drop the rune
+		case unknown:
+			b = append(b, s[k:start]...)
+			b = append(b, "\ufffd"...)
+		}
+		k = i
+	}
+	if k == 0 {
+		// No changes so far.
+		s = norm.NFC.String(s)
+	} else {
+		b = append(b, s[k:]...)
+		if norm.NFC.QuickSpan(b) != len(b) {
+			b = norm.NFC.Bytes(b)
 		}
+		// TODO: the punycode converters require strings as input.
+		s = string(b)
+	}
+	return s, err
+}
+
+// A labelIter allows iterating over domain name labels.
+type labelIter struct {
+	orig     string
+	slice    []string
+	curStart int
+	curEnd   int
+	i        int
+}
+
+func (l *labelIter) reset() {
+	l.curStart = 0
+	l.curEnd = 0
+	l.i = 0
+}
+
+func (l *labelIter) done() bool {
+	return l.curStart >= len(l.orig)
+}
+
+func (l *labelIter) result() string {
+	if l.slice != nil {
+		return strings.Join(l.slice, ".")
+	}
+	return l.orig
+}
+
+func (l *labelIter) label() string {
+	if l.slice != nil {
+		return l.slice[l.i]
+	}
+	p := strings.IndexByte(l.orig[l.curStart:], '.')
+	l.curEnd = l.curStart + p
+	if p == -1 {
+		l.curEnd = len(l.orig)
+	}
+	return l.orig[l.curStart:l.curEnd]
+}
+
+// next sets the value to the next label. It skips the last label if it is empty.
+func (l *labelIter) next() {
+	l.i++
+	if l.slice != nil {
+		if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
+			l.curStart = len(l.orig)
+		}
+	} else {
+		l.curStart = l.curEnd + 1
+		if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
+			l.curStart = len(l.orig)
+		}
+	}
+}
+
+func (l *labelIter) set(s string) {
+	if l.slice == nil {
+		l.slice = strings.Split(l.orig, ".")
+	}
+	l.slice[l.i] = s
+}
+
+// acePrefix is the ASCII Compatible Encoding prefix.
+const acePrefix = "xn--"
+
+func (p *Profile) simplify(cat category) category {
+	switch cat {
+	case disallowedSTD3Mapped:
+		if p.useSTD3Rules {
+			cat = disallowed
+		} else {
+			cat = mapped
+		}
+	case disallowedSTD3Valid:
+		if p.useSTD3Rules {
+			cat = disallowed
+		} else {
+			cat = valid
+		}
+	case deviation:
+		if !p.transitional {
+			cat = valid
+		}
+	case validNV8, validXV8:
+		// TODO: handle V2008
+		cat = valid
+	}
+	return cat
+}
+
+func validateFromPunycode(p *Profile, s string) error {
+	if !norm.NFC.IsNormalString(s) {
+		return &labelError{s, "V1"}
+	}
+	for i := 0; i < len(s); {
+		v, sz := trie.lookupString(s[i:])
+		if c := p.simplify(info(v).category()); c != valid && c != deviation {
+			return &labelError{s, "V6"}
+		}
+		i += sz
+	}
+	return nil
+}
+
+const (
+	zwnj = "\u200c"
+	zwj  = "\u200d"
+)
+
+type joinState int8
+
+const (
+	stateStart joinState = iota
+	stateVirama
+	stateBefore
+	stateBeforeVirama
+	stateAfter
+	stateFAIL
+)
+
+var joinStates = [][numJoinTypes]joinState{
+	stateStart: {
+		joiningL:   stateBefore,
+		joiningD:   stateBefore,
+		joinZWNJ:   stateFAIL,
+		joinZWJ:    stateFAIL,
+		joinVirama: stateVirama,
+	},
+	stateVirama: {
+		joiningL: stateBefore,
+		joiningD: stateBefore,
+	},
+	stateBefore: {
+		joiningL:   stateBefore,
+		joiningD:   stateBefore,
+		joiningT:   stateBefore,
+		joinZWNJ:   stateAfter,
+		joinZWJ:    stateFAIL,
+		joinVirama: stateBeforeVirama,
+	},
+	stateBeforeVirama: {
+		joiningL: stateBefore,
+		joiningD: stateBefore,
+		joiningT: stateBefore,
+	},
+	stateAfter: {
+		joiningL:   stateFAIL,
+		joiningD:   stateBefore,
+		joiningT:   stateAfter,
+		joiningR:   stateStart,
+		joinZWNJ:   stateFAIL,
+		joinZWJ:    stateFAIL,
+		joinVirama: stateAfter, // no-op as we can't accept joiners here
+	},
+	stateFAIL: {
+		0:          stateFAIL,
+		joiningL:   stateFAIL,
+		joiningD:   stateFAIL,
+		joiningT:   stateFAIL,
+		joiningR:   stateFAIL,
+		joinZWNJ:   stateFAIL,
+		joinZWJ:    stateFAIL,
+		joinVirama: stateFAIL,
+	},
+}
+
+// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
+// already implicitly satisfied by the overall implementation.
+func (p *Profile) validateLabel(s string) error {
+	if s == "" {
+		if p.verifyDNSLength {
+			return &labelError{s, "A4"}
+		}
+		return nil
+	}
+	if p.bidirule != nil && !p.bidirule(s) {
+		return &labelError{s, "B"}
+	}
+	if !p.validateLabels {
+		return nil
+	}
+	trie := p.trie // p.validateLabels is only set if trie is set.
+	if len(s) > 4 && s[2] == '-' && s[3] == '-' {
+		return &labelError{s, "V2"}
+	}
+	if s[0] == '-' || s[len(s)-1] == '-' {
+		return &labelError{s, "V3"}
+	}
+	// TODO: merge the use of this in the trie.
+	v, sz := trie.lookupString(s)
+	x := info(v)
+	if x.isModifier() {
+		return &labelError{s, "V5"}
+	}
+	// Quickly return in the absence of zero-width (non) joiners.
+	if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
+		return nil
+	}
+	st := stateStart
+	for i := 0; ; {
+		jt := x.joinType()
+		if s[i:i+sz] == zwj {
+			jt = joinZWJ
+		} else if s[i:i+sz] == zwnj {
+			jt = joinZWNJ
+		}
+		st = joinStates[st][jt]
+		if x.isViramaModifier() {
+			st = joinStates[st][joinVirama]
+		}
+		if i += sz; i == len(s) {
+			break
+		}
+		v, sz = trie.lookupString(s[i:])
+		x = info(v)
+	}
+	if st == stateFAIL || st == stateAfter {
+		return &labelError{s, "C"}
 	}
-	return strings.Join(labels, "."), nil
+	return nil
 }
 
 func ascii(s string) bool {
diff --git a/src/vendor/golang_org/x/net/idna/idna_test.go b/src/vendor/golang_org/x/net/idna/idna_test.go
deleted file mode 100644
index b1bc6fa..0000000
--- a/src/vendor/golang_org/x/net/idna/idna_test.go
+++ /dev/null
@@ -1,43 +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 idna
-
-import (
-	"testing"
-)
-
-var idnaTestCases = [...]struct {
-	ascii, unicode string
-}{
-	// Labels.
-	{"books", "books"},
-	{"xn--bcher-kva", "bücher"},
-
-	// Domains.
-	{"foo--xn--bar.org", "foo--xn--bar.org"},
-	{"golang.org", "golang.org"},
-	{"example.xn--p1ai", "example.рф"},
-	{"xn--czrw28b.tw", "商業.tw"},
-	{"www.xn--mller-kva.de", "www.müller.de"},
-}
-
-func TestIDNA(t *testing.T) {
-	for _, tc := range idnaTestCases {
-		if a, err := ToASCII(tc.unicode); err != nil {
-			t.Errorf("ToASCII(%q): %v", tc.unicode, err)
-		} else if a != tc.ascii {
-			t.Errorf("ToASCII(%q): got %q, want %q", tc.unicode, a, tc.ascii)
-		}
-
-		if u, err := ToUnicode(tc.ascii); err != nil {
-			t.Errorf("ToUnicode(%q): %v", tc.ascii, err)
-		} else if u != tc.unicode {
-			t.Errorf("ToUnicode(%q): got %q, want %q", tc.ascii, u, tc.unicode)
-		}
-	}
-}
-
-// TODO(nigeltao): test errors, once we've specified when ToASCII and ToUnicode
-// return errors.
diff --git a/src/vendor/golang_org/x/net/idna/punycode.go b/src/vendor/golang_org/x/net/idna/punycode.go
index 92e733f..fab9229 100644
--- a/src/vendor/golang_org/x/net/idna/punycode.go
+++ b/src/vendor/golang_org/x/net/idna/punycode.go
@@ -1,4 +1,6 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go 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 +9,6 @@ package idna
 // This file implements the Punycode algorithm from RFC 3492.
 
 import (
-	"fmt"
 	"math"
 	"strings"
 	"unicode/utf8"
@@ -27,6 +28,8 @@ const (
 	tmin        int32 = 1
 )
 
+func punyError(s string) error { return &labelError{s, "A3"} }
+
 // decode decodes a string as specified in section 6.2.
 func decode(encoded string) (string, error) {
 	if encoded == "" {
@@ -34,7 +37,7 @@ func decode(encoded string) (string, error) {
 	}
 	pos := 1 + strings.LastIndex(encoded, "-")
 	if pos == 1 {
-		return "", fmt.Errorf("idna: invalid label %q", encoded)
+		return "", punyError(encoded)
 	}
 	if pos == len(encoded) {
 		return encoded[:len(encoded)-1], nil
@@ -50,16 +53,16 @@ func decode(encoded string) (string, error) {
 		oldI, w := i, int32(1)
 		for k := base; ; k += base {
 			if pos == len(encoded) {
-				return "", fmt.Errorf("idna: invalid label %q", encoded)
+				return "", punyError(encoded)
 			}
 			digit, ok := decodeDigit(encoded[pos])
 			if !ok {
-				return "", fmt.Errorf("idna: invalid label %q", encoded)
+				return "", punyError(encoded)
 			}
 			pos++
 			i += digit * w
 			if i < 0 {
-				return "", fmt.Errorf("idna: invalid label %q", encoded)
+				return "", punyError(encoded)
 			}
 			t := k - bias
 			if t < tmin {
@@ -72,7 +75,7 @@ func decode(encoded string) (string, error) {
 			}
 			w *= base - t
 			if w >= math.MaxInt32/base {
-				return "", fmt.Errorf("idna: invalid label %q", encoded)
+				return "", punyError(encoded)
 			}
 		}
 		x := int32(len(output) + 1)
@@ -80,7 +83,7 @@ func decode(encoded string) (string, error) {
 		n += i / x
 		i %= x
 		if n > utf8.MaxRune || len(output) >= 1024 {
-			return "", fmt.Errorf("idna: invalid label %q", encoded)
+			return "", punyError(encoded)
 		}
 		output = append(output, 0)
 		copy(output[i+1:], output[i:])
@@ -121,14 +124,14 @@ func encode(prefix, s string) (string, error) {
 		}
 		delta += (m - n) * (h + 1)
 		if delta < 0 {
-			return "", fmt.Errorf("idna: invalid label %q", s)
+			return "", punyError(s)
 		}
 		n = m
 		for _, r := range s {
 			if r < n {
 				delta++
 				if delta < 0 {
-					return "", fmt.Errorf("idna: invalid label %q", s)
+					return "", punyError(s)
 				}
 				continue
 			}
diff --git a/src/vendor/golang_org/x/net/idna/tables.go b/src/vendor/golang_org/x/net/idna/tables.go
new file mode 100644
index 0000000..d57a3e2
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/tables.go
@@ -0,0 +1,4479 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT.
+
+package idna
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "9.0.0"
+
+var mappings string = "" + // Size: 8176 bytes
+	"\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" +
+	"\x053⁄4\x03i̇\x03l·\x03ʼn\x01s\x03dž\x03ⱥ\x03ⱦ\x01h\x01j\x01r\x01w\x01y" +
+	"\x03 ̆\x03 ̇\x03 ̊\x03 ̨\x03 ̃\x03 ̋\x01l\x01x\x04̈́\x03 ι\x01;\x05 ̈́" +
+	"\x04եւ\x04اٴ\x04وٴ\x04ۇٴ\x04يٴ\x06क़\x06ख़\x06ग़\x06ज़\x06ड़\x06ढ़\x06फ़" +
+	"\x06य़\x06ড়\x06ঢ়\x06য়\x06ਲ਼\x06ਸ਼\x06ਖ਼\x06ਗ਼\x06ਜ਼\x06ਫ਼\x06ଡ଼\x06ଢ଼" +
+	"\x06ํา\x06ໍາ\x06ຫນ\x06ຫມ\x06གྷ\x06ཌྷ\x06དྷ\x06བྷ\x06ཛྷ\x06ཀྵ\x06ཱི\x06ཱུ" +
+	"\x06ྲྀ\x09ྲཱྀ\x06ླྀ\x09ླཱྀ\x06ཱྀ\x06ྒྷ\x06ྜྷ\x06ྡྷ\x06ྦྷ\x06ྫྷ\x06ྐྵ\x02" +
+	"в\x02д\x02о\x02с\x02т\x02ъ\x02ѣ\x02æ\x01b\x01d\x01e\x02ǝ\x01g\x01i\x01k" +
+	"\x01m\x01n\x02ȣ\x01p\x01t\x01u\x02ɐ\x02ɑ\x02ə\x02ɛ\x02ɜ\x02ŋ\x02ɔ\x02ɯ" +
+	"\x01v\x02β\x02γ\x02δ\x02φ\x02χ\x02ρ\x02н\x02ɒ\x01c\x02ɕ\x02ð\x01f\x02ɟ" +
+	"\x02ɡ\x02ɥ\x02ɨ\x02ɩ\x02ɪ\x02ʝ\x02ɭ\x02ʟ\x02ɱ\x02ɰ\x02ɲ\x02ɳ\x02ɴ\x02ɵ" +
+	"\x02ɸ\x02ʂ\x02ʃ\x02ƫ\x02ʉ\x02ʊ\x02ʋ\x02ʌ\x01z\x02ʐ\x02ʑ\x02ʒ\x02θ\x02ss" +
+	"\x02ά\x02έ\x02ή\x02ί\x02ό\x02ύ\x02ώ\x05ἀι\x05ἁι\x05ἂι\x05ἃι\x05ἄι\x05ἅι" +
+	"\x05ἆι\x05ἇι\x05ἠι\x05ἡι\x05ἢι\x05ἣι\x05ἤι\x05ἥι\x05ἦι\x05ἧι\x05ὠι\x05ὡι" +
+	"\x05ὢι\x05ὣι\x05ὤι\x05ὥι\x05ὦι\x05ὧι\x05ὰι\x04αι\x04άι\x05ᾶι\x02ι\x05 ̈͂" +
+	"\x05ὴι\x04ηι\x04ήι\x05ῆι\x05 ̓̀\x05 ̓́\x05 ̓͂\x02ΐ\x05 ̔̀\x05 ̔́\x05 ̔͂" +
+	"\x02ΰ\x05 ̈̀\x01`\x05ὼι\x04ωι\x04ώι\x05ῶι\x06′′\x09′′′\x06‵‵\x09‵‵‵\x02!" +
+	"!\x02??\x02?!\x02!?\x0c′′′′\x010\x014\x015\x016\x017\x018\x019\x01+\x01=" +
+	"\x01(\x01)\x02rs\x02ħ\x02no\x01q\x02sm\x02tm\x02ω\x02å\x02א\x02ב\x02ג" +
+	"\x02ד\x02π\x051⁄7\x051⁄9\x061⁄10\x051⁄3\x052⁄3\x051⁄5\x052⁄5\x053⁄5\x054" +
+	"⁄5\x051⁄6\x055⁄6\x051⁄8\x053⁄8\x055⁄8\x057⁄8\x041⁄\x02ii\x02iv\x02vi" +
+	"\x04viii\x02ix\x02xi\x050⁄3\x06∫∫\x09∫∫∫\x06∮∮\x09∮∮∮\x0210\x0211\x0212" +
+	"\x0213\x0214\x0215\x0216\x0217\x0218\x0219\x0220\x04(10)\x04(11)\x04(12)" +
+	"\x04(13)\x04(14)\x04(15)\x04(16)\x04(17)\x04(18)\x04(19)\x04(20)\x0c∫∫∫∫" +
+	"\x02==\x05⫝̸\x02ɫ\x02ɽ\x02ȿ\x02ɀ\x01.\x04 ゙\x04 ゚\x06より\x06コト\x05(ᄀ)\x05" +
+	"(ᄂ)\x05(ᄃ)\x05(ᄅ)\x05(ᄆ)\x05(ᄇ)\x05(ᄉ)\x05(ᄋ)\x05(ᄌ)\x05(ᄎ)\x05(ᄏ)\x05(ᄐ" +
+	")\x05(ᄑ)\x05(ᄒ)\x05(가)\x05(나)\x05(다)\x05(라)\x05(마)\x05(바)\x05(사)\x05(아)" +
+	"\x05(자)\x05(차)\x05(카)\x05(타)\x05(파)\x05(하)\x05(주)\x08(오전)\x08(오후)\x05(一)" +
+	"\x05(二)\x05(三)\x05(四)\x05(五)\x05(六)\x05(七)\x05(八)\x05(九)\x05(十)\x05(月)" +
+	"\x05(火)\x05(水)\x05(木)\x05(金)\x05(土)\x05(日)\x05(株)\x05(有)\x05(社)\x05(名)" +
+	"\x05(特)\x05(財)\x05(祝)\x05(労)\x05(代)\x05(呼)\x05(学)\x05(監)\x05(企)\x05(資)" +
+	"\x05(協)\x05(祭)\x05(休)\x05(自)\x05(至)\x0221\x0222\x0223\x0224\x0225\x0226" +
+	"\x0227\x0228\x0229\x0230\x0231\x0232\x0233\x0234\x0235\x06참고\x06주의\x0236" +
+	"\x0237\x0238\x0239\x0240\x0241\x0242\x0243\x0244\x0245\x0246\x0247\x0248" +
+	"\x0249\x0250\x041月\x042月\x043月\x044月\x045月\x046月\x047月\x048月\x049月\x0510" +
+	"月\x0511月\x0512月\x02hg\x02ev\x0cアパート\x0cアルファ\x0cアンペア\x09アール\x0cイニング\x09" +
+	"インチ\x09ウォン\x0fエスクード\x0cエーカー\x09オンス\x09オーム\x09カイリ\x0cカラット\x0cカロリー\x09ガロ" +
+	"ン\x09ガンマ\x06ギガ\x09ギニー\x0cキュリー\x0cギルダー\x06キロ\x0fキログラム\x12キロメートル\x0fキロワッ" +
+	"ト\x09グラム\x0fグラムトン\x0fクルゼイロ\x0cクローネ\x09ケース\x09コルナ\x09コーポ\x0cサイクル\x0fサンチ" +
+	"ーム\x0cシリング\x09センチ\x09セント\x09ダース\x06デシ\x06ドル\x06トン\x06ナノ\x09ノット\x09ハイツ" +
+	"\x0fパーセント\x09パーツ\x0cバーレル\x0fピアストル\x09ピクル\x06ピコ\x06ビル\x0fファラッド\x0cフィート" +
+	"\x0fブッシェル\x09フラン\x0fヘクタール\x06ペソ\x09ペニヒ\x09ヘルツ\x09ペンス\x09ページ\x09ベータ\x0cポイ" +
+	"ント\x09ボルト\x06ホン\x09ポンド\x09ホール\x09ホーン\x0cマイクロ\x09マイル\x09マッハ\x09マルク\x0fマ" +
+	"ンション\x0cミクロン\x06ミリ\x0fミリバール\x06メガ\x0cメガトン\x0cメートル\x09ヤード\x09ヤール\x09ユアン" +
+	"\x0cリットル\x06リラ\x09ルピー\x0cルーブル\x06レム\x0fレントゲン\x09ワット\x040点\x041点\x042点" +
+	"\x043点\x044点\x045点\x046点\x047点\x048点\x049点\x0510点\x0511点\x0512点\x0513点" +
+	"\x0514点\x0515点\x0516点\x0517点\x0518点\x0519点\x0520点\x0521点\x0522点\x0523点" +
+	"\x0524点\x02da\x02au\x02ov\x02pc\x02dm\x02iu\x06平成\x06昭和\x06大正\x06明治\x0c株" +
+	"式会社\x02pa\x02na\x02ma\x02ka\x02kb\x02mb\x02gb\x04kcal\x02pf\x02nf\x02m" +
+	"g\x02kg\x02hz\x02ml\x02dl\x02kl\x02fm\x02nm\x02mm\x02cm\x02km\x02m2\x02m" +
+	"3\x05m∕s\x06m∕s2\x07rad∕s\x08rad∕s2\x02ps\x02ns\x02ms\x02pv\x02nv\x02mv" +
+	"\x02kv\x02pw\x02nw\x02mw\x02kw\x02bq\x02cc\x02cd\x06c∕kg\x02db\x02gy\x02" +
+	"ha\x02hp\x02in\x02kk\x02kt\x02lm\x02ln\x02lx\x02ph\x02pr\x02sr\x02sv\x02" +
+	"wb\x05v∕m\x05a∕m\x041日\x042日\x043日\x044日\x045日\x046日\x047日\x048日\x049日" +
+	"\x0510日\x0511日\x0512日\x0513日\x0514日\x0515日\x0516日\x0517日\x0518日\x0519日" +
+	"\x0520日\x0521日\x0522日\x0523日\x0524日\x0525日\x0526日\x0527日\x0528日\x0529日" +
+	"\x0530日\x0531日\x02ь\x02ɦ\x02ɬ\x02ʞ\x02ʇ\x02œ\x04𤋮\x04𢡊\x04𢡄\x04𣏕\x04𥉉" +
+	"\x04𥳐\x04𧻓\x02ff\x02fi\x02fl\x02st\x04մն\x04մե\x04մի\x04վն\x04մխ\x04יִ" +
+	"\x04ײַ\x02ע\x02ה\x02כ\x02ל\x02ם\x02ר\x02ת\x04שׁ\x04שׂ\x06שּׁ\x06שּׂ\x04א" +
+	"ַ\x04אָ\x04אּ\x04בּ\x04גּ\x04דּ\x04הּ\x04וּ\x04זּ\x04טּ\x04יּ\x04ךּ\x04" +
+	"כּ\x04לּ\x04מּ\x04נּ\x04סּ\x04ףּ\x04פּ\x04צּ\x04קּ\x04רּ\x04שּ\x04תּ" +
+	"\x04וֹ\x04בֿ\x04כֿ\x04פֿ\x04אל\x02ٱ\x02ٻ\x02پ\x02ڀ\x02ٺ\x02ٿ\x02ٹ\x02ڤ" +
+	"\x02ڦ\x02ڄ\x02ڃ\x02چ\x02ڇ\x02ڍ\x02ڌ\x02ڎ\x02ڈ\x02ژ\x02ڑ\x02ک\x02گ\x02ڳ" +
+	"\x02ڱ\x02ں\x02ڻ\x02ۀ\x02ہ\x02ھ\x02ے\x02ۓ\x02ڭ\x02ۇ\x02ۆ\x02ۈ\x02ۋ\x02ۅ" +
+	"\x02ۉ\x02ې\x02ى\x04ئا\x04ئە\x04ئو\x04ئۇ\x04ئۆ\x04ئۈ\x04ئې\x04ئى\x02ی\x04" +
+	"ئج\x04ئح\x04ئم\x04ئي\x04بج\x04بح\x04بخ\x04بم\x04بى\x04بي\x04تج\x04تح" +
+	"\x04تخ\x04تم\x04تى\x04تي\x04ثج\x04ثم\x04ثى\x04ثي\x04جح\x04جم\x04حج\x04حم" +
+	"\x04خج\x04خح\x04خم\x04سج\x04سح\x04سخ\x04سم\x04صح\x04صم\x04ضج\x04ضح\x04ضخ" +
+	"\x04ضم\x04طح\x04طم\x04ظم\x04عج\x04عم\x04غج\x04غم\x04فج\x04فح\x04فخ\x04فم" +
+	"\x04فى\x04في\x04قح\x04قم\x04قى\x04قي\x04كا\x04كج\x04كح\x04كخ\x04كل\x04كم" +
+	"\x04كى\x04كي\x04لج\x04لح\x04لخ\x04لم\x04لى\x04لي\x04مج\x04مح\x04مخ\x04مم" +
+	"\x04مى\x04مي\x04نج\x04نح\x04نخ\x04نم\x04نى\x04ني\x04هج\x04هم\x04هى\x04هي" +
+	"\x04يج\x04يح\x04يخ\x04يم\x04يى\x04يي\x04ذٰ\x04رٰ\x04ىٰ\x05 ٌّ\x05 ٍّ\x05" +
+	" َّ\x05 ُّ\x05 ِّ\x05 ّٰ\x04ئر\x04ئز\x04ئن\x04بر\x04بز\x04بن\x04تر\x04تز" +
+	"\x04تن\x04ثر\x04ثز\x04ثن\x04ما\x04نر\x04نز\x04نن\x04ير\x04يز\x04ين\x04ئخ" +
+	"\x04ئه\x04به\x04ته\x04صخ\x04له\x04نه\x04هٰ\x04يه\x04ثه\x04سه\x04شم\x04شه" +
+	"\x06ـَّ\x06ـُّ\x06ـِّ\x04طى\x04طي\x04عى\x04عي\x04غى\x04غي\x04سى\x04سي" +
+	"\x04شى\x04شي\x04حى\x04حي\x04جى\x04جي\x04خى\x04خي\x04صى\x04صي\x04ضى\x04ضي" +
+	"\x04شج\x04شح\x04شخ\x04شر\x04سر\x04صر\x04ضر\x04اً\x06تجم\x06تحج\x06تحم" +
+	"\x06تخم\x06تمج\x06تمح\x06تمخ\x06جمح\x06حمي\x06حمى\x06سحج\x06سجح\x06سجى" +
+	"\x06سمح\x06سمج\x06سمم\x06صحح\x06صمم\x06شحم\x06شجي\x06شمخ\x06شمم\x06ضحى" +
+	"\x06ضخم\x06طمح\x06طمم\x06طمي\x06عجم\x06عمم\x06عمى\x06غمم\x06غمي\x06غمى" +
+	"\x06فخم\x06قمح\x06قمم\x06لحم\x06لحي\x06لحى\x06لجج\x06لخم\x06لمح\x06محج" +
+	"\x06محم\x06محي\x06مجح\x06مجم\x06مخج\x06مخم\x06مجخ\x06همج\x06همم\x06نحم" +
+	"\x06نحى\x06نجم\x06نجى\x06نمي\x06نمى\x06يمم\x06بخي\x06تجي\x06تجى\x06تخي" +
+	"\x06تخى\x06تمي\x06تمى\x06جمي\x06جحى\x06جمى\x06سخى\x06صحي\x06شحي\x06ضحي" +
+	"\x06لجي\x06لمي\x06يحي\x06يجي\x06يمي\x06ممي\x06قمي\x06نحي\x06عمي\x06كمي" +
+	"\x06نجح\x06مخي\x06لجم\x06كمم\x06جحي\x06حجي\x06مجي\x06فمي\x06بحي\x06سخي" +
+	"\x06نجي\x06صلے\x06قلے\x08الله\x08اكبر\x08محمد\x08صلعم\x08رسول\x08عليه" +
+	"\x08وسلم\x06صلى!صلى الله عليه وسلم\x0fجل جلاله\x08ریال\x01,\x01:\x01!" +
+	"\x01?\x01_\x01{\x01}\x01[\x01]\x01#\x01&\x01*\x01-\x01<\x01>\x01\\\x01$" +
+	"\x01%\x01@\x04ـً\x04ـَ\x04ـُ\x04ـِ\x04ـّ\x04ـْ\x02ء\x02آ\x02أ\x02ؤ\x02إ" +
+	"\x02ئ\x02ا\x02ب\x02ة\x02ت\x02ث\x02ج\x02ح\x02خ\x02د\x02ذ\x02ر\x02ز\x02س" +
+	"\x02ش\x02ص\x02ض\x02ط\x02ظ\x02ع\x02غ\x02ف\x02ق\x02ك\x02ل\x02م\x02ن\x02ه" +
+	"\x02و\x02ي\x04لآ\x04لأ\x04لإ\x04لا\x01\x22\x01'\x01/\x01^\x01|\x01~\x02¢" +
+	"\x02£\x02¬\x02¦\x02¥\x08𝅗𝅥\x08𝅘𝅥\x0c𝅘𝅥𝅮\x0c𝅘𝅥𝅯\x0c𝅘𝅥𝅰\x0c𝅘𝅥𝅱\x0c𝅘𝅥𝅲\x08𝆹" +
+	"𝅥\x08𝆺𝅥\x0c𝆹𝅥𝅮\x0c𝆺𝅥𝅮\x0c𝆹𝅥𝅯\x0c𝆺𝅥𝅯\x02ı\x02ȷ\x02α\x02ε\x02ζ\x02η\x02" +
+	"κ\x02λ\x02μ\x02ν\x02ξ\x02ο\x02σ\x02τ\x02υ\x02ψ\x03∇\x03∂\x02ϝ\x02ٮ\x02ڡ" +
+	"\x02ٯ\x020,\x021,\x022,\x023,\x024,\x025,\x026,\x027,\x028,\x029,\x03(a)" +
+	"\x03(b)\x03(c)\x03(d)\x03(e)\x03(f)\x03(g)\x03(h)\x03(i)\x03(j)\x03(k)" +
+	"\x03(l)\x03(m)\x03(n)\x03(o)\x03(p)\x03(q)\x03(r)\x03(s)\x03(t)\x03(u)" +
+	"\x03(v)\x03(w)\x03(x)\x03(y)\x03(z)\x07〔s〕\x02wz\x02hv\x02sd\x03ppv\x02w" +
+	"c\x02mc\x02md\x02dj\x06ほか\x06ココ\x03サ\x03手\x03字\x03双\x03デ\x03二\x03多\x03解" +
+	"\x03天\x03交\x03映\x03無\x03料\x03前\x03後\x03再\x03新\x03初\x03終\x03生\x03販\x03声" +
+	"\x03吹\x03演\x03投\x03捕\x03一\x03三\x03遊\x03左\x03中\x03右\x03指\x03走\x03打\x03禁" +
+	"\x03空\x03合\x03満\x03有\x03月\x03申\x03割\x03営\x03配\x09〔本〕\x09〔三〕\x09〔二〕\x09〔安" +
+	"〕\x09〔点〕\x09〔打〕\x09〔盗〕\x09〔勝〕\x09〔敗〕\x03得\x03可\x03丽\x03丸\x03乁\x03你\x03" +
+	"侮\x03侻\x03倂\x03偺\x03備\x03僧\x03像\x03㒞\x03免\x03兔\x03兤\x03具\x03㒹\x03內\x03" +
+	"冗\x03冤\x03仌\x03冬\x03况\x03凵\x03刃\x03㓟\x03刻\x03剆\x03剷\x03㔕\x03勇\x03勉\x03" +
+	"勤\x03勺\x03包\x03匆\x03北\x03卉\x03卑\x03博\x03即\x03卽\x03卿\x03灰\x03及\x03叟\x03" +
+	"叫\x03叱\x03吆\x03咞\x03吸\x03呈\x03周\x03咢\x03哶\x03唐\x03啓\x03啣\x03善\x03喙\x03" +
+	"喫\x03喳\x03嗂\x03圖\x03嘆\x03圗\x03噑\x03噴\x03切\x03壮\x03城\x03埴\x03堍\x03型\x03" +
+	"堲\x03報\x03墬\x03売\x03壷\x03夆\x03夢\x03奢\x03姬\x03娛\x03娧\x03姘\x03婦\x03㛮\x03" +
+	"嬈\x03嬾\x03寃\x03寘\x03寧\x03寳\x03寿\x03将\x03尢\x03㞁\x03屠\x03屮\x03峀\x03岍\x03" +
+	"嵃\x03嵮\x03嵫\x03嵼\x03巡\x03巢\x03㠯\x03巽\x03帨\x03帽\x03幩\x03㡢\x03㡼\x03庰\x03" +
+	"庳\x03庶\x03廊\x03廾\x03舁\x03弢\x03㣇\x03形\x03彫\x03㣣\x03徚\x03忍\x03志\x03忹\x03" +
+	"悁\x03㤺\x03㤜\x03悔\x03惇\x03慈\x03慌\x03慎\x03慺\x03憎\x03憲\x03憤\x03憯\x03懞\x03" +
+	"懲\x03懶\x03成\x03戛\x03扝\x03抱\x03拔\x03捐\x03挽\x03拼\x03捨\x03掃\x03揤\x03搢\x03" +
+	"揅\x03掩\x03㨮\x03摩\x03摾\x03撝\x03摷\x03㩬\x03敏\x03敬\x03旣\x03書\x03晉\x03㬙\x03" +
+	"暑\x03㬈\x03㫤\x03冒\x03冕\x03最\x03暜\x03肭\x03䏙\x03朗\x03望\x03朡\x03杞\x03杓\x03" +
+	"㭉\x03柺\x03枅\x03桒\x03梅\x03梎\x03栟\x03椔\x03㮝\x03楂\x03榣\x03槪\x03檨\x03櫛\x03" +
+	"㰘\x03次\x03歔\x03㱎\x03歲\x03殟\x03殺\x03殻\x03汎\x03沿\x03泍\x03汧\x03洖\x03派\x03" +
+	"海\x03流\x03浩\x03浸\x03涅\x03洴\x03港\x03湮\x03㴳\x03滋\x03滇\x03淹\x03潮\x03濆\x03" +
+	"瀹\x03瀞\x03瀛\x03㶖\x03灊\x03災\x03灷\x03炭\x03煅\x03熜\x03爨\x03爵\x03牐\x03犀\x03" +
+	"犕\x03獺\x03王\x03㺬\x03玥\x03㺸\x03瑇\x03瑜\x03瑱\x03璅\x03瓊\x03㼛\x03甤\x03甾\x03" +
+	"異\x03瘐\x03㿼\x03䀈\x03直\x03眞\x03真\x03睊\x03䀹\x03瞋\x03䁆\x03䂖\x03硎\x03碌\x03" +
+	"磌\x03䃣\x03祖\x03福\x03秫\x03䄯\x03穀\x03穊\x03穏\x03䈂\x03篆\x03築\x03䈧\x03糒\x03" +
+	"䊠\x03糨\x03糣\x03紀\x03絣\x03䌁\x03緇\x03縂\x03繅\x03䌴\x03䍙\x03罺\x03羕\x03翺\x03" +
+	"者\x03聠\x03聰\x03䏕\x03育\x03脃\x03䐋\x03脾\x03媵\x03舄\x03辞\x03䑫\x03芑\x03芋\x03" +
+	"芝\x03劳\x03花\x03芳\x03芽\x03苦\x03若\x03茝\x03荣\x03莭\x03茣\x03莽\x03菧\x03著\x03" +
+	"荓\x03菊\x03菌\x03菜\x03䔫\x03蓱\x03蓳\x03蔖\x03蕤\x03䕝\x03䕡\x03䕫\x03虐\x03虜\x03" +
+	"虧\x03虩\x03蚩\x03蚈\x03蜎\x03蛢\x03蝹\x03蜨\x03蝫\x03螆\x03蟡\x03蠁\x03䗹\x03衠\x03" +
+	"衣\x03裗\x03裞\x03䘵\x03裺\x03㒻\x03䚾\x03䛇\x03誠\x03諭\x03變\x03豕\x03貫\x03賁\x03" +
+	"贛\x03起\x03跋\x03趼\x03跰\x03軔\x03輸\x03邔\x03郱\x03鄑\x03鄛\x03鈸\x03鋗\x03鋘\x03" +
+	"鉼\x03鏹\x03鐕\x03開\x03䦕\x03閷\x03䧦\x03雃\x03嶲\x03霣\x03䩮\x03䩶\x03韠\x03䪲\x03" +
+	"頋\x03頩\x03飢\x03䬳\x03餩\x03馧\x03駂\x03駾\x03䯎\x03鬒\x03鱀\x03鳽\x03䳎\x03䳭\x03" +
+	"鵧\x03䳸\x03麻\x03䵖\x03黹\x03黾\x03鼅\x03鼏\x03鼖\x03鼻"
+
+var xorData string = "" + // Size: 4855 bytes
+	"\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" +
+	"\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" +
+	"\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" +
+	"\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" +
+	"\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" +
+	"\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" +
+	"\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" +
+	"\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" +
+	"\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" +
+	"\x03\x037 \x03\x0b+\x03\x02\x01\x04\x02\x01\x02\x02\x019\x02\x03\x1c\x02" +
+	"\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03\xc1r\x02" +
+	"\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<\x03\xc1s*" +
+	"\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03\x83\xab" +
+	"\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96\xe1\xcd" +
+	"\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03\x9a\xec" +
+	"\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c!\x03" +
+	"\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03ʦ\x93" +
+	"\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7\x03" +
+	"\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca\xfa" +
+	"\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e\x03" +
+	"\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca\xe3" +
+	"\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99\x03" +
+	"\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca\xe8" +
+	"\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03\x0b" +
+	"\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06\x05" +
+	"\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03\x0786" +
+	"\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/\x03" +
+	"\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f\x03" +
+	"\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-\x03" +
+	"\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03\x07" +
+	"\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03\x07" +
+	"\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03\x07" +
+	"\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b\x0a" +
+	"\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03\x07" +
+	"\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+\x03" +
+	"\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03\x04" +
+	"4\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03\x04+ " +
+	"\x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!\x22" +
+	"\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04\x03" +
+	"\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>\x03" +
+	"\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03\x054" +
+	"\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03\x05)" +
+	":\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$\x1e" +
+	"\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226\x03" +
+	"\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05\x1b" +
+	"\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05\x03" +
+	"\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03\x06" +
+	"\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08\x03" +
+	"\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03\x0a6" +
+	"\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a\x1f" +
+	"\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03\x0a" +
+	"\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f\x02" +
+	"\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/\x03" +
+	"\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a\x00" +
+	"\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+\x10" +
+	"\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#<" +
+	"\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!\x00" +
+	"\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18.\x03" +
+	"\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15\x22" +
+	"\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b\x12" +
+	"\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05<" +
+	"\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" +
+	"\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" +
+	"\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" +
+	"\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" +
+	"\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" +
+	"\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" +
+	"\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" +
+	"\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" +
+	"\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" +
+	"\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" +
+	"\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" +
+	"\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" +
+	"\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" +
+	"\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" +
+	"\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" +
+	"\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" +
+	"\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" +
+	"\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" +
+	"\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" +
+	"\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" +
+	"\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" +
+	"\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" +
+	"\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" +
+	"\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" +
+	"\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" +
+	"\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" +
+	"\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" +
+	"\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," +
+	"\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" +
+	"\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" +
+	"\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" +
+	"\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" +
+	",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" +
+	"\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" +
+	"\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" +
+	"\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" +
+	"\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" +
+	"\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" +
+	"\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" +
+	"\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" +
+	"\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" +
+	"\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" +
+	"\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" +
+	"\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" +
+	"(\x04\x023 \x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!\x10\x03\x0b!0" +
+	"\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b\x03\x09\x1f" +
+	"\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14\x03\x0a\x01" +
+	"\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03\x08='\x03" +
+	"\x08\x1a\x0a\x03\x07</\x03\x07:+\x03\x07\x07*\x03\x06&\x1c\x03\x09\x0c" +
+	"\x16\x03\x09\x10\x0e\x03\x08'\x0f\x03\x08+\x09\x03\x074%\x03\x06!3\x03" +
+	"\x06\x03+\x03\x0b\x1e\x19\x03\x0a))\x03\x09\x08\x19\x03\x08,\x05\x03\x07" +
+	"<2\x03\x06\x1c>\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07\x01\x00" +
+	"\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03\x09\x11" +
+	"\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03\x0a/1" +
+	"\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03\x07<3" +
+	"\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06\x13\x00" +
+	"\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(;\x03" +
+	"\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08\x14$" +
+	"\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03\x0a" +
+	"\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19\x01" +
+	"\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18\x03" +
+	"\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03\x07" +
+	"\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03\x0a" +
+	"\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03\x0b" +
+	"\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03\x08" +
+	"\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05\x03" +
+	"\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11\x03" +
+	"\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03\x09" +
+	"\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a." +
+	"\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" +
+	"\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" +
+	"\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " +
+	"\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" +
+	"\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" +
+	"\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" +
+	"\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" +
+	"\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" +
+	"\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" +
+	"\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," +
+	"\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" +
+	"\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" +
+	"\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" +
+	"\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" +
+	"\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" +
+	"\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" +
+	"\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" +
+	"\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" +
+	"/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" +
+	"\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" +
+	"\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" +
+	"\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" +
+	"\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" +
+	"\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" +
+	"\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" +
+	"\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" +
+	"\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" +
+	"\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" +
+	"\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" +
+	"\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" +
+	"\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" +
+	"\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" +
+	"\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" +
+	"\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" +
+	"\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" +
+	"\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" +
+	"\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" +
+	"\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" +
+	"#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" +
+	"\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" +
+	"\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" +
+	"\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" +
+	"\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" +
+	"\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" +
+	"\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" +
+	"\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" +
+	"\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" +
+	"\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" +
+	"\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," +
+	"\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" +
+	"\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" +
+	"\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" +
+	"\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" +
+	"\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" +
+	"\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" +
+	"\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" +
+	"\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" +
+	"\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" +
+	"\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" +
+	"\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" +
+	"\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" +
+	"\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" +
+	"\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" +
+	"\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" +
+	"\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" +
+	"\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" +
+	"\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" +
+	"\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" +
+	"\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" +
+	"\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" +
+	"\x04\x03\x0c?\x05\x03\x0c<?\x03\x0c=\x00\x03\x0c=\x06\x03\x0c=\x05\x03" +
+	"\x0c=\x0c\x03\x0c=\x0f\x03\x0c=\x0d\x03\x0c=\x0b\x03\x0c=\x07\x03\x0c=" +
+	"\x19\x03\x0c=\x15\x03\x0c=\x11\x03\x0c=1\x03\x0c=3\x03\x0c=0\x03\x0c=>" +
+	"\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" +
+	"\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" +
+	"\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" +
+	"\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" +
+	"\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" +
+	"?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x01\x1e\x03\x0f$!\x03" +
+	"\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08\x18\x03\x0f" +
+	"\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$\x03\x0e\x0d)" +
+	"\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d\x03\x0d. \x03" +
+	"\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03\x0d\x0d\x0f\x03" +
+	"\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03\x0c\x09:\x03\x0e" +
+	"\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18\x03\x0c\x1f\x1c" +
+	"\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03\x0b<+\x03\x0b8" +
+	"\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d\x22&\x03\x0b\x1a" +
+	"\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03\x0a!\x1a\x03\x0a!" +
+	"7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03\x0a\x00 \x03\x0a" +
+	"\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a\x1b-\x03\x09-" +
+	"\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091\x1f\x03\x093" +
+	"\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(\x16\x03\x09" +
+	"\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!\x03\x09\x1a" +
+	"\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03\x08\x02*" +
+	"\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03\x070\x0c" +
+	"\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x0671\x03" +
+	"\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 \x1d\x03" +
+	"\x05\x22\x05\x03\x050\x1d"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return idnaValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = idnaIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = idnaIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = idnaIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *idnaTrie) lookupUnsafe(s []byte) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return idnaValues[c0]
+	}
+	i := idnaIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = idnaIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = idnaIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *idnaTrie) lookupString(s string) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return idnaValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = idnaIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := idnaIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = idnaIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = idnaIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *idnaTrie) lookupStringUnsafe(s string) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return idnaValues[c0]
+	}
+	i := idnaIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = idnaIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = idnaIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// idnaTrie. Total size: 28496 bytes (27.83 KiB). Checksum: 43288b883596640e.
+type idnaTrie struct{}
+
+func newIdnaTrie(i int) *idnaTrie {
+	return &idnaTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 {
+	switch {
+	case n < 123:
+		return uint16(idnaValues[n<<6+uint32(b)])
+	default:
+		n -= 123
+		return uint16(idnaSparse.lookup(n, b))
+	}
+}
+
+// idnaValues: 125 blocks, 8000 entries, 16000 bytes
+// The third block is the zero block.
+var idnaValues = [8000]uint16{
+	// Block 0x0, offset 0x0
+	0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080,
+	0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080,
+	0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080,
+	0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080,
+	0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080,
+	0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080,
+	0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080,
+	0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080,
+	0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008,
+	0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080,
+	0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080,
+	// Block 0x1, offset 0x40
+	0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105,
+	0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105,
+	0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105,
+	0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105,
+	0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080,
+	0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008,
+	0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008,
+	0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008,
+	0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008,
+	0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080,
+	0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040,
+	0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040,
+	0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040,
+	0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040,
+	0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040,
+	0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018,
+	0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x001a, 0xe9: 0x0018,
+	0xea: 0x0039, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x004a,
+	0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0069, 0xf3: 0x0079, 0xf4: 0x008a, 0xf5: 0x0005,
+	0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x00aa, 0xf9: 0x00c9, 0xfa: 0x00d9, 0xfb: 0x0018,
+	0xfc: 0x00e9, 0xfd: 0x0119, 0xfe: 0x0149, 0xff: 0x0018,
+	// Block 0x4, offset 0x100
+	0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008,
+	0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008,
+	0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008,
+	0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008,
+	0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008,
+	0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008,
+	0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008,
+	0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008,
+	0x130: 0x0179, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008,
+	0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d,
+	0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0199,
+	// Block 0x5, offset 0x140
+	0x140: 0x0199, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d,
+	0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x01b9, 0x14a: 0xe00d, 0x14b: 0x0008,
+	0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008,
+	0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008,
+	0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008,
+	0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008,
+	0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008,
+	0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008,
+	0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008,
+	0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d,
+	0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x01d9,
+	// Block 0x6, offset 0x180
+	0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008,
+	0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d,
+	0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d,
+	0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d,
+	0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155,
+	0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008,
+	0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d,
+	0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd,
+	0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d,
+	0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008,
+	0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x01e9, 0x1c5: 0x01e9,
+	0x1c6: 0x01e9, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d,
+	0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d,
+	0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d,
+	0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008,
+	0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008,
+	0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008,
+	0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008,
+	0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008,
+	0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008,
+	0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008,
+	// Block 0x8, offset 0x200
+	0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008,
+	0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008,
+	0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008,
+	0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008,
+	0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008,
+	0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008,
+	0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008,
+	0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008,
+	0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008,
+	0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0209, 0x23b: 0xe03d,
+	0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x0229, 0x23f: 0x0008,
+	// Block 0x9, offset 0x240
+	0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018,
+	0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008,
+	0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008,
+	0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018,
+	0x258: 0x029a, 0x259: 0x02ba, 0x25a: 0x02da, 0x25b: 0x02fa, 0x25c: 0x031a, 0x25d: 0x033a,
+	0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0359, 0x262: 0x01d9, 0x263: 0x0369,
+	0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018,
+	0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018,
+	0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018,
+	0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018,
+	0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018,
+	// Block 0xa, offset 0x280
+	0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x1308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d,
+	0x286: 0x1308, 0x287: 0x1308, 0x288: 0x1308, 0x289: 0x1308, 0x28a: 0x1308, 0x28b: 0x1308,
+	0x28c: 0x1308, 0x28d: 0x1308, 0x28e: 0x1308, 0x28f: 0x13c0, 0x290: 0x1308, 0x291: 0x1308,
+	0x292: 0x1308, 0x293: 0x1308, 0x294: 0x1308, 0x295: 0x1308, 0x296: 0x1308, 0x297: 0x1308,
+	0x298: 0x1308, 0x299: 0x1308, 0x29a: 0x1308, 0x29b: 0x1308, 0x29c: 0x1308, 0x29d: 0x1308,
+	0x29e: 0x1308, 0x29f: 0x1308, 0x2a0: 0x1308, 0x2a1: 0x1308, 0x2a2: 0x1308, 0x2a3: 0x1308,
+	0x2a4: 0x1308, 0x2a5: 0x1308, 0x2a6: 0x1308, 0x2a7: 0x1308, 0x2a8: 0x1308, 0x2a9: 0x1308,
+	0x2aa: 0x1308, 0x2ab: 0x1308, 0x2ac: 0x1308, 0x2ad: 0x1308, 0x2ae: 0x1308, 0x2af: 0x1308,
+	0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008,
+	0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008,
+	0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x008a, 0x2c5: 0x03d2,
+	0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040,
+	0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105,
+	0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105,
+	0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105,
+	0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d,
+	0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d,
+	0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008,
+	0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008,
+	0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008,
+	0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008,
+	// Block 0xc, offset 0x300
+	0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008,
+	0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008,
+	0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd,
+	0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008,
+	0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008,
+	0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008,
+	0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008,
+	0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008,
+	0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd,
+	0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008,
+	0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d,
+	// Block 0xd, offset 0x340
+	0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008,
+	0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008,
+	0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008,
+	0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008,
+	0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008,
+	0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008,
+	0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008,
+	0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008,
+	0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008,
+	0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008,
+	0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008,
+	// Block 0xe, offset 0x380
+	0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x1308, 0x384: 0x1308, 0x385: 0x1308,
+	0x386: 0x1308, 0x387: 0x1308, 0x388: 0x1318, 0x389: 0x1318, 0x38a: 0xe00d, 0x38b: 0x0008,
+	0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008,
+	0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008,
+	0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008,
+	0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008,
+	0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008,
+	0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008,
+	0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008,
+	0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008,
+	0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d,
+	0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d,
+	0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008,
+	0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008,
+	0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008,
+	0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008,
+	0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008,
+	0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008,
+	0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008,
+	0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008,
+	0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008,
+	// Block 0x10, offset 0x400
+	0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008,
+	0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008,
+	0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008,
+	0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008,
+	0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008,
+	0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008,
+	0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008,
+	0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008,
+	0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5,
+	0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5,
+	0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5,
+	// Block 0x11, offset 0x440
+	0x440: 0x0040, 0x441: 0x0040, 0x442: 0x0040, 0x443: 0x0040, 0x444: 0x0040, 0x445: 0x0040,
+	0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0018, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0018,
+	0x44c: 0x0018, 0x44d: 0x0018, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x1308, 0x451: 0x1308,
+	0x452: 0x1308, 0x453: 0x1308, 0x454: 0x1308, 0x455: 0x1308, 0x456: 0x1308, 0x457: 0x1308,
+	0x458: 0x1308, 0x459: 0x1308, 0x45a: 0x1308, 0x45b: 0x0018, 0x45c: 0x0340, 0x45d: 0x0040,
+	0x45e: 0x0018, 0x45f: 0x0018, 0x460: 0x0208, 0x461: 0x0008, 0x462: 0x0408, 0x463: 0x0408,
+	0x464: 0x0408, 0x465: 0x0408, 0x466: 0x0208, 0x467: 0x0408, 0x468: 0x0208, 0x469: 0x0408,
+	0x46a: 0x0208, 0x46b: 0x0208, 0x46c: 0x0208, 0x46d: 0x0208, 0x46e: 0x0208, 0x46f: 0x0408,
+	0x470: 0x0408, 0x471: 0x0408, 0x472: 0x0408, 0x473: 0x0208, 0x474: 0x0208, 0x475: 0x0208,
+	0x476: 0x0208, 0x477: 0x0208, 0x478: 0x0208, 0x479: 0x0208, 0x47a: 0x0208, 0x47b: 0x0208,
+	0x47c: 0x0208, 0x47d: 0x0208, 0x47e: 0x0208, 0x47f: 0x0208,
+	// Block 0x12, offset 0x480
+	0x480: 0x0408, 0x481: 0x0208, 0x482: 0x0208, 0x483: 0x0408, 0x484: 0x0408, 0x485: 0x0408,
+	0x486: 0x0408, 0x487: 0x0408, 0x488: 0x0408, 0x489: 0x0408, 0x48a: 0x0408, 0x48b: 0x0408,
+	0x48c: 0x0208, 0x48d: 0x0408, 0x48e: 0x0208, 0x48f: 0x0408, 0x490: 0x0208, 0x491: 0x0208,
+	0x492: 0x0408, 0x493: 0x0408, 0x494: 0x0018, 0x495: 0x0408, 0x496: 0x1308, 0x497: 0x1308,
+	0x498: 0x1308, 0x499: 0x1308, 0x49a: 0x1308, 0x49b: 0x1308, 0x49c: 0x1308, 0x49d: 0x0040,
+	0x49e: 0x0018, 0x49f: 0x1308, 0x4a0: 0x1308, 0x4a1: 0x1308, 0x4a2: 0x1308, 0x4a3: 0x1308,
+	0x4a4: 0x1308, 0x4a5: 0x0008, 0x4a6: 0x0008, 0x4a7: 0x1308, 0x4a8: 0x1308, 0x4a9: 0x0018,
+	0x4aa: 0x1308, 0x4ab: 0x1308, 0x4ac: 0x1308, 0x4ad: 0x1308, 0x4ae: 0x0408, 0x4af: 0x0408,
+	0x4b0: 0x0008, 0x4b1: 0x0008, 0x4b2: 0x0008, 0x4b3: 0x0008, 0x4b4: 0x0008, 0x4b5: 0x0008,
+	0x4b6: 0x0008, 0x4b7: 0x0008, 0x4b8: 0x0008, 0x4b9: 0x0008, 0x4ba: 0x0208, 0x4bb: 0x0208,
+	0x4bc: 0x0208, 0x4bd: 0x0008, 0x4be: 0x0008, 0x4bf: 0x0208,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x0018, 0x4c1: 0x0018, 0x4c2: 0x0018, 0x4c3: 0x0018, 0x4c4: 0x0018, 0x4c5: 0x0018,
+	0x4c6: 0x0018, 0x4c7: 0x0018, 0x4c8: 0x0018, 0x4c9: 0x0018, 0x4ca: 0x0018, 0x4cb: 0x0018,
+	0x4cc: 0x0018, 0x4cd: 0x0018, 0x4ce: 0x0040, 0x4cf: 0x0340, 0x4d0: 0x0408, 0x4d1: 0x1308,
+	0x4d2: 0x0208, 0x4d3: 0x0208, 0x4d4: 0x0208, 0x4d5: 0x0408, 0x4d6: 0x0408, 0x4d7: 0x0408,
+	0x4d8: 0x0408, 0x4d9: 0x0408, 0x4da: 0x0208, 0x4db: 0x0208, 0x4dc: 0x0208, 0x4dd: 0x0208,
+	0x4de: 0x0408, 0x4df: 0x0208, 0x4e0: 0x0208, 0x4e1: 0x0208, 0x4e2: 0x0208, 0x4e3: 0x0208,
+	0x4e4: 0x0208, 0x4e5: 0x0208, 0x4e6: 0x0208, 0x4e7: 0x0208, 0x4e8: 0x0408, 0x4e9: 0x0208,
+	0x4ea: 0x0408, 0x4eb: 0x0208, 0x4ec: 0x0408, 0x4ed: 0x0208, 0x4ee: 0x0208, 0x4ef: 0x0408,
+	0x4f0: 0x1308, 0x4f1: 0x1308, 0x4f2: 0x1308, 0x4f3: 0x1308, 0x4f4: 0x1308, 0x4f5: 0x1308,
+	0x4f6: 0x1308, 0x4f7: 0x1308, 0x4f8: 0x1308, 0x4f9: 0x1308, 0x4fa: 0x1308, 0x4fb: 0x1308,
+	0x4fc: 0x1308, 0x4fd: 0x1308, 0x4fe: 0x1308, 0x4ff: 0x1308,
+	// Block 0x14, offset 0x500
+	0x500: 0x1008, 0x501: 0x1308, 0x502: 0x1308, 0x503: 0x1308, 0x504: 0x1308, 0x505: 0x1308,
+	0x506: 0x1308, 0x507: 0x1308, 0x508: 0x1308, 0x509: 0x1008, 0x50a: 0x1008, 0x50b: 0x1008,
+	0x50c: 0x1008, 0x50d: 0x1b08, 0x50e: 0x1008, 0x50f: 0x1008, 0x510: 0x0008, 0x511: 0x1308,
+	0x512: 0x1308, 0x513: 0x1308, 0x514: 0x1308, 0x515: 0x1308, 0x516: 0x1308, 0x517: 0x1308,
+	0x518: 0x04c9, 0x519: 0x0501, 0x51a: 0x0539, 0x51b: 0x0571, 0x51c: 0x05a9, 0x51d: 0x05e1,
+	0x51e: 0x0619, 0x51f: 0x0651, 0x520: 0x0008, 0x521: 0x0008, 0x522: 0x1308, 0x523: 0x1308,
+	0x524: 0x0018, 0x525: 0x0018, 0x526: 0x0008, 0x527: 0x0008, 0x528: 0x0008, 0x529: 0x0008,
+	0x52a: 0x0008, 0x52b: 0x0008, 0x52c: 0x0008, 0x52d: 0x0008, 0x52e: 0x0008, 0x52f: 0x0008,
+	0x530: 0x0018, 0x531: 0x0008, 0x532: 0x0008, 0x533: 0x0008, 0x534: 0x0008, 0x535: 0x0008,
+	0x536: 0x0008, 0x537: 0x0008, 0x538: 0x0008, 0x539: 0x0008, 0x53a: 0x0008, 0x53b: 0x0008,
+	0x53c: 0x0008, 0x53d: 0x0008, 0x53e: 0x0008, 0x53f: 0x0008,
+	// Block 0x15, offset 0x540
+	0x540: 0x0008, 0x541: 0x1308, 0x542: 0x1008, 0x543: 0x1008, 0x544: 0x0040, 0x545: 0x0008,
+	0x546: 0x0008, 0x547: 0x0008, 0x548: 0x0008, 0x549: 0x0008, 0x54a: 0x0008, 0x54b: 0x0008,
+	0x54c: 0x0008, 0x54d: 0x0040, 0x54e: 0x0040, 0x54f: 0x0008, 0x550: 0x0008, 0x551: 0x0040,
+	0x552: 0x0040, 0x553: 0x0008, 0x554: 0x0008, 0x555: 0x0008, 0x556: 0x0008, 0x557: 0x0008,
+	0x558: 0x0008, 0x559: 0x0008, 0x55a: 0x0008, 0x55b: 0x0008, 0x55c: 0x0008, 0x55d: 0x0008,
+	0x55e: 0x0008, 0x55f: 0x0008, 0x560: 0x0008, 0x561: 0x0008, 0x562: 0x0008, 0x563: 0x0008,
+	0x564: 0x0008, 0x565: 0x0008, 0x566: 0x0008, 0x567: 0x0008, 0x568: 0x0008, 0x569: 0x0040,
+	0x56a: 0x0008, 0x56b: 0x0008, 0x56c: 0x0008, 0x56d: 0x0008, 0x56e: 0x0008, 0x56f: 0x0008,
+	0x570: 0x0008, 0x571: 0x0040, 0x572: 0x0008, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040,
+	0x576: 0x0008, 0x577: 0x0008, 0x578: 0x0008, 0x579: 0x0008, 0x57a: 0x0040, 0x57b: 0x0040,
+	0x57c: 0x1308, 0x57d: 0x0008, 0x57e: 0x1008, 0x57f: 0x1008,
+	// Block 0x16, offset 0x580
+	0x580: 0x1008, 0x581: 0x1308, 0x582: 0x1308, 0x583: 0x1308, 0x584: 0x1308, 0x585: 0x0040,
+	0x586: 0x0040, 0x587: 0x1008, 0x588: 0x1008, 0x589: 0x0040, 0x58a: 0x0040, 0x58b: 0x1008,
+	0x58c: 0x1008, 0x58d: 0x1b08, 0x58e: 0x0008, 0x58f: 0x0040, 0x590: 0x0040, 0x591: 0x0040,
+	0x592: 0x0040, 0x593: 0x0040, 0x594: 0x0040, 0x595: 0x0040, 0x596: 0x0040, 0x597: 0x1008,
+	0x598: 0x0040, 0x599: 0x0040, 0x59a: 0x0040, 0x59b: 0x0040, 0x59c: 0x0689, 0x59d: 0x06c1,
+	0x59e: 0x0040, 0x59f: 0x06f9, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x1308, 0x5a3: 0x1308,
+	0x5a4: 0x0040, 0x5a5: 0x0040, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008,
+	0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008,
+	0x5b0: 0x0008, 0x5b1: 0x0008, 0x5b2: 0x0018, 0x5b3: 0x0018, 0x5b4: 0x0018, 0x5b5: 0x0018,
+	0x5b6: 0x0018, 0x5b7: 0x0018, 0x5b8: 0x0018, 0x5b9: 0x0018, 0x5ba: 0x0018, 0x5bb: 0x0018,
+	0x5bc: 0x0040, 0x5bd: 0x0040, 0x5be: 0x0040, 0x5bf: 0x0040,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x0040, 0x5c1: 0x1308, 0x5c2: 0x1308, 0x5c3: 0x1008, 0x5c4: 0x0040, 0x5c5: 0x0008,
+	0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0040,
+	0x5cc: 0x0040, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040,
+	0x5d2: 0x0040, 0x5d3: 0x0008, 0x5d4: 0x0008, 0x5d5: 0x0008, 0x5d6: 0x0008, 0x5d7: 0x0008,
+	0x5d8: 0x0008, 0x5d9: 0x0008, 0x5da: 0x0008, 0x5db: 0x0008, 0x5dc: 0x0008, 0x5dd: 0x0008,
+	0x5de: 0x0008, 0x5df: 0x0008, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x0008, 0x5e3: 0x0008,
+	0x5e4: 0x0008, 0x5e5: 0x0008, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0040,
+	0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008,
+	0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0731, 0x5f4: 0x0040, 0x5f5: 0x0008,
+	0x5f6: 0x0769, 0x5f7: 0x0040, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040,
+	0x5fc: 0x1308, 0x5fd: 0x0040, 0x5fe: 0x1008, 0x5ff: 0x1008,
+	// Block 0x18, offset 0x600
+	0x600: 0x1008, 0x601: 0x1308, 0x602: 0x1308, 0x603: 0x0040, 0x604: 0x0040, 0x605: 0x0040,
+	0x606: 0x0040, 0x607: 0x1308, 0x608: 0x1308, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x1308,
+	0x60c: 0x1308, 0x60d: 0x1b08, 0x60e: 0x0040, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x1308,
+	0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x0040,
+	0x618: 0x0040, 0x619: 0x07a1, 0x61a: 0x07d9, 0x61b: 0x0811, 0x61c: 0x0008, 0x61d: 0x0040,
+	0x61e: 0x0849, 0x61f: 0x0040, 0x620: 0x0040, 0x621: 0x0040, 0x622: 0x0040, 0x623: 0x0040,
+	0x624: 0x0040, 0x625: 0x0040, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0008,
+	0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008,
+	0x630: 0x1308, 0x631: 0x1308, 0x632: 0x0008, 0x633: 0x0008, 0x634: 0x0008, 0x635: 0x1308,
+	0x636: 0x0040, 0x637: 0x0040, 0x638: 0x0040, 0x639: 0x0040, 0x63a: 0x0040, 0x63b: 0x0040,
+	0x63c: 0x0040, 0x63d: 0x0040, 0x63e: 0x0040, 0x63f: 0x0040,
+	// Block 0x19, offset 0x640
+	0x640: 0x0040, 0x641: 0x1308, 0x642: 0x1308, 0x643: 0x1008, 0x644: 0x0040, 0x645: 0x0008,
+	0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0008,
+	0x64c: 0x0008, 0x64d: 0x0008, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0008,
+	0x652: 0x0040, 0x653: 0x0008, 0x654: 0x0008, 0x655: 0x0008, 0x656: 0x0008, 0x657: 0x0008,
+	0x658: 0x0008, 0x659: 0x0008, 0x65a: 0x0008, 0x65b: 0x0008, 0x65c: 0x0008, 0x65d: 0x0008,
+	0x65e: 0x0008, 0x65f: 0x0008, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x0008, 0x663: 0x0008,
+	0x664: 0x0008, 0x665: 0x0008, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0040,
+	0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008,
+	0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0008, 0x674: 0x0040, 0x675: 0x0008,
+	0x676: 0x0008, 0x677: 0x0008, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040,
+	0x67c: 0x1308, 0x67d: 0x0008, 0x67e: 0x1008, 0x67f: 0x1008,
+	// Block 0x1a, offset 0x680
+	0x680: 0x1008, 0x681: 0x1308, 0x682: 0x1308, 0x683: 0x1308, 0x684: 0x1308, 0x685: 0x1308,
+	0x686: 0x0040, 0x687: 0x1308, 0x688: 0x1308, 0x689: 0x1008, 0x68a: 0x0040, 0x68b: 0x1008,
+	0x68c: 0x1008, 0x68d: 0x1b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0008, 0x691: 0x0040,
+	0x692: 0x0040, 0x693: 0x0040, 0x694: 0x0040, 0x695: 0x0040, 0x696: 0x0040, 0x697: 0x0040,
+	0x698: 0x0040, 0x699: 0x0040, 0x69a: 0x0040, 0x69b: 0x0040, 0x69c: 0x0040, 0x69d: 0x0040,
+	0x69e: 0x0040, 0x69f: 0x0040, 0x6a0: 0x0008, 0x6a1: 0x0008, 0x6a2: 0x1308, 0x6a3: 0x1308,
+	0x6a4: 0x0040, 0x6a5: 0x0040, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0008,
+	0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008,
+	0x6b0: 0x0018, 0x6b1: 0x0018, 0x6b2: 0x0040, 0x6b3: 0x0040, 0x6b4: 0x0040, 0x6b5: 0x0040,
+	0x6b6: 0x0040, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0008, 0x6ba: 0x0040, 0x6bb: 0x0040,
+	0x6bc: 0x0040, 0x6bd: 0x0040, 0x6be: 0x0040, 0x6bf: 0x0040,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x0040, 0x6c1: 0x1308, 0x6c2: 0x1008, 0x6c3: 0x1008, 0x6c4: 0x0040, 0x6c5: 0x0008,
+	0x6c6: 0x0008, 0x6c7: 0x0008, 0x6c8: 0x0008, 0x6c9: 0x0008, 0x6ca: 0x0008, 0x6cb: 0x0008,
+	0x6cc: 0x0008, 0x6cd: 0x0040, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0040,
+	0x6d2: 0x0040, 0x6d3: 0x0008, 0x6d4: 0x0008, 0x6d5: 0x0008, 0x6d6: 0x0008, 0x6d7: 0x0008,
+	0x6d8: 0x0008, 0x6d9: 0x0008, 0x6da: 0x0008, 0x6db: 0x0008, 0x6dc: 0x0008, 0x6dd: 0x0008,
+	0x6de: 0x0008, 0x6df: 0x0008, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x0008, 0x6e3: 0x0008,
+	0x6e4: 0x0008, 0x6e5: 0x0008, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0040,
+	0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008,
+	0x6f0: 0x0008, 0x6f1: 0x0040, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0040, 0x6f5: 0x0008,
+	0x6f6: 0x0008, 0x6f7: 0x0008, 0x6f8: 0x0008, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040,
+	0x6fc: 0x1308, 0x6fd: 0x0008, 0x6fe: 0x1008, 0x6ff: 0x1308,
+	// Block 0x1c, offset 0x700
+	0x700: 0x1008, 0x701: 0x1308, 0x702: 0x1308, 0x703: 0x1308, 0x704: 0x1308, 0x705: 0x0040,
+	0x706: 0x0040, 0x707: 0x1008, 0x708: 0x1008, 0x709: 0x0040, 0x70a: 0x0040, 0x70b: 0x1008,
+	0x70c: 0x1008, 0x70d: 0x1b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0040, 0x711: 0x0040,
+	0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x1308, 0x717: 0x1008,
+	0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0881, 0x71d: 0x08b9,
+	0x71e: 0x0040, 0x71f: 0x0008, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x1308, 0x723: 0x1308,
+	0x724: 0x0040, 0x725: 0x0040, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0008,
+	0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008,
+	0x730: 0x0018, 0x731: 0x0008, 0x732: 0x0018, 0x733: 0x0018, 0x734: 0x0018, 0x735: 0x0018,
+	0x736: 0x0018, 0x737: 0x0018, 0x738: 0x0040, 0x739: 0x0040, 0x73a: 0x0040, 0x73b: 0x0040,
+	0x73c: 0x0040, 0x73d: 0x0040, 0x73e: 0x0040, 0x73f: 0x0040,
+	// Block 0x1d, offset 0x740
+	0x740: 0x0040, 0x741: 0x0040, 0x742: 0x1308, 0x743: 0x0008, 0x744: 0x0040, 0x745: 0x0008,
+	0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0040,
+	0x74c: 0x0040, 0x74d: 0x0040, 0x74e: 0x0008, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040,
+	0x752: 0x0008, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0040, 0x757: 0x0040,
+	0x758: 0x0040, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0040, 0x75c: 0x0008, 0x75d: 0x0040,
+	0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0040, 0x761: 0x0040, 0x762: 0x0040, 0x763: 0x0008,
+	0x764: 0x0008, 0x765: 0x0040, 0x766: 0x0040, 0x767: 0x0040, 0x768: 0x0008, 0x769: 0x0008,
+	0x76a: 0x0008, 0x76b: 0x0040, 0x76c: 0x0040, 0x76d: 0x0040, 0x76e: 0x0008, 0x76f: 0x0008,
+	0x770: 0x0008, 0x771: 0x0008, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0008, 0x775: 0x0008,
+	0x776: 0x0008, 0x777: 0x0008, 0x778: 0x0008, 0x779: 0x0008, 0x77a: 0x0040, 0x77b: 0x0040,
+	0x77c: 0x0040, 0x77d: 0x0040, 0x77e: 0x1008, 0x77f: 0x1008,
+	// Block 0x1e, offset 0x780
+	0x780: 0x1308, 0x781: 0x1008, 0x782: 0x1008, 0x783: 0x1008, 0x784: 0x1008, 0x785: 0x0040,
+	0x786: 0x1308, 0x787: 0x1308, 0x788: 0x1308, 0x789: 0x0040, 0x78a: 0x1308, 0x78b: 0x1308,
+	0x78c: 0x1308, 0x78d: 0x1b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040,
+	0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x1308, 0x796: 0x1308, 0x797: 0x0040,
+	0x798: 0x0008, 0x799: 0x0008, 0x79a: 0x0008, 0x79b: 0x0040, 0x79c: 0x0040, 0x79d: 0x0040,
+	0x79e: 0x0040, 0x79f: 0x0040, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x1308, 0x7a3: 0x1308,
+	0x7a4: 0x0040, 0x7a5: 0x0040, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0008,
+	0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008,
+	0x7b0: 0x0040, 0x7b1: 0x0040, 0x7b2: 0x0040, 0x7b3: 0x0040, 0x7b4: 0x0040, 0x7b5: 0x0040,
+	0x7b6: 0x0040, 0x7b7: 0x0040, 0x7b8: 0x0018, 0x7b9: 0x0018, 0x7ba: 0x0018, 0x7bb: 0x0018,
+	0x7bc: 0x0018, 0x7bd: 0x0018, 0x7be: 0x0018, 0x7bf: 0x0018,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x0008, 0x7c1: 0x1308, 0x7c2: 0x1008, 0x7c3: 0x1008, 0x7c4: 0x0040, 0x7c5: 0x0008,
+	0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0008,
+	0x7cc: 0x0008, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040,
+	0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0008, 0x7d7: 0x0008,
+	0x7d8: 0x0008, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0008, 0x7dc: 0x0008, 0x7dd: 0x0008,
+	0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0008, 0x7e1: 0x0008, 0x7e2: 0x0008, 0x7e3: 0x0008,
+	0x7e4: 0x0008, 0x7e5: 0x0008, 0x7e6: 0x0008, 0x7e7: 0x0008, 0x7e8: 0x0008, 0x7e9: 0x0040,
+	0x7ea: 0x0008, 0x7eb: 0x0008, 0x7ec: 0x0008, 0x7ed: 0x0008, 0x7ee: 0x0008, 0x7ef: 0x0008,
+	0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0040, 0x7f5: 0x0008,
+	0x7f6: 0x0008, 0x7f7: 0x0008, 0x7f8: 0x0008, 0x7f9: 0x0008, 0x7fa: 0x0040, 0x7fb: 0x0040,
+	0x7fc: 0x1308, 0x7fd: 0x0008, 0x7fe: 0x1008, 0x7ff: 0x1308,
+	// Block 0x20, offset 0x800
+	0x800: 0x1008, 0x801: 0x1008, 0x802: 0x1008, 0x803: 0x1008, 0x804: 0x1008, 0x805: 0x0040,
+	0x806: 0x1308, 0x807: 0x1008, 0x808: 0x1008, 0x809: 0x0040, 0x80a: 0x1008, 0x80b: 0x1008,
+	0x80c: 0x1308, 0x80d: 0x1b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040,
+	0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x1008, 0x816: 0x1008, 0x817: 0x0040,
+	0x818: 0x0040, 0x819: 0x0040, 0x81a: 0x0040, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040,
+	0x81e: 0x0008, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x1308, 0x823: 0x1308,
+	0x824: 0x0040, 0x825: 0x0040, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0008,
+	0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008,
+	0x830: 0x0040, 0x831: 0x0008, 0x832: 0x0008, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040,
+	0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0040, 0x839: 0x0040, 0x83a: 0x0040, 0x83b: 0x0040,
+	0x83c: 0x0040, 0x83d: 0x0040, 0x83e: 0x0040, 0x83f: 0x0040,
+	// Block 0x21, offset 0x840
+	0x840: 0x1008, 0x841: 0x1308, 0x842: 0x1308, 0x843: 0x1308, 0x844: 0x1308, 0x845: 0x0040,
+	0x846: 0x1008, 0x847: 0x1008, 0x848: 0x1008, 0x849: 0x0040, 0x84a: 0x1008, 0x84b: 0x1008,
+	0x84c: 0x1008, 0x84d: 0x1b08, 0x84e: 0x0008, 0x84f: 0x0018, 0x850: 0x0040, 0x851: 0x0040,
+	0x852: 0x0040, 0x853: 0x0040, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x1008,
+	0x858: 0x0018, 0x859: 0x0018, 0x85a: 0x0018, 0x85b: 0x0018, 0x85c: 0x0018, 0x85d: 0x0018,
+	0x85e: 0x0018, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x1308, 0x863: 0x1308,
+	0x864: 0x0040, 0x865: 0x0040, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0008,
+	0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008,
+	0x870: 0x0018, 0x871: 0x0018, 0x872: 0x0018, 0x873: 0x0018, 0x874: 0x0018, 0x875: 0x0018,
+	0x876: 0x0018, 0x877: 0x0018, 0x878: 0x0018, 0x879: 0x0018, 0x87a: 0x0008, 0x87b: 0x0008,
+	0x87c: 0x0008, 0x87d: 0x0008, 0x87e: 0x0008, 0x87f: 0x0008,
+	// Block 0x22, offset 0x880
+	0x880: 0x0040, 0x881: 0x0008, 0x882: 0x0008, 0x883: 0x0040, 0x884: 0x0008, 0x885: 0x0040,
+	0x886: 0x0040, 0x887: 0x0008, 0x888: 0x0008, 0x889: 0x0040, 0x88a: 0x0008, 0x88b: 0x0040,
+	0x88c: 0x0040, 0x88d: 0x0008, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040,
+	0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0008, 0x895: 0x0008, 0x896: 0x0008, 0x897: 0x0008,
+	0x898: 0x0040, 0x899: 0x0008, 0x89a: 0x0008, 0x89b: 0x0008, 0x89c: 0x0008, 0x89d: 0x0008,
+	0x89e: 0x0008, 0x89f: 0x0008, 0x8a0: 0x0040, 0x8a1: 0x0008, 0x8a2: 0x0008, 0x8a3: 0x0008,
+	0x8a4: 0x0040, 0x8a5: 0x0008, 0x8a6: 0x0040, 0x8a7: 0x0008, 0x8a8: 0x0040, 0x8a9: 0x0040,
+	0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0040, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008,
+	0x8b0: 0x0008, 0x8b1: 0x1308, 0x8b2: 0x0008, 0x8b3: 0x0929, 0x8b4: 0x1308, 0x8b5: 0x1308,
+	0x8b6: 0x1308, 0x8b7: 0x1308, 0x8b8: 0x1308, 0x8b9: 0x1308, 0x8ba: 0x0040, 0x8bb: 0x1308,
+	0x8bc: 0x1308, 0x8bd: 0x0008, 0x8be: 0x0040, 0x8bf: 0x0040,
+	// Block 0x23, offset 0x8c0
+	0x8c0: 0x0008, 0x8c1: 0x0008, 0x8c2: 0x0008, 0x8c3: 0x09d1, 0x8c4: 0x0008, 0x8c5: 0x0008,
+	0x8c6: 0x0008, 0x8c7: 0x0008, 0x8c8: 0x0040, 0x8c9: 0x0008, 0x8ca: 0x0008, 0x8cb: 0x0008,
+	0x8cc: 0x0008, 0x8cd: 0x0a09, 0x8ce: 0x0008, 0x8cf: 0x0008, 0x8d0: 0x0008, 0x8d1: 0x0008,
+	0x8d2: 0x0a41, 0x8d3: 0x0008, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x0a79,
+	0x8d8: 0x0008, 0x8d9: 0x0008, 0x8da: 0x0008, 0x8db: 0x0008, 0x8dc: 0x0ab1, 0x8dd: 0x0008,
+	0x8de: 0x0008, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x0008, 0x8e3: 0x0008,
+	0x8e4: 0x0008, 0x8e5: 0x0008, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0ae9,
+	0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0040, 0x8ee: 0x0040, 0x8ef: 0x0040,
+	0x8f0: 0x0040, 0x8f1: 0x1308, 0x8f2: 0x1308, 0x8f3: 0x0b21, 0x8f4: 0x1308, 0x8f5: 0x0b59,
+	0x8f6: 0x0b91, 0x8f7: 0x0bc9, 0x8f8: 0x0c19, 0x8f9: 0x0c51, 0x8fa: 0x1308, 0x8fb: 0x1308,
+	0x8fc: 0x1308, 0x8fd: 0x1308, 0x8fe: 0x1308, 0x8ff: 0x1008,
+	// Block 0x24, offset 0x900
+	0x900: 0x1308, 0x901: 0x0ca1, 0x902: 0x1308, 0x903: 0x1308, 0x904: 0x1b08, 0x905: 0x0018,
+	0x906: 0x1308, 0x907: 0x1308, 0x908: 0x0008, 0x909: 0x0008, 0x90a: 0x0008, 0x90b: 0x0008,
+	0x90c: 0x0008, 0x90d: 0x1308, 0x90e: 0x1308, 0x90f: 0x1308, 0x910: 0x1308, 0x911: 0x1308,
+	0x912: 0x1308, 0x913: 0x0cd9, 0x914: 0x1308, 0x915: 0x1308, 0x916: 0x1308, 0x917: 0x1308,
+	0x918: 0x0040, 0x919: 0x1308, 0x91a: 0x1308, 0x91b: 0x1308, 0x91c: 0x1308, 0x91d: 0x0d11,
+	0x91e: 0x1308, 0x91f: 0x1308, 0x920: 0x1308, 0x921: 0x1308, 0x922: 0x0d49, 0x923: 0x1308,
+	0x924: 0x1308, 0x925: 0x1308, 0x926: 0x1308, 0x927: 0x0d81, 0x928: 0x1308, 0x929: 0x1308,
+	0x92a: 0x1308, 0x92b: 0x1308, 0x92c: 0x0db9, 0x92d: 0x1308, 0x92e: 0x1308, 0x92f: 0x1308,
+	0x930: 0x1308, 0x931: 0x1308, 0x932: 0x1308, 0x933: 0x1308, 0x934: 0x1308, 0x935: 0x1308,
+	0x936: 0x1308, 0x937: 0x1308, 0x938: 0x1308, 0x939: 0x0df1, 0x93a: 0x1308, 0x93b: 0x1308,
+	0x93c: 0x1308, 0x93d: 0x0040, 0x93e: 0x0018, 0x93f: 0x0018,
+	// Block 0x25, offset 0x940
+	0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x0008, 0x944: 0x0008, 0x945: 0x0008,
+	0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0008, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008,
+	0x94c: 0x0008, 0x94d: 0x0008, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008,
+	0x952: 0x0008, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0008,
+	0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0008, 0x95d: 0x0008,
+	0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008,
+	0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0008,
+	0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0039, 0x96d: 0x0ed1, 0x96e: 0x0ee9, 0x96f: 0x0008,
+	0x970: 0x0ef9, 0x971: 0x0f09, 0x972: 0x0f19, 0x973: 0x0f31, 0x974: 0x0249, 0x975: 0x0f41,
+	0x976: 0x0259, 0x977: 0x0f51, 0x978: 0x0359, 0x979: 0x0f61, 0x97a: 0x0f71, 0x97b: 0x0008,
+	0x97c: 0x00d9, 0x97d: 0x0f81, 0x97e: 0x0f99, 0x97f: 0x0269,
+	// Block 0x26, offset 0x980
+	0x980: 0x0fa9, 0x981: 0x0fb9, 0x982: 0x0279, 0x983: 0x0039, 0x984: 0x0fc9, 0x985: 0x0fe1,
+	0x986: 0x059d, 0x987: 0x0ee9, 0x988: 0x0ef9, 0x989: 0x0f09, 0x98a: 0x0ff9, 0x98b: 0x1011,
+	0x98c: 0x1029, 0x98d: 0x0f31, 0x98e: 0x0008, 0x98f: 0x0f51, 0x990: 0x0f61, 0x991: 0x1041,
+	0x992: 0x00d9, 0x993: 0x1059, 0x994: 0x05b5, 0x995: 0x05b5, 0x996: 0x0f99, 0x997: 0x0fa9,
+	0x998: 0x0fb9, 0x999: 0x059d, 0x99a: 0x1071, 0x99b: 0x1089, 0x99c: 0x05cd, 0x99d: 0x1099,
+	0x99e: 0x10b1, 0x99f: 0x10c9, 0x9a0: 0x10e1, 0x9a1: 0x10f9, 0x9a2: 0x0f41, 0x9a3: 0x0269,
+	0x9a4: 0x0fb9, 0x9a5: 0x1089, 0x9a6: 0x1099, 0x9a7: 0x10b1, 0x9a8: 0x1111, 0x9a9: 0x10e1,
+	0x9aa: 0x10f9, 0x9ab: 0x0008, 0x9ac: 0x0008, 0x9ad: 0x0008, 0x9ae: 0x0008, 0x9af: 0x0008,
+	0x9b0: 0x0008, 0x9b1: 0x0008, 0x9b2: 0x0008, 0x9b3: 0x0008, 0x9b4: 0x0008, 0x9b5: 0x0008,
+	0x9b6: 0x0008, 0x9b7: 0x0008, 0x9b8: 0x1129, 0x9b9: 0x0008, 0x9ba: 0x0008, 0x9bb: 0x0008,
+	0x9bc: 0x0008, 0x9bd: 0x0008, 0x9be: 0x0008, 0x9bf: 0x0008,
+	// Block 0x27, offset 0x9c0
+	0x9c0: 0x0008, 0x9c1: 0x0008, 0x9c2: 0x0008, 0x9c3: 0x0008, 0x9c4: 0x0008, 0x9c5: 0x0008,
+	0x9c6: 0x0008, 0x9c7: 0x0008, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008,
+	0x9cc: 0x0008, 0x9cd: 0x0008, 0x9ce: 0x0008, 0x9cf: 0x0008, 0x9d0: 0x0008, 0x9d1: 0x0008,
+	0x9d2: 0x0008, 0x9d3: 0x0008, 0x9d4: 0x0008, 0x9d5: 0x0008, 0x9d6: 0x0008, 0x9d7: 0x0008,
+	0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x1141, 0x9dc: 0x1159, 0x9dd: 0x1169,
+	0x9de: 0x1181, 0x9df: 0x1029, 0x9e0: 0x1199, 0x9e1: 0x11a9, 0x9e2: 0x11c1, 0x9e3: 0x11d9,
+	0x9e4: 0x11f1, 0x9e5: 0x1209, 0x9e6: 0x1221, 0x9e7: 0x05e5, 0x9e8: 0x1239, 0x9e9: 0x1251,
+	0x9ea: 0xe17d, 0x9eb: 0x1269, 0x9ec: 0x1281, 0x9ed: 0x1299, 0x9ee: 0x12b1, 0x9ef: 0x12c9,
+	0x9f0: 0x12e1, 0x9f1: 0x12f9, 0x9f2: 0x1311, 0x9f3: 0x1329, 0x9f4: 0x1341, 0x9f5: 0x1359,
+	0x9f6: 0x1371, 0x9f7: 0x1389, 0x9f8: 0x05fd, 0x9f9: 0x13a1, 0x9fa: 0x13b9, 0x9fb: 0x13d1,
+	0x9fc: 0x13e1, 0x9fd: 0x13f9, 0x9fe: 0x1411, 0x9ff: 0x1429,
+	// Block 0x28, offset 0xa00
+	0xa00: 0xe00d, 0xa01: 0x0008, 0xa02: 0xe00d, 0xa03: 0x0008, 0xa04: 0xe00d, 0xa05: 0x0008,
+	0xa06: 0xe00d, 0xa07: 0x0008, 0xa08: 0xe00d, 0xa09: 0x0008, 0xa0a: 0xe00d, 0xa0b: 0x0008,
+	0xa0c: 0xe00d, 0xa0d: 0x0008, 0xa0e: 0xe00d, 0xa0f: 0x0008, 0xa10: 0xe00d, 0xa11: 0x0008,
+	0xa12: 0xe00d, 0xa13: 0x0008, 0xa14: 0xe00d, 0xa15: 0x0008, 0xa16: 0xe00d, 0xa17: 0x0008,
+	0xa18: 0xe00d, 0xa19: 0x0008, 0xa1a: 0xe00d, 0xa1b: 0x0008, 0xa1c: 0xe00d, 0xa1d: 0x0008,
+	0xa1e: 0xe00d, 0xa1f: 0x0008, 0xa20: 0xe00d, 0xa21: 0x0008, 0xa22: 0xe00d, 0xa23: 0x0008,
+	0xa24: 0xe00d, 0xa25: 0x0008, 0xa26: 0xe00d, 0xa27: 0x0008, 0xa28: 0xe00d, 0xa29: 0x0008,
+	0xa2a: 0xe00d, 0xa2b: 0x0008, 0xa2c: 0xe00d, 0xa2d: 0x0008, 0xa2e: 0xe00d, 0xa2f: 0x0008,
+	0xa30: 0xe00d, 0xa31: 0x0008, 0xa32: 0xe00d, 0xa33: 0x0008, 0xa34: 0xe00d, 0xa35: 0x0008,
+	0xa36: 0xe00d, 0xa37: 0x0008, 0xa38: 0xe00d, 0xa39: 0x0008, 0xa3a: 0xe00d, 0xa3b: 0x0008,
+	0xa3c: 0xe00d, 0xa3d: 0x0008, 0xa3e: 0xe00d, 0xa3f: 0x0008,
+	// Block 0x29, offset 0xa40
+	0xa40: 0xe00d, 0xa41: 0x0008, 0xa42: 0xe00d, 0xa43: 0x0008, 0xa44: 0xe00d, 0xa45: 0x0008,
+	0xa46: 0xe00d, 0xa47: 0x0008, 0xa48: 0xe00d, 0xa49: 0x0008, 0xa4a: 0xe00d, 0xa4b: 0x0008,
+	0xa4c: 0xe00d, 0xa4d: 0x0008, 0xa4e: 0xe00d, 0xa4f: 0x0008, 0xa50: 0xe00d, 0xa51: 0x0008,
+	0xa52: 0xe00d, 0xa53: 0x0008, 0xa54: 0xe00d, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008,
+	0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0615, 0xa5b: 0x0635, 0xa5c: 0x0008, 0xa5d: 0x0008,
+	0xa5e: 0x1441, 0xa5f: 0x0008, 0xa60: 0xe00d, 0xa61: 0x0008, 0xa62: 0xe00d, 0xa63: 0x0008,
+	0xa64: 0xe00d, 0xa65: 0x0008, 0xa66: 0xe00d, 0xa67: 0x0008, 0xa68: 0xe00d, 0xa69: 0x0008,
+	0xa6a: 0xe00d, 0xa6b: 0x0008, 0xa6c: 0xe00d, 0xa6d: 0x0008, 0xa6e: 0xe00d, 0xa6f: 0x0008,
+	0xa70: 0xe00d, 0xa71: 0x0008, 0xa72: 0xe00d, 0xa73: 0x0008, 0xa74: 0xe00d, 0xa75: 0x0008,
+	0xa76: 0xe00d, 0xa77: 0x0008, 0xa78: 0xe00d, 0xa79: 0x0008, 0xa7a: 0xe00d, 0xa7b: 0x0008,
+	0xa7c: 0xe00d, 0xa7d: 0x0008, 0xa7e: 0xe00d, 0xa7f: 0x0008,
+	// Block 0x2a, offset 0xa80
+	0xa80: 0x0008, 0xa81: 0x0008, 0xa82: 0x0008, 0xa83: 0x0008, 0xa84: 0x0008, 0xa85: 0x0008,
+	0xa86: 0x0040, 0xa87: 0x0040, 0xa88: 0xe045, 0xa89: 0xe045, 0xa8a: 0xe045, 0xa8b: 0xe045,
+	0xa8c: 0xe045, 0xa8d: 0xe045, 0xa8e: 0x0040, 0xa8f: 0x0040, 0xa90: 0x0008, 0xa91: 0x0008,
+	0xa92: 0x0008, 0xa93: 0x0008, 0xa94: 0x0008, 0xa95: 0x0008, 0xa96: 0x0008, 0xa97: 0x0008,
+	0xa98: 0x0040, 0xa99: 0xe045, 0xa9a: 0x0040, 0xa9b: 0xe045, 0xa9c: 0x0040, 0xa9d: 0xe045,
+	0xa9e: 0x0040, 0xa9f: 0xe045, 0xaa0: 0x0008, 0xaa1: 0x0008, 0xaa2: 0x0008, 0xaa3: 0x0008,
+	0xaa4: 0x0008, 0xaa5: 0x0008, 0xaa6: 0x0008, 0xaa7: 0x0008, 0xaa8: 0xe045, 0xaa9: 0xe045,
+	0xaaa: 0xe045, 0xaab: 0xe045, 0xaac: 0xe045, 0xaad: 0xe045, 0xaae: 0xe045, 0xaaf: 0xe045,
+	0xab0: 0x0008, 0xab1: 0x1459, 0xab2: 0x0008, 0xab3: 0x1471, 0xab4: 0x0008, 0xab5: 0x1489,
+	0xab6: 0x0008, 0xab7: 0x14a1, 0xab8: 0x0008, 0xab9: 0x14b9, 0xaba: 0x0008, 0xabb: 0x14d1,
+	0xabc: 0x0008, 0xabd: 0x14e9, 0xabe: 0x0040, 0xabf: 0x0040,
+	// Block 0x2b, offset 0xac0
+	0xac0: 0x1501, 0xac1: 0x1531, 0xac2: 0x1561, 0xac3: 0x1591, 0xac4: 0x15c1, 0xac5: 0x15f1,
+	0xac6: 0x1621, 0xac7: 0x1651, 0xac8: 0x1501, 0xac9: 0x1531, 0xaca: 0x1561, 0xacb: 0x1591,
+	0xacc: 0x15c1, 0xacd: 0x15f1, 0xace: 0x1621, 0xacf: 0x1651, 0xad0: 0x1681, 0xad1: 0x16b1,
+	0xad2: 0x16e1, 0xad3: 0x1711, 0xad4: 0x1741, 0xad5: 0x1771, 0xad6: 0x17a1, 0xad7: 0x17d1,
+	0xad8: 0x1681, 0xad9: 0x16b1, 0xada: 0x16e1, 0xadb: 0x1711, 0xadc: 0x1741, 0xadd: 0x1771,
+	0xade: 0x17a1, 0xadf: 0x17d1, 0xae0: 0x1801, 0xae1: 0x1831, 0xae2: 0x1861, 0xae3: 0x1891,
+	0xae4: 0x18c1, 0xae5: 0x18f1, 0xae6: 0x1921, 0xae7: 0x1951, 0xae8: 0x1801, 0xae9: 0x1831,
+	0xaea: 0x1861, 0xaeb: 0x1891, 0xaec: 0x18c1, 0xaed: 0x18f1, 0xaee: 0x1921, 0xaef: 0x1951,
+	0xaf0: 0x0008, 0xaf1: 0x0008, 0xaf2: 0x1981, 0xaf3: 0x19b1, 0xaf4: 0x19d9, 0xaf5: 0x0040,
+	0xaf6: 0x0008, 0xaf7: 0x1a01, 0xaf8: 0xe045, 0xaf9: 0xe045, 0xafa: 0x064d, 0xafb: 0x1459,
+	0xafc: 0x19b1, 0xafd: 0x0666, 0xafe: 0x1a31, 0xaff: 0x0686,
+	// Block 0x2c, offset 0xb00
+	0xb00: 0x06a6, 0xb01: 0x1a4a, 0xb02: 0x1a79, 0xb03: 0x1aa9, 0xb04: 0x1ad1, 0xb05: 0x0040,
+	0xb06: 0x0008, 0xb07: 0x1af9, 0xb08: 0x06c5, 0xb09: 0x1471, 0xb0a: 0x06dd, 0xb0b: 0x1489,
+	0xb0c: 0x1aa9, 0xb0d: 0x1b2a, 0xb0e: 0x1b5a, 0xb0f: 0x1b8a, 0xb10: 0x0008, 0xb11: 0x0008,
+	0xb12: 0x0008, 0xb13: 0x1bb9, 0xb14: 0x0040, 0xb15: 0x0040, 0xb16: 0x0008, 0xb17: 0x0008,
+	0xb18: 0xe045, 0xb19: 0xe045, 0xb1a: 0x06f5, 0xb1b: 0x14a1, 0xb1c: 0x0040, 0xb1d: 0x1bd2,
+	0xb1e: 0x1c02, 0xb1f: 0x1c32, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x1c61,
+	0xb24: 0x0008, 0xb25: 0x0008, 0xb26: 0x0008, 0xb27: 0x0008, 0xb28: 0xe045, 0xb29: 0xe045,
+	0xb2a: 0x070d, 0xb2b: 0x14d1, 0xb2c: 0xe04d, 0xb2d: 0x1c7a, 0xb2e: 0x03d2, 0xb2f: 0x1caa,
+	0xb30: 0x0040, 0xb31: 0x0040, 0xb32: 0x1cb9, 0xb33: 0x1ce9, 0xb34: 0x1d11, 0xb35: 0x0040,
+	0xb36: 0x0008, 0xb37: 0x1d39, 0xb38: 0x0725, 0xb39: 0x14b9, 0xb3a: 0x0515, 0xb3b: 0x14e9,
+	0xb3c: 0x1ce9, 0xb3d: 0x073e, 0xb3e: 0x075e, 0xb3f: 0x0040,
+	// Block 0x2d, offset 0xb40
+	0xb40: 0x000a, 0xb41: 0x000a, 0xb42: 0x000a, 0xb43: 0x000a, 0xb44: 0x000a, 0xb45: 0x000a,
+	0xb46: 0x000a, 0xb47: 0x000a, 0xb48: 0x000a, 0xb49: 0x000a, 0xb4a: 0x000a, 0xb4b: 0x03c0,
+	0xb4c: 0x0003, 0xb4d: 0x0003, 0xb4e: 0x0340, 0xb4f: 0x0340, 0xb50: 0x0018, 0xb51: 0xe00d,
+	0xb52: 0x0018, 0xb53: 0x0018, 0xb54: 0x0018, 0xb55: 0x0018, 0xb56: 0x0018, 0xb57: 0x077e,
+	0xb58: 0x0018, 0xb59: 0x0018, 0xb5a: 0x0018, 0xb5b: 0x0018, 0xb5c: 0x0018, 0xb5d: 0x0018,
+	0xb5e: 0x0018, 0xb5f: 0x0018, 0xb60: 0x0018, 0xb61: 0x0018, 0xb62: 0x0018, 0xb63: 0x0018,
+	0xb64: 0x0040, 0xb65: 0x0040, 0xb66: 0x0040, 0xb67: 0x0018, 0xb68: 0x0040, 0xb69: 0x0040,
+	0xb6a: 0x0340, 0xb6b: 0x0340, 0xb6c: 0x0340, 0xb6d: 0x0340, 0xb6e: 0x0340, 0xb6f: 0x000a,
+	0xb70: 0x0018, 0xb71: 0x0018, 0xb72: 0x0018, 0xb73: 0x1d69, 0xb74: 0x1da1, 0xb75: 0x0018,
+	0xb76: 0x1df1, 0xb77: 0x1e29, 0xb78: 0x0018, 0xb79: 0x0018, 0xb7a: 0x0018, 0xb7b: 0x0018,
+	0xb7c: 0x1e7a, 0xb7d: 0x0018, 0xb7e: 0x079e, 0xb7f: 0x0018,
+	// Block 0x2e, offset 0xb80
+	0xb80: 0x0018, 0xb81: 0x0018, 0xb82: 0x0018, 0xb83: 0x0018, 0xb84: 0x0018, 0xb85: 0x0018,
+	0xb86: 0x0018, 0xb87: 0x1e92, 0xb88: 0x1eaa, 0xb89: 0x1ec2, 0xb8a: 0x0018, 0xb8b: 0x0018,
+	0xb8c: 0x0018, 0xb8d: 0x0018, 0xb8e: 0x0018, 0xb8f: 0x0018, 0xb90: 0x0018, 0xb91: 0x0018,
+	0xb92: 0x0018, 0xb93: 0x0018, 0xb94: 0x0018, 0xb95: 0x0018, 0xb96: 0x0018, 0xb97: 0x1ed9,
+	0xb98: 0x0018, 0xb99: 0x0018, 0xb9a: 0x0018, 0xb9b: 0x0018, 0xb9c: 0x0018, 0xb9d: 0x0018,
+	0xb9e: 0x0018, 0xb9f: 0x000a, 0xba0: 0x03c0, 0xba1: 0x0340, 0xba2: 0x0340, 0xba3: 0x0340,
+	0xba4: 0x03c0, 0xba5: 0x0040, 0xba6: 0x0040, 0xba7: 0x0040, 0xba8: 0x0040, 0xba9: 0x0040,
+	0xbaa: 0x0340, 0xbab: 0x0340, 0xbac: 0x0340, 0xbad: 0x0340, 0xbae: 0x0340, 0xbaf: 0x0340,
+	0xbb0: 0x1f41, 0xbb1: 0x0f41, 0xbb2: 0x0040, 0xbb3: 0x0040, 0xbb4: 0x1f51, 0xbb5: 0x1f61,
+	0xbb6: 0x1f71, 0xbb7: 0x1f81, 0xbb8: 0x1f91, 0xbb9: 0x1fa1, 0xbba: 0x1fb2, 0xbbb: 0x07bd,
+	0xbbc: 0x1fc2, 0xbbd: 0x1fd2, 0xbbe: 0x1fe2, 0xbbf: 0x0f71,
+	// Block 0x2f, offset 0xbc0
+	0xbc0: 0x1f41, 0xbc1: 0x00c9, 0xbc2: 0x0069, 0xbc3: 0x0079, 0xbc4: 0x1f51, 0xbc5: 0x1f61,
+	0xbc6: 0x1f71, 0xbc7: 0x1f81, 0xbc8: 0x1f91, 0xbc9: 0x1fa1, 0xbca: 0x1fb2, 0xbcb: 0x07d5,
+	0xbcc: 0x1fc2, 0xbcd: 0x1fd2, 0xbce: 0x1fe2, 0xbcf: 0x0040, 0xbd0: 0x0039, 0xbd1: 0x0f09,
+	0xbd2: 0x00d9, 0xbd3: 0x0369, 0xbd4: 0x0ff9, 0xbd5: 0x0249, 0xbd6: 0x0f51, 0xbd7: 0x0359,
+	0xbd8: 0x0f61, 0xbd9: 0x0f71, 0xbda: 0x0f99, 0xbdb: 0x01d9, 0xbdc: 0x0fa9, 0xbdd: 0x0040,
+	0xbde: 0x0040, 0xbdf: 0x0040, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018,
+	0xbe4: 0x0018, 0xbe5: 0x0018, 0xbe6: 0x0018, 0xbe7: 0x0018, 0xbe8: 0x1ff1, 0xbe9: 0x0018,
+	0xbea: 0x0018, 0xbeb: 0x0018, 0xbec: 0x0018, 0xbed: 0x0018, 0xbee: 0x0018, 0xbef: 0x0018,
+	0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x0018, 0xbf4: 0x0018, 0xbf5: 0x0018,
+	0xbf6: 0x0018, 0xbf7: 0x0018, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018,
+	0xbfc: 0x0018, 0xbfd: 0x0018, 0xbfe: 0x0018, 0xbff: 0x0040,
+	// Block 0x30, offset 0xc00
+	0xc00: 0x07ee, 0xc01: 0x080e, 0xc02: 0x1159, 0xc03: 0x082d, 0xc04: 0x0018, 0xc05: 0x084e,
+	0xc06: 0x086e, 0xc07: 0x1011, 0xc08: 0x0018, 0xc09: 0x088d, 0xc0a: 0x0f31, 0xc0b: 0x0249,
+	0xc0c: 0x0249, 0xc0d: 0x0249, 0xc0e: 0x0249, 0xc0f: 0x2009, 0xc10: 0x0f41, 0xc11: 0x0f41,
+	0xc12: 0x0359, 0xc13: 0x0359, 0xc14: 0x0018, 0xc15: 0x0f71, 0xc16: 0x2021, 0xc17: 0x0018,
+	0xc18: 0x0018, 0xc19: 0x0f99, 0xc1a: 0x2039, 0xc1b: 0x0269, 0xc1c: 0x0269, 0xc1d: 0x0269,
+	0xc1e: 0x0018, 0xc1f: 0x0018, 0xc20: 0x2049, 0xc21: 0x08ad, 0xc22: 0x2061, 0xc23: 0x0018,
+	0xc24: 0x13d1, 0xc25: 0x0018, 0xc26: 0x2079, 0xc27: 0x0018, 0xc28: 0x13d1, 0xc29: 0x0018,
+	0xc2a: 0x0f51, 0xc2b: 0x2091, 0xc2c: 0x0ee9, 0xc2d: 0x1159, 0xc2e: 0x0018, 0xc2f: 0x0f09,
+	0xc30: 0x0f09, 0xc31: 0x1199, 0xc32: 0x0040, 0xc33: 0x0f61, 0xc34: 0x00d9, 0xc35: 0x20a9,
+	0xc36: 0x20c1, 0xc37: 0x20d9, 0xc38: 0x20f1, 0xc39: 0x0f41, 0xc3a: 0x0018, 0xc3b: 0x08cd,
+	0xc3c: 0x2109, 0xc3d: 0x10b1, 0xc3e: 0x10b1, 0xc3f: 0x2109,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x08ed, 0xc41: 0x0018, 0xc42: 0x0018, 0xc43: 0x0018, 0xc44: 0x0018, 0xc45: 0x0ef9,
+	0xc46: 0x0ef9, 0xc47: 0x0f09, 0xc48: 0x0f41, 0xc49: 0x0259, 0xc4a: 0x0018, 0xc4b: 0x0018,
+	0xc4c: 0x0018, 0xc4d: 0x0018, 0xc4e: 0x0008, 0xc4f: 0x0018, 0xc50: 0x2121, 0xc51: 0x2151,
+	0xc52: 0x2181, 0xc53: 0x21b9, 0xc54: 0x21e9, 0xc55: 0x2219, 0xc56: 0x2249, 0xc57: 0x2279,
+	0xc58: 0x22a9, 0xc59: 0x22d9, 0xc5a: 0x2309, 0xc5b: 0x2339, 0xc5c: 0x2369, 0xc5d: 0x2399,
+	0xc5e: 0x23c9, 0xc5f: 0x23f9, 0xc60: 0x0f41, 0xc61: 0x2421, 0xc62: 0x0905, 0xc63: 0x2439,
+	0xc64: 0x1089, 0xc65: 0x2451, 0xc66: 0x0925, 0xc67: 0x2469, 0xc68: 0x2491, 0xc69: 0x0369,
+	0xc6a: 0x24a9, 0xc6b: 0x0945, 0xc6c: 0x0359, 0xc6d: 0x1159, 0xc6e: 0x0ef9, 0xc6f: 0x0f61,
+	0xc70: 0x0f41, 0xc71: 0x2421, 0xc72: 0x0965, 0xc73: 0x2439, 0xc74: 0x1089, 0xc75: 0x2451,
+	0xc76: 0x0985, 0xc77: 0x2469, 0xc78: 0x2491, 0xc79: 0x0369, 0xc7a: 0x24a9, 0xc7b: 0x09a5,
+	0xc7c: 0x0359, 0xc7d: 0x1159, 0xc7e: 0x0ef9, 0xc7f: 0x0f61,
+	// Block 0x32, offset 0xc80
+	0xc80: 0x0018, 0xc81: 0x0018, 0xc82: 0x0018, 0xc83: 0x0018, 0xc84: 0x0018, 0xc85: 0x0018,
+	0xc86: 0x0018, 0xc87: 0x0018, 0xc88: 0x0018, 0xc89: 0x0018, 0xc8a: 0x0018, 0xc8b: 0x0040,
+	0xc8c: 0x0040, 0xc8d: 0x0040, 0xc8e: 0x0040, 0xc8f: 0x0040, 0xc90: 0x0040, 0xc91: 0x0040,
+	0xc92: 0x0040, 0xc93: 0x0040, 0xc94: 0x0040, 0xc95: 0x0040, 0xc96: 0x0040, 0xc97: 0x0040,
+	0xc98: 0x0040, 0xc99: 0x0040, 0xc9a: 0x0040, 0xc9b: 0x0040, 0xc9c: 0x0040, 0xc9d: 0x0040,
+	0xc9e: 0x0040, 0xc9f: 0x0040, 0xca0: 0x00c9, 0xca1: 0x0069, 0xca2: 0x0079, 0xca3: 0x1f51,
+	0xca4: 0x1f61, 0xca5: 0x1f71, 0xca6: 0x1f81, 0xca7: 0x1f91, 0xca8: 0x1fa1, 0xca9: 0x2601,
+	0xcaa: 0x2619, 0xcab: 0x2631, 0xcac: 0x2649, 0xcad: 0x2661, 0xcae: 0x2679, 0xcaf: 0x2691,
+	0xcb0: 0x26a9, 0xcb1: 0x26c1, 0xcb2: 0x26d9, 0xcb3: 0x26f1, 0xcb4: 0x0a06, 0xcb5: 0x0a26,
+	0xcb6: 0x0a46, 0xcb7: 0x0a66, 0xcb8: 0x0a86, 0xcb9: 0x0aa6, 0xcba: 0x0ac6, 0xcbb: 0x0ae6,
+	0xcbc: 0x0b06, 0xcbd: 0x270a, 0xcbe: 0x2732, 0xcbf: 0x275a,
+	// Block 0x33, offset 0xcc0
+	0xcc0: 0x2782, 0xcc1: 0x27aa, 0xcc2: 0x27d2, 0xcc3: 0x27fa, 0xcc4: 0x2822, 0xcc5: 0x284a,
+	0xcc6: 0x2872, 0xcc7: 0x289a, 0xcc8: 0x0040, 0xcc9: 0x0040, 0xcca: 0x0040, 0xccb: 0x0040,
+	0xccc: 0x0040, 0xccd: 0x0040, 0xcce: 0x0040, 0xccf: 0x0040, 0xcd0: 0x0040, 0xcd1: 0x0040,
+	0xcd2: 0x0040, 0xcd3: 0x0040, 0xcd4: 0x0040, 0xcd5: 0x0040, 0xcd6: 0x0040, 0xcd7: 0x0040,
+	0xcd8: 0x0040, 0xcd9: 0x0040, 0xcda: 0x0040, 0xcdb: 0x0040, 0xcdc: 0x0b26, 0xcdd: 0x0b46,
+	0xcde: 0x0b66, 0xcdf: 0x0b86, 0xce0: 0x0ba6, 0xce1: 0x0bc6, 0xce2: 0x0be6, 0xce3: 0x0c06,
+	0xce4: 0x0c26, 0xce5: 0x0c46, 0xce6: 0x0c66, 0xce7: 0x0c86, 0xce8: 0x0ca6, 0xce9: 0x0cc6,
+	0xcea: 0x0ce6, 0xceb: 0x0d06, 0xcec: 0x0d26, 0xced: 0x0d46, 0xcee: 0x0d66, 0xcef: 0x0d86,
+	0xcf0: 0x0da6, 0xcf1: 0x0dc6, 0xcf2: 0x0de6, 0xcf3: 0x0e06, 0xcf4: 0x0e26, 0xcf5: 0x0e46,
+	0xcf6: 0x0039, 0xcf7: 0x0ee9, 0xcf8: 0x1159, 0xcf9: 0x0ef9, 0xcfa: 0x0f09, 0xcfb: 0x1199,
+	0xcfc: 0x0f31, 0xcfd: 0x0249, 0xcfe: 0x0f41, 0xcff: 0x0259,
+	// Block 0x34, offset 0xd00
+	0xd00: 0x0f51, 0xd01: 0x0359, 0xd02: 0x0f61, 0xd03: 0x0f71, 0xd04: 0x00d9, 0xd05: 0x0f99,
+	0xd06: 0x2039, 0xd07: 0x0269, 0xd08: 0x01d9, 0xd09: 0x0fa9, 0xd0a: 0x0fb9, 0xd0b: 0x1089,
+	0xd0c: 0x0279, 0xd0d: 0x0369, 0xd0e: 0x0289, 0xd0f: 0x13d1, 0xd10: 0x0039, 0xd11: 0x0ee9,
+	0xd12: 0x1159, 0xd13: 0x0ef9, 0xd14: 0x0f09, 0xd15: 0x1199, 0xd16: 0x0f31, 0xd17: 0x0249,
+	0xd18: 0x0f41, 0xd19: 0x0259, 0xd1a: 0x0f51, 0xd1b: 0x0359, 0xd1c: 0x0f61, 0xd1d: 0x0f71,
+	0xd1e: 0x00d9, 0xd1f: 0x0f99, 0xd20: 0x2039, 0xd21: 0x0269, 0xd22: 0x01d9, 0xd23: 0x0fa9,
+	0xd24: 0x0fb9, 0xd25: 0x1089, 0xd26: 0x0279, 0xd27: 0x0369, 0xd28: 0x0289, 0xd29: 0x13d1,
+	0xd2a: 0x1f41, 0xd2b: 0x0018, 0xd2c: 0x0018, 0xd2d: 0x0018, 0xd2e: 0x0018, 0xd2f: 0x0018,
+	0xd30: 0x0018, 0xd31: 0x0018, 0xd32: 0x0018, 0xd33: 0x0018, 0xd34: 0x0018, 0xd35: 0x0018,
+	0xd36: 0x0018, 0xd37: 0x0018, 0xd38: 0x0018, 0xd39: 0x0018, 0xd3a: 0x0018, 0xd3b: 0x0018,
+	0xd3c: 0x0018, 0xd3d: 0x0018, 0xd3e: 0x0018, 0xd3f: 0x0018,
+	// Block 0x35, offset 0xd40
+	0xd40: 0x0008, 0xd41: 0x0008, 0xd42: 0x0008, 0xd43: 0x0008, 0xd44: 0x0008, 0xd45: 0x0008,
+	0xd46: 0x0008, 0xd47: 0x0008, 0xd48: 0x0008, 0xd49: 0x0008, 0xd4a: 0x0008, 0xd4b: 0x0008,
+	0xd4c: 0x0008, 0xd4d: 0x0008, 0xd4e: 0x0008, 0xd4f: 0x0008, 0xd50: 0x0008, 0xd51: 0x0008,
+	0xd52: 0x0008, 0xd53: 0x0008, 0xd54: 0x0008, 0xd55: 0x0008, 0xd56: 0x0008, 0xd57: 0x0008,
+	0xd58: 0x0008, 0xd59: 0x0008, 0xd5a: 0x0008, 0xd5b: 0x0008, 0xd5c: 0x0008, 0xd5d: 0x0008,
+	0xd5e: 0x0008, 0xd5f: 0x0040, 0xd60: 0xe00d, 0xd61: 0x0008, 0xd62: 0x2971, 0xd63: 0x0ebd,
+	0xd64: 0x2989, 0xd65: 0x0008, 0xd66: 0x0008, 0xd67: 0xe07d, 0xd68: 0x0008, 0xd69: 0xe01d,
+	0xd6a: 0x0008, 0xd6b: 0xe03d, 0xd6c: 0x0008, 0xd6d: 0x0fe1, 0xd6e: 0x1281, 0xd6f: 0x0fc9,
+	0xd70: 0x1141, 0xd71: 0x0008, 0xd72: 0xe00d, 0xd73: 0x0008, 0xd74: 0x0008, 0xd75: 0xe01d,
+	0xd76: 0x0008, 0xd77: 0x0008, 0xd78: 0x0008, 0xd79: 0x0008, 0xd7a: 0x0008, 0xd7b: 0x0008,
+	0xd7c: 0x0259, 0xd7d: 0x1089, 0xd7e: 0x29a1, 0xd7f: 0x29b9,
+	// Block 0x36, offset 0xd80
+	0xd80: 0xe00d, 0xd81: 0x0008, 0xd82: 0xe00d, 0xd83: 0x0008, 0xd84: 0xe00d, 0xd85: 0x0008,
+	0xd86: 0xe00d, 0xd87: 0x0008, 0xd88: 0xe00d, 0xd89: 0x0008, 0xd8a: 0xe00d, 0xd8b: 0x0008,
+	0xd8c: 0xe00d, 0xd8d: 0x0008, 0xd8e: 0xe00d, 0xd8f: 0x0008, 0xd90: 0xe00d, 0xd91: 0x0008,
+	0xd92: 0xe00d, 0xd93: 0x0008, 0xd94: 0xe00d, 0xd95: 0x0008, 0xd96: 0xe00d, 0xd97: 0x0008,
+	0xd98: 0xe00d, 0xd99: 0x0008, 0xd9a: 0xe00d, 0xd9b: 0x0008, 0xd9c: 0xe00d, 0xd9d: 0x0008,
+	0xd9e: 0xe00d, 0xd9f: 0x0008, 0xda0: 0xe00d, 0xda1: 0x0008, 0xda2: 0xe00d, 0xda3: 0x0008,
+	0xda4: 0x0008, 0xda5: 0x0018, 0xda6: 0x0018, 0xda7: 0x0018, 0xda8: 0x0018, 0xda9: 0x0018,
+	0xdaa: 0x0018, 0xdab: 0xe03d, 0xdac: 0x0008, 0xdad: 0xe01d, 0xdae: 0x0008, 0xdaf: 0x1308,
+	0xdb0: 0x1308, 0xdb1: 0x1308, 0xdb2: 0xe00d, 0xdb3: 0x0008, 0xdb4: 0x0040, 0xdb5: 0x0040,
+	0xdb6: 0x0040, 0xdb7: 0x0040, 0xdb8: 0x0040, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018,
+	0xdbc: 0x0018, 0xdbd: 0x0018, 0xdbe: 0x0018, 0xdbf: 0x0018,
+	// Block 0x37, offset 0xdc0
+	0xdc0: 0x26fd, 0xdc1: 0x271d, 0xdc2: 0x273d, 0xdc3: 0x275d, 0xdc4: 0x277d, 0xdc5: 0x279d,
+	0xdc6: 0x27bd, 0xdc7: 0x27dd, 0xdc8: 0x27fd, 0xdc9: 0x281d, 0xdca: 0x283d, 0xdcb: 0x285d,
+	0xdcc: 0x287d, 0xdcd: 0x289d, 0xdce: 0x28bd, 0xdcf: 0x28dd, 0xdd0: 0x28fd, 0xdd1: 0x291d,
+	0xdd2: 0x293d, 0xdd3: 0x295d, 0xdd4: 0x297d, 0xdd5: 0x299d, 0xdd6: 0x0040, 0xdd7: 0x0040,
+	0xdd8: 0x0040, 0xdd9: 0x0040, 0xdda: 0x0040, 0xddb: 0x0040, 0xddc: 0x0040, 0xddd: 0x0040,
+	0xdde: 0x0040, 0xddf: 0x0040, 0xde0: 0x0040, 0xde1: 0x0040, 0xde2: 0x0040, 0xde3: 0x0040,
+	0xde4: 0x0040, 0xde5: 0x0040, 0xde6: 0x0040, 0xde7: 0x0040, 0xde8: 0x0040, 0xde9: 0x0040,
+	0xdea: 0x0040, 0xdeb: 0x0040, 0xdec: 0x0040, 0xded: 0x0040, 0xdee: 0x0040, 0xdef: 0x0040,
+	0xdf0: 0x0040, 0xdf1: 0x0040, 0xdf2: 0x0040, 0xdf3: 0x0040, 0xdf4: 0x0040, 0xdf5: 0x0040,
+	0xdf6: 0x0040, 0xdf7: 0x0040, 0xdf8: 0x0040, 0xdf9: 0x0040, 0xdfa: 0x0040, 0xdfb: 0x0040,
+	0xdfc: 0x0040, 0xdfd: 0x0040, 0xdfe: 0x0040, 0xdff: 0x0040,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x000a, 0xe01: 0x0018, 0xe02: 0x29d1, 0xe03: 0x0018, 0xe04: 0x0018, 0xe05: 0x0008,
+	0xe06: 0x0008, 0xe07: 0x0008, 0xe08: 0x0018, 0xe09: 0x0018, 0xe0a: 0x0018, 0xe0b: 0x0018,
+	0xe0c: 0x0018, 0xe0d: 0x0018, 0xe0e: 0x0018, 0xe0f: 0x0018, 0xe10: 0x0018, 0xe11: 0x0018,
+	0xe12: 0x0018, 0xe13: 0x0018, 0xe14: 0x0018, 0xe15: 0x0018, 0xe16: 0x0018, 0xe17: 0x0018,
+	0xe18: 0x0018, 0xe19: 0x0018, 0xe1a: 0x0018, 0xe1b: 0x0018, 0xe1c: 0x0018, 0xe1d: 0x0018,
+	0xe1e: 0x0018, 0xe1f: 0x0018, 0xe20: 0x0018, 0xe21: 0x0018, 0xe22: 0x0018, 0xe23: 0x0018,
+	0xe24: 0x0018, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018,
+	0xe2a: 0x1308, 0xe2b: 0x1308, 0xe2c: 0x1308, 0xe2d: 0x1308, 0xe2e: 0x1018, 0xe2f: 0x1018,
+	0xe30: 0x0018, 0xe31: 0x0018, 0xe32: 0x0018, 0xe33: 0x0018, 0xe34: 0x0018, 0xe35: 0x0018,
+	0xe36: 0xe125, 0xe37: 0x0018, 0xe38: 0x29bd, 0xe39: 0x29dd, 0xe3a: 0x29fd, 0xe3b: 0x0018,
+	0xe3c: 0x0008, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x2b3d, 0xe41: 0x2b5d, 0xe42: 0x2b7d, 0xe43: 0x2b9d, 0xe44: 0x2bbd, 0xe45: 0x2bdd,
+	0xe46: 0x2bdd, 0xe47: 0x2bdd, 0xe48: 0x2bfd, 0xe49: 0x2bfd, 0xe4a: 0x2bfd, 0xe4b: 0x2bfd,
+	0xe4c: 0x2c1d, 0xe4d: 0x2c1d, 0xe4e: 0x2c1d, 0xe4f: 0x2c3d, 0xe50: 0x2c5d, 0xe51: 0x2c5d,
+	0xe52: 0x2a7d, 0xe53: 0x2a7d, 0xe54: 0x2c5d, 0xe55: 0x2c5d, 0xe56: 0x2c7d, 0xe57: 0x2c7d,
+	0xe58: 0x2c5d, 0xe59: 0x2c5d, 0xe5a: 0x2a7d, 0xe5b: 0x2a7d, 0xe5c: 0x2c5d, 0xe5d: 0x2c5d,
+	0xe5e: 0x2c3d, 0xe5f: 0x2c3d, 0xe60: 0x2c9d, 0xe61: 0x2c9d, 0xe62: 0x2cbd, 0xe63: 0x2cbd,
+	0xe64: 0x0040, 0xe65: 0x2cdd, 0xe66: 0x2cfd, 0xe67: 0x2d1d, 0xe68: 0x2d1d, 0xe69: 0x2d3d,
+	0xe6a: 0x2d5d, 0xe6b: 0x2d7d, 0xe6c: 0x2d9d, 0xe6d: 0x2dbd, 0xe6e: 0x2ddd, 0xe6f: 0x2dfd,
+	0xe70: 0x2e1d, 0xe71: 0x2e3d, 0xe72: 0x2e3d, 0xe73: 0x2e5d, 0xe74: 0x2e7d, 0xe75: 0x2e7d,
+	0xe76: 0x2e9d, 0xe77: 0x2ebd, 0xe78: 0x2e5d, 0xe79: 0x2edd, 0xe7a: 0x2efd, 0xe7b: 0x2edd,
+	0xe7c: 0x2e5d, 0xe7d: 0x2f1d, 0xe7e: 0x2f3d, 0xe7f: 0x2f5d,
+	// Block 0x3a, offset 0xe80
+	0xe80: 0x2f7d, 0xe81: 0x2f9d, 0xe82: 0x2cfd, 0xe83: 0x2cdd, 0xe84: 0x2fbd, 0xe85: 0x2fdd,
+	0xe86: 0x2ffd, 0xe87: 0x301d, 0xe88: 0x303d, 0xe89: 0x305d, 0xe8a: 0x307d, 0xe8b: 0x309d,
+	0xe8c: 0x30bd, 0xe8d: 0x30dd, 0xe8e: 0x30fd, 0xe8f: 0x0040, 0xe90: 0x0018, 0xe91: 0x0018,
+	0xe92: 0x311d, 0xe93: 0x313d, 0xe94: 0x315d, 0xe95: 0x317d, 0xe96: 0x319d, 0xe97: 0x31bd,
+	0xe98: 0x31dd, 0xe99: 0x31fd, 0xe9a: 0x321d, 0xe9b: 0x323d, 0xe9c: 0x315d, 0xe9d: 0x325d,
+	0xe9e: 0x327d, 0xe9f: 0x329d, 0xea0: 0x0008, 0xea1: 0x0008, 0xea2: 0x0008, 0xea3: 0x0008,
+	0xea4: 0x0008, 0xea5: 0x0008, 0xea6: 0x0008, 0xea7: 0x0008, 0xea8: 0x0008, 0xea9: 0x0008,
+	0xeaa: 0x0008, 0xeab: 0x0008, 0xeac: 0x0008, 0xead: 0x0008, 0xeae: 0x0008, 0xeaf: 0x0008,
+	0xeb0: 0x0008, 0xeb1: 0x0008, 0xeb2: 0x0008, 0xeb3: 0x0008, 0xeb4: 0x0008, 0xeb5: 0x0008,
+	0xeb6: 0x0008, 0xeb7: 0x0008, 0xeb8: 0x0008, 0xeb9: 0x0008, 0xeba: 0x0008, 0xebb: 0x0040,
+	0xebc: 0x0040, 0xebd: 0x0040, 0xebe: 0x0040, 0xebf: 0x0040,
+	// Block 0x3b, offset 0xec0
+	0xec0: 0x36a2, 0xec1: 0x36d2, 0xec2: 0x3702, 0xec3: 0x3732, 0xec4: 0x32bd, 0xec5: 0x32dd,
+	0xec6: 0x32fd, 0xec7: 0x331d, 0xec8: 0x0018, 0xec9: 0x0018, 0xeca: 0x0018, 0xecb: 0x0018,
+	0xecc: 0x0018, 0xecd: 0x0018, 0xece: 0x0018, 0xecf: 0x0018, 0xed0: 0x333d, 0xed1: 0x3761,
+	0xed2: 0x3779, 0xed3: 0x3791, 0xed4: 0x37a9, 0xed5: 0x37c1, 0xed6: 0x37d9, 0xed7: 0x37f1,
+	0xed8: 0x3809, 0xed9: 0x3821, 0xeda: 0x3839, 0xedb: 0x3851, 0xedc: 0x3869, 0xedd: 0x3881,
+	0xede: 0x3899, 0xedf: 0x38b1, 0xee0: 0x335d, 0xee1: 0x337d, 0xee2: 0x339d, 0xee3: 0x33bd,
+	0xee4: 0x33dd, 0xee5: 0x33dd, 0xee6: 0x33fd, 0xee7: 0x341d, 0xee8: 0x343d, 0xee9: 0x345d,
+	0xeea: 0x347d, 0xeeb: 0x349d, 0xeec: 0x34bd, 0xeed: 0x34dd, 0xeee: 0x34fd, 0xeef: 0x351d,
+	0xef0: 0x353d, 0xef1: 0x355d, 0xef2: 0x357d, 0xef3: 0x359d, 0xef4: 0x35bd, 0xef5: 0x35dd,
+	0xef6: 0x35fd, 0xef7: 0x361d, 0xef8: 0x363d, 0xef9: 0x365d, 0xefa: 0x367d, 0xefb: 0x369d,
+	0xefc: 0x38c9, 0xefd: 0x3901, 0xefe: 0x36bd, 0xeff: 0x0018,
+	// Block 0x3c, offset 0xf00
+	0xf00: 0x36dd, 0xf01: 0x36fd, 0xf02: 0x371d, 0xf03: 0x373d, 0xf04: 0x375d, 0xf05: 0x377d,
+	0xf06: 0x379d, 0xf07: 0x37bd, 0xf08: 0x37dd, 0xf09: 0x37fd, 0xf0a: 0x381d, 0xf0b: 0x383d,
+	0xf0c: 0x385d, 0xf0d: 0x387d, 0xf0e: 0x389d, 0xf0f: 0x38bd, 0xf10: 0x38dd, 0xf11: 0x38fd,
+	0xf12: 0x391d, 0xf13: 0x393d, 0xf14: 0x395d, 0xf15: 0x397d, 0xf16: 0x399d, 0xf17: 0x39bd,
+	0xf18: 0x39dd, 0xf19: 0x39fd, 0xf1a: 0x3a1d, 0xf1b: 0x3a3d, 0xf1c: 0x3a5d, 0xf1d: 0x3a7d,
+	0xf1e: 0x3a9d, 0xf1f: 0x3abd, 0xf20: 0x3add, 0xf21: 0x3afd, 0xf22: 0x3b1d, 0xf23: 0x3b3d,
+	0xf24: 0x3b5d, 0xf25: 0x3b7d, 0xf26: 0x127d, 0xf27: 0x3b9d, 0xf28: 0x3bbd, 0xf29: 0x3bdd,
+	0xf2a: 0x3bfd, 0xf2b: 0x3c1d, 0xf2c: 0x3c3d, 0xf2d: 0x3c5d, 0xf2e: 0x239d, 0xf2f: 0x3c7d,
+	0xf30: 0x3c9d, 0xf31: 0x3939, 0xf32: 0x3951, 0xf33: 0x3969, 0xf34: 0x3981, 0xf35: 0x3999,
+	0xf36: 0x39b1, 0xf37: 0x39c9, 0xf38: 0x39e1, 0xf39: 0x39f9, 0xf3a: 0x3a11, 0xf3b: 0x3a29,
+	0xf3c: 0x3a41, 0xf3d: 0x3a59, 0xf3e: 0x3a71, 0xf3f: 0x3a89,
+	// Block 0x3d, offset 0xf40
+	0xf40: 0x3aa1, 0xf41: 0x3ac9, 0xf42: 0x3af1, 0xf43: 0x3b19, 0xf44: 0x3b41, 0xf45: 0x3b69,
+	0xf46: 0x3b91, 0xf47: 0x3bb9, 0xf48: 0x3be1, 0xf49: 0x3c09, 0xf4a: 0x3c39, 0xf4b: 0x3c69,
+	0xf4c: 0x3c99, 0xf4d: 0x3cbd, 0xf4e: 0x3cb1, 0xf4f: 0x3cdd, 0xf50: 0x3cfd, 0xf51: 0x3d15,
+	0xf52: 0x3d2d, 0xf53: 0x3d45, 0xf54: 0x3d5d, 0xf55: 0x3d5d, 0xf56: 0x3d45, 0xf57: 0x3d75,
+	0xf58: 0x07bd, 0xf59: 0x3d8d, 0xf5a: 0x3da5, 0xf5b: 0x3dbd, 0xf5c: 0x3dd5, 0xf5d: 0x3ded,
+	0xf5e: 0x3e05, 0xf5f: 0x3e1d, 0xf60: 0x3e35, 0xf61: 0x3e4d, 0xf62: 0x3e65, 0xf63: 0x3e7d,
+	0xf64: 0x3e95, 0xf65: 0x3e95, 0xf66: 0x3ead, 0xf67: 0x3ead, 0xf68: 0x3ec5, 0xf69: 0x3ec5,
+	0xf6a: 0x3edd, 0xf6b: 0x3ef5, 0xf6c: 0x3f0d, 0xf6d: 0x3f25, 0xf6e: 0x3f3d, 0xf6f: 0x3f3d,
+	0xf70: 0x3f55, 0xf71: 0x3f55, 0xf72: 0x3f55, 0xf73: 0x3f6d, 0xf74: 0x3f85, 0xf75: 0x3f9d,
+	0xf76: 0x3fb5, 0xf77: 0x3f9d, 0xf78: 0x3fcd, 0xf79: 0x3fe5, 0xf7a: 0x3f6d, 0xf7b: 0x3ffd,
+	0xf7c: 0x4015, 0xf7d: 0x4015, 0xf7e: 0x4015, 0xf7f: 0x0040,
+	// Block 0x3e, offset 0xf80
+	0xf80: 0x3cc9, 0xf81: 0x3d31, 0xf82: 0x3d99, 0xf83: 0x3e01, 0xf84: 0x3e51, 0xf85: 0x3eb9,
+	0xf86: 0x3f09, 0xf87: 0x3f59, 0xf88: 0x3fd9, 0xf89: 0x4041, 0xf8a: 0x4091, 0xf8b: 0x40e1,
+	0xf8c: 0x4131, 0xf8d: 0x4199, 0xf8e: 0x4201, 0xf8f: 0x4251, 0xf90: 0x42a1, 0xf91: 0x42d9,
+	0xf92: 0x4329, 0xf93: 0x4391, 0xf94: 0x43f9, 0xf95: 0x4431, 0xf96: 0x44b1, 0xf97: 0x4549,
+	0xf98: 0x45c9, 0xf99: 0x4619, 0xf9a: 0x4699, 0xf9b: 0x4719, 0xf9c: 0x4781, 0xf9d: 0x47d1,
+	0xf9e: 0x4821, 0xf9f: 0x4871, 0xfa0: 0x48d9, 0xfa1: 0x4959, 0xfa2: 0x49c1, 0xfa3: 0x4a11,
+	0xfa4: 0x4a61, 0xfa5: 0x4ab1, 0xfa6: 0x4ae9, 0xfa7: 0x4b21, 0xfa8: 0x4b59, 0xfa9: 0x4b91,
+	0xfaa: 0x4be1, 0xfab: 0x4c31, 0xfac: 0x4cb1, 0xfad: 0x4d01, 0xfae: 0x4d69, 0xfaf: 0x4de9,
+	0xfb0: 0x4e39, 0xfb1: 0x4e71, 0xfb2: 0x4ea9, 0xfb3: 0x4f29, 0xfb4: 0x4f91, 0xfb5: 0x5011,
+	0xfb6: 0x5061, 0xfb7: 0x50e1, 0xfb8: 0x5119, 0xfb9: 0x5169, 0xfba: 0x51b9, 0xfbb: 0x5209,
+	0xfbc: 0x5259, 0xfbd: 0x52a9, 0xfbe: 0x5311, 0xfbf: 0x5361,
+	// Block 0x3f, offset 0xfc0
+	0xfc0: 0x5399, 0xfc1: 0x53e9, 0xfc2: 0x5439, 0xfc3: 0x5489, 0xfc4: 0x54f1, 0xfc5: 0x5541,
+	0xfc6: 0x5591, 0xfc7: 0x55e1, 0xfc8: 0x5661, 0xfc9: 0x56c9, 0xfca: 0x5701, 0xfcb: 0x5781,
+	0xfcc: 0x57b9, 0xfcd: 0x5821, 0xfce: 0x5889, 0xfcf: 0x58d9, 0xfd0: 0x5929, 0xfd1: 0x5979,
+	0xfd2: 0x59e1, 0xfd3: 0x5a19, 0xfd4: 0x5a69, 0xfd5: 0x5ad1, 0xfd6: 0x5b09, 0xfd7: 0x5b89,
+	0xfd8: 0x5bd9, 0xfd9: 0x5c01, 0xfda: 0x5c29, 0xfdb: 0x5c51, 0xfdc: 0x5c79, 0xfdd: 0x5ca1,
+	0xfde: 0x5cc9, 0xfdf: 0x5cf1, 0xfe0: 0x5d19, 0xfe1: 0x5d41, 0xfe2: 0x5d69, 0xfe3: 0x5d99,
+	0xfe4: 0x5dc9, 0xfe5: 0x5df9, 0xfe6: 0x5e29, 0xfe7: 0x5e59, 0xfe8: 0x5e89, 0xfe9: 0x5eb9,
+	0xfea: 0x5ee9, 0xfeb: 0x5f19, 0xfec: 0x5f49, 0xfed: 0x5f79, 0xfee: 0x5fa9, 0xfef: 0x5fd9,
+	0xff0: 0x6009, 0xff1: 0x402d, 0xff2: 0x6039, 0xff3: 0x6051, 0xff4: 0x404d, 0xff5: 0x6069,
+	0xff6: 0x6081, 0xff7: 0x6099, 0xff8: 0x406d, 0xff9: 0x406d, 0xffa: 0x60b1, 0xffb: 0x60c9,
+	0xffc: 0x6101, 0xffd: 0x6139, 0xffe: 0x6171, 0xfff: 0x61a9,
+	// Block 0x40, offset 0x1000
+	0x1000: 0x6211, 0x1001: 0x6229, 0x1002: 0x408d, 0x1003: 0x6241, 0x1004: 0x6259, 0x1005: 0x6271,
+	0x1006: 0x6289, 0x1007: 0x62a1, 0x1008: 0x40ad, 0x1009: 0x62b9, 0x100a: 0x62e1, 0x100b: 0x62f9,
+	0x100c: 0x40cd, 0x100d: 0x40cd, 0x100e: 0x6311, 0x100f: 0x6329, 0x1010: 0x6341, 0x1011: 0x40ed,
+	0x1012: 0x410d, 0x1013: 0x412d, 0x1014: 0x414d, 0x1015: 0x416d, 0x1016: 0x6359, 0x1017: 0x6371,
+	0x1018: 0x6389, 0x1019: 0x63a1, 0x101a: 0x63b9, 0x101b: 0x418d, 0x101c: 0x63d1, 0x101d: 0x63e9,
+	0x101e: 0x6401, 0x101f: 0x41ad, 0x1020: 0x41cd, 0x1021: 0x6419, 0x1022: 0x41ed, 0x1023: 0x420d,
+	0x1024: 0x422d, 0x1025: 0x6431, 0x1026: 0x424d, 0x1027: 0x6449, 0x1028: 0x6479, 0x1029: 0x6211,
+	0x102a: 0x426d, 0x102b: 0x428d, 0x102c: 0x42ad, 0x102d: 0x42cd, 0x102e: 0x64b1, 0x102f: 0x64f1,
+	0x1030: 0x6539, 0x1031: 0x6551, 0x1032: 0x42ed, 0x1033: 0x6569, 0x1034: 0x6581, 0x1035: 0x6599,
+	0x1036: 0x430d, 0x1037: 0x65b1, 0x1038: 0x65c9, 0x1039: 0x65b1, 0x103a: 0x65e1, 0x103b: 0x65f9,
+	0x103c: 0x432d, 0x103d: 0x6611, 0x103e: 0x6629, 0x103f: 0x6611,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x434d, 0x1041: 0x436d, 0x1042: 0x0040, 0x1043: 0x6641, 0x1044: 0x6659, 0x1045: 0x6671,
+	0x1046: 0x6689, 0x1047: 0x0040, 0x1048: 0x66c1, 0x1049: 0x66d9, 0x104a: 0x66f1, 0x104b: 0x6709,
+	0x104c: 0x6721, 0x104d: 0x6739, 0x104e: 0x6401, 0x104f: 0x6751, 0x1050: 0x6769, 0x1051: 0x6781,
+	0x1052: 0x438d, 0x1053: 0x6799, 0x1054: 0x6289, 0x1055: 0x43ad, 0x1056: 0x43cd, 0x1057: 0x67b1,
+	0x1058: 0x0040, 0x1059: 0x43ed, 0x105a: 0x67c9, 0x105b: 0x67e1, 0x105c: 0x67f9, 0x105d: 0x6811,
+	0x105e: 0x6829, 0x105f: 0x6859, 0x1060: 0x6889, 0x1061: 0x68b1, 0x1062: 0x68d9, 0x1063: 0x6901,
+	0x1064: 0x6929, 0x1065: 0x6951, 0x1066: 0x6979, 0x1067: 0x69a1, 0x1068: 0x69c9, 0x1069: 0x69f1,
+	0x106a: 0x6a21, 0x106b: 0x6a51, 0x106c: 0x6a81, 0x106d: 0x6ab1, 0x106e: 0x6ae1, 0x106f: 0x6b11,
+	0x1070: 0x6b41, 0x1071: 0x6b71, 0x1072: 0x6ba1, 0x1073: 0x6bd1, 0x1074: 0x6c01, 0x1075: 0x6c31,
+	0x1076: 0x6c61, 0x1077: 0x6c91, 0x1078: 0x6cc1, 0x1079: 0x6cf1, 0x107a: 0x6d21, 0x107b: 0x6d51,
+	0x107c: 0x6d81, 0x107d: 0x6db1, 0x107e: 0x6de1, 0x107f: 0x440d,
+	// Block 0x42, offset 0x1080
+	0x1080: 0xe00d, 0x1081: 0x0008, 0x1082: 0xe00d, 0x1083: 0x0008, 0x1084: 0xe00d, 0x1085: 0x0008,
+	0x1086: 0xe00d, 0x1087: 0x0008, 0x1088: 0xe00d, 0x1089: 0x0008, 0x108a: 0xe00d, 0x108b: 0x0008,
+	0x108c: 0xe00d, 0x108d: 0x0008, 0x108e: 0xe00d, 0x108f: 0x0008, 0x1090: 0xe00d, 0x1091: 0x0008,
+	0x1092: 0xe00d, 0x1093: 0x0008, 0x1094: 0xe00d, 0x1095: 0x0008, 0x1096: 0xe00d, 0x1097: 0x0008,
+	0x1098: 0xe00d, 0x1099: 0x0008, 0x109a: 0xe00d, 0x109b: 0x0008, 0x109c: 0xe00d, 0x109d: 0x0008,
+	0x109e: 0xe00d, 0x109f: 0x0008, 0x10a0: 0xe00d, 0x10a1: 0x0008, 0x10a2: 0xe00d, 0x10a3: 0x0008,
+	0x10a4: 0xe00d, 0x10a5: 0x0008, 0x10a6: 0xe00d, 0x10a7: 0x0008, 0x10a8: 0xe00d, 0x10a9: 0x0008,
+	0x10aa: 0xe00d, 0x10ab: 0x0008, 0x10ac: 0xe00d, 0x10ad: 0x0008, 0x10ae: 0x0008, 0x10af: 0x1308,
+	0x10b0: 0x1318, 0x10b1: 0x1318, 0x10b2: 0x1318, 0x10b3: 0x0018, 0x10b4: 0x1308, 0x10b5: 0x1308,
+	0x10b6: 0x1308, 0x10b7: 0x1308, 0x10b8: 0x1308, 0x10b9: 0x1308, 0x10ba: 0x1308, 0x10bb: 0x1308,
+	0x10bc: 0x1308, 0x10bd: 0x1308, 0x10be: 0x0018, 0x10bf: 0x0008,
+	// Block 0x43, offset 0x10c0
+	0x10c0: 0xe00d, 0x10c1: 0x0008, 0x10c2: 0xe00d, 0x10c3: 0x0008, 0x10c4: 0xe00d, 0x10c5: 0x0008,
+	0x10c6: 0xe00d, 0x10c7: 0x0008, 0x10c8: 0xe00d, 0x10c9: 0x0008, 0x10ca: 0xe00d, 0x10cb: 0x0008,
+	0x10cc: 0xe00d, 0x10cd: 0x0008, 0x10ce: 0xe00d, 0x10cf: 0x0008, 0x10d0: 0xe00d, 0x10d1: 0x0008,
+	0x10d2: 0xe00d, 0x10d3: 0x0008, 0x10d4: 0xe00d, 0x10d5: 0x0008, 0x10d6: 0xe00d, 0x10d7: 0x0008,
+	0x10d8: 0xe00d, 0x10d9: 0x0008, 0x10da: 0xe00d, 0x10db: 0x0008, 0x10dc: 0x0ea1, 0x10dd: 0x6e11,
+	0x10de: 0x1308, 0x10df: 0x1308, 0x10e0: 0x0008, 0x10e1: 0x0008, 0x10e2: 0x0008, 0x10e3: 0x0008,
+	0x10e4: 0x0008, 0x10e5: 0x0008, 0x10e6: 0x0008, 0x10e7: 0x0008, 0x10e8: 0x0008, 0x10e9: 0x0008,
+	0x10ea: 0x0008, 0x10eb: 0x0008, 0x10ec: 0x0008, 0x10ed: 0x0008, 0x10ee: 0x0008, 0x10ef: 0x0008,
+	0x10f0: 0x0008, 0x10f1: 0x0008, 0x10f2: 0x0008, 0x10f3: 0x0008, 0x10f4: 0x0008, 0x10f5: 0x0008,
+	0x10f6: 0x0008, 0x10f7: 0x0008, 0x10f8: 0x0008, 0x10f9: 0x0008, 0x10fa: 0x0008, 0x10fb: 0x0008,
+	0x10fc: 0x0008, 0x10fd: 0x0008, 0x10fe: 0x0008, 0x10ff: 0x0008,
+	// Block 0x44, offset 0x1100
+	0x1100: 0x0018, 0x1101: 0x0018, 0x1102: 0x0018, 0x1103: 0x0018, 0x1104: 0x0018, 0x1105: 0x0018,
+	0x1106: 0x0018, 0x1107: 0x0018, 0x1108: 0x0018, 0x1109: 0x0018, 0x110a: 0x0018, 0x110b: 0x0018,
+	0x110c: 0x0018, 0x110d: 0x0018, 0x110e: 0x0018, 0x110f: 0x0018, 0x1110: 0x0018, 0x1111: 0x0018,
+	0x1112: 0x0018, 0x1113: 0x0018, 0x1114: 0x0018, 0x1115: 0x0018, 0x1116: 0x0018, 0x1117: 0x0008,
+	0x1118: 0x0008, 0x1119: 0x0008, 0x111a: 0x0008, 0x111b: 0x0008, 0x111c: 0x0008, 0x111d: 0x0008,
+	0x111e: 0x0008, 0x111f: 0x0008, 0x1120: 0x0018, 0x1121: 0x0018, 0x1122: 0xe00d, 0x1123: 0x0008,
+	0x1124: 0xe00d, 0x1125: 0x0008, 0x1126: 0xe00d, 0x1127: 0x0008, 0x1128: 0xe00d, 0x1129: 0x0008,
+	0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0xe00d, 0x112f: 0x0008,
+	0x1130: 0x0008, 0x1131: 0x0008, 0x1132: 0xe00d, 0x1133: 0x0008, 0x1134: 0xe00d, 0x1135: 0x0008,
+	0x1136: 0xe00d, 0x1137: 0x0008, 0x1138: 0xe00d, 0x1139: 0x0008, 0x113a: 0xe00d, 0x113b: 0x0008,
+	0x113c: 0xe00d, 0x113d: 0x0008, 0x113e: 0xe00d, 0x113f: 0x0008,
+	// Block 0x45, offset 0x1140
+	0x1140: 0xe00d, 0x1141: 0x0008, 0x1142: 0xe00d, 0x1143: 0x0008, 0x1144: 0xe00d, 0x1145: 0x0008,
+	0x1146: 0xe00d, 0x1147: 0x0008, 0x1148: 0xe00d, 0x1149: 0x0008, 0x114a: 0xe00d, 0x114b: 0x0008,
+	0x114c: 0xe00d, 0x114d: 0x0008, 0x114e: 0xe00d, 0x114f: 0x0008, 0x1150: 0xe00d, 0x1151: 0x0008,
+	0x1152: 0xe00d, 0x1153: 0x0008, 0x1154: 0xe00d, 0x1155: 0x0008, 0x1156: 0xe00d, 0x1157: 0x0008,
+	0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0xe00d, 0x115d: 0x0008,
+	0x115e: 0xe00d, 0x115f: 0x0008, 0x1160: 0xe00d, 0x1161: 0x0008, 0x1162: 0xe00d, 0x1163: 0x0008,
+	0x1164: 0xe00d, 0x1165: 0x0008, 0x1166: 0xe00d, 0x1167: 0x0008, 0x1168: 0xe00d, 0x1169: 0x0008,
+	0x116a: 0xe00d, 0x116b: 0x0008, 0x116c: 0xe00d, 0x116d: 0x0008, 0x116e: 0xe00d, 0x116f: 0x0008,
+	0x1170: 0xe0fd, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008,
+	0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0xe01d, 0x117a: 0x0008, 0x117b: 0xe03d,
+	0x117c: 0x0008, 0x117d: 0x442d, 0x117e: 0xe00d, 0x117f: 0x0008,
+	// Block 0x46, offset 0x1180
+	0x1180: 0xe00d, 0x1181: 0x0008, 0x1182: 0xe00d, 0x1183: 0x0008, 0x1184: 0xe00d, 0x1185: 0x0008,
+	0x1186: 0xe00d, 0x1187: 0x0008, 0x1188: 0x0008, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0xe03d,
+	0x118c: 0x0008, 0x118d: 0x11d9, 0x118e: 0x0008, 0x118f: 0x0008, 0x1190: 0xe00d, 0x1191: 0x0008,
+	0x1192: 0xe00d, 0x1193: 0x0008, 0x1194: 0x0008, 0x1195: 0x0008, 0x1196: 0xe00d, 0x1197: 0x0008,
+	0x1198: 0xe00d, 0x1199: 0x0008, 0x119a: 0xe00d, 0x119b: 0x0008, 0x119c: 0xe00d, 0x119d: 0x0008,
+	0x119e: 0xe00d, 0x119f: 0x0008, 0x11a0: 0xe00d, 0x11a1: 0x0008, 0x11a2: 0xe00d, 0x11a3: 0x0008,
+	0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008,
+	0x11aa: 0x6e29, 0x11ab: 0x1029, 0x11ac: 0x11c1, 0x11ad: 0x6e41, 0x11ae: 0x1221, 0x11af: 0x0040,
+	0x11b0: 0x6e59, 0x11b1: 0x6e71, 0x11b2: 0x1239, 0x11b3: 0x444d, 0x11b4: 0xe00d, 0x11b5: 0x0008,
+	0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0x0040, 0x11b9: 0x0040, 0x11ba: 0x0040, 0x11bb: 0x0040,
+	0x11bc: 0x0040, 0x11bd: 0x0040, 0x11be: 0x0040, 0x11bf: 0x0040,
+	// Block 0x47, offset 0x11c0
+	0x11c0: 0x64d5, 0x11c1: 0x64f5, 0x11c2: 0x6515, 0x11c3: 0x6535, 0x11c4: 0x6555, 0x11c5: 0x6575,
+	0x11c6: 0x6595, 0x11c7: 0x65b5, 0x11c8: 0x65d5, 0x11c9: 0x65f5, 0x11ca: 0x6615, 0x11cb: 0x6635,
+	0x11cc: 0x6655, 0x11cd: 0x6675, 0x11ce: 0x0008, 0x11cf: 0x0008, 0x11d0: 0x6695, 0x11d1: 0x0008,
+	0x11d2: 0x66b5, 0x11d3: 0x0008, 0x11d4: 0x0008, 0x11d5: 0x66d5, 0x11d6: 0x66f5, 0x11d7: 0x6715,
+	0x11d8: 0x6735, 0x11d9: 0x6755, 0x11da: 0x6775, 0x11db: 0x6795, 0x11dc: 0x67b5, 0x11dd: 0x67d5,
+	0x11de: 0x67f5, 0x11df: 0x0008, 0x11e0: 0x6815, 0x11e1: 0x0008, 0x11e2: 0x6835, 0x11e3: 0x0008,
+	0x11e4: 0x0008, 0x11e5: 0x6855, 0x11e6: 0x6875, 0x11e7: 0x0008, 0x11e8: 0x0008, 0x11e9: 0x0008,
+	0x11ea: 0x6895, 0x11eb: 0x68b5, 0x11ec: 0x68d5, 0x11ed: 0x68f5, 0x11ee: 0x6915, 0x11ef: 0x6935,
+	0x11f0: 0x6955, 0x11f1: 0x6975, 0x11f2: 0x6995, 0x11f3: 0x69b5, 0x11f4: 0x69d5, 0x11f5: 0x69f5,
+	0x11f6: 0x6a15, 0x11f7: 0x6a35, 0x11f8: 0x6a55, 0x11f9: 0x6a75, 0x11fa: 0x6a95, 0x11fb: 0x6ab5,
+	0x11fc: 0x6ad5, 0x11fd: 0x6af5, 0x11fe: 0x6b15, 0x11ff: 0x6b35,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x7a95, 0x1201: 0x7ab5, 0x1202: 0x7ad5, 0x1203: 0x7af5, 0x1204: 0x7b15, 0x1205: 0x7b35,
+	0x1206: 0x7b55, 0x1207: 0x7b75, 0x1208: 0x7b95, 0x1209: 0x7bb5, 0x120a: 0x7bd5, 0x120b: 0x7bf5,
+	0x120c: 0x7c15, 0x120d: 0x7c35, 0x120e: 0x7c55, 0x120f: 0x6ec9, 0x1210: 0x6ef1, 0x1211: 0x6f19,
+	0x1212: 0x7c75, 0x1213: 0x7c95, 0x1214: 0x7cb5, 0x1215: 0x6f41, 0x1216: 0x6f69, 0x1217: 0x6f91,
+	0x1218: 0x7cd5, 0x1219: 0x7cf5, 0x121a: 0x0040, 0x121b: 0x0040, 0x121c: 0x0040, 0x121d: 0x0040,
+	0x121e: 0x0040, 0x121f: 0x0040, 0x1220: 0x0040, 0x1221: 0x0040, 0x1222: 0x0040, 0x1223: 0x0040,
+	0x1224: 0x0040, 0x1225: 0x0040, 0x1226: 0x0040, 0x1227: 0x0040, 0x1228: 0x0040, 0x1229: 0x0040,
+	0x122a: 0x0040, 0x122b: 0x0040, 0x122c: 0x0040, 0x122d: 0x0040, 0x122e: 0x0040, 0x122f: 0x0040,
+	0x1230: 0x0040, 0x1231: 0x0040, 0x1232: 0x0040, 0x1233: 0x0040, 0x1234: 0x0040, 0x1235: 0x0040,
+	0x1236: 0x0040, 0x1237: 0x0040, 0x1238: 0x0040, 0x1239: 0x0040, 0x123a: 0x0040, 0x123b: 0x0040,
+	0x123c: 0x0040, 0x123d: 0x0040, 0x123e: 0x0040, 0x123f: 0x0040,
+	// Block 0x49, offset 0x1240
+	0x1240: 0x6fb9, 0x1241: 0x6fd1, 0x1242: 0x6fe9, 0x1243: 0x7d15, 0x1244: 0x7d35, 0x1245: 0x7001,
+	0x1246: 0x7001, 0x1247: 0x0040, 0x1248: 0x0040, 0x1249: 0x0040, 0x124a: 0x0040, 0x124b: 0x0040,
+	0x124c: 0x0040, 0x124d: 0x0040, 0x124e: 0x0040, 0x124f: 0x0040, 0x1250: 0x0040, 0x1251: 0x0040,
+	0x1252: 0x0040, 0x1253: 0x7019, 0x1254: 0x7041, 0x1255: 0x7069, 0x1256: 0x7091, 0x1257: 0x70b9,
+	0x1258: 0x0040, 0x1259: 0x0040, 0x125a: 0x0040, 0x125b: 0x0040, 0x125c: 0x0040, 0x125d: 0x70e1,
+	0x125e: 0x1308, 0x125f: 0x7109, 0x1260: 0x7131, 0x1261: 0x20a9, 0x1262: 0x20f1, 0x1263: 0x7149,
+	0x1264: 0x7161, 0x1265: 0x7179, 0x1266: 0x7191, 0x1267: 0x71a9, 0x1268: 0x71c1, 0x1269: 0x1fb2,
+	0x126a: 0x71d9, 0x126b: 0x7201, 0x126c: 0x7229, 0x126d: 0x7261, 0x126e: 0x7299, 0x126f: 0x72c1,
+	0x1270: 0x72e9, 0x1271: 0x7311, 0x1272: 0x7339, 0x1273: 0x7361, 0x1274: 0x7389, 0x1275: 0x73b1,
+	0x1276: 0x73d9, 0x1277: 0x0040, 0x1278: 0x7401, 0x1279: 0x7429, 0x127a: 0x7451, 0x127b: 0x7479,
+	0x127c: 0x74a1, 0x127d: 0x0040, 0x127e: 0x74c9, 0x127f: 0x0040,
+	// Block 0x4a, offset 0x1280
+	0x1280: 0x74f1, 0x1281: 0x7519, 0x1282: 0x0040, 0x1283: 0x7541, 0x1284: 0x7569, 0x1285: 0x0040,
+	0x1286: 0x7591, 0x1287: 0x75b9, 0x1288: 0x75e1, 0x1289: 0x7609, 0x128a: 0x7631, 0x128b: 0x7659,
+	0x128c: 0x7681, 0x128d: 0x76a9, 0x128e: 0x76d1, 0x128f: 0x76f9, 0x1290: 0x7721, 0x1291: 0x7721,
+	0x1292: 0x7739, 0x1293: 0x7739, 0x1294: 0x7739, 0x1295: 0x7739, 0x1296: 0x7751, 0x1297: 0x7751,
+	0x1298: 0x7751, 0x1299: 0x7751, 0x129a: 0x7769, 0x129b: 0x7769, 0x129c: 0x7769, 0x129d: 0x7769,
+	0x129e: 0x7781, 0x129f: 0x7781, 0x12a0: 0x7781, 0x12a1: 0x7781, 0x12a2: 0x7799, 0x12a3: 0x7799,
+	0x12a4: 0x7799, 0x12a5: 0x7799, 0x12a6: 0x77b1, 0x12a7: 0x77b1, 0x12a8: 0x77b1, 0x12a9: 0x77b1,
+	0x12aa: 0x77c9, 0x12ab: 0x77c9, 0x12ac: 0x77c9, 0x12ad: 0x77c9, 0x12ae: 0x77e1, 0x12af: 0x77e1,
+	0x12b0: 0x77e1, 0x12b1: 0x77e1, 0x12b2: 0x77f9, 0x12b3: 0x77f9, 0x12b4: 0x77f9, 0x12b5: 0x77f9,
+	0x12b6: 0x7811, 0x12b7: 0x7811, 0x12b8: 0x7811, 0x12b9: 0x7811, 0x12ba: 0x7829, 0x12bb: 0x7829,
+	0x12bc: 0x7829, 0x12bd: 0x7829, 0x12be: 0x7841, 0x12bf: 0x7841,
+	// Block 0x4b, offset 0x12c0
+	0x12c0: 0x7841, 0x12c1: 0x7841, 0x12c2: 0x7859, 0x12c3: 0x7859, 0x12c4: 0x7871, 0x12c5: 0x7871,
+	0x12c6: 0x7889, 0x12c7: 0x7889, 0x12c8: 0x78a1, 0x12c9: 0x78a1, 0x12ca: 0x78b9, 0x12cb: 0x78b9,
+	0x12cc: 0x78d1, 0x12cd: 0x78d1, 0x12ce: 0x78e9, 0x12cf: 0x78e9, 0x12d0: 0x78e9, 0x12d1: 0x78e9,
+	0x12d2: 0x7901, 0x12d3: 0x7901, 0x12d4: 0x7901, 0x12d5: 0x7901, 0x12d6: 0x7919, 0x12d7: 0x7919,
+	0x12d8: 0x7919, 0x12d9: 0x7919, 0x12da: 0x7931, 0x12db: 0x7931, 0x12dc: 0x7931, 0x12dd: 0x7931,
+	0x12de: 0x7949, 0x12df: 0x7949, 0x12e0: 0x7961, 0x12e1: 0x7961, 0x12e2: 0x7961, 0x12e3: 0x7961,
+	0x12e4: 0x7979, 0x12e5: 0x7979, 0x12e6: 0x7991, 0x12e7: 0x7991, 0x12e8: 0x7991, 0x12e9: 0x7991,
+	0x12ea: 0x79a9, 0x12eb: 0x79a9, 0x12ec: 0x79a9, 0x12ed: 0x79a9, 0x12ee: 0x79c1, 0x12ef: 0x79c1,
+	0x12f0: 0x79d9, 0x12f1: 0x79d9, 0x12f2: 0x0018, 0x12f3: 0x0018, 0x12f4: 0x0018, 0x12f5: 0x0018,
+	0x12f6: 0x0018, 0x12f7: 0x0018, 0x12f8: 0x0018, 0x12f9: 0x0018, 0x12fa: 0x0018, 0x12fb: 0x0018,
+	0x12fc: 0x0018, 0x12fd: 0x0018, 0x12fe: 0x0018, 0x12ff: 0x0018,
+	// Block 0x4c, offset 0x1300
+	0x1300: 0x0018, 0x1301: 0x0018, 0x1302: 0x0040, 0x1303: 0x0040, 0x1304: 0x0040, 0x1305: 0x0040,
+	0x1306: 0x0040, 0x1307: 0x0040, 0x1308: 0x0040, 0x1309: 0x0040, 0x130a: 0x0040, 0x130b: 0x0040,
+	0x130c: 0x0040, 0x130d: 0x0040, 0x130e: 0x0040, 0x130f: 0x0040, 0x1310: 0x0040, 0x1311: 0x0040,
+	0x1312: 0x0040, 0x1313: 0x79f1, 0x1314: 0x79f1, 0x1315: 0x79f1, 0x1316: 0x79f1, 0x1317: 0x7a09,
+	0x1318: 0x7a09, 0x1319: 0x7a21, 0x131a: 0x7a21, 0x131b: 0x7a39, 0x131c: 0x7a39, 0x131d: 0x0479,
+	0x131e: 0x7a51, 0x131f: 0x7a51, 0x1320: 0x7a69, 0x1321: 0x7a69, 0x1322: 0x7a81, 0x1323: 0x7a81,
+	0x1324: 0x7a99, 0x1325: 0x7a99, 0x1326: 0x7a99, 0x1327: 0x7a99, 0x1328: 0x7ab1, 0x1329: 0x7ab1,
+	0x132a: 0x7ac9, 0x132b: 0x7ac9, 0x132c: 0x7af1, 0x132d: 0x7af1, 0x132e: 0x7b19, 0x132f: 0x7b19,
+	0x1330: 0x7b41, 0x1331: 0x7b41, 0x1332: 0x7b69, 0x1333: 0x7b69, 0x1334: 0x7b91, 0x1335: 0x7b91,
+	0x1336: 0x7bb9, 0x1337: 0x7bb9, 0x1338: 0x7bb9, 0x1339: 0x7be1, 0x133a: 0x7be1, 0x133b: 0x7be1,
+	0x133c: 0x7c09, 0x133d: 0x7c09, 0x133e: 0x7c09, 0x133f: 0x7c09,
+	// Block 0x4d, offset 0x1340
+	0x1340: 0x85f9, 0x1341: 0x8621, 0x1342: 0x8649, 0x1343: 0x8671, 0x1344: 0x8699, 0x1345: 0x86c1,
+	0x1346: 0x86e9, 0x1347: 0x8711, 0x1348: 0x8739, 0x1349: 0x8761, 0x134a: 0x8789, 0x134b: 0x87b1,
+	0x134c: 0x87d9, 0x134d: 0x8801, 0x134e: 0x8829, 0x134f: 0x8851, 0x1350: 0x8879, 0x1351: 0x88a1,
+	0x1352: 0x88c9, 0x1353: 0x88f1, 0x1354: 0x8919, 0x1355: 0x8941, 0x1356: 0x8969, 0x1357: 0x8991,
+	0x1358: 0x89b9, 0x1359: 0x89e1, 0x135a: 0x8a09, 0x135b: 0x8a31, 0x135c: 0x8a59, 0x135d: 0x8a81,
+	0x135e: 0x8aaa, 0x135f: 0x8ada, 0x1360: 0x8b0a, 0x1361: 0x8b3a, 0x1362: 0x8b6a, 0x1363: 0x8b9a,
+	0x1364: 0x8bc9, 0x1365: 0x8bf1, 0x1366: 0x7c71, 0x1367: 0x8c19, 0x1368: 0x7be1, 0x1369: 0x7c99,
+	0x136a: 0x8c41, 0x136b: 0x8c69, 0x136c: 0x7d39, 0x136d: 0x8c91, 0x136e: 0x7d61, 0x136f: 0x7d89,
+	0x1370: 0x8cb9, 0x1371: 0x8ce1, 0x1372: 0x7e29, 0x1373: 0x8d09, 0x1374: 0x7e51, 0x1375: 0x7e79,
+	0x1376: 0x8d31, 0x1377: 0x8d59, 0x1378: 0x7ec9, 0x1379: 0x8d81, 0x137a: 0x7ef1, 0x137b: 0x7f19,
+	0x137c: 0x83a1, 0x137d: 0x83c9, 0x137e: 0x8441, 0x137f: 0x8469,
+	// Block 0x4e, offset 0x1380
+	0x1380: 0x8491, 0x1381: 0x8531, 0x1382: 0x8559, 0x1383: 0x8581, 0x1384: 0x85a9, 0x1385: 0x8649,
+	0x1386: 0x8671, 0x1387: 0x8699, 0x1388: 0x8da9, 0x1389: 0x8739, 0x138a: 0x8dd1, 0x138b: 0x8df9,
+	0x138c: 0x8829, 0x138d: 0x8e21, 0x138e: 0x8851, 0x138f: 0x8879, 0x1390: 0x8a81, 0x1391: 0x8e49,
+	0x1392: 0x8e71, 0x1393: 0x89b9, 0x1394: 0x8e99, 0x1395: 0x89e1, 0x1396: 0x8a09, 0x1397: 0x7c21,
+	0x1398: 0x7c49, 0x1399: 0x8ec1, 0x139a: 0x7c71, 0x139b: 0x8ee9, 0x139c: 0x7cc1, 0x139d: 0x7ce9,
+	0x139e: 0x7d11, 0x139f: 0x7d39, 0x13a0: 0x8f11, 0x13a1: 0x7db1, 0x13a2: 0x7dd9, 0x13a3: 0x7e01,
+	0x13a4: 0x7e29, 0x13a5: 0x8f39, 0x13a6: 0x7ec9, 0x13a7: 0x7f41, 0x13a8: 0x7f69, 0x13a9: 0x7f91,
+	0x13aa: 0x7fb9, 0x13ab: 0x7fe1, 0x13ac: 0x8031, 0x13ad: 0x8059, 0x13ae: 0x8081, 0x13af: 0x80a9,
+	0x13b0: 0x80d1, 0x13b1: 0x80f9, 0x13b2: 0x8f61, 0x13b3: 0x8121, 0x13b4: 0x8149, 0x13b5: 0x8171,
+	0x13b6: 0x8199, 0x13b7: 0x81c1, 0x13b8: 0x81e9, 0x13b9: 0x8239, 0x13ba: 0x8261, 0x13bb: 0x8289,
+	0x13bc: 0x82b1, 0x13bd: 0x82d9, 0x13be: 0x8301, 0x13bf: 0x8329,
+	// Block 0x4f, offset 0x13c0
+	0x13c0: 0x8351, 0x13c1: 0x8379, 0x13c2: 0x83f1, 0x13c3: 0x8419, 0x13c4: 0x84b9, 0x13c5: 0x84e1,
+	0x13c6: 0x8509, 0x13c7: 0x8531, 0x13c8: 0x8559, 0x13c9: 0x85d1, 0x13ca: 0x85f9, 0x13cb: 0x8621,
+	0x13cc: 0x8649, 0x13cd: 0x8f89, 0x13ce: 0x86c1, 0x13cf: 0x86e9, 0x13d0: 0x8711, 0x13d1: 0x8739,
+	0x13d2: 0x87b1, 0x13d3: 0x87d9, 0x13d4: 0x8801, 0x13d5: 0x8829, 0x13d6: 0x8fb1, 0x13d7: 0x88a1,
+	0x13d8: 0x88c9, 0x13d9: 0x8fd9, 0x13da: 0x8941, 0x13db: 0x8969, 0x13dc: 0x8991, 0x13dd: 0x89b9,
+	0x13de: 0x9001, 0x13df: 0x7c71, 0x13e0: 0x8ee9, 0x13e1: 0x7d39, 0x13e2: 0x8f11, 0x13e3: 0x7e29,
+	0x13e4: 0x8f39, 0x13e5: 0x7ec9, 0x13e6: 0x9029, 0x13e7: 0x80d1, 0x13e8: 0x9051, 0x13e9: 0x9079,
+	0x13ea: 0x90a1, 0x13eb: 0x8531, 0x13ec: 0x8559, 0x13ed: 0x8649, 0x13ee: 0x8829, 0x13ef: 0x8fb1,
+	0x13f0: 0x89b9, 0x13f1: 0x9001, 0x13f2: 0x90c9, 0x13f3: 0x9101, 0x13f4: 0x9139, 0x13f5: 0x9171,
+	0x13f6: 0x9199, 0x13f7: 0x91c1, 0x13f8: 0x91e9, 0x13f9: 0x9211, 0x13fa: 0x9239, 0x13fb: 0x9261,
+	0x13fc: 0x9289, 0x13fd: 0x92b1, 0x13fe: 0x92d9, 0x13ff: 0x9301,
+	// Block 0x50, offset 0x1400
+	0x1400: 0x9329, 0x1401: 0x9351, 0x1402: 0x9379, 0x1403: 0x93a1, 0x1404: 0x93c9, 0x1405: 0x93f1,
+	0x1406: 0x9419, 0x1407: 0x9441, 0x1408: 0x9469, 0x1409: 0x9491, 0x140a: 0x94b9, 0x140b: 0x94e1,
+	0x140c: 0x9079, 0x140d: 0x9509, 0x140e: 0x9531, 0x140f: 0x9559, 0x1410: 0x9581, 0x1411: 0x9171,
+	0x1412: 0x9199, 0x1413: 0x91c1, 0x1414: 0x91e9, 0x1415: 0x9211, 0x1416: 0x9239, 0x1417: 0x9261,
+	0x1418: 0x9289, 0x1419: 0x92b1, 0x141a: 0x92d9, 0x141b: 0x9301, 0x141c: 0x9329, 0x141d: 0x9351,
+	0x141e: 0x9379, 0x141f: 0x93a1, 0x1420: 0x93c9, 0x1421: 0x93f1, 0x1422: 0x9419, 0x1423: 0x9441,
+	0x1424: 0x9469, 0x1425: 0x9491, 0x1426: 0x94b9, 0x1427: 0x94e1, 0x1428: 0x9079, 0x1429: 0x9509,
+	0x142a: 0x9531, 0x142b: 0x9559, 0x142c: 0x9581, 0x142d: 0x9491, 0x142e: 0x94b9, 0x142f: 0x94e1,
+	0x1430: 0x9079, 0x1431: 0x9051, 0x1432: 0x90a1, 0x1433: 0x8211, 0x1434: 0x8059, 0x1435: 0x8081,
+	0x1436: 0x80a9, 0x1437: 0x9491, 0x1438: 0x94b9, 0x1439: 0x94e1, 0x143a: 0x8211, 0x143b: 0x8239,
+	0x143c: 0x95a9, 0x143d: 0x95a9, 0x143e: 0x0018, 0x143f: 0x0018,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x0040, 0x1441: 0x0040, 0x1442: 0x0040, 0x1443: 0x0040, 0x1444: 0x0040, 0x1445: 0x0040,
+	0x1446: 0x0040, 0x1447: 0x0040, 0x1448: 0x0040, 0x1449: 0x0040, 0x144a: 0x0040, 0x144b: 0x0040,
+	0x144c: 0x0040, 0x144d: 0x0040, 0x144e: 0x0040, 0x144f: 0x0040, 0x1450: 0x95d1, 0x1451: 0x9609,
+	0x1452: 0x9609, 0x1453: 0x9641, 0x1454: 0x9679, 0x1455: 0x96b1, 0x1456: 0x96e9, 0x1457: 0x9721,
+	0x1458: 0x9759, 0x1459: 0x9759, 0x145a: 0x9791, 0x145b: 0x97c9, 0x145c: 0x9801, 0x145d: 0x9839,
+	0x145e: 0x9871, 0x145f: 0x98a9, 0x1460: 0x98a9, 0x1461: 0x98e1, 0x1462: 0x9919, 0x1463: 0x9919,
+	0x1464: 0x9951, 0x1465: 0x9951, 0x1466: 0x9989, 0x1467: 0x99c1, 0x1468: 0x99c1, 0x1469: 0x99f9,
+	0x146a: 0x9a31, 0x146b: 0x9a31, 0x146c: 0x9a69, 0x146d: 0x9a69, 0x146e: 0x9aa1, 0x146f: 0x9ad9,
+	0x1470: 0x9ad9, 0x1471: 0x9b11, 0x1472: 0x9b11, 0x1473: 0x9b49, 0x1474: 0x9b81, 0x1475: 0x9bb9,
+	0x1476: 0x9bf1, 0x1477: 0x9bf1, 0x1478: 0x9c29, 0x1479: 0x9c61, 0x147a: 0x9c99, 0x147b: 0x9cd1,
+	0x147c: 0x9d09, 0x147d: 0x9d09, 0x147e: 0x9d41, 0x147f: 0x9d79,
+	// Block 0x52, offset 0x1480
+	0x1480: 0xa949, 0x1481: 0xa981, 0x1482: 0xa9b9, 0x1483: 0xa8a1, 0x1484: 0x9bb9, 0x1485: 0x9989,
+	0x1486: 0xa9f1, 0x1487: 0xaa29, 0x1488: 0x0040, 0x1489: 0x0040, 0x148a: 0x0040, 0x148b: 0x0040,
+	0x148c: 0x0040, 0x148d: 0x0040, 0x148e: 0x0040, 0x148f: 0x0040, 0x1490: 0x0040, 0x1491: 0x0040,
+	0x1492: 0x0040, 0x1493: 0x0040, 0x1494: 0x0040, 0x1495: 0x0040, 0x1496: 0x0040, 0x1497: 0x0040,
+	0x1498: 0x0040, 0x1499: 0x0040, 0x149a: 0x0040, 0x149b: 0x0040, 0x149c: 0x0040, 0x149d: 0x0040,
+	0x149e: 0x0040, 0x149f: 0x0040, 0x14a0: 0x0040, 0x14a1: 0x0040, 0x14a2: 0x0040, 0x14a3: 0x0040,
+	0x14a4: 0x0040, 0x14a5: 0x0040, 0x14a6: 0x0040, 0x14a7: 0x0040, 0x14a8: 0x0040, 0x14a9: 0x0040,
+	0x14aa: 0x0040, 0x14ab: 0x0040, 0x14ac: 0x0040, 0x14ad: 0x0040, 0x14ae: 0x0040, 0x14af: 0x0040,
+	0x14b0: 0xaa61, 0x14b1: 0xaa99, 0x14b2: 0xaad1, 0x14b3: 0xab19, 0x14b4: 0xab61, 0x14b5: 0xaba9,
+	0x14b6: 0xabf1, 0x14b7: 0xac39, 0x14b8: 0xac81, 0x14b9: 0xacc9, 0x14ba: 0xad02, 0x14bb: 0xae12,
+	0x14bc: 0xae91, 0x14bd: 0x0018, 0x14be: 0x0040, 0x14bf: 0x0040,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x13c0, 0x14c1: 0x13c0, 0x14c2: 0x13c0, 0x14c3: 0x13c0, 0x14c4: 0x13c0, 0x14c5: 0x13c0,
+	0x14c6: 0x13c0, 0x14c7: 0x13c0, 0x14c8: 0x13c0, 0x14c9: 0x13c0, 0x14ca: 0x13c0, 0x14cb: 0x13c0,
+	0x14cc: 0x13c0, 0x14cd: 0x13c0, 0x14ce: 0x13c0, 0x14cf: 0x13c0, 0x14d0: 0xaeda, 0x14d1: 0x7d55,
+	0x14d2: 0x0040, 0x14d3: 0xaeea, 0x14d4: 0x03c2, 0x14d5: 0xaefa, 0x14d6: 0xaf0a, 0x14d7: 0x7d75,
+	0x14d8: 0x7d95, 0x14d9: 0x0040, 0x14da: 0x0040, 0x14db: 0x0040, 0x14dc: 0x0040, 0x14dd: 0x0040,
+	0x14de: 0x0040, 0x14df: 0x0040, 0x14e0: 0x1308, 0x14e1: 0x1308, 0x14e2: 0x1308, 0x14e3: 0x1308,
+	0x14e4: 0x1308, 0x14e5: 0x1308, 0x14e6: 0x1308, 0x14e7: 0x1308, 0x14e8: 0x1308, 0x14e9: 0x1308,
+	0x14ea: 0x1308, 0x14eb: 0x1308, 0x14ec: 0x1308, 0x14ed: 0x1308, 0x14ee: 0x1308, 0x14ef: 0x1308,
+	0x14f0: 0x0040, 0x14f1: 0x7db5, 0x14f2: 0x7dd5, 0x14f3: 0xaf1a, 0x14f4: 0xaf1a, 0x14f5: 0x1fd2,
+	0x14f6: 0x1fe2, 0x14f7: 0xaf2a, 0x14f8: 0xaf3a, 0x14f9: 0x7df5, 0x14fa: 0x7e15, 0x14fb: 0x7e35,
+	0x14fc: 0x7df5, 0x14fd: 0x7e55, 0x14fe: 0x7e75, 0x14ff: 0x7e55,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x7e95, 0x1501: 0x7eb5, 0x1502: 0x7ed5, 0x1503: 0x7eb5, 0x1504: 0x7ef5, 0x1505: 0x0018,
+	0x1506: 0x0018, 0x1507: 0xaf4a, 0x1508: 0xaf5a, 0x1509: 0x7f16, 0x150a: 0x7f36, 0x150b: 0x7f56,
+	0x150c: 0x7f76, 0x150d: 0xaf1a, 0x150e: 0xaf1a, 0x150f: 0xaf1a, 0x1510: 0xaeda, 0x1511: 0x7f95,
+	0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x03c2, 0x1515: 0xaeea, 0x1516: 0xaf0a, 0x1517: 0xaefa,
+	0x1518: 0x7fb5, 0x1519: 0x1fd2, 0x151a: 0x1fe2, 0x151b: 0xaf2a, 0x151c: 0xaf3a, 0x151d: 0x7e95,
+	0x151e: 0x7ef5, 0x151f: 0xaf6a, 0x1520: 0xaf7a, 0x1521: 0xaf8a, 0x1522: 0x1fb2, 0x1523: 0xaf99,
+	0x1524: 0xafaa, 0x1525: 0xafba, 0x1526: 0x1fc2, 0x1527: 0x0040, 0x1528: 0xafca, 0x1529: 0xafda,
+	0x152a: 0xafea, 0x152b: 0xaffa, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040,
+	0x1530: 0x7fd6, 0x1531: 0xb009, 0x1532: 0x7ff6, 0x1533: 0x0008, 0x1534: 0x8016, 0x1535: 0x0040,
+	0x1536: 0x8036, 0x1537: 0xb031, 0x1538: 0x8056, 0x1539: 0xb059, 0x153a: 0x8076, 0x153b: 0xb081,
+	0x153c: 0x8096, 0x153d: 0xb0a9, 0x153e: 0x80b6, 0x153f: 0xb0d1,
+	// Block 0x55, offset 0x1540
+	0x1540: 0xb0f9, 0x1541: 0xb111, 0x1542: 0xb111, 0x1543: 0xb129, 0x1544: 0xb129, 0x1545: 0xb141,
+	0x1546: 0xb141, 0x1547: 0xb159, 0x1548: 0xb159, 0x1549: 0xb171, 0x154a: 0xb171, 0x154b: 0xb171,
+	0x154c: 0xb171, 0x154d: 0xb189, 0x154e: 0xb189, 0x154f: 0xb1a1, 0x1550: 0xb1a1, 0x1551: 0xb1a1,
+	0x1552: 0xb1a1, 0x1553: 0xb1b9, 0x1554: 0xb1b9, 0x1555: 0xb1d1, 0x1556: 0xb1d1, 0x1557: 0xb1d1,
+	0x1558: 0xb1d1, 0x1559: 0xb1e9, 0x155a: 0xb1e9, 0x155b: 0xb1e9, 0x155c: 0xb1e9, 0x155d: 0xb201,
+	0x155e: 0xb201, 0x155f: 0xb201, 0x1560: 0xb201, 0x1561: 0xb219, 0x1562: 0xb219, 0x1563: 0xb219,
+	0x1564: 0xb219, 0x1565: 0xb231, 0x1566: 0xb231, 0x1567: 0xb231, 0x1568: 0xb231, 0x1569: 0xb249,
+	0x156a: 0xb249, 0x156b: 0xb261, 0x156c: 0xb261, 0x156d: 0xb279, 0x156e: 0xb279, 0x156f: 0xb291,
+	0x1570: 0xb291, 0x1571: 0xb2a9, 0x1572: 0xb2a9, 0x1573: 0xb2a9, 0x1574: 0xb2a9, 0x1575: 0xb2c1,
+	0x1576: 0xb2c1, 0x1577: 0xb2c1, 0x1578: 0xb2c1, 0x1579: 0xb2d9, 0x157a: 0xb2d9, 0x157b: 0xb2d9,
+	0x157c: 0xb2d9, 0x157d: 0xb2f1, 0x157e: 0xb2f1, 0x157f: 0xb2f1,
+	// Block 0x56, offset 0x1580
+	0x1580: 0xb2f1, 0x1581: 0xb309, 0x1582: 0xb309, 0x1583: 0xb309, 0x1584: 0xb309, 0x1585: 0xb321,
+	0x1586: 0xb321, 0x1587: 0xb321, 0x1588: 0xb321, 0x1589: 0xb339, 0x158a: 0xb339, 0x158b: 0xb339,
+	0x158c: 0xb339, 0x158d: 0xb351, 0x158e: 0xb351, 0x158f: 0xb351, 0x1590: 0xb351, 0x1591: 0xb369,
+	0x1592: 0xb369, 0x1593: 0xb369, 0x1594: 0xb369, 0x1595: 0xb381, 0x1596: 0xb381, 0x1597: 0xb381,
+	0x1598: 0xb381, 0x1599: 0xb399, 0x159a: 0xb399, 0x159b: 0xb399, 0x159c: 0xb399, 0x159d: 0xb3b1,
+	0x159e: 0xb3b1, 0x159f: 0xb3b1, 0x15a0: 0xb3b1, 0x15a1: 0xb3c9, 0x15a2: 0xb3c9, 0x15a3: 0xb3c9,
+	0x15a4: 0xb3c9, 0x15a5: 0xb3e1, 0x15a6: 0xb3e1, 0x15a7: 0xb3e1, 0x15a8: 0xb3e1, 0x15a9: 0xb3f9,
+	0x15aa: 0xb3f9, 0x15ab: 0xb3f9, 0x15ac: 0xb3f9, 0x15ad: 0xb411, 0x15ae: 0xb411, 0x15af: 0x7ab1,
+	0x15b0: 0x7ab1, 0x15b1: 0xb429, 0x15b2: 0xb429, 0x15b3: 0xb429, 0x15b4: 0xb429, 0x15b5: 0xb441,
+	0x15b6: 0xb441, 0x15b7: 0xb469, 0x15b8: 0xb469, 0x15b9: 0xb491, 0x15ba: 0xb491, 0x15bb: 0xb4b9,
+	0x15bc: 0xb4b9, 0x15bd: 0x0040, 0x15be: 0x0040, 0x15bf: 0x03c0,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x0040, 0x15c1: 0xaefa, 0x15c2: 0xb4e2, 0x15c3: 0xaf6a, 0x15c4: 0xafda, 0x15c5: 0xafea,
+	0x15c6: 0xaf7a, 0x15c7: 0xb4f2, 0x15c8: 0x1fd2, 0x15c9: 0x1fe2, 0x15ca: 0xaf8a, 0x15cb: 0x1fb2,
+	0x15cc: 0xaeda, 0x15cd: 0xaf99, 0x15ce: 0x29d1, 0x15cf: 0xb502, 0x15d0: 0x1f41, 0x15d1: 0x00c9,
+	0x15d2: 0x0069, 0x15d3: 0x0079, 0x15d4: 0x1f51, 0x15d5: 0x1f61, 0x15d6: 0x1f71, 0x15d7: 0x1f81,
+	0x15d8: 0x1f91, 0x15d9: 0x1fa1, 0x15da: 0xaeea, 0x15db: 0x03c2, 0x15dc: 0xafaa, 0x15dd: 0x1fc2,
+	0x15de: 0xafba, 0x15df: 0xaf0a, 0x15e0: 0xaffa, 0x15e1: 0x0039, 0x15e2: 0x0ee9, 0x15e3: 0x1159,
+	0x15e4: 0x0ef9, 0x15e5: 0x0f09, 0x15e6: 0x1199, 0x15e7: 0x0f31, 0x15e8: 0x0249, 0x15e9: 0x0f41,
+	0x15ea: 0x0259, 0x15eb: 0x0f51, 0x15ec: 0x0359, 0x15ed: 0x0f61, 0x15ee: 0x0f71, 0x15ef: 0x00d9,
+	0x15f0: 0x0f99, 0x15f1: 0x2039, 0x15f2: 0x0269, 0x15f3: 0x01d9, 0x15f4: 0x0fa9, 0x15f5: 0x0fb9,
+	0x15f6: 0x1089, 0x15f7: 0x0279, 0x15f8: 0x0369, 0x15f9: 0x0289, 0x15fa: 0x13d1, 0x15fb: 0xaf4a,
+	0x15fc: 0xafca, 0x15fd: 0xaf5a, 0x15fe: 0xb512, 0x15ff: 0xaf1a,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x1caa, 0x1601: 0x0039, 0x1602: 0x0ee9, 0x1603: 0x1159, 0x1604: 0x0ef9, 0x1605: 0x0f09,
+	0x1606: 0x1199, 0x1607: 0x0f31, 0x1608: 0x0249, 0x1609: 0x0f41, 0x160a: 0x0259, 0x160b: 0x0f51,
+	0x160c: 0x0359, 0x160d: 0x0f61, 0x160e: 0x0f71, 0x160f: 0x00d9, 0x1610: 0x0f99, 0x1611: 0x2039,
+	0x1612: 0x0269, 0x1613: 0x01d9, 0x1614: 0x0fa9, 0x1615: 0x0fb9, 0x1616: 0x1089, 0x1617: 0x0279,
+	0x1618: 0x0369, 0x1619: 0x0289, 0x161a: 0x13d1, 0x161b: 0xaf2a, 0x161c: 0xb522, 0x161d: 0xaf3a,
+	0x161e: 0xb532, 0x161f: 0x80d5, 0x1620: 0x80f5, 0x1621: 0x29d1, 0x1622: 0x8115, 0x1623: 0x8115,
+	0x1624: 0x8135, 0x1625: 0x8155, 0x1626: 0x8175, 0x1627: 0x8195, 0x1628: 0x81b5, 0x1629: 0x81d5,
+	0x162a: 0x81f5, 0x162b: 0x8215, 0x162c: 0x8235, 0x162d: 0x8255, 0x162e: 0x8275, 0x162f: 0x8295,
+	0x1630: 0x82b5, 0x1631: 0x82d5, 0x1632: 0x82f5, 0x1633: 0x8315, 0x1634: 0x8335, 0x1635: 0x8355,
+	0x1636: 0x8375, 0x1637: 0x8395, 0x1638: 0x83b5, 0x1639: 0x83d5, 0x163a: 0x83f5, 0x163b: 0x8415,
+	0x163c: 0x81b5, 0x163d: 0x8435, 0x163e: 0x8455, 0x163f: 0x8215,
+	// Block 0x59, offset 0x1640
+	0x1640: 0x8475, 0x1641: 0x8495, 0x1642: 0x84b5, 0x1643: 0x84d5, 0x1644: 0x84f5, 0x1645: 0x8515,
+	0x1646: 0x8535, 0x1647: 0x8555, 0x1648: 0x84d5, 0x1649: 0x8575, 0x164a: 0x84d5, 0x164b: 0x8595,
+	0x164c: 0x8595, 0x164d: 0x85b5, 0x164e: 0x85b5, 0x164f: 0x85d5, 0x1650: 0x8515, 0x1651: 0x85f5,
+	0x1652: 0x8615, 0x1653: 0x85f5, 0x1654: 0x8635, 0x1655: 0x8615, 0x1656: 0x8655, 0x1657: 0x8655,
+	0x1658: 0x8675, 0x1659: 0x8675, 0x165a: 0x8695, 0x165b: 0x8695, 0x165c: 0x8615, 0x165d: 0x8115,
+	0x165e: 0x86b5, 0x165f: 0x86d5, 0x1660: 0x0040, 0x1661: 0x86f5, 0x1662: 0x8715, 0x1663: 0x8735,
+	0x1664: 0x8755, 0x1665: 0x8735, 0x1666: 0x8775, 0x1667: 0x8795, 0x1668: 0x87b5, 0x1669: 0x87b5,
+	0x166a: 0x87d5, 0x166b: 0x87d5, 0x166c: 0x87f5, 0x166d: 0x87f5, 0x166e: 0x87d5, 0x166f: 0x87d5,
+	0x1670: 0x8815, 0x1671: 0x8835, 0x1672: 0x8855, 0x1673: 0x8875, 0x1674: 0x8895, 0x1675: 0x88b5,
+	0x1676: 0x88b5, 0x1677: 0x88b5, 0x1678: 0x88d5, 0x1679: 0x88d5, 0x167a: 0x88d5, 0x167b: 0x88d5,
+	0x167c: 0x87b5, 0x167d: 0x87b5, 0x167e: 0x87b5, 0x167f: 0x0040,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x0040, 0x1681: 0x0040, 0x1682: 0x8715, 0x1683: 0x86f5, 0x1684: 0x88f5, 0x1685: 0x86f5,
+	0x1686: 0x8715, 0x1687: 0x86f5, 0x1688: 0x0040, 0x1689: 0x0040, 0x168a: 0x8915, 0x168b: 0x8715,
+	0x168c: 0x8935, 0x168d: 0x88f5, 0x168e: 0x8935, 0x168f: 0x8715, 0x1690: 0x0040, 0x1691: 0x0040,
+	0x1692: 0x8955, 0x1693: 0x8975, 0x1694: 0x8875, 0x1695: 0x8935, 0x1696: 0x88f5, 0x1697: 0x8935,
+	0x1698: 0x0040, 0x1699: 0x0040, 0x169a: 0x8995, 0x169b: 0x89b5, 0x169c: 0x8995, 0x169d: 0x0040,
+	0x169e: 0x0040, 0x169f: 0x0040, 0x16a0: 0xb541, 0x16a1: 0xb559, 0x16a2: 0xb571, 0x16a3: 0x89d6,
+	0x16a4: 0xb589, 0x16a5: 0xb5a1, 0x16a6: 0x89f5, 0x16a7: 0x0040, 0x16a8: 0x8a15, 0x16a9: 0x8a35,
+	0x16aa: 0x8a55, 0x16ab: 0x8a35, 0x16ac: 0x8a75, 0x16ad: 0x8a95, 0x16ae: 0x8ab5, 0x16af: 0x0040,
+	0x16b0: 0x0040, 0x16b1: 0x0040, 0x16b2: 0x0040, 0x16b3: 0x0040, 0x16b4: 0x0040, 0x16b5: 0x0040,
+	0x16b6: 0x0040, 0x16b7: 0x0040, 0x16b8: 0x0040, 0x16b9: 0x0340, 0x16ba: 0x0340, 0x16bb: 0x0340,
+	0x16bc: 0x0040, 0x16bd: 0x0040, 0x16be: 0x0040, 0x16bf: 0x0040,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x0208, 0x16c1: 0x0208, 0x16c2: 0x0208, 0x16c3: 0x0208, 0x16c4: 0x0208, 0x16c5: 0x0408,
+	0x16c6: 0x0008, 0x16c7: 0x0408, 0x16c8: 0x0018, 0x16c9: 0x0408, 0x16ca: 0x0408, 0x16cb: 0x0008,
+	0x16cc: 0x0008, 0x16cd: 0x0108, 0x16ce: 0x0408, 0x16cf: 0x0408, 0x16d0: 0x0408, 0x16d1: 0x0408,
+	0x16d2: 0x0408, 0x16d3: 0x0208, 0x16d4: 0x0208, 0x16d5: 0x0208, 0x16d6: 0x0208, 0x16d7: 0x0108,
+	0x16d8: 0x0208, 0x16d9: 0x0208, 0x16da: 0x0208, 0x16db: 0x0208, 0x16dc: 0x0208, 0x16dd: 0x0408,
+	0x16de: 0x0208, 0x16df: 0x0208, 0x16e0: 0x0208, 0x16e1: 0x0408, 0x16e2: 0x0008, 0x16e3: 0x0008,
+	0x16e4: 0x0408, 0x16e5: 0x1308, 0x16e6: 0x1308, 0x16e7: 0x0040, 0x16e8: 0x0040, 0x16e9: 0x0040,
+	0x16ea: 0x0040, 0x16eb: 0x0218, 0x16ec: 0x0218, 0x16ed: 0x0218, 0x16ee: 0x0218, 0x16ef: 0x0418,
+	0x16f0: 0x0018, 0x16f1: 0x0018, 0x16f2: 0x0018, 0x16f3: 0x0018, 0x16f4: 0x0018, 0x16f5: 0x0018,
+	0x16f6: 0x0018, 0x16f7: 0x0040, 0x16f8: 0x0040, 0x16f9: 0x0040, 0x16fa: 0x0040, 0x16fb: 0x0040,
+	0x16fc: 0x0040, 0x16fd: 0x0040, 0x16fe: 0x0040, 0x16ff: 0x0040,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x0208, 0x1701: 0x0408, 0x1702: 0x0208, 0x1703: 0x0408, 0x1704: 0x0408, 0x1705: 0x0408,
+	0x1706: 0x0208, 0x1707: 0x0208, 0x1708: 0x0208, 0x1709: 0x0408, 0x170a: 0x0208, 0x170b: 0x0208,
+	0x170c: 0x0408, 0x170d: 0x0208, 0x170e: 0x0408, 0x170f: 0x0408, 0x1710: 0x0208, 0x1711: 0x0408,
+	0x1712: 0x0040, 0x1713: 0x0040, 0x1714: 0x0040, 0x1715: 0x0040, 0x1716: 0x0040, 0x1717: 0x0040,
+	0x1718: 0x0040, 0x1719: 0x0018, 0x171a: 0x0018, 0x171b: 0x0018, 0x171c: 0x0018, 0x171d: 0x0040,
+	0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0x0040, 0x1721: 0x0040, 0x1722: 0x0040, 0x1723: 0x0040,
+	0x1724: 0x0040, 0x1725: 0x0040, 0x1726: 0x0040, 0x1727: 0x0040, 0x1728: 0x0040, 0x1729: 0x0418,
+	0x172a: 0x0418, 0x172b: 0x0418, 0x172c: 0x0418, 0x172d: 0x0218, 0x172e: 0x0218, 0x172f: 0x0018,
+	0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040,
+	0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0040, 0x173a: 0x0040, 0x173b: 0x0040,
+	0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040,
+	// Block 0x5d, offset 0x1740
+	0x1740: 0x1308, 0x1741: 0x1308, 0x1742: 0x1008, 0x1743: 0x1008, 0x1744: 0x0040, 0x1745: 0x0008,
+	0x1746: 0x0008, 0x1747: 0x0008, 0x1748: 0x0008, 0x1749: 0x0008, 0x174a: 0x0008, 0x174b: 0x0008,
+	0x174c: 0x0008, 0x174d: 0x0040, 0x174e: 0x0040, 0x174f: 0x0008, 0x1750: 0x0008, 0x1751: 0x0040,
+	0x1752: 0x0040, 0x1753: 0x0008, 0x1754: 0x0008, 0x1755: 0x0008, 0x1756: 0x0008, 0x1757: 0x0008,
+	0x1758: 0x0008, 0x1759: 0x0008, 0x175a: 0x0008, 0x175b: 0x0008, 0x175c: 0x0008, 0x175d: 0x0008,
+	0x175e: 0x0008, 0x175f: 0x0008, 0x1760: 0x0008, 0x1761: 0x0008, 0x1762: 0x0008, 0x1763: 0x0008,
+	0x1764: 0x0008, 0x1765: 0x0008, 0x1766: 0x0008, 0x1767: 0x0008, 0x1768: 0x0008, 0x1769: 0x0040,
+	0x176a: 0x0008, 0x176b: 0x0008, 0x176c: 0x0008, 0x176d: 0x0008, 0x176e: 0x0008, 0x176f: 0x0008,
+	0x1770: 0x0008, 0x1771: 0x0040, 0x1772: 0x0008, 0x1773: 0x0008, 0x1774: 0x0040, 0x1775: 0x0008,
+	0x1776: 0x0008, 0x1777: 0x0008, 0x1778: 0x0008, 0x1779: 0x0008, 0x177a: 0x0040, 0x177b: 0x0040,
+	0x177c: 0x1308, 0x177d: 0x0008, 0x177e: 0x1008, 0x177f: 0x1008,
+	// Block 0x5e, offset 0x1780
+	0x1780: 0x1308, 0x1781: 0x1008, 0x1782: 0x1008, 0x1783: 0x1008, 0x1784: 0x1008, 0x1785: 0x0040,
+	0x1786: 0x0040, 0x1787: 0x1008, 0x1788: 0x1008, 0x1789: 0x0040, 0x178a: 0x0040, 0x178b: 0x1008,
+	0x178c: 0x1008, 0x178d: 0x1808, 0x178e: 0x0040, 0x178f: 0x0040, 0x1790: 0x0008, 0x1791: 0x0040,
+	0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x1008,
+	0x1798: 0x0040, 0x1799: 0x0040, 0x179a: 0x0040, 0x179b: 0x0040, 0x179c: 0x0040, 0x179d: 0x0008,
+	0x179e: 0x0008, 0x179f: 0x0008, 0x17a0: 0x0008, 0x17a1: 0x0008, 0x17a2: 0x1008, 0x17a3: 0x1008,
+	0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x1308, 0x17a7: 0x1308, 0x17a8: 0x1308, 0x17a9: 0x1308,
+	0x17aa: 0x1308, 0x17ab: 0x1308, 0x17ac: 0x1308, 0x17ad: 0x0040, 0x17ae: 0x0040, 0x17af: 0x0040,
+	0x17b0: 0x1308, 0x17b1: 0x1308, 0x17b2: 0x1308, 0x17b3: 0x1308, 0x17b4: 0x1308, 0x17b5: 0x0040,
+	0x17b6: 0x0040, 0x17b7: 0x0040, 0x17b8: 0x0040, 0x17b9: 0x0040, 0x17ba: 0x0040, 0x17bb: 0x0040,
+	0x17bc: 0x0040, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040,
+	// Block 0x5f, offset 0x17c0
+	0x17c0: 0x0039, 0x17c1: 0x0ee9, 0x17c2: 0x1159, 0x17c3: 0x0ef9, 0x17c4: 0x0f09, 0x17c5: 0x1199,
+	0x17c6: 0x0f31, 0x17c7: 0x0249, 0x17c8: 0x0f41, 0x17c9: 0x0259, 0x17ca: 0x0f51, 0x17cb: 0x0359,
+	0x17cc: 0x0f61, 0x17cd: 0x0f71, 0x17ce: 0x00d9, 0x17cf: 0x0f99, 0x17d0: 0x2039, 0x17d1: 0x0269,
+	0x17d2: 0x01d9, 0x17d3: 0x0fa9, 0x17d4: 0x0fb9, 0x17d5: 0x1089, 0x17d6: 0x0279, 0x17d7: 0x0369,
+	0x17d8: 0x0289, 0x17d9: 0x13d1, 0x17da: 0x0039, 0x17db: 0x0ee9, 0x17dc: 0x1159, 0x17dd: 0x0ef9,
+	0x17de: 0x0f09, 0x17df: 0x1199, 0x17e0: 0x0f31, 0x17e1: 0x0249, 0x17e2: 0x0f41, 0x17e3: 0x0259,
+	0x17e4: 0x0f51, 0x17e5: 0x0359, 0x17e6: 0x0f61, 0x17e7: 0x0f71, 0x17e8: 0x00d9, 0x17e9: 0x0f99,
+	0x17ea: 0x2039, 0x17eb: 0x0269, 0x17ec: 0x01d9, 0x17ed: 0x0fa9, 0x17ee: 0x0fb9, 0x17ef: 0x1089,
+	0x17f0: 0x0279, 0x17f1: 0x0369, 0x17f2: 0x0289, 0x17f3: 0x13d1, 0x17f4: 0x0039, 0x17f5: 0x0ee9,
+	0x17f6: 0x1159, 0x17f7: 0x0ef9, 0x17f8: 0x0f09, 0x17f9: 0x1199, 0x17fa: 0x0f31, 0x17fb: 0x0249,
+	0x17fc: 0x0f41, 0x17fd: 0x0259, 0x17fe: 0x0f51, 0x17ff: 0x0359,
+	// Block 0x60, offset 0x1800
+	0x1800: 0x0f61, 0x1801: 0x0f71, 0x1802: 0x00d9, 0x1803: 0x0f99, 0x1804: 0x2039, 0x1805: 0x0269,
+	0x1806: 0x01d9, 0x1807: 0x0fa9, 0x1808: 0x0fb9, 0x1809: 0x1089, 0x180a: 0x0279, 0x180b: 0x0369,
+	0x180c: 0x0289, 0x180d: 0x13d1, 0x180e: 0x0039, 0x180f: 0x0ee9, 0x1810: 0x1159, 0x1811: 0x0ef9,
+	0x1812: 0x0f09, 0x1813: 0x1199, 0x1814: 0x0f31, 0x1815: 0x0040, 0x1816: 0x0f41, 0x1817: 0x0259,
+	0x1818: 0x0f51, 0x1819: 0x0359, 0x181a: 0x0f61, 0x181b: 0x0f71, 0x181c: 0x00d9, 0x181d: 0x0f99,
+	0x181e: 0x2039, 0x181f: 0x0269, 0x1820: 0x01d9, 0x1821: 0x0fa9, 0x1822: 0x0fb9, 0x1823: 0x1089,
+	0x1824: 0x0279, 0x1825: 0x0369, 0x1826: 0x0289, 0x1827: 0x13d1, 0x1828: 0x0039, 0x1829: 0x0ee9,
+	0x182a: 0x1159, 0x182b: 0x0ef9, 0x182c: 0x0f09, 0x182d: 0x1199, 0x182e: 0x0f31, 0x182f: 0x0249,
+	0x1830: 0x0f41, 0x1831: 0x0259, 0x1832: 0x0f51, 0x1833: 0x0359, 0x1834: 0x0f61, 0x1835: 0x0f71,
+	0x1836: 0x00d9, 0x1837: 0x0f99, 0x1838: 0x2039, 0x1839: 0x0269, 0x183a: 0x01d9, 0x183b: 0x0fa9,
+	0x183c: 0x0fb9, 0x183d: 0x1089, 0x183e: 0x0279, 0x183f: 0x0369,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x0289, 0x1841: 0x13d1, 0x1842: 0x0039, 0x1843: 0x0ee9, 0x1844: 0x1159, 0x1845: 0x0ef9,
+	0x1846: 0x0f09, 0x1847: 0x1199, 0x1848: 0x0f31, 0x1849: 0x0249, 0x184a: 0x0f41, 0x184b: 0x0259,
+	0x184c: 0x0f51, 0x184d: 0x0359, 0x184e: 0x0f61, 0x184f: 0x0f71, 0x1850: 0x00d9, 0x1851: 0x0f99,
+	0x1852: 0x2039, 0x1853: 0x0269, 0x1854: 0x01d9, 0x1855: 0x0fa9, 0x1856: 0x0fb9, 0x1857: 0x1089,
+	0x1858: 0x0279, 0x1859: 0x0369, 0x185a: 0x0289, 0x185b: 0x13d1, 0x185c: 0x0039, 0x185d: 0x0040,
+	0x185e: 0x1159, 0x185f: 0x0ef9, 0x1860: 0x0040, 0x1861: 0x0040, 0x1862: 0x0f31, 0x1863: 0x0040,
+	0x1864: 0x0040, 0x1865: 0x0259, 0x1866: 0x0f51, 0x1867: 0x0040, 0x1868: 0x0040, 0x1869: 0x0f71,
+	0x186a: 0x00d9, 0x186b: 0x0f99, 0x186c: 0x2039, 0x186d: 0x0040, 0x186e: 0x01d9, 0x186f: 0x0fa9,
+	0x1870: 0x0fb9, 0x1871: 0x1089, 0x1872: 0x0279, 0x1873: 0x0369, 0x1874: 0x0289, 0x1875: 0x13d1,
+	0x1876: 0x0039, 0x1877: 0x0ee9, 0x1878: 0x1159, 0x1879: 0x0ef9, 0x187a: 0x0040, 0x187b: 0x1199,
+	0x187c: 0x0040, 0x187d: 0x0249, 0x187e: 0x0f41, 0x187f: 0x0259,
+	// Block 0x62, offset 0x1880
+	0x1880: 0x0f51, 0x1881: 0x0359, 0x1882: 0x0f61, 0x1883: 0x0f71, 0x1884: 0x0040, 0x1885: 0x0f99,
+	0x1886: 0x2039, 0x1887: 0x0269, 0x1888: 0x01d9, 0x1889: 0x0fa9, 0x188a: 0x0fb9, 0x188b: 0x1089,
+	0x188c: 0x0279, 0x188d: 0x0369, 0x188e: 0x0289, 0x188f: 0x13d1, 0x1890: 0x0039, 0x1891: 0x0ee9,
+	0x1892: 0x1159, 0x1893: 0x0ef9, 0x1894: 0x0f09, 0x1895: 0x1199, 0x1896: 0x0f31, 0x1897: 0x0249,
+	0x1898: 0x0f41, 0x1899: 0x0259, 0x189a: 0x0f51, 0x189b: 0x0359, 0x189c: 0x0f61, 0x189d: 0x0f71,
+	0x189e: 0x00d9, 0x189f: 0x0f99, 0x18a0: 0x2039, 0x18a1: 0x0269, 0x18a2: 0x01d9, 0x18a3: 0x0fa9,
+	0x18a4: 0x0fb9, 0x18a5: 0x1089, 0x18a6: 0x0279, 0x18a7: 0x0369, 0x18a8: 0x0289, 0x18a9: 0x13d1,
+	0x18aa: 0x0039, 0x18ab: 0x0ee9, 0x18ac: 0x1159, 0x18ad: 0x0ef9, 0x18ae: 0x0f09, 0x18af: 0x1199,
+	0x18b0: 0x0f31, 0x18b1: 0x0249, 0x18b2: 0x0f41, 0x18b3: 0x0259, 0x18b4: 0x0f51, 0x18b5: 0x0359,
+	0x18b6: 0x0f61, 0x18b7: 0x0f71, 0x18b8: 0x00d9, 0x18b9: 0x0f99, 0x18ba: 0x2039, 0x18bb: 0x0269,
+	0x18bc: 0x01d9, 0x18bd: 0x0fa9, 0x18be: 0x0fb9, 0x18bf: 0x1089,
+	// Block 0x63, offset 0x18c0
+	0x18c0: 0x0279, 0x18c1: 0x0369, 0x18c2: 0x0289, 0x18c3: 0x13d1, 0x18c4: 0x0039, 0x18c5: 0x0ee9,
+	0x18c6: 0x0040, 0x18c7: 0x0ef9, 0x18c8: 0x0f09, 0x18c9: 0x1199, 0x18ca: 0x0f31, 0x18cb: 0x0040,
+	0x18cc: 0x0040, 0x18cd: 0x0259, 0x18ce: 0x0f51, 0x18cf: 0x0359, 0x18d0: 0x0f61, 0x18d1: 0x0f71,
+	0x18d2: 0x00d9, 0x18d3: 0x0f99, 0x18d4: 0x2039, 0x18d5: 0x0040, 0x18d6: 0x01d9, 0x18d7: 0x0fa9,
+	0x18d8: 0x0fb9, 0x18d9: 0x1089, 0x18da: 0x0279, 0x18db: 0x0369, 0x18dc: 0x0289, 0x18dd: 0x0040,
+	0x18de: 0x0039, 0x18df: 0x0ee9, 0x18e0: 0x1159, 0x18e1: 0x0ef9, 0x18e2: 0x0f09, 0x18e3: 0x1199,
+	0x18e4: 0x0f31, 0x18e5: 0x0249, 0x18e6: 0x0f41, 0x18e7: 0x0259, 0x18e8: 0x0f51, 0x18e9: 0x0359,
+	0x18ea: 0x0f61, 0x18eb: 0x0f71, 0x18ec: 0x00d9, 0x18ed: 0x0f99, 0x18ee: 0x2039, 0x18ef: 0x0269,
+	0x18f0: 0x01d9, 0x18f1: 0x0fa9, 0x18f2: 0x0fb9, 0x18f3: 0x1089, 0x18f4: 0x0279, 0x18f5: 0x0369,
+	0x18f6: 0x0289, 0x18f7: 0x13d1, 0x18f8: 0x0039, 0x18f9: 0x0ee9, 0x18fa: 0x0040, 0x18fb: 0x0ef9,
+	0x18fc: 0x0f09, 0x18fd: 0x1199, 0x18fe: 0x0f31, 0x18ff: 0x0040,
+	// Block 0x64, offset 0x1900
+	0x1900: 0x0f41, 0x1901: 0x0259, 0x1902: 0x0f51, 0x1903: 0x0359, 0x1904: 0x0f61, 0x1905: 0x0040,
+	0x1906: 0x00d9, 0x1907: 0x0040, 0x1908: 0x0040, 0x1909: 0x0040, 0x190a: 0x01d9, 0x190b: 0x0fa9,
+	0x190c: 0x0fb9, 0x190d: 0x1089, 0x190e: 0x0279, 0x190f: 0x0369, 0x1910: 0x0289, 0x1911: 0x0040,
+	0x1912: 0x0039, 0x1913: 0x0ee9, 0x1914: 0x1159, 0x1915: 0x0ef9, 0x1916: 0x0f09, 0x1917: 0x1199,
+	0x1918: 0x0f31, 0x1919: 0x0249, 0x191a: 0x0f41, 0x191b: 0x0259, 0x191c: 0x0f51, 0x191d: 0x0359,
+	0x191e: 0x0f61, 0x191f: 0x0f71, 0x1920: 0x00d9, 0x1921: 0x0f99, 0x1922: 0x2039, 0x1923: 0x0269,
+	0x1924: 0x01d9, 0x1925: 0x0fa9, 0x1926: 0x0fb9, 0x1927: 0x1089, 0x1928: 0x0279, 0x1929: 0x0369,
+	0x192a: 0x0289, 0x192b: 0x13d1, 0x192c: 0x0039, 0x192d: 0x0ee9, 0x192e: 0x1159, 0x192f: 0x0ef9,
+	0x1930: 0x0f09, 0x1931: 0x1199, 0x1932: 0x0f31, 0x1933: 0x0249, 0x1934: 0x0f41, 0x1935: 0x0259,
+	0x1936: 0x0f51, 0x1937: 0x0359, 0x1938: 0x0f61, 0x1939: 0x0f71, 0x193a: 0x00d9, 0x193b: 0x0f99,
+	0x193c: 0x2039, 0x193d: 0x0269, 0x193e: 0x01d9, 0x193f: 0x0fa9,
+	// Block 0x65, offset 0x1940
+	0x1940: 0x0fb9, 0x1941: 0x1089, 0x1942: 0x0279, 0x1943: 0x0369, 0x1944: 0x0289, 0x1945: 0x13d1,
+	0x1946: 0x0039, 0x1947: 0x0ee9, 0x1948: 0x1159, 0x1949: 0x0ef9, 0x194a: 0x0f09, 0x194b: 0x1199,
+	0x194c: 0x0f31, 0x194d: 0x0249, 0x194e: 0x0f41, 0x194f: 0x0259, 0x1950: 0x0f51, 0x1951: 0x0359,
+	0x1952: 0x0f61, 0x1953: 0x0f71, 0x1954: 0x00d9, 0x1955: 0x0f99, 0x1956: 0x2039, 0x1957: 0x0269,
+	0x1958: 0x01d9, 0x1959: 0x0fa9, 0x195a: 0x0fb9, 0x195b: 0x1089, 0x195c: 0x0279, 0x195d: 0x0369,
+	0x195e: 0x0289, 0x195f: 0x13d1, 0x1960: 0x0039, 0x1961: 0x0ee9, 0x1962: 0x1159, 0x1963: 0x0ef9,
+	0x1964: 0x0f09, 0x1965: 0x1199, 0x1966: 0x0f31, 0x1967: 0x0249, 0x1968: 0x0f41, 0x1969: 0x0259,
+	0x196a: 0x0f51, 0x196b: 0x0359, 0x196c: 0x0f61, 0x196d: 0x0f71, 0x196e: 0x00d9, 0x196f: 0x0f99,
+	0x1970: 0x2039, 0x1971: 0x0269, 0x1972: 0x01d9, 0x1973: 0x0fa9, 0x1974: 0x0fb9, 0x1975: 0x1089,
+	0x1976: 0x0279, 0x1977: 0x0369, 0x1978: 0x0289, 0x1979: 0x13d1, 0x197a: 0x0039, 0x197b: 0x0ee9,
+	0x197c: 0x1159, 0x197d: 0x0ef9, 0x197e: 0x0f09, 0x197f: 0x1199,
+	// Block 0x66, offset 0x1980
+	0x1980: 0x0f31, 0x1981: 0x0249, 0x1982: 0x0f41, 0x1983: 0x0259, 0x1984: 0x0f51, 0x1985: 0x0359,
+	0x1986: 0x0f61, 0x1987: 0x0f71, 0x1988: 0x00d9, 0x1989: 0x0f99, 0x198a: 0x2039, 0x198b: 0x0269,
+	0x198c: 0x01d9, 0x198d: 0x0fa9, 0x198e: 0x0fb9, 0x198f: 0x1089, 0x1990: 0x0279, 0x1991: 0x0369,
+	0x1992: 0x0289, 0x1993: 0x13d1, 0x1994: 0x0039, 0x1995: 0x0ee9, 0x1996: 0x1159, 0x1997: 0x0ef9,
+	0x1998: 0x0f09, 0x1999: 0x1199, 0x199a: 0x0f31, 0x199b: 0x0249, 0x199c: 0x0f41, 0x199d: 0x0259,
+	0x199e: 0x0f51, 0x199f: 0x0359, 0x19a0: 0x0f61, 0x19a1: 0x0f71, 0x19a2: 0x00d9, 0x19a3: 0x0f99,
+	0x19a4: 0x2039, 0x19a5: 0x0269, 0x19a6: 0x01d9, 0x19a7: 0x0fa9, 0x19a8: 0x0fb9, 0x19a9: 0x1089,
+	0x19aa: 0x0279, 0x19ab: 0x0369, 0x19ac: 0x0289, 0x19ad: 0x13d1, 0x19ae: 0x0039, 0x19af: 0x0ee9,
+	0x19b0: 0x1159, 0x19b1: 0x0ef9, 0x19b2: 0x0f09, 0x19b3: 0x1199, 0x19b4: 0x0f31, 0x19b5: 0x0249,
+	0x19b6: 0x0f41, 0x19b7: 0x0259, 0x19b8: 0x0f51, 0x19b9: 0x0359, 0x19ba: 0x0f61, 0x19bb: 0x0f71,
+	0x19bc: 0x00d9, 0x19bd: 0x0f99, 0x19be: 0x2039, 0x19bf: 0x0269,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x01d9, 0x19c1: 0x0fa9, 0x19c2: 0x0fb9, 0x19c3: 0x1089, 0x19c4: 0x0279, 0x19c5: 0x0369,
+	0x19c6: 0x0289, 0x19c7: 0x13d1, 0x19c8: 0x0039, 0x19c9: 0x0ee9, 0x19ca: 0x1159, 0x19cb: 0x0ef9,
+	0x19cc: 0x0f09, 0x19cd: 0x1199, 0x19ce: 0x0f31, 0x19cf: 0x0249, 0x19d0: 0x0f41, 0x19d1: 0x0259,
+	0x19d2: 0x0f51, 0x19d3: 0x0359, 0x19d4: 0x0f61, 0x19d5: 0x0f71, 0x19d6: 0x00d9, 0x19d7: 0x0f99,
+	0x19d8: 0x2039, 0x19d9: 0x0269, 0x19da: 0x01d9, 0x19db: 0x0fa9, 0x19dc: 0x0fb9, 0x19dd: 0x1089,
+	0x19de: 0x0279, 0x19df: 0x0369, 0x19e0: 0x0289, 0x19e1: 0x13d1, 0x19e2: 0x0039, 0x19e3: 0x0ee9,
+	0x19e4: 0x1159, 0x19e5: 0x0ef9, 0x19e6: 0x0f09, 0x19e7: 0x1199, 0x19e8: 0x0f31, 0x19e9: 0x0249,
+	0x19ea: 0x0f41, 0x19eb: 0x0259, 0x19ec: 0x0f51, 0x19ed: 0x0359, 0x19ee: 0x0f61, 0x19ef: 0x0f71,
+	0x19f0: 0x00d9, 0x19f1: 0x0f99, 0x19f2: 0x2039, 0x19f3: 0x0269, 0x19f4: 0x01d9, 0x19f5: 0x0fa9,
+	0x19f6: 0x0fb9, 0x19f7: 0x1089, 0x19f8: 0x0279, 0x19f9: 0x0369, 0x19fa: 0x0289, 0x19fb: 0x13d1,
+	0x19fc: 0x0039, 0x19fd: 0x0ee9, 0x19fe: 0x1159, 0x19ff: 0x0ef9,
+	// Block 0x68, offset 0x1a00
+	0x1a00: 0x0f09, 0x1a01: 0x1199, 0x1a02: 0x0f31, 0x1a03: 0x0249, 0x1a04: 0x0f41, 0x1a05: 0x0259,
+	0x1a06: 0x0f51, 0x1a07: 0x0359, 0x1a08: 0x0f61, 0x1a09: 0x0f71, 0x1a0a: 0x00d9, 0x1a0b: 0x0f99,
+	0x1a0c: 0x2039, 0x1a0d: 0x0269, 0x1a0e: 0x01d9, 0x1a0f: 0x0fa9, 0x1a10: 0x0fb9, 0x1a11: 0x1089,
+	0x1a12: 0x0279, 0x1a13: 0x0369, 0x1a14: 0x0289, 0x1a15: 0x13d1, 0x1a16: 0x0039, 0x1a17: 0x0ee9,
+	0x1a18: 0x1159, 0x1a19: 0x0ef9, 0x1a1a: 0x0f09, 0x1a1b: 0x1199, 0x1a1c: 0x0f31, 0x1a1d: 0x0249,
+	0x1a1e: 0x0f41, 0x1a1f: 0x0259, 0x1a20: 0x0f51, 0x1a21: 0x0359, 0x1a22: 0x0f61, 0x1a23: 0x0f71,
+	0x1a24: 0x00d9, 0x1a25: 0x0f99, 0x1a26: 0x2039, 0x1a27: 0x0269, 0x1a28: 0x01d9, 0x1a29: 0x0fa9,
+	0x1a2a: 0x0fb9, 0x1a2b: 0x1089, 0x1a2c: 0x0279, 0x1a2d: 0x0369, 0x1a2e: 0x0289, 0x1a2f: 0x13d1,
+	0x1a30: 0x0039, 0x1a31: 0x0ee9, 0x1a32: 0x1159, 0x1a33: 0x0ef9, 0x1a34: 0x0f09, 0x1a35: 0x1199,
+	0x1a36: 0x0f31, 0x1a37: 0x0249, 0x1a38: 0x0f41, 0x1a39: 0x0259, 0x1a3a: 0x0f51, 0x1a3b: 0x0359,
+	0x1a3c: 0x0f61, 0x1a3d: 0x0f71, 0x1a3e: 0x00d9, 0x1a3f: 0x0f99,
+	// Block 0x69, offset 0x1a40
+	0x1a40: 0x2039, 0x1a41: 0x0269, 0x1a42: 0x01d9, 0x1a43: 0x0fa9, 0x1a44: 0x0fb9, 0x1a45: 0x1089,
+	0x1a46: 0x0279, 0x1a47: 0x0369, 0x1a48: 0x0289, 0x1a49: 0x13d1, 0x1a4a: 0x0039, 0x1a4b: 0x0ee9,
+	0x1a4c: 0x1159, 0x1a4d: 0x0ef9, 0x1a4e: 0x0f09, 0x1a4f: 0x1199, 0x1a50: 0x0f31, 0x1a51: 0x0249,
+	0x1a52: 0x0f41, 0x1a53: 0x0259, 0x1a54: 0x0f51, 0x1a55: 0x0359, 0x1a56: 0x0f61, 0x1a57: 0x0f71,
+	0x1a58: 0x00d9, 0x1a59: 0x0f99, 0x1a5a: 0x2039, 0x1a5b: 0x0269, 0x1a5c: 0x01d9, 0x1a5d: 0x0fa9,
+	0x1a5e: 0x0fb9, 0x1a5f: 0x1089, 0x1a60: 0x0279, 0x1a61: 0x0369, 0x1a62: 0x0289, 0x1a63: 0x13d1,
+	0x1a64: 0xba81, 0x1a65: 0xba99, 0x1a66: 0x0040, 0x1a67: 0x0040, 0x1a68: 0xbab1, 0x1a69: 0x1099,
+	0x1a6a: 0x10b1, 0x1a6b: 0x10c9, 0x1a6c: 0xbac9, 0x1a6d: 0xbae1, 0x1a6e: 0xbaf9, 0x1a6f: 0x1429,
+	0x1a70: 0x1a31, 0x1a71: 0xbb11, 0x1a72: 0xbb29, 0x1a73: 0xbb41, 0x1a74: 0xbb59, 0x1a75: 0xbb71,
+	0x1a76: 0xbb89, 0x1a77: 0x2109, 0x1a78: 0x1111, 0x1a79: 0x1429, 0x1a7a: 0xbba1, 0x1a7b: 0xbbb9,
+	0x1a7c: 0xbbd1, 0x1a7d: 0x10e1, 0x1a7e: 0x10f9, 0x1a7f: 0xbbe9,
+	// Block 0x6a, offset 0x1a80
+	0x1a80: 0x2079, 0x1a81: 0xbc01, 0x1a82: 0xbab1, 0x1a83: 0x1099, 0x1a84: 0x10b1, 0x1a85: 0x10c9,
+	0x1a86: 0xbac9, 0x1a87: 0xbae1, 0x1a88: 0xbaf9, 0x1a89: 0x1429, 0x1a8a: 0x1a31, 0x1a8b: 0xbb11,
+	0x1a8c: 0xbb29, 0x1a8d: 0xbb41, 0x1a8e: 0xbb59, 0x1a8f: 0xbb71, 0x1a90: 0xbb89, 0x1a91: 0x2109,
+	0x1a92: 0x1111, 0x1a93: 0xbba1, 0x1a94: 0xbba1, 0x1a95: 0xbbb9, 0x1a96: 0xbbd1, 0x1a97: 0x10e1,
+	0x1a98: 0x10f9, 0x1a99: 0xbbe9, 0x1a9a: 0x2079, 0x1a9b: 0xbc21, 0x1a9c: 0xbac9, 0x1a9d: 0x1429,
+	0x1a9e: 0xbb11, 0x1a9f: 0x10e1, 0x1aa0: 0x1111, 0x1aa1: 0x2109, 0x1aa2: 0xbab1, 0x1aa3: 0x1099,
+	0x1aa4: 0x10b1, 0x1aa5: 0x10c9, 0x1aa6: 0xbac9, 0x1aa7: 0xbae1, 0x1aa8: 0xbaf9, 0x1aa9: 0x1429,
+	0x1aaa: 0x1a31, 0x1aab: 0xbb11, 0x1aac: 0xbb29, 0x1aad: 0xbb41, 0x1aae: 0xbb59, 0x1aaf: 0xbb71,
+	0x1ab0: 0xbb89, 0x1ab1: 0x2109, 0x1ab2: 0x1111, 0x1ab3: 0x1429, 0x1ab4: 0xbba1, 0x1ab5: 0xbbb9,
+	0x1ab6: 0xbbd1, 0x1ab7: 0x10e1, 0x1ab8: 0x10f9, 0x1ab9: 0xbbe9, 0x1aba: 0x2079, 0x1abb: 0xbc01,
+	0x1abc: 0xbab1, 0x1abd: 0x1099, 0x1abe: 0x10b1, 0x1abf: 0x10c9,
+	// Block 0x6b, offset 0x1ac0
+	0x1ac0: 0xbac9, 0x1ac1: 0xbae1, 0x1ac2: 0xbaf9, 0x1ac3: 0x1429, 0x1ac4: 0x1a31, 0x1ac5: 0xbb11,
+	0x1ac6: 0xbb29, 0x1ac7: 0xbb41, 0x1ac8: 0xbb59, 0x1ac9: 0xbb71, 0x1aca: 0xbb89, 0x1acb: 0x2109,
+	0x1acc: 0x1111, 0x1acd: 0xbba1, 0x1ace: 0xbba1, 0x1acf: 0xbbb9, 0x1ad0: 0xbbd1, 0x1ad1: 0x10e1,
+	0x1ad2: 0x10f9, 0x1ad3: 0xbbe9, 0x1ad4: 0x2079, 0x1ad5: 0xbc21, 0x1ad6: 0xbac9, 0x1ad7: 0x1429,
+	0x1ad8: 0xbb11, 0x1ad9: 0x10e1, 0x1ada: 0x1111, 0x1adb: 0x2109, 0x1adc: 0xbab1, 0x1add: 0x1099,
+	0x1ade: 0x10b1, 0x1adf: 0x10c9, 0x1ae0: 0xbac9, 0x1ae1: 0xbae1, 0x1ae2: 0xbaf9, 0x1ae3: 0x1429,
+	0x1ae4: 0x1a31, 0x1ae5: 0xbb11, 0x1ae6: 0xbb29, 0x1ae7: 0xbb41, 0x1ae8: 0xbb59, 0x1ae9: 0xbb71,
+	0x1aea: 0xbb89, 0x1aeb: 0x2109, 0x1aec: 0x1111, 0x1aed: 0x1429, 0x1aee: 0xbba1, 0x1aef: 0xbbb9,
+	0x1af0: 0xbbd1, 0x1af1: 0x10e1, 0x1af2: 0x10f9, 0x1af3: 0xbbe9, 0x1af4: 0x2079, 0x1af5: 0xbc01,
+	0x1af6: 0xbab1, 0x1af7: 0x1099, 0x1af8: 0x10b1, 0x1af9: 0x10c9, 0x1afa: 0xbac9, 0x1afb: 0xbae1,
+	0x1afc: 0xbaf9, 0x1afd: 0x1429, 0x1afe: 0x1a31, 0x1aff: 0xbb11,
+	// Block 0x6c, offset 0x1b00
+	0x1b00: 0xbb29, 0x1b01: 0xbb41, 0x1b02: 0xbb59, 0x1b03: 0xbb71, 0x1b04: 0xbb89, 0x1b05: 0x2109,
+	0x1b06: 0x1111, 0x1b07: 0xbba1, 0x1b08: 0xbba1, 0x1b09: 0xbbb9, 0x1b0a: 0xbbd1, 0x1b0b: 0x10e1,
+	0x1b0c: 0x10f9, 0x1b0d: 0xbbe9, 0x1b0e: 0x2079, 0x1b0f: 0xbc21, 0x1b10: 0xbac9, 0x1b11: 0x1429,
+	0x1b12: 0xbb11, 0x1b13: 0x10e1, 0x1b14: 0x1111, 0x1b15: 0x2109, 0x1b16: 0xbab1, 0x1b17: 0x1099,
+	0x1b18: 0x10b1, 0x1b19: 0x10c9, 0x1b1a: 0xbac9, 0x1b1b: 0xbae1, 0x1b1c: 0xbaf9, 0x1b1d: 0x1429,
+	0x1b1e: 0x1a31, 0x1b1f: 0xbb11, 0x1b20: 0xbb29, 0x1b21: 0xbb41, 0x1b22: 0xbb59, 0x1b23: 0xbb71,
+	0x1b24: 0xbb89, 0x1b25: 0x2109, 0x1b26: 0x1111, 0x1b27: 0x1429, 0x1b28: 0xbba1, 0x1b29: 0xbbb9,
+	0x1b2a: 0xbbd1, 0x1b2b: 0x10e1, 0x1b2c: 0x10f9, 0x1b2d: 0xbbe9, 0x1b2e: 0x2079, 0x1b2f: 0xbc01,
+	0x1b30: 0xbab1, 0x1b31: 0x1099, 0x1b32: 0x10b1, 0x1b33: 0x10c9, 0x1b34: 0xbac9, 0x1b35: 0xbae1,
+	0x1b36: 0xbaf9, 0x1b37: 0x1429, 0x1b38: 0x1a31, 0x1b39: 0xbb11, 0x1b3a: 0xbb29, 0x1b3b: 0xbb41,
+	0x1b3c: 0xbb59, 0x1b3d: 0xbb71, 0x1b3e: 0xbb89, 0x1b3f: 0x2109,
+	// Block 0x6d, offset 0x1b40
+	0x1b40: 0x1111, 0x1b41: 0xbba1, 0x1b42: 0xbba1, 0x1b43: 0xbbb9, 0x1b44: 0xbbd1, 0x1b45: 0x10e1,
+	0x1b46: 0x10f9, 0x1b47: 0xbbe9, 0x1b48: 0x2079, 0x1b49: 0xbc21, 0x1b4a: 0xbac9, 0x1b4b: 0x1429,
+	0x1b4c: 0xbb11, 0x1b4d: 0x10e1, 0x1b4e: 0x1111, 0x1b4f: 0x2109, 0x1b50: 0xbab1, 0x1b51: 0x1099,
+	0x1b52: 0x10b1, 0x1b53: 0x10c9, 0x1b54: 0xbac9, 0x1b55: 0xbae1, 0x1b56: 0xbaf9, 0x1b57: 0x1429,
+	0x1b58: 0x1a31, 0x1b59: 0xbb11, 0x1b5a: 0xbb29, 0x1b5b: 0xbb41, 0x1b5c: 0xbb59, 0x1b5d: 0xbb71,
+	0x1b5e: 0xbb89, 0x1b5f: 0x2109, 0x1b60: 0x1111, 0x1b61: 0x1429, 0x1b62: 0xbba1, 0x1b63: 0xbbb9,
+	0x1b64: 0xbbd1, 0x1b65: 0x10e1, 0x1b66: 0x10f9, 0x1b67: 0xbbe9, 0x1b68: 0x2079, 0x1b69: 0xbc01,
+	0x1b6a: 0xbab1, 0x1b6b: 0x1099, 0x1b6c: 0x10b1, 0x1b6d: 0x10c9, 0x1b6e: 0xbac9, 0x1b6f: 0xbae1,
+	0x1b70: 0xbaf9, 0x1b71: 0x1429, 0x1b72: 0x1a31, 0x1b73: 0xbb11, 0x1b74: 0xbb29, 0x1b75: 0xbb41,
+	0x1b76: 0xbb59, 0x1b77: 0xbb71, 0x1b78: 0xbb89, 0x1b79: 0x2109, 0x1b7a: 0x1111, 0x1b7b: 0xbba1,
+	0x1b7c: 0xbba1, 0x1b7d: 0xbbb9, 0x1b7e: 0xbbd1, 0x1b7f: 0x10e1,
+	// Block 0x6e, offset 0x1b80
+	0x1b80: 0x10f9, 0x1b81: 0xbbe9, 0x1b82: 0x2079, 0x1b83: 0xbc21, 0x1b84: 0xbac9, 0x1b85: 0x1429,
+	0x1b86: 0xbb11, 0x1b87: 0x10e1, 0x1b88: 0x1111, 0x1b89: 0x2109, 0x1b8a: 0xbc41, 0x1b8b: 0xbc41,
+	0x1b8c: 0x0040, 0x1b8d: 0x0040, 0x1b8e: 0x1f41, 0x1b8f: 0x00c9, 0x1b90: 0x0069, 0x1b91: 0x0079,
+	0x1b92: 0x1f51, 0x1b93: 0x1f61, 0x1b94: 0x1f71, 0x1b95: 0x1f81, 0x1b96: 0x1f91, 0x1b97: 0x1fa1,
+	0x1b98: 0x1f41, 0x1b99: 0x00c9, 0x1b9a: 0x0069, 0x1b9b: 0x0079, 0x1b9c: 0x1f51, 0x1b9d: 0x1f61,
+	0x1b9e: 0x1f71, 0x1b9f: 0x1f81, 0x1ba0: 0x1f91, 0x1ba1: 0x1fa1, 0x1ba2: 0x1f41, 0x1ba3: 0x00c9,
+	0x1ba4: 0x0069, 0x1ba5: 0x0079, 0x1ba6: 0x1f51, 0x1ba7: 0x1f61, 0x1ba8: 0x1f71, 0x1ba9: 0x1f81,
+	0x1baa: 0x1f91, 0x1bab: 0x1fa1, 0x1bac: 0x1f41, 0x1bad: 0x00c9, 0x1bae: 0x0069, 0x1baf: 0x0079,
+	0x1bb0: 0x1f51, 0x1bb1: 0x1f61, 0x1bb2: 0x1f71, 0x1bb3: 0x1f81, 0x1bb4: 0x1f91, 0x1bb5: 0x1fa1,
+	0x1bb6: 0x1f41, 0x1bb7: 0x00c9, 0x1bb8: 0x0069, 0x1bb9: 0x0079, 0x1bba: 0x1f51, 0x1bbb: 0x1f61,
+	0x1bbc: 0x1f71, 0x1bbd: 0x1f81, 0x1bbe: 0x1f91, 0x1bbf: 0x1fa1,
+	// Block 0x6f, offset 0x1bc0
+	0x1bc0: 0xe115, 0x1bc1: 0xe115, 0x1bc2: 0xe135, 0x1bc3: 0xe135, 0x1bc4: 0xe115, 0x1bc5: 0xe115,
+	0x1bc6: 0xe175, 0x1bc7: 0xe175, 0x1bc8: 0xe115, 0x1bc9: 0xe115, 0x1bca: 0xe135, 0x1bcb: 0xe135,
+	0x1bcc: 0xe115, 0x1bcd: 0xe115, 0x1bce: 0xe1f5, 0x1bcf: 0xe1f5, 0x1bd0: 0xe115, 0x1bd1: 0xe115,
+	0x1bd2: 0xe135, 0x1bd3: 0xe135, 0x1bd4: 0xe115, 0x1bd5: 0xe115, 0x1bd6: 0xe175, 0x1bd7: 0xe175,
+	0x1bd8: 0xe115, 0x1bd9: 0xe115, 0x1bda: 0xe135, 0x1bdb: 0xe135, 0x1bdc: 0xe115, 0x1bdd: 0xe115,
+	0x1bde: 0x8b05, 0x1bdf: 0x8b05, 0x1be0: 0x04b5, 0x1be1: 0x04b5, 0x1be2: 0x0208, 0x1be3: 0x0208,
+	0x1be4: 0x0208, 0x1be5: 0x0208, 0x1be6: 0x0208, 0x1be7: 0x0208, 0x1be8: 0x0208, 0x1be9: 0x0208,
+	0x1bea: 0x0208, 0x1beb: 0x0208, 0x1bec: 0x0208, 0x1bed: 0x0208, 0x1bee: 0x0208, 0x1bef: 0x0208,
+	0x1bf0: 0x0208, 0x1bf1: 0x0208, 0x1bf2: 0x0208, 0x1bf3: 0x0208, 0x1bf4: 0x0208, 0x1bf5: 0x0208,
+	0x1bf6: 0x0208, 0x1bf7: 0x0208, 0x1bf8: 0x0208, 0x1bf9: 0x0208, 0x1bfa: 0x0208, 0x1bfb: 0x0208,
+	0x1bfc: 0x0208, 0x1bfd: 0x0208, 0x1bfe: 0x0208, 0x1bff: 0x0208,
+	// Block 0x70, offset 0x1c00
+	0x1c00: 0xb189, 0x1c01: 0xb1a1, 0x1c02: 0xb201, 0x1c03: 0xb249, 0x1c04: 0x0040, 0x1c05: 0xb411,
+	0x1c06: 0xb291, 0x1c07: 0xb219, 0x1c08: 0xb309, 0x1c09: 0xb429, 0x1c0a: 0xb399, 0x1c0b: 0xb3b1,
+	0x1c0c: 0xb3c9, 0x1c0d: 0xb3e1, 0x1c0e: 0xb2a9, 0x1c0f: 0xb339, 0x1c10: 0xb369, 0x1c11: 0xb2d9,
+	0x1c12: 0xb381, 0x1c13: 0xb279, 0x1c14: 0xb2c1, 0x1c15: 0xb1d1, 0x1c16: 0xb1e9, 0x1c17: 0xb231,
+	0x1c18: 0xb261, 0x1c19: 0xb2f1, 0x1c1a: 0xb321, 0x1c1b: 0xb351, 0x1c1c: 0xbc59, 0x1c1d: 0x7949,
+	0x1c1e: 0xbc71, 0x1c1f: 0xbc89, 0x1c20: 0x0040, 0x1c21: 0xb1a1, 0x1c22: 0xb201, 0x1c23: 0x0040,
+	0x1c24: 0xb3f9, 0x1c25: 0x0040, 0x1c26: 0x0040, 0x1c27: 0xb219, 0x1c28: 0x0040, 0x1c29: 0xb429,
+	0x1c2a: 0xb399, 0x1c2b: 0xb3b1, 0x1c2c: 0xb3c9, 0x1c2d: 0xb3e1, 0x1c2e: 0xb2a9, 0x1c2f: 0xb339,
+	0x1c30: 0xb369, 0x1c31: 0xb2d9, 0x1c32: 0xb381, 0x1c33: 0x0040, 0x1c34: 0xb2c1, 0x1c35: 0xb1d1,
+	0x1c36: 0xb1e9, 0x1c37: 0xb231, 0x1c38: 0x0040, 0x1c39: 0xb2f1, 0x1c3a: 0x0040, 0x1c3b: 0xb351,
+	0x1c3c: 0x0040, 0x1c3d: 0x0040, 0x1c3e: 0x0040, 0x1c3f: 0x0040,
+	// Block 0x71, offset 0x1c40
+	0x1c40: 0x0040, 0x1c41: 0x0040, 0x1c42: 0xb201, 0x1c43: 0x0040, 0x1c44: 0x0040, 0x1c45: 0x0040,
+	0x1c46: 0x0040, 0x1c47: 0xb219, 0x1c48: 0x0040, 0x1c49: 0xb429, 0x1c4a: 0x0040, 0x1c4b: 0xb3b1,
+	0x1c4c: 0x0040, 0x1c4d: 0xb3e1, 0x1c4e: 0xb2a9, 0x1c4f: 0xb339, 0x1c50: 0x0040, 0x1c51: 0xb2d9,
+	0x1c52: 0xb381, 0x1c53: 0x0040, 0x1c54: 0xb2c1, 0x1c55: 0x0040, 0x1c56: 0x0040, 0x1c57: 0xb231,
+	0x1c58: 0x0040, 0x1c59: 0xb2f1, 0x1c5a: 0x0040, 0x1c5b: 0xb351, 0x1c5c: 0x0040, 0x1c5d: 0x7949,
+	0x1c5e: 0x0040, 0x1c5f: 0xbc89, 0x1c60: 0x0040, 0x1c61: 0xb1a1, 0x1c62: 0xb201, 0x1c63: 0x0040,
+	0x1c64: 0xb3f9, 0x1c65: 0x0040, 0x1c66: 0x0040, 0x1c67: 0xb219, 0x1c68: 0xb309, 0x1c69: 0xb429,
+	0x1c6a: 0xb399, 0x1c6b: 0x0040, 0x1c6c: 0xb3c9, 0x1c6d: 0xb3e1, 0x1c6e: 0xb2a9, 0x1c6f: 0xb339,
+	0x1c70: 0xb369, 0x1c71: 0xb2d9, 0x1c72: 0xb381, 0x1c73: 0x0040, 0x1c74: 0xb2c1, 0x1c75: 0xb1d1,
+	0x1c76: 0xb1e9, 0x1c77: 0xb231, 0x1c78: 0x0040, 0x1c79: 0xb2f1, 0x1c7a: 0xb321, 0x1c7b: 0xb351,
+	0x1c7c: 0xbc59, 0x1c7d: 0x0040, 0x1c7e: 0xbc71, 0x1c7f: 0x0040,
+	// Block 0x72, offset 0x1c80
+	0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0xb3f9, 0x1c85: 0xb411,
+	0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0x0040, 0x1c8b: 0xb3b1,
+	0x1c8c: 0xb3c9, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0xb369, 0x1c91: 0xb2d9,
+	0x1c92: 0xb381, 0x1c93: 0xb279, 0x1c94: 0xb2c1, 0x1c95: 0xb1d1, 0x1c96: 0xb1e9, 0x1c97: 0xb231,
+	0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0x0040, 0x1c9d: 0x0040,
+	0x1c9e: 0x0040, 0x1c9f: 0x0040, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0xb249,
+	0x1ca4: 0x0040, 0x1ca5: 0xb411, 0x1ca6: 0xb291, 0x1ca7: 0xb219, 0x1ca8: 0xb309, 0x1ca9: 0xb429,
+	0x1caa: 0x0040, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339,
+	0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0xb279, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1,
+	0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0xb261, 0x1cb9: 0xb2f1, 0x1cba: 0xb321, 0x1cbb: 0xb351,
+	0x1cbc: 0x0040, 0x1cbd: 0x0040, 0x1cbe: 0x0040, 0x1cbf: 0x0040,
+	// Block 0x73, offset 0x1cc0
+	0x1cc0: 0x0040, 0x1cc1: 0xbca2, 0x1cc2: 0xbcba, 0x1cc3: 0xbcd2, 0x1cc4: 0xbcea, 0x1cc5: 0xbd02,
+	0x1cc6: 0xbd1a, 0x1cc7: 0xbd32, 0x1cc8: 0xbd4a, 0x1cc9: 0xbd62, 0x1cca: 0xbd7a, 0x1ccb: 0x0018,
+	0x1ccc: 0x0018, 0x1ccd: 0x0040, 0x1cce: 0x0040, 0x1ccf: 0x0040, 0x1cd0: 0xbd92, 0x1cd1: 0xbdb2,
+	0x1cd2: 0xbdd2, 0x1cd3: 0xbdf2, 0x1cd4: 0xbe12, 0x1cd5: 0xbe32, 0x1cd6: 0xbe52, 0x1cd7: 0xbe72,
+	0x1cd8: 0xbe92, 0x1cd9: 0xbeb2, 0x1cda: 0xbed2, 0x1cdb: 0xbef2, 0x1cdc: 0xbf12, 0x1cdd: 0xbf32,
+	0x1cde: 0xbf52, 0x1cdf: 0xbf72, 0x1ce0: 0xbf92, 0x1ce1: 0xbfb2, 0x1ce2: 0xbfd2, 0x1ce3: 0xbff2,
+	0x1ce4: 0xc012, 0x1ce5: 0xc032, 0x1ce6: 0xc052, 0x1ce7: 0xc072, 0x1ce8: 0xc092, 0x1ce9: 0xc0b2,
+	0x1cea: 0xc0d1, 0x1ceb: 0x1159, 0x1cec: 0x0269, 0x1ced: 0x6671, 0x1cee: 0xc111, 0x1cef: 0x0040,
+	0x1cf0: 0x0039, 0x1cf1: 0x0ee9, 0x1cf2: 0x1159, 0x1cf3: 0x0ef9, 0x1cf4: 0x0f09, 0x1cf5: 0x1199,
+	0x1cf6: 0x0f31, 0x1cf7: 0x0249, 0x1cf8: 0x0f41, 0x1cf9: 0x0259, 0x1cfa: 0x0f51, 0x1cfb: 0x0359,
+	0x1cfc: 0x0f61, 0x1cfd: 0x0f71, 0x1cfe: 0x00d9, 0x1cff: 0x0f99,
+	// Block 0x74, offset 0x1d00
+	0x1d00: 0x2039, 0x1d01: 0x0269, 0x1d02: 0x01d9, 0x1d03: 0x0fa9, 0x1d04: 0x0fb9, 0x1d05: 0x1089,
+	0x1d06: 0x0279, 0x1d07: 0x0369, 0x1d08: 0x0289, 0x1d09: 0x13d1, 0x1d0a: 0xc129, 0x1d0b: 0x65b1,
+	0x1d0c: 0xc141, 0x1d0d: 0x1441, 0x1d0e: 0xc159, 0x1d0f: 0xc179, 0x1d10: 0x0018, 0x1d11: 0x0018,
+	0x1d12: 0x0018, 0x1d13: 0x0018, 0x1d14: 0x0018, 0x1d15: 0x0018, 0x1d16: 0x0018, 0x1d17: 0x0018,
+	0x1d18: 0x0018, 0x1d19: 0x0018, 0x1d1a: 0x0018, 0x1d1b: 0x0018, 0x1d1c: 0x0018, 0x1d1d: 0x0018,
+	0x1d1e: 0x0018, 0x1d1f: 0x0018, 0x1d20: 0x0018, 0x1d21: 0x0018, 0x1d22: 0x0018, 0x1d23: 0x0018,
+	0x1d24: 0x0018, 0x1d25: 0x0018, 0x1d26: 0x0018, 0x1d27: 0x0018, 0x1d28: 0x0018, 0x1d29: 0x0018,
+	0x1d2a: 0xc191, 0x1d2b: 0xc1a9, 0x1d2c: 0x0040, 0x1d2d: 0x0040, 0x1d2e: 0x0040, 0x1d2f: 0x0040,
+	0x1d30: 0x0018, 0x1d31: 0x0018, 0x1d32: 0x0018, 0x1d33: 0x0018, 0x1d34: 0x0018, 0x1d35: 0x0018,
+	0x1d36: 0x0018, 0x1d37: 0x0018, 0x1d38: 0x0018, 0x1d39: 0x0018, 0x1d3a: 0x0018, 0x1d3b: 0x0018,
+	0x1d3c: 0x0018, 0x1d3d: 0x0018, 0x1d3e: 0x0018, 0x1d3f: 0x0018,
+	// Block 0x75, offset 0x1d40
+	0x1d40: 0xc1d9, 0x1d41: 0xc211, 0x1d42: 0xc249, 0x1d43: 0x0040, 0x1d44: 0x0040, 0x1d45: 0x0040,
+	0x1d46: 0x0040, 0x1d47: 0x0040, 0x1d48: 0x0040, 0x1d49: 0x0040, 0x1d4a: 0x0040, 0x1d4b: 0x0040,
+	0x1d4c: 0x0040, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xc269, 0x1d51: 0xc289,
+	0x1d52: 0xc2a9, 0x1d53: 0xc2c9, 0x1d54: 0xc2e9, 0x1d55: 0xc309, 0x1d56: 0xc329, 0x1d57: 0xc349,
+	0x1d58: 0xc369, 0x1d59: 0xc389, 0x1d5a: 0xc3a9, 0x1d5b: 0xc3c9, 0x1d5c: 0xc3e9, 0x1d5d: 0xc409,
+	0x1d5e: 0xc429, 0x1d5f: 0xc449, 0x1d60: 0xc469, 0x1d61: 0xc489, 0x1d62: 0xc4a9, 0x1d63: 0xc4c9,
+	0x1d64: 0xc4e9, 0x1d65: 0xc509, 0x1d66: 0xc529, 0x1d67: 0xc549, 0x1d68: 0xc569, 0x1d69: 0xc589,
+	0x1d6a: 0xc5a9, 0x1d6b: 0xc5c9, 0x1d6c: 0xc5e9, 0x1d6d: 0xc609, 0x1d6e: 0xc629, 0x1d6f: 0xc649,
+	0x1d70: 0xc669, 0x1d71: 0xc689, 0x1d72: 0xc6a9, 0x1d73: 0xc6c9, 0x1d74: 0xc6e9, 0x1d75: 0xc709,
+	0x1d76: 0xc729, 0x1d77: 0xc749, 0x1d78: 0xc769, 0x1d79: 0xc789, 0x1d7a: 0xc7a9, 0x1d7b: 0xc7c9,
+	0x1d7c: 0x0040, 0x1d7d: 0x0040, 0x1d7e: 0x0040, 0x1d7f: 0x0040,
+	// Block 0x76, offset 0x1d80
+	0x1d80: 0xcaf9, 0x1d81: 0xcb19, 0x1d82: 0xcb39, 0x1d83: 0x8b1d, 0x1d84: 0xcb59, 0x1d85: 0xcb79,
+	0x1d86: 0xcb99, 0x1d87: 0xcbb9, 0x1d88: 0xcbd9, 0x1d89: 0xcbf9, 0x1d8a: 0xcc19, 0x1d8b: 0xcc39,
+	0x1d8c: 0xcc59, 0x1d8d: 0x8b3d, 0x1d8e: 0xcc79, 0x1d8f: 0xcc99, 0x1d90: 0xccb9, 0x1d91: 0xccd9,
+	0x1d92: 0x8b5d, 0x1d93: 0xccf9, 0x1d94: 0xcd19, 0x1d95: 0xc429, 0x1d96: 0x8b7d, 0x1d97: 0xcd39,
+	0x1d98: 0xcd59, 0x1d99: 0xcd79, 0x1d9a: 0xcd99, 0x1d9b: 0xcdb9, 0x1d9c: 0x8b9d, 0x1d9d: 0xcdd9,
+	0x1d9e: 0xcdf9, 0x1d9f: 0xce19, 0x1da0: 0xce39, 0x1da1: 0xce59, 0x1da2: 0xc789, 0x1da3: 0xce79,
+	0x1da4: 0xce99, 0x1da5: 0xceb9, 0x1da6: 0xced9, 0x1da7: 0xcef9, 0x1da8: 0xcf19, 0x1da9: 0xcf39,
+	0x1daa: 0xcf59, 0x1dab: 0xcf79, 0x1dac: 0xcf99, 0x1dad: 0xcfb9, 0x1dae: 0xcfd9, 0x1daf: 0xcff9,
+	0x1db0: 0xd019, 0x1db1: 0xd039, 0x1db2: 0xd039, 0x1db3: 0xd039, 0x1db4: 0x8bbd, 0x1db5: 0xd059,
+	0x1db6: 0xd079, 0x1db7: 0xd099, 0x1db8: 0x8bdd, 0x1db9: 0xd0b9, 0x1dba: 0xd0d9, 0x1dbb: 0xd0f9,
+	0x1dbc: 0xd119, 0x1dbd: 0xd139, 0x1dbe: 0xd159, 0x1dbf: 0xd179,
+	// Block 0x77, offset 0x1dc0
+	0x1dc0: 0xd199, 0x1dc1: 0xd1b9, 0x1dc2: 0xd1d9, 0x1dc3: 0xd1f9, 0x1dc4: 0xd219, 0x1dc5: 0xd239,
+	0x1dc6: 0xd239, 0x1dc7: 0xd259, 0x1dc8: 0xd279, 0x1dc9: 0xd299, 0x1dca: 0xd2b9, 0x1dcb: 0xd2d9,
+	0x1dcc: 0xd2f9, 0x1dcd: 0xd319, 0x1dce: 0xd339, 0x1dcf: 0xd359, 0x1dd0: 0xd379, 0x1dd1: 0xd399,
+	0x1dd2: 0xd3b9, 0x1dd3: 0xd3d9, 0x1dd4: 0xd3f9, 0x1dd5: 0xd419, 0x1dd6: 0xd439, 0x1dd7: 0xd459,
+	0x1dd8: 0xd479, 0x1dd9: 0x8bfd, 0x1dda: 0xd499, 0x1ddb: 0xd4b9, 0x1ddc: 0xd4d9, 0x1ddd: 0xc309,
+	0x1dde: 0xd4f9, 0x1ddf: 0xd519, 0x1de0: 0x8c1d, 0x1de1: 0x8c3d, 0x1de2: 0xd539, 0x1de3: 0xd559,
+	0x1de4: 0xd579, 0x1de5: 0xd599, 0x1de6: 0xd5b9, 0x1de7: 0xd5d9, 0x1de8: 0x0040, 0x1de9: 0xd5f9,
+	0x1dea: 0xd619, 0x1deb: 0xd619, 0x1dec: 0x8c5d, 0x1ded: 0xd639, 0x1dee: 0xd659, 0x1def: 0xd679,
+	0x1df0: 0xd699, 0x1df1: 0x8c7d, 0x1df2: 0xd6b9, 0x1df3: 0xd6d9, 0x1df4: 0x0040, 0x1df5: 0xd6f9,
+	0x1df6: 0xd719, 0x1df7: 0xd739, 0x1df8: 0xd759, 0x1df9: 0xd779, 0x1dfa: 0xd799, 0x1dfb: 0x8c9d,
+	0x1dfc: 0xd7b9, 0x1dfd: 0x8cbd, 0x1dfe: 0xd7d9, 0x1dff: 0xd7f9,
+	// Block 0x78, offset 0x1e00
+	0x1e00: 0xd819, 0x1e01: 0xd839, 0x1e02: 0xd859, 0x1e03: 0xd879, 0x1e04: 0xd899, 0x1e05: 0xd8b9,
+	0x1e06: 0xd8d9, 0x1e07: 0xd8f9, 0x1e08: 0xd919, 0x1e09: 0x8cdd, 0x1e0a: 0xd939, 0x1e0b: 0xd959,
+	0x1e0c: 0xd979, 0x1e0d: 0xd999, 0x1e0e: 0xd9b9, 0x1e0f: 0x8cfd, 0x1e10: 0xd9d9, 0x1e11: 0x8d1d,
+	0x1e12: 0x8d3d, 0x1e13: 0xd9f9, 0x1e14: 0xda19, 0x1e15: 0xda19, 0x1e16: 0xda39, 0x1e17: 0x8d5d,
+	0x1e18: 0x8d7d, 0x1e19: 0xda59, 0x1e1a: 0xda79, 0x1e1b: 0xda99, 0x1e1c: 0xdab9, 0x1e1d: 0xdad9,
+	0x1e1e: 0xdaf9, 0x1e1f: 0xdb19, 0x1e20: 0xdb39, 0x1e21: 0xdb59, 0x1e22: 0xdb79, 0x1e23: 0xdb99,
+	0x1e24: 0x8d9d, 0x1e25: 0xdbb9, 0x1e26: 0xdbd9, 0x1e27: 0xdbf9, 0x1e28: 0xdc19, 0x1e29: 0xdbf9,
+	0x1e2a: 0xdc39, 0x1e2b: 0xdc59, 0x1e2c: 0xdc79, 0x1e2d: 0xdc99, 0x1e2e: 0xdcb9, 0x1e2f: 0xdcd9,
+	0x1e30: 0xdcf9, 0x1e31: 0xdd19, 0x1e32: 0xdd39, 0x1e33: 0xdd59, 0x1e34: 0xdd79, 0x1e35: 0xdd99,
+	0x1e36: 0xddb9, 0x1e37: 0xddd9, 0x1e38: 0x8dbd, 0x1e39: 0xddf9, 0x1e3a: 0xde19, 0x1e3b: 0xde39,
+	0x1e3c: 0xde59, 0x1e3d: 0xde79, 0x1e3e: 0x8ddd, 0x1e3f: 0xde99,
+	// Block 0x79, offset 0x1e40
+	0x1e40: 0xe599, 0x1e41: 0xe5b9, 0x1e42: 0xe5d9, 0x1e43: 0xe5f9, 0x1e44: 0xe619, 0x1e45: 0xe639,
+	0x1e46: 0x8efd, 0x1e47: 0xe659, 0x1e48: 0xe679, 0x1e49: 0xe699, 0x1e4a: 0xe6b9, 0x1e4b: 0xe6d9,
+	0x1e4c: 0xe6f9, 0x1e4d: 0x8f1d, 0x1e4e: 0xe719, 0x1e4f: 0xe739, 0x1e50: 0x8f3d, 0x1e51: 0x8f5d,
+	0x1e52: 0xe759, 0x1e53: 0xe779, 0x1e54: 0xe799, 0x1e55: 0xe7b9, 0x1e56: 0xe7d9, 0x1e57: 0xe7f9,
+	0x1e58: 0xe819, 0x1e59: 0xe839, 0x1e5a: 0xe859, 0x1e5b: 0x8f7d, 0x1e5c: 0xe879, 0x1e5d: 0x8f9d,
+	0x1e5e: 0xe899, 0x1e5f: 0x0040, 0x1e60: 0xe8b9, 0x1e61: 0xe8d9, 0x1e62: 0xe8f9, 0x1e63: 0x8fbd,
+	0x1e64: 0xe919, 0x1e65: 0xe939, 0x1e66: 0x8fdd, 0x1e67: 0x8ffd, 0x1e68: 0xe959, 0x1e69: 0xe979,
+	0x1e6a: 0xe999, 0x1e6b: 0xe9b9, 0x1e6c: 0xe9d9, 0x1e6d: 0xe9d9, 0x1e6e: 0xe9f9, 0x1e6f: 0xea19,
+	0x1e70: 0xea39, 0x1e71: 0xea59, 0x1e72: 0xea79, 0x1e73: 0xea99, 0x1e74: 0xeab9, 0x1e75: 0x901d,
+	0x1e76: 0xead9, 0x1e77: 0x903d, 0x1e78: 0xeaf9, 0x1e79: 0x905d, 0x1e7a: 0xeb19, 0x1e7b: 0x907d,
+	0x1e7c: 0x909d, 0x1e7d: 0x90bd, 0x1e7e: 0xeb39, 0x1e7f: 0xeb59,
+	// Block 0x7a, offset 0x1e80
+	0x1e80: 0xeb79, 0x1e81: 0x90dd, 0x1e82: 0x90fd, 0x1e83: 0x911d, 0x1e84: 0x913d, 0x1e85: 0xeb99,
+	0x1e86: 0xebb9, 0x1e87: 0xebb9, 0x1e88: 0xebd9, 0x1e89: 0xebf9, 0x1e8a: 0xec19, 0x1e8b: 0xec39,
+	0x1e8c: 0xec59, 0x1e8d: 0x915d, 0x1e8e: 0xec79, 0x1e8f: 0xec99, 0x1e90: 0xecb9, 0x1e91: 0xecd9,
+	0x1e92: 0x917d, 0x1e93: 0xecf9, 0x1e94: 0x919d, 0x1e95: 0x91bd, 0x1e96: 0xed19, 0x1e97: 0xed39,
+	0x1e98: 0xed59, 0x1e99: 0xed79, 0x1e9a: 0xed99, 0x1e9b: 0xedb9, 0x1e9c: 0x91dd, 0x1e9d: 0x91fd,
+	0x1e9e: 0x921d, 0x1e9f: 0x0040, 0x1ea0: 0xedd9, 0x1ea1: 0x923d, 0x1ea2: 0xedf9, 0x1ea3: 0xee19,
+	0x1ea4: 0xee39, 0x1ea5: 0x925d, 0x1ea6: 0xee59, 0x1ea7: 0xee79, 0x1ea8: 0xee99, 0x1ea9: 0xeeb9,
+	0x1eaa: 0xeed9, 0x1eab: 0x927d, 0x1eac: 0xeef9, 0x1ead: 0xef19, 0x1eae: 0xef39, 0x1eaf: 0xef59,
+	0x1eb0: 0xef79, 0x1eb1: 0xef99, 0x1eb2: 0x929d, 0x1eb3: 0x92bd, 0x1eb4: 0xefb9, 0x1eb5: 0x92dd,
+	0x1eb6: 0xefd9, 0x1eb7: 0x92fd, 0x1eb8: 0xeff9, 0x1eb9: 0xf019, 0x1eba: 0xf039, 0x1ebb: 0x931d,
+	0x1ebc: 0x933d, 0x1ebd: 0xf059, 0x1ebe: 0x935d, 0x1ebf: 0xf079,
+	// Block 0x7b, offset 0x1ec0
+	0x1ec0: 0xf6b9, 0x1ec1: 0xf6d9, 0x1ec2: 0xf6f9, 0x1ec3: 0xf719, 0x1ec4: 0xf739, 0x1ec5: 0x951d,
+	0x1ec6: 0xf759, 0x1ec7: 0xf779, 0x1ec8: 0xf799, 0x1ec9: 0xf7b9, 0x1eca: 0xf7d9, 0x1ecb: 0x953d,
+	0x1ecc: 0x955d, 0x1ecd: 0xf7f9, 0x1ece: 0xf819, 0x1ecf: 0xf839, 0x1ed0: 0xf859, 0x1ed1: 0xf879,
+	0x1ed2: 0xf899, 0x1ed3: 0x957d, 0x1ed4: 0xf8b9, 0x1ed5: 0xf8d9, 0x1ed6: 0xf8f9, 0x1ed7: 0xf919,
+	0x1ed8: 0x959d, 0x1ed9: 0x95bd, 0x1eda: 0xf939, 0x1edb: 0xf959, 0x1edc: 0xf979, 0x1edd: 0x95dd,
+	0x1ede: 0xf999, 0x1edf: 0xf9b9, 0x1ee0: 0x6815, 0x1ee1: 0x95fd, 0x1ee2: 0xf9d9, 0x1ee3: 0xf9f9,
+	0x1ee4: 0xfa19, 0x1ee5: 0x961d, 0x1ee6: 0xfa39, 0x1ee7: 0xfa59, 0x1ee8: 0xfa79, 0x1ee9: 0xfa99,
+	0x1eea: 0xfab9, 0x1eeb: 0xfad9, 0x1eec: 0xfaf9, 0x1eed: 0x963d, 0x1eee: 0xfb19, 0x1eef: 0xfb39,
+	0x1ef0: 0xfb59, 0x1ef1: 0x965d, 0x1ef2: 0xfb79, 0x1ef3: 0xfb99, 0x1ef4: 0xfbb9, 0x1ef5: 0xfbd9,
+	0x1ef6: 0x7b35, 0x1ef7: 0x967d, 0x1ef8: 0xfbf9, 0x1ef9: 0xfc19, 0x1efa: 0xfc39, 0x1efb: 0x969d,
+	0x1efc: 0xfc59, 0x1efd: 0x96bd, 0x1efe: 0xfc79, 0x1eff: 0xfc79,
+	// Block 0x7c, offset 0x1f00
+	0x1f00: 0xfc99, 0x1f01: 0x96dd, 0x1f02: 0xfcb9, 0x1f03: 0xfcd9, 0x1f04: 0xfcf9, 0x1f05: 0xfd19,
+	0x1f06: 0xfd39, 0x1f07: 0xfd59, 0x1f08: 0xfd79, 0x1f09: 0x96fd, 0x1f0a: 0xfd99, 0x1f0b: 0xfdb9,
+	0x1f0c: 0xfdd9, 0x1f0d: 0xfdf9, 0x1f0e: 0xfe19, 0x1f0f: 0xfe39, 0x1f10: 0x971d, 0x1f11: 0xfe59,
+	0x1f12: 0x973d, 0x1f13: 0x975d, 0x1f14: 0x977d, 0x1f15: 0xfe79, 0x1f16: 0xfe99, 0x1f17: 0xfeb9,
+	0x1f18: 0xfed9, 0x1f19: 0xfef9, 0x1f1a: 0xff19, 0x1f1b: 0xff39, 0x1f1c: 0xff59, 0x1f1d: 0x979d,
+	0x1f1e: 0x0040, 0x1f1f: 0x0040, 0x1f20: 0x0040, 0x1f21: 0x0040, 0x1f22: 0x0040, 0x1f23: 0x0040,
+	0x1f24: 0x0040, 0x1f25: 0x0040, 0x1f26: 0x0040, 0x1f27: 0x0040, 0x1f28: 0x0040, 0x1f29: 0x0040,
+	0x1f2a: 0x0040, 0x1f2b: 0x0040, 0x1f2c: 0x0040, 0x1f2d: 0x0040, 0x1f2e: 0x0040, 0x1f2f: 0x0040,
+	0x1f30: 0x0040, 0x1f31: 0x0040, 0x1f32: 0x0040, 0x1f33: 0x0040, 0x1f34: 0x0040, 0x1f35: 0x0040,
+	0x1f36: 0x0040, 0x1f37: 0x0040, 0x1f38: 0x0040, 0x1f39: 0x0040, 0x1f3a: 0x0040, 0x1f3b: 0x0040,
+	0x1f3c: 0x0040, 0x1f3d: 0x0040, 0x1f3e: 0x0040, 0x1f3f: 0x0040,
+}
+
+// idnaIndex: 35 blocks, 2240 entries, 4480 bytes
+// Block 0 is the zero block.
+var idnaIndex = [2240]uint16{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x7b, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05,
+	0xc8: 0x06, 0xc9: 0x7c, 0xca: 0x7d, 0xcb: 0x07, 0xcc: 0x7e, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a,
+	0xd0: 0x7f, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x80, 0xd6: 0x81, 0xd7: 0x82,
+	0xd8: 0x0f, 0xd9: 0x83, 0xda: 0x84, 0xdb: 0x10, 0xdc: 0x11, 0xdd: 0x85, 0xde: 0x86, 0xdf: 0x87,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07,
+	0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c,
+	0xf0: 0x1c, 0xf1: 0x1d, 0xf2: 0x1d, 0xf3: 0x1f, 0xf4: 0x20,
+	// Block 0x4, offset 0x100
+	0x120: 0x88, 0x121: 0x89, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x12, 0x126: 0x13, 0x127: 0x14,
+	0x128: 0x15, 0x129: 0x16, 0x12a: 0x17, 0x12b: 0x18, 0x12c: 0x19, 0x12d: 0x1a, 0x12e: 0x1b, 0x12f: 0x8d,
+	0x130: 0x8e, 0x131: 0x1c, 0x132: 0x1d, 0x133: 0x1e, 0x134: 0x8f, 0x135: 0x1f, 0x136: 0x90, 0x137: 0x91,
+	0x138: 0x92, 0x139: 0x93, 0x13a: 0x20, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x21, 0x13e: 0x22, 0x13f: 0x96,
+	// Block 0x5, offset 0x140
+	0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9b, 0x147: 0x9b,
+	0x148: 0x9d, 0x149: 0x9e, 0x14a: 0x9f, 0x14b: 0xa0, 0x14c: 0xa1, 0x14d: 0xa2, 0x14e: 0xa3, 0x14f: 0xa4,
+	0x150: 0xa5, 0x151: 0x9d, 0x152: 0x9d, 0x153: 0x9d, 0x154: 0x9d, 0x155: 0x9d, 0x156: 0x9d, 0x157: 0x9d,
+	0x158: 0x9d, 0x159: 0xa6, 0x15a: 0xa7, 0x15b: 0xa8, 0x15c: 0xa9, 0x15d: 0xaa, 0x15e: 0xab, 0x15f: 0xac,
+	0x160: 0xad, 0x161: 0xae, 0x162: 0xaf, 0x163: 0xb0, 0x164: 0xb1, 0x165: 0xb2, 0x166: 0xb3, 0x167: 0xb4,
+	0x168: 0xb5, 0x169: 0xb6, 0x16a: 0xb7, 0x16b: 0xb8, 0x16c: 0xb9, 0x16d: 0xba, 0x16e: 0xbb, 0x16f: 0xbc,
+	0x170: 0xbd, 0x171: 0xbe, 0x172: 0xbf, 0x173: 0xc0, 0x174: 0x23, 0x175: 0x24, 0x176: 0x25, 0x177: 0xc1,
+	0x178: 0x26, 0x179: 0x26, 0x17a: 0x27, 0x17b: 0x26, 0x17c: 0xc2, 0x17d: 0x28, 0x17e: 0x29, 0x17f: 0x2a,
+	// Block 0x6, offset 0x180
+	0x180: 0x2b, 0x181: 0x2c, 0x182: 0x2d, 0x183: 0xc3, 0x184: 0x2e, 0x185: 0x2f, 0x186: 0xc4, 0x187: 0x9b,
+	0x188: 0xc5, 0x189: 0xc6, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc7, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0xc8,
+	0x190: 0xc9, 0x191: 0x30, 0x192: 0x31, 0x193: 0x32, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b,
+	0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b,
+	0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b,
+	0x1a8: 0xca, 0x1a9: 0xcb, 0x1aa: 0x9b, 0x1ab: 0xcc, 0x1ac: 0x9b, 0x1ad: 0xcd, 0x1ae: 0xce, 0x1af: 0xcf,
+	0x1b0: 0xd0, 0x1b1: 0x33, 0x1b2: 0x26, 0x1b3: 0x34, 0x1b4: 0xd1, 0x1b5: 0xd2, 0x1b6: 0xd3, 0x1b7: 0xd4,
+	0x1b8: 0xd5, 0x1b9: 0xd6, 0x1ba: 0xd7, 0x1bb: 0xd8, 0x1bc: 0xd9, 0x1bd: 0xda, 0x1be: 0xdb, 0x1bf: 0x35,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x36, 0x1c1: 0xdc, 0x1c2: 0xdd, 0x1c3: 0xde, 0x1c4: 0xdf, 0x1c5: 0x37, 0x1c6: 0x38, 0x1c7: 0xe0,
+	0x1c8: 0xe1, 0x1c9: 0x39, 0x1ca: 0x3a, 0x1cb: 0x3b, 0x1cc: 0x3c, 0x1cd: 0x3d, 0x1ce: 0x3e, 0x1cf: 0x3f,
+	0x1d0: 0x9d, 0x1d1: 0x9d, 0x1d2: 0x9d, 0x1d3: 0x9d, 0x1d4: 0x9d, 0x1d5: 0x9d, 0x1d6: 0x9d, 0x1d7: 0x9d,
+	0x1d8: 0x9d, 0x1d9: 0x9d, 0x1da: 0x9d, 0x1db: 0x9d, 0x1dc: 0x9d, 0x1dd: 0x9d, 0x1de: 0x9d, 0x1df: 0x9d,
+	0x1e0: 0x9d, 0x1e1: 0x9d, 0x1e2: 0x9d, 0x1e3: 0x9d, 0x1e4: 0x9d, 0x1e5: 0x9d, 0x1e6: 0x9d, 0x1e7: 0x9d,
+	0x1e8: 0x9d, 0x1e9: 0x9d, 0x1ea: 0x9d, 0x1eb: 0x9d, 0x1ec: 0x9d, 0x1ed: 0x9d, 0x1ee: 0x9d, 0x1ef: 0x9d,
+	0x1f0: 0x9d, 0x1f1: 0x9d, 0x1f2: 0x9d, 0x1f3: 0x9d, 0x1f4: 0x9d, 0x1f5: 0x9d, 0x1f6: 0x9d, 0x1f7: 0x9d,
+	0x1f8: 0x9d, 0x1f9: 0x9d, 0x1fa: 0x9d, 0x1fb: 0x9d, 0x1fc: 0x9d, 0x1fd: 0x9d, 0x1fe: 0x9d, 0x1ff: 0x9d,
+	// Block 0x8, offset 0x200
+	0x200: 0x9d, 0x201: 0x9d, 0x202: 0x9d, 0x203: 0x9d, 0x204: 0x9d, 0x205: 0x9d, 0x206: 0x9d, 0x207: 0x9d,
+	0x208: 0x9d, 0x209: 0x9d, 0x20a: 0x9d, 0x20b: 0x9d, 0x20c: 0x9d, 0x20d: 0x9d, 0x20e: 0x9d, 0x20f: 0x9d,
+	0x210: 0x9d, 0x211: 0x9d, 0x212: 0x9d, 0x213: 0x9d, 0x214: 0x9d, 0x215: 0x9d, 0x216: 0x9d, 0x217: 0x9d,
+	0x218: 0x9d, 0x219: 0x9d, 0x21a: 0x9d, 0x21b: 0x9d, 0x21c: 0x9d, 0x21d: 0x9d, 0x21e: 0x9d, 0x21f: 0x9d,
+	0x220: 0x9d, 0x221: 0x9d, 0x222: 0x9d, 0x223: 0x9d, 0x224: 0x9d, 0x225: 0x9d, 0x226: 0x9d, 0x227: 0x9d,
+	0x228: 0x9d, 0x229: 0x9d, 0x22a: 0x9d, 0x22b: 0x9d, 0x22c: 0x9d, 0x22d: 0x9d, 0x22e: 0x9d, 0x22f: 0x9d,
+	0x230: 0x9d, 0x231: 0x9d, 0x232: 0x9d, 0x233: 0x9d, 0x234: 0x9d, 0x235: 0x9d, 0x236: 0xb0, 0x237: 0x9b,
+	0x238: 0x9d, 0x239: 0x9d, 0x23a: 0x9d, 0x23b: 0x9d, 0x23c: 0x9d, 0x23d: 0x9d, 0x23e: 0x9d, 0x23f: 0x9d,
+	// Block 0x9, offset 0x240
+	0x240: 0x9d, 0x241: 0x9d, 0x242: 0x9d, 0x243: 0x9d, 0x244: 0x9d, 0x245: 0x9d, 0x246: 0x9d, 0x247: 0x9d,
+	0x248: 0x9d, 0x249: 0x9d, 0x24a: 0x9d, 0x24b: 0x9d, 0x24c: 0x9d, 0x24d: 0x9d, 0x24e: 0x9d, 0x24f: 0x9d,
+	0x250: 0x9d, 0x251: 0x9d, 0x252: 0x9d, 0x253: 0x9d, 0x254: 0x9d, 0x255: 0x9d, 0x256: 0x9d, 0x257: 0x9d,
+	0x258: 0x9d, 0x259: 0x9d, 0x25a: 0x9d, 0x25b: 0x9d, 0x25c: 0x9d, 0x25d: 0x9d, 0x25e: 0x9d, 0x25f: 0x9d,
+	0x260: 0x9d, 0x261: 0x9d, 0x262: 0x9d, 0x263: 0x9d, 0x264: 0x9d, 0x265: 0x9d, 0x266: 0x9d, 0x267: 0x9d,
+	0x268: 0x9d, 0x269: 0x9d, 0x26a: 0x9d, 0x26b: 0x9d, 0x26c: 0x9d, 0x26d: 0x9d, 0x26e: 0x9d, 0x26f: 0x9d,
+	0x270: 0x9d, 0x271: 0x9d, 0x272: 0x9d, 0x273: 0x9d, 0x274: 0x9d, 0x275: 0x9d, 0x276: 0x9d, 0x277: 0x9d,
+	0x278: 0x9d, 0x279: 0x9d, 0x27a: 0x9d, 0x27b: 0x9d, 0x27c: 0x9d, 0x27d: 0x9d, 0x27e: 0x9d, 0x27f: 0x9d,
+	// Block 0xa, offset 0x280
+	0x280: 0x9d, 0x281: 0x9d, 0x282: 0x9d, 0x283: 0x9d, 0x284: 0x9d, 0x285: 0x9d, 0x286: 0x9d, 0x287: 0x9d,
+	0x288: 0x9d, 0x289: 0x9d, 0x28a: 0x9d, 0x28b: 0x9d, 0x28c: 0x9d, 0x28d: 0x9d, 0x28e: 0x9d, 0x28f: 0x9d,
+	0x290: 0x9d, 0x291: 0x9d, 0x292: 0x9d, 0x293: 0x9d, 0x294: 0x9d, 0x295: 0x9d, 0x296: 0x9d, 0x297: 0x9d,
+	0x298: 0x9d, 0x299: 0x9d, 0x29a: 0x9d, 0x29b: 0x9d, 0x29c: 0x9d, 0x29d: 0x9d, 0x29e: 0x9d, 0x29f: 0x9d,
+	0x2a0: 0x9d, 0x2a1: 0x9d, 0x2a2: 0x9d, 0x2a3: 0x9d, 0x2a4: 0x9d, 0x2a5: 0x9d, 0x2a6: 0x9d, 0x2a7: 0x9d,
+	0x2a8: 0x9d, 0x2a9: 0x9d, 0x2aa: 0x9d, 0x2ab: 0x9d, 0x2ac: 0x9d, 0x2ad: 0x9d, 0x2ae: 0x9d, 0x2af: 0x9d,
+	0x2b0: 0x9d, 0x2b1: 0x9d, 0x2b2: 0x9d, 0x2b3: 0x9d, 0x2b4: 0x9d, 0x2b5: 0x9d, 0x2b6: 0x9d, 0x2b7: 0x9d,
+	0x2b8: 0x9d, 0x2b9: 0x9d, 0x2ba: 0x9d, 0x2bb: 0x9d, 0x2bc: 0x9d, 0x2bd: 0x9d, 0x2be: 0x9d, 0x2bf: 0xe2,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x9d, 0x2c1: 0x9d, 0x2c2: 0x9d, 0x2c3: 0x9d, 0x2c4: 0x9d, 0x2c5: 0x9d, 0x2c6: 0x9d, 0x2c7: 0x9d,
+	0x2c8: 0x9d, 0x2c9: 0x9d, 0x2ca: 0x9d, 0x2cb: 0x9d, 0x2cc: 0x9d, 0x2cd: 0x9d, 0x2ce: 0x9d, 0x2cf: 0x9d,
+	0x2d0: 0x9d, 0x2d1: 0x9d, 0x2d2: 0xe3, 0x2d3: 0xe4, 0x2d4: 0x9d, 0x2d5: 0x9d, 0x2d6: 0x9d, 0x2d7: 0x9d,
+	0x2d8: 0xe5, 0x2d9: 0x40, 0x2da: 0x41, 0x2db: 0xe6, 0x2dc: 0x42, 0x2dd: 0x43, 0x2de: 0x44, 0x2df: 0xe7,
+	0x2e0: 0xe8, 0x2e1: 0xe9, 0x2e2: 0xea, 0x2e3: 0xeb, 0x2e4: 0xec, 0x2e5: 0xed, 0x2e6: 0xee, 0x2e7: 0xef,
+	0x2e8: 0xf0, 0x2e9: 0xf1, 0x2ea: 0xf2, 0x2eb: 0xf3, 0x2ec: 0xf4, 0x2ed: 0xf5, 0x2ee: 0xf6, 0x2ef: 0xf7,
+	0x2f0: 0x9d, 0x2f1: 0x9d, 0x2f2: 0x9d, 0x2f3: 0x9d, 0x2f4: 0x9d, 0x2f5: 0x9d, 0x2f6: 0x9d, 0x2f7: 0x9d,
+	0x2f8: 0x9d, 0x2f9: 0x9d, 0x2fa: 0x9d, 0x2fb: 0x9d, 0x2fc: 0x9d, 0x2fd: 0x9d, 0x2fe: 0x9d, 0x2ff: 0x9d,
+	// Block 0xc, offset 0x300
+	0x300: 0x9d, 0x301: 0x9d, 0x302: 0x9d, 0x303: 0x9d, 0x304: 0x9d, 0x305: 0x9d, 0x306: 0x9d, 0x307: 0x9d,
+	0x308: 0x9d, 0x309: 0x9d, 0x30a: 0x9d, 0x30b: 0x9d, 0x30c: 0x9d, 0x30d: 0x9d, 0x30e: 0x9d, 0x30f: 0x9d,
+	0x310: 0x9d, 0x311: 0x9d, 0x312: 0x9d, 0x313: 0x9d, 0x314: 0x9d, 0x315: 0x9d, 0x316: 0x9d, 0x317: 0x9d,
+	0x318: 0x9d, 0x319: 0x9d, 0x31a: 0x9d, 0x31b: 0x9d, 0x31c: 0x9d, 0x31d: 0x9d, 0x31e: 0xf8, 0x31f: 0xf9,
+	// Block 0xd, offset 0x340
+	0x340: 0xb8, 0x341: 0xb8, 0x342: 0xb8, 0x343: 0xb8, 0x344: 0xb8, 0x345: 0xb8, 0x346: 0xb8, 0x347: 0xb8,
+	0x348: 0xb8, 0x349: 0xb8, 0x34a: 0xb8, 0x34b: 0xb8, 0x34c: 0xb8, 0x34d: 0xb8, 0x34e: 0xb8, 0x34f: 0xb8,
+	0x350: 0xb8, 0x351: 0xb8, 0x352: 0xb8, 0x353: 0xb8, 0x354: 0xb8, 0x355: 0xb8, 0x356: 0xb8, 0x357: 0xb8,
+	0x358: 0xb8, 0x359: 0xb8, 0x35a: 0xb8, 0x35b: 0xb8, 0x35c: 0xb8, 0x35d: 0xb8, 0x35e: 0xb8, 0x35f: 0xb8,
+	0x360: 0xb8, 0x361: 0xb8, 0x362: 0xb8, 0x363: 0xb8, 0x364: 0xb8, 0x365: 0xb8, 0x366: 0xb8, 0x367: 0xb8,
+	0x368: 0xb8, 0x369: 0xb8, 0x36a: 0xb8, 0x36b: 0xb8, 0x36c: 0xb8, 0x36d: 0xb8, 0x36e: 0xb8, 0x36f: 0xb8,
+	0x370: 0xb8, 0x371: 0xb8, 0x372: 0xb8, 0x373: 0xb8, 0x374: 0xb8, 0x375: 0xb8, 0x376: 0xb8, 0x377: 0xb8,
+	0x378: 0xb8, 0x379: 0xb8, 0x37a: 0xb8, 0x37b: 0xb8, 0x37c: 0xb8, 0x37d: 0xb8, 0x37e: 0xb8, 0x37f: 0xb8,
+	// Block 0xe, offset 0x380
+	0x380: 0xb8, 0x381: 0xb8, 0x382: 0xb8, 0x383: 0xb8, 0x384: 0xb8, 0x385: 0xb8, 0x386: 0xb8, 0x387: 0xb8,
+	0x388: 0xb8, 0x389: 0xb8, 0x38a: 0xb8, 0x38b: 0xb8, 0x38c: 0xb8, 0x38d: 0xb8, 0x38e: 0xb8, 0x38f: 0xb8,
+	0x390: 0xb8, 0x391: 0xb8, 0x392: 0xb8, 0x393: 0xb8, 0x394: 0xb8, 0x395: 0xb8, 0x396: 0xb8, 0x397: 0xb8,
+	0x398: 0xb8, 0x399: 0xb8, 0x39a: 0xb8, 0x39b: 0xb8, 0x39c: 0xb8, 0x39d: 0xb8, 0x39e: 0xb8, 0x39f: 0xb8,
+	0x3a0: 0xb8, 0x3a1: 0xb8, 0x3a2: 0xb8, 0x3a3: 0xb8, 0x3a4: 0xfa, 0x3a5: 0xfb, 0x3a6: 0xfc, 0x3a7: 0xfd,
+	0x3a8: 0x45, 0x3a9: 0xfe, 0x3aa: 0xff, 0x3ab: 0x46, 0x3ac: 0x47, 0x3ad: 0x48, 0x3ae: 0x49, 0x3af: 0x4a,
+	0x3b0: 0x100, 0x3b1: 0x4b, 0x3b2: 0x4c, 0x3b3: 0x4d, 0x3b4: 0x4e, 0x3b5: 0x4f, 0x3b6: 0x101, 0x3b7: 0x50,
+	0x3b8: 0x51, 0x3b9: 0x52, 0x3ba: 0x53, 0x3bb: 0x54, 0x3bc: 0x55, 0x3bd: 0x56, 0x3be: 0x57, 0x3bf: 0x58,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x102, 0x3c1: 0x103, 0x3c2: 0x9d, 0x3c3: 0x104, 0x3c4: 0x105, 0x3c5: 0x9b, 0x3c6: 0x106, 0x3c7: 0x107,
+	0x3c8: 0xb8, 0x3c9: 0xb8, 0x3ca: 0x108, 0x3cb: 0x109, 0x3cc: 0x10a, 0x3cd: 0x10b, 0x3ce: 0x10c, 0x3cf: 0x10d,
+	0x3d0: 0x10e, 0x3d1: 0x9d, 0x3d2: 0x10f, 0x3d3: 0x110, 0x3d4: 0x111, 0x3d5: 0x112, 0x3d6: 0xb8, 0x3d7: 0xb8,
+	0x3d8: 0x9d, 0x3d9: 0x9d, 0x3da: 0x9d, 0x3db: 0x9d, 0x3dc: 0x113, 0x3dd: 0x114, 0x3de: 0xb8, 0x3df: 0xb8,
+	0x3e0: 0x115, 0x3e1: 0x116, 0x3e2: 0x117, 0x3e3: 0x118, 0x3e4: 0x119, 0x3e5: 0xb8, 0x3e6: 0x11a, 0x3e7: 0x11b,
+	0x3e8: 0x11c, 0x3e9: 0x11d, 0x3ea: 0x11e, 0x3eb: 0x59, 0x3ec: 0x11f, 0x3ed: 0x120, 0x3ee: 0x5a, 0x3ef: 0xb8,
+	0x3f0: 0x9d, 0x3f1: 0x121, 0x3f2: 0x122, 0x3f3: 0x123, 0x3f4: 0xb8, 0x3f5: 0xb8, 0x3f6: 0xb8, 0x3f7: 0xb8,
+	0x3f8: 0xb8, 0x3f9: 0x124, 0x3fa: 0xb8, 0x3fb: 0xb8, 0x3fc: 0xb8, 0x3fd: 0xb8, 0x3fe: 0xb8, 0x3ff: 0xb8,
+	// Block 0x10, offset 0x400
+	0x400: 0x125, 0x401: 0x126, 0x402: 0x127, 0x403: 0x128, 0x404: 0x129, 0x405: 0x12a, 0x406: 0x12b, 0x407: 0x12c,
+	0x408: 0x12d, 0x409: 0xb8, 0x40a: 0x12e, 0x40b: 0x12f, 0x40c: 0x5b, 0x40d: 0x5c, 0x40e: 0xb8, 0x40f: 0xb8,
+	0x410: 0x130, 0x411: 0x131, 0x412: 0x132, 0x413: 0x133, 0x414: 0xb8, 0x415: 0xb8, 0x416: 0x134, 0x417: 0x135,
+	0x418: 0x136, 0x419: 0x137, 0x41a: 0x138, 0x41b: 0x139, 0x41c: 0x13a, 0x41d: 0xb8, 0x41e: 0xb8, 0x41f: 0xb8,
+	0x420: 0xb8, 0x421: 0xb8, 0x422: 0x13b, 0x423: 0x13c, 0x424: 0xb8, 0x425: 0xb8, 0x426: 0xb8, 0x427: 0xb8,
+	0x428: 0xb8, 0x429: 0xb8, 0x42a: 0xb8, 0x42b: 0x13d, 0x42c: 0xb8, 0x42d: 0xb8, 0x42e: 0xb8, 0x42f: 0xb8,
+	0x430: 0x13e, 0x431: 0x13f, 0x432: 0x140, 0x433: 0xb8, 0x434: 0xb8, 0x435: 0xb8, 0x436: 0xb8, 0x437: 0xb8,
+	0x438: 0xb8, 0x439: 0xb8, 0x43a: 0xb8, 0x43b: 0xb8, 0x43c: 0xb8, 0x43d: 0xb8, 0x43e: 0xb8, 0x43f: 0xb8,
+	// Block 0x11, offset 0x440
+	0x440: 0x9d, 0x441: 0x9d, 0x442: 0x9d, 0x443: 0x9d, 0x444: 0x9d, 0x445: 0x9d, 0x446: 0x9d, 0x447: 0x9d,
+	0x448: 0x9d, 0x449: 0x9d, 0x44a: 0x9d, 0x44b: 0x9d, 0x44c: 0x9d, 0x44d: 0x9d, 0x44e: 0x141, 0x44f: 0xb8,
+	0x450: 0x9b, 0x451: 0x142, 0x452: 0x9d, 0x453: 0x9d, 0x454: 0x9d, 0x455: 0x143, 0x456: 0xb8, 0x457: 0xb8,
+	0x458: 0xb8, 0x459: 0xb8, 0x45a: 0xb8, 0x45b: 0xb8, 0x45c: 0xb8, 0x45d: 0xb8, 0x45e: 0xb8, 0x45f: 0xb8,
+	0x460: 0xb8, 0x461: 0xb8, 0x462: 0xb8, 0x463: 0xb8, 0x464: 0xb8, 0x465: 0xb8, 0x466: 0xb8, 0x467: 0xb8,
+	0x468: 0xb8, 0x469: 0xb8, 0x46a: 0xb8, 0x46b: 0xb8, 0x46c: 0xb8, 0x46d: 0xb8, 0x46e: 0xb8, 0x46f: 0xb8,
+	0x470: 0xb8, 0x471: 0xb8, 0x472: 0xb8, 0x473: 0xb8, 0x474: 0xb8, 0x475: 0xb8, 0x476: 0xb8, 0x477: 0xb8,
+	0x478: 0xb8, 0x479: 0xb8, 0x47a: 0xb8, 0x47b: 0xb8, 0x47c: 0xb8, 0x47d: 0xb8, 0x47e: 0xb8, 0x47f: 0xb8,
+	// Block 0x12, offset 0x480
+	0x480: 0x9d, 0x481: 0x9d, 0x482: 0x9d, 0x483: 0x9d, 0x484: 0x9d, 0x485: 0x9d, 0x486: 0x9d, 0x487: 0x9d,
+	0x488: 0x9d, 0x489: 0x9d, 0x48a: 0x9d, 0x48b: 0x9d, 0x48c: 0x9d, 0x48d: 0x9d, 0x48e: 0x9d, 0x48f: 0x9d,
+	0x490: 0x144, 0x491: 0xb8, 0x492: 0xb8, 0x493: 0xb8, 0x494: 0xb8, 0x495: 0xb8, 0x496: 0xb8, 0x497: 0xb8,
+	0x498: 0xb8, 0x499: 0xb8, 0x49a: 0xb8, 0x49b: 0xb8, 0x49c: 0xb8, 0x49d: 0xb8, 0x49e: 0xb8, 0x49f: 0xb8,
+	0x4a0: 0xb8, 0x4a1: 0xb8, 0x4a2: 0xb8, 0x4a3: 0xb8, 0x4a4: 0xb8, 0x4a5: 0xb8, 0x4a6: 0xb8, 0x4a7: 0xb8,
+	0x4a8: 0xb8, 0x4a9: 0xb8, 0x4aa: 0xb8, 0x4ab: 0xb8, 0x4ac: 0xb8, 0x4ad: 0xb8, 0x4ae: 0xb8, 0x4af: 0xb8,
+	0x4b0: 0xb8, 0x4b1: 0xb8, 0x4b2: 0xb8, 0x4b3: 0xb8, 0x4b4: 0xb8, 0x4b5: 0xb8, 0x4b6: 0xb8, 0x4b7: 0xb8,
+	0x4b8: 0xb8, 0x4b9: 0xb8, 0x4ba: 0xb8, 0x4bb: 0xb8, 0x4bc: 0xb8, 0x4bd: 0xb8, 0x4be: 0xb8, 0x4bf: 0xb8,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0xb8, 0x4c1: 0xb8, 0x4c2: 0xb8, 0x4c3: 0xb8, 0x4c4: 0xb8, 0x4c5: 0xb8, 0x4c6: 0xb8, 0x4c7: 0xb8,
+	0x4c8: 0xb8, 0x4c9: 0xb8, 0x4ca: 0xb8, 0x4cb: 0xb8, 0x4cc: 0xb8, 0x4cd: 0xb8, 0x4ce: 0xb8, 0x4cf: 0xb8,
+	0x4d0: 0x9d, 0x4d1: 0x9d, 0x4d2: 0x9d, 0x4d3: 0x9d, 0x4d4: 0x9d, 0x4d5: 0x9d, 0x4d6: 0x9d, 0x4d7: 0x9d,
+	0x4d8: 0x9d, 0x4d9: 0x145, 0x4da: 0xb8, 0x4db: 0xb8, 0x4dc: 0xb8, 0x4dd: 0xb8, 0x4de: 0xb8, 0x4df: 0xb8,
+	0x4e0: 0xb8, 0x4e1: 0xb8, 0x4e2: 0xb8, 0x4e3: 0xb8, 0x4e4: 0xb8, 0x4e5: 0xb8, 0x4e6: 0xb8, 0x4e7: 0xb8,
+	0x4e8: 0xb8, 0x4e9: 0xb8, 0x4ea: 0xb8, 0x4eb: 0xb8, 0x4ec: 0xb8, 0x4ed: 0xb8, 0x4ee: 0xb8, 0x4ef: 0xb8,
+	0x4f0: 0xb8, 0x4f1: 0xb8, 0x4f2: 0xb8, 0x4f3: 0xb8, 0x4f4: 0xb8, 0x4f5: 0xb8, 0x4f6: 0xb8, 0x4f7: 0xb8,
+	0x4f8: 0xb8, 0x4f9: 0xb8, 0x4fa: 0xb8, 0x4fb: 0xb8, 0x4fc: 0xb8, 0x4fd: 0xb8, 0x4fe: 0xb8, 0x4ff: 0xb8,
+	// Block 0x14, offset 0x500
+	0x500: 0xb8, 0x501: 0xb8, 0x502: 0xb8, 0x503: 0xb8, 0x504: 0xb8, 0x505: 0xb8, 0x506: 0xb8, 0x507: 0xb8,
+	0x508: 0xb8, 0x509: 0xb8, 0x50a: 0xb8, 0x50b: 0xb8, 0x50c: 0xb8, 0x50d: 0xb8, 0x50e: 0xb8, 0x50f: 0xb8,
+	0x510: 0xb8, 0x511: 0xb8, 0x512: 0xb8, 0x513: 0xb8, 0x514: 0xb8, 0x515: 0xb8, 0x516: 0xb8, 0x517: 0xb8,
+	0x518: 0xb8, 0x519: 0xb8, 0x51a: 0xb8, 0x51b: 0xb8, 0x51c: 0xb8, 0x51d: 0xb8, 0x51e: 0xb8, 0x51f: 0xb8,
+	0x520: 0x9d, 0x521: 0x9d, 0x522: 0x9d, 0x523: 0x9d, 0x524: 0x9d, 0x525: 0x9d, 0x526: 0x9d, 0x527: 0x9d,
+	0x528: 0x13d, 0x529: 0x146, 0x52a: 0xb8, 0x52b: 0x147, 0x52c: 0x148, 0x52d: 0x149, 0x52e: 0x14a, 0x52f: 0xb8,
+	0x530: 0xb8, 0x531: 0xb8, 0x532: 0xb8, 0x533: 0xb8, 0x534: 0xb8, 0x535: 0xb8, 0x536: 0xb8, 0x537: 0xb8,
+	0x538: 0xb8, 0x539: 0xb8, 0x53a: 0xb8, 0x53b: 0xb8, 0x53c: 0x9d, 0x53d: 0x14b, 0x53e: 0x14c, 0x53f: 0x14d,
+	// Block 0x15, offset 0x540
+	0x540: 0x9d, 0x541: 0x9d, 0x542: 0x9d, 0x543: 0x9d, 0x544: 0x9d, 0x545: 0x9d, 0x546: 0x9d, 0x547: 0x9d,
+	0x548: 0x9d, 0x549: 0x9d, 0x54a: 0x9d, 0x54b: 0x9d, 0x54c: 0x9d, 0x54d: 0x9d, 0x54e: 0x9d, 0x54f: 0x9d,
+	0x550: 0x9d, 0x551: 0x9d, 0x552: 0x9d, 0x553: 0x9d, 0x554: 0x9d, 0x555: 0x9d, 0x556: 0x9d, 0x557: 0x9d,
+	0x558: 0x9d, 0x559: 0x9d, 0x55a: 0x9d, 0x55b: 0x9d, 0x55c: 0x9d, 0x55d: 0x9d, 0x55e: 0x9d, 0x55f: 0x14e,
+	0x560: 0x9d, 0x561: 0x9d, 0x562: 0x9d, 0x563: 0x9d, 0x564: 0x9d, 0x565: 0x9d, 0x566: 0x9d, 0x567: 0x9d,
+	0x568: 0x9d, 0x569: 0x9d, 0x56a: 0x9d, 0x56b: 0x14f, 0x56c: 0xb8, 0x56d: 0xb8, 0x56e: 0xb8, 0x56f: 0xb8,
+	0x570: 0xb8, 0x571: 0xb8, 0x572: 0xb8, 0x573: 0xb8, 0x574: 0xb8, 0x575: 0xb8, 0x576: 0xb8, 0x577: 0xb8,
+	0x578: 0xb8, 0x579: 0xb8, 0x57a: 0xb8, 0x57b: 0xb8, 0x57c: 0xb8, 0x57d: 0xb8, 0x57e: 0xb8, 0x57f: 0xb8,
+	// Block 0x16, offset 0x580
+	0x580: 0x150, 0x581: 0xb8, 0x582: 0xb8, 0x583: 0xb8, 0x584: 0xb8, 0x585: 0xb8, 0x586: 0xb8, 0x587: 0xb8,
+	0x588: 0xb8, 0x589: 0xb8, 0x58a: 0xb8, 0x58b: 0xb8, 0x58c: 0xb8, 0x58d: 0xb8, 0x58e: 0xb8, 0x58f: 0xb8,
+	0x590: 0xb8, 0x591: 0xb8, 0x592: 0xb8, 0x593: 0xb8, 0x594: 0xb8, 0x595: 0xb8, 0x596: 0xb8, 0x597: 0xb8,
+	0x598: 0xb8, 0x599: 0xb8, 0x59a: 0xb8, 0x59b: 0xb8, 0x59c: 0xb8, 0x59d: 0xb8, 0x59e: 0xb8, 0x59f: 0xb8,
+	0x5a0: 0xb8, 0x5a1: 0xb8, 0x5a2: 0xb8, 0x5a3: 0xb8, 0x5a4: 0xb8, 0x5a5: 0xb8, 0x5a6: 0xb8, 0x5a7: 0xb8,
+	0x5a8: 0xb8, 0x5a9: 0xb8, 0x5aa: 0xb8, 0x5ab: 0xb8, 0x5ac: 0xb8, 0x5ad: 0xb8, 0x5ae: 0xb8, 0x5af: 0xb8,
+	0x5b0: 0x9d, 0x5b1: 0x151, 0x5b2: 0x152, 0x5b3: 0xb8, 0x5b4: 0xb8, 0x5b5: 0xb8, 0x5b6: 0xb8, 0x5b7: 0xb8,
+	0x5b8: 0xb8, 0x5b9: 0xb8, 0x5ba: 0xb8, 0x5bb: 0xb8, 0x5bc: 0xb8, 0x5bd: 0xb8, 0x5be: 0xb8, 0x5bf: 0xb8,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x153, 0x5c4: 0x154, 0x5c5: 0x155, 0x5c6: 0x156, 0x5c7: 0x157,
+	0x5c8: 0x9b, 0x5c9: 0x158, 0x5ca: 0xb8, 0x5cb: 0xb8, 0x5cc: 0x9b, 0x5cd: 0x159, 0x5ce: 0xb8, 0x5cf: 0xb8,
+	0x5d0: 0x5d, 0x5d1: 0x5e, 0x5d2: 0x5f, 0x5d3: 0x60, 0x5d4: 0x61, 0x5d5: 0x62, 0x5d6: 0x63, 0x5d7: 0x64,
+	0x5d8: 0x65, 0x5d9: 0x66, 0x5da: 0x67, 0x5db: 0x68, 0x5dc: 0x69, 0x5dd: 0x6a, 0x5de: 0x6b, 0x5df: 0x6c,
+	0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b,
+	0x5e8: 0x15a, 0x5e9: 0x15b, 0x5ea: 0x15c, 0x5eb: 0xb8, 0x5ec: 0xb8, 0x5ed: 0xb8, 0x5ee: 0xb8, 0x5ef: 0xb8,
+	0x5f0: 0xb8, 0x5f1: 0xb8, 0x5f2: 0xb8, 0x5f3: 0xb8, 0x5f4: 0xb8, 0x5f5: 0xb8, 0x5f6: 0xb8, 0x5f7: 0xb8,
+	0x5f8: 0xb8, 0x5f9: 0xb8, 0x5fa: 0xb8, 0x5fb: 0xb8, 0x5fc: 0xb8, 0x5fd: 0xb8, 0x5fe: 0xb8, 0x5ff: 0xb8,
+	// Block 0x18, offset 0x600
+	0x600: 0x15d, 0x601: 0xb8, 0x602: 0xb8, 0x603: 0xb8, 0x604: 0xb8, 0x605: 0xb8, 0x606: 0xb8, 0x607: 0xb8,
+	0x608: 0xb8, 0x609: 0xb8, 0x60a: 0xb8, 0x60b: 0xb8, 0x60c: 0xb8, 0x60d: 0xb8, 0x60e: 0xb8, 0x60f: 0xb8,
+	0x610: 0xb8, 0x611: 0xb8, 0x612: 0xb8, 0x613: 0xb8, 0x614: 0xb8, 0x615: 0xb8, 0x616: 0xb8, 0x617: 0xb8,
+	0x618: 0xb8, 0x619: 0xb8, 0x61a: 0xb8, 0x61b: 0xb8, 0x61c: 0xb8, 0x61d: 0xb8, 0x61e: 0xb8, 0x61f: 0xb8,
+	0x620: 0x9d, 0x621: 0x9d, 0x622: 0x9d, 0x623: 0x15e, 0x624: 0x6d, 0x625: 0x15f, 0x626: 0xb8, 0x627: 0xb8,
+	0x628: 0xb8, 0x629: 0xb8, 0x62a: 0xb8, 0x62b: 0xb8, 0x62c: 0xb8, 0x62d: 0xb8, 0x62e: 0xb8, 0x62f: 0xb8,
+	0x630: 0xb8, 0x631: 0xb8, 0x632: 0xb8, 0x633: 0xb8, 0x634: 0xb8, 0x635: 0xb8, 0x636: 0xb8, 0x637: 0xb8,
+	0x638: 0x6e, 0x639: 0x6f, 0x63a: 0x70, 0x63b: 0x160, 0x63c: 0xb8, 0x63d: 0xb8, 0x63e: 0xb8, 0x63f: 0xb8,
+	// Block 0x19, offset 0x640
+	0x640: 0x161, 0x641: 0x9b, 0x642: 0x162, 0x643: 0x163, 0x644: 0x71, 0x645: 0x72, 0x646: 0x164, 0x647: 0x165,
+	0x648: 0x73, 0x649: 0x166, 0x64a: 0xb8, 0x64b: 0xb8, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b,
+	0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b,
+	0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x167, 0x65c: 0x9b, 0x65d: 0x168, 0x65e: 0x9b, 0x65f: 0x169,
+	0x660: 0x16a, 0x661: 0x16b, 0x662: 0x16c, 0x663: 0xb8, 0x664: 0x16d, 0x665: 0x16e, 0x666: 0x16f, 0x667: 0x170,
+	0x668: 0xb8, 0x669: 0xb8, 0x66a: 0xb8, 0x66b: 0xb8, 0x66c: 0xb8, 0x66d: 0xb8, 0x66e: 0xb8, 0x66f: 0xb8,
+	0x670: 0xb8, 0x671: 0xb8, 0x672: 0xb8, 0x673: 0xb8, 0x674: 0xb8, 0x675: 0xb8, 0x676: 0xb8, 0x677: 0xb8,
+	0x678: 0xb8, 0x679: 0xb8, 0x67a: 0xb8, 0x67b: 0xb8, 0x67c: 0xb8, 0x67d: 0xb8, 0x67e: 0xb8, 0x67f: 0xb8,
+	// Block 0x1a, offset 0x680
+	0x680: 0x9d, 0x681: 0x9d, 0x682: 0x9d, 0x683: 0x9d, 0x684: 0x9d, 0x685: 0x9d, 0x686: 0x9d, 0x687: 0x9d,
+	0x688: 0x9d, 0x689: 0x9d, 0x68a: 0x9d, 0x68b: 0x9d, 0x68c: 0x9d, 0x68d: 0x9d, 0x68e: 0x9d, 0x68f: 0x9d,
+	0x690: 0x9d, 0x691: 0x9d, 0x692: 0x9d, 0x693: 0x9d, 0x694: 0x9d, 0x695: 0x9d, 0x696: 0x9d, 0x697: 0x9d,
+	0x698: 0x9d, 0x699: 0x9d, 0x69a: 0x9d, 0x69b: 0x171, 0x69c: 0x9d, 0x69d: 0x9d, 0x69e: 0x9d, 0x69f: 0x9d,
+	0x6a0: 0x9d, 0x6a1: 0x9d, 0x6a2: 0x9d, 0x6a3: 0x9d, 0x6a4: 0x9d, 0x6a5: 0x9d, 0x6a6: 0x9d, 0x6a7: 0x9d,
+	0x6a8: 0x9d, 0x6a9: 0x9d, 0x6aa: 0x9d, 0x6ab: 0x9d, 0x6ac: 0x9d, 0x6ad: 0x9d, 0x6ae: 0x9d, 0x6af: 0x9d,
+	0x6b0: 0x9d, 0x6b1: 0x9d, 0x6b2: 0x9d, 0x6b3: 0x9d, 0x6b4: 0x9d, 0x6b5: 0x9d, 0x6b6: 0x9d, 0x6b7: 0x9d,
+	0x6b8: 0x9d, 0x6b9: 0x9d, 0x6ba: 0x9d, 0x6bb: 0x9d, 0x6bc: 0x9d, 0x6bd: 0x9d, 0x6be: 0x9d, 0x6bf: 0x9d,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x9d, 0x6c1: 0x9d, 0x6c2: 0x9d, 0x6c3: 0x9d, 0x6c4: 0x9d, 0x6c5: 0x9d, 0x6c6: 0x9d, 0x6c7: 0x9d,
+	0x6c8: 0x9d, 0x6c9: 0x9d, 0x6ca: 0x9d, 0x6cb: 0x9d, 0x6cc: 0x9d, 0x6cd: 0x9d, 0x6ce: 0x9d, 0x6cf: 0x9d,
+	0x6d0: 0x9d, 0x6d1: 0x9d, 0x6d2: 0x9d, 0x6d3: 0x9d, 0x6d4: 0x9d, 0x6d5: 0x9d, 0x6d6: 0x9d, 0x6d7: 0x9d,
+	0x6d8: 0x9d, 0x6d9: 0x9d, 0x6da: 0x9d, 0x6db: 0x9d, 0x6dc: 0x172, 0x6dd: 0x9d, 0x6de: 0x9d, 0x6df: 0x9d,
+	0x6e0: 0x173, 0x6e1: 0x9d, 0x6e2: 0x9d, 0x6e3: 0x9d, 0x6e4: 0x9d, 0x6e5: 0x9d, 0x6e6: 0x9d, 0x6e7: 0x9d,
+	0x6e8: 0x9d, 0x6e9: 0x9d, 0x6ea: 0x9d, 0x6eb: 0x9d, 0x6ec: 0x9d, 0x6ed: 0x9d, 0x6ee: 0x9d, 0x6ef: 0x9d,
+	0x6f0: 0x9d, 0x6f1: 0x9d, 0x6f2: 0x9d, 0x6f3: 0x9d, 0x6f4: 0x9d, 0x6f5: 0x9d, 0x6f6: 0x9d, 0x6f7: 0x9d,
+	0x6f8: 0x9d, 0x6f9: 0x9d, 0x6fa: 0x9d, 0x6fb: 0x9d, 0x6fc: 0x9d, 0x6fd: 0x9d, 0x6fe: 0x9d, 0x6ff: 0x9d,
+	// Block 0x1c, offset 0x700
+	0x700: 0x9d, 0x701: 0x9d, 0x702: 0x9d, 0x703: 0x9d, 0x704: 0x9d, 0x705: 0x9d, 0x706: 0x9d, 0x707: 0x9d,
+	0x708: 0x9d, 0x709: 0x9d, 0x70a: 0x9d, 0x70b: 0x9d, 0x70c: 0x9d, 0x70d: 0x9d, 0x70e: 0x9d, 0x70f: 0x9d,
+	0x710: 0x9d, 0x711: 0x9d, 0x712: 0x9d, 0x713: 0x9d, 0x714: 0x9d, 0x715: 0x9d, 0x716: 0x9d, 0x717: 0x9d,
+	0x718: 0x9d, 0x719: 0x9d, 0x71a: 0x9d, 0x71b: 0x9d, 0x71c: 0x9d, 0x71d: 0x9d, 0x71e: 0x9d, 0x71f: 0x9d,
+	0x720: 0x9d, 0x721: 0x9d, 0x722: 0x9d, 0x723: 0x9d, 0x724: 0x9d, 0x725: 0x9d, 0x726: 0x9d, 0x727: 0x9d,
+	0x728: 0x9d, 0x729: 0x9d, 0x72a: 0x9d, 0x72b: 0x9d, 0x72c: 0x9d, 0x72d: 0x9d, 0x72e: 0x9d, 0x72f: 0x9d,
+	0x730: 0x9d, 0x731: 0x9d, 0x732: 0x9d, 0x733: 0x9d, 0x734: 0x9d, 0x735: 0x9d, 0x736: 0x9d, 0x737: 0x9d,
+	0x738: 0x9d, 0x739: 0x9d, 0x73a: 0x174, 0x73b: 0xb8, 0x73c: 0xb8, 0x73d: 0xb8, 0x73e: 0xb8, 0x73f: 0xb8,
+	// Block 0x1d, offset 0x740
+	0x740: 0xb8, 0x741: 0xb8, 0x742: 0xb8, 0x743: 0xb8, 0x744: 0xb8, 0x745: 0xb8, 0x746: 0xb8, 0x747: 0xb8,
+	0x748: 0xb8, 0x749: 0xb8, 0x74a: 0xb8, 0x74b: 0xb8, 0x74c: 0xb8, 0x74d: 0xb8, 0x74e: 0xb8, 0x74f: 0xb8,
+	0x750: 0xb8, 0x751: 0xb8, 0x752: 0xb8, 0x753: 0xb8, 0x754: 0xb8, 0x755: 0xb8, 0x756: 0xb8, 0x757: 0xb8,
+	0x758: 0xb8, 0x759: 0xb8, 0x75a: 0xb8, 0x75b: 0xb8, 0x75c: 0xb8, 0x75d: 0xb8, 0x75e: 0xb8, 0x75f: 0xb8,
+	0x760: 0x74, 0x761: 0x75, 0x762: 0x76, 0x763: 0x175, 0x764: 0x77, 0x765: 0x78, 0x766: 0x176, 0x767: 0x79,
+	0x768: 0x7a, 0x769: 0xb8, 0x76a: 0xb8, 0x76b: 0xb8, 0x76c: 0xb8, 0x76d: 0xb8, 0x76e: 0xb8, 0x76f: 0xb8,
+	0x770: 0xb8, 0x771: 0xb8, 0x772: 0xb8, 0x773: 0xb8, 0x774: 0xb8, 0x775: 0xb8, 0x776: 0xb8, 0x777: 0xb8,
+	0x778: 0xb8, 0x779: 0xb8, 0x77a: 0xb8, 0x77b: 0xb8, 0x77c: 0xb8, 0x77d: 0xb8, 0x77e: 0xb8, 0x77f: 0xb8,
+	// Block 0x1e, offset 0x780
+	0x790: 0x0d, 0x791: 0x0e, 0x792: 0x0f, 0x793: 0x10, 0x794: 0x11, 0x795: 0x0b, 0x796: 0x12, 0x797: 0x07,
+	0x798: 0x13, 0x799: 0x0b, 0x79a: 0x0b, 0x79b: 0x14, 0x79c: 0x0b, 0x79d: 0x15, 0x79e: 0x16, 0x79f: 0x17,
+	0x7a0: 0x07, 0x7a1: 0x07, 0x7a2: 0x07, 0x7a3: 0x07, 0x7a4: 0x07, 0x7a5: 0x07, 0x7a6: 0x07, 0x7a7: 0x07,
+	0x7a8: 0x07, 0x7a9: 0x07, 0x7aa: 0x18, 0x7ab: 0x19, 0x7ac: 0x1a, 0x7ad: 0x0b, 0x7ae: 0x0b, 0x7af: 0x1b,
+	0x7b0: 0x0b, 0x7b1: 0x0b, 0x7b2: 0x0b, 0x7b3: 0x0b, 0x7b4: 0x0b, 0x7b5: 0x0b, 0x7b6: 0x0b, 0x7b7: 0x0b,
+	0x7b8: 0x0b, 0x7b9: 0x0b, 0x7ba: 0x0b, 0x7bb: 0x0b, 0x7bc: 0x0b, 0x7bd: 0x0b, 0x7be: 0x0b, 0x7bf: 0x0b,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x0b, 0x7c1: 0x0b, 0x7c2: 0x0b, 0x7c3: 0x0b, 0x7c4: 0x0b, 0x7c5: 0x0b, 0x7c6: 0x0b, 0x7c7: 0x0b,
+	0x7c8: 0x0b, 0x7c9: 0x0b, 0x7ca: 0x0b, 0x7cb: 0x0b, 0x7cc: 0x0b, 0x7cd: 0x0b, 0x7ce: 0x0b, 0x7cf: 0x0b,
+	0x7d0: 0x0b, 0x7d1: 0x0b, 0x7d2: 0x0b, 0x7d3: 0x0b, 0x7d4: 0x0b, 0x7d5: 0x0b, 0x7d6: 0x0b, 0x7d7: 0x0b,
+	0x7d8: 0x0b, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x0b, 0x7dc: 0x0b, 0x7dd: 0x0b, 0x7de: 0x0b, 0x7df: 0x0b,
+	0x7e0: 0x0b, 0x7e1: 0x0b, 0x7e2: 0x0b, 0x7e3: 0x0b, 0x7e4: 0x0b, 0x7e5: 0x0b, 0x7e6: 0x0b, 0x7e7: 0x0b,
+	0x7e8: 0x0b, 0x7e9: 0x0b, 0x7ea: 0x0b, 0x7eb: 0x0b, 0x7ec: 0x0b, 0x7ed: 0x0b, 0x7ee: 0x0b, 0x7ef: 0x0b,
+	0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b,
+	0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b,
+	// Block 0x20, offset 0x800
+	0x800: 0x177, 0x801: 0x178, 0x802: 0xb8, 0x803: 0xb8, 0x804: 0x179, 0x805: 0x179, 0x806: 0x179, 0x807: 0x17a,
+	0x808: 0xb8, 0x809: 0xb8, 0x80a: 0xb8, 0x80b: 0xb8, 0x80c: 0xb8, 0x80d: 0xb8, 0x80e: 0xb8, 0x80f: 0xb8,
+	0x810: 0xb8, 0x811: 0xb8, 0x812: 0xb8, 0x813: 0xb8, 0x814: 0xb8, 0x815: 0xb8, 0x816: 0xb8, 0x817: 0xb8,
+	0x818: 0xb8, 0x819: 0xb8, 0x81a: 0xb8, 0x81b: 0xb8, 0x81c: 0xb8, 0x81d: 0xb8, 0x81e: 0xb8, 0x81f: 0xb8,
+	0x820: 0xb8, 0x821: 0xb8, 0x822: 0xb8, 0x823: 0xb8, 0x824: 0xb8, 0x825: 0xb8, 0x826: 0xb8, 0x827: 0xb8,
+	0x828: 0xb8, 0x829: 0xb8, 0x82a: 0xb8, 0x82b: 0xb8, 0x82c: 0xb8, 0x82d: 0xb8, 0x82e: 0xb8, 0x82f: 0xb8,
+	0x830: 0xb8, 0x831: 0xb8, 0x832: 0xb8, 0x833: 0xb8, 0x834: 0xb8, 0x835: 0xb8, 0x836: 0xb8, 0x837: 0xb8,
+	0x838: 0xb8, 0x839: 0xb8, 0x83a: 0xb8, 0x83b: 0xb8, 0x83c: 0xb8, 0x83d: 0xb8, 0x83e: 0xb8, 0x83f: 0xb8,
+	// Block 0x21, offset 0x840
+	0x840: 0x0b, 0x841: 0x0b, 0x842: 0x0b, 0x843: 0x0b, 0x844: 0x0b, 0x845: 0x0b, 0x846: 0x0b, 0x847: 0x0b,
+	0x848: 0x0b, 0x849: 0x0b, 0x84a: 0x0b, 0x84b: 0x0b, 0x84c: 0x0b, 0x84d: 0x0b, 0x84e: 0x0b, 0x84f: 0x0b,
+	0x850: 0x0b, 0x851: 0x0b, 0x852: 0x0b, 0x853: 0x0b, 0x854: 0x0b, 0x855: 0x0b, 0x856: 0x0b, 0x857: 0x0b,
+	0x858: 0x0b, 0x859: 0x0b, 0x85a: 0x0b, 0x85b: 0x0b, 0x85c: 0x0b, 0x85d: 0x0b, 0x85e: 0x0b, 0x85f: 0x0b,
+	0x860: 0x1e, 0x861: 0x0b, 0x862: 0x0b, 0x863: 0x0b, 0x864: 0x0b, 0x865: 0x0b, 0x866: 0x0b, 0x867: 0x0b,
+	0x868: 0x0b, 0x869: 0x0b, 0x86a: 0x0b, 0x86b: 0x0b, 0x86c: 0x0b, 0x86d: 0x0b, 0x86e: 0x0b, 0x86f: 0x0b,
+	0x870: 0x0b, 0x871: 0x0b, 0x872: 0x0b, 0x873: 0x0b, 0x874: 0x0b, 0x875: 0x0b, 0x876: 0x0b, 0x877: 0x0b,
+	0x878: 0x0b, 0x879: 0x0b, 0x87a: 0x0b, 0x87b: 0x0b, 0x87c: 0x0b, 0x87d: 0x0b, 0x87e: 0x0b, 0x87f: 0x0b,
+	// Block 0x22, offset 0x880
+	0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b,
+	0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b,
+}
+
+// idnaSparseOffset: 256 entries, 512 bytes
+var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x5c, 0x60, 0x6f, 0x74, 0x7b, 0x87, 0x95, 0xa3, 0xa8, 0xb1, 0xc1, 0xcf, 0xdc, 0xe8, 0xf9, 0x103, 0x10a, 0x117, 0x128, 0x12f, 0x13a, 0x149, 0x157, 0x161, 0x163, 0x167, 0x169, 0x175, 0x180, 0x188, 0x18e, 0x194, 0x199, 0x19e, 0x1a1, 0x1a5, 0x1ab, 0x1b0, 0x1bc, 0x1c6, 0x1cc, 0x1dd, 0x1e7, 0x1ea, 0x1f2, 0x1f5, 0x202, 0x20a, 0x20e, 0x215, 0x21d, 0x22d, 0x239, 0x23b, 0x245, 0x251, 0x25d, 0x269, 0x271, 0x276, 0x2 [...]
+
+// idnaSparseValues: 1876 entries, 7504 bytes
+var idnaSparseValues = [1876]valueRange{
+	// Block 0x0, offset 0x0
+	{value: 0x0000, lo: 0x07},
+	{value: 0xe105, lo: 0x80, hi: 0x96},
+	{value: 0x0018, lo: 0x97, hi: 0x97},
+	{value: 0xe105, lo: 0x98, hi: 0x9e},
+	{value: 0x001f, lo: 0x9f, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xb7},
+	{value: 0x0008, lo: 0xb8, hi: 0xbf},
+	// Block 0x1, offset 0x8
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0xe01d, lo: 0x81, hi: 0x81},
+	{value: 0x0008, lo: 0x82, hi: 0x82},
+	{value: 0x0335, lo: 0x83, hi: 0x83},
+	{value: 0x034d, lo: 0x84, hi: 0x84},
+	{value: 0x0365, lo: 0x85, hi: 0x85},
+	{value: 0xe00d, lo: 0x86, hi: 0x86},
+	{value: 0x0008, lo: 0x87, hi: 0x87},
+	{value: 0xe00d, lo: 0x88, hi: 0x88},
+	{value: 0x0008, lo: 0x89, hi: 0x89},
+	{value: 0xe00d, lo: 0x8a, hi: 0x8a},
+	{value: 0x0008, lo: 0x8b, hi: 0x8b},
+	{value: 0xe00d, lo: 0x8c, hi: 0x8c},
+	{value: 0x0008, lo: 0x8d, hi: 0x8d},
+	{value: 0xe00d, lo: 0x8e, hi: 0x8e},
+	{value: 0x0008, lo: 0x8f, hi: 0xbf},
+	// Block 0x2, offset 0x19
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0xaf},
+	{value: 0x0249, lo: 0xb0, hi: 0xb0},
+	{value: 0x037d, lo: 0xb1, hi: 0xb1},
+	{value: 0x0259, lo: 0xb2, hi: 0xb2},
+	{value: 0x0269, lo: 0xb3, hi: 0xb3},
+	{value: 0x034d, lo: 0xb4, hi: 0xb4},
+	{value: 0x0395, lo: 0xb5, hi: 0xb5},
+	{value: 0xe1bd, lo: 0xb6, hi: 0xb6},
+	{value: 0x0279, lo: 0xb7, hi: 0xb7},
+	{value: 0x0289, lo: 0xb8, hi: 0xb8},
+	{value: 0x0008, lo: 0xb9, hi: 0xbf},
+	// Block 0x3, offset 0x25
+	{value: 0x0000, lo: 0x01},
+	{value: 0x1308, lo: 0x80, hi: 0xbf},
+	// Block 0x4, offset 0x27
+	{value: 0x0000, lo: 0x04},
+	{value: 0x03f5, lo: 0x80, hi: 0x8f},
+	{value: 0xe105, lo: 0x90, hi: 0x9f},
+	{value: 0x049d, lo: 0xa0, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x5, offset 0x2c
+	{value: 0x0000, lo: 0x07},
+	{value: 0xe185, lo: 0x80, hi: 0x8f},
+	{value: 0x0545, lo: 0x90, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x98},
+	{value: 0x0008, lo: 0x99, hi: 0x99},
+	{value: 0x0018, lo: 0x9a, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xa0},
+	{value: 0x0008, lo: 0xa1, hi: 0xbf},
+	// Block 0x6, offset 0x34
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x0401, lo: 0x87, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x88},
+	{value: 0x0018, lo: 0x89, hi: 0x8a},
+	{value: 0x0040, lo: 0x8b, hi: 0x8c},
+	{value: 0x0018, lo: 0x8d, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0x90},
+	{value: 0x1308, lo: 0x91, hi: 0xbd},
+	{value: 0x0018, lo: 0xbe, hi: 0xbe},
+	{value: 0x1308, lo: 0xbf, hi: 0xbf},
+	// Block 0x7, offset 0x3f
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0018, lo: 0x80, hi: 0x80},
+	{value: 0x1308, lo: 0x81, hi: 0x82},
+	{value: 0x0018, lo: 0x83, hi: 0x83},
+	{value: 0x1308, lo: 0x84, hi: 0x85},
+	{value: 0x0018, lo: 0x86, hi: 0x86},
+	{value: 0x1308, lo: 0x87, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xaa},
+	{value: 0x0040, lo: 0xab, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0x8, offset 0x4b
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0018, lo: 0x80, hi: 0x80},
+	{value: 0x0208, lo: 0x81, hi: 0x87},
+	{value: 0x0408, lo: 0x88, hi: 0x88},
+	{value: 0x0208, lo: 0x89, hi: 0x8a},
+	{value: 0x1308, lo: 0x8b, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa9},
+	{value: 0x0018, lo: 0xaa, hi: 0xad},
+	{value: 0x0208, lo: 0xae, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb0},
+	{value: 0x0408, lo: 0xb1, hi: 0xb3},
+	{value: 0x0008, lo: 0xb4, hi: 0xb4},
+	{value: 0x0429, lo: 0xb5, hi: 0xb5},
+	{value: 0x0451, lo: 0xb6, hi: 0xb6},
+	{value: 0x0479, lo: 0xb7, hi: 0xb7},
+	{value: 0x04a1, lo: 0xb8, hi: 0xb8},
+	{value: 0x0208, lo: 0xb9, hi: 0xbf},
+	// Block 0x9, offset 0x5c
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0208, lo: 0x80, hi: 0x87},
+	{value: 0x0408, lo: 0x88, hi: 0x99},
+	{value: 0x0208, lo: 0x9a, hi: 0xbf},
+	// Block 0xa, offset 0x60
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x1308, lo: 0x80, hi: 0x8a},
+	{value: 0x0040, lo: 0x8b, hi: 0x8c},
+	{value: 0x0408, lo: 0x8d, hi: 0x8d},
+	{value: 0x0208, lo: 0x8e, hi: 0x98},
+	{value: 0x0408, lo: 0x99, hi: 0x9b},
+	{value: 0x0208, lo: 0x9c, hi: 0xaa},
+	{value: 0x0408, lo: 0xab, hi: 0xac},
+	{value: 0x0208, lo: 0xad, hi: 0xb0},
+	{value: 0x0408, lo: 0xb1, hi: 0xb1},
+	{value: 0x0208, lo: 0xb2, hi: 0xb2},
+	{value: 0x0408, lo: 0xb3, hi: 0xb4},
+	{value: 0x0208, lo: 0xb5, hi: 0xb7},
+	{value: 0x0408, lo: 0xb8, hi: 0xb9},
+	{value: 0x0208, lo: 0xba, hi: 0xbf},
+	// Block 0xb, offset 0x6f
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xa5},
+	{value: 0x1308, lo: 0xa6, hi: 0xb0},
+	{value: 0x0008, lo: 0xb1, hi: 0xb1},
+	{value: 0x0040, lo: 0xb2, hi: 0xbf},
+	// Block 0xc, offset 0x74
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0208, lo: 0x8a, hi: 0xaa},
+	{value: 0x1308, lo: 0xab, hi: 0xb3},
+	{value: 0x0008, lo: 0xb4, hi: 0xb5},
+	{value: 0x0018, lo: 0xb6, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbf},
+	// Block 0xd, offset 0x7b
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x1308, lo: 0x96, hi: 0x99},
+	{value: 0x0008, lo: 0x9a, hi: 0x9a},
+	{value: 0x1308, lo: 0x9b, hi: 0xa3},
+	{value: 0x0008, lo: 0xa4, hi: 0xa4},
+	{value: 0x1308, lo: 0xa5, hi: 0xa7},
+	{value: 0x0008, lo: 0xa8, hi: 0xa8},
+	{value: 0x1308, lo: 0xa9, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xe, offset 0x87
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x0408, lo: 0x80, hi: 0x80},
+	{value: 0x0208, lo: 0x81, hi: 0x85},
+	{value: 0x0408, lo: 0x86, hi: 0x87},
+	{value: 0x0208, lo: 0x88, hi: 0x88},
+	{value: 0x0408, lo: 0x89, hi: 0x89},
+	{value: 0x0208, lo: 0x8a, hi: 0x93},
+	{value: 0x0408, lo: 0x94, hi: 0x94},
+	{value: 0x0208, lo: 0x95, hi: 0x95},
+	{value: 0x0008, lo: 0x96, hi: 0x98},
+	{value: 0x1308, lo: 0x99, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0xbf},
+	// Block 0xf, offset 0x95
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x0040, lo: 0x80, hi: 0x9f},
+	{value: 0x0208, lo: 0xa0, hi: 0xa9},
+	{value: 0x0408, lo: 0xaa, hi: 0xac},
+	{value: 0x0008, lo: 0xad, hi: 0xad},
+	{value: 0x0408, lo: 0xae, hi: 0xae},
+	{value: 0x0208, lo: 0xaf, hi: 0xb0},
+	{value: 0x0408, lo: 0xb1, hi: 0xb2},
+	{value: 0x0208, lo: 0xb3, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xb5},
+	{value: 0x0208, lo: 0xb6, hi: 0xb8},
+	{value: 0x0408, lo: 0xb9, hi: 0xb9},
+	{value: 0x0208, lo: 0xba, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbf},
+	// Block 0x10, offset 0xa3
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0040, lo: 0x80, hi: 0x93},
+	{value: 0x1308, lo: 0x94, hi: 0xa1},
+	{value: 0x0040, lo: 0xa2, hi: 0xa2},
+	{value: 0x1308, lo: 0xa3, hi: 0xbf},
+	// Block 0x11, offset 0xa8
+	{value: 0x0000, lo: 0x08},
+	{value: 0x1308, lo: 0x80, hi: 0x82},
+	{value: 0x1008, lo: 0x83, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0xb9},
+	{value: 0x1308, lo: 0xba, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbb},
+	{value: 0x1308, lo: 0xbc, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbf},
+	// Block 0x12, offset 0xb1
+	{value: 0x0000, lo: 0x0f},
+	{value: 0x1308, lo: 0x80, hi: 0x80},
+	{value: 0x1008, lo: 0x81, hi: 0x82},
+	{value: 0x0040, lo: 0x83, hi: 0x85},
+	{value: 0x1008, lo: 0x86, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x1008, lo: 0x8a, hi: 0x8c},
+	{value: 0x1b08, lo: 0x8d, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x96},
+	{value: 0x1008, lo: 0x97, hi: 0x97},
+	{value: 0x0040, lo: 0x98, hi: 0xa5},
+	{value: 0x0008, lo: 0xa6, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbf},
+	// Block 0x13, offset 0xc1
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x1308, lo: 0x80, hi: 0x80},
+	{value: 0x1008, lo: 0x81, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0x8c},
+	{value: 0x0040, lo: 0x8d, hi: 0x8d},
+	{value: 0x0008, lo: 0x8e, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x91},
+	{value: 0x0008, lo: 0x92, hi: 0xa8},
+	{value: 0x0040, lo: 0xa9, hi: 0xa9},
+	{value: 0x0008, lo: 0xaa, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbd},
+	{value: 0x1308, lo: 0xbe, hi: 0xbf},
+	// Block 0x14, offset 0xcf
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x1308, lo: 0x81, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0x8c},
+	{value: 0x0040, lo: 0x8d, hi: 0x8d},
+	{value: 0x0008, lo: 0x8e, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x91},
+	{value: 0x0008, lo: 0x92, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbf},
+	// Block 0x15, offset 0xdc
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0040, lo: 0x80, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x99},
+	{value: 0x0008, lo: 0x9a, hi: 0xb1},
+	{value: 0x0040, lo: 0xb2, hi: 0xb2},
+	{value: 0x0008, lo: 0xb3, hi: 0xbb},
+	{value: 0x0040, lo: 0xbc, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbf},
+	// Block 0x16, offset 0xe8
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x89},
+	{value: 0x1b08, lo: 0x8a, hi: 0x8a},
+	{value: 0x0040, lo: 0x8b, hi: 0x8e},
+	{value: 0x1008, lo: 0x8f, hi: 0x91},
+	{value: 0x1308, lo: 0x92, hi: 0x94},
+	{value: 0x0040, lo: 0x95, hi: 0x95},
+	{value: 0x1308, lo: 0x96, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x97},
+	{value: 0x1008, lo: 0x98, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xa5},
+	{value: 0x0008, lo: 0xa6, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xb1},
+	{value: 0x1008, lo: 0xb2, hi: 0xb3},
+	{value: 0x0018, lo: 0xb4, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0x17, offset 0xf9
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0xb0},
+	{value: 0x1308, lo: 0xb1, hi: 0xb1},
+	{value: 0x0008, lo: 0xb2, hi: 0xb2},
+	{value: 0x08f1, lo: 0xb3, hi: 0xb3},
+	{value: 0x1308, lo: 0xb4, hi: 0xb9},
+	{value: 0x1b08, lo: 0xba, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbe},
+	{value: 0x0018, lo: 0xbf, hi: 0xbf},
+	// Block 0x18, offset 0x103
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x1308, lo: 0x87, hi: 0x8e},
+	{value: 0x0018, lo: 0x8f, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0018, lo: 0x9a, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0xbf},
+	// Block 0x19, offset 0x10a
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0008, lo: 0x80, hi: 0x84},
+	{value: 0x0040, lo: 0x85, hi: 0x85},
+	{value: 0x0008, lo: 0x86, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x87},
+	{value: 0x1308, lo: 0x88, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9b},
+	{value: 0x0961, lo: 0x9c, hi: 0x9c},
+	{value: 0x0999, lo: 0x9d, hi: 0x9d},
+	{value: 0x0008, lo: 0x9e, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xbf},
+	// Block 0x1a, offset 0x117
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x8a},
+	{value: 0x0008, lo: 0x8b, hi: 0x8b},
+	{value: 0xe03d, lo: 0x8c, hi: 0x8c},
+	{value: 0x0018, lo: 0x8d, hi: 0x97},
+	{value: 0x1308, lo: 0x98, hi: 0x99},
+	{value: 0x0018, lo: 0x9a, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa9},
+	{value: 0x0018, lo: 0xaa, hi: 0xb4},
+	{value: 0x1308, lo: 0xb5, hi: 0xb5},
+	{value: 0x0018, lo: 0xb6, hi: 0xb6},
+	{value: 0x1308, lo: 0xb7, hi: 0xb7},
+	{value: 0x0018, lo: 0xb8, hi: 0xb8},
+	{value: 0x1308, lo: 0xb9, hi: 0xb9},
+	{value: 0x0018, lo: 0xba, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbf},
+	// Block 0x1b, offset 0x128
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x85},
+	{value: 0x1308, lo: 0x86, hi: 0x86},
+	{value: 0x0018, lo: 0x87, hi: 0x8c},
+	{value: 0x0040, lo: 0x8d, hi: 0x8d},
+	{value: 0x0018, lo: 0x8e, hi: 0x9a},
+	{value: 0x0040, lo: 0x9b, hi: 0xbf},
+	// Block 0x1c, offset 0x12f
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0xaa},
+	{value: 0x1008, lo: 0xab, hi: 0xac},
+	{value: 0x1308, lo: 0xad, hi: 0xb0},
+	{value: 0x1008, lo: 0xb1, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb7},
+	{value: 0x1008, lo: 0xb8, hi: 0xb8},
+	{value: 0x1b08, lo: 0xb9, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbc},
+	{value: 0x1308, lo: 0xbd, hi: 0xbe},
+	{value: 0x0008, lo: 0xbf, hi: 0xbf},
+	// Block 0x1d, offset 0x13a
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0018, lo: 0x8a, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x95},
+	{value: 0x1008, lo: 0x96, hi: 0x97},
+	{value: 0x1308, lo: 0x98, hi: 0x99},
+	{value: 0x0008, lo: 0x9a, hi: 0x9d},
+	{value: 0x1308, lo: 0x9e, hi: 0xa0},
+	{value: 0x0008, lo: 0xa1, hi: 0xa1},
+	{value: 0x1008, lo: 0xa2, hi: 0xa4},
+	{value: 0x0008, lo: 0xa5, hi: 0xa6},
+	{value: 0x1008, lo: 0xa7, hi: 0xad},
+	{value: 0x0008, lo: 0xae, hi: 0xb0},
+	{value: 0x1308, lo: 0xb1, hi: 0xb4},
+	{value: 0x0008, lo: 0xb5, hi: 0xbf},
+	// Block 0x1e, offset 0x149
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x0008, lo: 0x80, hi: 0x81},
+	{value: 0x1308, lo: 0x82, hi: 0x82},
+	{value: 0x1008, lo: 0x83, hi: 0x84},
+	{value: 0x1308, lo: 0x85, hi: 0x86},
+	{value: 0x1008, lo: 0x87, hi: 0x8c},
+	{value: 0x1308, lo: 0x8d, hi: 0x8d},
+	{value: 0x0008, lo: 0x8e, hi: 0x8e},
+	{value: 0x1008, lo: 0x8f, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x1008, lo: 0x9a, hi: 0x9c},
+	{value: 0x1308, lo: 0x9d, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xbf},
+	// Block 0x1f, offset 0x157
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0040, lo: 0x80, hi: 0x86},
+	{value: 0x055d, lo: 0x87, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8c},
+	{value: 0x055d, lo: 0x8d, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xba},
+	{value: 0x0018, lo: 0xbb, hi: 0xbb},
+	{value: 0xe105, lo: 0xbc, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbf},
+	// Block 0x20, offset 0x161
+	{value: 0x0000, lo: 0x01},
+	{value: 0x0018, lo: 0x80, hi: 0xbf},
+	// Block 0x21, offset 0x163
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0xa0},
+	{value: 0x0018, lo: 0xa1, hi: 0xbf},
+	// Block 0x22, offset 0x167
+	{value: 0x0000, lo: 0x01},
+	{value: 0x0008, lo: 0x80, hi: 0xbf},
+	// Block 0x23, offset 0x169
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0008, lo: 0x8a, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0x98},
+	{value: 0x0040, lo: 0x99, hi: 0x99},
+	{value: 0x0008, lo: 0x9a, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x24, offset 0x175
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0008, lo: 0x8a, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xb0},
+	{value: 0x0040, lo: 0xb1, hi: 0xb1},
+	{value: 0x0008, lo: 0xb2, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xb7},
+	{value: 0x0008, lo: 0xb8, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0x25, offset 0x180
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x0040, lo: 0x81, hi: 0x81},
+	{value: 0x0008, lo: 0x82, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x87},
+	{value: 0x0008, lo: 0x88, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0xbf},
+	// Block 0x26, offset 0x188
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x91},
+	{value: 0x0008, lo: 0x92, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0xbf},
+	// Block 0x27, offset 0x18e
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x9a},
+	{value: 0x0040, lo: 0x9b, hi: 0x9c},
+	{value: 0x1308, lo: 0x9d, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbf},
+	// Block 0x28, offset 0x194
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x29, offset 0x199
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xb7},
+	{value: 0xe045, lo: 0xb8, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbf},
+	// Block 0x2a, offset 0x19e
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0xbf},
+	// Block 0x2b, offset 0x1a1
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xac},
+	{value: 0x0018, lo: 0xad, hi: 0xae},
+	{value: 0x0008, lo: 0xaf, hi: 0xbf},
+	// Block 0x2c, offset 0x1a5
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0x9c},
+	{value: 0x0040, lo: 0x9d, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x2d, offset 0x1ab
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xaa},
+	{value: 0x0018, lo: 0xab, hi: 0xb0},
+	{value: 0x0008, lo: 0xb1, hi: 0xb8},
+	{value: 0x0040, lo: 0xb9, hi: 0xbf},
+	// Block 0x2e, offset 0x1b0
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x8c},
+	{value: 0x0040, lo: 0x8d, hi: 0x8d},
+	{value: 0x0008, lo: 0x8e, hi: 0x91},
+	{value: 0x1308, lo: 0x92, hi: 0x93},
+	{value: 0x1b08, lo: 0x94, hi: 0x94},
+	{value: 0x0040, lo: 0x95, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb3},
+	{value: 0x1b08, lo: 0xb4, hi: 0xb4},
+	{value: 0x0018, lo: 0xb5, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0x2f, offset 0x1bc
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x91},
+	{value: 0x1308, lo: 0x92, hi: 0x93},
+	{value: 0x0040, lo: 0x94, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xad},
+	{value: 0x0008, lo: 0xae, hi: 0xb0},
+	{value: 0x0040, lo: 0xb1, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xbf},
+	// Block 0x30, offset 0x1c6
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0xb3},
+	{value: 0x1340, lo: 0xb4, hi: 0xb5},
+	{value: 0x1008, lo: 0xb6, hi: 0xb6},
+	{value: 0x1308, lo: 0xb7, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbf},
+	// Block 0x31, offset 0x1cc
+	{value: 0x0000, lo: 0x10},
+	{value: 0x1008, lo: 0x80, hi: 0x85},
+	{value: 0x1308, lo: 0x86, hi: 0x86},
+	{value: 0x1008, lo: 0x87, hi: 0x88},
+	{value: 0x1308, lo: 0x89, hi: 0x91},
+	{value: 0x1b08, lo: 0x92, hi: 0x92},
+	{value: 0x1308, lo: 0x93, hi: 0x93},
+	{value: 0x0018, lo: 0x94, hi: 0x96},
+	{value: 0x0008, lo: 0x97, hi: 0x97},
+	{value: 0x0018, lo: 0x98, hi: 0x9b},
+	{value: 0x0008, lo: 0x9c, hi: 0x9c},
+	{value: 0x1308, lo: 0x9d, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa9},
+	{value: 0x0040, lo: 0xaa, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0x32, offset 0x1dd
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0018, lo: 0x80, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x86},
+	{value: 0x0218, lo: 0x87, hi: 0x87},
+	{value: 0x0018, lo: 0x88, hi: 0x8a},
+	{value: 0x13c0, lo: 0x8b, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x0208, lo: 0xa0, hi: 0xbf},
+	// Block 0x33, offset 0x1e7
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0208, lo: 0x80, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbf},
+	// Block 0x34, offset 0x1ea
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0x84},
+	{value: 0x1308, lo: 0x85, hi: 0x86},
+	{value: 0x0208, lo: 0x87, hi: 0xa8},
+	{value: 0x1308, lo: 0xa9, hi: 0xa9},
+	{value: 0x0208, lo: 0xaa, hi: 0xaa},
+	{value: 0x0040, lo: 0xab, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x35, offset 0x1f2
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xbf},
+	// Block 0x36, offset 0x1f5
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0008, lo: 0x80, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x1308, lo: 0xa0, hi: 0xa2},
+	{value: 0x1008, lo: 0xa3, hi: 0xa6},
+	{value: 0x1308, lo: 0xa7, hi: 0xa8},
+	{value: 0x1008, lo: 0xa9, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xaf},
+	{value: 0x1008, lo: 0xb0, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb2},
+	{value: 0x1008, lo: 0xb3, hi: 0xb8},
+	{value: 0x1308, lo: 0xb9, hi: 0xbb},
+	{value: 0x0040, lo: 0xbc, hi: 0xbf},
+	// Block 0x37, offset 0x202
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0018, lo: 0x80, hi: 0x80},
+	{value: 0x0040, lo: 0x81, hi: 0x83},
+	{value: 0x0018, lo: 0x84, hi: 0x85},
+	{value: 0x0008, lo: 0x86, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0x38, offset 0x20a
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x39, offset 0x20e
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0040, lo: 0x8a, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0028, lo: 0x9a, hi: 0x9a},
+	{value: 0x0040, lo: 0x9b, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0xbf},
+	// Block 0x3a, offset 0x215
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0x96},
+	{value: 0x1308, lo: 0x97, hi: 0x98},
+	{value: 0x1008, lo: 0x99, hi: 0x9a},
+	{value: 0x1308, lo: 0x9b, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x3b, offset 0x21d
+	{value: 0x0000, lo: 0x0f},
+	{value: 0x0008, lo: 0x80, hi: 0x94},
+	{value: 0x1008, lo: 0x95, hi: 0x95},
+	{value: 0x1308, lo: 0x96, hi: 0x96},
+	{value: 0x1008, lo: 0x97, hi: 0x97},
+	{value: 0x1308, lo: 0x98, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x1b08, lo: 0xa0, hi: 0xa0},
+	{value: 0x1008, lo: 0xa1, hi: 0xa1},
+	{value: 0x1308, lo: 0xa2, hi: 0xa2},
+	{value: 0x1008, lo: 0xa3, hi: 0xa4},
+	{value: 0x1308, lo: 0xa5, hi: 0xac},
+	{value: 0x1008, lo: 0xad, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbe},
+	{value: 0x1308, lo: 0xbf, hi: 0xbf},
+	// Block 0x3c, offset 0x22d
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0040, lo: 0x8a, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xa6},
+	{value: 0x0008, lo: 0xa7, hi: 0xa7},
+	{value: 0x0018, lo: 0xa8, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xbd},
+	{value: 0x1318, lo: 0xbe, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0x3d, offset 0x239
+	{value: 0x0000, lo: 0x01},
+	{value: 0x0040, lo: 0x80, hi: 0xbf},
+	// Block 0x3e, offset 0x23b
+	{value: 0x0000, lo: 0x09},
+	{value: 0x1308, lo: 0x80, hi: 0x83},
+	{value: 0x1008, lo: 0x84, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0xb3},
+	{value: 0x1308, lo: 0xb4, hi: 0xb4},
+	{value: 0x1008, lo: 0xb5, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbb},
+	{value: 0x1308, lo: 0xbc, hi: 0xbc},
+	{value: 0x1008, lo: 0xbd, hi: 0xbf},
+	// Block 0x3f, offset 0x245
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x1008, lo: 0x80, hi: 0x81},
+	{value: 0x1308, lo: 0x82, hi: 0x82},
+	{value: 0x1008, lo: 0x83, hi: 0x83},
+	{value: 0x1808, lo: 0x84, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0018, lo: 0x9a, hi: 0xaa},
+	{value: 0x1308, lo: 0xab, hi: 0xb3},
+	{value: 0x0018, lo: 0xb4, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbf},
+	// Block 0x40, offset 0x251
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x1308, lo: 0x80, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0xa0},
+	{value: 0x1008, lo: 0xa1, hi: 0xa1},
+	{value: 0x1308, lo: 0xa2, hi: 0xa5},
+	{value: 0x1008, lo: 0xa6, hi: 0xa7},
+	{value: 0x1308, lo: 0xa8, hi: 0xa9},
+	{value: 0x1808, lo: 0xaa, hi: 0xaa},
+	{value: 0x1b08, lo: 0xab, hi: 0xab},
+	{value: 0x1308, lo: 0xac, hi: 0xad},
+	{value: 0x0008, lo: 0xae, hi: 0xbf},
+	// Block 0x41, offset 0x25d
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0xa5},
+	{value: 0x1308, lo: 0xa6, hi: 0xa6},
+	{value: 0x1008, lo: 0xa7, hi: 0xa7},
+	{value: 0x1308, lo: 0xa8, hi: 0xa9},
+	{value: 0x1008, lo: 0xaa, hi: 0xac},
+	{value: 0x1308, lo: 0xad, hi: 0xad},
+	{value: 0x1008, lo: 0xae, hi: 0xae},
+	{value: 0x1308, lo: 0xaf, hi: 0xb1},
+	{value: 0x1808, lo: 0xb2, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xbb},
+	{value: 0x0018, lo: 0xbc, hi: 0xbf},
+	// Block 0x42, offset 0x269
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0xa3},
+	{value: 0x1008, lo: 0xa4, hi: 0xab},
+	{value: 0x1308, lo: 0xac, hi: 0xb3},
+	{value: 0x1008, lo: 0xb4, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xba},
+	{value: 0x0018, lo: 0xbb, hi: 0xbf},
+	// Block 0x43, offset 0x271
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0040, lo: 0x8a, hi: 0x8c},
+	{value: 0x0008, lo: 0x8d, hi: 0xbd},
+	{value: 0x0018, lo: 0xbe, hi: 0xbf},
+	// Block 0x44, offset 0x276
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0e29, lo: 0x80, hi: 0x80},
+	{value: 0x0e41, lo: 0x81, hi: 0x81},
+	{value: 0x0e59, lo: 0x82, hi: 0x82},
+	{value: 0x0e71, lo: 0x83, hi: 0x83},
+	{value: 0x0e89, lo: 0x84, hi: 0x85},
+	{value: 0x0ea1, lo: 0x86, hi: 0x86},
+	{value: 0x0eb9, lo: 0x87, hi: 0x87},
+	{value: 0x057d, lo: 0x88, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0xbf},
+	// Block 0x45, offset 0x280
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0018, lo: 0x80, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x1308, lo: 0x90, hi: 0x92},
+	{value: 0x0018, lo: 0x93, hi: 0x93},
+	{value: 0x1308, lo: 0x94, hi: 0xa0},
+	{value: 0x1008, lo: 0xa1, hi: 0xa1},
+	{value: 0x1308, lo: 0xa2, hi: 0xa8},
+	{value: 0x0008, lo: 0xa9, hi: 0xac},
+	{value: 0x1308, lo: 0xad, hi: 0xad},
+	{value: 0x0008, lo: 0xae, hi: 0xb1},
+	{value: 0x1008, lo: 0xb2, hi: 0xb3},
+	{value: 0x1308, lo: 0xb4, hi: 0xb4},
+	{value: 0x0008, lo: 0xb5, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xb7},
+	{value: 0x1308, lo: 0xb8, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0x46, offset 0x291
+	{value: 0x0000, lo: 0x03},
+	{value: 0x1308, lo: 0x80, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xba},
+	{value: 0x1308, lo: 0xbb, hi: 0xbf},
+	// Block 0x47, offset 0x295
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0x87},
+	{value: 0xe045, lo: 0x88, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x97},
+	{value: 0xe045, lo: 0x98, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa7},
+	{value: 0xe045, lo: 0xa8, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb7},
+	{value: 0xe045, lo: 0xb8, hi: 0xbf},
+	// Block 0x48, offset 0x2a0
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0040, lo: 0x80, hi: 0x8f},
+	{value: 0x1318, lo: 0x90, hi: 0xb0},
+	{value: 0x0040, lo: 0xb1, hi: 0xbf},
+	// Block 0x49, offset 0x2a4
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0018, lo: 0x80, hi: 0x82},
+	{value: 0x0040, lo: 0x83, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0x84},
+	{value: 0x0018, lo: 0x85, hi: 0x88},
+	{value: 0x24c1, lo: 0x89, hi: 0x89},
+	{value: 0x0018, lo: 0x8a, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0xbf},
+	// Block 0x4a, offset 0x2ad
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0018, lo: 0x80, hi: 0xab},
+	{value: 0x24f1, lo: 0xac, hi: 0xac},
+	{value: 0x2529, lo: 0xad, hi: 0xad},
+	{value: 0x0018, lo: 0xae, hi: 0xae},
+	{value: 0x2579, lo: 0xaf, hi: 0xaf},
+	{value: 0x25b1, lo: 0xb0, hi: 0xb0},
+	{value: 0x0018, lo: 0xb1, hi: 0xbf},
+	// Block 0x4b, offset 0x2b5
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x9f},
+	{value: 0x0080, lo: 0xa0, hi: 0xa0},
+	{value: 0x0018, lo: 0xa1, hi: 0xad},
+	{value: 0x0080, lo: 0xae, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xbf},
+	// Block 0x4c, offset 0x2bb
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0xa8},
+	{value: 0x09c5, lo: 0xa9, hi: 0xa9},
+	{value: 0x09e5, lo: 0xaa, hi: 0xaa},
+	{value: 0x0018, lo: 0xab, hi: 0xbf},
+	// Block 0x4d, offset 0x2c0
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0x4e, offset 0x2c3
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0xa6},
+	{value: 0x0040, lo: 0xa7, hi: 0xbf},
+	// Block 0x4f, offset 0x2c6
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0x8b},
+	{value: 0x28c1, lo: 0x8c, hi: 0x8c},
+	{value: 0x0018, lo: 0x8d, hi: 0xbf},
+	// Block 0x50, offset 0x2ca
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0xb3},
+	{value: 0x0e66, lo: 0xb4, hi: 0xb4},
+	{value: 0x292a, lo: 0xb5, hi: 0xb5},
+	{value: 0x0e86, lo: 0xb6, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xbf},
+	// Block 0x51, offset 0x2d0
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0x9b},
+	{value: 0x2941, lo: 0x9c, hi: 0x9c},
+	{value: 0x0018, lo: 0x9d, hi: 0xbf},
+	// Block 0x52, offset 0x2d4
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xb5},
+	{value: 0x0018, lo: 0xb6, hi: 0xbf},
+	// Block 0x53, offset 0x2d8
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x97},
+	{value: 0x0018, lo: 0x98, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbc},
+	{value: 0x0018, lo: 0xbd, hi: 0xbf},
+	// Block 0x54, offset 0x2de
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0018, lo: 0x8a, hi: 0x91},
+	{value: 0x0040, lo: 0x92, hi: 0xab},
+	{value: 0x0018, lo: 0xac, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+	// Block 0x55, offset 0x2e5
+	{value: 0x0000, lo: 0x05},
+	{value: 0xe185, lo: 0x80, hi: 0x8f},
+	{value: 0x03f5, lo: 0x90, hi: 0x9f},
+	{value: 0x0ea5, lo: 0xa0, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x56, offset 0x2eb
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0xa5},
+	{value: 0x0040, lo: 0xa6, hi: 0xa6},
+	{value: 0x0008, lo: 0xa7, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xac},
+	{value: 0x0008, lo: 0xad, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x57, offset 0x2f3
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xae},
+	{value: 0xe075, lo: 0xaf, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb0},
+	{value: 0x0040, lo: 0xb1, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0x58, offset 0x2fa
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa6},
+	{value: 0x0040, lo: 0xa7, hi: 0xa7},
+	{value: 0x0008, lo: 0xa8, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xb7},
+	{value: 0x0008, lo: 0xb8, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0x59, offset 0x305
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x87},
+	{value: 0x0008, lo: 0x88, hi: 0x8e},
+	{value: 0x0040, lo: 0x8f, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x1308, lo: 0xa0, hi: 0xbf},
+	// Block 0x5a, offset 0x30f
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xae},
+	{value: 0x0008, lo: 0xaf, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xbf},
+	// Block 0x5b, offset 0x313
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0x84},
+	{value: 0x0040, lo: 0x85, hi: 0xbf},
+	// Block 0x5c, offset 0x316
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0x9e},
+	{value: 0x0edd, lo: 0x9f, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xbf},
+	// Block 0x5d, offset 0x31c
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xb2},
+	{value: 0x0efd, lo: 0xb3, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xbf},
+	// Block 0x5e, offset 0x320
+	{value: 0x0020, lo: 0x01},
+	{value: 0x0f1d, lo: 0x80, hi: 0xbf},
+	// Block 0x5f, offset 0x322
+	{value: 0x0020, lo: 0x02},
+	{value: 0x171d, lo: 0x80, hi: 0x8f},
+	{value: 0x18fd, lo: 0x90, hi: 0xbf},
+	// Block 0x60, offset 0x325
+	{value: 0x0020, lo: 0x01},
+	{value: 0x1efd, lo: 0x80, hi: 0xbf},
+	// Block 0x61, offset 0x327
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0xbf},
+	// Block 0x62, offset 0x32a
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x98},
+	{value: 0x1308, lo: 0x99, hi: 0x9a},
+	{value: 0x29e2, lo: 0x9b, hi: 0x9b},
+	{value: 0x2a0a, lo: 0x9c, hi: 0x9c},
+	{value: 0x0008, lo: 0x9d, hi: 0x9e},
+	{value: 0x2a31, lo: 0x9f, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xa0},
+	{value: 0x0008, lo: 0xa1, hi: 0xbf},
+	// Block 0x63, offset 0x334
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xbe},
+	{value: 0x2a69, lo: 0xbf, hi: 0xbf},
+	// Block 0x64, offset 0x337
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x0040, lo: 0x80, hi: 0x84},
+	{value: 0x0008, lo: 0x85, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xb0},
+	{value: 0x2a1d, lo: 0xb1, hi: 0xb1},
+	{value: 0x2a3d, lo: 0xb2, hi: 0xb2},
+	{value: 0x2a5d, lo: 0xb3, hi: 0xb3},
+	{value: 0x2a7d, lo: 0xb4, hi: 0xb4},
+	{value: 0x2a5d, lo: 0xb5, hi: 0xb5},
+	{value: 0x2a9d, lo: 0xb6, hi: 0xb6},
+	{value: 0x2abd, lo: 0xb7, hi: 0xb7},
+	{value: 0x2add, lo: 0xb8, hi: 0xb9},
+	{value: 0x2afd, lo: 0xba, hi: 0xbb},
+	{value: 0x2b1d, lo: 0xbc, hi: 0xbd},
+	{value: 0x2afd, lo: 0xbe, hi: 0xbf},
+	// Block 0x65, offset 0x346
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xa3},
+	{value: 0x0040, lo: 0xa4, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x66, offset 0x34a
+	{value: 0x0030, lo: 0x04},
+	{value: 0x2aa2, lo: 0x80, hi: 0x9d},
+	{value: 0x305a, lo: 0x9e, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x30a2, lo: 0xa0, hi: 0xbf},
+	// Block 0x67, offset 0x34f
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0xbf},
+	// Block 0x68, offset 0x352
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0x8c},
+	{value: 0x0040, lo: 0x8d, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0xbf},
+	// Block 0x69, offset 0x356
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xbd},
+	{value: 0x0018, lo: 0xbe, hi: 0xbf},
+	// Block 0x6a, offset 0x35b
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x8c},
+	{value: 0x0018, lo: 0x8d, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xbf},
+	// Block 0x6b, offset 0x360
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0xa5},
+	{value: 0x0018, lo: 0xa6, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb1},
+	{value: 0x0018, lo: 0xb2, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbf},
+	// Block 0x6c, offset 0x366
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0040, lo: 0x80, hi: 0xb6},
+	{value: 0x0008, lo: 0xb7, hi: 0xb7},
+	{value: 0x2009, lo: 0xb8, hi: 0xb8},
+	{value: 0x6e89, lo: 0xb9, hi: 0xb9},
+	{value: 0x0008, lo: 0xba, hi: 0xbf},
+	// Block 0x6d, offset 0x36c
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x0008, lo: 0x80, hi: 0x81},
+	{value: 0x1308, lo: 0x82, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0x85},
+	{value: 0x1b08, lo: 0x86, hi: 0x86},
+	{value: 0x0008, lo: 0x87, hi: 0x8a},
+	{value: 0x1308, lo: 0x8b, hi: 0x8b},
+	{value: 0x0008, lo: 0x8c, hi: 0xa2},
+	{value: 0x1008, lo: 0xa3, hi: 0xa4},
+	{value: 0x1308, lo: 0xa5, hi: 0xa6},
+	{value: 0x1008, lo: 0xa7, hi: 0xa7},
+	{value: 0x0018, lo: 0xa8, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0x6e, offset 0x37b
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0208, lo: 0x80, hi: 0xb1},
+	{value: 0x0108, lo: 0xb2, hi: 0xb2},
+	{value: 0x0008, lo: 0xb3, hi: 0xb3},
+	{value: 0x0018, lo: 0xb4, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbf},
+	// Block 0x6f, offset 0x381
+	{value: 0x0000, lo: 0x03},
+	{value: 0x1008, lo: 0x80, hi: 0x81},
+	{value: 0x0008, lo: 0x82, hi: 0xb3},
+	{value: 0x1008, lo: 0xb4, hi: 0xbf},
+	// Block 0x70, offset 0x385
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x1008, lo: 0x80, hi: 0x83},
+	{value: 0x1b08, lo: 0x84, hi: 0x84},
+	{value: 0x1308, lo: 0x85, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x8d},
+	{value: 0x0018, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x1308, lo: 0xa0, hi: 0xb1},
+	{value: 0x0008, lo: 0xb2, hi: 0xb7},
+	{value: 0x0018, lo: 0xb8, hi: 0xba},
+	{value: 0x0008, lo: 0xbb, hi: 0xbb},
+	{value: 0x0018, lo: 0xbc, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbf},
+	// Block 0x71, offset 0x394
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xa5},
+	{value: 0x1308, lo: 0xa6, hi: 0xad},
+	{value: 0x0018, lo: 0xae, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x72, offset 0x399
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x1308, lo: 0x87, hi: 0x91},
+	{value: 0x1008, lo: 0x92, hi: 0x92},
+	{value: 0x1808, lo: 0x93, hi: 0x93},
+	{value: 0x0040, lo: 0x94, hi: 0x9e},
+	{value: 0x0018, lo: 0x9f, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbf},
+	// Block 0x73, offset 0x3a1
+	{value: 0x0000, lo: 0x09},
+	{value: 0x1308, lo: 0x80, hi: 0x82},
+	{value: 0x1008, lo: 0x83, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xb3},
+	{value: 0x1008, lo: 0xb4, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xb9},
+	{value: 0x1008, lo: 0xba, hi: 0xbb},
+	{value: 0x1308, lo: 0xbc, hi: 0xbc},
+	{value: 0x1008, lo: 0xbd, hi: 0xbf},
+	// Block 0x74, offset 0x3ab
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x1808, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8e},
+	{value: 0x0008, lo: 0x8f, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa4},
+	{value: 0x1308, lo: 0xa5, hi: 0xa5},
+	{value: 0x0008, lo: 0xa6, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0x75, offset 0x3b6
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0xa8},
+	{value: 0x1308, lo: 0xa9, hi: 0xae},
+	{value: 0x1008, lo: 0xaf, hi: 0xb0},
+	{value: 0x1308, lo: 0xb1, hi: 0xb2},
+	{value: 0x1008, lo: 0xb3, hi: 0xb4},
+	{value: 0x1308, lo: 0xb5, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0x76, offset 0x3be
+	{value: 0x0000, lo: 0x10},
+	{value: 0x0008, lo: 0x80, hi: 0x82},
+	{value: 0x1308, lo: 0x83, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0x8b},
+	{value: 0x1308, lo: 0x8c, hi: 0x8c},
+	{value: 0x1008, lo: 0x8d, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9b},
+	{value: 0x0018, lo: 0x9c, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xb9},
+	{value: 0x0008, lo: 0xba, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbb},
+	{value: 0x1308, lo: 0xbc, hi: 0xbc},
+	{value: 0x1008, lo: 0xbd, hi: 0xbd},
+	{value: 0x0008, lo: 0xbe, hi: 0xbf},
+	// Block 0x77, offset 0x3cf
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0008, lo: 0x80, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb0},
+	{value: 0x0008, lo: 0xb1, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb4},
+	{value: 0x0008, lo: 0xb5, hi: 0xb6},
+	{value: 0x1308, lo: 0xb7, hi: 0xb8},
+	{value: 0x0008, lo: 0xb9, hi: 0xbd},
+	{value: 0x1308, lo: 0xbe, hi: 0xbf},
+	// Block 0x78, offset 0x3d8
+	{value: 0x0000, lo: 0x0f},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x1308, lo: 0x81, hi: 0x81},
+	{value: 0x0008, lo: 0x82, hi: 0x82},
+	{value: 0x0040, lo: 0x83, hi: 0x9a},
+	{value: 0x0008, lo: 0x9b, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xaa},
+	{value: 0x1008, lo: 0xab, hi: 0xab},
+	{value: 0x1308, lo: 0xac, hi: 0xad},
+	{value: 0x1008, lo: 0xae, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb1},
+	{value: 0x0008, lo: 0xb2, hi: 0xb4},
+	{value: 0x1008, lo: 0xb5, hi: 0xb5},
+	{value: 0x1b08, lo: 0xb6, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0x79, offset 0x3e8
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x88},
+	{value: 0x0008, lo: 0x89, hi: 0x8e},
+	{value: 0x0040, lo: 0x8f, hi: 0x90},
+	{value: 0x0008, lo: 0x91, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa6},
+	{value: 0x0040, lo: 0xa7, hi: 0xa7},
+	{value: 0x0008, lo: 0xa8, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x7a, offset 0x3f5
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0x9b},
+	{value: 0x4465, lo: 0x9c, hi: 0x9c},
+	{value: 0x447d, lo: 0x9d, hi: 0x9d},
+	{value: 0x2971, lo: 0x9e, hi: 0x9e},
+	{value: 0xe06d, lo: 0x9f, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa5},
+	{value: 0x0040, lo: 0xa6, hi: 0xaf},
+	{value: 0x4495, lo: 0xb0, hi: 0xbf},
+	// Block 0x7b, offset 0x3ff
+	{value: 0x0000, lo: 0x04},
+	{value: 0x44b5, lo: 0x80, hi: 0x8f},
+	{value: 0x44d5, lo: 0x90, hi: 0x9f},
+	{value: 0x44f5, lo: 0xa0, hi: 0xaf},
+	{value: 0x44d5, lo: 0xb0, hi: 0xbf},
+	// Block 0x7c, offset 0x404
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0008, lo: 0x80, hi: 0xa2},
+	{value: 0x1008, lo: 0xa3, hi: 0xa4},
+	{value: 0x1308, lo: 0xa5, hi: 0xa5},
+	{value: 0x1008, lo: 0xa6, hi: 0xa7},
+	{value: 0x1308, lo: 0xa8, hi: 0xa8},
+	{value: 0x1008, lo: 0xa9, hi: 0xaa},
+	{value: 0x0018, lo: 0xab, hi: 0xab},
+	{value: 0x1008, lo: 0xac, hi: 0xac},
+	{value: 0x1b08, lo: 0xad, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0x7d, offset 0x411
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xa3},
+	{value: 0x0040, lo: 0xa4, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xbf},
+	// Block 0x7e, offset 0x415
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x8a},
+	{value: 0x0018, lo: 0x8b, hi: 0xbb},
+	{value: 0x0040, lo: 0xbc, hi: 0xbf},
+	// Block 0x7f, offset 0x41a
+	{value: 0x0020, lo: 0x01},
+	{value: 0x4515, lo: 0x80, hi: 0xbf},
+	// Block 0x80, offset 0x41c
+	{value: 0x0020, lo: 0x03},
+	{value: 0x4d15, lo: 0x80, hi: 0x94},
+	{value: 0x4ad5, lo: 0x95, hi: 0x95},
+	{value: 0x4fb5, lo: 0x96, hi: 0xbf},
+	// Block 0x81, offset 0x420
+	{value: 0x0020, lo: 0x01},
+	{value: 0x54f5, lo: 0x80, hi: 0xbf},
+	// Block 0x82, offset 0x422
+	{value: 0x0020, lo: 0x03},
+	{value: 0x5cf5, lo: 0x80, hi: 0x84},
+	{value: 0x5655, lo: 0x85, hi: 0x85},
+	{value: 0x5d95, lo: 0x86, hi: 0xbf},
+	// Block 0x83, offset 0x426
+	{value: 0x0020, lo: 0x08},
+	{value: 0x6b55, lo: 0x80, hi: 0x8f},
+	{value: 0x6d15, lo: 0x90, hi: 0x90},
+	{value: 0x6d55, lo: 0x91, hi: 0xab},
+	{value: 0x6ea1, lo: 0xac, hi: 0xac},
+	{value: 0x70b5, lo: 0xad, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xaf},
+	{value: 0x70d5, lo: 0xb0, hi: 0xbf},
+	// Block 0x84, offset 0x42f
+	{value: 0x0020, lo: 0x05},
+	{value: 0x72d5, lo: 0x80, hi: 0xad},
+	{value: 0x6535, lo: 0xae, hi: 0xae},
+	{value: 0x7895, lo: 0xaf, hi: 0xb5},
+	{value: 0x6f55, lo: 0xb6, hi: 0xb6},
+	{value: 0x7975, lo: 0xb7, hi: 0xbf},
+	// Block 0x85, offset 0x435
+	{value: 0x0028, lo: 0x03},
+	{value: 0x7c21, lo: 0x80, hi: 0x82},
+	{value: 0x7be1, lo: 0x83, hi: 0x83},
+	{value: 0x7c99, lo: 0x84, hi: 0xbf},
+	// Block 0x86, offset 0x439
+	{value: 0x0038, lo: 0x0f},
+	{value: 0x9db1, lo: 0x80, hi: 0x83},
+	{value: 0x9e59, lo: 0x84, hi: 0x85},
+	{value: 0x9e91, lo: 0x86, hi: 0x87},
+	{value: 0x9ec9, lo: 0x88, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x91},
+	{value: 0xa089, lo: 0x92, hi: 0x97},
+	{value: 0xa1a1, lo: 0x98, hi: 0x9c},
+	{value: 0xa281, lo: 0x9d, hi: 0xb3},
+	{value: 0x9d41, lo: 0xb4, hi: 0xb4},
+	{value: 0x9db1, lo: 0xb5, hi: 0xb5},
+	{value: 0xa789, lo: 0xb6, hi: 0xbb},
+	{value: 0xa869, lo: 0xbc, hi: 0xbc},
+	{value: 0xa7f9, lo: 0xbd, hi: 0xbd},
+	{value: 0xa8d9, lo: 0xbe, hi: 0xbf},
+	// Block 0x87, offset 0x449
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x8c},
+	{value: 0x0008, lo: 0x8d, hi: 0xa6},
+	{value: 0x0040, lo: 0xa7, hi: 0xa7},
+	{value: 0x0008, lo: 0xa8, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbb},
+	{value: 0x0008, lo: 0xbc, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbe},
+	{value: 0x0008, lo: 0xbf, hi: 0xbf},
+	// Block 0x88, offset 0x453
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0xbf},
+	// Block 0x89, offset 0x458
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbf},
+	// Block 0x8a, offset 0x45b
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x82},
+	{value: 0x0040, lo: 0x83, hi: 0x86},
+	{value: 0x0018, lo: 0x87, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xbf},
+	// Block 0x8b, offset 0x461
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x8e},
+	{value: 0x0040, lo: 0x8f, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xa0},
+	{value: 0x0040, lo: 0xa1, hi: 0xbf},
+	// Block 0x8c, offset 0x468
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0040, lo: 0x80, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0xbc},
+	{value: 0x1308, lo: 0xbd, hi: 0xbd},
+	{value: 0x0040, lo: 0xbe, hi: 0xbf},
+	// Block 0x8d, offset 0x46d
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0x9c},
+	{value: 0x0040, lo: 0x9d, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x8e, offset 0x471
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x90},
+	{value: 0x0040, lo: 0x91, hi: 0x9f},
+	{value: 0x1308, lo: 0xa0, hi: 0xa0},
+	{value: 0x0018, lo: 0xa1, hi: 0xbb},
+	{value: 0x0040, lo: 0xbc, hi: 0xbf},
+	// Block 0x8f, offset 0x477
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xa3},
+	{value: 0x0040, lo: 0xa4, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x90, offset 0x47c
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x81},
+	{value: 0x0008, lo: 0x82, hi: 0x89},
+	{value: 0x0018, lo: 0x8a, hi: 0x8a},
+	{value: 0x0040, lo: 0x8b, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbf},
+	// Block 0x91, offset 0x485
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9e},
+	{value: 0x0018, lo: 0x9f, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0x92, offset 0x48a
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x87},
+	{value: 0x0008, lo: 0x88, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0xbf},
+	// Block 0x93, offset 0x490
+	{value: 0x0000, lo: 0x06},
+	{value: 0xe145, lo: 0x80, hi: 0x87},
+	{value: 0xe1c5, lo: 0x88, hi: 0x8f},
+	{value: 0xe145, lo: 0x90, hi: 0x97},
+	{value: 0x8ad5, lo: 0x98, hi: 0x9f},
+	{value: 0x8aed, lo: 0xa0, hi: 0xa7},
+	{value: 0x0008, lo: 0xa8, hi: 0xbf},
+	// Block 0x94, offset 0x497
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa9},
+	{value: 0x0040, lo: 0xaa, hi: 0xaf},
+	{value: 0x8aed, lo: 0xb0, hi: 0xb7},
+	{value: 0x8ad5, lo: 0xb8, hi: 0xbf},
+	// Block 0x95, offset 0x49e
+	{value: 0x0000, lo: 0x06},
+	{value: 0xe145, lo: 0x80, hi: 0x87},
+	{value: 0xe1c5, lo: 0x88, hi: 0x8f},
+	{value: 0xe145, lo: 0x90, hi: 0x93},
+	{value: 0x0040, lo: 0x94, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0xbb},
+	{value: 0x0040, lo: 0xbc, hi: 0xbf},
+	// Block 0x96, offset 0x4a5
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0x97, offset 0x4a9
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xa3},
+	{value: 0x0040, lo: 0xa4, hi: 0xae},
+	{value: 0x0018, lo: 0xaf, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+	// Block 0x98, offset 0x4ae
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0x99, offset 0x4b1
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xbf},
+	// Block 0x9a, offset 0x4b6
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x87},
+	{value: 0x0008, lo: 0x88, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0008, lo: 0x8a, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xb6},
+	{value: 0x0008, lo: 0xb7, hi: 0xb8},
+	{value: 0x0040, lo: 0xb9, hi: 0xbb},
+	{value: 0x0008, lo: 0xbc, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbe},
+	{value: 0x0008, lo: 0xbf, hi: 0xbf},
+	// Block 0x9b, offset 0x4c2
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x96},
+	{value: 0x0018, lo: 0x97, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xbf},
+	// Block 0x9c, offset 0x4c8
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0xa6},
+	{value: 0x0018, lo: 0xa7, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+	// Block 0x9d, offset 0x4cd
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0040, lo: 0x80, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xb3},
+	{value: 0x0008, lo: 0xb4, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xba},
+	{value: 0x0018, lo: 0xbb, hi: 0xbf},
+	// Block 0x9e, offset 0x4d4
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x0018, lo: 0x96, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0x9e},
+	{value: 0x0018, lo: 0x9f, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbe},
+	{value: 0x0018, lo: 0xbf, hi: 0xbf},
+	// Block 0x9f, offset 0x4dc
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbb},
+	{value: 0x0018, lo: 0xbc, hi: 0xbd},
+	{value: 0x0008, lo: 0xbe, hi: 0xbf},
+	// Block 0xa0, offset 0x4e1
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0x91},
+	{value: 0x0018, lo: 0x92, hi: 0xbf},
+	// Block 0xa1, offset 0x4e5
+	{value: 0x0000, lo: 0x0f},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x1308, lo: 0x81, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x84},
+	{value: 0x1308, lo: 0x85, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x8b},
+	{value: 0x1308, lo: 0x8c, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x93},
+	{value: 0x0040, lo: 0x94, hi: 0x94},
+	{value: 0x0008, lo: 0x95, hi: 0x97},
+	{value: 0x0040, lo: 0x98, hi: 0x98},
+	{value: 0x0008, lo: 0x99, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xb7},
+	{value: 0x1308, lo: 0xb8, hi: 0xba},
+	{value: 0x0040, lo: 0xbb, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0xa2, offset 0x4f5
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x98},
+	{value: 0x0040, lo: 0x99, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbc},
+	{value: 0x0018, lo: 0xbd, hi: 0xbf},
+	// Block 0xa3, offset 0x4fc
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0x9c},
+	{value: 0x0018, lo: 0x9d, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xbf},
+	// Block 0xa4, offset 0x500
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xb8},
+	{value: 0x0018, lo: 0xb9, hi: 0xbf},
+	// Block 0xa5, offset 0x504
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x95},
+	{value: 0x0040, lo: 0x96, hi: 0x97},
+	{value: 0x0018, lo: 0x98, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xb7},
+	{value: 0x0018, lo: 0xb8, hi: 0xbf},
+	// Block 0xa6, offset 0x50b
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0xbf},
+	// Block 0xa7, offset 0x50e
+	{value: 0x0000, lo: 0x02},
+	{value: 0x03dd, lo: 0x80, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xbf},
+	// Block 0xa8, offset 0x511
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xb9},
+	{value: 0x0018, lo: 0xba, hi: 0xbf},
+	// Block 0xa9, offset 0x515
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0040, lo: 0x80, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xaa, offset 0x519
+	{value: 0x0000, lo: 0x05},
+	{value: 0x1008, lo: 0x80, hi: 0x80},
+	{value: 0x1308, lo: 0x81, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0xb7},
+	{value: 0x1308, lo: 0xb8, hi: 0xbf},
+	// Block 0xab, offset 0x51f
+	{value: 0x0000, lo: 0x08},
+	{value: 0x1308, lo: 0x80, hi: 0x85},
+	{value: 0x1b08, lo: 0x86, hi: 0x86},
+	{value: 0x0018, lo: 0x87, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x91},
+	{value: 0x0018, lo: 0x92, hi: 0xa5},
+	{value: 0x0008, lo: 0xa6, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0xac, offset 0x528
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x1308, lo: 0x80, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0xaf},
+	{value: 0x1008, lo: 0xb0, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xb6},
+	{value: 0x1008, lo: 0xb7, hi: 0xb8},
+	{value: 0x1b08, lo: 0xb9, hi: 0xb9},
+	{value: 0x1308, lo: 0xba, hi: 0xba},
+	{value: 0x0018, lo: 0xbb, hi: 0xbc},
+	{value: 0x0340, lo: 0xbd, hi: 0xbd},
+	{value: 0x0018, lo: 0xbe, hi: 0xbf},
+	// Block 0xad, offset 0x534
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x81},
+	{value: 0x0040, lo: 0x82, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xa8},
+	{value: 0x0040, lo: 0xa9, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0xae, offset 0x53b
+	{value: 0x0000, lo: 0x08},
+	{value: 0x1308, lo: 0x80, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0xa6},
+	{value: 0x1308, lo: 0xa7, hi: 0xab},
+	{value: 0x1008, lo: 0xac, hi: 0xac},
+	{value: 0x1308, lo: 0xad, hi: 0xb2},
+	{value: 0x1b08, lo: 0xb3, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xb5},
+	{value: 0x0008, lo: 0xb6, hi: 0xbf},
+	// Block 0xaf, offset 0x544
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0018, lo: 0x80, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xb3},
+	{value: 0x0018, lo: 0xb4, hi: 0xb5},
+	{value: 0x0008, lo: 0xb6, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0xb0, offset 0x54c
+	{value: 0x0000, lo: 0x06},
+	{value: 0x1308, lo: 0x80, hi: 0x81},
+	{value: 0x1008, lo: 0x82, hi: 0x82},
+	{value: 0x0008, lo: 0x83, hi: 0xb2},
+	{value: 0x1008, lo: 0xb3, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xbe},
+	{value: 0x1008, lo: 0xbf, hi: 0xbf},
+	// Block 0xb1, offset 0x553
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x1808, lo: 0x80, hi: 0x80},
+	{value: 0x0008, lo: 0x81, hi: 0x84},
+	{value: 0x0018, lo: 0x85, hi: 0x89},
+	{value: 0x1308, lo: 0x8a, hi: 0x8c},
+	{value: 0x0018, lo: 0x8d, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0x9b},
+	{value: 0x0008, lo: 0x9c, hi: 0x9c},
+	{value: 0x0018, lo: 0x9d, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xa0},
+	{value: 0x0018, lo: 0xa1, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0xb2, offset 0x561
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0008, lo: 0x80, hi: 0x91},
+	{value: 0x0040, lo: 0x92, hi: 0x92},
+	{value: 0x0008, lo: 0x93, hi: 0xab},
+	{value: 0x1008, lo: 0xac, hi: 0xae},
+	{value: 0x1308, lo: 0xaf, hi: 0xb1},
+	{value: 0x1008, lo: 0xb2, hi: 0xb3},
+	{value: 0x1308, lo: 0xb4, hi: 0xb4},
+	{value: 0x1808, lo: 0xb5, hi: 0xb5},
+	{value: 0x1308, lo: 0xb6, hi: 0xb7},
+	{value: 0x0018, lo: 0xb8, hi: 0xbd},
+	{value: 0x1308, lo: 0xbe, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xb3, offset 0x56e
+	{value: 0x0000, lo: 0x0c},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x87},
+	{value: 0x0008, lo: 0x88, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0008, lo: 0x8a, hi: 0x8d},
+	{value: 0x0040, lo: 0x8e, hi: 0x8e},
+	{value: 0x0008, lo: 0x8f, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9e},
+	{value: 0x0008, lo: 0x9f, hi: 0xa8},
+	{value: 0x0018, lo: 0xa9, hi: 0xa9},
+	{value: 0x0040, lo: 0xaa, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbf},
+	// Block 0xb4, offset 0x57b
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0008, lo: 0x80, hi: 0x9e},
+	{value: 0x1308, lo: 0x9f, hi: 0x9f},
+	{value: 0x1008, lo: 0xa0, hi: 0xa2},
+	{value: 0x1308, lo: 0xa3, hi: 0xa9},
+	{value: 0x1b08, lo: 0xaa, hi: 0xaa},
+	{value: 0x0040, lo: 0xab, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb9},
+	{value: 0x0040, lo: 0xba, hi: 0xbf},
+	// Block 0xb5, offset 0x584
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xb4},
+	{value: 0x1008, lo: 0xb5, hi: 0xb7},
+	{value: 0x1308, lo: 0xb8, hi: 0xbf},
+	// Block 0xb6, offset 0x588
+	{value: 0x0000, lo: 0x0d},
+	{value: 0x1008, lo: 0x80, hi: 0x81},
+	{value: 0x1b08, lo: 0x82, hi: 0x82},
+	{value: 0x1308, lo: 0x83, hi: 0x84},
+	{value: 0x1008, lo: 0x85, hi: 0x85},
+	{value: 0x1308, lo: 0x86, hi: 0x86},
+	{value: 0x0008, lo: 0x87, hi: 0x8a},
+	{value: 0x0018, lo: 0x8b, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0x9b},
+	{value: 0x0040, lo: 0x9c, hi: 0x9c},
+	{value: 0x0018, lo: 0x9d, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0xbf},
+	// Block 0xb7, offset 0x596
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0xaf},
+	{value: 0x1008, lo: 0xb0, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xb8},
+	{value: 0x1008, lo: 0xb9, hi: 0xb9},
+	{value: 0x1308, lo: 0xba, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbe},
+	{value: 0x1308, lo: 0xbf, hi: 0xbf},
+	// Block 0xb8, offset 0x59e
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x1308, lo: 0x80, hi: 0x80},
+	{value: 0x1008, lo: 0x81, hi: 0x81},
+	{value: 0x1b08, lo: 0x82, hi: 0x82},
+	{value: 0x1308, lo: 0x83, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0x85},
+	{value: 0x0018, lo: 0x86, hi: 0x86},
+	{value: 0x0008, lo: 0x87, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0xbf},
+	// Block 0xb9, offset 0x5a9
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0008, lo: 0x80, hi: 0xae},
+	{value: 0x1008, lo: 0xaf, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xb7},
+	{value: 0x1008, lo: 0xb8, hi: 0xbb},
+	{value: 0x1308, lo: 0xbc, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0xba, offset 0x5b2
+	{value: 0x0000, lo: 0x05},
+	{value: 0x1308, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x97},
+	{value: 0x0008, lo: 0x98, hi: 0x9b},
+	{value: 0x1308, lo: 0x9c, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0xbf},
+	// Block 0xbb, offset 0x5b8
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0008, lo: 0x80, hi: 0xaf},
+	{value: 0x1008, lo: 0xb0, hi: 0xb2},
+	{value: 0x1308, lo: 0xb3, hi: 0xba},
+	{value: 0x1008, lo: 0xbb, hi: 0xbc},
+	{value: 0x1308, lo: 0xbd, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0xbc, offset 0x5c0
+	{value: 0x0000, lo: 0x08},
+	{value: 0x1308, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x83},
+	{value: 0x0008, lo: 0x84, hi: 0x84},
+	{value: 0x0040, lo: 0x85, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xbf},
+	// Block 0xbd, offset 0x5c9
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0xaa},
+	{value: 0x1308, lo: 0xab, hi: 0xab},
+	{value: 0x1008, lo: 0xac, hi: 0xac},
+	{value: 0x1308, lo: 0xad, hi: 0xad},
+	{value: 0x1008, lo: 0xae, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb5},
+	{value: 0x1808, lo: 0xb6, hi: 0xb6},
+	{value: 0x1308, lo: 0xb7, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbf},
+	// Block 0xbe, offset 0x5d3
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x89},
+	{value: 0x0040, lo: 0x8a, hi: 0xbf},
+	// Block 0xbf, offset 0x5d6
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9c},
+	{value: 0x1308, lo: 0x9d, hi: 0x9f},
+	{value: 0x1008, lo: 0xa0, hi: 0xa1},
+	{value: 0x1308, lo: 0xa2, hi: 0xa5},
+	{value: 0x1008, lo: 0xa6, hi: 0xa6},
+	{value: 0x1308, lo: 0xa7, hi: 0xaa},
+	{value: 0x1b08, lo: 0xab, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xb9},
+	{value: 0x0018, lo: 0xba, hi: 0xbf},
+	// Block 0xc0, offset 0x5e2
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0040, lo: 0x80, hi: 0x9f},
+	{value: 0x049d, lo: 0xa0, hi: 0xbf},
+	// Block 0xc1, offset 0x5e5
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xa9},
+	{value: 0x0018, lo: 0xaa, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xbe},
+	{value: 0x0008, lo: 0xbf, hi: 0xbf},
+	// Block 0xc2, offset 0x5ea
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xb8},
+	{value: 0x0040, lo: 0xb9, hi: 0xbf},
+	// Block 0xc3, offset 0x5ed
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x89},
+	{value: 0x0008, lo: 0x8a, hi: 0xae},
+	{value: 0x1008, lo: 0xaf, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xb7},
+	{value: 0x1308, lo: 0xb8, hi: 0xbd},
+	{value: 0x1008, lo: 0xbe, hi: 0xbe},
+	{value: 0x1b08, lo: 0xbf, hi: 0xbf},
+	// Block 0xc4, offset 0x5f7
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0008, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0018, lo: 0x9a, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb1},
+	{value: 0x0008, lo: 0xb2, hi: 0xbf},
+	// Block 0xc5, offset 0x600
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x0008, lo: 0x80, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0x91},
+	{value: 0x1308, lo: 0x92, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xa8},
+	{value: 0x1008, lo: 0xa9, hi: 0xa9},
+	{value: 0x1308, lo: 0xaa, hi: 0xb0},
+	{value: 0x1008, lo: 0xb1, hi: 0xb1},
+	{value: 0x1308, lo: 0xb2, hi: 0xb3},
+	{value: 0x1008, lo: 0xb4, hi: 0xb4},
+	{value: 0x1308, lo: 0xb5, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0xc6, offset 0x60c
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0xbf},
+	// Block 0xc7, offset 0x60f
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0xc8, offset 0x614
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x83},
+	{value: 0x0040, lo: 0x84, hi: 0xbf},
+	// Block 0xc9, offset 0x617
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xbf},
+	// Block 0xca, offset 0x61a
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0xbf},
+	// Block 0xcb, offset 0x61d
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0008, lo: 0x80, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa9},
+	{value: 0x0040, lo: 0xaa, hi: 0xad},
+	{value: 0x0018, lo: 0xae, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+	// Block 0xcc, offset 0x624
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0040, lo: 0x80, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb4},
+	{value: 0x0018, lo: 0xb5, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xbf},
+	// Block 0xcd, offset 0x62b
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0xaf},
+	{value: 0x1308, lo: 0xb0, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xbf},
+	// Block 0xce, offset 0x62f
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x0008, lo: 0x80, hi: 0x83},
+	{value: 0x0018, lo: 0x84, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9a},
+	{value: 0x0018, lo: 0x9b, hi: 0xa1},
+	{value: 0x0040, lo: 0xa2, hi: 0xa2},
+	{value: 0x0008, lo: 0xa3, hi: 0xb7},
+	{value: 0x0040, lo: 0xb8, hi: 0xbc},
+	{value: 0x0008, lo: 0xbd, hi: 0xbf},
+	// Block 0xcf, offset 0x63a
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0xbf},
+	// Block 0xd0, offset 0x63d
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x84},
+	{value: 0x0040, lo: 0x85, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x90},
+	{value: 0x1008, lo: 0x91, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xd1, offset 0x643
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0040, lo: 0x80, hi: 0x8e},
+	{value: 0x1308, lo: 0x8f, hi: 0x92},
+	{value: 0x0008, lo: 0x93, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xbf},
+	// Block 0xd2, offset 0x648
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0040, lo: 0x80, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xa0},
+	{value: 0x0040, lo: 0xa1, hi: 0xbf},
+	// Block 0xd3, offset 0x64c
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xbf},
+	// Block 0xd4, offset 0x64f
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xb2},
+	{value: 0x0040, lo: 0xb3, hi: 0xbf},
+	// Block 0xd5, offset 0x652
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x81},
+	{value: 0x0040, lo: 0x82, hi: 0xbf},
+	// Block 0xd6, offset 0x655
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0008, lo: 0x80, hi: 0xaa},
+	{value: 0x0040, lo: 0xab, hi: 0xaf},
+	{value: 0x0008, lo: 0xb0, hi: 0xbc},
+	{value: 0x0040, lo: 0xbd, hi: 0xbf},
+	// Block 0xd7, offset 0x65a
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0008, lo: 0x80, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9b},
+	{value: 0x0018, lo: 0x9c, hi: 0x9c},
+	{value: 0x1308, lo: 0x9d, hi: 0x9e},
+	{value: 0x0018, lo: 0x9f, hi: 0x9f},
+	{value: 0x03c0, lo: 0xa0, hi: 0xa3},
+	{value: 0x0040, lo: 0xa4, hi: 0xbf},
+	// Block 0xd8, offset 0x664
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xbf},
+	// Block 0xd9, offset 0x667
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xa6},
+	{value: 0x0040, lo: 0xa7, hi: 0xa8},
+	{value: 0x0018, lo: 0xa9, hi: 0xbf},
+	// Block 0xda, offset 0x66b
+	{value: 0x0000, lo: 0x0e},
+	{value: 0x0018, lo: 0x80, hi: 0x9d},
+	{value: 0xb5b9, lo: 0x9e, hi: 0x9e},
+	{value: 0xb601, lo: 0x9f, hi: 0x9f},
+	{value: 0xb649, lo: 0xa0, hi: 0xa0},
+	{value: 0xb6b1, lo: 0xa1, hi: 0xa1},
+	{value: 0xb719, lo: 0xa2, hi: 0xa2},
+	{value: 0xb781, lo: 0xa3, hi: 0xa3},
+	{value: 0xb7e9, lo: 0xa4, hi: 0xa4},
+	{value: 0x1018, lo: 0xa5, hi: 0xa6},
+	{value: 0x1318, lo: 0xa7, hi: 0xa9},
+	{value: 0x0018, lo: 0xaa, hi: 0xac},
+	{value: 0x1018, lo: 0xad, hi: 0xb2},
+	{value: 0x0340, lo: 0xb3, hi: 0xba},
+	{value: 0x1318, lo: 0xbb, hi: 0xbf},
+	// Block 0xdb, offset 0x67a
+	{value: 0x0000, lo: 0x0b},
+	{value: 0x1318, lo: 0x80, hi: 0x82},
+	{value: 0x0018, lo: 0x83, hi: 0x84},
+	{value: 0x1318, lo: 0x85, hi: 0x8b},
+	{value: 0x0018, lo: 0x8c, hi: 0xa9},
+	{value: 0x1318, lo: 0xaa, hi: 0xad},
+	{value: 0x0018, lo: 0xae, hi: 0xba},
+	{value: 0xb851, lo: 0xbb, hi: 0xbb},
+	{value: 0xb899, lo: 0xbc, hi: 0xbc},
+	{value: 0xb8e1, lo: 0xbd, hi: 0xbd},
+	{value: 0xb949, lo: 0xbe, hi: 0xbe},
+	{value: 0xb9b1, lo: 0xbf, hi: 0xbf},
+	// Block 0xdc, offset 0x686
+	{value: 0x0000, lo: 0x03},
+	{value: 0xba19, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0xa8},
+	{value: 0x0040, lo: 0xa9, hi: 0xbf},
+	// Block 0xdd, offset 0x68a
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x81},
+	{value: 0x1318, lo: 0x82, hi: 0x84},
+	{value: 0x0018, lo: 0x85, hi: 0x85},
+	{value: 0x0040, lo: 0x86, hi: 0xbf},
+	// Block 0xde, offset 0x68f
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xb1},
+	{value: 0x0040, lo: 0xb2, hi: 0xbf},
+	// Block 0xdf, offset 0x694
+	{value: 0x0000, lo: 0x03},
+	{value: 0x1308, lo: 0x80, hi: 0xb6},
+	{value: 0x0018, lo: 0xb7, hi: 0xba},
+	{value: 0x1308, lo: 0xbb, hi: 0xbf},
+	// Block 0xe0, offset 0x698
+	{value: 0x0000, lo: 0x04},
+	{value: 0x1308, lo: 0x80, hi: 0xac},
+	{value: 0x0018, lo: 0xad, hi: 0xb4},
+	{value: 0x1308, lo: 0xb5, hi: 0xb5},
+	{value: 0x0018, lo: 0xb6, hi: 0xbf},
+	// Block 0xe1, offset 0x69d
+	{value: 0x0000, lo: 0x08},
+	{value: 0x0018, lo: 0x80, hi: 0x83},
+	{value: 0x1308, lo: 0x84, hi: 0x84},
+	{value: 0x0018, lo: 0x85, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x9a},
+	{value: 0x1308, lo: 0x9b, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xa0},
+	{value: 0x1308, lo: 0xa1, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+	// Block 0xe2, offset 0x6a6
+	{value: 0x0000, lo: 0x0a},
+	{value: 0x1308, lo: 0x80, hi: 0x86},
+	{value: 0x0040, lo: 0x87, hi: 0x87},
+	{value: 0x1308, lo: 0x88, hi: 0x98},
+	{value: 0x0040, lo: 0x99, hi: 0x9a},
+	{value: 0x1308, lo: 0x9b, hi: 0xa1},
+	{value: 0x0040, lo: 0xa2, hi: 0xa2},
+	{value: 0x1308, lo: 0xa3, hi: 0xa4},
+	{value: 0x0040, lo: 0xa5, hi: 0xa5},
+	{value: 0x1308, lo: 0xa6, hi: 0xaa},
+	{value: 0x0040, lo: 0xab, hi: 0xbf},
+	// Block 0xe3, offset 0x6b1
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0008, lo: 0x80, hi: 0x84},
+	{value: 0x0040, lo: 0x85, hi: 0x86},
+	{value: 0x0018, lo: 0x87, hi: 0x8f},
+	{value: 0x1308, lo: 0x90, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0xbf},
+	// Block 0xe4, offset 0x6b7
+	{value: 0x0000, lo: 0x07},
+	{value: 0x0208, lo: 0x80, hi: 0x83},
+	{value: 0x1308, lo: 0x84, hi: 0x8a},
+	{value: 0x0040, lo: 0x8b, hi: 0x8f},
+	{value: 0x0008, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9d},
+	{value: 0x0018, lo: 0x9e, hi: 0x9f},
+	{value: 0x0040, lo: 0xa0, hi: 0xbf},
+	// Block 0xe5, offset 0x6bf
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0040, lo: 0x80, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb1},
+	{value: 0x0040, lo: 0xb2, hi: 0xbf},
+	// Block 0xe6, offset 0x6c3
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0xab},
+	{value: 0x0040, lo: 0xac, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xbf},
+	// Block 0xe7, offset 0x6c7
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x93},
+	{value: 0x0040, lo: 0x94, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xae},
+	{value: 0x0040, lo: 0xaf, hi: 0xb0},
+	{value: 0x0018, lo: 0xb1, hi: 0xbf},
+	// Block 0xe8, offset 0x6cd
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0018, lo: 0x81, hi: 0x8f},
+	{value: 0x0040, lo: 0x90, hi: 0x90},
+	{value: 0x0018, lo: 0x91, hi: 0xb5},
+	{value: 0x0040, lo: 0xb6, hi: 0xbf},
+	// Block 0xe9, offset 0x6d3
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x8f},
+	{value: 0xc1c1, lo: 0x90, hi: 0x90},
+	{value: 0x0018, lo: 0x91, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xbf},
+	// Block 0xea, offset 0x6d8
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0040, lo: 0x80, hi: 0xa5},
+	{value: 0x0018, lo: 0xa6, hi: 0xbf},
+	// Block 0xeb, offset 0x6db
+	{value: 0x0000, lo: 0x0d},
+	{value: 0xc7e9, lo: 0x80, hi: 0x80},
+	{value: 0xc839, lo: 0x81, hi: 0x81},
+	{value: 0xc889, lo: 0x82, hi: 0x82},
+	{value: 0xc8d9, lo: 0x83, hi: 0x83},
+	{value: 0xc929, lo: 0x84, hi: 0x84},
+	{value: 0xc979, lo: 0x85, hi: 0x85},
+	{value: 0xc9c9, lo: 0x86, hi: 0x86},
+	{value: 0xca19, lo: 0x87, hi: 0x87},
+	{value: 0xca69, lo: 0x88, hi: 0x88},
+	{value: 0x0040, lo: 0x89, hi: 0x8f},
+	{value: 0xcab9, lo: 0x90, hi: 0x90},
+	{value: 0xcad9, lo: 0x91, hi: 0x91},
+	{value: 0x0040, lo: 0x92, hi: 0xbf},
+	// Block 0xec, offset 0x6e9
+	{value: 0x0000, lo: 0x06},
+	{value: 0x0018, lo: 0x80, hi: 0x92},
+	{value: 0x0040, lo: 0x93, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xac},
+	{value: 0x0040, lo: 0xad, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb6},
+	{value: 0x0040, lo: 0xb7, hi: 0xbf},
+	// Block 0xed, offset 0x6f0
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0xb3},
+	{value: 0x0040, lo: 0xb4, hi: 0xbf},
+	// Block 0xee, offset 0x6f3
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0x94},
+	{value: 0x0040, lo: 0x95, hi: 0xbf},
+	// Block 0xef, offset 0x6f6
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0018, lo: 0x80, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0xbf},
+	// Block 0xf0, offset 0x6fa
+	{value: 0x0000, lo: 0x05},
+	{value: 0x0018, lo: 0x80, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x99},
+	{value: 0x0040, lo: 0x9a, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xbf},
+	// Block 0xf1, offset 0x700
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x87},
+	{value: 0x0040, lo: 0x88, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0xad},
+	{value: 0x0040, lo: 0xae, hi: 0xbf},
+	// Block 0xf2, offset 0x705
+	{value: 0x0000, lo: 0x09},
+	{value: 0x0040, lo: 0x80, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0x9f},
+	{value: 0x0018, lo: 0xa0, hi: 0xa7},
+	{value: 0x0040, lo: 0xa8, hi: 0xaf},
+	{value: 0x0018, lo: 0xb0, hi: 0xb0},
+	{value: 0x0040, lo: 0xb1, hi: 0xb2},
+	{value: 0x0018, lo: 0xb3, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xf3, offset 0x70f
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0018, lo: 0x80, hi: 0x8b},
+	{value: 0x0040, lo: 0x8c, hi: 0x8f},
+	{value: 0x0018, lo: 0x90, hi: 0x9e},
+	{value: 0x0040, lo: 0x9f, hi: 0xbf},
+	// Block 0xf4, offset 0x714
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0x91},
+	{value: 0x0040, lo: 0x92, hi: 0xbf},
+	// Block 0xf5, offset 0x717
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0018, lo: 0x80, hi: 0x80},
+	{value: 0x0040, lo: 0x81, hi: 0xbf},
+	// Block 0xf6, offset 0x71a
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0x96},
+	{value: 0x0040, lo: 0x97, hi: 0xbf},
+	// Block 0xf7, offset 0x71d
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xb4},
+	{value: 0x0040, lo: 0xb5, hi: 0xbf},
+	// Block 0xf8, offset 0x720
+	{value: 0x0000, lo: 0x03},
+	{value: 0x0008, lo: 0x80, hi: 0x9d},
+	{value: 0x0040, lo: 0x9e, hi: 0x9f},
+	{value: 0x0008, lo: 0xa0, hi: 0xbf},
+	// Block 0xf9, offset 0x724
+	{value: 0x0000, lo: 0x02},
+	{value: 0x0008, lo: 0x80, hi: 0xa1},
+	{value: 0x0040, lo: 0xa2, hi: 0xbf},
+	// Block 0xfa, offset 0x727
+	{value: 0x0020, lo: 0x0f},
+	{value: 0xdeb9, lo: 0x80, hi: 0x89},
+	{value: 0x8dfd, lo: 0x8a, hi: 0x8a},
+	{value: 0xdff9, lo: 0x8b, hi: 0x9c},
+	{value: 0x8e1d, lo: 0x9d, hi: 0x9d},
+	{value: 0xe239, lo: 0x9e, hi: 0xa2},
+	{value: 0x8e3d, lo: 0xa3, hi: 0xa3},
+	{value: 0xe2d9, lo: 0xa4, hi: 0xab},
+	{value: 0x7ed5, lo: 0xac, hi: 0xac},
+	{value: 0xe3d9, lo: 0xad, hi: 0xaf},
+	{value: 0x8e5d, lo: 0xb0, hi: 0xb0},
+	{value: 0xe439, lo: 0xb1, hi: 0xb6},
+	{value: 0x8e7d, lo: 0xb7, hi: 0xb9},
+	{value: 0xe4f9, lo: 0xba, hi: 0xba},
+	{value: 0x8edd, lo: 0xbb, hi: 0xbb},
+	{value: 0xe519, lo: 0xbc, hi: 0xbf},
+	// Block 0xfb, offset 0x737
+	{value: 0x0020, lo: 0x10},
+	{value: 0x937d, lo: 0x80, hi: 0x80},
+	{value: 0xf099, lo: 0x81, hi: 0x86},
+	{value: 0x939d, lo: 0x87, hi: 0x8a},
+	{value: 0xd9f9, lo: 0x8b, hi: 0x8b},
+	{value: 0xf159, lo: 0x8c, hi: 0x96},
+	{value: 0x941d, lo: 0x97, hi: 0x97},
+	{value: 0xf2b9, lo: 0x98, hi: 0xa3},
+	{value: 0x943d, lo: 0xa4, hi: 0xa6},
+	{value: 0xf439, lo: 0xa7, hi: 0xaa},
+	{value: 0x949d, lo: 0xab, hi: 0xab},
+	{value: 0xf4b9, lo: 0xac, hi: 0xac},
+	{value: 0x94bd, lo: 0xad, hi: 0xad},
+	{value: 0xf4d9, lo: 0xae, hi: 0xaf},
+	{value: 0x94dd, lo: 0xb0, hi: 0xb1},
+	{value: 0xf519, lo: 0xb2, hi: 0xbe},
+	{value: 0x0040, lo: 0xbf, hi: 0xbf},
+	// Block 0xfc, offset 0x748
+	{value: 0x0000, lo: 0x04},
+	{value: 0x0040, lo: 0x80, hi: 0x80},
+	{value: 0x0340, lo: 0x81, hi: 0x81},
+	{value: 0x0040, lo: 0x82, hi: 0x9f},
+	{value: 0x0340, lo: 0xa0, hi: 0xbf},
+	// Block 0xfd, offset 0x74d
+	{value: 0x0000, lo: 0x01},
+	{value: 0x0340, lo: 0x80, hi: 0xbf},
+	// Block 0xfe, offset 0x74f
+	{value: 0x0000, lo: 0x01},
+	{value: 0x13c0, lo: 0x80, hi: 0xbf},
+	// Block 0xff, offset 0x751
+	{value: 0x0000, lo: 0x02},
+	{value: 0x13c0, lo: 0x80, hi: 0xaf},
+	{value: 0x0040, lo: 0xb0, hi: 0xbf},
+}
+
+// Total table size 41559 bytes (40KiB); checksum: F4A1FA4E
diff --git a/src/vendor/golang_org/x/net/idna/trie.go b/src/vendor/golang_org/x/net/idna/trie.go
new file mode 100644
index 0000000..000fb97
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/trie.go
@@ -0,0 +1,72 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package idna
+
+// appendMapping appends the mapping for the respective rune. isMapped must be
+// true. A mapping is a categorization of a rune as defined in UTS #46.
+func (c info) appendMapping(b []byte, s string) []byte {
+	index := int(c >> indexShift)
+	if c&xorBit == 0 {
+		s := mappings[index:]
+		return append(b, s[1:s[0]+1]...)
+	}
+	b = append(b, s...)
+	if c&inlineXOR == inlineXOR {
+		// TODO: support and handle two-byte inline masks
+		b[len(b)-1] ^= byte(index)
+	} else {
+		for p := len(b) - int(xorData[index]); p < len(b); p++ {
+			index++
+			b[p] ^= xorData[index]
+		}
+	}
+	return b
+}
+
+// Sparse block handling code.
+
+type valueRange struct {
+	value  uint16 // header: value:stride
+	lo, hi byte   // header: lo:n
+}
+
+type sparseBlocks struct {
+	values []valueRange
+	offset []uint16
+}
+
+var idnaSparse = sparseBlocks{
+	values: idnaSparseValues[:],
+	offset: idnaSparseOffset[:],
+}
+
+// Don't use newIdnaTrie to avoid unconditional linking in of the table.
+var trie = &idnaTrie{}
+
+// lookup determines the type of block n and looks up the value for b.
+// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
+// is a list of ranges with an accompanying value. Given a matching range r,
+// the value for b is by r.value + (b - r.lo) * stride.
+func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
+	offset := t.offset[n]
+	header := t.values[offset]
+	lo := offset + 1
+	hi := lo + uint16(header.lo)
+	for lo < hi {
+		m := lo + (hi-lo)/2
+		r := t.values[m]
+		if r.lo <= b && b <= r.hi {
+			return r.value + uint16(b-r.lo)*header.value
+		}
+		if b < r.lo {
+			hi = m
+		} else {
+			lo = m + 1
+		}
+	}
+	return 0
+}
diff --git a/src/vendor/golang_org/x/net/idna/trieval.go b/src/vendor/golang_org/x/net/idna/trieval.go
new file mode 100644
index 0000000..cd88e4d
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/trieval.go
@@ -0,0 +1,116 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT.
+
+package idna
+
+// This file contains definitions for interpreting the trie value of the idna
+// trie generated by "go run gen*.go". It is shared by both the generator
+// program and the resultant package. Sharing is achieved by the generator
+// copying gen_trieval.go to trieval.go and changing what's above this comment.
+
+// info holds information from the IDNA mapping table for a single rune. It is
+// the value returned by a trie lookup. In most cases, all information fits in
+// a 16-bit value. For mappings, this value may contain an index into a slice
+// with the mapped string. Such mappings can consist of the actual mapped value
+// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the
+// input rune. This technique is used by the cases packages and reduces the
+// table size significantly.
+//
+// The per-rune values have the following format:
+//
+//   if mapped {
+//     if inlinedXOR {
+//       15..13 inline XOR marker
+//       12..11 unused
+//       10..3  inline XOR mask
+//     } else {
+//       15..3  index into xor or mapping table
+//     }
+//   } else {
+//       15..13 unused
+//           12 modifier (including virama)
+//           11 virama modifier
+//       10..8  joining type
+//        7..3  category type
+//   }
+//      2  use xor pattern
+//   1..0  mapped category
+//
+// See the definitions below for a more detailed description of the various
+// bits.
+type info uint16
+
+const (
+	catSmallMask = 0x3
+	catBigMask   = 0xF8
+	indexShift   = 3
+	xorBit       = 0x4    // interpret the index as an xor pattern
+	inlineXOR    = 0xE000 // These bits are set if the XOR pattern is inlined.
+
+	joinShift = 8
+	joinMask  = 0x07
+
+	viramaModifier = 0x0800
+	modifier       = 0x1000
+)
+
+// A category corresponds to a category defined in the IDNA mapping table.
+type category uint16
+
+const (
+	unknown              category = 0 // not defined currently in unicode.
+	mapped               category = 1
+	disallowedSTD3Mapped category = 2
+	deviation            category = 3
+)
+
+const (
+	valid               category = 0x08
+	validNV8            category = 0x18
+	validXV8            category = 0x28
+	disallowed          category = 0x40
+	disallowedSTD3Valid category = 0x80
+	ignored             category = 0xC0
+)
+
+// join types and additional rune information
+const (
+	joiningL = (iota + 1)
+	joiningD
+	joiningT
+	joiningR
+
+	//the following types are derived during processing
+	joinZWJ
+	joinZWNJ
+	joinVirama
+	numJoinTypes
+)
+
+func (c info) isMapped() bool {
+	return c&0x3 != 0
+}
+
+func (c info) category() category {
+	small := c & catSmallMask
+	if small != 0 {
+		return category(small)
+	}
+	return category(c & catBigMask)
+}
+
+func (c info) joinType() info {
+	if c.isMapped() {
+		return 0
+	}
+	return (c >> joinShift) & joinMask
+}
+
+func (c info) isModifier() bool {
+	return c&(modifier|catSmallMask) == modifier
+}
+
+func (c info) isViramaModifier() bool {
+	return c&(viramaModifier|catSmallMask) == viramaModifier
+}
diff --git a/src/vendor/golang_org/x/net/lif/address.go b/src/vendor/golang_org/x/net/lif/address.go
index f9b34ae..afb957f 100644
--- a/src/vendor/golang_org/x/net/lif/address.go
+++ b/src/vendor/golang_org/x/net/lif/address.go
@@ -67,7 +67,7 @@ func Addrs(af int, name string) ([]Addr, error) {
 				continue
 			}
 			sa := (*sockaddrStorage)(unsafe.Pointer(&lifr.Lifru[0]))
-			l := int(littleEndian.Uint32(lifr.Lifru1[:4]))
+			l := int(nativeEndian.Uint32(lifr.Lifru1[:4]))
 			if l == 0 {
 				continue
 			}
@@ -77,7 +77,7 @@ func Addrs(af int, name string) ([]Addr, error) {
 				copy(a.IP[:], lifr.Lifru[4:8])
 				as = append(as, a)
 			case sysAF_INET6:
-				a := &Inet6Addr{PrefixLen: l, ZoneID: int(littleEndian.Uint32(lifr.Lifru[24:28]))}
+				a := &Inet6Addr{PrefixLen: l, ZoneID: int(nativeEndian.Uint32(lifr.Lifru[24:28]))}
 				copy(a.IP[:], lifr.Lifru[8:24])
 				as = append(as, a)
 			}
diff --git a/src/vendor/golang_org/x/net/lif/address_test.go b/src/vendor/golang_org/x/net/lif/address_test.go
index f62ed93..a25f10b 100644
--- a/src/vendor/golang_org/x/net/lif/address_test.go
+++ b/src/vendor/golang_org/x/net/lif/address_test.go
@@ -78,15 +78,17 @@ type addrPack struct {
 }
 
 func addrPacks() ([]addrPack, error) {
+	var lastErr error
 	var aps []addrPack
 	for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
 		as, err := Addrs(af, "")
 		if err != nil {
-			return nil, err
+			lastErr = err
+			continue
 		}
 		aps = append(aps, addrPack{af: af, as: as})
 	}
-	return aps, nil
+	return aps, lastErr
 }
 
 func TestAddrs(t *testing.T) {
diff --git a/src/vendor/golang_org/x/net/lif/binary.go b/src/vendor/golang_org/x/net/lif/binary.go
index aade9ea..738a94f 100644
--- a/src/vendor/golang_org/x/net/lif/binary.go
+++ b/src/vendor/golang_org/x/net/lif/binary.go
@@ -12,7 +12,10 @@ package lif
 // library. Therefore the package set used in the package must be the
 // same as net package.
 
-var littleEndian binaryLittleEndian
+var (
+	littleEndian binaryLittleEndian
+	bigEndian    binaryBigEndian
+)
 
 type binaryByteOrder interface {
 	Uint16([]byte) uint16
@@ -66,3 +69,47 @@ func (binaryLittleEndian) PutUint64(b []byte, v uint64) {
 	b[6] = byte(v >> 48)
 	b[7] = byte(v >> 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
+}
+
+func (binaryBigEndian) 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)
+	b[3] = byte(v >> 32)
+	b[4] = byte(v >> 24)
+	b[5] = byte(v >> 16)
+	b[6] = byte(v >> 8)
+	b[7] = byte(v)
+}
diff --git a/src/vendor/golang_org/x/net/lif/defs_solaris.go b/src/vendor/golang_org/x/net/lif/defs_solaris.go
index 8b84ba5..02c1998 100644
--- a/src/vendor/golang_org/x/net/lif/defs_solaris.go
+++ b/src/vendor/golang_org/x/net/lif/defs_solaris.go
@@ -75,7 +75,7 @@ const (
 	sizeofLifIfinfoReq = C.sizeof_struct_lif_ifinfo_req
 )
 
-type sysLifnum C.struct_lifnum
+type lifnum C.struct_lifnum
 
 type lifreq C.struct_lifreq
 
diff --git a/src/vendor/golang_org/x/net/lif/link.go b/src/vendor/golang_org/x/net/lif/link.go
index 76fa6c6..913a53e 100644
--- a/src/vendor/golang_org/x/net/lif/link.go
+++ b/src/vendor/golang_org/x/net/lif/link.go
@@ -31,15 +31,15 @@ func (ll *Link) fetch(s uintptr) {
 	}
 	ioc := int64(sysSIOCGLIFINDEX)
 	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
-		ll.Index = int(littleEndian.Uint32(lifr.Lifru[:4]))
+		ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4]))
 	}
 	ioc = int64(sysSIOCGLIFFLAGS)
 	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
-		ll.Flags = int(littleEndian.Uint64(lifr.Lifru[:8]))
+		ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8]))
 	}
 	ioc = int64(sysSIOCGLIFMTU)
 	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
-		ll.MTU = int(littleEndian.Uint32(lifr.Lifru[:4]))
+		ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4]))
 	}
 	switch ll.Type {
 	case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
@@ -70,7 +70,7 @@ func Links(af int, name string) ([]Link, error) {
 
 func links(eps []endpoint, name string) ([]Link, error) {
 	var lls []Link
-	lifn := sysLifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
+	lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
 	lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
 	for _, ep := range eps {
 		lifn.Family = uint16(ep.af)
@@ -84,7 +84,11 @@ func links(eps []endpoint, name string) ([]Link, error) {
 		b := make([]byte, lifn.Count*sizeofLifreq)
 		lifc.Family = uint16(ep.af)
 		lifc.Len = lifn.Count * sizeofLifreq
-		littleEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
+		if len(lifc.Lifcu) == 8 {
+			nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
+		} else {
+			nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0]))))
+		}
 		ioc = int64(sysSIOCGLIFCONF)
 		if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
 			continue
diff --git a/src/vendor/golang_org/x/net/lif/link_test.go b/src/vendor/golang_org/x/net/lif/link_test.go
index 8fb2bf6..0cb9b95 100644
--- a/src/vendor/golang_org/x/net/lif/link_test.go
+++ b/src/vendor/golang_org/x/net/lif/link_test.go
@@ -21,15 +21,17 @@ type linkPack struct {
 }
 
 func linkPacks() ([]linkPack, error) {
+	var lastErr error
 	var lps []linkPack
 	for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
 		lls, err := Links(af, "")
 		if err != nil {
-			return nil, err
+			lastErr = err
+			continue
 		}
 		lps = append(lps, linkPack{af: af, lls: lls})
 	}
-	return lps, nil
+	return lps, lastErr
 }
 
 func TestLinks(t *testing.T) {
diff --git a/src/vendor/golang_org/x/net/lif/sys.go b/src/vendor/golang_org/x/net/lif/sys.go
new file mode 100644
index 0000000..c896041
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/sys.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import "unsafe"
+
+var nativeEndian binaryByteOrder
+
+func init() {
+	i := uint32(1)
+	b := (*[4]byte)(unsafe.Pointer(&i))
+	if b[0] == 1 {
+		nativeEndian = littleEndian
+	} else {
+		nativeEndian = bigEndian
+	}
+}
diff --git a/src/vendor/golang_org/x/net/lif/sys_solaris_amd64.s b/src/vendor/golang_org/x/net/lif/sys_solaris_amd64.s
index 1ebca37..39d76af 100644
--- a/src/vendor/golang_org/x/net/lif/sys_solaris_amd64.s
+++ b/src/vendor/golang_org/x/net/lif/sys_solaris_amd64.s
@@ -6,6 +6,3 @@
 
 TEXT ·sysvicall6(SB),NOSPLIT,$0-88
 	JMP	syscall·sysvicall6(SB)
-
-TEXT ·keepAlive(SB),NOSPLIT,$0
-	RET
diff --git a/src/vendor/golang_org/x/net/lif/syscall.go b/src/vendor/golang_org/x/net/lif/syscall.go
index 5fe0736..aadab2e 100644
--- a/src/vendor/golang_org/x/net/lif/syscall.go
+++ b/src/vendor/golang_org/x/net/lif/syscall.go
@@ -19,13 +19,8 @@ var procIoctl uintptr
 
 func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (uintptr, uintptr, syscall.Errno)
 
-// TODO: replace with runtime.KeepAlive when available
-//go:noescape
-func keepAlive(p unsafe.Pointer)
-
 func ioctl(s, ioc uintptr, arg unsafe.Pointer) error {
 	_, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procIoctl)), 3, s, ioc, uintptr(arg), 0, 0, 0)
-	keepAlive(arg)
 	if errno != 0 {
 		return error(errno)
 	}
diff --git a/src/vendor/golang_org/x/net/lif/zsys_solaris_amd64.go b/src/vendor/golang_org/x/net/lif/zsys_solaris_amd64.go
index 94231c4..b5e999b 100644
--- a/src/vendor/golang_org/x/net/lif/zsys_solaris_amd64.go
+++ b/src/vendor/golang_org/x/net/lif/zsys_solaris_amd64.go
@@ -65,7 +65,7 @@ const (
 	sizeofLifIfinfoReq = 0x10
 )
 
-type sysLifnum struct {
+type lifnum struct {
 	Family    uint16
 	Pad_cgo_0 [2]byte
 	Flags     int32
diff --git a/src/vendor/golang_org/x/net/nettest/conntest.go b/src/vendor/golang_org/x/net/nettest/conntest.go
new file mode 100644
index 0000000..5bd3a8c
--- /dev/null
+++ b/src/vendor/golang_org/x/net/nettest/conntest.go
@@ -0,0 +1,456 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package nettest provides utilities for network testing.
+package nettest
+
+import (
+	"bytes"
+	"encoding/binary"
+	"io"
+	"io/ioutil"
+	"math/rand"
+	"net"
+	"runtime"
+	"sync"
+	"testing"
+	"time"
+)
+
+var (
+	aLongTimeAgo = time.Unix(233431200, 0)
+	neverTimeout = time.Time{}
+)
+
+// MakePipe creates a connection between two endpoints and returns the pair
+// as c1 and c2, such that anything written to c1 is read by c2 and vice-versa.
+// The stop function closes all resources, including c1, c2, and the underlying
+// net.Listener (if there is one), and should not be nil.
+type MakePipe func() (c1, c2 net.Conn, stop func(), err error)
+
+// TestConn tests that a net.Conn implementation properly satisfies the interface.
+// The tests should not produce any false positives, but may experience
+// false negatives. Thus, some issues may only be detected when the test is
+// run multiple times. For maximal effectiveness, run the tests under the
+// race detector.
+func TestConn(t *testing.T, mp MakePipe) {
+	testConn(t, mp)
+}
+
+type connTester func(t *testing.T, c1, c2 net.Conn)
+
+func timeoutWrapper(t *testing.T, mp MakePipe, f connTester) {
+	c1, c2, stop, err := mp()
+	if err != nil {
+		t.Fatalf("unable to make pipe: %v", err)
+	}
+	var once sync.Once
+	defer once.Do(func() { stop() })
+	timer := time.AfterFunc(time.Minute, func() {
+		once.Do(func() {
+			t.Error("test timed out; terminating pipe")
+			stop()
+		})
+	})
+	defer timer.Stop()
+	f(t, c1, c2)
+}
+
+// testBasicIO tests that the data sent on c1 is properly received on c2.
+func testBasicIO(t *testing.T, c1, c2 net.Conn) {
+	want := make([]byte, 1<<20)
+	rand.New(rand.NewSource(0)).Read(want)
+
+	dataCh := make(chan []byte)
+	go func() {
+		rd := bytes.NewReader(want)
+		if err := chunkedCopy(c1, rd); err != nil {
+			t.Errorf("unexpected c1.Write error: %v", err)
+		}
+		if err := c1.Close(); err != nil {
+			t.Errorf("unexpected c1.Close error: %v", err)
+		}
+	}()
+
+	go func() {
+		wr := new(bytes.Buffer)
+		if err := chunkedCopy(wr, c2); err != nil {
+			t.Errorf("unexpected c2.Read error: %v", err)
+		}
+		if err := c2.Close(); err != nil {
+			t.Errorf("unexpected c2.Close error: %v", err)
+		}
+		dataCh <- wr.Bytes()
+	}()
+
+	if got := <-dataCh; !bytes.Equal(got, want) {
+		t.Errorf("transmitted data differs")
+	}
+}
+
+// testPingPong tests that the two endpoints can synchronously send data to
+// each other in a typical request-response pattern.
+func testPingPong(t *testing.T, c1, c2 net.Conn) {
+	var wg sync.WaitGroup
+	defer wg.Wait()
+
+	pingPonger := func(c net.Conn) {
+		defer wg.Done()
+		buf := make([]byte, 8)
+		var prev uint64
+		for {
+			if _, err := io.ReadFull(c, buf); err != nil {
+				if err == io.EOF {
+					break
+				}
+				t.Errorf("unexpected Read error: %v", err)
+			}
+
+			v := binary.LittleEndian.Uint64(buf)
+			binary.LittleEndian.PutUint64(buf, v+1)
+			if prev != 0 && prev+2 != v {
+				t.Errorf("mismatching value: got %d, want %d", v, prev+2)
+			}
+			prev = v
+			if v == 1000 {
+				break
+			}
+
+			if _, err := c.Write(buf); err != nil {
+				t.Errorf("unexpected Write error: %v", err)
+				break
+			}
+		}
+		if err := c.Close(); err != nil {
+			t.Errorf("unexpected Close error: %v", err)
+		}
+	}
+
+	wg.Add(2)
+	go pingPonger(c1)
+	go pingPonger(c2)
+
+	// Start off the chain reaction.
+	if _, err := c1.Write(make([]byte, 8)); err != nil {
+		t.Errorf("unexpected c1.Write error: %v", err)
+	}
+}
+
+// testRacyRead tests that it is safe to mutate the input Read buffer
+// immediately after cancelation has occurred.
+func testRacyRead(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(c2, rand.New(rand.NewSource(0)))
+
+	var wg sync.WaitGroup
+	defer wg.Wait()
+
+	c1.SetReadDeadline(time.Now().Add(time.Millisecond))
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+
+			b1 := make([]byte, 1024)
+			b2 := make([]byte, 1024)
+			for j := 0; j < 100; j++ {
+				_, err := c1.Read(b1)
+				copy(b1, b2) // Mutate b1 to trigger potential race
+				if err != nil {
+					checkForTimeoutError(t, err)
+					c1.SetReadDeadline(time.Now().Add(time.Millisecond))
+				}
+			}
+		}()
+	}
+}
+
+// testRacyWrite tests that it is safe to mutate the input Write buffer
+// immediately after cancelation has occurred.
+func testRacyWrite(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(ioutil.Discard, c2)
+
+	var wg sync.WaitGroup
+	defer wg.Wait()
+
+	c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+
+			b1 := make([]byte, 1024)
+			b2 := make([]byte, 1024)
+			for j := 0; j < 100; j++ {
+				_, err := c1.Write(b1)
+				copy(b1, b2) // Mutate b1 to trigger potential race
+				if err != nil {
+					checkForTimeoutError(t, err)
+					c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
+				}
+			}
+		}()
+	}
+}
+
+// testReadTimeout tests that Read timeouts do not affect Write.
+func testReadTimeout(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(ioutil.Discard, c2)
+
+	c1.SetReadDeadline(aLongTimeAgo)
+	_, err := c1.Read(make([]byte, 1024))
+	checkForTimeoutError(t, err)
+	if _, err := c1.Write(make([]byte, 1024)); err != nil {
+		t.Errorf("unexpected Write error: %v", err)
+	}
+}
+
+// testWriteTimeout tests that Write timeouts do not affect Read.
+func testWriteTimeout(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(c2, rand.New(rand.NewSource(0)))
+
+	c1.SetWriteDeadline(aLongTimeAgo)
+	_, err := c1.Write(make([]byte, 1024))
+	checkForTimeoutError(t, err)
+	if _, err := c1.Read(make([]byte, 1024)); err != nil {
+		t.Errorf("unexpected Read error: %v", err)
+	}
+}
+
+// testPastTimeout tests that a deadline set in the past immediately times out
+// Read and Write requests.
+func testPastTimeout(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(c2, c2)
+
+	testRoundtrip(t, c1)
+
+	c1.SetDeadline(aLongTimeAgo)
+	n, err := c1.Write(make([]byte, 1024))
+	if n != 0 {
+		t.Errorf("unexpected Write count: got %d, want 0", n)
+	}
+	checkForTimeoutError(t, err)
+	n, err = c1.Read(make([]byte, 1024))
+	if n != 0 {
+		t.Errorf("unexpected Read count: got %d, want 0", n)
+	}
+	checkForTimeoutError(t, err)
+
+	testRoundtrip(t, c1)
+}
+
+// testPresentTimeout tests that a deadline set while there are pending
+// Read and Write operations immediately times out those operations.
+func testPresentTimeout(t *testing.T, c1, c2 net.Conn) {
+	var wg sync.WaitGroup
+	defer wg.Wait()
+	wg.Add(3)
+
+	deadlineSet := make(chan bool, 1)
+	go func() {
+		defer wg.Done()
+		time.Sleep(100 * time.Millisecond)
+		deadlineSet <- true
+		c1.SetReadDeadline(aLongTimeAgo)
+		c1.SetWriteDeadline(aLongTimeAgo)
+	}()
+	go func() {
+		defer wg.Done()
+		n, err := c1.Read(make([]byte, 1024))
+		if n != 0 {
+			t.Errorf("unexpected Read count: got %d, want 0", n)
+		}
+		checkForTimeoutError(t, err)
+		if len(deadlineSet) == 0 {
+			t.Error("Read timed out before deadline is set")
+		}
+	}()
+	go func() {
+		defer wg.Done()
+		var err error
+		for err == nil {
+			_, err = c1.Write(make([]byte, 1024))
+		}
+		checkForTimeoutError(t, err)
+		if len(deadlineSet) == 0 {
+			t.Error("Write timed out before deadline is set")
+		}
+	}()
+}
+
+// testFutureTimeout tests that a future deadline will eventually time out
+// Read and Write operations.
+func testFutureTimeout(t *testing.T, c1, c2 net.Conn) {
+	var wg sync.WaitGroup
+	wg.Add(2)
+
+	c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
+	go func() {
+		defer wg.Done()
+		_, err := c1.Read(make([]byte, 1024))
+		checkForTimeoutError(t, err)
+	}()
+	go func() {
+		defer wg.Done()
+		var err error
+		for err == nil {
+			_, err = c1.Write(make([]byte, 1024))
+		}
+		checkForTimeoutError(t, err)
+	}()
+	wg.Wait()
+
+	go chunkedCopy(c2, c2)
+	resyncConn(t, c1)
+	testRoundtrip(t, c1)
+}
+
+// testCloseTimeout tests that calling Close immediately times out pending
+// Read and Write operations.
+func testCloseTimeout(t *testing.T, c1, c2 net.Conn) {
+	go chunkedCopy(c2, c2)
+
+	var wg sync.WaitGroup
+	defer wg.Wait()
+	wg.Add(3)
+
+	// Test for cancelation upon connection closure.
+	c1.SetDeadline(neverTimeout)
+	go func() {
+		defer wg.Done()
+		time.Sleep(100 * time.Millisecond)
+		c1.Close()
+	}()
+	go func() {
+		defer wg.Done()
+		var err error
+		buf := make([]byte, 1024)
+		for err == nil {
+			_, err = c1.Read(buf)
+		}
+	}()
+	go func() {
+		defer wg.Done()
+		var err error
+		buf := make([]byte, 1024)
+		for err == nil {
+			_, err = c1.Write(buf)
+		}
+	}()
+}
+
+// testConcurrentMethods tests that the methods of net.Conn can safely
+// be called concurrently.
+func testConcurrentMethods(t *testing.T, c1, c2 net.Conn) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9; see https://golang.org/issue/20489")
+	}
+	go chunkedCopy(c2, c2)
+
+	// The results of the calls may be nonsensical, but this should
+	// not trigger a race detector warning.
+	var wg sync.WaitGroup
+	for i := 0; i < 100; i++ {
+		wg.Add(7)
+		go func() {
+			defer wg.Done()
+			c1.Read(make([]byte, 1024))
+		}()
+		go func() {
+			defer wg.Done()
+			c1.Write(make([]byte, 1024))
+		}()
+		go func() {
+			defer wg.Done()
+			c1.SetDeadline(time.Now().Add(10 * time.Millisecond))
+		}()
+		go func() {
+			defer wg.Done()
+			c1.SetReadDeadline(aLongTimeAgo)
+		}()
+		go func() {
+			defer wg.Done()
+			c1.SetWriteDeadline(aLongTimeAgo)
+		}()
+		go func() {
+			defer wg.Done()
+			c1.LocalAddr()
+		}()
+		go func() {
+			defer wg.Done()
+			c1.RemoteAddr()
+		}()
+	}
+	wg.Wait() // At worst, the deadline is set 10ms into the future
+
+	resyncConn(t, c1)
+	testRoundtrip(t, c1)
+}
+
+// checkForTimeoutError checks that the error satisfies the Error interface
+// and that Timeout returns true.
+func checkForTimeoutError(t *testing.T, err error) {
+	if nerr, ok := err.(net.Error); ok {
+		if !nerr.Timeout() {
+			t.Errorf("err.Timeout() = false, want true")
+		}
+	} else {
+		t.Errorf("got %T, want net.Error", err)
+	}
+}
+
+// testRoundtrip writes something into c and reads it back.
+// It assumes that everything written into c is echoed back to itself.
+func testRoundtrip(t *testing.T, c net.Conn) {
+	if err := c.SetDeadline(neverTimeout); err != nil {
+		t.Errorf("roundtrip SetDeadline error: %v", err)
+	}
+
+	const s = "Hello, world!"
+	buf := []byte(s)
+	if _, err := c.Write(buf); err != nil {
+		t.Errorf("roundtrip Write error: %v", err)
+	}
+	if _, err := io.ReadFull(c, buf); err != nil {
+		t.Errorf("roundtrip Read error: %v", err)
+	}
+	if string(buf) != s {
+		t.Errorf("roundtrip data mismatch: got %q, want %q", buf, s)
+	}
+}
+
+// resyncConn resynchronizes the connection into a sane state.
+// It assumes that everything written into c is echoed back to itself.
+// It assumes that 0xff is not currently on the wire or in the read buffer.
+func resyncConn(t *testing.T, c net.Conn) {
+	c.SetDeadline(neverTimeout)
+	errCh := make(chan error)
+	go func() {
+		_, err := c.Write([]byte{0xff})
+		errCh <- err
+	}()
+	buf := make([]byte, 1024)
+	for {
+		n, err := c.Read(buf)
+		if n > 0 && bytes.IndexByte(buf[:n], 0xff) == n-1 {
+			break
+		}
+		if err != nil {
+			t.Errorf("unexpected Read error: %v", err)
+			break
+		}
+	}
+	if err := <-errCh; err != nil {
+		t.Errorf("unexpected Write error: %v", err)
+	}
+}
+
+// chunkedCopy copies from r to w in fixed-width chunks to avoid
+// causing a Write that exceeds the maximum packet size for packet-based
+// connections like "unixpacket".
+// We assume that the maximum packet size is at least 1024.
+func chunkedCopy(w io.Writer, r io.Reader) error {
+	b := make([]byte, 1024)
+	_, err := io.CopyBuffer(struct{ io.Writer }{w}, struct{ io.Reader }{r}, b)
+	return err
+}
diff --git a/src/vendor/golang_org/x/net/nettest/conntest_go16.go b/src/vendor/golang_org/x/net/nettest/conntest_go16.go
new file mode 100644
index 0000000..4cbf48e
--- /dev/null
+++ b/src/vendor/golang_org/x/net/nettest/conntest_go16.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.
+
+// +build !go1.7
+
+package nettest
+
+import "testing"
+
+func testConn(t *testing.T, mp MakePipe) {
+	// Avoid using subtests on Go 1.6 and below.
+	timeoutWrapper(t, mp, testBasicIO)
+	timeoutWrapper(t, mp, testPingPong)
+	timeoutWrapper(t, mp, testRacyRead)
+	timeoutWrapper(t, mp, testRacyWrite)
+	timeoutWrapper(t, mp, testReadTimeout)
+	timeoutWrapper(t, mp, testWriteTimeout)
+	timeoutWrapper(t, mp, testPastTimeout)
+	timeoutWrapper(t, mp, testPresentTimeout)
+	timeoutWrapper(t, mp, testFutureTimeout)
+	timeoutWrapper(t, mp, testCloseTimeout)
+	timeoutWrapper(t, mp, testConcurrentMethods)
+}
diff --git a/src/vendor/golang_org/x/net/nettest/conntest_go17.go b/src/vendor/golang_org/x/net/nettest/conntest_go17.go
new file mode 100644
index 0000000..fa039f0
--- /dev/null
+++ b/src/vendor/golang_org/x/net/nettest/conntest_go17.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.
+
+// +build go1.7
+
+package nettest
+
+import "testing"
+
+func testConn(t *testing.T, mp MakePipe) {
+	// Use subtests on Go 1.7 and above since it is better organized.
+	t.Run("BasicIO", func(t *testing.T) { timeoutWrapper(t, mp, testBasicIO) })
+	t.Run("PingPong", func(t *testing.T) { timeoutWrapper(t, mp, testPingPong) })
+	t.Run("RacyRead", func(t *testing.T) { timeoutWrapper(t, mp, testRacyRead) })
+	t.Run("RacyWrite", func(t *testing.T) { timeoutWrapper(t, mp, testRacyWrite) })
+	t.Run("ReadTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testReadTimeout) })
+	t.Run("WriteTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testWriteTimeout) })
+	t.Run("PastTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testPastTimeout) })
+	t.Run("PresentTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testPresentTimeout) })
+	t.Run("FutureTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testFutureTimeout) })
+	t.Run("CloseTimeout", func(t *testing.T) { timeoutWrapper(t, mp, testCloseTimeout) })
+	t.Run("ConcurrentMethods", func(t *testing.T) { timeoutWrapper(t, mp, testConcurrentMethods) })
+}
diff --git a/src/vendor/golang_org/x/net/nettest/conntest_test.go b/src/vendor/golang_org/x/net/nettest/conntest_test.go
new file mode 100644
index 0000000..23bd69f
--- /dev/null
+++ b/src/vendor/golang_org/x/net/nettest/conntest_test.go
@@ -0,0 +1,126 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package nettest
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net"
+	"os"
+	"runtime"
+	"testing"
+)
+
+// testUnixAddr uses ioutil.TempFile to get a name that is unique.
+// It also uses /tmp directory in case it is prohibited to create UNIX
+// sockets in TMPDIR.
+func testUnixAddr() string {
+	f, err := ioutil.TempFile("", "go-nettest")
+	if err != nil {
+		panic(err)
+	}
+	addr := f.Name()
+	f.Close()
+	os.Remove(addr)
+	return addr
+}
+
+// testableNetwork reports whether network is testable on the current
+// platform configuration.
+// This is based on logic from standard library's net/platform_test.go.
+func testableNetwork(network string) bool {
+	switch network {
+	case "unix":
+		switch runtime.GOOS {
+		case "android", "nacl", "plan9", "windows":
+			return false
+		}
+		if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+			return false
+		}
+	case "unixpacket":
+		switch runtime.GOOS {
+		case "android", "darwin", "nacl", "plan9", "windows", "freebsd":
+			return false
+		}
+	}
+	return true
+}
+
+func newLocalListener(network string) (net.Listener, error) {
+	switch network {
+	case "tcp":
+		ln, err := net.Listen("tcp", "127.0.0.1:0")
+		if err != nil {
+			ln, err = net.Listen("tcp6", "[::1]:0")
+		}
+		return ln, err
+	case "unix", "unixpacket":
+		return net.Listen(network, testUnixAddr())
+	}
+	return nil, fmt.Errorf("%s is not supported", network)
+}
+
+func TestTestConn(t *testing.T) {
+	tests := []struct{ name, network string }{
+		{"TCP", "tcp"},
+		{"UnixPipe", "unix"},
+		{"UnixPacketPipe", "unixpacket"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if !testableNetwork(tt.network) {
+				t.Skipf("not supported on %s", runtime.GOOS)
+			}
+
+			mp := func() (c1, c2 net.Conn, stop func(), err error) {
+				ln, err := newLocalListener(tt.network)
+				if err != nil {
+					return nil, nil, nil, err
+				}
+
+				// Start a connection between two endpoints.
+				var err1, err2 error
+				done := make(chan bool)
+				go func() {
+					c2, err2 = ln.Accept()
+					close(done)
+				}()
+				c1, err1 = net.Dial(ln.Addr().Network(), ln.Addr().String())
+				<-done
+
+				stop = func() {
+					if err1 == nil {
+						c1.Close()
+					}
+					if err2 == nil {
+						c2.Close()
+					}
+					ln.Close()
+					switch tt.network {
+					case "unix", "unixpacket":
+						os.Remove(ln.Addr().String())
+					}
+				}
+
+				switch {
+				case err1 != nil:
+					stop()
+					return nil, nil, nil, err1
+				case err2 != nil:
+					stop()
+					return nil, nil, nil, err2
+				default:
+					return c1, c2, stop, nil
+				}
+			}
+
+			TestConn(t, mp)
+		})
+	}
+}
diff --git a/src/vendor/golang_org/x/net/proxy/direct.go b/src/vendor/golang_org/x/net/proxy/direct.go
new file mode 100644
index 0000000..4c5ad88
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/direct.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+	"net"
+)
+
+type direct struct{}
+
+// Direct is a direct proxy: one that makes network connections directly.
+var Direct = direct{}
+
+func (direct) Dial(network, addr string) (net.Conn, error) {
+	return net.Dial(network, addr)
+}
diff --git a/src/vendor/golang_org/x/net/proxy/per_host.go b/src/vendor/golang_org/x/net/proxy/per_host.go
new file mode 100644
index 0000000..f540b19
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/per_host.go
@@ -0,0 +1,140 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+	"net"
+	"strings"
+)
+
+// A PerHost directs connections to a default Dialer unless the hostname
+// requested matches one of a number of exceptions.
+type PerHost struct {
+	def, bypass Dialer
+
+	bypassNetworks []*net.IPNet
+	bypassIPs      []net.IP
+	bypassZones    []string
+	bypassHosts    []string
+}
+
+// NewPerHost returns a PerHost Dialer that directs connections to either
+// defaultDialer or bypass, depending on whether the connection matches one of
+// the configured rules.
+func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
+	return &PerHost{
+		def:    defaultDialer,
+		bypass: bypass,
+	}
+}
+
+// Dial connects to the address addr on the given network through either
+// defaultDialer or bypass.
+func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
+	host, _, err := net.SplitHostPort(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return p.dialerForRequest(host).Dial(network, addr)
+}
+
+func (p *PerHost) dialerForRequest(host string) Dialer {
+	if ip := net.ParseIP(host); ip != nil {
+		for _, net := range p.bypassNetworks {
+			if net.Contains(ip) {
+				return p.bypass
+			}
+		}
+		for _, bypassIP := range p.bypassIPs {
+			if bypassIP.Equal(ip) {
+				return p.bypass
+			}
+		}
+		return p.def
+	}
+
+	for _, zone := range p.bypassZones {
+		if strings.HasSuffix(host, zone) {
+			return p.bypass
+		}
+		if host == zone[1:] {
+			// For a zone "example.com", we match "example.com"
+			// too.
+			return p.bypass
+		}
+	}
+	for _, bypassHost := range p.bypassHosts {
+		if bypassHost == host {
+			return p.bypass
+		}
+	}
+	return p.def
+}
+
+// AddFromString parses a string that contains comma-separated values
+// specifying hosts that should use the bypass proxy. Each value is either an
+// IP address, a CIDR range, a zone (*.example.com) or a hostname
+// (localhost). A best effort is made to parse the string and errors are
+// ignored.
+func (p *PerHost) AddFromString(s string) {
+	hosts := strings.Split(s, ",")
+	for _, host := range hosts {
+		host = strings.TrimSpace(host)
+		if len(host) == 0 {
+			continue
+		}
+		if strings.Contains(host, "/") {
+			// We assume that it's a CIDR address like 127.0.0.0/8
+			if _, net, err := net.ParseCIDR(host); err == nil {
+				p.AddNetwork(net)
+			}
+			continue
+		}
+		if ip := net.ParseIP(host); ip != nil {
+			p.AddIP(ip)
+			continue
+		}
+		if strings.HasPrefix(host, "*.") {
+			p.AddZone(host[1:])
+			continue
+		}
+		p.AddHost(host)
+	}
+}
+
+// AddIP specifies an IP address that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match an IP.
+func (p *PerHost) AddIP(ip net.IP) {
+	p.bypassIPs = append(p.bypassIPs, ip)
+}
+
+// AddNetwork specifies an IP range that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match.
+func (p *PerHost) AddNetwork(net *net.IPNet) {
+	p.bypassNetworks = append(p.bypassNetworks, net)
+}
+
+// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
+// "example.com" matches "example.com" and all of its subdomains.
+func (p *PerHost) AddZone(zone string) {
+	if strings.HasSuffix(zone, ".") {
+		zone = zone[:len(zone)-1]
+	}
+	if !strings.HasPrefix(zone, ".") {
+		zone = "." + zone
+	}
+	p.bypassZones = append(p.bypassZones, zone)
+}
+
+// AddHost specifies a hostname that will use the bypass proxy.
+func (p *PerHost) AddHost(host string) {
+	if strings.HasSuffix(host, ".") {
+		host = host[:len(host)-1]
+	}
+	p.bypassHosts = append(p.bypassHosts, host)
+}
diff --git a/src/vendor/golang_org/x/net/proxy/per_host_test.go b/src/vendor/golang_org/x/net/proxy/per_host_test.go
new file mode 100644
index 0000000..a7d8095
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/per_host_test.go
@@ -0,0 +1,55 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+	"errors"
+	"net"
+	"reflect"
+	"testing"
+)
+
+type recordingProxy struct {
+	addrs []string
+}
+
+func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) {
+	r.addrs = append(r.addrs, addr)
+	return nil, errors.New("recordingProxy")
+}
+
+func TestPerHost(t *testing.T) {
+	var def, bypass recordingProxy
+	perHost := NewPerHost(&def, &bypass)
+	perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16")
+
+	expectedDef := []string{
+		"example.com:123",
+		"1.2.3.4:123",
+		"[1001::]:123",
+	}
+	expectedBypass := []string{
+		"localhost:123",
+		"zone:123",
+		"foo.zone:123",
+		"127.0.0.1:123",
+		"10.1.2.3:123",
+		"[1000::]:123",
+	}
+
+	for _, addr := range expectedDef {
+		perHost.Dial("tcp", addr)
+	}
+	for _, addr := range expectedBypass {
+		perHost.Dial("tcp", addr)
+	}
+
+	if !reflect.DeepEqual(expectedDef, def.addrs) {
+		t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef)
+	}
+	if !reflect.DeepEqual(expectedBypass, bypass.addrs) {
+		t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass)
+	}
+}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy.go b/src/vendor/golang_org/x/net/proxy/proxy.go
new file mode 100644
index 0000000..78a8b7b
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/proxy.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package proxy provides support for a variety of protocols to proxy network
+// data.
+package proxy // import "golang.org/x/net/proxy"
+
+import (
+	"errors"
+	"net"
+	"net/url"
+	"os"
+)
+
+// A Dialer is a means to establish a connection.
+type Dialer interface {
+	// Dial connects to the given address via the proxy.
+	Dial(network, addr string) (c net.Conn, err error)
+}
+
+// Auth contains authentication parameters that specific Dialers may require.
+type Auth struct {
+	User, Password string
+}
+
+// FromEnvironment returns the dialer specified by the proxy related variables in
+// the environment.
+func FromEnvironment() Dialer {
+	allProxy := os.Getenv("all_proxy")
+	if len(allProxy) == 0 {
+		return Direct
+	}
+
+	proxyURL, err := url.Parse(allProxy)
+	if err != nil {
+		return Direct
+	}
+	proxy, err := FromURL(proxyURL, Direct)
+	if err != nil {
+		return Direct
+	}
+
+	noProxy := os.Getenv("no_proxy")
+	if len(noProxy) == 0 {
+		return proxy
+	}
+
+	perHost := NewPerHost(proxy, Direct)
+	perHost.AddFromString(noProxy)
+	return perHost
+}
+
+// proxySchemes is a map from URL schemes to a function that creates a Dialer
+// from a URL with such a scheme.
+var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
+
+// RegisterDialerType takes a URL scheme and a function to generate Dialers from
+// a URL with that scheme and a forwarding Dialer. Registered schemes are used
+// by FromURL.
+func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
+	if proxySchemes == nil {
+		proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
+	}
+	proxySchemes[scheme] = f
+}
+
+// FromURL returns a Dialer given a URL specification and an underlying
+// Dialer for it to make network requests.
+func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
+	var auth *Auth
+	if u.User != nil {
+		auth = new(Auth)
+		auth.User = u.User.Username()
+		if p, ok := u.User.Password(); ok {
+			auth.Password = p
+		}
+	}
+
+	switch u.Scheme {
+	case "socks5":
+		return SOCKS5("tcp", u.Host, auth, forward)
+	}
+
+	// If the scheme doesn't match any of the built-in schemes, see if it
+	// was registered by another package.
+	if proxySchemes != nil {
+		if f, ok := proxySchemes[u.Scheme]; ok {
+			return f(u, forward)
+		}
+	}
+
+	return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
+}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy_test.go b/src/vendor/golang_org/x/net/proxy/proxy_test.go
new file mode 100644
index 0000000..c19a5c0
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/proxy_test.go
@@ -0,0 +1,142 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+	"io"
+	"net"
+	"net/url"
+	"strconv"
+	"sync"
+	"testing"
+)
+
+func TestFromURL(t *testing.T) {
+	endSystem, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("net.Listen failed: %v", err)
+	}
+	defer endSystem.Close()
+	gateway, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("net.Listen failed: %v", err)
+	}
+	defer gateway.Close()
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go socks5Gateway(t, gateway, endSystem, socks5Domain, &wg)
+
+	url, err := url.Parse("socks5://user:password@" + gateway.Addr().String())
+	if err != nil {
+		t.Fatalf("url.Parse failed: %v", err)
+	}
+	proxy, err := FromURL(url, Direct)
+	if err != nil {
+		t.Fatalf("FromURL failed: %v", err)
+	}
+	_, port, err := net.SplitHostPort(endSystem.Addr().String())
+	if err != nil {
+		t.Fatalf("net.SplitHostPort failed: %v", err)
+	}
+	if c, err := proxy.Dial("tcp", "localhost:"+port); err != nil {
+		t.Fatalf("FromURL.Dial failed: %v", err)
+	} else {
+		c.Close()
+	}
+
+	wg.Wait()
+}
+
+func TestSOCKS5(t *testing.T) {
+	endSystem, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("net.Listen failed: %v", err)
+	}
+	defer endSystem.Close()
+	gateway, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("net.Listen failed: %v", err)
+	}
+	defer gateway.Close()
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go socks5Gateway(t, gateway, endSystem, socks5IP4, &wg)
+
+	proxy, err := SOCKS5("tcp", gateway.Addr().String(), nil, Direct)
+	if err != nil {
+		t.Fatalf("SOCKS5 failed: %v", err)
+	}
+	if c, err := proxy.Dial("tcp", endSystem.Addr().String()); err != nil {
+		t.Fatalf("SOCKS5.Dial failed: %v", err)
+	} else {
+		c.Close()
+	}
+
+	wg.Wait()
+}
+
+func socks5Gateway(t *testing.T, gateway, endSystem net.Listener, typ byte, wg *sync.WaitGroup) {
+	defer wg.Done()
+
+	c, err := gateway.Accept()
+	if err != nil {
+		t.Errorf("net.Listener.Accept failed: %v", err)
+		return
+	}
+	defer c.Close()
+
+	b := make([]byte, 32)
+	var n int
+	if typ == socks5Domain {
+		n = 4
+	} else {
+		n = 3
+	}
+	if _, err := io.ReadFull(c, b[:n]); err != nil {
+		t.Errorf("io.ReadFull failed: %v", err)
+		return
+	}
+	if _, err := c.Write([]byte{socks5Version, socks5AuthNone}); err != nil {
+		t.Errorf("net.Conn.Write failed: %v", err)
+		return
+	}
+	if typ == socks5Domain {
+		n = 16
+	} else {
+		n = 10
+	}
+	if _, err := io.ReadFull(c, b[:n]); err != nil {
+		t.Errorf("io.ReadFull failed: %v", err)
+		return
+	}
+	if b[0] != socks5Version || b[1] != socks5Connect || b[2] != 0x00 || b[3] != typ {
+		t.Errorf("got an unexpected packet: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3])
+		return
+	}
+	if typ == socks5Domain {
+		copy(b[:5], []byte{socks5Version, 0x00, 0x00, socks5Domain, 9})
+		b = append(b, []byte("localhost")...)
+	} else {
+		copy(b[:4], []byte{socks5Version, 0x00, 0x00, socks5IP4})
+	}
+	host, port, err := net.SplitHostPort(endSystem.Addr().String())
+	if err != nil {
+		t.Errorf("net.SplitHostPort failed: %v", err)
+		return
+	}
+	b = append(b, []byte(net.ParseIP(host).To4())...)
+	p, err := strconv.Atoi(port)
+	if err != nil {
+		t.Errorf("strconv.Atoi failed: %v", err)
+		return
+	}
+	b = append(b, []byte{byte(p >> 8), byte(p)}...)
+	if _, err := c.Write(b); err != nil {
+		t.Errorf("net.Conn.Write failed: %v", err)
+		return
+	}
+}
diff --git a/src/vendor/golang_org/x/net/proxy/socks5.go b/src/vendor/golang_org/x/net/proxy/socks5.go
new file mode 100644
index 0000000..973f57f
--- /dev/null
+++ b/src/vendor/golang_org/x/net/proxy/socks5.go
@@ -0,0 +1,213 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proxy
+
+import (
+	"errors"
+	"io"
+	"net"
+	"strconv"
+)
+
+// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
+// with an optional username and password. See RFC 1928.
+func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
+	s := &socks5{
+		network: network,
+		addr:    addr,
+		forward: forward,
+	}
+	if auth != nil {
+		s.user = auth.User
+		s.password = auth.Password
+	}
+
+	return s, nil
+}
+
+type socks5 struct {
+	user, password string
+	network, addr  string
+	forward        Dialer
+}
+
+const socks5Version = 5
+
+const (
+	socks5AuthNone     = 0
+	socks5AuthPassword = 2
+)
+
+const socks5Connect = 1
+
+const (
+	socks5IP4    = 1
+	socks5Domain = 3
+	socks5IP6    = 4
+)
+
+var socks5Errors = []string{
+	"",
+	"general failure",
+	"connection forbidden",
+	"network unreachable",
+	"host unreachable",
+	"connection refused",
+	"TTL expired",
+	"command not supported",
+	"address type not supported",
+}
+
+// Dial connects to the address addr on the network net via the SOCKS5 proxy.
+func (s *socks5) Dial(network, addr string) (net.Conn, error) {
+	switch network {
+	case "tcp", "tcp6", "tcp4":
+	default:
+		return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
+	}
+
+	conn, err := s.forward.Dial(s.network, s.addr)
+	if err != nil {
+		return nil, err
+	}
+	if err := s.connect(conn, addr); err != nil {
+		conn.Close()
+		return nil, err
+	}
+	return conn, nil
+}
+
+// connect takes an existing connection to a socks5 proxy server,
+// and commands the server to extend that connection to target,
+// which must be a canonical address with a host and port.
+func (s *socks5) connect(conn net.Conn, target string) error {
+	host, portStr, err := net.SplitHostPort(target)
+	if err != nil {
+		return err
+	}
+
+	port, err := strconv.Atoi(portStr)
+	if err != nil {
+		return errors.New("proxy: failed to parse port number: " + portStr)
+	}
+	if port < 1 || port > 0xffff {
+		return errors.New("proxy: port number out of range: " + portStr)
+	}
+
+	// the size here is just an estimate
+	buf := make([]byte, 0, 6+len(host))
+
+	buf = append(buf, socks5Version)
+	if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
+		buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
+	} else {
+		buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
+	}
+
+	if _, err := conn.Write(buf); err != nil {
+		return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+
+	if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+		return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+	if buf[0] != 5 {
+		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
+	}
+	if buf[1] == 0xff {
+		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
+	}
+
+	if buf[1] == socks5AuthPassword {
+		buf = buf[:0]
+		buf = append(buf, 1 /* password protocol version */)
+		buf = append(buf, uint8(len(s.user)))
+		buf = append(buf, s.user...)
+		buf = append(buf, uint8(len(s.password)))
+		buf = append(buf, s.password...)
+
+		if _, err := conn.Write(buf); err != nil {
+			return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+		}
+
+		if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+			return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+		}
+
+		if buf[1] != 0 {
+			return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
+		}
+	}
+
+	buf = buf[:0]
+	buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
+
+	if ip := net.ParseIP(host); ip != nil {
+		if ip4 := ip.To4(); ip4 != nil {
+			buf = append(buf, socks5IP4)
+			ip = ip4
+		} else {
+			buf = append(buf, socks5IP6)
+		}
+		buf = append(buf, ip...)
+	} else {
+		if len(host) > 255 {
+			return errors.New("proxy: destination hostname too long: " + host)
+		}
+		buf = append(buf, socks5Domain)
+		buf = append(buf, byte(len(host)))
+		buf = append(buf, host...)
+	}
+	buf = append(buf, byte(port>>8), byte(port))
+
+	if _, err := conn.Write(buf); err != nil {
+		return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+
+	if _, err := io.ReadFull(conn, buf[:4]); err != nil {
+		return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+
+	failure := "unknown error"
+	if int(buf[1]) < len(socks5Errors) {
+		failure = socks5Errors[buf[1]]
+	}
+
+	if len(failure) > 0 {
+		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
+	}
+
+	bytesToDiscard := 0
+	switch buf[3] {
+	case socks5IP4:
+		bytesToDiscard = net.IPv4len
+	case socks5IP6:
+		bytesToDiscard = net.IPv6len
+	case socks5Domain:
+		_, err := io.ReadFull(conn, buf[:1])
+		if err != nil {
+			return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+		}
+		bytesToDiscard = int(buf[0])
+	default:
+		return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
+	}
+
+	if cap(buf) < bytesToDiscard {
+		buf = make([]byte, bytesToDiscard)
+	} else {
+		buf = buf[:bytesToDiscard]
+	}
+	if _, err := io.ReadFull(conn, buf); err != nil {
+		return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+
+	// Also need to discard the port number
+	if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+		return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+	}
+
+	return nil
+}
diff --git a/src/vendor/golang_org/x/net/route/address.go b/src/vendor/golang_org/x/net/route/address.go
index a56909c..e6bfa39 100644
--- a/src/vendor/golang_org/x/net/route/address.go
+++ b/src/vendor/golang_org/x/net/route/address.go
@@ -24,6 +24,39 @@ type LinkAddr struct {
 // Family implements the Family method of Addr interface.
 func (a *LinkAddr) Family() int { return sysAF_LINK }
 
+func (a *LinkAddr) lenAndSpace() (int, int) {
+	l := 8 + len(a.Name) + len(a.Addr)
+	return l, roundup(l)
+}
+
+func (a *LinkAddr) marshal(b []byte) (int, error) {
+	l, ll := a.lenAndSpace()
+	if len(b) < ll {
+		return 0, errShortBuffer
+	}
+	nlen, alen := len(a.Name), len(a.Addr)
+	if nlen > 255 || alen > 255 {
+		return 0, errInvalidAddr
+	}
+	b[0] = byte(l)
+	b[1] = sysAF_LINK
+	if a.Index > 0 {
+		nativeEndian.PutUint16(b[2:4], uint16(a.Index))
+	}
+	data := b[8:]
+	if nlen > 0 {
+		b[5] = byte(nlen)
+		copy(data[:nlen], a.Addr)
+		data = data[nlen:]
+	}
+	if alen > 0 {
+		b[6] = byte(alen)
+		copy(data[:alen], a.Name)
+		data = data[alen:]
+	}
+	return ll, nil
+}
+
 func parseLinkAddr(b []byte) (Addr, error) {
 	if len(b) < 8 {
 		return nil, errInvalidAddr
@@ -90,6 +123,21 @@ type Inet4Addr struct {
 // Family implements the Family method of Addr interface.
 func (a *Inet4Addr) Family() int { return sysAF_INET }
 
+func (a *Inet4Addr) lenAndSpace() (int, int) {
+	return sizeofSockaddrInet, roundup(sizeofSockaddrInet)
+}
+
+func (a *Inet4Addr) marshal(b []byte) (int, error) {
+	l, ll := a.lenAndSpace()
+	if len(b) < ll {
+		return 0, errShortBuffer
+	}
+	b[0] = byte(l)
+	b[1] = sysAF_INET
+	copy(b[4:8], a.IP[:])
+	return ll, nil
+}
+
 // An Inet6Addr represents an internet address for IPv6.
 type Inet6Addr struct {
 	IP     [16]byte // IP address
@@ -99,18 +147,36 @@ type Inet6Addr struct {
 // Family implements the Family method of Addr interface.
 func (a *Inet6Addr) Family() int { return sysAF_INET6 }
 
+func (a *Inet6Addr) lenAndSpace() (int, int) {
+	return sizeofSockaddrInet6, roundup(sizeofSockaddrInet6)
+}
+
+func (a *Inet6Addr) marshal(b []byte) (int, error) {
+	l, ll := a.lenAndSpace()
+	if len(b) < ll {
+		return 0, errShortBuffer
+	}
+	b[0] = byte(l)
+	b[1] = sysAF_INET6
+	copy(b[8:24], a.IP[:])
+	if a.ZoneID > 0 {
+		nativeEndian.PutUint32(b[24:28], uint32(a.ZoneID))
+	}
+	return ll, nil
+}
+
 // 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 {
+		if len(b) < sizeofSockaddrInet {
 			return nil, errInvalidAddr
 		}
 		a := &Inet4Addr{}
 		copy(a.IP[:], b[4:8])
 		return a, nil
 	case sysAF_INET6:
-		if len(b) < 28 {
+		if len(b) < sizeofSockaddrInet6 {
 			return nil, errInvalidAddr
 		}
 		a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
@@ -174,7 +240,7 @@ func parseKernelInetAddr(af int, b []byte) (int, Addr, error) {
 		off6 = 8 // offset of in6_addr
 	)
 	switch {
-	case b[0] == 28: // size of sockaddr_in6
+	case b[0] == sizeofSockaddrInet6:
 		a := &Inet6Addr{}
 		copy(a.IP[:], b[off6:off6+16])
 		return int(b[0]), a, nil
@@ -186,7 +252,7 @@ func parseKernelInetAddr(af int, b []byte) (int, Addr, error) {
 			copy(a.IP[:], b[l-off6:l])
 		}
 		return int(b[0]), a, nil
-	case b[0] == 16: // size of sockaddr_in
+	case b[0] == sizeofSockaddrInet:
 		a := &Inet4Addr{}
 		copy(a.IP[:], b[off4:off4+4])
 		return int(b[0]), a, nil
@@ -211,6 +277,24 @@ type DefaultAddr struct {
 // Family implements the Family method of Addr interface.
 func (a *DefaultAddr) Family() int { return a.af }
 
+func (a *DefaultAddr) lenAndSpace() (int, int) {
+	l := len(a.Raw)
+	return l, roundup(l)
+}
+
+func (a *DefaultAddr) marshal(b []byte) (int, error) {
+	l, ll := a.lenAndSpace()
+	if len(b) < ll {
+		return 0, errShortBuffer
+	}
+	if l > 255 {
+		return 0, errInvalidAddr
+	}
+	b[1] = byte(l)
+	copy(b[:l], a.Raw)
+	return ll, nil
+}
+
 func parseDefaultAddr(b []byte) (Addr, error) {
 	if len(b) < 2 || len(b) < int(b[0]) {
 		return nil, errInvalidAddr
@@ -219,6 +303,66 @@ func parseDefaultAddr(b []byte) (Addr, error) {
 	return a, nil
 }
 
+func addrsSpace(as []Addr) int {
+	var l int
+	for _, a := range as {
+		switch a := a.(type) {
+		case *LinkAddr:
+			_, ll := a.lenAndSpace()
+			l += ll
+		case *Inet4Addr:
+			_, ll := a.lenAndSpace()
+			l += ll
+		case *Inet6Addr:
+			_, ll := a.lenAndSpace()
+			l += ll
+		case *DefaultAddr:
+			_, ll := a.lenAndSpace()
+			l += ll
+		}
+	}
+	return l
+}
+
+// marshalAddrs marshals as and returns a bitmap indicating which
+// address is stored in b.
+func marshalAddrs(b []byte, as []Addr) (uint, error) {
+	var attrs uint
+	for i, a := range as {
+		switch a := a.(type) {
+		case *LinkAddr:
+			l, err := a.marshal(b)
+			if err != nil {
+				return 0, err
+			}
+			b = b[l:]
+			attrs |= 1 << uint(i)
+		case *Inet4Addr:
+			l, err := a.marshal(b)
+			if err != nil {
+				return 0, err
+			}
+			b = b[l:]
+			attrs |= 1 << uint(i)
+		case *Inet6Addr:
+			l, err := a.marshal(b)
+			if err != nil {
+				return 0, err
+			}
+			b = b[l:]
+			attrs |= 1 << uint(i)
+		case *DefaultAddr:
+			l, err := a.marshal(b)
+			if err != nil {
+				return 0, err
+			}
+			b = b[l:]
+			attrs |= 1 << uint(i)
+		}
+	}
+	return attrs, 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)
diff --git a/src/vendor/golang_org/x/net/route/binary.go b/src/vendor/golang_org/x/net/route/binary.go
index 4c56163..6910520 100644
--- a/src/vendor/golang_org/x/net/route/binary.go
+++ b/src/vendor/golang_org/x/net/route/binary.go
@@ -9,7 +9,7 @@ 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
+// library. Therefore the package set used in the package must be the
 // same as net package.
 
 var (
diff --git a/src/vendor/golang_org/x/net/route/defs_darwin.go b/src/vendor/golang_org/x/net/route/defs_darwin.go
index f452ad1..e771644 100644
--- a/src/vendor/golang_org/x/net/route/defs_darwin.go
+++ b/src/vendor/golang_org/x/net/route/defs_darwin.go
@@ -13,6 +13,8 @@ package route
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/route.h>
+
+#include <netinet/in.h>
 */
 import "C"
 
@@ -23,6 +25,8 @@ const (
 	sysAF_LINK   = C.AF_LINK
 	sysAF_INET6  = C.AF_INET6
 
+	sysSOCK_RAW = C.SOCK_RAW
+
 	sysNET_RT_DUMP    = C.NET_RT_DUMP
 	sysNET_RT_FLAGS   = C.NET_RT_FLAGS
 	sysNET_RT_IFLIST  = C.NET_RT_IFLIST
@@ -103,4 +107,8 @@ const (
 	sizeofRtMsghdrDarwin15  = C.sizeof_struct_rt_msghdr
 	sizeofRtMsghdr2Darwin15 = C.sizeof_struct_rt_msghdr2
 	sizeofRtMetricsDarwin15 = C.sizeof_struct_rt_metrics
+
+	sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+	sizeofSockaddrInet    = C.sizeof_struct_sockaddr_in
+	sizeofSockaddrInet6   = C.sizeof_struct_sockaddr_in6
 )
diff --git a/src/vendor/golang_org/x/net/route/defs_dragonfly.go b/src/vendor/golang_org/x/net/route/defs_dragonfly.go
index c737751..dd31de2 100644
--- a/src/vendor/golang_org/x/net/route/defs_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/defs_dragonfly.go
@@ -13,6 +13,8 @@ package route
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/route.h>
+
+#include <netinet/in.h>
 */
 import "C"
 
@@ -23,6 +25,8 @@ const (
 	sysAF_LINK   = C.AF_LINK
 	sysAF_INET6  = C.AF_INET6
 
+	sysSOCK_RAW = C.SOCK_RAW
+
 	sysNET_RT_DUMP   = C.NET_RT_DUMP
 	sysNET_RT_FLAGS  = C.NET_RT_FLAGS
 	sysNET_RT_IFLIST = C.NET_RT_IFLIST
@@ -102,4 +106,8 @@ const (
 
 	sizeofRtMsghdrDragonFlyBSD4  = C.sizeof_struct_rt_msghdr
 	sizeofRtMetricsDragonFlyBSD4 = C.sizeof_struct_rt_metrics
+
+	sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+	sizeofSockaddrInet    = C.sizeof_struct_sockaddr_in
+	sizeofSockaddrInet6   = C.sizeof_struct_sockaddr_in6
 )
diff --git a/src/vendor/golang_org/x/net/route/defs_freebsd.go b/src/vendor/golang_org/x/net/route/defs_freebsd.go
index 8f834e8..d95594d 100644
--- a/src/vendor/golang_org/x/net/route/defs_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_freebsd.go
@@ -14,6 +14,8 @@ package route
 #include <net/if_dl.h>
 #include <net/route.h>
 
+#include <netinet/in.h>
+
 struct if_data_freebsd7 {
 	u_char ifi_type;
 	u_char ifi_physical;
@@ -222,6 +224,8 @@ const (
 	sysAF_LINK   = C.AF_LINK
 	sysAF_INET6  = C.AF_INET6
 
+	sysSOCK_RAW = C.SOCK_RAW
+
 	sysNET_RT_DUMP     = C.NET_RT_DUMP
 	sysNET_RT_FLAGS    = C.NET_RT_FLAGS
 	sysNET_RT_IFLIST   = C.NET_RT_IFLIST
@@ -326,4 +330,8 @@ const (
 	sizeofIfDataFreeBSD9Emu  = C.sizeof_struct_if_data_freebsd9
 	sizeofIfDataFreeBSD10Emu = C.sizeof_struct_if_data_freebsd10
 	sizeofIfDataFreeBSD11Emu = C.sizeof_struct_if_data_freebsd11
+
+	sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+	sizeofSockaddrInet    = C.sizeof_struct_sockaddr_in
+	sizeofSockaddrInet6   = C.sizeof_struct_sockaddr_in6
 )
diff --git a/src/vendor/golang_org/x/net/route/defs_netbsd.go b/src/vendor/golang_org/x/net/route/defs_netbsd.go
index b18d85e..b0abd54 100644
--- a/src/vendor/golang_org/x/net/route/defs_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_netbsd.go
@@ -13,6 +13,8 @@ package route
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/route.h>
+
+#include <netinet/in.h>
 */
 import "C"
 
@@ -23,6 +25,8 @@ const (
 	sysAF_LINK   = C.AF_LINK
 	sysAF_INET6  = C.AF_INET6
 
+	sysSOCK_RAW = C.SOCK_RAW
+
 	sysNET_RT_DUMP   = C.NET_RT_DUMP
 	sysNET_RT_FLAGS  = C.NET_RT_FLAGS
 	sysNET_RT_IFLIST = C.NET_RT_IFLIST
@@ -101,4 +105,8 @@ const (
 
 	sizeofRtMsghdrNetBSD7  = C.sizeof_struct_rt_msghdr
 	sizeofRtMetricsNetBSD7 = C.sizeof_struct_rt_metrics
+
+	sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+	sizeofSockaddrInet    = C.sizeof_struct_sockaddr_in
+	sizeofSockaddrInet6   = C.sizeof_struct_sockaddr_in6
 )
diff --git a/src/vendor/golang_org/x/net/route/defs_openbsd.go b/src/vendor/golang_org/x/net/route/defs_openbsd.go
index 5df7a43..0f66d36 100644
--- a/src/vendor/golang_org/x/net/route/defs_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/defs_openbsd.go
@@ -13,6 +13,8 @@ package route
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/route.h>
+
+#include <netinet/in.h>
 */
 import "C"
 
@@ -23,6 +25,8 @@ const (
 	sysAF_LINK   = C.AF_LINK
 	sysAF_INET6  = C.AF_INET6
 
+	sysSOCK_RAW = C.SOCK_RAW
+
 	sysNET_RT_DUMP    = C.NET_RT_DUMP
 	sysNET_RT_FLAGS   = C.NET_RT_FLAGS
 	sysNET_RT_IFLIST  = C.NET_RT_IFLIST
@@ -91,3 +95,11 @@ const (
 	sysRTAX_LABEL   = C.RTAX_LABEL
 	sysRTAX_MAX     = C.RTAX_MAX
 )
+
+const (
+	sizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+
+	sizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage
+	sizeofSockaddrInet    = C.sizeof_struct_sockaddr_in
+	sizeofSockaddrInet6   = C.sizeof_struct_sockaddr_in6
+)
diff --git a/src/vendor/golang_org/x/net/route/message.go b/src/vendor/golang_org/x/net/route/message.go
index d7ae0eb..0fa7e09 100644
--- a/src/vendor/golang_org/x/net/route/message.go
+++ b/src/vendor/golang_org/x/net/route/message.go
@@ -7,9 +7,6 @@
 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
@@ -52,11 +49,10 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
 			b = b[l:]
 			continue
 		}
-		mtyp := int(b[3])
-		if fn, ok := parseFns[mtyp]; !ok {
+		if w, ok := wireFormats[int(b[3])]; !ok {
 			nskips++
 		} else {
-			m, err := fn(typ, b)
+			m, err := w.parse(typ, b)
 			if err != nil {
 				return nil, err
 			}
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
index 3fdd12d..316aa75 100644
--- a/src/vendor/golang_org/x/net/route/message_darwin_test.go
+++ b/src/vendor/golang_org/x/net/route/message_darwin_test.go
@@ -7,21 +7,28 @@ 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)
+	for _, typ := range []RIBType{sysNET_RT_FLAGS, sysNET_RT_DUMP2, sysNET_RT_IFLIST2} {
+		var lastErr error
+		var ms []Message
+		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+			rs, err := fetchAndParseRIB(af, typ)
 			if err != nil {
-				t.Error(err)
+				lastErr = 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)
-			}
+			ms = append(ms, rs...)
+		}
+		if len(ms) == 0 && lastErr != nil {
+			t.Error(typ, lastErr)
+			continue
+		}
+		ss, err := msgs(ms).validate()
+		if err != nil {
+			t.Error(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
index 785c273..db4b567 100644
--- a/src/vendor/golang_org/x/net/route/message_freebsd_test.go
+++ b/src/vendor/golang_org/x/net/route/message_freebsd_test.go
@@ -6,26 +6,32 @@ 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()
+	for _, typ := range []RIBType{sysNET_RT_IFMALIST} {
+		var lastErr error
+		var ms []Message
+		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+			rs, err := fetchAndParseRIB(af, typ)
 			if err != nil {
-				t.Errorf("%v %d %v", addrFamily(af), typ, err)
+				lastErr = err
 				continue
 			}
-			for _, s := range ss {
-				t.Log(s)
-			}
+			ms = append(ms, rs...)
+		}
+		if len(ms) == 0 && lastErr != nil {
+			t.Error(typ, lastErr)
+			continue
+		}
+		ss, err := msgs(ms).validate()
+		if err != nil {
+			t.Error(typ, err)
+			continue
+		}
+		for _, s := range ss {
+			t.Log(s)
 		}
 	}
 }
@@ -48,58 +54,38 @@ func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) {
 		{typ: sysNET_RT_IFLIST},
 		{typ: sysNET_RT_IFLISTL},
 	}
-	for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+	for i := range tests {
 		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
+		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+			rs, err := fetchAndParseRIB(af, tests[i].typ)
+			if err != nil {
+				lastErr = err
+				continue
 			}
+			tests[i].msgs = append(tests[i].msgs, rs...)
 		}
-		if lastErr != nil {
-			t.Error(af, lastErr)
+		if len(tests[i].msgs) == 0 && lastErr != nil {
+			t.Error(tests[i].typ, 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)
-			}
-		}
+		tests[i].ss, lastErr = msgs(tests[i].msgs).validate()
 		if lastErr != nil {
+			t.Error(tests[i].typ, lastErr)
 			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)
-			}
+		for _, s := range tests[i].ss {
+			t.Log(s)
 		}
-		if lastErr != nil {
+	}
+	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 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)
-				}
+		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
index c0c7c57..e848dab 100644
--- a/src/vendor/golang_org/x/net/route/message_test.go
+++ b/src/vendor/golang_org/x/net/route/message_test.go
@@ -14,30 +14,54 @@ import (
 )
 
 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)
+	for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} {
+		var lastErr error
+		var ms []Message
+		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+			rs, 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)
+				lastErr = err
 				continue
 			}
-			for _, s := range ss {
-				t.Log(s)
-			}
+			ms = append(ms, rs...)
+		}
+		if len(ms) == 0 && lastErr != nil {
+			t.Error(typ, lastErr)
+			continue
+		}
+		ss, err := msgs(ms).validate()
+		if err != nil {
+			t.Error(typ, err)
+			continue
+		}
+		for _, s := range ss {
+			t.Log(typ, s)
 		}
 	}
 }
 
+var (
+	rtmonSock int
+	rtmonErr  error
+)
+
+func init() {
+	// We need to keep rtmonSock alive to avoid treading on
+	// recycled socket descriptors.
+	rtmonSock, rtmonErr = syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
+}
+
+// TestMonitorAndParseRIB leaks a worker goroutine and a socket
+// descriptor but that's intentional.
 func TestMonitorAndParseRIB(t *testing.T) {
 	if testing.Short() || os.Getuid() != 0 {
 		t.Skip("must be root")
 	}
 
+	if rtmonErr != nil {
+		t.Fatal(rtmonErr)
+	}
+
 	// 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"}
@@ -49,16 +73,18 @@ func TestMonitorAndParseRIB(t *testing.T) {
 	}
 	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)
+			// There's no easy way to unblock this read
+			// call because the routing message exchange
+			// over routing socket is a connectionless
+			// message-oriented protocol, no control plane
+			// for signaling connectivity, and we cannot
+			// use the net package of standard library due
+			// to the lack of support for routing socket
+			// and circular dependency.
+			n, err := syscall.Read(rtmonSock, b)
 			if err != nil {
 				return
 			}
@@ -116,3 +142,98 @@ func TestParseRIBWithFuzz(t *testing.T) {
 		}
 	}
 }
+
+func TestRouteMessage(t *testing.T) {
+	s, err := syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer syscall.Close(s)
+
+	var ms []RouteMessage
+	for _, af := range []int{sysAF_INET, sysAF_INET6} {
+		if _, err := fetchAndParseRIB(af, sysNET_RT_DUMP); err != nil {
+			t.Log(err)
+			continue
+		}
+		switch af {
+		case sysAF_INET:
+			ms = append(ms, []RouteMessage{
+				{
+					Type: sysRTM_GET,
+					Addrs: []Addr{
+						&Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
+						nil,
+						nil,
+						nil,
+						&LinkAddr{},
+						&Inet4Addr{},
+						nil,
+						&Inet4Addr{},
+					},
+				},
+				{
+					Type: sysRTM_GET,
+					Addrs: []Addr{
+						&Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
+					},
+				},
+			}...)
+		case sysAF_INET6:
+			ms = append(ms, []RouteMessage{
+				{
+					Type: sysRTM_GET,
+					Addrs: []Addr{
+						&Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
+						nil,
+						nil,
+						nil,
+						&LinkAddr{},
+						&Inet6Addr{},
+						nil,
+						&Inet6Addr{},
+					},
+				},
+				{
+					Type: sysRTM_GET,
+					Addrs: []Addr{
+						&Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
+					},
+				},
+			}...)
+		}
+	}
+	for i, m := range ms {
+		m.ID = uintptr(os.Getpid())
+		m.Seq = i + 1
+		wb, err := m.Marshal()
+		if err != nil {
+			t.Fatalf("%v: %v", m, err)
+		}
+		if _, err := syscall.Write(s, wb); err != nil {
+			t.Fatalf("%v: %v", m, err)
+		}
+		rb := make([]byte, os.Getpagesize())
+		n, err := syscall.Read(s, rb)
+		if err != nil {
+			t.Fatalf("%v: %v", m, err)
+		}
+		rms, err := ParseRIB(0, rb[:n])
+		if err != nil {
+			t.Fatalf("%v: %v", m, err)
+		}
+		for _, rm := range rms {
+			err := rm.(*RouteMessage).Err
+			if err != nil {
+				t.Errorf("%v: %v", m, err)
+			}
+		}
+		ss, err := msgs(rms).validate()
+		if err != nil {
+			t.Fatalf("%v: %v", m, err)
+		}
+		for _, s := range ss {
+			t.Log(s)
+		}
+	}
+}
diff --git a/src/vendor/golang_org/x/net/route/route.go b/src/vendor/golang_org/x/net/route/route.go
index c986e29..081da0d 100644
--- a/src/vendor/golang_org/x/net/route/route.go
+++ b/src/vendor/golang_org/x/net/route/route.go
@@ -24,21 +24,70 @@ var (
 	errMessageTooShort    = errors.New("message too short")
 	errInvalidMessage     = errors.New("invalid message")
 	errInvalidAddr        = errors.New("invalid address")
+	errShortBuffer        = errors.New("short buffer")
 )
 
 // A RouteMessage represents a message conveying an address prefix, a
 // nexthop address and an output interface.
+//
+// Unlike other messages, this message can be used to query adjacency
+// information for the given address prefix, to add a new route, and
+// to delete or modify the existing route from the routing information
+// base inside the kernel by writing and reading route messages on a
+// routing socket.
+//
+// For the manipulation of routing information, the route message must
+// contain appropriate fields that include:
+//
+//	Version       = <must be specified>
+//	Type          = <must be specified>
+//	Flags         = <must be specified>
+//	Index         = <must be specified if necessary>
+//	ID            = <must be specified>
+//	Seq           = <must be specified>
+//	Addrs         = <must be specified>
+//
+// The Type field specifies a type of manipulation, the Flags field
+// specifies a class of target information and the Addrs field
+// specifies target information like the following:
+//
+//	route.RouteMessage{
+//		Version: RTM_VERSION,
+//		Type: RTM_GET,
+//		Flags: RTF_UP | RTF_HOST,
+//		ID: uintptr(os.Getpid()),
+//		Seq: 1,
+//		Addrs: []route.Addrs{
+//			RTAX_DST: &route.Inet4Addr{ ... },
+//			RTAX_IFP: &route.LinkAddr{ ... },
+//			RTAX_BRD: &route.Inet4Addr{ ... },
+//		},
+//	}
+//
+// The values for the above fields depend on the implementation of
+// each operating system.
+//
+// The Err field on a response message contains an error value on the
+// requested operation. If non-nil, the requested operation is failed.
 type RouteMessage struct {
-	Version int    // message version
-	Type    int    // message type
-	Flags   int    // route flags
-	Index   int    // interface index when atatched
-	Addrs   []Addr // addresses
+	Version int     // message version
+	Type    int     // message type
+	Flags   int     // route flags
+	Index   int     // interface index when atatched
+	ID      uintptr // sender's identifier; usually process ID
+	Seq     int     // sequence number
+	Err     error   // error on requested operation
+	Addrs   []Addr  // addresses
 
 	extOff int    // offset of header extension
 	raw    []byte // raw message
 }
 
+// Marshal returns the binary encoding of m.
+func (m *RouteMessage) Marshal() ([]byte, error) {
+	return m.marshal()
+}
+
 // A RIBType reprensents a type of routing information base.
 type RIBType int
 
diff --git a/src/vendor/golang_org/x/net/route/route_classic.go b/src/vendor/golang_org/x/net/route/route_classic.go
index d333c6a..61b2bb4 100644
--- a/src/vendor/golang_org/x/net/route/route_classic.go
+++ b/src/vendor/golang_org/x/net/route/route_classic.go
@@ -6,6 +6,36 @@
 
 package route
 
+import "syscall"
+
+func (m *RouteMessage) marshal() ([]byte, error) {
+	w, ok := wireFormats[m.Type]
+	if !ok {
+		return nil, errUnsupportedMessage
+	}
+	l := w.bodyOff + addrsSpace(m.Addrs)
+	b := make([]byte, l)
+	nativeEndian.PutUint16(b[:2], uint16(l))
+	if m.Version == 0 {
+		b[2] = sysRTM_VERSION
+	} else {
+		b[2] = byte(m.Version)
+	}
+	b[3] = byte(m.Type)
+	nativeEndian.PutUint32(b[8:12], uint32(m.Flags))
+	nativeEndian.PutUint16(b[4:6], uint16(m.Index))
+	nativeEndian.PutUint32(b[16:20], uint32(m.ID))
+	nativeEndian.PutUint32(b[20:24], uint32(m.Seq))
+	attrs, err := marshalAddrs(b[w.bodyOff:], m.Addrs)
+	if err != nil {
+		return nil, err
+	}
+	if attrs > 0 {
+		nativeEndian.PutUint32(b[12:16], uint32(attrs))
+	}
+	return b, nil
+}
+
 func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) {
 	if len(b) < w.bodyOff {
 		return nil, errMessageTooShort
@@ -19,9 +49,15 @@ func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) {
 		Type:    int(b[3]),
 		Flags:   int(nativeEndian.Uint32(b[8:12])),
 		Index:   int(nativeEndian.Uint16(b[4:6])),
+		ID:      uintptr(nativeEndian.Uint32(b[16:20])),
+		Seq:     int(nativeEndian.Uint32(b[20:24])),
 		extOff:  w.extOff,
 		raw:     b[:l],
 	}
+	errno := syscall.Errno(nativeEndian.Uint32(b[28:32]))
+	if errno != 0 {
+		m.Err = errno
+	}
 	var err error
 	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:])
 	if err != 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
index 76eae40..daf2e90 100644
--- a/src/vendor/golang_org/x/net/route/route_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/route_openbsd.go
@@ -4,8 +4,35 @@
 
 package route
 
+import "syscall"
+
+func (m *RouteMessage) marshal() ([]byte, error) {
+	l := sizeofRtMsghdr + addrsSpace(m.Addrs)
+	b := make([]byte, l)
+	nativeEndian.PutUint16(b[:2], uint16(l))
+	if m.Version == 0 {
+		b[2] = sysRTM_VERSION
+	} else {
+		b[2] = byte(m.Version)
+	}
+	b[3] = byte(m.Type)
+	nativeEndian.PutUint16(b[4:6], uint16(sizeofRtMsghdr))
+	nativeEndian.PutUint32(b[16:20], uint32(m.Flags))
+	nativeEndian.PutUint16(b[6:8], uint16(m.Index))
+	nativeEndian.PutUint32(b[24:28], uint32(m.ID))
+	nativeEndian.PutUint32(b[28:32], uint32(m.Seq))
+	attrs, err := marshalAddrs(b[sizeofRtMsghdr:], m.Addrs)
+	if err != nil {
+		return nil, err
+	}
+	if attrs > 0 {
+		nativeEndian.PutUint32(b[12:16], uint32(attrs))
+	}
+	return b, nil
+}
+
 func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
-	if len(b) < 40 {
+	if len(b) < sizeofRtMsghdr {
 		return nil, errMessageTooShort
 	}
 	l := int(nativeEndian.Uint16(b[:2]))
@@ -17,12 +44,18 @@ func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
 		Type:    int(b[3]),
 		Flags:   int(nativeEndian.Uint32(b[16:20])),
 		Index:   int(nativeEndian.Uint16(b[6:8])),
+		ID:      uintptr(nativeEndian.Uint32(b[24:28])),
+		Seq:     int(nativeEndian.Uint32(b[28:32])),
 		raw:     b[:l],
 	}
 	ll := int(nativeEndian.Uint16(b[4:6]))
 	if len(b) < ll {
 		return nil, errInvalidMessage
 	}
+	errno := syscall.Errno(nativeEndian.Uint32(b[32:36]))
+	if errno != 0 {
+		m.Err = errno
+	}
 	as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[ll:])
 	if err != nil {
 		return nil, err
diff --git a/src/vendor/golang_org/x/net/route/sys.go b/src/vendor/golang_org/x/net/route/sys.go
index 80ca83a..3d0ee9b 100644
--- a/src/vendor/golang_org/x/net/route/sys.go
+++ b/src/vendor/golang_org/x/net/route/sys.go
@@ -11,7 +11,7 @@ import "unsafe"
 var (
 	nativeEndian binaryByteOrder
 	kernelAlign  int
-	parseFns     map[int]parseFn
+	wireFormats  map[int]*wireFormat
 )
 
 func init() {
@@ -22,7 +22,7 @@ func init() {
 	} else {
 		nativeEndian = bigEndian
 	}
-	kernelAlign, parseFns = probeRoutingStack()
+	kernelAlign, wireFormats = probeRoutingStack()
 }
 
 func roundup(l int) int {
@@ -32,9 +32,8 @@ func roundup(l int) int {
 	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
+	parse   func(RIBType, []byte) (Message, error)
 }
diff --git a/src/vendor/golang_org/x/net/route/sys_darwin.go b/src/vendor/golang_org/x/net/route/sys_darwin.go
index fff3a0f..e742c91 100644
--- a/src/vendor/golang_org/x/net/route/sys_darwin.go
+++ b/src/vendor/golang_org/x/net/route/sys_darwin.go
@@ -49,32 +49,39 @@ func (m *InterfaceMessage) Sys() []Sys {
 	}
 }
 
-func probeRoutingStack() (int, map[int]parseFn) {
+func probeRoutingStack() (int, map[int]*wireFormat) {
 	rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15}
+	rtm.parse = rtm.parseRouteMessage
 	rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15}
+	rtm2.parse = rtm2.parseRouteMessage
 	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15}
+	ifm.parse = ifm.parseInterfaceMessage
 	ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15}
+	ifm2.parse = ifm2.parseInterfaceMessage
 	ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15}
+	ifam.parse = ifam.parseInterfaceAddrMessage
 	ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15}
+	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
 	ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15}
+	ifmam2.parse = ifmam2.parseInterfaceMulticastAddrMessage
 	// 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,
+	return 4, map[int]*wireFormat{
+		sysRTM_ADD:       rtm,
+		sysRTM_DELETE:    rtm,
+		sysRTM_CHANGE:    rtm,
+		sysRTM_GET:       rtm,
+		sysRTM_LOSING:    rtm,
+		sysRTM_REDIRECT:  rtm,
+		sysRTM_MISS:      rtm,
+		sysRTM_LOCK:      rtm,
+		sysRTM_RESOLVE:   rtm,
+		sysRTM_NEWADDR:   ifam,
+		sysRTM_DELADDR:   ifam,
+		sysRTM_IFINFO:    ifm,
+		sysRTM_NEWMADDR:  ifmam,
+		sysRTM_DELMADDR:  ifmam,
+		sysRTM_IFINFO2:   ifm2,
+		sysRTM_NEWMADDR2: ifmam2,
+		sysRTM_GET2:      rtm2,
 	}
 }
diff --git a/src/vendor/golang_org/x/net/route/sys_dragonfly.go b/src/vendor/golang_org/x/net/route/sys_dragonfly.go
index da848b3..b175cb1 100644
--- a/src/vendor/golang_org/x/net/route/sys_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/sys_dragonfly.go
@@ -44,28 +44,33 @@ func (m *InterfaceMessage) Sys() []Sys {
 	}
 }
 
-func probeRoutingStack() (int, map[int]parseFn) {
+func probeRoutingStack() (int, map[int]*wireFormat) {
 	var p uintptr
 	rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4}
+	rtm.parse = rtm.parseRouteMessage
 	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4}
+	ifm.parse = ifm.parseInterfaceMessage
 	ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4}
+	ifam.parse = ifam.parseInterfaceAddrMessage
 	ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4}
+	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
 	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,
+	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
+	return int(unsafe.Sizeof(p)), map[int]*wireFormat{
+		sysRTM_ADD:        rtm,
+		sysRTM_DELETE:     rtm,
+		sysRTM_CHANGE:     rtm,
+		sysRTM_GET:        rtm,
+		sysRTM_LOSING:     rtm,
+		sysRTM_REDIRECT:   rtm,
+		sysRTM_MISS:       rtm,
+		sysRTM_LOCK:       rtm,
+		sysRTM_RESOLVE:    rtm,
+		sysRTM_NEWADDR:    ifam,
+		sysRTM_DELADDR:    ifam,
+		sysRTM_IFINFO:     ifm,
+		sysRTM_NEWMADDR:   ifmam,
+		sysRTM_DELMADDR:   ifmam,
+		sysRTM_IFANNOUNCE: ifanm,
 	}
 }
diff --git a/src/vendor/golang_org/x/net/route/sys_freebsd.go b/src/vendor/golang_org/x/net/route/sys_freebsd.go
index 7b05c1a..010d4ae 100644
--- a/src/vendor/golang_org/x/net/route/sys_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_freebsd.go
@@ -54,7 +54,7 @@ func (m *InterfaceMessage) Sys() []Sys {
 	}
 }
 
-func probeRoutingStack() (int, map[int]parseFn) {
+func probeRoutingStack() (int, map[int]*wireFormat) {
 	var p uintptr
 	wordSize := int(unsafe.Sizeof(p))
 	align := int(unsafe.Sizeof(p))
@@ -130,21 +130,26 @@ func probeRoutingStack() (int, map[int]parseFn) {
 			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,
+	rtm.parse = rtm.parseRouteMessage
+	ifm.parse = ifm.parseInterfaceMessage
+	ifam.parse = ifam.parseInterfaceAddrMessage
+	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
+	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
+	return align, map[int]*wireFormat{
+		sysRTM_ADD:        rtm,
+		sysRTM_DELETE:     rtm,
+		sysRTM_CHANGE:     rtm,
+		sysRTM_GET:        rtm,
+		sysRTM_LOSING:     rtm,
+		sysRTM_REDIRECT:   rtm,
+		sysRTM_MISS:       rtm,
+		sysRTM_LOCK:       rtm,
+		sysRTM_RESOLVE:    rtm,
+		sysRTM_NEWADDR:    ifam,
+		sysRTM_DELADDR:    ifam,
+		sysRTM_IFINFO:     ifm,
+		sysRTM_NEWMADDR:   ifmam,
+		sysRTM_DELMADDR:   ifmam,
+		sysRTM_IFANNOUNCE: ifanm,
 	}
 }
diff --git a/src/vendor/golang_org/x/net/route/sys_netbsd.go b/src/vendor/golang_org/x/net/route/sys_netbsd.go
index 4d8076b..b4e3301 100644
--- a/src/vendor/golang_org/x/net/route/sys_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_netbsd.go
@@ -42,26 +42,30 @@ func (m *InterfaceMessage) Sys() []Sys {
 	}
 }
 
-func probeRoutingStack() (int, map[int]parseFn) {
+func probeRoutingStack() (int, map[int]*wireFormat) {
 	rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7}
+	rtm.parse = rtm.parseRouteMessage
 	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7}
+	ifm.parse = ifm.parseInterfaceMessage
 	ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7}
+	ifam.parse = ifam.parseInterfaceAddrMessage
 	ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7}
+	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
 	// 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,
+	return 8, map[int]*wireFormat{
+		sysRTM_ADD:        rtm,
+		sysRTM_DELETE:     rtm,
+		sysRTM_CHANGE:     rtm,
+		sysRTM_GET:        rtm,
+		sysRTM_LOSING:     rtm,
+		sysRTM_REDIRECT:   rtm,
+		sysRTM_MISS:       rtm,
+		sysRTM_LOCK:       rtm,
+		sysRTM_RESOLVE:    rtm,
+		sysRTM_NEWADDR:    ifam,
+		sysRTM_DELADDR:    ifam,
+		sysRTM_IFANNOUNCE: ifanm,
+		sysRTM_IFINFO:     ifm,
 	}
 }
diff --git a/src/vendor/golang_org/x/net/route/sys_openbsd.go b/src/vendor/golang_org/x/net/route/sys_openbsd.go
index 26d0438..8798dc4 100644
--- a/src/vendor/golang_org/x/net/route/sys_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_openbsd.go
@@ -51,22 +51,29 @@ func (m *InterfaceMessage) Sys() []Sys {
 	}
 }
 
-func probeRoutingStack() (int, map[int]parseFn) {
+func probeRoutingStack() (int, map[int]*wireFormat) {
 	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,
+	rtm := &wireFormat{extOff: -1, bodyOff: -1}
+	rtm.parse = rtm.parseRouteMessage
+	ifm := &wireFormat{extOff: -1, bodyOff: -1}
+	ifm.parse = ifm.parseInterfaceMessage
+	ifam := &wireFormat{extOff: -1, bodyOff: -1}
+	ifam.parse = ifam.parseInterfaceAddrMessage
+	ifanm := &wireFormat{extOff: -1, bodyOff: -1}
+	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
+	return int(unsafe.Sizeof(p)), map[int]*wireFormat{
+		sysRTM_ADD:        rtm,
+		sysRTM_DELETE:     rtm,
+		sysRTM_CHANGE:     rtm,
+		sysRTM_GET:        rtm,
+		sysRTM_LOSING:     rtm,
+		sysRTM_REDIRECT:   rtm,
+		sysRTM_MISS:       rtm,
+		sysRTM_LOCK:       rtm,
+		sysRTM_RESOLVE:    rtm,
+		sysRTM_NEWADDR:    ifam,
+		sysRTM_DELADDR:    ifam,
+		sysRTM_IFINFO:     ifm,
+		sysRTM_IFANNOUNCE: ifanm,
 	}
 }
diff --git a/src/vendor/golang_org/x/net/route/syscall.go b/src/vendor/golang_org/x/net/route/syscall.go
index d136325..c211188 100644
--- a/src/vendor/golang_org/x/net/route/syscall.go
+++ b/src/vendor/golang_org/x/net/route/syscall.go
@@ -11,10 +11,6 @@ import (
 	"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 {
@@ -25,7 +21,6 @@ func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		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)
 	}
diff --git a/src/vendor/golang_org/x/net/route/syscall.s b/src/vendor/golang_org/x/net/route/syscall.s
deleted file mode 100644
index fa6297f..0000000
--- a/src/vendor/golang_org/x/net/route/syscall.s
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2016 The Go 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
index 265b81c..4e2e1ab 100644
--- a/src/vendor/golang_org/x/net/route/zsys_darwin.go
+++ b/src/vendor/golang_org/x/net/route/zsys_darwin.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x1e
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP    = 0x1
 	sysNET_RT_FLAGS   = 0x2
 	sysNET_RT_IFLIST  = 0x3
@@ -90,4 +92,8 @@ const (
 	sizeofRtMsghdrDarwin15  = 0x5c
 	sizeofRtMsghdr2Darwin15 = 0x5c
 	sizeofRtMetricsDarwin15 = 0x38
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
diff --git a/src/vendor/golang_org/x/net/route/zsys_dragonfly.go b/src/vendor/golang_org/x/net/route/zsys_dragonfly.go
index dd36dec..719c88d 100644
--- a/src/vendor/golang_org/x/net/route/zsys_dragonfly.go
+++ b/src/vendor/golang_org/x/net/route/zsys_dragonfly.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x1c
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP   = 0x1
 	sysNET_RT_FLAGS  = 0x2
 	sysNET_RT_IFLIST = 0x3
@@ -89,4 +91,8 @@ const (
 
 	sizeofRtMsghdrDragonFlyBSD4  = 0x98
 	sizeofRtMetricsDragonFlyBSD4 = 0x70
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
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
index 9bac2e3..b03bc01 100644
--- a/src/vendor/golang_org/x/net/route/zsys_freebsd_386.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_386.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x1c
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP     = 0x1
 	sysNET_RT_FLAGS    = 0x2
 	sysNET_RT_IFLIST   = 0x3
@@ -117,4 +119,8 @@ const (
 	sizeofIfDataFreeBSD9Emu  = 0x98
 	sizeofIfDataFreeBSD10Emu = 0x98
 	sizeofIfDataFreeBSD11Emu = 0x98
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
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
index b1920d7..0b675b3 100644
--- a/src/vendor/golang_org/x/net/route/zsys_freebsd_amd64.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_amd64.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x1c
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP     = 0x1
 	sysNET_RT_FLAGS    = 0x2
 	sysNET_RT_IFLIST   = 0x3
@@ -114,4 +116,8 @@ const (
 	sizeofIfDataFreeBSD9Emu  = 0x98
 	sizeofIfDataFreeBSD10Emu = 0x98
 	sizeofIfDataFreeBSD11Emu = 0x98
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
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
index a034d6f..58f8ea1 100644
--- a/src/vendor/golang_org/x/net/route/zsys_freebsd_arm.go
+++ b/src/vendor/golang_org/x/net/route/zsys_freebsd_arm.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x1c
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP     = 0x1
 	sysNET_RT_FLAGS    = 0x2
 	sysNET_RT_IFLIST   = 0x3
@@ -114,4 +116,8 @@ const (
 	sizeofIfDataFreeBSD9Emu  = 0x60
 	sizeofIfDataFreeBSD10Emu = 0x60
 	sizeofIfDataFreeBSD11Emu = 0x98
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
diff --git a/src/vendor/golang_org/x/net/route/zsys_netbsd.go b/src/vendor/golang_org/x/net/route/zsys_netbsd.go
index aa4aad1..e0df45e 100644
--- a/src/vendor/golang_org/x/net/route/zsys_netbsd.go
+++ b/src/vendor/golang_org/x/net/route/zsys_netbsd.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x18
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP   = 0x1
 	sysNET_RT_FLAGS  = 0x2
 	sysNET_RT_IFLIST = 0x5
@@ -88,4 +90,8 @@ const (
 
 	sizeofRtMsghdrNetBSD7  = 0x78
 	sizeofRtMetricsNetBSD7 = 0x50
+
+	sizeofSockaddrStorage = 0x80
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
 )
diff --git a/src/vendor/golang_org/x/net/route/zsys_openbsd.go b/src/vendor/golang_org/x/net/route/zsys_openbsd.go
index 4fadc4e..f5a1ff9 100644
--- a/src/vendor/golang_org/x/net/route/zsys_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/zsys_openbsd.go
@@ -10,6 +10,8 @@ const (
 	sysAF_LINK   = 0x12
 	sysAF_INET6  = 0x18
 
+	sysSOCK_RAW = 0x3
+
 	sysNET_RT_DUMP    = 0x1
 	sysNET_RT_FLAGS   = 0x2
 	sysNET_RT_IFLIST  = 0x3
@@ -78,3 +80,11 @@ const (
 	sysRTAX_LABEL   = 0xa
 	sysRTAX_MAX     = 0xb
 )
+
+const (
+	sizeofRtMsghdr = 0x60
+
+	sizeofSockaddrStorage = 0x100
+	sizeofSockaddrInet    = 0x10
+	sizeofSockaddrInet6   = 0x1c
+)
diff --git a/src/vendor/golang_org/x/text/secure/bidirule/bidirule.go b/src/vendor/golang_org/x/text/secure/bidirule/bidirule.go
new file mode 100644
index 0000000..9f9594e
--- /dev/null
+++ b/src/vendor/golang_org/x/text/secure/bidirule/bidirule.go
@@ -0,0 +1,344 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bidirule implements the Bidi Rule defined by RFC 5893.
+//
+// This package is under development. The API may change without notice and
+// without preserving backward compatibility.
+package bidirule
+
+import (
+	"errors"
+	"unicode/utf8"
+
+	"golang_org/x/text/transform"
+	"golang_org/x/text/unicode/bidi"
+)
+
+// This file contains an implementation of RFC 5893: Right-to-Left Scripts for
+// Internationalized Domain Names for Applications (IDNA)
+//
+// A label is an individual component of a domain name.  Labels are usually
+// shown separated by dots; for example, the domain name "www.example.com" is
+// composed of three labels: "www", "example", and "com".
+//
+// An RTL label is a label that contains at least one character of class R, AL,
+// or AN. An LTR label is any label that is not an RTL label.
+//
+// A "Bidi domain name" is a domain name that contains at least one RTL label.
+//
+//  The following guarantees can be made based on the above:
+//
+//  o  In a domain name consisting of only labels that satisfy the rule,
+//     the requirements of Section 3 are satisfied.  Note that even LTR
+//     labels and pure ASCII labels have to be tested.
+//
+//  o  In a domain name consisting of only LDH labels (as defined in the
+//     Definitions document [RFC5890]) and labels that satisfy the rule,
+//     the requirements of Section 3 are satisfied as long as a label
+//     that starts with an ASCII digit does not come after a
+//     right-to-left label.
+//
+//  No guarantee is given for other combinations.
+
+// ErrInvalid indicates a label is invalid according to the Bidi Rule.
+var ErrInvalid = errors.New("bidirule: failed Bidi Rule")
+
+type ruleState uint8
+
+const (
+	ruleInitial ruleState = iota
+	ruleLTR
+	ruleLTRFinal
+	ruleRTL
+	ruleRTLFinal
+	ruleInvalid
+)
+
+type ruleTransition struct {
+	next ruleState
+	mask uint16
+}
+
+var transitions = [...][2]ruleTransition{
+	// [2.1] The first character must be a character with Bidi property L, R, or
+	// AL. If it has the R or AL property, it is an RTL label; if it has the L
+	// property, it is an LTR label.
+	ruleInitial: {
+		{ruleLTRFinal, 1 << bidi.L},
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL},
+	},
+	ruleRTL: {
+		// [2.3] In an RTL label, the end of the label must be a character with
+		// Bidi property R, AL, EN, or AN, followed by zero or more characters
+		// with Bidi property NSM.
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN},
+
+		// [2.2] In an RTL label, only characters with the Bidi properties R,
+		// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.3]
+		{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
+	},
+	ruleRTLFinal: {
+		// [2.3] In an RTL label, the end of the label must be a character with
+		// Bidi property R, AL, EN, or AN, followed by zero or more characters
+		// with Bidi property NSM.
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN | 1<<bidi.NSM},
+
+		// [2.2] In an RTL label, only characters with the Bidi properties R,
+		// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.3] and NSM.
+		{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
+	},
+	ruleLTR: {
+		// [2.6] In an LTR label, the end of the label must be a character with
+		// Bidi property L or EN, followed by zero or more characters with Bidi
+		// property NSM.
+		{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN},
+
+		// [2.5] In an LTR label, only characters with the Bidi properties L,
+		// EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.6].
+		{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
+	},
+	ruleLTRFinal: {
+		// [2.6] In an LTR label, the end of the label must be a character with
+		// Bidi property L or EN, followed by zero or more characters with Bidi
+		// property NSM.
+		{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN | 1<<bidi.NSM},
+
+		// [2.5] In an LTR label, only characters with the Bidi properties L,
+		// EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.6].
+		{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
+	},
+	ruleInvalid: {
+		{ruleInvalid, 0},
+		{ruleInvalid, 0},
+	},
+}
+
+// [2.4] In an RTL label, if an EN is present, no AN may be present, and
+// vice versa.
+const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN)
+
+// From RFC 5893
+// An RTL label is a label that contains at least one character of type
+// R, AL, or AN.
+//
+// An LTR label is any label that is not an RTL label.
+
+// Direction reports the direction of the given label as defined by RFC 5893.
+// The Bidi Rule does not have to be applied to labels of the category
+// LeftToRight.
+func Direction(b []byte) bidi.Direction {
+	for i := 0; i < len(b); {
+		e, sz := bidi.Lookup(b[i:])
+		if sz == 0 {
+			i++
+		}
+		c := e.Class()
+		if c == bidi.R || c == bidi.AL || c == bidi.AN {
+			return bidi.RightToLeft
+		}
+		i += sz
+	}
+	return bidi.LeftToRight
+}
+
+// DirectionString reports the direction of the given label as defined by RFC
+// 5893. The Bidi Rule does not have to be applied to labels of the category
+// LeftToRight.
+func DirectionString(s string) bidi.Direction {
+	for i := 0; i < len(s); {
+		e, sz := bidi.LookupString(s[i:])
+		if sz == 0 {
+			i++
+		}
+		c := e.Class()
+		if c == bidi.R || c == bidi.AL || c == bidi.AN {
+			return bidi.RightToLeft
+		}
+		i += sz
+	}
+	return bidi.LeftToRight
+}
+
+// Valid reports whether b conforms to the BiDi rule.
+func Valid(b []byte) bool {
+	var t Transformer
+	if n, ok := t.advance(b); !ok || n < len(b) {
+		return false
+	}
+	return t.isFinal()
+}
+
+// ValidString reports whether s conforms to the BiDi rule.
+func ValidString(s string) bool {
+	var t Transformer
+	if n, ok := t.advanceString(s); !ok || n < len(s) {
+		return false
+	}
+	return t.isFinal()
+}
+
+// New returns a Transformer that verifies that input adheres to the Bidi Rule.
+func New() *Transformer {
+	return &Transformer{}
+}
+
+// Transformer implements transform.Transform.
+type Transformer struct {
+	state  ruleState
+	hasRTL bool
+	seen   uint16
+}
+
+// A rule can only be violated for "Bidi Domain names", meaning if one of the
+// following categories has been observed.
+func (t *Transformer) isRTL() bool {
+	const isRTL = 1<<bidi.R | 1<<bidi.AL | 1<<bidi.AN
+	return t.seen&isRTL != 0
+}
+
+func (t *Transformer) isFinal() bool {
+	if !t.isRTL() {
+		return true
+	}
+	return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
+}
+
+// Reset implements transform.Transformer.
+func (t *Transformer) Reset() { *t = Transformer{} }
+
+// Transform implements transform.Transformer. This Transformer has state and
+// needs to be reset between uses.
+func (t *Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	if len(dst) < len(src) {
+		src = src[:len(dst)]
+		atEOF = false
+		err = transform.ErrShortDst
+	}
+	n, err1 := t.Span(src, atEOF)
+	copy(dst, src[:n])
+	if err == nil || err1 != nil && err1 != transform.ErrShortSrc {
+		err = err1
+	}
+	return n, n, err
+}
+
+// Span returns the first n bytes of src that conform to the Bidi rule.
+func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
+	if t.state == ruleInvalid && t.isRTL() {
+		return 0, ErrInvalid
+	}
+	n, ok := t.advance(src)
+	switch {
+	case !ok:
+		err = ErrInvalid
+	case n < len(src):
+		if !atEOF {
+			err = transform.ErrShortSrc
+			break
+		}
+		err = ErrInvalid
+	case !t.isFinal():
+		err = ErrInvalid
+	}
+	return n, err
+}
+
+// Precomputing the ASCII values decreases running time for the ASCII fast path
+// by about 30%.
+var asciiTable [128]bidi.Properties
+
+func init() {
+	for i := range asciiTable {
+		p, _ := bidi.LookupRune(rune(i))
+		asciiTable[i] = p
+	}
+}
+
+func (t *Transformer) advance(s []byte) (n int, ok bool) {
+	var e bidi.Properties
+	var sz int
+	for n < len(s) {
+		if s[n] < utf8.RuneSelf {
+			e, sz = asciiTable[s[n]], 1
+		} else {
+			e, sz = bidi.Lookup(s[n:])
+			if sz <= 1 {
+				if sz == 1 {
+					// We always consider invalid UTF-8 to be invalid, even if
+					// the string has not yet been determined to be RTL.
+					// TODO: is this correct?
+					return n, false
+				}
+				return n, true // incomplete UTF-8 encoding
+			}
+		}
+		// TODO: using CompactClass would result in noticeable speedup.
+		// See unicode/bidi/prop.go:Properties.CompactClass.
+		c := uint16(1 << e.Class())
+		t.seen |= c
+		if t.seen&exclusiveRTL == exclusiveRTL {
+			t.state = ruleInvalid
+			return n, false
+		}
+		switch tr := transitions[t.state]; {
+		case tr[0].mask&c != 0:
+			t.state = tr[0].next
+		case tr[1].mask&c != 0:
+			t.state = tr[1].next
+		default:
+			t.state = ruleInvalid
+			if t.isRTL() {
+				return n, false
+			}
+		}
+		n += sz
+	}
+	return n, true
+}
+
+func (t *Transformer) advanceString(s string) (n int, ok bool) {
+	var e bidi.Properties
+	var sz int
+	for n < len(s) {
+		if s[n] < utf8.RuneSelf {
+			e, sz = asciiTable[s[n]], 1
+		} else {
+			e, sz = bidi.LookupString(s[n:])
+			if sz <= 1 {
+				if sz == 1 {
+					return n, false // invalid UTF-8
+				}
+				return n, true // incomplete UTF-8 encoding
+			}
+		}
+		// TODO: using CompactClass results in noticeable speedup.
+		// See unicode/bidi/prop.go:Properties.CompactClass.
+		c := uint16(1 << e.Class())
+		t.seen |= c
+		if t.seen&exclusiveRTL == exclusiveRTL {
+			t.state = ruleInvalid
+			return n, false
+		}
+		switch tr := transitions[t.state]; {
+		case tr[0].mask&c != 0:
+			t.state = tr[0].next
+		case tr[1].mask&c != 0:
+			t.state = tr[1].next
+		default:
+			t.state = ruleInvalid
+			if t.isRTL() {
+				return n, false
+			}
+		}
+		n += sz
+	}
+	return n, true
+}
diff --git a/src/vendor/golang_org/x/text/secure/doc.go b/src/vendor/golang_org/x/text/secure/doc.go
new file mode 100644
index 0000000..4912b9b
--- /dev/null
+++ b/src/vendor/golang_org/x/text/secure/doc.go
@@ -0,0 +1,8 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// secure is a repository of text security related packages.
+package secure // import "golang_org/x/text/secure"
diff --git a/src/vendor/golang_org/x/text/transform/examples_test.go b/src/vendor/golang_org/x/text/transform/examples_test.go
new file mode 100644
index 0000000..1323d9b
--- /dev/null
+++ b/src/vendor/golang_org/x/text/transform/examples_test.go
@@ -0,0 +1,39 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package transform_test
+
+import (
+	"fmt"
+	"unicode"
+
+	"golang_org/x/text/transform"
+	"golang_org/x/text/unicode/norm"
+)
+
+func ExampleRemoveFunc() {
+	input := []byte(`tschüß; до свидания`)
+
+	b := make([]byte, len(input))
+
+	t := transform.RemoveFunc(unicode.IsSpace)
+	n, _, _ := t.Transform(b, input, true)
+	fmt.Println(string(b[:n]))
+
+	t = transform.RemoveFunc(func(r rune) bool {
+		return !unicode.Is(unicode.Latin, r)
+	})
+	n, _, _ = t.Transform(b, input, true)
+	fmt.Println(string(b[:n]))
+
+	n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true)
+	fmt.Println(string(b[:n]))
+
+	// Output:
+	// tschüß;досвидания
+	// tschüß
+	// tschuß
+}
diff --git a/src/vendor/golang_org/x/text/transform/transform.go b/src/vendor/golang_org/x/text/transform/transform.go
index fe47b9b..2a1b190 100644
--- a/src/vendor/golang_org/x/text/transform/transform.go
+++ b/src/vendor/golang_org/x/text/transform/transform.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2013 The Go 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 +8,7 @@
 // bytes passing through as well as various transformations. Example
 // transformations provided by other packages include normalization and
 // conversion between character sets.
-package transform // import "golang.org/x/text/transform"
+package transform // import "golang_org/x/text/transform"
 
 import (
 	"bytes"
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/bidi.go b/src/vendor/golang_org/x/text/unicode/bidi/bidi.go
new file mode 100644
index 0000000..4c9735e
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/bidi.go
@@ -0,0 +1,198 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bidi contains functionality for bidirectional text support.
+//
+// See http://www.unicode.org/reports/tr9.
+//
+// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
+// and without notice.
+package bidi // import "golang_org/x/text/unicode/bidi"
+
+// TODO:
+// The following functionality would not be hard to implement, but hinges on
+// the definition of a Segmenter interface. For now this is up to the user.
+// - Iterate over paragraphs
+// - Segmenter to iterate over runs directly from a given text.
+// Also:
+// - Transformer for reordering?
+// - Transformer (validator, really) for Bidi Rule.
+
+// This API tries to avoid dealing with embedding levels for now. Under the hood
+// these will be computed, but the question is to which extent the user should
+// know they exist. We should at some point allow the user to specify an
+// embedding hierarchy, though.
+
+// A Direction indicates the overall flow of text.
+type Direction int
+
+const (
+	// LeftToRight indicates the text contains no right-to-left characters and
+	// that either there are some left-to-right characters or the option
+	// DefaultDirection(LeftToRight) was passed.
+	LeftToRight Direction = iota
+
+	// RightToLeft indicates the text contains no left-to-right characters and
+	// that either there are some right-to-left characters or the option
+	// DefaultDirection(RightToLeft) was passed.
+	RightToLeft
+
+	// Mixed indicates text contains both left-to-right and right-to-left
+	// characters.
+	Mixed
+
+	// Neutral means that text contains no left-to-right and right-to-left
+	// characters and that no default direction has been set.
+	Neutral
+)
+
+type options struct{}
+
+// An Option is an option for Bidi processing.
+type Option func(*options)
+
+// ICU allows the user to define embedding levels. This may be used, for example,
+// to use hierarchical structure of markup languages to define embeddings.
+// The following option may be a way to expose this functionality in this API.
+// // LevelFunc sets a function that associates nesting levels with the given text.
+// // The levels function will be called with monotonically increasing values for p.
+// func LevelFunc(levels func(p int) int) Option {
+// 	panic("unimplemented")
+// }
+
+// DefaultDirection sets the default direction for a Paragraph. The direction is
+// overridden if the text contains directional characters.
+func DefaultDirection(d Direction) Option {
+	panic("unimplemented")
+}
+
+// A Paragraph holds a single Paragraph for Bidi processing.
+type Paragraph struct {
+	// buffers
+}
+
+// SetBytes configures p for the given paragraph text. It replaces text
+// previously set by SetBytes or SetString. If b contains a paragraph separator
+// it will only process the first paragraph and report the number of bytes
+// consumed from b including this separator. Error may be non-nil if options are
+// given.
+func (p *Paragraph) SetBytes(b []byte, opts ...Option) (n int, err error) {
+	panic("unimplemented")
+}
+
+// SetString configures p for the given paragraph text. It replaces text
+// previously set by SetBytes or SetString. If b contains a paragraph separator
+// it will only process the first paragraph and report the number of bytes
+// consumed from b including this separator. Error may be non-nil if options are
+// given.
+func (p *Paragraph) SetString(s string, opts ...Option) (n int, err error) {
+	panic("unimplemented")
+}
+
+// IsLeftToRight reports whether the principle direction of rendering for this
+// paragraphs is left-to-right. If this returns false, the principle direction
+// of rendering is right-to-left.
+func (p *Paragraph) IsLeftToRight() bool {
+	panic("unimplemented")
+}
+
+// Direction returns the direction of the text of this paragraph.
+//
+// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
+func (p *Paragraph) Direction() Direction {
+	panic("unimplemented")
+}
+
+// RunAt reports the Run at the given position of the input text.
+//
+// This method can be used for computing line breaks on paragraphs.
+func (p *Paragraph) RunAt(pos int) Run {
+	panic("unimplemented")
+}
+
+// Order computes the visual ordering of all the runs in a Paragraph.
+func (p *Paragraph) Order() (Ordering, error) {
+	panic("unimplemented")
+}
+
+// Line computes the visual ordering of runs for a single line starting and
+// ending at the given positions in the original text.
+func (p *Paragraph) Line(start, end int) (Ordering, error) {
+	panic("unimplemented")
+}
+
+// An Ordering holds the computed visual order of runs of a Paragraph. Calling
+// SetBytes or SetString on the originating Paragraph invalidates an Ordering.
+// The methods of an Ordering should only be called by one goroutine at a time.
+type Ordering struct{}
+
+// Direction reports the directionality of the runs.
+//
+// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
+func (o *Ordering) Direction() Direction {
+	panic("unimplemented")
+}
+
+// NumRuns returns the number of runs.
+func (o *Ordering) NumRuns() int {
+	panic("unimplemented")
+}
+
+// Run returns the ith run within the ordering.
+func (o *Ordering) Run(i int) Run {
+	panic("unimplemented")
+}
+
+// TODO: perhaps with options.
+// // Reorder creates a reader that reads the runes in visual order per character.
+// // Modifiers remain after the runes they modify.
+// func (l *Runs) Reorder() io.Reader {
+// 	panic("unimplemented")
+// }
+
+// A Run is a continuous sequence of characters of a single direction.
+type Run struct {
+}
+
+// String returns the text of the run in its original order.
+func (r *Run) String() string {
+	panic("unimplemented")
+}
+
+// Bytes returns the text of the run in its original order.
+func (r *Run) Bytes() []byte {
+	panic("unimplemented")
+}
+
+// TODO: methods for
+// - Display order
+// - headers and footers
+// - bracket replacement.
+
+// Direction reports the direction of the run.
+func (r *Run) Direction() Direction {
+	panic("unimplemented")
+}
+
+// Position of the Run within the text passed to SetBytes or SetString of the
+// originating Paragraph value.
+func (r *Run) Pos() (start, end int) {
+	panic("unimplemented")
+}
+
+// AppendReverse reverses the order of characters of in, appends them to out,
+// and returns the result. Modifiers will still follow the runes they modify.
+// Brackets are replaced with their counterparts.
+func AppendReverse(out, in []byte) []byte {
+	panic("unimplemented")
+}
+
+// ReverseString reverses the order of characters in s and returns a new string.
+// Modifiers will still follow the runes they modify. Brackets are replaced with
+// their counterparts.
+func ReverseString(s string) string {
+	panic("unimplemented")
+}
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/bracket.go b/src/vendor/golang_org/x/text/unicode/bidi/bracket.go
new file mode 100644
index 0000000..f08a93d
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/bracket.go
@@ -0,0 +1,337 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bidi
+
+import (
+	"container/list"
+	"fmt"
+	"sort"
+)
+
+// This file contains a port of the reference implementation of the
+// Bidi Parentheses Algorithm:
+// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
+//
+// The implementation in this file covers definitions BD14-BD16 and rule N0
+// of UAX#9.
+//
+// Some preprocessing is done for each rune before data is passed to this
+// algorithm:
+//  - opening and closing brackets are identified
+//  - a bracket pair type, like '(' and ')' is assigned a unique identifier that
+//    is identical for the opening and closing bracket. It is left to do these
+//    mappings.
+//  - The BPA algorithm requires that bracket characters that are canonical
+//    equivalents of each other be able to be substituted for each other.
+//    It is the responsibility of the caller to do this canonicalization.
+//
+// In implementing BD16, this implementation departs slightly from the "logical"
+// algorithm defined in UAX#9. In particular, the stack referenced there
+// supports operations that go beyond a "basic" stack. An equivalent
+// implementation based on a linked list is used here.
+
+// Bidi_Paired_Bracket_Type
+// BD14. An opening paired bracket is a character whose
+// Bidi_Paired_Bracket_Type property value is Open.
+//
+// BD15. A closing paired bracket is a character whose
+// Bidi_Paired_Bracket_Type property value is Close.
+type bracketType byte
+
+const (
+	bpNone bracketType = iota
+	bpOpen
+	bpClose
+)
+
+// bracketPair holds a pair of index values for opening and closing bracket
+// location of a bracket pair.
+type bracketPair struct {
+	opener int
+	closer int
+}
+
+func (b *bracketPair) String() string {
+	return fmt.Sprintf("(%v, %v)", b.opener, b.closer)
+}
+
+// bracketPairs is a slice of bracketPairs with a sort.Interface implementation.
+type bracketPairs []bracketPair
+
+func (b bracketPairs) Len() int           { return len(b) }
+func (b bracketPairs) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
+func (b bracketPairs) Less(i, j int) bool { return b[i].opener < b[j].opener }
+
+// resolvePairedBrackets runs the paired bracket part of the UBA algorithm.
+//
+// For each rune, it takes the indexes into the original string, the class the
+// bracket type (in pairTypes) and the bracket identifier (pairValues). It also
+// takes the direction type for the start-of-sentence and the embedding level.
+//
+// The identifiers for bracket types are the rune of the canonicalized opening
+// bracket for brackets (open or close) or 0 for runes that are not brackets.
+func resolvePairedBrackets(s *isolatingRunSequence) {
+	p := bracketPairer{
+		sos:              s.sos,
+		openers:          list.New(),
+		codesIsolatedRun: s.types,
+		indexes:          s.indexes,
+	}
+	dirEmbed := L
+	if s.level&1 != 0 {
+		dirEmbed = R
+	}
+	p.locateBrackets(s.p.pairTypes, s.p.pairValues)
+	p.resolveBrackets(dirEmbed, s.p.initialTypes)
+}
+
+type bracketPairer struct {
+	sos Class // direction corresponding to start of sequence
+
+	// The following is a restatement of BD 16 using non-algorithmic language.
+	//
+	// A bracket pair is a pair of characters consisting of an opening
+	// paired bracket and a closing paired bracket such that the
+	// Bidi_Paired_Bracket property value of the former equals the latter,
+	// subject to the following constraints.
+	// - both characters of a pair occur in the same isolating run sequence
+	// - the closing character of a pair follows the opening character
+	// - any bracket character can belong at most to one pair, the earliest possible one
+	// - any bracket character not part of a pair is treated like an ordinary character
+	// - pairs may nest properly, but their spans may not overlap otherwise
+
+	// Bracket characters with canonical decompositions are supposed to be
+	// treated as if they had been normalized, to allow normalized and non-
+	// normalized text to give the same result. In this implementation that step
+	// is pushed out to the caller. The caller has to ensure that the pairValue
+	// slices contain the rune of the opening bracket after normalization for
+	// any opening or closing bracket.
+
+	openers *list.List // list of positions for opening brackets
+
+	// bracket pair positions sorted by location of opening bracket
+	pairPositions bracketPairs
+
+	codesIsolatedRun []Class // directional bidi codes for an isolated run
+	indexes          []int   // array of index values into the original string
+
+}
+
+// matchOpener reports whether characters at given positions form a matching
+// bracket pair.
+func (p *bracketPairer) matchOpener(pairValues []rune, opener, closer int) bool {
+	return pairValues[p.indexes[opener]] == pairValues[p.indexes[closer]]
+}
+
+const maxPairingDepth = 63
+
+// locateBrackets locates matching bracket pairs according to BD16.
+//
+// This implementation uses a linked list instead of a stack, because, while
+// elements are added at the front (like a push) they are not generally removed
+// in atomic 'pop' operations, reducing the benefit of the stack archetype.
+func (p *bracketPairer) locateBrackets(pairTypes []bracketType, pairValues []rune) {
+	// traverse the run
+	// do that explicitly (not in a for-each) so we can record position
+	for i, index := range p.indexes {
+
+		// look at the bracket type for each character
+		if pairTypes[index] == bpNone || p.codesIsolatedRun[i] != ON {
+			// continue scanning
+			continue
+		}
+		switch pairTypes[index] {
+		case bpOpen:
+			// check if maximum pairing depth reached
+			if p.openers.Len() == maxPairingDepth {
+				p.openers.Init()
+				return
+			}
+			// remember opener location, most recent first
+			p.openers.PushFront(i)
+
+		case bpClose:
+			// see if there is a match
+			count := 0
+			for elem := p.openers.Front(); elem != nil; elem = elem.Next() {
+				count++
+				opener := elem.Value.(int)
+				if p.matchOpener(pairValues, opener, i) {
+					// if the opener matches, add nested pair to the ordered list
+					p.pairPositions = append(p.pairPositions, bracketPair{opener, i})
+					// remove up to and including matched opener
+					for ; count > 0; count-- {
+						p.openers.Remove(p.openers.Front())
+					}
+					break
+				}
+			}
+			sort.Sort(p.pairPositions)
+			// if we get here, the closing bracket matched no openers
+			// and gets ignored
+		}
+	}
+}
+
+// Bracket pairs within an isolating run sequence are processed as units so
+// that both the opening and the closing paired bracket in a pair resolve to
+// the same direction.
+//
+// N0. Process bracket pairs in an isolating run sequence sequentially in
+// the logical order of the text positions of the opening paired brackets
+// using the logic given below. Within this scope, bidirectional types EN
+// and AN are treated as R.
+//
+// Identify the bracket pairs in the current isolating run sequence
+// according to BD16. For each bracket-pair element in the list of pairs of
+// text positions:
+//
+// a Inspect the bidirectional types of the characters enclosed within the
+// bracket pair.
+//
+// b If any strong type (either L or R) matching the embedding direction is
+// found, set the type for both brackets in the pair to match the embedding
+// direction.
+//
+// o [ e ] o -> o e e e o
+//
+// o [ o e ] -> o e o e e
+//
+// o [ NI e ] -> o e NI e e
+//
+// c Otherwise, if a strong type (opposite the embedding direction) is
+// found, test for adjacent strong types as follows: 1 First, check
+// backwards before the opening paired bracket until the first strong type
+// (L, R, or sos) is found. If that first preceding strong type is opposite
+// the embedding direction, then set the type for both brackets in the pair
+// to that type. 2 Otherwise, set the type for both brackets in the pair to
+// the embedding direction.
+//
+// o [ o ] e -> o o o o e
+//
+// o [ o NI ] o -> o o o NI o o
+//
+// e [ o ] o -> e e o e o
+//
+// e [ o ] e -> e e o e e
+//
+// e ( o [ o ] NI ) e -> e e o o o o NI e e
+//
+// d Otherwise, do not set the type for the current bracket pair. Note that
+// if the enclosed text contains no strong types the paired brackets will
+// both resolve to the same level when resolved individually using rules N1
+// and N2.
+//
+// e ( NI ) o -> e ( NI ) o
+
+// getStrongTypeN0 maps character's directional code to strong type as required
+// by rule N0.
+//
+// TODO: have separate type for "strong" directionality.
+func (p *bracketPairer) getStrongTypeN0(index int) Class {
+	switch p.codesIsolatedRun[index] {
+	// in the scope of N0, number types are treated as R
+	case EN, AN, AL, R:
+		return R
+	case L:
+		return L
+	default:
+		return ON
+	}
+}
+
+// classifyPairContent reports the strong types contained inside a Bracket Pair,
+// assuming the given embedding direction.
+//
+// It returns ON if no strong type is found. If a single strong type is found,
+// it returns this this type. Otherwise it returns the embedding direction.
+//
+// TODO: use separate type for "strong" directionality.
+func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
+	dirOpposite := ON
+	for i := loc.opener + 1; i < loc.closer; i++ {
+		dir := p.getStrongTypeN0(i)
+		if dir == ON {
+			continue
+		}
+		if dir == dirEmbed {
+			return dir // type matching embedding direction found
+		}
+		dirOpposite = dir
+	}
+	// return ON if no strong type found, or class opposite to dirEmbed
+	return dirOpposite
+}
+
+// classBeforePair determines which strong types are present before a Bracket
+// Pair. Return R or L if strong type found, otherwise ON.
+func (p *bracketPairer) classBeforePair(loc bracketPair) Class {
+	for i := loc.opener - 1; i >= 0; i-- {
+		if dir := p.getStrongTypeN0(i); dir != ON {
+			return dir
+		}
+	}
+	// no strong types found, return sos
+	return p.sos
+}
+
+// assignBracketType implements rule N0 for a single bracket pair.
+func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initialTypes []Class) {
+	// rule "N0, a", inspect contents of pair
+	dirPair := p.classifyPairContent(loc, dirEmbed)
+
+	// dirPair is now L, R, or N (no strong type found)
+
+	// the following logical tests are performed out of order compared to
+	// the statement of the rules but yield the same results
+	if dirPair == ON {
+		return // case "d" - nothing to do
+	}
+
+	if dirPair != dirEmbed {
+		// case "c": strong type found, opposite - check before (c.1)
+		dirPair = p.classBeforePair(loc)
+		if dirPair == dirEmbed || dirPair == ON {
+			// no strong opposite type found before - use embedding (c.2)
+			dirPair = dirEmbed
+		}
+	}
+	// else: case "b", strong type found matching embedding,
+	// no explicit action needed, as dirPair is already set to embedding
+	// direction
+
+	// set the bracket types to the type found
+	p.setBracketsToType(loc, dirPair, initialTypes)
+}
+
+func (p *bracketPairer) setBracketsToType(loc bracketPair, dirPair Class, initialTypes []Class) {
+	p.codesIsolatedRun[loc.opener] = dirPair
+	p.codesIsolatedRun[loc.closer] = dirPair
+
+	for i := loc.opener + 1; i < loc.closer; i++ {
+		index := p.indexes[i]
+		if initialTypes[index] != NSM {
+			break
+		}
+		p.codesIsolatedRun[i] = dirPair
+	}
+
+	for i := loc.closer + 1; i < len(p.indexes); i++ {
+		index := p.indexes[i]
+		if initialTypes[index] != NSM {
+			break
+		}
+		p.codesIsolatedRun[i] = dirPair
+	}
+}
+
+// resolveBrackets implements rule N0 for a list of pairs.
+func (p *bracketPairer) resolveBrackets(dirEmbed Class, initialTypes []Class) {
+	for _, loc := range p.pairPositions {
+		p.assignBracketType(loc, dirEmbed, initialTypes)
+	}
+}
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/core.go b/src/vendor/golang_org/x/text/unicode/bidi/core.go
new file mode 100644
index 0000000..a352ad6
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/core.go
@@ -0,0 +1,1060 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bidi
+
+import "log"
+
+// This implementation is a port based on the reference implementation found at:
+// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
+//
+// described in Unicode Bidirectional Algorithm (UAX #9).
+//
+// Input:
+// There are two levels of input to the algorithm, since clients may prefer to
+// supply some information from out-of-band sources rather than relying on the
+// default behavior.
+//
+// - Bidi class array
+// - Bidi class array, with externally supplied base line direction
+//
+// Output:
+// Output is separated into several stages:
+//
+//  - levels array over entire paragraph
+//  - reordering array over entire paragraph
+//  - levels array over line
+//  - reordering array over line
+//
+// Note that for conformance to the Unicode Bidirectional Algorithm,
+// implementations are only required to generate correct reordering and
+// character directionality (odd or even levels) over a line. Generating
+// identical level arrays over a line is not required. Bidi explicit format
+// codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned arbitrary levels and
+// positions as long as the rest of the input is properly reordered.
+//
+// As the algorithm is defined to operate on a single paragraph at a time, this
+// implementation is written to handle single paragraphs. Thus rule P1 is
+// presumed by this implementation-- the data provided to the implementation is
+// assumed to be a single paragraph, and either contains no 'B' codes, or a
+// single 'B' code at the end of the input. 'B' is allowed as input to
+// illustrate how the algorithm assigns it a level.
+//
+// Also note that rules L3 and L4 depend on the rendering engine that uses the
+// result of the bidi algorithm. This implementation assumes that the rendering
+// engine expects combining marks in visual order (e.g. to the left of their
+// base character in RTL runs) and that it adjusts the glyphs used to render
+// mirrored characters that are in RTL runs so that they render appropriately.
+
+// level is the embedding level of a character. Even embedding levels indicate
+// left-to-right order and odd levels indicate right-to-left order. The special
+// level of -1 is reserved for undefined order.
+type level int8
+
+const implicitLevel level = -1
+
+// in returns if x is equal to any of the values in set.
+func (c Class) in(set ...Class) bool {
+	for _, s := range set {
+		if c == s {
+			return true
+		}
+	}
+	return false
+}
+
+// A paragraph contains the state of a paragraph.
+type paragraph struct {
+	initialTypes []Class
+
+	// Arrays of properties needed for paired bracket evaluation in N0
+	pairTypes  []bracketType // paired Bracket types for paragraph
+	pairValues []rune        // rune for opening bracket or pbOpen and pbClose; 0 for pbNone
+
+	embeddingLevel level // default: = implicitLevel;
+
+	// at the paragraph levels
+	resultTypes  []Class
+	resultLevels []level
+
+	// Index of matching PDI for isolate initiator characters. For other
+	// characters, the value of matchingPDI will be set to -1. For isolate
+	// initiators with no matching PDI, matchingPDI will be set to the length of
+	// the input string.
+	matchingPDI []int
+
+	// Index of matching isolate initiator for PDI characters. For other
+	// characters, and for PDIs with no matching isolate initiator, the value of
+	// matchingIsolateInitiator will be set to -1.
+	matchingIsolateInitiator []int
+}
+
+// newParagraph initializes a paragraph. The user needs to supply a few arrays
+// corresponding to the preprocessed text input. The types correspond to the
+// Unicode BiDi classes for each rune. pairTypes indicates the bracket type for
+// each rune. pairValues provides a unique bracket class identifier for each
+// rune (suggested is the rune of the open bracket for opening and matching
+// close brackets, after normalization). The embedding levels are optional, but
+// may be supplied to encode embedding levels of styled text.
+//
+// TODO: return an error.
+func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) *paragraph {
+	validateTypes(types)
+	validatePbTypes(pairTypes)
+	validatePbValues(pairValues, pairTypes)
+	validateParagraphEmbeddingLevel(levels)
+
+	p := &paragraph{
+		initialTypes:   append([]Class(nil), types...),
+		embeddingLevel: levels,
+
+		pairTypes:  pairTypes,
+		pairValues: pairValues,
+
+		resultTypes: append([]Class(nil), types...),
+	}
+	p.run()
+	return p
+}
+
+func (p *paragraph) Len() int { return len(p.initialTypes) }
+
+// The algorithm. Does not include line-based processing (Rules L1, L2).
+// These are applied later in the line-based phase of the algorithm.
+func (p *paragraph) run() {
+	p.determineMatchingIsolates()
+
+	// 1) determining the paragraph level
+	// Rule P1 is the requirement for entering this algorithm.
+	// Rules P2, P3.
+	// If no externally supplied paragraph embedding level, use default.
+	if p.embeddingLevel == implicitLevel {
+		p.embeddingLevel = p.determineParagraphEmbeddingLevel(0, p.Len())
+	}
+
+	// Initialize result levels to paragraph embedding level.
+	p.resultLevels = make([]level, p.Len())
+	setLevels(p.resultLevels, p.embeddingLevel)
+
+	// 2) Explicit levels and directions
+	// Rules X1-X8.
+	p.determineExplicitEmbeddingLevels()
+
+	// Rule X9.
+	// We do not remove the embeddings, the overrides, the PDFs, and the BNs
+	// from the string explicitly. But they are not copied into isolating run
+	// sequences when they are created, so they are removed for all
+	// practical purposes.
+
+	// Rule X10.
+	// Run remainder of algorithm one isolating run sequence at a time
+	for _, seq := range p.determineIsolatingRunSequences() {
+		// 3) resolving weak types
+		// Rules W1-W7.
+		seq.resolveWeakTypes()
+
+		// 4a) resolving paired brackets
+		// Rule N0
+		resolvePairedBrackets(seq)
+
+		// 4b) resolving neutral types
+		// Rules N1-N3.
+		seq.resolveNeutralTypes()
+
+		// 5) resolving implicit embedding levels
+		// Rules I1, I2.
+		seq.resolveImplicitLevels()
+
+		// Apply the computed levels and types
+		seq.applyLevelsAndTypes()
+	}
+
+	// Assign appropriate levels to 'hide' LREs, RLEs, LROs, RLOs, PDFs, and
+	// BNs. This is for convenience, so the resulting level array will have
+	// a value for every character.
+	p.assignLevelsToCharactersRemovedByX9()
+}
+
+// determineMatchingIsolates determines the matching PDI for each isolate
+// initiator and vice versa.
+//
+// Definition BD9.
+//
+// At the end of this function:
+//
+//  - The member variable matchingPDI is set to point to the index of the
+//    matching PDI character for each isolate initiator character. If there is
+//    no matching PDI, it is set to the length of the input text. For other
+//    characters, it is set to -1.
+//  - The member variable matchingIsolateInitiator is set to point to the
+//    index of the matching isolate initiator character for each PDI character.
+//    If there is no matching isolate initiator, or the character is not a PDI,
+//    it is set to -1.
+func (p *paragraph) determineMatchingIsolates() {
+	p.matchingPDI = make([]int, p.Len())
+	p.matchingIsolateInitiator = make([]int, p.Len())
+
+	for i := range p.matchingIsolateInitiator {
+		p.matchingIsolateInitiator[i] = -1
+	}
+
+	for i := range p.matchingPDI {
+		p.matchingPDI[i] = -1
+
+		if t := p.resultTypes[i]; t.in(LRI, RLI, FSI) {
+			depthCounter := 1
+			for j := i + 1; j < p.Len(); j++ {
+				if u := p.resultTypes[j]; u.in(LRI, RLI, FSI) {
+					depthCounter++
+				} else if u == PDI {
+					if depthCounter--; depthCounter == 0 {
+						p.matchingPDI[i] = j
+						p.matchingIsolateInitiator[j] = i
+						break
+					}
+				}
+			}
+			if p.matchingPDI[i] == -1 {
+				p.matchingPDI[i] = p.Len()
+			}
+		}
+	}
+}
+
+// determineParagraphEmbeddingLevel reports the resolved paragraph direction of
+// the substring limited by the given range [start, end).
+//
+// Determines the paragraph level based on rules P2, P3. This is also used
+// in rule X5c to find if an FSI should resolve to LRI or RLI.
+func (p *paragraph) determineParagraphEmbeddingLevel(start, end int) level {
+	var strongType Class = unknownClass
+
+	// Rule P2.
+	for i := start; i < end; i++ {
+		if t := p.resultTypes[i]; t.in(L, AL, R) {
+			strongType = t
+			break
+		} else if t.in(FSI, LRI, RLI) {
+			i = p.matchingPDI[i] // skip over to the matching PDI
+			if i > end {
+				log.Panic("assert (i <= end)")
+			}
+		}
+	}
+	// Rule P3.
+	switch strongType {
+	case unknownClass: // none found
+		// default embedding level when no strong types found is 0.
+		return 0
+	case L:
+		return 0
+	default: // AL, R
+		return 1
+	}
+}
+
+const maxDepth = 125
+
+// This stack will store the embedding levels and override and isolated
+// statuses
+type directionalStatusStack struct {
+	stackCounter        int
+	embeddingLevelStack [maxDepth + 1]level
+	overrideStatusStack [maxDepth + 1]Class
+	isolateStatusStack  [maxDepth + 1]bool
+}
+
+func (s *directionalStatusStack) empty()     { s.stackCounter = 0 }
+func (s *directionalStatusStack) pop()       { s.stackCounter-- }
+func (s *directionalStatusStack) depth() int { return s.stackCounter }
+
+func (s *directionalStatusStack) push(level level, overrideStatus Class, isolateStatus bool) {
+	s.embeddingLevelStack[s.stackCounter] = level
+	s.overrideStatusStack[s.stackCounter] = overrideStatus
+	s.isolateStatusStack[s.stackCounter] = isolateStatus
+	s.stackCounter++
+}
+
+func (s *directionalStatusStack) lastEmbeddingLevel() level {
+	return s.embeddingLevelStack[s.stackCounter-1]
+}
+
+func (s *directionalStatusStack) lastDirectionalOverrideStatus() Class {
+	return s.overrideStatusStack[s.stackCounter-1]
+}
+
+func (s *directionalStatusStack) lastDirectionalIsolateStatus() bool {
+	return s.isolateStatusStack[s.stackCounter-1]
+}
+
+// Determine explicit levels using rules X1 - X8
+func (p *paragraph) determineExplicitEmbeddingLevels() {
+	var stack directionalStatusStack
+	var overflowIsolateCount, overflowEmbeddingCount, validIsolateCount int
+
+	// Rule X1.
+	stack.push(p.embeddingLevel, ON, false)
+
+	for i, t := range p.resultTypes {
+		// Rules X2, X3, X4, X5, X5a, X5b, X5c
+		switch t {
+		case RLE, LRE, RLO, LRO, RLI, LRI, FSI:
+			isIsolate := t.in(RLI, LRI, FSI)
+			isRTL := t.in(RLE, RLO, RLI)
+
+			// override if this is an FSI that resolves to RLI
+			if t == FSI {
+				isRTL = (p.determineParagraphEmbeddingLevel(i+1, p.matchingPDI[i]) == 1)
+			}
+			if isIsolate {
+				p.resultLevels[i] = stack.lastEmbeddingLevel()
+				if stack.lastDirectionalOverrideStatus() != ON {
+					p.resultTypes[i] = stack.lastDirectionalOverrideStatus()
+				}
+			}
+
+			var newLevel level
+			if isRTL {
+				// least greater odd
+				newLevel = (stack.lastEmbeddingLevel() + 1) | 1
+			} else {
+				// least greater even
+				newLevel = (stack.lastEmbeddingLevel() + 2) &^ 1
+			}
+
+			if newLevel <= maxDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0 {
+				if isIsolate {
+					validIsolateCount++
+				}
+				// Push new embedding level, override status, and isolated
+				// status.
+				// No check for valid stack counter, since the level check
+				// suffices.
+				switch t {
+				case LRO:
+					stack.push(newLevel, L, isIsolate)
+				case RLO:
+					stack.push(newLevel, R, isIsolate)
+				default:
+					stack.push(newLevel, ON, isIsolate)
+				}
+				// Not really part of the spec
+				if !isIsolate {
+					p.resultLevels[i] = newLevel
+				}
+			} else {
+				// This is an invalid explicit formatting character,
+				// so apply the "Otherwise" part of rules X2-X5b.
+				if isIsolate {
+					overflowIsolateCount++
+				} else { // !isIsolate
+					if overflowIsolateCount == 0 {
+						overflowEmbeddingCount++
+					}
+				}
+			}
+
+		// Rule X6a
+		case PDI:
+			if overflowIsolateCount > 0 {
+				overflowIsolateCount--
+			} else if validIsolateCount == 0 {
+				// do nothing
+			} else {
+				overflowEmbeddingCount = 0
+				for !stack.lastDirectionalIsolateStatus() {
+					stack.pop()
+				}
+				stack.pop()
+				validIsolateCount--
+			}
+			p.resultLevels[i] = stack.lastEmbeddingLevel()
+
+		// Rule X7
+		case PDF:
+			// Not really part of the spec
+			p.resultLevels[i] = stack.lastEmbeddingLevel()
+
+			if overflowIsolateCount > 0 {
+				// do nothing
+			} else if overflowEmbeddingCount > 0 {
+				overflowEmbeddingCount--
+			} else if !stack.lastDirectionalIsolateStatus() && stack.depth() >= 2 {
+				stack.pop()
+			}
+
+		case B: // paragraph separator.
+			// Rule X8.
+
+			// These values are reset for clarity, in this implementation B
+			// can only occur as the last code in the array.
+			stack.empty()
+			overflowIsolateCount = 0
+			overflowEmbeddingCount = 0
+			validIsolateCount = 0
+			p.resultLevels[i] = p.embeddingLevel
+
+		default:
+			p.resultLevels[i] = stack.lastEmbeddingLevel()
+			if stack.lastDirectionalOverrideStatus() != ON {
+				p.resultTypes[i] = stack.lastDirectionalOverrideStatus()
+			}
+		}
+	}
+}
+
+type isolatingRunSequence struct {
+	p *paragraph
+
+	indexes []int // indexes to the original string
+
+	types          []Class // type of each character using the index
+	resolvedLevels []level // resolved levels after application of rules
+	level          level
+	sos, eos       Class
+}
+
+func (i *isolatingRunSequence) Len() int { return len(i.indexes) }
+
+func maxLevel(a, b level) level {
+	if a > b {
+		return a
+	}
+	return b
+}
+
+// Rule X10, second bullet: Determine the start-of-sequence (sos) and end-of-sequence (eos) types,
+// 			 either L or R, for each isolating run sequence.
+func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence {
+	length := len(indexes)
+	types := make([]Class, length)
+	for i, x := range indexes {
+		types[i] = p.resultTypes[x]
+	}
+
+	// assign level, sos and eos
+	prevChar := indexes[0] - 1
+	for prevChar >= 0 && isRemovedByX9(p.initialTypes[prevChar]) {
+		prevChar--
+	}
+	prevLevel := p.embeddingLevel
+	if prevChar >= 0 {
+		prevLevel = p.resultLevels[prevChar]
+	}
+
+	var succLevel level
+	lastType := types[length-1]
+	if lastType.in(LRI, RLI, FSI) {
+		succLevel = p.embeddingLevel
+	} else {
+		// the first character after the end of run sequence
+		limit := indexes[length-1] + 1
+		for ; limit < p.Len() && isRemovedByX9(p.initialTypes[limit]); limit++ {
+
+		}
+		succLevel = p.embeddingLevel
+		if limit < p.Len() {
+			succLevel = p.resultLevels[limit]
+		}
+	}
+	level := p.resultLevels[indexes[0]]
+	return &isolatingRunSequence{
+		p:       p,
+		indexes: indexes,
+		types:   types,
+		level:   level,
+		sos:     typeForLevel(maxLevel(prevLevel, level)),
+		eos:     typeForLevel(maxLevel(succLevel, level)),
+	}
+}
+
+// Resolving weak types Rules W1-W7.
+//
+// Note that some weak types (EN, AN) remain after this processing is
+// complete.
+func (s *isolatingRunSequence) resolveWeakTypes() {
+
+	// on entry, only these types remain
+	s.assertOnly(L, R, AL, EN, ES, ET, AN, CS, B, S, WS, ON, NSM, LRI, RLI, FSI, PDI)
+
+	// Rule W1.
+	// Changes all NSMs.
+	preceedingCharacterType := s.sos
+	for i, t := range s.types {
+		if t == NSM {
+			s.types[i] = preceedingCharacterType
+		} else {
+			if t.in(LRI, RLI, FSI, PDI) {
+				preceedingCharacterType = ON
+			}
+			preceedingCharacterType = t
+		}
+	}
+
+	// Rule W2.
+	// EN does not change at the start of the run, because sos != AL.
+	for i, t := range s.types {
+		if t == EN {
+			for j := i - 1; j >= 0; j-- {
+				if t := s.types[j]; t.in(L, R, AL) {
+					if t == AL {
+						s.types[i] = AN
+					}
+					break
+				}
+			}
+		}
+	}
+
+	// Rule W3.
+	for i, t := range s.types {
+		if t == AL {
+			s.types[i] = R
+		}
+	}
+
+	// Rule W4.
+	// Since there must be values on both sides for this rule to have an
+	// effect, the scan skips the first and last value.
+	//
+	// Although the scan proceeds left to right, and changes the type
+	// values in a way that would appear to affect the computations
+	// later in the scan, there is actually no problem. A change in the
+	// current value can only affect the value to its immediate right,
+	// and only affect it if it is ES or CS. But the current value can
+	// only change if the value to its right is not ES or CS. Thus
+	// either the current value will not change, or its change will have
+	// no effect on the remainder of the analysis.
+
+	for i := 1; i < s.Len()-1; i++ {
+		t := s.types[i]
+		if t == ES || t == CS {
+			prevSepType := s.types[i-1]
+			succSepType := s.types[i+1]
+			if prevSepType == EN && succSepType == EN {
+				s.types[i] = EN
+			} else if s.types[i] == CS && prevSepType == AN && succSepType == AN {
+				s.types[i] = AN
+			}
+		}
+	}
+
+	// Rule W5.
+	for i, t := range s.types {
+		if t == ET {
+			// locate end of sequence
+			runStart := i
+			runEnd := s.findRunLimit(runStart, ET)
+
+			// check values at ends of sequence
+			t := s.sos
+			if runStart > 0 {
+				t = s.types[runStart-1]
+			}
+			if t != EN {
+				t = s.eos
+				if runEnd < len(s.types) {
+					t = s.types[runEnd]
+				}
+			}
+			if t == EN {
+				setTypes(s.types[runStart:runEnd], EN)
+			}
+			// continue at end of sequence
+			i = runEnd
+		}
+	}
+
+	// Rule W6.
+	for i, t := range s.types {
+		if t.in(ES, ET, CS) {
+			s.types[i] = ON
+		}
+	}
+
+	// Rule W7.
+	for i, t := range s.types {
+		if t == EN {
+			// set default if we reach start of run
+			prevStrongType := s.sos
+			for j := i - 1; j >= 0; j-- {
+				t = s.types[j]
+				if t == L || t == R { // AL's have been changed to R
+					prevStrongType = t
+					break
+				}
+			}
+			if prevStrongType == L {
+				s.types[i] = L
+			}
+		}
+	}
+}
+
+// 6) resolving neutral types Rules N1-N2.
+func (s *isolatingRunSequence) resolveNeutralTypes() {
+
+	// on entry, only these types can be in resultTypes
+	s.assertOnly(L, R, EN, AN, B, S, WS, ON, RLI, LRI, FSI, PDI)
+
+	for i, t := range s.types {
+		switch t {
+		case WS, ON, B, S, RLI, LRI, FSI, PDI:
+			// find bounds of run of neutrals
+			runStart := i
+			runEnd := s.findRunLimit(runStart, B, S, WS, ON, RLI, LRI, FSI, PDI)
+
+			// determine effective types at ends of run
+			var leadType, trailType Class
+
+			// Note that the character found can only be L, R, AN, or
+			// EN.
+			if runStart == 0 {
+				leadType = s.sos
+			} else {
+				leadType = s.types[runStart-1]
+				if leadType.in(AN, EN) {
+					leadType = R
+				}
+			}
+			if runEnd == len(s.types) {
+				trailType = s.eos
+			} else {
+				trailType = s.types[runEnd]
+				if trailType.in(AN, EN) {
+					trailType = R
+				}
+			}
+
+			var resolvedType Class
+			if leadType == trailType {
+				// Rule N1.
+				resolvedType = leadType
+			} else {
+				// Rule N2.
+				// Notice the embedding level of the run is used, not
+				// the paragraph embedding level.
+				resolvedType = typeForLevel(s.level)
+			}
+
+			setTypes(s.types[runStart:runEnd], resolvedType)
+
+			// skip over run of (former) neutrals
+			i = runEnd
+		}
+	}
+}
+
+func setLevels(levels []level, newLevel level) {
+	for i := range levels {
+		levels[i] = newLevel
+	}
+}
+
+func setTypes(types []Class, newType Class) {
+	for i := range types {
+		types[i] = newType
+	}
+}
+
+// 7) resolving implicit embedding levels Rules I1, I2.
+func (s *isolatingRunSequence) resolveImplicitLevels() {
+
+	// on entry, only these types can be in resultTypes
+	s.assertOnly(L, R, EN, AN)
+
+	s.resolvedLevels = make([]level, len(s.types))
+	setLevels(s.resolvedLevels, s.level)
+
+	if (s.level & 1) == 0 { // even level
+		for i, t := range s.types {
+			// Rule I1.
+			if t == L {
+				// no change
+			} else if t == R {
+				s.resolvedLevels[i] += 1
+			} else { // t == AN || t == EN
+				s.resolvedLevels[i] += 2
+			}
+		}
+	} else { // odd level
+		for i, t := range s.types {
+			// Rule I2.
+			if t == R {
+				// no change
+			} else { // t == L || t == AN || t == EN
+				s.resolvedLevels[i] += 1
+			}
+		}
+	}
+}
+
+// Applies the levels and types resolved in rules W1-I2 to the
+// resultLevels array.
+func (s *isolatingRunSequence) applyLevelsAndTypes() {
+	for i, x := range s.indexes {
+		s.p.resultTypes[x] = s.types[i]
+		s.p.resultLevels[x] = s.resolvedLevels[i]
+	}
+}
+
+// Return the limit of the run consisting only of the types in validSet
+// starting at index. This checks the value at index, and will return
+// index if that value is not in validSet.
+func (s *isolatingRunSequence) findRunLimit(index int, validSet ...Class) int {
+loop:
+	for ; index < len(s.types); index++ {
+		t := s.types[index]
+		for _, valid := range validSet {
+			if t == valid {
+				continue loop
+			}
+		}
+		return index // didn't find a match in validSet
+	}
+	return len(s.types)
+}
+
+// Algorithm validation. Assert that all values in types are in the
+// provided set.
+func (s *isolatingRunSequence) assertOnly(codes ...Class) {
+loop:
+	for i, t := range s.types {
+		for _, c := range codes {
+			if t == c {
+				continue loop
+			}
+		}
+		log.Panicf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i])
+	}
+}
+
+// determineLevelRuns returns an array of level runs. Each level run is
+// described as an array of indexes into the input string.
+//
+// Determines the level runs. Rule X9 will be applied in determining the
+// runs, in the way that makes sure the characters that are supposed to be
+// removed are not included in the runs.
+func (p *paragraph) determineLevelRuns() [][]int {
+	run := []int{}
+	allRuns := [][]int{}
+	currentLevel := implicitLevel
+
+	for i := range p.initialTypes {
+		if !isRemovedByX9(p.initialTypes[i]) {
+			if p.resultLevels[i] != currentLevel {
+				// we just encountered a new run; wrap up last run
+				if currentLevel >= 0 { // only wrap it up if there was a run
+					allRuns = append(allRuns, run)
+					run = nil
+				}
+				// Start new run
+				currentLevel = p.resultLevels[i]
+			}
+			run = append(run, i)
+		}
+	}
+	// Wrap up the final run, if any
+	if len(run) > 0 {
+		allRuns = append(allRuns, run)
+	}
+	return allRuns
+}
+
+// Definition BD13. Determine isolating run sequences.
+func (p *paragraph) determineIsolatingRunSequences() []*isolatingRunSequence {
+	levelRuns := p.determineLevelRuns()
+
+	// Compute the run that each character belongs to
+	runForCharacter := make([]int, p.Len())
+	for i, run := range levelRuns {
+		for _, index := range run {
+			runForCharacter[index] = i
+		}
+	}
+
+	sequences := []*isolatingRunSequence{}
+
+	var currentRunSequence []int
+
+	for _, run := range levelRuns {
+		first := run[0]
+		if p.initialTypes[first] != PDI || p.matchingIsolateInitiator[first] == -1 {
+			currentRunSequence = nil
+			// int run = i;
+			for {
+				// Copy this level run into currentRunSequence
+				currentRunSequence = append(currentRunSequence, run...)
+
+				last := currentRunSequence[len(currentRunSequence)-1]
+				lastT := p.initialTypes[last]
+				if lastT.in(LRI, RLI, FSI) && p.matchingPDI[last] != p.Len() {
+					run = levelRuns[runForCharacter[p.matchingPDI[last]]]
+				} else {
+					break
+				}
+			}
+			sequences = append(sequences, p.isolatingRunSequence(currentRunSequence))
+		}
+	}
+	return sequences
+}
+
+// Assign level information to characters removed by rule X9. This is for
+// ease of relating the level information to the original input data. Note
+// that the levels assigned to these codes are arbitrary, they're chosen so
+// as to avoid breaking level runs.
+func (p *paragraph) assignLevelsToCharactersRemovedByX9() {
+	for i, t := range p.initialTypes {
+		if t.in(LRE, RLE, LRO, RLO, PDF, BN) {
+			p.resultTypes[i] = t
+			p.resultLevels[i] = -1
+		}
+	}
+	// now propagate forward the levels information (could have
+	// propagated backward, the main thing is not to introduce a level
+	// break where one doesn't already exist).
+
+	if p.resultLevels[0] == -1 {
+		p.resultLevels[0] = p.embeddingLevel
+	}
+	for i := 1; i < len(p.initialTypes); i++ {
+		if p.resultLevels[i] == -1 {
+			p.resultLevels[i] = p.resultLevels[i-1]
+		}
+	}
+	// Embedding information is for informational purposes only so need not be
+	// adjusted.
+}
+
+//
+// Output
+//
+
+// getLevels computes levels array breaking lines at offsets in linebreaks.
+// Rule L1.
+//
+// The linebreaks array must include at least one value. The values must be
+// in strictly increasing order (no duplicates) between 1 and the length of
+// the text, inclusive. The last value must be the length of the text.
+func (p *paragraph) getLevels(linebreaks []int) []level {
+	// Note that since the previous processing has removed all
+	// P, S, and WS values from resultTypes, the values referred to
+	// in these rules are the initial types, before any processing
+	// has been applied (including processing of overrides).
+	//
+	// This example implementation has reinserted explicit format codes
+	// and BN, in order that the levels array correspond to the
+	// initial text. Their final placement is not normative.
+	// These codes are treated like WS in this implementation,
+	// so they don't interrupt sequences of WS.
+
+	validateLineBreaks(linebreaks, p.Len())
+
+	result := append([]level(nil), p.resultLevels...)
+
+	// don't worry about linebreaks since if there is a break within
+	// a series of WS values preceding S, the linebreak itself
+	// causes the reset.
+	for i, t := range p.initialTypes {
+		if t.in(B, S) {
+			// Rule L1, clauses one and two.
+			result[i] = p.embeddingLevel
+
+			// Rule L1, clause three.
+			for j := i - 1; j >= 0; j-- {
+				if isWhitespace(p.initialTypes[j]) { // including format codes
+					result[j] = p.embeddingLevel
+				} else {
+					break
+				}
+			}
+		}
+	}
+
+	// Rule L1, clause four.
+	start := 0
+	for _, limit := range linebreaks {
+		for j := limit - 1; j >= start; j-- {
+			if isWhitespace(p.initialTypes[j]) { // including format codes
+				result[j] = p.embeddingLevel
+			} else {
+				break
+			}
+		}
+		start = limit
+	}
+
+	return result
+}
+
+// getReordering returns the reordering of lines from a visual index to a
+// logical index for line breaks at the given offsets.
+//
+// Lines are concatenated from left to right. So for example, the fifth
+// character from the left on the third line is
+//
+// 		getReordering(linebreaks)[linebreaks[1] + 4]
+//
+// (linebreaks[1] is the position after the last character of the second
+// line, which is also the index of the first character on the third line,
+// and adding four gets the fifth character from the left).
+//
+// The linebreaks array must include at least one value. The values must be
+// in strictly increasing order (no duplicates) between 1 and the length of
+// the text, inclusive. The last value must be the length of the text.
+func (p *paragraph) getReordering(linebreaks []int) []int {
+	validateLineBreaks(linebreaks, p.Len())
+
+	return computeMultilineReordering(p.getLevels(linebreaks), linebreaks)
+}
+
+// Return multiline reordering array for a given level array. Reordering
+// does not occur across a line break.
+func computeMultilineReordering(levels []level, linebreaks []int) []int {
+	result := make([]int, len(levels))
+
+	start := 0
+	for _, limit := range linebreaks {
+		tempLevels := make([]level, limit-start)
+		copy(tempLevels, levels[start:])
+
+		for j, order := range computeReordering(tempLevels) {
+			result[start+j] = order + start
+		}
+		start = limit
+	}
+	return result
+}
+
+// Return reordering array for a given level array. This reorders a single
+// line. The reordering is a visual to logical map. For example, the
+// leftmost char is string.charAt(order[0]). Rule L2.
+func computeReordering(levels []level) []int {
+	result := make([]int, len(levels))
+	// initialize order
+	for i := range result {
+		result[i] = i
+	}
+
+	// locate highest level found on line.
+	// Note the rules say text, but no reordering across line bounds is
+	// performed, so this is sufficient.
+	highestLevel := level(0)
+	lowestOddLevel := level(maxDepth + 2)
+	for _, level := range levels {
+		if level > highestLevel {
+			highestLevel = level
+		}
+		if level&1 != 0 && level < lowestOddLevel {
+			lowestOddLevel = level
+		}
+	}
+
+	for level := highestLevel; level >= lowestOddLevel; level-- {
+		for i := 0; i < len(levels); i++ {
+			if levels[i] >= level {
+				// find range of text at or above this level
+				start := i
+				limit := i + 1
+				for limit < len(levels) && levels[limit] >= level {
+					limit++
+				}
+
+				for j, k := start, limit-1; j < k; j, k = j+1, k-1 {
+					result[j], result[k] = result[k], result[j]
+				}
+				// skip to end of level run
+				i = limit
+			}
+		}
+	}
+
+	return result
+}
+
+// isWhitespace reports whether the type is considered a whitespace type for the
+// line break rules.
+func isWhitespace(c Class) bool {
+	switch c {
+	case LRE, RLE, LRO, RLO, PDF, LRI, RLI, FSI, PDI, BN, WS:
+		return true
+	}
+	return false
+}
+
+// isRemovedByX9 reports whether the type is one of the types removed in X9.
+func isRemovedByX9(c Class) bool {
+	switch c {
+	case LRE, RLE, LRO, RLO, PDF, BN:
+		return true
+	}
+	return false
+}
+
+// typeForLevel reports the strong type (L or R) corresponding to the level.
+func typeForLevel(level level) Class {
+	if (level & 0x1) == 0 {
+		return L
+	}
+	return R
+}
+
+// TODO: change validation to not panic
+
+func validateTypes(types []Class) {
+	if len(types) == 0 {
+		log.Panic("types is null")
+	}
+	for i, t := range types[:len(types)-1] {
+		if t == B {
+			log.Panicf("B type before end of paragraph at index: %d", i)
+		}
+	}
+}
+
+func validateParagraphEmbeddingLevel(embeddingLevel level) {
+	if embeddingLevel != implicitLevel &&
+		embeddingLevel != 0 &&
+		embeddingLevel != 1 {
+		log.Panicf("illegal paragraph embedding level: %d", embeddingLevel)
+	}
+}
+
+func validateLineBreaks(linebreaks []int, textLength int) {
+	prev := 0
+	for i, next := range linebreaks {
+		if next <= prev {
+			log.Panicf("bad linebreak: %d at index: %d", next, i)
+		}
+		prev = next
+	}
+	if prev != textLength {
+		log.Panicf("last linebreak was %d, want %d", prev, textLength)
+	}
+}
+
+func validatePbTypes(pairTypes []bracketType) {
+	if len(pairTypes) == 0 {
+		log.Panic("pairTypes is null")
+	}
+	for i, pt := range pairTypes {
+		switch pt {
+		case bpNone, bpOpen, bpClose:
+		default:
+			log.Panicf("illegal pairType value at %d: %v", i, pairTypes[i])
+		}
+	}
+}
+
+func validatePbValues(pairValues []rune, pairTypes []bracketType) {
+	if pairValues == nil {
+		log.Panic("pairValues is null")
+	}
+	if len(pairTypes) != len(pairValues) {
+		log.Panic("pairTypes is different length from pairValues")
+	}
+}
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/example_test.go b/src/vendor/golang_org/x/text/unicode/bidi/example_test.go
new file mode 100644
index 0000000..e173959
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/example_test.go
@@ -0,0 +1,185 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// +build ignore
+
+package bidi_test
+
+import (
+	"fmt"
+	"log"
+
+	"golang_org/x/text/bidi"
+)
+
+func foo() {
+	var sa StringAttributes
+	var p Paragraph
+	n, _ := p.SetString(s)
+	for i, o := 0, p.Ordering(); i < o.NumRuns(); i++ {
+		b := o.Run(i).Bytes()
+
+		start, end := o.Run(i).Pos()
+		for p := start; p < end; {
+			style, n := sa.StyleAt(start)
+			render()
+			p += n
+		}
+
+	}
+}
+
+type style int
+
+const (
+	styleNormal   = 0
+	styleSelected = 1 << (iota - 1)
+	styleBold
+	styleItalics
+)
+
+type styleRun struct {
+	end   int
+	style style
+}
+
+func getTextWidth(text string, styleRuns []styleRun) int {
+	// simplistic way to compute the width
+	return len([]rune(text))
+}
+
+// set limit and StyleRun limit for a line
+// from text[start] and from styleRuns[styleRunStart]
+// using Bidi.getLogicalRun(...)
+// returns line width
+func getLineBreak(p *bidi.Paragraph, start int, styles []styleRun) (n int) {
+	// dummy return
+	return 0
+}
+
+// render runs on a line sequentially, always from left to right
+
+// prepare rendering a new line
+func startLine(d bidi.Direction, lineWidth int) {
+	fmt.Println()
+}
+
+// render a run of text and advance to the right by the run width
+// the text[start..limit-1] is always in logical order
+func renderRun(text string, d bidi.Direction, styl style) {
+}
+
+// We could compute a cross-product
+// from the style runs with the directional runs
+// and then reorder it.
+// Instead, here we iterate over each run type
+// and render the intersections -
+// with shortcuts in simple (and common) cases.
+// renderParagraph() is the main function.
+
+// render a directional run with
+// (possibly) multiple style runs intersecting with it
+func renderDirectionalRun(text string, offset int, d bidi.Direction, styles []styleRun) {
+	start, end := offset, len(text)+offset
+	// iterate over style runs
+	if run.Direction() == bidi.LeftToRight {
+		styleEnd := 0
+		for _, sr := range styles {
+			styleEnd = styleRuns[i].end
+			if start < styleEnd {
+				if styleEnd > end {
+					styleEnd = end
+				}
+				renderRun(text[start-offset:styleEnd-offset], run.Direction(), styles[i].style)
+				if styleEnd == end {
+					break
+				}
+				start = styleEnd
+			}
+		}
+	} else {
+		styleStart := 0
+		for i := len(styles) - 1; i >= 0; i-- {
+			if i > 0 {
+				styleStart = styles[i-1].end
+			} else {
+				styleStart = 0
+			}
+			if end >= styleStart {
+				if styleStart < start {
+					styleStart = start
+				}
+				renderRun(text[styleStart-offset:end-offset], run.Direction(), styles[i].style)
+				if styleStart == start {
+					break
+				}
+				end = styleStart
+			}
+		}
+	}
+}
+
+// the line object represents text[start..limit-1]
+func renderLine(line *bidi.Runs, text string, offset int, styles []styleRun) {
+	if dir := line.Direction(); dir != bidi.Mixed {
+		if len(styles) == 1 {
+			renderRun(text, dir, styles[0].style)
+		} else {
+			for i := 0; i < line.NumRuns(); i++ {
+				renderDirectionalRun(text, offset, dir, styles)
+			}
+		}
+	} else {
+		// iterate over both directional and style runs
+		for i := 0; i < line.Len(); i++ {
+			run := line.Run(i)
+			start, _ := run.Pos()
+			renderDirectionalRun(text[start-offset:], start, run.Direction(), styles)
+		}
+	}
+}
+
+func renderParagraph(text string, d bidi.Direction, styles []styleRun, int lineWidth) {
+	var p bidi.Paragraph
+	if err := p.SetString(text, bidi.DefaultDirection(d)); err != nil {
+		log.Fatal(err)
+	}
+
+	if len(styles) == 0 {
+		styles = append(styles, []styleRun{len(text), styleNormal})
+	}
+
+	if width := getTextWidth(text, styles); width <= lineWidth {
+		// everything fits onto one line
+
+		runs, err := p.Runs()
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		// prepare rendering a new line from either left or right
+		startLine(p.Direction(), width)
+		renderLine(&runs, text, styles)
+	} else {
+		// we need to render several lines
+
+		for start, end := 0, 0; start < len(text); start = end {
+			for start >= styles[0].end {
+				styles = styles[1:]
+			}
+			end = getLineBreak(p, start, styles[startStyles:])
+
+			runs, err := p.Line(start, end)
+			if err != nil {
+				log.Fatal(err)
+			}
+
+			startLine(p.Direction(), end-start)
+			renderLine(&runs, text[start:end], styles[startStyles:])
+		}
+	}
+}
+
+func main() {
+	renderParagraph("Some Latin text...", bidi.LeftToRight, nil, 80)
+	renderParagraph("Some Hebrew text...", bidi.RightToLeft, nil, 60)
+}
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/prop.go b/src/vendor/golang_org/x/text/unicode/bidi/prop.go
new file mode 100644
index 0000000..ed191c2
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/prop.go
@@ -0,0 +1,208 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bidi
+
+import "unicode/utf8"
+
+// Properties provides access to BiDi properties of runes.
+type Properties struct {
+	entry uint8
+	last  uint8
+}
+
+var trie = newBidiTrie(0)
+
+// TODO: using this for bidirule reduces the running time by about 5%. Consider
+// if this is worth exposing or if we can find a way to speed up the Class
+// method.
+//
+// // CompactClass is like Class, but maps all of the BiDi control classes
+// // (LRO, RLO, LRE, RLE, PDF, LRI, RLI, FSI, PDI) to the class Control.
+// func (p Properties) CompactClass() Class {
+// 	return Class(p.entry & 0x0F)
+// }
+
+// Class returns the Bidi class for p.
+func (p Properties) Class() Class {
+	c := Class(p.entry & 0x0F)
+	if c == Control {
+		c = controlByteToClass[p.last&0xF]
+	}
+	return c
+}
+
+// IsBracket reports whether the rune is a bracket.
+func (p Properties) IsBracket() bool { return p.entry&0xF0 != 0 }
+
+// IsOpeningBracket reports whether the rune is an opening bracket.
+// IsBracket must return true.
+func (p Properties) IsOpeningBracket() bool { return p.entry&openMask != 0 }
+
+// TODO: find a better API and expose.
+func (p Properties) reverseBracket(r rune) rune {
+	return xorMasks[p.entry>>xorMaskShift] ^ r
+}
+
+var controlByteToClass = [16]Class{
+	0xD: LRO, // U+202D LeftToRightOverride,
+	0xE: RLO, // U+202E RightToLeftOverride,
+	0xA: LRE, // U+202A LeftToRightEmbedding,
+	0xB: RLE, // U+202B RightToLeftEmbedding,
+	0xC: PDF, // U+202C PopDirectionalFormat,
+	0x6: LRI, // U+2066 LeftToRightIsolate,
+	0x7: RLI, // U+2067 RightToLeftIsolate,
+	0x8: FSI, // U+2068 FirstStrongIsolate,
+	0x9: PDI, // U+2069 PopDirectionalIsolate,
+}
+
+// LookupRune returns properties for r.
+func LookupRune(r rune) (p Properties, size int) {
+	var buf [4]byte
+	n := utf8.EncodeRune(buf[:], r)
+	return Lookup(buf[:n])
+}
+
+// TODO: these lookup methods are based on the generated trie code. The returned
+// sizes have slightly different semantics from the generated code, in that it
+// always returns size==1 for an illegal UTF-8 byte (instead of the length
+// of the maximum invalid subsequence). Most Transformers, like unicode/norm,
+// leave invalid UTF-8 untouched, in which case it has performance benefits to
+// do so (without changing the semantics). Bidi requires the semantics used here
+// for the bidirule implementation to be compatible with the Go semantics.
+//  They ultimately should perhaps be adopted by all trie implementations, for
+// convenience sake.
+// This unrolled code also boosts performance of the secure/bidirule package by
+// about 30%.
+// So, to remove this code:
+//   - add option to trie generator to define return type.
+//   - always return 1 byte size for ill-formed UTF-8 runes.
+
+// Lookup returns properties for the first rune in s and the width in bytes of
+// its encoding. The size will be 0 if s does not hold enough bytes to complete
+// the encoding.
+func Lookup(s []byte) (p Properties, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return Properties{entry: bidiValues[c0]}, 1
+	case c0 < 0xC2:
+		return Properties{}, 1
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return Properties{}, 1
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = bidiIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
+	}
+	// Illegal rune
+	return Properties{}, 1
+}
+
+// LookupString returns properties for the first rune in s and the width in
+// bytes of its encoding. The size will be 0 if s does not hold enough bytes to
+// complete the encoding.
+func LookupString(s string) (p Properties, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return Properties{entry: bidiValues[c0]}, 1
+	case c0 < 0xC2:
+		return Properties{}, 1
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return Properties{}, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return Properties{}, 1
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return Properties{}, 1
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = bidiIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return Properties{}, 1
+		}
+		return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
+	}
+	// Illegal rune
+	return Properties{}, 1
+}
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/tables.go b/src/vendor/golang_org/x/text/unicode/bidi/tables.go
new file mode 100644
index 0000000..1245315
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/tables.go
@@ -0,0 +1,1781 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT.
+
+package bidi
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "9.0.0"
+
+// xorMasks contains masks to be xor-ed with brackets to get the reverse
+// version.
+var xorMasks = []int32{ // 8 elements
+	0, 1, 6, 7, 3, 15, 29, 63,
+} // Size: 56 bytes
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *bidiTrie) lookup(s []byte) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return bidiValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = bidiIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *bidiTrie) lookupUnsafe(s []byte) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return bidiValues[c0]
+	}
+	i := bidiIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = bidiIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = bidiIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *bidiTrie) lookupString(s string) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return bidiValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := bidiIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = bidiIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = bidiIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *bidiTrie) lookupStringUnsafe(s string) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return bidiValues[c0]
+	}
+	i := bidiIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = bidiIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = bidiIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// bidiTrie. Total size: 15744 bytes (15.38 KiB). Checksum: b4c3b70954803b86.
+type bidiTrie struct{}
+
+func newBidiTrie(i int) *bidiTrie {
+	return &bidiTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *bidiTrie) lookupValue(n uint32, b byte) uint8 {
+	switch {
+	default:
+		return uint8(bidiValues[n<<6+uint32(b)])
+	}
+}
+
+// bidiValues: 222 blocks, 14208 entries, 14208 bytes
+// The third block is the zero block.
+var bidiValues = [14208]uint8{
+	// Block 0x0, offset 0x0
+	0x00: 0x000b, 0x01: 0x000b, 0x02: 0x000b, 0x03: 0x000b, 0x04: 0x000b, 0x05: 0x000b,
+	0x06: 0x000b, 0x07: 0x000b, 0x08: 0x000b, 0x09: 0x0008, 0x0a: 0x0007, 0x0b: 0x0008,
+	0x0c: 0x0009, 0x0d: 0x0007, 0x0e: 0x000b, 0x0f: 0x000b, 0x10: 0x000b, 0x11: 0x000b,
+	0x12: 0x000b, 0x13: 0x000b, 0x14: 0x000b, 0x15: 0x000b, 0x16: 0x000b, 0x17: 0x000b,
+	0x18: 0x000b, 0x19: 0x000b, 0x1a: 0x000b, 0x1b: 0x000b, 0x1c: 0x0007, 0x1d: 0x0007,
+	0x1e: 0x0007, 0x1f: 0x0008, 0x20: 0x0009, 0x21: 0x000a, 0x22: 0x000a, 0x23: 0x0004,
+	0x24: 0x0004, 0x25: 0x0004, 0x26: 0x000a, 0x27: 0x000a, 0x28: 0x003a, 0x29: 0x002a,
+	0x2a: 0x000a, 0x2b: 0x0003, 0x2c: 0x0006, 0x2d: 0x0003, 0x2e: 0x0006, 0x2f: 0x0006,
+	0x30: 0x0002, 0x31: 0x0002, 0x32: 0x0002, 0x33: 0x0002, 0x34: 0x0002, 0x35: 0x0002,
+	0x36: 0x0002, 0x37: 0x0002, 0x38: 0x0002, 0x39: 0x0002, 0x3a: 0x0006, 0x3b: 0x000a,
+	0x3c: 0x000a, 0x3d: 0x000a, 0x3e: 0x000a, 0x3f: 0x000a,
+	// Block 0x1, offset 0x40
+	0x40: 0x000a,
+	0x5b: 0x005a, 0x5c: 0x000a, 0x5d: 0x004a,
+	0x5e: 0x000a, 0x5f: 0x000a, 0x60: 0x000a,
+	0x7b: 0x005a,
+	0x7c: 0x000a, 0x7d: 0x004a, 0x7e: 0x000a, 0x7f: 0x000b,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x000b, 0xc1: 0x000b, 0xc2: 0x000b, 0xc3: 0x000b, 0xc4: 0x000b, 0xc5: 0x0007,
+	0xc6: 0x000b, 0xc7: 0x000b, 0xc8: 0x000b, 0xc9: 0x000b, 0xca: 0x000b, 0xcb: 0x000b,
+	0xcc: 0x000b, 0xcd: 0x000b, 0xce: 0x000b, 0xcf: 0x000b, 0xd0: 0x000b, 0xd1: 0x000b,
+	0xd2: 0x000b, 0xd3: 0x000b, 0xd4: 0x000b, 0xd5: 0x000b, 0xd6: 0x000b, 0xd7: 0x000b,
+	0xd8: 0x000b, 0xd9: 0x000b, 0xda: 0x000b, 0xdb: 0x000b, 0xdc: 0x000b, 0xdd: 0x000b,
+	0xde: 0x000b, 0xdf: 0x000b, 0xe0: 0x0006, 0xe1: 0x000a, 0xe2: 0x0004, 0xe3: 0x0004,
+	0xe4: 0x0004, 0xe5: 0x0004, 0xe6: 0x000a, 0xe7: 0x000a, 0xe8: 0x000a, 0xe9: 0x000a,
+	0xeb: 0x000a, 0xec: 0x000a, 0xed: 0x000b, 0xee: 0x000a, 0xef: 0x000a,
+	0xf0: 0x0004, 0xf1: 0x0004, 0xf2: 0x0002, 0xf3: 0x0002, 0xf4: 0x000a,
+	0xf6: 0x000a, 0xf7: 0x000a, 0xf8: 0x000a, 0xf9: 0x0002, 0xfb: 0x000a,
+	0xfc: 0x000a, 0xfd: 0x000a, 0xfe: 0x000a, 0xff: 0x000a,
+	// Block 0x4, offset 0x100
+	0x117: 0x000a,
+	0x137: 0x000a,
+	// Block 0x5, offset 0x140
+	0x179: 0x000a, 0x17a: 0x000a,
+	// Block 0x6, offset 0x180
+	0x182: 0x000a, 0x183: 0x000a, 0x184: 0x000a, 0x185: 0x000a,
+	0x186: 0x000a, 0x187: 0x000a, 0x188: 0x000a, 0x189: 0x000a, 0x18a: 0x000a, 0x18b: 0x000a,
+	0x18c: 0x000a, 0x18d: 0x000a, 0x18e: 0x000a, 0x18f: 0x000a,
+	0x192: 0x000a, 0x193: 0x000a, 0x194: 0x000a, 0x195: 0x000a, 0x196: 0x000a, 0x197: 0x000a,
+	0x198: 0x000a, 0x199: 0x000a, 0x19a: 0x000a, 0x19b: 0x000a, 0x19c: 0x000a, 0x19d: 0x000a,
+	0x19e: 0x000a, 0x19f: 0x000a,
+	0x1a5: 0x000a, 0x1a6: 0x000a, 0x1a7: 0x000a, 0x1a8: 0x000a, 0x1a9: 0x000a,
+	0x1aa: 0x000a, 0x1ab: 0x000a, 0x1ac: 0x000a, 0x1ad: 0x000a, 0x1af: 0x000a,
+	0x1b0: 0x000a, 0x1b1: 0x000a, 0x1b2: 0x000a, 0x1b3: 0x000a, 0x1b4: 0x000a, 0x1b5: 0x000a,
+	0x1b6: 0x000a, 0x1b7: 0x000a, 0x1b8: 0x000a, 0x1b9: 0x000a, 0x1ba: 0x000a, 0x1bb: 0x000a,
+	0x1bc: 0x000a, 0x1bd: 0x000a, 0x1be: 0x000a, 0x1bf: 0x000a,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x000c, 0x1c1: 0x000c, 0x1c2: 0x000c, 0x1c3: 0x000c, 0x1c4: 0x000c, 0x1c5: 0x000c,
+	0x1c6: 0x000c, 0x1c7: 0x000c, 0x1c8: 0x000c, 0x1c9: 0x000c, 0x1ca: 0x000c, 0x1cb: 0x000c,
+	0x1cc: 0x000c, 0x1cd: 0x000c, 0x1ce: 0x000c, 0x1cf: 0x000c, 0x1d0: 0x000c, 0x1d1: 0x000c,
+	0x1d2: 0x000c, 0x1d3: 0x000c, 0x1d4: 0x000c, 0x1d5: 0x000c, 0x1d6: 0x000c, 0x1d7: 0x000c,
+	0x1d8: 0x000c, 0x1d9: 0x000c, 0x1da: 0x000c, 0x1db: 0x000c, 0x1dc: 0x000c, 0x1dd: 0x000c,
+	0x1de: 0x000c, 0x1df: 0x000c, 0x1e0: 0x000c, 0x1e1: 0x000c, 0x1e2: 0x000c, 0x1e3: 0x000c,
+	0x1e4: 0x000c, 0x1e5: 0x000c, 0x1e6: 0x000c, 0x1e7: 0x000c, 0x1e8: 0x000c, 0x1e9: 0x000c,
+	0x1ea: 0x000c, 0x1eb: 0x000c, 0x1ec: 0x000c, 0x1ed: 0x000c, 0x1ee: 0x000c, 0x1ef: 0x000c,
+	0x1f0: 0x000c, 0x1f1: 0x000c, 0x1f2: 0x000c, 0x1f3: 0x000c, 0x1f4: 0x000c, 0x1f5: 0x000c,
+	0x1f6: 0x000c, 0x1f7: 0x000c, 0x1f8: 0x000c, 0x1f9: 0x000c, 0x1fa: 0x000c, 0x1fb: 0x000c,
+	0x1fc: 0x000c, 0x1fd: 0x000c, 0x1fe: 0x000c, 0x1ff: 0x000c,
+	// Block 0x8, offset 0x200
+	0x200: 0x000c, 0x201: 0x000c, 0x202: 0x000c, 0x203: 0x000c, 0x204: 0x000c, 0x205: 0x000c,
+	0x206: 0x000c, 0x207: 0x000c, 0x208: 0x000c, 0x209: 0x000c, 0x20a: 0x000c, 0x20b: 0x000c,
+	0x20c: 0x000c, 0x20d: 0x000c, 0x20e: 0x000c, 0x20f: 0x000c, 0x210: 0x000c, 0x211: 0x000c,
+	0x212: 0x000c, 0x213: 0x000c, 0x214: 0x000c, 0x215: 0x000c, 0x216: 0x000c, 0x217: 0x000c,
+	0x218: 0x000c, 0x219: 0x000c, 0x21a: 0x000c, 0x21b: 0x000c, 0x21c: 0x000c, 0x21d: 0x000c,
+	0x21e: 0x000c, 0x21f: 0x000c, 0x220: 0x000c, 0x221: 0x000c, 0x222: 0x000c, 0x223: 0x000c,
+	0x224: 0x000c, 0x225: 0x000c, 0x226: 0x000c, 0x227: 0x000c, 0x228: 0x000c, 0x229: 0x000c,
+	0x22a: 0x000c, 0x22b: 0x000c, 0x22c: 0x000c, 0x22d: 0x000c, 0x22e: 0x000c, 0x22f: 0x000c,
+	0x234: 0x000a, 0x235: 0x000a,
+	0x23e: 0x000a,
+	// Block 0x9, offset 0x240
+	0x244: 0x000a, 0x245: 0x000a,
+	0x247: 0x000a,
+	// Block 0xa, offset 0x280
+	0x2b6: 0x000a,
+	// Block 0xb, offset 0x2c0
+	0x2c3: 0x000c, 0x2c4: 0x000c, 0x2c5: 0x000c,
+	0x2c6: 0x000c, 0x2c7: 0x000c, 0x2c8: 0x000c, 0x2c9: 0x000c,
+	// Block 0xc, offset 0x300
+	0x30a: 0x000a,
+	0x30d: 0x000a, 0x30e: 0x000a, 0x30f: 0x0004, 0x310: 0x0001, 0x311: 0x000c,
+	0x312: 0x000c, 0x313: 0x000c, 0x314: 0x000c, 0x315: 0x000c, 0x316: 0x000c, 0x317: 0x000c,
+	0x318: 0x000c, 0x319: 0x000c, 0x31a: 0x000c, 0x31b: 0x000c, 0x31c: 0x000c, 0x31d: 0x000c,
+	0x31e: 0x000c, 0x31f: 0x000c, 0x320: 0x000c, 0x321: 0x000c, 0x322: 0x000c, 0x323: 0x000c,
+	0x324: 0x000c, 0x325: 0x000c, 0x326: 0x000c, 0x327: 0x000c, 0x328: 0x000c, 0x329: 0x000c,
+	0x32a: 0x000c, 0x32b: 0x000c, 0x32c: 0x000c, 0x32d: 0x000c, 0x32e: 0x000c, 0x32f: 0x000c,
+	0x330: 0x000c, 0x331: 0x000c, 0x332: 0x000c, 0x333: 0x000c, 0x334: 0x000c, 0x335: 0x000c,
+	0x336: 0x000c, 0x337: 0x000c, 0x338: 0x000c, 0x339: 0x000c, 0x33a: 0x000c, 0x33b: 0x000c,
+	0x33c: 0x000c, 0x33d: 0x000c, 0x33e: 0x0001, 0x33f: 0x000c,
+	// Block 0xd, offset 0x340
+	0x340: 0x0001, 0x341: 0x000c, 0x342: 0x000c, 0x343: 0x0001, 0x344: 0x000c, 0x345: 0x000c,
+	0x346: 0x0001, 0x347: 0x000c, 0x348: 0x0001, 0x349: 0x0001, 0x34a: 0x0001, 0x34b: 0x0001,
+	0x34c: 0x0001, 0x34d: 0x0001, 0x34e: 0x0001, 0x34f: 0x0001, 0x350: 0x0001, 0x351: 0x0001,
+	0x352: 0x0001, 0x353: 0x0001, 0x354: 0x0001, 0x355: 0x0001, 0x356: 0x0001, 0x357: 0x0001,
+	0x358: 0x0001, 0x359: 0x0001, 0x35a: 0x0001, 0x35b: 0x0001, 0x35c: 0x0001, 0x35d: 0x0001,
+	0x35e: 0x0001, 0x35f: 0x0001, 0x360: 0x0001, 0x361: 0x0001, 0x362: 0x0001, 0x363: 0x0001,
+	0x364: 0x0001, 0x365: 0x0001, 0x366: 0x0001, 0x367: 0x0001, 0x368: 0x0001, 0x369: 0x0001,
+	0x36a: 0x0001, 0x36b: 0x0001, 0x36c: 0x0001, 0x36d: 0x0001, 0x36e: 0x0001, 0x36f: 0x0001,
+	0x370: 0x0001, 0x371: 0x0001, 0x372: 0x0001, 0x373: 0x0001, 0x374: 0x0001, 0x375: 0x0001,
+	0x376: 0x0001, 0x377: 0x0001, 0x378: 0x0001, 0x379: 0x0001, 0x37a: 0x0001, 0x37b: 0x0001,
+	0x37c: 0x0001, 0x37d: 0x0001, 0x37e: 0x0001, 0x37f: 0x0001,
+	// Block 0xe, offset 0x380
+	0x380: 0x0005, 0x381: 0x0005, 0x382: 0x0005, 0x383: 0x0005, 0x384: 0x0005, 0x385: 0x0005,
+	0x386: 0x000a, 0x387: 0x000a, 0x388: 0x000d, 0x389: 0x0004, 0x38a: 0x0004, 0x38b: 0x000d,
+	0x38c: 0x0006, 0x38d: 0x000d, 0x38e: 0x000a, 0x38f: 0x000a, 0x390: 0x000c, 0x391: 0x000c,
+	0x392: 0x000c, 0x393: 0x000c, 0x394: 0x000c, 0x395: 0x000c, 0x396: 0x000c, 0x397: 0x000c,
+	0x398: 0x000c, 0x399: 0x000c, 0x39a: 0x000c, 0x39b: 0x000d, 0x39c: 0x000d, 0x39d: 0x000d,
+	0x39e: 0x000d, 0x39f: 0x000d, 0x3a0: 0x000d, 0x3a1: 0x000d, 0x3a2: 0x000d, 0x3a3: 0x000d,
+	0x3a4: 0x000d, 0x3a5: 0x000d, 0x3a6: 0x000d, 0x3a7: 0x000d, 0x3a8: 0x000d, 0x3a9: 0x000d,
+	0x3aa: 0x000d, 0x3ab: 0x000d, 0x3ac: 0x000d, 0x3ad: 0x000d, 0x3ae: 0x000d, 0x3af: 0x000d,
+	0x3b0: 0x000d, 0x3b1: 0x000d, 0x3b2: 0x000d, 0x3b3: 0x000d, 0x3b4: 0x000d, 0x3b5: 0x000d,
+	0x3b6: 0x000d, 0x3b7: 0x000d, 0x3b8: 0x000d, 0x3b9: 0x000d, 0x3ba: 0x000d, 0x3bb: 0x000d,
+	0x3bc: 0x000d, 0x3bd: 0x000d, 0x3be: 0x000d, 0x3bf: 0x000d,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x000d, 0x3c1: 0x000d, 0x3c2: 0x000d, 0x3c3: 0x000d, 0x3c4: 0x000d, 0x3c5: 0x000d,
+	0x3c6: 0x000d, 0x3c7: 0x000d, 0x3c8: 0x000d, 0x3c9: 0x000d, 0x3ca: 0x000d, 0x3cb: 0x000c,
+	0x3cc: 0x000c, 0x3cd: 0x000c, 0x3ce: 0x000c, 0x3cf: 0x000c, 0x3d0: 0x000c, 0x3d1: 0x000c,
+	0x3d2: 0x000c, 0x3d3: 0x000c, 0x3d4: 0x000c, 0x3d5: 0x000c, 0x3d6: 0x000c, 0x3d7: 0x000c,
+	0x3d8: 0x000c, 0x3d9: 0x000c, 0x3da: 0x000c, 0x3db: 0x000c, 0x3dc: 0x000c, 0x3dd: 0x000c,
+	0x3de: 0x000c, 0x3df: 0x000c, 0x3e0: 0x0005, 0x3e1: 0x0005, 0x3e2: 0x0005, 0x3e3: 0x0005,
+	0x3e4: 0x0005, 0x3e5: 0x0005, 0x3e6: 0x0005, 0x3e7: 0x0005, 0x3e8: 0x0005, 0x3e9: 0x0005,
+	0x3ea: 0x0004, 0x3eb: 0x0005, 0x3ec: 0x0005, 0x3ed: 0x000d, 0x3ee: 0x000d, 0x3ef: 0x000d,
+	0x3f0: 0x000c, 0x3f1: 0x000d, 0x3f2: 0x000d, 0x3f3: 0x000d, 0x3f4: 0x000d, 0x3f5: 0x000d,
+	0x3f6: 0x000d, 0x3f7: 0x000d, 0x3f8: 0x000d, 0x3f9: 0x000d, 0x3fa: 0x000d, 0x3fb: 0x000d,
+	0x3fc: 0x000d, 0x3fd: 0x000d, 0x3fe: 0x000d, 0x3ff: 0x000d,
+	// Block 0x10, offset 0x400
+	0x400: 0x000d, 0x401: 0x000d, 0x402: 0x000d, 0x403: 0x000d, 0x404: 0x000d, 0x405: 0x000d,
+	0x406: 0x000d, 0x407: 0x000d, 0x408: 0x000d, 0x409: 0x000d, 0x40a: 0x000d, 0x40b: 0x000d,
+	0x40c: 0x000d, 0x40d: 0x000d, 0x40e: 0x000d, 0x40f: 0x000d, 0x410: 0x000d, 0x411: 0x000d,
+	0x412: 0x000d, 0x413: 0x000d, 0x414: 0x000d, 0x415: 0x000d, 0x416: 0x000d, 0x417: 0x000d,
+	0x418: 0x000d, 0x419: 0x000d, 0x41a: 0x000d, 0x41b: 0x000d, 0x41c: 0x000d, 0x41d: 0x000d,
+	0x41e: 0x000d, 0x41f: 0x000d, 0x420: 0x000d, 0x421: 0x000d, 0x422: 0x000d, 0x423: 0x000d,
+	0x424: 0x000d, 0x425: 0x000d, 0x426: 0x000d, 0x427: 0x000d, 0x428: 0x000d, 0x429: 0x000d,
+	0x42a: 0x000d, 0x42b: 0x000d, 0x42c: 0x000d, 0x42d: 0x000d, 0x42e: 0x000d, 0x42f: 0x000d,
+	0x430: 0x000d, 0x431: 0x000d, 0x432: 0x000d, 0x433: 0x000d, 0x434: 0x000d, 0x435: 0x000d,
+	0x436: 0x000d, 0x437: 0x000d, 0x438: 0x000d, 0x439: 0x000d, 0x43a: 0x000d, 0x43b: 0x000d,
+	0x43c: 0x000d, 0x43d: 0x000d, 0x43e: 0x000d, 0x43f: 0x000d,
+	// Block 0x11, offset 0x440
+	0x440: 0x000d, 0x441: 0x000d, 0x442: 0x000d, 0x443: 0x000d, 0x444: 0x000d, 0x445: 0x000d,
+	0x446: 0x000d, 0x447: 0x000d, 0x448: 0x000d, 0x449: 0x000d, 0x44a: 0x000d, 0x44b: 0x000d,
+	0x44c: 0x000d, 0x44d: 0x000d, 0x44e: 0x000d, 0x44f: 0x000d, 0x450: 0x000d, 0x451: 0x000d,
+	0x452: 0x000d, 0x453: 0x000d, 0x454: 0x000d, 0x455: 0x000d, 0x456: 0x000c, 0x457: 0x000c,
+	0x458: 0x000c, 0x459: 0x000c, 0x45a: 0x000c, 0x45b: 0x000c, 0x45c: 0x000c, 0x45d: 0x0005,
+	0x45e: 0x000a, 0x45f: 0x000c, 0x460: 0x000c, 0x461: 0x000c, 0x462: 0x000c, 0x463: 0x000c,
+	0x464: 0x000c, 0x465: 0x000d, 0x466: 0x000d, 0x467: 0x000c, 0x468: 0x000c, 0x469: 0x000a,
+	0x46a: 0x000c, 0x46b: 0x000c, 0x46c: 0x000c, 0x46d: 0x000c, 0x46e: 0x000d, 0x46f: 0x000d,
+	0x470: 0x0002, 0x471: 0x0002, 0x472: 0x0002, 0x473: 0x0002, 0x474: 0x0002, 0x475: 0x0002,
+	0x476: 0x0002, 0x477: 0x0002, 0x478: 0x0002, 0x479: 0x0002, 0x47a: 0x000d, 0x47b: 0x000d,
+	0x47c: 0x000d, 0x47d: 0x000d, 0x47e: 0x000d, 0x47f: 0x000d,
+	// Block 0x12, offset 0x480
+	0x480: 0x000d, 0x481: 0x000d, 0x482: 0x000d, 0x483: 0x000d, 0x484: 0x000d, 0x485: 0x000d,
+	0x486: 0x000d, 0x487: 0x000d, 0x488: 0x000d, 0x489: 0x000d, 0x48a: 0x000d, 0x48b: 0x000d,
+	0x48c: 0x000d, 0x48d: 0x000d, 0x48e: 0x000d, 0x48f: 0x000d, 0x490: 0x000d, 0x491: 0x000c,
+	0x492: 0x000d, 0x493: 0x000d, 0x494: 0x000d, 0x495: 0x000d, 0x496: 0x000d, 0x497: 0x000d,
+	0x498: 0x000d, 0x499: 0x000d, 0x49a: 0x000d, 0x49b: 0x000d, 0x49c: 0x000d, 0x49d: 0x000d,
+	0x49e: 0x000d, 0x49f: 0x000d, 0x4a0: 0x000d, 0x4a1: 0x000d, 0x4a2: 0x000d, 0x4a3: 0x000d,
+	0x4a4: 0x000d, 0x4a5: 0x000d, 0x4a6: 0x000d, 0x4a7: 0x000d, 0x4a8: 0x000d, 0x4a9: 0x000d,
+	0x4aa: 0x000d, 0x4ab: 0x000d, 0x4ac: 0x000d, 0x4ad: 0x000d, 0x4ae: 0x000d, 0x4af: 0x000d,
+	0x4b0: 0x000c, 0x4b1: 0x000c, 0x4b2: 0x000c, 0x4b3: 0x000c, 0x4b4: 0x000c, 0x4b5: 0x000c,
+	0x4b6: 0x000c, 0x4b7: 0x000c, 0x4b8: 0x000c, 0x4b9: 0x000c, 0x4ba: 0x000c, 0x4bb: 0x000c,
+	0x4bc: 0x000c, 0x4bd: 0x000c, 0x4be: 0x000c, 0x4bf: 0x000c,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x000c, 0x4c1: 0x000c, 0x4c2: 0x000c, 0x4c3: 0x000c, 0x4c4: 0x000c, 0x4c5: 0x000c,
+	0x4c6: 0x000c, 0x4c7: 0x000c, 0x4c8: 0x000c, 0x4c9: 0x000c, 0x4ca: 0x000c, 0x4cb: 0x000d,
+	0x4cc: 0x000d, 0x4cd: 0x000d, 0x4ce: 0x000d, 0x4cf: 0x000d, 0x4d0: 0x000d, 0x4d1: 0x000d,
+	0x4d2: 0x000d, 0x4d3: 0x000d, 0x4d4: 0x000d, 0x4d5: 0x000d, 0x4d6: 0x000d, 0x4d7: 0x000d,
+	0x4d8: 0x000d, 0x4d9: 0x000d, 0x4da: 0x000d, 0x4db: 0x000d, 0x4dc: 0x000d, 0x4dd: 0x000d,
+	0x4de: 0x000d, 0x4df: 0x000d, 0x4e0: 0x000d, 0x4e1: 0x000d, 0x4e2: 0x000d, 0x4e3: 0x000d,
+	0x4e4: 0x000d, 0x4e5: 0x000d, 0x4e6: 0x000d, 0x4e7: 0x000d, 0x4e8: 0x000d, 0x4e9: 0x000d,
+	0x4ea: 0x000d, 0x4eb: 0x000d, 0x4ec: 0x000d, 0x4ed: 0x000d, 0x4ee: 0x000d, 0x4ef: 0x000d,
+	0x4f0: 0x000d, 0x4f1: 0x000d, 0x4f2: 0x000d, 0x4f3: 0x000d, 0x4f4: 0x000d, 0x4f5: 0x000d,
+	0x4f6: 0x000d, 0x4f7: 0x000d, 0x4f8: 0x000d, 0x4f9: 0x000d, 0x4fa: 0x000d, 0x4fb: 0x000d,
+	0x4fc: 0x000d, 0x4fd: 0x000d, 0x4fe: 0x000d, 0x4ff: 0x000d,
+	// Block 0x14, offset 0x500
+	0x500: 0x000d, 0x501: 0x000d, 0x502: 0x000d, 0x503: 0x000d, 0x504: 0x000d, 0x505: 0x000d,
+	0x506: 0x000d, 0x507: 0x000d, 0x508: 0x000d, 0x509: 0x000d, 0x50a: 0x000d, 0x50b: 0x000d,
+	0x50c: 0x000d, 0x50d: 0x000d, 0x50e: 0x000d, 0x50f: 0x000d, 0x510: 0x000d, 0x511: 0x000d,
+	0x512: 0x000d, 0x513: 0x000d, 0x514: 0x000d, 0x515: 0x000d, 0x516: 0x000d, 0x517: 0x000d,
+	0x518: 0x000d, 0x519: 0x000d, 0x51a: 0x000d, 0x51b: 0x000d, 0x51c: 0x000d, 0x51d: 0x000d,
+	0x51e: 0x000d, 0x51f: 0x000d, 0x520: 0x000d, 0x521: 0x000d, 0x522: 0x000d, 0x523: 0x000d,
+	0x524: 0x000d, 0x525: 0x000d, 0x526: 0x000c, 0x527: 0x000c, 0x528: 0x000c, 0x529: 0x000c,
+	0x52a: 0x000c, 0x52b: 0x000c, 0x52c: 0x000c, 0x52d: 0x000c, 0x52e: 0x000c, 0x52f: 0x000c,
+	0x530: 0x000c, 0x531: 0x000d, 0x532: 0x000d, 0x533: 0x000d, 0x534: 0x000d, 0x535: 0x000d,
+	0x536: 0x000d, 0x537: 0x000d, 0x538: 0x000d, 0x539: 0x000d, 0x53a: 0x000d, 0x53b: 0x000d,
+	0x53c: 0x000d, 0x53d: 0x000d, 0x53e: 0x000d, 0x53f: 0x000d,
+	// Block 0x15, offset 0x540
+	0x540: 0x0001, 0x541: 0x0001, 0x542: 0x0001, 0x543: 0x0001, 0x544: 0x0001, 0x545: 0x0001,
+	0x546: 0x0001, 0x547: 0x0001, 0x548: 0x0001, 0x549: 0x0001, 0x54a: 0x0001, 0x54b: 0x0001,
+	0x54c: 0x0001, 0x54d: 0x0001, 0x54e: 0x0001, 0x54f: 0x0001, 0x550: 0x0001, 0x551: 0x0001,
+	0x552: 0x0001, 0x553: 0x0001, 0x554: 0x0001, 0x555: 0x0001, 0x556: 0x0001, 0x557: 0x0001,
+	0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001,
+	0x55e: 0x0001, 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001,
+	0x564: 0x0001, 0x565: 0x0001, 0x566: 0x0001, 0x567: 0x0001, 0x568: 0x0001, 0x569: 0x0001,
+	0x56a: 0x0001, 0x56b: 0x000c, 0x56c: 0x000c, 0x56d: 0x000c, 0x56e: 0x000c, 0x56f: 0x000c,
+	0x570: 0x000c, 0x571: 0x000c, 0x572: 0x000c, 0x573: 0x000c, 0x574: 0x0001, 0x575: 0x0001,
+	0x576: 0x000a, 0x577: 0x000a, 0x578: 0x000a, 0x579: 0x000a, 0x57a: 0x0001, 0x57b: 0x0001,
+	0x57c: 0x0001, 0x57d: 0x0001, 0x57e: 0x0001, 0x57f: 0x0001,
+	// Block 0x16, offset 0x580
+	0x580: 0x0001, 0x581: 0x0001, 0x582: 0x0001, 0x583: 0x0001, 0x584: 0x0001, 0x585: 0x0001,
+	0x586: 0x0001, 0x587: 0x0001, 0x588: 0x0001, 0x589: 0x0001, 0x58a: 0x0001, 0x58b: 0x0001,
+	0x58c: 0x0001, 0x58d: 0x0001, 0x58e: 0x0001, 0x58f: 0x0001, 0x590: 0x0001, 0x591: 0x0001,
+	0x592: 0x0001, 0x593: 0x0001, 0x594: 0x0001, 0x595: 0x0001, 0x596: 0x000c, 0x597: 0x000c,
+	0x598: 0x000c, 0x599: 0x000c, 0x59a: 0x0001, 0x59b: 0x000c, 0x59c: 0x000c, 0x59d: 0x000c,
+	0x59e: 0x000c, 0x59f: 0x000c, 0x5a0: 0x000c, 0x5a1: 0x000c, 0x5a2: 0x000c, 0x5a3: 0x000c,
+	0x5a4: 0x0001, 0x5a5: 0x000c, 0x5a6: 0x000c, 0x5a7: 0x000c, 0x5a8: 0x0001, 0x5a9: 0x000c,
+	0x5aa: 0x000c, 0x5ab: 0x000c, 0x5ac: 0x000c, 0x5ad: 0x000c, 0x5ae: 0x0001, 0x5af: 0x0001,
+	0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001,
+	0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001,
+	0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001,
+	0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, 0x5cb: 0x0001,
+	0x5cc: 0x0001, 0x5cd: 0x0001, 0x5ce: 0x0001, 0x5cf: 0x0001, 0x5d0: 0x0001, 0x5d1: 0x0001,
+	0x5d2: 0x0001, 0x5d3: 0x0001, 0x5d4: 0x0001, 0x5d5: 0x0001, 0x5d6: 0x0001, 0x5d7: 0x0001,
+	0x5d8: 0x0001, 0x5d9: 0x000c, 0x5da: 0x000c, 0x5db: 0x000c, 0x5dc: 0x0001, 0x5dd: 0x0001,
+	0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x0001, 0x5e1: 0x0001, 0x5e2: 0x0001, 0x5e3: 0x0001,
+	0x5e4: 0x0001, 0x5e5: 0x0001, 0x5e6: 0x0001, 0x5e7: 0x0001, 0x5e8: 0x0001, 0x5e9: 0x0001,
+	0x5ea: 0x0001, 0x5eb: 0x0001, 0x5ec: 0x0001, 0x5ed: 0x0001, 0x5ee: 0x0001, 0x5ef: 0x0001,
+	0x5f0: 0x0001, 0x5f1: 0x0001, 0x5f2: 0x0001, 0x5f3: 0x0001, 0x5f4: 0x0001, 0x5f5: 0x0001,
+	0x5f6: 0x0001, 0x5f7: 0x0001, 0x5f8: 0x0001, 0x5f9: 0x0001, 0x5fa: 0x0001, 0x5fb: 0x0001,
+	0x5fc: 0x0001, 0x5fd: 0x0001, 0x5fe: 0x0001, 0x5ff: 0x0001,
+	// Block 0x18, offset 0x600
+	0x600: 0x0001, 0x601: 0x0001, 0x602: 0x0001, 0x603: 0x0001, 0x604: 0x0001, 0x605: 0x0001,
+	0x606: 0x0001, 0x607: 0x0001, 0x608: 0x0001, 0x609: 0x0001, 0x60a: 0x0001, 0x60b: 0x0001,
+	0x60c: 0x0001, 0x60d: 0x0001, 0x60e: 0x0001, 0x60f: 0x0001, 0x610: 0x0001, 0x611: 0x0001,
+	0x612: 0x0001, 0x613: 0x0001, 0x614: 0x0001, 0x615: 0x0001, 0x616: 0x0001, 0x617: 0x0001,
+	0x618: 0x0001, 0x619: 0x0001, 0x61a: 0x0001, 0x61b: 0x0001, 0x61c: 0x0001, 0x61d: 0x0001,
+	0x61e: 0x0001, 0x61f: 0x0001, 0x620: 0x000d, 0x621: 0x000d, 0x622: 0x000d, 0x623: 0x000d,
+	0x624: 0x000d, 0x625: 0x000d, 0x626: 0x000d, 0x627: 0x000d, 0x628: 0x000d, 0x629: 0x000d,
+	0x62a: 0x000d, 0x62b: 0x000d, 0x62c: 0x000d, 0x62d: 0x000d, 0x62e: 0x000d, 0x62f: 0x000d,
+	0x630: 0x000d, 0x631: 0x000d, 0x632: 0x000d, 0x633: 0x000d, 0x634: 0x000d, 0x635: 0x000d,
+	0x636: 0x000d, 0x637: 0x000d, 0x638: 0x000d, 0x639: 0x000d, 0x63a: 0x000d, 0x63b: 0x000d,
+	0x63c: 0x000d, 0x63d: 0x000d, 0x63e: 0x000d, 0x63f: 0x000d,
+	// Block 0x19, offset 0x640
+	0x640: 0x000d, 0x641: 0x000d, 0x642: 0x000d, 0x643: 0x000d, 0x644: 0x000d, 0x645: 0x000d,
+	0x646: 0x000d, 0x647: 0x000d, 0x648: 0x000d, 0x649: 0x000d, 0x64a: 0x000d, 0x64b: 0x000d,
+	0x64c: 0x000d, 0x64d: 0x000d, 0x64e: 0x000d, 0x64f: 0x000d, 0x650: 0x000d, 0x651: 0x000d,
+	0x652: 0x000d, 0x653: 0x000d, 0x654: 0x000c, 0x655: 0x000c, 0x656: 0x000c, 0x657: 0x000c,
+	0x658: 0x000c, 0x659: 0x000c, 0x65a: 0x000c, 0x65b: 0x000c, 0x65c: 0x000c, 0x65d: 0x000c,
+	0x65e: 0x000c, 0x65f: 0x000c, 0x660: 0x000c, 0x661: 0x000c, 0x662: 0x0005, 0x663: 0x000c,
+	0x664: 0x000c, 0x665: 0x000c, 0x666: 0x000c, 0x667: 0x000c, 0x668: 0x000c, 0x669: 0x000c,
+	0x66a: 0x000c, 0x66b: 0x000c, 0x66c: 0x000c, 0x66d: 0x000c, 0x66e: 0x000c, 0x66f: 0x000c,
+	0x670: 0x000c, 0x671: 0x000c, 0x672: 0x000c, 0x673: 0x000c, 0x674: 0x000c, 0x675: 0x000c,
+	0x676: 0x000c, 0x677: 0x000c, 0x678: 0x000c, 0x679: 0x000c, 0x67a: 0x000c, 0x67b: 0x000c,
+	0x67c: 0x000c, 0x67d: 0x000c, 0x67e: 0x000c, 0x67f: 0x000c,
+	// Block 0x1a, offset 0x680
+	0x680: 0x000c, 0x681: 0x000c, 0x682: 0x000c,
+	0x6ba: 0x000c,
+	0x6bc: 0x000c,
+	// Block 0x1b, offset 0x6c0
+	0x6c1: 0x000c, 0x6c2: 0x000c, 0x6c3: 0x000c, 0x6c4: 0x000c, 0x6c5: 0x000c,
+	0x6c6: 0x000c, 0x6c7: 0x000c, 0x6c8: 0x000c,
+	0x6cd: 0x000c, 0x6d1: 0x000c,
+	0x6d2: 0x000c, 0x6d3: 0x000c, 0x6d4: 0x000c, 0x6d5: 0x000c, 0x6d6: 0x000c, 0x6d7: 0x000c,
+	0x6e2: 0x000c, 0x6e3: 0x000c,
+	// Block 0x1c, offset 0x700
+	0x701: 0x000c,
+	0x73c: 0x000c,
+	// Block 0x1d, offset 0x740
+	0x741: 0x000c, 0x742: 0x000c, 0x743: 0x000c, 0x744: 0x000c,
+	0x74d: 0x000c,
+	0x762: 0x000c, 0x763: 0x000c,
+	0x772: 0x0004, 0x773: 0x0004,
+	0x77b: 0x0004,
+	// Block 0x1e, offset 0x780
+	0x781: 0x000c, 0x782: 0x000c,
+	0x7bc: 0x000c,
+	// Block 0x1f, offset 0x7c0
+	0x7c1: 0x000c, 0x7c2: 0x000c,
+	0x7c7: 0x000c, 0x7c8: 0x000c, 0x7cb: 0x000c,
+	0x7cc: 0x000c, 0x7cd: 0x000c, 0x7d1: 0x000c,
+	0x7f0: 0x000c, 0x7f1: 0x000c, 0x7f5: 0x000c,
+	// Block 0x20, offset 0x800
+	0x801: 0x000c, 0x802: 0x000c, 0x803: 0x000c, 0x804: 0x000c, 0x805: 0x000c,
+	0x807: 0x000c, 0x808: 0x000c,
+	0x80d: 0x000c,
+	0x822: 0x000c, 0x823: 0x000c,
+	0x831: 0x0004,
+	// Block 0x21, offset 0x840
+	0x841: 0x000c,
+	0x87c: 0x000c, 0x87f: 0x000c,
+	// Block 0x22, offset 0x880
+	0x881: 0x000c, 0x882: 0x000c, 0x883: 0x000c, 0x884: 0x000c,
+	0x88d: 0x000c,
+	0x896: 0x000c,
+	0x8a2: 0x000c, 0x8a3: 0x000c,
+	// Block 0x23, offset 0x8c0
+	0x8c2: 0x000c,
+	// Block 0x24, offset 0x900
+	0x900: 0x000c,
+	0x90d: 0x000c,
+	0x933: 0x000a, 0x934: 0x000a, 0x935: 0x000a,
+	0x936: 0x000a, 0x937: 0x000a, 0x938: 0x000a, 0x939: 0x0004, 0x93a: 0x000a,
+	// Block 0x25, offset 0x940
+	0x940: 0x000c,
+	0x97e: 0x000c, 0x97f: 0x000c,
+	// Block 0x26, offset 0x980
+	0x980: 0x000c,
+	0x986: 0x000c, 0x987: 0x000c, 0x988: 0x000c, 0x98a: 0x000c, 0x98b: 0x000c,
+	0x98c: 0x000c, 0x98d: 0x000c,
+	0x995: 0x000c, 0x996: 0x000c,
+	0x9a2: 0x000c, 0x9a3: 0x000c,
+	0x9b8: 0x000a, 0x9b9: 0x000a, 0x9ba: 0x000a, 0x9bb: 0x000a,
+	0x9bc: 0x000a, 0x9bd: 0x000a, 0x9be: 0x000a,
+	// Block 0x27, offset 0x9c0
+	0x9cc: 0x000c, 0x9cd: 0x000c,
+	0x9e2: 0x000c, 0x9e3: 0x000c,
+	// Block 0x28, offset 0xa00
+	0xa01: 0x000c,
+	// Block 0x29, offset 0xa40
+	0xa41: 0x000c, 0xa42: 0x000c, 0xa43: 0x000c, 0xa44: 0x000c,
+	0xa4d: 0x000c,
+	0xa62: 0x000c, 0xa63: 0x000c,
+	// Block 0x2a, offset 0xa80
+	0xa8a: 0x000c,
+	0xa92: 0x000c, 0xa93: 0x000c, 0xa94: 0x000c, 0xa96: 0x000c,
+	// Block 0x2b, offset 0xac0
+	0xaf1: 0x000c, 0xaf4: 0x000c, 0xaf5: 0x000c,
+	0xaf6: 0x000c, 0xaf7: 0x000c, 0xaf8: 0x000c, 0xaf9: 0x000c, 0xafa: 0x000c,
+	0xaff: 0x0004,
+	// Block 0x2c, offset 0xb00
+	0xb07: 0x000c, 0xb08: 0x000c, 0xb09: 0x000c, 0xb0a: 0x000c, 0xb0b: 0x000c,
+	0xb0c: 0x000c, 0xb0d: 0x000c, 0xb0e: 0x000c,
+	// Block 0x2d, offset 0xb40
+	0xb71: 0x000c, 0xb74: 0x000c, 0xb75: 0x000c,
+	0xb76: 0x000c, 0xb77: 0x000c, 0xb78: 0x000c, 0xb79: 0x000c, 0xb7b: 0x000c,
+	0xb7c: 0x000c,
+	// Block 0x2e, offset 0xb80
+	0xb88: 0x000c, 0xb89: 0x000c, 0xb8a: 0x000c, 0xb8b: 0x000c,
+	0xb8c: 0x000c, 0xb8d: 0x000c,
+	// Block 0x2f, offset 0xbc0
+	0xbd8: 0x000c, 0xbd9: 0x000c,
+	0xbf5: 0x000c,
+	0xbf7: 0x000c, 0xbf9: 0x000c, 0xbfa: 0x003a, 0xbfb: 0x002a,
+	0xbfc: 0x003a, 0xbfd: 0x002a,
+	// Block 0x30, offset 0xc00
+	0xc31: 0x000c, 0xc32: 0x000c, 0xc33: 0x000c, 0xc34: 0x000c, 0xc35: 0x000c,
+	0xc36: 0x000c, 0xc37: 0x000c, 0xc38: 0x000c, 0xc39: 0x000c, 0xc3a: 0x000c, 0xc3b: 0x000c,
+	0xc3c: 0x000c, 0xc3d: 0x000c, 0xc3e: 0x000c,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x000c, 0xc41: 0x000c, 0xc42: 0x000c, 0xc43: 0x000c, 0xc44: 0x000c,
+	0xc46: 0x000c, 0xc47: 0x000c,
+	0xc4d: 0x000c, 0xc4e: 0x000c, 0xc4f: 0x000c, 0xc50: 0x000c, 0xc51: 0x000c,
+	0xc52: 0x000c, 0xc53: 0x000c, 0xc54: 0x000c, 0xc55: 0x000c, 0xc56: 0x000c, 0xc57: 0x000c,
+	0xc59: 0x000c, 0xc5a: 0x000c, 0xc5b: 0x000c, 0xc5c: 0x000c, 0xc5d: 0x000c,
+	0xc5e: 0x000c, 0xc5f: 0x000c, 0xc60: 0x000c, 0xc61: 0x000c, 0xc62: 0x000c, 0xc63: 0x000c,
+	0xc64: 0x000c, 0xc65: 0x000c, 0xc66: 0x000c, 0xc67: 0x000c, 0xc68: 0x000c, 0xc69: 0x000c,
+	0xc6a: 0x000c, 0xc6b: 0x000c, 0xc6c: 0x000c, 0xc6d: 0x000c, 0xc6e: 0x000c, 0xc6f: 0x000c,
+	0xc70: 0x000c, 0xc71: 0x000c, 0xc72: 0x000c, 0xc73: 0x000c, 0xc74: 0x000c, 0xc75: 0x000c,
+	0xc76: 0x000c, 0xc77: 0x000c, 0xc78: 0x000c, 0xc79: 0x000c, 0xc7a: 0x000c, 0xc7b: 0x000c,
+	0xc7c: 0x000c,
+	// Block 0x32, offset 0xc80
+	0xc86: 0x000c,
+	// Block 0x33, offset 0xcc0
+	0xced: 0x000c, 0xcee: 0x000c, 0xcef: 0x000c,
+	0xcf0: 0x000c, 0xcf2: 0x000c, 0xcf3: 0x000c, 0xcf4: 0x000c, 0xcf5: 0x000c,
+	0xcf6: 0x000c, 0xcf7: 0x000c, 0xcf9: 0x000c, 0xcfa: 0x000c,
+	0xcfd: 0x000c, 0xcfe: 0x000c,
+	// Block 0x34, offset 0xd00
+	0xd18: 0x000c, 0xd19: 0x000c,
+	0xd1e: 0x000c, 0xd1f: 0x000c, 0xd20: 0x000c,
+	0xd31: 0x000c, 0xd32: 0x000c, 0xd33: 0x000c, 0xd34: 0x000c,
+	// Block 0x35, offset 0xd40
+	0xd42: 0x000c, 0xd45: 0x000c,
+	0xd46: 0x000c,
+	0xd4d: 0x000c,
+	0xd5d: 0x000c,
+	// Block 0x36, offset 0xd80
+	0xd9d: 0x000c,
+	0xd9e: 0x000c, 0xd9f: 0x000c,
+	// Block 0x37, offset 0xdc0
+	0xdd0: 0x000a, 0xdd1: 0x000a,
+	0xdd2: 0x000a, 0xdd3: 0x000a, 0xdd4: 0x000a, 0xdd5: 0x000a, 0xdd6: 0x000a, 0xdd7: 0x000a,
+	0xdd8: 0x000a, 0xdd9: 0x000a,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x000a,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x0009,
+	0xe5b: 0x007a, 0xe5c: 0x006a,
+	// Block 0x3a, offset 0xe80
+	0xe92: 0x000c, 0xe93: 0x000c, 0xe94: 0x000c,
+	0xeb2: 0x000c, 0xeb3: 0x000c, 0xeb4: 0x000c,
+	// Block 0x3b, offset 0xec0
+	0xed2: 0x000c, 0xed3: 0x000c,
+	0xef2: 0x000c, 0xef3: 0x000c,
+	// Block 0x3c, offset 0xf00
+	0xf34: 0x000c, 0xf35: 0x000c,
+	0xf37: 0x000c, 0xf38: 0x000c, 0xf39: 0x000c, 0xf3a: 0x000c, 0xf3b: 0x000c,
+	0xf3c: 0x000c, 0xf3d: 0x000c,
+	// Block 0x3d, offset 0xf40
+	0xf46: 0x000c, 0xf49: 0x000c, 0xf4a: 0x000c, 0xf4b: 0x000c,
+	0xf4c: 0x000c, 0xf4d: 0x000c, 0xf4e: 0x000c, 0xf4f: 0x000c, 0xf50: 0x000c, 0xf51: 0x000c,
+	0xf52: 0x000c, 0xf53: 0x000c,
+	0xf5b: 0x0004, 0xf5d: 0x000c,
+	0xf70: 0x000a, 0xf71: 0x000a, 0xf72: 0x000a, 0xf73: 0x000a, 0xf74: 0x000a, 0xf75: 0x000a,
+	0xf76: 0x000a, 0xf77: 0x000a, 0xf78: 0x000a, 0xf79: 0x000a,
+	// Block 0x3e, offset 0xf80
+	0xf80: 0x000a, 0xf81: 0x000a, 0xf82: 0x000a, 0xf83: 0x000a, 0xf84: 0x000a, 0xf85: 0x000a,
+	0xf86: 0x000a, 0xf87: 0x000a, 0xf88: 0x000a, 0xf89: 0x000a, 0xf8a: 0x000a, 0xf8b: 0x000c,
+	0xf8c: 0x000c, 0xf8d: 0x000c, 0xf8e: 0x000b,
+	// Block 0x3f, offset 0xfc0
+	0xfc5: 0x000c,
+	0xfc6: 0x000c,
+	0xfe9: 0x000c,
+	// Block 0x40, offset 0x1000
+	0x1020: 0x000c, 0x1021: 0x000c, 0x1022: 0x000c,
+	0x1027: 0x000c, 0x1028: 0x000c,
+	0x1032: 0x000c,
+	0x1039: 0x000c, 0x103a: 0x000c, 0x103b: 0x000c,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x000a, 0x1044: 0x000a, 0x1045: 0x000a,
+	// Block 0x42, offset 0x1080
+	0x109e: 0x000a, 0x109f: 0x000a, 0x10a0: 0x000a, 0x10a1: 0x000a, 0x10a2: 0x000a, 0x10a3: 0x000a,
+	0x10a4: 0x000a, 0x10a5: 0x000a, 0x10a6: 0x000a, 0x10a7: 0x000a, 0x10a8: 0x000a, 0x10a9: 0x000a,
+	0x10aa: 0x000a, 0x10ab: 0x000a, 0x10ac: 0x000a, 0x10ad: 0x000a, 0x10ae: 0x000a, 0x10af: 0x000a,
+	0x10b0: 0x000a, 0x10b1: 0x000a, 0x10b2: 0x000a, 0x10b3: 0x000a, 0x10b4: 0x000a, 0x10b5: 0x000a,
+	0x10b6: 0x000a, 0x10b7: 0x000a, 0x10b8: 0x000a, 0x10b9: 0x000a, 0x10ba: 0x000a, 0x10bb: 0x000a,
+	0x10bc: 0x000a, 0x10bd: 0x000a, 0x10be: 0x000a, 0x10bf: 0x000a,
+	// Block 0x43, offset 0x10c0
+	0x10d7: 0x000c,
+	0x10d8: 0x000c, 0x10db: 0x000c,
+	// Block 0x44, offset 0x1100
+	0x1116: 0x000c,
+	0x1118: 0x000c, 0x1119: 0x000c, 0x111a: 0x000c, 0x111b: 0x000c, 0x111c: 0x000c, 0x111d: 0x000c,
+	0x111e: 0x000c, 0x1120: 0x000c, 0x1122: 0x000c,
+	0x1125: 0x000c, 0x1126: 0x000c, 0x1127: 0x000c, 0x1128: 0x000c, 0x1129: 0x000c,
+	0x112a: 0x000c, 0x112b: 0x000c, 0x112c: 0x000c,
+	0x1133: 0x000c, 0x1134: 0x000c, 0x1135: 0x000c,
+	0x1136: 0x000c, 0x1137: 0x000c, 0x1138: 0x000c, 0x1139: 0x000c, 0x113a: 0x000c, 0x113b: 0x000c,
+	0x113c: 0x000c, 0x113f: 0x000c,
+	// Block 0x45, offset 0x1140
+	0x1170: 0x000c, 0x1171: 0x000c, 0x1172: 0x000c, 0x1173: 0x000c, 0x1174: 0x000c, 0x1175: 0x000c,
+	0x1176: 0x000c, 0x1177: 0x000c, 0x1178: 0x000c, 0x1179: 0x000c, 0x117a: 0x000c, 0x117b: 0x000c,
+	0x117c: 0x000c, 0x117d: 0x000c, 0x117e: 0x000c,
+	// Block 0x46, offset 0x1180
+	0x1180: 0x000c, 0x1181: 0x000c, 0x1182: 0x000c, 0x1183: 0x000c,
+	0x11b4: 0x000c,
+	0x11b6: 0x000c, 0x11b7: 0x000c, 0x11b8: 0x000c, 0x11b9: 0x000c, 0x11ba: 0x000c,
+	0x11bc: 0x000c,
+	// Block 0x47, offset 0x11c0
+	0x11c2: 0x000c,
+	0x11eb: 0x000c, 0x11ec: 0x000c, 0x11ed: 0x000c, 0x11ee: 0x000c, 0x11ef: 0x000c,
+	0x11f0: 0x000c, 0x11f1: 0x000c, 0x11f2: 0x000c, 0x11f3: 0x000c,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x000c, 0x1201: 0x000c,
+	0x1222: 0x000c, 0x1223: 0x000c,
+	0x1224: 0x000c, 0x1225: 0x000c, 0x1228: 0x000c, 0x1229: 0x000c,
+	0x122b: 0x000c, 0x122c: 0x000c, 0x122d: 0x000c,
+	// Block 0x49, offset 0x1240
+	0x1266: 0x000c, 0x1268: 0x000c, 0x1269: 0x000c,
+	0x126d: 0x000c, 0x126f: 0x000c,
+	0x1270: 0x000c, 0x1271: 0x000c,
+	// Block 0x4a, offset 0x1280
+	0x12ac: 0x000c, 0x12ad: 0x000c, 0x12ae: 0x000c, 0x12af: 0x000c,
+	0x12b0: 0x000c, 0x12b1: 0x000c, 0x12b2: 0x000c, 0x12b3: 0x000c,
+	0x12b6: 0x000c, 0x12b7: 0x000c,
+	// Block 0x4b, offset 0x12c0
+	0x12d0: 0x000c, 0x12d1: 0x000c,
+	0x12d2: 0x000c, 0x12d4: 0x000c, 0x12d5: 0x000c, 0x12d6: 0x000c, 0x12d7: 0x000c,
+	0x12d8: 0x000c, 0x12d9: 0x000c, 0x12da: 0x000c, 0x12db: 0x000c, 0x12dc: 0x000c, 0x12dd: 0x000c,
+	0x12de: 0x000c, 0x12df: 0x000c, 0x12e0: 0x000c, 0x12e2: 0x000c, 0x12e3: 0x000c,
+	0x12e4: 0x000c, 0x12e5: 0x000c, 0x12e6: 0x000c, 0x12e7: 0x000c, 0x12e8: 0x000c,
+	0x12ed: 0x000c,
+	0x12f4: 0x000c,
+	0x12f8: 0x000c, 0x12f9: 0x000c,
+	// Block 0x4c, offset 0x1300
+	0x1300: 0x000c, 0x1301: 0x000c, 0x1302: 0x000c, 0x1303: 0x000c, 0x1304: 0x000c, 0x1305: 0x000c,
+	0x1306: 0x000c, 0x1307: 0x000c, 0x1308: 0x000c, 0x1309: 0x000c, 0x130a: 0x000c, 0x130b: 0x000c,
+	0x130c: 0x000c, 0x130d: 0x000c, 0x130e: 0x000c, 0x130f: 0x000c, 0x1310: 0x000c, 0x1311: 0x000c,
+	0x1312: 0x000c, 0x1313: 0x000c, 0x1314: 0x000c, 0x1315: 0x000c, 0x1316: 0x000c, 0x1317: 0x000c,
+	0x1318: 0x000c, 0x1319: 0x000c, 0x131a: 0x000c, 0x131b: 0x000c, 0x131c: 0x000c, 0x131d: 0x000c,
+	0x131e: 0x000c, 0x131f: 0x000c, 0x1320: 0x000c, 0x1321: 0x000c, 0x1322: 0x000c, 0x1323: 0x000c,
+	0x1324: 0x000c, 0x1325: 0x000c, 0x1326: 0x000c, 0x1327: 0x000c, 0x1328: 0x000c, 0x1329: 0x000c,
+	0x132a: 0x000c, 0x132b: 0x000c, 0x132c: 0x000c, 0x132d: 0x000c, 0x132e: 0x000c, 0x132f: 0x000c,
+	0x1330: 0x000c, 0x1331: 0x000c, 0x1332: 0x000c, 0x1333: 0x000c, 0x1334: 0x000c, 0x1335: 0x000c,
+	0x133b: 0x000c,
+	0x133c: 0x000c, 0x133d: 0x000c, 0x133e: 0x000c, 0x133f: 0x000c,
+	// Block 0x4d, offset 0x1340
+	0x137d: 0x000a, 0x137f: 0x000a,
+	// Block 0x4e, offset 0x1380
+	0x1380: 0x000a, 0x1381: 0x000a,
+	0x138d: 0x000a, 0x138e: 0x000a, 0x138f: 0x000a,
+	0x139d: 0x000a,
+	0x139e: 0x000a, 0x139f: 0x000a,
+	0x13ad: 0x000a, 0x13ae: 0x000a, 0x13af: 0x000a,
+	0x13bd: 0x000a, 0x13be: 0x000a,
+	// Block 0x4f, offset 0x13c0
+	0x13c0: 0x0009, 0x13c1: 0x0009, 0x13c2: 0x0009, 0x13c3: 0x0009, 0x13c4: 0x0009, 0x13c5: 0x0009,
+	0x13c6: 0x0009, 0x13c7: 0x0009, 0x13c8: 0x0009, 0x13c9: 0x0009, 0x13ca: 0x0009, 0x13cb: 0x000b,
+	0x13cc: 0x000b, 0x13cd: 0x000b, 0x13cf: 0x0001, 0x13d0: 0x000a, 0x13d1: 0x000a,
+	0x13d2: 0x000a, 0x13d3: 0x000a, 0x13d4: 0x000a, 0x13d5: 0x000a, 0x13d6: 0x000a, 0x13d7: 0x000a,
+	0x13d8: 0x000a, 0x13d9: 0x000a, 0x13da: 0x000a, 0x13db: 0x000a, 0x13dc: 0x000a, 0x13dd: 0x000a,
+	0x13de: 0x000a, 0x13df: 0x000a, 0x13e0: 0x000a, 0x13e1: 0x000a, 0x13e2: 0x000a, 0x13e3: 0x000a,
+	0x13e4: 0x000a, 0x13e5: 0x000a, 0x13e6: 0x000a, 0x13e7: 0x000a, 0x13e8: 0x0009, 0x13e9: 0x0007,
+	0x13ea: 0x000e, 0x13eb: 0x000e, 0x13ec: 0x000e, 0x13ed: 0x000e, 0x13ee: 0x000e, 0x13ef: 0x0006,
+	0x13f0: 0x0004, 0x13f1: 0x0004, 0x13f2: 0x0004, 0x13f3: 0x0004, 0x13f4: 0x0004, 0x13f5: 0x000a,
+	0x13f6: 0x000a, 0x13f7: 0x000a, 0x13f8: 0x000a, 0x13f9: 0x000a, 0x13fa: 0x000a, 0x13fb: 0x000a,
+	0x13fc: 0x000a, 0x13fd: 0x000a, 0x13fe: 0x000a, 0x13ff: 0x000a,
+	// Block 0x50, offset 0x1400
+	0x1400: 0x000a, 0x1401: 0x000a, 0x1402: 0x000a, 0x1403: 0x000a, 0x1404: 0x0006, 0x1405: 0x009a,
+	0x1406: 0x008a, 0x1407: 0x000a, 0x1408: 0x000a, 0x1409: 0x000a, 0x140a: 0x000a, 0x140b: 0x000a,
+	0x140c: 0x000a, 0x140d: 0x000a, 0x140e: 0x000a, 0x140f: 0x000a, 0x1410: 0x000a, 0x1411: 0x000a,
+	0x1412: 0x000a, 0x1413: 0x000a, 0x1414: 0x000a, 0x1415: 0x000a, 0x1416: 0x000a, 0x1417: 0x000a,
+	0x1418: 0x000a, 0x1419: 0x000a, 0x141a: 0x000a, 0x141b: 0x000a, 0x141c: 0x000a, 0x141d: 0x000a,
+	0x141e: 0x000a, 0x141f: 0x0009, 0x1420: 0x000b, 0x1421: 0x000b, 0x1422: 0x000b, 0x1423: 0x000b,
+	0x1424: 0x000b, 0x1425: 0x000b, 0x1426: 0x000e, 0x1427: 0x000e, 0x1428: 0x000e, 0x1429: 0x000e,
+	0x142a: 0x000b, 0x142b: 0x000b, 0x142c: 0x000b, 0x142d: 0x000b, 0x142e: 0x000b, 0x142f: 0x000b,
+	0x1430: 0x0002, 0x1434: 0x0002, 0x1435: 0x0002,
+	0x1436: 0x0002, 0x1437: 0x0002, 0x1438: 0x0002, 0x1439: 0x0002, 0x143a: 0x0003, 0x143b: 0x0003,
+	0x143c: 0x000a, 0x143d: 0x009a, 0x143e: 0x008a,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x0002, 0x1441: 0x0002, 0x1442: 0x0002, 0x1443: 0x0002, 0x1444: 0x0002, 0x1445: 0x0002,
+	0x1446: 0x0002, 0x1447: 0x0002, 0x1448: 0x0002, 0x1449: 0x0002, 0x144a: 0x0003, 0x144b: 0x0003,
+	0x144c: 0x000a, 0x144d: 0x009a, 0x144e: 0x008a,
+	0x1460: 0x0004, 0x1461: 0x0004, 0x1462: 0x0004, 0x1463: 0x0004,
+	0x1464: 0x0004, 0x1465: 0x0004, 0x1466: 0x0004, 0x1467: 0x0004, 0x1468: 0x0004, 0x1469: 0x0004,
+	0x146a: 0x0004, 0x146b: 0x0004, 0x146c: 0x0004, 0x146d: 0x0004, 0x146e: 0x0004, 0x146f: 0x0004,
+	0x1470: 0x0004, 0x1471: 0x0004, 0x1472: 0x0004, 0x1473: 0x0004, 0x1474: 0x0004, 0x1475: 0x0004,
+	0x1476: 0x0004, 0x1477: 0x0004, 0x1478: 0x0004, 0x1479: 0x0004, 0x147a: 0x0004, 0x147b: 0x0004,
+	0x147c: 0x0004, 0x147d: 0x0004, 0x147e: 0x0004, 0x147f: 0x0004,
+	// Block 0x52, offset 0x1480
+	0x1480: 0x0004, 0x1481: 0x0004, 0x1482: 0x0004, 0x1483: 0x0004, 0x1484: 0x0004, 0x1485: 0x0004,
+	0x1486: 0x0004, 0x1487: 0x0004, 0x1488: 0x0004, 0x1489: 0x0004, 0x148a: 0x0004, 0x148b: 0x0004,
+	0x148c: 0x0004, 0x148d: 0x0004, 0x148e: 0x0004, 0x148f: 0x0004, 0x1490: 0x000c, 0x1491: 0x000c,
+	0x1492: 0x000c, 0x1493: 0x000c, 0x1494: 0x000c, 0x1495: 0x000c, 0x1496: 0x000c, 0x1497: 0x000c,
+	0x1498: 0x000c, 0x1499: 0x000c, 0x149a: 0x000c, 0x149b: 0x000c, 0x149c: 0x000c, 0x149d: 0x000c,
+	0x149e: 0x000c, 0x149f: 0x000c, 0x14a0: 0x000c, 0x14a1: 0x000c, 0x14a2: 0x000c, 0x14a3: 0x000c,
+	0x14a4: 0x000c, 0x14a5: 0x000c, 0x14a6: 0x000c, 0x14a7: 0x000c, 0x14a8: 0x000c, 0x14a9: 0x000c,
+	0x14aa: 0x000c, 0x14ab: 0x000c, 0x14ac: 0x000c, 0x14ad: 0x000c, 0x14ae: 0x000c, 0x14af: 0x000c,
+	0x14b0: 0x000c,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x000a, 0x14c1: 0x000a, 0x14c3: 0x000a, 0x14c4: 0x000a, 0x14c5: 0x000a,
+	0x14c6: 0x000a, 0x14c8: 0x000a, 0x14c9: 0x000a,
+	0x14d4: 0x000a, 0x14d6: 0x000a, 0x14d7: 0x000a,
+	0x14d8: 0x000a,
+	0x14de: 0x000a, 0x14df: 0x000a, 0x14e0: 0x000a, 0x14e1: 0x000a, 0x14e2: 0x000a, 0x14e3: 0x000a,
+	0x14e5: 0x000a, 0x14e7: 0x000a, 0x14e9: 0x000a,
+	0x14ee: 0x0004,
+	0x14fa: 0x000a, 0x14fb: 0x000a,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x000a, 0x1501: 0x000a, 0x1502: 0x000a, 0x1503: 0x000a, 0x1504: 0x000a,
+	0x150a: 0x000a, 0x150b: 0x000a,
+	0x150c: 0x000a, 0x150d: 0x000a, 0x1510: 0x000a, 0x1511: 0x000a,
+	0x1512: 0x000a, 0x1513: 0x000a, 0x1514: 0x000a, 0x1515: 0x000a, 0x1516: 0x000a, 0x1517: 0x000a,
+	0x1518: 0x000a, 0x1519: 0x000a, 0x151a: 0x000a, 0x151b: 0x000a, 0x151c: 0x000a, 0x151d: 0x000a,
+	0x151e: 0x000a, 0x151f: 0x000a,
+	// Block 0x55, offset 0x1540
+	0x1549: 0x000a, 0x154a: 0x000a, 0x154b: 0x000a,
+	0x1550: 0x000a, 0x1551: 0x000a,
+	0x1552: 0x000a, 0x1553: 0x000a, 0x1554: 0x000a, 0x1555: 0x000a, 0x1556: 0x000a, 0x1557: 0x000a,
+	0x1558: 0x000a, 0x1559: 0x000a, 0x155a: 0x000a, 0x155b: 0x000a, 0x155c: 0x000a, 0x155d: 0x000a,
+	0x155e: 0x000a, 0x155f: 0x000a, 0x1560: 0x000a, 0x1561: 0x000a, 0x1562: 0x000a, 0x1563: 0x000a,
+	0x1564: 0x000a, 0x1565: 0x000a, 0x1566: 0x000a, 0x1567: 0x000a, 0x1568: 0x000a, 0x1569: 0x000a,
+	0x156a: 0x000a, 0x156b: 0x000a, 0x156c: 0x000a, 0x156d: 0x000a, 0x156e: 0x000a, 0x156f: 0x000a,
+	0x1570: 0x000a, 0x1571: 0x000a, 0x1572: 0x000a, 0x1573: 0x000a, 0x1574: 0x000a, 0x1575: 0x000a,
+	0x1576: 0x000a, 0x1577: 0x000a, 0x1578: 0x000a, 0x1579: 0x000a, 0x157a: 0x000a, 0x157b: 0x000a,
+	0x157c: 0x000a, 0x157d: 0x000a, 0x157e: 0x000a, 0x157f: 0x000a,
+	// Block 0x56, offset 0x1580
+	0x1580: 0x000a, 0x1581: 0x000a, 0x1582: 0x000a, 0x1583: 0x000a, 0x1584: 0x000a, 0x1585: 0x000a,
+	0x1586: 0x000a, 0x1587: 0x000a, 0x1588: 0x000a, 0x1589: 0x000a, 0x158a: 0x000a, 0x158b: 0x000a,
+	0x158c: 0x000a, 0x158d: 0x000a, 0x158e: 0x000a, 0x158f: 0x000a, 0x1590: 0x000a, 0x1591: 0x000a,
+	0x1592: 0x000a, 0x1593: 0x000a, 0x1594: 0x000a, 0x1595: 0x000a, 0x1596: 0x000a, 0x1597: 0x000a,
+	0x1598: 0x000a, 0x1599: 0x000a, 0x159a: 0x000a, 0x159b: 0x000a, 0x159c: 0x000a, 0x159d: 0x000a,
+	0x159e: 0x000a, 0x159f: 0x000a, 0x15a0: 0x000a, 0x15a1: 0x000a, 0x15a2: 0x000a, 0x15a3: 0x000a,
+	0x15a4: 0x000a, 0x15a5: 0x000a, 0x15a6: 0x000a, 0x15a7: 0x000a, 0x15a8: 0x000a, 0x15a9: 0x000a,
+	0x15aa: 0x000a, 0x15ab: 0x000a, 0x15ac: 0x000a, 0x15ad: 0x000a, 0x15ae: 0x000a, 0x15af: 0x000a,
+	0x15b0: 0x000a, 0x15b1: 0x000a, 0x15b2: 0x000a, 0x15b3: 0x000a, 0x15b4: 0x000a, 0x15b5: 0x000a,
+	0x15b6: 0x000a, 0x15b7: 0x000a, 0x15b8: 0x000a, 0x15b9: 0x000a, 0x15ba: 0x000a, 0x15bb: 0x000a,
+	0x15bc: 0x000a, 0x15bd: 0x000a, 0x15be: 0x000a, 0x15bf: 0x000a,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x000a, 0x15c1: 0x000a, 0x15c2: 0x000a, 0x15c3: 0x000a, 0x15c4: 0x000a, 0x15c5: 0x000a,
+	0x15c6: 0x000a, 0x15c7: 0x000a, 0x15c8: 0x000a, 0x15c9: 0x000a, 0x15ca: 0x000a, 0x15cb: 0x000a,
+	0x15cc: 0x000a, 0x15cd: 0x000a, 0x15ce: 0x000a, 0x15cf: 0x000a, 0x15d0: 0x000a, 0x15d1: 0x000a,
+	0x15d2: 0x0003, 0x15d3: 0x0004, 0x15d4: 0x000a, 0x15d5: 0x000a, 0x15d6: 0x000a, 0x15d7: 0x000a,
+	0x15d8: 0x000a, 0x15d9: 0x000a, 0x15da: 0x000a, 0x15db: 0x000a, 0x15dc: 0x000a, 0x15dd: 0x000a,
+	0x15de: 0x000a, 0x15df: 0x000a, 0x15e0: 0x000a, 0x15e1: 0x000a, 0x15e2: 0x000a, 0x15e3: 0x000a,
+	0x15e4: 0x000a, 0x15e5: 0x000a, 0x15e6: 0x000a, 0x15e7: 0x000a, 0x15e8: 0x000a, 0x15e9: 0x000a,
+	0x15ea: 0x000a, 0x15eb: 0x000a, 0x15ec: 0x000a, 0x15ed: 0x000a, 0x15ee: 0x000a, 0x15ef: 0x000a,
+	0x15f0: 0x000a, 0x15f1: 0x000a, 0x15f2: 0x000a, 0x15f3: 0x000a, 0x15f4: 0x000a, 0x15f5: 0x000a,
+	0x15f6: 0x000a, 0x15f7: 0x000a, 0x15f8: 0x000a, 0x15f9: 0x000a, 0x15fa: 0x000a, 0x15fb: 0x000a,
+	0x15fc: 0x000a, 0x15fd: 0x000a, 0x15fe: 0x000a, 0x15ff: 0x000a,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x000a, 0x1601: 0x000a, 0x1602: 0x000a, 0x1603: 0x000a, 0x1604: 0x000a, 0x1605: 0x000a,
+	0x1606: 0x000a, 0x1607: 0x000a, 0x1608: 0x003a, 0x1609: 0x002a, 0x160a: 0x003a, 0x160b: 0x002a,
+	0x160c: 0x000a, 0x160d: 0x000a, 0x160e: 0x000a, 0x160f: 0x000a, 0x1610: 0x000a, 0x1611: 0x000a,
+	0x1612: 0x000a, 0x1613: 0x000a, 0x1614: 0x000a, 0x1615: 0x000a, 0x1616: 0x000a, 0x1617: 0x000a,
+	0x1618: 0x000a, 0x1619: 0x000a, 0x161a: 0x000a, 0x161b: 0x000a, 0x161c: 0x000a, 0x161d: 0x000a,
+	0x161e: 0x000a, 0x161f: 0x000a, 0x1620: 0x000a, 0x1621: 0x000a, 0x1622: 0x000a, 0x1623: 0x000a,
+	0x1624: 0x000a, 0x1625: 0x000a, 0x1626: 0x000a, 0x1627: 0x000a, 0x1628: 0x000a, 0x1629: 0x009a,
+	0x162a: 0x008a, 0x162b: 0x000a, 0x162c: 0x000a, 0x162d: 0x000a, 0x162e: 0x000a, 0x162f: 0x000a,
+	0x1630: 0x000a, 0x1631: 0x000a, 0x1632: 0x000a, 0x1633: 0x000a, 0x1634: 0x000a, 0x1635: 0x000a,
+	// Block 0x59, offset 0x1640
+	0x167b: 0x000a,
+	0x167c: 0x000a, 0x167d: 0x000a, 0x167e: 0x000a, 0x167f: 0x000a,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x000a, 0x1681: 0x000a, 0x1682: 0x000a, 0x1683: 0x000a, 0x1684: 0x000a, 0x1685: 0x000a,
+	0x1686: 0x000a, 0x1687: 0x000a, 0x1688: 0x000a, 0x1689: 0x000a, 0x168a: 0x000a, 0x168b: 0x000a,
+	0x168c: 0x000a, 0x168d: 0x000a, 0x168e: 0x000a, 0x168f: 0x000a, 0x1690: 0x000a, 0x1691: 0x000a,
+	0x1692: 0x000a, 0x1693: 0x000a, 0x1694: 0x000a, 0x1696: 0x000a, 0x1697: 0x000a,
+	0x1698: 0x000a, 0x1699: 0x000a, 0x169a: 0x000a, 0x169b: 0x000a, 0x169c: 0x000a, 0x169d: 0x000a,
+	0x169e: 0x000a, 0x169f: 0x000a, 0x16a0: 0x000a, 0x16a1: 0x000a, 0x16a2: 0x000a, 0x16a3: 0x000a,
+	0x16a4: 0x000a, 0x16a5: 0x000a, 0x16a6: 0x000a, 0x16a7: 0x000a, 0x16a8: 0x000a, 0x16a9: 0x000a,
+	0x16aa: 0x000a, 0x16ab: 0x000a, 0x16ac: 0x000a, 0x16ad: 0x000a, 0x16ae: 0x000a, 0x16af: 0x000a,
+	0x16b0: 0x000a, 0x16b1: 0x000a, 0x16b2: 0x000a, 0x16b3: 0x000a, 0x16b4: 0x000a, 0x16b5: 0x000a,
+	0x16b6: 0x000a, 0x16b7: 0x000a, 0x16b8: 0x000a, 0x16b9: 0x000a, 0x16ba: 0x000a, 0x16bb: 0x000a,
+	0x16bc: 0x000a, 0x16bd: 0x000a, 0x16be: 0x000a, 0x16bf: 0x000a,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x000a, 0x16c1: 0x000a, 0x16c2: 0x000a, 0x16c3: 0x000a, 0x16c4: 0x000a, 0x16c5: 0x000a,
+	0x16c6: 0x000a, 0x16c7: 0x000a, 0x16c8: 0x000a, 0x16c9: 0x000a, 0x16ca: 0x000a, 0x16cb: 0x000a,
+	0x16cc: 0x000a, 0x16cd: 0x000a, 0x16ce: 0x000a, 0x16cf: 0x000a, 0x16d0: 0x000a, 0x16d1: 0x000a,
+	0x16d2: 0x000a, 0x16d3: 0x000a, 0x16d4: 0x000a, 0x16d5: 0x000a, 0x16d6: 0x000a, 0x16d7: 0x000a,
+	0x16d8: 0x000a, 0x16d9: 0x000a, 0x16da: 0x000a, 0x16db: 0x000a, 0x16dc: 0x000a, 0x16dd: 0x000a,
+	0x16de: 0x000a, 0x16df: 0x000a, 0x16e0: 0x000a, 0x16e1: 0x000a, 0x16e2: 0x000a, 0x16e3: 0x000a,
+	0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, 0x16e7: 0x000a, 0x16e8: 0x000a, 0x16e9: 0x000a,
+	0x16ea: 0x000a, 0x16eb: 0x000a, 0x16ec: 0x000a, 0x16ed: 0x000a, 0x16ee: 0x000a, 0x16ef: 0x000a,
+	0x16f0: 0x000a, 0x16f1: 0x000a, 0x16f2: 0x000a, 0x16f3: 0x000a, 0x16f4: 0x000a, 0x16f5: 0x000a,
+	0x16f6: 0x000a, 0x16f7: 0x000a, 0x16f8: 0x000a, 0x16f9: 0x000a, 0x16fa: 0x000a, 0x16fb: 0x000a,
+	0x16fc: 0x000a, 0x16fd: 0x000a, 0x16fe: 0x000a,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x000a, 0x1701: 0x000a, 0x1702: 0x000a, 0x1703: 0x000a, 0x1704: 0x000a, 0x1705: 0x000a,
+	0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, 0x170b: 0x000a,
+	0x170c: 0x000a, 0x170d: 0x000a, 0x170e: 0x000a, 0x170f: 0x000a, 0x1710: 0x000a, 0x1711: 0x000a,
+	0x1712: 0x000a, 0x1713: 0x000a, 0x1714: 0x000a, 0x1715: 0x000a, 0x1716: 0x000a, 0x1717: 0x000a,
+	0x1718: 0x000a, 0x1719: 0x000a, 0x171a: 0x000a, 0x171b: 0x000a, 0x171c: 0x000a, 0x171d: 0x000a,
+	0x171e: 0x000a, 0x171f: 0x000a, 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a,
+	0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a,
+	// Block 0x5d, offset 0x1740
+	0x1740: 0x000a, 0x1741: 0x000a, 0x1742: 0x000a, 0x1743: 0x000a, 0x1744: 0x000a, 0x1745: 0x000a,
+	0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x000a, 0x1749: 0x000a, 0x174a: 0x000a,
+	0x1760: 0x000a, 0x1761: 0x000a, 0x1762: 0x000a, 0x1763: 0x000a,
+	0x1764: 0x000a, 0x1765: 0x000a, 0x1766: 0x000a, 0x1767: 0x000a, 0x1768: 0x000a, 0x1769: 0x000a,
+	0x176a: 0x000a, 0x176b: 0x000a, 0x176c: 0x000a, 0x176d: 0x000a, 0x176e: 0x000a, 0x176f: 0x000a,
+	0x1770: 0x000a, 0x1771: 0x000a, 0x1772: 0x000a, 0x1773: 0x000a, 0x1774: 0x000a, 0x1775: 0x000a,
+	0x1776: 0x000a, 0x1777: 0x000a, 0x1778: 0x000a, 0x1779: 0x000a, 0x177a: 0x000a, 0x177b: 0x000a,
+	0x177c: 0x000a, 0x177d: 0x000a, 0x177e: 0x000a, 0x177f: 0x000a,
+	// Block 0x5e, offset 0x1780
+	0x1780: 0x000a, 0x1781: 0x000a, 0x1782: 0x000a, 0x1783: 0x000a, 0x1784: 0x000a, 0x1785: 0x000a,
+	0x1786: 0x000a, 0x1787: 0x000a, 0x1788: 0x0002, 0x1789: 0x0002, 0x178a: 0x0002, 0x178b: 0x0002,
+	0x178c: 0x0002, 0x178d: 0x0002, 0x178e: 0x0002, 0x178f: 0x0002, 0x1790: 0x0002, 0x1791: 0x0002,
+	0x1792: 0x0002, 0x1793: 0x0002, 0x1794: 0x0002, 0x1795: 0x0002, 0x1796: 0x0002, 0x1797: 0x0002,
+	0x1798: 0x0002, 0x1799: 0x0002, 0x179a: 0x0002, 0x179b: 0x0002,
+	// Block 0x5f, offset 0x17c0
+	0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ec: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a,
+	0x17f0: 0x000a, 0x17f1: 0x000a, 0x17f2: 0x000a, 0x17f3: 0x000a, 0x17f4: 0x000a, 0x17f5: 0x000a,
+	0x17f6: 0x000a, 0x17f7: 0x000a, 0x17f8: 0x000a, 0x17f9: 0x000a, 0x17fa: 0x000a, 0x17fb: 0x000a,
+	0x17fc: 0x000a, 0x17fd: 0x000a, 0x17fe: 0x000a, 0x17ff: 0x000a,
+	// Block 0x60, offset 0x1800
+	0x1800: 0x000a, 0x1801: 0x000a, 0x1802: 0x000a, 0x1803: 0x000a, 0x1804: 0x000a, 0x1805: 0x000a,
+	0x1806: 0x000a, 0x1807: 0x000a, 0x1808: 0x000a, 0x1809: 0x000a, 0x180a: 0x000a, 0x180b: 0x000a,
+	0x180c: 0x000a, 0x180d: 0x000a, 0x180e: 0x000a, 0x180f: 0x000a, 0x1810: 0x000a, 0x1811: 0x000a,
+	0x1812: 0x000a, 0x1813: 0x000a, 0x1814: 0x000a, 0x1815: 0x000a, 0x1816: 0x000a, 0x1817: 0x000a,
+	0x1818: 0x000a, 0x1819: 0x000a, 0x181a: 0x000a, 0x181b: 0x000a, 0x181c: 0x000a, 0x181d: 0x000a,
+	0x181e: 0x000a, 0x181f: 0x000a, 0x1820: 0x000a, 0x1821: 0x000a, 0x1822: 0x000a, 0x1823: 0x000a,
+	0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x000a, 0x1829: 0x000a,
+	0x182a: 0x000a, 0x182b: 0x000a, 0x182d: 0x000a, 0x182e: 0x000a, 0x182f: 0x000a,
+	0x1830: 0x000a, 0x1831: 0x000a, 0x1832: 0x000a, 0x1833: 0x000a, 0x1834: 0x000a, 0x1835: 0x000a,
+	0x1836: 0x000a, 0x1837: 0x000a, 0x1838: 0x000a, 0x1839: 0x000a, 0x183a: 0x000a, 0x183b: 0x000a,
+	0x183c: 0x000a, 0x183d: 0x000a, 0x183e: 0x000a, 0x183f: 0x000a,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x000a,
+	0x1846: 0x000a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a,
+	0x184c: 0x000a, 0x184d: 0x000a, 0x184e: 0x000a, 0x184f: 0x000a, 0x1850: 0x000a, 0x1851: 0x000a,
+	0x1852: 0x000a, 0x1853: 0x000a, 0x1854: 0x000a, 0x1855: 0x000a, 0x1856: 0x000a, 0x1857: 0x000a,
+	0x1858: 0x000a, 0x1859: 0x000a, 0x185a: 0x000a, 0x185b: 0x000a, 0x185c: 0x000a, 0x185d: 0x000a,
+	0x185e: 0x000a, 0x185f: 0x000a, 0x1860: 0x000a, 0x1861: 0x000a, 0x1862: 0x000a, 0x1863: 0x000a,
+	0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x000a, 0x1867: 0x000a, 0x1868: 0x003a, 0x1869: 0x002a,
+	0x186a: 0x003a, 0x186b: 0x002a, 0x186c: 0x003a, 0x186d: 0x002a, 0x186e: 0x003a, 0x186f: 0x002a,
+	0x1870: 0x003a, 0x1871: 0x002a, 0x1872: 0x003a, 0x1873: 0x002a, 0x1874: 0x003a, 0x1875: 0x002a,
+	0x1876: 0x000a, 0x1877: 0x000a, 0x1878: 0x000a, 0x1879: 0x000a, 0x187a: 0x000a, 0x187b: 0x000a,
+	0x187c: 0x000a, 0x187d: 0x000a, 0x187e: 0x000a, 0x187f: 0x000a,
+	// Block 0x62, offset 0x1880
+	0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x000a, 0x1884: 0x000a, 0x1885: 0x009a,
+	0x1886: 0x008a, 0x1887: 0x000a, 0x1888: 0x000a, 0x1889: 0x000a, 0x188a: 0x000a, 0x188b: 0x000a,
+	0x188c: 0x000a, 0x188d: 0x000a, 0x188e: 0x000a, 0x188f: 0x000a, 0x1890: 0x000a, 0x1891: 0x000a,
+	0x1892: 0x000a, 0x1893: 0x000a, 0x1894: 0x000a, 0x1895: 0x000a, 0x1896: 0x000a, 0x1897: 0x000a,
+	0x1898: 0x000a, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a,
+	0x189e: 0x000a, 0x189f: 0x000a, 0x18a0: 0x000a, 0x18a1: 0x000a, 0x18a2: 0x000a, 0x18a3: 0x000a,
+	0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x003a, 0x18a7: 0x002a, 0x18a8: 0x003a, 0x18a9: 0x002a,
+	0x18aa: 0x003a, 0x18ab: 0x002a, 0x18ac: 0x003a, 0x18ad: 0x002a, 0x18ae: 0x003a, 0x18af: 0x002a,
+	0x18b0: 0x000a, 0x18b1: 0x000a, 0x18b2: 0x000a, 0x18b3: 0x000a, 0x18b4: 0x000a, 0x18b5: 0x000a,
+	0x18b6: 0x000a, 0x18b7: 0x000a, 0x18b8: 0x000a, 0x18b9: 0x000a, 0x18ba: 0x000a, 0x18bb: 0x000a,
+	0x18bc: 0x000a, 0x18bd: 0x000a, 0x18be: 0x000a, 0x18bf: 0x000a,
+	// Block 0x63, offset 0x18c0
+	0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x007a, 0x18c4: 0x006a, 0x18c5: 0x009a,
+	0x18c6: 0x008a, 0x18c7: 0x00ba, 0x18c8: 0x00aa, 0x18c9: 0x009a, 0x18ca: 0x008a, 0x18cb: 0x007a,
+	0x18cc: 0x006a, 0x18cd: 0x00da, 0x18ce: 0x002a, 0x18cf: 0x003a, 0x18d0: 0x00ca, 0x18d1: 0x009a,
+	0x18d2: 0x008a, 0x18d3: 0x007a, 0x18d4: 0x006a, 0x18d5: 0x009a, 0x18d6: 0x008a, 0x18d7: 0x00ba,
+	0x18d8: 0x00aa, 0x18d9: 0x000a, 0x18da: 0x000a, 0x18db: 0x000a, 0x18dc: 0x000a, 0x18dd: 0x000a,
+	0x18de: 0x000a, 0x18df: 0x000a, 0x18e0: 0x000a, 0x18e1: 0x000a, 0x18e2: 0x000a, 0x18e3: 0x000a,
+	0x18e4: 0x000a, 0x18e5: 0x000a, 0x18e6: 0x000a, 0x18e7: 0x000a, 0x18e8: 0x000a, 0x18e9: 0x000a,
+	0x18ea: 0x000a, 0x18eb: 0x000a, 0x18ec: 0x000a, 0x18ed: 0x000a, 0x18ee: 0x000a, 0x18ef: 0x000a,
+	0x18f0: 0x000a, 0x18f1: 0x000a, 0x18f2: 0x000a, 0x18f3: 0x000a, 0x18f4: 0x000a, 0x18f5: 0x000a,
+	0x18f6: 0x000a, 0x18f7: 0x000a, 0x18f8: 0x000a, 0x18f9: 0x000a, 0x18fa: 0x000a, 0x18fb: 0x000a,
+	0x18fc: 0x000a, 0x18fd: 0x000a, 0x18fe: 0x000a, 0x18ff: 0x000a,
+	// Block 0x64, offset 0x1900
+	0x1900: 0x000a, 0x1901: 0x000a, 0x1902: 0x000a, 0x1903: 0x000a, 0x1904: 0x000a, 0x1905: 0x000a,
+	0x1906: 0x000a, 0x1907: 0x000a, 0x1908: 0x000a, 0x1909: 0x000a, 0x190a: 0x000a, 0x190b: 0x000a,
+	0x190c: 0x000a, 0x190d: 0x000a, 0x190e: 0x000a, 0x190f: 0x000a, 0x1910: 0x000a, 0x1911: 0x000a,
+	0x1912: 0x000a, 0x1913: 0x000a, 0x1914: 0x000a, 0x1915: 0x000a, 0x1916: 0x000a, 0x1917: 0x000a,
+	0x1918: 0x003a, 0x1919: 0x002a, 0x191a: 0x003a, 0x191b: 0x002a, 0x191c: 0x000a, 0x191d: 0x000a,
+	0x191e: 0x000a, 0x191f: 0x000a, 0x1920: 0x000a, 0x1921: 0x000a, 0x1922: 0x000a, 0x1923: 0x000a,
+	0x1924: 0x000a, 0x1925: 0x000a, 0x1926: 0x000a, 0x1927: 0x000a, 0x1928: 0x000a, 0x1929: 0x000a,
+	0x192a: 0x000a, 0x192b: 0x000a, 0x192c: 0x000a, 0x192d: 0x000a, 0x192e: 0x000a, 0x192f: 0x000a,
+	0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, 0x1934: 0x000a, 0x1935: 0x000a,
+	0x1936: 0x000a, 0x1937: 0x000a, 0x1938: 0x000a, 0x1939: 0x000a, 0x193a: 0x000a, 0x193b: 0x000a,
+	0x193c: 0x003a, 0x193d: 0x002a, 0x193e: 0x000a, 0x193f: 0x000a,
+	// Block 0x65, offset 0x1940
+	0x1940: 0x000a, 0x1941: 0x000a, 0x1942: 0x000a, 0x1943: 0x000a, 0x1944: 0x000a, 0x1945: 0x000a,
+	0x1946: 0x000a, 0x1947: 0x000a, 0x1948: 0x000a, 0x1949: 0x000a, 0x194a: 0x000a, 0x194b: 0x000a,
+	0x194c: 0x000a, 0x194d: 0x000a, 0x194e: 0x000a, 0x194f: 0x000a, 0x1950: 0x000a, 0x1951: 0x000a,
+	0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, 0x1956: 0x000a, 0x1957: 0x000a,
+	0x1958: 0x000a, 0x1959: 0x000a, 0x195a: 0x000a, 0x195b: 0x000a, 0x195c: 0x000a, 0x195d: 0x000a,
+	0x195e: 0x000a, 0x195f: 0x000a, 0x1960: 0x000a, 0x1961: 0x000a, 0x1962: 0x000a, 0x1963: 0x000a,
+	0x1964: 0x000a, 0x1965: 0x000a, 0x1966: 0x000a, 0x1967: 0x000a, 0x1968: 0x000a, 0x1969: 0x000a,
+	0x196a: 0x000a, 0x196b: 0x000a, 0x196c: 0x000a, 0x196d: 0x000a, 0x196e: 0x000a, 0x196f: 0x000a,
+	0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a,
+	0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, 0x197a: 0x000a, 0x197b: 0x000a,
+	0x197c: 0x000a, 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a,
+	// Block 0x66, offset 0x1980
+	0x1980: 0x000a, 0x1981: 0x000a, 0x1982: 0x000a, 0x1983: 0x000a, 0x1984: 0x000a, 0x1985: 0x000a,
+	0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x1989: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a,
+	0x198c: 0x000a, 0x198d: 0x000a, 0x198e: 0x000a, 0x198f: 0x000a, 0x1990: 0x000a, 0x1991: 0x000a,
+	0x1992: 0x000a, 0x1993: 0x000a, 0x1994: 0x000a, 0x1995: 0x000a,
+	0x1998: 0x000a, 0x1999: 0x000a, 0x199a: 0x000a, 0x199b: 0x000a, 0x199c: 0x000a, 0x199d: 0x000a,
+	0x199e: 0x000a, 0x199f: 0x000a, 0x19a0: 0x000a, 0x19a1: 0x000a, 0x19a2: 0x000a, 0x19a3: 0x000a,
+	0x19a4: 0x000a, 0x19a5: 0x000a, 0x19a6: 0x000a, 0x19a7: 0x000a, 0x19a8: 0x000a, 0x19a9: 0x000a,
+	0x19aa: 0x000a, 0x19ab: 0x000a, 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a,
+	0x19b0: 0x000a, 0x19b1: 0x000a, 0x19b2: 0x000a, 0x19b3: 0x000a, 0x19b4: 0x000a, 0x19b5: 0x000a,
+	0x19b6: 0x000a, 0x19b7: 0x000a, 0x19b8: 0x000a, 0x19b9: 0x000a,
+	0x19bd: 0x000a, 0x19be: 0x000a, 0x19bf: 0x000a,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x000a, 0x19c1: 0x000a, 0x19c2: 0x000a, 0x19c3: 0x000a, 0x19c4: 0x000a, 0x19c5: 0x000a,
+	0x19c6: 0x000a, 0x19c7: 0x000a, 0x19c8: 0x000a, 0x19ca: 0x000a, 0x19cb: 0x000a,
+	0x19cc: 0x000a, 0x19cd: 0x000a, 0x19ce: 0x000a, 0x19cf: 0x000a, 0x19d0: 0x000a, 0x19d1: 0x000a,
+	0x19ec: 0x000a, 0x19ed: 0x000a, 0x19ee: 0x000a, 0x19ef: 0x000a,
+	// Block 0x68, offset 0x1a00
+	0x1a25: 0x000a, 0x1a26: 0x000a, 0x1a27: 0x000a, 0x1a28: 0x000a, 0x1a29: 0x000a,
+	0x1a2a: 0x000a, 0x1a2f: 0x000c,
+	0x1a30: 0x000c, 0x1a31: 0x000c,
+	0x1a39: 0x000a, 0x1a3a: 0x000a, 0x1a3b: 0x000a,
+	0x1a3c: 0x000a, 0x1a3d: 0x000a, 0x1a3e: 0x000a, 0x1a3f: 0x000a,
+	// Block 0x69, offset 0x1a40
+	0x1a7f: 0x000c,
+	// Block 0x6a, offset 0x1a80
+	0x1aa0: 0x000c, 0x1aa1: 0x000c, 0x1aa2: 0x000c, 0x1aa3: 0x000c,
+	0x1aa4: 0x000c, 0x1aa5: 0x000c, 0x1aa6: 0x000c, 0x1aa7: 0x000c, 0x1aa8: 0x000c, 0x1aa9: 0x000c,
+	0x1aaa: 0x000c, 0x1aab: 0x000c, 0x1aac: 0x000c, 0x1aad: 0x000c, 0x1aae: 0x000c, 0x1aaf: 0x000c,
+	0x1ab0: 0x000c, 0x1ab1: 0x000c, 0x1ab2: 0x000c, 0x1ab3: 0x000c, 0x1ab4: 0x000c, 0x1ab5: 0x000c,
+	0x1ab6: 0x000c, 0x1ab7: 0x000c, 0x1ab8: 0x000c, 0x1ab9: 0x000c, 0x1aba: 0x000c, 0x1abb: 0x000c,
+	0x1abc: 0x000c, 0x1abd: 0x000c, 0x1abe: 0x000c, 0x1abf: 0x000c,
+	// Block 0x6b, offset 0x1ac0
+	0x1ac0: 0x000a, 0x1ac1: 0x000a, 0x1ac2: 0x000a, 0x1ac3: 0x000a, 0x1ac4: 0x000a, 0x1ac5: 0x000a,
+	0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, 0x1aca: 0x000a, 0x1acb: 0x000a,
+	0x1acc: 0x000a, 0x1acd: 0x000a, 0x1ace: 0x000a, 0x1acf: 0x000a, 0x1ad0: 0x000a, 0x1ad1: 0x000a,
+	0x1ad2: 0x000a, 0x1ad3: 0x000a, 0x1ad4: 0x000a, 0x1ad5: 0x000a, 0x1ad6: 0x000a, 0x1ad7: 0x000a,
+	0x1ad8: 0x000a, 0x1ad9: 0x000a, 0x1ada: 0x000a, 0x1adb: 0x000a, 0x1adc: 0x000a, 0x1add: 0x000a,
+	0x1ade: 0x000a, 0x1adf: 0x000a, 0x1ae0: 0x000a, 0x1ae1: 0x000a, 0x1ae2: 0x003a, 0x1ae3: 0x002a,
+	0x1ae4: 0x003a, 0x1ae5: 0x002a, 0x1ae6: 0x003a, 0x1ae7: 0x002a, 0x1ae8: 0x003a, 0x1ae9: 0x002a,
+	0x1aea: 0x000a, 0x1aeb: 0x000a, 0x1aec: 0x000a, 0x1aed: 0x000a, 0x1aee: 0x000a, 0x1aef: 0x000a,
+	0x1af0: 0x000a, 0x1af1: 0x000a, 0x1af2: 0x000a, 0x1af3: 0x000a, 0x1af4: 0x000a, 0x1af5: 0x000a,
+	0x1af6: 0x000a, 0x1af7: 0x000a, 0x1af8: 0x000a, 0x1af9: 0x000a, 0x1afa: 0x000a, 0x1afb: 0x000a,
+	0x1afc: 0x000a, 0x1afd: 0x000a, 0x1afe: 0x000a, 0x1aff: 0x000a,
+	// Block 0x6c, offset 0x1b00
+	0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a,
+	// Block 0x6d, offset 0x1b40
+	0x1b40: 0x000a, 0x1b41: 0x000a, 0x1b42: 0x000a, 0x1b43: 0x000a, 0x1b44: 0x000a, 0x1b45: 0x000a,
+	0x1b46: 0x000a, 0x1b47: 0x000a, 0x1b48: 0x000a, 0x1b49: 0x000a, 0x1b4a: 0x000a, 0x1b4b: 0x000a,
+	0x1b4c: 0x000a, 0x1b4d: 0x000a, 0x1b4e: 0x000a, 0x1b4f: 0x000a, 0x1b50: 0x000a, 0x1b51: 0x000a,
+	0x1b52: 0x000a, 0x1b53: 0x000a, 0x1b54: 0x000a, 0x1b55: 0x000a, 0x1b56: 0x000a, 0x1b57: 0x000a,
+	0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a,
+	0x1b5e: 0x000a, 0x1b5f: 0x000a, 0x1b60: 0x000a, 0x1b61: 0x000a, 0x1b62: 0x000a, 0x1b63: 0x000a,
+	0x1b64: 0x000a, 0x1b65: 0x000a, 0x1b66: 0x000a, 0x1b67: 0x000a, 0x1b68: 0x000a, 0x1b69: 0x000a,
+	0x1b6a: 0x000a, 0x1b6b: 0x000a, 0x1b6c: 0x000a, 0x1b6d: 0x000a, 0x1b6e: 0x000a, 0x1b6f: 0x000a,
+	0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, 0x1b74: 0x000a, 0x1b75: 0x000a,
+	0x1b76: 0x000a, 0x1b77: 0x000a, 0x1b78: 0x000a, 0x1b79: 0x000a, 0x1b7a: 0x000a, 0x1b7b: 0x000a,
+	0x1b7c: 0x000a, 0x1b7d: 0x000a, 0x1b7e: 0x000a, 0x1b7f: 0x000a,
+	// Block 0x6e, offset 0x1b80
+	0x1b80: 0x000a, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a, 0x1b85: 0x000a,
+	0x1b86: 0x000a, 0x1b87: 0x000a, 0x1b88: 0x000a, 0x1b89: 0x000a, 0x1b8a: 0x000a, 0x1b8b: 0x000a,
+	0x1b8c: 0x000a, 0x1b8d: 0x000a, 0x1b8e: 0x000a, 0x1b8f: 0x000a, 0x1b90: 0x000a, 0x1b91: 0x000a,
+	0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a, 0x1b96: 0x000a, 0x1b97: 0x000a,
+	0x1b98: 0x000a, 0x1b99: 0x000a, 0x1b9a: 0x000a, 0x1b9b: 0x000a, 0x1b9c: 0x000a, 0x1b9d: 0x000a,
+	0x1b9e: 0x000a, 0x1b9f: 0x000a, 0x1ba0: 0x000a, 0x1ba1: 0x000a, 0x1ba2: 0x000a, 0x1ba3: 0x000a,
+	0x1ba4: 0x000a, 0x1ba5: 0x000a, 0x1ba6: 0x000a, 0x1ba7: 0x000a, 0x1ba8: 0x000a, 0x1ba9: 0x000a,
+	0x1baa: 0x000a, 0x1bab: 0x000a, 0x1bac: 0x000a, 0x1bad: 0x000a, 0x1bae: 0x000a, 0x1baf: 0x000a,
+	0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a,
+	// Block 0x6f, offset 0x1bc0
+	0x1bc0: 0x000a, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a, 0x1bc5: 0x000a,
+	0x1bc6: 0x000a, 0x1bc7: 0x000a, 0x1bc8: 0x000a, 0x1bc9: 0x000a, 0x1bca: 0x000a, 0x1bcb: 0x000a,
+	0x1bcc: 0x000a, 0x1bcd: 0x000a, 0x1bce: 0x000a, 0x1bcf: 0x000a, 0x1bd0: 0x000a, 0x1bd1: 0x000a,
+	0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x000a, 0x1bd5: 0x000a,
+	0x1bf0: 0x000a, 0x1bf1: 0x000a, 0x1bf2: 0x000a, 0x1bf3: 0x000a, 0x1bf4: 0x000a, 0x1bf5: 0x000a,
+	0x1bf6: 0x000a, 0x1bf7: 0x000a, 0x1bf8: 0x000a, 0x1bf9: 0x000a, 0x1bfa: 0x000a, 0x1bfb: 0x000a,
+	// Block 0x70, offset 0x1c00
+	0x1c00: 0x0009, 0x1c01: 0x000a, 0x1c02: 0x000a, 0x1c03: 0x000a, 0x1c04: 0x000a,
+	0x1c08: 0x003a, 0x1c09: 0x002a, 0x1c0a: 0x003a, 0x1c0b: 0x002a,
+	0x1c0c: 0x003a, 0x1c0d: 0x002a, 0x1c0e: 0x003a, 0x1c0f: 0x002a, 0x1c10: 0x003a, 0x1c11: 0x002a,
+	0x1c12: 0x000a, 0x1c13: 0x000a, 0x1c14: 0x003a, 0x1c15: 0x002a, 0x1c16: 0x003a, 0x1c17: 0x002a,
+	0x1c18: 0x003a, 0x1c19: 0x002a, 0x1c1a: 0x003a, 0x1c1b: 0x002a, 0x1c1c: 0x000a, 0x1c1d: 0x000a,
+	0x1c1e: 0x000a, 0x1c1f: 0x000a, 0x1c20: 0x000a,
+	0x1c2a: 0x000c, 0x1c2b: 0x000c, 0x1c2c: 0x000c, 0x1c2d: 0x000c,
+	0x1c30: 0x000a,
+	0x1c36: 0x000a, 0x1c37: 0x000a,
+	0x1c3d: 0x000a, 0x1c3e: 0x000a, 0x1c3f: 0x000a,
+	// Block 0x71, offset 0x1c40
+	0x1c59: 0x000c, 0x1c5a: 0x000c, 0x1c5b: 0x000a, 0x1c5c: 0x000a,
+	0x1c60: 0x000a,
+	// Block 0x72, offset 0x1c80
+	0x1cbb: 0x000a,
+	// Block 0x73, offset 0x1cc0
+	0x1cc0: 0x000a, 0x1cc1: 0x000a, 0x1cc2: 0x000a, 0x1cc3: 0x000a, 0x1cc4: 0x000a, 0x1cc5: 0x000a,
+	0x1cc6: 0x000a, 0x1cc7: 0x000a, 0x1cc8: 0x000a, 0x1cc9: 0x000a, 0x1cca: 0x000a, 0x1ccb: 0x000a,
+	0x1ccc: 0x000a, 0x1ccd: 0x000a, 0x1cce: 0x000a, 0x1ccf: 0x000a, 0x1cd0: 0x000a, 0x1cd1: 0x000a,
+	0x1cd2: 0x000a, 0x1cd3: 0x000a, 0x1cd4: 0x000a, 0x1cd5: 0x000a, 0x1cd6: 0x000a, 0x1cd7: 0x000a,
+	0x1cd8: 0x000a, 0x1cd9: 0x000a, 0x1cda: 0x000a, 0x1cdb: 0x000a, 0x1cdc: 0x000a, 0x1cdd: 0x000a,
+	0x1cde: 0x000a, 0x1cdf: 0x000a, 0x1ce0: 0x000a, 0x1ce1: 0x000a, 0x1ce2: 0x000a, 0x1ce3: 0x000a,
+	// Block 0x74, offset 0x1d00
+	0x1d1d: 0x000a,
+	0x1d1e: 0x000a,
+	// Block 0x75, offset 0x1d40
+	0x1d50: 0x000a, 0x1d51: 0x000a,
+	0x1d52: 0x000a, 0x1d53: 0x000a, 0x1d54: 0x000a, 0x1d55: 0x000a, 0x1d56: 0x000a, 0x1d57: 0x000a,
+	0x1d58: 0x000a, 0x1d59: 0x000a, 0x1d5a: 0x000a, 0x1d5b: 0x000a, 0x1d5c: 0x000a, 0x1d5d: 0x000a,
+	0x1d5e: 0x000a, 0x1d5f: 0x000a,
+	0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a,
+	// Block 0x76, offset 0x1d80
+	0x1db1: 0x000a, 0x1db2: 0x000a, 0x1db3: 0x000a, 0x1db4: 0x000a, 0x1db5: 0x000a,
+	0x1db6: 0x000a, 0x1db7: 0x000a, 0x1db8: 0x000a, 0x1db9: 0x000a, 0x1dba: 0x000a, 0x1dbb: 0x000a,
+	0x1dbc: 0x000a, 0x1dbd: 0x000a, 0x1dbe: 0x000a, 0x1dbf: 0x000a,
+	// Block 0x77, offset 0x1dc0
+	0x1dcc: 0x000a, 0x1dcd: 0x000a, 0x1dce: 0x000a, 0x1dcf: 0x000a,
+	// Block 0x78, offset 0x1e00
+	0x1e37: 0x000a, 0x1e38: 0x000a, 0x1e39: 0x000a, 0x1e3a: 0x000a,
+	// Block 0x79, offset 0x1e40
+	0x1e5e: 0x000a, 0x1e5f: 0x000a,
+	0x1e7f: 0x000a,
+	// Block 0x7a, offset 0x1e80
+	0x1e90: 0x000a, 0x1e91: 0x000a,
+	0x1e92: 0x000a, 0x1e93: 0x000a, 0x1e94: 0x000a, 0x1e95: 0x000a, 0x1e96: 0x000a, 0x1e97: 0x000a,
+	0x1e98: 0x000a, 0x1e99: 0x000a, 0x1e9a: 0x000a, 0x1e9b: 0x000a, 0x1e9c: 0x000a, 0x1e9d: 0x000a,
+	0x1e9e: 0x000a, 0x1e9f: 0x000a, 0x1ea0: 0x000a, 0x1ea1: 0x000a, 0x1ea2: 0x000a, 0x1ea3: 0x000a,
+	0x1ea4: 0x000a, 0x1ea5: 0x000a, 0x1ea6: 0x000a, 0x1ea7: 0x000a, 0x1ea8: 0x000a, 0x1ea9: 0x000a,
+	0x1eaa: 0x000a, 0x1eab: 0x000a, 0x1eac: 0x000a, 0x1ead: 0x000a, 0x1eae: 0x000a, 0x1eaf: 0x000a,
+	0x1eb0: 0x000a, 0x1eb1: 0x000a, 0x1eb2: 0x000a, 0x1eb3: 0x000a, 0x1eb4: 0x000a, 0x1eb5: 0x000a,
+	0x1eb6: 0x000a, 0x1eb7: 0x000a, 0x1eb8: 0x000a, 0x1eb9: 0x000a, 0x1eba: 0x000a, 0x1ebb: 0x000a,
+	0x1ebc: 0x000a, 0x1ebd: 0x000a, 0x1ebe: 0x000a, 0x1ebf: 0x000a,
+	// Block 0x7b, offset 0x1ec0
+	0x1ec0: 0x000a, 0x1ec1: 0x000a, 0x1ec2: 0x000a, 0x1ec3: 0x000a, 0x1ec4: 0x000a, 0x1ec5: 0x000a,
+	0x1ec6: 0x000a,
+	// Block 0x7c, offset 0x1f00
+	0x1f0d: 0x000a, 0x1f0e: 0x000a, 0x1f0f: 0x000a,
+	// Block 0x7d, offset 0x1f40
+	0x1f6f: 0x000c,
+	0x1f70: 0x000c, 0x1f71: 0x000c, 0x1f72: 0x000c, 0x1f73: 0x000a, 0x1f74: 0x000c, 0x1f75: 0x000c,
+	0x1f76: 0x000c, 0x1f77: 0x000c, 0x1f78: 0x000c, 0x1f79: 0x000c, 0x1f7a: 0x000c, 0x1f7b: 0x000c,
+	0x1f7c: 0x000c, 0x1f7d: 0x000c, 0x1f7e: 0x000a, 0x1f7f: 0x000a,
+	// Block 0x7e, offset 0x1f80
+	0x1f9e: 0x000c, 0x1f9f: 0x000c,
+	// Block 0x7f, offset 0x1fc0
+	0x1ff0: 0x000c, 0x1ff1: 0x000c,
+	// Block 0x80, offset 0x2000
+	0x2000: 0x000a, 0x2001: 0x000a, 0x2002: 0x000a, 0x2003: 0x000a, 0x2004: 0x000a, 0x2005: 0x000a,
+	0x2006: 0x000a, 0x2007: 0x000a, 0x2008: 0x000a, 0x2009: 0x000a, 0x200a: 0x000a, 0x200b: 0x000a,
+	0x200c: 0x000a, 0x200d: 0x000a, 0x200e: 0x000a, 0x200f: 0x000a, 0x2010: 0x000a, 0x2011: 0x000a,
+	0x2012: 0x000a, 0x2013: 0x000a, 0x2014: 0x000a, 0x2015: 0x000a, 0x2016: 0x000a, 0x2017: 0x000a,
+	0x2018: 0x000a, 0x2019: 0x000a, 0x201a: 0x000a, 0x201b: 0x000a, 0x201c: 0x000a, 0x201d: 0x000a,
+	0x201e: 0x000a, 0x201f: 0x000a, 0x2020: 0x000a, 0x2021: 0x000a,
+	// Block 0x81, offset 0x2040
+	0x2048: 0x000a,
+	// Block 0x82, offset 0x2080
+	0x2082: 0x000c,
+	0x2086: 0x000c, 0x208b: 0x000c,
+	0x20a5: 0x000c, 0x20a6: 0x000c, 0x20a8: 0x000a, 0x20a9: 0x000a,
+	0x20aa: 0x000a, 0x20ab: 0x000a,
+	0x20b8: 0x0004, 0x20b9: 0x0004,
+	// Block 0x83, offset 0x20c0
+	0x20f4: 0x000a, 0x20f5: 0x000a,
+	0x20f6: 0x000a, 0x20f7: 0x000a,
+	// Block 0x84, offset 0x2100
+	0x2104: 0x000c, 0x2105: 0x000c,
+	0x2120: 0x000c, 0x2121: 0x000c, 0x2122: 0x000c, 0x2123: 0x000c,
+	0x2124: 0x000c, 0x2125: 0x000c, 0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c,
+	0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c, 0x212e: 0x000c, 0x212f: 0x000c,
+	0x2130: 0x000c, 0x2131: 0x000c,
+	// Block 0x85, offset 0x2140
+	0x2166: 0x000c, 0x2167: 0x000c, 0x2168: 0x000c, 0x2169: 0x000c,
+	0x216a: 0x000c, 0x216b: 0x000c, 0x216c: 0x000c, 0x216d: 0x000c,
+	// Block 0x86, offset 0x2180
+	0x2187: 0x000c, 0x2188: 0x000c, 0x2189: 0x000c, 0x218a: 0x000c, 0x218b: 0x000c,
+	0x218c: 0x000c, 0x218d: 0x000c, 0x218e: 0x000c, 0x218f: 0x000c, 0x2190: 0x000c, 0x2191: 0x000c,
+	// Block 0x87, offset 0x21c0
+	0x21c0: 0x000c, 0x21c1: 0x000c, 0x21c2: 0x000c,
+	0x21f3: 0x000c,
+	0x21f6: 0x000c, 0x21f7: 0x000c, 0x21f8: 0x000c, 0x21f9: 0x000c,
+	0x21fc: 0x000c,
+	// Block 0x88, offset 0x2200
+	0x2225: 0x000c,
+	// Block 0x89, offset 0x2240
+	0x2269: 0x000c,
+	0x226a: 0x000c, 0x226b: 0x000c, 0x226c: 0x000c, 0x226d: 0x000c, 0x226e: 0x000c,
+	0x2271: 0x000c, 0x2272: 0x000c, 0x2275: 0x000c,
+	0x2276: 0x000c,
+	// Block 0x8a, offset 0x2280
+	0x2283: 0x000c,
+	0x228c: 0x000c,
+	0x22bc: 0x000c,
+	// Block 0x8b, offset 0x22c0
+	0x22f0: 0x000c, 0x22f2: 0x000c, 0x22f3: 0x000c, 0x22f4: 0x000c,
+	0x22f7: 0x000c, 0x22f8: 0x000c,
+	0x22fe: 0x000c, 0x22ff: 0x000c,
+	// Block 0x8c, offset 0x2300
+	0x2301: 0x000c,
+	0x232c: 0x000c, 0x232d: 0x000c,
+	0x2336: 0x000c,
+	// Block 0x8d, offset 0x2340
+	0x2365: 0x000c, 0x2368: 0x000c,
+	0x236d: 0x000c,
+	// Block 0x8e, offset 0x2380
+	0x239d: 0x0001,
+	0x239e: 0x000c, 0x239f: 0x0001, 0x23a0: 0x0001, 0x23a1: 0x0001, 0x23a2: 0x0001, 0x23a3: 0x0001,
+	0x23a4: 0x0001, 0x23a5: 0x0001, 0x23a6: 0x0001, 0x23a7: 0x0001, 0x23a8: 0x0001, 0x23a9: 0x0003,
+	0x23aa: 0x0001, 0x23ab: 0x0001, 0x23ac: 0x0001, 0x23ad: 0x0001, 0x23ae: 0x0001, 0x23af: 0x0001,
+	0x23b0: 0x0001, 0x23b1: 0x0001, 0x23b2: 0x0001, 0x23b3: 0x0001, 0x23b4: 0x0001, 0x23b5: 0x0001,
+	0x23b6: 0x0001, 0x23b7: 0x0001, 0x23b8: 0x0001, 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001,
+	0x23bc: 0x0001, 0x23bd: 0x0001, 0x23be: 0x0001, 0x23bf: 0x0001,
+	// Block 0x8f, offset 0x23c0
+	0x23c0: 0x0001, 0x23c1: 0x0001, 0x23c2: 0x0001, 0x23c3: 0x0001, 0x23c4: 0x0001, 0x23c5: 0x0001,
+	0x23c6: 0x0001, 0x23c7: 0x0001, 0x23c8: 0x0001, 0x23c9: 0x0001, 0x23ca: 0x0001, 0x23cb: 0x0001,
+	0x23cc: 0x0001, 0x23cd: 0x0001, 0x23ce: 0x0001, 0x23cf: 0x0001, 0x23d0: 0x000d, 0x23d1: 0x000d,
+	0x23d2: 0x000d, 0x23d3: 0x000d, 0x23d4: 0x000d, 0x23d5: 0x000d, 0x23d6: 0x000d, 0x23d7: 0x000d,
+	0x23d8: 0x000d, 0x23d9: 0x000d, 0x23da: 0x000d, 0x23db: 0x000d, 0x23dc: 0x000d, 0x23dd: 0x000d,
+	0x23de: 0x000d, 0x23df: 0x000d, 0x23e0: 0x000d, 0x23e1: 0x000d, 0x23e2: 0x000d, 0x23e3: 0x000d,
+	0x23e4: 0x000d, 0x23e5: 0x000d, 0x23e6: 0x000d, 0x23e7: 0x000d, 0x23e8: 0x000d, 0x23e9: 0x000d,
+	0x23ea: 0x000d, 0x23eb: 0x000d, 0x23ec: 0x000d, 0x23ed: 0x000d, 0x23ee: 0x000d, 0x23ef: 0x000d,
+	0x23f0: 0x000d, 0x23f1: 0x000d, 0x23f2: 0x000d, 0x23f3: 0x000d, 0x23f4: 0x000d, 0x23f5: 0x000d,
+	0x23f6: 0x000d, 0x23f7: 0x000d, 0x23f8: 0x000d, 0x23f9: 0x000d, 0x23fa: 0x000d, 0x23fb: 0x000d,
+	0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000d, 0x23ff: 0x000d,
+	// Block 0x90, offset 0x2400
+	0x2400: 0x000d, 0x2401: 0x000d, 0x2402: 0x000d, 0x2403: 0x000d, 0x2404: 0x000d, 0x2405: 0x000d,
+	0x2406: 0x000d, 0x2407: 0x000d, 0x2408: 0x000d, 0x2409: 0x000d, 0x240a: 0x000d, 0x240b: 0x000d,
+	0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000d, 0x2411: 0x000d,
+	0x2412: 0x000d, 0x2413: 0x000d, 0x2414: 0x000d, 0x2415: 0x000d, 0x2416: 0x000d, 0x2417: 0x000d,
+	0x2418: 0x000d, 0x2419: 0x000d, 0x241a: 0x000d, 0x241b: 0x000d, 0x241c: 0x000d, 0x241d: 0x000d,
+	0x241e: 0x000d, 0x241f: 0x000d, 0x2420: 0x000d, 0x2421: 0x000d, 0x2422: 0x000d, 0x2423: 0x000d,
+	0x2424: 0x000d, 0x2425: 0x000d, 0x2426: 0x000d, 0x2427: 0x000d, 0x2428: 0x000d, 0x2429: 0x000d,
+	0x242a: 0x000d, 0x242b: 0x000d, 0x242c: 0x000d, 0x242d: 0x000d, 0x242e: 0x000d, 0x242f: 0x000d,
+	0x2430: 0x000d, 0x2431: 0x000d, 0x2432: 0x000d, 0x2433: 0x000d, 0x2434: 0x000d, 0x2435: 0x000d,
+	0x2436: 0x000d, 0x2437: 0x000d, 0x2438: 0x000d, 0x2439: 0x000d, 0x243a: 0x000d, 0x243b: 0x000d,
+	0x243c: 0x000d, 0x243d: 0x000d, 0x243e: 0x000a, 0x243f: 0x000a,
+	// Block 0x91, offset 0x2440
+	0x2440: 0x000d, 0x2441: 0x000d, 0x2442: 0x000d, 0x2443: 0x000d, 0x2444: 0x000d, 0x2445: 0x000d,
+	0x2446: 0x000d, 0x2447: 0x000d, 0x2448: 0x000d, 0x2449: 0x000d, 0x244a: 0x000d, 0x244b: 0x000d,
+	0x244c: 0x000d, 0x244d: 0x000d, 0x244e: 0x000d, 0x244f: 0x000d, 0x2450: 0x000b, 0x2451: 0x000b,
+	0x2452: 0x000b, 0x2453: 0x000b, 0x2454: 0x000b, 0x2455: 0x000b, 0x2456: 0x000b, 0x2457: 0x000b,
+	0x2458: 0x000b, 0x2459: 0x000b, 0x245a: 0x000b, 0x245b: 0x000b, 0x245c: 0x000b, 0x245d: 0x000b,
+	0x245e: 0x000b, 0x245f: 0x000b, 0x2460: 0x000b, 0x2461: 0x000b, 0x2462: 0x000b, 0x2463: 0x000b,
+	0x2464: 0x000b, 0x2465: 0x000b, 0x2466: 0x000b, 0x2467: 0x000b, 0x2468: 0x000b, 0x2469: 0x000b,
+	0x246a: 0x000b, 0x246b: 0x000b, 0x246c: 0x000b, 0x246d: 0x000b, 0x246e: 0x000b, 0x246f: 0x000b,
+	0x2470: 0x000d, 0x2471: 0x000d, 0x2472: 0x000d, 0x2473: 0x000d, 0x2474: 0x000d, 0x2475: 0x000d,
+	0x2476: 0x000d, 0x2477: 0x000d, 0x2478: 0x000d, 0x2479: 0x000d, 0x247a: 0x000d, 0x247b: 0x000d,
+	0x247c: 0x000d, 0x247d: 0x000a, 0x247e: 0x000d, 0x247f: 0x000d,
+	// Block 0x92, offset 0x2480
+	0x2480: 0x000c, 0x2481: 0x000c, 0x2482: 0x000c, 0x2483: 0x000c, 0x2484: 0x000c, 0x2485: 0x000c,
+	0x2486: 0x000c, 0x2487: 0x000c, 0x2488: 0x000c, 0x2489: 0x000c, 0x248a: 0x000c, 0x248b: 0x000c,
+	0x248c: 0x000c, 0x248d: 0x000c, 0x248e: 0x000c, 0x248f: 0x000c, 0x2490: 0x000a, 0x2491: 0x000a,
+	0x2492: 0x000a, 0x2493: 0x000a, 0x2494: 0x000a, 0x2495: 0x000a, 0x2496: 0x000a, 0x2497: 0x000a,
+	0x2498: 0x000a, 0x2499: 0x000a,
+	0x24a0: 0x000c, 0x24a1: 0x000c, 0x24a2: 0x000c, 0x24a3: 0x000c,
+	0x24a4: 0x000c, 0x24a5: 0x000c, 0x24a6: 0x000c, 0x24a7: 0x000c, 0x24a8: 0x000c, 0x24a9: 0x000c,
+	0x24aa: 0x000c, 0x24ab: 0x000c, 0x24ac: 0x000c, 0x24ad: 0x000c, 0x24ae: 0x000c, 0x24af: 0x000c,
+	0x24b0: 0x000a, 0x24b1: 0x000a, 0x24b2: 0x000a, 0x24b3: 0x000a, 0x24b4: 0x000a, 0x24b5: 0x000a,
+	0x24b6: 0x000a, 0x24b7: 0x000a, 0x24b8: 0x000a, 0x24b9: 0x000a, 0x24ba: 0x000a, 0x24bb: 0x000a,
+	0x24bc: 0x000a, 0x24bd: 0x000a, 0x24be: 0x000a, 0x24bf: 0x000a,
+	// Block 0x93, offset 0x24c0
+	0x24c0: 0x000a, 0x24c1: 0x000a, 0x24c2: 0x000a, 0x24c3: 0x000a, 0x24c4: 0x000a, 0x24c5: 0x000a,
+	0x24c6: 0x000a, 0x24c7: 0x000a, 0x24c8: 0x000a, 0x24c9: 0x000a, 0x24ca: 0x000a, 0x24cb: 0x000a,
+	0x24cc: 0x000a, 0x24cd: 0x000a, 0x24ce: 0x000a, 0x24cf: 0x000a, 0x24d0: 0x0006, 0x24d1: 0x000a,
+	0x24d2: 0x0006, 0x24d4: 0x000a, 0x24d5: 0x0006, 0x24d6: 0x000a, 0x24d7: 0x000a,
+	0x24d8: 0x000a, 0x24d9: 0x009a, 0x24da: 0x008a, 0x24db: 0x007a, 0x24dc: 0x006a, 0x24dd: 0x009a,
+	0x24de: 0x008a, 0x24df: 0x0004, 0x24e0: 0x000a, 0x24e1: 0x000a, 0x24e2: 0x0003, 0x24e3: 0x0003,
+	0x24e4: 0x000a, 0x24e5: 0x000a, 0x24e6: 0x000a, 0x24e8: 0x000a, 0x24e9: 0x0004,
+	0x24ea: 0x0004, 0x24eb: 0x000a,
+	0x24f0: 0x000d, 0x24f1: 0x000d, 0x24f2: 0x000d, 0x24f3: 0x000d, 0x24f4: 0x000d, 0x24f5: 0x000d,
+	0x24f6: 0x000d, 0x24f7: 0x000d, 0x24f8: 0x000d, 0x24f9: 0x000d, 0x24fa: 0x000d, 0x24fb: 0x000d,
+	0x24fc: 0x000d, 0x24fd: 0x000d, 0x24fe: 0x000d, 0x24ff: 0x000d,
+	// Block 0x94, offset 0x2500
+	0x2500: 0x000d, 0x2501: 0x000d, 0x2502: 0x000d, 0x2503: 0x000d, 0x2504: 0x000d, 0x2505: 0x000d,
+	0x2506: 0x000d, 0x2507: 0x000d, 0x2508: 0x000d, 0x2509: 0x000d, 0x250a: 0x000d, 0x250b: 0x000d,
+	0x250c: 0x000d, 0x250d: 0x000d, 0x250e: 0x000d, 0x250f: 0x000d, 0x2510: 0x000d, 0x2511: 0x000d,
+	0x2512: 0x000d, 0x2513: 0x000d, 0x2514: 0x000d, 0x2515: 0x000d, 0x2516: 0x000d, 0x2517: 0x000d,
+	0x2518: 0x000d, 0x2519: 0x000d, 0x251a: 0x000d, 0x251b: 0x000d, 0x251c: 0x000d, 0x251d: 0x000d,
+	0x251e: 0x000d, 0x251f: 0x000d, 0x2520: 0x000d, 0x2521: 0x000d, 0x2522: 0x000d, 0x2523: 0x000d,
+	0x2524: 0x000d, 0x2525: 0x000d, 0x2526: 0x000d, 0x2527: 0x000d, 0x2528: 0x000d, 0x2529: 0x000d,
+	0x252a: 0x000d, 0x252b: 0x000d, 0x252c: 0x000d, 0x252d: 0x000d, 0x252e: 0x000d, 0x252f: 0x000d,
+	0x2530: 0x000d, 0x2531: 0x000d, 0x2532: 0x000d, 0x2533: 0x000d, 0x2534: 0x000d, 0x2535: 0x000d,
+	0x2536: 0x000d, 0x2537: 0x000d, 0x2538: 0x000d, 0x2539: 0x000d, 0x253a: 0x000d, 0x253b: 0x000d,
+	0x253c: 0x000d, 0x253d: 0x000d, 0x253e: 0x000d, 0x253f: 0x000b,
+	// Block 0x95, offset 0x2540
+	0x2541: 0x000a, 0x2542: 0x000a, 0x2543: 0x0004, 0x2544: 0x0004, 0x2545: 0x0004,
+	0x2546: 0x000a, 0x2547: 0x000a, 0x2548: 0x003a, 0x2549: 0x002a, 0x254a: 0x000a, 0x254b: 0x0003,
+	0x254c: 0x0006, 0x254d: 0x0003, 0x254e: 0x0006, 0x254f: 0x0006, 0x2550: 0x0002, 0x2551: 0x0002,
+	0x2552: 0x0002, 0x2553: 0x0002, 0x2554: 0x0002, 0x2555: 0x0002, 0x2556: 0x0002, 0x2557: 0x0002,
+	0x2558: 0x0002, 0x2559: 0x0002, 0x255a: 0x0006, 0x255b: 0x000a, 0x255c: 0x000a, 0x255d: 0x000a,
+	0x255e: 0x000a, 0x255f: 0x000a, 0x2560: 0x000a,
+	0x257b: 0x005a,
+	0x257c: 0x000a, 0x257d: 0x004a, 0x257e: 0x000a, 0x257f: 0x000a,
+	// Block 0x96, offset 0x2580
+	0x2580: 0x000a,
+	0x259b: 0x005a, 0x259c: 0x000a, 0x259d: 0x004a,
+	0x259e: 0x000a, 0x259f: 0x00fa, 0x25a0: 0x00ea, 0x25a1: 0x000a, 0x25a2: 0x003a, 0x25a3: 0x002a,
+	0x25a4: 0x000a, 0x25a5: 0x000a,
+	// Block 0x97, offset 0x25c0
+	0x25e0: 0x0004, 0x25e1: 0x0004, 0x25e2: 0x000a, 0x25e3: 0x000a,
+	0x25e4: 0x000a, 0x25e5: 0x0004, 0x25e6: 0x0004, 0x25e8: 0x000a, 0x25e9: 0x000a,
+	0x25ea: 0x000a, 0x25eb: 0x000a, 0x25ec: 0x000a, 0x25ed: 0x000a, 0x25ee: 0x000a,
+	0x25f0: 0x000b, 0x25f1: 0x000b, 0x25f2: 0x000b, 0x25f3: 0x000b, 0x25f4: 0x000b, 0x25f5: 0x000b,
+	0x25f6: 0x000b, 0x25f7: 0x000b, 0x25f8: 0x000b, 0x25f9: 0x000a, 0x25fa: 0x000a, 0x25fb: 0x000a,
+	0x25fc: 0x000a, 0x25fd: 0x000a, 0x25fe: 0x000b, 0x25ff: 0x000b,
+	// Block 0x98, offset 0x2600
+	0x2601: 0x000a,
+	// Block 0x99, offset 0x2640
+	0x2640: 0x000a, 0x2641: 0x000a, 0x2642: 0x000a, 0x2643: 0x000a, 0x2644: 0x000a, 0x2645: 0x000a,
+	0x2646: 0x000a, 0x2647: 0x000a, 0x2648: 0x000a, 0x2649: 0x000a, 0x264a: 0x000a, 0x264b: 0x000a,
+	0x264c: 0x000a, 0x2650: 0x000a, 0x2651: 0x000a,
+	0x2652: 0x000a, 0x2653: 0x000a, 0x2654: 0x000a, 0x2655: 0x000a, 0x2656: 0x000a, 0x2657: 0x000a,
+	0x2658: 0x000a, 0x2659: 0x000a, 0x265a: 0x000a, 0x265b: 0x000a,
+	0x2660: 0x000a,
+	// Block 0x9a, offset 0x2680
+	0x26bd: 0x000c,
+	// Block 0x9b, offset 0x26c0
+	0x26e0: 0x000c, 0x26e1: 0x0002, 0x26e2: 0x0002, 0x26e3: 0x0002,
+	0x26e4: 0x0002, 0x26e5: 0x0002, 0x26e6: 0x0002, 0x26e7: 0x0002, 0x26e8: 0x0002, 0x26e9: 0x0002,
+	0x26ea: 0x0002, 0x26eb: 0x0002, 0x26ec: 0x0002, 0x26ed: 0x0002, 0x26ee: 0x0002, 0x26ef: 0x0002,
+	0x26f0: 0x0002, 0x26f1: 0x0002, 0x26f2: 0x0002, 0x26f3: 0x0002, 0x26f4: 0x0002, 0x26f5: 0x0002,
+	0x26f6: 0x0002, 0x26f7: 0x0002, 0x26f8: 0x0002, 0x26f9: 0x0002, 0x26fa: 0x0002, 0x26fb: 0x0002,
+	// Block 0x9c, offset 0x2700
+	0x2736: 0x000c, 0x2737: 0x000c, 0x2738: 0x000c, 0x2739: 0x000c, 0x273a: 0x000c,
+	// Block 0x9d, offset 0x2740
+	0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, 0x2743: 0x0001, 0x2744: 0x0001, 0x2745: 0x0001,
+	0x2746: 0x0001, 0x2747: 0x0001, 0x2748: 0x0001, 0x2749: 0x0001, 0x274a: 0x0001, 0x274b: 0x0001,
+	0x274c: 0x0001, 0x274d: 0x0001, 0x274e: 0x0001, 0x274f: 0x0001, 0x2750: 0x0001, 0x2751: 0x0001,
+	0x2752: 0x0001, 0x2753: 0x0001, 0x2754: 0x0001, 0x2755: 0x0001, 0x2756: 0x0001, 0x2757: 0x0001,
+	0x2758: 0x0001, 0x2759: 0x0001, 0x275a: 0x0001, 0x275b: 0x0001, 0x275c: 0x0001, 0x275d: 0x0001,
+	0x275e: 0x0001, 0x275f: 0x0001, 0x2760: 0x0001, 0x2761: 0x0001, 0x2762: 0x0001, 0x2763: 0x0001,
+	0x2764: 0x0001, 0x2765: 0x0001, 0x2766: 0x0001, 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001,
+	0x276a: 0x0001, 0x276b: 0x0001, 0x276c: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001,
+	0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, 0x2775: 0x0001,
+	0x2776: 0x0001, 0x2777: 0x0001, 0x2778: 0x0001, 0x2779: 0x0001, 0x277a: 0x0001, 0x277b: 0x0001,
+	0x277c: 0x0001, 0x277d: 0x0001, 0x277e: 0x0001, 0x277f: 0x0001,
+	// Block 0x9e, offset 0x2780
+	0x2780: 0x0001, 0x2781: 0x0001, 0x2782: 0x0001, 0x2783: 0x0001, 0x2784: 0x0001, 0x2785: 0x0001,
+	0x2786: 0x0001, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001,
+	0x278c: 0x0001, 0x278d: 0x0001, 0x278e: 0x0001, 0x278f: 0x0001, 0x2790: 0x0001, 0x2791: 0x0001,
+	0x2792: 0x0001, 0x2793: 0x0001, 0x2794: 0x0001, 0x2795: 0x0001, 0x2796: 0x0001, 0x2797: 0x0001,
+	0x2798: 0x0001, 0x2799: 0x0001, 0x279a: 0x0001, 0x279b: 0x0001, 0x279c: 0x0001, 0x279d: 0x0001,
+	0x279e: 0x0001, 0x279f: 0x000a, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001,
+	0x27a4: 0x0001, 0x27a5: 0x0001, 0x27a6: 0x0001, 0x27a7: 0x0001, 0x27a8: 0x0001, 0x27a9: 0x0001,
+	0x27aa: 0x0001, 0x27ab: 0x0001, 0x27ac: 0x0001, 0x27ad: 0x0001, 0x27ae: 0x0001, 0x27af: 0x0001,
+	0x27b0: 0x0001, 0x27b1: 0x0001, 0x27b2: 0x0001, 0x27b3: 0x0001, 0x27b4: 0x0001, 0x27b5: 0x0001,
+	0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x0001, 0x27b9: 0x0001, 0x27ba: 0x0001, 0x27bb: 0x0001,
+	0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x0001,
+	// Block 0x9f, offset 0x27c0
+	0x27c0: 0x0001, 0x27c1: 0x000c, 0x27c2: 0x000c, 0x27c3: 0x000c, 0x27c4: 0x0001, 0x27c5: 0x000c,
+	0x27c6: 0x000c, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001,
+	0x27cc: 0x000c, 0x27cd: 0x000c, 0x27ce: 0x000c, 0x27cf: 0x000c, 0x27d0: 0x0001, 0x27d1: 0x0001,
+	0x27d2: 0x0001, 0x27d3: 0x0001, 0x27d4: 0x0001, 0x27d5: 0x0001, 0x27d6: 0x0001, 0x27d7: 0x0001,
+	0x27d8: 0x0001, 0x27d9: 0x0001, 0x27da: 0x0001, 0x27db: 0x0001, 0x27dc: 0x0001, 0x27dd: 0x0001,
+	0x27de: 0x0001, 0x27df: 0x0001, 0x27e0: 0x0001, 0x27e1: 0x0001, 0x27e2: 0x0001, 0x27e3: 0x0001,
+	0x27e4: 0x0001, 0x27e5: 0x0001, 0x27e6: 0x0001, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001,
+	0x27ea: 0x0001, 0x27eb: 0x0001, 0x27ec: 0x0001, 0x27ed: 0x0001, 0x27ee: 0x0001, 0x27ef: 0x0001,
+	0x27f0: 0x0001, 0x27f1: 0x0001, 0x27f2: 0x0001, 0x27f3: 0x0001, 0x27f4: 0x0001, 0x27f5: 0x0001,
+	0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x000c, 0x27f9: 0x000c, 0x27fa: 0x000c, 0x27fb: 0x0001,
+	0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x000c,
+	// Block 0xa0, offset 0x2800
+	0x2800: 0x0001, 0x2801: 0x0001, 0x2802: 0x0001, 0x2803: 0x0001, 0x2804: 0x0001, 0x2805: 0x0001,
+	0x2806: 0x0001, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001,
+	0x280c: 0x0001, 0x280d: 0x0001, 0x280e: 0x0001, 0x280f: 0x0001, 0x2810: 0x0001, 0x2811: 0x0001,
+	0x2812: 0x0001, 0x2813: 0x0001, 0x2814: 0x0001, 0x2815: 0x0001, 0x2816: 0x0001, 0x2817: 0x0001,
+	0x2818: 0x0001, 0x2819: 0x0001, 0x281a: 0x0001, 0x281b: 0x0001, 0x281c: 0x0001, 0x281d: 0x0001,
+	0x281e: 0x0001, 0x281f: 0x0001, 0x2820: 0x0001, 0x2821: 0x0001, 0x2822: 0x0001, 0x2823: 0x0001,
+	0x2824: 0x0001, 0x2825: 0x000c, 0x2826: 0x000c, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001,
+	0x282a: 0x0001, 0x282b: 0x0001, 0x282c: 0x0001, 0x282d: 0x0001, 0x282e: 0x0001, 0x282f: 0x0001,
+	0x2830: 0x0001, 0x2831: 0x0001, 0x2832: 0x0001, 0x2833: 0x0001, 0x2834: 0x0001, 0x2835: 0x0001,
+	0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x0001, 0x2839: 0x0001, 0x283a: 0x0001, 0x283b: 0x0001,
+	0x283c: 0x0001, 0x283d: 0x0001, 0x283e: 0x0001, 0x283f: 0x0001,
+	// Block 0xa1, offset 0x2840
+	0x2840: 0x0001, 0x2841: 0x0001, 0x2842: 0x0001, 0x2843: 0x0001, 0x2844: 0x0001, 0x2845: 0x0001,
+	0x2846: 0x0001, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001,
+	0x284c: 0x0001, 0x284d: 0x0001, 0x284e: 0x0001, 0x284f: 0x0001, 0x2850: 0x0001, 0x2851: 0x0001,
+	0x2852: 0x0001, 0x2853: 0x0001, 0x2854: 0x0001, 0x2855: 0x0001, 0x2856: 0x0001, 0x2857: 0x0001,
+	0x2858: 0x0001, 0x2859: 0x0001, 0x285a: 0x0001, 0x285b: 0x0001, 0x285c: 0x0001, 0x285d: 0x0001,
+	0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0001, 0x2861: 0x0001, 0x2862: 0x0001, 0x2863: 0x0001,
+	0x2864: 0x0001, 0x2865: 0x0001, 0x2866: 0x0001, 0x2867: 0x0001, 0x2868: 0x0001, 0x2869: 0x0001,
+	0x286a: 0x0001, 0x286b: 0x0001, 0x286c: 0x0001, 0x286d: 0x0001, 0x286e: 0x0001, 0x286f: 0x0001,
+	0x2870: 0x0001, 0x2871: 0x0001, 0x2872: 0x0001, 0x2873: 0x0001, 0x2874: 0x0001, 0x2875: 0x0001,
+	0x2876: 0x0001, 0x2877: 0x0001, 0x2878: 0x0001, 0x2879: 0x000a, 0x287a: 0x000a, 0x287b: 0x000a,
+	0x287c: 0x000a, 0x287d: 0x000a, 0x287e: 0x000a, 0x287f: 0x000a,
+	// Block 0xa2, offset 0x2880
+	0x2880: 0x0001, 0x2881: 0x0001, 0x2882: 0x0001, 0x2883: 0x0001, 0x2884: 0x0001, 0x2885: 0x0001,
+	0x2886: 0x0001, 0x2887: 0x0001, 0x2888: 0x0001, 0x2889: 0x0001, 0x288a: 0x0001, 0x288b: 0x0001,
+	0x288c: 0x0001, 0x288d: 0x0001, 0x288e: 0x0001, 0x288f: 0x0001, 0x2890: 0x0001, 0x2891: 0x0001,
+	0x2892: 0x0001, 0x2893: 0x0001, 0x2894: 0x0001, 0x2895: 0x0001, 0x2896: 0x0001, 0x2897: 0x0001,
+	0x2898: 0x0001, 0x2899: 0x0001, 0x289a: 0x0001, 0x289b: 0x0001, 0x289c: 0x0001, 0x289d: 0x0001,
+	0x289e: 0x0001, 0x289f: 0x0001, 0x28a0: 0x0005, 0x28a1: 0x0005, 0x28a2: 0x0005, 0x28a3: 0x0005,
+	0x28a4: 0x0005, 0x28a5: 0x0005, 0x28a6: 0x0005, 0x28a7: 0x0005, 0x28a8: 0x0005, 0x28a9: 0x0005,
+	0x28aa: 0x0005, 0x28ab: 0x0005, 0x28ac: 0x0005, 0x28ad: 0x0005, 0x28ae: 0x0005, 0x28af: 0x0005,
+	0x28b0: 0x0005, 0x28b1: 0x0005, 0x28b2: 0x0005, 0x28b3: 0x0005, 0x28b4: 0x0005, 0x28b5: 0x0005,
+	0x28b6: 0x0005, 0x28b7: 0x0005, 0x28b8: 0x0005, 0x28b9: 0x0005, 0x28ba: 0x0005, 0x28bb: 0x0005,
+	0x28bc: 0x0005, 0x28bd: 0x0005, 0x28be: 0x0005, 0x28bf: 0x0001,
+	// Block 0xa3, offset 0x28c0
+	0x28c1: 0x000c,
+	0x28f8: 0x000c, 0x28f9: 0x000c, 0x28fa: 0x000c, 0x28fb: 0x000c,
+	0x28fc: 0x000c, 0x28fd: 0x000c, 0x28fe: 0x000c, 0x28ff: 0x000c,
+	// Block 0xa4, offset 0x2900
+	0x2900: 0x000c, 0x2901: 0x000c, 0x2902: 0x000c, 0x2903: 0x000c, 0x2904: 0x000c, 0x2905: 0x000c,
+	0x2906: 0x000c,
+	0x2912: 0x000a, 0x2913: 0x000a, 0x2914: 0x000a, 0x2915: 0x000a, 0x2916: 0x000a, 0x2917: 0x000a,
+	0x2918: 0x000a, 0x2919: 0x000a, 0x291a: 0x000a, 0x291b: 0x000a, 0x291c: 0x000a, 0x291d: 0x000a,
+	0x291e: 0x000a, 0x291f: 0x000a, 0x2920: 0x000a, 0x2921: 0x000a, 0x2922: 0x000a, 0x2923: 0x000a,
+	0x2924: 0x000a, 0x2925: 0x000a,
+	0x293f: 0x000c,
+	// Block 0xa5, offset 0x2940
+	0x2940: 0x000c, 0x2941: 0x000c,
+	0x2973: 0x000c, 0x2974: 0x000c, 0x2975: 0x000c,
+	0x2976: 0x000c, 0x2979: 0x000c, 0x297a: 0x000c,
+	// Block 0xa6, offset 0x2980
+	0x2980: 0x000c, 0x2981: 0x000c, 0x2982: 0x000c,
+	0x29a7: 0x000c, 0x29a8: 0x000c, 0x29a9: 0x000c,
+	0x29aa: 0x000c, 0x29ab: 0x000c, 0x29ad: 0x000c, 0x29ae: 0x000c, 0x29af: 0x000c,
+	0x29b0: 0x000c, 0x29b1: 0x000c, 0x29b2: 0x000c, 0x29b3: 0x000c, 0x29b4: 0x000c,
+	// Block 0xa7, offset 0x29c0
+	0x29f3: 0x000c,
+	// Block 0xa8, offset 0x2a00
+	0x2a00: 0x000c, 0x2a01: 0x000c,
+	0x2a36: 0x000c, 0x2a37: 0x000c, 0x2a38: 0x000c, 0x2a39: 0x000c, 0x2a3a: 0x000c, 0x2a3b: 0x000c,
+	0x2a3c: 0x000c, 0x2a3d: 0x000c, 0x2a3e: 0x000c,
+	// Block 0xa9, offset 0x2a40
+	0x2a4a: 0x000c, 0x2a4b: 0x000c,
+	0x2a4c: 0x000c,
+	// Block 0xaa, offset 0x2a80
+	0x2aaf: 0x000c,
+	0x2ab0: 0x000c, 0x2ab1: 0x000c, 0x2ab4: 0x000c,
+	0x2ab6: 0x000c, 0x2ab7: 0x000c,
+	0x2abe: 0x000c,
+	// Block 0xab, offset 0x2ac0
+	0x2adf: 0x000c, 0x2ae3: 0x000c,
+	0x2ae4: 0x000c, 0x2ae5: 0x000c, 0x2ae6: 0x000c, 0x2ae7: 0x000c, 0x2ae8: 0x000c, 0x2ae9: 0x000c,
+	0x2aea: 0x000c,
+	// Block 0xac, offset 0x2b00
+	0x2b00: 0x000c, 0x2b01: 0x000c,
+	0x2b3c: 0x000c,
+	// Block 0xad, offset 0x2b40
+	0x2b40: 0x000c,
+	0x2b66: 0x000c, 0x2b67: 0x000c, 0x2b68: 0x000c, 0x2b69: 0x000c,
+	0x2b6a: 0x000c, 0x2b6b: 0x000c, 0x2b6c: 0x000c,
+	0x2b70: 0x000c, 0x2b71: 0x000c, 0x2b72: 0x000c, 0x2b73: 0x000c, 0x2b74: 0x000c,
+	// Block 0xae, offset 0x2b80
+	0x2bb8: 0x000c, 0x2bb9: 0x000c, 0x2bba: 0x000c, 0x2bbb: 0x000c,
+	0x2bbc: 0x000c, 0x2bbd: 0x000c, 0x2bbe: 0x000c, 0x2bbf: 0x000c,
+	// Block 0xaf, offset 0x2bc0
+	0x2bc2: 0x000c, 0x2bc3: 0x000c, 0x2bc4: 0x000c,
+	0x2bc6: 0x000c,
+	// Block 0xb0, offset 0x2c00
+	0x2c33: 0x000c, 0x2c34: 0x000c, 0x2c35: 0x000c,
+	0x2c36: 0x000c, 0x2c37: 0x000c, 0x2c38: 0x000c, 0x2c3a: 0x000c,
+	0x2c3f: 0x000c,
+	// Block 0xb1, offset 0x2c40
+	0x2c40: 0x000c, 0x2c42: 0x000c, 0x2c43: 0x000c,
+	// Block 0xb2, offset 0x2c80
+	0x2cb2: 0x000c, 0x2cb3: 0x000c, 0x2cb4: 0x000c, 0x2cb5: 0x000c,
+	0x2cbc: 0x000c, 0x2cbd: 0x000c, 0x2cbf: 0x000c,
+	// Block 0xb3, offset 0x2cc0
+	0x2cc0: 0x000c,
+	0x2cdc: 0x000c, 0x2cdd: 0x000c,
+	// Block 0xb4, offset 0x2d00
+	0x2d33: 0x000c, 0x2d34: 0x000c, 0x2d35: 0x000c,
+	0x2d36: 0x000c, 0x2d37: 0x000c, 0x2d38: 0x000c, 0x2d39: 0x000c, 0x2d3a: 0x000c,
+	0x2d3d: 0x000c, 0x2d3f: 0x000c,
+	// Block 0xb5, offset 0x2d40
+	0x2d40: 0x000c,
+	0x2d60: 0x000a, 0x2d61: 0x000a, 0x2d62: 0x000a, 0x2d63: 0x000a,
+	0x2d64: 0x000a, 0x2d65: 0x000a, 0x2d66: 0x000a, 0x2d67: 0x000a, 0x2d68: 0x000a, 0x2d69: 0x000a,
+	0x2d6a: 0x000a, 0x2d6b: 0x000a, 0x2d6c: 0x000a,
+	// Block 0xb6, offset 0x2d80
+	0x2dab: 0x000c, 0x2dad: 0x000c,
+	0x2db0: 0x000c, 0x2db1: 0x000c, 0x2db2: 0x000c, 0x2db3: 0x000c, 0x2db4: 0x000c, 0x2db5: 0x000c,
+	0x2db7: 0x000c,
+	// Block 0xb7, offset 0x2dc0
+	0x2ddd: 0x000c,
+	0x2dde: 0x000c, 0x2ddf: 0x000c, 0x2de2: 0x000c, 0x2de3: 0x000c,
+	0x2de4: 0x000c, 0x2de5: 0x000c, 0x2de7: 0x000c, 0x2de8: 0x000c, 0x2de9: 0x000c,
+	0x2dea: 0x000c, 0x2deb: 0x000c,
+	// Block 0xb8, offset 0x2e00
+	0x2e30: 0x000c, 0x2e31: 0x000c, 0x2e32: 0x000c, 0x2e33: 0x000c, 0x2e34: 0x000c, 0x2e35: 0x000c,
+	0x2e36: 0x000c, 0x2e38: 0x000c, 0x2e39: 0x000c, 0x2e3a: 0x000c, 0x2e3b: 0x000c,
+	0x2e3c: 0x000c, 0x2e3d: 0x000c,
+	// Block 0xb9, offset 0x2e40
+	0x2e52: 0x000c, 0x2e53: 0x000c, 0x2e54: 0x000c, 0x2e55: 0x000c, 0x2e56: 0x000c, 0x2e57: 0x000c,
+	0x2e58: 0x000c, 0x2e59: 0x000c, 0x2e5a: 0x000c, 0x2e5b: 0x000c, 0x2e5c: 0x000c, 0x2e5d: 0x000c,
+	0x2e5e: 0x000c, 0x2e5f: 0x000c, 0x2e60: 0x000c, 0x2e61: 0x000c, 0x2e62: 0x000c, 0x2e63: 0x000c,
+	0x2e64: 0x000c, 0x2e65: 0x000c, 0x2e66: 0x000c, 0x2e67: 0x000c,
+	0x2e6a: 0x000c, 0x2e6b: 0x000c, 0x2e6c: 0x000c, 0x2e6d: 0x000c, 0x2e6e: 0x000c, 0x2e6f: 0x000c,
+	0x2e70: 0x000c, 0x2e72: 0x000c, 0x2e73: 0x000c, 0x2e75: 0x000c,
+	0x2e76: 0x000c,
+	// Block 0xba, offset 0x2e80
+	0x2eb0: 0x000c, 0x2eb1: 0x000c, 0x2eb2: 0x000c, 0x2eb3: 0x000c, 0x2eb4: 0x000c,
+	// Block 0xbb, offset 0x2ec0
+	0x2ef0: 0x000c, 0x2ef1: 0x000c, 0x2ef2: 0x000c, 0x2ef3: 0x000c, 0x2ef4: 0x000c, 0x2ef5: 0x000c,
+	0x2ef6: 0x000c,
+	// Block 0xbc, offset 0x2f00
+	0x2f0f: 0x000c, 0x2f10: 0x000c, 0x2f11: 0x000c,
+	0x2f12: 0x000c,
+	// Block 0xbd, offset 0x2f40
+	0x2f5d: 0x000c,
+	0x2f5e: 0x000c, 0x2f60: 0x000b, 0x2f61: 0x000b, 0x2f62: 0x000b, 0x2f63: 0x000b,
+	// Block 0xbe, offset 0x2f80
+	0x2fa7: 0x000c, 0x2fa8: 0x000c, 0x2fa9: 0x000c,
+	0x2fb3: 0x000b, 0x2fb4: 0x000b, 0x2fb5: 0x000b,
+	0x2fb6: 0x000b, 0x2fb7: 0x000b, 0x2fb8: 0x000b, 0x2fb9: 0x000b, 0x2fba: 0x000b, 0x2fbb: 0x000c,
+	0x2fbc: 0x000c, 0x2fbd: 0x000c, 0x2fbe: 0x000c, 0x2fbf: 0x000c,
+	// Block 0xbf, offset 0x2fc0
+	0x2fc0: 0x000c, 0x2fc1: 0x000c, 0x2fc2: 0x000c, 0x2fc5: 0x000c,
+	0x2fc6: 0x000c, 0x2fc7: 0x000c, 0x2fc8: 0x000c, 0x2fc9: 0x000c, 0x2fca: 0x000c, 0x2fcb: 0x000c,
+	0x2fea: 0x000c, 0x2feb: 0x000c, 0x2fec: 0x000c, 0x2fed: 0x000c,
+	// Block 0xc0, offset 0x3000
+	0x3000: 0x000a, 0x3001: 0x000a, 0x3002: 0x000c, 0x3003: 0x000c, 0x3004: 0x000c, 0x3005: 0x000a,
+	// Block 0xc1, offset 0x3040
+	0x3040: 0x000a, 0x3041: 0x000a, 0x3042: 0x000a, 0x3043: 0x000a, 0x3044: 0x000a, 0x3045: 0x000a,
+	0x3046: 0x000a, 0x3047: 0x000a, 0x3048: 0x000a, 0x3049: 0x000a, 0x304a: 0x000a, 0x304b: 0x000a,
+	0x304c: 0x000a, 0x304d: 0x000a, 0x304e: 0x000a, 0x304f: 0x000a, 0x3050: 0x000a, 0x3051: 0x000a,
+	0x3052: 0x000a, 0x3053: 0x000a, 0x3054: 0x000a, 0x3055: 0x000a, 0x3056: 0x000a,
+	// Block 0xc2, offset 0x3080
+	0x309b: 0x000a,
+	// Block 0xc3, offset 0x30c0
+	0x30d5: 0x000a,
+	// Block 0xc4, offset 0x3100
+	0x310f: 0x000a,
+	// Block 0xc5, offset 0x3140
+	0x3149: 0x000a,
+	// Block 0xc6, offset 0x3180
+	0x3183: 0x000a,
+	0x318e: 0x0002, 0x318f: 0x0002, 0x3190: 0x0002, 0x3191: 0x0002,
+	0x3192: 0x0002, 0x3193: 0x0002, 0x3194: 0x0002, 0x3195: 0x0002, 0x3196: 0x0002, 0x3197: 0x0002,
+	0x3198: 0x0002, 0x3199: 0x0002, 0x319a: 0x0002, 0x319b: 0x0002, 0x319c: 0x0002, 0x319d: 0x0002,
+	0x319e: 0x0002, 0x319f: 0x0002, 0x31a0: 0x0002, 0x31a1: 0x0002, 0x31a2: 0x0002, 0x31a3: 0x0002,
+	0x31a4: 0x0002, 0x31a5: 0x0002, 0x31a6: 0x0002, 0x31a7: 0x0002, 0x31a8: 0x0002, 0x31a9: 0x0002,
+	0x31aa: 0x0002, 0x31ab: 0x0002, 0x31ac: 0x0002, 0x31ad: 0x0002, 0x31ae: 0x0002, 0x31af: 0x0002,
+	0x31b0: 0x0002, 0x31b1: 0x0002, 0x31b2: 0x0002, 0x31b3: 0x0002, 0x31b4: 0x0002, 0x31b5: 0x0002,
+	0x31b6: 0x0002, 0x31b7: 0x0002, 0x31b8: 0x0002, 0x31b9: 0x0002, 0x31ba: 0x0002, 0x31bb: 0x0002,
+	0x31bc: 0x0002, 0x31bd: 0x0002, 0x31be: 0x0002, 0x31bf: 0x0002,
+	// Block 0xc7, offset 0x31c0
+	0x31c0: 0x000c, 0x31c1: 0x000c, 0x31c2: 0x000c, 0x31c3: 0x000c, 0x31c4: 0x000c, 0x31c5: 0x000c,
+	0x31c6: 0x000c, 0x31c7: 0x000c, 0x31c8: 0x000c, 0x31c9: 0x000c, 0x31ca: 0x000c, 0x31cb: 0x000c,
+	0x31cc: 0x000c, 0x31cd: 0x000c, 0x31ce: 0x000c, 0x31cf: 0x000c, 0x31d0: 0x000c, 0x31d1: 0x000c,
+	0x31d2: 0x000c, 0x31d3: 0x000c, 0x31d4: 0x000c, 0x31d5: 0x000c, 0x31d6: 0x000c, 0x31d7: 0x000c,
+	0x31d8: 0x000c, 0x31d9: 0x000c, 0x31da: 0x000c, 0x31db: 0x000c, 0x31dc: 0x000c, 0x31dd: 0x000c,
+	0x31de: 0x000c, 0x31df: 0x000c, 0x31e0: 0x000c, 0x31e1: 0x000c, 0x31e2: 0x000c, 0x31e3: 0x000c,
+	0x31e4: 0x000c, 0x31e5: 0x000c, 0x31e6: 0x000c, 0x31e7: 0x000c, 0x31e8: 0x000c, 0x31e9: 0x000c,
+	0x31ea: 0x000c, 0x31eb: 0x000c, 0x31ec: 0x000c, 0x31ed: 0x000c, 0x31ee: 0x000c, 0x31ef: 0x000c,
+	0x31f0: 0x000c, 0x31f1: 0x000c, 0x31f2: 0x000c, 0x31f3: 0x000c, 0x31f4: 0x000c, 0x31f5: 0x000c,
+	0x31f6: 0x000c, 0x31fb: 0x000c,
+	0x31fc: 0x000c, 0x31fd: 0x000c, 0x31fe: 0x000c, 0x31ff: 0x000c,
+	// Block 0xc8, offset 0x3200
+	0x3200: 0x000c, 0x3201: 0x000c, 0x3202: 0x000c, 0x3203: 0x000c, 0x3204: 0x000c, 0x3205: 0x000c,
+	0x3206: 0x000c, 0x3207: 0x000c, 0x3208: 0x000c, 0x3209: 0x000c, 0x320a: 0x000c, 0x320b: 0x000c,
+	0x320c: 0x000c, 0x320d: 0x000c, 0x320e: 0x000c, 0x320f: 0x000c, 0x3210: 0x000c, 0x3211: 0x000c,
+	0x3212: 0x000c, 0x3213: 0x000c, 0x3214: 0x000c, 0x3215: 0x000c, 0x3216: 0x000c, 0x3217: 0x000c,
+	0x3218: 0x000c, 0x3219: 0x000c, 0x321a: 0x000c, 0x321b: 0x000c, 0x321c: 0x000c, 0x321d: 0x000c,
+	0x321e: 0x000c, 0x321f: 0x000c, 0x3220: 0x000c, 0x3221: 0x000c, 0x3222: 0x000c, 0x3223: 0x000c,
+	0x3224: 0x000c, 0x3225: 0x000c, 0x3226: 0x000c, 0x3227: 0x000c, 0x3228: 0x000c, 0x3229: 0x000c,
+	0x322a: 0x000c, 0x322b: 0x000c, 0x322c: 0x000c,
+	0x3235: 0x000c,
+	// Block 0xc9, offset 0x3240
+	0x3244: 0x000c,
+	0x325b: 0x000c, 0x325c: 0x000c, 0x325d: 0x000c,
+	0x325e: 0x000c, 0x325f: 0x000c, 0x3261: 0x000c, 0x3262: 0x000c, 0x3263: 0x000c,
+	0x3264: 0x000c, 0x3265: 0x000c, 0x3266: 0x000c, 0x3267: 0x000c, 0x3268: 0x000c, 0x3269: 0x000c,
+	0x326a: 0x000c, 0x326b: 0x000c, 0x326c: 0x000c, 0x326d: 0x000c, 0x326e: 0x000c, 0x326f: 0x000c,
+	// Block 0xca, offset 0x3280
+	0x3280: 0x000c, 0x3281: 0x000c, 0x3282: 0x000c, 0x3283: 0x000c, 0x3284: 0x000c, 0x3285: 0x000c,
+	0x3286: 0x000c, 0x3288: 0x000c, 0x3289: 0x000c, 0x328a: 0x000c, 0x328b: 0x000c,
+	0x328c: 0x000c, 0x328d: 0x000c, 0x328e: 0x000c, 0x328f: 0x000c, 0x3290: 0x000c, 0x3291: 0x000c,
+	0x3292: 0x000c, 0x3293: 0x000c, 0x3294: 0x000c, 0x3295: 0x000c, 0x3296: 0x000c, 0x3297: 0x000c,
+	0x3298: 0x000c, 0x329b: 0x000c, 0x329c: 0x000c, 0x329d: 0x000c,
+	0x329e: 0x000c, 0x329f: 0x000c, 0x32a0: 0x000c, 0x32a1: 0x000c, 0x32a3: 0x000c,
+	0x32a4: 0x000c, 0x32a6: 0x000c, 0x32a7: 0x000c, 0x32a8: 0x000c, 0x32a9: 0x000c,
+	0x32aa: 0x000c,
+	// Block 0xcb, offset 0x32c0
+	0x32c0: 0x0001, 0x32c1: 0x0001, 0x32c2: 0x0001, 0x32c3: 0x0001, 0x32c4: 0x0001, 0x32c5: 0x0001,
+	0x32c6: 0x0001, 0x32c7: 0x0001, 0x32c8: 0x0001, 0x32c9: 0x0001, 0x32ca: 0x0001, 0x32cb: 0x0001,
+	0x32cc: 0x0001, 0x32cd: 0x0001, 0x32ce: 0x0001, 0x32cf: 0x0001, 0x32d0: 0x000c, 0x32d1: 0x000c,
+	0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x0001,
+	0x32d8: 0x0001, 0x32d9: 0x0001, 0x32da: 0x0001, 0x32db: 0x0001, 0x32dc: 0x0001, 0x32dd: 0x0001,
+	0x32de: 0x0001, 0x32df: 0x0001, 0x32e0: 0x0001, 0x32e1: 0x0001, 0x32e2: 0x0001, 0x32e3: 0x0001,
+	0x32e4: 0x0001, 0x32e5: 0x0001, 0x32e6: 0x0001, 0x32e7: 0x0001, 0x32e8: 0x0001, 0x32e9: 0x0001,
+	0x32ea: 0x0001, 0x32eb: 0x0001, 0x32ec: 0x0001, 0x32ed: 0x0001, 0x32ee: 0x0001, 0x32ef: 0x0001,
+	0x32f0: 0x0001, 0x32f1: 0x0001, 0x32f2: 0x0001, 0x32f3: 0x0001, 0x32f4: 0x0001, 0x32f5: 0x0001,
+	0x32f6: 0x0001, 0x32f7: 0x0001, 0x32f8: 0x0001, 0x32f9: 0x0001, 0x32fa: 0x0001, 0x32fb: 0x0001,
+	0x32fc: 0x0001, 0x32fd: 0x0001, 0x32fe: 0x0001, 0x32ff: 0x0001,
+	// Block 0xcc, offset 0x3300
+	0x3300: 0x0001, 0x3301: 0x0001, 0x3302: 0x0001, 0x3303: 0x0001, 0x3304: 0x000c, 0x3305: 0x000c,
+	0x3306: 0x000c, 0x3307: 0x000c, 0x3308: 0x000c, 0x3309: 0x000c, 0x330a: 0x000c, 0x330b: 0x0001,
+	0x330c: 0x0001, 0x330d: 0x0001, 0x330e: 0x0001, 0x330f: 0x0001, 0x3310: 0x0001, 0x3311: 0x0001,
+	0x3312: 0x0001, 0x3313: 0x0001, 0x3314: 0x0001, 0x3315: 0x0001, 0x3316: 0x0001, 0x3317: 0x0001,
+	0x3318: 0x0001, 0x3319: 0x0001, 0x331a: 0x0001, 0x331b: 0x0001, 0x331c: 0x0001, 0x331d: 0x0001,
+	0x331e: 0x0001, 0x331f: 0x0001, 0x3320: 0x0001, 0x3321: 0x0001, 0x3322: 0x0001, 0x3323: 0x0001,
+	0x3324: 0x0001, 0x3325: 0x0001, 0x3326: 0x0001, 0x3327: 0x0001, 0x3328: 0x0001, 0x3329: 0x0001,
+	0x332a: 0x0001, 0x332b: 0x0001, 0x332c: 0x0001, 0x332d: 0x0001, 0x332e: 0x0001, 0x332f: 0x0001,
+	0x3330: 0x0001, 0x3331: 0x0001, 0x3332: 0x0001, 0x3333: 0x0001, 0x3334: 0x0001, 0x3335: 0x0001,
+	0x3336: 0x0001, 0x3337: 0x0001, 0x3338: 0x0001, 0x3339: 0x0001, 0x333a: 0x0001, 0x333b: 0x0001,
+	0x333c: 0x0001, 0x333d: 0x0001, 0x333e: 0x0001, 0x333f: 0x0001,
+	// Block 0xcd, offset 0x3340
+	0x3340: 0x000d, 0x3341: 0x000d, 0x3342: 0x000d, 0x3343: 0x000d, 0x3344: 0x000d, 0x3345: 0x000d,
+	0x3346: 0x000d, 0x3347: 0x000d, 0x3348: 0x000d, 0x3349: 0x000d, 0x334a: 0x000d, 0x334b: 0x000d,
+	0x334c: 0x000d, 0x334d: 0x000d, 0x334e: 0x000d, 0x334f: 0x000d, 0x3350: 0x000d, 0x3351: 0x000d,
+	0x3352: 0x000d, 0x3353: 0x000d, 0x3354: 0x000d, 0x3355: 0x000d, 0x3356: 0x000d, 0x3357: 0x000d,
+	0x3358: 0x000d, 0x3359: 0x000d, 0x335a: 0x000d, 0x335b: 0x000d, 0x335c: 0x000d, 0x335d: 0x000d,
+	0x335e: 0x000d, 0x335f: 0x000d, 0x3360: 0x000d, 0x3361: 0x000d, 0x3362: 0x000d, 0x3363: 0x000d,
+	0x3364: 0x000d, 0x3365: 0x000d, 0x3366: 0x000d, 0x3367: 0x000d, 0x3368: 0x000d, 0x3369: 0x000d,
+	0x336a: 0x000d, 0x336b: 0x000d, 0x336c: 0x000d, 0x336d: 0x000d, 0x336e: 0x000d, 0x336f: 0x000d,
+	0x3370: 0x000a, 0x3371: 0x000a, 0x3372: 0x000d, 0x3373: 0x000d, 0x3374: 0x000d, 0x3375: 0x000d,
+	0x3376: 0x000d, 0x3377: 0x000d, 0x3378: 0x000d, 0x3379: 0x000d, 0x337a: 0x000d, 0x337b: 0x000d,
+	0x337c: 0x000d, 0x337d: 0x000d, 0x337e: 0x000d, 0x337f: 0x000d,
+	// Block 0xce, offset 0x3380
+	0x3380: 0x000a, 0x3381: 0x000a, 0x3382: 0x000a, 0x3383: 0x000a, 0x3384: 0x000a, 0x3385: 0x000a,
+	0x3386: 0x000a, 0x3387: 0x000a, 0x3388: 0x000a, 0x3389: 0x000a, 0x338a: 0x000a, 0x338b: 0x000a,
+	0x338c: 0x000a, 0x338d: 0x000a, 0x338e: 0x000a, 0x338f: 0x000a, 0x3390: 0x000a, 0x3391: 0x000a,
+	0x3392: 0x000a, 0x3393: 0x000a, 0x3394: 0x000a, 0x3395: 0x000a, 0x3396: 0x000a, 0x3397: 0x000a,
+	0x3398: 0x000a, 0x3399: 0x000a, 0x339a: 0x000a, 0x339b: 0x000a, 0x339c: 0x000a, 0x339d: 0x000a,
+	0x339e: 0x000a, 0x339f: 0x000a, 0x33a0: 0x000a, 0x33a1: 0x000a, 0x33a2: 0x000a, 0x33a3: 0x000a,
+	0x33a4: 0x000a, 0x33a5: 0x000a, 0x33a6: 0x000a, 0x33a7: 0x000a, 0x33a8: 0x000a, 0x33a9: 0x000a,
+	0x33aa: 0x000a, 0x33ab: 0x000a,
+	0x33b0: 0x000a, 0x33b1: 0x000a, 0x33b2: 0x000a, 0x33b3: 0x000a, 0x33b4: 0x000a, 0x33b5: 0x000a,
+	0x33b6: 0x000a, 0x33b7: 0x000a, 0x33b8: 0x000a, 0x33b9: 0x000a, 0x33ba: 0x000a, 0x33bb: 0x000a,
+	0x33bc: 0x000a, 0x33bd: 0x000a, 0x33be: 0x000a, 0x33bf: 0x000a,
+	// Block 0xcf, offset 0x33c0
+	0x33c0: 0x000a, 0x33c1: 0x000a, 0x33c2: 0x000a, 0x33c3: 0x000a, 0x33c4: 0x000a, 0x33c5: 0x000a,
+	0x33c6: 0x000a, 0x33c7: 0x000a, 0x33c8: 0x000a, 0x33c9: 0x000a, 0x33ca: 0x000a, 0x33cb: 0x000a,
+	0x33cc: 0x000a, 0x33cd: 0x000a, 0x33ce: 0x000a, 0x33cf: 0x000a, 0x33d0: 0x000a, 0x33d1: 0x000a,
+	0x33d2: 0x000a, 0x33d3: 0x000a,
+	0x33e0: 0x000a, 0x33e1: 0x000a, 0x33e2: 0x000a, 0x33e3: 0x000a,
+	0x33e4: 0x000a, 0x33e5: 0x000a, 0x33e6: 0x000a, 0x33e7: 0x000a, 0x33e8: 0x000a, 0x33e9: 0x000a,
+	0x33ea: 0x000a, 0x33eb: 0x000a, 0x33ec: 0x000a, 0x33ed: 0x000a, 0x33ee: 0x000a,
+	0x33f1: 0x000a, 0x33f2: 0x000a, 0x33f3: 0x000a, 0x33f4: 0x000a, 0x33f5: 0x000a,
+	0x33f6: 0x000a, 0x33f7: 0x000a, 0x33f8: 0x000a, 0x33f9: 0x000a, 0x33fa: 0x000a, 0x33fb: 0x000a,
+	0x33fc: 0x000a, 0x33fd: 0x000a, 0x33fe: 0x000a, 0x33ff: 0x000a,
+	// Block 0xd0, offset 0x3400
+	0x3401: 0x000a, 0x3402: 0x000a, 0x3403: 0x000a, 0x3404: 0x000a, 0x3405: 0x000a,
+	0x3406: 0x000a, 0x3407: 0x000a, 0x3408: 0x000a, 0x3409: 0x000a, 0x340a: 0x000a, 0x340b: 0x000a,
+	0x340c: 0x000a, 0x340d: 0x000a, 0x340e: 0x000a, 0x340f: 0x000a, 0x3411: 0x000a,
+	0x3412: 0x000a, 0x3413: 0x000a, 0x3414: 0x000a, 0x3415: 0x000a, 0x3416: 0x000a, 0x3417: 0x000a,
+	0x3418: 0x000a, 0x3419: 0x000a, 0x341a: 0x000a, 0x341b: 0x000a, 0x341c: 0x000a, 0x341d: 0x000a,
+	0x341e: 0x000a, 0x341f: 0x000a, 0x3420: 0x000a, 0x3421: 0x000a, 0x3422: 0x000a, 0x3423: 0x000a,
+	0x3424: 0x000a, 0x3425: 0x000a, 0x3426: 0x000a, 0x3427: 0x000a, 0x3428: 0x000a, 0x3429: 0x000a,
+	0x342a: 0x000a, 0x342b: 0x000a, 0x342c: 0x000a, 0x342d: 0x000a, 0x342e: 0x000a, 0x342f: 0x000a,
+	0x3430: 0x000a, 0x3431: 0x000a, 0x3432: 0x000a, 0x3433: 0x000a, 0x3434: 0x000a, 0x3435: 0x000a,
+	// Block 0xd1, offset 0x3440
+	0x3440: 0x0002, 0x3441: 0x0002, 0x3442: 0x0002, 0x3443: 0x0002, 0x3444: 0x0002, 0x3445: 0x0002,
+	0x3446: 0x0002, 0x3447: 0x0002, 0x3448: 0x0002, 0x3449: 0x0002, 0x344a: 0x0002, 0x344b: 0x000a,
+	0x344c: 0x000a,
+	// Block 0xd2, offset 0x3480
+	0x34aa: 0x000a, 0x34ab: 0x000a,
+	// Block 0xd3, offset 0x34c0
+	0x34c0: 0x000a, 0x34c1: 0x000a, 0x34c2: 0x000a, 0x34c3: 0x000a, 0x34c4: 0x000a, 0x34c5: 0x000a,
+	0x34c6: 0x000a, 0x34c7: 0x000a, 0x34c8: 0x000a, 0x34c9: 0x000a, 0x34ca: 0x000a, 0x34cb: 0x000a,
+	0x34cc: 0x000a, 0x34cd: 0x000a, 0x34ce: 0x000a, 0x34cf: 0x000a, 0x34d0: 0x000a, 0x34d1: 0x000a,
+	0x34d2: 0x000a,
+	0x34e0: 0x000a, 0x34e1: 0x000a, 0x34e2: 0x000a, 0x34e3: 0x000a,
+	0x34e4: 0x000a, 0x34e5: 0x000a, 0x34e6: 0x000a, 0x34e7: 0x000a, 0x34e8: 0x000a, 0x34e9: 0x000a,
+	0x34ea: 0x000a, 0x34eb: 0x000a, 0x34ec: 0x000a,
+	0x34f0: 0x000a, 0x34f1: 0x000a, 0x34f2: 0x000a, 0x34f3: 0x000a, 0x34f4: 0x000a, 0x34f5: 0x000a,
+	0x34f6: 0x000a,
+	// Block 0xd4, offset 0x3500
+	0x3500: 0x000a, 0x3501: 0x000a, 0x3502: 0x000a, 0x3503: 0x000a, 0x3504: 0x000a, 0x3505: 0x000a,
+	0x3506: 0x000a, 0x3507: 0x000a, 0x3508: 0x000a, 0x3509: 0x000a, 0x350a: 0x000a, 0x350b: 0x000a,
+	0x350c: 0x000a, 0x350d: 0x000a, 0x350e: 0x000a, 0x350f: 0x000a, 0x3510: 0x000a, 0x3511: 0x000a,
+	0x3512: 0x000a, 0x3513: 0x000a, 0x3514: 0x000a,
+	// Block 0xd5, offset 0x3540
+	0x3540: 0x000a, 0x3541: 0x000a, 0x3542: 0x000a, 0x3543: 0x000a, 0x3544: 0x000a, 0x3545: 0x000a,
+	0x3546: 0x000a, 0x3547: 0x000a, 0x3548: 0x000a, 0x3549: 0x000a, 0x354a: 0x000a, 0x354b: 0x000a,
+	0x3550: 0x000a, 0x3551: 0x000a,
+	0x3552: 0x000a, 0x3553: 0x000a, 0x3554: 0x000a, 0x3555: 0x000a, 0x3556: 0x000a, 0x3557: 0x000a,
+	0x3558: 0x000a, 0x3559: 0x000a, 0x355a: 0x000a, 0x355b: 0x000a, 0x355c: 0x000a, 0x355d: 0x000a,
+	0x355e: 0x000a, 0x355f: 0x000a, 0x3560: 0x000a, 0x3561: 0x000a, 0x3562: 0x000a, 0x3563: 0x000a,
+	0x3564: 0x000a, 0x3565: 0x000a, 0x3566: 0x000a, 0x3567: 0x000a, 0x3568: 0x000a, 0x3569: 0x000a,
+	0x356a: 0x000a, 0x356b: 0x000a, 0x356c: 0x000a, 0x356d: 0x000a, 0x356e: 0x000a, 0x356f: 0x000a,
+	0x3570: 0x000a, 0x3571: 0x000a, 0x3572: 0x000a, 0x3573: 0x000a, 0x3574: 0x000a, 0x3575: 0x000a,
+	0x3576: 0x000a, 0x3577: 0x000a, 0x3578: 0x000a, 0x3579: 0x000a, 0x357a: 0x000a, 0x357b: 0x000a,
+	0x357c: 0x000a, 0x357d: 0x000a, 0x357e: 0x000a, 0x357f: 0x000a,
+	// Block 0xd6, offset 0x3580
+	0x3580: 0x000a, 0x3581: 0x000a, 0x3582: 0x000a, 0x3583: 0x000a, 0x3584: 0x000a, 0x3585: 0x000a,
+	0x3586: 0x000a, 0x3587: 0x000a,
+	0x3590: 0x000a, 0x3591: 0x000a,
+	0x3592: 0x000a, 0x3593: 0x000a, 0x3594: 0x000a, 0x3595: 0x000a, 0x3596: 0x000a, 0x3597: 0x000a,
+	0x3598: 0x000a, 0x3599: 0x000a,
+	0x35a0: 0x000a, 0x35a1: 0x000a, 0x35a2: 0x000a, 0x35a3: 0x000a,
+	0x35a4: 0x000a, 0x35a5: 0x000a, 0x35a6: 0x000a, 0x35a7: 0x000a, 0x35a8: 0x000a, 0x35a9: 0x000a,
+	0x35aa: 0x000a, 0x35ab: 0x000a, 0x35ac: 0x000a, 0x35ad: 0x000a, 0x35ae: 0x000a, 0x35af: 0x000a,
+	0x35b0: 0x000a, 0x35b1: 0x000a, 0x35b2: 0x000a, 0x35b3: 0x000a, 0x35b4: 0x000a, 0x35b5: 0x000a,
+	0x35b6: 0x000a, 0x35b7: 0x000a, 0x35b8: 0x000a, 0x35b9: 0x000a, 0x35ba: 0x000a, 0x35bb: 0x000a,
+	0x35bc: 0x000a, 0x35bd: 0x000a, 0x35be: 0x000a, 0x35bf: 0x000a,
+	// Block 0xd7, offset 0x35c0
+	0x35c0: 0x000a, 0x35c1: 0x000a, 0x35c2: 0x000a, 0x35c3: 0x000a, 0x35c4: 0x000a, 0x35c5: 0x000a,
+	0x35c6: 0x000a, 0x35c7: 0x000a,
+	0x35d0: 0x000a, 0x35d1: 0x000a,
+	0x35d2: 0x000a, 0x35d3: 0x000a, 0x35d4: 0x000a, 0x35d5: 0x000a, 0x35d6: 0x000a, 0x35d7: 0x000a,
+	0x35d8: 0x000a, 0x35d9: 0x000a, 0x35da: 0x000a, 0x35db: 0x000a, 0x35dc: 0x000a, 0x35dd: 0x000a,
+	0x35de: 0x000a, 0x35df: 0x000a, 0x35e0: 0x000a, 0x35e1: 0x000a, 0x35e2: 0x000a, 0x35e3: 0x000a,
+	0x35e4: 0x000a, 0x35e5: 0x000a, 0x35e6: 0x000a, 0x35e7: 0x000a, 0x35e8: 0x000a, 0x35e9: 0x000a,
+	0x35ea: 0x000a, 0x35eb: 0x000a, 0x35ec: 0x000a, 0x35ed: 0x000a,
+	// Block 0xd8, offset 0x3600
+	0x3610: 0x000a, 0x3611: 0x000a,
+	0x3612: 0x000a, 0x3613: 0x000a, 0x3614: 0x000a, 0x3615: 0x000a, 0x3616: 0x000a, 0x3617: 0x000a,
+	0x3618: 0x000a, 0x3619: 0x000a, 0x361a: 0x000a, 0x361b: 0x000a, 0x361c: 0x000a, 0x361d: 0x000a,
+	0x361e: 0x000a, 0x3620: 0x000a, 0x3621: 0x000a, 0x3622: 0x000a, 0x3623: 0x000a,
+	0x3624: 0x000a, 0x3625: 0x000a, 0x3626: 0x000a, 0x3627: 0x000a,
+	0x3630: 0x000a, 0x3633: 0x000a, 0x3634: 0x000a, 0x3635: 0x000a,
+	0x3636: 0x000a, 0x3637: 0x000a, 0x3638: 0x000a, 0x3639: 0x000a, 0x363a: 0x000a, 0x363b: 0x000a,
+	0x363c: 0x000a, 0x363d: 0x000a, 0x363e: 0x000a,
+	// Block 0xd9, offset 0x3640
+	0x3640: 0x000a, 0x3641: 0x000a, 0x3642: 0x000a, 0x3643: 0x000a, 0x3644: 0x000a, 0x3645: 0x000a,
+	0x3646: 0x000a, 0x3647: 0x000a, 0x3648: 0x000a, 0x3649: 0x000a, 0x364a: 0x000a, 0x364b: 0x000a,
+	0x3650: 0x000a, 0x3651: 0x000a,
+	0x3652: 0x000a, 0x3653: 0x000a, 0x3654: 0x000a, 0x3655: 0x000a, 0x3656: 0x000a, 0x3657: 0x000a,
+	0x3658: 0x000a, 0x3659: 0x000a, 0x365a: 0x000a, 0x365b: 0x000a, 0x365c: 0x000a, 0x365d: 0x000a,
+	0x365e: 0x000a,
+	// Block 0xda, offset 0x3680
+	0x3680: 0x000a, 0x3681: 0x000a, 0x3682: 0x000a, 0x3683: 0x000a, 0x3684: 0x000a, 0x3685: 0x000a,
+	0x3686: 0x000a, 0x3687: 0x000a, 0x3688: 0x000a, 0x3689: 0x000a, 0x368a: 0x000a, 0x368b: 0x000a,
+	0x368c: 0x000a, 0x368d: 0x000a, 0x368e: 0x000a, 0x368f: 0x000a, 0x3690: 0x000a, 0x3691: 0x000a,
+	// Block 0xdb, offset 0x36c0
+	0x36fe: 0x000b, 0x36ff: 0x000b,
+	// Block 0xdc, offset 0x3700
+	0x3700: 0x000b, 0x3701: 0x000b, 0x3702: 0x000b, 0x3703: 0x000b, 0x3704: 0x000b, 0x3705: 0x000b,
+	0x3706: 0x000b, 0x3707: 0x000b, 0x3708: 0x000b, 0x3709: 0x000b, 0x370a: 0x000b, 0x370b: 0x000b,
+	0x370c: 0x000b, 0x370d: 0x000b, 0x370e: 0x000b, 0x370f: 0x000b, 0x3710: 0x000b, 0x3711: 0x000b,
+	0x3712: 0x000b, 0x3713: 0x000b, 0x3714: 0x000b, 0x3715: 0x000b, 0x3716: 0x000b, 0x3717: 0x000b,
+	0x3718: 0x000b, 0x3719: 0x000b, 0x371a: 0x000b, 0x371b: 0x000b, 0x371c: 0x000b, 0x371d: 0x000b,
+	0x371e: 0x000b, 0x371f: 0x000b, 0x3720: 0x000b, 0x3721: 0x000b, 0x3722: 0x000b, 0x3723: 0x000b,
+	0x3724: 0x000b, 0x3725: 0x000b, 0x3726: 0x000b, 0x3727: 0x000b, 0x3728: 0x000b, 0x3729: 0x000b,
+	0x372a: 0x000b, 0x372b: 0x000b, 0x372c: 0x000b, 0x372d: 0x000b, 0x372e: 0x000b, 0x372f: 0x000b,
+	0x3730: 0x000b, 0x3731: 0x000b, 0x3732: 0x000b, 0x3733: 0x000b, 0x3734: 0x000b, 0x3735: 0x000b,
+	0x3736: 0x000b, 0x3737: 0x000b, 0x3738: 0x000b, 0x3739: 0x000b, 0x373a: 0x000b, 0x373b: 0x000b,
+	0x373c: 0x000b, 0x373d: 0x000b, 0x373e: 0x000b, 0x373f: 0x000b,
+	// Block 0xdd, offset 0x3740
+	0x3740: 0x000c, 0x3741: 0x000c, 0x3742: 0x000c, 0x3743: 0x000c, 0x3744: 0x000c, 0x3745: 0x000c,
+	0x3746: 0x000c, 0x3747: 0x000c, 0x3748: 0x000c, 0x3749: 0x000c, 0x374a: 0x000c, 0x374b: 0x000c,
+	0x374c: 0x000c, 0x374d: 0x000c, 0x374e: 0x000c, 0x374f: 0x000c, 0x3750: 0x000c, 0x3751: 0x000c,
+	0x3752: 0x000c, 0x3753: 0x000c, 0x3754: 0x000c, 0x3755: 0x000c, 0x3756: 0x000c, 0x3757: 0x000c,
+	0x3758: 0x000c, 0x3759: 0x000c, 0x375a: 0x000c, 0x375b: 0x000c, 0x375c: 0x000c, 0x375d: 0x000c,
+	0x375e: 0x000c, 0x375f: 0x000c, 0x3760: 0x000c, 0x3761: 0x000c, 0x3762: 0x000c, 0x3763: 0x000c,
+	0x3764: 0x000c, 0x3765: 0x000c, 0x3766: 0x000c, 0x3767: 0x000c, 0x3768: 0x000c, 0x3769: 0x000c,
+	0x376a: 0x000c, 0x376b: 0x000c, 0x376c: 0x000c, 0x376d: 0x000c, 0x376e: 0x000c, 0x376f: 0x000c,
+	0x3770: 0x000b, 0x3771: 0x000b, 0x3772: 0x000b, 0x3773: 0x000b, 0x3774: 0x000b, 0x3775: 0x000b,
+	0x3776: 0x000b, 0x3777: 0x000b, 0x3778: 0x000b, 0x3779: 0x000b, 0x377a: 0x000b, 0x377b: 0x000b,
+	0x377c: 0x000b, 0x377d: 0x000b, 0x377e: 0x000b, 0x377f: 0x000b,
+}
+
+// bidiIndex: 24 blocks, 1536 entries, 1536 bytes
+// Block 0 is the zero block.
+var bidiIndex = [1536]uint8{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x02,
+	0xca: 0x03, 0xcb: 0x04, 0xcc: 0x05, 0xcd: 0x06, 0xce: 0x07, 0xcf: 0x08,
+	0xd2: 0x09, 0xd6: 0x0a, 0xd7: 0x0b,
+	0xd8: 0x0c, 0xd9: 0x0d, 0xda: 0x0e, 0xdb: 0x0f, 0xdc: 0x10, 0xdd: 0x11, 0xde: 0x12, 0xdf: 0x13,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06,
+	0xea: 0x07, 0xef: 0x08,
+	0xf0: 0x11, 0xf1: 0x12, 0xf2: 0x12, 0xf3: 0x14, 0xf4: 0x15,
+	// Block 0x4, offset 0x100
+	0x120: 0x14, 0x121: 0x15, 0x122: 0x16, 0x123: 0x17, 0x124: 0x18, 0x125: 0x19, 0x126: 0x1a, 0x127: 0x1b,
+	0x128: 0x1c, 0x129: 0x1d, 0x12a: 0x1c, 0x12b: 0x1e, 0x12c: 0x1f, 0x12d: 0x20, 0x12e: 0x21, 0x12f: 0x22,
+	0x130: 0x23, 0x131: 0x24, 0x132: 0x1a, 0x133: 0x25, 0x134: 0x26, 0x135: 0x27, 0x137: 0x28,
+	0x138: 0x29, 0x139: 0x2a, 0x13a: 0x2b, 0x13b: 0x2c, 0x13c: 0x2d, 0x13d: 0x2e, 0x13e: 0x2f, 0x13f: 0x30,
+	// Block 0x5, offset 0x140
+	0x140: 0x31, 0x141: 0x32, 0x142: 0x33,
+	0x14d: 0x34, 0x14e: 0x35,
+	0x150: 0x36,
+	0x15a: 0x37, 0x15c: 0x38, 0x15d: 0x39, 0x15e: 0x3a, 0x15f: 0x3b,
+	0x160: 0x3c, 0x162: 0x3d, 0x164: 0x3e, 0x165: 0x3f, 0x167: 0x40,
+	0x168: 0x41, 0x169: 0x42, 0x16a: 0x43, 0x16c: 0x44, 0x16d: 0x45, 0x16e: 0x46, 0x16f: 0x47,
+	0x170: 0x48, 0x173: 0x49, 0x177: 0x4a,
+	0x17e: 0x4b, 0x17f: 0x4c,
+	// Block 0x6, offset 0x180
+	0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54,
+	0x188: 0x55, 0x189: 0x54, 0x18a: 0x54, 0x18b: 0x54, 0x18c: 0x56, 0x18d: 0x57, 0x18e: 0x58, 0x18f: 0x59,
+	0x190: 0x5a, 0x191: 0x5b, 0x192: 0x5c, 0x193: 0x5d, 0x194: 0x54, 0x195: 0x54, 0x196: 0x54, 0x197: 0x54,
+	0x198: 0x54, 0x199: 0x54, 0x19a: 0x5e, 0x19b: 0x54, 0x19c: 0x54, 0x19d: 0x5f, 0x19e: 0x54, 0x19f: 0x60,
+	0x1a4: 0x54, 0x1a5: 0x54, 0x1a6: 0x61, 0x1a7: 0x62,
+	0x1a8: 0x54, 0x1a9: 0x54, 0x1aa: 0x54, 0x1ab: 0x54, 0x1ac: 0x54, 0x1ad: 0x63, 0x1ae: 0x64, 0x1af: 0x65,
+	0x1b3: 0x66, 0x1b5: 0x67, 0x1b7: 0x68,
+	0x1b8: 0x69, 0x1b9: 0x6a, 0x1ba: 0x6b, 0x1bb: 0x6c, 0x1bc: 0x54, 0x1bd: 0x54, 0x1be: 0x54, 0x1bf: 0x6d,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x6e, 0x1c2: 0x6f, 0x1c3: 0x70, 0x1c7: 0x71,
+	0x1c8: 0x72, 0x1c9: 0x73, 0x1ca: 0x74, 0x1cb: 0x75, 0x1cd: 0x76, 0x1cf: 0x77,
+	// Block 0x8, offset 0x200
+	0x237: 0x54,
+	// Block 0x9, offset 0x240
+	0x252: 0x78, 0x253: 0x79,
+	0x258: 0x7a, 0x259: 0x7b, 0x25a: 0x7c, 0x25b: 0x7d, 0x25c: 0x7e, 0x25e: 0x7f,
+	0x260: 0x80, 0x261: 0x81, 0x263: 0x82, 0x264: 0x83, 0x265: 0x84, 0x266: 0x85, 0x267: 0x86,
+	0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26f: 0x8b,
+	// Block 0xa, offset 0x280
+	0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x0e, 0x2af: 0x0e,
+	0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8e, 0x2b5: 0x0e, 0x2b6: 0x0e, 0x2b7: 0x8f,
+	0x2b8: 0x90, 0x2b9: 0x91, 0x2ba: 0x0e, 0x2bb: 0x92, 0x2bc: 0x93, 0x2bd: 0x94, 0x2bf: 0x95,
+	// Block 0xb, offset 0x2c0
+	0x2c4: 0x96, 0x2c5: 0x54, 0x2c6: 0x97, 0x2c7: 0x98,
+	0x2cb: 0x99, 0x2cd: 0x9a,
+	0x2e0: 0x9b, 0x2e1: 0x9b, 0x2e2: 0x9b, 0x2e3: 0x9b, 0x2e4: 0x9c, 0x2e5: 0x9b, 0x2e6: 0x9b, 0x2e7: 0x9b,
+	0x2e8: 0x9d, 0x2e9: 0x9b, 0x2ea: 0x9b, 0x2eb: 0x9e, 0x2ec: 0x9f, 0x2ed: 0x9b, 0x2ee: 0x9b, 0x2ef: 0x9b,
+	0x2f0: 0x9b, 0x2f1: 0x9b, 0x2f2: 0x9b, 0x2f3: 0x9b, 0x2f4: 0x9b, 0x2f5: 0x9b, 0x2f6: 0x9b, 0x2f7: 0x9b,
+	0x2f8: 0x9b, 0x2f9: 0xa0, 0x2fa: 0x9b, 0x2fb: 0x9b, 0x2fc: 0x9b, 0x2fd: 0x9b, 0x2fe: 0x9b, 0x2ff: 0x9b,
+	// Block 0xc, offset 0x300
+	0x300: 0xa1, 0x301: 0xa2, 0x302: 0xa3, 0x304: 0xa4, 0x305: 0xa5, 0x306: 0xa6, 0x307: 0xa7,
+	0x308: 0xa8, 0x30b: 0xa9, 0x30c: 0xaa, 0x30d: 0xab,
+	0x310: 0xac, 0x311: 0xad, 0x312: 0xae, 0x313: 0xaf, 0x316: 0xb0, 0x317: 0xb1,
+	0x318: 0xb2, 0x319: 0xb3, 0x31a: 0xb4, 0x31c: 0xb5,
+	0x330: 0xb6, 0x332: 0xb7,
+	// Block 0xd, offset 0x340
+	0x36b: 0xb8, 0x36c: 0xb9,
+	0x37e: 0xba,
+	// Block 0xe, offset 0x380
+	0x3b2: 0xbb,
+	// Block 0xf, offset 0x3c0
+	0x3c5: 0xbc, 0x3c6: 0xbd,
+	0x3c8: 0x54, 0x3c9: 0xbe, 0x3cc: 0x54, 0x3cd: 0xbf,
+	0x3db: 0xc0, 0x3dc: 0xc1, 0x3dd: 0xc2, 0x3de: 0xc3, 0x3df: 0xc4,
+	0x3e8: 0xc5, 0x3e9: 0xc6, 0x3ea: 0xc7,
+	// Block 0x10, offset 0x400
+	0x400: 0xc8,
+	0x420: 0x9b, 0x421: 0x9b, 0x422: 0x9b, 0x423: 0xc9, 0x424: 0x9b, 0x425: 0xca, 0x426: 0x9b, 0x427: 0x9b,
+	0x428: 0x9b, 0x429: 0x9b, 0x42a: 0x9b, 0x42b: 0x9b, 0x42c: 0x9b, 0x42d: 0x9b, 0x42e: 0x9b, 0x42f: 0x9b,
+	0x430: 0x9b, 0x431: 0x9b, 0x432: 0x9b, 0x433: 0x9b, 0x434: 0x9b, 0x435: 0x9b, 0x436: 0x9b, 0x437: 0x9b,
+	0x438: 0x0e, 0x439: 0x0e, 0x43a: 0x0e, 0x43b: 0xcb, 0x43c: 0x9b, 0x43d: 0x9b, 0x43e: 0x9b, 0x43f: 0x9b,
+	// Block 0x11, offset 0x440
+	0x440: 0xcc, 0x441: 0x54, 0x442: 0xcd, 0x443: 0xce, 0x444: 0xcf, 0x445: 0xd0,
+	0x44c: 0x54, 0x44d: 0x54, 0x44e: 0x54, 0x44f: 0x54,
+	0x450: 0x54, 0x451: 0x54, 0x452: 0x54, 0x453: 0x54, 0x454: 0x54, 0x455: 0x54, 0x456: 0x54, 0x457: 0x54,
+	0x458: 0x54, 0x459: 0x54, 0x45a: 0x54, 0x45b: 0xd1, 0x45c: 0x54, 0x45d: 0x6c, 0x45e: 0x54, 0x45f: 0xd2,
+	0x460: 0xd3, 0x461: 0xd4, 0x462: 0xd5, 0x464: 0xd6, 0x465: 0xd7, 0x466: 0xd8, 0x467: 0x36,
+	0x47f: 0xd9,
+	// Block 0x12, offset 0x480
+	0x4bf: 0xd9,
+	// Block 0x13, offset 0x4c0
+	0x4d0: 0x09, 0x4d1: 0x0a, 0x4d6: 0x0b,
+	0x4db: 0x0c, 0x4dd: 0x0d, 0x4de: 0x0e, 0x4df: 0x0f,
+	0x4ef: 0x10,
+	0x4ff: 0x10,
+	// Block 0x14, offset 0x500
+	0x50f: 0x10,
+	0x51f: 0x10,
+	0x52f: 0x10,
+	0x53f: 0x10,
+	// Block 0x15, offset 0x540
+	0x540: 0xda, 0x541: 0xda, 0x542: 0xda, 0x543: 0xda, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0xdb,
+	0x548: 0xda, 0x549: 0xda, 0x54a: 0xda, 0x54b: 0xda, 0x54c: 0xda, 0x54d: 0xda, 0x54e: 0xda, 0x54f: 0xda,
+	0x550: 0xda, 0x551: 0xda, 0x552: 0xda, 0x553: 0xda, 0x554: 0xda, 0x555: 0xda, 0x556: 0xda, 0x557: 0xda,
+	0x558: 0xda, 0x559: 0xda, 0x55a: 0xda, 0x55b: 0xda, 0x55c: 0xda, 0x55d: 0xda, 0x55e: 0xda, 0x55f: 0xda,
+	0x560: 0xda, 0x561: 0xda, 0x562: 0xda, 0x563: 0xda, 0x564: 0xda, 0x565: 0xda, 0x566: 0xda, 0x567: 0xda,
+	0x568: 0xda, 0x569: 0xda, 0x56a: 0xda, 0x56b: 0xda, 0x56c: 0xda, 0x56d: 0xda, 0x56e: 0xda, 0x56f: 0xda,
+	0x570: 0xda, 0x571: 0xda, 0x572: 0xda, 0x573: 0xda, 0x574: 0xda, 0x575: 0xda, 0x576: 0xda, 0x577: 0xda,
+	0x578: 0xda, 0x579: 0xda, 0x57a: 0xda, 0x57b: 0xda, 0x57c: 0xda, 0x57d: 0xda, 0x57e: 0xda, 0x57f: 0xda,
+	// Block 0x16, offset 0x580
+	0x58f: 0x10,
+	0x59f: 0x10,
+	0x5a0: 0x13,
+	0x5af: 0x10,
+	0x5bf: 0x10,
+	// Block 0x17, offset 0x5c0
+	0x5cf: 0x10,
+}
+
+// Total table size 15800 bytes (15KiB); checksum: F50EF68C
diff --git a/src/vendor/golang_org/x/text/unicode/bidi/trieval.go b/src/vendor/golang_org/x/text/unicode/bidi/trieval.go
new file mode 100644
index 0000000..a825fde
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/bidi/trieval.go
@@ -0,0 +1,62 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT.
+
+package bidi
+
+// Class is the Unicode BiDi class. Each rune has a single class.
+type Class uint
+
+const (
+	L       Class = iota // LeftToRight
+	R                    // RightToLeft
+	EN                   // EuropeanNumber
+	ES                   // EuropeanSeparator
+	ET                   // EuropeanTerminator
+	AN                   // ArabicNumber
+	CS                   // CommonSeparator
+	B                    // ParagraphSeparator
+	S                    // SegmentSeparator
+	WS                   // WhiteSpace
+	ON                   // OtherNeutral
+	BN                   // BoundaryNeutral
+	NSM                  // NonspacingMark
+	AL                   // ArabicLetter
+	Control              // Control LRO - PDI
+
+	numClass
+
+	LRO // LeftToRightOverride
+	RLO // RightToLeftOverride
+	LRE // LeftToRightEmbedding
+	RLE // RightToLeftEmbedding
+	PDF // PopDirectionalFormat
+	LRI // LeftToRightIsolate
+	RLI // RightToLeftIsolate
+	FSI // FirstStrongIsolate
+	PDI // PopDirectionalIsolate
+
+	unknownClass = ^Class(0)
+)
+
+var controlToClass = map[rune]Class{
+	0x202D: LRO, // LeftToRightOverride,
+	0x202E: RLO, // RightToLeftOverride,
+	0x202A: LRE, // LeftToRightEmbedding,
+	0x202B: RLE, // RightToLeftEmbedding,
+	0x202C: PDF, // PopDirectionalFormat,
+	0x2066: LRI, // LeftToRightIsolate,
+	0x2067: RLI, // RightToLeftIsolate,
+	0x2068: FSI, // FirstStrongIsolate,
+	0x2069: PDI, // PopDirectionalIsolate,
+}
+
+// A trie entry has the following bits:
+// 7..5  XOR mask for brackets
+// 4     1: Bracket open, 0: Bracket close
+// 3..0  Class type
+
+const (
+	openMask     = 0x10
+	xorMaskShift = 5
+)
diff --git a/src/vendor/golang_org/x/text/unicode/doc.go b/src/vendor/golang_org/x/text/unicode/doc.go
new file mode 100644
index 0000000..36b462a
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/doc.go
@@ -0,0 +1,10 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// unicode holds packages with implementations of Unicode standards that are
+// mostly used as building blocks for other packages in golang_org/x/text,
+// layout engines, or are otherwise more low-level in nature.
+package unicode
diff --git a/src/vendor/golang_org/x/text/unicode/norm/composition.go b/src/vendor/golang_org/x/text/unicode/norm/composition.go
index d17b278..7380b05 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/composition.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/composition.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/unicode/norm/example_iter_test.go b/src/vendor/golang_org/x/text/unicode/norm/example_iter_test.go
new file mode 100644
index 0000000..aed6c16
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/example_iter_test.go
@@ -0,0 +1,84 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm_test
+
+import (
+	"bytes"
+	"fmt"
+	"unicode/utf8"
+
+	"golang_org/x/text/unicode/norm"
+)
+
+// EqualSimple uses a norm.Iter to compare two non-normalized
+// strings for equivalence.
+func EqualSimple(a, b string) bool {
+	var ia, ib norm.Iter
+	ia.InitString(norm.NFKD, a)
+	ib.InitString(norm.NFKD, b)
+	for !ia.Done() && !ib.Done() {
+		if !bytes.Equal(ia.Next(), ib.Next()) {
+			return false
+		}
+	}
+	return ia.Done() && ib.Done()
+}
+
+// FindPrefix finds the longest common prefix of ASCII characters
+// of a and b.
+func FindPrefix(a, b string) int {
+	i := 0
+	for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ {
+	}
+	return i
+}
+
+// EqualOpt is like EqualSimple, but optimizes the special
+// case for ASCII characters.
+func EqualOpt(a, b string) bool {
+	n := FindPrefix(a, b)
+	a, b = a[n:], b[n:]
+	var ia, ib norm.Iter
+	ia.InitString(norm.NFKD, a)
+	ib.InitString(norm.NFKD, b)
+	for !ia.Done() && !ib.Done() {
+		if !bytes.Equal(ia.Next(), ib.Next()) {
+			return false
+		}
+		if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 {
+			ia.Seek(n, 1)
+			ib.Seek(n, 1)
+		}
+	}
+	return ia.Done() && ib.Done()
+}
+
+var compareTests = []struct{ a, b string }{
+	{"aaa", "aaa"},
+	{"aaa", "aab"},
+	{"a\u0300a", "\u00E0a"},
+	{"a\u0300\u0320b", "a\u0320\u0300b"},
+	{"\u1E0A\u0323", "\x44\u0323\u0307"},
+	// A character that decomposes into multiple segments
+	// spans several iterations.
+	{"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"},
+}
+
+func ExampleIter() {
+	for i, t := range compareTests {
+		r0 := EqualSimple(t.a, t.b)
+		r1 := EqualOpt(t.a, t.b)
+		fmt.Printf("%d: %v %v\n", i, r0, r1)
+	}
+	// Output:
+	// 0: true true
+	// 1: false false
+	// 2: true true
+	// 3: true true
+	// 4: true true
+	// 5: true true
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/example_test.go b/src/vendor/golang_org/x/text/unicode/norm/example_test.go
new file mode 100644
index 0000000..72e72c9
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/example_test.go
@@ -0,0 +1,29 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm_test
+
+import (
+	"fmt"
+
+	"golang_org/x/text/unicode/norm"
+)
+
+func ExampleForm_NextBoundary() {
+	s := norm.NFD.String("Mêlée")
+
+	for i := 0; i < len(s); {
+		d := norm.NFC.NextBoundaryInString(s[i:], true)
+		fmt.Printf("%[1]s: %+[1]q\n", s[i:i+d])
+		i += d
+	}
+	// Output:
+	// M: "M"
+	// ê: "e\u0302"
+	// l: "l"
+	// é: "e\u0301"
+	// e: "e"
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/forminfo.go b/src/vendor/golang_org/x/text/unicode/norm/forminfo.go
index 15a67c6..f3e2930 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/forminfo.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/forminfo.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go 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 +12,7 @@ package norm
 // and its corresponding decomposing form share the same trie.  Each trie maps
 // a rune to a uint16. The values take two forms.  For v >= 0x8000:
 //   bits
-//   15:    1 (inverse of NFD_QD bit of qcInfo)
+//   15:    1 (inverse of NFD_QC bit of qcInfo)
 //   13..7: qcInfo (see below). isYesD is always true (no decompostion).
 //    6..0: ccc (compressed CCC value).
 // For v < 0x8000, the respective rune has a decomposition and v is an index
@@ -56,28 +58,31 @@ type formInfo struct {
 	nextMain                 iterFunc
 }
 
-var formTable []*formInfo
-
-func init() {
-	formTable = make([]*formInfo, 4)
-
-	for i := range formTable {
-		f := &formInfo{}
-		formTable[i] = f
-		f.form = Form(i)
-		if Form(i) == NFKD || Form(i) == NFKC {
-			f.compatibility = true
-			f.info = lookupInfoNFKC
-		} else {
-			f.info = lookupInfoNFC
-		}
-		f.nextMain = nextDecomposed
-		if Form(i) == NFC || Form(i) == NFKC {
-			f.nextMain = nextComposed
-			f.composing = true
-		}
-	}
-}
+var formTable = []*formInfo{{
+	form:          NFC,
+	composing:     true,
+	compatibility: false,
+	info:          lookupInfoNFC,
+	nextMain:      nextComposed,
+}, {
+	form:          NFD,
+	composing:     false,
+	compatibility: false,
+	info:          lookupInfoNFC,
+	nextMain:      nextDecomposed,
+}, {
+	form:          NFKC,
+	composing:     true,
+	compatibility: true,
+	info:          lookupInfoNFKC,
+	nextMain:      nextComposed,
+}, {
+	form:          NFKD,
+	composing:     false,
+	compatibility: true,
+	info:          lookupInfoNFKC,
+	nextMain:      nextDecomposed,
+}}
 
 // We do not distinguish between boundaries for NFC, NFD, etc. to avoid
 // unexpected behavior for the user.  For example, in NFD, there is a boundary
diff --git a/src/vendor/golang_org/x/text/unicode/norm/input.go b/src/vendor/golang_org/x/text/unicode/norm/input.go
index 045d4cc..202bde1 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/input.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/input.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/unicode/norm/iter.go b/src/vendor/golang_org/x/text/unicode/norm/iter.go
index 0a42a72..c0cf949 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/iter.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/iter.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/unicode/norm/normalize.go b/src/vendor/golang_org/x/text/unicode/norm/normalize.go
index 15c962e..4427ee3 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/normalize.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/normalize.go
@@ -1,12 +1,13 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go 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 maketables.go triegen.go
-//go:generate go run maketables.go triegen.go -test
+// Note: the file data_test.go that is generated should not be checked in.
 
 // Package norm contains types and functions for normalizing Unicode strings.
-package norm // import "golang.org/x/text/unicode/norm"
+package norm // import "golang_org/x/text/unicode/norm"
 
 import (
 	"unicode/utf8"
diff --git a/src/vendor/golang_org/x/text/unicode/norm/readwriter.go b/src/vendor/golang_org/x/text/unicode/norm/readwriter.go
index d926ee9..482ac85 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/readwriter.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/readwriter.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/unicode/norm/tables.go b/src/vendor/golang_org/x/text/unicode/norm/tables.go
index a56697b..ac99519 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/tables.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/tables.go
@@ -1,4 +1,6 @@
-// This file was generated by go generate; DO NOT EDIT
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
+// Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT.
 
 package norm
 
@@ -27,14 +29,14 @@ const (
 	firstMulti            = 0x186D
 	firstCCC              = 0x2C9E
 	endMulti              = 0x2F60
-	firstLeadingCCC       = 0x4A44
-	firstCCCZeroExcept    = 0x4A5A
-	firstStarterWithNLead = 0x4A81
-	lastDecomp            = 0x4A83
+	firstLeadingCCC       = 0x49AE
+	firstCCCZeroExcept    = 0x4A78
+	firstStarterWithNLead = 0x4A9F
+	lastDecomp            = 0x4AA1
 	maxDecomp             = 0x8000
 )
 
-// decomps: 19075 bytes
+// decomps: 19105 bytes
 var decomps = [...]byte{
 	// Bytes 0 - 3f
 	0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41,
@@ -2443,283 +2445,287 @@ var decomps = [...]byte{
 	0xD9, 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D,
 	0x43, 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9,
 	0x92, 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43,
-	0x73, 0xCC, 0x87, 0xC9, 0x43, 0xE1, 0x85, 0xA1,
-	0x01, 0x43, 0xE1, 0x85, 0xA2, 0x01, 0x43, 0xE1,
-	0x85, 0xA3, 0x01, 0x43, 0xE1, 0x85, 0xA4, 0x01,
-	0x43, 0xE1, 0x85, 0xA5, 0x01, 0x43, 0xE1, 0x85,
-	0xA6, 0x01, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x43,
+	0x73, 0xCC, 0x87, 0xC9, 0x44, 0x20, 0xE3, 0x82,
+	0x99, 0x0D, 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D,
+	0x44, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE,
+	0x91, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC,
+	0x81, 0xC9, 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9,
 	// Bytes 4300 - 433f
-	0xE1, 0x85, 0xA8, 0x01, 0x43, 0xE1, 0x85, 0xA9,
-	0x01, 0x43, 0xE1, 0x85, 0xAA, 0x01, 0x43, 0xE1,
-	0x85, 0xAB, 0x01, 0x43, 0xE1, 0x85, 0xAC, 0x01,
-	0x43, 0xE1, 0x85, 0xAD, 0x01, 0x43, 0xE1, 0x85,
-	0xAE, 0x01, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x43,
-	0xE1, 0x85, 0xB0, 0x01, 0x43, 0xE1, 0x85, 0xB1,
-	0x01, 0x43, 0xE1, 0x85, 0xB2, 0x01, 0x43, 0xE1,
-	0x85, 0xB3, 0x01, 0x43, 0xE1, 0x85, 0xB4, 0x01,
+	0x44, 0xCE, 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
+	0x9F, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC,
+	0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9,
+	0x44, 0xCE, 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
+	0xB1, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC,
+	0x81, 0xC9, 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9,
+	0x44, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
+	0xBF, 0xCC, 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC,
 	// Bytes 4340 - 437f
-	0x43, 0xE1, 0x85, 0xB5, 0x01, 0x43, 0xE1, 0x86,
-	0xAA, 0x01, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x43,
-	0xE1, 0x86, 0xAD, 0x01, 0x43, 0xE1, 0x86, 0xB0,
-	0x01, 0x43, 0xE1, 0x86, 0xB1, 0x01, 0x43, 0xE1,
-	0x86, 0xB2, 0x01, 0x43, 0xE1, 0x86, 0xB3, 0x01,
-	0x43, 0xE1, 0x86, 0xB4, 0x01, 0x43, 0xE1, 0x86,
-	0xB5, 0x01, 0x44, 0x20, 0xE3, 0x82, 0x99, 0x0D,
-	0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, 0x44, 0xC2,
+	0x81, 0xC9, 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9,
+	0x44, 0xD7, 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7,
+	0x90, 0xD6, 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41,
+	0x44, 0xD7, 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7,
+	0x92, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41,
+	0x44, 0xD7, 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7,
 	// Bytes 4380 - 43bf
-	0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, 0x91, 0xCC,
-	0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, 0x81, 0xC9,
-	0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
-	0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x9F, 0xCC,
-	0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x81, 0xC9,
-	0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x44, 0xCE,
-	0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB1, 0xCC,
-	0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, 0x81, 0xC9,
+	0x95, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41,
+	0x44, 0xD7, 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7,
+	0x99, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41,
+	0x44, 0xD7, 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7,
+	0x9C, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41,
 	// Bytes 43c0 - 43ff
-	0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
-	0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xBF, 0xCC,
-	0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, 0x81, 0xC9,
-	0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, 0x44, 0xD7,
-	0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, 0x90, 0xD6,
-	0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
-	0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x92, 0xD6,
+	0x44, 0xD7, 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+	0xA3, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49,
+	0x44, 0xD7, 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+	0xA7, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6,
+	0xBC, 0x41, 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41,
+	0x44, 0xD7, 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7,
+	0xA9, 0xD7, 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6,
 	// Bytes 4400 - 443f
-	0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
-	0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, 0x95, 0xD6,
-	0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
-	0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, 0x99, 0xD6,
-	0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
+	0xBC, 0x41, 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31,
+	0x44, 0xD8, 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8,
+	0xA7, 0xD9, 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9,
+	0x94, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5,
+	0x44, 0xD8, 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8,
+	0xB1, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9,
+	0x8B, 0x59, 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65,
+	0x44, 0xD9, 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9,
 	// Bytes 4440 - 447f
-	0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x9C, 0xD6,
-	0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
-	0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA3, 0xD6,
-	0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, 0x44, 0xD7,
-	0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA7, 0xD6,
-	0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, 0xBC, 0x41,
+	0x80, 0xD9, 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9,
+	0x91, 0x71, 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75,
+	0x44, 0xD9, 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9,
+	0x88, 0xD9, 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9,
+	0xB0, 0x79, 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9,
+	0x44, 0xDB, 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB,
+	0x95, 0xD9, 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88,
+	0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC,
 	// Bytes 4480 - 44bf
-	0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
-	0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, 0xA9, 0xD7,
-	0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, 0xBC, 0x41,
-	0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, 0x44, 0xD8,
-	0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, 0xA7, 0xD9,
-	0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
-	0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x44, 0xD8,
-	0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, 0xB1, 0xD9,
+	0x81, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82,
+	0xCA, 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+	0x45, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45,
+	0x20, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20,
+	0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC,
+	0x94, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94,
+	0xCD, 0x82, 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9,
+	0x91, 0x72, 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91,
 	// Bytes 44c0 - 44ff
-	0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, 0x8B, 0x59,
-	0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, 0x44, 0xD9,
-	0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, 0x80, 0xD9,
-	0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, 0x91, 0x71,
-	0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, 0x44, 0xD9,
-	0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x88, 0xD9,
-	0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, 0xB0, 0x79,
-	0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x44, 0xDB,
+	0x72, 0x45, 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72,
+	0x45, 0x20, 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45,
+	0x20, 0xD9, 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20,
+	0xD9, 0x91, 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB,
+	0x9D, 0xCC, 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC,
+	0x88, 0xCC, 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC,
+	0x88, 0xCC, 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6,
+	0xBC, 0xD7, 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6,
 	// Bytes 4500 - 453f
-	0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, 0x95, 0xD9,
-	0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x80,
-	0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
-	0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xCA, 0x45,
-	0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x45, 0x20,
-	0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xCC, 0x94,
-	0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCC,
+	0xBC, 0xD7, 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9,
+	0x8E, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9,
+	0x8F, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9,
+	0x90, 0xD9, 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1,
 	// Bytes 4540 - 457f
-	0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCD, 0x82,
-	0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x72,
-	0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, 0x72, 0x45,
-	0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, 0x45, 0x20,
-	0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9,
-	0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, 0x91,
-	0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, 0x9D, 0xCC,
-	0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF,
+	0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1,
+	0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2,
+	0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF,
+	0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97,
 	// Bytes 4580 - 45bf
-	0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
-	0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
-	0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
-	0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, 0x8E, 0xD9,
-	0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x8F, 0xD9,
-	0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x90, 0xD9,
-	0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, 0xE0, 0xA4,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8,
+	0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1,
+	0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2,
+	0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2,
+	0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3,
 	// Bytes 45c0 - 45ff
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4,
-	0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, 0xE0, 0xA6,
-	0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6,
+	0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86,
+	0xE3, 0x82, 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85,
+	0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0,
+	0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD,
+	0x48, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85,
+	0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+	0x9D, 0x85, 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2,
+	0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49,
 	// Bytes 4600 - 463f
-	0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8,
-	0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC,
-	// Bytes 4640 - 467f
-	0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC,
-	0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, 0xE0, 0xBE,
-	0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE,
-	0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, 0xE3, 0x82,
-	0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, 0x97, 0xF0,
-	0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x85,
-	0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0,
-	0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xAD,
-	// Bytes 4680 - 46bf
-	0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
-	0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
-	0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, 0xE0, 0xBE,
-	0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
+	0xE0, 0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE,
+	0x80, 0x9E, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+	0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE,
 	0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
-	0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0,
+	0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0,
 	0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
-	0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x85,
-	// Bytes 46c0 - 46ff
+	0x9D, 0x85, 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85,
 	0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
-	0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
-	0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0xAE,
-	0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
-	0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, 0x4C, 0xF0,
+	// Bytes 4640 - 467f
+	0xB1, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+	0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE,
+	0x4C, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85,
+	0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0,
 	0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
-	0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86,
-	0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+	0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86,
+	0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+	0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+	// Bytes 4680 - 46bf
+	0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE,
+	0x83, 0x41, 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC,
+	0x86, 0xC9, 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83,
+	0x41, 0xCC, 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A,
+	0xC9, 0x83, 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43,
+	0xCC, 0xA7, 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9,
+	0x83, 0x45, 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC,
+	0xA3, 0xB5, 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83,
+	// Bytes 46c0 - 46ff
+	0x49, 0xCC, 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3,
+	0xB5, 0x83, 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F,
+	0xCC, 0x83, 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9,
+	0x83, 0x4F, 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC,
+	0x88, 0xC9, 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83,
+	0x4F, 0xCC, 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8,
+	0xA5, 0x83, 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53,
+	0xCC, 0x81, 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9,
 	// Bytes 4700 - 473f
-	0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
-	0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE,
-	0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
-	0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x83, 0x41,
-	0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, 0x86, 0xC9,
-	0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, 0x41, 0xCC,
-	0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, 0xC9, 0x83,
-	0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, 0xCC, 0xA7,
+	0x83, 0x53, 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC,
+	0x83, 0xC9, 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83,
+	0x55, 0xCC, 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B,
+	0xAD, 0x83, 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61,
+	0xCC, 0x86, 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9,
+	0x83, 0x61, 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC,
+	0x8A, 0xC9, 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83,
+	0x63, 0xCC, 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82,
 	// Bytes 4740 - 477f
-	0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, 0x83, 0x45,
-	0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, 0xA3, 0xB5,
-	0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, 0x49, 0xCC,
-	0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, 0xB5, 0x83,
-	0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, 0xCC, 0x83,
-	0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, 0x83, 0x4F,
-	0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, 0x88, 0xC9,
-	0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, 0x4F, 0xCC,
+	0xC9, 0x83, 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65,
+	0xCC, 0xA3, 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5,
+	0x83, 0x69, 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC,
+	0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83,
+	0x6F, 0xCC, 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84,
+	0xC9, 0x83, 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F,
+	0xCC, 0x88, 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD,
+	0x83, 0x6F, 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC,
 	// Bytes 4780 - 47bf
-	0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, 0xA5, 0x83,
-	0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, 0xCC, 0x81,
-	0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, 0x83, 0x53,
-	0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, 0x83, 0xC9,
-	0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, 0x55, 0xCC,
-	0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, 0xAD, 0x83,
-	0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, 0xCC, 0x86,
-	0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, 0x83, 0x61,
+	0xA8, 0xA5, 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83,
+	0x73, 0xCC, 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C,
+	0xC9, 0x83, 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75,
+	0xCC, 0x83, 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9,
+	0x83, 0x75, 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC,
+	0x9B, 0xAD, 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9,
+	0x84, 0xCE, 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
+	0x95, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC,
 	// Bytes 47c0 - 47ff
-	0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, 0x8A, 0xC9,
-	0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, 0x63, 0xCC,
-	0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, 0xC9, 0x83,
-	0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, 0xCC, 0xA3,
-	0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, 0x83, 0x69,
-	0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, 0xA3, 0xB5,
-	0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, 0x6F, 0xCC,
-	0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, 0xC9, 0x83,
+	0x94, 0xC9, 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9,
+	0x84, 0xCE, 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
+	0x99, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC,
+	0x94, 0xC9, 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9,
+	0x84, 0xCE, 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
+	0xA5, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC,
+	0x93, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9,
+	0x84, 0xCE, 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE,
 	// Bytes 4800 - 483f
-	0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, 0xCC, 0x88,
-	0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, 0x83, 0x6F,
-	0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0xA8, 0xA5,
-	0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, 0x73, 0xCC,
-	0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, 0xC9, 0x83,
-	0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, 0xCC, 0x83,
-	0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, 0x83, 0x75,
-	0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, 0x9B, 0xAD,
+	0xB1, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC,
+	0x93, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9,
+	0x84, 0xCE, 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE,
+	0xB5, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC,
+	0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9,
+	0x84, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE,
+	0xB7, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC,
+	0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9,
 	// Bytes 4840 - 487f
-	0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
-	0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x95, 0xCC,
-	0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, 0x94, 0xC9,
-	0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
-	0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x99, 0xCC,
-	0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, 0x94, 0xC9,
-	0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
-	0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA5, 0xCC,
+	0x84, 0xCE, 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE,
+	0xB9, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC,
+	0x94, 0xC9, 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9,
+	0x84, 0xCE, 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
+	0x85, 0xCC, 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC,
+	0x93, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9,
+	0x84, 0xCF, 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF,
+	0x89, 0xCC, 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC,
 	// Bytes 4880 - 48bf
-	0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x93, 0xC9,
-	0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
-	0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, 0xB1, 0xCC,
-	0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x93, 0xC9,
-	0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
-	0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, 0xB5, 0xCC,
-	0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, 0x94, 0xC9,
-	0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, 0x84, 0xCE,
+	0x93, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9,
+	0x84, 0xCF, 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE,
+	0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0x91, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
 	// Bytes 48c0 - 48ff
-	0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB7, 0xCC,
-	0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x94, 0xC9,
-	0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, 0x84, 0xCE,
-	0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, 0xB9, 0xCC,
-	0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x94, 0xC9,
-	0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
-	0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x85, 0xCC,
-	0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x93, 0xC9,
+	0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
 	// Bytes 4900 - 493f
-	0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
-	0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, 0x89, 0xCC,
-	0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x93, 0xC9,
-	0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
-	0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, 0x91, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
+	0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xB1, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
 	// Bytes 4940 - 497f
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
-	0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
+	0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE,
+	0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF,
 	// Bytes 4980 - 49bf
-	0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
-	0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
+	0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF,
+	0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF,
+	0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF,
+	0x89, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF,
+	0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF,
+	0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC,
+	0x80, 0xC9, 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32,
+	0x42, 0xCC, 0x93, 0xC9, 0x32, 0x43, 0xE1, 0x85,
 	// Bytes 49c0 - 49ff
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
-	0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
+	0xA1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA2, 0x01,
+	0x00, 0x43, 0xE1, 0x85, 0xA3, 0x01, 0x00, 0x43,
+	0xE1, 0x85, 0xA4, 0x01, 0x00, 0x43, 0xE1, 0x85,
+	0xA5, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA6, 0x01,
+	0x00, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x00, 0x43,
+	0xE1, 0x85, 0xA8, 0x01, 0x00, 0x43, 0xE1, 0x85,
+	0xA9, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAA, 0x01,
+	0x00, 0x43, 0xE1, 0x85, 0xAB, 0x01, 0x00, 0x43,
 	// Bytes 4a00 - 4a3f
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
-	0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
-	0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
-	0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
-	0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
-	0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
-	0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
+	0xE1, 0x85, 0xAC, 0x01, 0x00, 0x43, 0xE1, 0x85,
+	0xAD, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAE, 0x01,
+	0x00, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x00, 0x43,
+	0xE1, 0x85, 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x85,
+	0xB1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xB2, 0x01,
+	0x00, 0x43, 0xE1, 0x85, 0xB3, 0x01, 0x00, 0x43,
+	0xE1, 0x85, 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x85,
+	0xB5, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xAA, 0x01,
 	// Bytes 4a40 - 4a7f
-	0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, 0x80, 0xC9,
-	0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, 0x42, 0xCC,
-	0x93, 0xC9, 0x32, 0x44, 0xCC, 0x88, 0xCC, 0x81,
-	0xCA, 0x32, 0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03,
-	0x43, 0xE3, 0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0,
-	0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46,
-	0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26,
-	0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
+	0x00, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x00, 0x43,
+	0xE1, 0x86, 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x86,
+	0xB0, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB1, 0x01,
+	0x00, 0x43, 0xE1, 0x86, 0xB2, 0x01, 0x00, 0x43,
+	0xE1, 0x86, 0xB3, 0x01, 0x00, 0x43, 0xE1, 0x86,
+	0xB4, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB5, 0x01,
+	0x00, 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x32,
+	0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03, 0x43, 0xE3,
 	// Bytes 4a80 - 4abf
-	0x26, 0x00, 0x01,
+	0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0, 0xBD, 0xB1,
+	0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46, 0xE0, 0xBD,
+	0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26, 0x46, 0xE0,
+	0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x26, 0x00,
+	0x01,
 }
 
 // lookup returns the trie value for the first UTF-8 encoding in s and
@@ -2892,7 +2898,7 @@ func (t *nfcTrie) lookupStringUnsafe(s string) uint16 {
 	return 0
 }
 
-// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: ad355b768fddb1b6.
+// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: 51cc525b297fc970.
 type nfcTrie struct{}
 
 func newNfcTrie(i int) *nfcTrie {
@@ -2928,22 +2934,22 @@ var nfcValues = [2944]uint16{
 	0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
 	// Block 0x2, offset 0x80
 	// Block 0x3, offset 0xc0
-	0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
-	0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
-	0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
-	0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
-	0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
-	0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
-	0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
-	0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
-	0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
-	0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
-	0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
+	0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c,
+	0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb,
+	0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104,
+	0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd,
+	0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235,
+	0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285,
+	0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3,
+	0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750,
+	0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f,
+	0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
+	0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569,
 	// Block 0x4, offset 0x100
-	0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
+	0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8,
 	0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
 	0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
-	0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
+	0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
 	0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
 	0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
 	0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
@@ -2954,12 +2960,12 @@ var nfcValues = [2944]uint16{
 	// Block 0x5, offset 0x140
 	0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
 	0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f,
-	0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
+	0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
 	0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
-	0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
-	0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
-	0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
-	0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
+	0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d,
+	0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba,
+	0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796,
+	0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
 	0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
 	0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
 	0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0xa000,
@@ -2971,7 +2977,7 @@ var nfcValues = [2944]uint16{
 	0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
 	0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
 	0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
-	0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
+	0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
 	0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334,
 	0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
 	0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
@@ -2982,8 +2988,8 @@ var nfcValues = [2944]uint16{
 	0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
 	0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
 	0x1de: 0x305a, 0x1df: 0x3366,
-	0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
-	0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
+	0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b,
+	0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769,
 	0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
 	// Block 0x8, offset 0x200
 	0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
@@ -2998,7 +3004,7 @@ var nfcValues = [2944]uint16{
 	0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
 	0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
 	// Block 0x9, offset 0x240
-	0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
+	0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936,
 	0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
 	0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
 	0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
@@ -3017,7 +3023,7 @@ var nfcValues = [2944]uint16{
 	0x299: 0xa000,
 	0x29f: 0xa000, 0x2a1: 0xa000,
 	0x2a5: 0xa000, 0x2a9: 0xa000,
-	0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
+	0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9,
 	0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
 	0x2b7: 0xa000, 0x2b9: 0xa000,
 	0x2bf: 0xa000,
@@ -3078,15 +3084,15 @@ var nfcValues = [2944]uint16{
 	0x424: 0x305f, 0x425: 0x336b, 0x426: 0x3055, 0x427: 0x3361, 0x428: 0x3064, 0x429: 0x3370,
 	0x42a: 0x3069, 0x42b: 0x3375, 0x42c: 0x30af, 0x42d: 0x33bb, 0x42e: 0x390b, 0x42f: 0x3a9a,
 	0x430: 0x30b9, 0x431: 0x33ca, 0x432: 0x30c3, 0x433: 0x33d4, 0x434: 0x30cd, 0x435: 0x33de,
-	0x436: 0x475a, 0x437: 0x47eb, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7,
+	0x436: 0x46c4, 0x437: 0x4755, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7,
 	0x43c: 0x30e1, 0x43d: 0x33f2, 0x43e: 0x30eb, 0x43f: 0x33fc,
 	// Block 0x11, offset 0x440
 	0x440: 0x30f0, 0x441: 0x3401, 0x442: 0x30f5, 0x443: 0x3406, 0x444: 0x3109, 0x445: 0x341a,
 	0x446: 0x3113, 0x447: 0x3424, 0x448: 0x3122, 0x449: 0x3433, 0x44a: 0x311d, 0x44b: 0x342e,
 	0x44c: 0x3935, 0x44d: 0x3ac4, 0x44e: 0x3943, 0x44f: 0x3ad2, 0x450: 0x394a, 0x451: 0x3ad9,
 	0x452: 0x3951, 0x453: 0x3ae0, 0x454: 0x314f, 0x455: 0x3460, 0x456: 0x3154, 0x457: 0x3465,
-	0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x4787, 0x45b: 0x4818, 0x45c: 0x3997, 0x45d: 0x3b26,
-	0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4796, 0x463: 0x4827,
+	0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x46f1, 0x45b: 0x4782, 0x45c: 0x3997, 0x45d: 0x3b26,
+	0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4700, 0x463: 0x4791,
 	0x464: 0x399e, 0x465: 0x3b2d, 0x466: 0x39a5, 0x467: 0x3b34, 0x468: 0x39ac, 0x469: 0x3b3b,
 	0x46a: 0x3190, 0x46b: 0x34a1, 0x46c: 0x319a, 0x46d: 0x34b0, 0x46e: 0x31ae, 0x46f: 0x34c4,
 	0x470: 0x31a9, 0x471: 0x34bf, 0x472: 0x31ea, 0x473: 0x3500, 0x474: 0x31f9, 0x475: 0x350f,
@@ -3098,16 +3104,16 @@ var nfcValues = [2944]uint16{
 	0x48c: 0x322b, 0x48d: 0x3546, 0x48e: 0x3249, 0x48f: 0x3564, 0x490: 0x3262, 0x491: 0x3582,
 	0x492: 0x3271, 0x493: 0x3591, 0x494: 0x3276, 0x495: 0x3596, 0x496: 0x337a, 0x497: 0x34a6,
 	0x498: 0x3537, 0x499: 0x3573, 0x49b: 0x35d1,
-	0x4a0: 0x4737, 0x4a1: 0x47c8, 0x4a2: 0x2f83, 0x4a3: 0x328f,
+	0x4a0: 0x46a1, 0x4a1: 0x4732, 0x4a2: 0x2f83, 0x4a3: 0x328f,
 	0x4a4: 0x3878, 0x4a5: 0x3a07, 0x4a6: 0x3871, 0x4a7: 0x3a00, 0x4a8: 0x3886, 0x4a9: 0x3a15,
 	0x4aa: 0x387f, 0x4ab: 0x3a0e, 0x4ac: 0x38be, 0x4ad: 0x3a4d, 0x4ae: 0x3894, 0x4af: 0x3a23,
 	0x4b0: 0x388d, 0x4b1: 0x3a1c, 0x4b2: 0x38a2, 0x4b3: 0x3a31, 0x4b4: 0x389b, 0x4b5: 0x3a2a,
-	0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x474b, 0x4b9: 0x47dc, 0x4ba: 0x3000, 0x4bb: 0x330c,
+	0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x46b5, 0x4b9: 0x4746, 0x4ba: 0x3000, 0x4bb: 0x330c,
 	0x4bc: 0x2fec, 0x4bd: 0x32f8, 0x4be: 0x38da, 0x4bf: 0x3a69,
 	// Block 0x13, offset 0x4c0
 	0x4c0: 0x38d3, 0x4c1: 0x3a62, 0x4c2: 0x38e8, 0x4c3: 0x3a77, 0x4c4: 0x38e1, 0x4c5: 0x3a70,
 	0x4c6: 0x38fd, 0x4c7: 0x3a8c, 0x4c8: 0x3091, 0x4c9: 0x339d, 0x4ca: 0x30a5, 0x4cb: 0x33b1,
-	0x4cc: 0x477d, 0x4cd: 0x480e, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf,
+	0x4cc: 0x46e7, 0x4cd: 0x4778, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf,
 	0x4d2: 0x3919, 0x4d3: 0x3aa8, 0x4d4: 0x392e, 0x4d5: 0x3abd, 0x4d6: 0x3927, 0x4d7: 0x3ab6,
 	0x4d8: 0x3989, 0x4d9: 0x3b18, 0x4da: 0x396d, 0x4db: 0x3afc, 0x4dc: 0x3966, 0x4dd: 0x3af5,
 	0x4de: 0x397b, 0x4df: 0x3b0a, 0x4e0: 0x3974, 0x4e1: 0x3b03, 0x4e2: 0x3982, 0x4e3: 0x3b11,
@@ -3116,29 +3122,29 @@ var nfcValues = [2944]uint16{
 	0x4f0: 0x39f9, 0x4f1: 0x3b88, 0x4f2: 0x3230, 0x4f3: 0x354b, 0x4f4: 0x3258, 0x4f5: 0x3578,
 	0x4f6: 0x3253, 0x4f7: 0x356e, 0x4f8: 0x323f, 0x4f9: 0x355a,
 	// Block 0x14, offset 0x500
-	0x500: 0x489a, 0x501: 0x48a0, 0x502: 0x49b4, 0x503: 0x49cc, 0x504: 0x49bc, 0x505: 0x49d4,
-	0x506: 0x49c4, 0x507: 0x49dc, 0x508: 0x4840, 0x509: 0x4846, 0x50a: 0x4924, 0x50b: 0x493c,
-	0x50c: 0x492c, 0x50d: 0x4944, 0x50e: 0x4934, 0x50f: 0x494c, 0x510: 0x48ac, 0x511: 0x48b2,
+	0x500: 0x4804, 0x501: 0x480a, 0x502: 0x491e, 0x503: 0x4936, 0x504: 0x4926, 0x505: 0x493e,
+	0x506: 0x492e, 0x507: 0x4946, 0x508: 0x47aa, 0x509: 0x47b0, 0x50a: 0x488e, 0x50b: 0x48a6,
+	0x50c: 0x4896, 0x50d: 0x48ae, 0x50e: 0x489e, 0x50f: 0x48b6, 0x510: 0x4816, 0x511: 0x481c,
 	0x512: 0x3db8, 0x513: 0x3dc8, 0x514: 0x3dc0, 0x515: 0x3dd0,
-	0x518: 0x484c, 0x519: 0x4852, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00,
-	0x520: 0x48c4, 0x521: 0x48ca, 0x522: 0x49e4, 0x523: 0x49fc,
-	0x524: 0x49ec, 0x525: 0x4a04, 0x526: 0x49f4, 0x527: 0x4a0c, 0x528: 0x4858, 0x529: 0x485e,
-	0x52a: 0x4954, 0x52b: 0x496c, 0x52c: 0x495c, 0x52d: 0x4974, 0x52e: 0x4964, 0x52f: 0x497c,
-	0x530: 0x48dc, 0x531: 0x48e2, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38,
-	0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x4864, 0x539: 0x486a, 0x53a: 0x3d18, 0x53b: 0x3d30,
+	0x518: 0x47b6, 0x519: 0x47bc, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00,
+	0x520: 0x482e, 0x521: 0x4834, 0x522: 0x494e, 0x523: 0x4966,
+	0x524: 0x4956, 0x525: 0x496e, 0x526: 0x495e, 0x527: 0x4976, 0x528: 0x47c2, 0x529: 0x47c8,
+	0x52a: 0x48be, 0x52b: 0x48d6, 0x52c: 0x48c6, 0x52d: 0x48de, 0x52e: 0x48ce, 0x52f: 0x48e6,
+	0x530: 0x4846, 0x531: 0x484c, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38,
+	0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x47ce, 0x539: 0x47d4, 0x53a: 0x3d18, 0x53b: 0x3d30,
 	0x53c: 0x3d20, 0x53d: 0x3d38, 0x53e: 0x3d28, 0x53f: 0x3d40,
 	// Block 0x15, offset 0x540
-	0x540: 0x48e8, 0x541: 0x48ee, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60,
-	0x548: 0x4870, 0x549: 0x4876, 0x54a: 0x3d48, 0x54b: 0x3d58,
-	0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x48fa, 0x551: 0x4900,
+	0x540: 0x4852, 0x541: 0x4858, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60,
+	0x548: 0x47da, 0x549: 0x47e0, 0x54a: 0x3d48, 0x54b: 0x3d58,
+	0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x4864, 0x551: 0x486a,
 	0x552: 0x3e80, 0x553: 0x3e98, 0x554: 0x3e88, 0x555: 0x3ea0, 0x556: 0x3e90, 0x557: 0x3ea8,
-	0x559: 0x487c, 0x55b: 0x3d68, 0x55d: 0x3d70,
-	0x55f: 0x3d78, 0x560: 0x4912, 0x561: 0x4918, 0x562: 0x4a14, 0x563: 0x4a2c,
-	0x564: 0x4a1c, 0x565: 0x4a34, 0x566: 0x4a24, 0x567: 0x4a3c, 0x568: 0x4882, 0x569: 0x4888,
-	0x56a: 0x4984, 0x56b: 0x499c, 0x56c: 0x498c, 0x56d: 0x49a4, 0x56e: 0x4994, 0x56f: 0x49ac,
-	0x570: 0x488e, 0x571: 0x43b4, 0x572: 0x3691, 0x573: 0x43ba, 0x574: 0x48b8, 0x575: 0x43c0,
-	0x576: 0x36a3, 0x577: 0x43c6, 0x578: 0x36c1, 0x579: 0x43cc, 0x57a: 0x36d9, 0x57b: 0x43d2,
-	0x57c: 0x4906, 0x57d: 0x43d8,
+	0x559: 0x47e6, 0x55b: 0x3d68, 0x55d: 0x3d70,
+	0x55f: 0x3d78, 0x560: 0x487c, 0x561: 0x4882, 0x562: 0x497e, 0x563: 0x4996,
+	0x564: 0x4986, 0x565: 0x499e, 0x566: 0x498e, 0x567: 0x49a6, 0x568: 0x47ec, 0x569: 0x47f2,
+	0x56a: 0x48ee, 0x56b: 0x4906, 0x56c: 0x48f6, 0x56d: 0x490e, 0x56e: 0x48fe, 0x56f: 0x4916,
+	0x570: 0x47f8, 0x571: 0x431e, 0x572: 0x3691, 0x573: 0x4324, 0x574: 0x4822, 0x575: 0x432a,
+	0x576: 0x36a3, 0x577: 0x4330, 0x578: 0x36c1, 0x579: 0x4336, 0x57a: 0x36d9, 0x57b: 0x433c,
+	0x57c: 0x4870, 0x57d: 0x4342,
 	// Block 0x16, offset 0x580
 	0x580: 0x3da0, 0x581: 0x3da8, 0x582: 0x4184, 0x583: 0x41a2, 0x584: 0x418e, 0x585: 0x41ac,
 	0x586: 0x4198, 0x587: 0x41b6, 0x588: 0x3cd8, 0x589: 0x3ce0, 0x58a: 0x40d0, 0x58b: 0x40ee,
@@ -3149,19 +3155,19 @@ var nfcValues = [2944]uint16{
 	0x5a4: 0x4206, 0x5a5: 0x4224, 0x5a6: 0x4210, 0x5a7: 0x422e, 0x5a8: 0x3d80, 0x5a9: 0x3d88,
 	0x5aa: 0x4148, 0x5ab: 0x4166, 0x5ac: 0x4152, 0x5ad: 0x4170, 0x5ae: 0x415c, 0x5af: 0x417a,
 	0x5b0: 0x3685, 0x5b1: 0x367f, 0x5b2: 0x3d90, 0x5b3: 0x368b, 0x5b4: 0x3d98,
-	0x5b6: 0x48a6, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x4384,
+	0x5b6: 0x4810, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x42ee,
 	0x5bc: 0x35fb, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100,
 	// Block 0x17, offset 0x5c0
 	0x5c0: 0x8100, 0x5c1: 0x35a7, 0x5c2: 0x3dd8, 0x5c3: 0x369d, 0x5c4: 0x3de0,
-	0x5c6: 0x48d0, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x438a, 0x5ca: 0x360d, 0x5cb: 0x4390,
+	0x5c6: 0x483a, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x42f4, 0x5ca: 0x360d, 0x5cb: 0x42fa,
 	0x5cc: 0x3619, 0x5cd: 0x3b8f, 0x5ce: 0x3b96, 0x5cf: 0x3b9d, 0x5d0: 0x36b5, 0x5d1: 0x36af,
-	0x5d2: 0x3e00, 0x5d3: 0x457a, 0x5d6: 0x36bb, 0x5d7: 0x3e10,
-	0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4396, 0x5dd: 0x3ba4,
-	0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x4582,
+	0x5d2: 0x3e00, 0x5d3: 0x44e4, 0x5d6: 0x36bb, 0x5d7: 0x3e10,
+	0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4300, 0x5dd: 0x3ba4,
+	0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x44ec,
 	0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b,
-	0x5ea: 0x364f, 0x5eb: 0x43a2, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x437e, 0x5ef: 0x0081,
+	0x5ea: 0x364f, 0x5eb: 0x430c, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x42e8, 0x5ef: 0x0081,
 	0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8,
-	0x5f6: 0x491e, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x439c, 0x5fa: 0x366d, 0x5fb: 0x43ae,
+	0x5f6: 0x4888, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x4306, 0x5fa: 0x366d, 0x5fb: 0x4318,
 	0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100,
 	// Block 0x18, offset 0x600
 	0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000,
@@ -3519,8 +3525,8 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x8100, lo: 0xb8, hi: 0xb8},
 	// Block 0x1, offset 0x5
 	{value: 0x0091, lo: 0x03},
-	{value: 0x4778, lo: 0xa0, hi: 0xa1},
-	{value: 0x47aa, lo: 0xaf, hi: 0xb0},
+	{value: 0x46e2, lo: 0xa0, hi: 0xa1},
+	{value: 0x4714, lo: 0xaf, hi: 0xb0},
 	{value: 0xa000, lo: 0xb7, hi: 0xb7},
 	// Block 0x2, offset 0x9
 	{value: 0x0000, lo: 0x01},
@@ -3533,11 +3539,11 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0xa000, lo: 0x81, hi: 0x81},
 	{value: 0xa000, lo: 0x85, hi: 0x85},
 	{value: 0xa000, lo: 0x89, hi: 0x89},
-	{value: 0x48d6, lo: 0x8a, hi: 0x8a},
-	{value: 0x48f4, lo: 0x8b, hi: 0x8b},
+	{value: 0x4840, lo: 0x8a, hi: 0x8a},
+	{value: 0x485e, lo: 0x8b, hi: 0x8b},
 	{value: 0x36c7, lo: 0x8c, hi: 0x8c},
 	{value: 0x36df, lo: 0x8d, hi: 0x8d},
-	{value: 0x490c, lo: 0x8e, hi: 0x8e},
+	{value: 0x4876, lo: 0x8e, hi: 0x8e},
 	{value: 0xa000, lo: 0x92, hi: 0x92},
 	{value: 0x36fd, lo: 0x93, hi: 0x94},
 	// Block 0x5, offset 0x18
@@ -3665,7 +3671,7 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x812d, lo: 0x92, hi: 0x92},
 	{value: 0x8132, lo: 0x93, hi: 0x93},
 	{value: 0x8132, lo: 0x94, hi: 0x94},
-	{value: 0x45b2, lo: 0x98, hi: 0x9f},
+	{value: 0x451c, lo: 0x98, hi: 0x9f},
 	// Block 0x12, offset 0x89
 	{value: 0x0000, lo: 0x02},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
@@ -3676,18 +3682,18 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x2c9e, lo: 0x8b, hi: 0x8c},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
 	{value: 0x9900, lo: 0x97, hi: 0x97},
-	{value: 0x45f2, lo: 0x9c, hi: 0x9d},
-	{value: 0x4602, lo: 0x9f, hi: 0x9f},
+	{value: 0x455c, lo: 0x9c, hi: 0x9d},
+	{value: 0x456c, lo: 0x9f, hi: 0x9f},
 	// Block 0x14, offset 0x93
 	{value: 0x0000, lo: 0x03},
-	{value: 0x462a, lo: 0xb3, hi: 0xb3},
-	{value: 0x4632, lo: 0xb6, hi: 0xb6},
+	{value: 0x4594, lo: 0xb3, hi: 0xb3},
+	{value: 0x459c, lo: 0xb6, hi: 0xb6},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
 	// Block 0x15, offset 0x97
 	{value: 0x0008, lo: 0x03},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
-	{value: 0x460a, lo: 0x99, hi: 0x9b},
-	{value: 0x4622, lo: 0x9e, hi: 0x9e},
+	{value: 0x4574, lo: 0x99, hi: 0x9b},
+	{value: 0x458c, lo: 0x9e, hi: 0x9e},
 	// Block 0x16, offset 0x9b
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
@@ -3702,8 +3708,8 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x2cbe, lo: 0x8c, hi: 0x8c},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
 	{value: 0x9900, lo: 0x96, hi: 0x97},
-	{value: 0x463a, lo: 0x9c, hi: 0x9c},
-	{value: 0x4642, lo: 0x9d, hi: 0x9d},
+	{value: 0x45a4, lo: 0x9c, hi: 0x9c},
+	{value: 0x45ac, lo: 0x9d, hi: 0x9d},
 	// Block 0x19, offset 0xa8
 	{value: 0x0000, lo: 0x03},
 	{value: 0xa000, lo: 0x92, hi: 0x92},
@@ -3787,18 +3793,18 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x263d, lo: 0xa9, hi: 0xa9},
 	{value: 0x8126, lo: 0xb1, hi: 0xb1},
 	{value: 0x8127, lo: 0xb2, hi: 0xb2},
-	{value: 0x4a66, lo: 0xb3, hi: 0xb3},
+	{value: 0x4a84, lo: 0xb3, hi: 0xb3},
 	{value: 0x8128, lo: 0xb4, hi: 0xb4},
-	{value: 0x4a6f, lo: 0xb5, hi: 0xb5},
-	{value: 0x464a, lo: 0xb6, hi: 0xb6},
+	{value: 0x4a8d, lo: 0xb5, hi: 0xb5},
+	{value: 0x45b4, lo: 0xb6, hi: 0xb6},
 	{value: 0x8200, lo: 0xb7, hi: 0xb7},
-	{value: 0x4652, lo: 0xb8, hi: 0xb8},
+	{value: 0x45bc, lo: 0xb8, hi: 0xb8},
 	{value: 0x8200, lo: 0xb9, hi: 0xb9},
 	{value: 0x8127, lo: 0xba, hi: 0xbd},
 	// Block 0x27, offset 0xf5
 	{value: 0x0000, lo: 0x0b},
 	{value: 0x8127, lo: 0x80, hi: 0x80},
-	{value: 0x4a78, lo: 0x81, hi: 0x81},
+	{value: 0x4a96, lo: 0x81, hi: 0x81},
 	{value: 0x8132, lo: 0x82, hi: 0x83},
 	{value: 0x8104, lo: 0x84, hi: 0x84},
 	{value: 0x8132, lo: 0x86, hi: 0x87},
@@ -3975,7 +3981,7 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x048b, lo: 0xa9, hi: 0xaa},
 	// Block 0x45, offset 0x189
 	{value: 0x0000, lo: 0x01},
-	{value: 0x4573, lo: 0x9c, hi: 0x9c},
+	{value: 0x44dd, lo: 0x9c, hi: 0x9c},
 	// Block 0x46, offset 0x18b
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8132, lo: 0xaf, hi: 0xb1},
@@ -3994,12 +4000,12 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x812f, lo: 0xae, hi: 0xaf},
 	// Block 0x4a, offset 0x197
 	{value: 0x0000, lo: 0x03},
-	{value: 0x4a81, lo: 0xb3, hi: 0xb3},
-	{value: 0x4a81, lo: 0xb5, hi: 0xb6},
-	{value: 0x4a81, lo: 0xba, hi: 0xbf},
+	{value: 0x4a9f, lo: 0xb3, hi: 0xb3},
+	{value: 0x4a9f, lo: 0xb5, hi: 0xb6},
+	{value: 0x4a9f, lo: 0xba, hi: 0xbf},
 	// Block 0x4b, offset 0x19b
 	{value: 0x0000, lo: 0x01},
-	{value: 0x4a81, lo: 0x8f, hi: 0xa3},
+	{value: 0x4a9f, lo: 0x8f, hi: 0xa3},
 	// Block 0x4c, offset 0x19d
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8100, lo: 0xae, hi: 0xbe},
@@ -4119,29 +4125,29 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0xc600, lo: 0x89, hi: 0xa3},
 	// Block 0x63, offset 0x1fb
 	{value: 0x0006, lo: 0x0d},
-	{value: 0x4426, lo: 0x9d, hi: 0x9d},
+	{value: 0x4390, lo: 0x9d, hi: 0x9d},
 	{value: 0x8115, lo: 0x9e, hi: 0x9e},
-	{value: 0x4498, lo: 0x9f, hi: 0x9f},
-	{value: 0x4486, lo: 0xaa, hi: 0xab},
-	{value: 0x458a, lo: 0xac, hi: 0xac},
-	{value: 0x4592, lo: 0xad, hi: 0xad},
-	{value: 0x43de, lo: 0xae, hi: 0xb1},
-	{value: 0x43fc, lo: 0xb2, hi: 0xb4},
-	{value: 0x4414, lo: 0xb5, hi: 0xb6},
-	{value: 0x4420, lo: 0xb8, hi: 0xb8},
-	{value: 0x442c, lo: 0xb9, hi: 0xbb},
-	{value: 0x4444, lo: 0xbc, hi: 0xbc},
-	{value: 0x444a, lo: 0xbe, hi: 0xbe},
+	{value: 0x4402, lo: 0x9f, hi: 0x9f},
+	{value: 0x43f0, lo: 0xaa, hi: 0xab},
+	{value: 0x44f4, lo: 0xac, hi: 0xac},
+	{value: 0x44fc, lo: 0xad, hi: 0xad},
+	{value: 0x4348, lo: 0xae, hi: 0xb1},
+	{value: 0x4366, lo: 0xb2, hi: 0xb4},
+	{value: 0x437e, lo: 0xb5, hi: 0xb6},
+	{value: 0x438a, lo: 0xb8, hi: 0xb8},
+	{value: 0x4396, lo: 0xb9, hi: 0xbb},
+	{value: 0x43ae, lo: 0xbc, hi: 0xbc},
+	{value: 0x43b4, lo: 0xbe, hi: 0xbe},
 	// Block 0x64, offset 0x209
 	{value: 0x0006, lo: 0x08},
-	{value: 0x4450, lo: 0x80, hi: 0x81},
-	{value: 0x445c, lo: 0x83, hi: 0x84},
-	{value: 0x446e, lo: 0x86, hi: 0x89},
-	{value: 0x4492, lo: 0x8a, hi: 0x8a},
-	{value: 0x440e, lo: 0x8b, hi: 0x8b},
-	{value: 0x43f6, lo: 0x8c, hi: 0x8c},
-	{value: 0x443e, lo: 0x8d, hi: 0x8d},
-	{value: 0x4468, lo: 0x8e, hi: 0x8e},
+	{value: 0x43ba, lo: 0x80, hi: 0x81},
+	{value: 0x43c6, lo: 0x83, hi: 0x84},
+	{value: 0x43d8, lo: 0x86, hi: 0x89},
+	{value: 0x43fc, lo: 0x8a, hi: 0x8a},
+	{value: 0x4378, lo: 0x8b, hi: 0x8b},
+	{value: 0x4360, lo: 0x8c, hi: 0x8c},
+	{value: 0x43a8, lo: 0x8d, hi: 0x8d},
+	{value: 0x43d2, lo: 0x8e, hi: 0x8e},
 	// Block 0x65, offset 0x212
 	{value: 0x0000, lo: 0x02},
 	{value: 0x8100, lo: 0xa4, hi: 0xa5},
@@ -4179,16 +4185,16 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x8100, lo: 0xb5, hi: 0xba},
 	// Block 0x6e, offset 0x22c
 	{value: 0x0000, lo: 0x04},
-	{value: 0x4a81, lo: 0x9e, hi: 0x9f},
-	{value: 0x4a81, lo: 0xa3, hi: 0xa3},
-	{value: 0x4a81, lo: 0xa5, hi: 0xa6},
-	{value: 0x4a81, lo: 0xaa, hi: 0xaf},
+	{value: 0x4a9f, lo: 0x9e, hi: 0x9f},
+	{value: 0x4a9f, lo: 0xa3, hi: 0xa3},
+	{value: 0x4a9f, lo: 0xa5, hi: 0xa6},
+	{value: 0x4a9f, lo: 0xaa, hi: 0xaf},
 	// Block 0x6f, offset 0x231
 	{value: 0x0000, lo: 0x05},
-	{value: 0x4a81, lo: 0x82, hi: 0x87},
-	{value: 0x4a81, lo: 0x8a, hi: 0x8f},
-	{value: 0x4a81, lo: 0x92, hi: 0x97},
-	{value: 0x4a81, lo: 0x9a, hi: 0x9c},
+	{value: 0x4a9f, lo: 0x82, hi: 0x87},
+	{value: 0x4a9f, lo: 0x8a, hi: 0x8f},
+	{value: 0x4a9f, lo: 0x92, hi: 0x97},
+	{value: 0x4a9f, lo: 0x9a, hi: 0x9c},
 	{value: 0x8100, lo: 0xa3, hi: 0xa3},
 	// Block 0x70, offset 0x237
 	{value: 0x0000, lo: 0x01},
@@ -4295,13 +4301,13 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x8101, lo: 0x9e, hi: 0x9e},
 	// Block 0x86, offset 0x288
 	{value: 0x0000, lo: 0x0c},
-	{value: 0x4662, lo: 0x9e, hi: 0x9e},
-	{value: 0x466c, lo: 0x9f, hi: 0x9f},
-	{value: 0x46a0, lo: 0xa0, hi: 0xa0},
-	{value: 0x46ae, lo: 0xa1, hi: 0xa1},
-	{value: 0x46bc, lo: 0xa2, hi: 0xa2},
-	{value: 0x46ca, lo: 0xa3, hi: 0xa3},
-	{value: 0x46d8, lo: 0xa4, hi: 0xa4},
+	{value: 0x45cc, lo: 0x9e, hi: 0x9e},
+	{value: 0x45d6, lo: 0x9f, hi: 0x9f},
+	{value: 0x460a, lo: 0xa0, hi: 0xa0},
+	{value: 0x4618, lo: 0xa1, hi: 0xa1},
+	{value: 0x4626, lo: 0xa2, hi: 0xa2},
+	{value: 0x4634, lo: 0xa3, hi: 0xa3},
+	{value: 0x4642, lo: 0xa4, hi: 0xa4},
 	{value: 0x812b, lo: 0xa5, hi: 0xa6},
 	{value: 0x8101, lo: 0xa7, hi: 0xa9},
 	{value: 0x8130, lo: 0xad, hi: 0xad},
@@ -4313,14 +4319,14 @@ var nfcSparseValues = [688]valueRange{
 	{value: 0x8132, lo: 0x85, hi: 0x89},
 	{value: 0x812d, lo: 0x8a, hi: 0x8b},
 	{value: 0x8132, lo: 0xaa, hi: 0xad},
-	{value: 0x4676, lo: 0xbb, hi: 0xbb},
-	{value: 0x4680, lo: 0xbc, hi: 0xbc},
-	{value: 0x46e6, lo: 0xbd, hi: 0xbd},
-	{value: 0x4702, lo: 0xbe, hi: 0xbe},
-	{value: 0x46f4, lo: 0xbf, hi: 0xbf},
+	{value: 0x45e0, lo: 0xbb, hi: 0xbb},
+	{value: 0x45ea, lo: 0xbc, hi: 0xbc},
+	{value: 0x4650, lo: 0xbd, hi: 0xbd},
+	{value: 0x466c, lo: 0xbe, hi: 0xbe},
+	{value: 0x465e, lo: 0xbf, hi: 0xbf},
 	// Block 0x88, offset 0x29f
 	{value: 0x0000, lo: 0x01},
-	{value: 0x4710, lo: 0x80, hi: 0x80},
+	{value: 0x467a, lo: 0x80, hi: 0x80},
 	// Block 0x89, offset 0x2a1
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8132, lo: 0x82, hi: 0x84},
@@ -4513,7 +4519,7 @@ func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 {
 	return 0
 }
 
-// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: 146925fc21092b17.
+// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: c3ed54ee046f3c46.
 type nfkcTrie struct{}
 
 func newNfkcTrie(i int) *nfkcTrie {
@@ -4549,22 +4555,22 @@ var nfkcValues = [5888]uint16{
 	0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
 	// Block 0x2, offset 0x80
 	// Block 0x3, offset 0xc0
-	0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
-	0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
-	0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
-	0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
-	0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
-	0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
-	0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
-	0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
-	0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
-	0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
-	0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
+	0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c,
+	0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb,
+	0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104,
+	0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd,
+	0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235,
+	0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285,
+	0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3,
+	0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750,
+	0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f,
+	0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
+	0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569,
 	// Block 0x4, offset 0x100
-	0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
+	0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8,
 	0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
 	0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
-	0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
+	0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
 	0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
 	0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
 	0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
@@ -4575,12 +4581,12 @@ var nfkcValues = [5888]uint16{
 	// Block 0x5, offset 0x140
 	0x140: 0x1c34, 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
 	0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, 0x149: 0x1c5c,
-	0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
+	0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
 	0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
-	0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
-	0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
-	0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
-	0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
+	0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d,
+	0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba,
+	0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796,
+	0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
 	0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
 	0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
 	0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0x00a7,
@@ -4592,7 +4598,7 @@ var nfkcValues = [5888]uint16{
 	0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
 	0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
 	0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
-	0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
+	0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
 	0x1b0: 0x33c5, 0x1b1: 0x1942, 0x1b2: 0x1945, 0x1b3: 0x19cf, 0x1b4: 0x3028, 0x1b5: 0x3334,
 	0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
 	0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
@@ -4603,8 +4609,8 @@ var nfkcValues = [5888]uint16{
 	0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
 	0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
 	0x1de: 0x305a, 0x1df: 0x3366,
-	0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
-	0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
+	0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b,
+	0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769,
 	0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
 	// Block 0x8, offset 0x200
 	0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
@@ -4619,7 +4625,7 @@ var nfkcValues = [5888]uint16{
 	0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
 	0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
 	// Block 0x9, offset 0x240
-	0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
+	0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936,
 	0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
 	0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
 	0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
@@ -4631,22 +4637,22 @@ var nfkcValues = [5888]uint16{
 	0x27a: 0x42a5,
 	0x27e: 0x0037,
 	// Block 0xa, offset 0x280
-	0x284: 0x425a, 0x285: 0x4511,
+	0x284: 0x425a, 0x285: 0x447b,
 	0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625,
 	0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000,
 	0x295: 0xa000, 0x297: 0xa000,
 	0x299: 0xa000,
 	0x29f: 0xa000, 0x2a1: 0xa000,
 	0x2a5: 0xa000, 0x2a9: 0xa000,
-	0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
+	0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9,
 	0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
 	0x2b7: 0xa000, 0x2b9: 0xa000,
 	0x2bf: 0xa000,
 	// Block 0xb, offset 0x2c0
 	0x2c1: 0xa000, 0x2c5: 0xa000,
-	0x2c9: 0xa000, 0x2ca: 0x48d6, 0x2cb: 0x48f4,
-	0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x490c, 0x2d0: 0x01be, 0x2d1: 0x01d0,
-	0x2d2: 0x01ac, 0x2d3: 0x43a2, 0x2d4: 0x43a8, 0x2d5: 0x01fa, 0x2d6: 0x01e8,
+	0x2c9: 0xa000, 0x2ca: 0x4840, 0x2cb: 0x485e,
+	0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x4876, 0x2d0: 0x01be, 0x2d1: 0x01d0,
+	0x2d2: 0x01ac, 0x2d3: 0x430c, 0x2d4: 0x4312, 0x2d5: 0x01fa, 0x2d6: 0x01e8,
 	0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7,
 	0x2f9: 0x01a6,
 	// Block 0xc, offset 0x300
@@ -4726,15 +4732,15 @@ var nfkcValues = [5888]uint16{
 	0x4e4: 0x305f, 0x4e5: 0x336b, 0x4e6: 0x3055, 0x4e7: 0x3361, 0x4e8: 0x3064, 0x4e9: 0x3370,
 	0x4ea: 0x3069, 0x4eb: 0x3375, 0x4ec: 0x30af, 0x4ed: 0x33bb, 0x4ee: 0x390b, 0x4ef: 0x3a9a,
 	0x4f0: 0x30b9, 0x4f1: 0x33ca, 0x4f2: 0x30c3, 0x4f3: 0x33d4, 0x4f4: 0x30cd, 0x4f5: 0x33de,
-	0x4f6: 0x475a, 0x4f7: 0x47eb, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7,
+	0x4f6: 0x46c4, 0x4f7: 0x4755, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7,
 	0x4fc: 0x30e1, 0x4fd: 0x33f2, 0x4fe: 0x30eb, 0x4ff: 0x33fc,
 	// Block 0x14, offset 0x500
 	0x500: 0x30f0, 0x501: 0x3401, 0x502: 0x30f5, 0x503: 0x3406, 0x504: 0x3109, 0x505: 0x341a,
 	0x506: 0x3113, 0x507: 0x3424, 0x508: 0x3122, 0x509: 0x3433, 0x50a: 0x311d, 0x50b: 0x342e,
 	0x50c: 0x3935, 0x50d: 0x3ac4, 0x50e: 0x3943, 0x50f: 0x3ad2, 0x510: 0x394a, 0x511: 0x3ad9,
 	0x512: 0x3951, 0x513: 0x3ae0, 0x514: 0x314f, 0x515: 0x3460, 0x516: 0x3154, 0x517: 0x3465,
-	0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x4787, 0x51b: 0x4818, 0x51c: 0x3997, 0x51d: 0x3b26,
-	0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4796, 0x523: 0x4827,
+	0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x46f1, 0x51b: 0x4782, 0x51c: 0x3997, 0x51d: 0x3b26,
+	0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4700, 0x523: 0x4791,
 	0x524: 0x399e, 0x525: 0x3b2d, 0x526: 0x39a5, 0x527: 0x3b34, 0x528: 0x39ac, 0x529: 0x3b3b,
 	0x52a: 0x3190, 0x52b: 0x34a1, 0x52c: 0x319a, 0x52d: 0x34b0, 0x52e: 0x31ae, 0x52f: 0x34c4,
 	0x530: 0x31a9, 0x531: 0x34bf, 0x532: 0x31ea, 0x533: 0x3500, 0x534: 0x31f9, 0x535: 0x350f,
@@ -4746,16 +4752,16 @@ var nfkcValues = [5888]uint16{
 	0x54c: 0x322b, 0x54d: 0x3546, 0x54e: 0x3249, 0x54f: 0x3564, 0x550: 0x3262, 0x551: 0x3582,
 	0x552: 0x3271, 0x553: 0x3591, 0x554: 0x3276, 0x555: 0x3596, 0x556: 0x337a, 0x557: 0x34a6,
 	0x558: 0x3537, 0x559: 0x3573, 0x55a: 0x1be0, 0x55b: 0x42d7,
-	0x560: 0x4737, 0x561: 0x47c8, 0x562: 0x2f83, 0x563: 0x328f,
+	0x560: 0x46a1, 0x561: 0x4732, 0x562: 0x2f83, 0x563: 0x328f,
 	0x564: 0x3878, 0x565: 0x3a07, 0x566: 0x3871, 0x567: 0x3a00, 0x568: 0x3886, 0x569: 0x3a15,
 	0x56a: 0x387f, 0x56b: 0x3a0e, 0x56c: 0x38be, 0x56d: 0x3a4d, 0x56e: 0x3894, 0x56f: 0x3a23,
 	0x570: 0x388d, 0x571: 0x3a1c, 0x572: 0x38a2, 0x573: 0x3a31, 0x574: 0x389b, 0x575: 0x3a2a,
-	0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x474b, 0x579: 0x47dc, 0x57a: 0x3000, 0x57b: 0x330c,
+	0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x46b5, 0x579: 0x4746, 0x57a: 0x3000, 0x57b: 0x330c,
 	0x57c: 0x2fec, 0x57d: 0x32f8, 0x57e: 0x38da, 0x57f: 0x3a69,
 	// Block 0x16, offset 0x580
 	0x580: 0x38d3, 0x581: 0x3a62, 0x582: 0x38e8, 0x583: 0x3a77, 0x584: 0x38e1, 0x585: 0x3a70,
 	0x586: 0x38fd, 0x587: 0x3a8c, 0x588: 0x3091, 0x589: 0x339d, 0x58a: 0x30a5, 0x58b: 0x33b1,
-	0x58c: 0x477d, 0x58d: 0x480e, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf,
+	0x58c: 0x46e7, 0x58d: 0x4778, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf,
 	0x592: 0x3919, 0x593: 0x3aa8, 0x594: 0x392e, 0x595: 0x3abd, 0x596: 0x3927, 0x597: 0x3ab6,
 	0x598: 0x3989, 0x599: 0x3b18, 0x59a: 0x396d, 0x59b: 0x3afc, 0x59c: 0x3966, 0x59d: 0x3af5,
 	0x59e: 0x397b, 0x59f: 0x3b0a, 0x5a0: 0x3974, 0x5a1: 0x3b03, 0x5a2: 0x3982, 0x5a3: 0x3b11,
@@ -4764,29 +4770,29 @@ var nfkcValues = [5888]uint16{
 	0x5b0: 0x39f9, 0x5b1: 0x3b88, 0x5b2: 0x3230, 0x5b3: 0x354b, 0x5b4: 0x3258, 0x5b5: 0x3578,
 	0x5b6: 0x3253, 0x5b7: 0x356e, 0x5b8: 0x323f, 0x5b9: 0x355a,
 	// Block 0x17, offset 0x5c0
-	0x5c0: 0x489a, 0x5c1: 0x48a0, 0x5c2: 0x49b4, 0x5c3: 0x49cc, 0x5c4: 0x49bc, 0x5c5: 0x49d4,
-	0x5c6: 0x49c4, 0x5c7: 0x49dc, 0x5c8: 0x4840, 0x5c9: 0x4846, 0x5ca: 0x4924, 0x5cb: 0x493c,
-	0x5cc: 0x492c, 0x5cd: 0x4944, 0x5ce: 0x4934, 0x5cf: 0x494c, 0x5d0: 0x48ac, 0x5d1: 0x48b2,
+	0x5c0: 0x4804, 0x5c1: 0x480a, 0x5c2: 0x491e, 0x5c3: 0x4936, 0x5c4: 0x4926, 0x5c5: 0x493e,
+	0x5c6: 0x492e, 0x5c7: 0x4946, 0x5c8: 0x47aa, 0x5c9: 0x47b0, 0x5ca: 0x488e, 0x5cb: 0x48a6,
+	0x5cc: 0x4896, 0x5cd: 0x48ae, 0x5ce: 0x489e, 0x5cf: 0x48b6, 0x5d0: 0x4816, 0x5d1: 0x481c,
 	0x5d2: 0x3db8, 0x5d3: 0x3dc8, 0x5d4: 0x3dc0, 0x5d5: 0x3dd0,
-	0x5d8: 0x484c, 0x5d9: 0x4852, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00,
-	0x5e0: 0x48c4, 0x5e1: 0x48ca, 0x5e2: 0x49e4, 0x5e3: 0x49fc,
-	0x5e4: 0x49ec, 0x5e5: 0x4a04, 0x5e6: 0x49f4, 0x5e7: 0x4a0c, 0x5e8: 0x4858, 0x5e9: 0x485e,
-	0x5ea: 0x4954, 0x5eb: 0x496c, 0x5ec: 0x495c, 0x5ed: 0x4974, 0x5ee: 0x4964, 0x5ef: 0x497c,
-	0x5f0: 0x48dc, 0x5f1: 0x48e2, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38,
-	0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x4864, 0x5f9: 0x486a, 0x5fa: 0x3d18, 0x5fb: 0x3d30,
+	0x5d8: 0x47b6, 0x5d9: 0x47bc, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00,
+	0x5e0: 0x482e, 0x5e1: 0x4834, 0x5e2: 0x494e, 0x5e3: 0x4966,
+	0x5e4: 0x4956, 0x5e5: 0x496e, 0x5e6: 0x495e, 0x5e7: 0x4976, 0x5e8: 0x47c2, 0x5e9: 0x47c8,
+	0x5ea: 0x48be, 0x5eb: 0x48d6, 0x5ec: 0x48c6, 0x5ed: 0x48de, 0x5ee: 0x48ce, 0x5ef: 0x48e6,
+	0x5f0: 0x4846, 0x5f1: 0x484c, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38,
+	0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x47ce, 0x5f9: 0x47d4, 0x5fa: 0x3d18, 0x5fb: 0x3d30,
 	0x5fc: 0x3d20, 0x5fd: 0x3d38, 0x5fe: 0x3d28, 0x5ff: 0x3d40,
 	// Block 0x18, offset 0x600
-	0x600: 0x48e8, 0x601: 0x48ee, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60,
-	0x608: 0x4870, 0x609: 0x4876, 0x60a: 0x3d48, 0x60b: 0x3d58,
-	0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x48fa, 0x611: 0x4900,
+	0x600: 0x4852, 0x601: 0x4858, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60,
+	0x608: 0x47da, 0x609: 0x47e0, 0x60a: 0x3d48, 0x60b: 0x3d58,
+	0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x4864, 0x611: 0x486a,
 	0x612: 0x3e80, 0x613: 0x3e98, 0x614: 0x3e88, 0x615: 0x3ea0, 0x616: 0x3e90, 0x617: 0x3ea8,
-	0x619: 0x487c, 0x61b: 0x3d68, 0x61d: 0x3d70,
-	0x61f: 0x3d78, 0x620: 0x4912, 0x621: 0x4918, 0x622: 0x4a14, 0x623: 0x4a2c,
-	0x624: 0x4a1c, 0x625: 0x4a34, 0x626: 0x4a24, 0x627: 0x4a3c, 0x628: 0x4882, 0x629: 0x4888,
-	0x62a: 0x4984, 0x62b: 0x499c, 0x62c: 0x498c, 0x62d: 0x49a4, 0x62e: 0x4994, 0x62f: 0x49ac,
-	0x630: 0x488e, 0x631: 0x43b4, 0x632: 0x3691, 0x633: 0x43ba, 0x634: 0x48b8, 0x635: 0x43c0,
-	0x636: 0x36a3, 0x637: 0x43c6, 0x638: 0x36c1, 0x639: 0x43cc, 0x63a: 0x36d9, 0x63b: 0x43d2,
-	0x63c: 0x4906, 0x63d: 0x43d8,
+	0x619: 0x47e6, 0x61b: 0x3d68, 0x61d: 0x3d70,
+	0x61f: 0x3d78, 0x620: 0x487c, 0x621: 0x4882, 0x622: 0x497e, 0x623: 0x4996,
+	0x624: 0x4986, 0x625: 0x499e, 0x626: 0x498e, 0x627: 0x49a6, 0x628: 0x47ec, 0x629: 0x47f2,
+	0x62a: 0x48ee, 0x62b: 0x4906, 0x62c: 0x48f6, 0x62d: 0x490e, 0x62e: 0x48fe, 0x62f: 0x4916,
+	0x630: 0x47f8, 0x631: 0x431e, 0x632: 0x3691, 0x633: 0x4324, 0x634: 0x4822, 0x635: 0x432a,
+	0x636: 0x36a3, 0x637: 0x4330, 0x638: 0x36c1, 0x639: 0x4336, 0x63a: 0x36d9, 0x63b: 0x433c,
+	0x63c: 0x4870, 0x63d: 0x4342,
 	// Block 0x19, offset 0x640
 	0x640: 0x3da0, 0x641: 0x3da8, 0x642: 0x4184, 0x643: 0x41a2, 0x644: 0x418e, 0x645: 0x41ac,
 	0x646: 0x4198, 0x647: 0x41b6, 0x648: 0x3cd8, 0x649: 0x3ce0, 0x64a: 0x40d0, 0x64b: 0x40ee,
@@ -4797,19 +4803,19 @@ var nfkcValues = [5888]uint16{
 	0x664: 0x4206, 0x665: 0x4224, 0x666: 0x4210, 0x667: 0x422e, 0x668: 0x3d80, 0x669: 0x3d88,
 	0x66a: 0x4148, 0x66b: 0x4166, 0x66c: 0x4152, 0x66d: 0x4170, 0x66e: 0x415c, 0x66f: 0x417a,
 	0x670: 0x3685, 0x671: 0x367f, 0x672: 0x3d90, 0x673: 0x368b, 0x674: 0x3d98,
-	0x676: 0x48a6, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x4384,
+	0x676: 0x4810, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x42ee,
 	0x67c: 0x35fb, 0x67d: 0x4287, 0x67e: 0x01d3, 0x67f: 0x4287,
 	// Block 0x1a, offset 0x680
-	0x680: 0x42a0, 0x681: 0x4518, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0,
-	0x686: 0x48d0, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x438a, 0x68a: 0x360d, 0x68b: 0x4390,
-	0x68c: 0x3619, 0x68d: 0x451f, 0x68e: 0x4526, 0x68f: 0x452d, 0x690: 0x36b5, 0x691: 0x36af,
-	0x692: 0x3e00, 0x693: 0x457a, 0x696: 0x36bb, 0x697: 0x3e10,
-	0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4396, 0x69d: 0x4534,
-	0x69e: 0x453b, 0x69f: 0x4542, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x4582,
+	0x680: 0x42a0, 0x681: 0x4482, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0,
+	0x686: 0x483a, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x42f4, 0x68a: 0x360d, 0x68b: 0x42fa,
+	0x68c: 0x3619, 0x68d: 0x4489, 0x68e: 0x4490, 0x68f: 0x4497, 0x690: 0x36b5, 0x691: 0x36af,
+	0x692: 0x3e00, 0x693: 0x44e4, 0x696: 0x36bb, 0x697: 0x3e10,
+	0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4300, 0x69d: 0x449e,
+	0x69e: 0x44a5, 0x69f: 0x44ac, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x44ec,
 	0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b,
-	0x6aa: 0x364f, 0x6ab: 0x43a2, 0x6ac: 0x3649, 0x6ad: 0x450a, 0x6ae: 0x4511, 0x6af: 0x0081,
+	0x6aa: 0x364f, 0x6ab: 0x430c, 0x6ac: 0x3649, 0x6ad: 0x4474, 0x6ae: 0x447b, 0x6af: 0x0081,
 	0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8,
-	0x6b6: 0x491e, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x439c, 0x6ba: 0x366d, 0x6bb: 0x43ae,
+	0x6b6: 0x4888, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x4306, 0x6ba: 0x366d, 0x6bb: 0x4318,
 	0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c,
 	// Block 0x1b, offset 0x6c0
 	0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8,
@@ -4922,7 +4928,7 @@ var nfkcValues = [5888]uint16{
 	0x93c: 0x3fc0, 0x93d: 0x3fc8,
 	// Block 0x25, offset 0x940
 	0x954: 0x3f00,
-	0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x4372, 0x95c: 0x4378, 0x95d: 0xa000,
+	0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x42dc, 0x95c: 0x42e2, 0x95d: 0xa000,
 	0x95e: 0x3fd0, 0x95f: 0x26b4,
 	0x966: 0xa000,
 	0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000,
@@ -4942,10 +4948,10 @@ var nfkcValues = [5888]uint16{
 	// Block 0x27, offset 0x9c0
 	0x9c0: 0x0367, 0x9c1: 0x032b, 0x9c2: 0x032f, 0x9c3: 0x0333, 0x9c4: 0x037b, 0x9c5: 0x0337,
 	0x9c6: 0x033b, 0x9c7: 0x033f, 0x9c8: 0x0343, 0x9c9: 0x0347, 0x9ca: 0x034b, 0x9cb: 0x034f,
-	0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x42dc, 0x9d0: 0x42e1, 0x9d1: 0x42e6,
-	0x9d2: 0x42eb, 0x9d3: 0x42f0, 0x9d4: 0x42f5, 0x9d5: 0x42fa, 0x9d6: 0x42ff, 0x9d7: 0x4304,
-	0x9d8: 0x4309, 0x9d9: 0x430e, 0x9da: 0x4313, 0x9db: 0x4318, 0x9dc: 0x431d, 0x9dd: 0x4322,
-	0x9de: 0x4327, 0x9df: 0x432c, 0x9e0: 0x4331, 0x9e1: 0x4336, 0x9e2: 0x433b, 0x9e3: 0x4340,
+	0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x49bd, 0x9d0: 0x49c3, 0x9d1: 0x49c9,
+	0x9d2: 0x49cf, 0x9d3: 0x49d5, 0x9d4: 0x49db, 0x9d5: 0x49e1, 0x9d6: 0x49e7, 0x9d7: 0x49ed,
+	0x9d8: 0x49f3, 0x9d9: 0x49f9, 0x9da: 0x49ff, 0x9db: 0x4a05, 0x9dc: 0x4a0b, 0x9dd: 0x4a11,
+	0x9de: 0x4a17, 0x9df: 0x4a1d, 0x9e0: 0x4a23, 0x9e1: 0x4a29, 0x9e2: 0x4a2f, 0x9e3: 0x4a35,
 	0x9e4: 0x03c3, 0x9e5: 0x035f, 0x9e6: 0x0363, 0x9e7: 0x03e7, 0x9e8: 0x03eb, 0x9e9: 0x03ef,
 	0x9ea: 0x03f3, 0x9eb: 0x03f7, 0x9ec: 0x03fb, 0x9ed: 0x03ff, 0x9ee: 0x036b, 0x9ef: 0x0403,
 	0x9f0: 0x0407, 0x9f1: 0x036f, 0x9f2: 0x0373, 0x9f3: 0x0377, 0x9f4: 0x037f, 0x9f5: 0x0383,
@@ -5148,17 +5154,17 @@ var nfkcValues = [5888]uint16{
 	0xe40: 0x19d5, 0xe41: 0x19d8, 0xe42: 0x19db, 0xe43: 0x1c08, 0xe44: 0x1c0c, 0xe45: 0x1a5f,
 	0xe46: 0x1a5f,
 	0xe53: 0x1d75, 0xe54: 0x1d66, 0xe55: 0x1d6b, 0xe56: 0x1d7a, 0xe57: 0x1d70,
-	0xe5d: 0x4426,
-	0xe5e: 0x8115, 0xe5f: 0x4498, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221,
+	0xe5d: 0x4390,
+	0xe5e: 0x8115, 0xe5f: 0x4402, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221,
 	0xe64: 0x0224, 0xe65: 0x0227, 0xe66: 0x022a, 0xe67: 0x0230, 0xe68: 0x0233, 0xe69: 0x0017,
-	0xe6a: 0x4486, 0xe6b: 0x448c, 0xe6c: 0x458a, 0xe6d: 0x4592, 0xe6e: 0x43de, 0xe6f: 0x43e4,
-	0xe70: 0x43ea, 0xe71: 0x43f0, 0xe72: 0x43fc, 0xe73: 0x4402, 0xe74: 0x4408, 0xe75: 0x4414,
-	0xe76: 0x441a, 0xe78: 0x4420, 0xe79: 0x442c, 0xe7a: 0x4432, 0xe7b: 0x4438,
-	0xe7c: 0x4444, 0xe7e: 0x444a,
+	0xe6a: 0x43f0, 0xe6b: 0x43f6, 0xe6c: 0x44f4, 0xe6d: 0x44fc, 0xe6e: 0x4348, 0xe6f: 0x434e,
+	0xe70: 0x4354, 0xe71: 0x435a, 0xe72: 0x4366, 0xe73: 0x436c, 0xe74: 0x4372, 0xe75: 0x437e,
+	0xe76: 0x4384, 0xe78: 0x438a, 0xe79: 0x4396, 0xe7a: 0x439c, 0xe7b: 0x43a2,
+	0xe7c: 0x43ae, 0xe7e: 0x43b4,
 	// Block 0x3a, offset 0xe80
-	0xe80: 0x4450, 0xe81: 0x4456, 0xe83: 0x445c, 0xe84: 0x4462,
-	0xe86: 0x446e, 0xe87: 0x4474, 0xe88: 0x447a, 0xe89: 0x4480, 0xe8a: 0x4492, 0xe8b: 0x440e,
-	0xe8c: 0x43f6, 0xe8d: 0x443e, 0xe8e: 0x4468, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299,
+	0xe80: 0x43ba, 0xe81: 0x43c0, 0xe83: 0x43c6, 0xe84: 0x43cc,
+	0xe86: 0x43d8, 0xe87: 0x43de, 0xe88: 0x43e4, 0xe89: 0x43ea, 0xe8a: 0x43fc, 0xe8b: 0x4378,
+	0xe8c: 0x4360, 0xe8d: 0x43a8, 0xe8e: 0x43d2, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299,
 	0xe92: 0x02a2, 0xe93: 0x02a2, 0xe94: 0x02a2, 0xe95: 0x02a2, 0xe96: 0x02a5, 0xe97: 0x02a5,
 	0xe98: 0x02a5, 0xe99: 0x02a5, 0xe9a: 0x02ab, 0xe9b: 0x02ab, 0xe9c: 0x02ab, 0xe9d: 0x02ab,
 	0xe9e: 0x029f, 0xe9f: 0x029f, 0xea0: 0x029f, 0xea1: 0x029f, 0xea2: 0x02a8, 0xea3: 0x02a8,
@@ -5174,9 +5180,9 @@ var nfkcValues = [5888]uint16{
 	0xed2: 0x02db, 0xed3: 0x02db, 0xed4: 0x02db, 0xed5: 0x02db, 0xed6: 0x02e1, 0xed7: 0x02e1,
 	0xed8: 0x02e1, 0xed9: 0x02e1, 0xeda: 0x02de, 0xedb: 0x02de, 0xedc: 0x02de, 0xedd: 0x02de,
 	0xede: 0x02e4, 0xedf: 0x02e4, 0xee0: 0x02e7, 0xee1: 0x02e7, 0xee2: 0x02e7, 0xee3: 0x02e7,
-	0xee4: 0x4504, 0xee5: 0x4504, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed,
+	0xee4: 0x446e, 0xee5: 0x446e, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed,
 	0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308,
-	0xef0: 0x44fe, 0xef1: 0x44fe,
+	0xef0: 0x4468, 0xef1: 0x4468,
 	// Block 0x3c, offset 0xf00
 	0xf13: 0x02d8, 0xf14: 0x02d8, 0xf15: 0x02d8, 0xf16: 0x02d8, 0xf17: 0x02f6,
 	0xf18: 0x02f6, 0xf19: 0x02f3, 0xf1a: 0x02f3, 0xf1b: 0x02f9, 0xf1c: 0x02f9, 0xf1d: 0x204f,
@@ -5203,8 +5209,8 @@ var nfkcValues = [5888]uint16{
 	0xf86: 0x1fb4, 0xf87: 0x1fb9, 0xf88: 0x1fbe, 0xf89: 0x1fc3, 0xf8a: 0x1fc8, 0xf8b: 0x1fcd,
 	0xf8c: 0x1fd2, 0xf8d: 0x1fd7, 0xf8e: 0x1fe6, 0xf8f: 0x1ff5, 0xf90: 0x1ffa, 0xf91: 0x1fff,
 	0xf92: 0x2004, 0xf93: 0x2009, 0xf94: 0x200e, 0xf95: 0x2018, 0xf96: 0x201d, 0xf97: 0x2022,
-	0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x44b6, 0xf9c: 0x44bc, 0xf9d: 0x44f2,
-	0xf9e: 0x4549, 0xf9f: 0x4550, 0xfa0: 0x4557, 0xfa1: 0x455e, 0xfa2: 0x4565, 0xfa3: 0x456c,
+	0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x4420, 0xf9c: 0x4426, 0xf9d: 0x445c,
+	0xf9e: 0x44b3, 0xf9f: 0x44ba, 0xfa0: 0x44c1, 0xfa1: 0x44c8, 0xfa2: 0x44cf, 0xfa3: 0x44d6,
 	0xfa4: 0x25c6, 0xfa5: 0x25cd, 0xfa6: 0x25d4, 0xfa7: 0x25db, 0xfa8: 0x25f0, 0xfa9: 0x25f7,
 	0xfaa: 0x1d98, 0xfab: 0x1d9d, 0xfac: 0x1da2, 0xfad: 0x1da7, 0xfae: 0x1db1, 0xfaf: 0x1db6,
 	0xfb0: 0x1dca, 0xfb1: 0x1dcf, 0xfb2: 0x1dd4, 0xfb3: 0x1dd9, 0xfb4: 0x1de3, 0xfb5: 0x1de8,
@@ -5213,7 +5219,7 @@ var nfkcValues = [5888]uint16{
 	// Block 0x3f, offset 0xfc0
 	0xfc0: 0x1f5a, 0xfc1: 0x1f6e, 0xfc2: 0x1f73, 0xfc3: 0x1f78, 0xfc4: 0x1f7d, 0xfc5: 0x1f96,
 	0xfc6: 0x1fa0, 0xfc7: 0x1fa5, 0xfc8: 0x1faa, 0xfc9: 0x1fbe, 0xfca: 0x1fdc, 0xfcb: 0x1fe1,
-	0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x44f2, 0xfd1: 0x2027,
+	0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x445c, 0xfd1: 0x2027,
 	0xfd2: 0x202c, 0xfd3: 0x2031, 0xfd4: 0x2036, 0xfd5: 0x2040, 0xfd6: 0x2045, 0xfd7: 0x25b1,
 	0xfd8: 0x25b8, 0xfd9: 0x25bf, 0xfda: 0x25d4, 0xfdb: 0x25e2, 0xfdc: 0x1d89, 0xfdd: 0x1d8e,
 	0xfde: 0x1d93, 0xfdf: 0x1da2, 0xfe0: 0x1dac, 0xfe1: 0x1dbb, 0xfe2: 0x1dc0, 0xfe3: 0x1dc5,
@@ -5227,11 +5233,11 @@ var nfkcValues = [5888]uint16{
 	0x1006: 0x1f69, 0x1007: 0x1f6e, 0x1008: 0x1f73, 0x1009: 0x1f87, 0x100a: 0x1f8c, 0x100b: 0x1f91,
 	0x100c: 0x1f96, 0x100d: 0x1f9b, 0x100e: 0x1faf, 0x100f: 0x1fb4, 0x1010: 0x1fb9, 0x1011: 0x1fbe,
 	0x1012: 0x1fcd, 0x1013: 0x1fd2, 0x1014: 0x1fd7, 0x1015: 0x1fe6, 0x1016: 0x1ff0, 0x1017: 0x1fff,
-	0x1018: 0x2004, 0x1019: 0x44e6, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031,
+	0x1018: 0x2004, 0x1019: 0x4450, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031,
 	0x101e: 0x203b, 0x101f: 0x25d4, 0x1020: 0x25e2, 0x1021: 0x1da2, 0x1022: 0x1dac, 0x1023: 0x1dd4,
 	0x1024: 0x1dde, 0x1025: 0x1dfc, 0x1026: 0x1e06, 0x1027: 0x1e6a, 0x1028: 0x1e6f, 0x1029: 0x1e92,
 	0x102a: 0x1e97, 0x102b: 0x1f6e, 0x102c: 0x1f73, 0x102d: 0x1f96, 0x102e: 0x1fe6, 0x102f: 0x1ff0,
-	0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x459a, 0x1033: 0x45a2, 0x1034: 0x45aa, 0x1035: 0x1ef1,
+	0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x4504, 0x1033: 0x450c, 0x1034: 0x4514, 0x1035: 0x1ef1,
 	0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74,
 	0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33,
 	// Block 0x41, offset 0x1040
@@ -5245,7 +5251,7 @@ var nfkcValues = [5888]uint16{
 	0x106a: 0x1e65, 0x106b: 0x1eb0, 0x106c: 0x1ed3, 0x106d: 0x1e7e, 0x106e: 0x1e83, 0x106f: 0x1e88,
 	0x1070: 0x1e92, 0x1071: 0x1e6f, 0x1072: 0x1e97, 0x1073: 0x1eec, 0x1074: 0x1e56, 0x1075: 0x1e5b,
 	0x1076: 0x1e60, 0x1077: 0x1e7e, 0x1078: 0x1e83, 0x1079: 0x1e88, 0x107a: 0x1eec, 0x107b: 0x1efb,
-	0x107c: 0x449e, 0x107d: 0x449e,
+	0x107c: 0x4408, 0x107d: 0x4408,
 	// Block 0x42, offset 0x1080
 	0x1090: 0x2311, 0x1091: 0x2326,
 	0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357,
@@ -5293,13 +5299,13 @@ var nfkcValues = [5888]uint16{
 	0x119e: 0x04bb, 0x119f: 0x0007, 0x11a0: 0x000d, 0x11a1: 0x0015, 0x11a2: 0x0017, 0x11a3: 0x001b,
 	0x11a4: 0x0039, 0x11a5: 0x003d, 0x11a6: 0x003b, 0x11a8: 0x0079, 0x11a9: 0x0009,
 	0x11aa: 0x000b, 0x11ab: 0x0041,
-	0x11b0: 0x42aa, 0x11b1: 0x44c2, 0x11b2: 0x42af, 0x11b4: 0x42b4,
-	0x11b6: 0x42b9, 0x11b7: 0x44c8, 0x11b8: 0x42be, 0x11b9: 0x44ce, 0x11ba: 0x42c3, 0x11bb: 0x44d4,
-	0x11bc: 0x42c8, 0x11bd: 0x44da, 0x11be: 0x42cd, 0x11bf: 0x44e0,
+	0x11b0: 0x42aa, 0x11b1: 0x442c, 0x11b2: 0x42af, 0x11b4: 0x42b4,
+	0x11b6: 0x42b9, 0x11b7: 0x4432, 0x11b8: 0x42be, 0x11b9: 0x4438, 0x11ba: 0x42c3, 0x11bb: 0x443e,
+	0x11bc: 0x42c8, 0x11bd: 0x4444, 0x11be: 0x42cd, 0x11bf: 0x444a,
 	// Block 0x47, offset 0x11c0
-	0x11c0: 0x0236, 0x11c1: 0x44a4, 0x11c2: 0x44a4, 0x11c3: 0x44aa, 0x11c4: 0x44aa, 0x11c5: 0x44ec,
-	0x11c6: 0x44ec, 0x11c7: 0x44b0, 0x11c8: 0x44b0, 0x11c9: 0x44f8, 0x11ca: 0x44f8, 0x11cb: 0x44f8,
-	0x11cc: 0x44f8, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c,
+	0x11c0: 0x0236, 0x11c1: 0x440e, 0x11c2: 0x440e, 0x11c3: 0x4414, 0x11c4: 0x4414, 0x11c5: 0x4456,
+	0x11c6: 0x4456, 0x11c7: 0x441a, 0x11c8: 0x441a, 0x11c9: 0x4462, 0x11ca: 0x4462, 0x11cb: 0x4462,
+	0x11cc: 0x4462, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c,
 	0x11d2: 0x023c, 0x11d3: 0x023f, 0x11d4: 0x023f, 0x11d5: 0x0242, 0x11d6: 0x0242, 0x11d7: 0x0242,
 	0x11d8: 0x0242, 0x11d9: 0x0245, 0x11da: 0x0245, 0x11db: 0x0245, 0x11dc: 0x0245, 0x11dd: 0x0248,
 	0x11de: 0x0248, 0x11df: 0x0248, 0x11e0: 0x0248, 0x11e1: 0x024b, 0x11e2: 0x024b, 0x11e3: 0x024b,
@@ -5338,18 +5344,18 @@ var nfkcValues = [5888]uint16{
 	0x128c: 0x054b, 0x128d: 0x054f, 0x128e: 0x0553, 0x128f: 0x0557, 0x1290: 0x055b, 0x1291: 0x055f,
 	0x1292: 0x0563, 0x1293: 0x0567, 0x1294: 0x056f, 0x1295: 0x0577, 0x1296: 0x057f, 0x1297: 0x0583,
 	0x1298: 0x0587, 0x1299: 0x058b, 0x129a: 0x058f, 0x129b: 0x0593, 0x129c: 0x0597, 0x129d: 0x05a7,
-	0x129e: 0x4a5a, 0x129f: 0x4a60, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4345,
-	0x12a4: 0x031b, 0x12a5: 0x434a, 0x12a6: 0x434f, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327,
-	0x12aa: 0x4354, 0x12ab: 0x4359, 0x12ac: 0x435e, 0x12ad: 0x4363, 0x12ae: 0x4368, 0x12af: 0x436d,
+	0x129e: 0x4a78, 0x129f: 0x4a7e, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4a3b,
+	0x12a4: 0x031b, 0x12a5: 0x4a41, 0x12a6: 0x4a47, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327,
+	0x12aa: 0x4a4d, 0x12ab: 0x4a53, 0x12ac: 0x4a59, 0x12ad: 0x4a5f, 0x12ae: 0x4a65, 0x12af: 0x4a6b,
 	0x12b0: 0x0367, 0x12b1: 0x032b, 0x12b2: 0x032f, 0x12b3: 0x0333, 0x12b4: 0x037b, 0x12b5: 0x0337,
 	0x12b6: 0x033b, 0x12b7: 0x033f, 0x12b8: 0x0343, 0x12b9: 0x0347, 0x12ba: 0x034b, 0x12bb: 0x034f,
 	0x12bc: 0x0353, 0x12bd: 0x0357, 0x12be: 0x035b,
 	// Block 0x4b, offset 0x12c0
-	0x12c2: 0x42dc, 0x12c3: 0x42e1, 0x12c4: 0x42e6, 0x12c5: 0x42eb,
-	0x12c6: 0x42f0, 0x12c7: 0x42f5, 0x12ca: 0x42fa, 0x12cb: 0x42ff,
-	0x12cc: 0x4304, 0x12cd: 0x4309, 0x12ce: 0x430e, 0x12cf: 0x4313,
-	0x12d2: 0x4318, 0x12d3: 0x431d, 0x12d4: 0x4322, 0x12d5: 0x4327, 0x12d6: 0x432c, 0x12d7: 0x4331,
-	0x12da: 0x4336, 0x12db: 0x433b, 0x12dc: 0x4340,
+	0x12c2: 0x49bd, 0x12c3: 0x49c3, 0x12c4: 0x49c9, 0x12c5: 0x49cf,
+	0x12c6: 0x49d5, 0x12c7: 0x49db, 0x12ca: 0x49e1, 0x12cb: 0x49e7,
+	0x12cc: 0x49ed, 0x12cd: 0x49f3, 0x12ce: 0x49f9, 0x12cf: 0x49ff,
+	0x12d2: 0x4a05, 0x12d3: 0x4a0b, 0x12d4: 0x4a11, 0x12d5: 0x4a17, 0x12d6: 0x4a1d, 0x12d7: 0x4a23,
+	0x12da: 0x4a29, 0x12db: 0x4a2f, 0x12dc: 0x4a35,
 	0x12e0: 0x00bf, 0x12e1: 0x00c2, 0x12e2: 0x00cb, 0x12e3: 0x4264,
 	0x12e4: 0x00c8, 0x12e5: 0x00c5, 0x12e6: 0x0447, 0x12e8: 0x046b, 0x12e9: 0x044b,
 	0x12ea: 0x044f, 0x12eb: 0x0453, 0x12ec: 0x0457, 0x12ed: 0x046f, 0x12ee: 0x0473,
@@ -5426,7 +5432,7 @@ var nfkcValues = [5888]uint16{
 	// Block 0x52, offset 0x1480
 	0x1480: 0x26ad, 0x1481: 0x26c2, 0x1482: 0x0503,
 	0x1490: 0x0c0f, 0x1491: 0x0a47,
-	0x1492: 0x08d3, 0x1493: 0x465a, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff,
+	0x1492: 0x08d3, 0x1493: 0x45c4, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff,
 	0x1498: 0x0727, 0x1499: 0x0cd7, 0x149a: 0x0eaf, 0x149b: 0x0caf, 0x149c: 0x0827, 0x149d: 0x0b6b,
 	0x149e: 0x07bf, 0x149f: 0x0cb7, 0x14a0: 0x0813, 0x14a1: 0x1117, 0x14a2: 0x0f83, 0x14a3: 0x138b,
 	0x14a4: 0x09d3, 0x14a5: 0x090b, 0x14a6: 0x0e63, 0x14a7: 0x0c1b, 0x14a8: 0x0c47, 0x14a9: 0x06bf,
@@ -5665,8 +5671,8 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x22b2, lo: 0xbe, hi: 0xbe},
 	// Block 0x1, offset 0xe
 	{value: 0x0091, lo: 0x03},
-	{value: 0x4778, lo: 0xa0, hi: 0xa1},
-	{value: 0x47aa, lo: 0xaf, hi: 0xb0},
+	{value: 0x46e2, lo: 0xa0, hi: 0xa1},
+	{value: 0x4714, lo: 0xaf, hi: 0xb0},
 	{value: 0xa000, lo: 0xb7, hi: 0xb7},
 	// Block 0x2, offset 0x12
 	{value: 0x0003, lo: 0x08},
@@ -5814,7 +5820,7 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x812d, lo: 0x92, hi: 0x92},
 	{value: 0x8132, lo: 0x93, hi: 0x93},
 	{value: 0x8132, lo: 0x94, hi: 0x94},
-	{value: 0x45b2, lo: 0x98, hi: 0x9f},
+	{value: 0x451c, lo: 0x98, hi: 0x9f},
 	// Block 0x11, offset 0x96
 	{value: 0x0000, lo: 0x02},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
@@ -5825,18 +5831,18 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x2c9e, lo: 0x8b, hi: 0x8c},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
 	{value: 0x9900, lo: 0x97, hi: 0x97},
-	{value: 0x45f2, lo: 0x9c, hi: 0x9d},
-	{value: 0x4602, lo: 0x9f, hi: 0x9f},
+	{value: 0x455c, lo: 0x9c, hi: 0x9d},
+	{value: 0x456c, lo: 0x9f, hi: 0x9f},
 	// Block 0x13, offset 0xa0
 	{value: 0x0000, lo: 0x03},
-	{value: 0x462a, lo: 0xb3, hi: 0xb3},
-	{value: 0x4632, lo: 0xb6, hi: 0xb6},
+	{value: 0x4594, lo: 0xb3, hi: 0xb3},
+	{value: 0x459c, lo: 0xb6, hi: 0xb6},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
 	// Block 0x14, offset 0xa4
 	{value: 0x0008, lo: 0x03},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
-	{value: 0x460a, lo: 0x99, hi: 0x9b},
-	{value: 0x4622, lo: 0x9e, hi: 0x9e},
+	{value: 0x4574, lo: 0x99, hi: 0x9b},
+	{value: 0x458c, lo: 0x9e, hi: 0x9e},
 	// Block 0x15, offset 0xa8
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8102, lo: 0xbc, hi: 0xbc},
@@ -5851,8 +5857,8 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x2cbe, lo: 0x8c, hi: 0x8c},
 	{value: 0x8104, lo: 0x8d, hi: 0x8d},
 	{value: 0x9900, lo: 0x96, hi: 0x97},
-	{value: 0x463a, lo: 0x9c, hi: 0x9c},
-	{value: 0x4642, lo: 0x9d, hi: 0x9d},
+	{value: 0x45a4, lo: 0x9c, hi: 0x9c},
+	{value: 0x45ac, lo: 0x9d, hi: 0x9d},
 	// Block 0x18, offset 0xb5
 	{value: 0x0000, lo: 0x03},
 	{value: 0xa000, lo: 0x92, hi: 0x92},
@@ -5941,18 +5947,18 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x263d, lo: 0xa9, hi: 0xa9},
 	{value: 0x8126, lo: 0xb1, hi: 0xb1},
 	{value: 0x8127, lo: 0xb2, hi: 0xb2},
-	{value: 0x4a66, lo: 0xb3, hi: 0xb3},
+	{value: 0x4a84, lo: 0xb3, hi: 0xb3},
 	{value: 0x8128, lo: 0xb4, hi: 0xb4},
-	{value: 0x4a6f, lo: 0xb5, hi: 0xb5},
-	{value: 0x464a, lo: 0xb6, hi: 0xb6},
-	{value: 0x468a, lo: 0xb7, hi: 0xb7},
-	{value: 0x4652, lo: 0xb8, hi: 0xb8},
-	{value: 0x4695, lo: 0xb9, hi: 0xb9},
+	{value: 0x4a8d, lo: 0xb5, hi: 0xb5},
+	{value: 0x45b4, lo: 0xb6, hi: 0xb6},
+	{value: 0x45f4, lo: 0xb7, hi: 0xb7},
+	{value: 0x45bc, lo: 0xb8, hi: 0xb8},
+	{value: 0x45ff, lo: 0xb9, hi: 0xb9},
 	{value: 0x8127, lo: 0xba, hi: 0xbd},
 	// Block 0x26, offset 0x107
 	{value: 0x0000, lo: 0x0b},
 	{value: 0x8127, lo: 0x80, hi: 0x80},
-	{value: 0x4a78, lo: 0x81, hi: 0x81},
+	{value: 0x4a96, lo: 0x81, hi: 0x81},
 	{value: 0x8132, lo: 0x82, hi: 0x83},
 	{value: 0x8104, lo: 0x84, hi: 0x84},
 	{value: 0x8132, lo: 0x86, hi: 0x87},
@@ -6199,7 +6205,7 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x192d, lo: 0xb5, hi: 0xb6},
 	// Block 0x4a, offset 0x1db
 	{value: 0x0000, lo: 0x01},
-	{value: 0x4573, lo: 0x9c, hi: 0x9c},
+	{value: 0x44dd, lo: 0x9c, hi: 0x9c},
 	// Block 0x4b, offset 0x1dd
 	{value: 0x0000, lo: 0x02},
 	{value: 0x0095, lo: 0xbc, hi: 0xbc},
@@ -6245,16 +6251,16 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x04b3, lo: 0xb6, hi: 0xb6},
 	{value: 0x0887, lo: 0xb8, hi: 0xba},
 	// Block 0x53, offset 0x201
-	{value: 0x0005, lo: 0x09},
+	{value: 0x0006, lo: 0x09},
 	{value: 0x0313, lo: 0xb1, hi: 0xb1},
 	{value: 0x0317, lo: 0xb2, hi: 0xb2},
-	{value: 0x4345, lo: 0xb3, hi: 0xb3},
+	{value: 0x4a3b, lo: 0xb3, hi: 0xb3},
 	{value: 0x031b, lo: 0xb4, hi: 0xb4},
-	{value: 0x434a, lo: 0xb5, hi: 0xb6},
+	{value: 0x4a41, lo: 0xb5, hi: 0xb6},
 	{value: 0x031f, lo: 0xb7, hi: 0xb7},
 	{value: 0x0323, lo: 0xb8, hi: 0xb8},
 	{value: 0x0327, lo: 0xb9, hi: 0xb9},
-	{value: 0x4354, lo: 0xba, hi: 0xbf},
+	{value: 0x4a4d, lo: 0xba, hi: 0xbf},
 	// Block 0x54, offset 0x20b
 	{value: 0x0000, lo: 0x02},
 	{value: 0x8132, lo: 0xaf, hi: 0xaf},
@@ -6479,13 +6485,13 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x8101, lo: 0x9e, hi: 0x9e},
 	// Block 0x83, offset 0x2ba
 	{value: 0x0000, lo: 0x0c},
-	{value: 0x4662, lo: 0x9e, hi: 0x9e},
-	{value: 0x466c, lo: 0x9f, hi: 0x9f},
-	{value: 0x46a0, lo: 0xa0, hi: 0xa0},
-	{value: 0x46ae, lo: 0xa1, hi: 0xa1},
-	{value: 0x46bc, lo: 0xa2, hi: 0xa2},
-	{value: 0x46ca, lo: 0xa3, hi: 0xa3},
-	{value: 0x46d8, lo: 0xa4, hi: 0xa4},
+	{value: 0x45cc, lo: 0x9e, hi: 0x9e},
+	{value: 0x45d6, lo: 0x9f, hi: 0x9f},
+	{value: 0x460a, lo: 0xa0, hi: 0xa0},
+	{value: 0x4618, lo: 0xa1, hi: 0xa1},
+	{value: 0x4626, lo: 0xa2, hi: 0xa2},
+	{value: 0x4634, lo: 0xa3, hi: 0xa3},
+	{value: 0x4642, lo: 0xa4, hi: 0xa4},
 	{value: 0x812b, lo: 0xa5, hi: 0xa6},
 	{value: 0x8101, lo: 0xa7, hi: 0xa9},
 	{value: 0x8130, lo: 0xad, hi: 0xad},
@@ -6497,14 +6503,14 @@ var nfkcSparseValues = [875]valueRange{
 	{value: 0x8132, lo: 0x85, hi: 0x89},
 	{value: 0x812d, lo: 0x8a, hi: 0x8b},
 	{value: 0x8132, lo: 0xaa, hi: 0xad},
-	{value: 0x4676, lo: 0xbb, hi: 0xbb},
-	{value: 0x4680, lo: 0xbc, hi: 0xbc},
-	{value: 0x46e6, lo: 0xbd, hi: 0xbd},
-	{value: 0x4702, lo: 0xbe, hi: 0xbe},
-	{value: 0x46f4, lo: 0xbf, hi: 0xbf},
+	{value: 0x45e0, lo: 0xbb, hi: 0xbb},
+	{value: 0x45ea, lo: 0xbc, hi: 0xbc},
+	{value: 0x4650, lo: 0xbd, hi: 0xbd},
+	{value: 0x466c, lo: 0xbe, hi: 0xbe},
+	{value: 0x465e, lo: 0xbf, hi: 0xbf},
 	// Block 0x85, offset 0x2d1
 	{value: 0x0000, lo: 0x01},
-	{value: 0x4710, lo: 0x80, hi: 0x80},
+	{value: 0x467a, lo: 0x80, hi: 0x80},
 	// Block 0x86, offset 0x2d3
 	{value: 0x0000, lo: 0x01},
 	{value: 0x8132, lo: 0x82, hi: 0x84},
@@ -7624,4 +7630,4 @@ var recompMap = map[uint32]rune{
 	0x15B915AF: 0x115BB,
 }
 
-// Total size of tables: 53KB (53976 bytes)
+// Total size of tables: 53KB (54006 bytes)
diff --git a/src/vendor/golang_org/x/text/unicode/norm/transform.go b/src/vendor/golang_org/x/text/unicode/norm/transform.go
index b341789..4dec306 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/transform.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/transform.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2013 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/unicode/norm/trie.go b/src/vendor/golang_org/x/text/unicode/norm/trie.go
index 423386b..4cbea64 100644
--- a/src/vendor/golang_org/x/text/unicode/norm/trie.go
+++ b/src/vendor/golang_org/x/text/unicode/norm/trie.go
@@ -1,3 +1,5 @@
+// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT.
+
 // Copyright 2011 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/src/vendor/golang_org/x/text/width/kind_string.go b/src/vendor/golang_org/x/text/width/kind_string.go
deleted file mode 100644
index ab4fee5..0000000
--- a/src/vendor/golang_org/x/text/width/kind_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type=Kind"; DO NOT EDIT
-
-package width
-
-import "fmt"
-
-const _Kind_name = "NeutralEastAsianAmbiguousEastAsianWideEastAsianNarrowEastAsianFullwidthEastAsianHalfwidth"
-
-var _Kind_index = [...]uint8{0, 7, 25, 38, 53, 71, 89}
-
-func (i Kind) String() string {
-	if i < 0 || i >= Kind(len(_Kind_index)-1) {
-		return fmt.Sprintf("Kind(%d)", i)
-	}
-	return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
-}
diff --git a/src/vendor/golang_org/x/text/width/tables.go b/src/vendor/golang_org/x/text/width/tables.go
deleted file mode 100644
index 242da0f..0000000
--- a/src/vendor/golang_org/x/text/width/tables.go
+++ /dev/null
@@ -1,1284 +0,0 @@
-// This file was generated by go generate; DO NOT EDIT
-
-package width
-
-// UnicodeVersion is the Unicode version from which the tables in this package are derived.
-const UnicodeVersion = "9.0.0"
-
-// lookup returns the trie value for the first UTF-8 encoding in s and
-// the width in bytes of this encoding. The size will be 0 if s does not
-// hold enough bytes to complete the encoding. len(s) must be greater than 0.
-func (t *widthTrie) lookup(s []byte) (v uint16, sz int) {
-	c0 := s[0]
-	switch {
-	case c0 < 0x80: // is ASCII
-		return widthValues[c0], 1
-	case c0 < 0xC2:
-		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
-	case c0 < 0xE0: // 2-byte UTF-8
-		if len(s) < 2 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c1), 2
-	case c0 < 0xF0: // 3-byte UTF-8
-		if len(s) < 3 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		o := uint32(i)<<6 + uint32(c1)
-		i = widthIndex[o]
-		c2 := s[2]
-		if c2 < 0x80 || 0xC0 <= c2 {
-			return 0, 2 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c2), 3
-	case c0 < 0xF8: // 4-byte UTF-8
-		if len(s) < 4 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		o := uint32(i)<<6 + uint32(c1)
-		i = widthIndex[o]
-		c2 := s[2]
-		if c2 < 0x80 || 0xC0 <= c2 {
-			return 0, 2 // Illegal UTF-8: not a continuation byte.
-		}
-		o = uint32(i)<<6 + uint32(c2)
-		i = widthIndex[o]
-		c3 := s[3]
-		if c3 < 0x80 || 0xC0 <= c3 {
-			return 0, 3 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c3), 4
-	}
-	// Illegal rune
-	return 0, 1
-}
-
-// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
-// s must start with a full and valid UTF-8 encoded rune.
-func (t *widthTrie) lookupUnsafe(s []byte) uint16 {
-	c0 := s[0]
-	if c0 < 0x80 { // is ASCII
-		return widthValues[c0]
-	}
-	i := widthIndex[c0]
-	if c0 < 0xE0 { // 2-byte UTF-8
-		return t.lookupValue(uint32(i), s[1])
-	}
-	i = widthIndex[uint32(i)<<6+uint32(s[1])]
-	if c0 < 0xF0 { // 3-byte UTF-8
-		return t.lookupValue(uint32(i), s[2])
-	}
-	i = widthIndex[uint32(i)<<6+uint32(s[2])]
-	if c0 < 0xF8 { // 4-byte UTF-8
-		return t.lookupValue(uint32(i), s[3])
-	}
-	return 0
-}
-
-// lookupString returns the trie value for the first UTF-8 encoding in s and
-// the width in bytes of this encoding. The size will be 0 if s does not
-// hold enough bytes to complete the encoding. len(s) must be greater than 0.
-func (t *widthTrie) lookupString(s string) (v uint16, sz int) {
-	c0 := s[0]
-	switch {
-	case c0 < 0x80: // is ASCII
-		return widthValues[c0], 1
-	case c0 < 0xC2:
-		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
-	case c0 < 0xE0: // 2-byte UTF-8
-		if len(s) < 2 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c1), 2
-	case c0 < 0xF0: // 3-byte UTF-8
-		if len(s) < 3 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		o := uint32(i)<<6 + uint32(c1)
-		i = widthIndex[o]
-		c2 := s[2]
-		if c2 < 0x80 || 0xC0 <= c2 {
-			return 0, 2 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c2), 3
-	case c0 < 0xF8: // 4-byte UTF-8
-		if len(s) < 4 {
-			return 0, 0
-		}
-		i := widthIndex[c0]
-		c1 := s[1]
-		if c1 < 0x80 || 0xC0 <= c1 {
-			return 0, 1 // Illegal UTF-8: not a continuation byte.
-		}
-		o := uint32(i)<<6 + uint32(c1)
-		i = widthIndex[o]
-		c2 := s[2]
-		if c2 < 0x80 || 0xC0 <= c2 {
-			return 0, 2 // Illegal UTF-8: not a continuation byte.
-		}
-		o = uint32(i)<<6 + uint32(c2)
-		i = widthIndex[o]
-		c3 := s[3]
-		if c3 < 0x80 || 0xC0 <= c3 {
-			return 0, 3 // Illegal UTF-8: not a continuation byte.
-		}
-		return t.lookupValue(uint32(i), c3), 4
-	}
-	// Illegal rune
-	return 0, 1
-}
-
-// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
-// s must start with a full and valid UTF-8 encoded rune.
-func (t *widthTrie) lookupStringUnsafe(s string) uint16 {
-	c0 := s[0]
-	if c0 < 0x80 { // is ASCII
-		return widthValues[c0]
-	}
-	i := widthIndex[c0]
-	if c0 < 0xE0 { // 2-byte UTF-8
-		return t.lookupValue(uint32(i), s[1])
-	}
-	i = widthIndex[uint32(i)<<6+uint32(s[1])]
-	if c0 < 0xF0 { // 3-byte UTF-8
-		return t.lookupValue(uint32(i), s[2])
-	}
-	i = widthIndex[uint32(i)<<6+uint32(s[2])]
-	if c0 < 0xF8 { // 4-byte UTF-8
-		return t.lookupValue(uint32(i), s[3])
-	}
-	return 0
-}
-
-// widthTrie. Total size: 14080 bytes (13.75 KiB). Checksum: 3b8aeb3dc03667a3.
-type widthTrie struct{}
-
-func newWidthTrie(i int) *widthTrie {
-	return &widthTrie{}
-}
-
-// lookupValue determines the type of block n and looks up the value for b.
-func (t *widthTrie) lookupValue(n uint32, b byte) uint16 {
-	switch {
-	default:
-		return uint16(widthValues[n<<6+uint32(b)])
-	}
-}
-
-// widthValues: 99 blocks, 6336 entries, 12672 bytes
-// The third block is the zero block.
-var widthValues = [6336]uint16{
-	// Block 0x0, offset 0x0
-	0x20: 0x6001, 0x21: 0x6002, 0x22: 0x6002, 0x23: 0x6002,
-	0x24: 0x6002, 0x25: 0x6002, 0x26: 0x6002, 0x27: 0x6002, 0x28: 0x6002, 0x29: 0x6002,
-	0x2a: 0x6002, 0x2b: 0x6002, 0x2c: 0x6002, 0x2d: 0x6002, 0x2e: 0x6002, 0x2f: 0x6002,
-	0x30: 0x6002, 0x31: 0x6002, 0x32: 0x6002, 0x33: 0x6002, 0x34: 0x6002, 0x35: 0x6002,
-	0x36: 0x6002, 0x37: 0x6002, 0x38: 0x6002, 0x39: 0x6002, 0x3a: 0x6002, 0x3b: 0x6002,
-	0x3c: 0x6002, 0x3d: 0x6002, 0x3e: 0x6002, 0x3f: 0x6002,
-	// Block 0x1, offset 0x40
-	0x40: 0x6003, 0x41: 0x6003, 0x42: 0x6003, 0x43: 0x6003, 0x44: 0x6003, 0x45: 0x6003,
-	0x46: 0x6003, 0x47: 0x6003, 0x48: 0x6003, 0x49: 0x6003, 0x4a: 0x6003, 0x4b: 0x6003,
-	0x4c: 0x6003, 0x4d: 0x6003, 0x4e: 0x6003, 0x4f: 0x6003, 0x50: 0x6003, 0x51: 0x6003,
-	0x52: 0x6003, 0x53: 0x6003, 0x54: 0x6003, 0x55: 0x6003, 0x56: 0x6003, 0x57: 0x6003,
-	0x58: 0x6003, 0x59: 0x6003, 0x5a: 0x6003, 0x5b: 0x6003, 0x5c: 0x6003, 0x5d: 0x6003,
-	0x5e: 0x6003, 0x5f: 0x6003, 0x60: 0x6004, 0x61: 0x6004, 0x62: 0x6004, 0x63: 0x6004,
-	0x64: 0x6004, 0x65: 0x6004, 0x66: 0x6004, 0x67: 0x6004, 0x68: 0x6004, 0x69: 0x6004,
-	0x6a: 0x6004, 0x6b: 0x6004, 0x6c: 0x6004, 0x6d: 0x6004, 0x6e: 0x6004, 0x6f: 0x6004,
-	0x70: 0x6004, 0x71: 0x6004, 0x72: 0x6004, 0x73: 0x6004, 0x74: 0x6004, 0x75: 0x6004,
-	0x76: 0x6004, 0x77: 0x6004, 0x78: 0x6004, 0x79: 0x6004, 0x7a: 0x6004, 0x7b: 0x6004,
-	0x7c: 0x6004, 0x7d: 0x6004, 0x7e: 0x6004,
-	// Block 0x2, offset 0x80
-	// Block 0x3, offset 0xc0
-	0xe1: 0x2000, 0xe2: 0x6005, 0xe3: 0x6005,
-	0xe4: 0x2000, 0xe5: 0x6006, 0xe6: 0x6005, 0xe7: 0x2000, 0xe8: 0x2000,
-	0xea: 0x2000, 0xec: 0x6007, 0xed: 0x2000, 0xee: 0x2000, 0xef: 0x6008,
-	0xf0: 0x2000, 0xf1: 0x2000, 0xf2: 0x2000, 0xf3: 0x2000, 0xf4: 0x2000,
-	0xf6: 0x2000, 0xf7: 0x2000, 0xf8: 0x2000, 0xf9: 0x2000, 0xfa: 0x2000,
-	0xfc: 0x2000, 0xfd: 0x2000, 0xfe: 0x2000, 0xff: 0x2000,
-	// Block 0x4, offset 0x100
-	0x106: 0x2000,
-	0x110: 0x2000,
-	0x117: 0x2000,
-	0x118: 0x2000,
-	0x11e: 0x2000, 0x11f: 0x2000, 0x120: 0x2000, 0x121: 0x2000,
-	0x126: 0x2000, 0x128: 0x2000, 0x129: 0x2000,
-	0x12a: 0x2000, 0x12c: 0x2000, 0x12d: 0x2000,
-	0x130: 0x2000, 0x132: 0x2000, 0x133: 0x2000,
-	0x137: 0x2000, 0x138: 0x2000, 0x139: 0x2000, 0x13a: 0x2000,
-	0x13c: 0x2000, 0x13e: 0x2000,
-	// Block 0x5, offset 0x140
-	0x141: 0x2000,
-	0x151: 0x2000,
-	0x153: 0x2000,
-	0x15b: 0x2000,
-	0x166: 0x2000, 0x167: 0x2000,
-	0x16b: 0x2000,
-	0x171: 0x2000, 0x172: 0x2000, 0x173: 0x2000,
-	0x178: 0x2000,
-	0x17f: 0x2000,
-	// Block 0x6, offset 0x180
-	0x180: 0x2000, 0x181: 0x2000, 0x182: 0x2000, 0x184: 0x2000,
-	0x188: 0x2000, 0x189: 0x2000, 0x18a: 0x2000, 0x18b: 0x2000,
-	0x18d: 0x2000,
-	0x192: 0x2000, 0x193: 0x2000,
-	0x1a6: 0x2000, 0x1a7: 0x2000,
-	0x1ab: 0x2000,
-	// Block 0x7, offset 0x1c0
-	0x1ce: 0x2000, 0x1d0: 0x2000,
-	0x1d2: 0x2000, 0x1d4: 0x2000, 0x1d6: 0x2000,
-	0x1d8: 0x2000, 0x1da: 0x2000, 0x1dc: 0x2000,
-	// Block 0x8, offset 0x200
-	0x211: 0x2000,
-	0x221: 0x2000,
-	// Block 0x9, offset 0x240
-	0x244: 0x2000,
-	0x247: 0x2000, 0x249: 0x2000, 0x24a: 0x2000, 0x24b: 0x2000,
-	0x24d: 0x2000, 0x250: 0x2000,
-	0x258: 0x2000, 0x259: 0x2000, 0x25a: 0x2000, 0x25b: 0x2000, 0x25d: 0x2000,
-	0x25f: 0x2000,
-	// Block 0xa, offset 0x280
-	0x280: 0x2000, 0x281: 0x2000, 0x282: 0x2000, 0x283: 0x2000, 0x284: 0x2000, 0x285: 0x2000,
-	0x286: 0x2000, 0x287: 0x2000, 0x288: 0x2000, 0x289: 0x2000, 0x28a: 0x2000, 0x28b: 0x2000,
-	0x28c: 0x2000, 0x28d: 0x2000, 0x28e: 0x2000, 0x28f: 0x2000, 0x290: 0x2000, 0x291: 0x2000,
-	0x292: 0x2000, 0x293: 0x2000, 0x294: 0x2000, 0x295: 0x2000, 0x296: 0x2000, 0x297: 0x2000,
-	0x298: 0x2000, 0x299: 0x2000, 0x29a: 0x2000, 0x29b: 0x2000, 0x29c: 0x2000, 0x29d: 0x2000,
-	0x29e: 0x2000, 0x29f: 0x2000, 0x2a0: 0x2000, 0x2a1: 0x2000, 0x2a2: 0x2000, 0x2a3: 0x2000,
-	0x2a4: 0x2000, 0x2a5: 0x2000, 0x2a6: 0x2000, 0x2a7: 0x2000, 0x2a8: 0x2000, 0x2a9: 0x2000,
-	0x2aa: 0x2000, 0x2ab: 0x2000, 0x2ac: 0x2000, 0x2ad: 0x2000, 0x2ae: 0x2000, 0x2af: 0x2000,
-	0x2b0: 0x2000, 0x2b1: 0x2000, 0x2b2: 0x2000, 0x2b3: 0x2000, 0x2b4: 0x2000, 0x2b5: 0x2000,
-	0x2b6: 0x2000, 0x2b7: 0x2000, 0x2b8: 0x2000, 0x2b9: 0x2000, 0x2ba: 0x2000, 0x2bb: 0x2000,
-	0x2bc: 0x2000, 0x2bd: 0x2000, 0x2be: 0x2000, 0x2bf: 0x2000,
-	// Block 0xb, offset 0x2c0
-	0x2c0: 0x2000, 0x2c1: 0x2000, 0x2c2: 0x2000, 0x2c3: 0x2000, 0x2c4: 0x2000, 0x2c5: 0x2000,
-	0x2c6: 0x2000, 0x2c7: 0x2000, 0x2c8: 0x2000, 0x2c9: 0x2000, 0x2ca: 0x2000, 0x2cb: 0x2000,
-	0x2cc: 0x2000, 0x2cd: 0x2000, 0x2ce: 0x2000, 0x2cf: 0x2000, 0x2d0: 0x2000, 0x2d1: 0x2000,
-	0x2d2: 0x2000, 0x2d3: 0x2000, 0x2d4: 0x2000, 0x2d5: 0x2000, 0x2d6: 0x2000, 0x2d7: 0x2000,
-	0x2d8: 0x2000, 0x2d9: 0x2000, 0x2da: 0x2000, 0x2db: 0x2000, 0x2dc: 0x2000, 0x2dd: 0x2000,
-	0x2de: 0x2000, 0x2df: 0x2000, 0x2e0: 0x2000, 0x2e1: 0x2000, 0x2e2: 0x2000, 0x2e3: 0x2000,
-	0x2e4: 0x2000, 0x2e5: 0x2000, 0x2e6: 0x2000, 0x2e7: 0x2000, 0x2e8: 0x2000, 0x2e9: 0x2000,
-	0x2ea: 0x2000, 0x2eb: 0x2000, 0x2ec: 0x2000, 0x2ed: 0x2000, 0x2ee: 0x2000, 0x2ef: 0x2000,
-	// Block 0xc, offset 0x300
-	0x311: 0x2000,
-	0x312: 0x2000, 0x313: 0x2000, 0x314: 0x2000, 0x315: 0x2000, 0x316: 0x2000, 0x317: 0x2000,
-	0x318: 0x2000, 0x319: 0x2000, 0x31a: 0x2000, 0x31b: 0x2000, 0x31c: 0x2000, 0x31d: 0x2000,
-	0x31e: 0x2000, 0x31f: 0x2000, 0x320: 0x2000, 0x321: 0x2000, 0x323: 0x2000,
-	0x324: 0x2000, 0x325: 0x2000, 0x326: 0x2000, 0x327: 0x2000, 0x328: 0x2000, 0x329: 0x2000,
-	0x331: 0x2000, 0x332: 0x2000, 0x333: 0x2000, 0x334: 0x2000, 0x335: 0x2000,
-	0x336: 0x2000, 0x337: 0x2000, 0x338: 0x2000, 0x339: 0x2000, 0x33a: 0x2000, 0x33b: 0x2000,
-	0x33c: 0x2000, 0x33d: 0x2000, 0x33e: 0x2000, 0x33f: 0x2000,
-	// Block 0xd, offset 0x340
-	0x340: 0x2000, 0x341: 0x2000, 0x343: 0x2000, 0x344: 0x2000, 0x345: 0x2000,
-	0x346: 0x2000, 0x347: 0x2000, 0x348: 0x2000, 0x349: 0x2000,
-	// Block 0xe, offset 0x380
-	0x381: 0x2000,
-	0x390: 0x2000, 0x391: 0x2000,
-	0x392: 0x2000, 0x393: 0x2000, 0x394: 0x2000, 0x395: 0x2000, 0x396: 0x2000, 0x397: 0x2000,
-	0x398: 0x2000, 0x399: 0x2000, 0x39a: 0x2000, 0x39b: 0x2000, 0x39c: 0x2000, 0x39d: 0x2000,
-	0x39e: 0x2000, 0x39f: 0x2000, 0x3a0: 0x2000, 0x3a1: 0x2000, 0x3a2: 0x2000, 0x3a3: 0x2000,
-	0x3a4: 0x2000, 0x3a5: 0x2000, 0x3a6: 0x2000, 0x3a7: 0x2000, 0x3a8: 0x2000, 0x3a9: 0x2000,
-	0x3aa: 0x2000, 0x3ab: 0x2000, 0x3ac: 0x2000, 0x3ad: 0x2000, 0x3ae: 0x2000, 0x3af: 0x2000,
-	0x3b0: 0x2000, 0x3b1: 0x2000, 0x3b2: 0x2000, 0x3b3: 0x2000, 0x3b4: 0x2000, 0x3b5: 0x2000,
-	0x3b6: 0x2000, 0x3b7: 0x2000, 0x3b8: 0x2000, 0x3b9: 0x2000, 0x3ba: 0x2000, 0x3bb: 0x2000,
-	0x3bc: 0x2000, 0x3bd: 0x2000, 0x3be: 0x2000, 0x3bf: 0x2000,
-	// Block 0xf, offset 0x3c0
-	0x3c0: 0x2000, 0x3c1: 0x2000, 0x3c2: 0x2000, 0x3c3: 0x2000, 0x3c4: 0x2000, 0x3c5: 0x2000,
-	0x3c6: 0x2000, 0x3c7: 0x2000, 0x3c8: 0x2000, 0x3c9: 0x2000, 0x3ca: 0x2000, 0x3cb: 0x2000,
-	0x3cc: 0x2000, 0x3cd: 0x2000, 0x3ce: 0x2000, 0x3cf: 0x2000, 0x3d1: 0x2000,
-	// Block 0x10, offset 0x400
-	0x400: 0x4000, 0x401: 0x4000, 0x402: 0x4000, 0x403: 0x4000, 0x404: 0x4000, 0x405: 0x4000,
-	0x406: 0x4000, 0x407: 0x4000, 0x408: 0x4000, 0x409: 0x4000, 0x40a: 0x4000, 0x40b: 0x4000,
-	0x40c: 0x4000, 0x40d: 0x4000, 0x40e: 0x4000, 0x40f: 0x4000, 0x410: 0x4000, 0x411: 0x4000,
-	0x412: 0x4000, 0x413: 0x4000, 0x414: 0x4000, 0x415: 0x4000, 0x416: 0x4000, 0x417: 0x4000,
-	0x418: 0x4000, 0x419: 0x4000, 0x41a: 0x4000, 0x41b: 0x4000, 0x41c: 0x4000, 0x41d: 0x4000,
-	0x41e: 0x4000, 0x41f: 0x4000, 0x420: 0x4000, 0x421: 0x4000, 0x422: 0x4000, 0x423: 0x4000,
-	0x424: 0x4000, 0x425: 0x4000, 0x426: 0x4000, 0x427: 0x4000, 0x428: 0x4000, 0x429: 0x4000,
-	0x42a: 0x4000, 0x42b: 0x4000, 0x42c: 0x4000, 0x42d: 0x4000, 0x42e: 0x4000, 0x42f: 0x4000,
-	0x430: 0x4000, 0x431: 0x4000, 0x432: 0x4000, 0x433: 0x4000, 0x434: 0x4000, 0x435: 0x4000,
-	0x436: 0x4000, 0x437: 0x4000, 0x438: 0x4000, 0x439: 0x4000, 0x43a: 0x4000, 0x43b: 0x4000,
-	0x43c: 0x4000, 0x43d: 0x4000, 0x43e: 0x4000, 0x43f: 0x4000,
-	// Block 0x11, offset 0x440
-	0x440: 0x4000, 0x441: 0x4000, 0x442: 0x4000, 0x443: 0x4000, 0x444: 0x4000, 0x445: 0x4000,
-	0x446: 0x4000, 0x447: 0x4000, 0x448: 0x4000, 0x449: 0x4000, 0x44a: 0x4000, 0x44b: 0x4000,
-	0x44c: 0x4000, 0x44d: 0x4000, 0x44e: 0x4000, 0x44f: 0x4000, 0x450: 0x4000, 0x451: 0x4000,
-	0x452: 0x4000, 0x453: 0x4000, 0x454: 0x4000, 0x455: 0x4000, 0x456: 0x4000, 0x457: 0x4000,
-	0x458: 0x4000, 0x459: 0x4000, 0x45a: 0x4000, 0x45b: 0x4000, 0x45c: 0x4000, 0x45d: 0x4000,
-	0x45e: 0x4000, 0x45f: 0x4000,
-	// Block 0x12, offset 0x480
-	0x490: 0x2000,
-	0x493: 0x2000, 0x494: 0x2000, 0x495: 0x2000, 0x496: 0x2000,
-	0x498: 0x2000, 0x499: 0x2000, 0x49c: 0x2000, 0x49d: 0x2000,
-	0x4a0: 0x2000, 0x4a1: 0x2000, 0x4a2: 0x2000,
-	0x4a4: 0x2000, 0x4a5: 0x2000, 0x4a6: 0x2000, 0x4a7: 0x2000,
-	0x4b0: 0x2000, 0x4b2: 0x2000, 0x4b3: 0x2000, 0x4b5: 0x2000,
-	0x4bb: 0x2000,
-	0x4be: 0x2000,
-	// Block 0x13, offset 0x4c0
-	0x4f4: 0x2000,
-	0x4ff: 0x2000,
-	// Block 0x14, offset 0x500
-	0x501: 0x2000, 0x502: 0x2000, 0x503: 0x2000, 0x504: 0x2000,
-	0x529: 0xa009,
-	0x52c: 0x2000,
-	// Block 0x15, offset 0x540
-	0x543: 0x2000, 0x545: 0x2000,
-	0x549: 0x2000,
-	0x553: 0x2000, 0x556: 0x2000,
-	0x561: 0x2000, 0x562: 0x2000,
-	0x566: 0x2000,
-	0x56b: 0x2000,
-	// Block 0x16, offset 0x580
-	0x593: 0x2000, 0x594: 0x2000,
-	0x59b: 0x2000, 0x59c: 0x2000, 0x59d: 0x2000,
-	0x59e: 0x2000, 0x5a0: 0x2000, 0x5a1: 0x2000, 0x5a2: 0x2000, 0x5a3: 0x2000,
-	0x5a4: 0x2000, 0x5a5: 0x2000, 0x5a6: 0x2000, 0x5a7: 0x2000, 0x5a8: 0x2000, 0x5a9: 0x2000,
-	0x5aa: 0x2000, 0x5ab: 0x2000,
-	0x5b0: 0x2000, 0x5b1: 0x2000, 0x5b2: 0x2000, 0x5b3: 0x2000, 0x5b4: 0x2000, 0x5b5: 0x2000,
-	0x5b6: 0x2000, 0x5b7: 0x2000, 0x5b8: 0x2000, 0x5b9: 0x2000,
-	// Block 0x17, offset 0x5c0
-	0x5c9: 0x2000,
-	0x5d0: 0x200a, 0x5d1: 0x200b,
-	0x5d2: 0x200a, 0x5d3: 0x200c, 0x5d4: 0x2000, 0x5d5: 0x2000, 0x5d6: 0x2000, 0x5d7: 0x2000,
-	0x5d8: 0x2000, 0x5d9: 0x2000,
-	0x5f8: 0x2000, 0x5f9: 0x2000,
-	// Block 0x18, offset 0x600
-	0x612: 0x2000, 0x614: 0x2000,
-	0x627: 0x2000,
-	// Block 0x19, offset 0x640
-	0x640: 0x2000, 0x642: 0x2000, 0x643: 0x2000,
-	0x647: 0x2000, 0x648: 0x2000, 0x64b: 0x2000,
-	0x64f: 0x2000, 0x651: 0x2000,
-	0x655: 0x2000,
-	0x65a: 0x2000, 0x65d: 0x2000,
-	0x65e: 0x2000, 0x65f: 0x2000, 0x660: 0x2000, 0x663: 0x2000,
-	0x665: 0x2000, 0x667: 0x2000, 0x668: 0x2000, 0x669: 0x2000,
-	0x66a: 0x2000, 0x66b: 0x2000, 0x66c: 0x2000, 0x66e: 0x2000,
-	0x674: 0x2000, 0x675: 0x2000,
-	0x676: 0x2000, 0x677: 0x2000,
-	0x67c: 0x2000, 0x67d: 0x2000,
-	// Block 0x1a, offset 0x680
-	0x688: 0x2000,
-	0x68c: 0x2000,
-	0x692: 0x2000,
-	0x6a0: 0x2000, 0x6a1: 0x2000,
-	0x6a4: 0x2000, 0x6a5: 0x2000, 0x6a6: 0x2000, 0x6a7: 0x2000,
-	0x6aa: 0x2000, 0x6ab: 0x2000, 0x6ae: 0x2000, 0x6af: 0x2000,
-	// Block 0x1b, offset 0x6c0
-	0x6c2: 0x2000, 0x6c3: 0x2000,
-	0x6c6: 0x2000, 0x6c7: 0x2000,
-	0x6d5: 0x2000,
-	0x6d9: 0x2000,
-	0x6e5: 0x2000,
-	0x6ff: 0x2000,
-	// Block 0x1c, offset 0x700
-	0x712: 0x2000,
-	0x71a: 0x4000, 0x71b: 0x4000,
-	0x729: 0x4000,
-	0x72a: 0x4000,
-	// Block 0x1d, offset 0x740
-	0x769: 0x4000,
-	0x76a: 0x4000, 0x76b: 0x4000, 0x76c: 0x4000,
-	0x770: 0x4000, 0x773: 0x4000,
-	// Block 0x1e, offset 0x780
-	0x7a0: 0x2000, 0x7a1: 0x2000, 0x7a2: 0x2000, 0x7a3: 0x2000,
-	0x7a4: 0x2000, 0x7a5: 0x2000, 0x7a6: 0x2000, 0x7a7: 0x2000, 0x7a8: 0x2000, 0x7a9: 0x2000,
-	0x7aa: 0x2000, 0x7ab: 0x2000, 0x7ac: 0x2000, 0x7ad: 0x2000, 0x7ae: 0x2000, 0x7af: 0x2000,
-	0x7b0: 0x2000, 0x7b1: 0x2000, 0x7b2: 0x2000, 0x7b3: 0x2000, 0x7b4: 0x2000, 0x7b5: 0x2000,
-	0x7b6: 0x2000, 0x7b7: 0x2000, 0x7b8: 0x2000, 0x7b9: 0x2000, 0x7ba: 0x2000, 0x7bb: 0x2000,
-	0x7bc: 0x2000, 0x7bd: 0x2000, 0x7be: 0x2000, 0x7bf: 0x2000,
-	// Block 0x1f, offset 0x7c0
-	0x7c0: 0x2000, 0x7c1: 0x2000, 0x7c2: 0x2000, 0x7c3: 0x2000, 0x7c4: 0x2000, 0x7c5: 0x2000,
-	0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7c9: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000,
-	0x7cc: 0x2000, 0x7cd: 0x2000, 0x7ce: 0x2000, 0x7cf: 0x2000, 0x7d0: 0x2000, 0x7d1: 0x2000,
-	0x7d2: 0x2000, 0x7d3: 0x2000, 0x7d4: 0x2000, 0x7d5: 0x2000, 0x7d6: 0x2000, 0x7d7: 0x2000,
-	0x7d8: 0x2000, 0x7d9: 0x2000, 0x7da: 0x2000, 0x7db: 0x2000, 0x7dc: 0x2000, 0x7dd: 0x2000,
-	0x7de: 0x2000, 0x7df: 0x2000, 0x7e0: 0x2000, 0x7e1: 0x2000, 0x7e2: 0x2000, 0x7e3: 0x2000,
-	0x7e4: 0x2000, 0x7e5: 0x2000, 0x7e6: 0x2000, 0x7e7: 0x2000, 0x7e8: 0x2000, 0x7e9: 0x2000,
-	0x7eb: 0x2000, 0x7ec: 0x2000, 0x7ed: 0x2000, 0x7ee: 0x2000, 0x7ef: 0x2000,
-	0x7f0: 0x2000, 0x7f1: 0x2000, 0x7f2: 0x2000, 0x7f3: 0x2000, 0x7f4: 0x2000, 0x7f5: 0x2000,
-	0x7f6: 0x2000, 0x7f7: 0x2000, 0x7f8: 0x2000, 0x7f9: 0x2000, 0x7fa: 0x2000, 0x7fb: 0x2000,
-	0x7fc: 0x2000, 0x7fd: 0x2000, 0x7fe: 0x2000, 0x7ff: 0x2000,
-	// Block 0x20, offset 0x800
-	0x800: 0x2000, 0x801: 0x2000, 0x802: 0x200d, 0x803: 0x2000, 0x804: 0x2000, 0x805: 0x2000,
-	0x806: 0x2000, 0x807: 0x2000, 0x808: 0x2000, 0x809: 0x2000, 0x80a: 0x2000, 0x80b: 0x2000,
-	0x80c: 0x2000, 0x80d: 0x2000, 0x80e: 0x2000, 0x80f: 0x2000, 0x810: 0x2000, 0x811: 0x2000,
-	0x812: 0x2000, 0x813: 0x2000, 0x814: 0x2000, 0x815: 0x2000, 0x816: 0x2000, 0x817: 0x2000,
-	0x818: 0x2000, 0x819: 0x2000, 0x81a: 0x2000, 0x81b: 0x2000, 0x81c: 0x2000, 0x81d: 0x2000,
-	0x81e: 0x2000, 0x81f: 0x2000, 0x820: 0x2000, 0x821: 0x2000, 0x822: 0x2000, 0x823: 0x2000,
-	0x824: 0x2000, 0x825: 0x2000, 0x826: 0x2000, 0x827: 0x2000, 0x828: 0x2000, 0x829: 0x2000,
-	0x82a: 0x2000, 0x82b: 0x2000, 0x82c: 0x2000, 0x82d: 0x2000, 0x82e: 0x2000, 0x82f: 0x2000,
-	0x830: 0x2000, 0x831: 0x2000, 0x832: 0x2000, 0x833: 0x2000, 0x834: 0x2000, 0x835: 0x2000,
-	0x836: 0x2000, 0x837: 0x2000, 0x838: 0x2000, 0x839: 0x2000, 0x83a: 0x2000, 0x83b: 0x2000,
-	0x83c: 0x2000, 0x83d: 0x2000, 0x83e: 0x2000, 0x83f: 0x2000,
-	// Block 0x21, offset 0x840
-	0x840: 0x2000, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, 0x845: 0x2000,
-	0x846: 0x2000, 0x847: 0x2000, 0x848: 0x2000, 0x849: 0x2000, 0x84a: 0x2000, 0x84b: 0x2000,
-	0x850: 0x2000, 0x851: 0x2000,
-	0x852: 0x2000, 0x853: 0x2000, 0x854: 0x2000, 0x855: 0x2000, 0x856: 0x2000, 0x857: 0x2000,
-	0x858: 0x2000, 0x859: 0x2000, 0x85a: 0x2000, 0x85b: 0x2000, 0x85c: 0x2000, 0x85d: 0x2000,
-	0x85e: 0x2000, 0x85f: 0x2000, 0x860: 0x2000, 0x861: 0x2000, 0x862: 0x2000, 0x863: 0x2000,
-	0x864: 0x2000, 0x865: 0x2000, 0x866: 0x2000, 0x867: 0x2000, 0x868: 0x2000, 0x869: 0x2000,
-	0x86a: 0x2000, 0x86b: 0x2000, 0x86c: 0x2000, 0x86d: 0x2000, 0x86e: 0x2000, 0x86f: 0x2000,
-	0x870: 0x2000, 0x871: 0x2000, 0x872: 0x2000, 0x873: 0x2000,
-	// Block 0x22, offset 0x880
-	0x880: 0x2000, 0x881: 0x2000, 0x882: 0x2000, 0x883: 0x2000, 0x884: 0x2000, 0x885: 0x2000,
-	0x886: 0x2000, 0x887: 0x2000, 0x888: 0x2000, 0x889: 0x2000, 0x88a: 0x2000, 0x88b: 0x2000,
-	0x88c: 0x2000, 0x88d: 0x2000, 0x88e: 0x2000, 0x88f: 0x2000,
-	0x892: 0x2000, 0x893: 0x2000, 0x894: 0x2000, 0x895: 0x2000,
-	0x8a0: 0x200e, 0x8a1: 0x2000, 0x8a3: 0x2000,
-	0x8a4: 0x2000, 0x8a5: 0x2000, 0x8a6: 0x2000, 0x8a7: 0x2000, 0x8a8: 0x2000, 0x8a9: 0x2000,
-	0x8b2: 0x2000, 0x8b3: 0x2000,
-	0x8b6: 0x2000, 0x8b7: 0x2000,
-	0x8bc: 0x2000, 0x8bd: 0x2000,
-	// Block 0x23, offset 0x8c0
-	0x8c0: 0x2000, 0x8c1: 0x2000,
-	0x8c6: 0x2000, 0x8c7: 0x2000, 0x8c8: 0x2000, 0x8cb: 0x200f,
-	0x8ce: 0x2000, 0x8cf: 0x2000, 0x8d0: 0x2000, 0x8d1: 0x2000,
-	0x8e2: 0x2000, 0x8e3: 0x2000,
-	0x8e4: 0x2000, 0x8e5: 0x2000,
-	0x8ef: 0x2000,
-	0x8fd: 0x4000, 0x8fe: 0x4000,
-	// Block 0x24, offset 0x900
-	0x905: 0x2000,
-	0x906: 0x2000, 0x909: 0x2000,
-	0x90e: 0x2000, 0x90f: 0x2000,
-	0x914: 0x4000, 0x915: 0x4000,
-	0x91c: 0x2000,
-	0x91e: 0x2000,
-	// Block 0x25, offset 0x940
-	0x940: 0x2000, 0x942: 0x2000,
-	0x948: 0x4000, 0x949: 0x4000, 0x94a: 0x4000, 0x94b: 0x4000,
-	0x94c: 0x4000, 0x94d: 0x4000, 0x94e: 0x4000, 0x94f: 0x4000, 0x950: 0x4000, 0x951: 0x4000,
-	0x952: 0x4000, 0x953: 0x4000,
-	0x960: 0x2000, 0x961: 0x2000, 0x963: 0x2000,
-	0x964: 0x2000, 0x965: 0x2000, 0x967: 0x2000, 0x968: 0x2000, 0x969: 0x2000,
-	0x96a: 0x2000, 0x96c: 0x2000, 0x96d: 0x2000, 0x96f: 0x2000,
-	0x97f: 0x4000,
-	// Block 0x26, offset 0x980
-	0x993: 0x4000,
-	0x99e: 0x2000, 0x99f: 0x2000, 0x9a1: 0x4000,
-	0x9aa: 0x4000, 0x9ab: 0x4000,
-	0x9bd: 0x4000, 0x9be: 0x4000, 0x9bf: 0x2000,
-	// Block 0x27, offset 0x9c0
-	0x9c4: 0x4000, 0x9c5: 0x4000,
-	0x9c6: 0x2000, 0x9c7: 0x2000, 0x9c8: 0x2000, 0x9c9: 0x2000, 0x9ca: 0x2000, 0x9cb: 0x2000,
-	0x9cc: 0x2000, 0x9cd: 0x2000, 0x9ce: 0x4000, 0x9cf: 0x2000, 0x9d0: 0x2000, 0x9d1: 0x2000,
-	0x9d2: 0x2000, 0x9d3: 0x2000, 0x9d4: 0x4000, 0x9d5: 0x2000, 0x9d6: 0x2000, 0x9d7: 0x2000,
-	0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000,
-	0x9de: 0x2000, 0x9df: 0x2000, 0x9e0: 0x2000, 0x9e1: 0x2000, 0x9e3: 0x2000,
-	0x9e8: 0x2000, 0x9e9: 0x2000,
-	0x9ea: 0x4000, 0x9eb: 0x2000, 0x9ec: 0x2000, 0x9ed: 0x2000, 0x9ee: 0x2000, 0x9ef: 0x2000,
-	0x9f0: 0x2000, 0x9f1: 0x2000, 0x9f2: 0x4000, 0x9f3: 0x4000, 0x9f4: 0x2000, 0x9f5: 0x4000,
-	0x9f6: 0x2000, 0x9f7: 0x2000, 0x9f8: 0x2000, 0x9f9: 0x2000, 0x9fa: 0x4000, 0x9fb: 0x2000,
-	0x9fc: 0x2000, 0x9fd: 0x4000, 0x9fe: 0x2000, 0x9ff: 0x2000,
-	// Block 0x28, offset 0xa00
-	0xa05: 0x4000,
-	0xa0a: 0x4000, 0xa0b: 0x4000,
-	0xa28: 0x4000,
-	0xa3d: 0x2000,
-	// Block 0x29, offset 0xa40
-	0xa4c: 0x4000, 0xa4e: 0x4000,
-	0xa53: 0x4000, 0xa54: 0x4000, 0xa55: 0x4000, 0xa57: 0x4000,
-	0xa76: 0x2000, 0xa77: 0x2000, 0xa78: 0x2000, 0xa79: 0x2000, 0xa7a: 0x2000, 0xa7b: 0x2000,
-	0xa7c: 0x2000, 0xa7d: 0x2000, 0xa7e: 0x2000, 0xa7f: 0x2000,
-	// Block 0x2a, offset 0xa80
-	0xa95: 0x4000, 0xa96: 0x4000, 0xa97: 0x4000,
-	0xab0: 0x4000,
-	0xabf: 0x4000,
-	// Block 0x2b, offset 0xac0
-	0xae6: 0x6000, 0xae7: 0x6000, 0xae8: 0x6000, 0xae9: 0x6000,
-	0xaea: 0x6000, 0xaeb: 0x6000, 0xaec: 0x6000, 0xaed: 0x6000,
-	// Block 0x2c, offset 0xb00
-	0xb05: 0x6010,
-	0xb06: 0x6011,
-	// Block 0x2d, offset 0xb40
-	0xb5b: 0x4000, 0xb5c: 0x4000,
-	// Block 0x2e, offset 0xb80
-	0xb90: 0x4000,
-	0xb95: 0x4000, 0xb96: 0x2000, 0xb97: 0x2000,
-	0xb98: 0x2000, 0xb99: 0x2000,
-	// Block 0x2f, offset 0xbc0
-	0xbc0: 0x4000, 0xbc1: 0x4000, 0xbc2: 0x4000, 0xbc3: 0x4000, 0xbc4: 0x4000, 0xbc5: 0x4000,
-	0xbc6: 0x4000, 0xbc7: 0x4000, 0xbc8: 0x4000, 0xbc9: 0x4000, 0xbca: 0x4000, 0xbcb: 0x4000,
-	0xbcc: 0x4000, 0xbcd: 0x4000, 0xbce: 0x4000, 0xbcf: 0x4000, 0xbd0: 0x4000, 0xbd1: 0x4000,
-	0xbd2: 0x4000, 0xbd3: 0x4000, 0xbd4: 0x4000, 0xbd5: 0x4000, 0xbd6: 0x4000, 0xbd7: 0x4000,
-	0xbd8: 0x4000, 0xbd9: 0x4000, 0xbdb: 0x4000, 0xbdc: 0x4000, 0xbdd: 0x4000,
-	0xbde: 0x4000, 0xbdf: 0x4000, 0xbe0: 0x4000, 0xbe1: 0x4000, 0xbe2: 0x4000, 0xbe3: 0x4000,
-	0xbe4: 0x4000, 0xbe5: 0x4000, 0xbe6: 0x4000, 0xbe7: 0x4000, 0xbe8: 0x4000, 0xbe9: 0x4000,
-	0xbea: 0x4000, 0xbeb: 0x4000, 0xbec: 0x4000, 0xbed: 0x4000, 0xbee: 0x4000, 0xbef: 0x4000,
-	0xbf0: 0x4000, 0xbf1: 0x4000, 0xbf2: 0x4000, 0xbf3: 0x4000, 0xbf4: 0x4000, 0xbf5: 0x4000,
-	0xbf6: 0x4000, 0xbf7: 0x4000, 0xbf8: 0x4000, 0xbf9: 0x4000, 0xbfa: 0x4000, 0xbfb: 0x4000,
-	0xbfc: 0x4000, 0xbfd: 0x4000, 0xbfe: 0x4000, 0xbff: 0x4000,
-	// Block 0x30, offset 0xc00
-	0xc00: 0x4000, 0xc01: 0x4000, 0xc02: 0x4000, 0xc03: 0x4000, 0xc04: 0x4000, 0xc05: 0x4000,
-	0xc06: 0x4000, 0xc07: 0x4000, 0xc08: 0x4000, 0xc09: 0x4000, 0xc0a: 0x4000, 0xc0b: 0x4000,
-	0xc0c: 0x4000, 0xc0d: 0x4000, 0xc0e: 0x4000, 0xc0f: 0x4000, 0xc10: 0x4000, 0xc11: 0x4000,
-	0xc12: 0x4000, 0xc13: 0x4000, 0xc14: 0x4000, 0xc15: 0x4000, 0xc16: 0x4000, 0xc17: 0x4000,
-	0xc18: 0x4000, 0xc19: 0x4000, 0xc1a: 0x4000, 0xc1b: 0x4000, 0xc1c: 0x4000, 0xc1d: 0x4000,
-	0xc1e: 0x4000, 0xc1f: 0x4000, 0xc20: 0x4000, 0xc21: 0x4000, 0xc22: 0x4000, 0xc23: 0x4000,
-	0xc24: 0x4000, 0xc25: 0x4000, 0xc26: 0x4000, 0xc27: 0x4000, 0xc28: 0x4000, 0xc29: 0x4000,
-	0xc2a: 0x4000, 0xc2b: 0x4000, 0xc2c: 0x4000, 0xc2d: 0x4000, 0xc2e: 0x4000, 0xc2f: 0x4000,
-	0xc30: 0x4000, 0xc31: 0x4000, 0xc32: 0x4000, 0xc33: 0x4000,
-	// Block 0x31, offset 0xc40
-	0xc40: 0x4000, 0xc41: 0x4000, 0xc42: 0x4000, 0xc43: 0x4000, 0xc44: 0x4000, 0xc45: 0x4000,
-	0xc46: 0x4000, 0xc47: 0x4000, 0xc48: 0x4000, 0xc49: 0x4000, 0xc4a: 0x4000, 0xc4b: 0x4000,
-	0xc4c: 0x4000, 0xc4d: 0x4000, 0xc4e: 0x4000, 0xc4f: 0x4000, 0xc50: 0x4000, 0xc51: 0x4000,
-	0xc52: 0x4000, 0xc53: 0x4000, 0xc54: 0x4000, 0xc55: 0x4000,
-	0xc70: 0x4000, 0xc71: 0x4000, 0xc72: 0x4000, 0xc73: 0x4000, 0xc74: 0x4000, 0xc75: 0x4000,
-	0xc76: 0x4000, 0xc77: 0x4000, 0xc78: 0x4000, 0xc79: 0x4000, 0xc7a: 0x4000, 0xc7b: 0x4000,
-	// Block 0x32, offset 0xc80
-	0xc80: 0x9012, 0xc81: 0x4013, 0xc82: 0x4014, 0xc83: 0x4000, 0xc84: 0x4000, 0xc85: 0x4000,
-	0xc86: 0x4000, 0xc87: 0x4000, 0xc88: 0x4000, 0xc89: 0x4000, 0xc8a: 0x4000, 0xc8b: 0x4000,
-	0xc8c: 0x4015, 0xc8d: 0x4015, 0xc8e: 0x4000, 0xc8f: 0x4000, 0xc90: 0x4000, 0xc91: 0x4000,
-	0xc92: 0x4000, 0xc93: 0x4000, 0xc94: 0x4000, 0xc95: 0x4000, 0xc96: 0x4000, 0xc97: 0x4000,
-	0xc98: 0x4000, 0xc99: 0x4000, 0xc9a: 0x4000, 0xc9b: 0x4000, 0xc9c: 0x4000, 0xc9d: 0x4000,
-	0xc9e: 0x4000, 0xc9f: 0x4000, 0xca0: 0x4000, 0xca1: 0x4000, 0xca2: 0x4000, 0xca3: 0x4000,
-	0xca4: 0x4000, 0xca5: 0x4000, 0xca6: 0x4000, 0xca7: 0x4000, 0xca8: 0x4000, 0xca9: 0x4000,
-	0xcaa: 0x4000, 0xcab: 0x4000, 0xcac: 0x4000, 0xcad: 0x4000, 0xcae: 0x4000, 0xcaf: 0x4000,
-	0xcb0: 0x4000, 0xcb1: 0x4000, 0xcb2: 0x4000, 0xcb3: 0x4000, 0xcb4: 0x4000, 0xcb5: 0x4000,
-	0xcb6: 0x4000, 0xcb7: 0x4000, 0xcb8: 0x4000, 0xcb9: 0x4000, 0xcba: 0x4000, 0xcbb: 0x4000,
-	0xcbc: 0x4000, 0xcbd: 0x4000, 0xcbe: 0x4000,
-	// Block 0x33, offset 0xcc0
-	0xcc1: 0x4000, 0xcc2: 0x4000, 0xcc3: 0x4000, 0xcc4: 0x4000, 0xcc5: 0x4000,
-	0xcc6: 0x4000, 0xcc7: 0x4000, 0xcc8: 0x4000, 0xcc9: 0x4000, 0xcca: 0x4000, 0xccb: 0x4000,
-	0xccc: 0x4000, 0xccd: 0x4000, 0xcce: 0x4000, 0xccf: 0x4000, 0xcd0: 0x4000, 0xcd1: 0x4000,
-	0xcd2: 0x4000, 0xcd3: 0x4000, 0xcd4: 0x4000, 0xcd5: 0x4000, 0xcd6: 0x4000, 0xcd7: 0x4000,
-	0xcd8: 0x4000, 0xcd9: 0x4000, 0xcda: 0x4000, 0xcdb: 0x4000, 0xcdc: 0x4000, 0xcdd: 0x4000,
-	0xcde: 0x4000, 0xcdf: 0x4000, 0xce0: 0x4000, 0xce1: 0x4000, 0xce2: 0x4000, 0xce3: 0x4000,
-	0xce4: 0x4000, 0xce5: 0x4000, 0xce6: 0x4000, 0xce7: 0x4000, 0xce8: 0x4000, 0xce9: 0x4000,
-	0xcea: 0x4000, 0xceb: 0x4000, 0xcec: 0x4000, 0xced: 0x4000, 0xcee: 0x4000, 0xcef: 0x4000,
-	0xcf0: 0x4000, 0xcf1: 0x4000, 0xcf2: 0x4000, 0xcf3: 0x4000, 0xcf4: 0x4000, 0xcf5: 0x4000,
-	0xcf6: 0x4000, 0xcf7: 0x4000, 0xcf8: 0x4000, 0xcf9: 0x4000, 0xcfa: 0x4000, 0xcfb: 0x4000,
-	0xcfc: 0x4000, 0xcfd: 0x4000, 0xcfe: 0x4000, 0xcff: 0x4000,
-	// Block 0x34, offset 0xd00
-	0xd00: 0x4000, 0xd01: 0x4000, 0xd02: 0x4000, 0xd03: 0x4000, 0xd04: 0x4000, 0xd05: 0x4000,
-	0xd06: 0x4000, 0xd07: 0x4000, 0xd08: 0x4000, 0xd09: 0x4000, 0xd0a: 0x4000, 0xd0b: 0x4000,
-	0xd0c: 0x4000, 0xd0d: 0x4000, 0xd0e: 0x4000, 0xd0f: 0x4000, 0xd10: 0x4000, 0xd11: 0x4000,
-	0xd12: 0x4000, 0xd13: 0x4000, 0xd14: 0x4000, 0xd15: 0x4000, 0xd16: 0x4000,
-	0xd19: 0x4016, 0xd1a: 0x4017, 0xd1b: 0x4000, 0xd1c: 0x4000, 0xd1d: 0x4000,
-	0xd1e: 0x4000, 0xd1f: 0x4000, 0xd20: 0x4000, 0xd21: 0x4018, 0xd22: 0x4019, 0xd23: 0x401a,
-	0xd24: 0x401b, 0xd25: 0x401c, 0xd26: 0x401d, 0xd27: 0x401e, 0xd28: 0x401f, 0xd29: 0x4020,
-	0xd2a: 0x4021, 0xd2b: 0x4022, 0xd2c: 0x4000, 0xd2d: 0x4010, 0xd2e: 0x4000, 0xd2f: 0x4023,
-	0xd30: 0x4000, 0xd31: 0x4024, 0xd32: 0x4000, 0xd33: 0x4025, 0xd34: 0x4000, 0xd35: 0x4026,
-	0xd36: 0x4000, 0xd37: 0x401a, 0xd38: 0x4000, 0xd39: 0x4027, 0xd3a: 0x4000, 0xd3b: 0x4028,
-	0xd3c: 0x4000, 0xd3d: 0x4020, 0xd3e: 0x4000, 0xd3f: 0x4029,
-	// Block 0x35, offset 0xd40
-	0xd40: 0x4000, 0xd41: 0x402a, 0xd42: 0x4000, 0xd43: 0x402b, 0xd44: 0x402c, 0xd45: 0x4000,
-	0xd46: 0x4017, 0xd47: 0x4000, 0xd48: 0x402d, 0xd49: 0x4000, 0xd4a: 0x402e, 0xd4b: 0x402f,
-	0xd4c: 0x4030, 0xd4d: 0x4017, 0xd4e: 0x4016, 0xd4f: 0x4017, 0xd50: 0x4000, 0xd51: 0x4000,
-	0xd52: 0x4031, 0xd53: 0x4000, 0xd54: 0x4000, 0xd55: 0x4031, 0xd56: 0x4000, 0xd57: 0x4000,
-	0xd58: 0x4032, 0xd59: 0x4000, 0xd5a: 0x4000, 0xd5b: 0x4032, 0xd5c: 0x4000, 0xd5d: 0x4000,
-	0xd5e: 0x4033, 0xd5f: 0x402e, 0xd60: 0x4034, 0xd61: 0x4035, 0xd62: 0x4034, 0xd63: 0x4036,
-	0xd64: 0x4037, 0xd65: 0x4024, 0xd66: 0x4035, 0xd67: 0x4025, 0xd68: 0x4038, 0xd69: 0x4038,
-	0xd6a: 0x4039, 0xd6b: 0x4039, 0xd6c: 0x403a, 0xd6d: 0x403a, 0xd6e: 0x4000, 0xd6f: 0x4035,
-	0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x403b, 0xd73: 0x403c, 0xd74: 0x4000, 0xd75: 0x4000,
-	0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x403d,
-	0xd7c: 0x401c, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000,
-	// Block 0x36, offset 0xd80
-	0xd85: 0x4000,
-	0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000,
-	0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000,
-	0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000,
-	0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000,
-	0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000,
-	0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000,
-	0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000,
-	0xdb1: 0x403e, 0xdb2: 0x403e, 0xdb3: 0x403e, 0xdb4: 0x403e, 0xdb5: 0x403e,
-	0xdb6: 0x403e, 0xdb7: 0x403e, 0xdb8: 0x403e, 0xdb9: 0x403e, 0xdba: 0x403e, 0xdbb: 0x403e,
-	0xdbc: 0x403e, 0xdbd: 0x403e, 0xdbe: 0x403e, 0xdbf: 0x403e,
-	// Block 0x37, offset 0xdc0
-	0xdc0: 0x4037, 0xdc1: 0x4037, 0xdc2: 0x4037, 0xdc3: 0x4037, 0xdc4: 0x4037, 0xdc5: 0x4037,
-	0xdc6: 0x4037, 0xdc7: 0x4037, 0xdc8: 0x4037, 0xdc9: 0x4037, 0xdca: 0x4037, 0xdcb: 0x4037,
-	0xdcc: 0x4037, 0xdcd: 0x4037, 0xdce: 0x4037, 0xdcf: 0x400e, 0xdd0: 0x403f, 0xdd1: 0x4040,
-	0xdd2: 0x4041, 0xdd3: 0x4040, 0xdd4: 0x403f, 0xdd5: 0x4042, 0xdd6: 0x4043, 0xdd7: 0x4044,
-	0xdd8: 0x4040, 0xdd9: 0x4041, 0xdda: 0x4040, 0xddb: 0x4045, 0xddc: 0x4009, 0xddd: 0x4045,
-	0xdde: 0x4046, 0xddf: 0x4045, 0xde0: 0x4047, 0xde1: 0x400b, 0xde2: 0x400a, 0xde3: 0x400c,
-	0xde4: 0x4048, 0xde5: 0x4000, 0xde6: 0x4000, 0xde7: 0x4000, 0xde8: 0x4000, 0xde9: 0x4000,
-	0xdea: 0x4000, 0xdeb: 0x4000, 0xdec: 0x4000, 0xded: 0x4000, 0xdee: 0x4000, 0xdef: 0x4000,
-	0xdf0: 0x4000, 0xdf1: 0x4000, 0xdf2: 0x4000, 0xdf3: 0x4000, 0xdf4: 0x4000, 0xdf5: 0x4000,
-	0xdf6: 0x4000, 0xdf7: 0x4000, 0xdf8: 0x4000, 0xdf9: 0x4000, 0xdfa: 0x4000, 0xdfb: 0x4000,
-	0xdfc: 0x4000, 0xdfd: 0x4000, 0xdfe: 0x4000, 0xdff: 0x4000,
-	// Block 0x38, offset 0xe00
-	0xe00: 0x4000, 0xe01: 0x4000, 0xe02: 0x4000, 0xe03: 0x4000, 0xe04: 0x4000, 0xe05: 0x4000,
-	0xe06: 0x4000, 0xe07: 0x4000, 0xe08: 0x4000, 0xe09: 0x4000, 0xe0a: 0x4000, 0xe0b: 0x4000,
-	0xe0c: 0x4000, 0xe0d: 0x4000, 0xe0e: 0x4000, 0xe10: 0x4000, 0xe11: 0x4000,
-	0xe12: 0x4000, 0xe13: 0x4000, 0xe14: 0x4000, 0xe15: 0x4000, 0xe16: 0x4000, 0xe17: 0x4000,
-	0xe18: 0x4000, 0xe19: 0x4000, 0xe1a: 0x4000, 0xe1b: 0x4000, 0xe1c: 0x4000, 0xe1d: 0x4000,
-	0xe1e: 0x4000, 0xe1f: 0x4000, 0xe20: 0x4000, 0xe21: 0x4000, 0xe22: 0x4000, 0xe23: 0x4000,
-	0xe24: 0x4000, 0xe25: 0x4000, 0xe26: 0x4000, 0xe27: 0x4000, 0xe28: 0x4000, 0xe29: 0x4000,
-	0xe2a: 0x4000, 0xe2b: 0x4000, 0xe2c: 0x4000, 0xe2d: 0x4000, 0xe2e: 0x4000, 0xe2f: 0x4000,
-	0xe30: 0x4000, 0xe31: 0x4000, 0xe32: 0x4000, 0xe33: 0x4000, 0xe34: 0x4000, 0xe35: 0x4000,
-	0xe36: 0x4000, 0xe37: 0x4000, 0xe38: 0x4000, 0xe39: 0x4000, 0xe3a: 0x4000,
-	// Block 0x39, offset 0xe40
-	0xe40: 0x4000, 0xe41: 0x4000, 0xe42: 0x4000, 0xe43: 0x4000, 0xe44: 0x4000, 0xe45: 0x4000,
-	0xe46: 0x4000, 0xe47: 0x4000, 0xe48: 0x4000, 0xe49: 0x4000, 0xe4a: 0x4000, 0xe4b: 0x4000,
-	0xe4c: 0x4000, 0xe4d: 0x4000, 0xe4e: 0x4000, 0xe4f: 0x4000, 0xe50: 0x4000, 0xe51: 0x4000,
-	0xe52: 0x4000, 0xe53: 0x4000, 0xe54: 0x4000, 0xe55: 0x4000, 0xe56: 0x4000, 0xe57: 0x4000,
-	0xe58: 0x4000, 0xe59: 0x4000, 0xe5a: 0x4000, 0xe5b: 0x4000, 0xe5c: 0x4000, 0xe5d: 0x4000,
-	0xe5e: 0x4000, 0xe5f: 0x4000, 0xe60: 0x4000, 0xe61: 0x4000, 0xe62: 0x4000, 0xe63: 0x4000,
-	0xe70: 0x4000, 0xe71: 0x4000, 0xe72: 0x4000, 0xe73: 0x4000, 0xe74: 0x4000, 0xe75: 0x4000,
-	0xe76: 0x4000, 0xe77: 0x4000, 0xe78: 0x4000, 0xe79: 0x4000, 0xe7a: 0x4000, 0xe7b: 0x4000,
-	0xe7c: 0x4000, 0xe7d: 0x4000, 0xe7e: 0x4000, 0xe7f: 0x4000,
-	// Block 0x3a, offset 0xe80
-	0xe80: 0x4000, 0xe81: 0x4000, 0xe82: 0x4000, 0xe83: 0x4000, 0xe84: 0x4000, 0xe85: 0x4000,
-	0xe86: 0x4000, 0xe87: 0x4000, 0xe88: 0x4000, 0xe89: 0x4000, 0xe8a: 0x4000, 0xe8b: 0x4000,
-	0xe8c: 0x4000, 0xe8d: 0x4000, 0xe8e: 0x4000, 0xe8f: 0x4000, 0xe90: 0x4000, 0xe91: 0x4000,
-	0xe92: 0x4000, 0xe93: 0x4000, 0xe94: 0x4000, 0xe95: 0x4000, 0xe96: 0x4000, 0xe97: 0x4000,
-	0xe98: 0x4000, 0xe99: 0x4000, 0xe9a: 0x4000, 0xe9b: 0x4000, 0xe9c: 0x4000, 0xe9d: 0x4000,
-	0xe9e: 0x4000, 0xea0: 0x4000, 0xea1: 0x4000, 0xea2: 0x4000, 0xea3: 0x4000,
-	0xea4: 0x4000, 0xea5: 0x4000, 0xea6: 0x4000, 0xea7: 0x4000, 0xea8: 0x4000, 0xea9: 0x4000,
-	0xeaa: 0x4000, 0xeab: 0x4000, 0xeac: 0x4000, 0xead: 0x4000, 0xeae: 0x4000, 0xeaf: 0x4000,
-	0xeb0: 0x4000, 0xeb1: 0x4000, 0xeb2: 0x4000, 0xeb3: 0x4000, 0xeb4: 0x4000, 0xeb5: 0x4000,
-	0xeb6: 0x4000, 0xeb7: 0x4000, 0xeb8: 0x4000, 0xeb9: 0x4000, 0xeba: 0x4000, 0xebb: 0x4000,
-	0xebc: 0x4000, 0xebd: 0x4000, 0xebe: 0x4000, 0xebf: 0x4000,
-	// Block 0x3b, offset 0xec0
-	0xec0: 0x4000, 0xec1: 0x4000, 0xec2: 0x4000, 0xec3: 0x4000, 0xec4: 0x4000, 0xec5: 0x4000,
-	0xec6: 0x4000, 0xec7: 0x4000, 0xec8: 0x2000, 0xec9: 0x2000, 0xeca: 0x2000, 0xecb: 0x2000,
-	0xecc: 0x2000, 0xecd: 0x2000, 0xece: 0x2000, 0xecf: 0x2000, 0xed0: 0x4000, 0xed1: 0x4000,
-	0xed2: 0x4000, 0xed3: 0x4000, 0xed4: 0x4000, 0xed5: 0x4000, 0xed6: 0x4000, 0xed7: 0x4000,
-	0xed8: 0x4000, 0xed9: 0x4000, 0xeda: 0x4000, 0xedb: 0x4000, 0xedc: 0x4000, 0xedd: 0x4000,
-	0xede: 0x4000, 0xedf: 0x4000, 0xee0: 0x4000, 0xee1: 0x4000, 0xee2: 0x4000, 0xee3: 0x4000,
-	0xee4: 0x4000, 0xee5: 0x4000, 0xee6: 0x4000, 0xee7: 0x4000, 0xee8: 0x4000, 0xee9: 0x4000,
-	0xeea: 0x4000, 0xeeb: 0x4000, 0xeec: 0x4000, 0xeed: 0x4000, 0xeee: 0x4000, 0xeef: 0x4000,
-	0xef0: 0x4000, 0xef1: 0x4000, 0xef2: 0x4000, 0xef3: 0x4000, 0xef4: 0x4000, 0xef5: 0x4000,
-	0xef6: 0x4000, 0xef7: 0x4000, 0xef8: 0x4000, 0xef9: 0x4000, 0xefa: 0x4000, 0xefb: 0x4000,
-	0xefc: 0x4000, 0xefd: 0x4000, 0xefe: 0x4000, 0xeff: 0x4000,
-	// Block 0x3c, offset 0xf00
-	0xf00: 0x4000, 0xf01: 0x4000, 0xf02: 0x4000, 0xf03: 0x4000, 0xf04: 0x4000, 0xf05: 0x4000,
-	0xf06: 0x4000, 0xf07: 0x4000, 0xf08: 0x4000, 0xf09: 0x4000, 0xf0a: 0x4000, 0xf0b: 0x4000,
-	0xf0c: 0x4000, 0xf0d: 0x4000, 0xf0e: 0x4000, 0xf0f: 0x4000, 0xf10: 0x4000, 0xf11: 0x4000,
-	0xf12: 0x4000, 0xf13: 0x4000, 0xf14: 0x4000, 0xf15: 0x4000, 0xf16: 0x4000, 0xf17: 0x4000,
-	0xf18: 0x4000, 0xf19: 0x4000, 0xf1a: 0x4000, 0xf1b: 0x4000, 0xf1c: 0x4000, 0xf1d: 0x4000,
-	0xf1e: 0x4000, 0xf1f: 0x4000, 0xf20: 0x4000, 0xf21: 0x4000, 0xf22: 0x4000, 0xf23: 0x4000,
-	0xf24: 0x4000, 0xf25: 0x4000, 0xf26: 0x4000, 0xf27: 0x4000, 0xf28: 0x4000, 0xf29: 0x4000,
-	0xf2a: 0x4000, 0xf2b: 0x4000, 0xf2c: 0x4000, 0xf2d: 0x4000, 0xf2e: 0x4000, 0xf2f: 0x4000,
-	0xf30: 0x4000, 0xf31: 0x4000, 0xf32: 0x4000, 0xf33: 0x4000, 0xf34: 0x4000, 0xf35: 0x4000,
-	0xf36: 0x4000, 0xf37: 0x4000, 0xf38: 0x4000, 0xf39: 0x4000, 0xf3a: 0x4000, 0xf3b: 0x4000,
-	0xf3c: 0x4000, 0xf3d: 0x4000, 0xf3e: 0x4000,
-	// Block 0x3d, offset 0xf40
-	0xf40: 0x4000, 0xf41: 0x4000, 0xf42: 0x4000, 0xf43: 0x4000, 0xf44: 0x4000, 0xf45: 0x4000,
-	0xf46: 0x4000, 0xf47: 0x4000, 0xf48: 0x4000, 0xf49: 0x4000, 0xf4a: 0x4000, 0xf4b: 0x4000,
-	0xf4c: 0x4000, 0xf50: 0x4000, 0xf51: 0x4000,
-	0xf52: 0x4000, 0xf53: 0x4000, 0xf54: 0x4000, 0xf55: 0x4000, 0xf56: 0x4000, 0xf57: 0x4000,
-	0xf58: 0x4000, 0xf59: 0x4000, 0xf5a: 0x4000, 0xf5b: 0x4000, 0xf5c: 0x4000, 0xf5d: 0x4000,
-	0xf5e: 0x4000, 0xf5f: 0x4000, 0xf60: 0x4000, 0xf61: 0x4000, 0xf62: 0x4000, 0xf63: 0x4000,
-	0xf64: 0x4000, 0xf65: 0x4000, 0xf66: 0x4000, 0xf67: 0x4000, 0xf68: 0x4000, 0xf69: 0x4000,
-	0xf6a: 0x4000, 0xf6b: 0x4000, 0xf6c: 0x4000, 0xf6d: 0x4000, 0xf6e: 0x4000, 0xf6f: 0x4000,
-	0xf70: 0x4000, 0xf71: 0x4000, 0xf72: 0x4000, 0xf73: 0x4000, 0xf74: 0x4000, 0xf75: 0x4000,
-	0xf76: 0x4000, 0xf77: 0x4000, 0xf78: 0x4000, 0xf79: 0x4000, 0xf7a: 0x4000, 0xf7b: 0x4000,
-	0xf7c: 0x4000, 0xf7d: 0x4000, 0xf7e: 0x4000, 0xf7f: 0x4000,
-	// Block 0x3e, offset 0xf80
-	0xf80: 0x4000, 0xf81: 0x4000, 0xf82: 0x4000, 0xf83: 0x4000, 0xf84: 0x4000, 0xf85: 0x4000,
-	0xf86: 0x4000,
-	// Block 0x3f, offset 0xfc0
-	0xfe0: 0x4000, 0xfe1: 0x4000, 0xfe2: 0x4000, 0xfe3: 0x4000,
-	0xfe4: 0x4000, 0xfe5: 0x4000, 0xfe6: 0x4000, 0xfe7: 0x4000, 0xfe8: 0x4000, 0xfe9: 0x4000,
-	0xfea: 0x4000, 0xfeb: 0x4000, 0xfec: 0x4000, 0xfed: 0x4000, 0xfee: 0x4000, 0xfef: 0x4000,
-	0xff0: 0x4000, 0xff1: 0x4000, 0xff2: 0x4000, 0xff3: 0x4000, 0xff4: 0x4000, 0xff5: 0x4000,
-	0xff6: 0x4000, 0xff7: 0x4000, 0xff8: 0x4000, 0xff9: 0x4000, 0xffa: 0x4000, 0xffb: 0x4000,
-	0xffc: 0x4000,
-	// Block 0x40, offset 0x1000
-	0x1000: 0x4000, 0x1001: 0x4000, 0x1002: 0x4000, 0x1003: 0x4000, 0x1004: 0x4000, 0x1005: 0x4000,
-	0x1006: 0x4000, 0x1007: 0x4000, 0x1008: 0x4000, 0x1009: 0x4000, 0x100a: 0x4000, 0x100b: 0x4000,
-	0x100c: 0x4000, 0x100d: 0x4000, 0x100e: 0x4000, 0x100f: 0x4000, 0x1010: 0x4000, 0x1011: 0x4000,
-	0x1012: 0x4000, 0x1013: 0x4000, 0x1014: 0x4000, 0x1015: 0x4000, 0x1016: 0x4000, 0x1017: 0x4000,
-	0x1018: 0x4000, 0x1019: 0x4000, 0x101a: 0x4000, 0x101b: 0x4000, 0x101c: 0x4000, 0x101d: 0x4000,
-	0x101e: 0x4000, 0x101f: 0x4000, 0x1020: 0x4000, 0x1021: 0x4000, 0x1022: 0x4000, 0x1023: 0x4000,
-	// Block 0x41, offset 0x1040
-	0x1040: 0x2000, 0x1041: 0x2000, 0x1042: 0x2000, 0x1043: 0x2000, 0x1044: 0x2000, 0x1045: 0x2000,
-	0x1046: 0x2000, 0x1047: 0x2000, 0x1048: 0x2000, 0x1049: 0x2000, 0x104a: 0x2000, 0x104b: 0x2000,
-	0x104c: 0x2000, 0x104d: 0x2000, 0x104e: 0x2000, 0x104f: 0x2000, 0x1050: 0x4000, 0x1051: 0x4000,
-	0x1052: 0x4000, 0x1053: 0x4000, 0x1054: 0x4000, 0x1055: 0x4000, 0x1056: 0x4000, 0x1057: 0x4000,
-	0x1058: 0x4000, 0x1059: 0x4000,
-	0x1070: 0x4000, 0x1071: 0x4000, 0x1072: 0x4000, 0x1073: 0x4000, 0x1074: 0x4000, 0x1075: 0x4000,
-	0x1076: 0x4000, 0x1077: 0x4000, 0x1078: 0x4000, 0x1079: 0x4000, 0x107a: 0x4000, 0x107b: 0x4000,
-	0x107c: 0x4000, 0x107d: 0x4000, 0x107e: 0x4000, 0x107f: 0x4000,
-	// Block 0x42, offset 0x1080
-	0x1080: 0x4000, 0x1081: 0x4000, 0x1082: 0x4000, 0x1083: 0x4000, 0x1084: 0x4000, 0x1085: 0x4000,
-	0x1086: 0x4000, 0x1087: 0x4000, 0x1088: 0x4000, 0x1089: 0x4000, 0x108a: 0x4000, 0x108b: 0x4000,
-	0x108c: 0x4000, 0x108d: 0x4000, 0x108e: 0x4000, 0x108f: 0x4000, 0x1090: 0x4000, 0x1091: 0x4000,
-	0x1092: 0x4000, 0x1094: 0x4000, 0x1095: 0x4000, 0x1096: 0x4000, 0x1097: 0x4000,
-	0x1098: 0x4000, 0x1099: 0x4000, 0x109a: 0x4000, 0x109b: 0x4000, 0x109c: 0x4000, 0x109d: 0x4000,
-	0x109e: 0x4000, 0x109f: 0x4000, 0x10a0: 0x4000, 0x10a1: 0x4000, 0x10a2: 0x4000, 0x10a3: 0x4000,
-	0x10a4: 0x4000, 0x10a5: 0x4000, 0x10a6: 0x4000, 0x10a8: 0x4000, 0x10a9: 0x4000,
-	0x10aa: 0x4000, 0x10ab: 0x4000,
-	// Block 0x43, offset 0x10c0
-	0x10c1: 0x9012, 0x10c2: 0x9012, 0x10c3: 0x9012, 0x10c4: 0x9012, 0x10c5: 0x9012,
-	0x10c6: 0x9012, 0x10c7: 0x9012, 0x10c8: 0x9012, 0x10c9: 0x9012, 0x10ca: 0x9012, 0x10cb: 0x9012,
-	0x10cc: 0x9012, 0x10cd: 0x9012, 0x10ce: 0x9012, 0x10cf: 0x9012, 0x10d0: 0x9012, 0x10d1: 0x9012,
-	0x10d2: 0x9012, 0x10d3: 0x9012, 0x10d4: 0x9012, 0x10d5: 0x9012, 0x10d6: 0x9012, 0x10d7: 0x9012,
-	0x10d8: 0x9012, 0x10d9: 0x9012, 0x10da: 0x9012, 0x10db: 0x9012, 0x10dc: 0x9012, 0x10dd: 0x9012,
-	0x10de: 0x9012, 0x10df: 0x9012, 0x10e0: 0x9049, 0x10e1: 0x9049, 0x10e2: 0x9049, 0x10e3: 0x9049,
-	0x10e4: 0x9049, 0x10e5: 0x9049, 0x10e6: 0x9049, 0x10e7: 0x9049, 0x10e8: 0x9049, 0x10e9: 0x9049,
-	0x10ea: 0x9049, 0x10eb: 0x9049, 0x10ec: 0x9049, 0x10ed: 0x9049, 0x10ee: 0x9049, 0x10ef: 0x9049,
-	0x10f0: 0x9049, 0x10f1: 0x9049, 0x10f2: 0x9049, 0x10f3: 0x9049, 0x10f4: 0x9049, 0x10f5: 0x9049,
-	0x10f6: 0x9049, 0x10f7: 0x9049, 0x10f8: 0x9049, 0x10f9: 0x9049, 0x10fa: 0x9049, 0x10fb: 0x9049,
-	0x10fc: 0x9049, 0x10fd: 0x9049, 0x10fe: 0x9049, 0x10ff: 0x9049,
-	// Block 0x44, offset 0x1100
-	0x1100: 0x9049, 0x1101: 0x9049, 0x1102: 0x9049, 0x1103: 0x9049, 0x1104: 0x9049, 0x1105: 0x9049,
-	0x1106: 0x9049, 0x1107: 0x9049, 0x1108: 0x9049, 0x1109: 0x9049, 0x110a: 0x9049, 0x110b: 0x9049,
-	0x110c: 0x9049, 0x110d: 0x9049, 0x110e: 0x9049, 0x110f: 0x9049, 0x1110: 0x9049, 0x1111: 0x9049,
-	0x1112: 0x9049, 0x1113: 0x9049, 0x1114: 0x9049, 0x1115: 0x9049, 0x1116: 0x9049, 0x1117: 0x9049,
-	0x1118: 0x9049, 0x1119: 0x9049, 0x111a: 0x9049, 0x111b: 0x9049, 0x111c: 0x9049, 0x111d: 0x9049,
-	0x111e: 0x9049, 0x111f: 0x904a, 0x1120: 0x904b, 0x1121: 0xb04c, 0x1122: 0xb04d, 0x1123: 0xb04d,
-	0x1124: 0xb04e, 0x1125: 0xb04f, 0x1126: 0xb050, 0x1127: 0xb051, 0x1128: 0xb052, 0x1129: 0xb053,
-	0x112a: 0xb054, 0x112b: 0xb055, 0x112c: 0xb056, 0x112d: 0xb057, 0x112e: 0xb058, 0x112f: 0xb059,
-	0x1130: 0xb05a, 0x1131: 0xb05b, 0x1132: 0xb05c, 0x1133: 0xb05d, 0x1134: 0xb05e, 0x1135: 0xb05f,
-	0x1136: 0xb060, 0x1137: 0xb061, 0x1138: 0xb062, 0x1139: 0xb063, 0x113a: 0xb064, 0x113b: 0xb065,
-	0x113c: 0xb052, 0x113d: 0xb066, 0x113e: 0xb067, 0x113f: 0xb055,
-	// Block 0x45, offset 0x1140
-	0x1140: 0xb068, 0x1141: 0xb069, 0x1142: 0xb06a, 0x1143: 0xb06b, 0x1144: 0xb05a, 0x1145: 0xb056,
-	0x1146: 0xb06c, 0x1147: 0xb06d, 0x1148: 0xb06b, 0x1149: 0xb06e, 0x114a: 0xb06b, 0x114b: 0xb06f,
-	0x114c: 0xb06f, 0x114d: 0xb070, 0x114e: 0xb070, 0x114f: 0xb071, 0x1150: 0xb056, 0x1151: 0xb072,
-	0x1152: 0xb073, 0x1153: 0xb072, 0x1154: 0xb074, 0x1155: 0xb073, 0x1156: 0xb075, 0x1157: 0xb075,
-	0x1158: 0xb076, 0x1159: 0xb076, 0x115a: 0xb077, 0x115b: 0xb077, 0x115c: 0xb073, 0x115d: 0xb078,
-	0x115e: 0xb079, 0x115f: 0xb067, 0x1160: 0xb07a, 0x1161: 0xb07b, 0x1162: 0xb07b, 0x1163: 0xb07b,
-	0x1164: 0xb07b, 0x1165: 0xb07b, 0x1166: 0xb07b, 0x1167: 0xb07b, 0x1168: 0xb07b, 0x1169: 0xb07b,
-	0x116a: 0xb07b, 0x116b: 0xb07b, 0x116c: 0xb07b, 0x116d: 0xb07b, 0x116e: 0xb07b, 0x116f: 0xb07b,
-	0x1170: 0xb07c, 0x1171: 0xb07c, 0x1172: 0xb07c, 0x1173: 0xb07c, 0x1174: 0xb07c, 0x1175: 0xb07c,
-	0x1176: 0xb07c, 0x1177: 0xb07c, 0x1178: 0xb07c, 0x1179: 0xb07c, 0x117a: 0xb07c, 0x117b: 0xb07c,
-	0x117c: 0xb07c, 0x117d: 0xb07c, 0x117e: 0xb07c,
-	// Block 0x46, offset 0x1180
-	0x1182: 0xb07d, 0x1183: 0xb07e, 0x1184: 0xb07f, 0x1185: 0xb080,
-	0x1186: 0xb07f, 0x1187: 0xb07e, 0x118a: 0xb081, 0x118b: 0xb082,
-	0x118c: 0xb083, 0x118d: 0xb07f, 0x118e: 0xb080, 0x118f: 0xb07f,
-	0x1192: 0xb084, 0x1193: 0xb085, 0x1194: 0xb084, 0x1195: 0xb086, 0x1196: 0xb084, 0x1197: 0xb087,
-	0x119a: 0xb088, 0x119b: 0xb089, 0x119c: 0xb08a,
-	0x11a0: 0x908b, 0x11a1: 0x908b, 0x11a2: 0x908c, 0x11a3: 0x908d,
-	0x11a4: 0x908b, 0x11a5: 0x908e, 0x11a6: 0x908f, 0x11a8: 0xb090, 0x11a9: 0xb091,
-	0x11aa: 0xb092, 0x11ab: 0xb091, 0x11ac: 0xb093, 0x11ad: 0xb094, 0x11ae: 0xb095,
-	0x11bd: 0x2000,
-	// Block 0x47, offset 0x11c0
-	0x11e0: 0x4000,
-	// Block 0x48, offset 0x1200
-	0x1200: 0x4000, 0x1201: 0x4000, 0x1202: 0x4000, 0x1203: 0x4000, 0x1204: 0x4000, 0x1205: 0x4000,
-	0x1206: 0x4000, 0x1207: 0x4000, 0x1208: 0x4000, 0x1209: 0x4000, 0x120a: 0x4000, 0x120b: 0x4000,
-	0x120c: 0x4000, 0x120d: 0x4000, 0x120e: 0x4000, 0x120f: 0x4000, 0x1210: 0x4000, 0x1211: 0x4000,
-	0x1212: 0x4000, 0x1213: 0x4000, 0x1214: 0x4000, 0x1215: 0x4000, 0x1216: 0x4000, 0x1217: 0x4000,
-	0x1218: 0x4000, 0x1219: 0x4000, 0x121a: 0x4000, 0x121b: 0x4000, 0x121c: 0x4000, 0x121d: 0x4000,
-	0x121e: 0x4000, 0x121f: 0x4000, 0x1220: 0x4000, 0x1221: 0x4000, 0x1222: 0x4000, 0x1223: 0x4000,
-	0x1224: 0x4000, 0x1225: 0x4000, 0x1226: 0x4000, 0x1227: 0x4000, 0x1228: 0x4000, 0x1229: 0x4000,
-	0x122a: 0x4000, 0x122b: 0x4000, 0x122c: 0x4000,
-	// Block 0x49, offset 0x1240
-	0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
-	0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000, 0x1249: 0x4000, 0x124a: 0x4000, 0x124b: 0x4000,
-	0x124c: 0x4000, 0x124d: 0x4000, 0x124e: 0x4000, 0x124f: 0x4000, 0x1250: 0x4000, 0x1251: 0x4000,
-	0x1252: 0x4000, 0x1253: 0x4000, 0x1254: 0x4000, 0x1255: 0x4000, 0x1256: 0x4000, 0x1257: 0x4000,
-	0x1258: 0x4000, 0x1259: 0x4000, 0x125a: 0x4000, 0x125b: 0x4000, 0x125c: 0x4000, 0x125d: 0x4000,
-	0x125e: 0x4000, 0x125f: 0x4000, 0x1260: 0x4000, 0x1261: 0x4000, 0x1262: 0x4000, 0x1263: 0x4000,
-	0x1264: 0x4000, 0x1265: 0x4000, 0x1266: 0x4000, 0x1267: 0x4000, 0x1268: 0x4000, 0x1269: 0x4000,
-	0x126a: 0x4000, 0x126b: 0x4000, 0x126c: 0x4000, 0x126d: 0x4000, 0x126e: 0x4000, 0x126f: 0x4000,
-	0x1270: 0x4000, 0x1271: 0x4000, 0x1272: 0x4000,
-	// Block 0x4a, offset 0x1280
-	0x1280: 0x4000, 0x1281: 0x4000,
-	// Block 0x4b, offset 0x12c0
-	0x12c4: 0x4000,
-	// Block 0x4c, offset 0x1300
-	0x130f: 0x4000,
-	// Block 0x4d, offset 0x1340
-	0x1340: 0x2000, 0x1341: 0x2000, 0x1342: 0x2000, 0x1343: 0x2000, 0x1344: 0x2000, 0x1345: 0x2000,
-	0x1346: 0x2000, 0x1347: 0x2000, 0x1348: 0x2000, 0x1349: 0x2000, 0x134a: 0x2000,
-	0x1350: 0x2000, 0x1351: 0x2000,
-	0x1352: 0x2000, 0x1353: 0x2000, 0x1354: 0x2000, 0x1355: 0x2000, 0x1356: 0x2000, 0x1357: 0x2000,
-	0x1358: 0x2000, 0x1359: 0x2000, 0x135a: 0x2000, 0x135b: 0x2000, 0x135c: 0x2000, 0x135d: 0x2000,
-	0x135e: 0x2000, 0x135f: 0x2000, 0x1360: 0x2000, 0x1361: 0x2000, 0x1362: 0x2000, 0x1363: 0x2000,
-	0x1364: 0x2000, 0x1365: 0x2000, 0x1366: 0x2000, 0x1367: 0x2000, 0x1368: 0x2000, 0x1369: 0x2000,
-	0x136a: 0x2000, 0x136b: 0x2000, 0x136c: 0x2000, 0x136d: 0x2000,
-	0x1370: 0x2000, 0x1371: 0x2000, 0x1372: 0x2000, 0x1373: 0x2000, 0x1374: 0x2000, 0x1375: 0x2000,
-	0x1376: 0x2000, 0x1377: 0x2000, 0x1378: 0x2000, 0x1379: 0x2000, 0x137a: 0x2000, 0x137b: 0x2000,
-	0x137c: 0x2000, 0x137d: 0x2000, 0x137e: 0x2000, 0x137f: 0x2000,
-	// Block 0x4e, offset 0x1380
-	0x1380: 0x2000, 0x1381: 0x2000, 0x1382: 0x2000, 0x1383: 0x2000, 0x1384: 0x2000, 0x1385: 0x2000,
-	0x1386: 0x2000, 0x1387: 0x2000, 0x1388: 0x2000, 0x1389: 0x2000, 0x138a: 0x2000, 0x138b: 0x2000,
-	0x138c: 0x2000, 0x138d: 0x2000, 0x138e: 0x2000, 0x138f: 0x2000, 0x1390: 0x2000, 0x1391: 0x2000,
-	0x1392: 0x2000, 0x1393: 0x2000, 0x1394: 0x2000, 0x1395: 0x2000, 0x1396: 0x2000, 0x1397: 0x2000,
-	0x1398: 0x2000, 0x1399: 0x2000, 0x139a: 0x2000, 0x139b: 0x2000, 0x139c: 0x2000, 0x139d: 0x2000,
-	0x139e: 0x2000, 0x139f: 0x2000, 0x13a0: 0x2000, 0x13a1: 0x2000, 0x13a2: 0x2000, 0x13a3: 0x2000,
-	0x13a4: 0x2000, 0x13a5: 0x2000, 0x13a6: 0x2000, 0x13a7: 0x2000, 0x13a8: 0x2000, 0x13a9: 0x2000,
-	0x13b0: 0x2000, 0x13b1: 0x2000, 0x13b2: 0x2000, 0x13b3: 0x2000, 0x13b4: 0x2000, 0x13b5: 0x2000,
-	0x13b6: 0x2000, 0x13b7: 0x2000, 0x13b8: 0x2000, 0x13b9: 0x2000, 0x13ba: 0x2000, 0x13bb: 0x2000,
-	0x13bc: 0x2000, 0x13bd: 0x2000, 0x13be: 0x2000, 0x13bf: 0x2000,
-	// Block 0x4f, offset 0x13c0
-	0x13c0: 0x2000, 0x13c1: 0x2000, 0x13c2: 0x2000, 0x13c3: 0x2000, 0x13c4: 0x2000, 0x13c5: 0x2000,
-	0x13c6: 0x2000, 0x13c7: 0x2000, 0x13c8: 0x2000, 0x13c9: 0x2000, 0x13ca: 0x2000, 0x13cb: 0x2000,
-	0x13cc: 0x2000, 0x13cd: 0x2000, 0x13ce: 0x4000, 0x13cf: 0x2000, 0x13d0: 0x2000, 0x13d1: 0x4000,
-	0x13d2: 0x4000, 0x13d3: 0x4000, 0x13d4: 0x4000, 0x13d5: 0x4000, 0x13d6: 0x4000, 0x13d7: 0x4000,
-	0x13d8: 0x4000, 0x13d9: 0x4000, 0x13da: 0x4000, 0x13db: 0x2000, 0x13dc: 0x2000, 0x13dd: 0x2000,
-	0x13de: 0x2000, 0x13df: 0x2000, 0x13e0: 0x2000, 0x13e1: 0x2000, 0x13e2: 0x2000, 0x13e3: 0x2000,
-	0x13e4: 0x2000, 0x13e5: 0x2000, 0x13e6: 0x2000, 0x13e7: 0x2000, 0x13e8: 0x2000, 0x13e9: 0x2000,
-	0x13ea: 0x2000, 0x13eb: 0x2000, 0x13ec: 0x2000,
-	// Block 0x50, offset 0x1400
-	0x1400: 0x4000, 0x1401: 0x4000, 0x1402: 0x4000,
-	0x1410: 0x4000, 0x1411: 0x4000,
-	0x1412: 0x4000, 0x1413: 0x4000, 0x1414: 0x4000, 0x1415: 0x4000, 0x1416: 0x4000, 0x1417: 0x4000,
-	0x1418: 0x4000, 0x1419: 0x4000, 0x141a: 0x4000, 0x141b: 0x4000, 0x141c: 0x4000, 0x141d: 0x4000,
-	0x141e: 0x4000, 0x141f: 0x4000, 0x1420: 0x4000, 0x1421: 0x4000, 0x1422: 0x4000, 0x1423: 0x4000,
-	0x1424: 0x4000, 0x1425: 0x4000, 0x1426: 0x4000, 0x1427: 0x4000, 0x1428: 0x4000, 0x1429: 0x4000,
-	0x142a: 0x4000, 0x142b: 0x4000, 0x142c: 0x4000, 0x142d: 0x4000, 0x142e: 0x4000, 0x142f: 0x4000,
-	0x1430: 0x4000, 0x1431: 0x4000, 0x1432: 0x4000, 0x1433: 0x4000, 0x1434: 0x4000, 0x1435: 0x4000,
-	0x1436: 0x4000, 0x1437: 0x4000, 0x1438: 0x4000, 0x1439: 0x4000, 0x143a: 0x4000, 0x143b: 0x4000,
-	// Block 0x51, offset 0x1440
-	0x1440: 0x4000, 0x1441: 0x4000, 0x1442: 0x4000, 0x1443: 0x4000, 0x1444: 0x4000, 0x1445: 0x4000,
-	0x1446: 0x4000, 0x1447: 0x4000, 0x1448: 0x4000,
-	0x1450: 0x4000, 0x1451: 0x4000,
-	// Block 0x52, offset 0x1480
-	0x1480: 0x4000, 0x1481: 0x4000, 0x1482: 0x4000, 0x1483: 0x4000, 0x1484: 0x4000, 0x1485: 0x4000,
-	0x1486: 0x4000, 0x1487: 0x4000, 0x1488: 0x4000, 0x1489: 0x4000, 0x148a: 0x4000, 0x148b: 0x4000,
-	0x148c: 0x4000, 0x148d: 0x4000, 0x148e: 0x4000, 0x148f: 0x4000, 0x1490: 0x4000, 0x1491: 0x4000,
-	0x1492: 0x4000, 0x1493: 0x4000, 0x1494: 0x4000, 0x1495: 0x4000, 0x1496: 0x4000, 0x1497: 0x4000,
-	0x1498: 0x4000, 0x1499: 0x4000, 0x149a: 0x4000, 0x149b: 0x4000, 0x149c: 0x4000, 0x149d: 0x4000,
-	0x149e: 0x4000, 0x149f: 0x4000, 0x14a0: 0x4000,
-	0x14ad: 0x4000, 0x14ae: 0x4000, 0x14af: 0x4000,
-	0x14b0: 0x4000, 0x14b1: 0x4000, 0x14b2: 0x4000, 0x14b3: 0x4000, 0x14b4: 0x4000, 0x14b5: 0x4000,
-	0x14b7: 0x4000, 0x14b8: 0x4000, 0x14b9: 0x4000, 0x14ba: 0x4000, 0x14bb: 0x4000,
-	0x14bc: 0x4000, 0x14bd: 0x4000, 0x14be: 0x4000, 0x14bf: 0x4000,
-	// Block 0x53, offset 0x14c0
-	0x14c0: 0x4000, 0x14c1: 0x4000, 0x14c2: 0x4000, 0x14c3: 0x4000, 0x14c4: 0x4000, 0x14c5: 0x4000,
-	0x14c6: 0x4000, 0x14c7: 0x4000, 0x14c8: 0x4000, 0x14c9: 0x4000, 0x14ca: 0x4000, 0x14cb: 0x4000,
-	0x14cc: 0x4000, 0x14cd: 0x4000, 0x14ce: 0x4000, 0x14cf: 0x4000, 0x14d0: 0x4000, 0x14d1: 0x4000,
-	0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
-	0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x4000, 0x14dc: 0x4000, 0x14dd: 0x4000,
-	0x14de: 0x4000, 0x14df: 0x4000, 0x14e0: 0x4000, 0x14e1: 0x4000, 0x14e2: 0x4000, 0x14e3: 0x4000,
-	0x14e4: 0x4000, 0x14e5: 0x4000, 0x14e6: 0x4000, 0x14e7: 0x4000, 0x14e8: 0x4000, 0x14e9: 0x4000,
-	0x14ea: 0x4000, 0x14eb: 0x4000, 0x14ec: 0x4000, 0x14ed: 0x4000, 0x14ee: 0x4000, 0x14ef: 0x4000,
-	0x14f0: 0x4000, 0x14f1: 0x4000, 0x14f2: 0x4000, 0x14f3: 0x4000, 0x14f4: 0x4000, 0x14f5: 0x4000,
-	0x14f6: 0x4000, 0x14f7: 0x4000, 0x14f8: 0x4000, 0x14f9: 0x4000, 0x14fa: 0x4000, 0x14fb: 0x4000,
-	0x14fc: 0x4000, 0x14fe: 0x4000, 0x14ff: 0x4000,
-	// Block 0x54, offset 0x1500
-	0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000, 0x1503: 0x4000, 0x1504: 0x4000, 0x1505: 0x4000,
-	0x1506: 0x4000, 0x1507: 0x4000, 0x1508: 0x4000, 0x1509: 0x4000, 0x150a: 0x4000, 0x150b: 0x4000,
-	0x150c: 0x4000, 0x150d: 0x4000, 0x150e: 0x4000, 0x150f: 0x4000, 0x1510: 0x4000, 0x1511: 0x4000,
-	0x1512: 0x4000, 0x1513: 0x4000,
-	0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
-	0x1524: 0x4000, 0x1525: 0x4000, 0x1526: 0x4000, 0x1527: 0x4000, 0x1528: 0x4000, 0x1529: 0x4000,
-	0x152a: 0x4000, 0x152b: 0x4000, 0x152c: 0x4000, 0x152d: 0x4000, 0x152e: 0x4000, 0x152f: 0x4000,
-	0x1530: 0x4000, 0x1531: 0x4000, 0x1532: 0x4000, 0x1533: 0x4000, 0x1534: 0x4000, 0x1535: 0x4000,
-	0x1536: 0x4000, 0x1537: 0x4000, 0x1538: 0x4000, 0x1539: 0x4000, 0x153a: 0x4000, 0x153b: 0x4000,
-	0x153c: 0x4000, 0x153d: 0x4000, 0x153e: 0x4000, 0x153f: 0x4000,
-	// Block 0x55, offset 0x1540
-	0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
-	0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000, 0x1549: 0x4000, 0x154a: 0x4000,
-	0x154f: 0x4000, 0x1550: 0x4000, 0x1551: 0x4000,
-	0x1552: 0x4000, 0x1553: 0x4000,
-	0x1560: 0x4000, 0x1561: 0x4000, 0x1562: 0x4000, 0x1563: 0x4000,
-	0x1564: 0x4000, 0x1565: 0x4000, 0x1566: 0x4000, 0x1567: 0x4000, 0x1568: 0x4000, 0x1569: 0x4000,
-	0x156a: 0x4000, 0x156b: 0x4000, 0x156c: 0x4000, 0x156d: 0x4000, 0x156e: 0x4000, 0x156f: 0x4000,
-	0x1570: 0x4000, 0x1574: 0x4000,
-	0x1578: 0x4000, 0x1579: 0x4000, 0x157a: 0x4000, 0x157b: 0x4000,
-	0x157c: 0x4000, 0x157d: 0x4000, 0x157e: 0x4000, 0x157f: 0x4000,
-	// Block 0x56, offset 0x1580
-	0x1580: 0x4000, 0x1582: 0x4000, 0x1583: 0x4000, 0x1584: 0x4000, 0x1585: 0x4000,
-	0x1586: 0x4000, 0x1587: 0x4000, 0x1588: 0x4000, 0x1589: 0x4000, 0x158a: 0x4000, 0x158b: 0x4000,
-	0x158c: 0x4000, 0x158d: 0x4000, 0x158e: 0x4000, 0x158f: 0x4000, 0x1590: 0x4000, 0x1591: 0x4000,
-	0x1592: 0x4000, 0x1593: 0x4000, 0x1594: 0x4000, 0x1595: 0x4000, 0x1596: 0x4000, 0x1597: 0x4000,
-	0x1598: 0x4000, 0x1599: 0x4000, 0x159a: 0x4000, 0x159b: 0x4000, 0x159c: 0x4000, 0x159d: 0x4000,
-	0x159e: 0x4000, 0x159f: 0x4000, 0x15a0: 0x4000, 0x15a1: 0x4000, 0x15a2: 0x4000, 0x15a3: 0x4000,
-	0x15a4: 0x4000, 0x15a5: 0x4000, 0x15a6: 0x4000, 0x15a7: 0x4000, 0x15a8: 0x4000, 0x15a9: 0x4000,
-	0x15aa: 0x4000, 0x15ab: 0x4000, 0x15ac: 0x4000, 0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
-	0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
-	0x15b6: 0x4000, 0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
-	0x15bc: 0x4000, 0x15bd: 0x4000, 0x15be: 0x4000, 0x15bf: 0x4000,
-	// Block 0x57, offset 0x15c0
-	0x15c0: 0x4000, 0x15c1: 0x4000, 0x15c2: 0x4000, 0x15c3: 0x4000, 0x15c4: 0x4000, 0x15c5: 0x4000,
-	0x15c6: 0x4000, 0x15c7: 0x4000, 0x15c8: 0x4000, 0x15c9: 0x4000, 0x15ca: 0x4000, 0x15cb: 0x4000,
-	0x15cc: 0x4000, 0x15cd: 0x4000, 0x15ce: 0x4000, 0x15cf: 0x4000, 0x15d0: 0x4000, 0x15d1: 0x4000,
-	0x15d2: 0x4000, 0x15d3: 0x4000, 0x15d4: 0x4000, 0x15d5: 0x4000, 0x15d6: 0x4000, 0x15d7: 0x4000,
-	0x15d8: 0x4000, 0x15d9: 0x4000, 0x15da: 0x4000, 0x15db: 0x4000, 0x15dc: 0x4000, 0x15dd: 0x4000,
-	0x15de: 0x4000, 0x15df: 0x4000, 0x15e0: 0x4000, 0x15e1: 0x4000, 0x15e2: 0x4000, 0x15e3: 0x4000,
-	0x15e4: 0x4000, 0x15e5: 0x4000, 0x15e6: 0x4000, 0x15e7: 0x4000, 0x15e8: 0x4000, 0x15e9: 0x4000,
-	0x15ea: 0x4000, 0x15eb: 0x4000, 0x15ec: 0x4000, 0x15ed: 0x4000, 0x15ee: 0x4000, 0x15ef: 0x4000,
-	0x15f0: 0x4000, 0x15f1: 0x4000, 0x15f2: 0x4000, 0x15f3: 0x4000, 0x15f4: 0x4000, 0x15f5: 0x4000,
-	0x15f6: 0x4000, 0x15f7: 0x4000, 0x15f8: 0x4000, 0x15f9: 0x4000, 0x15fa: 0x4000, 0x15fb: 0x4000,
-	0x15fc: 0x4000, 0x15ff: 0x4000,
-	// Block 0x58, offset 0x1600
-	0x1600: 0x4000, 0x1601: 0x4000, 0x1602: 0x4000, 0x1603: 0x4000, 0x1604: 0x4000, 0x1605: 0x4000,
-	0x1606: 0x4000, 0x1607: 0x4000, 0x1608: 0x4000, 0x1609: 0x4000, 0x160a: 0x4000, 0x160b: 0x4000,
-	0x160c: 0x4000, 0x160d: 0x4000, 0x160e: 0x4000, 0x160f: 0x4000, 0x1610: 0x4000, 0x1611: 0x4000,
-	0x1612: 0x4000, 0x1613: 0x4000, 0x1614: 0x4000, 0x1615: 0x4000, 0x1616: 0x4000, 0x1617: 0x4000,
-	0x1618: 0x4000, 0x1619: 0x4000, 0x161a: 0x4000, 0x161b: 0x4000, 0x161c: 0x4000, 0x161d: 0x4000,
-	0x161e: 0x4000, 0x161f: 0x4000, 0x1620: 0x4000, 0x1621: 0x4000, 0x1622: 0x4000, 0x1623: 0x4000,
-	0x1624: 0x4000, 0x1625: 0x4000, 0x1626: 0x4000, 0x1627: 0x4000, 0x1628: 0x4000, 0x1629: 0x4000,
-	0x162a: 0x4000, 0x162b: 0x4000, 0x162c: 0x4000, 0x162d: 0x4000, 0x162e: 0x4000, 0x162f: 0x4000,
-	0x1630: 0x4000, 0x1631: 0x4000, 0x1632: 0x4000, 0x1633: 0x4000, 0x1634: 0x4000, 0x1635: 0x4000,
-	0x1636: 0x4000, 0x1637: 0x4000, 0x1638: 0x4000, 0x1639: 0x4000, 0x163a: 0x4000, 0x163b: 0x4000,
-	0x163c: 0x4000, 0x163d: 0x4000,
-	// Block 0x59, offset 0x1640
-	0x164b: 0x4000,
-	0x164c: 0x4000, 0x164d: 0x4000, 0x164e: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
-	0x1652: 0x4000, 0x1653: 0x4000, 0x1654: 0x4000, 0x1655: 0x4000, 0x1656: 0x4000, 0x1657: 0x4000,
-	0x1658: 0x4000, 0x1659: 0x4000, 0x165a: 0x4000, 0x165b: 0x4000, 0x165c: 0x4000, 0x165d: 0x4000,
-	0x165e: 0x4000, 0x165f: 0x4000, 0x1660: 0x4000, 0x1661: 0x4000, 0x1662: 0x4000, 0x1663: 0x4000,
-	0x1664: 0x4000, 0x1665: 0x4000, 0x1666: 0x4000, 0x1667: 0x4000,
-	0x167a: 0x4000,
-	// Block 0x5a, offset 0x1680
-	0x1695: 0x4000, 0x1696: 0x4000,
-	0x16a4: 0x4000,
-	// Block 0x5b, offset 0x16c0
-	0x16fb: 0x4000,
-	0x16fc: 0x4000, 0x16fd: 0x4000, 0x16fe: 0x4000, 0x16ff: 0x4000,
-	// Block 0x5c, offset 0x1700
-	0x1700: 0x4000, 0x1701: 0x4000, 0x1702: 0x4000, 0x1703: 0x4000, 0x1704: 0x4000, 0x1705: 0x4000,
-	0x1706: 0x4000, 0x1707: 0x4000, 0x1708: 0x4000, 0x1709: 0x4000, 0x170a: 0x4000, 0x170b: 0x4000,
-	0x170c: 0x4000, 0x170d: 0x4000, 0x170e: 0x4000, 0x170f: 0x4000,
-	// Block 0x5d, offset 0x1740
-	0x1740: 0x4000, 0x1741: 0x4000, 0x1742: 0x4000, 0x1743: 0x4000, 0x1744: 0x4000, 0x1745: 0x4000,
-	0x174c: 0x4000, 0x1750: 0x4000, 0x1751: 0x4000,
-	0x1752: 0x4000,
-	0x176b: 0x4000, 0x176c: 0x4000,
-	0x1774: 0x4000, 0x1775: 0x4000,
-	0x1776: 0x4000,
-	// Block 0x5e, offset 0x1780
-	0x1790: 0x4000, 0x1791: 0x4000,
-	0x1792: 0x4000, 0x1793: 0x4000, 0x1794: 0x4000, 0x1795: 0x4000, 0x1796: 0x4000, 0x1797: 0x4000,
-	0x1798: 0x4000, 0x1799: 0x4000, 0x179a: 0x4000, 0x179b: 0x4000, 0x179c: 0x4000, 0x179d: 0x4000,
-	0x179e: 0x4000, 0x17a0: 0x4000, 0x17a1: 0x4000, 0x17a2: 0x4000, 0x17a3: 0x4000,
-	0x17a4: 0x4000, 0x17a5: 0x4000, 0x17a6: 0x4000, 0x17a7: 0x4000,
-	0x17b0: 0x4000, 0x17b3: 0x4000, 0x17b4: 0x4000, 0x17b5: 0x4000,
-	0x17b6: 0x4000, 0x17b7: 0x4000, 0x17b8: 0x4000, 0x17b9: 0x4000, 0x17ba: 0x4000, 0x17bb: 0x4000,
-	0x17bc: 0x4000, 0x17bd: 0x4000, 0x17be: 0x4000,
-	// Block 0x5f, offset 0x17c0
-	0x17c0: 0x4000, 0x17c1: 0x4000, 0x17c2: 0x4000, 0x17c3: 0x4000, 0x17c4: 0x4000, 0x17c5: 0x4000,
-	0x17c6: 0x4000, 0x17c7: 0x4000, 0x17c8: 0x4000, 0x17c9: 0x4000, 0x17ca: 0x4000, 0x17cb: 0x4000,
-	0x17d0: 0x4000, 0x17d1: 0x4000,
-	0x17d2: 0x4000, 0x17d3: 0x4000, 0x17d4: 0x4000, 0x17d5: 0x4000, 0x17d6: 0x4000, 0x17d7: 0x4000,
-	0x17d8: 0x4000, 0x17d9: 0x4000, 0x17da: 0x4000, 0x17db: 0x4000, 0x17dc: 0x4000, 0x17dd: 0x4000,
-	0x17de: 0x4000,
-	// Block 0x60, offset 0x1800
-	0x1800: 0x4000, 0x1801: 0x4000, 0x1802: 0x4000, 0x1803: 0x4000, 0x1804: 0x4000, 0x1805: 0x4000,
-	0x1806: 0x4000, 0x1807: 0x4000, 0x1808: 0x4000, 0x1809: 0x4000, 0x180a: 0x4000, 0x180b: 0x4000,
-	0x180c: 0x4000, 0x180d: 0x4000, 0x180e: 0x4000, 0x180f: 0x4000, 0x1810: 0x4000, 0x1811: 0x4000,
-	// Block 0x61, offset 0x1840
-	0x1840: 0x4000,
-	// Block 0x62, offset 0x1880
-	0x1880: 0x2000, 0x1881: 0x2000, 0x1882: 0x2000, 0x1883: 0x2000, 0x1884: 0x2000, 0x1885: 0x2000,
-	0x1886: 0x2000, 0x1887: 0x2000, 0x1888: 0x2000, 0x1889: 0x2000, 0x188a: 0x2000, 0x188b: 0x2000,
-	0x188c: 0x2000, 0x188d: 0x2000, 0x188e: 0x2000, 0x188f: 0x2000, 0x1890: 0x2000, 0x1891: 0x2000,
-	0x1892: 0x2000, 0x1893: 0x2000, 0x1894: 0x2000, 0x1895: 0x2000, 0x1896: 0x2000, 0x1897: 0x2000,
-	0x1898: 0x2000, 0x1899: 0x2000, 0x189a: 0x2000, 0x189b: 0x2000, 0x189c: 0x2000, 0x189d: 0x2000,
-	0x189e: 0x2000, 0x189f: 0x2000, 0x18a0: 0x2000, 0x18a1: 0x2000, 0x18a2: 0x2000, 0x18a3: 0x2000,
-	0x18a4: 0x2000, 0x18a5: 0x2000, 0x18a6: 0x2000, 0x18a7: 0x2000, 0x18a8: 0x2000, 0x18a9: 0x2000,
-	0x18aa: 0x2000, 0x18ab: 0x2000, 0x18ac: 0x2000, 0x18ad: 0x2000, 0x18ae: 0x2000, 0x18af: 0x2000,
-	0x18b0: 0x2000, 0x18b1: 0x2000, 0x18b2: 0x2000, 0x18b3: 0x2000, 0x18b4: 0x2000, 0x18b5: 0x2000,
-	0x18b6: 0x2000, 0x18b7: 0x2000, 0x18b8: 0x2000, 0x18b9: 0x2000, 0x18ba: 0x2000, 0x18bb: 0x2000,
-	0x18bc: 0x2000, 0x18bd: 0x2000,
-}
-
-// widthIndex: 22 blocks, 1408 entries, 1408 bytes
-// Block 0 is the zero block.
-var widthIndex = [1408]uint8{
-	// Block 0x0, offset 0x0
-	// Block 0x1, offset 0x40
-	// Block 0x2, offset 0x80
-	// Block 0x3, offset 0xc0
-	0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05,
-	0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b,
-	0xd0: 0x0c, 0xd1: 0x0d,
-	0xe1: 0x02, 0xe2: 0x03, 0xe3: 0x04, 0xe4: 0x05, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06,
-	0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a,
-	0xf0: 0x0f, 0xf3: 0x12, 0xf4: 0x13,
-	// Block 0x4, offset 0x100
-	0x104: 0x0e, 0x105: 0x0f,
-	// Block 0x5, offset 0x140
-	0x140: 0x10, 0x141: 0x11, 0x142: 0x12, 0x144: 0x13, 0x145: 0x14, 0x146: 0x15, 0x147: 0x16,
-	0x148: 0x17, 0x149: 0x18, 0x14a: 0x19, 0x14c: 0x1a, 0x14f: 0x1b,
-	0x151: 0x1c, 0x152: 0x08, 0x153: 0x1d, 0x154: 0x1e, 0x155: 0x1f, 0x156: 0x20, 0x157: 0x21,
-	0x158: 0x22, 0x159: 0x23, 0x15a: 0x24, 0x15b: 0x25, 0x15c: 0x26, 0x15d: 0x27, 0x15e: 0x28, 0x15f: 0x29,
-	0x166: 0x2a,
-	0x16c: 0x2b, 0x16d: 0x2c,
-	0x17a: 0x2d, 0x17b: 0x2e, 0x17c: 0x0e, 0x17d: 0x0e, 0x17e: 0x0e, 0x17f: 0x2f,
-	// Block 0x6, offset 0x180
-	0x180: 0x30, 0x181: 0x31, 0x182: 0x32, 0x183: 0x33, 0x184: 0x34, 0x185: 0x35, 0x186: 0x36, 0x187: 0x37,
-	0x188: 0x38, 0x189: 0x39, 0x18a: 0x0e, 0x18b: 0x3a, 0x18c: 0x0e, 0x18d: 0x0e, 0x18e: 0x0e, 0x18f: 0x0e,
-	0x190: 0x0e, 0x191: 0x0e, 0x192: 0x0e, 0x193: 0x0e, 0x194: 0x0e, 0x195: 0x0e, 0x196: 0x0e, 0x197: 0x0e,
-	0x198: 0x0e, 0x199: 0x0e, 0x19a: 0x0e, 0x19b: 0x0e, 0x19c: 0x0e, 0x19d: 0x0e, 0x19e: 0x0e, 0x19f: 0x0e,
-	0x1a0: 0x0e, 0x1a1: 0x0e, 0x1a2: 0x0e, 0x1a3: 0x0e, 0x1a4: 0x0e, 0x1a5: 0x0e, 0x1a6: 0x0e, 0x1a7: 0x0e,
-	0x1a8: 0x0e, 0x1a9: 0x0e, 0x1aa: 0x0e, 0x1ab: 0x0e, 0x1ac: 0x0e, 0x1ad: 0x0e, 0x1ae: 0x0e, 0x1af: 0x0e,
-	0x1b0: 0x0e, 0x1b1: 0x0e, 0x1b2: 0x0e, 0x1b3: 0x0e, 0x1b4: 0x0e, 0x1b5: 0x0e, 0x1b6: 0x0e, 0x1b7: 0x0e,
-	0x1b8: 0x0e, 0x1b9: 0x0e, 0x1ba: 0x0e, 0x1bb: 0x0e, 0x1bc: 0x0e, 0x1bd: 0x0e, 0x1be: 0x0e, 0x1bf: 0x0e,
-	// Block 0x7, offset 0x1c0
-	0x1c0: 0x0e, 0x1c1: 0x0e, 0x1c2: 0x0e, 0x1c3: 0x0e, 0x1c4: 0x0e, 0x1c5: 0x0e, 0x1c6: 0x0e, 0x1c7: 0x0e,
-	0x1c8: 0x0e, 0x1c9: 0x0e, 0x1ca: 0x0e, 0x1cb: 0x0e, 0x1cc: 0x0e, 0x1cd: 0x0e, 0x1ce: 0x0e, 0x1cf: 0x0e,
-	0x1d0: 0x0e, 0x1d1: 0x0e, 0x1d2: 0x0e, 0x1d3: 0x0e, 0x1d4: 0x0e, 0x1d5: 0x0e, 0x1d6: 0x0e, 0x1d7: 0x0e,
-	0x1d8: 0x0e, 0x1d9: 0x0e, 0x1da: 0x0e, 0x1db: 0x0e, 0x1dc: 0x0e, 0x1dd: 0x0e, 0x1de: 0x0e, 0x1df: 0x0e,
-	0x1e0: 0x0e, 0x1e1: 0x0e, 0x1e2: 0x0e, 0x1e3: 0x0e, 0x1e4: 0x0e, 0x1e5: 0x0e, 0x1e6: 0x0e, 0x1e7: 0x0e,
-	0x1e8: 0x0e, 0x1e9: 0x0e, 0x1ea: 0x0e, 0x1eb: 0x0e, 0x1ec: 0x0e, 0x1ed: 0x0e, 0x1ee: 0x0e, 0x1ef: 0x0e,
-	0x1f0: 0x0e, 0x1f1: 0x0e, 0x1f2: 0x0e, 0x1f3: 0x0e, 0x1f4: 0x0e, 0x1f5: 0x0e, 0x1f6: 0x0e,
-	0x1f8: 0x0e, 0x1f9: 0x0e, 0x1fa: 0x0e, 0x1fb: 0x0e, 0x1fc: 0x0e, 0x1fd: 0x0e, 0x1fe: 0x0e, 0x1ff: 0x0e,
-	// Block 0x8, offset 0x200
-	0x200: 0x0e, 0x201: 0x0e, 0x202: 0x0e, 0x203: 0x0e, 0x204: 0x0e, 0x205: 0x0e, 0x206: 0x0e, 0x207: 0x0e,
-	0x208: 0x0e, 0x209: 0x0e, 0x20a: 0x0e, 0x20b: 0x0e, 0x20c: 0x0e, 0x20d: 0x0e, 0x20e: 0x0e, 0x20f: 0x0e,
-	0x210: 0x0e, 0x211: 0x0e, 0x212: 0x0e, 0x213: 0x0e, 0x214: 0x0e, 0x215: 0x0e, 0x216: 0x0e, 0x217: 0x0e,
-	0x218: 0x0e, 0x219: 0x0e, 0x21a: 0x0e, 0x21b: 0x0e, 0x21c: 0x0e, 0x21d: 0x0e, 0x21e: 0x0e, 0x21f: 0x0e,
-	0x220: 0x0e, 0x221: 0x0e, 0x222: 0x0e, 0x223: 0x0e, 0x224: 0x0e, 0x225: 0x0e, 0x226: 0x0e, 0x227: 0x0e,
-	0x228: 0x0e, 0x229: 0x0e, 0x22a: 0x0e, 0x22b: 0x0e, 0x22c: 0x0e, 0x22d: 0x0e, 0x22e: 0x0e, 0x22f: 0x0e,
-	0x230: 0x0e, 0x231: 0x0e, 0x232: 0x0e, 0x233: 0x0e, 0x234: 0x0e, 0x235: 0x0e, 0x236: 0x0e, 0x237: 0x0e,
-	0x238: 0x0e, 0x239: 0x0e, 0x23a: 0x0e, 0x23b: 0x0e, 0x23c: 0x0e, 0x23d: 0x0e, 0x23e: 0x0e, 0x23f: 0x0e,
-	// Block 0x9, offset 0x240
-	0x240: 0x0e, 0x241: 0x0e, 0x242: 0x0e, 0x243: 0x0e, 0x244: 0x0e, 0x245: 0x0e, 0x246: 0x0e, 0x247: 0x0e,
-	0x248: 0x0e, 0x249: 0x0e, 0x24a: 0x0e, 0x24b: 0x0e, 0x24c: 0x0e, 0x24d: 0x0e, 0x24e: 0x0e, 0x24f: 0x0e,
-	0x250: 0x0e, 0x251: 0x0e, 0x252: 0x3b, 0x253: 0x3c,
-	0x265: 0x3d,
-	0x270: 0x0e, 0x271: 0x0e, 0x272: 0x0e, 0x273: 0x0e, 0x274: 0x0e, 0x275: 0x0e, 0x276: 0x0e, 0x277: 0x0e,
-	0x278: 0x0e, 0x279: 0x0e, 0x27a: 0x0e, 0x27b: 0x0e, 0x27c: 0x0e, 0x27d: 0x0e, 0x27e: 0x0e, 0x27f: 0x0e,
-	// Block 0xa, offset 0x280
-	0x280: 0x0e, 0x281: 0x0e, 0x282: 0x0e, 0x283: 0x0e, 0x284: 0x0e, 0x285: 0x0e, 0x286: 0x0e, 0x287: 0x0e,
-	0x288: 0x0e, 0x289: 0x0e, 0x28a: 0x0e, 0x28b: 0x0e, 0x28c: 0x0e, 0x28d: 0x0e, 0x28e: 0x0e, 0x28f: 0x0e,
-	0x290: 0x0e, 0x291: 0x0e, 0x292: 0x0e, 0x293: 0x0e, 0x294: 0x0e, 0x295: 0x0e, 0x296: 0x0e, 0x297: 0x0e,
-	0x298: 0x0e, 0x299: 0x0e, 0x29a: 0x0e, 0x29b: 0x0e, 0x29c: 0x0e, 0x29d: 0x0e, 0x29e: 0x3e,
-	// Block 0xb, offset 0x2c0
-	0x2c0: 0x08, 0x2c1: 0x08, 0x2c2: 0x08, 0x2c3: 0x08, 0x2c4: 0x08, 0x2c5: 0x08, 0x2c6: 0x08, 0x2c7: 0x08,
-	0x2c8: 0x08, 0x2c9: 0x08, 0x2ca: 0x08, 0x2cb: 0x08, 0x2cc: 0x08, 0x2cd: 0x08, 0x2ce: 0x08, 0x2cf: 0x08,
-	0x2d0: 0x08, 0x2d1: 0x08, 0x2d2: 0x08, 0x2d3: 0x08, 0x2d4: 0x08, 0x2d5: 0x08, 0x2d6: 0x08, 0x2d7: 0x08,
-	0x2d8: 0x08, 0x2d9: 0x08, 0x2da: 0x08, 0x2db: 0x08, 0x2dc: 0x08, 0x2dd: 0x08, 0x2de: 0x08, 0x2df: 0x08,
-	0x2e0: 0x08, 0x2e1: 0x08, 0x2e2: 0x08, 0x2e3: 0x08, 0x2e4: 0x08, 0x2e5: 0x08, 0x2e6: 0x08, 0x2e7: 0x08,
-	0x2e8: 0x08, 0x2e9: 0x08, 0x2ea: 0x08, 0x2eb: 0x08, 0x2ec: 0x08, 0x2ed: 0x08, 0x2ee: 0x08, 0x2ef: 0x08,
-	0x2f0: 0x08, 0x2f1: 0x08, 0x2f2: 0x08, 0x2f3: 0x08, 0x2f4: 0x08, 0x2f5: 0x08, 0x2f6: 0x08, 0x2f7: 0x08,
-	0x2f8: 0x08, 0x2f9: 0x08, 0x2fa: 0x08, 0x2fb: 0x08, 0x2fc: 0x08, 0x2fd: 0x08, 0x2fe: 0x08, 0x2ff: 0x08,
-	// Block 0xc, offset 0x300
-	0x300: 0x08, 0x301: 0x08, 0x302: 0x08, 0x303: 0x08, 0x304: 0x08, 0x305: 0x08, 0x306: 0x08, 0x307: 0x08,
-	0x308: 0x08, 0x309: 0x08, 0x30a: 0x08, 0x30b: 0x08, 0x30c: 0x08, 0x30d: 0x08, 0x30e: 0x08, 0x30f: 0x08,
-	0x310: 0x08, 0x311: 0x08, 0x312: 0x08, 0x313: 0x08, 0x314: 0x08, 0x315: 0x08, 0x316: 0x08, 0x317: 0x08,
-	0x318: 0x08, 0x319: 0x08, 0x31a: 0x08, 0x31b: 0x08, 0x31c: 0x08, 0x31d: 0x08, 0x31e: 0x08, 0x31f: 0x08,
-	0x320: 0x08, 0x321: 0x08, 0x322: 0x08, 0x323: 0x08, 0x324: 0x0e, 0x325: 0x0e, 0x326: 0x0e, 0x327: 0x0e,
-	0x328: 0x0e, 0x329: 0x0e, 0x32a: 0x0e, 0x32b: 0x0e,
-	0x338: 0x3f, 0x339: 0x40, 0x33c: 0x41, 0x33d: 0x42, 0x33e: 0x43, 0x33f: 0x44,
-	// Block 0xd, offset 0x340
-	0x37f: 0x45,
-	// Block 0xe, offset 0x380
-	0x380: 0x0e, 0x381: 0x0e, 0x382: 0x0e, 0x383: 0x0e, 0x384: 0x0e, 0x385: 0x0e, 0x386: 0x0e, 0x387: 0x0e,
-	0x388: 0x0e, 0x389: 0x0e, 0x38a: 0x0e, 0x38b: 0x0e, 0x38c: 0x0e, 0x38d: 0x0e, 0x38e: 0x0e, 0x38f: 0x0e,
-	0x390: 0x0e, 0x391: 0x0e, 0x392: 0x0e, 0x393: 0x0e, 0x394: 0x0e, 0x395: 0x0e, 0x396: 0x0e, 0x397: 0x0e,
-	0x398: 0x0e, 0x399: 0x0e, 0x39a: 0x0e, 0x39b: 0x0e, 0x39c: 0x0e, 0x39d: 0x0e, 0x39e: 0x0e, 0x39f: 0x46,
-	0x3a0: 0x0e, 0x3a1: 0x0e, 0x3a2: 0x0e, 0x3a3: 0x0e, 0x3a4: 0x0e, 0x3a5: 0x0e, 0x3a6: 0x0e, 0x3a7: 0x0e,
-	0x3a8: 0x0e, 0x3a9: 0x0e, 0x3aa: 0x0e, 0x3ab: 0x47,
-	// Block 0xf, offset 0x3c0
-	0x3c0: 0x48,
-	// Block 0x10, offset 0x400
-	0x400: 0x49, 0x403: 0x4a, 0x404: 0x4b, 0x405: 0x4c, 0x406: 0x4d,
-	0x408: 0x4e, 0x409: 0x4f, 0x40c: 0x50, 0x40d: 0x51, 0x40e: 0x52, 0x40f: 0x53,
-	0x410: 0x3a, 0x411: 0x54, 0x412: 0x0e, 0x413: 0x55, 0x414: 0x56, 0x415: 0x57, 0x416: 0x58, 0x417: 0x59,
-	0x418: 0x0e, 0x419: 0x5a, 0x41a: 0x0e, 0x41b: 0x5b,
-	0x424: 0x5c, 0x425: 0x5d, 0x426: 0x5e, 0x427: 0x5f,
-	// Block 0x11, offset 0x440
-	0x456: 0x0b, 0x457: 0x06,
-	0x458: 0x0c, 0x45b: 0x0d, 0x45f: 0x0e,
-	0x460: 0x06, 0x461: 0x06, 0x462: 0x06, 0x463: 0x06, 0x464: 0x06, 0x465: 0x06, 0x466: 0x06, 0x467: 0x06,
-	0x468: 0x06, 0x469: 0x06, 0x46a: 0x06, 0x46b: 0x06, 0x46c: 0x06, 0x46d: 0x06, 0x46e: 0x06, 0x46f: 0x06,
-	0x470: 0x06, 0x471: 0x06, 0x472: 0x06, 0x473: 0x06, 0x474: 0x06, 0x475: 0x06, 0x476: 0x06, 0x477: 0x06,
-	0x478: 0x06, 0x479: 0x06, 0x47a: 0x06, 0x47b: 0x06, 0x47c: 0x06, 0x47d: 0x06, 0x47e: 0x06, 0x47f: 0x06,
-	// Block 0x12, offset 0x480
-	0x484: 0x08, 0x485: 0x08, 0x486: 0x08, 0x487: 0x09,
-	// Block 0x13, offset 0x4c0
-	0x4c0: 0x08, 0x4c1: 0x08, 0x4c2: 0x08, 0x4c3: 0x08, 0x4c4: 0x08, 0x4c5: 0x08, 0x4c6: 0x08, 0x4c7: 0x08,
-	0x4c8: 0x08, 0x4c9: 0x08, 0x4ca: 0x08, 0x4cb: 0x08, 0x4cc: 0x08, 0x4cd: 0x08, 0x4ce: 0x08, 0x4cf: 0x08,
-	0x4d0: 0x08, 0x4d1: 0x08, 0x4d2: 0x08, 0x4d3: 0x08, 0x4d4: 0x08, 0x4d5: 0x08, 0x4d6: 0x08, 0x4d7: 0x08,
-	0x4d8: 0x08, 0x4d9: 0x08, 0x4da: 0x08, 0x4db: 0x08, 0x4dc: 0x08, 0x4dd: 0x08, 0x4de: 0x08, 0x4df: 0x08,
-	0x4e0: 0x08, 0x4e1: 0x08, 0x4e2: 0x08, 0x4e3: 0x08, 0x4e4: 0x08, 0x4e5: 0x08, 0x4e6: 0x08, 0x4e7: 0x08,
-	0x4e8: 0x08, 0x4e9: 0x08, 0x4ea: 0x08, 0x4eb: 0x08, 0x4ec: 0x08, 0x4ed: 0x08, 0x4ee: 0x08, 0x4ef: 0x08,
-	0x4f0: 0x08, 0x4f1: 0x08, 0x4f2: 0x08, 0x4f3: 0x08, 0x4f4: 0x08, 0x4f5: 0x08, 0x4f6: 0x08, 0x4f7: 0x08,
-	0x4f8: 0x08, 0x4f9: 0x08, 0x4fa: 0x08, 0x4fb: 0x08, 0x4fc: 0x08, 0x4fd: 0x08, 0x4fe: 0x08, 0x4ff: 0x60,
-	// Block 0x14, offset 0x500
-	0x520: 0x10,
-	0x530: 0x09, 0x531: 0x09, 0x532: 0x09, 0x533: 0x09, 0x534: 0x09, 0x535: 0x09, 0x536: 0x09, 0x537: 0x09,
-	0x538: 0x09, 0x539: 0x09, 0x53a: 0x09, 0x53b: 0x09, 0x53c: 0x09, 0x53d: 0x09, 0x53e: 0x09, 0x53f: 0x11,
-	// Block 0x15, offset 0x540
-	0x540: 0x09, 0x541: 0x09, 0x542: 0x09, 0x543: 0x09, 0x544: 0x09, 0x545: 0x09, 0x546: 0x09, 0x547: 0x09,
-	0x548: 0x09, 0x549: 0x09, 0x54a: 0x09, 0x54b: 0x09, 0x54c: 0x09, 0x54d: 0x09, 0x54e: 0x09, 0x54f: 0x11,
-}
-
-// inverseData contains 4-byte entries of the following format:
-//   <length> <modified UTF-8-encoded rune> <0 padding>
-// The last byte of the UTF-8-encoded rune is xor-ed with the last byte of the
-// UTF-8 encoding of the original rune. Mappings often have the following
-// pattern:
-//   A -> A  (U+FF21 -> U+0041)
-//   B -> B  (U+FF22 -> U+0042)
-//   ...
-// By xor-ing the last byte the same entry can be shared by many mappings. This
-// reduces the total number of distinct entries by about two thirds.
-// The resulting entry for the aforementioned mappings is
-//   { 0x01, 0xE0, 0x00, 0x00 }
-// Using this entry to map U+FF21 (UTF-8 [EF BC A1]), we get
-//   E0 ^ A1 = 41.
-// Similarly, for U+FF22 (UTF-8 [EF BC A2]), we get
-//   E0 ^ A2 = 42.
-// Note that because of the xor-ing, the byte sequence stored in the entry is
-// not valid UTF-8.
-var inverseData = [150][4]byte{
-	{0x00, 0x00, 0x00, 0x00},
-	{0x03, 0xe3, 0x80, 0xa0},
-	{0x03, 0xef, 0xbc, 0xa0},
-	{0x03, 0xef, 0xbc, 0xe0},
-	{0x03, 0xef, 0xbd, 0xe0},
-	{0x03, 0xef, 0xbf, 0x02},
-	{0x03, 0xef, 0xbf, 0x00},
-	{0x03, 0xef, 0xbf, 0x0e},
-	{0x03, 0xef, 0xbf, 0x0c},
-	{0x03, 0xef, 0xbf, 0x0f},
-	{0x03, 0xef, 0xbf, 0x39},
-	{0x03, 0xef, 0xbf, 0x3b},
-	{0x03, 0xef, 0xbf, 0x3f},
-	{0x03, 0xef, 0xbf, 0x2a},
-	{0x03, 0xef, 0xbf, 0x0d},
-	{0x03, 0xef, 0xbf, 0x25},
-	{0x03, 0xef, 0xbd, 0x1a},
-	{0x03, 0xef, 0xbd, 0x26},
-	{0x01, 0xa0, 0x00, 0x00},
-	{0x03, 0xef, 0xbd, 0x25},
-	{0x03, 0xef, 0xbd, 0x23},
-	{0x03, 0xef, 0xbd, 0x2e},
-	{0x03, 0xef, 0xbe, 0x07},
-	{0x03, 0xef, 0xbe, 0x05},
-	{0x03, 0xef, 0xbd, 0x06},
-	{0x03, 0xef, 0xbd, 0x13},
-	{0x03, 0xef, 0xbd, 0x0b},
-	{0x03, 0xef, 0xbd, 0x16},
-	{0x03, 0xef, 0xbd, 0x0c},
-	{0x03, 0xef, 0xbd, 0x15},
-	{0x03, 0xef, 0xbd, 0x0d},
-	{0x03, 0xef, 0xbd, 0x1c},
-	{0x03, 0xef, 0xbd, 0x02},
-	{0x03, 0xef, 0xbd, 0x1f},
-	{0x03, 0xef, 0xbd, 0x1d},
-	{0x03, 0xef, 0xbd, 0x17},
-	{0x03, 0xef, 0xbd, 0x08},
-	{0x03, 0xef, 0xbd, 0x09},
-	{0x03, 0xef, 0xbd, 0x0e},
-	{0x03, 0xef, 0xbd, 0x04},
-	{0x03, 0xef, 0xbd, 0x05},
-	{0x03, 0xef, 0xbe, 0x3f},
-	{0x03, 0xef, 0xbe, 0x00},
-	{0x03, 0xef, 0xbd, 0x2c},
-	{0x03, 0xef, 0xbe, 0x06},
-	{0x03, 0xef, 0xbe, 0x0c},
-	{0x03, 0xef, 0xbe, 0x0f},
-	{0x03, 0xef, 0xbe, 0x0d},
-	{0x03, 0xef, 0xbe, 0x0b},
-	{0x03, 0xef, 0xbe, 0x19},
-	{0x03, 0xef, 0xbe, 0x15},
-	{0x03, 0xef, 0xbe, 0x11},
-	{0x03, 0xef, 0xbe, 0x31},
-	{0x03, 0xef, 0xbe, 0x33},
-	{0x03, 0xef, 0xbd, 0x0f},
-	{0x03, 0xef, 0xbe, 0x30},
-	{0x03, 0xef, 0xbe, 0x3e},
-	{0x03, 0xef, 0xbe, 0x32},
-	{0x03, 0xef, 0xbe, 0x36},
-	{0x03, 0xef, 0xbd, 0x14},
-	{0x03, 0xef, 0xbe, 0x2e},
-	{0x03, 0xef, 0xbd, 0x1e},
-	{0x03, 0xef, 0xbe, 0x10},
-	{0x03, 0xef, 0xbf, 0x13},
-	{0x03, 0xef, 0xbf, 0x15},
-	{0x03, 0xef, 0xbf, 0x17},
-	{0x03, 0xef, 0xbf, 0x1f},
-	{0x03, 0xef, 0xbf, 0x1d},
-	{0x03, 0xef, 0xbf, 0x1b},
-	{0x03, 0xef, 0xbf, 0x09},
-	{0x03, 0xef, 0xbf, 0x0b},
-	{0x03, 0xef, 0xbf, 0x37},
-	{0x03, 0xef, 0xbe, 0x04},
-	{0x01, 0xe0, 0x00, 0x00},
-	{0x03, 0xe2, 0xa6, 0x1a},
-	{0x03, 0xe2, 0xa6, 0x26},
-	{0x03, 0xe3, 0x80, 0x23},
-	{0x03, 0xe3, 0x80, 0x2e},
-	{0x03, 0xe3, 0x80, 0x25},
-	{0x03, 0xe3, 0x83, 0x1e},
-	{0x03, 0xe3, 0x83, 0x14},
-	{0x03, 0xe3, 0x82, 0x06},
-	{0x03, 0xe3, 0x82, 0x0b},
-	{0x03, 0xe3, 0x82, 0x0c},
-	{0x03, 0xe3, 0x82, 0x0d},
-	{0x03, 0xe3, 0x82, 0x02},
-	{0x03, 0xe3, 0x83, 0x0f},
-	{0x03, 0xe3, 0x83, 0x08},
-	{0x03, 0xe3, 0x83, 0x09},
-	{0x03, 0xe3, 0x83, 0x2c},
-	{0x03, 0xe3, 0x83, 0x0c},
-	{0x03, 0xe3, 0x82, 0x13},
-	{0x03, 0xe3, 0x82, 0x16},
-	{0x03, 0xe3, 0x82, 0x15},
-	{0x03, 0xe3, 0x82, 0x1c},
-	{0x03, 0xe3, 0x82, 0x1f},
-	{0x03, 0xe3, 0x82, 0x1d},
-	{0x03, 0xe3, 0x82, 0x1a},
-	{0x03, 0xe3, 0x82, 0x17},
-	{0x03, 0xe3, 0x82, 0x08},
-	{0x03, 0xe3, 0x82, 0x09},
-	{0x03, 0xe3, 0x82, 0x0e},
-	{0x03, 0xe3, 0x82, 0x04},
-	{0x03, 0xe3, 0x82, 0x05},
-	{0x03, 0xe3, 0x82, 0x3f},
-	{0x03, 0xe3, 0x83, 0x00},
-	{0x03, 0xe3, 0x83, 0x06},
-	{0x03, 0xe3, 0x83, 0x05},
-	{0x03, 0xe3, 0x83, 0x0d},
-	{0x03, 0xe3, 0x83, 0x0b},
-	{0x03, 0xe3, 0x83, 0x07},
-	{0x03, 0xe3, 0x83, 0x19},
-	{0x03, 0xe3, 0x83, 0x15},
-	{0x03, 0xe3, 0x83, 0x11},
-	{0x03, 0xe3, 0x83, 0x31},
-	{0x03, 0xe3, 0x83, 0x33},
-	{0x03, 0xe3, 0x83, 0x30},
-	{0x03, 0xe3, 0x83, 0x3e},
-	{0x03, 0xe3, 0x83, 0x32},
-	{0x03, 0xe3, 0x83, 0x36},
-	{0x03, 0xe3, 0x83, 0x2e},
-	{0x03, 0xe3, 0x82, 0x07},
-	{0x03, 0xe3, 0x85, 0x04},
-	{0x03, 0xe3, 0x84, 0x10},
-	{0x03, 0xe3, 0x85, 0x30},
-	{0x03, 0xe3, 0x85, 0x0d},
-	{0x03, 0xe3, 0x85, 0x13},
-	{0x03, 0xe3, 0x85, 0x15},
-	{0x03, 0xe3, 0x85, 0x17},
-	{0x03, 0xe3, 0x85, 0x1f},
-	{0x03, 0xe3, 0x85, 0x1d},
-	{0x03, 0xe3, 0x85, 0x1b},
-	{0x03, 0xe3, 0x85, 0x09},
-	{0x03, 0xe3, 0x85, 0x0f},
-	{0x03, 0xe3, 0x85, 0x0b},
-	{0x03, 0xe3, 0x85, 0x37},
-	{0x03, 0xe3, 0x85, 0x3b},
-	{0x03, 0xe3, 0x85, 0x39},
-	{0x03, 0xe3, 0x85, 0x3f},
-	{0x02, 0xc2, 0x02, 0x00},
-	{0x02, 0xc2, 0x0e, 0x00},
-	{0x02, 0xc2, 0x0c, 0x00},
-	{0x02, 0xc2, 0x00, 0x00},
-	{0x03, 0xe2, 0x82, 0x0f},
-	{0x03, 0xe2, 0x94, 0x2a},
-	{0x03, 0xe2, 0x86, 0x39},
-	{0x03, 0xe2, 0x86, 0x3b},
-	{0x03, 0xe2, 0x86, 0x3f},
-	{0x03, 0xe2, 0x96, 0x0d},
-	{0x03, 0xe2, 0x97, 0x25},
-}
-
-// Total table size 14680 bytes (14KiB)
diff --git a/src/vendor/golang_org/x/text/width/transform.go b/src/vendor/golang_org/x/text/width/transform.go
deleted file mode 100644
index 04f1a3f..0000000
--- a/src/vendor/golang_org/x/text/width/transform.go
+++ /dev/null
@@ -1,239 +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 width
-
-import (
-	"unicode/utf8"
-
-	"golang_org/x/text/transform"
-)
-
-type foldTransform struct {
-	transform.NopResetter
-}
-
-func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
-	for n < len(src) {
-		if src[n] < utf8.RuneSelf {
-			// ASCII fast path.
-			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
-			}
-			continue
-		}
-		v, size := trie.lookup(src[n:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				err = transform.ErrShortSrc
-			} else {
-				n = len(src)
-			}
-			break
-		}
-		if elem(v)&tagNeedsFold != 0 {
-			err = transform.ErrEndOfSpan
-			break
-		}
-		n += size
-	}
-	return n, err
-}
-
-func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-	for nSrc < len(src) {
-		if src[nSrc] < utf8.RuneSelf {
-			// ASCII fast path.
-			start, end := nSrc, len(src)
-			if d := len(dst) - nDst; d < end-start {
-				end = nSrc + d
-			}
-			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
-			}
-			n := copy(dst[nDst:], src[start:nSrc])
-			if nDst += n; nDst == len(dst) {
-				nSrc = start + n
-				if nSrc == len(src) {
-					return nDst, nSrc, nil
-				}
-				if src[nSrc] < utf8.RuneSelf {
-					return nDst, nSrc, transform.ErrShortDst
-				}
-			}
-			continue
-		}
-		v, size := trie.lookup(src[nSrc:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				return nDst, nSrc, transform.ErrShortSrc
-			}
-			size = 1 // gobble 1 byte
-		}
-		if elem(v)&tagNeedsFold == 0 {
-			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			nDst += size
-		} else {
-			data := inverseData[byte(v)]
-			if len(dst)-nDst < int(data[0]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			i := 1
-			for end := int(data[0]); i < end; i++ {
-				dst[nDst] = data[i]
-				nDst++
-			}
-			dst[nDst] = data[i] ^ src[nSrc+size-1]
-			nDst++
-		}
-		nSrc += size
-	}
-	return nDst, nSrc, nil
-}
-
-type narrowTransform struct {
-	transform.NopResetter
-}
-
-func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
-	for n < len(src) {
-		if src[n] < utf8.RuneSelf {
-			// ASCII fast path.
-			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
-			}
-			continue
-		}
-		v, size := trie.lookup(src[n:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				err = transform.ErrShortSrc
-			} else {
-				n = len(src)
-			}
-			break
-		}
-		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
-		} else {
-			err = transform.ErrEndOfSpan
-			break
-		}
-		n += size
-	}
-	return n, err
-}
-
-func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-	for nSrc < len(src) {
-		if src[nSrc] < utf8.RuneSelf {
-			// ASCII fast path.
-			start, end := nSrc, len(src)
-			if d := len(dst) - nDst; d < end-start {
-				end = nSrc + d
-			}
-			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
-			}
-			n := copy(dst[nDst:], src[start:nSrc])
-			if nDst += n; nDst == len(dst) {
-				nSrc = start + n
-				if nSrc == len(src) {
-					return nDst, nSrc, nil
-				}
-				if src[nSrc] < utf8.RuneSelf {
-					return nDst, nSrc, transform.ErrShortDst
-				}
-			}
-			continue
-		}
-		v, size := trie.lookup(src[nSrc:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				return nDst, nSrc, transform.ErrShortSrc
-			}
-			size = 1 // gobble 1 byte
-		}
-		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
-			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			nDst += size
-		} else {
-			data := inverseData[byte(v)]
-			if len(dst)-nDst < int(data[0]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			i := 1
-			for end := int(data[0]); i < end; i++ {
-				dst[nDst] = data[i]
-				nDst++
-			}
-			dst[nDst] = data[i] ^ src[nSrc+size-1]
-			nDst++
-		}
-		nSrc += size
-	}
-	return nDst, nSrc, nil
-}
-
-type wideTransform struct {
-	transform.NopResetter
-}
-
-func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
-	for n < len(src) {
-		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
-		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
-		// not enough to warrant the extra code and complexity.
-		v, size := trie.lookup(src[n:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				err = transform.ErrShortSrc
-			} else {
-				n = len(src)
-			}
-			break
-		}
-		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
-		} else {
-			err = transform.ErrEndOfSpan
-			break
-		}
-		n += size
-	}
-	return n, err
-}
-
-func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-	for nSrc < len(src) {
-		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
-		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
-		// not enough to warrant the extra code and complexity.
-		v, size := trie.lookup(src[nSrc:])
-		if size == 0 { // incomplete UTF-8 encoding
-			if !atEOF {
-				return nDst, nSrc, transform.ErrShortSrc
-			}
-			size = 1 // gobble 1 byte
-		}
-		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
-			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			nDst += size
-		} else {
-			data := inverseData[byte(v)]
-			if len(dst)-nDst < int(data[0]) {
-				return nDst, nSrc, transform.ErrShortDst
-			}
-			i := 1
-			for end := int(data[0]); i < end; i++ {
-				dst[nDst] = data[i]
-				nDst++
-			}
-			dst[nDst] = data[i] ^ src[nSrc+size-1]
-			nDst++
-		}
-		nSrc += size
-	}
-	return nDst, nSrc, nil
-}
diff --git a/src/vendor/golang_org/x/text/width/trieval.go b/src/vendor/golang_org/x/text/width/trieval.go
deleted file mode 100644
index 0ecffb4..0000000
--- a/src/vendor/golang_org/x/text/width/trieval.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// This file was generated by go generate; DO NOT EDIT
-
-package width
-
-// elem is an entry of the width trie. The high byte is used to encode the type
-// of the rune. The low byte is used to store the index to a mapping entry in
-// the inverseData array.
-type elem uint16
-
-const (
-	tagNeutral elem = iota << typeShift
-	tagAmbiguous
-	tagWide
-	tagNarrow
-	tagFullwidth
-	tagHalfwidth
-)
-
-const (
-	numTypeBits = 3
-	typeShift   = 16 - numTypeBits
-
-	// tagNeedsFold is true for all fullwidth and halfwidth runes except for
-	// the Won sign U+20A9.
-	tagNeedsFold = 0x1000
-
-	// The Korean Won sign is halfwidth, but SHOULD NOT be mapped to a wide
-	// variant.
-	wonSign rune = 0x20A9
-)
diff --git a/src/vendor/golang_org/x/text/width/width.go b/src/vendor/golang_org/x/text/width/width.go
deleted file mode 100644
index 27f55b8..0000000
--- a/src/vendor/golang_org/x/text/width/width.go
+++ /dev/null
@@ -1,206 +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.
-
-//go:generate stringer -type=Kind
-//go:generate go run gen.go gen_common.go gen_trieval.go
-
-// Package width provides functionality for handling different widths in text.
-//
-// Wide characters behave like ideographs; they tend to allow line breaks after
-// each character and remain upright in vertical text layout. Narrow characters
-// are kept together in words or runs that are rotated sideways in vertical text
-// layout.
-//
-// For more information, see http://unicode.org/reports/tr11/.
-package width // import "golang_org/x/text/width"
-
-import (
-	"unicode/utf8"
-
-	"golang_org/x/text/transform"
-)
-
-// TODO
-// 1) Reduce table size by compressing blocks.
-// 2) API proposition for computing display length
-//    (approximation, fixed pitch only).
-// 3) Implement display length.
-
-// Kind indicates the type of width property as defined in http://unicode.org/reports/tr11/.
-type Kind int
-
-const (
-	// Neutral characters do not occur in legacy East Asian character sets.
-	Neutral Kind = iota
-
-	// EastAsianAmbiguous characters that can be sometimes wide and sometimes
-	// narrow and require additional information not contained in the character
-	// code to further resolve their width.
-	EastAsianAmbiguous
-
-	// EastAsianWide characters are wide in its usual form. They occur only in
-	// the context of East Asian typography. These runes may have explicit
-	// halfwidth counterparts.
-	EastAsianWide
-
-	// EastAsianNarrow characters are narrow in its usual form. They often have
-	// fullwidth counterparts.
-	EastAsianNarrow
-
-	// Note: there exist Narrow runes that do not have fullwidth or wide
-	// counterparts, despite what the definition says (e.g. U+27E6).
-
-	// EastAsianFullwidth characters have a compatibility decompositions of type
-	// wide that map to a narrow counterpart.
-	EastAsianFullwidth
-
-	// EastAsianHalfwidth characters have a compatibility decomposition of type
-	// narrow that map to a wide or ambiguous counterpart, plus U+20A9 ₩ WON
-	// SIGN.
-	EastAsianHalfwidth
-
-	// Note: there exist runes that have a halfwidth counterparts but that are
-	// classified as Ambiguous, rather than wide (e.g. U+2190).
-)
-
-// TODO: the generated tries need to return size 1 for invalid runes for the
-// width to be computed correctly (each byte should render width 1)
-
-var trie = newWidthTrie(0)
-
-// Lookup reports the Properties of the first rune in b and the number of bytes
-// of its UTF-8 encoding.
-func Lookup(b []byte) (p Properties, size int) {
-	v, sz := trie.lookup(b)
-	return Properties{elem(v), b[sz-1]}, sz
-}
-
-// LookupString reports the Properties of the first rune in s and the number of
-// bytes of its UTF-8 encoding.
-func LookupString(s string) (p Properties, size int) {
-	v, sz := trie.lookupString(s)
-	return Properties{elem(v), s[sz-1]}, sz
-}
-
-// LookupRune reports the Properties of rune r.
-func LookupRune(r rune) Properties {
-	var buf [4]byte
-	n := utf8.EncodeRune(buf[:], r)
-	v, _ := trie.lookup(buf[:n])
-	last := byte(r)
-	if r >= utf8.RuneSelf {
-		last = 0x80 + byte(r&0x3f)
-	}
-	return Properties{elem(v), last}
-}
-
-// Properties provides access to width properties of a rune.
-type Properties struct {
-	elem elem
-	last byte
-}
-
-func (e elem) kind() Kind {
-	return Kind(e >> typeShift)
-}
-
-// Kind returns the Kind of a rune as defined in Unicode TR #11.
-// See http://unicode.org/reports/tr11/ for more details.
-func (p Properties) Kind() Kind {
-	return p.elem.kind()
-}
-
-// Folded returns the folded variant of a rune or 0 if the rune is canonical.
-func (p Properties) Folded() rune {
-	if p.elem&tagNeedsFold != 0 {
-		buf := inverseData[byte(p.elem)]
-		buf[buf[0]] ^= p.last
-		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
-		return r
-	}
-	return 0
-}
-
-// Narrow returns the narrow variant of a rune or 0 if the rune is already
-// narrow or doesn't have a narrow variant.
-func (p Properties) Narrow() rune {
-	if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous) {
-		buf := inverseData[byte(p.elem)]
-		buf[buf[0]] ^= p.last
-		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
-		return r
-	}
-	return 0
-}
-
-// Wide returns the wide variant of a rune or 0 if the rune is already
-// wide or doesn't have a wide variant.
-func (p Properties) Wide() rune {
-	if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianHalfwidth || k == EastAsianNarrow) {
-		buf := inverseData[byte(p.elem)]
-		buf[buf[0]] ^= p.last
-		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
-		return r
-	}
-	return 0
-}
-
-// TODO for Properties:
-// - Add Fullwidth/Halfwidth or Inverted methods for computing variants
-// mapping.
-// - Add width information (including information on non-spacing runes).
-
-// Transformer implements the transform.Transformer interface.
-type Transformer struct {
-	t transform.SpanningTransformer
-}
-
-// Reset implements the transform.Transformer interface.
-func (t Transformer) Reset() { t.t.Reset() }
-
-// Transform implements the transform.Transformer interface.
-func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-	return t.t.Transform(dst, src, atEOF)
-}
-
-// Span implements the transform.SpanningTransformer interface.
-func (t Transformer) Span(src []byte, atEOF bool) (n int, err error) {
-	return t.t.Span(src, atEOF)
-}
-
-// Bytes returns a new byte slice with the result of applying t to b.
-func (t Transformer) Bytes(b []byte) []byte {
-	b, _, _ = transform.Bytes(t, b)
-	return b
-}
-
-// String returns a string with the result of applying t to s.
-func (t Transformer) String(s string) string {
-	s, _, _ = transform.String(t, s)
-	return s
-}
-
-var (
-	// Fold is a transform that maps all runes to their canonical width.
-	//
-	// Note that the NFKC and NFKD transforms in golang.org/x/text/unicode/norm
-	// provide a more generic folding mechanism.
-	Fold Transformer = Transformer{foldTransform{}}
-
-	// Widen is a transform that maps runes to their wide variant, if
-	// available.
-	Widen Transformer = Transformer{wideTransform{}}
-
-	// Narrow is a transform that maps runes to their narrow variant, if
-	// available.
-	Narrow Transformer = Transformer{narrowTransform{}}
-)
-
-// TODO: Consider the following options:
-// - Treat Ambiguous runes that have a halfwidth counterpart as wide, or some
-//   generalized variant of this.
-// - Consider a wide Won character to be the default width (or some generalized
-//   variant of this).
-// - Filter the set of characters that gets converted (the preferred approach is
-//   to allow applying filters to transforms).
diff --git a/test/alias2.go b/test/alias2.go
new file mode 100644
index 0000000..32c3654
--- /dev/null
+++ b/test/alias2.go
@@ -0,0 +1,104 @@
+// 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 basic restrictions on type aliases.
+
+package p
+
+import (
+	"reflect"
+	. "reflect"
+)
+
+type T0 struct{}
+
+// Valid type alias declarations.
+
+type _ = T0
+type _ = int
+type _ = struct{}
+type _ = reflect.Value
+type _ = Value
+
+type (
+	A0 = T0
+	A1 = int
+	A2 = struct{}
+	A3 = reflect.Value
+	A4 = Value
+	A5 = Value
+
+	N0 A0
+)
+
+// Methods can be declared on the original named type and the alias.
+func (T0) m1()  {} // GCCGO_ERROR "previous"
+func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m2()  {}
+
+// Type aliases and the original type name can be used interchangeably.
+var _ A0 = T0{}
+var _ T0 = A0{}
+
+// But aliases and original types cannot be used with new types based on them.
+var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+var _ A5 = Value{}
+
+var _ interface {
+	m1()
+	m2()
+} = T0{}
+
+var _ interface {
+	m1()
+	m2()
+} = A0{}
+
+func _() {
+	type _ = T0
+	type _ = int
+	type _ = struct{}
+	type _ = reflect.Value
+	type _ = Value
+
+	type (
+		A0 = T0
+		A1 = int
+		A2 = struct{}
+		A3 = reflect.Value
+		A4 = Value
+		A5 Value
+
+		N0 A0
+	)
+
+	var _ A0 = T0{}
+	var _ T0 = A0{}
+
+	var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+	var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+	var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment|incompatible type"
+}
+
+// Invalid type alias declarations.
+
+type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
+
+func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
+func (A2) m() {} // ERROR "invalid receiver type"
+func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+func (A4) m() {} // ERROR "reflect.Value.m redeclared in this block" "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+
+type B1 = struct{}
+
+func (B1) m() {} // ERROR "m redeclared in this block" "invalid receiver type"
+
+// TODO(gri) expand
diff --git a/test/alias3.dir/a.go b/test/alias3.dir/a.go
new file mode 100644
index 0000000..09b3408
--- /dev/null
+++ b/test/alias3.dir/a.go
@@ -0,0 +1,42 @@
+// Copyright 2017 The Go Authors. 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 "go/build"
+
+type (
+	Float64 = float64
+	Rune    = rune
+)
+
+type (
+	Int       int
+	IntAlias  = Int
+	IntAlias2 = IntAlias
+	S         struct {
+		Int
+		IntAlias
+		IntAlias2
+	}
+)
+
+type (
+	Context = build.Context
+)
+
+type (
+	I1 interface {
+		M1(IntAlias2) Float64
+		M2() Context
+	}
+
+	I2 = interface {
+		M1(Int) float64
+		M2() build.Context
+	}
+)
+
+var i1 I1
+var i2 I2 = i1
diff --git a/test/alias3.dir/b.go b/test/alias3.dir/b.go
new file mode 100644
index 0000000..8a86cc0
--- /dev/null
+++ b/test/alias3.dir/b.go
@@ -0,0 +1,26 @@
+// Copyright 2017 The Go Authors. 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"
+	. "go/build"
+)
+
+func F(x float64) a.Float64 {
+	return x
+}
+
+type MyContext = Context // = build.Context
+
+var C a.Context = Default
+
+type S struct{}
+
+func (S) M1(x a.IntAlias) float64 { return a.Float64(x) }
+func (S) M2() Context             { return Default }
+
+var _ a.I1 = S{}
+var _ a.I2 = S{}
diff --git a/test/alias3.dir/c.go b/test/alias3.dir/c.go
new file mode 100644
index 0000000..161d593
--- /dev/null
+++ b/test/alias3.dir/c.go
@@ -0,0 +1,25 @@
+// Copyright 2017 The Go Authors. 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"
+	"./b"
+)
+
+func main() {
+	var _ float64 = b.F(0)
+	var _ a.Rune = int32(0)
+
+	// embedded types can have different names but the same types
+	var s a.S
+	s.Int = 1
+	s.IntAlias = s.Int
+	s.IntAlias2 = s.Int
+
+	// aliases denote identical types across packages
+	var c a.Context = b.C
+	var _ b.MyContext = c
+}
diff --git a/test/alias3.go b/test/alias3.go
new file mode 100644
index 0000000..c3732c3
--- /dev/null
+++ b/test/alias3.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2017 The Go Authors. 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/append1.go b/test/append1.go
new file mode 100644
index 0000000..6d42368
--- /dev/null
+++ b/test/append1.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 append arguments requirements are enforced by the
+// compiler.
+
+package main
+
+func main() {
+
+	s := make([]int, 8)
+
+	_ = append()           // ERROR "missing arguments to append"
+	_ = append(s...)       // ERROR "cannot use ... on first argument"
+	_ = append(s, 2, s...) // ERROR "too many arguments to append"
+
+}
diff --git a/test/armimm.go b/test/armimm.go
new file mode 100644
index 0000000..65124ad
--- /dev/null
+++ b/test/armimm.go
@@ -0,0 +1,179 @@
+// run
+
+// Copyright 2017 The Go 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 the splitting of constants into
+// multiple immediates on arm.
+
+package main
+
+import "fmt"
+
+const c32a = 0x00aa00dd
+const c32s = 0x00ffff00
+const c64a = 0x00aa00dd55000066
+const c64s = 0x00ffff00004fff00
+
+//go:noinline
+func add32a(x uint32) uint32 {
+	return x + c32a
+}
+
+//go:noinline
+func add32s(x uint32) uint32 {
+	return x + c32s
+}
+
+//go:noinline
+func sub32a(x uint32) uint32 {
+	return x - c32a
+}
+
+//go:noinline
+func sub32s(x uint32) uint32 {
+	return x - c32s
+}
+
+//go:noinline
+func or32(x uint32) uint32 {
+	return x | c32a
+}
+
+//go:noinline
+func xor32(x uint32) uint32 {
+	return x ^ c32a
+}
+
+//go:noinline
+func subr32a(x uint32) uint32 {
+	return c32a - x
+}
+
+//go:noinline
+func subr32s(x uint32) uint32 {
+	return c32s - x
+}
+
+//go:noinline
+func bic32(x uint32) uint32 {
+	return x &^ c32a
+}
+
+//go:noinline
+func add64a(x uint64) uint64 {
+	return x + c64a
+}
+
+//go:noinline
+func add64s(x uint64) uint64 {
+	return x + c64s
+}
+
+//go:noinline
+func sub64a(x uint64) uint64 {
+	return x - c64a
+}
+
+//go:noinline
+func sub64s(x uint64) uint64 {
+	return x - c64s
+}
+
+//go:noinline
+func or64(x uint64) uint64 {
+	return x | c64a
+}
+
+//go:noinline
+func xor64(x uint64) uint64 {
+	return x ^ c64a
+}
+
+//go:noinline
+func subr64a(x uint64) uint64 {
+	return c64a - x
+}
+
+//go:noinline
+func subr64s(x uint64) uint64 {
+	return c64s - x
+}
+
+//go:noinline
+func bic64(x uint64) uint64 {
+	return x &^ c64a
+}
+
+// Note: x-c gets rewritten to x+(-c), so SUB and SBC are not directly testable.
+// I disabled that rewrite rule before running this test.
+
+func main() {
+	test32()
+	test64()
+}
+
+func test32() {
+	var a uint32 = 0x11111111
+	var want, got uint32
+	if want, got = a+c32a, add32a(a); got != want {
+		panic(fmt.Sprintf("add32a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a+c32s, add32s(a); got != want {
+		panic(fmt.Sprintf("add32s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a-c32a, sub32a(a); got != want {
+		panic(fmt.Sprintf("sub32a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a-c32s, sub32s(a); got != want {
+		panic(fmt.Sprintf("sub32s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a|c32a, or32(a); got != want {
+		panic(fmt.Sprintf("or32(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a^c32a, xor32(a); got != want {
+		panic(fmt.Sprintf("xor32(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = c32a-a, subr32a(a); got != want {
+		panic(fmt.Sprintf("subr32a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = c32s-a, subr32s(a); got != want {
+		panic(fmt.Sprintf("subr32s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a&^c32a, bic32(a); got != want {
+		panic(fmt.Sprintf("bic32(%x) = %x, want %x", a, got, want))
+	}
+}
+
+func test64() {
+	var a uint64 = 0x1111111111111111
+	var want, got uint64
+	if want, got = a+c64a, add64a(a); got != want {
+		panic(fmt.Sprintf("add64a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a+c64s, add64s(a); got != want {
+		panic(fmt.Sprintf("add64s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a-c64a, sub64a(a); got != want {
+		panic(fmt.Sprintf("sub64a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a-c64s, sub64s(a); got != want {
+		panic(fmt.Sprintf("sub64s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a|c64a, or64(a); got != want {
+		panic(fmt.Sprintf("or64(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a^c64a, xor64(a); got != want {
+		panic(fmt.Sprintf("xor64(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = c64a-a, subr64a(a); got != want {
+		panic(fmt.Sprintf("subr64a(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = c64s-a, subr64s(a); got != want {
+		panic(fmt.Sprintf("subr64s(%x) = %x, want %x", a, got, want))
+	}
+	if want, got = a&^c64a, bic64(a); got != want {
+		panic(fmt.Sprintf("bic64(%x) = %x, want %x", a, got, want))
+	}
+}
diff --git a/test/bench/go1/parserdata_test.go b/test/bench/go1/parserdata_test.go
index 001c5d8..8255d18 100644
--- a/test/bench/go1/parserdata_test.go
+++ b/test/bench/go1/parserdata_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Input for parser benchmark.
-// This was generated by starting with a the contents of
+// This was generated by starting with the contents of
 // 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
diff --git a/test/chan/doubleselect.go b/test/chan/doubleselect.go
index 6be3faf..ff69dbe 100644
--- a/test/chan/doubleselect.go
+++ b/test/chan/doubleselect.go
@@ -61,6 +61,7 @@ func recver(in <-chan int) {
 func main() {
 	runtime.GOMAXPROCS(2)
 
+	flag.Parse()
 	c1 := make(chan int)
 	c2 := make(chan int)
 	c3 := make(chan int)
diff --git a/test/chan/fifo.go b/test/chan/fifo.go
index 70d20b3..0001bcf 100644
--- a/test/chan/fifo.go
+++ b/test/chan/fifo.go
@@ -54,4 +54,3 @@ func main() {
 	AsynchFifo()
 	SynchFifo()
 }
-
diff --git a/test/chan/perm.go b/test/chan/perm.go
index 919fa30..7da88bd 100644
--- a/test/chan/perm.go
+++ b/test/chan/perm.go
@@ -24,19 +24,23 @@ func main() {
 	cr = cs // ERROR "illegal types|incompatible|cannot"
 	cs = cr // ERROR "illegal types|incompatible|cannot"
 
-	c <- 0 // ok
-	<-c    // ok
-	x, ok := <-c	// ok
+	var n int
+	<-n    // ERROR "receive from non-chan"
+	n <- 2 // ERROR "send to non-chan"
+
+	c <- 0       // ok
+	<-c          // ok
+	x, ok := <-c // ok
 	_, _ = x, ok
 
-	cr <- 0 // ERROR "send"
-	<-cr    // ok
-	x, ok = <-cr	// ok
+	cr <- 0      // ERROR "send"
+	<-cr         // ok
+	x, ok = <-cr // ok
 	_, _ = x, ok
 
-	cs <- 0 // ok
-	<-cs    // ERROR "receive"
-	x, ok = <-cs	// ERROR "receive"
+	cs <- 0      // ok
+	<-cs         // ERROR "receive"
+	x, ok = <-cs // ERROR "receive"
 	_, _ = x, ok
 
 	select {
@@ -53,13 +57,14 @@ func main() {
 		_ = x
 	}
 
-	for _ = range cs {// ERROR "receive"
+	for _ = range cs { // ERROR "receive"
 	}
 
-	for range cs {// ERROR "receive"
+	for range cs { // ERROR "receive"
 	}
 
 	close(c)
 	close(cs)
-	close(cr)  // ERROR "receive"
+	close(cr) // ERROR "receive"
+	close(n)  // ERROR "invalid operation.*non-chan type"
 }
diff --git a/test/chan/powser1.go b/test/chan/powser1.go
index 6bf2a91..9386200 100644
--- a/test/chan/powser1.go
+++ b/test/chan/powser1.go
@@ -17,12 +17,12 @@ package main
 
 import "os"
 
-type rat struct  {
-	num, den  int64	// numerator, denominator
+type rat struct {
+	num, den int64 // numerator, denominator
 }
 
 func (u rat) pr() {
-	if u.den==1 {
+	if u.den == 1 {
 		print(u.num)
 	} else {
 		print(u.num, "/", u.den)
@@ -35,12 +35,12 @@ func (u rat) eq(c rat) bool {
 }
 
 type dch struct {
-	req chan  int
-	dat chan  rat
+	req chan int
+	dat chan rat
 	nam int
 }
 
-type dch2 [2] *dch
+type dch2 [2]*dch
 
 var chnames string
 var chnameserial int
@@ -77,17 +77,17 @@ func mkdch2() *dch2 {
 // a signal on the release-wait channel tells the next newer
 // generation to begin servicing out[1].
 
-func dosplit(in *dch, out *dch2, wait chan int ) {
-	both := false	// do not service both channels
+func dosplit(in *dch, out *dch2, wait chan int) {
+	both := false // do not service both channels
 
 	select {
 	case <-out[0].req:
-		
+
 	case <-wait:
 		both = true
 		select {
 		case <-out[0].req:
-			
+
 		case <-out[1].req:
 			out[0], out[1] = out[1], out[0]
 		}
@@ -95,7 +95,7 @@ func dosplit(in *dch, out *dch2, wait chan int ) {
 
 	seqno++
 	in.req <- seqno
-	release := make(chan  int)
+	release := make(chan int)
 	go dosplit(in, out, release)
 	dat := <-in.dat
 	out[0].dat <- dat
@@ -128,17 +128,19 @@ func get(in *dch) rat {
 
 func getn(in []*dch) []rat {
 	n := len(in)
-	if n != 2 { panic("bad n in getn") }
-	req := new([2] chan int)
-	dat := new([2] chan rat)
+	if n != 2 {
+		panic("bad n in getn")
+	}
+	req := new([2]chan int)
+	dat := new([2]chan rat)
 	out := make([]rat, 2)
 	var i int
 	var it rat
-	for i=0; i<n; i++ {
+	for i = 0; i < n; i++ {
 		req[i] = in[i].req
 		dat[i] = nil
 	}
-	for n=2*n; n>0; n-- {
+	for n = 2 * n; n > 0; n-- {
 		seqno++
 
 		select {
@@ -178,8 +180,8 @@ func repeat(dat rat, out *dch) {
 	}
 }
 
-type PS *dch	// power series
-type PS2 *[2] PS // pair of power series
+type PS *dch    // power series
+type PS2 *[2]PS // pair of power series
 
 var Ones PS
 var Twos PS
@@ -200,23 +202,27 @@ func mkPS2() *dch2 {
 
 // Integer gcd; needed for rational arithmetic
 
-func gcd (u, v int64) int64 {
-	if u < 0 { return gcd(-u, v) }
-	if u == 0 { return v }
+func gcd(u, v int64) int64 {
+	if u < 0 {
+		return gcd(-u, v)
+	}
+	if u == 0 {
+		return v
+	}
 	return gcd(v%u, u)
 }
 
 // Make a rational from two ints and from one int
 
 func i2tor(u, v int64) rat {
-	g := gcd(u,v)
+	g := gcd(u, v)
 	var r rat
 	if v > 0 {
-		r.num = u/g
-		r.den = v/g
+		r.num = u / g
+		r.den = v / g
 	} else {
-		r.num = -u/g
-		r.den = -v/g
+		r.num = -u / g
+		r.den = -v / g
 	}
 	return r
 }
@@ -228,29 +234,30 @@ func itor(u int64) rat {
 var zero rat
 var one rat
 
-
 // End mark and end test
 
 var finis rat
 
 func end(u rat) int64 {
-	if u.den==0 { return 1 }
+	if u.den == 0 {
+		return 1
+	}
 	return 0
 }
 
 // Operations on rationals
 
 func add(u, v rat) rat {
-	g := gcd(u.den,v.den)
-	return  i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
+	g := gcd(u.den, v.den)
+	return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
 }
 
 func mul(u, v rat) rat {
-	g1 := gcd(u.num,v.den)
-	g2 := gcd(u.den,v.num)
+	g1 := gcd(u.num, v.den)
+	g2 := gcd(u.den, v.num)
 	var r rat
-	r.num = (u.num/g1)*(v.num/g2)
-	r.den = (u.den/g2)*(v.den/g1)
+	r.num = (u.num / g1) * (v.num / g2)
+	r.den = (u.den / g2) * (v.den / g1)
 	return r
 }
 
@@ -262,23 +269,25 @@ func sub(u, v rat) rat {
 	return add(u, neg(v))
 }
 
-func inv(u rat) rat {	// invert a rat
-	if u.num == 0 { panic("zero divide in inv") }
+func inv(u rat) rat { // invert a rat
+	if u.num == 0 {
+		panic("zero divide in inv")
+	}
 	return i2tor(u.den, u.num)
 }
 
 // print eval in floating point of PS at x=c to n terms
 func evaln(c rat, U PS, n int) {
 	xn := float64(1)
-	x := float64(c.num)/float64(c.den)
+	x := float64(c.num) / float64(c.den)
 	val := float64(0)
-	for i:=0; i<n; i++ {
+	for i := 0; i < n; i++ {
 		u := get(U)
 		if end(u) != 0 {
 			break
 		}
-		val = val + x * float64(u.num)/float64(u.den)
-		xn = xn*x
+		val = val + x*float64(u.num)/float64(u.den)
+		xn = xn * x
 	}
 	print(val, "\n")
 }
@@ -286,7 +295,7 @@ func evaln(c rat, U PS, n int) {
 // Print n terms of a power series
 func printn(U PS, n int) {
 	done := false
-	for ; !done && n>0; n-- {
+	for ; !done && n > 0; n-- {
 		u := get(U)
 		if end(u) != 0 {
 			done = true
@@ -299,10 +308,14 @@ func printn(U PS, n int) {
 
 // Evaluate n terms of power series U at x=c
 func eval(c rat, U PS, n int) rat {
-	if n==0 { return zero }
+	if n == 0 {
+		return zero
+	}
 	y := get(U)
-	if end(y) != 0 { return zero }
-	return add(y,mul(c,eval(c,U,n-1)))
+	if end(y) != 0 {
+		return zero
+	}
+	return add(y, mul(c, eval(c, U, n-1)))
 }
 
 // Power-series constructors return channels on which power
@@ -313,7 +326,7 @@ func eval(c rat, U PS, n int) rat {
 
 func Split(U PS) *dch2 {
 	UU := mkdch2()
-	go split(U,UU)
+	go split(U, UU)
 	return UU
 }
 
@@ -324,16 +337,16 @@ func Add(U, V PS) PS {
 		var uv []rat
 		for {
 			<-Z.req
-			uv = get2(U,V)
-			switch end(uv[0])+2*end(uv[1]) {
+			uv = get2(U, V)
+			switch end(uv[0]) + 2*end(uv[1]) {
 			case 0:
 				Z.dat <- add(uv[0], uv[1])
 			case 1:
 				Z.dat <- uv[1]
-				copy(V,Z)
+				copy(V, Z)
 			case 2:
 				Z.dat <- uv[0]
-				copy(U,Z)
+				copy(U, Z)
 			case 3:
 				Z.dat <- finis
 			}
@@ -343,7 +356,7 @@ func Add(U, V PS) PS {
 }
 
 // Multiply a power series by a constant
-func Cmul(c rat,U PS) PS {
+func Cmul(c rat, U PS) PS {
 	Z := mkPS()
 	go func() {
 		done := false
@@ -353,7 +366,7 @@ func Cmul(c rat,U PS) PS {
 			if end(u) != 0 {
 				done = true
 			} else {
-				Z.dat <- mul(c,u)
+				Z.dat <- mul(c, u)
 			}
 		}
 		Z.dat <- finis
@@ -372,8 +385,10 @@ func Sub(U, V PS) PS {
 func Monmul(U PS, n int) PS {
 	Z := mkPS()
 	go func() {
-		for ; n>0; n-- { put(zero,Z) }
-		copy(U,Z)
+		for ; n > 0; n-- {
+			put(zero, Z)
+		}
+		copy(U, Z)
 	}()
 	return Z
 }
@@ -381,25 +396,27 @@ func Monmul(U PS, n int) PS {
 // Multiply by x
 
 func Xmul(U PS) PS {
-	return Monmul(U,1)
+	return Monmul(U, 1)
 }
 
 func Rep(c rat) PS {
 	Z := mkPS()
-	go repeat(c,Z)
+	go repeat(c, Z)
 	return Z
 }
 
 // Monomial c*x^n
 
 func Mon(c rat, n int) PS {
-	Z:=mkPS()
+	Z := mkPS()
 	go func() {
-		if(c.num!=0) {
-			for ; n>0; n=n-1 { put(zero,Z) }
-			put(c,Z)
+		if c.num != 0 {
+			for ; n > 0; n = n - 1 {
+				put(zero, Z)
+			}
+			put(c, Z)
 		}
-		put(finis,Z)
+		put(finis, Z)
 	}()
 	return Z
 }
@@ -407,8 +424,8 @@ func Mon(c rat, n int) PS {
 func Shift(c rat, U PS) PS {
 	Z := mkPS()
 	go func() {
-		put(c,Z)
-		copy(U,Z)
+		put(c, Z)
+		copy(U, Z)
 	}()
 	return Z
 }
@@ -440,20 +457,20 @@ func Poly(a []rat) PS {
 //	then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
 
 func Mul(U, V PS) PS {
-	Z:=mkPS()
+	Z := mkPS()
 	go func() {
 		<-Z.req
-		uv := get2(U,V)
-		if end(uv[0])!=0 || end(uv[1]) != 0 {
+		uv := get2(U, V)
+		if end(uv[0]) != 0 || end(uv[1]) != 0 {
 			Z.dat <- finis
 		} else {
-			Z.dat <- mul(uv[0],uv[1])
+			Z.dat <- mul(uv[0], uv[1])
 			UU := Split(U)
 			VV := Split(V)
-			W := Add(Cmul(uv[0],VV[0]),Cmul(uv[1],UU[0]))
+			W := Add(Cmul(uv[0], VV[0]), Cmul(uv[1], UU[0]))
 			<-Z.req
 			Z.dat <- get(W)
-			copy(Add(W,Mul(UU[1],VV[1])),Z)
+			copy(Add(W, Mul(UU[1], VV[1])), Z)
 		}
 	}()
 	return Z
@@ -462,18 +479,18 @@ func Mul(U, V PS) PS {
 // Differentiate
 
 func Diff(U PS) PS {
-	Z:=mkPS()
+	Z := mkPS()
 	go func() {
 		<-Z.req
 		u := get(U)
 		if end(u) == 0 {
-			done:=false
-			for i:=1; !done; i++ {
+			done := false
+			for i := 1; !done; i++ {
 				u = get(U)
 				if end(u) != 0 {
 					done = true
 				} else {
-					Z.dat <- mul(itor(int64(i)),u)
+					Z.dat <- mul(itor(int64(i)), u)
 					<-Z.req
 				}
 			}
@@ -484,16 +501,18 @@ func Diff(U PS) PS {
 }
 
 // Integrate, with const of integration
-func Integ(c rat,U PS) PS {
-	Z:=mkPS()
+func Integ(c rat, U PS) PS {
+	Z := mkPS()
 	go func() {
-		put(c,Z)
-		done:=false
-		for i:=1; !done; i++ {
+		put(c, Z)
+		done := false
+		for i := 1; !done; i++ {
 			<-Z.req
 			u := get(U)
-			if end(u) != 0 { done= true }
-			Z.dat <- mul(i2tor(1,int64(i)),u)
+			if end(u) != 0 {
+				done = true
+			}
+			Z.dat <- mul(i2tor(1, int64(i)), u)
 		}
 		Z.dat <- finis
 	}()
@@ -503,17 +522,17 @@ func Integ(c rat,U PS) PS {
 // Binomial theorem (1+x)^c
 
 func Binom(c rat) PS {
-	Z:=mkPS()
+	Z := mkPS()
 	go func() {
 		n := 1
 		t := itor(1)
-		for c.num!=0 {
-			put(t,Z)
-			t = mul(mul(t,c),i2tor(1,int64(n)))
-			c = sub(c,one)
+		for c.num != 0 {
+			put(t, Z)
+			t = mul(mul(t, c), i2tor(1, int64(n)))
+			c = sub(c, one)
 			n++
 		}
-		put(finis,Z)
+		put(finis, Z)
 	}()
 	return Z
 }
@@ -527,14 +546,14 @@ func Binom(c rat) PS {
 //	ZZ = -UU*(z+x*ZZ)/u
 
 func Recip(U PS) PS {
-	Z:=mkPS()
+	Z := mkPS()
 	go func() {
-		ZZ:=mkPS2()
+		ZZ := mkPS2()
 		<-Z.req
 		z := inv(get(U))
 		Z.dat <- z
-		split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
-		copy(ZZ[1],Z)
+		split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
+		copy(ZZ[1], Z)
 	}()
 	return Z
 }
@@ -548,7 +567,7 @@ func Recip(U PS) PS {
 
 func Exp(U PS) PS {
 	ZZ := mkPS2()
-	split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+	split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
 	return ZZ[1]
 }
 
@@ -559,7 +578,7 @@ func Exp(U PS) PS {
 // bug: a nonzero constant term is ignored
 
 func Subst(U, V PS) PS {
-	Z:= mkPS()
+	Z := mkPS()
 	go func() {
 		VV := Split(V)
 		<-Z.req
@@ -567,9 +586,9 @@ func Subst(U, V PS) PS {
 		Z.dat <- u
 		if end(u) == 0 {
 			if end(get(VV[0])) != 0 {
-				put(finis,Z)
+				put(finis, Z)
 			} else {
-				copy(Mul(VV[0],Subst(U,VV[1])),Z)
+				copy(Mul(VV[0], Subst(U, VV[1])), Z)
 			}
 		}
 	}()
@@ -580,7 +599,7 @@ func Subst(U, V PS) PS {
 // Each Ui is multiplied by c^i and followed by n-1 zeros
 
 func MonSubst(U PS, c0 rat, n int) PS {
-	Z:= mkPS()
+	Z := mkPS()
 	go func() {
 		c := one
 		for {
@@ -601,14 +620,13 @@ func MonSubst(U PS, c0 rat, n int) PS {
 	return Z
 }
 
-
 func Init() {
 	chnameserial = -1
 	seqno = 0
 	chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 	zero = itor(0)
 	one = itor(1)
-	finis = i2tor(1,0)
+	finis = i2tor(1, 0)
 	Ones = Rep(one)
 	Twos = Rep(itor(2))
 }
@@ -627,7 +645,8 @@ func check(U PS, c rat, count int, str string) {
 	}
 }
 
-const N=10
+const N = 10
+
 func checka(U PS, a []rat, str string) {
 	for i := 0; i < N; i++ {
 		check(U, a[i], 1, str)
@@ -636,53 +655,64 @@ func checka(U PS, a []rat, str string) {
 
 func main() {
 	Init()
-	if len(os.Args) > 1 {  // print
-		print("Ones: "); printn(Ones, 10)
-		print("Twos: "); printn(Twos, 10)
-		print("Add: "); printn(Add(Ones, Twos), 10)
-		print("Diff: "); printn(Diff(Ones), 10)
-		print("Integ: "); printn(Integ(zero, Ones), 10)
-		print("CMul: "); printn(Cmul(neg(one), Ones), 10)
-		print("Sub: "); printn(Sub(Ones, Twos), 10)
-		print("Mul: "); printn(Mul(Ones, Ones), 10)
-		print("Exp: "); printn(Exp(Ones), 15)
-		print("MonSubst: "); printn(MonSubst(Ones, neg(one), 2), 10)
-		print("ATan: "); printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
-	} else {  // test
+	if len(os.Args) > 1 { // print
+		print("Ones: ")
+		printn(Ones, 10)
+		print("Twos: ")
+		printn(Twos, 10)
+		print("Add: ")
+		printn(Add(Ones, Twos), 10)
+		print("Diff: ")
+		printn(Diff(Ones), 10)
+		print("Integ: ")
+		printn(Integ(zero, Ones), 10)
+		print("CMul: ")
+		printn(Cmul(neg(one), Ones), 10)
+		print("Sub: ")
+		printn(Sub(Ones, Twos), 10)
+		print("Mul: ")
+		printn(Mul(Ones, Ones), 10)
+		print("Exp: ")
+		printn(Exp(Ones), 15)
+		print("MonSubst: ")
+		printn(MonSubst(Ones, neg(one), 2), 10)
+		print("ATan: ")
+		printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
+	} else { // test
 		check(Ones, one, 5, "Ones")
-		check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones")  // 1 1 1 1 1
+		check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
 		check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
 		a := make([]rat, N)
 		d := Diff(Ones)
-		for i:=0; i < N; i++ {
-			a[i] = itor(int64(i+1))
+		for i := 0; i < N; i++ {
+			a[i] = itor(int64(i + 1))
 		}
-		checka(d, a, "Diff")  // 1 2 3 4 5
+		checka(d, a, "Diff") // 1 2 3 4 5
 		in := Integ(zero, Ones)
-		a[0] = zero  // integration constant
-		for i:=1; i < N; i++ {
+		a[0] = zero // integration constant
+		for i := 1; i < N; i++ {
 			a[i] = i2tor(1, int64(i))
 		}
-		checka(in, a, "Integ")  // 0 1 1/2 1/3 1/4 1/5
-		check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")  // -1 -1 -1 -1 -1
-		check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos")  // -1 -1 -1 -1 -1
+		checka(in, a, "Integ")                               // 0 1 1/2 1/3 1/4 1/5
+		check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")    // -1 -1 -1 -1 -1
+		check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
 		m := Mul(Ones, Ones)
-		for i:=0; i < N; i++ {
-			a[i] = itor(int64(i+1))
+		for i := 0; i < N; i++ {
+			a[i] = itor(int64(i + 1))
 		}
-		checka(m, a, "Mul")  // 1 2 3 4 5
+		checka(m, a, "Mul") // 1 2 3 4 5
 		e := Exp(Ones)
 		a[0] = itor(1)
 		a[1] = itor(1)
-		a[2] = i2tor(3,2)
-		a[3] = i2tor(13,6)
-		a[4] = i2tor(73,24)
-		a[5] = i2tor(167,40)
-		a[6] = i2tor(4051,720)
-		a[7] = i2tor(37633,5040)
-		a[8] = i2tor(43817,4480)
-		a[9] = i2tor(4596553,362880)
-		checka(e, a, "Exp")  // 1 1 3/2 13/6 73/24
+		a[2] = i2tor(3, 2)
+		a[3] = i2tor(13, 6)
+		a[4] = i2tor(73, 24)
+		a[5] = i2tor(167, 40)
+		a[6] = i2tor(4051, 720)
+		a[7] = i2tor(37633, 5040)
+		a[8] = i2tor(43817, 4480)
+		a[9] = i2tor(4596553, 362880)
+		checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
 		at := Integ(zero, MonSubst(Ones, neg(one), 2))
 		for c, i := 1, 0; i < N; i++ {
 			if i%2 == 0 {
@@ -692,20 +722,20 @@ func main() {
 				c *= -1
 			}
 		}
-		checka(at, a, "ATan")  // 0 -1 0 -1/3 0 -1/5
-/*
-		t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
-		a[0] = zero
-		a[1] = itor(1)
-		a[2] = zero
-		a[3] = i2tor(1,3)
-		a[4] = zero
-		a[5] = i2tor(2,15)
-		a[6] = zero
-		a[7] = i2tor(17,315)
-		a[8] = zero
-		a[9] = i2tor(62,2835)
-		checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
-*/
+		checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
+		/*
+			t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+			a[0] = zero
+			a[1] = itor(1)
+			a[2] = zero
+			a[3] = i2tor(1,3)
+			a[4] = zero
+			a[5] = i2tor(2,15)
+			a[6] = zero
+			a[7] = i2tor(17,315)
+			a[8] = zero
+			a[9] = i2tor(62,2835)
+			checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
+		*/
 	}
 }
diff --git a/test/chan/powser2.go b/test/chan/powser2.go
index 33abd5c..8fa3b7e 100644
--- a/test/chan/powser2.go
+++ b/test/chan/powser2.go
@@ -21,8 +21,8 @@ package main
 
 import "os"
 
-type rat struct  {
-	num, den  int64	// numerator, denominator
+type rat struct {
+	num, den int64 // numerator, denominator
 }
 
 type item interface {
@@ -30,8 +30,8 @@ type item interface {
 	eq(c item) bool
 }
 
-func (u *rat) pr(){
-	if u.den==1 {
+func (u *rat) pr() {
+	if u.den == 1 {
 		print(u.num)
 	} else {
 		print(u.num, "/", u.den)
@@ -45,12 +45,12 @@ func (u *rat) eq(c item) bool {
 }
 
 type dch struct {
-	req chan  int
-	dat chan  item
+	req chan int
+	dat chan item
 	nam int
 }
 
-type dch2 [2] *dch
+type dch2 [2]*dch
 
 var chnames string
 var chnameserial int
@@ -87,25 +87,25 @@ func mkdch2() *dch2 {
 // a signal on the release-wait channel tells the next newer
 // generation to begin servicing out[1].
 
-func dosplit(in *dch, out *dch2, wait chan int ){
-	both := false	// do not service both channels
+func dosplit(in *dch, out *dch2, wait chan int) {
+	both := false // do not service both channels
 
 	select {
 	case <-out[0].req:
-		
+
 	case <-wait:
 		both = true
 		select {
 		case <-out[0].req:
-			
+
 		case <-out[1].req:
-			out[0],out[1] = out[1], out[0]
+			out[0], out[1] = out[1], out[0]
 		}
 	}
 
 	seqno++
 	in.req <- seqno
-	release := make(chan  int)
+	release := make(chan int)
 	go dosplit(in, out, release)
 	dat := <-in.dat
 	out[0].dat <- dat
@@ -117,13 +117,13 @@ func dosplit(in *dch, out *dch2, wait chan int ){
 	release <- 0
 }
 
-func split(in *dch, out *dch2){
+func split(in *dch, out *dch2) {
 	release := make(chan int)
 	go dosplit(in, out, release)
 	release <- 0
 }
 
-func put(dat item, out *dch){
+func put(dat item, out *dch) {
 	<-out.req
 	out.dat <- dat
 }
@@ -137,21 +137,23 @@ func get(in *dch) *rat {
 // Get one item from each of n demand channels
 
 func getn(in []*dch) []item {
-	n:=len(in)
-	if n != 2 { panic("bad n in getn") }
-	req := make([] chan int, 2)
-	dat := make([] chan item, 2)
+	n := len(in)
+	if n != 2 {
+		panic("bad n in getn")
+	}
+	req := make([]chan int, 2)
+	dat := make([]chan item, 2)
 	out := make([]item, 2)
 	var i int
 	var it item
-	for i=0; i<n; i++ {
+	for i = 0; i < n; i++ {
 		req[i] = in[i].req
 		dat[i] = nil
 	}
-	for n=2*n; n>0; n-- {
+	for n = 2 * n; n > 0; n-- {
 		seqno++
 
-		select{
+		select {
 		case req[0] <- seqno:
 			dat[0] = in[0].dat
 			req[0] = nil
@@ -171,25 +173,25 @@ func getn(in []*dch) []item {
 
 // Get one item from each of 2 demand channels
 
-func get2(in0 *dch, in1 *dch)  []item {
+func get2(in0 *dch, in1 *dch) []item {
 	return getn([]*dch{in0, in1})
 }
 
-func copy(in *dch, out *dch){
+func copy(in *dch, out *dch) {
 	for {
 		<-out.req
 		out.dat <- get(in)
 	}
 }
 
-func repeat(dat item, out *dch){
+func repeat(dat item, out *dch) {
 	for {
 		put(dat, out)
 	}
 }
 
-type PS *dch	// power series
-type PS2 *[2] PS // pair of power series
+type PS *dch    // power series
+type PS2 *[2]PS // pair of power series
 
 var Ones PS
 var Twos PS
@@ -210,93 +212,100 @@ func mkPS2() *dch2 {
 
 // Integer gcd; needed for rational arithmetic
 
-func gcd (u, v int64) int64{
-	if u < 0 { return gcd(-u, v) }
-	if u == 0 { return v }
+func gcd(u, v int64) int64 {
+	if u < 0 {
+		return gcd(-u, v)
+	}
+	if u == 0 {
+		return v
+	}
 	return gcd(v%u, u)
 }
 
 // Make a rational from two ints and from one int
 
-func i2tor(u, v int64) *rat{
-	g := gcd(u,v)
+func i2tor(u, v int64) *rat {
+	g := gcd(u, v)
 	r := new(rat)
 	if v > 0 {
-		r.num = u/g
-		r.den = v/g
+		r.num = u / g
+		r.den = v / g
 	} else {
-		r.num = -u/g
-		r.den = -v/g
+		r.num = -u / g
+		r.den = -v / g
 	}
 	return r
 }
 
-func itor(u int64) *rat{
+func itor(u int64) *rat {
 	return i2tor(u, 1)
 }
 
 var zero *rat
 var one *rat
 
-
 // End mark and end test
 
 var finis *rat
 
 func end(u *rat) int64 {
-	if u.den==0 { return 1 }
+	if u.den == 0 {
+		return 1
+	}
 	return 0
 }
 
 // Operations on rationals
 
 func add(u, v *rat) *rat {
-	g := gcd(u.den,v.den)
-	return  i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
+	g := gcd(u.den, v.den)
+	return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
 }
 
-func mul(u, v *rat) *rat{
-	g1 := gcd(u.num,v.den)
-	g2 := gcd(u.den,v.num)
+func mul(u, v *rat) *rat {
+	g1 := gcd(u.num, v.den)
+	g2 := gcd(u.den, v.num)
 	r := new(rat)
-	r.num =(u.num/g1)*(v.num/g2)
-	r.den = (u.den/g2)*(v.den/g1)
+	r.num = (u.num / g1) * (v.num / g2)
+	r.den = (u.den / g2) * (v.den / g1)
 	return r
 }
 
-func neg(u *rat) *rat{
+func neg(u *rat) *rat {
 	return i2tor(-u.num, u.den)
 }
 
-func sub(u, v *rat) *rat{
+func sub(u, v *rat) *rat {
 	return add(u, neg(v))
 }
 
-func inv(u *rat) *rat{	// invert a rat
-	if u.num == 0 { panic("zero divide in inv") }
+func inv(u *rat) *rat { // invert a rat
+	if u.num == 0 {
+		panic("zero divide in inv")
+	}
 	return i2tor(u.den, u.num)
 }
 
 // print eval in floating point of PS at x=c to n terms
 func Evaln(c *rat, U PS, n int) {
 	xn := float64(1)
-	x := float64(c.num)/float64(c.den)
+	x := float64(c.num) / float64(c.den)
 	val := float64(0)
-	for i:=0; i<n; i++ {
+	for i := 0; i < n; i++ {
 		u := get(U)
 		if end(u) != 0 {
 			break
 		}
-		val = val + x * float64(u.num)/float64(u.den)
-		xn = xn*x
+		val = val + x*float64(u.num)/float64(u.den)
+		xn = xn * x
 	}
 	print(val, "\n")
 }
 
 // Print n terms of a power series
-func Printn(U PS, n int){
+func Printn(U PS, n int) {
 	done := false
-	for ; !done && n>0; n-- {
+	for ; !done && n > 0; n-- {
 		u := get(U)
 		if end(u) != 0 {
 			done = true
@@ -307,16 +316,20 @@ func Printn(U PS, n int){
 	print(("\n"))
 }
 
-func Print(U PS){
-	Printn(U,1000000000)
+func Print(U PS) {
+	Printn(U, 1000000000)
 }
 
 // Evaluate n terms of power series U at x=c
-func eval(c *rat, U PS, n int) *rat{
-	if n==0 { return zero }
+func eval(c *rat, U PS, n int) *rat {
+	if n == 0 {
+		return zero
+	}
 	y := get(U)
-	if end(y) != 0 { return zero }
-	return add(y,mul(c,eval(c,U,n-1)))
+	if end(y) != 0 {
+		return zero
+	}
+	return add(y, mul(c, eval(c, U, n-1)))
 }
 
 // Power-series constructors return channels on which power
@@ -325,29 +338,29 @@ func eval(c *rat, U PS, n int) *rat{
 
 // Make a pair of power series identical to a given power series
 
-func Split(U PS) *dch2{
+func Split(U PS) *dch2 {
 	UU := mkdch2()
-	go split(U,UU)
+	go split(U, UU)
 	return UU
 }
 
 // Add two power series
-func Add(U, V PS) PS{
+func Add(U, V PS) PS {
 	Z := mkPS()
-	go func(U, V, Z PS){
-		var uv [] item
+	go func(U, V, Z PS) {
+		var uv []item
 		for {
 			<-Z.req
-			uv = get2(U,V)
-			switch end(uv[0].(*rat))+2*end(uv[1].(*rat)) {
+			uv = get2(U, V)
+			switch end(uv[0].(*rat)) + 2*end(uv[1].(*rat)) {
 			case 0:
 				Z.dat <- add(uv[0].(*rat), uv[1].(*rat))
 			case 1:
 				Z.dat <- uv[1]
-				copy(V,Z)
+				copy(V, Z)
 			case 2:
 				Z.dat <- uv[0]
-				copy(U,Z)
+				copy(U, Z)
 			case 3:
 				Z.dat <- finis
 			}
@@ -357,9 +370,9 @@ func Add(U, V PS) PS{
 }
 
 // Multiply a power series by a constant
-func Cmul(c *rat,U PS) PS{
+func Cmul(c *rat, U PS) PS {
 	Z := mkPS()
-	go func(c *rat, U, Z PS){
+	go func(c *rat, U, Z PS) {
 		done := false
 		for !done {
 			<-Z.req
@@ -367,7 +380,7 @@ func Cmul(c *rat,U PS) PS{
 			if end(u) != 0 {
 				done = true
 			} else {
-				Z.dat <- mul(c,u)
+				Z.dat <- mul(c, u)
 			}
 		}
 		Z.dat <- finis
@@ -377,52 +390,56 @@ func Cmul(c *rat,U PS) PS{
 
 // Subtract
 
-func Sub(U, V PS) PS{
+func Sub(U, V PS) PS {
 	return Add(U, Cmul(neg(one), V))
 }
 
 // Multiply a power series by the monomial x^n
 
-func Monmul(U PS, n int) PS{
+func Monmul(U PS, n int) PS {
 	Z := mkPS()
-	go func(n int, U PS, Z PS){
-		for ; n>0; n-- { put(zero,Z) }
-		copy(U,Z)
+	go func(n int, U PS, Z PS) {
+		for ; n > 0; n-- {
+			put(zero, Z)
+		}
+		copy(U, Z)
 	}(n, U, Z)
 	return Z
 }
 
 // Multiply by x
 
-func Xmul(U PS) PS{
-	return Monmul(U,1)
+func Xmul(U PS) PS {
+	return Monmul(U, 1)
 }
 
-func Rep(c *rat) PS{
+func Rep(c *rat) PS {
 	Z := mkPS()
-	go repeat(c,Z)
+	go repeat(c, Z)
 	return Z
 }
 
 // Monomial c*x^n
 
-func Mon(c *rat, n int) PS{
-	Z:=mkPS()
-	go func(c *rat, n int, Z PS){
-		if(c.num!=0) {
-			for ; n>0; n=n-1 { put(zero,Z) }
-			put(c,Z)
+func Mon(c *rat, n int) PS {
+	Z := mkPS()
+	go func(c *rat, n int, Z PS) {
+		if c.num != 0 {
+			for ; n > 0; n = n - 1 {
+				put(zero, Z)
+			}
+			put(c, Z)
 		}
-		put(finis,Z)
+		put(finis, Z)
 	}(c, n, Z)
 	return Z
 }
 
-func Shift(c *rat, U PS) PS{
+func Shift(c *rat, U PS) PS {
 	Z := mkPS()
-	go func(c *rat, U, Z PS){
-		put(c,Z)
-		copy(U,Z)
+	go func(c *rat, U, Z PS) {
+		put(c, Z)
+		copy(U, Z)
 	}(c, U, Z)
 	return Z
 }
@@ -453,21 +470,21 @@ func Poly(a [] *rat) PS{
 //	let V = v + x*VV
 //	then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
 
-func Mul(U, V PS) PS{
-	Z:=mkPS()
-	go func(U, V, Z PS){
+func Mul(U, V PS) PS {
+	Z := mkPS()
+	go func(U, V, Z PS) {
 		<-Z.req
-		uv := get2(U,V)
-		if end(uv[0].(*rat))!=0 || end(uv[1].(*rat)) != 0 {
+		uv := get2(U, V)
+		if end(uv[0].(*rat)) != 0 || end(uv[1].(*rat)) != 0 {
 			Z.dat <- finis
 		} else {
-			Z.dat <- mul(uv[0].(*rat),uv[1].(*rat))
+			Z.dat <- mul(uv[0].(*rat), uv[1].(*rat))
 			UU := Split(U)
 			VV := Split(V)
-			W := Add(Cmul(uv[0].(*rat),VV[0]),Cmul(uv[1].(*rat),UU[0]))
+			W := Add(Cmul(uv[0].(*rat), VV[0]), Cmul(uv[1].(*rat), UU[0]))
 			<-Z.req
 			Z.dat <- get(W)
-			copy(Add(W,Mul(UU[1],VV[1])),Z)
+			copy(Add(W, Mul(UU[1], VV[1])), Z)
 		}
 	}(U, V, Z)
 	return Z
@@ -475,19 +492,19 @@ func Mul(U, V PS) PS{
 
 // Differentiate
 
-func Diff(U PS) PS{
-	Z:=mkPS()
-	go func(U, Z PS){
+func Diff(U PS) PS {
+	Z := mkPS()
+	go func(U, Z PS) {
 		<-Z.req
 		u := get(U)
 		if end(u) == 0 {
-			done:=false
-			for i:=1; !done; i++ {
+			done := false
+			for i := 1; !done; i++ {
 				u = get(U)
 				if end(u) != 0 {
-					done=true
+					done = true
 				} else {
-					Z.dat <- mul(itor(int64(i)),u)
+					Z.dat <- mul(itor(int64(i)), u)
 					<-Z.req
 				}
 			}
@@ -498,16 +515,18 @@ func Diff(U PS) PS{
 }
 
 // Integrate, with const of integration
-func Integ(c *rat,U PS) PS{
-	Z:=mkPS()
-	go func(c *rat, U, Z PS){
-		put(c,Z)
-		done:=false
-		for i:=1; !done; i++ {
+func Integ(c *rat, U PS) PS {
+	Z := mkPS()
+	go func(c *rat, U, Z PS) {
+		put(c, Z)
+		done := false
+		for i := 1; !done; i++ {
 			<-Z.req
 			u := get(U)
-			if end(u) != 0 { done= true }
-			Z.dat <- mul(i2tor(1,int64(i)),u)
+			if end(u) != 0 {
+				done = true
+			}
+			Z.dat <- mul(i2tor(1, int64(i)), u)
 		}
 		Z.dat <- finis
 	}(c, U, Z)
@@ -516,18 +535,18 @@ func Integ(c *rat,U PS) PS{
 
 // Binomial theorem (1+x)^c
 
-func Binom(c *rat) PS{
-	Z:=mkPS()
-	go func(c *rat, Z PS){
+func Binom(c *rat) PS {
+	Z := mkPS()
+	go func(c *rat, Z PS) {
 		n := 1
 		t := itor(1)
-		for c.num!=0 {
-			put(t,Z)
-			t = mul(mul(t,c),i2tor(1,int64(n)))
-			c = sub(c,one)
+		for c.num != 0 {
+			put(t, Z)
+			t = mul(mul(t, c), i2tor(1, int64(n)))
+			c = sub(c, one)
 			n++
 		}
-		put(finis,Z)
+		put(finis, Z)
 	}(c, Z)
 	return Z
 }
@@ -540,15 +559,15 @@ func Binom(c *rat) PS{
 //	u*ZZ + z*UU +x*UU*ZZ = 0
 //	ZZ = -UU*(z+x*ZZ)/u
 
-func Recip(U PS) PS{
-	Z:=mkPS()
-	go func(U, Z PS){
-		ZZ:=mkPS2()
+func Recip(U PS) PS {
+	Z := mkPS()
+	go func(U, Z PS) {
+		ZZ := mkPS2()
 		<-Z.req
 		z := inv(get(U))
 		Z.dat <- z
-		split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
-		copy(ZZ[1],Z)
+		split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
+		copy(ZZ[1], Z)
 	}(U, Z)
 	return Z
 }
@@ -560,9 +579,9 @@ func Recip(U PS) PS{
 //	DZ = Z*DU
 //	integrate to get Z
 
-func Exp(U PS) PS{
+func Exp(U PS) PS {
 	ZZ := mkPS2()
-	split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+	split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
 	return ZZ[1]
 }
 
@@ -573,7 +592,7 @@ func Exp(U PS) PS{
 // bug: a nonzero constant term is ignored
 
 func Subst(U, V PS) PS {
-	Z:= mkPS()
+	Z := mkPS()
 	go func(U, V, Z PS) {
 		VV := Split(V)
 		<-Z.req
@@ -581,9 +600,9 @@ func Subst(U, V PS) PS {
 		Z.dat <- u
 		if end(u) == 0 {
 			if end(get(VV[0])) != 0 {
-				put(finis,Z)
+				put(finis, Z)
 			} else {
-				copy(Mul(VV[0],Subst(U,VV[1])),Z)
+				copy(Mul(VV[0], Subst(U, VV[1])), Z)
 			}
 		}
 	}(U, V, Z)
@@ -594,7 +613,7 @@ func Subst(U, V PS) PS {
 // Each Ui is multiplied by c^i and followed by n-1 zeros
 
 func MonSubst(U PS, c0 *rat, n int) PS {
-	Z:= mkPS()
+	Z := mkPS()
 	go func(U, Z PS, c0 *rat, n int) {
 		c := one
 		for {
@@ -615,14 +634,13 @@ func MonSubst(U PS, c0 *rat, n int) PS {
 	return Z
 }
 
-
 func Init() {
 	chnameserial = -1
 	seqno = 0
 	chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 	zero = itor(0)
 	one = itor(1)
-	finis = i2tor(1,0)
+	finis = i2tor(1, 0)
 	Ones = Rep(one)
 	Twos = Rep(itor(2))
 }
@@ -641,7 +659,8 @@ func check(U PS, c *rat, count int, str string) {
 	}
 }
 
-const N=10
+const N = 10
+
 func checka(U PS, a []*rat, str string) {
 	for i := 0; i < N; i++ {
 		check(U, a[i], 1, str)
@@ -650,53 +669,64 @@ func checka(U PS, a []*rat, str string) {
 
 func main() {
 	Init()
-	if len(os.Args) > 1 {  // print
-		print("Ones: "); Printn(Ones, 10)
-		print("Twos: "); Printn(Twos, 10)
-		print("Add: "); Printn(Add(Ones, Twos), 10)
-		print("Diff: "); Printn(Diff(Ones), 10)
-		print("Integ: "); Printn(Integ(zero, Ones), 10)
-		print("CMul: "); Printn(Cmul(neg(one), Ones), 10)
-		print("Sub: "); Printn(Sub(Ones, Twos), 10)
-		print("Mul: "); Printn(Mul(Ones, Ones), 10)
-		print("Exp: "); Printn(Exp(Ones), 15)
-		print("MonSubst: "); Printn(MonSubst(Ones, neg(one), 2), 10)
-		print("ATan: "); Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
-	} else {  // test
+	if len(os.Args) > 1 { // print
+		print("Ones: ")
+		Printn(Ones, 10)
+		print("Twos: ")
+		Printn(Twos, 10)
+		print("Add: ")
+		Printn(Add(Ones, Twos), 10)
+		print("Diff: ")
+		Printn(Diff(Ones), 10)
+		print("Integ: ")
+		Printn(Integ(zero, Ones), 10)
+		print("CMul: ")
+		Printn(Cmul(neg(one), Ones), 10)
+		print("Sub: ")
+		Printn(Sub(Ones, Twos), 10)
+		print("Mul: ")
+		Printn(Mul(Ones, Ones), 10)
+		print("Exp: ")
+		Printn(Exp(Ones), 15)
+		print("MonSubst: ")
+		Printn(MonSubst(Ones, neg(one), 2), 10)
+		print("ATan: ")
+		Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
+	} else { // test
 		check(Ones, one, 5, "Ones")
-		check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones")  // 1 1 1 1 1
+		check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
 		check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
 		a := make([]*rat, N)
 		d := Diff(Ones)
-		for i:=0; i < N; i++ {
-			a[i] = itor(int64(i+1))
+		for i := 0; i < N; i++ {
+			a[i] = itor(int64(i + 1))
 		}
-		checka(d, a, "Diff")  // 1 2 3 4 5
+		checka(d, a, "Diff") // 1 2 3 4 5
 		in := Integ(zero, Ones)
-		a[0] = zero  // integration constant
-		for i:=1; i < N; i++ {
+		a[0] = zero // integration constant
+		for i := 1; i < N; i++ {
 			a[i] = i2tor(1, int64(i))
 		}
-		checka(in, a, "Integ")  // 0 1 1/2 1/3 1/4 1/5
-		check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")  // -1 -1 -1 -1 -1
-		check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos")  // -1 -1 -1 -1 -1
+		checka(in, a, "Integ")                               // 0 1 1/2 1/3 1/4 1/5
+		check(Cmul(neg(one), Twos), itor(-2), 10, "CMul")    // -1 -1 -1 -1 -1
+		check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
 		m := Mul(Ones, Ones)
-		for i:=0; i < N; i++ {
-			a[i] = itor(int64(i+1))
+		for i := 0; i < N; i++ {
+			a[i] = itor(int64(i + 1))
 		}
-		checka(m, a, "Mul")  // 1 2 3 4 5
+		checka(m, a, "Mul") // 1 2 3 4 5
 		e := Exp(Ones)
 		a[0] = itor(1)
 		a[1] = itor(1)
-		a[2] = i2tor(3,2)
-		a[3] = i2tor(13,6)
-		a[4] = i2tor(73,24)
-		a[5] = i2tor(167,40)
-		a[6] = i2tor(4051,720)
-		a[7] = i2tor(37633,5040)
-		a[8] = i2tor(43817,4480)
-		a[9] = i2tor(4596553,362880)
-		checka(e, a, "Exp")  // 1 1 3/2 13/6 73/24
+		a[2] = i2tor(3, 2)
+		a[3] = i2tor(13, 6)
+		a[4] = i2tor(73, 24)
+		a[5] = i2tor(167, 40)
+		a[6] = i2tor(4051, 720)
+		a[7] = i2tor(37633, 5040)
+		a[8] = i2tor(43817, 4480)
+		a[9] = i2tor(4596553, 362880)
+		checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
 		at := Integ(zero, MonSubst(Ones, neg(one), 2))
 		for c, i := 1, 0; i < N; i++ {
 			if i%2 == 0 {
@@ -706,20 +736,20 @@ func main() {
 				c *= -1
 			}
 		}
-		checka(at, a, "ATan");  // 0 -1 0 -1/3 0 -1/5
-/*
-		t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
-		a[0] = zero
-		a[1] = itor(1)
-		a[2] = zero
-		a[3] = i2tor(1,3)
-		a[4] = zero
-		a[5] = i2tor(2,15)
-		a[6] = zero
-		a[7] = i2tor(17,315)
-		a[8] = zero
-		a[9] = i2tor(62,2835)
-		checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
-*/
+		checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
+		/*
+			t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+			a[0] = zero
+			a[1] = itor(1)
+			a[2] = zero
+			a[3] = i2tor(1,3)
+			a[4] = zero
+			a[5] = i2tor(2,15)
+			a[6] = zero
+			a[7] = i2tor(17,315)
+			a[8] = zero
+			a[9] = i2tor(62,2835)
+			checka(t, a, "Tan")  // 0 1 0 1/3 0 2/15
+		*/
 	}
 }
diff --git a/test/chan/select3.go b/test/chan/select3.go
index 847d8ed..e9391f5 100644
--- a/test/chan/select3.go
+++ b/test/chan/select3.go
@@ -14,12 +14,10 @@ import "time"
 const always = "function did not"
 const never = "function did"
 
-
 func unreachable() {
 	panic("control flow shouldn't reach here")
 }
 
-
 // Calls f and verifies that f always/never panics depending on signal.
 func testPanic(signal string, f func()) {
 	defer func() {
@@ -34,7 +32,6 @@ func testPanic(signal string, f func()) {
 	f()
 }
 
-
 // Calls f and empirically verifies that f always/never blocks depending on signal.
 func testBlock(signal string, f func()) {
 	c := make(chan string)
@@ -51,7 +48,6 @@ func testBlock(signal string, f func()) {
 	}
 }
 
-
 func main() {
 	const async = 1 // asynchronous channels
 	var nilch chan int
@@ -114,8 +110,7 @@ func main() {
 
 	// empty selects always block
 	testBlock(always, func() {
-		select {
-		}
+		select {}
 	})
 
 	// selects with only nil channels always block
diff --git a/test/chan/sendstmt.go b/test/chan/sendstmt.go
index 278fa1b..c0f1a29 100644
--- a/test/chan/sendstmt.go
+++ b/test/chan/sendstmt.go
@@ -30,7 +30,7 @@ func chanchan() {
 
 func sendprec() {
 	c := make(chan bool, 1)
-	c <- false || true	// not a syntax error: same as c <- (false || true)
+	c <- false || true // not a syntax error: same as c <- (false || true)
 	if !<-c {
 		panic("sent false")
 	}
diff --git a/test/checkbce.go b/test/checkbce.go
index 59bd41b..430dcf9 100644
--- a/test/checkbce.go
+++ b/test/checkbce.go
@@ -1,6 +1,13 @@
 // +build amd64
 // errorcheck -0 -d=ssa/check_bce/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.
+
+// Test that the compiler does bounds check elimination as expected.
+// This avoids accidental regressions.
+
 package main
 
 func f0(a []int) {
@@ -13,10 +20,14 @@ func f0(a []int) {
 }
 
 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])
+	var j int
+	useInt(a[i]) // ERROR "Found IsInBounds$"
+	j = i % 256
+	useInt(a[j]) // ERROR "Found IsInBounds$"
+	j = i & 255
+	useInt(a[j])
+	j = i & 17
+	useInt(a[j])
 
 	if 4 <= i && i < len(a) {
 		useInt(a[i])
@@ -29,9 +40,36 @@ func f1(a [256]int, i int) {
 
 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])
+	j := i % 256
+	useInt(a[j])
+	j = i & 255
+	useInt(a[j])
+	j = i & 17
+	useInt(a[j])
+}
+
+func f2a(a [35]int, i uint8) {
+	useInt(a[i]) // ERROR "Found IsInBounds$"
+	j := i & 34
+	useInt(a[j])
+	j = i & 17
+	useInt(a[j])
+}
+
+func f2b(a [35]int, i uint16) {
+	useInt(a[i]) // ERROR "Found IsInBounds$"
+	j := i & 34
+	useInt(a[j])
+	j = i & 17
+	useInt(a[j])
+}
+
+func f2c(a [35]int, i uint32) {
+	useInt(a[i]) // ERROR "Found IsInBounds$"
+	j := i & 34
+	useInt(a[j])
+	j = i & 17
+	useInt(a[j])
 }
 
 func f3(a [256]int, i uint8) {
@@ -50,7 +88,7 @@ func f5(a []int) {
 	if len(a) > 5 {
 		useInt(a[5])
 		useSlice(a[6:])
-		useSlice(a[:6]) // ERROR "Found IsSliceInBounds$"
+		useSlice(a[:6])
 	}
 }
 
diff --git a/test/cmplx.go b/test/cmplx.go
index 2d8a622..dedf2bd 100644
--- a/test/cmplx.go
+++ b/test/cmplx.go
@@ -28,6 +28,14 @@ var (
 	C128 Complex128
 )
 
+func F1() int {
+	return 1
+}
+
+func F3() (int, int, int) {
+	return 1, 2, 3
+}
+
 func main() {
 	// ok
 	c64 = complex(f32, f32)
@@ -41,6 +49,11 @@ func main() {
 	_ = complex(f64, F64) // ERROR "complex"
 	_ = complex(F64, f64) // ERROR "complex"
 
+	_ = complex(F1()) // ERROR "expects two arguments.*returns 1"
+	_ = complex(F3()) // ERROR "expects two arguments.*returns 3"
+
+	_ = complex() // ERROR "missing argument"
+
 	c128 = complex(f32, f32) // ERROR "cannot use"
 	c64 = complex(f64, f64)  // ERROR "cannot use"
 
@@ -51,4 +64,5 @@ func main() {
 
 	C64 = complex(f32, f32)  // ERROR "cannot use"
 	C128 = complex(f64, f64) // ERROR "cannot use"
+
 }
diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c
index a475cc2..89a2868 100644
--- a/test/cmplxdivide.c
+++ b/test/cmplxdivide.c
@@ -23,50 +23,63 @@
 #define nelem(x) (sizeof(x)/sizeof((x)[0]))
 
 double f[] = {
-	0,
-	1,
-	-1,
-	2,
+	0.0,
+	-0.0,
+	1.0,
+	-1.0,
+	2.0,
 	NAN,
 	INFINITY,
 	-INFINITY,
 };
 
-char*
-fmt(double g)
-{
+char* fmt(double g) {
 	static char buf[10][30];
 	static int n;
 	char *p;
-	
+
 	p = buf[n++];
-	if(n == 10)
+	if(n == 10) {
 		n = 0;
+	}
+
 	sprintf(p, "%g", g);
-	if(strcmp(p, "-0") == 0)
-		strcpy(p, "negzero");
-	return p;
-}
 
-int
-iscnan(double complex d)
-{
-	return !isinf(creal(d)) && !isinf(cimag(d)) && (isnan(creal(d)) || isnan(cimag(d)));
-}
+	if(strcmp(p, "0") == 0) {
+		strcpy(p, "zero");
+		return p;
+	}
+
+	if(strcmp(p, "-0") == 0) {
+		strcpy(p, "-zero");
+		return p;
+	}
 
-double complex zero;	// attempt to hide zero division from gcc
+	return p;
+}
 
-int
-main(void)
-{
+int main(void) {
 	int i, j, k, l;
 	double complex n, d, q;
-	
+
 	printf("// skip\n");
 	printf("// # generated by cmplxdivide.c\n");
 	printf("\n");
 	printf("package main\n");
-	printf("var tests = []Test{\n");
+	printf("\n");
+	printf("import \"math\"\n");
+	printf("\n");
+	printf("var (\n");
+	printf("\tnan     = math.NaN()\n");
+	printf("\tinf     = math.Inf(1)\n");
+	printf("\tzero    = 0.0\n");
+	printf(")\n");
+	printf("\n");
+	printf("var tests = []struct {\n");
+	printf("\tf, g complex128\n");
+	printf("\tout  complex128\n");
+	printf("}{\n");
+
 	for(i=0; i<nelem(f); i++)
 	for(j=0; j<nelem(f); j++)
 	for(k=0; k<nelem(f); k++)
@@ -74,17 +87,8 @@ main(void)
 		n = f[i] + f[j]*I;
 		d = f[k] + f[l]*I;
 		q = n/d;
-		
-		// BUG FIX.
-		// Gcc gets the wrong answer for NaN/0 unless both sides are NaN.
-		// That is, it treats (NaN+NaN*I)/0 = NaN+NaN*I (a complex NaN)
-		// but it then computes (1+NaN*I)/0 = Inf+NaN*I (a complex infinity).
-		// Since both numerators are complex NaNs, it seems that the
-		// results should agree in kind.  Override the gcc computation in this case.
-		if(iscnan(n) && d == 0)
-			q = (NAN+NAN*I) / zero;
 
-		printf("\tTest{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n",
+		printf("\t{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n",
 			fmt(creal(n)), fmt(cimag(n)),
 			fmt(creal(d)), fmt(cimag(d)),
 			fmt(creal(q)), fmt(cimag(q)));
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
index a8ae515..49cd5bf 100644
--- a/test/cmplxdivide.go
+++ b/test/cmplxdivide.go
@@ -5,33 +5,25 @@
 // license that can be found in the LICENSE file.
 
 // Driver for complex division table defined in cmplxdivide1.go
-// For details, see the comment at the top of in cmplxdivide.c.
+// For details, see the comment at the top of cmplxdivide.c.
 
 package main
 
 import (
 	"fmt"
 	"math"
-	"math/cmplx"
 )
 
-type Test struct {
-	f, g complex128
-	out  complex128
-}
-
-var nan = math.NaN()
-var inf = math.Inf(1)
-var negzero = math.Copysign(0, -1)
-
 func calike(a, b complex128) bool {
-	switch {
-	case cmplx.IsInf(a) && cmplx.IsInf(b):
-		return true
-	case cmplx.IsNaN(a) && cmplx.IsNaN(b):
-		return true
+	if imag(a) != imag(b) && !(math.IsNaN(imag(a)) && math.IsNaN(imag(b))) {
+		return false
 	}
-	return a == b
+
+	if real(a) != real(b) && !(math.IsNaN(real(a)) && math.IsNaN(real(b))) {
+		return false
+	}
+
+	return true
 }
 
 func main() {
diff --git a/test/cmplxdivide1.go b/test/cmplxdivide1.go
index e9031dd..a52fb6f 100644
--- a/test/cmplxdivide1.go
+++ b/test/cmplxdivide1.go
@@ -2,2406 +2,4113 @@
 // # generated by cmplxdivide.c
 
 package main
-var tests = []Test{
-	Test{complex(0, 0), complex(0, 0), complex(-nan, -nan)},
-	Test{complex(0, 0), complex(0, 1), complex(0, 0)},
-	Test{complex(0, 0), complex(0, -1), complex(negzero, 0)},
-	Test{complex(0, 0), complex(0, 2), complex(0, 0)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(1, 0), complex(0, 0)},
-	Test{complex(0, 0), complex(1, 1), complex(0, 0)},
-	Test{complex(0, 0), complex(1, -1), complex(0, 0)},
-	Test{complex(0, 0), complex(1, 2), complex(0, 0)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(-1, 0), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-1, 1), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-1, -1), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-1, 2), complex(0, negzero)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(2, 0), complex(0, 0)},
-	Test{complex(0, 0), complex(2, 1), complex(0, 0)},
-	Test{complex(0, 0), complex(2, -1), complex(0, 0)},
-	Test{complex(0, 0), complex(2, 2), complex(0, 0)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(0, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(0, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(0, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(inf, 0), complex(0, 0)},
-	Test{complex(0, 0), complex(inf, 1), complex(0, 0)},
-	Test{complex(0, 0), complex(inf, -1), complex(0, 0)},
-	Test{complex(0, 0), complex(inf, 2), complex(0, 0)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 0), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(0, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(0, 0), complex(-nan, inf)},
-	Test{complex(0, 1), complex(0, 1), complex(1, 0)},
-	Test{complex(0, 1), complex(0, -1), complex(-1, 0)},
-	Test{complex(0, 1), complex(0, 2), complex(0.5, 0)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(1, 0), complex(0, 1)},
-	Test{complex(0, 1), complex(1, 1), complex(0.5, 0.5)},
-	Test{complex(0, 1), complex(1, -1), complex(-0.5, 0.5)},
-	Test{complex(0, 1), complex(1, 2), complex(0.4, 0.2)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(-1, 0), complex(negzero, -1)},
-	Test{complex(0, 1), complex(-1, 1), complex(0.5, -0.5)},
-	Test{complex(0, 1), complex(-1, -1), complex(-0.5, -0.5)},
-	Test{complex(0, 1), complex(-1, 2), complex(0.4, -0.2)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(2, 0), complex(0, 0.5)},
-	Test{complex(0, 1), complex(2, 1), complex(0.2, 0.4)},
-	Test{complex(0, 1), complex(2, -1), complex(-0.2, 0.4)},
-	Test{complex(0, 1), complex(2, 2), complex(0.25, 0.25)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(0, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(0, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(0, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(inf, 0), complex(0, 0)},
-	Test{complex(0, 1), complex(inf, 1), complex(0, 0)},
-	Test{complex(0, 1), complex(inf, -1), complex(0, 0)},
-	Test{complex(0, 1), complex(inf, 2), complex(0, 0)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 1), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(0, 1), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(0, 1), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(0, 1), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(0, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(0, -1), complex(0, 1), complex(-1, negzero)},
-	Test{complex(0, -1), complex(0, -1), complex(1, negzero)},
-	Test{complex(0, -1), complex(0, 2), complex(-0.5, negzero)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(1, 0), complex(0, -1)},
-	Test{complex(0, -1), complex(1, 1), complex(-0.5, -0.5)},
-	Test{complex(0, -1), complex(1, -1), complex(0.5, -0.5)},
-	Test{complex(0, -1), complex(1, 2), complex(-0.4, -0.2)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(-1, 0), complex(negzero, 1)},
-	Test{complex(0, -1), complex(-1, 1), complex(-0.5, 0.5)},
-	Test{complex(0, -1), complex(-1, -1), complex(0.5, 0.5)},
-	Test{complex(0, -1), complex(-1, 2), complex(-0.4, 0.2)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(2, 0), complex(0, -0.5)},
-	Test{complex(0, -1), complex(2, 1), complex(-0.2, -0.4)},
-	Test{complex(0, -1), complex(2, -1), complex(0.2, -0.4)},
-	Test{complex(0, -1), complex(2, 2), complex(-0.25, -0.25)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(0, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(0, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(0, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(inf, 0), complex(0, negzero)},
-	Test{complex(0, -1), complex(inf, 1), complex(0, negzero)},
-	Test{complex(0, -1), complex(inf, -1), complex(0, negzero)},
-	Test{complex(0, -1), complex(inf, 2), complex(0, negzero)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, -1), complex(-inf, 0), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-inf, 1), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-inf, -1), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-inf, 2), complex(negzero, 0)},
-	Test{complex(0, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(0, 2), complex(0, 0), complex(-nan, inf)},
-	Test{complex(0, 2), complex(0, 1), complex(2, 0)},
-	Test{complex(0, 2), complex(0, -1), complex(-2, 0)},
-	Test{complex(0, 2), complex(0, 2), complex(1, 0)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(1, 0), complex(0, 2)},
-	Test{complex(0, 2), complex(1, 1), complex(1, 1)},
-	Test{complex(0, 2), complex(1, -1), complex(-1, 1)},
-	Test{complex(0, 2), complex(1, 2), complex(0.8, 0.4)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(-1, 0), complex(negzero, -2)},
-	Test{complex(0, 2), complex(-1, 1), complex(1, -1)},
-	Test{complex(0, 2), complex(-1, -1), complex(-1, -1)},
-	Test{complex(0, 2), complex(-1, 2), complex(0.8, -0.4)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(2, 0), complex(0, 1)},
-	Test{complex(0, 2), complex(2, 1), complex(0.4, 0.8)},
-	Test{complex(0, 2), complex(2, -1), complex(-0.4, 0.8)},
-	Test{complex(0, 2), complex(2, 2), complex(0.5, 0.5)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(0, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(0, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(0, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(inf, 0), complex(0, 0)},
-	Test{complex(0, 2), complex(inf, 1), complex(0, 0)},
-	Test{complex(0, 2), complex(inf, -1), complex(0, 0)},
-	Test{complex(0, 2), complex(inf, 2), complex(0, 0)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(0, 2), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(0, 2), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(0, 2), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(0, 2), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(0, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(1, 0), complex(0, 0), complex(inf, -nan)},
-	Test{complex(1, 0), complex(0, 1), complex(0, -1)},
-	Test{complex(1, 0), complex(0, -1), complex(negzero, 1)},
-	Test{complex(1, 0), complex(0, 2), complex(0, -0.5)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(1, 0), complex(1, 0)},
-	Test{complex(1, 0), complex(1, 1), complex(0.5, -0.5)},
-	Test{complex(1, 0), complex(1, -1), complex(0.5, 0.5)},
-	Test{complex(1, 0), complex(1, 2), complex(0.2, -0.4)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(-1, 0), complex(-1, negzero)},
-	Test{complex(1, 0), complex(-1, 1), complex(-0.5, -0.5)},
-	Test{complex(1, 0), complex(-1, -1), complex(-0.5, 0.5)},
-	Test{complex(1, 0), complex(-1, 2), complex(-0.2, -0.4)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(2, 0), complex(0.5, 0)},
-	Test{complex(1, 0), complex(2, 1), complex(0.4, -0.2)},
-	Test{complex(1, 0), complex(2, -1), complex(0.4, 0.2)},
-	Test{complex(1, 0), complex(2, 2), complex(0.25, -0.25)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(1, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(1, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(1, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(inf, 0), complex(0, 0)},
-	Test{complex(1, 0), complex(inf, 1), complex(0, 0)},
-	Test{complex(1, 0), complex(inf, -1), complex(0, 0)},
-	Test{complex(1, 0), complex(inf, 2), complex(0, 0)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 0), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(1, 0), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(1, 0), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(1, 0), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(0, 0), complex(inf, inf)},
-	Test{complex(1, 1), complex(0, 1), complex(1, -1)},
-	Test{complex(1, 1), complex(0, -1), complex(-1, 1)},
-	Test{complex(1, 1), complex(0, 2), complex(0.5, -0.5)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(1, 0), complex(1, 1)},
-	Test{complex(1, 1), complex(1, 1), complex(1, 0)},
-	Test{complex(1, 1), complex(1, -1), complex(0, 1)},
-	Test{complex(1, 1), complex(1, 2), complex(0.6, -0.2)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(-1, 0), complex(-1, -1)},
-	Test{complex(1, 1), complex(-1, 1), complex(negzero, -1)},
-	Test{complex(1, 1), complex(-1, -1), complex(-1, negzero)},
-	Test{complex(1, 1), complex(-1, 2), complex(0.2, -0.6)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(2, 0), complex(0.5, 0.5)},
-	Test{complex(1, 1), complex(2, 1), complex(0.6, 0.2)},
-	Test{complex(1, 1), complex(2, -1), complex(0.2, 0.6)},
-	Test{complex(1, 1), complex(2, 2), complex(0.5, 0)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(1, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(1, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(1, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(inf, 0), complex(0, 0)},
-	Test{complex(1, 1), complex(inf, 1), complex(0, 0)},
-	Test{complex(1, 1), complex(inf, -1), complex(0, 0)},
-	Test{complex(1, 1), complex(inf, 2), complex(0, 0)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 1), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(1, 1), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(1, 1), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(1, 1), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, -1), complex(0, 0), complex(inf, -inf)},
-	Test{complex(1, -1), complex(0, 1), complex(-1, -1)},
-	Test{complex(1, -1), complex(0, -1), complex(1, 1)},
-	Test{complex(1, -1), complex(0, 2), complex(-0.5, -0.5)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(1, 0), complex(1, -1)},
-	Test{complex(1, -1), complex(1, 1), complex(0, -1)},
-	Test{complex(1, -1), complex(1, -1), complex(1, 0)},
-	Test{complex(1, -1), complex(1, 2), complex(-0.2, -0.6)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(-1, 0), complex(-1, 1)},
-	Test{complex(1, -1), complex(-1, 1), complex(-1, negzero)},
-	Test{complex(1, -1), complex(-1, -1), complex(negzero, 1)},
-	Test{complex(1, -1), complex(-1, 2), complex(-0.6, -0.2)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(2, 0), complex(0.5, -0.5)},
-	Test{complex(1, -1), complex(2, 1), complex(0.2, -0.6)},
-	Test{complex(1, -1), complex(2, -1), complex(0.6, -0.2)},
-	Test{complex(1, -1), complex(2, 2), complex(0, -0.5)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(1, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(1, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(1, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(inf, 0), complex(0, negzero)},
-	Test{complex(1, -1), complex(inf, 1), complex(0, negzero)},
-	Test{complex(1, -1), complex(inf, -1), complex(0, negzero)},
-	Test{complex(1, -1), complex(inf, 2), complex(0, negzero)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, -1), complex(-inf, 0), complex(negzero, 0)},
-	Test{complex(1, -1), complex(-inf, 1), complex(negzero, 0)},
-	Test{complex(1, -1), complex(-inf, -1), complex(negzero, 0)},
-	Test{complex(1, -1), complex(-inf, 2), complex(negzero, 0)},
-	Test{complex(1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(1, 2), complex(0, 0), complex(inf, inf)},
-	Test{complex(1, 2), complex(0, 1), complex(2, -1)},
-	Test{complex(1, 2), complex(0, -1), complex(-2, 1)},
-	Test{complex(1, 2), complex(0, 2), complex(1, -0.5)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(1, 0), complex(1, 2)},
-	Test{complex(1, 2), complex(1, 1), complex(1.5, 0.5)},
-	Test{complex(1, 2), complex(1, -1), complex(-0.5, 1.5)},
-	Test{complex(1, 2), complex(1, 2), complex(1, 0)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(-1, 0), complex(-1, -2)},
-	Test{complex(1, 2), complex(-1, 1), complex(0.5, -1.5)},
-	Test{complex(1, 2), complex(-1, -1), complex(-1.5, -0.5)},
-	Test{complex(1, 2), complex(-1, 2), complex(0.6, -0.8)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(2, 0), complex(0.5, 1)},
-	Test{complex(1, 2), complex(2, 1), complex(0.8, 0.6)},
-	Test{complex(1, 2), complex(2, -1), complex(0, 1)},
-	Test{complex(1, 2), complex(2, 2), complex(0.75, 0.25)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(1, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(1, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(1, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(inf, 0), complex(0, 0)},
-	Test{complex(1, 2), complex(inf, 1), complex(0, 0)},
-	Test{complex(1, 2), complex(inf, -1), complex(0, 0)},
-	Test{complex(1, 2), complex(inf, 2), complex(0, 0)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(1, 2), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(1, 2), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(1, 2), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(1, 2), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-1, 0), complex(0, 0), complex(-inf, -nan)},
-	Test{complex(-1, 0), complex(0, 1), complex(0, 1)},
-	Test{complex(-1, 0), complex(0, -1), complex(negzero, -1)},
-	Test{complex(-1, 0), complex(0, 2), complex(0, 0.5)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(1, 0), complex(-1, 0)},
-	Test{complex(-1, 0), complex(1, 1), complex(-0.5, 0.5)},
-	Test{complex(-1, 0), complex(1, -1), complex(-0.5, -0.5)},
-	Test{complex(-1, 0), complex(1, 2), complex(-0.2, 0.4)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(-1, 0), complex(1, negzero)},
-	Test{complex(-1, 0), complex(-1, 1), complex(0.5, 0.5)},
-	Test{complex(-1, 0), complex(-1, -1), complex(0.5, -0.5)},
-	Test{complex(-1, 0), complex(-1, 2), complex(0.2, 0.4)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(2, 0), complex(-0.5, 0)},
-	Test{complex(-1, 0), complex(2, 1), complex(-0.4, 0.2)},
-	Test{complex(-1, 0), complex(2, -1), complex(-0.4, -0.2)},
-	Test{complex(-1, 0), complex(2, 2), complex(-0.25, 0.25)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-1, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-1, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-1, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(inf, 0), complex(negzero, 0)},
-	Test{complex(-1, 0), complex(inf, 1), complex(negzero, 0)},
-	Test{complex(-1, 0), complex(inf, -1), complex(negzero, 0)},
-	Test{complex(-1, 0), complex(inf, 2), complex(negzero, 0)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 0), complex(-inf, 0), complex(0, negzero)},
-	Test{complex(-1, 0), complex(-inf, 1), complex(0, negzero)},
-	Test{complex(-1, 0), complex(-inf, -1), complex(0, negzero)},
-	Test{complex(-1, 0), complex(-inf, 2), complex(0, negzero)},
-	Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 1), complex(0, 0), complex(-inf, inf)},
-	Test{complex(-1, 1), complex(0, 1), complex(1, 1)},
-	Test{complex(-1, 1), complex(0, -1), complex(-1, -1)},
-	Test{complex(-1, 1), complex(0, 2), complex(0.5, 0.5)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(1, 0), complex(-1, 1)},
-	Test{complex(-1, 1), complex(1, 1), complex(0, 1)},
-	Test{complex(-1, 1), complex(1, -1), complex(-1, 0)},
-	Test{complex(-1, 1), complex(1, 2), complex(0.2, 0.6)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(-1, 0), complex(1, -1)},
-	Test{complex(-1, 1), complex(-1, 1), complex(1, negzero)},
-	Test{complex(-1, 1), complex(-1, -1), complex(negzero, -1)},
-	Test{complex(-1, 1), complex(-1, 2), complex(0.6, 0.2)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(2, 0), complex(-0.5, 0.5)},
-	Test{complex(-1, 1), complex(2, 1), complex(-0.2, 0.6)},
-	Test{complex(-1, 1), complex(2, -1), complex(-0.6, 0.2)},
-	Test{complex(-1, 1), complex(2, 2), complex(0, 0.5)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-1, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-1, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-1, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(inf, 0), complex(negzero, 0)},
-	Test{complex(-1, 1), complex(inf, 1), complex(negzero, 0)},
-	Test{complex(-1, 1), complex(inf, -1), complex(negzero, 0)},
-	Test{complex(-1, 1), complex(inf, 2), complex(negzero, 0)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 1), complex(-inf, 0), complex(0, negzero)},
-	Test{complex(-1, 1), complex(-inf, 1), complex(0, negzero)},
-	Test{complex(-1, 1), complex(-inf, -1), complex(0, negzero)},
-	Test{complex(-1, 1), complex(-inf, 2), complex(0, negzero)},
-	Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, -1), complex(0, 0), complex(-inf, -inf)},
-	Test{complex(-1, -1), complex(0, 1), complex(-1, 1)},
-	Test{complex(-1, -1), complex(0, -1), complex(1, -1)},
-	Test{complex(-1, -1), complex(0, 2), complex(-0.5, 0.5)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(1, 0), complex(-1, -1)},
-	Test{complex(-1, -1), complex(1, 1), complex(-1, 0)},
-	Test{complex(-1, -1), complex(1, -1), complex(0, -1)},
-	Test{complex(-1, -1), complex(1, 2), complex(-0.6, 0.2)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(-1, 0), complex(1, 1)},
-	Test{complex(-1, -1), complex(-1, 1), complex(negzero, 1)},
-	Test{complex(-1, -1), complex(-1, -1), complex(1, negzero)},
-	Test{complex(-1, -1), complex(-1, 2), complex(-0.2, 0.6)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(2, 0), complex(-0.5, -0.5)},
-	Test{complex(-1, -1), complex(2, 1), complex(-0.6, -0.2)},
-	Test{complex(-1, -1), complex(2, -1), complex(-0.2, -0.6)},
-	Test{complex(-1, -1), complex(2, 2), complex(-0.5, 0)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-1, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-1, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-1, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(inf, 0), complex(negzero, negzero)},
-	Test{complex(-1, -1), complex(inf, 1), complex(negzero, negzero)},
-	Test{complex(-1, -1), complex(inf, -1), complex(negzero, negzero)},
-	Test{complex(-1, -1), complex(inf, 2), complex(negzero, negzero)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, -1), complex(-inf, 0), complex(0, 0)},
-	Test{complex(-1, -1), complex(-inf, 1), complex(0, 0)},
-	Test{complex(-1, -1), complex(-inf, -1), complex(0, 0)},
-	Test{complex(-1, -1), complex(-inf, 2), complex(0, 0)},
-	Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)},
-	Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)},
-	Test{complex(-1, 2), complex(0, 0), complex(-inf, inf)},
-	Test{complex(-1, 2), complex(0, 1), complex(2, 1)},
-	Test{complex(-1, 2), complex(0, -1), complex(-2, -1)},
-	Test{complex(-1, 2), complex(0, 2), complex(1, 0.5)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(1, 0), complex(-1, 2)},
-	Test{complex(-1, 2), complex(1, 1), complex(0.5, 1.5)},
-	Test{complex(-1, 2), complex(1, -1), complex(-1.5, 0.5)},
-	Test{complex(-1, 2), complex(1, 2), complex(0.6, 0.8)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(-1, 0), complex(1, -2)},
-	Test{complex(-1, 2), complex(-1, 1), complex(1.5, -0.5)},
-	Test{complex(-1, 2), complex(-1, -1), complex(-0.5, -1.5)},
-	Test{complex(-1, 2), complex(-1, 2), complex(1, 0)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(2, 0), complex(-0.5, 1)},
-	Test{complex(-1, 2), complex(2, 1), complex(0, 1)},
-	Test{complex(-1, 2), complex(2, -1), complex(-0.8, 0.6)},
-	Test{complex(-1, 2), complex(2, 2), complex(0.25, 0.75)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-1, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-1, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-1, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(inf, 0), complex(negzero, 0)},
-	Test{complex(-1, 2), complex(inf, 1), complex(negzero, 0)},
-	Test{complex(-1, 2), complex(inf, -1), complex(negzero, 0)},
-	Test{complex(-1, 2), complex(inf, 2), complex(negzero, 0)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(-1, 2), complex(-inf, 0), complex(0, negzero)},
-	Test{complex(-1, 2), complex(-inf, 1), complex(0, negzero)},
-	Test{complex(-1, 2), complex(-inf, -1), complex(0, negzero)},
-	Test{complex(-1, 2), complex(-inf, 2), complex(0, negzero)},
-	Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)},
-	Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(2, 0), complex(0, 0), complex(inf, -nan)},
-	Test{complex(2, 0), complex(0, 1), complex(0, -2)},
-	Test{complex(2, 0), complex(0, -1), complex(negzero, 2)},
-	Test{complex(2, 0), complex(0, 2), complex(0, -1)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(1, 0), complex(2, 0)},
-	Test{complex(2, 0), complex(1, 1), complex(1, -1)},
-	Test{complex(2, 0), complex(1, -1), complex(1, 1)},
-	Test{complex(2, 0), complex(1, 2), complex(0.4, -0.8)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(-1, 0), complex(-2, negzero)},
-	Test{complex(2, 0), complex(-1, 1), complex(-1, -1)},
-	Test{complex(2, 0), complex(-1, -1), complex(-1, 1)},
-	Test{complex(2, 0), complex(-1, 2), complex(-0.4, -0.8)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(2, 0), complex(1, 0)},
-	Test{complex(2, 0), complex(2, 1), complex(0.8, -0.4)},
-	Test{complex(2, 0), complex(2, -1), complex(0.8, 0.4)},
-	Test{complex(2, 0), complex(2, 2), complex(0.5, -0.5)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(2, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(2, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(2, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(inf, 0), complex(0, 0)},
-	Test{complex(2, 0), complex(inf, 1), complex(0, 0)},
-	Test{complex(2, 0), complex(inf, -1), complex(0, 0)},
-	Test{complex(2, 0), complex(inf, 2), complex(0, 0)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 0), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(2, 0), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(2, 0), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(2, 0), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(2, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(0, 0), complex(inf, inf)},
-	Test{complex(2, 1), complex(0, 1), complex(1, -2)},
-	Test{complex(2, 1), complex(0, -1), complex(-1, 2)},
-	Test{complex(2, 1), complex(0, 2), complex(0.5, -1)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(1, 0), complex(2, 1)},
-	Test{complex(2, 1), complex(1, 1), complex(1.5, -0.5)},
-	Test{complex(2, 1), complex(1, -1), complex(0.5, 1.5)},
-	Test{complex(2, 1), complex(1, 2), complex(0.8, -0.6)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(-1, 0), complex(-2, -1)},
-	Test{complex(2, 1), complex(-1, 1), complex(-0.5, -1.5)},
-	Test{complex(2, 1), complex(-1, -1), complex(-1.5, 0.5)},
-	Test{complex(2, 1), complex(-1, 2), complex(0, -1)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(2, 0), complex(1, 0.5)},
-	Test{complex(2, 1), complex(2, 1), complex(1, 0)},
-	Test{complex(2, 1), complex(2, -1), complex(0.6, 0.8)},
-	Test{complex(2, 1), complex(2, 2), complex(0.75, -0.25)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(2, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(2, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(2, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(inf, 0), complex(0, 0)},
-	Test{complex(2, 1), complex(inf, 1), complex(0, 0)},
-	Test{complex(2, 1), complex(inf, -1), complex(0, 0)},
-	Test{complex(2, 1), complex(inf, 2), complex(0, 0)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 1), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(2, 1), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(2, 1), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(2, 1), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(2, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, -1), complex(0, 0), complex(inf, -inf)},
-	Test{complex(2, -1), complex(0, 1), complex(-1, -2)},
-	Test{complex(2, -1), complex(0, -1), complex(1, 2)},
-	Test{complex(2, -1), complex(0, 2), complex(-0.5, -1)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(1, 0), complex(2, -1)},
-	Test{complex(2, -1), complex(1, 1), complex(0.5, -1.5)},
-	Test{complex(2, -1), complex(1, -1), complex(1.5, 0.5)},
-	Test{complex(2, -1), complex(1, 2), complex(0, -1)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(-1, 0), complex(-2, 1)},
-	Test{complex(2, -1), complex(-1, 1), complex(-1.5, -0.5)},
-	Test{complex(2, -1), complex(-1, -1), complex(-0.5, 1.5)},
-	Test{complex(2, -1), complex(-1, 2), complex(-0.8, -0.6)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(2, 0), complex(1, -0.5)},
-	Test{complex(2, -1), complex(2, 1), complex(0.6, -0.8)},
-	Test{complex(2, -1), complex(2, -1), complex(1, 0)},
-	Test{complex(2, -1), complex(2, 2), complex(0.25, -0.75)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(2, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(2, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(2, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(inf, 0), complex(0, negzero)},
-	Test{complex(2, -1), complex(inf, 1), complex(0, negzero)},
-	Test{complex(2, -1), complex(inf, -1), complex(0, negzero)},
-	Test{complex(2, -1), complex(inf, 2), complex(0, negzero)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, -1), complex(-inf, 0), complex(negzero, 0)},
-	Test{complex(2, -1), complex(-inf, 1), complex(negzero, 0)},
-	Test{complex(2, -1), complex(-inf, -1), complex(negzero, 0)},
-	Test{complex(2, -1), complex(-inf, 2), complex(negzero, 0)},
-	Test{complex(2, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)},
-	Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)},
-	Test{complex(2, 2), complex(0, 0), complex(inf, inf)},
-	Test{complex(2, 2), complex(0, 1), complex(2, -2)},
-	Test{complex(2, 2), complex(0, -1), complex(-2, 2)},
-	Test{complex(2, 2), complex(0, 2), complex(1, -1)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(1, 0), complex(2, 2)},
-	Test{complex(2, 2), complex(1, 1), complex(2, 0)},
-	Test{complex(2, 2), complex(1, -1), complex(0, 2)},
-	Test{complex(2, 2), complex(1, 2), complex(1.2, -0.4)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(-1, 0), complex(-2, -2)},
-	Test{complex(2, 2), complex(-1, 1), complex(negzero, -2)},
-	Test{complex(2, 2), complex(-1, -1), complex(-2, negzero)},
-	Test{complex(2, 2), complex(-1, 2), complex(0.4, -1.2)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(2, 0), complex(1, 1)},
-	Test{complex(2, 2), complex(2, 1), complex(1.2, 0.4)},
-	Test{complex(2, 2), complex(2, -1), complex(0.4, 1.2)},
-	Test{complex(2, 2), complex(2, 2), complex(1, 0)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(2, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(2, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(2, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(inf, 0), complex(0, 0)},
-	Test{complex(2, 2), complex(inf, 1), complex(0, 0)},
-	Test{complex(2, 2), complex(inf, -1), complex(0, 0)},
-	Test{complex(2, 2), complex(inf, 2), complex(0, 0)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(2, 2), complex(-inf, 0), complex(negzero, negzero)},
-	Test{complex(2, 2), complex(-inf, 1), complex(negzero, negzero)},
-	Test{complex(2, 2), complex(-inf, -1), complex(negzero, negzero)},
-	Test{complex(2, 2), complex(-inf, 2), complex(negzero, negzero)},
-	Test{complex(2, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)},
-	Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(0, 0), complex(inf, -nan)},
-	Test{complex(inf, 0), complex(0, 1), complex(-nan, -inf)},
-	Test{complex(inf, 0), complex(0, -1), complex(-nan, inf)},
-	Test{complex(inf, 0), complex(0, 2), complex(-nan, -inf)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(1, 0), complex(inf, -nan)},
-	Test{complex(inf, 0), complex(1, 1), complex(inf, -inf)},
-	Test{complex(inf, 0), complex(1, -1), complex(inf, inf)},
-	Test{complex(inf, 0), complex(1, 2), complex(inf, -inf)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-1, 0), complex(-inf, -nan)},
-	Test{complex(inf, 0), complex(-1, 1), complex(-inf, -inf)},
-	Test{complex(inf, 0), complex(-1, -1), complex(-inf, inf)},
-	Test{complex(inf, 0), complex(-1, 2), complex(-inf, -inf)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(2, 0), complex(inf, -nan)},
-	Test{complex(inf, 0), complex(2, 1), complex(inf, -inf)},
-	Test{complex(inf, 0), complex(2, -1), complex(inf, inf)},
-	Test{complex(inf, 0), complex(2, 2), complex(inf, -inf)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(inf, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(inf, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(inf, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(0, 0), complex(inf, inf)},
-	Test{complex(inf, 1), complex(0, 1), complex(-nan, -inf)},
-	Test{complex(inf, 1), complex(0, -1), complex(-nan, inf)},
-	Test{complex(inf, 1), complex(0, 2), complex(-nan, -inf)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(1, 0), complex(inf, -nan)},
-	Test{complex(inf, 1), complex(1, 1), complex(inf, -inf)},
-	Test{complex(inf, 1), complex(1, -1), complex(inf, inf)},
-	Test{complex(inf, 1), complex(1, 2), complex(inf, -inf)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-1, 0), complex(-inf, -nan)},
-	Test{complex(inf, 1), complex(-1, 1), complex(-inf, -inf)},
-	Test{complex(inf, 1), complex(-1, -1), complex(-inf, inf)},
-	Test{complex(inf, 1), complex(-1, 2), complex(-inf, -inf)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(2, 0), complex(inf, -nan)},
-	Test{complex(inf, 1), complex(2, 1), complex(inf, -inf)},
-	Test{complex(inf, 1), complex(2, -1), complex(inf, inf)},
-	Test{complex(inf, 1), complex(2, 2), complex(inf, -inf)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(inf, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(inf, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(inf, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(0, 0), complex(inf, -inf)},
-	Test{complex(inf, -1), complex(0, 1), complex(-nan, -inf)},
-	Test{complex(inf, -1), complex(0, -1), complex(-nan, inf)},
-	Test{complex(inf, -1), complex(0, 2), complex(-nan, -inf)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(1, 0), complex(inf, -nan)},
-	Test{complex(inf, -1), complex(1, 1), complex(inf, -inf)},
-	Test{complex(inf, -1), complex(1, -1), complex(inf, inf)},
-	Test{complex(inf, -1), complex(1, 2), complex(inf, -inf)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-1, 0), complex(-inf, -nan)},
-	Test{complex(inf, -1), complex(-1, 1), complex(-inf, -inf)},
-	Test{complex(inf, -1), complex(-1, -1), complex(-inf, inf)},
-	Test{complex(inf, -1), complex(-1, 2), complex(-inf, -inf)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(2, 0), complex(inf, -nan)},
-	Test{complex(inf, -1), complex(2, 1), complex(inf, -inf)},
-	Test{complex(inf, -1), complex(2, -1), complex(inf, inf)},
-	Test{complex(inf, -1), complex(2, 2), complex(inf, -inf)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(inf, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(inf, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(inf, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(0, 0), complex(inf, inf)},
-	Test{complex(inf, 2), complex(0, 1), complex(-nan, -inf)},
-	Test{complex(inf, 2), complex(0, -1), complex(-nan, inf)},
-	Test{complex(inf, 2), complex(0, 2), complex(-nan, -inf)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(1, 0), complex(inf, -nan)},
-	Test{complex(inf, 2), complex(1, 1), complex(inf, -inf)},
-	Test{complex(inf, 2), complex(1, -1), complex(inf, inf)},
-	Test{complex(inf, 2), complex(1, 2), complex(inf, -inf)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-1, 0), complex(-inf, -nan)},
-	Test{complex(inf, 2), complex(-1, 1), complex(-inf, -inf)},
-	Test{complex(inf, 2), complex(-1, -1), complex(-inf, inf)},
-	Test{complex(inf, 2), complex(-1, 2), complex(-inf, -inf)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(2, 0), complex(inf, -nan)},
-	Test{complex(inf, 2), complex(2, 1), complex(inf, -inf)},
-	Test{complex(inf, 2), complex(2, -1), complex(inf, inf)},
-	Test{complex(inf, 2), complex(2, 2), complex(inf, -inf)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(inf, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(inf, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(inf, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(0, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 0), complex(0, 1), complex(-nan, inf)},
-	Test{complex(-inf, 0), complex(0, -1), complex(-nan, -inf)},
-	Test{complex(-inf, 0), complex(0, 2), complex(-nan, inf)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(1, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 0), complex(1, 1), complex(-inf, inf)},
-	Test{complex(-inf, 0), complex(1, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 0), complex(1, 2), complex(-inf, inf)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-1, 0), complex(inf, -nan)},
-	Test{complex(-inf, 0), complex(-1, 1), complex(inf, inf)},
-	Test{complex(-inf, 0), complex(-1, -1), complex(inf, -inf)},
-	Test{complex(-inf, 0), complex(-1, 2), complex(inf, inf)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(2, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 0), complex(2, 1), complex(-inf, inf)},
-	Test{complex(-inf, 0), complex(2, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 0), complex(2, 2), complex(-inf, inf)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(0, 0), complex(-inf, inf)},
-	Test{complex(-inf, 1), complex(0, 1), complex(-nan, inf)},
-	Test{complex(-inf, 1), complex(0, -1), complex(-nan, -inf)},
-	Test{complex(-inf, 1), complex(0, 2), complex(-nan, inf)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(1, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 1), complex(1, 1), complex(-inf, inf)},
-	Test{complex(-inf, 1), complex(1, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 1), complex(1, 2), complex(-inf, inf)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-1, 0), complex(inf, -nan)},
-	Test{complex(-inf, 1), complex(-1, 1), complex(inf, inf)},
-	Test{complex(-inf, 1), complex(-1, -1), complex(inf, -inf)},
-	Test{complex(-inf, 1), complex(-1, 2), complex(inf, inf)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(2, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 1), complex(2, 1), complex(-inf, inf)},
-	Test{complex(-inf, 1), complex(2, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 1), complex(2, 2), complex(-inf, inf)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(0, 0), complex(-inf, -inf)},
-	Test{complex(-inf, -1), complex(0, 1), complex(-nan, inf)},
-	Test{complex(-inf, -1), complex(0, -1), complex(-nan, -inf)},
-	Test{complex(-inf, -1), complex(0, 2), complex(-nan, inf)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(1, 0), complex(-inf, -nan)},
-	Test{complex(-inf, -1), complex(1, 1), complex(-inf, inf)},
-	Test{complex(-inf, -1), complex(1, -1), complex(-inf, -inf)},
-	Test{complex(-inf, -1), complex(1, 2), complex(-inf, inf)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-1, 0), complex(inf, -nan)},
-	Test{complex(-inf, -1), complex(-1, 1), complex(inf, inf)},
-	Test{complex(-inf, -1), complex(-1, -1), complex(inf, -inf)},
-	Test{complex(-inf, -1), complex(-1, 2), complex(inf, inf)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(2, 0), complex(-inf, -nan)},
-	Test{complex(-inf, -1), complex(2, 1), complex(-inf, inf)},
-	Test{complex(-inf, -1), complex(2, -1), complex(-inf, -inf)},
-	Test{complex(-inf, -1), complex(2, 2), complex(-inf, inf)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(0, 0), complex(-inf, inf)},
-	Test{complex(-inf, 2), complex(0, 1), complex(-nan, inf)},
-	Test{complex(-inf, 2), complex(0, -1), complex(-nan, -inf)},
-	Test{complex(-inf, 2), complex(0, 2), complex(-nan, inf)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(1, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 2), complex(1, 1), complex(-inf, inf)},
-	Test{complex(-inf, 2), complex(1, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 2), complex(1, 2), complex(-inf, inf)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-1, 0), complex(inf, -nan)},
-	Test{complex(-inf, 2), complex(-1, 1), complex(inf, inf)},
-	Test{complex(-inf, 2), complex(-1, -1), complex(inf, -inf)},
-	Test{complex(-inf, 2), complex(-1, 2), complex(inf, inf)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(2, 0), complex(-inf, -nan)},
-	Test{complex(-inf, 2), complex(2, 1), complex(-inf, inf)},
-	Test{complex(-inf, 2), complex(2, -1), complex(-inf, -inf)},
-	Test{complex(-inf, 2), complex(2, 2), complex(-inf, inf)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(nan, nan), complex(0, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(0, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(2, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
-	Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)},
-	Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)},
-	Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)},
-	Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)},
-	Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)},
-	Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)},
-	Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)},
-	Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)},
-	Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)},
-	Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)},
-	Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)},
-	Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)},
-	Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)},
+
+import "math"
+
+var (
+	nan     = math.NaN()
+	inf     = math.Inf(1)
+	zero    = 0.0
+)
+
+var tests = []struct {
+	f, g complex128
+	out  complex128
+}{
+	{complex(zero, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(zero, -1), complex(-zero, zero)},
+	{complex(zero, zero), complex(zero, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(-zero, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(zero, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(1, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(1, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(1, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(1, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(1, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(-1, zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, -zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, 1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, 2), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(2, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(2, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(2, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(2, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(2, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(zero, 1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(zero, -1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(zero, 2), complex(zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(zero, 1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(-zero, -1), complex(-zero, zero)},
+	{complex(zero, -zero), complex(zero, 2), complex(zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(1, zero), complex(zero, -zero)},
+	{complex(zero, -zero), complex(1, -zero), complex(zero, zero)},
+	{complex(zero, -zero), complex(1, 1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(1, -1), complex(zero, zero)},
+	{complex(zero, -zero), complex(1, 2), complex(zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(-1, zero), complex(-zero, -zero)},
+	{complex(zero, -zero), complex(-1, -zero), complex(-zero, zero)},
+	{complex(zero, -zero), complex(-1, 1), complex(-zero, -zero)},
+	{complex(zero, -zero), complex(-1, -1), complex(-zero, zero)},
+	{complex(zero, -zero), complex(-1, 2), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(2, zero), complex(zero, -zero)},
+	{complex(zero, -zero), complex(2, -zero), complex(zero, zero)},
+	{complex(zero, -zero), complex(2, 1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(2, -1), complex(zero, zero)},
+	{complex(zero, -zero), complex(2, 2), complex(zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(inf, zero), complex(zero, -zero)},
+	{complex(zero, -zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, -zero), complex(inf, 1), complex(zero, -zero)},
+	{complex(zero, -zero), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, -zero), complex(inf, 2), complex(zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, -zero), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(zero, -zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, -zero), complex(-inf, -1), complex(-zero, zero)},
+	{complex(zero, -zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -zero), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 1), complex(zero, -zero), complex(nan, inf)},
+	{complex(zero, 1), complex(zero, 1), complex(1, zero)},
+	{complex(zero, 1), complex(zero, -1), complex(-1, zero)},
+	{complex(zero, 1), complex(zero, 2), complex(0.5, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 1), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(zero, 1), complex(zero, 1), complex(1, zero)},
+	{complex(zero, 1), complex(-zero, -1), complex(-1, -zero)},
+	{complex(zero, 1), complex(zero, 2), complex(0.5, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(1, zero), complex(zero, 1)},
+	{complex(zero, 1), complex(1, -zero), complex(zero, 1)},
+	{complex(zero, 1), complex(1, 1), complex(0.5, 0.5)},
+	{complex(zero, 1), complex(1, -1), complex(-0.5, 0.5)},
+	{complex(zero, 1), complex(1, 2), complex(0.4, 0.2)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(-1, zero), complex(-zero, -1)},
+	{complex(zero, 1), complex(-1, -zero), complex(-zero, -1)},
+	{complex(zero, 1), complex(-1, 1), complex(0.5, -0.5)},
+	{complex(zero, 1), complex(-1, -1), complex(-0.5, -0.5)},
+	{complex(zero, 1), complex(-1, 2), complex(0.4, -0.2)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(2, zero), complex(zero, 0.5)},
+	{complex(zero, 1), complex(2, -zero), complex(zero, 0.5)},
+	{complex(zero, 1), complex(2, 1), complex(0.2, 0.4)},
+	{complex(zero, 1), complex(2, -1), complex(-0.2, 0.4)},
+	{complex(zero, 1), complex(2, 2), complex(0.25, 0.25)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(zero, -1), complex(zero, -zero), complex(nan, -inf)},
+	{complex(zero, -1), complex(zero, 1), complex(-1, -zero)},
+	{complex(zero, -1), complex(zero, -1), complex(1, -zero)},
+	{complex(zero, -1), complex(zero, 2), complex(-0.5, -zero)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(zero, -1), complex(-zero, -zero), complex(nan, inf)},
+	{complex(zero, -1), complex(zero, 1), complex(-1, -zero)},
+	{complex(zero, -1), complex(-zero, -1), complex(1, zero)},
+	{complex(zero, -1), complex(zero, 2), complex(-0.5, -zero)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(1, zero), complex(zero, -1)},
+	{complex(zero, -1), complex(1, -zero), complex(zero, -1)},
+	{complex(zero, -1), complex(1, 1), complex(-0.5, -0.5)},
+	{complex(zero, -1), complex(1, -1), complex(0.5, -0.5)},
+	{complex(zero, -1), complex(1, 2), complex(-0.4, -0.2)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(-1, zero), complex(-zero, 1)},
+	{complex(zero, -1), complex(-1, -zero), complex(-zero, 1)},
+	{complex(zero, -1), complex(-1, 1), complex(-0.5, 0.5)},
+	{complex(zero, -1), complex(-1, -1), complex(0.5, 0.5)},
+	{complex(zero, -1), complex(-1, 2), complex(-0.4, 0.2)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(2, zero), complex(zero, -0.5)},
+	{complex(zero, -1), complex(2, -zero), complex(zero, -0.5)},
+	{complex(zero, -1), complex(2, 1), complex(-0.2, -0.4)},
+	{complex(zero, -1), complex(2, -1), complex(0.2, -0.4)},
+	{complex(zero, -1), complex(2, 2), complex(-0.25, -0.25)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(inf, zero), complex(zero, -zero)},
+	{complex(zero, -1), complex(inf, -zero), complex(zero, -zero)},
+	{complex(zero, -1), complex(inf, 1), complex(zero, -zero)},
+	{complex(zero, -1), complex(inf, -1), complex(zero, -zero)},
+	{complex(zero, -1), complex(inf, 2), complex(zero, -zero)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, -1), complex(-inf, zero), complex(-zero, zero)},
+	{complex(zero, -1), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(zero, -1), complex(-inf, 1), complex(-zero, zero)},
+	{complex(zero, -1), complex(-inf, -1), complex(-zero, zero)},
+	{complex(zero, -1), complex(-inf, 2), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 2), complex(zero, -zero), complex(nan, inf)},
+	{complex(zero, 2), complex(zero, 1), complex(2, zero)},
+	{complex(zero, 2), complex(zero, -1), complex(-2, zero)},
+	{complex(zero, 2), complex(zero, 2), complex(1, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 2), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(zero, 2), complex(zero, 1), complex(2, zero)},
+	{complex(zero, 2), complex(-zero, -1), complex(-2, -zero)},
+	{complex(zero, 2), complex(zero, 2), complex(1, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(1, zero), complex(zero, 2)},
+	{complex(zero, 2), complex(1, -zero), complex(zero, 2)},
+	{complex(zero, 2), complex(1, 1), complex(1, 1)},
+	{complex(zero, 2), complex(1, -1), complex(-1, 1)},
+	{complex(zero, 2), complex(1, 2), complex(0.8, 0.4)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(-1, zero), complex(-zero, -2)},
+	{complex(zero, 2), complex(-1, -zero), complex(-zero, -2)},
+	{complex(zero, 2), complex(-1, 1), complex(1, -1)},
+	{complex(zero, 2), complex(-1, -1), complex(-1, -1)},
+	{complex(zero, 2), complex(-1, 2), complex(0.8, -0.4)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(2, zero), complex(zero, 1)},
+	{complex(zero, 2), complex(2, -zero), complex(zero, 1)},
+	{complex(zero, 2), complex(2, 1), complex(0.4, 0.8)},
+	{complex(zero, 2), complex(2, -1), complex(-0.4, 0.8)},
+	{complex(zero, 2), complex(2, 2), complex(0.5, 0.5)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(zero, -1), complex(-zero, zero)},
+	{complex(zero, zero), complex(zero, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(zero, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(-zero, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(zero, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(1, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(1, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(1, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(1, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(1, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(-1, zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, -zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, 1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-1, 2), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(2, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(2, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(2, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(2, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(2, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, zero), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(zero, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(zero, -1), complex(-zero, -zero)},
+	{complex(-zero, -zero), complex(zero, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(zero, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(-zero, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(zero, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(1, zero), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(1, -zero), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(1, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(1, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(1, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(-1, zero), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(-1, -zero), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(-1, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(-1, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(-1, 2), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(2, zero), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(2, -zero), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(2, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(2, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(2, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(inf, zero), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(inf, -zero), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(inf, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(inf, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(inf, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(-inf, zero), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(-inf, -zero), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(-inf, 1), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(-inf, -1), complex(zero, -zero)},
+	{complex(-zero, -zero), complex(-inf, 2), complex(-zero, zero)},
+	{complex(-zero, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-zero, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 1), complex(zero, -zero), complex(nan, inf)},
+	{complex(zero, 1), complex(zero, 1), complex(1, zero)},
+	{complex(zero, 1), complex(zero, -1), complex(-1, zero)},
+	{complex(zero, 1), complex(zero, 2), complex(0.5, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 1), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(zero, 1), complex(zero, 1), complex(1, zero)},
+	{complex(zero, 1), complex(-zero, -1), complex(-1, -zero)},
+	{complex(zero, 1), complex(zero, 2), complex(0.5, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(1, zero), complex(zero, 1)},
+	{complex(zero, 1), complex(1, -zero), complex(zero, 1)},
+	{complex(zero, 1), complex(1, 1), complex(0.5, 0.5)},
+	{complex(zero, 1), complex(1, -1), complex(-0.5, 0.5)},
+	{complex(zero, 1), complex(1, 2), complex(0.4, 0.2)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(-1, zero), complex(-zero, -1)},
+	{complex(zero, 1), complex(-1, -zero), complex(-zero, -1)},
+	{complex(zero, 1), complex(-1, 1), complex(0.5, -0.5)},
+	{complex(zero, 1), complex(-1, -1), complex(-0.5, -0.5)},
+	{complex(zero, 1), complex(-1, 2), complex(0.4, -0.2)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(2, zero), complex(zero, 0.5)},
+	{complex(zero, 1), complex(2, -zero), complex(zero, 0.5)},
+	{complex(zero, 1), complex(2, 1), complex(0.2, 0.4)},
+	{complex(zero, 1), complex(2, -1), complex(-0.2, 0.4)},
+	{complex(zero, 1), complex(2, 2), complex(0.25, 0.25)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, 1), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 1), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, 1), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(-zero, -1), complex(zero, -zero), complex(nan, -inf)},
+	{complex(-zero, -1), complex(zero, 1), complex(-1, zero)},
+	{complex(-zero, -1), complex(zero, -1), complex(1, -zero)},
+	{complex(-zero, -1), complex(zero, 2), complex(-0.5, zero)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(-zero, -1), complex(-zero, -zero), complex(nan, inf)},
+	{complex(-zero, -1), complex(zero, 1), complex(-1, zero)},
+	{complex(-zero, -1), complex(-zero, -1), complex(1, -zero)},
+	{complex(-zero, -1), complex(zero, 2), complex(-0.5, zero)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(1, zero), complex(-zero, -1)},
+	{complex(-zero, -1), complex(1, -zero), complex(zero, -1)},
+	{complex(-zero, -1), complex(1, 1), complex(-0.5, -0.5)},
+	{complex(-zero, -1), complex(1, -1), complex(0.5, -0.5)},
+	{complex(-zero, -1), complex(1, 2), complex(-0.4, -0.2)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(-1, zero), complex(-zero, 1)},
+	{complex(-zero, -1), complex(-1, -zero), complex(zero, 1)},
+	{complex(-zero, -1), complex(-1, 1), complex(-0.5, 0.5)},
+	{complex(-zero, -1), complex(-1, -1), complex(0.5, 0.5)},
+	{complex(-zero, -1), complex(-1, 2), complex(-0.4, 0.2)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(2, zero), complex(-zero, -0.5)},
+	{complex(-zero, -1), complex(2, -zero), complex(zero, -0.5)},
+	{complex(-zero, -1), complex(2, 1), complex(-0.2, -0.4)},
+	{complex(-zero, -1), complex(2, -1), complex(0.2, -0.4)},
+	{complex(-zero, -1), complex(2, 2), complex(-0.25, -0.25)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(inf, zero), complex(-zero, -zero)},
+	{complex(-zero, -1), complex(inf, -zero), complex(zero, -zero)},
+	{complex(-zero, -1), complex(inf, 1), complex(-zero, -zero)},
+	{complex(-zero, -1), complex(inf, -1), complex(zero, -zero)},
+	{complex(-zero, -1), complex(inf, 2), complex(-zero, -zero)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(-zero, -1), complex(-inf, zero), complex(-zero, zero)},
+	{complex(-zero, -1), complex(-inf, -zero), complex(zero, zero)},
+	{complex(-zero, -1), complex(-inf, 1), complex(-zero, zero)},
+	{complex(-zero, -1), complex(-inf, -1), complex(zero, zero)},
+	{complex(-zero, -1), complex(-inf, 2), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-zero, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-zero, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(zero, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 2), complex(zero, -zero), complex(nan, inf)},
+	{complex(zero, 2), complex(zero, 1), complex(2, zero)},
+	{complex(zero, 2), complex(zero, -1), complex(-2, zero)},
+	{complex(zero, 2), complex(zero, 2), complex(1, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(zero, 2), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(zero, 2), complex(zero, 1), complex(2, zero)},
+	{complex(zero, 2), complex(-zero, -1), complex(-2, -zero)},
+	{complex(zero, 2), complex(zero, 2), complex(1, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(1, zero), complex(zero, 2)},
+	{complex(zero, 2), complex(1, -zero), complex(zero, 2)},
+	{complex(zero, 2), complex(1, 1), complex(1, 1)},
+	{complex(zero, 2), complex(1, -1), complex(-1, 1)},
+	{complex(zero, 2), complex(1, 2), complex(0.8, 0.4)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(-1, zero), complex(-zero, -2)},
+	{complex(zero, 2), complex(-1, -zero), complex(-zero, -2)},
+	{complex(zero, 2), complex(-1, 1), complex(1, -1)},
+	{complex(zero, 2), complex(-1, -1), complex(-1, -1)},
+	{complex(zero, 2), complex(-1, 2), complex(0.8, -0.4)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(2, zero), complex(zero, 1)},
+	{complex(zero, 2), complex(2, -zero), complex(zero, 1)},
+	{complex(zero, 2), complex(2, 1), complex(0.4, 0.8)},
+	{complex(zero, 2), complex(2, -1), complex(-0.4, 0.8)},
+	{complex(zero, 2), complex(2, 2), complex(0.5, 0.5)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(inf, zero), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, -zero), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, 1), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, -1), complex(zero, zero)},
+	{complex(zero, 2), complex(inf, 2), complex(zero, zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(zero, 2), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(zero, 2), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(zero, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(zero, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(zero, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(1, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(1, zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(1, zero), complex(zero, 1), complex(zero, -1)},
+	{complex(1, zero), complex(zero, -1), complex(-zero, 1)},
+	{complex(1, zero), complex(zero, 2), complex(zero, -0.5)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(1, zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(1, zero), complex(zero, 1), complex(zero, -1)},
+	{complex(1, zero), complex(-zero, -1), complex(-zero, 1)},
+	{complex(1, zero), complex(zero, 2), complex(zero, -0.5)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(1, zero), complex(1, zero)},
+	{complex(1, zero), complex(1, -zero), complex(1, zero)},
+	{complex(1, zero), complex(1, 1), complex(0.5, -0.5)},
+	{complex(1, zero), complex(1, -1), complex(0.5, 0.5)},
+	{complex(1, zero), complex(1, 2), complex(0.2, -0.4)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(-1, zero), complex(-1, -zero)},
+	{complex(1, zero), complex(-1, -zero), complex(-1, -zero)},
+	{complex(1, zero), complex(-1, 1), complex(-0.5, -0.5)},
+	{complex(1, zero), complex(-1, -1), complex(-0.5, 0.5)},
+	{complex(1, zero), complex(-1, 2), complex(-0.2, -0.4)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(2, zero), complex(0.5, zero)},
+	{complex(1, zero), complex(2, -zero), complex(0.5, zero)},
+	{complex(1, zero), complex(2, 1), complex(0.4, -0.2)},
+	{complex(1, zero), complex(2, -1), complex(0.4, 0.2)},
+	{complex(1, zero), complex(2, 2), complex(0.25, -0.25)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(1, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(1, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(1, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(1, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(inf, zero), complex(zero, zero)},
+	{complex(1, zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(1, zero), complex(inf, 1), complex(zero, zero)},
+	{complex(1, zero), complex(inf, -1), complex(zero, zero)},
+	{complex(1, zero), complex(inf, 2), complex(zero, zero)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(1, zero), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(1, zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(1, zero), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(1, zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(1, -zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(1, -zero), complex(zero, 1), complex(zero, -1)},
+	{complex(1, -zero), complex(zero, -1), complex(zero, 1)},
+	{complex(1, -zero), complex(zero, 2), complex(zero, -0.5)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(1, -zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(1, -zero), complex(zero, 1), complex(zero, -1)},
+	{complex(1, -zero), complex(-zero, -1), complex(-zero, 1)},
+	{complex(1, -zero), complex(zero, 2), complex(zero, -0.5)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(1, zero), complex(1, -zero)},
+	{complex(1, -zero), complex(1, -zero), complex(1, zero)},
+	{complex(1, -zero), complex(1, 1), complex(0.5, -0.5)},
+	{complex(1, -zero), complex(1, -1), complex(0.5, 0.5)},
+	{complex(1, -zero), complex(1, 2), complex(0.2, -0.4)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(-1, zero), complex(-1, -zero)},
+	{complex(1, -zero), complex(-1, -zero), complex(-1, zero)},
+	{complex(1, -zero), complex(-1, 1), complex(-0.5, -0.5)},
+	{complex(1, -zero), complex(-1, -1), complex(-0.5, 0.5)},
+	{complex(1, -zero), complex(-1, 2), complex(-0.2, -0.4)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(2, zero), complex(0.5, -zero)},
+	{complex(1, -zero), complex(2, -zero), complex(0.5, zero)},
+	{complex(1, -zero), complex(2, 1), complex(0.4, -0.2)},
+	{complex(1, -zero), complex(2, -1), complex(0.4, 0.2)},
+	{complex(1, -zero), complex(2, 2), complex(0.25, -0.25)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(inf, zero), complex(zero, -zero)},
+	{complex(1, -zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(1, -zero), complex(inf, 1), complex(zero, -zero)},
+	{complex(1, -zero), complex(inf, -1), complex(zero, zero)},
+	{complex(1, -zero), complex(inf, 2), complex(zero, -zero)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(1, -zero), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(1, -zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(1, -zero), complex(-inf, -1), complex(-zero, zero)},
+	{complex(1, -zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(1, 1), complex(zero, -zero), complex(inf, inf)},
+	{complex(1, 1), complex(zero, 1), complex(1, -1)},
+	{complex(1, 1), complex(zero, -1), complex(-1, 1)},
+	{complex(1, 1), complex(zero, 2), complex(0.5, -0.5)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(1, 1), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(1, 1), complex(zero, 1), complex(1, -1)},
+	{complex(1, 1), complex(-zero, -1), complex(-1, 1)},
+	{complex(1, 1), complex(zero, 2), complex(0.5, -0.5)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(1, zero), complex(1, 1)},
+	{complex(1, 1), complex(1, -zero), complex(1, 1)},
+	{complex(1, 1), complex(1, 1), complex(1, zero)},
+	{complex(1, 1), complex(1, -1), complex(zero, 1)},
+	{complex(1, 1), complex(1, 2), complex(0.6, -0.2)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(-1, zero), complex(-1, -1)},
+	{complex(1, 1), complex(-1, -zero), complex(-1, -1)},
+	{complex(1, 1), complex(-1, 1), complex(-zero, -1)},
+	{complex(1, 1), complex(-1, -1), complex(-1, -zero)},
+	{complex(1, 1), complex(-1, 2), complex(0.2, -0.6)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(2, zero), complex(0.5, 0.5)},
+	{complex(1, 1), complex(2, -zero), complex(0.5, 0.5)},
+	{complex(1, 1), complex(2, 1), complex(0.6, 0.2)},
+	{complex(1, 1), complex(2, -1), complex(0.2, 0.6)},
+	{complex(1, 1), complex(2, 2), complex(0.5, zero)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(1, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(1, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(1, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(1, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(inf, zero), complex(zero, zero)},
+	{complex(1, 1), complex(inf, -zero), complex(zero, zero)},
+	{complex(1, 1), complex(inf, 1), complex(zero, zero)},
+	{complex(1, 1), complex(inf, -1), complex(zero, zero)},
+	{complex(1, 1), complex(inf, 2), complex(zero, zero)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 1), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(1, 1), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(1, 1), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(1, 1), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(1, 1), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(1, -1), complex(zero, -zero), complex(inf, -inf)},
+	{complex(1, -1), complex(zero, 1), complex(-1, -1)},
+	{complex(1, -1), complex(zero, -1), complex(1, 1)},
+	{complex(1, -1), complex(zero, 2), complex(-0.5, -0.5)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(1, -1), complex(-zero, -zero), complex(-inf, inf)},
+	{complex(1, -1), complex(zero, 1), complex(-1, -1)},
+	{complex(1, -1), complex(-zero, -1), complex(1, 1)},
+	{complex(1, -1), complex(zero, 2), complex(-0.5, -0.5)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(1, zero), complex(1, -1)},
+	{complex(1, -1), complex(1, -zero), complex(1, -1)},
+	{complex(1, -1), complex(1, 1), complex(zero, -1)},
+	{complex(1, -1), complex(1, -1), complex(1, zero)},
+	{complex(1, -1), complex(1, 2), complex(-0.2, -0.6)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(-1, zero), complex(-1, 1)},
+	{complex(1, -1), complex(-1, -zero), complex(-1, 1)},
+	{complex(1, -1), complex(-1, 1), complex(-1, -zero)},
+	{complex(1, -1), complex(-1, -1), complex(-zero, 1)},
+	{complex(1, -1), complex(-1, 2), complex(-0.6, -0.2)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(2, zero), complex(0.5, -0.5)},
+	{complex(1, -1), complex(2, -zero), complex(0.5, -0.5)},
+	{complex(1, -1), complex(2, 1), complex(0.2, -0.6)},
+	{complex(1, -1), complex(2, -1), complex(0.6, -0.2)},
+	{complex(1, -1), complex(2, 2), complex(zero, -0.5)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(1, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(1, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(1, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(1, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(inf, zero), complex(zero, -zero)},
+	{complex(1, -1), complex(inf, -zero), complex(zero, -zero)},
+	{complex(1, -1), complex(inf, 1), complex(zero, -zero)},
+	{complex(1, -1), complex(inf, -1), complex(zero, -zero)},
+	{complex(1, -1), complex(inf, 2), complex(zero, -zero)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, -1), complex(-inf, zero), complex(-zero, zero)},
+	{complex(1, -1), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(1, -1), complex(-inf, 1), complex(-zero, zero)},
+	{complex(1, -1), complex(-inf, -1), complex(-zero, zero)},
+	{complex(1, -1), complex(-inf, 2), complex(-zero, zero)},
+	{complex(1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(1, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(1, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(1, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(1, 2), complex(zero, -zero), complex(inf, inf)},
+	{complex(1, 2), complex(zero, 1), complex(2, -1)},
+	{complex(1, 2), complex(zero, -1), complex(-2, 1)},
+	{complex(1, 2), complex(zero, 2), complex(1, -0.5)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(1, 2), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(1, 2), complex(zero, 1), complex(2, -1)},
+	{complex(1, 2), complex(-zero, -1), complex(-2, 1)},
+	{complex(1, 2), complex(zero, 2), complex(1, -0.5)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(1, zero), complex(1, 2)},
+	{complex(1, 2), complex(1, -zero), complex(1, 2)},
+	{complex(1, 2), complex(1, 1), complex(1.5, 0.5)},
+	{complex(1, 2), complex(1, -1), complex(-0.5, 1.5)},
+	{complex(1, 2), complex(1, 2), complex(1, zero)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(-1, zero), complex(-1, -2)},
+	{complex(1, 2), complex(-1, -zero), complex(-1, -2)},
+	{complex(1, 2), complex(-1, 1), complex(0.5, -1.5)},
+	{complex(1, 2), complex(-1, -1), complex(-1.5, -0.5)},
+	{complex(1, 2), complex(-1, 2), complex(0.6, -0.8)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(2, zero), complex(0.5, 1)},
+	{complex(1, 2), complex(2, -zero), complex(0.5, 1)},
+	{complex(1, 2), complex(2, 1), complex(0.8, 0.6)},
+	{complex(1, 2), complex(2, -1), complex(zero, 1)},
+	{complex(1, 2), complex(2, 2), complex(0.75, 0.25)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(1, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(1, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(1, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(1, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(inf, zero), complex(zero, zero)},
+	{complex(1, 2), complex(inf, -zero), complex(zero, zero)},
+	{complex(1, 2), complex(inf, 1), complex(zero, zero)},
+	{complex(1, 2), complex(inf, -1), complex(zero, zero)},
+	{complex(1, 2), complex(inf, 2), complex(zero, zero)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(1, 2), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(1, 2), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(1, 2), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(1, 2), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(1, 2), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(1, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(1, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(-1, zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-1, zero), complex(zero, -zero), complex(-inf, nan)},
+	{complex(-1, zero), complex(zero, 1), complex(zero, 1)},
+	{complex(-1, zero), complex(zero, -1), complex(-zero, -1)},
+	{complex(-1, zero), complex(zero, 2), complex(zero, 0.5)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-1, zero), complex(-zero, -zero), complex(inf, nan)},
+	{complex(-1, zero), complex(zero, 1), complex(zero, 1)},
+	{complex(-1, zero), complex(-zero, -1), complex(-zero, -1)},
+	{complex(-1, zero), complex(zero, 2), complex(zero, 0.5)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(1, zero), complex(-1, zero)},
+	{complex(-1, zero), complex(1, -zero), complex(-1, zero)},
+	{complex(-1, zero), complex(1, 1), complex(-0.5, 0.5)},
+	{complex(-1, zero), complex(1, -1), complex(-0.5, -0.5)},
+	{complex(-1, zero), complex(1, 2), complex(-0.2, 0.4)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(-1, zero), complex(1, -zero)},
+	{complex(-1, zero), complex(-1, -zero), complex(1, -zero)},
+	{complex(-1, zero), complex(-1, 1), complex(0.5, 0.5)},
+	{complex(-1, zero), complex(-1, -1), complex(0.5, -0.5)},
+	{complex(-1, zero), complex(-1, 2), complex(0.2, 0.4)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(2, zero), complex(-0.5, zero)},
+	{complex(-1, zero), complex(2, -zero), complex(-0.5, zero)},
+	{complex(-1, zero), complex(2, 1), complex(-0.4, 0.2)},
+	{complex(-1, zero), complex(2, -1), complex(-0.4, -0.2)},
+	{complex(-1, zero), complex(2, 2), complex(-0.25, 0.25)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(inf, zero), complex(-zero, zero)},
+	{complex(-1, zero), complex(inf, -zero), complex(-zero, zero)},
+	{complex(-1, zero), complex(inf, 1), complex(-zero, zero)},
+	{complex(-1, zero), complex(inf, -1), complex(-zero, zero)},
+	{complex(-1, zero), complex(inf, 2), complex(-zero, zero)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, zero), complex(-inf, zero), complex(zero, -zero)},
+	{complex(-1, zero), complex(-inf, -zero), complex(zero, -zero)},
+	{complex(-1, zero), complex(-inf, 1), complex(zero, -zero)},
+	{complex(-1, zero), complex(-inf, -1), complex(zero, -zero)},
+	{complex(-1, zero), complex(-inf, 2), complex(zero, -zero)},
+	{complex(-1, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-1, -zero), complex(zero, -zero), complex(-inf, nan)},
+	{complex(-1, -zero), complex(zero, 1), complex(-zero, 1)},
+	{complex(-1, -zero), complex(zero, -1), complex(-zero, -1)},
+	{complex(-1, -zero), complex(zero, 2), complex(-zero, 0.5)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-1, -zero), complex(-zero, -zero), complex(inf, nan)},
+	{complex(-1, -zero), complex(zero, 1), complex(-zero, 1)},
+	{complex(-1, -zero), complex(-zero, -1), complex(zero, -1)},
+	{complex(-1, -zero), complex(zero, 2), complex(-zero, 0.5)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(1, zero), complex(-1, zero)},
+	{complex(-1, -zero), complex(1, -zero), complex(-1, -zero)},
+	{complex(-1, -zero), complex(1, 1), complex(-0.5, 0.5)},
+	{complex(-1, -zero), complex(1, -1), complex(-0.5, -0.5)},
+	{complex(-1, -zero), complex(1, 2), complex(-0.2, 0.4)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(-1, zero), complex(1, zero)},
+	{complex(-1, -zero), complex(-1, -zero), complex(1, -zero)},
+	{complex(-1, -zero), complex(-1, 1), complex(0.5, 0.5)},
+	{complex(-1, -zero), complex(-1, -1), complex(0.5, -0.5)},
+	{complex(-1, -zero), complex(-1, 2), complex(0.2, 0.4)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(2, zero), complex(-0.5, zero)},
+	{complex(-1, -zero), complex(2, -zero), complex(-0.5, -zero)},
+	{complex(-1, -zero), complex(2, 1), complex(-0.4, 0.2)},
+	{complex(-1, -zero), complex(2, -1), complex(-0.4, -0.2)},
+	{complex(-1, -zero), complex(2, 2), complex(-0.25, 0.25)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(inf, zero), complex(-zero, zero)},
+	{complex(-1, -zero), complex(inf, -zero), complex(-zero, -zero)},
+	{complex(-1, -zero), complex(inf, 1), complex(-zero, zero)},
+	{complex(-1, -zero), complex(inf, -1), complex(-zero, -zero)},
+	{complex(-1, -zero), complex(inf, 2), complex(-zero, zero)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -zero), complex(-inf, zero), complex(zero, zero)},
+	{complex(-1, -zero), complex(-inf, -zero), complex(zero, -zero)},
+	{complex(-1, -zero), complex(-inf, 1), complex(zero, zero)},
+	{complex(-1, -zero), complex(-inf, -1), complex(zero, -zero)},
+	{complex(-1, -zero), complex(-inf, 2), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -zero), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, -zero), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, 1), complex(zero, zero), complex(-inf, inf)},
+	{complex(-1, 1), complex(zero, -zero), complex(-inf, inf)},
+	{complex(-1, 1), complex(zero, 1), complex(1, 1)},
+	{complex(-1, 1), complex(zero, -1), complex(-1, -1)},
+	{complex(-1, 1), complex(zero, 2), complex(0.5, 0.5)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(zero, zero), complex(-inf, inf)},
+	{complex(-1, 1), complex(-zero, -zero), complex(inf, -inf)},
+	{complex(-1, 1), complex(zero, 1), complex(1, 1)},
+	{complex(-1, 1), complex(-zero, -1), complex(-1, -1)},
+	{complex(-1, 1), complex(zero, 2), complex(0.5, 0.5)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(1, zero), complex(-1, 1)},
+	{complex(-1, 1), complex(1, -zero), complex(-1, 1)},
+	{complex(-1, 1), complex(1, 1), complex(zero, 1)},
+	{complex(-1, 1), complex(1, -1), complex(-1, zero)},
+	{complex(-1, 1), complex(1, 2), complex(0.2, 0.6)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(-1, zero), complex(1, -1)},
+	{complex(-1, 1), complex(-1, -zero), complex(1, -1)},
+	{complex(-1, 1), complex(-1, 1), complex(1, -zero)},
+	{complex(-1, 1), complex(-1, -1), complex(-zero, -1)},
+	{complex(-1, 1), complex(-1, 2), complex(0.6, 0.2)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(2, zero), complex(-0.5, 0.5)},
+	{complex(-1, 1), complex(2, -zero), complex(-0.5, 0.5)},
+	{complex(-1, 1), complex(2, 1), complex(-0.2, 0.6)},
+	{complex(-1, 1), complex(2, -1), complex(-0.6, 0.2)},
+	{complex(-1, 1), complex(2, 2), complex(zero, 0.5)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(inf, zero), complex(-zero, zero)},
+	{complex(-1, 1), complex(inf, -zero), complex(-zero, zero)},
+	{complex(-1, 1), complex(inf, 1), complex(-zero, zero)},
+	{complex(-1, 1), complex(inf, -1), complex(-zero, zero)},
+	{complex(-1, 1), complex(inf, 2), complex(-zero, zero)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 1), complex(-inf, zero), complex(zero, -zero)},
+	{complex(-1, 1), complex(-inf, -zero), complex(zero, -zero)},
+	{complex(-1, 1), complex(-inf, 1), complex(zero, -zero)},
+	{complex(-1, 1), complex(-inf, -1), complex(zero, -zero)},
+	{complex(-1, 1), complex(-inf, 2), complex(zero, -zero)},
+	{complex(-1, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 1), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 1), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, -1), complex(zero, zero), complex(-inf, -inf)},
+	{complex(-1, -1), complex(zero, -zero), complex(-inf, -inf)},
+	{complex(-1, -1), complex(zero, 1), complex(-1, 1)},
+	{complex(-1, -1), complex(zero, -1), complex(1, -1)},
+	{complex(-1, -1), complex(zero, 2), complex(-0.5, 0.5)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(zero, zero), complex(-inf, -inf)},
+	{complex(-1, -1), complex(-zero, -zero), complex(inf, inf)},
+	{complex(-1, -1), complex(zero, 1), complex(-1, 1)},
+	{complex(-1, -1), complex(-zero, -1), complex(1, -1)},
+	{complex(-1, -1), complex(zero, 2), complex(-0.5, 0.5)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(1, zero), complex(-1, -1)},
+	{complex(-1, -1), complex(1, -zero), complex(-1, -1)},
+	{complex(-1, -1), complex(1, 1), complex(-1, zero)},
+	{complex(-1, -1), complex(1, -1), complex(zero, -1)},
+	{complex(-1, -1), complex(1, 2), complex(-0.6, 0.2)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(-1, zero), complex(1, 1)},
+	{complex(-1, -1), complex(-1, -zero), complex(1, 1)},
+	{complex(-1, -1), complex(-1, 1), complex(-zero, 1)},
+	{complex(-1, -1), complex(-1, -1), complex(1, -zero)},
+	{complex(-1, -1), complex(-1, 2), complex(-0.2, 0.6)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(2, zero), complex(-0.5, -0.5)},
+	{complex(-1, -1), complex(2, -zero), complex(-0.5, -0.5)},
+	{complex(-1, -1), complex(2, 1), complex(-0.6, -0.2)},
+	{complex(-1, -1), complex(2, -1), complex(-0.2, -0.6)},
+	{complex(-1, -1), complex(2, 2), complex(-0.5, zero)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(inf, zero), complex(-zero, -zero)},
+	{complex(-1, -1), complex(inf, -zero), complex(-zero, -zero)},
+	{complex(-1, -1), complex(inf, 1), complex(-zero, -zero)},
+	{complex(-1, -1), complex(inf, -1), complex(-zero, -zero)},
+	{complex(-1, -1), complex(inf, 2), complex(-zero, -zero)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, -1), complex(-inf, zero), complex(zero, zero)},
+	{complex(-1, -1), complex(-inf, -zero), complex(zero, zero)},
+	{complex(-1, -1), complex(-inf, 1), complex(zero, zero)},
+	{complex(-1, -1), complex(-inf, -1), complex(zero, zero)},
+	{complex(-1, -1), complex(-inf, 2), complex(zero, zero)},
+	{complex(-1, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, -1), complex(nan, inf), complex(-zero, zero)},
+	{complex(-1, -1), complex(nan, -inf), complex(zero, -zero)},
+	{complex(-1, 2), complex(zero, zero), complex(-inf, inf)},
+	{complex(-1, 2), complex(zero, -zero), complex(-inf, inf)},
+	{complex(-1, 2), complex(zero, 1), complex(2, 1)},
+	{complex(-1, 2), complex(zero, -1), complex(-2, -1)},
+	{complex(-1, 2), complex(zero, 2), complex(1, 0.5)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(zero, zero), complex(-inf, inf)},
+	{complex(-1, 2), complex(-zero, -zero), complex(inf, -inf)},
+	{complex(-1, 2), complex(zero, 1), complex(2, 1)},
+	{complex(-1, 2), complex(-zero, -1), complex(-2, -1)},
+	{complex(-1, 2), complex(zero, 2), complex(1, 0.5)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(1, zero), complex(-1, 2)},
+	{complex(-1, 2), complex(1, -zero), complex(-1, 2)},
+	{complex(-1, 2), complex(1, 1), complex(0.5, 1.5)},
+	{complex(-1, 2), complex(1, -1), complex(-1.5, 0.5)},
+	{complex(-1, 2), complex(1, 2), complex(0.6, 0.8)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(-1, zero), complex(1, -2)},
+	{complex(-1, 2), complex(-1, -zero), complex(1, -2)},
+	{complex(-1, 2), complex(-1, 1), complex(1.5, -0.5)},
+	{complex(-1, 2), complex(-1, -1), complex(-0.5, -1.5)},
+	{complex(-1, 2), complex(-1, 2), complex(1, zero)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(2, zero), complex(-0.5, 1)},
+	{complex(-1, 2), complex(2, -zero), complex(-0.5, 1)},
+	{complex(-1, 2), complex(2, 1), complex(zero, 1)},
+	{complex(-1, 2), complex(2, -1), complex(-0.8, 0.6)},
+	{complex(-1, 2), complex(2, 2), complex(0.25, 0.75)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(inf, zero), complex(-zero, zero)},
+	{complex(-1, 2), complex(inf, -zero), complex(-zero, zero)},
+	{complex(-1, 2), complex(inf, 1), complex(-zero, zero)},
+	{complex(-1, 2), complex(inf, -1), complex(-zero, zero)},
+	{complex(-1, 2), complex(inf, 2), complex(-zero, zero)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(-1, 2), complex(-inf, zero), complex(zero, -zero)},
+	{complex(-1, 2), complex(-inf, -zero), complex(zero, -zero)},
+	{complex(-1, 2), complex(-inf, 1), complex(zero, -zero)},
+	{complex(-1, 2), complex(-inf, -1), complex(zero, -zero)},
+	{complex(-1, 2), complex(-inf, 2), complex(zero, -zero)},
+	{complex(-1, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-1, 2), complex(nan, inf), complex(zero, zero)},
+	{complex(-1, 2), complex(nan, -inf), complex(-zero, -zero)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(2, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(2, zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(2, zero), complex(zero, 1), complex(zero, -2)},
+	{complex(2, zero), complex(zero, -1), complex(-zero, 2)},
+	{complex(2, zero), complex(zero, 2), complex(zero, -1)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(2, zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(2, zero), complex(zero, 1), complex(zero, -2)},
+	{complex(2, zero), complex(-zero, -1), complex(-zero, 2)},
+	{complex(2, zero), complex(zero, 2), complex(zero, -1)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(1, zero), complex(2, zero)},
+	{complex(2, zero), complex(1, -zero), complex(2, zero)},
+	{complex(2, zero), complex(1, 1), complex(1, -1)},
+	{complex(2, zero), complex(1, -1), complex(1, 1)},
+	{complex(2, zero), complex(1, 2), complex(0.4, -0.8)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(-1, zero), complex(-2, -zero)},
+	{complex(2, zero), complex(-1, -zero), complex(-2, -zero)},
+	{complex(2, zero), complex(-1, 1), complex(-1, -1)},
+	{complex(2, zero), complex(-1, -1), complex(-1, 1)},
+	{complex(2, zero), complex(-1, 2), complex(-0.4, -0.8)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(2, zero), complex(1, zero)},
+	{complex(2, zero), complex(2, -zero), complex(1, zero)},
+	{complex(2, zero), complex(2, 1), complex(0.8, -0.4)},
+	{complex(2, zero), complex(2, -1), complex(0.8, 0.4)},
+	{complex(2, zero), complex(2, 2), complex(0.5, -0.5)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(2, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(2, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(2, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(2, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(inf, zero), complex(zero, zero)},
+	{complex(2, zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(2, zero), complex(inf, 1), complex(zero, zero)},
+	{complex(2, zero), complex(inf, -1), complex(zero, zero)},
+	{complex(2, zero), complex(inf, 2), complex(zero, zero)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(2, zero), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(2, zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(2, zero), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(2, zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(2, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, zero), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, zero), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(2, -zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(2, -zero), complex(zero, 1), complex(zero, -2)},
+	{complex(2, -zero), complex(zero, -1), complex(zero, 2)},
+	{complex(2, -zero), complex(zero, 2), complex(zero, -1)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(2, -zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(2, -zero), complex(zero, 1), complex(zero, -2)},
+	{complex(2, -zero), complex(-zero, -1), complex(-zero, 2)},
+	{complex(2, -zero), complex(zero, 2), complex(zero, -1)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(1, zero), complex(2, -zero)},
+	{complex(2, -zero), complex(1, -zero), complex(2, zero)},
+	{complex(2, -zero), complex(1, 1), complex(1, -1)},
+	{complex(2, -zero), complex(1, -1), complex(1, 1)},
+	{complex(2, -zero), complex(1, 2), complex(0.4, -0.8)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(-1, zero), complex(-2, -zero)},
+	{complex(2, -zero), complex(-1, -zero), complex(-2, zero)},
+	{complex(2, -zero), complex(-1, 1), complex(-1, -1)},
+	{complex(2, -zero), complex(-1, -1), complex(-1, 1)},
+	{complex(2, -zero), complex(-1, 2), complex(-0.4, -0.8)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(2, zero), complex(1, -zero)},
+	{complex(2, -zero), complex(2, -zero), complex(1, zero)},
+	{complex(2, -zero), complex(2, 1), complex(0.8, -0.4)},
+	{complex(2, -zero), complex(2, -1), complex(0.8, 0.4)},
+	{complex(2, -zero), complex(2, 2), complex(0.5, -0.5)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(inf, zero), complex(zero, -zero)},
+	{complex(2, -zero), complex(inf, -zero), complex(zero, zero)},
+	{complex(2, -zero), complex(inf, 1), complex(zero, -zero)},
+	{complex(2, -zero), complex(inf, -1), complex(zero, zero)},
+	{complex(2, -zero), complex(inf, 2), complex(zero, -zero)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -zero), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(2, -zero), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(2, -zero), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(2, -zero), complex(-inf, -1), complex(-zero, zero)},
+	{complex(2, -zero), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -zero), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -zero), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(2, 1), complex(zero, -zero), complex(inf, inf)},
+	{complex(2, 1), complex(zero, 1), complex(1, -2)},
+	{complex(2, 1), complex(zero, -1), complex(-1, 2)},
+	{complex(2, 1), complex(zero, 2), complex(0.5, -1)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(2, 1), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(2, 1), complex(zero, 1), complex(1, -2)},
+	{complex(2, 1), complex(-zero, -1), complex(-1, 2)},
+	{complex(2, 1), complex(zero, 2), complex(0.5, -1)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(1, zero), complex(2, 1)},
+	{complex(2, 1), complex(1, -zero), complex(2, 1)},
+	{complex(2, 1), complex(1, 1), complex(1.5, -0.5)},
+	{complex(2, 1), complex(1, -1), complex(0.5, 1.5)},
+	{complex(2, 1), complex(1, 2), complex(0.8, -0.6)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(-1, zero), complex(-2, -1)},
+	{complex(2, 1), complex(-1, -zero), complex(-2, -1)},
+	{complex(2, 1), complex(-1, 1), complex(-0.5, -1.5)},
+	{complex(2, 1), complex(-1, -1), complex(-1.5, 0.5)},
+	{complex(2, 1), complex(-1, 2), complex(zero, -1)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(2, zero), complex(1, 0.5)},
+	{complex(2, 1), complex(2, -zero), complex(1, 0.5)},
+	{complex(2, 1), complex(2, 1), complex(1, zero)},
+	{complex(2, 1), complex(2, -1), complex(0.6, 0.8)},
+	{complex(2, 1), complex(2, 2), complex(0.75, -0.25)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(2, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(2, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(2, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(2, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(inf, zero), complex(zero, zero)},
+	{complex(2, 1), complex(inf, -zero), complex(zero, zero)},
+	{complex(2, 1), complex(inf, 1), complex(zero, zero)},
+	{complex(2, 1), complex(inf, -1), complex(zero, zero)},
+	{complex(2, 1), complex(inf, 2), complex(zero, zero)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 1), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(2, 1), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(2, 1), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(2, 1), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(2, 1), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(2, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 1), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 1), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(2, -1), complex(zero, -zero), complex(inf, -inf)},
+	{complex(2, -1), complex(zero, 1), complex(-1, -2)},
+	{complex(2, -1), complex(zero, -1), complex(1, 2)},
+	{complex(2, -1), complex(zero, 2), complex(-0.5, -1)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(2, -1), complex(-zero, -zero), complex(-inf, inf)},
+	{complex(2, -1), complex(zero, 1), complex(-1, -2)},
+	{complex(2, -1), complex(-zero, -1), complex(1, 2)},
+	{complex(2, -1), complex(zero, 2), complex(-0.5, -1)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(1, zero), complex(2, -1)},
+	{complex(2, -1), complex(1, -zero), complex(2, -1)},
+	{complex(2, -1), complex(1, 1), complex(0.5, -1.5)},
+	{complex(2, -1), complex(1, -1), complex(1.5, 0.5)},
+	{complex(2, -1), complex(1, 2), complex(zero, -1)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(-1, zero), complex(-2, 1)},
+	{complex(2, -1), complex(-1, -zero), complex(-2, 1)},
+	{complex(2, -1), complex(-1, 1), complex(-1.5, -0.5)},
+	{complex(2, -1), complex(-1, -1), complex(-0.5, 1.5)},
+	{complex(2, -1), complex(-1, 2), complex(-0.8, -0.6)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(2, zero), complex(1, -0.5)},
+	{complex(2, -1), complex(2, -zero), complex(1, -0.5)},
+	{complex(2, -1), complex(2, 1), complex(0.6, -0.8)},
+	{complex(2, -1), complex(2, -1), complex(1, zero)},
+	{complex(2, -1), complex(2, 2), complex(0.25, -0.75)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(2, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(2, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(2, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(2, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(inf, zero), complex(zero, -zero)},
+	{complex(2, -1), complex(inf, -zero), complex(zero, -zero)},
+	{complex(2, -1), complex(inf, 1), complex(zero, -zero)},
+	{complex(2, -1), complex(inf, -1), complex(zero, -zero)},
+	{complex(2, -1), complex(inf, 2), complex(zero, -zero)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, -1), complex(-inf, zero), complex(-zero, zero)},
+	{complex(2, -1), complex(-inf, -zero), complex(-zero, zero)},
+	{complex(2, -1), complex(-inf, 1), complex(-zero, zero)},
+	{complex(2, -1), complex(-inf, -1), complex(-zero, zero)},
+	{complex(2, -1), complex(-inf, 2), complex(-zero, zero)},
+	{complex(2, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(2, -1), complex(nan, inf), complex(-zero, -zero)},
+	{complex(2, -1), complex(nan, -inf), complex(zero, zero)},
+	{complex(2, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(2, 2), complex(zero, -zero), complex(inf, inf)},
+	{complex(2, 2), complex(zero, 1), complex(2, -2)},
+	{complex(2, 2), complex(zero, -1), complex(-2, 2)},
+	{complex(2, 2), complex(zero, 2), complex(1, -1)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(2, 2), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(2, 2), complex(zero, 1), complex(2, -2)},
+	{complex(2, 2), complex(-zero, -1), complex(-2, 2)},
+	{complex(2, 2), complex(zero, 2), complex(1, -1)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(1, zero), complex(2, 2)},
+	{complex(2, 2), complex(1, -zero), complex(2, 2)},
+	{complex(2, 2), complex(1, 1), complex(2, zero)},
+	{complex(2, 2), complex(1, -1), complex(zero, 2)},
+	{complex(2, 2), complex(1, 2), complex(1.2, -0.4)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(-1, zero), complex(-2, -2)},
+	{complex(2, 2), complex(-1, -zero), complex(-2, -2)},
+	{complex(2, 2), complex(-1, 1), complex(-zero, -2)},
+	{complex(2, 2), complex(-1, -1), complex(-2, -zero)},
+	{complex(2, 2), complex(-1, 2), complex(0.4, -1.2)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(2, zero), complex(1, 1)},
+	{complex(2, 2), complex(2, -zero), complex(1, 1)},
+	{complex(2, 2), complex(2, 1), complex(1.2, 0.4)},
+	{complex(2, 2), complex(2, -1), complex(0.4, 1.2)},
+	{complex(2, 2), complex(2, 2), complex(1, zero)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(2, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(2, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(2, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(2, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(inf, zero), complex(zero, zero)},
+	{complex(2, 2), complex(inf, -zero), complex(zero, zero)},
+	{complex(2, 2), complex(inf, 1), complex(zero, zero)},
+	{complex(2, 2), complex(inf, -1), complex(zero, zero)},
+	{complex(2, 2), complex(inf, 2), complex(zero, zero)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(2, 2), complex(-inf, zero), complex(-zero, -zero)},
+	{complex(2, 2), complex(-inf, -zero), complex(-zero, -zero)},
+	{complex(2, 2), complex(-inf, 1), complex(-zero, -zero)},
+	{complex(2, 2), complex(-inf, -1), complex(-zero, -zero)},
+	{complex(2, 2), complex(-inf, 2), complex(-zero, -zero)},
+	{complex(2, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(2, 2), complex(nan, inf), complex(zero, -zero)},
+	{complex(2, 2), complex(nan, -inf), complex(-zero, zero)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(1, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(1, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(1, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(1, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(2, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(2, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(2, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(2, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(1, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(1, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(1, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(1, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(2, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(2, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(2, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(2, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, 1), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, 1), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, 1), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, 1), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(1, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(1, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(1, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(1, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(2, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(2, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(2, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(2, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 1), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, 1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, 1), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, 1), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, 1), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -1), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -1), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -1), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -1), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(1, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(1, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(1, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(1, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(2, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(2, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(2, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(2, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -1), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -1), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -1), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -1), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, 2), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, 2), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, 2), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, 2), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(1, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(1, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(1, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(1, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(2, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(2, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(2, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(2, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, 2), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, 2), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, 2), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, 2), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, 2), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(inf, zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(inf, zero), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, zero), complex(zero, -1), complex(nan, inf)},
+	{complex(inf, zero), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(zero, zero), complex(inf, nan)},
+	{complex(inf, zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(inf, zero), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, zero), complex(-zero, -1), complex(nan, inf)},
+	{complex(inf, zero), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(1, zero), complex(inf, nan)},
+	{complex(inf, zero), complex(1, -zero), complex(inf, nan)},
+	{complex(inf, zero), complex(1, 1), complex(inf, -inf)},
+	{complex(inf, zero), complex(1, -1), complex(inf, inf)},
+	{complex(inf, zero), complex(1, 2), complex(inf, -inf)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(-1, zero), complex(-inf, nan)},
+	{complex(inf, zero), complex(-1, -zero), complex(-inf, nan)},
+	{complex(inf, zero), complex(-1, 1), complex(-inf, -inf)},
+	{complex(inf, zero), complex(-1, -1), complex(-inf, inf)},
+	{complex(inf, zero), complex(-1, 2), complex(-inf, -inf)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(2, zero), complex(inf, nan)},
+	{complex(inf, zero), complex(2, -zero), complex(inf, nan)},
+	{complex(inf, zero), complex(2, 1), complex(inf, -inf)},
+	{complex(inf, zero), complex(2, -1), complex(inf, inf)},
+	{complex(inf, zero), complex(2, 2), complex(inf, -inf)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(inf, zero), complex(nan, nan)},
+	{complex(inf, zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(inf, zero), complex(inf, 1), complex(nan, nan)},
+	{complex(inf, zero), complex(inf, -1), complex(nan, nan)},
+	{complex(inf, zero), complex(inf, 2), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(inf, zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(inf, zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(inf, zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(inf, zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(zero, -zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, -zero), complex(zero, -1), complex(nan, inf)},
+	{complex(inf, -zero), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(zero, zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(-zero, -zero), complex(-inf, nan)},
+	{complex(inf, -zero), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, -zero), complex(-zero, -1), complex(nan, inf)},
+	{complex(inf, -zero), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(1, zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(1, -zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(1, 1), complex(inf, -inf)},
+	{complex(inf, -zero), complex(1, -1), complex(inf, inf)},
+	{complex(inf, -zero), complex(1, 2), complex(inf, -inf)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(-1, zero), complex(-inf, nan)},
+	{complex(inf, -zero), complex(-1, -zero), complex(-inf, nan)},
+	{complex(inf, -zero), complex(-1, 1), complex(-inf, -inf)},
+	{complex(inf, -zero), complex(-1, -1), complex(-inf, inf)},
+	{complex(inf, -zero), complex(-1, 2), complex(-inf, -inf)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(2, zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(2, -zero), complex(inf, nan)},
+	{complex(inf, -zero), complex(2, 1), complex(inf, -inf)},
+	{complex(inf, -zero), complex(2, -1), complex(inf, inf)},
+	{complex(inf, -zero), complex(2, 2), complex(inf, -inf)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(inf, zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(inf, 1), complex(nan, nan)},
+	{complex(inf, -zero), complex(inf, -1), complex(nan, nan)},
+	{complex(inf, -zero), complex(inf, 2), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(inf, -zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(inf, -zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(inf, -zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(inf, 1), complex(zero, -zero), complex(inf, inf)},
+	{complex(inf, 1), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, 1), complex(zero, -1), complex(nan, inf)},
+	{complex(inf, 1), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(zero, zero), complex(inf, inf)},
+	{complex(inf, 1), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(inf, 1), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, 1), complex(-zero, -1), complex(nan, inf)},
+	{complex(inf, 1), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(1, zero), complex(inf, nan)},
+	{complex(inf, 1), complex(1, -zero), complex(inf, nan)},
+	{complex(inf, 1), complex(1, 1), complex(inf, -inf)},
+	{complex(inf, 1), complex(1, -1), complex(inf, inf)},
+	{complex(inf, 1), complex(1, 2), complex(inf, -inf)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(-1, zero), complex(-inf, nan)},
+	{complex(inf, 1), complex(-1, -zero), complex(-inf, nan)},
+	{complex(inf, 1), complex(-1, 1), complex(-inf, -inf)},
+	{complex(inf, 1), complex(-1, -1), complex(-inf, inf)},
+	{complex(inf, 1), complex(-1, 2), complex(-inf, -inf)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(2, zero), complex(inf, nan)},
+	{complex(inf, 1), complex(2, -zero), complex(inf, nan)},
+	{complex(inf, 1), complex(2, 1), complex(inf, -inf)},
+	{complex(inf, 1), complex(2, -1), complex(inf, inf)},
+	{complex(inf, 1), complex(2, 2), complex(inf, -inf)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(inf, zero), complex(nan, nan)},
+	{complex(inf, 1), complex(inf, -zero), complex(nan, nan)},
+	{complex(inf, 1), complex(inf, 1), complex(nan, nan)},
+	{complex(inf, 1), complex(inf, -1), complex(nan, nan)},
+	{complex(inf, 1), complex(inf, 2), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 1), complex(-inf, zero), complex(nan, nan)},
+	{complex(inf, 1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(inf, 1), complex(-inf, 1), complex(nan, nan)},
+	{complex(inf, 1), complex(-inf, -1), complex(nan, nan)},
+	{complex(inf, 1), complex(-inf, 2), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(inf, -1), complex(zero, -zero), complex(inf, -inf)},
+	{complex(inf, -1), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, -1), complex(zero, -1), complex(nan, inf)},
+	{complex(inf, -1), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(zero, zero), complex(inf, -inf)},
+	{complex(inf, -1), complex(-zero, -zero), complex(-inf, inf)},
+	{complex(inf, -1), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, -1), complex(-zero, -1), complex(nan, inf)},
+	{complex(inf, -1), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(1, zero), complex(inf, nan)},
+	{complex(inf, -1), complex(1, -zero), complex(inf, nan)},
+	{complex(inf, -1), complex(1, 1), complex(inf, -inf)},
+	{complex(inf, -1), complex(1, -1), complex(inf, inf)},
+	{complex(inf, -1), complex(1, 2), complex(inf, -inf)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(-1, zero), complex(-inf, nan)},
+	{complex(inf, -1), complex(-1, -zero), complex(-inf, nan)},
+	{complex(inf, -1), complex(-1, 1), complex(-inf, -inf)},
+	{complex(inf, -1), complex(-1, -1), complex(-inf, inf)},
+	{complex(inf, -1), complex(-1, 2), complex(-inf, -inf)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(2, zero), complex(inf, nan)},
+	{complex(inf, -1), complex(2, -zero), complex(inf, nan)},
+	{complex(inf, -1), complex(2, 1), complex(inf, -inf)},
+	{complex(inf, -1), complex(2, -1), complex(inf, inf)},
+	{complex(inf, -1), complex(2, 2), complex(inf, -inf)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(inf, zero), complex(nan, nan)},
+	{complex(inf, -1), complex(inf, -zero), complex(nan, nan)},
+	{complex(inf, -1), complex(inf, 1), complex(nan, nan)},
+	{complex(inf, -1), complex(inf, -1), complex(nan, nan)},
+	{complex(inf, -1), complex(inf, 2), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, -1), complex(-inf, zero), complex(nan, nan)},
+	{complex(inf, -1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(inf, -1), complex(-inf, 1), complex(nan, nan)},
+	{complex(inf, -1), complex(-inf, -1), complex(nan, nan)},
+	{complex(inf, -1), complex(-inf, 2), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(inf, 2), complex(zero, -zero), complex(inf, inf)},
+	{complex(inf, 2), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, 2), complex(zero, -1), complex(nan, inf)},
+	{complex(inf, 2), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(zero, zero), complex(inf, inf)},
+	{complex(inf, 2), complex(-zero, -zero), complex(-inf, -inf)},
+	{complex(inf, 2), complex(zero, 1), complex(nan, -inf)},
+	{complex(inf, 2), complex(-zero, -1), complex(nan, inf)},
+	{complex(inf, 2), complex(zero, 2), complex(nan, -inf)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(1, zero), complex(inf, nan)},
+	{complex(inf, 2), complex(1, -zero), complex(inf, nan)},
+	{complex(inf, 2), complex(1, 1), complex(inf, -inf)},
+	{complex(inf, 2), complex(1, -1), complex(inf, inf)},
+	{complex(inf, 2), complex(1, 2), complex(inf, -inf)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(-1, zero), complex(-inf, nan)},
+	{complex(inf, 2), complex(-1, -zero), complex(-inf, nan)},
+	{complex(inf, 2), complex(-1, 1), complex(-inf, -inf)},
+	{complex(inf, 2), complex(-1, -1), complex(-inf, inf)},
+	{complex(inf, 2), complex(-1, 2), complex(-inf, -inf)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(2, zero), complex(inf, nan)},
+	{complex(inf, 2), complex(2, -zero), complex(inf, nan)},
+	{complex(inf, 2), complex(2, 1), complex(inf, -inf)},
+	{complex(inf, 2), complex(2, -1), complex(inf, inf)},
+	{complex(inf, 2), complex(2, 2), complex(inf, -inf)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(inf, zero), complex(nan, nan)},
+	{complex(inf, 2), complex(inf, -zero), complex(nan, nan)},
+	{complex(inf, 2), complex(inf, 1), complex(nan, nan)},
+	{complex(inf, 2), complex(inf, -1), complex(nan, nan)},
+	{complex(inf, 2), complex(inf, 2), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(inf, 2), complex(-inf, zero), complex(nan, nan)},
+	{complex(inf, 2), complex(-inf, -zero), complex(nan, nan)},
+	{complex(inf, 2), complex(-inf, 1), complex(nan, nan)},
+	{complex(inf, 2), complex(-inf, -1), complex(nan, nan)},
+	{complex(inf, 2), complex(-inf, 2), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(zero, -zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, zero), complex(zero, -1), complex(nan, -inf)},
+	{complex(-inf, zero), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(-zero, -zero), complex(inf, nan)},
+	{complex(-inf, zero), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, zero), complex(-zero, -1), complex(nan, -inf)},
+	{complex(-inf, zero), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(1, zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(1, -zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(1, 1), complex(-inf, inf)},
+	{complex(-inf, zero), complex(1, -1), complex(-inf, -inf)},
+	{complex(-inf, zero), complex(1, 2), complex(-inf, inf)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(-1, zero), complex(inf, nan)},
+	{complex(-inf, zero), complex(-1, -zero), complex(inf, nan)},
+	{complex(-inf, zero), complex(-1, 1), complex(inf, inf)},
+	{complex(-inf, zero), complex(-1, -1), complex(inf, -inf)},
+	{complex(-inf, zero), complex(-1, 2), complex(inf, inf)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(2, zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(2, -zero), complex(-inf, nan)},
+	{complex(-inf, zero), complex(2, 1), complex(-inf, inf)},
+	{complex(-inf, zero), complex(2, -1), complex(-inf, -inf)},
+	{complex(-inf, zero), complex(2, 2), complex(-inf, inf)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, 1), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -1), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, 2), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(inf, zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(inf, 1), complex(nan, nan)},
+	{complex(-inf, zero), complex(inf, -1), complex(nan, nan)},
+	{complex(-inf, zero), complex(inf, 2), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(-inf, zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(-inf, zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(-inf, zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(zero, -zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, -zero), complex(zero, -1), complex(nan, -inf)},
+	{complex(-inf, -zero), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(zero, zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(-zero, -zero), complex(inf, nan)},
+	{complex(-inf, -zero), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, -zero), complex(-zero, -1), complex(nan, -inf)},
+	{complex(-inf, -zero), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(1, zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(1, -zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(1, 1), complex(-inf, inf)},
+	{complex(-inf, -zero), complex(1, -1), complex(-inf, -inf)},
+	{complex(-inf, -zero), complex(1, 2), complex(-inf, inf)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-1, zero), complex(inf, nan)},
+	{complex(-inf, -zero), complex(-1, -zero), complex(inf, nan)},
+	{complex(-inf, -zero), complex(-1, 1), complex(inf, inf)},
+	{complex(-inf, -zero), complex(-1, -1), complex(inf, -inf)},
+	{complex(-inf, -zero), complex(-1, 2), complex(inf, inf)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(2, zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(2, -zero), complex(-inf, nan)},
+	{complex(-inf, -zero), complex(2, 1), complex(-inf, inf)},
+	{complex(-inf, -zero), complex(2, -1), complex(-inf, -inf)},
+	{complex(-inf, -zero), complex(2, 2), complex(-inf, inf)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, 1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, 2), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(inf, zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(inf, -zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(inf, 1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(inf, -1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(inf, 2), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-inf, zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-inf, -zero), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-inf, 1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-inf, -1), complex(nan, nan)},
+	{complex(-inf, -zero), complex(-inf, 2), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -zero), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(zero, zero), complex(-inf, inf)},
+	{complex(-inf, 1), complex(zero, -zero), complex(-inf, inf)},
+	{complex(-inf, 1), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, 1), complex(zero, -1), complex(nan, -inf)},
+	{complex(-inf, 1), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(zero, zero), complex(-inf, inf)},
+	{complex(-inf, 1), complex(-zero, -zero), complex(inf, -inf)},
+	{complex(-inf, 1), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, 1), complex(-zero, -1), complex(nan, -inf)},
+	{complex(-inf, 1), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(1, zero), complex(-inf, nan)},
+	{complex(-inf, 1), complex(1, -zero), complex(-inf, nan)},
+	{complex(-inf, 1), complex(1, 1), complex(-inf, inf)},
+	{complex(-inf, 1), complex(1, -1), complex(-inf, -inf)},
+	{complex(-inf, 1), complex(1, 2), complex(-inf, inf)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(-1, zero), complex(inf, nan)},
+	{complex(-inf, 1), complex(-1, -zero), complex(inf, nan)},
+	{complex(-inf, 1), complex(-1, 1), complex(inf, inf)},
+	{complex(-inf, 1), complex(-1, -1), complex(inf, -inf)},
+	{complex(-inf, 1), complex(-1, 2), complex(inf, inf)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(2, zero), complex(-inf, nan)},
+	{complex(-inf, 1), complex(2, -zero), complex(-inf, nan)},
+	{complex(-inf, 1), complex(2, 1), complex(-inf, inf)},
+	{complex(-inf, 1), complex(2, -1), complex(-inf, -inf)},
+	{complex(-inf, 1), complex(2, 2), complex(-inf, inf)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, 1), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -1), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, 2), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(inf, zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(inf, -zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(inf, 1), complex(nan, nan)},
+	{complex(-inf, 1), complex(inf, -1), complex(nan, nan)},
+	{complex(-inf, 1), complex(inf, 2), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(-inf, zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(-inf, 1), complex(-inf, 1), complex(nan, nan)},
+	{complex(-inf, 1), complex(-inf, -1), complex(nan, nan)},
+	{complex(-inf, 1), complex(-inf, 2), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(zero, zero), complex(-inf, -inf)},
+	{complex(-inf, -1), complex(zero, -zero), complex(-inf, -inf)},
+	{complex(-inf, -1), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, -1), complex(zero, -1), complex(nan, -inf)},
+	{complex(-inf, -1), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(zero, zero), complex(-inf, -inf)},
+	{complex(-inf, -1), complex(-zero, -zero), complex(inf, inf)},
+	{complex(-inf, -1), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, -1), complex(-zero, -1), complex(nan, -inf)},
+	{complex(-inf, -1), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(1, zero), complex(-inf, nan)},
+	{complex(-inf, -1), complex(1, -zero), complex(-inf, nan)},
+	{complex(-inf, -1), complex(1, 1), complex(-inf, inf)},
+	{complex(-inf, -1), complex(1, -1), complex(-inf, -inf)},
+	{complex(-inf, -1), complex(1, 2), complex(-inf, inf)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(-1, zero), complex(inf, nan)},
+	{complex(-inf, -1), complex(-1, -zero), complex(inf, nan)},
+	{complex(-inf, -1), complex(-1, 1), complex(inf, inf)},
+	{complex(-inf, -1), complex(-1, -1), complex(inf, -inf)},
+	{complex(-inf, -1), complex(-1, 2), complex(inf, inf)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(2, zero), complex(-inf, nan)},
+	{complex(-inf, -1), complex(2, -zero), complex(-inf, nan)},
+	{complex(-inf, -1), complex(2, 1), complex(-inf, inf)},
+	{complex(-inf, -1), complex(2, -1), complex(-inf, -inf)},
+	{complex(-inf, -1), complex(2, 2), complex(-inf, inf)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, 1), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -1), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, 2), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(inf, zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(inf, -zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(inf, 1), complex(nan, nan)},
+	{complex(-inf, -1), complex(inf, -1), complex(nan, nan)},
+	{complex(-inf, -1), complex(inf, 2), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(-inf, zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(-inf, -zero), complex(nan, nan)},
+	{complex(-inf, -1), complex(-inf, 1), complex(nan, nan)},
+	{complex(-inf, -1), complex(-inf, -1), complex(nan, nan)},
+	{complex(-inf, -1), complex(-inf, 2), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, -1), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(zero, zero), complex(-inf, inf)},
+	{complex(-inf, 2), complex(zero, -zero), complex(-inf, inf)},
+	{complex(-inf, 2), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, 2), complex(zero, -1), complex(nan, -inf)},
+	{complex(-inf, 2), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(zero, zero), complex(-inf, inf)},
+	{complex(-inf, 2), complex(-zero, -zero), complex(inf, -inf)},
+	{complex(-inf, 2), complex(zero, 1), complex(nan, inf)},
+	{complex(-inf, 2), complex(-zero, -1), complex(nan, -inf)},
+	{complex(-inf, 2), complex(zero, 2), complex(nan, inf)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(1, zero), complex(-inf, nan)},
+	{complex(-inf, 2), complex(1, -zero), complex(-inf, nan)},
+	{complex(-inf, 2), complex(1, 1), complex(-inf, inf)},
+	{complex(-inf, 2), complex(1, -1), complex(-inf, -inf)},
+	{complex(-inf, 2), complex(1, 2), complex(-inf, inf)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(-1, zero), complex(inf, nan)},
+	{complex(-inf, 2), complex(-1, -zero), complex(inf, nan)},
+	{complex(-inf, 2), complex(-1, 1), complex(inf, inf)},
+	{complex(-inf, 2), complex(-1, -1), complex(inf, -inf)},
+	{complex(-inf, 2), complex(-1, 2), complex(inf, inf)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(2, zero), complex(-inf, nan)},
+	{complex(-inf, 2), complex(2, -zero), complex(-inf, nan)},
+	{complex(-inf, 2), complex(2, 1), complex(-inf, inf)},
+	{complex(-inf, 2), complex(2, -1), complex(-inf, -inf)},
+	{complex(-inf, 2), complex(2, 2), complex(-inf, inf)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, 1), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -1), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, 2), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(inf, zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(inf, -zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(inf, 1), complex(nan, nan)},
+	{complex(-inf, 2), complex(inf, -1), complex(nan, nan)},
+	{complex(-inf, 2), complex(inf, 2), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(-inf, zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(-inf, -zero), complex(nan, nan)},
+	{complex(-inf, 2), complex(-inf, 1), complex(nan, nan)},
+	{complex(-inf, 2), complex(-inf, -1), complex(nan, nan)},
+	{complex(-inf, 2), complex(-inf, 2), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, nan), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, inf), complex(nan, nan)},
+	{complex(-inf, 2), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-zero, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(zero, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-1, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(2, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(2, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, nan), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, nan), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(zero, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(-zero, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(zero, 1), complex(inf, nan)},
+	{complex(nan, inf), complex(-zero, -1), complex(-inf, nan)},
+	{complex(nan, inf), complex(zero, 2), complex(inf, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(1, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(1, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(1, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(1, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-1, zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, -zero), complex(nan, -inf)},
+	{complex(nan, inf), complex(-1, 1), complex(inf, -inf)},
+	{complex(nan, inf), complex(-1, -1), complex(-inf, -inf)},
+	{complex(nan, inf), complex(-1, 2), complex(inf, -inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(2, zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, -zero), complex(nan, inf)},
+	{complex(nan, inf), complex(2, 1), complex(inf, inf)},
+	{complex(nan, inf), complex(2, -1), complex(-inf, inf)},
+	{complex(nan, inf), complex(2, 2), complex(inf, inf)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(zero, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(-zero, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(zero, 1), complex(-inf, nan)},
+	{complex(nan, -inf), complex(-zero, -1), complex(inf, nan)},
+	{complex(nan, -inf), complex(zero, 2), complex(-inf, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(1, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(1, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(1, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(1, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-1, zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, -zero), complex(nan, inf)},
+	{complex(nan, -inf), complex(-1, 1), complex(-inf, inf)},
+	{complex(nan, -inf), complex(-1, -1), complex(inf, inf)},
+	{complex(nan, -inf), complex(-1, 2), complex(-inf, inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(2, zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, -zero), complex(nan, -inf)},
+	{complex(nan, -inf), complex(2, 1), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(2, -1), complex(inf, -inf)},
+	{complex(nan, -inf), complex(2, 2), complex(-inf, -inf)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -zero), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, -1), complex(nan, nan)},
+	{complex(nan, -inf), complex(-inf, 2), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, nan), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, inf), complex(nan, nan)},
+	{complex(nan, -inf), complex(nan, -inf), complex(nan, nan)},
 }
diff --git a/test/complit1.go b/test/complit1.go
index 9dde994..83695a9 100644
--- a/test/complit1.go
+++ b/test/complit1.go
@@ -22,6 +22,10 @@ var (
 	_ = m[0][:]            // ERROR "slice of unaddressable value"
 	_ = f()[:]             // ERROR "slice of unaddressable value"
 
+	_ = 301[:]  // ERROR "cannot slice"
+	_ = 3.1[:]  // ERROR "cannot slice"
+	_ = true[:] // ERROR "cannot slice"
+
 	// these are okay because they are slicing a pointer to an array
 	_ = (&[3]int{1, 2, 3})[:]
 	_ = mp[0][:]
@@ -35,10 +39,15 @@ type T struct {
 	next *T
 }
 
+type TP *T
+type Ti int
+
 var (
 	_ = &T{0, 0, "", nil}               // ok
 	_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
 	_ = &T{0, 0, "", {}}                // ERROR "missing type in composite literal|omit types within composite literal"
+	_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid pointer type"
+	_ = &Ti{}                           // ERROR "invalid pointer type"
 )
 
 type M map[T]T
diff --git a/test/copy1.go b/test/copy1.go
new file mode 100644
index 0000000..1428549
--- /dev/null
+++ b/test/copy1.go
@@ -0,0 +1,27 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 copy arguments requirements are enforced by the
+// compiler.
+
+package main
+
+func main() {
+
+	si := make([]int, 8)
+	sf := make([]float64, 8)
+
+	_ = copy()        // ERROR "missing arguments"
+	_ = copy(1, 2, 3) // ERROR "too many arguments"
+
+	_ = copy(si, "hi") // ERROR "have different element types.*int.*string"
+	_ = copy(si, sf)   // ERROR "have different element types.*int.*float64"
+
+	_ = copy(1, 2)  // ERROR "must be slices; have int, int"
+	_ = copy(1, si) // ERROR "first argument to copy should be"
+	_ = copy(si, 2) // ERROR "second argument to copy should be"
+
+}
diff --git a/test/ddd1.go b/test/ddd1.go
index cf6a3a5..4284e32 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -42,6 +42,8 @@ var (
 	_ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
 )
 
+func Foo(n int) {}
+
 func bad(args ...int) {
 	print(1, 2, args...)	// ERROR "[.][.][.]"
 	println(args...)	// ERROR "[.][.][.]"
@@ -58,4 +60,6 @@ func bad(args ...int) {
 	_ = unsafe.Sizeof(x...)	// ERROR "[.][.][.]"
 	_ = [...]byte("foo") // ERROR "[.][.][.]"
 	_ = [...][...]int{{1,2,3},{4,5,6}}	// ERROR "[.][.][.]"
+
+	Foo(x...) // ERROR "invalid use of [.][.][.] in call"
 }
diff --git a/test/devirt.go b/test/devirt.go
new file mode 100644
index 0000000..2357709
--- /dev/null
+++ b/test/devirt.go
@@ -0,0 +1,39 @@
+// errorcheck -0 -d=ssa/opt/debug=3
+
+package main
+
+// Trivial interface call devirtualization test.
+
+type real struct {
+	value int
+}
+
+func (r *real) Value() int { return r.value }
+
+type Valuer interface {
+	Value() int
+}
+
+type indirectiface struct {
+	a, b, c int
+}
+
+func (i indirectiface) Value() int {
+	return i.a + i.b + i.c
+}
+
+func main() {
+	var r Valuer
+	rptr := &real{value: 3}
+	r = rptr
+
+	if r.Value() != 3 { // ERROR "de-virtualizing call$"
+		panic("not 3")
+	}
+
+	// Can't do types that aren't "direct" interfaces (yet).
+	r = indirectiface{3, 4, 5}
+	if r.Value() != 12 {
+		panic("not 12")
+	}
+}
diff --git a/test/escape2.go b/test/escape2.go
index 3490c29..e10dbc2 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1824,3 +1824,18 @@ func issue11387(x int) func() int {
 	copy(slice2, slice1)
 	return slice2[0]
 }
+
+func issue12397(x, y int) { // ERROR "moved to heap: y$"
+	// x does not escape below, because all relevant code is dead.
+	if false {
+		gxx = &x
+	} else {
+		gxx = &y // ERROR "&y escapes to heap$"
+	}
+
+	if true {
+		gxx = &y // ERROR "&y escapes to heap$"
+	} else {
+		gxx = &x
+	}
+}
diff --git a/test/escape5.go b/test/escape5.go
index c4bf17b..7d6ef55 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -9,6 +9,8 @@
 
 package foo
 
+import "runtime"
+
 func noleak(p *int) int { // ERROR "p does not escape"
 	return *p
 }
@@ -149,3 +151,15 @@ func f10() {
 	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
 	_ = x[0] + y[0]
 }
+
+// Test for issue 19687 (passing to unnamed parameters does not escape).
+func f11(**int) {
+}
+func f12(_ **int) {
+}
+func f13() {
+	var x *int
+	f11(&x)               // ERROR "&x does not escape"
+	f12(&x)               // ERROR "&x does not escape"
+	runtime.KeepAlive(&x) // ERROR "&x does not escape"
+}
diff --git a/test/escape_closure.go b/test/escape_closure.go
index e9cf776..fc35cb5 100644
--- a/test/escape_closure.go
+++ b/test/escape_closure.go
@@ -55,9 +55,9 @@ func ClosureCallArgs4() {
 
 func ClosureCallArgs5() {
 	x := 0                     // ERROR "moved to heap: x"
-	sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape"
+	sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap"
 		return p
-	}(&x) // ERROR "&x escapes to heap" "\(func literal\)\(&x\) escapes to heap"
+	}(&x) // ERROR "&x escapes to heap"
 }
 
 func ClosureCallArgs6() {
@@ -140,10 +140,10 @@ func ClosureCallArgs14() {
 func ClosureCallArgs15() {
 	x := 0                      // ERROR "moved to heap: x"
 	p := &x                     // ERROR "moved to heap: p" "&x escapes to heap"
-	sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape"
+	sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap"
 		return *p
 		// BAD: p should not escape here
-	}(&p) // ERROR "&p escapes to heap" "\(func literal\)\(&p\) escapes to heap"
+	}(&p) // ERROR "&p escapes to heap"
 }
 
 func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape"
diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go
index 85367cb..8d392bd 100644
--- a/test/fixedbugs/bug195.go
+++ b/test/fixedbugs/bug195.go
@@ -14,14 +14,14 @@ type I3 interface { int }	// ERROR "interface"
 type S struct {
 	x interface{ S }	// ERROR "interface"
 }
-type I4 interface {
-	I4	// ERROR "interface"
+type I4 interface { // GC_ERROR "invalid recursive type"
+	I4	// GCCGO_ERROR "interface"
 }
 
 type I5 interface {
 	I6	// GCCGO_ERROR "interface"
 }
 
-type I6 interface {
-	I5	// ERROR "interface"
+type I6 interface { // GC_ERROR "invalid recursive type"
+	I5	// GCCGO_ERROR "interface"
 }
diff --git a/test/fixedbugs/bug217.go b/test/fixedbugs/bug217.go
index aafc260..ea836b9 100644
--- a/test/fixedbugs/bug217.go
+++ b/test/fixedbugs/bug217.go
@@ -13,3 +13,5 @@ func () x()	// ERROR "no receiver"
 
 func (a b, c d) x()	// ERROR "multiple receiver"
 
+type b int
+
diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go
index f061723..05e111a 100644
--- a/test/fixedbugs/bug251.go
+++ b/test/fixedbugs/bug251.go
@@ -6,13 +6,17 @@
 
 package main
 
-type I1 interface {
+type I1 interface { // GC_ERROR "invalid recursive type"
 	m() I2
-	I2 // GCCGO_ERROR "loop|interface"
+	// TODO(mdempsky): The duplicate method error is silly
+	// and redundant, but tricky to prevent as it's actually
+	// being emitted against the underlying interface type
+	// literal, not I1 itself.
+	I2 // ERROR "loop|interface|duplicate method m"
 }
 
 type I2 interface {
-	I1 // ERROR "loop|interface"
+	I1 // GCCGO_ERROR "loop|interface"
 }
 
 
diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go
index 247ca32..458fb97 100644
--- a/test/fixedbugs/bug255.go
+++ b/test/fixedbugs/bug255.go
@@ -11,7 +11,7 @@ var b [1e1]int     // ok
 var c [1.5]int     // ERROR "truncated"
 var d ["abc"]int   // ERROR "invalid array bound|not numeric"
 var e [nil]int     // ERROR "use of untyped nil|invalid array bound|not numeric"
-var f [e]int       // ERROR "invalid array bound|not constant"
+var f [e]int       // ok: error already reported for e
 var g [1 << 65]int // ERROR "array bound is too large|overflows"
 var h [len(a)]int  // ok
 
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index b6258d5..c04f211 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -48,15 +48,6 @@ func bigcap() {
 	g1 = make([]block, 10, big)
 }
 
-var g3 map[block]block
-func badmapcap() {
-	g3 = make(map[block]block, minus1)
-}
-
-func bigmapcap() {
-	g3 = make(map[block]block, big)
-}
-
 type cblock [1<<16-1]byte
 
 var g4 chan cblock
@@ -78,8 +69,6 @@ func main() {
 	shouldfail(badcap, "badcap")
 	shouldfail(badcap1, "badcap1")
 	shouldfail(bigcap, "bigcap")
-	shouldfail(badmapcap, "badmapcap")
-	shouldfail(bigmapcap, "bigmapcap")
 	shouldfail(badchancap, "badchancap")
 	shouldfail(bigchancap, "bigchancap")
 	shouldfail(overflowchan, "overflowchan")
diff --git a/test/fixedbugs/bug289.go b/test/fixedbugs/bug289.go
index 5a30979..a3f7295 100644
--- a/test/fixedbugs/bug289.go
+++ b/test/fixedbugs/bug289.go
@@ -9,14 +9,14 @@
 package main
 
 func f1() {
-	a, b := f()	// ERROR "mismatch|does not match"
+	a, b := f()	// ERROR "cannot assign|does not match"
 	_ = a
 	_ = b
 }
 
 func f2() {
 	var a, b int
-	a, b = f()	// ERROR "mismatch|does not match"
+	a, b = f()	// ERROR "cannot assign|does not match"
 	_ = a
 	_ = b
 }
diff --git a/test/fixedbugs/bug398.go b/test/fixedbugs/bug398.go
index 81bf33c..a1583bd 100644
--- a/test/fixedbugs/bug398.go
+++ b/test/fixedbugs/bug398.go
@@ -5,16 +5,36 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash compiler in interface type equality check.
+// (This test used to have problems - see #15596.)
 
 package p
 
+// exported interfaces
+
+type I1 interface {
+      F() interface{I1}
+}
+
+type I2 interface {
+      F() interface{I2}
+}
+
+var V1 I1
+var V2 I2
+
+func F() bool {
+       return V1 == V2
+}
+
+// non-exported interfaces
+
 type i1 interface {
       F() interface{i1}
 }
 
 type i2 interface {
       F() interface{i2}
-}       
+}
 
 var v1 i1
 var v2 i2
@@ -22,6 +42,3 @@ 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/bug487.go b/test/fixedbugs/bug487.go
index e60af6c..60a4ea9 100644
--- a/test/fixedbugs/bug487.go
+++ b/test/fixedbugs/bug487.go
@@ -14,8 +14,8 @@ func G() (int, int, int) {
 }
 
 func F() {
-	a, b := G()	// ERROR "mismatch"
-	a, b = G()	// ERROR "mismatch"
+	a, b := G()	// ERROR "cannot assign"
+	a, b = G()	// ERROR "cannot assign"
 	_, _ = a, b
 }
 
diff --git a/test/fixedbugs/bug502.go b/test/fixedbugs/bug502.go
new file mode 100644
index 0000000..cff73e7
--- /dev/null
+++ b/test/fixedbugs/bug502.go
@@ -0,0 +1,28 @@
+// build
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Linking this with gccgo got an undefined symbol reference,
+// because the private method in testing.TB led gccgo to assume that
+// the interface method table would be defined in the testing package.
+
+package main
+
+import "testing"
+
+type I interface {
+	testing.TB
+	Parallel()
+}
+
+func F(i I) {
+	i.Log("F")
+}
+
+var t testing.T
+
+func main() {
+	F(&t)
+}
diff --git a/test/fixedbugs/gcc80226.go b/test/fixedbugs/gcc80226.go
new file mode 100644
index 0000000..530b397
--- /dev/null
+++ b/test/fixedbugs/gcc80226.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2017 The Go 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 gccgo compiler crashed while compiling a function that returned
+// multiple zero-sized structs.
+// https://gcc.gnu.org/PR80226.
+
+package p
+
+type S struct{}
+
+func F() (S, S) {
+	return S{}, S{}
+}
diff --git a/test/fixedbugs/issue10607a.go b/test/fixedbugs/issue10607a.go
index 18bf1a2..51399e4 100644
--- a/test/fixedbugs/issue10607a.go
+++ b/test/fixedbugs/issue10607a.go
@@ -35,7 +35,7 @@ func main() {
 
 		d, err := s.Data()
 		if err != nil {
-			fmt.Fprintln(os.Stderr, "reading data of note section %d: %v", i, err)
+			fmt.Fprintf(os.Stderr, "reading data of note section %d: %v\n", i, err)
 			continue
 		}
 
diff --git a/test/fixedbugs/issue10958.go b/test/fixedbugs/issue10958.go
index 86d2057..2b76694 100644
--- a/test/fixedbugs/issue10958.go
+++ b/test/fixedbugs/issue10958.go
@@ -1,4 +1,4 @@
-// +build !nacl,disabled
+// +build !nacl,disabled_see_issue_18589
 // buildrun -t 10  -gcflags=-d=ssa/insert_resched_checks/on,ssa/check/on
 
 // Copyright 2016 The Go Authors. All rights reserved.
diff --git a/test/fixedbugs/issue11354.go b/test/fixedbugs/issue11354.go
new file mode 100644
index 0000000..3980e8f
--- /dev/null
+++ b/test/fixedbugs/issue11354.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2017 The Go Authors. 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 X int
+
+var foo = map[int]X{}
+
+var bar = map[int][8]X{}
+
+func main() {}
diff --git a/test/fixedbugs/issue11371.go b/test/fixedbugs/issue11371.go
new file mode 100644
index 0000000..b2d966f
--- /dev/null
+++ b/test/fixedbugs/issue11371.go
@@ -0,0 +1,17 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 11371 (cmd/compile: meaningless error message "truncated to
+// integer")
+
+package issue11371
+
+const a int = 1.1        // ERROR "constant 1.1 truncated to integer"
+const b int = 1e20       // ERROR "overflows int"
+const c int = 1 + 1e-100 // ERROR "constant truncated to integer"
+const d int = 1 - 1e-100 // ERROR "constant truncated to integer"
+const e int = 1.00000001 // ERROR "constant truncated to integer"
+const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer"
diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go
index 5e77932..8ca31bf 100644
--- a/test/fixedbugs/issue11610.go
+++ b/test/fixedbugs/issue11610.go
@@ -9,7 +9,7 @@
 
 package a
 import""  // ERROR "import path is empty"
-var?      // ERROR "illegal character U\+003F '\?'"
+var?      // ERROR "invalid character U\+003F '\?'"
 
 var x int // ERROR "unexpected var"
 
diff --git a/test/fixedbugs/issue11614.go b/test/fixedbugs/issue11614.go
index 959643a..91f134d 100644
--- a/test/fixedbugs/issue11614.go
+++ b/test/fixedbugs/issue11614.go
@@ -15,7 +15,7 @@ type I interface {
 }
 
 func n() {
-	(I) // ERROR "type I is not an expression"
+	(I)
 }
 
 func m() {
diff --git a/test/fixedbugs/issue11674.go b/test/fixedbugs/issue11674.go
new file mode 100644
index 0000000..e7d0bf2
--- /dev/null
+++ b/test/fixedbugs/issue11674.go
@@ -0,0 +1,40 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 11674: cmd/compile: does not diagnose constant division by
+// zero
+
+package p
+
+const x complex64 = 0
+const y complex128 = 0
+
+var _ = x / 1e-20
+var _ = x / 1e-50   // ERROR "complex division by zero"
+var _ = x / 1e-1000 // ERROR "complex division by zero"
+var _ = x / 1e-20i
+var _ = x / 1e-50i   // ERROR "complex division by zero"
+var _ = x / 1e-1000i // ERROR "complex division by zero"
+
+var _ = x / 1e-45 // smallest positive float32
+
+var _ = x / (1e-20 + 1e-20i)
+var _ = x / (1e-50 + 1e-20i)
+var _ = x / (1e-20 + 1e-50i)
+var _ = x / (1e-50 + 1e-50i)     // ERROR "complex division by zero"
+var _ = x / (1e-1000 + 1e-1000i) // ERROR "complex division by zero"
+
+var _ = y / 1e-50
+var _ = y / 1e-1000 // ERROR "complex division by zero"
+var _ = y / 1e-50i
+var _ = y / 1e-1000i // ERROR "complex division by zero"
+
+var _ = y / 5e-324 // smallest positive float64
+
+var _ = y / (1e-50 + 1e-50)
+var _ = y / (1e-1000 + 1e-50i)
+var _ = y / (1e-50 + 1e-1000i)
+var _ = y / (1e-1000 + 1e-1000i) // ERROR "complex division by zero"
diff --git a/test/fixedbugs/issue11945.go b/test/fixedbugs/issue11945.go
new file mode 100644
index 0000000..510b655
--- /dev/null
+++ b/test/fixedbugs/issue11945.go
@@ -0,0 +1,71 @@
+// run
+
+// Copyright 2017 The Go Authors. 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"
+
+// issue 17446
+const (
+	_ = real(0) // from bug report
+	_ = imag(0) // from bug report
+
+	// if the arguments are untyped, the results must be untyped
+	// (and compatible with types that can represent the values)
+	_ int = real(1)
+	_ int = real('a')
+	_ int = real(2.0)
+	_ int = real(3i)
+
+	_ float32 = real(1)
+	_ float32 = real('a')
+	_ float32 = real(2.1)
+	_ float32 = real(3.2i)
+
+	_ float64 = real(1)
+	_ float64 = real('a')
+	_ float64 = real(2.1)
+	_ float64 = real(3.2i)
+
+	_ int = imag(1)
+	_ int = imag('a')
+	_ int = imag(2.1 + 3i)
+	_ int = imag(3i)
+
+	_ float32 = imag(1)
+	_ float32 = imag('a')
+	_ float32 = imag(2.1 + 3.1i)
+	_ float32 = imag(3i)
+
+	_ float64 = imag(1)
+	_ float64 = imag('a')
+	_ float64 = imag(2.1 + 3.1i)
+	_ float64 = imag(3i)
+)
+
+var tests = []struct {
+	code      string
+	got, want interface{}
+}{
+	{"real(1)", real(1), 1.0},
+	{"real('a')", real('a'), float64('a')},
+	{"real(2.0)", real(2.0), 2.0},
+	{"real(3.2i)", real(3.2i), 0.0},
+
+	{"imag(1)", imag(1), 0.0},
+	{"imag('a')", imag('a'), 0.0},
+	{"imag(2.1 + 3.1i)", imag(2.1 + 3.1i), 3.1},
+	{"imag(3i)", imag(3i), 3.0},
+}
+
+func main() {
+	// verify compile-time evaluated constant expressions
+	for _, test := range tests {
+		if test.got != test.want {
+			panic(fmt.Sprintf("%s: %v (%T) != %v (%T)", test.code, test.got, test.got, test.want, test.want))
+		}
+	}
+}
diff --git a/test/fixedbugs/issue12536.go b/test/fixedbugs/issue12536.go
new file mode 100644
index 0000000..ceeaec4
--- /dev/null
+++ b/test/fixedbugs/issue12536.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2017 The Go 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 12536: compiler crashes while checking keys in a map literal for equality
+
+package p
+
+func main() {
+	m1 := map[interface{}]interface{}{
+		nil:  0,
+		true: 1,
+	}
+	m2 := map[interface{}]interface{}{
+		true: 1,
+		nil:  0,
+	}
+	println(len(m1))
+	println(len(m2))
+}
diff --git a/test/fixedbugs/issue13471.go b/test/fixedbugs/issue13471.go
index 81f034b..0bfed42 100644
--- a/test/fixedbugs/issue13471.go
+++ b/test/fixedbugs/issue13471.go
@@ -9,17 +9,17 @@
 package main
 
 func main() {
-	const _ int64 = 1e646456992 // ERROR "1e\+646456992 overflows integer"
-	const _ int32 = 1e64645699  // ERROR "1e\+64645699 overflows integer"
-	const _ int16 = 1e6464569   // ERROR "1e\+6464569 overflows integer"
-	const _ int8 = 1e646456     // ERROR "1e\+646456 overflows integer"
-	const _ int = 1e64645       // ERROR "1e\+64645 overflows integer"
+	const _ int64 = 1e646456992 // ERROR "integer too large"
+	const _ int32 = 1e64645699  // ERROR "integer too large"
+	const _ int16 = 1e6464569   // ERROR "integer too large"
+	const _ int8 = 1e646456     // ERROR "integer too large"
+	const _ int = 1e64645       // ERROR "integer too large"
 
-	const _ uint64 = 1e646456992 // ERROR "1e\+646456992 overflows integer"
-	const _ uint32 = 1e64645699  // ERROR "1e\+64645699 overflows integer"
-	const _ uint16 = 1e6464569   // ERROR "1e\+6464569 overflows integer"
-	const _ uint8 = 1e646456     // ERROR "1e\+646456 overflows integer"
-	const _ uint = 1e64645       // ERROR "1e\+64645 overflows integer"
+	const _ uint64 = 1e646456992 // ERROR "integer too large"
+	const _ uint32 = 1e64645699  // ERROR "integer too large"
+	const _ uint16 = 1e6464569   // ERROR "integer too large"
+	const _ uint8 = 1e646456     // ERROR "integer too large"
+	const _ uint = 1e64645       // ERROR "integer too large"
 
-	const _ rune = 1e64645 // ERROR "1e\+64645 overflows integer"
+	const _ rune = 1e64645 // ERROR "integer too large"
 }
diff --git a/test/fixedbugs/issue13559.go b/test/fixedbugs/issue13559.go
index 4783c62..16de2a2 100644
--- a/test/fixedbugs/issue13559.go
+++ b/test/fixedbugs/issue13559.go
@@ -13,11 +13,11 @@ package p
 const _ int64 = 1e-10000 // ERROR "1e\-10000 truncated"
 
 const (
-	_ int64 = 1e10000000 // ERROR "1e\+10000000 overflows"
-	_ int64 = 1e1000000  // ERROR "1e\+1000000 overflows"
-	_ int64 = 1e100000   // ERROR "1e\+100000 overflows"
-	_ int64 = 1e10000    // ERROR "1e\+10000 overflows"
-	_ int64 = 1e1000     // ERROR "1e\+1000 overflows"
+	_ int64 = 1e10000000 // ERROR "integer too large"
+	_ int64 = 1e1000000  // ERROR "integer too large"
+	_ int64 = 1e100000   // ERROR "integer too large"
+	_ int64 = 1e10000    // ERROR "integer too large"
+	_ int64 = 1e1000     // ERROR "integer too large"
 	_ int64 = 1e100      // ERROR "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
 	_ int64 = 1e10
 	_ int64 = 1e1
@@ -32,11 +32,11 @@ const (
 )
 
 const (
-	_ int64 = -1e10000000 // ERROR "\-1e\+10000000 overflows"
-	_ int64 = -1e1000000  // ERROR "\-1e\+1000000 overflows"
-	_ int64 = -1e100000   // ERROR "\-1e\+100000 overflows"
-	_ int64 = -1e10000    // ERROR "\-1e\+10000 overflows"
-	_ int64 = -1e1000     // ERROR "\-1e\+1000 overflows"
+	_ int64 = -1e10000000 // ERROR "integer too large"
+	_ int64 = -1e1000000  // ERROR "integer too large"
+	_ int64 = -1e100000   // ERROR "integer too large"
+	_ int64 = -1e10000    // ERROR "integer too large"
+	_ int64 = -1e1000     // ERROR "integer too large"
 	_ int64 = -1e100      // ERROR "\-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
 	_ int64 = -1e10
 	_ int64 = -1e1
@@ -51,11 +51,11 @@ const (
 )
 
 const (
-	_ int64 = 1.23456789e10000000 // ERROR "1\.23457e\+10000000 overflows"
-	_ int64 = 1.23456789e1000000  // ERROR "1\.23457e\+1000000 overflows"
-	_ int64 = 1.23456789e100000   // ERROR "1\.23457e\+100000 overflows"
-	_ int64 = 1.23456789e10000    // ERROR "1\.23457e\+10000 overflows"
-	_ int64 = 1.23456789e1000     // ERROR "1\.23457e\+1000 overflows"
+	_ int64 = 1.23456789e10000000 // ERROR "integer too large"
+	_ int64 = 1.23456789e1000000  // ERROR "integer too large"
+	_ int64 = 1.23456789e100000   // ERROR "integer too large"
+	_ int64 = 1.23456789e10000    // ERROR "integer too large"
+	_ int64 = 1.23456789e1000     // ERROR "integer too large"
 	_ int64 = 1.23456789e100      // ERROR "12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
 	_ int64 = 1.23456789e10
 	_ int64 = 1.23456789e1        // ERROR "12\.3457 truncated"
@@ -70,11 +70,11 @@ const (
 )
 
 const (
-	_ int64 = -1.23456789e10000000 // ERROR "\-1\.23457e\+10000000 overflows"
-	_ int64 = -1.23456789e1000000  // ERROR "\-1\.23457e\+1000000 overflows"
-	_ int64 = -1.23456789e100000   // ERROR "\-1\.23457e\+100000 overflows"
-	_ int64 = -1.23456789e10000    // ERROR "\-1\.23457e\+10000 overflows"
-	_ int64 = -1.23456789e1000     // ERROR "\-1\.23457e\+1000 overflows"
+	_ int64 = -1.23456789e10000000 // ERROR "integer too large"
+	_ int64 = -1.23456789e1000000  // ERROR "integer too large"
+	_ int64 = -1.23456789e100000   // ERROR "integer too large"
+	_ int64 = -1.23456789e10000    // ERROR "integer too large"
+	_ int64 = -1.23456789e1000     // ERROR "integer too large"
 	_ int64 = -1.23456789e100      // ERROR "\-12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
 	_ int64 = -1.23456789e10
 	_ int64 = -1.23456789e1        // ERROR "\-12\.3457 truncated"
diff --git a/test/fixedbugs/issue14006.go b/test/fixedbugs/issue14006.go
index c3c56b1..d69bdd4 100644
--- a/test/fixedbugs/issue14006.go
+++ b/test/fixedbugs/issue14006.go
@@ -53,12 +53,12 @@ func f() {
 
 	switch {
 	case z:
-		labelname:
+		labelname:	// ERROR "label labelname defined and not used"
 	}
 
 	switch {
 	case z:
-		labelname: ;
+		labelname: ;	// ERROR "label labelname already defined at LINE-5"
 	case false:
 	}
 }
\ No newline at end of file
diff --git a/test/fixedbugs/issue14010.go b/test/fixedbugs/issue14010.go
index f5cab41..2786e10 100644
--- a/test/fixedbugs/issue14010.go
+++ b/test/fixedbugs/issue14010.go
@@ -11,5 +11,5 @@ package main
 
 func main() {
 	true = false // ERROR "cannot assign to true"
-	byte = 0     // ERROR "not an expression" "cannot assign to byte"
+	byte = 0     // ERROR "not an expression"
 }
diff --git a/test/fixedbugs/issue14520.go b/test/fixedbugs/issue14520.go
index 1b1f4de..84d240f 100644
--- a/test/fixedbugs/issue14520.go
+++ b/test/fixedbugs/issue14520.go
@@ -9,6 +9,6 @@ package f
 import /* // ERROR "import path" */ `
 bogus`
 
-func f(x int /* // ERROR "unexpected semicolon"
+func f(x int /* // ERROR "unexpected newline"
 
 */)
diff --git a/test/fixedbugs/issue15055.go b/test/fixedbugs/issue15055.go
new file mode 100644
index 0000000..e58047e
--- /dev/null
+++ b/test/fixedbugs/issue15055.go
@@ -0,0 +1,17 @@
+// 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 main() {
+	type name string
+	_ = []byte("abc", "def", 12)    // ERROR "too many arguments to conversion to \[\]byte: \(\[\]byte\)\(.abc., .def., 12\)"
+	_ = string("a", "b", nil)       // ERROR "too many arguments to conversion to string: string\(.a., .b., nil\)"
+	_ = []byte()                    // ERROR "missing argument to conversion to \[\]byte: \(\[\]byte\)\(\)"
+	_ = string()                    // ERROR "missing argument to conversion to string: string\(\)"
+	_ = name("a", 1, 3.3)           // ERROR "too many arguments to conversion to name: name\(.a., 1, 3.3\)"
+	_ = map[string]string(nil, nil) // ERROR "too many arguments to conversion to map\[string\]string: \(map\[string\]string\)\(nil, nil\)"
+}
diff --git a/test/fixedbugs/issue15550.go b/test/fixedbugs/issue15550.go
new file mode 100644
index 0000000..f2853fc
--- /dev/null
+++ b/test/fixedbugs/issue15550.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2017 The Go Authors. 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 "unsafe"
+
+const (
+	_ = unsafe.Sizeof(func() int {
+		const (
+			_ = 1
+			_
+			_
+		)
+		return 0
+	}())
+
+	y = iota
+)
+
+func main() {
+	if y != 1 {
+		panic(y)
+	}
+}
diff --git a/test/fixedbugs/issue15611.go b/test/fixedbugs/issue15611.go
new file mode 100644
index 0000000..6a627d9
--- /dev/null
+++ b/test/fixedbugs/issue15611.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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
+
+// These error messages are for the invalid literals on lines 19 and 20:
+
+// ERROR "newline in character literal"
+// ERROR "invalid character literal \(missing closing '\)"
+
+const (
+	_ = ''     // ERROR "empty character literal or unescaped ' in character literal"
+	_ = 'f'
+	_ = 'foo'  // ERROR "invalid character literal \(more than one character\)"
+//line issue15611.go:11
+	_ = '
+	_ = '
\ No newline at end of file
diff --git a/test/fixedbugs/issue16369.go b/test/fixedbugs/issue16369.go
index bd03fbc..e97f4a0 100644
--- a/test/fixedbugs/issue16369.go
+++ b/test/fixedbugs/issue16369.go
@@ -1,4 +1,4 @@
-// errorcheck
+// compile
 
 // Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -9,5 +9,5 @@ package p
 type T interface {
 	M(interface {
 		T
-	}) // ERROR "cannot export unnamed recursive interface"
+	})
 }
diff --git a/test/fixedbugs/issue16439.go b/test/fixedbugs/issue16439.go
index d321b60..f9382ba 100644
--- a/test/fixedbugs/issue16439.go
+++ b/test/fixedbugs/issue16439.go
@@ -13,6 +13,6 @@ var c []int = []int{2.0: 2}
 var d []int = []int{-2.0: 2} // ERROR "must be non-negative integer constant"
 
 var e []int = []int{3 + 0i: 3}
-var f []int = []int{3i: 3} // ERROR "truncated to real"
+var f []int = []int{3i: 3} // ERROR "truncated to integer"
 
 var g []int = []int{"a": 4} // ERROR "must be non-negative integer constant"
diff --git a/test/fixedbugs/issue17328.go b/test/fixedbugs/issue17328.go
new file mode 100644
index 0000000..abe4daa
--- /dev/null
+++ b/test/fixedbugs/issue17328.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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() {
+	i := 0
+	for ; ; i++) { // ERROR "unexpected \), expecting { after for clause"
+	}
+}
diff --git a/test/fixedbugs/issue18089.go b/test/fixedbugs/issue18089.go
new file mode 100644
index 0000000..fe5c1d4
--- /dev/null
+++ b/test/fixedbugs/issue18089.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package foo
+
+type T struct {
+	x int
+	_ int
+}
+
+func main() {
+	_ = T{0, 0}
+
+	x := T{1, 1}
+	_ = x
+}
diff --git a/test/fixedbugs/issue18231.go b/test/fixedbugs/issue18231.go
new file mode 100644
index 0000000..adfd227
--- /dev/null
+++ b/test/fixedbugs/issue18231.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 error message for composite literals with
+// missing type is at the right place.
+
+package p
+
+type T struct {
+	f map[string]string
+}
+
+var _ = T{
+	f: {                // ERROR "missing type in composite literal"
+		"a": "b",
+	},
+}
diff --git a/test/fixedbugs/issue18331.go b/test/fixedbugs/issue18331.go
new file mode 100644
index 0000000..a527bce
--- /dev/null
+++ b/test/fixedbugs/issue18331.go
@@ -0,0 +1,20 @@
+// errorcheck -std
+// Copyright 2017 The Go 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 18331: We should catch invalid pragma verbs
+// for code that resides in the standard library.
+package issue18331
+
+//go:unknown // ERROR "//go:unknown is not allowed in the standard library"
+func foo()
+
+//go:nowritebarrierc // ERROR "//go:nowritebarrierc is not allowed in the standard library"
+func bar()
+
+//go:noesape // ERROR "//go:noesape is not allowed in the standard library"
+func groot()
+
+//go:noescape
+func hey() { // ERROR "can only use //go:noescape with external func implementations"
+}
diff --git a/test/fixedbugs/issue18392.go b/test/fixedbugs/issue18392.go
index ad64238..053a337 100644
--- a/test/fixedbugs/issue18392.go
+++ b/test/fixedbugs/issue18392.go
@@ -7,5 +7,8 @@
 package p
 
 type A interface {
-	Fn(A.Fn) // ERROR "type A has no method A.Fn"
+	// TODO(mdempsky): This should be an error, but this error is
+	// nonsense. The error should actually mention that there's a
+	// type loop.
+	Fn(A.Fn) // ERROR "type A has no method Fn"
 }
diff --git a/test/fixedbugs/issue18393.go b/test/fixedbugs/issue18393.go
new file mode 100644
index 0000000..c16ff4d
--- /dev/null
+++ b/test/fixedbugs/issue18393.go
@@ -0,0 +1,24 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 compiler directives are ignored if they
+// don't start at the beginning of the line.
+
+package p
+
+//line issue18393.go:20
+import 42 // error on line 20
+
+
+/* //line not at start of line: ignored */ //line issue18393.go:30
+var x     // error on line 24, not 30
+
+
+// ERROR "import path must be a string"
+
+
+
+// ERROR "syntax error: unexpected newline, expecting type"
diff --git a/test/fixedbugs/issue18419.dir/other.go b/test/fixedbugs/issue18419.dir/other.go
new file mode 100644
index 0000000..27243d2
--- /dev/null
+++ b/test/fixedbugs/issue18419.dir/other.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package other
+
+type Exported struct {
+	Member int
+}
+
+func (e *Exported) member() int { return 1 }
diff --git a/test/fixedbugs/issue18419.dir/test.go b/test/fixedbugs/issue18419.dir/test.go
new file mode 100644
index 0000000..31c6025
--- /dev/null
+++ b/test/fixedbugs/issue18419.dir/test.go
@@ -0,0 +1,15 @@
+// errorcheck -0 -m -l
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./other"
+
+func InMyCode(e *other.Exported) {
+	e.member() // ERROR "e\.member undefined .cannot refer to unexported field or method other\.\(\*Exported\)\.member."
+}
+
+func main() {}
diff --git a/test/fixedbugs/issue18419.go b/test/fixedbugs/issue18419.go
new file mode 100644
index 0000000..25544ef
--- /dev/null
+++ b/test/fixedbugs/issue18419.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/fixedbugs/issue18459.go b/test/fixedbugs/issue18459.go
index ac07661..46601e7 100644
--- a/test/fixedbugs/issue18459.go
+++ b/test/fixedbugs/issue18459.go
@@ -8,6 +8,6 @@
 
 package main
 
-//go:nowritebarrier // ERROR "go:nowritebarrier only allowed in runtime"
+//go:nowritebarrier // ERROR "//go:nowritebarrier only allowed in runtime"
 func main() {
 }
diff --git a/test/fixedbugs/issue18595.go b/test/fixedbugs/issue18595.go
new file mode 100644
index 0000000..d6f07b3
--- /dev/null
+++ b/test/fixedbugs/issue18595.go
@@ -0,0 +1,53 @@
+// run
+
+// Copyright 2017 The Go 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 itabs are unique.
+// More explicitly, we require that only one itab structure exists for the pair of
+// a given compile-time interface type and underlying concrete type.
+// Ensuring this invariant enables fixes for 18492 (improve type switch code).
+
+package main
+
+type I interface {
+	M()
+}
+type J interface {
+	M()
+}
+
+type T struct{}
+
+func (*T) M() {}
+
+func main() {
+	test1()
+	test2()
+}
+
+func test1() {
+	t := new(T)
+	var i1, i2 I
+	var j interface {
+		M()
+	}
+	i1 = t
+	j = t
+	i2 = j
+	if i1 != i2 {
+		panic("interfaces not equal")
+	}
+}
+
+func test2() {
+	t := new(T)
+	i1 := (I)(t)
+	i2 := (I)((interface {
+		M()
+	})((J)(t)))
+	if i1 != i2 {
+		panic("interfaces not equal")
+	}
+}
diff --git a/test/fixedbugs/issue18636.go b/test/fixedbugs/issue18636.go
new file mode 100644
index 0000000..2704fc4
--- /dev/null
+++ b/test/fixedbugs/issue18636.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2017 The Go Authors. 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/debug"
+
+type Foo struct {
+	A [1 << 20]byte
+	B string
+}
+
+func run(c chan bool) {
+	f := new(Foo)
+	*f = Foo{B: "hello"}
+	c <- true
+}
+
+func main() {
+	debug.SetMaxStack(1 << 16)
+	c := make(chan bool)
+	go run(c)
+	<-c
+}
diff --git a/test/fixedbugs/issue18640.go b/test/fixedbugs/issue18640.go
new file mode 100644
index 0000000..c4f948b
--- /dev/null
+++ b/test/fixedbugs/issue18640.go
@@ -0,0 +1,26 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type (
+	a = b
+	b struct {
+		*a
+	}
+
+	c struct {
+		*d
+	}
+	d = c
+
+	e = f
+	f = g
+	g = []h
+	h i
+	i = j
+	j = e
+)
diff --git a/test/fixedbugs/issue18655.go b/test/fixedbugs/issue18655.go
new file mode 100644
index 0000000..abc2600
--- /dev/null
+++ b/test/fixedbugs/issue18655.go
@@ -0,0 +1,22 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct{}
+type A = T
+type B = T
+
+func (T) m() {}
+func (T) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+
+func (*T) m() {} // ERROR "redeclared"
+func (*A) m() {} // ERROR "redeclared"
+func (*B) m() {} // ERROR "redeclared"
diff --git a/test/fixedbugs/issue18661.go b/test/fixedbugs/issue18661.go
index 8c83775..e64a771 100644
--- a/test/fixedbugs/issue18661.go
+++ b/test/fixedbugs/issue18661.go
@@ -1,10 +1,15 @@
-// compile
+// run
 
 // Copyright 2017 The Go Authors. 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
+package main
+
+import (
+	"fmt"
+	"os"
+)
 
 var (
 	e interface{}
@@ -16,3 +21,19 @@ func test(obj interface{}) {
 	if obj != struct{ a *string }{} {
 	}
 }
+
+var x int
+
+func f() [2]string {
+	x++
+	return [2]string{"abc", "def"}
+}
+
+func main() {
+	var e interface{} = [2]string{"abc", "def"}
+	_ = e == f()
+	if x != 1 {
+		fmt.Println("x=", x)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/issue18747.go b/test/fixedbugs/issue18747.go
new file mode 100644
index 0000000..fb8331f
--- /dev/null
+++ b/test/fixedbugs/issue18747.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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 _ () {
+	if {} // ERROR "missing condition in if statement"
+
+	if
+	{} // ERROR "missing condition in if statement"
+
+	if ; {} // ERROR "missing condition in if statement"
+
+	if foo; {} // ERROR "missing condition in if statement"
+
+	if foo; // ERROR "missing condition in if statement"
+	{}
+
+	if foo {}
+
+	if ; foo {}
+
+	if foo // ERROR "unexpected newline, expecting { after if clause"
+	{}
+}
diff --git a/test/fixedbugs/issue18882.go b/test/fixedbugs/issue18882.go
new file mode 100644
index 0000000..9c3658d
--- /dev/null
+++ b/test/fixedbugs/issue18882.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 we have a line number for this error.
+
+package main
+
+//go:cgo_ldflag // ERROR "usage: //go:cgo_ldflag"
+func main() {
+}
diff --git a/test/fixedbugs/issue18902.go b/test/fixedbugs/issue18902.go
new file mode 100644
index 0000000..f5bca16
--- /dev/null
+++ b/test/fixedbugs/issue18902.go
@@ -0,0 +1,137 @@
+// run
+// +build !nacl
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Runs a build -S to capture the assembly language
+// output, checks that the line numbers associated with
+// the stream of instructions do not change "too much".
+// The changes that fixes this (that reduces the amount
+// of change) does so by treating register spill, reload,
+// copy, and rematerializations as being "unimportant" and
+// just assigns them the line numbers of whatever "real"
+// instructions preceded them.
+
+// nacl is excluded because this runs a compiler.
+
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+// updateEnv modifies env to ensure that key=val
+func updateEnv(env *[]string, key, val string) {
+	if val != "" {
+		var found bool
+		key = key + "="
+		for i, kv := range *env {
+			if strings.HasPrefix(kv, key) {
+				(*env)[i] = key + val
+				found = true
+				break
+			}
+		}
+		if !found {
+			*env = append(*env, key+val)
+		}
+	}
+}
+
+func main() {
+	testarch := os.Getenv("TESTARCH")     // Targets other platform in test compilation.
+	debug := os.Getenv("TESTDEBUG") != "" // Output the relevant assembly language.
+
+	cmd := exec.Command("go", "build", "-gcflags", "-S", "fixedbugs/issue18902b.go")
+	var buf bytes.Buffer
+	cmd.Stdout = &buf
+	cmd.Stderr = &buf
+	cmd.Env = os.Environ()
+
+	updateEnv(&cmd.Env, "GOARCH", testarch)
+
+	err := cmd.Run()
+	if err != nil {
+		fmt.Printf("%s\n%s", err, buf.Bytes())
+		return
+	}
+	begin := "\"\".(*gcSortBuf).flush" // Text at beginning of relevant dissassembly.
+	s := buf.String()
+	i := strings.Index(s, begin)
+	if i < 0 {
+		fmt.Printf("Failed to find expected symbol %s in output\n%s\n", begin, s)
+		return
+	}
+	s = s[i:]
+	r := strings.NewReader(s)
+	scanner := bufio.NewScanner(r)
+	first := true                         // The first line after the begin text will be skipped
+	beforeLineNumber := "issue18902b.go:" // Text preceding line number in each line.
+	lbln := len(beforeLineNumber)
+
+	var scannedCount, changes, sumdiffs float64
+
+	prevVal := 0
+	for scanner.Scan() {
+		line := scanner.Text()
+		if first {
+			first = false
+			continue
+		}
+		i = strings.Index(line, beforeLineNumber)
+		if i < 0 {
+			// Done reading lines
+			if scannedCount < 200 { // When test was written, 251 lines observed on amd64
+				fmt.Printf("Scanned only %d lines, was expecting more than 200", scannedCount)
+				return
+			}
+			// Note: when test was written, before changes=92, after=50 (was 62 w/o rematerialization NoXPos in *Value.copyInto())
+			// and before sumdiffs=784, after=180 (was 446 w/o rematerialization NoXPos in *Value.copyInto())
+			// Set the dividing line between pass and fail at the midpoint.
+			// Normalize against instruction count in case we unroll loops, etc.
+			if changes/scannedCount >= (50+92)/(2*scannedCount) || sumdiffs/scannedCount >= (180+784)/(2*scannedCount) {
+				fmt.Printf("Line numbers change too much, # of changes=%.f, sumdiffs=%.f, # of instructions=%.f\n", changes, sumdiffs, scannedCount)
+			}
+			return
+		}
+		scannedCount++
+		i += lbln
+		lineVal, err := strconv.Atoi(line[i : i+3])
+		if err != nil {
+			fmt.Printf("Expected 3-digit line number after %s in %s\n", beforeLineNumber, line)
+		}
+		if prevVal == 0 {
+			prevVal = lineVal
+		}
+		diff := lineVal - prevVal
+		if diff < 0 {
+			diff = -diff
+		}
+		if diff != 0 {
+			changes++
+			sumdiffs += float64(diff)
+		}
+		// If things change too much, set environment variable TESTDEBUG to help figure out what's up.
+		// The "before" behavior can be recreated in DebugFriendlySetPosFrom (currently in gc/ssa.go)
+		// by inserting unconditional
+		//   	s.SetPos(v.Pos)
+		// at the top of the function.
+
+		if debug {
+			fmt.Printf("%d %.f %.f %s\n", lineVal, changes, sumdiffs, line)
+		}
+		prevVal = lineVal
+	}
+	if err := scanner.Err(); err != nil {
+		fmt.Println("Reading standard input:", err)
+		return
+	}
+}
diff --git a/test/fixedbugs/issue18902b.go b/test/fixedbugs/issue18902b.go
new file mode 100644
index 0000000..2e43e9f
--- /dev/null
+++ b/test/fixedbugs/issue18902b.go
@@ -0,0 +1,161 @@
+// skip
+
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"unsafe"
+)
+
+type gcMaxTreeNodeVal uint64
+
+var work struct {
+	full         uint64    // lock-free list of full blocks workbuf
+	empty        uint64    // lock-free list of empty blocks workbuf
+	pad0         [64]uint8 // prevents false-sharing between full/empty and nproc/nwait
+	bytesMarked  uint64
+	markrootNext uint32 // next markroot job
+	markrootJobs uint32 // number of markroot jobs
+	nproc        uint32
+	tstart       int64
+	nwait        uint32
+	ndone        uint32
+}
+
+type gcShardQueue1 struct {
+	partial *workbuf
+	full    *workbuf
+	n       uintptr
+	maxTree gcMaxTreeNodeVal
+}
+type gcShardQueue struct {
+	gcShardQueue1
+	pad [64 - unsafe.Sizeof(gcShardQueue1{})]byte
+}
+
+const gcSortBufPointers = (64 << 10) / 8
+
+type gcSortBuf struct {
+	buf *gcSortArray
+	tmp *gcSortArray
+	n   uintptr
+}
+
+//go:notinheap
+type gcSortArray [gcSortBufPointers]uintptr
+
+const (
+	_DebugGC             = 0
+	_ConcurrentSweep     = true
+	_FinBlockSize        = 4 * 1024
+	sweepMinHeapDistance = 1024 * 1024
+	gcShardShift         = 2 + 20
+	gcShardBytes         = 1 << gcShardShift
+)
+
+//go:notinheap
+type mheap struct {
+	shardQueues       []gcShardQueue
+	_                 uint32     // align uint64 fields on 32-bit for atomics
+	pagesInUse        uint64     // pages of spans in stats _MSpanInUse; R/W with mheap.lock
+	spanBytesAlloc    uint64     // bytes of spans allocated this cycle; updated atomically
+	pagesSwept        uint64     // pages swept this cycle; updated atomically
+	sweepPagesPerByte float64    // proportional sweep ratio; written with lock, read without
+	largefree         uint64     // bytes freed for large objects (>maxsmallsize)
+	nlargefree        uint64     // number of frees for large objects (>maxsmallsize)
+	nsmallfree        [67]uint64 // number of frees for small objects (<=maxsmallsize)
+	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
+	arena_end         uintptr
+	arena_reserved    bool
+}
+
+var mheap_ mheap
+
+type lfnode struct {
+	next    uint64
+	pushcnt uintptr
+}
+type workbufhdr struct {
+	node lfnode // must be first
+	next *workbuf
+	nobj int
+}
+
+//go:notinheap
+type workbuf struct {
+	workbufhdr
+	obj [(2048 - unsafe.Sizeof(workbufhdr{})) / 8]uintptr
+}
+
+//go:noinline
+func (b *workbuf) checkempty() {
+	if b.nobj != 0 {
+		b.nobj = 0
+	}
+}
+func putempty(b *workbuf) {
+	b.checkempty()
+	lfstackpush(&work.empty, &b.node)
+}
+
+//go:noinline
+func lfstackpush(head *uint64, node *lfnode) {
+}
+
+//go:noinline
+func (q *gcShardQueue) add(qidx uintptr, ptrs []uintptr, spare *workbuf) *workbuf {
+	return spare
+}
+
+func (b *gcSortBuf) flush() {
+	if b.n == 0 {
+		return
+	}
+	const sortDigitBits = 11
+	buf, tmp := b.buf[:b.n], b.tmp[:b.n]
+	moreBits := true
+	for shift := uint(gcShardShift); moreBits; shift += sortDigitBits {
+		const k = 1 << sortDigitBits
+		var pos [k]uint16
+		nshift := shift + sortDigitBits
+		nbits := buf[0] >> nshift
+		moreBits = false
+		for _, v := range buf {
+			pos[(v>>shift)%k]++
+			moreBits = moreBits || v>>nshift != nbits
+		}
+		var sum uint16
+		for i, count := range &pos {
+			pos[i] = sum
+			sum += count
+		}
+		for _, v := range buf {
+			digit := (v >> shift) % k
+			tmp[pos[digit]] = v
+			pos[digit]++
+		}
+		buf, tmp = tmp, buf
+	}
+	start := mheap_.arena_start
+	i0 := 0
+	shard0 := (buf[0] - start) / gcShardBytes
+	var spare *workbuf
+	for i, p := range buf {
+		shard := (p - start) / gcShardBytes
+		if shard != shard0 {
+			spare = mheap_.shardQueues[shard0].add(shard0, buf[i0:i], spare)
+			i0, shard0 = i, shard
+		}
+	}
+	spare = mheap_.shardQueues[shard0].add(shard0, buf[i0:], spare)
+	b.n = 0
+	if spare != nil {
+		putempty(spare)
+	}
+}
diff --git a/test/fixedbugs/issue18994.go b/test/fixedbugs/issue18994.go
new file mode 100644
index 0000000..aa30713
--- /dev/null
+++ b/test/fixedbugs/issue18994.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2017 The Go 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 18994: SSA didn't handle DOT STRUCTLIT for zero-valued
+// STRUCTLIT.
+
+package main
+
+// large struct - not SSA-able
+type T struct {
+	a, b, c, d, e, f, g, h int
+}
+
+func main() {
+	x := T{}.a
+	if x != 0 {
+		panic("FAIL")
+	}
+}
diff --git a/test/fixedbugs/issue19012.go b/test/fixedbugs/issue19012.go
new file mode 100644
index 0000000..636bf06
--- /dev/null
+++ b/test/fixedbugs/issue19012.go
@@ -0,0 +1,25 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 19012: if we have any unknown type at a call site,
+// we must ensure that we return to the user a suppressed
+// error message saying instead of including <T> in
+// the message.
+
+package main
+
+func f(x int, y uint) {
+	if true {
+		return "a" > 10 // ERROR "^too many arguments to return$" "."
+	}
+	return "gopher" == true, 10 // ERROR "^too many arguments to return$" "."
+}
+
+func main() {
+	f(2, 3 < "x", 10) // ERROR "^too many arguments in call to f$" "."
+
+	f(10, 10, "a") // ERROR "too many arguments in call to f\n\thave \(number, number, string\)\n\twant \(int, uint\)"
+}
diff --git a/test/fixedbugs/issue19040.go b/test/fixedbugs/issue19040.go
new file mode 100644
index 0000000..67881df
--- /dev/null
+++ b/test/fixedbugs/issue19040.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2017 The Go 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 text of the panic that comes from
+// a nil pointer passed to automatically generated method wrapper.
+
+package main
+
+import "fmt"
+
+type T int
+
+type I interface {
+	F()
+}
+
+func (t T) F() {}
+
+var (
+	t *T
+	i I = t
+)
+
+func main() {
+	defer func() {
+		got := recover().(error).Error()
+		want := "value method main.T.F called using nil *T pointer"
+		if got != want {
+			fmt.Printf("panicwrap error text:\n\t%q\nwant:\n\t%q\n", got, want)
+		}
+	}()
+	i.F()
+}
diff --git a/test/fixedbugs/issue19056.go b/test/fixedbugs/issue19056.go
new file mode 100644
index 0000000..e4e8d07
--- /dev/null
+++ b/test/fixedbugs/issue19056.go
@@ -0,0 +1,9 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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 _ = ... . // ERROR "unexpected ..."
diff --git a/test/fixedbugs/issue19078.go b/test/fixedbugs/issue19078.go
new file mode 100644
index 0000000..b19e874
--- /dev/null
+++ b/test/fixedbugs/issue19078.go
@@ -0,0 +1,42 @@
+// run
+
+// Copyright 2017 The Go 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 19078: liveness & zero-initialization of results
+// when there is a defer.
+package main
+
+import "unsafe"
+
+func main() {
+	// Construct an invalid pointer.  We do this by
+	// making a pointer which points to the unused space
+	// between the last 48-byte object in a span and the
+	// end of the span (there are 32 unused bytes there).
+	p := new([48]byte)              // make a 48-byte object
+	sink = &p                       // escape it, so it allocates for real
+	u := uintptr(unsafe.Pointer(p)) // get its address
+	u = u >> 13 << 13               // round down to page size
+	u += 1<<13 - 1                  // add almost a page
+
+	for i := 0; i < 1000000; i++ {
+		_ = identity(u)         // installs u at return slot
+		_ = liveReturnSlot(nil) // incorrectly marks return slot as live
+	}
+}
+
+//go:noinline
+func liveReturnSlot(x *int) *int {
+	defer func() {}() // causes return slot to be marked live
+	sink = &x         // causes x to be moved to the heap, triggering allocation
+	return x
+}
+
+//go:noinline
+func identity(x uintptr) uintptr {
+	return x
+}
+
+var sink interface{}
diff --git a/test/fixedbugs/issue19084.go b/test/fixedbugs/issue19084.go
new file mode 100644
index 0000000..ba53063
--- /dev/null
+++ b/test/fixedbugs/issue19084.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2017 The Go 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 19084: SSA doesn't handle CONVNOP STRUCTLIT
+
+package p
+
+type T struct {
+	a, b, c, d, e, f, g, h int // big, not SSA-able
+}
+
+func f() {
+	_ = T(T{})
+}
diff --git a/test/fixedbugs/issue19246.go b/test/fixedbugs/issue19246.go
new file mode 100644
index 0000000..3ece2a1
--- /dev/null
+++ b/test/fixedbugs/issue19246.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2017 The Go 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 19246: Failed to evaluate some zero-sized values
+// when converting them to interfaces.
+
+package main
+
+import "os"
+
+type B struct{}
+
+//go:noinline
+func f(i interface{}) {}
+
+func main() {
+	defer func() {
+		if recover() == nil {
+			println("expected nil pointer dereference panic")
+			os.Exit(1)
+		}
+	}()
+	var b *B
+	f(*b)
+}
diff --git a/test/fixedbugs/issue19275.go b/test/fixedbugs/issue19275.go
new file mode 100644
index 0000000..f7e64fc
--- /dev/null
+++ b/test/fixedbugs/issue19275.go
@@ -0,0 +1,72 @@
+// run
+
+// Copyright 2017 The Go Authors. 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"
+)
+
+type PI struct {
+	Enabled bool
+}
+
+type SI struct {
+	M map[string]*PI
+}
+
+//go:noinline
+func (s *SI) test(name string) (*int, error) {
+	n := new(int)
+	*n = 99
+	if err := addUpdate(n, s.M[name].Enabled, "enabled"); err != nil { // this was miscompiled
+		return nil, fmt.Errorf(" error adding update for enable flag %t : %s",
+			s.M[name].Enabled, err)
+	}
+	return n, nil
+}
+
+//go:noinline
+func addUpdate(n *int, in interface{}, s ...string) error {
+	if *n != 99 {
+		println("FAIL, *n should be 99, not", *n)
+	}
+	return nil
+}
+
+func main1() {
+	s := &SI{make(map[string]*PI)}
+	s.M["dog"] = &PI{}
+	s.test("dog")
+}
+
+//go:noinline
+func g(b *byte, i interface{}) error {
+	if *b != 17 {
+		println("FAIL, *b should be 17, not", *b)
+	}
+	return nil
+}
+
+//go:noinline
+func f(x *byte, m map[string]*bool) {
+	if err := g(x, *m["hello"]); err != nil { // this was miscompiled
+		return
+	}
+}
+
+func main2() {
+	m := make(map[string]*bool)
+	x := false
+	m["hello"] = &x
+	b := byte(17)
+	f(&b, m)
+}
+
+func main() {
+	main2()
+	main1()
+}
diff --git a/test/fixedbugs/issue19359.go b/test/fixedbugs/issue19359.go
new file mode 100644
index 0000000..4717d13
--- /dev/null
+++ b/test/fixedbugs/issue19359.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2017 The Go Authors. 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 set(m map[interface{}]interface{}, key interface{}) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("set failed: %v", r)
+		}
+	}()
+	m[key] = nil
+	return nil
+}
+
+func del(m map[interface{}]interface{}, key interface{}) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("del failed: %v", r)
+		}
+	}()
+	delete(m, key)
+	return nil
+}
+
+func main() {
+	m := make(map[interface{}]interface{})
+	set(m, []int{1, 2, 3})
+	set(m, "abc") // used to throw
+	del(m, []int{1, 2, 3})
+	del(m, "abc") // used to throw
+}
diff --git a/test/fixedbugs/issue19467.dir/mysync.go b/test/fixedbugs/issue19467.dir/mysync.go
new file mode 100644
index 0000000..d0e6fe0
--- /dev/null
+++ b/test/fixedbugs/issue19467.dir/mysync.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mysync
+
+import "runtime"
+
+type WaitGroup struct {
+	Callers []uintptr
+}
+
+func (wg *WaitGroup) Add(x int) {
+	wg.Callers = make([]uintptr, 32)
+	n := runtime.Callers(1, wg.Callers)
+	wg.Callers = wg.Callers[:n]
+}
+
+func (wg *WaitGroup) Done() {
+	wg.Add(-1)
+}
diff --git a/test/fixedbugs/issue19467.dir/z.go b/test/fixedbugs/issue19467.dir/z.go
new file mode 100644
index 0000000..d381103
--- /dev/null
+++ b/test/fixedbugs/issue19467.dir/z.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. 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 (
+	"./mysync"
+	"log"
+	"runtime"
+)
+
+func main() {
+	var wg mysync.WaitGroup
+	wg.Done()
+	ci := runtime.CallersFrames(wg.Callers)
+	frames := make([]runtime.Frame, 0, 4)
+	for {
+		frame, more := ci.Next()
+		frames = append(frames, frame)
+		if !more {
+			break
+		}
+	}
+	expecting := []string{
+		"mysync.(*WaitGroup).Add",
+		"mysync.(*WaitGroup).Done",
+	}
+	for i := 0; i < 2; i++ {
+		if frames[i].Function != expecting[i] {
+			log.Fatalf("frame %d: got %s, want %s", i, frames[i].Function, expecting[i])
+		}
+	}
+}
diff --git a/test/fixedbugs/issue19467.go b/test/fixedbugs/issue19467.go
new file mode 100644
index 0000000..4212157
--- /dev/null
+++ b/test/fixedbugs/issue19467.go
@@ -0,0 +1,7 @@
+// rundir -l=4
+
+// Copyright 2017 The Go Authors. 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/issue19482.go b/test/fixedbugs/issue19482.go
new file mode 100644
index 0000000..97497a4
--- /dev/null
+++ b/test/fixedbugs/issue19482.go
@@ -0,0 +1,34 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Compiler rejected initialization of structs to composite literals
+// in a non-static setting (e.g. in a function)
+// when the struct contained a field named _.
+
+package p
+
+type T struct {
+	_ string
+}
+
+func ok() {
+	var x = T{"check"}
+	_ = x
+	_ = T{"et"}
+}
+
+var (
+	y = T{"stare"}
+	w = T{_: "look"} // ERROR "invalid field name _ in struct initializer"
+	_ = T{"page"}
+	_ = T{_: "out"} // ERROR "invalid field name _ in struct initializer"
+)
+
+func bad() {
+	var z = T{_: "verse"} // ERROR "invalid field name _ in struct initializer"
+	_ = z
+	_ = T{_: "itinerary"} // ERROR "invalid field name _ in struct initializer"
+}
diff --git a/test/fixedbugs/issue19515.go b/test/fixedbugs/issue19515.go
new file mode 100644
index 0000000..a1605be
--- /dev/null
+++ b/test/fixedbugs/issue19515.go
@@ -0,0 +1,51 @@
+// compile
+
+// Copyright 2017 The Go 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 19515: compiler panics on spilling int128 constant.
+
+package x
+
+type VScrollPanel struct {
+	x, y int
+}
+
+type Color struct {
+	R, G, B, A float32
+}
+
+func maxF(a, b float32) float32 {
+	if a > b {
+		return 0
+	}
+	return 1
+}
+
+type TransformMatrix [6]float32
+
+type Paint struct {
+	xform      TransformMatrix
+	feather    float32
+	innerColor Color
+	outerColor Color
+}
+
+func BoxGradient(x, y, w, h, f float32, iColor, oColor Color) Paint {
+	return Paint{
+		xform:      TransformMatrix{9, 0, 0, 0, x, y},
+		feather:    maxF(1.0, f),
+		innerColor: iColor,
+		outerColor: oColor,
+	}
+}
+
+func (v *VScrollPanel) Draw() {
+	x := float32(v.x)
+	y := float32(v.y)
+
+	BoxGradient(x+x-2, y-1, 0, 0, 0, Color{}, Color{})
+	BoxGradient(x+y-2, y-1, 0, 0, 0, Color{}, Color{})
+}
+
diff --git a/test/fixedbugs/issue19548.dir/a.go b/test/fixedbugs/issue19548.dir/a.go
new file mode 100644
index 0000000..3b7cd4b
--- /dev/null
+++ b/test/fixedbugs/issue19548.dir/a.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.
+
+package a
+
+type Mode uint
+
+func (m Mode) String() string { return "mode string" }
+func (m *Mode) Addr() *Mode   { return m }
+
+type Stringer interface {
+	String() string
+}
+
+var global Stringer
+var m Mode
+
+func init() {
+	// force compilation of the (*Mode).String() wrapper
+	global = &m
+}
+
+func String() string {
+	return global.String() + Mode(0).String()
+}
diff --git a/test/fixedbugs/issue19548.dir/b.go b/test/fixedbugs/issue19548.dir/b.go
new file mode 100644
index 0000000..e5e807f
--- /dev/null
+++ b/test/fixedbugs/issue19548.dir/b.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 main
+
+import "./a"
+
+type Value interface {
+	a.Stringer
+	Addr() *a.Mode
+}
+
+var global a.Mode
+
+func f() int {
+	var v Value
+	v = &global
+	return int(v.String()[0])
+}
+
+func main() {
+	f()
+}
diff --git a/test/fixedbugs/issue19548.go b/test/fixedbugs/issue19548.go
new file mode 100644
index 0000000..e0e7693
--- /dev/null
+++ b/test/fixedbugs/issue19548.go
@@ -0,0 +1,9 @@
+// rundir
+
+// Copyright 2017 The Go 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 interface wrappers can be compiled successfully
+// in multiple translation units.
+package ignore
diff --git a/test/fixedbugs/issue19555.go b/test/fixedbugs/issue19555.go
new file mode 100644
index 0000000..53b2ebd
--- /dev/null
+++ b/test/fixedbugs/issue19555.go
@@ -0,0 +1,36 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type NodeLink struct{}
+
+// A role our end of NodeLink is intended to play
+type LinkRole int64
+
+const (
+	LinkServer LinkRole = iota // link created as server
+	LinkClient                 // link created as client
+
+	// for testing:
+	linkNoRecvSend LinkRole = 1 << 16 // do not spawn serveRecv & serveSend
+	linkFlagsMask  LinkRole = (1<<32 - 1) << 16
+)
+
+func NewNodeLink(role LinkRole) *NodeLink {
+	var nextConnId uint32
+	switch role &^ linkFlagsMask {
+	case LinkServer:
+		nextConnId = 0 // all initiated by us connId will be even
+	case LinkClient:
+		nextConnId = 1 // ----//---- odd
+	default:
+		panic("invalid conn role")
+	}
+
+	_ = nextConnId
+	return nil
+}
diff --git a/test/fixedbugs/issue19610.go b/test/fixedbugs/issue19610.go
new file mode 100644
index 0000000..01beda3
--- /dev/null
+++ b/test/fixedbugs/issue19610.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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() {
+	for ; ; x := 1 { // ERROR "cannot declare in post statement"
+		_ = x
+		break
+	}
+}
diff --git a/test/fixedbugs/issue19632.go b/test/fixedbugs/issue19632.go
new file mode 100644
index 0000000..41cb1ff
--- /dev/null
+++ b/test/fixedbugs/issue19632.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2017 The Go 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 don't crash due to "lost track of variable in
+// liveness" errors against unused variables.
+
+package p
+
+import "strings"
+
+// Minimized test case from github.com/mvdan/sh/syntax.
+func F() {
+	var _ = []string{
+		strings.Repeat("\n\n\t\t        \n", 10) +
+			"# " + strings.Repeat("foo bar ", 10) + "\n" +
+			strings.Repeat("longlit_", 10) + "\n",
+	}
+}
diff --git a/test/fixedbugs/issue19658.go b/test/fixedbugs/issue19658.go
new file mode 100644
index 0000000..91cb886
--- /dev/null
+++ b/test/fixedbugs/issue19658.go
@@ -0,0 +1,99 @@
+// +build !nacl
+// run
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// ensure that panic(x) where x is a numeric type displays a readable number
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+const fn = `
+package main
+
+import  "errors"
+type S struct {
+
+}
+func (s S) String() string {
+	return "s-stringer"
+}
+func main() {
+ 	_ = errors.New
+  panic(%s(%s))
+}
+`
+
+func main() {
+	tempDir, err := ioutil.TempDir("", "")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer os.RemoveAll(tempDir)
+	tmpFile := filepath.Join(tempDir, "tmp.go")
+
+	for _, tc := range []struct {
+		Type   string
+		Input  string
+		Expect string
+	}{{"", "nil", "panic: nil"},
+		{"errors.New", `"test"`, "panic: test"},
+		{"S", "S{}", "panic: s-stringer"},
+		{"byte", "8", "panic: 8"},
+		{"rune", "8", "panic: 8"},
+		{"int", "8", "panic: 8"},
+		{"int8", "8", "panic: 8"},
+		{"int16", "8", "panic: 8"},
+		{"int32", "8", "panic: 8"},
+		{"int64", "8", "panic: 8"},
+		{"uint", "8", "panic: 8"},
+		{"uint8", "8", "panic: 8"},
+		{"uint16", "8", "panic: 8"},
+		{"uint32", "8", "panic: 8"},
+		{"uint64", "8", "panic: 8"},
+		{"uintptr", "8", "panic: 8"},
+		{"bool", "true", "panic: true"},
+		{"complex64", "8 + 16i", "panic: (+8.000000e+000+1.600000e+001i)"},
+		{"complex128", "8+16i", "panic: (+8.000000e+000+1.600000e+001i)"},
+		{"string", `"test"`, "panic: test"}} {
+
+		b := bytes.Buffer{}
+		fmt.Fprintf(&b, fn, tc.Type, tc.Input)
+
+		err = ioutil.WriteFile(tmpFile, b.Bytes(), 0644)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		cmd := exec.Command("go", "run", tmpFile)
+		var buf bytes.Buffer
+		cmd.Stdout = &buf
+		cmd.Stderr = &buf
+		cmd.Env = os.Environ()
+		cmd.Run() // ignore err as we expect a panic
+
+		out := buf.Bytes()
+		panicIdx := bytes.Index(out, []byte("panic: "))
+		if panicIdx == -1 {
+			log.Fatalf("expected a panic in output for %s, got: %s", tc.Type, out)
+		}
+		eolIdx := bytes.IndexByte(out[panicIdx:], '\n') + panicIdx
+		if panicIdx == -1 {
+			log.Fatalf("expected a newline in output for %s after the panic, got: %s", tc.Type, out)
+		}
+		out = out[0:eolIdx]
+		if string(out) != tc.Expect {
+			log.Fatalf("expected '%s' for panic(%s(%s)), got %s", tc.Expect, tc.Type, tc.Input, out)
+		}
+	}
+}
diff --git a/test/fixedbugs/issue19667.go b/test/fixedbugs/issue19667.go
new file mode 100644
index 0000000..c94a11d
--- /dev/null
+++ b/test/fixedbugs/issue19667.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 we don't crash when reporting this error.
+
+package p
+
+func f() {
+	if err := http.ListenAndServe(
+} // ERROR "unexpected }, expecting expression"
diff --git a/test/fixedbugs/issue19671.go b/test/fixedbugs/issue19671.go
new file mode 100644
index 0000000..475c3e0
--- /dev/null
+++ b/test/fixedbugs/issue19671.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash when compiling assignments involving [0]T,
+// where T is not SSA-able.
+
+package a
+
+func f() {
+	var i int
+	arr := [0][2]int{}
+	arr[i][0] = 0
+}
diff --git a/test/fixedbugs/issue19678.go b/test/fixedbugs/issue19678.go
new file mode 100644
index 0000000..81ef331
--- /dev/null
+++ b/test/fixedbugs/issue19678.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash when compiling functions containing
+// forward refs in dead code.
+
+package p
+
+var f func(int)
+
+func g() {
+l1:
+	i := 0
+	goto l1
+l2:
+	f(i)
+	goto l2
+}
diff --git a/test/fixedbugs/issue19679.go b/test/fixedbugs/issue19679.go
new file mode 100644
index 0000000..636b27f
--- /dev/null
+++ b/test/fixedbugs/issue19679.go
@@ -0,0 +1,38 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash when a type switch was present in dead code
+// in an inlineable function.
+
+package p
+
+func Then() {
+	var i interface{}
+	if false {
+		switch i.(type) {
+		}
+	}
+}
+
+func Else() {
+	var i interface{}
+	if true {
+		_ = i
+	} else {
+		switch i.(type) {
+		}
+	}
+}
+
+func Switch() {
+	var i interface{}
+	switch 5 {
+	case 3:
+		switch i.(type) {
+		}
+	case 5:
+	}
+}
diff --git a/test/fixedbugs/issue19696.go b/test/fixedbugs/issue19696.go
new file mode 100644
index 0000000..4cb2789
--- /dev/null
+++ b/test/fixedbugs/issue19696.go
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash when compiling assignments involving [0]T,
+// where T is not SSA-able.
+
+package p
+
+type s struct {
+	a, b, c, d, e int
+}
+
+func f() {
+	var i int
+	arr := [0]s{}
+	arr[i].a++
+}
diff --git a/test/fixedbugs/issue19699.dir/a.go b/test/fixedbugs/issue19699.dir/a.go
new file mode 100644
index 0000000..83be926
--- /dev/null
+++ b/test/fixedbugs/issue19699.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2017 The Go Authors. 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 F() {
+l1:
+	if false {
+		goto l1
+	}
+}
diff --git a/test/fixedbugs/issue19699.dir/b.go b/test/fixedbugs/issue19699.dir/b.go
new file mode 100644
index 0000000..e727133
--- /dev/null
+++ b/test/fixedbugs/issue19699.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+	a.F()
+}
diff --git a/test/fixedbugs/issue19699.go b/test/fixedbugs/issue19699.go
new file mode 100644
index 0000000..8000a52
--- /dev/null
+++ b/test/fixedbugs/issue19699.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2017 The Go Authors. 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/issue19699b.go b/test/fixedbugs/issue19699b.go
new file mode 100644
index 0000000..4afc0ca
--- /dev/null
+++ b/test/fixedbugs/issue19699b.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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() bool {
+	if false {
+	} else {
+		return true
+	}
+} // ERROR "missing return at end of function"
diff --git a/test/fixedbugs/issue19705.go b/test/fixedbugs/issue19705.go
new file mode 100644
index 0000000..6157945
--- /dev/null
+++ b/test/fixedbugs/issue19705.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2017 The Go Authors. 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 f1() {
+	f2()
+}
+
+func f2() {
+	if false {
+		_ = func() {}
+	}
+}
diff --git a/test/fixedbugs/issue19710.go b/test/fixedbugs/issue19710.go
new file mode 100644
index 0000000..c42ea7c
--- /dev/null
+++ b/test/fixedbugs/issue19710.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2017 The Go 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 19710: mishandled defer delete(...)
+
+package main
+
+func main() {
+	if n := len(f()); n != 0 {
+		println("got", n, "want 0")
+		panic("bad defer delete")
+	}
+}
+
+func f() map[int]bool {
+	m := map[int]bool{}
+	for i := 0; i < 3; i++ {
+		m[i] = true
+		defer delete(m, i)
+	}
+	return m
+}
diff --git a/test/fixedbugs/issue19764.dir/a.go b/test/fixedbugs/issue19764.dir/a.go
new file mode 100644
index 0000000..64538e5
--- /dev/null
+++ b/test/fixedbugs/issue19764.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. 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{ _ int }
+func (t T) M() {}
+
+type I interface { M() }
+
+func F() {
+	var t I = &T{}
+	t.M() // call to the wrapper (*T).M
+}
diff --git a/test/fixedbugs/issue19764.dir/b.go b/test/fixedbugs/issue19764.dir/b.go
new file mode 100644
index 0000000..d39f125
--- /dev/null
+++ b/test/fixedbugs/issue19764.dir/b.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+	var x a.I = &a.T{}
+	x.M() // call to the wrapper (*T).M
+	a.F() // make sure a.F is not dead, which also calls (*T).M inside package a
+}
diff --git a/test/fixedbugs/issue19764.go b/test/fixedbugs/issue19764.go
new file mode 100644
index 0000000..26fb00b
--- /dev/null
+++ b/test/fixedbugs/issue19764.go
@@ -0,0 +1,10 @@
+// rundir
+
+// Copyright 2017 The Go 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 19764: test that the linker's trampoline insertion
+// pass is happy with direct calls to interface wrappers that
+// may be defined in multiple packages.
+package ignore
diff --git a/test/fixedbugs/issue19783.go b/test/fixedbugs/issue19783.go
new file mode 100644
index 0000000..8d6494e
--- /dev/null
+++ b/test/fixedbugs/issue19783.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2017 The Go Authors. 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 Spin() {
+l1:
+	for true {
+		goto l1
+	l2:
+		if true {
+			goto l2
+		}
+	}
+}
diff --git a/test/fixedbugs/issue19799.go b/test/fixedbugs/issue19799.go
new file mode 100644
index 0000000..cb675d7
--- /dev/null
+++ b/test/fixedbugs/issue19799.go
@@ -0,0 +1,71 @@
+// run
+
+// Copyright 2017 The Go Authors. 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"
+	"runtime"
+)
+
+func foo(x int) int {
+	return x + 1
+}
+
+func test() {
+	defer func() {
+		if r := recover(); r != nil {
+			pcs := make([]uintptr, 10)
+			n := runtime.Callers(0, pcs)
+			pcs = pcs[:n]
+			frames := runtime.CallersFrames(pcs)
+			for {
+				f, more := frames.Next()
+				if f.Function == "main.foo" {
+					println("did not expect to see call to foo in stack trace")
+					os.Exit(1)
+				}
+				if !more {
+					break
+				}
+			}
+		}
+	}()
+	var v []int
+	foo(v[0])
+}
+
+func bar(x ...int) int {
+	return x[0] + 1
+}
+
+func testVariadic() {
+	defer func() {
+		if r := recover(); r != nil {
+			pcs := make([]uintptr, 10)
+			n := runtime.Callers(0, pcs)
+			pcs = pcs[:n]
+			frames := runtime.CallersFrames(pcs)
+			for {
+				f, more := frames.Next()
+				if f.Function == "main.bar" {
+					println("did not expect to see call to bar in stack trace")
+					os.Exit(1)
+				}
+				if !more {
+					break
+				}
+			}
+		}
+	}()
+	var v []int
+	bar(v[0])
+}
+
+func main() {
+	test()
+	testVariadic()
+}
diff --git a/test/fixedbugs/issue19880.go b/test/fixedbugs/issue19880.go
new file mode 100644
index 0000000..629c95d
--- /dev/null
+++ b/test/fixedbugs/issue19880.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct {
+	f [1]int
+}
+
+func a() {
+	_ = T // ERROR "type T is not an expression"
+}
+
+func b() {
+	var v [len(T{}.f)]int // ok
+	_ = v
+}
diff --git a/test/fixedbugs/issue19911.go b/test/fixedbugs/issue19911.go
new file mode 100644
index 0000000..af7f598
--- /dev/null
+++ b/test/fixedbugs/issue19911.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2017 The Go Authors. 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"
+	"strings"
+)
+
+type ET struct{}
+
+func (*ET) Error() string { return "err" }
+
+func main() {
+	check("false", fmt.Sprintf("(*ET)(nil) == error(nil): %v", (*ET)(nil) == error(nil)))
+	check("true", fmt.Sprintf("(*ET)(nil) != error(nil): %v", (*ET)(nil) != error(nil)))
+
+	nilET := (*ET)(nil)
+	nilError := error(nil)
+
+	check("false", fmt.Sprintf("nilET == nilError: %v", nilET == nilError))
+	check("true", fmt.Sprintf("nilET != nilError: %v", nilET != nilError))
+}
+
+func check(want, gotfull string) {
+	got := gotfull[strings.Index(gotfull, ": ")+len(": "):]
+	if got != want {
+		panic("want " + want + " got " + got + " from " + gotfull)
+	}
+}
diff --git a/test/fixedbugs/issue19947.go b/test/fixedbugs/issue19947.go
new file mode 100644
index 0000000..3233469
--- /dev/null
+++ b/test/fixedbugs/issue19947.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// No double error on ideal -> float{32,64} conversion overflow
+
+package issue19947
+
+var _ = float32(1) * 1e200 // ERROR "constant 1e\+200 overflows float32"
+var _ = float64(1) * 1e500 // ERROR "constant 1e\+500 overflows float64"
+
+var _ = complex64(1) * 1e200  // ERROR "constant 1e\+200 overflows complex64"
+var _ = complex128(1) * 1e500 // ERROR "constant 1e\+500 overflows complex128"
diff --git a/test/fixedbugs/issue19977.go b/test/fixedbugs/issue19977.go
new file mode 100644
index 0000000..3db1dfd
--- /dev/null
+++ b/test/fixedbugs/issue19977.go
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 19977: multiple error messages when type switching on an undefined
+
+package foo
+
+func Foo() {
+	switch x := a.(type) { // ERROR "undefined: a"
+	default:
+		_ = x
+	}
+}
diff --git a/test/fixedbugs/issue20145.go b/test/fixedbugs/issue20145.go
new file mode 100644
index 0000000..67ba5ae
--- /dev/null
+++ b/test/fixedbugs/issue20145.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2017 The Go 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 20145: some func types weren't dowidth-ed by the front end,
+// leading to races in the backend.
+
+package p
+
+func f() {
+	_ = (func())(nil)
+}
diff --git a/test/fixedbugs/issue20162.go b/test/fixedbugs/issue20162.go
new file mode 100644
index 0000000..41f156e
--- /dev/null
+++ b/test/fixedbugs/issue20162.go
@@ -0,0 +1,16 @@
+// compile -c=4
+
+// Copyright 2017 The Go 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 20162: embedded interfaces weren't dowidth-ed by the front end,
+// leading to races in the backend.
+
+package p
+
+func Foo() {
+	_ = (make([]func() interface {
+		M(interface{})
+	}, 1))
+}
diff --git a/test/fixedbugs/issue20174.go b/test/fixedbugs/issue20174.go
new file mode 100644
index 0000000..a9c1fd8
--- /dev/null
+++ b/test/fixedbugs/issue20174.go
@@ -0,0 +1,18 @@
+// compile -c=2
+
+// Copyright 2017 The Go 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 20174: failure to typecheck contents of *T in the frontend.
+
+package p
+
+func f() {
+	_ = (*interface{})(nil) // interface{} here used to not have its width calculated going into backend
+	select {
+	case _ = <-make(chan interface {
+		M()
+	}, 1):
+	}
+}
diff --git a/test/fixedbugs/issue20185.go b/test/fixedbugs/issue20185.go
new file mode 100644
index 0000000..00c23f6
--- /dev/null
+++ b/test/fixedbugs/issue20185.go
@@ -0,0 +1,25 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 20185: type switching on untyped values (e.g. nil or consts)
+// caused an internal compiler error.
+
+package p
+
+func F() {
+	switch t := nil.(type) { // ERROR "cannot type switch on non-interface value nil"
+	default:
+		_ = t
+	}
+}
+
+const x = 1
+
+func G() {
+	switch t := x.(type) { // ERROR "cannot type switch on non-interface value x \(type untyped number\)"
+	default:
+	}
+}
diff --git a/test/fixedbugs/issue20227.go b/test/fixedbugs/issue20227.go
new file mode 100644
index 0000000..4448eb5
--- /dev/null
+++ b/test/fixedbugs/issue20227.go
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 20227: panic while constructing constant "1i/1e-600000000"
+
+package p
+
+var _ = 1 / 1e-600000000i  // ERROR "complex division by zero"
+var _ = 1i / 1e-600000000  // ERROR "complex division by zero"
+var _ = 1i / 1e-600000000i // ERROR "complex division by zero"
+
+var _ = 1 / (1e-600000000 + 1e-600000000i)  // ERROR "complex division by zero"
+var _ = 1i / (1e-600000000 + 1e-600000000i) // ERROR "complex division by zero"
diff --git a/test/fixedbugs/issue20232.go b/test/fixedbugs/issue20232.go
new file mode 100644
index 0000000..f91c749
--- /dev/null
+++ b/test/fixedbugs/issue20232.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const _ = 6e5518446744 // ERROR "malformed constant: 6e5518446744 \(exponent overflow\)"
+const _ = 1e-1000000000
+const _ = 1e+1000000000 // ERROR "constant too large"
diff --git a/test/fixedbugs/issue20233.go b/test/fixedbugs/issue20233.go
new file mode 100644
index 0000000..4dec4e4
--- /dev/null
+++ b/test/fixedbugs/issue20233.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 20233: panic while formatting an error message
+
+package p
+
+var f = func(...A) // ERROR "undefined: A"
diff --git a/test/fixedbugs/issue20245.go b/test/fixedbugs/issue20245.go
new file mode 100644
index 0000000..b07dbe2
--- /dev/null
+++ b/test/fixedbugs/issue20245.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 20245: panic while formatting an error message
+
+package p
+
+var e = interface{ I1 } // ERROR "undefined: I1"
diff --git a/test/fixedbugs/issue20250.go b/test/fixedbugs/issue20250.go
new file mode 100644
index 0000000..f24710a
--- /dev/null
+++ b/test/fixedbugs/issue20250.go
@@ -0,0 +1,24 @@
+// errorcheck -0 -live -d=compilelater
+
+// Copyright 2017 The Go 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 20250: liveness differed with concurrent compilation
+// due to propagation of addrtaken to outer variables for
+// closure variables.
+
+package p
+
+type T struct {
+	s string
+}
+
+func f(a T) { // ERROR "live at entry to f: a"
+	var e interface{}
+	func() { // ERROR "live at entry to f.func1: &e a"
+		e = a.s // ERROR "live at call to convT2Estring: &e a" "live at call to writebarrierptr: a"
+	}() // ERROR "live at call to f.func1: e$"
+	// Before the fix, both a and e were live at the previous line.
+	_ = e
+}
diff --git a/test/fixedbugs/issue20298.go b/test/fixedbugs/issue20298.go
new file mode 100644
index 0000000..7572a6b
--- /dev/null
+++ b/test/fixedbugs/issue20298.go
@@ -0,0 +1,32 @@
+// errorcheck -e=0
+
+// Copyright 2017 The Go 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 20298: "imported and not used" error report order was non-deterministic.
+// This test works by limiting the number of errors (-e=0)
+// and checking that the errors are all at the beginning.
+
+package p
+
+import (
+	"bufio"       // ERROR "imported and not used"
+	"bytes"       // ERROR "imported and not used"
+	"crypto/x509" // ERROR "imported and not used"
+	"flag"        // ERROR "imported and not used"
+	"fmt"         // ERROR "imported and not used"
+	"io"          // ERROR "imported and not used"
+	"io/ioutil"   // ERROR "imported and not used"
+	"log"         // ERROR "imported and not used"
+	"math"        // ERROR "imported and not used"
+	"math/big"    // ERROR "imported and not used" "too many errors"
+	"math/bits"
+	"net"
+	"net/http"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
diff --git a/test/fixedbugs/issue20333.go b/test/fixedbugs/issue20333.go
new file mode 100644
index 0000000..8202ab3
--- /dev/null
+++ b/test/fixedbugs/issue20333.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2017 The Go 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 20333: early checkwidth of [...] arrays led to compilation errors.
+
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println(&[...]string{"abc", "def", "ghi"})
+}
diff --git a/test/fixedbugs/issue20415.go b/test/fixedbugs/issue20415.go
new file mode 100644
index 0000000..6f2c342
--- /dev/null
+++ b/test/fixedbugs/issue20415.go
@@ -0,0 +1,33 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 redeclaration errors report correct position.
+
+package p
+
+// 1
+var f byte
+
+var f interface{} // ERROR "previous declaration at issue20415.go:12"
+
+func _(f int) {
+}
+
+// 2
+var g byte
+
+func _(g int) {
+}
+
+var g interface{} // ERROR "previous declaration at issue20415.go:20"
+
+// 3
+func _(h int) {
+}
+
+var h byte
+
+var h interface{} // ERROR "previous declaration at issue20415.go:31"
diff --git a/test/fixedbugs/issue20529.go b/test/fixedbugs/issue20529.go
new file mode 100644
index 0000000..cd0c23d
--- /dev/null
+++ b/test/fixedbugs/issue20529.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// +build amd64
+
+// Copyright 2017 The Go 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 20529: Large stack frames caused compiler panics.
+// Only tested on amd64 because the test only makes sense
+// on a 64 bit system, and it is platform-agnostic,
+// so testing one suffices.
+
+package p
+
+func f() { // ERROR "stack frame too large"
+	_ = [][]int{1e9: []int{}}
+}
diff --git a/test/fixedbugs/issue20530.go b/test/fixedbugs/issue20530.go
new file mode 100644
index 0000000..51f0bd8
--- /dev/null
+++ b/test/fixedbugs/issue20530.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a uint8
+
+//go:noinline
+func f() {
+	b := int8(func() int32 { return -1 }())
+	a = uint8(b)
+	if int32(a) != 255 {
+		// Failing case prints 'got 255 expected 255'
+		println("got", a, "expected 255")
+	}
+}
+
+//go:noinline
+func g() {
+	b := int8(func() uint32 { return 0xffffffff }())
+	a = uint8(b)
+	if int32(a) != 255 {
+		// Failing case prints 'got 255 expected 255'
+		println("got", a, "expected 255")
+	}
+}
+
+func main() {
+	f()
+	g()
+}
diff --git a/test/fixedbugs/issue20602.go b/test/fixedbugs/issue20602.go
new file mode 100644
index 0000000..ca4ce09
--- /dev/null
+++ b/test/fixedbugs/issue20602.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 the correct (not implicitly dereferenced)
+// type is reported in the error message.
+
+package p
+
+var p = &[1]complex128{0}
+var _ = real(p)  // ERROR "type \*\[1\]complex128"
+var _ = imag(p)	 // ERROR "type \*\[1\]complex128"
diff --git a/test/fixedbugs/issue7525.go b/test/fixedbugs/issue7525.go
index 4e1d88a..6e69593 100644
--- a/test/fixedbugs/issue7525.go
+++ b/test/fixedbugs/issue7525.go
@@ -11,9 +11,7 @@ package main
 import "unsafe"
 
 var x struct {
-	a [unsafe.Sizeof(x.a)]int // ERROR "array bound|typechecking loop|invalid expression"
+	a [unsafe.Sizeof(x.a)]int   // ERROR "array bound|typechecking loop|invalid expression"
 	b [unsafe.Offsetof(x.b)]int // ERROR "array bound"
-	c [unsafe.Alignof(x.c)]int // ERROR "array bound|invalid expression"
-	d [len(x.d)]int // ERROR "array bound|invalid array"
-	e [cap(x.e)]int // ERROR "array bound|invalid array"
+	c [unsafe.Alignof(x.c)]int  // ERROR "array bound|invalid expression"
 }
diff --git a/test/fixedbugs/issue7525b.go b/test/fixedbugs/issue7525b.go
new file mode 100644
index 0000000..20a62ee
--- /dev/null
+++ b/test/fixedbugs/issue7525b.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 7525: self-referential array types.
+
+package main
+
+var y struct {
+	d [len(y.d)]int // ERROR "array bound|typechecking loop|invalid array"
+}
diff --git a/test/fixedbugs/issue7525c.go b/test/fixedbugs/issue7525c.go
new file mode 100644
index 0000000..f633b1c
--- /dev/null
+++ b/test/fixedbugs/issue7525c.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 7525: self-referential array types.
+
+package main
+
+var z struct {
+	e [cap(z.e)]int // ERROR "array bound|typechecking loop|invalid array"
+}
diff --git a/test/fixedbugs/issue8042.go b/test/fixedbugs/issue8042.go
new file mode 100644
index 0000000..5639f97
--- /dev/null
+++ b/test/fixedbugs/issue8042.go
@@ -0,0 +1,66 @@
+// compile
+
+// Copyright 2017 The Go 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 gotos across non-variable declarations
+// are accepted.
+
+package p
+
+func _() {
+	goto L1
+	const x = 0
+L1:
+	goto L2
+	type T int
+L2:
+}
+
+func _() {
+	{
+		goto L1
+	}
+	const x = 0
+L1:
+	{
+		goto L2
+	}
+	type T int
+L2:
+}
+
+func _(d int) {
+	if d > 0 {
+		goto L1
+	} else {
+		goto L2
+	}
+	const x = 0
+L1:
+	switch d {
+	case 1:
+		goto L3
+	case 2:
+	default:
+		goto L4
+	}
+	type T1 int
+L2:
+	const y = 1
+L3:
+	for d > 0 {
+		if d < 10 {
+			goto L4
+		}
+	}
+	type T2 int
+L4:
+	select {
+	default:
+		goto L5
+	}
+	type T3 int
+L5:
+}
diff --git a/test/fixedbugs/issue8438.go b/test/fixedbugs/issue8438.go
new file mode 100644
index 0000000..b28025c
--- /dev/null
+++ b/test/fixedbugs/issue8438.go
@@ -0,0 +1,17 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 don't print duplicate errors for string ->
+// array-literal conversion
+
+package main
+
+func main() {
+	_ = []byte{"foo"}   // ERROR "cannot convert"
+	_ = []int{"foo"}    // ERROR "cannot convert"
+	_ = []rune{"foo"}   // ERROR "cannot convert"
+	_ = []string{"foo"} // OK
+}
diff --git a/test/fixedbugs/issue8440.go b/test/fixedbugs/issue8440.go
new file mode 100644
index 0000000..f9b1dea
--- /dev/null
+++ b/test/fixedbugs/issue8440.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2017 The Go Authors. 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() {
+	n.foo = 6 // ERROR "undefined: n in n.foo"
+}
diff --git a/test/fixedbugs/issue9432.go b/test/fixedbugs/issue9432.go
index 2049460..e8946a5 100644
--- a/test/fixedbugs/issue9432.go
+++ b/test/fixedbugs/issue9432.go
@@ -9,7 +9,7 @@
 // See golang.org/issue/9432.
 package p
 
-type foo struct { // GCCGO_ERROR "invalid recursive type"
+type foo struct { // ERROR "invalid recursive type"
 	bar  foo
 	blah foo
-} // ERROR "invalid recursive type foo"
+}
diff --git a/test/goto.go b/test/goto.go
index f456901..d660c9c 100644
--- a/test/goto.go
+++ b/test/goto.go
@@ -77,7 +77,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"
+	goto L // ERROR "goto L jumps over declaration of y at LINE+3|goto jumps over declaration"
 	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 	y := 1
@@ -87,7 +87,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"
+	goto L // ERROR "goto L jumps over declaration of y at LINE+3|goto jumps over declaration"
 	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 	y := 1
@@ -130,7 +130,7 @@ func _() {
 
 // error shows first (outermost) offending block
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
 	{
 		{
 			{ // GCCGO_ERROR "block starts here"
@@ -194,7 +194,7 @@ func _() {
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	if true {
 	} else { // GCCGO_ERROR "block starts here"
 	L:
@@ -241,7 +241,7 @@ func _() {
 	// really is LINE+1 (like in the previous test),
 	// even though it looks like it might be LINE+3 instead.
 	if true {
-		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+		goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	} else if false {
 	} else { // GCCGO_ERROR "block starts here"
 	L:
@@ -395,7 +395,7 @@ func _() {
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	switch i {
 	case 0:
 	L: // GCCGO_ERROR "block starts here"
@@ -403,7 +403,7 @@ func _() {
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	switch i {
 	case 0:
 	L: // GCCGO_ERROR "block starts here"
@@ -413,7 +413,7 @@ func _() {
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
 	switch i {
 	case 0:
 	default:
diff --git a/test/import5.go b/test/import5.go
index 6480acf..8fdc8c3 100644
--- a/test/import5.go
+++ b/test/import5.go
@@ -21,35 +21,7 @@ import _ "go/parser"
 //import "greek/αβ"
 
 // Import paths must be strings.
-import 42    // ERROR "import statement"
-import 'a'   // ERROR "import statement"
-import 3.14  // ERROR "import statement"
-import 0.25i // ERROR "import statement"
-
-// Each of these pairs tests both `` vs "" strings
-// and also use of invalid characters spelled out as
-// escape sequences and written directly.
-// For example `"\x00"` tests import "\x00"
-// while "`\x00`" tests import `<actual-NUL-byte>`.
-import ""         // ERROR "import path"
-import ``         // ERROR "import path"
-import "\x00"     // ERROR "import path"
-import `\x00`     // ERROR "import path"
-import "\x7f"     // ERROR "import path"
-import `\x7f`     // ERROR "import path"
-import "a!"       // ERROR "import path"
-import `a!`       // ERROR "import path"
-import "a b"      // ERROR "import path"
-import `a b`      // ERROR "import path"
-import "a\\b"     // ERROR "import path"
-import `a\\b`     // ERROR "import path"
-import "\"`a`\""  // ERROR "import path"
-import `\"a\"`    // ERROR "import path"
-import "\x80\x80" // ERROR "import path"
-import `\x80\x80` // ERROR "import path"
-import "\xFFFD"   // ERROR "import path"
-import `\xFFFD`   // ERROR "import path"
-
-// Invalid local imports.
-import "/foo"  // ERROR "import path cannot be absolute path"
-import "c:/foo"  // ERROR "import path contains invalid character"
+import 42    // ERROR "import path must be a string"
+import 'a'   // ERROR "import path must be a string"
+import 3.14  // ERROR "import path must be a string"
+import 0.25i // ERROR "import path must be a string"
diff --git a/test/import6.go b/test/import6.go
new file mode 100644
index 0000000..c19280f
--- /dev/null
+++ b/test/import6.go
@@ -0,0 +1,38 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 invalid imports are rejected by the compiler.
+// Does not compile.
+
+package main
+
+// Each of these pairs tests both `` vs "" strings
+// and also use of invalid characters spelled out as
+// escape sequences and written directly.
+// For example `"\x00"` tests import "\x00"
+// while "`\x00`" tests import `<actual-NUL-byte>`.
+import ""         // ERROR "import path"
+import ``         // ERROR "import path"
+import "\x00"     // ERROR "import path"
+import `\x00`     // ERROR "import path"
+import "\x7f"     // ERROR "import path"
+import `\x7f`     // ERROR "import path"
+import "a!"       // ERROR "import path"
+import `a!`       // ERROR "import path"
+import "a b"      // ERROR "import path"
+import `a b`      // ERROR "import path"
+import "a\\b"     // ERROR "import path"
+import `a\\b`     // ERROR "import path"
+import "\"`a`\""  // ERROR "import path"
+import `\"a\"`    // ERROR "import path"
+import "\x80\x80" // ERROR "import path"
+import `\x80\x80` // ERROR "import path"
+import "\xFFFD"   // ERROR "import path"
+import `\xFFFD`   // ERROR "import path"
+
+// Invalid local imports.
+import "/foo"  // ERROR "import path cannot be absolute path"
+import "c:/foo"  // ERROR "import path contains invalid character"
diff --git a/test/initializerr.go b/test/initializerr.go
index ca05414..990ab60 100644
--- a/test/initializerr.go
+++ b/test/initializerr.go
@@ -23,6 +23,7 @@ var a2 = S { Y: 3, Z: 2, Y: 3 } // ERROR "duplicate"
 var a3 = T { S{}, 2, 3, 4, 5, 6 }	// ERROR "convert|too many"
 var a4 = [5]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }	// ERROR "index|too many"
 var a5 = []byte { x: 2 }	// ERROR "index"
+var a6 = []byte{1: 1, 2: 2, 1: 3}	// ERROR "duplicate index"
 
 var ok1 = S { }	// should be ok
 var ok2 = T { S: ok1 }	// should be ok
diff --git a/test/inline_caller.go b/test/inline_caller.go
new file mode 100644
index 0000000..79039a6
--- /dev/null
+++ b/test/inline_caller.go
@@ -0,0 +1,77 @@
+// run -gcflags -l=4
+
+// Copyright 2017 The Go Authors. 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"
+)
+
+type frame struct {
+	pc   uintptr
+	file string
+	line int
+	ok   bool
+}
+
+var (
+	skip        int
+	globalFrame frame
+)
+
+func f() {
+	g() // line 27
+}
+
+func g() {
+	h() // line 31
+}
+
+func h() {
+	x := &globalFrame
+	x.pc, x.file, x.line, x.ok = runtime.Caller(skip) // line 36
+}
+
+//go:noinline
+func testCaller(skp int) frame {
+	skip = skp
+	f() // line 42
+	frame := globalFrame
+	if !frame.ok {
+		panic(fmt.Sprintf("skip=%d runtime.Caller failed", skp))
+	}
+	return frame
+}
+
+type wantFrame struct {
+	funcName string
+	line     int
+}
+
+// -1 means don't care
+var expected = []wantFrame{
+	0: {"main.testCaller", 36},
+	1: {"main.testCaller", 31},
+	2: {"main.testCaller", 27},
+	3: {"main.testCaller", 42},
+	4: {"main.main", 68},
+	5: {"runtime.main", -1},
+	6: {"runtime.goexit", -1},
+}
+
+func main() {
+	for i := 0; i <= 6; i++ {
+		frame := testCaller(i) // line 68
+		fn := runtime.FuncForPC(frame.pc)
+		if expected[i].line >= 0 && frame.line != expected[i].line {
+			panic(fmt.Sprintf("skip=%d expected line %d, got line %d", i, expected[i].line, frame.line))
+		}
+		if fn.Name() != expected[i].funcName {
+			panic(fmt.Sprintf("skip=%d expected function %s, got %s", i, expected[i].funcName, fn.Name()))
+		}
+	}
+}
diff --git a/test/inline_callers.go b/test/inline_callers.go
new file mode 100644
index 0000000..fb6ff6c
--- /dev/null
+++ b/test/inline_callers.go
@@ -0,0 +1,95 @@
+// run -gcflags -l=4
+
+// Copyright 2017 The Go Authors. 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 (
+	"log"
+	"runtime"
+)
+
+var skip int
+var npcs int
+var pcs = make([]uintptr, 32)
+
+func f() {
+	g()
+}
+
+func g() {
+	h()
+}
+
+func h() {
+	npcs = runtime.Callers(skip, pcs)
+}
+
+func testCallers(skp int) (frames []string) {
+	skip = skp
+	f()
+	for i := 0; i < npcs; i++ {
+		fn := runtime.FuncForPC(pcs[i])
+		frames = append(frames, fn.Name())
+		if fn.Name() == "main.main" {
+			break
+		}
+	}
+	return
+}
+
+func testCallersFrames(skp int) (frames []string) {
+	skip = skp
+	f()
+	callers := pcs[:npcs]
+	ci := runtime.CallersFrames(callers)
+	for {
+		frame, more := ci.Next()
+		frames = append(frames, frame.Function)
+		if !more || frame.Function == "main.main" {
+			break
+		}
+	}
+	return
+}
+
+var expectedFrames [][]string = [][]string{
+	0: {"runtime.Callers", "main.testCallers", "main.main"},
+	1: {"main.testCallers", "main.main"},
+	2: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
+	3: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
+	4: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
+	5: {"main.main"},
+}
+
+var allFrames = []string{"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallersFrames", "main.main"}
+
+func same(xs, ys []string) bool {
+	if len(xs) != len(ys) {
+		return false
+	}
+	for i := range xs {
+		if xs[i] != ys[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func main() {
+	for i := 0; i <= 5; i++ {
+		frames := testCallers(i)
+		expected := expectedFrames[i]
+		if !same(frames, expected) {
+			log.Fatalf("testCallers(%d):\n got %v\n want %v", i, frames, expected)
+		}
+
+		frames = testCallersFrames(i)
+		expected = allFrames[i:]
+		if !same(frames, expected) {
+			log.Fatalf("testCallersFrames(%d):\n got %v\n want %v", i, frames, expected)
+		}
+	}
+}
diff --git a/test/inline_literal.go b/test/inline_literal.go
new file mode 100644
index 0000000..53c6c05
--- /dev/null
+++ b/test/inline_literal.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2017 The Go Authors. 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 (
+	"log"
+	"reflect"
+	"runtime"
+)
+
+func hello() string {
+	return "Hello World" // line 16
+}
+
+func foo() string { // line 19
+	x := hello() // line 20
+	y := hello() // line 21
+	return x + y // line 22
+}
+
+func bar() string {
+	x := hello() // line 26
+	return x
+}
+
+// funcPC returns the PC for the func value f.
+func funcPC(f interface{}) uintptr {
+	return reflect.ValueOf(f).Pointer()
+}
+
+// Test for issue #15453. Previously, line 26 would appear in foo().
+func main() {
+	pc := funcPC(foo)
+	f := runtime.FuncForPC(pc)
+	for ; runtime.FuncForPC(pc) == f; pc++ {
+		file, line := f.FileLine(pc)
+		if line == 0 {
+			continue
+		}
+		// Line 16 can appear inside foo() because PC-line table has
+		// innermost line numbers after inlining.
+		if line != 16 && !(line >= 19 && line <= 22) {
+			log.Fatalf("unexpected line at PC=%d: %s:%d\n", pc, file, line)
+		}
+	}
+}
diff --git a/test/interface/explicit.go b/test/interface/explicit.go
index b10d02f..1fb3b6a 100644
--- a/test/interface/explicit.go
+++ b/test/interface/explicit.go
@@ -53,7 +53,12 @@ func main() {
 	i2 = I2(i) // ERROR "invalid|missing N method"
 
 	e = E(t) // ok
-	t = T(e) // ERROR "need explicit|need type assertion|incompatible" "as type [*]T"
+	t = T(e) // ERROR "need explicit|need type assertion|incompatible"
+
+	// cannot type-assert non-interfaces
+	f := 2.0
+	_ = f.(int) // ERROR "non-interface type"
+
 }
 
 type M interface {
@@ -81,7 +86,6 @@ var m2 M = jj // ERROR "incompatible|wrong type for M method"
 var m3 = M(ii) // ERROR "invalid|missing"
 var m4 = M(jj) // ERROR "invalid|wrong type for M method"
 
-
 type B1 interface {
 	_() // ERROR "methods must have a unique non-blank name"
 }
diff --git a/test/intrinsic.dir/main.go b/test/intrinsic.dir/main.go
index e0c11d0..4340dd4 100644
--- a/test/intrinsic.dir/main.go
+++ b/test/intrinsic.dir/main.go
@@ -22,7 +22,7 @@ func logf(f string, args ...interface{}) {
 	}
 }
 
-func test(i, x uint64) {
+func test(i int, 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)
@@ -36,12 +36,12 @@ func test(i, x uint64) {
 	if i <= 32 {
 		x32 := uint32(x)
 		t32 := T.Ctz32(x32) // ERROR "intrinsic substitution for Ctz32"
-		if uint32(i) != t32 {
+		if 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 {
+		if i != t32 {
 			logf("Ctz32(0x%x) expected %d but got %d\n", x32, i, t32)
 		}
 	}
@@ -83,10 +83,10 @@ func main() {
 		logf("ctz64(0) != 64")
 	}
 
-	for i := uint64(0); i <= 64; i++ {
+	for i := 0; i <= 64; i++ {
 		for j := uint64(1); j <= 255; j += 2 {
 			for k := uint64(1); k <= 65537; k += 128 {
-				x := (j * k) << i
+				x := (j * k) << uint(i)
 				test(i, x)
 			}
 		}
diff --git a/test/label1.go b/test/label1.go
index bdd489f..b2e0ef0 100644
--- a/test/label1.go
+++ b/test/label1.go
@@ -12,7 +12,19 @@ package main
 
 var x int
 
-func f() {
+func f1() {
+	switch x {
+	case 1:
+		continue // ERROR "continue is not in a loop$"
+	}
+	select {
+	default:
+		continue // ERROR "continue is not in a loop$"
+	}
+
+}
+
+func f2() {
 L1:
 	for {
 		if x == 0 {
@@ -31,7 +43,7 @@ L2:
 			break L2
 		}
 		if x == 1 {
-			continue L2 // ERROR "invalid continue label .*L2|continue is not in a loop"
+			continue L2 // ERROR "invalid continue label .*L2|continue is not in a loop$"
 		}
 		goto L2
 	}
@@ -49,7 +61,7 @@ L3:
 			break L3
 		}
 		if x == 12 {
-			continue L3 // ERROR "invalid continue label .*L3|continue is not in a loop"
+			continue L3 // ERROR "invalid continue label .*L3|continue is not in a loop$"
 		}
 		goto L3
 	}
@@ -60,7 +72,7 @@ L4:
 			break L4 // ERROR "invalid break label .*L4"
 		}
 		if x == 14 {
-			continue L4 // ERROR "invalid continue label .*L4|continue is not in a loop"
+			continue L4 // ERROR "invalid continue label .*L4|continue is not in a loop$"
 		}
 		if x == 15 {
 			goto L4
@@ -68,12 +80,12 @@ L4:
 	}
 
 L5:
-	f()
+	f2()
 	if x == 16 {
 		break L5 // ERROR "invalid break label .*L5"
 	}
 	if x == 17 {
-		continue L5 // ERROR "invalid continue label .*L5|continue is not in a loop"
+		continue L5 // ERROR "invalid continue label .*L5|continue is not in a loop$"
 	}
 	if x == 18 {
 		goto L5
@@ -91,12 +103,12 @@ L5:
 		}
 	}
 
-	continue // ERROR "continue is not in a loop"
+	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"
+	break // ERROR "break is not in a loop, switch, or select"
 	for {
 		break dance // ERROR "break label not defined: dance"
 	}
diff --git a/test/linkname.dir/linkname1.go b/test/linkname.dir/linkname1.go
new file mode 100644
index 0000000..9c61522
--- /dev/null
+++ b/test/linkname.dir/linkname1.go
@@ -0,0 +1,10 @@
+package x
+
+func indexByte(xs []byte, b byte) int { // ERROR "indexByte xs does not escape"
+	for i, x := range xs {
+		if x == b {
+			return i
+		}
+	}
+	return -1
+}
diff --git a/test/linkname.dir/linkname2.go b/test/linkname.dir/linkname2.go
new file mode 100644
index 0000000..5df4f50
--- /dev/null
+++ b/test/linkname.dir/linkname2.go
@@ -0,0 +1,13 @@
+package y
+
+import _ "unsafe"
+
+//go:linkname byteIndex linkname1.indexByte
+func byteIndex(xs []byte, b byte) int
+
+func ContainsSlash(data []byte) bool { // ERROR "leaking param: data" "can inline ContainsSlash"
+	if byteIndex(data, '/') != -1 {
+		return true
+	}
+	return false
+}
diff --git a/test/linkname.dir/linkname3.go b/test/linkname.dir/linkname3.go
new file mode 100644
index 0000000..cbbd3a1
--- /dev/null
+++ b/test/linkname.dir/linkname3.go
@@ -0,0 +1,11 @@
+package main
+
+import _ "./linkname1"
+import "./linkname2"
+
+func main() { // ERROR "can inline main"
+	str := "hello/world"
+	bs := []byte(str)        // ERROR "\(\[\]byte\)\(str\) escapes to heap"
+	if y.ContainsSlash(bs) { // ERROR "inlining call to y.ContainsSlash"
+	}
+}
diff --git a/test/linkname.go b/test/linkname.go
new file mode 100644
index 0000000..c94a113
--- /dev/null
+++ b/test/linkname.go
@@ -0,0 +1,15 @@
+// errorcheckandrundir -0 -m -l=4
+
+// Copyright 2010 The Go 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 that linknames are included in export data (issue 18167).
+package ignored
+
+/*
+Without CL 33911, this test would fail with the following error:
+
+main.main: relocation target linkname2.byteIndex not defined
+main.main: undefined: "linkname2.byteIndex"
+*/
diff --git a/test/live.go b/test/live.go
index b23e150..ef988a0 100644
--- a/test/live.go
+++ b/test/live.go
@@ -141,7 +141,7 @@ var i9 interface{}
 func f9() bool {
 	g8()
 	x := i9
-	y := interface{}(99.0i) // ERROR "live at call to convT2E: x.data x.type$"
+	y := interface{}(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+ x.data x.type$" "live at call to str: x.data x.type$"
 	i9 = y                  // make y escape so the line above has to call convT2E
 	return x != y
 }
@@ -255,13 +255,18 @@ func g15() string
 // and also that none show up in "ambiguously live" messages.
 
 var m map[string]int
+var mi map[interface{}]int
+
+// str and iface are used to ensure that a temp is required for runtime calls below.
+func str() string
+func iface() interface{}
 
 func f16() {
 	if b {
-		delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
+		delete(mi, iface()) // 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]+$"
+	delete(mi, iface()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
+	delete(mi, iface()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
 }
 
 var m2s map[string]*byte
@@ -280,19 +285,19 @@ func f17a(p *byte) { // ERROR "live at entry to f17a: p$"
 func f17b(p *byte) { // ERROR "live at entry to f17b: p$"
 	// key temporary
 	if b {
-		m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$"
+		m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
 	}
-	m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$"
-	m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$"
+	m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
+	m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
 }
 
 func f17c() {
 	// key and value temporaries
 	if b {
-		m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$"
+		m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
 	}
-	m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$"
-	m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$"
+	m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
+	m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
 }
 
 func f17d() *byte
@@ -313,6 +318,9 @@ func f18() {
 
 var ch chan *byte
 
+// byteptr is used to ensure that a temp is required for runtime calls below.
+func byteptr() *byte
+
 func f19() {
 	// dest temporary for channel receive.
 	var z *byte
@@ -328,10 +336,10 @@ func f19() {
 func f20() {
 	// src temporary for channel send
 	if b {
-		ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
+		ch <- byteptr() // 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]+$"
+	ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
+	ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
 }
 
 func f21() {
@@ -488,13 +496,13 @@ func f30(b bool) {
 
 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]+$"
+		g31(str()) // ERROR "live at call to convT2Estring: .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]+$"
+		h31(str()) // ERROR "live at call to convT2Estring: .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]+$"
+		panic(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+$" "live at call to gopanic: .autotmp_[0-9]+$"
 	}
 	print(b3)
 }
@@ -529,7 +537,7 @@ func call32(func())
 var m33 map[interface{}]int
 
 func f33() {
-	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+	if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
 		printnl()
 		return
 	} else {
@@ -539,7 +547,7 @@ func f33() {
 }
 
 func f34() {
-	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+	if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
 		printnl()
 		return
 	}
@@ -547,7 +555,7 @@ func f34() {
 }
 
 func f35() {
-	if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+	if m33[byteptr()] == 0 && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
 		printnl()
 		return
 	}
@@ -555,7 +563,7 @@ func f35() {
 }
 
 func f36() {
-	if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+	if m33[byteptr()] == 0 || m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
 		printnl()
 		return
 	}
@@ -563,7 +571,7 @@ func f36() {
 }
 
 func f37() {
-	if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+	if (m33[byteptr()] == 0 || m33[byteptr()] == 0) && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
 		printnl()
 		return
 	}
@@ -583,14 +591,14 @@ func f38(b bool) {
 	// we care that the println lines have no live variables
 	// and therefore no output.
 	if b {
-		select { // ERROR "live at call 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]+$"
+		select { // ERROR "live at call to newselect:( .autotmp_[0-9]+)+$" "live at call to selectgo:( .autotmp_[0-9]+)+$"
+		case <-fc38(): // ERROR "live at call to selectrecv:( .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]+$"
+		case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectsend:( .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]+$"
+		case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectrecv:( .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]+$"
+		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38:( .autotmp_[0-9]+)+$" "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectrecv:( .autotmp_[0-9]+)+$"
 			printnl()
 		}
 		printnl()
@@ -668,3 +676,15 @@ type T struct{}
 func (*T) Foo(ptr *int) {}
 
 type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "live at entry to R\.Foo: \.this ptr"
+
+// issue 18860: output arguments must be live all the time if there is a defer.
+// In particular, at printint r must be live.
+func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
+	r = p
+	defer func() { // ERROR "live at call to deferproc: q r$" "live at call to deferreturn: r$"
+		recover()
+	}()
+	printint(0) // ERROR "live at call to printint: q r$"
+	r = q
+	return // ERROR "live at call to deferreturn: r$"
+}
diff --git a/test/locklinear.go b/test/locklinear.go
new file mode 100644
index 0000000..161912b
--- /dev/null
+++ b/test/locklinear.go
@@ -0,0 +1,165 @@
+// run
+
+// Copyright 2017 The Go 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 locks don't go quadratic due to runtime hash table collisions.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"sync"
+	"time"
+)
+
+const debug = false
+
+// checkLinear asserts that the running time of f(n) is at least linear but sub-quadratic.
+// tries is the initial number of iterations.
+func checkLinear(typ string, tries int, f func(n int)) {
+	// Depending on the machine and OS, this test might be too fast
+	// to measure with accurate enough granularity. On failure,
+	// make it run longer, hoping that the timing granularity
+	// is eventually sufficient.
+
+	timeF := func(n int) time.Duration {
+		t1 := time.Now()
+		f(n)
+		return time.Since(t1)
+	}
+
+	n := tries
+	fails := 0
+	var buf bytes.Buffer
+	inversions := 0
+	for {
+		t1 := timeF(n)
+		t2 := timeF(2 * n)
+		if debug {
+			println(n, t1.String(), 2*n, t2.String())
+		}
+		fmt.Fprintf(&buf, "%d %v %d %v (%.1fX)\n", n, t1, 2*n, t2, float64(t2)/float64(t1))
+		// should be 2x (linear); allow up to 3x
+		if t1*3/2 < t2 && t2 < t1*3 {
+			return
+		}
+		if t2 < t1 {
+			if inversions++; inversions >= 5 {
+				// The system must be overloaded (some builders). Give up.
+				return
+			}
+			continue // try again; don't increment fails
+		}
+		// Once the test runs long enough for n ops,
+		// try to get the right ratio at least once.
+		// If many in a row all fail, give up.
+		if fails++; fails >= 5 {
+			// If 2n ops run in under a second and the ratio
+			// doesn't work out, make n bigger, trying to reduce
+			// the effect that a constant amount of overhead has
+			// on the computed ratio.
+			if t2 < time.Second*4/10 {
+				fails = 0
+				n *= 2
+				continue
+			}
+			panic(fmt.Sprintf("%s: too slow: %d ops: %v; %d ops: %v\n\n%s",
+				typ, n, t1, 2*n, t2, buf.String()))
+		}
+	}
+}
+
+const offset = 251 // known size of runtime hash table
+
+const profile = false
+
+func main() {
+	if profile {
+		f, err := os.Create("lock.prof")
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+	}
+
+	checkLinear("lockone", 1000, func(n int) {
+		ch := make(chan int)
+		locks := make([]sync.RWMutex, offset+1)
+		for i := 0; i < n; i++ {
+			go func() {
+				locks[0].Lock()
+				ch <- 1
+			}()
+		}
+		time.Sleep(1 * time.Millisecond)
+
+		go func() {
+			for j := 0; j < n; j++ {
+				locks[1].Lock()
+				locks[offset].Lock()
+				locks[1].Unlock()
+				runtime.Gosched()
+				locks[offset].Unlock()
+			}
+		}()
+
+		for j := 0; j < n; j++ {
+			locks[1].Lock()
+			locks[offset].Lock()
+			locks[1].Unlock()
+			runtime.Gosched()
+			locks[offset].Unlock()
+		}
+
+		for i := 0; i < n; i++ {
+			<-ch
+			locks[0].Unlock()
+		}
+	})
+
+	checkLinear("lockmany", 1000, func(n int) {
+		locks := make([]sync.RWMutex, n*offset+1)
+
+		var wg sync.WaitGroup
+		for i := 0; i < n; i++ {
+			wg.Add(1)
+			go func(i int) {
+				locks[(i+1)*offset].Lock()
+				wg.Done()
+				locks[(i+1)*offset].Lock()
+				locks[(i+1)*offset].Unlock()
+			}(i)
+		}
+		wg.Wait()
+
+		go func() {
+			for j := 0; j < n; j++ {
+				locks[1].Lock()
+				locks[0].Lock()
+				locks[1].Unlock()
+				runtime.Gosched()
+				locks[0].Unlock()
+			}
+		}()
+
+		for j := 0; j < n; j++ {
+			locks[1].Lock()
+			locks[0].Lock()
+			locks[1].Unlock()
+			runtime.Gosched()
+			locks[0].Unlock()
+		}
+
+		for i := 0; i < n; i++ {
+			locks[(i+1)*offset].Unlock()
+		}
+	})
+}
diff --git a/test/loopbce.go b/test/loopbce.go
index ea19521..63bb4ba 100644
--- a/test/loopbce.go
+++ b/test/loopbce.go
@@ -31,7 +31,7 @@ func f0c(a []int) int {
 
 func f1(a []int) int {
 	x := 0
-	for _, i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+	for _, i := range a { // Change to "for i,e := range array/slice" hides IV report.
 		x += i
 	}
 	return x
@@ -197,7 +197,7 @@ func k4(a [100]int) [100]int {
 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+50] = i   // ERROR "Found redundant \(IsInBounds ind 100\), ind < 50$"
 		a[i-(max-70)] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 70$"
 	}
 	return a
diff --git a/test/makenew.go b/test/makenew.go
new file mode 100644
index 0000000..058d975
--- /dev/null
+++ b/test/makenew.go
@@ -0,0 +1,19 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 make and new arguments requirements are enforced by the
+// compiler.
+
+package main
+
+func main() {
+	_ = make()      // ERROR "missing argument"
+	_ = make(int)   // ERROR "cannot make type"
+	_ = make([]int) // ERROR "missing len argument"
+
+	_ = new()       // ERROR "missing argument"
+	_ = new(int, 2) // ERROR "too many arguments"
+}
diff --git a/test/map1.go b/test/map1.go
index d3c0a90..498c2ec 100644
--- a/test/map1.go
+++ b/test/map1.go
@@ -9,8 +9,6 @@
 
 package main
 
-func main() {}
-
 type v bool
 
 var (
@@ -60,3 +58,11 @@ type T5 *int
 type T6 struct { F T5 }
 type T7 *T4
 type T8 struct { F *T7 }
+
+func main() {
+	m := make(map[int]int)
+	delete()        // ERROR "missing arguments"
+	delete(m)       // ERROR "missing second \(key\) argument"
+	delete(m, 2, 3) // ERROR "too many arguments"
+	delete(1, m)    // ERROR "first argument to delete must be map"
+}
\ No newline at end of file
diff --git a/test/nilptr3.go b/test/nilptr3.go
index c681cba..195c8ca 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -40,23 +40,23 @@ var (
 )
 
 func f1() {
-	_ = *intp // ERROR "removed nil check"
+	_ = *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 "removed nil check"
+	_ = *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 "removed nil check"
 	_ = *array0p // ERROR "generated nil check"
+	_ = *array0p // ERROR "removed nil check"
 
-	_ = *intp    // ERROR "generated nil check"
+	_ = *intp    // ERROR "removed nil check"
 	_ = *arrayp  // ERROR "removed nil check"
 	_ = *structp // ERROR "generated nil check"
 	_ = *emptyp  // ERROR "generated nil check"
-	_ = *arrayp  // ERROR "generated nil check"
+	_ = *arrayp  // ERROR "removed nil check"
 }
 
 func f2() {
@@ -71,15 +71,15 @@ func f2() {
 		empty1p    *Empty1
 	)
 
-	_ = *intp       // ERROR "removed.* nil check"
-	_ = *arrayp     // ERROR "removed.* nil check"
-	_ = *array0p    // ERROR "removed.* nil check"
-	_ = *array0p    // ERROR "generated nil check"
 	_ = *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 "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"
@@ -122,16 +122,16 @@ func f3(x *[10000]int) {
 	// 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 "generated nil check" // TODO: fix
+	_ = x[9999] // ERROR "removed nil check"
 }
 
 func f3a() {
 	x := fx10k()
 	y := fx10k()
 	z := fx10k()
-	_ = &x[9] // ERROR "removed.* nil check"
-	y = z
 	_ = &x[9] // ERROR "generated nil check"
+	y = z
+	_ = &x[9] // ERROR "removed.* nil check"
 	x = y
 	_ = &x[9] // ERROR "generated nil check"
 }
@@ -139,11 +139,11 @@ func f3a() {
 func f3b() {
 	x := fx10k()
 	y := fx10k()
-	_ = &x[9] // ERROR "removed.* nil check"
+	_ = &x[9] // ERROR "generated nil check"
 	y = x
 	_ = &x[9] // ERROR "removed.* nil check"
 	x = y
-	_ = &x[9] // ERROR "generated nil check"
+	_ = &x[9] // ERROR "removed.* nil check"
 }
 
 func fx10() *[10]int
@@ -179,15 +179,15 @@ func f4(x *[10]int) {
 	_ = x[9] // ERROR "generated nil check"  // bug would like to remove before indirect
 
 	fx10()
-	_ = x[9] // ERROR "generated nil check"  // TODO: fix
+	_ = x[9] // ERROR "removed nil check"
 
 	x = fx10()
 	y := fx10()
-	_ = &x[9] // ERROR "removed[a-z ]* nil check"
+	_ = &x[9] // ERROR "generated nil check"
 	y = x
 	_ = &x[9] // ERROR "removed[a-z ]* nil check"
 	x = y
-	_ = &x[9] // ERROR "generated nil check"
+	_ = &x[9] // ERROR "removed[a-z ]* nil check"
 }
 
 func f5(p *float32, q *float64, r *float32, s *float64) float64 {
@@ -254,3 +254,8 @@ func f7() (*Struct, float64) {
 	p := &t.Y    // ERROR "removed nil check"
 	return t, *p // ERROR "removed nil check"
 }
+
+// make sure to remove nil check for memory move (issue #18003)
+func f8(t *[8]int) [8]int {
+	return *t // ERROR "removed nil check"
+}
diff --git a/test/nosplit.go b/test/nosplit.go
index e0d531c..3244df5 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -310,7 +310,7 @@ TestCases:
 					size += (880 - 128) - 128
 					// Noopt builds have a larger stackguard.
 					// See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
-					// This increase is included in obj.StackGuard
+					// This increase is included in objabi.StackGuard
 					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
 						if s == "-N" {
 							size += 880
diff --git a/test/notinheap.go b/test/notinheap.go
index c3fdfd6..44b7964 100644
--- a/test/notinheap.go
+++ b/test/notinheap.go
@@ -13,15 +13,15 @@ type nih struct{}
 
 // Types embedding notinheap types must be notinheap.
 
-type embed1 struct {
+type embed1 struct { // ERROR "must be go:notinheap"
 	x nih
-} // ERROR "must be go:notinheap"
+}
 
 type embed2 [1]nih // ERROR "must be go:notinheap"
 
-type embed3 struct {
+type embed3 struct { // ERROR "must be go:notinheap"
 	x [1]nih
-} // ERROR "must be go:notinheap"
+}
 
 type embed4 map[nih]int // ERROR "go:notinheap map key not allowed"
 
diff --git a/test/prove.go b/test/prove.go
index 9ced616..e89ab3f 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -250,7 +250,9 @@ func f9(a, b bool) int {
 
 func f10(a string) int {
 	n := len(a)
-	if a[:n>>1] == "aaaaaaaaaaaaaa" {
+	// We optimize comparisons with small constant strings (see cmd/compile/internal/gc/walk.go),
+	// so this string literal must be long.
+	if a[:n>>1] == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
 		return 0
 	}
 	return 1
@@ -273,7 +275,7 @@ func f11c(a []int, i int) {
 
 func f11d(a []int, i int) {
 	useInt(a[2*i+7])
-	useInt(a[2*i+7])
+	useInt(a[2*i+7]) // ERROR "Proved boolean IsInBounds$"
 }
 
 func f12(a []int, b int) {
@@ -438,6 +440,31 @@ func f13i(a uint) int {
 	return 3
 }
 
+func f14(p, q *int, a []int) {
+	// This crazy ordering usually gives i1 the lowest value ID,
+	// j the middle value ID, and i2 the highest value ID.
+	// That used to confuse CSE because it ordered the args
+	// of the two + ops below differently.
+	// That in turn foiled bounds check elimination.
+	i1 := *p
+	j := *q
+	i2 := *p
+	useInt(a[i1+j])
+	useInt(a[i2+j]) // ERROR "Proved boolean IsInBounds$"
+}
+
+func f15(s []int, x int) {
+	useSlice(s[x:])
+	useSlice(s[:x]) // ERROR "Proved IsSliceInBounds$"
+}
+
+func f16(s []int) []int {
+	if len(s) >= 10 {
+		return s[:10] // ERROR "Proved non-negative bounds IsSliceInBounds$"
+	}
+	return nil
+}
+
 //go:noinline
 func useInt(a int) {
 }
diff --git a/test/range.go b/test/range.go
index bae7a1c..afdac57 100644
--- a/test/range.go
+++ b/test/range.go
@@ -277,6 +277,26 @@ func teststring() {
 		println("wrong sum ranging over makestring", s)
 		panic("fail")
 	}
+
+	x := []rune{'a', 'b'}
+	i := 1
+	for i, x[i] = range "c" {
+		break
+	}
+	if i != 0 || x[0] != 'a' || x[1] != 'c' {
+		println("wrong parallel assignment", i, x[0], x[1])
+		panic("fail")
+	}
+
+	y := []int{1, 2, 3}
+	r := rune(1)
+	for y[r], r = range "\x02" {
+		break
+	}
+	if r != 2 || y[0] != 1 || y[1] != 0 || y[2] != 3 {
+		println("wrong parallel assignment", r, y[0], y[1], y[2])
+		panic("fail")
+	}
 }
 
 func teststring1() {
diff --git a/test/recover5.go b/test/recover5.go
new file mode 100644
index 0000000..0e93f5e
--- /dev/null
+++ b/test/recover5.go
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2017 The Go 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 recover arguments requirements are enforced by the
+// compiler.
+
+package main
+
+func main() {
+	_ = recover()     // OK
+	_ = recover(1)    // ERROR "too many arguments"
+	_ = recover(1, 2) // ERROR "too many arguments"
+}
diff --git a/test/reorder.go b/test/reorder.go
index fc44be9..3a87d02 100644
--- a/test/reorder.go
+++ b/test/reorder.go
@@ -19,6 +19,7 @@ func main() {
 	p6()
 	p7()
 	p8()
+	p9()
 }
 
 var gx []int
@@ -112,3 +113,39 @@ func p8() {
 		panic(m[0])
 	}
 }
+
+// Issue #13433: Left-to-right assignment of OAS2XXX nodes.
+func p9() {
+	var x bool
+
+	// OAS2FUNC
+	x, x = fn()
+	checkOAS2XXX(x, "x, x = fn()")
+
+	// OAS2RECV
+	var c = make(chan bool, 10)
+	c <- false
+	x, x = <-c
+	checkOAS2XXX(x, "x, x <-c")
+
+	// OAS2MAPR
+	var m = map[int]bool{0: false}
+	x, x = m[0]
+	checkOAS2XXX(x, "x, x = m[0]")
+
+	// OAS2DOTTYPE
+	var i interface{} = false
+	x, x = i.(bool)
+	checkOAS2XXX(x, "x, x = i.(bool)")
+}
+
+//go:noinline
+func fn() (bool, bool) { return false, true }
+
+// checks the order of OAS2XXX.
+func checkOAS2XXX(x bool, s string) {
+	if !x {
+		fmt.Printf("%s; got=(false); want=(true)\n", s)
+		panic("failed")
+	}
+}
diff --git a/test/run.go b/test/run.go
index 19ca328..dc86ab7 100644
--- a/test/run.go
+++ b/test/run.go
@@ -193,8 +193,9 @@ func goFiles(dir string) []string {
 
 type runCmd func(...string) ([]byte, error)
 
-func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
+func compileFile(runcmd runCmd, longname string, flags []string) (out []byte, err error) {
 	cmd := []string{"go", "tool", "compile", "-e"}
+	cmd = append(cmd, flags...)
 	if *linkshared {
 		cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
 	}
@@ -585,7 +586,8 @@ func (t *test) run() {
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "errorcheck":
-		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
+		// TODO(gri) remove need for -C (disable printing of columns in error messages)
+		cmdline := []string{"go", "tool", "compile", "-C", "-e", "-o", "a.o"}
 		// No need to add -dynlink even if linkshared if we're just checking for errors...
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, long)
@@ -608,7 +610,7 @@ func (t *test) run() {
 		return
 
 	case "compile":
-		_, t.err = compileFile(runcmd, long)
+		_, t.err = compileFile(runcmd, long, flags)
 
 	case "compiledir":
 		// Compile all files in the directory in lexicographic order.
@@ -736,6 +738,7 @@ func (t *test) run() {
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
 		}
+		cmd = append(cmd, flags...)
 		cmd = append(cmd, t.goFileName())
 		out, err := runcmd(append(cmd, args...)...)
 		if err != nil {
diff --git a/test/runtime.go b/test/runtime.go
index bccc9b5..0cf781b 100644
--- a/test/runtime.go
+++ b/test/runtime.go
@@ -17,5 +17,5 @@ package main
 import "runtime"
 
 func main() {
-	runtime.printbool(true)	// ERROR "unexported"
+	runtime.printbool(true)	// ERROR "unexported" "undefined"
 }
diff --git a/test/shift1.go b/test/shift1.go
index aeefbc4..c81ee51 100644
--- a/test/shift1.go
+++ b/test/shift1.go
@@ -68,6 +68,12 @@ func _() {
 		w  int64   = 1.0 << 33   // 1.0<<33 is a constant shift expression
 		_, _, _, _, _, _, _, _, _, _ = j, k, m, n, o, u, u1, u2, v, w
 	)
+
+	// non constants arguments trigger a different path
+	f2 := 1.2
+	s2 := "hi"
+	_ = f2 << 2 // ERROR "shift of type float64"
+	_ = s2 << 2 // ERROR "shift of type string"
 }
 
 // shifts in comparisons w/ untyped operands
diff --git a/test/switch5.go b/test/switch5.go
index 5ca53ba..ce95bf8 100644
--- a/test/switch5.go
+++ b/test/switch5.go
@@ -9,8 +9,6 @@
 
 package main
 
-import "fmt"
-
 func f0(x int) {
 	switch x {
 	case 0:
@@ -19,7 +17,7 @@ func f0(x int) {
 
 	switch x {
 	case 0:
-	case int(0): // ERROR "duplicate case 0 in switch"
+	case int(0): // ERROR "duplicate case int.0. .value 0. in switch"
 	}
 }
 
@@ -46,30 +44,9 @@ func f3(e interface{}) {
 	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 float32(10): // ERROR "duplicate case float32\(10\) .value 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:
-	case error: // ERROR "duplicate case error in type switch"
-	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"
+	case float64(10): // ERROR "duplicate case float64\(10\) .value 10. in switch"
 	}
 }
 
@@ -99,3 +76,19 @@ func f7(a int) {
 	case 1, 2, 3, 4: // ERROR "duplicate case 1"
 	}
 }
+
+// Ensure duplicates with simple literals are printed as they were
+// written, not just their values. Particularly useful for runes.
+func f8(r rune) {
+	const x = 10
+	switch r {
+	case 33, 33: // ERROR "duplicate case 33 in switch"
+	case 34, '"': // ERROR "duplicate case '"' .value 34. in switch"
+	case 35, rune('#'): // ERROR "duplicate case rune.'#'. .value 35. in switch"
+	case 36, rune(36): // ERROR "duplicate case rune.36. .value 36. in switch"
+	case 37, '$'+1: // ERROR "duplicate case '\$' \+ 1 .value 37. in switch"
+	case 'b':
+	case 'a', 'b', 'c', 'd': // ERROR "duplicate case 'b' .value 98."
+	case x, x: // ERROR "duplicate case x .value 10."
+	}
+}
diff --git a/test/switch6.go b/test/switch6.go
index 32392d8..9d102fe 100644
--- a/test/switch6.go
+++ b/test/switch6.go
@@ -30,3 +30,17 @@ func f1(e interface{}) {
 	default: // ERROR "multiple defaults in switch"
 	}
 }
+
+type I interface {
+	Foo()
+}
+
+type X int
+
+func (*X) Foo() {}
+func f2() {
+	var i I
+	switch i.(type) {
+	case X: // ERROR "impossible type switch case: i \(type I\) cannot have dynamic type X \(Foo method has pointer receiver\)"
+	}
+}
diff --git a/test/switch7.go b/test/switch7.go
new file mode 100644
index 0000000..7506066
--- /dev/null
+++ b/test/switch7.go
@@ -0,0 +1,35 @@
+// 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 type switch statements with duplicate cases are detected
+// by the compiler.
+// Does not compile.
+
+package main
+
+import "fmt"
+
+func f4(e interface{}) {
+	switch e.(type) {
+	case int:
+	case int: // ERROR "duplicate case int in type switch"
+	case int64:
+	case error:
+	case error: // ERROR "duplicate case error in type switch"
+	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 { // ERROR "duplicate case struct { i int .tag1. } in type switch"
+		i int "tag1"
+	}:
+	}
+}
+
diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go
index a33a0d4..4eb6379 100644
--- a/test/syntax/chan1.go
+++ b/test/syntax/chan1.go
@@ -10,8 +10,8 @@ var c chan int
 var v int
 
 func main() {
-	if c <- v { // ERROR "used as value|missing condition|invalid condition"
+	if c <- v { // ERROR "used as value"
 	}
 }
 
-var _ = c <- v // ERROR "used as value|unexpected <-"
+var _ = c <- v // ERROR "unexpected <-"
diff --git a/test/syntax/forvar.go b/test/syntax/forvar.go
deleted file mode 100644
index 3a70d9c..0000000
--- a/test/syntax/forvar.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// errorcheck
-
-// Copyright 2010 The Go Authors. 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() {
-	var x int // avoid undefined: x error below with recursive-descent parser
-	for var x = 0; x < 10; x++ {	// ERROR "var declaration not allowed in for initializer"
diff --git a/test/syntax/initvar.go b/test/syntax/initvar.go
new file mode 100644
index 0000000..74623f5
--- /dev/null
+++ b/test/syntax/initvar.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2010 The Go Authors. 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() {
+	if var x = 0; x < 10 {}    // ERROR "var declaration not allowed in if initializer"
+
+	switch var x = 0; x {}     // ERROR "var declaration not allowed in switch initializer"
+
+	for var x = 0; x < 10; {}  // ERROR "var declaration not allowed in for initializer"
+}
diff --git a/test/syntax/semi1.go b/test/syntax/semi1.go
index c755445..8eed05c 100644
--- a/test/syntax/semi1.go
+++ b/test/syntax/semi1.go
@@ -7,7 +7,7 @@
 package main
 
 func main() {
-	if x; y		// ERROR "missing .*{.* after if clause|undefined"
+	if x; y		// ERROR "expected .*{.* after if clause|undefined"
 	{
 		z	// GCCGO_ERROR "undefined"
 
diff --git a/test/syntax/semi3.go b/test/syntax/semi3.go
index d625d08..d064ce6 100644
--- a/test/syntax/semi3.go
+++ b/test/syntax/semi3.go
@@ -7,7 +7,7 @@
 package main
 
 func main() {
-	for x; y; z	// ERROR "missing .*{.* after for clause|undefined"
+	for x; y; z	// ERROR "expected .*{.* after for clause|undefined"
 	{
 		z	// GCCGO_ERROR "undefined"
 
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index 6f5592e..f21431b 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -4,14 +4,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(mdempsky): Update error expectations for new parser.
-// The new parser emits an extra "missing { after for clause" error.
-// The old parser is supposed to emit this too, but it panics first
-// due to a nil pointer dereference.
-
 package main
 
 func main() {
 	for x		// GCCGO_ERROR "undefined"
-	{		// ERROR "missing .*{.* after for clause|missing operand"
-		z	// ERROR "undefined|missing { after for clause"
+	{		// ERROR "unexpected {, expecting for loop condition"
+		z
diff --git a/test/syntax/semi6.go b/test/syntax/semi6.go
index 325cc27..4a04f89 100644
--- a/test/syntax/semi6.go
+++ b/test/syntax/semi6.go
@@ -6,6 +6,6 @@
 
 package main
 
-type T	// ERROR "unexpected semicolon or newline in type declaration"
-// line below uncommented to avoid follow-up error
-// {
\ No newline at end of file
+type T1	// ERROR "unexpected newline in type declaration"
+
+type T2 /* // ERROR "unexpected EOF in type declaration" */
\ No newline at end of file
diff --git a/test/typeswitch2.go b/test/typeswitch2.go
index 6c70307..1160b62 100644
--- a/test/typeswitch2.go
+++ b/test/typeswitch2.go
@@ -26,10 +26,10 @@ func whatis(x interface{}) string {
 		w()
 	}:
 		return "rw"
-	case interface {	// GCCGO_ERROR "duplicate"
+	case interface {	// ERROR "duplicate"
 		w()
 		r()
-	}: // GC_ERROR "duplicate"
+	}:
 		return "wr"
 
 	}
diff --git a/test/typeswitch3.go b/test/typeswitch3.go
index 287e32e..58d4cba 100644
--- a/test/typeswitch3.go
+++ b/test/typeswitch3.go
@@ -18,26 +18,39 @@ type I interface {
 	M()
 }
 
-func main(){
+func main() {
 	var x I
 	switch x.(type) {
-	case string:	// ERROR "impossible"
+	case string: // ERROR "impossible"
 		println("FAIL")
 	}
-	
+
 	// Issue 2700: if the case type is an interface, nothing is impossible
-	
+
 	var r io.Reader
-	
+
 	_, _ = r.(io.Writer)
-	
+
 	switch r.(type) {
 	case io.Writer:
 	}
-	
+
 	// Issue 2827.
-	switch _ := r.(type) {  // ERROR "invalid variable name _|no new variables"
+	switch _ := r.(type) { // ERROR "invalid variable name _|no new variables"
 	}
 }
 
+func noninterface() {
+	var i int
+	switch i.(type) { // ERROR "cannot type switch on non-interface value"
+	case string:
+	case int:
+	}
 
+	type S struct {
+		name string
+	}
+	var s S
+	switch s.(type) { // ERROR "cannot type switch on non-interface value"
+	}
+}
diff --git a/test/writebarrier.go b/test/writebarrier.go
index 13f7b54..55ba81e 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -11,14 +11,14 @@ package p
 import "unsafe"
 
 func f(x **byte, y *byte) {
-	*x = y // ERROR "write barrier"
+	*x = y // no barrier (dead store)
 
 	z := y // no barrier
 	*x = z // ERROR "write barrier"
 }
 
 func f1(x *[]byte, y []byte) {
-	*x = y // ERROR "write barrier"
+	*x = y // no barrier (dead store)
 
 	z := y // no barrier
 	*x = z // ERROR "write barrier"
@@ -32,21 +32,21 @@ func f1a(x *[]byte, y *[]byte) {
 }
 
 func f2(x *interface{}, y interface{}) {
-	*x = y // ERROR "write barrier"
+	*x = y // no barrier (dead store)
 
 	z := y // no barrier
 	*x = z // ERROR "write barrier"
 }
 
 func f2a(x *interface{}, y *interface{}) {
-	*x = *y // ERROR "write barrier"
+	*x = *y // no barrier (dead store)
 
 	z := y // no barrier
 	*x = z // ERROR "write barrier"
 }
 
 func f3(x *string, y string) {
-	*x = y // ERROR "write barrier"
+	*x = y // no barrier (dead store)
 
 	z := y // no barrier
 	*x = z // ERROR "write barrier"
@@ -204,12 +204,18 @@ var y21 struct {
 }
 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                // ERROR "write barrier"
-	y21.x = &z21              // ERROR "write barrier"
+// f21x: Global -> heap pointer updates must have write barriers.
+func f21a(x *int) {
+	x21 = x   // ERROR "write barrier"
+	y21.x = x // ERROR "write barrier"
+}
+
+func f21b(x *int) {
+	x21 = &z21   // ERROR "write barrier"
+	y21.x = &z21 // ERROR "write barrier"
+}
+
+func f21c(x *int) {
 	y21 = struct{ x *int }{x} // ERROR "write barrier"
 }
 
@@ -229,10 +235,18 @@ type T23 struct {
 var t23 T23
 var i23 int
 
-func f23() {
-	// zeroing global needs write barrier for the hybrid barrier.
+// f23x: zeroing global needs write barrier for the hybrid barrier.
+func f23a() {
 	t23 = T23{} // ERROR "write barrier"
+}
+
+func f23b() {
+	// also test partial assignments
+	t23 = T23{a: 1} // ERROR "write barrier"
+}
+
+func f23c() {
+	t23 = T23{} // no barrier (dead store)
 	// also test partial assignments
-	t23 = T23{a: 1}    // ERROR "write barrier"
 	t23 = T23{p: &i23} // 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